mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-20 03:25:49 +01:00
Revives Organ Datumization (#23397)
* first runthrough lol * okay make this shit actually work * nerfs slime people * fixes * more changes * fix * bim bim bam bam * ok back in the head becuz i dont give a shit * Sirryan review * Sirryan review * Fixes CI * Stealthy CI fail --------- Co-authored-by: Contrabang <91113370+Contrabang@users.noreply.github.com>
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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("<span class='boldnotice'>[defib_ref] buzzes: Resuscitation failed - Failed to pick up any heart electrical activity.</span>")
|
||||
else if(heart.status & ORGAN_DEAD)
|
||||
else if(heart.linked_organ.status & ORGAN_DEAD)
|
||||
user.visible_message("<span class='boldnotice'>[defib_ref] buzzes: Resuscitation failed - Heart necrosis detected.</span>")
|
||||
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("<span class='danger'>[affecting]'s entire body shakes as a shock travels up [affecting.p_their()] arm!</span>", \
|
||||
"<span class='userdanger'>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")]!</span>")
|
||||
affecting.set_heartattack(TRUE)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(..())
|
||||
|
||||
@@ -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(!..())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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("<span class='warning'>[user] raises [src] to [user.p_their()] mouth and tears into it with [user.p_their()] teeth!</span>", \
|
||||
"<span class='danger'>An unnatural hunger consumes you. You raise [src] to your mouth and devour it!</span>")
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
/obj/item/painter/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] is inhaling toner from [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
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
|
||||
|
||||
@@ -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 += "<span class='notice'><font color='red'><b>The patient's heart has stopped.</b>\nPossible Cure: Electric Shock</font></span>"
|
||||
msgs += "<span class='notice'><font color='red'><b>The patient's heart has stopped.</b>\nPossible Cure: Electric Shock</font>"
|
||||
else if(heart && (heart.status & ORGAN_DEAD))
|
||||
msgs += "<span class='notice'><font color='red'><b>Subject's heart is necrotic.</b></font></span>"
|
||||
msgs += "<span class='notice'><font color='red'><b>Subject's heart is necrotic.</b></font>"
|
||||
else if(!heart)
|
||||
msgs += "<span class='notice'><font color='red'><b>Subject has no heart.</b></font></span>"
|
||||
msgs += "<span class='notice'><font color='red'><b>Subject has no heart.</b></font>"
|
||||
|
||||
if(H.getStaminaLoss())
|
||||
msgs += "<span class='info'>Subject appears to be suffering from fatigue.</span>"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
if(dna.species)
|
||||
var/datum/species/S = dna.species
|
||||
// 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(S.breathid == "o2")
|
||||
if(dna.species)
|
||||
var/datum/species/S = dna.species
|
||||
|
||||
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"))
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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, "<span class='notice'>You feel resistant to airborne toxins.</span>")
|
||||
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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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, "<span class='warning'>You can't restart a dead heart.</span>")
|
||||
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, "<span class='warning'>Your [name] detects a cardiac event and attempts to return to its normal rhythm!</span>")
|
||||
if(prob(20) && emagged)
|
||||
attempted_restart = TRUE
|
||||
Restart()
|
||||
addtimer(CALLBACK(src, PROC_REF(message_to_owner), owner, "<span class='warning'>Your [name] returns to its normal rhythm!</span>"), 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, "<span class='warning'>Your [name] returns to its normal rhythm!</span>"), 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, "<span class='warning'>Your [name] returns to its normal rhythm!</span>"), 30)
|
||||
addtimer(CALLBACK(src, PROC_REF(recharge)), 300)
|
||||
heart_datum.change_beating(TRUE)
|
||||
addtimer(CALLBACK(src, PROC_REF(message_to_owner), owner, "<span class='warning'>Your [name] returns to its normal rhythm!</span>"), 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, "<span class='warning'>Your [name] fails to return to its normal rhythm!</span>"), 30)
|
||||
addtimer(CALLBACK(src, PROC_REF(recharge)), 30 SECONDS)
|
||||
addtimer(CALLBACK(src, PROC_REF(message_to_owner), owner, "<span class='warning'>Your [name] fails to return to its normal rhythm!</span>"), 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, "<span class='warning'>Your [name] detects a cardiac event and attempts to return to its normal rhythm!</span>")
|
||||
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, "<span class='warning'>Your [name] fails to return to its normal rhythm!</span>"), 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, "<span class='danger'>Your [name] stops beating!</span>")
|
||||
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, "<span class='danger'>Your [name] shuts down!</span>")
|
||||
necrotize()
|
||||
|
||||
@@ -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, "<span class='warning'>You feel [cold_message] in your [name]!</span>")
|
||||
|
||||
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, "<span class='warning'>You feel [hot_message] in your [name]!</span>")
|
||||
|
||||
/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, "<span class='notice'>You configure [src] to replace vox lungs.</span>")
|
||||
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, "<span class='notice'>You configure [src] to replace plasmamen lungs.</span>")
|
||||
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, "<span class='notice'>You configure [src] back to default settings.</span>")
|
||||
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, "<span class='notice'>You configure [src] to [chosen] settings.</span>")
|
||||
|
||||
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()
|
||||
|
||||
@@ -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
|
||||
@@ -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, "<span class='warning'>You feel [cold_message] in your [linked_organ.name]!</span>")
|
||||
|
||||
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, "<span class='warning'>You feel [hot_message] in your [linked_organ.name]!</span>")
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -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
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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."
|
||||
@@ -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)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
+3
-1
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user