From 971ddef989f7f4f365a714ef3d4df5dea2d53d9a Mon Sep 17 00:00:00 2001 From: Poojawa Date: Wed, 22 May 2019 04:10:29 -0500 Subject: [PATCH] reverts forensics components. If I can't figure it out, MURDER IT --- code/__DEFINES/cleaning.dm | 5 - code/__DEFINES/forensics.dm | 2 - code/datums/components/cleaning.dm | 22 +- code/datums/components/decals/blood.dm | 40 ---- code/datums/components/forensics.dm | 213 ------------------ code/game/atoms.dm | 143 ++++++++++-- code/game/machinery/suit_storage_unit.dm | 3 +- code/game/machinery/washing_machine.dm | 9 +- code/game/objects/effects/decals/cleanable.dm | 6 +- .../effects/decals/cleanable/aliens.dm | 15 +- .../objects/effects/decals/cleanable/gibs.dm | 3 +- .../effects/decals/cleanable/humans.dm | 45 ++-- .../objects/effects/spawners/gibspawner.dm | 4 +- .../temporary_visuals/miscellaneous.dm | 2 +- code/game/objects/items.dm | 11 + code/game/objects/items/clown_items.dm | 2 +- .../objects/items/devices/radio/intercom.dm | 2 +- code/game/objects/items/melee/energy.dm | 2 +- code/game/objects/items/melee/misc.dm | 2 +- code/game/objects/items/mop.dm | 2 +- code/game/objects/items/stacks/stack.dm | 8 +- code/game/objects/items/storage/book.dm | 2 +- code/game/objects/items/twohanded.dm | 2 +- code/game/objects/structures/watercloset.dm | 16 +- code/game/turfs/open.dm | 2 +- .../devil/true_devil/_true_devil.dm | 6 +- .../antagonists/wizard/equipment/artefact.dm | 5 +- code/modules/clothing/clothing.dm | 7 + code/modules/clothing/gloves/_gloves.dm | 14 +- code/modules/clothing/head/_head.dm | 5 +- code/modules/clothing/masks/_masks.dm | 5 +- code/modules/clothing/neck/_neck.dm | 4 +- code/modules/clothing/shoes/_shoes.dm | 15 +- code/modules/clothing/suits/_suits.dm | 7 +- code/modules/clothing/under/_under.dm | 5 +- code/modules/detectivework/detective_work.dm | 202 ++++++++--------- .../detectivework/footprints_and_rag.dm | 7 +- code/modules/detectivework/scanner.dm | 22 +- code/modules/mob/living/blood.dm | 7 +- code/modules/mob/living/carbon/examine.dm | 15 +- .../mob/living/carbon/human/examine.dm | 72 ++++-- code/modules/mob/living/carbon/human/human.dm | 26 ++- .../mob/living/carbon/human/human_defines.dm | 2 + .../mob/living/carbon/human/human_helpers.dm | 6 + .../mob/living/carbon/human/human_movement.dm | 63 +++--- .../mob/living/simple_animal/bot/mulebot.dm | 6 +- .../simple_animal/friendly/drone/_drone.dm | 16 +- .../simple_animal/guardian/types/dextrous.dm | 10 +- .../mob/living/simple_animal/hostile/alien.dm | 2 +- code/modules/projectiles/guns/ballistic.dm | 2 +- code/modules/projectiles/projectile.dm | 13 +- .../projectiles/projectile/bullets/smg.dm | 14 +- .../chemistry/reagents/other_reagents.dm | 24 +- .../reagents/reagent_containers/blood_pack.dm | 8 +- icons/mob/dam_mob.dmi | Bin 16165 -> 16184 bytes .../objects/items/melee/eutactic_blades.dm | 2 +- .../chemistry/reagents/other_reagents.dm | 2 +- .../modules/reagents/reagents/cit_reagents.dm | 17 +- 58 files changed, 551 insertions(+), 623 deletions(-) delete mode 100644 code/__DEFINES/forensics.dm delete mode 100644 code/datums/components/decals/blood.dm delete mode 100644 code/datums/components/forensics.dm diff --git a/code/__DEFINES/cleaning.dm b/code/__DEFINES/cleaning.dm index c4db590e90..6049fd7918 100644 --- a/code/__DEFINES/cleaning.dm +++ b/code/__DEFINES/cleaning.dm @@ -5,8 +5,3 @@ #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 deleted file mode 100644 index bb512edcde..0000000000 --- a/code/__DEFINES/forensics.dm +++ /dev/null @@ -1,2 +0,0 @@ -#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)) diff --git a/code/datums/components/cleaning.dm b/code/datums/components/cleaning.dm index 05c26efcc1..08ac57b79a 100644 --- a/code/datums/components/cleaning.dm +++ b/code/datums/components/cleaning.dm @@ -12,28 +12,28 @@ if(!isturf(tile)) return - SEND_SIGNAL(tile, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + tile.clean_blood() for(var/A in tile) if(is_cleanable(A)) qdel(A) - 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 + 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 M.regenerate_icons() else if(ishuman(A)) var/mob/living/carbon/human/cleaned_human = A if(cleaned_human.lying) if(cleaned_human.head) - SEND_SIGNAL(cleaned_human.head, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + cleaned_human.head.clean_blood() if(cleaned_human.wear_suit) - SEND_SIGNAL(cleaned_human.wear_suit, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + cleaned_human.wear_suit.clean_blood() else if(cleaned_human.w_uniform) - SEND_SIGNAL(cleaned_human.w_uniform, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + cleaned_human.w_uniform.clean_blood() if(cleaned_human.shoes) - 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.shoes.clean_blood() + cleaned_human.clean_blood() cleaned_human.wash_cream() cleaned_human.regenerate_icons() to_chat(cleaned_human, "[AM] cleans your face!") diff --git a/code/datums/components/decals/blood.dm b/code/datums/components/decals/blood.dm deleted file mode 100644 index 3daa4b5944..0000000000 --- a/code/datums/components/decals/blood.dm +++ /dev/null @@ -1,40 +0,0 @@ -/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/static/list/blood_splatter_appearances = list() - //try to find a pre-processed blood-splatter. otherwise, make a new one - var/index = "[REF(icon)]-[icon_state]" - pic = blood_splatter_appearances[index] - - if(!pic) - 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)) - pic.color = I.blood_color //add the blood's color with DNA information - blood_splatter_appearances[index] = pic - 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 \ No newline at end of file diff --git a/code/datums/components/forensics.dm b/code/datums/components/forensics.dm deleted file mode 100644 index 4ee8b93cc7..0000000000 --- a/code/datums/components/forensics.dm +++ /dev/null @@ -1,213 +0,0 @@ -/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 - var/list/blood_mix_types // data("[blood_type]" = sting list - var/blood_mix_color - -/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 - blood_mix_types = blood_mix_types | F.blood_mix_types - blood_mix_color = blood_mix_color | F.blood_mix_color - check_blood() - return ..() - -/datum/component/forensics/Initialize(new_fingerprints, new_hiddenprints, new_blood_DNA, new_fibers, new_blood_mix_types, new_blood_mix_color) - if(!isatom(parent)) - return COMPONENT_INCOMPATIBLE - fingerprints = new_fingerprints - hiddenprints = new_hiddenprints - blood_DNA = new_blood_DNA - fibers = new_fibers - blood_mix_types = new_blood_mix_types - blood_mix_color = new_blood_mix_color - check_blood() - -/datum/component/forensics/RegisterWithParent() - check_blood() - RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, .proc/clean_act) -// RegisterSignal(parent, COMSIG_BLOOD_COLOR, .proc/ - -/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 - blood_mix_types = null - blood_mix_color = null - 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(!M) - return - 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/living/M) - if(!M || !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) - LAZYINITLIST(blood_mix_types) - for(var/i in dna) - blood_DNA[i] = dna[i] - for(var/type in blood_DNA) - if(type in blood_DNA[type]) - blood_mix_types += blood_DNA[type] - - blood_list_check(blood_mix_types) - check_blood() - return TRUE - -/datum/component/forensics/proc/check_blood() - if(!isitem(parent) || !ismob(parent)) - return - if(!length(blood_DNA)) - return - -/datum/component/forensics/proc/blood_list_check(list/blood_types, blood_type) //This is a messy attempt at trying to reduce lists of items and mobs with blood colors on them - if(blood_type in GLOB.regular_bloods) - blood_type = "A+" //generic so we don't have 8 different types of human blood - if(blood_type in blood_mix_types) - return - else - LAZYADD(blood_mix_types, blood_type) - - if(blood_mix_types.len) - blood_DNA_to_color(blood_mix_types) - else - return - -/datum/component/forensics/proc/blood_DNA_to_color(list/bloods) - var/final_rgb = "#940000" //We default to red just in case - if(bloods.len) - var/sum = 0 //this is all shitcode, but it works; trust me - final_rgb = bloodtype_to_color(bloods[1]) - sum = bloods[bloods[1]] - if(bloods.len > 1) - var/i = 2 - while(i <= bloods.len) - var/tmp = bloods[bloods[i]] - final_rgb = BlendRGB(final_rgb, bloodtype_to_color(bloods[i]), tmp/(tmp+sum)) - sum += tmp - i++ - else - final_rgb = BlendRGB(final_rgb, bloodtype_to_color(bloods)) - - blood_mix_color = final_rgb diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 0ba8d7411b..50f6cdf968 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -36,6 +36,9 @@ 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 @@ -244,23 +247,22 @@ return TRUE return FALSE -/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("") - -/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)) + //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]!" + + to_chat(user, "[icon2html(src, user)] That's [f_name]") 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(container_type & TRANSPARENT) @@ -282,8 +284,6 @@ 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 @@ -345,18 +345,123 @@ var/new_blood_dna = L.get_blood_dna_list() if(!new_blood_dna) return FALSE - var/old_length = blood_DNA_length() - add_blood_DNA(new_blood_dna) - if(blood_DNA_length() == old_length) + 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) 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() if(!blood_dna) return FALSE - return add_blood_DNA(blood_dna) + 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_splatter_icon.Blend(blood_DNA_to_color(), ICON_MULTIPLY) + add_overlay(blood_splatter_icon) + +/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 b84db2ca8d..930edfe467 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -246,7 +246,8 @@ 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 - SEND_SIGNAL(I, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRONG) + I.clean_blood() + I.fingerprints = list() var/datum/component/radioactive/contamination = I.GetComponent(/datum/component/radioactive) if(contamination) qdel(contamination) diff --git a/code/game/machinery/washing_machine.dm b/code/game/machinery/washing_machine.dm index 0a9a135986..1a8dd231f4 100644 --- a/code/game/machinery/washing_machine.dm +++ b/code/game/machinery/washing_machine.dm @@ -11,10 +11,6 @@ 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.") @@ -59,7 +55,8 @@ M.Translate(rand(-3, 3), rand(-1, 3)) animate(src, transform=M, time=2) -/obj/machinery/washing_machine/proc/clean_blood() +/obj/machinery/washing_machine/clean_blood() + ..() if(!busy) bloody_mess = FALSE update_icon() @@ -67,7 +64,7 @@ /obj/machinery/washing_machine/proc/wash_cycle() for(var/X in contents) var/atom/movable/AM = X - SEND_SIGNAL(AM, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + AM.clean_blood() AM.machine_wash(src) busy = FALSE diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm index f5e929a7ae..61dff565af 100644 --- a/code/game/objects/effects/decals/cleanable.dm +++ b/code/game/objects/effects/decals/cleanable.dm @@ -82,7 +82,8 @@ add_blood = bloodiness bloodiness -= add_blood S.blood_smear[blood_state] = min(MAX_SHOE_BLOODINESS,S.blood_smear[blood_state]+add_blood) - S.add_blood_DNA(return_blood_DNA()) + if(blood_DNA && blood_DNA.len) + S.add_blood(blood_DNA) S.blood_state = blood_state S.blood_color = blood_color update_icon() @@ -97,7 +98,8 @@ bloodiness -= add_blood H.blood_smear[blood_state] = min(MAX_SHOE_BLOODINESS,H.blood_smear[blood_state]+add_blood) H.bloodiness = add_blood - H.add_blood_DNA(return_blood_DNA()) + if(blood_DNA && blood_DNA.len) + H.add_blood(blood_DNA) H.blood_state = blood_state H.blood_color = blood_color update_icon() diff --git a/code/game/objects/effects/decals/cleanable/aliens.dm b/code/game/objects/effects/decals/cleanable/aliens.dm index 9b4d65cff4..33d1e41bef 100644 --- a/code/game/objects/effects/decals/cleanable/aliens.dm +++ b/code/game/objects/effects/decals/cleanable/aliens.dm @@ -4,10 +4,7 @@ name = "xeno blood" desc = "It's green and acidic. It looks like... blood?" color = BLOOD_COLOR_XENO - -/obj/effect/decal/cleanable/blood/xeno/Initialize() - . = ..() - add_blood_DNA(list("UNKNOWN DNA" = "X*")) + blood_DNA = list("UNKNOWN DNA" = "X*") /obj/effect/decal/cleanable/blood/splatter/xeno color = BLOOD_COLOR_XENO @@ -64,6 +61,10 @@ /obj/effect/decal/cleanable/blood/gibs/xeno/larva/body random_icon_states = list("xgiblarvahead", "xgiblarvatorso") -/obj/effect/decal/cleanable/blood/xeno/tracks/Initialize() - . = ..() - add_blood_DNA(list("UNKNOWN DNA" = "X*")) \ No newline at end of file +/obj/effect/decal/cleanable/blood/xtracks + icon_state = "tracks" + random_icon_states = null + +/obj/effect/decal/cleanable/blood/xtracks/Initialize() + add_blood(list("UNKNOWN DNA" = "X*")) + . = ..() \ No newline at end of file diff --git a/code/game/objects/effects/decals/cleanable/gibs.dm b/code/game/objects/effects/decals/cleanable/gibs.dm index 31849c7251..7a36ce8f7a 100644 --- a/code/game/objects/effects/decals/cleanable/gibs.dm +++ b/code/game/objects/effects/decals/cleanable/gibs.dm @@ -48,6 +48,7 @@ diseases = infective.diseases var/obj/effect/decal/cleanable/blood/gibs/gibbers = src var/obj/effect/decal/cleanable/blood/splatter/splat = new /obj/effect/decal/cleanable/blood/splatter(loc, diseases) + splat.transfer_blood_dna(blood_DNA) splat.color = gibbers.blood_color splat.blood_color = gibbers.blood_color @@ -87,7 +88,7 @@ . = ..() setDir(pick(1,2,4,8)) icon_state += "-old" - add_blood_DNA(list("Non-human DNA" = "A+")) + add_blood(list("Non-human DNA" = "A+")) /obj/effect/decal/cleanable/blood/drip name = "drips of blood" diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm index 0a4a266874..0bfec90afd 100644 --- a/code/game/objects/effects/decals/cleanable/humans.dm +++ b/code/game/objects/effects/decals/cleanable/humans.dm @@ -4,40 +4,28 @@ 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 color = BLOOD_COLOR_HUMAN //default so we don't have white splotches everywhere. bloodiness = BLOOD_AMOUNT_PER_DECAL /obj/effect/decal/cleanable/blood/replace_decal(obj/effect/decal/cleanable/blood/C) - if(bloodiness) - if(C.bloodiness < MAX_SHOE_BLOODINESS) - C.bloodiness += bloodiness + if (C.blood_DNA) + blood_DNA |= C.blood_DNA.Copy() update_icon() - return ..() + ..() -/obj/effect/decal/cleanable/blood/add_blood_DNA(list/blood_dna) - return TRUE +/obj/effect/decal/cleanable/blood/transfer_blood_dna() + ..() + update_icon() /obj/effect/decal/cleanable/blood/transfer_mob_blood_dna() . = ..() update_icon() /obj/effect/decal/cleanable/blood/update_icon() - if(!blood_color) - if(reagents.reagent_list.len) - for(var/datum/reagent/R in reagents.reagent_list) - // Get blood data from the blood reagent. - if(istype(R, /datum/reagent/blood)) - if(R.data["blood_type"]) - blood_color = bloodtype_to_color(R.data["blood_type"]) - else if(istype(R, /datum/reagent/liquidgibs)) - if(R.data["blood_type"]) - blood_color = bloodtype_to_color(R.data["blood_type"]) - else - return - else - color = blood_color + color = blood_DNA_to_color() //obj/effect/decal/cleanable/blood/update_color() // if(SEND_SIGNAL(COMSIG_BLOOD_COLOR) & COMPONENT_BLOCK_UPDATE_COLOR) @@ -50,8 +38,9 @@ color = "#3a0505" /obj/effect/decal/cleanable/blood/old/Initialize(mapload, list/datum/disease/diseases) - . = ..() - add_blood_DNA(list("blood_type"= "A+")) + ..() + icon_state += "-old" + add_blood(list("Non-human DNA" = "A+")) /obj/effect/decal/cleanable/blood/splatter random_icon_states = list("gibbl1", "gibbl2", "gibbl3", "gibbl4", "gibbl5") @@ -66,10 +55,7 @@ bloodiness = BLOOD_AMOUNT_PER_DECAL /obj/effect/decal/cleanable/trail_holder/update_icon() - GET_COMPONENT(D, /datum/component/forensics) - if(istype(D) && !blood_color) - blood_color = D.blood_mix_color - color = blood_color + color = blood_DNA_to_color() /obj/effect/cleanable/trail_holder/Initialize() . = ..() @@ -78,6 +64,10 @@ /obj/effect/decal/cleanable/trail_holder/can_bloodcrawl_in() return TRUE +/obj/effect/decal/cleanable/trail_holder/transfer_blood_dna() + ..() + update_icon() + /obj/effect/decal/cleanable/trail_holder/transfer_mob_blood_dna() . = ..() update_icon() @@ -122,6 +112,8 @@ var/mob/living/carbon/human/H = O var/obj/item/clothing/shoes/S = H.shoes if(S && S.blood_smear[blood_state]) + if(color != bloodtype_to_color(S.last_bloodtype))//last entry - we check its color + return S.blood_smear[blood_state] = max(S.blood_smear[blood_state] - BLOOD_LOSS_PER_STEP, 0) S.blood_color = blood_color shoe_types |= S.type @@ -138,6 +130,7 @@ update_icon() /obj/effect/decal/cleanable/blood/footprints/tracks/update_icon() + ..() cut_overlays() for(var/Ddir in GLOB.cardinals) diff --git a/code/game/objects/effects/spawners/gibspawner.dm b/code/game/objects/effects/spawners/gibspawner.dm index 7e960b5d78..0cb17f11be 100644 --- a/code/game/objects/effects/spawners/gibspawner.dm +++ b/code/game/objects/effects/spawners/gibspawner.dm @@ -12,8 +12,6 @@ /obj/effect/gibspawner/Initialize(mapload, mob/living/source_mob, list/datum/disease/diseases) . = ..() - AddComponent(/datum/component/forensics) - if(gibtypes.len != gibamounts.len) stack_trace("Gib list amount length mismatch!") return @@ -74,7 +72,7 @@ var/mob/living/carbon/digester = loc digester.stomach_contents += gib - gib.add_blood_DNA(dna_to_add) + gib.blood_DNA += dna_to_add // color them properly, please. gib.body_colors = body_coloring gib.update_icon() diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm index 27ec0a4026..fbad000098 100644 --- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm +++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm @@ -43,7 +43,7 @@ animate(src, pixel_x = target_pixel_x, pixel_y = target_pixel_y, alpha = 0, time = duration) /obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter - splatter_type = "xsplatter" + color = BLOOD_COLOR_XENO /obj/effect/temp_visual/dir_setting/speedbike_trail name = "speedbike trails" diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 88eb8e9ad4..e942396c16 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -538,6 +538,17 @@ 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 1d302b409e..e371ae7d40 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) - SEND_SIGNAL(target, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_MEDIUM) + target.clean_blood() target.wash_cream() return diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm index eb0271c1b9..56511b481a 100644 --- a/code/game/objects/items/devices/radio/intercom.dm +++ b/code/game/objects/items/devices/radio/intercom.dm @@ -136,7 +136,7 @@ else icon_state = initial(icon_state) -/obj/item/radio/intercom/add_blood_DNA(list/blood_dna) +/obj/item/radio/intercom/add_blood(list/blood_dna) return FALSE //Created through the autolathe or through deconstructing intercoms. Can be applied to wall to make a new intercom on it! diff --git a/code/game/objects/items/melee/energy.dm b/code/game/objects/items/melee/energy.dm index 935d2a007e..a5929e95cb 100644 --- a/code/game/objects/items/melee/energy.dm +++ b/code/game/objects/items/melee/energy.dm @@ -22,7 +22,7 @@ user.visible_message("[user] is [pick("slitting [user.p_their()] stomach open with", "falling on")] [src]! It looks like [user.p_theyre()] trying to commit seppuku!") return (BRUTELOSS|FIRELOSS) -/obj/item/melee/transforming/energy/add_blood_DNA(list/blood_dna) +/obj/item/melee/transforming/energy/add_blood(list/blood_dna) return FALSE /obj/item/melee/transforming/energy/is_sharp() diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index 3a35f4d8ef..b201ef60a8 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -343,7 +343,7 @@ shard.Consume() T.CalculateAdjacentTurfs() -/obj/item/melee/supermatter_sword/add_blood_DNA(list/blood_dna) +/obj/item/melee/supermatter_sword/add_blood(list/blood_dna) return FALSE /obj/item/melee/curator_whip diff --git a/code/game/objects/items/mop.dm b/code/game/objects/items/mop.dm index 44ccd7aad5..32428bf298 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)) - SEND_SIGNAL(A, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_MEDIUM) + A.clean_blood() 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 34ae4cb5ef..470261bd6d 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) - add_blood_DNA(from.return_blood_DNA()) - add_fingerprint_list(from.return_fingerprints()) - add_hiddenprint_list(from.return_hiddenprints()) +/obj/item/stack/proc/copy_evidences(obj/item/stack/from as obj) + blood_DNA = from.blood_DNA + fingerprints = from.fingerprints + fingerprintshidden = from.fingerprintshidden fingerprintslast = from.fingerprintslast //TODO bloody overlay diff --git a/code/game/objects/items/storage/book.dm b/code/game/objects/items/storage/book.dm index b95d6a897e..6b093841de 100644 --- a/code/game/objects/items/storage/book.dm +++ b/code/game/objects/items/storage/book.dm @@ -241,5 +241,5 @@ GLOBAL_LIST_INIT(bibleitemstates, list("bible", "koran", "scrapbook", "bible", else return ..(M,user,heal_mode = FALSE) -/obj/item/storage/book/bible/syndicate/add_blood_DNA(list/blood_dna) +/obj/item/storage/book/bible/syndicate/add_blood(list/blood_dna) return FALSE diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm index d4ec9217e7..784aed077e 100644 --- a/code/game/objects/items/twohanded.dm +++ b/code/game/objects/items/twohanded.dm @@ -341,7 +341,7 @@ icon_state = "dualsaber[item_color][wielded]" else icon_state = "dualsaber0" - SEND_SIGNAL(src, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + clean_blood()//blood overlays get weird otherwise, because the sprite changes. /obj/item/twohanded/dualsaber/attack(mob/target, mob/living/carbon/human/user) if(user.has_dna()) diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index d70838a30b..a03c0c2b46 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) - . = SEND_SIGNAL(O, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK) + . = O.clean_blood() 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 - SEND_SIGNAL(tile, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK) + tile.clean_blood() 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) - SEND_SIGNAL(L, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK) + L.clean_blood() 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) - SEND_SIGNAL(H, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + H.clean_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) - SEND_SIGNAL(M, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + M.clean_blood() else - SEND_SIGNAL(L, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + L.clean_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 - SEND_SIGNAL(user, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + user.clean_blood() /obj/structure/sink/attackby(obj/item/O, mob/living/user, params) if(busy) @@ -554,7 +554,7 @@ busy = FALSE return 1 busy = FALSE - SEND_SIGNAL(O, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + O.clean_blood() O.acid_level = 0 create_reagents(5) reagents.add_reagent(dispensedreagent, 5) diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm index 63b5f4b160..96a24e0b2c 100644 --- a/code/game/turfs/open.dm +++ b/code/game/turfs/open.dm @@ -225,7 +225,7 @@ for(var/mob/living/simple_animal/slime/M in src) M.apply_water() - SEND_SIGNAL(src, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK) + clean_blood() 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 923a224b81..949fb2e4ed 100644 --- a/code/modules/antagonists/devil/true_devil/_true_devil.dm +++ b/code/modules/antagonists/devil/true_devil/_true_devil.dm @@ -69,8 +69,10 @@ //Left hand items for(var/obj/item/I in held_items) if(!(I.item_flags & ABSTRACT)) - msg += "It is holding [I.get_examine_string(user)] in its [get_held_index_name(get_held_index_of_item(I))].\n" - + 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" //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 7cfefd5413..f985818b76 100644 --- a/code/modules/antagonists/wizard/equipment/artefact.dm +++ b/code/modules/antagonists/wizard/equipment/artefact.dm @@ -327,11 +327,8 @@ 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(prints[md5(H.dna.uni_identity)]) + if(md5(H.dna.uni_identity) in voodoo_link.fingerprints) possible |= H /obj/item/voodoo/proc/GiveHint(mob/victim,force=0) diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 922f37b270..caf12d4b86 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -43,6 +43,8 @@ var/blood_state = BLOOD_STATE_NOT_BLOODY var/list/blood_smear = 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 /obj/item/clothing/Initialize() . = ..() @@ -157,6 +159,11 @@ damaged_clothes = 0 cut_overlay(damaged_clothes_icons[index], TRUE) +/obj/item/clothing/transfer_blood_dna(list/blood_dna) + ..() + if(blood_dna.len) + last_bloodtype = blood_dna[blood_dna[blood_dna.len]]//trust me this works + last_blood_DNA = blood_dna[blood_dna.len] /* SEE_SELF // can see self, no matter what diff --git a/code/modules/clothing/gloves/_gloves.dm b/code/modules/clothing/gloves/_gloves.dm index 50bfeb1407..a661a978b0 100644 --- a/code/modules/clothing/gloves/_gloves.dm +++ b/code/modules/clothing/gloves/_gloves.dm @@ -11,15 +11,6 @@ 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 @@ -29,9 +20,8 @@ if(!isinhands) if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damagedgloves") - IF_HAS_BLOOD_DNA(src) - GET_COMPONENT(D, /datum/component/forensics) - . += mutable_appearance('icons/effects/blood.dmi', "bloodyhands", color = D.blood_mix_color) + if(blood_DNA) + . += 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 591b6c1d3b..ccc167dcbc 100644 --- a/code/modules/clothing/head/_head.dm +++ b/code/modules/clothing/head/_head.dm @@ -46,9 +46,8 @@ if(!isinhands) if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damagedhelmet") - IF_HAS_BLOOD_DNA(src) - GET_COMPONENT(D, /datum/component/forensics) - . += mutable_appearance('icons/effects/blood.dmi', "helmetblood", color = D.blood_DNA_to_color()) + if(blood_DNA) + . += 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 13f3a81b99..ae4d324805 100644 --- a/code/modules/clothing/masks/_masks.dm +++ b/code/modules/clothing/masks/_masks.dm @@ -17,9 +17,8 @@ if(body_parts_covered & HEAD) if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damagedmask") - IF_HAS_BLOOD_DNA(src) - GET_COMPONENT(D, /datum/component/forensics) - . += mutable_appearance('icons/effects/blood.dmi', "maskblood", color = D.blood_mix_color) + if(blood_DNA) + . += mutable_appearance('icons/effects/blood.dmi', "maskblood", color = blood_DNA_to_color()) /obj/item/clothing/mask/equipped(mob/user, slot) ..() diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm index 4179e69a45..ee63c137af 100644 --- a/code/modules/clothing/neck/_neck.dm +++ b/code/modules/clothing/neck/_neck.dm @@ -12,8 +12,8 @@ if(body_parts_covered & HEAD) if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damagedmask") - IF_HAS_BLOOD_DNA(src) - . += mutable_appearance('icons/effects/blood.dmi', "maskblood") + if(blood_DNA) + . += mutable_appearance('icons/effects/blood.dmi', "maskblood", color = blood_DNA_to_color()) /obj/item/clothing/neck/tie name = "tie" diff --git a/code/modules/clothing/shoes/_shoes.dm b/code/modules/clothing/shoes/_shoes.dm index 4aec17fafe..fb85d057b2 100644 --- a/code/modules/clothing/shoes/_shoes.dm +++ b/code/modules/clothing/shoes/_shoes.dm @@ -19,10 +19,6 @@ var/move_trail = /obj/effect/decal/cleanable/blood/footprints/tracks/shoe -/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!") @@ -46,7 +42,7 @@ . = list() if(!isinhands) var/bloody = FALSE - IF_HAS_BLOOD_DNA(src) + if(blood_DNA) bloody = TRUE else bloody = blood_smear[BLOOD_STATE_BLOOD] @@ -55,9 +51,9 @@ . += mutable_appearance('icons/effects/item_damage.dmi', "damagedshoe") if(bloody) if(adjusted == NORMAL_STYLE) - . += mutable_appearance('icons/effects/blood.dmi', "shoeblood", color = blood_color) + . += mutable_appearance('icons/effects/blood.dmi', "shoeblood", color = blood_DNA_to_color()) else - . += mutable_appearance('modular_citadel/icons/mob/digishoes.dmi', "shoeblood", color = blood_color) + . += mutable_appearance('modular_citadel/icons/mob/digishoes.dmi', "shoeblood", color = blood_DNA_to_color()) /obj/item/clothing/shoes/equipped(mob/user, slot) . = ..() @@ -93,9 +89,8 @@ var/mob/M = loc M.update_inv_shoes() -/obj/item/clothing/shoes/proc/clean_blood(datum/source, strength) - if(strength < CLEAN_STRENGTH_BLOOD) - return +/obj/item/clothing/shoes/clean_blood() + ..() blood_smear = list(BLOOD_STATE_BLOOD = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0) blood_state = BLOOD_STATE_NOT_BLOODY blood_color = null diff --git a/code/modules/clothing/suits/_suits.dm b/code/modules/clothing/suits/_suits.dm index 3a3e5c3d84..74637cd22f 100644 --- a/code/modules/clothing/suits/_suits.dm +++ b/code/modules/clothing/suits/_suits.dm @@ -54,12 +54,11 @@ if(!isinhands) if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damaged[blood_overlay_type]") - IF_HAS_BLOOD_DNA(src) - GET_COMPONENT(D, /datum/component/forensics) + if(blood_DNA) if(taurmode >= SNEK_TAURIC) - . += mutable_appearance('modular_citadel/icons/mob/64x32_effects.dmi', "[blood_overlay_type]blood", color = D.blood_mix_color) + . += mutable_appearance('modular_citadel/icons/mob/64x32_effects.dmi', "[blood_overlay_type]blood", color = blood_DNA_to_color()) else - . += mutable_appearance('icons/effects/blood.dmi', "[blood_overlay_type]blood", color = D.blood_mix_color) + . += mutable_appearance('icons/effects/blood.dmi', "[blood_overlay_type]blood", color = blood_DNA_to_color()) 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 df5004a259..eda0e31e93 100644 --- a/code/modules/clothing/under/_under.dm +++ b/code/modules/clothing/under/_under.dm @@ -22,9 +22,8 @@ if(!isinhands) if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damageduniform") - IF_HAS_BLOOD_DNA(src) - GET_COMPONENT(D, /datum/component/forensics) - . += mutable_appearance('icons/effects/blood.dmi', "uniformblood", color = D.blood_mix_color) + if(blood_DNA) + . += 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 0b1d6807bf..d5584bc29f 100644 --- a/code/modules/detectivework/detective_work.dm +++ b/code/modules/detectivework/detective_work.dm @@ -1,121 +1,119 @@ //CONTAINS: Suit fibers and Detective's Scanning Computer -/atom/proc/return_fingerprints() - GET_COMPONENT(D, /datum/component/forensics) - if(D) - . = D.fingerprints - -/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/blood_DNA_length() - GET_COMPONENT(D, /datum/component/forensics) - if(D) - . = length(D.blood_DNA) - -/atom/proc/return_fibers() - GET_COMPONENT(D, /datum/component/forensics) - if(D) - . = D.fibers - -/atom/proc/return_blood_mix_types() - GET_COMPONENT(D, /datum/component/forensics) - if(D) - . = D.blood_mix_types - -/atom/proc/return_blood_mix_color() - GET_COMPONENT(D, /datum/component/forensics) - if(D) - . = D.blood_mix_color - -/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 = FALSE) - var/datum/component/forensics/D = AddComponent(/datum/component/forensics) - . = D.add_fingerprint(M, ignoregloves) - -/atom/proc/add_fiber_list(list/fibertext) //ASSOC LIST FIBERTEXT = FIBERTEXT - if(length(fibertext)) - . = AddComponent(/datum/component/forensics, null, null, null, fibertext) +/atom/var/list/suit_fibers /atom/proc/add_fibers(mob/living/carbon/human/M) - var/old = 0 - if(M.gloves && istype(M.gloves, /obj/item/clothing)) + 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_DNA(G.return_blood_DNA()) && length(G.return_blood_DNA()) > old) //only reduces the bloodiness of our gloves if the item wasn't already bloody + if(add_blood(G.blood_DNA)) //only reduces the bloodiness of our gloves if the item wasn't already bloody G.transfer_blood-- else if(M.bloody_hands > 1) - old = length(M.return_blood_DNA()) - if(add_blood_DNA(M.return_blood_DNA()) && length(M.return_blood_DNA()) > old) + if(add_blood(M.blood_DNA)) M.bloody_hands-- - var/datum/component/forensics/D = AddComponent(/datum/component/forensics) - . = D.add_fibers(M) + 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/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) /atom/proc/add_hiddenprint(mob/living/M) - var/datum/component/forensics/D = AddComponent(/datum/component/forensics) - . = D.add_hiddenprint(M) + if(!M || !M.key) + return -/atom/proc/add_blood_DNA(list/dna) //ASSOC LIST DNA = BLOODTYPE - return FALSE + if(!fingerprintshidden) //Add the list if it does not exist + fingerprintshidden = list() -/obj/add_blood_DNA(list/dna) - . = ..() - if(length(dna)) - . = AddComponent(/datum/component/forensics, null, null, dna) + 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 + + +//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 + + 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 = 1 + + if(!ignoregloves) + H.gloves.add_fingerprint(H, 1) //ignoregloves = 1 to avoid infinite loop. + return + + 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/item/clothing/gloves/add_blood_DNA(list/blood_dna, list/datum/disease/diseases) - . = ..() - transfer_blood = rand(2, 4) -/turf/add_blood_DNA(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_DNA(blood_dna) //give blood info to the blood decal. - return TRUE //we bloodied the floor -/mob/living/carbon/human/add_blood_DNA(list/blood_dna, list/datum/disease/diseases) - if(wear_suit) - wear_suit.add_blood_DNA(blood_dna) - update_inv_wear_suit() - else if(w_uniform) - w_uniform.add_blood_DNA(blood_dna) - update_inv_w_uniform() - if(gloves) - var/obj/item/clothing/gloves/G = gloves - G.add_blood_DNA(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_DNA(blood_dna) - update_inv_head() - else if(wear_mask) - wear_mask.add_blood_DNA(blood_dna) - update_inv_wear_mask() - if(wear_neck) - wear_neck.add_blood_DNA(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() + + if(!islist(fingerprints)) + fingerprints = list() + if(!islist(fingerprintshidden)) + fingerprintshidden = list() + + // Transfer + if(fingerprints) + A.fingerprints |= fingerprints.Copy() //detective + if(fingerprintshidden) + A.fingerprintshidden |= fingerprintshidden.Copy() //admin + A.fingerprintslast = fingerprintslast \ No newline at end of file diff --git a/code/modules/detectivework/footprints_and_rag.dm b/code/modules/detectivework/footprints_and_rag.dm index 9f1f2bf380..611001ecf9 100644 --- a/code/modules/detectivework/footprints_and_rag.dm +++ b/code/modules/detectivework/footprints_and_rag.dm @@ -1,10 +1,14 @@ /mob var/bloody_hands = 0 + var/bloody_feet = 0 /obj/item/clothing/gloves var/transfer_blood = 0 +/obj/item/clothing/shoes + var/transfer_blood = 0 + /obj/item/reagent_containers/glass/rag name = "damp rag" @@ -46,5 +50,6 @@ user.visible_message("[user] starts to wipe down [A] with [src]!", "You start to wipe down [A] with [src]...") if(do_after(user,30, target = A)) user.visible_message("[user] finishes wiping off [A]!", "You finish wiping off [A].") - SEND_SIGNAL(A, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_MEDIUM) + A.clean_blood() + A.wash_cream() return diff --git a/code/modules/detectivework/scanner.dm b/code/modules/detectivework/scanner.dm index fd7591db81..eace1bf7b1 100644 --- a/code/modules/detectivework/scanner.dm +++ b/code/modules/detectivework/scanner.dm @@ -80,14 +80,20 @@ //Make our lists var/list/fingerprints = list() - var/list/blood = A.return_blood_DNA() - var/list/fibers = A.return_fibers() + var/list/blood = list() + var/list/fibers = list() 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 @@ -96,7 +102,8 @@ else if(!ismob(A)) - fingerprints = A.return_fingerprints() + if(A.fingerprints && A.fingerprints.len) + fingerprints = A.fingerprints.Copy() // Only get reagents from non-mobs. if(A.reagents && A.reagents.reagent_list.len) @@ -110,7 +117,6 @@ 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. @@ -119,7 +125,7 @@ add_log("[STATION_TIME_TIMESTAMP("hh:mm:ss")][get_timestamp()] - [target_name]", 0) // Fingerprints - if(length(fingerprints)) + if(fingerprints && fingerprints.len) sleep(30) add_log("Prints:") for(var/finger in fingerprints) @@ -127,7 +133,7 @@ found_something = 1 // Blood - if (length(blood)) + if (blood && blood.len) sleep(30) add_log("Blood:") found_something = 1 @@ -135,7 +141,7 @@ add_log("Type: [blood[B]] DNA: [B]") //Fibers - if(length(fibers)) + if(fibers && fibers.len) sleep(30) add_log("Fibers:") for(var/fiber in fibers) @@ -143,7 +149,7 @@ found_something = 1 //Reagents - if(length(reagents)) + if(reagents && reagents.len) sleep(30) add_log("Reagents:") for(var/R in reagents) diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index 86bf676f7e..fa6e12e6ce 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -287,7 +287,8 @@ drop.transfer_mob_blood_dna(src) return else - temp_blood_DNA = drop.return_blood_DNA() //we transfer the dna from the drip to the splatter + temp_blood_DNA = list() + temp_blood_DNA |= drop.blood_DNA.Copy() //we transfer the dna from the drip to the splatter qdel(drop)//the drip is replaced by a bigger splatter else drop = new(T, get_static_viruses()) @@ -303,9 +304,9 @@ B.transfer_mob_blood_dna(src) //give blood info to the blood decal. if(temp_blood_DNA) if(isalien(src)) - B.add_blood_DNA(list("UNKNOWN DNA" = "X*")) + B.blood_DNA["UNKNOWN DNA"] = "X*" else - B.add_blood_DNA(temp_blood_DNA) + B.blood_DNA |= temp_blood_DNA /mob/living/carbon/human/add_splatter_floor(turf/T, small_drip) if(!(NOBLOOD in dna.species.species_traits)) diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm index c42bd82797..a99776d03e 100644 --- a/code/modules/mob/living/carbon/examine.dm +++ b/code/modules/mob/living/carbon/examine.dm @@ -11,18 +11,21 @@ if (handcuffed) msg += "[t_He] [t_is] [icon2html(handcuffed, user)] handcuffed!\n" if (head) - msg += "[t_He] [t_is] wearing [head.get_examine_string(user)] on [t_his] head. \n" + msg += "[t_He] [t_is] wearing [icon2html(head, user)] \a [src.head] on [t_his] head. \n" if (wear_mask) - msg += "[t_He] [t_is] wearing [wear_mask.get_examine_string(user)] on [t_his] face.\n" + msg += "[t_He] [t_is] wearing [icon2html(wear_mask, user)] \a [src.wear_mask] on [t_his] face.\n" if (wear_neck) - msg += "[t_He] [t_is] wearing [wear_neck.get_examine_string(user)] around [t_his] neck.\n" + msg += "[t_He] [t_is] wearing [icon2html(wear_neck, user)] \a [src.wear_neck] around [t_his] neck.\n" for(var/obj/item/I in held_items) 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" + 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 (back) - msg += "[t_He] [t_has] [back.get_examine_string(user)] on [t_his] back.\n" + msg += "[t_He] [t_has] [icon2html(back, user)] \a [src.back] on [t_his] back.\n" var/appears_dead = 0 if (stat == DEAD) appears_dead = 1 @@ -88,7 +91,7 @@ if(digitalcamo) msg += "[t_He] [t_is] moving [t_his] body in an unnatural and blatantly unsimian manner.\n" - + if(combatmode) msg += "[t_He] [t_is] visibly tense[resting ? "." : ", and [t_is] standing in combative stance."]\n" diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 26e19ff376..aa0c7283ef 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -37,30 +37,46 @@ if(U.attached_accessory) accessory_msg += " with [icon2html(U.attached_accessory, user)] \a [U.attached_accessory]" - msg += "[t_He] [t_is] wearing [w_uniform.get_examine_string(user)][accessory_msg].\n" + 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" //head if(head) - msg += "[t_He] [t_is] wearing [head.get_examine_string(user)] on [t_his] head.\n" + 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" //suit/armor if(wear_suit) - msg += "[t_He] [t_is] wearing [wear_suit.get_examine_string(user)].\n" + 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/armor storage - if(s_store) - msg += "[t_He] [t_is] carrying [s_store.get_examine_string(user)] on [t_his] [wear_suit.name].\n" + 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" //back if(back) - msg += "[t_He] [t_has] [back.get_examine_string(user)] on [t_his] back.\n" - + 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" //Hands for(var/obj/item/I in held_items) - 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" - - GET_COMPONENT(FR, /datum/component/forensics) + 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" //gloves if(gloves && !(SLOT_GLOVES in obscured)) - msg += "[t_He] [t_has] [gloves.get_examine_string(user)] on [t_his] hands.\n" - else if(FR && length(FR.blood_DNA)) + 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) 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" @@ -76,33 +92,47 @@ //belt if(belt) - msg += "[t_He] [t_has] [belt.get_examine_string(user)] about [t_his] waist.\n" + 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" //shoes if(shoes && !(SLOT_SHOES in obscured)) - msg += "[t_He] [t_is] wearing [shoes.get_examine_string(user)] on [t_his] feet.\n" + 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" //mask if(wear_mask && !(SLOT_WEAR_MASK in obscured)) - msg += "[t_He] [t_has] [wear_mask.get_examine_string(user)] on [t_his] face.\n" + 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" - if (wear_neck && !(SLOT_NECK in obscured)) - msg += "[t_He] [t_is] wearing [wear_neck.get_examine_string(user)] around [t_his] neck.\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" //eyes if(!(SLOT_GLASSES in obscured)) if(glasses) - msg += "[t_He] [t_has] [glasses.get_examine_string(user)] covering [t_his] eyes.\n" + 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" + else if(eye_color == BLOODCULT_EYE && iscultist(src) && has_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] [ears.get_examine_string(user)] on [t_his] ears.\n" + msg += "[t_He] [t_has] [icon2html(ears, user)] \a [ears] on [t_his] ears.\n" //ID if(wear_id) - msg += "[t_He] [t_is] wearing [wear_id.get_examine_string(user)].\n" + msg += "[t_He] [t_is] wearing [icon2html(wear_id, user)] \a [wear_id].\n" //Status effects msg += status_effect_examines() diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 49d2722323..bbf77eb8b5 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -31,8 +31,6 @@ 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,16 +685,22 @@ if(..()) dropItemToGround(I) -/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() +/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() else - if(bloody_hands) - bloody_hands = 0 - update_inv_gloves() + ..() // 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() + bloodiness = 0 + + update_icons() //apply the now updated overlays to the mob /mob/living/carbon/human/wash_cream() if(creamed) //clean both to prevent a rare bug diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 95139f75ee..1fe16b3a2e 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -45,6 +45,8 @@ var/bloodiness = 0 var/bloodinessmax = 5 + var/last_bloodtype = ""//used to track the last bloodtype to have graced this filthy spaceman; makes for better performing footprint shenanigans + var/last_blood_DNA = ""//same as last one var/blood_state = BLOOD_STATE_NOT_BLOODY var/list/blood_smear = list(BLOOD_STATE_BLOOD = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0) var/blood_color //For blood smearing stuff diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index dd37563f8f..1620b8eed9 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -147,3 +147,9 @@ return FALSE return . + +/mob/living/carbon/human/transfer_blood_dna(list/blood_dna) + ..() + if(blood_dna.len) + last_bloodtype = blood_dna[blood_dna[blood_dna.len]]//trust me this works + last_blood_DNA = blood_dna[blood_dna.len] diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index b2592ae157..024f2590e7 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -57,18 +57,20 @@ var/turf/T = get_turf(src) if(S.blood_smear && S.blood_smear[S.blood_state]) var/obj/effect/decal/cleanable/blood/footprints/tracks/shoe/oldFP = locate(/obj/effect/decal/cleanable/blood/footprints/tracks/shoe) in T - if(oldFP && (oldFP.blood_state == S.blood_state && oldFP.color == S.blood_color)) + if(oldFP && (oldFP.blood_state == S.blood_state && oldFP.color == bloodtype_to_color(S.last_bloodtype))) return - S.blood_smear[S.blood_state] = max(0, S.blood_smear[S.blood_state]-BLOOD_LOSS_PER_STEP) - var/obj/effect/decal/cleanable/blood/footprints/tracks/shoe/FP = new /obj/effect/decal/cleanable/blood/footprints/tracks/shoe(T) - FP.icon_state = FOOTPRINT_SHOE - FP.print_state = FOOTPRINT_SHOE - FP.blood_state = S.blood_state - FP.blood_color = S.blood_color - FP.entered_dirs |= dir - FP.bloodiness = S.blood_smear[S.blood_state] - FP.update_icon() - update_inv_shoes() + S.blood_smear[S.blood_state] = max(0, S.blood_smear[S.blood_state]-BLOOD_LOSS_PER_STEP) + var/obj/effect/decal/cleanable/blood/footprints/tracks/shoe/FP = new /obj/effect/decal/cleanable/blood/footprints/tracks/shoe(T) + FP.icon_state = FOOTPRINT_SHOE + FP.print_state = FOOTPRINT_SHOE + FP.blood_state = S.blood_state + FP.entered_dirs |= dir + FP.bloodiness = S.blood_smear[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.update_icon() + update_inv_shoes() //End bloody footprints S.step_action() @@ -80,27 +82,28 @@ var/step_print = dna.species.get_move_trail(src) if(bloodiness && blood_smear[blood_state]) var/obj/effect/decal/cleanable/blood/footprints/tracks/oldFP = locate(step_print) in T - if(oldFP && (oldFP.blood_state == blood_state && oldFP == dna.species.move_trail && oldFP.blood_color == blood_color)) + if(oldFP && (oldFP.blood_state == blood_state && oldFP.color == bloodtype_to_color(last_bloodtype))) return - else - var/obj/effect/decal/cleanable/blood/footprints/tracks/FP = new step_print(T) - if(("taur" in dna.species.mutant_bodyparts) && (dna.features["taur"] != "None") && !lying) - if(dna.features["taur"] in GLOB.noodle_taurs) - FP.icon_state = FOOTPRINT_SNAKE - FP.print_state = FOOTPRINT_SNAKE - else if(dna.features["taur"] in GLOB.paw_taurs) - FP.icon_state = FOOTPRINT_PAW - FP.print_state = FOOTPRINT_PAW - if(!dna.species.move_trail && !lying) //we're assuming people have their chosen snowflake on, so. - FP.icon_state = FOOTPRINT_SHOE - FP.print_state = FOOTPRINT_SHOE + var/obj/effect/decal/cleanable/blood/footprints/tracks/FP = new step_print(T) + if(("taur" in dna.species.mutant_bodyparts) && (dna.features["taur"] != "None") && !lying) + if(dna.features["taur"] in GLOB.noodle_taurs) + FP.icon_state = FOOTPRINT_SNAKE + FP.print_state = FOOTPRINT_SNAKE + else if(dna.features["taur"] in GLOB.paw_taurs) + FP.icon_state = FOOTPRINT_PAW + FP.print_state = FOOTPRINT_PAW + if(!dna.species.move_trail && !lying) //we're assuming people have their chosen snowflake on, so. + FP.icon_state = FOOTPRINT_SHOE + FP.print_state = FOOTPRINT_SHOE - FP.add_blood_DNA(return_blood_DNA()) - FP.blood_color = blood_color - FP.entered_dirs |= dir - FP.bloodiness = blood_smear[blood_state] - FP.update_icon() - bloodiness-- + FP.blood_state = blood_state + FP.entered_dirs |= dir + FP.bloodiness = blood_smear[blood_state] + if(last_blood_DNA && last_bloodtype) + FP.blood_DNA += list(last_blood_DNA = last_bloodtype) + //hacky as heck; we need to move the LAST entry to there, otherwise we mix all the blood + FP.update_icon() + bloodiness-- /mob/living/carbon/human/Process_Spacemove(movement_dir = 0) //Temporary laziness thing. Will change to handles by species reee. if(dna.species.space_move(src)) diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm index 41ab5eb79f..10a0bc9e5c 100644 --- a/code/modules/mob/living/simple_animal/bot/mulebot.dm +++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm @@ -474,7 +474,8 @@ if(isturf(next)) if(bloodiness) var/obj/effect/decal/cleanable/blood/footprints/tracks/wheels/B = new(loc) - B.add_blood_DNA(return_blood_DNA()) + if(blood_DNA && blood_DNA.len) + B.blood_DNA |= blood_DNA.Copy() var/newdir = get_dir(next, loc) if(newdir == dir) B.setDir(newdir) @@ -656,7 +657,8 @@ T.add_mob_blood(H) var/list/blood_dna = H.get_blood_dna_list() - add_blood_DNA(blood_dna) + if(blood_dna) + transfer_blood_dna(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 cf3742fcc5..4a2e9232dd 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -169,15 +169,23 @@ //Hands for(var/obj/item/I in held_items) if(!(I.item_flags & ABSTRACT)) - msg += "It has [I.get_examine_string(user)] in its [get_held_index_name(get_held_index_of_item(I))].\n" - + 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" //Internal storage if(internal_storage && !(internal_storage.item_flags & ABSTRACT)) - msg += "It is holding [internal_storage.get_examine_string(user)] in its internal storage.\n" + 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" //Cosmetic hat - provides no function other than looks if(head && !(head.item_flags & ABSTRACT)) - msg += "It is wearing [head.get_examine_string(user)] on its head.\n" + 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" //Braindead if(!client && stat != DEAD) 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 e7dbbda242..9e962f6afb 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm @@ -23,9 +23,15 @@ for(var/obj/item/I in held_items) if(!(I.item_flags & ABSTRACT)) - msg += "It has [I.get_examine_string(user)] in its [get_held_index_name(get_held_index_of_item(I))].\n" + 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" if(internal_storage && !(internal_storage.item_flags & ABSTRACT)) - msg += "It is holding [internal_storage.get_examine_string(user)] in its internal storage.\n" + 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 += "*---------*" to_chat(user, msg) else diff --git a/code/modules/mob/living/simple_animal/hostile/alien.dm b/code/modules/mob/living/simple_animal/hostile/alien.dm index 3d92912f9c..253d92a57f 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 - SEND_SIGNAL(M, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + M.clean_blood() visible_message("[src] polishes \the [target].") return TRUE diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm index 157cf1f03f..1f60f5cdb5 100644 --- a/code/modules/projectiles/guns/ballistic.dm +++ b/code/modules/projectiles/guns/ballistic.dm @@ -169,7 +169,7 @@ if(iscarbon(user)) var/mob/living/carbon/C = user user_dna = C.dna - B.add_blood_DNA(user_dna) + B.add_blood(user_dna) var/datum/callback/gibspawner = CALLBACK(GLOBAL_PROC, /proc/spawn_atom_to_turf, /obj/effect/gibspawner/generic, B, 1, FALSE, list(user_dna)) B.throw_at(target, BRAINS_BLOWN_THROW_RANGE, BRAINS_BLOWN_THROW_SPEED, callback=gibspawner) return(BRUTELOSS) diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index efae090707..44185b601f 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -161,10 +161,19 @@ var/splatter_dir = dir if(starting) splatter_dir = get_dir(starting, target_loca) - if(isalien(L)) + var/obj/item/bodypart/B = L.get_bodypart(def_zone) + if(B.status == BODYPART_ROBOTIC) // So if you hit a robotic, it sparks instead of bloodspatters + do_sparks(2, FALSE, target.loc) + if(prob(25)) + new /obj/effect/decal/cleanable/oil(target_loca) + else if(isalien(L)) new /obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter(target_loca, splatter_dir) else - new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_loca, splatter_dir) + if(ishuman(target)) + var/mob/living/carbon/human/H = target + new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_loca, splatter_dir, bloodtype_to_color(H.dna.blood_type)) + else + new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_loca, splatter_dir, bloodtype_to_color()) if(iscarbon(L)) var/mob/living/carbon/C = L C.bleed(damage) diff --git a/code/modules/projectiles/projectile/bullets/smg.dm b/code/modules/projectiles/projectile/bullets/smg.dm index dfc6df537d..bba9e746be 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 - SEND_SIGNAL(T, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + clean_blood()//blood overlays get weird otherwise, because the sprite changes. for(var/A in T) if(is_cleanable(A)) qdel(A) else if(istype(A, /obj/item)) var/obj/item/I = A - SEND_SIGNAL(I, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + I.clean_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) - SEND_SIGNAL(cleaned_human.head, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + cleaned_human.head.clean_blood() if(cleaned_human.wear_suit) - SEND_SIGNAL(cleaned_human.wear_suit, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + cleaned_human.wear_suit.clean_blood() else if(cleaned_human.w_uniform) - SEND_SIGNAL(cleaned_human.w_uniform, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + cleaned_human.w_uniform.clean_blood() if(cleaned_human.shoes) - 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.shoes.clean_blood() + cleaned_human.clean_blood() cleaned_human.wash_cream() cleaned_human.regenerate_icons() diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index d91b675e22..a4e56c9429 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -41,12 +41,12 @@ C.blood_volume = min(C.blood_volume + round(reac_volume, 0.1), BLOOD_VOLUME_MAXIMUM) if(reac_volume >= 10 && istype(L)) - L.add_blood_DNA(list(data["blood_DNA"] = data["blood_type"])) + L.add_blood(list(data["blood_DNA"] = data["blood_type"])) L.color = bloodtype_to_color(data["blood_type"]) /datum/reagent/blood/reaction_obj(obj/O, volume) if(volume >= 3 && istype(O)) - O.add_blood_DNA(list(data["blood_DNA"] = data["blood_type"])) + O.add_blood(list(data["blood_DNA"] = data["blood_type"])) O.color = bloodtype_to_color(data["blood_type"]) /datum/reagent/blood/on_new(list/data) @@ -1004,7 +1004,7 @@ /datum/reagent/iron/on_mob_life(mob/living/carbon/C) if(C.blood_volume < BLOOD_VOLUME_NORMAL) - C.blood_volume += 0.5 + C.blood_volume += 0.01 //we'll have synthetics from medbay. ..() /datum/reagent/iron/reaction_mob(mob/living/M, method=TOUCH, reac_volume) @@ -1128,12 +1128,12 @@ else if(O) O.remove_atom_colour(WASHABLE_COLOUR_PRIORITY) - SEND_SIGNAL(O, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + O.clean_blood() /datum/reagent/space_cleaner/reaction_turf(turf/T, reac_volume) if(reac_volume >= 1) T.remove_atom_colour(WASHABLE_COLOUR_PRIORITY) - SEND_SIGNAL(T, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + T.clean_blood() for(var/obj/effect/decal/cleanable/C in T) qdel(C) @@ -1151,26 +1151,26 @@ H.lip_style = null H.update_body() for(var/obj/item/I in C.held_items) - SEND_SIGNAL(I, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + I.clean_blood() if(C.wear_mask) - if(SEND_SIGNAL(C.wear_mask, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)) + if(C.clean_blood()) C.update_inv_wear_mask() if(ishuman(M)) var/mob/living/carbon/human/H = C if(H.head) - if(SEND_SIGNAL(H.head, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)) + if(H.head.clean_blood()) H.update_inv_head() if(H.wear_suit) - if(SEND_SIGNAL(H.wear_suit, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)) + if(H.wear_suit.clean_blood()) H.update_inv_wear_suit() else if(H.w_uniform) - if(SEND_SIGNAL(H.w_uniform, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)) + if(H.w_uniform.clean_blood()) H.update_inv_w_uniform() if(H.shoes) - if(SEND_SIGNAL(H.shoes, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)) + if(H.shoes.clean_blood()) H.update_inv_shoes() H.wash_cream() - SEND_SIGNAL(M, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + M.clean_blood() /datum/reagent/space_cleaner/ez_clean name = "EZ Clean" diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm index a710d127fb..d250dcff0e 100644 --- a/code/modules/reagents/reagent_containers/blood_pack.dm +++ b/code/modules/reagents/reagent_containers/blood_pack.dm @@ -48,7 +48,7 @@ /obj/item/reagent_containers/blood/random/Initialize() icon_state = "bloodpack" - blood_type = pick("A+", "A-", "B+", "B-", "O+", "O-", "L", "SY") + blood_type = pick("A+", "A-", "B+", "B-", "O+", "O-", "L", "SY", "HF", "GEL") return ..() /obj/item/reagent_containers/blood/APlus @@ -78,6 +78,12 @@ /obj/item/reagent_containers/blood/synthetics blood_type = "SY" +/obj/item/reagent_containers/blood/oilblood + blood_type = "HF" + +/obj/item/reagent_containers/blood/jellyblood + blood_type = "GEL" + /obj/item/reagent_containers/blood/attackby(obj/item/I, mob/user, params) if (istype(I, /obj/item/pen) || istype(I, /obj/item/toy/crayon)) if(!user.is_literate()) diff --git a/icons/mob/dam_mob.dmi b/icons/mob/dam_mob.dmi index fe92746b43ece7dce16cb6364b0c600f3c709c6e..c34b57b434be7c6228ec585974944b1bc4382088 100644 GIT binary patch delta 15405 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 delta 15467 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 F{0|bemxBNR 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 e6ba224f8d..c6e1a4cbbd 100644 --- a/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm +++ b/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm @@ -327,7 +327,7 @@ var/mob/M = loc M.update_inv_hands() - 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) + clean_blood()//blood overlays get weird otherwise, because the sprite changes. /obj/item/twohanded/hypereutactic/AltClick(mob/living/user) if(!in_range(src, user)) //Basic checks to prevent abuse 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 0f71a71add..cb918da21f 100644 --- a/modular_citadel/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/modular_citadel/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -4,7 +4,7 @@ else if(O) O.remove_atom_colour(WASHABLE_COLOUR_PRIORITY) - SEND_SIGNAL(O, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD) + O.clean_blood() /datum/reagent/syndicateadrenals name = "Syndicate Adrenaline" diff --git a/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm b/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm index 1c857bf8a6..d81fc62d6c 100644 --- a/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm +++ b/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm @@ -2,7 +2,7 @@ /datum/reagent/consumable/semen name = "Semen" id = "semen" - description = "Sperm from some animal. Useless for anything but insemination, really." + description = "Sperm from some animal. I bet you'll drink this out of a bucket someday." taste_description = "something salty" taste_mult = 2 //Not very overpowering flavor data = list("donor"=null,"viruses"=null,"donor_DNA"=null,"blood_type"=null,"resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null) @@ -21,7 +21,7 @@ S = new(T) S.reagents.add_reagent("semen", reac_volume) if(data["blood_DNA"]) - S.add_blood_DNA(list(data["blood_DNA"] = data["blood_type"])) + S.add_blood(list(data["blood_DNA"] = data["blood_type"])) /obj/effect/decal/cleanable/semen name = "semen" @@ -36,10 +36,12 @@ /obj/effect/decal/cleanable/semen/New() ..() dir = pick(1,2,4,8) - add_blood_DNA(list("Non-human DNA" = "A+")) + add_blood(list("Non-human DNA" = "A+")) /obj/effect/decal/cleanable/semen/replace_decal(obj/effect/decal/cleanable/semen/S) - S.add_blood_DNA(return_blood_DNA()) + if (S.blood_DNA) + blood_DNA |= S.blood_DNA.Copy() + ..() /datum/reagent/consumable/femcum name = "Female Ejaculate" @@ -67,10 +69,11 @@ /obj/effect/decal/cleanable/femcum/New() ..() dir = pick(1,2,4,8) - add_blood_DNA(list("Non-human DNA" = "A+")) + add_blood(list("Non-human DNA" = "A+")) /obj/effect/decal/cleanable/femcum/replace_decal(obj/effect/decal/cleanable/femcum/F) - F.add_blood_DNA(return_blood_DNA()) + if(F.blood_DNA) + blood_DNA |= F.blood_DNA.Copy() ..() /datum/reagent/consumable/femcum/reaction_turf(turf/T, reac_volume) @@ -84,7 +87,7 @@ S = new(T) S.reagents.add_reagent("femcum", reac_volume) if(data["blood_DNA"]) - S.add_blood_DNA(list(data["blood_DNA"] = data["blood_type"])) + S.add_blood(list(data["blood_DNA"] = data["blood_type"])) //aphrodisiac & anaphrodisiac