Add a unit test to check that maploaded simple/basic mobs are in an environment they can survive in. (#82180)

## About The Pull Request
I've recently noticed that the maploaded penguins from the snowdin away
mission were dying from unsafe atmos/temperature. This sparked the idea
of making a (focus only) unit test that would prevent this sort of
issues from happening.

This PR also implements the usage of the `atmos_requirements` and
`body_temp_sensitive` elements for simple animals too, cutting down the
copypaste.

## Why It's Good For The Game
More unit tests to make sure things are done correctly.

## Changelog

🆑
fix: Made sure that mapped critters (i.e. penguins on the snow cabin
away mission) can survive in the environment they're spawned in.
/🆑
This commit is contained in:
Ghom
2024-03-27 16:01:56 -06:00
committed by GitHub
parent 772d508e29
commit 95b7fa1fb7
56 changed files with 310 additions and 273 deletions
@@ -41,7 +41,7 @@
death_sound = 'sound/voice/hiss6.ogg'
death_message = "lets out a waning guttural screech, green blood bubbling from its maw..."
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
unsuitable_atmos_damage = FALSE
unsuitable_heat_damage = 20
+21 -12
View File
@@ -93,9 +93,9 @@
var/minimum_survivable_temperature = NPC_DEFAULT_MIN_TEMP
///Maximal body temperature without receiving damage
var/maximum_survivable_temperature = NPC_DEFAULT_MAX_TEMP
///This damage is taken when the body temp is too cold. Set both this and unsuitable_heat_damage to 0 to avoid adding the basic_body_temp_sensitive element.
///This damage is taken when the body temp is too cold. Set both this and unsuitable_heat_damage to 0 to avoid adding the body_temp_sensitive element.
var/unsuitable_cold_damage = 1
///This damage is taken when the body temp is too hot. Set both this and unsuitable_cold_damage to 0 to avoid adding the basic_body_temp_sensitive element.
///This damage is taken when the body temp is too hot. Set both this and unsuitable_cold_damage to 0 to avoid adding the body_temp_sensitive element.
var/unsuitable_heat_damage = 1
/mob/living/basic/Initialize(mapload)
@@ -115,23 +115,32 @@
if(speak_emote)
speak_emote = string_list(speak_emote)
apply_atmos_requirements()
apply_temperature_requirements()
///We need to wait for SSair to be initialized before we can check atmos/temp requirements.
if(PERFORM_ALL_TESTS(focus_only/atmos_and_temp_requirements) && mapload && !SSair.initialized)
RegisterSignal(SSair, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(on_ssair_init))
return
apply_atmos_requirements(mapload)
apply_temperature_requirements(mapload)
/mob/living/basic/proc/on_ssair_init(datum/source)
SIGNAL_HANDLER
UnregisterSignal(SSair, COMSIG_SUBSYSTEM_POST_INITIALIZE)
apply_atmos_requirements(TRUE)
apply_temperature_requirements(TRUE)
/// Ensures this mob can take atmospheric damage if it's supposed to
/mob/living/basic/proc/apply_atmos_requirements()
if(unsuitable_atmos_damage == 0)
/mob/living/basic/proc/apply_atmos_requirements(mapload)
if(unsuitable_atmos_damage == 0 || isnull(habitable_atmos))
return
//String assoc list returns a cached list, so this is like a static list to pass into the element below.
habitable_atmos = string_assoc_list(habitable_atmos)
AddElement(/datum/element/atmos_requirements, habitable_atmos, unsuitable_atmos_damage)
AddElement(/datum/element/atmos_requirements, habitable_atmos, unsuitable_atmos_damage, mapload)
/// Ensures this mob can take temperature damage if it's supposed to
/mob/living/basic/proc/apply_temperature_requirements()
if(unsuitable_cold_damage == 0 && unsuitable_heat_damage == 0)
/mob/living/basic/proc/apply_temperature_requirements(mapload)
if((unsuitable_cold_damage == 0 && unsuitable_heat_damage == 0) || (minimum_survivable_temperature <= 0 && maximum_survivable_temperature >= INFINITY))
return
AddElement(/datum/element/basic_body_temp_sensitive, minimum_survivable_temperature, maximum_survivable_temperature, unsuitable_cold_damage, unsuitable_heat_damage)
AddElement(/datum/element/body_temp_sensitive, minimum_survivable_temperature, maximum_survivable_temperature, unsuitable_cold_damage, unsuitable_heat_damage, mapload)
/mob/living/basic/Life(seconds_per_tick = SSMOBS_DT, times_fired)
. = ..()
@@ -219,7 +228,7 @@
RemoveElement(/datum/element/atmos_requirements, habitable_atmos, unsuitable_atmos_damage)
. = TRUE
if(NAMEOF(src, minimum_survivable_temperature), NAMEOF(src, maximum_survivable_temperature), NAMEOF(src, unsuitable_cold_damage), NAMEOF(src, unsuitable_heat_damage))
RemoveElement(/datum/element/basic_body_temp_sensitive, minimum_survivable_temperature, maximum_survivable_temperature, unsuitable_cold_damage, unsuitable_heat_damage)
RemoveElement(/datum/element/body_temp_sensitive, minimum_survivable_temperature, maximum_survivable_temperature, unsuitable_cold_damage, unsuitable_heat_damage)
. = TRUE
. = ..()
@@ -10,7 +10,7 @@
combat_mode = TRUE
bubble_icon = "blob"
speak_emote = null
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
minimum_survivable_temperature = 0
maximum_survivable_temperature = INFINITY
lighting_cutoff_red = 20
+1 -1
View File
@@ -16,7 +16,7 @@ GLOBAL_LIST_INIT(command_strings, list(
icon_state = "medibot0"
base_icon_state = "medibot"
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, STAMINA = 0, OXY = 0)
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
hud_possible = list(DIAG_STAT_HUD, DIAG_BOT_HUD, DIAG_HUD, DIAG_BATT_HUD, DIAG_PATH_HUD = HUD_LIST_LIST)
maximum_survivable_temperature = INFINITY
minimum_survivable_temperature = 0
@@ -39,7 +39,7 @@
can_be_held = TRUE
held_w_class = WEIGHT_CLASS_TINY
environment_smash = ENVIRONMENT_SMASH_NONE
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
basic_mob_flags = DEL_ON_DEATH
ai_controller = /datum/ai_controller/basic_controller/bee
///the reagent the bee has
@@ -49,5 +49,5 @@
/// Cold resistent and doesn't need to breathe
/mob/living/basic/deer/ice
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
minimum_survivable_temperature = 0
@@ -129,7 +129,7 @@
faction = list(ROLE_SYNDICATE)
ponycolors = list("#5d566f", COLOR_RED)
pressure_resistance = 200
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
minimum_survivable_temperature = 0
maximum_survivable_temperature = 1500
unique_tamer = TRUE
@@ -8,7 +8,7 @@
gender = NEUTER
mob_biotypes = NONE
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, STAMINA = 0, OXY = 0)
speed = 0
melee_attack_cooldown = CLICK_CD_MELEE
@@ -16,7 +16,7 @@
pixel_x = -16
base_pixel_x = -16
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
faction = list(FACTION_JUNGLE)
obj_damage = 30
environment_smash = ENVIRONMENT_SMASH_WALLS
@@ -148,7 +148,7 @@
attack_sound = 'sound/creatures/venus_trap_hit.ogg'
unsuitable_heat_damage = 5 // heat damage is different from cold damage since coldmos is significantly more common than plasmafires
unsuitable_cold_damage = 2 // they now do take cold damage, but this should be sufficiently small that it does not cause major issues
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
unsuitable_atmos_damage = 0
/// copied over from the code from eyeballs (the mob) to make it easier for venus human traps to see in kudzu that doesn't have the transparency mutation
sight = SEE_SELF|SEE_MOBS|SEE_OBJS|SEE_TURFS
@@ -9,7 +9,7 @@
status_flags = CANSTUN|CANKNOCKDOWN|CANPUSH
mouse_opacity = MOUSE_OPACITY_ICON
combat_mode = TRUE
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
minimum_survivable_temperature = 0
health = 125
maxHealth = 125
@@ -38,6 +38,13 @@
collar_icon_state = "bullterrier"
held_state = "bullterrier"
/mob/living/basic/pet/dog/bullterrier/lavaland_party
name = "Saint Nick's Helpful Associate"
desc = "Undergraduate in 'Being a Good Boy'."
habitable_atmos = null
gold_core_spawnable = NO_SPAWN
unique_pet = TRUE
/mob/living/basic/pet/dog/breaddog //Most of the code originates from Cak
name = "Kobun"
real_name = "Kobun"
@@ -72,3 +72,10 @@
// A more docile subtype that won't attack other animals.
/mob/living/basic/pet/fox/docile
ai_controller = /datum/ai_controller/basic_controller/fox/docile
/mob/living/basic/pet/fox/icemoon
name = "icemoon fox"
desc = "A fox, scraping by the icemoon hostile atmosphere."
gold_core_spawnable = NO_SPAWN
habitable_atmos = null
minimum_survivable_temperature = ICEBOX_MIN_TEMPERATURE
@@ -13,7 +13,7 @@
light_range = 6
light_color = "#64bee1"
health = 100
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
unsuitable_atmos_damage = 0
can_buckle_to = FALSE
density = FALSE
@@ -196,4 +196,10 @@
/mob/living/basic/pet/penguin/baby/permanent
can_grow_up = FALSE
/mob/living/basic/pet/penguin/emperor/snowdin
minimum_survivable_temperature = ICEBOX_MIN_TEMPERATURE
gold_core_spawnable = NO_SPAWN
/mob/living/basic/pet/penguin/baby/permanent/snowdin
minimum_survivable_temperature = ICEBOX_MIN_TEMPERATURE
gold_core_spawnable = NO_SPAWN
@@ -33,7 +33,7 @@
faction = list(FACTION_RUSSIAN)
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
minimum_survivable_temperature = TCMB
maximum_survivable_temperature = T0C + 1500
ai_controller = /datum/ai_controller/basic_controller/bear
@@ -41,7 +41,7 @@
butcher_results = list(/obj/item/food/fishmeat/carp = 2, /obj/item/stack/sheet/animalhide/carp = 1)
greyscale_config = /datum/greyscale_config/carp
ai_controller = /datum/ai_controller/basic_controller/carp
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
minimum_survivable_temperature = 0
maximum_survivable_temperature = 1500
@@ -36,7 +36,7 @@
death_message = "screams in agony as it sublimates into a sulfurous smoke."
death_sound = 'sound/magic/demon_dies.ogg'
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
minimum_survivable_temperature = T0C - 25 //Weak to cold
maximum_survivable_temperature = INFINITY
@@ -30,7 +30,7 @@
faction = list(FACTION_SPOOKY)
speak_emote = list("telepathically cries")
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
minimum_survivable_temperature = T0C
maximum_survivable_temperature = T0C + 1500
sight = SEE_SELF|SEE_MOBS|SEE_OBJS|SEE_TURFS
@@ -29,7 +29,7 @@
speech_span = SPAN_ROBOT
death_message = "blows apart!"
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
minimum_survivable_temperature = TCMB
ai_controller = /datum/ai_controller/basic_controller/hivebot
///does this type do range attacks?
@@ -22,7 +22,7 @@
response_disarm_simple = "gently push"
faction = list()
ai_controller = /datum/ai_controller/basic_controller/meteor_heart
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
minimum_survivable_temperature = 0
maximum_survivable_temperature = 1500
combat_mode = TRUE
@@ -15,7 +15,7 @@
maxHealth = 150
health = 150
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
minimum_survivable_temperature = TCMB
obj_damage = 50
@@ -33,7 +33,7 @@
response_harm_simple = "punch through"
unsuitable_atmos_damage = 0
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, STAMINA = 0, OXY = 0) //I don't know how you'd apply those, but revenants no-sell them anyway.
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
minimum_survivable_temperature = 0
maximum_survivable_temperature = INFINITY
@@ -109,6 +109,11 @@
. = ..()
AddElement(/datum/element/web_walker, /datum/movespeed_modifier/fast_web)
///Used in the caves away mission.
/mob/living/basic/spider/giant/hunter/away_caves
minimum_survivable_temperature = 0
gold_core_spawnable = NO_SPAWN
/**
* ### Scout Spider
* A subtype of the giant spider which is faster, has thermal vision, but less health and damage.
@@ -166,6 +171,11 @@
///The health HUD applied to the mob.
var/health_hud = DATA_HUD_MEDICAL_ADVANCED
///Used in the caves away mission.
/mob/living/basic/spider/giant/nurse/away_caves
minimum_survivable_temperature = 0
gold_core_spawnable = NO_SPAWN
/mob/living/basic/spider/giant/nurse/Initialize(mapload)
. = ..()
var/datum/atom_hud/datahud = GLOB.huds[health_hud]
@@ -464,7 +474,7 @@
*/
/mob/living/basic/spider/giant/ice
name = "giant ice spider"
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
minimum_survivable_temperature = 0
maximum_survivable_temperature = 1500
color = rgb(114,228,250)
@@ -478,7 +488,7 @@
*/
/mob/living/basic/spider/giant/nurse/ice
name = "giant ice spider"
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
minimum_survivable_temperature = 0
maximum_survivable_temperature = 1500
poison_type = /datum/reagent/consumable/frostoil
@@ -492,7 +502,7 @@
*/
/mob/living/basic/spider/giant/hunter/ice
name = "giant ice spider"
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
minimum_survivable_temperature = 0
maximum_survivable_temperature = 1500
poison_type = /datum/reagent/consumable/frostoil
@@ -22,7 +22,7 @@
health = 10
minimum_survivable_temperature = TCMB
maximum_survivable_temperature = T0C + 1250
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
death_message = "falls to the ground, its shard dulling to a miserable grey!"
faction = list(FACTION_HOSTILE)
@@ -41,7 +41,7 @@
lighting_cutoff_red = 20
lighting_cutoff_green = 10
lighting_cutoff_blue = 40
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
minimum_survivable_temperature = 0
maximum_survivable_temperature = INFINITY
ai_controller = /datum/ai_controller/basic_controller/wumborian_fugu
@@ -64,7 +64,7 @@
desc = "Pray for your life, syndicate. Run while you can."
maxHealth = 150
health = 150
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
habitable_atmos = null
unsuitable_cold_damage = 0
casingtype = /obj/item/ammo_casing/energy/laser
burst_shots = 3
@@ -40,7 +40,6 @@
var/static/list/roach_drops = list(/obj/effect/decal/cleanable/insectguts)
AddElement(/datum/element/death_drops, roach_drops)
AddElement(/datum/element/swabable, cockroach_cell_line, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 7)
AddElement(/datum/element/basic_body_temp_sensitive, 270, INFINITY)
AddComponent( \
/datum/component/squashable, \
squash_chance = 50, \
+21 -7
View File
@@ -52,13 +52,7 @@
ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
if(prob(1))
name = "rare frog"
desc = "They seem a little smug."
icon_state = "rare_frog"
icon_living = "rare_frog"
icon_dead = "rare_frog_dead"
butcher_results = list(/obj/item/food/nugget = 5)
poison_type = /datum/reagent/drug/mushroomhallucinogen
make_rare()
var/static/list/loc_connections = list(
COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
@@ -68,6 +62,15 @@
AddElement(/datum/element/ai_retaliate)
AddElement(/datum/element/swabable, CELL_LINE_TABLE_FROG, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
/mob/living/basic/frog/proc/make_rare()
name = "rare frog"
desc = "They seem a little smug."
icon_state = "rare_[icon_state]"
icon_living = "rare_[icon_living]"
icon_dead = "rare_[icon_dead]"
butcher_results = list(/obj/item/food/nugget = 5)
poison_type = /datum/reagent/drug/mushroomhallucinogen
/mob/living/basic/frog/proc/on_entered(datum/source, AM as mob|obj)
SIGNAL_HANDLER
if(!stat && isliving(AM))
@@ -75,6 +78,17 @@
if(L.mob_size > MOB_SIZE_TINY)
playsound(src, stepped_sound, 50, TRUE)
/mob/living/basic/frog/icemoon_facility
name = "Peter Jr."
desc = "They seem a little cold."
minimum_survivable_temperature = ICEBOX_MIN_TEMPERATURE
habitable_atmos = null
gold_core_spawnable = NO_SPAWN
/mob/living/basic/frog/icemoon_facility/make_rare()
. = ..()
name = "Peter Sr." //make him senior.
/mob/living/basic/frog/frog_suicide
name = "suicide frog"
desc = "Driven by sheer will."
@@ -53,3 +53,10 @@
/datum/ai_planning_subtree/target_retaliate,
/datum/ai_planning_subtree/basic_melee_attack_subtree,
)
///Subtype used in the caves away mission
/mob/living/basic/bat/away_caves
name = "cave bat"
desc = "A rare breed of bat which roosts deep in caves."
minimum_survivable_temperature = 0
gold_core_spawnable = NO_SPAWN