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