From 5e802574231c9c6fe835c40b55f2c8aa9f1c68b4 Mon Sep 17 00:00:00 2001 From: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Date: Tue, 24 Jan 2023 10:34:27 -0800 Subject: [PATCH] Refactors crew records (#72725) ## About The Pull Request I have attempted or otherwise started this project at least 4 times. I am sick of it being on my calendar. The code needs it. I need it. - This makes crew records a proper datum rather than assigning properties record.fields. - General, medical, and security records are merged. - Did some slight refactoring here and there for things that looked obvious. - Wanted states are now defined (and you can suspect someone through sechud) - pAI (unrelated but annoying) had some poorly named exported types that i made more specific - Job icons are moved back to the JS side (I wanted to get icons for initial rank without passing trim)
previews Editable fields & security console ![CM6d74brnC](https://user-images.githubusercontent.com/42397676/213950290-af6cfd76-eb8b-48e9-b792-925949311d9a.gif) Medical records ![bFJErsvOaN](https://user-images.githubusercontent.com/42397676/214132534-59af1f8c-9920-4b51-8b27-297103649962.gif) Look and feel of the more current version ![cxGruQsJpP](https://user-images.githubusercontent.com/42397676/214132611-0134eef0-e74c-4fad-9cde-328ff7c06165.gif)
## Why It's Good For The Game TGUI'd some of the worst UIs in the game. Creating new records is made much simpler. Manifest_inject is made readable. Probably bug fixes ## Changelog :cl: refactor: Crew records have been refactored. refactor: Medical records -> TGUI refactor: Security records -> TGUI refactor: Warrants console -> TGUI qol: Players are now alerted when their fines are paid off. qol: Cleaned up sec hud examination text. qol: Adding and deleting crimes is easier. qol: Writing crimes in the console sets players to arrest. qol: You can now mark someone as a suspect through sec hud. /:cl: Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> --- code/__DEFINES/security.dm | 18 + code/__HELPERS/_lists.dm | 31 +- code/__HELPERS/cmp.dm | 9 +- code/__HELPERS/names.dm | 4 +- code/__HELPERS/records.dm | 6 +- code/_globalvars/lists/mobs.dm | 5 +- code/controllers/subsystem/ticker.dm | 2 +- code/datums/datacore.dm | 394 ------ code/datums/dna.dm | 11 +- code/datums/id_trim/_id_trim.dm | 2 - code/datums/id_trim/jobs.dm | 33 - code/datums/records/crime.dm | 60 + code/datums/records/data.dm | 4 + code/datums/records/manifest.dm | 157 +++ code/datums/records/medical_note.dm | 15 + code/datums/records/record.dm | 256 ++++ code/game/data_huds.dm | 48 +- code/game/machinery/computer/_computer.dm | 153 +++ code/game/machinery/computer/arcade/orion.dm | 6 - code/game/machinery/computer/medical.dm | 682 ++-------- .../computer/prisoner/gulag_teleporter.dm | 13 +- code/game/machinery/computer/security.dm | 1202 +++++------------ code/game/machinery/computer/warrant.dm | 287 ++-- code/game/machinery/gulag_teleporter.dm | 6 +- .../machinery/porta_turret/portable_turret.dm | 4 +- code/game/machinery/scan_gate.dm | 4 +- code/game/say.dm | 6 +- code/modules/admin/admin_verbs.dm | 2 +- code/modules/admin/verbs/admingame.dm | 19 +- code/modules/admin/verbs/list_exposer.dm | 4 +- .../antagonists/ninja/ninjaDrainAct.dm | 5 +- code/modules/detectivework/scanner.dm | 2 +- code/modules/jobs/job_types/prisoner.dm | 6 +- code/modules/mob/dead/crew_manifest.dm | 2 +- .../mob/dead/new_player/latejoin_menu.dm | 4 - .../modules/mob/dead/new_player/new_player.dm | 2 +- code/modules/mob/dead/observer/orbit.dm | 2 - .../mob/living/carbon/human/examine.dm | 22 +- code/modules/mob/living/carbon/human/human.dm | 184 +-- code/modules/mob/living/silicon/ai/ai.dm | 4 +- code/modules/mob/mob.dm | 4 +- .../file_system/programs/card.dm | 2 +- .../file_system/programs/crewmanifest.dm | 4 +- .../file_system/programs/records.dm | 33 +- .../file_system/programs/robocontrol.dm | 2 +- code/modules/paperwork/filingcabinet.dm | 57 +- tgstation.dme | 6 +- .../packages/tgui/interfaces/JobSelection.tsx | 3 +- .../interfaces/MedicalRecords/NoteKeeper.tsx | 119 ++ .../interfaces/MedicalRecords/RecordTabs.tsx | 103 ++ .../interfaces/MedicalRecords/RecordView.tsx | 131 ++ .../tgui/interfaces/MedicalRecords/helpers.ts | 25 + .../tgui/interfaces/MedicalRecords/index.tsx | 81 ++ .../tgui/interfaces/MedicalRecords/types.ts | 29 + tgui/packages/tgui/interfaces/Orbit/index.tsx | 4 +- tgui/packages/tgui/interfaces/Orbit/types.ts | 1 - .../interfaces/PaiInterface/Available.tsx | 8 +- .../interfaces/PaiInterface/Directives.tsx | 4 +- .../interfaces/PaiInterface/Installed.tsx | 18 +- .../tgui/interfaces/PaiInterface/System.tsx | 6 +- .../tgui/interfaces/PaiInterface/constants.ts | 2 +- .../tgui/interfaces/PaiInterface/index.tsx | 33 +- .../tgui/interfaces/PaiInterface/types.ts | 2 +- .../interfaces/PreferencesMenu/MainPage.tsx | 2 +- .../PreferencesMenu/SpeciesPage.tsx | 2 +- .../SecurityRecords/CrimeWatcher.tsx | 208 +++ .../SecurityRecords/RecordPrint.tsx | 178 +++ .../interfaces/SecurityRecords/RecordTabs.tsx | 106 ++ .../interfaces/SecurityRecords/RecordView.tsx | 173 +++ .../interfaces/SecurityRecords/constants.ts | 15 + .../interfaces/SecurityRecords/helpers.ts | 72 + .../tgui/interfaces/SecurityRecords/index.tsx | 81 ++ .../tgui/interfaces/SecurityRecords/types.ts | 44 + .../tgui/interfaces/WarrantConsole.tsx | 214 +++ .../CharacterPreview.tsx | 0 .../tgui/interfaces/common/EditableText.tsx | 76 ++ .../tgui/interfaces/common/JobToIcon.ts | 47 +- 77 files changed, 3204 insertions(+), 2367 deletions(-) delete mode 100644 code/datums/datacore.dm create mode 100644 code/datums/records/crime.dm create mode 100644 code/datums/records/data.dm create mode 100644 code/datums/records/manifest.dm create mode 100644 code/datums/records/medical_note.dm create mode 100644 code/datums/records/record.dm create mode 100644 tgui/packages/tgui/interfaces/MedicalRecords/NoteKeeper.tsx create mode 100644 tgui/packages/tgui/interfaces/MedicalRecords/RecordTabs.tsx create mode 100644 tgui/packages/tgui/interfaces/MedicalRecords/RecordView.tsx create mode 100644 tgui/packages/tgui/interfaces/MedicalRecords/helpers.ts create mode 100644 tgui/packages/tgui/interfaces/MedicalRecords/index.tsx create mode 100644 tgui/packages/tgui/interfaces/MedicalRecords/types.ts create mode 100644 tgui/packages/tgui/interfaces/SecurityRecords/CrimeWatcher.tsx create mode 100644 tgui/packages/tgui/interfaces/SecurityRecords/RecordPrint.tsx create mode 100644 tgui/packages/tgui/interfaces/SecurityRecords/RecordTabs.tsx create mode 100644 tgui/packages/tgui/interfaces/SecurityRecords/RecordView.tsx create mode 100644 tgui/packages/tgui/interfaces/SecurityRecords/constants.ts create mode 100644 tgui/packages/tgui/interfaces/SecurityRecords/helpers.ts create mode 100644 tgui/packages/tgui/interfaces/SecurityRecords/index.tsx create mode 100644 tgui/packages/tgui/interfaces/SecurityRecords/types.ts create mode 100644 tgui/packages/tgui/interfaces/WarrantConsole.tsx rename tgui/packages/tgui/interfaces/{PreferencesMenu => common}/CharacterPreview.tsx (100%) create mode 100644 tgui/packages/tgui/interfaces/common/EditableText.tsx diff --git a/code/__DEFINES/security.dm b/code/__DEFINES/security.dm index 3e741d82aaf..a385d843398 100644 --- a/code/__DEFINES/security.dm +++ b/code/__DEFINES/security.dm @@ -54,3 +54,21 @@ /// if any categories list has this entry, it will be hidden #define DETSCAN_BLOCK "DETSCAN_BLOCK" + +/// Wanted statuses +#define WANTED_ARREST "Arrest" +#define WANTED_DISCHARGED "Discharged" +#define WANTED_NONE "None" +#define WANTED_PAROLE "Parole" +#define WANTED_PRISONER "Incarcerated" +#define WANTED_SUSPECT "Suspected" + +/// List of available wanted statuses +#define WANTED_STATUSES(...) list(\ + WANTED_NONE, \ + WANTED_SUSPECT, \ + WANTED_ARREST, \ + WANTED_PRISONER, \ + WANTED_PAROLE, \ + WANTED_DISCHARGED, \ +) diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index 074ade9e5af..4a4bc828cf8 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -594,12 +594,11 @@ inserted_list[key] = temp[key] ///for sorting clients or mobs by ckey -/proc/sort_key(list/ckey_list, order=1) +/proc/sort_key(list/ckey_list, order = 1) return sortTim(ckey_list, order >= 0 ? GLOBAL_PROC_REF(cmp_ckey_asc) : GLOBAL_PROC_REF(cmp_ckey_dsc)) ///Specifically for record datums in a list. -/proc/sort_record(list/record_list, field = "name", order = 1) - GLOB.cmp_field = field +/proc/sort_record(list/record_list, order = 1) return sortTim(record_list, order >= 0 ? GLOBAL_PROC_REF(cmp_records_asc) : GLOBAL_PROC_REF(cmp_records_dsc)) ///sort any value in a list @@ -639,11 +638,27 @@ i++ return i -/// Returns datum/data/record -/proc/find_record(field, value, list/inserted_list) - for(var/datum/data/record/record_to_check in inserted_list) - if(record_to_check.fields[field] == value) - return record_to_check +/** + * Returns the first record in the list that matches the name + * + * If locked_only is TRUE, locked records will be checked + * + * If locked_only is FALSE, crew records will be checked + * + * If no record is found, returns null + */ +/proc/find_record(value, locked_only = FALSE) + if(locked_only) + for(var/datum/record/locked/target in GLOB.manifest.locked) + if(target.name != value) + continue + return target + return null + + for(var/datum/record/crew/target in GLOB.manifest.general) + if(target.name != value) + continue + return target return null diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm index 467f60e8195..e7af8e0dcd7 100644 --- a/code/__HELPERS/cmp.dm +++ b/code/__HELPERS/cmp.dm @@ -16,12 +16,11 @@ /proc/cmp_name_dsc(atom/a, atom/b) return sorttext(a.name, b.name) -GLOBAL_VAR_INIT(cmp_field, "name") -/proc/cmp_records_asc(datum/data/record/a, datum/data/record/b) - return sorttext(b.fields[GLOB.cmp_field], a.fields[GLOB.cmp_field]) +/proc/cmp_records_asc(datum/record/a, datum/record/b) + return sorttext(b.name, a.name) -/proc/cmp_records_dsc(datum/data/record/a, datum/data/record/b) - return sorttext(a.fields[GLOB.cmp_field], b.fields[GLOB.cmp_field]) +/proc/cmp_records_dsc(datum/record/a, datum/record/b) + return sorttext(a.name, b.name) // Datum cmp with vars is always slower than a specialist cmp proc, use your judgement. /proc/cmp_datum_numeric_asc(datum/a, datum/b, variable) diff --git a/code/__HELPERS/names.dm b/code/__HELPERS/names.dm index d5356227613..5ed955ffdb2 100644 --- a/code/__HELPERS/names.dm +++ b/code/__HELPERS/names.dm @@ -176,8 +176,8 @@ GLOBAL_DATUM(syndicate_code_response_regex, /regex) var/locations = strings(LOCATIONS_FILE, "locations") var/list/names = list() - for(var/datum/data/record/t in GLOB.data_core.general)//Picks from crew manifest. - names += t.fields["name"] + for(var/datum/record/crew/target in GLOB.manifest.general)//Picks from crew manifest. + names += target.name var/maxwords = words//Extra var to check for duplicates. diff --git a/code/__HELPERS/records.dm b/code/__HELPERS/records.dm index b3dba849d3c..288ef5284d2 100644 --- a/code/__HELPERS/records.dm +++ b/code/__HELPERS/records.dm @@ -1,6 +1,6 @@ -/proc/overwrite_field_if_available(datum/data/record/base, datum/data/record/other, field_name) - if(other.fields[field_name]) - base.fields[field_name] = other.fields[field_name] +/proc/overwrite_field_if_available(datum/record/base, datum/record/other, field_name) + if(other[field_name]) + base[field_name] = other[field_name] diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index 1cb4fd688f1..1c6b4b90bc6 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -110,9 +110,8 @@ GLOBAL_LIST_INIT(construct_radial_images, list( /proc/get_crewmember_minds() var/list/minds = list() - for(var/data in GLOB.data_core.locked) - var/datum/data/record/record = data - var/datum/mind/mind = record.fields["mindref"] + for(var/datum/record/locked/target in GLOB.manifest.locked) + var/datum/mind/mind = target.mind_ref if(mind) minds += mind return minds diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 8065d2e6aff..52a29c96686 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -255,7 +255,7 @@ SUBSYSTEM_DEF(ticker) collect_minds() equip_characters() - GLOB.data_core.manifest() + GLOB.manifest.build() transfer_characters() //transfer keys to the new mobs diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm deleted file mode 100644 index 028ccb4988f..00000000000 --- a/code/datums/datacore.dm +++ /dev/null @@ -1,394 +0,0 @@ -GLOBAL_DATUM_INIT(data_core, /datum/datacore, new) - -//TODO: someone please get rid of this shit -/datum/datacore - var/list/medical = list() - var/medicalPrintCount = 0 - var/list/general = list() - var/list/security = list() - var/securityPrintCount = 0 - var/securityCrimeCounter = 0 - ///This list tracks characters spawned in the world and cannot be modified in-game. Currently referenced by respawn_character(). - var/list/locked = list() - -/datum/data - var/name = "data" - -/datum/data/record - name = "record" - var/list/fields = list() - -/datum/data/record/Destroy() - GLOB.data_core.medical -= src - GLOB.data_core.security -= src - GLOB.data_core.general -= src - GLOB.data_core.locked -= src - . = ..() - -/// A helper proc to get the front photo of a character from the record. -/// Handles calling `get_photo()`, read its documentation for more information. -/datum/data/record/proc/get_front_photo() - return get_photo("photo_front", SOUTH) - -/// A helper proc to get the side photo of a character from the record. -/// Handles calling `get_photo()`, read its documentation for more information. -/datum/data/record/proc/get_side_photo() - return get_photo("photo_side", WEST) - -/** - * You shouldn't be calling this directly, use `get_front_photo()` or `get_side_photo()` - * instead. - * - * This is the proc that handles either fetching (if it was already generated before) or - * generating (if it wasn't) the specified photo from the specified record. This is only - * intended to be used by records that used to try to access `fields["photo_front"]` or - * `fields["photo_side"]`, and will return an empty icon if there isn't any of the necessary - * fields. - * - * Arguments: - * * field_name - The name of the key in the `fields` list, of the record itself. - * * orientation - The direction in which you want the character appearance to be rotated - * in the outputed photo. - * - * Returns an empty `/icon` if there was no `character_appearance` entry in the `fields` list, - * returns the generated/cached photo otherwise. - */ -/datum/data/record/proc/get_photo(field_name, orientation) - if(fields[field_name]) - return fields[field_name] - - if(!fields["character_appearance"]) - return new /icon() - - var/mutable_appearance/character_appearance = fields["character_appearance"] - character_appearance.setDir(orientation) - - var/icon/picture_image = getFlatIcon(character_appearance) - - var/datum/picture/picture = new - picture.picture_name = "[fields["name"]]" - picture.picture_desc = "This is [fields["name"]]." - picture.picture_image = picture_image - - var/obj/item/photo/photo = new(null, picture) - fields[field_name] = photo - return photo - -/datum/data/crime - name = "crime" - var/crimeName = "" - var/crimeDetails = "" - var/author = "" - var/time = "" - var/fine = 0 - var/paid = 0 - var/dataId = 0 - -/datum/datacore/proc/createCrimeEntry(cname = "", cdetails = "", author = "", time = "", fine = 0) - var/datum/data/crime/c = new /datum/data/crime - c.crimeName = cname - c.crimeDetails = cdetails - c.author = author - c.time = time - c.fine = fine - c.paid = 0 - c.dataId = ++securityCrimeCounter - return c - -/datum/datacore/proc/addCitation(id = "", datum/data/crime/crime) - for(var/datum/data/record/R in security) - if(R.fields["id"] == id) - var/list/crimes = R.fields["citation"] - crimes |= crime - return - -/datum/datacore/proc/removeCitation(id, cDataId) - for(var/datum/data/record/R in security) - if(R.fields["id"] == id) - var/list/crimes = R.fields["citation"] - for(var/datum/data/crime/crime in crimes) - if(crime.dataId == text2num(cDataId)) - crimes -= crime - return - -/datum/datacore/proc/payCitation(id, cDataId, amount) - for(var/datum/data/record/R in security) - if(R.fields["id"] == id) - var/list/crimes = R.fields["citation"] - for(var/datum/data/crime/crime in crimes) - if(crime.dataId == text2num(cDataId)) - crime.paid = crime.paid + amount - var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_SEC) - D.adjust_money(amount) - return - -/** - * Adds crime to security record. - * - * Is used to add single crime to someone's security record. - * Arguments: - * * id - record id. - * * datum/data/crime/crime - premade array containing every variable, usually created by createCrimeEntry. - */ -/datum/datacore/proc/addCrime(id = "", datum/data/crime/crime) - for(var/datum/data/record/R in security) - if(R.fields["id"] == id) - var/list/crimes = R.fields["crim"] - crimes |= crime - return - -/** - * Deletes crime from security record. - * - * Is used to delete single crime to someone's security record. - * Arguments: - * * id - record id. - * * cDataId - id of already existing crime. - */ -/datum/datacore/proc/removeCrime(id, cDataId) - for(var/datum/data/record/R in security) - if(R.fields["id"] == id) - var/list/crimes = R.fields["crim"] - for(var/datum/data/crime/crime in crimes) - if(crime.dataId == text2num(cDataId)) - crimes -= crime - return - -/** - * Adds details to a crime. - * - * Is used to add or replace details to already existing crime. - * Arguments: - * * id - record id. - * * cDataId - id of already existing crime. - * * details - data you want to add. - */ -/datum/datacore/proc/addCrimeDetails(id, cDataId, details) - for(var/datum/data/record/R in security) - if(R.fields["id"] == id) - var/list/crimes = R.fields["crim"] - for(var/datum/data/crime/crime in crimes) - if(crime.dataId == text2num(cDataId)) - crime.crimeDetails = details - return - -/datum/datacore/proc/manifest() - for(var/i in GLOB.new_player_list) - var/mob/dead/new_player/N = i - if(N.new_character) - log_manifest(N.ckey,N.new_character.mind,N.new_character) - if(ishuman(N.new_character)) - manifest_inject(N.new_character) - CHECK_TICK - -/datum/datacore/proc/manifest_modify(name, assignment, trim) - var/datum/data/record/foundrecord = find_record("name", name, GLOB.data_core.general) - if(foundrecord) - foundrecord.fields["rank"] = assignment - foundrecord.fields["trim"] = trim - - -/datum/datacore/proc/get_manifest() - // First we build up the order in which we want the departments to appear in. - var/list/manifest_out = list() - for(var/datum/job_department/department as anything in SSjob.joinable_departments) - manifest_out[department.department_name] = list() - manifest_out[DEPARTMENT_UNASSIGNED] = list() - - var/list/departments_by_type = SSjob.joinable_departments_by_type - for(var/datum/data/record/record as anything in GLOB.data_core.general) - var/name = record.fields["name"] - var/rank = record.fields["rank"] // user-visible job - var/trim = record.fields["trim"] // internal jobs by trim type - var/datum/job/job = SSjob.GetJob(trim) - if(!job || !(job.job_flags & JOB_CREW_MANIFEST) || !LAZYLEN(job.departments_list)) // In case an unlawful custom rank is added. - var/list/misc_list = manifest_out[DEPARTMENT_UNASSIGNED] - misc_list[++misc_list.len] = list( - "name" = name, - "rank" = rank, - ) - continue - for(var/department_type as anything in job.departments_list) - var/datum/job_department/department = departments_by_type[department_type] - if(!department) - stack_trace("get_manifest() failed to get job department for [department_type] of [job.type]") - continue - var/list/entry = list( - "name" = name, - "rank" = rank, - ) - var/list/department_list = manifest_out[department.department_name] - if(istype(job, department.department_head)) - department_list.Insert(1, null) - department_list[1] = entry - else - department_list[++department_list.len] = entry - - // Trim the empty categories. - for (var/department in manifest_out) - if(!length(manifest_out[department])) - manifest_out -= department - - return manifest_out - -/datum/datacore/proc/get_manifest_html(monochrome = FALSE) - var/list/manifest = get_manifest() - var/dat = {" - - - - "} - for(var/department in manifest) - var/list/entries = manifest[department] - dat += "" - //JUST - var/even = FALSE - for(var/entry in entries) - var/list/entry_list = entry - dat += "" - even = !even - - dat += "
NameRank
[department]
[entry_list["name"]][entry_list["rank"]]
" - dat = replacetext(dat, "\n", "") - dat = replacetext(dat, "\t", "") - return dat - - -/datum/datacore/proc/manifest_inject(mob/living/carbon/human/H) - set waitfor = FALSE - var/static/list/show_directions = list(SOUTH, WEST) - if(H.mind?.assigned_role.job_flags & JOB_CREW_MANIFEST) - var/assignment = H.mind.assigned_role.title - - var/static/record_id_num = 1001 - var/id = num2hex(record_id_num++,6) - var/mutable_appearance/character_appearance = new(H.appearance) - - //These records should ~really~ be merged or something - //General Record - var/datum/data/record/G = new() - G.fields["id"] = id - G.fields["name"] = H.real_name - G.fields["rank"] = assignment - G.fields["trim"] = assignment - G.fields["initial_rank"] = assignment - G.fields["age"] = H.age - G.fields["species"] = H.dna.species.name - G.fields["fingerprint"] = md5(H.dna.unique_identity) - G.fields["p_stat"] = "Active" - G.fields["m_stat"] = "Stable" - G.fields["gender"] = H.gender - if(H.gender == "male") - G.fields["gender"] = "Male" - else if(H.gender == "female") - G.fields["gender"] = "Female" - else - G.fields["gender"] = "Other" - G.fields["character_appearance"] = character_appearance - general += G - - //Medical Record - var/datum/data/record/M = new() - M.fields["id"] = id - M.fields["name"] = H.real_name - M.fields["blood_type"] = H.dna.blood_type - M.fields["b_dna"] = H.dna.unique_enzymes - M.fields["mi_dis"] = H.get_quirk_string(!medical, CAT_QUIRK_MINOR_DISABILITY) - M.fields["mi_dis_d"] = H.get_quirk_string(medical, CAT_QUIRK_MINOR_DISABILITY) - M.fields["ma_dis"] = H.get_quirk_string(!medical, CAT_QUIRK_MAJOR_DISABILITY) - M.fields["ma_dis_d"] = H.get_quirk_string(medical, CAT_QUIRK_MAJOR_DISABILITY) - M.fields["cdi"] = "None" - M.fields["cdi_d"] = "No diseases have been diagnosed at the moment." - M.fields["notes"] = H.get_quirk_string(!medical, CAT_QUIRK_NOTES) - M.fields["notes_d"] = H.get_quirk_string(medical, CAT_QUIRK_NOTES) - medical += M - - //Security Record - var/datum/data/record/S = new() - S.fields["id"] = id - S.fields["name"] = H.real_name - S.fields["criminal"] = "None" - S.fields["citation"] = list() - S.fields["crim"] = list() - S.fields["notes"] = "No notes." - security += S - - //Locked Record - var/datum/data/record/L = new() - L.fields["id"] = md5("[H.real_name][assignment]") //surely this should just be id, like the others? - L.fields["name"] = H.real_name - L.fields["rank"] = assignment - L.fields["trim"] = assignment - G.fields["initial_rank"] = assignment - L.fields["age"] = H.age - L.fields["gender"] = H.gender - if(H.gender == "male") - G.fields["gender"] = "Male" - else if(H.gender == "female") - G.fields["gender"] = "Female" - else - G.fields["gender"] = "Other" - L.fields["blood_type"] = H.dna.blood_type - L.fields["b_dna"] = H.dna.unique_enzymes - L.fields["identity"] = H.dna.unique_identity - L.fields["species"] = H.dna.species.type - L.fields["features"] = H.dna.features - L.fields["character_appearance"] = character_appearance - L.fields["mindref"] = H.mind - locked += L - return - -//Todo: Add citations to the prinout - you get them from sec record's "citation" field, same as "crim" (which is frankly a terrible fucking field name) -///Standardized printed records. SPRs. Like SATs but for bad guys who probably didn't actually finish school. Input the records and out comes a paper. -/proc/print_security_record(datum/data/record/general_data, datum/data/record/security, atom/location) - if(!istype(general_data) && !istype(security)) - stack_trace("called without any datacores! this may or may not be intentional!") - if(!isatom(location)) //can't drop the paper if we didn't get passed an atom. - CRASH("NO VALID LOCATION PASSED.") - - GLOB.data_core.securityPrintCount++ //just alters the name of the paper. - var/obj/item/paper/printed_paper = new(location) - var/final_paper_text = "
Security Record - (SR-[GLOB.data_core.securityPrintCount])

" - if((istype(general_data, /datum/data/record) && GLOB.data_core.general.Find(general_data))) - final_paper_text += text("Name: [] ID: []
\nGender: []
\nAge: []
", general_data.fields["name"], general_data.fields["id"], general_data.fields["gender"], general_data.fields["age"]) - final_paper_text += "\nSpecies: [general_data.fields["species"]]
" - final_paper_text += text("\nFingerprint: []
\nPhysical Status: []
\nMental Status: []
", general_data.fields["fingerprint"], general_data.fields["p_stat"], general_data.fields["m_stat"]) - else - final_paper_text += "General Record Lost!
" - if((istype(security, /datum/data/record) && GLOB.data_core.security.Find(security))) - final_paper_text += text("
\n
Security Data

\nCriminal Status: []", security.fields["criminal"]) - - final_paper_text += "
\n
\nCrimes:
\n" - final_paper_text +={" - - - - - -"} - for(var/datum/data/crime/c in security.fields["crim"]) - final_paper_text += "" - final_paper_text += "" - final_paper_text += "" - final_paper_text += "" - final_paper_text += "" - final_paper_text += "
CrimeDetailsAuthorTime Added
[c.crimeName][c.crimeDetails][c.author][c.time]
" - - final_paper_text += text("
\nImportant Notes:
\n\t[]
\n
\n
Comments/Log

", security.fields["notes"]) - var/counter = 1 - while(security.fields[text("com_[]", counter)]) - final_paper_text += text("[]
", security.fields[text("com_[]", counter)]) - counter++ - printed_paper.name = text("SR-[] '[]'", GLOB.data_core.securityPrintCount, general_data.fields["name"]) - else //if no security record - final_paper_text += "Security Record Lost!
" - printed_paper.name = text("SR-[] '[]'", GLOB.data_core.securityPrintCount, "Record Lost") - final_paper_text += "" - printed_paper.add_raw_text(final_paper_text) - printed_paper.update_appearance() //make sure we make the paper look like it has writing on it. diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 058670c9d1e..d70c030607c 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -504,7 +504,8 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) return dna -/mob/living/carbon/human/proc/hardset_dna(ui, list/mutation_index, list/default_mutation_genes, newreal_name, newblood_type, datum/species/mrace, newfeatures, list/mutations, force_transfer_mutations) +/// Sets the DNA of the mob to the given DNA. +/mob/living/carbon/human/proc/hardset_dna(unique_identity, list/mutation_index, list/default_mutation_genes, newreal_name, newblood_type, datum/species/mrace, newfeatures, list/mutations, force_transfer_mutations) //Do not use force_transfer_mutations for stuff like cloners without some precautions, otherwise some conditional mutations could break (timers, drill hat etc) if(newfeatures) dna.features = newfeatures @@ -522,9 +523,9 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if(newblood_type) dna.blood_type = newblood_type - if(ui) - dna.unique_identity = ui - updateappearance(icon_update=0) + if(unique_identity) + dna.unique_identity = unique_identity + updateappearance(icon_update = 0) if(LAZYLEN(mutation_index)) dna.mutation_index = mutation_index.Copy() @@ -534,7 +535,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) dna.default_mutation_genes = mutation_index.Copy() domutcheck() - if(mrace || newfeatures || ui) + if(mrace || newfeatures || unique_identity) update_body(is_creating = TRUE) update_mutations_overlay() diff --git a/code/datums/id_trim/_id_trim.dm b/code/datums/id_trim/_id_trim.dm index 06c2bec74ec..7000e2d6b1d 100644 --- a/code/datums/id_trim/_id_trim.dm +++ b/code/datums/id_trim/_id_trim.dm @@ -16,8 +16,6 @@ var/intern_alt_name = null /// The icon_state associated with this trim, as it will show on the security HUD. var/sechud_icon_state = SECHUD_UNKNOWN - /// Icons to be displayed in the orbit ui. Source: FontAwesome v6 Free Edition. - var/orbit_icon /// Accesses that this trim unlocks on a card it is imprinted on. These accesses never take wildcard slots and can be added and removed at will. var/list/access = list() diff --git a/code/datums/id_trim/jobs.dm b/code/datums/id_trim/jobs.dm index 86290c69ec6..18a32214b5c 100644 --- a/code/datums/id_trim/jobs.dm +++ b/code/datums/id_trim/jobs.dm @@ -79,7 +79,6 @@ /datum/id_trim/job/assistant assignment = "Assistant" trim_state = "trim_assistant" - orbit_icon = "toolbox" sechud_icon_state = SECHUD_ASSISTANT minimal_access = list() extra_access = list( @@ -106,7 +105,6 @@ /datum/id_trim/job/atmospheric_technician assignment = "Atmospheric Technician" trim_state = "trim_atmospherictechnician" - orbit_icon = "fan" department_color = COLOR_ENGINEERING_ORANGE subdepartment_color = COLOR_ENGINEERING_ORANGE sechud_icon_state = SECHUD_ATMOSPHERIC_TECHNICIAN @@ -136,7 +134,6 @@ /datum/id_trim/job/bartender assignment = "Bartender" trim_state = "trim_bartender" - orbit_icon = "cocktail" department_color = COLOR_SERVICE_LIME subdepartment_color = COLOR_SERVICE_LIME sechud_icon_state = SECHUD_BARTENDER @@ -161,7 +158,6 @@ /datum/id_trim/job/botanist assignment = "Botanist" trim_state = "trim_botanist" - orbit_icon = "seedling" department_color = COLOR_SERVICE_LIME subdepartment_color = COLOR_SERVICE_LIME sechud_icon_state = SECHUD_BOTANIST @@ -186,7 +182,6 @@ assignment = "Captain" intern_alt_name = "Captain-in-Training" trim_state = "trim_captain" - orbit_icon = "crown" department_color = COLOR_COMMAND_BLUE subdepartment_color = COLOR_COMMAND_BLUE department_state = "departmenthead" @@ -209,7 +204,6 @@ /datum/id_trim/job/cargo_technician assignment = "Cargo Technician" trim_state = "trim_cargotechnician" - orbit_icon = "box" department_color = COLOR_CARGO_BROWN subdepartment_color = COLOR_CARGO_BROWN sechud_icon_state = SECHUD_CARGO_TECHNICIAN @@ -234,7 +228,6 @@ /datum/id_trim/job/chaplain assignment = "Chaplain" trim_state = "trim_chaplain" - orbit_icon = "cross" department_color = COLOR_SERVICE_LIME subdepartment_color = COLOR_SERVICE_LIME sechud_icon_state = SECHUD_CHAPLAIN @@ -256,7 +249,6 @@ /datum/id_trim/job/chemist assignment = "Chemist" trim_state = "trim_chemist" - orbit_icon = "prescription-bottle" department_color = COLOR_MEDICAL_BLUE subdepartment_color = COLOR_MEDICAL_BLUE sechud_icon_state = SECHUD_CHEMIST @@ -283,7 +275,6 @@ assignment = "Chief Engineer" intern_alt_name = "Chief Engineer-in-Training" trim_state = "trim_stationengineer" - orbit_icon = "user-astronaut" department_color = COLOR_COMMAND_BLUE subdepartment_color = COLOR_ENGINEERING_ORANGE department_state = "departmenthead" @@ -325,7 +316,6 @@ assignment = "Chief Medical Officer" intern_alt_name = "Chief Medical Officer-in-Training" trim_state = "trim_medicaldoctor" - orbit_icon = "user-md" department_color = COLOR_COMMAND_BLUE subdepartment_color = COLOR_MEDICAL_BLUE department_state = "departmenthead" @@ -363,7 +353,6 @@ /datum/id_trim/job/clown assignment = "Clown" trim_state = "trim_clown" - orbit_icon = "face-grin-tears" department_color = COLOR_MAGENTA subdepartment_color = COLOR_MAGENTA sechud_icon_state = SECHUD_CLOWN @@ -382,7 +371,6 @@ /datum/id_trim/job/cook assignment = "Cook" trim_state = "trim_cook" - orbit_icon = "utensils" department_color = COLOR_SERVICE_LIME subdepartment_color = COLOR_SERVICE_LIME sechud_icon_state = SECHUD_COOK @@ -410,7 +398,6 @@ /datum/id_trim/job/curator assignment = "Curator" trim_state = "trim_curator" - orbit_icon = "book" department_color = COLOR_SERVICE_LIME subdepartment_color = COLOR_SERVICE_LIME sechud_icon_state = SECHUD_CURATOR @@ -431,7 +418,6 @@ /datum/id_trim/job/detective assignment = "Detective" trim_state = "trim_detective" - orbit_icon = "user-secret" department_color = COLOR_SECURITY_RED subdepartment_color = COLOR_SECURITY_RED sechud_icon_state = SECHUD_DETECTIVE @@ -469,7 +455,6 @@ /datum/id_trim/job/geneticist assignment = "Geneticist" trim_state = "trim_geneticist" - orbit_icon = "dna" department_color = COLOR_SCIENCE_PINK subdepartment_color = COLOR_SCIENCE_PINK sechud_icon_state = SECHUD_GENETICIST @@ -497,7 +482,6 @@ assignment = "Head of Personnel" intern_alt_name = "Head of Personnel-in-Training" trim_state = "trim_headofpersonnel" - orbit_icon = "dog" department_color = COLOR_COMMAND_BLUE subdepartment_color = COLOR_SERVICE_LIME department_state = "departmenthead" @@ -549,7 +533,6 @@ assignment = "Head of Security" intern_alt_name = "Head of Security-in-Training" trim_state = "trim_securityofficer" - orbit_icon = "user-shield" department_color = COLOR_COMMAND_BLUE subdepartment_color = COLOR_SECURITY_RED department_state = "departmenthead" @@ -606,7 +589,6 @@ /datum/id_trim/job/janitor assignment = "Janitor" trim_state = "trim_janitor" - orbit_icon = "broom" department_color = COLOR_SERVICE_LIME subdepartment_color = COLOR_SERVICE_LIME sechud_icon_state = SECHUD_JANITOR @@ -627,7 +609,6 @@ /datum/id_trim/job/lawyer assignment = "Lawyer" trim_state = "trim_lawyer" - orbit_icon = "gavel" department_color = COLOR_SERVICE_LIME subdepartment_color = COLOR_SECURITY_RED sechud_icon_state = SECHUD_LAWYER @@ -648,7 +629,6 @@ /datum/id_trim/job/medical_doctor assignment = "Medical Doctor" trim_state = "trim_medicaldoctor" - orbit_icon = "staff-snake" department_color = COLOR_MEDICAL_BLUE subdepartment_color = COLOR_MEDICAL_BLUE sechud_icon_state = SECHUD_MEDICAL_DOCTOR @@ -674,7 +654,6 @@ /datum/id_trim/job/mime assignment = "Mime" trim_state = "trim_mime" - orbit_icon = "comment-slash" department_color = COLOR_SILVER subdepartment_color = COLOR_WHITE sechud_icon_state = SECHUD_MIME @@ -693,7 +672,6 @@ /datum/id_trim/job/paramedic assignment = "Paramedic" trim_state = "trim_paramedic" - orbit_icon = "truck-medical" department_color = COLOR_MEDICAL_BLUE subdepartment_color = COLOR_MEDICAL_BLUE sechud_icon_state = SECHUD_PARAMEDIC @@ -724,7 +702,6 @@ /datum/id_trim/job/prisoner assignment = "Prisoner" trim_state = "trim_warden" - orbit_icon = "lock" department_color = COLOR_PRISONER_BLACK subdepartment_color = COLOR_PRISONER_ORANGE sechud_icon_state = SECHUD_PRISONER @@ -767,7 +744,6 @@ /datum/id_trim/job/psychologist assignment = "Psychologist" trim_state = "trim_psychologist" - orbit_icon = "brain" department_color = COLOR_SERVICE_LIME subdepartment_color = COLOR_MEDICAL_BLUE sechud_icon_state = SECHUD_PSYCHOLOGIST @@ -788,7 +764,6 @@ /datum/id_trim/job/quartermaster assignment = "Quartermaster" trim_state = "trim_quartermaster" - orbit_icon = "sack-dollar" department_color = COLOR_COMMAND_BLUE subdepartment_color = COLOR_CARGO_BROWN department_state = "departmenthead" @@ -824,7 +799,6 @@ assignment = "Research Director" intern_alt_name = "Research Director-in-Training" trim_state = "trim_scientist" - orbit_icon = "user-graduate" department_color = COLOR_COMMAND_BLUE subdepartment_color = COLOR_SCIENCE_PINK department_state = "departmenthead" @@ -872,7 +846,6 @@ /datum/id_trim/job/roboticist assignment = "Roboticist" trim_state = "trim_roboticist" - orbit_icon = "battery-half" department_color = COLOR_SCIENCE_PINK subdepartment_color = COLOR_SCIENCE_PINK sechud_icon_state = SECHUD_ROBOTICIST @@ -900,7 +873,6 @@ /datum/id_trim/job/scientist assignment = "Scientist" trim_state = "trim_scientist" - orbit_icon = "flask" department_color = COLOR_SCIENCE_PINK subdepartment_color = COLOR_SCIENCE_PINK sechud_icon_state = SECHUD_SCIENTIST @@ -929,7 +901,6 @@ /datum/id_trim/job/security_officer assignment = "Security Officer" trim_state = "trim_securityofficer" - orbit_icon = "shield-halved" department_color = COLOR_SECURITY_RED subdepartment_color = COLOR_SECURITY_RED sechud_icon_state = SECHUD_SECURITY_OFFICER @@ -1050,7 +1021,6 @@ /datum/id_trim/job/shaft_miner assignment = "Shaft Miner" trim_state = "trim_shaftminer" - orbit_icon = "digging" department_color = COLOR_CARGO_BROWN subdepartment_color = COLOR_SCIENCE_PINK sechud_icon_state = SECHUD_SHAFT_MINER @@ -1087,7 +1057,6 @@ /datum/id_trim/job/station_engineer assignment = "Station Engineer" trim_state = "trim_stationengineer" - orbit_icon = "gears" department_color = COLOR_ENGINEERING_ORANGE subdepartment_color = COLOR_ENGINEERING_ORANGE sechud_icon_state = SECHUD_STATION_ENGINEER @@ -1117,7 +1086,6 @@ /datum/id_trim/job/virologist assignment = "Virologist" trim_state = "trim_virologist" - orbit_icon = "virus" department_color = COLOR_MEDICAL_BLUE subdepartment_color = COLOR_MEDICAL_BLUE sechud_icon_state = SECHUD_VIROLOGIST @@ -1142,7 +1110,6 @@ /datum/id_trim/job/warden assignment = "Warden" trim_state = "trim_warden" - orbit_icon = "handcuffs" department_color = COLOR_SECURITY_RED subdepartment_color = COLOR_SECURITY_RED sechud_icon_state = SECHUD_WARDEN diff --git a/code/datums/records/crime.dm b/code/datums/records/crime.dm new file mode 100644 index 00000000000..27daf0646f6 --- /dev/null +++ b/code/datums/records/crime.dm @@ -0,0 +1,60 @@ +/** + * Crime data. Used to store information about crimes. + */ +/datum/crime + /// Name of the crime + var/name + /// Details about the crime + var/details + /// Player that wrote the crime + var/author + /// Time of the crime + var/time + +/datum/crime/New(name = "Crime", details = "No details provided.", author = "Anonymous") + src.author = author + src.details = details + src.name = name + src.time = station_time_timestamp() + +/datum/crime/citation + /// Fine for the crime + var/fine + /// Amount of money paid for the crime + var/paid + +/datum/crime/citation/New(name = "Citation", details = "No details provided.", author = "Anonymous", fine = 0) + . = ..() + src.fine = fine + src.paid = 0 + +/// Pays off a fine and attempts to fix any weird values. +/datum/crime/citation/proc/pay_fine(amount) + paid += amount + if(paid > fine) + paid = fine + + fine -= amount + if(fine < 0) + fine = 0 + + return TRUE + +/// Sends a citation alert message to the target's PDA. +/datum/crime/citation/proc/alert_owner(mob/sender, atom/source, target_name, message) + for(var/obj/item/modular_computer/tablet in GLOB.TabletMessengers) + if(tablet.saved_identification != target_name) + continue + + var/datum/signal/subspace/messaging/tablet_msg/signal = new(source, list( + name = "Security Citation", + job = "Citation Server", + message = message, + targets = list(tablet), + automated = TRUE + )) + signal.send_to_receivers() + sender.log_message("(PDA: Citation Server) sent \"[message]\" to [signal.format_target()]", LOG_PDA) + break + + return TRUE diff --git a/code/datums/records/data.dm b/code/datums/records/data.dm new file mode 100644 index 00000000000..2b63dd4e796 --- /dev/null +++ b/code/datums/records/data.dm @@ -0,0 +1,4 @@ +/// Currently used for experiments, vending products. +/datum/data + /// Given name for the item. + var/name diff --git a/code/datums/records/manifest.dm b/code/datums/records/manifest.dm new file mode 100644 index 00000000000..47c3124c3cc --- /dev/null +++ b/code/datums/records/manifest.dm @@ -0,0 +1,157 @@ +GLOBAL_DATUM_INIT(manifest, /datum/manifest, new) + +/** Stores crew records. */ +/datum/manifest + /// All of the crew records. + var/list/general = list() + /// This list tracks characters spawned in the world and cannot be modified in-game. Currently referenced by respawn_character(). + var/list/locked = list() + /// Total number of security rapsheet prints. Changes the header. + var/print_count = 0 + +/// Builds the list of crew records for all crew members. +/datum/manifest/proc/build() + for(var/i in GLOB.new_player_list) + var/mob/dead/new_player/readied_player = i + if(readied_player.new_character) + log_manifest(readied_player.ckey,readied_player.new_character.mind,readied_player.new_character) + if(ishuman(readied_player.new_character)) + inject(readied_player.new_character) + CHECK_TICK + +/// Gets the current manifest. +/datum/manifest/proc/get_manifest() + // First we build up the order in which we want the departments to appear in. + var/list/manifest_out = list() + for(var/datum/job_department/department as anything in SSjob.joinable_departments) + manifest_out[department.department_name] = list() + manifest_out[DEPARTMENT_UNASSIGNED] = list() + + var/list/departments_by_type = SSjob.joinable_departments_by_type + for(var/datum/record/crew/target as anything in GLOB.manifest.general) + var/name = target.name + var/rank = target.rank // user-visible job + var/trim = target.trim // internal jobs by trim type + var/datum/job/job = SSjob.GetJob(trim) + if(!job || !(job.job_flags & JOB_CREW_MANIFEST) || !LAZYLEN(job.departments_list)) // In case an unlawful custom rank is added. + var/list/misc_list = manifest_out[DEPARTMENT_UNASSIGNED] + misc_list[++misc_list.len] = list( + "name" = name, + "rank" = rank, + ) + continue + for(var/department_type as anything in job.departments_list) + var/datum/job_department/department = departments_by_type[department_type] + if(!department) + stack_trace("get_manifest() failed to get job department for [department_type] of [job.type]") + continue + var/list/entry = list( + "name" = name, + "rank" = rank, + ) + var/list/department_list = manifest_out[department.department_name] + if(istype(job, department.department_head)) + department_list.Insert(1, null) + department_list[1] = entry + else + department_list[++department_list.len] = entry + + // Trim the empty categories. + for (var/department in manifest_out) + if(!length(manifest_out[department])) + manifest_out -= department + + return manifest_out + +/// Returns the manifest as an html. +/datum/manifest/proc/get_html(monochrome = FALSE) + var/list/manifest = get_manifest() + var/dat = {" + + + + "} + for(var/department in manifest) + var/list/entries = manifest[department] + dat += "" + //JUST + var/even = FALSE + for(var/entry in entries) + var/list/entry_list = entry + dat += "" + even = !even + + dat += "
NameRank
[department]
[entry_list["name"]][entry_list["rank"]]
" + dat = replacetext(dat, "\n", "") + dat = replacetext(dat, "\t", "") + return dat + + +/// Injects a record into the manifest. +/datum/manifest/proc/inject(mob/living/carbon/human/person) + set waitfor = FALSE + if(!(person.mind?.assigned_role.job_flags & JOB_CREW_MANIFEST)) + return + + var/assignment = person.mind.assigned_role.title + var/mutable_appearance/character_appearance = new(person.appearance) + var/person_gender = "Other" + if(person.gender == "male") + person_gender = "Male" + if(person.gender == "female") + person_gender = "Female" + + var/datum/record/locked/lockfile = new( + age = person.age, + blood_type = person.dna.blood_type, + character_appearance = character_appearance, + dna_string = person.dna.unique_enzymes, + fingerprint = md5(person.dna.unique_identity), + gender = person_gender, + initial_rank = assignment, + name = person.real_name, + rank = assignment, + species = person.dna.species.name, + trim = assignment, + // Locked specifics + dna_ref = person.dna, + mind_ref = person.mind, + ) + + new /datum/record/crew( + age = person.age, + blood_type = person.dna.blood_type, + character_appearance = character_appearance, + dna_string = person.dna.unique_enzymes, + fingerprint = md5(person.dna.unique_identity), + gender = person_gender, + initial_rank = assignment, + name = person.real_name, + rank = assignment, + species = person.dna.species.name, + trim = assignment, + // Crew specific + lock_ref = REF(lockfile), + major_disabilities = person.get_quirk_string(FALSE, CAT_QUIRK_MAJOR_DISABILITY), + major_disabilities_desc = person.get_quirk_string(TRUE, CAT_QUIRK_MAJOR_DISABILITY), + minor_disabilities = person.get_quirk_string(FALSE, CAT_QUIRK_MINOR_DISABILITY), + minor_disabilities_desc = person.get_quirk_string(TRUE, CAT_QUIRK_MINOR_DISABILITY), + quirk_notes = person.get_quirk_string(TRUE, CAT_QUIRK_NOTES), + ) + + return + +/// Edits the rank and trim of the found record. +/datum/manifest/proc/modify(name, assignment, trim) + var/datum/record/crew/target = find_record(name) + if(!target) + return + + target.rank = assignment + target.trim = trim diff --git a/code/datums/records/medical_note.dm b/code/datums/records/medical_note.dm new file mode 100644 index 00000000000..a1843394c2a --- /dev/null +++ b/code/datums/records/medical_note.dm @@ -0,0 +1,15 @@ +/** + * Player-written medical note. + */ +/datum/medical_note + /// Player that wrote the note + var/author + /// Details of the note + var/content + /// Station timestamp + var/time + +/datum/medical_note/New(author = "Anonymous", content = "No details provided.") + src.author = author + src.content = content + src.time = station_time_timestamp() diff --git a/code/datums/records/record.dm b/code/datums/records/record.dm new file mode 100644 index 00000000000..8b6bf4c9b70 --- /dev/null +++ b/code/datums/records/record.dm @@ -0,0 +1,256 @@ +/** + * Record datum. Used for crew records and admin locked records. + */ +/datum/record + /// Age of the character + var/age + /// Their blood type + var/blood_type + /// Character appearance + var/mutable_appearance/character_appearance + /// DNA string + var/dna_string + /// Fingerprint string (md5) + var/fingerprint + /// The character's gender + var/gender + /// The character's initial rank at roundstart + var/initial_rank + /// The character's name + var/name = "Unknown" + /// The character's rank + var/rank + /// The character's species + var/species + /// The character's ID trim + var/trim + +/datum/record/New( + age = 18, + blood_type = "?", + character_appearance, + dna_string = "Unknown", + fingerprint = "?????", + gender = "Other", + initial_rank = "Unassigned", + name = "Unknown", + rank = "Unassigned", + species = "Human", + trim = "Unassigned", +) + src.age = age + src.blood_type = blood_type + src.character_appearance = character_appearance + src.dna_string = dna_string + src.fingerprint = fingerprint + src.gender = gender + src.initial_rank = rank + src.name = name + src.rank = rank + src.species = species + src.trim = trim + +/** + * Crew record datum + */ +/datum/record/crew + /// List of citations + var/list/citations = list() + /// List of crimes + var/list/crimes = list() + /// Unique ID generated that is used to fetch lock record + var/lock_ref + /// Names of major disabilities + var/major_disabilities + /// Fancy description of major disabilities + var/major_disabilities_desc + /// List of medical notes + var/list/medical_notes = list() + /// Names of minor disabilities + var/minor_disabilities + /// Fancy description of minor disabilities + var/minor_disabilities_desc + /// Positive and neutral quirk strings + var/quirk_notes + /// Security note + var/security_note + /// Current arrest status + var/wanted_status = WANTED_NONE + +/datum/record/crew/New( + age = 18, + blood_type = "?", + character_appearance, + dna_string = "Unknown", + fingerprint = "?????", + gender = "Other", + initial_rank = "Unassigned", + name = "Unknown", + rank = "Unassigned", + species = "Human", + trim = "Unassigned", + /// Crew specific + lock_ref, + major_disabilities = "None", + major_disabilities_desc = "No disabilities have been diagnosed at the moment.", + minor_disabilities = "None", + minor_disabilities_desc = "No disabilities have been diagnosed at the moment.", + quirk_notes, +) + . = ..() + src.lock_ref = lock_ref + src.major_disabilities = major_disabilities + src.major_disabilities_desc = major_disabilities_desc + src.minor_disabilities = minor_disabilities + src.minor_disabilities_desc = minor_disabilities_desc + src.quirk_notes = quirk_notes + + GLOB.manifest.general += src + +/datum/record/crew/Destroy() + GLOB.manifest.general -= src + return ..() + +/** + * Admin locked record + */ +/datum/record/locked + /// Mob's dna + var/datum/dna/dna_ref + /// Mind datum + var/datum/mind/mind_ref + +/datum/record/locked/New( + age = 18, + blood_type = "?", + character_appearance, + dna_string = "Unknown", + fingerprint = "?????", + gender = "Other", + initial_rank = "Unassigned", + name = "Unknown", + rank = "Unassigned", + species = "Human", + trim = "Unassigned", + /// Locked specific + datum/dna/dna_ref, + datum/mind/mind_ref, +) + . = ..() + src.dna_ref = dna_ref + src.mind_ref = mind_ref + + GLOB.manifest.locked += src + +/datum/record/locked/Destroy() + GLOB.manifest.locked -= src + return ..() + +/// A helper proc to get the front photo of a character from the record. +/// Handles calling `get_photo()`, read its documentation for more information. +/datum/record/crew/proc/get_front_photo() + return get_photo("photo_front", SOUTH) + +/// A helper proc to get the side photo of a character from the record. +/// Handles calling `get_photo()`, read its documentation for more information. +/datum/record/crew/proc/get_side_photo() + return get_photo("photo_side", WEST) + +/** + * You shouldn't be calling this directly, use `get_front_photo()` or `get_side_photo()` + * instead. + * + * This is the proc that handles either fetching (if it was already generated before) or + * generating (if it wasn't) the specified photo from the specified record. This is only + * intended to be used by records that used to try to access `fields["photo_front"]` or + * `fields["photo_side"]`, and will return an empty icon if there isn't any of the necessary + * fields. + * + * Arguments: + * * field_name - The name of the key in the `fields` list, of the record itself. + * * orientation - The direction in which you want the character appearance to be rotated + * in the outputed photo. + * + * Returns an empty `/icon` if there was no `character_appearance` entry in the `fields` list, + * returns the generated/cached photo otherwise. + */ +/datum/record/crew/proc/get_photo(field_name, orientation) + if(!field_name) + return + + if(!character_appearance) + return new /icon() + + var/mutable_appearance/appearance = character_appearance + appearance.setDir(orientation) + + var/icon/picture_image = getFlatIcon(appearance) + + var/datum/picture/picture = new + picture.picture_name = name + picture.picture_desc = "This is [name]." + picture.picture_image = picture_image + + var/obj/item/photo/photo = new(null, picture) + field_name = photo + return photo + +/// Returns a paper printout of the current record's crime data. +/datum/record/crew/proc/get_rapsheet(alias, header = "Rapsheet", description = "No further details.") + var/print_count = ++GLOB.manifest.print_count + var/obj/item/paper/printed_paper = new + var/final_paper_text = text("
SR-[print_count]: [header]

") + + final_paper_text += text("Name: []
Gender: []
Age: []
", name, gender, age) + if(alias != name) + final_paper_text += text("Alias: []
", alias) + + final_paper_text += text("Species: []
Fingerprint: []
Wanted Status: []

", species, fingerprint, wanted_status) + + final_paper_text += text("
Security Data


") + + final_paper_text += "Crimes:
" + final_paper_text += {" + + + + + + "} + for(var/datum/crime/crime in crimes) + final_paper_text += "" + final_paper_text += "" + final_paper_text += "" + final_paper_text += "" + final_paper_text += "" + final_paper_text += "
CrimeDetailsAuthorTime Added
[crime.name][crime.details][crime.author][crime.time]


" + + final_paper_text += "Citations:
" + final_paper_text += {" + + + + + + +
"} + for(var/datum/crime/citation/warrant in citations) + final_paper_text += "" + final_paper_text += "" + final_paper_text += "" + final_paper_text += "" + final_paper_text += "" + final_paper_text += "" + final_paper_text += "
CitationDetailsAuthorTime AddedFine
[warrant.name][warrant.details][warrant.author][warrant.time][warrant.fine]


" + + final_paper_text += text("
Important Notes:

") + if(security_note) + final_paper_text += text("- [security_note]
") + if(description) + final_paper_text += text("- [description]
") + + printed_paper.name = text("SR-[] '[]'", print_count, name) + printed_paper.add_raw_text(final_paper_text) + printed_paper.update_appearance() + + return printed_paper diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index 3d04c79c543..023d528d9d5 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -301,32 +301,30 @@ Security HUDs! Basic mode shows only the job. /mob/living/carbon/human/proc/sec_hud_set_security_status() var/image/holder = hud_list[WANTED_HUD] - var/icon/I = icon(icon, icon_state, dir) - holder.pixel_y = I.Height() - world.icon_size - var/perpname = get_face_name(get_id_name("")) - if(perpname && GLOB.data_core) - var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.security) - if(R) - var/has_criminal_entry = TRUE - switch(R.fields["criminal"]) - if("*Arrest*") - holder.icon_state = "hudwanted" - if("Incarcerated") - holder.icon_state = "hudincarcerated" - if("Suspected") - holder.icon_state = "hudsuspected" - if("Paroled") - holder.icon_state = "hudparolled" - if("Discharged") - holder.icon_state = "huddischarged" - else - has_criminal_entry = FALSE - if(has_criminal_entry) - set_hud_image_active(WANTED_HUD) - return + var/icon/sec_icon = icon(icon, icon_state, dir) + holder.pixel_y = sec_icon.Height() - world.icon_size + var/perp_name = get_face_name(get_id_name("")) - holder.icon_state = null - set_hud_image_inactive(WANTED_HUD) + if(!perp_name || !GLOB.manifest) + holder.icon_state = null + set_hud_image_inactive(WANTED_HUD) + return + + var/datum/record/crew/target = find_record(perp_name) + if(!target || target.wanted_status == WANTED_NONE) + return + + switch(target.wanted_status) + if(WANTED_ARREST) + holder.icon_state = "hudwanted" + if(WANTED_PRISONER) + holder.icon_state = "hudincarcerated" + if(WANTED_SUSPECT) + holder.icon_state = "hudsuspected" + if(WANTED_PAROLE) + holder.icon_state = "hudparolled" + if(WANTED_DISCHARGED) + holder.icon_state = "huddischarged" /*********************************************** Diagnostic HUDs! diff --git a/code/game/machinery/computer/_computer.dm b/code/game/machinery/computer/_computer.dm index 6506c35d564..9a27d1b8279 100644 --- a/code/game/machinery/computer/_computer.dm +++ b/code/game/machinery/computer/_computer.dm @@ -19,6 +19,8 @@ var/time_to_unscrew = 2 SECONDS /// Are we authenticated to use this? Used by things like comms console, security and medical data, and apc controller. var/authenticated = FALSE + /// The character preview view for the UI. + var/atom/movable/screen/map_view/char_preview/character_preview_view /datum/armor/machinery_computer fire = 40 @@ -143,3 +145,154 @@ SHOULD_CALL_PARENT(TRUE) . = ..() update_use_power(IDLE_POWER_USE) + +/obj/machinery/computer/ui_act(action, list/params, datum/tgui/ui) + . = ..() + if(.) + return + + var/datum/record/crew/target + if(params["crew_ref"]) + target = locate(params["crew_ref"]) in GLOB.manifest.general + + switch(action) + if("edit_field") + target = locate(params["ref"]) in GLOB.manifest.general + var/field = params["field"] + if(!field || !target?.vars[field]) + return FALSE + + var/value = trim(params["value"], MAX_BROADCAST_LEN) + target.vars[field] = value || "Unknown" + + return TRUE + + if("expunge_record") + if(!target) + return FALSE + + expunge_record_info(target) + balloon_alert(usr, "record expunged") + playsound(src, 'sound/machines/terminal_eject.ogg', 70, TRUE) + + return TRUE + + if("login") + authenticated = secure_login(usr) + return TRUE + + if("logout") + balloon_alert(usr, "logged out") + playsound(src, 'sound/machines/terminal_off.ogg', 70, TRUE) + authenticated = FALSE + + return TRUE + + if("purge_records") + ui.close() + balloon_alert(usr, "purging records") + playsound(src, 'sound/machines/terminal_alert.ogg', 70, TRUE) + + if(do_after(usr, 5 SECONDS)) + for(var/datum/record/crew/entry in GLOB.manifest.general) + expunge_record_info(entry) + + balloon_alert(usr, "records purged") + playsound(src, 'sound/machines/terminal_off.ogg', 70, TRUE) + + return TRUE + + if("view_record") + if(!target) + return FALSE + + playsound(src, "sound/machines/terminal_button0[rand(1, 8)].ogg", 50, TRUE) + update_preview(usr, params["assigned_view"], target) + return TRUE + + return FALSE + +/// Creates a character preview view for the UI. +/obj/machinery/computer/proc/create_character_preview_view(mob/user) + var/assigned_view = "preview_[user.ckey]_[REF(src)]_records" + if(user.client?.screen_maps[assigned_view]) + return + + var/atom/movable/screen/map_view/char_preview/new_view = new(null, src) + new_view.generate_view(assigned_view) + new_view.display_to(user) + +/// Takes a record and updates the character preview view to match it. +/obj/machinery/computer/proc/update_preview(mob/user, assigned_view, datum/record/crew/target) + var/mutable_appearance/preview = new(target.character_appearance) + preview.underlays += mutable_appearance('icons/effects/effects.dmi', "static_base", alpha = 20) + preview.add_overlay(mutable_appearance(generate_icon_alpha_mask('icons/effects/effects.dmi', "scanline"), alpha = 20)) + + var/atom/movable/screen/map_view/char_preview/old_view = user.client?.screen_maps[assigned_view]?[1] + if(!old_view) + return + + old_view.appearance = preview.appearance + +/// Expunges info from a record. +/obj/machinery/computer/proc/expunge_record_info(datum/record/crew/target) + return + +/// Detects whether a user can use buttons on the machine +/obj/machinery/computer/proc/has_auth(mob/user) + if(!isliving(user)) + return FALSE + var/mob/living/player = user + + if(issilicon(player)) // Silicons don't need to authenticate + return TRUE + + var/obj/item/card/auth = player.get_idcard(TRUE) + if(!auth) + return FALSE + var/list/access = auth.GetAccess() + if(!check_access_list(access)) + return FALSE + + return TRUE + +/// Inserts a new record into GLOB.manifest.general. Requires a photo to be taken. +/obj/machinery/computer/proc/insert_new_record(mob/user, obj/item/photo/mugshot) + if(!mugshot || !is_operational || !user.canUseTopic(src, be_close = !issilicon(user))) + return FALSE + + if(!authenticated && !has_auth(user)) + balloon_alert(user, "access denied") + playsound(src, 'sound/machines/terminal_error.ogg', 70, TRUE) + return FALSE + + var/trimmed = copytext(mugshot.name, 9, MAX_NAME_LEN) // Remove "photo - " + var/name = tgui_input_text(user, "Enter the name of the new record.", "New Record", trimmed, MAX_NAME_LEN) + if(!name || !is_operational || !user.canUseTopic(src, be_close = !issilicon(user)) || !mugshot || QDELETED(mugshot) || QDELETED(src)) + return FALSE + + new /datum/record/crew(name = name, character_appearance = mugshot.picture.picture_image) + + balloon_alert(user, "record created") + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 70, TRUE) + + qdel(mugshot) + + return TRUE + +/// Secure login +/obj/machinery/computer/proc/secure_login(mob/user) + if(!user.canUseTopic(src, be_close = !issilicon(user)) || !is_operational) + return FALSE + + if(!has_auth(user)) + balloon_alert(user, "access denied") + playsound(src, 'sound/machines/terminal_error.ogg', 70, TRUE) + return FALSE + + balloon_alert(user, "logged in") + playsound(src, 'sound/machines/terminal_on.ogg', 70, TRUE) + + return TRUE + + diff --git a/code/game/machinery/computer/arcade/orion.dm b/code/game/machinery/computer/arcade/orion.dm index 4669254622c..05123a4c11b 100644 --- a/code/game/machinery/computer/arcade/orion.dm +++ b/code/game/machinery/computer/arcade/orion.dm @@ -139,12 +139,6 @@ GLOBAL_LIST_INIT(orion_events, generate_orion_events()) gamer.client.give_award(/datum/award/achievement/misc/gamer, gamer) // PSYCH REPORT NOTE: patient kept rambling about how they did it for an "achievement", recommend continued holding for observation gamer.mind?.adjust_experience(/datum/skill/gaming, 50) // cheevos make u better - if(!isnull(GLOB.data_core.general)) - for(var/datum/data/record/insanity_records in GLOB.data_core.general) - if(insanity_records.fields["name"] == gamer.name) - insanity_records.fields["m_stat"] = "*Unstable*" - return - /obj/machinery/computer/arcade/orion_trail/ui_interact(mob/user, datum/tgui/ui) . = ..() ui = SStgui.try_update_ui(user, src, ui) diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm index 45c791944a7..820c26ca099 100644 --- a/code/game/machinery/computer/medical.dm +++ b/code/game/machinery/computer/medical.dm @@ -1,6 +1,4 @@ - - -/obj/machinery/computer/med_data//TODO:SANITY +/obj/machinery/computer/med_data name = "medical records console" desc = "This can be used to check medical records." icon_screen = "medcomp" @@ -8,573 +6,11 @@ req_one_access = list(ACCESS_MEDICAL, ACCESS_DETECTIVE, ACCESS_GENETICS) circuit = /obj/item/circuitboard/computer/med_data light_color = LIGHT_COLOR_BLUE - var/rank = null - var/screen = null - var/datum/data/record/active1 - var/datum/data/record/active2 - var/temp = null - var/printing = null - //Sorting Variables - var/sortBy = "name" - var/order = 1 // -1 = Descending - 1 = Ascending - /obj/machinery/computer/med_data/syndie icon_keyboard = "syndie_key" req_one_access = list(ACCESS_SYNDICATE) -/obj/machinery/computer/med_data/ui_interact(mob/user) - . = ..() - if(isliving(user)) - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) - var/dat - if(temp) - dat = text("[temp]

Clear Screen") - else - if(authenticated) - switch(screen) - if(1) - dat += {" -Search Records -
List Records -
-
Virus Database -
Medbot Tracking -
-
Record Maintenance -
{Log Out}
-"} - if(2) - dat += {" -

- - - - -
Records:
- - - - - - - - -"} - - - if(!isnull(GLOB.data_core.general)) - for(var/datum/data/record/R in sort_record(GLOB.data_core.general, sortBy, order)) - var/blood_type = "" - var/b_dna = "" - for(var/datum/data/record/E in GLOB.data_core.medical) - if((E.fields["name"] == R.fields["name"] && E.fields["id"] == R.fields["id"])) - blood_type = E.fields["blood_type"] - b_dna = E.fields["b_dna"] - var/background - - if(R.fields["m_stat"] == "*Insane*" || R.fields["p_stat"] == "*Deceased*") - background = "'background-color:#990000;'" - else if(R.fields["p_stat"] == "*Unconscious*" || R.fields["m_stat"] == "*Unstable*") - background = "'background-color:#CD6500;'" - else if(R.fields["p_stat"] == "Physically Unfit" || R.fields["m_stat"] == "*Watch*") - background = "'background-color:#3BB9FF;'" - else - background = "'background-color:#4F7529;'" - - dat += text("", background, R.fields["id"], R.fields["name"]) - dat += text("", R.fields["id"]) - dat += text("", R.fields["fingerprint"], b_dna) - dat += text("", blood_type) - dat += text("", R.fields["p_stat"]) - dat += text("", R.fields["m_stat"]) - dat += "
NameIDFingerprints (F) | DNA UE (D)Blood TypePhysical StatusMental Status
[][]F: []
D: []
[][][]

" - dat += "
Back" - if(3) - dat += "Records Maintenance
\nBackup To Disk
\nUpload From Disk
\nDelete All Records
\n
\nBack" - if(4) - - dat += "" - if(active1 in GLOB.data_core.general) - var/front_photo = active1.get_front_photo() - if(istype(front_photo, /obj/item/photo)) - var/obj/item/photo/photo_front = front_photo - user << browse_rsc(photo_front.picture.picture_image, "photo_front") - var/side_photo = active1.get_side_photo() - if(istype(side_photo, /obj/item/photo)) - var/obj/item/photo/photo_side = side_photo - user << browse_rsc(photo_side.picture.picture_image, "photo_side") - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - else - dat += "" - - dat += "" - if(active2 in GLOB.data_core.medical) - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" //(per disease info placed in log/comment section) - dat += "" - dat += "" - dat += "" - - dat += "" - var/counter = 1 - while(active2.fields[text("com_[]", counter)]) - dat += "" - counter++ - dat += "" - - dat += "" - else - dat += "" - dat += "" - dat += "" - dat += "" - dat += "
Medical Record
Name:[active1.fields["name"]]
ID:[active1.fields["id"]]
Gender: [active1.fields["gender"]] 
Age: [active1.fields["age"]] 
Species: [active1.fields["species"]] 
Fingerprint: [active1.fields["fingerprint"]] 
Physical Status: [active1.fields["p_stat"]] 
Mental Status: [active1.fields["m_stat"]] 
General Record Lost!

Medical Data
Blood Type: [active2.fields["blood_type"]] 
DNA: [active2.fields["b_dna"]] 

Minor Disabilities:

 [active2.fields["mi_dis"]] 
Details: [active2.fields["mi_dis_d"]] 

Major Disabilities:

 [active2.fields["ma_dis"]] 
Details: [active2.fields["ma_dis_d"]] 

Current Diseases:

 [active2.fields["cdi"]] 
Details: [active2.fields["cdi_d"]] 

Important Notes:

 [active2.fields["notes"]] 

Notes Cont'd:

 [active2.fields["notes_d"]] 

Comments/Log
[active2.fields[text("com_[]", counter)]]
Delete Entry
Add Entry

Delete Record (Medical Only)
Medical Record Lost!

New Record
Print Record
Back
" - if(5) - dat += "
Virus Database
" - for(var/Dt in typesof(/datum/disease/)) - var/datum/disease/Dis = new Dt(0) - if(istype(Dis, /datum/disease/advance)) - continue // TODO (tm): Add advance diseases to the virus database which no one uses. - if(!Dis.desc) - continue - dat += "
[Dis.name]" - dat += "
Back" - if(6) - dat += "
Medical Robot Monitor
" - dat += "Back" - dat += "
Medical Robots:" - var/bdat = null - for(var/mob/living/simple_animal/bot/medbot/M in GLOB.alive_mob_list) - if(M.z != z) - continue //only find medibots on the same z-level as the computer - var/turf/bl = get_turf(M) - if(bl) //if it can't find a turf for the medibot, then it probably shouldn't be showing up - bdat += "[M.name] - \[[bl.x],[bl.y]\] - [M.bot_mode_flags & BOT_MODE_ON ? "Online" : "Offline"]
" - if(!bdat) - dat += "
None detected
" - else - dat += "
[bdat]" - - else - else - dat += "{Log In}" - var/datum/browser/popup = new(user, "med_rec", "Medical Records Console", 600, 400) - popup.set_content(dat) - popup.open() - -/obj/machinery/computer/med_data/Topic(href, href_list) - . = ..() - if(.) - return . - if(!(active1 in GLOB.data_core.general)) - active1 = null - if(!(active2 in GLOB.data_core.medical)) - active2 = null - - if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)) || issilicon(usr) || isAdminGhostAI(usr)) - usr.set_machine(src) - if(href_list["temp"]) - temp = null - else if(href_list["logout"]) - authenticated = null - screen = null - active1 = null - active2 = null - playsound(src, 'sound/machines/terminal_off.ogg', 50, FALSE) - else if(href_list["choice"]) - // SORTING! - if(href_list["choice"] == "Sorting") - // Reverse the order if clicked twice - if(sortBy == href_list["sort"]) - if(order == 1) - order = -1 - else - order = 1 - else - // New sorting order! - sortBy = href_list["sort"] - order = initial(order) - else if(href_list["login"]) - var/obj/item/card/id/I - if(isliving(usr)) - var/mob/living/L = usr - I = L.get_idcard(TRUE) - if(issilicon(usr)) - active1 = null - active2 = null - authenticated = 1 - rank = "AI" - screen = 1 - else if(isAdminGhostAI(usr)) - active1 = null - active2 = null - authenticated = 1 - rank = "Central Command" - screen = 1 - else if(istype(I) && check_access(I)) - active1 = null - active2 = null - authenticated = I.registered_name - rank = I.assignment - screen = 1 - else - to_chat(usr, span_danger("Unauthorized access.")) - playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE) - if(authenticated) - if(href_list["screen"]) - screen = text2num(href_list["screen"]) - if(screen < 1) - screen = 1 - - active1 = null - active2 = null - - else if(href_list["vir"]) - var/type = text2path(href_list["vir"] || "") - if(!ispath(type, /datum/disease)) - return - - var/datum/disease/disease = new type(0) - var/applicable_mob_names = "" - for(var/mob/viable_mob as anything in disease.viable_mobtypes) - applicable_mob_names += " [initial(viable_mob.name)];" - temp = {"Name: [disease.name] -
Number of stages: [disease.max_stages] -
Spread: [disease.spread_text] Transmission -
Possible Cure: [(disease.cure_text || "none")] -
Affected Lifeforms:[applicable_mob_names] -
-
Notes: [disease.desc] -
-
Severity: [disease.severity]"} - - else if(href_list["del_all"]) - temp = "Are you sure you wish to delete all records?
\n\tYes
\n\tNo
" - - else if(href_list["del_all2"]) - usr.investigate_log("has deleted all medical records.", INVESTIGATE_RECORDS) - GLOB.data_core.medical.Cut() - temp = "All records deleted." - - else if(href_list["field"]) - var/a1 = active1 - var/a2 = active2 - switch(href_list["field"]) - if("fingerprint") - if(active1) - var/t1 = stripped_input("Please input fingerprint hash:", "Med. records", active1.fields["fingerprint"], null) - if(!canUseMedicalRecordsConsole(usr, t1, a1)) - return - active1.fields["fingerprint"] = t1 - if("gender") - if(active1) - if(active1.fields["gender"] == "Male") - active1.fields["gender"] = "Female" - else if(active1.fields["gender"] == "Female") - active1.fields["gender"] = "Other" - else - active1.fields["gender"] = "Male" - if("age") - if(active1) - var/t1 = input("Please input age:", "Med. records", active1.fields["age"], null) as num - if(!canUseMedicalRecordsConsole(usr, t1, a1)) - return - active1.fields["age"] = t1 - if("species") - if(active1) - var/t1 = stripped_input("Please input species name", "Med. records", active1.fields["species"], null) - if(!canUseMedicalRecordsConsole(usr, t1, a1)) - return - active1.fields["species"] = t1 - if("mi_dis") - if(active2) - var/t1 = stripped_input("Please input minor disabilities list:", "Med. records", active2.fields["mi_dis"], null) - if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) - return - active2.fields["mi_dis"] = t1 - if("mi_dis_d") - if(active2) - var/t1 = stripped_input("Please summarize minor dis.:", "Med. records", active2.fields["mi_dis_d"], null) - if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) - return - active2.fields["mi_dis_d"] = t1 - if("ma_dis") - if(active2) - var/t1 = stripped_input("Please input major disabilities list:", "Med. records", active2.fields["ma_dis"], null) - if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) - return - active2.fields["ma_dis"] = t1 - if("ma_dis_d") - if(active2) - var/t1 = stripped_input("Please summarize major dis.:", "Med. records", active2.fields["ma_dis_d"], null) - if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) - return - active2.fields["ma_dis_d"] = t1 - if("alg") - if(active2) - var/t1 = stripped_input("Please state allergies:", "Med. records", active2.fields["alg"], null) - if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) - return - active2.fields["alg"] = t1 - if("alg_d") - if(active2) - var/t1 = stripped_input("Please summarize allergies:", "Med. records", active2.fields["alg_d"], null) - if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) - return - active2.fields["alg_d"] = t1 - if("cdi") - if(active2) - var/t1 = stripped_input("Please state diseases:", "Med. records", active2.fields["cdi"], null) - if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) - return - active2.fields["cdi"] = t1 - if("cdi_d") - if(active2) - var/t1 = stripped_input("Please summarize diseases:", "Med. records", active2.fields["cdi_d"], null) - if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) - return - active2.fields["cdi_d"] = t1 - if("notes") - if(active2) - var/t1 = stripped_input("Please summarize notes:", "Med. records", active2.fields["notes"], null) - if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) - return - active2.fields["notes"] = t1 - if("p_stat") - if(active1) - temp = "Physical Condition:
\n\t*Deceased*
\n\t*Unconscious*
\n\tActive
\n\tPhysically Unfit
" - if("m_stat") - if(active1) - temp = "Mental Condition:
\n\t*Insane*
\n\t*Unstable*
\n\t*Watch*
\n\tStable
" - if("blood_type") - if(active2) - temp = "Blood Type:
\n\tA- A+
\n\tB- B+
\n\tAB- AB+
\n\tO- O+
" - if("b_dna") - if(active2) - var/t1 = stripped_input("Please input DNA hash:", "Med. records", active2.fields["b_dna"], null) - if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) - return - active2.fields["b_dna"] = t1 - if("show_photo_front") - if(active1) - var/front_photo = active1.get_front_photo() - if(istype(front_photo, /obj/item/photo)) - var/obj/item/photo/photo = front_photo - photo.show(usr) - if("show_photo_side") - if(active1) - var/side_photo = active1.get_side_photo() - if(istype(side_photo, /obj/item/photo)) - var/obj/item/photo/photo = side_photo - photo.show(usr) - else - - else if(href_list["p_stat"]) - if(active1) - switch(href_list["p_stat"]) - if("deceased") - active1.fields["p_stat"] = "*Deceased*" - if("unconscious") - active1.fields["p_stat"] = "*Unconscious*" - if("active") - active1.fields["p_stat"] = "Active" - if("unfit") - active1.fields["p_stat"] = "Physically Unfit" - - else if(href_list["m_stat"]) - if(active1) - switch(href_list["m_stat"]) - if("insane") - active1.fields["m_stat"] = "*Insane*" - if("unstable") - active1.fields["m_stat"] = "*Unstable*" - if("watch") - active1.fields["m_stat"] = "*Watch*" - if("stable") - active1.fields["m_stat"] = "Stable" - - - else if(href_list["blood_type"]) - if(active2) - switch(href_list["blood_type"]) - if("an") - active2.fields["blood_type"] = "A-" - if("bn") - active2.fields["blood_type"] = "B-" - if("abn") - active2.fields["blood_type"] = "AB-" - if("on") - active2.fields["blood_type"] = "O-" - if("ap") - active2.fields["blood_type"] = "A+" - if("bp") - active2.fields["blood_type"] = "B+" - if("abp") - active2.fields["blood_type"] = "AB+" - if("op") - active2.fields["blood_type"] = "O+" - - - else if(href_list["del_r"]) - if(active2) - temp = "Are you sure you wish to delete the record (Medical Portion Only)?
\n\tYes
\n\tNo
" - - else if(href_list["del_r2"]) - usr.investigate_log("has deleted the medical records for [active1.fields["name"]].", INVESTIGATE_RECORDS) - if(active2) - qdel(active2) - active2 = null - - else if(href_list["d_rec"]) - active1 = find_record("id", href_list["d_rec"], GLOB.data_core.general) - if(active1) - active2 = find_record("id", href_list["d_rec"], GLOB.data_core.medical) - if(!active2) - active1 = null - screen = 4 - - else if(href_list["new"]) - if((istype(active1, /datum/data/record) && !( istype(active2, /datum/data/record) ))) - var/datum/data/record/R = new /datum/data/record() - R.fields["name"] = active1.fields["name"] - R.fields["id"] = active1.fields["id"] - R.name = text("Medical Record #[]", R.fields["id"]) - R.fields["blood_type"] = "Unknown" - R.fields["b_dna"] = "Unknown" - R.fields["mi_dis"] = "None" - R.fields["mi_dis_d"] = "No minor disabilities have been diagnosed." - R.fields["ma_dis"] = "None" - R.fields["ma_dis_d"] = "No major disabilities have been diagnosed." - R.fields["alg"] = "None" - R.fields["alg_d"] = "No allergies have been detected in this patient." - R.fields["cdi"] = "None" - R.fields["cdi_d"] = "No diseases have been diagnosed at the moment." - R.fields["notes"] = "No notes." - GLOB.data_core.medical += R - active2 = R - screen = 4 - - else if(href_list["add_c"]) - if(!(active2 in GLOB.data_core.medical)) - return - var/a2 = active2 - var/t1 = stripped_multiline_input("Add Comment:", "Med. records", null, null) - if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) - return - var/counter = 1 - while(active2.fields[text("com_[]", counter)]) - counter++ - active2.fields[text("com_[]", counter)] = text("Made by [] ([]) on [] [], []
[]", authenticated, rank, station_time_timestamp(), time2text(world.realtime, "MMM DD"), CURRENT_STATION_YEAR, t1) - - else if(href_list["del_c"]) - if((istype(active2, /datum/data/record) && active2.fields[text("com_[]", href_list["del_c"])])) - active2.fields[text("com_[]", href_list["del_c"])] = "Deleted" - - else if(href_list["search"]) - var/t1 = stripped_input(usr, "Search String: (Name, DNA, or ID)", "Med. records") - if(!canUseMedicalRecordsConsole(usr, t1)) - return - active1 = null - active2 = null - t1 = lowertext(t1) - for(var/datum/data/record/R in GLOB.data_core.medical) - if((lowertext(R.fields["name"]) == t1 || t1 == lowertext(R.fields["id"]) || t1 == lowertext(R.fields["b_dna"]))) - active2 = R - else - //Foreach continue //goto(3229) - if(!( active2 )) - temp = text("Could not locate record [].", sanitize(t1)) - else - for(var/datum/data/record/E in GLOB.data_core.general) - if((E.fields["name"] == active2.fields["name"] || E.fields["id"] == active2.fields["id"])) - active1 = E - else - //Foreach continue //goto(3334) - screen = 4 - - else if(href_list["print_p"]) - if(!( printing )) - printing = 1 - GLOB.data_core.medicalPrintCount++ - playsound(loc, 'sound/items/poster_being_created.ogg', 100, TRUE) - sleep(3 SECONDS) - var/obj/item/paper/printed_paper = new /obj/item/paper(loc) - var/final_paper_text = "
Medical Record - (MR-[GLOB.data_core.medicalPrintCount])

" - if(active1 in GLOB.data_core.general) - final_paper_text += text("Name: [] ID: []
\nGender: []
\nAge: []
", active1.fields["name"], active1.fields["id"], active1.fields["gender"], active1.fields["age"]) - final_paper_text += "\nSpecies: [active1.fields["species"]]
" - final_paper_text += text("\nFingerprint: []
\nPhysical Status: []
\nMental Status: []
", active1.fields["fingerprint"], active1.fields["p_stat"], active1.fields["m_stat"]) - else - final_paper_text += "General Record Lost!
" - if(active2 in GLOB.data_core.medical) - final_paper_text += text("
\n
Medical Data

\nBlood Type: []
\nDNA: []
\n
\nMinor Disabilities: []
\nDetails: []
\n
\nMajor Disabilities: []
\nDetails: []
\n
\nAllergies: []
\nDetails: []
\n
\nCurrent Diseases: [] (per disease info placed in log/comment section)
\nDetails: []
\n
\nImportant Notes:
\n\t[]
\n
\n
Comments/Log

", active2.fields["blood_type"], active2.fields["b_dna"], active2.fields["mi_dis"], active2.fields["mi_dis_d"], active2.fields["ma_dis"], active2.fields["ma_dis_d"], active2.fields["alg"], active2.fields["alg_d"], active2.fields["cdi"], active2.fields["cdi_d"], active2.fields["notes"]) - var/counter = 1 - while(active2.fields[text("com_[]", counter)]) - final_paper_text += text("[]
", active2.fields[text("com_[]", counter)]) - counter++ - printed_paper.name = text("MR-[] '[]'", GLOB.data_core.medicalPrintCount, active1.fields["name"]) - else - final_paper_text += "Medical Record Lost!
" - printed_paper.name = text("MR-[] '[]'", GLOB.data_core.medicalPrintCount, "Record Lost") - final_paper_text += "" - printed_paper.add_raw_text(final_paper_text) - printed_paper.update_appearance() - printing = null - - add_fingerprint(usr) - updateUsrDialog() - return - -/obj/machinery/computer/med_data/emp_act(severity) - . = ..() - if(!(machine_stat & (BROKEN|NOPOWER)) && !(. & EMP_PROTECT_SELF)) - for(var/datum/data/record/R in GLOB.data_core.medical) - if(prob(10/severity)) - switch(rand(1,6)) - if(1) - if(prob(10)) - R.fields["name"] = random_unique_lizard_name(R.fields["gender"],1) - else - R.fields["name"] = random_unique_name(R.fields["gender"],1) - if(2) - R.fields["gender"] = pick("Male", "Female", "Other") - if(3) - R.fields["age"] = rand(AGE_MIN, AGE_MAX) - if(4) - R.fields["blood_type"] = random_blood_type() - if(5) - R.fields["p_stat"] = pick("*Unconscious*", "Active", "Physically Unfit") - if(6) - R.fields["m_stat"] = pick("*Insane*", "*Unstable*", "*Watch*", "Stable") - continue - - else if(prob(1)) - qdel(R) - continue - -/obj/machinery/computer/med_data/proc/canUseMedicalRecordsConsole(mob/user, message = 1, record1, record2) - if(user && message && authenticated) - if(user.canUseTopic(src, !issilicon(user))) - if(!record1 || record1 == active1) - if(!record2 || record2 == active2) - return TRUE - return FALSE - /obj/machinery/computer/med_data/laptop name = "medical laptop" desc = "A cheap Nanotrasen medical laptop, it functions as a medical records computer. It's bolted to the table." @@ -582,3 +18,119 @@ icon_screen = "medlaptop" icon_keyboard = "laptop_key" pass_flags = PASSTABLE + +/obj/machinery/computer/med_data/attacked_by(obj/item/attacking_item, mob/living/user) + . = ..() + if(!istype(attacking_item, /obj/item/photo)) + return + insert_new_record(user, attacking_item) + +/obj/machinery/computer/med_data/ui_interact(mob/user, datum/tgui/ui) + . = ..() + if(.) + return + ui = SStgui.try_update_ui(user, src, ui) + if (!ui) + create_character_preview_view(user) + ui = new(user, src, "MedicalRecords") + ui.set_autoupdate(FALSE) + ui.open() + +/obj/machinery/computer/med_data/ui_data(mob/user) + var/list/data = list() + + var/has_access = authenticated && isliving(user) + data["authenticated"] = authenticated + if(!has_access) + return data + + data["assigned_view"] = "preview_[user.ckey]_[REF(src)]_records" + + var/list/records = list() + for(var/datum/record/crew/target in GLOB.manifest.general) + var/list/notes = list() + for(var/datum/medical_note/note in target.medical_notes) + notes += list(list( + author = note.author, + content = note.content, + note_ref = REF(note), + time = note.time, + )) + + records += list(list( + age = target.age, + blood_type = target.blood_type, + crew_ref = REF(target), + dna = target.dna_string, + gender = target.gender, + major_disabilities = target.major_disabilities_desc, + minor_disabilities = target.minor_disabilities_desc, + name = target.name, + notes = notes, + quirk_notes = target.quirk_notes, + rank = target.rank, + species = target.species, + )) + + data["records"] = records + + return data + +/obj/machinery/computer/med_data/ui_act(action, list/params, datum/tgui/ui) + . = ..() + if(.) + return + + var/datum/record/crew/target + if(params["crew_ref"]) + target = locate(params["crew_ref"]) in GLOB.manifest.general + if(!target) + return FALSE + + switch(action) + if("add_note") + if(!params["content"]) + return FALSE + var/content = trim(params["content"], MAX_MESSAGE_LEN) + + var/datum/medical_note/new_note = new(usr.name, content) + while(length(target.medical_notes) > 2) + target.medical_notes.Cut(1, 2) + + target.medical_notes += new_note + + return TRUE + + if("delete_note") + var/datum/medical_note/old_note = locate(params["note_ref"]) in target.medical_notes + if(!old_note) + return FALSE + + target.medical_notes -= old_note + qdel(old_note) + + return TRUE + + return FALSE + +/// Deletes medical information from a record. +/obj/machinery/computer/med_data/expunge_record_info(datum/record/crew/target) + if(!target) + return FALSE + + target.age = 18 + target.blood_type = pick(list("A+", "A-", "B+", "B-", "O+", "O-", "AB+", "AB-")) + target.dna_string = "Unknown" + target.gender = "Unknown" + target.major_disabilities = "" + target.major_disabilities_desc = "" + target.medical_notes.Cut() + target.minor_disabilities = "" + target.minor_disabilities_desc = "" + target.name = "Unknown" + target.quirk_notes = "" + target.rank = "Unknown" + target.species = "Unknown" + target.trim = "Unknown" + + return TRUE diff --git a/code/game/machinery/computer/prisoner/gulag_teleporter.dm b/code/game/machinery/computer/prisoner/gulag_teleporter.dm index acdb74f9442..45124eefeee 100644 --- a/code/game/machinery/computer/prisoner/gulag_teleporter.dm +++ b/code/game/machinery/computer/prisoner/gulag_teleporter.dm @@ -12,7 +12,7 @@ var/obj/machinery/gulag_teleporter/teleporter = null var/obj/structure/gulag_beacon/beacon = null var/mob/living/carbon/human/prisoner = null - var/datum/data/record/temporary_record = null + var/datum/record/crew/temporary_record = null /obj/machinery/computer/prisoner/gulag_teleporter_computer/Initialize(mapload) @@ -37,12 +37,11 @@ prisoner_list["name"] = prisoner.real_name if(contained_id) can_teleport = TRUE - if(!isnull(GLOB.data_core.general)) - for(var/r in GLOB.data_core.security) - var/datum/data/record/R = r - if(R.fields["name"] == prisoner_list["name"]) - temporary_record = R - prisoner_list["crimstat"] = temporary_record.fields["criminal"] + if(!isnull(GLOB.manifest.general)) + for(var/datum/record/crew/record as anything in GLOB.manifest.general) + if(record.name == prisoner_list["name"]) + temporary_record = record + prisoner_list["crimstat"] = temporary_record.wanted_status data["prisoner"] = prisoner_list diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm index c7ff56e17a5..503f4ecec16 100644 --- a/code/game/machinery/computer/security.dm +++ b/code/game/machinery/computer/security.dm @@ -1,3 +1,8 @@ +#define COMP_SECURITY_ARREST_AMOUNT_TO_FLAG 10 +#define PRINTOUT_MISSING "Missing" +#define PRINTOUT_RAPSHEET "Rapsheet" +#define PRINTOUT_WANTED "Wanted" + /obj/machinery/computer/secure_data//TODO:SANITY name = "security records console" desc = "Used to view and edit personnel's security records." @@ -6,18 +11,24 @@ req_one_access = list(ACCESS_SECURITY, ACCESS_HOP) circuit = /obj/item/circuitboard/computer/secure_data light_color = COLOR_SOFT_RED - var/rank = null - var/screen = null - var/datum/data/record/active1 = null - var/datum/data/record/active2 = null - var/temp = null - var/printing = null - var/can_change_id = 0 - var/list/Perp - var/tempname = null - //Sorting Variables - var/sortBy = "name" - var/order = 1 // -1 = Descending - 1 = Ascending + /// The current state of the printer + var/printing = FALSE + +/obj/machinery/computer/secure_data/syndie + icon_keyboard = "syndie_key" + req_one_access = list(ACCESS_SYNDICATE) + +/obj/machinery/computer/secure_data/laptop + name = "security laptop" + desc = "A cheap Nanotrasen security laptop, it functions as a security records console. It's bolted to the table." + icon_state = "laptop" + icon_screen = "seclaptop" + icon_keyboard = "laptop_key" + pass_flags = PASSTABLE + +/obj/machinery/computer/secure_data/laptop/syndie + desc = "A cheap, jailbroken security laptop. It functions as a security records console. It's bolted to the table." + req_one_access = list(ACCESS_SYNDICATE) /obj/machinery/computer/secure_data/Initialize(mapload, obj/item/circuitboard/C) . = ..() @@ -26,14 +37,273 @@ /obj/item/circuit_component/arrest_console_arrest, )) -#define COMP_STATE_ARREST "*Arrest*" -#define COMP_STATE_PRISONER "Incarcerated" -#define COMP_STATE_SUSPECTED "Suspected" -#define COMP_STATE_PAROL "Paroled" -#define COMP_STATE_DISCHARGED "Discharged" -#define COMP_STATE_NONE "None" -#define COMP_SECURITY_ARREST_AMOUNT_TO_FLAG 10 +/obj/machinery/computer/secure_data/emp_act(severity) + . = ..() + if(machine_stat & (BROKEN|NOPOWER) || . & EMP_PROTECT_SELF) + return + + for(var/datum/record/crew/target in GLOB.manifest.general) + if(prob(10/severity)) + switch(rand(1,5)) + if(1) + if(prob(10)) + target.name = "[pick(lizard_name(MALE),lizard_name(FEMALE))]" + else + target.name = "[pick(pick(GLOB.first_names_male), pick(GLOB.first_names_female))] [pick(GLOB.last_names)]" + if(2) + target.gender = pick("Male", "Female", "Other") + if(3) + target.age = rand(5, 85) + if(4) + target.wanted_status = pick(WANTED_STATUSES()) + if(5) + target.species = pick(get_selectable_species()) + continue + + else if(prob(1)) + qdel(target) + continue + +/obj/machinery/computer/secure_data/attacked_by(obj/item/attacking_item, mob/living/user) + . = ..() + if(!istype(attacking_item, /obj/item/photo)) + return + insert_new_record(user, attacking_item) + +/obj/machinery/computer/secure_data/ui_interact(mob/user, datum/tgui/ui) + . = ..() + if(.) + return + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + character_preview_view = create_character_preview_view(user) + ui = new(user, src, "SecurityRecords") + ui.set_autoupdate(FALSE) + ui.open() + +/obj/machinery/computer/secure_data/ui_data(mob/user) + var/list/data = list() + + var/has_access = authenticated && isliving(user) + data["authenticated"] = has_access + if(!has_access) + return data + + data["assigned_view"] = "preview_[user.ckey]_[REF(src)]_records" + data["available_statuses"] = WANTED_STATUSES() + + var/list/records = list() + for(var/datum/record/crew/target in GLOB.manifest.general) + var/list/citations = list() + for(var/datum/crime/citation/warrant in target.citations) + citations += list(list( + author = warrant.author, + crime_ref = REF(warrant), + details = warrant.details, + fine = warrant.fine, + name = warrant.name, + paid = warrant.paid, + time = warrant.time, + )) + + var/list/crimes = list() + for(var/datum/crime/crime in target.crimes) + crimes += list(list( + author = crime.author, + crime_ref = REF(crime), + details = crime.details, + name = crime.name, + time = crime.time, + )) + + records += list(list( + age = target.age, + citations = citations, + crew_ref = REF(target), + crimes = crimes, + fingerprint = target.fingerprint, + gender = target.gender, + name = target.name, + note = target.security_note, + rank = target.rank, + species = target.species, + wanted_status = target.wanted_status, + )) + + data["records"] = records + + return data + +/obj/machinery/computer/secure_data/ui_act(action, list/params, datum/tgui/ui) + . = ..() + if(.) + return + + var/datum/record/crew/target + if(params["crew_ref"]) + target = locate(params["crew_ref"]) in GLOB.manifest.general + if(!target) + return FALSE + + switch(action) + if("add_crime") + add_crime(usr, target, params) + return TRUE + + if("delete_crime") + delete_crime(target, params) + return TRUE + + if("print_record") + print_record(usr, target, params) + return TRUE + + if("set_note") + var/note = params["note"] + target.security_note = trim(note, MAX_MESSAGE_LEN) + return TRUE + + if("set_wanted") + var/wanted_status = params["status"] + if(!wanted_status || !(wanted_status in WANTED_STATUSES())) + return FALSE + target.wanted_status = wanted_status + + return TRUE + + return FALSE + +/// Handles adding a crime to a particular record. +/obj/machinery/computer/secure_data/proc/add_crime(mob/user, datum/record/crew/target, list/params) + var/input_name = trim(params["name"], 24) + if(!input_name) + to_chat(usr, span_warning("You must enter a name for the crime.")) + playsound(src, 'sound/machines/terminal_error.ogg', 100, TRUE) + return FALSE + + var/max = CONFIG_GET(number/maxfine) + if(params["fine"] > max) + to_chat(usr, span_warning("The maximum fine is [max] credits.")) + playsound(src, 'sound/machines/terminal_error.ogg', 100, TRUE) + return FALSE + + var/input_details + if(params["details"]) + input_details = trim(params["details"], MAX_MESSAGE_LEN) + + if(params["fine"] == 0) + var/datum/crime/new_crime = new(name = input_name, details = input_details, author = usr) + target.crimes += new_crime + target.wanted_status = WANTED_ARREST + investigate_log("New Crime: [input_name] | Added to [target.name] by [key_name(user)]", INVESTIGATE_RECORDS) + return TRUE + + var/datum/crime/citation/new_citation = new(name = input_name, details = input_details, author = usr, fine = params["fine"]) + + target.citations += new_citation + new_citation.alert_owner(user, src, target.name, "You have been issued a [params["fine"]]cr citation for [input_name]. Fines are payable at Security.") + investigate_log("New Citation: [input_name] Fine: [params["fine"]] | Added to [target.name] by [key_name(user)]", INVESTIGATE_RECORDS) + SSblackbox.ReportCitation(REF(new_citation), user.ckey, user.real_name, target.name, input_name, params["fine"]) + + return TRUE + +/// Deletes a crime or citation from the chosen record. +/obj/machinery/computer/secure_data/proc/delete_crime(datum/record/crew/target, list/params) + var/datum/crime/incident = locate(params["crime_ref"]) in target.crimes + if(incident) + target.crimes -= incident + qdel(incident) + return TRUE + + var/datum/crime/citation/warrant = locate(params["crime_ref"]) in target.citations + if(warrant) + target.citations -= warrant + qdel(warrant) + return TRUE + + return FALSE + +/// Deletes security information from a record. +/obj/machinery/computer/secure_data/expunge_record_info(datum/record/crew/target) + target.age = 18 + target.citations.Cut() + target.crimes.Cut() + target.fingerprint = "Unknown" + target.gender = "Unknown" + target.name = "Unknown" + target.rank = "Unknown" + target.security_note = "None" + target.species = "Unknown" + target.trim = "Unknown" + target.wanted_status = WANTED_NONE + + return TRUE + +/// Finishes printing, resets the printer. +/obj/machinery/computer/secure_data/proc/print_finish(obj/item/printable) + printing = FALSE + playsound(src, 'sound/machines/terminal_eject.ogg', 100, TRUE) + printable.forceMove(loc) + + return TRUE + +/// Handles printing records via UI. Takes the params from UI_act. +/obj/machinery/computer/secure_data/proc/print_record(mob/user, datum/record/crew/target, list/params) + if(printing) + balloon_alert(usr, "printer busy") + playsound(src, 'sound/machines/terminal_error.ogg', 100, TRUE) + return FALSE + + printing = TRUE + balloon_alert(user, "printing") + playsound(src, 'sound/machines/printer.ogg', 100, TRUE) + + var/obj/item/printable + var/input_alias = trim(params["alias"], MAX_NAME_LEN) || target.name + var/input_description = trim(params["desc"], MAX_BROADCAST_LEN) || "No further details." + var/input_header = trim(params["head"], 8) || capitalize(params["type"]) + + switch(params["type"]) + if("missing") + var/obj/item/photo/mugshot = target.get_front_photo() + var/obj/item/poster/wanted/missing/missing_poster = new(null, mugshot.picture.picture_image, input_alias, input_description, input_header) + + printable = missing_poster + + if("wanted") + var/list/crimes = target.crimes + if(!length(crimes)) + balloon_alert(user, "no crimes") + return FALSE + + input_description += "\n\nWANTED FOR:" + for(var/datum/crime/incident in crimes) + input_description += "\n [incident.name]\n" + input_description += "Details: [incident.details]\n" + + var/obj/item/photo/mugshot = target.get_front_photo() + var/obj/item/poster/wanted/wanted_poster = new(null, mugshot.picture.picture_image, input_alias, input_description, input_header) + + printable = wanted_poster + + if("rapsheet") + var/list/crimes = target.crimes + if(!length(crimes)) + balloon_alert(user, "no crimes") + return FALSE + + var/obj/item/paper/rapsheet = target.get_rapsheet(input_alias, input_header, input_description) + printable = rapsheet + + addtimer(CALLBACK(src, PROC_REF(print_finish), printable), 2 SECONDS, TIMER_UNIQUE | TIMER_STOPPABLE) + + return TRUE + + +/** + * Security circuit component + */ /obj/item/circuit_component/arrest_console_data display_name = "Security Records Data" desc = "Outputs the security records data, where it can then be filtered with a Select Query component" @@ -73,35 +343,30 @@ "fingerprint", )) - /obj/item/circuit_component/arrest_console_data/input_received(datum/port/input/port) if(!attached_console || !attached_console.authenticated) on_fail.set_output(COMPONENT_SIGNAL) return - if(isnull(GLOB.data_core.general)) + if(isnull(GLOB.manifest.general)) on_fail.set_output(COMPONENT_SIGNAL) return var/list/new_table = list() - for(var/datum/data/record/player_record as anything in GLOB.data_core.general) + for(var/datum/record/crew/player_record as anything in GLOB.manifest.general) var/list/entry = list() - var/datum/data/record/player_security_record = find_record("id", player_record.fields["id"], GLOB.data_core.security) - if(player_security_record) - entry["arrest_status"] = player_security_record.fields["criminal"] - entry["security_record"] = player_security_record - entry["name"] = player_record.fields["name"] - entry["id"] = player_record.fields["id"] - entry["rank"] = player_record.fields["rank"] - entry["gender"] = player_record.fields["gender"] - entry["age"] = player_record.fields["age"] - entry["species"] = player_record.fields["species"] - entry["fingerprint"] = player_record.fields["fingerprint"] + entry["age"] = player_record.age + entry["arrest_status"] = player_record.wanted_status + entry["fingerprint"] = player_record.fingerprint + entry["gender"] = player_record.gender + entry["name"] = player_record.name + entry["rank"] = player_record.rank + entry["record"] = REF(player_record) + entry["species"] = player_record.species new_table += list(entry) records.set_output(new_table) - /obj/item/circuit_component/arrest_console_arrest display_name = "Security Records Set Status" desc = "Receives a table to use to set people's arrest status. Table should be from the security records data component. If New Status port isn't set, the status will be decided by the options." @@ -131,15 +396,10 @@ return ..() /obj/item/circuit_component/arrest_console_arrest/populate_options() - var/static/list/component_options = list( - COMP_STATE_ARREST, - COMP_STATE_PRISONER, - COMP_STATE_SUSPECTED, - COMP_STATE_PAROL, - COMP_STATE_DISCHARGED, - COMP_STATE_NONE, - ) - new_status = add_option_port("Arrest Options", component_options) + if(!attached_console) + return + var/list/available_statuses = WANTED_STATUSES() + new_status = add_option_port("Arrest Options", available_statuses) /obj/item/circuit_component/arrest_console_arrest/populate_ports() targets = add_input_port("Targets", PORT_TYPE_TABLE) @@ -162,14 +422,14 @@ var/successful_set = 0 var/list/names_of_entries = list() for(var/list/target in target_table) - var/datum/data/record/sec_record = target["security_record"] + var/datum/record/crew/sec_record = target["security_record"] if(!sec_record) continue - if(sec_record.fields["criminal"] != status_to_set) + if(sec_record.wanted_status != status_to_set) successful_set++ names_of_entries += target["name"] - sec_record.fields["criminal"] = status_to_set + sec_record.wanted_status = status_to_set if(successful_set > 0) @@ -179,851 +439,7 @@ for(var/mob/living/carbon/human/human as anything in GLOB.human_list) human.sec_hud_set_security_status() -#undef COMP_STATE_ARREST -#undef COMP_STATE_PRISONER -#undef COMP_STATE_SUSPECTED -#undef COMP_STATE_PAROL -#undef COMP_STATE_DISCHARGED -#undef COMP_STATE_NONE #undef COMP_SECURITY_ARREST_AMOUNT_TO_FLAG - -/obj/machinery/computer/secure_data/syndie - icon_keyboard = "syndie_key" - req_one_access = list(ACCESS_SYNDICATE) - -/obj/machinery/computer/secure_data/laptop - name = "security laptop" - desc = "A cheap Nanotrasen security laptop, it functions as a security records console. It's bolted to the table." - icon_state = "laptop" - icon_screen = "seclaptop" - icon_keyboard = "laptop_key" - pass_flags = PASSTABLE - -/obj/machinery/computer/secure_data/laptop/syndie - desc = "A cheap, jailbroken security laptop. It functions as a security records console. It's bolted to the table." - req_one_access = list(ACCESS_SYNDICATE) - -//Someone needs to break down the dat += into chunks instead of long ass lines. -/obj/machinery/computer/secure_data/ui_interact(mob/user) - . = ..() - if(isliving(user)) - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) - if(src.z > 6) - to_chat(user, "[span_boldannounce("Unable to establish a connection")]: \black You're too far away from the station!") - return - var/dat - - if(temp) - dat = "[temp]

Clear Screen" - else - dat = "" - if(authenticated) - switch(screen) - if(1) - - //body tag start + onload and onkeypress (onkeyup) javascript event calls - dat += "" - //search bar javascript - dat += {" - - - - - - - - "} - dat += {" -

"} - dat += "New Record
" - //search bar - dat += {" - - - - -
- Search: -
- "} - dat += {" -

- - - - -
Records:
- - - - - - - - - -"} - if(!isnull(GLOB.data_core.general)) - for(var/datum/data/record/R in sort_record(GLOB.data_core.general, sortBy, order)) - var/crimstat = "" - for(var/datum/data/record/E in GLOB.data_core.security) - if((E.fields["name"] == R.fields["name"]) && (E.fields["id"] == R.fields["id"])) - crimstat = E.fields["criminal"] - var/background - switch(crimstat) - if("*Arrest*") - background = "'background-color:#990000;'" - if("Incarcerated") - background = "'background-color:#CD6500;'" - if("Suspected") - background = "'background-color:#CD6500;'" - if("Paroled") - background = "'background-color:#CD6500;'" - if("Discharged") - background = "'background-color:#006699;'" - if("None") - background = "'background-color:#4F7529;'" - if("") - background = "''" //"'background-color:#FFFFFF;'" - crimstat = "No Record." - dat += "" - dat += text("", R.fields["name"], R.fields["id"], R.fields["rank"], R.fields["fingerprint"], R.fields["name"]) - dat += text("", R.fields["id"]) - dat += text("", R.fields["rank"]) - dat += text("", R.fields["fingerprint"]) - dat += text("", crimstat) - dat += {" -
NameIDRankFingerprintsCriminal Status
[][][][][]
- -
"} - dat += "Record Maintenance

" - dat += "{Log Out}" - if(2) - dat += "Records Maintenance
" - dat += "
Delete All Records

Back" - if(3) - dat += "Security Record
" - if(istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1)) - var/front_photo = active1.get_front_photo() - if(istype(front_photo, /obj/item/photo)) - var/obj/item/photo/photo_front = front_photo - user << browse_rsc(photo_front.picture.picture_image, "photo_front") - var/side_photo = active1.get_side_photo() - if(istype(side_photo, /obj/item/photo)) - var/obj/item/photo/photo_side = side_photo - user << browse_rsc(photo_side.picture.picture_image, "photo_side") - dat += {" -
- - - - "} - dat += "" - dat += {" - - - - -
Name: [active1.fields["name"]] 
ID: [active1.fields["id"]] 
Gender: [active1.fields["gender"]] 
Age: [active1.fields["age"]] 
Species: [active1.fields["species"]] 
Rank: [active1.fields["rank"]] 
Initial Rank:[active1.fields["initial_rank"]]
Fingerprint: [active1.fields["fingerprint"]] 
Physical Status: [active1.fields["p_stat"]] 
Mental Status: [active1.fields["m_stat"]] 
-

- Print photo
- Update front photo

- Print photo
- Update side photo
-
"} - else - dat += "
General Record Lost!
" - if((istype(active2, /datum/data/record) && GLOB.data_core.security.Find(active2))) - dat += "Security Data" - dat += "
Criminal Status: [active2.fields["criminal"]]" - dat += "

Citations: Add New" - - dat +={" - - - - - - - - "} - for(var/datum/data/crime/c in active2.fields["citation"]) - var/owed = c.fine - c.paid - dat += {" - - "} - if(owed > 0) - dat += "" - else - dat += "" - dat += {" - "} - dat += "
CrimeFineAuthorTime AddedAmount DueDel
[c.crimeName][c.fine] cr[c.author][c.time][owed] cr \[Pay\]All Paid Off - \[X\] -
" - - dat += "

Crimes: Add New" - - - dat +={" - - - - - - - "} - for(var/datum/data/crime/c in active2.fields["crim"]) - dat += "" - if(!c.crimeDetails) - dat += "" - else - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "
CrimeDetailsAuthorTime AddedDel
[c.crimeName]\[+\][c.crimeDetails][c.author][c.time]\[X\]
" - - dat += "
\nImportant Notes:
\n\t [active2.fields["notes"]] " - dat += "

Comments/Log
" - var/counter = 1 - while(active2.fields[text("com_[]", counter)]) - dat += (active2.fields[text("com_[]", counter)] + "
") - if(active2.fields[text("com_[]", counter)] != "Deleted") - dat += text("Delete Entry

", counter) - counter++ - dat += "Add Entry

" - dat += "Delete Record (Security Only)
" - else - dat += "Security Record Lost!
" - dat += "New Security Record

" - dat += "Delete Record (ALL)
Print Record
Print Wanted Poster
Print Missing Persons Poster
Back

" - dat += "{Log Out}" - else - else - dat += "{Log In}" - var/datum/browser/popup = new(user, "secure_rec", "Security Records Console", 600, 400) - popup.set_content(dat) - popup.open() - return - -/*Revised /N -I can't be bothered to look more of the actual code outside of switch but that probably needs revising too. -What a mess.*/ -/obj/machinery/computer/secure_data/Topic(href, href_list) - . = ..() - if(.) - return . - if(!( GLOB.data_core.general.Find(active1) )) - active1 = null - if(!( GLOB.data_core.security.Find(active2) )) - active2 = null - if(!authenticated && href_list["choice"] != "Log In") // logging in is the only action you can do if not logged in - return - if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)) || issilicon(usr) || isAdminGhostAI(usr)) - usr.set_machine(src) - switch(href_list["choice"]) -// SORTING! - if("Sorting") - // Reverse the order if clicked twice - if(sortBy == href_list["sort"]) - if(order == 1) - order = -1 - else - order = 1 - else - // New sorting order! - sortBy = href_list["sort"] - order = initial(order) -//BASIC FUNCTIONS - if("Clear Screen") - temp = null - - if("Return") - screen = 1 - active1 = null - active2 = null - - if("Log Out") - authenticated = null - screen = null - active1 = null - active2 = null - playsound(src, 'sound/machines/terminal_off.ogg', 50, FALSE) - - if("Log In") - var/obj/item/card/id/I - if(isliving(usr)) - var/mob/living/L = usr - I = L.get_idcard(TRUE) - if(issilicon(usr)) - active1 = null - active2 = null - authenticated = usr.name - rank = "AI" - screen = 1 - else if(isAdminGhostAI(usr)) - active1 = null - active2 = null - authenticated = usr.client.holder.admin_signature - rank = "Central Command" - screen = 1 - else if(I && check_access(I)) - active1 = null - active2 = null - authenticated = (I.registered_name ? I.registered_name : "Unknown") - rank = I.assignment - screen = 1 - else - to_chat(usr, span_danger("Unauthorized Access.")) - playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE) - -//RECORD FUNCTIONS - if("Record Maintenance") - screen = 2 - active1 = null - active2 = null - - if("Browse Record") - var/datum/data/record/R = locate(href_list["d_rec"]) in GLOB.data_core.general - if(!R) - temp = "Record Not Found!" - else - active1 = active2 = R - for(var/datum/data/record/E in GLOB.data_core.security) - if((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) - active2 = E - screen = 3 - - if("Pay") - for(var/datum/data/crime/p in active2.fields["citation"]) - if(p.dataId == text2num(href_list["cdataid"])) - var/obj/item/holochip/C = usr.is_holding_item_of_type(/obj/item/holochip) - if(C && istype(C)) - var/pay = C.get_item_credit_value() - if(!pay) - to_chat(usr, span_warning("[C] doesn't seem to be worth anything!")) - else - var/diff = p.fine - p.paid - GLOB.data_core.payCitation(active2.fields["id"], text2num(href_list["cdataid"]), pay) - to_chat(usr, span_notice("You have paid [pay] credit\s towards your fine.")) - if (pay == diff || pay > diff || pay >= diff) - investigate_log("Citation Paid off: [p.crimeName] Fine: [p.fine] | Paid off by [key_name(usr)]", INVESTIGATE_RECORDS) - to_chat(usr, span_notice("The fine has been paid in full.")) - SSblackbox.ReportCitation(text2num(href_list["cdataid"]),"","","","", 0, pay) - qdel(C) - playsound(src, SFX_TERMINAL_TYPE, 25, FALSE) - else - to_chat(usr, span_warning("Fines can only be paid with holochips!")) - - if("Print Record") - if(!( printing )) - printing = TRUE - playsound(src, 'sound/items/poster_being_created.ogg', 100, TRUE) - sleep(3 SECONDS) - print_security_record(active1, active2, loc) - printing = FALSE - if("Print Poster") - if(!( printing )) - var/wanted_name = tgui_input_text(usr, "Enter an alias for the criminal", "Print Wanted Poster", active1.fields["name"]) - if(wanted_name) - var/default_description = "A poster declaring [wanted_name] to be a dangerous individual, wanted by Nanotrasen. Report any sightings to security immediately." - var/list/crimes = active2.fields["crim"] - if(length(crimes)) - default_description += "\n[wanted_name] is wanted for the following crimes:\n" - for(var/datum/data/crime/c in active2.fields["crim"]) - default_description += "\n[c.crimeName]\n" - default_description += "[c.crimeDetails]\n" - - var/headerText = tgui_input_text(usr, "Enter a poster heading", "Print Wanted Poster", "WANTED", 7) - - var/info = tgui_input_text(usr, "Input a description for the poster", "Print Wanted Poster", default_description) - if(info) - playsound(loc, 'sound/items/poster_being_created.ogg', 100, TRUE) - printing = 1 - sleep(3 SECONDS) - if((istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1)))//make sure the record still exists. - var/obj/item/photo/photo = active1.get_front_photo() - new /obj/item/poster/wanted(loc, photo.picture.picture_image, wanted_name, info, headerText) - printing = 0 - if("Print Missing") - if(!( printing )) - var/missing_name = tgui_input_text(usr, "Enter an alias for the missing person", "Print Missing Persons Poster", active1.fields["name"]) - if(missing_name) - var/default_description = "A poster declaring [missing_name] to be a missing individual, missed by Nanotrasen. Report any sightings to security immediately." - - var/headerText = tgui_input_text(usr, "Enter a poster heading", "Print Missing Persons Poster", "MISSING", 7) - - var/info = tgui_input_text(usr, "Input a description for the poster", "Print Missing Persons Poster", default_description) - if(info) - playsound(loc, 'sound/items/poster_being_created.ogg', 100, TRUE) - printing = 1 - sleep(3 SECONDS) - if((istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1)))//make sure the record still exists. - var/obj/item/photo/photo = active1.get_front_photo() - new /obj/item/poster/wanted/missing(loc, photo.picture.picture_image, missing_name, info, headerText) - printing = 0 - -//RECORD DELETE - if("Delete All Records") - temp = "" - temp += "Are you sure you wish to delete all Security records?
" - temp += "Yes
" - temp += "No" - - if("Purge All Records") - investigate_log("[key_name(usr)] has purged all the security records.", INVESTIGATE_RECORDS) - for(var/datum/data/record/R in GLOB.data_core.security) - qdel(R) - GLOB.data_core.security.Cut() - temp = "All Security records deleted." - - if("Add Entry") - if(!( istype(active2, /datum/data/record) )) - return - var/a2 = active2 - var/t1 = tgui_input_text(usr, "Add a comment", "Security Records") - if(!canUseSecurityRecordsConsole(usr, t1, null, a2)) - return - var/counter = 1 - while(active2.fields[text("com_[]", counter)]) - counter++ - active2.fields[text("com_[]", counter)] = text("Made by [] ([]) on [] [], []
[]", src.authenticated, src.rank, station_time_timestamp(), time2text(world.realtime, "MMM DD"), CURRENT_STATION_YEAR, t1) - - if("Delete Record (ALL)") - if(active1) - temp = "
Are you sure you wish to delete the record (ALL)?
" - temp += "Yes
" - temp += "No" - - if("Delete Record (Security)") - if(active2) - temp = "
Are you sure you wish to delete the record (Security Portion Only)?
" - temp += "Yes
" - temp += "No" - - if("Delete Entry") - if((istype(active2, /datum/data/record) && active2.fields[text("com_[]", href_list["del_c"])])) - active2.fields[text("com_[]", href_list["del_c"])] = "Deleted" -//RECORD CREATE - if("New Record (Security)") - if((istype(active1, /datum/data/record) && !( istype(active2, /datum/data/record) ))) - var/datum/data/record/R = new /datum/data/record() - R.fields["name"] = active1.fields["name"] - R.fields["id"] = active1.fields["id"] - R.name = text("Security Record #[]", R.fields["id"]) - R.fields["criminal"] = "None" - R.fields["crim"] = list() - R.fields["notes"] = "No notes." - GLOB.data_core.security += R - active2 = R - screen = 3 - - if("New Record (General)") - //General Record - var/datum/data/record/G = new /datum/data/record() - G.fields["name"] = "New Record" - G.fields["id"] = "[num2hex(rand(1, 1.6777215E7), 6)]" - G.fields["rank"] = "Unassigned" - G.fields["trim"] = "Unassigned" - G.fields["initial_rank"] = "Unassigned" - G.fields["gender"] = "Male" - G.fields["age"] = "Unknown" - G.fields["species"] = "Human" - G.fields["photo_front"] = new /icon() - G.fields["photo_side"] = new /icon() - G.fields["fingerprint"] = "?????" - G.fields["p_stat"] = "Active" - G.fields["m_stat"] = "Stable" - GLOB.data_core.general += G - active1 = G - - //Security Record - var/datum/data/record/R = new /datum/data/record() - R.fields["name"] = active1.fields["name"] - R.fields["id"] = active1.fields["id"] - R.name = text("Security Record #[]", R.fields["id"]) - R.fields["criminal"] = "None" - R.fields["crim"] = list() - R.fields["notes"] = "No notes." - GLOB.data_core.security += R - active2 = R - - //Medical Record - var/datum/data/record/M = new /datum/data/record() - M.fields["id"] = active1.fields["id"] - M.fields["name"] = active1.fields["name"] - M.fields["blood_type"] = "?" - M.fields["b_dna"] = "?????" - M.fields["mi_dis"] = "None" - M.fields["mi_dis_d"] = "No minor disabilities have been declared." - M.fields["ma_dis"] = "None" - M.fields["ma_dis_d"] = "No major disabilities have been diagnosed." - M.fields["alg"] = "None" - M.fields["alg_d"] = "No allergies have been detected in this patient." - M.fields["cdi"] = "None" - M.fields["cdi_d"] = "No diseases have been diagnosed at the moment." - M.fields["notes"] = "No notes." - GLOB.data_core.medical += M - - - -//FIELD FUNCTIONS - if("Edit Field") - var/a1 = active1 - var/a2 = active2 - - switch(href_list["field"]) - if("name") - if(istype(active1, /datum/data/record) || istype(active2, /datum/data/record)) - var/t1 = tgui_input_text(usr, "Input a name", "Security Records", active1.fields["name"]) - if(!canUseSecurityRecordsConsole(usr, t1, a1)) - return - if(istype(active1, /datum/data/record)) - active1.fields["name"] = t1 - if(istype(active2, /datum/data/record)) - active2.fields["name"] = t1 - if("id") - if(istype(active2, /datum/data/record) || istype(active1, /datum/data/record)) - var/t1 = tgui_input_text(usr, "Input an id", "Security Records", active1.fields["id"]) - if(!canUseSecurityRecordsConsole(usr, t1, a1)) - return - if(istype(active1, /datum/data/record)) - active1.fields["id"] = t1 - if(istype(active2, /datum/data/record)) - active2.fields["id"] = t1 - if("fingerprint") - if(istype(active1, /datum/data/record)) - var/t1 = tgui_input_text(usr, "Input a fingerprint hash", "Security Records", active1.fields["fingerprint"]) - if(!canUseSecurityRecordsConsole(usr, t1, a1)) - return - active1.fields["fingerprint"] = t1 - if("gender") - if(istype(active1, /datum/data/record)) - if(active1.fields["gender"] == "Male") - active1.fields["gender"] = "Female" - else if(active1.fields["gender"] == "Female") - active1.fields["gender"] = "Other" - else - active1.fields["gender"] = "Male" - if("age") - if(istype(active1, /datum/data/record)) - var/t1 = tgui_input_number(usr, "Input age", "Security records", active1.fields["age"], AGE_MAX, AGE_MIN) - if (!t1) - return - if(!canUseSecurityRecordsConsole(usr, "age", a1)) - return - active1.fields["age"] = t1 - if("species") - if(istype(active1, /datum/data/record)) - var/t1 = tgui_input_list(usr, "Select a species", "Species Selection", get_selectable_species()) - if(isnull(t1)) - return - if(!canUseSecurityRecordsConsole(usr, t1, a1)) - return - active1.fields["species"] = t1 - if("show_photo_front") - if(active1) - var/front_photo = active1.get_front_photo() - if(istype(front_photo, /obj/item/photo)) - var/obj/item/photo/photo = front_photo - photo.show(usr) - if("upd_photo_front") - var/obj/item/photo/photo = get_photo(usr) - if(photo) - qdel(active1.fields["photo_front"]) - //Lets center it to a 32x32. - var/icon/I = photo.picture.picture_image - var/w = I.Width() - var/h = I.Height() - var/dw = w - 32 - var/dh = w - 32 - I.Crop(dw/2, dh/2, w - dw/2, h - dh/2) - active1.fields["photo_front"] = photo - if("print_photo_front") - if(active1) - var/front_photo = active1.get_front_photo() - if(istype(front_photo, /obj/item/photo)) - var/obj/item/photo/photo_front = front_photo - print_photo(photo_front.picture.picture_image, active1.fields["name"]) - if("show_photo_side") - if(active1) - var/side_photo = active1.get_side_photo() - if(istype(side_photo, /obj/item/photo)) - var/obj/item/photo/photo = side_photo - photo.show(usr) - if("upd_photo_side") - var/obj/item/photo/photo = get_photo(usr) - if(photo) - qdel(active1.fields["photo_side"]) - //Lets center it to a 32x32. - var/icon/I = photo.picture.picture_image - var/w = I.Width() - var/h = I.Height() - var/dw = w - 32 - var/dh = w - 32 - I.Crop(dw/2, dh/2, w - dw/2, h - dh/2) - active1.fields["photo_side"] = photo - if("print_photo_side") - if(active1) - var/side_photo = active1.get_side_photo() - if(istype(side_photo, /obj/item/photo)) - var/obj/item/photo/photo_side = side_photo - print_photo(photo_side.picture.picture_image, active1.fields["name"]) - if("crim_add") - if(istype(active1, /datum/data/record)) - var/t1 = tgui_input_text(usr, "Input crime names", "Security Records") - var/t2 = tgui_input_text(usr, "Input crime details", "Security Records") - if(!canUseSecurityRecordsConsole(usr, t1, null, a2)) - return - var/crime = GLOB.data_core.createCrimeEntry(t1, t2, authenticated, station_time_timestamp()) - GLOB.data_core.addCrime(active1.fields["id"], crime) - investigate_log("New Crime: [t1]: [t2] | Added to [active1.fields["name"]] by [key_name(usr)]", INVESTIGATE_RECORDS) - if("crim_delete") - if(istype(active1, /datum/data/record)) - if(href_list["cdataid"]) - if(!canUseSecurityRecordsConsole(usr, "delete", null, a2)) - return - GLOB.data_core.removeCrime(active1.fields["id"],href_list["cdataid"]) - if("add_details") - if(istype(active1, /datum/data/record)) - if(href_list["cdataid"]) - var/t1 = tgui_input_text(usr, "Input crime details", "Security Records") - if(!canUseSecurityRecordsConsole(usr, t1, null, a2)) - return - GLOB.data_core.addCrimeDetails(active1.fields["id"], href_list["cdataid"], t1) - investigate_log("New Crime details: [t1] | Added to [active1.fields["name"]] by [key_name(usr)]", INVESTIGATE_RECORDS) - if("citation_add") - if(istype(active1, /datum/data/record)) - var/maxFine = CONFIG_GET(number/maxfine) - - var/t1 = tgui_input_text(usr, "Input citation crime", "Security Records") - if(!t1) - return - var/fine = tgui_input_number(usr, "Input citation fine", "Security Records", 50, maxFine) - if (!fine || QDELETED(usr) || QDELETED(src) || !canUseSecurityRecordsConsole(usr, t1, null, a2)) - return - var/datum/data/crime/crime = GLOB.data_core.createCrimeEntry(t1, "", authenticated, station_time_timestamp(), fine) - for (var/obj/item/modular_computer/tablet as anything in GLOB.TabletMessengers) - if(tablet.saved_identification == active1.fields["name"]) - var/message = "You have been fined [fine] credits for '[t1]'. Fines may be paid at security." - var/datum/signal/subspace/messaging/tablet_msg/signal = new(src, list( - "name" = "Security Citation", - "job" = "Citation Server", - "message" = message, - "targets" = list(tablet), - "automated" = TRUE - )) - signal.send_to_receivers() - usr.log_message("(PDA: Citation Server) sent \"[message]\" to [signal.format_target()]", LOG_PDA) - GLOB.data_core.addCitation(active1.fields["id"], crime) - investigate_log("New Citation: [t1] Fine: [fine] | Added to [active1.fields["name"]] by [key_name(usr)]", INVESTIGATE_RECORDS) - SSblackbox.ReportCitation(crime.dataId, usr.ckey, usr.real_name, active1.fields["name"], t1, fine) - if("citation_delete") - if(istype(active1, /datum/data/record)) - if(href_list["cdataid"]) - if(!canUseSecurityRecordsConsole(usr, "delete", null, a2)) - return - GLOB.data_core.removeCitation(active1.fields["id"], href_list["cdataid"]) - if("notes") - if(istype(active2, /datum/data/record)) - var/t1 = tgui_input_text(usr, "Please summarize notes", "Security Records", active2.fields["notes"]) - if(!canUseSecurityRecordsConsole(usr, t1, null, a2)) - return - active2.fields["notes"] = t1 - if("criminal") - if(istype(active2, /datum/data/record)) - temp = "
Criminal Status:
" - temp += "" - if("rank") - var/list/L = list( - JOB_CAPTAIN, - JOB_HEAD_OF_PERSONNEL, - JOB_AI, - JOB_CENTCOM, - ) - //This was so silly before the change. Now it actually works without beating your head against the keyboard. /N - if((istype(active1, /datum/data/record) && L.Find(rank))) - temp = "
Rank:
" - temp += "" - else - tgui_alert(usr, "You do not have the required rank to do this!") -//TEMPORARY MENU FUNCTIONS - else//To properly clear as per clear screen. - temp=null - switch(href_list["choice"]) - if("Change Rank") - if(active1) - var/text = strip_html(href_list["rank"]) - var/path = text2path(text) - if(ispath(path)) - var/rank = SSid_access.station_job_templates[path] - if(rank) - active1.fields["rank"] = rank - active1.fields["trim"] = active1.fields["rank"] - else - message_admins("Warning: possible href exploit by [key_name(usr)] - attempted to set change a crew member rank to an invalid path: [path]") - log_game("Warning: possible href exploit by [key_name(usr)] - attempted to set change a crew member rank to an invalid path: [path]") - usr.log_message("possibly trying to href exploit - attempted to set change a crew member rank to an invalid path: [path]", LOG_ADMIN, log_globally = FALSE) - else if(!isnull(text)) - message_admins("Warning: possible href exploit by [key_name(usr)] - attempted to set change a crew member rank to an invalid value: [text]") - log_game("Warning: possible href exploit by [key_name(usr)] - attempted to set change a crew member rank to an invalid value: [text]") - usr.log_message("possibly trying to href exploit - attempted to set change a crew member rank to an invalid value: [text]", LOG_ADMIN, log_globally = FALSE) - - if("Change Criminal Status") - if(active2) - var/old_field = active2.fields["criminal"] - switch(href_list["criminal2"]) - if("none") - active2.fields["criminal"] = "None" - if("arrest") - active2.fields["criminal"] = "*Arrest*" - if("incarcerated") - active2.fields["criminal"] = "Incarcerated" - if("suspected") - active2.fields["criminal"] = "Suspected" - if("paroled") - active2.fields["criminal"] = "Paroled" - if("released") - active2.fields["criminal"] = "Discharged" - investigate_log("[active1.fields["name"]] has been set from [old_field] to [active2.fields["criminal"]] by [key_name(usr)].", INVESTIGATE_RECORDS) - for(var/i in GLOB.human_list) - var/mob/living/carbon/human/H = i - H.sec_hud_set_security_status() - if("Delete Record (Security) Execute") - usr.investigate_log("has deleted the security records for [active1.fields["name"]].", INVESTIGATE_RECORDS) - if(active2) - qdel(active2) - active2 = null - - if("Delete Record (ALL) Execute") - if(active1) - usr.investigate_log("has deleted all records for [active1.fields["name"]].", INVESTIGATE_RECORDS) - for(var/datum/data/record/R in GLOB.data_core.medical) - if((R.fields["name"] == active1.fields["name"] || R.fields["id"] == active1.fields["id"])) - qdel(R) - break - qdel(active1) - active1 = null - - if(active2) - qdel(active2) - active2 = null - else - temp = "This function does not appear to be working at the moment. Our apologies." - - add_fingerprint(usr) - updateUsrDialog() - return - -/obj/machinery/computer/secure_data/proc/get_photo(mob/user) - var/obj/item/photo/P = null - if(issilicon(user)) - var/mob/living/silicon/tempAI = user - var/datum/picture/selection = tempAI.GetPhoto(user) - if(selection) - P = new(null, selection) - else if(istype(user.get_active_held_item(), /obj/item/photo)) - P = user.get_active_held_item() - return P - -/obj/machinery/computer/secure_data/proc/print_photo(icon/temp, person_name) - if (printing) - return - printing = TRUE - sleep(2 SECONDS) - var/obj/item/photo/P = new/obj/item/photo(drop_location()) - var/datum/picture/toEmbed = new(name = person_name, desc = "The photo on file for [person_name].", image = temp) - P.set_picture(toEmbed, TRUE, TRUE) - P.pixel_x = rand(-10, 10) - P.pixel_y = rand(-10, 10) - printing = FALSE - -/obj/machinery/computer/secure_data/emp_act(severity) - . = ..() - - if(machine_stat & (BROKEN|NOPOWER) || . & EMP_PROTECT_SELF) - return - - for(var/datum/data/record/R in GLOB.data_core.security) - if(prob(10/severity)) - switch(rand(1,8)) - if(1) - if(prob(10)) - R.fields["name"] = "[pick(lizard_name(MALE),lizard_name(FEMALE))]" - else - R.fields["name"] = "[pick(pick(GLOB.first_names_male), pick(GLOB.first_names_female))] [pick(GLOB.last_names)]" - if(2) - R.fields["gender"] = pick("Male", "Female", "Other") - if(3) - R.fields["age"] = rand(5, 85) - if(4) - R.fields["criminal"] = pick("None", "*Arrest*", "Incarcerated", "Suspected", "Paroled", "Discharged") - if(5) - R.fields["p_stat"] = pick("*Unconscious*", "Active", "Physically Unfit") - if(6) - R.fields["m_stat"] = pick("*Insane*", "*Unstable*", "*Watch*", "Stable") - if(7) - R.fields["species"] = pick(get_selectable_species()) - if(8) - var/datum/data/record/G = pick(GLOB.data_core.general) - R.fields["photo_front"] = G.fields["photo_front"] - R.fields["photo_side"] = G.fields["photo_side"] - continue - - else if(prob(1)) - qdel(R) - continue - -/obj/machinery/computer/secure_data/proc/canUseSecurityRecordsConsole(mob/user, message1 = 0, record1, record2) - if(user && authenticated) - if(user.canUseTopic(src, !issilicon(user))) - if(!trim(message1)) - return FALSE - if(!record1 || record1 == active1) - if(!record2 || record2 == active2) - return TRUE - return FALSE +#undef PRINTOUT_MISSING +#undef PRINTOUT_RAPSHEET +#undef PRINTOUT_WANTED diff --git a/code/game/machinery/computer/warrant.dm b/code/game/machinery/computer/warrant.dm index 52f06860752..dca46c5b634 100644 --- a/code/game/machinery/computer/warrant.dm +++ b/code/game/machinery/computer/warrant.dm @@ -1,137 +1,178 @@ -/obj/machinery/computer/warrant//TODO:SANITY +/obj/machinery/computer/warrant name = "security warrant console" - desc = "Used to view crewmember security records" + desc = "Used to view outstanding warrants." icon_screen = "security" icon_keyboard = "security_key" circuit = /obj/item/circuitboard/computer/warrant light_color = COLOR_SOFT_RED - var/screen = null - var/datum/data/record/current = null + /// The state of the printer + var/printing = FALSE -/obj/machinery/computer/warrant/ui_interact(mob/user) +/obj/machinery/computer/warrant/ui_interact(mob/user, datum/tgui/ui) . = ..() + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "WarrantConsole", name) + ui.set_autoupdate(FALSE) + ui.open() - var/list/dat = list("Logged in as: ") - if(authenticated) - dat += {"[authenticated]
"} - if(current) - var/background - var/notice = "" - switch(current.fields["criminal"]) - if("*Arrest*") - background = "background-color:#990000;" - notice = "
**REPORT TO THE BRIG**" - if("Incarcerated") - background = "background-color:#CD6500;" - if("Suspected") - background = "background-color:#CD6500;" - if("Paroled") - background = "background-color:#CD6500;" - if("Discharged") - background = "background-color:#006699;" - if("None") - background = "background-color:#4F7529;" - if("") - background = "''" //"'background-color:#FFFFFF;'" - dat += "Warrant Data" - dat += {" - - -
Name: [current.fields["name"]] 
ID: [current.fields["id"]] 
"} - dat += {"Criminal Status:
-
- [current.fields["criminal"]][notice] -
"} +/obj/machinery/computer/warrant/ui_data(mob/user) + var/list/data = list() - dat += "

Citations:" + var/list/records = list() - dat +={" - - - - - - - - "} - for(var/datum/data/crime/c in current.fields["citation"]) - var/owed = c.fine - c.paid - dat += {" - - - "} - if(owed > 0) - dat += {" - "} - else - dat += "" - dat += "" - dat += "
CrimeFineAuthorTime AddedAmount DueMake Payment
[c.crimeName][c.fine] cr[c.author][c.time][owed] cr\[Pay\]All Paid Off
" + for(var/datum/record/crew/target in GLOB.manifest.general) + if(!length(target.citations)) + continue - dat += "
Crimes:" - dat +={" - - - - - - "} - for(var/datum/data/crime/c in current.fields["crim"]) - dat += {" - - - - "} - dat += "
CrimeDetailsAuthorTime Added
[c.crimeName][c.crimeDetails][c.author][c.time]
" - else - dat += {"** No security record found for this ID **"} - else - dat += {"------------
"} + var/list/citations = list() - var/datum/browser/popup = new(user, "warrant", "Security Warrant Console", 600, 400) - popup.set_content(dat.Join()) - popup.open() + for(var/datum/crime/citation/warrant as anything in target.citations) + var/list/entry = list(list( + author = warrant.author, + details = warrant.details, + fine = warrant.fine, + fine_name = warrant.name, + fine_ref = REF(warrant), + paid = warrant.paid, + time = warrant.time, + )) -/obj/machinery/computer/warrant/Topic(href, href_list) - if(..()) - return - var/mob/M = usr - switch(href_list["choice"]) - if("Login") - if(isliving(M)) - var/mob/living/L = M - var/obj/item/card/id/scan = L.get_idcard(TRUE) - if (!scan) - say("You do not have a registered ID!") - return - authenticated = scan.registered_name - if(authenticated) - current = find_record("name", authenticated, GLOB.data_core.security) - playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE) - if("Logout") - current = null - authenticated = null - playsound(src, 'sound/machines/terminal_off.ogg', 50, FALSE) + citations += entry - if("Pay") - for(var/datum/data/crime/p in current.fields["citation"]) - if(p.dataId == text2num(href_list["cdataid"])) - var/obj/item/holochip/C = M.is_holding_item_of_type(/obj/item/holochip) - if(C && istype(C)) - var/pay = C.get_item_credit_value() - if(!pay) - to_chat(M, span_warning("[C] doesn't seem to be worth anything!")) - else - var/diff = p.fine - p.paid - GLOB.data_core.payCitation(current.fields["id"], text2num(href_list["cdataid"]), pay) - to_chat(M, span_notice("You have paid [pay] credit\s towards your fine.")) - if (pay == diff || pay > diff || pay >= diff) - investigate_log("Citation Paid off: [p.crimeName] Fine: [p.fine] | Paid off by [key_name(usr)]", INVESTIGATE_RECORDS) - to_chat(M, span_notice("The fine has been paid in full.")) - SSblackbox.ReportCitation(text2num(href_list["cdataid"]),"","","","", 0, pay) - qdel(C) - playsound(src, SFX_TERMINAL_TYPE, 25, FALSE) - else - to_chat(M, span_warning("Fines can only be paid with holochips!")) - updateUsrDialog() - add_fingerprint(M) + var/list/record = list(list( + citations = citations, + crew_name = target.name, + crew_ref = REF(target), + notes = target.security_note, + rank = target.rank, + )) + + records += record + data["records"] = records + + return data + +/obj/machinery/computer/warrant/ui_act(action, list/params, datum/tgui/ui) + . = ..() + if(.) + return FALSE + + switch(action) + if("pay") + pay_fine(usr, params) + return TRUE + + if("print") + ui.close() + print_bounty(usr, params) + return TRUE + + if("refresh") + return TRUE + + return FALSE + +/// Pays towards a listed fine. +/obj/machinery/computer/warrant/proc/pay_fine(mob/user, list/params) + var/datum/record/crew/target = locate(params["crew_ref"]) in GLOB.manifest.general + if(!target) + return FALSE + + var/datum/crime/citation/warrant = locate(params["fine_ref"]) in target.citations + if(!warrant) + return FALSE + + if(!isliving(user) || issilicon(user)) + to_chat(user, span_warning("ACCESS DENIED")) + playsound(src, 'sound/machines/terminal_error.ogg', 100, TRUE) + return FALSE + + var/mob/living/player = user + var/obj/item/card/id/auth = player.get_idcard(TRUE) + if(!auth) + to_chat(user, span_warning("ACCESS DENIED: No ID card detected.")) + playsound(src, 'sound/machines/terminal_error.ogg', 100, TRUE) + return FALSE + + var/datum/bank_account/account = auth.registered_account + if(!account?.account_holder || account.account_holder == "Unassigned") + to_chat(user, span_warning("ACCESS DENIED: No account linked to ID.")) + playsound(src, 'sound/machines/terminal_error.ogg', 100, TRUE) + return FALSE + + var/amount = params["amount"] + if(!amount || !isnum(amount) || amount > warrant.fine || !account.adjust_money(-amount, "Paid fine for [target.name]")) + to_chat(user, span_warning("ACCESS DENIED: Invalid amount.")) + playsound(src, 'sound/machines/terminal_error.ogg', 100, TRUE) + return FALSE + + account.bank_card_talk("You have paid [amount]cr towards [target.name]'s fine of [warrant.fine]cr.") + log_econ("[amount]cr was transferred from [user]'s transaction to [target.name]'s [warrant.fine]cr fine") + SSblackbox.record_feedback("amount", "credits_transferred", amount) + warrant.pay_fine(amount) + + if(amount >= 100 && target?.name != user) + var/list/titles = list( + "An anonymous benefactor", + "A generous citizen", + "A kind soul", + "A good samaritan", + "A friendly face", + "A helpful stranger", + ) + warrant.alert_owner(user, src, target.name, "[pick(titles)] has paid [amount]cr towards your fine.") + + var/datum/bank_account/sec_account = SSeconomy.get_dep_account(ACCOUNT_SEC) + sec_account.adjust_money(amount) + + if(warrant.fine != 0 || target.name == user) + return TRUE + + warrant.alert_owner(user, src, target.name, "One of your outstanding warrants has been completely paid.") + return TRUE + +/// Finishes printing, resets the printer. +/obj/machinery/computer/warrant/proc/print_finish(obj/item/paper/bounty) + printing = FALSE + playsound(src, 'sound/machines/terminal_eject.ogg', 100, TRUE) + bounty.forceMove(loc) + + return TRUE + +/// Prints a bounty for a listed fine. +/obj/machinery/computer/warrant/proc/print_bounty(mob/user, list/params) + if(printing) + balloon_alert(user, "printer busy") + playsound(src, 'sound/machines/terminal_error.ogg', 100, TRUE) + return FALSE + + var/datum/record/crew/target = locate(params["crew_ref"]) in GLOB.manifest.general + if(!target) + return FALSE + + var/datum/crime/citation/warrant = locate(params["fine_ref"]) in target.citations + if(!warrant?.fine) + return FALSE + + var/bounty_text = "

Bounty for [target.name]


" + bounty_text += "
Wanted for [warrant.name]


" + bounty_text += "Details:
[warrant.details]
" + bounty_text += "Issued to:
[usr]
" + bounty_text += "Issued on:
[warrant.time]
" + bounty_text += "Comments:
[!target.security_note ? "None." : target.security_note]

" + bounty_text += "
FINE: [warrant.fine] credits
" + + printing = TRUE + balloon_alert(user, "printing") + playsound(src, 'sound/machines/printer.ogg', 100, TRUE) + + var/obj/item/paper/bounty = new(null) + bounty.name = "Bounty for [target.name]" + bounty.desc = "A [warrant.fine]cr bounty for [target.name]." + bounty.add_raw_text(bounty_text) + bounty.update_icon() + + addtimer(CALLBACK(src, PROC_REF(print_finish), bounty), 2 SECONDS) + + return TRUE diff --git a/code/game/machinery/gulag_teleporter.dm b/code/game/machinery/gulag_teleporter.dm index e0d48dee344..1d3eaba6358 100644 --- a/code/game/machinery/gulag_teleporter.dm +++ b/code/game/machinery/gulag_teleporter.dm @@ -144,7 +144,7 @@ The console is located at computer/gulag_teleporter.dm else W.forceMove(src) -/obj/machinery/gulag_teleporter/proc/handle_prisoner(obj/item/id, datum/data/record/R) +/obj/machinery/gulag_teleporter/proc/handle_prisoner(obj/item/id, datum/record/crew/target) if(!ishuman(occupant)) return strip_occupant() @@ -158,8 +158,8 @@ The console is located at computer/gulag_teleporter.dm prisoner.equip_to_appropriate_slot(new shoes_type, qdel_on_fail = TRUE) if(id) prisoner.equip_to_appropriate_slot(id, qdel_on_fail = TRUE) - if(R) - R.fields["criminal"] = "Incarcerated" + if(target) + target.wanted_status = WANTED_PRISONER use_power(active_power_usage) diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index 12980a91f3c..4af74322929 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -569,8 +569,8 @@ DEFINE_BITFIELD(turret_flags, list( if(turret_flags & TURRET_FLAG_SHOOT_CRIMINALS) //if the turret can check the records, check if they are set to *Arrest* on records var/perpname = perp.get_face_name(perp.get_id_name()) - var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.security) - if(!R || (R.fields["criminal"] == "*Arrest*")) + var/datum/record/crew/target = find_record(perpname) + if(!target || (target.wanted_status == WANTED_ARREST)) threatcount += 4 if((turret_flags & TURRET_FLAG_SHOOT_UNSHIELDED) && (!HAS_TRAIT(perp, TRAIT_MINDSHIELD))) diff --git a/code/game/machinery/scan_gate.dm b/code/game/machinery/scan_gate.dm index 2096f173911..e1f3505b40b 100644 --- a/code/game/machinery/scan_gate.dm +++ b/code/game/machinery/scan_gate.dm @@ -123,8 +123,8 @@ if(ishuman(M)) var/mob/living/carbon/human/H = M var/perpname = H.get_face_name(H.get_id_name()) - var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.security) - if(!R || (R.fields["criminal"] == "*Arrest*")) + var/datum/record/crew/target = find_record(perpname) + if(!target || (target.wanted_status == WANTED_ARREST)) beep = TRUE if(SCANGATE_MINDSHIELD) if(HAS_TRAIT(M, TRAIT_MINDSHIELD)) diff --git a/code/game/say.dm b/code/game/say.dm index a3063fcd9b8..918d97bd458 100644 --- a/code/game/say.dm +++ b/code/game/say.dm @@ -243,9 +243,9 @@ INITIALIZE_IMMEDIATE(/atom/movable/virtualspeaker) if(ishuman(M)) // Humans use their job as seen on the crew manifest. This is so the AI // can know their job even if they don't carry an ID. - var/datum/data/record/findjob = find_record("name", name, GLOB.data_core.general) - if(findjob) - job = findjob.fields["rank"] + var/datum/record/crew/found_record = find_record(name) + if(found_record) + job = found_record.rank else job = "Unknown" else if(iscarbon(M)) // Carbon nonhuman diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index f7e2a68c76f..146e152cb42 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -945,7 +945,7 @@ GLOBAL_PROTECT(admin_verbs_poll) // Finally, ensure the minds are tracked and in the manifest. SSticker.minds += character.mind if(ishuman(character)) - GLOB.data_core.manifest_inject(character) + GLOB.manifest.inject(character) number_made++ CHECK_TICK diff --git a/code/modules/admin/verbs/admingame.dm b/code/modules/admin/verbs/admingame.dm index 554b89d4cfa..b578708c7f1 100644 --- a/code/modules/admin/verbs/admingame.dm +++ b/code/modules/admin/verbs/admingame.dm @@ -206,19 +206,16 @@ Traitors and the like can also be revived with the previous role mostly intact. var/mob/living/carbon/human/new_character = new//The mob being spawned. SSjob.SendToLateJoin(new_character) - var/datum/data/record/record_found //Referenced to later to either randomize or not randomize the character. + var/datum/record/locked/record_found //Referenced to later to either randomize or not randomize the character. if(G_found.mind && !G_found.mind.active) //mind isn't currently in use by someone/something - /*Try and locate a record for the person being respawned through GLOB.data_core. - This isn't an exact science but it does the trick more often than not.*/ - var/id = md5("[G_found.real_name][G_found.mind.assigned_role.title]") - - record_found = find_record("id", id, GLOB.data_core.locked) + record_found = find_record(G_found.name, locked_only = TRUE) if(record_found)//If they have a record we can determine a few things. - new_character.real_name = record_found.fields["name"] - new_character.gender = record_found.fields["gender"] - new_character.age = record_found.fields["age"] - new_character.hardset_dna(record_found.fields["identity"], record_found.fields["enzymes"], null, record_found.fields["name"], record_found.fields["blood_type"], new record_found.fields["species"], record_found.fields["features"]) + new_character.real_name = record_found.name + new_character.gender = record_found.gender + new_character.age = record_found.age + var/datum/dna/found_dna = record_found.dna_ref + new_character.hardset_dna(found_dna.unique_identity, record_found.dna_string, null, record_found.name, record_found.blood_type, new record_found.species, found_dna.features) else new_character.randomize_human_appearance() new_character.dna.update_dna_identity() @@ -282,7 +279,7 @@ Traitors and the like can also be revived with the previous role mostly intact. if(!record_found && (new_character.mind.assigned_role.job_flags & JOB_CREW_MEMBER)) //Power to the user! if(tgui_alert(new_character,"Warning: No data core entry detected. Would you like to announce the arrival of this character by adding them to various databases, such as medical records?",,list("No","Yes")) == "Yes") - GLOB.data_core.manifest_inject(new_character) + GLOB.manifest.inject(new_character) if(tgui_alert(new_character,"Would you like an active AI to announce this character?",,list("No","Yes")) == "Yes") announce_arrival(new_character, new_character.mind.assigned_role.title) diff --git a/code/modules/admin/verbs/list_exposer.dm b/code/modules/admin/verbs/list_exposer.dm index b4cd1f42e76..851bd901c1e 100644 --- a/code/modules/admin/verbs/list_exposer.dm +++ b/code/modules/admin/verbs/list_exposer.dm @@ -53,8 +53,8 @@ return var/data = "Showing Crew Manifest.
" data += "" - for(var/datum/data/record/entry in GLOB.data_core.general) - data += "" + for(var/datum/record/crew/entry in GLOB.manifest.general) + data += "" data += "
NamePosition
[entry.fields["name"]][entry.fields["rank"]][entry.fields["rank"] != entry.fields["trim"] ? " ([entry.fields["trim"]])" : ""]
[entry.name][entry.rank][entry.rank != entry.trim ? " ([entry.trim])" : ""]
" usr << browse(data, "window=manifest;size=440x410") diff --git a/code/modules/antagonists/ninja/ninjaDrainAct.dm b/code/modules/antagonists/ninja/ninjaDrainAct.dm index 8e600b8466b..838cd677348 100644 --- a/code/modules/antagonists/ninja/ninjaDrainAct.dm +++ b/code/modules/antagonists/ninja/ninjaDrainAct.dm @@ -156,9 +156,8 @@ /obj/machinery/computer/secure_data/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module) if(!do_after(ninja, 20 SECONDS, src, extra_checks = CALLBACK(src, PROC_REF(can_hack), ninja))) return - for(var/datum/data/record/rec in sort_record(GLOB.data_core.general, sortBy, order)) - for(var/datum/data/record/security_record in GLOB.data_core.security) - security_record.fields["criminal"] = "*Arrest*" + for(var/datum/record/crew/target in GLOB.manifest.general) + target.wanted_status = WANTED_ARREST var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja) if(!ninja_antag) return diff --git a/code/modules/detectivework/scanner.dm b/code/modules/detectivework/scanner.dm index 9a873ffeec3..b688b0546ad 100644 --- a/code/modules/detectivework/scanner.dm +++ b/code/modules/detectivework/scanner.dm @@ -45,7 +45,7 @@ // Create our paper var/obj/item/paper/report_paper = new(get_turf(src)) - //This could be a global count like sec and med record printouts. See GLOB.data_core.medicalPrintCount AKA datacore.dm + //This could be a global count like sec and med record printouts. See GLOB.manifest.generalPrintCount AKA datacore.dm var/frNum = ++forensicPrintCount report_paper.name = text("FR-[] 'Forensic Record'", frNum) diff --git a/code/modules/jobs/job_types/prisoner.dm b/code/modules/jobs/job_types/prisoner.dm index 783283960f4..2a422c9c5ae 100644 --- a/code/modules/jobs/job_types/prisoner.dm +++ b/code/modules/jobs/job_types/prisoner.dm @@ -41,9 +41,9 @@ crime_name = pick(assoc_to_keys(GLOB.prisoner_crimes)) var/datum/prisoner_crime/crime = GLOB.prisoner_crimes[crime_name] - var/datum/data/record/target_record = find_record("name", crewmember.real_name, GLOB.data_core.security) - var/datum/data/crime/past_crime = GLOB.data_core.createCrimeEntry(crime.name, crime.desc, "Central Command", "Indefinite.") - GLOB.data_core.addCrime(target_record.fields["id"], past_crime) + var/datum/record/crew/target_record = find_record(crewmember.real_name) + var/datum/crime/past_crime = new(crime.name, crime.desc, "Central Command", "Indefinite.") + target_record.crimes += past_crime to_chat(crewmember, span_warning("You are imprisoned for \"[crime_name]\".")) /datum/outfit/job/prisoner diff --git a/code/modules/mob/dead/crew_manifest.dm b/code/modules/mob/dead/crew_manifest.dm index 08ff61de1a6..6a2c84622a2 100644 --- a/code/modules/mob/dead/crew_manifest.dm +++ b/code/modules/mob/dead/crew_manifest.dm @@ -33,6 +33,6 @@ positions[department.department_name] = list("exceptions" = exceptions, "open" = open) return list( - "manifest" = GLOB.data_core.get_manifest(), + "manifest" = GLOB.manifest.get_manifest(), "positions" = positions ) diff --git a/code/modules/mob/dead/new_player/latejoin_menu.dm b/code/modules/mob/dead/new_player/latejoin_menu.dm index 98f365a8ec4..3b3e99068ad 100644 --- a/code/modules/mob/dead/new_player/latejoin_menu.dm +++ b/code/modules/mob/dead/new_player/latejoin_menu.dm @@ -101,13 +101,9 @@ GLOBAL_DATUM_INIT(latejoin_menu, /datum/latejoin_menu, new) departments[department.department_name] = department_data for(var/datum/job/job_datum as anything in department.department_jobs) - var/datum/outfit/outfit = job_datum.outfit - var/datum/id_trim/trim = initial(outfit.id_trim) - var/list/job_data = list( "command" = !!(job_datum.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND), "description" = job_datum.description, - "icon" = initial(trim.orbit_icon), ) department_jobs[job_datum.title] = job_data diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index f219489c40e..19940dcaf26 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -198,7 +198,7 @@ humanc = character //Let's retypecast the var to be human, if(humanc) //These procs all expect humans - GLOB.data_core.manifest_inject(humanc) + GLOB.manifest.inject(humanc) if(SSshuttle.arrivals) SSshuttle.arrivals.QueueAnnounce(humanc, rank) else diff --git a/code/modules/mob/dead/observer/orbit.dm b/code/modules/mob/dead/observer/orbit.dm index 93495de2038..0e9334b896f 100644 --- a/code/modules/mob/dead/observer/orbit.dm +++ b/code/modules/mob/dead/observer/orbit.dm @@ -97,8 +97,6 @@ GLOBAL_DATUM_INIT(orbit_menu, /datum/orbit_menu, new) else var/obj/item/card/id/id_card = player.get_idcard(hand_first = FALSE) serialized["job"] = id_card?.get_trim_assignment() - var/datum/id_trim/trim = id_card?.trim - serialized["job_icon"] = trim?.orbit_icon for(var/datum/antagonist/antag_datum as anything in mind.antag_datums) if (antag_datum.show_to_ghosts) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 428b53478d4..e11c6239c5d 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -369,9 +369,9 @@ var/perpname = get_face_name(get_id_name("")) if(perpname && (HAS_TRAIT(user, TRAIT_SECURITY_HUD) || HAS_TRAIT(user, TRAIT_MEDICAL_HUD))) - var/datum/data/record/target_record = find_record("name", perpname, GLOB.data_core.general) + var/datum/record/crew/target_record = find_record(perpname) if(target_record) - . += "Rank: [target_record.fields["rank"]]\n\[Front photo\]\[Side photo\]" + . += "Rank: [target_record.rank]\n\[Front photo\]\[Side photo\]" if(HAS_TRAIT(user, TRAIT_MEDICAL_HUD)) var/cyberimp_detect for(var/obj/item/organ/internal/cyberimp/CI in internal_organs) @@ -380,12 +380,7 @@ if(cyberimp_detect) . += "Detected cybernetic modifications:" . += "[cyberimp_detect]" - if(target_record) - var/health_r = target_record.fields["p_stat"] - . += "\[[health_r]\]" - health_r = target_record.fields["m_stat"] - . += "\[[health_r]\]" - target_record = find_record("name", perpname, GLOB.data_core.medical) + target_record = find_record(perpname) if(target_record) . += "\[Medical evaluation\]
" . += "\[See quirks\]" @@ -393,18 +388,17 @@ if(HAS_TRAIT(user, TRAIT_SECURITY_HUD)) if(!user.stat && user != src) //|| !user.canmove || user.restrained()) Fluff: Sechuds have eye-tracking technology and sets 'arrest' to people that the wearer looks and blinks at. - var/criminal = "None" + var/wanted_status = WANTED_NONE - target_record = find_record("name", perpname, GLOB.data_core.security) + target_record = find_record(perpname) if(target_record) - criminal = target_record.fields["criminal"] + wanted_status = target_record.wanted_status - . += "Criminal status: \[[criminal]\]" + . += "Criminal status: \[[wanted_status]\]" . += jointext(list("Security record: \[View\]", "\[Add citation\]", "\[Add crime\]", - "\[View comment log\]", - "\[Add comment\]"), "") + "\[Add note\]"), "") else if(isobserver(user)) . += span_info("Traits: [get_quirk_string(FALSE, CAT_QUIRK_ALL)]") . += "" diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 78824aa5220..5ee4671006f 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -104,7 +104,7 @@ if((text2num(href_list["examine_time"]) + 1 MINUTES) < world.time) to_chat(human_user, "[span_notice("It's too late to use this now!")]") return - var/datum/data/record/target_record = find_record("name", perpname, GLOB.data_core.general) + var/datum/record/crew/target_record = find_record(perpname) if(href_list["photo_front"] || href_list["photo_side"]) if(!target_record) return @@ -173,28 +173,6 @@ if(!(ACCESS_MEDICAL in access)) to_chat(human_user, span_warning("ERROR: Invalid access")) return - if(href_list["p_stat"]) - var/health_status = input(human_user, "Specify a new physical status for this person.", "Medical HUD", target_record.fields["p_stat"]) in list("Active", "Physically Unfit", "*Unconscious*", "*Deceased*", "Cancel") - if(!target_record) - return - if(!human_user.canUseHUD()) - return - if(!HAS_TRAIT(human_user, TRAIT_MEDICAL_HUD)) - return - if(health_status && health_status != "Cancel") - target_record.fields["p_stat"] = health_status - return - if(href_list["m_stat"]) - var/health_status = input(human_user, "Specify a new mental status for this person.", "Medical HUD", target_record.fields["m_stat"]) in list("Stable", "*Watch*", "*Unstable*", "*Insane*", "Cancel") - if(!target_record) - return - if(!human_user.canUseHUD()) - return - if(!HAS_TRAIT(human_user, TRAIT_MEDICAL_HUD)) - return - if(health_status && health_status != "Cancel") - target_record.fields["m_stat"] = health_status - return if(href_list["quirk"]) var/quirkstring = get_quirk_string(TRUE, CAT_QUIRK_ALL) if(quirkstring) @@ -226,22 +204,17 @@ if(!perpname) to_chat(human_user, span_warning("ERROR: Can not identify target.")) return - target_record = find_record("name", perpname, GLOB.data_core.security) + target_record = find_record(perpname) if(!target_record) to_chat(human_user, span_warning("ERROR: Unable to locate data core entry for target.")) return if(href_list["status"]) - var/setcriminal = input(human_user, "Specify a new criminal status for this person.", "Security HUD", target_record.fields["criminal"]) in list("None", "*Arrest*", "Incarcerated", "Suspected", "Paroled", "Discharged", "Cancel") - if(setcriminal != "Cancel") - if(!target_record) - return - if(!human_user.canUseHUD()) - return - if(!HAS_TRAIT(human_user, TRAIT_SECURITY_HUD)) - return - investigate_log("has been set from [target_record.fields["criminal"]] to [setcriminal] by [key_name(human_user)].", INVESTIGATE_RECORDS) - target_record.fields["criminal"] = setcriminal - sec_hud_set_security_status() + var/setcriminal = tgui_input_list(human_user, "Specify a new criminal status for this person.", "Security HUD", WANTED_STATUSES(), target_record.wanted_status) + if(!setcriminal || !target_record || !human_user.canUseHUD() || !HAS_TRAIT(human_user, TRAIT_SECURITY_HUD)) + return + investigate_log("has been set from [target_record.wanted_status] to [setcriminal] by [key_name(human_user)].", INVESTIGATE_RECORDS) + target_record.wanted_status = setcriminal + sec_hud_set_security_status() return if(href_list["view"]) @@ -249,103 +222,55 @@ return if(!HAS_TRAIT(human_user, TRAIT_SECURITY_HUD)) return - to_chat(human_user, "Name: [target_record.fields["name"]] Criminal Status: [target_record.fields["criminal"]]") - for(var/datum/data/crime/c in target_record.fields["crim"]) - to_chat(human_user, "Crime: [c.crimeName]") - if (c.crimeDetails) - to_chat(human_user, "Details: [c.crimeDetails]") - else - to_chat(human_user, "Details: \[Add details]") - to_chat(human_user, "Added by [c.author] at [c.time]") + to_chat(human_user, "Name: [target_record.name]") + to_chat(human_user, "Criminal Status: [target_record.wanted_status]") + to_chat(human_user, "Rapsheet:") + for(var/datum/crime/crime in target_record.crimes) + to_chat(human_user, "Crime: [crime.name]") + to_chat(human_user, "Details: [crime.details]") + to_chat(human_user, "Added by [crime.author] at [crime.time]") to_chat(human_user, "----------") - to_chat(human_user, "Notes: [target_record.fields["notes"]]") + to_chat(human_user, "Citations: [length(target_record.citations)]") + to_chat(human_user, "Note: [target_record.security_note || "None."]") + return if(href_list["add_citation"]) - var/maxFine = CONFIG_GET(number/maxfine) - var/t1 = tgui_input_text(human_user, "Citation crime", "Security HUD") - var/fine = tgui_input_number(human_user, "Citation fine", "Security HUD", 50, maxFine, 5) - if(!fine) - return - if(!target_record || !t1 || !allowed_access) - return - if(!human_user.canUseHUD()) - return - if(!HAS_TRAIT(human_user, TRAIT_SECURITY_HUD)) + var/max_fine = CONFIG_GET(number/maxfine) + var/citation_name = tgui_input_text(human_user, "Citation crime", "Security HUD") + var/fine = tgui_input_number(human_user, "Citation fine", "Security HUD", 50, max_fine, 5) + if(!fine || !target_record || !citation_name || !allowed_access || !isnum(fine) || fine > max_fine || fine <= 0 || !human_user.canUseHUD() || !HAS_TRAIT(human_user, TRAIT_SECURITY_HUD)) return - var/datum/data/crime/crime = GLOB.data_core.createCrimeEntry(t1, "", allowed_access, station_time_timestamp(), fine) - for (var/obj/item/modular_computer/tablet in GLOB.TabletMessengers) - if(tablet.saved_identification == target_record.fields["name"]) - var/message = "You have been fined [fine] credits for '[t1]'. Fines may be paid at security." - var/datum/signal/subspace/messaging/tablet_msg/signal = new(src, list( - "name" = "Security Citation", - "job" = "Citation Server", - "message" = message, - "targets" = list(tablet), - "automated" = TRUE - )) - signal.send_to_receivers() - human_user.log_message("(PDA: Citation Server) sent \"[message]\" to [signal.format_target()]", LOG_PDA) - GLOB.data_core.addCitation(target_record.fields["id"], crime) - investigate_log("New Citation: [t1] Fine: [fine] | Added to [target_record.fields["name"]] by [key_name(human_user)]", INVESTIGATE_RECORDS) - SSblackbox.ReportCitation(crime.dataId, human_user.ckey, human_user.real_name, target_record.fields["name"], t1, fine) + var/datum/crime/citation/new_citation = new(name = citation_name, author = allowed_access, fine = fine) + + target_record.citations += new_citation + new_citation.alert_owner(target_record.name, "You have been fined [fine] credits for '[citation_name]'. Fines may be paid at security.") + investigate_log("New Citation: [citation_name] Fine: [fine] | Added to [target_record.name] by [key_name(human_user)]", INVESTIGATE_RECORDS) + SSblackbox.ReportCitation(REF(new_citation), human_user.ckey, human_user.real_name, target_record.name, citation_name, fine) + return if(href_list["add_crime"]) - var/t1 = tgui_input_text(human_user, "Crime name", "Security HUD") - if(!target_record || !t1 || !allowed_access) + var/crime_name = tgui_input_text(human_user, "Crime name", "Security HUD") + if(!target_record || !crime_name || !allowed_access || !human_user.canUseHUD() || !HAS_TRAIT(human_user, TRAIT_SECURITY_HUD)) return - if(!human_user.canUseHUD()) - return - if(!HAS_TRAIT(human_user, TRAIT_SECURITY_HUD)) - return - var/crime = GLOB.data_core.createCrimeEntry(t1, null, allowed_access, station_time_timestamp()) - GLOB.data_core.addCrime(target_record.fields["id"], crime) - investigate_log("New Crime: [t1] | Added to [target_record.fields["name"]] by [key_name(human_user)]", INVESTIGATE_RECORDS) + + var/datum/crime/new_crime = new(name = crime_name, author = allowed_access) + + target_record.crimes += new_crime + investigate_log("New Crime: [crime_name] | Added to [target_record.name] by [key_name(human_user)]", INVESTIGATE_RECORDS) to_chat(human_user, span_notice("Successfully added a crime.")) + return - if(href_list["add_details"]) - var/t1 = tgui_input_text(human_user, "Crime details", "Security Records", multiline = TRUE) - if(!target_record || !t1 || !allowed_access) + if(href_list["add_note"]) + var/new_note = tgui_input_text(human_user, "Security note", "Security Records", multiline = TRUE) + if(!target_record || !new_note || !allowed_access || !human_user.canUseHUD() || !HAS_TRAIT(human_user, TRAIT_SECURITY_HUD)) return - if(!human_user.canUseHUD()) - return - if(!HAS_TRAIT(human_user, TRAIT_SECURITY_HUD)) - return - if(href_list["cdataid"]) - GLOB.data_core.addCrimeDetails(target_record.fields["id"], href_list["cdataid"], t1) - investigate_log("New Crime details: [t1] | Added to [target_record.fields["name"]] by [key_name(human_user)]", INVESTIGATE_RECORDS) - to_chat(human_user, span_notice("Successfully added details.")) - return - if(href_list["view_comment"]) - if(!human_user.canUseHUD()) - return - if(!HAS_TRAIT(human_user, TRAIT_SECURITY_HUD)) - return - to_chat(human_user, "Comments/Log:") - var/counter = 1 - while(target_record.fields[text("com_[]", counter)]) - to_chat(human_user, target_record.fields[text("com_[]", counter)]) - to_chat(human_user, "----------") - counter++ - return + target_record.security_note = new_note - if(href_list["add_comment"]) - var/t1 = tgui_input_text(human_user, "Add a comment", "Security Records", multiline = TRUE) - if (!target_record || !t1 || !allowed_access) - return - if(!human_user.canUseHUD()) - return - if(!HAS_TRAIT(human_user, TRAIT_SECURITY_HUD)) - return - var/counter = 1 - while(target_record.fields[text("com_[]", counter)]) - counter++ - target_record.fields[text("com_[]", counter)] = text("Made by [] on [] [], []
[]", allowed_access, station_time_timestamp(), time2text(world.realtime, "MMM DD"), CURRENT_STATION_YEAR, t1) - to_chat(human_user, span_notice("Successfully added comment.")) return ..() //end of this massive fucking chain. TODO: make the hud chain not spooky. - Yeah, great job doing that. @@ -427,16 +352,16 @@ //Check for arrest warrant if(judgement_criteria & JUDGE_RECORDCHECK) var/perpname = get_face_name(get_id_name()) - var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.security) - if(R?.fields["criminal"]) - switch(R.fields["criminal"]) - if("*Arrest*") + var/datum/record/crew/record = find_record(perpname) + if(record?.wanted_status) + switch(record.wanted_status) + if(WANTED_ARREST) threatcount += 5 - if("Incarcerated") + if(WANTED_PRISONER) threatcount += 2 - if("Suspected") + if(WANTED_SUSPECT) threatcount += 2 - if("Paroled") + if(WANTED_PAROLE) threatcount += 2 //Check for dresscode violations @@ -679,11 +604,14 @@ to_chat(src, span_notice("You successfully [cuff_break ? "break" : "remove"] [I].")) return TRUE -/mob/living/carbon/human/replace_records_name(oldname,newname) // Only humans have records right now, move this up if changed. - for(var/list/L in list(GLOB.data_core.general,GLOB.data_core.medical,GLOB.data_core.security,GLOB.data_core.locked)) - var/datum/data/record/R = find_record("name", oldname, L) - if(R) - R.fields["name"] = newname +/mob/living/carbon/human/replace_records_name(oldname, newname) // Only humans have records right now, move this up if changed. + var/datum/record/crew/crew_record = find_record(oldname) + var/datum/record/locked/locked_record = find_record(oldname, locked_only = TRUE) + + if(crew_record) + crew_record.name = newname + if(locked_record) + locked_record.name = newname /mob/living/carbon/human/update_health_hud() if(!client || !hud_used) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 4185b1e6121..00b4b9894e5 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -659,8 +659,8 @@ if("Station Member") var/list/personnel_list = list() - for(var/datum/data/record/record_datum in GLOB.data_core.locked)//Look in data core locked. - personnel_list["[record_datum.fields["name"]]: [record_datum.fields["rank"]]"] = record_datum.fields["character_appearance"]//Pull names, rank, and image. + for(var/datum/record/crew/record in GLOB.manifest.locked)//Look in data core locked. + personnel_list["[record.name]: [record.rank]"] = record.character_appearance//Pull names, rank, and image. if(!length(personnel_list)) tgui_alert(usr,"No suitable records found. Aborting.") diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 911f1058006..9ac7e474fce 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1041,7 +1041,7 @@ /** * Fully update the name of a mob * - * This will update a mob's name, real_name, mind.name, GLOB.data_core records, pda, id and traitor text + * This will update a mob's name, real_name, mind.name, GLOB.manifest records, pda, id and traitor text * * Calling this proc without an oldname will only update the mob and skip updating the pda, id and records ~Carn */ @@ -1084,7 +1084,7 @@ return TRUE -///Updates GLOB.data_core records with new name , see mob/living/carbon/human +///Updates GLOB.manifest records with new name , see mob/living/carbon/human /mob/proc/replace_records_name(oldname,newname) return diff --git a/code/modules/modular_computers/file_system/programs/card.dm b/code/modules/modular_computers/file_system/programs/card.dm index fb21969726c..769865bce01 100644 --- a/code/modules/modular_computers/file_system/programs/card.dm +++ b/code/modules/modular_computers/file_system/programs/card.dm @@ -133,7 +133,7 @@ // Eject the ID being modified. if("PRG_ejectmodid") if(inserted_auth_card) - GLOB.data_core.manifest_modify(inserted_auth_card.registered_name, inserted_auth_card.assignment, inserted_auth_card.get_trim_assignment()) + GLOB.manifest.modify(inserted_auth_card.registered_name, inserted_auth_card.assignment, inserted_auth_card.get_trim_assignment()) return computer.RemoveID(usr) else var/obj/item/I = user.get_active_held_item() diff --git a/code/modules/modular_computers/file_system/programs/crewmanifest.dm b/code/modules/modular_computers/file_system/programs/crewmanifest.dm index 63c09d33d5d..345bee97d90 100644 --- a/code/modules/modular_computers/file_system/programs/crewmanifest.dm +++ b/code/modules/modular_computers/file_system/programs/crewmanifest.dm @@ -13,7 +13,7 @@ /datum/computer_file/program/crew_manifest/ui_static_data(mob/user) var/list/data = get_header_data() - data["manifest"] = GLOB.data_core.get_manifest() + data["manifest"] = GLOB.manifest.get_manifest() return data /datum/computer_file/program/crew_manifest/ui_act(action, params, datum/tgui/ui) @@ -26,7 +26,7 @@ if(computer) //This option should never be called if there is no printer var/contents = {"

Crew Manifest


- [GLOB.data_core ? GLOB.data_core.get_manifest_html(0) : ""] + [GLOB.manifest ? GLOB.manifest.get_html(0) : ""] "} if(!computer.print_text(contents,text("crew manifest ([])", station_time_timestamp()))) to_chat(usr, span_notice("Printer is out of paper.")) diff --git a/code/modules/modular_computers/file_system/programs/records.dm b/code/modules/modular_computers/file_system/programs/records.dm index e0329103814..15da0d8f61b 100644 --- a/code/modules/modular_computers/file_system/programs/records.dm +++ b/code/modules/modular_computers/file_system/programs/records.dm @@ -35,32 +35,27 @@ switch(mode) if("security") - for(var/datum/data/record/person in GLOB.data_core.general) - var/datum/data/record/security_person = find_record("id", person.fields["id"], GLOB.data_core.security) + for(var/datum/record/crew/person in GLOB.manifest.general) var/list/current_record = list() - if(security_person) - current_record["wanted"] = security_person.fields["criminal"] - - current_record["id"] = person.fields["id"] - current_record["name"] = person.fields["name"] - current_record["rank"] = person.fields["rank"] - current_record["gender"] = person.fields["gender"] - current_record["age"] = person.fields["age"] - current_record["species"] = person.fields["species"] - current_record["fingerprint"] = person.fields["fingerprint"] + current_record["age"] = person.age + current_record["fingerprint"] = person.fingerprint + current_record["gender"] = person.gender + current_record["name"] = person.name + current_record["rank"] = person.rank + current_record["species"] = person.species + current_record["wanted"] = person.wanted_status all_records += list(current_record) if("medical") - for(var/datum/data/record/person in GLOB.data_core.medical) + for(var/datum/record/crew/person in GLOB.manifest.general) var/list/current_record = list() - current_record["name"] = person.fields["name"] - current_record["bloodtype"] = person.fields["blood_type"] - current_record["mi_dis"] = person.fields["mi_dis"] - current_record["ma_dis"] = person.fields["ma_dis"] - current_record["notes"] = person.fields["notes"] - current_record["cnotes"] = person.fields["notes_d"] + current_record["bloodtype"] = person.blood_type + current_record["ma_dis"] = person.major_disabilities_desc + current_record["minor_disabilities"] = person.minor_disabilities_desc + current_record["name"] = person.name + current_record["notes"] = person.medical_notes all_records += list(current_record) diff --git a/code/modules/modular_computers/file_system/programs/robocontrol.dm b/code/modules/modular_computers/file_system/programs/robocontrol.dm index 80bba20cfd1..fe053b7cc25 100644 --- a/code/modules/modular_computers/file_system/programs/robocontrol.dm +++ b/code/modules/modular_computers/file_system/programs/robocontrol.dm @@ -121,7 +121,7 @@ if(!computer || !computer.computer_id_slot) return if(id_card) - GLOB.data_core.manifest_modify(id_card.registered_name, id_card.assignment, id_card.get_trim_assignment()) + GLOB.manifest.modify(id_card.registered_name, id_card.assignment, id_card.get_trim_assignment()) computer.RemoveID(usr) else playsound(get_turf(ui_host()) , 'sound/machines/buzz-sigh.ogg', 25, FALSE) diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm index 52327092e03..0c49a6b1cad 100644 --- a/code/modules/paperwork/filingcabinet.dm +++ b/code/modules/paperwork/filingcabinet.dm @@ -124,14 +124,13 @@ var/virgin = TRUE /obj/structure/filingcabinet/security/proc/populate() - if(virgin) - for(var/datum/data/record/G in GLOB.data_core.general) - var/datum/data/record/S = find_record("name", G.fields["name"], GLOB.data_core.security) - if(!S) - continue - print_security_record(G, S, src) - virgin = FALSE //tabbing here is correct- it's possible for people to try and use it - //before the records have been generated, so we do this inside the loop. + if(!virgin) + return + for(var/datum/record/crew/target in GLOB.manifest.general) + var/obj/item/paper/rapsheet = target.get_rapsheet() + rapsheet.forceMove(src) + virgin = FALSE //tabbing here is correct- it's possible for people to try and use it + //before the records have been generated, so we do this inside the loop. /obj/structure/filingcabinet/security/attack_hand(mob/user, list/modifiers) populate() @@ -149,24 +148,18 @@ var/virgin = TRUE /obj/structure/filingcabinet/medical/proc/populate() - if(virgin) - for(var/datum/data/record/G in GLOB.data_core.general) - var/datum/data/record/M = find_record("name", G.fields["name"], GLOB.data_core.medical) - if(!M) - continue - var/obj/item/paper/med_record_paper = new /obj/item/paper(src) - var/med_record_text = "
Medical Record

" - med_record_text += "Name: [G.fields["name"]] ID: [G.fields["id"]]
\nGender: [G.fields["gender"]]
\nAge: [G.fields["age"]]
\nFingerprint: [G.fields["fingerprint"]]
\nPhysical Status: [G.fields["p_stat"]]
\nMental Status: [G.fields["m_stat"]]
" - med_record_text += "
\n
Medical Data

\nBlood Type: [M.fields["blood_type"]]
\nDNA: [M.fields["b_dna"]]
\n
\nMinor Disabilities: [M.fields["mi_dis"]]
\nDetails: [M.fields["mi_dis_d"]]
\n
\nMajor Disabilities: [M.fields["ma_dis"]]
\nDetails: [M.fields["ma_dis_d"]]
\n
\nAllergies: [M.fields["alg"]]
\nDetails: [M.fields["alg_d"]]
\n
\nCurrent Diseases: [M.fields["cdi"]] (per disease info placed in log/comment section)
\nDetails: [M.fields["cdi_d"]]
\n
\nImportant Notes:
\n\t[M.fields["notes"]]
\n
\n
Comments/Log

" - var/counter = 1 - while(M.fields["com_[counter]"]) - med_record_text += "[M.fields["com_[counter]"]]
" - counter++ - med_record_text += "" - med_record_paper.add_raw_text(med_record_text) - med_record_paper.name = "paper - '[G.fields["name"]]'" - med_record_paper.update_appearance() - virgin = FALSE //tabbing here is correct- it's possible for people to try and use it + if(!virgin) + return + for(var/datum/record/crew/record in GLOB.manifest.general) + var/obj/item/paper/med_record_paper = new /obj/item/paper(src) + var/med_record_text = "
Medical Record

" + med_record_text += "Name: [record.name] Rank: [record.rank]
\nGender: [record.gender]
\nAge: [record.age]
" + med_record_text += "
\n
Medical Data

\nBlood Type: [record.blood_type]
\nDNA: [record.dna_string]
\n
\nMinor Disabilities: [record.minor_disabilities]
\nDetails: [record.minor_disabilities_desc]
\n
\nMajor Disabilities: [record.major_disabilities]
\nDetails: [record.major_disabilities_desc]
\n
\nImportant Notes:
\n\t[record.medical_notes]
\n
\n
Comments/Log

" + med_record_text += "" + med_record_paper.add_raw_text(med_record_text) + med_record_paper.name = "paper - '[record.name]'" + med_record_paper.update_appearance() + virgin = FALSE //tabbing here is correct- it's possible for people to try and use it //before the records have been generated, so we do this inside the loop. //ATTACK HAND IGNORING PARENT RETURN VALUE @@ -199,14 +192,10 @@ GLOBAL_LIST_EMPTY(employmentCabinets) /obj/structure/filingcabinet/employment/proc/fillCurrent() //This proc fills the cabinet with the current crew. - for(var/record in GLOB.data_core.locked) - var/datum/data/record/G = record - if(!G) - continue - var/datum/mind/M = G.fields["mindref"] - if(M && ishuman(M.current)) - addFile(M.current) - + for(var/datum/record/locked/target in GLOB.manifest.locked) + var/datum/mind/mind_ref = target.mind_ref + if(mind_ref && ishuman(mind_ref.current)) + addFile(mind_ref.current) /obj/structure/filingcabinet/employment/proc/addFile(mob/living/carbon/human/employee) new /obj/item/paper/employment_contract(src, employee.mind.name) diff --git a/tgstation.dme b/tgstation.dme index ac20961e6d9..32f9f83c076 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -635,7 +635,6 @@ #include "code\datums\callback.dm" #include "code\datums\chatmessage.dm" #include "code\datums\dash_weapon.dm" -#include "code\datums\datacore.dm" #include "code\datums\datum.dm" #include "code\datums\datumvars.dm" #include "code\datums\dna.dm" @@ -1309,6 +1308,11 @@ #include "code\datums\quirks\negative_quirks.dm" #include "code\datums\quirks\neutral_quirks.dm" #include "code\datums\quirks\positive_quirks.dm" +#include "code\datums\records\crime.dm" +#include "code\datums\records\data.dm" +#include "code\datums\records\manifest.dm" +#include "code\datums\records\medical_note.dm" +#include "code\datums\records\record.dm" #include "code\datums\ruins\icemoon.dm" #include "code\datums\ruins\lavaland.dm" #include "code\datums\ruins\space.dm" diff --git a/tgui/packages/tgui/interfaces/JobSelection.tsx b/tgui/packages/tgui/interfaces/JobSelection.tsx index 7dd1a8225ab..c3d1a89fc34 100644 --- a/tgui/packages/tgui/interfaces/JobSelection.tsx +++ b/tgui/packages/tgui/interfaces/JobSelection.tsx @@ -12,7 +12,6 @@ type Job = { command: BooleanLike; open_slots: number; used_slots: number; - icon: string; prioritized: BooleanLike; description: string; }; @@ -42,7 +41,7 @@ export const JobEntry: SFC<{ const jobName = data.jobName; const job = data.job; const department = data.department; - const jobIcon = job.icon || JOB2ICON[jobName] || null; + const jobIcon = JOB2ICON[jobName] || null; return (