From a3add3761884e925059d0e4fd4e74af5febfac5c Mon Sep 17 00:00:00 2001 From: Seth Scherer Date: Mon, 16 May 2022 00:33:59 -0400 Subject: [PATCH] Refactors the forensics component into a datum (#66809) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit About The Pull Request This was doing things component really shouldn't be doing, and now all of its behaviour is contained onto a datum, as it should've been the whole time Why It's Good For The CODEBASE some things just really shouldn't be components, this was made back when DCS was first implemented and just thrown in because it was the new hot thing i guess, but datumized forensics makes far more sense, AND doesn't use GetComponent TODO: More thorough testing to make sure nothing broke Changelog 🆑 refactor: Turned the forensics component into a datum. /🆑 --- code/__DEFINES/blood.dm | 5 +- code/__HELPERS/forensics.dm | 10 + code/datums/brain_damage/phobia.dm | 4 +- code/datums/components/bloodysoles.dm | 6 +- code/datums/components/forensics.dm | 188 -------------- code/datums/mutations/actions.dm | 2 +- code/game/atoms.dm | 9 +- .../effects/decals/cleanable/humans.dm | 2 +- code/game/objects/items/stacks/stack.dm | 6 +- code/modules/admin/verbs/hiddenprints.dm | 2 +- .../antagonists/heretic/heretic_knowledge.dm | 2 +- code/modules/clothing/gloves/_gloves.dm | 2 +- code/modules/clothing/head/_head.dm | 2 +- code/modules/clothing/masks/_masks.dm | 2 +- code/modules/clothing/neck/_neck.dm | 2 +- code/modules/clothing/shoes/_shoes.dm | 2 +- code/modules/clothing/suits/_suits.dm | 2 +- code/modules/clothing/under/_under.dm | 2 +- code/modules/detectivework/detective_work.dm | 114 --------- code/modules/detectivework/scanner.dm | 6 +- code/modules/forensics/_forensics.dm | 237 ++++++++++++++++++ code/modules/forensics/forensics_helpers.dm | 122 +++++++++ code/modules/mob/living/blood.dm | 2 +- code/modules/mob/living/carbon/carbon.dm | 2 +- .../mob/living/carbon/human/examine.dm | 3 +- .../living/simple_animal/bot/hygienebot.dm | 2 +- .../mob/living/simple_animal/bot/mulebot.dm | 2 +- tgstation.dme | 5 +- 28 files changed, 407 insertions(+), 338 deletions(-) create mode 100644 code/__HELPERS/forensics.dm delete mode 100644 code/datums/components/forensics.dm delete mode 100644 code/modules/detectivework/detective_work.dm create mode 100644 code/modules/forensics/_forensics.dm create mode 100644 code/modules/forensics/forensics_helpers.dm diff --git a/code/__DEFINES/blood.dm b/code/__DEFINES/blood.dm index b3b8c0d1f3d..320c3ded51a 100644 --- a/code/__DEFINES/blood.dm +++ b/code/__DEFINES/blood.dm @@ -1,6 +1,3 @@ -/// Checks if an object is covered in blood -#define HAS_BLOOD_DNA(thing) (length(thing.GetComponent(/datum/component/forensics)?.blood_DNA)) - //Bloody shoes/footprints /// Minimum alpha of footprints #define BLOODY_FOOTPRINT_BASE_ALPHA 20 @@ -20,5 +17,5 @@ #define BLOOD_STATE_XENO "xeno" /// Black robot oil #define BLOOD_STATE_OIL "oil" -/// No blood is present +/// No blood is present #define BLOOD_STATE_NOT_BLOODY "no blood whatsoever" diff --git a/code/__HELPERS/forensics.dm b/code/__HELPERS/forensics.dm new file mode 100644 index 00000000000..2d43a1ad61b --- /dev/null +++ b/code/__HELPERS/forensics.dm @@ -0,0 +1,10 @@ +/// Returns the fingerprints on this atom +#define GET_ATOM_FINGERPRINTS(atom) atom.forensics?.fingerprints +/// Returns the hidden prints on this atom +#define GET_ATOM_HIDDENPRINTS(atom) atom.forensics?.hiddenprints +/// Returns the blood dna on this atom +#define GET_ATOM_BLOOD_DNA(atom) atom.forensics?.blood_DNA +/// Returns the fibers on this atom +#define GET_ATOM_FIBRES(atom) atom.forensics?.fibers +/// Returns the number of unique blood dna sources on this atom +#define GET_ATOM_BLOOD_DNA_LENGTH(atom) (isnull(atom.forensics) ? 0 : length(atom.forensics.blood_DNA)) diff --git a/code/datums/brain_damage/phobia.dm b/code/datums/brain_damage/phobia.dm index ac7e9f363ae..7e8f0d1ab99 100644 --- a/code/datums/brain_damage/phobia.dm +++ b/code/datums/brain_damage/phobia.dm @@ -48,13 +48,13 @@ var/list/seen_atoms = view(7, owner) if(LAZYLEN(trigger_objs)) for(var/obj/O in seen_atoms) - if(is_type_in_typecache(O, trigger_objs) || (phobia_type == "blood" && HAS_BLOOD_DNA(O))) + if(is_type_in_typecache(O, trigger_objs) || (phobia_type == "blood" && GET_ATOM_BLOOD_DNA_LENGTH(O))) freak_out(O) return for(var/mob/living/carbon/human/HU in seen_atoms) //check equipment for trigger items for(var/X in HU.get_all_worn_items() | HU.held_items) var/obj/I = X - if(!QDELETED(I) && (is_type_in_typecache(I, trigger_objs) || (phobia_type == "blood" && HAS_BLOOD_DNA(I)))) + if(!QDELETED(I) && (is_type_in_typecache(I, trigger_objs) || (phobia_type == "blood" && GET_ATOM_BLOOD_DNA_LENGTH(I)))) freak_out(I) return diff --git a/code/datums/components/bloodysoles.dm b/code/datums/components/bloodysoles.dm index 83dcdab0207..006da44dfdf 100644 --- a/code/datums/components/bloodysoles.dm +++ b/code/datums/components/bloodysoles.dm @@ -71,7 +71,7 @@ if(HAS_TRAIT(parent_atom, TRAIT_LIGHT_STEP)) //the character is agile enough to don't mess their clothing and hands just from one blood splatter at floor return TRUE - parent_atom.add_blood_DNA(pool.return_blood_DNA()) + parent_atom.add_blood_DNA(GET_ATOM_BLOOD_DNA(pool)) update_icon() /** @@ -156,7 +156,7 @@ oldLocFP.exited_dirs |= wielder.dir add_parent_to_footprint(oldLocFP) oldLocFP.bloodiness = half_our_blood - oldLocFP.add_blood_DNA(parent_atom.return_blood_DNA()) + oldLocFP.add_blood_DNA(GET_ATOM_BLOOD_DNA(parent_atom)) oldLocFP.update_appearance() half_our_blood = bloody_shoes[last_blood_state] / 2 @@ -176,7 +176,7 @@ FP.entered_dirs |= wielder.dir add_parent_to_footprint(FP) FP.bloodiness = half_our_blood - FP.add_blood_DNA(parent_atom.return_blood_DNA()) + FP.add_blood_DNA(GET_ATOM_BLOOD_DNA(parent_atom)) FP.update_appearance() diff --git a/code/datums/components/forensics.dm b/code/datums/components/forensics.dm deleted file mode 100644 index 26b3d9f5c14..00000000000 --- a/code/datums/components/forensics.dm +++ /dev/null @@ -1,188 +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 - -/datum/component/forensics/InheritComponent(datum/component/forensics/F, original) //Use of | and |= being different here is INTENTIONAL. - fingerprints = LAZY_LISTS_OR(fingerprints, F.fingerprints) - hiddenprints = LAZY_LISTS_OR(hiddenprints, F.hiddenprints) - blood_DNA = LAZY_LISTS_OR(blood_DNA, F.blood_DNA) - fibers = LAZY_LISTS_OR(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 - return TRUE - -/datum/component/forensics/proc/wipe_fibers() - fibers = null - return TRUE - -/datum/component/forensics/proc/clean_act(datum/source, clean_types) - SIGNAL_HANDLER - - . = NONE - if(clean_types & CLEAN_TYPE_FINGERPRINTS) - wipe_fingerprints() - . = COMPONENT_CLEANED - if(clean_types & CLEAN_TYPE_BLOOD) - wipe_blood_DNA() - . = COMPONENT_CLEANED - if(clean_types & CLEAN_TYPE_FIBERS) - wipe_fibers() - . = COMPONENT_CLEANED - -/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/ai_eye/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) - var/obj/item/gloves = H.gloves - if(gloves) //Check if the gloves (if any) hide fingerprints - if(!(gloves.body_parts_covered & HANDS) || HAS_TRAIT(gloves, TRAIT_FINGERPRINT_PASSTHROUGH) || HAS_TRAIT(H, TRAIT_FINGERPRINT_PASSTHROUGH)) - ignoregloves = TRUE - if(!ignoregloves) - H.gloves.add_fingerprint(H, TRUE) //ignoregloves = 1 to avoid infinite loop. - return - var/full_print = md5(H.dna.unique_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/ai_eye/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() - if(!LAZYACCESS(hiddenprints, M.key)) - LAZYSET(hiddenprints, M.key, "First: \[[current_time]\] \"[M.real_name]\"[hasgloves]. Ckey: [M.ckey]") - else - var/laststamppos = findtext(LAZYACCESS(hiddenprints, M.key), "\nLast: ") - if(laststamppos) - LAZYSET(hiddenprints, M.key, copytext(hiddenprints[M.key], 1, laststamppos)) - hiddenprints[M.key] += "\nLast: \[[current_time]\] \"[M.real_name]\"[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.AddElement(/datum/element/decal/blood) diff --git a/code/datums/mutations/actions.dm b/code/datums/mutations/actions.dm index d1119a4fa44..57b40b12476 100644 --- a/code/datums/mutations/actions.dm +++ b/code/datums/mutations/actions.dm @@ -53,7 +53,7 @@ if(sniffed) var/old_target = tracking_target possible = list() - var/list/prints = sniffed.return_fingerprints() + var/list/prints = GET_ATOM_FINGERPRINTS(sniffed) if(prints) for(var/mob/living/carbon/C in GLOB.carbon_list) if(prints[md5(C.dna.unique_identity)]) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 2d19e21b559..6f31121470f 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -159,6 +159,8 @@ var/damage_deflection = 0 var/resistance_flags = NONE // INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ON_FIRE | UNACIDABLE | ACID_PROOF + /// forensics datum, contains fingerprints, fibres, blood_dna and hiddenprints on this atom + var/datum/forensics/forensics /** * Called when an atom is created in byond (built in engine proc) @@ -309,6 +311,9 @@ if(reagents) QDEL_NULL(reagents) + if(forensics) + QDEL_NULL(forensics) + orbiters = null // The component is attached to us normaly and will be deleted elsewhere LAZYCLEARLIST(overlays) @@ -888,9 +893,9 @@ var/new_blood_dna = injected_mob.get_blood_dna_list() if(!new_blood_dna) return FALSE - var/old_length = blood_DNA_length() + var/old_length = GET_ATOM_BLOOD_DNA_LENGTH(src) add_blood_DNA(new_blood_dna) - if(blood_DNA_length() == old_length) + if(GET_ATOM_BLOOD_DNA_LENGTH(src) == old_length) return FALSE return TRUE diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm index 2cbd1d0117a..0c4f8332bf3 100644 --- a/code/game/objects/effects/decals/cleanable/humans.dm +++ b/code/game/objects/effects/decals/cleanable/humans.dm @@ -52,7 +52,7 @@ return TRUE /obj/effect/decal/cleanable/blood/replace_decal(obj/effect/decal/cleanable/blood/C) - C.add_blood_DNA(return_blood_DNA()) + C.add_blood_DNA(GET_ATOM_BLOOD_DNA(src)) if (bloodiness) C.bloodiness = min((C.bloodiness + bloodiness), BLOOD_AMOUNT_PER_DECAL) return ..() diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 6efe730f822..6573ef69b1e 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -567,9 +567,9 @@ . = ..() /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()) + add_blood_DNA(GET_ATOM_BLOOD_DNA(from)) + add_fingerprint_list(GET_ATOM_FINGERPRINTS(from)) + add_hiddenprint_list(GET_ATOM_HIDDENPRINTS(from)) fingerprintslast = from.fingerprintslast //TODO bloody overlay diff --git a/code/modules/admin/verbs/hiddenprints.dm b/code/modules/admin/verbs/hiddenprints.dm index 2d87e404498..500792cc42a 100644 --- a/code/modules/admin/verbs/hiddenprints.dm +++ b/code/modules/admin/verbs/hiddenprints.dm @@ -3,7 +3,7 @@ return var/interface = "A log of every player who has touched [victim], sorted by last touch.

    " - var/victim_hiddenprints = victim.return_hiddenprints() + var/victim_hiddenprints = GET_ATOM_HIDDENPRINTS(victim) if(!islist(victim_hiddenprints)) victim_hiddenprints = list() diff --git a/code/modules/antagonists/heretic/heretic_knowledge.dm b/code/modules/antagonists/heretic/heretic_knowledge.dm index c3e9f086aa7..8f0ded9411a 100644 --- a/code/modules/antagonists/heretic/heretic_knowledge.dm +++ b/code/modules/antagonists/heretic/heretic_knowledge.dm @@ -373,7 +373,7 @@ /datum/heretic_knowledge/curse/recipe_snowflake_check(mob/living/user, list/atoms, list/selected_atoms, turf/loc) fingerprints = list() for(var/atom/requirements as anything in atoms) - fingerprints[requirements.return_fingerprints()] = 1 + fingerprints[GET_ATOM_FINGERPRINTS(requirements)] = 1 list_clear_nulls(fingerprints) // No fingerprints? No ritual diff --git a/code/modules/clothing/gloves/_gloves.dm b/code/modules/clothing/gloves/_gloves.dm index ab008846a5c..f1111075c2b 100644 --- a/code/modules/clothing/gloves/_gloves.dm +++ b/code/modules/clothing/gloves/_gloves.dm @@ -32,7 +32,7 @@ if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damagedgloves") - if(HAS_BLOOD_DNA(src)) + if(GET_ATOM_BLOOD_DNA_LENGTH(src)) . += mutable_appearance('icons/effects/blood.dmi', "bloodyhands") /obj/item/clothing/gloves/update_clothes_damaged_state(damaged_state = CLOTHING_DAMAGED) diff --git a/code/modules/clothing/head/_head.dm b/code/modules/clothing/head/_head.dm index 83585452208..b6f8596f05d 100644 --- a/code/modules/clothing/head/_head.dm +++ b/code/modules/clothing/head/_head.dm @@ -65,7 +65,7 @@ if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damagedhelmet") - if(HAS_BLOOD_DNA(src)) + if(GET_ATOM_BLOOD_DNA_LENGTH(src)) if(clothing_flags & LARGE_WORN_ICON) . += mutable_appearance('icons/effects/64x64.dmi', "helmetblood_large") else diff --git a/code/modules/clothing/masks/_masks.dm b/code/modules/clothing/masks/_masks.dm index d9c7dc8bae6..a0007239abc 100644 --- a/code/modules/clothing/masks/_masks.dm +++ b/code/modules/clothing/masks/_masks.dm @@ -50,7 +50,7 @@ if(body_parts_covered & HEAD) if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damagedmask") - if(HAS_BLOOD_DNA(src)) + if(GET_ATOM_BLOOD_DNA_LENGTH(src)) . += mutable_appearance('icons/effects/blood.dmi', "maskblood") /obj/item/clothing/mask/update_clothes_damaged_state(damaged_state = CLOTHING_DAMAGED) diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm index 08cd3288c38..0f9963342db 100644 --- a/code/modules/clothing/neck/_neck.dm +++ b/code/modules/clothing/neck/_neck.dm @@ -14,7 +14,7 @@ if(body_parts_covered & HEAD) if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damagedmask") - if(HAS_BLOOD_DNA(src)) + if(GET_ATOM_BLOOD_DNA_LENGTH(src)) . += mutable_appearance('icons/effects/blood.dmi', "maskblood") /obj/item/clothing/neck/tie diff --git a/code/modules/clothing/shoes/_shoes.dm b/code/modules/clothing/shoes/_shoes.dm index d6f93fc025e..e471bf1ee48 100644 --- a/code/modules/clothing/shoes/_shoes.dm +++ b/code/modules/clothing/shoes/_shoes.dm @@ -47,7 +47,7 @@ if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damagedshoe") - if(HAS_BLOOD_DNA(src)) + if(GET_ATOM_BLOOD_DNA_LENGTH(src)) if(clothing_flags & LARGE_WORN_ICON) . += mutable_appearance('icons/effects/64x64.dmi', "shoeblood_large") else diff --git a/code/modules/clothing/suits/_suits.dm b/code/modules/clothing/suits/_suits.dm index b384c0d573f..5d65dfb19e4 100644 --- a/code/modules/clothing/suits/_suits.dm +++ b/code/modules/clothing/suits/_suits.dm @@ -21,7 +21,7 @@ if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damaged[blood_overlay_type]") - if(HAS_BLOOD_DNA(src)) + if(GET_ATOM_BLOOD_DNA_LENGTH(src)) . += mutable_appearance('icons/effects/blood.dmi', "[blood_overlay_type]blood") var/mob/living/carbon/human/M = loc diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm index 34101e8433e..a1c5e776aae 100644 --- a/code/modules/clothing/under/_under.dm +++ b/code/modules/clothing/under/_under.dm @@ -34,7 +34,7 @@ if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damageduniform") - if(HAS_BLOOD_DNA(src)) + if(GET_ATOM_BLOOD_DNA_LENGTH(src)) . += mutable_appearance('icons/effects/blood.dmi', "uniformblood") if(accessory_overlay) . += accessory_overlay diff --git a/code/modules/detectivework/detective_work.dm b/code/modules/detectivework/detective_work.dm deleted file mode 100644 index 036ed2c4c47..00000000000 --- a/code/modules/detectivework/detective_work.dm +++ /dev/null @@ -1,114 +0,0 @@ -//CONTAINS: Suit fibers and Detective's Scanning Computer - -/atom/proc/return_fingerprints() - var/datum/component/forensics/D = GetComponent(/datum/component/forensics) - if(D) - . = D.fingerprints - -/atom/proc/return_hiddenprints() - var/datum/component/forensics/D = GetComponent(/datum/component/forensics) - if(D) - . = D.hiddenprints - -/atom/proc/return_blood_DNA() - var/datum/component/forensics/D = GetComponent(/datum/component/forensics) - if(D) - . = D.blood_DNA - -/atom/proc/blood_DNA_length() - var/datum/component/forensics/D = GetComponent(/datum/component/forensics) - if(D) - . = length(D.blood_DNA) - -/atom/proc/return_fibers() - var/datum/component/forensics/D = GetComponent(/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/M, ignoregloves = FALSE) - if (QDELING(src)) - return - 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/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_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 - G.transfer_blood-- - else if(M.blood_in_hands > 1) - old = length(M.return_blood_DNA()) - if(add_blood_DNA(M.return_blood_DNA()) && length(M.return_blood_DNA()) > old) - M.blood_in_hands-- - var/datum/component/forensics/D = AddComponent(/datum/component/forensics) - . = D.add_fibers(M) - -/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/M) - var/datum/component/forensics/D = AddComponent(/datum/component/forensics) - . = D.add_hiddenprint(M) - -/atom/proc/add_blood_DNA(list/dna) //ASSOC LIST DNA = BLOODTYPE - return FALSE - -/obj/add_blood_DNA(list/dna) - . = ..() - if(length(dna)) - . = AddComponent(/datum/component/forensics, null, null, dna) - -/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) - if(!QDELETED(B)) - 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) - blood_in_hands = rand(2, 4) - update_inv_gloves() //handles bloody hands overlays and updating - return TRUE - -/* - * Transfer all the fingerprints and hidden prints from [src] to [transfer_to]. - */ -/atom/proc/transfer_fingerprints_to(atom/transfer_to) - transfer_to.add_fingerprint_list(return_fingerprints()) - transfer_to.add_hiddenprint_list(return_hiddenprints()) - transfer_to.fingerprintslast = fingerprintslast - -/* - * Transfer all the fibers from [src] to [transfer_to]. - */ -/atom/proc/transfer_fibers_to(atom/transfer_to) - transfer_to.add_fiber_list(return_fibers()) diff --git a/code/modules/detectivework/scanner.dm b/code/modules/detectivework/scanner.dm index f3af29917d6..83513f44fb1 100644 --- a/code/modules/detectivework/scanner.dm +++ b/code/modules/detectivework/scanner.dm @@ -86,8 +86,8 @@ //Make our lists var/list/fingerprints = list() - var/list/blood = A.return_blood_DNA() - var/list/fibers = A.return_fibers() + var/list/blood = GET_ATOM_BLOOD_DNA(A) + var/list/fibers = GET_ATOM_FIBRES(A) var/list/reagents = list() var/target_name = A.name @@ -102,7 +102,7 @@ else if(!ismob(A)) - fingerprints = A.return_fingerprints() + fingerprints = GET_ATOM_FINGERPRINTS(A) // Only get reagents from non-mobs. if(A.reagents && A.reagents.reagent_list.len) diff --git a/code/modules/forensics/_forensics.dm b/code/modules/forensics/_forensics.dm new file mode 100644 index 00000000000..70d7699b3bb --- /dev/null +++ b/code/modules/forensics/_forensics.dm @@ -0,0 +1,237 @@ +/** + * Forensics datum + * + * Placed onto atoms, and contains: + * * List of fingerprints on the atom + * * List of hidden prints (used for admins) + * * List of blood on the atom + * * List of clothing fibers on the atom + */ +/datum/forensics + /// Weakref to the parent owning this datum + var/datum/weakref/parent + /** + * List of fingerprints on this atom + * + * Formatting: + * * print = print + */ + var/list/fingerprints + /** + * List of hiddenprints on this atom + * + * Formatting: + * * ckey = realname/gloves/ckey + */ + var/list/hiddenprints + /** + * List of blood dna on this atom + * + * Formatting: + * * dna = bloodtype + */ + var/list/blood_DNA + /** + * List of clothing fibers on this atom + * + * Formatting: + * * fiber = fiber + */ + var/list/fibers + +/datum/forensics/New(atom/parent, fingerprints, hiddenprints, blood_DNA, fibers) + if(!isatom(parent)) + stack_trace("We tried adding a forensics datum to something that isnt an atom. What the hell are you doing?") + qdel(src) + return + + RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, .proc/clean_act) + + src.parent = WEAKREF(parent) + src.fingerprints = fingerprints + src.hiddenprints = hiddenprints + src.blood_DNA = blood_DNA + src.fibers = fibers + check_blood() + +/// Merges the given lists into the preexisting values +/datum/forensics/proc/inherit_new(list/fingerprints, list/hiddenprints, list/blood_DNA, list/fibers) //Use of | and |= being different here is INTENTIONAL. + if (fingerprints) + src.fingerprints = LAZY_LISTS_OR(src.fingerprints, fingerprints) + if (hiddenprints) + src.hiddenprints = LAZY_LISTS_OR(src.hiddenprints, hiddenprints) + if (blood_DNA) + src.blood_DNA = LAZY_LISTS_OR(src.blood_DNA, blood_DNA) + if (fibers) + src.fibers = LAZY_LISTS_OR(src.fibers, fibers) + check_blood() + +/datum/forensics/Destroy(force, ...) + var/atom/parent_atom = parent.resolve() + if (!isnull(parent_atom)) + UnregisterSignal(parent_atom, list(COMSIG_COMPONENT_CLEAN_ACT)) + return ..() + +/// Empties the fingerprints list +/datum/forensics/proc/wipe_fingerprints() + fingerprints = null + return TRUE + +/// Empties the blood_DNA list +/datum/forensics/proc/wipe_blood_DNA() + blood_DNA = null + return TRUE + +/// Empties the fibers list +/datum/forensics/proc/wipe_fibers() + fibers = null + return TRUE + +/// Handles cleaning up the various forensic types +/datum/forensics/proc/clean_act(datum/source, clean_types) + SIGNAL_HANDLER + + if(clean_types & CLEAN_TYPE_FINGERPRINTS) + wipe_fingerprints() + if(clean_types & CLEAN_TYPE_BLOOD) + wipe_blood_DNA() + if(clean_types & CLEAN_TYPE_FIBERS) + wipe_fibers() + +/// Adds the given list into fingerprints +/datum/forensics/proc/add_fingerprint_list(list/fingerprints) + if(!length(fingerprints)) + return + LAZYINITLIST(src.fingerprints) + for(var/fingerprint in fingerprints) //We use an associative list, make sure we don't just merge a non-associative list into ours. + src.fingerprints[fingerprint] = fingerprint + return TRUE + +/// Adds a single fingerprint +/datum/forensics/proc/add_fingerprint(mob/living/suspect, ignoregloves = FALSE) + if(!isliving(suspect)) + if(!iscameramob(suspect)) + return + if(isaicamera(suspect)) + var/mob/camera/ai_eye/ai_camera = suspect + if(!ai_camera.ai) + return + suspect = ai_camera.ai + add_hiddenprint(suspect) + if(ishuman(suspect)) + var/mob/living/carbon/human/human_suspect = suspect + add_fibers(human_suspect) + var/obj/item/gloves = human_suspect.gloves + if(gloves) //Check if the gloves (if any) hide fingerprints + if(!(gloves.body_parts_covered & HANDS) || HAS_TRAIT(gloves, TRAIT_FINGERPRINT_PASSTHROUGH) || HAS_TRAIT(human_suspect, TRAIT_FINGERPRINT_PASSTHROUGH)) + ignoregloves = TRUE + if(!ignoregloves) + human_suspect.gloves.add_fingerprint(human_suspect, ignoregloves = TRUE) //ignoregloves = TRUE to avoid infinite loop. + return + var/full_print = md5(human_suspect.dna.unique_identity) + LAZYSET(fingerprints, full_print, full_print) + return TRUE + +/// Adds the given list into fibers +/datum/forensics/proc/add_fiber_list(list/fibers) + if(!length(fibers)) + return + LAZYINITLIST(src.fibers) + for(var/fiber in fibers) //We use an associative list, make sure we don't just merge a non-associative list into ours. + src.fibers[fiber] = fiber + return TRUE + +#define ITEM_FIBER_MULTIPLIER 1.2 +#define NON_ITEM_FIBER_MULTIPLIER 1 + +/// Adds a single fiber +/datum/forensics/proc/add_fibers(mob/living/carbon/human/suspect) + var/fibertext + var/item_multiplier = isitem(src) ? ITEM_FIBER_MULTIPLIER : NON_ITEM_FIBER_MULTIPLIER + if(suspect.wear_suit) + fibertext = "Material from \a [suspect.wear_suit]." + if(prob(10 * item_multiplier) && !LAZYACCESS(fibers, fibertext)) + LAZYSET(fibers, fibertext, fibertext) + if(!(suspect.wear_suit.body_parts_covered & CHEST)) + if(suspect.w_uniform) + fibertext = "Fibers from \a [suspect.w_uniform]." + if(prob(12 * item_multiplier) && !LAZYACCESS(fibers, fibertext)) //Wearing a suit means less of the uniform exposed. + LAZYSET(fibers, fibertext, fibertext) + if(!(suspect.wear_suit.body_parts_covered & HANDS)) + if(suspect.gloves) + fibertext = "Material from a pair of [suspect.gloves.name]." + if(prob(20 * item_multiplier) && !LAZYACCESS(fibers, fibertext)) + LAZYSET(fibers, fibertext, fibertext) + else if(suspect.w_uniform) + fibertext = "Fibers from \a [suspect.w_uniform]." + if(prob(15 * item_multiplier) && !LAZYACCESS(fibers, fibertext)) + LAZYSET(fibers, fibertext, fibertext) + if(suspect.gloves) + fibertext = "Material from a pair of [suspect.gloves.name]." + if(prob(20 * item_multiplier) && !LAZYACCESS(fibers, fibertext)) + LAZYSET(fibers, fibertext, fibertext) + else if(suspect.gloves) + fibertext = "Material from a pair of [suspect.gloves.name]." + if(prob(20 * item_multiplier) && !LAZYACCESS(fibers, fibertext)) + LAZYSET(fibers, fibertext, fibertext) + return TRUE + +#undef ITEM_FIBER_MULTIPLIER +#undef NON_ITEM_FIBER_MULTIPLIER + +/// Adds the given list into hiddenprints +/datum/forensics/proc/add_hiddenprint_list(list/hiddenprints) //list(ckey = text) + if(!length(hiddenprints)) + return + LAZYINITLIST(src.hiddenprints) + for(var/hidden_print in hiddenprints) //We use an associative list, make sure we don't just merge a non-associative list into ours. + src.hiddenprints[hidden_print] = hiddenprints[hidden_print] + return TRUE + +/// Adds a single hiddenprint +/datum/forensics/proc/add_hiddenprint(mob/suspect) + if(!isliving(suspect)) + if(!iscameramob(suspect)) + return + if(isaicamera(suspect)) + var/mob/camera/ai_eye/ai_camera = suspect + if(!ai_camera.ai) + return + suspect = ai_camera.ai + if(!suspect.key) + return + var/has_gloves = "" + if(ishuman(suspect)) + var/mob/living/carbon/human/human_suspect = suspect + if(human_suspect.gloves) + has_gloves = "(gloves)" + var/current_time = time_stamp() + if(!LAZYACCESS(hiddenprints, suspect.key)) + LAZYSET(hiddenprints, suspect.key, "First: \[[current_time]\] \"[suspect.real_name]\"[has_gloves]. Ckey: [suspect.ckey]") + else + var/last_stamp_pos = findtext(LAZYACCESS(hiddenprints, suspect.key), "\nLast: ") + if(last_stamp_pos) + LAZYSET(hiddenprints, suspect.key, copytext(hiddenprints[suspect.key], 1, last_stamp_pos)) + hiddenprints[suspect.key] += "\nLast: \[[current_time]\] \"[suspect.real_name]\"[has_gloves]. Ckey: [suspect.ckey]" //made sure to be existing by if(!LAZYACCESS);else + var/atom/parent_atom = parent.resolve() + parent_atom.fingerprintslast = suspect.ckey + return TRUE + +/// Adds the given list into blood_DNA +/datum/forensics/proc/add_blood_DNA(list/blood_DNA) + if(!length(blood_DNA)) + return + LAZYINITLIST(src.blood_DNA) + for(var/gene in blood_DNA) + src.blood_DNA[gene] = blood_DNA[gene] + check_blood() + return TRUE + +/// Updates the blood displayed on parent +/datum/forensics/proc/check_blood() + if(!isitem(parent.resolve())) + return + if(!length(blood_DNA)) + return + var/atom/parent_atom = parent.resolve() + parent_atom.AddElement(/datum/element/decal/blood) diff --git a/code/modules/forensics/forensics_helpers.dm b/code/modules/forensics/forensics_helpers.dm new file mode 100644 index 00000000000..155c6ab6788 --- /dev/null +++ b/code/modules/forensics/forensics_helpers.dm @@ -0,0 +1,122 @@ +/// Adds a list of fingerprints to the atom +/atom/proc/add_fingerprint_list(list/fingerprints_to_add) //ASSOC LIST FINGERPRINT = FINGERPRINT + if (isnull(fingerprints_to_add)) + return + if (forensics) + forensics.inherit_new(fingerprints = fingerprints_to_add) + else + forensics = new(src, fingerprints = fingerprints_to_add) + return TRUE + +/// Adds a single fingerprint to the atom +/atom/proc/add_fingerprint(mob/suspect, ignoregloves = FALSE) //Set ignoregloves to add prints irrespective of the mob having gloves on. + if (QDELING(src)) + return + if (isnull(forensics)) + forensics = new(src) + forensics.add_fingerprint(suspect, ignoregloves) + return TRUE + +/// Add a list of fibers to the atom +/atom/proc/add_fiber_list(list/fibers_to_add) //ASSOC LIST FIBERTEXT = FIBERTEXT + if (isnull(fibers_to_add)) + return + if (forensics) + forensics.inherit_new(fibers = fibers_to_add) + else + forensics = new(src, fibers = fibers_to_add) + return TRUE + +/// Adds a single fiber to the atom +/atom/proc/add_fibers(mob/living/carbon/human/suspect) + var/old = 0 + if(suspect.gloves && istype(suspect.gloves, /obj/item/clothing)) + var/obj/item/clothing/gloves/suspect_gloves = suspect.gloves + old = length(GET_ATOM_BLOOD_DNA(suspect_gloves)) + if(suspect_gloves.transfer_blood > 1) //bloodied gloves transfer blood to touched objects + if(add_blood_DNA(GET_ATOM_BLOOD_DNA(suspect_gloves)) && GET_ATOM_BLOOD_DNA_LENGTH(suspect_gloves) > old) //only reduces the bloodiness of our gloves if the item wasn't already bloody + suspect_gloves.transfer_blood -= 1 + else if(suspect.blood_in_hands > 1) + old = length(GET_ATOM_BLOOD_DNA(suspect)) + if(add_blood_DNA(GET_ATOM_BLOOD_DNA(suspect)) && GET_ATOM_BLOOD_DNA_LENGTH(suspect) > old) + suspect.blood_in_hands -= 1 + if (isnull(forensics)) + forensics = new(src) + forensics.add_fibers(suspect) + return TRUE + +/// Adds a list of hiddenprints to the atom +/atom/proc/add_hiddenprint_list(list/hiddenprints_to_add) //NOTE: THIS IS FOR ADMINISTRATION FINGERPRINTS, YOU MUST CUSTOM SET THIS TO INCLUDE CKEY/REAL NAMES! CHECK FORENSICS.DM + if (isnull(hiddenprints_to_add)) + return + if (forensics) + forensics.inherit_new(hiddenprints = hiddenprints_to_add) + else + forensics = new(src, hiddenprints = hiddenprints_to_add) + return TRUE + +/// Adds a single hiddenprint to the atom +/atom/proc/add_hiddenprint(mob/suspect) + if (isnull(forensics)) + forensics = new(src) + forensics.add_hiddenprint(suspect) + return TRUE + +/// Adds blood dna to the atom +/atom/proc/add_blood_DNA(list/blood_DNA_to_add) //ASSOC LIST DNA = BLOODTYPE + return FALSE + +/obj/add_blood_DNA(list/blood_DNA_to_add) + . = ..() + if (isnull(blood_DNA_to_add)) + return . + if (forensics) + forensics.inherit_new(blood_DNA = blood_DNA_to_add) + else + forensics = new(src, blood_DNA = blood_DNA_to_add) + return TRUE + +/obj/item/clothing/gloves/add_blood_DNA(list/blood_dna, list/datum/disease/diseases) + transfer_blood = rand(2, 4) + return ..() + +/turf/add_blood_DNA(list/blood_dna, list/datum/disease/diseases) + var/obj/effect/decal/cleanable/blood/splatter/blood_splatter = locate() in src + if(!blood_splatter) + blood_splatter = new /obj/effect/decal/cleanable/blood/splatter(src, diseases) + if(!QDELETED(blood_splatter)) + blood_splatter.add_blood_DNA(blood_dna) //give blood info to the blood decal. + return TRUE //we bloodied the floor + return FALSE + +/mob/living/carbon/human/add_blood_DNA(list/blood_DNA_to_add, list/datum/disease/diseases) + if(wear_suit) + wear_suit.add_blood_DNA(blood_DNA_to_add) + update_inv_wear_suit() + else if(w_uniform) + w_uniform.add_blood_DNA(blood_DNA_to_add) + update_inv_w_uniform() + if(gloves) + var/obj/item/clothing/gloves/mob_gloves = gloves + mob_gloves.add_blood_DNA(blood_DNA_to_add) + else if(length(blood_DNA_to_add)) + if (isnull(forensics)) + forensics = new(src) + forensics.inherit_new(blood_DNA = blood_DNA_to_add) + blood_in_hands = rand(2, 4) + update_inv_gloves() + return TRUE + +/* + * Transfer all the fingerprints and hidden prints from [src] to [transfer_to]. + */ +/atom/proc/transfer_fingerprints_to(atom/transfer_to) + transfer_to.add_fingerprint_list(GET_ATOM_FINGERPRINTS(src)) + transfer_to.add_hiddenprint_list(GET_ATOM_HIDDENPRINTS(src)) + transfer_to.fingerprintslast = fingerprintslast + +/* + * Transfer all the fibers from [src] to [transfer_to]. + */ +/atom/proc/transfer_fibers_to(atom/transfer_to) + transfer_to.add_fiber_list(GET_ATOM_FIBRES(src)) diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index 799c699cdaa..2ca05a57026 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -326,7 +326,7 @@ 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 = GET_ATOM_BLOOD_DNA(drop) //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()) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 2f576c8e29c..497bc5e4feb 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1398,7 +1398,7 @@ if(!isturf(loc)) return var/obj/effect/decal/cleanable/blood/hitsplatter/our_splatter = new(loc) - our_splatter.add_blood_DNA(return_blood_DNA()) + our_splatter.add_blood_DNA(GET_ATOM_BLOOD_DNA(src)) our_splatter.blood_dna_info = get_blood_dna_list() var/turf/targ = get_ranged_target_turf(src, splatter_direction, splatter_strength) our_splatter.fly_towards(targ, splatter_strength) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index c8bbffe620d..4ad62a57204 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -46,11 +46,10 @@ if(!(I.item_flags & ABSTRACT) && !(I.item_flags & EXAMINE_SKIP)) . += "[t_He] [t_is] holding [I.get_examine_string(user)] in [t_his] [get_held_index_name(get_held_index_of_item(I))]." - var/datum/component/forensics/FR = GetComponent(/datum/component/forensics) //gloves if(gloves && !(obscured & ITEM_SLOT_GLOVES) && !(gloves.item_flags & EXAMINE_SKIP)) . += "[t_He] [t_has] [gloves.get_examine_string(user)] on [t_his] hands." - else if(FR && length(FR.blood_DNA)) + else if(GET_ATOM_BLOOD_DNA_LENGTH(src)) if(num_hands) . += span_warning("[t_He] [t_has] [num_hands > 1 ? "" : "a"] blood-stained hand[num_hands > 1 ? "s" : ""]!") diff --git a/code/modules/mob/living/simple_animal/bot/hygienebot.dm b/code/modules/mob/living/simple_animal/bot/hygienebot.dm index a1d9ab81793..f4527a55902 100644 --- a/code/modules/mob/living/simple_animal/bot/hygienebot.dm +++ b/code/modules/mob/living/simple_animal/bot/hygienebot.dm @@ -211,7 +211,7 @@ for(var/X in list(ITEM_SLOT_HEAD, ITEM_SLOT_MASK, ITEM_SLOT_ICLOTHING, ITEM_SLOT_OCLOTHING, ITEM_SLOT_FEET)) var/obj/item/I = L.get_item_by_slot(X) - if(I && HAS_BLOOD_DNA(I)) + if(I && GET_ATOM_BLOOD_DNA_LENGTH(I)) return FALSE return TRUE diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm index 2dd22bd7571..3447985e3be 100644 --- a/code/modules/mob/living/simple_animal/bot/mulebot.dm +++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm @@ -487,7 +487,7 @@ if(!last_move || isspaceturf(oldLoc)) //if we didn't sucessfully move, or if our old location was a spaceturf. return var/obj/effect/decal/cleanable/blood/tracks/B = new(oldLoc) - B.add_blood_DNA(return_blood_DNA()) + B.add_blood_DNA(GET_ATOM_BLOOD_DNA(src)) B.setDir(direct) bloodiness-- diff --git a/tgstation.dme b/tgstation.dme index bdb40cc8c55..1f7009d1bc6 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -290,6 +290,7 @@ #include "code\__HELPERS\dna.dm" #include "code\__HELPERS\files.dm" #include "code\__HELPERS\filters.dm" +#include "code\__HELPERS\forensics.dm" #include "code\__HELPERS\game.dm" #include "code\__HELPERS\global_lists.dm" #include "code\__HELPERS\guid.dm" @@ -724,7 +725,6 @@ #include "code\datums\components\explodable.dm" #include "code\datums\components\faction_granter.dm" #include "code\datums\components\force_move.dm" -#include "code\datums\components\forensics.dm" #include "code\datums\components\fov_handler.dm" #include "code\datums\components\fullauto.dm" #include "code\datums\components\gas_leaker.dm" @@ -2693,7 +2693,6 @@ #include "code\modules\clothing\under\jobs\Plasmaman\engineering.dm" #include "code\modules\clothing\under\jobs\Plasmaman\medsci.dm" #include "code\modules\clothing\under\jobs\Plasmaman\security.dm" -#include "code\modules\detectivework\detective_work.dm" #include "code\modules\detectivework\evidence.dm" #include "code\modules\detectivework\scanner.dm" #include "code\modules\discord\accountlink.dm" @@ -2860,6 +2859,8 @@ #include "code\modules\food_and_drinks\restaurant\custom_order.dm" #include "code\modules\food_and_drinks\restaurant\generic_venues.dm" #include "code\modules\food_and_drinks\restaurant\customers\_customer.dm" +#include "code\modules\forensics\_forensics.dm" +#include "code\modules\forensics\forensics_helpers.dm" #include "code\modules\holiday\easter.dm" #include "code\modules\holiday\foreign_calendar.dm" #include "code\modules\holiday\holidays.dm"