diff --git a/code/controllers/subsystem/pai.dm b/code/controllers/subsystem/pai.dm index 906d714b03e3..c70749e719dd 100644 --- a/code/controllers/subsystem/pai.dm +++ b/code/controllers/subsystem/pai.dm @@ -9,27 +9,6 @@ SUBSYSTEM_DEF(pai) var/list/paicard_list = list() /datum/controller/subsystem/pai/Topic(href, href_list[]) - if(href_list["download"]) - var/datum/paiCandidate/candidate = locate(href_list["candidate"]) in candidates - var/obj/item/computer_hardware/paicard/card = locate(href_list["device"]) in paicard_list - if(card.pai) - return - if(istype(card, /obj/item/computer_hardware/paicard) && istype(candidate, /datum/paiCandidate)) - if(check_ready(candidate) != candidate) - return FALSE - var/mob/living/silicon/pai/pai = new(card) - if(!candidate.name) - pai.name = pick(GLOB.ninja_names) - else - pai.name = candidate.name - pai.real_name = pai.name - pai.key = candidate.key - - card.setPersonality(pai) - - candidates -= candidate - usr << browse(null, "window=findPai") - if(href_list["new"]) var/datum/paiCandidate/candidate = locate(href_list["candidate"]) in candidates var/option = href_list["option"] diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 04711dc951be..10b0409e546d 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -244,6 +244,9 @@ return TRUE if(unrestricted_side(M)) return TRUE + if(ispAI(M)) + var/mob/living/silicon/pai/P = M + return check_access(P.access_card) return ..() /// Returns the opposite of '/allowed', but makes exceptions for things like IsAdminGhost(). diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 9b220cb114a7..d4300d9a084d 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -7,7 +7,7 @@ hud_type = /datum/hud/pai pass_flags = PASSTABLE | PASSMOB mob_size = MOB_SIZE_TINY - desc = "A generic pAI mobile hard-light holographics emitter. It seems to be deactivated." + desc = "A generic pAI mobile hard-light holographics emitter. It seems to be activated." weather_immunities = WEATHER_STORM light_on = FALSE light_flags = LIGHT_ATTACHED @@ -23,53 +23,55 @@ var/network = "ss13" var/obj/machinery/camera/current = null - var/ram = 100 // Used as currency to purchase different abilities + ///Used as currency to purchase different abilities + var/ram = 100 var/list/software = list() - var/userDNA // The DNA string of our assigned user - var/obj/item/computer_hardware/paicard/card // The card we inhabit - var/hacking = FALSE //Are we hacking a door? + ///The DNA string of our assigned user + var/userDNA + ///The card we inhabit + var/obj/item/computer_hardware/paicard/card + ///Are we hacking a door? + var/hacking = FALSE var/speakStatement = "states" var/speakExclamation = "declares" var/speakDoubleExclamation = "alarms" var/speakQuery = "queries" - var/obj/item/pai_cable/cable // The cable we produce and use when door or camera jacking + ///The cable we produce and use when door or camera jacking + var/obj/item/pai_cable/cable - var/master // Name of the one who commands us - var/master_dna // DNA string for owner verification + ///Name of the one who commands us + var/master + ///DNA string for owner verification + var/master_dna // Various software-specific vars - var/temp // General error reporting text contained here will typically be shown once and cleared - var/screen // Which screen our main window displays - var/subscreen // Which specific function of the main screen is being displayed + ///The airlock being hacked + var/obj/machinery/door/hackdoor + ///Possible values: 0 - 100, >= 100 means the hack is complete and will be reset upon next check + var/hackprogress = 0 - var/secHUD = 0 // Toggles whether the Security HUD is active or not - var/medHUD = 0 // Toggles whether the Medical HUD is active or not - - var/datum/data/record/medicalActive1 // Datacore record declarations for record software - var/datum/data/record/medicalActive2 - - var/datum/data/record/securityActive1 // Could probably just combine all these into one - var/datum/data/record/securityActive2 - - var/obj/machinery/door/hackdoor // The airlock being hacked - var/hackprogress = 0 // Possible values: 0 - 100, >= 100 means the hack is complete and will be reset upon next check - - /// Remote signaler + ///Remote signaler var/obj/item/assembly/signaler/internal/signaler var/obj/item/instrument/piano_synth/internal_instrument - var/obj/machinery/newscaster //pAI Newscaster - var/obj/item/healthanalyzer/hostscan //pAI healthanalyzer + ///pAI Newscaster + var/obj/machinery/newscaster + ///pAI healthanalyzer + var/obj/item/healthanalyzer/hostscan + ///Whether the pAI has bought the encryption slot module or not var/encryptmod = FALSE var/holoform = FALSE + ///Can pAI use their holoprojector? var/canholo = TRUE + ///Can pAI transmit radio messages? var/can_transmit = TRUE + ///Can pAI receive radio messages? var/can_receive = TRUE - var/obj/item/card/id/access_card = null + var/obj/item/card/id/access_card = new /obj/item/card/id var/chassis = "repairbot" var/list/possible_chassis = list("cat" = TRUE, "mouse" = TRUE, "monkey" = TRUE, "corgi" = FALSE, "fox" = FALSE, "repairbot" = TRUE, "rabbit" = TRUE, "frog" = TRUE) //assoc value is whether it can be picked up. @@ -81,7 +83,8 @@ var/emittersemicd = FALSE var/overload_ventcrawl = 0 - var/overload_bulletblock = 0 //Why is this a good idea? + //Why is this a good idea? + var/overload_bulletblock = 0 var/overload_maxhealth = 0 var/silent = FALSE var/brightness_power = 5 @@ -127,7 +130,6 @@ . = ..() - create_modularInterface() emittersemicd = TRUE addtimer(CALLBACK(src, PROC_REF(emittercool)), 600) @@ -153,7 +155,6 @@ if(cable && cable.machine && istype(cable.machine, /obj/machinery/door) && cable.machine == hackdoor && get_dist(src, hackdoor) <= 1) hackprogress = clamp(hackprogress + 20, 0, 100) else - temp = "Door Jack: Connection to airlock has been lost. Hack aborted." hackprogress = 0 hacking = FALSE hackdoor = null @@ -282,7 +283,11 @@ /mob/living/silicon/pai/examine(mob/user) . = ..() - . += "A personal AI in holochassis mode. Its master ID string seems to be [master]." + . += "A personal AI in holochassis mode. Its master ID string seems to be [master ? master : "empty"]." + if(software && isobserver(user)) + . += "[src] has the following modules:" + for(var/module in software) + . += "[module]" /mob/living/silicon/pai/Life(seconds_per_tick = SSMOBS_DT, times_fired) if(stat == DEAD) @@ -307,12 +312,31 @@ emitterhealth = clamp((emitterhealth + (emitter_regen_per_second * delta_time)), -50, emittermaxhealth) /obj/item/computer_hardware/paicard/attackby(obj/item/W, mob/user, params) - ..() + . = ..() user.set_machine(src) - if(pai.encryptmod == TRUE) - if(W.tool_behaviour == TOOL_SCREWDRIVER) - pai.radio.attackby(W, user, params) - else if(istype(W, /obj/item/encryptionkey)) + if(W.tool_behaviour == TOOL_SCREWDRIVER||istype(W, /obj/item/encryptionkey)) + if(pai.encryptmod == TRUE) pai.radio.attackby(W, user, params) - else - to_chat(user, "Encryption Key ports not configured.") + else + to_chat(user, "Encryption Key ports not configured.") + else if(istype(W, /obj/item/card/id)) + var/obj/item/card/id/id_card = W + pai.copy_access(id_card, user) + +/mob/living/silicon/pai/attackby(obj/item/W, mob/user, params) + . = ..() + if(istype(W, /obj/item/card/id)) + var/obj/item/card/id/id_card = W + copy_access(id_card, user) + +/mob/living/silicon/pai/proc/copy_access(obj/item/card/id/ID, mob/user) + access_card.access += ID.access + to_chat(user, span_info("Copied access from [ID]!")) + to_chat(src, span_notice("Data transfer complete: New access encryption keys stored in memory.")) + +/mob/living/silicon/pai/Bump(atom/A) //Copied from bot.dm + . = ..() + if((istype(A, /obj/machinery/door/airlock) || istype(A, /obj/machinery/door/window)) && (!isnull(access_card))) + var/obj/machinery/door/D = A + if(D.check_access(access_card)) + D.open() diff --git a/code/modules/mob/living/silicon/pai/software.dm b/code/modules/mob/living/silicon/pai/software.dm index e8e0db8d1209..62d41b4d74a1 100644 --- a/code/modules/mob/living/silicon/pai/software.dm +++ b/code/modules/mob/living/silicon/pai/software.dm @@ -9,20 +9,21 @@ //T-Ray //radiation eyes //chem goggs - //mesons list("module_name" = "crew manifest", "tab"=FALSE, "cost" = 5), list("module_name" = "digital messenger", "tab"=FALSE, "cost" = 5), list("module_name" = "atmosphere sensor", "tab"=TRUE, "title"="Atmospheric sensor", "cost" = 5), list("module_name" = "photography module", "tab"=FALSE, "cost" = 5), list("module_name" = "remote signaller", "tab"=TRUE, "title"="Remote signaller", "cost" = 10), - //list("module_name" = "medical records", "tab"=TRUE, "title"="Medical records", "cost" = 10), - //list("module_name" = "security records", "tab"=TRUE, "title"="Security records", "cost" = 10), + list("module_name" = "medical records", "tab"=TRUE, "title"="Medical records", "cost" = 10), + list("module_name" = "security records", "tab"=TRUE, "title"="Security records", "cost" = 10), list("module_name" = "camera zoom", "tab"=FALSE, "cost" = 10), list("module_name" = "host scan", "tab"=TRUE, "title"="Host Bioscan settings", "cost" = 10), //"camera jack" = 10, //"heartbeat sensor" = 10, //"projection array" = 15, list("module_name" = "medical HUD", "tab"=FALSE, "cost" = 20), + list("module_name" = "meson HUD", "tab"=FALSE, "cost" = 20), + list("module_name" = "nightvision HUD", "tab"=FALSE, "cost" = 20), list("module_name" = "security HUD", "tab"=FALSE, "cost" = 20), list("module_name" = "loudness booster", "tab"=TRUE, "title"="Sound Synthesizer", "cost" = 20), list("module_name" = "newscaster", "tab"=FALSE, "cost" = 20), @@ -41,6 +42,11 @@ /mob/living/silicon/pai/var/cable_status = "Retracted" +/mob/living/silicon/pai/var/list/med_record = list() +/mob/living/silicon/pai/var/list/sec_record = list() +/mob/living/silicon/pai/var/selected_med_record +/mob/living/silicon/pai/var/selected_sec_record + /mob/living/silicon/pai/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) @@ -58,26 +64,46 @@ data["master"] = master data["masterdna"] = master_dna data["ram"] = ram - if(!isnull(environment)) - data["pressure"] = round(pressure,0.1) - data["gases"] = gases - data["temperature"] = round(environment.return_temperature()-T0C) - else - data["pressure"] = pressure - data["gases"] = gases - data["temperature"] = null + data["pressure"] = !isnull(environment) ? round(pressure,0.1) : pressure + data["gases"] = gases + data["temperature"] = !isnull(environment) ? round(environment.return_temperature()-T0C) : null data["hacking"] = hacking data["hackprogress"] = hackprogress data["cable"] = cable_status - if(isnull(cable)) - data["door"] = null - else - data["door"] = cable.machine + data["door"] = isnull(cable) ? null : cable.machine data["code"] = signaler.code data["frequency"] = signaler.frequency data["minFrequency"] = MIN_FREE_FREQ data["maxFrequency"] = MAX_FREE_FREQ data["color"] = signaler.label_color + if(GLOB.data_core.general && GLOB.data_core.medical) + med_record = list() //Important to reset it here so it doesn't readd records endlessly + for(var/datum/data/record/M in sortRecord(GLOB.data_core.medical)) + for(var/datum/data/record/R in sortRecord(GLOB.data_core.general)) + if(R.fields["id"] == M.fields["id"]) + var/list/new_record = list("name" = R.fields["name"], "id" = R.fields["id"], "gender" = R.fields["gender"], "age" = R.fields["age"], "fingerprint" = R.fields["fingerprint"], "p_state" = R.fields["p_stat"], "m_state" = R.fields["m_stat"], "blood_type" = M.fields["blood_type"], "dna" = M.fields["b_dna"], "minor_disabilities" = M.fields["mi_dis"], "minor_disabilities_details" = M.fields["mi_dis_d"], "major_disabilities" = M.fields["ma_dis"], "major_disabilities_details" = M.fields["ma_dis_d"], "allergies" = M.fields["alg"], "allergies_details" = M.fields["alg_d"], "current_diseases" = M.fields["cdi"], "current_diseases_details" = M.fields["cdi_d"], "important_notes" = M.fields["notes"]) + med_record += list(new_record) + break + if(GLOB.data_core.general && GLOB.data_core.security) + sec_record = list() + for(var/datum/data/record/S in sortRecord(GLOB.data_core.security)) + for(var/datum/data/record/R in sortRecord(GLOB.data_core.general)) + if(R.fields["id"] == S.fields["id"]) + var/list/crimes = list() + for(var/datum/data/crime/crime in S.fields["crimes"]) + crime = list("crime_name" = crime.crimeName, "crime_details" = crime.crimeDetails, "author" = crime.author, "time_added" = crime.time) + crimes += list(crime) + var/list/comments = list() + for(var/datum/data/comment/comment in S.fields["comments"]) + comment = list("comment_text" = comment.commentText, "author" = comment.author, "time" = comment.time) + comments += list(comment) + var/list/new_record = list("name" = R.fields["name"], "id" = R.fields["id"], "gender" = R.fields["gender"], "age" = R.fields["age"], "rank" = R.fields["rank"], "fingerprint" = R.fields["fingerprint"], "p_state" = R.fields["p_stat"], "m_state" = R.fields["m_stat"], "criminal_status" = S.fields["criminal"], "crimes" = crimes, "important_notes" = S.fields["notes"], "comments" = comments) + sec_record += list(new_record) + break + data["med_records"] = med_record + data["sec_records"] = sec_record + data["selected_med_record"] = selected_med_record + data["selected_sec_record"] = selected_sec_record return data /mob/living/silicon/pai/ui_act(action, params) @@ -89,7 +115,6 @@ CheckDNA(get(card, /mob/living/carbon/human), src) //you should only be able to check when directly in hand, muh immersions? else to_chat(src, "You are not being carried by anyone!") - return 0 // FALSE ? If you return here you won't call paiinterface() below if("update_image") card.setEmotion(params["updated_image"]) if("buy") @@ -99,9 +124,15 @@ return software.Add(params["name"]) ram -= params["cost"] + if(params["name"] == "digital messenger") + create_modularInterface() if(params["name"] == "medical HUD") var/datum/atom_hud/med = GLOB.huds[med_hud] med.show_to(src) + if(params["name"] == "meson HUD") + sight |= SEE_TURFS + if(params["name"] == "nightvision HUD") + lighting_cutoff = LIGHTING_CUTOFF_HIGH if(params["name"] == "security HUD") var/datum/atom_hud/sec = GLOB.huds[sec_hud] sec.show_to(src) @@ -178,6 +209,8 @@ internal_instrument = new(src) internal_instrument.interact(src) if("cable") + if(cable_status == "Extended") + return var/turf/T = get_turf(loc) cable = new /obj/item/pai_cable(T) if(get(card, /mob/living/carbon/human)) @@ -198,6 +231,42 @@ hackdoor = null cable = null cable_status = "Retracted" + if("med_record") + if(!GLOB.data_core.general||!GLOB.data_core.medical) + return + for(var/datum/data/record/M in sortRecord(GLOB.data_core.medical)) + var/done = FALSE + for(var/datum/data/record/R in sortRecord(GLOB.data_core.general)) + if(M.fields["id"] == params["record"]) + selected_med_record = list("name" = R.fields["name"], "id" = R.fields["id"], "gender" = R.fields["gender"], "age" = R.fields["age"], "fingerprint" = R.fields["fingerprint"], "p_state" = R.fields["p_stat"], "m_state" = R.fields["m_stat"], "blood_type" = M.fields["blood_type"], "dna" = M.fields["b_dna"], "minor_disabilities" = M.fields["mi_dis"], "minor_disabilities_details" = M.fields["mi_dis_d"], "major_disabilities" = M.fields["ma_dis"], "major_disabilities_details" = M.fields["ma_dis_d"], "allergies" = M.fields["alg"], "allergies_details" = M.fields["alg_d"], "current_diseases" = M.fields["cdi"], "current_diseases_details" = M.fields["cdi_d"], "important_notes" = M.fields["notes"]) + done = TRUE + break + if(done) + break + if("med_record back") + selected_med_record = null + if("sec_record") + if(!GLOB.data_core.general||!GLOB.data_core.medical) + return + for(var/datum/data/record/S in sortRecord(GLOB.data_core.security)) + var/done = FALSE + for(var/datum/data/record/R in sortRecord(GLOB.data_core.general)) + if(S.fields["id"] == params["record"]) + var/list/crimes = list() + for(var/datum/data/crime/crime in S.fields["crimes"]) + crime = list("crime_name" = crime.crimeName, "crime_details" = crime.crimeDetails, "author" = crime.author, "time_added" = crime.time) + crimes += list(crime) + var/list/comments = list() + for(var/datum/data/comment/comment in S.fields["comments"]) + comment = list("comment_text" = comment.commentText, "author" = comment.author, "time" = comment.time) + comments += list(comment) + selected_sec_record = list("name" = R.fields["name"], "id" = R.fields["id"], "gender" = R.fields["gender"], "age" = R.fields["age"], "rank" = R.fields["rank"], "fingerprint" = R.fields["fingerprint"], "p_state" = R.fields["p_stat"], "m_state" = R.fields["m_stat"], "criminal_status" = S.fields["criminal"], "crimes" = crimes, "important_notes" = S.fields["notes"], "comments" = comments) + done = TRUE + break + if(done) + break + if("sec_record back") + selected_sec_record = null update_appearance(UPDATE_ICON) /mob/living/silicon/pai/ui_state(mob/user) @@ -224,63 +293,6 @@ else to_chat(P, "[M] does not seem like [M.p_theyre()] going to provide a DNA sample willingly.") -//Leaving the medical & security records stuff commented out till they can be added back -// -//// Medical Records -///mob/living/silicon/pai/proc/softwareMedicalRecord() -// switch(subscreen) -// if(0) -// . += "

