/
githubmirror
/
vgstation13
Обзор
Документация
Войти
/
githubmirror
/
vgstation13
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
Bleeding-Edge
code/modules/detectivework/detective_work.dm
692 строки
26 KB
SECBATON GRIFFON
Makes forensic computer much easier to use. (#38760)
03 янв 2026, 17:00
Не верифицирован
03 янв 2026, 17:00
3737816
Код
Авторство
О чём код?
//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_from_data(G.bloody_hands_data)) //only reduces the bloodiness of our gloves if the item wasn't already bloody G.transfer_blood-- M.update_inv_gloves() else if(M.bloody_hands > 1) if(add_blood_from_data(M.bloody_hands_data)) M.bloody_hands-- M.update_inv_gloves() 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 & 32)) 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 & 64)) 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 /atom/proc/add_custom_fibers(var/txt, var/duplicates = TRUE) if(!suit_fibers) suit_fibers = list() if(duplicates) suit_fibers += txt else suit_fibers |= txt #define SCAN_STEPS 8 /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 circuit = "/obj/item/weapon/circuitboard/forensic_computer" light_color = LIGHT_COLOR_RED //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) /obj/machinery/computer/forensic_scanning/attack_hand(mob/user) if(..()) return user.set_machine(src) var/dat = "" var/isai = FALSE if(isAI(user)) isai = TRUE 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: <span class='linkOff'>[scanning.name]</span><br> <a href='?src=\ref[src];operation=cancel'>Cancel Scan</a> <span class='linkOff'>Print</span><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 += "<span class='linkOff'>Scan</span> <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>" var/datum/browser/popup = new(user, "scanner", "Forensic Scanning Computer", 375, 500, src) popup.set_content(dat) popup.open() onclose(user, "scanner") /obj/machinery/computer/forensic_scanning/attackby(obj/item/I, mob/user) . = ..() if(authenticated) if(isgripper(I)) if(scanning) to_chat(usr, "<span class='warning'>There is already \a [scanning] in the scanning slot!.</span>") return var/obj/item/weapon/gripper/G = I if(G.wrapped && G.drop_item(I)) scanning = G.wrapped //We add it as scanned object first because we'll lose the wrapped reference once we drop it. else if(istype(I,/obj/item/weapon/f_card)) if(files && files.len) card = I if(!card.fingerprints) card.fingerprints = list() if(card.amount > 1 || !card.fingerprints.len) to_chat(usr, "<span class='warning'>ERROR: No prints/too many cards.</span>") if(card.loc == src) card.forceMove(src.loc) card = null return if(user.drop_item(I, src)) process_card() else to_chat(usr, "<span class='warning'>No files detected to scan with [I].</span>") return if(I && scanning) to_chat(usr, "<span class='warning'>There is already \a [scanning] in the scanning slot!.</span>") return if(istype(I, /obj/item/weapon/storage/evidencebag)) if(I.contents.len) var/obj/item/weapon/storage/evidencebag/EVB = I scanning = EVB.contents[1] EVB.remove_from_storage(scanning, src, TRUE, TRUE) else if(user.drop_item(I, src)) scanning = I updateUsrDialog() /obj/machinery/computer/forensic_scanning/Topic(href,href_list) . = ..() if(.) return switch(href_list["operation"]) if("login") var/mob/M = usr if(issilicon(M)) authenticated = 1 updateDialog() if(allowed(M)) authenticated = 1 if("logout") authenticated = 0 if("clear") if(canclear) temp = null if("eject") if(scanning) scanning.forceMove(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(isgripper(I)) var/obj/item/weapon/gripper/G = I if(G.wrapped) scanning = G.wrapped //We add it as scanned object first because we'll lose the wrapped reference once we drop it. G.drop_item(G.wrapped, src) else if(istype(I, /obj/item/weapon/storage/evidencebag) && I.contents.len) var/obj/item/weapon/storage/evidencebag/EVB = I scanning = EVB.contents[1] EVB.remove_from_storage(scanning, src, TRUE, TRUE) else if(M.drop_item(I, src)) scanning = I else to_chat(usr, "<span class='warning'>Invalid Object Rejected.</span>") 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) to_chat(usr, "<span class='warning'>ERROR: No prints/too many cards.</span>") if(card.loc == src) card.forceMove(src.loc) card = null return if(M.drop_item(I, src)) process_card() else to_chat(usr, "<span class='warning'>Invalid Object Rejected.</span>") 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> 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 to_chat(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>  <b>Fingerprints:</b><br> [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> <br><a href='?src=\ref[src];operation=database;delete_record=[href_list["identifier"]]'>Delete this Dossier</a> <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.overlays += image(icon = P.icon, icon_state = "paper_words") P.info = {"<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>" 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>  <b>Fingerprints:</b><br> [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 to_chat(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> [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> <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.overlays += image(icon = P.icon, icon_state = "paper_words") P.info = {"<b>Auxiliary Evidence Database</b><br><br> <big><b>Consolidated data points:</b> [outputs[3]]</big><br>"} var/list/prints = outputs[4] if(prints) P.info += {" <b>Fingerprints:</b><br> [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 to_chat(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 = SCAN_STEPS 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.overlays += image(icon = P.icon, icon_state = "paper_words") else temp = "Print Failed: No Data" if("erase") scan_data = "" if("cancel") if(scan_process > 0) scan_data = "" 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() /obj/machinery/computer/forensic_scanning/process() if(..()) if(scan_process > 0) scan_process-- scan_data = "Scanning [scanning]: [(100/SCAN_STEPS)*(SCAN_STEPS-scan_process)]% complete" if(scan_process <= 0) 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>" var/is_scanner = istype(scanning, /obj/item/device/detective_scanner) /*if(istype(scanning, /obj/item/device/pda)) var/obj/item/device/pda/the_pda = scanning if(istype(the_pda.scanning_app,/datum/pda_app/cart/scanner/detective)) is_scanner = TRUE*/ if(is_scanner) 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 scan_data = null updateUsrDialog() /obj/machinery/computer/forensic_scanning/ex_act() return /obj/machinery/computer/forensic_scanning/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)) var/obj/item/device/pda/the_pda = W istype(the_pda.scanning_app,/datum/pda_app/cart/scanner/detective) var/datum/pda_app/cart/scanner/detective/D = the_pda.scanning_app if(D.stored_data) for(var/atom in D) var/list/data = D[atom] add_data_master(atom,data[1],data[2],data[3],data[4]) D.stored_data = list()*/ return /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] (Direct Scan)") /******************************** *****DO NOT DIRECTLY CALL ME***** ********************************/ /obj/machinery/computer/forensic_scanning/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*** ********************************/ /obj/machinery/computer/forensic_scanning/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 /obj/machinery/computer/forensic_scanning/proc/process_card() //Same as above, but for fingerprint cards if(card.fingerprints && !(card.amount > 1) && islist(card.fingerprints) && files && files.len) to_chat(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) to_chat(usr, "The machinery finds it can complete a match.") else to_chat(usr, "No match found.") QDEL_NULL(card) else to_chat(usr, "<span class='warning'>ERROR: No prints/too many cards.</span>") if(card.loc == src) card.forceMove(src.loc) card = null return return /obj/machinery/computer/forensic_scanning/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 /obj/machinery/computer/forensic_scanning/proc/delete_dossier(var/print) //Deletes a Dossier at a given location. if(files && files.len) files.Remove(print) return /obj/machinery/computer/forensic_scanning/detective icon_state = "old" name = "PowerScan Mk.I"