From e79871e40bea969f659767bab2b31435a2d007b0 Mon Sep 17 00:00:00 2001 From: SkyMarshal Date: Sat, 2 Jun 2012 13:28:47 -0700 Subject: [PATCH] Detective improvements, take two. --- baystation12.dme | 2 + code/defines/obj/weapon.dm | 2 +- code/game/atom_procs.dm | 23 +- code/game/objects/devices/scanners.dm | 160 -------- code/modules/DetectiveWork/detective_work.dm | 359 +++++------------- code/modules/DetectiveWork/evidence.dm | 5 +- .../DetectiveWork/footprints_and_rag.dm | 207 ++++++++++ code/modules/DetectiveWork/scanner.dm | 172 +++++++++ 8 files changed, 499 insertions(+), 431 deletions(-) create mode 100644 code/modules/DetectiveWork/footprints_and_rag.dm create mode 100644 code/modules/DetectiveWork/scanner.dm diff --git a/baystation12.dme b/baystation12.dme index 5828ec80391..98ba31217bb 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -879,6 +879,8 @@ #include "code\modules\customitems\item_spawning.dm" #include "code\modules\DetectiveWork\detective_work.dm" #include "code\modules\DetectiveWork\evidence.dm" +#include "code\modules\DetectiveWork\footprints_and_rag.dm" +#include "code\modules\DetectiveWork\scanner.dm" #include "code\modules\flufftext\Dreaming.dm" #include "code\modules\flufftext\Hallucination.dm" #include "code\modules\flufftext\TextFilters.dm" diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm index a36f4bed2ac..e8eba76c3d4 100644 --- a/code/defines/obj/weapon.dm +++ b/code/defines/obj/weapon.dm @@ -1017,7 +1017,7 @@ icon_state = "cone" /obj/item/weapon/paper - name = "Paper" + name = "\improper Paper" icon = 'paper.dmi' icon_state = "paper" var/info = null diff --git a/code/game/atom_procs.dm b/code/game/atom_procs.dm index 15b56014d13..55bbb859d07 100644 --- a/code/game/atom_procs.dm +++ b/code/game/atom_procs.dm @@ -104,13 +104,6 @@ if(isnull(M.key)) return if (!( src.flags ) & FPRINT) return - //Smudge up dem prints some - for(var/P in fingerprints) - var/test_print = stars(fingerprints[P], rand(85,95)) - if(stringpercent(test_print) == 32) //She's full of stars! (No actual print left) - fingerprints.Remove(P) - else - fingerprints[P] = test_print if (ishuman(M)) //Add the list if it does not exist. if(!fingerprintshidden) @@ -142,6 +135,15 @@ return 0 else if(H.gloves && !istype(H.gloves, /obj/item/clothing/gloves/latex) && !istype(H.gloves, /obj/item/clothing/gloves/fingerless)) return 0 + //Smudge up dem prints some + for(var/P in fingerprints) + if(P == md5(H.dna.uni_identity)) + continue + var/test_print = stars(fingerprints[P], rand(85,95)) + if(stringpercent(test_print) == 32) //She's full of stars! (No actual print left) + fingerprints.Remove(P) + else + fingerprints[P] = test_print //More adminstuffz if(fingerprintslast != H.key) fingerprintshidden += text("Real name: [], Key: []",H.real_name, H.key) @@ -160,6 +162,13 @@ fingerprints[full_print] = stringmerge(print, stars(full_print, (H.gloves ? rand(10,20) : rand(25,40)))) return 1 else + //Smudge up dem prints some + for(var/P in fingerprints) + var/test_print = stars(fingerprints[P], rand(85,95)) + if(stringpercent(test_print) == 32) //She's full of stars! (No actual print left) + fingerprints.Remove(P) + else + fingerprints[P] = test_print if(fingerprintslast != M.key) fingerprintshidden += text("Real name: [], Key: []",M.real_name, M.key) fingerprintslast = M.key diff --git a/code/game/objects/devices/scanners.dm b/code/game/objects/devices/scanners.dm index f1e42988ef0..13b69e2db33 100644 --- a/code/game/objects/devices/scanners.dm +++ b/code/game/objects/devices/scanners.dm @@ -60,166 +60,6 @@ MASS SPECTROMETER if(M) M.invisibility = 2 -/obj/item/device/detective_scanner - name = "Scanner" - desc = "Used to scan objects for DNA and fingerprints." - icon_state = "forensic1" - var/amount = 20.0 - var/list/stored = list() - w_class = 3.0 - item_state = "electronic" - flags = FPRINT | TABLEPASS | CONDUCT | USEDELAY - slot_flags = SLOT_BELT - - attackby(obj/item/weapon/f_card/W as obj, mob/user as mob) - ..() - if (istype(W, /obj/item/weapon/f_card)) - if (W.fingerprints) - return - if (src.amount == 20) - return - if (W.amount + src.amount > 20) - src.amount = 20 - W.amount = W.amount + src.amount - 20 - else - src.amount += W.amount - //W = null - del(W) - add_fingerprint(user) - if (W) - W.add_fingerprint(user) - return - - attack(mob/living/carbon/human/M as mob, mob/user as mob) - if (!ishuman(M)) - user << "\red [M] is not human and cannot have the fingerprints." - return 0 - if (( !( istype(M.dna, /datum/dna) ) || M.gloves) ) - user << "\blue No fingerprints found on [M]" - return 0 - else - if (src.amount < 1) - user << text("\blue Fingerprints scanned on [M]. Need more cards to print.") - else - src.amount-- - var/obj/item/weapon/f_card/F = new /obj/item/weapon/f_card( user.loc ) - F.amount = 1 - F.add_fingerprint(M) - F.icon_state = "fingerprint1" - F.name = text("FPrintC- '[M.name]'") - - user << "\blue Done printing." - user << "\blue [M]'s Fingerprints: [md5(M.dna.uni_identity)]" - if ( !M.blood_DNA || !M.blood_DNA.len ) - user << "\blue No blood found on [M]" - if(M.blood_DNA) - del(M.blood_DNA) - else - user << "\blue Blood found on [M]. Analysing..." - spawn(15) - for(var/blood in M.blood_DNA) - user << "\blue Blood type: [M.blood_DNA[blood]]\nDNA: [blood]" - return - - afterattack(atom/A as obj|turf|area, mob/user as mob) - if(!in_range(A,user)) - return - if(loc != user) - return - if(istype(A,/obj/machinery/computer/forensic_scanning)) //breaks shit. - return - if(istype(A,/obj/item/weapon/f_card)) - user << "The scanner displays on the screen: \"ERROR 43: Object on Excluded Object List.\"" - return - - add_fingerprint(user) - - - //Special case for blood splaters. - if (istype(A, /obj/effect/decal/cleanable/blood) || istype(A, /obj/effect/rune)) - if(!isnull(A.blood_DNA)) - for(var/blood in A.blood_DNA) - user << "\blue Blood type: [A.blood_DNA[blood]]\nDNA: [blood]" - return - - //General - if ((!A.fingerprints || !A.fingerprints.len) && !A.suit_fibers && !A.blood_DNA) - user.visible_message("\The [user] scans \the [A] with \a [src], the air around [user.get_gender_form("it")] humming[prob(70) ? " gently." : "."]" ,\ - "\blue Unable to locate any fingerprints, materials, fibers, or blood on [A]!",\ - "You hear a faint hum of electrical equipment.") - return 0 - - if(add_data(A)) - user << "\blue Object already in internal memory. Consolidating data..." - return - - - //PRINTS - if(!A.fingerprints || !A.fingerprints.len) - if(A.fingerprints) - del(A.fingerprints) - else - user << "\blue Isolated [A.fingerprints.len] fingerprints: Data Stored: Scan with Hi-Res Forensic Scanner to retrieve." - - //FIBERS - if(A.suit_fibers) - user << "\blue Fibers/Materials Data Stored: Scan with Hi-Res Forensic Scanner to retrieve." - - //Blood - if (A.blood_DNA) - user << "\blue Blood found on [A]. Analysing..." - spawn(15) - for(var/blood in A.blood_DNA) - user << "Blood type: \red [A.blood_DNA[blood]] \t \black DNA: \red [blood]" - if(prob(5)) - user.visible_message("\The [user] scans \the [A] with \a [src], the air around [user.get_gender_form("it")] humming[prob(70) ? " gently." : "."]" ,\ - "You finish scanning \the [A].",\ - "You hear a faint hum of electrical equipment.") - return 0 - else - user.visible_message("\The [user] scans \the [A] with \a [src], the air around [user.get_gender_form("it")] humming[prob(70) ? " gently." : "."]\n[user.get_gender_form("It")] seems to perk up slightly at the readout." ,\ - "The results of the scan pique your interest.",\ - "You hear a faint hum of electrical equipment, and someone making a thoughtful noise.") - return 0 - return - - proc/add_data(atom/A as mob|obj|turf|area) - //I love hashtables. - var/list/data_entry = stored["\ref [A]"] - if(islist(data_entry)) //Yay, it was already stored! - //Merge the fingerprints. - var/list/data_prints = data_entry[1] - for(var/print in A.fingerprints) - var/merged_print = data_prints[print] - if(!merged_print) - data_prints[print] = A.fingerprints[print] - else - data_prints[print] = stringmerge(data_prints[print],A.fingerprints[print]) - - //Now the fibers - var/list/fibers = data_entry[2] - if(!fibers) - fibers = list() - if(A.suit_fibers && A.suit_fibers.len) - for(var/j = 1, j <= A.suit_fibers.len, j++) //Fibers~~~ - if(!fibers.Find(A.suit_fibers[j])) //It isn't! Add! - fibers += A.suit_fibers[j] - var/list/blood = data_entry[3] - if(!blood) - blood = list() - if(A.blood_DNA && A.blood_DNA.len) - for(var/main_blood in A.blood_DNA) - if(!blood[main_blood]) - blood[main_blood] = A.blood_DNA[blood] - return 1 - var/list/sum_list[4] //Pack it back up! - sum_list[1] = A.fingerprints - sum_list[2] = A.suit_fibers - sum_list[3] = A.blood_DNA - sum_list[4] = "\The [A] in \the [get_area(A)]" - stored["\ref [A]"] = sum_list - return 0 - /obj/item/device/healthanalyzer name = "Health Analyzer" diff --git a/code/modules/DetectiveWork/detective_work.dm b/code/modules/DetectiveWork/detective_work.dm index 4c9b20b7281..37524d9c691 100644 --- a/code/modules/DetectiveWork/detective_work.dm +++ b/code/modules/DetectiveWork/detective_work.dm @@ -1,4 +1,4 @@ -//gloves w_uniform wear_suit shoes +//CONTAINS: Suit fibers and Detective's Scanning Computer atom/var/list/suit_fibers @@ -52,7 +52,7 @@ var/const/FINGERPRINT_COMPLETE = 6 //This is the output of the stringpercent(pri //the print must be there for it to be complete. (Prints are 32 digits) obj/machinery/computer/forensic_scanning - name = "High-Res Forensic Scanning Computer" + name = "\improper High-Res Forensic Scanning Computer" icon_state = "forensic" var obj/item/scanning @@ -136,9 +136,6 @@ obj/machinery/computer/forensic_scanning return if (allowed(M)) authenticated = 1 - //usr << "\green Access Granted" - //if(!authenticated) - //usr << "\red Access Denied" if("logout") authenticated = 0 if("clear") @@ -197,10 +194,9 @@ obj/machinery/computer/forensic_scanning if(files && files.len) temp = "Criminal Evidence Database

