mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-28 15:47:15 +01:00
refactor detective scan categories, fix some categories not being shown at all, remove Syndicate scan category (#93138)
## About The Pull Request Refactor detective scan categories. Fix some categories not being shown at all. Remove Syndicate scan category. <details> <summary>TGUI</summary> <img width="514" height="545" alt="image" src="https://github.com/user-attachments/assets/754ce576-545e-40e5-9fad-86f19d8d2606" /> </details> <details> <summary>Paper report</summary> <img width="460" height="609" alt="image" src="https://github.com/user-attachments/assets/e37e1965-e90a-4e0c-8109-f4384d6a4a79" /> </details> ## Why It's Good For The Game DETSCAN_CATEGORY_SETTINGS, DETSCAN_CATEGORY_HOLY, DETSCAN_CATEGORY_ILLEGAL and DETSCAN_CATEGORY_NOTES are now shown in detective scanner ui and printed report. Cleaner code ## Changelog 🆑 fix: energy dagger pen report will be now shown in detective scanner and also all items that transform will have additional note about it /🆑 --------- Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
GLOBAL_LIST_INIT_TYPED(detective_scan_categories, /datum/detective_scan_category, initialize_detective_scan_categories())
|
||||
|
||||
/proc/initialize_detective_scan_categories()
|
||||
var/list/categories = list()
|
||||
for(var/datum/detective_scan_category/category_path as anything in subtypesof(/datum/detective_scan_category))
|
||||
var/datum/detective_scan_category/existing_category = categories[category_path::id]
|
||||
if(!isnull(existing_category))
|
||||
stack_trace("`[category_path]` has duplicate id - `[category_path::id]` of `[existing_category.type]`")
|
||||
continue
|
||||
|
||||
categories[category_path::id] = new category_path
|
||||
|
||||
return categories
|
||||
|
||||
/datum/detective_scan_category
|
||||
/// Category ID. Must be defined in `code/__DEFINES/security.dm`
|
||||
var/id = "no id"
|
||||
/// Name of scan category. Used in UIs and in paper
|
||||
var/name = "no name"
|
||||
/// Order the data with this category will be sorted by
|
||||
var/display_order = 0
|
||||
/// Fontawesome icon used in TGUI near this category data entry
|
||||
var/ui_icon = "question"
|
||||
/// Fontawesome icon color used in TGUI near this category data entry
|
||||
var/ui_icon_color = "white"
|
||||
|
||||
/// Generates report data used in `/datum/detective_scanner_log/proc/generate_report_text()`
|
||||
/datum/detective_scan_category/proc/generate_report_data(list/data)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
|
||||
var/list/report_text = list()
|
||||
report_text += "<dt><b>[name]</b></dt><dd>"
|
||||
|
||||
for(var/entry in data)
|
||||
report_text += format_report_entry(entry, data[entry])
|
||||
|
||||
report_text += "</dd>"
|
||||
return report_text
|
||||
|
||||
/// Formats entered log data. Can be used to have unique formating per each category
|
||||
/datum/detective_scan_category/proc/format_report_entry(entry, entry_associated_value)
|
||||
return "[entry]<br>"
|
||||
|
||||
/datum/detective_scan_category/fingers
|
||||
id = DETSCAN_CATEGORY_FINGERS
|
||||
name = "Fingerprints"
|
||||
display_order = 1
|
||||
ui_icon = "fingerprint"
|
||||
ui_icon_color = "yellow"
|
||||
|
||||
/datum/detective_scan_category/blood
|
||||
id = DETSCAN_CATEGORY_BLOOD
|
||||
name = "Blood DNA, Type"
|
||||
display_order = 2
|
||||
ui_icon = "droplet"
|
||||
ui_icon_color = "red"
|
||||
|
||||
/datum/detective_scan_category/blood/format_report_entry(entry, entry_associated_value)
|
||||
return "[entry], [entry_associated_value]<br>"
|
||||
|
||||
/datum/detective_scan_category/fiber
|
||||
id = DETSCAN_CATEGORY_FIBER
|
||||
name = "Fibers"
|
||||
display_order = 3
|
||||
ui_icon = "shirt"
|
||||
ui_icon_color = "green"
|
||||
|
||||
/datum/detective_scan_category/drink
|
||||
id = DETSCAN_CATEGORY_REAGENTS
|
||||
name = "Reagents"
|
||||
display_order = 4
|
||||
ui_icon = "flask"
|
||||
ui_icon_color = "blue"
|
||||
|
||||
/datum/detective_scan_category/drink/format_report_entry(entry, entry_associated_value)
|
||||
return "<b>[entry]</b>: [entry_associated_value] u.<br>"
|
||||
|
||||
/datum/detective_scan_category/access
|
||||
id = DETSCAN_CATEGORY_ACCESS
|
||||
name = "ID Access"
|
||||
display_order = 5
|
||||
ui_icon = "id-card"
|
||||
ui_icon_color = "blue"
|
||||
|
||||
/datum/detective_scan_category/access/format_report_entry(entry, entry_associated_value)
|
||||
var/list/associated_value_list = entry_associated_value
|
||||
return "<b>[entry]</b>: [associated_value_list]<br>"
|
||||
|
||||
/datum/detective_scan_category/setting
|
||||
id = DETSCAN_CATEGORY_SETTINGS
|
||||
name = "Active settings"
|
||||
display_order = 6
|
||||
ui_icon = "wrench"
|
||||
ui_icon_color = "orange"
|
||||
|
||||
/datum/detective_scan_category/holy
|
||||
id = DETSCAN_CATEGORY_HOLY
|
||||
name = "Holy data"
|
||||
display_order = 7
|
||||
ui_icon = "book-bible"
|
||||
ui_icon_color = "brown"
|
||||
|
||||
/datum/detective_scan_category/illegal
|
||||
id = DETSCAN_CATEGORY_ILLEGAL
|
||||
name = "Illegal tech"
|
||||
display_order = 8
|
||||
ui_icon = "handcuffs"
|
||||
ui_icon_color = "red"
|
||||
|
||||
/datum/detective_scan_category/notes
|
||||
id = DETSCAN_CATEGORY_NOTES
|
||||
name = "Additional notes"
|
||||
ui_icon = "clipboard"
|
||||
ui_icon_color = "yellow"
|
||||
display_order = 9
|
||||
@@ -0,0 +1,25 @@
|
||||
/proc/cmp_detective_scanner_data_entry(datum/detective_scanner_data_entry/a, datum/detective_scanner_data_entry/b)
|
||||
return cmp_numeric_asc(a.display_order, b.display_order)
|
||||
|
||||
/datum/detective_scanner_data_entry
|
||||
/// Category this data entry is related to
|
||||
var/category
|
||||
/// Order this entry will be displayed in TGUI and paper report
|
||||
var/display_order = 0
|
||||
/// List of data for this entry. Displayed in UIs and paper report
|
||||
var/list/data = list()
|
||||
|
||||
/datum/detective_scanner_data_entry/New(category, display_order, data)
|
||||
src.category = category
|
||||
src.display_order = display_order
|
||||
if(!isnull(data))
|
||||
src.data += data
|
||||
|
||||
/datum/detective_scanner_data_entry/ui_data(mob/user)
|
||||
var/list/ui_data = list()
|
||||
ui_data["category"] = category
|
||||
ui_data["data"] = data
|
||||
return ui_data
|
||||
|
||||
/datum/detective_scanner_data_entry/proc/add_data(data)
|
||||
src.data += data
|
||||
@@ -0,0 +1,65 @@
|
||||
/datum/detective_scanner_log
|
||||
/// Name of the scanned atom
|
||||
var/scan_target
|
||||
/// Time the scan was performed at
|
||||
var/scan_time
|
||||
/// `data_entries` is an assoc list, which can't use `BINARY_INSERT`
|
||||
/// And to not perform sorting pipeline every time new data is added,
|
||||
/// this var will be utilized to only sort list when it's required
|
||||
var/sorted = TRUE
|
||||
/// Scan data for current log
|
||||
var/list/data_entries = list()
|
||||
|
||||
/datum/detective_scanner_log/ui_data(mob/user)
|
||||
var/list/ui_data = list()
|
||||
ui_data["scanTarget"] = scan_target
|
||||
ui_data["scanTime"] = scan_time
|
||||
|
||||
sort_data_entries()
|
||||
var/list/data_entries_ui_data = list()
|
||||
for(var/key,value in data_entries)
|
||||
var/datum/detective_scanner_data_entry/entry = value
|
||||
UNTYPED_LIST_ADD(data_entries_ui_data, entry.ui_data(user))
|
||||
|
||||
ui_data["dataEntries"] = data_entries_ui_data
|
||||
return ui_data
|
||||
|
||||
/// Adds new data entry to `data_entries` or updates existing one
|
||||
/// Entries will be not sorted after using it
|
||||
/// Returns TRUE if `data_entries` can be unsorted
|
||||
/datum/detective_scanner_log/proc/add_data_entry(scan_category_id, data)
|
||||
var/datum/detective_scan_category/category = GLOB.detective_scan_categories[scan_category_id]
|
||||
if(isnull(category))
|
||||
stack_trace("scan_category_id - `[scan_category_id]` with no corresponding `/datum/detective_scan_category`")
|
||||
category = GLOB.detective_scan_categories[DETSCAN_CATEGORY_NOTES]
|
||||
|
||||
var/datum/detective_scanner_data_entry/data_entry = data_entries[category.id]
|
||||
if(!isnull(data_entry))
|
||||
data_entry.add_data(data)
|
||||
return
|
||||
|
||||
data_entries[scan_category_id] = new /datum/detective_scanner_data_entry(scan_category_id, category.display_order, data)
|
||||
sorted = (length(data_entries) <= 1)
|
||||
|
||||
/// Sorts the `data_entries` list if it's considered not sorted
|
||||
/datum/detective_scanner_log/proc/sort_data_entries()
|
||||
if(!sorted)
|
||||
sortTim(data_entries, GLOBAL_PROC_REF(cmp_detective_scanner_data_entry), TRUE)
|
||||
sorted = TRUE
|
||||
|
||||
/// Return text that will be used in printed paper report
|
||||
/// Called in `/obj/item/detective_scanner/proc/print_report()`
|
||||
/datum/detective_scanner_log/proc/generate_report_text()
|
||||
var/list/report_text = list()
|
||||
report_text += "<h2>[capitalize(scan_target)] scan at [scan_time]</h2><dr>"
|
||||
if(!length(data_entries))
|
||||
report_text += "No forensic traces found."
|
||||
else
|
||||
sort_data_entries()
|
||||
for(var/log_category,data_entry in data_entries)
|
||||
var/datum/detective_scanner_data_entry/data_entry_datum = data_entry
|
||||
report_text += GLOB.detective_scan_categories[log_category].generate_report_data(data_entry_datum.data)
|
||||
|
||||
report_text += "</dl><hr>"
|
||||
|
||||
return report_text
|
||||
@@ -44,49 +44,12 @@
|
||||
var/frNum = ++forensicPrintCount
|
||||
|
||||
report_paper.name = "FR-[frNum] 'Forensic Record'"
|
||||
var/list/report_text = list("<H1>Forensic Record - (FR-[frNum])</H1><HR>")
|
||||
var/list/report_text = list("<h1>Forensic Record - (FR-[frNum])</h1><hr>")
|
||||
|
||||
for(var/list/log in log_data)
|
||||
report_text += "<H2>[capitalize(log["scan_target"])] scan at [log["scan_time"]]</H2><DL>"
|
||||
for(var/datum/detective_scanner_log/log_entry as anything in log_data)
|
||||
report_text += log_entry.generate_report_text()
|
||||
|
||||
if(!log[DETSCAN_CATEGORY_FIBER] && !log[DETSCAN_CATEGORY_BLOOD] && !log[DETSCAN_CATEGORY_FINGERS] && !log[DETSCAN_CATEGORY_DRINK] && !log[DETSCAN_CATEGORY_ACCESS])
|
||||
report_text += "No forensic traces found.<HR>"
|
||||
continue
|
||||
|
||||
if(log[DETSCAN_CATEGORY_FIBER])
|
||||
report_text += "<DT><B>[DETSCAN_CATEGORY_FIBER]</B></DT><DD>"
|
||||
for(var/fibers in log[DETSCAN_CATEGORY_FIBER])
|
||||
report_text += fibers + "<BR>"
|
||||
report_text += "</DD>"
|
||||
|
||||
if(log[DETSCAN_CATEGORY_BLOOD])
|
||||
report_text += "<DT><B>[DETSCAN_CATEGORY_BLOOD]</B></DT><DD>"
|
||||
for(var/blood in log[DETSCAN_CATEGORY_BLOOD])
|
||||
report_text += "[blood], [log[DETSCAN_CATEGORY_BLOOD][blood]]<BR>"
|
||||
report_text += "</DD>"
|
||||
|
||||
if(log[DETSCAN_CATEGORY_FINGERS])
|
||||
report_text += "<DT><B>[DETSCAN_CATEGORY_FINGERS]</B></DT><DD>"
|
||||
for(var/fingers in log[DETSCAN_CATEGORY_FINGERS])
|
||||
report_text += fingers + "<BR>"
|
||||
report_text += "</DD>"
|
||||
|
||||
if(log[DETSCAN_CATEGORY_DRINK])
|
||||
report_text += "<DT><B>[DETSCAN_CATEGORY_DRINK]</B></DT><DD>"
|
||||
for(var/reagent in log[DETSCAN_CATEGORY_DRINK])
|
||||
report_text += "<B>[reagent]</B>: [log[DETSCAN_CATEGORY_DRINK][reagent]] u.<BR>"
|
||||
report_text += "</DD>"
|
||||
|
||||
if(log[DETSCAN_CATEGORY_ACCESS])
|
||||
report_text += "<DT><B>[DETSCAN_CATEGORY_ACCESS]</B></DT><DD>"
|
||||
for(var/region in log[DETSCAN_CATEGORY_ACCESS])
|
||||
var/list/access_list = log[DETSCAN_CATEGORY_ACCESS][region]
|
||||
report_text += "<B>[region]</B>: [access_list.Join(", ")]<BR>"
|
||||
report_text += "</DD>"
|
||||
|
||||
report_text += "</DL><HR>"
|
||||
|
||||
report_text += "<H1>Notes:</H1><BR>"
|
||||
report_text += "<h1>Notes:</h1><br>"
|
||||
|
||||
report_paper.add_raw_text(report_text.Join())
|
||||
report_paper.update_appearance()
|
||||
@@ -149,35 +112,38 @@
|
||||
|
||||
// GATHER INFORMATION
|
||||
|
||||
var/list/log_entry_data = list()
|
||||
var/datum/detective_scanner_log/log_entry = new
|
||||
|
||||
// Start gathering
|
||||
|
||||
log_entry_data["scan_target"] = scanned_atom.name
|
||||
log_entry_data["scan_time"] = station_time_timestamp()
|
||||
log_entry.scan_target = scanned_atom.name
|
||||
log_entry.scan_time = station_time_timestamp()
|
||||
|
||||
var/list/atom_fibers = GET_ATOM_FIBRES(scanned_atom)
|
||||
if(length(atom_fibers))
|
||||
log_entry_data[DETSCAN_CATEGORY_FIBER] = atom_fibers.Copy()
|
||||
log_entry.add_data_entry(DETSCAN_CATEGORY_FIBER, atom_fibers.Copy())
|
||||
|
||||
var/list/blood = GET_ATOM_BLOOD_DNA(scanned_atom)
|
||||
if(length(blood))
|
||||
log_entry_data[DETSCAN_CATEGORY_BLOOD] = blood.Copy()
|
||||
log_entry.add_data_entry(DETSCAN_CATEGORY_BLOOD, blood.Copy())
|
||||
|
||||
if(ishuman(scanned_atom))
|
||||
var/mob/living/carbon/human/scanned_human = scanned_atom
|
||||
if(!scanned_human.gloves)
|
||||
LAZYADD(log_entry_data[DETSCAN_CATEGORY_FINGERS], md5(scanned_human.dna?.unique_identity))
|
||||
log_entry.add_data_entry(
|
||||
DETSCAN_CATEGORY_FINGERS,
|
||||
rustg_hash_string(RUSTG_HASH_MD5, scanned_human.dna?.unique_identity)
|
||||
)
|
||||
|
||||
else if(!ismob(scanned_atom))
|
||||
|
||||
var/list/atom_fingerprints = GET_ATOM_FINGERPRINTS(scanned_atom)
|
||||
if(length(atom_fingerprints))
|
||||
log_entry_data[DETSCAN_CATEGORY_FINGERS] = atom_fingerprints.Copy()
|
||||
log_entry.add_data_entry(DETSCAN_CATEGORY_FINGERS, atom_fingerprints.Copy())
|
||||
|
||||
// Only get reagents from non-mobs.
|
||||
for(var/datum/reagent/present_reagent as anything in scanned_atom.reagents?.reagent_list)
|
||||
LAZYADD(log_entry_data[DETSCAN_CATEGORY_DRINK], list(present_reagent.name = present_reagent.volume))
|
||||
log_entry.add_data_entry(DETSCAN_CATEGORY_REAGENTS, list(present_reagent.name = present_reagent.volume))
|
||||
|
||||
// Get blood data from the blood reagent.
|
||||
if(!istype(present_reagent, /datum/reagent/blood))
|
||||
@@ -188,10 +154,7 @@
|
||||
if(!blood_DNA || !blood_type)
|
||||
continue
|
||||
|
||||
// Add to our copied blood list instead of the original
|
||||
if(!log_entry_data[DETSCAN_CATEGORY_BLOOD])
|
||||
log_entry_data[DETSCAN_CATEGORY_BLOOD] = list()
|
||||
LAZYSET(log_entry_data[DETSCAN_CATEGORY_BLOOD], blood_DNA, blood_type)
|
||||
log_entry.add_data_entry(DETSCAN_CATEGORY_BLOOD, list(blood_DNA = blood_type))
|
||||
|
||||
if(istype(scanned_atom, /obj/item/card/id))
|
||||
var/obj/item/card/id/user_id = scanned_atom
|
||||
@@ -202,14 +165,17 @@
|
||||
var/list/access_names = list()
|
||||
for(var/access_num in access_in_region)
|
||||
access_names += SSid_access.get_access_desc(access_num)
|
||||
LAZYADD(log_entry_data[DETSCAN_CATEGORY_ACCESS], region)
|
||||
LAZYADD(log_entry_data[DETSCAN_CATEGORY_ACCESS][region], english_list(access_names))
|
||||
|
||||
log_entry.add_data_entry(DETSCAN_CATEGORY_ACCESS, list("[region]" = english_list(access_names)))
|
||||
|
||||
// sends it off to be modified by the items
|
||||
SEND_SIGNAL(scanned_atom, COMSIG_DETECTIVE_SCANNED, user, log_entry_data)
|
||||
SEND_SIGNAL(scanned_atom, COMSIG_DETECTIVE_SCANNED, user, log_entry)
|
||||
|
||||
// Perform sorting now, because probably this will be never modified
|
||||
log_entry.sort_data_entries()
|
||||
|
||||
stoplag(3 SECONDS)
|
||||
log_data += list(log_entry_data)
|
||||
log_data += log_entry
|
||||
return TRUE
|
||||
|
||||
/obj/item/detective_scanner/click_alt(mob/living/user)
|
||||
@@ -217,7 +183,7 @@
|
||||
|
||||
/obj/item/detective_scanner/examine(mob/user)
|
||||
. = ..()
|
||||
if(LAZYLEN(log_data) && !scanner_busy)
|
||||
if(length(log_data) && !scanner_busy)
|
||||
. += span_notice("Alt-click to clear scanner logs.")
|
||||
|
||||
|
||||
@@ -228,8 +194,28 @@
|
||||
ui.open()
|
||||
|
||||
/obj/item/detective_scanner/ui_data(mob/user)
|
||||
var/list/logs = list()
|
||||
for(var/datum/detective_scanner_log/log as anything in log_data)
|
||||
UNTYPED_LIST_ADD(logs, log.ui_data(user))
|
||||
|
||||
var/list/data = list()
|
||||
data["log_data"] = log_data
|
||||
data["logs"] = logs
|
||||
return data
|
||||
|
||||
/obj/item/detective_scanner/ui_static_data(mob/user)
|
||||
var/list/categories = list()
|
||||
for(var/key,value in GLOB.detective_scan_categories)
|
||||
var/datum/detective_scan_category/category = value
|
||||
|
||||
var/list/category_data = list()
|
||||
category_data["name"] = category.name
|
||||
category_data["uiIcon"] = category.ui_icon
|
||||
category_data["uiIconColor"] = category.ui_icon_color
|
||||
|
||||
categories[category.id] = category_data
|
||||
|
||||
var/list/data = list()
|
||||
data["categories"] = categories
|
||||
return data
|
||||
|
||||
/obj/item/detective_scanner/ui_act(action, params, datum/tgui/ui)
|
||||
@@ -251,7 +237,7 @@
|
||||
balloon_alert(ui.user, "log deleted")
|
||||
ui.send_update()
|
||||
if("print")
|
||||
if(!LAZYLEN(log_data))
|
||||
if(!length(log_data))
|
||||
balloon_alert(ui.user, "no logs!")
|
||||
return
|
||||
if(scanner_busy)
|
||||
@@ -263,7 +249,7 @@
|
||||
addtimer(CALLBACK(src, PROC_REF(safe_print_report)), 3 SECONDS)
|
||||
|
||||
/obj/item/detective_scanner/proc/clear_logs(mob/living/user)
|
||||
if(!LAZYLEN(log_data))
|
||||
if(!length(log_data))
|
||||
balloon_alert(user, "no logs!")
|
||||
return CLICK_ACTION_BLOCKING
|
||||
if(scanner_busy)
|
||||
|
||||
@@ -445,9 +445,10 @@
|
||||
/datum/embedding/edagger_active
|
||||
embed_chance = 100
|
||||
|
||||
/obj/item/pen/edagger/proc/on_scan(datum/source, mob/user, list/extra_data)
|
||||
/obj/item/pen/edagger/proc/on_scan(datum/source, mob/user, datum/detective_scanner_log/entry)
|
||||
SIGNAL_HANDLER
|
||||
LAZYADD(extra_data[DETSCAN_CATEGORY_ILLEGAL], "Hard-light generator detected.")
|
||||
|
||||
entry.add_data_entry(DETSCAN_CATEGORY_ILLEGAL, "Hard-light generator detected.")
|
||||
|
||||
/obj/item/pen/survival
|
||||
name = "survival pen"
|
||||
|
||||
Reference in New Issue
Block a user