diff --git a/code/__DEFINES/genetics.dm b/code/__DEFINES/genetics.dm index 4cf307dbf34..44057453814 100644 --- a/code/__DEFINES/genetics.dm +++ b/code/__DEFINES/genetics.dm @@ -91,3 +91,12 @@ #define NUTRITION_LEVEL_FED 350 #define NUTRITION_LEVEL_HUNGRY 250 #define NUTRITION_LEVEL_STARVING 150 + +//Blood levels +#define BLOOD_VOLUME_MAXIMUM 2000 +#define BLOOD_VOLUME_SLIME_SPLIT 1120 +#define BLOOD_VOLUME_NORMAL 560 +#define BLOOD_VOLUME_SAFE 501 +#define BLOOD_VOLUME_OKAY 336 +#define BLOOD_VOLUME_BAD 224 +#define BLOOD_VOLUME_SURVIVE 122 diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index d981f93f573..19a1dcf84e1 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -64,9 +64,11 @@ if(apply_damage(I.force, I.damtype)) if(I.damtype == BRUTE) if(prob(33)) + I.add_mob_blood(src) var/turf/location = get_turf(src) - location.add_blood_floor(src) - + add_splatter_floor(location) + if(get_dist(user, src) <= 1) //people with TK won't get smeared with blood + user.add_mob_blood(src) // Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person. diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 4a2c0a330ee..3702069a3cc 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -226,37 +226,73 @@ var/list/blood_splatter_icons = list() /atom/proc/blood_splatter_index() return "\ref[initial(icon)]-[initial(icon_state)]" -/atom/proc/add_blood_list(mob/living/carbon/M) +//returns the mob's dna info as a list, to be inserted in an object's blood_DNA list +/mob/living/proc/get_blood_dna_list() + if(get_blood_id() != "blood") + return + return list("ANIMAL DNA" = "Y-") + +/mob/living/carbon/get_blood_dna_list() + if(get_blood_id() != "blood") + return + var/list/blood_dna = list() + if(dna) + blood_dna[dna.unique_enzymes] = dna.blood_type + else + blood_dna["UNKNOWN DNA"] = "X*" + return blood_dna + +/mob/living/carbon/alien/get_blood_dna_list() + return list("UNKNOWN DNA" = "X*") + +//to add a mob's dna info into an object's blood_DNA list. +/atom/proc/transfer_mob_blood_dna(mob/living/L) // Returns 0 if we have that blood already - if(!istype(blood_DNA, /list)) //if our list of DNA doesn't exist yet (or isn't a list) initialise it. + var/new_blood_dna = L.get_blood_dna_list() + if(!new_blood_dna) + return 0 + if(!blood_DNA) //if our list of DNA doesn't exist yet, initialise it. blood_DNA = list() - //if this blood isn't already in the list, add it - if(blood_DNA[M.dna.unique_enzymes]) - return 0 //already bloodied with this blood. Cannot add more. - blood_DNA[M.dna.unique_enzymes] = M.dna.blood_type + var/old_length = blood_DNA.len + blood_DNA |= new_blood_dna + if(blood_DNA.len == old_length) + return 0 return 1 -//returns 1 if made bloody, returns 0 otherwise -/atom/proc/add_blood(mob/living/carbon/M) - if(!M || !M.has_dna() || rejects_blood()) - return 0 - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(NOBLOOD in H.dna.species.specflags) - return 0 - return 1 +//to add blood dna info to the object's blood_DNA list +/atom/proc/transfer_blood_dna(list/blood_dna) + if(!blood_DNA) + blood_DNA = list() + var/old_length = blood_DNA.len + blood_DNA |= blood_dna + if(blood_DNA.len > old_length) + return 1//some new blood DNA was added -/obj/add_blood(mob/living/carbon/M) - if(!..()) - return 0 - return add_blood_list(M) -/obj/item/add_blood(mob/living/carbon/M) +//to add blood from a mob onto something, and transfer their dna info +/atom/proc/add_mob_blood(mob/living/M) + var/list/blood_dna = M.get_blood_dna_list() + if(!blood_dna) + return 0 + return add_blood(blood_dna) + +//to add blood onto something, with blood dna info to include. +/atom/proc/add_blood(list/blood_dna) + return 0 + +/obj/add_blood(list/blood_dna) + return transfer_blood_dna(blood_dna) + +/obj/item/add_blood(list/blood_dna) var/blood_count = !blood_DNA ? 0 : blood_DNA.len if(!..()) return 0 - //apply the blood-splatter overlay if it isn't already in there - if(!blood_count && initial(icon) && initial(icon_state)) + if(!blood_count)//apply the blood-splatter overlay if it isn't already in there + add_blood_overlay() + return 1 //we applied blood to the item + +/obj/item/proc/add_blood_overlay() + if(initial(icon) && initial(icon_state)) //try to find a pre-processed blood-splatter. otherwise, make a new one var/index = blood_splatter_index() var/icon/blood_splatter_icon = blood_splatter_icons[index] @@ -267,56 +303,33 @@ var/list/blood_splatter_icons = list() blood_splatter_icon = fcopy_rsc(blood_splatter_icon) blood_splatter_icons[index] = blood_splatter_icon overlays += blood_splatter_icon - return 1 //we applied blood to the item -/obj/item/clothing/gloves/add_blood(mob/living/carbon/M) - if(!..()) - return 0 +/obj/item/clothing/gloves/add_blood(list/blood_dna) + . = ..() transfer_blood = rand(2, 4) - bloody_hands_mob = M - return 1 -/turf/add_blood(mob/living/carbon/human/M) - if(!..()) - return 0 - - var/obj/effect/decal/cleanable/blood/B = locate() in contents //check for existing blood splatter +/turf/add_blood(list/blood_dna) + var/obj/effect/decal/cleanable/blood/splatter/B = locate() in src if(!B) - blood_splatter(src,M.get_blood(M.vessel),1) - B = locate(/obj/effect/decal/cleanable/blood) in contents - B.add_blood_list(M) + B = new /obj/effect/decal/cleanable/blood/splatter(src) + B.transfer_blood_dna(blood_dna) //give blood info to the blood decal. return 1 //we bloodied the floor -/mob/living/carbon/human/add_blood(mob/living/carbon/M) - if(!..()) - return 0 - add_blood_list(M) +/mob/living/carbon/human/add_blood(list/blood_dna) + if(wear_suit) + wear_suit.add_blood(blood_dna) + update_inv_wear_suit() + else if(w_uniform) + w_uniform.add_blood(blood_dna) + update_inv_w_uniform() + if(gloves) + var/obj/item/clothing/gloves/G = gloves + G.add_blood(blood_dna) + else + transfer_blood_dna(blood_dna) bloody_hands = rand(2, 4) - bloody_hands_mob = M update_inv_gloves() //handles bloody hands overlays and updating - return 1 //we applied blood to the item - -/atom/proc/rejects_blood() - return 0 - -// Only adds blood on the floor -- Skie -/atom/proc/add_blood_floor(mob/living/carbon/M) - if(istype(src, /turf)) - if(M.has_dna()) //mobs with dna = (monkeys + humans at time of writing) - var/obj/effect/decal/cleanable/blood/B = locate() in contents - if(!B) - blood_splatter(src,M,1) - B = locate(/obj/effect/decal/cleanable/blood) in contents - B.blood_DNA[M.dna.unique_enzymes] = M.dna.blood_type - else if(istype(M, /mob/living/carbon/alien)) - var/obj/effect/decal/cleanable/xenoblood/B = locate() in contents - if(!B) - B = new(src) - B.blood_DNA["UNKNOWN BLOOD"] = "X*" - else if(istype(M, /mob/living/silicon/robot)) - var/obj/effect/decal/cleanable/oil/B = locate() in contents - if(!B) - B = new(src) + return 1 /atom/proc/clean_blood() if(istype(blood_DNA, /list)) diff --git a/code/game/gamemodes/changeling/powers/mutations.dm b/code/game/gamemodes/changeling/powers/mutations.dm index 1dc79ffc084..7d50aca1ee6 100644 --- a/code/game/gamemodes/changeling/powers/mutations.dm +++ b/code/game/gamemodes/changeling/powers/mutations.dm @@ -96,10 +96,8 @@ H.update_hair() if(blood_on_castoff) - var/turf/T = get_turf(H) - if(istype(T)) - T.add_blood(H) //So real blood decals - playsound(H.loc, 'sound/effects/splat.ogg', 50, 1) //So real sounds + H.add_splatter_floor() + playsound(H.loc, 'sound/effects/splat.ogg', 50, 1) //So real sounds changeling.geneticdamage += genetic_damage //Casting off a space suit leaves you weak for a few seconds. changeling.chem_recharge_slowdown -= recharge_slowdown diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm index 73ec9b1982c..5607b1f6bdf 100644 --- a/code/game/gamemodes/cult/cult_items.dm +++ b/code/game/gamemodes/cult/cult_items.dm @@ -45,9 +45,9 @@ /obj/item/weapon/melee/cultblade/dagger/attack(mob/living/target, mob/living/carbon/human/user) ..() - if(ishuman(target)) - var/mob/living/carbon/human/H = target - H.drip(50) + if(iscarbon(target)) + var/mob/living/carbon/C = target + C.bleed(50) /obj/item/weapon/restraints/legcuffs/bola/cult diff --git a/code/game/gamemodes/miniantags/abduction/gland.dm b/code/game/gamemodes/miniantags/abduction/gland.dm index 537f29f3551..74e592ba826 100644 --- a/code/game/gamemodes/miniantags/abduction/gland.dm +++ b/code/game/gamemodes/miniantags/abduction/gland.dm @@ -191,14 +191,9 @@ "Blood pours from your skin!") for(var/turf/T in oview(3,owner)) //Make this respect walls and such - T.add_blood_floor(owner) + owner.add_splatter_floor(T) for(var/mob/living/carbon/human/H in oview(3,owner)) //Blood decals for simple animals would be neat. aka Carp with blood on it. - if(H.wear_suit) - H.wear_suit.add_blood(owner) - H.update_inv_wear_suit(0) - else if(H.w_uniform) - H.w_uniform.add_blood(owner) - H.update_inv_w_uniform(0) + H.add_mob_blood(owner) /obj/item/organ/gland/bodysnatch origin_tech = "materials=4;biotech=7;abductor=3" diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm index 1213bfe6ca5..3f8d58b7377 100644 --- a/code/game/gamemodes/wizard/artefact.dm +++ b/code/game/gamemodes/wizard/artefact.dm @@ -419,7 +419,7 @@ var/global/list/multiverse = list() M.equip_to_slot_or_del(sword, slot_r_hand) for(var/obj/item/carried_item in M.contents) if(!istype(carried_item, /obj/item/weapon/implant)) - carried_item.add_blood(M) + carried_item.add_mob_blood(M) if("pirate") M.equip_to_slot_or_del(new /obj/item/clothing/under/pirate(M), slot_w_uniform) diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm index 51c0c3e8264..4de92482f3b 100644 --- a/code/game/machinery/computer/medical.dm +++ b/code/game/machinery/computer/medical.dm @@ -563,35 +563,31 @@ return /obj/machinery/computer/med_data/emp_act(severity) - if(stat & (BROKEN|NOPOWER)) - ..(severity) - return + if(!(stat & (BROKEN|NOPOWER))) + for(var/datum/data/record/R in data_core.medical) + if(prob(10/severity)) + switch(rand(1,6)) + if(1) + if(prob(10)) + R.fields["name"] = random_unique_lizard_name(R.fields["sex"],1) + else + R.fields["name"] = random_unique_name(R.fields["sex"],1) + if(2) + R.fields["sex"] = pick("Male", "Female") + if(3) + R.fields["age"] = rand(AGE_MIN, AGE_MAX) + if(4) + R.fields["blood_type"] = random_blood_type() + if(5) + R.fields["p_stat"] = pick("*Unconcious*", "Active", "Physically Unfit") + if(6) + R.fields["m_stat"] = pick("*Insane*", "*Unstable*", "*Watch*", "Stable") + continue - for(var/datum/data/record/R in data_core.medical) - if(prob(10/severity)) - switch(rand(1,6)) - if(1) - if(prob(10)) - R.fields["name"] = random_unique_lizard_name(R.fields["sex"],1) - else - R.fields["name"] = random_unique_name(R.fields["sex"],1) - if(2) - R.fields["sex"] = pick("Male", "Female") - if(3) - R.fields["age"] = rand(AGE_MIN, AGE_MAX) - if(4) - R.fields["blood_type"] = random_blood_type() - if(5) - R.fields["p_stat"] = pick("*Unconcious*", "Active", "Physically Unfit") - if(6) - R.fields["m_stat"] = pick("*Insane*", "*Unstable*", "*Watch*", "Stable") - continue - - else if(prob(1)) - qdel(R) - continue - - ..(severity) + else if(prob(1)) + qdel(R) + continue + ..() /obj/machinery/computer/med_data/proc/canUseMedicalRecordsConsole(mob/user, message = 1, record1, record2) if(user) diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 015c78b195a..5ff956d30dc 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -307,7 +307,7 @@ obj/machinery/door/proc/try_to_crowbar(obj/item/I, mob/user) L.adjustBruteLoss(DOOR_CRUSH_DAMAGE) var/turf/location = get_turf(src) //add_blood doesn't work for borgs/xenos, but add_blood_floor does. - location.add_blood_floor(L) + L.add_splatter_floor(location) for(var/obj/mecha/M in get_turf(src)) M.take_damage(DOOR_CRUSH_DAMAGE) diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm index c47bc00617d..a6ef761b884 100644 --- a/code/game/machinery/iv_drip.dm +++ b/code/game/machinery/iv_drip.dm @@ -4,7 +4,7 @@ icon_state = "iv_drip" anchored = 0 density = 1 - var/mob/living/carbon/human/attached = null + var/mob/living/carbon/attached = null var/mode = 1 // 1 is injecting, 0 is taking blood. var/obj/item/weapon/reagent_containers/beaker = null @@ -65,8 +65,8 @@ update_icon() return - if(!ishuman(target)) - usr << "The drip beeps: Warning, human patients only!" + if(!target.has_dna()) + usr << "The drip beeps: Warning, incompatible creature!" return if(Adjacent(target) && usr.Adjacent(target)) @@ -129,36 +129,15 @@ if(prob(5)) visible_message("\The [src] pings.") return - var/mob/living/carbon/human/T = attached - - if(!istype(T)) - return - - if(T.disabilities & NOCLONE) - return - - if((NOBLOOD in T.dna.species.specflags) && !T.dna.species.exotic_blood) - return - - if(T.dna.species.exotic_blood) - T.reagents.trans_to(beaker, amount) - update_icon() - else - // If the human is losing too much blood, beep. - if(T.vessel.get_reagent_amount("blood") < BLOOD_VOLUME_SAFE && prob(5)) - visible_message("\The [src] beeps loudly.") - playsound(loc, 'sound/machines/twobeep.ogg', 50, 1) - var/datum/reagent/B = T.take_blood(beaker,amount) - - if (B) - beaker.reagents.reagent_list |= B - beaker.reagents.update_total() - beaker.on_reagent_change() - beaker.reagents.handle_reactions() - update_icon() + // If the human is losing too much blood, beep. + if(attached.blood_volume < BLOOD_VOLUME_SAFE && prob(5)) + visible_message("\The [src] beeps loudly.") + playsound(loc, 'sound/machines/twobeep.ogg', 50, 1) + attached.transfer_blood_to(beaker, amount) + update_icon() /obj/machinery/iv_drip/attack_hand(mob/user) - if (!ishuman(user)) + if(!ishuman(user)) return if(attached) visible_message("[attached] is detached from \the [src]") diff --git a/code/game/machinery/pipe/construction.dm b/code/game/machinery/pipe/construction.dm index 05915bc884c..2d125831b43 100644 --- a/code/game/machinery/pipe/construction.dm +++ b/code/game/machinery/pipe/construction.dm @@ -248,9 +248,7 @@ var/global/list/pipeID2State = list( for(var/i=1 to 20) C.vomit(0,1,0,4,0) sleep(5) - if(istype(user, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = C - H.vessel.remove_reagent("blood",560) + C.blood_volume = 0 return(OXYLOSS|BRUTELOSS) else return ..() diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm index 4b37378f666..21db6aeb7cc 100644 --- a/code/game/machinery/recycler.dm +++ b/code/game/machinery/recycler.dm @@ -169,7 +169,7 @@ var/const/SAFETY_COOLDOWN = 100 gib = FALSE if(L.stat == CONSCIOUS) L.say("ARRRRRRRRRRRGH!!!") - add_blood(L) + add_mob_blood(L) if(!blood && !issilicon(L)) blood = TRUE diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm index e6e90cbde1c..4c679597d97 100644 --- a/code/game/objects/effects/decals/Cleanable/humans.dm +++ b/code/game/objects/effects/decals/Cleanable/humans.dm @@ -3,7 +3,7 @@ desc = "It's red and gooey. Perhaps it's the chef's cooking?" gender = PLURAL density = 0 - layer = ABOVE_OPEN_TURF_LAYER + layer = ABOVE_NORMAL_TURF_LAYER icon = 'icons/effects/blood.dmi' icon_state = "floor1" random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7") @@ -106,12 +106,8 @@ icon_state = "1" random_icon_states = list("1","2","3","4","5") bloodiness = 0 - var/list/drips = list() + var/drips = 1 -/obj/effect/decal/cleanable/blood/drip/New() - ..() - spawn(1) - drips |= icon_state /obj/effect/decal/cleanable/blood/drip/can_bloodcrawl_in() return 1 diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm index 548ade544e2..9a24696cc87 100644 --- a/code/game/objects/effects/decals/cleanable.dm +++ b/code/game/objects/effects/decals/cleanable.dm @@ -70,6 +70,8 @@ add_blood = bloodiness bloodiness -= add_blood S.bloody_shoes[blood_state] = min(MAX_SHOE_BLOODINESS,S.bloody_shoes[blood_state]+add_blood) + if(blood_DNA && blood_DNA.len) + S.add_blood(blood_DNA) S.blood_state = blood_state update_icon() H.update_inv_shoes() diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 2839bb1250b..936a599281a 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -511,7 +511,6 @@ obj/item/proc/item_action_slot_check(slot, mob/user) . = ..() if(.) transfer_blood = 0 - bloody_hands_mob = null /obj/item/singularity_pull(S, current_size) if(current_size >= STAGE_FOUR) diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm index 8532aeb4ea2..e69d096205c 100644 --- a/code/game/objects/items/devices/radio/intercom.dm +++ b/code/game/objects/items/devices/radio/intercom.dm @@ -67,5 +67,5 @@ else icon_state = "intercom" -/obj/item/device/radio/intercom/rejects_blood() - return 1 +/obj/item/device/radio/intercom/add_mob_blood(mob/living/carbon/M) + return 0 diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 146610a5197..7ef05e74f23 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -173,7 +173,7 @@ MASS SPECTROMETER // Time of death if(M.tod && (M.stat == DEAD || (M.status_flags & FAKEDEATH))) user << "Time of Death: [M.tod]" - var/tdelta = world.time - M.timeofdeath + var/tdelta = round(world.time - M.timeofdeath) if(tdelta < (DEFIB_TIME_LIMIT * 10)) user << "Subject died [tdelta / 10] seconds \ ago, defibrillation may be possible!" @@ -183,26 +183,29 @@ MASS SPECTROMETER user << "Warning: [D.form] detected\nName: [D.name].\nType: [D.spread_text].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure_text]" // Blood Level - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.vessel) - if(H.blood_max) - user << "Subject is bleeding!" - var/blood_volume = round(H.vessel.get_reagent_amount("blood")) - var/blood_percent = round((blood_volume / 560),0.01) - var/blood_type = H.dna.blood_type - blood_percent *= 100 - if(blood_volume <= 500 && blood_volume > 336) - user << "LOW blood level [blood_percent] %, [blood_volume] cl, type: [blood_type]" - else if(blood_volume <= 336) - user << "CRITICAL blood level CRITICAL [blood_percent] %, [blood_volume] cl, type: [blood_type]" + if(M.has_dna()) + var/mob/living/carbon/C = M + var/blood_id = C.get_blood_id() + if(blood_id) + if(ishuman(C)) + var/mob/living/carbon/human/H = C + if(H.bleed_rate) + user << "Subject is bleeding!" + var/blood_percent = round((C.blood_volume / BLOOD_VOLUME_NORMAL)*100) + var/blood_type = C.dna.blood_type + if(blood_id != "blood")//special blood substance + blood_type = blood_id + if(C.blood_volume <= BLOOD_VOLUME_SAFE && C.blood_volume > BLOOD_VOLUME_OKAY) + user << "LOW blood level [blood_percent] %, [C.blood_volume] cl, type: [blood_type]" + else if(C.blood_volume <= BLOOD_VOLUME_OKAY) + user << "CRITICAL blood level [blood_percent] %, [C.blood_volume] cl, type: [blood_type]" else - user << "Blood level [blood_percent] %, [blood_volume] cl, type: [blood_type]" + user << "Blood level [blood_percent] %, [C.blood_volume] cl, type: [blood_type]" var/implant_detect - for(var/obj/item/organ/cyberimp/CI in H.internal_organs) + for(var/obj/item/organ/cyberimp/CI in C.internal_organs) if(CI.status == ORGAN_ROBOTIC) - implant_detect += "[H.name] is modified with a [CI.name].
" + implant_detect += "[C.name] is modified with a [CI.name].
" if(implant_detect) user << "Detected cybernetic modifications:" user << "[implant_detect]" diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index eb1a1d7abd0..4cbf7c75299 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -40,7 +40,7 @@ if(H.bleedsuppress) user << "[H]'s bleeding is already bandaged!" return - else if(!H.blood_max) + else if(!H.bleed_rate) user << "[H] isn't bleeding!" return diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm index ac17bdbae2a..25cf489bf0f 100644 --- a/code/game/objects/items/weapons/melee/energy.dm +++ b/code/game/objects/items/weapons/melee/energy.dm @@ -13,8 +13,8 @@ "[user] is falling on the [src.name]! It looks like \he's trying to commit suicide.")) return (BRUTELOSS|FIRELOSS) -/obj/item/weapon/melee/energy/rejects_blood() - return 1 +/obj/item/weapon/melee/energy/add_mob_blood(mob/living/carbon/M) + return 0 /obj/item/weapon/melee/energy/is_sharp() return active * sharpness diff --git a/code/game/objects/items/weapons/melee/misc.dm b/code/game/objects/items/weapons/melee/misc.dm index 5f33b5a192d..4953a136b4c 100644 --- a/code/game/objects/items/weapons/melee/misc.dm +++ b/code/game/objects/items/weapons/melee/misc.dm @@ -220,5 +220,5 @@ T.ChangeTurf(T.baseturf) T.CalculateAdjacentTurfs() -/obj/item/weapon/melee/supermatter_sword/add_blood() +/obj/item/weapon/melee/supermatter_sword/add_mob_blood() return diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index f8b5263cba1..431996019f4 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -113,7 +113,7 @@ step(W, pick(alldirs)) H.hair_style = "Bald" H.update_hair() - H.blood_max = 5 + H.bleed_rate = 5 gibs(H.loc, H.viruses, H.dna) H.adjustBruteLoss(1000) //to make the body super-bloody diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm index 998a6820328..ddfd102d863 100644 --- a/code/game/objects/structures/kitchen_spike.dm +++ b/code/game/objects/structures/kitchen_spike.dm @@ -65,9 +65,7 @@ L.visible_message("[user] slams [L] onto the meat spike!", "[user] slams you onto the meat spike!", "You hear a squishy wet noise.") L.loc = src.loc L.emote("scream") - if(ishuman(L)) //So you don't get human blood when you spike a giant spider - var/turf/pos = get_turf(L) - pos.add_blood_floor(L) + L.add_splatter_floor() L.adjustBruteLoss(30) L.buckled = src L.dir = 2 diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 57854738378..c3747346a01 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -47,7 +47,6 @@ var/list/preferences_datums = list() var/be_random_body = 0 //whether we'll have a random body every round var/gender = MALE //gender of character (well duh) var/age = 30 //age of character - var/blood_type = "A+" //blood type (not-chooseable) var/underwear = "Nude" //underwear type var/undershirt = "Nude" //undershirt type var/socks = "Nude" //socks type @@ -92,7 +91,6 @@ var/list/preferences_datums = list() var/list/ignoring = list() /datum/preferences/New(client/C) - blood_type = random_blood_type() custom_names["ai"] = pick(ai_names) custom_names["cyborg"] = pick(ai_names) custom_names["clown"] = pick(clown_names) @@ -190,7 +188,6 @@ var/list/preferences_datums = list() else dat += "Species: Human
" - dat += "Blood Type: [blood_type]
" dat += "Underwear:
[underwear]
" dat += "Undershirt:
[undershirt]
" dat += "Socks:
[socks]
" @@ -1192,7 +1189,6 @@ var/list/preferences_datums = list() character.backbag = backbag - character.dna.blood_type = blood_type character.dna.features = features.Copy() character.dna.real_name = character.real_name var/datum/species/chosen_species diff --git a/code/modules/clothing/outfits/standard.dm b/code/modules/clothing/outfits/standard.dm index e1f8ad0bdcc..517230e8773 100644 --- a/code/modules/clothing/outfits/standard.dm +++ b/code/modules/clothing/outfits/standard.dm @@ -135,7 +135,7 @@ /datum/outfit/psycho/post_equip(mob/living/carbon/human/H) for(var/obj/item/carried_item in H.contents) if(!istype(carried_item, /obj/item/weapon/implant))//If it's not an implant. - carried_item.add_blood(H)//Oh yes, there will be blood... + carried_item.add_mob_blood(H)//Oh yes, there will be blood... H.regenerate_icons() /datum/outfit/assassin diff --git a/code/modules/detectivework/detective_work.dm b/code/modules/detectivework/detective_work.dm index 6fa698d12d2..4322546b022 100644 --- a/code/modules/detectivework/detective_work.dm +++ b/code/modules/detectivework/detective_work.dm @@ -6,10 +6,10 @@ if(M.gloves && istype(M.gloves,/obj/item/clothing/)) var/obj/item/clothing/gloves/G = M.gloves if(G.transfer_blood > 1) //bloodied gloves transfer blood to touched objects - if(add_blood(G.bloody_hands_mob)) //only reduces the bloodiness of our gloves if the item wasn't already bloody + if(add_blood(G.blood_DNA)) //only reduces the bloodiness of our gloves if the item wasn't already bloody G.transfer_blood-- else if(M.bloody_hands > 1) - if(add_blood(M.bloody_hands_mob)) + if(add_blood(M.blood_DNA)) M.bloody_hands-- if(!suit_fibers) suit_fibers = list() var/fibertext diff --git a/code/modules/detectivework/footprints_and_rag.dm b/code/modules/detectivework/footprints_and_rag.dm index 17e5b467066..df05f33ccdb 100644 --- a/code/modules/detectivework/footprints_and_rag.dm +++ b/code/modules/detectivework/footprints_and_rag.dm @@ -1,11 +1,9 @@ /mob var/bloody_hands = 0 - var/mob/living/carbon/human/bloody_hands_mob /obj/item/clothing/gloves var/transfer_blood = 0 - var/mob/living/carbon/human/bloody_hands_mob /obj/item/weapon/reagent_containers/glass/rag diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm new file mode 100644 index 00000000000..f4a39d34771 --- /dev/null +++ b/code/modules/mob/living/blood.dm @@ -0,0 +1,271 @@ +/**************************************************** + BLOOD SYSTEM +****************************************************/ + +/mob/living/carbon/human/proc/suppress_bloodloss(amount) + if(bleedsuppress) + return + else + bleedsuppress = 1 + spawn(amount) + bleedsuppress = 0 + if(stat != DEAD && bleed_rate) + src << "The blood soaks through your bandage." + + +/mob/living/carbon/monkey/handle_blood() + if(bodytemperature >= 225 && !(disabilities & NOCLONE)) //cryosleep or husked people do not pump the blood. + //Blood regeneration if there is some space + if(blood_volume < BLOOD_VOLUME_NORMAL) + blood_volume += 0.1 // regenerate blood VERY slowly + +// Takes care blood loss and regeneration +/mob/living/carbon/human/handle_blood() + + if(NOBLOOD in dna.species.specflags) + bleed_rate = 0 + return + + if(bodytemperature >= 225 && !(disabilities & NOCLONE)) //cryosleep or husked people do not pump the blood. + + //Blood regeneration if there is some space + if(blood_volume < BLOOD_VOLUME_NORMAL) + blood_volume += 0.1 // regenerate blood VERY slowly + + //Effects of bloodloss + switch(blood_volume) + if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE) + if(prob(5)) + src << "You feel [pick("dizzy","woozy","faint")]." + adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.01, 1)) + if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY) + adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1)) + if(prob(5)) + blur_eyes(6) + var/word = pick("dizzy","woozy","faint") + src << "You feel very [word]." + if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD) + adjustOxyLoss(5) + if(prob(15)) + Paralyse(rand(1,3)) + var/word = pick("dizzy","woozy","faint") + src << "You feel extremely [word]." + if(0 to BLOOD_VOLUME_SURVIVE) + death() + + var/temp_bleed = 0 + //Bleeding out + for(var/X in bodyparts) + var/obj/item/bodypart/BP = X + var/brutedamage = BP.brute_dam + + //We want an accurate reading of .len + listclearnulls(BP.embedded_objects) + temp_bleed += 0.5*BP.embedded_objects.len + + if(brutedamage > 30) + temp_bleed += 0.5 + if(brutedamage > 50) + temp_bleed += 1 + if(brutedamage > 70) + temp_bleed += 2 + + bleed_rate = max(bleed_rate - 0.5, temp_bleed)//if no wounds, other bleed effects (heparin) naturally decreases + + if(bleed_rate && !bleedsuppress) + bleed(bleed_rate) + +//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(src.loc)) //Blood loss still happens in locker, floor stays clean + if(amt >= 10) + add_splatter_floor(src.loc) + else + add_splatter_floor(src.loc, 1) + +/mob/living/carbon/human/bleed(amt) + if(!(NOBLOOD in dna.species.specflags)) + ..() + + + +/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 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 + + if(blood_volume < amount) + amount = blood_volume + + var/blood_id = get_blood_id() + if(!blood_id) + return 0 + + blood_volume -= amount + + var/list/blood_data = get_blood_data(blood_id) + + 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/datum/disease/D in blood_data["viruses"]) + 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.blood_type))) + C.reagents.add_reagent("toxin", amount * 0.5) + return 1 + + C.blood_volume = min(C.blood_volume + round(amount, 0.1), BLOOD_VOLUME_MAXIMUM) + return 1 + + AM.reagents.add_reagent(blood_id, amount, blood_data, bodytemperature) + return 1 + + +/mob/living/proc/get_blood_data(blood_id) + return + +/mob/living/carbon/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/datum/disease/D in viruses) + 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 reagents.reagent_list) + temp_chem[R.id] = R.volume + 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(dna.blood_type,1,0) + blood_data["gender"] = gender + blood_data["real_name"] = real_name + blood_data["features"] = dna.features + blood_data["factions"] = faction + return blood_data + +//get the id of the substance this mob use as blood. +/mob/proc/get_blood_id() + return + +/mob/living/simple_animal/get_blood_id() + if(blood_volume) + return "blood" + +/mob/living/carbon/monkey/get_blood_id() + if(!(disabilities & NOCLONE)) + return "blood" + +/mob/living/carbon/human/get_blood_id() + if(dna.species.exotic_blood) + return dna.species.exotic_blood + else if((NOBLOOD in dna.species.specflags) || (disabilities & NOCLONE)) + return + return "blood" + +// 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+") + if("L") + return list("L") + +//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") + return + if(!T) + T = get_turf(src) + + var/list/temp_blood_DNA + 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) + return + else + temp_blood_DNA = list() + temp_blood_DNA |= drop.blood_DNA.Copy() //we transfer the dna from the drip to the splatter + qdel(drop)//the drip is replaced by a bigger splatter + else + drop = new(T) + drop.transfer_mob_blood_dna(src) + return + + // Find a blood decal or create a new one. + var/obj/effect/decal/cleanable/blood/B = locate() in T + if(!B) + 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 + +/mob/living/carbon/human/add_splatter_floor(turf/T, small_drip) + if(!(NOBLOOD in dna.species.specflags)) + ..() + +/mob/living/carbon/alien/add_splatter_floor(turf/T, small_drip) + if(!T) + T = get_turf(src) + var/obj/effect/decal/cleanable/xenoblood/B = locate() in T.contents + if(!B) + B = new(T) + B.blood_DNA["UNKNOWN DNA"] = "X*" + +/mob/living/silicon/robot/add_splatter_floor(turf/T, small_drip) + if(!T) + T = get_turf(src) + var/obj/effect/decal/cleanable/oil/B = locate() in T.contents + if(!B) + B = new(T) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 75ae791a001..54c33958954 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1,3 +1,6 @@ +/mob/living/carbon + blood_volume = BLOOD_VOLUME_NORMAL + /mob/living/carbon/New() create_reagents(1000) ..() @@ -294,16 +297,6 @@ "[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM].") - -/mob/living/carbon/getTrail() - if(getBruteLoss() < 300) - if(prob(50)) - return "ltrails_1" - return "ltrails_2" - else if(prob(50)) - return "trails_1" - return "trails_2" - /mob/living/carbon/fall(forced) loc.handle_fall(src, forced)//it's loc so it doesn't call the mob's handle_fall which does nothing @@ -561,7 +554,7 @@ for(var/i=0 to distance) if(blood) if(T) - T.add_blood_floor(src) + add_splatter_floor(T) if(stun) adjustBruteLoss(3) else diff --git a/code/modules/mob/living/carbon/human/blood.dm b/code/modules/mob/living/carbon/human/blood.dm deleted file mode 100644 index b68124230d4..00000000000 --- a/code/modules/mob/living/carbon/human/blood.dm +++ /dev/null @@ -1,318 +0,0 @@ -/**************************************************** - 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/pale = 0 //Should affect how mob sprite is drawn, but currently doesn't. - -//Initializes blood vessels -/mob/living/carbon/human/proc/make_blood() - if(vessel) - return - - vessel = new/datum/reagents(600) - vessel.my_atom = src - - if(NOBLOOD in dna.species.specflags) - return - - vessel.add_reagent("blood", BLOOD_VOLUME_NORMAL) - 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.blood_type, - "resistances" = null, - "trace_chem" = null, - "mind" = null, - "ckey" = null, - "gender" = null, - "real_name" = null, - "cloneable" = null, - "features" = null, - "factions" = null) - -/mob/living/carbon/human/proc/suppress_bloodloss(amount) - if(bleedsuppress) - return - else - bleedsuppress = 1 - spawn(amount) - bleedsuppress = 0 - if(stat != DEAD && blood_max) - src << "The blood soaks through your bandage." - -// Takes care blood loss and regeneration -/mob/living/carbon/human/handle_blood() - - if(NOBLOOD in dna.species.specflags) - blood_max = 0 - return - - if(stat != DEAD && bodytemperature >= 225) // 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) - 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.4 - reagents.remove_reagent("iron", 0.1) - - //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","woozy","faint") - src << "You feel [word]." - adjustOxyLoss((BLOOD_VOLUME_NORMAL - blood_volume) / 100) - if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY) - if(!pale) - pale = 1 - update_body() - adjustOxyLoss((BLOOD_VOLUME_NORMAL - blood_volume) / 50) - if(prob(5)) - blur_eyes(6) - var/word = pick("dizzy","woozy","faint") - src << "You feel very [word]." - if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD) - oxyloss += 5 - if(prob(15)) - Paralyse(rand(1,3)) - var/word = pick("dizzy","woozy","faint") - src << "You feel extremely [word]." - if(0 to BLOOD_VOLUME_SURVIVE) - death() - - //Bleeding out - blood_max = 0 - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - var/brutedamage = BP.brute_dam - - //We want an accurate reading of .len - listclearnulls(BP.embedded_objects) - blood_max += 0.5*BP.embedded_objects.len - - if(brutedamage > 30) - blood_max += 0.5 - if(brutedamage > 50) - blood_max += 1 - if(brutedamage > 70) - blood_max += 2 - if(bleedsuppress) - blood_max = 0 - if(reagents.has_reagent("heparin") && getBruteLoss()) //Heparin is a powerful toxin that causes bleeding - blood_max += 3 - drip(blood_max) - -//Makes a blood drop, leaking amt units of blood from the mob -/mob/living/carbon/human/proc/drip(amt as num) - - if(!amt) - return - - vessel.remove_reagent("blood",amt) - if (isturf(src.loc)) //Blood loss still happens in locker, floor stays clean - 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, 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 - B.data["viruses"] = list() - /* - if(T.virus && T.virus.spread_type != SPECIAL) - B.data["virus"] = new T.virus.type(0) - */ - - for(var/datum/disease/D in src.viruses) - B.data["viruses"] += D.Copy() - - B.data["blood_DNA"] = copytext(src.dna.unique_enzymes,1,0) - if(src.resistances&&src.resistances.len) - B.data["resistances"] = src.resistances.Copy() - var/list/temp_chem = list() - for(var/datum/reagent/R in src.reagents.reagent_list) - temp_chem[R.id] = R.volume - B.data["trace_chem"] = list2params(temp_chem) - if(mind) - B.data["mind"] = src.mind - if(ckey) - B.data["ckey"] = src.ckey - if(!suiciding) - B.data["cloneable"] = 1 - B.data["blood_type"] = copytext(src.dna.blood_type,1,0) - B.data["gender"] = src.gender - B.data["real_name"] = src.real_name - B.data["features"] = src.dna.features - B.data["factions"] = src.faction - 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, amount) - - if(NOBLOOD in dna.species.specflags) - return null - - if(vessel.get_reagent_amount("blood") < amount) - return null - - . = ..() - vessel.remove_reagent("blood",amount) // Removes blood if human - -//Transfers blood from container to vessels -/mob/living/carbon/proc/inject_blood(obj/item/weapon/reagent_containers/container, amount) - - var/datum/reagent/blood/injected = get_blood(container.reagents) - - if(!injected) - return - - var/list/chems = list() - chems = params2list(injected.data["trace_chem"]) - for(var/C in chems) - src.reagents.add_reagent(C, (text2num(chems[C]) / 560) * amount)//adds trace chemicals to owner's blood - reagents.update_total() - - container.reagents.remove_reagent("blood", amount) - -//Transfers blood from container to vessels, respecting blood types compatibility. -/mob/living/carbon/human/inject_blood(obj/item/weapon/reagent_containers/container, amount) - - var/datum/reagent/blood/injected = get_blood(container.reagents) - - if(NOBLOOD in dna.species.specflags) - reagents.add_reagent("blood", amount, injected.data) - reagents.update_total() - return - - var/datum/reagent/blood/our = get_blood(vessel) - - if (!injected || !our || !dna) - return - - if (!(injected.data["blood_type"] in get_safe_blood(dna.blood_type)) || (injected.data["species"] && injected.data["species"] != dna.species.id)) - reagents.add_reagent("toxin",amount * 0.5) - our.on_merge(injected.data) //still transfer viruses and such, even if incompatibles bloods - 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 - -// 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_splatter(target,datum/reagent/blood/source,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) - else if(istype(source,/mob/living/carbon/monkey)) - var/mob/living/carbon/monkey/donor = source - source = new() - source.data["blood_DNA"] = donor.dna.unique_enzymes - source.data["blood_type"] = donor.dna.blood_type - - // 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) && drips && drips.len && !large) - drop.overlays |= drips - drop.drips |= drips - - // If there's no data to copy, call it quits here. - if(!source) - return B - - // 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+" - - return B diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 393e7e9f2e5..07e56e80a1b 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -57,4 +57,5 @@ /mob/living/carbon/proc/Drain() ChangeToHusk() disabilities |= NOCLONE + blood_volume = 0 return 1 diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index b2fa55a403d..e6b9d15be24 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -247,12 +247,12 @@ else msg += "[t_He] [t_is] quite chubby.\n" - if(pale) + if(blood_volume < BLOOD_VOLUME_SAFE) msg += "[t_He] [t_has] pale skin.\n" if(bleedsuppress) msg += "[t_He] [t_is] bandaged with something.\n" - if(blood_max) + if(bleed_rate) if(reagents.has_reagent("heparin")) msg += "[t_He] [t_is] bleeding uncontrollably!\n" else diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 0614caaf9f0..dab8babb2d8 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -49,8 +49,6 @@ for(var/obj/item/organ/I in internal_organs) I.Insert(src) - make_blood() - martial_art = default_martial_art handcrafting = new() @@ -800,7 +798,7 @@ for(var/t in missing) src << "Your [parse_zone(t)] is missing!" - if(blood_max) + if(bleed_rate) src << "You are bleeding!" if(staminaloss) if(staminaloss > 30) @@ -893,7 +891,6 @@ ..() // Clear the Blood_DNA list if(H.bloody_hands) H.bloody_hands = 0 - H.bloody_hands_mob = null H.update_inv_gloves() update_icons() //apply the now updated overlays to the mob @@ -1032,7 +1029,6 @@ T = new() T.Insert(src) - restore_blood() remove_all_embedded_objects() drunkenness = 0 for(var/datum/mutation/human/HM in dna.mutations) @@ -1083,4 +1079,4 @@ /mob/living/carbon/human/update_gravity(has_gravity,override = 0) override = dna.species.override_float - ..() + ..() diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index ca45f109c58..da3204f6b0e 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -153,11 +153,6 @@ if(update) update_damage_overlays(0) -/mob/living/carbon/human/proc/restore_blood() - if(!(NOBLOOD in dna.species.specflags)) - var/blood_volume = vessel.get_reagent_amount("blood") - vessel.add_reagent("blood",560-blood_volume) - //////////////////////////////////////////// diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 91cfb3d12d7..312f41bddba 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -357,7 +357,7 @@ throw_alert("embeddedobject", /obj/screen/alert/embeddedobject) var/obj/item/bodypart/L = pick(bodyparts) L.embedded_objects |= I - I.add_blood(src)//it embedded itself in you, of course it's bloody! + I.add_mob_blood(src)//it embedded itself in you, of course it's bloody! I.loc = src L.take_damage(I.w_class*I.embedded_impact_pain_multiplier) visible_message("\the [I.name] embeds itself in [src]'s [L.name]!","\the [I.name] embeds itself in your [L.name]!") diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 4a1699d80e1..1054ae35ea2 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -44,7 +44,7 @@ var/global/default_martial_art = new/datum/martial_art var/gender_ambiguous = 0 //if something goes wrong during gender reassignment this generates a line in examine - var/blood_max = 0 //how much are we bleeding + var/bleed_rate = 0 //how much are we bleeding var/bleedsuppress = 0 //for stopping bloodloss, eventually this will be limb-based like bleeding var/datum/martial_art/martial_art = null @@ -54,4 +54,4 @@ var/global/default_martial_art = new/datum/martial_art var/heart_attack = 0 var/drunkenness = 0 //Overall drunkenness - check handle_alcohol() in life.dm for effects - var/datum/personal_crafting/handcrafting + var/datum/personal_crafting/handcrafting diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index 0bc87b8520a..3bb4c433f4c 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -48,6 +48,8 @@ FP.blood_state = S.blood_state FP.entered_dirs |= dir FP.bloodiness = S.bloody_shoes[S.blood_state] + if(S.blood_DNA && S.blood_DNA.len) + FP.transfer_blood_dna(S.blood_DNA) FP.update_icon() update_inv_shoes() //End bloody footprints diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 70450bd83ec..390fe71f69b 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -137,8 +137,6 @@ C.unEquip(thing) if(NODISMEMBER in specflags) C.regenerate_limbs() //if we don't handle dismemberment, we grow our missing limbs back - if(exotic_blood) - C.reagents.add_reagent(exotic_blood, 80) var/obj/item/organ/heart/heart = C.getorganslot("heart") var/obj/item/organ/lungs/lungs = C.getorganslot("lungs") @@ -733,6 +731,10 @@ return /datum/species/proc/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) + if(chem.id == exotic_blood) + H.blood_volume = min(H.blood_volume + round(chem.volume, 0.1), BLOOD_VOLUME_MAXIMUM) + H.reagents.remove_reagent(chem.id) + return 1 return 0 /datum/species/proc/handle_speech(message, mob/living/carbon/human/H) @@ -1104,34 +1106,20 @@ //dismemberment if(prob(I.get_dismemberment_chance(affecting))) if(affecting.dismember(I.damtype)) - I.add_blood(H) + I.add_mob_blood(H) playsound(get_turf(H), I.get_dismember_sound(), 80, 1) var/bloody = 0 if(((I.damtype == BRUTE) && I.force && prob(25 + (I.force * 2)))) if(affecting.status == ORGAN_ORGANIC) - I.add_blood(H) //Make the weapon bloody, not the person. + I.add_mob_blood(H) //Make the weapon bloody, not the person. if(prob(I.force * 2)) //blood spatter! bloody = 1 var/turf/location = H.loc - if(istype(location, /turf)) - location.add_blood(H) - if(ishuman(user)) - var/mob/living/carbon/human/M = user - if(get_dist(M, H) <= 1) //people with TK won't get smeared with blood - if(M.wear_suit) - M.wear_suit.add_blood(H) - M.update_inv_wear_suit() //updates mob overlays to show the new blood (no refresh) - else if(M.w_uniform) - M.w_uniform.add_blood(H) - M.update_inv_w_uniform() //updates mob overlays to show the new blood (no refresh) - if (M.gloves) - var/obj/item/clothing/gloves/G = M.gloves - G.add_blood(H) - else - M.add_blood(H) - M.update_inv_gloves() //updates on-mob overlays for bloody hands and/or bloody gloves - + if(istype(location)) + H.add_splatter_floor(location) + if(get_dist(user, H) <= 1) //people with TK won't get smeared with blood + user.add_mob_blood(H) switch(hit_area) if("head") //Harder to score a stun but if you do it lasts a bit longer @@ -1145,13 +1133,13 @@ if(bloody) //Apply blood if(H.wear_mask) - H.wear_mask.add_blood(H) + H.wear_mask.add_mob_blood(H) H.update_inv_wear_mask() if(H.head) - H.head.add_blood(H) + H.head.add_mob_blood(H) H.update_inv_head() if(H.glasses && prob(33)) - H.glasses.add_blood(H) + H.glasses.add_mob_blood(H) H.update_inv_glasses() if("chest") //Easier to score a stun but lasts less time @@ -1162,10 +1150,10 @@ if(bloody) if(H.wear_suit) - H.wear_suit.add_blood(H) + H.wear_suit.add_mob_blood(H) H.update_inv_wear_suit() if(H.w_uniform) - H.w_uniform.add_blood(H) + H.w_uniform.add_mob_blood(H) H.update_inv_w_uniform() if(Iforce > 10 || Iforce >= 5 && prob(33)) diff --git a/code/modules/mob/living/carbon/human/species_types.dm b/code/modules/mob/living/carbon/human/species_types.dm index 3eeb393cdb6..cb8d6a881ba 100644 --- a/code/modules/mob/living/carbon/human/species_types.dm +++ b/code/modules/mob/living/carbon/human/species_types.dm @@ -75,6 +75,13 @@ return randname +/datum/species/lizard/on_species_gain(mob/living/carbon/C) + if(C.dna.blood_type != "L") + C.dna.blood_type = "L" + +/datum/species/lizard/on_species_loss(mob/living/carbon/C) + C.dna.blood_type = random_blood_type() + //I wag in death /datum/species/lizard/spec_death(gibbed, mob/living/carbon/human/H) if(H) @@ -194,27 +201,21 @@ /datum/species/jelly/spec_life(mob/living/carbon/human/H) if(H.stat == DEAD) //can't farm slime jelly from a dead slime/jelly person indefinitely return - if(!H.reagents.get_reagent_amount(exotic_blood)) - H.reagents.add_reagent(exotic_blood, 5) + if(!H.blood_volume) + H.blood_volume += 5 H.adjustBruteLoss(5) H << "You feel empty!" - var/jelly_amount = H.reagents.get_reagent_amount(exotic_blood) - - if(jelly_amount < 100) + if(H.blood_volume < BLOOD_VOLUME_NORMAL) if(H.nutrition >= NUTRITION_LEVEL_STARVING) - H.reagents.add_reagent(exotic_blood, 0.5) + H.blood_volume += 3 H.nutrition -= 2.5 - if(jelly_amount < 50) + if(H.blood_volume < BLOOD_VOLUME_OKAY) if(prob(5)) H << "You feel drained!" - if(jelly_amount < 10) + if(H.blood_volume < BLOOD_VOLUME_BAD) H.losebreath++ -/datum/species/jelly/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) - if(chem.id == exotic_blood) - return 1 - /* SLIMEPEOPLE */ @@ -245,6 +246,7 @@ callforward.Remove(C) if(callback) callback.Remove(C) + C.blood_volume = min(C.blood_volume, BLOOD_VOLUME_NORMAL) ..() /datum/species/jelly/slime/on_species_gain(mob/living/carbon/C) @@ -254,12 +256,11 @@ slime_split.Grant(C) /datum/species/jelly/slime/spec_life(mob/living/carbon/human/H) - var/jelly_amount = H.reagents.get_reagent_amount(exotic_blood) - if(jelly_amount >= 200) + if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT) if(prob(5)) H << "You feel very bloated!" else if(H.nutrition >= NUTRITION_LEVEL_WELL_FED) - H.reagents.add_reagent(exotic_blood, 0.5) + H.blood_volume += 3 H.nutrition -= 2.5 ..() @@ -274,29 +275,28 @@ var/mob/living/carbon/human/H = owner H << "You focus intently on moving your body while standing perfectly still..." H.notransform = 1 - for(var/datum/reagent/toxin/slimejelly/S in H.reagents.reagent_list) - if(S.volume >= 200) - var/mob/living/carbon/human/spare = new /mob/living/carbon/human(H.loc) - spare.underwear = "Nude" - H.dna.transfer_identity(spare, transfer_SE=1) - H.dna.features["mcolor"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F") - spare.real_name = spare.dna.real_name - spare.name = spare.dna.real_name - spare.updateappearance(mutcolor_update=1) - spare.domutcheck() - spare.Move(get_step(H.loc, pick(NORTH,SOUTH,EAST,WEST))) - S.volume = 80 - H.notransform = 0 - var/datum/species/jelly/slime/SS = H.dna.species - SS.callforward = new - SS.callforward.body = spare - SS.callforward.Grant(H) - SS.callback = new - SS.callback.body = H - SS.callback.Grant(spare) - H.mind.transfer_to(spare) - spare << "...and after a moment of disorentation, you're besides yourself!" - return + if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT) + var/mob/living/carbon/human/spare = new /mob/living/carbon/human(H.loc) + spare.underwear = "Nude" + H.dna.transfer_identity(spare, transfer_SE=1) + H.dna.features["mcolor"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F") + spare.real_name = spare.dna.real_name + spare.name = spare.dna.real_name + spare.updateappearance(mutcolor_update=1) + spare.domutcheck() + spare.Move(get_step(H.loc, pick(NORTH,SOUTH,EAST,WEST))) + H.blood_volume = BLOOD_VOLUME_SAFE + H.notransform = 0 + var/datum/species/jelly/slime/SS = H.dna.species + SS.callforward = new + SS.callforward.body = spare + SS.callforward.Grant(H) + SS.callback = new + SS.callback.body = H + SS.callback.Grant(spare) + H.mind.transfer_to(spare) + spare << "...and after a moment of disorentation, you're besides yourself!" + return H << "...but there is not enough of you to go around! You must attain more mass to split!" H.notransform = 0 diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index c055c89375a..aaaf5cc8086 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -14,6 +14,8 @@ if(..()) . = 1 + handle_blood() + for(var/obj/item/organ/O in internal_organs) O.on_life() @@ -212,6 +214,9 @@ update_internals_hud_icon(1) return internal.remove_air_volume(volume_needed) +/mob/living/carbon/proc/handle_blood() + return + /mob/living/carbon/proc/handle_changeling() if(mind && hud_used && hud_used.lingchemdisplay) if(mind.changeling) diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index 7584716e394..7bd479db031 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -22,9 +22,6 @@ //Chemicals in the body handle_chemicals_in_body() - //Blud - handle_blood() - //Random events (vomiting etc) handle_random_events() @@ -69,9 +66,6 @@ AI.client.images |= src.digitaldisguise -/mob/living/proc/handle_blood() - return - /mob/living/proc/handle_random_events() return diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 97cbc6c99e9..1ba8be20c72 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -499,6 +499,7 @@ Sorry Giacom. Please don't be mad :( //proc used to completely heal a mob. /mob/living/proc/fully_heal(admin_revive = 0) + restore_blood() setToxLoss(0, 0) setOxyLoss(0, 0) setCloneLoss(0, 0) @@ -572,8 +573,8 @@ Sorry Giacom. Please don't be mad :( if(get_dist(src, pulling) > 1 || ((pull_dir - 1) & pull_dir)) //puller and pullee more than one tile away or in diagonal position if(isliving(pulling)) var/mob/living/M = pulling - if(M.lying && !M.buckled && (prob(M.getBruteLoss() / 2))) - makeTrail(T, M) + if(M.lying && !M.buckled && (prob(M.getBruteLoss()*200/M.maxHealth))) + M.makeTrail(T) pulling.Move(T, get_dir(pulling, T)) //the pullee tries to reach our previous position if(pulling && get_dist(src, pulling) > 1) //the pullee couldn't keep up stop_pulling() @@ -598,39 +599,46 @@ Sorry Giacom. Please don't be mad :( if("walk") . += config.walk_speed -/mob/living/proc/makeTrail(turf/T, mob/living/M) - if(!has_gravity(M)) +/mob/living/proc/makeTrail(turf/T) + if(!has_gravity(src)) return - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if((NOBLOOD in H.dna.species.specflags) || (!H.blood_max) || (H.bleedsuppress)) - return var/blood_exists = 0 - var/trail_type = M.getTrail() - for(var/obj/effect/decal/cleanable/trail_holder/C in M.loc) //checks for blood splatter already on the floor - blood_exists = 1 - if (istype(M.loc, /turf) && trail_type != null) - var/newdir = get_dir(T, M.loc) - if(newdir != M.dir) - newdir = newdir | M.dir - if(newdir == 3) //N + S - newdir = NORTH - else if(newdir == 12) //E + W - newdir = EAST - if((newdir in list(1, 2, 4, 8)) && (prob(50))) - newdir = turn(get_dir(T, M.loc), 180) - if(!blood_exists) - new /obj/effect/decal/cleanable/trail_holder(M.loc) - for(var/obj/effect/decal/cleanable/trail_holder/H in M.loc) - if((!(newdir in H.existing_dirs) || trail_type == "trails_1" || trail_type == "trails_2") && H.existing_dirs.len <= 16) //maximum amount of overlays is 16 (all light & heavy directions filled) - H.existing_dirs += newdir - H.overlays.Add(image('icons/effects/blood.dmi',trail_type,dir = newdir)) - if(M.has_dna()) //blood DNA - var/mob/living/carbon/DNA_helper = M - H.blood_DNA[DNA_helper.dna.unique_enzymes] = DNA_helper.dna.blood_type -/mob/living/proc/getTrail() //silicon and simple_animals don't get blood trails - return null + for(var/obj/effect/decal/cleanable/trail_holder/C in src.loc) //checks for blood splatter already on the floor + blood_exists = 1 + if (isturf(src.loc)) + var/trail_type = getTrail() + if(trail_type) + var/brute_ratio = round(getBruteLoss()/maxHealth, 0.1) + if(blood_volume && blood_volume > max(BLOOD_VOLUME_NORMAL*(1 - brute_ratio * 0.25), 0))//don't leave trail if blood volume below a threshold + blood_volume = max(blood_volume - max(1, brute_ratio * 2), 0) //that depends on our brute damage. + var/newdir = get_dir(T, src.loc) + if(newdir != src.dir) + newdir = newdir | src.dir + if(newdir == 3) //N + S + newdir = NORTH + else if(newdir == 12) //E + W + newdir = EAST + if((newdir in cardinal) && (prob(50))) + newdir = turn(get_dir(T, src.loc), 180) + if(!blood_exists) + new /obj/effect/decal/cleanable/trail_holder(src.loc) + for(var/obj/effect/decal/cleanable/trail_holder/TH in src.loc) + if((!(newdir in TH.existing_dirs) || trail_type == "trails_1" || trail_type == "trails_2") && TH.existing_dirs.len <= 16) //maximum amount of overlays is 16 (all light & heavy directions filled) + TH.existing_dirs += newdir + TH.overlays.Add(image('icons/effects/blood.dmi',trail_type,dir = newdir)) + TH.transfer_mob_blood_dna(src) + +/mob/living/carbon/human/makeTrail(turf/T) + if((NOBLOOD in dna.species.specflags) || !bleed_rate || bleedsuppress) + return + ..() + +/mob/living/proc/getTrail() + if(getBruteLoss() < 300) + return pick("ltrails_1", "ltrails_2") + else + return pick("trails_1", "trails_2") /mob/living/verb/resist() set name = "Resist" diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 400503818f9..2a338caa35e 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -68,3 +68,5 @@ var/mob/living/mental_dominator //The person controlling the mind of this person, if applicable var/mob/living/mind_control_holder/mind_control_holder //If the mob is being mind controlled, where their old mind is stored (check clock_mobs.dm) + + var/blood_volume = 0 //how much blood the mob has \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm index ce5d311e7bf..857f93b8a63 100644 --- a/code/modules/mob/living/simple_animal/bot/mulebot.dm +++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm @@ -662,9 +662,8 @@ var/global/mulebot_count = 0 H.apply_damage(0.5*damage, BRUTE, "l_arm", run_armor_check("l_arm", "melee")) H.apply_damage(0.5*damage, BRUTE, "r_arm", run_armor_check("r_arm", "melee")) - var/obj/effect/decal/cleanable/blood/B = new(loc) - B.add_blood_list(H) - add_blood_list(H) + var/turf/T = get_turf(src) + T.add_mob_blood(H) bloodiness += 4 // player on mulebot attempted to move diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm index 94dd02f7501..67a0d63fdac 100644 --- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm +++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm @@ -26,6 +26,7 @@ melee_damage_upper = 2 environment_smash = 0 stop_automated_movement_when_pulled = 1 + blood_volume = BLOOD_VOLUME_NORMAL var/obj/item/udder/udder = null /mob/living/simple_animal/hostile/retaliate/goat/New() @@ -102,6 +103,7 @@ maxHealth = 50 var/obj/item/udder/udder = null gold_core_spawnable = 2 + blood_volume = BLOOD_VOLUME_NORMAL /mob/living/simple_animal/cow/New() udder = new() diff --git a/code/modules/mob/living/simple_animal/friendly/pet.dm b/code/modules/mob/living/simple_animal/friendly/pet.dm index dd6bbd56bc5..587900add16 100644 --- a/code/modules/mob/living/simple_animal/friendly/pet.dm +++ b/code/modules/mob/living/simple_animal/friendly/pet.dm @@ -4,6 +4,7 @@ var/obj/item/clothing/tie/petcollar/pcollar = null var/image/collar = null var/image/pettag = null + blood_volume = BLOOD_VOLUME_NORMAL /mob/living/simple_animal/pet/attackby(obj/item/O, mob/user, params) if(istype(O, /obj/item/clothing/tie/petcollar) && !pcollar) diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm index ba2db3344ed..6e25b296f1c 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm @@ -288,10 +288,8 @@ if(NOBLOOD in H.dna.species.specflags) return - var/datum/reagent/blood/B = locate() in H.vessel.reagent_list - var/blood_volume = round(H.vessel.get_reagent_amount("blood")) - if(B && blood_volume < 560 && blood_volume) - B.volume += 2 // Fast blood regen + if(H.blood_volume && H.blood_volume < BLOOD_VOLUME_NORMAL) + H.blood_volume += 2 // Fast blood regen /obj/item/organ/hivelord_core/afterattack(atom/target, mob/user, proximity_flag) if(proximity_flag && ishuman(target)) @@ -398,7 +396,7 @@ transfer_reagents(C) death() -/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/proc/transfer_reagents(mob/living/carbon/C, var/volume = 30) +/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/proc/transfer_reagents(mob/living/carbon/C, volume = 30) if(!reagents.total_volume) return @@ -406,29 +404,11 @@ var/fraction = min(volume/reagents.total_volume, 1) reagents.reaction(C, INJECT, fraction) - - var/datum/reagent/blood/B - for(var/datum/reagent/blood/d in reagents.reagent_list) - B = d - break - if(B) - C.inject_blood(src, min(B.volume, volume)) - reagents.trans_to(C, volume) /mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/proc/link_host(mob/living/carbon/C) faction = list("\ref[src]", "\ref[C]") // Hostile to everyone except the host. - var/datum/reagent/B = C.take_blood(src, 30) - if(!B) - if(ishuman(C)) - var/mob/living/carbon/human/H = C - if(H.dna.species.exotic_blood && H.reagents.total_volume) - H.reagents.trans_to(src, 10) - - else - reagents.reagent_list += B - reagents.update_total() - + C.transfer_blood_to(src, 30) color = mix_color_from_reagents(reagents.reagent_list) /mob/living/simple_animal/hostile/asteroid/goliath diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index d8fd2af810f..04814cbd2bb 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -411,6 +411,7 @@ icon_state = icon_dead stat = DEAD density = 0 + lying = 1 ..() /mob/living/simple_animal/ex_act(severity, target) @@ -457,6 +458,7 @@ icon = initial(icon) icon_state = icon_living density = initial(density) + lying = 0 . = 1 /mob/living/simple_animal/fully_heal(admin_revive = 0) diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index 22178caa4bf..d5e9c1916ab 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -335,9 +335,6 @@ var/list/slime_colours = list("rainbow", "grey", "purple", "metal", "orange", ++Discipline return -/mob/living/simple_animal/slime/getTrail() - return null - /mob/living/simple_animal/slime/examine(mob/user) var/msg = "*---------*\nThis is \icon[src] \a [src]!\n" diff --git a/code/modules/paperwork/contract.dm b/code/modules/paperwork/contract.dm index 43a8e5fce22..b7a09fcf5a1 100644 --- a/code/modules/paperwork/contract.dm +++ b/code/modules/paperwork/contract.dm @@ -145,9 +145,7 @@ add_fingerprint(user) if(M == user && target == M.mind && M.mind.soulOwner == M.mind && attempt_signature(user)) user.visible_message("[user] slices their wrist with [src], and scrawls their name in blood.", "You slice your wrist open and scrawl your name in blood.") - if(istype(user, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = user - H.vessel.remove_reagent("blood",10) + user.blood_volume = max(user.blood_volume - 10, 0) else return ..() diff --git a/code/modules/projectiles/guns/projectile/saw.dm b/code/modules/projectiles/guns/projectile/saw.dm index ebc79dfd8ad..a1a3231135e 100644 --- a/code/modules/projectiles/guns/projectile/saw.dm +++ b/code/modules/projectiles/guns/projectile/saw.dm @@ -77,9 +77,9 @@ /obj/item/projectile/bullet/saw/bleeding/on_hit(atom/target, blocked = 0, hit_zone) . = ..() - if((blocked != 100) && istype(target, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = target - H.drip(35) + if((blocked != 100) && iscarbon(target)) + var/mob/living/carbon/C = target + C.bleed(35) /obj/item/projectile/bullet/saw/hollow damage = 60 diff --git a/code/modules/projectiles/guns/projectile/sniper.dm b/code/modules/projectiles/guns/projectile/sniper.dm index 3cb65acd8ed..555dbe4df73 100644 --- a/code/modules/projectiles/guns/projectile/sniper.dm +++ b/code/modules/projectiles/guns/projectile/sniper.dm @@ -127,9 +127,9 @@ breakthings = FALSE /obj/item/projectile/bullet/sniper/haemorrhage/on_hit(atom/target, blocked = 0, hit_zone) - if((blocked != 100) && istype(target, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = target - H.drip(100) + if((blocked != 100) && iscarbon(target)) + var/mob/living/carbon/C = target + C.bleed(100) return ..() diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index c27f060df24..1b5ad721edf 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -142,10 +142,6 @@ var/const/INJECT = 5 //injection var/trans_data = null for(var/reagent in reagent_list) var/datum/reagent/T = reagent - if(T.id == "blood" && ishuman(target)) - var/mob/living/carbon/human/H = target - H.inject_blood(my_atom, amount) - continue var/transfer_amount = T.volume * part if(preserve_data) trans_data = copy_data(T) diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index c9e1e5c4897..dc8126d6f42 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -29,6 +29,10 @@ if(prob(50)) M.heal_organ_damage(1,0, 0) . = 1 + if(iscarbon(M)) + var/mob/living/carbon/C = M + if(C.blood_volume < BLOOD_VOLUME_NORMAL) + C.blood_volume += 0.4 ..() /datum/reagent/consumable/vitamin @@ -44,6 +48,10 @@ . = 1 if(M.satiety < 600) M.satiety += 30 + if(iscarbon(M)) + var/mob/living/carbon/C = M + if(C.blood_volume < BLOOD_VOLUME_NORMAL) + C.blood_volume += 0.5 ..() /datum/reagent/consumable/sugar diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index b7bc550d64a..54e4340d690 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -272,13 +272,13 @@ ..() /datum/reagent/medicine/salglu_solution/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1) - if(iscarbon(M) && method == INJECT) + if(ishuman(M) && method == INJECT) var/mob/living/carbon/human/H = M - //The lower the blood of the patient, the better it is as a blood substitute. - var/efficiency = (560-H.vessel.get_reagent_amount("blood"))/700 + 0.2 - efficiency = min(0.75,efficiency) - //As it's designed for an IV drip, make large injections not as effective as repeated small injections. - H.vessel.add_reagent("blood", efficiency * min(5,reac_volume)) + if(H.dna && !(NOBLOOD in H.dna.species.specflags)) + var/efficiency = (BLOOD_VOLUME_NORMAL-H.blood_volume)/700 + 0.2//The lower the blood of the patient, the better it is as a blood substitute. + efficiency = min(0.75,efficiency) + //As it's designed for an IV drip, make large injections not as effective as repeated small injections. + H.blood_volume += round(efficiency * min(5,reac_volume), 0.1) ..() /datum/reagent/medicine/mine_salve diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index eaf4e1c8c68..2daca1f733a 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -1,15 +1,16 @@ /datum/reagent/blood - data = list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=null,"resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null) - name = "Blood" - id = "blood" - color = "#C80000" // rgb: 200, 0, 0 + data = list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=null,"resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null) + name = "Blood" + id = "blood" + color = "#C80000" // rgb: 200, 0, 0 + metabolization_rate = 5 //fast rate so it disappears fast. /datum/reagent/blood/reaction_mob(mob/M, method=TOUCH, reac_volume) if(data && data["viruses"]) for(var/datum/disease/D in data["viruses"]) - if(D.spread_flags & SPECIAL || D.spread_flags & NON_CONTAGIOUS) + if((D.spread_flags & SPECIAL) || (D.spread_flags & NON_CONTAGIOUS)) continue if(method == TOUCH || method == VAPOR) @@ -17,6 +18,15 @@ else //ingest, patch or inject M.ForceContractDisease(D) + if(method == INJECT && iscarbon(M)) + var/mob/living/carbon/C = M + if(C.get_blood_id() == "blood") + if(!data || !(data["blood_type"] in get_safe_blood(C.dna.blood_type))) + C.reagents.add_reagent("toxin", reac_volume * 0.5) + else + C.blood_volume = min(C.blood_volume + round(reac_volume, 0.1), BLOOD_VOLUME_MAXIMUM) + + /datum/reagent/blood/on_new(list/data) if(istype(data)) SetViruses(src, data) @@ -51,38 +61,18 @@ return if(reac_volume < 3) return - if(!data["donor"] || istype(data["donor"], /mob/living/carbon/human)) - var/obj/effect/decal/cleanable/blood/blood_prop = locate() in T //find some blood here - if(!blood_prop) //first blood! - blood_prop = new(T) - blood_prop.blood_DNA[data["blood_DNA"]] = data["blood_type"] - for(var/datum/disease/D in data["viruses"]) - var/datum/disease/newVirus = D.Copy(1) - blood_prop.viruses += newVirus - newVirus.holder = blood_prop + var/obj/effect/decal/cleanable/blood/B = locate() in T //find some blood here + if(!B) + B = new(T) + if(data["blood_DNA"]) + B.blood_DNA[data["blood_DNA"]] = data["blood_type"] + for(var/datum/disease/D in data["viruses"]) + var/datum/disease/newVirus = D.Copy(1) + B.viruses += newVirus + newVirus.holder = B - else if(istype(data["donor"], /mob/living/carbon/monkey)) - var/obj/effect/decal/cleanable/blood/blood_prop = locate() in T - if(!blood_prop) - blood_prop = new(T) - blood_prop.blood_DNA["Non-Human DNA"] = "A+" - for(var/datum/disease/D in data["viruses"]) - var/datum/disease/newVirus = D.Copy(1) - blood_prop.viruses += newVirus - newVirus.holder = blood_prop - - else if(istype(data["donor"], /mob/living/carbon/alien)) - var/obj/effect/decal/cleanable/xenoblood/blood_prop = locate() in T - if(!blood_prop) - blood_prop = new(T) - blood_prop.blood_DNA["UNKNOWN DNA STRUCTURE"] = "X*" - for(var/datum/disease/D in data["viruses"]) - var/datum/disease/newVirus = D.Copy(1) - blood_prop.viruses += newVirus - newVirus.holder = blood_prop - return /datum/reagent/liquidgibs name = "Liquid gibs" @@ -634,6 +624,13 @@ color = "#C8A5DC" // rgb: 200, 165, 220 +/datum/reagent/iron/on_mob_life(mob/living/M) + if(iscarbon(M)) + var/mob/living/carbon/C = M + if(C.blood_volume < BLOOD_VOLUME_NORMAL) + C.blood_volume += 0.5 + ..() + /datum/reagent/iron/reaction_mob(mob/living/M, method=TOUCH, reac_volume) if(!istype(M, /mob/living)) return diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index 8d3c4dd2b89..8da685439b5 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -649,7 +649,7 @@ /datum/reagent/toxin/heparin/on_mob_life(mob/living/M) if(ishuman(M)) var/mob/living/carbon/human/H = M - H.blood_max += 2 + H.bleed_rate = min(H.bleed_rate + 2, 8) H.adjustBruteLoss(1, 0) //Brute damage increases with the amount they're bleeding . = 1 return ..() || . diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm index 353b3276e18..3894e80b6b5 100644 --- a/code/modules/reagents/reagent_containers/blood_pack.dm +++ b/code/modules/reagents/reagent_containers/blood_pack.dm @@ -4,19 +4,35 @@ icon = 'icons/obj/bloodpack.dmi' icon_state = "empty" volume = 200 - var/blood_type = null + var/labelled = 0 /obj/item/weapon/reagent_containers/blood/New() ..() if(blood_type != null) - name = "blood pack [blood_type]" reagents.add_reagent("blood", 200, list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=blood_type,"resistances"=null,"trace_chem"=null)) update_icon() /obj/item/weapon/reagent_containers/blood/on_reagent_change() + if(reagents) + var/datum/reagent/blood/B = reagents.has_reagent("blood") + if(B && B.data && B.data["blood_type"]) + blood_type = B.data["blood_type"] + else + blood_type = null + update_pack_name() update_icon() +/obj/item/weapon/reagent_containers/blood/proc/update_pack_name() + if(!labelled) + if(volume) + if(blood_type) + name = "blood pack [blood_type]" + else + name = "blood pack" + else + name = "empty blood pack" + /obj/item/weapon/reagent_containers/blood/update_icon() var/percent = round((reagents.total_volume / volume) * 100) switch(percent) @@ -49,9 +65,11 @@ /obj/item/weapon/reagent_containers/blood/OMinus blood_type = "O-" +/obj/item/weapon/reagent_containers/blood/lizard + blood_type = "L" + /obj/item/weapon/reagent_containers/blood/empty name = "empty blood pack" - desc = "Seems pretty useless... Maybe if there were a way to fill it?" icon_state = "empty" /obj/item/weapon/reagent_containers/blood/attackby(obj/item/I, mob/user, params) @@ -62,10 +80,13 @@ return if(user.get_active_hand() != I) return - if(!in_range(src, user) && loc != user) + if(loc != user) return if(t) + labelled = 1 name = "blood pack - [t]" else - name = "blood pack" - return + labelled = 0 + update_pack_name() + else + return ..() diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index 68bc332d528..de1b92ca252 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -46,15 +46,18 @@ /obj/item/weapon/reagent_containers/syringe/attackby(obj/item/I, mob/user, params) return -/obj/item/weapon/reagent_containers/syringe/afterattack(obj/target, mob/user , proximity) +/obj/item/weapon/reagent_containers/syringe/afterattack(atom/target, mob/user , proximity) if(busy) return - if(!proximity) return - if(!target.reagents) return + if(!proximity) + return + if(!target.reagents) + return + var/mob/living/L if(isliving(target)) - var/mob/living/M = target - if(!M.can_inject(user, 1)) + L = target + if(!L.can_inject(user, 1)) return switch(mode) @@ -64,45 +67,22 @@ user << "The syringe is full." return - if(ismob(target)) //Blood! - if(ishuman(target)) - var/mob/living/carbon/human/H = target - if((NOBLOOD in H.dna.species.specflags) && !H.dna.species.exotic_blood) - user << "You are unable to locate any blood!" + if(L) //living mob + var/drawn_amount = reagents.maximum_volume - reagents.total_volume + if(target != user) + target.visible_message("[user] is trying to take a blood sample from [target]!", \ + "[user] is trying to take a blood sample from [target]!") + busy = 1 + if(!do_mob(user, target)) + busy = 0 return - if(reagents.has_reagent("blood")) - user << "There is already a blood sample in this syringe!" - return - 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 - if(!T.has_dna() || (T.disabilities & NOCLONE)) //target done been eat, no more blood in him - user << "You are unable to locate any blood!" + if(reagents.total_volume >= reagents.maximum_volume) return - if(target != user) - target.visible_message("[user] is trying to take a blood sample from [target]!", \ - "[user] is trying to take a blood sample from [target]!") - busy = 1 - if(!do_mob(user, target)) - busy = 0 - return - busy = 0 - var/datum/reagent/B - B = T.take_blood(src,amount) - - if(!B && ishuman(target)) - var/mob/living/carbon/human/H = target - if(H.dna.species.exotic_blood && H.reagents.total_volume) - target.reagents.trans_to(src, amount) - else - user << "You are unable to locate any blood!" - return - if (B) - src.reagents.reagent_list += B - src.reagents.update_total() - src.on_reagent_change() - src.reagents.handle_reactions() - user.visible_message("[user] takes a blood sample from [target].") + busy = 0 + if(L.transfer_blood_to(src, drawn_amount)) + user.visible_message("[user] takes a blood sample from [L].") + else + user << "You are unable to draw any blood from [L]!" else //if not mob if(!target.reagents.total_volume) @@ -132,53 +112,38 @@ user << "[target] is full." return - if(ismob(target) && target != user) - target.visible_message("[user] is trying to inject [target]!", \ - "[user] is trying to inject [target]!") - if(!do_mob(user, target)) - return - //Sanity checks after sleep - if(!reagents.total_volume) - return - if(target.reagents.total_volume >= target.reagents.maximum_volume) - return + if(L) //living mob + if(L != user) + L.visible_message("[user] is trying to inject [L]!", \ + "[user] is trying to inject [L]!") + if(!do_mob(user, L)) + return + if(!reagents.total_volume) + return + if(L.reagents.total_volume >= L.reagents.maximum_volume) + return + + L.visible_message("[user] injects [L] with the syringe!", \ + "[user] injects [L] with the syringe!") - target.visible_message("[user] injects [target] with the syringe!", \ - "[user] injects [target] with the syringe!") - //Attack log entries are produced here due to failure to produce elsewhere. Remove them here if you have doubles from normal syringes. var/list/rinject = list() - for(var/datum/reagent/R in src.reagents.reagent_list) + for(var/datum/reagent/R in reagents.reagent_list) rinject += R.name var/contained = english_list(rinject) - var/mob/M = target - add_logs(user, M, "injected", src, addition="which had [contained]") - var/fraction = min(amount_per_transfer_from_this/reagents.total_volume, 1) - reagents.reaction(target, INJECT, fraction) - if(ismob(target) && target == user) - //Attack log entries are produced here due to failure to produce elsewhere. Remove them here if you have doubles from normal syringes. - var/list/rinject = list() - for(var/datum/reagent/R in src.reagents.reagent_list) - rinject += R.name - var/contained = english_list(rinject) - var/mob/M = target - log_attack("[user.name] ([user.ckey]) injected [M.name] ([M.ckey]) with [src.name], which had [contained] (INTENT: [uppertext(user.a_intent)])") - M.attack_log += text("\[[time_stamp()]\] Injected themselves ([contained]) with [src.name].") - var/fraction = min(amount_per_transfer_from_this/reagents.total_volume, 1) - reagents.reaction(target, INJECT, fraction) - spawn(5) - var/datum/reagent/blood/B - for(var/datum/reagent/blood/d in src.reagents.reagent_list) - B = d - break - if(B && istype(target,/mob/living/carbon)) - var/mob/living/carbon/C = target - C.inject_blood(src,5) + + if(L != user) + add_logs(user, L, "injected", src, addition="which had [contained]") else - src.reagents.trans_to(target, amount_per_transfer_from_this) - user << "You inject [amount_per_transfer_from_this] units of the solution. The syringe now contains [src.reagents.total_volume] units." - if (reagents.total_volume <= 0 && mode==SYRINGE_INJECT) - mode = SYRINGE_DRAW - update_icon() + log_attack("[user.name] ([user.ckey]) injected [L.name] ([L.ckey]) with [src.name], which had [contained] (INTENT: [uppertext(user.a_intent)])") + L.attack_log += "\[[time_stamp()]\] Injected themselves ([contained]) with [src.name]." + + var/fraction = min(amount_per_transfer_from_this/reagents.total_volume, 1) + reagents.reaction(L, INJECT, fraction) + reagents.trans_to(target, amount_per_transfer_from_this) + user << "You inject [amount_per_transfer_from_this] units of the solution. The syringe now contains [reagents.total_volume] units." + if (reagents.total_volume <= 0 && mode==SYRINGE_INJECT) + mode = SYRINGE_DRAW + update_icon() /obj/item/weapon/reagent_containers/syringe/update_icon() diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index 0316b3899ff..b100ed0f386 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -17,10 +17,10 @@ if(dam_type == BURN) burn() return 1 - add_blood(H) + add_mob_blood(H) var/turf/location = H.loc if(istype(location)) - location.add_blood(H) + H.add_splatter_floor(location) var/direction = pick(cardinal) var/t_range = rand(2,max(throw_range/2, 2)) var/turf/target_turf = get_turf(src) @@ -40,7 +40,7 @@ var/organ_spilled = 0 var/turf/T = get_turf(H) - T.add_blood(H) + H.add_splatter_floor(T) playsound(get_turf(owner), 'sound/misc/splort.ogg', 80, 1) for(var/X in owner.internal_organs) var/obj/item/organ/O = X diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index 1b47c0172f6..47e3615388d 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -193,11 +193,12 @@ 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) - H << "You have to keep pumping your blood!" - if(add_colour) - H.add_client_colour(/datum/client_colour/cursed_heart_blood) //bloody screen so real - add_colour = FALSE + if(H.dna && !(NOBLOOD in H.dna.species.specflags)) + H.blood_volume = max(H.blood_volume - blood_loss, 0) + H << "You have to keep pumping your blood!" + if(add_colour) + H.add_client_colour(/datum/client_colour/cursed_heart_blood) //bloody screen so real + add_colour = FALSE else last_pump = world.time //lets be extra fair *sigh* @@ -225,12 +226,13 @@ 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 - H.remove_client_colour(/datum/client_colour/cursed_heart_blood) - cursed_heart.add_colour = TRUE - H.adjustBruteLoss(-cursed_heart.heal_brute) - H.adjustFireLoss(-cursed_heart.heal_burn) - H.adjustOxyLoss(-cursed_heart.heal_oxy) + if(H.dna && !(NOBLOOD in H.dna.species.specflags)) + H.blood_volume = min(H.blood_volume + cursed_heart.blood_loss*0.5, BLOOD_VOLUME_MAXIMUM) + H.remove_client_colour(/datum/client_colour/cursed_heart_blood) + cursed_heart.add_colour = TRUE + H.adjustBruteLoss(-cursed_heart.heal_brute) + H.adjustFireLoss(-cursed_heart.heal_burn) + H.adjustOxyLoss(-cursed_heart.heal_oxy) /datum/client_colour/cursed_heart_blood diff --git a/tgstation.dme b/tgstation.dme index 9f147302728..2a20872de2a 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1252,6 +1252,7 @@ #include "code\modules\mob\dead\observer\logout.dm" #include "code\modules\mob\dead\observer\observer.dm" #include "code\modules\mob\dead\observer\say.dm" +#include "code\modules\mob\living\blood.dm" #include "code\modules\mob\living\bloodcrawl.dm" #include "code\modules\mob\living\damage_procs.dm" #include "code\modules\mob\living\death.dm" @@ -1317,7 +1318,6 @@ #include "code\modules\mob\living\carbon\brain\posibrain.dm" #include "code\modules\mob\living\carbon\brain\say.dm" #include "code\modules\mob\living\carbon\brain\status_procs.dm" -#include "code\modules\mob\living\carbon\human\blood.dm" #include "code\modules\mob\living\carbon\human\death.dm" #include "code\modules\mob\living\carbon\human\emote.dm" #include "code\modules\mob\living\carbon\human\examine.dm"