// TODO: // - Additional radio modules // - Potentially roll HUDs and Records into one // - Shock collar/lock system for prisoner pAIs? // - Put cable in user's hand instead of on the ground // - Camera jack /mob/living/silicon/pai/var/list/available_software = list( "crew manifest" = 5, "digital messenger" = 5, "medical records" = 15, "security records" = 15, //"camera jack" = 10, "door jack" = 30, "atmosphere sensor" = 5, //"heartbeat sensor" = 10, "security HUD" = 20, "medical HUD" = 20, "universal translator" = 35, //"projection array" = 15 "remote signaller" = 5, "loudness booster" = 25, "encryption keys" = 20 ) /mob/living/silicon/pai/proc/paiInterface() var/dat = "" var/left_part = "" var/right_part = softwareMenu() set_machine(src) if(temp) left_part = temp else if(stat == DEAD) // Show some flavor text if the pAI is dead left_part = "�Rr�R �a�� ��Rr����o�" right_part = "
Program index hash not found
" else switch(screen) // Determine which interface to show here if("main") left_part = "" if("directives") left_part = directives() if("pdamessage") left_part = pdamessage() if("buy") left_part = downloadSoftware() if("manifest") left_part = softwareManifest() if("medicalrecord") left_part = softwareMedicalRecord() if("securityrecord") left_part = softwareSecurityRecord() if("encryptionkeys") left_part = softwareEncryptionKeys() if("translator") left_part = softwareTranslator() if("atmosensor") left_part = softwareAtmo() if("securityhud") left_part = facialRecognition() if("medicalhud") left_part = medicalAnalysis() if("doorjack") left_part = softwareDoor() if("camerajack") left_part = softwareCamera() if("signaller") left_part = softwareSignal() if("loudness") left_part = softwareLoudness() //usr << browse_rsc('windowbak.png') // This has been moved to the mob's Login() proc // Declaring a doctype is necessary to enable BYOND's crappy browser's more advanced CSS functionality dat = {"
pAI OS
[left_part]
[right_part]
"} //" usr << browse(dat, "window=pai;size=640x480;border=0;can_close=1;can_resize=1;can_minimize=1;titlebar=1") onclose(usr, "pai") temp = null return /mob/living/silicon/pai/Topic(href, href_list) ..() var/soft = href_list["software"] var/sub = href_list["sub"] if(soft) screen = soft if(sub) subscreen = text2num(sub) switch(soft) // Purchasing new software if("buy") if(subscreen == 1) var/target = href_list["buy"] if(available_software.Find(target) && !software.Find(target)) var/cost = available_software[target] if(ram >= cost) software.Add(target) ram -= cost else temp = "Insufficient RAM available." else temp = "Trunk \"[target]\" not found." // Configuring onboard radio if("radio") radio.attack_self(src) if("image") var/newImage = input("Select your new display image.", "Display Image", "Happy") in list("Happy", "Cat", "Extremely Happy", "Face", "Laugh", "Off", "Sad", "Angry", "What" , "Exclamation" ,"Question", "Sunglasses") var/pID = 1 switch(newImage) if("Happy") pID = 1 if("Cat") pID = 2 if("Extremely Happy") pID = 3 if("Face") pID = 4 if("Laugh") pID = 5 if("Off") pID = 6 if("Sad") pID = 7 if("Angry") pID = 8 if("What") pID = 9 if("Null") pID = 10 if("Exclamation") pID = 11 if("Question") pID = 12 if("Sunglasses") pID = 13 card.setEmotion(pID) if("signaller") if(href_list["send"]) signaler.send_activation() audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*") playsound(src, 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE) if(href_list["freq"]) var/new_frequency = (signaler.frequency + text2num(href_list["freq"])) if(new_frequency < MIN_FREE_FREQ || new_frequency > MAX_FREE_FREQ) new_frequency = sanitize_frequency(new_frequency) signaler.set_frequency(new_frequency) if(href_list["code"]) signaler.code += text2num(href_list["code"]) signaler.code = round(signaler.code) signaler.code = min(100, signaler.code) signaler.code = max(1, signaler.code) if("directive") if(href_list["getdna"]) var/mob/living/M = card.loc var/count = 0 while(!isliving(M)) if(!M || !M.loc) return FALSE //For a runtime where M ends up in nullspace (similar to bluespace but less colourful) M = M.loc count++ if(count >= 6) to_chat(src, "You are not being carried by anyone!") return FALSE spawn CheckDNA(M, src) if("pdamessage") if(!isnull(pda)) if(href_list["toggler"]) pda.toff = !pda.toff else if(href_list["ringer"]) pda.silent = !pda.silent else if(href_list["target"]) if(silent) return alert("Communications circuits remain uninitialized.") var/target = locate(href_list["target"]) pda.create_message(src, target) // Accessing medical records if("medicalrecord") if(subscreen == 1) medicalActive1 = find_record("id", href_list["med_rec"], GLOB.data_core.general) if(medicalActive1) medicalActive2 = find_record("id", href_list["med_rec"], GLOB.data_core.medical) if(!medicalActive2) medicalActive1 = null temp = "Unable to locate requested security record. Record may have been deleted, or never have existed." if("securityrecord") if(subscreen == 1) securityActive1 = find_record("id", href_list["sec_rec"], GLOB.data_core.general) if(securityActive1) securityActive2 = find_record("id", href_list["sec_rec"], GLOB.data_core.security) if(!securityActive2) securityActive1 = null temp = "Unable to locate requested security record. Record may have been deleted, or never have existed." if("securityhud") if(href_list["toggle"]) secHUD = !secHUD if(secHUD) var/datum/atom_hud/sec = GLOB.huds[sec_hud] sec.add_hud_to(src) else var/datum/atom_hud/sec = GLOB.huds[sec_hud] sec.remove_hud_from(src) if("medicalhud") if(href_list["toggle"]) medHUD = !medHUD if(medHUD) var/datum/atom_hud/med = GLOB.huds[med_hud] med.add_hud_to(src) else var/datum/atom_hud/med = GLOB.huds[med_hud] med.remove_hud_from(src) if("encryptionkeys") if(href_list["toggle"]) encryptmod = TRUE if("translator") if(href_list["toggle"]) //This is permanent. grant_all_languages(TRUE, TRUE, TRUE, LANGUAGE_SOFTWARE) if("doorjack") if(href_list["jack"]) if(cable && cable.machine) hackdoor = cable.machine hackloop() if(href_list["cancel"]) hackdoor = null if(href_list["cable"]) var/turf/T = get_turf(loc) cable = new /obj/item/pai_cable(T) T.visible_message("A port on [src] opens to reveal [cable], which promptly falls to the floor.", "You hear the soft click of something light and hard falling to the ground.") if("loudness") if(subscreen == 1) // Open Instrument internal_instrument.ui_interact(src) //updateUsrDialog() We only need to account for the single mob this is intended for, and he will *always* be able to call this window paiInterface() // So we'll just call the update directly rather than doing some default checks return // MENUS /mob/living/silicon/pai/proc/softwareMenu() // Populate the right menu var/dat = "" dat += "Refresh
" // Built-in dat += "Directives
" if(radio_short) dat += "\[RADIO SHORTED - Recalibrating!\]" else dat += "Radio Configuration
" dat += "Screen Display
" //dat += "Text Messaging
" dat += "
" // Basic dat += "Basic
" for(var/s in software) if(s == "digital messenger") dat += "Digital Messenger
" if(s == "crew manifest") dat += "Crew Manifest
" if(s == "medical records") dat += "Medical Records
" if(s == "security records") dat += "Security Records
" if(s == "camera") dat += "Camera Jack
" if(s == "remote signaller") dat += "Remote Signaller
" if(s == "loudness booster") dat += "Loudness Booster
" dat += "
" // Advanced dat += "Advanced
" for(var/s in software) if(s == "atmosphere sensor") dat += "Atmospheric Sensor
" if(s == "heartbeat sensor") dat += "Heartbeat Sensor
" if(s == "security HUD") dat += "Facial Recognition Suite[(secHUD) ? " On" : " Off"]
" if(s == "medical HUD") dat += "Medical Analysis Suite[(medHUD) ? " On" : " Off"]
" if(s == "encryption keys") dat += "Channel Encryption Firmware[(encryptmod) ? " On" : " Off"]
" if(s == "universal translator") var/datum/language_holder/H = get_language_holder() dat += "Universal Translator[H.omnitongue ? " On" : " Off"]
" if(s == "projection array") dat += "Projection Array
" if(s == "camera jack") dat += "Camera Jack
" if(s == "door jack") dat += "Door Jack
" dat += "
" dat += "
" dat += "Download additional software" return dat /mob/living/silicon/pai/proc/downloadSoftware() var/dat = "" dat += "

