mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 10:12:45 +00:00
Initial commit of detective console rewrite.
Changed forensic data to use record datum instead of unreadable arrays. Now handheld scanner transfers data by clicking the big console, not by scan. Rewrote high res scanner console. Now it leaves compiling dossiers to player, via use of filters.
This commit is contained in:
@@ -1,629 +0,0 @@
|
||||
//CONTAINS: Suit fibers and Detective's Scanning Computer
|
||||
|
||||
atom/var/list/suit_fibers
|
||||
|
||||
atom/proc/add_fibers(mob/living/carbon/human/M)
|
||||
if(M.gloves && istype(M.gloves,/obj/item/clothing/))
|
||||
var/obj/item/clothing/gloves/G = M.gloves
|
||||
if(G.transfer_blood) //bloodied gloves transfer blood to touched objects
|
||||
if(add_blood(G.bloody_hands_mob)) //only reduces the bloodiness of our gloves if the item wasn't already bloody
|
||||
G.transfer_blood--
|
||||
else if(M.bloody_hands)
|
||||
if(add_blood(M.bloody_hands_mob))
|
||||
M.bloody_hands--
|
||||
if(!suit_fibers) suit_fibers = list()
|
||||
var/fibertext
|
||||
var/item_multiplier = istype(src,/obj/item)?1.2:1
|
||||
if(M.wear_suit)
|
||||
fibertext = "Material from \a [M.wear_suit]."
|
||||
if(prob(10*item_multiplier) && !(fibertext in suit_fibers))
|
||||
//world.log << "Added fibertext: [fibertext]"
|
||||
suit_fibers += fibertext
|
||||
if(M.wear_suit.body_parts_covered & ~FULL_BODY && (M.wear_suit.body_parts_covered & ~UPPER_TORSO || M.wear_suit.body_parts_covered & ~LOWER_TORSO || M.wear_suit.body_parts_covered & ~ARMS || M.wear_suit.body_parts_covered & ~LEGS))
|
||||
if(M.w_uniform)
|
||||
fibertext = "Fibers from \a [M.w_uniform]."
|
||||
if(prob(12*item_multiplier) && !(fibertext in suit_fibers)) //Wearing a suit means less of the uniform exposed.
|
||||
//world.log << "Added fibertext: [fibertext]"
|
||||
suit_fibers += fibertext
|
||||
if(M.wear_suit.body_parts_covered & ~HANDS)
|
||||
if(M.gloves)
|
||||
fibertext = "Material from a pair of [M.gloves.name]."
|
||||
if(prob(20*item_multiplier) && !(fibertext in suit_fibers))
|
||||
//world.log << "Added fibertext: [fibertext]"
|
||||
suit_fibers += fibertext
|
||||
else if(M.w_uniform)
|
||||
fibertext = "Fibers from \a [M.w_uniform]."
|
||||
if(prob(15*item_multiplier) && !(fibertext in suit_fibers))
|
||||
// "Added fibertext: [fibertext]"
|
||||
suit_fibers += fibertext
|
||||
if(M.gloves)
|
||||
fibertext = "Material from a pair of [M.gloves.name]."
|
||||
if(prob(20*item_multiplier) && !(fibertext in suit_fibers))
|
||||
//world.log << "Added fibertext: [fibertext]"
|
||||
suit_fibers += "Material from a pair of [M.gloves.name]."
|
||||
else if(M.gloves)
|
||||
fibertext = "Material from a pair of [M.gloves.name]."
|
||||
if(prob(20*item_multiplier) && !(fibertext in suit_fibers))
|
||||
//world.log << "Added fibertext: [fibertext]"
|
||||
suit_fibers += "Material from a pair of [M.gloves.name]."
|
||||
if(!suit_fibers.len) del suit_fibers
|
||||
|
||||
var/const/FINGERPRINT_COMPLETE = 6 //This is the output of the stringpercent(print) proc, and means about 80% of
|
||||
//the print must be there for it to be complete. (Prints are 32 digits)
|
||||
|
||||
obj/machinery/computer/forensic_scanning
|
||||
name = "\improper High-Res Forensic Scanning Computer"
|
||||
icon_state = "forensic"
|
||||
var/obj/item/scanning
|
||||
var/temp = ""
|
||||
var/canclear = 1
|
||||
var/authenticated = 0
|
||||
|
||||
//Here's the structure for files: each entry is a list, and entry one in that list is the string of their
|
||||
//full and scrambled fingerprint. This acts as the method to arrange evidence. Each subsequent entry is list
|
||||
//in the form (from entries):
|
||||
// 1: Object
|
||||
// 2: All prints on the object
|
||||
// 3: All fibers on the object
|
||||
// 4: All blood on the object
|
||||
//This is then used to show what objects were used to "find" the full print, as well as the fibers on it.
|
||||
var/list/files
|
||||
//This holds objects (1) without prints, and their fibers(2) and blood(3).
|
||||
var/list/misc
|
||||
var/obj/item/weapon/f_card/card
|
||||
|
||||
var/scan_data = ""
|
||||
var/scan_name = ""
|
||||
var/scan_process = 0
|
||||
|
||||
req_access = list(access_forensics_lockers)
|
||||
|
||||
|
||||
New()
|
||||
..()
|
||||
new /obj/item/weapon/book/manual/detective(get_turf(src))
|
||||
return
|
||||
|
||||
|
||||
attack_ai(mob/user)
|
||||
return attack_hand(user)
|
||||
|
||||
|
||||
attack_hand(mob/user)
|
||||
if(..())
|
||||
return
|
||||
user.set_machine(src)
|
||||
var/dat = ""
|
||||
var/isai = 0
|
||||
if(istype(usr,/mob/living/silicon))
|
||||
isai = 1
|
||||
if(temp)
|
||||
dat += "<tt>[temp]</tt><br><br>"
|
||||
if(canclear) dat += "<a href='?src=\ref[src];operation=clear'>{Clear Screen}</a>"
|
||||
else
|
||||
if(!authenticated)
|
||||
dat += "<a href='?src=\ref[src];operation=login'>{Log In}</a>"
|
||||
else
|
||||
dat += "<a href='?src=\ref[src];operation=logout'>{Log Out}</a><br><hr><br>"
|
||||
if(scanning)
|
||||
if(scan_process)
|
||||
dat += {"Scan Object: {[scanning.name]}<br>
|
||||
<a href='?src=\ref[src];operation=cancel'>{Cancel Scan}</a> {Print}<br>"}
|
||||
else
|
||||
if(isai) dat += "Scan Object: {[scanning.name]}<br>"
|
||||
else dat += "Scan Object: <a href='?src=\ref[src];operation=eject'>{[scanning.name]}</a><br>"
|
||||
dat += "<a href='?src=\ref[src];operation=scan'>{Scan}</a> <a href='?src=\ref[src];operation=print'>{Print}</a><br>"
|
||||
else
|
||||
if(isai) dat += "{No Object Inserted}<br>"
|
||||
else dat += "<a href='?src=\ref[src];operation=insert'>{No Object Inserted}</a><br>"
|
||||
dat += "{Scan} <a href='?src=\ref[src];operation=print'>{Print}</a><br>"
|
||||
dat += {"<a href='?src=\ref[src];operation=database'>{Access Database}</a><br><br>"
|
||||
<tt>[scan_data]</tt>"}
|
||||
if(scan_data && !scan_process)
|
||||
dat += "<br><a href='?src=\ref[src];operation=erase'>{Erase Data}</a>"
|
||||
user << browse(dat,"window=scanner")
|
||||
onclose(user,"scanner")
|
||||
|
||||
|
||||
Topic(href,href_list)
|
||||
if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
|
||||
usr.set_machine(src)
|
||||
switch(href_list["operation"])
|
||||
if("login")
|
||||
var/mob/M = usr
|
||||
if(istype(M,/mob/living/silicon))
|
||||
authenticated = 1
|
||||
updateDialog()
|
||||
return
|
||||
if (allowed(M))
|
||||
authenticated = 1
|
||||
if("logout")
|
||||
authenticated = 0
|
||||
if("clear")
|
||||
if(canclear)
|
||||
temp = null
|
||||
if("eject")
|
||||
if(scanning)
|
||||
scanning.loc = loc
|
||||
scanning = null
|
||||
else
|
||||
temp = "Eject Failed: No Object"
|
||||
if("insert")
|
||||
var/mob/M = usr
|
||||
var/obj/item/I = M.get_active_hand()
|
||||
if(I && istype(I))
|
||||
if(istype(I, /obj/item/weapon/evidencebag))
|
||||
scanning = I.contents[1]
|
||||
scanning.loc = src
|
||||
I.overlays -= scanning
|
||||
I.icon_state = "evidenceobj"
|
||||
else
|
||||
scanning = I
|
||||
M.drop_item()
|
||||
I.loc = src
|
||||
else
|
||||
usr << "Invalid Object Rejected."
|
||||
if("card") //Processing a fingerprint card.
|
||||
var/mob/M = usr
|
||||
var/obj/item/I = M.get_active_hand()
|
||||
if(!(I && istype(I,/obj/item/weapon/f_card)))
|
||||
I = card
|
||||
if(I && istype(I,/obj/item/weapon/f_card))
|
||||
card = I
|
||||
if(!card.fingerprints)
|
||||
card.fingerprints = list()
|
||||
if(card.amount > 1 || !card.fingerprints.len)
|
||||
usr << "\red ERROR: No prints/too many cards."
|
||||
if(card.loc == src)
|
||||
card.loc = src.loc
|
||||
card = null
|
||||
return
|
||||
M.drop_item()
|
||||
I.loc = src
|
||||
process_card()
|
||||
else
|
||||
usr << "\red Invalid Object Rejected."
|
||||
if("database") //Viewing all records in each database
|
||||
canclear = 1
|
||||
if(href_list["delete_record"])
|
||||
delete_dossier(href_list["delete_record"])
|
||||
if(href_list["delete_aux"])
|
||||
delete_record(href_list["delete_aux"])
|
||||
if((!misc || !misc.len) && (!files || !files.len))
|
||||
temp = "Database is empty."
|
||||
else
|
||||
if(files && files.len)
|
||||
temp = "<b>Criminal Evidence Database</b><br><br>"
|
||||
temp += "Consolidated data points:<br>"
|
||||
for(var/print in files)
|
||||
var/list/file = files[print]
|
||||
temp += "<a href='?src=\ref[src];operation=record;identifier=[print]'>{[file[2]]}</a><br>"
|
||||
temp += "<br><a href='?src=\ref[src];operation=card'>{Insert Finger Print Card (To complete a Dossier)}</a><br><br><br>"
|
||||
else
|
||||
temp = ""
|
||||
if(misc && misc.len)
|
||||
temp += {"<b>Auxiliary Evidence Database</b><br><br>
|
||||
This is where anything without fingerprints goes.<br><br>"}
|
||||
for(var/atom in misc)
|
||||
var/list/data_entry = misc[atom]
|
||||
temp += "<a href='?src=\ref[src];operation=auxiliary;identifier=[atom]'>{[data_entry[3]]}</a><br>"
|
||||
if("record") //Viewing a record from the "files" database.
|
||||
canclear = 0
|
||||
if(files)
|
||||
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 = {"<b>Criminal Evidence Database</b><br><br>
|
||||
Consolidated data points: [dossier[2]]<br>"}
|
||||
var/print_string = "Fingerprints: Print not complete!<br>"
|
||||
if(stringpercent(dossier[1]) <= FINGERPRINT_COMPLETE)
|
||||
print_string = "Fingerprints: (80% or higher completion reached)<br>[dossier[1]]<br>"
|
||||
temp += print_string
|
||||
for(var/object in dossier)
|
||||
if(object == dossier[1] || object == dossier[2])
|
||||
continue
|
||||
temp += "<hr>"
|
||||
var/list/outputs = dossier[object]
|
||||
var/list/prints = outputs[1]
|
||||
temp += "<big><b>Object:</b> [outputs[4]]</big><br>"
|
||||
temp += " <b>Fingerprints:</b><br>"
|
||||
temp += " [prints.len] Unique fingerprints found.<br>"
|
||||
var/complete_prints = 0
|
||||
for(var/print in prints)
|
||||
if(stringpercent(prints[print]) <= FINGERPRINT_COMPLETE)
|
||||
complete_prints++
|
||||
temp += " [prints[print]]<br>"
|
||||
if(complete_prints)
|
||||
temp += " And [prints.len - complete_prints] unknown unique prints.<br>"
|
||||
else
|
||||
temp += " No prints of sufficient completeness.<br>"
|
||||
var/list/fibers = outputs[2]
|
||||
if(fibers && fibers.len)
|
||||
temp += " <b>Fibers:</b><br>"
|
||||
for(var/j = 1, j <= fibers.len, j++)
|
||||
temp += " [fibers[j]]<br>"
|
||||
var/list/blood = outputs[3]
|
||||
if(blood && blood.len)
|
||||
temp += " <b>Blood:</b><br>"
|
||||
for(var/named in blood)
|
||||
temp += " Type: [blood[named]], DNA: [named]<br>"
|
||||
temp += "<br><a href='?src=\ref[src];operation=record;identifier=[href_list["identifier"]];ren=true'>{Rename this Dossier}</a>"
|
||||
temp += "<br><a href='?src=\ref[src];operation=database;delete_record=[href_list["identifier"]]'>{Delete this Dossier}</a>"
|
||||
temp += "<br><a href='?src=\ref[src];operation=databaseprint;identifier=[href_list["identifier"]]'>{Print}</a>"
|
||||
else
|
||||
temp = "ERROR. Database not found!<br>"
|
||||
temp += "<br><a href='?src=\ref[src];operation=database'>{Return}</a>"
|
||||
if("databaseprint") //Printing from the "files" database.
|
||||
if(files)
|
||||
var/obj/item/weapon/paper/P = new(loc)
|
||||
var/list/dossier = files[href_list["identifier"]]
|
||||
P.name = "\improper Database File ([dossier[2]])"
|
||||
P.icon_state = "paper_words"
|
||||
P.info = "<b>Criminal Evidence Database</b><br><br>"
|
||||
P.info += "Consolidated data points: [dossier[2]]<br>"
|
||||
var/print_string = "Fingerprints: Print not complete!<br>"
|
||||
if(stringpercent(dossier[1]) <= FINGERPRINT_COMPLETE)
|
||||
print_string = "Fingerprints: (80% or higher completion reached)<br>[dossier[1]]<br>"
|
||||
P.info += print_string
|
||||
for(var/object in dossier)
|
||||
if(object == dossier[1] || object == dossier[2])
|
||||
continue
|
||||
P.info += "<hr>"
|
||||
var/list/outputs = dossier[object]
|
||||
var/list/prints = outputs[1]
|
||||
P.info += "<big><b>Object:</b> [outputs[4]]</big><br>"
|
||||
P.info += " <b>Fingerprints:</b><br>"
|
||||
P.info += " [prints.len] Unique fingerprints found.<br>"
|
||||
var/complete_prints = 0
|
||||
for(var/print in prints)
|
||||
if(stringpercent(prints[print]) <= FINGERPRINT_COMPLETE)
|
||||
complete_prints++
|
||||
P.info += " [prints[print]]<br>"
|
||||
if(complete_prints)
|
||||
P.info += " And [prints.len - complete_prints] unknown unique prints.<br>"
|
||||
else
|
||||
P.info += " No prints of sufficient completeness.<br>"
|
||||
var/list/fibers = outputs[2]
|
||||
if(fibers && fibers.len)
|
||||
P.info += " <b>Fibers:</b><br>"
|
||||
for(var/j = 1, j <= fibers.len, j++)
|
||||
P.info += " [fibers[j]]<br>"
|
||||
var/list/blood = outputs[3]
|
||||
if(blood && blood.len)
|
||||
P.info += " <b>Blood:</b><br>"
|
||||
for(var/named in blood)
|
||||
P.info += " Type: [blood[named]], DNA: [named]<br>"
|
||||
else
|
||||
usr << "ERROR. Database not found!<br>"
|
||||
if("auxiliary") //Viewing a record from the "misc" database.
|
||||
canclear = 0
|
||||
if(misc)
|
||||
temp = "<b>Auxiliary Evidence Database</b><br><br>"
|
||||
var/list/outputs = misc[href_list["identifier"]]
|
||||
temp += "<big><b>Consolidated data points:</b> [outputs[3]]</big><br>"
|
||||
var/list/prints = outputs[4]
|
||||
if(prints)
|
||||
temp += " <b>Fingerprints:</b><br>"
|
||||
temp += " [prints.len] Unique fingerprints found.<br>"
|
||||
var/complete_prints = 0
|
||||
for(var/print in prints)
|
||||
if(stringpercent(prints[print]) <= FINGERPRINT_COMPLETE)
|
||||
complete_prints++
|
||||
temp += " [prints[print]]<br>"
|
||||
if(complete_prints)
|
||||
temp += " And [prints.len - complete_prints] unknown unique prints.<br>"
|
||||
else
|
||||
temp += " No prints of sufficient completeness.<br>"
|
||||
var/list/fibers = outputs[1]
|
||||
if(fibers && fibers.len)
|
||||
temp += " <b>Fibers:</b><br>"
|
||||
for(var/fiber in fibers)
|
||||
temp += " [fiber]<br>"
|
||||
var/list/blood = outputs[2]
|
||||
if(blood && blood.len)
|
||||
temp += " <b>Blood:</b><br>"
|
||||
for(var/named in blood)
|
||||
temp += " Type: [blood[named]], DNA: [named]<br>"
|
||||
temp += "<br><a href='?src=\ref[src];operation=database;delete_aux=[href_list["identifier"]]'>{Delete This Record}</a>"
|
||||
temp += "<br><a href='?src=\ref[src];operation=auxiliaryprint;identifier=[href_list["identifier"]]'>{Print}</a>"
|
||||
else
|
||||
temp = "ERROR. Database not found!<br>"
|
||||
temp += "<br><a href='?src=\ref[src];operation=database'>{Return}</a>"
|
||||
if("auxiliaryprint") //Printing from the "misc" database.
|
||||
if(misc)
|
||||
var/obj/item/weapon/paper/P = new(loc)
|
||||
var/list/outputs = misc[href_list["identifier"]]
|
||||
P.name = "\improper Auxiliary Database File ([outputs[3]])"
|
||||
P.icon_state = "paper_words"
|
||||
P.info = "<b>Auxiliary Evidence Database</b><br><br>"
|
||||
P.info += "<big><b>Consolidated data points:</b> [outputs[3]]</big><br>"
|
||||
var/list/prints = outputs[4]
|
||||
if(prints)
|
||||
P.info += " <b>Fingerprints:</b><br>"
|
||||
P.info += " [prints.len] Unique fingerprints found.<br>"
|
||||
var/complete_prints = 0
|
||||
for(var/print in prints)
|
||||
if(stringpercent(prints[print]) <= FINGERPRINT_COMPLETE)
|
||||
complete_prints++
|
||||
P.info += " [prints[print]]<br>"
|
||||
if(complete_prints)
|
||||
P.info += " And [prints.len - complete_prints] unknown unique prints.<br>"
|
||||
else
|
||||
P.info += " No prints of sufficient completeness.<br>"
|
||||
var/list/fibers = outputs[1]
|
||||
if(fibers && fibers.len)
|
||||
P.info += " <b>Fibers:</b><br>"
|
||||
for(var/fiber in fibers)
|
||||
P.info += " [fiber]<br>"
|
||||
var/list/blood = outputs[2]
|
||||
if(blood && blood.len)
|
||||
P.info += " <b>Blood:</b><br>"
|
||||
for(var/named in blood)
|
||||
P.info += " Type: [blood[named]], DNA: [named]<br>"
|
||||
else
|
||||
usr << "ERROR. Database not found!<br>"
|
||||
if("scan")
|
||||
if(istype(scanning,/obj/item/weapon/f_card))
|
||||
card = scanning
|
||||
scanning = initial(scanning)
|
||||
process_card()
|
||||
else if(scanning)
|
||||
scan_process = 3
|
||||
scan_data = "Scanning [scanning]: 25% complete"
|
||||
updateDialog()
|
||||
sleep(50)
|
||||
if(!scan_process)
|
||||
scan_data = null
|
||||
updateDialog()
|
||||
return
|
||||
scan_data = "Scanning [scanning]: 50% complete"
|
||||
updateDialog()
|
||||
scan_process = 2
|
||||
sleep(50)
|
||||
if(!scan_process)
|
||||
scan_data = null
|
||||
updateDialog()
|
||||
return
|
||||
scan_data = "Scanning [scanning]: 75% complete"
|
||||
updateDialog()
|
||||
scan_process = 1
|
||||
sleep(50)
|
||||
if(!scan_process)
|
||||
scan_data = null
|
||||
updateDialog()
|
||||
return
|
||||
if(scanning)
|
||||
scan_process = 0
|
||||
scan_name = scanning.name
|
||||
scan_data = "<u>[scanning]</u><br><br>"
|
||||
if (scanning.blood_DNA)
|
||||
scan_data += "Blood Found:<br>"
|
||||
for(var/blood in scanning.blood_DNA)
|
||||
scan_data += "Blood type: [scanning.blood_DNA[blood]]\nDNA: [blood]<br><br>"
|
||||
else
|
||||
scan_data += "No Blood Found<br><br>"
|
||||
if(!scanning.fingerprints)
|
||||
scan_data += "No Fingerprints Found<br><br>"
|
||||
else
|
||||
scan_data += "Isolated [scanning.fingerprints.len] Fingerprints. Loaded into database.<br>"
|
||||
add_data(scanning)
|
||||
|
||||
if(!scanning.suit_fibers)
|
||||
scan_data += "No Fibers/Materials Located<br>"
|
||||
else
|
||||
scan_data += "Fibers/Materials Found:<br>"
|
||||
for(var/data in scanning.suit_fibers)
|
||||
scan_data += "- [data]<br>"
|
||||
if(istype(scanning,/obj/item/device/detective_scanner) || (istype(scanning, /obj/item/device/pda) && scanning:cartridge && scanning:cartridge.access_security))
|
||||
scan_data += "<br><b>Data transfered from \the [scanning] to Database.</b><br>"
|
||||
add_data_scanner(scanning)
|
||||
else if(!scanning.fingerprints)
|
||||
scan_data += "<br><b><a href='?src=\ref[src];operation=add'>Add to Database?</a></b><br>"
|
||||
else
|
||||
temp = "Scan Failed: No Object"
|
||||
|
||||
|
||||
if("print") //Printing scan data
|
||||
if(scan_data)
|
||||
temp = "Scan Data Printed."
|
||||
var/obj/item/weapon/paper/P = new(loc)
|
||||
P.name = "\improper Scan Data ([scan_name])"
|
||||
P.info = "<tt>[scan_data]</tt>"
|
||||
P.icon_state = "paper_words"
|
||||
else
|
||||
temp = "Print Failed: No Data"
|
||||
if("erase")
|
||||
scan_data = ""
|
||||
if("cancel")
|
||||
scan_process = 0
|
||||
if("add") //Adding an object (Manually) to the database.
|
||||
if(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()
|
||||
return
|
||||
|
||||
|
||||
proc/add_data_scanner(var/obj/item/device/W)
|
||||
if(istype(W, /obj/item/device/detective_scanner))
|
||||
var/obj/item/device/detective_scanner/D = W
|
||||
if(D.stored)
|
||||
for(var/atom in D.stored)
|
||||
var/list/data = D.stored[atom]
|
||||
add_data_master(atom,data[1],data[2],data[3],data[4])
|
||||
D.stored = list()
|
||||
else if(istype(W, /obj/item/device/pda) && W:cartridge && W:cartridge.access_security)
|
||||
if(W:cartridge.stored_data)
|
||||
for(var/atom in W:cartridge.stored_data)
|
||||
var/list/data = W:cartridge.stored_data[atom]
|
||||
add_data_master(atom,data[1],data[2],data[3],data[4])
|
||||
W:cartridge.stored_data = list()
|
||||
return
|
||||
|
||||
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] (Direct Scan)")
|
||||
|
||||
|
||||
|
||||
/********************************
|
||||
*****DO NOT DIRECTLY CALL ME*****
|
||||
********************************/
|
||||
proc/add_data_master(var/atom_reference, var/list/atom_fingerprints, var/list/atom_suit_fibers, var/list/atom_blood_DNA, var/atom_name)
|
||||
//What follows is massive. It cross references all stored data in the scanner with the other stored data,
|
||||
//and what is already in the computer. Not sure how bad the lag may/may not be.
|
||||
|
||||
if(!misc)
|
||||
misc = list()
|
||||
var/list/data_entry = misc[atom_reference]
|
||||
if(data_entry)
|
||||
var/list/fibers = data_entry[1]
|
||||
if(!fibers)
|
||||
fibers = list()
|
||||
if(atom_suit_fibers)
|
||||
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()
|
||||
if(atom_blood_DNA)
|
||||
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[4]
|
||||
templist[1] = atom_suit_fibers ? atom_suit_fibers.Copy() : null
|
||||
templist[2] = atom_blood_DNA ? atom_blood_DNA.Copy() : null
|
||||
templist[3] = atom_name
|
||||
templist[4] = atom_fingerprints ? atom_fingerprints.Copy() : null
|
||||
misc[atom_reference] = templist //Store it!
|
||||
//Has prints.
|
||||
if(atom_fingerprints)
|
||||
if(!files)
|
||||
files = list()
|
||||
for(var/main_print in atom_fingerprints)
|
||||
data_entry = files[main_print]
|
||||
if(data_entry)//The print is already in here!
|
||||
var/list/internal_atom = data_entry[atom_reference] //Lets see if we can find the current object
|
||||
if(internal_atom)
|
||||
//We must be on a roll! Just update what needs to be updated.
|
||||
var/list/internal_prints = internal_atom[1]
|
||||
for(var/print in atom_fingerprints) //Sorry for the double loop! D:
|
||||
var/associated_print = internal_prints[print]
|
||||
var/reference_print = atom_fingerprints[print]
|
||||
if(associated_print && associated_print != reference_print) //It does not match
|
||||
internal_prints[print] = stringmerge(associated_print, reference_print)
|
||||
else if(!associated_print)
|
||||
internal_prints[print] = reference_print
|
||||
//If the main print was updated, lets update the master as well.
|
||||
if(print == main_print && (!associated_print || (associated_print && associated_print != reference_print)))
|
||||
update_fingerprints(main_print, internal_prints[print])
|
||||
//Fibers.
|
||||
var/list/fibers = internal_atom[2]
|
||||
if(!fibers)
|
||||
fibers = list()
|
||||
if(atom_suit_fibers)
|
||||
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)
|
||||
blood = list()
|
||||
if(atom_blood_DNA)
|
||||
for(var/main_blood in atom_blood_DNA)
|
||||
if(!blood[main_blood])
|
||||
blood[main_blood] = atom_blood_DNA[blood]
|
||||
|
||||
continue
|
||||
//It's not in there! We gotta add it.
|
||||
update_fingerprints(main_print, atom_fingerprints[main_print])
|
||||
var/list/data_point[4]
|
||||
data_point[1] = atom_fingerprints ? atom_fingerprints.Copy() : null
|
||||
data_point[2] = atom_suit_fibers ? atom_suit_fibers.Copy() : null
|
||||
data_point[3] = atom_blood_DNA ? atom_blood_DNA.Copy() : null
|
||||
data_point[4] = atom_name
|
||||
data_entry[atom_reference] = data_point
|
||||
continue
|
||||
//No print at all! New data entry, go!
|
||||
var/list/data_point[4]
|
||||
data_point[1] = atom_fingerprints ? atom_fingerprints.Copy() : null
|
||||
data_point[2] = atom_suit_fibers ? atom_suit_fibers.Copy() : null
|
||||
data_point[3] = atom_blood_DNA ? atom_blood_DNA.Copy() : null
|
||||
data_point[4] = atom_name
|
||||
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
|
||||
/********************************
|
||||
***END DO NOT DIRECTLY CALL ME***
|
||||
********************************/
|
||||
|
||||
proc/update_fingerprints(var/ref_print, var/new_print)
|
||||
var/list/master = files[ref_print]
|
||||
if(master)
|
||||
master[1] = stringmerge(master[1],new_print)
|
||||
else
|
||||
CRASH("Fucking hell. Something went wrong, and it tried to update a null print or something. Tell SkyMarshal (and give him this call stack)")
|
||||
return
|
||||
|
||||
proc/process_card() //Same as above, but for fingerprint cards
|
||||
if(card.fingerprints && !(card.amount > 1) && islist(card.fingerprints) && files && files.len)
|
||||
usr << "You insert the card, and it is destroyed by the machinery in the process of comparing prints."
|
||||
var/found = 0
|
||||
for(var/master_print in card.fingerprints)
|
||||
var/list/data_entry = files[master_print]
|
||||
if(data_entry)
|
||||
found = 1
|
||||
data_entry[1] = master_print
|
||||
if(found)
|
||||
usr << "The machinery finds it can complete a match."
|
||||
else
|
||||
usr << "No match found."
|
||||
del(card)
|
||||
else
|
||||
usr << "\red ERROR: No prints/too many cards."
|
||||
if(card.loc == src)
|
||||
card.loc = src.loc
|
||||
card = null
|
||||
return
|
||||
return
|
||||
|
||||
proc/delete_record(var/atom_ref) //Deletes an entry in the misc database at the given location
|
||||
if(misc && misc.len)
|
||||
misc.Remove(atom_ref)
|
||||
return
|
||||
|
||||
proc/delete_dossier(var/print) //Deletes a Dossier at a given location.
|
||||
if(files && files.len)
|
||||
files.Remove(print)
|
||||
return
|
||||
|
||||
detective
|
||||
icon_state = "old"
|
||||
name = "PowerScan Mk.I"
|
||||
73
code/modules/detectivework/forensics.dm
Normal file
73
code/modules/detectivework/forensics.dm
Normal file
@@ -0,0 +1,73 @@
|
||||
//This is the output of the stringpercent(print) proc, and means about 80% of
|
||||
//the print must be there for it to be complete. (Prints are 32 digits)
|
||||
var/const/FINGERPRINT_COMPLETE = 6
|
||||
proc/is_complete_print(var/print)
|
||||
return stringpercent(print) <= FINGERPRINT_COMPLETE
|
||||
|
||||
atom/var/list/suit_fibers
|
||||
|
||||
atom/proc/add_fibers(mob/living/carbon/human/M)
|
||||
if(M.gloves && istype(M.gloves,/obj/item/clothing/gloves))
|
||||
var/obj/item/clothing/gloves/G = M.gloves
|
||||
if(G.transfer_blood) //bloodied gloves transfer blood to touched objects
|
||||
if(add_blood(G.bloody_hands_mob)) //only reduces the bloodiness of our gloves if the item wasn't already bloody
|
||||
G.transfer_blood--
|
||||
else if(M.bloody_hands)
|
||||
if(add_blood(M.bloody_hands_mob))
|
||||
M.bloody_hands--
|
||||
|
||||
if(!suit_fibers) suit_fibers = list()
|
||||
var/fibertext
|
||||
var/item_multiplier = istype(src,/obj/item)?1.2:1
|
||||
var/suit_coverage = 0
|
||||
if(M.wear_suit)
|
||||
fibertext = "Material from \a [M.wear_suit]."
|
||||
if(prob(10*item_multiplier) && !(fibertext in suit_fibers))
|
||||
suit_fibers += fibertext
|
||||
suit_coverage = M.wear_suit.body_parts_covered
|
||||
|
||||
if(M.w_uniform && (M.w_uniform.body_parts_covered & ~suit_coverage))
|
||||
fibertext = "Fibers from \a [M.w_uniform]."
|
||||
if(prob(15*item_multiplier) && !(fibertext in suit_fibers))
|
||||
suit_fibers += fibertext
|
||||
|
||||
if(M.gloves && (M.w_uniform.body_parts_covered & ~suit_coverage))
|
||||
fibertext = "Material from a pair of [M.gloves.name]."
|
||||
if(prob(20*item_multiplier) && !(fibertext in suit_fibers))
|
||||
suit_fibers += "Material from a pair of [M.gloves.name]."
|
||||
|
||||
/datum/data/record/forensic
|
||||
name = "forensic data"
|
||||
var/uid
|
||||
|
||||
/datum/data/record/forensic/New(var/atom/A)
|
||||
uid = "\ref [A]"
|
||||
fields["name"] = sanitize(A.name)
|
||||
fields["area"] = sanitize("[get_area(A)]")
|
||||
fields["fprints"] = A.fingerprints ? A.fingerprints.Copy() : list()
|
||||
fields["fibers"] = A.suit_fibers ? A.suit_fibers.Copy() : list()
|
||||
fields["blood"] = A.blood_DNA ? A.blood_DNA.Copy() : list()
|
||||
fields["time"] = world.time
|
||||
|
||||
/datum/data/record/forensic/proc/merge(var/datum/data/record/other)
|
||||
var/list/prints = fields["fprints"]
|
||||
var/list/o_prints = other.fields["fprints"]
|
||||
for(var/print in o_prints)
|
||||
if(!prints[print])
|
||||
prints[print] = o_prints[print]
|
||||
else
|
||||
prints[print] = stringmerge(prints[print], o_prints[print])
|
||||
fields["fprints"] = prints
|
||||
|
||||
var/list/fibers = fields["fibers"]
|
||||
var/list/o_fibers = other.fields["fibers"]
|
||||
fibers |= o_fibers
|
||||
fields["fibers"] = fibers
|
||||
|
||||
var/list/blood = other.fields["blood"]
|
||||
var/list/o_blood = other.fields["blood"]
|
||||
blood |= o_blood
|
||||
fields["blood"] = blood
|
||||
|
||||
fields["area"] = other.fields["area"]
|
||||
fields["time"] = other.fields["time"]
|
||||
@@ -1,181 +1,107 @@
|
||||
//CONTAINS: Detective's Scanner
|
||||
|
||||
|
||||
/obj/item/device/detective_scanner
|
||||
name = "Scanner"
|
||||
name = "forensic 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 | NOBLUDGEON
|
||||
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."
|
||||
flick("forensic0",src)
|
||||
return 0
|
||||
if (( !( istype(M.dna, /datum/dna) ) || M.gloves) )
|
||||
user << "\blue No fingerprints found on [M]"
|
||||
flick("forensic0",src)
|
||||
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, proximity)
|
||||
if(!proximity) 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.\""
|
||||
flick("forensic0",src)
|
||||
return
|
||||
|
||||
add_fingerprint(user)
|
||||
|
||||
//Special case for blood splatters, runes and gibs.
|
||||
if (istype(A, /obj/effect/decal/cleanable/blood) || istype(A, /obj/effect/rune) || istype(A, /obj/effect/decal/cleanable/blood/gibs))
|
||||
if(!isnull(A.blood_DNA))
|
||||
for(var/blood in A.blood_DNA)
|
||||
user << "\blue Blood type: [A.blood_DNA[blood]]\nDNA: [blood]"
|
||||
flick("forensic2",src)
|
||||
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.gender == MALE ? "him" : "her"] humming[prob(70) ? " gently." : "."]" ,\
|
||||
"\blue Unable to locate any fingerprints, materials, fibers, or blood on [A]!",\
|
||||
"You hear a faint hum of electrical equipment.")
|
||||
flick("forensic0",src)
|
||||
return 0
|
||||
|
||||
if(add_data(A))
|
||||
user << "\blue Object already in internal memory. Consolidating data..."
|
||||
flick("forensic2",src)
|
||||
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."
|
||||
flick("forensic2",src)
|
||||
|
||||
//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.gender == MALE ? "him" : "her"] humming[prob(70) ? " gently." : "."]" ,\
|
||||
"You finish scanning \the [A].",\
|
||||
"You hear a faint hum of electrical equipment.")
|
||||
flick("forensic2",src)
|
||||
return 0
|
||||
else
|
||||
user.visible_message("\The [user] scans \the [A] with \a [src], the air around [user.gender == MALE ? "him" : "her"] humming[prob(70) ? " gently." : "."]\n[user.gender == MALE ? "He" : "She"] 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.")
|
||||
flick("forensic2",src)
|
||||
return 0
|
||||
return
|
||||
|
||||
proc/add_data(atom/A as mob|obj|turf|area)
|
||||
//I love associative lists.
|
||||
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 ? A.fingerprints.Copy() : null
|
||||
sum_list[2] = A.suit_fibers ? A.suit_fibers.Copy() : null
|
||||
sum_list[3] = A.blood_DNA ? A.blood_DNA.Copy() : null
|
||||
sum_list[4] = "\The [A] in \the [get_area(A)]"
|
||||
stored["\ref [A]"] = sum_list
|
||||
/obj/item/device/detective_scanner/attack(mob/living/carbon/human/M as mob, mob/user as mob)
|
||||
if (!ishuman(M))
|
||||
user << "<span class='warning'>[M] is not human and cannot have the fingerprints.</span>"
|
||||
flick("forensic0",src)
|
||||
return 0
|
||||
if (( !( istype(M.dna, /datum/dna) ) || M.gloves) )
|
||||
user << "<span class='notice'>No fingerprints found on [M]</span>"
|
||||
flick("forensic0",src)
|
||||
return 0
|
||||
else
|
||||
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 << "<span class='notice'>Done printing."
|
||||
user << "<span class='notice'>[M]'s Fingerprints: [md5(M.dna.uni_identity)]"
|
||||
if ( M.blood_DNA && M.blood_DNA.len )
|
||||
user << "<span class='notice'>Blood found on [M]. Analysing...</span>"
|
||||
spawn(15)
|
||||
for(var/blood in M.blood_DNA)
|
||||
user << "<span class='notice'>Blood type: [M.blood_DNA[blood]]\nDNA: [blood]</span>"
|
||||
return
|
||||
|
||||
/obj/item/device/detective_scanner/afterattack(atom/A as obj|turf, mob/user, proximity)
|
||||
if(!proximity) return
|
||||
if(ismob(A))
|
||||
return
|
||||
if(istype(A,/obj/machinery/computer/forensic_scanning))
|
||||
user.visible_message("[user] takes a cord out of [src] and hooks its end into [A]" ,\
|
||||
"<span class='notice'>You download data from [src] to [A]</span>")
|
||||
var/obj/machinery/computer/forensic_scanning/F = A
|
||||
F.sync_data(stored)
|
||||
return
|
||||
|
||||
if(istype(A,/obj/item/weapon/f_card))
|
||||
user << "The scanner displays on the screen: \"ERROR 43: Object on Excluded Object List.\""
|
||||
flick("forensic0",src)
|
||||
return
|
||||
|
||||
add_fingerprint(user)
|
||||
|
||||
//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.gender == MALE ? "him" : "her"] humming[prob(70) ? " gently." : "."]" ,\
|
||||
"<span class='warning'>Unable to locate any fingerprints, materials, fibers, or blood on [A]!</span>",\
|
||||
"You hear a faint hum of electrical equipment.")
|
||||
flick("forensic0",src)
|
||||
return 0
|
||||
|
||||
if(add_data(A))
|
||||
user << "<span class='notice'>Object already in internal memory. Consolidating data...</span>"
|
||||
flick("forensic2",src)
|
||||
return
|
||||
|
||||
//PRINTS
|
||||
if(A.fingerprints && A.fingerprints.len)
|
||||
user << "<span class='notice'>Isolated [A.fingerprints.len] fingerprints:</span>"
|
||||
user << "Data Stored: Scan with Hi-Res Forensic Scanner to retrieve.</span>"
|
||||
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 << "<span class='notice'>No intact prints found</span>"
|
||||
else
|
||||
user << "<span class='notice'>Found [complete_prints.len] intact prints</span>"
|
||||
for(var/i in complete_prints)
|
||||
user << "<span class='notice'> [i]</span>"
|
||||
|
||||
//FIBERS
|
||||
if(A.suit_fibers && A.suit_fibers.len)
|
||||
user << "<span class='notice'>Fibers/Materials Data Stored: Scan with Hi-Res Forensic Scanner to retrieve."
|
||||
flick("forensic2",src)
|
||||
|
||||
//Blood
|
||||
if (A.blood_DNA && A.blood_DNA.len)
|
||||
user << "<span class='notice'>Blood detected. Analysing...</span>"
|
||||
spawn(15)
|
||||
for(var/blood in A.blood_DNA)
|
||||
user << "Blood type: \red [A.blood_DNA[blood]] \t \black DNA: \red [blood]"
|
||||
|
||||
user.visible_message("\The [user] scans \the [A] with \a [src], the air around [user.gender == MALE ? "him" : "her"] humming[prob(70) ? " gently." : "."]" ,\
|
||||
"<span class='notice'>You finish scanning \the [A].</span>",\
|
||||
"You hear a faint hum of electrical equipment.")
|
||||
flick("forensic2",src)
|
||||
return 0
|
||||
|
||||
/obj/item/device/detective_scanner/proc/add_data(atom/A as mob|obj|turf|area)
|
||||
var/datum/data/record/forensic/old = stored["\ref [A]"]
|
||||
var/datum/data/record/forensic/fresh = new(A)
|
||||
|
||||
if(old)
|
||||
fresh.merge(old)
|
||||
. = 1
|
||||
stored["\ref [A]"] = fresh
|
||||
305
code/modules/detectivework/scanning_console.dm
Normal file
305
code/modules/detectivework/scanning_console.dm
Normal file
@@ -0,0 +1,305 @@
|
||||
/obj/machinery/computer/forensic_scanning
|
||||
name = "high-res forensic scanning computer"
|
||||
icon_state = "forensic"
|
||||
|
||||
var/screen = "database"
|
||||
var/authenticated = 0
|
||||
req_access = list(access_forensics_lockers)
|
||||
var/scan_progress = -1
|
||||
var/obj/item/scanning
|
||||
var/datum/data/record/forensic/current
|
||||
|
||||
var/list/filters = list()
|
||||
var/list/current_list = list()
|
||||
|
||||
var/list/files = list()
|
||||
|
||||
/obj/machinery/computer/forensic_scanning/proc/get_printable_data(var/datum/data/record/forensic/fresh)
|
||||
. += "<h2>[fresh.fields["name"]]</h2>"
|
||||
. += "Scanned in [fresh.fields["area"]] at [worldtime2text(fresh.fields["time"])]<br>"
|
||||
var/list/prints = fresh.fields["fprints"]
|
||||
if(prints.len)
|
||||
. += "<h3>Fingerprints:</h3>"
|
||||
var/incomplete = 0
|
||||
for(var/fullprint in prints)
|
||||
var/print = prints[fullprint]
|
||||
if(is_complete_print(print))
|
||||
. += "[print]<br>"
|
||||
else
|
||||
incomplete++
|
||||
if(incomplete)
|
||||
. += "[incomplete] incomplete fingerprints."
|
||||
else
|
||||
. += "<br>No fingerprints recorded.<br>"
|
||||
|
||||
var/list/fibers = fresh.fields["fibers"]
|
||||
if(fibers.len)
|
||||
. += "<h3>Fibers:</h3>"
|
||||
. += "<ul>"
|
||||
for(var/fiber in fibers)
|
||||
. += "<li>[fiber]</li>"
|
||||
. += "</ul>"
|
||||
else
|
||||
. += "<br>No fibers recorded."
|
||||
|
||||
var/list/bloods = fresh.fields["blood"]
|
||||
if(bloods.len)
|
||||
. += "<h3>Blood:</h3>"
|
||||
. += "<ul>"
|
||||
for(var/blood in bloods)
|
||||
. += "<li>DNA: [blood] Type: [bloods[blood]]</li>"
|
||||
. += "</ul>"
|
||||
else
|
||||
. += "<br>No blood recorded."
|
||||
|
||||
/obj/machinery/computer/forensic_scanning/proc/add_record(var/datum/data/record/forensic/fresh)
|
||||
var/datum/data/record/forensic/old = files[fresh.uid]
|
||||
if(old)
|
||||
fresh.merge(old)
|
||||
fresh.fields["label"] = old.fields["label"]
|
||||
files[fresh.uid] = fresh
|
||||
|
||||
/obj/machinery/computer/forensic_scanning/proc/process_card(var/obj/item/weapon/f_card/card)
|
||||
if(card.fingerprints)
|
||||
usr << "<span class='notice'>\The [src] sucks in \the [card] and whirrs, scanning it.</span>"
|
||||
var/found = 0
|
||||
for(var/id in files)
|
||||
var/datum/data/record/forensic/rec = files[id]
|
||||
var/list/prints = rec.fields["fprints"]
|
||||
for(var/master_print in card.fingerprints)
|
||||
if(prints[master_print])
|
||||
prints[master_print] = master_print
|
||||
found = 1
|
||||
if(found)
|
||||
usr << "<span class='notice'>Complete match found.</span>"
|
||||
else
|
||||
usr << "<span class='notice'>No match found.</span>"
|
||||
return 1
|
||||
else
|
||||
usr << "<span class='warning'>No fingerprints detected on [card].</span>"
|
||||
return 0
|
||||
|
||||
//Takes a list of forensic records, with key being reference to object, and updates internal database.
|
||||
/obj/machinery/computer/forensic_scanning/proc/sync_data(var/list/newdata)
|
||||
for(var/id in newdata)
|
||||
var/datum/data/record/forensic/fresh = newdata[id]
|
||||
add_record(fresh)
|
||||
|
||||
/obj/machinery/computer/forensic_scanning/proc/get_filtered_set()
|
||||
.= list()
|
||||
for(var/id in files)
|
||||
var/datum/data/record/forensic/cur = files[id]
|
||||
var/add = 1
|
||||
if(filters["name"])
|
||||
add = 0
|
||||
for(var/filter in filters["name"])
|
||||
if(findtext(cur.fields["name"], filter))
|
||||
add = 1
|
||||
break
|
||||
|
||||
if(filters["area"])
|
||||
add = 0
|
||||
for(var/filter in filters["area"])
|
||||
if(findtext(cur.fields["area"], filter))
|
||||
add = 1
|
||||
break
|
||||
|
||||
if(filters["fprints"])
|
||||
add = 0
|
||||
var/list/prints = cur.fields["fprints"]
|
||||
for(var/pid in prints)
|
||||
var/print = prints[pid]
|
||||
if (is_complete_print(print))
|
||||
for(var/filter in filters["fprints"])
|
||||
if(findtext(print, filter))
|
||||
add = 1
|
||||
break
|
||||
|
||||
if(filters["fibers"])
|
||||
add = 0
|
||||
for(var/fiber in cur.fields["fibers"])
|
||||
for(var/filter in filters["fibers"])
|
||||
if(findtext(fiber, filter))
|
||||
add = 1
|
||||
break
|
||||
|
||||
if(filters["blood"])
|
||||
add = 0
|
||||
for(var/DNA in cur.fields["blood"])
|
||||
for(var/filter in filters["blood"])
|
||||
if(findtext(DNA, filter))
|
||||
add = 1
|
||||
break
|
||||
|
||||
if(filters["label"])
|
||||
add = 0
|
||||
for(var/filter in filters["label"])
|
||||
if(cur.fields["label"] && findtext(cur.fields["label"], filter))
|
||||
add = 1
|
||||
break
|
||||
if (add)
|
||||
.+=cur
|
||||
|
||||
/obj/machinery/computer/forensic_scanning/attack_hand(mob/user)
|
||||
if(..())
|
||||
return
|
||||
user.set_machine(src)
|
||||
|
||||
var/dat
|
||||
if(!authenticated)
|
||||
dat += "<a href='?src=\ref[src];operation=login'>{Log In}</a>"
|
||||
else
|
||||
dat += "<a href='?src=\ref[src];operation=logout'>{Log Out}</a>"
|
||||
dat += " | "
|
||||
dat += "<a href='?src=\ref[src];operation=screen;screen=database'>Database</a>"
|
||||
dat += " | "
|
||||
dat += "<a href='?src=\ref[src];operation=screen;screen=details'>Record details</a>"
|
||||
dat += " | "
|
||||
dat += "<a href='?src=\ref[src];operation=screen;screen=scan'>Scanning</a>"
|
||||
dat +="<br><hr><br>"
|
||||
switch(screen)
|
||||
if("database") //Database screen
|
||||
dat += "Search filters:<br>"
|
||||
var/list/filternames = list("Object"="name", "Area"="area", "Fingerprints"="fprints", "Fibers"="fibers", "DNA"="blood", "Label"="label")
|
||||
for(var/filter in filternames)
|
||||
var/fname = filternames[filter]
|
||||
dat += "<br>[filter]: <a href='?src=\ref[src];operation=filter;filter=[fname]'>[filters[fname] ? list2text(filters[fname], ",") : "All"]</a>"
|
||||
|
||||
current_list = get_filtered_set()
|
||||
dat+= "<br><hr><br>"
|
||||
if(current_list.len < 1)
|
||||
dat += "No data matching your request found."
|
||||
else
|
||||
dat += "<table><tr>"
|
||||
dat += "<th>Object</th><th>Area</th><th>Fingerprints</th><th>Fibers</th><th>Blood</th><th>Label</th></tr>"
|
||||
for(var/datum/data/record/forensic/record in current_list)
|
||||
dat += "<tr><td><a href='?src=\ref[src];operation=details;identifier=[record.uid]'>[record.fields["name"]]</td>"
|
||||
dat += "<td>[record.fields["area"]]</td>"
|
||||
for(var/criteria in list("fprints", "fibers", "blood"))
|
||||
var/list/data = record.fields[criteria]
|
||||
dat += "<td>[data.len ? data.len : "None"]</td>"
|
||||
dat += "<td>[record.fields["label"] ? record.fields["label"] : ""]</td>"
|
||||
dat += "<td><a href='?src=\ref[src];operation=delete;identifier=[record.uid]'>Delete</a></td>"
|
||||
dat += "</tr>"
|
||||
dat += "</table>"
|
||||
dat += "<a href='?src=\ref[src];operation=printall'>Print all listed</a><br>"
|
||||
|
||||
if("details") //Details screen
|
||||
if(!current)
|
||||
dat += "<br>NO RECORD SELECTED"
|
||||
else
|
||||
dat += get_printable_data(current)
|
||||
dat += "<b>Labels:</b> "
|
||||
dat += "<a href='?src=\ref[src];operation=label'>[current.fields["label"] ? current.fields["label"] : "None"]</a><br>"
|
||||
dat += "<a href='?src=\ref[src];operation=print'>Print record</a><br>"
|
||||
|
||||
if("scan") //Scanning screen
|
||||
dat += "Object: <a href='?src=\ref[src];operation=object'>[scanning ? scanning.name : "-----"]</a><br>"
|
||||
if (scanning)
|
||||
if (scan_progress > 0)
|
||||
dat += "Scan in progress."
|
||||
dat += " <a href='?src=\ref[src];operation=cancel'>Cancel</a><br>"
|
||||
else
|
||||
dat += "<a href='?src=\ref[src];operation=scan'>Scan</a><br>"
|
||||
dat += "Insert fingerprint card here: <a href='?src=\ref[src];operation=card'>-----</a>"
|
||||
|
||||
user << browse(dat,"window=fscanner")
|
||||
onclose(user,"fscanner")
|
||||
|
||||
/obj/machinery/computer/forensic_scanning/Topic(href,href_list)
|
||||
switch(href_list["operation"])
|
||||
if("login")
|
||||
var/mob/M = usr
|
||||
if(istype(M,/mob/living/silicon) || allowed(M))
|
||||
authenticated = 1
|
||||
if("logout")
|
||||
authenticated = 0
|
||||
if("filter")
|
||||
var/filterstr = stripped_input(usr,"Input the search criteria. Multiple values can be input, separated by a comma.", "Filter setting") as text|null
|
||||
if(filterstr)
|
||||
filters[href_list["filter"]] = text2list(filterstr,",")
|
||||
else
|
||||
filters[href_list["filter"]] = null
|
||||
if("screen")
|
||||
screen = href_list["screen"]
|
||||
if("details")
|
||||
if(href_list["identifier"])
|
||||
screen = "details"
|
||||
current = files[href_list["identifier"]]
|
||||
else
|
||||
usr << "<spawn class='warning'>No record found.</span>"
|
||||
if("delete")
|
||||
if(href_list["identifier"])
|
||||
if(alert("Are you sure you want to delete this record?","Record deletion", "Yes", "No") == "Yes")
|
||||
files.Remove(href_list["identifier"])
|
||||
if(current && current.uid == href_list["identifier"])
|
||||
current = null
|
||||
if("label")
|
||||
if(current)
|
||||
var/label = stripped_input(usr,"Input the label for this record. Multiple values can be input, separated by a comma.", "Labeling record", current.fields["label"]) as text|null
|
||||
current.fields["label"] = label
|
||||
if("object")
|
||||
if(scanning)
|
||||
scanning.loc = get_turf(src)
|
||||
scan_progress = -1
|
||||
scanning = null
|
||||
else
|
||||
var/mob/M = usr
|
||||
var/obj/item/I = M.get_active_hand()
|
||||
if(I && istype(I))
|
||||
if(istype(I, /obj/item/weapon/evidencebag))
|
||||
scanning = I.contents[1]
|
||||
scanning.loc = src
|
||||
I.overlays.Cut()
|
||||
I.w_class = 1
|
||||
I.icon_state = "evidenceobj"
|
||||
else
|
||||
scanning = I
|
||||
M.drop_item()
|
||||
I.loc = src
|
||||
else
|
||||
usr << "<spawn class='warning'>Invalid object, rejected.</span>"
|
||||
if("scan")
|
||||
if(scanning)
|
||||
scan_progress = 10
|
||||
if("cancel")
|
||||
scan_progress = -1
|
||||
if("card")
|
||||
var/mob/M = usr
|
||||
var/obj/item/I = M.get_active_hand()
|
||||
if(istype(I, /obj/item/weapon/f_card))
|
||||
if(process_card(I))
|
||||
M.drop_item()
|
||||
del(I)
|
||||
else
|
||||
usr << "<spawn class='warning'>Invalid fingerprint card, rejected.</span>"
|
||||
if("print")
|
||||
if(current)
|
||||
var/obj/item/weapon/paper/P = new(loc)
|
||||
P.name = "\improper Forensics Data ([current.fields["name"]])"
|
||||
P.icon_state = "paper_words"
|
||||
P.info = "<b>Forensics Database</b> - [worldtime2text(world.time)]<br><br>"
|
||||
P.info += get_printable_data(current)
|
||||
if("printall")
|
||||
var/obj/item/weapon/paper/P = new(loc)
|
||||
P.name = "\improper Forensics Data"
|
||||
P.icon_state = "paper_words"
|
||||
P.info = "<b>Forensics Database</b> - [worldtime2text(world.time)]<br><br>"
|
||||
for(var/datum/data/record/forensic/cur in current_list)
|
||||
P.info += get_printable_data(cur)
|
||||
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/computer/forensic_scanning/process()
|
||||
if (!..())
|
||||
return
|
||||
if(scanning)
|
||||
if(scan_progress > 0)
|
||||
scan_progress--
|
||||
updateUsrDialog()
|
||||
if(scan_progress == 0)
|
||||
scan_progress = -1
|
||||
ping("Scan complete.")
|
||||
var/datum/data/record/forensic/fresh = new(scanning)
|
||||
add_record(fresh)
|
||||
updateUsrDialog()
|
||||
Reference in New Issue
Block a user