" temp += "Consolidated data points:
" - var/i = 1 for(var/print in files) - temp += "{Dossier [i]}
" - i++ + var/list/file = files[print] + temp += "{[file[2]]}
" temp += "
{Insert Finger Print Card (To complete a Dossier)}


" else temp = "" @@ -213,22 +209,37 @@ obj/machinery/computer/forensic_scanning if("record") //Viewing a record from the "files" database. canclear = 0 if(files) - temp = "Criminal Evidence Database

" - temp += "Consolidated data points: Dossier [files.Find(href_list["identifier"])]
" var/list/dossier = files[href_list["identifier"]] + if(href_list["ren"]) + var/new_title = copytext(sanitize(input("Rename to what?", "Dossier Editing", "Dossier [files.Find(href_list["identifier"])]") as null|text),1,MAX_MESSAGE_LEN) + if(new_title) + dossier[2] = new_title + else + usr << "Illegal or blank name." + temp = "Criminal Evidence Database

" + temp += "Consolidated data points: [dossier[2]]
" var/print_string = "Fingerprints: Print not complete!
" if(stringpercent(dossier[1]) <= FINGERPRINT_COMPLETE) print_string = "Fingerprints: (80% or higher completion reached)
[dossier[1]]
" temp += print_string for(var/object in dossier) - if(object == dossier[1]) + if(object == dossier[1] || object == dossier[2]) continue temp += "
" var/list/outputs = dossier[object] - var/list/prints_len = outputs[1] + var/list/prints = outputs[1] temp += "Object: [outputs[4]]
" temp += " Fingerprints:
" - temp += "    [prints_len.len] Unique fingerprints found.
" + temp += "    [prints.len] Unique fingerprints found.
" + var/complete_prints = 0 + for(var/print in prints) + if(stringpercent(prints[print]) <= FINGERPRINT_COMPLETE) + complete_prints++ + temp += "      [prints[print]]
" + if(complete_prints) + temp += "      And [prints.len - complete_prints] unknown unique prints.
" + else + temp += "      No prints of sufficient completeness.
" var/list/fibers = outputs[2] if(fibers && fibers.len) temp += " Fibers:
" @@ -239,6 +250,7 @@ obj/machinery/computer/forensic_scanning temp += " Blood:
" for(var/named in blood) temp += "      Type: [blood[named]], DNA: [named]
" + temp += "
{Rename this Dossier}" temp += "
{Delete this Dossier}" temp += "
{Print}" else @@ -247,24 +259,33 @@ obj/machinery/computer/forensic_scanning if("databaseprint") //Printing from the "files" database. if(files) var/obj/item/weapon/paper/P = new(loc) - P.name = "Database File (Dossier [files.Find(href_list["identifier"])])" + P.name = "\improper Database File (Dossier [files.Find(href_list["identifier"])])" P.overlays += "paper_words" P.info = "Criminal Evidence Database

