diff --git a/code/__DEFINES/atmospherics.dm b/code/__DEFINES/atmospherics.dm index 1eafe07b13..2f82e49462 100644 --- a/code/__DEFINES/atmospherics.dm +++ b/code/__DEFINES/atmospherics.dm @@ -68,6 +68,20 @@ #define TEMPERATURE_DAMAGE_COEFFICIENT 1.5 //This is used in handle_temperature_damage() for humans, and in reagents that affect body temperature. Temperature damage is multiplied by this amount. +#define SYNTH_PASSIVE_HEAT_GAIN 10 //Degrees C per handle_environment() Synths passively heat up. Mitigated by cooling efficiency. Can lead to overheating if not managed. +#define SYNTH_MAX_PASSIVE_GAIN_TEMP 250 //Degrees C that a synth can be heated up to by their internal heat gain, provided their cooling is insufficient to mitigate it. +#define SYNTH_MIN_PASSIVE_COOLING_TEMP -30 //Degrees C a synth can cool towards at very high cooling efficiency. +#define SYNTH_HEAT_EFFICIENCY_COEFF 0.005 //How quick the difference between the Synth and the environment starts to matter. The smaller the higher the difference has to be for the same change. +#define SYNTH_SINGLE_INFLUENCE_COOLING_EFFECT_CAP 3 //How big can the multiplier for heat / pressure cooling be in an optimal environment +#define SYNTH_TOTAL_ENVIRONMENT_EFFECT_CAP 2 //How big of an multiplier can the environment give in an optimal scenario (maximum efficiency in the end is at a lower cap, this mostly counters low coolant levels) +#define SYNTH_MAX_COOLING_EFFICIENCY 1.5 //The maximum possible cooling efficiency one can achieve at optimal conditions. +#define SYNTH_ACTIVE_COOLING_TEMP_BOUNDARY 10 //The minimum distance from room temperature a Synth needs to have for active cooling to actively cool. +#define SYNTH_ACTIVE_COOLING_LOW_PRESSURE_THRESHOLD 0.05 //At how much percentage of default pressure (or lower) active cooling gets a massive cost penalty. +#define SYNTH_ACTIVE_COOLING_LOW_PRESSURE_PENALTY 2.5 //By how much is active cooling cost multiplied if in a very-low-pressure environment? +#define SYNTH_ACTIVE_COOLING_MIN_ADJUSTMENT 5 //What is the minimum amount of temp you move towards the target point, even if it would be less with default calculations? +#define SYNTH_INTEGRATION_COOLANT_PENALTY 0.4 //Integrating coolant is multiplied with this for calculation of impact on passive cooling. +#define SYNTH_INTEGRATION_COOLANT_CAP 0.25 //Integrating coolant is capped at counting as current_blood * this number. This is so you can't just run on salglu or whatever. + #define BODYTEMP_NORMAL 310.15 //The natural temperature for a body #define BODYTEMP_AUTORECOVERY_DIVISOR 11 //This is the divisor which handles how much of the temperature difference between the current body temperature and 310.15K (optimal temperature) humans auto-regenerate each tick. The higher the number, the slower the recovery. This is applied each tick, so long as the mob is alive. #define BODYTEMP_AUTORECOVERY_MINIMUM 12 //Minimum amount of kelvin moved toward 310K per tick. So long as abs(310.15 - bodytemp) is more than 50. diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 9538cf91fa..0609b9dabe 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -79,7 +79,7 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list( #define isangel(A) (is_species(A, /datum/species/angel)) #define ismush(A) (is_species(A, /datum/species/mush)) #define isshadow(A) (is_species(A, /datum/species/shadow)) -#define isrobotic(A) (is_species(A, /datum/species/ipc) || is_species(A, /datum/species/synthliz)) +#define isrobotic(A) (is_species(A, /datum/species/ipc) || is_species(A, /datum/species/synthliz) || is_species(A, /datum/species/mammal/synthetic)) #define isdwarf(A) (is_species(A, /datum/species/dwarf)) // Citadel specific species diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index ca326ece5f..edc6f58eaf 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -121,6 +121,7 @@ #define TRAIT_ROBOTIC_ORGANISM "robotic_organism" #define TRAIT_ROBOT_RADSHIELDING "robot_radshielding" #define TRAIT_NOBREATH "no_breath" +#define TRAIT_AUXILIARY_LUNGS "auxiliary_lungs" //Lungs not neccessary required due to nobreath, but provides some other helpful function. #define TRAIT_ANTIMAGIC "anti_magic" #define TRAIT_HOLY "holy" #define TRAIT_DEPRESSION "depression" diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm index bbe801cfc2..a3a1a35888 100644 --- a/code/_globalvars/traits.dm +++ b/code/_globalvars/traits.dm @@ -55,6 +55,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_ROBOTIC_ORGANISM" = TRAIT_ROBOTIC_ORGANISM, "TRAIT_ROBOT_RADSHIELDING" = TRAIT_ROBOT_RADSHIELDING, "TRAIT_NOBREATH" = TRAIT_NOBREATH, + "TRAIT_AUXILIARY_LUNGS" = TRAIT_AUXILIARY_LUNGS, "TRAIT_ANTIMAGIC" = TRAIT_ANTIMAGIC, "TRAIT_HOLY" = TRAIT_HOLY, "TRAIT_DEPRESSION" = TRAIT_DEPRESSION, diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 36a3cd1f1a..144a38e728 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -35,6 +35,8 @@ GLOBAL_LIST_INIT(available_ui_styles, list( var/atom/movable/screen/devil/soul_counter/devilsouldisplay + var/atom/movable/screen/synth/coolant_counter/coolant_display + var/atom/movable/screen/action_intent var/atom/movable/screen/zone_select var/atom/movable/screen/pull_icon diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index e4a9dc24e8..83b8d7be48 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -80,6 +80,98 @@ icon_state = "power_display" screen_loc = ui_lingchemdisplay +#define ui_coolant_display "EAST,SOUTH+3:15" + +/atom/movable/screen/synth + invisibility = INVISIBILITY_ABSTRACT + + +/atom/movable/screen/synth/proc/clear() + invisibility = INVISIBILITY_ABSTRACT + +/atom/movable/screen/synth/proc/update_counter(mob/living/carbon/human/owner) + invisibility = 0 + +/atom/movable/screen/synth/coolant_counter + icon = 'icons/mob/screen_synth.dmi' + name = "Coolant System Readout" + icon_state = "coolant-3-1" + screen_loc = ui_coolant_display + var/jammed = 0 + +/atom/movable/screen/synth/coolant_counter/update_counter(mob/living/carbon/owner) + ..() + var/valuecolor = "#ff2525" + if(owner.stat == DEAD) + maptext = "
ERR-0F
" + icon_state = "coolant-3-1" + return + var/coolant_efficiency + var/coolant + if(!jammed) + coolant_efficiency = owner.get_cooling_efficiency() + coolant = owner.blood_volume + else + coolant_efficiency = rand(1, 15) / 10 + coolant = rand(1, 600) + jammed-- + if(coolant > BLOOD_VOLUME_SAFE * owner.blood_ratio) //I unfortunately have to use this else-if stack because switch doesn't support variables. + valuecolor = "#4bbd34" + else if(coolant > BLOOD_VOLUME_OKAY * owner.blood_ratio) + valuecolor = "#dabb0d" + else if(coolant > BLOOD_VOLUME_BAD * owner.blood_ratio) + valuecolor = "#dd8109" + else if(coolant > BLOOD_VOLUME_SURVIVE * owner.blood_ratio) + valuecolor = "#e7520d" + maptext = "
[round((coolant / (BLOOD_VOLUME_NORMAL * owner.blood_ratio)) * 100, 1)]
" + + var/efficiency_suffix + var/state_suffix + switch(coolant_efficiency) + if(-INFINITY to 0.4) + efficiency_suffix = "1" + if(0.4 to 0.75) + efficiency_suffix = "2" + if(0.75 to 0.95) + efficiency_suffix = "3" + if(0.95 to 1.3) + efficiency_suffix = "4" + else + efficiency_suffix = "5" + var/obj/item/organ/lungs/ipc/L = owner.getorganslot(ORGAN_SLOT_LUNGS) + if(istype(L) && L.is_cooling) + state_suffix = "2" + else + state_suffix = "1" + icon_state = "coolant-[efficiency_suffix]-[state_suffix]" + +/atom/movable/screen/synth/coolant_counter/examine(mob/user) + . = ..() + var/mob/living/carbon/human/owner = hud.mymob + if(owner.stat == DEAD) + return + var/coolant + var/total_efficiency + var/environ_efficiency + var/suitlink_efficiency + if(!jammed) + coolant = owner.blood_volume + total_efficiency = owner.get_cooling_efficiency() + environ_efficiency = owner.get_environment_cooling_efficiency() + suitlink_efficiency = owner.check_suitlinking() + else + coolant = rand(1, 600) + total_efficiency = rand(1, 15) / 10 + environ_efficiency = rand(1, 20) / 10 + . += "Performing internal cooling system diagnostics:" + . += "Coolant level: [coolant] units, [round((coolant / (BLOOD_VOLUME_NORMAL * owner.blood_ratio)) * 100, 0.1)] percent" + . += "Current Cooling Efficiency: [round(total_efficiency * 100, 0.1)] percent, [suitlink_efficiency ? "active suitlink detected, guaranteeing [suitlink_efficiency * 100]% environmental cooling efficiency." : "environment viability: [round(environ_efficiency * 100, 0.1)] percent."]" + +/atom/movable/screen/synth/coolant_counter/proc/jam(amount, cap = 20) + if(jammed > cap) //Preserve previous more impactful event. + return + jammed = min(jammed + amount, cap) + /datum/hud/human/New(mob/living/carbon/human/owner) ..() owner.overlay_fullscreen("see_through_darkness", /atom/movable/screen/fullscreen/see_through_darkness) @@ -359,6 +451,10 @@ sunlight_display.hud = src infodisplay += sunlight_display + coolant_display = new /atom/movable/screen/synth/coolant_counter //Coolant & cooling efficiency readouts for Synths. + coolant_display.hud = src + infodisplay += coolant_display + zone_select = new /atom/movable/screen/zone_sel() zone_select.icon = ui_style zone_select.hud = src diff --git a/code/controllers/subsystem/processing/quirks.dm b/code/controllers/subsystem/processing/quirks.dm index 74cd53b0ae..b3c8a6422f 100644 --- a/code/controllers/subsystem/processing/quirks.dm +++ b/code/controllers/subsystem/processing/quirks.dm @@ -48,6 +48,13 @@ PROCESSING_SUBSYSTEM_DEF(quirks) cli.prefs.save_character() if (!silent && LAZYLEN(cut)) to_chat(to_chat_target || user, "Some quirks have been cut from your character because of these quirks conflicting with your job assignment: [english_list(cut)].") + + var/mob/living/carbon/human/H = user + if(istype(H) && H.dna?.species) + var/datum/species/S = H.dna.species + if(S.remove_blacklisted_quirks(H)) + to_chat(to_chat_target || user, "Some quirks have been cut from your character due to them conflicting with your species: [english_list(S.removed_quirks)]") + /datum/controller/subsystem/processing/quirks/proc/quirk_path_by_name(name) return quirks[name] diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 3ded0310dd..a8e76d04ca 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -325,7 +325,7 @@ GENETICS SCANNER var/breathes = TRUE var/blooded = TRUE if(C.dna && C.dna.species) - if(HAS_TRAIT_FROM(C, TRAIT_NOBREATH, SPECIES_TRAIT)) + if(!HAS_TRAIT_FROM(C, TRAIT_AUXILIARY_LUNGS, SPECIES_TRAIT) && HAS_TRAIT_FROM(C, TRAIT_NOBREATH, SPECIES_TRAIT)) breathes = FALSE if(NOBLOOD in C.dna.species.species_traits) blooded = FALSE @@ -434,12 +434,13 @@ GENETICS SCANNER if(R) blood_type = R.name + if((C.scan_blood_volume() + C.integrating_blood) <= (BLOOD_VOLUME_SAFE * C.blood_ratio) && (C.scan_blood_volume() + C.integrating_blood) > (BLOOD_VOLUME_OKAY*C.blood_ratio)) - msg += "LOW blood level [blood_percent] %, [C.scan_blood_volume()] cl[C.integrating_blood? ", with [integrated_blood_percent] % of it integrating, [C.integrating_blood] cl " : ""]. type: [blood_type]\n" + msg += "LOW [HAS_TRAIT(C, TRAIT_ROBOTIC_ORGANISM) ? "coolant" : "blood"] level [blood_percent] %, [C.scan_blood_volume()] cl[C.integrating_blood? ", with [integrated_blood_percent] % of it integrating, [C.integrating_blood] cl " : ""]. type: [blood_type]\n" else if((C.scan_blood_volume() + C.integrating_blood) <= (BLOOD_VOLUME_OKAY * C.blood_ratio)) - msg += "CRITICAL blood level [blood_percent] %, [C.scan_blood_volume()] cl[C.integrating_blood? ", with [integrated_blood_percent] % of it integrating, [C.integrating_blood] cl " : ""]. type: [blood_type]\n" + msg += "CRITICAL [HAS_TRAIT(C, TRAIT_ROBOTIC_ORGANISM) ? "coolant" : "blood"] level [blood_percent] %, [C.scan_blood_volume()] cl[C.integrating_blood? ", with [integrated_blood_percent] % of it integrating, [C.integrating_blood] cl " : ""]. type: [blood_type]\n" else - msg += "Blood level [blood_percent] %, [C.scan_blood_volume()] cl[C.integrating_blood? ", with [integrated_blood_percent] % of it integrating, [C.integrating_blood] cl " : ""]. type: [blood_type]\n" + msg += "[HAS_TRAIT(C, TRAIT_ROBOTIC_ORGANISM) ? "Coolant" : "Blood"] level [blood_percent] %, [C.scan_blood_volume()] cl[C.integrating_blood? ", with [integrated_blood_percent] % of it integrating, [C.integrating_blood] cl " : ""]. type: [blood_type]\n" var/cyberimp_detect diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index f888927411..0bd3083a59 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -488,6 +488,9 @@ icon_state = "nanogel" var/being_applied = FALSE //No doafter stacking. +/obj/item/stack/medical/nanogel/one + amount = 1 + /obj/item/stack/medical/nanogel/try_heal(mob/living/M, mob/user, silent = FALSE) if(being_applied) to_chat(user, "You are already applying [src]!") diff --git a/code/modules/antagonists/abductor/equipment/glands/heal.dm b/code/modules/antagonists/abductor/equipment/glands/heal.dm index 8917e1661e..e995826af6 100644 --- a/code/modules/antagonists/abductor/equipment/glands/heal.dm +++ b/code/modules/antagonists/abductor/equipment/glands/heal.dm @@ -23,7 +23,7 @@ return var/obj/item/organ/lungs/lungs = owner.getorganslot(ORGAN_SLOT_LUNGS) - if((!lungs && !HAS_TRAIT(owner, TRAIT_NOBREATH)) || (lungs && (istype(lungs, /obj/item/organ/lungs/cybernetic)))) + if((!lungs && (HAS_TRAIT_FROM(owner, TRAIT_AUXILIARY_LUNGS, SPECIES_TRAIT) || !HAS_TRAIT(owner, TRAIT_NOBREATH))) || (lungs && (istype(lungs, /obj/item/organ/lungs/cybernetic)))) replace_lungs(lungs) return diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index 2a05639ad9..eabf2e2d0e 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -65,29 +65,30 @@ blood_volume = min(BLOOD_VOLUME_NORMAL, blood_volume + 0.5 * nutrition_ratio) //Effects of bloodloss - var/word = pick("dizzy","woozy","faint") - var/blood_effect_volume = blood_volume + integrating_blood - switch(blood_effect_volume) - if(BLOOD_VOLUME_MAXIMUM to BLOOD_VOLUME_EXCESS) - if(prob(10)) - to_chat(src, "You feel terribly bloated.") - if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE) - if(prob(5)) - to_chat(src, "You feel [word].") - adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.01, 1)) - if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY) - adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1)) - if(prob(5)) - blur_eyes(6) - to_chat(src, "You feel very [word].") - if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD) - adjustOxyLoss(5) - if(prob(15)) - Unconscious(rand(20,60)) - to_chat(src, "You feel extremely [word].") - if(-INFINITY to BLOOD_VOLUME_SURVIVE) - if(!HAS_TRAIT(src, TRAIT_NODEATH)) - death() + if(!HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM)) //Synths are immune to direct consequences of bloodloss, instead suffering penalties to heat exchange. + var/word = pick("dizzy","woozy","faint") + var/blood_effect_volume = blood_volume + integrating_blood + switch(blood_effect_volume) + if(BLOOD_VOLUME_MAXIMUM to BLOOD_VOLUME_EXCESS) + if(prob(10)) + to_chat(src, "You feel terribly bloated.") + if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE) + if(prob(5)) + to_chat(src, "You feel [word].") + adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.01, 1)) + if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY) + adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1)) + if(prob(5)) + blur_eyes(6) + to_chat(src, "You feel very [word].") + if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD) + adjustOxyLoss(5) + if(prob(15)) + Unconscious(rand(20,60)) + to_chat(src, "You feel extremely [word].") + if(-INFINITY to BLOOD_VOLUME_SURVIVE) + if(!HAS_TRAIT(src, TRAIT_NODEATH)) + death() var/temp_bleed = 0 //Bleeding out diff --git a/code/modules/mob/living/carbon/handle_corruption.dm b/code/modules/mob/living/carbon/handle_corruption.dm index 5ac2a2f616..b56752453b 100644 --- a/code/modules/mob/living/carbon/handle_corruption.dm +++ b/code/modules/mob/living/carbon/handle_corruption.dm @@ -37,7 +37,7 @@ var/list/whatmighthappen = list() whatmighthappen += list("avoided" = 3, "dropthing" = 1, "movetile" = 1, "shortdeaf" = 1, "flopover" = 1, "nutriloss" = 1, "selfflash" = 1, "harmies" = 1) if(corruption >= CORRUPTION_THRESHHOLD_MAJOR) - whatmighthappen += list("longdeaf" = 1, "longknockdown" = 1, "shortlimbdisable" = 1, "shortblind" = 1, "shortstun" = 1, "shortmute" = 1, "vomit" = 1, "halluscinate" = 1) + whatmighthappen += list("longdeaf" = 1, "longknockdown" = 1, "shortlimbdisable" = 1, "shortblind" = 1, "shortstun" = 1, "shortmute" = 1, "vomit" = 1, "hallucinate" = 1, "jamcoolanthud" = 1) if(corruption >= CORRUPTION_THRESHHOLD_CRITICAL) whatmighthappen += list("receporgandamage" = 1, "longlimbdisable" = 1, "blindmutedeaf" = 1, "longstun" = 1, "sleep" = 1, "inducetrauma" = 1, "amplifycorrupt" = 1, "changetemp" = 1) var/event = pickweight(whatmighthappen) @@ -97,8 +97,10 @@ if("vomit") to_chat(src, "Ejecting contaminant.") vomit() - if("halluscinate") + if("hallucinate") hallucination += 20 //Doesn't give a cue + if("jamcoolanthud") + hud_used.coolant_display.jam(10) if("receporgandamage") adjustOrganLoss(ORGAN_SLOT_EARS, rand(10, 20)) adjustOrganLoss(ORGAN_SLOT_EYES, rand(10, 20)) @@ -159,7 +161,7 @@ /mob/living/carbon/proc/forcesleep(time = 100) to_chat(src, "Preparations complete, powering down.") - Sleeping(time, 0) + Sleeping(time) #undef CORRUPTION_CHECK_INTERVAL diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 0e75595c75..c3fb82de36 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -249,16 +249,17 @@ if(DISGUST_LEVEL_DISGUSTED to INFINITY) msg += "[t_He] look[p_s()] extremely disgusted.\n" - var/apparent_blood_volume = blood_volume - if(dna.species.use_skintones && skin_tone == "albino") - apparent_blood_volume -= 150 // enough to knock you down one tier - switch(apparent_blood_volume) - if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE) - msg += "[t_He] [t_has] pale skin.\n" - if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY) - msg += "[t_He] look[p_s()] like pale death.\n" - if(-INFINITY to BLOOD_VOLUME_BAD) - msg += "[t_He] resemble[p_s()] a crushed, empty juice pouch.\n" + if(!HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM)) + var/apparent_blood_volume = blood_volume + if(dna.species.use_skintones && skin_tone == "albino") + apparent_blood_volume -= 150 // enough to knock you down one tier + switch(apparent_blood_volume) + if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE) + msg += "[t_He] [t_has] pale skin.\n" + if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY) + msg += "[t_He] look[p_s()] like pale death.\n" + if(-INFINITY to BLOOD_VOLUME_BAD) + msg += "[t_He] resemble[p_s()] a crushed, empty juice pouch.\n" if(bleedsuppress) msg += "[t_He] [t_is] embued with a power that defies bleeding.\n" // only statues and highlander sword can cause this so whatever diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 16ab351d64..71573abc90 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -416,6 +416,7 @@ severity *= 0.5 var/do_not_stun = FALSE if(HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM)) + hud_used?.coolant_display.jam(round(severity / 10, 1)) //Messes up the cooling system readout. severity *= 0.5 //Robotpeople take less limb damage, but instead suffer system corruption (see carbon emp_act) do_not_stun = TRUE for(var/obj/item/bodypart/L in src.bodyparts) diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 85f01e63b3..1ea28211af 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -30,6 +30,8 @@ /mob/living/carbon/human/PhysicalLife(seconds, times_fired) if(!(. = ..())) return + if(HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM) && hud_used) + hud_used.coolant_display.update_counter(src) //Update our name based on whether our face is obscured/disfigured name = get_visible_name() @@ -76,9 +78,23 @@ /mob/living/carbon/human/check_breath(datum/gas_mixture/breath) - var/L = getorganslot(ORGAN_SLOT_LUNGS) + if(breath && HAS_TRAIT(src, TRAIT_NOBREATH) && HAS_TRAIT(src, TRAIT_AUXILIARY_LUNGS)) //Something something bz and synth cooling systems interacting (in reality, this only exists to not make robot lings too strong) + var/total_moles = breath.total_moles() + var/pressure = breath.return_pressure() + #define PP_MOLES(X) ((X / total_moles) * pressure) + #define PP(air, gas) PP_MOLES(air.get_moles(gas)) + var/bz_pp = PP(breath, GAS_BZ) + if(bz_pp > 1) + reagents.add_reagent(/datum/reagent/bz_metabolites,5) + else if(bz_pp > 0.1) + reagents.add_reagent(/datum/reagent/bz_metabolites,1) + #undef PP_MOLES + #undef PP + var/L = getorganslot(ORGAN_SLOT_LUNGS) if(!L) + if(HAS_TRAIT(src, TRAIT_NOBREATH)) + return if(health >= crit_threshold) adjustOxyLoss(HUMAN_MAX_OXYLOSS + 1) else if(!HAS_TRAIT(src, TRAIT_NOCRITDAMAGE)) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index d81297d41f..1c5bdb6114 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -108,6 +108,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) var/burnmod = 1 ///multiplier for damage from cold temperature var/coldmod = 1 + ///moves their safe minimum temp by this value. + var/cold_offset = 0 + ///moves their safe maximum temp by this value. + var/hot_offset = 0 ///multiplier for damage from hot temperature var/heatmod = 1 ///multiplier for stun durations @@ -147,6 +151,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) var/list/blacklisted_quirks = list() // Quirks that will be removed upon gaining this species, to be defined by species var/list/removed_quirks = list() // Quirks that got removed due to being blacklisted, and will be restored when on_species_loss() is called + var/balance_point_values = FALSE //If true, will balance point values on species gain after removing blacklisted quirks. Use this for roundstart species with blacklisted quirks that people may attempt to use to powergame trait points. ///Punch-specific attack verb. var/attack_verb = "punch" @@ -331,7 +336,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) var/should_have_brain = TRUE var/should_have_heart = !(NOBLOOD in species_traits) - var/should_have_lungs = !(TRAIT_NOBREATH in inherent_traits) + var/should_have_lungs = ((TRAIT_AUXILIARY_LUNGS in inherent_traits) || !(TRAIT_NOBREATH in inherent_traits)) var/should_have_appendix = !(TRAIT_NOHUNGER in inherent_traits) var/should_have_eyes = TRUE var/should_have_ears = TRUE @@ -569,17 +574,39 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) for(var/obj/item/bodypart/B in C.bodyparts) B.change_bodypart_status(initial(B.status), FALSE, TRUE) + if((TRAIT_ROBOTIC_ORGANISM in inherent_traits) && C.hud_used) + C.hud_used.coolant_display.clear() + SEND_SIGNAL(C, COMSIG_SPECIES_LOSS, src) // shamelessly inspired by antag_datum.remove_blacklisted_quirks() /datum/species/proc/remove_blacklisted_quirks(mob/living/carbon/C) - var/mob/living/L = C.mind?.current - if(istype(L)) - for(var/q in L.roundstart_quirks) - var/datum/quirk/Q = q - if(Q.type in blacklisted_quirks) - qdel(Q) - removed_quirks += Q.type + . = 0 + if(istype(C)) + if(!balance_point_values) + for(var/q in C.roundstart_quirks) + var/datum/quirk/Q = q + if(Q.type in blacklisted_quirks) + removed_quirks += Q.type + . += 1 + qdel(Q) + else + var/point_overhead = 0 + for(var/datum/quirk/Q as anything in C.roundstart_quirks) + if(Q.type in blacklisted_quirks) + point_overhead -= Q.value + removed_quirks += Q.type + . += 1 + qdel(Q) + if(point_overhead) + for(var/datum/quirk/Q as anything in C.roundstart_quirks) + if(Q.value > 0) + point_overhead -= Q.value + removed_quirks += Q.type + . += 1 + qdel(Q) + if(!point_overhead) + break // restore any quirks that we removed /datum/species/proc/restore_quirks(mob/living/carbon/C) @@ -1165,7 +1192,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) var/takes_crit_damage = !HAS_TRAIT(H, TRAIT_NOCRITDAMAGE) if((H.health < H.crit_threshold) && takes_crit_damage) - H.adjustBruteLoss(1) + if(!HAS_TRAIT(H, TRAIT_ROBOTIC_ORGANISM)) + H.adjustBruteLoss(1) + else + H.adjustFireLoss(1) //Robots melt instead of taking brute. /datum/species/proc/spec_death(gibbed, mob/living/carbon/human/H) if(H) @@ -1874,7 +1904,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(BODY_ZONE_HEAD) if(!I.get_sharpness() && armor_block < 50) if(prob(I.force)) - if(HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM)) + if(HAS_TRAIT(H, TRAIT_ROBOTIC_ORGANISM)) H.adjustToxLoss(5, toxins_type = TOX_SYSCORRUPT) //Bonk! - Effectively 5 bonus damage else H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 20) @@ -2171,15 +2201,20 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) //Thermal protection (insulation) has mixed benefits in two situations (hot in hot places, cold in hot places) if(!H.on_fire) //If you're on fire, you do not heat up or cool down based on surrounding gases var/natural = 0 + var/cooling_efficiency = 1 if(H.stat != DEAD) natural = H.natural_bodytemperature_stabilization() + cooling_efficiency = H.get_cooling_efficiency() + + if(HAS_TRAIT(H, TRAIT_ROBOTIC_ORGANISM)) //Synths by default slowly heat up and need to lose said heat to the environment or active cooling. If you have very high cooling efficiency, you instead passively cool. + H.adjust_bodytemperature(SYNTH_PASSIVE_HEAT_GAIN * (1 - cooling_efficiency), (T0C + SYNTH_MIN_PASSIVE_COOLING_TEMP), (T0C + SYNTH_MAX_PASSIVE_GAIN_TEMP)) var/thermal_protection = 1 if(loc_temp < H.bodytemperature) //Place is colder than we are thermal_protection -= H.get_thermal_protection(loc_temp, TRUE) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to. if(H.bodytemperature < BODYTEMP_NORMAL) //we're cold, insulation helps us retain body heat and will reduce the heat we lose to the environment - H.adjust_bodytemperature((thermal_protection+1)*natural + max(thermal_protection * (loc_temp - H.bodytemperature) / BODYTEMP_COLD_DIVISOR, BODYTEMP_COOLING_MAX)) + H.adjust_bodytemperature((thermal_protection+1)*natural + max((thermal_protection * (loc_temp - H.bodytemperature) * cooling_efficiency) / BODYTEMP_COLD_DIVISOR, BODYTEMP_COOLING_MAX)) else //we're sweating, insulation hinders our ability to reduce heat - and it will reduce the amount of cooling you get from the environment - H.adjust_bodytemperature(natural*(1/(thermal_protection+1)) + max((thermal_protection * (loc_temp - H.bodytemperature) + BODYTEMP_NORMAL - H.bodytemperature) / BODYTEMP_COLD_DIVISOR , BODYTEMP_COOLING_MAX)) //Extra calculation for hardsuits to bleed off heat + H.adjust_bodytemperature(natural*(1/(thermal_protection+1)) + max(((thermal_protection * (loc_temp - H.bodytemperature) + BODYTEMP_NORMAL - H.bodytemperature) * cooling_efficiency) / BODYTEMP_COLD_DIVISOR , BODYTEMP_COOLING_MAX)) //Extra calculation for hardsuits to bleed off heat else //Place is hotter than we are thermal_protection -= H.get_thermal_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to. if(H.bodytemperature < BODYTEMP_NORMAL) //and we're cold, insulation enhances our ability to retain body heat but reduces the heat we get from the environment @@ -2203,7 +2238,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) H.throw_alert("tempfeel", /atom/movable/screen/alert/hot, 3) // +/- 50 degrees from 310K is the 'safe' zone, where no damage is dealt. - if(H.bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT && !HAS_TRAIT(H, TRAIT_RESISTHEAT)) + if(H.bodytemperature > (BODYTEMP_HEAT_DAMAGE_LIMIT + hot_offset) && !HAS_TRAIT(H, TRAIT_RESISTHEAT)) //Body temperature is too hot. SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "cold") @@ -2231,11 +2266,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) H.emote("scream") H.apply_damage(burn_damage, BURN) - else if(H.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT && !HAS_TRAIT(H, TRAIT_RESISTCOLD)) + else if(H.bodytemperature < (BODYTEMP_COLD_DAMAGE_LIMIT + cold_offset) && !HAS_TRAIT(H, TRAIT_RESISTCOLD)) SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "hot") SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "cold", /datum/mood_event/cold) //Apply cold slowdown - H.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/cold, multiplicative_slowdown = ((BODYTEMP_COLD_DAMAGE_LIMIT - H.bodytemperature) / COLD_SLOWDOWN_FACTOR)) + H.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/cold, multiplicative_slowdown = (((BODYTEMP_COLD_DAMAGE_LIMIT + cold_offset) - H.bodytemperature) / COLD_SLOWDOWN_FACTOR)) switch(H.bodytemperature) if(200 to BODYTEMP_COLD_DAMAGE_LIMIT) H.throw_alert("temp", /atom/movable/screen/alert/shiver, 1) diff --git a/code/modules/mob/living/carbon/human/species_types/anthropomorph.dm b/code/modules/mob/living/carbon/human/species_types/anthropomorph.dm index df129c6ff4..334f76c487 100644 --- a/code/modules/mob/living/carbon/human/species_types/anthropomorph.dm +++ b/code/modules/mob/living/carbon/human/species_types/anthropomorph.dm @@ -24,11 +24,18 @@ id = SPECIES_MAMMAL_SYNTHETIC species_traits = list(MUTCOLORS,NOTRANSSTING,EYECOLOR,LIPS,HAIR,ROBOTIC_LIMBS,HAS_FLESH,HAS_BONE,WINGCOLOR,HORNCOLOR) - inherent_traits = list(TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NO_PROCESS_FOOD, TRAIT_ROBOTIC_ORGANISM) + inherent_traits = list(TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NO_PROCESS_FOOD, TRAIT_ROBOTIC_ORGANISM, TRAIT_RESISTLOWPRESSURE, TRAIT_NOBREATH, TRAIT_AUXILIARY_LUNGS) inherent_biotypes = MOB_ROBOTIC|MOB_HUMANOID|MOB_BEAST meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/ipc gib_types = list(/obj/effect/gibspawner/ipc, /obj/effect/gibspawner/ipc/bodypartless) + + coldmod = 0.5 + heatmod = 1.2 + cold_offset = -125 //Can handle pretty cold environments, but it's still a slightly bad idea if you enter a room thats full of near-absolute-zero gas + blacklisted_quirks = list(/datum/quirk/coldblooded) + balance_point_values = TRUE + //Just robo looking parts. mutant_heart = /obj/item/organ/heart/ipc mutantlungs = /obj/item/organ/lungs/ipc @@ -47,5 +54,7 @@ attack_sound = 'sound/weapons/slash.ogg' miss_sound = 'sound/weapons/slashmiss.ogg' + exotic_bloodtype = "S" + exotic_blood_color = BLOOD_COLOR_OIL allowed_limb_ids = list("mammal","aquatic","avian", "human") species_category = "robot" diff --git a/code/modules/mob/living/carbon/human/species_types/ipc.dm b/code/modules/mob/living/carbon/human/species_types/ipc.dm index eb870f9624..4f6b940692 100644 --- a/code/modules/mob/living/carbon/human/species_types/ipc.dm +++ b/code/modules/mob/living/carbon/human/species_types/ipc.dm @@ -5,7 +5,7 @@ default_color = "00FF00" blacklisted = 0 sexes = 0 - inherent_traits = list(TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NO_PROCESS_FOOD, TRAIT_ROBOTIC_ORGANISM) + inherent_traits = list(TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NO_PROCESS_FOOD, TRAIT_ROBOTIC_ORGANISM, TRAIT_RESISTLOWPRESSURE, TRAIT_NOBREATH, TRAIT_AUXILIARY_LUNGS) species_traits = list(MUTCOLORS,NOEYES,NOTRANSSTING,HAS_FLESH,HAS_BONE,HAIR,ROBOTIC_LIMBS) hair_alpha = 210 inherent_biotypes = MOB_ROBOTIC|MOB_HUMANOID @@ -13,6 +13,12 @@ meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/ipc gib_types = list(/obj/effect/gibspawner/ipc, /obj/effect/gibspawner/ipc/bodypartless) + coldmod = 0.5 + heatmod = 1.2 + cold_offset = -125 //Can handle pretty cold environments, but it's still a slightly bad idea if you enter a room thats full of near-absolute-zero gas + blacklisted_quirks = list(/datum/quirk/coldblooded) + balance_point_values = TRUE + //Just robo looking parts. mutant_heart = /obj/item/organ/heart/ipc mutantlungs = /obj/item/organ/lungs/ipc @@ -26,7 +32,7 @@ //special cybernetic organ for getting power from apcs mutant_organs = list(/obj/item/organ/cyberimp/arm/power_cord) - exotic_bloodtype = "HF" + exotic_bloodtype = "S" exotic_blood_color = BLOOD_COLOR_OIL species_category = SPECIES_CATEGORY_ROBOT diff --git a/code/modules/mob/living/carbon/human/species_types/synthliz.dm b/code/modules/mob/living/carbon/human/species_types/synthliz.dm index b6a7e93c72..7fc2da1132 100644 --- a/code/modules/mob/living/carbon/human/species_types/synthliz.dm +++ b/code/modules/mob/living/carbon/human/species_types/synthliz.dm @@ -4,11 +4,18 @@ say_mod = "beeps" default_color = "00FF00" species_traits = list(MUTCOLORS,NOTRANSSTING,EYECOLOR,LIPS,HAIR,ROBOTIC_LIMBS,HAS_FLESH,HAS_BONE) - inherent_traits = list(TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NO_PROCESS_FOOD, TRAIT_ROBOTIC_ORGANISM) + inherent_traits = list(TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NO_PROCESS_FOOD, TRAIT_ROBOTIC_ORGANISM, TRAIT_RESISTLOWPRESSURE, TRAIT_NOBREATH, TRAIT_AUXILIARY_LUNGS) inherent_biotypes = MOB_ROBOTIC|MOB_HUMANOID mutant_bodyparts = list("ipc_antenna" = "Synthetic Lizard - Antennae","mam_tail" = "Synthetic Lizard", "mam_snouts" = "Synthetic Lizard - Snout", "legs" = "Digitigrade", "mam_body_markings" = "Synthetic Lizard - Plates", "taur" = "None") meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/ipc gib_types = list(/obj/effect/gibspawner/ipc, /obj/effect/gibspawner/ipc/bodypartless) + + coldmod = 0.5 + heatmod = 1.2 + cold_offset = -125 //Can handle pretty cold environments, but it's still a slightly bad idea if you enter a room thats full of near-absolute-zero gas + blacklisted_quirks = list(/datum/quirk/coldblooded) + balance_point_values = TRUE + //Just robo looking parts. mutant_heart = /obj/item/organ/heart/ipc mutantlungs = /obj/item/organ/lungs/ipc diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 28c5ca5334..9cc96f2ddd 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -659,7 +659,7 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put //used in human and monkey handle_environment() /mob/living/carbon/proc/natural_bodytemperature_stabilization() - if (HAS_TRAIT(src, TRAIT_COLDBLOODED)) + if(HAS_TRAIT(src, TRAIT_COLDBLOODED) || HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM)) return 0 //Return 0 as your natural temperature. Species proc handle_environment() will adjust your temperature based on this. var/body_temperature_difference = BODYTEMP_NORMAL - bodytemperature @@ -672,6 +672,49 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put return min(body_temperature_difference * metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR, max(body_temperature_difference, -BODYTEMP_AUTORECOVERY_MINIMUM/4)) if(BODYTEMP_HEAT_DAMAGE_LIMIT to INFINITY) return min((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), -BODYTEMP_AUTORECOVERY_MINIMUM) //We're dealing with negative numbers + +/mob/living/carbon/proc/get_cooling_efficiency() + if(!HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM)) + return 1 + + var/integration_bonus = min(blood_volume * SYNTH_INTEGRATION_COOLANT_CAP, integrating_blood * SYNTH_INTEGRATION_COOLANT_PENALTY) //Integration blood somewhat helps, though only at 40% impact and to a cap of 25% of current blood level. + var/blood_effective_volume = blood_volume + integration_bonus + var/coolant_efficiency = min(blood_effective_volume / BLOOD_VOLUME_SAFE, 1) //Low coolant is only a negative, adding more than needed will not help you. + var/environment_efficiency = get_environment_cooling_efficiency() + + return min(coolant_efficiency * environment_efficiency, SYNTH_MAX_COOLING_EFFICIENCY) + + +/mob/living/carbon/proc/get_environment_cooling_efficiency() + var/suitlink = check_suitlinking() + if(suitlink) + return suitlink //If you are wearing full EVA or lavaland hazard gear (on lavaland), assume it has been made to accomodate your cooling needs. + var/datum/gas_mixture/environment = loc.return_air() + if(!environment) + return 0 + + var/pressure = environment.return_pressure() + var/heat = environment.return_temperature() + + var/heat_efficiency = clamp(1 + ((bodytemperature - heat) * SYNTH_HEAT_EFFICIENCY_COEFF), 0, SYNTH_SINGLE_INFLUENCE_COOLING_EFFECT_CAP) + var/pressure_efficiency = clamp(pressure / ONE_ATMOSPHERE, 0, SYNTH_SINGLE_INFLUENCE_COOLING_EFFECT_CAP) + + var/total_environment_efficiency = min(heat_efficiency * pressure_efficiency, SYNTH_TOTAL_ENVIRONMENT_EFFECT_CAP) //At best, you can get 200% total + return total_environment_efficiency + +/mob/living/carbon/proc/check_suitlinking() + var/suit_item = get_item_by_slot(SLOT_WEAR_SUIT) + var/head_item = get_item_by_slot(SLOT_HEAD) + var/turf/T = get_turf(src) + + if(istype(head_item, /obj/item/clothing/head/helmet/space) && istype(suit_item, /obj/item/clothing/suit/space)) + return 1 + + if(T && is_mining_level(T.z) && istype(head_item, /obj/item/clothing/head/hooded/explorer) && istype(suit_item, /obj/item/clothing/suit/hooded/explorer)) + return 1 + + return 0 + ///////// //LIVER// ///////// diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index 650409b5cc..a47ac494bf 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -17,7 +17,6 @@ /datum/reagent/medicine/leporazine name = "Leporazine" description = "Leporazine will effectively regulate a patient's body temperature, ensuring it never leaves safe levels." - chemical_flags = REAGENT_ALL_PROCESS pH = 8.4 color = "#82b8aa" value = REAGENT_VALUE_COMMON @@ -693,7 +692,6 @@ reagent_state = LIQUID color = "#00FFFF" metabolization_rate = 0.25 * REAGENTS_METABOLISM - chemical_flags = REAGENT_ALL_PROCESS pH = 2 /datum/reagent/medicine/salbutamol/on_mob_life(mob/living/carbon/M) @@ -710,7 +708,6 @@ reagent_state = LIQUID color = "#FF6464" metabolization_rate = 0.25 * REAGENTS_METABOLISM - chemical_flags = REAGENT_ALL_PROCESS pH = 11 /datum/reagent/medicine/perfluorodecalin/on_mob_life(mob/living/carbon/human/M) @@ -920,7 +917,6 @@ reagent_state = LIQUID color = "#000000" metabolization_rate = 0.25 * REAGENTS_METABOLISM - chemical_flags = REAGENT_ALL_PROCESS overdose_threshold = 35 pH = 12 value = REAGENT_VALUE_UNCOMMON @@ -951,7 +947,6 @@ reagent_state = LIQUID color = "#D2FFFA" metabolization_rate = 0.25 * REAGENTS_METABOLISM - chemical_flags = REAGENT_ALL_PROCESS overdose_threshold = 30 pH = 10.2 @@ -1203,7 +1198,6 @@ description = "Restores oxygen loss. Overdose causes it instead." reagent_state = LIQUID color = "#13d2f0" - chemical_flags = REAGENT_ALL_PROCESS overdose_threshold = 30 pH = 9.7 @@ -1267,7 +1261,6 @@ reagent_state = LIQUID pH = 8.5 color = "#5dc1f0" - chemical_flags = REAGENT_ALL_PROCESS /datum/reagent/medicine/inaprovaline/on_mob_life(mob/living/carbon/M) if(M.losebreath >= 5) diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm index 663cf1fdd7..cf17ec8545 100644 --- a/code/modules/research/designs/medical_designs.dm +++ b/code/modules/research/designs/medical_designs.dm @@ -213,7 +213,7 @@ category = list("Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE -/datum/design/hypospray/mkii +/datum/design/hypospray_mkii name = "Hypospray Mk. II" id = "hypospray_mkii" build_type = PROTOLATHE @@ -222,6 +222,15 @@ category = list("Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL +/datum/design/nanogel + name = "Nanogel paste" + id = "nanogel" + build_type = PROTOLATHE | MECHFAB + materials = list(/datum/material/iron = 800, /datum/material/titanium = 500, /datum/material/gold = 100, /datum/material/diamond = 20) + build_path = /obj/item/stack/medical/nanogel/one + category = list("Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + /datum/design/blood_bag name = "Empty Blood Bag" desc = "A small sterilized plastic bag for blood." diff --git a/code/modules/research/techweb/nodes/robotics_nodes.dm b/code/modules/research/techweb/nodes/robotics_nodes.dm index 6248cd99aa..ee4fbd261b 100644 --- a/code/modules/research/techweb/nodes/robotics_nodes.dm +++ b/code/modules/research/techweb/nodes/robotics_nodes.dm @@ -28,7 +28,7 @@ display_name = "Advanced Robotics Research" description = "It can even do the dishes!" prereq_ids = list("robotics") - design_ids = list("borg_upgrade_diamonddrill", "borg_upgrade_advancedmop", "borg_upgrade_advcutter") + design_ids = list("borg_upgrade_diamonddrill", "borg_upgrade_advancedmop", "borg_upgrade_advcutter", "nanogel") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3000) /datum/techweb_node/neural_programming diff --git a/code/modules/surgery/organs/ears.dm b/code/modules/surgery/organs/ears.dm index 3787d4e781..80b7599ec3 100644 --- a/code/modules/surgery/organs/ears.dm +++ b/code/modules/surgery/organs/ears.dm @@ -148,14 +148,14 @@ return to_chat(owner, "Alert: Auditory systems corrupted!.") switch(severity) - if(1) - owner.Jitter(30) - owner.Dizzy(30) - owner.DefaultCombatKnockdown(80) - deaf = 30 - - if(2) + if(1 to 50) owner.Jitter(15) owner.Dizzy(15) owner.DefaultCombatKnockdown(40) + + if(50 to INFINITY) + owner.Jitter(30) + owner.Dizzy(30) + owner.DefaultCombatKnockdown(80) + deaf = max(deaf, 30) damage += 0.15 * severity diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm index cbb46242c3..f6265969e7 100644 --- a/code/modules/surgery/organs/lungs.dm +++ b/code/modules/surgery/organs/lungs.dm @@ -415,7 +415,7 @@ if(!.) return if(!failed && organ_flags & ORGAN_FAILING) - if(owner && owner.stat == CONSCIOUS) + if(owner && owner.stat == CONSCIOUS && !HAS_TRAIT(owner, TRAIT_NOBREATH)) owner.visible_message("[owner] grabs [owner.p_their()] throat, struggling for breath!", \ "You suddenly feel like you can't breathe!") failed = TRUE @@ -425,6 +425,10 @@ /obj/item/organ/lungs/ipc name = "ipc cooling system" icon_state = "lungs-c" + var/is_cooling = 0 + var/cooling_coolant_drain = 5 //Coolant (blood) use per tick of active cooling. + var/next_warn = BLOOD_VOLUME_NORMAL + actions_types = list(/datum/action/item_action/organ_action/toggle) /obj/item/organ/lungs/ipc/emp_act(severity) //Should probably put it somewhere else later . = ..() @@ -432,11 +436,65 @@ return to_chat(owner, "Alert: Critical cooling system failure!") switch(severity) - if(1) - owner.adjust_bodytemperature(100*TEMPERATURE_DAMAGE_COEFFICIENT) - if(2) + if(1 to 50) owner.adjust_bodytemperature(30*TEMPERATURE_DAMAGE_COEFFICIENT) + if(50 to INFINITY) + owner.adjust_bodytemperature(100*TEMPERATURE_DAMAGE_COEFFICIENT) + +/obj/item/organ/lungs/ipc/ui_action_click(mob/user, actiontype) + if(!owner) + return + if(!HAS_TRAIT(user, TRAIT_ROBOTIC_ORGANISM)) + to_chat(user, "Biotype incompatible with cooling system. Activation signal suppressed.") + return + if(!is_cooling && owner.blood_volume < cooling_coolant_drain) + to_chat(user, "Coolant levels insufficient to enable active cooling - Replenish immediately.") + return + is_cooling = !is_cooling + to_chat(user, "Active cooling [is_cooling ? "enabled" : "disabled"] - current coolant level: [round(owner.blood_volume / BLOOD_VOLUME_NORMAL * 100, 0.1)] percent.") + var/possible_next_warn = owner.blood_volume - (BLOOD_VOLUME_NORMAL * 0.1) + if(possible_next_warn > next_warn) + next_warn = possible_next_warn //If we recovered blood inbetween activations, update warning + +/obj/item/organ/lungs/ipc/on_life(seconds, times_fired) + . = ..() + if(!.) + if(is_cooling) + to_chat(owner, "Cooling system safeguards triggered - active cooling aborted.") + is_cooling = 0 + return + if(!is_cooling) + return + if(!HAS_TRAIT(owner, TRAIT_ROBOTIC_ORGANISM)) + to_chat(owner, "Biotype incompatible with cooling system. Commencing emergency shutdown.") + is_cooling = 0 + return + if(owner.stat >= SOFT_CRIT) + to_chat(owner, "Operating system ping returned null response - Shutting down active cooling to avoid component damage.") + is_cooling = 0 + return + if(owner.blood_volume < cooling_coolant_drain) + to_chat(owner, "Coolant levels insufficient to maintain active cooling - Replenish immediately.") + is_cooling = 0 + return + if(abs(owner.bodytemperature - T20C) < SYNTH_ACTIVE_COOLING_TEMP_BOUNDARY) + return //Does not drain coolant (blood) nor do anything if we are close enough to room temp. + var/cooling_efficiency = owner.get_cooling_efficiency() + var/actual_drain = cooling_coolant_drain * max(1 - cooling_efficiency, 0.2) //Being in a suitable environment reduces drain by up to 80% + var/temp_diff = owner.bodytemperature - T20C + if(temp_diff > 0) + owner.adjust_bodytemperature(clamp(((T0C - owner.bodytemperature) * max(cooling_efficiency, 0.5) / BODYTEMP_COLD_DIVISOR), BODYTEMP_COOLING_MAX, -SYNTH_ACTIVE_COOLING_MIN_ADJUSTMENT)) + else + owner.adjust_bodytemperature(clamp(((T20C - owner.bodytemperature) * max(cooling_efficiency, 0.5) / BODYTEMP_HEAT_DIVISOR), SYNTH_ACTIVE_COOLING_MIN_ADJUSTMENT, BODYTEMP_HEATING_MAX)) + var/datum/gas_mixture/air = owner.loc.return_air() + if(!air || air.return_pressure() < ONE_ATMOSPHERE * SYNTH_ACTIVE_COOLING_LOW_PRESSURE_THRESHOLD) + actual_drain *= SYNTH_ACTIVE_COOLING_LOW_PRESSURE_PENALTY //Our cooling system can handle hot places okayish, but starts to cry at low pressures (reads: Effectively vents hot coolant thats been warmed up via internal heat-exchange as emergency measure and with very low efficiency) + owner.blood_volume = max(owner.blood_volume - actual_drain, 0) + if(owner.blood_volume <= next_warn) + to_chat(owner, "[owner.blood_volume > BLOOD_VOLUME_BAD ? "" : ""]Coolant level passed threshold - now [round(owner.blood_volume / BLOOD_VOLUME_NORMAL * 100, 0.1)] percent.") + next_warn -= (BLOOD_VOLUME_NORMAL * 0.1) + /obj/item/organ/lungs/plasmaman name = "plasma filter" desc = "A spongy rib-shaped mass for filtering plasma from the air." diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index de8e3d623d..a3c6ea06c8 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -249,7 +249,7 @@ var/breathes = TRUE var/blooded = TRUE if(dna && dna.species) - if(HAS_TRAIT_FROM(src, TRAIT_NOBREATH, SPECIES_TRAIT)) + if(!HAS_TRAIT_FROM(src, TRAIT_AUXILIARY_LUNGS, SPECIES_TRAIT) && HAS_TRAIT_FROM(src, TRAIT_NOBREATH, SPECIES_TRAIT)) breathes = FALSE if(NOBLOOD in dna.species.species_traits) blooded = FALSE diff --git a/code/modules/surgery/organs/stomach.dm b/code/modules/surgery/organs/stomach.dm index f436b31513..f7b84eab20 100644 --- a/code/modules/surgery/organs/stomach.dm +++ b/code/modules/surgery/organs/stomach.dm @@ -136,11 +136,11 @@ if(!owner || . & EMP_PROTECT_SELF) return switch(severity) - if(1) - owner.nutrition = min(owner.nutrition - 50, 0) + if(1 to 50) + owner.nutrition = max(owner.nutrition - 50, 0) to_chat(owner, "Alert: Detected severe battery discharge!") - if(2) - owner.nutrition = min(owner.nutrition - 100, 0) + if(50 to INFINITY) + owner.nutrition = max(owner.nutrition - 100, 0) to_chat(owner, "Alert: Minor battery discharge!") /obj/item/organ/stomach/ethereal diff --git a/icons/mob/screen_synth.dmi b/icons/mob/screen_synth.dmi new file mode 100644 index 0000000000..95ecc5e2bb Binary files /dev/null and b/icons/mob/screen_synth.dmi differ