tg Code complete, now to bugtest and clear compile errors.

This commit is contained in:
Fermi
2019-09-18 23:57:21 +01:00
parent c23d6f0113
commit dfa40a4b22
25 changed files with 427 additions and 110 deletions

View File

@@ -203,8 +203,6 @@
#define MAX_CHICKENS 50
#define UNHEALING_EAR_DAMAGE 100
#define INCORPOREAL_MOVE_BASIC 1
#define INCORPOREAL_MOVE_SHADOW 2 // leaves a trail of shadows

View File

@@ -26,5 +26,5 @@
if(!HAS_TRAIT(wearer, TRAIT_DEAF))
var/obj/item/organ/ears/ears = wearer.getorganslot(ORGAN_SLOT_EARS)
if (ears)
ears.deaf = max(ears.deaf - 1, (ears.ear_damage < UNHEALING_EAR_DAMAGE ? 0 : 1)) // Do not clear deafness while above the unhealing ear damage threshold
ears.ear_damage = max(ears.ear_damage - 0.1, 0)
ears.deaf = max(ears.deaf - 1, (ears.damage < ears.maxHealth ? 0 : 1)) // Do not clear deafness if our ears are too damaged
ears.damage = max(ears.damage - 0.1, 0)

View File

@@ -50,9 +50,9 @@ Bonus
if(5)
if(power > 2)
var/obj/item/organ/ears/ears = M.getorganslot(ORGAN_SLOT_EARS)
if(istype(ears) && ears.ear_damage < UNHEALING_EAR_DAMAGE)
if(istype(ears) && ears.damage < ears.maxHealth)
to_chat(M, "<span class='userdanger'>Your ears pop painfully and start bleeding!</span>")
ears.ear_damage = max(ears.ear_damage, UNHEALING_EAR_DAMAGE)
ears.damage = max(ears.damage, ears.maxHealth)
M.emote("scream")
else
to_chat(M, "<span class='userdanger'>Your ears pop and begin ringing loudly!</span>")

View File

