diff --git a/baystation12.dme b/baystation12.dme index f589264002..5a899acba0 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -486,6 +486,7 @@ #include "code\game\objects\items\devices\pipe_painter.dm" #include "code\game\objects\items\devices\powersink.dm" #include "code\game\objects\items\devices\scanners.dm" +#include "code\game\objects\items\devices\suit_cooling.dm" #include "code\game\objects\items\devices\taperecorder.dm" #include "code\game\objects\items\devices\traitordevices.dm" #include "code\game\objects\items\devices\transfer_valve.dm" diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 351216b8bf..3253f272d0 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -10,7 +10,7 @@ var/last_bumped = 0 var/pass_flags = 0 var/throwpass = 0 - var/germ_level = 0 // The higher the germ level, the more germ on the atom. + var/germ_level = GERM_LEVEL_AMBIENT // The higher the germ level, the more germ on the atom. ///Chemistry. var/datum/reagents/reagents = null diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 1326e65e5e..41da5ea7c8 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -15,8 +15,8 @@ /atom/movable/Move() var/atom/A = src.loc . = ..() - src.move_speed = world.timeofday - src.l_move_time - src.l_move_time = world.timeofday + src.move_speed = world.time - src.l_move_time + src.l_move_time = world.time src.m_flag = 1 if ((A != src.loc && A && A.z == src.z)) src.last_move = get_dir(A, src.loc) diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm index 4e38f4fe44..d55417c5f5 100644 --- a/code/game/gamemodes/cult/cult_items.dm +++ b/code/game/gamemodes/cult/cult_items.dm @@ -98,7 +98,7 @@ item_state = "cult_armour" desc = "A bulky suit of armour, bristling with spikes. It looks space proof." w_class = 3 - allowed = list(/obj/item/weapon/tome,/obj/item/weapon/melee/cultblade,/obj/item/weapon/tank/emergency_oxygen) + allowed = list(/obj/item/weapon/tome,/obj/item/weapon/melee/cultblade,/obj/item/weapon/tank/emergency_oxygen,/obj/item/device/suit_cooling_unit) slowdown = 1 armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 30, rad = 30) siemens_coefficient = 0 \ No newline at end of file diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm index c400185a45..ec5529c80c 100644 --- a/code/game/machinery/adv_med.dm +++ b/code/game/machinery/adv_med.dm @@ -308,6 +308,13 @@ robot = "Prosthetic:" if(e.open) open = "Open:" + switch (e.germ_level) + if (INFECTION_LEVEL_ONE + 50 to INFECTION_LEVEL_TWO) + infected = "Mild Infection:" + if (INFECTION_LEVEL_TWO to INFECTION_LEVEL_THREE) + infected = "Acute Infection:" + if (INFECTION_LEVEL_THREE to INFINITY) + infected = "Septic:" var/unknown_body = 0 for(var/I in e.implants) @@ -332,8 +339,16 @@ mech = "Assisted:" if(i.robotic == 2) mech = "Mechanical:" + + var/infection = "None" + switch (i.germ_level) + if (1 to INFECTION_LEVEL_TWO) + infection = "Mild Infection:" + if (INFECTION_LEVEL_TWO to INFINITY) + infection = "Acute Infection:" + dat += "" - dat += "[i.name]N/A[i.damage]None:[mech]" + dat += "[i.name]N/A[i.damage][infection]:[mech]" dat += "" dat += "" if(occupant.sdisabilities & BLIND) diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index c0b230b4a7..22caeb2090 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -92,6 +92,17 @@ REAGENT SCANNER usr << "\red You don't have the dexterity to do this!" return user.visible_message(" [user] has analyzed [M]'s vitals."," You have analyzed [M]'s vitals.") + + if (!istype(M, /mob/living/carbon) || (ishuman(M) && (M:species.flags & IS_SYNTHETIC))) + //these sensors are designed for organic life + user.show_message("\blue Analyzing Results for ERROR:\n\t Overall Status: ERROR") + user.show_message("\t Key: Suffocation/Toxin/Burns/Brute", 1) + user.show_message("\t Damage Specifics: ? - ? - ? - ?") + user.show_message("\blue Body Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)", 1) + user.show_message("\red Warning: Blood Level ERROR: --% --cl.\blue Type: ERROR") + user.show_message("\blue Subject's pulse: -- bpm.") + return + var/fake_oxy = max(rand(1,40), M.getOxyLoss(), (300 - (M.getToxLoss() + M.getFireLoss() + M.getBruteLoss()))) var/OX = M.getOxyLoss() > 50 ? "[M.getOxyLoss()]" : M.getOxyLoss() var/TX = M.getToxLoss() > 50 ? "[M.getToxLoss()]" : M.getToxLoss() @@ -161,7 +172,7 @@ REAGENT SCANNER if(e.status & ORGAN_BROKEN) if(((e.name == "l_arm") || (e.name == "r_arm") || (e.name == "l_leg") || (e.name == "r_leg")) && (!(e.status & ORGAN_SPLINTED))) user << "\red Unsecured fracture in subject [limb]. Splinting recommended for transport." - if(e.is_infected()) + if(e.has_infected_wound()) user << "\red Infected wound detected in subject [limb]. Disinfection recommended." for(var/name in H.organs_by_name) diff --git a/code/game/objects/items/devices/suit_cooling.dm b/code/game/objects/items/devices/suit_cooling.dm new file mode 100644 index 0000000000..2fcf545d9b --- /dev/null +++ b/code/game/objects/items/devices/suit_cooling.dm @@ -0,0 +1,171 @@ +/obj/item/device/suit_cooling_unit + name = "portable suit cooling unit" + desc = "A portable heat sink and liquid cooled radiator that can be hooked up to a space suit's existing temperature controls to provide industrial levels of cooling." + w_class = 4 + icon = 'icons/obj/device.dmi' //temporary, I hope + icon_state = "suitcooler0" + slot_flags = SLOT_BACK //you can carry it on your back if you want, but it won't do anything unless attached to suit storage + + var/on = 0 //is it turned on? + var/cover_open = 0 //is the cover open? + var/obj/item/weapon/cell/cell + var/max_cooling = 12 //in degrees per second - probably don't need to mess with heat capacity here + var/charge_consumption = 16.6 //charge per second at max_cooling + var/thermostat = T20C + + //TODO: make it heat up the surroundings when not in space + +/obj/item/device/suit_cooling_unit/New() + cell = new/obj/item/weapon/cell() //comes with the crappy default power cell - high-capacity ones shouldn't be hard to find + cell.loc = src + +/obj/item/device/suit_cooling_unit/proc/cool_mob(mob/M) + if (!on || !cell) return + + //make sure they have a suit and we are attached to it + if (!attached_to_suit(M)) + return + + var/mob/living/carbon/human/H = M + + var/efficiency = H.get_pressure_protection() //you need to have a good seal for effective cooling + var/env_temp = get_environment_temperature() //wont save you from a fire + var/temp_adj = min(H.bodytemperature - max(thermostat, env_temp), max_cooling) + + if (temp_adj < 0) //only cools, doesn't heat + return + + var/charge_usage = (temp_adj/max_cooling)*charge_consumption + + H.bodytemperature -= temp_adj*efficiency + + cell.use(charge_usage) + + if(cell.charge <= 0) + turn_off() + +/obj/item/device/suit_cooling_unit/proc/get_environment_temperature() + if (ishuman(loc)) + var/mob/living/carbon/human/H = loc + if(istype(H.loc, /obj/mecha)) + var/obj/mecha/M = loc + return M.return_temperature() + else if(istype(H.loc, /obj/machinery/atmospherics/unary/cryo_cell)) + return H.loc:air_contents.temperature + + var/turf/T = get_turf(src) + if(istype(T, /turf/space)) + return 0 //space has no temperature, this just makes sure the cooling unit works in space + + var/datum/gas_mixture/environment = T.return_air() + if (!environment) + return 0 + + return environment.temperature + +/obj/item/device/suit_cooling_unit/proc/attached_to_suit(mob/M) + if (!ishuman(M)) + return 0 + + var/mob/living/carbon/human/H = M + + if (!H.wear_suit || H.s_store != src) + return 0 + + return 1 + +/obj/item/device/suit_cooling_unit/proc/turn_on() + if(!cell) + return + if(cell.charge <= 0) + return + + on = 1 + updateicon() + +/obj/item/device/suit_cooling_unit/proc/turn_off() + if (ismob(src.loc)) + src.loc << "\The [src] clicks and whines as it powers down." //let them know + on = 0 + updateicon() + +/obj/item/device/suit_cooling_unit/attack_self(mob/user as mob) + if(cover_open && cell) + if(ishuman(user)) + user.put_in_hands(cell) + else + cell.loc = get_turf(loc) + + cell.add_fingerprint(user) + cell.updateicon() + + user << "You remove the [src.cell]." + src.cell = null + updateicon() + return + + //TODO use a UI like the air tanks + if(on) + turn_off() + else + turn_on() + if (on) + user << "You switch on the [src]." + +/obj/item/device/suit_cooling_unit/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/screwdriver)) + if(cover_open) + cover_open = 0 + user << "You screw the panel into place." + else + cover_open = 1 + user << "You unscrew the panel." + updateicon() + return + + if (istype(W, /obj/item/weapon/cell)) + if(cover_open) + if(cell) + user << "There is a [cell] already installed here." + else + user.drop_item() + W.loc = src + cell = W + user << "You insert the [cell]." + updateicon() + return + + return ..() + +/obj/item/device/suit_cooling_unit/proc/updateicon() + if (cover_open) + if (cell) + icon_state = "suitcooler1" + else + icon_state = "suitcooler2" + else + icon_state = "suitcooler0" + +/obj/item/device/suit_cooling_unit/examine() + set src in view(1) + + ..() + + if (on) + if (attached_to_suit(src.loc)) + usr << "It's switched on and running." + else + usr << "It's switched on, but not attached to anything." + else + usr << "It is switched off." + + if (cover_open) + if(cell) + usr << "The panel is open, exposing the [cell]." + else + usr << "The panel is open." + + if (cell) + usr << "The charge meter reads [round(cell.percent())]%." + else + usr << "It doesn't have a power cell installed." \ No newline at end of file diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index 6623c99cb3..8b883f818a 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -6,6 +6,7 @@ icon = 'icons/obj/tank.dmi' flags = FPRINT | TABLEPASS | CONDUCT slot_flags = SLOT_BACK + w_class = 3 pressure_resistance = ONE_ATMOSPHERE*5 diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 84acdb6aca..76e4bb01d2 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -220,7 +220,7 @@ BLIND // can't see anything permeability_coefficient = 0.02 flags = FPRINT | TABLEPASS | STOPSPRESSUREDMAGE | THICKMATERIAL body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS - allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank/emergency_oxygen) + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank/emergency_oxygen,/obj/item/device/suit_cooling_unit) slowdown = 3 armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 100, rad = 50) flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL diff --git a/code/modules/clothing/spacesuits/ninja.dm b/code/modules/clothing/spacesuits/ninja.dm index c146bb21a5..c51594e0e6 100644 --- a/code/modules/clothing/spacesuits/ninja.dm +++ b/code/modules/clothing/spacesuits/ninja.dm @@ -13,7 +13,7 @@ desc = "A unique, vaccum-proof suit of nano-enhanced armor designed specifically for Spider Clan assassins." icon_state = "s-ninja" item_state = "s-ninja_suit" - allowed = list(/obj/item/weapon/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs,/obj/item/weapon/tank,/obj/item/weapon/cell) + allowed = list(/obj/item/weapon/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/weapon/cell) slowdown = 0 armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 30, rad = 30) siemens_coefficient = 0.2 diff --git a/code/modules/clothing/spacesuits/rig.dm b/code/modules/clothing/spacesuits/rig.dm index ab3f723674..995e116717 100644 --- a/code/modules/clothing/spacesuits/rig.dm +++ b/code/modules/clothing/spacesuits/rig.dm @@ -55,7 +55,7 @@ item_state = "eng_hardsuit" slowdown = 1 armor = list(melee = 40, bullet = 5, laser = 20,energy = 5, bomb = 35, bio = 100, rad = 80) - allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/weapon/storage/bag/ore,/obj/item/device/t_scanner,/obj/item/weapon/pickaxe, /obj/item/weapon/rcd) + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/weapon/storage/bag/ore,/obj/item/device/t_scanner,/obj/item/weapon/pickaxe, /obj/item/weapon/rcd) heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS max_heat_protection_temperature = SPACE_SUIT_MAX_HEAT_PROTECTION_TEMPERATURE @@ -359,7 +359,7 @@ slowdown = 1 w_class = 3 armor = list(melee = 60, bullet = 50, laser = 30, energy = 15, bomb = 35, bio = 100, rad = 60) - allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/weapon/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/energy/sword,/obj/item/weapon/handcuffs) + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/weapon/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/energy/sword,/obj/item/weapon/handcuffs) siemens_coefficient = 0.6 species_restricted = list("exclude","Unathi","Tajaran","Skrell","Vox") @@ -402,7 +402,7 @@ name = "medical hardsuit" desc = "A special suit that protects against hazardous, low pressure environments. Has minor radiation shielding." item_state = "medical_hardsuit" - allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/weapon/storage/firstaid,/obj/item/device/healthanalyzer,/obj/item/stack/medical) + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/weapon/storage/firstaid,/obj/item/device/healthanalyzer,/obj/item/stack/medical) armor = list(melee = 30, bullet = 5, laser = 20,energy = 5, bomb = 25, bio = 100, rad = 50) //Security @@ -421,7 +421,7 @@ desc = "A special suit that protects against hazardous, low pressure environments. Has an additional layer of armor." item_state = "sec_hardsuit" armor = list(melee = 60, bullet = 10, laser = 30, energy = 5, bomb = 45, bio = 100, rad = 10) - allowed = list(/obj/item/weapon/gun,/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/weapon/melee/baton) + allowed = list(/obj/item/weapon/gun,/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/weapon/melee/baton) siemens_coefficient = 0.7 diff --git a/code/modules/events/organ_failure.dm b/code/modules/events/organ_failure.dm index 80e7f807dd..1499afcb45 100644 --- a/code/modules/events/organ_failure.dm +++ b/code/modules/events/organ_failure.dm @@ -21,9 +21,25 @@ datum/event/organ_failure/start() while(severity > 0 && candidates.len) var/mob/living/carbon/human/C = candidates[1] - // Bruise one of their organs - var/O = pick(C.internal_organs) - var/datum/organ/internal/I = C.internal_organs[O] - I.damage = I.min_bruised_damage - candidates.Remove(C) - severity-- \ No newline at end of file + var/acute = prob(15) + if (prob(75)) + //internal organ infection + var/O = pick(C.internal_organs) + var/datum/organ/internal/I = C.internal_organs[O] + + if (acute) + I.germ_level = max(INFECTION_LEVEL_TWO, I.germ_level) + else + I.germ_level = max(rand(INFECTION_LEVEL_ONE,INFECTION_LEVEL_ONE*2), I.germ_level) + else + //external organ infection + var/datum/organ/external/O = pick(C.organs) + + if (acute) + O.germ_level = max(INFECTION_LEVEL_TWO, O.germ_level) + else + O.germ_level = max(rand(INFECTION_LEVEL_ONE,INFECTION_LEVEL_ONE*2), O.germ_level) + + C.bad_external_organs |= O + + severity-- diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 1fed0f1854..64e70e05b9 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1,3 +1,10 @@ +/mob/living/carbon/Life() + ..() + + // Increase germ_level regularly + if(germ_level < GERM_LEVEL_AMBIENT && prob(80)) //if you're just standing there, you shouldn't get more germs beyond an ambient level + germ_level++ + /mob/living/carbon/Move(NewLoc, direct) . = ..() if(.) @@ -7,6 +14,10 @@ src.nutrition -= HUNGER_FACTOR/10 if((FAT in src.mutations) && src.m_intent == "run" && src.bodytemperature <= 360) src.bodytemperature += 2 + + // Moving around increases germ_level faster + if(germ_level < GERM_LEVEL_MOVE_CAP && prob(8)) + germ_level++ /mob/living/carbon/relaymove(var/mob/user, direction) if(user in src.stomach_contents) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 51abb2769f..6ce436e12a 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -284,8 +284,8 @@ var/this_wound_desc = W.desc if(W.bleeding()) this_wound_desc = "bleeding [this_wound_desc]" else if(W.bandaged) this_wound_desc = "bandaged [this_wound_desc]" - if(W.germ_level > 1000) this_wound_desc = "badly infected [this_wound_desc]" - else if(W.germ_level > 100) this_wound_desc = "lightly infected [this_wound_desc]" + if(W.germ_level > 600) this_wound_desc = "badly infected [this_wound_desc]" + else if(W.germ_level > 330) this_wound_desc = "lightly infected [this_wound_desc]" if(this_wound_desc in wound_descriptors) wound_descriptors[this_wound_desc] += W.amount continue diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 2925449d0e..c25a712ec7 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1220,7 +1220,7 @@ return usr << "Don't move until counting is finished." - var/time = world.timeofday + var/time = world.time sleep(60) if(usr.l_move_time >= time) //checks if our mob has moved during the sleep() usr << "You moved while counting. Try again." diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 91fffaedd4..4a174a439f 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -129,12 +129,10 @@ G.process() -/mob/living/carbon/human/calculate_affecting_pressure(var/pressure) - ..() - var/pressure_difference = abs( pressure - ONE_ATMOSPHERE ) - +//Much like get_heat_protection(), 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. +/mob/living/carbon/human/proc/get_pressure_protection() var/pressure_adjustment_coefficient = 1 //Determins how much the clothing you are wearing protects you in percent. - + if(head && (head.flags & STOPSPRESSUREDMAGE)) pressure_adjustment_coefficient -= PRESSURE_HEAD_REDUCTION_COEFFICIENT @@ -147,10 +145,16 @@ if(S.can_breach && S.damage) var/pressure_loss = S.damage * 0.1 pressure_adjustment_coefficient += pressure_loss - + pressure_adjustment_coefficient = min(1,max(pressure_adjustment_coefficient,0)) //So it isn't less than 0 or larger than 1. + + return 1 - pressure_adjustment_coefficient //want 0 to be bad protection, 1 to be good protection - pressure_difference = pressure_difference * pressure_adjustment_coefficient +/mob/living/carbon/human/calculate_affecting_pressure(var/pressure) + ..() + var/pressure_difference = abs( pressure - ONE_ATMOSPHERE ) + + pressure_difference = pressure_difference * (1 - get_pressure_protection()) if(pressure > ONE_ATMOSPHERE) return ONE_ATMOSPHERE + pressure_difference @@ -316,9 +320,6 @@ if(istype(loc, /obj/machinery/atmospherics/unary/cryo_cell)) return if(species && (species.flags & NO_BREATHE || species.flags & IS_SYNTHETIC)) return - var/datum/organ/internal/lungs/L = internal_organs["lungs"] - L.process() - var/datum/gas_mixture/environment = loc.return_air() var/datum/gas_mixture/breath @@ -619,14 +620,14 @@ adjustOxyLoss(-5) // Hot air hurts :( - if( (abs(310.15 - breath.temperature) > 50) && !(COLD_RESISTANCE in mutations)) + if( (breath.temperature < species.cold_level_1 || breath.temperature > species.heat_level_1) && !(COLD_RESISTANCE in mutations)) if(status_flags & GODMODE) return 1 if(breath.temperature < species.cold_level_1) if(prob(20)) - src << "\red You feel your face freezing and an icicle forming in your lungs!" + src << "\red You feel your face freezing and icicles forming in your lungs!" else if(breath.temperature > species.heat_level_1) if(prob(20)) src << "\red You feel your face burning and a searing heat in your lungs!" @@ -650,9 +651,21 @@ if(species.heat_level_3 to INFINITY) apply_damage(HEAT_GAS_DAMAGE_LEVEL_3, BURN, "head", used_weapon = "Excessive Heat") fire_alert = max(fire_alert, 2) - - //Temporary fixes to the alerts. - + + //breathing in hot/cold air also heats/cools you a bit + var/temp_adj = breath.temperature - bodytemperature + if (temp_adj < 0) + temp_adj /= (BODYTEMP_COLD_DIVISOR * 5) //don't raise temperature as much as if we were directly exposed + else + temp_adj /= (BODYTEMP_HEAT_DIVISOR * 5) //don't raise temperature as much as if we were directly exposed + + var/relative_density = breath.total_moles() / (MOLES_CELLSTANDARD * BREATH_PERCENTAGE) + temp_adj *= relative_density + + if (temp_adj > BODYTEMP_HEATING_MAX) temp_adj = BODYTEMP_HEATING_MAX + if (temp_adj < BODYTEMP_COOLING_MAX) temp_adj = BODYTEMP_COOLING_MAX + //world << "Breath: [breath.temperature], [src]: [bodytemperature], Adjusting: [temp_adj]" + bodytemperature += temp_adj return 1 proc/handle_environment(datum/gas_mixture/environment) @@ -668,60 +681,63 @@ if(istype(loc, /obj/mecha)) var/obj/mecha/M = loc loc_temp = M.return_temperature() - else if(istype(get_turf(src), /turf/space)) else if(istype(loc, /obj/machinery/atmospherics/unary/cryo_cell)) loc_temp = loc:air_contents.temperature else loc_temp = environment.temperature - if(adjusted_pressure < species.warning_low_pressure && adjusted_pressure > species.warning_low_pressure && abs(loc_temp - 293.15) < 20 && abs(bodytemperature - 310.14) < 0.5 && environment.phoron < MOLES_PHORON_VISIBLE) + if(adjusted_pressure < species.warning_high_pressure && adjusted_pressure > species.warning_low_pressure && abs(loc_temp - bodytemperature) < 20 && bodytemperature < species.heat_level_1 && bodytemperature > species.cold_level_1 && environment.phoron < MOLES_PHORON_VISIBLE) return // Temperatures are within normal ranges, fuck all this processing. ~Ccomp - //Body temperature is adjusted in two steps. Firstly your body tries to stabilize itself a bit. - if(stat != 2) - stabilize_temperature_from_calories() - - //After then, it reacts to the surrounding atmosphere based on your thermal protection - if(loc_temp < BODYTEMP_COLD_DAMAGE_LIMIT) //Place is colder than we are + //Body temperature adjusts depending on surrounding atmosphere based on your thermal protection + var/temp_adj = 0 + if(loc_temp < bodytemperature) //Place is colder than we are var/thermal_protection = get_cold_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(thermal_protection < 1) - var/amt = min((1-thermal_protection) * ((loc_temp - bodytemperature) / BODYTEMP_COLD_DIVISOR), BODYTEMP_COOLING_MAX) - bodytemperature += amt - else if (loc_temp > BODYTEMP_HEAT_DAMAGE_LIMIT) //Place is hotter than we are + temp_adj = (1-thermal_protection) * ((loc_temp - bodytemperature) / BODYTEMP_COLD_DIVISOR) //this will be negative + else if (loc_temp > bodytemperature) //Place is hotter than we are var/thermal_protection = get_heat_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(thermal_protection < 1) - var/amt = min((1-thermal_protection) * ((loc_temp - bodytemperature) / BODYTEMP_HEAT_DIVISOR), BODYTEMP_HEATING_MAX) - bodytemperature += amt + temp_adj = (1-thermal_protection) * ((loc_temp - bodytemperature) / BODYTEMP_HEAT_DIVISOR) + + //Use heat transfer as proportional to the gas density. However, we only care about the relative density vs standard 101 kPa/20 C air. Therefore we can use mole ratios + var/relative_density = environment.total_moles() / MOLES_CELLSTANDARD + temp_adj *= relative_density + + if (temp_adj > BODYTEMP_HEATING_MAX) temp_adj = BODYTEMP_HEATING_MAX + if (temp_adj < BODYTEMP_COOLING_MAX) temp_adj = BODYTEMP_COOLING_MAX + //world << "Environment: [loc_temp], [src]: [bodytemperature], Adjusting: [temp_adj]" + bodytemperature += temp_adj // +/- 50 degrees from 310.15K is the 'safe' zone, where no damage is dealt. - if(bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT) + if(bodytemperature > species.heat_level_1) //Body temperature is too hot. fire_alert = max(fire_alert, 1) if(status_flags & GODMODE) return 1 //godmode switch(bodytemperature) - if(360 to 400) - apply_damage(HEAT_DAMAGE_LEVEL_1, BURN, used_weapon = "High Body Temperature") + if(species.heat_level_1 to species.heat_level_2) + take_overall_damage(burn=HEAT_DAMAGE_LEVEL_1, used_weapon = "High Body Temperature") fire_alert = max(fire_alert, 2) - if(400 to 1000) - apply_damage(HEAT_DAMAGE_LEVEL_2, BURN, used_weapon = "High Body Temperature") + if(species.heat_level_2 to species.heat_level_3) + take_overall_damage(burn=HEAT_DAMAGE_LEVEL_2, used_weapon = "High Body Temperature") fire_alert = max(fire_alert, 2) - if(1000 to INFINITY) - apply_damage(HEAT_DAMAGE_LEVEL_3, BURN, used_weapon = "High Body Temperature") + if(species.heat_level_3 to INFINITY) + take_overall_damage(burn=HEAT_DAMAGE_LEVEL_3, used_weapon = "High Body Temperature") fire_alert = max(fire_alert, 2) - else if(bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT) + else if(bodytemperature < species.cold_level_1) fire_alert = max(fire_alert, 1) if(status_flags & GODMODE) return 1 //godmode if(!istype(loc, /obj/machinery/atmospherics/unary/cryo_cell)) switch(bodytemperature) - if(200 to 260) - apply_damage(COLD_DAMAGE_LEVEL_1, BURN, used_weapon = "Low Body Temperature") + if(species.cold_level_2 to species.cold_level_1) + take_overall_damage(burn=COLD_DAMAGE_LEVEL_1, used_weapon = "High Body Temperature") fire_alert = max(fire_alert, 1) - if(120 to 200) - apply_damage(COLD_DAMAGE_LEVEL_2, BURN, used_weapon = "Low Body Temperature") + if(species.cold_level_3 to species.cold_level_2) + take_overall_damage(burn=COLD_DAMAGE_LEVEL_2, used_weapon = "High Body Temperature") fire_alert = max(fire_alert, 1) - if(-INFINITY to 120) - apply_damage(COLD_DAMAGE_LEVEL_3, BURN, used_weapon = "Low Body Temperature") + if(-INFINITY to species.cold_level_3) + take_overall_damage(burn=COLD_DAMAGE_LEVEL_3, used_weapon = "High Body Temperature") fire_alert = max(fire_alert, 1) // Account for massive pressure differences. Done by Polymorph @@ -729,7 +745,8 @@ if(status_flags & GODMODE) return 1 //godmode if(adjusted_pressure >= species.hazard_high_pressure) - adjustBruteLoss( min( ( (adjusted_pressure / species.hazard_high_pressure) -1 )*PRESSURE_DAMAGE_COEFFICIENT , MAX_HIGH_PRESSURE_DAMAGE) ) + var/pressure_damage = min( ( (adjusted_pressure / species.hazard_high_pressure) -1 )*PRESSURE_DAMAGE_COEFFICIENT , MAX_HIGH_PRESSURE_DAMAGE) + take_overall_damage(brute=pressure_damage, used_weapon = "High Pressure") pressure_alert = 2 else if(adjusted_pressure >= species.warning_high_pressure) pressure_alert = 1 @@ -737,17 +754,9 @@ pressure_alert = 0 else if(adjusted_pressure >= species.hazard_low_pressure) pressure_alert = -1 - - if(species && species.flags & IS_SYNTHETIC) - bodytemperature += 0.5 * TEMPERATURE_DAMAGE_COEFFICIENT //Synthetics suffer overheating in a vaccuum. ~Z - else - - if(species && species.flags & IS_SYNTHETIC) - bodytemperature += 1 * TEMPERATURE_DAMAGE_COEFFICIENT - if( !(COLD_RESISTANCE in mutations)) - adjustBruteLoss( LOW_PRESSURE_DAMAGE ) + take_overall_damage(brute=LOW_PRESSURE_DAMAGE, used_weapon = "Low Pressure") pressure_alert = -2 else pressure_alert = -1 @@ -774,27 +783,40 @@ temp_change = (temperature - current) return temp_change */ - - proc/stabilize_temperature_from_calories() - var/body_temperature_difference = 310.15 - bodytemperature + + proc/stabilize_body_temperature() + //TODO find a better place to put this + if (s_store && istype(s_store, /obj/item/device/suit_cooling_unit)) + var/obj/item/device/suit_cooling_unit/CU = s_store + CU.cool_mob(src) + + if (species.flags & IS_SYNTHETIC) + bodytemperature += species.synth_temp_gain //that CPU/posibrain just keeps putting out heat. + return + + var/body_temperature_difference = species.body_temperature - bodytemperature + if (abs(body_temperature_difference) < 0.5) return //fuck this precision - switch(bodytemperature) - if(-INFINITY to 260.15) //260.15 is 310.15 - 50, the temperature where you start to feel effects. - if(nutrition >= 2) //If we are very, very cold we'll use up quite a bit of nutriment to heat us up. - nutrition -= 2 - var/recovery_amt = max((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), BODYTEMP_AUTORECOVERY_MINIMUM) + + if(bodytemperature < species.cold_level_1) //260.15 is 310.15 - 50, the temperature where you start to feel effects. + if(nutrition >= 2) //If we are very, very cold we'll use up quite a bit of nutriment to heat us up. + nutrition -= 2 + var/recovery_amt = max((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), BODYTEMP_AUTORECOVERY_MINIMUM) + //world << "Cold. Difference = [body_temperature_difference]. Recovering [recovery_amt]" // log_debug("Cold. Difference = [body_temperature_difference]. Recovering [recovery_amt]") - bodytemperature += recovery_amt - if(260.15 to 360.15) - var/recovery_amt = body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR + bodytemperature += recovery_amt + else if(species.cold_level_1 <= bodytemperature && bodytemperature <= species.heat_level_1) + var/recovery_amt = body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR + //world << "Norm. Difference = [body_temperature_difference]. Recovering [recovery_amt]" // log_debug("Norm. Difference = [body_temperature_difference]. Recovering [recovery_amt]") - bodytemperature += recovery_amt - if(360.15 to INFINITY) //360.15 is 310.15 + 50, the temperature where you start to feel effects. - //We totally need a sweat system cause it totally makes sense...~ - var/recovery_amt = min((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), -BODYTEMP_AUTORECOVERY_MINIMUM) //We're dealing with negative numbers + bodytemperature += recovery_amt + else if(bodytemperature > species.heat_level_1) //360.15 is 310.15 + 50, the temperature where you start to feel effects. + //We totally need a sweat system cause it totally makes sense...~ + var/recovery_amt = min((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), -BODYTEMP_AUTORECOVERY_MINIMUM) //We're dealing with negative numbers + //world << "Hot. Difference = [body_temperature_difference]. Recovering [recovery_amt]" // log_debug("Hot. Difference = [body_temperature_difference]. Recovering [recovery_amt]") - bodytemperature += recovery_amt + bodytemperature += recovery_amt //This proc returns a number made up of the flags for body parts which you are protected on. (such as HEAD, UPPER_TORSO, LOWER_TORSO, etc. See setup.dm for the full list) proc/get_heat_protection_flags(temperature) //Temperature is the temperature you're being exposed to. @@ -1074,12 +1096,6 @@ if(!(species.flags & IS_SYNTHETIC)) handle_trace_chems() - var/datum/organ/internal/liver/liver = internal_organs["liver"] - liver.process() - - var/datum/organ/internal/eyes/eyes = internal_organs["eyes"] - eyes.process() - updatehealth() return //TODO: DEFERRED @@ -1091,6 +1107,7 @@ else //ALIVE. LIGHTS ARE ON updatehealth() //TODO if(!in_stasis) + stabilize_body_temperature() //Body temperature adjusts itself handle_organs() //Optimized. handle_blood() @@ -1215,14 +1232,11 @@ if(druggy) druggy = max(druggy-1, 0) -/* - // Increase germ_level regularly - if(prob(40)) - germ_level += 1 + // If you're dirty, your gloves will become dirty, too. if(gloves && germ_level > gloves.germ_level && prob(10)) gloves.germ_level += 1 -*/ + return 1 proc/handle_regular_hud_updates() @@ -1449,17 +1463,46 @@ else fire.icon_state = "fire0" if(bodytemp) - switch(bodytemperature) //310.055 optimal body temp - if(370 to INFINITY) bodytemp.icon_state = "temp4" - if(350 to 370) bodytemp.icon_state = "temp3" - if(335 to 350) bodytemp.icon_state = "temp2" - if(320 to 335) bodytemp.icon_state = "temp1" - if(300 to 320) bodytemp.icon_state = "temp0" - if(295 to 300) bodytemp.icon_state = "temp-1" - if(280 to 295) bodytemp.icon_state = "temp-2" - if(260 to 280) bodytemp.icon_state = "temp-3" - else bodytemp.icon_state = "temp-4" - + if (!species) + switch(bodytemperature) //310.055 optimal body temp + if(370 to INFINITY) bodytemp.icon_state = "temp4" + if(350 to 370) bodytemp.icon_state = "temp3" + if(335 to 350) bodytemp.icon_state = "temp2" + if(320 to 335) bodytemp.icon_state = "temp1" + if(300 to 320) bodytemp.icon_state = "temp0" + if(295 to 300) bodytemp.icon_state = "temp-1" + if(280 to 295) bodytemp.icon_state = "temp-2" + if(260 to 280) bodytemp.icon_state = "temp-3" + else bodytemp.icon_state = "temp-4" + else + var/temp_step + if (bodytemperature >= species.body_temperature) + temp_step = (species.heat_level_1 - species.body_temperature)/4 + + if (bodytemperature >= species.heat_level_1) + bodytemp.icon_state = "temp4" + else if (bodytemperature >= species.body_temperature + temp_step*3) + bodytemp.icon_state = "temp3" + else if (bodytemperature >= species.body_temperature + temp_step*2) + bodytemp.icon_state = "temp2" + else if (bodytemperature >= species.body_temperature + temp_step*1) + bodytemp.icon_state = "temp1" + else + bodytemp.icon_state = "temp0" + + else if (bodytemperature < species.body_temperature) + temp_step = (species.body_temperature - species.cold_level_1)/4 + + if (bodytemperature <= species.cold_level_1) + bodytemp.icon_state = "temp-4" + else if (bodytemperature <= species.body_temperature - temp_step*3) + bodytemp.icon_state = "temp-3" + else if (bodytemperature <= species.body_temperature - temp_step*2) + bodytemp.icon_state = "temp-2" + else if (bodytemperature <= species.body_temperature - temp_step*1) + bodytemp.icon_state = "temp-1" + else + bodytemp.icon_state = "temp0" if(blind) if(blinded) blind.layer = 18 else blind.layer = 0 diff --git a/code/modules/mob/living/carbon/species.dm b/code/modules/mob/living/carbon/species.dm index 028e93e5bb..b171bfb884 100644 --- a/code/modules/mob/living/carbon/species.dm +++ b/code/modules/mob/living/carbon/species.dm @@ -28,6 +28,9 @@ var/heat_level_1 = 360 // Heat damage level 1 above this point. var/heat_level_2 = 400 // Heat damage level 2 above this point. var/heat_level_3 = 1000 // Heat damage level 2 above this point. + + var/body_temperature = 310.15 //non-IS_SYNTHETIC species will try to stabilize at this temperature. (also affects temperature processing) + var/synth_temp_gain = 0 //IS_SYNTHETIC species will gain this much temperature every second var/darksight = 2 var/hazard_high_pressure = HAZARD_HIGH_PRESSURE // Dangerously high pressure. @@ -279,6 +282,8 @@ heat_level_2 = 3000 heat_level_3 = 4000 + body_temperature = T0C + 15 //make the plant people have a bit lower body temperature, why not + flags = IS_WHITELISTED | NO_BREATHE | REQUIRE_LIGHT | NO_SCAN | IS_PLANT | RAD_ABSORB | NO_BLOOD | IS_SLOW | NO_PAIN blood_color = "#004400" @@ -317,15 +322,17 @@ burn_mod = 1 warning_low_pressure = 50 - hazard_low_pressure = 10 + hazard_low_pressure = 0 cold_level_1 = 50 cold_level_2 = -1 cold_level_3 = -1 - heat_level_1 = 2000 - heat_level_2 = 3000 - heat_level_3 = 4000 + heat_level_1 = 500 //gives them about 25 seconds in space before taking damage + heat_level_2 = 1000 + heat_level_3 = 2000 + + synth_temp_gain = 10 //this should cause IPCs to stabilize at ~80 C in a 20 C environment. flags = IS_WHITELISTED | NO_BREATHE | NO_SCAN | NO_BLOOD | NO_PAIN | IS_SYNTHETIC diff --git a/code/modules/mob/living/silicon/robot/component.dm b/code/modules/mob/living/silicon/robot/component.dm index cee310ae59..d97d2a5391 100644 --- a/code/modules/mob/living/silicon/robot/component.dm +++ b/code/modules/mob/living/silicon/robot/component.dm @@ -188,7 +188,7 @@ if(!(istype(user, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") user << "\red You don't have the dexterity to do this!" return - if(!istype(M, /mob/living/silicon/robot)) + if(!istype(M, /mob/living/silicon/robot) && !(ishuman(M) && (M:species.flags & IS_SYNTHETIC))) user << "\red You can't analyze non-robotic things!" return @@ -200,22 +200,39 @@ user.show_message("\t Damage Specifics: [BU] - [BR]") if(M.tod && M.stat == DEAD) user.show_message("\blue Time of Disable: [M.tod]") - - var/mob/living/silicon/robot/H = M - var/list/damaged = H.get_damaged_components(1,1,1) - user.show_message("\blue Localized Damage:",1) - if(length(damaged)>0) - for(var/datum/robot_component/org in damaged) - user.show_message(text("\blue \t []: [][] - [] - [] - []", \ - capitalize(org.name), \ - (org.installed == -1) ? "DESTROYED " :"",\ - (org.electronics_damage > 0) ? "[org.electronics_damage]" :0, \ - (org.brute_damage > 0) ? "[org.brute_damage]" :0, \ - (org.toggled) ? "Toggled ON" : "Toggled OFF",\ - (org.powered) ? "Power ON" : "Power OFF"),1) - else - user.show_message("\blue \t Components are OK.",1) - if(H.emagged && prob(5)) - user.show_message("\red \t ERROR: INTERNAL SYSTEMS COMPROMISED",1) + + if (istype(M, /mob/living/silicon/robot)) + var/mob/living/silicon/robot/H = M + var/list/damaged = H.get_damaged_components(1,1,1) + user.show_message("\blue Localized Damage:",1) + if(length(damaged)>0) + for(var/datum/robot_component/org in damaged) + user.show_message(text("\blue \t []: [][] - [] - [] - []", \ + capitalize(org.name), \ + (org.installed == -1) ? "DESTROYED " :"",\ + (org.electronics_damage > 0) ? "[org.electronics_damage]" :0, \ + (org.brute_damage > 0) ? "[org.brute_damage]" :0, \ + (org.toggled) ? "Toggled ON" : "Toggled OFF",\ + (org.powered) ? "Power ON" : "Power OFF"),1) + else + user.show_message("\blue \t Components are OK.",1) + if(H.emagged && prob(5)) + user.show_message("\red \t ERROR: INTERNAL SYSTEMS COMPROMISED",1) + + if (ishuman(M) && (M:species.flags & IS_SYNTHETIC)) + var/mob/living/carbon/human/H = M + var/list/damaged = H.get_damaged_organs(1,1) + user.show_message("\blue Localized Damage, Brute/Electronics:",1) + if(length(damaged)>0) + for(var/datum/organ/external/org in damaged) + user.show_message(text("\blue \t []: [] - []", \ + capitalize(org.display_name), \ + (org.brute_dam > 0) ? "\red [org.brute_dam]" :0, \ + (org.burn_dam > 0) ? "[org.burn_dam]" :0),1) + else + user.show_message("\blue \t Components are OK.",1) + + user.show_message("\blue Operating Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)", 1) + src.add_fingerprint(user) return diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index 47a7f67a07..b5761df24c 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -5,6 +5,9 @@ var/list/datum/autopsy_data/autopsy_data = list() var/list/trace_chemicals = list() // traces of chemicals in the organ, // links chemical IDs to number of ticks for which they'll stay in the blood + + var/germ_level = 0 // INTERNAL germs inside the organ, this is BAD if it's greater than INFECTION_LEVEL_ONE + proc/process() return 0 @@ -46,13 +49,18 @@ if(damage_this_tick > last_dam) force_process = 1 last_dam = damage_this_tick - if(!force_process && !bad_external_organs.len) - return if(force_process) bad_external_organs.Cut() for(var/datum/organ/external/Ex in organs) bad_external_organs += Ex - + + //processing internal organs is pretty cheap, do that first. + for(var/datum/organ/internal/I in internal_organs) + I.process() + + if(!force_process && !bad_external_organs.len) + return + for(var/datum/organ/external/E in bad_external_organs) if(!E) continue @@ -62,53 +70,24 @@ else E.process() number_wounds += E.number_wounds - //Robotic limb malfunctions - var/malfunction = 0 - if (E.status & ORGAN_ROBOT && prob(E.brute_dam + E.burn_dam)) - malfunction = 1 - - //Broken limbs hurt too - var/broken = 0 - if(E.status & ORGAN_BROKEN && !(E.status & ORGAN_SPLINTED) ) - broken = 1 + if (!lying && world.time - l_move_time < 15) //Moving around with fractured ribs won't do you any good - if (broken && E.internal_organs && prob(15)) - if (!lying && world.timeofday - l_move_time < 15) + if (E.is_broken() && E.internal_organs && prob(15)) var/datum/organ/internal/I = pick(E.internal_organs) custom_pain("You feel broken bones moving in your [E.display_name]!", 1) I.take_damage(rand(3,5)) + + //Moving makes open wounds get infected much faster + if (E.wounds.len) + for(var/datum/wound/W in E.wounds) + if (W.infection_check()) + W.germ_level += 1 - //Special effects for limbs. - if(E.name in list("l_hand","l_arm","r_hand","r_arm")) - var/obj/item/c_hand //Getting what's in this hand - var/hand - if(E.name == "l_hand" || E.name == "l_arm") - c_hand = l_hand - hand = "left hand" - if(E.name == "r_hand" || E.name == "r_arm") - c_hand = r_hand - hand = "right hand" - if (c_hand) - - if(broken) - u_equip(c_hand) - var/emote_scream = pick("screams in pain and", "let's out a sharp hiss and", "cries out and") - emote("me", 1, "[(species && species.flags & NO_PAIN) ? "" : emote_scream ] drops what they were holding in their [hand]!") - if(malfunction) - u_equip(c_hand) - emote("me", 1, "drops what they were holding, their [hand] malfunctioning!") - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() - spark_system.set_up(5, 0, src) - spark_system.attach(src) - spark_system.start() - spawn(10) - del(spark_system) - - else if(E.name in list("l_leg","l_foot","r_leg","r_foot") && !lying) - if (!E.is_usable() || malfunction || (broken && !(E.status & ORGAN_SPLINTED))) + if(E.name in list("l_leg","l_foot","r_leg","r_foot") && !lying) + if (!E.is_usable() || E.is_malfunctioning() || (E.is_broken() && !(E.status & ORGAN_SPLINTED))) leg_tally-- // let it fail even if just foot&leg - + // standing is poor if(leg_tally <= 0 && !paralysis && !(lying || resting) && prob(5)) if(species && species.flags & NO_PAIN) diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index c51d516715..56d7129544 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -40,8 +40,6 @@ var/obj/item/hidden = null var/list/implants = list() - // INTERNAL germs inside the organ, this is BAD if it's greater 0 - var/germ_level = 0 // how often wounds should be updated, a higher number means less often var/wound_update_accuracy = 1 @@ -298,7 +296,10 @@ This function completely restores a damaged organ to perfect condition. if(last_dam != brute_dam + burn_dam) // Process when we are fully healed up. last_dam = brute_dam + burn_dam return 1 - last_dam = brute_dam + burn_dam + else + last_dam = brute_dam + burn_dam + if(germ_level) + return 1 return 0 /datum/organ/external/process() @@ -330,50 +331,89 @@ This function completely restores a damaged organ to perfect condition. if(!(status & ORGAN_BROKEN)) perma_injury = 0 + //Infections update_germs() return //Updating germ levels. Handles organ germ levels and necrosis. -#define GANGREN_LEVEL_ONE 100 -#define GANGREN_LEVEL_TWO 1000 -#define GANGREN_LEVEL_TERMINAL 2500 -#define GERM_TRANSFER_AMOUNT germ_level/500 +/* +The INFECTION_LEVEL values defined in setup.dm control the time it takes to reach the different +infection levels. Since infection growth is exponential, you can adjust the time it takes to get +from one germ_level to another using the rough formula: + +desired_germ_level = initial_germ_level*e^(desired_time_in_seconds/1000) + +So if I wanted it to take an average of 15 minutes to get from level one (100) to level two +I would set INFECTION_LEVEL_TWO to 100*e^(15*60/1000) = 245. Note that this is the average time, +the actual time is dependent on RNG. + +INFECTION_LEVEL_ONE below this germ level nothing happens, and the infection doesn't grow +INFECTION_LEVEL_TWO above this germ level the infection will start to spread to internal and adjacent organs +INFECTION_LEVEL_THREE above this germ level the player will take additional toxin damage per second, and will die in minutes without + antitox. also, above this germ level you will need to overdose on spaceacillin to reduce the germ_level. + +Note that amputating the affected organ does in fact remove the infection from the +player's body, though, antitox and spaceacillin are easy enough to get I doubt it will ever be needed. +*/ /datum/organ/external/proc/update_germs() - if(status & ORGAN_ROBOT|ORGAN_DESTROYED) //Robotic limbs shouldn't be infected, nor should nonexistant limbs. + if(status & (ORGAN_ROBOT|ORGAN_DESTROYED)) //Robotic limbs shouldn't be infected, nor should nonexistant limbs. germ_level = 0 return - if(germ_level > 0 && owner.bodytemperature >= 170) //cryo stops germs from moving and doing their bad stuffs + if(owner.bodytemperature >= 170) //cryo stops germs from moving and doing their bad stuffs //Syncing germ levels with external wounds for(var/datum/wound/W in wounds) - if(!W.bandaged && !W.salved) - W.germ_level = max(W.germ_level, germ_level) //Wounds get all the germs - if (W.germ_level > germ_level) //Badly infected wounds raise internal germ levels - germ_level++ + //Open wounds can become infected + if (owner.germ_level > W.germ_level && W.infection_check()) + W.germ_level++ + + //Infected wounds raise the organ's germ level + W.germ_level = max(W.germ_level, germ_level) //Wounds get all the germs + if (W.germ_level > germ_level) //Badly infected wounds raise internal germ levels + germ_level++ - if(germ_level > GANGREN_LEVEL_ONE && prob(round(germ_level/100))) - germ_level++ - owner.adjustToxLoss(1) - - if(germ_level > GANGREN_LEVEL_TWO) - germ_level++ - owner.adjustToxLoss(1) -/* - if(germ_level > GANGREN_LEVEL_TERMINAL) + var/antibiotics = owner.reagents.get_reagent_amount("spaceacillin") + if (germ_level > 0 && antibiotics > 5) + if (prob(4*antibiotics)) germ_level-- //the higher the germ level the more antibiotics you'll need. + + if(germ_level >= INFECTION_LEVEL_ONE) + //having an infection raises your body temperature + var/fever_temperature = (owner.species.heat_level_1 - owner.species.body_temperature - 1)* min(germ_level/INFECTION_LEVEL_THREE, 1) + owner.species.body_temperature + if (owner.bodytemperature < fever_temperature) + //world << "fever: [owner.bodytemperature] < [fever_temperature], raising temperature." + owner.bodytemperature++ + + if(prob(round(germ_level/10))) + germ_level++ + if (prob(5)) //adjust this to tweak how fast people take toxin damage from infections + owner.adjustToxLoss(1) + + if(germ_level >= INFECTION_LEVEL_TWO) + //spread the infection + for (var/datum/organ/internal/I in internal_organs) + if (I.germ_level < germ_level) + I.germ_level++ + + if (children) //To child organs + for (var/datum/organ/external/child in children) + if (child.germ_level < germ_level && !(child.status & ORGAN_ROBOT)) + if (child.germ_level < INFECTION_LEVEL_ONE*2 || prob(30)) + child.germ_level++ + + if (parent) + if (parent.germ_level < germ_level && !(parent.status & ORGAN_ROBOT)) + if (parent.germ_level < INFECTION_LEVEL_ONE*2 || prob(30)) + parent.germ_level++ + + if(germ_level >= INFECTION_LEVEL_THREE && antibiotics < 30) //overdosing is necessary to stop severe infections if (!(status & ORGAN_DEAD)) status |= ORGAN_DEAD owner << "You can't feel your [display_name] anymore..." - owner.update_body(1) - if (prob(10)) //Spreading the fun - if (children) //To child organs - for (var/datum/organ/external/child in children) - if (!(child.status & (ORGAN_DEAD|ORGAN_DESTROYED|ORGAN_ROBOT))) - child.germ_level += round(GERM_TRANSFER_AMOUNT) - if (parent) - if (!(parent.status & (ORGAN_DEAD|ORGAN_DESTROYED|ORGAN_ROBOT))) - parent.germ_level += round(GERM_TRANSFER_AMOUNT) -*/ + + germ_level++ + owner.adjustToxLoss(1) + //Updating wounds. Handles wound natural I had some free spachealing, internal bleedings and infections /datum/organ/external/proc/update_wounds() @@ -684,9 +724,9 @@ This function completely restores a damaged organ to perfect condition. /datum/organ/external/proc/get_damage() //returns total damage return max(brute_dam + burn_dam - perma_injury, perma_injury) //could use health? -/datum/organ/external/proc/is_infected() +/datum/organ/external/proc/has_infected_wound() for(var/datum/wound/W in wounds) - if(W.germ_level > 100) + if(W.germ_level > 150) return 1 return 0 @@ -703,6 +743,32 @@ This function completely restores a damaged organ to perfect condition. /datum/organ/external/proc/is_usable() return !(status & (ORGAN_DESTROYED|ORGAN_MUTATED|ORGAN_DEAD)) +/datum/organ/external/proc/is_broken() + return ((status & ORGAN_BROKEN) && !(status & ORGAN_SPLINTED)) + +/datum/organ/external/proc/is_malfunctioning() + return ((status & ORGAN_ROBOT) && prob(brute_dam + burn_dam)) + +//for arms and hands +/datum/organ/external/proc/process_grasp(var/obj/item/c_hand, var/hand_name) + if (!c_hand) + return + + if(is_broken()) + owner.u_equip(c_hand) + var/emote_scream = pick("screams in pain and", "lets out a sharp cry and", "cries out and") + owner.emote("me", 1, "[(owner.species && owner.species.flags & NO_PAIN) ? "" : emote_scream ] drops what they were holding in their [hand_name]!") + if(is_malfunctioning()) + owner.u_equip(c_hand) + owner.emote("me", 1, "drops what they were holding, their [hand_name] malfunctioning!") + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, src) + spark_system.attach(src) + spark_system.start() + spawn(10) + del(spark_system) + + /**************************************************** ORGAN DEFINES ****************************************************/ @@ -731,6 +797,10 @@ This function completely restores a damaged organ to perfect condition. max_damage = 50 min_broken_damage = 20 body_part = ARM_LEFT + + process() + ..() + process_grasp(owner.l_hand, "left hand") /datum/organ/external/l_leg name = "l_leg" @@ -748,6 +818,10 @@ This function completely restores a damaged organ to perfect condition. max_damage = 50 min_broken_damage = 20 body_part = ARM_RIGHT + + process() + ..() + process_grasp(owner.r_hand, "right hand") /datum/organ/external/r_leg name = "r_leg" @@ -783,6 +857,10 @@ This function completely restores a damaged organ to perfect condition. max_damage = 30 min_broken_damage = 15 body_part = HAND_RIGHT + + process() + ..() + process_grasp(owner.r_hand, "right hand") /datum/organ/external/l_hand name = "l_hand" @@ -791,6 +869,10 @@ This function completely restores a damaged organ to perfect condition. max_damage = 30 min_broken_damage = 15 body_part = HAND_LEFT + + process() + ..() + process_grasp(owner.l_hand, "left hand") /datum/organ/external/head name = "head" diff --git a/code/modules/organs/organ_internal.dm b/code/modules/organs/organ_internal.dm index bb1ce19ad2..d5e1b19b6c 100644 --- a/code/modules/organs/organ_internal.dm +++ b/code/modules/organs/organ_internal.dm @@ -21,6 +21,7 @@ return damage >= min_broken_damage + /datum/organ/internal/New(mob/living/carbon/human/H) ..() var/datum/organ/external/E = H.organs_by_name[src.parent_organ] @@ -30,6 +31,37 @@ H.internal_organs[src.name] = src src.owner = H +/datum/organ/internal/process() + + //Process infections + if (!germ_level) + return + + if (robotic >= 2) //TODO make robotic internal and external organs separate types of organ instead of a flag + germ_level = 0 + return + + var/antibiotics = owner.reagents.get_reagent_amount("spaceacillin") + + if (germ_level > 0 && antibiotics > 5) + if (prob(4*antibiotics)) germ_level-- + if (antibiotics > 30) germ_level-- + + if (germ_level >= INFECTION_LEVEL_ONE/2) + if(prob(round(germ_level/6))) //aiming for germ level to go from ambient to INFECTION_LEVEL_TWO in an average of 15 minutes + germ_level++ + if(prob(1)) + take_damage(1,silent=0) + + if (germ_level >= INFECTION_LEVEL_TWO) + var/datum/organ/external/parent = owner.get_organ(parent_organ) + if (parent.germ_level < germ_level && ( parent.germ_level < INFECTION_LEVEL_ONE*2 || prob(30) )) + parent.germ_level++ + + if (prob(5)) //about once every 20 seconds + take_damage(1,silent=prob(30)) + + /datum/organ/internal/proc/take_damage(amount, var/silent=0) if(src.robotic == 2) src.damage += (amount * 0.8) @@ -40,7 +72,6 @@ if (!silent) owner.custom_pain("Something inside your [parent.display_name] hurts a lot.", 1) - /datum/organ/internal/proc/emp_act(severity) switch(robotic) if(0) @@ -96,7 +127,7 @@ owner.drip(10) if(prob(4)) spawn owner.emote("me", 1, "gasps for air!") - owner.losebreath += 5 + owner.losebreath += 15 /datum/organ/internal/liver name = "liver" diff --git a/code/modules/organs/wound.dm b/code/modules/organs/wound.dm index a789248627..e2763d4697 100644 --- a/code/modules/organs/wound.dm +++ b/code/modules/organs/wound.dm @@ -119,7 +119,7 @@ // checks if wound is considered open for external infections // untreated cuts (and bleeding bruises) and burns are possibly infectable, chance higher if wound is bigger - proc/can_infect() + proc/infection_check() if (is_treated() && damage < 10) return 0 if (disinfected) diff --git a/code/modules/research/xenoarchaeology/tools/anomaly_suit.dm b/code/modules/research/xenoarchaeology/tools/anomaly_suit.dm index 05e6d02d35..67ac1bd867 100644 --- a/code/modules/research/xenoarchaeology/tools/anomaly_suit.dm +++ b/code/modules/research/xenoarchaeology/tools/anomaly_suit.dm @@ -20,7 +20,7 @@ icon_state = "cespace_suit" item_state = "cespace_suit" armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 100, rad = 100) - allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank) + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit) /obj/item/clothing/head/helmet/space/anomaly name = "Excavation hood" diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm index 936d96e362..416cd159ce 100644 --- a/code/modules/vehicles/vehicle.dm +++ b/code/modules/vehicles/vehicle.dm @@ -37,7 +37,7 @@ //spawn the cell you want in each vehicle /obj/vehicle/Move() - if(world.timeofday > l_move_time + move_delay) + if(world.time > l_move_time + move_delay) if(on && powered && cell.charge < power_use) turn_off() diff --git a/code/setup.dm b/code/setup.dm index 3c190f1e2a..a444f3a2fb 100644 --- a/code/setup.dm +++ b/code/setup.dm @@ -35,10 +35,10 @@ #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 BODYTEMP_AUTORECOVERY_DIVISOR 12 //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 10 //Minimum amount of kelvin moved toward 310.15K per tick. So long as abs(310.15 - bodytemp) is more than 50. +#define BODYTEMP_AUTORECOVERY_MINIMUM 1 //Minimum amount of kelvin moved toward 310.15K per tick. So long as abs(310.15 - bodytemp) is more than 50. #define BODYTEMP_COLD_DIVISOR 6 //Similar to the BODYTEMP_AUTORECOVERY_DIVISOR, but this is the divisor which is applied at the stage that follows autorecovery. This is the divisor which comes into play when the human's loc temperature is lower than their body temperature. Make it lower to lose bodytemp faster. #define BODYTEMP_HEAT_DIVISOR 6 //Similar to the BODYTEMP_AUTORECOVERY_DIVISOR, but this is the divisor which is applied at the stage that follows autorecovery. This is the divisor which comes into play when the human's loc temperature is higher than their body temperature. Make it lower to gain bodytemp faster. -#define BODYTEMP_COOLING_MAX 30 //The maximum number of degrees that your body can cool in 1 tick, when in a cold area. +#define BODYTEMP_COOLING_MAX -30 //The maximum number of degrees that your body can cool in 1 tick, when in a cold area. #define BODYTEMP_HEATING_MAX 30 //The maximum number of degrees that your body can heat up in 1 tick, when in a hot area. #define BODYTEMP_HEAT_DAMAGE_LIMIT 360.15 // The limit the human body can take before it starts taking damage from heat. @@ -765,4 +765,12 @@ var/list/RESTRICTED_CAMERA_NETWORKS = list( //Those networks can only be accesse //Shuttle moving status #define SHUTTLE_IDLE 0 #define SHUTTLE_WARMUP 1 -#define SHUTTLE_INTRANSIT 2 \ No newline at end of file +#define SHUTTLE_INTRANSIT 2 + +//Germs and infection +#define GERM_LEVEL_AMBIENT 110 //maximum germ level you can reach by standing still +#define GERM_LEVEL_MOVE_CAP 200 //maximum germ level you can reach by running around + +#define INFECTION_LEVEL_ONE 100 +#define INFECTION_LEVEL_TWO 500 +#define INFECTION_LEVEL_THREE 1000 diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi index 54ea7f9f4c..bf2b6c4d5b 100644 Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ diff --git a/maps/tgstation2.dmm b/maps/tgstation2.dmm index afc42b26f4..9137ca4027 100644 --- a/maps/tgstation2.dmm +++ b/maps/tgstation2.dmm @@ -1626,7 +1626,7 @@ "aFn" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/structure/table/reinforced,/obj/machinery/cell_charger,/obj/item/weapon/cell/high{charge = 100; maxcharge = 15000},/obj/item/weapon/cell/high{charge = 100; maxcharge = 15000},/obj/item/weapon/cable_coil{pixel_x = 3; pixel_y = -7},/obj/item/weapon/cable_coil{pixel_x = 3; pixel_y = -7},/turf/simulated/floor{dir = 8; icon_state = "warning"},/area/ai_monitored/storage/eva) "aFo" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor{icon_state = "dark"},/area/ai_monitored/storage/eva) "aFp" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/rack{dir = 8; layer = 2.9},/obj/item/weapon/tank/oxygen,/obj/item/weapon/tank/oxygen,/obj/item/clothing/mask/breath,/obj/item/clothing/mask/breath,/obj/item/device/flashlight,/obj/item/device/flashlight,/obj/item/weapon/storage/box/lights/mixed,/turf/simulated/floor/plating,/area/storage/emergency2) -"aFq" = (/obj/structure/rack{dir = 8; layer = 2.9},/obj/item/device/modkit/tajaran,/obj/item/device/modkit/tajaran,/obj/item/device/modkit/tajaran,/turf/simulated/floor{icon_state = "vault"; dir = 8},/area/ai_monitored/storage/eva) +"aFq" = (/obj/structure/rack{dir = 8; layer = 2.9},/obj/item/device/modkit/tajaran,/obj/item/device/modkit/tajaran,/obj/item/device/modkit/tajaran,/obj/item/device/suit_cooling_unit,/obj/item/device/suit_cooling_unit,/obj/item/device/suit_cooling_unit,/turf/simulated/floor{icon_state = "vault"; dir = 8},/area/ai_monitored/storage/eva) "aFr" = (/obj/machinery/light_switch{pixel_y = 28},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/unary/vent_scrubber{dir = 4; icon_state = "off"; on = 1; scrub_N2O = 0; scrub_Toxins = 0},/turf/simulated/floor/wood,/area/bridge/meeting_room) "aFs" = (/obj/machinery/door/airlock/glass{name = "Central Access"},/turf/simulated/floor,/area/hallway/primary/fore) "aFt" = (/obj/machinery/door/airlock/glass{name = "Central Access"},/turf/simulated/floor{icon_state = "bluecorner"},/area/hallway/primary/fore)