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
@@ -2601,9 +2601,7 @@
pixel_x = 15;
pixel_y = 14
},
/mob/living/basic/frog{
name = "Peter Jr."
},
/mob/living/basic/frog/icemoon_facility,
/turf/open/floor/plating/icemoon,
/area/ruin/plasma_facility/operations)
"TK" = (
@@ -145,7 +145,7 @@
},
/area/ruin/unpowered/buried_library)
"aO" = (
/mob/living/basic/pet/fox,
/mob/living/basic/pet/fox/icemoon,
/turf/open/floor/wood{
initial_gas_mix = "ICEMOON_ATMOS"
},
@@ -327,7 +327,7 @@
/area/ruin/unpowered/buried_library)
"cA" = (
/obj/effect/decal/cleanable/dirt,
/mob/living/basic/pet/fox,
/mob/living/basic/pet/fox/icemoon,
/turf/open/floor/wood{
initial_gas_mix = "ICEMOON_ATMOS"
},
@@ -394,7 +394,7 @@
/obj/structure/fluff/paper{
dir = 1
},
/mob/living/basic/pet/fox,
/mob/living/basic/pet/fox/icemoon,
/turf/open/floor/wood{
initial_gas_mix = "ICEMOON_ATMOS"
},
@@ -208,9 +208,7 @@
"nq" = (
/obj/effect/decal/cleanable/cobweb,
/obj/machinery/light/small/directional/north,
/mob/living/basic/pet/dog/bullterrier{
name = "Saint Nick's Helpful Associate"
},
/mob/living/basic/pet/dog/bullterrier/lavaland_party,
/turf/open/floor/carpet/blue/lavaland,
/area/ruin/unpowered)
"nI" = (
+2 -2
View File
@@ -3002,7 +3002,7 @@
set_luminosity = 6;
light_color = "#9bbbff"
},
/mob/living/basic/pet/penguin/baby/permanent,
/mob/living/basic/pet/penguin/baby/permanent/snowdin,
/turf/open/misc/ice/smooth,
/area/awaymission/cabin/snowforest)
"sK" = (
@@ -3725,7 +3725,7 @@
set_luminosity = 6;
light_color = "#9bbbff"
},
/mob/living/basic/pet/penguin/emperor,
/mob/living/basic/pet/penguin/emperor/snowdin,
/turf/open/misc/ice/smooth,
/area/awaymission/cabin/snowforest)
"Aa" = (
+10 -19
View File
@@ -1260,7 +1260,7 @@
},
/area/awaymission/caves/bmp_asteroid/level_two)
"kE" = (
/mob/living/basic/spider/giant/hunter,
/mob/living/basic/spider/giant/hunter/away_caves,
/turf/open/floor/iron,
/area/awaymission/caves/bmp_asteroid)
"kL" = (
@@ -1332,7 +1332,7 @@
/area/awaymission/caves/northblock)
"pC" = (
/obj/item/mjollnir,
/mob/living/basic/spider/giant/nurse,
/mob/living/basic/spider/giant/nurse/away_caves,
/turf/open/misc/asteroid/basalt{
initial_gas_mix = "n2=23;o2=14;TEMP=2.7"
},
@@ -1432,7 +1432,7 @@
/obj/machinery/sleeper{
dir = 8
},
/mob/living/basic/spider/giant/hunter,
/mob/living/basic/spider/giant/hunter/away_caves,
/turf/open/floor/iron,
/area/awaymission/caves/bmp_asteroid)
"uO" = (
@@ -1590,7 +1590,7 @@
},
/area/awaymission/caves/bmp_asteroid/level_two)
"Bz" = (
/mob/living/basic/spider/giant/nurse,
/mob/living/basic/spider/giant/nurse/away_caves,
/turf/open/misc/asteroid/basalt{
initial_gas_mix = "n2=23;o2=14;TEMP=2.7"
},
@@ -1672,7 +1672,7 @@
"FS" = (
/obj/machinery/light/small/built/directional/north,
/obj/structure/spider/stickyweb,
/mob/living/basic/spider/giant/hunter,
/mob/living/basic/spider/giant/hunter/away_caves,
/turf/open/floor/iron,
/area/awaymission/caves/bmp_asteroid)
"FV" = (
@@ -1856,10 +1856,7 @@
/turf/open/floor/iron,
/area/awaymission/caves/listeningpost)
"Qe" = (
/mob/living/basic/bat{
desc = "A rare breed of bat which roosts deep in caves.";
name = "Cave Bat"
},
/mob/living/basic/bat/away_caves,
/turf/open/misc/asteroid/basalt{
initial_gas_mix = "n2=23;o2=14;TEMP=2.7"
},
@@ -1871,10 +1868,7 @@
},
/area/awaymission/caves/bmp_asteroid/level_four)
"Rt" = (
/mob/living/basic/bat{
desc = "A rare breed of bat which roosts deep in caves.";
name = "Cave Bat"
},
/mob/living/basic/bat/away_caves,
/turf/open/misc/asteroid/basalt{
initial_gas_mix = "n2=23;o2=14;TEMP=2.7"
},
@@ -1951,14 +1945,11 @@
/turf/open/floor/iron/recharge_floor,
/area/awaymission/caves/bmp_asteroid)
"Xa" = (
/mob/living/basic/bat{
desc = "A rare breed of bat which roosts deep in caves.";
name = "Cave Bat"
},
/mob/living/basic/bat/away_caves,
/turf/open/floor/iron,
/area/awaymission/caves/northblock)
"Xs" = (
/mob/living/basic/spider/giant/hunter,
/mob/living/basic/spider/giant/hunter/away_caves,
/turf/open/misc/asteroid/basalt{
initial_gas_mix = "n2=23;o2=14;TEMP=2.7"
},
@@ -1980,7 +1971,7 @@
/area/awaymission/caves/bmp_asteroid/level_two)
"XR" = (
/obj/structure/spider/stickyweb,
/mob/living/basic/spider/giant/hunter,
/mob/living/basic/spider/giant/hunter/away_caves,
/turf/open/misc/asteroid/basalt{
initial_gas_mix = "n2=23;o2=14;TEMP=2.7"
},
+1 -1
View File
@@ -57,7 +57,7 @@ PROCESSING_SUBSYSTEM_DEF(dcs)
var/datum/element/eletype = arguments[1]
var/list/fullid = list(eletype)
var/list/named_arguments
for(var/i in initial(eletype.argument_hash_start_idx) to length(arguments))
for(var/i in initial(eletype.argument_hash_start_idx) to (initial(eletype.argument_hash_end_idx) || length(arguments)))
var/key = arguments[i]
if(istext(key))
+8 -2
View File
@@ -10,14 +10,20 @@
/**
* The index of the first attach argument to consider for duplicate elements
*
* All arguments from this index onwards (1 based) are hashed into the key to determine
* if this is a new unique element or one already exists
* All arguments from this index onwards (1 based, until `argument_hash_end_idx` is reached, if set)
* are hashed into the key to determine if this is a new unique element or one already exists
*
* Is only used when flags contains [ELEMENT_BESPOKE]
*
* This is infinity so you must explicitly set this
*/
var/argument_hash_start_idx = INFINITY
/**
* The index of the last attach argument to consider for duplicate elements
* Only used when `element_flags` contains [ELEMENT_BESPOKE].
* If not set, it'll copy every argument from `argument_hash_start_idx` onwards as normal
*/
var/argument_hash_end_idx = 0
/// Activates the functionality defined by the element on the given target datum
/datum/element/proc/Attach(datum/target)
+44 -25
View File
@@ -6,21 +6,29 @@
/datum/element/atmos_requirements
element_flags = ELEMENT_BESPOKE
argument_hash_start_idx = 2
argument_hash_end_idx = 3
/// An assoc list of "what atmos does this mob require to survive in".
var/list/atmos_requirements
/// How much (brute) damage we take from being in unsuitable atmos.
var/unsuitable_atmos_damage
/datum/element/atmos_requirements/Attach(datum/target, list/atmos_requirements, unsuitable_atmos_damage = 5)
/datum/element/atmos_requirements/Attach(datum/target, list/atmos_requirements, unsuitable_atmos_damage = 5, mapload = FALSE)
. = ..()
if(!isliving(target))
return ELEMENT_INCOMPATIBLE
if(!atmos_requirements)
stack_trace("[type] added to [target] without any requirements specified.")
CRASH("[type] added to [target] without any requirements specified.")
var/list/short = atmos_requirements
if(!short["min_oxy"] && !short["max_oxy"] && !short["min_plas"] && !short["max_plas"] && !short["min_co2"] && !short["max_co2"] && !short["min_n2"] && !short["max_n2"])
CRASH("[type] added to [target] with all requirements set to 0.")
src.atmos_requirements = atmos_requirements
src.unsuitable_atmos_damage = unsuitable_atmos_damage
RegisterSignal(target, COMSIG_LIVING_HANDLE_BREATHING, PROC_REF(on_non_stasis_life))
if(!mapload || !PERFORM_ALL_TESTS(focus_only/atmos_and_temp_requirements))
return
check_safe_environment(target)
/datum/element/atmos_requirements/Detach(datum/target)
. = ..()
UnregisterSignal(target, COMSIG_LIVING_HANDLE_BREATHING)
@@ -42,34 +50,45 @@
return TRUE
var/turf/open/open_turf = target.loc
if(!open_turf.air && (atmos_requirements["min_oxy"] || atmos_requirements["min_tox"] || atmos_requirements["min_n2"] || atmos_requirements["min_co2"]))
return FALSE
if(isnull(open_turf.air))
if(atmos_requirements["min_oxy"] || atmos_requirements["min_plas"] || atmos_requirements["min_n2"] || atmos_requirements["min_co2"])
return FALSE
return TRUE
var/list/gases = get_atmos_req_list(open_turf)
if(!ISINRANGE(gases["oxy"], atmos_requirements["min_oxy"], (atmos_requirements["max_oxy"] || INFINITY)))
return FALSE
if(!ISINRANGE(gases["plas"], atmos_requirements["min_plas"], (atmos_requirements["max_plas"] || INFINITY)))
return FALSE
if(!ISINRANGE(gases["n2"], atmos_requirements["min_n2"], (atmos_requirements["max_n2"] || INFINITY)))
return FALSE
if(!ISINRANGE(gases["co2"], atmos_requirements["min_co2"], (atmos_requirements["max_co2"] || INFINITY)))
return FALSE
return TRUE
/datum/element/atmos_requirements/proc/get_atmos_req_list(turf/open/open_turf)
var/open_turf_gases = open_turf.air.gases
open_turf.air.assert_gases(/datum/gas/oxygen, /datum/gas/pluoxium, /datum/gas/nitrogen, /datum/gas/carbon_dioxide, /datum/gas/plasma)
var/plas = open_turf_gases[/datum/gas/plasma][MOLES]
var/oxy = open_turf_gases[/datum/gas/oxygen][MOLES] + (open_turf_gases[/datum/gas/pluoxium][MOLES] * PLUOXIUM_PROPORTION)
var/n2 = open_turf_gases[/datum/gas/nitrogen][MOLES]
var/co2 = open_turf_gases[/datum/gas/carbon_dioxide][MOLES]
var/list/return_gases = list()
return_gases["plas"] = open_turf_gases[/datum/gas/plasma][MOLES]
return_gases["oxy"] = open_turf_gases[/datum/gas/oxygen][MOLES] + (open_turf_gases[/datum/gas/pluoxium][MOLES] * PLUOXIUM_PROPORTION)
return_gases["n2"] = open_turf_gases[/datum/gas/nitrogen][MOLES]
return_gases["co2"] = open_turf_gases[/datum/gas/carbon_dioxide][MOLES]
open_turf.air.garbage_collect()
if(atmos_requirements["min_oxy"] && oxy < atmos_requirements["min_oxy"])
return FALSE
else if(atmos_requirements["max_oxy"] && oxy > atmos_requirements["max_oxy"])
return FALSE
else if(atmos_requirements["min_plas"] && plas < atmos_requirements["min_plas"])
return FALSE
else if(atmos_requirements["max_plas"] && plas > atmos_requirements["max_plas"])
return FALSE
else if(atmos_requirements["min_n2"] && n2 < atmos_requirements["min_n2"])
return FALSE
else if(atmos_requirements["max_n2"] && n2 > atmos_requirements["max_n2"])
return FALSE
else if(atmos_requirements["min_co2"] && co2 < atmos_requirements["min_co2"])
return FALSE
else if(atmos_requirements["max_co2"] && co2 > atmos_requirements["max_co2"])
return FALSE
return return_gases
return TRUE
///Ensures that maploaded mobs are in a safe environment. Unit test stuff.
/datum/element/atmos_requirements/proc/check_safe_environment(mob/living/living_mob)
if(living_mob.stat == DEAD || is_breathable_atmos(living_mob))
return
var/turf/open/open_turf = living_mob.loc
var/list/gases
var/string_text = "No Air"
if(open_turf.air)
gases = get_atmos_req_list(open_turf)
string_text = "O2: [gases["o2"]] - Plasma: [gases["plasma"]] - N2: [gases["n2"]] - CO2: [gases["co2"]]"
stack_trace("[living_mob] loaded on a turf with unsafe atmos at \[[open_turf.x], [open_turf.y], [open_turf.z]\] (area : [open_turf.loc]). Turf gases: [string_text]. Check the mob atmos requirements again.")
@@ -1,72 +0,0 @@
/**
* When attached to a basic mob, it gives it the ability to be hurt by cold/hot body temperatures
*/
/datum/element/basic_body_temp_sensitive
element_flags = ELEMENT_BESPOKE
argument_hash_start_idx = 2
///Min body temp
var/min_body_temp = 250
///Max body temp
var/max_body_temp = 350
////Damage when below min temp
var/cold_damage = 1
///Damage when above max temp
var/heat_damage = 1
/datum/element/basic_body_temp_sensitive/Attach(datum/target, min_body_temp, max_body_temp, cold_damage, heat_damage)
. = ..()
if(!isbasicmob(target))
return ELEMENT_INCOMPATIBLE
if(isnum(min_body_temp))
src.min_body_temp = min_body_temp
if(isnum(max_body_temp))
src.max_body_temp = max_body_temp
if(isnum(cold_damage))
src.cold_damage = cold_damage
if(isnum(heat_damage))
src.heat_damage = heat_damage
RegisterSignal(target, COMSIG_LIVING_LIFE, PROC_REF(on_life))
/datum/element/basic_body_temp_sensitive/Detach(datum/source)
if(source)
UnregisterSignal(source, COMSIG_LIVING_LIFE)
return ..()
/datum/element/basic_body_temp_sensitive/proc/on_life(datum/target, seconds_per_tick, times_fired)
SIGNAL_HANDLER
var/mob/living/basic/basic_mob = target
var/gave_alert = FALSE
if(basic_mob.bodytemperature < min_body_temp)
basic_mob.adjust_health(cold_damage * seconds_per_tick)
if(!basic_mob.has_status_effect(/datum/status_effect/inebriated))
switch(cold_damage)
if(1 to 5)
basic_mob.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 1)
if(5 to 10)
basic_mob.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 2)
if(10 to INFINITY)
basic_mob.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 3)
gave_alert = TRUE
else if(basic_mob.bodytemperature > max_body_temp)
basic_mob.adjust_health(heat_damage * seconds_per_tick)
switch(heat_damage)
if(1 to 5)
basic_mob.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 1)
if(5 to 10)
basic_mob.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 2)
if(10 to INFINITY)
basic_mob.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 3)
gave_alert = TRUE
if(!gave_alert)
basic_mob.clear_alert(ALERT_TEMPERATURE)
@@ -0,0 +1,86 @@
/**
* When attached to a basic mob, it gives it the ability to be hurt by cold/hot body temperatures
*/
/datum/element/body_temp_sensitive
element_flags = ELEMENT_BESPOKE
argument_hash_start_idx = 2
argument_hash_end_idx = 5
///Min body temp
var/min_body_temp = 250
///Max body temp
var/max_body_temp = 350
////Damage when below min temp
var/cold_damage = 1
///Damage when above max temp
var/heat_damage = 1
/datum/element/body_temp_sensitive/Attach(datum/target, min_body_temp, max_body_temp, cold_damage, heat_damage, mapload = FALSE)
. = ..()
if(!isliving(target))
return ELEMENT_INCOMPATIBLE
if(isnum(min_body_temp))
src.min_body_temp = min_body_temp
if(isnum(max_body_temp))
src.max_body_temp = max_body_temp
if(isnum(cold_damage))
src.cold_damage = cold_damage
if(isnum(heat_damage))
src.heat_damage = heat_damage
RegisterSignal(target, COMSIG_LIVING_LIFE, PROC_REF(on_life))
if(!mapload || !PERFORM_ALL_TESTS(focus_only/atmos_and_temp_requirements))
return
check_safe_environment(target)
/datum/element/body_temp_sensitive/Detach(datum/source)
if(source)
UnregisterSignal(source, COMSIG_LIVING_LIFE)
return ..()
/datum/element/body_temp_sensitive/proc/on_life(datum/target, seconds_per_tick, times_fired)
SIGNAL_HANDLER
var/mob/living/living_mob = target
var/gave_alert = FALSE
if(living_mob.bodytemperature < min_body_temp)
living_mob.adjustFireLoss(cold_damage * seconds_per_tick, forced = TRUE)
if(!living_mob.has_status_effect(/datum/status_effect/inebriated))
switch(cold_damage)
if(1 to 5)
living_mob.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 1)
if(5 to 10)
living_mob.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 2)
if(10 to INFINITY)
living_mob.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 3)
gave_alert = TRUE
else if(living_mob.bodytemperature > max_body_temp)
living_mob.adjustFireLoss(heat_damage * seconds_per_tick, forced = TRUE)
switch(heat_damage)
if(1 to 5)
living_mob.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 1)
if(5 to 10)
living_mob.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 2)
if(10 to INFINITY)
living_mob.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 3)
gave_alert = TRUE
if(!gave_alert)
living_mob.clear_alert(ALERT_TEMPERATURE)
///Ensures that maploaded mobs are in a safe environment. Unit test stuff.
/datum/element/body_temp_sensitive/proc/check_safe_environment(mob/living/living_mob)
if(living_mob.stat == DEAD)
return
var/atom/location = living_mob.loc
var/datum/gas_mixture/environment = location.return_air()
var/areatemp = living_mob.get_temperature(environment)
if(!ISINRANGE(areatemp, min_body_temp, max_body_temp))
stack_trace("[living_mob] loaded on in a loc with unsafe temperature at \[[location.x], [location.y], [location.z]\] (area : [get_area(location)]): [areatemp]K. Acceptable Range: [min_body_temp]K - [max_body_temp]K,")
@@ -134,6 +134,13 @@
/obj/effect/spawner/random/trash/cigbutt = 2,
)
/obj/effect/spawner/random/trash/grime/Initialize(mapload)
if(mapload)
var/turf/location = get_turf(loc)
if(location.initial_gas_mix != OPENTURF_DEFAULT_ATMOS && location.initial_gas_mix != OPENTURF_DIRTY_ATMOS)
loot -= /mob/living/basic/cockroach
return ..()
/obj/effect/spawner/random/trash/moisture
name = "water hazard spawner"
icon_state = "caution"
@@ -150,6 +157,13 @@
/mob/living/basic/axolotl = 1,
)
/obj/effect/spawner/random/trash/moisture/Initialize(mapload)
if(mapload)
var/turf/location = get_turf(loc)
if(location.initial_gas_mix != OPENTURF_DEFAULT_ATMOS && location.initial_gas_mix != OPENTURF_DIRTY_ATMOS)
loot -= list(/mob/living/basic/frog, /mob/living/basic/axolotl)
return ..()
/obj/effect/spawner/random/trash/graffiti
name = "random graffiti spawner"
icon_state = "rune"
@@ -172,8 +172,8 @@
* Also used in other chat-based gas scans.
*/
/proc/atmos_scan(mob/user, atom/target, silent=FALSE)
var/mixture = target.return_analyzable_air()
if(!mixture)
var/mixture = target.return_air()
if(mixture)
return FALSE
var/icon = target
@@ -45,7 +45,7 @@
speech_span = SPAN_ROBOT
death_message = "malfunctions!"
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/netguardian
@@ -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
@@ -7,7 +7,8 @@
stop_automated_movement = TRUE
wander = FALSE
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, STAMINA = 0, OXY = 0)
atmos_requirements = 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)
atmos_requirements = null
unsuitable_atmos_damage = 0
hud_possible = list(DIAG_STAT_HUD, DIAG_BOT_HUD, DIAG_HUD, DIAG_BATT_HUD, DIAG_PATH_HUD = HUD_LIST_LIST)
maxbodytemp = INFINITY
minbodytemp = 0
@@ -22,7 +22,7 @@
icon_living = "gondola"
loot = list(/obj/effect/decal/cleanable/blood/gibs, /obj/item/stack/sheet/animalhide/gondola = 1, /obj/item/food/meat/slab/gondola = 1)
//Gondolas aren't affected by cold.
atmos_requirements = 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)
atmos_requirements = null
minbodytemp = 0
maxbodytemp = 1500
maxHealth = 200
@@ -29,7 +29,7 @@
weather_immunities = list(TRAIT_LAVA_IMMUNE, TRAIT_ASHSTORM_IMMUNE)
minbodytemp = 0
maxbodytemp = INFINITY
atmos_requirements = 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)
atmos_requirements = null
loot = list(/obj/effect/decal/remains/human)
del_on_death = TRUE
@@ -14,7 +14,7 @@
robust_searching = TRUE
ranged_ignores_vision = TRUE
stat_attack = DEAD
atmos_requirements = 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)
atmos_requirements = null
damage_coeff = list(BRUTE = 1, BURN = 0.5, TOX = 1, STAMINA = 0, OXY = 1)
minbodytemp = 0
maxbodytemp = INFINITY
@@ -32,7 +32,7 @@ GLOBAL_LIST_INIT(animatable_blacklist, typecacheof(list(
speak_emote = list("creaks")
taunt_chance = 30
atmos_requirements = 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)
atmos_requirements = null
minbodytemp = 0
faction = list(FACTION_MIMIC)
@@ -1,7 +1,7 @@
//the base mining mob
/mob/living/simple_animal/hostile/asteroid
vision_range = 2
atmos_requirements = 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)
atmos_requirements = null
faction = list(FACTION_MINING)
weather_immunities = list(TRAIT_LAVA_IMMUNE,TRAIT_ASHSTORM_IMMUNE)
obj_damage = 30
@@ -10,7 +10,7 @@
gender = NEUTER
emote_see = list("jiggles", "bounces in place")
speak_emote = list("blorbles")
atmos_requirements = 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)
atmos_requirements = null
hud_type = /datum/hud/ooze
minbodytemp = 250
maxbodytemp = INFINITY
@@ -11,7 +11,7 @@
gender = NEUTER
environment_smash = ENVIRONMENT_SMASH_STRUCTURES
speak_emote = list("roars")
atmos_requirements = 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)
atmos_requirements = null
health = 250
maxHealth = 250
damage_coeff = list(BRUTE = 0.7, BURN = 0.7, TOX = 1, STAMINA = 0, OXY = 1)
@@ -16,7 +16,7 @@
attack_sound = 'sound/hallucinations/growl1.ogg'
attack_vis_effect = ATTACK_EFFECT_BITE
combat_mode = TRUE
atmos_requirements = 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)
atmos_requirements = null
minbodytemp = 0
status_flags = CANPUSH
death_message = "collapses, flesh gone in a pile of bones!"
@@ -176,7 +176,6 @@
add_traits(weather_immunities, ROUNDSTART_TRAIT)
if (environment_smash >= ENVIRONMENT_SMASH_WALLS)
AddElement(/datum/element/wall_smasher, strength_flag = environment_smash)
if(speak)
speak = string_list(speak)
if(speak_emote)
@@ -185,8 +184,6 @@
emote_hear = string_list(emote_hear)
if(emote_see)
emote_see = string_list(emote_hear)
if(atmos_requirements)
atmos_requirements = string_assoc_list(atmos_requirements)
if(damage_coeff)
damage_coeff = string_assoc_list(damage_coeff)
if(footstep_type)
@@ -196,6 +193,24 @@
if(isnull(unsuitable_heat_damage))
unsuitable_heat_damage = unsuitable_atmos_damage
///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
init_atmos_temp_requirement(mapload)
/mob/living/simple_animal/proc/on_ssair_init(datum/source)
SIGNAL_HANDLER
UnregisterSignal(SSair, COMSIG_SUBSYSTEM_POST_INITIALIZE)
init_atmos_temp_requirement(TRUE)
/mob/living/simple_animal/proc/init_atmos_temp_requirement(mapload)
if(atmos_requirements && unsuitable_atmos_damage)
atmos_requirements = string_assoc_list(atmos_requirements)
AddElement(/datum/element/atmos_requirements, atmos_requirements, unsuitable_atmos_damage, mapload)
if((unsuitable_cold_damage || unsuitable_heat_damage) && (minbodytemp > 0 || maxbodytemp < INFINITY))
AddElement(/datum/element/body_temp_sensitive, minbodytemp, maxbodytemp, unsuitable_cold_damage, unsuitable_heat_damage, mapload)
/mob/living/simple_animal/Life(seconds_per_tick = SSMOBS_DT, times_fired)
. = ..()
if(staminaloss > 0)
@@ -302,51 +317,6 @@
else
manual_emote(pick(emote_hear))
/mob/living/simple_animal/proc/environment_air_is_safe()
. = TRUE
if(pulledby && pulledby.grab_state >= GRAB_KILL && atmos_requirements["min_oxy"])
. = FALSE //getting choked
if(isturf(loc) && isopenturf(loc))
var/turf/open/ST = loc
if(ST.air)
var/ST_gases = ST.air.gases
ST.air.assert_gases(/datum/gas/oxygen, /datum/gas/pluoxium, /datum/gas/nitrogen, /datum/gas/carbon_dioxide, /datum/gas/plasma)
var/plas = ST_gases[/datum/gas/plasma][MOLES]
var/oxy = ST_gases[/datum/gas/oxygen][MOLES] + (ST_gases[/datum/gas/pluoxium][MOLES] * PLUOXIUM_PROPORTION)
var/n2 = ST_gases[/datum/gas/nitrogen][MOLES]
var/co2 = ST_gases[/datum/gas/carbon_dioxide][MOLES]
ST.air.garbage_collect()
if(atmos_requirements["min_oxy"] && oxy < atmos_requirements["min_oxy"])
. = FALSE
else if(atmos_requirements["max_oxy"] && oxy > atmos_requirements["max_oxy"])
. = FALSE
else if(atmos_requirements["min_plas"] && plas < atmos_requirements["min_plas"])
. = FALSE
else if(atmos_requirements["max_plas"] && plas > atmos_requirements["max_plas"])
. = FALSE
else if(atmos_requirements["min_n2"] && n2 < atmos_requirements["min_n2"])
. = FALSE
else if(atmos_requirements["max_n2"] && n2 > atmos_requirements["max_n2"])
. = FALSE
else if(atmos_requirements["min_co2"] && co2 < atmos_requirements["min_co2"])
. = FALSE
else if(atmos_requirements["max_co2"] && co2 > atmos_requirements["max_co2"])
. = FALSE
else
if(atmos_requirements["min_oxy"] || atmos_requirements["min_plas"] || atmos_requirements["min_n2"] || atmos_requirements["min_co2"])
. = FALSE
/mob/living/simple_animal/proc/environment_temperature_is_safe(datum/gas_mixture/environment)
. = TRUE
var/areatemp = get_temperature(environment)
if((areatemp < minbodytemp) || (areatemp > maxbodytemp))
. = FALSE
/mob/living/simple_animal/handle_environment(datum/gas_mixture/environment, seconds_per_tick, times_fired)
var/atom/A = loc
if(isturf(A))
@@ -359,42 +329,6 @@
else
adjust_bodytemperature(clamp(temp_delta * seconds_per_tick / temperature_normalization_speed, 0, temp_delta))
if(!environment_air_is_safe() && unsuitable_atmos_damage)
adjustHealth(unsuitable_atmos_damage * seconds_per_tick)
if(unsuitable_atmos_damage > 0)
throw_alert(ALERT_NOT_ENOUGH_OXYGEN, /atom/movable/screen/alert/not_enough_oxy)
else
clear_alert(ALERT_NOT_ENOUGH_OXYGEN)
handle_temperature_damage(seconds_per_tick, times_fired)
/mob/living/simple_animal/proc/handle_temperature_damage(seconds_per_tick, times_fired)
. = FALSE
if((bodytemperature < minbodytemp) && unsuitable_cold_damage)
adjustHealth(unsuitable_cold_damage * seconds_per_tick)
switch(unsuitable_cold_damage)
if(1 to 5)
throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 1)
if(5 to 10)
throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 2)
if(10 to INFINITY)
throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 3)
. = TRUE
if((bodytemperature > maxbodytemp) && unsuitable_heat_damage)
adjustHealth(unsuitable_heat_damage * seconds_per_tick)
switch(unsuitable_heat_damage)
if(1 to 5)
throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 1)
if(5 to 10)
throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 2)
if(10 to INFINITY)
throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 3)
. = TRUE
if(!.)
clear_alert(ALERT_TEMPERATURE)
/mob/living/simple_animal/gib()
if(butcher_results || guaranteed_butcher_results)
var/list/butcher = list()
@@ -27,7 +27,7 @@
bubble_icon = "slime"
initial_language_holder = /datum/language_holder/slime
atmos_requirements = 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)
atmos_requirements = null
maxHealth = 150
health = 150
@@ -44,3 +44,6 @@
/// Checks that the contents of the fish_counts list are also present in fish_table
/datum/unit_test/focus_only/fish_sources_tables
/// Checks that maploaded mobs with either the `atmos_requirements` or `body_temp_sensitive`
/datum/unit_test/focus_only/atmos_and_temp_requirements
+1 -1
View File
@@ -1360,12 +1360,12 @@
#include "code\datums\elements\attack_equip.dm"
#include "code\datums\elements\backblast.dm"
#include "code\datums\elements\bane.dm"
#include "code\datums\elements\basic_body_temp_sensitive.dm"
#include "code\datums\elements\basic_eating.dm"
#include "code\datums\elements\beauty.dm"
#include "code\datums\elements\bed_tucking.dm"
#include "code\datums\elements\befriend_petting.dm"
#include "code\datums\elements\blocks_explosives.dm"
#include "code\datums\elements\body_temp_sensitive.dm"
#include "code\datums\elements\bombable_turf.dm"
#include "code\datums\elements\bonus_damage.dm"
#include "code\datums\elements\bsa_blocker.dm"