From fdfaf83b22da7943abe06db69ab05211ba7f4422 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Thu, 2 Nov 2023 21:36:44 +0100 Subject: [PATCH] [MIRROR] Mobs will not path into dangerous turfs. [MDB IGNORE] (#24739) * Mobs will not path into dangerous turfs. (#79428) ## About The Pull Request Fixes #79255 Fixes #79272 Fixes #79313 Fixes #79328 As it turns out, "basic avoidance" and "dumb" AI pathfinding were both broken with regards to dangerous turfs, as was "random walk" idle behavior. Now, these three things will properly avoid turfs that could kill the mob. The global typecache of dangerous turfs has been removed, in favor of a turf-level proc, `can_cross_safely`, which returns TRUE or FALSE based on whether a movable atom can cross the turf without being harmed. This obviously defaults to TRUE, and is overridden for the four dangerous turf types: - **Space** can be safely crossed only with TRAIT_SPACEWALK. While space does not directly cause harm, being sent drifting away is not desirable behavior. - **Chasms** and **open space** can be safely crossed with TRAIT_MOVE_FLYING. - **Lava** can be safely crossed with TRAIT_MOVE_FLYING or TRAIT_LAVA_IMMUNE. If an AI's pathfinding would take it through a dangerous turf, or if it tries to randomly step onto one, the movement will be cancelled. ## Why It's Good For The Game Basic mobs have all been ignoring dangerous terrain this whole time. This means that mobs on Lavaland could walk right into chasms, mobs on multi-Z stations could be tricked into falling into pits, and so on. In the case of idle movement, no checks were happening whatsoever, causing similar problems without players ever being involved. Notably, skeleton mobs on certain away missions were randomly wandering into lava, causing one of our many random CI failures of the last week. They won't do that anymore. All told, this should make AI behavior a little more believable, by giving basic mobs literally any sense whatsoever of self-preservation. ## Changelog :cl: fix: Basic mobs will no longer randomly walk into terrain that harms or kills them. /:cl: --------- Co-authored-by: Jacquerel * Mobs will not path into dangerous turfs. --------- Co-authored-by: lizardqueenlexi <105025397+lizardqueenlexi@users.noreply.github.com> Co-authored-by: Jacquerel --- code/_globalvars/lists/mobs.dm | 6 ------ code/datums/ai/idle_behaviors/idle_random_walk.dm | 7 +++++-- code/datums/ai/movement/ai_movement_basic_avoidance.dm | 4 ++-- code/datums/ai/movement/ai_movement_dumb.dm | 4 ++-- code/game/turfs/open/chasm.dm | 3 +++ code/game/turfs/open/lava.dm | 3 +++ code/game/turfs/open/openspace.dm | 3 +++ code/game/turfs/open/space/space.dm | 3 +++ code/game/turfs/turf.dm | 6 +++++- 9 files changed, 26 insertions(+), 13 deletions(-) diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index 45c69734d6d..d72ca6fb5c9 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -6,12 +6,6 @@ GLOBAL_LIST_EMPTY(deadmins) //all ckeys who have used the de-admin verb. GLOBAL_LIST_EMPTY(directory) //all ckeys with associated client GLOBAL_LIST_EMPTY(stealthminID) //reference list with IDs that store ckeys, for stealthmins -GLOBAL_LIST_INIT(dangerous_turfs, typecacheof(list( - /turf/open/lava, - /turf/open/chasm, - /turf/open/space, - /turf/open/openspace))) - /// List of types of abstract mob which shouldn't usually exist in the world on its own if we're spawning random mobs GLOBAL_LIST_INIT(abstract_mob_types, list( /mob/living/basic/blob_minion, diff --git a/code/datums/ai/idle_behaviors/idle_random_walk.dm b/code/datums/ai/idle_behaviors/idle_random_walk.dm index f189e89b423..8924da5c30b 100644 --- a/code/datums/ai/idle_behaviors/idle_random_walk.dm +++ b/code/datums/ai/idle_behaviors/idle_random_walk.dm @@ -10,7 +10,10 @@ if(SPT_PROB(walk_chance, seconds_per_tick) && (living_pawn.mobility_flags & MOBILITY_MOVE) && isturf(living_pawn.loc) && !living_pawn.pulledby) var/move_dir = pick(GLOB.alldirs) - living_pawn.Move(get_step(living_pawn, move_dir), move_dir) + var/turf/destination_turf = get_step(living_pawn, move_dir) + if(!destination_turf?.can_cross_safely(living_pawn)) + return + living_pawn.Move(destination_turf, move_dir) /datum/idle_behavior/idle_random_walk/less_walking walk_chance = 10 @@ -69,7 +72,7 @@ var/turf/possible_step = get_step(living_pawn, direction) if(get_dist(possible_step, target) > minimum_distance) continue - if(possible_step.is_blocked_turf()) + if(possible_step.is_blocked_turf() || !possible_step.can_cross_safely(living_pawn)) continue possible_turfs += possible_step diff --git a/code/datums/ai/movement/ai_movement_basic_avoidance.dm b/code/datums/ai/movement/ai_movement_basic_avoidance.dm index 371fb9dbc4b..ad5b51a0ca3 100644 --- a/code/datums/ai/movement/ai_movement_basic_avoidance.dm +++ b/code/datums/ai/movement/ai_movement_basic_avoidance.dm @@ -17,8 +17,8 @@ . = ..() var/turf/target_turf = get_step_towards(source.moving, source.target) - if(is_type_in_typecache(target_turf, GLOB.dangerous_turfs)) - . = FALSE + if(!target_turf?.can_cross_safely(source.moving)) + . = MOVELOOP_SKIP_STEP return . /// Move immediately and don't update our facing diff --git a/code/datums/ai/movement/ai_movement_dumb.dm b/code/datums/ai/movement/ai_movement_dumb.dm index a38024ff2cc..041f1a967c2 100644 --- a/code/datums/ai/movement/ai_movement_dumb.dm +++ b/code/datums/ai/movement/ai_movement_dumb.dm @@ -15,6 +15,6 @@ . = ..() var/turf/target_turf = get_step_towards(source.moving, source.target) - if(is_type_in_typecache(target_turf, GLOB.dangerous_turfs)) - . = FALSE + if(!target_turf?.can_cross_safely(source.moving)) + . = MOVELOOP_SKIP_STEP return . diff --git a/code/game/turfs/open/chasm.dm b/code/game/turfs/open/chasm.dm index 3af4d12b176..f4094c35b36 100644 --- a/code/game/turfs/open/chasm.dm +++ b/code/game/turfs/open/chasm.dm @@ -76,6 +76,9 @@ /turf/open/chasm/proc/apply_components(mapload) AddComponent(/datum/component/chasm, GET_TURF_BELOW(src), mapload) +/turf/open/chasm/can_cross_safely(atom/movable/crossing) + return HAS_TRAIT(src, TRAIT_CHASM_STOPPED) || HAS_TRAIT(crossing, TRAIT_MOVE_FLYING) + // Chasms for Lavaland, with planetary atmos and lava glow /turf/open/chasm/lavaland initial_gas_mix = LAVALAND_DEFAULT_ATMOS diff --git a/code/game/turfs/open/lava.dm b/code/game/turfs/open/lava.dm index 623da55f104..ebcfd4d3843 100644 --- a/code/game/turfs/open/lava.dm +++ b/code/game/turfs/open/lava.dm @@ -315,6 +315,9 @@ burn_living.adjust_fire_stacks(lava_firestacks * seconds_per_tick) burn_living.ignite_mob() +/turf/open/lava/can_cross_safely(atom/movable/crossing) + return HAS_TRAIT(src, TRAIT_LAVA_STOPPED) || HAS_TRAIT(crossing, immunity_trait ) || HAS_TRAIT(crossing, TRAIT_MOVE_FLYING) + /turf/open/lava/smooth name = "lava" baseturfs = /turf/open/lava/smooth diff --git a/code/game/turfs/open/openspace.dm b/code/game/turfs/open/openspace.dm index 8b8b7ca00c6..bd74acab440 100644 --- a/code/game/turfs/open/openspace.dm +++ b/code/game/turfs/open/openspace.dm @@ -166,6 +166,9 @@ PlaceOnTop(/turf/open/floor/plating, flags = flags) PlaceOnTop(new_floor_path, flags = flags) +/turf/open/openspace/can_cross_safely(atom/movable/crossing) + return HAS_TRAIT(crossing, TRAIT_MOVE_FLYING) + /turf/open/openspace/icemoon name = "ice chasm" baseturfs = /turf/open/openspace/icemoon diff --git a/code/game/turfs/open/space/space.dm b/code/game/turfs/open/space/space.dm index 182e918dc33..049309c262b 100644 --- a/code/game/turfs/open/space/space.dm +++ b/code/game/turfs/open/space/space.dm @@ -254,6 +254,9 @@ GLOBAL_LIST_EMPTY(starlight) destination_y = dest_y destination_z = dest_z +/turf/open/space/can_cross_safely(atom/movable/crossing) + return HAS_TRAIT(crossing, TRAIT_SPACEWALK) + /turf/open/space/openspace icon = 'icons/turf/floors.dmi' icon_state = MAP_SWITCH("pure_white", "invisible") diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index a16c5710521..2bee06e7c49 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -6,7 +6,7 @@ GLOBAL_LIST_EMPTY(station_turfs) vis_flags = VIS_INHERIT_ID // Important for interaction with and visualization of openspace. luminosity = 1 light_height = LIGHTING_HEIGHT_FLOOR - + ///what /mob/oranges_ear instance is already assigned to us as there should only ever be one. ///used for guaranteeing there is only one oranges_ear per turf when assigned, speeds up view() iteration var/mob/oranges_ear/assigned_oranges_ear @@ -756,3 +756,7 @@ GLOBAL_LIST_EMPTY(station_turfs) explosive_resistance -= get_explosive_block() inherent_explosive_resistance = explosion_block explosive_resistance += get_explosive_block() + +/// Returns whether it is safe for an atom to move across this turf +/turf/proc/can_cross_safely(atom/movable/crossing) + return TRUE