Merge remote-tracking branch 'upstream/master' into disease-controller-bye-bye

This commit is contained in:
Fox-McCloud
2017-07-11 17:13:47 -04:00
174 changed files with 1900 additions and 1726 deletions
+200 -292
View File
@@ -1,87 +1,42 @@
/****************************************************
BLOOD SYSTEM
****************************************************/
/mob/living/carbon/human/var/datum/reagents/vessel //Container for blood and BLOOD ONLY. Do not transfer other chems here.
//Initializes blood vessels
/mob/living/carbon/human/proc/make_blood()
if(vessel)
/mob/living/carbon/human/proc/suppress_bloodloss(amount)
if(bleedsuppress)
return
vessel = new/datum/reagents(max_blood)
vessel.my_atom = src
if(species && species.exotic_blood)
vessel.add_reagent(species.exotic_blood, max_blood)
else
vessel.add_reagent("blood", max_blood)
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_colour" = species.blood_color,
"blood_type" = b_type,
"resistances" = null,
"trace_chem" = null)
spawn(1)
fixblood()
bleedsuppress = 1
spawn(amount)
bleedsuppress = 0
if(stat != DEAD && bleed_rate)
to_chat(src, "<span class='warning'>The blood soaks through your bandage.</span>")
//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_colour" = species.blood_color,
"blood_type" = b_type,
"resistances" = null,
"trace_chem" = null)
// Takes care blood loss and regeneration
/mob/living/carbon/human/proc/handle_blood()
var/blood_volume
if(species && species.flags & NO_BLOOD)
/mob/living/carbon/human/handle_blood()
var/list/blood_data = get_blood_data(get_blood_id())//PROCCEPTION
if(in_stasis)
return
if(stat != DEAD && bodytemperature >= 170) //Dead or cryosleep people do not pump the blood.
if(species.exotic_blood)
var/blood_reagent = species.exotic_blood // This is a string of the name of the species' blood reagent
blood_volume = round(vessel.get_reagent_amount(blood_reagent))
if(blood_volume < max_blood && blood_volume)
vessel.add_reagent(blood_reagent, 0.1) // regenerate blood VERY slowly
if(reagents.has_reagent(blood_reagent))
vessel.add_reagent(blood_reagent, 0.4)
else
blood_volume = round(vessel.get_reagent_amount("blood"))
//Blood regeneration if there is some space
if(blood_volume < max_blood && 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(mind) //Handles vampires "eating" blood that isn't their own.
if(mind in ticker.mode.vampires)
for(var/datum/reagent/blood/BL in vessel.reagent_list)
if(nutrition >= NUTRITION_LEVEL_WELL_FED)
break //We don't want blood tranfusions making vampires fat.
if(BL.data["donor"] != src)
nutrition += (15 * REAGENTS_METABOLISM)
BL.volume -= REAGENTS_METABOLISM
if(BL.volume <= 0)
qdel(BL)
break //Only process one blood per tick, to maintain the same metabolism as nutriment for non-vampires.
if(species && species.flags & NO_BLOOD)
bleed_rate = 0
return
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
if(bodytemperature >= 225 && !(NOCLONE in mutations)) //cryosleep or husked people do not pump the blood.
vessel.add_reagent("blood", 0.1) // regenerate blood VERY slowly
//Blood regeneration if there is some space
if(blood_volume < max_blood && blood_volume)
if(mind) //Handles vampires "eating" blood that isn't their own.
if(mind in ticker.mode.vampires)
if(nutrition >= NUTRITION_LEVEL_WELL_FED)
return //We don't want blood tranfusions making vampires fat.
if(blood_data["donor"] != src)
nutrition += (15 * REAGENTS_METABOLISM)
return //Only process one blood per tick, to maintain the same metabolism as nutriment for non-vampires.
if(blood_volume < BLOOD_VOLUME_NORMAL)
blood_volume += 0.1 // regenerate blood VERY slowly
//Effects of bloodloss
@@ -102,6 +57,7 @@
adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1))
if(prob(5))
EyeBlurry(6)
var/word = pick("dizzy","woozy","faint")
to_chat(src, "<span class='warning'>You feel very [word].</span>")
if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD)
@@ -117,265 +73,217 @@
death()
//Bleeding out
var/blood_max = 0
var/temp_bleed = 0
for(var/obj/item/organ/external/temp in bodyparts)
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
temp_bleed += W.damage / 4
if(temp.open)
blood_max += 2 //Yer stomach is cut open
drip(blood_max)
temp_bleed += 0.5
//Makes a blood drop, leaking certain amount of blood from the mob
/mob/living/carbon/human/proc/drip(var/amt as num)
bleed_rate = max(bleed_rate - 0.5, temp_bleed)//if no wounds, other bleed effects (heparin) naturally decreases
if(species && species.flags & NO_BLOOD) //TODO: Make drips come from the reagents instead.
return
if(bleed_rate && !bleedsuppress)
bleed(bleed_rate)
if(!amt)
return
//Makes a blood drop, leaking amt units of blood from the mob
/mob/living/carbon/proc/bleed(amt)
if(blood_volume)
blood_volume = max(blood_volume - amt, 0)
if(isturf(loc)) //Blood loss still happens in locker, floor stays clean
if(amt >= 10)
add_splatter_floor(loc)
else
add_splatter_floor(loc, 1)
var/amm = 0.1 * amt
var/turf/T = get_turf(src)
/mob/living/carbon/human/bleed(amt)
if(!(species && species.flags & NO_BLOOD))
..()
if(species.exotic_blood)
var/datum/reagent/R = chemical_reagents_list[get_blood_id()]
if(istype(R) && isturf(loc))
R.reaction_turf(get_turf(src), amt)
if(species.exotic_blood)
vessel.remove_reagent(species.exotic_blood,amm)
if(vessel.total_volume)
var/fraction = amm / vessel.total_volume
vessel.reaction(T, TOUCH, fraction)
return
else
vessel.remove_reagent("blood",amm)
blood_splatter(src, src)
/mob/living/proc/restore_blood()
blood_volume = initial(blood_volume)
/mob/living/carbon/human/restore_blood()
blood_volume = BLOOD_VOLUME_NORMAL
bleed_rate = 0
/****************************************************
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(!istype(B, /datum/reagent/blood)) B = new /datum/reagent/blood
B.holder = container
B.volume += amount
//Gets blood from mob to a container or other mob, preserving all data in it.
/mob/living/proc/transfer_blood_to(atom/movable/AM, amount, forced)
if(!blood_volume || !AM.reagents)
return 0
if(blood_volume < BLOOD_VOLUME_BAD && !forced)
return 0
//set reagent data
B.data["donor"] = src
B.data["viruses"] = list()
if(blood_volume < amount)
amount = blood_volume
for(var/thing in viruses)
var/datum/disease/D = thing
B.data["viruses"] += D.Copy()
if(resistances && resistances.len)
B.data["resistances"] = resistances.Copy()
var/blood_id = get_blood_id()
if(!blood_id)
return 0
B.data["blood_DNA"] = copytext(src.dna.unique_enzymes,1,0)
B.data["blood_type"] = copytext(src.dna.b_type,1,0)
blood_volume -= amount
// Putting this here due to return shenanigans.
if(istype(src,/mob/living/carbon/human))
var/mob/living/carbon/human/H = src
B.data["blood_colour"] = H.species.blood_color
B.color = B.data["blood_colour"]
var/list/blood_data = get_blood_data(blood_id)
var/list/temp_chem = list()
for(var/datum/reagent/R in src.reagents.reagent_list)
temp_chem += R.id
temp_chem[R.id] = R.volume
B.data["trace_chem"] = list2params(temp_chem)
if(mind)
B.data["mind"] = mind
if(ckey)
B.data["ckey"] = ckey
if(iscarbon(AM))
var/mob/living/carbon/C = AM
if(blood_id == C.get_blood_id())//both mobs have the same blood substance
if(blood_id == "blood") //normal blood
if(blood_data["viruses"])
for(var/thing in blood_data["viruses"])
var/datum/disease/D = thing
if((D.spread_flags & SPECIAL) || (D.spread_flags & NON_CONTAGIOUS))
continue
C.ForceContractDisease(D)
if(!(blood_data["blood_type"] in get_safe_blood(C.dna.b_type)))
C.reagents.add_reagent("toxin", amount * 0.5)
return 1
if(!suiciding)
B.data["cloneable"] = 1
B.data["gender"] = gender
B.data["real_name"] = real_name
B.data["factions"] = faction
return B
C.blood_volume = min(C.blood_volume + round(amount, 0.1), BLOOD_VOLUME_MAXIMUM)
return 1
//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(src.species.exotic_blood)
if(vessel.get_reagent_amount(src.species.exotic_blood) < amount)
return null
var/datum/reagent/W = new /datum/reagent
W.holder = container
W.volume += amount
AM.reagents.add_reagent(blood_id, amount, blood_data, bodytemperature)
return 1
/mob/living/proc/get_blood_data(blood_id)
return
/mob/living/carbon/human/get_blood_data(blood_id)
if(blood_id == "blood") //actual blood reagent
var/blood_data = list()
//set the blood data
blood_data["donor"] = src
blood_data["viruses"] = list()
for(var/thing in viruses)
var/datum/disease/D = thing
blood_data["viruses"] += D.Copy()
blood_data["blood_DNA"] = copytext(dna.unique_enzymes,1,0)
if(resistances && resistances.len)
blood_data["resistances"] = resistances.Copy()
var/list/temp_chem = list()
for(var/datum/reagent/R in src.reagents.reagent_list)
temp_chem += R.id
for(var/datum/reagent/R in reagents.reagent_list)
temp_chem[R.id] = R.volume
W.data["trace_chem"] = list2params(temp_chem)
vessel.remove_reagent(src.species.exotic_blood,amount) // Removes blood if human
return W
if(species && species.flags & NO_BLOOD)
return null
else
if(vessel.get_reagent_amount("blood") < amount)
return null
. = ..()
vessel.remove_reagent("blood",amount) // Removes blood if human
blood_data["trace_chem"] = list2params(temp_chem)
if(mind)
blood_data["mind"] = mind
if(ckey)
blood_data["ckey"] = ckey
if(!suiciding)
blood_data["cloneable"] = 1
blood_data["blood_type"] = copytext(src.dna.b_type,1,0)
blood_data["gender"] = gender
blood_data["real_name"] = real_name
blood_data["blood_color"] = species.blood_color
blood_data["factions"] = faction
return blood_data
//Transfers blood from container ot vessels
/mob/living/carbon/proc/inject_blood(obj/item/weapon/reagent_containers/container, var/amount)
var/datum/reagent/blood/injected = get_blood(container.reagents)
//get the id of the substance this mob use as blood.
/mob/proc/get_blood_id()
return
if(!istype(injected))
/mob/living/simple_animal/get_blood_id()
if(blood_volume)
return "blood"
/mob/living/carbon/human/get_blood_id()
if(species.exotic_blood)//some races may bleed water..or kethcup..
return species.exotic_blood
else if((species && species.flags & NO_BLOOD) || (NOCLONE in mutations))
return
var/list/chems = list()
chems = params2list(injected.data["trace_chem"])
for(var/C in chems)
src.reagents.add_reagent(C, (text2num(chems[C]) / BLOOD_VOLUME_NORMAL) * amount)//adds trace chemicals to owner's blood
reagents.update_total()
container.reagents.remove_reagent("blood", amount)
//Transfers blood from container ot vessels, respecting blood types compatability.
/mob/living/carbon/human/inject_blood(obj/item/weapon/reagent_containers/container, var/amount)
var/datum/reagent/blood/injected = get_blood(container.reagents)
if(!istype(injected)) //Sanity..
return
if(species && species.flags & NO_BLOOD)
reagents.add_reagent("blood", amount, injected.data)
reagents.update_total()
return
var/datum/reagent/blood/our = get_blood(vessel)
if(!istype(our)) // Do we not have blood?
vessel.add_reagent("blood", amount, injected.data) // This is only ran once, so we need to add back their DNA.
vessel.update_total()
..()
our = get_blood(vessel) // Get the new blood.
our.data["blood_DNA"] = dna.unique_enzymes // Give it the proper DNA we had before (src.dna)
our.data["blood_type"] = dna.b_type // Proper blood type.
our.data["donor"] = src // Without this, it'd be random each time it was extracted or Null.
return
if(blood_incompatible(injected.data["blood_type"],our.data["blood_type"]) )
reagents.add_reagent("toxin",amount * 0.5)
reagents.update_total()
else
vessel.add_reagent("blood", amount, injected.data)
vessel.update_total()
..()
//Gets human's own blood.
/mob/living/carbon/proc/get_blood(datum/reagents/container)
var/datum/reagent/blood/res = locate() in container.reagent_list //Grab some blood
if(res) // Make sure there's some blood at all
if(res.data["donor"] != src) //If it's not theirs, then we look for theirs
for(var/datum/reagent/blood/D in container.reagent_list)
if(D.data["donor"] == src)
return D
return res
/mob/living/carbon/human/get_blood(datum/reagents/container)
if(species.exotic_blood)
return container.get_reagent_from_id(species.exotic_blood)
else
return ..()
/mob/living/carbon/proc/get_blood_name()
return "blood"
/mob/living/carbon/human/get_blood_name()
if(species.exotic_blood)
return species.exotic_blood
else
return ..()
// This is has more potential uses, and is probably faster than the old proc.
/proc/get_safe_blood(bloodtype)
. = list()
if(!bloodtype)
return
switch(bloodtype)
if("A-")
return list("A-", "O-")
if("A+")
return list("A-", "A+", "O-", "O+")
if("B-")
return list("B-", "O-")
if("B+")
return list("B-", "B+", "O-", "O+")
if("AB-")
return list("A-", "B-", "O-", "AB-")
if("AB+")
return list("A-", "A+", "B-", "B+", "O-", "O+", "AB-", "AB+")
if("O-")
return list("O-")
if("O+")
return list("O-", "O+")
/proc/blood_incompatible(donor,receiver)
//to add a splatter of blood or other mob liquid.
/mob/living/proc/add_splatter_floor(turf/T, small_drip)
if(get_blood_id() != "blood")//is it blood or welding fuel?
return
var/donor_antigen = copytext(donor,1,lentext(donor))
var/receiver_antigen = copytext(receiver,1,lentext(receiver))
var/donor_rh = findtext("+",donor)
var/receiver_rh = findtext("+",receiver)
if(!T)
T = get_turf(src)
if(donor_rh && !receiver_rh) return 1
switch(receiver_antigen)
if("A")
if(donor_antigen != "A" && donor_antigen != "O") return 1
if("B")
if(donor_antigen != "B" && donor_antigen != "O") return 1
if("O")
if(donor_antigen != "O") return 1
//AB is a universal receiver.
return 0
var/list/temp_blood_DNA
var/list/b_data = get_blood_data(get_blood_id())
/*
Target: Thing/tile to get bloody
Source: Human or blood reagent
Large: Whether the splat should be big or not
*/
/proc/blood_splatter(var/target,var/source,var/large = 0)
var/obj/effect/decal/cleanable/blood/B
var/decal_type = /obj/effect/decal/cleanable/blood/splatter
var/turf/T = get_turf(target)
var/datum/reagent/blood/bld
if(istype(source,/mob/living/carbon/human))
var/mob/living/carbon/human/H = source
bld = H.get_blood(H.vessel)
if(H.species.exotic_blood)
H.vessel.reaction(T, TOUCH)
if(small_drip)
// Only a certain number of drips (or one large splatter) can be on a given turf.
var/obj/effect/decal/cleanable/blood/drip/drop = locate() in T
if(drop)
if(drop.drips < 3)
drop.drips++
drop.overlays |= pick(drop.random_icon_states)
drop.transfer_mob_blood_dna(src)
drop.basecolor = b_data["blood_color"]
drop.update_icon()
else
temp_blood_DNA = list()
temp_blood_DNA |= drop.blood_DNA.Copy() //we transfer the dna from the drip to the splatter
qdel(drop)
else
drop = new(T)
drop.transfer_mob_blood_dna(src)
drop.basecolor = b_data["blood_color"]
drop.update_icon()
return
else if(H.species.flags & NO_BLOOD)
return
else if(istype(source, /datum/reagent))
bld = source
if(!istype(bld, /datum/reagent/blood))
var/datum/reagent/R = bld
if(istype(R))
R.reaction_turf(T, R.volume)
return
else if(source)
log_runtime(EXCEPTION("Non-human or reagent blood source. Area: [get_area(source)], Name: [source]"), source)
// Are we dripping or splattering?
var/list/drips = list()
// Only a certain number of drips (or one large splatter) can be on a given turf.
for(var/obj/effect/decal/cleanable/blood/drip/drop in T)
drips |= drop.drips
qdel(drop)
if(!large && drips.len < 3)
decal_type = /obj/effect/decal/cleanable/blood/drip
// Find a blood decal or create a new one.
B = locate(decal_type) in T
var/obj/effect/decal/cleanable/blood/B = locate() in T
if(!B)
B = new decal_type(T)
B = new /obj/effect/decal/cleanable/blood/splatter(T)
B.transfer_mob_blood_dna(src) //give blood info to the blood decal.
if(temp_blood_DNA)
B.blood_DNA |= temp_blood_DNA
B.update_icon()
var/obj/effect/decal/cleanable/blood/drip/drop = B
if(istype(drop) && drips && drips.len && !large)
drop.overlays |= drips
drop.drips |= drips
/mob/living/carbon/human/add_splatter_floor(turf/T, small_drip)
if(!(species && species.flags & NO_BLOOD))
..()
// If there's no data to copy, call it quits here.
if(!bld)
return B
/mob/living/carbon/alien/add_splatter_floor(turf/T, small_drip)
if(!T)
T = get_turf(src)
var/obj/effect/decal/cleanable/blood/xeno/B = locate() in T.contents
if(!B)
B = new(T)
B.blood_DNA["UNKNOWN DNA"] = "X*"
// Update appearance.
if(bld.data["blood_colour"])
B.basecolor = bld.data["blood_colour"]
B.update_icon()
// Update blood information.
if(bld.data["blood_DNA"])
B.blood_DNA = list()
if(bld.data["blood_type"])
B.blood_DNA[bld.data["blood_DNA"]] = bld.data["blood_type"]
else
B.blood_DNA[bld.data["blood_DNA"]] = "O+"
return B
/mob/living/silicon/robot/add_splatter_floor(turf/T, small_drip)
if(!T)
T = get_turf(src)
var/obj/effect/decal/cleanable/blood/oil/B = locate() in T.contents
if(!B)
B = new(T)
+3 -2
View File
@@ -32,6 +32,7 @@ var/list/organ_cache = list()
var/sterile = 0 //can the organ be infected by germs?
var/tough = 0 //can organ be easily damaged?
/obj/item/organ/Destroy()
processing_objects.Remove(src)
if(owner)
@@ -316,9 +317,9 @@ var/list/organ_cache = list()
loc = get_turf(owner)
processing_objects |= src
var/datum/reagent/blood/organ_blood
if(reagents) organ_blood = reagents.get_reagent_from_id(owner.get_blood_name())
if(reagents) organ_blood = reagents.get_reagent_from_id(owner.get_blood_id())
if((!organ_blood || !organ_blood.data["blood_DNA"]) && (owner && !(owner.species.flags & NO_BLOOD)))
owner.vessel.trans_to(src, 5, 1, 1)
owner.transfer_blood_to(src)
if(owner && vital && is_primary_organ()) // I'd do another check for species or whatever so that you couldn't "kill" an IPC by removing a human head from them, but it doesn't matter since they'll come right back from the dead
if(user)
@@ -577,9 +577,9 @@ Note that amputating the affected organ does in fact remove the infection from t
var/bicardose = owner.reagents.get_reagent_amount("styptic_powder")
if(!bicardose) //styptic powder stops internal wounds from growing bigger with time, and also stop bleeding
W.open_wound(0.1 * wound_update_accuracy)
owner.vessel.remove_reagent("blood",0.05 * W.damage * wound_update_accuracy)
owner.blood_volume -= (0.05 * W.damage * wound_update_accuracy)
owner.vessel.remove_reagent("blood",0.02 * W.damage * wound_update_accuracy)
owner.blood_volume -= (0.02 * W.damage * wound_update_accuracy)
if(prob(1 * wound_update_accuracy))
owner.custom_pain("You feel a stabbing pain in your [name]!",1)
@@ -744,7 +744,7 @@ Note that amputating the affected organ does in fact remove the infection from t
switch(disintegrate)
if(DROPLIMB_SHARP)
compile_icon()
add_blood(victim)
add_blood(victim.blood_DNA, victim.species.blood_color)
var/matrix/M = matrix()
M.Turn(rand(180))
src.transform = M
+13 -11
View File
@@ -224,10 +224,11 @@
if(world.time > (last_pump + pump_delay))
if(ishuman(owner) && owner.client) //While this entire item exists to make people suffer, they can't control disconnects.
var/mob/living/carbon/human/H = owner
H.vessel.remove_reagent("blood", blood_loss)
to_chat(H, "<span class='userdanger'>You have to keep pumping your blood!</span>")
if(H.client)
H.client.color = "red" //bloody screen so real
if(!(H.species.flags & NO_BLOOD))
H.blood_volume = max(H.blood_volume - blood_loss, 0)
to_chat(H, "<span class='userdanger'>You have to keep pumping your blood!</span>")
if(H.client)
H.client.color = "red" //bloody screen so real
else
last_pump = world.time //lets be extra fair *sigh*
@@ -256,13 +257,14 @@
var/mob/living/carbon/human/H = owner
if(istype(H))
H.vessel.add_reagent("blood", (cursed_heart.blood_loss*0.5))//gain half the blood back from a failure
if(owner.client)
owner.client.color = ""
if(!(H.species.flags & NO_BLOOD))
H.blood_volume = min(H.blood_volume + cursed_heart.blood_loss*0.5, BLOOD_VOLUME_MAXIMUM)
if(owner.client)
owner.client.color = ""
H.adjustBruteLoss(-cursed_heart.heal_brute)
H.adjustFireLoss(-cursed_heart.heal_burn)
H.adjustOxyLoss(-cursed_heart.heal_oxy)
H.adjustBruteLoss(-cursed_heart.heal_brute)
H.adjustFireLoss(-cursed_heart.heal_burn)
H.adjustOxyLoss(-cursed_heart.heal_oxy)
/obj/item/organ/internal/lungs
name = "lungs"
@@ -289,7 +291,7 @@
if(is_bruised())
if(prob(2))
owner.custom_emote(1, "coughs up blood!")
owner.drip(10)
owner.bleed(1)
if(prob(4))
owner.custom_emote(1, "gasps for air!")
owner.AdjustLoseBreath(5)
+1 -1
View File
@@ -244,7 +244,7 @@ var/static/regex/multispin_words = regex("like a record baby")
//BLEED
else if((findtext(message, bleed_words)))
for(var/mob/living/carbon/human/H in listeners)
H.drip(100 * power_multiplier)
H.bleed_rate += (5 * power_multiplier)
next_command = world.time + cooldown_damage
//FIRE