//CONTAINS: Detective's Scanner // TODO: Split everything into easy to manage procs. /obj/item/detective_scanner name = "forensic scanner" desc = "Used to remotely scan objects and biomass for DNA and fingerprints. Can print a report of the findings." icon = 'icons/goonstation/objects/objects.dmi' icon_state = "detscanner" w_class = WEIGHT_CLASS_NORMAL item_state = "electronic" flags = CONDUCT | NOBLUDGEON slot_flags = SLOT_FLAG_BELT origin_tech = "engineering=4;biotech=2;programming=5" var/scanning = FALSE var/list/log = list() actions_types = list(/datum/action/item_action/print_forensic_report, /datum/action/item_action/clear_records) /obj/item/detective_scanner/attack_self(mob/user) var/search = input(user, "Enter name, fingerprint or blood DNA.", "Find record", "") if(!search || user.stat || user.incapacitated()) return search = lowertext(search) //This is here so that it doesn't run 'lowertext()' until the checks have passed. var/name var/fingerprint = "FINGERPRINT NOT FOUND" var/dna = "BLOOD DNA NOT FOUND" // I really, really wish I didn't have to split this into two seperate loops. But the datacore is awful. for(var/record in GLOB.data_core.general) // Search in the 'general' datacore var/datum/data/record/S = record if(S && (search == lowertext(S.fields["fingerprint"]) || search == lowertext(S.fields["name"]))) // Get Fingerprint and Name name = S.fields["name"] fingerprint = S.fields["fingerprint"] break for(var/record in GLOB.data_core.medical) // Then search in the 'medical' datacore var/datum/data/record/M = record if(M && (search == lowertext(M.fields["b_dna"]) || name == M.fields["name"])) // Get Blood DNA dna = M.fields["b_dna"] if(fingerprint == "FINGERPRINT NOT FOUND") // We have searched for DNA, and so do not have the relevant information from the fingerprint records. name = M.fields["name"] for(var/gen_record in GLOB.data_core.general) var/datum/data/record/S = gen_record if(S && (name == S.fields["name"])) fingerprint = S.fields["fingerprint"] break else //Eveything's been set, break the loop break if(name) to_chat(user, "Match found in station records: [name]
\ Fingerprint: [fingerprint]
\ Blood DNA: [dna]") else to_chat(user, "No match found in station records.") /obj/item/detective_scanner/ui_action_click(mob/user, actiontype) if(actiontype == /datum/action/item_action/print_forensic_report) print_scanner_report() else clear_scanner() /obj/item/detective_scanner/proc/print_scanner_report() if(length(log) && !scanning) scanning = TRUE to_chat(usr, "Printing report, please wait...") playsound(loc, 'sound/goonstation/machines/printer_thermal.ogg', 50, 1) addtimer(CALLBACK(src, PROC_REF(make_paper), log), 10 SECONDS) // Create our paper log = list() // Clear the logs scanning = FALSE else to_chat(usr, "The scanner has no logs or is in use.") /obj/item/detective_scanner/proc/make_paper(log) // Moved to a proc because 'spawn()' is evil var/obj/item/paper/P = new(get_turf(src)) P.name = "paper- 'Scanner Report'" P.info = "
Scanner Report


" P.info += jointext(log, "
") P.info += "
Notes:
" P.info_links = P.info if(ismob(loc)) var/mob/M = loc M.put_in_hands(P) to_chat(M, "Report printed. Log cleared.") /obj/item/detective_scanner/proc/clear_scanner() if(length(log) && !scanning) log = list() playsound(loc, 'sound/machines/ding.ogg', 40) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), usr, "Scanner logs cleared."), 1.5 SECONDS) //Timer so that it clears on the 'ding' else to_chat(usr, "The scanner has no logs or is in use.") /obj/item/detective_scanner/attack() return /obj/item/detective_scanner/afterattack(atom/A, mob/user) scan(A, user) /obj/item/detective_scanner/proc/scan(atom/A, mob/user) if(!scanning) // Can remotely scan objects and mobs. if(!(A in view(world.view, user))) return if(loc != user) return scanning = TRUE user.visible_message("[user] points [src] at [A] and performs a forensic scan.", "You scan [A]. The scanner is now analysing the results...") // GATHER INFORMATION //Make our lists var/list/fingerprints = list() var/list/blood = list() var/list/fibers = list() var/list/reagents = list() var/target_name = A.name // Start gathering if(length(A.blood_DNA)) blood = A.blood_DNA.Copy() if(length(A.suit_fibers)) fibers = A.suit_fibers.Copy() if(ishuman(A)) var/mob/living/carbon/human/H = A if(istype(H.dna, /datum/dna) && !H.gloves) fingerprints += md5(H.dna.uni_identity) else if(!ismob(A)) if(length(A.fingerprints)) fingerprints = A.fingerprints.Copy() // Only get reagents from non-mobs. if(A.reagents && length(A.reagents.reagent_list)) for(var/datum/reagent/R in A.reagents.reagent_list) reagents[R.name] = R.volume // Get blood data from the blood reagent. if(istype(R, /datum/reagent/blood)) if(R.data["blood_DNA"] && R.data["blood_type"]) var/blood_DNA = R.data["blood_DNA"] var/blood_type = R.data["blood_type"] blood[blood_DNA] = blood_type // We gathered everything. Slowly display the results to the holder of the scanner. var/found_something = FALSE add_log("[station_time_timestamp()][get_timestamp()] - [target_name]", FALSE) // Fingerprints if(length(fingerprints)) sleep(30) add_log("Prints:") for(var/finger in fingerprints) add_log("[finger]") found_something = TRUE // Blood if(length(blood)) sleep(30) add_log("Blood:") found_something = TRUE for(var/B in blood) add_log("Type: [blood[B]] DNA: [B]") //Fibers if(length(fibers)) sleep(30) add_log("Fibers:") for(var/fiber in fibers) add_log("[fiber]") found_something = TRUE //Reagents if(length(reagents)) sleep(30) add_log("Reagents:") for(var/R in reagents) add_log("Reagent: [R] Volume: [reagents[R]]") found_something = TRUE // Get a new user var/mob/holder = null if(ismob(loc)) holder = loc if(!found_something) add_log("# No forensic traces found #", FALSE) // Don't display this to the holder user if(holder) to_chat(holder, "Unable to locate any fingerprints, materials, fibers, or blood on [A]!") else if(holder) to_chat(holder, "You finish scanning [A].") add_log("---------------------------------------------------------", FALSE) scanning = FALSE /obj/item/detective_scanner/proc/add_log(msg, broadcast = TRUE) if(scanning) if(broadcast && ismob(loc)) var/mob/M = loc to_chat(M, msg) log += "  [msg]" else CRASH("[src] \ref[src] is adding a log when it was never put in scanning mode!") /proc/get_timestamp() return time2text(world.time + 432000, ":ss")