diff --git a/code/__DEFINES/mob_defines.dm b/code/__DEFINES/mob_defines.dm index de0aafa4096e..f1514f1126f0 100644 --- a/code/__DEFINES/mob_defines.dm +++ b/code/__DEFINES/mob_defines.dm @@ -11,6 +11,10 @@ #define ORGAN_BURNT (1 << 7) #define ORGAN_SALVED (1 << 8) +// Organ datum defines. Each one of these represents a slot for organ datums in internal_organ_datums +#define ORGAN_DATUM_HEART "heart" +#define ORGAN_DATUM_LUNGS "lungs" + // For limb resistance flags #define CANNOT_BREAK (1 << 0) #define CANNOT_DISMEMBER (1 << 1) diff --git a/code/datums/components/defibrillator.dm b/code/datums/components/defibrillator.dm index 945df4b16ed8..22c884160532 100644 --- a/code/datums/components/defibrillator.dm +++ b/code/datums/components/defibrillator.dm @@ -205,12 +205,12 @@ return if(target.undergoing_cardiac_arrest()) // Can have a heart attack and heart is either missing, necrotic, or not beating - var/obj/item/organ/internal/heart/heart = target.get_int_organ(/obj/item/organ/internal/heart) + var/datum/organ/heart/heart = target.get_int_organ_datum(ORGAN_DATUM_HEART) if(!heart) user.visible_message("[defib_ref] buzzes: Resuscitation failed - Failed to pick up any heart electrical activity.") - else if(heart.status & ORGAN_DEAD) + else if(heart.linked_organ.status & ORGAN_DEAD) user.visible_message("[defib_ref] buzzes: Resuscitation failed - Heart necrosis detected.") - if(!heart || (heart.status & ORGAN_DEAD)) + if(!heart || (heart.linked_organ.status & ORGAN_DEAD)) playsound(get_turf(defib_ref), 'sound/machines/defib_failed.ogg', 50, 0) busy = FALSE return @@ -384,8 +384,8 @@ return if(electrocute_mob(affecting, power_source, origin)) // shock anyone touching them >:) - var/obj/item/organ/internal/heart/HE = affecting.get_organ_slot("heart") - if(HE.parent_organ == "chest" && affecting.has_both_hands()) // making sure the shock will go through their heart (drask hearts are in their head), and that they have both arms so the shock can cross their heart inside their chest + var/datum/organ/heart/heart = affecting.get_int_organ_datum(ORGAN_DATUM_HEART) + if(heart.linked_organ.parent_organ == "chest" && affecting.has_both_hands()) // making sure the shock will go through their heart (drask hearts are in their head), and that they have both arms so the shock can cross their heart inside their chest affecting.visible_message("[affecting]'s entire body shakes as a shock travels up [affecting.p_their()] arm!", \ "You feel a powerful shock travel up your [affecting.hand ? affecting.get_organ("l_arm") : affecting.get_organ("r_arm")] and back down your [affecting.hand ? affecting.get_organ("r_arm") : affecting.get_organ("l_arm")]!") affecting.set_heartattack(TRUE) diff --git a/code/datums/diseases/_MobProcs.dm b/code/datums/diseases/_MobProcs.dm index 0ff5231ae302..0992a054df33 100644 --- a/code/datums/diseases/_MobProcs.dm +++ b/code/datums/diseases/_MobProcs.dm @@ -153,9 +153,14 @@ if(HAS_TRAIT(src, TRAIT_VIRUSIMMUNE) && !D.bypasses_immunity) return FALSE - for(var/thing in D.required_organs) - if(!((locate(thing) in bodyparts) || (locate(thing) in internal_organs))) - return FALSE + for(var/organ in D.required_organs) + if(istext(organ) && get_int_organ_datum(organ)) + continue + if(locate(organ) in internal_organs) + continue + if(locate(organ) in bodyparts) + continue + return FALSE return ..() /mob/living/carbon/human/monkey/CanContractDisease(datum/disease/D) diff --git a/code/datums/diseases/critical.dm b/code/datums/diseases/critical.dm index ac83c8f15de6..1807c8a86e3e 100644 --- a/code/datums/diseases/critical.dm +++ b/code/datums/diseases/critical.dm @@ -87,7 +87,10 @@ cure_chance = 10 stage_prob = 5 severity = HARMFUL - required_organs = list(/obj/item/organ/internal/heart) + disease_flags = CURABLE + required_organs = list(ORGAN_DATUM_HEART) + bypasses_immunity = TRUE + virus_heal_resistant = TRUE /datum/disease/critical/heart_failure/stage_act() if(..()) diff --git a/code/datums/diseases/tuberculosis.dm b/code/datums/diseases/tuberculosis.dm index 83cf7609bf1c..e8f6bb317b5d 100644 --- a/code/datums/diseases/tuberculosis.dm +++ b/code/datums/diseases/tuberculosis.dm @@ -9,9 +9,9 @@ viable_mobtypes = list(/mob/living/carbon/human) cure_chance = 5 // Like hell are you getting out of hell desc = "A rare highly transmittable virulent virus. Few samples exist, rumoured to be carefully grown and cultured by clandestine bio-weapon specialists. Causes fever, blood vomiting, lung damage, weight loss, and fatigue." - required_organs = list(/obj/item/organ/internal/lungs) + required_organs = list(ORGAN_DATUM_LUNGS) severity = HARMFUL - bypasses_immunity = TRUE // Fungal and bacterial in nature; also infects the lungs + bypasses_immunity = TRUE //Fungal and bacterial in nature; also infects the lungs /datum/disease/tuberculosis/stage_act() if(!..()) diff --git a/code/game/gamemodes/miniantags/abduction/abduction_surgery.dm b/code/game/gamemodes/miniantags/abduction/abduction_surgery.dm index 81a53fe481a9..71890815b0df 100644 --- a/code/game/gamemodes/miniantags/abduction/abduction_surgery.dm +++ b/code/game/gamemodes/miniantags/abduction/abduction_surgery.dm @@ -29,7 +29,7 @@ /datum/surgery_step/internal/extract_organ/begin_step(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) for(var/obj/item/I in target.internal_organs) - // Allows for multiple subtypes of heart. + // Allows for multiple subtypes of heart. Doesn't use the organ datum so that slimes dont get their brains pulled out of their head if(istype(I, /obj/item/organ/internal/heart)) IC = I break diff --git a/code/game/gamemodes/miniantags/abduction/gland.dm b/code/game/gamemodes/miniantags/abduction/gland.dm index 917b73b48d6d..b8c75eb8bd32 100644 --- a/code/game/gamemodes/miniantags/abduction/gland.dm +++ b/code/game/gamemodes/miniantags/abduction/gland.dm @@ -6,14 +6,15 @@ dead_icon = null status = ORGAN_ROBOT origin_tech = "materials=4;biotech=7;abductor=3" - beating = TRUE + organ_datums = list(/datum/organ/heart/always_beating) // alien glands are immune to stopping + tough = TRUE //not easily broken by combat damage + var/cooldown_low = 300 var/cooldown_high = 300 var/next_activation = 0 var/uses // -1 For inifinite var/human_only = FALSE var/active = FALSE - tough = TRUE //not easily broken by combat damage var/mind_control_uses = 1 var/mind_control_duration = 1800 @@ -84,9 +85,6 @@ update_gland_hud() /obj/item/organ/internal/heart/gland/on_life() - if(!beating) - // alien glands are immune to stopping. - beating = TRUE if(!active) return if(!ownerCheck()) diff --git a/code/game/gamemodes/miniantags/demons/slaughter demon/slaughter.dm b/code/game/gamemodes/miniantags/demons/slaughter demon/slaughter.dm index e0a32fe54689..b4436375173c 100644 --- a/code/game/gamemodes/miniantags/demons/slaughter demon/slaughter.dm +++ b/code/game/gamemodes/miniantags/demons/slaughter demon/slaughter.dm @@ -212,6 +212,7 @@ icon = 'icons/obj/surgery.dmi' icon_state = "demon_heart" origin_tech = "combat=5;biotech=7" + organ_datums = list(/datum/organ/heart/always_beating) /obj/item/organ/internal/heart/demon/update_icon_state() return //always beating visually @@ -219,9 +220,6 @@ /obj/item/organ/internal/heart/demon/prepare_eat() return // Just so people don't accidentally waste it -/obj/item/organ/internal/heart/demon/Stop() - return 0 // Always beating. - /obj/item/organ/internal/heart/demon/attack_self(mob/living/user) user.visible_message("[user] raises [src] to [user.p_their()] mouth and tears into it with [user.p_their()] teeth!", \ "An unnatural hunger consumes you. You raise [src] to your mouth and devour it!") diff --git a/code/game/objects/items/devices/painter/painter.dm b/code/game/objects/items/devices/painter/painter.dm index 601606b035ba..fd1b2c86f800 100644 --- a/code/game/objects/items/devices/painter/painter.dm +++ b/code/game/objects/items/devices/painter/painter.dm @@ -114,7 +114,7 @@ /obj/item/painter/suicide_act(mob/user) user.visible_message("[user] is inhaling toner from [src]! It looks like [user.p_theyre()] trying to commit suicide!") playsound(src, usesound, 50, TRUE) - var/obj/item/organ/internal/lungs/L = user.get_organ_slot("lungs") + var/obj/item/organ/internal/lungs/L = user.get_organ_slot("lungs") // not going to use an organ datum here, would be too easy for slime people to throw up their brains var/turf/T = get_turf(user) if(!do_mob(user, user, 3 SECONDS) || !L) return SHAME diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index d9e251d96970..723c11a2c3c8 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -200,11 +200,11 @@ REAGENT SCANNER if(H.undergoing_cardiac_arrest()) var/obj/item/organ/internal/heart/heart = H.get_int_organ(/obj/item/organ/internal/heart) if(heart && !(heart.status & ORGAN_DEAD)) - msgs += "The patient's heart has stopped.\nPossible Cure: Electric Shock" + msgs += "The patient's heart has stopped.\nPossible Cure: Electric Shock" else if(heart && (heart.status & ORGAN_DEAD)) - msgs += "Subject's heart is necrotic." + msgs += "Subject's heart is necrotic." else if(!heart) - msgs += "Subject has no heart." + msgs += "Subject has no heart." if(H.getStaminaLoss()) msgs += "Subject appears to be suffering from fatigue." diff --git a/code/modules/clothing/under/accessories/accessory.dm b/code/modules/clothing/under/accessories/accessory.dm index 06f7622506a7..a0c2fce34752 100644 --- a/code/modules/clothing/under/accessories/accessory.dm +++ b/code/modules/clothing/under/accessories/accessory.dm @@ -156,8 +156,10 @@ user.visible_message("[user] places [src] against [user.p_their()] chest and listens attentively.", "You place [src] against your chest...") else user.visible_message("[user] places \the [src] against [M]'s chest and listens attentively.", "You place \the [src] against [M]'s chest...") - var/obj/item/organ/internal/H = M.get_int_organ(/obj/item/organ/internal/heart) - var/obj/item/organ/internal/L = M.get_int_organ(/obj/item/organ/internal/lungs) + var/datum/organ/heart/heart_datum = M.get_int_organ_datum(ORGAN_DATUM_HEART) + var/obj/item/organ/internal/H = heart_datum.linked_organ + var/datum/organ/lungs/lung_datum = M.get_int_organ_datum(ORGAN_DATUM_LUNGS) + var/obj/item/organ/internal/L = lung_datum.linked_organ if(M.pulse && (H || (L && !HAS_TRAIT(M, TRAIT_NOBREATH)))) var/color = "notice" if(H) diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index 0b0b8fa108de..a7a58c4bf233 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -3,8 +3,10 @@ pressure_resistance = 15 var/list/stomach_contents var/list/processing_patches - var/list/internal_organs = list() - var/list/internal_organs_slot = list() //Same as above, but stores "slot ID" - "organ" pairs for easy access. + var/list/internal_organs = list() + var/list/internal_organs_slot = list() //Same as above, but stores "slot ID" - "organ" pairs for easy access. + /// An associated list of strings that associate it with the organ datum, e.g. [ORGAN_DATUM_HEART] = /datum/organ/heart + var/list/internal_organ_datums = list() var/life_tick = 0 // The amount of life ticks that have processed on this mob. diff --git a/code/modules/mob/living/carbon/carbon_life.dm b/code/modules/mob/living/carbon/carbon_life.dm index 0a59c7b113b9..f533b975c095 100644 --- a/code/modules/mob/living/carbon/carbon_life.dm +++ b/code/modules/mob/living/carbon/carbon_life.dm @@ -105,7 +105,7 @@ if(status_flags & GODMODE) return FALSE - var/lungs = get_organ_slot("lungs") + var/lungs = get_int_organ_datum(ORGAN_DATUM_LUNGS) if(!lungs) adjustOxyLoss(2) @@ -201,6 +201,9 @@ for(var/thing in internal_organs) var/obj/item/organ/internal/O = thing O.on_life() + for(var/organ_tag in internal_organ_datums) + var/datum/organ/datum_organ_var_name_idk = internal_organ_datums[organ_tag] + datum_organ_var_name_idk.on_life() /mob/living/carbon/handle_diseases() for(var/thing in viruses) diff --git a/code/modules/mob/living/carbon/human/human_life.dm b/code/modules/mob/living/carbon/human/human_life.dm index 484bf057e6f5..f4583c0c60e6 100644 --- a/code/modules/mob/living/carbon/human/human_life.dm +++ b/code/modules/mob/living/carbon/human/human_life.dm @@ -131,31 +131,31 @@ /mob/living/carbon/human/check_breath(datum/gas_mixture/breath) - var/obj/item/organ/internal/L = get_organ_slot("lungs") + var/datum/organ/lungs/lung_datum = get_int_organ_datum(ORGAN_DATUM_LUNGS) - if(!L || L && (L.status & ORGAN_DEAD)) - if(health >= HEALTH_THRESHOLD_CRIT) - adjustOxyLoss(HUMAN_MAX_OXYLOSS + 1) - else if(!HAS_TRAIT(src, TRAIT_NOCRITDAMAGE)) - adjustOxyLoss(HUMAN_MAX_OXYLOSS) + if(lung_datum && !(lung_datum.linked_organ.status & ORGAN_DEAD)) + lung_datum.check_breath(breath, src) + return + + // We have no lungs, or our lungs are dead! + if(health >= HEALTH_THRESHOLD_CRIT) + adjustOxyLoss(HUMAN_MAX_OXYLOSS + 1) + else if(!HAS_TRAIT(src, TRAIT_NOCRITDAMAGE)) + adjustOxyLoss(HUMAN_MAX_OXYLOSS) - if(dna.species) - var/datum/species/S = dna.species + if(dna.species) + var/datum/species/S = dna.species - if(S.breathid == "o2") + switch(S.breathid) + if("o2") throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy) - else if(S.breathid == "tox") + if("tox") throw_alert("not_enough_tox", /obj/screen/alert/not_enough_tox) - else if(S.breathid == "co2") + if("co2") // currently unused throw_alert("not_enough_co2", /obj/screen/alert/not_enough_co2) - else if(S.breathid == "n2") + if("n2") throw_alert("not_enough_nitro", /obj/screen/alert/not_enough_nitro) - - return FALSE - else - if(istype(L, /obj/item/organ/internal/lungs)) - var/obj/item/organ/internal/lungs/lun = L - lun.check_breath(breath, src) + return FALSE // USED IN DEATHWHISPERS /mob/living/carbon/human/proc/isInCrit() @@ -796,14 +796,13 @@ H.fakevomit() /mob/living/carbon/human/proc/handle_heartbeat() - var/client/C = src.client - if(C && C.prefs.sound & SOUND_HEARTBEAT) //disable heartbeat by pref - var/obj/item/organ/internal/heart/H = get_int_organ(/obj/item/organ/internal/heart) + if(client && client.prefs.sound & SOUND_HEARTBEAT) //disable heartbeat by pref + var/datum/organ/heart/H = get_int_organ_datum(ORGAN_DATUM_HEART) if(!H) //H.status will runtime if there is no H (obviously) return - if(H.is_robotic()) //Handle robotic hearts specially with a wuuuubb. This also applies to machine-people. + if(H.linked_organ.is_robotic()) //Handle robotic hearts specially with a wuuuubb. This also applies to machine-people. if(isinspace()) //PULSE_THREADY - maximum value for pulse, currently it 5. //High pulse value corresponds to a fast rate of heartbeat. @@ -816,7 +815,6 @@ else heartbeat++ - return return if(pulse == PULSE_NONE) @@ -851,21 +849,18 @@ if(!can_heartattack()) return FALSE - var/obj/item/organ/internal/heart/heart = get_int_organ(/obj/item/organ/internal/heart) - if(!istype(heart) || (heart.status & ORGAN_DEAD) || !heart.beating) + var/datum/organ/heart/heart_datum = get_int_organ_datum(ORGAN_DATUM_HEART) + if(!istype(heart_datum) || (heart_datum.linked_organ.status & ORGAN_DEAD)) return TRUE - return FALSE + return !heart_datum.beating + /mob/living/carbon/human/proc/set_heartattack(status) if(!can_heartattack()) return FALSE - - var/obj/item/organ/internal/heart/heart = get_int_organ(/obj/item/organ/internal/heart) - if(!istype(heart)) - return FALSE - - heart.beating = !status + var/datum/organ/heart/heart_datum = get_int_organ_datum(ORGAN_DATUM_HEART) + heart_datum?.change_beating(!status) /mob/living/carbon/human/handle_heartattack() if(!can_heartattack() || !undergoing_cardiac_arrest() || reagents.has_reagent("corazone")) diff --git a/code/modules/mob/living/carbon/human/human_mob.dm b/code/modules/mob/living/carbon/human/human_mob.dm index 9c0b81b97412..6e33d88a31ae 100644 --- a/code/modules/mob/living/carbon/human/human_mob.dm +++ b/code/modules/mob/living/carbon/human/human_mob.dm @@ -1207,20 +1207,16 @@ ..() /mob/living/carbon/human/proc/is_lung_ruptured() - var/obj/item/organ/internal/lungs/L = get_int_organ(/obj/item/organ/internal/lungs) - if(!L) - return 0 + var/datum/organ/lungs/L = get_int_organ_datum(ORGAN_DATUM_LUNGS) - return L.is_bruised() + return L?.linked_organ.is_bruised() /mob/living/carbon/human/proc/rupture_lung() - var/obj/item/organ/internal/lungs/L = get_int_organ(/obj/item/organ/internal/lungs) - if(!L) - return 0 - - if(!L.is_bruised()) - L.custom_pain("You feel a stabbing pain in your chest!") - L.damage = L.min_bruised_damage + var/datum/organ/lungs/L = get_int_organ_datum(ORGAN_DATUM_LUNGS) + if(L && !L.linked_organ.is_bruised()) + var/obj/item/organ/external/affected = get_organ("chest") + affected.custom_pain("You feel a stabbing pain in your chest!") + L.linked_organ.damage = L.linked_organ.min_bruised_damage /mob/living/carbon/human/cuff_resist(obj/item/I) if(HAS_TRAIT(src, TRAIT_HULK)) diff --git a/code/modules/mob/living/carbon/human/human_organs.dm b/code/modules/mob/living/carbon/human/human_organs.dm index eefd16486c7c..2815f929a9c3 100644 --- a/code/modules/mob/living/carbon/human/human_organs.dm +++ b/code/modules/mob/living/carbon/human/human_organs.dm @@ -162,17 +162,6 @@ old_ue: Set this to a UE string, and this proc will overwrite the dna of organs if(assimilate || O.dna.unique_enzymes == ue_to_compare) O.set_dna(dna) -/* -Given the name of an organ, returns the external organ it's contained in -I use this to standardize shadowling dethrall code --- Crazylemon -*/ -/mob/living/carbon/human/proc/named_organ_parent(organ_name) - if(!get_int_organ_tag(organ_name)) - return null - var/obj/item/organ/internal/O = get_int_organ_tag(organ_name) - return O.parent_organ - /mob/living/carbon/human/has_organic_damage() var/robo_damage = 0 var/perma_injury_damage = 0 diff --git a/code/modules/mob/living/carbon/human/human_say.dm b/code/modules/mob/living/carbon/human/human_say.dm index b158aa2aec42..c6e66e1b38ee 100644 --- a/code/modules/mob/living/carbon/human/human_say.dm +++ b/code/modules/mob/living/carbon/human/human_say.dm @@ -67,10 +67,10 @@ return TRUE // how do species that don't breathe talk? magic, that's what. var/breathes = (!HAS_TRAIT(src, TRAIT_NOBREATH)) - var/obj/item/organ/internal/L = get_organ_slot("lungs") + var/datum/organ/lungs/L = get_int_organ_datum(ORGAN_DATUM_LUNGS) if(HAS_TRAIT(src, TRAIT_MUTE)) return FALSE - if((breathes && !L) || breathes && L && (L.status & ORGAN_DEAD)) + if(breathes && (!L || L.linked_organ.status & ORGAN_DEAD)) return FALSE if(mind) return !mind.miming diff --git a/code/modules/mob/living/carbon/human/species/slimepeople.dm b/code/modules/mob/living/carbon/human/species/slimepeople.dm index 69df4f74bf20..9a7cc5098eef 100644 --- a/code/modules/mob/living/carbon/human/species/slimepeople.dm +++ b/code/modules/mob/living/carbon/human/species/slimepeople.dm @@ -49,9 +49,7 @@ vision_organ = null has_organ = list( - "heart" = /obj/item/organ/internal/heart/slime, - "brain" = /obj/item/organ/internal/brain/slime, - "lungs" = /obj/item/organ/internal/lungs/slime + "brain" = /obj/item/organ/internal/brain/slime ) mutantears = null suicide_messages = list( diff --git a/code/modules/reagents/chemistry/reagents/disease.dm b/code/modules/reagents/chemistry/reagents/disease.dm index c5941b342456..335af8f37b19 100644 --- a/code/modules/reagents/chemistry/reagents/disease.dm +++ b/code/modules/reagents/chemistry/reagents/disease.dm @@ -124,6 +124,7 @@ if(volume > 4.5) if(ishuman(M)) var/mob/living/carbon/human/H = M + // im not going to make this an organ datum, so that slime people dont get their brain instantly deleted var/obj/item/organ/internal/heart/ate_heart = H.get_int_organ(/obj/item/organ/internal/heart) if(ate_heart) ate_heart.remove(H) diff --git a/code/modules/station_goals/dna_vault.dm b/code/modules/station_goals/dna_vault.dm index eeaa2cf22ce4..794b0f1fadc0 100644 --- a/code/modules/station_goals/dna_vault.dm +++ b/code/modules/station_goals/dna_vault.dm @@ -305,7 +305,7 @@ GLOBAL_LIST_INIT(non_simple_animals, typecacheof(list(/mob/living/carbon/human/m switch(upgrade_type) if(VAULT_TOXIN) to_chat(H, "You feel resistant to airborne toxins.") - var/obj/item/organ/internal/lungs/L = H.get_int_organ(/obj/item/organ/internal/lungs) + var/datum/organ/lungs/L = H.get_int_organ_datum(ORGAN_DATUM_LUNGS) if(L) L.tox_breath_dam_min = 0 L.tox_breath_dam_max = 0 diff --git a/code/modules/surgery/organs/brain.dm b/code/modules/surgery/organs/brain.dm index 3e55578c4a4c..a7e8b1c9e853 100644 --- a/code/modules/surgery/organs/brain.dm +++ b/code/modules/surgery/organs/brain.dm @@ -187,13 +187,14 @@ /obj/item/organ/internal/brain/prepare_eat() return // Too important to eat. +// Hello I am from the ministry of rubber forehead aliens how are you /obj/item/organ/internal/brain/slime name = "slime core" desc = "A complex, organic knot of jelly and crystalline particles." icon = 'icons/mob/slimes.dmi' icon_state = "green slime extract" mmi_icon_state = "slime_mmi" -// parent_organ = "chest" Hello I am from the ministry of rubber forehead aliens how are you + organ_datums = list(/datum/organ/heart, /datum/organ/lungs) /obj/item/organ/internal/brain/golem name = "Runic mind" diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm index f20903ee0252..029bbbec2234 100644 --- a/code/modules/surgery/organs/heart.dm +++ b/code/modules/surgery/organs/heart.dm @@ -5,74 +5,35 @@ parent_organ = "chest" slot = "heart" origin_tech = "biotech=5" - var/beating = TRUE dead_icon = "heart-off" - var/icon_base = "heart" + base_icon_state = "heart" + organ_datums = list(/datum/organ/heart) /obj/item/organ/internal/heart/update_icon_state() - if(beating) - icon_state = "[icon_base]-on" + var/datum/organ/heart/heart = organ_datums["heart"] + if(heart.beating) + icon_state = "[base_icon_state]-on" else - icon_state = "[icon_base]-off" - -/obj/item/organ/internal/heart/remove(mob/living/carbon/M, special = 0) - . = ..() - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.stat == DEAD) - Stop() - return - - if(!special) - addtimer(CALLBACK(src, PROC_REF(stop_if_unowned)), 120) - -/obj/item/organ/internal/heart/emp_act(intensity) - if(!is_robotic() || emp_proof) - return - Stop() - -/obj/item/organ/internal/heart/necrotize() - ..() - Stop() + icon_state = "[base_icon_state]-off" /obj/item/organ/internal/heart/attack_self(mob/user) ..() if(status & ORGAN_DEAD) to_chat(user, "You can't restart a dead heart.") return - if(!beating) - Restart() - addtimer(CALLBACK(src, PROC_REF(stop_if_unowned)), 80) + var/datum/organ/heart/heart = organ_datums["heart"] + heart.try_restart(8 SECONDS) /obj/item/organ/internal/heart/safe_replace(mob/living/carbon/human/target) - Restart() + var/datum/organ/heart/heart = organ_datums["heart"] + heart.change_beating(TRUE) ..() -/obj/item/organ/internal/heart/proc/stop_if_unowned() - if(!owner) - Stop() - -/obj/item/organ/internal/heart/proc/Stop() - beating = FALSE - update_icon(UPDATE_ICON_STATE) - return TRUE - -/obj/item/organ/internal/heart/proc/Restart() - beating = TRUE - update_icon(UPDATE_ICON_STATE) - return TRUE - -/obj/item/organ/internal/heart/prepare_eat() - var/obj/S = ..() - if(S) - S.icon_state = dead_icon - return S - /obj/item/organ/internal/heart/cursed name = "cursed heart" desc = "it needs to be pumped..." icon_state = "cursedheart-off" - icon_base = "cursedheart" + base_icon_state = "cursedheart" origin_tech = "biotech=6" actions_types = list(/datum/action/item_action/organ_action/cursed_heart) var/last_pump = 0 @@ -215,7 +176,7 @@ name = "cybernetic heart" desc = "An electronic device designed to mimic the functions of an organic human heart. Offers no benefit over an organic heart other than being easy to make." icon_state = "heart-c-on" - icon_base = "heart-c" + base_icon_state = "heart-c" dead_icon = "heart-c-off" status = ORGAN_ROBOT @@ -223,7 +184,7 @@ name = "upgraded cybernetic heart" desc = "A more advanced version of a cybernetic heart. Grants the user additional stamina and heart stability, but the electronics are vulnerable to shock." icon_state = "heart-c-u-on" - icon_base = "heart-c-u" + base_icon_state = "heart-c-u" dead_icon = "heart-c-u-off" var/attempted_restart = FALSE @@ -242,27 +203,42 @@ if(!ishuman(owner)) return - if(!(status & ORGAN_DEAD) && !attempted_restart && !beating) + if(status & ORGAN_DEAD) + return + + var/boost = emagged ? 2 : 1 + owner.AdjustParalysis(-2 SECONDS * boost) + owner.AdjustStunned(-2 SECONDS * boost) + owner.AdjustWeakened(-2 SECONDS * boost) + owner.AdjustKnockDown(-2 SECONDS * boost) + owner.adjustStaminaLoss(-10 * boost) + + if(attempted_restart) + return + + var/datum/organ/heart/heart_datum = organ_datums["heart"] + + if(!heart_datum.beating) to_chat(owner, "Your [name] detects a cardiac event and attempts to return to its normal rhythm!") if(prob(20) && emagged) attempted_restart = TRUE - Restart() - addtimer(CALLBACK(src, PROC_REF(message_to_owner), owner, "Your [name] returns to its normal rhythm!"), 30) - addtimer(CALLBACK(src, PROC_REF(recharge)), 200) + heart_datum.change_beating(TRUE) // Mötley Crüe - Kickstart My Heart + addtimer(CALLBACK(src, PROC_REF(message_to_owner), owner, "Your [name] returns to its normal rhythm!"), 3 SECONDS) + addtimer(CALLBACK(src, PROC_REF(recharge)), 20 SECONDS) else if(prob(10)) attempted_restart = TRUE - Restart() - addtimer(CALLBACK(src, PROC_REF(message_to_owner), owner, "Your [name] returns to its normal rhythm!"), 30) - addtimer(CALLBACK(src, PROC_REF(recharge)), 300) + heart_datum.change_beating(TRUE) + addtimer(CALLBACK(src, PROC_REF(message_to_owner), owner, "Your [name] returns to its normal rhythm!"), 3 SECONDS) + addtimer(CALLBACK(src, PROC_REF(recharge)), 30 SECONDS) else attempted_restart = TRUE if(emagged) - addtimer(CALLBACK(src, PROC_REF(recharge)), 200) + addtimer(CALLBACK(src, PROC_REF(recharge)), 20 SECONDS) else - addtimer(CALLBACK(src, PROC_REF(recharge)), 300) - addtimer(CALLBACK(src, PROC_REF(message_to_owner), owner, "Your [name] fails to return to its normal rhythm!"), 30) + addtimer(CALLBACK(src, PROC_REF(recharge)), 30 SECONDS) + addtimer(CALLBACK(src, PROC_REF(message_to_owner), owner, "Your [name] fails to return to its normal rhythm!"), 3 SECONDS) - if(!(status & ORGAN_DEAD) && !attempted_restart && owner.HasDisease(new /datum/disease/critical/heart_failure(0))) + if(owner.HasDisease(new /datum/disease/critical/heart_failure(0))) to_chat(owner, "Your [name] detects a cardiac event and attempts to return to its normal rhythm!") if(prob(40) && emagged) attempted_restart = TRUE @@ -284,14 +260,6 @@ addtimer(CALLBACK(src, PROC_REF(recharge)), 300) addtimer(CALLBACK(src, PROC_REF(message_to_owner), owner, "Your [name] fails to return to its normal rhythm!"), 30) - if(!(status & ORGAN_DEAD)) - var/boost = emagged ? 2 : 1 - owner.AdjustParalysis(-2 SECONDS * boost) - owner.AdjustStunned(-2 SECONDS * boost) - owner.AdjustWeakened(-2 SECONDS * boost) - owner.AdjustKnockDown(-2 SECONDS * boost) - owner.adjustStaminaLoss(-10 * boost) - /obj/item/organ/internal/heart/cybernetic/upgraded/proc/message_to_owner(mob/M, message) to_chat(M, message) @@ -333,7 +301,8 @@ owner.ForceContractDisease(new /datum/disease/critical/heart_failure(0)) if(prob(numMid)) to_chat(owner, "Your [name] stops beating!") - Stop() + var/datum/organ/heart/heart_datum = organ_datums["heart"] + heart_datum.change_beating(FALSE) // Rambunctious Crew - Stop My Fucking Heart if(prob(numLow)) to_chat(owner, "Your [name] shuts down!") necrotize() diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm index 858c448ad82b..4aed3d4d5c31 100644 --- a/code/modules/surgery/organs/lungs.dm +++ b/code/modules/surgery/organs/lungs.dm @@ -7,306 +7,7 @@ gender = PLURAL w_class = WEIGHT_CLASS_NORMAL - //Breath damage - - var/safe_oxygen_min = 16 // Minimum safe partial pressure of O2, in kPa - var/safe_oxygen_max = 0 - var/safe_nitro_min = 0 - var/safe_nitro_max = 0 - var/safe_co2_min = 0 - var/safe_co2_max = 10 // Yes it's an arbitrary value who cares? - var/safe_toxins_min = 0 - var/safe_toxins_max = 0.05 - var/SA_para_min = 1 //Sleeping agent - var/SA_sleep_min = 5 //Sleeping agent - - - var/oxy_breath_dam_min = MIN_TOXIC_GAS_DAMAGE - var/oxy_breath_dam_max = MAX_TOXIC_GAS_DAMAGE - var/oxy_damage_type = OXY - var/nitro_breath_dam_min = MIN_TOXIC_GAS_DAMAGE - var/nitro_breath_dam_max = MAX_TOXIC_GAS_DAMAGE - var/nitro_damage_type = OXY - var/co2_breath_dam_min = MIN_TOXIC_GAS_DAMAGE - var/co2_breath_dam_max = MAX_TOXIC_GAS_DAMAGE - var/co2_damage_type = OXY - var/tox_breath_dam_min = MIN_TOXIC_GAS_DAMAGE - var/tox_breath_dam_max = MAX_TOXIC_GAS_DAMAGE - var/tox_damage_type = TOX - - var/cold_message = "your face freezing and an icicle forming" - var/cold_level_1_threshold = 260 - var/cold_level_2_threshold = 200 - var/cold_level_3_threshold = 120 - var/cold_level_1_damage = COLD_GAS_DAMAGE_LEVEL_1 //Keep in mind with gas damage levels, you can set these to be negative, if you want someone to heal, instead. - var/cold_level_2_damage = COLD_GAS_DAMAGE_LEVEL_2 - var/cold_level_3_damage = COLD_GAS_DAMAGE_LEVEL_3 - var/cold_damage_types = list(BURN = 1) - - var/hot_message = "your face burning and a searing heat" - var/heat_level_1_threshold = 360 - var/heat_level_2_threshold = 400 - var/heat_level_3_threshold = 1000 - var/heat_level_1_damage = HEAT_GAS_DAMAGE_LEVEL_1 - var/heat_level_2_damage = HEAT_GAS_DAMAGE_LEVEL_2 - var/heat_level_3_damage = HEAT_GAS_DAMAGE_LEVEL_3 - var/heat_damage_types = list(BURN = 1) - -/obj/item/organ/internal/lungs/emp_act() - if(!is_robotic() || emp_proof) - return - if(owner) - owner.LoseBreath(40 SECONDS) - -/obj/item/organ/internal/lungs/insert(mob/living/carbon/M, special = 0, dont_remove_slot = 0) - ..() - for(var/thing in list("oxy", "tox", "co2", "nitro")) - M.clear_alert("not_enough_[thing]") - M.clear_alert("too_much_[thing]") - -/obj/item/organ/internal/lungs/remove(mob/living/carbon/M, special = 0) - for(var/thing in list("oxy", "tox", "co2", "nitro")) - M.clear_alert("not_enough_[thing]") - M.clear_alert("too_much_[thing]") - return ..() - -/obj/item/organ/internal/lungs/on_life() - if(germ_level > INFECTION_LEVEL_ONE) - if(prob(5)) - owner.emote("cough") //respitory tract infection - - if(is_bruised()) - if(prob(2) && !(NO_BLOOD in owner.dna.species.species_traits)) - owner.custom_emote(EMOTE_VISIBLE, "coughs up blood!") - owner.bleed(1) - if(prob(4)) - owner.custom_emote(EMOTE_VISIBLE, "gasps for air!") - owner.AdjustLoseBreath(10 SECONDS) - -/obj/item/organ/internal/lungs/proc/check_breath(datum/gas_mixture/breath, mob/living/carbon/human/H) - if((H.status_flags & GODMODE)) - return - - if(HAS_TRAIT(H, TRAIT_NOBREATH)) - return - - if(!breath || (breath.total_moles() == 0)) - if(isspaceturf(H.loc)) - H.adjustOxyLoss(10) - else - H.adjustOxyLoss(5) - - if(safe_oxygen_min) - H.throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy) - else if(safe_toxins_min) - H.throw_alert("not_enough_tox", /obj/screen/alert/not_enough_tox) - else if(safe_co2_min) - H.throw_alert("not_enough_co2", /obj/screen/alert/not_enough_co2) - else if(safe_nitro_min) - H.throw_alert("not_enough_nitro", /obj/screen/alert/not_enough_nitro) - return FALSE - - - if(H.health < HEALTH_THRESHOLD_CRIT) - return FALSE - - var/gas_breathed = 0 - - //Partial pressures in our breath - var/O2_pp = breath.get_breath_partial_pressure(breath.oxygen) - var/N2_pp = breath.get_breath_partial_pressure(breath.nitrogen) - var/Toxins_pp = breath.get_breath_partial_pressure(breath.toxins) - var/CO2_pp = breath.get_breath_partial_pressure(breath.carbon_dioxide) - var/SA_pp = breath.get_breath_partial_pressure(breath.sleeping_agent) - - - //-- OXY --// - - //Too much oxygen! //Yes, some species may not like it. - if(safe_oxygen_max) - if(O2_pp > safe_oxygen_max) - var/ratio = (breath.oxygen / safe_oxygen_max / safe_oxygen_max) * 10 - H.apply_damage_type(clamp(ratio, oxy_breath_dam_min, oxy_breath_dam_max), oxy_damage_type) - H.throw_alert("too_much_oxy", /obj/screen/alert/too_much_oxy) - else - H.clear_alert("too_much_oxy") - - //Too little oxygen! - if(safe_oxygen_min) - if(O2_pp < safe_oxygen_min) - gas_breathed = handle_too_little_breath(H, O2_pp, safe_oxygen_min, breath.oxygen) - H.throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy) - else - H.adjustOxyLoss(-HUMAN_MAX_OXYLOSS) - gas_breathed = breath.oxygen - H.clear_alert("not_enough_oxy") - - //Exhale - breath.oxygen -= gas_breathed - breath.carbon_dioxide += gas_breathed - gas_breathed = 0 - - //-- Nitrogen --// - - //Too much nitrogen! - if(safe_nitro_max) - if(N2_pp > safe_nitro_max) - var/ratio = (breath.nitrogen / safe_nitro_max) * 10 - H.apply_damage_type(clamp(ratio, nitro_breath_dam_min, nitro_breath_dam_max), nitro_damage_type) - H.throw_alert("too_much_nitro", /obj/screen/alert/too_much_nitro) - else - H.clear_alert("too_much_nitro") - - //Too little nitrogen! - if(safe_nitro_min) - if(N2_pp < safe_nitro_min) - gas_breathed = handle_too_little_breath(H, N2_pp, safe_nitro_min, breath.nitrogen) - H.throw_alert("not_enough_nitro", /obj/screen/alert/not_enough_nitro) - else - H.adjustOxyLoss(-HUMAN_MAX_OXYLOSS) - gas_breathed = breath.nitrogen - H.clear_alert("not_enough_nitro") - - //Exhale - breath.nitrogen -= gas_breathed - breath.carbon_dioxide += gas_breathed - gas_breathed = 0 - - //-- CO2 --// - - //CO2 does not affect failed_last_breath. So if there was enough oxygen in the air but too much co2, this will hurt you, but only once per 4 ticks, instead of once per tick. - if(safe_co2_max) - if(CO2_pp > safe_co2_max) - if(!H.co2overloadtime) // If it's the first breath with too much CO2 in it, lets start a counter, then have them pass out after 12s or so. - H.co2overloadtime = world.time - else if(world.time - H.co2overloadtime > 120) - H.Paralyse(6 SECONDS) - H.apply_damage_type(HUMAN_MAX_OXYLOSS, co2_damage_type) // Lets hurt em a little, let them know we mean business - if(world.time - H.co2overloadtime > 300) // They've been in here 30s now, lets start to kill them for their own good! - H.apply_damage_type(15, co2_damage_type) - H.throw_alert("too_much_co2", /obj/screen/alert/too_much_co2) - if(prob(20)) // Lets give them some chance to know somethings not right though I guess. - H.emote("cough") - - else - H.co2overloadtime = 0 - H.clear_alert("too_much_co2") - - //Too little CO2! - if(safe_co2_min) - if(CO2_pp < safe_co2_min) - gas_breathed = handle_too_little_breath(H, CO2_pp, safe_co2_min, breath.carbon_dioxide) - H.throw_alert("not_enough_co2", /obj/screen/alert/not_enough_co2) - else - H.adjustOxyLoss(-HUMAN_MAX_OXYLOSS) - gas_breathed = breath.carbon_dioxide - H.clear_alert("not_enough_co2") - - //Exhale - breath.carbon_dioxide -= gas_breathed - breath.oxygen += gas_breathed - gas_breathed = 0 - - - //-- TOX --// - - //Too much toxins! - if(safe_toxins_max) - if(Toxins_pp > safe_toxins_max) - var/ratio = (breath.toxins / safe_toxins_max) * 10 - H.apply_damage_type(clamp(ratio, tox_breath_dam_min, tox_breath_dam_max), tox_damage_type) - H.throw_alert("too_much_tox", /obj/screen/alert/too_much_tox) - else - H.clear_alert("too_much_tox") - - - //Too little toxins! - if(safe_toxins_min) - if(Toxins_pp < safe_toxins_min) - gas_breathed = handle_too_little_breath(H, Toxins_pp, safe_toxins_min, breath.toxins) - H.throw_alert("not_enough_tox", /obj/screen/alert/not_enough_tox) - else - H.adjustOxyLoss(-HUMAN_MAX_OXYLOSS) - gas_breathed = breath.toxins - H.clear_alert("not_enough_tox") - - //Exhale - breath.toxins -= gas_breathed - breath.carbon_dioxide += gas_breathed - gas_breathed = 0 - - - //-- TRACES --// - - if(breath.sleeping_agent) // If there's some other shit in the air lets deal with it here. - if(SA_pp > SA_para_min) - H.Paralyse(6 SECONDS) // 6 seconds gives them one second to wake up and run away a bit! - if(SA_pp > SA_sleep_min) // Enough to make us sleep as well - H.AdjustSleeping(16 SECONDS, bound_lower = 0, bound_upper = 20 SECONDS) - else if(SA_pp > 0.01) // There is sleeping gas in their lungs, but only a little, so give them a bit of a warning - if(prob(20)) - H.emote(pick("giggle", "laugh")) - - handle_breath_temperature(breath, H) - - return TRUE - - -/obj/item/organ/internal/lungs/proc/handle_too_little_breath(mob/living/carbon/human/H = null, breath_pp = 0, safe_breath_min = 0, true_pp = 0) - . = 0 - if(!H || !safe_breath_min) //the other args are either: Ok being 0 or Specifically handled. - return FALSE - - if(prob(20)) - H.emote("gasp") - if(breath_pp > 0) - var/ratio = safe_breath_min/breath_pp - H.adjustOxyLoss(min(5*ratio, HUMAN_MAX_OXYLOSS)) // Don't fuck them up too fast (space only does HUMAN_MAX_OXYLOSS after all! - . = true_pp*ratio/6 - else - H.adjustOxyLoss(HUMAN_MAX_OXYLOSS) - - -/obj/item/organ/internal/lungs/proc/handle_breath_temperature(datum/gas_mixture/breath, mob/living/carbon/human/H) // called by human/life, handles temperatures - var/breath_temperature = breath.temperature - - if(!HAS_TRAIT(H, TRAIT_RESISTCOLD)) // COLD DAMAGE - var/CM = abs(H.dna.species.coldmod) - var/TC = 0 - if(breath_temperature < cold_level_3_threshold) - TC = cold_level_3_damage - if(breath_temperature > cold_level_3_threshold && breath_temperature < cold_level_2_threshold) - TC = cold_level_2_damage - if(breath_temperature > cold_level_2_threshold && breath_temperature < cold_level_1_threshold) - TC = cold_level_1_damage - if(TC) - for(var/D in cold_damage_types) - H.apply_damage_type(TC * CM * cold_damage_types[D], D) - if(breath_temperature < cold_level_1_threshold) - if(prob(20)) - to_chat(H, "You feel [cold_message] in your [name]!") - - if(!HAS_TRAIT(H, TRAIT_RESISTHEAT)) // HEAT DAMAGE - var/HM = abs(H.dna.species.heatmod) - var/TH = 0 - if(breath_temperature > heat_level_1_threshold && breath_temperature < heat_level_2_threshold) - TH = heat_level_1_damage - if(breath_temperature > heat_level_2_threshold && breath_temperature < heat_level_3_threshold) - TH = heat_level_2_damage - if(breath_temperature > heat_level_3_threshold) - TH = heat_level_3_damage - if(TH) - for(var/D in heat_damage_types) - H.apply_damage_type(TH * HM * heat_damage_types[D], D) - if(breath_temperature > heat_level_1_threshold) - if(prob(20)) - to_chat(H, "You feel [hot_message] in your [name]!") - -/obj/item/organ/internal/lungs/prepare_eat() - var/obj/S = ..() - if(S) - S.reagents.add_reagent("salbutamol", 5) - return S + organ_datums = list(/datum/organ/lungs) /obj/item/organ/internal/lungs/plasmaman name = "plasma filter" @@ -314,9 +15,7 @@ icon = 'icons/obj/species_organs/plasmaman.dmi' icon_state = "lungs" - safe_oxygen_min = 0 //We don't breath this - safe_toxins_min = 16 //We breathe THIS! - safe_toxins_max = 0 + organ_datums = list(/datum/organ/lungs/plasmamen) /obj/item/organ/internal/lungs/vox name = "vox lungs" @@ -325,20 +24,12 @@ icon_state = "lungs" sterile = TRUE - safe_oxygen_min = 0 //We don't breathe this - safe_oxygen_max = 0.05 //This is toxic to us - safe_nitro_min = 16 //We breathe THIS! - oxy_damage_type = TOX //And it poisons us + organ_datums = list(/datum/organ/lungs/vox) /obj/item/organ/internal/lungs/drask icon = 'icons/obj/species_organs/drask.dmi' - cold_message = "an invigorating coldness" - cold_level_3_threshold = 60 - cold_level_1_damage = -COLD_GAS_DAMAGE_LEVEL_1 //They heal when the air is cold - cold_level_2_damage = -COLD_GAS_DAMAGE_LEVEL_2 - cold_level_3_damage = -COLD_GAS_DAMAGE_LEVEL_3 - cold_damage_types = list(BRUTE = 0.5, BURN = 0.25) + organ_datums = list(/datum/organ/lungs/drask) /obj/item/organ/internal/lungs/cybernetic name = "cybernetic lungs" @@ -346,7 +37,7 @@ icon_state = "lungs-c" origin_tech = "biotech=4" status = ORGAN_ROBOT - var/species_state = "human" + var/species_state = "default" /obj/item/organ/internal/lungs/cybernetic/examine(mob/user) . = ..() @@ -356,28 +47,20 @@ . = TRUE if(!I.use_tool(src, user, 0, volume = I.tool_volume)) return - switch(species_state) - if("human") // from human to vox - safe_oxygen_min = 0 - safe_oxygen_max = safe_toxins_max - safe_nitro_min = 16 - oxy_damage_type = TOX - to_chat(user, "You configure [src] to replace vox lungs.") - species_state = "vox" - if("vox") // from vox to plasmamen - safe_oxygen_max = initial(safe_oxygen_max) - safe_toxins_min = 16 - safe_toxins_max = 0 - safe_nitro_min = initial(safe_nitro_min) - oxy_damage_type = OXY - to_chat(user, "You configure [src] to replace plasmamen lungs.") - species_state = "plasmamen" - if("plasmamen") // from plasmamen to human - safe_oxygen_min = initial(safe_oxygen_min) - safe_toxins_min = initial(safe_toxins_min) - safe_toxins_max = initial(safe_toxins_max) - to_chat(user, "You configure [src] back to default settings.") - species_state = "human" + + var/possible = list("default" = /datum/organ/lungs, "vox" = /datum/organ/lungs/vox, "plasmamen" = /datum/organ/lungs/plasmamen) + var/chosen = input(user, "Select lung type", "What kind of lung settings?") as null|anything in possible + if(isnull(chosen) || chosen == species_state || !Adjacent(user) || !I.use_tool(src, user, 0, volume = I.tool_volume)) + return + species_state = chosen + to_chat(user, "You configure [src] to [chosen] settings.") + + var/typepath = possible[chosen] + var/datum/organ/lungs/lungs = new typepath(src) + qdel(organ_datums[lungs.organ_tag]) + organ_datums[lungs.organ_tag] = lungs + if(owner) // this should never happen, but in case it somehow does... + owner.internal_organ_datums[lungs.organ_tag] = lungs /obj/item/organ/internal/lungs/cybernetic/upgraded name = "upgraded cybernetic lungs" @@ -385,9 +68,9 @@ icon_state = "lungs-c-u" origin_tech = "biotech=5" - safe_toxins_max = 20 - safe_co2_max = 20 + organ_datums = list(/datum/organ/lungs/advanced_cyber) - cold_level_1_threshold = 200 - cold_level_2_threshold = 140 - cold_level_3_threshold = 100 +/obj/item/organ/internal/lungs/cybernetic/upgraded/multitool_act(mob/user, obj/item/I) + . = ..() + var/datum/organ/lungs/lungs = organ_datums["lungs"] + lungs.make_advanced() diff --git a/code/modules/surgery/organs/organ_datums/heart_datum.dm b/code/modules/surgery/organs/organ_datums/heart_datum.dm new file mode 100644 index 000000000000..1c18c21bed53 --- /dev/null +++ b/code/modules/surgery/organs/organ_datums/heart_datum.dm @@ -0,0 +1,47 @@ +/datum/organ/heart + organ_tag = ORGAN_DATUM_HEART + var/beating = TRUE + var/always_beating = FALSE + +/datum/organ/heart/on_remove(mob/living/carbon/removed_from, special = FALSE) + . = ..() + if(ishuman(removed_from)) + var/mob/living/carbon/human/H = removed_from + if(H.stat == DEAD) + change_beating(FALSE) + return + + if(!special) + addtimer(CALLBACK(src, PROC_REF(stop_if_unowned)), 12 SECONDS) + +/datum/organ/heart/proc/change_beating(change_to = FALSE) + if(always_beating) + beating = TRUE + return + beating = change_to + linked_organ.update_icon() + +/datum/organ/heart/on_successful_emp() + change_beating(FALSE) + return TRUE + +/datum/organ/heart/on_necrotize() + change_beating(FALSE) + return TRUE + +/datum/organ/heart/proc/try_restart(duration = 8 SECONDS) + if(beating) + return + change_beating(TRUE) + addtimer(CALLBACK(src, PROC_REF(stop_if_unowned)), duration) + +/datum/organ/heart/proc/stop_if_unowned() + if(!linked_organ.owner) + change_beating(FALSE) + +/datum/organ/heart/on_prepare_eat(obj/item/food/snacks/organ/snorgan) + snorgan.icon_state = linked_organ.dead_icon + +/// A subtype that is always beating. Abductor glands and demon hearts use this. +/datum/organ/heart/always_beating + always_beating = TRUE diff --git a/code/modules/surgery/organs/organ_datums/lung_datum.dm b/code/modules/surgery/organs/organ_datums/lung_datum.dm new file mode 100644 index 000000000000..19e683c06251 --- /dev/null +++ b/code/modules/surgery/organs/organ_datums/lung_datum.dm @@ -0,0 +1,345 @@ +/datum/organ/lungs + organ_tag = ORGAN_DATUM_LUNGS + + //Breath damage + + var/safe_oxygen_min = 16 // Minimum safe partial pressure of O2, in kPa + var/safe_oxygen_max = 0 + var/safe_nitro_min = 0 + var/safe_nitro_max = 0 + var/safe_co2_min = 0 + var/safe_co2_max = 10 // Yes it's an arbitrary value who cares? + var/safe_toxins_min = 0 + var/safe_toxins_max = 0.05 + var/SA_para_min = 1 //Sleeping agent + var/SA_sleep_min = 5 //Sleeping agent + + + var/oxy_breath_dam_min = MIN_TOXIC_GAS_DAMAGE + var/oxy_breath_dam_max = MAX_TOXIC_GAS_DAMAGE + var/oxy_damage_type = OXY + var/nitro_breath_dam_min = MIN_TOXIC_GAS_DAMAGE + var/nitro_breath_dam_max = MAX_TOXIC_GAS_DAMAGE + var/nitro_damage_type = OXY + var/co2_breath_dam_min = MIN_TOXIC_GAS_DAMAGE + var/co2_breath_dam_max = MAX_TOXIC_GAS_DAMAGE + var/co2_damage_type = OXY + var/tox_breath_dam_min = MIN_TOXIC_GAS_DAMAGE + var/tox_breath_dam_max = MAX_TOXIC_GAS_DAMAGE + var/tox_damage_type = TOX + + var/cold_message = "your face freezing and an icicle forming" + var/cold_level_1_threshold = 260 + var/cold_level_2_threshold = 200 + var/cold_level_3_threshold = 120 + var/cold_level_1_damage = COLD_GAS_DAMAGE_LEVEL_1 //Keep in mind with gas damage levels, you can set these to be negative, if you want someone to heal, instead. + var/cold_level_2_damage = COLD_GAS_DAMAGE_LEVEL_2 + var/cold_level_3_damage = COLD_GAS_DAMAGE_LEVEL_3 + var/cold_damage_types = list(BURN = 1) + + var/hot_message = "your face burning and a searing heat" + var/heat_level_1_threshold = 360 + var/heat_level_2_threshold = 400 + var/heat_level_3_threshold = 1000 + var/heat_level_1_damage = HEAT_GAS_DAMAGE_LEVEL_1 + var/heat_level_2_damage = HEAT_GAS_DAMAGE_LEVEL_2 + var/heat_level_3_damage = HEAT_GAS_DAMAGE_LEVEL_3 + var/heat_damage_types = list(BURN = 1) + + +/** + * LUNG ATMOS CODE, VENTURE FURTHER IF YOU DARE!!! + */ + +/datum/organ/lungs/proc/check_breath(datum/gas_mixture/breath, mob/living/carbon/human/H) + if((H.status_flags & GODMODE)) + return + + if(HAS_TRAIT(H, TRAIT_NOBREATH)) + return + + if(!breath || (breath.total_moles() == 0)) + if(isspaceturf(H.loc)) + H.adjustOxyLoss(10) + else + H.adjustOxyLoss(5) + + if(safe_oxygen_min) + H.throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy) + else if(safe_toxins_min) + H.throw_alert("not_enough_tox", /obj/screen/alert/not_enough_tox) + else if(safe_co2_min) + H.throw_alert("not_enough_co2", /obj/screen/alert/not_enough_co2) + else if(safe_nitro_min) + H.throw_alert("not_enough_nitro", /obj/screen/alert/not_enough_nitro) + return FALSE + + + if(H.health < HEALTH_THRESHOLD_CRIT) + return FALSE + + var/gas_breathed = 0 + + //Partial pressures in our breath + var/O2_pp = breath.get_breath_partial_pressure(breath.oxygen) + var/N2_pp = breath.get_breath_partial_pressure(breath.nitrogen) + var/Toxins_pp = breath.get_breath_partial_pressure(breath.toxins) + var/CO2_pp = breath.get_breath_partial_pressure(breath.carbon_dioxide) + var/SA_pp = breath.get_breath_partial_pressure(breath.sleeping_agent) + + + //-- OXY --// + + //Too much oxygen! //Yes, some species may not like it. + if(safe_oxygen_max) + if(O2_pp > safe_oxygen_max) + var/ratio = (breath.oxygen / safe_oxygen_max / safe_oxygen_max) * 10 + H.apply_damage_type(clamp(ratio, oxy_breath_dam_min, oxy_breath_dam_max), oxy_damage_type) + H.throw_alert("too_much_oxy", /obj/screen/alert/too_much_oxy) + else + H.clear_alert("too_much_oxy") + + //Too little oxygen! + if(safe_oxygen_min) + if(O2_pp < safe_oxygen_min) + gas_breathed = handle_too_little_breath(H, O2_pp, safe_oxygen_min, breath.oxygen) + H.throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy) + else + H.adjustOxyLoss(-HUMAN_MAX_OXYLOSS) + gas_breathed = breath.oxygen + H.clear_alert("not_enough_oxy") + + //Exhale + breath.oxygen -= gas_breathed + breath.carbon_dioxide += gas_breathed + gas_breathed = 0 + + //-- Nitrogen --// + + //Too much nitrogen! + if(safe_nitro_max) + if(N2_pp > safe_nitro_max) + var/ratio = (breath.nitrogen / safe_nitro_max) * 10 + H.apply_damage_type(clamp(ratio, nitro_breath_dam_min, nitro_breath_dam_max), nitro_damage_type) + H.throw_alert("too_much_nitro", /obj/screen/alert/too_much_nitro) + else + H.clear_alert("too_much_nitro") + + //Too little nitrogen! + if(safe_nitro_min) + if(N2_pp < safe_nitro_min) + gas_breathed = handle_too_little_breath(H, N2_pp, safe_nitro_min, breath.nitrogen) + H.throw_alert("not_enough_nitro", /obj/screen/alert/not_enough_nitro) + else + H.adjustOxyLoss(-HUMAN_MAX_OXYLOSS) + gas_breathed = breath.nitrogen + H.clear_alert("not_enough_nitro") + + //Exhale + breath.nitrogen -= gas_breathed + breath.carbon_dioxide += gas_breathed + gas_breathed = 0 + + //-- CO2 --// + + //CO2 does not affect failed_last_breath. So if there was enough oxygen in the air but too much co2, this will hurt you, but only once per 4 ticks, instead of once per tick. + if(safe_co2_max) + if(CO2_pp > safe_co2_max) + if(!H.co2overloadtime) // If it's the first breath with too much CO2 in it, lets start a counter, then have them pass out after 12s or so. + H.co2overloadtime = world.time + else if(world.time - H.co2overloadtime > 120) + H.Paralyse(6 SECONDS) + H.apply_damage_type(HUMAN_MAX_OXYLOSS, co2_damage_type) // Lets hurt em a little, let them know we mean business + if(world.time - H.co2overloadtime > 300) // They've been in here 30s now, lets start to kill them for their own good! + H.apply_damage_type(15, co2_damage_type) + H.throw_alert("too_much_co2", /obj/screen/alert/too_much_co2) + if(prob(20)) // Lets give them some chance to know somethings not right though I guess. + H.emote("cough") + + else + H.co2overloadtime = 0 + H.clear_alert("too_much_co2") + + //Too little CO2! + if(safe_co2_min) + if(CO2_pp < safe_co2_min) + gas_breathed = handle_too_little_breath(H, CO2_pp, safe_co2_min, breath.carbon_dioxide) + H.throw_alert("not_enough_co2", /obj/screen/alert/not_enough_co2) + else + H.adjustOxyLoss(-HUMAN_MAX_OXYLOSS) + gas_breathed = breath.carbon_dioxide + H.clear_alert("not_enough_co2") + + //Exhale + breath.carbon_dioxide -= gas_breathed + breath.oxygen += gas_breathed + gas_breathed = 0 + + + //-- TOX --// + + //Too much toxins! + if(safe_toxins_max) + if(Toxins_pp > safe_toxins_max) + var/ratio = (breath.toxins / safe_toxins_max) * 10 + H.apply_damage_type(clamp(ratio, tox_breath_dam_min, tox_breath_dam_max), tox_damage_type) + H.throw_alert("too_much_tox", /obj/screen/alert/too_much_tox) + else + H.clear_alert("too_much_tox") + + + //Too little toxins! + if(safe_toxins_min) + if(Toxins_pp < safe_toxins_min) + gas_breathed = handle_too_little_breath(H, Toxins_pp, safe_toxins_min, breath.toxins) + H.throw_alert("not_enough_tox", /obj/screen/alert/not_enough_tox) + else + H.adjustOxyLoss(-HUMAN_MAX_OXYLOSS) + gas_breathed = breath.toxins + H.clear_alert("not_enough_tox") + + //Exhale + breath.toxins -= gas_breathed + breath.carbon_dioxide += gas_breathed + gas_breathed = 0 + + + //-- TRACES --// + + if(breath.sleeping_agent) // If there's some other shit in the air lets deal with it here. + if(SA_pp > SA_para_min) + H.Paralyse(6 SECONDS) // 6 seconds gives them one second to wake up and run away a bit! + if(SA_pp > SA_sleep_min) // Enough to make us sleep as well + H.AdjustSleeping(16 SECONDS, bound_lower = 0, bound_upper = 20 SECONDS) + else if(SA_pp > 0.01) // There is sleeping gas in their lungs, but only a little, so give them a bit of a warning + if(prob(20)) + H.emote(pick("giggle", "laugh")) + + handle_breath_temperature(breath, H) + + return TRUE + + +/datum/organ/lungs/proc/handle_too_little_breath(mob/living/carbon/human/H = null, breath_pp = 0, safe_breath_min = 0, true_pp = 0) + . = 0 + if(!H || !safe_breath_min) //the other args are either: Ok being 0 or Specifically handled. + return FALSE + + if(prob(20)) + H.emote("gasp") + if(breath_pp > 0) + var/ratio = safe_breath_min/breath_pp + H.adjustOxyLoss(min(5*ratio, HUMAN_MAX_OXYLOSS)) // Don't fuck them up too fast (space only does HUMAN_MAX_OXYLOSS after all! + . = true_pp*ratio/6 + else + H.adjustOxyLoss(HUMAN_MAX_OXYLOSS) + + +/datum/organ/lungs/proc/handle_breath_temperature(datum/gas_mixture/breath, mob/living/carbon/human/H) // called by human/life, handles temperatures + var/breath_temperature = breath.temperature + + if(!HAS_TRAIT(H, TRAIT_RESISTCOLD)) // COLD DAMAGE + var/CM = abs(H.dna.species.coldmod) + var/TC = 0 + if(breath_temperature < cold_level_3_threshold) + TC = cold_level_3_damage + if(breath_temperature > cold_level_3_threshold && breath_temperature < cold_level_2_threshold) + TC = cold_level_2_damage + if(breath_temperature > cold_level_2_threshold && breath_temperature < cold_level_1_threshold) + TC = cold_level_1_damage + if(TC) + for(var/D in cold_damage_types) + H.apply_damage_type(TC * CM * cold_damage_types[D], D) + if(breath_temperature < cold_level_1_threshold) + if(prob(20)) + to_chat(H, "You feel [cold_message] in your [linked_organ.name]!") + + if(!HAS_TRAIT(H, TRAIT_RESISTHEAT)) // HEAT DAMAGE + var/HM = abs(H.dna.species.heatmod) + var/TH = 0 + if(breath_temperature > heat_level_1_threshold && breath_temperature < heat_level_2_threshold) + TH = heat_level_1_damage + if(breath_temperature > heat_level_2_threshold && breath_temperature < heat_level_3_threshold) + TH = heat_level_2_damage + if(breath_temperature > heat_level_3_threshold) + TH = heat_level_3_damage + if(TH) + for(var/D in heat_damage_types) + H.apply_damage_type(TH * HM * heat_damage_types[D], D) + if(breath_temperature > heat_level_1_threshold) + if(prob(20)) + to_chat(H, "You feel [hot_message] in your [linked_organ.name]!") + + +/** + * Lung atmos code ends here. Thank god... + */ + +/datum/organ/lungs/on_successful_emp() + linked_organ.owner?.LoseBreath(40 SECONDS) + +/datum/organ/lungs/on_insert(mob/living/carbon/given_to) + clear_alerts(given_to) + +/datum/organ/lungs/on_replace(mob/living/carbon/human/organ_owner) + clear_alerts(organ_owner) + +/datum/organ/lungs/on_remove(mob/living/carbon/removed_from, special = FALSE) + clear_alerts(removed_from) + +/datum/organ/lungs/proc/clear_alerts(mob/living/carbon/alert_owner) + for(var/thing in list("oxy", "tox", "co2", "nitro")) + alert_owner.clear_alert("not_enough_[thing]") + alert_owner.clear_alert("too_much_[thing]") + +/datum/organ/lungs/on_life() + if(linked_organ.germ_level > INFECTION_LEVEL_ONE) + if(prob(5)) + linked_organ.owner.emote("cough") //respitory tract infection + + if(linked_organ.is_bruised()) + if(prob(2) && !(NO_BLOOD in linked_organ.owner.dna.species.species_traits)) + linked_organ.owner.custom_emote(EMOTE_VISIBLE, "coughs up blood!") + linked_organ.owner.bleed(1) + if(prob(4)) + linked_organ.owner.custom_emote(EMOTE_VISIBLE, "gasps for air!") + linked_organ.owner.AdjustLoseBreath(10 SECONDS) + + +/datum/organ/lungs/on_prepare_eat(obj/item/food/snacks/organ/snorgan) + snorgan.reagents.add_reagent("salbutamol", 5) + + +/datum/organ/lungs/vox + safe_oxygen_min = 0 //We don't breathe this + safe_oxygen_max = 0.05 //This is toxic to us + safe_nitro_min = 16 //We breathe THIS! + oxy_damage_type = TOX //And it poisons us + +/datum/organ/lungs/plasmamen + safe_oxygen_min = 0 //We don't breath this + safe_toxins_min = 16 //We breathe THIS! + safe_toxins_max = 0 + +/datum/organ/lungs/drask + cold_message = "an invigorating coldness" + cold_level_3_threshold = 60 + cold_level_1_damage = -COLD_GAS_DAMAGE_LEVEL_1 //They heal when the air is cold + cold_level_2_damage = -COLD_GAS_DAMAGE_LEVEL_2 + cold_level_3_damage = -COLD_GAS_DAMAGE_LEVEL_3 + cold_damage_types = list(BRUTE = 0.5, BURN = 0.25) + +/datum/organ/lungs/ashwalker + safe_oxygen_min = 4 // 4x as efficient as regular Unathi, can comfortably breathe on lavaland + +/datum/organ/lungs/advanced_cyber/New(obj/item/organ/internal/link_em) + . = ..() + make_advanced() + +/datum/organ/lungs/proc/make_advanced() + safe_toxins_max = 20 + safe_co2_max = 20 + + cold_level_1_threshold = 200 + cold_level_2_threshold = 140 + cold_level_3_threshold = 100 diff --git a/code/modules/surgery/organs/organ_datums/organ_datum.dm b/code/modules/surgery/organs/organ_datums/organ_datum.dm new file mode 100644 index 000000000000..7872b984af11 --- /dev/null +++ b/code/modules/surgery/organs/organ_datums/organ_datum.dm @@ -0,0 +1,36 @@ +/datum/organ + var/organ_tag // heart, brain, lungs, etc + var/obj/item/organ/internal/linked_organ + +/datum/organ/New(obj/item/organ/internal/link_em) + ..() + linked_organ = link_em + +/datum/organ/Destroy(force, ...) + linked_organ = null + return ..() + +/// Called when the linked organ is inserted. +/datum/organ/proc/on_insert(mob/living/carbon/human/given_to) + return + +/// Called when another organ is removed, and this organ datum takes its place in the organ_owner. +/datum/organ/proc/on_replace(mob/living/carbon/human/organ_owner) + return + +/// Called when the linked organ is removed. +/datum/organ/proc/on_remove(mob/living/carbon/removed_from, special = FALSE) + return + +/datum/organ/proc/on_life() + return + +/// Only called when the organ is robotic AND is not emp proof. Return true to override default functions +/datum/organ/proc/on_successful_emp() + return FALSE + +/datum/organ/proc/on_necrotize() + return FALSE + +/datum/organ/proc/on_prepare_eat(obj/item/food/snacks/organ/snorgan) + return FALSE diff --git a/code/modules/surgery/organs/organ_helpers.dm b/code/modules/surgery/organs/organ_helpers.dm index a7fec193dcdc..6eaa4154e297 100644 --- a/code/modules/surgery/organs/organ_helpers.dm +++ b/code/modules/surgery/organs/organ_helpers.dm @@ -16,6 +16,10 @@ /mob/living/carbon/get_int_organ(typepath) return (locate(typepath) in internal_organs) +/mob/living/carbon/proc/get_int_organ_datum(tag_to_check) + RETURN_TYPE(/datum/organ) + return internal_organ_datums[tag_to_check] + /mob/living/carbon/get_organs_zone(zone, subzones = 0) var/list/returnorg = list() diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index 2f3413a5157a..12143a6b53ca 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -7,12 +7,34 @@ // DO NOT add slots with matching names to different zones - it will break internal_organs_slot list! var/non_primary = 0 var/unremovable = FALSE //Whether it shows up as an option to remove during surgery. + /// An associated list of organ datums that this organ has. + var/list/datum/organ/organ_datums /obj/item/organ/internal/New(mob/living/carbon/holder) ..() if(istype(holder)) insert(holder) +/obj/item/organ/internal/Initialize(mapload) + . = ..() + if(!organ_datums) + return + var/list/temp_list = organ_datums.Copy() + organ_datums = list() + for(var/path in temp_list) + var/datum/organ/organ_datum = new path(src) + if(!organ_datum.organ_tag) + stack_trace("There was an organ datum [organ_datum] ([organ_datum.type]), that had no organ tag.") + continue + organ_datums[organ_datum.organ_tag] = organ_datum + +/obj/item/organ/internal/Destroy() + if(owner) // we have to remove BEFORE organ_datums are qdel'd, or we can just live even if our heart organ got deleted + remove(owner, TRUE) + QDEL_LIST_ASSOC_VAL(organ_datums) // The removal from internal_organ_datums should be handled when the organ is removed + . = ..() + + /obj/item/organ/internal/proc/insert(mob/living/carbon/M, special = 0, dont_remove_slot = 0) if(!iscarbon(M) || owner == M) return @@ -28,6 +50,12 @@ M.internal_organs |= src M.internal_organs_slot[slot] = src + + for(var/organ_tag in organ_datums) + var/datum/organ/new_organ = organ_datums[organ_tag] + M.internal_organ_datums[new_organ.organ_tag] = new_organ + new_organ.on_insert(M) + var/obj/item/organ/external/parent if(ishuman(M)) var/mob/living/carbon/human/H = M @@ -56,6 +84,23 @@ M.internal_organs -= src if(M.internal_organs_slot[slot] == src) M.internal_organs_slot.Remove(slot) + + + for(var/removal_tag in organ_datums) + if(M.internal_organ_datums[removal_tag] == organ_datums[removal_tag]) + M.internal_organ_datums -= removal_tag + var/datum/organ/removed = organ_datums[removal_tag] + removed.on_remove(M) + + // Lets see if we have any backup organ datums from other internal organs. + for(var/obj/item/organ/internal/backup_organ in M.internal_organs) + for(var/replacement_tag in backup_organ.organ_datums) + if(M.internal_organ_datums[replacement_tag]) // some other organ is already covering it + continue + var/datum/organ/replacement_organ = backup_organ.organ_datums[replacement_tag] + M.internal_organ_datums[replacement_organ.organ_tag] = replacement_organ + replacement_organ.on_replace(M) + if(vital && !special) if(M.stat != DEAD)//safety check! M.death() @@ -90,6 +135,12 @@ /obj/item/organ/internal/replaced(mob/living/carbon/human/target) insert(target) +/obj/item/organ/internal/necrotize(update_sprite) + for(var/organ_tag in organ_datums) // let the organ datums handle first + var/datum/organ/dead_organ = organ_datums[organ_tag] + dead_organ.on_necrotize() + return ..() + /obj/item/organ/internal/item_action_slot_check(slot, mob/user) return @@ -114,6 +165,10 @@ S.origin_tech = origin_tech S.w_class = w_class + for(var/organ_tag in organ_datums) + var/datum/organ/delicious = organ_datums[organ_tag] + delicious.on_prepare_eat(S) + return S /obj/item/organ/internal/attempt_become_organ(obj/item/organ/external/parent,mob/living/carbon/human/H) @@ -160,7 +215,7 @@ if(slot == "heart" && ("[slot]-c-on" in states) && ("[slot]-c-off" in states)) //Give the robotic heart its robotic heart icons if they exist. var/obj/item/organ/internal/heart/H = src H.icon = icon('icons/obj/surgery.dmi') - H.icon_base = "[slot]-c" + H.base_icon_state = "[slot]-c" H.dead_icon = "[slot]-c-off" H.update_icon() else if("[slot]-c" in states) //Give the robotic organ its robotic organ icons if they exist. @@ -318,6 +373,17 @@ /obj/item/organ/internal/emp_act(severity) if(!is_robotic() || emp_proof) return + + var/we_done = FALSE + for(var/organ_tag in organ_datums) + var/datum/organ/borgan = organ_datums[organ_tag] + if(borgan.on_successful_emp()) + we_done = TRUE + + if(we_done) + return + + // No EMP handling was done, lets just give em damage switch(severity) if(1) receive_damage(20, 1) diff --git a/code/modules/surgery/organs/subtypes/slime_organs.dm b/code/modules/surgery/organs/subtypes/slime_organs.dm deleted file mode 100644 index d5f1cb8aef50..000000000000 --- a/code/modules/surgery/organs/subtypes/slime_organs.dm +++ /dev/null @@ -1,15 +0,0 @@ -/obj/item/organ/internal/heart/slime - icon = 'icons/obj/species_organs/slime.dmi' - name = "slime heart" - icon_state = "heart" - desc = "This is a slime's osmotic pressure regulator, it appears to be some kind of biological pump that uses osmotic pressure to regulate water flow. It seems to work similar to a heart." - dead_icon = null - -/obj/item/organ/internal/heart/slime/update_icon_state() - return - -/obj/item/organ/internal/lungs/slime - icon = 'icons/obj/species_organs/slime.dmi' - name = "slime lungs" - icon_state = "lungs" - desc = "This is a slime's gas exchange membrane, this membrane used for oxygen intake and gas exchange. These seem to work similar to lungs." diff --git a/code/modules/surgery/organs/subtypes/unathi_organs.dm b/code/modules/surgery/organs/subtypes/unathi_organs.dm index f31935f49946..13857d77ab23 100644 --- a/code/modules/surgery/organs/subtypes/unathi_organs.dm +++ b/code/modules/surgery/organs/subtypes/unathi_organs.dm @@ -30,4 +30,4 @@ icon = 'icons/obj/species_organs/unathi.dmi' /obj/item/organ/internal/lungs/unathi/ash_walker - safe_oxygen_min = 4 // 4x as efficient as regular Unathi, can comfortably breathe on lavaland + organ_datums = list(/datum/organ/lungs/ashwalker) diff --git a/icons/obj/species_organs/slime.dmi b/icons/obj/species_organs/slime.dmi index 58ec636ca7ec..dab38fcd51f3 100644 Binary files a/icons/obj/species_organs/slime.dmi and b/icons/obj/species_organs/slime.dmi differ diff --git a/paradise.dme b/paradise.dme index c1cd5e22e75e..607b980ce6c6 100644 --- a/paradise.dme +++ b/paradise.dme @@ -2741,6 +2741,9 @@ #include "code\modules\surgery\organs\robolimbs.dm" #include "code\modules\surgery\organs\skeleton_organs.dm" #include "code\modules\surgery\organs\vocal_cords.dm" +#include "code\modules\surgery\organs\organ_datums\heart_datum.dm" +#include "code\modules\surgery\organs\organ_datums\lung_datum.dm" +#include "code\modules\surgery\organs\organ_datums\organ_datum.dm" #include "code\modules\surgery\organs\subtypes\abductor_organs.dm" #include "code\modules\surgery\organs\subtypes\diona_organs.dm" #include "code\modules\surgery\organs\subtypes\drask_organs.dm" @@ -2750,7 +2753,6 @@ #include "code\modules\surgery\organs\subtypes\moth_organs.dm" #include "code\modules\surgery\organs\subtypes\plasmaman_organs.dm" #include "code\modules\surgery\organs\subtypes\skrell_organs.dm" -#include "code\modules\surgery\organs\subtypes\slime_organs.dm" #include "code\modules\surgery\organs\subtypes\standard_organs.dm" #include "code\modules\surgery\organs\subtypes\tajaran_organs.dm" #include "code\modules\surgery\organs\subtypes\unathi_organs.dm"