" - P.info += "Consolidated data points: Dossier [href_list["identifier"]]
" var/list/dossier = files[href_list["identifier"]] + P.info += "Consolidated data points: [dossier[2]]
" var/print_string = "Fingerprints: Print not complete!
" if(stringpercent(dossier[1]) <= FINGERPRINT_COMPLETE) print_string = "Fingerprints: (80% or higher completion reached)
[dossier[1]]
" P.info += print_string for(var/object in dossier) - if(object == dossier[1]) + if(object == dossier[1] || object == dossier[2]) continue P.info += "
" var/list/outputs = dossier[object] - var/list/prints_len = outputs[1] + var/list/prints = outputs[1] P.info += "Object: [outputs[4]]
" P.info += " Fingerprints:
" - P.info += "    [prints_len.len] Unique fingerprints found.
" + P.info += "    [prints.len] Unique fingerprints found.
" + var/complete_prints = 0 + for(var/print in prints) + if(stringpercent(prints[print]) <= FINGERPRINT_COMPLETE) + complete_prints++ + P.info += "      [prints[print]]
" + if(complete_prints) + P.info += "      And [prints.len - complete_prints] unknown unique prints.
" + else + P.info += "      No prints of sufficient completeness.
" var/list/fibers = outputs[2] if(fibers && fibers.len) P.info += " Fibers:
" @@ -283,11 +304,24 @@ obj/machinery/computer/forensic_scanning temp = "Auxiliary Evidence Database

" var/list/outputs = misc[href_list["identifier"]] temp += "Consolidated data points: [outputs[3]]
" + var/list/prints = outputs[4] + if(prints) + temp += " Fingerprints:
" + temp += "    [prints.len] Unique fingerprints found.
" + var/complete_prints = 0 + for(var/print in prints) + if(stringpercent(prints[print]) <= FINGERPRINT_COMPLETE) + complete_prints++ + temp += "      [prints[print]]
" + if(complete_prints) + temp += "      And [prints.len - complete_prints] unknown unique prints.
" + else + temp += "      No prints of sufficient completeness.
" var/list/fibers = outputs[1] if(fibers && fibers.len) temp += " Fibers:
" - for(var/j = 1, j <= fibers.len, j++) - temp += "      [fibers[j]]
" + for(var/fiber in fibers) + temp += "      [fiber]
" var/list/blood = outputs[2] if(blood && blood.len) temp += " Blood:
" @@ -302,15 +336,28 @@ obj/machinery/computer/forensic_scanning if(misc) var/obj/item/weapon/paper/P = new(loc) var/list/outputs = misc[href_list["identifier"]] - P.name = "Auxiliary Database File ([outputs[3]])" + P.name = "\improper Auxiliary Database File ([outputs[3]])" P.overlays += "paper_words" P.info = "Auxiliary Evidence Database

" P.info += "Consolidated data points: [outputs[3]]
" + var/list/prints = outputs[4] + if(prints) + P.info += " Fingerprints:
" + P.info += "    [prints.len] Unique fingerprints found.
" + var/complete_prints = 0 + for(var/print in prints) + if(stringpercent(prints[print]) <= FINGERPRINT_COMPLETE) + complete_prints++ + P.info += "      [prints[print]]
" + if(complete_prints) + P.info += "      And [prints.len - complete_prints] unknown unique prints.
" + else + P.info += "      No prints of sufficient completeness.
" var/list/fibers = outputs[1] if(fibers && fibers.len) P.info += " Fibers:
" - for(var/j = 1, j <= fibers.len, j++) - P.info += "      [fibers[j]]
" + for(var/fiber in fibers) + P.info += "      [fiber]
" var/list/blood = outputs[2] if(blood && blood.len) P.info += " Blood:
" @@ -361,36 +408,17 @@ obj/machinery/computer/forensic_scanning if(!scanning.fingerprints) scan_data += "No Fingerprints Found

