/**************************************************** BLOOD SYSTEM ****************************************************/ //Blood levels var/const/BLOOD_VOLUME_NORMAL = 560 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(BLOOD_VOLUME_NORMAL + 40) vessel.my_atom = src if(species && species.flags & NO_BLOOD) //We want the var for safety but we can do without the actual blood. return vessel.add_reagent("blood",BLOOD_VOLUME_NORMAL) 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" = WEAKREF(src), "viruses" = null, "species" = species.bodytype, "blood_DNA" = dna.unique_enzymes, "blood_colour" = species.blood_color, "blood_type" = dna.b_type, "resistances" = null, "trace_chem" = null, "virus2" = null, "antibodies" = list() ) B.color = B.data["blood_colour"] // Takes care blood loss and regeneration /mob/living/carbon/human/handle_blood() if(in_stasis) return if(species && species.flags & NO_BLOOD) return if(stat != DEAD && bodytemperature >= 170) //Dead or cryosleep people do not pump the blood. var/blood_volume = round(vessel.get_reagent_amount("blood")) //Blood regeneration if there is some space if(blood_volume < BLOOD_VOLUME_NORMAL && 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(weakref && B.data["donor"] != weakref) //If it's not theirs, then we look for theirs - donor is a weakref here, but it should be safe to just directly compare it. for(var/datum/reagent/blood/D in vessel.reagent_list) if(weakref && D.data["donor"] == weakref) B = D break B.volume += 0.1 // regenerate blood VERY slowly if(CE_BLOODRESTORE in chem_effects) B.volume += chem_effects[CE_BLOODRESTORE] //The heartfix to end all heartfixes if(species && species.has_organ["heart"]) var/obj/item/organ/heart/heart = internal_organs_by_name["heart"] if(!heart) blood_volume = 0 else if (heart.is_damaged()) blood_volume = min(BLOOD_VOLUME_SAFE - 1,blood_volume) blood_volume = (BLOOD_VOLUME_SURVIVE + (BLOOD_VOLUME_NORMAL-BLOOD_VOLUME_SURVIVE) * max(1 - heart.damage/heart.min_broken_damage,0)) * (blood_volume/BLOOD_VOLUME_NORMAL) //Effects of bloodloss if(blood_volume < BLOOD_VOLUME_SAFE && oxyloss < 100 * (1 - blood_volume/BLOOD_VOLUME_NORMAL)) oxyloss += 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") to_chat(src, "You feel [word]...") if(prob(1)) var/word = pick("dizzy","woosey","faint") to_chat(src, "You feel [word]...") if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY) if(!pale) pale = 1 update_body() eye_blurry = max(eye_blurry,6) oxyloss += 1 if(prob(15)) Paralyse(rand(1,3)) var/word = pick("dizzy","woosey","faint") to_chat(src, "You feel extremely [word]...") if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD) oxyloss += 3 toxloss += 3 if(prob(15)) var/word = pick("dizzy","woosey","faint") to_chat(src, "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 and thirsty if(blood_volume <= BLOOD_VOLUME_SAFE) adjustNutritionLoss(7) adjustHydrationLoss(3) //Bleeding out var/blood_max = 0 for(var/obj/item/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 / 40) * species.bleed_mod) if (temp.open) blood_max += 2 * species.bleed_mod //Yer stomach is cut open drip(blood_max) //Makes a blood drop, leaking amt units of blood from the mob /mob/living/carbon/human/proc/drip(var/amt as num) if(species && species.flags & NO_BLOOD) //TODO: Make drips come from the reagents instead. return if(!amt) return vessel.remove_reagent("blood",amt) blood_splatter(src,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"] = WEAKREF(src) if (!B.data["virus2"]) B.data["virus2"] = list() B.data["virus2"] |= virus_copylist(src.virus2) B.data["antibodies"] = src.antibodies B.data["blood_DNA"] = copytext(src.dna.unique_enzymes,1,0) if(src.resistances && src.resistances.len) if(B.data["resistances"]) B.data["resistances"] |= src.resistances.Copy() else B.data["resistances"] = src.resistances.Copy() B.data["blood_type"] = copytext(src.dna.b_type,1,0) // 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"] B.data["species"] = H.species.bodytype var/list/temp_chem = list() for(var/datum/reagent/R in src.reagents.reagent_list) temp_chem += R.id temp_chem[R.id] = R.volume B.data["trace_chem"] = list2params(temp_chem) return B //For humans, blood does not appear from blue, it comes from vessels. /mob/living/carbon/human/take_blood(obj/item/weapon/reagent_containers/container, var/amount) if(species && species.flags & NO_BLOOD) return null if(vessel.get_reagent_amount("blood") < amount) return null . = ..() vessel.remove_reagent("blood",amount) // Removes blood if human //Transfers blood from container ot vessels /mob/living/carbon/proc/inject_blood(var/datum/reagent/blood/injected, var/amount) if (!injected || !istype(injected)) return var/list/sniffles = virus_copylist(injected.data["virus2"]) for(var/ID in sniffles) var/datum/disease2/disease/sniffle = sniffles[ID] infect_virus2(src,sniffle,1) if (injected.data["antibodies"] && prob(5)) antibodies |= injected.data["antibodies"] var/list/chems = list() chems = params2list(injected.data["trace_chem"]) for(var/C in chems) src.reagents.add_reagent(C, (text2num(chems[C]) / BLOOD_VOLUME_NORMAL) * amount)//adds trace chemicals to owner's blood reagents.update_total() //Transfers blood from reagents to vessel, respecting blood types compatability. /mob/living/carbon/human/inject_blood(var/datum/reagent/blood/injected, var/amount) // In case of mobs without blood, put it in their chem storage. if(species.flags & NO_BLOOD) reagents.add_reagent("blood", amount, injected.data) reagents.update_total() return var/datum/reagent/blood/our = get_blood(vessel) if (!injected || !our) return if(blood_incompatible(injected.data["blood_type"],our.data["blood_type"],injected.data["species"],our.data["species"]) && !(mind && mind.vampire)) 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(weakref && res.data["donor"] != weakref) //If it's not theirs, then we look for theirs for(var/datum/reagent/blood/D in container.reagent_list) if(D.data["donor"] == weakref) return D return res proc/blood_incompatible(donor,receiver,donor_species,receiver_species) if(!donor || !receiver) return 0 if(donor_species && receiver_species) if(donor_species != receiver_species) return 1 var/donor_antigen = copytext(donor,1,lentext(donor)) var/receiver_antigen = copytext(receiver,1,lentext(receiver)) var/donor_rh = (findtext(donor,"+")>0) var/receiver_rh = (findtext(receiver,"+")>0) if(donor_rh && !receiver_rh) return 1 switch(receiver_antigen) if("A") if(donor_antigen != "A" && donor_antigen != "O") return 1 if("B") if(donor_antigen != "B" && donor_antigen != "O") return 1 if("O") if(donor_antigen != "O") return 1 //AB is a universal receiver. return 0 proc/blood_splatter(var/target,var/datum/reagent/blood/source,var/large) var/obj/effect/decal/cleanable/blood/B var/decal_type = /obj/effect/decal/cleanable/blood/splatter var/turf/T = get_turf(target) if(istype(source,/mob/living/carbon/human)) var/mob/living/carbon/human/M = source source = M.get_blood(M.vessel) // 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 if(!B) B = new decal_type(T) var/obj/effect/decal/cleanable/blood/drip/drop = B if(istype(drop) && LAZYLEN(drips) && !large) drop.add_overlay(drips) drop.drips |= drips // If there's no data to copy, call it quits here. if(!source) return B // Update appearance. if(source.data["blood_colour"]) B.basecolor = source.data["blood_colour"] B.update_icon() // Update blood information. if(source.data["blood_DNA"]) B.blood_DNA = list() if(source.data["blood_type"]) B.blood_DNA[source.data["blood_DNA"]] = source.data["blood_type"] else B.blood_DNA[source.data["blood_DNA"]] = "O+" // Update virus information. if(source.data["virus2"]) B.virus2 = virus_copylist(source.data["virus2"]) B.fluorescent = 0 B.invisibility = 0 return B