diff --git a/code/__DEFINES/genetics.dm b/code/__DEFINES/genetics.dm
index 4f07d54ee01..be243c66386 100644
--- a/code/__DEFINES/genetics.dm
+++ b/code/__DEFINES/genetics.dm
@@ -99,6 +99,7 @@
#define NUTRITION_LEVEL_CURSED 0
//Blood levels
+#define BLOOD_VOLUME_MAXIMUM 2000
#define BLOOD_VOLUME_NORMAL 560
#define BLOOD_VOLUME_SAFE 501
#define BLOOD_VOLUME_OKAY 336
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index a2f487086ae..61e5e5069b4 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -334,4 +334,16 @@
#define FIRST_DIAG_STEP 1
#define SECOND_DIAG_STEP 2
-#define ARBITRARY_VIEWRANGE_NOHUD 2
\ No newline at end of file
+#define ARBITRARY_VIEWRANGE_NOHUD 2
+#define SECOND_DIAG_STEP 2
+
+//Bloody shoes/footprints
+#define MAX_SHOE_BLOODINESS 100
+#define BLOODY_FOOTPRINT_BASE_ALPHA 150
+#define BLOOD_GAIN_PER_STEP 100
+#define BLOOD_LOSS_PER_STEP 5
+
+//Bloody shoe blood states
+#define BLOOD_STATE_HUMAN "blood"
+#define BLOOD_STATE_XENO "xeno"
+#define BLOOD_STATE_NOT_BLOODY "no blood whatsoever"
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index 59cbf9c6219..8d132ed2586 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -183,9 +183,7 @@
M.take_organ_damage(power)
if(prob(33)) // Added blood for whacking non-humans too
- var/turf/simulated/location = M.loc
- if(istype(location, /turf/simulated))
- location.add_blood_floor(M)
+ M.add_splatter_floor()
if("fire")
M.take_organ_damage(0, power)
to_chat(M, "Aargh it burns!")
diff --git a/code/datums/outfits/outfit_admin.dm b/code/datums/outfits/outfit_admin.dm
index 4a6f2a941ff..d70fc1ca4ac 100644
--- a/code/datums/outfits/outfit_admin.dm
+++ b/code/datums/outfits/outfit_admin.dm
@@ -587,6 +587,8 @@
apply_to_card(I, H, list(access_maint_tunnels), "Legit Xenomorph")
/datum/outfit/admin/soviet
+
+ gloves = /obj/item/clothing/gloves/combat
uniform = /obj/item/clothing/under/soviet
back = /obj/item/weapon/storage/backpack/satchel
head = /obj/item/clothing/head/ushanka
@@ -970,7 +972,7 @@
for(var/obj/item/I in H.contents)
if(!istype(I, /obj/item/weapon/implant))
- I.add_blood(H)
+ I.add_mob_blood(H)
if(visualsOnly)
return
@@ -1005,7 +1007,7 @@
for(var/obj/item/I in H.contents)
if(!istype(I, /obj/item/weapon/implant))
- I.add_blood(H)
+ I.add_mob_blood(H)
if(visualsOnly)
return
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 292ad651235..8c12e452d1d 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -242,7 +242,7 @@
if(density && !has_gravity(AM)) //thrown stuff bounces off dense stuff in no grav, unless the thrown stuff ends up inside what it hit(embedding, bola, etc...).
addtimer(src, "hitby_react", 2, TRUE, AM)
-/atom/proc/hitby_react(atom/movable/AM)
+/atom/proc/hitby_react(atom/movable/AM)
if(AM && isturf(AM.loc))
step(AM, turn(AM.dir, 180))
@@ -365,47 +365,194 @@
A.fingerprintshidden |= fingerprintshidden.Copy() //admin
A.fingerprintslast = fingerprintslast
+var/list/blood_splatter_icons = list()
-//returns 1 if made bloody, returns 0 otherwise
-/atom/proc/add_blood(mob/living/carbon/human/M as mob)
+/atom/proc/blood_splatter_index()
+ return "\ref[initial(icon)]-[initial(icon_state)]"
- if(!blood_DNA || !istype(blood_DNA, /list)) //if our list of DNA doesn't exist yet (or isn't a list) initialise it.
+//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)
+ var/mob/living/carbon/human/H = src
+ blood_dna[dna.unique_enzymes] = H.b_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)
+ var/new_blood_dna = L.get_blood_dna_list()
+ if(!new_blood_dna)
+ return 0
+ return transfer_blood_dna(new_blood_dna)
+
+/obj/effect/decal/cleanable/blood/splatter/transfer_mob_blood_dna(mob/living/L)
+ ..(L)
+ var/list/b_data = L.get_blood_data(L.get_blood_id())
+ if(b_data)
+ basecolor = b_data["blood_color"]
+ else
+ basecolor = "#A10808"
+ update_icon()
+
+/obj/effect/decal/cleanable/blood/footprints/transfer_mob_blood_dna(mob/living/L)
+ ..(L)
+ var/list/b_data = L.get_blood_data(L.get_blood_id())
+ if(b_data)
+ basecolor = b_data["blood_color"]
+ else
+ basecolor = "#A10808"
+ update_icon()
+
+//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
- blood_color = "#A10808"
- if(istype(M))
- if(M.species.flags & NO_BLOOD)
- return 0
- M.check_dna()
- blood_color = M.species.blood_color
- . = 1
+//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
+ var/bloodcolor = "#A10808"
+ var/list/b_data = M.get_blood_data(M.get_blood_id())
+ if(b_data)
+ bloodcolor = b_data["blood_color"]
+
+ return add_blood(blood_dna, bloodcolor)
+
+//to add blood onto something, with blood dna info to include.
+/atom/proc/add_blood(list/blood_dna, color)
+ return 0
+
+/obj/add_blood(list/blood_dna, color)
+ return transfer_blood_dna(blood_dna)
+
+/obj/item/add_blood(list/blood_dna, color)
+ var/blood_count = !blood_DNA ? 0 : blood_DNA.len
+ if(!..())
+ return 0
+ if(!blood_count)//apply the blood-splatter overlay if it isn't already in there
+ add_blood_overlay(color)
+ return 1 //we applied blood to the item
+
+/obj/item/clothing/gloves/add_blood(list/blood_dna, color)
+ . = ..()
+ transfer_blood = rand(2, 4)
+
+/turf/add_blood(list/blood_dna, color)
+ var/obj/effect/decal/cleanable/blood/splatter/B = locate() in src
+ if(!B)
+ B = new /obj/effect/decal/cleanable/blood/splatter(src)
+ B.transfer_blood_dna(blood_dna) //give blood info to the blood decal.
+ B.basecolor = color
+ return 1 //we bloodied the floor
+
+/mob/living/carbon/human/add_blood(list/blood_dna, color)
+ if(wear_suit)
+ wear_suit.add_blood(blood_dna, color)
+ wear_suit.blood_color = color
+ update_inv_wear_suit(1)
+ else if(w_uniform)
+ w_uniform.add_blood(blood_dna, color)
+ w_uniform.blood_color = color
+ update_inv_w_uniform(1)
+ if(head)
+ head.add_blood(blood_dna, color)
+ head.blood_color = color
+ update_inv_head(0,0)
+ if(glasses)
+ glasses.add_blood(blood_dna, color)
+ glasses.blood_color = color
+ update_inv_glasses(0)
+ if(gloves)
+ var/obj/item/clothing/gloves/G = gloves
+ G.add_blood(blood_dna, color)
+ G.blood_color = color
+ verbs += /mob/living/carbon/human/proc/bloody_doodle
+ else
+ hand_blood_color = color
+ bloody_hands = rand(2, 4)
+ transfer_blood_dna(blood_dna)
+ verbs += /mob/living/carbon/human/proc/bloody_doodle
+
+ update_inv_gloves(1) //handles bloody hands overlays and updating
return 1
-/atom/proc/add_blood_list(mob/living/carbon/M)
- // 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.
- 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.
- var/blood_type = "X*"
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- blood_type = H.b_type
- blood_DNA[M.dna.unique_enzymes] = blood_type
- return 1
+/obj/item/proc/add_blood_overlay(color)
+ 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]
+ if(!blood_splatter_icon)
+ blood_splatter_icon = icon(initial(icon), initial(icon_state), , 1) //we only want to apply blood-splatters to the initial icon_state for each object
+ blood_splatter_icon.Blend("#fff", ICON_ADD) //fills the icon_state with white (except where it's transparent)
+ blood_splatter_icon.Blend(icon('icons/effects/blood.dmi', "itemblood"), ICON_MULTIPLY) //adds blood and the remaining white areas become transparant
+ blood_splatter_icon = fcopy_rsc(blood_splatter_icon)
+ blood_splatter_icons[index] = blood_splatter_icon
-// Only adds blood on the floor -- Skie
-/atom/proc/add_blood_floor(mob/living/carbon/M)
- return //why the fuck this is at an atom level but only works on simulated turfs I don't know
+ blood_overlay = image(blood_splatter_icon)
+ blood_overlay.color = color
+ overlays += blood_overlay
/atom/proc/clean_blood()
- src.germ_level = 0
- if(istype(blood_DNA, /list))
- qdel(blood_DNA)
+ germ_level = 0
+ if(islist(blood_DNA))
+ blood_DNA = null
return 1
+
+/obj/item/clean_blood()
+ . = ..()
+ if(.)
+ if(blood_overlay)
+ overlays -= blood_overlay
+
+/obj/item/clothing/gloves/clean_blood()
+ . = ..()
+ if(.)
+ transfer_blood = 0
+
+
+/obj/item/clothing/shoes/clean_blood()
+ ..()
+ bloody_shoes = list(BLOOD_STATE_HUMAN = 0, BLOOD_STATE_XENO = 0, BLOOD_STATE_NOT_BLOODY = 0)
+ blood_state = BLOOD_STATE_NOT_BLOODY
+ if(ismob(loc))
+ var/mob/M = loc
+ M.update_inv_shoes()
+
+
+/mob/living/carbon/human/clean_blood()
+ if(gloves)
+ if(gloves.clean_blood())
+ clean_blood()
+ update_inv_gloves()
+ gloves.germ_level = 0
+ else
+ ..() // Clear the Blood_DNA list
+ if(bloody_hands)
+ bloody_hands = 0
+ update_inv_gloves()
+ update_icons() //apply the now updated overlays to the mob
+
+
/atom/proc/add_vomit_floor(mob/living/carbon/M as mob, var/toxvomit = 0)
if( istype(src, /turf/simulated) )
var/obj/effect/decal/cleanable/vomit/this = new /obj/effect/decal/cleanable/vomit(src)
diff --git a/code/game/gamemodes/changeling/powers/fleshmend.dm b/code/game/gamemodes/changeling/powers/fleshmend.dm
index cd09cc8d764..e6ccafcffa0 100644
--- a/code/game/gamemodes/changeling/powers/fleshmend.dm
+++ b/code/game/gamemodes/changeling/powers/fleshmend.dm
@@ -13,8 +13,6 @@
var/mob/living/carbon/human/H = user
H.restore_blood()
H.shock_stage = 0
- spawn(1)
- H.fixblood()
spawn(0)
for(var/i = 0, i<10,i++)
user.heal_overall_damage(10, 10)
diff --git a/code/game/gamemodes/changeling/powers/mutations.dm b/code/game/gamemodes/changeling/powers/mutations.dm
index 13378f6ff8e..943b15a6172 100644
--- a/code/game/gamemodes/changeling/powers/mutations.dm
+++ b/code/game/gamemodes/changeling/powers/mutations.dm
@@ -76,10 +76,8 @@
H.update_fhair()
if(blood_on_castoff)
- var/turf/simulated/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/changeling/powers/revive.dm b/code/game/gamemodes/changeling/powers/revive.dm
index 9077f623a2c..376e6d5a148 100644
--- a/code/game/gamemodes/changeling/powers/revive.dm
+++ b/code/game/gamemodes/changeling/powers/revive.dm
@@ -30,8 +30,6 @@
var/mob/living/carbon/human/H = user
H.restore_blood()
H.shock_stage = 0
- spawn(1)
- H.fixblood()
H.species.create_organs(H)
// Now that recreating all organs is necessary, the rest of this organ stuff probably
// isn't, but I don't want to remove it, just in case.
diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm
index 7ec4240769d..289ae7e4656 100644
--- a/code/game/gamemodes/cult/cult_items.dm
+++ b/code/game/gamemodes/cult/cult_items.dm
@@ -48,7 +48,7 @@
var/mob/living/carbon/human/bleeder = target
if(!(cooldown > world.time) && ((bleeder.stat != DEAD) && !(bleeder.species.flags & NO_BLOOD)))
user.visible_message("The runes on the blade absorb the blood of [target]!")
- bleeder.drip(5000)
+ bleeder.bleed(5000)
cooldown = world.time + 2400
/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 e58665c514e..09ca45e2049 100644
--- a/code/game/gamemodes/miniantags/abduction/gland.dm
+++ b/code/game/gamemodes/miniantags/abduction/gland.dm
@@ -181,21 +181,14 @@
uses = -1
/obj/item/organ/internal/heart/gland/bloody/activate()
- if(ishuman(owner))
- var/mob/living/carbon/human/H = owner
- H.drip(200)
+ owner.blood_volume -= 20
owner.visible_message("[owner]'s skin erupts with blood!",\
"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/internal/heart/gland/bodysnatch
cooldown_low = 600
@@ -211,8 +204,7 @@
C.Copy(owner)
C.Start()
owner.adjustBruteLoss(40)
- var/turf/T = get_turf(owner)
- T.add_blood_floor(src)
+ owner.add_splatter_floor()
/obj/effect/cocoon/abductor
name = "slimy cocoon"
diff --git a/code/game/gamemodes/vampire/vampire.dm b/code/game/gamemodes/vampire/vampire.dm
index 00c99e76f29..6e0cc7ebd22 100644
--- a/code/game/gamemodes/vampire/vampire.dm
+++ b/code/game/gamemodes/vampire/vampire.dm
@@ -289,20 +289,20 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
return
old_bloodtotal = bloodtotal
old_bloodusable = bloodusable
- if(!H.vessel.get_reagent_amount("blood"))
+ if(!H.blood_volume)
to_chat(owner, "They've got no blood left to give.")
break
if(H.stat < DEAD)
- blood = min(20, H.vessel.get_reagent_amount("blood")) // if they have less than 20 blood, give them the remnant else they get 20 blood
+ blood = min(20, H.blood_volume) // if they have less than 20 blood, give them the remnant else they get 20 blood
bloodtotal += blood / 2 //divide by 2 to counted the double suction since removing cloneloss -Melandor0
bloodusable += blood / 2
else
- blood = min(5, H.vessel.get_reagent_amount("blood")) // The dead only give 5 bloods
+ blood = min(5, H.blood_volume) // The dead only give 5 bloods
bloodtotal += blood
if(old_bloodtotal != bloodtotal)
to_chat(owner, "You have accumulated [bloodtotal] [bloodtotal > 1 ? "units" : "unit"] of blood[bloodusable != old_bloodusable ? ", and have [bloodusable] left to use" : ""].")
check_vampire_upgrade()
- H.vessel.remove_reagent("blood", 25)
+ H.blood_volume -= 25
if(ishuman(owner))
var/mob/living/carbon/human/V = owner
V.nutrition = min(NUTRITION_LEVEL_WELL_FED, V.nutrition + (blood / 2))
diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm
index c6f3b4c4280..88251dcdd36 100644
--- a/code/game/gamemodes/wizard/artefact.dm
+++ b/code/game/gamemodes/wizard/artefact.dm
@@ -525,7 +525,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/Sleeper.dm b/code/game/machinery/Sleeper.dm
index f74380432d2..5bd5b69d9dd 100644
--- a/code/game/machinery/Sleeper.dm
+++ b/code/game/machinery/Sleeper.dm
@@ -97,10 +97,10 @@
return
if(beaker.reagents.total_volume < beaker.reagents.maximum_volume)
- src.occupant.vessel.trans_to(beaker, 1)
+ src.occupant.transfer_blood_to(beaker, 1)
for(var/datum/reagent/x in src.occupant.reagents.reagent_list)
src.occupant.reagents.trans_to(beaker, 3)
- src.occupant.vessel.trans_to(beaker, 1)
+ src.occupant.transfer_blood_to(beaker, 1)
if(occupant)
for(var/A in occupant.reagents.addiction_list)
@@ -197,13 +197,12 @@
crisis = (occupant.health < min_health)
// I'm not sure WHY you'd want to put a simple_animal in a sleeper, but precedent is precedent
// Runtime is aptly named, isn't she?
- if(ishuman(occupant) && occupant.vessel && !(occupant.species && occupant.species.flags & NO_BLOOD))
- var/blood_type = occupant.get_blood_name()
+ if(ishuman(occupant) && !(occupant.species && occupant.species.flags & NO_BLOOD))
occupantData["pulse"] = occupant.get_pulse(GETPULSE_TOOL)
occupantData["hasBlood"] = 1
- occupantData["bloodLevel"] = round(occupant.vessel.get_reagent_amount(blood_type))
+ occupantData["bloodLevel"] = round(occupant.blood_volume)
occupantData["bloodMax"] = occupant.max_blood
- occupantData["bloodPercent"] = round(100*(occupant.vessel.get_reagent_amount(blood_type)/occupant.max_blood), 0.01)
+ occupantData["bloodPercent"] = round(100*(occupant.blood_volume/occupant.max_blood), 0.01)
data["occupant"] = occupantData
data["maxchem"] = max_chem
diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm
index 6d7264e9256..aeb3b37c7bd 100644
--- a/code/game/machinery/adv_med.dm
+++ b/code/game/machinery/adv_med.dm
@@ -364,14 +364,12 @@
var/bloodData[0]
bloodData["hasBlood"] = 0
- if(ishuman(H) && H.vessel && !(H.species && H.species.flags & NO_BLOOD))
- var/blood_type = H.get_blood_name()
- var/blood_volume = round(H.vessel.get_reagent_amount(blood_type))
+ if(ishuman(H) && !(H.species && H.species.flags & NO_BLOOD))
bloodData["hasBlood"] = 1
- bloodData["volume"] = blood_volume
- bloodData["percent"] = round(((blood_volume / BLOOD_VOLUME_NORMAL)*100))
+ bloodData["volume"] = H.blood_volume
+ bloodData["percent"] = round(((H.blood_volume / BLOOD_VOLUME_NORMAL)*100))
bloodData["pulse"] = H.get_pulse(GETPULSE_TOOL)
- bloodData["bloodLevel"] = blood_volume
+ bloodData["bloodLevel"] = H.blood_volume
bloodData["bloodMax"] = H.max_blood
occupantData["blood"] = bloodData
@@ -532,14 +530,11 @@
if(occupant.has_brain_worms())
dat += "Large growth detected in frontal lobe, possibly cancerous. Surgical removal is recommended.
"
- if(occupant.vessel)
- var/blood_type = occupant.get_blood_name()
- var/blood_volume = round(occupant.vessel.get_reagent_amount(blood_type))
- var/blood_percent = blood_volume / BLOOD_VOLUME_NORMAL
- blood_percent *= 100
+ var/blood_percent = round((occupant.blood_volume / BLOOD_VOLUME_NORMAL))
+ blood_percent *= 100
- extra_font = (blood_volume > 448 ? "" : "")
- dat += "[extra_font]\tBlood Level %: [blood_percent] ([blood_volume] units)
"
+ extra_font = (occupant.blood_volume > 448 ? "" : "")
+ dat += "[extra_font]\tBlood Level %: [blood_percent] ([occupant.blood_volume] units)
"
if(occupant.reagents)
dat += "Epinephrine units: [occupant.reagents.get_reagent_amount("Epinephrine")] units
"
diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm
index 19d61e0daf9..64b441b6170 100644
--- a/code/game/machinery/computer/Operating.dm
+++ b/code/game/machinery/computer/Operating.dm
@@ -148,13 +148,12 @@
occupantData["btCelsius"] = occupant.bodytemperature - T0C
occupantData["btFaren"] = ((occupant.bodytemperature - T0C) * (9.0/5.0))+ 32
- if(ishuman(occupant) && occupant.vessel && !(occupant.species && occupant.species.flags & NO_BLOOD))
- var/blood_type = occupant.get_blood_name()
+ if(ishuman(occupant) && !(occupant.species && occupant.species.flags & NO_BLOOD))
occupantData["pulse"] = occupant.get_pulse(GETPULSE_TOOL)
occupantData["hasBlood"] = 1
- occupantData["bloodLevel"] = round(occupant.vessel.get_reagent_amount(blood_type))
+ occupantData["bloodLevel"] = round(occupant.blood_volume)
occupantData["bloodMax"] = occupant.max_blood
- occupantData["bloodPercent"] = round(100*(occupant.vessel.get_reagent_amount(blood_type)/occupant.max_blood), 0.01) //copy pasta ends here
+ occupantData["bloodPercent"] = round(100*(occupant.blood_volume/occupant.max_blood), 0.01) //copy pasta ends here
occupantData["bloodType"]=occupant.b_type
if(occupant.surgeries.len)
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index d6b295e1811..2b2039c9743 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -278,9 +278,9 @@
L.Weaken(5)
else //for simple_animals & borgs
L.adjustBruteLoss(DOOR_CRUSH_DAMAGE)
- var/turf/simulated/location = loc
- if(istype(location, /turf/simulated)) //add_blood doesn't work for borgs/xenos, but add_blood_floor does.
- location.add_blood_floor(L)
+ var/turf/location = get_turf(src)
+ L.add_splatter_floor(location)
+
/obj/machinery/door/proc/requiresID()
return 1
diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm
index 26785e248b1..7ed7bc8dbc2 100644
--- a/code/game/machinery/iv_drip.dm
+++ b/code/game/machinery/iv_drip.dm
@@ -125,42 +125,15 @@
amount = min(amount, 4)
// If the beaker is full, ping
if(amount == 0)
- if(prob(5))
- visible_message("[src] pings.")
+ if(prob(5)) visible_message("\The [src] pings.")
return
- var/mob/living/carbon/human/T = attached
-
- if(!ishuman(T))
- return
-
- if(!T.dna)
- return
-
- if(NOCLONE in T.mutations)
- return
-
- if(T.species.flags & NO_BLOOD)
- return
-
- if(T.species.exotic_blood)
- T.vessel.trans_to(beaker, amount)
- update_icon()
- else
- 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 attached is losing too much blood, beep.
- var/blood_type = attached.get_blood_name()
- if(T.vessel.get_reagent_amount(blood_type) < BLOOD_VOLUME_SAFE && prob(5))
- visible_message("[src] beeps loudly.")
+ // 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))
diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm
index 698c1c5fe91..9cf58846feb 100644
--- a/code/game/machinery/recycler.dm
+++ b/code/game/machinery/recycler.dm
@@ -168,7 +168,7 @@ var/const/SAFETY_COOLDOWN = 100
gib = 0
if(L.stat == CONSCIOUS)
L.say("ARRRRRRRRRRRGH!!!")
- add_blood(L)
+ add_mob_blood(L)
if(!blood && !issilicon(L))
blood = 1
diff --git a/code/game/objects/effects/decals/Cleanable/aliens.dm b/code/game/objects/effects/decals/Cleanable/aliens.dm
index 57a32434af2..a3c2bc2c649 100644
--- a/code/game/objects/effects/decals/Cleanable/aliens.dm
+++ b/code/game/objects/effects/decals/Cleanable/aliens.dm
@@ -3,6 +3,8 @@
desc = "It's green and acidic. It looks like... blood?"
icon = 'icons/effects/blood.dmi'
basecolor = "#05EE05"
+ bloodiness = MAX_SHOE_BLOODINESS
+ blood_state = BLOOD_STATE_XENO
/obj/effect/decal/cleanable/blood/gibs/xeno
name = "xeno gibs"
diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm
index 37063b8a90b..2305bf8feb7 100644
--- a/code/game/objects/effects/decals/Cleanable/humans.dm
+++ b/code/game/objects/effects/decals/Cleanable/humans.dm
@@ -16,8 +16,12 @@ var/global/list/image/splatter_cache=list()
random_icon_states = list("mfloor1", "mfloor2", "mfloor3", "mfloor4", "mfloor5", "mfloor6", "mfloor7")
var/base_icon = 'icons/effects/blood.dmi'
var/list/viruses = list()
+ appearance_flags = NO_CLIENT_COLOR
+
blood_DNA = list()
- var/basecolor="#A10808" // Color when wet.
+ var/blood_state = BLOOD_STATE_HUMAN
+ var/bloodiness = MAX_SHOE_BLOODINESS
+ var/basecolor = "#A10808" // Color when wet.
var/amount = 5
appearance_flags = NO_CLIENT_COLOR
var/dry_timer = 0
@@ -33,11 +37,11 @@ var/global/list/image/splatter_cache=list()
mode_ticker.bloody_floors += T
mode_ticker.bloody_floors[T] = T
mode_ticker.blood_check()
- if(istype(src, /obj/effect/decal/cleanable/blood/gibs))
+ if(type == /obj/effect/decal/cleanable/blood/gibs)
return
- if(src.type == /obj/effect/decal/cleanable/blood)
- if(src.loc && isturf(src.loc))
- for(var/obj/effect/decal/cleanable/blood/B in src.loc)
+ if(type == /obj/effect/decal/cleanable/blood)
+ if(loc && isturf(loc))
+ for(var/obj/effect/decal/cleanable/blood/B in loc)
if(B != src)
if(B.blood_DNA)
blood_DNA |= B.blood_DNA.Copy()
@@ -59,44 +63,6 @@ var/global/list/image/splatter_cache=list()
if(basecolor == "rainbow") basecolor = "#[pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))]"
color = basecolor
-/obj/effect/decal/cleanable/blood/Crossed(mob/living/carbon/human/perp)
- if(!istype(perp))
- return
- if(amount < 1)
- return
-
- var/obj/item/organ/external/l_foot = perp.get_organ("l_foot")
- var/obj/item/organ/external/r_foot = perp.get_organ("r_foot")
- var/hasfeet = 1
- if((!l_foot || l_foot.status & ORGAN_DESTROYED) && (!r_foot || r_foot.status & ORGAN_DESTROYED))
- hasfeet = 0
- if(perp.shoes && !perp.buckled)//Adding blood to shoes
- var/obj/item/clothing/shoes/S = perp.shoes
- if(istype(S))
- S.blood_color = basecolor
- S.track_blood = max(amount,S.track_blood)
- if(!S.blood_overlay)
- S.generate_blood_overlay()
- if(!S.blood_DNA)
- S.blood_DNA = list()
- S.blood_overlay.color = basecolor
- S.overlays += S.blood_overlay
- if(S.blood_overlay && S.blood_overlay.color != basecolor)
- S.blood_overlay.color = basecolor
- S.overlays.Cut()
- S.overlays += S.blood_overlay
- S.blood_DNA |= blood_DNA.Copy()
-
- else if(hasfeet)//Or feet
- perp.feet_blood_color = basecolor
- perp.track_blood = max(amount,perp.track_blood)
- if(!perp.feet_blood_DNA)
- perp.feet_blood_DNA = list()
- perp.feet_blood_DNA |= blood_DNA.Copy()
-
- perp.update_inv_shoes(1)
- amount--
-
/obj/effect/decal/cleanable/blood/proc/dry()
name = dryname
desc = drydesc
@@ -123,6 +89,46 @@ var/global/list/image/splatter_cache=list()
/obj/effect/decal/cleanable/blood/can_bloodcrawl_in()
return TRUE
+//Add "bloodiness" of this blood's type, to the human's shoes
+/obj/effect/decal/cleanable/blood/Crossed(atom/movable/O)
+ if(ishuman(O))
+ var/mob/living/carbon/human/H = O
+ var/obj/item/organ/external/l_foot = H.get_organ("l_foot")
+ var/obj/item/organ/external/r_foot = H.get_organ("r_foot")
+ var/hasfeet = 1
+ if((!l_foot || l_foot.status & ORGAN_DESTROYED) && (!r_foot || r_foot.status & ORGAN_DESTROYED))
+ hasfeet = 0
+ if(H.shoes && blood_state && bloodiness)
+ var/obj/item/clothing/shoes/S = H.shoes
+ var/add_blood = 0
+ if(bloodiness >= BLOOD_GAIN_PER_STEP)
+ add_blood = BLOOD_GAIN_PER_STEP
+ else
+ 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(H.blood_DNA, basecolor)
+ S.blood_state = blood_state
+ S.blood_color = basecolor
+ update_icon()
+ H.update_inv_shoes()
+ else if(hasfeet && blood_state && bloodiness)//Or feet
+ var/add_blood = 0
+ if(bloodiness >= BLOOD_GAIN_PER_STEP)
+ add_blood = BLOOD_GAIN_PER_STEP
+ else
+ add_blood = bloodiness
+ bloodiness -= add_blood
+ H.bloody_feet[blood_state] = min(MAX_SHOE_BLOODINESS, H.bloody_feet[blood_state] + add_blood)
+ if(!H.feet_blood_DNA)
+ H.feet_blood_DNA = list()
+ H.blood_state = blood_state
+ H.feet_blood_DNA |= blood_DNA.Copy()
+ H.feet_blood_color = basecolor
+ update_icon()
+ H.update_inv_shoes()
+
/obj/effect/decal/cleanable/blood/splatter
random_icon_states = list("mgibbl1", "mgibbl2", "mgibbl3", "mgibbl4", "mgibbl5")
amount = 2
@@ -135,11 +141,25 @@ var/global/list/image/splatter_cache=list()
icon_state = "1"
random_icon_states = list("1","2","3","4","5")
amount = 0
- var/list/drips = list()
+ var/drips = 1
+ bloodiness = 0
-/obj/effect/decal/cleanable/blood/drip/New()
- ..()
- drips |= icon_state
+/obj/effect/decal/cleanable/blood/drip/can_bloodcrawl_in()
+ return TRUE
+
+/obj/effect/decal/cleanable/trail_holder //not a child of blood on purpose
+ name = "blood"
+ icon_state = "ltrails_1"
+ desc = "Your instincts say you shouldn't be following these."
+ gender = PLURAL
+ density = 0
+ layer = 2
+ random_icon_states = null
+ var/list/existing_dirs = list()
+ blood_DNA = list()
+
+/obj/effect/decal/cleanable/trail_holder/can_bloodcrawl_in()
+ return TRUE
/obj/effect/decal/cleanable/blood/writing
icon_state = "tracks"
@@ -176,19 +196,16 @@ var/global/list/image/splatter_cache=list()
noclear = 1
/obj/effect/decal/cleanable/blood/gibs/update_icon()
-
var/image/giblets = new(base_icon, "[icon_state]_flesh", dir)
if(!fleshcolor || fleshcolor == "rainbow")
fleshcolor = "#[pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))]"
giblets.color = fleshcolor
-
var/icon/blood = new(base_icon,"[icon_state]",dir)
- if(basecolor == "rainbow") basecolor = "#[pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))]"
- blood.Blend(basecolor,ICON_MULTIPLY)
icon = blood
overlays.Cut()
overlays += giblets
+ . = ..()
/obj/effect/decal/cleanable/blood/gibs/up
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibup1","gibup1","gibup1")
@@ -236,8 +253,16 @@ var/global/list/image/splatter_cache=list()
/obj/effect/decal/cleanable/blood/old/New()
..()
+ bloodiness = 0
dry()
+/obj/effect/decal/cleanable/blood/old/can_bloodcrawl_in()
+ return FALSE
+
/obj/effect/decal/cleanable/blood/gibs/old/New()
..()
+ bloodiness = 0
dry()
+
+/obj/effect/decal/cleanable/blood/gibs/old/can_bloodcrawl_in()
+ return FALSE
diff --git a/code/game/objects/effects/decals/Cleanable/robots.dm b/code/game/objects/effects/decals/Cleanable/robots.dm
index 5fc09b6ec34..dbebd72066d 100644
--- a/code/game/objects/effects/decals/Cleanable/robots.dm
+++ b/code/game/objects/effects/decals/Cleanable/robots.dm
@@ -5,13 +5,17 @@
icon_state = "gib1"
basecolor="#030303"
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7")
+ bloodiness = MAX_SHOE_BLOODINESS
+
+/obj/effect/decal/cleanable/blood/gibs/robot/can_bloodcrawl_in()
+ return FALSE
/obj/effect/decal/cleanable/blood/gibs/robot/update_icon()
color = "#FFFFFF"
/obj/effect/decal/cleanable/blood/gibs/robot/dry() //pieces of robots do not dry up like
return
-
+
/obj/effect/decal/cleanable/blood/gibs/robot/can_bloodcrawl_in()
return FALSE
@@ -44,6 +48,7 @@
name = "motor oil"
desc = "It's black and greasy. Looks like Beepsky made another mess."
basecolor="#030303"
+ bloodiness = MAX_SHOE_BLOODINESS
/obj/effect/decal/cleanable/blood/oil/can_bloodcrawl_in()
return FALSE
diff --git a/code/game/objects/effects/decals/Cleanable/tracks.dm b/code/game/objects/effects/decals/Cleanable/tracks.dm
index ad404ce28b3..20dee798e8d 100644
--- a/code/game/objects/effects/decals/Cleanable/tracks.dm
+++ b/code/game/objects/effects/decals/Cleanable/tracks.dm
@@ -1,165 +1,104 @@
-// Stolen en masse from N3X15 of /vg/station with much gratitude.
-
-// The idea is to have 4 bits for coming and 4 for going.
-#define TRACKS_COMING_NORTH 1
-#define TRACKS_COMING_SOUTH 2
-#define TRACKS_COMING_EAST 4
-#define TRACKS_COMING_WEST 8
-#define TRACKS_GOING_NORTH 16
-#define TRACKS_GOING_SOUTH 32
-#define TRACKS_GOING_EAST 64
-#define TRACKS_GOING_WEST 128
-
// 5 seconds
#define TRACKS_CRUSTIFY_TIME 50
// color-dir-dry
var/global/list/image/fluidtrack_cache=list()
-/datum/fluidtrack
- var/direction=0
- var/basecolor="#A10808"
- var/wet=0
- var/fresh=1
- var/crusty=0
- var/image/overlay
-
- New(_direction,item_color,_wet)
- src.direction=_direction
- src.basecolor=item_color
- src.wet=_wet
-
// Footprints, tire trails...
/obj/effect/decal/cleanable/blood/tracks
- amount = 0
- random_icon_states = null
- var/dirs=0
icon = 'icons/effects/fluidtracks.dmi'
- icon_state = ""
- var/coming_state="blood1"
- var/going_state="blood2"
- var/updatedtracks=0
-
- // dir = id in stack
- var/list/setdirs=list(
- "1"=0,
- "2"=0,
- "4"=0,
- "8"=0,
- "16"=0,
- "32"=0,
- "64"=0,
- "128"=0
- )
-
- // List of laid tracks and their colors.
- var/list/datum/fluidtrack/stack=list()
-
- /**
- * Add tracks to an existing trail.
- *
- * @param DNA bloodDNA to add to collection.
- * @param comingdir Direction tracks come from, or 0.
- * @param goingdir Direction tracks are going to (or 0).
- * @param bloodcolor Color of the blood when wet.
- */
- proc/AddTracks(var/list/DNA, var/comingdir, var/goingdir, var/bloodcolor="#A10808")
- var/updated=0
- // Shift our goingdir 4 spaces to the left so it's in the GOING bitblock.
- var/realgoing=goingdir<<4
-
- // Current bit
- var/b=0
-
- // When tracks will start to dry out
- var/t=world.time + TRACKS_CRUSTIFY_TIME
-
- var/datum/fluidtrack/track
-
- // Process 4 bits
- for(var/bi=0;bi<4;bi++)
- b = 1 << bi
- // COMING BIT
- // If setting
- if(comingdir&b)
- // If not wet or not set
- if(dirs&b)
- var/sid=setdirs["[b]"]
- track=stack[sid]
- if(track.wet==t && track.basecolor==bloodcolor)
- continue
- // Remove existing stack entry
- stack.Remove(track)
- track=new /datum/fluidtrack(b,bloodcolor,t)
- stack.Add(track)
- setdirs["[b]"]=stack.Find(track)
- updatedtracks |= b
- updated=1
-
- // GOING BIT (shift up 4)
- b=b<<4
- if(realgoing&b)
- // If not wet or not set
- if(dirs&b)
- var/sid=setdirs["[b]"]
- track=stack[sid]
- if(track.wet==t && track.basecolor==bloodcolor)
- continue
- // Remove existing stack entry
- stack.Remove(track)
- track=new /datum/fluidtrack(b,bloodcolor,t)
- stack.Add(track)
- setdirs["[b]"]=stack.Find(track)
- updatedtracks |= b
- updated=1
-
- dirs |= comingdir|realgoing
- blood_DNA |= DNA.Copy()
- if(updated)
- update_icon()
-
- update_icon()
- overlays.Cut()
- color = "#FFFFFF"
- var/truedir=0
-
- // Update ONLY the overlays that have changed.
- for(var/datum/fluidtrack/track in stack)
- var/stack_idx=setdirs["[track.direction]"]
- var/state=coming_state
- truedir=track.direction
- if(truedir&240) // Check if we're in the GOING block
- state=going_state
- truedir=truedir>>4
-
- if(track.overlay)
- track.overlay=null
- var/image/I = image(icon, icon_state=state, dir=num2dir(truedir))
- I.color = track.basecolor
-
- track.fresh=0
- track.overlay=I
- stack[stack_idx]=track
- overlays += I
- updatedtracks=0 // Clear our memory of updated tracks.
-
-/obj/effect/decal/cleanable/blood/tracks/footprints
- name = "wet footprints"
- dryname = "dried footprints"
- desc = "Whoops..."
- drydesc = "Whoops..."
- coming_state = "human1"
- going_state = "human2"
- amount = 0
-
-/obj/effect/decal/cleanable/blood/tracks/wheels
name = "wet tracks"
dryname = "dried tracks"
desc = "Whoops..."
drydesc = "Whoops..."
- coming_state = "wheels1"
- going_state = "wheels2"
- desc = "They look like tracks left by wheels."
+ icon_state = "wheels1"
gender = PLURAL
random_icon_states = null
- amount = 0
\ No newline at end of file
+ amount = 0
+
+//BLOODY FOOTPRINTS
+/obj/effect/decal/cleanable/blood/footprints
+ icon = 'icons/effects/fluidtracks.dmi'
+ icon_state = "nothingwhatsoever"
+ desc = "You REALLY shouldn't follow these.."
+ gender = PLURAL
+ random_icon_states = null
+ basecolor="#A10808"
+ var/entered_dirs = 0
+ var/exited_dirs = 0
+ blood_state = BLOOD_STATE_HUMAN //the icon state to load images from
+
+
+/obj/effect/decal/cleanable/blood/footprints/Crossed(atom/movable/O)
+ if(ishuman(O))
+ var/mob/living/carbon/human/H = O
+ var/obj/item/clothing/shoes/S = H.shoes
+ var/obj/item/organ/external/l_foot = H.get_organ("l_foot")
+ var/obj/item/organ/external/r_foot = H.get_organ("r_foot")
+ var/hasfeet = 1
+ if((!l_foot || l_foot.status & ORGAN_DESTROYED) && (!r_foot || r_foot.status & ORGAN_DESTROYED))
+ hasfeet = 0
+ if(S && S.bloody_shoes[blood_state] && S.blood_color == basecolor)
+ S.bloody_shoes[blood_state] = max(S.bloody_shoes[blood_state] - BLOOD_LOSS_PER_STEP, 0)
+ entered_dirs |= H.dir
+ if(!S.blood_DNA)
+ S.blood_DNA = list()
+ S.blood_DNA |= blood_DNA.Copy()
+ else if(hasfeet && H.bloody_feet[blood_state] && H.feet_blood_color == basecolor)//Or feet //This will need to be changed.
+ H.bloody_feet[blood_state] = max(H.bloody_feet[blood_state] - BLOOD_LOSS_PER_STEP, 0)
+ entered_dirs |= H.dir
+ if(!H.feet_blood_DNA)
+ H.feet_blood_DNA = list()
+ H.feet_blood_DNA |= blood_DNA.Copy()
+ update_icon()
+
+/obj/effect/decal/cleanable/blood/footprints/Uncrossed(atom/movable/O)
+ if(ishuman(O))
+ var/mob/living/carbon/human/H = O
+ var/obj/item/clothing/shoes/S = H.shoes
+ var/obj/item/organ/external/l_foot = H.get_organ("l_foot")
+ var/obj/item/organ/external/r_foot = H.get_organ("r_foot")
+ var/hasfeet = 1
+ if((!l_foot || l_foot.status & ORGAN_DESTROYED) && (!r_foot || r_foot.status & ORGAN_DESTROYED))
+ hasfeet = 0
+ if(S && S.bloody_shoes[blood_state] && S.blood_color == basecolor)
+ S.bloody_shoes[blood_state] = max(S.bloody_shoes[blood_state] - BLOOD_LOSS_PER_STEP, 0)
+ exited_dirs |= H.dir
+ if(!S.blood_DNA)
+ S.blood_DNA = list()
+ S.blood_DNA |= blood_DNA.Copy()
+ else if(hasfeet && H.bloody_feet[blood_state] && H.feet_blood_color == basecolor)//Or feet
+ H.bloody_feet[blood_state] = max(H.bloody_feet[blood_state] - BLOOD_LOSS_PER_STEP, 0)
+ exited_dirs |= H.dir
+ if(!H.feet_blood_DNA)
+ H.feet_blood_DNA = list()
+ H.feet_blood_DNA |= blood_DNA.Copy()
+ update_icon()
+
+
+/obj/effect/decal/cleanable/blood/footprints/update_icon()
+ overlays.Cut()
+
+ for(var/Ddir in cardinal)
+ if(entered_dirs & Ddir)
+ var/image/I
+ if(fluidtrack_cache["entered-[blood_state]-[Ddir]"])
+ I = fluidtrack_cache["entered-[blood_state]-[Ddir]"]
+ else
+ I = image(icon,"[blood_state]1",dir = Ddir)
+ fluidtrack_cache["entered-[blood_state]-[Ddir]"] = I
+ if(I)
+ I.color = basecolor
+ overlays += I
+ if(exited_dirs & Ddir)
+ var/image/I
+ if(fluidtrack_cache["exited-[blood_state]-[Ddir]"])
+ I = fluidtrack_cache["exited-[blood_state]-[Ddir]"]
+ else
+ I = image(icon,"[blood_state]2",dir = Ddir)
+ fluidtrack_cache["exited-[blood_state]-[Ddir]"] = I
+ if(I)
+ I.color = basecolor
+ overlays += I
+
+ alpha = BLOODY_FOOTPRINT_BASE_ALPHA+bloodiness
\ No newline at end of file
diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm
index cfde9ab55a4..f2a936eca57 100644
--- a/code/game/objects/effects/decals/cleanable.dm
+++ b/code/game/objects/effects/decals/cleanable.dm
@@ -43,4 +43,4 @@
if(reagents)
reagents.chem_temp += 30
reagents.handle_reactions()
- ..()
\ No newline at end of file
+ ..()
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 294dda0d674..9f92bfa87f7 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -474,51 +474,6 @@ var/global/image/fire_overlay = image("icon" = 'icons/goonstation/effects/fire.d
M.AdjustEyeBlurry(rand(3,4))
return
-/obj/item/clean_blood()
- . = ..()
- if(blood_overlay)
- overlays.Remove(blood_overlay)
- if(istype(src, /obj/item/clothing/gloves))
- var/obj/item/clothing/gloves/G = src
- G.transfer_blood = 0
-
-
-/obj/item/add_blood(mob/living/carbon/human/M as mob)
- if(!..())
- return 0
-
- if(istype(src, /obj/item/weapon/melee/energy))
- return
-
- //if we haven't made our blood_overlay already
- if( !blood_overlay )
- generate_blood_overlay()
-
- //apply the blood-splatter overlay if it isn't already in there
- if(!blood_DNA.len)
- blood_overlay.color = blood_color
- overlays += blood_overlay
-
- //if this blood isn't already in the list, add it
- if(istype(M))
- 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.b_type
- return 1 //we applied blood to the item
-
-/obj/item/proc/generate_blood_overlay()
- if(blood_overlay)
- return
-
- var/icon/I = new /icon(icon, icon_state)
- I.Blend(new /icon('icons/effects/blood.dmi', rgb(255,255,255)),ICON_ADD) //fills the icon_state with white (except where it's transparent)
- I.Blend(new /icon('icons/effects/blood.dmi', "itemblood"),ICON_MULTIPLY) //adds blood and the remaining white areas become transparant
-
- //not sure if this is worth it. It attaches the blood_overlay to every item of the same type if they don't have one already made.
- for(var/obj/item/A in world)
- if(A.type == type && !A.blood_overlay)
- A.blood_overlay = image(I)
-
/obj/item/singularity_pull(S, current_size)
spawn(0) //this is needed or multiple items will be thrown sequentially and not simultaneously
if(current_size >= STAGE_FOUR)
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index e31c49f9392..7603ba459ff 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -14,6 +14,7 @@ REAGENT SCANNER
icon_state = "t-ray0"
var/on = 0
slot_flags = SLOT_BELT
+ w_class = 2
w_class = WEIGHT_CLASS_SMALL
item_state = "electronic"
materials = list(MAT_METAL=150)
@@ -223,20 +224,21 @@ REAGENT SCANNER
for(var/datum/wound/W in e.wounds) if(W.internal)
user.show_message(text("Internal bleeding detected. Advanced scanner required for location."), 1)
break
- if(H.vessel)
- var/blood_type = H.get_blood_name()
- var/blood_volume = round(H.vessel.get_reagent_amount(blood_type))
- var/blood_percent = blood_volume / BLOOD_VOLUME_NORMAL
- blood_percent *= 100
- if(blood_volume <= 500)
- user.show_message("Warning: Blood Level LOW: [blood_percent]% [blood_volume]cl")
- else if(blood_volume <= 336)
- user.show_message("Warning: Blood Level CRITICAL: [blood_percent]% [blood_volume]cl")
- else
- user.show_message("Blood Level Normal: [blood_percent]% [blood_volume]cl")
- if(H.species.exotic_blood)
- user.show_message("Subject possesses exotic blood.")
- user.show_message("Exotic blood type: [blood_type].")
+ var/blood_id = H.get_blood_id()
+ if(blood_id)
+ if(H.bleed_rate)
+ to_chat(user, "Subject is bleeding!")
+ var/blood_percent = round((H.blood_volume / BLOOD_VOLUME_NORMAL)*100)
+ var/blood_type = H.b_type
+ if(blood_id != "blood")//special blood substance
+ blood_type = blood_id
+ if(H.blood_volume <= BLOOD_VOLUME_SAFE && H.blood_volume > BLOOD_VOLUME_OKAY)
+ user.show_message("LOW blood level [blood_percent] %, [H.blood_volume] cl, type: [blood_type]")
+ else if(H.blood_volume <= BLOOD_VOLUME_OKAY)
+ to_chat(user, "CRITICAL blood level [blood_percent] %, [H.blood_volume] cl, type: [blood_type]")
+
+ user.show_message("blood type: [blood_type].")
+
if(H.undergoing_cardiac_arrest() && H.stat != DEAD)
user.show_message("Subject suffering from heart attack: Apply defibrillator immediately.")
user.show_message("Subject's pulse: [H.get_pulse(GETPULSE_TOOL)] bpm.")
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index 82d2ce8c024..e63d74af020 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -11,6 +11,7 @@
var/heal_burn = 0
var/self_delay = 20
var/unique_handling = 0 //some things give a special prompt, do we want to bypass some checks in parent?
+ var/stop_bleeding = 0
/obj/item/stack/medical/attack(mob/living/M, mob/user)
if(!iscarbon(M) && !isanimal(M))
@@ -37,6 +38,14 @@
to_chat(user, "This can't be used on a robotic limb.")
return 1
+ if(stop_bleeding)
+ if(H.bleedsuppress)
+ to_chat(user, "[H]'s bleeding is already bandaged!")
+ return 1
+ else if(!H.bleed_rate)
+ to_chat(user, "[H] isn't bleeding!")
+ return 1
+
if(M == user && !unique_handling)
user.visible_message("[user] starts to apply [src] on [H]...")
if(!do_mob(user, H, self_delay))
@@ -76,6 +85,7 @@
desc = "Some sterile gauze to wrap around bloody stumps."
icon_state = "gauze"
origin_tech = "biotech=2"
+ stop_bleeding = 1800
/obj/item/stack/medical/bruise_pack/attack(mob/living/M, mob/user)
if(..())
@@ -96,6 +106,9 @@
user.visible_message("[user] bandages the wounds on [H]'s [affecting.name].", \
"You bandage the wounds on [H]'s [affecting.name]." )
+ if(stop_bleeding)
+ if(!H.bleedsuppress) //so you can't stack bleed suppression
+ H.suppress_bloodloss(stop_bleeding)
affecting.heal_damage(heal_brute, heal_burn)
H.UpdateDamageIcon()
use(1)
diff --git a/code/game/objects/items/weapons/scissors.dm b/code/game/objects/items/weapons/scissors.dm
index 345d2d2a571..e519b96d0fd 100644
--- a/code/game/objects/items/weapons/scissors.dm
+++ b/code/game/objects/items/weapons/scissors.dm
@@ -117,9 +117,8 @@
user.visible_message("[user] abruptly stops cutting [M]'s hair and slices their throat!", "You stop cutting [M]'s hair and slice their throat!") //Just a little off the top.
H.AdjustLoseBreath(10) //30 Oxy damage over time
H.apply_damage(18, BRUTE, "head", sharp =1, used_weapon = "scissors")
- var/turf/location = get_turf(H)
- if(istype(location, /turf/simulated))
- location.add_blood(H)
+ var/turf/location = get_turf(src)
+ H.add_splatter_floor(location)
H.bloody_hands(H)
H.bloody_body(H)
var/mob/living/carbon/human/U = user
diff --git a/code/game/objects/items/weapons/soap.dm b/code/game/objects/items/weapons/soap.dm
index e4183b5bafd..85dfe4868d0 100644
--- a/code/game/objects/items/weapons/soap.dm
+++ b/code/game/objects/items/weapons/soap.dm
@@ -38,7 +38,7 @@
else if(istype(target,/mob/living/carbon))
for(var/obj/item/carried_item in target.contents)
if(!istype(carried_item, /obj/item/weapon/implant))//If it's not an implant.
- carried_item.add_blood(target)//Oh yes, there will be blood...
+ carried_item.add_mob_blood(target)//Oh yes, there will be blood...
var/mob/living/carbon/human/H = target
H.bloody_hands(target,0)
H.bloody_body(target)
diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm
index 043177551ff..73c47ba98a6 100644
--- a/code/game/objects/structures/kitchen_spike.dm
+++ b/code/game/objects/structures/kitchen_spike.dm
@@ -82,9 +82,8 @@
playsound(loc, 'sound/effects/splat.ogg', 25, 1)
H.forceMove(loc)
H.emote("scream")
- if(istype(H, /mob/living/carbon/human)) //So you don't get human blood when you spike a giant spidere
- var/turf/simulated/pos = get_turf(H)
- pos.add_blood_floor(H)
+ if(ishuman(H))
+ H.add_splatter_floor()
H.adjustBruteLoss(30)
H.buckled = src
H.dir = 2
diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm
index cf1a1303025..22ccbecfdf6 100644
--- a/code/game/turfs/simulated.dm
+++ b/code/game/turfs/simulated.dm
@@ -45,12 +45,6 @@
if(wet_overlay)
overlays -= wet_overlay
-/turf/simulated/proc/AddTracks(var/typepath,var/bloodDNA,var/comingdir,var/goingdir,var/bloodcolor="#A10808")
- var/obj/effect/decal/cleanable/blood/tracks/tracks = locate(typepath) in src
- if(!tracks)
- tracks = new typepath(src)
- tracks.AddTracks(bloodDNA,comingdir,goingdir,bloodcolor)
-
/turf/simulated/Entered(atom/A, atom/OL, ignoreRest = 0)
..()
if(!ignoreRest)
@@ -73,29 +67,6 @@
if(M.flying)
return ..()
- // Tracking blood
- var/list/bloodDNA = null
- var/bloodcolor = ""
- if(M.shoes)
- var/obj/item/clothing/shoes/S = M.shoes
- if(S.track_blood && S.blood_DNA)
- bloodDNA = S.blood_DNA
- bloodcolor = S.blood_color
- S.track_blood--
- else
- if(M.track_blood && M.feet_blood_DNA)
- bloodDNA = M.feet_blood_DNA
- bloodcolor = M.feet_blood_color
- M.track_blood--
-
- if(bloodDNA)
- src.AddTracks(/obj/effect/decal/cleanable/blood/tracks/footprints,bloodDNA,M.dir,0,bloodcolor) // Coming
- var/turf/simulated/from = get_step(M,reverse_direction(M.dir))
- if(istype(from) && from)
- from.AddTracks(/obj/effect/decal/cleanable/blood/tracks/footprints,bloodDNA,0,M.dir,bloodcolor) // Going
-
- bloodDNA = null
-
switch(src.wet)
if(TURF_WET_WATER)
if(!(M.slip("wet floor", 4, 2, 0, 1)))
@@ -110,32 +81,6 @@
if(!(prob(30) && M.slip("icy floor", 4, 2, 1, 1)))
M.inertia_dir = 0
-
-//returns 1 if made bloody, returns 0 otherwise
-/turf/simulated/add_blood(mob/living/carbon/human/M)
- if(!..())
- return 0
-
- if(!istype(M)) // To avoid non-humans from causing runtimes whena dding blood to the floor
- return 0
- var/obj/effect/decal/cleanable/blood/B = locate() in contents //check for existing blood splatter
- if(!B)
- B = blood_splatter(src,M.get_blood(M.vessel),1)
- if(B)
- B.add_blood_list(M)
- return 1 //we bloodied the floor
- return 0 // Clean floors club
-
-// Only adds blood on the floor -- Skie
-/turf/simulated/add_blood_floor(mob/living/carbon/M as mob)
- if(ishuman(M))
- blood_splatter(src,M,1)
- if( istype(M, /mob/living/carbon/alien ))
- var/obj/effect/decal/cleanable/blood/xeno/this = new /obj/effect/decal/cleanable/blood/xeno(src)
- this.blood_DNA["UNKNOWN BLOOD"] = "X*"
- else if( istype(M, /mob/living/silicon/robot ))
- new /obj/effect/decal/cleanable/blood/oil(src)
-
/turf/simulated/ChangeTurf(var/path)
. = ..()
smooth_icon_neighbors(src)
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 596259b47da..94b9e50d37b 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -372,6 +372,8 @@ BLIND // can't see anything
var/silence_steps = 0
var/shoe_sound_footstep = 1
var/shoe_sound = null
+ var/blood_state = BLOOD_STATE_NOT_BLOODY
+ var/list/bloody_shoes = list(BLOOD_STATE_HUMAN = 0, BLOOD_STATE_XENO = 0, BLOOD_STATE_NOT_BLOODY = 0)
permeability_coefficient = 0.50
slowdown = SHOES_SLOWDOWN
diff --git a/code/modules/detective_work/detective_work.dm b/code/modules/detective_work/detective_work.dm
index dd22a439c19..cc53bacc956 100644
--- a/code/modules/detective_work/detective_work.dm
+++ b/code/modules/detective_work/detective_work.dm
@@ -6,10 +6,10 @@ atom/proc/add_fibers(mob/living/carbon/human/M)
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, G.blood_color)) //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.hand_blood_color))
M.bloody_hands--
if(!suit_fibers) suit_fibers = list()
var/fibertext
diff --git a/code/modules/detective_work/footprints_and_rag.dm b/code/modules/detective_work/footprints_and_rag.dm
index cc6a463a0ee..f0d99152574 100644
--- a/code/modules/detective_work/footprints_and_rag.dm
+++ b/code/modules/detective_work/footprints_and_rag.dm
@@ -1,18 +1,13 @@
/mob
var/bloody_hands = 0
- var/mob/living/carbon/human/bloody_hands_mob
- var/track_blood = 0
var/list/feet_blood_DNA
- var/track_blood_type
var/feet_blood_color
+ var/blood_state = BLOOD_STATE_NOT_BLOODY
+ var/list/bloody_feet = list(BLOOD_STATE_HUMAN = 0, BLOOD_STATE_XENO = 0, BLOOD_STATE_NOT_BLOODY = 0)
/obj/item/clothing/gloves
var/transfer_blood = 0
- var/mob/living/carbon/human/bloody_hands_mob
-
-/obj/item/clothing/shoes/
- var/track_blood = 0
/obj/item/weapon/reagent_containers/glass/rag
name = "damp rag"
diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm
index eef224e8378..8bd8ffe5eed 100644
--- a/code/modules/mob/living/carbon/alien/alien.dm
+++ b/code/modules/mob/living/carbon/alien/alien.dm
@@ -294,3 +294,9 @@ Des: Removes all infected images from the alien.
playsound(T, S, volume, 1, range)
return 1
return 0
+
+/mob/living/carbon/alien/getTrail()
+ if(getBruteLoss() < 200)
+ return pick("xltrails_1", "xltrails_2")
+ else
+ return pick("xttrails_1", "xttrails_2")
\ 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 fa6a3f8a92b..0c4c34d6b40 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -107,7 +107,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
@@ -477,21 +477,6 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump,
if(istype(loc, /obj/machinery/atmospherics))
add_ventcrawl(loc)
-/mob/living/carbon/clean_blood()
- . = ..()
- if(ishuman(src))
- var/mob/living/carbon/human/H = src
- if(H.gloves)
- if(H.gloves.clean_blood())
- H.update_inv_gloves(0,0)
- H.gloves.germ_level = 0
- else
- if(H.bloody_hands)
- H.bloody_hands = 0
- H.update_inv_gloves(0,0)
- H.germ_level = 0
- update_icons() //apply the now updated overlays to the mob
-
//Throwing stuff
diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm
index ab7a5f1d5a9..a409e8460db 100644
--- a/code/modules/mob/living/carbon/carbon_defines.dm
+++ b/code/modules/mob/living/carbon/carbon_defines.dm
@@ -30,3 +30,5 @@
var/failed_last_breath = 0 //This is used to determine if the mob failed a breath. If they did fail a brath, they will attempt to breathe each tick, otherwise just once per 4 ticks.
var/co2overloadtime = null
+
+ blood_volume = BLOOD_VOLUME_NORMAL
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 961ee9ffd0b..9bb3308c944 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -441,6 +441,11 @@
if(display_gloves)
msg += "[src] has blood running from under [t_his] gloves!\n"
+ 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(digitalcamo)
msg += "[t_He] [t_is] repulsively uncanny!\n"
if(!(skipface || ( wear_mask && ( wear_mask.flags_inv & HIDEFACE || wear_mask.flags_cover & MASKCOVERSMOUTH) ) ) && is_thrall(src) && in_range(user,src))
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index cb3d7723537..76aa7eaa483 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -33,7 +33,6 @@
create_reagents(330)
prev_gender = gender // Debug for plural genders
- make_blood()
martial_art = default_martial_art
@@ -539,12 +538,10 @@
popup.open()
-// called when something steps onto a human
-// this handles mulebots and vehicles
-/mob/living/carbon/human/Crossed(var/atom/movable/AM)
- if(istype(AM, /obj/vehicle))
- var/obj/vehicle/V = AM
- V.RunOver(src)
+/mob/living/carbon/human/Crossed(atom/movable/AM)
+ var/mob/living/simple_animal/bot/mulebot/MB = AM
+ if(istype(MB))
+ MB.RunOver(src)
// Get rank from ID, ID inside PDA, PDA, ID in wallet, etc.
/mob/living/carbon/human/proc/get_authentification_rank(var/if_no_id = "No id", var/if_no_job = "No job")
@@ -1255,12 +1252,6 @@
I.insert(H)
/mob/living/carbon/human/revive()
-
- if(species && !(species.flags & NO_BLOOD))
- var/blood_reagent = get_blood_name()
- vessel.add_reagent(blood_reagent, max_blood-vessel.total_volume)
- fixblood()
-
//Fix up all organs and replace lost ones.
restore_all_organs() //Rejuvenate and reset all existing organs.
check_and_regenerate_organs(src) //Regenerate limbs and organs only if they're really missing.
@@ -1332,23 +1323,13 @@
*/
//returns 1 if made bloody, returns 0 otherwise
-/mob/living/carbon/human/add_blood(mob/living/carbon/human/M as mob)
- if(!..())
- return 0
- //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.b_type
- hand_blood_color = blood_color
- src.update_inv_gloves()
- verbs += /mob/living/carbon/human/proc/bloody_doodle
- return 1 //we applied blood to the item
-
/mob/living/carbon/human/clean_blood(var/clean_feet)
.=..()
if(clean_feet && !shoes && istype(feet_blood_DNA, /list) && feet_blood_DNA.len)
feet_blood_color = null
qdel(feet_blood_DNA)
+ bloody_feet = list(BLOOD_STATE_HUMAN = 0, BLOOD_STATE_XENO = 0, BLOOD_STATE_NOT_BLOODY = 0)
+ blood_state = BLOOD_STATE_NOT_BLOODY
update_inv_shoes(1)
return 1
@@ -1443,10 +1424,6 @@
tail = species.tail
- if(vessel)
- vessel = null
- make_blood()
-
maxHealth = species.total_health
toxins_alert = 0
@@ -1543,7 +1520,6 @@
overlays.Cut()
update_mutantrace(1)
regenerate_icons()
- fixblood()
if(!delay_icon_update)
UpdateAppearance()
diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm
index 4b1e8e66b1b..9a96ec72c28 100644
--- a/code/modules/mob/living/carbon/human/human_damage.dm
+++ b/code/modules/mob/living/carbon/human/human_damage.dm
@@ -300,15 +300,6 @@
////////////////////////////////////////////
-/*
-This function restores the subjects blood to max.
-*/
-/mob/living/carbon/human/proc/restore_blood()
- if(!(species.flags & NO_BLOOD))
- var/blood_type = get_blood_name()
- var/blood_volume = vessel.get_reagent_amount(blood_type)
- vessel.add_reagent(blood_type, BLOOD_VOLUME_NORMAL - blood_volume)
-
/*
This function restores all organs.
*/
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 4926b60e267..8b9629d656b 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -8,6 +8,7 @@ emp_act
*/
+
/mob/living/carbon/human/bullet_act(obj/item/projectile/P, def_zone)
if(P.is_reflectable)
@@ -185,7 +186,7 @@ emp_act
newmeat.subjectjob = src.job
newmeat.reagents.add_reagent ("nutriment", (src.nutrition / 15) / 3)
src.reagents.trans_to (newmeat, round ((src.reagents.total_volume) / 3, 1))
- src.loc.add_blood(src)
+ add_mob_blood(src)
--src.meatleft
to_chat(user, "You hack off a chunk of meat from [src.name]")
if(!src.meatleft)
@@ -232,19 +233,18 @@ emp_act
var/bloody = 0
if(I.damtype == BRUTE && I.force && prob(25 + I.force * 2))
- I.add_blood(src) //Make the weapon bloody, not the person.
+ I.add_mob_blood(src) //Make the weapon bloody, not the person.
// if(user.hand) user.update_inv_l_hand() //updates the attacker's overlay for the (now bloodied) weapon
// else user.update_inv_r_hand() //removed because weapons don't have on-mob blood overlays
- if(prob(33))
+ if(prob(I.force * 2)) //blood spatter!
bloody = 1
var/turf/location = loc
if(istype(location, /turf/simulated))
- location.add_blood(src)
+ add_splatter_floor(location)
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(get_dist(H, src) <= 1) //people with TK won't get smeared with blood
- H.bloody_body(src)
- H.bloody_hands(src)
+ H.add_mob_blood(src)
if(!stat)
switch(hit_area)
@@ -260,15 +260,16 @@ emp_act
if(bloody)//Apply blood
if(wear_mask)
- wear_mask.add_blood(src)
+ wear_mask.add_mob_blood(src)
update_inv_wear_mask(0)
if(head)
- head.add_blood(src)
+ head.add_mob_blood(src)
update_inv_head(0,0)
if(glasses && prob(33))
- glasses.add_blood(src)
+ glasses.add_mob_blood(src)
update_inv_glasses(0)
+
if("upper body")//Easier to score a stun but lasts less time
if(stat == CONSCIOUS && I.force && prob(I.force + 10))
visible_message("[src] has been knocked down!", \
@@ -276,7 +277,13 @@ emp_act
apply_effect(5, WEAKEN, armor)
if(bloody)
- bloody_body(src)
+ if(wear_suit)
+ wear_suit.add_mob_blood(src)
+ update_inv_wear_suit(1)
+ if(w_uniform)
+ w_uniform.add_mob_blood(src)
+ update_inv_w_uniform(1)
+
if(Iforce > 10 || Iforce >= 5 && prob(33))
@@ -313,22 +320,20 @@ emp_act
/mob/living/carbon/human/proc/bloody_hands(var/mob/living/source, var/amount = 2)
if(gloves)
- gloves.add_blood(source)
+ gloves.add_mob_blood(source)
gloves:transfer_blood = amount
- gloves:bloody_hands_mob = source
else
- add_blood(source)
+ add_mob_blood(source)
bloody_hands = amount
- bloody_hands_mob = source
update_inv_gloves(1) //updates on-mob overlays for bloody hands and/or bloody gloves
/mob/living/carbon/human/proc/bloody_body(var/mob/living/source)
if(wear_suit)
- wear_suit.add_blood(source)
+ wear_suit.add_mob_blood(source)
update_inv_wear_suit(0)
return
if(w_uniform)
- w_uniform.add_blood(source)
+ w_uniform.add_mob_blood(source)
update_inv_w_uniform(1)
/mob/living/carbon/human/proc/handle_suit_punctures(var/damtype, var/damage)
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index 15f9b6d112e..036202e1ae0 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -65,6 +65,8 @@ var/global/default_martial_art = new/datum/martial_art
var/meatleft = 3 //For chef item
var/decaylevel = 0 // For rotting bodies
var/max_blood = BLOOD_VOLUME_NORMAL // For stuff in the vessel
+ var/bleed_rate = 0
+ var/bleedsuppress = 0 //for stopping bloodloss
var/check_mutations=0 // Check mutations on next life tick
diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm
index 85dd6e81f3c..164eb14e7cd 100644
--- a/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/code/modules/mob/living/carbon/human/human_movement.dm
@@ -35,12 +35,52 @@
/mob/living/carbon/human/Move(NewLoc, direct)
. = ..()
- if(shoes && .) // did we actually move?
+ if(.) // did we actually move?
if(!lying && !buckled)
+ var/obj/item/clothing/shoes/S = shoes
if(!has_gravity(loc))
return
- var/obj/item/clothing/shoes/S = shoes
- S.step_action(src)
+ //Bloody footprints
+ var/turf/T = get_turf(src)
+ var/obj/item/organ/external/l_foot = get_organ("l_foot")
+ var/obj/item/organ/external/r_foot = get_organ("r_foot")
+ var/hasfeet = 1
+ if((!l_foot || l_foot.status & ORGAN_DESTROYED) && (!r_foot || r_foot.status & ORGAN_DESTROYED))
+ hasfeet = 0
+
+ if(shoes)
+ if(S.bloody_shoes && S.bloody_shoes[S.blood_state])
+ var/obj/effect/decal/cleanable/blood/footprints/oldFP = locate(/obj/effect/decal/cleanable/blood/footprints) in T
+ if(oldFP && oldFP.blood_state == S.blood_state && oldFP.basecolor == S.blood_color)
+ return
+ else
+ //No oldFP or it's a different kind of blood
+ S.bloody_shoes[S.blood_state] = max(0, S.bloody_shoes[S.blood_state] - BLOOD_LOSS_PER_STEP)
+ var/obj/effect/decal/cleanable/blood/footprints/FP = new /obj/effect/decal/cleanable/blood/footprints(T)
+ FP.blood_state = S.blood_state
+ FP.entered_dirs |= dir
+ FP.bloodiness = S.bloody_shoes[S.blood_state]
+ FP.blood_DNA = S.blood_DNA
+ FP.basecolor = S.blood_color
+ FP.update_icon()
+ update_inv_shoes()
+ else if(hasfeet)
+ if(bloody_feet && bloody_feet[blood_state])
+ var/obj/effect/decal/cleanable/blood/footprints/oldFP = locate(/obj/effect/decal/cleanable/blood/footprints) in T
+ if(oldFP && oldFP.blood_state == blood_state && oldFP.basecolor == feet_blood_color)
+ return
+ else
+ bloody_feet[blood_state] = max(0, bloody_feet[blood_state] - BLOOD_LOSS_PER_STEP)
+ var/obj/effect/decal/cleanable/blood/footprints/FP = new /obj/effect/decal/cleanable/blood/footprints(T)
+ FP.blood_state = blood_state
+ FP.entered_dirs |= dir
+ FP.bloodiness = bloody_feet[blood_state]
+ FP.basecolor = feet_blood_color
+ FP.update_icon()
+ update_inv_shoes()
+ //End bloody footprints
+ if(S)
+ S.step_action(src)
/mob/living/carbon/human/handle_footstep(turf/T)
if(..())
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 3ed573eb2cb..2d693dfedcb 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -893,7 +893,6 @@
if(!in_stasis)
handle_organs()
- handle_blood()
else //dead
@@ -1040,8 +1039,7 @@
var/temp = PULSE_NORM
- var/blood_type = get_blood_name()
- if(round(vessel.get_reagent_amount(blood_type)) <= BLOOD_VOLUME_BAD) //how much blood do we have
+ if(blood_volume <= BLOOD_VOLUME_BAD)//how much blood do we have
temp = PULSE_THREADY //not enough :(
if(status_flags & FAKEDEATH)
diff --git a/code/modules/mob/living/carbon/human/species/station.dm b/code/modules/mob/living/carbon/human/species/station.dm
index 60e71f7e8ab..fe3d8a262b3 100644
--- a/code/modules/mob/living/carbon/human/species/station.dm
+++ b/code/modules/mob/living/carbon/human/species/station.dm
@@ -519,6 +519,7 @@
"is cracking their exoskeleton!",
"is stabbing themselves with their mandibles!",
"is holding their breath!")
+
/datum/species/slime
name = "Slime People"
name_plural = "Slime People"
@@ -547,6 +548,7 @@
bodyflags = HAS_SKIN_COLOR | NO_EYES
dietflags = DIET_CARN
reagent_tag = PROCESS_ORG
+ blood_color = "#0064C8"
exotic_blood = "water"
//ventcrawler = 1 //ventcrawling commented out
butt_sprite = "slime"
@@ -575,7 +577,7 @@
#define SLIMEPERSON_BLOOD_SCALING_FACTOR 5 // Used to adjust how much of an effect the blood has on the rate of color change. Higher is slower.
// Slowly shifting to the color of the reagents
if((H in recolor_list) && H.reagents.total_volume > SLIMEPERSON_COLOR_SHIFT_TRIGGER)
- var/blood_amount = H.vessel.total_volume
+ var/blood_amount = H.blood_volume
var/r_color = mix_color_from_reagents(H.reagents.reagent_list)
var/new_body_color = BlendRGB(r_color, rgb(H.r_skin, H.g_skin, H.b_skin), (blood_amount*SLIMEPERSON_BLOOD_SCALING_FACTOR)/((blood_amount*SLIMEPERSON_BLOOD_SCALING_FACTOR)+(H.reagents.total_volume)))
var/list/new_color_list = ReadRGB(new_body_color)
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index b448732fe8c..2a9aca19206 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -9,6 +9,7 @@
if(..())
. = 1
+ handle_blood()
for(var/obj/item/organ/internal/O in internal_organs)
O.on_life()
handle_changeling()
@@ -196,6 +197,8 @@
return
//remember to remove the "proc" of the child procs of these.
+/mob/living/carbon/proc/handle_blood()
+ return
/mob/living/carbon/proc/handle_changeling()
return
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 7215c05a8e2..c2600c4feac 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -524,6 +524,7 @@
stat = CONSCIOUS
update_fire()
regenerate_icons()
+ restore_blood()
if(human_mob)
human_mob.update_eyes()
human_mob.update_dna()
@@ -577,10 +578,10 @@
var/pull_dir = get_dir(src, pulling)
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() * 200 / M.maxHealth)))
- //M.makeTrail(T)
+ if(isliving(pulling))
+ var/mob/living/M = pulling
+ 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()
@@ -601,6 +602,55 @@
return 1
return 0
+/mob/living/proc/makeTrail(turf/T)
+ if(!has_gravity(src))
+ return
+ var/blood_exists = 0
+
+ for(var/obj/effect/decal/cleanable/trail_holder/C in loc) //checks for blood splatter already on the floor
+ blood_exists = 1
+ if(isturf(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, loc)
+ if(newdir != src.dir)
+ newdir = newdir | 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, loc), 180)
+ if(!blood_exists)
+ new /obj/effect/decal/cleanable/trail_holder(loc)
+ for(var/obj/effect/decal/cleanable/trail_holder/TH in 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)
+ if(ishuman(src))
+ var/mob/living/carbon/human/H = src
+ if(H.species.blood_color)
+ TH.color = H.species.blood_color
+ else
+ TH.color = "#A10808"
+
+/mob/living/carbon/human/makeTrail(turf/T)
+
+ if((species.flags & NO_BLOOD) || species.exotic_blood || !bleed_rate || bleedsuppress)
+ return
+ ..()
+
+/mob/living/proc/getTrail()
+ if(getBruteLoss() < 300)
+ return pick("ltrails_1", "ltrails_2")
+ else
+ return pick("trails_1", "trails_2")
+
+
/*//////////////////////
START RESIST PROCS
*///////////////////////
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index 397ce90af6c..67c8ca04172 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -59,3 +59,5 @@
var/tesla_ignore = FALSE
var/list/say_log = list() //a log of what we've said, plain text, no spans or junk, essentially just each individual "message"
+
+ var/blood_volume = 0 //how much blood the mob has
diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm
index 9f8725067b0..a38e97b170b 100644
--- a/code/modules/mob/living/simple_animal/bot/mulebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm
@@ -568,23 +568,6 @@
mode = BOT_NO_ROUTE
-/mob/living/simple_animal/bot/mulebot/Move(turf/simulated/next)
- var/turf/simulated/last = loc
-
- if(istype(last) && bloodiness)
- last.AddTracks(/obj/effect/decal/cleanable/blood/tracks/wheels, currentDNA, 0, get_dir(last, next), currentBloodColor)
-
- . = ..()
-
- if(. && istype(next))
- if(bloodiness)
- next.AddTracks(/obj/effect/decal/cleanable/blood/tracks/wheels, currentDNA, get_dir(last, next), 0, currentBloodColor)
- bloodiness--
-
- for(var/mob/living/carbon/human/H in next)
- if(H != load)
- RunOver(H)
-
// calculates a path to the current destination
// given an optional turf to avoid
/mob/living/simple_animal/bot/mulebot/calc_path(turf/avoid = null)
@@ -668,6 +651,30 @@
return
+/mob/living/simple_animal/bot/mulebot/Move(turf/simulated/next)
+ . = ..()
+
+ if(. && istype(next))
+ if(bloodiness)
+ var/obj/effect/decal/cleanable/blood/tracks/B = locate() in next
+ if(!B)
+ B = new /obj/effect/decal/cleanable/blood/tracks(loc)
+ if(blood_DNA && blood_DNA.len)
+ B.blood_DNA |= blood_DNA.Copy()
+ B.basecolor = currentBloodColor
+ var/newdir = get_dir(next, loc)
+ if(newdir == dir)
+ B.setDir(newdir)
+ else
+ newdir = newdir | dir
+ if(newdir == 3)
+ newdir = 1
+ else if(newdir == 12)
+ newdir = 4
+ B.setDir(newdir)
+ B.update_icon()
+ bloodiness--
+
// called when bot bumps into anything
/mob/living/simple_animal/bot/mulebot/Bump(atom/obs)
if(!wires.MobAvoid()) // usually just bumps, but if avoidance disabled knock over mobs
@@ -697,21 +704,18 @@
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.blood_DNA = list()
- B.blood_DNA[H.dna.unique_enzymes] = H.dna.b_type
- currentDNA = B.blood_DNA
+
+ var/turf/T = get_turf(src)
+ H.add_mob_blood(H)
+ H.add_splatter_floor(T)
bloodiness += 4
- currentBloodColor = "#A10808"
- if(istype(H))
- var/datum/reagent/blood/bld = H.get_blood(H.vessel)
- if(bld.data["blood_colour"])
- currentBloodColor = bld.data["blood_colour"]
- return
- B.basecolor = currentBloodColor
- B.update_icon()
+ var/list/blood_dna = H.get_blood_dna_list()
+ if(blood_dna)
+ transfer_blood_dna(blood_dna)
+ currentBloodColor = H.species.blood_color
+ return
/mob/living/simple_animal/bot/mulebot/bot_control_message(command, mob/user, user_turf)
switch(command)
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 4f3d4588378..b7bd4fc46c1 100644
--- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
+++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
@@ -27,6 +27,7 @@
stop_automated_movement_when_pulled = 1
var/milk_content = 0
can_collar = 1
+ blood_volume = BLOOD_VOLUME_NORMAL
/mob/living/simple_animal/hostile/retaliate/goat/handle_automated_movement()
..()
@@ -110,6 +111,7 @@
var/milk_content = 0
can_collar = 1
gold_core_spawnable = CHEM_MOB_SPAWN_FRIENDLY
+ blood_volume = BLOOD_VOLUME_NORMAL
/mob/living/simple_animal/cow/New()
..()
@@ -312,6 +314,7 @@ var/global/chicken_count = 0
maxHealth = 50
can_collar = 1
gold_core_spawnable = CHEM_MOB_SPAWN_FRIENDLY
+ blood_volume = BLOOD_VOLUME_NORMAL
/mob/living/simple_animal/turkey
name = "turkey"
@@ -381,6 +384,7 @@ var/global/chicken_count = 0
maxHealth = 50
can_collar = 1
gold_core_spawnable = CHEM_MOB_SPAWN_FRIENDLY
+ blood_volume = BLOOD_VOLUME_NORMAL
/mob/living/simple_animal/walrus
name = "walrus"
@@ -404,3 +408,4 @@ var/global/chicken_count = 0
maxHealth = 50
can_collar = 1
gold_core_spawnable = CHEM_MOB_SPAWN_FRIENDLY
+ blood_volume = BLOOD_VOLUME_NORMAL
diff --git a/code/modules/mob/living/simple_animal/friendly/pet.dm b/code/modules/mob/living/simple_animal/friendly/pet.dm
index 2d7bc63dc75..7202c8a4054 100644
--- a/code/modules/mob/living/simple_animal/friendly/pet.dm
+++ b/code/modules/mob/living/simple_animal/friendly/pet.dm
@@ -2,6 +2,7 @@
icon = 'icons/mob/pets.dmi'
can_collar = 1
mob_size = MOB_SIZE_SMALL
+ blood_volume = BLOOD_VOLUME_NORMAL
/mob/living/simple_animal/pet/attackby(var/obj/item/O as obj, var/mob/user as mob, params)
if(istype(O, /obj/item/weapon/newspaper))
diff --git a/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm
index 517b71a3a6d..a0f0a2b8b22 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm
@@ -203,9 +203,9 @@
reagents.reaction(C, INGEST, fraction)
reagents.trans_to(C, volume)
-/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/proc/link_host(mob/living/carbon/human/H)
- faction = list("\ref[src]", "\ref[H]") // Hostile to everyone except the host.
- H.vessel.trans_to(src, 30)
+/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.
+ C.transfer_blood_to(src, 30)
color = mix_color_from_reagents(reagents.reagent_list)
// Legion
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 72c416e8f23..fc331fb74b9 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -422,6 +422,13 @@
damage = O.force
if(O.damtype == STAMINA)
damage = 0
+ if(O.damtype == BRUTE)
+ if(prob(33))
+ O.add_mob_blood(src)
+ var/turf/location = get_turf(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)
visible_message("[user] has [O.attack_verb.len ? "[pick(O.attack_verb)]": "attacked"] [src] with [O]!",\
"[user] has [O.attack_verb.len ? "[pick(O.attack_verb)]": "attacked"] you with [O]!")
else
@@ -432,7 +439,6 @@
"This weapon is ineffective, it does no damage.")
adjustBruteLoss(damage)
-
/mob/living/simple_animal/movement_delay()
. = ..()
diff --git a/code/modules/projectiles/guns/alien.dm b/code/modules/projectiles/guns/alien.dm
index 18101968d6f..bf0cd79f322 100644
--- a/code/modules/projectiles/guns/alien.dm
+++ b/code/modules/projectiles/guns/alien.dm
@@ -66,7 +66,7 @@
/obj/item/projectile/bullet/spike/on_hit(atom/target, blocked = 0)
if((blocked != 100) && istype(target, /mob/living/carbon/human))
var/mob/living/carbon/human/H = target
- H.drip(500)
+ H.bleed(50)
..()
//This gun only functions for armalis. The on-sprite is too huge to render properly on other sprites.
diff --git a/code/modules/projectiles/guns/projectile/saw.dm b/code/modules/projectiles/guns/projectile/saw.dm
index 8b35ac805b4..3714a7983da 100644
--- a/code/modules/projectiles/guns/projectile/saw.dm
+++ b/code/modules/projectiles/guns/projectile/saw.dm
@@ -67,9 +67,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(350)
+ 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 b0bcc0743e2..cd8a64fbde6 100644
--- a/code/modules/projectiles/guns/projectile/sniper.dm
+++ b/code/modules/projectiles/guns/projectile/sniper.dm
@@ -119,9 +119,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(1000)
+ if((blocked != 100) && iscarbon(target))
+ var/mob/living/carbon/C = target
+ C.bleed(100)
return ..()
diff --git a/code/modules/reagents/chemistry/colors.dm b/code/modules/reagents/chemistry/colors.dm
index 3d4ab41fe9c..0eea945349c 100644
--- a/code/modules/reagents/chemistry/colors.dm
+++ b/code/modules/reagents/chemistry/colors.dm
@@ -14,8 +14,8 @@ var/list/random_color_list = list("#00aedb","#a200ff","#f47835","#d41243","#d111
var/vol_temp
// see libs/IconProcs/IconProcs.dm
for(var/datum/reagent/reagent in reagent_list)
- if(reagent.id == "blood" && reagent.data && reagent.data["blood_colour"])
- reagent_color = reagent.data["blood_colour"]
+ if(reagent.id == "blood" && reagent.data && reagent.data["blood_color"])
+ reagent_color = reagent.data["blood_color"]
else
reagent_color = reagent.color
diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm
index 662843e337a..9ad885cd9b7 100644
--- a/code/modules/reagents/chemistry/holder.dm
+++ b/code/modules/reagents/chemistry/holder.dm
@@ -135,10 +135,6 @@ var/const/INGEST = 2
for(var/datum/reagent/current_reagent in reagent_list)
if(!current_reagent)
continue
- if(current_reagent.id == "blood" && ishuman(target))
- var/mob/living/carbon/human/H = target
- H.inject_blood(my_atom, amount)
- continue
var/current_reagent_transfer = current_reagent.volume * part
if(preserve_data)
trans_data = copy_data(current_reagent)
diff --git a/code/modules/reagents/chemistry/reagents/food.dm b/code/modules/reagents/chemistry/reagents/food.dm
index a18f1c01c42..4fd973878dd 100644
--- a/code/modules/reagents/chemistry/reagents/food.dm
+++ b/code/modules/reagents/chemistry/reagents/food.dm
@@ -31,11 +31,9 @@
if(H.can_eat(diet_flags)) //Make sure the species has it's dietflag set, otherwise it can't digest any nutrients
if(prob(50))
M.adjustBruteLoss(-1)
- if(H.species.exotic_blood)
- H.vessel.add_reagent(H.species.exotic_blood, 0.4)
- else
- if(!(H.species.flags & NO_BLOOD))
- H.vessel.add_reagent("blood", 0.4)
+ if(!(H.species.flags & NO_BLOOD))//do not restore blood on things with no blood by nature.
+ if(H.blood_volume < BLOOD_VOLUME_NORMAL)
+ H.blood_volume += 0.4
..()
/datum/reagent/consumable/nutriment/protein // Meat-based protein, digestable by carnivores and omnivores, worthless to herbivores
@@ -65,11 +63,9 @@
M.satiety += 30
if(ishuman(M))
var/mob/living/carbon/human/H = M
- if(H.species.exotic_blood)
- H.vessel.add_reagent(H.species.exotic_blood, 0.5)
- else
- if(!(H.species.flags & NO_BLOOD))
- H.vessel.add_reagent("blood", 0.5)
+ if(!(H.species.flags & NO_BLOOD))//do not restore blood on things with no blood by nature.
+ if(H.blood_volume < BLOOD_VOLUME_NORMAL)
+ H.blood_volume += 0.5
..()
/datum/reagent/consumable/sugar
diff --git a/code/modules/reagents/chemistry/reagents/medicine.dm b/code/modules/reagents/chemistry/reagents/medicine.dm
index 452f9f6d2ff..4b35b5fbeca 100644
--- a/code/modules/reagents/chemistry/reagents/medicine.dm
+++ b/code/modules/reagents/chemistry/reagents/medicine.dm
@@ -210,10 +210,11 @@
if(prob(33))
M.adjustBruteLoss(-2*REAGENTS_EFFECT_MULTIPLIER)
M.adjustFireLoss(-2*REAGENTS_EFFECT_MULTIPLIER)
- if(ishuman(M))
+ if(ishuman(M) && prob(33))
var/mob/living/carbon/human/H = M
- if(!H.species.exotic_blood && !(H.species.flags & NO_BLOOD) && prob(33))
- H.vessel.add_reagent("blood", 1)
+ if(!(H.species.flags & NO_BLOOD))//do not restore blood on things with no blood by nature.
+ if(H.blood_volume < BLOOD_VOLUME_NORMAL)
+ H.blood_volume += 1
..()
/datum/reagent/medicine/synthflesh
diff --git a/code/modules/reagents/chemistry/reagents/misc.dm b/code/modules/reagents/chemistry/reagents/misc.dm
index 9670c80afef..815c9b91123 100644
--- a/code/modules/reagents/chemistry/reagents/misc.dm
+++ b/code/modules/reagents/chemistry/reagents/misc.dm
@@ -148,7 +148,7 @@
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(!H.species.exotic_blood && !(H.species.flags & NO_BLOOD))
- H.vessel.add_reagent("blood", 0.8)
+ H.blood_volume += 0.8
..()
//foam
diff --git a/code/modules/reagents/chemistry/reagents/water.dm b/code/modules/reagents/chemistry/reagents/water.dm
index 773d03c6006..ae40dcb5a8f 100644
--- a/code/modules/reagents/chemistry/reagents/water.dm
+++ b/code/modules/reagents/chemistry/reagents/water.dm
@@ -206,6 +206,14 @@
else //ingest, patch or inject
M.ForceContractDisease(D)
+ if(method == INGEST && 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.b_type))) && !M.mind.vampire)
+ C.reagents.add_reagent("toxin", volume * 0.5)
+ else
+ C.blood_volume = min(C.blood_volume + round(volume, 0.1), BLOOD_VOLUME_MAXIMUM)
+
/datum/reagent/blood/on_new(list/data)
if(istype(data))
SetViruses(src, data)
@@ -234,13 +242,13 @@
preserve += D
data["viruses"] = preserve
- if(mix_data["blood_colour"])
- color = mix_data["blood_colour"]
+ if(mix_data["blood_color"])
+ color = mix_data["blood_color"]
return 1
/datum/reagent/blood/on_update(atom/A)
- if(data["blood_colour"])
- color = data["blood_colour"]
+ if(data["blood_color"])
+ color = data["blood_color"]
return ..()
/datum/reagent/blood/reaction_turf(turf/simulated/T, volume)//splash the blood all over the place
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index 009828543ce..c379e869768 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -32,7 +32,7 @@
create_reagents(volume)
if(spawned_disease)
var/datum/disease/F = new spawned_disease(0)
- var/list/data = list("viruses" = list(F), "blood_colour" = "#A10808")
+ var/list/data = list("viruses" = list(F), "blood_color" = "#A10808")
reagents.add_reagent("blood", disease_amount, data)
if(list_reagents)
reagents.add_reagent_list(list_reagents)
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index ebb13f0830c..e4205ef54d0 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -16,6 +16,7 @@
volume = 15
w_class = WEIGHT_CLASS_TINY
sharp = 1
+ var/busy = 0
var/mode = SYRINGE_DRAW
var/projectile_type = /obj/item/projectile/bullet/dart/syringe
@@ -58,13 +59,16 @@
..()
return
-/obj/item/weapon/reagent_containers/syringe/afterattack(obj/target, mob/user, proximity)
- if(!proximity) return
- if(!target.reagents) return
+/obj/item/weapon/reagent_containers/syringe/afterattack(atom/target, mob/user , proximity)
+ 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
if(mode == SYRINGE_BROKEN)
@@ -75,163 +79,84 @@
if(SYRINGE_DRAW)
if(reagents.total_volume >= reagents.maximum_volume)
- to_chat(user, "The syringe is full.")
+ to_chat(user, "The syringe is full.")
return
- if(ismob(target))//Blood!
- if(istype(target, /mob/living/carbon/slime))
- to_chat(user, "You are unable to locate any blood.")
- return
- if(reagents.has_reagent("blood"))
- to_chat(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/mob/living/carbon/T = target
- if(!T.dna)
- to_chat(usr, "You are unable to locate any blood. (To be specific, your target seems to be missing their DNA datum)")
+ 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(NOCLONE in T.mutations) //target done been et, no more blood in him
- to_chat(user, "You are unable to locate any blood.")
+ if(reagents.total_volume >= reagents.maximum_volume)
return
-
-
- var/time = 30
- if(istype(target,/mob/living/carbon/human))
- var/mob/living/carbon/human/H = T
- if(H.species.flags & NO_BLOOD)
- to_chat(usr, "You are unable to locate any blood.")
- return
- if(target == user)
- time = 0
- else
- for(var/mob/O in viewers(world.view, user))
- O.show_message(text("[] is trying to take a blood sample from []!", user, target), 1)
- if(!do_mob(user, target, time))
- return
-
- var/amount = reagents.maximum_volume - reagents.total_volume
- if(amount == 0)
- to_chat(usr, "The syringe is full!")
- return
-
- var/datum/reagent/B
- if(istype(T,/mob/living/carbon/human))
- var/mob/living/carbon/human/H = T
- if(H.species && H.species.exotic_blood && H.vessel.total_volume)
- H.vessel.trans_to(src,amount)
- else
- B = T.take_blood(src,amount)
- else
- B = T.take_blood(src,amount)
-
- if(B)
- reagents.reagent_list |= B
- reagents.update_total()
- on_reagent_change()
- reagents.handle_reactions()
-
- to_chat(user, "You take a blood sample from [target]")
- for(var/mob/O in viewers(4, user))
- O.show_message("[user] takes a blood sample from [target].", 1)
- else
- user.visible_message("[user] takes a sample from [target].", "You take a sample from [target].")
+ busy = 0
+ if(L.transfer_blood_to(src, drawn_amount))
+ user.visible_message("[user] takes a blood sample from [L].")
+ else
+ to_chat(user, "You are unable to draw any blood from [L]!")
else //if not mob
if(!target.reagents.total_volume)
- to_chat(user, "[target] is empty.")
+ to_chat(user, "[target] is empty!")
return
if(!target.is_open_container() && !istype(target,/obj/structure/reagent_dispensers) && !istype(target,/obj/item/slime_extract))
- to_chat(user, "You cannot directly remove reagents from this object.")
+ to_chat(user, "You cannot directly remove reagents from [target]!")
return
var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this) // transfer from, transfer to - who cares?
- to_chat(user, "You fill the syringe with [trans] units of the solution.")
+ to_chat(user, "You fill [src] with [trans] units of the solution.")
if(reagents.total_volume >= reagents.maximum_volume)
mode=!mode
update_icon()
if(SYRINGE_INJECT)
if(!reagents.total_volume)
- to_chat(user, "The Syringe is empty.")
- return
- if(istype(target, /obj/item/weapon/implantcase/chem))
+ to_chat(user, "[src] is empty.")
return
if(!target.is_open_container() && !ismob(target) && !istype(target, /obj/item/weapon/reagent_containers/food) && !istype(target, /obj/item/slime_extract) && !istype(target, /obj/item/clothing/mask/cigarette) && !istype(target, /obj/item/weapon/storage/fancy/cigarettes))
- to_chat(user, "You cannot directly fill this object.")
+ to_chat(user, "You cannot directly fill [target]!")
return
- if(istype(target, /obj/item/clothing/mask/cigarette))
- var/obj/item/clothing/mask/cigarette/C = target
- if(istype(C.loc, /obj/item/weapon/storage/fancy/cigarettes))
- to_chat(user, "You cannot inject a cigarette while it's still in the pack.")
- return
if(target.reagents.total_volume >= target.reagents.maximum_volume)
- to_chat(user, "[target] is full.")
+ to_chat(user, "[target] is full.")
return
- var/mob/living/carbon/human/H = target
- if(istype(H))
- var/obj/item/organ/external/affected = H.get_organ(user.zone_sel.selecting)
- if(!affected)
- to_chat(user, "\The [H] is missing that limb!")
- return
- /* else if(affected.status & ORGAN_ROBOT)
- to_chat(user, "You cannot inject a robotic limb.")
- 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!")
- if(ismob(target) && target != user)
- for(var/mob/O in viewers(world.view, user))
- O.show_message(text("[] is trying to inject []!", user, target), 1)
+ var/list/rinject = list()
+ for(var/datum/reagent/R in reagents.reagent_list)
+ rinject += R.name
+ var/contained = english_list(rinject)
- if(!do_mob(user, target, 30)) return
-
- for(var/mob/O in viewers(world.view, user))
- O.show_message(text("[] injects [] with the syringe!", user, target), 1)
-
- if(istype(target,/mob/living))
- var/mob/living/M = target
- var/list/injected = list()
- for(var/datum/reagent/R in reagents.reagent_list)
- injected += R.name
- var/contained = english_list(injected)
- M.create_attack_log("Has been injected with [name] by [key_name(user)]. Reagents: [contained]")
- user.create_attack_log("Used the [name] to inject [key_name(M)]. Reagents: [contained]")
- if(M.ckey)
- msg_admin_attack("[key_name_admin(user)] injected [key_name_admin(M)] with [name]. Reagents: [contained] (INTENT: [uppertext(user.a_intent)])")
- if(!iscarbon(user))
- M.LAssailant = null
- else
- M.LAssailant = user
-
- reagents.reaction(target, INGEST)
- if(ismob(target) && target == user)
- reagents.reaction(target, INGEST)
-
- spawn(5)
- var/datum/reagent/blood/B
- for(var/datum/reagent/blood/d in reagents.reagent_list)
- B = d
- break
- var/trans
- 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
- trans = reagents.trans_to(target, amount_per_transfer_from_this)
- to_chat(user, "You inject [trans] units of the solution. The syringe now contains [reagents.total_volume] units.")
- if(istype(target, /obj/item/weapon/reagent_containers/food/pill/patch))
- var/obj/item/weapon/reagent_containers/food/pill/patch/P = target
- if(P.instant_application)
- to_chat(user, "You break the medical seal on the [P]!")
- P.instant_application = 0
+ log_attack("[user.name] ([user.ckey]) injected [L.name] ([L.ckey]) with [src.name], which had [contained] (INTENT: [uppertext(user.a_intent)])")
- if(reagents.total_volume <= 0 && mode==SYRINGE_INJECT)
- mode = SYRINGE_DRAW
- update_icon()
-
- return
+ var/fraction = min(amount_per_transfer_from_this/reagents.total_volume, 1)
+ reagents.reaction(L, INGEST, fraction)
+ reagents.trans_to(target, amount_per_transfer_from_this)
+ to_chat(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()
if(mode == SYRINGE_BROKEN)
diff --git a/code/modules/recycling/disposal-construction.dm b/code/modules/recycling/disposal-construction.dm
index 73fbb455835..e38ea69f345 100644
--- a/code/modules/recycling/disposal-construction.dm
+++ b/code/modules/recycling/disposal-construction.dm
@@ -98,7 +98,7 @@
/obj/structure/disposalconstruct/AltClick(mob/user)
if(user.incapacitated())
- to_chat(user << "You can't do that right now!")
+ to_chat(user, "You can't do that right now!")
return
if(!Adjacent(user))
return
@@ -195,7 +195,7 @@
playsound(src.loc, I.usesound, 100, 1)
update()
return
-
+
var/obj/structure/disposalpipe/CP = locate() in T
if(ptype>=6 && ptype <= 8) // Disposal or outlet
if(CP) // There's something there
diff --git a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_heal.dm b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_heal.dm
index b1071222b17..f3b82e18ecd 100644
--- a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_heal.dm
+++ b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_heal.dm
@@ -17,14 +17,12 @@
if(affecting && istype(affecting))
affecting.heal_damage(25 * weakness, 25 * weakness)
//H:heal_organ_damage(25, 25)
- H.vessel.add_reagent("blood",5)
+ H.blood_volume += 5
H.nutrition += 50 * weakness
H.adjustBrainLoss(-25 * weakness)
var/radiation = min(H.radiation, 25 * weakness)
H.apply_effect(-radiation,IRRADIATE,0)
H.bodytemperature = initial(H.bodytemperature)
- spawn(1)
- H.fixblood()
//
C.adjustOxyLoss(-25 * weakness)
C.adjustToxLoss(-25 * weakness)
diff --git a/code/modules/research/xenoarchaeology/finds/finds_special.dm b/code/modules/research/xenoarchaeology/finds/finds_special.dm
index 5fd432a7a6f..cf0c1cfa273 100644
--- a/code/modules/research/xenoarchaeology/finds/finds_special.dm
+++ b/code/modules/research/xenoarchaeology/finds/finds_special.dm
@@ -134,7 +134,7 @@
B.target_turf = pick(range(1, src))
B.blood_DNA = list()
B.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type
- M.vessel.remove_reagent("blood",rand(25,50))
+ M.blood_volume -= rand(25,50)
//animated blood 2 SPOOKY
/obj/effect/decal/cleanable/blood/splatter/animated
diff --git a/code/modules/surgery/organs/blood.dm b/code/modules/surgery/organs/blood.dm
index 9eefe264524..16ab98c525e 100644
--- a/code/modules/surgery/organs/blood.dm
+++ b/code/modules/surgery/organs/blood.dm
@@ -1,87 +1,42 @@
/****************************************************
BLOOD SYSTEM
****************************************************/
-
-/mob/living/carbon/human/var/datum/reagents/vessel //Container for blood and BLOOD ONLY. Do not transfer other chems here.
-
-//Initializes blood vessels
-/mob/living/carbon/human/proc/make_blood()
-
- if(vessel)
+/mob/living/carbon/human/proc/suppress_bloodloss(amount)
+ if(bleedsuppress)
return
-
- vessel = new/datum/reagents(max_blood)
- vessel.my_atom = src
-
- if(species && species.exotic_blood)
- vessel.add_reagent(species.exotic_blood, max_blood)
else
- vessel.add_reagent("blood", max_blood)
- for(var/datum/reagent/blood/B in vessel.reagent_list)
- if(B.id == "blood")
- B.data = list(
- "donor" = src,
- "viruses" = null,
- "blood_DNA" = dna.unique_enzymes,
- "blood_colour" = species.blood_color,
- "blood_type" = b_type,
- "resistances" = null,
- "trace_chem" = null)
- spawn(1)
- fixblood()
+ bleedsuppress = 1
+ spawn(amount)
+ bleedsuppress = 0
+ if(stat != DEAD && bleed_rate)
+ to_chat(src, "The blood soaks through your bandage.")
+
-//Resets blood data
-/mob/living/carbon/human/proc/fixblood()
- for(var/datum/reagent/blood/B in vessel.reagent_list)
- if(B.id == "blood")
- B.data = list(
- "donor" = src,
- "viruses" = null,
- "blood_DNA" = dna.unique_enzymes,
- "blood_colour" = species.blood_color,
- "blood_type" = b_type,
- "resistances" = null,
- "trace_chem" = null)
// Takes care blood loss and regeneration
-/mob/living/carbon/human/proc/handle_blood()
- var/blood_volume
- if(species && species.flags & NO_BLOOD)
+/mob/living/carbon/human/handle_blood()
+ var/list/blood_data = get_blood_data(get_blood_id())//PROCCEPTION
+
+ if(in_stasis)
return
- if(stat != DEAD && bodytemperature >= 170) //Dead or cryosleep people do not pump the blood.
- if(species.exotic_blood)
- var/blood_reagent = species.exotic_blood // This is a string of the name of the species' blood reagent
- blood_volume = round(vessel.get_reagent_amount(blood_reagent))
- if(blood_volume < max_blood && blood_volume)
- vessel.add_reagent(blood_reagent, 0.1) // regenerate blood VERY slowly
- if(reagents.has_reagent(blood_reagent))
- vessel.add_reagent(blood_reagent, 0.4)
- else
- blood_volume = round(vessel.get_reagent_amount("blood"))
- //Blood regeneration if there is some space
- if(blood_volume < max_blood && blood_volume)
- var/datum/reagent/blood/B = locate() in vessel.reagent_list //Grab some blood
- if(B) // Make sure there's some blood at all
- if(mind) //Handles vampires "eating" blood that isn't their own.
- if(mind in ticker.mode.vampires)
- for(var/datum/reagent/blood/BL in vessel.reagent_list)
- if(nutrition >= NUTRITION_LEVEL_WELL_FED)
- break //We don't want blood tranfusions making vampires fat.
- if(BL.data["donor"] != src)
- nutrition += (15 * REAGENTS_METABOLISM)
- BL.volume -= REAGENTS_METABOLISM
- if(BL.volume <= 0)
- qdel(BL)
- break //Only process one blood per tick, to maintain the same metabolism as nutriment for non-vampires.
+ if(species && species.flags & NO_BLOOD)
+ bleed_rate = 0
+ return
- if(B.data["donor"] != src) //If it's not theirs, then we look for theirs
- for(var/datum/reagent/blood/D in vessel.reagent_list)
- if(D.data["donor"] == src)
- B = D
- break
+ if(bodytemperature >= 225 && !(NOCLONE in mutations)) //cryosleep or husked people do not pump the blood.
- vessel.add_reagent("blood", 0.1) // regenerate blood VERY slowly
+ //Blood regeneration if there is some space
+ if(blood_volume < max_blood && blood_volume)
+ if(mind) //Handles vampires "eating" blood that isn't their own.
+ if(mind in ticker.mode.vampires)
+ if(nutrition >= NUTRITION_LEVEL_WELL_FED)
+ return //We don't want blood tranfusions making vampires fat.
+ if(blood_data["donor"] != src)
+ nutrition += (15 * REAGENTS_METABOLISM)
+ return //Only process one blood per tick, to maintain the same metabolism as nutriment for non-vampires.
+ if(blood_volume < BLOOD_VOLUME_NORMAL)
+ blood_volume += 0.1 // regenerate blood VERY slowly
//Effects of bloodloss
@@ -102,6 +57,7 @@
adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1))
if(prob(5))
EyeBlurry(6)
+
var/word = pick("dizzy","woozy","faint")
to_chat(src, "You feel very [word].")
if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD)
@@ -117,264 +73,215 @@
death()
//Bleeding out
- var/blood_max = 0
+ var/temp_bleed = 0
for(var/obj/item/organ/external/temp in bodyparts)
if(!(temp.status & ORGAN_BLEEDING) || temp.status & ORGAN_ROBOT)
continue
for(var/datum/wound/W in temp.wounds)
if(W.bleeding())
- blood_max += W.damage / 4
+ temp_bleed += W.damage / 4
if(temp.open)
- blood_max += 2 //Yer stomach is cut open
- drip(blood_max)
+ temp_bleed += 0.5
-//Makes a blood drop, leaking certain amount of blood from the mob
-/mob/living/carbon/human/proc/drip(var/amt as num)
+ bleed_rate = max(bleed_rate - 0.5, temp_bleed)//if no wounds, other bleed effects (heparin) naturally decreases
- if(species && species.flags & NO_BLOOD) //TODO: Make drips come from the reagents instead.
- return
+ if(bleed_rate && !bleedsuppress)
+ bleed(bleed_rate)
- if(!amt)
- return
+//Makes a blood drop, leaking amt units of blood from the mob
+/mob/living/carbon/proc/bleed(amt)
+ if(blood_volume)
+ blood_volume = max(blood_volume - amt, 0)
+ if(isturf(loc)) //Blood loss still happens in locker, floor stays clean
+ if(amt >= 10)
+ add_splatter_floor(loc)
+ else
+ add_splatter_floor(loc, 1)
- var/amm = 0.1 * amt
- var/turf/T = get_turf(src)
+/mob/living/carbon/human/bleed(amt)
+ if(!(species && species.flags & NO_BLOOD))
+ ..()
+ if(species.exotic_blood)
+ var/datum/reagent/R = chemical_reagents_list[get_blood_id()]
+ if(istype(R) && isturf(loc))
+ R.reaction_turf(get_turf(src), amt)
- if(species.exotic_blood)
- vessel.remove_reagent(species.exotic_blood,amm)
- if(vessel.total_volume)
- var/fraction = amm / vessel.total_volume
- vessel.reaction(T, TOUCH, fraction)
- return
-
- else
- vessel.remove_reagent("blood",amm)
- blood_splatter(src, src)
+/mob/living/proc/restore_blood()
+ blood_volume = initial(blood_volume)
+/mob/living/carbon/human/restore_blood()
+ blood_volume = BLOOD_VOLUME_NORMAL
+ bleed_rate = 0
/****************************************************
BLOOD TRANSFERS
****************************************************/
-//Gets blood from mob to the container, preserving all data in it.
-/mob/living/carbon/proc/take_blood(obj/item/weapon/reagent_containers/container, var/amount)
- var/datum/reagent/B = get_blood(container.reagents)
- if(!istype(B, /datum/reagent/blood)) B = new /datum/reagent/blood
- B.holder = container
- B.volume += amount
+//Gets blood from mob to a container or other mob, preserving all data in it.
+/mob/living/proc/transfer_blood_to(atom/movable/AM, amount, forced)
+ if(!blood_volume || !AM.reagents)
+ return 0
+ if(blood_volume < BLOOD_VOLUME_BAD && !forced)
+ return 0
- //set reagent data
- B.data["donor"] = src
- B.data["viruses"] = list()
+ if(blood_volume < amount)
+ amount = blood_volume
- for(var/datum/disease/D in viruses)
- B.data["viruses"] += D.Copy()
- if(resistances && resistances.len)
- B.data["resistances"] = resistances.Copy()
+ var/blood_id = get_blood_id()
+ if(!blood_id)
+ return 0
- B.data["blood_DNA"] = copytext(src.dna.unique_enzymes,1,0)
- B.data["blood_type"] = copytext(src.dna.b_type,1,0)
+ blood_volume -= amount
- // Putting this here due to return shenanigans.
- if(istype(src,/mob/living/carbon/human))
- var/mob/living/carbon/human/H = src
- B.data["blood_colour"] = H.species.blood_color
- B.color = B.data["blood_colour"]
+ var/list/blood_data = get_blood_data(blood_id)
- var/list/temp_chem = list()
- for(var/datum/reagent/R in src.reagents.reagent_list)
- temp_chem += R.id
- temp_chem[R.id] = R.volume
- B.data["trace_chem"] = list2params(temp_chem)
- if(mind)
- B.data["mind"] = mind
- if(ckey)
- B.data["ckey"] = ckey
+ if(iscarbon(AM))
+ var/mob/living/carbon/C = AM
+ if(blood_id == C.get_blood_id())//both mobs have the same blood substance
+ if(blood_id == "blood") //normal blood
+ if(blood_data["viruses"])
+ for(var/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.b_type)))
+ C.reagents.add_reagent("toxin", amount * 0.5)
+ return 1
- if(!suiciding)
- B.data["cloneable"] = 1
- B.data["gender"] = gender
- B.data["real_name"] = real_name
- B.data["factions"] = faction
- return B
+ C.blood_volume = min(C.blood_volume + round(amount, 0.1), BLOOD_VOLUME_MAXIMUM)
+ return 1
-//For humans, blood does not appear from blue, it comes from vessels.
-/mob/living/carbon/human/take_blood(obj/item/weapon/reagent_containers/container, var/amount)
- if(src.species.exotic_blood)
- if(vessel.get_reagent_amount(src.species.exotic_blood) < amount)
- return null
- var/datum/reagent/W = new /datum/reagent
- W.holder = container
- W.volume += amount
+ AM.reagents.add_reagent(blood_id, amount, blood_data, bodytemperature)
+ return 1
+
+
+/mob/living/proc/get_blood_data(blood_id)
+ return
+
+/mob/living/carbon/human/get_blood_data(blood_id)
+ if(blood_id == "blood") //actual blood reagent
+ var/blood_data = list()
+ //set the blood data
+ blood_data["donor"] = src
+ blood_data["viruses"] = list()
+
+ for(var/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 src.reagents.reagent_list)
- temp_chem += R.id
+ for(var/datum/reagent/R in reagents.reagent_list)
temp_chem[R.id] = R.volume
- W.data["trace_chem"] = list2params(temp_chem)
- vessel.remove_reagent(src.species.exotic_blood,amount) // Removes blood if human
- return W
- if(species && species.flags & NO_BLOOD)
- return null
- else
- if(vessel.get_reagent_amount("blood") < amount)
- return null
- . = ..()
- vessel.remove_reagent("blood",amount) // Removes blood if human
+ blood_data["trace_chem"] = list2params(temp_chem)
+ if(mind)
+ blood_data["mind"] = mind
+ if(ckey)
+ blood_data["ckey"] = ckey
+ if(!suiciding)
+ blood_data["cloneable"] = 1
+ blood_data["blood_type"] = copytext(src.dna.b_type,1,0)
+ blood_data["gender"] = gender
+ blood_data["real_name"] = real_name
+ blood_data["blood_color"] = species.blood_color
+ blood_data["factions"] = faction
+ return blood_data
-//Transfers blood from container ot vessels
-/mob/living/carbon/proc/inject_blood(obj/item/weapon/reagent_containers/container, var/amount)
- var/datum/reagent/blood/injected = get_blood(container.reagents)
+//get the id of the substance this mob use as blood.
+/mob/proc/get_blood_id()
+ return
- if(!istype(injected))
+/mob/living/simple_animal/get_blood_id()
+ if(blood_volume)
+ return "blood"
+
+/mob/living/carbon/human/get_blood_id()
+ if(species.exotic_blood)//some races may bleed water..or kethcup..
+ return species.exotic_blood
+ else if((species && species.flags & NO_BLOOD) || (NOCLONE in mutations))
return
-
- var/list/chems = list()
- chems = params2list(injected.data["trace_chem"])
- for(var/C in chems)
- src.reagents.add_reagent(C, (text2num(chems[C]) / BLOOD_VOLUME_NORMAL) * amount)//adds trace chemicals to owner's blood
- reagents.update_total()
-
- container.reagents.remove_reagent("blood", amount)
-
-//Transfers blood from container ot vessels, respecting blood types compatability.
-/mob/living/carbon/human/inject_blood(obj/item/weapon/reagent_containers/container, var/amount)
-
- var/datum/reagent/blood/injected = get_blood(container.reagents)
-
- if(!istype(injected)) //Sanity..
- return
-
- if(species && species.flags & NO_BLOOD)
- reagents.add_reagent("blood", amount, injected.data)
- reagents.update_total()
- return
-
- var/datum/reagent/blood/our = get_blood(vessel)
-
- if(!istype(our)) // Do we not have blood?
- vessel.add_reagent("blood", amount, injected.data) // This is only ran once, so we need to add back their DNA.
- vessel.update_total()
- ..()
- our = get_blood(vessel) // Get the new blood.
- our.data["blood_DNA"] = dna.unique_enzymes // Give it the proper DNA we had before (src.dna)
- our.data["blood_type"] = dna.b_type // Proper blood type.
- our.data["donor"] = src // Without this, it'd be random each time it was extracted or Null.
- return
-
- if(blood_incompatible(injected.data["blood_type"],our.data["blood_type"]) )
- reagents.add_reagent("toxin",amount * 0.5)
- reagents.update_total()
- else
- vessel.add_reagent("blood", amount, injected.data)
- vessel.update_total()
- ..()
-
-//Gets human's own blood.
-/mob/living/carbon/proc/get_blood(datum/reagents/container)
- var/datum/reagent/blood/res = locate() in container.reagent_list //Grab some blood
- if(res) // Make sure there's some blood at all
- if(res.data["donor"] != src) //If it's not theirs, then we look for theirs
- for(var/datum/reagent/blood/D in container.reagent_list)
- if(D.data["donor"] == src)
- return D
- return res
-
-/mob/living/carbon/human/get_blood(datum/reagents/container)
- if(species.exotic_blood)
- return container.get_reagent_from_id(species.exotic_blood)
- else
- return ..()
-
-/mob/living/carbon/proc/get_blood_name()
return "blood"
-/mob/living/carbon/human/get_blood_name()
- if(species.exotic_blood)
- return species.exotic_blood
- else
- return ..()
+// This is has more potential uses, and is probably faster than the old proc.
+/proc/get_safe_blood(bloodtype)
+ . = list()
+ if(!bloodtype)
+ return
+ switch(bloodtype)
+ if("A-")
+ return list("A-", "O-")
+ if("A+")
+ return list("A-", "A+", "O-", "O+")
+ if("B-")
+ return list("B-", "O-")
+ if("B+")
+ return list("B-", "B+", "O-", "O+")
+ if("AB-")
+ return list("A-", "B-", "O-", "AB-")
+ if("AB+")
+ return list("A-", "A+", "B-", "B+", "O-", "O+", "AB-", "AB+")
+ if("O-")
+ return list("O-")
+ if("O+")
+ return list("O-", "O+")
-/proc/blood_incompatible(donor,receiver)
+//to add a splatter of blood or other mob liquid.
+/mob/living/proc/add_splatter_floor(turf/T, small_drip)
+ if(get_blood_id() != "blood")//is it blood or welding fuel?
+ return
- var/donor_antigen = copytext(donor,1,lentext(donor))
- var/receiver_antigen = copytext(receiver,1,lentext(receiver))
- var/donor_rh = findtext("+",donor)
- var/receiver_rh = findtext("+",receiver)
+ if(!T)
+ T = get_turf(src)
- if(donor_rh && !receiver_rh) return 1
- switch(receiver_antigen)
- if("A")
- if(donor_antigen != "A" && donor_antigen != "O") return 1
- if("B")
- if(donor_antigen != "B" && donor_antigen != "O") return 1
- if("O")
- if(donor_antigen != "O") return 1
- //AB is a universal receiver.
- return 0
+ var/list/temp_blood_DNA
+ var/list/b_data = get_blood_data(get_blood_id())
-/*
-Target: Thing/tile to get bloody
-Source: Human or blood reagent
-Large: Whether the splat should be big or not
-*/
-/proc/blood_splatter(var/target,var/source,var/large = 0)
-
- var/obj/effect/decal/cleanable/blood/B
- var/decal_type = /obj/effect/decal/cleanable/blood/splatter
- var/turf/T = get_turf(target)
- var/datum/reagent/blood/bld
- if(istype(source,/mob/living/carbon/human))
- var/mob/living/carbon/human/H = source
- bld = H.get_blood(H.vessel)
- if(H.species.exotic_blood)
- H.vessel.reaction(T, TOUCH)
+ if(small_drip)
+ // Only a certain number of drips (or one large splatter) can be on a given turf.
+ var/obj/effect/decal/cleanable/blood/drip/drop = locate() in T
+ if(drop)
+ if(drop.drips < 3)
+ drop.drips++
+ drop.overlays |= pick(drop.random_icon_states)
+ drop.transfer_mob_blood_dna(src)
+ drop.basecolor = b_data["blood_color"]
+ drop.update_icon()
+ else
+ temp_blood_DNA = list()
+ temp_blood_DNA |= drop.blood_DNA.Copy() //we transfer the dna from the drip to the splatter
+ qdel(drop)
+ else
+ drop = new(T)
+ drop.transfer_mob_blood_dna(src)
+ drop.basecolor = b_data["blood_color"]
+ drop.update_icon()
return
- else if(H.species.flags & NO_BLOOD)
- return
- else if(istype(source, /datum/reagent))
- bld = source
- if(!istype(bld, /datum/reagent/blood))
- var/datum/reagent/R = bld
- if(istype(R))
- R.reaction_turf(T, R.volume)
- return
- else if(source)
- log_runtime(EXCEPTION("Non-human or reagent blood source. Area: [get_area(source)], Name: [source]"), source)
-
- // Are we dripping or splattering?
- var/list/drips = list()
- // Only a certain number of drips (or one large splatter) can be on a given turf.
- for(var/obj/effect/decal/cleanable/blood/drip/drop in T)
- drips |= drop.drips
- qdel(drop)
- if(!large && drips.len < 3)
- decal_type = /obj/effect/decal/cleanable/blood/drip
// Find a blood decal or create a new one.
- B = locate(decal_type) in T
+ var/obj/effect/decal/cleanable/blood/B = locate() in T
if(!B)
- B = new decal_type(T)
+ B = new /obj/effect/decal/cleanable/blood/splatter(T)
+ B.transfer_mob_blood_dna(src) //give blood info to the blood decal.
+ if(temp_blood_DNA)
+ B.blood_DNA |= temp_blood_DNA
+ B.update_icon()
- var/obj/effect/decal/cleanable/blood/drip/drop = B
- if(istype(drop) && drips && drips.len && !large)
- drop.overlays |= drips
- drop.drips |= drips
+/mob/living/carbon/human/add_splatter_floor(turf/T, small_drip)
+ if(!(species && species.flags & NO_BLOOD))
+ ..()
- // If there's no data to copy, call it quits here.
- if(!bld)
- return B
+/mob/living/carbon/alien/add_splatter_floor(turf/T, small_drip)
+ if(!T)
+ T = get_turf(src)
+ var/obj/effect/decal/cleanable/blood/xeno/B = locate() in T.contents
+ if(!B)
+ B = new(T)
+ B.blood_DNA["UNKNOWN DNA"] = "X*"
- // Update appearance.
- if(bld.data["blood_colour"])
- B.basecolor = bld.data["blood_colour"]
- B.update_icon()
-
- // Update blood information.
- if(bld.data["blood_DNA"])
- B.blood_DNA = list()
- if(bld.data["blood_type"])
- B.blood_DNA[bld.data["blood_DNA"]] = bld.data["blood_type"]
- else
- B.blood_DNA[bld.data["blood_DNA"]] = "O+"
-
- return B
+/mob/living/silicon/robot/add_splatter_floor(turf/T, small_drip)
+ if(!T)
+ T = get_turf(src)
+ var/obj/effect/decal/cleanable/blood/oil/B = locate() in T.contents
+ if(!B)
+ B = new(T)
\ No newline at end of file
diff --git a/code/modules/surgery/organs/organ.dm b/code/modules/surgery/organs/organ.dm
index 572a4112f06..414bdc0e844 100644
--- a/code/modules/surgery/organs/organ.dm
+++ b/code/modules/surgery/organs/organ.dm
@@ -32,6 +32,7 @@ var/list/organ_cache = list()
var/sterile = 0 //can the organ be infected by germs?
var/tough = 0 //can organ be easily damaged?
+
/obj/item/organ/Destroy()
processing_objects.Remove(src)
if(owner)
@@ -316,9 +317,9 @@ var/list/organ_cache = list()
loc = get_turf(owner)
processing_objects |= src
var/datum/reagent/blood/organ_blood
- if(reagents) organ_blood = reagents.get_reagent_from_id(owner.get_blood_name())
+ if(reagents) organ_blood = reagents.get_reagent_from_id(owner.get_blood_id())
if((!organ_blood || !organ_blood.data["blood_DNA"]) && (owner && !(owner.species.flags & NO_BLOOD)))
- owner.vessel.trans_to(src, 5, 1, 1)
+ owner.transfer_blood_to(src)
if(owner && vital && is_primary_organ()) // I'd do another check for species or whatever so that you couldn't "kill" an IPC by removing a human head from them, but it doesn't matter since they'll come right back from the dead
if(user)
diff --git a/code/modules/surgery/organs/organ_external.dm b/code/modules/surgery/organs/organ_external.dm
index b43b7ad1c64..7ad38b5060d 100644
--- a/code/modules/surgery/organs/organ_external.dm
+++ b/code/modules/surgery/organs/organ_external.dm
@@ -577,9 +577,9 @@ Note that amputating the affected organ does in fact remove the infection from t
var/bicardose = owner.reagents.get_reagent_amount("styptic_powder")
if(!bicardose) //styptic powder stops internal wounds from growing bigger with time, and also stop bleeding
W.open_wound(0.1 * wound_update_accuracy)
- owner.vessel.remove_reagent("blood",0.05 * W.damage * wound_update_accuracy)
+ owner.blood_volume -= (0.05 * W.damage * wound_update_accuracy)
- owner.vessel.remove_reagent("blood",0.02 * W.damage * wound_update_accuracy)
+ owner.blood_volume -= (0.02 * W.damage * wound_update_accuracy)
if(prob(1 * wound_update_accuracy))
owner.custom_pain("You feel a stabbing pain in your [name]!",1)
@@ -744,7 +744,7 @@ Note that amputating the affected organ does in fact remove the infection from t
switch(disintegrate)
if(DROPLIMB_SHARP)
compile_icon()
- add_blood(victim)
+ add_blood(victim.blood_DNA, victim.species.blood_color)
var/matrix/M = matrix()
M.Turn(rand(180))
src.transform = M
diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm
index 602a6e295d5..e07208cc97d 100644
--- a/code/modules/surgery/organs/organ_internal.dm
+++ b/code/modules/surgery/organs/organ_internal.dm
@@ -224,10 +224,11 @@
if(world.time > (last_pump + pump_delay))
if(ishuman(owner) && owner.client) //While this entire item exists to make people suffer, they can't control disconnects.
var/mob/living/carbon/human/H = owner
- H.vessel.remove_reagent("blood", blood_loss)
- to_chat(H, "You have to keep pumping your blood!")
- if(H.client)
- H.client.color = "red" //bloody screen so real
+ if(!(H.species.flags & NO_BLOOD))
+ H.blood_volume = max(H.blood_volume - blood_loss, 0)
+ to_chat(H, "You have to keep pumping your blood!")
+ if(H.client)
+ H.client.color = "red" //bloody screen so real
else
last_pump = world.time //lets be extra fair *sigh*
@@ -256,13 +257,14 @@
var/mob/living/carbon/human/H = owner
if(istype(H))
- H.vessel.add_reagent("blood", (cursed_heart.blood_loss*0.5))//gain half the blood back from a failure
- if(owner.client)
- owner.client.color = ""
+ if(!(H.species.flags & NO_BLOOD))
+ H.blood_volume = min(H.blood_volume + cursed_heart.blood_loss*0.5, BLOOD_VOLUME_MAXIMUM)
+ if(owner.client)
+ owner.client.color = ""
- H.adjustBruteLoss(-cursed_heart.heal_brute)
- H.adjustFireLoss(-cursed_heart.heal_burn)
- H.adjustOxyLoss(-cursed_heart.heal_oxy)
+ H.adjustBruteLoss(-cursed_heart.heal_brute)
+ H.adjustFireLoss(-cursed_heart.heal_burn)
+ H.adjustOxyLoss(-cursed_heart.heal_oxy)
/obj/item/organ/internal/lungs
name = "lungs"
@@ -289,7 +291,7 @@
if(is_bruised())
if(prob(2))
owner.custom_emote(1, "coughs up blood!")
- owner.drip(10)
+ owner.bleed(1)
if(prob(4))
owner.custom_emote(1, "gasps for air!")
owner.AdjustLoseBreath(5)
diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm
index d3f3c2c933b..4bb0f2846c7 100644
--- a/code/modules/surgery/organs/vocal_cords.dm
+++ b/code/modules/surgery/organs/vocal_cords.dm
@@ -244,7 +244,7 @@ var/static/regex/multispin_words = regex("like a record baby")
//BLEED
else if((findtext(message, bleed_words)))
for(var/mob/living/carbon/human/H in listeners)
- H.drip(100 * power_multiplier)
+ H.bleed_rate += (5 * power_multiplier)
next_command = world.time + cooldown_damage
//FIRE
diff --git a/icons/effects/blood.dmi b/icons/effects/blood.dmi
index 28e2fd791ff..855c443a203 100644
Binary files a/icons/effects/blood.dmi and b/icons/effects/blood.dmi differ
diff --git a/icons/effects/fluidtracks.dmi b/icons/effects/fluidtracks.dmi
index 810ecc7f265..d4152ea83bc 100644
Binary files a/icons/effects/fluidtracks.dmi and b/icons/effects/fluidtracks.dmi differ