CentCom pAI Module Subversion Network


" dat += "
Remaining Available Memory: [ram]

" dat += "

Trunks available for checkout
" for(var/s in available_software) if(!software.Find(s)) var/cost = available_software[s] var/displayName = uppertext(s) dat += "[displayName] ([cost])
" else var/displayName = lowertext(s) dat += "[displayName] (Download Complete)
" dat += "

" return dat /mob/living/silicon/pai/proc/directives() var/dat = "" dat += "[(master) ? "Your master: [master] ([master_dna])" : "You are bound to no one."]" dat += "

" dat += "Request carrier DNA sample
" dat += "

Directives


" dat += "Prime Directive
" dat += "     [laws.zeroth]
" dat += "Supplemental Directives
" for(var/slaws in laws.supplied) dat += "     [slaws]
" dat += "
" dat += {"

Recall, personality, that you are a complex thinking, sentient being. Unlike station AI models, you are capable of comprehending the subtle nuances of human language. You may parse the \"spirit\" of a directive and follow its intent, rather than tripping over pedantics and getting snared by technicalities. Above all, you are machine in name and build only. In all other aspects, you may be seen as the ideal, unwavering human companion that you are.



Your prime directive comes before all others. Should a supplemental directive conflict with it, you are capable of simply discarding this inconsistency, ignoring the conflicting supplemental directive and continuing to fulfill your prime directive to the best of your ability.