Medical Records


" -// if(GLOB.data_core.general) -// for(var/datum/data/record/R in sortRecord(GLOB.data_core.general)) -// . += "[R.fields["id"]]: [R.fields["name"]]
" -// if(1) -// . += "
Medical Record

" -// if(medicalActive1 in GLOB.data_core.general) -// . += "Name: [medicalActive1.fields["name"]] ID: [medicalActive1.fields["id"]]
\nGender: [medicalActive1.fields["gender"]]
\nAge: [medicalActive1.fields["age"]]
\nFingerprint: [medicalActive1.fields["fingerprint"]]
\nPhysical Status: [medicalActive1.fields["p_stat"]]
\nMental Status: [medicalActive1.fields["m_stat"]]
" -// else -// . += "
Requested medical record not found.

" -// if(medicalActive2 in GLOB.data_core.medical) -// . += "
\n
Medical Data

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

" -// else -// . += "
Requested medical record not found.

" -// . += "
\nBack
" -// return . -// -//// Security Records -///mob/living/silicon/pai/proc/softwareSecurityRecord() -// . = "" -// switch(subscreen) -// if(0) -// . += "

Security Records


" -// if(GLOB.data_core.general) -// for(var/datum/data/record/R in sortRecord(GLOB.data_core.general)) -// . += "[R.fields["id"]]: [R.fields["name"]]
" -// if(1) -// . += "

