mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-11 10:43:20 +00:00
Moved organ and blood code to module folder.
Moved most organ and blood procs to that folder. Refactored handle_organs a little. Added comments in some places.
This commit is contained in:
148
code/modules/organs/blood.dm
Normal file
148
code/modules/organs/blood.dm
Normal file
@@ -0,0 +1,148 @@
|
||||
//Blood levels
|
||||
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.
|
||||
/mob/living/carbon/human/var/var/pale = 0 //Should affect how mob sprite is drawn, but currently doesn't.
|
||||
|
||||
//Initializes blood vessels
|
||||
/mob/living/carbon/human/proc/make_blood()
|
||||
if (vessel)
|
||||
return
|
||||
vessel = new/datum/reagents(600)
|
||||
vessel.my_atom = src
|
||||
vessel.add_reagent("blood",560)
|
||||
spawn(1)
|
||||
fixblood()
|
||||
|
||||
//Resets blood data
|
||||
/mob/living/carbon/human/proc/fixblood()
|
||||
for(var/datum/reagent/blood/B in vessel.reagent_list)
|
||||
if(B.id == "blood")
|
||||
B.data = list( "donor"=src,"viruses"=null,"blood_DNA"=dna.unique_enzymes,"blood_type"=dna.b_type, \
|
||||
"resistances"=null,"trace_chem"=null, "virus2" = null, "antobodies" = null)
|
||||
|
||||
//Makes a blood drop, leaking certain amount of blood from the mob
|
||||
/mob/living/carbon/human/proc/drip(var/amt as num)
|
||||
if(!amt)
|
||||
return
|
||||
|
||||
var/amm = 0.1 * amt
|
||||
var/turf/T = get_turf(src)
|
||||
var/list/obj/effect/decal/cleanable/blood/drip/nums = list()
|
||||
var/list/iconL = list("1","2","3","4","5")
|
||||
|
||||
vessel.remove_reagent("blood",amm)
|
||||
|
||||
for(var/obj/effect/decal/cleanable/blood/drip/G in T)
|
||||
nums += G
|
||||
iconL.Remove(G.icon_state)
|
||||
|
||||
if (nums.len < 5)
|
||||
var/obj/effect/decal/cleanable/blood/drip/this = new(T)
|
||||
this.icon_state = pick(iconL)
|
||||
this.blood_DNA = list()
|
||||
this.blood_DNA[dna.unique_enzymes] = dna.b_type
|
||||
else
|
||||
for(var/obj/effect/decal/cleanable/blood/drip/G in nums)
|
||||
del G
|
||||
T.add_blood(src)
|
||||
|
||||
// Takes care blood loss and regeneration
|
||||
/mob/living/carbon/human/proc/handle_blood()
|
||||
if(stat != DEAD && bodytemperature >= 170) //Dead or cryosleep people do not pump the blood.
|
||||
|
||||
var/blood_volume = round(vessel.get_reagent_amount("blood"))
|
||||
|
||||
//Blood regeneration if there is some space
|
||||
if(blood_volume < 560 && blood_volume)
|
||||
var/datum/reagent/blood/B = locate() in vessel.reagent_list //Grab some blood
|
||||
if(B) // Make sure there's some blood at all
|
||||
if(B.data["donor"] != src) //If it's not theirs, then we look for theirs
|
||||
for(var/datum/reagent/blood/D in vessel.reagent_list)
|
||||
if(D.data["donor"] == src)
|
||||
B = D
|
||||
break
|
||||
|
||||
B.volume += + 0.1 // regenerate blood VERY slowly
|
||||
if (reagents.reagent_list.has_reagent("nutriment")) //Getting food speeds it up
|
||||
B.volume += 0.4
|
||||
reagents.reagent_list.remove_reagent("nutriment", 0.1)
|
||||
if (reagents.reagent_list.has_reagent("iron")) //Hematogen candy anyone?
|
||||
B.volume += 0.8
|
||||
reagents.reagent_list.remove_reagent("iron", 0.1)
|
||||
|
||||
// Damaged heart virtually reduces the blood volume, as the blood isn't
|
||||
// being pumped properly anymore.
|
||||
var/datum/organ/internal/heart/heart = internal_organs["heart"]
|
||||
switch(heart.damage)
|
||||
if(5 to 10)
|
||||
blood_volume *= 0.8
|
||||
if(11 to 20)
|
||||
blood_volume *= 0.5
|
||||
if(21 to INFINITY)
|
||||
blood_volume *= 0.3
|
||||
|
||||
//Effects of bloodloss
|
||||
switch(blood_volume)
|
||||
if(BLOOD_VOLUME_SAFE to 10000)
|
||||
if(pale)
|
||||
pale = 0
|
||||
update_body()
|
||||
if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE)
|
||||
if(!pale)
|
||||
pale = 1
|
||||
update_body()
|
||||
var/word = pick("dizzy","woosey","faint")
|
||||
src << "\red You feel [word]"
|
||||
if(prob(1))
|
||||
var/word = pick("dizzy","woosey","faint")
|
||||
src << "\red You feel [word]"
|
||||
if(oxyloss < 20)
|
||||
oxyloss += 3
|
||||
if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY)
|
||||
if(!pale)
|
||||
pale = 1
|
||||
update_body()
|
||||
eye_blurry += 6
|
||||
if(oxyloss < 50)
|
||||
oxyloss += 10
|
||||
oxyloss += 1
|
||||
if(prob(15))
|
||||
Paralyse(rand(1,3))
|
||||
var/word = pick("dizzy","woosey","faint")
|
||||
src << "\red You feel extremely [word]"
|
||||
if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD)
|
||||
oxyloss += 5
|
||||
toxloss += 5
|
||||
if(prob(15))
|
||||
var/word = pick("dizzy","woosey","faint")
|
||||
src << "\red You feel extremely [word]"
|
||||
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.
|
||||
toxloss += 300 // just to be safe!
|
||||
death()
|
||||
|
||||
// Without enough blood you slowly go hungry.
|
||||
if(blood_volume < BLOOD_VOLUME_SAFE)
|
||||
if(nutrition >= 300)
|
||||
nutrition -= 10
|
||||
else if(nutrition >= 200)
|
||||
nutrition -= 3
|
||||
|
||||
//Bleeding out
|
||||
var/blood_max = 0
|
||||
for(var/datum/organ/external/temp in organs)
|
||||
if(!(temp.status & ORGAN_BLEEDING) || temp.status & ORGAN_ROBOT)
|
||||
continue
|
||||
for(var/datum/wound/W in temp.wounds) if(W.bleeding())
|
||||
blood_max += W.damage / 4
|
||||
if(temp.status & ORGAN_DESTROYED && !(temp.status & ORGAN_GAUZED) && !temp.amputated)
|
||||
blood_max += 20 //Yer missing a fucking limb.
|
||||
if (temp.open)
|
||||
blood_max += 2 //Yer stomach is cut open
|
||||
drip(blood_max)
|
||||
150
code/modules/organs/organ.dm
Normal file
150
code/modules/organs/organ.dm
Normal file
@@ -0,0 +1,150 @@
|
||||
/datum/organ
|
||||
var/name = "organ"
|
||||
var/mob/living/carbon/human/owner = null
|
||||
|
||||
var/list/datum/autopsy_data/autopsy_data = list()
|
||||
var/list/trace_chemicals = list() // traces of chemicals in the organ,
|
||||
// links chemical IDs to number of ticks for which they'll stay in the blood
|
||||
proc/process()
|
||||
return 0
|
||||
|
||||
proc/receive_chem(chemical as obj)
|
||||
return 0
|
||||
|
||||
//Handles chem traces
|
||||
/mob/living/carbon/human/proc/handle_trace_chems()
|
||||
//New are added for reagents to random organs.
|
||||
for(var/datum/reagent/A in reagents.reagent_list)
|
||||
var/datum/organ/O = pick(organs)
|
||||
O.trace_chemicals[A.name] = 100
|
||||
|
||||
//Adds autopsy data for used_weapon.
|
||||
/datum/organ/proc/add_autopsy_data(var/used_weapon, var/damage)
|
||||
var/datum/autopsy_data/W = autopsy_data[used_weapon]
|
||||
if(!W)
|
||||
W = new()
|
||||
W.weapon = used_weapon
|
||||
autopsy_data[used_weapon] = W
|
||||
|
||||
W.hits += 1
|
||||
W.damage += damage
|
||||
W.time_inflicted = world.time
|
||||
|
||||
/mob/living/carbon/human/var/list/organs = list()
|
||||
/mob/living/carbon/human/var/list/organs_by_name = list() // map organ names to organs
|
||||
|
||||
//Creates and initializes and connects external and internal organs
|
||||
/mob/living/carbon/human/proc/make_organs()
|
||||
if (organs)
|
||||
return
|
||||
organs = list()
|
||||
organs_by_name["chest"] = new/datum/organ/external/chest()
|
||||
organs_by_name["groin"] = new/datum/organ/external/groin(organs_by_name["chest"])
|
||||
organs_by_name["head"] = new/datum/organ/external/head(organs_by_name["chest"])
|
||||
organs_by_name["l_arm"] = new/datum/organ/external/l_arm(organs_by_name["chest"])
|
||||
organs_by_name["r_arm"] = new/datum/organ/external/r_arm(organs_by_name["chest"])
|
||||
organs_by_name["r_leg"] = new/datum/organ/external/r_leg(organs_by_name["groin"])
|
||||
organs_by_name["l_leg"] = new/datum/organ/external/l_leg(organs_by_name["groin"])
|
||||
organs_by_name["l_hand"] = new/datum/organ/external/l_hand(organs_by_name["l_arm"])
|
||||
organs_by_name["r_hand"] = new/datum/organ/external/r_hand(organs_by_name["r_arm"])
|
||||
organs_by_name["l_foot"] = new/datum/organ/external/l_foot(organs_by_name["l_leg"])
|
||||
organs_by_name["r_foot"] = new/datum/organ/external/r_foot(organs_by_name["r_leg"])
|
||||
|
||||
new/datum/organ/internal/heart(src)
|
||||
new/datum/organ/internal/lungs(src)
|
||||
new/datum/organ/internal/liver(src)
|
||||
new/datum/organ/internal/kidney(src)
|
||||
new/datum/organ/internal/brain(src)
|
||||
|
||||
for(var/name in organs_by_name)
|
||||
organs += organs_by_name[name]
|
||||
|
||||
for(var/datum/organ/external/O in organs)
|
||||
O.owner = src
|
||||
|
||||
// Takes care of organ related updates, such as broken and missing limbs
|
||||
/mob/living/carbon/human/proc/handle_organs()
|
||||
number_wounds = 0
|
||||
var/leg_tally = 2
|
||||
for(var/datum/organ/external/E in organs)
|
||||
if(!E)
|
||||
continue
|
||||
E.process()
|
||||
number_wounds += E.number_wounds
|
||||
|
||||
//Robotic limb malfunctions
|
||||
var/malfunction = 0
|
||||
if (E.status & ORGAN_ROBOT && prob(E.brute_dam + E.burn_dam))
|
||||
malfunction = 1
|
||||
|
||||
//Broken limbs hurt too
|
||||
var/broken = 0
|
||||
if(E.status & ORGAN_BROKEN && !(E.status & ORGAN_SPLINTED && prob(10)) )
|
||||
broken = 1
|
||||
|
||||
//Special effects for limbs.
|
||||
if(E.name in list("l_hand","l_arm","r_hand","r_arm"))
|
||||
var/obj/item/c_hand //Getting what's in this hand
|
||||
if(E.name == "l_hand" || E.name == "l_arm")
|
||||
c_hand = l_hand
|
||||
if(E.name == "r_hand" || E.name == "r_arm")
|
||||
c_hand = r_hand
|
||||
|
||||
if (c_hand)
|
||||
if (broken||malfunction)
|
||||
u_equip(c_hand)
|
||||
|
||||
if(broken)
|
||||
emote("me", 1, "screams in pain and drops what they were holding in their [E.display_name?"[E.display_name]":"[E]"]!")
|
||||
if(malfunction)
|
||||
emote("me", 1, "drops what they were holding, their [E.display_name?"[E.display_name]":"[E]"] malfunctioning!")
|
||||
var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread()
|
||||
spark_system.set_up(5, 0, src)
|
||||
spark_system.attach(src)
|
||||
spark_system.start()
|
||||
spawn(10)
|
||||
del(spark_system)
|
||||
|
||||
else if(E.name in list("l_leg","l_foot","r_leg","r_foot") && !lying)
|
||||
if (E.status & ORGAN_DESTROYED || malfunction || (broken && !(E.status & ORGAN_SPLINTED)))
|
||||
leg_tally-- // let it fail even if just foot&leg
|
||||
|
||||
// standing is poor
|
||||
if(leg_tally <= 0 && !paralysis && !(lying || resting) && prob(5))
|
||||
emote("scream")
|
||||
emote("collapse")
|
||||
paralysis = 10
|
||||
|
||||
//Check arms and legs for existence
|
||||
var/canstand_l = 1 //Can stand on left leg
|
||||
var/canstand_r = 1 //Can stand on right leg
|
||||
var/hasleg_l = 1 //Have left leg
|
||||
var/hasleg_r = 1 //Have right leg
|
||||
var/hasarm_l = 1 //Have left arm
|
||||
var/hasarm_r = 1 //Have right arm
|
||||
var/datum/organ/external/E
|
||||
E = get_organ("l_leg")
|
||||
if(E.status & ORGAN_DESTROYED && !(E.status & ORGAN_SPLINTED))
|
||||
canstand_l = 0
|
||||
hasleg_l = 0
|
||||
E = get_organ("r_leg")
|
||||
if(E.status & ORGAN_DESTROYED && !(E.status & ORGAN_SPLINTED))
|
||||
canstand_r = 0
|
||||
hasleg_r = 0
|
||||
E = get_organ("l_foot")
|
||||
if(E.status & ORGAN_DESTROYED && !(E.status & ORGAN_SPLINTED))
|
||||
canstand_l = 0
|
||||
E = get_organ("r_foot")
|
||||
if(E.status & ORGAN_DESTROYED && !(E.status & ORGAN_SPLINTED))
|
||||
canstand_r = 0
|
||||
E = get_organ("l_arm")
|
||||
if(E.status & ORGAN_DESTROYED && !(E.status & ORGAN_SPLINTED))
|
||||
hasarm_l = 0
|
||||
E = get_organ("r_arm")
|
||||
if(E.status & ORGAN_DESTROYED && !(E.status & ORGAN_SPLINTED))
|
||||
hasarm_r = 0
|
||||
|
||||
// Can stand if have at least one full leg (with leg and foot parts present)
|
||||
// Has limbs to move around if at least one arm or leg is at least partially there
|
||||
can_stand = canstand_l||canstand_r
|
||||
has_limbs = hasleg_l||hasleg_r||hasarm_l||hasarm_r
|
||||
831
code/modules/organs/organ_external.dm
Normal file
831
code/modules/organs/organ_external.dm
Normal file
@@ -0,0 +1,831 @@
|
||||
/****************************************************
|
||||
EXTERNAL ORGANS
|
||||
****************************************************/
|
||||
/datum/organ/external
|
||||
name = "external"
|
||||
var/icon_name = null
|
||||
var/body_part = null
|
||||
var/icon_position = 0
|
||||
|
||||
var/damage_state = "00"
|
||||
var/brute_dam = 0
|
||||
var/burn_dam = 0
|
||||
var/max_damage = 0
|
||||
var/max_size = 0
|
||||
|
||||
var/display_name
|
||||
var/list/wounds = list()
|
||||
var/number_wounds = 0 // cache the number of wounds, which is NOT wounds.len!
|
||||
|
||||
var/tmp/perma_injury = 0
|
||||
var/tmp/destspawn = 0 //Has it spawned the broken limb?
|
||||
var/tmp/amputated = 0 //Whether this has been cleanly amputated, thus causing no pain
|
||||
var/min_broken_damage = 30
|
||||
|
||||
var/datum/organ/external/parent
|
||||
var/list/datum/organ/external/children
|
||||
|
||||
// Internal organs of this body part
|
||||
var/list/datum/organ/internal/internal_organs
|
||||
|
||||
var/damage_msg = "\red You feel an intense pain"
|
||||
var/broken_description
|
||||
|
||||
var/status = 0
|
||||
var/open = 0
|
||||
var/stage = 0
|
||||
var/cavity = 0
|
||||
|
||||
var/obj/item/hidden = null
|
||||
var/list/implants = list()
|
||||
// INTERNAL germs inside the organ, this is BAD if it's greater 0
|
||||
var/germ_level = 0
|
||||
|
||||
// how often wounds should be updated, a higher number means less often
|
||||
var/wound_update_accuracy = 20 // update every 20 ticks(roughly every minute)
|
||||
|
||||
/datum/organ/external/New(var/datum/organ/external/P)
|
||||
if(P)
|
||||
parent = P
|
||||
if(!parent.children)
|
||||
parent.children = list()
|
||||
parent.children.Add(src)
|
||||
return ..()
|
||||
|
||||
/****************************************************
|
||||
DAMAGE PROCS
|
||||
****************************************************/
|
||||
|
||||
/datum/organ/external/proc/emp_act(severity)
|
||||
if(!(status & ORGAN_ROBOT)) //meatbags do not care about EMP
|
||||
return
|
||||
var/probability = 30
|
||||
var/damage = 15
|
||||
if(severity == 2)
|
||||
probability = 1
|
||||
damage = 3
|
||||
if(prob(probability))
|
||||
droplimb(1)
|
||||
else
|
||||
take_damage(damage, 0, 1, used_weapon = "EMP")
|
||||
|
||||
/datum/organ/external/proc/take_damage(brute, burn, sharp, used_weapon = null, list/forbidden_limbs = list())
|
||||
if((brute <= 0) && (burn <= 0))
|
||||
return 0
|
||||
|
||||
if(status & ORGAN_DESTROYED)
|
||||
return 0
|
||||
if(status & ORGAN_ROBOT)
|
||||
brute *= 0.66 //~2/3 damage for ROBOLIMBS
|
||||
burn *= 0.66 //~2/3 damage for ROBOLIMBS
|
||||
|
||||
//If limb took enough damage, try to cut or tear it off
|
||||
if(config.limbs_can_break && brute_dam >= max_damage * config.organ_health_multiplier)
|
||||
if( (sharp && prob(5 * brute)) || (brute > 20 && prob(2 * brute)) )
|
||||
droplimb(1)
|
||||
return
|
||||
|
||||
// High brute damage or sharp objects may damage internal organs
|
||||
if(internal_organs != null) if( (sharp && brute >= 5) || brute >= 10) if(prob(5))
|
||||
// Damage an internal organ
|
||||
var/datum/organ/internal/I = pick(internal_organs)
|
||||
I.take_damage(brute / 2)
|
||||
brute -= brute / 2
|
||||
|
||||
if(status & ORGAN_BROKEN && prob(40) && brute)
|
||||
owner.emote("scream") //getting hit on broken hand hurts
|
||||
if(used_weapon)
|
||||
add_autopsy_data(used_weapon, brute + burn)
|
||||
|
||||
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
|
||||
if((brute_dam + burn_dam + brute + burn) < max_damage || !config.limbs_can_break)
|
||||
if(brute)
|
||||
if(can_cut)
|
||||
createwound( CUT, brute )
|
||||
else
|
||||
createwound( BRUISE, brute )
|
||||
if(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)
|
||||
if(can_inflict)
|
||||
if (brute > 0)
|
||||
//Inflict all burte damage we can
|
||||
if(can_cut)
|
||||
createwound( CUT, min(brute,can_inflict) )
|
||||
else
|
||||
createwound( BRUISE, min(brute,can_inflict) )
|
||||
var/temp = can_inflict
|
||||
//How much mroe damage can we inflict
|
||||
can_inflict = max(0, can_inflict - brute)
|
||||
//How much brute damage is left to inflict
|
||||
brute = max(0, brute - temp)
|
||||
|
||||
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
|
||||
burn = max(0, burn - can_inflict)
|
||||
//If there are still hurties to dispense
|
||||
if (burn || brute)
|
||||
if (status & ORGAN_ROBOT)
|
||||
droplimb(1) //Robot limbs just kinda fail at full damage.
|
||||
else
|
||||
//List organs we can pass it to
|
||||
var/list/datum/organ/external/possible_points = list()
|
||||
if(parent)
|
||||
possible_points += parent
|
||||
if(children)
|
||||
possible_points += children
|
||||
if(forbidden_limbs.len)
|
||||
possible_points -= forbidden_limbs
|
||||
if(possible_points.len)
|
||||
//And pass the pain around
|
||||
var/datum/organ/external/target = pick(possible_points)
|
||||
target.take_damage(brute, burn, sharp, used_weapon, forbidden_limbs + src)
|
||||
|
||||
// sync the organ's damage with its wounds
|
||||
src.update_damages()
|
||||
owner.updatehealth()
|
||||
|
||||
var/result = update_icon()
|
||||
return result
|
||||
|
||||
/datum/organ/external/proc/heal_damage(brute, burn, internal = 0, robo_repair = 0)
|
||||
if(status & ORGAN_ROBOT && !robo_repair)
|
||||
return
|
||||
|
||||
//Heal damage on the individual wounds
|
||||
for(var/datum/wound/W in wounds)
|
||||
if(brute == 0 && burn == 0)
|
||||
break
|
||||
|
||||
// heal brute damage
|
||||
if(W.damage_type == CUT || W.damage_type == BRUISE)
|
||||
brute = W.heal_damage(brute)
|
||||
else if(W.damage_type == BURN)
|
||||
burn = W.heal_damage(burn)
|
||||
|
||||
if(internal)
|
||||
status &= ~ORGAN_BROKEN
|
||||
perma_injury = 0
|
||||
|
||||
//Sync the organ's damage with its wounds
|
||||
src.update_damages()
|
||||
owner.updatehealth()
|
||||
|
||||
var/result = update_icon()
|
||||
return result
|
||||
|
||||
|
||||
/datum/organ/external/proc/createwound(var/type = CUT, var/damage)
|
||||
if(damage == 0) return
|
||||
|
||||
// first check whether we can widen an existing wound
|
||||
if(wounds.len > 0 && prob(max(50+owner.number_wounds*10,100)))
|
||||
if((type == CUT || type == BRUISE) && damage >= 5)
|
||||
var/datum/wound/W = pick(wounds)
|
||||
if(W.amount == 1 && W.started_healing())
|
||||
W.open_wound(damage)
|
||||
if(prob(25))
|
||||
owner.visible_message("\red The wound on [owner.name]'s [display_name] widens with a nasty ripping voice.",\
|
||||
"\red The wound on your [display_name] widens with a nasty ripping voice.",\
|
||||
"You hear a nasty ripping noise, as if flesh is being torn apart.")
|
||||
return
|
||||
|
||||
//Creating wound
|
||||
var/datum/wound/W
|
||||
var/size = min( max( 1, damage/10 ) , 6)
|
||||
//Possible types of wound
|
||||
var/list/size_names = list()
|
||||
switch(type)
|
||||
if(CUT)
|
||||
size_names = typesof(/datum/wound/cut/) - /datum/wound/cut/
|
||||
if(BRUISE)
|
||||
size_names = typesof(/datum/wound/bruise/) - /datum/wound/bruise/
|
||||
if(BURN)
|
||||
size_names = typesof(/datum/wound/burn/) - /datum/wound/burn/
|
||||
|
||||
size = min(size,size_names.len)
|
||||
var/wound_type = size_names[size]
|
||||
W = new wound_type(damage)
|
||||
|
||||
//Possibly trigger an internal wound, too.
|
||||
var/local_damage = brute_dam + burn_dam + damage
|
||||
if(damage > 10 && type != BURN && local_damage > 20 && prob(damage) && !(status & ORGAN_ROBOT))
|
||||
var/datum/wound/internal_bleeding/I = new (15)
|
||||
wounds += I
|
||||
owner.custom_pain("You feel something rip in your [display_name]!", 1)
|
||||
|
||||
//Check whether we can add the wound to an existing wound
|
||||
for(var/datum/wound/other in wounds)
|
||||
if(other.desc == W.desc)
|
||||
// okay, add it!
|
||||
other.damage += W.damage
|
||||
other.amount += 1
|
||||
W = null // to signify that the wound was added
|
||||
break
|
||||
if(W)
|
||||
wounds += W
|
||||
|
||||
/****************************************************
|
||||
PROCESSING & UPDATING
|
||||
****************************************************/
|
||||
|
||||
/datum/organ/external/process()
|
||||
// Process wounds, doing healing etc. Only do this every few ticks to save processing power
|
||||
if(owner.life_tick % wound_update_accuracy == 0)
|
||||
update_wounds()
|
||||
|
||||
//Chem traces slowly vanish
|
||||
if(owner.life_tick % 10 == 0)
|
||||
for(var/chemID in trace_chemicals)
|
||||
trace_chemicals[chemID] = trace_chemicals[chemID] - 1
|
||||
if(trace_chemicals[chemID] <= 0)
|
||||
trace_chemicals.Remove(chemID)
|
||||
|
||||
//Dismemberment
|
||||
if(status & ORGAN_DESTROYED)
|
||||
if(!destspawn && config.limbs_can_break)
|
||||
droplimb()
|
||||
return
|
||||
if(parent)
|
||||
if(parent.status & ORGAN_DESTROYED)
|
||||
status |= ORGAN_DESTROYED
|
||||
owner.update_body(1)
|
||||
return
|
||||
|
||||
//Bone fracurtes
|
||||
if(config.bones_can_break && brute_dam > min_broken_damage * config.organ_health_multiplier && !(status & ORGAN_ROBOT))
|
||||
src.fracture()
|
||||
if(!(status & ORGAN_BROKEN))
|
||||
perma_injury = 0
|
||||
|
||||
update_germs()
|
||||
update_icon()
|
||||
return
|
||||
|
||||
//Updating germ levels. Handles organ germ levels and necrosis.
|
||||
#define GANGREN_LEVEL_ONE 100
|
||||
#define GANGREN_LEVEL_TWO 1000
|
||||
#define GANGREN_LEVEL_TERMINAL 2500
|
||||
#define GERM_TRANSFER_AMOUNT germ_level/500
|
||||
/datum/organ/external/proc/update_germs()
|
||||
if(germ_level > 0 && owner.bodytemperature >= 170) //cryo stops germs from moving and doing their bad stuffs
|
||||
//Syncing germ levels with external wounds
|
||||
for(var/datum/wound/W in wounds)
|
||||
if(!W.bandaged && !W.salved)
|
||||
W.germ_level = max(W.germ_level, germ_level) //Wounds get all the germs
|
||||
if (W.germ_level > germ_level) //Badly infected wounds raise internal germ levels
|
||||
germ_level++
|
||||
|
||||
if(germ_level > GANGREN_LEVEL_ONE && prob(round(germ_level/100)))
|
||||
germ_level++
|
||||
owner.adjustToxLoss(1)
|
||||
|
||||
if(germ_level > GANGREN_LEVEL_TWO)
|
||||
germ_level++
|
||||
owner.adjustToxLoss(1)
|
||||
/*
|
||||
if(germ_level > GANGREN_LEVEL_TERMINAL)
|
||||
if (!(status & ORGAN_DEAD))
|
||||
status |= ORGAN_DEAD
|
||||
owner << "<span class='notice'>You can't feel your [display_name] anymore...</span>"
|
||||
owner.update_body(1)
|
||||
if (prob(10)) //Spreading the fun
|
||||
if (children) //To child organs
|
||||
for (var/datum/organ/external/child in children)
|
||||
if (!(child.status & (ORGAN_DEAD|ORGAN_DESTROYED|ORGAN_ROBOT)))
|
||||
child.germ_level += round(GERM_TRANSFER_AMOUNT)
|
||||
if (parent)
|
||||
if (!(parent.status & (ORGAN_DEAD|ORGAN_DESTROYED|ORGAN_ROBOT)))
|
||||
parent.germ_level += round(GERM_TRANSFER_AMOUNT)
|
||||
*/
|
||||
|
||||
//Updating wounds. Handles wound natural healing, internal bleedings and infections
|
||||
/datum/organ/external/proc/update_wounds()
|
||||
for(var/datum/wound/W in wounds)
|
||||
// wounds can disappear after 10 minutes at the earliest
|
||||
if(W.damage == 0 && W.created + 10 * 10 * 60 <= world.time)
|
||||
wounds -= W
|
||||
// let the GC handle the deletion of the wound
|
||||
|
||||
// Internal wounds get worse over time. Low temperatures (cryo) stop them.
|
||||
if(W.internal && !W.is_treated() && owner.bodytemperature >= 170)
|
||||
W.open_wound(0.1 * wound_update_accuracy)
|
||||
owner.vessel.remove_reagent("blood",0.07 * W.damage * wound_update_accuracy)
|
||||
if(prob(1 * wound_update_accuracy))
|
||||
owner.custom_pain("You feel a stabbing pain in your [display_name]!",1)
|
||||
|
||||
if(W.bandaged || W.salved)
|
||||
// slow healing
|
||||
var/amount = 0.2
|
||||
if(W.is_treated())
|
||||
amount += 10
|
||||
// amount of healing is spread over all the wounds
|
||||
W.heal_damage((wound_update_accuracy * amount * W.amount * config.organ_regeneration_multiplier) / (20*owner.number_wounds+1))
|
||||
|
||||
// Salving also helps against infection
|
||||
if(W.germ_level > 0 && W.salved && prob(2))
|
||||
W.germ_level = 0
|
||||
W.disinfected = 1
|
||||
|
||||
|
||||
|
||||
// sync the organ's damage with its wounds
|
||||
src.update_damages()
|
||||
|
||||
//Updates brute_damn and burn_damn from wound damages. Updates BLEEDING status.
|
||||
/datum/organ/external/proc/update_damages()
|
||||
number_wounds = 0
|
||||
brute_dam = 0
|
||||
burn_dam = 0
|
||||
status &= ~ORGAN_BLEEDING
|
||||
var/clamped = 0
|
||||
for(var/datum/wound/W in wounds)
|
||||
if(W.damage_type == CUT || W.damage_type == BRUISE)
|
||||
brute_dam += W.damage
|
||||
else if(W.damage_type == BURN)
|
||||
burn_dam += W.damage
|
||||
|
||||
if(!(status & ORGAN_ROBOT) && W.bleeding())
|
||||
status |= ORGAN_BLEEDING
|
||||
|
||||
clamped |= W.clamped
|
||||
|
||||
number_wounds += W.amount
|
||||
|
||||
if (open && !clamped) //things tend to bleed if they are CUT OPEN
|
||||
status |= ORGAN_BLEEDING
|
||||
|
||||
|
||||
// new damage icon system
|
||||
// adjusted to set damage_state to brute/burn code only (without r_name0 as before)
|
||||
/datum/organ/external/proc/update_icon()
|
||||
var/n_is = damage_state_text()
|
||||
if (n_is != damage_state)
|
||||
damage_state = n_is
|
||||
owner.update_body(1)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
// new damage icon system
|
||||
// returns just the brute/burn damage code
|
||||
/datum/organ/external/proc/damage_state_text()
|
||||
if(status & ORGAN_DESTROYED)
|
||||
return "--"
|
||||
|
||||
var/tburn = 0
|
||||
var/tbrute = 0
|
||||
|
||||
if(burn_dam ==0)
|
||||
tburn =0
|
||||
else if (burn_dam < (max_damage * 0.25 / 2))
|
||||
tburn = 1
|
||||
else if (burn_dam < (max_damage * 0.75 / 2))
|
||||
tburn = 2
|
||||
else
|
||||
tburn = 3
|
||||
|
||||
if (brute_dam == 0)
|
||||
tbrute = 0
|
||||
else if (brute_dam < (max_damage * 0.25 / 2))
|
||||
tbrute = 1
|
||||
else if (brute_dam < (max_damage * 0.75 / 2))
|
||||
tbrute = 2
|
||||
else
|
||||
tbrute = 3
|
||||
return "[tbrute][tburn]"
|
||||
|
||||
/****************************************************
|
||||
DISMEMBERMENT
|
||||
****************************************************/
|
||||
|
||||
//Recursive setting of all child organs to amputated
|
||||
/datum/organ/external/proc/setAmputatedTree()
|
||||
for(var/datum/organ/external/O in children)
|
||||
O.amputated=amputated
|
||||
O.setAmputatedTree()
|
||||
|
||||
//Handles dismemberment
|
||||
/datum/organ/external/proc/droplimb(var/override = 0,var/no_explode = 0)
|
||||
if(destspawn) return
|
||||
if(override)
|
||||
status |= ORGAN_DESTROYED
|
||||
if(status & ORGAN_DESTROYED)
|
||||
if(body_part == UPPER_TORSO)
|
||||
return
|
||||
|
||||
src.status &= ~ORGAN_BROKEN
|
||||
src.status &= ~ORGAN_BLEEDING
|
||||
src.status &= ~ORGAN_SPLINTED
|
||||
for(var/implant in implants)
|
||||
del(implant)
|
||||
|
||||
// If any organs are attached to this, destroy them
|
||||
for(var/datum/organ/external/O in owner.organs)
|
||||
if(O.parent == src)
|
||||
O.droplimb(1)
|
||||
|
||||
var/obj/organ //Dropped limb object
|
||||
switch(body_part)
|
||||
if(LOWER_TORSO)
|
||||
owner << "\red You are now sterile."
|
||||
if(HEAD)
|
||||
organ= new /obj/item/weapon/organ/head(owner.loc, owner)
|
||||
owner.u_equip(owner.glasses)
|
||||
owner.u_equip(owner.head)
|
||||
owner.u_equip(owner.ears)
|
||||
owner.u_equip(owner.wear_mask)
|
||||
if(ARM_RIGHT)
|
||||
if(status & ORGAN_ROBOT)
|
||||
organ = new /obj/item/robot_parts/r_arm(owner.loc)
|
||||
else
|
||||
organ= new /obj/item/weapon/organ/r_arm(owner.loc, owner)
|
||||
if(ARM_LEFT)
|
||||
if(status & ORGAN_ROBOT)
|
||||
organ= new /obj/item/robot_parts/l_arm(owner.loc)
|
||||
else
|
||||
organ= new /obj/item/weapon/organ/l_arm(owner.loc, owner)
|
||||
if(LEG_RIGHT)
|
||||
if(status & ORGAN_ROBOT)
|
||||
organ = new /obj/item/robot_parts/l_leg(owner.loc)
|
||||
else
|
||||
organ= new /obj/item/weapon/organ/r_leg(owner.loc, owner)
|
||||
if(LEG_LEFT)
|
||||
if(status & ORGAN_ROBOT)
|
||||
organ = new /obj/item/robot_parts/r_leg(owner.loc)
|
||||
else
|
||||
organ= new /obj/item/weapon/organ/l_leg(owner.loc, owner)
|
||||
if(HAND_RIGHT)
|
||||
organ= new /obj/item/weapon/organ/r_hand(owner.loc, owner)
|
||||
owner.u_equip(owner.gloves)
|
||||
if(HAND_LEFT)
|
||||
organ= new /obj/item/weapon/organ/l_hand(owner.loc, owner)
|
||||
owner.u_equip(owner.gloves)
|
||||
if(FOOT_RIGHT)
|
||||
organ= new /obj/item/weapon/organ/r_foot/(owner.loc, owner)
|
||||
owner.u_equip(owner.shoes)
|
||||
if(FOOT_LEFT)
|
||||
organ = new /obj/item/weapon/organ/l_foot(owner.loc, owner)
|
||||
owner.u_equip(owner.shoes)
|
||||
if(organ)
|
||||
destspawn = 1
|
||||
//Robotic limbs explode until specified otherwise
|
||||
if(status & ORGAN_ROBOT && !no_explode)
|
||||
owner.visible_message("\red \The [owner]'s [display_name] explodes violently!",\
|
||||
"\red <b>Your [display_name] explodes!</b>",\
|
||||
"You hear an explosion followed by a scream!")
|
||||
explosion(get_turf(owner),-1,-1,2,3)
|
||||
var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread()
|
||||
spark_system.set_up(5, 0, owner)
|
||||
spark_system.attach(owner)
|
||||
spark_system.start()
|
||||
spawn(10)
|
||||
del(spark_system)
|
||||
else
|
||||
owner.visible_message("\red [owner.name]'s [display_name] flies off in an arc.",\
|
||||
"<span class='moderate'><b>Your [display_name] goes flying off!</b></span>",\
|
||||
"You hear a terrible sound of ripping tendons and flesh.")
|
||||
|
||||
//Throw organs around
|
||||
var/lol = pick(cardinal)
|
||||
step(organ,lol)
|
||||
|
||||
owner.regenerate_icons()
|
||||
|
||||
|
||||
/****************************************************
|
||||
HELPERS
|
||||
****************************************************/
|
||||
|
||||
/datum/organ/external/proc/bandage()
|
||||
var/rval = 0
|
||||
src.status &= ~ORGAN_BLEEDING
|
||||
for(var/datum/wound/W in wounds)
|
||||
if(W.internal) continue
|
||||
rval |= !W.bandaged
|
||||
W.bandaged = 1
|
||||
return rval
|
||||
|
||||
/datum/organ/external/proc/clamp()
|
||||
var/rval = 0
|
||||
src.status &= ~ORGAN_BLEEDING
|
||||
for(var/datum/wound/W in wounds)
|
||||
if(W.internal) continue
|
||||
rval |= !W.clamped
|
||||
W.clamped = 1
|
||||
return rval
|
||||
|
||||
/datum/organ/external/proc/salve()
|
||||
var/rval = 0
|
||||
for(var/datum/wound/W in wounds)
|
||||
rval |= !W.salved
|
||||
W.salved = 1
|
||||
return rval
|
||||
|
||||
/datum/organ/external/proc/fracture()
|
||||
if(status & ORGAN_BROKEN)
|
||||
return
|
||||
owner.visible_message("\red You hear a loud cracking sound coming from \the [owner].","\red <b>Something feels like it shattered in your [display_name]!</b>","You hear a sickening crack.")
|
||||
owner.emote("scream")
|
||||
status |= ORGAN_BROKEN
|
||||
broken_description = pick("broken","fracture","hairline fracture")
|
||||
perma_injury = brute_dam
|
||||
|
||||
/datum/organ/external/proc/robotize()
|
||||
src.status &= ~ORGAN_BROKEN
|
||||
src.status &= ~ORGAN_BLEEDING
|
||||
src.status &= ~ORGAN_SPLINTED
|
||||
src.status &= ~ORGAN_ATTACHABLE
|
||||
src.status &= ~ORGAN_DESTROYED
|
||||
src.status |= ORGAN_ROBOT
|
||||
for (var/datum/organ/external/T in children)
|
||||
if(T)
|
||||
T.robotize()
|
||||
|
||||
/datum/organ/external/proc/get_damage() //returns total damage
|
||||
return max(brute_dam + burn_dam - perma_injury, perma_injury) //could use health?
|
||||
|
||||
/datum/organ/external/proc/is_infected()
|
||||
for(var/datum/wound/W in wounds)
|
||||
if(W.germ_level > 100)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/****************************************************
|
||||
ORGAN DEFINES
|
||||
****************************************************/
|
||||
|
||||
/datum/organ/external/chest
|
||||
name = "chest"
|
||||
icon_name = "chest"
|
||||
display_name = "chest"
|
||||
max_damage = 150
|
||||
min_broken_damage = 75
|
||||
body_part = UPPER_TORSO
|
||||
|
||||
/datum/organ/external/groin
|
||||
name = "groin"
|
||||
icon_name = "diaper"
|
||||
display_name = "groin"
|
||||
max_damage = 115
|
||||
min_broken_damage = 70
|
||||
body_part = LOWER_TORSO
|
||||
|
||||
/datum/organ/external/l_arm
|
||||
name = "l_arm"
|
||||
display_name = "left arm"
|
||||
icon_name = "l_arm"
|
||||
max_damage = 75
|
||||
min_broken_damage = 30
|
||||
body_part = ARM_LEFT
|
||||
|
||||
/datum/organ/external/l_leg
|
||||
name = "l_leg"
|
||||
display_name = "left leg"
|
||||
icon_name = "l_leg"
|
||||
max_damage = 75
|
||||
min_broken_damage = 30
|
||||
body_part = LEG_LEFT
|
||||
icon_position = LEFT
|
||||
|
||||
/datum/organ/external/r_arm
|
||||
name = "r_arm"
|
||||
display_name = "right arm"
|
||||
icon_name = "r_arm"
|
||||
max_damage = 75
|
||||
min_broken_damage = 30
|
||||
body_part = ARM_RIGHT
|
||||
|
||||
/datum/organ/external/r_leg
|
||||
name = "r_leg"
|
||||
display_name = "right leg"
|
||||
icon_name = "r_leg"
|
||||
max_damage = 75
|
||||
min_broken_damage = 30
|
||||
body_part = LEG_RIGHT
|
||||
icon_position = RIGHT
|
||||
|
||||
/datum/organ/external/l_foot
|
||||
name = "l_foot"
|
||||
display_name = "left foot"
|
||||
icon_name = "l_foot"
|
||||
max_damage = 40
|
||||
min_broken_damage = 15
|
||||
body_part = FOOT_LEFT
|
||||
icon_position = LEFT
|
||||
|
||||
/datum/organ/external/r_foot
|
||||
name = "r_foot"
|
||||
display_name = "right foot"
|
||||
icon_name = "r_foot"
|
||||
max_damage = 40
|
||||
min_broken_damage = 15
|
||||
body_part = FOOT_RIGHT
|
||||
icon_position = RIGHT
|
||||
|
||||
/datum/organ/external/r_hand
|
||||
name = "r_hand"
|
||||
display_name = "right hand"
|
||||
icon_name = "r_hand"
|
||||
max_damage = 40
|
||||
min_broken_damage = 15
|
||||
body_part = HAND_RIGHT
|
||||
|
||||
/datum/organ/external/l_hand
|
||||
name = "l_hand"
|
||||
display_name = "left hand"
|
||||
icon_name = "l_hand"
|
||||
max_damage = 40
|
||||
min_broken_damage = 15
|
||||
body_part = HAND_LEFT
|
||||
|
||||
/datum/organ/external/head
|
||||
name = "head"
|
||||
icon_name = "head"
|
||||
display_name = "head"
|
||||
max_damage = 75
|
||||
min_broken_damage = 40
|
||||
body_part = HEAD
|
||||
var/disfigured = 0
|
||||
|
||||
take_damage(brute, burn, sharp, used_weapon = null, list/forbidden_limbs = list())
|
||||
..(brute, burn, sharp, used_weapon, forbidden_limbs)
|
||||
if (!disfigured)
|
||||
if (brute_dam > 40)
|
||||
if (prob(50))
|
||||
disfigure("brute")
|
||||
if (burn_dam > 40)
|
||||
disfigure("burn")
|
||||
|
||||
proc/disfigure(var/type = "brute")
|
||||
if (disfigured)
|
||||
return
|
||||
if(type == "brute")
|
||||
owner.visible_message("\red You hear a sickening cracking sound coming from \the [owner]'s face.", \
|
||||
"\red <b>Your face becomes unrecognizible mangled mess!</b>", \
|
||||
"\red You hear a sickening crack.")
|
||||
else
|
||||
owner.visible_message("\red [owner]'s face melts away, turning into mangled mess!", \
|
||||
"\red <b>Your face melts off!</b>", \
|
||||
"\red You hear a sickening sizzle.")
|
||||
disfigured = 1
|
||||
|
||||
/****************************************************
|
||||
EXTERNAL ORGAN ITEMS
|
||||
****************************************************/
|
||||
|
||||
obj/item/weapon/organ
|
||||
icon = 'icons/mob/human_races/r_human.dmi'
|
||||
|
||||
obj/item/weapon/organ/New(loc, mob/living/carbon/human/H)
|
||||
..(loc)
|
||||
if(!istype(H))
|
||||
return
|
||||
if(H.dna)
|
||||
if(!blood_DNA)
|
||||
blood_DNA = list()
|
||||
blood_DNA[H.dna.unique_enzymes] = H.dna.b_type
|
||||
|
||||
//Forming icon for the limb
|
||||
|
||||
//Setting base icon for this mob's race
|
||||
if(ishuman(H) && H.dna)
|
||||
var/icon/base
|
||||
switch(H.dna.mutantrace)
|
||||
if("tajaran")
|
||||
base = new('icons/mob/human_races/r_tajaran.dmi')
|
||||
if("lizard")
|
||||
base = new('icons/mob/human_races/r_lizard.dmi')
|
||||
if("skrell")
|
||||
base = new('icons/mob/human_races/r_skrell.dmi')
|
||||
else
|
||||
base = new('icons/mob/human_races/r_human.dmi')
|
||||
if(base)
|
||||
icon = base.MakeLying()
|
||||
else
|
||||
icon_state = initial(icon_state)+"_l"
|
||||
|
||||
var/icon/I = new /icon(icon, icon_state)
|
||||
|
||||
//Changing limb's skin tone to match owner
|
||||
if (H.s_tone >= 0)
|
||||
I.Blend(rgb(H.s_tone, H.s_tone, H.s_tone), ICON_ADD)
|
||||
else
|
||||
I.Blend(rgb(-H.s_tone, -H.s_tone, -H.s_tone), ICON_SUBTRACT)
|
||||
icon = I
|
||||
|
||||
|
||||
/****************************************************
|
||||
EXTERNAL ORGAN ITEMS DEFINES
|
||||
****************************************************/
|
||||
|
||||
obj/item/weapon/organ/l_arm
|
||||
name = "left arm"
|
||||
icon_state = "l_arm"
|
||||
obj/item/weapon/organ/l_foot
|
||||
name = "left foot"
|
||||
icon_state = "l_foot"
|
||||
obj/item/weapon/organ/l_hand
|
||||
name = "left hand"
|
||||
icon_state = "l_hand"
|
||||
obj/item/weapon/organ/l_leg
|
||||
name = "left leg"
|
||||
icon_state = "l_leg"
|
||||
obj/item/weapon/organ/r_arm
|
||||
name = "right arm"
|
||||
icon_state = "r_arm"
|
||||
obj/item/weapon/organ/r_foot
|
||||
name = "right foot"
|
||||
icon_state = "r_foot"
|
||||
obj/item/weapon/organ/r_hand
|
||||
name = "right hand"
|
||||
icon_state = "r_hand"
|
||||
obj/item/weapon/organ/r_leg
|
||||
name = "right leg"
|
||||
icon_state = "r_leg"
|
||||
obj/item/weapon/organ/head
|
||||
name = "head"
|
||||
icon_state = "head_m"
|
||||
var/mob/living/carbon/brain/brainmob
|
||||
var/brain_op_stage = 0
|
||||
|
||||
obj/item/weapon/organ/head/New(loc, mob/living/carbon/human/H)
|
||||
..()
|
||||
spawn(5)
|
||||
if(brainmob && brainmob.client)
|
||||
brainmob.client.screen.len = null //clear the hud
|
||||
if(ishuman(H))
|
||||
if(H.gender == FEMALE)
|
||||
H.icon_state = "head_f"
|
||||
H.overlays += H.generate_head_icon()
|
||||
transfer_identity(H)
|
||||
pixel_x = -10
|
||||
pixel_y = 6
|
||||
name = "[H.real_name]'s head"
|
||||
|
||||
H.regenerate_icons()
|
||||
|
||||
H.death()
|
||||
|
||||
obj/item/weapon/organ/head/proc/transfer_identity(var/mob/living/carbon/human/H)//Same deal as the regular brain proc. Used for human-->head
|
||||
brainmob = new(src)
|
||||
brainmob.name = H.real_name
|
||||
brainmob.real_name = H.real_name
|
||||
brainmob.dna = H.dna
|
||||
if(H.mind)
|
||||
H.mind.transfer_to(brainmob)
|
||||
brainmob.container = src
|
||||
|
||||
obj/item/weapon/organ/head/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
if(istype(W,/obj/item/weapon/scalpel))
|
||||
switch(brain_op_stage)
|
||||
if(0)
|
||||
for(var/mob/O in (oviewers(brainmob) - user))
|
||||
O.show_message("\red [brainmob] is beginning to have \his head cut open with [src] by [user].", 1)
|
||||
brainmob << "\red [user] begins to cut open your head with [src]!"
|
||||
user << "\red You cut [brainmob]'s head open with [src]!"
|
||||
|
||||
brain_op_stage = 1
|
||||
|
||||
if(2)
|
||||
for(var/mob/O in (oviewers(brainmob) - user))
|
||||
O.show_message("\red [brainmob] is having \his connections to the brain delicately severed with [src] by [user].", 1)
|
||||
brainmob << "\red [user] begins to cut open your head with [src]!"
|
||||
user << "\red You cut [brainmob]'s head open with [src]!"
|
||||
|
||||
brain_op_stage = 3.0
|
||||
else
|
||||
..()
|
||||
else if(istype(W,/obj/item/weapon/circular_saw))
|
||||
switch(brain_op_stage)
|
||||
if(1)
|
||||
for(var/mob/O in (oviewers(brainmob) - user))
|
||||
O.show_message("\red [brainmob] has \his skull sawed open with [src] by [user].", 1)
|
||||
brainmob << "\red [user] begins to saw open your head with [src]!"
|
||||
user << "\red You saw [brainmob]'s head open with [src]!"
|
||||
|
||||
brain_op_stage = 2
|
||||
if(3)
|
||||
for(var/mob/O in (oviewers(brainmob) - user))
|
||||
O.show_message("\red [brainmob] has \his spine's connection to the brain severed with [src] by [user].", 1)
|
||||
brainmob << "\red [user] severs your brain's connection to the spine with [src]!"
|
||||
user << "\red You sever [brainmob]'s brain's connection to the spine with [src]!"
|
||||
|
||||
user.attack_log += "\[[time_stamp()]\]<font color='red'> Debrained [brainmob.name] ([brainmob.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])</font>"
|
||||
brainmob.attack_log += "\[[time_stamp()]\]<font color='orange'> Debrained by [user.name] ([user.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])</font>"
|
||||
log_admin("ATTACK: [brainmob] ([brainmob.ckey]) debrained [user] ([user.ckey]).")
|
||||
message_admins("ATTACK: [brainmob] ([brainmob.ckey]) debrained [user] ([user.ckey]).")
|
||||
|
||||
var/obj/item/brain/B = new(loc)
|
||||
B.transfer_identity(brainmob)
|
||||
|
||||
brain_op_stage = 4.0
|
||||
else
|
||||
..()
|
||||
else
|
||||
..()
|
||||
74
code/modules/organs/organ_internal.dm
Normal file
74
code/modules/organs/organ_internal.dm
Normal file
@@ -0,0 +1,74 @@
|
||||
/****************************************************
|
||||
INTERNAL ORGANS
|
||||
****************************************************/
|
||||
|
||||
/mob/living/carbon/human/var/list/internal_organs = list()
|
||||
|
||||
/datum/organ/internal
|
||||
// amount of damage to the organ
|
||||
var/damage = 0
|
||||
var/min_bruised_damage = 10
|
||||
var/min_broken_damage = 30
|
||||
var/parent_organ = "chest"
|
||||
|
||||
/datum/organ/internal/proc/is_bruised()
|
||||
return damage >= min_bruised_damage
|
||||
|
||||
/datum/organ/internal/proc/is_broken()
|
||||
return damage >= min_broken_damage
|
||||
|
||||
|
||||
/datum/organ/internal/New(mob/living/carbon/human/H)
|
||||
..()
|
||||
var/datum/organ/external/E = H.organs_by_name[src.parent_organ]
|
||||
if(E.internal_organs == null)
|
||||
E.internal_organs = list()
|
||||
E.internal_organs += src
|
||||
H.internal_organs[src.name] = src
|
||||
src.owner = H
|
||||
|
||||
/datum/organ/internal/proc/take_damage(amount)
|
||||
src.damage += amount
|
||||
|
||||
var/datum/organ/external/parent = owner.get_organ(parent_organ)
|
||||
owner.custom_pain("Something inside your [parent.display_name] hurts a lot.", 1)
|
||||
|
||||
/****************************************************
|
||||
INTERNAL ORGANS DEFINES
|
||||
****************************************************/
|
||||
|
||||
/datum/organ/internal/heart
|
||||
name = "heart"
|
||||
parent_organ = "chest"
|
||||
|
||||
|
||||
/datum/organ/internal/lungs
|
||||
name = "lungs"
|
||||
parent_organ = "chest"
|
||||
|
||||
/datum/organ/internal/liver
|
||||
name = "liver"
|
||||
parent_organ = "chest"
|
||||
var/process_accuracy = 10
|
||||
|
||||
process()
|
||||
if(owner.life_tick % process_accuracy == 0)
|
||||
// Damaged liver means some chemicals are very dangerous
|
||||
if(src.damage >= src.min_bruised_damage)
|
||||
for(var/datum/reagent/R in owner.reagents.reagent_list)
|
||||
// Ethanol and all drinks are bad
|
||||
if(istype(R, /datum/reagent/ethanol))
|
||||
owner.adjustToxLoss(0.1 * process_accuracy)
|
||||
|
||||
// Can't cope with toxins at all
|
||||
for(var/toxin in list("toxin", "plasma", "sacid", "pacid", "cyanide", "lexorin", "amatoxin", "chloralhydrate", "carpotoxin", "zombiepowder", "mindbreaker"))
|
||||
if(owner.reagents.has_reagent(toxin))
|
||||
owner.adjustToxLoss(0.3 * process_accuracy)
|
||||
|
||||
/datum/organ/internal/kidney
|
||||
name = "kidney"
|
||||
parent_organ = "chest"
|
||||
|
||||
/datum/organ/internal/brain
|
||||
name = "brain"
|
||||
parent_organ = "head"
|
||||
109
code/modules/organs/pain.dm
Normal file
109
code/modules/organs/pain.dm
Normal file
@@ -0,0 +1,109 @@
|
||||
mob/proc/flash_pain()
|
||||
flick("pain",pain)
|
||||
|
||||
mob/var/list/pain_stored = list()
|
||||
mob/var/last_pain_message = ""
|
||||
mob/var/next_pain_time = 0
|
||||
|
||||
// partname is the name of a body part
|
||||
// amount is a num from 1 to 100
|
||||
mob/proc/pain(var/partname, var/amount, var/force, var/burning = 0)
|
||||
if(stat >= 2) return
|
||||
if(world.time < next_pain_time && !force)
|
||||
return
|
||||
if(amount > 10 && istype(src,/mob/living/carbon/human))
|
||||
if(src:paralysis)
|
||||
src:paralysis = max(0, src:paralysis-round(amount/10))
|
||||
if(amount > 50 && prob(amount / 5))
|
||||
src:drop_item()
|
||||
var/msg
|
||||
if(burning)
|
||||
switch(amount)
|
||||
if(1 to 10)
|
||||
msg = "\red <b>Your [partname] burns.</b>"
|
||||
if(11 to 90)
|
||||
flash_weak_pain()
|
||||
msg = "\red <b><font size=2>Your [partname] burns badly!</font></b>"
|
||||
if(91 to 10000)
|
||||
flash_pain()
|
||||
msg = "\red <b><font size=3>OH GOD! Your [partname] is on fire!</font></b>"
|
||||
else
|
||||
switch(amount)
|
||||
if(1 to 10)
|
||||
msg = "<b>Your [partname] hurts.</b>"
|
||||
if(11 to 90)
|
||||
flash_weak_pain()
|
||||
msg = "<b><font size=2>Your [partname] hurts badly.</font></b>"
|
||||
if(91 to 10000)
|
||||
flash_pain()
|
||||
msg = "<b><font size=3>OH GOD! Your [partname] is hurting terribly!</font></b>"
|
||||
if(msg && (msg != last_pain_message || prob(10)))
|
||||
last_pain_message = msg
|
||||
src << msg
|
||||
next_pain_time = world.time + (100 - amount)
|
||||
|
||||
|
||||
// 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(reagents.has_reagent("tramadol"))
|
||||
return
|
||||
if(reagents.has_reagent("oxycodone"))
|
||||
return
|
||||
if(analgesic)
|
||||
return
|
||||
var/msg = "\red <b>[message]</b>"
|
||||
if(flash_strength >= 1)
|
||||
msg = "\red <font size=3><b>[message]</b></font>"
|
||||
src << msg
|
||||
|
||||
mob/living/carbon/human/proc/handle_pain()
|
||||
// not when sleeping
|
||||
if(stat >= 2) return
|
||||
if(reagents.has_reagent("tramadol"))
|
||||
return
|
||||
if(reagents.has_reagent("oxycodone"))
|
||||
return
|
||||
if(analgesic)
|
||||
return
|
||||
var/maxdam = 0
|
||||
var/datum/organ/external/damaged_organ = null
|
||||
for(var/datum/organ/external/E in organs)
|
||||
// amputated limbs don't cause pain
|
||||
if(E.amputated) continue
|
||||
|
||||
var/dam = E.get_damage()
|
||||
// make the choice of the organ depend on damage,
|
||||
// but also sometimes use one of the less damaged ones
|
||||
if(dam > maxdam && (maxdam == 0 || prob(70)) )
|
||||
damaged_organ = E
|
||||
maxdam = dam
|
||||
if(damaged_organ)
|
||||
pain(damaged_organ.display_name, maxdam, 0)
|
||||
|
||||
// Damage to internal organs hurts a lot.
|
||||
for(var/organ_name in internal_organs)
|
||||
var/datum/organ/internal/I = internal_organs[organ_name]
|
||||
if(I.damage > 2) if(prob(2))
|
||||
var/datum/organ/external/parent = get_organ(I.parent_organ)
|
||||
src.custom_pain("You feel a sharp pain in your [parent.display_name]", 1)
|
||||
|
||||
var/toxDamageMessage = null
|
||||
var/toxMessageProb = 1
|
||||
switch(getToxLoss())
|
||||
if(1 to 5)
|
||||
toxMessageProb = 1
|
||||
toxDamageMessage = "Your body stings slightly."
|
||||
if(6 to 10)
|
||||
toxMessageProb = 2
|
||||
toxDamageMessage = "Your whole body hurts a little."
|
||||
if(11 to 15)
|
||||
toxMessageProb = 2
|
||||
toxDamageMessage = "Your whole body hurts."
|
||||
if(91 to 10000)
|
||||
toxMessageProb = 5
|
||||
toxDamageMessage = "Your body aches all over, it's driving you mad."
|
||||
|
||||
if(toxDamageMessage && prob(toxMessageProb))
|
||||
src.custom_pain(toxDamageMessage, getToxLoss() >= 15)
|
||||
254
code/modules/organs/wound.dm
Normal file
254
code/modules/organs/wound.dm
Normal file
@@ -0,0 +1,254 @@
|
||||
|
||||
/****************************************************
|
||||
WOUNDS
|
||||
****************************************************/
|
||||
/datum/wound
|
||||
// stages such as "cut", "deep cut", etc.
|
||||
var/list/stages
|
||||
// number representing the current stage
|
||||
var/current_stage = 0
|
||||
|
||||
// description of the wound
|
||||
var/desc = ""
|
||||
|
||||
// amount of damage this wound causes
|
||||
var/damage = 0
|
||||
|
||||
// amount of damage the current wound type requires(less means we need to apply the next healing stage)
|
||||
var/min_damage = 0
|
||||
|
||||
// one of CUT, BRUISE, BURN
|
||||
var/damage_type = CUT
|
||||
|
||||
// whether this wound needs a bandage/salve to heal at all
|
||||
var/needs_treatment = 0
|
||||
|
||||
// is the wound bandaged?
|
||||
var/tmp/bandaged = 0
|
||||
// Similar to bandaged, but works differently
|
||||
var/tmp/clamped = 0
|
||||
// is the wound salved?
|
||||
var/tmp/salved = 0
|
||||
// is the wound disinfected?
|
||||
var/tmp/disinfected = 0
|
||||
var/tmp/created = 0
|
||||
|
||||
// number of wounds of this type
|
||||
var/tmp/amount = 1
|
||||
|
||||
// maximum stage at which bleeding should still happen, counted from the right rather than the left of the list
|
||||
// 1 means all stages except the last should bleed
|
||||
var/max_bleeding_stage = 1
|
||||
|
||||
// internal wounds can only be fixed through surgery
|
||||
var/internal = 0
|
||||
|
||||
// amount of germs in the wound
|
||||
var/germ_level = 0
|
||||
|
||||
// helper lists
|
||||
var/tmp/list/desc_list = list()
|
||||
var/tmp/list/damage_list = list()
|
||||
New(var/damage)
|
||||
|
||||
created = world.time
|
||||
|
||||
// reading from a list("stage" = damage) is pretty difficult, so build two separate
|
||||
// lists from them instead
|
||||
for(var/V in stages)
|
||||
desc_list += V
|
||||
damage_list += stages[V]
|
||||
|
||||
src.damage = damage
|
||||
|
||||
// initialize with the first stage
|
||||
next_stage()
|
||||
|
||||
// this will ensure the size of the wound matches the damage
|
||||
src.heal_damage(0)
|
||||
|
||||
// make the max_bleeding_stage count from the end of the list rather than the start
|
||||
// this is more robust to changes to the list
|
||||
max_bleeding_stage = src.desc_list.len - max_bleeding_stage
|
||||
|
||||
// returns 1 if there's a next stage, 0 otherwise
|
||||
proc/next_stage()
|
||||
if(current_stage + 1 > src.desc_list.len)
|
||||
return 0
|
||||
|
||||
current_stage++
|
||||
|
||||
src.min_damage = damage_list[current_stage]
|
||||
src.desc = desc_list[current_stage]
|
||||
return 1
|
||||
|
||||
// returns 1 if the wound has started healing
|
||||
proc/started_healing()
|
||||
return (current_stage > 1)
|
||||
|
||||
// checks whether the wound has been appropriately treated
|
||||
// always returns 1 for wounds that don't need to be treated
|
||||
proc/is_treated()
|
||||
if(!needs_treatment) return 1
|
||||
|
||||
if(damage_type == BRUISE || damage_type == CUT)
|
||||
return bandaged
|
||||
else if(damage_type == BURN)
|
||||
return salved
|
||||
|
||||
// checks if wound is considered open for external infections
|
||||
// untreated cuts (and bleeding bruises) and burns are possibly infectable, chance higher if wound is bigger
|
||||
proc/can_infect()
|
||||
if (is_treated() && damage < 10)
|
||||
return 0
|
||||
if (disinfected)
|
||||
return 0
|
||||
var/dam_coef = round(damage/10)
|
||||
switch (damage_type)
|
||||
if (BRUISE)
|
||||
return prob(dam_coef*5) && bleeding() //bruises only infectable if bleeding
|
||||
if (BURN)
|
||||
return prob(dam_coef*10)
|
||||
if (CUT)
|
||||
return prob(dam_coef*20)
|
||||
|
||||
return 0
|
||||
// heal the given amount of damage, and if the given amount of damage was more
|
||||
// than what needed to be healed, return how much heal was left
|
||||
// set @heals_internal to also heal internal organ damage
|
||||
proc/heal_damage(amount, heals_internal = 0)
|
||||
if(src.internal && !heals_internal)
|
||||
// heal nothing
|
||||
return amount
|
||||
|
||||
var/healed_damage = min(src.damage, amount)
|
||||
amount -= healed_damage
|
||||
src.damage -= healed_damage
|
||||
|
||||
while(src.damage / src.amount < damage_list[current_stage] && current_stage < src.desc_list.len)
|
||||
current_stage++
|
||||
desc = desc_list[current_stage]
|
||||
src.min_damage = damage_list[current_stage]
|
||||
|
||||
// return amount of healing still leftover, can be used for other wounds
|
||||
return amount
|
||||
|
||||
// opens the wound again
|
||||
proc/open_wound(damage)
|
||||
src.damage += damage
|
||||
|
||||
while(src.current_stage > 1 && src.damage_list[current_stage-1] <= src.damage)
|
||||
src.current_stage--
|
||||
|
||||
src.desc = desc_list[current_stage]
|
||||
src.min_damage = damage_list[current_stage]
|
||||
|
||||
proc/bleeding()
|
||||
// internal wounds don't bleed in the sense of this function
|
||||
return (!(bandaged||clamped) && (damage_type == BRUISE && damage >= 20 || damage_type == CUT) && current_stage <= max_bleeding_stage && !src.internal)
|
||||
|
||||
/** CUTS **/
|
||||
/datum/wound/cut/small
|
||||
// link wound descriptions to amounts of damage
|
||||
max_bleeding_stage = 2
|
||||
stages = list("ugly ripped cut" = 20, "ripped cut" = 10, "cut" = 5, "healing cut" = 2, "small scab" = 0)
|
||||
|
||||
/datum/wound/cut/deep
|
||||
max_bleeding_stage = 3
|
||||
stages = list("ugly deep ripped cut" = 25, "deep ripped cut" = 20, "deep cut" = 15, "clotted cut" = 8, "scab" = 2, "fresh skin" = 0)
|
||||
|
||||
/datum/wound/cut/flesh
|
||||
max_bleeding_stage = 3
|
||||
stages = list("ugly ripped flesh wound" = 35, "ugly flesh wound" = 30, "flesh wound" = 25, "blood soaked clot" = 15, "large scab" = 5, "fresh skin" = 0)
|
||||
|
||||
/datum/wound/cut/gaping
|
||||
max_bleeding_stage = 2
|
||||
stages = list("gaping wound" = 50, "large blood soaked clot" = 25, "large clot" = 15, "small angry scar" = 5, \
|
||||
"small straight scar" = 0)
|
||||
|
||||
/datum/wound/cut/gaping_big
|
||||
max_bleeding_stage = 2
|
||||
stages = list("big gaping wound" = 60, "healing gaping wound" = 40, "large angry scar" = 10, "large straight scar" = 0)
|
||||
|
||||
needs_treatment = 1 // this only heals when bandaged
|
||||
|
||||
datum/wound/cut/massive
|
||||
max_bleeding_stage = 2
|
||||
stages = list("massive wound" = 70, "massive healing wound" = 50, "massive angry scar" = 10, "massive jagged scar" = 0)
|
||||
|
||||
needs_treatment = 1 // this only heals when bandaged
|
||||
|
||||
/** BRUISES **/
|
||||
/datum/wound/bruise
|
||||
stages = list("monumental bruise" = 80, "huge bruise" = 50, "large bruise" = 30,\
|
||||
"moderate bruise" = 20, "small bruise" = 10, "tiny bruise" = 5)
|
||||
|
||||
needs_treatment = 1 // this only heals when bandaged
|
||||
damage_type = BRUISE
|
||||
|
||||
/datum/wound/bruise/monumental
|
||||
|
||||
// implement sub-paths by starting at a later stage
|
||||
|
||||
/datum/wound/bruise/tiny
|
||||
current_stage = 5
|
||||
needs_treatment = 0
|
||||
|
||||
/datum/wound/bruise/small
|
||||
current_stage = 4
|
||||
needs_treatment = 0
|
||||
|
||||
/datum/wound/bruise/moderate
|
||||
current_stage = 3
|
||||
needs_treatment = 0
|
||||
|
||||
/datum/wound/bruise/large
|
||||
current_stage = 2
|
||||
|
||||
/datum/wound/bruise/huge
|
||||
current_stage = 1
|
||||
|
||||
/** BURNS **/
|
||||
/datum/wound/burn/moderate
|
||||
stages = list("ripped burn" = 10, "moderate burn" = 5, "moderate salved burn" = 2, "fresh skin" = 0)
|
||||
|
||||
needs_treatment = 1 // this only heals when bandaged
|
||||
|
||||
damage_type = BURN
|
||||
|
||||
/datum/wound/burn/large
|
||||
stages = list("ripped large burn" = 20, "large burn" = 15, "large salved burn" = 5, "fresh skin" = 0)
|
||||
|
||||
needs_treatment = 1 // this only heals when bandaged
|
||||
|
||||
damage_type = BURN
|
||||
|
||||
/datum/wound/burn/severe
|
||||
stages = list("ripped severe burn" = 35, "severe burn" = 30, "severe salved burn" = 10, "burn scar" = 0)
|
||||
|
||||
needs_treatment = 1 // this only heals when bandaged
|
||||
|
||||
damage_type = BURN
|
||||
|
||||
/datum/wound/burn/deep
|
||||
stages = list("ripped deep burn" = 45, "deep burn" = 40, "deep salved burn" = 15, "large burn scar" = 0)
|
||||
|
||||
needs_treatment = 1 // this only heals when bandaged
|
||||
|
||||
damage_type = BURN
|
||||
|
||||
|
||||
/datum/wound/burn/carbonised
|
||||
stages = list("carbonised area" = 50, "treated carbonised area" = 20, "massive burn scar" = 0)
|
||||
|
||||
needs_treatment = 1 // this only heals when bandaged
|
||||
|
||||
damage_type = BURN
|
||||
|
||||
/datum/wound/internal_bleeding
|
||||
internal = 1
|
||||
|
||||
stages = list("severed vein" = 30, "cut vein" = 20, "damaged vein" = 10, "bruised vein" = 5)
|
||||
max_bleeding_stage = 0
|
||||
|
||||
needs_treatment = 1
|
||||
Reference in New Issue
Block a user