@@ -100,8 +100,8 @@
else if(M.eye_blind || M.eye_blurry)
M.set_blindness(0)
M.set_blurriness(0)
else if(eyes.eye_damage > 0)
M.adjust_eye_damage(-1)
else if(eyes.damage > 0)
eyes.applyOrganDamage(-1)
else
if(prob(base_message_chance))
to_chat(M, "<span class='notice'>[pick("Your eyes feel great.","You feel like your eyes can focus more clearly.", "You don't feel the need to blink.","Your ears feel great.","Your healing feels more acute.")]</span>")
to_chat(M, "<span class='notice'>[pick("Your eyes feel great.","You feel like your eyes can focus more clearly.", "You don't feel the need to blink.","Your ears feel great.","Your healing feels more acute.")]</span>")

View File

@@ -53,20 +53,20 @@ Bonus
if(3, 4)
to_chat(M, "<span class='warning'><b>Your eyes burn!</b></span>")
M.blur_eyes(10)
M.adjust_eye_damage(1)
eyes.applyOrganDamage(1)
else
M.blur_eyes(20)
M.adjust_eye_damage(5)
if(eyes.eye_damage >= 10)
eyes.applyOrganDamage(5)
if(eyes.damage >= 10)
M.become_nearsighted(EYE_DAMAGE)
if(prob(eyes.eye_damage - 10 + 1))
if(prob(eyes.damage - 10 + 1))
if(!remove_eyes)
if(!HAS_TRAIT(M, TRAIT_BLIND))
to_chat(M, "<span class='userdanger'>You go blind!</span>")
M.become_blind(EYE_DAMAGE)
eyes.applyOrganDamage(eyes.maxHealth)
else
M.visible_message("<span class='warning'>[M]'s eyes fall off their sockets!</span>", "<span class='userdanger'>Your eyes fall off their sockets!</span>")
eyes.Remove(M)
eyes.forceMove(get_turf(M))
else
to_chat(M, "<span class='userdanger'>Your eyes burn horrifically!</span>")
to_chat(M, "<span class='userdanger'>Your eyes burn horrifically!</span>")

View File

@@ -514,12 +514,12 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
log_combat(user, M, "attacked", "[src.name]", "(INTENT: [uppertext(user.a_intent)])")
M.adjust_blurriness(3)
M.adjust_eye_damage(rand(2,4))
var/obj/item/organ/eyes/eyes = M.getorganslot(ORGAN_SLOT_EYES)
if (!eyes)
return
if(eyes.eye_damage >= 10)
M.adjust_blurriness(3)
eyes.applyOrganDamage(rand(2,4))
if(eyes.damage >= 10)
M.adjust_blurriness(15)
if(M.stat != DEAD)
to_chat(M, "<span class='danger'>Your eyes start to bleed profusely!</span>")
@@ -533,7 +533,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
M.adjust_blurriness(10)
M.Unconscious(20)
M.Knockdown(40)
if (prob(eyes.eye_damage - 10 + 1))
if (prob(eyes.damage - 10 + 1))
M.become_blind(EYE_DAMAGE)
to_chat(M, "<span class='danger'>You go blind!</span>")

View File

@@ -17,26 +17,27 @@
/obj/item/organ/body_egg/Insert(var/mob/living/carbon/M, special = 0)
..()
ADD_TRAIT(owner, TRAIT_XENO_HOST, TRAIT_GENERIC)
START_PROCESSING(SSobj, src)
owner.med_hud_set_status()
INVOKE_ASYNC(src, .proc/AddInfectionImages, owner)
/obj/item/organ/body_egg/Remove(var/mob/living/carbon/M, special = 0)
STOP_PROCESSING(SSobj, src)
if(owner)
REMOVE_TRAIT(owner, TRAIT_XENO_HOST, TRAIT_GENERIC)
owner.med_hud_set_status()
INVOKE_ASYNC(src, .proc/RemoveInfectionImages, owner)
..()
/obj/item/organ/body_egg/process()
/obj/item/organ/body_egg/on_death()
. = ..()
if(!owner)
return
if(!(src in owner.internal_organs))
Remove(owner)
return
egg_process()
/obj/item/organ/body_egg/on_life()
. = ..()
egg_process()
/obj/item/organ/body_egg/proc/egg_process()
return

View File

@@ -397,39 +397,28 @@
return FALSE
/obj/machinery/smartfridge/organ/load(obj/item/O)
if(..()) //if the item loads, clear can_decompose
var/obj/item/organ/organ = O
organ.organ_flags |= ORGAN_FROZEN
/obj/machinery/smartfridge/organ/dispense(obj/item/O, var/mob/M)
. = ..()
if(!.) //if the item loads, clear can_decompose
return
var/obj/item/organ/organ = O
organ.organ_flags &= ~ORGAN_FROZEN
..()
organ.organ_flags |= ORGAN_FROZEN
/obj/machinery/smartfridge/organ/RefreshParts()
for(var/obj/item/stock_parts/matter_bin/B in component_parts)
max_n_of_items = 20 * B.rating
repair_rate = max(0, STANDARD_ORGAN_HEALING * (B.rating - 1))
/obj/machinery/smartfridge/organ/Destroy()
for(var/organ in src)
var/obj/item/organ/O = organ
if(O)
O.organ_flags &= ~ORGAN_FROZEN
..()
/obj/machinery/smartfridge/organ/process()
for(var/organ in src)
for(var/organ in contents)
var/obj/item/organ/O = organ
if(O)
O.damage = max(0, O.damage - repair_rate)
if(!istype(O))
return
O.applyOrganDamage(-repair_rate)
/obj/machinery/smartfridge/organ/deconstruct()
for(var/organ in src)
var/obj/item/organ/O = organ
if(O)
O.organ_flags &= ~ORGAN_FROZEN
..()
/obj/machinery/smartfridge/organ/Exited(obj/item/organ/AM, atom/newLoc)
. = ..()
if(istype(AM))
AM.organ_flags &= ~ORGAN_FROZEN
// -----------------------------
// Chemistry Medical Smartfridge

View File

@@ -64,6 +64,7 @@
brainmob.reset_perspective()
brain = newbrain
brain.organ_flags |= ORGAN_FROZEN
name = "Man-Machine Interface: [brainmob.real_name]"
update_icon()
@@ -100,6 +101,7 @@
user.put_in_hands(brain) //puts brain in the user's hand or otherwise drops it on the user's turf
else
brain.forceMove(get_turf(src))
brain.organ_flags &= ~ORGAN_FROZEN
brain = null //No more brain in here

View File

@@ -22,6 +22,7 @@
return S
/obj/item/organ/body_egg/alien_embryo/on_life()
. = ..()
switch(stage)
if(2, 3)
if(prob(2))

View File

@@ -120,7 +120,10 @@
/mob/living/carbon/adjustOrganLoss(slot, amount, maximum)
var/obj/item/organ/O = getorganslot(slot)
if(O && !(status_flags & GODMODE))
if(!maximum)
maximum = O.maxHealth
O.applyOrganDamage(amount, maximum)
O.onDamage(amount, maximum)
/** setOrganLoss
* inputs: slot (organ slot, like ORGAN_SLOT_HEART), amount(damage to be set to)
@@ -132,6 +135,7 @@
var/obj/item/organ/O = getorganslot(slot)
if(O && !(status_flags & GODMODE))
O.setOrganDamage(amount)
O.onSetDamage(amount)
/** getOrganLoss
* inputs: slot (organ slot, like ORGAN_SLOT_HEART)
@@ -143,6 +147,15 @@
if(O)
return O.damage
/mob/living/carbon/adjustAllOrganLoss(amount, maximum)
for(var/o in internal_organs)
if(O && !(status_flags & GODMODE))
continue
if(!maximum)
maximum = O.maxHealth
O.applyOrganDamage(amount, maximum)
O.onDamage(amount, maximum)
////////////////////////////////////////////

View File

@@ -123,10 +123,8 @@
if(special != HEART_SPECIAL_SHADOWIFY)
blade = new/obj/item/light_eater
M.put_in_hands(blade)
START_PROCESSING(SSobj, src)
/obj/item/organ/heart/nightmare/Remove(mob/living/carbon/M, special = 0)
STOP_PROCESSING(SSobj, src)
respawn_progress = 0
if(blade && special != HEART_SPECIAL_SHADOWIFY)
QDEL_NULL(blade)
@@ -139,9 +137,8 @@
/obj/item/organ/heart/nightmare/update_icon()
return //always beating visually
/obj/item/organ/heart/nightmare/process()
if(QDELETED(owner) || owner.stat != DEAD)
respawn_progress = 0
/obj/item/organ/heart/nightmare/on_death()
if(!owner)
return
var/turf/T = get_turf(owner)
if(istype(T))

View File

@@ -8,8 +8,8 @@
damageoverlaytemp = 0
update_damage_hud()
if(stat != DEAD) //Reagent processing needs to come before breathing, to prevent edge cases.
handle_organs()
//Reagent processing needs to come before breathing, to prevent edge cases.
handle_organs()
. = ..()
@@ -384,9 +384,14 @@
. |= BP.on_life()
/mob/living/carbon/proc/handle_organs()
for(var/V in internal_organs)
var/obj/item/organ/O = V
O.on_life()
if(stat != DEAD)
for(var/V in internal_organs)
var/obj/item/organ/O = V
O.on_life()
else
for(var/V in internal_organs)
var/obj/item/organ/O = V
O.on_death() //Needed so organs decay while inside the body.
/mob/living/carbon/handle_diseases()
for(var/thing in diseases)

View File

@@ -0,0 +1,62 @@
//Organ reconstruction, limited to the chest region as most organs in the head have their own repair method (eyes/brain). We require synthflesh for these
//steps since fixing internal organs aren't as simple as mending exterior flesh, though in the future it would be neat to add more chems to the viable list.
//TBD: Add heart damage, have heart reconstruction seperate from organ reconstruction, and find a better name for this. I can imagine people getting it confused with manipulation.
/datum/surgery/graft_synthtissue
name = "Graft_synthtissue"
target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
possible_locs = list(BODY_ZONE_CHEST)
steps = list(
/datum/surgery_step/incise,
/datum/surgery_step/retract_skin,
/datum/surgery_step/saw,
/datum/surgery_step/clamp_bleeders,
/datum/surgery_step/incise,
/datum/surgery_step/graft_synthtissue,
/datum/surgery_step/close
)
//repair lungs step
/datum/surgery_step/repair_synthtissue
name = "graft synthtissue"
implements = list(/obj/item/hemostat = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15)
repeatable = TRUE
time = 25
chems_needed = list("synthtissue")
var/obj/item/organ/chosen_organ
//Repair lungs
/datum/surgery_step/repair_synthtissue/preop(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(implement_type in implements_extract)
current_type = "insert"
var/list/organs = target.getorganszone(target_zone)
if(!organs.len)
to_chat(user, "<span class='notice'>There are no targetable organs in [target]'s [parse_zone(target_zone)]!</span>")
return -1
else
for(var/obj/item/organ/O in organs)
O.on_find(user)
organs -= O
organs[O.name] = O
chosen_organ = input("Remove which organ?", "Surgery", null, null) as null|anything in organs
if(chosen_organ.organ_flags & ORGAN_FAILING))
to_chat(user, "<span class='notice'>[target]'s [chosen_organ] is too damaged to repair graft onto!</span>")
return -1
user.visible_message("[user] begins to repair damaged portions of [target]'s [chosen_organ].</span>")
/datum/surgery_step/repair_synthtissue/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if((!chosen_organ)||(chosen_organ.organ_flags & ORGAN_FAILING))
to_chat(user, "[target] has no [chosen_organ] capable of repair!")
else
user.visible_message("[user] successfully repairs part of [target]'s [chosen_organ].", "<span class='notice'>You succeed in repairing parts of [target]'s [chosen_organ].</span>")
chosen_organ.applyOrganDamage(-10)
/datum/surgery_step/repair_synthtissue/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if((!chosen_organ)||(chosen_organ.organ_flags & ORGAN_FAILING))
to_chat(user, "[target] has no [chosen_organ] capable of repair!")
else
user.visible_message("<span class='warning'>[user] accidentally damages part of [target]'s [chosen_organ]!</span>", "<span class='warning'>You damage [target]'s [chosen_organ]! Apply more synthtissue if it's run out.</span>")
chosen_organ.applyOrganDamage(10)
return FALSE

View File

@@ -31,17 +31,26 @@
/obj/item/organ/ears/on_life()
if(!iscarbon(owner))
return
..()
var/mob/living/carbon/C = owner
if((damage < maxHealth) && (organ_flags & ORGAN_FAILING)) //ear damage can be repaired from the failing condition
organ_flags &= ~ORGAN_FAILING
// genetic deafness prevents the body from using the ears, even if healthy
if(HAS_TRAIT(C, TRAIT_DEAF))
deaf = max(deaf, 1)
else if(ear_damage < UNHEALING_EAR_DAMAGE) // if higher than UNHEALING_EAR_DAMAGE, no natural healing occurs.
ear_damage = max(ear_damage - 0.05, 0)
else if(!(organ_flags & ORGAN_FAILING)) // if this organ is failing, do not clear deaf stacks.
deaf = max(deaf - 1, 0)
if(prob(damage / 20) && (damage > low_threshold))
adjustEarDamage(0, 4)
SEND_SOUND(C, sound('sound/weapons/flash_ring.ogg'))
to_chat(C, "<span class='warning'>The ringing in your ears grows louder, blocking out any external noises for a moment.</span>")
else if((organ_flags & ORGAN_FAILING) && (deaf == 0))
deaf = 1 //stop being not deaf you deaf idiot
/obj/item/organ/ears/proc/restoreEars()
deaf = 0
ear_damage = 0
organ_flags &= ~ORGAN_FAILING
var/mob/living/carbon/C = owner

View File

@@ -6,6 +6,19 @@
slot = ORGAN_SLOT_EYES
gender = PLURAL
healing_factor = STANDARD_ORGAN_HEALING
decay_factor = STANDARD_ORGAN_DECAY
maxHealth = 0.5 * STANDARD_ORGAN_THRESHOLD //half the normal health max since we go blind at 30, a permanent blindness at 50 therefore makes sense unless medicine is administered
high_threshold = 0.3 * STANDARD_ORGAN_THRESHOLD //threshold at 30
low_threshold = 0.2 * STANDARD_ORGAN_THRESHOLD //threshold at 20
low_threshold_passed = "<span class='info'>Distant objects become somewhat less tangible.</span>"
high_threshold_passed = "<span class='info'>Everything starts to look a lot less clear.</span>"
now_failing = "<span class='warning'>Darkness envelopes you, as your eyes go blind!</span>"
now_fixed = "<span class='info'>Color and shapes are once again perceivable.</span>"
high_threshold_cleared = "<span class='info'>Your vision functions passably once more.</span>"
low_threshold_cleared = "<span class='info'>Your vision is cleared of any ailment.</span>"
var/sight_flags = 0
var/see_in_dark = 2
var/eye_damage = 0
@@ -15,6 +28,7 @@
var/flash_protect = 0
var/see_invisible = SEE_INVISIBLE_LIVING
var/lighting_alpha
var/damaged = FALSE //damaged indicates that our eyes are undergoing some level of negative effect
/obj/item/organ/eyes/Insert(mob/living/carbon/M, special = FALSE, drop_if_replaced = FALSE)
..()
@@ -41,6 +55,29 @@
M.update_tint()
M.update_sight()
/obj/item/organ/eyes/on_life()
..()
var/mob/living/carbon/C = owner
//since we can repair fully damaged eyes, check if healing has occurred
if((organ_flags & ORGAN_FAILING) && (damage < maxHealth))
organ_flags &= ~ORGAN_FAILING
C.cure_blind(EYE_DAMAGE)
//various degrees of "oh fuck my eyes", from "point a laser at your eye" to "staring at the Sun" intensities
if(damage > 20)
damaged = TRUE
if((organ_flags & ORGAN_FAILING))
C.become_blind(EYE_DAMAGE)
else if(damage > 30)
C.overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 2)
else
C.overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 1)
//called once since we don't want to keep clearing the screen of eye damage for people who are below 20 damage
else if(damaged)
damaged = FALSE
C.clear_fullscreen("eye_damage")
return
/obj/item/organ/eyes/night_vision
name = "shadow eyes"
desc = "A spooky set of eyes that can see in the dark."
@@ -88,6 +125,7 @@
icon_state = "cybernetic_eyeballs"
desc = "Your vision is augmented."
status = ORGAN_ROBOTIC
organ_flags = ORGAN_SYNTHETIC
/obj/item/organ/eyes/robotic/emp_act(severity)
. = ..()
@@ -97,6 +135,7 @@
return
to_chat(owner, "<span class='warning'>Static obfuscates your vision!</span>")
owner.flash_act(visual = 1)
owner.adjustOrganLoss(ORGAN_SLOT_EYES, 25)
/obj/item/organ/eyes/robotic/xray
name = "\improper X-ray eyes"

View File

@@ -4,12 +4,24 @@
icon_state = "heart-on"
zone = BODY_ZONE_CHEST
slot = ORGAN_SLOT_HEART
healing_factor = STANDARD_ORGAN_HEALING
decay_factor = 5 * STANDARD_ORGAN_DECAY //designed to fail about 5 minutes after death
low_threshold_passed = "<span class='info'>Prickles of pain appear then die out from within your chest...</span>"
high_threshold_passed = "<span class='warning'>Something inside your chest hurts, and the pain isn't subsiding. You notice yourself breathing far faster than before.</span>"
now_fixed = "<span class='info'>Your heart begins to beat again.</span>"
high_threshold_cleared = "<span class='info'>The pain in your chest has died down, and your breathing becomes more relaxed.</span>"
// Heart attack code is in code/modules/mob/living/carbon/human/life.dm
var/beating = 1
var/icon_base = "heart"
attack_verb = list("beat", "thumped")
var/beat = BEAT_NONE//is this mob having a heatbeat sound played? if so, which?
var/failed = FALSE //to prevent constantly running failing code
var/operated = FALSE //whether the heart's been operated on to fix some of its damages
/obj/item/organ/heart/update_icon()
if(beating)
icon_state = "[icon_base]-on"
@@ -50,6 +62,7 @@
/obj/item/organ/heart/on_life()
if(owner.client && beating)
failed = FALSE
var/sound/slowbeat = sound('sound/health/slowbeat.ogg', repeat = TRUE)
var/sound/fastbeat = sound('sound/health/fastbeat.ogg', repeat = TRUE)
var/mob/living/carbon/H = owner
@@ -70,11 +83,18 @@
H.stop_sound_channel(CHANNEL_HEARTBEAT)
beat = BEAT_NONE
if(organ_flags & ORGAN_FAILING) //heart broke, stopped beating, death imminent
if(owner.stat == CONSCIOUS)
owner.visible_message("<span class='userdanger'>[owner] clutches at [owner.p_their()] chest as if [owner.p_their()] heart is stopping!</span>")
owner.set_heartattack(TRUE)
failed = TRUE
/obj/item/organ/heart/cursed
name = "cursed heart"
desc = "A heart that, when inserted, will force you to pump it manually."
icon_state = "cursedheart-off"
icon_base = "cursedheart"
decay_factor = 0
actions_types = list(/datum/action/item_action/organ_action/cursed_heart)
var/last_pump = 0
var/add_colour = TRUE //So we're not constantly recreating colour datums
@@ -153,7 +173,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"
synthetic = TRUE
organ_flags = ORGAN_SYNTHETIC
/obj/item/organ/heart/cybernetic/emp_act()
. = ..()
@@ -164,7 +184,7 @@
/obj/item/organ/heart/freedom
name = "heart of freedom"
desc = "This heart pumps with the passion to give... something freedom."
synthetic = TRUE //the power of freedom prevents heart attacks
organ_flags = ORGAN_SYNTHETIC //the power of freedom prevents heart attacks
var/min_next_adrenaline = 0
/obj/item/organ/heart/freedom/on_life()

View File

@@ -10,6 +10,11 @@
zone = BODY_ZONE_CHEST
slot = ORGAN_SLOT_LIVER
desc = "Pairing suggestion: chianti and fava beans."
maxHealth = STANDARD_ORGAN_THRESHOLD
healing_factor = STANDARD_ORGAN_HEALING
decay_factor = STANDARD_ORGAN_DECAY
var/damage = 0 //liver damage, 0 is no damage, damage=maxHealth causes liver failure
var/alcohol_tolerance = ALCOHOL_RATE//affects how much damage the liver takes from alcohol
var/failing //is this liver failing?
@@ -24,7 +29,7 @@
var/mob/living/carbon/C = owner
if(istype(C))
if(!failing)//can't process reagents with a failing liver
if(!(organ_flags & ORGAN_FAILING))//can't process reagents with a failing liver
//slowly heal liver damage
damage = max(0, damage - 0.1)
@@ -69,7 +74,7 @@
if(moveCalc == cachedmoveCalc)//reduce calculations
return
if(prob(5))
to_chat(owner, "<span class='notice'>You feel a stange ache in your side, almost like a sitch. This pain is affecting your movements and making you feel lightheaded.</span>")
to_chat(owner, "<span class='notice'>You feel a stange ache in your side, almost like a stitch. This pain is affecting your movements and making you feel lightheaded.</span>")
var/mob/living/carbon/human/H = owner
H.add_movespeed_modifier(LIVER_SWELLING_MOVE_MODIFY, TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = moveCalc)
H.AdjustBloodVol(moveCalc/3)
@@ -97,14 +102,15 @@
name = "cybernetic liver"
icon_state = "liver-c"
desc = "An electronic device designed to mimic the functions of a human liver. It has no benefits over an organic liver, but is easy to produce."
synthetic = TRUE
organ_flags = ORGAN_SYNTHETIC
maxHealth = 1.1 * STANDARD_ORGAN_THRESHOLD
/obj/item/organ/liver/cybernetic/upgraded
name = "upgraded cybernetic liver"
icon_state = "liver-c-u"
desc = "An upgraded version of the cybernetic liver, designed to improve upon organic livers. It is resistant to alcohol poisoning and is very robust at filtering toxins."
alcohol_tolerance = 0.001
maxHealth = 200 //double the health of a normal liver
maxHealth = 2 * STANDARD_ORGAN_THRESHOLD
toxTolerance = 15 //can shrug off up to 15u of toxins
toxLethality = 0.008 //20% less damage than a normal liver

View File

@@ -8,6 +8,19 @@
gender = PLURAL
w_class = WEIGHT_CLASS_NORMAL
var/failed = FALSE
var/operated = FALSE //whether we can still have our damages fixed through surgery
//health
maxHealth = LUNGS_MAX_HEALTH
healing_factor = STANDARD_ORGAN_HEALING
decay_factor = STANDARD_ORGAN_DECAY
high_threshold_passed = "<span class='warning'>You feel some sort of constriction around your chest as your breathing becomes shallow and rapid.</span>"
now_fixed = "<span class='warning'>Your lungs seem to once again be able to hold air.</span>"
high_threshold_cleared = "<span class='info'>The constriction around your chest loosens as your breathing calms down.</span>"
//Breath damage
var/safe_oxygen_min = 16 // Minimum safe partial pressure of O2, in kPa
@@ -56,12 +69,10 @@
var/crit_stabilizing_reagent = "epinephrine"
//health
var/maxHealth = LUNGS_MAX_HEALTH
var/damage = 0
//TODO: lung health affects lung function
/obj/item/organ/lungs/proc/adjustLungLoss(damage_mod, mob/living/carbon/M) //damage might be too low atm.
/obj/item/organ/lungs/onDamage(damage_mod) //damage might be too low atm.
if (maxHealth == INFINITY)
return
if(damage+damage_mod < 0)
@@ -70,22 +81,22 @@
damage += damage_mod
if ((damage / maxHealth) > 1)
to_chat(M, "<span class='userdanger'>You feel your lungs collapse within your chest as you gasp for air, unable to inflate them anymore!</span>")
M.emote("gasp")
to_chat(owner, "<span class='userdanger'>You feel your lungs collapse within your chest as you gasp for air, unable to inflate them anymore!</span>")
owner.emote("gasp")
SSblackbox.record_feedback("tally", "fermi_chem", 1, "Lungs lost")
qdel(src)
//qdel(src) - Handled elsewhere for now.
else if ((damage / maxHealth) > 0.75)
to_chat(M, "<span class='warning'>It's getting really hard to breathe!!</span>")
M.emote("gasp")
M.Dizzy(3)
to_chat(owner, "<span class='warning'>It's getting really hard to breathe!!</span>")
owner.emote("gasp")
owner.Dizzy(3)
else if ((damage / maxHealth) > 0.5)
M.Dizzy(2)
to_chat(M, "<span class='notice'>Your chest is really starting to hurt.</span>")
M.emote("cough")
owner.Dizzy(2)
to_chat(owner, "<span class='notice'>Your chest is really starting to hurt.</span>")
owner.emote("cough")
else if ((damage / maxHealth) > 0.2)
to_chat(M, "<span class='notice'>You feel an ache within your chest.</span>")
M.emote("cough")
M.Dizzy(1)
to_chat(owner, "<span class='notice'>You feel an ache within your chest.</span>")
owner.emote("cough")
owner.Dizzy(1)
/obj/item/organ/lungs/proc/check_breath(datum/gas_mixture/breath, mob/living/carbon/human/H)
//TODO: add lung damage = less oxygen gains
@@ -405,13 +416,13 @@
var/cold_modifier = H.dna.species.coldmod
if(breath_temperature < cold_level_3_threshold)
H.apply_damage_type(cold_level_3_damage*cold_modifier, cold_damage_type)
adjustLungLoss((cold_level_3_damage*cold_modifier*2), H)
adjustOrganLoss(ORGAN_SLOT_LUNG, (cold_level_3_damage*cold_modifier*2))
if(breath_temperature > cold_level_3_threshold && breath_temperature < cold_level_2_threshold)
H.apply_damage_type(cold_level_2_damage*cold_modifier, cold_damage_type)
adjustLungLoss((cold_level_2_damage*cold_modifier*2), H)
adjustOrganLoss(ORGAN_SLOT_LUNG, (cold_level_2_damage*cold_modifier*2))
if(breath_temperature > cold_level_2_threshold && breath_temperature < cold_level_1_threshold)
H.apply_damage_type(cold_level_1_damage*cold_modifier, cold_damage_type)
adjustLungLoss((cold_level_1_damage*cold_modifier*2), H)
adjustOrganLoss(ORGAN_SLOT_LUNG, (cold_level_1_damage*cold_modifier*2))
if(breath_temperature < cold_level_1_threshold)
if(prob(20))
to_chat(H, "<span class='warning'>You feel [cold_message] in your [name]!</span>")
@@ -420,17 +431,29 @@
var/heat_modifier = H.dna.species.heatmod
if(breath_temperature > heat_level_1_threshold && breath_temperature < heat_level_2_threshold)
H.apply_damage_type(heat_level_1_damage*heat_modifier, heat_damage_type)
adjustLungLoss((heat_level_1_damage*heat_modifier*2), H)
adjustOrganLoss(ORGAN_SLOT_LUNG, (heat_level_1_damage*heat_modifier*2))
if(breath_temperature > heat_level_2_threshold && breath_temperature < heat_level_3_threshold)
H.apply_damage_type(heat_level_2_damage*heat_modifier, heat_damage_type)
adjustLungLoss((heat_level_2_damage*heat_modifier*2), H)
adjustOrganLoss(ORGAN_SLOT_LUNG, (heat_level_2_damage*heat_modifier*2))
if(breath_temperature > heat_level_3_threshold)
H.apply_damage_type(heat_level_3_damage*heat_modifier, heat_damage_type)
adjustLungLoss((heat_level_3_damage*heat_modifier*2), H)
adjustOrganLoss(ORGAN_SLOT_LUNG, (heat_level_3_damage*heat_modifier*2))
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/lungs/on_life()
..()
if((!failed) && ((organ_flags & ORGAN_FAILING)))
if(owner.stat == CONSCIOUS)
owner.visible_message("<span class='danger'>[owner] grabs [owner.p_their()] throat, struggling for breath!</span>", \
"<span class='userdanger'>You suddenly feel like you can't breathe!</span>")
failed = TRUE
else if(!(organ_flags & ORGAN_FAILING))
failed = FALSE
return
/obj/item/organ/lungs/prepare_eat()
var/obj/S = ..()
S.reagents.add_reagent("salbutamol", 5)
@@ -451,14 +474,16 @@
name = "cybernetic lungs"
desc = "A cybernetic version of the lungs found in traditional humanoid entities. It functions the same as an organic lung and is merely meant as a replacement."
icon_state = "lungs-c"
synthetic = TRUE
organ_flags = ORGAN_SYNTHETIC
maxHealth = 400
safe_oxygen_min = 13
/obj/item/organ/lungs/cybernetic/emp_act()
. = ..()
if(. & EMP_PROTECT_SELF)
return
owner.losebreath = 20
owner.adjustOrganLoss(ORGAN_SLOT_LUNGS, 25)
/obj/item/organ/lungs/cybernetic/upgraded
@@ -495,8 +520,24 @@
safe_toxins_max = 0 //We breathe this to gain POWER.
cold_level_1_threshold = 285 // Remember when slimes used to be succeptable to cold? Well....
cold_level_2_threshold = 260
cold_level_3_threshold = 230
maxHealth = 250
/obj/item/organ/lungs/slime/check_breath(datum/gas_mixture/breath, mob/living/carbon/human/H)
. = ..()
if (breath && breath.gases[/datum/gas/plasma])
var/plasma_pp = breath.get_breath_partial_pressure(breath.gases[/datum/gas/plasma])
owner.blood_volume += (0.2 * plasma_pp) // 10/s when breathing literally nothing but plasma, which will suffocate you.
/obj/item/organ/lungs/yamerol
name = "Yamerol lungs"
desc = "A temporary pair of lungs made from self assembling yamerol molecules."
maxHealth = 200
color = "#68e83a"
/obj/item/organ/lungs/yamerol/on_life()
..()
damage += 2 //Yamerol lungs are temporary

View File

@@ -1,3 +1,6 @@
#define STANDARD_ORGAN_THRESHOLD 100
#define STANDARD_ORGAN_HEALING 0.001
/obj/item/organ
name = "organ"
icon = 'icons/obj/surgery.dmi'
@@ -8,11 +11,34 @@
var/zone = BODY_ZONE_CHEST
var/slot
// DO NOT add slots with matching names to different zones - it will break internal_organs_slot list!
var/vital = 0
//Was this organ implanted/inserted/etc, if true will not be removed during species change.
var/external = FALSE
var/synthetic = FALSE // To distinguish between organic and synthetic organs
var/organ_flags = 0
var/maxHealth = STANDARD_ORGAN_THRESHOLD
var/damage = 0 //total damage this organ has sustained
///Healing factor and decay factor function on % of maxhealth, and do not work by applying a static number per tick
var/healing_factor = 0 //fraction of maxhealth healed per on_life(), set to 0 for generic organs
var/decay_factor = 0 //same as above but when without a living owner, set to 0 for generic organs
var/high_threshold = STANDARD_ORGAN_THRESHOLD * 0.45 //when severe organ damage occurs
var/low_threshold = STANDARD_ORGAN_THRESHOLD * 0.1 //when minor organ damage occurs
///Organ variables for determining what we alert the owner with when they pass/clear the damage thresholds
var/prev_damage = 0
var/low_threshold_passed
var/high_threshold_passed
var/now_failing
var/now_fixed
var/high_threshold_cleared
var/low_threshold_cleared
/obj/item/organ/proc/Assemble_Failure_Message() //need to assemble a failure message since we can't have variables be based off of the same object's variables
var/name_length
//if no unique failure message is set, output the generic one, otherwise give the one we have set
if(!Unique_Failure_Msg)
name_length = lentext(name)
if(name[name_length] == "s") //plural case, done without much sanitization since I don't know any organ that ends with an "s" that isn't plural at the moment
Unique_Failure_Msg = "<span class='danger'>Subject's [name] are too damaged to function, and needs to be replaced or fixed!</span>"
else
Unique_Failure_Msg = "<span class='danger'>Subject's [name] is too damaged to function, and needs to be replaced or fixed!</span>"
return Unique_Failure_Msg
/obj/item/organ/proc/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
if(!iscarbon(M) || owner == M)
@@ -33,31 +59,53 @@
for(var/X in actions)
var/datum/action/A = X
A.Grant(M)
STOP_PROCESSING(SSobj, src)
//Special is for instant replacement like autosurgeons
/obj/item/organ/proc/Remove(mob/living/carbon/M, special = 0)
/obj/item/organ/proc/Remove(mob/living/carbon/M, special = FALSE)
owner = null
if(M)
M.internal_organs -= src
if(M.internal_organs_slot[slot] == src)
M.internal_organs_slot.Remove(slot)
if(vital && !special && !(M.status_flags & GODMODE))
if((organ_flags & ORGAN_VITAL) && !special && !(M.status_flags & GODMODE))
M.death()
for(var/X in actions)
var/datum/action/A = X
A.Remove(M)
START_PROCESSING(SSobj, src)
/obj/item/organ/proc/on_find(mob/living/finder)
return
/obj/item/organ/proc/on_life()
return
/obj/item/organ/process()
on_death() //Kinda hate doing it like this, but I really don't want to call process directly.
/obj/item/organ/proc/on_death() //runs decay when outside of a person
if(organ_flags & (ORGAN_SYNTHETIC | ORGAN_FROZEN))
return
applyOrganDamage(maxHealth * decay_factor)
/obj/item/organ/proc/on_life() //repair organ damage if the organ is not failing
if(organ_flags & ORGAN_FAILING)
return
///Damage decrements by a percent of its maxhealth
var/healing_amount = -(maxHealth * healing_factor)
///Damage decrements again by a percent of its maxhealth, up to a total of 4 extra times depending on the owner's health
healing_amount -= owner.satiety > 0 ? 4 * healing_factor * owner.satiety / MAX_SATIETY : 0
applyOrganDamage(healing_amount) //FERMI_TWEAK
/obj/item/organ/examine(mob/user)
..()
if(status == ORGAN_ROBOTIC && crit_fail)
to_chat(user, "<span class='warning'>[src] seems to be broken!</span>")
. = ..()
if(organ_flags & ORGAN_FAILING)
if(status == ORGAN_ROBOTIC)
. += "<span class='warning'>[src] seems to be broken!</span>"
return
. += "<span class='warning'>[src] has decayed for too long, and has turned a sickly color! It doesn't look like it will work anymore!</span>"
return
if(damage > high_threshold)
. += "<span class='warning'>[src] is starting to look discolored.</span>"
/obj/item/organ/proc/prepare_eat()
@@ -78,6 +126,10 @@
foodtype = RAW | MEAT | GROSS
/obj/item/organ/Initialize()
. = ..()
START_PROCESSING(SSobj, src)
/obj/item/organ/Destroy()
if(owner)
// The special flag is important, because otherwise mobs can die
@@ -100,6 +152,57 @@
/obj/item/organ/item_action_slot_check(slot,mob/user)
return //so we don't grant the organ's action to mobs who pick up the organ.
///Adjusts an organ's damage by the amount "d", up to a maximum amount, which is by default max damage
/obj/item/organ/proc/applyOrganDamage(var/d, var/maximum = maxHealth) //use for damaging effects
if(!d) //Micro-optimization.
return
if(maximum < damage)
return
damage = CLAMP(damage + d, 0, maximum)
var/mess = check_damage_thresholds(owner)
prev_damage = damage
if(mess && owner)
to_chat(owner, mess)
///SETS an organ's damage to the amount "d", and in doing so clears or sets the failing flag, good for when you have an effect that should fix an organ if broken
/obj/item/organ/proc/setOrganDamage(var/d) //use mostly for admin heals
applyOrganDamage(d - damage)
/** check_damage_thresholds
* input: M (a mob, the owner of the organ we call the proc on)
* output: returns a message should get displayed.
* description: By checking our current damage against our previous damage, we can decide whether we've passed an organ threshold.
* If we have, send the corresponding threshold message to the owner, if such a message exists.
*/
/obj/item/organ/proc/check_damage_thresholds(var/M)
if(damage == prev_damage)
return
var/delta = damage - prev_damage
if(delta > 0)
if(damage >= maxHealth)
organ_flags |= ORGAN_FAILING
return now_failing
if(damage > high_threshold && prev_damage <= high_threshold)
return high_threshold_passed
if(damage > low_threshold && prev_damage <= low_threshold)
return low_threshold_passed
else
organ_flags &= ~ORGAN_FAILING
if(prev_damage > low_threshold && damage <= low_threshold)
return low_threshold_cleared
if(prev_damage > high_threshold && damage <= high_threshold)
return high_threshold_cleared
if(prev_damage == maxHealth)
return now_fixed
//Runs some code on the organ when damage is taken/healed
/obj/item/organ/proc/onDamage(var/d, var/maximum = maxHealth)
return
//Runs some code on the organ when damage is taken/healed
/obj/item/organ/proc/onSetDamage(var/d, var/maximum = maxHealth)
return
//Looking for brains?
//Try code/modules/mob/living/carbon/brain/brain_item.dm

View File

@@ -8,12 +8,43 @@
desc = "Onaka ga suite imasu."
var/disgust_metabolism = 1
healing_factor = STANDARD_ORGAN_HEALING
decay_factor = STANDARD_ORGAN_DECAY
low_threshold_passed = "<span class='info'>Your stomach flashes with pain before subsiding. Food doesn't seem like a good idea right now.</span>"
high_threshold_passed = "<span class='warning'>Your stomach flares up with constant pain- you can hardly stomach the idea of food right now!</span>"
high_threshold_cleared = "<span class='info'>The pain in your stomach dies down for now, but food still seems unappealing.</span>"
low_threshold_cleared = "<span class='info'>The last bouts of pain in your stomach have died out.</span>"
/obj/item/organ/stomach/on_life()
var/mob/living/carbon/human/H = owner
var/datum/reagent/consumable/nutriment/Nutri = locate(/datum/reagent/consumable/nutriment) in H.reagents.reagent_list
if(istype(H))
H.dna.species.handle_digestion(H)
if(!(organ_flags & ORGAN_FAILING))
H.dna.species.handle_digestion(H)
handle_disgust(H)
if(Nutri)
if(damage < low_threshold)
return
Nutri = locate(/datum/reagent/consumable/nutriment) in H.reagents.reagent_list
if(Nutri)
if(prob((damage/40) * Nutri.volume * Nutri.volume))
H.vomit(damage)
to_chat(H, "<span class='warning'>Your stomach reels in pain as you're incapable of holding down all that food!</span>")
else if(Nutri && damage > high_threshold)
if(prob((damage/10) * Nutri.volume * Nutri.volume))
H.vomit(damage)
to_chat(H, "<span class='warning'>Your stomach reels in pain as you're incapable of holding down all that food!</span>")
/obj/item/organ/stomach/proc/handle_disgust(mob/living/carbon/human/H)
if(H.disgust)

View File

@@ -26,12 +26,14 @@
zone = BODY_ZONE_HEAD
slot = ORGAN_SLOT_ADAMANTINE_RESONATOR
icon_state = "adamantine_resonator"
decay_factor = 0
/obj/item/organ/vocal_cords/adamantine
name = "adamantine vocal cords"
desc = "When adamantine resonates, it causes all nearby pieces of adamantine to resonate as well. Adamantine golems use this to broadcast messages to nearby golems."
actions_types = list(/datum/action/item_action/organ_action/use/adamantine_vocal_cords)
icon_state = "adamantine_cords"
decay_factor = 0
/datum/action/item_action/organ_action/use/adamantine_vocal_cords/Trigger()
if(!IsAvailable())
@@ -62,6 +64,7 @@
var/cooldown_mod = 1
var/base_multiplier = 1
spans = list("colossus","yell")
decay_factor = 0
/datum/action/item_action/organ_action/colossus
name = "Voice of God"
@@ -623,10 +626,6 @@
/datum/action/item_action/organ_action/velvet
name = "Velvet chords"
var/obj/item/organ/vocal_cords/velvet/cords = null
//icon_icon = 'icons/mob/screen_alert.dmi'
//button_icon_state = "velvet_chords"
//icon = 'icons/mob/screen_alert.dmi'
//icon_state = "in_love"
/datum/action/item_action/organ_action/velvet/New()
..()

View File

@@ -288,7 +288,7 @@
if(prob(20))
to_chat(C, "<span class='warning'>You can feel your lungs burning!</b></span>")
var/obj/item/organ/lungs/L = C.getorganslot(ORGAN_SLOT_LUNGS)
L.adjustLungLoss(acidstr*2, C)
L.adjustOrganLoss(ORGAN_SLOT_LUNG, acidstr*2)
C.apply_damage(acidstr/5, BURN, target)
C.acid_act(acidstr, volume)
..()

View File

@@ -18,7 +18,7 @@
if(T)
T.adjustTongueLoss(C, -2)//Fix the inputs me!
if(L)
L.adjustLungLoss(-5, C)
L.adjustOrganLoss(ORGAN_SLOT_LUNG, -5)
C.adjustOxyLoss(-2)
else
C.adjustOxyLoss(-10)
@@ -65,9 +65,9 @@
holder.remove_reagent(src.id, "10")
if(!C.getorganslot(ORGAN_SLOT_LUNGS))
var/obj/item/organ/lungs/L = new()
var/obj/item/organ/lungs/yamero/L = new()
L.Insert(C)
to_chat(C, "<span class='notice'>You feel your lungs reform in your chest.</span>")
to_chat(C, "<span class='notice'>You feel the yamerol merge in your chest.</span>")
holder.remove_reagent(src.id, "10")
C.adjustOxyLoss(-3)
@@ -88,7 +88,7 @@
if(T)
T.adjustTongueLoss(C, 1)
if(L)
L.adjustLungLoss(4, C)
L.adjustOrganLoss(ORGAN_SLOT_LUNG, 4)
C.adjustOxyLoss(3)
else
C.adjustOxyLoss(10)

View File

@@ -2483,6 +2483,7 @@
#include "code\modules\projectiles\projectile\special\temperature.dm"
#include "code\modules\projectiles\projectile\special\wormhole.dm"
#include "code\modules\reagents\chem_splash.dm"
#include "code\modules\reagents\chem_wiki_render.dm"
#include "code\modules\reagents\reagent_containers.dm"
#include "code\modules\reagents\reagent_dispenser.dm"
#include "code\modules\reagents\chemistry\colors.dm"