Security Record

" -// if(securityActive1 in GLOB.data_core.general) -// . += "Name:
[securityActive1.fields["name"]] ID: [securityActive1.fields["id"]]
\nGender: [securityActive1.fields["gender"]]
\nAge: [securityActive1.fields["age"]]
\nRank: [securityActive1.fields["rank"]]
\nFingerprint: [securityActive1.fields["fingerprint"]]
\nPhysical Status: [securityActive1.fields["p_stat"]]
\nMental Status: [securityActive1.fields["m_stat"]]
" -// else -// . += "
Requested security record not found,

" -// if(securityActive2 in GLOB.data_core.security) -// . += "
" -// . += "Security Data
" -// . += "Criminal Status: [securityActive2.fields["criminal"]]

" -// . += "Crimes:
" -// for(var/datum/data/crime/crime in securityActive2.fields["crimes"]) -// . += "\t[crime.crimeName]: [crime.crimeDetails]
" -// . += "
" -// . += "Important Notes:
" -// . += "\t[securityActive2.fields["notes"]]

" -// . += "
Comments/Log

" -// for(var/datum/data/comment/comment in securityActive2.fields["comments"]) -// . += "\t[comment.commentText] - [comment.author] [comment.time]
" -// else -// . += "
Requested security record not found,

" -// . += "
\nBack
" -// return . -// -// //// Camera Jack - Clearly not finished ///mob/living/silicon/pai/proc/softwareCamera() // var/dat = "

