diff --git a/baystation12.dme b/baystation12.dme
index 376c9c9989..ed845c859c 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -166,11 +166,6 @@
#include "code\datums\helper_datums\global_iterator.dm"
#include "code\datums\helper_datums\teleport.dm"
#include "code\datums\helper_datums\topic_input.dm"
-#include "code\datums\organs\organ.dm"
-#include "code\datums\organs\organ_external.dm"
-#include "code\datums\organs\organ_internal.dm"
-#include "code\datums\organs\pain.dm"
-#include "code\datums\organs\wound.dm"
#include "code\datums\spells\area_teleport.dm"
#include "code\datums\spells\conjure.dm"
#include "code\datums\spells\dumbfire.dm"
@@ -508,6 +503,7 @@
#include "code\game\objects\items\robot\robot_parts.dm"
#include "code\game\objects\items\robot\robot_upgrades.dm"
#include "code\game\objects\items\stacks\medical.dm"
+#include "code\game\objects\items\stacks\nanopaste.dm"
#include "code\game\objects\items\stacks\rods.dm"
#include "code\game\objects\items\stacks\stack.dm"
#include "code\game\objects\items\stacks\sheets\glass.dm"
@@ -1029,6 +1025,12 @@
#include "code\modules\mob\new_player\preferences_setup.dm"
#include "code\modules\mob\new_player\skill.dm"
#include "code\modules\mob\new_player\sprite_accessories.dm"
+#include "code\modules\organs\blood.dm"
+#include "code\modules\organs\organ.dm"
+#include "code\modules\organs\organ_external.dm"
+#include "code\modules\organs\organ_internal.dm"
+#include "code\modules\organs\pain.dm"
+#include "code\modules\organs\wound.dm"
#include "code\modules\paperwork\clipboard.dm"
#include "code\modules\paperwork\filingcabinet.dm"
#include "code\modules\paperwork\folders.dm"
diff --git a/code/datums/organs/organ.dm b/code/datums/organs/organ.dm
deleted file mode 100644
index 7c219e899b..0000000000
--- a/code/datums/organs/organ.dm
+++ /dev/null
@@ -1,20 +0,0 @@
-/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
-
-
-///datum/organ/proc/process()
-// return 0
-
-///datum/organ/proc/receive_chem(chemical as obj)
-// return 0
-
- proc/process()
- return 0
-
- proc/receive_chem(chemical as obj)
- return 0
diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm
index 311f8d8810..62ed84d34f 100644
--- a/code/game/machinery/iv_drip.dm
+++ b/code/game/machinery/iv_drip.dm
@@ -84,7 +84,7 @@
if(istype(src.beaker, /obj/item/weapon/reagent_containers/blood))
// speed up transfer on blood packs
transfer_amount = 4
- src.beaker.reagents.trans_to(src.attached, transfer_amount)
+ attached.inject_blood(beaker,transfer_amount)
update_icon()
// Take blood
@@ -99,52 +99,23 @@
var/mob/living/carbon/human/T = attached
if(!istype(T)) return
- var/datum/reagent/B
- for(var/datum/reagent/blood/Blood in beaker.reagents.reagent_list)
- if(Blood.data && Blood.data["blood_type"]==T.dna.b_type)
- B = Blood
- break
- if(!B) B = new /datum/reagent/blood
if(!T.dna)
return
if(NOCLONE in T.mutations)
return
+
// If the human is losing too much blood, beep.
if(T.vessel.get_reagent_amount("blood") < BLOOD_VOLUME_SAFE) if(prob(5))
visible_message("\The [src] beeps loudly.")
- if(T.vessel.get_reagent_amount("blood") < amount)
- return
- B.holder = beaker
- B.volume += amount
- //set reagent data
- B.data["donor"] = T
- if(T.virus2)
- B.data["virus2"] = T.virus2.getcopy()
+ var/datum/reagent/B = T.take_blood(beaker,amount)
- B.data["blood_DNA"] = copytext(T.dna.unique_enzymes,1,0)
- if(T.resistances && T.resistances.len)
- if(B.data["resistances"])
- B.data["resistances"] |= T.resistances.Copy()
- else
- B.data["resistances"] = T.resistances.Copy()
-
- B.data["blood_type"] = copytext(T.dna.b_type,1,0)
-
- var/list/temp_chem = list()
- for(var/datum/reagent/R in T.reagents.reagent_list)
- temp_chem += R.name
- temp_chem[R.name] = R.volume
- B.data["trace_chem"] = list2params(temp_chem)
- B.data["antibodies"] |= T.antibodies
-
- T.vessel.remove_reagent("blood",amount) // Removes blood if human
-
- beaker.reagents.reagent_list |= B
- beaker.reagents.update_total()
- beaker.on_reagent_change()
- beaker.reagents.handle_reactions()
- update_icon()
+ if (B)
+ beaker.reagents.reagent_list |= B
+ beaker.reagents.update_total()
+ beaker.on_reagent_change()
+ beaker.reagents.handle_reactions()
+ update_icon()
/obj/machinery/iv_drip/attack_hand(mob/user as mob)
if(src.beaker)
diff --git a/code/game/objects/items/stacks/nanopaste.dm b/code/game/objects/items/stacks/nanopaste.dm
new file mode 100644
index 0000000000..c4697e63b6
--- /dev/null
+++ b/code/game/objects/items/stacks/nanopaste.dm
@@ -0,0 +1,37 @@
+/obj/item/stack/nanopaste
+ name = "nanopaste"
+ singular_name = "nanite swarm"
+ desc = "A tube of paste containing swarms of repair nanties. Very effective in repairing robotic machinery."
+ icon = 'icons/obj/nanopaste.dmi'
+ icon_state = "tube"
+ origin_tech = "materials=4;engineering=3"
+ amount = 10
+
+
+/obj/item/stack/nanopaste/attack(mob/living/M as mob, mob/user as mob)
+ if (!istype(M) || !istype(user))
+ return 0
+ if (istype(M,/mob/living/silicon/robot)) //Repairing cyborgs
+ var/mob/living/silicon/robot/R = M
+ if (R.getBruteLoss() || R.getFireLoss() )
+ R.adjustBruteLoss(-60)
+ R.adjustFireLoss(-60)
+ R.updatehealth()
+ use(1)
+ user.visible_message("You apply some [src] at [R]'s damaged areas.",\
+ "\The [user] applied some [src] at [R]'s damaged areas.")
+ else
+ user << "All [R]'s systems are nominal."
+
+ if (istype(M,/mob/living/carbon/human)) //Repairing robolimbs
+ var/mob/living/carbon/human/H = M
+ var/datum/organ/external/S = H.get_organ(user.zone_sel.selecting)
+ if (S && (S.status & ORGAN_ROBOT))
+ if(S.get_damage())
+ S.heal_damage(30, 30, robo_repair = 1)
+ H.updatehealth()
+ use(1)
+ user.visible_message("You apply some nanite paste at [user == M ? "your" : "[M]'s"] [S.display_name]",\
+ "\The [user] applies some nanite paste at[user != M ? " \the [M]'s" : " \the"][S.display_name] with \the [src]")
+ else
+ user << "Nothing to fix here."
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index e070e84b39..5d1ed6107b 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -5,10 +5,6 @@
icon = 'icons/mob/human.dmi'
icon_state = "body_m_s"
- var/datum/reagents/vessel
- // TODO: make this actually affect the way the mob is rendered
- var/pale = 0
-
/mob/living/carbon/human/dummy
real_name = "Test Dummy"
@@ -24,78 +20,14 @@
if(!dna)
dna = new /datum/dna(null)
- //initialise 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"])
-
- 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
-
..()
if(dna)
dna.real_name = real_name
prev_gender = gender // Debug for plural genders
-
-
- vessel = new/datum/reagents(600)
- vessel.my_atom = src
- vessel.add_reagent("blood",560)
- spawn(1)
- fixblood()
-
-/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)
-
-
-/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)
-
+ make_organs()
+ make_blood()
/mob/living/carbon/human/Bump(atom/movable/AM as mob|obj, yes)
if ((!( yes ) || now_pushing))
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index 72cb8f83cd..d9768992d3 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -47,9 +47,6 @@
var/icon/stand_icon = null
var/icon/lying_icon = null
- var/list/organs = list() //Gets filled up in the constructor (human.dm, New() proc, line 24. I'm sick and tired of missing comments. -Agouri
- var/list/organs_by_name = list() // map organ names to organs
-
var/miming = null //Toggle for the mime's abilities.
var/special_voice = "" // For changing our voice. Used by a symptom.
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 923e75ade4..7ce5d2a454 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -21,11 +21,6 @@
#define COLD_GAS_DAMAGE_LEVEL_2 1.5 //Amount of damage applied when the current breath's temperature passes the 200K point
#define COLD_GAS_DAMAGE_LEVEL_3 3 //Amount of damage applied when the current breath's temperature passes the 120K point
-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/oxygen_alert = 0
var/toxins_alert = 0
@@ -133,98 +128,6 @@ var/const/BLOOD_VOLUME_SURVIVE = 122
/mob/living/carbon/human
- proc/handle_blood()
- // take care of blood and blood loss
- if(stat < 2 && bodytemperature >= 170)
- var/blood_volume = round(vessel.get_reagent_amount("blood"))
- 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
- var/datum/reagent/nutriment/F = locate() in reagents.reagent_list
- if(F != null)
- if(F.volume >= 1)
- // nutriment speeds it up quite a bit
- B.volume += 0.4
- F.volume -= 0.1
- else
- //At this point, we dun care which blood we are adding to, as long as they get more blood.
- B.volume = B.volume + 0.1 // regenerate blood VERY slowly
-
- // 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
-
- 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)
- // hint that they're getting close to suffocation
- 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
-
- 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.
- drip(blood_max)
-
proc/handle_disabilities()
if (disabilities & EPILEPSY)
if ((prob(1) && paralysis < 1))
@@ -291,108 +194,6 @@ var/const/BLOOD_VOLUME_SURVIVE = 122
src << "\red Your legs won't respond properly, you fall down."
lying = 1
- proc/handle_organs()
- // take care of organ related updates, such as broken and missing limbs
-
- // recalculate number of wounds
- number_wounds = 0
- for(var/datum/organ/external/E in organs)
- if(!E)
- world << name
- continue
- number_wounds += E.number_wounds
-
- var/leg_tally = 2
- 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
- for(var/datum/organ/external/E in organs)
- E.process()
- if(E.status & ORGAN_ROBOT && prob(E.brute_dam + E.burn_dam))
- if(E.name == "l_hand" || E.name == "l_arm")
- if(hand && equipped())
- drop_item()
- 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 == "r_hand" || E.name == "r_arm")
- if(!hand && equipped())
- drop_item()
- 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 == "l_leg" || E.name == "l_foot" \
- || E.name == "r_leg" || E.name == "r_foot" && !lying)
- leg_tally-- // let it fail even if just foot&leg
- if(E.status & ORGAN_BROKEN || (E.status & ORGAN_DESTROYED && !E.amputated))
- if(E.name == "l_hand" || E.name == "l_arm")
- if(hand && equipped())
- if(E.status & ORGAN_SPLINTED && prob(10))
- drop_item()
- emote("scream")
- else
- drop_item()
- emote("scream")
- else if(E.name == "r_hand" || E.name == "r_arm")
- if(!hand && equipped())
- if(E.status & ORGAN_SPLINTED && prob(10))
- drop_item()
- emote("scream")
- else
- drop_item()
- emote("scream")
- else if(E.name == "l_leg" || E.name == "l_foot" \
- || E.name == "r_leg" || E.name == "r_foot" && !lying)
- if(!(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/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
-
-
proc/handle_mutations_and_radiation()
if(getFireLoss())
if((COLD_RESISTANCE in mutations) || (prob(1)))
@@ -455,20 +256,14 @@ var/const/BLOOD_VOLUME_SURVIVE = 122
if(reagents.has_reagent("lexorin")) return
if(istype(loc, /obj/machinery/atmospherics/unary/cryo_cell)) return
- var/lung_ruptured = is_lung_ruptured()
-
- if(lung_ruptured && prob(2))
- spawn emote("me", 1, "coughs up blood!")
- src.drip(10)
+ var/datum/organ/internal/lungs/L = internal_organs["lungs"]
+ L.process()
var/datum/gas_mixture/environment = loc.return_air()
var/datum/gas_mixture/breath
// HACK NEED CHANGING LATER
if(health < 0)
losebreath++
- if(lung_ruptured && prob(4))
- spawn emote("me", 1, "gasps for air!")
- losebreath += 5
if(losebreath>0) //Suffocating so do not take a breath
losebreath--
if (prob(10)) //Gasp per 10 ticks? Sounds about right.
@@ -498,7 +293,7 @@ var/const/BLOOD_VOLUME_SURVIVE = 122
breath = loc.remove_air(breath_moles)
- if(!lung_ruptured)
+ if(!is_lung_ruptured())
if(!breath || breath.total_moles < BREATH_MOLES / 5 || breath.total_moles > BREATH_MOLES * 5)
if(prob(5))
rupture_lung()
@@ -1061,34 +856,10 @@ var/const/BLOOD_VOLUME_SURVIVE = 122
dizziness = max(0, dizziness - 3)
jitteriness = max(0, jitteriness - 3)
+ handle_trace_chems()
- if(life_tick % 10 == 0)
- // handle trace chemicals for autopsy
- for(var/datum/organ/O in organs)
- for(var/chemID in O.trace_chemicals)
- O.trace_chemicals[chemID] = O.trace_chemicals[chemID] - 1
- if(O.trace_chemicals[chemID] <= 0)
- O.trace_chemicals.Remove(chemID)
- for(var/datum/reagent/A in reagents.reagent_list)
- // add chemistry traces to a random organ
- var/datum/organ/O = pick(organs)
- O.trace_chemicals[A.name] = 100
-
- var/damaged_liver_process_accuracy = 10
- if(life_tick % damaged_liver_process_accuracy == 0)
- // Damaged liver means some chemicals are very dangerous
- var/datum/organ/internal/liver/liver = internal_organs["liver"]
- if(liver.damage >= liver.min_bruised_damage)
- for(var/datum/reagent/R in src.reagents.reagent_list)
- // Ethanol and all drinks are bad
- if(istype(R, /datum/reagent/ethanol))
- adjustToxLoss(0.1 * damaged_liver_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(src.reagents.has_reagent(toxin))
- adjustToxLoss(0.3 * damaged_liver_process_accuracy)
-
+ var/datum/organ/internal/liver/liver = internal_organs["liver"]
+ liver.process()
updatehealth()
diff --git a/code/modules/organs/blood.dm b/code/modules/organs/blood.dm
new file mode 100644
index 0000000000..6764da2e28
--- /dev/null
+++ b/code/modules/organs/blood.dm
@@ -0,0 +1,213 @@
+/****************************************************
+ 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
+ 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)
+
+// 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.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"]
+ 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)
+
+//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)
+
+/****************************************************
+ 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(src.virus2)
+ B.data["virus2"] = src.virus2.getcopy()
+ 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.name
+ temp_chem[R.name] = 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(vessel.get_reagent_amount("blood") < amount)
+ return null
+ . = ..()
+ vessel.remove_reagent("blood",amount) // Removes blood if human
+
+//Transfers blood from container ot vessels, respecting blood types compatability.
+/mob/living/carbon/human/proc/inject_blood(obj/item/weapon/reagent_containers/container, var/amount)
+ var/datum/reagent/blood/our = get_blood(vessel)
+ var/datum/reagent/blood/injected = get_blood(container.reagents)
+
+ 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)
+ vessel.update_total()
+
+ container.reagents.remove_reagent("blood", amount)
+
+//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
\ No newline at end of file
diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm
new file mode 100644
index 0000000000..e0d73cfdbb
--- /dev/null
+++ b/code/modules/organs/organ.dm
@@ -0,0 +1,148 @@
+/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()
+ 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
diff --git a/code/datums/organs/organ_external.dm b/code/modules/organs/organ_external.dm
similarity index 95%
rename from code/datums/organs/organ_external.dm
rename to code/modules/organs/organ_external.dm
index 31dc038c2c..8e646c830f 100644
--- a/code/datums/organs/organ_external.dm
+++ b/code/modules/organs/organ_external.dm
@@ -1,825 +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 ..()
-
-/datum/organ/external/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
-
-/****************************************************
- 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 4 ticks to save processing power
- if(owner.life_tick % wound_update_accuracy == 0)
- update_wounds()
-
- //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 << "You can't feel your [display_name] anymore..."
- 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
- 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
-
- number_wounds += W.amount
-
-
-// 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 Your [display_name] explodes!",\
- "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.",\
- "Your [display_name] goes flying off!",\
- "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 Something feels like it shattered in your [display_name]!","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 Your face becomes unrecognizible mangled mess!", \
- "\red You hear a sickening crack.")
- else
- owner.visible_message("\red [owner]'s face melts away, turning into mangled mess!", \
- "\red Your face melts off!", \
- "\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
-
-
-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()]\] Debrained [brainmob.name] ([brainmob.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])"
- brainmob.attack_log += "\[[time_stamp()]\] Debrained by [user.name] ([user.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])"
- 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
- ..()
+/****************************************************
+ 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 << "You can't feel your [display_name] anymore..."
+ 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 Your [display_name] explodes!",\
+ "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.",\
+ "Your [display_name] goes flying off!",\
+ "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 Something feels like it shattered in your [display_name]!","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 Your face becomes unrecognizible mangled mess!", \
+ "\red You hear a sickening crack.")
+ else
+ owner.visible_message("\red [owner]'s face melts away, turning into mangled mess!", \
+ "\red Your face melts off!", \
+ "\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()]\] Debrained [brainmob.name] ([brainmob.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])"
+ brainmob.attack_log += "\[[time_stamp()]\] Debrained by [user.name] ([user.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])"
+ 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
+ ..()
diff --git a/code/datums/organs/organ_internal.dm b/code/modules/organs/organ_internal.dm
similarity index 50%
rename from code/datums/organs/organ_internal.dm
rename to code/modules/organs/organ_internal.dm
index 38599ec3cb..431804dd98 100644
--- a/code/datums/organs/organ_internal.dm
+++ b/code/modules/organs/organ_internal.dm
@@ -1,120 +1,83 @@
-/****************************************************
- INTERNAL ORGANS
-****************************************************/
-
-/*
-/datum/organ/internal
- name = "internal"
- var/damage = 0
- var/max_damage = 100
-
-/datum/organ/internal/skeleton
- name = "spooky scary skeleton"
- max_damage = 200
-
-/datum/organ/internal/skin
- name = "skin"
- max_damage = 100
-
-/datum/organ/internal/blood_vessels
- name = "blood vessels"
- var/heart = null
- var/lungs = null
- var/kidneys = null
-
-/datum/organ/internal/brain
- name = "brain"
- var/head = null
-
-/datum/organ/internal/excretory
- name = "excretory"
- var/excretory = 7.0
- var/blood_vessels = null
-
-/datum/organ/internal/heart
- name = "heart"
-
-/datum/organ/internal/immune_system
- name = "immune system"
- var/blood_vessels = null
- var/isys = null
-
-/datum/organ/internal/intestines
- name = "intestines"
- var/intestines = 3.0
- var/blood_vessels = null
-
-/datum/organ/internal/liver
- name = "liver"
- var/intestines = null
- var/blood_vessels = null
-
-/datum/organ/internal/lungs
- name = "lungs"
- var/lungs = 3.0
- var/throat = null
- var/blood_vessels = null
-
-/datum/organ/internal/stomach
- name = "stomach"
- var/intestines = null
-
-/datum/organ/internal/throat
- name = "throat"
- var/lungs = null
- var/stomach = null
-
-*/
-
-/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)
-
-/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"
-
-
-/datum/organ/internal/kidney
- name = "kidney"
- parent_organ = "chest"
-
-/datum/organ/internal/brain
- name = "brain"
+/****************************************************
+ 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"
+
+ 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)
+ // 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"
\ No newline at end of file
diff --git a/code/datums/organs/pain.dm b/code/modules/organs/pain.dm
similarity index 97%
rename from code/datums/organs/pain.dm
rename to code/modules/organs/pain.dm
index 0b9158eff1..3452b0795f 100644
--- a/code/datums/organs/pain.dm
+++ b/code/modules/organs/pain.dm
@@ -101,7 +101,7 @@ mob/living/carbon/human/proc/handle_pain()
if(11 to 15)
toxMessageProb = 2
toxDamageMessage = "Your whole body hurts."
- else
+ if(91 to 10000)
toxMessageProb = 5
toxDamageMessage = "Your body aches all over, it's driving you mad."
diff --git a/code/datums/organs/wound.dm b/code/modules/organs/wound.dm
similarity index 100%
rename from code/datums/organs/wound.dm
rename to code/modules/organs/wound.dm
diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/Chemistry-Holder.dm
index 2bae324b69..b274e09ffd 100644
--- a/code/modules/reagents/Chemistry-Holder.dm
+++ b/code/modules/reagents/Chemistry-Holder.dm
@@ -107,30 +107,9 @@ datum
var/current_reagent_transfer = current_reagent.volume * part
if(preserve_data)
trans_data = current_reagent.data
- if(current_reagent.id == "blood" && ishuman(target)) // can never be sure
- var/mob/living/carbon/human/H = target
- var/datum/reagent/blood/HisBlood = locate() in H.vessel.reagent_list //Grab some blood
- if(HisBlood) // Make sure there's some blood at all
- if(HisBlood.data["donor"] != H) //If it's not theirs, then we look for theirs
- for(var/datum/reagent/blood/D in H.vessel.reagent_list)
- if(D.data["donor"] == H)
- HisBlood = D
- break
- if(HisBlood && HisBlood.data && trans_data)
- if(blood_incompatible(trans_data["blood_type"],HisBlood.data["blood_type"]))
- H.reagents.add_reagent("toxin",(current_reagent_transfer * multiplier * 0.5))
- H.reagents.update_total()
- else
- H.vessel.add_reagent(current_reagent.id, (current_reagent_transfer * multiplier), trans_data)
- H.vessel.update_total()
- else
- H.vessel.add_reagent(current_reagent.id, (current_reagent_transfer * multiplier), trans_data)
- H.vessel.update_total()
- src.remove_reagent(current_reagent.id, current_reagent_transfer)
- else
- R.add_reagent(current_reagent.id, (current_reagent_transfer * multiplier), trans_data)
- src.remove_reagent(current_reagent.id, current_reagent_transfer)
+ R.add_reagent(current_reagent.id, (current_reagent_transfer * multiplier), trans_data)
+ src.remove_reagent(current_reagent.id, current_reagent_transfer)
src.update_total()
R.update_total()
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index 5fd09ddc4a..6edc909cd8 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -80,57 +80,20 @@
if(istype(target, /mob/living/carbon))//maybe just add a blood reagent to all mobs. Then you can suck them dry...With hundreds of syringes. Jolly good idea.
var/amount = src.reagents.maximum_volume - src.reagents.total_volume
var/mob/living/carbon/T = target
- var/datum/reagent/B = new /datum/reagent/blood
if(!T.dna)
usr << "You are unable to locate any blood. (To be specific, your target seems to be missing their DNA datum)"
return
if(NOCLONE in T.mutations) //target done been et, no more blood in him
user << "\red You are unable to locate any blood."
return
- if(ishuman(T))
- if(T:vessel.get_reagent_amount("blood") < amount)
- return
- B.holder = src
- B.volume = amount
- //set reagent data
- B.data["donor"] = T
- /*
- if(T.virus && T.virus.spread_type != SPECIAL)
- B.data["virus"] = new T.virus.type(0)
- */
+ var/datum/reagent/B = T.take_blood(src,amount)
-
- for(var/datum/disease/D in T.viruses)
- if(!B.data["viruses"])
- B.data["viruses"] = list()
-
-
- B.data["viruses"] += new D.type(0, D, 1)
-
- if(T.virus2)
- B.data["virus2"] = T.virus2.getcopy()
-
- B.data["blood_DNA"] = copytext(T.dna.unique_enzymes,1,0)
- if(T.resistances&&T.resistances.len)
- B.data["resistances"] = T.resistances.Copy()
- if(istype(target, /mob/living/carbon/human))//I wish there was some hasproperty operation...
- var/mob/living/carbon/human/HT = target
- B.data["blood_type"] = copytext(HT.dna.b_type,1,0)
- var/list/temp_chem = list()
- for(var/datum/reagent/R in target.reagents.reagent_list)
- temp_chem += R.name
- temp_chem[R.name] = R.volume
- B.data["trace_chem"] = list2params(temp_chem)
- B.data["antibodies"] = T.antibodies
-
- if(ishuman(T))
- T:vessel.remove_reagent("blood",amount) // Removes blood if human
-
- src.reagents.reagent_list += B
- src.reagents.update_total()
- src.on_reagent_change()
- src.reagents.handle_reactions()
+ if (B)
+ src.reagents.reagent_list += B
+ src.reagents.update_total()
+ src.on_reagent_change()
+ src.reagents.handle_reactions()
user << "\blue You take a blood sample from [target]"
for(var/mob/O in viewers(4, user))
O.show_message("\red [user] takes a blood sample from [target].", 1)
@@ -182,9 +145,7 @@
var/trans
if(B && ishuman(target))
var/mob/living/carbon/human/H = target
- trans = B.volume > 5? 5 : B.volume
- H.vessel.add_reagent("blood",trans,B.data)
- src.reagents.remove_reagent("blood",trans)
+ H.inject_blood(src,5)
else
trans = src.reagents.trans_to(target, amount_per_transfer_from_this)
user << "\blue You inject [trans] units of the solution. The syringe now contains [src.reagents.total_volume] units."
diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm
index 0fd82e0b38..f1a4e8b683 100644
--- a/code/modules/research/designs.dm
+++ b/code/modules/research/designs.dm
@@ -1321,6 +1321,14 @@ datum/design/synthetic_flash
build_path = "/obj/item/device/flash/synthetic"
category = "Misc"
+datum/design/nanopaste
+ name = "nanopaste"
+ desc = "A tube of paste containing swarms of repair nanties. Very effective in repairing robotic machinery."
+ id = "nanopaste"
+ req_tech = list("materials" = 4, "engineering" = 3)
+ build_type = PROTOLATHE
+ materials = list("$metal" = 7000, "$glass" = 7000)
+ build_path = "/obj/item/stack/nanopaste"
/////////////////////////////////////////
/////////////////Weapons/////////////////
/////////////////////////////////////////
diff --git a/icons/obj/nanopaste.dmi b/icons/obj/nanopaste.dmi
new file mode 100644
index 0000000000..b3c096325f
Binary files /dev/null and b/icons/obj/nanopaste.dmi differ