" else - var/list/L = scanning.fingerprints - scan_data += "Isolated [L.len] Fingerprints. Loaded into database.
" + scan_data += "Isolated [scanning.fingerprints.len] Fingerprints. Loaded into database.
" add_data(scanning) if(!scanning.suit_fibers) - /*if(istype(scanning,/obj/item/device/detective_scanner)) - var/obj/item/device/detective_scanner/scanner = scanning - if(scanner.stored_name) - scan_data += "Fibers/Materials Data - [scanner.stored_name]:
" - for(var/data in scanner.stored_fibers) - scan_data += "- [data]
" - else - scan_data += "No Fibers/Materials Data
" - else*/ scan_data += "No Fibers/Materials Located
" else - /*if(istype(scanning,/obj/item/device/detective_scanner)) - var/obj/item/device/detective_scanner/scanner = scanning - if(scanner.stored_name) - scan_data += "Fibers/Materials Data - [scanner.stored_name]:
" - for(var/data in scanner.stored_fibers) - scan_data += "- [data]
" - else - scan_data += "No Fibers/Materials Data
"*/ - scan_data += "Fibers/Materials Found:
" for(var/data in scanning.suit_fibers) scan_data += "- [data]
" if(istype(scanning,/obj/item/device/detective_scanner) || (istype(scanning, /obj/item/device/pda) && scanning:cartridge && scanning:cartridge.access_security)) - scan_data += "
Data transfered from Scanner to Database.
" + scan_data += "
Data transfered from \the [scanning] to Database.
" add_data_scanner(scanning) else if(!scanning.fingerprints) scan_data += "
Add to Database?
" @@ -402,7 +430,7 @@ obj/machinery/computer/forensic_scanning if(scan_data) temp = "Scan Data Printed." var/obj/item/weapon/paper/P = new(loc) - P.name = "Scan Data ([scan_name])" + P.name = "\improper Scan Data ([scan_name])" P.info = "[scan_data]" P.overlays += "paper_words" else @@ -416,6 +444,14 @@ obj/machinery/computer/forensic_scanning add_data(scanning) else temp = "Data Transfer Failed: No Object." + if("rename") + if(!files || !files[href_list["identifier"]]) + temp = "ERROR: Record/Database not found!" + else + var/new_title = copytext(sanitize(input("Rename to what?", "Dossier Editing", "Dossier [files.Find(href_list["identifier"])]") as null|text),1,MAX_MESSAGE_LEN) + if(new_title) + var/list/file = files[href_list["identifier"]] + file[2] = new_title updateUsrDialog() ex_act() @@ -439,7 +475,7 @@ obj/machinery/computer/forensic_scanning proc/add_data(var/atom/scanned_atom) return add_data_master("\ref [scanned_atom]", scanned_atom.fingerprints,\ - scanned_atom.suit_fibers, scanned_atom.blood_DNA, scanned_atom.name) + scanned_atom.suit_fibers, scanned_atom.blood_DNA, "[scanned_atom.name] (Direct Scan)") @@ -458,9 +494,9 @@ obj/machinery/computer/forensic_scanning if(!fibers) fibers = list() if(atom_suit_fibers) - for(var/j = 1, j <= atom_suit_fibers.len, j++) //Fibers~~~ - if(!fibers.Find(atom_suit_fibers[j])) //It isn't! Add! - fibers += atom_suit_fibers[j] + for(var/fiber in atom_suit_fibers) //Fibers~~~ + if(!fibers.Find(fiber)) //It isn't! Add! + fibers += fiber var/list/blood = data_entry[2] if(!blood) blood = list() @@ -468,11 +504,19 @@ obj/machinery/computer/forensic_scanning for(var/main_blood in atom_blood_DNA) if(!blood[main_blood]) blood[main_blood] = atom_blood_DNA[blood] + var/list/prints = data_entry[4] + if(!prints && atom_fingerprints) + prints = list() + if(atom_fingerprints) + for(var/print in atom_fingerprints) + if(!prints[print]) + prints[print] = atom_fingerprints[print] else - var/list/templist[3] + var/list/templist[4] templist[1] = atom_suit_fibers templist[2] = atom_blood_DNA templist[3] = atom_name + templist[4] = atom_fingerprints misc[atom_reference] = templist //Store it! //Has prints. if(atom_fingerprints) @@ -500,9 +544,9 @@ obj/machinery/computer/forensic_scanning if(!fibers) fibers = list() if(atom_suit_fibers) - for(var/j = 1, j < atom_suit_fibers.len, j++) //Fibers~~~ - if(!fibers.Find(atom_suit_fibers[j])) //It isn't! Add! - fibers += atom_suit_fibers[j] + for(var/fiber in atom_suit_fibers) //Fibers~~~ + if(!fibers.Find(fiber)) //It isn't! Add! + fibers += fiber //Blood. var/list/blood = internal_atom[3] if(!blood) @@ -528,8 +572,9 @@ obj/machinery/computer/forensic_scanning data_point[2] = atom_suit_fibers data_point[3] = atom_blood_DNA data_point[4] = atom_name - var/list/new_file[1] + var/list/new_file[2] new_file[1] = atom_fingerprints[main_print] + new_file[2] = "Dossier [files.len + 1]" new_file[atom_reference] = data_point files[main_print] = new_file return 1 @@ -580,209 +625,3 @@ obj/machinery/computer/forensic_scanning detective icon_state = "old" name = "PowerScan Mk.I" - -obj/item/clothing/shoes/var - track_blood = 0 - mob/living/carbon/human/track_blood_mob - track_blood_type -mob/var - bloody_hands = 0 - mob/living/carbon/human/bloody_hands_mob - track_blood - mob/living/carbon/human/track_blood_mob - track_blood_type -obj/item/clothing/gloves/var - transfer_blood = 0 - mob/living/carbon/human/bloody_hands_mob - - -obj/effect/decal/cleanable/var - track_amt = 3 - mob/blood_owner - -turf/Exited(mob/living/carbon/human/M) - if(istype(M,/mob/living) && !istype(M,/mob/living/carbon/metroid)) - if(!istype(src, /turf/space)) // Bloody tracks code starts here - var/dofoot = 1 - if(istype(M,/mob/living/simple_animal)) - if(!(istype(M,/mob/living/simple_animal/cat) || istype(M,/mob/living/simple_animal/corgi) || istype(M,/mob/living/simple_animal/constructwraith))) - dofoot = 0 - - if(dofoot) - - if(!istype(src, /turf/space)) // Bloody tracks code starts here - if(M.track_blood > 0) - M.track_blood-- - src.add_bloody_footprints(M.track_blood_mob,1,M.dir,get_tracks(M),M.track_blood_type) - else if(istype(M,/mob/living/carbon/human)) - if(M.shoes && istype(M.shoes,/obj/item/clothing/shoes)) - var/obj/item/clothing/shoes/S = M.shoes - if(S.track_blood > 0) - S.track_blood-- - src.add_bloody_footprints(S.track_blood_mob,1,M.dir,S.name,S.track_blood_type) // And bloody tracks end here - . = ..() -turf/Entered(mob/living/carbon/human/M) - if(istype(M,/mob/living) && !istype(M,/mob/living/carbon/metroid)) - var/dofoot = 1 - if(istype(M,/mob/living/simple_animal)) - if(!(istype(M,/mob/living/simple_animal/cat) || istype(M,/mob/living/simple_animal/corgi) || istype(M,/mob/living/simple_animal/constructwraith))) - dofoot = 0 - - if(dofoot) - - if(M.track_blood > 0) - M.track_blood-- - src.add_bloody_footprints(M.track_blood_mob,0,M.dir,get_tracks(M),M.track_blood_type) - else if(istype(M,/mob/living/carbon/human)) - if(M.shoes && istype(M.shoes,/obj/item/clothing/shoes) && !istype(src,/turf/space)) - var/obj/item/clothing/shoes/S = M.shoes - if(S.track_blood > 0) - S.track_blood-- - src.add_bloody_footprints(S.track_blood_mob,0,M.dir,S.name,S.track_blood_type) - - - for(var/obj/effect/decal/cleanable/B in src) - if(B:track_amt <= 0) continue - if(B.type != /obj/effect/decal/cleanable/blood/tracks) - if(istype(B, /obj/effect/decal/cleanable/xenoblood) || istype(B, /obj/effect/decal/cleanable/blood) || istype(B, /obj/effect/decal/cleanable/oil) || istype(B, /obj/effect/decal/cleanable/robot_debris)) - - var/track_type = "blood" - if(istype(B, /obj/effect/decal/cleanable/xenoblood)) - track_type = "xeno" - else if(istype(B, /obj/effect/decal/cleanable/oil) || istype(B, /obj/effect/decal/cleanable/robot_debris)) - track_type = "oil" - - if(istype(M,/mob/living/carbon/human)) - if(M.shoes && istype(M.shoes,/obj/item/clothing/shoes)) - var/obj/item/clothing/shoes/S = M.shoes - S.add_blood(B.blood_owner) - S.track_blood_mob = B.blood_owner - S.track_blood = max(S.track_blood,8) - S.track_blood_type = track_type - else - M.add_blood(B.blood_owner) - M.track_blood_mob = B.blood_owner - M.track_blood = max(M.track_blood,rand(4,8)) - M.track_blood_type = track_type - B.track_amt-- - break - . = ..() - -turf/proc/add_bloody_footprints(mob/living/carbon/human/M,leaving,d,info,bloodcolor) - for(var/obj/effect/decal/cleanable/blood/tracks/T in src) - if(T.dir == d && findtext(T.icon_state, bloodcolor)) - if((leaving && T.icon_state == "steps2") || (!leaving && T.icon_state == "steps1")) - T.desc = "These bloody footprints appear to have been made by [info]." - if(!T.blood_DNA) - T.blood_DNA = list() - if(istype(M,/mob/living/carbon/human)) - T.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type - else if(istype(M,/mob/living/carbon/alien)) - T.blood_DNA["UNKNOWN DNA"] = "X*" - else if(istype(M,/mob/living/carbon/monkey)) - T.blood_DNA["Non-human DNA"] = "A+" - return - var/obj/effect/decal/cleanable/blood/tracks/this = new(src) - this.icon = 'footprints.dmi' - - var/preiconstate = "" - - if(info == "animal paws") - preiconstate = "paw" - else if(info == "alien claws") - preiconstate = "claw" - else if(info == "small alien feet") - preiconstate = "paw" - - if(leaving) - this.icon_state = "[bloodcolor][preiconstate]2" - else - this.icon_state = "[bloodcolor][preiconstate]1" - this.dir = d - - if(bloodcolor == "blood") - this.desc = "These bloody footprints appear to have been made by [info]." - else if(bloodcolor == "xeno") - this.desc = "These acidic bloody footprints appear to have been made by [info]." - else if(bloodcolor == "oil") - this.name = "oil" - this.desc = "These oil footprints appear to have been made by [info]." - - if(istype(M,/mob/living/carbon/human)) - if(!this.blood_DNA) - this.blood_DNA = list() - this.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type - -proc/get_tracks(mob/M) - if(istype(M,/mob/living)) - if(istype(M,/mob/living/carbon/human)) - . = "human feet" - else if(istype(M,/mob/living/carbon/monkey) || istype(M,/mob/living/simple_animal/cat) || istype(M,/mob/living/simple_animal/corgi) || istype(M,/mob/living/simple_animal/crab)) - . = "animal paws" - else if(istype(M,/mob/living/silicon/robot)) - . = "robot feet" - else if(istype(M,/mob/living/carbon/alien/humanoid)) - . = "alien claws" - else if(istype(M,/mob/living/carbon/alien/larva)) - . = "small alien feet" - else - . = "an unknown creature" - - -proc/blood_incompatible(donor,receiver) - var - donor_antigen = copytext(donor,1,lentext(donor)) - receiver_antigen = copytext(receiver,1,lentext(receiver)) - donor_rh = findtext("+",donor) - receiver_rh = findtext("+",receiver) - if(donor_rh && !receiver_rh) return 1 - switch(receiver_antigen) - if("A") - if(donor_antigen != "A" && donor_antigen != "O") return 1 - if("B") - if(donor_antigen != "B" && donor_antigen != "O") return 1 - if("O") - if(donor_antigen != "O") return 1 - //AB is a universal receiver. - return 0 - -/obj/item/weapon/rag - New() // So I don't have to grab maplock - spawn(1) - new/obj/item/weapon/reagent_containers/glass/rag(loc) - del src - -/obj/item/weapon/reagent_containers/glass/rag - name = "damp rag" - desc = "For cleaning up messes, you suppose." - w_class = 1 - icon = 'toy.dmi' - icon_state = "rag" - amount_per_transfer_from_this = 5 - possible_transfer_amounts = list(5) - volume = 5 - can_be_placed_into = null - - attack(atom/target as obj|turf|area, mob/user as mob , flag) - if(ismob(target) && target.reagents && reagents.total_volume) - user.visible_message("\red \The [target] has been smothered with \the [src] by \the [user]!", "\red You smother \the [target] with \the [src]!", "You hear some struggling and muffled cries of surprise") - src.reagents.reaction(target, TOUCH) - spawn(5) src.reagents.clear_reagents() - return - else - ..() - - afterattack(atom/A as obj|turf|area, mob/user as mob) - if(istype(A) && src in user) - user.visible_message("[user] starts to wipe down [A] with [src]!") - if(do_after(user,30)) - user.visible_message("[user] finishes wiping off the [A]!") - A.clean_blood() - return - - examine() - if (!usr) - return - usr << "That's \a [src]." - usr << desc - return diff --git a/code/modules/DetectiveWork/evidence.dm b/code/modules/DetectiveWork/evidence.dm index a35a4982a2d..8853efb2be6 100644 --- a/code/modules/DetectiveWork/evidence.dm +++ b/code/modules/DetectiveWork/evidence.dm @@ -1,6 +1,5 @@ -//CONTAINS: -//Evidence bags and stuff -/////////// +//CONTAINS: Evidence bags + /obj/item/weapon/evidencebag name = "evidence bag" desc = "An empty evidence bag." diff --git a/code/modules/DetectiveWork/footprints_and_rag.dm b/code/modules/DetectiveWork/footprints_and_rag.dm new file mode 100644 index 00000000000..83e49347897 --- /dev/null +++ b/code/modules/DetectiveWork/footprints_and_rag.dm @@ -0,0 +1,207 @@ +//CONTAINS: Bloody footprints code, code for managing blood incompatability, and a rag to wipe away evidence. + +obj/item/clothing/shoes/var + track_blood = 0 + mob/living/carbon/human/track_blood_mob + track_blood_type +mob/var + bloody_hands = 0 + mob/living/carbon/human/bloody_hands_mob + track_blood + mob/living/carbon/human/track_blood_mob + track_blood_type +obj/item/clothing/gloves/var + transfer_blood = 0 + mob/living/carbon/human/bloody_hands_mob + + +obj/effect/decal/cleanable/var + track_amt = 3 + mob/blood_owner + +turf/Exited(mob/living/carbon/human/M) + if(istype(M,/mob/living) && !istype(M,/mob/living/carbon/metroid)) + if(!istype(src, /turf/space)) // Bloody tracks code starts here + var/dofoot = 1 + if(istype(M,/mob/living/simple_animal)) + if(!(istype(M,/mob/living/simple_animal/cat) || istype(M,/mob/living/simple_animal/corgi) || istype(M,/mob/living/simple_animal/constructwraith))) + dofoot = 0 + + if(dofoot) + + if(!istype(src, /turf/space)) // Bloody tracks code starts here + if(M.track_blood > 0) + M.track_blood-- + src.add_bloody_footprints(M.track_blood_mob,1,M.dir,get_tracks(M),M.track_blood_type) + else if(istype(M,/mob/living/carbon/human)) + if(M.shoes && istype(M.shoes,/obj/item/clothing/shoes)) + var/obj/item/clothing/shoes/S = M.shoes + if(S.track_blood > 0) + S.track_blood-- + src.add_bloody_footprints(S.track_blood_mob,1,M.dir,S.name,S.track_blood_type) // And bloody tracks end here + . = ..() +turf/Entered(mob/living/carbon/human/M) + if(istype(M,/mob/living) && !istype(M,/mob/living/carbon/metroid)) + var/dofoot = 1 + if(istype(M,/mob/living/simple_animal)) + if(!(istype(M,/mob/living/simple_animal/cat) || istype(M,/mob/living/simple_animal/corgi) || istype(M,/mob/living/simple_animal/constructwraith))) + dofoot = 0 + + if(dofoot) + + if(M.track_blood > 0) + M.track_blood-- + src.add_bloody_footprints(M.track_blood_mob,0,M.dir,get_tracks(M),M.track_blood_type) + else if(istype(M,/mob/living/carbon/human)) + if(M.shoes && istype(M.shoes,/obj/item/clothing/shoes) && !istype(src,/turf/space)) + var/obj/item/clothing/shoes/S = M.shoes + if(S.track_blood > 0) + S.track_blood-- + src.add_bloody_footprints(S.track_blood_mob,0,M.dir,S.name,S.track_blood_type) + + + for(var/obj/effect/decal/cleanable/B in src) + if(B:track_amt <= 0) continue + if(B.type != /obj/effect/decal/cleanable/blood/tracks) + if(istype(B, /obj/effect/decal/cleanable/xenoblood) || istype(B, /obj/effect/decal/cleanable/blood) || istype(B, /obj/effect/decal/cleanable/oil) || istype(B, /obj/effect/decal/cleanable/robot_debris)) + + var/track_type = "blood" + if(istype(B, /obj/effect/decal/cleanable/xenoblood)) + track_type = "xeno" + else if(istype(B, /obj/effect/decal/cleanable/oil) || istype(B, /obj/effect/decal/cleanable/robot_debris)) + track_type = "oil" + + if(istype(M,/mob/living/carbon/human)) + if(M.shoes && istype(M.shoes,/obj/item/clothing/shoes)) + var/obj/item/clothing/shoes/S = M.shoes + S.add_blood(B.blood_owner) + S.track_blood_mob = B.blood_owner + S.track_blood = max(S.track_blood,8) + S.track_blood_type = track_type + else + M.add_blood(B.blood_owner) + M.track_blood_mob = B.blood_owner + M.track_blood = max(M.track_blood,rand(4,8)) + M.track_blood_type = track_type + B.track_amt-- + break + . = ..() + +turf/proc/add_bloody_footprints(mob/living/carbon/human/M,leaving,d,info,bloodcolor) + for(var/obj/effect/decal/cleanable/blood/tracks/T in src) + if(T.dir == d && findtext(T.icon_state, bloodcolor)) + if((leaving && T.icon_state == "steps2") || (!leaving && T.icon_state == "steps1")) + T.desc = "These bloody footprints appear to have been made by [info]." + if(!T.blood_DNA) + T.blood_DNA = list() + if(istype(M,/mob/living/carbon/human)) + T.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type + else if(istype(M,/mob/living/carbon/alien)) + T.blood_DNA["UNKNOWN DNA"] = "X*" + else if(istype(M,/mob/living/carbon/monkey)) + T.blood_DNA["Non-human DNA"] = "A+" + return + var/obj/effect/decal/cleanable/blood/tracks/this = new(src) + this.icon = 'footprints.dmi' + + var/preiconstate = "" + + if(info == "animal paws") + preiconstate = "paw" + else if(info == "alien claws") + preiconstate = "claw" + else if(info == "small alien feet") + preiconstate = "paw" + + if(leaving) + this.icon_state = "[bloodcolor][preiconstate]2" + else + this.icon_state = "[bloodcolor][preiconstate]1" + this.dir = d + + if(bloodcolor == "blood") + this.desc = "These bloody footprints appear to have been made by [info]." + else if(bloodcolor == "xeno") + this.desc = "These acidic bloody footprints appear to have been made by [info]." + else if(bloodcolor == "oil") + this.name = "oil" + this.desc = "These oil footprints appear to have been made by [info]." + + if(istype(M,/mob/living/carbon/human)) + if(!this.blood_DNA) + this.blood_DNA = list() + this.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type + +proc/get_tracks(mob/M) + if(istype(M,/mob/living)) + if(istype(M,/mob/living/carbon/human)) + . = "human feet" + else if(istype(M,/mob/living/carbon/monkey) || istype(M,/mob/living/simple_animal/cat) || istype(M,/mob/living/simple_animal/corgi) || istype(M,/mob/living/simple_animal/crab)) + . = "animal paws" + else if(istype(M,/mob/living/silicon/robot)) + . = "robot feet" + else if(istype(M,/mob/living/carbon/alien/humanoid)) + . = "alien claws" + else if(istype(M,/mob/living/carbon/alien/larva)) + . = "small alien feet" + else + . = "an unknown creature" + + +proc/blood_incompatible(donor,receiver) + var + donor_antigen = copytext(donor,1,lentext(donor)) + receiver_antigen = copytext(receiver,1,lentext(receiver)) + donor_rh = findtext("+",donor) + receiver_rh = findtext("+",receiver) + if(donor_rh && !receiver_rh) return 1 + switch(receiver_antigen) + if("A") + if(donor_antigen != "A" && donor_antigen != "O") return 1 + if("B") + if(donor_antigen != "B" && donor_antigen != "O") return 1 + if("O") + if(donor_antigen != "O") return 1 + //AB is a universal receiver. + return 0 + +/obj/item/weapon/rag + New() // So I don't have to grab maplock + spawn(1) + new/obj/item/weapon/reagent_containers/glass/rag(loc) + del src + +/obj/item/weapon/reagent_containers/glass/rag + name = "damp rag" + desc = "For cleaning up messes, you suppose." + w_class = 1 + icon = 'toy.dmi' + icon_state = "rag" + amount_per_transfer_from_this = 5 + possible_transfer_amounts = list(5) + volume = 5 + can_be_placed_into = null + + attack(atom/target as obj|turf|area, mob/user as mob , flag) + if(ismob(target) && target.reagents && reagents.total_volume) + user.visible_message("\red \The [target] has been smothered with \the [src] by \the [user]!", "\red You smother \the [target] with \the [src]!", "You hear some struggling and muffled cries of surprise") + src.reagents.reaction(target, TOUCH) + spawn(5) src.reagents.clear_reagents() + return + else + ..() + + afterattack(atom/A as obj|turf|area, mob/user as mob) + if(istype(A) && src in user) + user.visible_message("\The [user] starts to wipe down \a [A] with \a [src]!", "You start to wipe down \the [A].", "You hear a damp rag being rubbed against something.") + if(do_after(user,30)) + user.visible_message("\The [user] finishes wiping off \a [A]!", "You finish wiping down \the [A].") + A.clean_blood() + return + + examine() + if (!usr) + return + usr << "That's \a [src]." + usr << desc + return \ No newline at end of file diff --git a/code/modules/DetectiveWork/scanner.dm b/code/modules/DetectiveWork/scanner.dm new file mode 100644 index 00000000000..65285684049 --- /dev/null +++ b/code/modules/DetectiveWork/scanner.dm @@ -0,0 +1,172 @@ +//CONTAINS: Detective's Scanner + +/obj/item/device/detective_scanner + name = "Scanner" + desc = "Used to scan objects for DNA and fingerprints." + icon_state = "forensic1" + var/amount = 20.0 + var/list/stored = list() + w_class = 3.0 + item_state = "electronic" + flags = FPRINT | TABLEPASS | CONDUCT | USEDELAY + slot_flags = SLOT_BELT + + attackby(obj/item/weapon/f_card/W as obj, mob/user as mob) + ..() + if (istype(W, /obj/item/weapon/f_card)) + if (W.fingerprints) + return + if (src.amount == 20) + return + if (W.amount + src.amount > 20) + src.amount = 20 + W.amount = W.amount + src.amount - 20 + else + src.amount += W.amount + //W = null + del(W) + add_fingerprint(user) + if (W) + W.add_fingerprint(user) + return + + attack(mob/living/carbon/human/M as mob, mob/user as mob) + if (!ishuman(M)) + user << "\red [M] is not human and cannot have the fingerprints." + return 0 + if (( !( istype(M.dna, /datum/dna) ) || M.gloves) ) + user << "\blue No fingerprints found on [M]" + return 0 + else + if (src.amount < 1) + user << text("\blue Fingerprints scanned on [M]. Need more cards to print.") + else + src.amount-- + var/obj/item/weapon/f_card/F = new /obj/item/weapon/f_card( user.loc ) + F.amount = 1 + F.add_fingerprint(M) + F.icon_state = "fingerprint1" + F.name = text("FPrintC- '[M.name]'") + + user << "\blue Done printing." + user << "\blue [M]'s Fingerprints: [md5(M.dna.uni_identity)]" + if ( !M.blood_DNA || !M.blood_DNA.len ) + user << "\blue No blood found on [M]" + if(M.blood_DNA) + del(M.blood_DNA) + else + user << "\blue Blood found on [M]. Analysing..." + spawn(15) + for(var/blood in M.blood_DNA) + user << "\blue Blood type: [M.blood_DNA[blood]]\nDNA: [blood]" + return + + afterattack(atom/A as obj|turf|area, mob/user as mob) + if(!in_range(A,user)) + return + if(loc != user) + return + if(istype(A,/obj/machinery/computer/forensic_scanning)) //breaks shit. + return + if(istype(A,/obj/item/weapon/f_card)) + user << "The scanner displays on the screen: \"ERROR 43: Object on Excluded Object List.\"" + return + + add_fingerprint(user) + + + //Special case for blood splaters. + if (istype(A, /obj/effect/decal/cleanable/blood) || istype(A, /obj/effect/rune)) + if(!isnull(A.blood_DNA)) + for(var/blood in A.blood_DNA) + user << "\blue Blood type: [A.blood_DNA[blood]]\nDNA: [blood]" + return + + //General + if ((!A.fingerprints || !A.fingerprints.len) && !A.suit_fibers && !A.blood_DNA) + user.visible_message("\The [user] scans \the [A] with \a [src], the air around [user.get_gender_form("it")] humming[prob(70) ? " gently." : "."]" ,\ + "\blue Unable to locate any fingerprints, materials, fibers, or blood on [A]!",\ + "You hear a faint hum of electrical equipment.") + return 0 + + if(add_data(A)) + user << "\blue Object already in internal memory. Consolidating data..." + return + + + //PRINTS + if(!A.fingerprints || !A.fingerprints.len) + if(A.fingerprints) + del(A.fingerprints) + else + user << "\blue Isolated [A.fingerprints.len] fingerprints: Data Stored: Scan with Hi-Res Forensic Scanner to retrieve." + var/list/complete_prints = list() + for(var/i in A.fingerprints) + var/print = A.fingerprints[i] + if(stringpercent(print) <= FINGERPRINT_COMPLETE) + complete_prints += print + if(complete_prints.len < 1) + user << "\blue   No intact prints found" + else + user << "\blue   Found [complete_prints.len] intact prints" + for(var/i in complete_prints) + user << "\blue     [i]" + + //FIBERS + if(A.suit_fibers) + user << "\blue Fibers/Materials Data Stored: Scan with Hi-Res Forensic Scanner to retrieve." + + //Blood + if (A.blood_DNA) + user << "\blue Blood found on [A]. Analysing..." + spawn(15) + for(var/blood in A.blood_DNA) + user << "Blood type: \red [A.blood_DNA[blood]] \t \black DNA: \red [blood]" + if(prob(80) || !A.fingerprints) + user.visible_message("\The [user] scans \the [A] with \a [src], the air around [user.get_gender_form("it")] humming[prob(70) ? " gently." : "."]" ,\ + "You finish scanning \the [A].",\ + "You hear a faint hum of electrical equipment.") + return 0 + else + user.visible_message("\The [user] scans \the [A] with \a [src], the air around [user.get_gender_form("it")] humming[prob(70) ? " gently." : "."]\n[user.get_gender_form("It")] seems to perk up slightly at the readout." ,\ + "The results of the scan pique your interest.",\ + "You hear a faint hum of electrical equipment, and someone making a thoughtful noise.") + return 0 + return + + proc/add_data(atom/A as mob|obj|turf|area) + //I love hashtables. + var/list/data_entry = stored["\ref [A]"] + if(islist(data_entry)) //Yay, it was already stored! + //Merge the fingerprints. + var/list/data_prints = data_entry[1] + for(var/print in A.fingerprints) + var/merged_print = data_prints[print] + if(!merged_print) + data_prints[print] = A.fingerprints[print] + else + data_prints[print] = stringmerge(data_prints[print],A.fingerprints[print]) + + //Now the fibers + var/list/fibers = data_entry[2] + if(!fibers) + fibers = list() + if(A.suit_fibers && A.suit_fibers.len) + for(var/j = 1, j <= A.suit_fibers.len, j++) //Fibers~~~ + if(!fibers.Find(A.suit_fibers[j])) //It isn't! Add! + fibers += A.suit_fibers[j] + var/list/blood = data_entry[3] + if(!blood) + blood = list() + if(A.blood_DNA && A.blood_DNA.len) + for(var/main_blood in A.blood_DNA) + if(!blood[main_blood]) + blood[main_blood] = A.blood_DNA[blood] + return 1 + var/list/sum_list[4] //Pack it back up! + sum_list[1] = A.fingerprints + sum_list[2] = A.suit_fibers + sum_list[3] = A.blood_DNA + sum_list[4] = "\The [A] in \the [get_area(A)]" + stored["\ref [A]"] = sum_list + return 0 \ No newline at end of file