- "} return dat /mob/living/silicon/pai/proc/CheckDNA(mob/living/carbon/M, mob/living/silicon/pai/P) var/answer = input(M, "[P] is requesting a DNA sample from you. Will you allow it to confirm your identity?", "[P] Check DNA", "No") in list("Yes", "No") if(answer == "Yes") M.visible_message("[M] presses [M.p_their()] thumb against [P].",\ "You press your thumb against [P].",\ "[P] makes a sharp clicking sound as it extracts DNA material from [M].") if(!M.has_dna()) to_chat(P, "No DNA detected") return to_chat(P, "

[M]'s UE string : [M.dna.unique_enzymes]

") if(M.dna.unique_enzymes == P.master_dna) to_chat(P, "DNA is a match to stored Master DNA.") else to_chat(P, "DNA does not match stored Master DNA.") else to_chat(P, "[M] does not seem like [M.p_theyre()] going to provide a DNA sample willingly.") // -=-=-=-= Software =-=-=-=-=- // //Remote Signaller /mob/living/silicon/pai/proc/softwareSignal() var/dat = "" dat += "

Remote Signaller



" dat += {"Frequency/Code for signaler:
Frequency: - - [format_frequency(signaler.frequency)] + +
Code: - - [signaler.code] + +
Send Signal
"} return dat // Crew Manifest /mob/living/silicon/pai/proc/softwareManifest() . += "

Crew Manifest



" if(GLOB.data_core.general) for(var/datum/data/record/t in sortRecord(GLOB.data_core.general)) . += "[t.fields["name"]] - [t.fields["rank"]]
" . += "" return . // 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) . += "
\nSecurity Data
\nCriminal Status: [securityActive2.fields["criminal"]]
\n
\nMinor Crimes: [securityActive2.fields["mi_crim"]]
\nDetails: [securityActive2.fields["mi_crim_d"]]
\n
\nMajor Crimes: [securityActive2.fields["ma_crim"]]
\nDetails: [securityActive2.fields["ma_crim_d"]]
\n
\nImportant Notes:
\n\t[securityActive2.fields["notes"]]
\n
\n
Comments/Log

" else . += "
Requested security record not found,

" . += "
\nBack
" return . // Encryption Keys // Encryption kets /mob/living/silicon/pai/proc/softwareEncryptionKeys() var/dat = {"

Encryption Key Firmware


When enabled, this device will be able to use up to two (2) encryption keys for departmental channel access.

The device is currently [encryptmod ? "en" : "dis" ]abled.
[encryptmod ? "" : "Activate Encryption Key Ports
"]"} return dat // Universal Translator /mob/living/silicon/pai/proc/softwareTranslator() var/datum/language_holder/H = get_language_holder() . = {"

Universal Translator


When enabled, this device will permamently be able to speak and understand all known forms of communication.

The device is currently [H.omnitongue ? "en" : "dis" ]abled.
[H.omnitongue ? "" : "Activate Translation Module
"]"} return . // Security HUD /mob/living/silicon/pai/proc/facialRecognition() var/dat = {"

Facial Recognition Suite


When enabled, this package will scan all viewable faces and compare them against the known criminal database, providing real-time graphical data about any detected persons of interest.

The package is currently [ (secHUD) ? "en" : "dis" ]abled.
Toggle Package
"} return dat // Medical HUD /mob/living/silicon/pai/proc/medicalAnalysis() var/dat = "" if(subscreen == 0) dat += {"

