Initial Commit

This commit is contained in:
skull132
2014-03-11 09:03:52 +02:00
commit a8d9450c7e
3486 changed files with 415920 additions and 0 deletions
+279
View File
@@ -0,0 +1,279 @@
/****************************************************
BLOOD SYSTEM
****************************************************/
//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
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",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, "antibodies" = null)
// Takes care blood loss and regeneration
/mob/living/carbon/human/proc/handle_blood()
if(species && species.flags & NO_BLOOD)
return
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.has_reagent("nutriment")) //Getting food speeds it up
B.volume += 0.4
reagents.remove_reagent("nutriment", 0.1)
if (reagents.has_reagent("iron")) //Hematogen candy anyone?
B.volume += 0.8
reagents.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"]
if(heart.damage > 1 && heart.damage < heart.min_bruised_damage)
blood_volume *= 0.8
else if(heart.damage >= heart.min_bruised_damage && heart.damage < heart.min_broken_damage)
blood_volume *= 0.6
else if(heart.damage >= heart.min_broken_damage && heart.damage < 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 += 3
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)
//Makes a blood drop, leaking certain amount of blood from the mob
/mob/living/carbon/human/proc/drip(var/amt as num)
if(species && species.flags & NO_BLOOD) //TODO: Make drips come from the reagents instead.
return
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
if (species) this.basecolor = species.blood_color
this.update_icon()
else
for(var/obj/effect/decal/cleanable/blood/drip/G in nums)
del G
T.add_blood(src)
/****************************************************
BLOOD TRANSFERS
****************************************************/
//Gets blood from mob to the container, preserving all data in it.
/mob/living/carbon/proc/take_blood(obj/item/weapon/reagent_containers/container, var/amount)
var/datum/reagent/B = get_blood(container.reagents)
if(!B) B = new /datum/reagent/blood
B.holder = container
B.volume += amount
//set reagent data
B.data["donor"] = src
if (!B.data["virus2"])
B.data["virus2"] = list()
B.data["virus2"] |= virus_copylist(src.virus2)
B.data["antibodies"] = src.antibodies
B.data["blood_DNA"] = copytext(src.dna.unique_enzymes,1,0)
if(src.resistances && src.resistances.len)
if(B.data["resistances"])
B.data["resistances"] |= src.resistances.Copy()
else
B.data["resistances"] = src.resistances.Copy()
B.data["blood_type"] = copytext(src.dna.b_type,1,0)
var/list/temp_chem = list()
for(var/datum/reagent/R in src.reagents.reagent_list)
temp_chem += R.id
temp_chem[R.id] = R.volume
B.data["trace_chem"] = list2params(temp_chem)
return B
//For humans, blood does not appear from blue, it comes from vessels.
/mob/living/carbon/human/take_blood(obj/item/weapon/reagent_containers/container, var/amount)
if(species && species.flags & NO_BLOOD)
return null
if(vessel.get_reagent_amount("blood") < amount)
return null
. = ..()
vessel.remove_reagent("blood",amount) // Removes blood if human
//Transfers blood from container ot vessels
/mob/living/carbon/proc/inject_blood(obj/item/weapon/reagent_containers/container, var/amount)
var/datum/reagent/blood/injected = get_blood(container.reagents)
if (!injected)
return
src.virus2 |= virus_copylist(injected.data["virus2"])
if (injected.data["antibodies"] && prob(5))
antibodies |= injected.data["antibodies"]
var/list/chems = list()
chems = params2list(injected.data["trace_chem"])
for(var/C in chems)
src.reagents.add_reagent(C, (text2num(chems[C]) / 560) * amount)//adds trace chemicals to owner's blood
reagents.update_total()
container.reagents.remove_reagent("blood", amount)
//Transfers blood from container ot vessels, respecting blood types compatability.
/mob/living/carbon/human/inject_blood(obj/item/weapon/reagent_containers/container, var/amount)
var/datum/reagent/blood/injected = get_blood(container.reagents)
if(species && species.flags & NO_BLOOD)
reagents.add_reagent("blood", amount, injected.data)
reagents.update_total()
return
var/datum/reagent/blood/our = get_blood(vessel)
if (!injected || !our)
return
if(blood_incompatible(injected.data["blood_type"],our.data["blood_type"]) )
reagents.add_reagent("toxin",amount * 0.5)
reagents.update_total()
else
vessel.add_reagent("blood", amount, injected.data)
vessel.update_total()
..()
//Gets human's own blood.
/mob/living/carbon/proc/get_blood(datum/reagents/container)
var/datum/reagent/blood/res = locate() in container.reagent_list //Grab some blood
if(res) // Make sure there's some blood at all
if(res.data["donor"] != src) //If it's not theirs, then we look for theirs
for(var/datum/reagent/blood/D in container.reagent_list)
if(D.data["donor"] == src)
return D
return res
proc/blood_incompatible(donor,receiver)
if(!donor || !receiver) return 0
var
donor_antigen = copytext(donor,1,lentext(donor))
receiver_antigen = copytext(receiver,1,lentext(receiver))
donor_rh = (findtext(donor,"+")>0)
receiver_rh = (findtext(receiver,"+")>0)
if(donor_rh && !receiver_rh) return 1
switch(receiver_antigen)
if("A")
if(donor_antigen != "A" && donor_antigen != "O") return 1
if("B")
if(donor_antigen != "B" && donor_antigen != "O") return 1
if("O")
if(donor_antigen != "O") return 1
//AB is a universal receiver.
return 0
+136
View File
@@ -0,0 +1,136 @@
/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
/datum/organ/proc/get_icon()
return icon('icons/mob/human.dmi',"blank")
//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
/mob/living/carbon/human/var/list/internal_organs_by_name = list() // so internal organs have less ickiness too
//Creates and initializes and connects external and internal organs
/mob/living/carbon/human/proc/make_organs()
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"])
internal_organs_by_name["heart"] = new/datum/organ/internal/heart(src)
internal_organs_by_name["lungs"] = new/datum/organ/internal/lungs(src)
internal_organs_by_name["liver"] = new/datum/organ/internal/liver(src)
internal_organs_by_name["kidney"] = new/datum/organ/internal/kidney(src)
internal_organs_by_name["brain"] = new/datum/organ/internal/brain(src)
internal_organs_by_name["eyes"] = new/datum/organ/internal/eyes(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) )
broken = 1
//Moving around with fractured ribs won't do you any good
if (broken && E.internal_organs && prob(15))
if (!lying && world.timeofday - l_move_time < 15)
var/datum/organ/internal/I = pick(E.internal_organs)
custom_pain("You feel broken bones moving in your [E.display_name]!", 1)
I.take_damage(rand(3,5))
//Special effects for limbs.
if(E.name in list("l_hand","l_arm","r_hand","r_arm") && (broken||malfunction))
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)
u_equip(c_hand)
if(broken)
emote("me", 1, "[(species && species.flags & NO_PAIN) ? "" : "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.is_usable() || 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))
if(species && species.flags & NO_PAIN)
emote("scream")
emote("collapse")
paralysis = 10
//Check arms and legs for existence
can_stand = 2 //can stand on both legs
var/datum/organ/external/E = organs_by_name["l_foot"]
if(E.status & ORGAN_DESTROYED)
can_stand--
E = organs_by_name["r_foot"]
if(E.status & ORGAN_DESTROYED)
can_stand--
+941
View File
@@ -0,0 +1,941 @@
/****************************************************
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/sabotaged = 0 //If a prosthetic limb is emagged, it will detonate when it fails.
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 = 1
/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(body_part != UPPER_TORSO && body_part != LOWER_TORSO) //as hilarious as it is, getting hit on the chest too much shouldn't effectively gib you.
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
/*
This function completely restores a damaged organ to perfect condition.
*/
/datum/organ/external/proc/rejuvenate()
damage_state = "00"
status = 0
perma_injury = 0
brute_dam = 0
burn_dam = 0
// handle internal organs
for(var/datum/organ/internal/current_organ in internal_organs)
current_organ.rejuvenate()
// remove embedded objects and drop them on the floor
for(var/obj/implanted_object in implants)
if(!istype(implanted_object,/obj/item/weapon/implant)) // We don't want to remove REAL implants. Just shrapnel etc.
implanted_object.loc = owner.loc
implants -= implanted_object
owner.updatehealth()
/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 > 15 && type != BURN && local_damage > 30 && 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()
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(status & ORGAN_ROBOT|ORGAN_DESTROYED) //Robotic limbs shouldn't be infected, nor should nonexistant limbs.
germ_level = 0
return
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 I had some free spachealing, internal bleedings and infections
/datum/organ/external/proc/update_wounds()
if((status & ORGAN_ROBOT)) //Robotic limbs don't heal or get worse.
return
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
continue
// 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)
if(!owner.reagents.has_reagent("bicaridine")) //bicard stops internal wounds from growing bigger with time, and also stop bleeding
W.open_wound(0.1 * wound_update_accuracy)
owner.vessel.remove_reagent("blood",0.05 * W.damage * wound_update_accuracy)
if(!owner.reagents.has_reagent("inaprovaline")) //This little copypaste will allow inaprovaline to work too, giving it a much needed buff to help medical.
W.open_wound(0.1 * wound_update_accuracy)
owner.vessel.remove_reagent("blood",0.05 * W.damage * wound_update_accuracy)
owner.vessel.remove_reagent("blood",0.02 * W.damage * wound_update_accuracy)//Bicaridine slows Internal Bleeding
if(prob(1 * wound_update_accuracy))
owner.custom_pain("You feel a stabbing pain in your [display_name]!",1)
//overdose of bicaridine begins healing IB
if(owner.reagents.get_reagent_amount("bicaridine") >= 30)
W.damage = max(0, W.damage - 0.2)
// slow healing
var/heal_amt = 0
if (W.damage < 15) //this thing's edges are not in day's travel of each other, what healing?
heal_amt += 0.2
if(W.is_treated() && W.damage < 50) //whoa, not even magical band aid can hold it together
heal_amt += 0.3
//we only update wounds once in [wound_update_accuracy] ticks so have to emulate realtime
heal_amt = heal_amt * wound_update_accuracy
//configurable regen speed woo, no-regen hardcore or instaheal hugbox, choose your destiny
heal_amt = heal_amt * config.organ_regeneration_multiplier
// amount of healing is spread over all the wounds
heal_amt = heal_amt / (wounds.len + 1)
// making it look prettier on scanners
heal_amt = round(heal_amt,0.1)
W.heal_damage(heal_amt)
// 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()
if (update_icon())
owner.UpdateDamageIcon(1)
//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())
W.bleed_timer--
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
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.l_ear)
owner.u_equip(owner.r_ear)
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/r_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/l_leg(owner.loc)
else
organ= new /obj/item/weapon/organ/l_leg(owner.loc, owner)
if(HAND_RIGHT)
if(!(status & ORGAN_ROBOT))
organ= new /obj/item/weapon/organ/r_hand(owner.loc, owner)
owner.u_equip(owner.gloves)
if(HAND_LEFT)
if(!(status & ORGAN_ROBOT))
organ= new /obj/item/weapon/organ/l_hand(owner.loc, owner)
owner.u_equip(owner.gloves)
if(FOOT_RIGHT)
if(!(status & ORGAN_ROBOT))
organ= new /obj/item/weapon/organ/r_foot/(owner.loc, owner)
owner.u_equip(owner.shoes)
if(FOOT_LEFT)
if(!(status & ORGAN_ROBOT))
organ = new /obj/item/weapon/organ/l_foot(owner.loc, owner)
owner.u_equip(owner.shoes)
if(organ)
destspawn = 1
//Robotic limbs explode if sabotaged.
if(status & ORGAN_ROBOT && !no_explode && sabotaged)
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)
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.update_body(1)
/****************************************************
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.")
if(owner.species && !(owner.species.flags & NO_PAIN))
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_CUT_AWAY
src.status &= ~ORGAN_ATTACHABLE
src.status &= ~ORGAN_DESTROYED
src.status |= ORGAN_ROBOT
src.destspawn = 0
for (var/datum/organ/external/T in children)
if(T)
T.robotize()
/datum/organ/external/proc/mutate()
src.status |= ORGAN_MUTATED
owner.update_body()
/datum/organ/external/proc/unmutate()
src.status &= ~ORGAN_MUTATED
owner.update_body()
/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
/datum/organ/external/get_icon(gender="")
if (status & ORGAN_ROBOT)
return new /icon('icons/mob/human_races/robotic.dmi', "[icon_name][gender ? "_[gender]" : ""]")
if (status & ORGAN_MUTATED)
return new /icon(owner.deform_icon, "[icon_name][gender ? "_[gender]" : ""]")
return new /icon(owner.race_icon, "[icon_name][gender ? "_[gender]" : ""]")
/datum/organ/external/proc/is_usable()
return !(status & (ORGAN_DESTROYED|ORGAN_MUTATED|ORGAN_DEAD))
/****************************************************
ORGAN DEFINES
****************************************************/
/datum/organ/external/chest
name = "chest"
icon_name = "torso"
display_name = "chest"
max_damage = 75
min_broken_damage = 40
body_part = UPPER_TORSO
/datum/organ/external/groin
name = "groin"
icon_name = "groin"
display_name = "groin"
max_damage = 50
min_broken_damage = 30
body_part = LOWER_TORSO
/datum/organ/external/l_arm
name = "l_arm"
display_name = "left arm"
icon_name = "l_arm"
max_damage = 50
min_broken_damage = 20
body_part = ARM_LEFT
/datum/organ/external/l_leg
name = "l_leg"
display_name = "left leg"
icon_name = "l_leg"
max_damage = 50
min_broken_damage = 20
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 = 50
min_broken_damage = 20
body_part = ARM_RIGHT
/datum/organ/external/r_leg
name = "r_leg"
display_name = "right leg"
icon_name = "r_leg"
max_damage = 50
min_broken_damage = 20
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 = 30
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 = 30
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 = 30
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 = 30
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
/datum/organ/external/head/get_icon()
if (!owner)
return ..()
var/g = "m"
if(owner.gender == FEMALE) g = "f"
if (status & ORGAN_MUTATED)
. = new /icon(owner.deform_icon, "[icon_name]_[g]")
else
. = new /icon(owner.race_icon, "[icon_name]_[g]")
/datum/organ/external/head/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")
/datum/organ/external/head/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
var/icon/base
if(H.species && H.species.icobase)
base = icon(H.species.icobase)
else
base = icon('icons/mob/human_races/r_human.dmi')
if(base)
//Changing limb's skin tone to match owner
if(!H.species || H.species.flags & HAS_SKIN_TONE)
if (H.s_tone >= 0)
base.Blend(rgb(H.s_tone, H.s_tone, H.s_tone), ICON_ADD)
else
base.Blend(rgb(-H.s_tone, -H.s_tone, -H.s_tone), ICON_SUBTRACT)
icon = base
dir = SOUTH
src.transform = turn(src.transform, rand(70,130))
/****************************************************
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)
if(istype(H))
src.icon_state = H.gender == MALE? "head_m" : "head_f"
..()
//Add (facial) hair.
if(H.f_style)
var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[H.f_style]
if(facial_hair_style)
var/icon/facial = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s")
if(facial_hair_style.do_colouration)
facial.Blend(rgb(H.r_facial, H.g_facial, H.b_facial), ICON_ADD)
overlays.Add(facial) // icon.Blend(facial, ICON_OVERLAY)
if(H.h_style && !(H.head && (H.head.flags & BLOCKHEADHAIR)))
var/datum/sprite_accessory/hair_style = hair_styles_list[H.h_style]
if(hair_style)
var/icon/hair = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s")
if(hair_style.do_colouration)
hair.Blend(rgb(H.r_hair, H.g_hair, H.b_hair), ICON_ADD)
overlays.Add(hair) //icon.Blend(hair, ICON_OVERLAY)
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)
name = "[H.real_name]'s head"
H.regenerate_icons()
brainmob.stat = 2
brainmob.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.Clone()
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 [W] by [user].", 1)
brainmob << "\red [user] begins to cut open your head with [W]!"
user << "\red You cut [brainmob]'s head open with [W]!"
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 [W] by [user].", 1)
brainmob << "\red [user] begins to cut open your head with [W]!"
user << "\red You cut [brainmob]'s head open with [W]!"
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 [W] by [user].", 1)
brainmob << "\red [user] begins to saw open your head with [W]!"
user << "\red You saw [brainmob]'s head open with [W]!"
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 [W] by [user].", 1)
brainmob << "\red [user] severs your brain's connection to the spine with [W]!"
user << "\red You sever [brainmob]'s brain's connection to the spine with [W]!"
user.attack_log += "\[[time_stamp()]\]<font color='red'> Debrained [brainmob.name] ([brainmob.ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)])</font>"
brainmob.attack_log += "\[[time_stamp()]\]<font color='orange'> Debrained by [user.name] ([user.ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)])</font>"
msg_admin_attack("[user] ([user.ckey]) debrained [brainmob] ([brainmob.ckey]) (INTENT: [uppertext(user.a_intent)]) (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[user.x];Y=[user.y];Z=[user.z]'>JMP</a>)")
var/obj/item/brain/B = new(loc)
B.transfer_identity(brainmob)
brain_op_stage = 4.0
else
..()
else
..()
+154
View File
@@ -0,0 +1,154 @@
/****************************************************
INTERNAL ORGANS
****************************************************/
/mob/living/carbon/human/var/list/internal_organs = list()
/datum/organ/internal
var/damage = 0 // amount of damage to the organ
var/min_bruised_damage = 10
var/min_broken_damage = 30
var/parent_organ = "chest"
var/robotic = 0 //For being a robot
/datum/organ/internal/proc/rejuvenate()
damage=0
/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, var/silent=0)
if(src.robotic == 2)
src.damage += (amount * 0.8)
else
src.damage += amount
var/datum/organ/external/parent = owner.get_organ(parent_organ)
if (!silent)
owner.custom_pain("Something inside your [parent.display_name] hurts a lot.", 1)
/datum/organ/internal/proc/emp_act(severity)
switch(robotic)
if(0)
return
if(1)
switch (severity)
if (1.0)
take_damage(20,0)
return
if (2.0)
take_damage(7,0)
return
if(3.0)
take_damage(3,0)
return
if(2)
switch (severity)
if (1.0)
take_damage(40,0)
return
if (2.0)
take_damage(15,0)
return
if(3.0)
take_damage(10,0)
return
/datum/organ/internal/proc/mechanize() //Being used to make robutt hearts, etc
robotic = 2
/datum/organ/internal/proc/mechassist() //Used to add things like pacemakers, etc
robotic = 1
min_bruised_damage = 15
min_broken_damage = 35
/****************************************************
INTERNAL ORGANS DEFINES
****************************************************/
/datum/organ/internal/heart
name = "heart"
parent_organ = "chest"
/datum/organ/internal/lungs
name = "lungs"
parent_organ = "chest"
process()
if(is_bruised())
if(prob(2))
spawn owner.emote("me", 1, "coughs up blood!")
owner.drip(10)
if(prob(4))
spawn owner.emote("me", 1, "gasps for air!")
owner.losebreath += 5
/datum/organ/internal/liver
name = "liver"
parent_organ = "chest"
var/process_accuracy = 10
process()
if(owner.life_tick % process_accuracy == 0)
if(src.damage < 0)
src.damage = 0
//High toxins levels are 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/victim = pick(owner.internal_organs)
var/datum/organ/internal/O = owner.internal_organs[victim]
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
// 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"
/datum/organ/internal/eyes
name = "eyes"
parent_organ = "head"
process() //Eye damage replaces the old eye_stat var.
if(is_bruised())
owner.eye_blurry = 20
if(is_broken())
owner.eye_blind = 20
+131
View File
@@ -0,0 +1,131 @@
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/living/carbon/proc/pain(var/partname, var/amount, var/force, var/burning = 0)
if(stat >= 2) return
if(reagents.has_reagent("paracetamol"))
return
if(reagents.has_reagent("tramadol"))
return
if(reagents.has_reagent("oxycodone"))
return
if(analgesic)
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(species && species.flags & NO_PAIN) 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>"
// Anti message spam checks
if(msg && ((msg != last_pain_message) || (world.time >= next_pain_time)))
last_pain_message = msg
src << msg
next_pain_time = world.time + 100
mob/living/carbon/human/proc/handle_pain()
// not when sleeping
if(species && species.flags & NO_PAIN) return
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
if(E.status & ORGAN_DEAD) 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(15 to 25)
toxMessageProb = 3
toxDamageMessage = "Your whole body hurts badly."
if(26 to INFINITY)
toxMessageProb = 5
toxDamageMessage = "Your body aches all over, it's driving you mad."
if(toxDamageMessage && prob(toxMessageProb))
src.custom_pain(toxDamageMessage, getToxLoss() >= 15)
+258
View File
@@ -0,0 +1,258 @@
/****************************************************
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
// ticks of bleeding left.
var/bleed_timer = 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
bleed_timer += damage
// 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
bleed_timer += 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 ((damage > 30 || bleed_timer > 0) && !(bandaged||clamped) && (damage_type == BRUISE && damage >= 20 || damage_type == CUT && damage >= 5) && 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