diff --git a/code/__DEFINES/human_ai.dm b/code/__DEFINES/human_ai.dm index be6a6d62e8..8decd957f2 100644 --- a/code/__DEFINES/human_ai.dm +++ b/code/__DEFINES/human_ai.dm @@ -2,6 +2,15 @@ #define HUMAN_AI_AMMUNITION "ammo" #define HUMAN_AI_GRENADES "grenades" +#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/item_pickup.dm b/code/modules/mob/living/carbon/human/ai/action_datums/item_pickup.dm index 8d5322e346..49481419b4 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 @@ -63,6 +63,7 @@ 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, HUMAN_AI_AMMUNITION) 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 e68000b1c4..249ceae6fb 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 @@ -91,14 +91,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 @@ -125,7 +133,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 @@ -184,7 +192,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 ce0c36e8ab..5b033a8c8e 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 @@ -84,6 +84,6 @@ if(gun_data?.disposable) return FALSE - if(primary_weapon?.current_mag?.current_rounds <= 0) + if(primary_weapon?.current_mag.current_rounds > 0 || primary_weapon?.in_chamber) return TRUE return FALSE 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 4ca353fd76..7cab59727d 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 @@ -65,6 +65,8 @@ if(slot_type) equipment_map[slot_type][object_ref] = object_loc + 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) @@ -244,7 +246,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") @@ -289,19 +291,19 @@ continue search_loop break - 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) @@ -309,18 +311,18 @@ 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(primary_weapon, mag.gun_type)) - ADD_ONGOING_ACTION(src, /datum/ongoing_action/item_pickup, thing) + ADD_ONGOING_ACTION(src, AI_ACTION_PICKUP, thing) break else if(istype(thing, /obj/item/explosive/grenade)) var/obj/item/explosive/grenade/nade = thing if(nade.active) continue - ADD_ONGOING_ACTION(src, /datum/ongoing_action/item_pickup, thing) + ADD_ONGOING_ACTION(src, AI_ACTION_PICKUP, thing) 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 9168ef2e22..015decc130 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 @@ -150,7 +150,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 @@ -199,15 +199,19 @@ 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() if(gun_data?.disposable) var/obj/item/gun = primary_weapon @@ -215,7 +219,7 @@ tied_human.drop_held_item(gun) 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() 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 132e7fbea0..c027d7fd77 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 @@ -42,14 +42,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 4f47474ae3..5ee739c13f 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -1983,6 +1983,8 @@ #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\throw_grenade.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"