From 473c5124df4f34634f3d4202f8ef2f9f14a4bb6d Mon Sep 17 00:00:00 2001 From: xDanilcusx Date: Thu, 19 Sep 2024 04:52:37 +0300 Subject: [PATCH 1/2] Retreating and pursuing --- code/__DEFINES/human_ai.dm | 9 +++++ code/_compile_options.dm | 2 +- .../human/ai/action_datums/approach_target.dm | 9 ++++- .../approach_target_carefully.dm | 7 ++++ .../ai/action_datums/retreat_from_target.dm | 40 +++++++++++++++++++ .../living/carbon/human/ai/brain/ai_brain.dm | 28 ++++++++----- .../carbon/human/ai/brain/ai_brain_cover.dm | 10 ++--- .../carbon/human/ai/brain/ai_brain_guns.dm | 2 +- .../carbon/human/ai/brain/ai_brain_items.dm | 18 +++++---- .../human/ai/brain/ai_brain_targeting.dm | 16 ++++---- .../carbon/human/ai/firearm_appraisal.dm | 7 ++-- colonialmarines.dme | 2 + 12 files changed, 115 insertions(+), 35 deletions(-) create mode 100644 code/modules/mob/living/carbon/human/ai/action_datums/approach_target_carefully.dm create mode 100644 code/modules/mob/living/carbon/human/ai/action_datums/retreat_from_target.dm diff --git a/code/__DEFINES/human_ai.dm b/code/__DEFINES/human_ai.dm index 076224e13f..246b8bddb4 100644 --- a/code/__DEFINES/human_ai.dm +++ b/code/__DEFINES/human_ai.dm @@ -1,6 +1,15 @@ #define HUMAN_AI_HEALTHITEMS "health" #define HUMAN_AI_AMMUNITION "ammo" +#define AI_ACTION_APPROACH /datum/ongoing_action/approach_target +#define AI_ACTION_APPROACH_C /datum/ongoing_action/approach_target/carefully +#define AI_ACTION_RETREAT /datum/ongoing_action/retreat_from_target +#define AI_ACTION_PICKUP /datum/ongoing_action/item_pickup +#define AI_ACTION_PICKUP_GUN /datum/ongoing_action/item_pickup/pickup_primary +#define AI_ACTION_COVER /datum/ongoing_action/take_cover +#define AI_ACTION_COVER_I /datum/ongoing_action/take_inside_cover +#define AI_ACTION_TROWBACK /datum/ongoing_action/throw_back_nade + /// Action is completed, delete this and move onto the next ongoing action #define ONGOING_ACTION_COMPLETED "completed" /// Action isn't finished, move onto the next ongoing action diff --git a/code/_compile_options.dm b/code/_compile_options.dm index 1c3f335a57..20aa208131 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -38,6 +38,6 @@ //#define UNIT_TESTS //If this is uncommented, we do a single run though of the game setup and tear down process with unit tests in between -#define TESTING +// #define TESTING // #define REFERENCE_TRACKING // #define GC_FAILURE_HARD_LOOKUP diff --git a/code/modules/mob/living/carbon/human/ai/action_datums/approach_target.dm b/code/modules/mob/living/carbon/human/ai/action_datums/approach_target.dm index 1f0cdc492b..ff5e086cc2 100644 --- a/code/modules/mob/living/carbon/human/ai/action_datums/approach_target.dm +++ b/code/modules/mob/living/carbon/human/ai/action_datums/approach_target.dm @@ -2,20 +2,27 @@ name = "Approach Target" var/atom/movable/target var/acceptable_distance + var/do_target_dead /datum/ongoing_action/approach_target/New(datum/human_ai_brain/brain, list/arguments) . = ..() target = arguments[2] acceptable_distance = arguments[3] + do_target_dead = length(arguments) < 4 ? TRUE : arguments[4] /datum/ongoing_action/approach_target/Destroy(force, ...) target = null return ..() /datum/ongoing_action/approach_target/trigger_action() - if(QDELETED(target) || !isturf(target.loc)) + if(QDELETED(target)) return ONGOING_ACTION_COMPLETED + if(ismob(target) && do_target_dead) + var/mob/M = target + if(M.is_dead()) + return ONGOING_ACTION_COMPLETED + if(get_dist(target, brain.tied_human) > acceptable_distance) if(!brain.move_to_next_turf(get_turf(target))) return ONGOING_ACTION_COMPLETED diff --git a/code/modules/mob/living/carbon/human/ai/action_datums/approach_target_carefully.dm b/code/modules/mob/living/carbon/human/ai/action_datums/approach_target_carefully.dm new file mode 100644 index 0000000000..d55eed4315 --- /dev/null +++ b/code/modules/mob/living/carbon/human/ai/action_datums/approach_target_carefully.dm @@ -0,0 +1,7 @@ +/datum/ongoing_action/approach_target/carefully + name = "Approach Target Carefully" + +/datum/ongoing_action/approach_target/carefully/trigger_action() + if(brain.current_target) + return ONGOING_ACTION_COMPLETED + . = ..() diff --git a/code/modules/mob/living/carbon/human/ai/action_datums/retreat_from_target.dm b/code/modules/mob/living/carbon/human/ai/action_datums/retreat_from_target.dm new file mode 100644 index 0000000000..8bcea49b0a --- /dev/null +++ b/code/modules/mob/living/carbon/human/ai/action_datums/retreat_from_target.dm @@ -0,0 +1,40 @@ +/datum/ongoing_action/retreat_from_target + name = "Retreat From Target" + var/atom/movable/target + var/acceptable_distance + var/do_target_dead + +/datum/ongoing_action/retreat_from_target/New(datum/human_ai_brain/brain, list/arguments) + . = ..() + target = arguments[2] + acceptable_distance = arguments[3] + do_target_dead = length(arguments) < 4 ? TRUE : arguments[4] + +/datum/ongoing_action/retreat_from_target/Destroy(force, ...) + target = null + return ..() + +/datum/ongoing_action/retreat_from_target/trigger_action() + if(QDELETED(target)) + return ONGOING_ACTION_COMPLETED + + if(ismob(target) && do_target_dead) + var/mob/M = target + if(M.is_dead()) + return ONGOING_ACTION_COMPLETED + + if(get_dist(target, brain.tied_human) < acceptable_distance) + var/relative_dir = Get_Compass_Dir(target, brain.tied_human) + var/moved = FALSE + for(var/D in list(relative_dir, turn(relative_dir, 90), turn(relative_dir, -90))) + if(brain.move_to_next_turf(get_step(get_turf(brain.tied_human), D))) + moved = TRUE + break + + if(!moved) + return ONGOING_ACTION_COMPLETED + + if(get_dist(target, brain.tied_human) < acceptable_distance) + return ONGOING_ACTION_UNFINISHED + + return ONGOING_ACTION_COMPLETED diff --git a/code/modules/mob/living/carbon/human/ai/brain/ai_brain.dm b/code/modules/mob/living/carbon/human/ai/brain/ai_brain.dm index 4977d452c4..e6c9a9f0ee 100644 --- a/code/modules/mob/living/carbon/human/ai/brain/ai_brain.dm +++ b/code/modules/mob/living/carbon/human/ai/brain/ai_brain.dm @@ -90,14 +90,22 @@ GLOBAL_LIST_EMPTY(human_ai_brains) item_search(things_around) //bullet_detect(things_around) - if(!currently_busy && primary_weapon && current_target && !currently_firing && COOLDOWN_FINISHED(src, fire_overload_cooldown) && primary_weapon.has_ammunition()) - currently_busy = TRUE - var/target_futile = current_target.is_mob_incapacitated() - if(get_dist(tied_human, current_target) > gun_data.optimal_range || target_futile) - if(!has_ongoing_action(/datum/ongoing_action/approach_target) && !in_cover) - var/walk_distance = target_futile ? gun_data.minimum_range : gun_data.optimal_range - ADD_ONGOING_ACTION(src, /datum/ongoing_action/approach_target, current_target, walk_distance) - attack_target() + if(primary_weapon && current_target) + if(!has_ongoing_action(AI_ACTION_APPROACH) && !has_ongoing_action(AI_ACTION_RETREAT)) + var/target_futile = current_target.is_mob_incapacitated() + var/distance = get_dist(tied_human, current_target) + if(distance > gun_data.optimal_range || target_futile) + if(!in_cover) + var/walk_distance = target_futile ? gun_data.minimum_range : gun_data.optimal_range + ADD_ONGOING_ACTION(src, AI_ACTION_APPROACH, current_target, walk_distance) + + else if(distance < gun_data.optimal_range) + var/walk_distance = in_cover ? gun_data.minimum_range : gun_data.optimal_range + ADD_ONGOING_ACTION(src, AI_ACTION_RETREAT, current_target, walk_distance) + + if(!currently_busy && !currently_firing && COOLDOWN_FINISHED(src, fire_overload_cooldown)) + currently_busy = TRUE + attack_target() if(!currently_busy && healing_start_check()) currently_busy = TRUE @@ -124,7 +132,7 @@ GLOBAL_LIST_EMPTY(human_ai_brains) tied_human.swap_hand() /datum/human_ai_brain/proc/nade_throwback(list/things_around) - if(has_ongoing_action(/datum/ongoing_action/throw_back_nade)) + if(has_ongoing_action(AI_ACTION_TROWBACK)) return var/turf/place_to_throw @@ -183,7 +191,7 @@ GLOBAL_LIST_EMPTY(human_ai_brains) return throw_back_nade: - ADD_ONGOING_ACTION(src, /datum/ongoing_action/throw_back_nade, throw_nade, place_to_throw) + ADD_ONGOING_ACTION(src, AI_ACTION_TROWBACK, throw_nade, place_to_throw) /// Use ADD_ONGOING_ACTION() macro instead of calling this directly /datum/human_ai_brain/proc/_add_ongoing_action(datum/ongoing_action/path, ...) diff --git a/code/modules/mob/living/carbon/human/ai/brain/ai_brain_cover.dm b/code/modules/mob/living/carbon/human/ai/brain/ai_brain_cover.dm index 144648ee68..9cd75406f6 100644 --- a/code/modules/mob/living/carbon/human/ai/brain/ai_brain_cover.dm +++ b/code/modules/mob/living/carbon/human/ai/brain/ai_brain_cover.dm @@ -117,7 +117,7 @@ shortest_cover_turf = get_turf(cade) cover_atom = cade if(shortest_cover_turf) - ADD_ONGOING_ACTION(src, /datum/ongoing_action/take_cover, shortest_cover_turf, cover_atom, FALSE) + ADD_ONGOING_ACTION(src, AI_ACTION_COVER, shortest_cover_turf, cover_atom, FALSE) if(!from_squad) squad_cover_processing(FALSE, view_contents - shortest_cover_turf) else @@ -140,7 +140,7 @@ shortest_cover_turf = maybe_cover cover_atom = wall if(shortest_cover_turf) - ADD_ONGOING_ACTION(src, /datum/ongoing_action/take_cover, shortest_cover_turf, cover_atom, TRUE) + ADD_ONGOING_ACTION(src, AI_ACTION_COVER, shortest_cover_turf, cover_atom, TRUE) if(!from_squad) squad_cover_processing(FALSE, view_contents - shortest_cover_turf) @@ -164,7 +164,7 @@ #ifdef TESTING to_chat(world, "highest_cover_value: [highest_cover_value], turf coords: [highest_cover_turf.x], [highest_cover_turf.y], [highest_cover_turf.z]") addtimer(CALLBACK(src, PROC_REF(clear_cover_value_debug), turf_dict), 60 SECONDS) - ADD_ONGOING_ACTION(src, /datum/ongoing_action/take_inside_cover, highest_cover_turf) + ADD_ONGOING_ACTION(src, AI_ACTION_COVER_I, highest_cover_turf) if(!from_squad) squad_cover_processing(TRUE, turf_dict - highest_cover_turf) else @@ -175,9 +175,9 @@ T.maptext = null #else - ADD_ONGOING_ACTION(src, /datum/ongoing_action/take_inside_cover, highest_cover_turf) + ADD_ONGOING_ACTION(src, AI_ACTION_COVER_I, highest_cover_turf) if(!from_squad) - squad_cover_processing(TRUE, view_contents - highest_cover_turf) + squad_cover_processing(TRUE, turf_dict - highest_cover_turf) else squad_covering = FALSE #endif diff --git a/code/modules/mob/living/carbon/human/ai/brain/ai_brain_guns.dm b/code/modules/mob/living/carbon/human/ai/brain/ai_brain_guns.dm index 192d22c1b0..70548919ae 100644 --- a/code/modules/mob/living/carbon/human/ai/brain/ai_brain_guns.dm +++ b/code/modules/mob/living/carbon/human/ai/brain/ai_brain_guns.dm @@ -81,4 +81,4 @@ return mag /datum/human_ai_brain/proc/should_reload_primary() - return (primary_weapon?.current_mag?.current_rounds <= 0) + return (primary_weapon?.current_mag?.current_rounds <= 0 && !primary_weapon?.in_chamber) diff --git a/code/modules/mob/living/carbon/human/ai/brain/ai_brain_items.dm b/code/modules/mob/living/carbon/human/ai/brain/ai_brain_items.dm index 3e29b4931b..cd43b8b01d 100644 --- a/code/modules/mob/living/carbon/human/ai/brain/ai_brain_items.dm +++ b/code/modules/mob/living/carbon/human/ai/brain/ai_brain_items.dm @@ -59,6 +59,8 @@ var/obj/item/storage/storage_item = container_refs[object_loc] storage_item.attempt_item_insertion(object_ref, FALSE, tied_human) + appraise_inventory() + /// Whenever an item is deleted, purge it from anywhere it may be stored in here /datum/human_ai_brain/proc/on_item_delete(obj/item/source, force) @@ -235,7 +237,7 @@ if(dropped == primary_weapon) set_primary_weapon(null) - ADD_ONGOING_ACTION(src, /datum/ongoing_action/item_pickup/pickup_primary, dropped) + ADD_ONGOING_ACTION(src, AI_ACTION_PICKUP_GUN, dropped) for(var/slot in container_refs) if(container_refs[slot] == dropped) appraise_inventory(slot == "belt", slot == "backpack", slot == "left_pocket", slot == "right_pocket") @@ -272,19 +274,19 @@ continue if(!primary_weapon && isgun(thing)) - ADD_ONGOING_ACTION(src, /datum/ongoing_action/item_pickup, thing) + ADD_ONGOING_ACTION(src, AI_ACTION_PICKUP, thing) break if(istype(thing, /obj/item/storage/belt) && !container_refs["belt"]) - ADD_ONGOING_ACTION(src, /datum/ongoing_action/item_pickup, thing) + ADD_ONGOING_ACTION(src, AI_ACTION_PICKUP, thing) break if(istype(thing, /obj/item/storage/backpack) && !container_refs["backpack"]) - ADD_ONGOING_ACTION(src, /datum/ongoing_action/item_pickup, thing) + ADD_ONGOING_ACTION(src, AI_ACTION_PICKUP, thing) break if(istype(thing, /obj/item/storage/pouch) && (!container_refs["left_pocket"] || !container_refs["right_pocket"])) - ADD_ONGOING_ACTION(src, /datum/ongoing_action/item_pickup, thing) + ADD_ONGOING_ACTION(src, AI_ACTION_PICKUP, thing) break var/storage_spot = storage_has_room(thing) @@ -292,12 +294,14 @@ continue if(is_type_in_list(thing, all_medical_items)) - ADD_ONGOING_ACTION(src, /datum/ongoing_action/item_pickup, thing) + ADD_ONGOING_ACTION(src, AI_ACTION_PICKUP, thing) break else if(primary_weapon && istype(thing, /obj/item/ammo_magazine)) var/obj/item/ammo_magazine/mag = thing + if(istype(mag, /obj/item/ammo_magazine/handful)) + continue if(istype(primary_weapon, mag.gun_type)) - ADD_ONGOING_ACTION(src, /datum/ongoing_action/item_pickup, thing) + ADD_ONGOING_ACTION(src, AI_ACTION_PICKUP, thing) break diff --git a/code/modules/mob/living/carbon/human/ai/brain/ai_brain_targeting.dm b/code/modules/mob/living/carbon/human/ai/brain/ai_brain_targeting.dm index aa97231ed7..ce0f691b07 100644 --- a/code/modules/mob/living/carbon/human/ai/brain/ai_brain_targeting.dm +++ b/code/modules/mob/living/carbon/human/ai/brain/ai_brain_targeting.dm @@ -148,7 +148,7 @@ primary_weapon.set_target(current_target) gun_data.before_fire(primary_weapon, tied_human, src) - if(!primary_weapon.current_mag || !primary_weapon.current_mag.current_rounds || !friendly_check()) + if((!primary_weapon?.current_mag.current_rounds && !primary_weapon.in_chamber) || !friendly_check()) end_gun_fire() return @@ -197,22 +197,24 @@ end_gun_fire() return - if(get_dist(tied_human, current_target) > gun_data.maximum_range) + if(QDELETED(current_target) || !friendly_check()) end_gun_fire() return - if(QDELETED(current_target) || !friendly_check()) + if(primary_weapon.current_mag?.current_rounds <= 1 && !primary_weapon.in_chamber) // bullet removal comes after comsig is triggered end_gun_fire() return - if(primary_weapon.current_mag?.current_rounds <= 1) // bullet removal comes after comsig is triggered + if(!(current_target in viewers(world.view, tied_human))) + if(!in_cover) + ADD_ONGOING_ACTION(src, AI_ACTION_APPROACH_C, current_target, 0) + else if(overwatch_allowed) + establish_overwatch() end_gun_fire() return - if(!(current_target in viewers(world.view, tied_human))) + if(get_dist(tied_human, current_target) > gun_data.maximum_range) end_gun_fire() - if(overwatch_allowed) - establish_overwatch() return if(istype(primary_weapon, /obj/item/weapon/gun/shotgun/pump)) diff --git a/code/modules/mob/living/carbon/human/ai/firearm_appraisal.dm b/code/modules/mob/living/carbon/human/ai/firearm_appraisal.dm index 5d484c8902..83417c4838 100644 --- a/code/modules/mob/living/carbon/human/ai/firearm_appraisal.dm +++ b/code/modules/mob/living/carbon/human/ai/firearm_appraisal.dm @@ -8,8 +8,8 @@ GLOBAL_LIST_INIT_TYPED(firearm_appraisals, /datum/firearm_appraisal, build_firea /datum/firearm_appraisal /// Minimum engagement range with weapon type - var/minimum_range = 1 - /// Optimal engagement range, try to approach if further than this + var/minimum_range = 2 + /// Optimal engagement range, try to stay at this distance var/optimal_range = 6 /// Maximum engagement range, stop firing at this distance var/maximum_range = 9 @@ -34,14 +34,15 @@ GLOBAL_LIST_INIT_TYPED(firearm_appraisals, /datum/firearm_appraisal, build_firea /datum/firearm_appraisal/smg burst_amount_max = 10 + minimum_range = 1 optimal_range = 5 - maximum_range = 7 gun_types = list( /obj/item/weapon/gun/smg, ) /datum/firearm_appraisal/shotgun burst_amount_max = 2 + minimum_range = 1 optimal_range = 1 // point-blank our beloved maximum_range = 3 gun_types = list( diff --git a/colonialmarines.dme b/colonialmarines.dme index e11d4e4f5e..c6a709a839 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -1982,6 +1982,8 @@ #include "code\modules\mob\living\carbon\human\ai\ai_management_menu.dm" #include "code\modules\mob\living\carbon\human\ai\faction_management_panel.dm" #include "code\modules\mob\living\carbon\human\ai\action_datums\pickup_primary.dm" +#include "code\modules\mob\living\carbon\human\ai\action_datums\approach_target_carefully.dm" +#include "code\modules\mob\living\carbon\human\ai\action_datums\retreat_from_target.dm" #include "code\modules\mob\living\carbon\human\ai\action_datums\orders\order_action.dm" #include "code\modules\mob\living\carbon\human\ai\action_datums\orders\patrol_waypoints.dm" #include "code\modules\mob\living\carbon\human\ai\brain\ai_brain_communication.dm" From f48085f1e212a889aa431e0667f05af7c27c8095 Mon Sep 17 00:00:00 2001 From: xDanilcusx Date: Thu, 19 Sep 2024 04:52:56 +0300 Subject: [PATCH 2/2] Pick up mags fix --- .../mob/living/carbon/human/ai/action_datums/item_pickup.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/modules/mob/living/carbon/human/ai/action_datums/item_pickup.dm b/code/modules/mob/living/carbon/human/ai/action_datums/item_pickup.dm index de113f8231..80cb53d6c2 100644 --- a/code/modules/mob/living/carbon/human/ai/action_datums/item_pickup.dm +++ b/code/modules/mob/living/carbon/human/ai/action_datums/item_pickup.dm @@ -55,11 +55,13 @@ return ONGOING_ACTION_COMPLETED if(is_type_in_list(to_pickup, brain.all_medical_items)) + brain.tied_human.put_in_hands(to_pickup, TRUE) brain.store_item(to_pickup, storage_spot) return ONGOING_ACTION_COMPLETED if(brain.primary_weapon && istype(to_pickup, /obj/item/ammo_magazine)) var/obj/item/ammo_magazine/mag = to_pickup if(istype(brain.primary_weapon, mag.gun_type)) + brain.tied_human.put_in_hands(to_pickup, TRUE) brain.store_item(to_pickup, storage_spot) return ONGOING_ACTION_COMPLETED