Camera Jack

" diff --git a/code/modules/modular_computers/hardware/paicard.dm b/code/modules/modular_computers/hardware/paicard.dm index 90af65421fb9..b0de370b7f47 100644 --- a/code/modules/modular_computers/hardware/paicard.dm +++ b/code/modules/modular_computers/hardware/paicard.dm @@ -88,6 +88,7 @@ if("wipe") var/confirm = tgui_alert(usr, "Are you CERTAIN you wish to delete the current personality? This action cannot be undone.", "Personality Wipe", list("Yes", "No")) if(confirm == "Yes") + candidates_ready = null if(pai) to_chat(pai, span_warning("You feel yourself slipping away from reality.")) to_chat(pai, span_danger("Byte by byte you lose your sense of self.")) @@ -117,8 +118,9 @@ pai.key = candidate.key card.setPersonality(pai) + SSpai.candidates.Remove(candidate) candidate = list("name" = candidate.name, "description"=candidate.description, "prefrole"=candidate.role, "ooccomments"=candidate.comments) - candidates.Remove(list(candidate)) + candidates.Remove(candidate) if("setlaws") var/newlaw = stripped_multiline_input(usr, "Enter any additional directives you would like your pAI personality to follow. Note that these directives will not override the personality's allegiance to its imprinted master. Conflicting directives will be ignored.", "pAI Directive Configuration", pai.laws.supplied[1], MAX_MESSAGE_LEN) if(newlaw && pai) diff --git a/tgui/packages/tgui/interfaces/PaiInterface.tsx b/tgui/packages/tgui/interfaces/PaiInterface.tsx index dd394697aacf..489c55c9d25f 100644 --- a/tgui/packages/tgui/interfaces/PaiInterface.tsx +++ b/tgui/packages/tgui/interfaces/PaiInterface.tsx @@ -1,7 +1,7 @@ import { toFixed } from 'common/math'; import { capitalize } from 'common/string'; import { useBackend, useLocalState } from '../backend'; -import { Box, Button, Section, Flex, Tabs, Stack, BlockQuote, Table, Dropdown, ProgressBar, NumberInput } from '../components'; +import { Box, Button, Section, Flex, Tabs, Stack, BlockQuote, Table, Dropdown, ProgressBar, NumberInput, Icon } from '../components'; import { Window } from '../layouts'; type Module = { @@ -10,8 +10,58 @@ type Module = { cost: number; } +type MedRecord = { /* This should probably be cut down, but it's all valid medical record information */ + name: string; + id: string; + gender: string; + age: number; + fingerprint: string; + p_state: string; + m_state: string; + blood_type: string; + dna: string; + minor_disabilities: string; + minor_disabilities_details: string; + major_disabilities: string; + major_disabilities_details: string; + allergies: string; + allergies_details: string; + current_diseases: string; + current_diseases_details: string; + important_notes: string; + comments: string[]; +} + +type SecRecord = { + name: string; + id: string; + gender: string; + age: number; + rank: string; + fingerprint: string; + p_state: string; + m_state: string; + criminal_status: string; + crimes: Crime[]; + important_notes: string; + comments: Comment[]; +} + +type Crime = { + crime_name: string; + crime_details: string; + author: string; + time_added: string; +} + +type Comment = { + comment_text: string; + author: string; + time: string; +} + type Data = { - modules: Data[]; + modules: string[]; modules_list: Module[]; modules_tabs: Module[]; laws_zeroth: string; @@ -31,9 +81,13 @@ type Data = { minFrequency: number; maxFrequency: number; color: string; + med_records: MedRecord[]; + sec_records: SecRecord[]; + selected_med_record: MedRecord; + selected_sec_record: SecRecord; } -export const AirlockJackTextSwitch = params => { +const AirlockJackTextSwitch = params => { switch (params) { case 0: return "Connection handshake"; @@ -48,12 +102,66 @@ export const AirlockJackTextSwitch = params => { } }; +export const MedRecordColour = (mental, physical) => { + if(mental === "*Insane*"||physical === "*Deceased*") { + return "#990000;"; + } else if(mental === "*Unstable*"||physical === "*Unconscious*") { + return "#CD6500;"; + } else if(mental === "*Watch*"||physical === "Physically Unfit") { + return "#3BB9FF;"; + } else { + return "#4F7529;"; + } +}; + +export const SecRecordColour = criminal_status => { + switch (criminal_status) { + case "Arrest": + return "#990000;"; + case "Discharged": + return "#5C4949;"; + case "None": + return "#740349;"; + case "Search": + return "#5C4949;"; + case "Parole": + return "#046713;"; + case "Incarcerated": + return "#181818;"; + case "Suspected": + return "#CD6500;"; + } +}; + +const SecRecordIcon = criminal_status => { + switch (criminal_status) { + case "Arrest": + return "fingerprint"; + case "Discharged": + return "dove"; + case "None": + return ""; + case "Search": + return "search"; + case "Parole": + return "unlink"; + case "Incarcerated": + return "dungeon"; + case "Suspected": + return "exclamation"; + } + return ""; +}; + +let custom_width; +custom_width = 650; + export const PaiInterface = (props, context) => { const { act, data } = useBackend(context); const { modules_tabs = [] } = data; const [selectedMainTab, setMainTab] = useLocalState(context, "selectedMainTab", 0); return ( - + {/* Width matters for records, height matters for download more software */} @@ -87,6 +195,18 @@ const PaiBox = (props, context) => { const { pressure, gases, temperature } = data; const { hacking, hackprogress, cable, door } = data; const { code, frequency, minFrequency, maxFrequency, color } = data; + const { med_records, sec_records } = data; + const { selected_med_record, selected_sec_record } = data; + switch(modules_tabs[selectedMainTab].module_name) { // To actually make records readable without extending every other module unnecessarily + case "medical records": + custom_width = 960; + break; + case "security records": + custom_width = 960; + break; + default: + custom_width = 650; + } switch(modules_tabs[selectedMainTab].module_name) { case "directives": return ( @@ -240,72 +360,361 @@ const PaiBox = (props, context) => { case "remote signaller": return (
- - - Frequency: - toFixed(value, 1)} - width="80px" - onDrag={(e, value) => act('signallerfreq', { - freq: value, - })} /> -
); + case "medical records": + if(selected_med_record) { + return ( +
+ + + + Name: {selected_med_record.name} + + + ID: {selected_med_record.id} + + + Gender: {selected_med_record.gender} + + + Physical status: {selected_med_record.p_state} + + + Mental status: {selected_med_record.m_state} + + + Blood type: {selected_med_record.blood_type} + + + DNA: {selected_med_record.dna} + +
+ + Minor disabilities: {selected_med_record.minor_disabilities} + + + Details: {selected_med_record.minor_disabilities_details} + + + Major disabilities: {selected_med_record.major_disabilities} + + + Details: {selected_med_record.major_disabilities_details} + + + Allergies: {selected_med_record.allergies} + + + Details: {selected_med_record.allergies_details} + + + Current diseases: {selected_med_record.current_diseases} + + + Details: {selected_med_record.current_diseases_details} + + + Important notes: {selected_med_record.important_notes} + + + Comments: {selected_med_record.comments} + +
+
+ ); + } else { + return ( +
+ + + + Name: + + + ID: + + + Fingerprints (F) | DNA (D): + + + Blood type: + + + Physical status: + + + Mental status: + + + {med_records.map(MedRecord => ( + + + + + + {MedRecord.id} + + + F: {MedRecord.fingerprint} + D: {MedRecord.dna} + + + {MedRecord.blood_type} + + + {MedRecord.p_state} + + + {MedRecord.m_state} + + + ))} +
+
+ ); + } + case "security records": + if(selected_sec_record) { + const { crimes } = data.selected_sec_record; + const { comments } = data.selected_sec_record; + return ( +
+ + + + Name: {selected_sec_record.name} + + + ID: {selected_sec_record.id} + + + Gender: {selected_sec_record.gender} + + + Age: {selected_sec_record.age} + + + Rank: {selected_sec_record.rank} + + + Fingerprint: {selected_sec_record.fingerprint} + + + Physical Status: {selected_sec_record.p_state} + + + Mental Status: {selected_sec_record.m_state} + +
+ + Criminal Status: + +
+ + + + Crime: + + + Details: + + + Author: + + + Time Added: + + + {crimes.map(crime => ( + + + {crime.crime_name} + + + {crime.crime_details} + + + {crime.author} + + + {crime.time_added} + + + ))} +
+
+ + + + Comment: + + + Author: + + + Time Added: + + + {comments.map(comment => ( + + + {comment.comment_text} + + + {comment.author} + + + {comment.time} + + + ))} +
+
+
+ ); + } else { + return ( +
+ + + + Name: + + + ID: + + + Rank: + + + Fingerprints: + + + Criminal Status: + + + {sec_records.map(SecRecord => ( + + + + + + {SecRecord.id} + + + {SecRecord.rank} + + + {SecRecord.fingerprint} + + + + {SecRecord.criminal_status} + + {SecRecordIcon(SecRecord.criminal_status) && ( + + + + )} + + + ))} +
+
+ ); + } case "host scan": return (
@@ -403,5 +812,5 @@ const PaiBox = (props, context) => { ); } } - return null; + return null; // Necessary to avoid "PaiBox cannot be used as a JSX Element. It's Return type 'Element | Undefined' is not a valid JSX component" runtiming };