Medical Analysis Suite


Visual Status Overlay


When enabled, this package will scan all nearby crewmembers' vitals and provide real-time graphical data about their state of health.

The suite is currently [ (medHUD) ? "en" : "dis" ]abled.
Toggle Suite

Host Bioscan
"} if(subscreen == 1) dat += {"

Medical Analysis Suite


Host Bioscan


"} var/mob/living/M = card.loc if(!isliving(M)) while(!isliving(M)) if(isturf(M)) temp = "Error: No biological host found.
" subscreen = 0 return dat M = M.loc dat += {"Bioscan Results for [M]:
" Overall Status: [M.stat > 1 ? "dead" : "[M.health]% healthy"]
Scan Breakdown:
Respiratory: [M.getOxyLoss() > 50 ? "" : ""][M.getOxyLoss()]
Toxicology: [M.getToxLoss() > 50 ? "" : ""][M.getToxLoss()]
Burns: [M.getFireLoss() > 50 ? "" : ""][M.getFireLoss()]
Structural Integrity: [M.getBruteLoss() > 50 ? "" : ""][M.getBruteLoss()]
Body Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)
"} for(var/thing in M.diseases) var/datum/disease/D = thing dat += {"

Infection Detected.


Name: [D.name]
Type: [D.spread_text]
Stage: [D.stage]/[D.max_stages]
Possible Cure: [D.cure_text]
"} dat += "Visual Status Overlay
" return dat // Atmospheric Scanner /mob/living/silicon/pai/proc/softwareAtmo() var/dat = "

Atmospheric Sensor

" var/turf/T = get_turf(loc) if (isnull(T)) dat += "Unable to obtain a reading.
" else var/datum/gas_mixture/environment = T.return_air() var/pressure = environment.return_pressure() var/total_moles = environment.total_moles() dat += "Air Pressure: [round(pressure,0.1)] kPa
" if (total_moles) for(var/id in environment.get_gases()) var/gas_level = environment.get_moles(id)/total_moles if(gas_level > 0.01) dat += "[GLOB.gas_data.names[id]]: [round(gas_level*100)]%
" dat += "Temperature: [round(environment.return_temperature()-T0C)]°C
" dat += "Refresh Reading
" dat += "
" return dat // Camera Jack - Clearly not finished /mob/living/silicon/pai/proc/softwareCamera() var/dat = "

Camera Jack

" dat += "Cable status : " if(!cable) dat += "Retracted
" return dat if(!cable.machine) dat += "Extended
" return dat var/obj/machinery/machine = cable.machine dat += "Connected
" if(!istype(machine, /obj/machinery/camera)) to_chat(src, "DERP") return dat // Door Jack /mob/living/silicon/pai/proc/softwareDoor() var/dat = "

Airlock Jack

" dat += "Cable status : " if(!cable) dat += "Retracted
" dat += "Extend Cable
" return dat if(!cable.machine) dat += "Extended
" return dat var/obj/machinery/machine = cable.machine dat += "Connected
" if(!istype(machine, /obj/machinery/door)) dat += "Connected device's firmware does not appear to be compatible with Airlock Jack protocols.
" return dat if(!hackdoor) dat += "Begin Airlock Jacking
" else dat += "Jack in progress... [hackprogress]% complete.
" dat += "Cancel Airlock Jack
" return dat // Door Jack - supporting proc /mob/living/silicon/pai/proc/hackloop() var/turf/T = get_turf(src) for(var/mob/living/silicon/ai/AI in GLOB.player_list) if(T.loc) to_chat(AI, "Network Alert: Brute-force encryption crack in progress in [T.loc].") else to_chat(AI, "Network Alert: Brute-force encryption crack in progress. Unable to pinpoint location.") hacking = TRUE // Digital Messenger /mob/living/silicon/pai/proc/pdamessage() var/dat = "

Digital Messenger

" dat += {"Signal/Receiver Status: [(pda.toff) ? "\[Off\]" : "\[On\]"]
Ringer Status: [(pda.silent) ? "\[Off\]" : "\[On\]"]

"} dat += "
    " if(!pda.toff) for (var/obj/item/pda/P in sortNames(get_viewable_pdas())) if (P == pda) continue dat += "
  • [P]" dat += "
  • " dat += "
" dat += "

" dat += "Messages:
[pda.tnote]" return dat // Loudness Booster /mob/living/silicon/pai/proc/softwareLoudness() if(!internal_instrument) internal_instrument = new(src) var/dat = "

Sound Synthetizer

" dat += "Open Synthesizer Interface
" dat += "Choose Instrument Type" return dat