diff --git a/code/__DEFINES/xeno_ai.dm b/code/__DEFINES/xeno_ai.dm index defe61de11..1b4006d507 100644 --- a/code/__DEFINES/xeno_ai.dm +++ b/code/__DEFINES/xeno_ai.dm @@ -15,10 +15,6 @@ #define WALL_PENALTY 50 #define FIRE_PENALTY 25 -// Xeno AI flags -#define XENO_AI_NO_DESPAWN (1<<0) -#define XENO_AI_CHOOSE_RANDOM_STRAIN (1<<1) - /* PROBABILITY CALCULATIONS ARE HERE */ @@ -86,41 +82,6 @@ PROBABILITY CALCULATIONS ARE HERE #define PRAETORIAN_SPIT 80 #define PRAETORIAN_SPRAY 80 -/* - GAME DIRECTOR AI -*/ - -/datum/config_entry/number/ai_director - abstract_type = /datum/config_entry/number/ai_director - -#define IDEAL_T2_PERCENT 0.5 -#define IDEAL_T3_PERCENT 0.25 - -/// The maximum amount of xenomorphs that can spawn, scaled up by population. -/datum/config_entry/number/ai_director/max_xeno_per_player - config_entry_value = 1 - -// Xenos spawn -/datum/config_entry/number/ai_director/t2_spawn_at_percentage - config_entry_value = 0.25 - -/datum/config_entry/number/ai_director/t3_spawn_at_percentage - config_entry_value = 0.5 - -/// The minimum range at which a xeno can be spawned from a human -#define MIN_RANGE_TO_SPAWN_XENO 10 -/// The maximum range at which a xeno can be spawned from a human -#define MAX_RANGE_TO_SPAWN_XENO 25 - -/// When a xeno gets despawned if there is no human within a specific range. -#define RANGE_TO_DESPAWN_XENO 25 -/// When a xeno gets despawned if they can't find a target within a specific amount of time. -#define XENO_DESPAWN_NO_TARGET_PERIOD 200 SECONDS - -// Director flags -#define XENO_SPAWN_T1 (1<<0) -#define XENO_SPAWN_T2 (1<<1) -#define XENO_SPAWN_T3 (1<<2) /// Special blockers for pathfinding or obstacle handling #define XENO_AI_SPECIAL_BLOCKERS list(/obj/flamer_fire, /obj/vehicle/multitile) diff --git a/code/_globalvars/lists/object_lists.dm b/code/_globalvars/lists/object_lists.dm index a224d0761b..0bbd63cdcf 100644 --- a/code/_globalvars/lists/object_lists.dm +++ b/code/_globalvars/lists/object_lists.dm @@ -28,7 +28,7 @@ GLOBAL_LIST_EMPTY_TYPED(hijack_deletable_windows, /obj/structure/machinery/door/ GLOBAL_LIST_EMPTY_TYPED(hijack_bustable_ladders, /obj/structure/ladder/fragile_almayer) GLOBAL_LIST_EMPTY_TYPED(all_multi_vehicles, /obj/vehicle/multitile) -GLOBAL_LIST_EMPTY_TYPED(all_defenses, /obj/structure/machinery/defenses) +GLOBAL_LIST_EMPTY_TYPED(all_active_defenses, /obj/structure/machinery/defenses) GLOBAL_LIST_EMPTY_TYPED(lifeboat_almayer_docks, /obj/docking_port/stationary/lifeboat_dock) GLOBAL_LIST_EMPTY_TYPED(lifeboat_doors, /obj/structure/machinery/door/airlock/multi_tile/almayer/dropshiprear/lifeboat/blastdoor) diff --git a/code/modules/defenses/defenses.dm b/code/modules/defenses/defenses.dm index a43af36097..cf1ff5a278 100644 --- a/code/modules/defenses/defenses.dm +++ b/code/modules/defenses/defenses.dm @@ -101,14 +101,14 @@ power_on_action() update_icon() - GLOB.all_defenses += src + GLOB.all_active_defenses += src /obj/structure/machinery/defenses/proc/power_off() turned_on = FALSE power_off_action() update_icon() - GLOB.all_defenses -= src + GLOB.all_active_defenses -= src /** * Update state category for this structure. @@ -472,7 +472,7 @@ return /obj/structure/machinery/defenses/Destroy() - GLOB.all_defenses -= src + GLOB.all_active_defenses -= src if(owner_mob) owner_mob = null diff --git a/code/modules/mob/living/carbon/xenomorph/ai/xeno_ai.dm b/code/modules/mob/living/carbon/xenomorph/ai/xeno_ai.dm index 8ffe258ca7..e6e5a72e15 100644 --- a/code/modules/mob/living/carbon/xenomorph/ai/xeno_ai.dm +++ b/code/modules/mob/living/carbon/xenomorph/ai/xeno_ai.dm @@ -1,6 +1,5 @@ /mob/living/carbon/xenomorph // AI stuff - var/flags_ai = XENO_AI_NO_DESPAWN var/atom/movable/current_target var/next_path_generation = 0 @@ -206,61 +205,103 @@ GLOBAL_LIST_INIT(ai_target_limbs, list( return TRUE +#define EXTRA_CHECK_DISTANCE_MULTIPLIER 0.20 + /mob/living/carbon/xenomorph/proc/get_target(range) - var/list/viable_humans = list() - var/list/viable_vehicles = list() - var/list/viable_defenses = list() + var/list/viable_targets = list() + var/atom/movable/closest_target var/smallest_distance = INFINITY - for(var/mob/living/carbon/human/alive_human as anything in GLOB.alive_human_list) - if(alive_human.species.flags & IS_SYNTHETIC) + for(var/mob/living/carbon/human/potential_alive_human_target as anything in GLOB.alive_human_list) + if(z != potential_alive_human_target.z) continue - if(z != alive_human.z) + if(!check_mob_target(potential_alive_human_target)) continue - if(FACTION_XENOMORPH in alive_human.faction_group) + var/distance = get_dist(src, potential_alive_human_target) + + if(distance > ai_range) continue - var/distance = get_dist(src, alive_human) + viable_targets += potential_alive_human_target + + if(smallest_distance <= distance) + continue - if(distance < ai_range && alive_human.stat == CONSCIOUS) - viable_humans += alive_human - smallest_distance = min(distance, smallest_distance) + closest_target = potential_alive_human_target + smallest_distance = distance - for(var/l in GLOB.all_multi_vehicles) - var/obj/vehicle/multitile/V = l - if(z != V.z) + for(var/obj/vehicle/multitile/potential_vehicle_target as anything in GLOB.all_multi_vehicles) + if(z != potential_vehicle_target.z) continue - var/distance = get_dist(src, V) - if(distance < ai_range) - viable_vehicles += V - smallest_distance = min(distance, smallest_distance) + var/distance = get_dist(src, potential_vehicle_target) - for(var/l in GLOB.all_defenses) - var/obj/structure/machinery/defenses/S = l - if(z != S.z) + if(distance > ai_range) continue - var/distance = get_dist(src, S) - if(distance < ai_range) - viable_defenses += S - smallest_distance = min(distance, smallest_distance) + if(potential_vehicle_target.health <= 0) + var/skip_vehicle = TRUE + var/list/interior_living_mobs = potential_vehicle_target.interior.get_passengers() + for(var/mob/living/carbon/human/human_mob in interior_living_mobs) + if(!check_mob_target(human_mob)) + continue - if(smallest_distance > RANGE_TO_DESPAWN_XENO && !(XENO_AI_NO_DESPAWN & flags_ai)) - remove_ai() - qdel(src) - return + skip_vehicle = FALSE + + if(skip_vehicle) + continue + + viable_targets += potential_vehicle_target + + if(smallest_distance <= distance) + continue + + closest_target = potential_vehicle_target + smallest_distance = distance + + for(var/obj/structure/machinery/defenses/potential_defense_target as anything in GLOB.all_active_defenses) + if(z != potential_defense_target.z) + continue + + var/distance = get_dist(src, potential_defense_target) + + if(distance > ai_range) + continue - if(length(viable_humans)) - return pick(viable_humans) + viable_targets += potential_defense_target - if(length(viable_vehicles)) - return pick(viable_vehicles) + if(smallest_distance <= distance) + continue + + closest_target = potential_defense_target + smallest_distance = distance + + var/extra_check_distance = round(smallest_distance * EXTRA_CHECK_DISTANCE_MULTIPLIER) + + if(extra_check_distance < 1) + return closest_target + + var/list/extra_checked = orange(extra_check_distance, closest_target) + + var/list/final_targets = extra_checked & viable_targets + + return length(final_targets) ? pick(final_targets) : closest_target + +#undef EXTRA_CHECK_DISTANCE_MULTIPLIER - if(length(viable_defenses)) - return pick(viable_defenses) +/mob/living/carbon/xenomorph/proc/check_mob_target(mob/living/carbon/human/checked_human) + if(checked_human.species.flags & IS_SYNTHETIC) + return FALSE + + if(FACTION_XENOMORPH in checked_human.faction_group) + return FALSE + + if(checked_human.stat != CONSCIOUS) + return FALSE + + return TRUE /mob/living/carbon/xenomorph/proc/make_ai() SHOULD_CALL_PARENT(TRUE)