Brainmed Update (#7502)

gamer time.
This commit is contained in:
Matt Atlas
2019-12-10 20:41:15 +02:00
committed by Erki
parent b90d703d20
commit df0cd6189a
178 changed files with 3183 additions and 2109 deletions
+54 -9
View File
@@ -1,12 +1,6 @@
/****************************************************
BLOOD SYSTEM
****************************************************/
//Blood levels
var/const/BLOOD_VOLUME_NORMAL = 560
var/const/BLOOD_VOLUME_SAFE = 501
var/const/BLOOD_VOLUME_OKAY = 336
var/const/BLOOD_VOLUME_BAD = 224
var/const/BLOOD_VOLUME_SURVIVE = 122
/mob/living/carbon/human/var/datum/reagents/vessel //Container for blood and BLOOD ONLY. Do not transfer other chems here.
@@ -15,13 +9,13 @@ var/const/BLOOD_VOLUME_SURVIVE = 122
if(vessel)
return
vessel = new/datum/reagents(BLOOD_VOLUME_NORMAL + 40)
vessel = new/datum/reagents(DEFAULT_BLOOD_SPECIES + 40)
vessel.my_atom = src
if(species && species.flags & NO_BLOOD) //We want the var for safety but we can do without the actual blood.
return
vessel.add_reagent("blood",BLOOD_VOLUME_NORMAL)
vessel.add_reagent("blood", DEFAULT_BLOOD_SPECIES)
fixblood()
//Resets blood data
@@ -99,6 +93,57 @@ var/const/BLOOD_VOLUME_SURVIVE = 122
return bled
#undef BLOOD_SPRAY_DISTANCE
/mob/living/carbon/human/proc/get_blood_volume()
return round((vessel.get_reagent_amount("blood")/species.blood_volume)*100)
/mob/living/carbon/human/proc/get_blood_circulation()
var/obj/item/organ/internal/heart/heart = internal_organs_by_name[BP_HEART]
var/blood_volume = get_blood_volume()
if(!heart)
return 0.25 * blood_volume
var/recent_pump = LAZYACCESS(heart.external_pump, 1) > world.time - (20 SECONDS)
var/pulse_mod = 1
if((status_flags & FAKEDEATH) || BP_IS_ROBOTIC(heart))
pulse_mod = 1
else
switch(heart.pulse)
if(PULSE_NONE)
if(recent_pump)
pulse_mod = LAZYACCESS(heart.external_pump, 2)
else
pulse_mod *= 0.25
if(PULSE_SLOW)
pulse_mod *= 0.9
if(PULSE_FAST)
pulse_mod *= 1.1
if(PULSE_2FAST, PULSE_THREADY)
pulse_mod *= 1.25
blood_volume *= pulse_mod
var/min_efficiency = recent_pump ? 0.5 : 0.3
blood_volume *= max(min_efficiency, (1-(heart.damage / heart.max_damage)))
return min(blood_volume, 100)
/mob/living/carbon/human/proc/get_blood_oxygenation()
var/blood_volume = get_blood_circulation()
if(is_asystole()) // Heart is missing or isn't beating and we're not breathing (hardcrit)
return min(blood_volume, BLOOD_VOLUME_SURVIVE)
if(!need_breathe())
return blood_volume
var/blood_volume_mod = max(0, 1 - getOxyLoss()/(species.total_health/2))
var/oxygenated_mult = 0
if(chem_effects[CE_OXYGENATED] == 1) // Dexalin.
oxygenated_mult = 0.5
else if(chem_effects[CE_OXYGENATED] >= 2) // Dexplus.
oxygenated_mult = 0.8
blood_volume_mod = blood_volume_mod + oxygenated_mult - (blood_volume_mod * oxygenated_mult)
blood_volume = blood_volume * blood_volume_mod
return min(blood_volume, 100)
/****************************************************
BLOOD TRANSFERS
****************************************************/
@@ -164,7 +209,7 @@ var/const/BLOOD_VOLUME_SURVIVE = 122
var/list/chems = list()
chems = params2list(injected.data["trace_chem"])
for(var/C in chems)
src.reagents.add_reagent(C, (text2num(chems[C]) / BLOOD_VOLUME_NORMAL) * amount)//adds trace chemicals to owner's blood
src.reagents.add_reagent(C, (text2num(chems[C]) / DEFAULT_BLOOD_SPECIES) * amount)//adds trace chemicals to owner's blood
reagents.update_total()
//Transfers blood from reagents to vessel, respecting blood types compatability.
+14 -4
View File
@@ -4,6 +4,8 @@
/obj/item/organ/internal
var/dead_icon // Icon to use when the organ has died.
var/damage_reduction = 0.5 //modifier for internal organ injury
var/toxin_type = "undefined"
var/relative_size = 25 //Used for size calcs
min_broken_damage = 10 //Internal organs are frail, man.
@@ -42,9 +44,15 @@
if((status & ORGAN_DEAD) && dead_icon)
icon_state = dead_icon
/obj/item/organ/internal/proc/is_usable()
/obj/item/organ/internal/proc/surgical_fix() //to be used for scarring -mattatlas
heal_damage(damage)
/obj/item/organ/internal/is_usable()
return ..() && !is_broken()
/obj/item/organ/internal/proc/is_damaged()
return damage > 0
/obj/item/organ/internal/robotize()
..()
min_bruised_damage += 5
@@ -75,7 +83,7 @@
degree = " a lot"
if(damage < 5)
degree = " a bit"
owner.custom_pain("Something inside your [parent.name] hurts[degree].", amount, affecting = parent)
owner.custom_pain("Something inside your [parent.name] hurts[degree].", amount)
/obj/item/organ/internal/proc/get_visible_state()
if(damage > max_damage)
@@ -95,10 +103,12 @@
/obj/item/organ/internal/process()
..()
if(istype(owner) && (toxin_type in owner.chem_effects))
take_damage(owner.chem_effects[toxin_type] * 0.1 * PROCESS_ACCURACY, prob(1))
handle_regeneration()
/obj/item/organ/internal/proc/handle_regeneration()
if(!damage || BP_IS_ROBOTIC(src) || !owner || owner.chem_effects[CE_TOXIN])
if(!damage || BP_IS_ROBOTIC(src) || !owner || owner.chem_effects[CE_TOXIN] || owner.is_asystole())
return
if(damage < 0.1*max_damage)
heal_damage(0.02)
heal_damage(0.1)
+2 -2
View File
@@ -1,10 +1,10 @@
/obj/item/organ/appendix
/obj/item/organ/internal/appendix
name = "appendix"
icon_state = "appendix"
parent_organ = BP_GROIN
organ_tag = "appendix"
/obj/item/organ/appendix/removed()
/obj/item/organ/internal/appendix/removed()
if(owner)
var/inflamed = 0
for(var/datum/disease/appendicitis/appendicitis in owner.viruses)
+134 -48
View File
@@ -13,62 +13,148 @@
throw_range = 5
origin_tech = list(TECH_BIO = 3)
attack_verb = list("attacked", "slapped", "whacked")
toxin_type = CE_NEUROTOXIC
damage_reduction = 0
relative_size = 85
var/mob/living/carbon/brain/brainmob = null
var/list/datum/brain_trauma/traumas = list()
var/lobotomized = 0
var/can_lobotomize = 1
var/const/damage_threshold_count = 10
var/damage_threshold_value
var/healed_threshold = 1
var/oxygen_reserve = 6
/obj/item/organ/internal/brain/can_recover()
return ~status & ORGAN_DEAD
/obj/item/organ/internal/brain/proc/get_current_damage_threshold()
return round(damage / damage_threshold_value)
/obj/item/organ/internal/brain/proc/past_damage_threshold(var/threshold)
return (get_current_damage_threshold() > threshold)
/obj/item/organ/internal/brain/set_max_damage(var/ndamage)
..()
damage_threshold_value = round(max_damage / damage_threshold_count)
/obj/item/organ/internal/brain/Initialize(mapload)
. = ..()
if(species)
set_max_damage(species.total_health)
else
set_max_damage(200)
if(!mapload)
addtimer(CALLBACK(src, .proc/clear_screen), 5)
/obj/item/organ/internal/brain/process()
if(owner)
if(damage > max_damage / 2 && healed_threshold)
handle_severe_brain_damage()
if(damage < (max_damage / 4))
healed_threshold = 1
handle_damage_effects()
// Brain damage from low oxygenation or lack of blood.
if(owner.should_have_organ(BP_HEART))
// No heart? You are going to have a very bad time. Not 100% lethal because heart transplants should be a thing.
var/blood_volume = owner.get_blood_oxygenation()
if(blood_volume < BLOOD_VOLUME_SURVIVE)
if(!owner.chem_effects[CE_STABLE] || prob(60))
oxygen_reserve = max(0, oxygen_reserve-1)
else
oxygen_reserve = min(initial(oxygen_reserve), oxygen_reserve+1)
if(!oxygen_reserve) //(hardcrit)
owner.Paralyse(3)
var/can_heal = damage && damage < max_damage && (damage % damage_threshold_value || owner.chem_effects[CE_BRAIN_REGEN] || (!past_damage_threshold(3) && owner.chem_effects[CE_STABLE]))
var/damprob
//Effects of bloodloss
switch(blood_volume)
if(BLOOD_VOLUME_SAFE to INFINITY)
if(can_heal)
damage = max(damage-1, 0)
if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE)
if(prob(1))
to_chat(owner, "<span class='warning'>You feel [pick("dizzy","woozy","faint")]...</span>")
damprob = owner.chem_effects[CE_STABLE] ? 30 : 60
if(!past_damage_threshold(2) && prob(damprob))
take_internal_damage(1)
if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY)
owner.eye_blurry = max(owner.eye_blurry,6)
damprob = owner.chem_effects[CE_STABLE] ? 40 : 80
if(!past_damage_threshold(4) && prob(damprob))
take_internal_damage(1)
if(!owner.paralysis && prob(10))
owner.Paralyse(rand(1,3))
to_chat(owner, "<span class='warning'>You feel extremely [pick("dizzy","woozy","faint")]...</span>")
if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD)
owner.eye_blurry = max(owner.eye_blurry,6)
damprob = owner.chem_effects[CE_STABLE] ? 60 : 100
if(!past_damage_threshold(6) && prob(damprob))
take_internal_damage(1)
if(!owner.paralysis && prob(15))
owner.Paralyse(3,5)
to_chat(owner, "<span class='warning'>You feel extremely [pick("dizzy","woozy","faint")]...</span>")
if(-(INFINITY) to BLOOD_VOLUME_SURVIVE) // Also see heart.dm, being below this point puts you into cardiac arrest.
owner.eye_blurry = max(owner.eye_blurry,6)
damprob = owner.chem_effects[CE_STABLE] ? 80 : 100
if(prob(damprob))
take_internal_damage(1)
if(prob(damprob))
take_internal_damage(1)
..()
/obj/item/organ/internal/brain/take_internal_damage(var/damage, var/silent)
set waitfor = 0
..()
if(damage >= 10) //This probably won't be triggered by oxyloss or mercury. Probably.
var/damage_secondary = damage * 0.20
owner.eye_blurry += damage_secondary
owner.confused += damage_secondary * 2
owner.Paralyse(damage_secondary)
owner.Weaken(round(damage, 1))
if(prob(30))
addtimer(CALLBACK(src, .proc/brain_damage_callback, damage), rand(6, 20) SECONDS, TIMER_UNIQUE)
/obj/item/organ/internal/brain/proc/brain_damage_callback(var/damage) //Confuse them as a somewhat uncommon aftershock. Side note: Only here so a spawn isn't used. Also, for the sake of a unique timer.
to_chat(owner, "<span class = 'notice' font size='10'><B>I can't remember which way is forward...</B></span>")
owner.confused += damage
/obj/item/organ/internal/brain/proc/handle_severe_brain_damage()
set waitfor = FALSE
healed_threshold = 0
to_chat(owner, "<span class = 'notice' font size='10'><B>Where am I...?</B></span>")
sleep(5 SECONDS)
if(!owner)
return
to_chat(owner, "<span class = 'notice' font size='10'><B>What's going on...?</B></span>")
sleep(10 SECONDS)
if(!owner)
return
to_chat(owner, "<span class = 'notice' font size='10'><B>What happened...?</B></span>")
alert(owner, "You have taken massive brain damage! You will not be able to remember the events leading up to your injury.", "Brain Damaged")
if(lobotomized && (owner.getBrainLoss() < 40)) //lobotomized brains cannot be healed with chemistry. Part of the brain is irrevocably missing. Can be fixed magically with cloning, ofc.
owner.setBrainLoss(40)
for(var/T in owner.get_traumas())
var/datum/brain_trauma/BT = T
if(!BT.suppressed)
BT.on_life()
var/blood_volume = round(owner.vessel.get_reagent_amount("blood"))
switch(blood_volume)
if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE)
var/word = pick("dizzy","woosey","faint")
to_chat(owner, "<span class='warning'>You feel [word]...</span>")
if(prob(1))
word = pick("dizzy","woosey","faint")
to_chat(owner, "<span class='warning'>You feel [word]...</span>")
if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY)
owner.eye_blurry = max(owner.eye_blurry,6)
owner.oxyloss += 1
if(prob(15))
owner.Paralyse(rand(1,3))
var/word = pick("dizzy","woosey","faint")
to_chat(owner, "<span class='warning'>You feel extremely [word]...</span>")
if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD)
owner.oxyloss += 3
owner.toxloss += 3
if(prob(15))
var/word = pick("dizzy","woosey","faint")
to_chat(owner, "<span class='warning'>You feel extremely [word]...</span>")
if(0 to BLOOD_VOLUME_SURVIVE)
// There currently is a strange bug here. If the mob is not below -100 health
// when death() is called, apparently they will be just fine, and this way it'll
// spam deathgasp. Adjusting toxloss ensures the mob will stay dead.
owner.toxloss += 300 // just to be safe!
owner.death()
if(owner.species.has_organ[BP_HEART]) //This is where the bad times start if you have no heart.
var/obj/item/organ/internal/heart/H = owner.internal_organs_by_name[BP_HEART]
if(!istype(H))
var/damprob
owner.eye_blurry = max(owner.eye_blurry,6)
damprob = owner.chem_effects[CE_STABLE] ? 80 : 100
if(prob(10))
to_chat(owner, "<span class='danger'><font size=3>You jerk and gasp for breath, yet you still feel like you're suffocating!</font></span>")
owner.emote("jerks and gasps!")
if(prob(damprob))
owner.adjustOxyLoss(15)
/obj/item/organ/internal/brain/proc/handle_damage_effects()
if(owner.stat)
return
if(damage > 0 && prob(1))
owner.custom_pain("Your head feels numb and painful.",10)
if(is_bruised() && prob(1) && owner.eye_blurry <= 0)
to_chat(owner, "<span class='warning'>It becomes hard to see for some reason.</span>")
owner.eye_blurry = 10
if(damage >= 0.5*max_damage && prob(1) && owner.get_active_hand())
to_chat(owner, "<span class='danger'>Your hand won't respond properly, and you drop what you are holding!</span>")
owner.drop_item()
if(damage >= 0.6*max_damage)
owner.slurring = max(owner.slurring, 2)
if(is_broken())
if(!owner.lying)
to_chat(owner, "<span class='danger'>You black out!</span>")
owner.Paralyse(10)
+2
View File
@@ -6,6 +6,8 @@
parent_organ = BP_HEAD
robotic_name = "visual prosthesis"
robotic_sprite = "eyes-prosthetic"
max_damage = 45
relative_size = 5
var/list/eye_colour = list(0,0,0)
var/singular_name = "eye"
+82 -42
View File
@@ -6,60 +6,98 @@
dead_icon = "heart-off"
robotic_name = "circulatory pump"
robotic_sprite = "heart-prosthetic"
toxin_type = CE_CARDIOTOXIC
max_damage = 45
relative_size = 5
damage_reduction = 0.7
var/pulse = PULSE_NORM //current pulse level
var/heartbeat = 0
var/next_blood_squirt = 0
var/list/external_pump
/obj/item/organ/internal/heart/process()
if(owner)
handle_pulse()
if(pulse)
if(pulse == PULSE_2FAST && prob(1))
take_internal_damage(0.5)
if(pulse == PULSE_THREADY && prob(5))
take_internal_damage(0.5)
handle_heartbeat()
handle_blood()
..()
/obj/item/organ/internal/heart/proc/handle_pulse()
if((species && species.flags & NO_BLOOD)) //No heart, no pulse, buddy.
if((species && species.flags & NO_BLOOD) || BP_IS_ROBOTIC(src)) //No heart, no pulse, buddy. Or if the heart is robotic.
pulse = PULSE_NONE
return
var/temp = PULSE_NORM
// pulse mod starts out as just the chemical effect amount
var/pulse_mod = owner.chem_effects[CE_PULSE]
var/is_stable = owner.chem_effects[CE_STABLE]
if(round(owner.vessel.get_reagent_amount("blood")) <= BLOOD_VOLUME_BAD) //how much blood do we have
temp = PULSE_THREADY //not enough :(
// If you have enough heart chemicals to be over 2, you're likely to take extra damage.
if(pulse_mod > 2 && !is_stable)
var/damage_chance = (pulse_mod - 2) ** 2
if(prob(damage_chance))
take_internal_damage(0.5)
if(owner.status_flags & FAKEDEATH)
temp = PULSE_NONE //pretend that we're dead. unlike actual death, can be inflienced by meds
// Now pulse mod is impacted by shock stage and other things too
if(owner.shock_stage > 30)
pulse_mod++
if(owner.shock_stage > 80)
pulse_mod++
//handles different chems' influence on pulse
for(var/datum/reagent/R in owner.reagents.reagent_list)
if(R.id in bradycardics)
if(temp <= PULSE_THREADY && temp >= PULSE_NORM)
temp--
if(R.id in tachycardics)
if(temp <= PULSE_FAST && temp >= PULSE_NONE)
temp++
if(R.id in heartstopper) //To avoid using fakedeath
if(rand(0,6) == 3)
take_internal_damage(5)
if(R.id in cheartstopper) //Conditional heart-stoppage
if(R.volume >= R.overdose)
if(rand(0,6) == 3)
take_internal_damage(5)
var/oxy = owner.get_blood_oxygenation()
if(oxy < BLOOD_VOLUME_OKAY) //brain wants us to get MOAR OXY
pulse_mod++
if(oxy < BLOOD_VOLUME_BAD) //MOAR
pulse_mod++
pulse = temp
if(owner.status_flags & FAKEDEATH || owner.chem_effects[CE_NOPULSE])
pulse = Clamp(PULSE_NONE + pulse_mod, PULSE_NONE, PULSE_2FAST) //pretend that we're dead. unlike actual death, can be inflienced by meds
return
//If heart is stopped, it isn't going to restart itself randomly.
if(pulse == PULSE_NONE)
return
else //and if it's beating, let's see if it should
var/should_stop = prob(80) && owner.get_blood_circulation() < BLOOD_VOLUME_SURVIVE //cardiovascular shock, not enough liquid to pump
should_stop = should_stop || prob(max(0, owner.getBrainLoss() - owner.maxHealth * 0.75)) //brain failing to work heart properly
should_stop = should_stop || (prob(5) && pulse == PULSE_THREADY) //erratic heart patterns, usually caused by oxyloss
if(should_stop) // The heart has stopped due to going into traumatic or cardiovascular shock.
to_chat(owner, "<span class='danger'>Your heart has stopped!</span>")
pulse = PULSE_NONE
return
// Pulse normally shouldn't go above PULSE_2FAST
pulse = Clamp(PULSE_NORM + pulse_mod, PULSE_SLOW, PULSE_2FAST)
// If fibrillation, then it can be PULSE_THREADY
var/fibrillation = oxy <= BLOOD_VOLUME_SURVIVE || (prob(30) && owner.shock_stage > 120)
if(pulse && fibrillation) //I SAID MOAR OXYGEN
pulse = PULSE_THREADY
// Stablising chemicals pull the heartbeat towards the center
if(pulse != PULSE_NORM && is_stable)
if(pulse > PULSE_NORM)
pulse--
else
pulse++
/obj/item/organ/internal/heart/proc/handle_heartbeat()
if(pulse == PULSE_NONE || !owner.species.has_organ[BP_HEART])
return
if(!src || status & ORGAN_ROBOT)
return
if(pulse >= PULSE_2FAST || owner.shock_stage >= 10 || istype(get_turf(src), /turf/space))
//PULSE_THREADY - maximum value for pulse, currently it 5.
if(pulse >= PULSE_2FAST || owner.shock_stage >= 10)
//PULSE_THREADY - maximum value for pulse, currently it is 5.
//High pulse value corresponds to a fast rate of heartbeat.
//Divided by 2, otherwise it is too slow.
var/rate = (PULSE_THREADY - pulse) / 2
var/rate = (PULSE_THREADY - pulse)/2
switch(owner.chem_effects[CE_PULSE])
if(2 to INFINITY)
heartbeat++
if(-INFINITY to -2)
heartbeat--
if(heartbeat >= rate)
heartbeat = 0
@@ -68,20 +106,20 @@
heartbeat++
/obj/item/organ/internal/heart/proc/handle_blood()
if(owner.in_stasis)
if(!owner)
return
if(owner.species && owner.species.flags & NO_BLOOD)
return
if(owner.stat == DEAD && owner.bodytemperature < 170) //Dead or cryosleep people do not pump the blood.
if(!owner || owner.stat == DEAD || owner.bodytemperature < 170 || owner.in_stasis) //Dead or cryosleep people do not pump the blood.
return
if(pulse != PULSE_NONE || BP_IS_ROBOTIC(src))
var/blood_volume = round(owner.vessel.get_reagent_amount("blood"))
//Blood regeneration if there is some space
if(blood_volume < BLOOD_VOLUME_NORMAL && blood_volume)
if(blood_volume < DEFAULT_BLOOD_SPECIES && blood_volume)
var/datum/reagent/blood/B = locate() in owner.vessel.reagent_list //Grab some blood
if(B) // Make sure there's some blood at all
if(weakref && B.data["donor"] != weakref) //If it's not theirs, then we look for theirs - donor is a weakref here, but it should be safe to just directly compare it.
@@ -97,10 +135,6 @@
if(CE_BLOODRESTORE in owner.chem_effects)
B.volume += owner.chem_effects[CE_BLOODRESTORE]
//Effects of bloodloss
if(blood_volume < BLOOD_VOLUME_SAFE && owner.oxyloss < 100 * (1 - blood_volume/BLOOD_VOLUME_NORMAL))
owner.oxyloss += 3
//Bleeding out
var/blood_max = 0
var/open_wound
@@ -144,11 +178,17 @@
owner.eye_blurry = 2
owner.Stun(1)
next_blood_squirt = world.time + 100
var/turf/sprayloc = get_turf(src)
var/turf/sprayloc = get_turf(owner)
blood_max -= owner.drip(Ceiling(blood_max/3), sprayloc)
if(blood_max > 0)
blood_max -= owner.blood_squirt(blood_max, sprayloc)
if(blood_max > 0)
owner.drip(blood_max, get_turf(src))
owner.drip(blood_max, get_turf(owner))
else
owner.drip(blood_max)
owner.drip(blood_max)
/obj/item/organ/internal/heart/proc/is_working()
if(!is_usable())
return FALSE
return pulse > PULSE_NONE || BP_IS_ROBOTIC(src) || (owner.status_flags & FAKEDEATH)
+21 -1
View File
@@ -6,6 +6,11 @@
parent_organ = BP_GROIN
robotic_name = "prosthetic kidneys"
robotic_sprite = "kidneys-prosthetic"
min_bruised_damage = 25
min_broken_damage = 45
max_damage = 70
relative_size = 10
toxin_type = CE_NEPHROTOXIC
/obj/item/organ/internal/kidneys/process()
@@ -22,4 +27,19 @@
if(is_bruised())
owner.adjustToxLoss(0.1 * PROCESS_ACCURACY)
else if(is_broken())
owner.adjustToxLoss(0.3 * PROCESS_ACCURACY)
owner.adjustToxLoss(0.3 * PROCESS_ACCURACY)
if(is_bruised())
if(prob(5) && reagents.get_reagent_amount("potassium") < 5)
reagents.add_reagent("potassium", REM*5)
if(is_broken())
if(owner.reagents.get_reagent_amount("potassium") < 15)
owner.reagents.add_reagent("potassium", REM*2)
//If your kidneys aren't working, your body's going to have a hard time cleaning your blood.
if(!owner.chem_effects[CE_ANTITOXIN])
if(prob(33))
if(is_broken())
owner.adjustToxLoss(0.5)
if(status & ORGAN_DEAD)
owner.adjustToxLoss(1)
+61 -51
View File
@@ -5,6 +5,13 @@
parent_organ = BP_GROIN
robotic_name = "toxin filter"
robotic_sprite = "liver-prosthetic"
toxin_type = CE_HEPATOTOXIC
min_bruised_damage = 25
min_broken_damage = 45
max_damage = 70
relative_size = 60
var/tolerance = 5
/obj/item/organ/internal/liver/process()
@@ -21,58 +28,61 @@
if(prob(1))
spawn owner.delayed_vomit()
if(owner.life_tick % PROCESS_ACCURACY == 0)
if(!(owner.life_tick % PROCESS_ACCURACY == 0))
return
//A liver's duty is to get rid of toxins
if(owner.getToxLoss() > 0 && owner.getToxLoss() <= tolerance)
owner.adjustToxLoss(-0.2) //there isn't a lot of toxin damage, so we're going to be chill and slowly filter it out
else if(owner.getToxLoss() > tolerance)
if(is_bruised())
//damaged liver works less efficiently
owner.adjustToxLoss(-0.5)
if(!owner.reagents.has_reagent("anti_toxin")) //no damage to liver if anti-toxin is present
src.damage += 0.1 * PROCESS_ACCURACY
else if(is_broken())
//non-functioning liver ADDS toxins
owner.adjustToxLoss(-0.1) //roughly 33 minutes to kill someone straight out, stacks with 60+ tox proc tho
else
//functioning liver removes toxins at a cost
owner.adjustToxLoss(-1)
if(!owner.reagents.has_reagent("anti_toxin")) //no damage to liver if anti-toxin is present
src.damage += 0.05 * PROCESS_ACCURACY
//High toxins levels are super dangerous
if(owner.getToxLoss() >= 60 && !owner.reagents.has_reagent("anti_toxin"))
//Healthy liver suffers on its own
if (src.damage < min_broken_damage)
src.damage += 0.2 * PROCESS_ACCURACY
//Damaged one shares the fun
else
var/obj/item/organ/O = pick(owner.internal_organs)
if(O)
O.damage += 0.2 * PROCESS_ACCURACY
//Detox can heal small amounts of damage
if (src.damage && src.damage < src.min_bruised_damage && owner.reagents.has_reagent("anti_toxin"))
src.damage -= 0.2 * PROCESS_ACCURACY
if(src.damage < 0)
src.damage = 0
var/filter_strength = INTOX_FILTER_HEALTHY
//A liver's duty is to get rid of toxins
if(owner.getToxLoss() > 0 && owner.getToxLoss() <= tolerance)
owner.adjustToxLoss(-0.2) //there isn't a lot of toxin damage, so we're going to be chill and slowly filter it out
else if(owner.getToxLoss() > tolerance)
if(is_bruised())
filter_strength = INTOX_FILTER_BRUISED
if(is_broken())
filter_strength = INTOX_FILTER_DAMAGED
//damaged liver works less efficiently
owner.adjustToxLoss(-0.5)
if(!owner.chem_effects[CE_ANTITOXIN]) //no damage to liver if anti-toxin is present
src.damage += 0.1 * PROCESS_ACCURACY
else if(is_broken())
//non-functioning liver ADDS toxins
owner.adjustToxLoss(-0.1) //roughly 33 minutes to kill someone straight out, stacks with 60+ tox proc tho
else
//functioning liver removes toxins at a cost
owner.adjustToxLoss(-1)
if(!owner.chem_effects[CE_ANTITOXIN]) //no damage to liver if anti-toxin is present
src.damage += 0.05 * PROCESS_ACCURACY
if (owner.intoxication > 0)
owner.intoxication -= filter_strength*PROCESS_ACCURACY
owner.intoxication = max(owner.intoxication, 0)
if (!owner.intoxication)
owner.handle_intoxication()
if(owner.chem_effects[CE_ALCOHOL_TOXIC])
take_damage(owner.chem_effects[CE_ALCOHOL_TOXIC] * 0.1 * PROCESS_ACCURACY, prob(1))
if(is_damaged())
owner.adjustToxLoss(owner.chem_effects[CE_ALCOHOL_TOXIC] * 0.1 * PROCESS_ACCURACY)
//High toxins levels are super dangerous
if(owner.getToxLoss() >= 100 && !owner.chem_effects[CE_ANTITOXIN])
//Healthy liver suffers on its own
if (src.damage < min_broken_damage)
src.damage += 0.2 * PROCESS_ACCURACY
//Damaged one shares the fun
else
var/obj/item/organ/O = pick(owner.internal_organs)
if(O)
O.damage += 0.2 * PROCESS_ACCURACY
//Detox can heal small amounts of damage
if (src.damage && src.damage < src.min_bruised_damage && owner.chem_effects[CE_ANTITOXIN])
src.damage -= 0.2 * PROCESS_ACCURACY
if(src.damage < 0)
src.damage = 0
var/filter_strength = INTOX_FILTER_HEALTHY
if(is_bruised())
filter_strength = INTOX_FILTER_BRUISED
if(is_broken())
filter_strength = INTOX_FILTER_DAMAGED
if (owner.intoxication > 0)
owner.intoxication -= min(owner.intoxication, filter_strength*PROCESS_ACCURACY)
if (!owner.intoxication)
owner.handle_intoxication()
if(toxin_type in owner.chem_effects)
if(is_damaged())
owner.adjustToxLoss(owner.chem_effects[toxin_type] * 0.1 * PROCESS_ACCURACY) // as actual organ damage is handled elsewhere
//We got it covered in Process with more detailed thing
/obj/item/organ/internal/liver/handle_regeneration()
return
+68 -27
View File
@@ -9,19 +9,45 @@
parent_organ = BP_CHEST
robotic_name = "gas exchange system"
robotic_sprite = "lungs-prosthetic"
min_bruised_damage = 25
min_broken_damage = 45
toxin_type = CE_PNEUMOTOXIC
max_damage = 70
relative_size = 60
var/rescued = FALSE // whether or not a collapsed lung has been rescued with a syringe
var/oxygen_deprivation = 0
var/last_successful_breath
var/breath_fail_ratio //How badly they failed a breath
/obj/item/organ/internal/lungs/proc/remove_oxygen_deprivation(var/amount)
var/last_suffocation = oxygen_deprivation
oxygen_deprivation = min(species.total_health,max(0,oxygen_deprivation - amount))
return -(oxygen_deprivation - last_suffocation)
/obj/item/organ/internal/lungs/proc/add_oxygen_deprivation(var/amount)
var/last_suffocation = oxygen_deprivation
oxygen_deprivation = min(species.total_health,max(0,oxygen_deprivation + amount))
return (oxygen_deprivation - last_suffocation)
// Returns a percentage value for use by GetOxyloss().
/obj/item/organ/internal/lungs/proc/get_oxygen_deprivation()
if(status & ORGAN_DEAD)
return 100
return round((oxygen_deprivation/species.total_health)*100)
/obj/item/organ/internal/lungs/process()
..()
if(!owner)
return
if (germ_level > INFECTION_LEVEL_ONE)
if(germ_level > INFECTION_LEVEL_ONE)
if(prob(5))
owner.emote("cough") //Respiratory tract infection
if(is_broken() || (is_bruised() && !rescued)) // a thoracostomy can only help with a collapsed lung, not a mangled one
if(is_broken() || (is_bruised() && !rescued) && !owner.is_asystole()) // a thoracostomy can only help with a collapsed lung, not a mangled one
if(prob(2))
spawn owner.emote("me", 1, "coughs up blood!")
owner.drip(10)
@@ -35,25 +61,36 @@
if (owner.losebreath < 5)
owner.losebreath = min(owner.losebreath + 1, 5) // it's still not good, but it's much better than an untreated collapsed lung
/obj/item/organ/internal/lungs/proc/rupture()
var/obj/item/organ/external/parent = owner.get_organ(parent_organ)
if(istype(parent))
owner.custom_pain("You feel a stabbing pain in your [parent.name]!", 50, affecting = parent)
bruise()
/obj/item/organ/internal/lungs/proc/handle_failed_breath()
if(prob(15) && !owner.nervous_system_failure())
if(!owner.is_asystole())
owner.emote("gasp")
else
owner.emote(pick("shiver","twitch"))
if(damage || world.time > last_successful_breath + 2 MINUTES)
owner.adjustOxyLoss(HUMAN_MAX_OXYLOSS*breath_fail_ratio)
owner.oxygen_alert = max(owner.oxygen_alert, 2)
/obj/item/organ/internal/lungs/proc/handle_breath(datum/gas_mixture/breath)
if(!owner)
return 1
if(!breath || (max_damage <= 0))
breath_fail_ratio = 1
handle_failed_breath()
return 1
//exposure to extreme pressures can rupture lungs
if(breath && (breath.total_moles/(owner.species?.breath_vol_mul || 1) < BREATH_MOLES / 5 || breath.total_moles/(owner.species?.breath_vol_mul || 1) > BREATH_MOLES * 5))
if(!is_bruised() && prob(5))
bruise()
//check if we actually need to process breath
if(!breath || (breath.total_moles == 0))
owner.failed_last_breath = 1
if(owner.health > config.health_threshold_crit)
owner.adjustOxyLoss(HUMAN_MAX_OXYLOSS)
else
owner.adjustOxyLoss(HUMAN_CRIT_MAX_OXYLOSS)
owner.oxygen_alert = max(owner.oxygen_alert, 1)
return 0
rupture()
var/safe_pressure_min = owner.species.breath_pressure // Minimum safe partial pressure of breathable gas in kPa
@@ -100,25 +137,24 @@
else
exhaling = 0
var/inhale_pp = (inhaling/breath.total_moles)*breath_pressure
var/toxins_pp = (poison/breath.total_moles)*breath_pressure
var/exhaled_pp = (exhaling/breath.total_moles)*breath_pressure
var/inhale_efficiency = min(round(((inhaling/breath.total_moles)*breath_pressure)/safe_pressure_min, 0.001), 3)
// Not enough to breathe
if(inhale_pp < safe_pressure_min)
if(inhale_efficiency < 1)
if(prob(20))
spawn(0)
if(inhale_efficiency < 0.8)
owner.emote("gasp")
var/ratio = inhale_pp/safe_pressure_min
// Don't fuck them up too fast (space only does HUMAN_MAX_OXYLOSS after all!)
owner.adjustOxyLoss(max(HUMAN_MAX_OXYLOSS*(1-ratio), 0))
else if(prob(20))
to_chat(owner, span("warning", "It's hard to breathe..."))
breath_fail_ratio = 1 - inhale_efficiency
failed_inhale = 1
owner.oxygen_alert = max(owner.oxygen_alert, 1)
else
// We're in safe limits
owner.oxygen_alert = 0
breath_fail_ratio = 0
owner.oxygen_alert = failed_inhale * 2
inhaled_gas_used = inhaling/6 * (owner.species?.breath_eff_mul || 1)
@@ -208,6 +244,11 @@
var/failed_breath = failed_inhale || failed_exhale
if(failed_breath)
handle_failed_breath()
else
last_successful_breath = world.time
owner.oxygen_alert = 0
return failed_breath
/obj/item/organ/internal/lungs/proc/handle_temperature_effects(datum/gas_mixture/breath)
+116
View File
@@ -0,0 +1,116 @@
/obj/item/organ/internal/stomach
name = "stomach"
desc = "Gross. This is hard to stomach."
icon_state = "stomach"
dead_icon = "stomach"
organ_tag = BP_STOMACH
parent_organ = BP_GROIN
var/stomach_capacity
var/datum/reagents/metabolism/ingested
var/next_cramp = 0
/obj/item/organ/internal/stomach/Destroy()
QDEL_NULL(ingested)
. = ..()
/obj/item/organ/internal/stomach/Initialize()
..()
ingested = new /datum/reagents/metabolism(240, owner, CHEM_INGEST)
if(!ingested.my_atom)
ingested.my_atom = src
/obj/item/organ/internal/stomach/removed()
. = ..()
ingested.my_atom = src
ingested.parent = null
/obj/item/organ/internal/stomach/replaced()
. = ..()
ingested.my_atom = owner
ingested.parent = owner
/obj/item/organ/internal/stomach/proc/can_eat_atom(var/atom/movable/food)
return !isnull(get_devour_time(food))
/obj/item/organ/internal/stomach/proc/is_full(var/atom/movable/food)
var/total = Floor(ingested.total_volume / 10)
for(var/a in contents + food)
if(ismob(a))
var/mob/M = a
total += M.mob_size
else if(isobj(a))
var/obj/item/I = a
total += I.get_storage_cost()
else
continue
if(total > species.stomach_capacity)
return TRUE
return FALSE
/obj/item/organ/internal/stomach/proc/get_devour_time(var/atom/movable/food)
if(iscarbon(food) || isanimal(food))
var/mob/living/L = food
if((species.gluttonous & GLUT_TINY) && (L.mob_size <= MOB_TINY) && !ishuman(food)) // Anything MOB_TINY or smaller
return DEVOUR_SLOW
else if((species.gluttonous & GLUT_SMALLER) && owner.mob_size > L.mob_size) // Anything we're larger than
return DEVOUR_SLOW
else if(species.gluttonous & GLUT_ANYTHING) // Eat anything ever
return DEVOUR_FAST
else if(istype(food, /obj/item) && !istype(food, /obj/item/holder)) //Don't eat holders. They are special.
var/obj/item/I = food
var/cost = I.get_storage_cost()
if(cost != INFINITY) // i blame bay - geeves
if((species.gluttonous & GLUT_ITEM_TINY) && cost < 4)
return DEVOUR_SLOW
else if((species.gluttonous & GLUT_ITEM_NORMAL) && cost <= 4)
return DEVOUR_SLOW
else if(species.gluttonous & GLUT_ITEM_ANYTHING)
return DEVOUR_FAST
/obj/item/organ/internal/stomach/return_air()
return null
// This call needs to be split out to make sure that all the ingested things are metabolised
// before the process call is made on any of the other organs
/obj/item/organ/internal/stomach/proc/metabolize()
if(is_usable())
ingested.metabolize()
#define STOMACH_VOLUME 65
/obj/item/organ/internal/stomach/process()
..()
if(owner)
var/functioning = is_usable()
if(damage >= min_bruised_damage && prob((damage / max_damage) * 100))
functioning = FALSE
if(functioning)
for(var/mob/living/M in contents)
if(M.stat == DEAD)
qdel(M)
continue
M.adjustBruteLoss(3)
M.adjustFireLoss(3)
M.adjustToxLoss(3)
var/digestion_product = M.get_digestion_product()
if(digestion_product)
ingested.add_reagent(digestion_product, rand(1,3))
else if(world.time >= next_cramp)
next_cramp = world.time + rand(200,800)
owner.custom_pain("Your stomach cramps agonizingly!",1)
var/alcohol_volume = ingested.get_reagent_amount(/datum/reagent/alcohol/ethanol)
// Alcohol counts as double volume for the purposes of vomit probability
var/effective_volume = ingested.total_volume + alcohol_volume
// Just over the limit, the probability will be low. It rises a lot such that at double ingested it's 64% chance.
var/vomit_probability = (effective_volume / STOMACH_VOLUME) ** 6
if(prob(vomit_probability))
owner.vomit()
#undef STOMACH_VOLUME
+4 -15
View File
@@ -43,7 +43,7 @@
qdel(src)
//VOX ORGANS.
/obj/item/organ/stack
/obj/item/organ/internal/stack
name = "cortical stack"
icon_state = "brain-prosthetic"
organ_tag = "stack"
@@ -54,22 +54,11 @@
var/datum/mind/backup
origin_tech = list(TECH_ENGINEERING = 5, TECH_DATA=3, TECH_BIO=3)
/obj/item/organ/stack/process()
/obj/item/organ/internal/stack/process()
if(owner && owner.stat != DEAD && !is_broken())
backup_time = world.time
if(owner.mind) backup = owner.mind
/obj/item/organ/stack/vox
/obj/item/organ/internal/stack/vox
name = "vox cortical stack"
vital = 0
/obj/item/organ/stack/vox/removed(var/mob/living/user)
if(owner && ishuman(owner))
if(!isvox(owner))
return
if(prob(80))
owner.death()
else
to_chat(owner, "<span class='warning'>Your mind breaks apart when your cortical stack is removed! Your memories and personality are nothing but echoes lost in the numbness of your thoughts...</span>")
owner.set_species("Vox Pariah")
..()
vital = 0
+27 -34
View File
@@ -16,7 +16,7 @@
var/damage = 0 // amount of damage to the organ
var/min_broken_damage = 30
var/min_bruised_damage = 10 // Damage before considered bruised
var/max_damage
var/max_damage = 30
//Strings.
var/organ_tag = "organ"
@@ -47,6 +47,11 @@
args[1] = TRUE
SSatoms.InitAtom(src, args)
if(max_damage)
min_broken_damage = Floor(max_damage / 2)
else
max_damage = min_broken_damage * 2
/obj/item/organ/Destroy()
STOP_PROCESSING(SSprocessing, src)
if(!owner)
@@ -121,9 +126,6 @@
if(owner && vital)
owner.death()
/obj/item/organ/proc/is_damaged()
return damage > 1
/obj/item/organ/proc/is_bruised()
return damage >= min_bruised_damage
@@ -134,7 +136,7 @@
return (!BP_IS_ROBOTIC(src) && (!species || !(species.flags & NO_PAIN)))
/obj/item/organ/proc/can_recover()
return (max_damage > 0) && !(status & ORGAN_DEAD)
return max_damage > 0
/obj/item/organ/process()
@@ -196,7 +198,11 @@
/obj/item/organ/proc/handle_germ_effects()
//** Handle the effects of infections
var/antibiotics = owner.reagents.get_reagent_amount("thetamycin")
var/antibiotics = 0
if(!owner)
return
if (CE_ANTIBIOTIC in owner.chem_effects)
antibiotics = owner.chem_effects[CE_ANTIBIOTIC]
if (germ_level > 0 && germ_level < INFECTION_LEVEL_ONE/2 && prob(30))
germ_level--
@@ -207,8 +213,7 @@
germ_level++
if(germ_level >= INFECTION_LEVEL_ONE)
var/fever_temperature = (owner.species.heat_level_1 - owner.species.body_temperature - 5)* min(germ_level/INFECTION_LEVEL_TWO, 1) + owner.species.body_temperature
owner.bodytemperature += between(0, (fever_temperature - T20C)/BODYTEMP_COLD_DIVISOR + 1, fever_temperature - owner.bodytemperature)
owner.add_chemical_effect(CE_FEVER, germ_level/INFECTION_LEVEL_ONE) //10u of paracetamol minimum for a level 3 infection
if (germ_level >= INFECTION_LEVEL_TWO)
var/obj/item/organ/external/parent = owner.get_organ(parent_organ)
@@ -247,15 +252,21 @@
damage = 0
/obj/item/organ/proc/heal_damage(amount)
if (can_recover())
if(can_recover())
damage = between(0, damage - round(amount, 0.1), max_damage)
/obj/item/organ/proc/is_broken()
return (damage >= min_broken_damage || (status & ORGAN_CUT_AWAY) || (status & ORGAN_BROKEN))
/obj/item/organ/proc/is_usable()
return !(status & (ORGAN_CUT_AWAY|ORGAN_MUTATED|ORGAN_DEAD))
//Germs
/obj/item/organ/proc/handle_antibiotics()
var/antibiotics = owner.reagents.get_reagent_amount("thetamycin")
if(!owner)
return
var/antibiotics = owner.reagents?.get_reagent_amount("thetamycin")
if (!germ_level || antibiotics < 5)
return
@@ -359,7 +370,7 @@
if(owner && vital)
if(user)
user.attack_log += "\[[time_stamp()]\]<font color='red'> removed a vital organ ([src]) from [owner.name] ([owner.ckey]) (INTENT: [uppertext(user.a_intent)])</font>"
user.attack_log += "\[[time_stamp()]\]<font color='red'> removed a vital organ ([src]) from [owner.name] ([owner.ckey]) [user ? "(INTENT: [uppertext(user.a_intent)])" : ""]</font>"
owner.attack_log += "\[[time_stamp()]\]<font color='orange'> had a vital organ ([src]) removed by [user.name] ([user.ckey]) (INTENT: [uppertext(user.a_intent)])</font>"
msg_admin_attack("[user.name] ([user.ckey]) removed a vital organ ([src]) from [owner.name] ([owner.ckey]) (INTENT: [uppertext(user.a_intent)]) (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[user.x];Y=[user.y];Z=[user.z]'>JMP</a>)",ckey=key_name(user),ckey_target=key_name(owner))
owner.death()
@@ -367,31 +378,13 @@
owner.update_action_buttons()
owner = null
/obj/item/organ/proc/replaced(var/mob/living/carbon/human/target,var/obj/item/organ/external/affected)
if(!istype(target)) return
var/datum/reagent/blood/transplant_blood = locate(/datum/reagent/blood) in reagents.reagent_list
transplant_data = list()
if(!transplant_blood)
transplant_data["species"] = target.species.name
transplant_data["blood_type"] = target.dna.b_type
transplant_data["blood_DNA"] = target.dna.unique_enzymes
else
transplant_data["species"] = transplant_blood.data["species"]
transplant_data["blood_type"] = transplant_blood.data["blood_type"]
transplant_data["blood_DNA"] = transplant_blood.data["blood_DNA"]
/obj/item/organ/proc/replaced(var/mob/living/carbon/human/target, var/obj/item/organ/external/affected)
owner = target
action_button_name = initial(action_button_name)
src.forceMove(owner)
STOP_PROCESSING(SSprocessing, src)
target.internal_organs |= src
affected.internal_organs |= src
target.internal_organs_by_name[organ_tag] = src
if(robotic)
robotize()
owner.update_action_buttons()
forceMove(owner) //just in case
if(BP_IS_ROBOTIC(src))
set_dna(owner.dna)
return 1
/obj/item/organ/internal/eyes/replaced(var/mob/living/carbon/human/target)
+191 -47
View File
@@ -14,34 +14,49 @@
dir = SOUTH
organ_tag = "limb"
var/brute_mod = 1
var/burn_mod = 1
var/icon_name = null
var/body_part = null
var/icon_position = 0
var/model
var/force_icon
var/damage_state = "00"
var/brute_dam = 0
var/burn_dam = 0
var/max_size = 0
//Damage variables
var/brute_mod = 1
var/brute_dam = 0 // Actual current brute damage.
var/brute_ratio = 0 // Ratio of current brute damage to max damage.
var/burn_mod = 1
var/burn_dam = 0 // Actual current burn damage.
var/burn_ratio = 0 // Ratio of current burn damage to max damage.
var/last_dam = -1
var/genetic_degradation = 0 // Amount of current genetic damage.
var/pain = 0 // How much the limb hurts.
var/pain_disability_threshold // Point at which a limb becomes unusable due to pain.
var/max_size = 0
var/icon/mob_icon
var/gendered_icon = 0
var/force_icon
var/limb_name
var/disfigured = 0
var/cannot_amputate
var/cannot_break
var/s_tone
var/skin_color
var/hair_color
var/list/wounds = list()
var/list/implants = list()
var/number_wounds = 0 // cache the number of wounds, which is NOT wounds.len!
var/perma_injury = 0
var/obj/item/organ/external/parent
var/list/obj/item/organ/external/children
var/list/internal_organs = list() // Internal organs of this body part
var/damage_msg = "<span class='warning'>You feel an intense pain!</span>"
var/broken_description
var/open = 0
@@ -49,23 +64,25 @@
var/cavity = 0
var/sabotaged = 0 // If a prosthetic limb is emagged, it will detonate when it fails.
var/encased // Needs to be opened with a saw to access the organs.
var/list/implants = list()
var/wound_update_accuracy = 1 // how often wounds should be updated, a higher number means less often
var/has_tendon = FALSE //Does this limb have a tendon?
var/joint = "joint" // Descriptive string used in dislocation.
var/artery_name = "artery" //Name of the artery. Cartoid, etc.
var/tendon_name = "tendon" //Name of the limb's tendon. Achilles heel, etc.
var/amputation_point // Descriptive string used in amputation.
var/dislocated = 0 // If you target a joint, you can dislocate the limb, causing temporary damage to the organ.
var/wound_update_accuracy = 1 // how often wounds should be updated, a higher number means less often
var/can_grasp //It would be more appropriate if these two were named "affects_grasp" and "affects_stand" at this point
var/can_stand
var/body_hair
var/painted = 0
var/maim_bonus = 0.75 //For special projectile gibbing calculation, dubbed "maiming"
var/can_be_maimed = TRUE //Can this limb be 'maimed'?
var/list/genetic_markings // Markings (body_markings) to apply to the icon
var/list/temporary_markings // Same as above, but not preserved when cloning
var/list/cached_markings // The two above lists cached for perf. reasons.
var/maim_bonus = 0.75 //For special projectile gibbing calculation, dubbed "maiming"
var/can_be_maimed = TRUE //Can this limb be 'maimed'?
var/atom/movable/applied_pressure //Pressure applied to wounds. It'll make them bleed less, generally.
@@ -184,6 +201,8 @@
robotize(robotize_type)
. = ..(mapload, FALSE)
if(isnull(pain_disability_threshold))
pain_disability_threshold = (max_damage * 0.75)
if(owner)
replaced(owner)
sync_colour_to_human(owner)
@@ -194,19 +213,14 @@
get_icon()
/obj/item/organ/external/replaced(var/mob/living/carbon/human/target)
owner = target
if(!species)
species = owner.species
if(!dna)
dna = owner.dna
forceMove(owner)
..()
if(istype(owner))
owner.organs_by_name[limb_name] = src
owner.organs |= src
for(var/obj/item/organ/organ in src)
organ.replaced(owner,src)
if(parent_organ)
if(!parent && parent_organ)
parent = owner.organs_by_name[src.parent_organ]
if(parent)
if(!parent.children)
@@ -229,20 +243,14 @@
/obj/item/organ/external/proc/is_damageable(var/additional_damage = 0)
return (vital || brute_dam + burn_dam + additional_damage < max_damage)
/obj/item/organ/external/take_damage(brute, burn, sharp, edge, used_weapon = null, list/forbidden_limbs = list())
/obj/item/organ/external/take_damage(brute, burn, sharp, edge, used_weapon = null, list/forbidden_limbs = list(), damage_flags)
if((brute <= 0) && (burn <= 0))
return 0
brute *= brute_mod
burn *= burn_mod
// High brute damage or sharp objects may damage internal organs
if(internal_organs && (brute_dam >= max_damage || (((sharp && brute >= 5) || brute >= 10) && prob(5))))
// Damage an internal organ
if(internal_organs && internal_organs.len)
var/obj/item/organ/I = pick(internal_organs)
I.take_damage(brute / 2)
brute -= brute / 2
add_pain(0.6*burn + 0.4*brute)
if(status & ORGAN_BROKEN && prob(40) && brute)
if (owner && (owner.can_feel_pain()))
@@ -250,6 +258,12 @@
if(used_weapon)
add_autopsy_data("[used_weapon]", brute + burn)
// High brute damage or sharp objects may damage internal organs
if(length(internal_organs))
if(damage_internal_organs(brute, burn, sharp, damage_flags))
brute /= 2
burn /= 2
var/can_cut = (prob(brute*2) || sharp) && !(status & ORGAN_ROBOT)
// If the limbs can break, make sure we don't exceed the maximum damage a limb can take before breaking
@@ -259,35 +273,35 @@
if(brute)
if(can_cut)
if(sharp && !edge)
createwound( PIERCE, brute )
createwound(PIERCE, brute)
else
createwound( CUT, brute )
createwound(CUT, brute)
else
createwound( BRUISE, brute )
createwound(BRUISE, brute)
if(burn)
createwound( BURN, burn )
createwound(BURN, burn)
else
//If we can't inflict the full amount of damage, spread the damage in other ways
//How much damage can we actually cause?
var/can_inflict = max_damage * config.organ_health_multiplier - (brute_dam + burn_dam)
var/spillover = 0
if(can_inflict)
if (brute > 0)
//Inflict all burte damage we can
if(brute > 0)
//Inflict all brute damage we can
if(can_cut)
if(sharp && !edge)
createwound( PIERCE, min(brute,can_inflict) )
createwound(PIERCE, min(brute,can_inflict))
else
createwound( CUT, min(brute,can_inflict) )
createwound(CUT, min(brute,can_inflict))
else
createwound( BRUISE, min(brute,can_inflict) )
createwound(BRUISE, min(brute,can_inflict))
var/temp = can_inflict
//How much mroe damage can we inflict
//How much more damage can we inflict
can_inflict = max(0, can_inflict - brute)
//How much brute damage is left to inflict
spillover += max(0, brute - temp)
if (burn > 0 && can_inflict)
if(burn > 0 && can_inflict)
//Inflict all burn damage we can
createwound(BURN, min(burn,can_inflict))
//How much burn damage is left to inflict
@@ -307,6 +321,53 @@
return update_icon()
/obj/item/organ/external/proc/damage_internal_organs(brute, burn, sharp, damage_flags)
if(!length(internal_organs))
return FALSE
var/damage_amt = brute
var/cur_damage = brute_dam
var/laser = (damage_flags & DAM_LASER)
if(laser)
damage_amt += burn
cur_damage += burn_dam
if(!damage_amt)
return FALSE
var/organ_damage_threshold = 10
if(sharp)
organ_damage_threshold *= 0.5
if(laser)
organ_damage_threshold *= 2
if(!(cur_damage + damage_amt >= max_damage) && !(damage_amt >= organ_damage_threshold))
return FALSE
var/list/victims = list()
var/organ_hit_chance = 0
for(var/obj/item/organ/internal/I in internal_organs)
if(I.damage < I.max_damage)
victims[I] = I.relative_size
organ_hit_chance += I.relative_size
//No damageable organs
if(!length(victims))
return FALSE
organ_hit_chance += 5 * damage_amt/organ_damage_threshold
if(encased && !(status & ORGAN_BROKEN)) //ribs protect
organ_hit_chance *= 0.6
organ_hit_chance = min(organ_hit_chance, 100)
if(prob(organ_hit_chance))
var/obj/item/organ/internal/victim = pickweight(victims)
damage_amt -= max(damage_amt*victim.damage_reduction, 0)
victim.take_internal_damage(damage_amt)
return TRUE
/obj/item/organ/external/proc/handle_limb_gibbing(var/used_weapon,var/brute,var/burn)
//If limb took enough damage, try to cut or tear it off
if(owner && loc == owner && !is_stump())
@@ -565,7 +626,9 @@ Note that amputating the affected organ does in fact remove the infection from t
handle_germ_effects()
/obj/item/organ/external/proc/handle_germ_sync()
var/antibiotics = owner.reagents.get_reagent_amount("thetamycin")
var/antibiotics = 0
if(CE_ANTIBIOTIC in owner.chem_effects)
antibiotics = owner.chem_effects[CE_ANTIBIOTIC]
for(var/datum/wound/W in wounds)
//Open wounds can become infected
if (owner.germ_level > W.germ_level && W.infection_check())
@@ -583,7 +646,9 @@ Note that amputating the affected organ does in fact remove the infection from t
if(germ_level < INFECTION_LEVEL_TWO)
return ..()
var/antibiotics = owner.reagents.get_reagent_amount("thetamycin")
var/antibiotics = 0
if(CE_ANTIBIOTIC in owner.chem_effects)
antibiotics = owner.chem_effects[CE_ANTIBIOTIC]
if(germ_level >= INFECTION_LEVEL_TWO)
//spread the infection to internal organs
@@ -706,6 +771,12 @@ Note that amputating the affected organ does in fact remove the infection from t
//Bone fractures
if(config.bones_can_break && brute_dam > min_broken_damage * config.organ_health_multiplier && !(status & ORGAN_ROBOT))
src.fracture()
update_damage_ratios()
/obj/item/organ/external/proc/update_damage_ratios()
var/limb_loss_threshold = max_damage
brute_ratio = brute_dam / (limb_loss_threshold * 2)
burn_ratio = burn_dam / (limb_loss_threshold * 2)
// new damage icon system
// adjusted to set damage_state to brute/burn code only (without r_name0 as before)
@@ -783,7 +854,8 @@ Note that amputating the affected organ does in fact remove the infection from t
var/mob/living/carbon/human/victim = owner //Keep a reference for post-removed().
var/obj/item/organ/external/parent_organ = parent
removed(null, ignore_children)
victim.traumatic_shock += 60
if(!clean)
victim.shock_stage += min_broken_damage
if(parent_organ)
var/datum/wound/lost_limb/W = new (src, disintegrate, clean)
@@ -993,14 +1065,15 @@ Note that amputating the affected organ does in fact remove the infection from t
T.robotize_advanced()
/obj/item/organ/external/proc/mutate()
if(src.status & ORGAN_ROBOT)
if(BP_IS_ROBOTIC(src))
return
src.status |= ORGAN_MUTATED
if(owner) owner.update_body()
/obj/item/organ/external/proc/unmutate()
src.status &= ~ORGAN_MUTATED
if(owner) owner.update_body()
if(!BP_IS_ROBOTIC(src))
src.status &= ~ORGAN_MUTATED
if(owner) owner.update_body()
/obj/item/organ/external/proc/get_damage() //returns total damage
return max(brute_dam + burn_dam - perma_injury, perma_injury) //could use max_damage?
@@ -1011,8 +1084,8 @@ Note that amputating the affected organ does in fact remove the infection from t
return 1
return 0
/obj/item/organ/external/proc/is_usable()
return !is_dislocated() && !(status & (ORGAN_MUTATED|ORGAN_DEAD)) && !(status & ORGAN_TENDON_CUT)
/obj/item/organ/external/is_usable()
return ..() && !is_dislocated() && !(status & ORGAN_TENDON_CUT) && (!can_feel_pain() || get_pain() < pain_disability_threshold) && brute_ratio < 1 && burn_ratio < 1
/obj/item/organ/external/proc/is_malfunctioning()
return ((status & ORGAN_ROBOT) && (brute_dam + burn_dam) >= 10 && prob(brute_dam + burn_dam))
@@ -1144,12 +1217,12 @@ Note that amputating the affected organ does in fact remove the infection from t
wound_descriptors[this_wound_desc] += W.amount
else
wound_descriptors[this_wound_desc] = W.amount
if(open > 1)
var/bone = encased ? encased : "bone"
if(status & ORGAN_BROKEN)
bone = "broken [bone]"
wound_descriptors["[bone] exposed"] = 1
wound_descriptors["a [bone] exposed"] = 1
if(!encased || open > 1)
var/list/bits = list()
@@ -1188,3 +1261,74 @@ Note that amputating the affected organ does in fact remove the infection from t
status |= ORGAN_TENDON_CUT
return TRUE
// Damage procs
/obj/item/organ/external/proc/get_brute_damage()
return brute_dam
/obj/item/organ/external/proc/get_burn_damage()
return burn_dam
/obj/item/organ/external/proc/get_genetic_damage()
return BP_IS_ROBOTIC(src) ? 0 : genetic_degradation
/obj/item/organ/external/proc/remove_genetic_damage(var/amount)
if(BP_IS_ROBOTIC(src) || (species.flags & NO_SCAN))
genetic_degradation = 0
status &= ~ORGAN_MUTATED
return
var/last_gene_dam = genetic_degradation
genetic_degradation = min(100,max(0,genetic_degradation - amount))
if(genetic_degradation <= 30)
if(status & ORGAN_MUTATED)
unmutate()
to_chat(src, "<span class = 'notice'>Your [name] is shaped normally again.</span>")
return -(genetic_degradation - last_gene_dam)
/obj/item/organ/external/proc/add_genetic_damage(var/amount)
if(BP_IS_ROBOTIC(src) || (species.flags & NO_SCAN))
genetic_degradation = 0
status &= ~ORGAN_MUTATED
return
var/last_gene_dam = genetic_degradation
genetic_degradation = min(100,max(0,genetic_degradation + amount))
if(genetic_degradation > 30)
if(!(status & ORGAN_MUTATED) && prob(genetic_degradation))
mutate()
to_chat(owner, "<span class = 'notice'>Something is not right with your [name]...</span>")
return (genetic_degradation - last_gene_dam)
// Pain/halloss
/obj/item/organ/external/proc/get_pain()
if(!can_feel_pain() || BP_IS_ROBOTIC(src))
return 0
var/lasting_pain = 0
if(is_broken())
lasting_pain += 10
else if(is_dislocated())
lasting_pain += 5
var/tox_dam = 0
for(var/obj/item/organ/internal/I in internal_organs)
tox_dam += I.getToxLoss()
return pain + lasting_pain + 0.7 * brute_dam + 0.8 * burn_dam + 0.3 * tox_dam + 0.5 * get_genetic_damage()
/obj/item/organ/external/proc/remove_pain(var/amount)
if(!can_feel_pain())
pain = 0
return
var/last_pain = pain
pain = max(0,min(max_damage,pain-amount))
return -(pain-last_pain)
/obj/item/organ/external/proc/add_pain(var/amount)
if(!can_feel_pain())
pain = 0
return
var/last_pain = pain
if(owner)
amount -= (owner.chem_effects[CE_PAINKILLER]/3)
if(amount <= 0)
return
pain = max(0,min(max_damage,pain+amount))
if(owner && ((amount > 15 && prob(20)) || (amount > 30 && prob(60))))
owner.emote("scream")
return pain-last_pain
+29 -23
View File
@@ -7,7 +7,7 @@ mob/var/next_pain_time = 0
// partname is the name of a body part
// amount is a num from 1 to 100
mob/living/carbon/proc/pain(var/partname, var/amount, var/force, var/burning = 0)
/mob/living/carbon/proc/pain(var/partname, var/amount, var/force, var/burning = 0)
if(stat >= 1)
return
if(!can_feel_pain())
@@ -41,35 +41,41 @@ mob/living/carbon/proc/pain(var/partname, var/amount, var/force, var/burning = 0
msg = "<b><font size=3>Your [partname] hurts badly!</font></b>"
if(91 to 10000)
flash_pain()
msg = "<b><font size=4>Your [partname] is screaming out in pain!</font></b>"
msg = "<b><font size=3>Your [partname] is screaming out in pain!</font></b>"
if(msg && (msg != last_pain_message || prob(10)))
last_pain_message = msg
to_chat(src, msg)
next_pain_time = world.time + (100 - amount)
next_pain_time = world.time + 50
// message is the custom message to be displayed
// flash_strength is 0 for weak pain flash, 1 for strong pain flash
mob/living/carbon/human/proc/custom_pain(var/message, var/flash_strength)
if(stat >= 1)
return
if(!can_feel_pain())
return
if(reagents.has_reagent("tramadol"))
return
if(reagents.has_reagent("oxycodone"))
return
if(analgesic)
return
var/msg = "<span class='danger'>[message]</span>"
if(flash_strength >= 1)
msg = "<span class='danger'><font size=3>[message]</font></span>"
// power decides how much painkillers will stop the message
// force means it ignores anti-spam timer
/mob/living/carbon/proc/custom_pain(var/message, var/power, var/force, var/obj/item/organ/external/affecting, var/nohalloss)
if(!message || stat || !can_feel_pain() || chem_effects[CE_PAINKILLER] > power)
return 0
power -= chem_effects[CE_PAINKILLER]/2 //Take the edge off.
// Excessive halloss is horrible, just give them enough to make it visible.
if(!nohalloss && power)
adjustHalLoss(Ceiling(power/2))
flash_pain(min(round(2*power)+55, 255))
// Anti message spam checks
if(msg && ((msg != last_pain_message) || (world.time >= next_pain_time)))
last_pain_message = msg
to_chat(src, msg)
next_pain_time = world.time + 100
if(force || (message != last_pain_message) || (world.time >= next_pain_time))
last_pain_message = message
if(power >= 70)
to_chat(src, "<span class='danger'><font size=3>[message]</font></span>")
else if(power >= 40)
to_chat(src, "<span class='danger'><font size=2>[message]</font></span>")
else if(power >= 10)
to_chat(src, "<span class='danger'>[message]</span>")
else
to_chat(src, "<span class='warning'>[message]</span>")
next_pain_time = world.time + (100-power)
mob/living/carbon/human/proc/handle_pain()
// not when sleeping
@@ -93,7 +99,7 @@ mob/living/carbon/human/proc/handle_pain()
pain(damaged_organ.name, maxdam, 0)
// Damage to internal organs hurts a lot.
for(var/obj/item/organ/I in internal_organs)
for(var/obj/item/organ/internal/I in internal_organs)
if(I.status & (ORGAN_DEAD|ORGAN_ROBOT))
continue
if(prob(2))
+1 -1
View File
@@ -231,7 +231,7 @@
owner.vessel.remove_reagent("blood",rand(15,30))
owner.reagents.add_reagent("paracetamol", 5)
owner.reagents.add_reagent("inaprovaline", 5)
owner.reagents.add_reagent("norepinephrine", 5)
/obj/item/organ/internal/haemodynamic
name = "haemodynamic control system"
+11 -11
View File
@@ -178,37 +178,37 @@
amputation_point = "branch"
vital = FALSE // Lore team requested this, not vital organ. We can still live without it.
/obj/item/organ/diona/process()
/obj/item/organ/internal/diona/process()
return
/obj/item/organ/diona/strata
/obj/item/organ/internal/diona/strata
name = "neural strata"
parent_organ = BP_CHEST
organ_tag = "neural strata"
/obj/item/organ/diona/bladder
/obj/item/organ/internal/diona/bladder
name = "gas bladder"
parent_organ = BP_HEAD
organ_tag = "gas bladder"
/obj/item/organ/diona/polyp
/obj/item/organ/internal/diona/polyp
name = "polyp segment"
parent_organ = BP_GROIN
organ_tag = "polyp segment"
/obj/item/organ/diona/ligament
/obj/item/organ/internal/diona/ligament
name = "anchoring ligament"
parent_organ = BP_GROIN
organ_tag = "anchoring ligament"
/obj/item/organ/diona
/obj/item/organ/internal/diona
name = "diona nymph"
icon = 'icons/obj/objects.dmi'
icon_state = "nymph"
organ_tag = "special" // Turns into a nymph instantly, no transplanting possible.
/obj/item/organ/diona/removed(var/mob/living/user)
/obj/item/organ/internal/diona/removed(var/mob/living/user)
var/mob/living/carbon/human/H = owner
..()
if(!istype(H) || !H.organs || !H.organs.len)
@@ -221,22 +221,22 @@
// These are different to the standard diona organs as they have a purpose in other
// species (absorbing radiation and light respectively)
/obj/item/organ/diona/nutrients
/obj/item/organ/internal/diona/nutrients
name = "nutrient channel"
parent_organ = BP_CHEST
organ_tag = "nutrient channel"
icon = 'icons/mob/npc/alien.dmi'
icon_state = "claw"
/obj/item/organ/diona/nutrients/removed()
/obj/item/organ/internal/diona/nutrients/removed()
return
/obj/item/organ/diona/node
/obj/item/organ/internal/diona/node
name = "response node"
parent_organ = BP_HEAD
organ_tag = "response node"
icon = 'icons/mob/npc/alien.dmi'
icon_state = "claw"
/obj/item/organ/diona/node/removed()
/obj/item/organ/internal/diona/node/removed()
return
+12 -12
View File
@@ -57,7 +57,7 @@
encased = "support frame"
robotize_type = PROSTHETIC_IPC
/obj/item/organ/cell
/obj/item/organ/internal/cell
name = "microbattery"
desc = "A small, powerful cell for use in fully prosthetic bodies."
icon = 'icons/obj/power.dmi'
@@ -67,23 +67,23 @@
vital = 1
var/emp_counter = 0
/obj/item/organ/cell/Initialize()
/obj/item/organ/internal/cell/Initialize()
robotize()
. = ..()
/obj/item/organ/cell/process()
/obj/item/organ/internal/cell/process()
..()
if(emp_counter)
emp_counter--
/obj/item/organ/cell/emp_act(severity)
/obj/item/organ/internal/cell/emp_act(severity)
emp_counter += 30/severity
if(emp_counter >= 30)
owner.Paralyse(emp_counter/6)
to_chat(owner, "<span class='danger'>%#/ERR: Power leak detected!$%^/</span>")
/obj/item/organ/surge
/obj/item/organ/internal/surge
name = "surge preventor"
desc = "A small device that give immunity to EMP for few pulses."
icon = 'icons/obj/robot_component.dmi'
@@ -94,19 +94,19 @@
var/surge_left = 0
var/broken = 0
/obj/item/organ/surge/Initialize()
/obj/item/organ/internal/surge/Initialize()
if(!surge_left && !broken)
surge_left = rand(2, 5)
robotize()
. = ..()
/obj/item/organ/surge/advanced
/obj/item/organ/internal/surge/advanced
name = "advanced surge preventor"
var/max_charges = 5
var/stage_ticker = 0
var/stage_interval = 250
/obj/item/organ/surge/advanced/process()
/obj/item/organ/internal/surge/advanced/process()
..()
if(!owner)
@@ -203,7 +203,7 @@
vital = 1
emp_coeff = 0.1
/obj/item/organ/data
/obj/item/organ/internal/data
name = "data core"
organ_tag = "data core"
parent_organ = BP_GROIN
@@ -212,11 +212,11 @@
vital = 0
emp_coeff = 0.1
/obj/item/organ/data/Initialize()
/obj/item/organ/internal/data/Initialize()
robotize()
. = ..()
/obj/item/organ/cell/terminator
/obj/item/organ/internal/cell/terminator
name = "shielded microbattery"
desc = "A small, powerful cell for use in fully prosthetic bodies. Equipped with a Faraday shield."
icon = 'icons/obj/power.dmi'
@@ -226,7 +226,7 @@
vital = 1
emp_coeff = 0.1
/obj/item/organ/cell/Initialize()
/obj/item/organ/internal/cell/Initialize()
robotize()
. = ..()
+2 -2
View File
@@ -184,8 +184,8 @@
owner.update_hair()
..()
/obj/item/organ/external/head/take_damage(brute, burn, sharp, edge, used_weapon = null, list/forbidden_limbs = list())
..(brute, burn, sharp, edge, used_weapon, forbidden_limbs)
/obj/item/organ/external/head/take_damage(brute, burn, sharp, edge, used_weapon = null, list/forbidden_limbs = list(), damage_flags)
..(brute, burn, sharp, edge, used_weapon, forbidden_limbs, damage_flags)
if (!disfigured)
if (brute_dam > 40)
if (prob(50))
+6 -12
View File
@@ -1,16 +1,10 @@
/obj/item/organ/internal/heart/left
name = "heart"
icon_state = "vaurca_heart_l-on"
organ_tag = "left heart"
/obj/item/organ/internal/heart/vaurca
name = "double heart system"
icon_state = "vaurca_heart_d-on"
organ_tag = BP_HEART
parent_organ = BP_CHEST
dead_icon = "vaurca_heart_l-off"
/obj/item/organ/internal/heart/right
name = "heart"
icon_state = "vaurca_heart_r-on"
organ_tag = "right heart"
parent_organ = BP_CHEST
dead_icon = "vaurca_heart_r-off"
dead_icon = "vaurca_heart_d-off"
max_damage = 90 //two hearts = stronger hearts
/obj/item/organ/internal/lungs/vaurca
icon_state = "lungs_vaurca"