//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/obj/device.dmi' icon_state = "forensicnew" w_class = WEIGHT_CLASS_SMALL item_state = "electronic" lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' flags_1 = CONDUCT_1 item_flags = NOBLUDGEON slot_flags = ITEM_SLOT_BELT var/scanning = FALSE var/list/log = list() var/range = 8 var/view_check = TRUE var/forensicPrintCount = 0 actions_types = list(/datum/action/item_action/displayDetectiveScanResults) /datum/action/item_action/displayDetectiveScanResults name = "Display Forensic Scanner Results" /datum/action/item_action/displayDetectiveScanResults/Trigger() var/obj/item/detective_scanner/scanner = target if(istype(scanner)) scanner.displayDetectiveScanResults(usr) /obj/item/detective_scanner/attack_self(mob/user) if(log.len && !scanning) scanning = TRUE to_chat(user, "Printing report, please wait...") addtimer(CALLBACK(src, .proc/PrintReport), 100) else to_chat(user, "The scanner has no logs or is in use.") /obj/item/detective_scanner/attack(mob/living/M, mob/user) return /obj/item/detective_scanner/proc/PrintReport() // Create our paper var/obj/item/paper/P = new(get_turf(src)) //This could be a global count like sec and med record printouts. See GLOB.data_core.medicalPrintCount AKA datacore.dm var frNum = ++forensicPrintCount P.name = text("FR-[] 'Forensic Record'", frNum) P.info = text("
Forensic Record - (FR-[])


", frNum) P.info += jointext(log, "
") P.info += "
Notes:
" P.update_icon() if(ismob(loc)) var/mob/M = loc M.put_in_hands(P) to_chat(M, "Report printed. Log cleared.") // Clear the logs log = list() scanning = FALSE /obj/item/detective_scanner/afterattack(atom/A, mob/user, params) . = ..() scan(A, user) return FALSE /obj/item/detective_scanner/proc/scan(atom/A, mob/user) set waitfor = 0 if(!scanning) // Can remotely scan objects and mobs. if((get_dist(A, user) > range) || (!(A in view(range, user)) && view_check) || (loc != user)) return scanning = TRUE user.visible_message("\The [user] points the [src.name] at \the [A] and performs a forensic scan.") to_chat(user, "You scan \the [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(A.blood_DNA && A.blood_DNA.len) blood = A.blood_DNA.Copy() if(A.suit_fibers && A.suit_fibers.len) fibers = A.suit_fibers.Copy() if(ishuman(A)) var/mob/living/carbon/human/H = A if(!H.gloves) fingerprints += md5(H.dna.uni_identity) else if(!ismob(A)) if(A.fingerprints && A.fingerprints.len) fingerprints = A.fingerprints.Copy() // Only get reagents from non-mobs. if(A.reagents && A.reagents.reagent_list.len) 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"] LAZYINITLIST(blood) blood[blood_DNA] = blood_type // We gathered everything. Create a fork and slowly display the results to the holder of the scanner. var/found_something = FALSE add_log("[STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)][get_timestamp()] - [target_name]", 0) // Fingerprints if(length(fingerprints)) sleep(3 SECONDS) add_log("Prints:") for(var/finger in fingerprints) add_log("[finger]") found_something = TRUE // Blood if (length(blood)) sleep(3 SECONDS) add_log("Blood:") found_something = TRUE for(var/B in blood) if(B == "color") continue add_log("Type: [blood[B]] DNA: [B]") //Fibers if(length(fibers)) sleep(3 SECONDS) add_log("Fibers:") for(var/fiber in fibers) add_log("[fiber]") found_something = TRUE //Reagents if(length(reagents)) sleep(3 SECONDS) 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(src.loc)) holder = src.loc if(!found_something) add_log("# No forensic traces found #", 0) // Don't display this to the holder user if(holder) to_chat(holder, "Unable to locate any fingerprints, materials, fibers, or blood on \the [target_name]!") else if(holder) to_chat(holder, "You finish scanning \the [target_name].") add_log("---------------------------------------------------------", 0) scanning = FALSE return /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") /obj/item/detective_scanner/AltClick(mob/living/user) . = ..() // Best way for checking if a player can use while not incapacitated, etc if(!user.canUseTopic(src, be_close=TRUE)) return . = TRUE if(!LAZYLEN(log)) to_chat(user, "Cannot clear logs, the scanner has no logs.") return if(scanning) to_chat(user, "Cannot clear logs, the scanner is in use.") return to_chat(user, "The scanner logs are cleared.") log = list() /obj/item/detective_scanner/examine(mob/user) . = ..() if(LAZYLEN(log) && !scanning) . += "Alt-click to clear scanner logs." /obj/item/detective_scanner/proc/displayDetectiveScanResults(mob/living/user) // No need for can-use checks since the action button should do proper checks if(!LAZYLEN(log)) to_chat(user, "Cannot display logs, the scanner has no logs.") return if(scanning) to_chat(user, "Cannot display logs, the scanner is in use.") return to_chat(user, "Scanner Report") for(var/iterLog in log) to_chat(user, iterLog)