From 9e732afe6300a608f571067fbae187adc048ccfc Mon Sep 17 00:00:00 2001
From: Casper3667 <8396443+Casper3667@users.noreply.github.com>
Date: Mon, 17 Jan 2022 16:51:52 +0100
Subject: [PATCH] Changes how forensic machine reports works (#12868)
---
code/modules/clothing/clothing.dm | 4 +-
.../detectivework/microscope/dnascanner.dm | 12 ++--
.../detectivework/microscope/microscope.dm | 47 ++++++++-----
.../detectivework/tools/evidencebag.dm | 4 +-
.../detectivework/tools/sample_kits.dm | 67 ++++++++++++++-----
code/modules/detectivework/tools/swabs.dm | 14 ++--
code/modules/mob/living/carbon/human/human.dm | 2 +-
.../mob/living/carbon/human/human_defines.dm | 2 +-
code/modules/projectiles/guns/projectile.dm | 4 +-
html/changelogs/ForensicReports.yml | 10 +++
10 files changed, 113 insertions(+), 53 deletions(-)
create mode 100644 html/changelogs/ForensicReports.yml
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 11f90e3a2a4..ed6f0910b7c 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -6,7 +6,7 @@
var/flash_protection = FLASH_PROTECTION_NONE // Sets the item's level of flash protection.
var/tint = TINT_NONE // Sets the item's level of visual impairment tint.
var/list/species_restricted = null //Only these species can wear this kit.
- var/gunshot_residue //Used by forensics.
+ var/list/gunshot_residue //Used by forensics.
var/list/accessories
var/list/valid_accessory_slots
@@ -56,7 +56,7 @@
// Aurora forensics port.
/obj/item/clothing/clean_blood()
. = ..()
- gunshot_residue = null
+ LAZYCLEARLIST(gunshot_residue)
/obj/item/proc/negates_gravity()
return 0
diff --git a/code/modules/detectivework/microscope/dnascanner.dm b/code/modules/detectivework/microscope/dnascanner.dm
index 6ce527e22a1..3eba6060a12 100644
--- a/code/modules/detectivework/microscope/dnascanner.dm
+++ b/code/modules/detectivework/microscope/dnascanner.dm
@@ -99,7 +99,7 @@
last_process_worldtime = world.time
/obj/machinery/dnaforensics/proc/complete_scan()
- visible_message("[icon2html(src, viewers(get_turf(src)))] makes an insistent chime.", range = 2)
+ visible_message(SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] makes an insistent chime."), range = 2)
update_icon()
if(bloodsamp)
var/obj/item/paper/P = new()
@@ -110,13 +110,15 @@
//dna data itself
var/data = "No scan information available."
if(bloodsamp.dna != null)
- data = "Spectometric analysis on provided sample has determined the presence of [bloodsamp.dna.len] strings of DNA.
"
+ data = "Spectometric analysis on provided sample has determined the presence of [length(bloodsamp.dna)] string\s of DNA.
"
for(var/blood in bloodsamp.dna)
- data += "Blood type: [bloodsamp.dna[blood]]
\nDNA: [blood]
"
+ if(bloodsamp.dna[blood])
+ data += "Blood type: [bloodsamp.dna[blood]]
"
+ data += "DNA: [blood]
"
else
data += "No DNA found.
"
- info = "[src] analysis report #[report_num]
"
- info += "Scanned item:
[bloodsamp.name]
[bloodsamp.desc]
" + data
+ info = "[src] analysis report #[report_num]
"
+ info += "Scanned item: [bloodsamp.name]
" + data
P.set_content_unsafe(pname, info)
print(P)
scanning = 0
diff --git a/code/modules/detectivework/microscope/microscope.dm b/code/modules/detectivework/microscope/microscope.dm
index 91a4536ae6c..fd735214aef 100644
--- a/code/modules/detectivework/microscope/microscope.dm
+++ b/code/modules/detectivework/microscope/microscope.dm
@@ -10,7 +10,9 @@
density = 1
var/obj/item/sample = null
- var/report_num = 0
+ var/report_fiber_num = 0
+ var/report_print_num = 0
+ var/report_gsr_num = 0
/obj/machinery/microscope/attackby(obj/item/W as obj, mob/user as mob)
@@ -43,47 +45,56 @@
var/info
report.stamped = list(/obj/item/stamp)
report.overlays = list("paper_stamped")
- report_num++
if(istype(sample, /obj/item/forensics/slide))
var/obj/item/forensics/slide/slide = sample
if(slide.has_swab)
var/obj/item/forensics/swab/swab = slide.has_swab
-
- pname = "GSR report #[report_num]"
- info = "Scanned item:
[swab.name]
"
-
- if(swab.gsr)
- info += "Residue from a [swab.gsr] bullet detected."
+ report_gsr_num++
+ pname = "GSR report #[report_gsr_num]"
+ info = "GSR anaylsis report #[report_gsr_num]
"
+ if(length(swab.gsr))
+ info += "Residue analysis of the [swab.name] has determined the presence of the following residues."
+ for(var/gsr in swab.gsr)
+ info += "- Residue from a [gsr] bullet detected.
"
+ info += "
"
else
info += "No gunpowder residue found."
else if(slide.has_sample)
var/obj/item/sample/fibers/fibers = slide.has_sample
- pname = "Fiber report #[report_num]"
- info = "Scanned item:
[initial(fibers.name)]
"
+ report_fiber_num++
+ pname = "Fiber report #[report_fiber_num]"
if(fibers.evidence)
- info = "Molecular analysis on [fibers.name] has determined the presence of unique fiber strings.
"
+ info = "Fiber anaylsis report #[report_fiber_num]
"
+ info += "Source locations: "
+ info += "[english_list(fibers.source, "no sources were found", ", ", ", ", "")].
"
+ info += "Molecular analysis on [fibers.name] has determined the presence of unique fiber strings."
for(var/fiber in fibers.evidence)
- info += SPAN_NOTICE("Most likely match for fibers: [fiber]
")
+ info += "- Most likely match for fibers: [fiber]
"
+ info += "
"
else
info += "No fibers found."
else
- pname = "Empty slide report #[report_num]"
+ pname = "Empty slide report #[report_fiber_num]"
info = "Evidence suggests that there's nothing in this slide."
else if(istype(sample, /obj/item/sample/print))
- pname = "Fingerprint report #[report_num]"
- info = "Fingerprint analysis report #[report_num]: [sample.name]
"
+ report_print_num++
+ pname = "Fingerprint report #[report_print_num]"
var/obj/item/sample/print/card = sample
+ info = "Fingerprint analysis report #[report_print_num]
"
+ info += "Source locations: "
+ info += "[english_list(card.source, "no sources were found", ", ", ", ", "")].
"
if(card.evidence && card.evidence.len)
- info += "Surface analysis has determined unique fingerprint strings:
"
+ info += "Surface analysis has determined unique fingerprint strings:"
for(var/prints in card.evidence)
- info += SPAN_NOTICE("Fingerprint string: ")
+ info += "- Fingerprint string: "
if(!is_complete_print(prints))
info += "INCOMPLETE PRINT"
else
info += "[prints]"
- info += "
"
+ info += " "
+ info += "
"
else
info += "No information available."
diff --git a/code/modules/detectivework/tools/evidencebag.dm b/code/modules/detectivework/tools/evidencebag.dm
index cbf2c097253..1073821072e 100644
--- a/code/modules/detectivework/tools/evidencebag.dm
+++ b/code/modules/detectivework/tools/evidencebag.dm
@@ -102,8 +102,8 @@
/obj/item/evidencebag/attackby(obj/item/W as obj, mob/user as mob)
if(W.ispen() || istype(W, /obj/item/device/flashlight/pen))
var/tmp_label = sanitizeSafe(input(user, "Enter a label for [name]", "Label", label_text), MAX_NAME_LEN)
- if(length(tmp_label) > 15)
- to_chat(user, "The label can be at most 15 characters long.")
+ if(length(tmp_label) > MAX_NAME_LEN)
+ to_chat(user, SPAN_NOTICE("The label can be at most [MAX_NAME_LEN] characters long."))
else
to_chat(user, "You set the label to \"[tmp_label]\".")
label_text = tmp_label
diff --git a/code/modules/detectivework/tools/sample_kits.dm b/code/modules/detectivework/tools/sample_kits.dm
index bcd08995e72..15ce1012a1c 100644
--- a/code/modules/detectivework/tools/sample_kits.dm
+++ b/code/modules/detectivework/tools/sample_kits.dm
@@ -2,28 +2,32 @@
name = "forensic sample"
icon = 'icons/obj/forensics.dmi'
w_class = ITEMSIZE_TINY
- var/list/evidence = list()
+ var/list/evidence
+ var/list/source
+ var/label_text = ""
-/obj/item/sample/New(var/newloc, var/atom/supplied)
+/obj/item/sample/Initialize(var/newloc, var/atom/supplied)
..(newloc)
if(supplied)
copy_evidence(supplied)
- name = "[initial(name)] (\the [initial(supplied.name)])"
+ name = "[initial(name)] ([supplied.get_swab_name()])"
+ LAZYADD(source, supplied.get_swab_name())
-/obj/item/sample/print/New(var/newloc, var/atom/supplied)
+/obj/item/sample/print/Initialize(var/newloc, var/atom/supplied)
..(newloc, supplied)
- if(evidence && evidence.len)
+ if(LAZYLEN(evidence))
icon_state = "fingerprint1"
/obj/item/sample/proc/copy_evidence(var/atom/supplied)
if(supplied.suit_fibers && supplied.suit_fibers.len)
- evidence = supplied.suit_fibers.Copy()
+ LAZYADD(evidence, supplied.suit_fibers.Copy())
supplied.suit_fibers.Cut()
/obj/item/sample/proc/merge_evidence(var/obj/item/sample/supplied, var/mob/user)
if(!supplied.evidence || !supplied.evidence.len)
return 0
- evidence |= supplied.evidence
+ LAZYDISTINCTADD(evidence, supplied.evidence)
+ LAZYDISTINCTADD(source, supplied.source)
name = "[initial(name)] (combined)"
to_chat(user, SPAN_NOTICE("You transfer the contents of \the [initial(supplied.name)] into \the [src]."))
return 1
@@ -32,10 +36,11 @@
if(!supplied.evidence || !supplied.evidence.len)
return 0
for(var/print in supplied.evidence)
- if(evidence[print])
- evidence[print] = stringmerge(evidence[print],supplied.evidence[print])
+ if(LAZYISIN(evidence, print))
+ LAZYSET(evidence, print, stringmerge(evidence[print],supplied.evidence[print]))
else
- evidence[print] = supplied.evidence[print]
+ LAZYSET(evidence, print, supplied.evidence[print])
+ LAZYDISTINCTADD(source, supplied.source)
name = "[initial(name)] (combined)"
to_chat(user, SPAN_NOTICE("You overlay \the [src] and \the [initial(supplied.name)], combining the print records."))
return 1
@@ -46,8 +51,38 @@
if(merge_evidence(O, user))
qdel(O)
return 1
+ else if (O.ispen())
+ var/tmp_label = sanitizeSafe(input(user, "Enter a label for [name]", "Label", label_text), MAX_NAME_LEN)
+ if(length(tmp_label) > MAX_NAME_LEN)
+ to_chat(user, SPAN_WARNING("The label can be at most [MAX_NAME_LEN] characters long."))
+ else
+ to_chat(user, SPAN_NOTICE("You set the label to \"[tmp_label]\"."))
+ label_text = tmp_label
+ update_name_label()
+ return
return ..()
+/obj/item/sample/proc/update_name_label()
+ if(label_text == null)
+ name = initial(name)
+ else
+ name = "[initial(name)] ([label_text])"
+
+/obj/item/sample/Initialize(var/newloc, var/atom/supplied)
+ ..(newloc)
+ if(supplied)
+ copy_evidence(supplied)
+ name = "[initial(name)] ([supplied.get_swab_name()])"
+ LAZYADD(source, supplied.get_swab_name())
+
+/atom/proc/get_swab_name()
+ return "\the [initial(name)]"
+
+/obj/machinery/door/get_swab_name()
+ if(name != initial(name))
+ return "\the [initial(name)]: [name]"
+ return ..()
+
/obj/item/sample/fibers
name = "fiber bag"
desc = "Used to hold fiber evidence for the detective."
@@ -65,7 +100,7 @@
item_state = "paper"
/obj/item/sample/print/attack_self(var/mob/user)
- if(evidence && evidence.len)
+ if(LAZYLEN(evidence))
return
if(!ishuman(user))
return
@@ -76,7 +111,8 @@
to_chat(user, SPAN_NOTICE("You firmly press your fingertips onto the card."))
var/fullprint = H.get_full_print()
- evidence[fullprint] = fullprint
+ LAZYSET(evidence, fullprint, fullprint)
+ LAZYADD(source, "[H.name]")
name = "[initial(name)] (\the [H])"
icon_state = "fingerprint1"
@@ -85,7 +121,7 @@
if(!ishuman(M))
return ..()
- if(evidence && evidence.len)
+ if(LAZYLEN(evidence))
return 0
var/mob/living/carbon/human/H = M
@@ -112,8 +148,9 @@
return 1
user.visible_message("[user] takes a copy of \the [H]'s fingerprints.")
var/fullprint = H.get_full_print()
- evidence[fullprint] = fullprint
+ LAZYSET(evidence, fullprint, fullprint)
copy_evidence(src)
+ LAZYADD(source, "[H.name]")
name = "[initial(name)] (\the [H])"
icon_state = "fingerprint1"
return 1
@@ -122,7 +159,7 @@
/obj/item/sample/print/copy_evidence(var/atom/supplied)
if(supplied.fingerprints && supplied.fingerprints.len)
for(var/print in supplied.fingerprints)
- evidence[print] = supplied.fingerprints[print]
+ LAZYSET(evidence, print, supplied.fingerprints[print])
supplied.fingerprints.Cut()
/obj/item/forensics/sample_kit
diff --git a/code/modules/detectivework/tools/swabs.dm b/code/modules/detectivework/tools/swabs.dm
index 2608803356e..c17890e0dd6 100644
--- a/code/modules/detectivework/tools/swabs.dm
+++ b/code/modules/detectivework/tools/swabs.dm
@@ -14,7 +14,7 @@
\n\nGSR samples are put in a slide and examined in a microscope. \
\nBlood and DNA samples are checked in the DNA analyzer"
icon_state = "swab"
- var/gsr = 0
+ var/list/gsr
var/list/dna
var/used
drop_sound = 'sound/items/drop/glass.ogg'
@@ -70,17 +70,17 @@
return
if(H.gloves)
var/obj/item/clothing/B = H.gloves
- if(!B.gunshot_residue)
+ if(!LAZYLEN(B.gunshot_residue))
to_chat(user, SPAN_WARNING("There is no residue on [H]'s [B]."))
return
user.visible_message("[user] swabs [H]'s [B] for a sample.")
- gsr = B.gunshot_residue
+ LAZYADD(gsr, B.gunshot_residue)
else
- if(!H.gunshot_residue)
+ if(!LAZYLEN(H.gunshot_residue))
to_chat(user, SPAN_WARNING("There is no residue on [H]'s palms."))
return
user.visible_message("[user] swabs [H]'s palm for a sample.")
- gsr = H.gunshot_residue
+ LAZYADD(gsr, H.gunshot_residue)
sample_type = "GSR"
else
return
@@ -134,10 +134,10 @@
if (EVIDENCE_TYPE_GSR)
var/obj/item/clothing/B = A
- if(!istype(B) || !B.gunshot_residue)
+ if(!istype(B) || !LAZYLEN(B.gunshot_residue))
to_chat(user, SPAN_WARNING("There is no residue on \the [A]."))
return
- gsr = B.gunshot_residue
+ LAZYADD(gsr, B.gunshot_residue)
sample_type = "residue"
if (EVIDENCE_TYPE_SALIVA)
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 003517cdd9d..b2692cf7fa1 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -1291,7 +1291,7 @@
update_inv_gloves(1)
germ_level = 0
- gunshot_residue = null
+ LAZYCLEARLIST(gunshot_residue)
if(clean_feet && !shoes)
footprint_color = null
feet_blood_DNA = null
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index e8f1e24542e..79cb756fe8c 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -95,7 +95,7 @@
var/hand_blood_color
var/list/flavor_texts = list()
- var/gunshot_residue
+ var/list/gunshot_residue
var/pulling_punches // Are you trying not to hurt your opponent?
mob_bump_flag = HUMAN
diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm
index 7bd1e49757b..a16f8309807 100644
--- a/code/modules/projectiles/guns/projectile.dm
+++ b/code/modules/projectiles/guns/projectile.dm
@@ -101,10 +101,10 @@
var/mob/living/carbon/human/H = loc
if(istype(H))
if(!istype(H.gloves, /obj/item/clothing))
- H.gunshot_residue = chambered.caliber
+ LAZYDISTINCTADD(H.gunshot_residue, chambered.caliber)
else
var/obj/item/clothing/G = H.gloves
- G.gunshot_residue = chambered.caliber
+ LAZYDISTINCTADD(G.gunshot_residue, chambered.caliber)
switch(handle_casings)
if(DELETE_CASINGS)
diff --git a/html/changelogs/ForensicReports.yml b/html/changelogs/ForensicReports.yml
new file mode 100644
index 00000000000..c524c832e29
--- /dev/null
+++ b/html/changelogs/ForensicReports.yml
@@ -0,0 +1,10 @@
+author: TheGreyWolf
+
+delete-after: True
+
+changes:
+ - rscadd: "Fingerprint & fiber reports now show all source locations, even when combined and doors will have the door's name attached."
+ - rscadd: "Added the ability to rename fingerprint cards & fiber bags."
+ - tweak: "Changed the layout of the various forensic machine reports."
+ - tweak: "Each report from the forensic machines are now numbered per evidence type (fiber, fingerprint, GSR, DNA) rather than combined amount of reports."
+ - bugfix: "Gunshot residue now shows all residue on something rather than only the most recent."