diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm
index 0ccc674cfc..07b53848cf 100644
--- a/code/__DEFINES/citadel_defines.dm
+++ b/code/__DEFINES/citadel_defines.dm
@@ -104,13 +104,6 @@
#define isgenital(A) (istype(A, /obj/item/organ/genital))
#define isborer(A) (istype(A, /mob/living/simple_animal/borer))
-#define isipcperson(A) (is_species(A, /datum/species/ipc))
-#define ismammal(A) (is_species(A, /datum/species/mammal))
-#define isavian(A) (is_species(A, /datum/species/avian))
-#define isaquatic(A) (is_species(A, /datum/species/aquatic))
-#define isinsect(A) (is_species(A, /datum/species/insect))
-#define isxenoperson(A) (is_species(A, /datum/species/xeno))
-#define isstartjelly(A) (is_species(A, /datum/species/jelly/roundstartslime))
#define CITADEL_MENTOR_OOC_COLOUR "#224724"
diff --git a/code/__DEFINES/cleaning.dm b/code/__DEFINES/cleaning.dm
index 6049fd7918..c4db590e90 100644
--- a/code/__DEFINES/cleaning.dm
+++ b/code/__DEFINES/cleaning.dm
@@ -5,3 +5,8 @@
#define CLEAN_STRONG 4 // Industrial strength
#define CLEAN_IMPRESSIVE 5 // Cleaning strong enough your granny would be proud
#define CLEAN_GOD 6 // Cleans things spotless down to the atomic structure
+
+//How strong things have to be to wipe forensic evidence...
+#define CLEAN_STRENGTH_FINGERPRINTS CLEAN_IMPRESSIVE
+#define CLEAN_STRENGTH_BLOOD CLEAN_WEAK
+#define CLEAN_STRENGTH_FIBERS CLEAN_IMPRESSIVE
diff --git a/code/__DEFINES/forensics.dm b/code/__DEFINES/forensics.dm
new file mode 100644
index 0000000000..0cda5d997a
--- /dev/null
+++ b/code/__DEFINES/forensics.dm
@@ -0,0 +1,2 @@
+#define IF_HAS_BLOOD_DNA(__thing) GET_COMPONENT_FROM(__FR##__thing, /datum/component/forensics, __thing); if(__FR##__thing && length(__FR##__thing.blood_DNA))
+#define IF_HAS_BLOOD_DNA_AND(__thing, __conditions...) GET_COMPONENT_FROM(__FR##__thing, /datum/component/forensics, __thing); if(__FR##__thing && length(__FR##__thing.blood_DNA) && (##__conditions))
\ No newline at end of file
diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index 8ff40c3ef9..ba6ffe12bd 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -60,6 +60,15 @@
#define ishumanbasic(A) (is_species(A, /datum/species/human))
#define iscatperson(A) (ishumanbasic(A) && istype(A.dna.species, /datum/species/human/felinid) )
+// Citadel specific species
+#define isipcperson(A) (is_species(A, /datum/species/ipc))
+#define ismammal(A) (is_species(A, /datum/species/mammal))
+#define isavian(A) (is_species(A, /datum/species/avian))
+#define isaquatic(A) (is_species(A, /datum/species/aquatic))
+#define isinsect(A) (is_species(A, /datum/species/insect))
+#define isxenoperson(A) (is_species(A, /datum/species/xeno))
+#define isstartjelly(A) (is_species(A, /datum/species/jelly/roundstartslime))
+
//more carbon mobs
#define ismonkey(A) (istype(A, /mob/living/carbon/monkey))
@@ -175,6 +184,8 @@ GLOBAL_LIST_INIT(heavyfootmob, typecacheof(list(
#define iscameramob(A) (istype(A, /mob/camera))
+#define isaicamera(A) (istype(A, /mob/camera/aiEye))
+
#define iseminence(A) (istype(A, /mob/camera/eminence))
//Footstep helpers
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 1a38e368c2..6b924ef207 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -183,6 +183,9 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache)
#define BLOOD_COLOR_SYNTHETIC "#3f48aa"
#define BLOOD_COLOR_SLIME "#00ff90"
#define BLOOD_COLOR_LIZARD "#db004D"
+#define BLOOD_COLOR_UNIVERSAL "#db3300"
+#define BLOOD_COLOR_BUG "#a37c0f"
+
//suit sensors: sensor_mode defines
diff --git a/code/__HELPERS/_cit_helpers.dm b/code/__HELPERS/_cit_helpers.dm
index 77b79cf532..8683f75b08 100644
--- a/code/__HELPERS/_cit_helpers.dm
+++ b/code/__HELPERS/_cit_helpers.dm
@@ -94,72 +94,6 @@ GLOBAL_LIST_INIT(dildo_colors, list(//mostly neon colors
"Purple" = "#e300ff"//purple
))
-GLOBAL_LIST_INIT(noodle_taurs, list(
- "Naga",
- "Tentacle"
- ))
-
-GLOBAL_LIST_INIT(paw_taurs, list(
- "Fox",
- "Wolf",
- "Otie",
- "Drake",
- "Lab",
- "Shepherd",
- "Husky",
- "Eevee",
- "Panther",
- "Horse",
- "Cow",
- "Tiger"
- ))
-
- //blood types
-GLOBAL_LIST_INIT(regular_bloods,list(
- "O-",
- "O+",
- "A-",
- "A+",
- "B-",
- "B+",
- "AB-",
- "AB+"
- ))
-
-GLOBAL_LIST_INIT(all_types_bloods,list(
- "O-",
- "O+",
- "A-",
- "A+",
- "B-",
- "B+",
- "AB-",
- "AB+",
- "SY",
- "X*",
- "HF",
- "L",
- "U",
- "GEL"
- ))
-
-GLOBAL_LIST_INIT(blood_types, list(
- "blood",
- "syntheticblood",
- "xenoblood",
- "oilblood",
- "jellyblood"
- ))
-
-GLOBAL_LIST_INIT(blood_id_types, list(
- "blood" = /datum/reagent/blood,
- "syntheticblood" = /datum/reagent/blood/synthetics,
- "xenoblood" = /datum/reagent/blood/xenomorph,
- "oilblood" = /datum/reagent/blood/oil,
- "jellyblood" = /datum/reagent/blood/jellyblood
- ))
-
-
//Crew objective and miscreants stuff
GLOBAL_VAR_INIT(miscreants_allowed, FALSE)
diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm
index c883254afe..5143cc3028 100644
--- a/code/_globalvars/lists/mobs.dm
+++ b/code/_globalvars/lists/mobs.dm
@@ -58,3 +58,70 @@ GLOBAL_LIST_EMPTY(latejoiners) //CIT CHANGE - All latejoining people, for traito
for(var/i in GLOB.mob_list)
var/mob/M = i
M.update_config_movespeed()
+
+GLOBAL_LIST_INIT(noodle_taurs, list(
+ "Naga",
+ "Tentacle"
+ ))
+
+GLOBAL_LIST_INIT(paw_taurs, list(
+ "Fox",
+ "Wolf",
+ "Otie",
+ "Drake",
+ "Lab",
+ "Shepherd",
+ "Husky",
+ "Eevee",
+ "Panther",
+ "Horse",
+ "Cow",
+ "Tiger"
+ ))
+
+ //blood types
+GLOBAL_LIST_INIT(regular_bloods,list(
+ "O-",
+ "O+",
+ "A-",
+ "A+",
+ "B-",
+ "B+",
+ "AB-",
+ "AB+"
+ ))
+
+GLOBAL_LIST_INIT(all_types_bloods,list(
+ "O-",
+ "O+",
+ "A-",
+ "A+",
+ "B-",
+ "B+",
+ "AB-",
+ "AB+",
+ "SY",
+ "X*",
+ "HF",
+ "L",
+ "U",
+ "GEL",
+ "BUG"
+ ))
+
+GLOBAL_LIST_INIT(blood_types, list(
+ "blood",
+ "syntheticblood",
+ "xenoblood",
+ "oilblood",
+ "jellyblood"
+ ))
+
+GLOBAL_LIST_INIT(blood_id_types, list(
+ "blood" = /datum/reagent/blood,
+ "syntheticblood" = /datum/reagent/blood/synthetics,
+ "xenoblood" = /datum/reagent/blood/xenomorph,
+ "oilblood" = /datum/reagent/blood/oil,
+ "jellyblood" = /datum/reagent/blood/jellyblood
+ ))
+
diff --git a/code/datums/components/cleaning.dm b/code/datums/components/cleaning.dm
index 08ac57b79a..0cb0fce7b9 100644
--- a/code/datums/components/cleaning.dm
+++ b/code/datums/components/cleaning.dm
@@ -12,28 +12,28 @@
if(!isturf(tile))
return
- tile.clean_blood()
+ SEND_SIGNAL(tile, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
for(var/A in tile)
if(is_cleanable(A))
qdel(A)
- else if(isitem(A))
- var/obj/item/cleaned_item = A
- cleaned_item.clean_blood()
- if(ismob(cleaned_item.loc))
- var/mob/M = cleaned_item.loc
+ else if(istype(A, /obj/item))
+ var/obj/item/I = A
+ SEND_SIGNAL(I, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
+ if(ismob(I.loc))
+ var/mob/M = I.loc
M.regenerate_icons()
else if(ishuman(A))
var/mob/living/carbon/human/cleaned_human = A
if(cleaned_human.lying)
if(cleaned_human.head)
- cleaned_human.head.clean_blood()
+ SEND_SIGNAL(cleaned_human.head, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
if(cleaned_human.wear_suit)
- cleaned_human.wear_suit.clean_blood()
+ SEND_SIGNAL(cleaned_human.wear_suit, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
else if(cleaned_human.w_uniform)
- cleaned_human.w_uniform.clean_blood()
+ SEND_SIGNAL(cleaned_human.w_uniform, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
if(cleaned_human.shoes)
- cleaned_human.shoes.clean_blood()
- cleaned_human.clean_blood()
+ SEND_SIGNAL(cleaned_human.shoes, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
+ SEND_SIGNAL(cleaned_human, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
cleaned_human.wash_cream()
cleaned_human.regenerate_icons()
- to_chat(cleaned_human, "[AM] cleans your face!")
+ to_chat(cleaned_human, "[AM] cleans your face!")
\ No newline at end of file
diff --git a/code/datums/components/decals/blood.dm b/code/datums/components/decals/blood.dm
new file mode 100644
index 0000000000..47c7fb8228
--- /dev/null
+++ b/code/datums/components/decals/blood.dm
@@ -0,0 +1,37 @@
+/datum/component/decal/blood
+ dupe_mode = COMPONENT_DUPE_UNIQUE
+
+/datum/component/decal/blood/Initialize(_icon, _icon_state, _dir, _cleanable=CLEAN_STRENGTH_BLOOD, _color, _layer=ABOVE_OBJ_LAYER)
+ if(!isitem(parent))
+ return COMPONENT_INCOMPATIBLE
+ . = ..()
+ RegisterSignal(parent, COMSIG_ATOM_GET_EXAMINE_NAME, .proc/get_examine_name)
+
+/datum/component/decal/blood/generate_appearance(_icon, _icon_state, _dir, _layer, _color)
+ var/obj/item/I = parent
+ if(!_icon)
+ _icon = 'icons/effects/blood.dmi'
+ if(!_icon_state)
+ _icon_state = "itemblood"
+ var/icon = initial(I.icon)
+ var/icon_state = initial(I.icon_state)
+ if(!icon || !icon_state)
+ // It's something which takes on the look of other items, probably
+ icon = I.icon
+ icon_state = I.icon_state
+ var/icon/blood_splatter_icon = icon(initial(I.icon), initial(I.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(_icon, _icon_state), ICON_MULTIPLY) //adds blood and the remaining white areas become transparant
+ pic = mutable_appearance(blood_splatter_icon, initial(I.icon_state))
+
+ I.blood_overlay = image(blood_splatter_icon)
+ I.blood_overlay.color = I.blood_DNA_to_color()
+ I.add_overlay(I.blood_overlay)
+
+ return TRUE
+
+/datum/component/decal/blood/proc/get_examine_name(datum/source, mob/user, list/override)
+ var/atom/A = parent
+ override[EXAMINE_POSITION_ARTICLE] = A.gender == PLURAL? "some" : "a"
+ override[EXAMINE_POSITION_BEFORE] = " blood-stained "
+ return COMPONENT_EXNAME_CHANGED
diff --git a/code/datums/components/forensics.dm b/code/datums/components/forensics.dm
new file mode 100644
index 0000000000..cd3cbbd8c1
--- /dev/null
+++ b/code/datums/components/forensics.dm
@@ -0,0 +1,184 @@
+/datum/component/forensics
+ dupe_mode = COMPONENT_DUPE_UNIQUE
+ can_transfer = TRUE
+ var/list/fingerprints //assoc print = print
+ var/list/hiddenprints //assoc ckey = realname/gloves/ckey
+ var/list/blood_DNA //assoc dna = bloodtype
+ var/list/fibers //assoc print = print
+
+/datum/component/forensics/InheritComponent(datum/component/forensics/F, original) //Use of | and |= being different here is INTENTIONAL.
+ fingerprints = fingerprints | F.fingerprints
+ hiddenprints = hiddenprints | F.hiddenprints
+ blood_DNA = blood_DNA | F.blood_DNA
+ fibers = fibers | F.fibers
+ check_blood()
+ return ..()
+
+/datum/component/forensics/Initialize(new_fingerprints, new_hiddenprints, new_blood_DNA, new_fibers)
+ if(!isatom(parent))
+ return COMPONENT_INCOMPATIBLE
+ fingerprints = new_fingerprints
+ hiddenprints = new_hiddenprints
+ blood_DNA = new_blood_DNA
+ fibers = new_fibers
+ check_blood()
+
+/datum/component/forensics/RegisterWithParent()
+ check_blood()
+ RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, .proc/clean_act)
+
+/datum/component/forensics/UnregisterFromParent()
+ UnregisterSignal(parent, list(COMSIG_COMPONENT_CLEAN_ACT))
+
+/datum/component/forensics/PostTransfer()
+ if(!isatom(parent))
+ return COMPONENT_INCOMPATIBLE
+
+/datum/component/forensics/proc/wipe_fingerprints()
+ fingerprints = null
+ return TRUE
+
+/datum/component/forensics/proc/wipe_hiddenprints()
+ return //no.
+
+/datum/component/forensics/proc/wipe_blood_DNA()
+ blood_DNA = null
+ if(isitem(parent))
+ qdel(parent.GetComponent(/datum/component/decal/blood))
+ return TRUE
+
+/datum/component/forensics/proc/wipe_fibers()
+ fibers = null
+ return TRUE
+
+/datum/component/forensics/proc/clean_act(datum/source, strength)
+ if(strength >= CLEAN_STRENGTH_FINGERPRINTS)
+ wipe_fingerprints()
+ if(strength >= CLEAN_STRENGTH_BLOOD)
+ wipe_blood_DNA()
+ if(strength >= CLEAN_STRENGTH_FIBERS)
+ wipe_fibers()
+
+/datum/component/forensics/proc/add_fingerprint_list(list/_fingerprints) //list(text)
+ if(!length(_fingerprints))
+ return
+ LAZYINITLIST(fingerprints)
+ for(var/i in _fingerprints) //We use an associative list, make sure we don't just merge a non-associative list into ours.
+ fingerprints[i] = i
+ return TRUE
+
+/datum/component/forensics/proc/add_fingerprint(mob/living/M, ignoregloves = FALSE)
+ if(!isliving(M))
+ if(!iscameramob(M))
+ return
+ if(isaicamera(M))
+ var/mob/camera/aiEye/ai_camera = M
+ if(!ai_camera.ai)
+ return
+ M = ai_camera.ai
+ add_hiddenprint(M)
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ add_fibers(H)
+ if(H.gloves) //Check if the gloves (if any) hide fingerprints
+ var/obj/item/clothing/gloves/G = H.gloves
+ if(G.transfer_prints)
+ ignoregloves = TRUE
+ if(!ignoregloves)
+ H.gloves.add_fingerprint(H, TRUE) //ignoregloves = 1 to avoid infinite loop.
+ return
+ var/full_print = md5(H.dna.uni_identity)
+ LAZYSET(fingerprints, full_print, full_print)
+ return TRUE
+
+/datum/component/forensics/proc/add_fiber_list(list/_fibertext) //list(text)
+ if(!length(_fibertext))
+ return
+ LAZYINITLIST(fibers)
+ for(var/i in _fibertext) //We use an associative list, make sure we don't just merge a non-associative list into ours.
+ fibers[i] = i
+ return TRUE
+
+/datum/component/forensics/proc/add_fibers(mob/living/carbon/human/M)
+ var/fibertext
+ var/item_multiplier = isitem(src)?1.2:1
+ if(M.wear_suit)
+ fibertext = "Material from \a [M.wear_suit]."
+ if(prob(10*item_multiplier) && !LAZYACCESS(fibers, fibertext))
+ LAZYSET(fibers, fibertext, fibertext)
+ if(!(M.wear_suit.body_parts_covered & CHEST))
+ if(M.w_uniform)
+ fibertext = "Fibers from \a [M.w_uniform]."
+ if(prob(12*item_multiplier) && !LAZYACCESS(fibers, fibertext)) //Wearing a suit means less of the uniform exposed.
+ LAZYSET(fibers, fibertext, fibertext)
+ if(!(M.wear_suit.body_parts_covered & HANDS))
+ if(M.gloves)
+ fibertext = "Material from a pair of [M.gloves.name]."
+ if(prob(20*item_multiplier) && !LAZYACCESS(fibers, fibertext))
+ LAZYSET(fibers, fibertext, fibertext)
+ else if(M.w_uniform)
+ fibertext = "Fibers from \a [M.w_uniform]."
+ if(prob(15*item_multiplier) && !LAZYACCESS(fibers, fibertext))
+ // "Added fibertext: [fibertext]"
+ LAZYSET(fibers, fibertext, fibertext)
+ if(M.gloves)
+ fibertext = "Material from a pair of [M.gloves.name]."
+ if(prob(20*item_multiplier) && !LAZYACCESS(fibers, fibertext))
+ LAZYSET(fibers, fibertext, fibertext)
+ else if(M.gloves)
+ fibertext = "Material from a pair of [M.gloves.name]."
+ if(prob(20*item_multiplier) && !LAZYACCESS(fibers, fibertext))
+ LAZYSET(fibers, fibertext, fibertext)
+ return TRUE
+
+/datum/component/forensics/proc/add_hiddenprint_list(list/_hiddenprints) //list(ckey = text)
+ if(!length(_hiddenprints))
+ return
+ LAZYINITLIST(hiddenprints)
+ for(var/i in _hiddenprints) //We use an associative list, make sure we don't just merge a non-associative list into ours.
+ hiddenprints[i] = _hiddenprints[i]
+ return TRUE
+
+/datum/component/forensics/proc/add_hiddenprint(mob/M)
+ if(!isliving(M))
+ if(!iscameramob(M))
+ return
+ if(isaicamera(M))
+ var/mob/camera/aiEye/ai_camera = M
+ if(!ai_camera.ai)
+ return
+ M = ai_camera.ai
+ if(!M.key)
+ return
+ var/hasgloves = ""
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ if(H.gloves)
+ hasgloves = "(gloves)"
+ var/current_time = TIME_STAMP("hh:mm:ss", FALSE)
+ if(!LAZYACCESS(hiddenprints, M.key))
+ LAZYSET(hiddenprints, M.key, "First: [M.real_name]\[[current_time]\][hasgloves]. Ckey: [M.ckey]")
+ else
+ var/laststamppos = findtext(LAZYACCESS(hiddenprints, M.key), " Last: ")
+ if(laststamppos)
+ LAZYSET(hiddenprints, M.key, copytext(hiddenprints[M.key], 1, laststamppos))
+ hiddenprints[M.key] += " Last: [M.real_name]\[[current_time]\][hasgloves]. Ckey: [M.ckey]" //made sure to be existing by if(!LAZYACCESS);else
+ var/atom/A = parent
+ A.fingerprintslast = M.ckey
+ return TRUE
+
+/datum/component/forensics/proc/add_blood_DNA(list/dna) //list(dna_enzymes = type)
+ if(!length(dna))
+ return
+ LAZYINITLIST(blood_DNA)
+ for(var/i in dna)
+ blood_DNA[i] = dna[i]
+ check_blood()
+ return TRUE
+
+/datum/component/forensics/proc/check_blood()
+ if(!isitem(parent))
+ return
+ if(!length(blood_DNA))
+ return
+ parent.LoadComponent(/datum/component/decal/blood)
diff --git a/code/datums/dna.dm b/code/datums/dna.dm
index 8d04ff246a..33e92e4de5 100644
--- a/code/datums/dna.dm
+++ b/code/datums/dna.dm
@@ -303,14 +303,6 @@
if(!dna.species)
var/rando_race = pick(GLOB.roundstart_races)
dna.species = new rando_race()
- if(isjellyperson(dna.species))
- dna.blood_type = "GEL"
- if(isipcperson(dna.species))
- dna.blood_type = "HF"
- if(isxenoperson(dna.species))
- dna.blood_type = "X*"
- if(islizard(dna.species))
- dna.blood_type = "L"
//proc used to update the mob's appearance after its dna UI has been changed
/mob/living/carbon/proc/updateappearance(icon_update=1, mutcolor_update=0, mutations_overlay_update=0)
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 71e06abd15..a740edacfc 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -37,9 +37,6 @@
var/rad_insulation = RAD_NO_INSULATION
var/icon/blood_splatter_icon
- var/list/fingerprints
- var/list/fingerprintshidden
- var/list/blood_DNA
/atom/New(loc, ...)
//atom creation method that preloads variables at creation
@@ -248,22 +245,24 @@
return TRUE
return FALSE
-/atom/proc/examine(mob/user)
- //This reformat names to get a/an properly working on item descriptions when they are bloody
- var/f_name = "\a [src]."
- if(src.blood_DNA && !istype(src, /obj/effect/decal))
- if(gender == PLURAL)
- f_name = "some "
- else
- f_name = "a "
- f_name += "blood-stained [name]!"
+/atom/proc/get_examine_name(mob/user)
+ . = "\a [src]"
+ var/list/override = list(gender == PLURAL ? "some" : "a", " ", "[name]")
+ if(article)
+ . = "[article] [src]"
+ override[EXAMINE_POSITION_ARTICLE] = article
+ if(SEND_SIGNAL(src, COMSIG_ATOM_GET_EXAMINE_NAME, user, override) & COMPONENT_EXNAME_CHANGED)
+ . = override.Join("")
- to_chat(user, "[icon2html(src, user)] That's [f_name]")
+///Generate the full examine string of this atom (including icon for goonchat)
+/atom/proc/get_examine_string(mob/user, thats = FALSE)
+ . = "[icon2html(src, user)] [thats? "That's ":""][get_examine_name(user)]"
+
+/atom/proc/examine(mob/user)
+ to_chat(user, "[get_examine_string(user, TRUE)].")
if(desc)
to_chat(user, desc)
- // *****RM
- //to_chat(user, "[name]: Dn:[density] dir:[dir] cont:[contents] icon:[icon] is:[icon_state] loc:[loc]")
if(reagents)
if(reagents.reagents_holder_flags & TRANSPARENT)
@@ -285,6 +284,8 @@
else
to_chat(user, "It's empty.")
+ SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user)
+
/atom/proc/relaymove(mob/user)
if(buckle_message_cooldown <= world.time)
buckle_message_cooldown = world.time + 50
@@ -349,24 +350,12 @@
var/new_blood_dna = L.get_blood_dna_list()
if(!new_blood_dna)
return FALSE
- if(!blood_DNA) //if our list of DNA doesn't exist yet, initialise it.
- blood_DNA = list()
- var/old_length = blood_DNA.len
- blood_DNA |= new_blood_dna
- if(blood_DNA.len == old_length)
+ var/old_length = blood_DNA_length()
+ add_blood(new_blood_dna)
+ if(blood_DNA_length() == old_length)
return FALSE
return TRUE
-//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 TRUE//some new blood DNA was added
-
-
//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()
@@ -374,101 +363,6 @@
return FALSE
return add_blood(blood_dna)
-//to add blood onto something, with blood dna info to include.
-/atom/proc/add_blood(list/blood_dna)
- return FALSE
-
-/obj/add_blood(list/blood_dna)
- return transfer_blood_dna(blood_dna)
-
-/obj/item/add_blood(list/blood_dna)
- if(!..())
- return FALSE
- add_blood_overlay()
- return TRUE //we applied blood to the item
-
-/obj/item/proc/add_blood_overlay()
- if(!blood_DNA.len)
- return
- if(initial(icon) && initial(icon_state))
- 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_overlay = image(blood_splatter_icon)
- blood_overlay.color = blood_DNA_to_color()
- add_overlay(blood_overlay)
-
-/obj/item/clothing/gloves/add_blood(mob/living/carbon/M)
- . = ..()
- transfer_blood = rand(2, 4)
- return TRUE
-
-/obj/item/clothing/shoes/add_blood(mob/living/carbon/M)
- . = ..()
-// transfer_blood = rand(2, 4)
- return TRUE
-
-/turf/add_blood(list/blood_dna)
- 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.
- return TRUE //we bloodied the floor
-
-/mob/living/carbon/human/add_blood(list/blood_dna)
- if(wear_suit)
- wear_suit.add_blood(blood_dna)
- update_inv_wear_suit()
- else if(w_uniform)
- w_uniform.add_blood(blood_dna)
- update_inv_w_uniform()
- if(gloves)
- var/obj/item/clothing/gloves/G = gloves
- G.add_blood(blood_dna)
- else
- transfer_blood_dna(blood_dna)
- bloody_hands = rand(2, 4)
- update_inv_gloves() //handles bloody hands overlays and updating
- if(shoes)
- var/obj/item/clothing/shoes/S = shoes
- S.add_blood(blood_dna)
-// else
-// transfer_blood_dna(blood_dna)
-// bloody_feet = rand(2, 4)
- update_inv_shoes() // get them feet messy for prints!
- return TRUE
-
-/atom/proc/clean_blood()
- if(islist(blood_DNA))
- blood_DNA = null
- return TRUE
-
-/atom/proc/blood_DNA_to_color()
- var/list/colors = list()//first we make a list of all bloodtypes present
- for(var/bloop in blood_DNA)
- if(colors[blood_DNA[bloop]])
- colors[blood_DNA[bloop]]++
- else
- colors[blood_DNA[bloop]] = 1
-
- var/final_rgb = "#940000"
-
- if(colors.len)
- var/sum = 0 //this is all shitcode, but it works; trust me
- final_rgb = bloodtype_to_color(colors[1])
- sum = colors[colors[1]]
- if(colors.len > 1)
- var/i = 2
- while(i <= colors.len)
- var/tmp = colors[colors[i]]
- final_rgb = BlendRGB(final_rgb, bloodtype_to_color(colors[i]), tmp/(tmp+sum))
- sum += tmp
- i++
-
- return final_rgb
-
-
/atom/proc/wash_cream()
return TRUE
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index 27faa6bffb..94d3e2f499 100644
--- a/code/game/machinery/suit_storage_unit.dm
+++ b/code/game/machinery/suit_storage_unit.dm
@@ -247,8 +247,7 @@
visible_message("[src]'s door slides open, barraging you with the nauseating smell of charred flesh.")
playsound(src, 'sound/machines/airlockclose.ogg', 25, 1)
for(var/obj/item/I in src) //Scorches away blood and forensic evidence, although the SSU itself is unaffected
- I.clean_blood()
- I.fingerprints = list()
+ SEND_SIGNAL(I, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRONG)
var/datum/component/radioactive/contamination = I.GetComponent(/datum/component/radioactive)
if(contamination)
qdel(contamination)
@@ -419,4 +418,4 @@
if(I)
I.forceMove(loc)
. = TRUE
- update_icon()
+ update_icon()
\ No newline at end of file
diff --git a/code/game/machinery/washing_machine.dm b/code/game/machinery/washing_machine.dm
index 2ff7ee1a13..e117c680ca 100644
--- a/code/game/machinery/washing_machine.dm
+++ b/code/game/machinery/washing_machine.dm
@@ -11,6 +11,10 @@
var/obj/item/color_source
var/max_wash_capacity = 5
+/obj/machinery/washing_machine/ComponentInitialize()
+ . = ..()
+ AddComponent(/datum/component/redirect, list(COMSIG_COMPONENT_CLEAN_ACT = CALLBACK(src, .proc/clean_blood)))
+
/obj/machinery/washing_machine/examine(mob/user)
..()
to_chat(user, "Alt-click it to start a wash cycle.")
@@ -55,8 +59,7 @@
M.Translate(rand(-3, 3), rand(-1, 3))
animate(src, transform=M, time=2)
-/obj/machinery/washing_machine/clean_blood()
- ..()
+/obj/machinery/washing_machine/proc/clean_blood()
if(!busy)
bloody_mess = FALSE
update_icon()
@@ -64,7 +67,7 @@
/obj/machinery/washing_machine/proc/wash_cycle()
for(var/X in contents)
var/atom/movable/AM = X
- AM.clean_blood()
+ SEND_SIGNAL(AM, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
AM.machine_wash(src)
busy = FALSE
@@ -92,12 +95,6 @@
var/obj/item/toy/crayon/CR = WM.color_source
add_atom_colour(CR.paint_color, WASHABLE_COLOUR_PRIORITY)
-/obj/item/reagents_containers/rag/towel/machine_wash(obj/machinery/washing_machine/WM)
- if(WM.color_source)
- if(istype(WM.color_source, /obj/item/toy/crayon))
- var/obj/item/toy/crayon/CR = WM.color_source
- add_atom_colour(CR.paint_color, WASHABLE_COLOUR_PRIORITY)
-
/mob/living/simple_animal/pet/dog/corgi/machine_wash(obj/machinery/washing_machine/WM)
gib()
@@ -274,4 +271,4 @@
..()
density = TRUE //because machinery/open_machine() sets it to 0
color_source = null
- has_corgi = 0
+ has_corgi = 0
\ 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 6746c41f0b..a56f45a712 100644
--- a/code/game/objects/effects/decals/cleanable.dm
+++ b/code/game/objects/effects/decals/cleanable.dm
@@ -1,8 +1,7 @@
-
/obj/effect/decal/cleanable
gender = PLURAL
layer = ABOVE_NORMAL_TURF_LAYER
- var/list/random_icon_states = list()
+ var/list/random_icon_states = null
var/blood_state = "" //I'm sorry but cleanable/blood code is ass, and so is blood_DNA
var/bloodiness = 0 //0-100, amount of blood in this decal, used for making footprints and affecting the alpha of bloody footprints
var/mergeable_decal = TRUE //when two of these are on a same tile or do we need to merge them into just one?
@@ -26,9 +25,9 @@
if(LAZYLEN(diseases_to_add))
AddComponent(/datum/component/infective, diseases_to_add)
-/obj/effect/decal/cleanable/proc/replace_decal(obj/effect/decal/cleanable/C)
+/obj/effect/decal/cleanable/proc/replace_decal(obj/effect/decal/cleanable/C) // Returns true if we should give up in favor of the pre-existing decal
if(mergeable_decal)
- qdel(C)
+ return TRUE
/obj/effect/decal/cleanable/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/reagent_containers/glass) || istype(W, /obj/item/reagent_containers/food/drinks))
@@ -70,9 +69,10 @@
//Add "bloodiness" of this blood's type, to the human's shoes
//This is on /cleanable because fuck this ancient mess
/obj/effect/decal/cleanable/Crossed(atom/movable/O)
+ ..()
if(ishuman(O))
var/mob/living/carbon/human/H = O
- if(H.shoes && blood_state && bloodiness && (!HAS_TRAIT(H,TRAIT_LIGHT_STEP) || !H.mind.assigned_role == "Detective"))
+ if(H.shoes && blood_state && bloodiness && !HAS_TRAIT(H, TRAIT_LIGHT_STEP))
var/obj/item/clothing/shoes/S = H.shoes
var/add_blood = 0
if(bloodiness >= BLOOD_GAIN_PER_STEP)
@@ -81,8 +81,7 @@
add_blood = bloodiness
bloodiness -= add_blood
S.bloody_shoes[blood_state] = min(MAX_SHOE_BLOODINESS,S.bloody_shoes[blood_state]+add_blood)
- if(blood_DNA && blood_DNA.len)
- S.add_blood(blood_DNA)
+ S.add_blood(return_blood_DNA())
S.blood_state = blood_state
update_icon()
H.update_inv_shoes()
diff --git a/code/game/objects/effects/decals/cleanable/aliens.dm b/code/game/objects/effects/decals/cleanable/aliens.dm
index e6edc7661a..3a9f851e4c 100644
--- a/code/game/objects/effects/decals/cleanable/aliens.dm
+++ b/code/game/objects/effects/decals/cleanable/aliens.dm
@@ -3,17 +3,17 @@
name = "xeno blood"
desc = "It's green and acidic. It looks like... blood?"
color = BLOOD_COLOR_XENO
- blood_DNA = list("UNKNOWN DNA" = "X*")
/obj/effect/decal/cleanable/blood/splatter/xeno
color = BLOOD_COLOR_XENO
/obj/effect/decal/cleanable/blood/gibs/xeno
color = BLOOD_COLOR_XENO
+ gibs_reagent_id = "liquidxenogibs"
+ gibs_bloodtype = "X*"
/obj/effect/decal/cleanable/blood/gibs/xeno/Initialize(mapload, list/datum/disease/diseases)
. = ..()
- reagents.add_reagent("liquidxenogibs", 5)
update_icon()
/obj/effect/decal/cleanable/blood/gibs/xeno/update_icon()
@@ -35,7 +35,7 @@
if(infective)
diseases = infective.diseases
var/obj/effect/decal/cleanable/blood/splatter/xeno/splat = new /obj/effect/decal/cleanable/blood/splatter/xeno(loc, diseases)
- splat.transfer_blood_dna(blood_DNA)
+ splat.add_blood(return_blood_DNA())
if(!step_to(src, get_step(src, direction), 0))
break
diff --git a/code/game/objects/effects/decals/cleanable/gibs.dm b/code/game/objects/effects/decals/cleanable/gibs.dm
index c7df4e4ecf..73c89b4db5 100644
--- a/code/game/objects/effects/decals/cleanable/gibs.dm
+++ b/code/game/objects/effects/decals/cleanable/gibs.dm
@@ -6,11 +6,17 @@
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6")
mergeable_decal = FALSE
var/body_colors = "#e3ba84" //a default color just in case.
+ var/gibs_reagent_id = "liquidgibs"
+ var/gibs_bloodtype = "A+"
/obj/effect/decal/cleanable/blood/gibs/Initialize(mapload, list/datum/disease/diseases)
. = ..()
if(random_icon_states && (icon_state == initial(icon_state)) && length(random_icon_states) > 0)
icon_state = pick(random_icon_states)
+ if(gibs_reagent_id)
+ reagents.add_reagent(gibs_reagent_id, 5)
+ if(gibs_bloodtype)
+ add_blood(list("Non-human DNA" = gibs_bloodtype))
update_icon()
@@ -51,7 +57,7 @@
if(infective)
diseases = infective.diseases
var/obj/effect/decal/cleanable/blood/splatter/splat = new /obj/effect/decal/cleanable/blood/splatter(loc, diseases)
- splat.transfer_blood_dna(blood_DNA)
+ splat.add_blood(return_blood_DNA())
if(!step_to(src, get_step(src, direction), 0))
break
@@ -81,9 +87,8 @@
/obj/effect/decal/cleanable/blood/gibs/old/Initialize(mapload, list/datum/disease/diseases)
. = ..()
- setDir(pick(1,2,4,8))
+ setDir(pick(GLOB.cardinals))
icon_state += "-old"
- add_blood(list("Non-human DNA" = "A+"))
update_icon()
/obj/effect/decal/cleanable/blood/drip
@@ -101,9 +106,6 @@
/obj/effect/decal/cleanable/blood/gibs/human/Initialize(mapload, list/datum/disease/diseases)
. = ..()
- reagents.add_reagent("liquidgibs", 5)
- if(!blood_DNA.len)
- add_blood(list("Non-human DNA" = "A+"))
update_icon()
/obj/effect/decal/cleanable/blood/gibs/human/up
@@ -128,12 +130,11 @@
//Lizards
/obj/effect/decal/cleanable/blood/gibs/human/lizard
body_colors = "117720"
+ gibs_reagent_id = "liquidgibs"
+ gibs_bloodtype = "L"
/obj/effect/decal/cleanable/blood/gibs/human/lizard/Initialize(mapload, list/datum/disease/diseases)
. = ..()
- reagents.add_reagent("liquidgibs", 5)
- if(!blood_DNA.len)
- add_blood(list("Non-human DNA" = "L"))
update_icon()
/obj/effect/decal/cleanable/blood/gibs/human/lizard/up
@@ -157,12 +158,11 @@
// Slime Gibs
/obj/effect/decal/cleanable/blood/gibs/slime
desc = "They look gooey and gruesome."
+ gibs_reagent_id = "liquidslimegibs"
+ gibs_bloodtype = "GEL"
/obj/effect/decal/cleanable/blood/gibs/slime/Initialize(mapload, list/datum/disease/diseases)
. = ..()
- reagents.add_reagent("liquidslimegibs", 5)
- if(!blood_DNA.len)
- add_blood(list("Non-human DNA" = "GEL"))
update_icon()
/obj/effect/decal/cleanable/blood/gibs/slime/update_icon()
@@ -197,21 +197,22 @@
/obj/effect/decal/cleanable/blood/gibs/synth
desc = "They look sludgy and disgusting."
+ gibs_reagent_id = "liquidsyntheticgibs"
+ gibs_bloodtype = "SY"
/obj/effect/decal/cleanable/blood/gibs/synth/Initialize(mapload, list/datum/disease/diseases)
. = ..()
- reagents.add_reagent("liquidsyntheticgibs", 5)
+ update_icon()
//IPCs
/obj/effect/decal/cleanable/blood/gibs/ipc
desc = "They look sharp yet oozing."
body_colors = "00ff00"
+ gibs_reagent_id = "liquidoilgibs"
+ gibs_bloodtype = "HF"
/obj/effect/decal/cleanable/blood/gibs/ipc/Initialize(mapload, list/datum/disease/diseases)
. = ..()
- reagents.add_reagent("liquidoilgibs", 5)
- if(!blood_DNA.len)
- add_blood(list("Non-human DNA" = "HF"))
update_icon()
/obj/effect/decal/cleanable/blood/gibs/ipc/update_icon()
diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm
index 8b582587fe..ceb41dee5c 100644
--- a/code/game/objects/effects/decals/cleanable/humans.dm
+++ b/code/game/objects/effects/decals/cleanable/humans.dm
@@ -4,16 +4,17 @@
icon = 'icons/effects/blood.dmi'
icon_state = "floor1"
random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7")
- blood_DNA = list()
blood_state = BLOOD_STATE_BLOOD
bloodiness = MAX_SHOE_BLOODINESS
color = BLOOD_COLOR_HUMAN //default so we don't have white splotches everywhere.
/obj/effect/decal/cleanable/blood/replace_decal(obj/effect/decal/cleanable/blood/C)
- if (C.blood_DNA)
- blood_DNA |= C.blood_DNA.Copy()
+ C.add_blood(return_blood_DNA())
+ if (bloodiness)
+ if (C.bloodiness < MAX_SHOE_BLOODINESS)
+ C.bloodiness += bloodiness
update_icon()
- ..()
+ return ..()
/obj/effect/decal/cleanable/blood/transfer_blood_dna()
..()
@@ -50,7 +51,6 @@
desc = "Your instincts say you shouldn't be following these."
random_icon_states = null
var/list/existing_dirs = list()
- blood_DNA = list()
/obj/effect/decal/cleanable/trail_holder/update_icon()
color = blood_DNA_to_color()
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 22daea7b56..229d8fcb3a 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -541,17 +541,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
M.become_blind(EYE_DAMAGE)
to_chat(M, "You go blind!")
-/obj/item/clean_blood()
- . = ..()
- if(.)
- if(blood_splatter_icon)
- cut_overlay(blood_splatter_icon)
-
-/obj/item/clothing/gloves/clean_blood()
- . = ..()
- if(.)
- transfer_blood = 0
-
/obj/item/singularity_pull(S, current_size)
..()
if(current_size >= STAGE_FOUR)
diff --git a/code/game/objects/items/clown_items.dm b/code/game/objects/items/clown_items.dm
index e371ae7d40..1d302b409e 100644
--- a/code/game/objects/items/clown_items.dm
+++ b/code/game/objects/items/clown_items.dm
@@ -88,7 +88,7 @@
var/obj/effect/decal/cleanable/C = locate() in target
qdel(C)
target.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
- target.clean_blood()
+ SEND_SIGNAL(target, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_MEDIUM)
target.wash_cream()
return
diff --git a/code/game/objects/items/mop.dm b/code/game/objects/items/mop.dm
index 65246aefa4..7524fc9007 100644
--- a/code/game/objects/items/mop.dm
+++ b/code/game/objects/items/mop.dm
@@ -26,7 +26,7 @@
/obj/item/mop/proc/clean(turf/A)
if(reagents.has_reagent("water", 1) || reagents.has_reagent("holywater", 1) || reagents.has_reagent("vodka", 1) || reagents.has_reagent("cleaner", 1))
- A.clean_blood()
+ SEND_SIGNAL(A, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_MEDIUM)
for(var/obj/effect/O in A)
if(is_cleanable(O))
qdel(O)
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 9b714b7b15..a4b0740c1c 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -388,10 +388,10 @@
else
. = ..()
-/obj/item/stack/proc/copy_evidences(obj/item/stack/from as obj)
- blood_DNA = from.blood_DNA
- fingerprints = from.fingerprints
- fingerprintshidden = from.fingerprintshidden
+/obj/item/stack/proc/copy_evidences(obj/item/stack/from)
+ add_blood(from.return_blood_DNA())
+ add_fingerprint_list(from.return_fingerprints())
+ add_hiddenprint_list(from.return_hiddenprints())
fingerprintslast = from.fingerprintslast
//TODO bloody overlay
@@ -436,4 +436,4 @@
/datum/stack_recipe_list/New(title, recipes)
src.title = title
- src.recipes = recipes
+ src.recipes = recipes
\ No newline at end of file
diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm
index 34b3c90d07..80b68213aa 100644
--- a/code/game/objects/items/twohanded.dm
+++ b/code/game/objects/items/twohanded.dm
@@ -346,7 +346,7 @@
icon_state = "dualsaber[item_color][wielded]"
else
icon_state = "dualsaber0"
- clean_blood()//blood overlays get weird otherwise, because the sprite changes.
+ SEND_SIGNAL(src, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
/obj/item/twohanded/dualsaber/attack(mob/target, mob/living/carbon/human/user)
if(user.has_dna())
@@ -881,4 +881,4 @@
var/client/C = user.client
C.change_view(CONFIG_GET(string/default_view))
user.client.pixel_x = 0
- user.client.pixel_y = 0
+ user.client.pixel_y = 0
\ No newline at end of file
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index 61aa776f01..ea2bbb0dcd 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -317,7 +317,7 @@
/obj/machinery/shower/proc/wash_obj(obj/O)
- . = O.clean_blood()
+ . = SEND_SIGNAL(O, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
O.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
if(isitem(O))
var/obj/item/I = O
@@ -328,7 +328,7 @@
/obj/machinery/shower/proc/wash_turf()
if(isturf(loc))
var/turf/tile = loc
- tile.clean_blood()
+ SEND_SIGNAL(tile, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
tile.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
for(var/obj/effect/E in tile)
if(is_cleanable(E))
@@ -336,7 +336,7 @@
/obj/machinery/shower/proc/wash_mob(mob/living/L)
- L.clean_blood()
+ SEND_SIGNAL(L, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
L.wash_cream()
L.ExtinguishMob()
L.adjust_fire_stacks(-20) //Douse ourselves with water to avoid fire more easily
@@ -381,7 +381,7 @@
else if(H.w_uniform && wash_obj(H.w_uniform))
H.update_inv_w_uniform()
if(washgloves)
- H.clean_blood()
+ SEND_SIGNAL(H, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
if(H.shoes && washshoes && wash_obj(H.shoes))
H.update_inv_shoes()
if(H.wear_mask && washmask && wash_obj(H.wear_mask))
@@ -398,9 +398,9 @@
else
if(M.wear_mask && wash_obj(M.wear_mask))
M.update_inv_wear_mask(0)
- M.clean_blood()
+ SEND_SIGNAL(M, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
else
- L.clean_blood()
+ SEND_SIGNAL(L, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
/obj/machinery/shower/proc/contamination_cleanse(atom/movable/thing)
var/datum/component/radioactive/healthy_green_glow = thing.GetComponent(/datum/component/radioactive)
@@ -498,7 +498,7 @@
H.regenerate_icons()
user.drowsyness = max(user.drowsyness - rand(2,3), 0) //Washing your face wakes you up if you're falling asleep
else
- user.clean_blood()
+ SEND_SIGNAL(user, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
/obj/structure/sink/attackby(obj/item/O, mob/living/user, params)
if(busy)
@@ -554,7 +554,7 @@
busy = FALSE
return 1
busy = FALSE
- O.clean_blood()
+ SEND_SIGNAL(O, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
O.acid_level = 0
create_reagents(5)
reagents.add_reagent(dispensedreagent, 5)
@@ -675,4 +675,4 @@
else
playsound(loc, 'sound/weapons/tap.ogg', 50, 1)
if(BURN)
- playsound(loc, 'sound/items/welder.ogg', 80, 1)
+ playsound(loc, 'sound/items/welder.ogg', 80, 1)
\ No newline at end of file
diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm
index 62cd626d5d..f6d234b346 100644
--- a/code/game/turfs/open.dm
+++ b/code/game/turfs/open.dm
@@ -250,7 +250,7 @@
for(var/mob/living/simple_animal/slime/M in src)
M.apply_water()
- clean_blood()
+ SEND_SIGNAL(src, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
for(var/obj/effect/O in src)
if(is_cleanable(O))
qdel(O)
diff --git a/code/modules/antagonists/devil/true_devil/_true_devil.dm b/code/modules/antagonists/devil/true_devil/_true_devil.dm
index d595428378..1df81a797b 100644
--- a/code/modules/antagonists/devil/true_devil/_true_devil.dm
+++ b/code/modules/antagonists/devil/true_devil/_true_devil.dm
@@ -69,10 +69,8 @@
//Left hand items
for(var/obj/item/I in held_items)
if(!(I.item_flags & ABSTRACT))
- if(I.blood_DNA)
- msg += "It is holding [icon2html(I, user)] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in its [get_held_index_name(get_held_index_of_item(I))]!\n"
- else
- msg += "It is holding [icon2html(I, user)] \a [I] in its [get_held_index_name(get_held_index_of_item(I))].\n"
+ msg += "It is holding [I.get_examine_string(user)] in its [get_held_index_name(get_held_index_of_item(I))].\n"
+
//Braindead
if(!client && stat != DEAD)
msg += "The devil seems to be in deep contemplation.\n"
diff --git a/code/modules/antagonists/wizard/equipment/artefact.dm b/code/modules/antagonists/wizard/equipment/artefact.dm
index 3a5564cf05..08e00ea0f4 100644
--- a/code/modules/antagonists/wizard/equipment/artefact.dm
+++ b/code/modules/antagonists/wizard/equipment/artefact.dm
@@ -327,8 +327,11 @@
possible = list()
if(!voodoo_link)
return
+ var/list/prints = voodoo_link.return_fingerprints()
+ if(!length(prints))
+ return FALSE
for(var/mob/living/carbon/human/H in GLOB.alive_mob_list)
- if(md5(H.dna.uni_identity) in voodoo_link.fingerprints)
+ if(prints[md5(H.dna.uni_identity)])
possible |= H
/obj/item/voodoo/proc/GiveHint(mob/victim,force=0)
diff --git a/code/modules/clothing/gloves/_gloves.dm b/code/modules/clothing/gloves/_gloves.dm
index 2932912ed7..0ae04c1f7a 100644
--- a/code/modules/clothing/gloves/_gloves.dm
+++ b/code/modules/clothing/gloves/_gloves.dm
@@ -12,6 +12,15 @@
strip_delay = 20
equip_delay_other = 40
+/obj/item/clothing/gloves/ComponentInitialize()
+ . = ..()
+ AddComponent(/datum/component/redirect, list(COMSIG_COMPONENT_CLEAN_ACT = CALLBACK(src, .proc/clean_blood)))
+
+/obj/item/clothing/gloves/proc/clean_blood(datum/source, strength)
+ if(strength < CLEAN_STRENGTH_BLOOD)
+ return
+ transfer_blood = 0
+
/obj/item/clothing/gloves/suicide_act(mob/living/carbon/user)
user.visible_message("\the [src] are forcing [user]'s hands around [user.p_their()] neck! It looks like the gloves are possessed!")
return OXYLOSS
@@ -21,7 +30,7 @@
if(!isinhands)
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedgloves")
- if(blood_DNA)
+ IF_HAS_BLOOD_DNA(src)
. += mutable_appearance('icons/effects/blood.dmi', "bloodyhands", color = blood_DNA_to_color())
/obj/item/clothing/gloves/update_clothes_damaged_state(damaging = TRUE)
diff --git a/code/modules/clothing/head/_head.dm b/code/modules/clothing/head/_head.dm
index ccc167dcbc..98bb3aec13 100644
--- a/code/modules/clothing/head/_head.dm
+++ b/code/modules/clothing/head/_head.dm
@@ -46,7 +46,7 @@
if(!isinhands)
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedhelmet")
- if(blood_DNA)
+ IF_HAS_BLOOD_DNA(src)
. += mutable_appearance('icons/effects/blood.dmi', "helmetblood", color = blood_DNA_to_color())
/obj/item/clothing/head/update_clothes_damaged_state(damaging = TRUE)
diff --git a/code/modules/clothing/masks/_masks.dm b/code/modules/clothing/masks/_masks.dm
index c00e6f72e0..362ab9b3bd 100644
--- a/code/modules/clothing/masks/_masks.dm
+++ b/code/modules/clothing/masks/_masks.dm
@@ -59,7 +59,7 @@
if(body_parts_covered & HEAD)
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedmask")
- if(blood_DNA)
+ IF_HAS_BLOOD_DNA(src)
. += mutable_appearance('icons/effects/blood.dmi', "maskblood", color = blood_DNA_to_color())
/obj/item/clothing/mask/update_clothes_damaged_state(damaging = TRUE)
diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm
index 2356bb16eb..0bb7c8ebfd 100644
--- a/code/modules/clothing/neck/_neck.dm
+++ b/code/modules/clothing/neck/_neck.dm
@@ -12,7 +12,7 @@
if(body_parts_covered & HEAD)
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedmask")
- if(blood_DNA)
+ IF_HAS_BLOOD_DNA(src)
. += mutable_appearance('icons/effects/blood.dmi', "maskblood", color = blood_DNA_to_color())
/obj/item/clothing/neck/tie
diff --git a/code/modules/clothing/shoes/_shoes.dm b/code/modules/clothing/shoes/_shoes.dm
index d6927f9953..04c5644fb5 100644
--- a/code/modules/clothing/shoes/_shoes.dm
+++ b/code/modules/clothing/shoes/_shoes.dm
@@ -10,18 +10,22 @@
permeability_coefficient = 0.5
slowdown = SHOES_SLOWDOWN
- var/offset = 0
- var/equipped_before_drop = FALSE
-
var/blood_state = BLOOD_STATE_NOT_BLOODY
var/list/bloody_shoes = list(BLOOD_STATE_BLOOD = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0)
- var/last_bloodtype = ""//used to track the last bloodtype to have graced these shoes; makes for better performing footprint shenanigans
- var/last_blood_DNA = ""//same as last one
+ var/offset = 0
+ var/equipped_before_drop = FALSE
//CITADEL EDIT Enables digitigrade shoe styles
var/adjusted = NORMAL_STYLE
mutantrace_variation = MUTANTRACE_VARIATION
+ var/last_bloodtype = ""//used to track the last bloodtype to have graced these shoes; makes for better performing footprint shenanigans
+ var/last_blood_DNA = ""//same as last one
+
+/obj/item/clothing/shoes/ComponentInitialize()
+ . = ..()
+ AddComponent(/datum/component/redirect, list(COMSIG_COMPONENT_CLEAN_ACT = CALLBACK(src, .proc/clean_blood)))
+
/obj/item/clothing/shoes/suicide_act(mob/living/carbon/user)
if(rand(2)>1)
user.visible_message("[user] begins tying \the [src] up waaay too tightly! It looks like [user.p_theyre()] trying to commit suicide!")
@@ -45,7 +49,7 @@
. = list()
if(!isinhands)
var/bloody = FALSE
- if(blood_DNA)
+ IF_HAS_BLOOD_DNA(src)
bloody = TRUE
else
bloody = bloody_shoes[BLOOD_STATE_BLOOD]
@@ -92,11 +96,11 @@
var/mob/M = loc
M.update_inv_shoes()
-/obj/item/clothing/shoes/clean_blood()
- ..()
+/obj/item/clothing/shoes/proc/clean_blood(datum/source, strength)
+ if(strength < CLEAN_STRENGTH_BLOOD)
+ return
bloody_shoes = list(BLOOD_STATE_BLOOD = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0)
blood_state = BLOOD_STATE_NOT_BLOODY
- blood_color = null
if(ismob(loc))
var/mob/M = loc
M.update_inv_shoes()
diff --git a/code/modules/clothing/suits/_suits.dm b/code/modules/clothing/suits/_suits.dm
index 2ad1bba042..86d473ca7b 100644
--- a/code/modules/clothing/suits/_suits.dm
+++ b/code/modules/clothing/suits/_suits.dm
@@ -53,11 +53,11 @@
if(!isinhands)
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damaged[blood_overlay_type]")
- if(blood_DNA)
+ IF_HAS_BLOOD_DNA(src)
if(taurmode >= SNEK_TAURIC)
- . += mutable_appearance('modular_citadel/icons/mob/64x32_effects.dmi', "[blood_overlay_type]blood", color = blood_DNA_to_color())
+ . += mutable_appearance('modular_citadel/icons/mob/64x32_effects.dmi', "[blood_overlay_type]blood")
else
- . += mutable_appearance('icons/effects/blood.dmi', "[blood_overlay_type]blood", color = blood_DNA_to_color())
+ . += mutable_appearance('icons/effects/blood.dmi', "[blood_overlay_type]blood")
var/mob/living/carbon/human/M = loc
if(ishuman(M) && M.w_uniform)
var/obj/item/clothing/under/U = M.w_uniform
diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm
index eda0e31e93..5f123cd745 100644
--- a/code/modules/clothing/under/_under.dm
+++ b/code/modules/clothing/under/_under.dm
@@ -22,7 +22,7 @@
if(!isinhands)
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damageduniform")
- if(blood_DNA)
+ IF_HAS_BLOOD_DNA(src)
. += mutable_appearance('icons/effects/blood.dmi', "uniformblood", color = blood_DNA_to_color())
if(accessory_overlay)
. += accessory_overlay
diff --git a/code/modules/detectivework/detective_work.dm b/code/modules/detectivework/detective_work.dm
index d5584bc29f..8451019efb 100644
--- a/code/modules/detectivework/detective_work.dm
+++ b/code/modules/detectivework/detective_work.dm
@@ -1,119 +1,146 @@
//CONTAINS: Suit fibers and Detective's Scanning Computer
-/atom/var/list/suit_fibers
+/atom/proc/return_fingerprints()
+ GET_COMPONENT(D, /datum/component/forensics)
+ if(D)
+ . = D.fingerprints
-/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.blood_DNA)) //only reduces the bloodiness of our gloves if the item wasn't already bloody
- G.transfer_blood--
- else if(M.bloody_hands > 1)
- if(add_blood(M.blood_DNA))
- M.bloody_hands--
- if(!suit_fibers)
- suit_fibers = list()
- var/fibertext
- var/item_multiplier = isitem(src)?1.2:1
- if(M.wear_suit)
- fibertext = "Material from \a [M.wear_suit]."
- if(prob(10*item_multiplier) && !(fibertext in suit_fibers))
- suit_fibers += fibertext
- if(!(M.wear_suit.body_parts_covered & CHEST))
- if(M.w_uniform)
- fibertext = "Fibers from \a [M.w_uniform]."
- if(prob(12*item_multiplier) && !(fibertext in suit_fibers)) //Wearing a suit means less of the uniform exposed.
- suit_fibers += fibertext
- if(!(M.wear_suit.body_parts_covered & HANDS))
- if(M.gloves)
- fibertext = "Material from a pair of [M.gloves.name]."
- if(prob(20*item_multiplier) && !(fibertext in suit_fibers))
- suit_fibers += fibertext
- else if(M.w_uniform)
- fibertext = "Fibers from \a [M.w_uniform]."
- if(prob(15*item_multiplier) && !(fibertext in suit_fibers))
- // "Added fibertext: [fibertext]"
- suit_fibers += fibertext
- if(M.gloves)
- fibertext = "Material from a pair of [M.gloves.name]."
- if(prob(20*item_multiplier) && !(fibertext in suit_fibers))
- suit_fibers += "Material from a pair of [M.gloves.name]."
- else if(M.gloves)
- fibertext = "Material from a pair of [M.gloves.name]."
- if(prob(20*item_multiplier) && !(fibertext in suit_fibers))
- suit_fibers += "Material from a pair of [M.gloves.name]."
+/atom/proc/return_hiddenprints()
+ GET_COMPONENT(D, /datum/component/forensics)
+ if(D)
+ . = D.hiddenprints
+/atom/proc/return_blood_DNA()
+ GET_COMPONENT(D, /datum/component/forensics)
+ if(D)
+ . = D.blood_DNA
-/atom/proc/add_hiddenprint(mob/living/M)
- if(!M || !M.key)
- return
+/atom/proc/blood_DNA_length()
+ GET_COMPONENT(D, /datum/component/forensics)
+ if(D)
+ . = length(D.blood_DNA)
- if(!fingerprintshidden) //Add the list if it does not exist
- fingerprintshidden = list()
-
- var/hasgloves = ""
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(H.gloves)
- hasgloves = "(gloves)"
-
- var/current_time = TIME_STAMP("hh:mm:ss", FALSE)
- if(!fingerprintshidden[M.key])
- fingerprintshidden[M.key] = "First: [M.real_name]\[[current_time]\][hasgloves]. Ckey: [M.ckey]"
- else
- var/laststamppos = findtext(fingerprintshidden[M.key], " Last: ")
- if(laststamppos)
- fingerprintshidden[M.key] = copytext(fingerprintshidden[M.key], 1, laststamppos)
- fingerprintshidden[M.key] += " Last: [M.real_name]\[[current_time]\][hasgloves]. Ckey: [M.ckey]"
-
- fingerprintslast = M.ckey
+/atom/proc/return_fibers()
+ GET_COMPONENT(D, /datum/component/forensics)
+ if(D)
+ . = D.fibers
+/atom/proc/add_fingerprint_list(list/fingerprints) //ASSOC LIST FINGERPRINT = FINGERPRINT
+ if(length(fingerprints))
+ . = AddComponent(/datum/component/forensics, fingerprints)
//Set ignoregloves to add prints irrespective of the mob having gloves on.
-/atom/proc/add_fingerprint(mob/living/M, ignoregloves = 0)
- if(!M || !M.key)
- return
+/atom/proc/add_fingerprint(mob/living/M, ignoregloves = FALSE)
+ var/datum/component/forensics/D = AddComponent(/datum/component/forensics)
+ . = D.add_fingerprint(M, ignoregloves)
- add_hiddenprint(M)
+/atom/proc/add_fiber_list(list/fibertext) //ASSOC LIST FIBERTEXT = FIBERTEXT
+ if(length(fibertext))
+ . = AddComponent(/datum/component/forensics, null, null, null, fibertext)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
+/atom/proc/add_fibers(mob/living/carbon/human/M)
+ var/old = 0
+ if(M.gloves && istype(M.gloves, /obj/item/clothing))
+ var/obj/item/clothing/gloves/G = M.gloves
+ old = length(G.return_blood_DNA())
+ if(G.transfer_blood > 1) //bloodied gloves transfer blood to touched objects
+ if(add_blood(G.return_blood_DNA()) && length(G.return_blood_DNA()) > old) //only reduces the bloodiness of our gloves if the item wasn't already bloody
+ G.transfer_blood--
+ else if(M.bloody_hands > 1)
+ old = length(M.return_blood_DNA())
+ if(add_blood(M.return_blood_DNA()) && length(M.return_blood_DNA()) > old)
+ M.bloody_hands--
+ var/datum/component/forensics/D = AddComponent(/datum/component/forensics)
+ . = D.add_fibers(M)
- add_fibers(H)
+/atom/proc/add_hiddenprint_list(list/hiddenprints) //NOTE: THIS IS FOR ADMINISTRATION FINGERPRINTS, YOU MUST CUSTOM SET THIS TO INCLUDE CKEY/REAL NAMES! CHECK FORENSICS.DM
+ if(length(hiddenprints))
+ . = AddComponent(/datum/component/forensics, null, hiddenprints)
- if(H.gloves) //Check if the gloves (if any) hide fingerprints
- var/obj/item/clothing/gloves/G = H.gloves
- if(G.transfer_prints)
- ignoregloves = 1
+/atom/proc/add_hiddenprint(mob/living/M)
+ var/datum/component/forensics/D = AddComponent(/datum/component/forensics)
+ . = D.add_hiddenprint(M)
- if(!ignoregloves)
- H.gloves.add_fingerprint(H, 1) //ignoregloves = 1 to avoid infinite loop.
- return
+/atom/proc/add_blood(list/dna) //ASSOC LIST DNA = BLOODTYPE
+ return FALSE
- if(!fingerprints) //Add the list if it does not exist
- fingerprints = list()
- var/full_print = md5(H.dna.uni_identity)
- fingerprints[full_print] = full_print
+/obj/add_blood(list/dna)
+ . = ..()
+ if(length(dna))
+ . = AddComponent(/datum/component/forensics, null, null, dna)
+/obj/item/clothing/gloves/add_blood(list/blood_dna, list/datum/disease/diseases)
+ . = ..()
+ transfer_blood = rand(2, 4)
+/turf/add_blood(list/blood_dna, list/datum/disease/diseases)
+ var/obj/effect/decal/cleanable/blood/splatter/B = locate() in src
+ if(!B)
+ B = new /obj/effect/decal/cleanable/blood/splatter(src, diseases)
+ B.add_blood(blood_dna) //give blood info to the blood decal.
+ return TRUE //we bloodied the floor
+/mob/living/carbon/human/add_blood(list/blood_dna, list/datum/disease/diseases)
+ if(wear_suit)
+ wear_suit.add_blood(blood_dna)
+ update_inv_wear_suit()
+ else if(w_uniform)
+ w_uniform.add_blood(blood_dna)
+ update_inv_w_uniform()
+ if(gloves)
+ var/obj/item/clothing/gloves/G = gloves
+ G.add_blood(blood_dna)
+ else if(length(blood_dna))
+ AddComponent(/datum/component/forensics, null, null, blood_dna)
+ bloody_hands = rand(2, 4)
+ if(head)
+ head.add_blood(blood_dna)
+ update_inv_head()
+ else if(wear_mask)
+ wear_mask.add_blood(blood_dna)
+ update_inv_wear_mask()
+ if(wear_neck)
+ wear_neck.add_blood(blood_dna)
+ update_inv_neck()
+ update_inv_gloves() //handles bloody hands overlays and updating
+ return TRUE
/atom/proc/transfer_fingerprints_to(atom/A)
+ A.add_fingerprint_list(return_fingerprints())
+ A.add_hiddenprint_list(return_hiddenprints())
+ A.fingerprintslast = fingerprintslast
- // Make sure everything are lists.
- if(!islist(A.fingerprints))
- A.fingerprints = list()
- if(!islist(A.fingerprintshidden))
- A.fingerprintshidden = list()
+//to add blood dna info to the object's blood_DNA list
+/atom/proc/transfer_blood_dna(list/blood_dna)
+ var/list/dna = blood_DNA_length()
+ if(!dna)
+ dna = list()
+ var/old_length = dna.len
+ dna |= blood_dna
+ if(dna.len > old_length)
+ return TRUE//some new blood DNA was added
- if(!islist(fingerprints))
- fingerprints = list()
- if(!islist(fingerprintshidden))
- fingerprintshidden = list()
+/atom/proc/blood_DNA_to_color() //handles RGB colorings of blood
+ var/list/dna = blood_DNA_length()
+ var/list/colors = list()//first we make a list of all bloodtypes present
+ for(var/bloop in dna)
+ if(colors[dna[bloop]])
+ colors[dna[bloop]]++
+ else
+ colors[dna[bloop]] = 1
- // Transfer
- if(fingerprints)
- A.fingerprints |= fingerprints.Copy() //detective
- if(fingerprintshidden)
- A.fingerprintshidden |= fingerprintshidden.Copy() //admin
- A.fingerprintslast = fingerprintslast
\ No newline at end of file
+ var/final_rgb = BLOOD_COLOR_HUMAN
+
+ if(colors.len)
+ var/sum = 0 //this is all shitcode, but it works; trust me
+ final_rgb = bloodtype_to_color(colors[1])
+ sum = colors[colors[1]]
+ if(colors.len > 1)
+ var/i = 2
+ while(i <= colors.len)
+ var/tmp = colors[colors[i]]
+ final_rgb = BlendRGB(final_rgb, bloodtype_to_color(colors[i]), tmp/(tmp+sum))
+ sum += tmp
+ i++
+
+ return final_rgb
diff --git a/code/modules/detectivework/scanner.dm b/code/modules/detectivework/scanner.dm
index eace1bf7b1..5940c3328d 100644
--- a/code/modules/detectivework/scanner.dm
+++ b/code/modules/detectivework/scanner.dm
@@ -80,20 +80,14 @@
//Make our lists
var/list/fingerprints = list()
- var/list/blood = list()
- var/list/fibers = list()
+ var/list/blood = A.return_blood_DNA()
+ var/list/fibers = A.return_fibers()
var/list/reagents = list()
var/target_name = A.name
// Start gathering
- if(A.blood_DNA && A.blood_DNA.len)
- blood = A.blood_DNA.Copy()
-
- if(A.suit_fibers && A.suit_fibers.len)
- fibers = A.suit_fibers.Copy()
-
if(ishuman(A))
var/mob/living/carbon/human/H = A
@@ -102,8 +96,7 @@
else if(!ismob(A))
- if(A.fingerprints && A.fingerprints.len)
- fingerprints = A.fingerprints.Copy()
+ fingerprints = A.return_fingerprints()
// Only get reagents from non-mobs.
if(A.reagents && A.reagents.reagent_list.len)
@@ -117,6 +110,7 @@
if(R.data["blood_DNA"] && R.data["blood_type"])
var/blood_DNA = R.data["blood_DNA"]
var/blood_type = R.data["blood_type"]
+ LAZYINITLIST(blood)
blood[blood_DNA] = blood_type
// We gathered everything. Create a fork and slowly display the results to the holder of the scanner.
@@ -125,7 +119,7 @@
add_log("[STATION_TIME_TIMESTAMP("hh:mm:ss")][get_timestamp()] - [target_name]", 0)
// Fingerprints
- if(fingerprints && fingerprints.len)
+ if(length(fingerprints))
sleep(30)
add_log("Prints:")
for(var/finger in fingerprints)
@@ -133,7 +127,7 @@
found_something = 1
// Blood
- if (blood && blood.len)
+ if (length(blood))
sleep(30)
add_log("Blood:")
found_something = 1
@@ -141,7 +135,7 @@
add_log("Type: [blood[B]] DNA: [B]")
//Fibers
- if(fibers && fibers.len)
+ if(length(fibers))
sleep(30)
add_log("Fibers:")
for(var/fiber in fibers)
@@ -149,7 +143,7 @@
found_something = 1
//Reagents
- if(reagents && reagents.len)
+ if(length(reagents))
sleep(30)
add_log("Reagents:")
for(var/R in reagents)
@@ -213,4 +207,4 @@
return
to_chat(user, "Scanner Report")
for(var/iterLog in log)
- to_chat(user, iterLog)
+ to_chat(user, iterLog)
\ No newline at end of file
diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm
index 9191f627e5..dbe0e31d3b 100644
--- a/code/modules/mob/living/blood.dm
+++ b/code/modules/mob/living/blood.dm
@@ -160,7 +160,7 @@
C.reagents.add_reagent("bonehurtingjuice", amount * 0.5)
else
C.blood_volume = min(C.blood_volume + round(amount, 0.1), BLOOD_VOLUME_MAXIMUM)
- return 1
+ return 1
C.blood_volume = min(C.blood_volume + round(amount, 0.1), BLOOD_VOLUME_MAXIMUM)
return 1
@@ -232,12 +232,7 @@
return "blood"
/mob/living/carbon/get_blood_id()
- var/mob/living/carbon/C = src
- if(ishuman(C))
- var/mob/living/carbon/human/H = C
- if(H.dna.species.exotic_blood)
- return H.dna.species.exotic_blood
- if(dna.species.exotic_blood)
+ if(dna?.species?.exotic_blood)
return dna.species.exotic_blood
else if((NOBLOOD in dna.species.species_traits) || (HAS_TRAIT(src, TRAIT_NOCLONE)))
return
@@ -290,8 +285,7 @@
drop.transfer_mob_blood_dna(src)
return
else
- temp_blood_DNA = list()
- temp_blood_DNA |= drop.blood_DNA.Copy() //we transfer the dna from the drip to the splatter
+ temp_blood_DNA = drop.return_blood_DNA() //we transfer the dna from the drip to the splatter
qdel(drop)//the drip is replaced by a bigger splatter
else
drop = new(T, get_static_viruses())
@@ -307,9 +301,9 @@
B.transfer_mob_blood_dna(src) //give blood info to the blood decal.
if(temp_blood_DNA)
if(isalien(src))
- B.blood_DNA["UNKNOWN DNA"] = "X*"
+ B.add_blood(list("UNKNOWN DNA" = "X*"))
else
- B.blood_DNA |= temp_blood_DNA
+ B.add_blood(temp_blood_DNA)
/mob/living/carbon/human/add_splatter_floor(turf/T, small_drip)
if(!(NOBLOOD in dna.species.species_traits))
diff --git a/code/modules/mob/living/brain/brain.dm b/code/modules/mob/living/brain/brain.dm
index 9a39d5bc7d..1b2944c1f6 100644
--- a/code/modules/mob/living/brain/brain.dm
+++ b/code/modules/mob/living/brain/brain.dm
@@ -24,14 +24,8 @@
if(!stored_dna.species)
var/rando_race = pick(GLOB.roundstart_races)
stored_dna.species = new rando_race()
- if(isjellyperson(stored_dna.species))
- stored_dna.blood_type = "GEL"
- if(isipcperson(stored_dna.species))
- stored_dna.blood_type = "HF"
- if(isxenoperson(stored_dna.species))
- stored_dna.blood_type = "X*"
- if(islizard(stored_dna.species))
- stored_dna.blood_type = "L"
+ if(stored_dna.species.exotic_bloodtype)
+ stored_dna.blood_type = stored_dna.species.exotic_bloodtype
/mob/living/brain/Destroy()
if(key) //If there is a mob connected to this thing. Have to check key twice to avoid false death reporting.
diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm
index efdd1a96c5..22da46346c 100644
--- a/code/modules/mob/living/carbon/examine.dm
+++ b/code/modules/mob/living/carbon/examine.dm
@@ -11,21 +11,18 @@
if (handcuffed)
msg += "[t_He] [t_is] [icon2html(handcuffed, user)] handcuffed!\n"
if (head)
- msg += "[t_He] [t_is] wearing [icon2html(head, user)] \a [src.head] on [t_his] head. \n"
+ msg += "[t_He] [t_is] wearing [head.get_examine_string(user)] on [t_his] head. \n"
if (wear_mask)
- msg += "[t_He] [t_is] wearing [icon2html(wear_mask, user)] \a [src.wear_mask] on [t_his] face.\n"
+ msg += "[t_He] [t_is] wearing [wear_mask.get_examine_string(user)] on [t_his] face.\n"
if (wear_neck)
- msg += "[t_He] [t_is] wearing [icon2html(wear_neck, user)] \a [src.wear_neck] around [t_his] neck.\n"
+ msg += "[t_He] [t_is] wearing [wear_neck.get_examine_string(user)] around [t_his] neck.\n"
for(var/obj/item/I in held_items)
if(!(I.item_flags & ABSTRACT))
- if(I.blood_DNA)
- msg += "[t_He] [t_is] holding [icon2html(I, user)] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in [t_his] [get_held_index_name(get_held_index_of_item(I))]!\n"
- else
- msg += "[t_He] [t_is] holding [icon2html(I, user)] \a [I] in [t_his] [get_held_index_name(get_held_index_of_item(I))].\n"
+ msg += "[t_He] [t_is] holding [I.get_examine_string(user)] in [t_his] [get_held_index_name(get_held_index_of_item(I))].\n"
if (back)
- msg += "[t_He] [t_has] [icon2html(back, user)] \a [src.back] on [t_his] back.\n"
+ msg += "[t_He] [t_has] [back.get_examine_string(user)] on [t_his] back.\n"
var/appears_dead = 0
if (stat == DEAD)
appears_dead = 1
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 0a34b02e4b..632281bb23 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -1,4 +1,4 @@
-/mob/living/carbon/human/examine(mob/user) //User is the person being examined
+/mob/living/carbon/human/examine(mob/user)
//this is very slightly better than it was because you can use it more places. still can't do \his[src] though.
var/t_He = p_they(TRUE)
var/t_His = p_their(TRUE)
@@ -37,47 +37,30 @@
if(U.attached_accessory)
accessory_msg += " with [icon2html(U.attached_accessory, user)] \a [U.attached_accessory]"
- if(w_uniform.blood_DNA)
- msg += "[t_He] [t_is] wearing [icon2html(w_uniform, user)] [w_uniform.gender==PLURAL?"some":"a"] blood-stained [w_uniform.name][accessory_msg]!\n"
- else
- msg += "[t_He] [t_is] wearing [icon2html(w_uniform, user)] \a [w_uniform][accessory_msg].\n"
+ msg += "[t_He] [t_is] wearing [w_uniform.get_examine_string(user)][accessory_msg].\n"
//head
if(head)
- if(head.blood_DNA)
- msg += "[t_He] [t_is] wearing [icon2html(head, user)] [head.gender==PLURAL?"some":"a"] blood-stained [head.name] on [t_his] head!\n"
- else
- msg += "[t_He] [t_is] wearing [icon2html(head, user)] \a [head] on [t_his] head.\n"
+ msg += "[t_He] [t_is] wearing [head.get_examine_string(user)] on [t_his] head.\n"
//suit/armor
if(wear_suit)
- if(wear_suit.blood_DNA)
- msg += "[t_He] [t_is] wearing [icon2html(wear_suit, user)] [wear_suit.gender==PLURAL?"some":"a"] blood-stained [wear_suit.name]!\n"
- else
- msg += "[t_He] [t_is] wearing [icon2html(wear_suit, user)] \a [wear_suit].\n"
- //suit/armour storage
- if(s_store)
- if(s_store.blood_DNA)
- msg += "[t_He] [t_is] carrying [icon2html(s_store, user)] [s_store.gender==PLURAL?"some":"a"] blood-stained [s_store.name] on [t_his] [wear_suit.name]!\n"
- else
- msg += "[t_He] [t_is] carrying [icon2html(s_store, user)] \a [s_store] on [t_his] [wear_suit.name].\n"
+ msg += "[t_He] [t_is] wearing [wear_suit.get_examine_string(user)].\n"
+ //suit/armor storage
+ if(s_store && !(SLOT_S_STORE in obscured))
+ msg += "[t_He] [t_is] carrying [s_store.get_examine_string(user)] on [t_his] [wear_suit.name].\n"
//back
if(back)
- if(back.blood_DNA)
- msg += "[t_He] [t_has] [icon2html(back, user)] [back.gender==PLURAL?"some":"a"] blood-stained [back] on [t_his] back.\n"
- else
- msg += "[t_He] [t_has] [icon2html(back, user)] \a [back] on [t_his] back.\n"
+ msg += "[t_He] [t_has] [back.get_examine_string(user)] on [t_his] back.\n"
+
//Hands
for(var/obj/item/I in held_items)
- if(I.blood_DNA)
- msg += "[t_He] [t_is] holding [icon2html(I, user)] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in [t_his] [get_held_index_name(get_held_index_of_item(I))]!\n"
- else
- msg += "[t_He] [t_is] holding [icon2html(I, user)] \a [I] in [t_his] [get_held_index_name(get_held_index_of_item(I))].\n"
+ if(!(I.item_flags & ABSTRACT))
+ msg += "[t_He] [t_is] holding [I.get_examine_string(user)] in [t_his] [get_held_index_name(get_held_index_of_item(I))].\n"
+
+ var/datum/component/forensics/FR = GetComponent(/datum/component/forensics)
//gloves
if(gloves && !(SLOT_GLOVES in obscured))
- if(gloves.blood_DNA)
- msg += "[t_He] [t_has] [icon2html(gloves, user)] [gloves.gender==PLURAL?"some":"a"] blood-stained [gloves.name] on [t_his] hands!\n"
- else
- msg += "[t_He] [t_has] [icon2html(gloves, user)] \a [gloves] on [t_his] hands.\n"
- else if(blood_DNA)
+ msg += "[t_He] [t_has] [gloves.get_examine_string(user)] on [t_his] hands.\n"
+ else if(FR && length(FR.blood_DNA))
var/hand_number = get_num_arms(FALSE)
if(hand_number)
msg += "[t_He] [t_has] [hand_number > 1 ? "" : "a"] blood-stained hand[hand_number > 1 ? "s" : ""]!\n"
@@ -93,47 +76,33 @@
//belt
if(belt)
- if(belt.blood_DNA)
- msg += "[t_He] [t_has] [icon2html(belt, user)] [belt.gender==PLURAL?"some":"a"] blood-stained [belt.name] about [t_his] waist!\n"
- else
- msg += "[t_He] [t_has] [icon2html(belt, user)] \a [belt] about [t_his] waist.\n"
+ msg += "[t_He] [t_has] [belt.get_examine_string(user)] about [t_his] waist.\n"
//shoes
if(shoes && !(SLOT_SHOES in obscured))
- if(shoes.blood_DNA)
- msg += "[t_He] [t_is] wearing [icon2html(shoes, user)] [shoes.gender==PLURAL?"some":"a"] blood-stained [shoes.name] on [t_his] feet!\n"
- else
- msg += "[t_He] [t_is] wearing [icon2html(shoes, user)] \a [shoes] on [t_his] feet.\n"
+ msg += "[t_He] [t_is] wearing [shoes.get_examine_string(user)] on [t_his] feet.\n"
//mask
if(wear_mask && !(SLOT_WEAR_MASK in obscured))
- if(wear_mask.blood_DNA)
- msg += "[t_He] [t_has] [icon2html(wear_mask, user)] [wear_mask.gender==PLURAL?"some":"a"] blood-stained [wear_mask.name] on [t_his] face!\n"
- else
- msg += "[t_He] [t_has] [icon2html(wear_mask, user)] \a [wear_mask] on [t_his] face.\n"
+ msg += "[t_He] [t_has] [wear_mask.get_examine_string(user)] on [t_his] face.\n"
- //neck
if(wear_neck && !(SLOT_NECK in obscured))
- msg += "[t_He] [t_is] wearing [icon2html(wear_neck, user)] \a [src.wear_neck] around [t_his] neck.\n"
+ msg += "[t_He] [t_is] wearing [wear_neck.get_examine_string(user)] around [t_his] neck.\n"
//eyes
if(!(SLOT_GLASSES in obscured))
if(glasses)
- if(glasses.blood_DNA)
- msg += "[t_He] [t_has] [icon2html(glasses, user)] [glasses.gender==PLURAL?"some":"a"] blood-stained [glasses] covering [t_his] eyes!\n"
- else
- msg += "[t_He] [t_has] [icon2html(glasses, user)] \a [glasses] covering [t_his] eyes.\n"
-
+ msg += "[t_He] [t_has] [glasses.get_examine_string(user)] covering [t_his] eyes.\n"
else if(eye_color == BLOODCULT_EYE && iscultist(src) && HAS_TRAIT(src, TRAIT_CULT_EYES))
msg += "[t_His] eyes are glowing an unnatural red!\n"
//ears
if(ears && !(SLOT_EARS in obscured))
- msg += "[t_He] [t_has] [icon2html(ears, user)] \a [ears] on [t_his] ears.\n"
+ msg += "[t_He] [t_has] [ears.get_examine_string(user)] on [t_his] ears.\n"
//ID
if(wear_id)
- msg += "[t_He] [t_is] wearing [icon2html(wear_id, user)] \a [wear_id].\n"
+ msg += "[t_He] [t_is] wearing [wear_id.get_examine_string(user)].\n"
//Status effects
msg += status_effect_examines()
@@ -183,7 +152,7 @@
var/temp = getBruteLoss() //no need to calculate each of these twice
- msg += ""
+ msg += "" //Everything below gets this span
var/list/missing = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
var/list/disabled = list()
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index daf5917f87..f6d06c2d07 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -32,6 +32,8 @@
if(CONFIG_GET(flag/disable_stambuffer))
togglesprint()
+ AddComponent(/datum/component/redirect, list(COMSIG_COMPONENT_CLEAN_ACT = CALLBACK(src, .proc/clean_blood)))
+
/mob/living/carbon/human/ComponentInitialize()
. = ..()
@@ -687,21 +689,16 @@
if(..())
dropItemToGround(I)
-/mob/living/carbon/human/clean_blood()
- var/mob/living/carbon/human/H = src
- if(H.gloves)
- if(H.gloves.clean_blood())
- H.update_inv_gloves()
+/mob/living/carbon/human/proc/clean_blood(datum/source, strength)
+ if(strength < CLEAN_STRENGTH_BLOOD)
+ return
+ if(gloves)
+ if(SEND_SIGNAL(gloves, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD))
+ update_inv_gloves()
else
- ..() // Clear the Blood_DNA list
- if(H.bloody_hands)
- H.bloody_hands = 0
- H.update_inv_gloves()
-/* if(H.bloody_feet)
- H.bloody_feet = 0
- H.update_inv_shoes()*/
-
- update_icons() //apply the now updated overlays to the mob
+ if(bloody_hands)
+ bloody_hands = 0
+ update_inv_gloves()
/mob/living/carbon/human/wash_cream()
if(creamed) //clean both to prevent a rare bug
@@ -1069,4 +1066,4 @@
race = /datum/species/zombie/infectious
/mob/living/carbon/human/species/zombie/krokodil_addict
- race = /datum/species/krokodil_addict
+ race = /datum/species/krokodil_addict
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm
index f03b75cf11..d0b90387f7 100644
--- a/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/code/modules/mob/living/carbon/human/human_movement.dm
@@ -64,9 +64,7 @@
FP.blood_state = S.blood_state
FP.entered_dirs |= dir
FP.bloodiness = S.bloody_shoes[S.blood_state]
- if(S.last_blood_DNA && S.last_bloodtype)
- FP.blood_DNA += list(S.last_blood_DNA = S.last_bloodtype)
- //hacky as heck; we need to move the LAST entry to there, otherwise we mix all the blood
+ FP.add_blood(S.return_blood_DNA())
FP.update_icon()
update_inv_shoes()
//End bloody footprints
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 73149c422d..caa3a0bcf9 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -269,16 +269,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
regenerate_organs(C,old_species)
if(exotic_bloodtype && C.dna.blood_type != exotic_bloodtype)
- if(isjellyperson(C))
- C.dna.blood_type = "GEL"
- if(isipcperson(C))
- C.dna.blood_type = "HF"
- if(isxenoperson(C))
- C.dna.blood_type = "X*"
- if(islizard(C))
- C.dna.blood_type = "L"
- else
- C.dna.blood_type = exotic_bloodtype
+ C.dna.blood_type = exotic_bloodtype
if(old_species.mutanthands)
for(var/obj/item/I in C.held_items)
@@ -319,16 +310,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
/datum/species/proc/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load)
if(C.dna.species.exotic_bloodtype)
- if(isjellyperson(C))
- C.dna.blood_type = "GEL"
- if(isipcperson(C))
- C.dna.blood_type = "HF"
- if(isxenoperson(C))
- C.dna.blood_type = "X*"
- if(islizard(C))
- C.dna.blood_type = "L"
- else
- C.dna.blood_type = random_blood_type()
+ C.dna.blood_type = random_blood_type()
if(DIGITIGRADE in species_traits)
C.Digitigrade_Leg_Swap(TRUE)
for(var/X in inherent_traits)
diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm
index 55a6357e02..17b58fd461 100644
--- a/code/modules/mob/living/simple_animal/bot/mulebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm
@@ -474,8 +474,7 @@
if(isturf(next))
if(bloodiness)
var/obj/effect/decal/cleanable/blood/tracks/B = new(loc)
- if(blood_DNA && blood_DNA.len)
- B.blood_DNA |= blood_DNA.Copy()
+ B.add_blood(return_blood_DNA())
var/newdir = get_dir(next, loc)
if(newdir == dir)
B.setDir(newdir)
@@ -488,7 +487,6 @@
B.setDir(newdir)
bloodiness--
-
var/oldloc = loc
var/moved = step_towards(src, next) // attempt to move
if(cell)
@@ -657,8 +655,7 @@
T.add_mob_blood(H)
var/list/blood_dna = H.get_blood_dna_list()
- if(blood_dna)
- transfer_blood_dna(blood_dna)
+ add_blood(blood_dna)
bloodiness += 4
// player on mulebot attempted to move
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
index a27a3ab4ed..49bbe31ad3 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
@@ -37,7 +37,6 @@
gender = NEUTER
mob_biotypes = list(MOB_ROBOTIC)
speak_emote = list("chirps")
- speech_span = SPAN_ROBOT
bubble_icon = "machine"
initial_language_holder = /datum/language_holder/drone
mob_size = MOB_SIZE_SMALL
@@ -93,7 +92,7 @@
var/obj/item/I = new default_hatmask(src)
equip_to_slot_or_del(I, SLOT_HEAD)
- ADD_TRAIT(access_card, TRAIT_NODROP, ABSTRACT_ITEM_TRAIT)
+ access_card.item_flags |= TRAIT_NODROP
alert_drones(DRONE_NET_CONNECT)
@@ -170,23 +169,15 @@
//Hands
for(var/obj/item/I in held_items)
if(!(I.item_flags & ABSTRACT))
- if(I.blood_DNA)
- msg += "It has [icon2html(I, user)] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in its [get_held_index_name(get_held_index_of_item(I))]!\n"
- else
- msg += "It has [icon2html(I, user)] \a [I] in its [get_held_index_name(get_held_index_of_item(I))].\n"
+ msg += "It has [I.get_examine_string(user)] in its [get_held_index_name(get_held_index_of_item(I))].\n"
+
//Internal storage
if(internal_storage && !(internal_storage.item_flags & ABSTRACT))
- if(internal_storage.blood_DNA)
- msg += "It is holding [icon2html(internal_storage, user)] [internal_storage.gender==PLURAL?"some":"a"] blood-stained [internal_storage.name] in its internal storage!\n"
- else
- msg += "It is holding [icon2html(internal_storage, user)] \a [internal_storage] in its internal storage.\n"
+ msg += "It is holding [internal_storage.get_examine_string(user)] in its internal storage.\n"
//Cosmetic hat - provides no function other than looks
if(head && !(head.item_flags & ABSTRACT))
- if(head.blood_DNA)
- msg += "It is wearing [icon2html(head, user)] [head.gender==PLURAL?"some":"a"] blood-stained [head.name] on its head!\n"
- else
- msg += "It is wearing [icon2html(head, user)] \a [head] on its head.\n"
+ msg += "It is wearing [head.get_examine_string(user)] on its head.\n"
//Braindead
if(!client && stat != DEAD)
@@ -281,4 +272,4 @@
return 1
/mob/living/simple_animal/drone/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
- return 0 //So they don't die trying to fix wiring
+ return 0 //So they don't die trying to fix wiring
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm b/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm
index 9e962f6afb..28a7dd057a 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm
@@ -23,15 +23,9 @@
for(var/obj/item/I in held_items)
if(!(I.item_flags & ABSTRACT))
- if(I.blood_DNA)
- msg += "It has [icon2html(I, user)] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in its [get_held_index_name(get_held_index_of_item(I))]!\n"
- else
- msg += "It has [icon2html(I, user)] \a [I] in its [get_held_index_name(get_held_index_of_item(I))].\n"
+ msg += "It has [I.get_examine_string(user)] in its [get_held_index_name(get_held_index_of_item(I))].\n"
if(internal_storage && !(internal_storage.item_flags & ABSTRACT))
- if(internal_storage.blood_DNA)
- msg += "It is holding [icon2html(internal_storage, user)] [internal_storage.gender==PLURAL?"some":"a"] blood-stained [internal_storage.name] in its internal storage!\n"
- else
- msg += "It is holding [icon2html(internal_storage, user)] \a [internal_storage] in its internal storage.\n"
+ msg += "It is holding [internal_storage.get_examine_string(user)] in its internal storage.\n"
msg += "*---------*"
to_chat(user, msg)
else
@@ -90,4 +84,4 @@
/mob/living/simple_animal/hostile/guardian/dextrous/regenerate_icons()
..()
- update_inv_internal_storage()
+ update_inv_internal_storage()
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/hostile/alien.dm b/code/modules/mob/living/simple_animal/hostile/alien.dm
index 253d92a57f..d33fa6334f 100644
--- a/code/modules/mob/living/simple_animal/hostile/alien.dm
+++ b/code/modules/mob/living/simple_animal/hostile/alien.dm
@@ -177,6 +177,6 @@
qdel(target)
return TRUE
var/atom/movable/M = target
- M.clean_blood()
+ SEND_SIGNAL(M, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
visible_message("[src] polishes \the [target].")
- return TRUE
+ return TRUE
\ No newline at end of file
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 9e5c9c26c4..bfdcafb95b 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -491,7 +491,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
. = BLOOD_COLOR_HUMAN
switch(type)
if("U")//Universal blood; a bit orange
- . = "#db3300"
+ . = BLOOD_COLOR_UNIVERSAL
if("SY")//Synthetics blood; blue
. = BLOOD_COLOR_SYNTHETIC
if("L")//lizard, a bit pink/purple
@@ -502,6 +502,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
. = BLOOD_COLOR_OIL
if("GEL")// slimepeople blood, rgb 0, 255, 144
. = BLOOD_COLOR_SLIME
- if("BUG")
- . = "#a37c0f"
+ if("BUG")// yellowish, like, y'know bug guts I guess.
+ . = BLOOD_COLOR_BUG
//add more stuff to the switch if you have more blood colors for different types
+ // the defines are in _DEFINES/misc.dm
diff --git a/code/modules/projectiles/projectile/bullets/smg.dm b/code/modules/projectiles/projectile/bullets/smg.dm
index bba9e746be..33e090844e 100644
--- a/code/modules/projectiles/projectile/bullets/smg.dm
+++ b/code/modules/projectiles/projectile/bullets/smg.dm
@@ -19,27 +19,27 @@
var/turf/T = get_turf(target)
//section shamelessly copypasta'd from the clean component
- clean_blood()//blood overlays get weird otherwise, because the sprite changes.
+ SEND_SIGNAL(T, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
for(var/A in T)
if(is_cleanable(A))
qdel(A)
else if(istype(A, /obj/item))
var/obj/item/I = A
- I.clean_blood()
+ SEND_SIGNAL(I, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
if(ismob(I.loc))
var/mob/M = I.loc
M.regenerate_icons()
else if(ishuman(A))
var/mob/living/carbon/human/cleaned_human = A
if(cleaned_human.head)
- cleaned_human.head.clean_blood()
+ SEND_SIGNAL(cleaned_human.head, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
if(cleaned_human.wear_suit)
- cleaned_human.wear_suit.clean_blood()
+ SEND_SIGNAL(cleaned_human.wear_suit, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
else if(cleaned_human.w_uniform)
- cleaned_human.w_uniform.clean_blood()
+ SEND_SIGNAL(cleaned_human.w_uniform, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
if(cleaned_human.shoes)
- cleaned_human.shoes.clean_blood()
- cleaned_human.clean_blood()
+ SEND_SIGNAL(cleaned_human.shoes, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
+ SEND_SIGNAL(cleaned_human, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
cleaned_human.wash_cream()
cleaned_human.regenerate_icons()
@@ -57,4 +57,4 @@
/obj/item/projectile/bullet/incendiary/c46x30mm
name = "4.6x30mm incendiary bullet"
damage = 10
- fire_stacks = 1
+ fire_stacks = 1
\ No newline at end of file
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index 7bb5acff72..7163d9db13 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -216,7 +216,7 @@
color = BLOOD_COLOR_OIL
taste_description = "chunky burnt oil"
data = list("donor"=null,"viruses"=null,"blood_DNA"=null, "bloodcolor" = BLOOD_COLOR_OIL, "blood_type"="HF","resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null)
- pH = 9.75
+ pH = 9.75
/datum/reagent/vaccine
//data must contain virus type
@@ -738,11 +738,11 @@
mutationtext = "The pain subsides. You feel... attracted to dark, moist areas."
/datum/reagent/mutationtoxin/xenoperson
- name = "Xeno Mutation Toxin"
+ name = "Xeno-Hybrid Mutation Toxin"
id = "xenopersonmutationtoxin"
description = "A glowing toxin."
color = "#5EFF3B" //RGB: 94, 255, 59
- race = /datum/species/xenoperson
+ race = /datum/species/xeno
mutationtext = "The pain subsides. You feel... oddly longing for the Queen." //sadly, not the British one.
//BLACKLISTED RACES
@@ -1241,12 +1241,12 @@
else
if(O)
O.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
- O.clean_blood()
+ SEND_SIGNAL(O, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
/datum/reagent/space_cleaner/reaction_turf(turf/T, reac_volume)
if(reac_volume >= 1)
T.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
- T.clean_blood()
+ SEND_SIGNAL(T, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
for(var/obj/effect/decal/cleanable/C in T)
qdel(C)
@@ -1264,26 +1264,26 @@
H.lip_style = null
H.update_body()
for(var/obj/item/I in C.held_items)
- I.clean_blood()
+ SEND_SIGNAL(I, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
if(C.wear_mask)
- if(C.clean_blood())
+ if(SEND_SIGNAL(C.wear_mask, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD))
C.update_inv_wear_mask()
if(ishuman(M))
var/mob/living/carbon/human/H = C
if(H.head)
- if(H.head.clean_blood())
+ if(SEND_SIGNAL(H.head, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD))
H.update_inv_head()
if(H.wear_suit)
- if(H.wear_suit.clean_blood())
+ if(SEND_SIGNAL(H.wear_suit, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD))
H.update_inv_wear_suit()
else if(H.w_uniform)
- if(H.w_uniform.clean_blood())
+ if(SEND_SIGNAL(H.w_uniform, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD))
H.update_inv_w_uniform()
if(H.shoes)
- if(H.shoes.clean_blood())
+ if(SEND_SIGNAL(H.shoes, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD))
H.update_inv_shoes()
H.wash_cream()
- M.clean_blood()
+ SEND_SIGNAL(M, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
/datum/reagent/space_cleaner/ez_clean
name = "EZ Clean"
diff --git a/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm b/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm
index 65301454fa..68ab229f0a 100644
--- a/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm
+++ b/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm
@@ -298,7 +298,7 @@
var/mob/M = loc
M.update_inv_hands()
- clean_blood()//blood overlays get weird otherwise, because the sprite changes.
+ SEND_SIGNAL(src, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)//blood overlays get weird otherwise, because the sprite changes. (retained from original desword because I have no idea what this is)
/obj/item/twohanded/dualsaber/hypereutactic/AltClick(mob/living/user)
if(!user.canUseTopic(src, BE_CLOSE, FALSE) || hacked)
diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/other_reagents.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/other_reagents.dm
index d218f76310..c8ebde11d9 100644
--- a/modular_citadel/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/modular_citadel/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -1,11 +1,3 @@
-/datum/reagent/space_cleaner/reaction_obj(obj/O, reac_volume)
- if(istype(O, /obj/effect/decal/cleanable) || istype(O, /obj/item/projectile/bullet/reusable/foam_dart) || istype(O, /obj/item/ammo_casing/caseless/foam_dart))
- qdel(O)
- else
- if(O)
- O.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
- O.clean_blood()
-
/datum/reagent/syndicateadrenals
name = "Syndicate Adrenaline"
id = "syndicateadrenals"
diff --git a/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm b/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm
index 680f7a3408..437a794f98 100644
--- a/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm
+++ b/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm
@@ -39,9 +39,8 @@
add_blood(list("Non-human DNA" = "A+"))
/obj/effect/decal/cleanable/semen/replace_decal(obj/effect/decal/cleanable/semen/S)
- if (S.blood_DNA)
- blood_DNA |= S.blood_DNA.Copy()
- ..()
+ S.add_blood(return_blood_DNA())
+ return ..()
/datum/reagent/consumable/femcum
name = "Female Ejaculate"
@@ -73,9 +72,8 @@
add_blood(list("Non-human DNA" = "A+"))
/obj/effect/decal/cleanable/femcum/replace_decal(obj/effect/decal/cleanable/femcum/F)
- if(F.blood_DNA)
- blood_DNA |= F.blood_DNA.Copy()
- ..()
+ F.add_blood(return_blood_DNA())
+ return ..()
/datum/reagent/consumable/femcum/reaction_turf(turf/T, reac_volume)
if(!istype(T))
diff --git a/tgstation.dme b/tgstation.dme
index a7031883dc..9a03e5838d 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -46,6 +46,7 @@
#include "code\__DEFINES\flags.dm"
#include "code\__DEFINES\food.dm"
#include "code\__DEFINES\footsteps.dm"
+#include "code\__DEFINES\forensics.dm"
#include "code\__DEFINES\hud.dm"
#include "code\__DEFINES\integrated_electronics.dm"
#include "code\__DEFINES\interaction_flags.dm"
@@ -351,6 +352,7 @@
#include "code\datums\components\empprotection.dm"
#include "code\datums\components\footstep.dm"
#include "code\datums\components\forced_gravity.dm"
+#include "code\datums\components\forensics.dm"
#include "code\datums\components\infective.dm"
#include "code\datums\components\jousting.dm"
#include "code\datums\components\knockoff.dm"
@@ -378,6 +380,7 @@
#include "code\datums\components\uplink.dm"
#include "code\datums\components\wearertargeting.dm"
#include "code\datums\components\wet_floor.dm"
+#include "code\datums\components\decals\blood.dm"
#include "code\datums\components\storage\storage.dm"
#include "code\datums\components\storage\concrete\_concrete.dm"
#include "code\datums\components\storage\concrete\bag_of_holding.dm"