From 411486f7b46e482d7461ff46fe07d077cc965f63 Mon Sep 17 00:00:00 2001 From: ShadowLarkens Date: Tue, 15 Sep 2020 18:16:08 -0700 Subject: [PATCH 1/8] Move PDA to code/modules/pda --- code/modules/pda/app.dm | 106 ++++++++++++++++++ .../items/devices/PDA => modules/pda}/cart.dm | 0 .../devices/PDA => modules/pda}/cart_vr.dm | 0 .../devices/PDA => modules/pda}/chatroom.dm | 0 .../devices/PDA/PDA.dm => modules/pda/pda.dm} | 0 .../PDA/PDA_vr.dm => modules/pda/pda_vr.dm} | 0 .../devices/PDA => modules/pda}/radio.dm | 0 vorestation.dme | 13 ++- 8 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 code/modules/pda/app.dm rename code/{game/objects/items/devices/PDA => modules/pda}/cart.dm (100%) rename code/{game/objects/items/devices/PDA => modules/pda}/cart_vr.dm (100%) rename code/{game/objects/items/devices/PDA => modules/pda}/chatroom.dm (100%) rename code/{game/objects/items/devices/PDA/PDA.dm => modules/pda/pda.dm} (100%) rename code/{game/objects/items/devices/PDA/PDA_vr.dm => modules/pda/pda_vr.dm} (100%) rename code/{game/objects/items/devices/PDA => modules/pda}/radio.dm (100%) diff --git a/code/modules/pda/app.dm b/code/modules/pda/app.dm new file mode 100644 index 00000000000..655bb891de5 --- /dev/null +++ b/code/modules/pda/app.dm @@ -0,0 +1,106 @@ +// Base class for anything that can show up on home screen +/datum/data/pda + var/icon = "tasks" //options comes from http://fontawesome.io/icons/ + var/notify_icon = "exclamation-circle" + var/notify_silent = 0 + var/hidden = 0 // program not displayed in main menu + var/category = "General" // the category to list it in on the main menu + var/obj/item/pda/pda // if this is null, and the app is running code, something's gone wrong + +/datum/data/pda/Destroy() + pda = null + return ..() + +/datum/data/pda/proc/start() + return + +/datum/data/pda/proc/stop() + return + +/datum/data/pda/proc/program_process() + return + +/datum/data/pda/proc/program_hit_check() + return + +/datum/data/pda/proc/notify(message, blink = 1) + if(message) + //Search for holder of the PDA. + var/mob/living/L = null + if(pda.loc && isliving(pda.loc)) + L = pda.loc + //Maybe they are a pAI! + else + L = get(pda, /mob/living/silicon) + + if(L) + to_chat(L, "[bicon(pda)] [message]") + SSnanoui.update_user_uis(L, pda) // Update the receiving user's PDA UI so that they can see the new message + + if(!notify_silent) + pda.play_ringtone() + + if(blink && !(src in pda.notifying_programs)) + pda.overlays += image('icons/obj/pda.dmi', "pda-r") + pda.notifying_programs |= src + +/datum/data/pda/proc/unnotify() + if(src in pda.notifying_programs) + pda.notifying_programs -= src + if(!pda.notifying_programs.len) + pda.overlays -= image('icons/obj/pda.dmi', "pda-r") + +// An app has a button on the home screen and its own UI +/datum/data/pda/app + name = "App" + size = 3 + var/title = null // what is displayed in the title bar when this is the current app + var/template = "" + var/update = PDA_APP_UPDATE + var/has_back = 0 + +/datum/data/pda/app/New() + if(!title) + title = name + +/datum/data/pda/app/start() + if(pda.current_app) + pda.current_app.stop() + pda.current_app = src + return 1 + +/datum/data/pda/app/proc/update_ui(mob/user as mob, list/data) + + +// Utilities just have a button on the home screen, but custom code when clicked +/datum/data/pda/utility + name = "Utility" + icon = "gear" + size = 1 + category = "Utilities" + + +/datum/data/pda/utility/scanmode + var/base_name + category = "Scanners" + +/datum/data/pda/utility/scanmode/New(obj/item/cartridge/C) + ..(C) + name = "Enable [base_name]" + +/datum/data/pda/utility/scanmode/start() + if(pda.scanmode) + pda.scanmode.name = "Enable [pda.scanmode.base_name]" + + if(pda.scanmode == src) + pda.scanmode = null + else + pda.scanmode = src + name = "Disable [base_name]" + + pda.update_shortcuts() + return 1 + +/datum/data/pda/utility/scanmode/proc/scan_mob(mob/living/C as mob, mob/living/user as mob) + +/datum/data/pda/utility/scanmode/proc/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob) diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/modules/pda/cart.dm similarity index 100% rename from code/game/objects/items/devices/PDA/cart.dm rename to code/modules/pda/cart.dm diff --git a/code/game/objects/items/devices/PDA/cart_vr.dm b/code/modules/pda/cart_vr.dm similarity index 100% rename from code/game/objects/items/devices/PDA/cart_vr.dm rename to code/modules/pda/cart_vr.dm diff --git a/code/game/objects/items/devices/PDA/chatroom.dm b/code/modules/pda/chatroom.dm similarity index 100% rename from code/game/objects/items/devices/PDA/chatroom.dm rename to code/modules/pda/chatroom.dm diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/modules/pda/pda.dm similarity index 100% rename from code/game/objects/items/devices/PDA/PDA.dm rename to code/modules/pda/pda.dm diff --git a/code/game/objects/items/devices/PDA/PDA_vr.dm b/code/modules/pda/pda_vr.dm similarity index 100% rename from code/game/objects/items/devices/PDA/PDA_vr.dm rename to code/modules/pda/pda_vr.dm diff --git a/code/game/objects/items/devices/PDA/radio.dm b/code/modules/pda/radio.dm similarity index 100% rename from code/game/objects/items/devices/PDA/radio.dm rename to code/modules/pda/radio.dm diff --git a/vorestation.dme b/vorestation.dme index 6b5153f0392..16816e2506e 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -1157,12 +1157,6 @@ #include "code\game\objects\items\devices\communicator\messaging.dm" #include "code\game\objects\items\devices\communicator\phone.dm" #include "code\game\objects\items\devices\communicator\UI.dm" -#include "code\game\objects\items\devices\PDA\cart.dm" -#include "code\game\objects\items\devices\PDA\cart_vr.dm" -#include "code\game\objects\items\devices\PDA\chatroom.dm" -#include "code\game\objects\items\devices\PDA\PDA.dm" -#include "code\game\objects\items\devices\PDA\PDA_vr.dm" -#include "code\game\objects\items\devices\PDA\radio.dm" #include "code\game\objects\items\devices\radio\beacon.dm" #include "code\game\objects\items\devices\radio\electropack.dm" #include "code\game\objects\items\devices\radio\encryptionkey.dm" @@ -3071,6 +3065,13 @@ #include "code\modules\paperwork\photography.dm" #include "code\modules\paperwork\silicon_photography.dm" #include "code\modules\paperwork\stamps.dm" +#include "code\modules\pda\app.dm" +#include "code\modules\pda\cart.dm" +#include "code\modules\pda\cart_vr.dm" +#include "code\modules\pda\chatroom.dm" +#include "code\modules\pda\pda.dm" +#include "code\modules\pda\pda_vr.dm" +#include "code\modules\pda\radio.dm" #include "code\modules\persistence\filth.dm" #include "code\modules\persistence\graffiti.dm" #include "code\modules\persistence\noticeboard.dm" From 8c338ed9da92a1c002ee6f227192f2a217f89af4 Mon Sep 17 00:00:00 2001 From: ShadowLarkens Date: Tue, 15 Sep 2020 20:08:25 -0700 Subject: [PATCH 2/8] NanoUI PDAs made Modular (lazy commit) --- code/__defines/pda.dm | 3 + code/_helpers/text.dm | 21 + code/modules/nano/nanoui.dm | 1 + code/modules/pda/app.dm | 4 +- code/modules/pda/cart.dm | 38 +- code/modules/pda/cart_apps.dm | 410 ++++++++ code/modules/pda/core_apps.dm | 111 +++ code/modules/pda/messenger.dm | 215 ++++ code/modules/pda/messenger_plugins.dm | 91 ++ code/modules/pda/pda.dm | 838 ++++++---------- code/modules/pda/pda_tgui.dm | 59 ++ code/modules/pda/utilities.dm | 200 ++++ nano/css/shared.css | 192 ++-- nano/js/nano_state_pda.js | 51 + nano/js/nano_template.js | 3 + nano/js/nano_utility.js | 5 + nano/templates/pda.tmpl | 914 +++--------------- nano/templates/pda_atmos_scan.tmpl | 60 ++ nano/templates/pda_janitor.tmpl | 66 ++ nano/templates/pda_main_menu.tmpl | 76 ++ nano/templates/pda_manifest.tmpl | 96 ++ nano/templates/pda_medical.tmpl | 54 ++ nano/templates/pda_messenger.tmpl | 90 ++ nano/templates/pda_mob_hunt.tmpl | 91 ++ nano/templates/pda_mule.tmpl | 118 +++ nano/templates/pda_notekeeper.tmpl | 21 + nano/templates/pda_power.tmpl | 49 + nano/templates/pda_secbot.tmpl | 59 ++ nano/templates/pda_security.tmpl | 50 + nano/templates/pda_signaller.tmpl | 38 + nano/templates/pda_status_display.tmpl | 44 + nano/templates/pda_supply.tmpl | 39 + tgui/packages/tgui/interfaces/Pda.js | 17 + .../tgui/interfaces/pda/pda_main_menu.js | 14 + tools/nano-tester/index.html | 1 + vorestation.dme | 7 + 36 files changed, 2751 insertions(+), 1395 deletions(-) create mode 100644 code/__defines/pda.dm create mode 100644 code/modules/pda/cart_apps.dm create mode 100644 code/modules/pda/core_apps.dm create mode 100644 code/modules/pda/messenger.dm create mode 100644 code/modules/pda/messenger_plugins.dm create mode 100644 code/modules/pda/pda_tgui.dm create mode 100644 code/modules/pda/utilities.dm create mode 100644 nano/js/nano_state_pda.js create mode 100644 nano/templates/pda_atmos_scan.tmpl create mode 100644 nano/templates/pda_janitor.tmpl create mode 100644 nano/templates/pda_main_menu.tmpl create mode 100644 nano/templates/pda_manifest.tmpl create mode 100644 nano/templates/pda_medical.tmpl create mode 100644 nano/templates/pda_messenger.tmpl create mode 100644 nano/templates/pda_mob_hunt.tmpl create mode 100644 nano/templates/pda_mule.tmpl create mode 100644 nano/templates/pda_notekeeper.tmpl create mode 100644 nano/templates/pda_power.tmpl create mode 100644 nano/templates/pda_secbot.tmpl create mode 100644 nano/templates/pda_security.tmpl create mode 100644 nano/templates/pda_signaller.tmpl create mode 100644 nano/templates/pda_status_display.tmpl create mode 100644 nano/templates/pda_supply.tmpl create mode 100644 tgui/packages/tgui/interfaces/Pda.js create mode 100644 tgui/packages/tgui/interfaces/pda/pda_main_menu.js diff --git a/code/__defines/pda.dm b/code/__defines/pda.dm new file mode 100644 index 00000000000..c5d32f03ba8 --- /dev/null +++ b/code/__defines/pda.dm @@ -0,0 +1,3 @@ +#define PDA_APP_UPDATE 0 +#define PDA_APP_NOUPDATE 1 +#define PDA_APP_UPDATE_SLOW 2 diff --git a/code/_helpers/text.dm b/code/_helpers/text.dm index 02a8806089d..a9aac1ffcf5 100644 --- a/code/_helpers/text.dm +++ b/code/_helpers/text.dm @@ -21,6 +21,27 @@ /* * Text sanitization */ +// Can be used almost the same way as normal input for text +/proc/clean_input(Message, Title, Default, mob/user=usr) + var/txt = input(user, Message, Title, Default) as text | null + if(txt) + return html_encode(txt) + +//Simply removes < and > and limits the length of the message +/proc/strip_html_simple(var/t,var/limit=MAX_MESSAGE_LEN) + var/list/strip_chars = list("<",">") + t = copytext(t,1,limit) + for(var/char in strip_chars) + var/index = findtext(t, char) + while(index) + t = copytext(t, 1, index) + copytext(t, index+1) + index = findtext(t, char) + return t + +//Runs byond's sanitization proc along-side strip_html_simple +//I believe strip_html_simple() is required to run first to prevent '<' from displaying as '<' that html_encode() would cause +/proc/adminscrub(var/t,var/limit=MAX_MESSAGE_LEN) + return copytext((html_encode(strip_html_simple(t))),1,limit) //Used for preprocessing entered text /proc/sanitize(var/input, var/max_length = MAX_MESSAGE_LEN, var/encode = 1, var/trim = 1, var/extra = 1) diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm index 900f5b9d336..29863f56170 100644 --- a/code/modules/nano/nanoui.dm +++ b/code/modules/nano/nanoui.dm @@ -109,6 +109,7 @@ nanoui is used to open and update nano browser uis add_script("nano_state_manager.js") // The NanoStateManager JS, it handles updates from the server and passes data to the current state add_script("nano_state.js") // The NanoState JS, this is the base state which all states must inherit from add_script("nano_state_default.js") // The NanoStateDefault JS, this is the "default" state (used by all UIs by default), which inherits from NanoState + add_script("nano_state_pda.js") // The NanoStatePDA JS, this is the state used for PDAs. add_script("nano_base_callbacks.js") // The NanoBaseCallbacks JS, this is used to set up (before and after update) callbacks which are common to all UIs add_script("nano_base_helpers.js") // The NanoBaseHelpers JS, this is used to set up template helpers which are common to all UIs add_stylesheet("shared.css") // this CSS sheet is common to all UIs diff --git a/code/modules/pda/app.dm b/code/modules/pda/app.dm index 655bb891de5..055e302e101 100644 --- a/code/modules/pda/app.dm +++ b/code/modules/pda/app.dm @@ -5,7 +5,7 @@ var/notify_silent = 0 var/hidden = 0 // program not displayed in main menu var/category = "General" // the category to list it in on the main menu - var/obj/item/pda/pda // if this is null, and the app is running code, something's gone wrong + var/obj/item/device/pda/pda // if this is null, and the app is running code, something's gone wrong /datum/data/pda/Destroy() pda = null @@ -84,7 +84,7 @@ var/base_name category = "Scanners" -/datum/data/pda/utility/scanmode/New(obj/item/cartridge/C) +/datum/data/pda/utility/scanmode/New(obj/item/weapon/cartridge/C) ..(C) name = "Enable [base_name]" diff --git a/code/modules/pda/cart.dm b/code/modules/pda/cart.dm index 5a404288e31..75fdc28c31e 100644 --- a/code/modules/pda/cart.dm +++ b/code/modules/pda/cart.dm @@ -80,9 +80,13 @@ var/list/civilian_cartridges = list( var/message1 // used for status_displays var/message2 var/list/stored_data = list() + var/list/programs = list() + var/list/messenger_plugins = list() /obj/item/weapon/cartridge/Destroy() QDEL_NULL(radio) + QDEL_LIST(programs) + QDEL_LIST(messenger_plugins) return ..() /obj/item/weapon/cartridge/engineering @@ -234,14 +238,25 @@ var/list/civilian_cartridges = list( name = "\improper Value-PAK cartridge" desc = "Now with 200% more value!" icon_state = "cart-c" - access_quartermaster = 1 - access_janitor = 1 - access_engine = 1 - access_security = 1 - access_medical = 1 - access_reagent_scanner = 1 - access_status_display = 1 - access_atmos = 1 + programs = list( + new/datum/data/pda/app/power, + new/datum/data/pda/utility/scanmode/halogen, + + new/datum/data/pda/utility/scanmode/gas, + + new/datum/data/pda/app/crew_records/medical, + new/datum/data/pda/utility/scanmode/medical, + + new/datum/data/pda/utility/scanmode/reagent, + + new/datum/data/pda/app/crew_records/security, + new/datum/data/pda/app/secbot_control, + + new/datum/data/pda/app/janitor, + + new/datum/data/pda/app/supply, + + new/datum/data/pda/app/status_display) /obj/item/weapon/cartridge/syndicate name = "\improper Detomatix cartridge" @@ -276,6 +291,13 @@ var/list/civilian_cartridges = list( frequency.post_signal(src, status_signal) +/obj/item/weapon/cartridge/frame + name = "F.R.A.M.E. cartridge" + icon_state = "cart" + charges = 5 + var/telecrystals = 0 + messenger_plugins = list(new/datum/data/pda/messenger_plugin/virus/frame) + /* This generates the nano values of the cart menus. diff --git a/code/modules/pda/cart_apps.dm b/code/modules/pda/cart_apps.dm new file mode 100644 index 00000000000..0754e7fb924 --- /dev/null +++ b/code/modules/pda/cart_apps.dm @@ -0,0 +1,410 @@ +/datum/data/pda/app/status_display + name = "Status Display" + icon = "list-alt" + template = "pda_status_display" + category = "Utilities" + + var/message1 // used for status_displays + var/message2 + +/datum/data/pda/app/status_display/update_ui(mob/user as mob, list/data) + data["records"] = list( + "message1" = message1 ? message1 : "(none)", + "message2" = message2 ? message2 : "(none)") + +/datum/data/pda/app/status_display/Topic(href, list/href_list) + switch(href_list["choice"]) + if("Status") + switch(href_list["statdisp"]) + if("message") + post_status("message", message1, message2) + if("alert") + post_status("alert", href_list["alert"]) + if("setmsg1") + message1 = clean_input("Line 1", "Enter Message Text", message1) + if("setmsg2") + message2 = clean_input("Line 2", "Enter Message Text", message2) + else + post_status(href_list["statdisp"]) + +/datum/data/pda/app/status_display/proc/post_status(var/command, var/data1, var/data2) + var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435) + if(!frequency) + return + + var/datum/signal/status_signal = new + status_signal.source = src + status_signal.transmission_method = 1 + status_signal.data["command"] = command + + switch(command) + if("message") + status_signal.data["msg1"] = data1 + status_signal.data["msg2"] = data2 + var/mob/user = pda.fingerprintslast + if(istype(pda.loc, /mob/living)) + name = pda.loc + log_admin("STATUS: [user] set status screen with [pda]. Message: [data1] [data2]") + message_admins("STATUS: [user] set status screen with [pda]. Message: [data1] [data2]") + + if("alert") + status_signal.data["picture_state"] = data1 + + spawn(0) + frequency.post_signal(src, status_signal) + + +/datum/data/pda/app/signaller + name = "Signaler System" + icon = "rss" + template = "pda_signaller" + category = "Utilities" + +/datum/data/pda/app/signaller/update_ui(mob/user as mob, list/data) + if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/radio/integrated/signal)) + var/obj/item/radio/integrated/signal/R = pda.cartridge.radio + data["signal_freq"] = format_frequency(R.frequency) + data["signal_code"] = R.code + +/datum/data/pda/app/signaller/Topic(href, list/href_list) + if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/radio/integrated/signal)) + var/obj/item/radio/integrated/signal/R = pda.cartridge.radio + + switch(href_list["choice"]) + if("Send Signal") + spawn(0) + R.send_signal("ACTIVATE") + + if("Signal Frequency") + var/new_frequency = sanitize_frequency(R.frequency + text2num(href_list["sfreq"])) + R.set_frequency(new_frequency) + + if("Signal Code") + R.code += text2num(href_list["scode"]) + R.code = round(R.code) + R.code = min(100, R.code) + R.code = max(1, R.code) + +/datum/data/pda/app/power + name = "Power Monitor" + icon = "exclamation-triangle" + template = "pda_power" + category = "Engineering" + update = PDA_APP_UPDATE_SLOW + +// var/obj/machinery/computer/monitor/powmonitor = null + +// /datum/data/pda/app/power/update_ui(mob/user as mob, list/data) +// update = PDA_APP_UPDATE_SLOW + +// if(powmonitor && !isnull(powmonitor.powernet)) +// data["records"] = list( +// "powerconnected" = 1, +// "poweravail" = powmonitor.powernet.avail, +// "powerload" = num2text(powmonitor.powernet.viewload, 10), +// "powerdemand" = powmonitor.powernet.load, +// "apcs" = GLOB.apc_repository.apc_data(powmonitor.powernet)) +// has_back = 1 +// else +// data["records"] = list( +// "powerconnected" = 0, +// "powermonitors" = GLOB.powermonitor_repository.powermonitor_data()) +// has_back = 0 + +// /datum/data/pda/app/power/Topic(href, list/href_list) +// switch(href_list["choice"]) +// if("Power Select") +// var/pref = href_list["target"] +// powmonitor = locate(pref) +// update = PDA_APP_UPDATE +// if("Back") +// powmonitor = null +// update = PDA_APP_UPDATE + +/datum/data/pda/app/crew_records + var/datum/data/record/general_records = null + +/datum/data/pda/app/crew_records/update_ui(mob/user as mob, list/data) + var/list/records[0] + + if(general_records && (general_records in data_core.general)) + data["records"] = records + records["general"] = general_records.fields + return records + else + for(var/A in sortRecord(data_core.general)) + var/datum/data/record/R = A + if(R) + records += list(list(Name = R.fields["name"], "ref" = "\ref[R]")) + data["recordsList"] = records + return null + +/datum/data/pda/app/crew_records/Topic(href, list/href_list) + switch(href_list["choice"]) + if("Records") + var/datum/data/record/R = locate(href_list["target"]) + if(R && (R in data_core.general)) + load_records(R) + if("Back") + general_records = null + has_back = 0 + +/datum/data/pda/app/crew_records/proc/load_records(datum/data/record/R) + general_records = R + has_back = 1 + +/datum/data/pda/app/crew_records/medical + name = "Medical Records" + icon = "heartbeat" + template = "pda_medical" + category = "Medical" + + var/datum/data/record/medical_records = null + +/datum/data/pda/app/crew_records/medical/update_ui(mob/user as mob, list/data) + var/list/records = ..() + if(!records) + return + + if(medical_records && (medical_records in data_core.medical)) + records["medical"] = medical_records.fields + + return records + +/datum/data/pda/app/crew_records/medical/load_records(datum/data/record/R) + ..(R) + for(var/A in data_core.medical) + var/datum/data/record/E = A + if(E && (E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) + medical_records = E + break + +/datum/data/pda/app/crew_records/security + name = "Security Records" + icon = "tags" + template = "pda_security" + category = "Security" + + var/datum/data/record/security_records = null + +/datum/data/pda/app/crew_records/security/update_ui(mob/user as mob, list/data) + var/list/records = ..() + if(!records) + return + + if(security_records && (security_records in data_core.security)) + records["security"] = security_records.fields + + return records + +/datum/data/pda/app/crew_records/security/load_records(datum/data/record/R) + ..(R) + for(var/A in data_core.security) + var/datum/data/record/E = A + if(E && (E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) + security_records = E + break + +/datum/data/pda/app/secbot_control + name = "Security Bot Access" + icon = "rss" + template = "pda_secbot" + category = "Security" + +/datum/data/pda/app/secbot_control/update_ui(mob/user as mob, list/data) + var/botsData[0] + var/beepskyData[0] + if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/radio/integrated/beepsky)) + var/obj/item/radio/integrated/beepsky/SC = pda.cartridge.radio + beepskyData["active"] = SC.active ? sanitize(SC.active.name) : null + has_back = SC.active ? 1 : 0 + if(SC.active && !isnull(SC.botstatus)) + var/area/loca = SC.botstatus["loca"] + var/loca_name = sanitize(loca.name) + beepskyData["botstatus"] = list("loca" = loca_name, "mode" = SC.botstatus["mode"]) + else + beepskyData["botstatus"] = list("loca" = null, "mode" = -1) + var/botsCount=0 + if(SC.botlist && SC.botlist.len) + for(var/mob/living/bot/B in SC.botlist) + botsCount++ + if(B.loc) + botsData[++botsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]") + + if(!botsData.len) + botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) + + beepskyData["bots"] = botsData + beepskyData["count"] = botsCount + + else + beepskyData["active"] = 0 + botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) + beepskyData["botstatus"] = list("loca" = null, "mode" = null) + beepskyData["bots"] = botsData + beepskyData["count"] = 0 + has_back = 0 + + data["beepsky"] = beepskyData + +/datum/data/pda/app/secbot_control/Topic(href, list/href_list) + switch(href_list["choice"]) + if("Back") + if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/radio/integrated/beepsky)) + pda.cartridge.radio.Topic(null, list(radiomenu = "1", op = "botlist")) + +/datum/data/pda/app/mule_control + name = "Delivery Bot Control" + icon = "truck" + template = "pda_mule" + category = "Quartermaster" + +// /datum/data/pda/app/mule_control/update_ui(mob/user as mob, list/data) +// var/muleData[0] +// var/mulebotsData[0] +// if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/radio/integrated/mule)) +// var/obj/item/radio/integrated/mule/QC = pda.cartridge.radio +// muleData["active"] = QC.active ? sanitize(QC.active.name) : null +// has_back = QC.active ? 1 : 0 +// if(QC.active && !isnull(QC.botstatus)) +// var/area/loca = QC.botstatus["loca"] +// var/loca_name = sanitize(loca.name) +// muleData["botstatus"] = list("loca" = loca_name, "mode" = QC.botstatus["mode"],"home"=QC.botstatus["home"],"powr" = QC.botstatus["powr"],"retn" =QC.botstatus["retn"], "pick"=QC.botstatus["pick"], "load" = QC.botstatus["load"], "dest" = sanitize(QC.botstatus["dest"])) + +// else +// muleData["botstatus"] = list("loca" = null, "mode" = -1,"home"=null,"powr" = null,"retn" =null, "pick"=null, "load" = null, "dest" = null) + + +// var/mulebotsCount=0 +// for(var/mob/living/bot/B in QC.botlist) +// mulebotsCount++ +// if(B.loc) +// mulebotsData[++mulebotsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]") + +// if(!mulebotsData.len) +// mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) + +// muleData["bots"] = mulebotsData +// muleData["count"] = mulebotsCount + +// else +// muleData["botstatus"] = list("loca" = null, "mode" = -1,"home"=null,"powr" = null,"retn" =null, "pick"=null, "load" = null, "dest" = null) +// muleData["active"] = 0 +// mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) +// muleData["bots"] = mulebotsData +// muleData["count"] = 0 +// has_back = 0 + +// data["mulebot"] = muleData + +// /datum/data/pda/app/mule_control/Topic(href, list/href_list) +// switch(href_list["choice"]) +// if("Back") +// if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/radio/integrated/mule)) +// pda.cartridge.radio.Topic(null, list(radiomenu = "1", op = "botlist")) + +/datum/data/pda/app/supply + name = "Supply Records" + icon = "file-text-o" + template = "pda_supply" + category = "Quartermaster" + update = PDA_APP_UPDATE_SLOW + +// /datum/data/pda/app/supply/update_ui(mob/user as mob, list/data) +// var/supplyData[0] + +// if(SSshuttle.supply.mode == SHUTTLE_CALL) +// supplyData["shuttle_moving"] = 1 + +// if(is_station_level(SSshuttle.supply.z)) +// supplyData["shuttle_loc"] = "Station" +// else +// supplyData["shuttle_loc"] = "CentCom" + +// supplyData["shuttle_time"] = "([SSshuttle.supply.timeLeft(600)] Mins)" + +// var/supplyOrderCount = 0 +// var/supplyOrderData[0] +// for(var/S in SSshuttle.shoppinglist) +// var/datum/supply_order/SO = S +// supplyOrderCount++ +// supplyOrderData[++supplyOrderData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "ApprovedBy" = SO.orderedby, "Comment" = html_encode(SO.comment)) + +// if(!supplyOrderData.len) +// supplyOrderData[++supplyOrderData.len] = list("Number" = null, "Name" = null, "OrderedBy"=null) + +// supplyData["approved"] = supplyOrderData +// supplyData["approved_count"] = supplyOrderCount + +// var/requestCount = 0 +// var/requestData[0] +// for(var/S in SSshuttle.requestlist) +// var/datum/supply_order/SO = S +// requestCount++ +// requestData[++requestData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "OrderedBy" = SO.orderedby, "Comment" = html_encode(SO.comment)) + +// if(!requestData.len) +// requestData[++requestData.len] = list("Number" = null, "Name" = null, "orderedBy" = null, "Comment" = null) + +// supplyData["requests"] = requestData +// supplyData["requests_count"] = requestCount + +// data["supply"] = supplyData + +/datum/data/pda/app/janitor + name = "Custodial Locator" + icon = "trash-o" + template = "pda_janitor" + category = "Utilities" + update = PDA_APP_UPDATE_SLOW + +/datum/data/pda/app/janitor/update_ui(mob/user as mob, list/data) + var/JaniData[0] + var/turf/cl = get_turf(pda) + + if(cl) + JaniData["user_loc"] = list("x" = cl.x, "y" = cl.y) + else + JaniData["user_loc"] = list("x" = 0, "y" = 0) + + var/MopData[0] + for(var/obj/item/weapon/mop/M in all_mops)//GLOB.janitorial_equipment) + var/turf/ml = get_turf(M) + if(ml) + if(ml.z != cl.z) + continue + var/direction = get_dir(pda, M) + MopData[++MopData.len] = list ("x" = ml.x, "y" = ml.y, "dir" = uppertext(dir2text(direction)), "status" = M.reagents.total_volume ? "Wet" : "Dry") + + var/BucketData[0] + for(var/obj/structure/mopbucket/B in all_mopbuckets)//GLOB.janitorial_equipment) + var/turf/bl = get_turf(B) + if(bl) + if(bl.z != cl.z) + continue + var/direction = get_dir(pda,B) + BucketData[++BucketData.len] = list ("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "volume" = B.reagents.total_volume, "max_volume" = B.reagents.maximum_volume) + + var/CbotData[0] + for(var/mob/living/bot/cleanbot/B in mob_list) + var/turf/bl = get_turf(B) + if(bl) + if(bl.z != cl.z) + continue + var/direction = get_dir(pda,B) + CbotData[++CbotData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.on ? "Online" : "Offline") + + var/CartData[0] + for(var/obj/structure/janitorialcart/B in all_janitorial_carts)//GLOB.janitorial_equipment) + var/turf/bl = get_turf(B) + if(bl) + if(bl.z != cl.z) + continue + var/direction = get_dir(pda,B) + CartData[++CartData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "volume" = B.reagents.total_volume, "max_volume" = B.reagents.maximum_volume) + + JaniData["mops"] = MopData.len ? MopData : null + JaniData["buckets"] = BucketData.len ? BucketData : null + JaniData["cleanbots"] = CbotData.len ? CbotData : null + JaniData["carts"] = CartData.len ? CartData : null + data["janitor"] = JaniData diff --git a/code/modules/pda/core_apps.dm b/code/modules/pda/core_apps.dm new file mode 100644 index 00000000000..468b9005f53 --- /dev/null +++ b/code/modules/pda/core_apps.dm @@ -0,0 +1,111 @@ +/datum/data/pda/app/main_menu + icon = "home" + template = "pda_main_menu" + hidden = 1 + +/datum/data/pda/app/main_menu/update_ui(mob/user as mob, list/data) + title = pda.name + + data["app"]["is_home"] = 1 + + data["apps"] = pda.shortcut_cache + data["categories"] = pda.shortcut_cat_order + data["pai"] = !isnull(pda.pai) // pAI inserted? + + var/list/notifying[0] + for(var/P in pda.notifying_programs) + notifying["\ref[P]"] = 1 + data["notifying"] = notifying + +/datum/data/pda/app/main_menu/Topic(href, list/href_list) + switch(href_list["choice"]) + if("UpdateInfo") + pda.ownjob = pda.id.assignment + pda.ownrank = pda.id.rank + pda.name = "PDA-[pda.owner] ([pda.ownjob])" + if("pai") + if(pda.pai) + if(pda.pai.loc != pda) + pda.pai = null + else + switch(href_list["option"]) + if("1") // Configure pAI device + pda.pai.attack_self(usr) + if("2") // Eject pAI device + var/turf/T = get_turf_or_move(pda.loc) + if(T) + pda.pai.loc = T + pda.pai = null + +/datum/data/pda/app/notekeeper + name = "Notekeeper" + icon = "sticky-note-o" + template = "pda_notekeeper" + + var/note = null + var/notehtml = "" + +/datum/data/pda/app/notekeeper/start() + . = ..() + if(!note) + note = "Congratulations, your station has chosen the [pda.model_name]!" + +/datum/data/pda/app/notekeeper/update_ui(mob/user as mob, list/data) + data["note"] = note // current pda notes + +/datum/data/pda/app/notekeeper/Topic(href, list/href_list) + switch(href_list["choice"]) + if("Edit") + var/n = input("Please enter message", name, notehtml) as message + if(pda.loc == usr) + note = adminscrub(n) + notehtml = html_decode(note) + note = replacetext(note, "\n", "
") + else + pda.close(usr) + +/datum/data/pda/app/manifest + name = "Crew Manifest" + icon = "user" + template = "pda_manifest" + update = PDA_APP_UPDATE_SLOW + +// /datum/data/pda/app/manifest/update_ui(mob/user as mob, list/data) + // data_core.get_manifest_json() + // data["manifest"] = PDA_Manifest + +/datum/data/pda/app/manifest/Topic(href, list/href_list) + +/datum/data/pda/app/atmos_scanner + name = "Atmospheric Scan" + icon = "fire" + template = "pda_atmos_scan" + category = "Utilities" + update = PDA_APP_UPDATE_SLOW + +// /datum/data/pda/app/atmos_scanner/update_ui(mob/user as mob, list/data) +// var/turf/T = get_turf(user.loc) +// if(!isnull(T)) +// var/datum/gas_mixture/environment = T.return_air() + +// var/pressure = environment.return_pressure() +// var/total_moles = environment.total_moles + +// if(total_moles) +// var/o2_level = environment.oxygen/total_moles +// var/n2_level = environment.nitrogen/total_moles +// var/co2_level = environment.carbon_dioxide/total_moles +// var/plasma_level = environment.toxins/total_moles +// var/unknown_level = 1-(o2_level+n2_level+co2_level+plasma_level) +// data["aircontents"] = list( +// "pressure" = pressure, +// "nitrogen" = n2_level*100, +// "oxygen" = o2_level*100, +// "carbon_dioxide" = co2_level*100, +// "plasma" = plasma_level*100, +// "other" = unknown_level, +// "temp" = environment.temperature-T0C, +// "reading" = 1 +// ) +// if(isnull(data["aircontents"])) +// data["aircontents"] = list("reading" = 0) diff --git a/code/modules/pda/messenger.dm b/code/modules/pda/messenger.dm new file mode 100644 index 00000000000..578ab9fcfbc --- /dev/null +++ b/code/modules/pda/messenger.dm @@ -0,0 +1,215 @@ +/datum/data/pda/app/messenger + name = "Messenger" + icon = "comments-o" + notify_icon = "comments" + title = "SpaceMessenger V4.1.0" + template = "pda_messenger" + + var/toff = 0 //If 1, messenger disabled + var/list/tnote[0] //Current Texts + var/last_text //No text spamming + + var/m_hidden = 0 // Is the PDA hidden from the PDA list? + var/active_conversation = null // New variable that allows us to only view a single conversation. + var/list/conversations = list() // For keeping up with who we have PDA messsages from. + var/latest_post = 0 + var/auto_scroll = 1 + +/datum/data/pda/app/messenger/start() + . = ..() + unnotify() + latest_post = 0 + +/datum/data/pda/app/messenger/update_ui(mob/user as mob, list/data) + data["silent"] = notify_silent // does the pda make noise when it receives a message? + data["toff"] = toff // is the messenger function turned off? + data["active_conversation"] = active_conversation // Which conversation are we following right now? + + has_back = active_conversation + if(active_conversation) + data["messages"] = tnote + for(var/c in tnote) + if(c["target"] == active_conversation) + data["convo_name"] = sanitize(c["owner"]) + data["convo_job"] = sanitize(c["job"]) + break + data["auto_scroll"] = auto_scroll + data["latest_post"] = latest_post + latest_post = tnote.len + else + var/convopdas[0] + var/pdas[0] + for(var/A in PDAs) + var/obj/item/device/pda/P = A + var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger) + + if(!P.owner || PM.toff || P == pda || PM.m_hidden) + continue + if(conversations.Find("\ref[P]")) + convopdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "1"))) + else + pdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "0"))) + + data["convopdas"] = convopdas + data["pdas"] = pdas + + var/list/plugins = list() + if(pda.cartridge) + for(var/A in pda.cartridge.messenger_plugins) + var/datum/data/pda/messenger_plugin/P = A + plugins += list(list(name = P.name, icon = P.icon, ref = "\ref[P]")) + data["plugins"] = plugins + + if(pda.cartridge) + data["charges"] = pda.cartridge.charges ? pda.cartridge.charges : 0 + +/datum/data/pda/app/messenger/Topic(href, list/href_list) + if(!pda.can_use()) + return + unnotify() + + switch(href_list["choice"]) + if("Toggle Messenger") + toff = !toff + if("Toggle Ringer")//If viewing texts then erase them, if not then toggle silent status + notify_silent = !notify_silent + if("Clear")//Clears messages + if(href_list["option"] == "All") + tnote.Cut() + conversations.Cut() + if(href_list["option"] == "Convo") + var/new_tnote[0] + for(var/i in tnote) + if(i["target"] != active_conversation) + new_tnote[++new_tnote.len] = i + tnote = new_tnote + conversations.Remove(active_conversation) + + active_conversation = null + latest_post = 0 + if("Message") + var/obj/item/device/pda/P = locate(href_list["target"]) + create_message(usr, P) + if(href_list["target"] in conversations) // Need to make sure the message went through, if not welp. + active_conversation = href_list["target"] + latest_post = 0 + if("Select Conversation") + var/P = href_list["convo"] + for(var/n in conversations) + if(P == n) + active_conversation = P + latest_post = 0 + if("Messenger Plugin") + if(!href_list["target"] || !href_list["plugin"]) + return + + var/obj/item/device/pda/P = locate(href_list["target"]) + if(!P) + to_chat(usr, "PDA not found.") + + var/datum/data/pda/messenger_plugin/plugin = locate(href_list["plugin"]) + if(plugin && (plugin in pda.cartridge.messenger_plugins)) + plugin.messenger = src + plugin.user_act(usr, P) + if("Back") + active_conversation = null + latest_post = 0 + if("Autoscroll") + auto_scroll = !auto_scroll + +/datum/data/pda/app/messenger/proc/create_message(var/mob/living/U, var/obj/item/device/pda/P) + var/t = input(U, "Please enter message", name, null) as text|null + if(!t) + return + t = sanitize(copytext(t, 1, MAX_MESSAGE_LEN)) + t = readd_quotes(t) + if(!t || !istype(P)) + return + if(!in_range(pda, U) && pda.loc != U) + return + + var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger) + + if(!PM || PM.toff || toff) + return + + if(last_text && world.time < last_text + 5) + return + + if(!pda.can_use()) + return + + last_text = world.time + // check if telecomms I/O route 1459 is stable + //var/telecomms_intact = telecomms_process(P.owner, owner, t) + var/obj/machinery/message_server/useMS = null + if(message_servers) + for(var/A in message_servers) + var/obj/machinery/message_server/MS = A + //PDAs are now dependent on the Message Server. + if(MS.active) + useMS = MS + break + + var/datum/signal/signal = pda.telecomms_process() + + var/useTC = 0 + if(signal) + if(signal.data["done"]) + useTC = 1 + var/turf/pos = get_turf(P) + // TODO: Make the radio system cooperate with the space manager + if(pos.z in signal.data["level"]) + useTC = 2 + //Let's make this barely readable + if(signal.data["compression"] > 0) + t = Gibberish(t, signal.data["compression"] + 50) + + if(useMS && useTC) // only send the message if it's stable + if(useTC != 2) // Does our recipient have a broadcaster on their level? + to_chat(U, "ERROR: Cannot reach recipient.") + return + useMS.send_pda_message("[P.owner]","[pda.owner]","[t]") + tnote.Add(list(list("sent" = 1, "owner" = "[P.owner]", "job" = "[P.ownjob]", "message" = "[t]", "target" = "\ref[P]"))) + PM.tnote.Add(list(list("sent" = 0, "owner" = "[pda.owner]", "job" = "[pda.ownjob]", "message" = "[t]", "target" = "\ref[pda]"))) + pda.investigate_log("PDA Message - [U.key] - [pda.owner] -> [P.owner]: [t]", "pda") + if(!conversations.Find("\ref[P]")) + conversations.Add("\ref[P]") + if(!PM.conversations.Find("\ref[pda]")) + PM.conversations.Add("\ref[pda]") + + SSnanoui.update_user_uis(U, P) // Update the sending user's PDA UI so that they can see the new message + PM.notify("Message from [pda.owner] ([pda.ownjob]), \"[t]\" (Reply)") + log_pda("(PDA: [src.name]) sent \"[t]\" to [P.name]", usr) + else + to_chat(U, "ERROR: Messaging server is not responding.") + +/datum/data/pda/app/messenger/proc/available_pdas() + var/list/names = list() + var/list/plist = list() + var/list/namecounts = list() + + if(toff) + to_chat(usr, "Turn on your receiver in order to send messages.") + return + + for(var/A in PDAs) + var/obj/item/device/pda/P = A + var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger) + + if(!P.owner || !PM || PM.hidden || P == pda || PM.toff) + continue + + var/name = P.owner + if(name in names) + namecounts[name]++ + name = text("[name] ([namecounts[name]])") + else + names.Add(name) + namecounts[name] = 1 + + plist[text("[name]")] = P + return plist + +/datum/data/pda/app/messenger/proc/can_receive() + return pda.owner && !toff && !hidden diff --git a/code/modules/pda/messenger_plugins.dm b/code/modules/pda/messenger_plugins.dm new file mode 100644 index 00000000000..90cb9460a48 --- /dev/null +++ b/code/modules/pda/messenger_plugins.dm @@ -0,0 +1,91 @@ +/datum/data/pda/messenger_plugin + var/datum/data/pda/app/messenger/messenger + +/datum/data/pda/messenger_plugin/proc/user_act(mob/user as mob, obj/item/device/pda/P) + + +/datum/data/pda/messenger_plugin/virus + name = "*Send Virus*" + +/datum/data/pda/messenger_plugin/virus/user_act(mob/user as mob, obj/item/device/pda/P) + var/datum/data/pda/app/messenger/M = P.find_program(/datum/data/pda/app/messenger) + + if(M && !M.toff && pda.cartridge.charges > 0) + pda.cartridge.charges-- + return 1 + return 0 + + +/datum/data/pda/messenger_plugin/virus/clown + icon = "star" + +/datum/data/pda/messenger_plugin/virus/clown/user_act(mob/user as mob, obj/item/device/pda/P) + . = ..(user, P) + if(.) + user.show_message("Virus sent!", 1) + P.honkamt = (rand(15,20)) + P.ttone = "honk" + + +/datum/data/pda/messenger_plugin/virus/mime + icon = "arrow-circle-down" + +/datum/data/pda/messenger_plugin/virus/mime/user_act(mob/user as mob, obj/item/device/pda/P) + . = ..(user, P) + if(.) + user.show_message("Virus sent!", 1) + var/datum/data/pda/app/M = P.find_program(/datum/data/pda/app/messenger) + if(M) + M.notify_silent = 1 + P.ttone = "silence" + + +/datum/data/pda/messenger_plugin/virus/detonate + name = "*Detonate*" + icon = "exclamation-circle" + +/datum/data/pda/messenger_plugin/virus/detonate/user_act(mob/user as mob, obj/item/device/pda/P) + . = ..(user, P) + if(.) + var/difficulty = 0 + + if(pda.cartridge) + difficulty += pda.cartridge.programs.len / 2 + else + difficulty += 2 + + if(!P.detonate || P.hidden_uplink) + user.show_message("The target PDA does not seem to respond to the detonation command.", 1) + pda.cartridge.charges++ + else if(prob(difficulty * 12)) + user.show_message("An error flashes on your [pda].", 1) + else if(prob(difficulty * 3)) + user.show_message("Energy feeds back into your [pda]!", 1) + pda.close(user) + pda.explode() + log_admin("[key_name(user)] just attempted to blow up [P] with the Detomatix cartridge but failed, blowing themselves up") + message_admins("[key_name_admin(user)] just attempted to blow up [P] with the Detomatix cartridge but failed, blowing themselves up", 1) + else + user.show_message("Success!", 1) + log_admin("[key_name(user)] just attempted to blow up [P] with the Detomatix cartridge and succeded") + message_admins("[key_name_admin(user)] just attempted to blow up [P] with the Detomatix cartridge and succeded", 1) + P.explode() + +/datum/data/pda/messenger_plugin/virus/frame + icon = "exclamation-circle" + +/datum/data/pda/messenger_plugin/virus/frame/user_act(mob/user, obj/item/device/pda/P) + . = ..(user, P) + if(.) + var/lock_code = "[rand(100,999)] [pick("Alpha","Bravo","Charlie","Delta","Echo","Foxtrot","Golf","Hotel","India","Juliet","Kilo","Lima","Mike","November","Oscar","Papa","Quebec","Romeo","Sierra","Tango","Uniform","Victor","Whiskey","X-ray","Yankee","Zulu")]" + user.show_message("Virus Sent! The unlock code to the target is: [lock_code]") + if(!P.hidden_uplink) + var/obj/item/device/uplink/hidden/uplink = new(P) + P.hidden_uplink = uplink + P.lock_code = lock_code + // else + // P.hidden_uplink.hidden_crystals += P.hidden_uplink.uses //Temporarially hide the PDA's crystals, so you can't steal telecrystals. + var/obj/item/weapon/cartridge/frame/parent_cart = pda.cartridge + P.hidden_uplink.uses = parent_cart.telecrystals + parent_cart.telecrystals = 0 + P.hidden_uplink.active = TRUE diff --git a/code/modules/pda/pda.dm b/code/modules/pda/pda.dm index 91784b5de6d..bbb27f9a78e 100644 --- a/code/modules/pda/pda.dm +++ b/code/modules/pda/pda.dm @@ -18,14 +18,10 @@ var/global/list/obj/item/device/pda/PDAs = list() var/owner = null var/default_cartridge = 0 // Access level defined by cartridge var/obj/item/weapon/cartridge/cartridge = null //current cartridge - var/mode = 0 //Controls what menu the PDA will display. 0 is hub; the rest are either built in or based on cartridge. - - var/lastmode = 0 var/ui_tick = 0 - var/nanoUI[0] //Secondary variables - var/scanmode = 0 //1 is medical scanner, 2 is forensics, 3 is reagent scanner. + // var/scanmode = 0 //1 is medical scanner, 2 is forensics, 3 is reagent scanner. var/fon = 0 //Is the flashlight function on? var/f_lum = 2 //Luminosity for the flashlight function var/message_silent = 0 //To beep or not to beep, that is the question @@ -34,7 +30,14 @@ var/global/list/obj/item/device/pda/PDAs = list() var/tnote[0] //Current Texts var/last_text //No text spamming var/last_honk //Also no honk spamming that's bad too - var/ttone = "beep" //The PDA ringtone! + var/ttone = "beep" //The ringtone! + var/list/ttone_sound = list("beep" = 'sound/machines/twobeep.ogg', + "boom" = 'sound/effects/explosionfar.ogg', + "slip" = 'sound/misc/slip.ogg', + "honk" = 'sound/items/bikehorn.ogg', + "SKREE" = 'sound/voice/shriek1.ogg', + // "holy" = 'sound/items/PDA/ambicha4-short.ogg', + "xeno" = 'sound/voice/hiss1.ogg') var/newstone = "beep, beep" //The news ringtone! var/lock_code = "" // Lockcode to unlock uplink var/honkamt = 0 //How many honks left when infected with honk.exe @@ -67,6 +70,24 @@ var/global/list/obj/item/device/pda/PDAs = list() var/spam_proof = FALSE // If true, it can't be spammed by random events. + // App-based PDAs + var/model_name = "Thinktronic 5230 Personal Data Assistant" + var/datum/data/pda/utility/scanmode/scanmode = null + var/datum/data/pda/app/current_app = null + var/datum/data/pda/app/lastapp = null + var/list/programs = list( + new/datum/data/pda/app/main_menu, + new/datum/data/pda/app/notekeeper, + new/datum/data/pda/app/messenger, + new/datum/data/pda/app/manifest, + new/datum/data/pda/app/atmos_scanner, + new/datum/data/pda/utility/scanmode/notes, + new/datum/data/pda/utility/flashlight) + var/list/shortcut_cache = list() + var/list/shortcut_cat_order = list() + var/list/notifying_programs = list() + var/retro_mode = 0 + /obj/item/device/pda/examine(mob/user) . = ..() if(Adjacent(user)) @@ -97,6 +118,32 @@ var/global/list/obj/item/device/pda/PDAs = list() if(iscarbon(user) && !touch_silent) playsound(src, 'sound/machines/pda_click.ogg', 20) +/obj/item/device/pda/proc/play_ringtone() + var/S + + if(ttone in ttone_sound) + S = ttone_sound[ttone] + else + S = 'sound/machines/twobeep.ogg' + playsound(loc, S, 50, 1) + for(var/mob/O in hearers(3, loc)) + O.show_message(text("[bicon(src)] *[ttone]*")) + +/obj/item/device/pda/proc/set_ringtone() + var/t = input("Please enter new ringtone", name, ttone) as text + if(in_range(src, usr) && loc == usr) + if(t) + if(hidden_uplink && hidden_uplink.check_trigger(usr, lowertext(t), lowertext(lock_code))) + to_chat(usr, "The PDA softly beeps.") + close(usr) + else + t = sanitize(copytext(t, 1, 20)) + ttone = t + return 1 + else + close(usr) + return 0 + /obj/item/device/pda/medical default_cartridge = /obj/item/weapon/cartridge/medical icon_state = "pda-m" @@ -442,6 +489,7 @@ var/global/list/obj/item/device/pda/PDAs = list() ..() PDAs += src PDAs = sortAtom(PDAs) + update_programs() if(default_cartridge) cartridge = new default_cartridge(src) new /obj/item/weapon/pen(src) @@ -469,6 +517,7 @@ var/global/list/obj/item/device/pda/PDAs = list() else icon = 'icons/obj/pda_old.dmi' log_debug("Invalid switch for PDA, defaulting to old PDA icons. [pdachoice] chosen.") + start_program(find_program(/datum/data/pda/app/main_menu)) /obj/item/device/pda/proc/can_use() @@ -499,17 +548,25 @@ var/global/list/obj/item/device/pda/PDAs = list() return attack_self(M) return +/obj/item/device/pda/proc/close(mob/user) + var/datum/nanoui/ui = SSnanoui.get_open_ui(user, src, "main") + ui.close() + + SStgui.close_uis(src) /obj/item/device/pda/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) ui_tick++ var/datum/nanoui/old_ui = SSnanoui.get_open_ui(user, src, "main") var/auto_update = 1 - if(mode in no_auto_update) - auto_update = 0 - if(old_ui && (mode == lastmode && ui_tick % 5 && mode in update_every_five)) + if(!current_app) return - lastmode = mode + if(current_app.update == PDA_APP_NOUPDATE && current_app == lastapp) + auto_update = 0 + if(old_ui && (current_app == lastapp && ui_tick % 5 && current_app.update == PDA_APP_UPDATE_SLOW)) + return + + lastapp = current_app var/title = "Personal Data Assistant" @@ -518,156 +575,57 @@ var/global/list/obj/item/device/pda/PDAs = list() data["owner"] = owner // Who is your daddy... data["ownjob"] = ownjob // ...and what does he do? - data["mode"] = mode // The current view - data["scanmode"] = scanmode // Scanners - data["fon"] = fon // Flashlight on? - data["pai"] = (isnull(pai) ? 0 : 1) // pAI inserted? - data["note"] = note // current pda notes - data["message_silent"] = message_silent // does the pda make noise when it receives a message? - data["news_silent"] = news_silent // does the pda make noise when it receives news? - data["touch_silent"] = touch_silent // does the pda make noise when it receives news? - data["toff"] = toff // is the messenger function turned off? - data["active_conversation"] = active_conversation // Which conversation are we following right now? + // update list of shortcuts, only if they changed + if(!shortcut_cache.len) + shortcut_cache = list() + shortcut_cat_order = list() + var/prog_list = programs.Copy() + if(cartridge) + prog_list |= cartridge.programs + for(var/A in prog_list) + var/datum/data/pda/P = A + + if(P.hidden) + continue + var/list/cat + if(P.category in shortcut_cache) + cat = shortcut_cache[P.category] + else + cat = list() + shortcut_cache[P.category] = cat + shortcut_cat_order += P.category + cat |= list(list(name = P.name, icon = P.icon, notify_icon = P.notify_icon, ref = "\ref[P]")) + + // force the order of a few core categories + shortcut_cat_order = list("General") \ + + sortList(shortcut_cat_order - list("General", "Scanners", "Utilities")) \ + + list("Scanners", "Utilities") data["idInserted"] = (id ? 1 : 0) data["idLink"] = (id ? text("[id.registered_name], [id.assignment]") : "--------") - data["cart_loaded"] = cartridge ? 1:0 - if(cartridge) - var/cartdata[0] - cartdata["access"] = list(\ - "access_security" = cartridge.access_security,\ - "access_engine" = cartridge.access_engine,\ - "access_atmos" = cartridge.access_atmos,\ - "access_medical" = cartridge.access_medical,\ - "access_clown" = cartridge.access_clown,\ - "access_mime" = cartridge.access_mime,\ - "access_janitor" = cartridge.access_janitor,\ - "access_quartermaster" = cartridge.access_quartermaster,\ - "access_hydroponics" = cartridge.access_hydroponics,\ - "access_reagent_scanner" = cartridge.access_reagent_scanner,\ - "access_remote_door" = cartridge.access_remote_door,\ - "access_status_display" = cartridge.access_status_display,\ - "access_detonate_pda" = cartridge.access_detonate_pda\ - ) + data["useRetro"] = retro_mode - if(mode in cartmodes) - data["records"] = cartridge.create_NanoUI_values() + data["cartridge_name"] = cartridge ? cartridge.name : "" + data["stationTime"] = worldtime2stationtime(world.time) - if(mode == 0) - cartdata["name"] = cartridge.name - if(isnull(cartridge.radio)) - cartdata["radio"] = 0 - else - if(istype(cartridge.radio, /obj/item/radio/integrated/beepsky)) - cartdata["radio"] = 1 - if(istype(cartridge.radio, /obj/item/radio/integrated/signal)) - cartdata["radio"] = 2 - //if(istype(cartridge.radio, /obj/item/radio/integrated/mule)) - // cartdata["radio"] = 3 + data["app"] = list() + current_app.update_ui(user, data) + data["app"] |= list( + "name" = current_app.title, + "icon" = current_app.icon, + "template" = current_app.template, + "has_back" = current_app.has_back) - if(mode == 2) - cartdata["charges"] = cartridge.charges ? cartridge.charges : 0 - data["cartridge"] = cartdata - - data["stationTime"] = stationtime2text() - data["new_Message"] = new_message - data["new_News"] = new_news - - var/datum/reception/reception = get_reception(src, do_sleep = 0) - var/has_reception = reception.telecomms_reception & TELECOMMS_RECEPTION_SENDER - data["reception"] = has_reception - - if(mode==2) - var/convopdas[0] - var/pdas[0] - var/count = 0 - for (var/obj/item/device/pda/P in PDAs) - if (!P.owner||P.toff||P == src||P.hidden) continue - if(conversations.Find("\ref[P]")) - convopdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "1"))) - else - pdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "0"))) - count++ - - data["convopdas"] = convopdas - data["pdas"] = pdas - data["pda_count"] = count - - if(mode==21) - data["messagescount"] = tnote.len - data["messages"] = tnote - else - data["messagescount"] = null - data["messages"] = null - - if(active_conversation) - for(var/c in tnote) - if(c["target"] == active_conversation) - data["convo_name"] = sanitize(c["owner"]) - data["convo_job"] = sanitize(c["job"]) - break - if(mode==41) - data_core.get_manifest_list() - - - if(mode==3) - data["aircontents"] = src.analyze_air() - if(mode==6) - if(has_reception) - feeds.Cut() - for(var/datum/feed_channel/channel in news_network.network_channels) - feeds[++feeds.len] = list("name" = channel.channel_name, "censored" = channel.censored) - data["feedChannels"] = feeds - if(mode==61) - var/datum/feed_channel/FC - for(FC in news_network.network_channels) - if(FC.channel_name == active_feed["name"]) - break - - var/list/feed = feed_info[active_feed] - if(!feed) - feed = list() - feed["channel"] = FC.channel_name - feed["author"] = "Unknown" - feed["censored"]= 0 - feed["updated"] = -1 - feed_info[active_feed] = feed - - if(FC.updated > feed["updated"] && has_reception) - feed["author"] = FC.author - feed["updated"] = FC.updated - feed["censored"] = FC.censored - - var/list/messages = list() - if(!FC.censored) - var/index = 0 - for(var/datum/feed_message/FM in FC.messages) - index++ - if(FM.img) - usr << browse_rsc(FM.img, "pda_news_tmp_photo_[feed["channel"]]_[index].png") - // News stories are HTML-stripped but require newline replacement to be properly displayed in NanoUI - var/body = replacetext(FM.body, "\n", "
") - messages[++messages.len] = list("author" = FM.author, "body" = body, "message_type" = FM.message_type, "time_stamp" = FM.time_stamp, "has_image" = (FM.img != null), "caption" = FM.caption, "index" = index) - feed["messages"] = messages - - data["feed"] = feed - - data["manifest"] = PDA_Manifest - - nanoUI = data // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) + if(!ui) // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm ui = new(user, src, ui_key, "pda.tmpl", title, 520, 400, state = inventory_state) - // add templates for screens in common with communicator. - ui.add_template("atmosphericScan", "atmospheric_scan.tmpl") - ui.add_template("crewManifest", "crew_manifest.tmpl") + ui.set_state_key("pda") // when the ui is first opened this is the data it will use ui.set_initial_data(data) // open the new ui window @@ -682,24 +640,42 @@ var/global/list/obj/item/device/pda/PDAs = list() return ui_interact(user) //NanoUI requires this proc + tgui_interact(user) return +/obj/item/device/pda/proc/start_program(datum/data/pda/P) + if(P && ((P in programs) || (cartridge && (P in cartridge.programs)))) + return P.start() + return 0 + +/obj/item/device/pda/proc/find_program(type) + var/datum/data/pda/A = locate(type) in programs + if(A) + return A + if(cartridge) + A = locate(type) in cartridge.programs + if(A) + return A + return null + +// force the cache to rebuild on update_ui +/obj/item/device/pda/proc/update_shortcuts() + shortcut_cache.Cut() + +/obj/item/device/pda/proc/update_programs() + for(var/A in programs) + var/datum/data/pda/P = A + P.pda = src + /obj/item/device/pda/Topic(href, href_list) - if(href_list["cartmenu"] && !isnull(cartridge)) - cartridge.Topic(href, href_list) - return 1 - if(href_list["radiomenu"] && !isnull(cartridge) && !isnull(cartridge.radio)) - cartridge.radio.Topic(href, href_list) - return 1 + . = ..() + if(.) + return - - ..() var/mob/user = usr var/datum/nanoui/ui = SSnanoui.get_open_ui(user, src, "main") var/mob/living/U = usr - //Looking for master was kind of pointless since PDAs don't appear to have one. - //if ((src in U.contents) || ( istype(loc, /turf) && in_range(src, U) ) ) - if (usr.stat == DEAD) + if(usr.stat == DEAD) return 0 if(!can_use()) //Why reinvent the wheel? There's a proc that does exactly that. U.unset_machine() @@ -710,293 +686,56 @@ var/global/list/obj/item/device/pda/PDAs = list() add_fingerprint(U) U.set_machine(src) + if(href_list["radiomenu"] && !isnull(cartridge) && !isnull(cartridge.radio)) + cartridge.radio.Topic(href, href_list) + return 1 + + . = 1 + switch(href_list["choice"]) - -//BASIC FUNCTIONS=================================== - - if("Close")//Self explanatory - U.unset_machine() - ui.close() - return 0 - if("Refresh")//Refresh, goes to the end of the proc. - if("Return")//Return - if(mode<=9) - mode = 0 - else - mode = round(mode/10) - if(mode==2) - active_conversation = null - if(mode==4)//Fix for cartridges. Redirects to hub. - mode = 0 - else if(mode >= 40 && mode <= 49)//Fix for cartridges. Redirects to refresh the menu. - cartridge.mode = mode - if ("Authenticate")//Checks for ID - id_check(U, 1) - if("UpdateInfo") - ownjob = id.assignment - ownrank = id.rank - name = "PDA-[owner] ([ownjob])" + if("Home")//Go home, largely replaces the old Return + var/datum/data/pda/app/main_menu/A = find_program(/datum/data/pda/app/main_menu) + if(A) + start_program(A) + if("StartProgram") + if(href_list["program"]) + var/datum/data/pda/app/A = locate(href_list["program"]) + if(A) + start_program(A) if("Eject")//Ejects the cart, only done from hub. - verb_remove_cartridge() - -//MENU FUNCTIONS=================================== - - if("0")//Hub - mode = 0 - if("1")//Notes - mode = 1 - if("2")//Messenger - mode = 2 - if("21")//Read messages - mode = 21 - if("3")//Atmos scan - mode = 3 - if("4")//Redirects to hub - mode = 0 - if("chatroom") // chatroom hub - mode = 5 - if("41") //Manifest - mode = 41 - - -//MAIN FUNCTIONS=================================== - - if("Light") - if(fon) - fon = 0 - set_light(0) - else - fon = 1 - set_light(f_lum) - if("Medical Scan") - if(scanmode == 1) - scanmode = 0 - else if((!isnull(cartridge)) && (cartridge.access_medical)) - scanmode = 1 - if("Reagent Scan") - if(scanmode == 3) - scanmode = 0 - else if((!isnull(cartridge)) && (cartridge.access_reagent_scanner)) - scanmode = 3 - if("Halogen Counter") - if(scanmode == 4) - scanmode = 0 - else if((!isnull(cartridge)) && (cartridge.access_engine)) - scanmode = 4 - if("Honk") - if ( !(last_honk && world.time < last_honk + 20) ) - playsound(src, 'sound/items/bikehorn.ogg', 50, 1) - last_honk = world.time - if("Gas Scan") - if(scanmode == 5) - scanmode = 0 - else if((!isnull(cartridge)) && (cartridge.access_atmos)) - scanmode = 5 - if("Toggle Beeping") - touch_silent = !touch_silent - -//MESSENGER/NOTE FUNCTIONS=================================== - - if ("Edit") - var/n = input(U, "Please enter message", name, notehtml) as message - if (in_range(src, U) && loc == U) - n = sanitizeSafe(n, extra = 0) - if (mode == 1) - note = html_decode(n) - notehtml = note - note = replacetext(note, "\n", "
") - else - ui.close() - if("Toggle Messenger") - toff = !toff - if("Toggle Ringer")//If viewing texts then erase them, if not then toggle silent status - message_silent = !message_silent - if("Toggle News") - news_silent = !news_silent - if("Clear")//Clears messages - if(href_list["option"] == "All") - tnote.Cut() - conversations.Cut() - if(href_list["option"] == "Convo") - var/new_tnote[0] - for(var/i in tnote) - if(i["target"] != active_conversation) - new_tnote[++new_tnote.len] = i - tnote = new_tnote - conversations.Remove(active_conversation) - - active_conversation = null - if(mode==21) - mode=2 - + if(!isnull(cartridge)) + var/turf/T = loc + if(ismob(T)) + T = T.loc + var/obj/item/weapon/cartridge/C = cartridge + C.forceMove(T) + if(scanmode in C.programs) + scanmode = null + if(current_app in C.programs) + start_program(find_program(/datum/data/pda/app/main_menu)) + if(C.radio) + C.radio.hostpda = null + for(var/datum/data/pda/P in notifying_programs) + if(P in C.programs) + P.unnotify() + cartridge = null + update_shortcuts() + if("Authenticate")//Checks for ID + id_check(usr, 1) + if("Retro") + retro_mode = !retro_mode if("Ringtone") - var/t = input(U, "Please enter new ringtone", name, ttone) as text - if (in_range(src, U) && loc == U) - if (t) - if(src.hidden_uplink && hidden_uplink.check_trigger(U, lowertext(t), lowertext(lock_code))) - to_chat(U, "The PDA softly beeps.") - ui.close() - else - t = sanitize(t, 20) - ttone = t - else - ui.close() - return 0 - if("Newstone") - var/t = input(U, "Please enter new news tone", name, newstone) as text - if (in_range(src, U) && loc == U) - if (t) - t = sanitize(t, 20) - newstone = t - else - ui.close() - return 0 - if("Message") - - var/obj/item/device/pda/P = locate(href_list["target"]) - src.create_message(U, P, !href_list["notap"]) - if(mode == 2) - if(href_list["target"] in conversations) // Need to make sure the message went through, if not welp. - active_conversation = href_list["target"] - mode = 21 - - if("Select Conversation") - var/P = href_list["convo"] - for(var/n in conversations) - if(P == n) - active_conversation=P - mode=21 - if("Select Feed") - var/n = href_list["name"] - for(var/f in feeds) - if(f["name"] == n) - active_feed = f - mode=61 - if("Send Honk")//Honk virus - if(cartridge && cartridge.access_clown)//Cartridge checks are kind of unnecessary since everything is done through switch. - var/obj/item/device/pda/P = locate(href_list["target"])//Leaving it alone in case it may do something useful, I guess. - if(!isnull(P)) - if (!P.toff && cartridge.charges > 0) - cartridge.charges-- - U.show_message("Virus sent!", 1) - P.honkamt = (rand(15,20)) - else - to_chat(U, "PDA not found.") - else - ui.close() - return 0 - if("Send Silence")//Silent virus - if(cartridge && cartridge.access_mime) - var/obj/item/device/pda/P = locate(href_list["target"]) - if(!isnull(P)) - if (!P.toff && cartridge.charges > 0) - cartridge.charges-- - U.show_message("Virus sent!", 1) - P.message_silent = 1 - P.news_silent = 1 - P.ttone = "silence" - P.newstone = "silence" - else - to_chat(U, "PDA not found.") - else - ui.close() - return 0 - - -//SYNDICATE FUNCTIONS=================================== - - if("Toggle Door") - if(cartridge && cartridge.access_remote_door) - for(var/obj/machinery/door/blast/M in machines) - if(M.id == cartridge.remote_door_id) - if(M.density) - M.open() - else - M.close() - - if("Detonate")//Detonate PDA... maybe - if(cartridge && cartridge.access_detonate_pda) - var/obj/item/device/pda/P = locate(href_list["target"]) - var/datum/reception/reception = get_reception(src, P, "", do_sleep = 0) - if(!(reception.message_server && reception.telecomms_reception & TELECOMMS_RECEPTION_SENDER)) - U.show_message("An error flashes on your [src]: Connection unavailable", 1) - return - if(reception.telecomms_reception & TELECOMMS_RECEPTION_RECEIVER == 0) // Does our recepient have a broadcaster on their level? - U.show_message("An error flashes on your [src]: Recipient unavailable", 1) - return - if(!isnull(P)) - if (!P.toff && cartridge.charges > 0) - cartridge.charges-- - - var/difficulty = 2 - - if(P.cartridge) - difficulty += P.cartridge.access_medical - difficulty += P.cartridge.access_security - difficulty += P.cartridge.access_engine - difficulty += P.cartridge.access_clown - difficulty += P.cartridge.access_janitor - if(P.hidden_uplink) - difficulty += 3 - - if(prob(difficulty)) - U.show_message("An error flashes on your [src].", 1) - else if (prob(difficulty * 7)) - U.show_message("Energy feeds back into your [src]!", 1) - ui.close() - detonate_act(src) - log_admin("[key_name(U)] just attempted to blow up [P] with the Detomatix cartridge but failed, blowing themselves up") - message_admins("[key_name_admin(U)] just attempted to blow up [P] with the Detomatix cartridge but failed.", 1) - else - U.show_message("Success!", 1) - log_admin("[key_name(U)] just attempted to blow up [P] with the Detomatix cartridge and succeeded") - message_admins("[key_name_admin(U)] just attempted to blow up [P] with the Detomatix cartridge and succeeded.", 1) - detonate_act(P) - else - to_chat(U, "No charges left.") - - else - to_chat(U, "PDA not found.") - else - U.unset_machine() - ui.close() - return 0 - -//pAI FUNCTIONS=================================== - if("pai") - if(pai) - if(pai.loc != src) - pai = null - else - switch(href_list["option"]) - if("1") // Configure pAI device - pai.attack_self(U) - if("2") // Eject pAI device - var/turf/T = get_turf_or_move(src.loc) - if(T) - pai.loc = T - pai = null - + return set_ringtone() else - mode = text2num(href_list["choice"]) - if(cartridge) - cartridge.mode = mode + if(current_app) + . = current_app.Topic(href, href_list) //EXTRA FUNCTIONS=================================== - - if (mode == 2||mode == 21)//To clear message overlays. - new_message = 0 - update_icon() - - if (mode == 6||mode == 61)//To clear news overlays. - new_news = 0 - update_icon() - - if ((honkamt > 0) && (prob(60)))//For clown virus. + if((honkamt > 0) && (prob(60)))//For clown virus. honkamt-- - playsound(src, 'sound/items/bikehorn.ogg', 30, 1) + playsound(loc, 'sound/items/bikehorn.ogg', 30, 1) - return 1 // return 1 tells it to refresh the UI in NanoUI + return // return 1 tells it to refresh the UI in NanoUI /obj/item/device/pda/update_icon() ..() @@ -1230,8 +969,9 @@ var/global/list/obj/item/device/pda/PDAs = list() return if(can_use(usr)) - mode = 0 - SSnanoui.update_uis(src) + start_program(find_program(/datum/data/pda/app/main_menu)) + notifying_programs.Cut() + overlays -= image('icons/obj/pda.dmi', "pda-r") to_chat(usr, "You press the reset button on \the [src].") else to_chat(usr, "You cannot do this while restrained.") @@ -1286,8 +1026,8 @@ var/global/list/obj/item/device/pda/PDAs = list() if(ismob(loc)) var/mob/M = loc M.put_in_hands(cartridge) - mode = 0 - scanmode = 0 + // mode = 0 + // scanmode = 0 if (cartridge.radio) cartridge.radio.hostpda = null to_chat(usr, "You remove \the [cartridge] from the [name].") @@ -1363,128 +1103,132 @@ var/global/list/obj/item/device/pda/PDAs = list() return /obj/item/device/pda/attack(mob/living/C as mob, mob/living/user as mob) - if (istype(C, /mob/living/carbon)) - switch(scanmode) - if(1) + if (istype(C, /mob/living/carbon) && scanmode) + scanmode.scan_mob(C, user) - for (var/mob/O in viewers(C, null)) - O.show_message("\The [user] has analyzed [C]'s vitals!", 1) + // switch(scanmode) + // if(1) - user.show_message("Analyzing Results for [C]:") - user.show_message(" Overall Status: [C.stat > 1 ? "dead" : "[C.health - C.halloss]% healthy"]", 1) - user.show_message(text(" Damage Specifics: []-[]-[]-[]", - (C.getOxyLoss() > 50) ? "warning" : "", C.getOxyLoss(), - (C.getToxLoss() > 50) ? "warning" : "", C.getToxLoss(), - (C.getFireLoss() > 50) ? "warning" : "", C.getFireLoss(), - (C.getBruteLoss() > 50) ? "warning" : "", C.getBruteLoss() - ), 1) - user.show_message(" Key: Suffocation/Toxin/Burns/Brute", 1) - user.show_message(" Body Temperature: [C.bodytemperature-T0C]°C ([C.bodytemperature*1.8-459.67]°F)", 1) - if(C.tod && (C.stat == DEAD || (C.status_flags & FAKEDEATH))) - user.show_message(" Time of Death: [C.tod]") - if(istype(C, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = C - var/list/damaged = H.get_damaged_organs(1,1) - user.show_message("Localized Damage, Brute/Burn:",1) - if(length(damaged)>0) - for(var/obj/item/organ/external/org in damaged) - user.show_message(text(" []: []-[]", - capitalize(org.name), (org.brute_dam > 0) ? "warning" : "notice", org.brute_dam, (org.burn_dam > 0) ? "warning" : "notice", org.burn_dam),1) - else - user.show_message(" Limbs are OK.",1) + // for (var/mob/O in viewers(C, null)) + // O.show_message("\The [user] has analyzed [C]'s vitals!", 1) - if(2) - if (!istype(C:dna, /datum/dna)) - to_chat(user, "No fingerprints found on [C]") - else - to_chat(user, text("\The [C]'s Fingerprints: [md5(C:dna.uni_identity)]")) - if ( !(C:blood_DNA) ) - to_chat(user, "No blood found on [C]") - if(C:blood_DNA) - qdel(C:blood_DNA) - else - to_chat(user, "Blood found on [C]. Analysing...") - spawn(15) - for(var/blood in C:blood_DNA) - to_chat(user, "Blood type: [C:blood_DNA[blood]]\nDNA: [blood]") + // user.show_message("Analyzing Results for [C]:") + // user.show_message(" Overall Status: [C.stat > 1 ? "dead" : "[C.health - C.halloss]% healthy"]", 1) + // user.show_message(text(" Damage Specifics: []-[]-[]-[]", + // (C.getOxyLoss() > 50) ? "warning" : "", C.getOxyLoss(), + // (C.getToxLoss() > 50) ? "warning" : "", C.getToxLoss(), + // (C.getFireLoss() > 50) ? "warning" : "", C.getFireLoss(), + // (C.getBruteLoss() > 50) ? "warning" : "", C.getBruteLoss() + // ), 1) + // user.show_message(" Key: Suffocation/Toxin/Burns/Brute", 1) + // user.show_message(" Body Temperature: [C.bodytemperature-T0C]°C ([C.bodytemperature*1.8-459.67]°F)", 1) + // if(C.tod && (C.stat == DEAD || (C.status_flags & FAKEDEATH))) + // user.show_message(" Time of Death: [C.tod]") + // if(istype(C, /mob/living/carbon/human)) + // var/mob/living/carbon/human/H = C + // var/list/damaged = H.get_damaged_organs(1,1) + // user.show_message("Localized Damage, Brute/Burn:",1) + // if(length(damaged)>0) + // for(var/obj/item/organ/external/org in damaged) + // user.show_message(text(" []: []-[]", + // capitalize(org.name), (org.brute_dam > 0) ? "warning" : "notice", org.brute_dam, (org.burn_dam > 0) ? "warning" : "notice", org.burn_dam),1) + // else + // user.show_message(" Limbs are OK.",1) - if(4) - user.visible_message("\The [user] has analyzed [C]'s radiation levels!", "You have analyzed [C]'s radiation levels!") - to_chat(user, "Analyzing Results for [C]:") - if(C.radiation) - to_chat(user, "Radiation Level: [C.radiation]") - else - to_chat(user, "No radiation detected.") + // if(2) + // if (!istype(C:dna, /datum/dna)) + // to_chat(user, "No fingerprints found on [C]") + // else + // to_chat(user, text("\The [C]'s Fingerprints: [md5(C:dna.uni_identity)]")) + // if ( !(C:blood_DNA) ) + // to_chat(user, "No blood found on [C]") + // if(C:blood_DNA) + // qdel(C:blood_DNA) + // else + // to_chat(user, "Blood found on [C]. Analysing...") + // spawn(15) + // for(var/blood in C:blood_DNA) + // to_chat(user, "Blood type: [C:blood_DNA[blood]]\nDNA: [blood]") + + // if(4) + // user.visible_message("\The [user] has analyzed [C]'s radiation levels!", "You have analyzed [C]'s radiation levels!") + // to_chat(user, "Analyzing Results for [C]:") + // if(C.radiation) + // to_chat(user, "Radiation Level: [C.radiation]") + // else + // to_chat(user, "No radiation detected.") /obj/item/device/pda/afterattack(atom/A as mob|obj|turf|area, mob/user as mob, proximity) - if(!proximity) return - switch(scanmode) + if(proximity && scanmode) + scanmode.scan_atom(A, user) + // if(!proximity) return + // switch(scanmode) - if(3) - if(!isobj(A)) - return - if(!isnull(A.reagents)) - if(A.reagents.reagent_list.len > 0) - var/reagents_length = A.reagents.reagent_list.len - to_chat(user, "[reagents_length] chemical agent[reagents_length > 1 ? "s" : ""] found.") - for (var/re in A.reagents.reagent_list) - to_chat(user, " [re]") - else - to_chat(user, "No active chemical agents found in [A].") - else - to_chat(user, "No significantchemical agents found in [A].") + // if(3) + // if(!isobj(A)) + // return + // if(!isnull(A.reagents)) + // if(A.reagents.reagent_list.len > 0) + // var/reagents_length = A.reagents.reagent_list.len + // to_chat(user, "[reagents_length] chemical agent[reagents_length > 1 ? "s" : ""] found.") + // for (var/re in A.reagents.reagent_list) + // to_chat(user, " [re]") + // else + // to_chat(user, "No active chemical agents found in [A].") + // else + // to_chat(user, "No significantchemical agents found in [A].") - if(5) - analyze_gases(A, user) + // if(5) + // analyze_gases(A, user) - if (!scanmode && istype(A, /obj/item/weapon/paper) && owner) - // JMO 20140705: Makes scanned document show up properly in the notes. Not pretty for formatted documents, - // as this will clobber the HTML, but at least it lets you scan a document. You can restore the original - // notes by editing the note again. (Was going to allow you to edit, but scanned documents are too long.) - var/raw_scan = (A:info) - var/formatted_scan = "" - // Scrub out the tags (replacing a few formatting ones along the way) + // if (!scanmode && istype(A, /obj/item/weapon/paper) && owner) + // // JMO 20140705: Makes scanned document show up properly in the notes. Not pretty for formatted documents, + // // as this will clobber the HTML, but at least it lets you scan a document. You can restore the original + // // notes by editing the note again. (Was going to allow you to edit, but scanned documents are too long.) + // var/raw_scan = (A:info) + // var/formatted_scan = "" + // // Scrub out the tags (replacing a few formatting ones along the way) - // Find the beginning and end of the first tag. - var/tag_start = findtext(raw_scan,"<") - var/tag_stop = findtext(raw_scan,">") + // // Find the beginning and end of the first tag. + // var/tag_start = findtext(raw_scan,"<") + // var/tag_stop = findtext(raw_scan,">") - // Until we run out of complete tags... - while(tag_start&&tag_stop) - var/pre = copytext(raw_scan,1,tag_start) // Get the stuff that comes before the tag - var/tag = lowertext(copytext(raw_scan,tag_start+1,tag_stop)) // Get the tag so we can do intellegent replacement - var/tagend = findtext(tag," ") // Find the first space in the tag if there is one. + // // Until we run out of complete tags... + // while(tag_start&&tag_stop) + // var/pre = copytext(raw_scan,1,tag_start) // Get the stuff that comes before the tag + // var/tag = lowertext(copytext(raw_scan,tag_start+1,tag_stop)) // Get the tag so we can do intellegent replacement + // var/tagend = findtext(tag," ") // Find the first space in the tag if there is one. - // Anything that's before the tag can just be added as is. - formatted_scan = formatted_scan+pre + // // Anything that's before the tag can just be added as is. + // formatted_scan = formatted_scan+pre - // If we have a space after the tag (and presumably attributes) just crop that off. - if (tagend) - tag=copytext(tag,1,tagend) + // // If we have a space after the tag (and presumably attributes) just crop that off. + // if (tagend) + // tag=copytext(tag,1,tagend) - if (tag=="p"||tag=="/p"||tag=="br") // Check if it's I vertical space tag. - formatted_scan=formatted_scan+"
" // If so, add some padding in. + // if (tag=="p"||tag=="/p"||tag=="br") // Check if it's I vertical space tag. + // formatted_scan=formatted_scan+"
" // If so, add some padding in. - raw_scan = copytext(raw_scan,tag_stop+1) // continue on with the stuff after the tag + // raw_scan = copytext(raw_scan,tag_stop+1) // continue on with the stuff after the tag - // Look for the next tag in what's left - tag_start = findtext(raw_scan,"<") - tag_stop = findtext(raw_scan,">") + // // Look for the next tag in what's left + // tag_start = findtext(raw_scan,"<") + // tag_stop = findtext(raw_scan,">") - // Anything that is left in the page. just tack it on to the end as is - formatted_scan=formatted_scan+raw_scan + // // Anything that is left in the page. just tack it on to the end as is + // formatted_scan=formatted_scan+raw_scan - // If there is something in there already, pad it out. - if (length(note)>0) - note = note + "

" + // // If there is something in there already, pad it out. + // if (length(note)>0) + // note = note + "

" - // Store the scanned document to the notes - note = "Scanned Document. Edit to restore previous notes/delete scan.
----------
" + formatted_scan + "
" - // notehtml ISN'T set to allow user to get their old notes back. A better implementation would add a "scanned documents" - // feature to the PDA, which would better convey the availability of the feature, but this will work for now. + // // Store the scanned document to the notes + // note = "Scanned Document. Edit to restore previous notes/delete scan.
----------
" + formatted_scan + "
" + // // notehtml ISN'T set to allow user to get their old notes back. A better implementation would add a "scanned documents" + // // feature to the PDA, which would better convey the availability of the feature, but this will work for now. - // Inform the user - to_chat(user, "Paper scanned and OCRed to notekeeper.") //concept of scanning paper copyright brainoblivion 2009 + // // Inform the user + // to_chat(user, "Paper scanned and OCRed to notekeeper.") //concept of scanning paper copyright brainoblivion 2009 /obj/item/device/pda/proc/explode() //This needs tuning. //Sure did. @@ -1501,8 +1245,12 @@ var/global/list/obj/item/device/pda/PDAs = list() src.id.forceMove(get_turf(src.loc)) else QDEL_NULL(src.id) - QDEL_NULL(src.cartridge) - QDEL_NULL(src.pai) + + current_app = null + scanmode = null + QDEL_NULL(pai) + QDEL_LIST(programs) + QDEL_NULL(cartridge) return ..() /obj/item/device/pda/clown/Crossed(atom/movable/AM as mob|obj) //Clown PDA is slippery. diff --git a/code/modules/pda/pda_tgui.dm b/code/modules/pda/pda_tgui.dm new file mode 100644 index 00000000000..532c31fc80f --- /dev/null +++ b/code/modules/pda/pda_tgui.dm @@ -0,0 +1,59 @@ +// Self contained file for all things TGUI +/obj/item/device/pda/tgui_state(mob/user) + return GLOB.tgui_inventory_state + +/obj/item/device/pda/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Pda", "Personal Data Assistant") + ui.open() + +/obj/item/device/pda/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + + data["owner"] = owner // Who is your daddy... + data["ownjob"] = ownjob // ...and what does he do? + + // update list of shortcuts, only if they changed + if(!shortcut_cache.len) + shortcut_cache = list() + shortcut_cat_order = list() + var/prog_list = programs.Copy() + if(cartridge) + prog_list |= cartridge.programs + + for(var/A in prog_list) + var/datum/data/pda/P = A + + if(P.hidden) + continue + var/list/cat + if(P.category in shortcut_cache) + cat = shortcut_cache[P.category] + else + cat = list() + shortcut_cache[P.category] = cat + shortcut_cat_order += P.category + cat |= list(list(name = P.name, icon = P.icon, notify_icon = P.notify_icon, ref = "\ref[P]")) + + // force the order of a few core categories + shortcut_cat_order = list("General") \ + + sortList(shortcut_cat_order - list("General", "Scanners", "Utilities")) \ + + list("Scanners", "Utilities") + + data["idInserted"] = (id ? 1 : 0) + data["idLink"] = (id ? text("[id.registered_name], [id.assignment]") : "--------") + + data["useRetro"] = retro_mode + + data["cartridge_name"] = cartridge ? cartridge.name : "" + data["stationTime"] = worldtime2stationtime(world.time) + + data["app"] = list( + "name" = current_app.title, + "icon" = current_app.icon, + "template" = current_app.template, + "has_back" = current_app.has_back) + current_app.update_ui(user, data) + + return data \ No newline at end of file diff --git a/code/modules/pda/utilities.dm b/code/modules/pda/utilities.dm new file mode 100644 index 00000000000..dee706b88af --- /dev/null +++ b/code/modules/pda/utilities.dm @@ -0,0 +1,200 @@ +/datum/data/pda/utility/flashlight + name = "Enable Flashlight" + icon = "lightbulb-o" + + var/fon = 0 //Is the flashlight function on? + var/f_lum = 2 //Luminosity for the flashlight function + +/datum/data/pda/utility/flashlight/start() + fon = !fon + name = fon ? "Disable Flashlight" : "Enable Flashlight" + pda.update_shortcuts() + pda.set_light(fon ? f_lum : 0) + +/datum/data/pda/utility/honk + name = "Honk Synthesizer" + icon = "smile-o" + category = "Clown" + + var/last_honk //Also no honk spamming that's bad too + +/datum/data/pda/utility/honk/start() + if(!(last_honk && world.time < last_honk + 20)) + playsound(pda.loc, 'sound/items/bikehorn.ogg', 50, 1) + last_honk = world.time + +/datum/data/pda/utility/toggle_door + name = "Toggle Door" + icon = "external-link" + var/remote_door_id = "" + +// /datum/data/pda/utility/toggle_door/start() +// for(var/obj/machinery/door/poddoor/M in airlocks) +// if(M.id_tag == remote_door_id) +// if(M.density) +// M.open() +// else +// M.close() + +/datum/data/pda/utility/scanmode/medical + base_name = "Med Scanner" + icon = "heart-o" + +/datum/data/pda/utility/scanmode/medical/scan_mob(mob/living/C as mob, mob/living/user as mob) + C.visible_message("[user] has analyzed [C]'s vitals!") + + user.show_message("Analyzing Results for [C]:") + user.show_message("\t Overall Status: [C.stat > 1 ? "dead" : "[C.health]% healthy"]", 1) + user.show_message("\t Damage Specifics: [C.getOxyLoss() > 50 ? "" : ""][C.getOxyLoss()]-[C.getToxLoss() > 50 ? "" : ""][C.getToxLoss()]-[C.getFireLoss() > 50 ? "" : ""][C.getFireLoss()]-[C.getBruteLoss() > 50 ? "" : ""][C.getBruteLoss()]", 1) + user.show_message("\t Key: Suffocation/Toxin/Burns/Brute", 1) + user.show_message("\t Body Temperature: [C.bodytemperature-T0C]°C ([C.bodytemperature*1.8-459.67]°F)", 1) + if(C.tod && (C.stat == DEAD || (C.status_flags & FAKEDEATH))) + user.show_message("\t Time of Death: [C.tod]") + if(istype(C, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = C + var/list/damaged = H.get_damaged_organs(1,1) + user.show_message("Localized Damage, Brute/Burn:",1) + if(length(damaged)>0) + for(var/obj/item/organ/external/org in damaged) + user.show_message("\t [capitalize(org.name)]: [org.brute_dam > 0 ? "[org.brute_dam]" : "0"]-[org.burn_dam > 0 ? "[org.burn_dam]" : "0"]", 1) + else + user.show_message("\t Limbs are OK.",1) + +/datum/data/pda/utility/scanmode/dna + base_name = "DNA Scanner" + icon = "link" + +/datum/data/pda/utility/scanmode/dna/scan_mob(mob/living/C as mob, mob/living/user as mob) + if(istype(C, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = C + if(!istype(H.dna, /datum/dna)) + to_chat(user, "No fingerprints found on [H]") + else + to_chat(user, "[H]'s Fingerprints: [md5(H.dna.uni_identity)]") + scan_blood(C, user) + +/datum/data/pda/utility/scanmode/dna/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob) + scan_blood(A, user) + +/datum/data/pda/utility/scanmode/dna/proc/scan_blood(atom/A, mob/user) + if(!A.blood_DNA) + to_chat(user, "No blood found on [A]") + if(A.blood_DNA) + qdel(A.blood_DNA) + else + to_chat(user, "Blood found on [A]. Analysing...") + spawn(15) + for(var/blood in A.blood_DNA) + to_chat(user, "Blood type: [A.blood_DNA[blood]]\nDNA: [blood]") + +/datum/data/pda/utility/scanmode/halogen + base_name = "Halogen Counter" + icon = "exclamation-circle" + +/datum/data/pda/utility/scanmode/halogen/scan_mob(mob/living/C as mob, mob/living/user as mob) + C.visible_message("[user] has analyzed [C]'s radiation levels!") + + user.show_message("Analyzing Results for [C]:") + if(C.radiation) + user.show_message("Radiation Level: [C.radiation > 0 ? "[C.radiation]" : "0"]") + else + user.show_message("No radiation detected.") + +/datum/data/pda/utility/scanmode/reagent + base_name = "Reagent Scanner" + icon = "flask" + +/datum/data/pda/utility/scanmode/reagent/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob) + if(!isnull(A.reagents)) + if(A.reagents.reagent_list.len > 0) + var/reagents_length = A.reagents.reagent_list.len + to_chat(user, "[reagents_length] chemical agent[reagents_length > 1 ? "s" : ""] found.") + for(var/re in A.reagents.reagent_list) + to_chat(user, "\t [re]") + else + to_chat(user, "No active chemical agents found in [A].") + else + to_chat(user, "No significant chemical agents found in [A].") + +/datum/data/pda/utility/scanmode/gas + base_name = "Gas Scanner" + icon = "tachometer" + +/datum/data/pda/utility/scanmode/gas/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob) + // if(istype(A, /obj/item/tank)) + // var/obj/item/tank/T = A + // pda.atmosanalyzer_scan(T.air_contents, user, T) + // else if(istype(A, /obj/machinery/portable_atmospherics)) + // var/obj/machinery/portable_atmospherics/T = A + // pda.atmosanalyzer_scan(T.air_contents, user, T) + // else if(istype(A, /obj/machinery/atmospherics/pipe)) + // var/obj/machinery/atmospherics/pipe/T = A + // pda.atmosanalyzer_scan(T.parent.air, user, T) + // else if(istype(A, /obj/machinery/power/rad_collector)) + // var/obj/machinery/power/rad_collector/T = A + // if(T.P) + // pda.atmosanalyzer_scan(T.P.air_contents, user, T) + // else if(istype(A, /obj/item/flamethrower)) + // var/obj/item/flamethrower/T = A + // if(T.ptank) + // pda.atmosanalyzer_scan(T.ptank.air_contents, user, T) + // else if(istype(A, /obj/machinery/portable_atmospherics/scrubber/huge)) + // var/obj/machinery/portable_atmospherics/scrubber/huge/T = A + // pda.atmosanalyzer_scan(T.air_contents, user, T) + // else if(istype(A, /obj/machinery/atmospherics/unary/tank)) + // var/obj/machinery/atmospherics/unary/tank/T = A + // pda.atmosanalyzer_scan(T.air_contents, user, T) + +/datum/data/pda/utility/scanmode/notes + base_name = "Note Scanner" + icon = "clipboard" + var/datum/data/pda/app/notekeeper/notes + +/datum/data/pda/utility/scanmode/notes/start() + . = ..() + notes = pda.find_program(/datum/data/pda/app/notekeeper) + +/datum/data/pda/utility/scanmode/notes/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob) + if(notes && istype(A, /obj/item/weapon/paper)) + var/obj/item/weapon/paper/P = A + var/list/brlist = list("p", "/p", "br", "hr", "h1", "h2", "h3", "h4", "/h1", "/h2", "/h3", "/h4") + + // JMO 20140705: Makes scanned document show up properly in the notes. Not pretty for formatted documents, + // as this will clobber the HTML, but at least it lets you scan a document. You can restore the original + // notes by editing the note again. (Was going to allow you to edit, but scanned documents are too long.) + var/raw_scan = sanitize_simple(P.info, list("\t" = "", "ÿ" = "")) + var/formatted_scan = "" + // Scrub out the tags (replacing a few formatting ones along the way) + // Find the beginning and end of the first tag. + var/tag_start = findtext(raw_scan, "<") + var/tag_stop = findtext(raw_scan, ">") + // Until we run out of complete tags... + while(tag_start && tag_stop) + var/pre = copytext(raw_scan, 1, tag_start) // Get the stuff that comes before the tag + var/tag = lowertext(copytext(raw_scan, tag_start + 1, tag_stop)) // Get the tag so we can do intellegent replacement + var/tagend = findtext(tag, " ") // Find the first space in the tag if there is one. + // Anything that's before the tag can just be added as is. + formatted_scan = formatted_scan + pre + // If we have a space after the tag (and presumably attributes) just crop that off. + if(tagend) + tag = copytext(tag, 1, tagend) + if(tag in brlist) // Check if it's I vertical space tag. + formatted_scan = formatted_scan + "
" // If so, add some padding in. + raw_scan = copytext(raw_scan, tag_stop + 1) // continue on with the stuff after the tag + // Look for the next tag in what's left + tag_start = findtext(raw_scan, "<") + tag_stop = findtext(raw_scan, ">") + // Anything that is left in the page. just tack it on to the end as is + formatted_scan = formatted_scan + raw_scan + // If there is something in there already, pad it out. + if(length(notes.note) > 0) + notes.note += "

" + // Store the scanned document to the notes + notes.note += "Scanned Document. Edit to restore previous notes/delete scan.
----------
" + formatted_scan + "
" + // notehtml ISN'T set to allow user to get their old notes back. A better implementation would add a "scanned documents" + // feature to the PDA, which would better convey the availability of the feature, but this will work for now. + // Inform the user + to_chat(user, "Paper scanned and OCRed to notekeeper.")//concept of scanning paper copyright brainoblivion 2009 + + else + to_chat(user, "Error scanning [A].") diff --git a/nano/css/shared.css b/nano/css/shared.css index 3517402e2af..83d1e85cc3c 100644 --- a/nano/css/shared.css +++ b/nano/css/shared.css @@ -48,13 +48,13 @@ hr { .link32 { float: left; min-width: 15px; - max-width: 31px; + max-width: 31px; height: 31px; text-align: center; - text-decoration: none; - background: #40628a; + text-decoration: none; + background: #40628a; border: 1px solid #161616; - margin: 0 2px 2px 0; + margin: 0 2px 2px 0; cursor: default; } @@ -191,7 +191,7 @@ h4 { } .greenButton { - background: #00aa00; + background: #00aa00; } .yellowButton { @@ -209,11 +209,11 @@ h4 { .caption { font-size: 10px; font-weight: bold; - padding: 5px; + padding: 5px; } .footer { - font-size: 10px; + font-size: 10px; } .multiLine { @@ -267,7 +267,7 @@ div.notice { width: 100%; margin: 4px 0 0 0; clear: both; - overflow: auto; + overflow: auto; } .itemContentNarrow, .itemContent, .itemContentWide, .itemContentSmall, .itemContentMedium { @@ -325,7 +325,7 @@ div.notice { border: 1px solid #40628a; padding: 4px; margin: 3px 0; - overflow: hidden; + overflow: hidden; } .statusDisplayRecords { @@ -339,16 +339,16 @@ div.notice { } .statusDisplayComm { - width: 100%; + width: 100%; background: rgba(0, 0, 0, 0.5); color: #ffffff; - padding-bottom: 4px; - border-top: 0 none; - border-left: 0 none; - border-right: 0 none; - border-bottom: 2px inset #40628a; + padding-bottom: 4px; + border-top: 0 none; + border-left: 0 none; + border-right: 0 none; + border-bottom: 2px inset #40628a; margin: 3px 0; - overflow: hidden; + overflow: hidden; } .statusLabel { @@ -410,7 +410,7 @@ div.notice { float: left; margin: 0 5px 0 0; overflow: hidden; - background: #40628a; + background: #40628a; } .displayBarVerticalFill { @@ -418,7 +418,7 @@ div.notice { height: 0%; overflow: hidden; float: left; - background: #000000; + background: #000000; } /*used in xenobio2 computer*/ @@ -428,12 +428,12 @@ div.notice { width: 100px; height: 110px; border-right: 2px solid rgb(102, 179, 255); - border-left: 2px solid rgb(102, 179, 255); - border-bottom: 2px solid rgb(102, 179, 255); + border-left: 2px solid rgb(102, 179, 255); + border-bottom: 2px solid rgb(102, 179, 255); float: left; margin: 0 5px 0 0; overflow: hidden; - background: #40628a; + background: #40628a; } .displayBarBeakerFill { @@ -441,7 +441,7 @@ div.notice { height: 0%; overflow: hidden; float: left; - background: rgba(153, 204, 255, 0.3); + background: rgba(153, 204, 255, 0.3); } .displayBarFill.alignRight { @@ -514,7 +514,7 @@ div.notice { .fixedLeftWiderRed { width: 220px; float: left; - background: #ee0000; + background: #ee0000; } .floatRight { @@ -522,7 +522,7 @@ div.notice { } .floatLeft { - float: left; + float: left; } /* Used in PDA */ @@ -538,6 +538,14 @@ div.notice { .pdalink { float: left; white-space: nowrap; + cursor: default !important; +} + +.pdalink.disabled { + background: none; + border: none; + color: #999; + text-align: left; } /* DNA Modifier UI (dna_modifier.tmpl) */ @@ -585,11 +593,11 @@ div.notice { } table.fixed { - table-layout:fixed; + table-layout:fixed; } table.fixed td { - overflow: hidden; + overflow: hidden; } /* Table stuffs for power monitor */ @@ -641,9 +649,9 @@ th.Cargo { } th.Planetside{ - background: #555555; - font-weight: bold; - color: #ffffff; + background: #555555; + font-weight: bold; + color: #ffffff; } th.Civilian { @@ -659,9 +667,9 @@ th.Miscellaneous { } th.Silicon { - background: #222222; - font-weight: bold; - color: #ffffff; + background: #222222; + font-weight: bold; + color: #ffffff; } /* Damage/health colors for crew monitoring computer */ @@ -696,20 +704,20 @@ th.Silicon { /*Communicator Homescreen*/ div.homeContainer { - width: 100%; - text-align: center; - margin: auto; - padding-top: 5px; + width: 100%; + text-align: center; + margin: auto; + padding-top: 5px; } div.homeScreen { - padding: 0 20px 0 20px; + padding: 0 20px 0 20px; } .link64 { float: left; min-width: 15px; - max-width: 68px; + max-width: 68px; height: 64px; text-align: center; color: #ffffff; @@ -717,43 +725,43 @@ div.homeScreen { background: rgba(64, 98, 138, 0.6); border: 1px solid #161616; padding: 0 0 4px 0; - margin: 0 0 30px 5.5%; + margin: 0 0 30px 5.5%; cursor: default; - border-radius: 10px; + border-radius: 10px; } .link64:hover { - font-size: 13px; + font-size: 13px; } /*Communicator Dialing*/ .dialPad { clear: both; - text-align: center; - margin: auto; + text-align: center; + margin: auto; } .dialPadKeys { float: left; - width: 47px; - height: 47px; - font-size: 32px; - text-align: center; + width: 47px; + height: 47px; + font-size: 32px; + text-align: center; color: #ffffff; text-decoration: none; background: rgba(64, 98, 138, 0.15); border: 1px inset rgba(100, 100, 100, 0.25); cursor: default; - line-height: 47px; + line-height: 47px; } .dialPadKeys:hover { - background: rgba(80, 122, 172, 0.5); + background: rgba(80, 122, 172, 0.5); } .dialPadButtons { float: left; - width: 63.2px; + width: 63.2px; height: 63.2px; text-align: center; color: #ffffff; @@ -762,42 +770,88 @@ div.homeScreen { border: 1px inset rgba(100, 100, 100, 0.25); padding: 0 0 4px 0; cursor: default; - margin-bottom: 25px; + margin-bottom: 25px; } .dialPadButtons:hover { - background: rgba(80, 122, 172, 0.5); - font-size: 13px; - + background: rgba(80, 122, 172, 0.5); + font-size: 13px; + } .dialPadAddress { float: left; - width: 192px; - height: 18px; + width: 192px; + height: 18px; background: rgba(64, 98, 138, 0.15); - color: #ffffff; - border-left: 1px inset #40628a; - border-top: 1px inset #40628a; - border-bottom: 1px inset #40628a; + color: #ffffff; + border-left: 1px inset #40628a; + border-top: 1px inset #40628a; + border-bottom: 1px inset #40628a; } .dialPadAddress:hover{ - background: rgba(80, 122, 172, 0.5); + background: rgba(80, 122, 172, 0.5); } .dialPadClear { float: left; - width: 19%; - height: 18px; + width: 19%; + height: 18px; background: rgba(64, 98, 138, 0.15); - color: #ffffff; - border-right: 1px inset #40628a; - border-top: 1px inset #40628a; - border-bottom: 1px inset #40628a; + color: #ffffff; + border-right: 1px inset #40628a; + border-top: 1px inset #40628a; + border-bottom: 1px inset #40628a; } .dialPadClear:hover{ - background: rgba(80, 122, 172, 0.5); -} \ No newline at end of file + background: rgba(80, 122, 172, 0.5); +} + + +.item.mainmenu { + padding-bottom: 0.5em; +} + +div.clock { + color: white; + font-weight: bold; + float: right; + padding-right: 2em; +} + +#pdaFooter { + position: fixed; + left: 0; + bottom: 0; + width: 100%; + background: #2c2c2c; +} + +.pdaFooterButton { + width: 33%; + padding: 0.5em 0; + font-size: 200%; + border: none; + background: none; + color: #fff; +} + +.pdaFooterButton:hover { + background: #507aac; +} + +.pdaFooterButton.disabled { + background: none !important; + color: #555 !important; +} + +.pdaFooterButton.uiLinkPendingIcon { + position: absolute; + width: 33%; + background-repeat: no-repeat; + background-position: center; +} + diff --git a/nano/js/nano_state_pda.js b/nano/js/nano_state_pda.js new file mode 100644 index 00000000000..a27da2e1c12 --- /dev/null +++ b/nano/js/nano_state_pda.js @@ -0,0 +1,51 @@ +NanoStatePDAClass.inheritsFrom(NanoStateClass); +var NanoStatePDA = new NanoStatePDAClass(); + +function NanoStatePDAClass() { + this.key = 'pda'; + this.key = this.key.toLowerCase(); + this.current_template = ""; + + NanoStateManager.addState(this); +} + +NanoStatePDAClass.prototype.onUpdate = function(data) { + NanoStateClass.prototype.onUpdate.call(this, data); + var state = this; + + try { + if(data['data']['app'] != null) { + var template = data['data']['app']['template']; + if(template != null && template != state.current_template) { + var templateMarkup = nanouiTemplateBundle()[template + ".tmpl"]; + if (templateMarkup) { + templateMarkup += '
'; + + try { + NanoTemplate.addTemplate('app', templateMarkup); + NanoTemplate.resetTemplate('app'); + $("#uiApp").html(NanoTemplate.parse('app', data)); + state.current_template = template; + + if(data['config']['status'] == 2) { + $('#uiApp .linkActive').addClass('linkPending'); + $('#uiApp .linkActive').oneTime(400, 'linkPending', function () { + $('#uiApp .linkActive').removeClass('linkPending inactive'); + }); + } + } catch(error) { + reportError('ERROR: An error occurred while loading the PDA App UI: ' + error.message); + return; + } + } + } else { + if (NanoTemplate.templateExists('app')) { + $("#uiApp").html(NanoTemplate.parse('app', data)); + } + } + } + } catch(error) { + reportError('ERROR: An error occurred while rendering the PDA App UI: ' + error.message); + return; + } +} \ No newline at end of file diff --git a/nano/js/nano_template.js b/nano/js/nano_template.js index b50df1281a7..a8b095da7cd 100644 --- a/nano/js/nano_template.js +++ b/nano/js/nano_template.js @@ -76,6 +76,9 @@ var NanoTemplate = function () { templateExists: function (key) { return _templates.hasOwnProperty(key); }, + resetTemplate: function (key) { + _compiledTemplates[key] = null; + }, parse: function (templateKey, data) { if (!_compiledTemplates.hasOwnProperty(templateKey) || !_compiledTemplates[templateKey]) { if (!_templates.hasOwnProperty(templateKey)) { diff --git a/nano/js/nano_utility.js b/nano/js/nano_utility.js index e65b7bbd138..879d3409922 100644 --- a/nano/js/nano_utility.js +++ b/nano/js/nano_utility.js @@ -166,4 +166,9 @@ if (!String.prototype.ckey) { String.prototype.ckey = function () { return this.replace(/\W/g, '').toLowerCase(); }; +} + +var reportError = function (str) { + window.location = "byond://?nano_err=" + encodeURIComponent(str); + alert(str); } \ No newline at end of file diff --git a/nano/templates/pda.tmpl b/nano/templates/pda.tmpl index 3177450ba64..61579d0fb6d 100644 --- a/nano/templates/pda.tmpl +++ b/nano/templates/pda.tmpl @@ -1,784 +1,156 @@ - +{{if data.useRetro}} + + + +{{/if}} {{if data.owner}}
-
- Functions: -
-
- - {{:helper.link('Close', 'gear', {'choice' : "Close"}, null, 'fixedLeft')}} - {{if data.idInserted}} {{:helper.link('Update PDA Info', 'eject', {'choice' : "UpdateInfo"}, null, 'fixedLeftWide')}} {{/if}} - {{if data.mode != 0}} {{:helper.link('Return', 'arrowreturn-1-w', {'choice' : "Return"}, null, 'fixedLeft')}} {{/if}} +
+ {{if data.idInserted}} + {{:helper.link(data.idLink, 'eject', {'choice' : "Authenticate"}, null, 'pdalink fixedLeftWide')}} + {{/if}} + {{if data.cartridge_name}} + {{:helper.link(data.cartridge_name, 'eject', {'choice' : "Eject"}, null, 'pdalink fixedLeftWidest')}} + {{/if}} + {{:helper.link('Toggle R.E.T.R.O. mode', 'gear', {'choice': "Retro"}, null, 'pdalink fixedLeftWide')}} +
+
+ {{:data.stationTime}}
-
-
-
- Station Time: -
-
- {{:data.stationTime}} -
+ + {{if data.app}} +

 {{:data.app.name}}

+
+
 
+ {{/if}} + +
+ {{:helper.link("", 'back', {'choice' : "Back"}, data.app.has_back ? null : 'disabled', 'link pdaFooterButton')}} + {{:helper.link("", 'home', {'choice' : "Home"}, data.app.is_home ? 'disabled' : null, 'link pdaFooterButton')}}
-
- - - {{if data.mode == 0}} -
-
- Owner: -
-
- {{:data.owner}}, {{:data.ownjob}} -
-
-
-
-
- ID: -
-
- {{:helper.link(data.idLink, 'eject', {'choice' : "Authenticate"}, data.idInserted ? null : 'disabled', data.idInserted ? 'floatright' : 'fixedLeft')}} -
-
-
-
-
- Cartridge: -
-
- {{if data.cart_loaded==1}} - {{:helper.link(data.cartridge.name, 'eject', {'choice' : "Eject"},null,null)}} - {{else}} - {{:helper.link('None', 'eject', {'choice' : "Eject"},'disabled',null)}} - {{/if}} -
-
-
-

Functions

-
-
-
- General: -
-
- {{:helper.link('Notekeeper', 'note', {'choice' : "1"}, null, 'fixedLeftWide')}} - {{:helper.link('Messenger', data.new_Message ? 'mail-closed' : 'mail-open', {'choice' : "2"}, null, 'fixedLeftWide')}} - {{:helper.link('Crew Manifest', 'contact', {'choice' : "41"}, null, 'fixedLeftWide')}} - {{:helper.link('News', data.new_News ? 'mail-closed' : 'mail-open', {'choice' : "6"}, null, 'fixedLeftWide')}} -
-
-
- {{if data.cartridge}} - {{if data.cartridge.access.access_clown == 1}} -
-
- Clown: -
-
- {{:helper.link('Honk Synthesizer', 'gear', {'choice' : "Honk"}, null, 'fixedLeftWide')}} -
-
-
- {{/if}} - {{if data.cartridge.access.access_engine == 1}} -
-
- Engineering: -
-
- {{:helper.link('Power Monitor', 'alert', {'choice' : "43"}, null, 'fixedLeftWide')}} -
-
-
- {{/if}} - {{if data.cartridge.access.access_medical == 1}} -
-
- Medical: -
-
- {{:helper.link('Medical Records', 'gear', {'choice' : "44"}, null, 'fixedLeftWide')}} - {{:helper.link(data.scanmode == 1 ? 'Disable Med Scanner' : 'Enable Med Scanner', 'gear', {'choice' : "Medical Scan"}, null , 'fixedLeftWide')}} -
-
-
- {{/if}} - {{if data.cartridge.access.access_security == 1}} -
-
- Security: -
-
- {{:helper.link('Security Records', 'gear', {'choice' : "45"}, null, 'fixedLeftWide')}} - {{if data.cartridge.radio ==1}} {{:helper.link('Security Bot Access', 'gear', {'choice' : "46"}, null, 'fixedLeftWide')}} {{/if}} -
-
-
-
- {{/if}} - {{if data.cartridge.access.access_quartermaster == 1}} -
-
- Quartermaster: -
-
- {{:helper.link('Supply Records', 'gear', {'choice' : "47"}, null, 'fixedLeftWide')}} - {{:helper.link('Delivery Bot Control', 'gear', {'choice' : "48"}, null, 'fixedLeftWide')}} -
-
-
-
- {{/if}} - {{/if}} -
-
-
- Utilities: -
-
- {{if data.cartridge}} - {{if data.cartridge.access.access_status_display == 1}} - {{:helper.link('Status Display', 'gear', {'choice' : "42"}, null, 'fixedLeftWide')}} - {{/if}} - {{if data.cartridge.access.access_janitor==1}} - {{:helper.link('Custodial Locator', 'gear', {'choice' : "49"}, null, 'fixedLeftWide')}} - {{/if}} - {{if data.cartridge.radio == 2}} - {{:helper.link('Signaler System', 'gear', {'choice' : "40"}, null, 'fixedLeftWide')}} - {{/if}} - {{if data.cartridge.access.access_reagent_scanner==1}} - {{:helper.link(data.scanmode == 3 ? 'Disable Reagent Scanner' : 'Enable Reagent Scanner', 'gear', {'choice' : "Reagent Scan"}, null, 'fixedLeftWider')}} - {{/if}} - {{if data.cartridge.access.access_engine==1}} - {{:helper.link(data.scanmode == 4 ? 'Disable Halogen Counter' : 'Enable Halogen Counter', 'gear', {'choice' : "Halogen Counter"}, null, 'fixedLeftWider')}} - {{/if}} - {{if data.cartridge.access.access_atmos==1}} - {{:helper.link(data.scanmode == 5 ? 'Disable Gas Scanner' : 'Enable Gas Scanner', 'gear', {'choice' : "Gas Scan"}, null, 'fixedLeftWide')}} - {{/if}} - {{if data.cartridge.access.access_remote_door==1}} - {{:helper.link('Toggle Door', 'gear', {'choice' : "Toggle Door"}, null, 'fixedLeftWide')}} - {{/if}} - {{/if}} - {{:helper.link('Atmospheric Scan', 'gear', {'choice' : "3"}, null, 'fixedLeftWide')}} - {{:helper.link(data.touch_silent==1 ? 'Enable Beeping' : 'Disable Beeping', 'gear', {'choice' : "Toggle Beeping"}, null,'fixedLeftWide')}} - {{:helper.link(data.fon==1 ? 'Disable Flashlight' : 'Enable Flashlight', 'lightbulb', {'choice' : "Light"}, null,'fixedLeftWide')}} -
-
- {{if data.pai}} -
-
- PAI Utilities: -
-
- {{:helper.link('Configuration', 'gear', {'choice' : "pai", 'option' : "1"}, null, 'fixedLeft')}} - {{:helper.link('Eject pAI', 'eject', {'choice' : "pai", 'option' : "2"}, null, 'fixedLeft')}} -
-
- {{/if}} - - - {{else data.mode == 1}} -
-
- Notes: -
-
-
-
-
- {{:data.note}} -
-
-
-
-
- {{:helper.link('Edit Notes', 'gear', {'choice' : "Edit"}, null, 'fixedLeft')}} -
-
- - - {{else data.mode == 2}} -

SpaceMessenger V4.0.1

-
-
- Messenger Functions: -
-
- {{:helper.link(data.message_silent==1 ? 'Ringer: Off' : 'Ringer: On', data.message_silent==1 ? 'volume-off' : 'volume-on', {'choice' : "Toggle Ringer"}, null, 'fixedLeftWide')}} - {{:helper.link(data.toff==1 ? 'Messenger: Off' : 'Messenger: On',data.toff==1 ? 'close':'check', {'choice' : "Toggle Messenger"}, null, 'fixedLeftWide')}} - {{:helper.link('Set Ringtone', 'comment', {'choice' : "Ringtone"}, null, 'fixedLeftWide')}} - {{:helper.link('Delete all Conversations', 'trash', {'choice' : "Clear", 'option' : "All"}, null, 'fixedLeftWider')}} -
-
- {{if data.toff == 0}} -

- {{if data.cartridge}} - {{if data.cartridge.charges}} -
- {{:data.cartridge.charges}} - {{if data.cartridge.access.access_detonate_pda}} detonation charges left. {{/if}} - {{if data.cartridge.access.access_clown || data.cartridge.access.access_mime}} viral files left. {{/if}} - -

-
- {{/if}} - {{/if}} - - {{if data.pda_count == 0}} - No other PDAS located - {{else}} -

Current Conversations

- {{for data.convopdas}} -
- {{:helper.link(value.Name, 'circle-arrow-s', {'choice' : "Select Conversation", 'convo' : value.Reference } , null, value.fixedLeftWider)}} - {{if data.cartridge}} - {{if data.cartridge.access.access_detonate_pda && value.Detonate}} - {{:helper.link('*Detonate*', 'radiation', {'choice' : "Detonate", 'target' : value.Reference}, null, 'fixedLeft')}} - {{/if}} - {{if data.cartridge.access.access_clown}} - {{:helper.link('*Send Virus*', 'star', {'choice' : "Send Honk", 'target' : value.Reference}, null, 'fixedLeft')}} - {{/if}} - {{if data.cartridge.access.access_mime}} - {{:helper.link('*Send Virus*', 'circle-arrow-s', {'choice' : "Send Silence", 'target' : value.Reference}, null, 'fixedLeft')}} - {{/if}} - {{/if}} -
- {{/for}} -

Other PDAs

- {{for data.pdas}} -
- {{:helper.link(value.Name, 'circle-arrow-s', {'choice' : "Message", 'target' : value.Reference}, null, value.fixedLeftWider)}} - {{if data.cartridge}} - {{if data.cartridge.access.access_detonate_pda && value.Detonate}} {{:helper.link('*Detonate*', 'radiation', {'choice' : "Detonate", 'target' : value.Reference}, null, 'fixedLeft')}} {{/if}} - {{if data.cartridge.access.access_clown}} {{:helper.link('*Send Virus*', 'star', {'choice' : "Send Honk", 'target' : value.Reference}, null, 'fixedLeft')}} {{/if}} - {{if data.cartridge.access.access_mime}} {{:helper.link('*Send Virus*', 'circle-arrow-s', {'choice' : "Send Silence", 'target' : value.Reference}, null, 'fixedLeft')}} {{/if}} - {{/if}} -
- {{/for}} - {{/if}} - {{/if}} - - - {{else data.mode == 21}} -

SpaceMessenger V4.0.1

-
-
- Messenger Functions: -
-
- {{:helper.link('Delete Conversation', 'trash', {'choice' : "Clear", 'option' : "Convo"}, null, 'fixedLeftWide')}} -
-
-
-
-

Conversation with: {{:data.convo_name}} ({{:data.convo_job}})

-
-
-
- {{for data.messages}} - {{if data.active_conversation == value.target}} - {{if value.sent==0}} - Them: {{:value.message}}
- {{else}} - You: {{:value.message}}
- {{/if}} - {{/if}} - {{/for}} -
-
-
- {{:helper.link('Reply', 'comment', {'choice' : "Message", 'target': data.active_conversation}, null, 'fixedLeft')}} - - - {{else data.mode== 41}} - {{#def.crewManifest}} - - - {{else data.mode == 3}} -

Atmospheric Scan

- {{#def.atmosphericScan}} - - {{else data.mode == 40}} -

Remote Signaling System

-
-
- Frequency: -
-
- {{:data.records.signal_freq}} -
-   - {{:helper.link('-1', null, {'cartmenu' : "1", 'choice' : "Signal Frequency", 'sfreq' : "-10"}, null, null)}}  - {{:helper.link('-.2', null, {'cartmenu' : "1", 'choice' : "Signal Frequency", 'sfreq' : "-2"}, null, null)}}  - - {{:helper.link('+.2', null, {'cartmenu' : "1", 'choice' : "Signal Frequency", 'sfreq' : "2"}, null, null)}}  - {{:helper.link('+1', null, {'cartmenu' : "1", 'choice' : "Signal Frequency", 'sfreq' : "10"}, null, null)}} -
-
-
-
-
-
- Code: -
-
- - {{:data.records.signal_code}}
-
- {{:helper.link('-5', null, {'cartmenu' : "1", 'choice' : "Signal Code", 'scode' : "-5"}, null, null)}} - {{:helper.link('-1', null, {'cartmenu' : "1", 'choice' : "Signal Code", 'scode' : "-1"}, null, null)}} - {{:helper.link('+1', null, {'cartmenu' : "1", 'choice' : "Signal Code", 'scode' : "1"}, null, null)}} - {{:helper.link('+5', null, {'cartmenu' : "1", 'choice' : "Signal Code", 'scode' : "5"}, null, null)}} -
-
-
- {{:helper.link('Send Signal', 'radiation', {'cartmenu' : "1", 'choice' : "Send Signal"}, null, null)}} -
- - - {{else data.mode == 42}} -

Station Status Displays Interlink

-
-
- Code: -
-
- {{:helper.link('Clear', 'trash', {'cartmenu' : "1", 'choice' : "Status", 'statdisp' : "blank"}, null, null)}} - - {{:helper.link('Tram ETA', 'gear', {'cartmenu' : "1", 'choice' : "Status",'statdisp' : "shuttle"}, null, null)}} - {{:helper.link('Message', 'gear', {'cartmenu' : "1", 'choice' : "Status",'statdisp' : "message"}, null, null)}} -
-
-
-
-
- Message line 1 -
-
- {{:helper.link(data.records.message1 + ' (set)', 'pencil', {'cartmenu' : "1", 'choice' : "Status",'statdisp' : "setmsg1"}, null, null)}} -
-
-
-
- Message line 2 -
-
- {{:helper.link(data.records.message2 + ' (set)', 'pencil', {'cartmenu' : "1", 'choice' : "Status",'statdisp' : "setmsg2"}, null, null)}} -
-
- -
-
-
- ALERT!: -
-
- {{:helper.link('None', 'alert', {'cartmenu' : "1", 'choice' : "Status",'statdisp' : "alert", 'alert' : "default"}, null, null)}} - {{:helper.link('Red Alert', 'alert', {'cartmenu' : "1", 'choice' : "Status",'statdisp' : "alert", 'alert' : "redalert"}, null, null)}} - {{:helper.link('Lockdown', 'caution', {'cartmenu' : "1", 'choice' : "Status",'statdisp' : "alert", 'alert' : "lockdown"}, null, null)}} - {{:helper.link('Biohazard', 'radiation', {'cartmenu' : "1", 'choice' : "Status",'statdisp' : "alert", 'alert' : "biohazard"}, null, null)}} -
-
- - {{else data.mode == 43}} -

Sensor Selection

-
- Available Sensors: -
- {{for data.records.power_sensors}} -
- {{:helper.link(value.name_tag, 'plus', {'cartmenu' : "1", 'choice' : "Power Select",'target' : value.name_tag})}}
-
- {{/for}} - - - {{else data.mode == 433}} -

Sensor Reading(Simplified View)

- {{if data.records.sensor_reading}} -
AreaCell %Load - {{for data.records.sensor_reading.apc_data}} -
{{:value.name}} - {{:value.cell_charge}}% - {{:value.total_load}} - {{empty}} -
No APCs found! - {{/for}} -
-
Available: {{:data.records.sensor_reading.total_avail}} -
Load: {{:data.records.sensor_reading.total_used_all}} - {{else}} - Unable to contact sensor controller! Please retry and contact tech support if problem persists. - {{/if}} - - {{else data.mode == 44}} -

Medical Record List

-
- Select A record -
-
- {{for data.records.medical_records}} -
- {{:helper.link(value.Name, 'gear', {'cartmenu' : "1", 'choice' : "Medical Records",'target' : value.ref}, null, null)}} -
- {{/for}} - - - {{else data.mode == 441}} -

Medical Record

-
-
-
- {{if data.records.general_exists == 1}} - Name: {{:data.records.general.name}}
- Entity Class: {{:data.records.general.brain_type}}
- Sex: {{:data.records.general.sex}}
- Species: {{:data.records.general.species}}
- Age: {{:data.records.general.age}}
- Rank: {{:data.records.general.rank}}
- Fingerprint: {{:data.records.general.fingerprint}}
- Physical Status: {{:data.records.general.p_stat}}
- Mental Status: {{:data.records.general.m_stat}}

- {{else}} - - General Record Lost!

-
- {{/if}} - {{if data.records.medical_exists == 1}} - Medical Data:
- Blood Type: {{:data.records.medical.b_type}}

- Minor Disabilities: {{:data.records.medical.mi_dis}}
- Details: {{:data.records.medical.mi_dis_d}}

- Major Disabilities: {{:data.records.medical.ma_dis}}
- Details: {{:data.records.medical.ma_dis_d}}

- Allergies: {{:data.records.medical.alg}}
- Details: {{:data.records.medical.alg_d}}

- Current Disease: {{:data.records.medical.cdi}}
- Details: {{:data.records.medical.alg_d}}

- Important Notes: {{:data.records.medical.notes}} - {{else}} - - Medical Record Lost! -
-
-
- {{/if}} -
-
-
- - - {{else data.mode == 45}} -

Security Record List

-
- Select A record -
-
- {{for data.records.security_records}} -
- {{:helper.link(value.Name, 'gear', {'cartmenu' : "1", 'choice' : "Security Records",'target' : value.ref}, null, null)}} -
- {{/for}} - - - {{else data.mode == 451}} -

Security Record

-
-
-
- {{if data.records.general_exists == 1}} - Name: {{:data.records.general.name}}
- Sex: {{:data.records.general.sex}}
- Species: {{:data.records.general.species}}
- Age: {{:data.records.general.age}}
- Rank: {{:data.records.general.rank}}
- Fingerprint: {{:data.records.general.fingerprint}}
- Physical Status: {{:data.records.general.p_stat}}
- Mental Status: {{:data.records.general.m_stat}}

- {{else}} - - General Record Lost!

-
- {{/if}} - {{if data.records.security_exists == 1}} - Security Data:
- Criminal Status: {{:data.records.security.criminal}}

- Minor Crimes: {{:data.records.security.mi_crim}}
- Details: {{:data.records.security.mi_crim_d}}

- Major Crimes: {{:data.records.security.ma_crim}}
- Details: {{:data.records.security.ma_crim_d}}

- Important Notes: {{:data.records.security.notes}} - {{else}} - - Security Record Lost!

-
- {{/if}} -
-
-
- - - {{else data.mode == 46}} -

Security Bot Control

- {{if data.records.beepsky.active == null || data.records.beepsky.active == 0}} - {{if data.records.beepsky.count == 0}} -

No bots found.

- {{else}} -
- Select A Bot. -
-
- {{for data.records.beepsky.bots}} -
- {{:helper.link(value.Name, 'gear', {'radiomenu' : "1", 'op' : "control",'bot' : value.ref}, null, null)}} (Location: {{:value.Location}}) -
- {{/for}} - {{/if}} -
- {{:helper.link('Scan for Bots','gear', {'radiomenu' : "1", 'op' : "scanbots"}, null, null)}} - {{else}} -

{{:data.records.beepsky.active}}

-

- {{if data.records.beepsky.botstatus.mode == -1}} -

Waiting for response...

- {{else}} -

Status:

-
-
-
- Location: -
-
- {{:data.records.beepsky.botstatus.loca}} -
-
-
-
- Mode: -
-
- - {{if data.records.beepsky.botstatus.mode ==0}} - Ready - {{else data.records.beepsky.botstatus.mode == 1}} - Apprehending target - {{else data.records.beepsky.botstatus.mode ==2 || data.records.beepsky.botstatus.mode == 3}} - Arresting target - {{else data.records.beepsky.botstatus.mode ==4}} - Starting patrol - {{else data.records.beepsky.botstatus.mode ==5}} - On Patrol - {{else data.records.beepsky.botstatus.mode ==6}} - Responding to summons - {{/if}} - -
-
-
- {{:helper.link('Stop Patrol', 'gear', {'radiomenu' : "1", 'op' : "stop"}, null, null)}} - {{:helper.link('Start Patrol', 'gear', {'radiomenu' : "1", 'op' : "go"}, null, null)}} - {{:helper.link('Summon Bot', 'gear', {'radiomenu' : "1", 'op' : "summon"}, null, null)}} -
- {{/if}} - {{:helper.link('Return to Bot list', 'gear', {'radiomenu' : "1", 'op' : "botlist"}, null, null)}} - {{/if}} - - - {{else data.mode == 47}} -

Supply Record Interlink

-
-
- Location: -
-
- - {{if data.records.supply.shuttle_moving}} - Moving to station ({{:data.records.supply.shuttle_eta}}) - {{else}} - Shuttle at {{:data.records.supply.shuttle_loc}} - {{/if}} - -
-
-
-
-
- Current Approved Orders
- {{if data.records.supply.approved_count == 0}} - No current approved orders

- {{else}} - {{for data.records.supply.approved}} - #{{:value.Number}} - {{:value.Name}} approved by {{:value.OrderedBy}}
{{if value.Comment != ""}} {{:value.Comment}}
{{/if}}
- {{/for}} - {{/if}} -

- Current Requested Orders
- {{if data.records.supply.requests_count == 0}} - No current requested orders

- {{else}} - {{for data.records.supply.requests}} - #{{:value.Number}} - {{:value.Name}} requested by {{:value.OrderedBy}}
{{if value.Comment != ""}} {{:value.Comment}}
{{/if}}
- {{/for}} - {{/if}} -
-
-
- - - {{else data.mode == 48}} -

Mule Control

- {{if data.records.mulebotcount == 0}} -

No bots found.

- {{else}} -

Mule List

- {{for data.records.mulebots}} -
-
Mulebot #{{:value.name}}
-
Location: {{:value.location}}
Home: {{:value.home}}
Target: {{:value.target}}
Load: {{:value.load}}
-
-
-
Status:
-
- {{if value.paused == 0}} - Nominal - {{else value.paused == 1}} - Paused - {{/if}} -
-
-
- {{:helper.link('Go home', null, {'cartmenu' : "1", 'choice' : "MULEbot", 'ref' : value.ref, 'command' : "Home"})}} - {{:helper.link('Set destination', null, {'cartmenu' : "1", 'choice' : "MULEbot", 'ref' : value.ref, 'command' : "SetD"})}} - {{:helper.link('Go', null, {'cartmenu' : "1", 'choice' : "MULEbot", 'ref' : value.ref, 'command' : "GoTD"})}} - {{:helper.link('Stop', null, {'cartmenu' : "1", 'choice' : "MULEbot", 'ref' : value.ref, 'command' : "Stop"})}} -
- {{/for}} - {{/if}} - - - {{else data.mode == 49}} -

Janatorial Supplies Locator

-
- Current Location: - {{if data.records.janitor.user_loc.x == 0}} - Unknown - {{else}} - {{:data.records.janitor.user_loc.x}} / {{:data.records.janitor.user_loc.y}} - {{/if}} -
-
- {{for data.records.janitor.mops}} - {{if value.x==0}} - Unable to locate Mop - {{else}} - Mop Location: - ({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Status: {{:value.status}}
- {{/if}} - {{/for}} -
-
- {{for data.records.janitor.buckets}} - {{if value.x==0}} - Unable to locate Water Buckets - {{else}} - Water Buckets Location: - ({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Water Level: {{:value.status}}
- {{/if}} - {{/for}} -
-
- {{for data.records.janitor.cleanbots}} - {{if value.x==0}} - Unable to locate Clean Bots - {{else}} - Clean Bots Location: - ({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Status: {{:value.status}}
- {{/if}} - {{/for}} -
-
- {{for data.records.janitor.carts}} - {{if value.x==0}} - Unable to locate Janitorial Cart - {{else}} - Janitorial cart Location: - ({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Status: {{:value.status}}
- {{/if}} - {{/for}} - - {{else data.mode == 6}} -

InstaNews ED 2.0.9

- -
-
- Functions: -
-
- {{:helper.link(data.news_silent==1 ? 'Ringer: Off' : 'Ringer: On', data.news_silent==1 ? 'volume-off' : 'volume-on', {'choice' : "Toggle News"}, null, 'fixedLeftWide')}} - {{:helper.link('Set news tone', 'comment', {'choice' : "Newstone"}, null, 'fixedLeftWide')}} -
-
- - {{if data.reception != 1}} - No reception with newscaster network. - {{/if}} - -
-
- {{for data.feedChannels}} - {{if value.censored}} - {{:helper.link(value.name, 'circle-arrow-s', {'choice' : "Select Feed", 'feed' : value.feed, 'name' : value.name } , null, 'fixedLeftWiderRed')}} - {{else}} - {{:helper.link(value.name, 'circle-arrow-s', {'choice' : "Select Feed", 'feed' : value.feed, 'name' : value.name } , null, 'fixedLeftWider')}} - {{/if}} - {{empty}} - No active channels found... - {{/for}} -
-
- - {{else data.mode == 61}} -

{{:data.feed.channel}}

- Created by: {{:data.feed.author}}
- - {{if data.reception != 1}} - No reception with newscaster network. - {{/if}} - -
-
-
- {{if data.feed.censored}} -

Attention

- This channel has been deemed as threatening to the welfare of the station, and marked with a Nanotrasen D-Notice.
- No further feed story additions are allowed while the D-Notice is in effect.
- {{else}} - {{for data.feed.messages}} - -{{:value.body}}
- {{if value.has_image}} -
- {{if value.caption}} - {{:value.caption}}
- {{/if}} - {{/if}} - [{{:value.message_type}} by {{:value.author}} - {{:value.time_stamp}}]
-
- {{empty}} - No feed messages found in channel... - {{/for}} - {{/if}} -
-
-
- - {{/if}} {{else}}







No Owner information found, please swipe ID
-{{/if}} - +{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_atmos_scan.tmpl b/nano/templates/pda_atmos_scan.tmpl new file mode 100644 index 00000000000..57f0a356a16 --- /dev/null +++ b/nano/templates/pda_atmos_scan.tmpl @@ -0,0 +1,60 @@ + +
+
+ {{if data.aircontents.reading == 1}} +
+ Pressure: +
+
+ {{:helper.string('{1} kPa', data.aircontents.pressure < 80 || data.aircontents.pressure > 120 ? 'bad' : data.aircontents.pressure < 95 || data.aircontents.pressure > 110 ? 'average' : 'good', helper.smoothRound(data.aircontents.pressure, 1))}} +
+
+ Temperature: +
+
+ {{:helper.string('{1} °C', data.aircontents.temp < 5 || data.aircontents.temp > 35 ? 'bad' : data.aircontents.temp < 15 || data.aircontents.temp > 25 ? 'average' : 'good' , helper.smoothRound(data.aircontents.temp, 1))}} +
+
+
+ Oxygen: +
+
+ {{:helper.string('{1}%', data.aircontents.oxygen < 17 ? 'bad' : data.aircontents.oxygen < 19 ? 'average' : 'good', helper.smoothRound(data.aircontents.oxygen, 1))}} +
+
+ Nitrogen: +
+
+ {{:helper.string('{1}%', data.aircontents.nitrogen > 82 ? 'bad' : data.aircontents.nitrogen > 80 ? 'average' : 'good', helper.smoothRound(data.aircontents.nitrogen, 1))}} +
+
+ Carbon Dioxide: +
+
+ {{:helper.string('{1}%', data.aircontents.carbon_dioxide > 5 ? 'bad' : 'good', helper.smoothRound(data.aircontents.carbon_dioxide, 1))}} +
+
+ Plasma: +
+
+ {{:helper.string('{1}%', data.aircontents.plasma > 0 ? 'bad' : 'good', helper.smoothRound(data.aircontents.plasma, 1))}} + +
+ {{if data.aircontents.other > 0}} +
+ Unknown: +
+
+ {{:helper.smoothRound(data.aircontents.other, 1)}}% +
+ {{/if}} + {{else}} +
+ Unable to get air reading +
+ {{/if}} +
+
\ No newline at end of file diff --git a/nano/templates/pda_janitor.tmpl b/nano/templates/pda_janitor.tmpl new file mode 100644 index 00000000000..864692d8a04 --- /dev/null +++ b/nano/templates/pda_janitor.tmpl @@ -0,0 +1,66 @@ +
+
+ Current Location: + {{if data.janitor.user_loc.x == 0}} + Unknown + {{else}} + {{:data.janitor.user_loc.x}} / {{:data.janitor.user_loc.y}} + {{/if}} +
+
+ {{if data.janitor.mops}} + Mop Locations: +
    + {{for data.janitor.mops}} +
  • + ({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Status: {{:value.status}} +
  • + {{/for}} +
+ {{else}} + Unable to locate Mops + {{/if}} +
+
+ {{if data.janitor.buckets}} + Mop Bucket Locations: +
    + {{for data.janitor.buckets}} +
  • + ({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Capacity: {{:value.volume}}/{{:value.max_volume}} +
  • + {{/for}} +
+ {{else}} + Unable to locate Mop Buckets + {{/if}} +
+
+ {{if data.janitor.cleanbots}} + Cleanbot Locations: +
    + {{for data.janitor.cleanbots}} +
  • + ({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Status: {{:value.status}} +
  • + {{/for}} +
+ {{else}} + Unable to locate Cleanbots + {{/if}} +
+
+ {{if data.janitor.carts}} + Janitorial Cart Locations: +
    + {{for data.janitor.carts}} +
  • + ({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Water Level: {{:value.volume}}/{{:value.max_volume}} +
  • + {{/for}} +
+ {{else}} + Unable to locate Janitorial Carts + {{/if}} +
+
diff --git a/nano/templates/pda_main_menu.tmpl b/nano/templates/pda_main_menu.tmpl new file mode 100644 index 00000000000..692cdb7039d --- /dev/null +++ b/nano/templates/pda_main_menu.tmpl @@ -0,0 +1,76 @@ + + + + +
+
+ Owner: +
+
+ {{:data.owner}}, {{:data.ownjob}} +
+
+
+
+ ID: +
+
+ {{:helper.link('Update PDA Info', 'refresh', {'choice' : "UpdateInfo"}, data.idInserted ? null : 'disabled', 'pdalink fixedLeftWide')}} +
+
+ +
+

Functions

+
+{{for data.categories : cat : i}} + +{{/for}} + +{{if data.pai}} +
+
+ PAI Utilities: +
+
+ {{:helper.link('Configuration', 'gear', {'choice' : "pai", 'option' : "1"}, null, 'pdalink fixedLeft')}} + {{:helper.link('Eject pAI', 'eject', {'choice' : "pai", 'option' : "2"}, null, 'pdalink fixedLeft')}} +
+
+{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_manifest.tmpl b/nano/templates/pda_manifest.tmpl new file mode 100644 index 00000000000..ef9e91a088f --- /dev/null +++ b/nano/templates/pda_manifest.tmpl @@ -0,0 +1,96 @@ + +
+
+ {{if data.manifest.heads}} + + {{for data.manifest["heads"]}} + {{if value.rank == "Captain"}} + + {{else}} + + {{/if}} + {{/for}} + {{/if}} + {{if data.manifest.sec}} + + {{for data.manifest["sec"]}} + {{if value.rank == "Head of Security"}} + + {{else}} + + {{/if}} + {{/for}} + {{/if}} + {{if data.manifest.eng}} + + {{for data.manifest["eng"]}} + {{if value.rank == "Chief Engineer"}} + + {{else}} + + {{/if}} + {{/for}} + {{/if}} + {{if data.manifest.med}} + + {{for data.manifest["med"]}} + {{if value.rank == "Chief Medical Officer"}} + + {{else}} + + {{/if}} + {{/for}} + {{/if}} + {{if data.manifest.sci}} + + {{for data.manifest["sci"]}} + {{if value.rank == "Research Director"}} + + {{else}} + + {{/if}} + {{/for}} + {{/if}} + {{if data.manifest.ser}} + + {{for data.manifest["ser"]}} + {{if value.rank == "Head of Personnel"}} + + {{else}} + + {{/if}} + {{/for}} + {{/if}} + {{if data.manifest.sup}} + + {{for data.manifest["sup"]}} + {{if value.rank == "Head of Personnel"}} + + {{else value.rank == "Quartermaster"}} + + {{else}} + + {{/if}} + {{/for}} + {{/if}} + {{if data.manifest.civ}} + + {{for data.manifest["civ"]}} + {{if value.rank == "Head of Personnel"}} + + {{else}} + + {{/if}} + {{/for}} + {{/if}} + {{if data.manifest.misc}} + + {{for data.manifest["misc"]}} + + {{/for}} + {{/if}} +
Command
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Security
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Engineering
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Medical
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Science
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Service
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Supply
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Civilian
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Misc
{{:value.name}}{{:value.rank}}{{:value.active}}
+
\ No newline at end of file diff --git a/nano/templates/pda_medical.tmpl b/nano/templates/pda_medical.tmpl new file mode 100644 index 00000000000..777fb91f4b8 --- /dev/null +++ b/nano/templates/pda_medical.tmpl @@ -0,0 +1,54 @@ +{{if !data.records}} +
+
Select a record:
+
+ {{for data.recordsList}} +
+ {{:helper.link(value.Name, 'user', {'choice' : "Records", 'target' : value.ref}, null, 'pdalink fixedLeftWidest')}} +
+ {{empty}} +
+ No records found. +
+ {{/for}} +{{else}} +
+
+
+ {{if data.records.general}} + Name: {{:data.records.general.name}}
+ Sex: {{:data.records.general.sex}}
+ Species: {{:data.records.general.species}}
+ Age: {{:data.records.general.age}}
+ Rank: {{:data.records.general.rank}}
+ Fingerprint: {{:data.records.general.fingerprint}}
+ Physical Status: {{:data.records.general.p_stat}}
+ Mental Status: {{:data.records.general.m_stat}}

+ {{else}} + + General Record Lost!

+
+ {{/if}} + {{if data.records.medical}} +
+
Medical Data:
+
+ Blood Type: {{:data.records.medical.b_type}}

+ Minor Disabilities: {{:data.records.medical.mi_dis}}
+ Details: {{:data.records.medical.mi_dis_d}}

+ Major Disabilities: {{:data.records.medical.ma_dis}}
+ Details: {{:data.records.medical.ma_dis_d}}

+ Allergies: {{:data.records.medical.alg}}
+ Details: {{:data.records.medical.alg_d}}

+ Current Disease: {{:data.records.medical.cdi}}
+ Details: {{:data.records.medical.alg_d}}

+ Important Notes: {{:data.records.medical.notes}} + {{else}} + + Medical Record Lost! + + {{/if}} +
+
+
+{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_messenger.tmpl b/nano/templates/pda_messenger.tmpl new file mode 100644 index 00000000000..4871934e4e9 --- /dev/null +++ b/nano/templates/pda_messenger.tmpl @@ -0,0 +1,90 @@ + +{{if data.active_conversation}} +
+
+ Messenger Functions: +
+
+ {{:helper.link('Delete Conversation', 'trash', {'choice' : "Clear", 'option' : "Convo"}, null, 'pdalink fixedLeftWide')}} + {{:helper.link(data.auto_scroll ? 'Autoscroll: On' : 'Autoscroll: Off', 'level-down', {'choice' : "Autoscroll"}, null, 'pdalink fixedLeftWide')}} +
+
+
+
+

Conversation with: {{:data.convo_name}} ({{:data.convo_job}})

+
+
+
+ {{for data.messages}} + {{if data.active_conversation == value.target}} + {{if value.sent==0}} + Them: {{:value.message}}
+ {{else}} + You: {{:value.message}}
+ {{/if}} + {{/if}} + {{/for}} +
+
+
+ {{:helper.link('Reply', 'comment', {'choice' : "Message", 'target': data.active_conversation}, null, 'pdalink fixedLeftWidest')}} + +{{else}} +
+
+ Messenger Functions: +
+
+ {{:helper.link(data.silent==1 ? 'Ringer: Off' : 'Ringer: On', data.silent==1 ? 'volume-off' : 'volume-up', {'choice' : "Toggle Ringer"}, null, 'pdalink fixedLeftWide')}} + {{:helper.link(data.toff==1 ? 'Messenger: Off' : 'Messenger: On',data.toff==1 ? 'close':'check', {'choice' : "Toggle Messenger"}, null, 'pdalink fixedLeftWide')}} + {{:helper.link('Set Ringtone', 'bell-o', {'choice' : "Ringtone"}, null, 'pdalink fixedLeftWide')}} + {{:helper.link('Delete all Conversations', 'trash', {'choice' : "Clear", 'option' : "All"}, null, 'pdalink fixedLeftWider')}} +
+
+ {{if data.toff == 0}} +
+ {{if data.charges}} +
+ {{:data.charges}} charges left. +

+
+ {{/if}} + + {{if !data.convopdas.length && !data.pdas.length}} + No other PDAS located + {{else}} +

Current Conversations

+ {{for data.convopdas}} +
+ {{:helper.link(value.Name, 'arrow-circle-down', {'choice' : "Select Conversation", 'convo' : value.Reference } , null, 'pdalink')}} + {{if data.charges}} + {{for data.plugins : plugin : i}} + {{:helper.link(plugin.name, plugin.icon, {'choice' : "Messenger Plugin", 'plugin' : plugin.ref, 'target' : value.Reference}, null, 'pdalink fixedLeft')}} + {{/for}} + {{/if}} +
+ {{/for}} +

Other PDAs

+ {{for data.pdas}} +
+ {{:helper.link(value.Name, 'arrow-circle-down', {'choice' : "Message", 'target' : value.Reference}, null, 'pdalink')}} + {{if data.charges}} + {{for data.plugins : plugin : i}} + {{:helper.link(plugin.name, plugin.icon, {'choice' : "Messenger Plugin", 'plugin' : plugin.ref, 'target' : value.Reference}, null, 'pdalink fixedLeft')}} + {{/for}} + {{/if}} +
+ {{/for}} + {{/if}} + {{/if}} +{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_mob_hunt.tmpl b/nano/templates/pda_mob_hunt.tmpl new file mode 100644 index 00000000000..dde4ab82a5c --- /dev/null +++ b/nano/templates/pda_mob_hunt.tmpl @@ -0,0 +1,91 @@ +
+
+ + + + {{if data.connected}} + + + {{else}} + + + {{/if}} + +
+ Connection Status: + + Connected + + {{:helper.link('Disconnect', 'sign-out', {'choice': 'Disconnect'})}} + + No Connection + + {{:helper.link('Connect', 'sign-in', {'choice': 'Reconnect'})}} +
+
+
+
+
My Collection:
+{{if data.no_collection}} +
+
+ Your collection is empty! Go capture some Nano-Mobs! +
+
+
+ Wild mobs captured: {{:data.wild_captures}} +{{else}} +
+
+
+ {{if data.entry}} + {{if data.entry.nickname}} + Name: {{:data.entry.nickname}}
+ {{/if}} + Species: {{:data.entry.real_name}}
+ Level: {{:data.entry.level}}
+ Primary Type: {{:data.entry.type1}}
+ {{if data.entry.type2}} + Secondary Type: {{:data.entry.type2}}
+ {{/if}} + {{if data.entry.sprite}} + + {{else}} + Mob Image Missing! + {{/if}} + {{else}} + + Mob Data Missing!

+
+ {{/if}} +
+
+
+
+ Wild mobs captured: {{:data.wild_captures}} +
+ + + + + + + + +
+ {{:helper.link('Previous Mob', 'arrow-left', {'choice': 'Prev'})}} + + {{:helper.link('Transfer Mob', 'exchange', {'choice': 'Transfer'})}} + + {{:helper.link('Rename Mob', 'pencil', {'choice': 'Rename'})}} + + {{:helper.link('Release Mob', 'tree', {'choice': 'Release'})}} + + {{:helper.link('Next Mob', 'arrow-right', {'choice': 'Next'})}} +
+ {{if data.entry.is_hacked}} +
+ {{:helper.link('Set Trap', 'bolt', {'choice': 'Set_Trap'})}} + {{/if}} +
+{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_mule.tmpl b/nano/templates/pda_mule.tmpl new file mode 100644 index 00000000000..369d0830aa5 --- /dev/null +++ b/nano/templates/pda_mule.tmpl @@ -0,0 +1,118 @@ +{{if !data.mulebot.active}} + {{if data.mulebot.count == 0}} +

No bots found.

+ {{else}} +
+ Select a MULE: +
+
+ {{for data.mulebot.bots}} +
+ {{:helper.link(value.Name, 'gear', {'radiomenu' : "1", 'op' : "control",'bot' : value.ref}, null, 'pdalink fixedLeftWidest')}} (Location: {{:value.Location}}) +
+ {{/for}} + {{/if}} +
+ {{:helper.link('Scan for Bots','rss', {'radiomenu' : "1", 'op' : "scanbots"}, null, 'pdalink fixedLeftWidest')}} +{{else}} +

{{:data.mulebot.active}}

+ {{if data.mulebot.botstatus.mode == -1}} +

Waiting for response...

+ {{else}} +

Status:

+
+
+ Location: +
+
+ {{:data.mulebot.botstatus.loca}} +
+
+
+
+ Mode: +
+
+ + {{if data.mulebot.botstatus.mode == 0}} + Ready + {{else data.mulebot.botstatus.mode == 1}} + Loading/Unloading + {{else data.mulebot.botstatus.mode == 2}} + Navigating to Delivery Location + {{else data.mulebot.botstatus.mode == 3}} + Navigating to Home + {{else data.mulebot.botstatus.mode == 4}} + Waiting for Clear Path + {{else data.mulebot.botstatus.mode == 5 || data.mulebot.botstatus.mode == 6}} + Calculating navigation Path + {{else data.mulebot.botstatus.mode == 7}} + Unable to locate destination + {{/if}} + +
+
+
+
+ Current Load: +
+
+ + {{:helper.link(data.mulebot.botstatus.load == null ? 'None (Unload)' : data.mulebot.botstatus.load + ' (Unload)', 'archive', {'radiomenu' : "1", 'op' : "unload"},data.mulebot.botstatus.load == null ? 'disabled' : null, 'pdalink fixedLeftWidest')}} + +
+
+
+
+ Power: +
+
+ + {{:data.mulebot.botstatus.powr}}% + +
+
+
+
+ Destination: +
+
+ {{:helper.link(data.mulebot.botstatus.dest == null || data.mulebot.botstatus.dest == "" ? 'None (Set)' : data.mulebot.botstatus.dest + ' (Set)', 'gear', {'radiomenu' : "1", 'op' : "setdest"}, null, 'pdalink fixedLeftWidest')}} +
+
+
+
+ Home: +
+
+ {{if data.mulebot.botstatus.home == null}} None {{else}} {{:data.mulebot.botstatus.home}} {{/if}} +
+
+
+
+ Auto Return: +
+
+ {{:helper.link(data.mulebot.botstatus.retn == 1 ? 'ON' : 'OFF', 'gear', {'radiomenu' : "1", 'op' : (data.mulebot.botstatus.retn==1 ? "retoff" : "reton")}, null, 'pdalink fixedLeftWidest')}} +
+
+
+
+ Auto Pickup: +
+
+ {{:helper.link(data.mulebot.botstatus.pick==1? 'ON' : 'OFF', 'gear', {'radiomenu' : "1", 'op' : (data.mulebot.botstatus.pick==1 ? "pickoff" : "pickon")}, null, 'pdalink fixedLeftWidest')}} +
+
+
+
+ Functions: +
+
+ {{:helper.link('Stop', 'gear', {'radiomenu' : "1", 'op' : "stop"}, null, 'pdalink fixedLeft')}} + {{:helper.link('Proceed', 'gear', {'radiomenu' : "1", 'op' : "start"}, null, 'pdalink fixedLeft')}} + {{:helper.link('Return Home', 'gear', {'radiomenu' : "1", 'op' : "home"}, null, 'pdalink fixedLeft')}} +
+
+ {{/if}} +{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_notekeeper.tmpl b/nano/templates/pda_notekeeper.tmpl new file mode 100644 index 00000000000..53db3be6438 --- /dev/null +++ b/nano/templates/pda_notekeeper.tmpl @@ -0,0 +1,21 @@ + +
+
+ Notes: +
+
+
+
+
+ {{:data.note}} +
+
+
+
+
+ {{:helper.link('Edit Notes', 'pencil-square-o', {'choice': "Edit"}, null, 'pdalink')}} +
+
\ No newline at end of file diff --git a/nano/templates/pda_power.tmpl b/nano/templates/pda_power.tmpl new file mode 100644 index 00000000000..7ba04188b71 --- /dev/null +++ b/nano/templates/pda_power.tmpl @@ -0,0 +1,49 @@ +{{if !data.records.powerconnected}} +
+
Select a power monitor:
+
+ {{for data.records.powermonitors}} +
+ {{:helper.link(value.Name, 'exclamation-circle', {'choice' : "Power Select", 'target' : value.ref}, null, 'pdalink fixedLeftWidest')}} +
+ {{/for}} +{{else}} +
+
+ Total Power: +
+
+ {{:data.records.poweravail}} W +
+
+
+
+ Total Load: +
+
+ {{:data.records.powerload}} W +
+
+
+
+ Total Demand: +
+
+ {{:data.records.powerdemand}} W +
+
+
+ + + {{for data.records.apcs}} + + {{:helper.string('', value.Equipment == "On" || value.Equipment == "AOn" ? '#4f7529' : '#8f1414', value.Equipment)}} + {{:helper.string('', value.Lights == "On" || value.Lights == "AOn" ? '#4f7529' : '#8f1414', value.Lights)}} + {{:helper.string('', value.Environment == "On" || value.Environment == "AOn" ? '#4f7529' : '#8f1414', value.Environment)}} + {{:helper.string('', value.CellStatus == "F" ? '#4f7529' : value.CellStatus == "C" ? '#cd6500' : '#8f1414', value.CellStatus == "M" ? 'No Cell' : value.CellPct + '%', value.CellStatus == "M" ? '' : ' (' + value.CellStatus + ')')}} + + + {{/for}} +
AreaEquip.LightingEnviron.CellLoad
{{:value.Name}}{1}{1}{1}{1}{2}{{:value.Load}}W
+
+{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_secbot.tmpl b/nano/templates/pda_secbot.tmpl new file mode 100644 index 00000000000..6ff8c98e147 --- /dev/null +++ b/nano/templates/pda_secbot.tmpl @@ -0,0 +1,59 @@ +{{if !data.beepsky.active}} + {{if data.beepsky.count == 0}} +

No bots found.

+ {{else}} +
+ Select a bot: +
+
+ {{for data.beepsky.bots}} +
+ {{:helper.link(value.Name, 'gear', {'radiomenu' : "1", 'op' : "control",'bot' : value.ref}, null, 'pdalink fixedLeftWidest')}} (Location: {{:value.Location}}) +
+ {{/for}} + {{/if}} +
+ {{:helper.link('Scan for Bots','rss', {'radiomenu' : "1", 'op' : "scanbots"}, null, 'pdalink fixedLeftWidest')}} +{{else}} +

{{:data.beepsky.active}}

+ {{if data.beepsky.botstatus.mode == -1}} +

Waiting for response...

+ {{else}} +

Status:

+
+
+ Location: +
+
+ {{:data.beepsky.botstatus.loca}} +
+
+
+
+ Mode: +
+
+ + {{if data.beepsky.botstatus.mode ==0}} + Ready + {{else data.beepsky.botstatus.mode == 1}} + Apprehending target + {{else data.beepsky.botstatus.mode ==2 || data.beepsky.botstatus.mode == 3}} + Arresting target + {{else data.beepsky.botstatus.mode ==4}} + Starting patrol + {{else data.beepsky.botstatus.mode ==5}} + On Patrol + {{else data.beepsky.botstatus.mode ==6}} + Responding to summons + {{/if}} + +
+
+
+ {{:helper.link('Stop Patrol', 'gear', {'radiomenu' : "1", 'op' : "stop"}, null, 'pdalink fixedLeftWide')}} + {{:helper.link('Start Patrol', 'gear', {'radiomenu' : "1", 'op' : "go"}, null, 'pdalink fixedLeftWide')}} + {{:helper.link('Summon Bot', 'gear', {'radiomenu' : "1", 'op' : "summon"}, null, 'pdalink fixedLeftWide')}} +
+ {{/if}} +{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_security.tmpl b/nano/templates/pda_security.tmpl new file mode 100644 index 00000000000..53d40185e05 --- /dev/null +++ b/nano/templates/pda_security.tmpl @@ -0,0 +1,50 @@ +{{if !data.records}} +
+
Select a record:
+
+ {{for data.recordsList}} +
+ {{:helper.link(value.Name, 'user', {'choice' : "Records", 'target' : value.ref}, null, 'pdalink fixedLeftWidest')}} +
+ {{empty}} +
+ No records found. +
+ {{/for}} +{{else}} +
+
+
+ {{if data.records.general}} + Name: {{:data.records.general.name}}
+ Sex: {{:data.records.general.sex}}
+ Species: {{:data.records.general.species}}
+ Age: {{:data.records.general.age}}
+ Rank: {{:data.records.general.rank}}
+ Fingerprint: {{:data.records.general.fingerprint}}
+ Physical Status: {{:data.records.general.p_stat}}
+ Mental Status: {{:data.records.general.m_stat}}

+ {{else}} + + General Record Lost!

+
+ {{/if}} + {{if data.records.security}} +
+
Security Data:
+
+ Criminal Status: {{:data.records.security.criminal}}

+ Minor Crimes: {{:data.records.security.mi_crim}}
+ Details: {{:data.records.security.mi_crim_d}}

+ Major Crimes: {{:data.records.security.ma_crim}}
+ Details: {{:data.records.security.ma_crim_d}}

+ Important Notes: {{:data.records.security.notes}} + {{else}} + + Security Record Lost!

+
+ {{/if}} +
+
+
+{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_signaller.tmpl b/nano/templates/pda_signaller.tmpl new file mode 100644 index 00000000000..2b5f148b025 --- /dev/null +++ b/nano/templates/pda_signaller.tmpl @@ -0,0 +1,38 @@ + +
+
+ Frequency: +
+
+ {{:data.signal_freq}} +
+   + {{:helper.link('-1', null, {'choice' : "Signal Frequency", 'sfreq' : "-10"}, null, null)}}  + {{:helper.link('-.2', null, {'choice' : "Signal Frequency", 'sfreq' : "-2"}, null, null)}}  + + {{:helper.link('+.2', null, {'choice' : "Signal Frequency", 'sfreq' : "2"}, null, null)}}  + {{:helper.link('+1', null, {'choice' : "Signal Frequency", 'sfreq' : "10"}, null, null)}} +
+
+
+
+
+
+ Code: +
+
+ + {{:data.signal_code}}
+
+ {{:helper.link('-5', null, {'choice' : "Signal Code", 'scode' : "-5"}, null, null)}} + {{:helper.link('-1', null, {'choice' : "Signal Code", 'scode' : "-1"}, null, null)}} + {{:helper.link('+1', null, {'choice' : "Signal Code", 'scode' : "1"}, null, null)}} + {{:helper.link('+5', null, {'choice' : "Signal Code", 'scode' : "5"}, null, null)}} +
+
+
+ {{:helper.link('Send Signal', 'exclamation-circle', {'choice' : "Send Signal"}, null, null)}} +
\ No newline at end of file diff --git a/nano/templates/pda_status_display.tmpl b/nano/templates/pda_status_display.tmpl new file mode 100644 index 00000000000..8b153ad0ffd --- /dev/null +++ b/nano/templates/pda_status_display.tmpl @@ -0,0 +1,44 @@ + +
+
+ Code: +
+
+ {{:helper.link('Clear', 'trash', {'choice' : "Status", 'statdisp' : "blank"}, null, 'pdalink fixedLeftWide')}} + {{:helper.link('Shuttle ETA', 'gear', {'cartmenu' : "1", 'choice' : "Status", 'statdisp' : "shuttle"}, null, 'pdalink fixedLeftWide')}} + {{:helper.link('Message', 'gear', {'choice' : "Status", 'statdisp' : "message"}, null, 'pdalink fixedLeftWide')}} +
+
+
+
+
+ Message line 1 +
+
+ {{:helper.link(data.records.message1 + ' (set)', 'pencil', {'choice' : "Status", 'statdisp' : "setmsg1"}, null, 'pdalink fixedLeftWide')}} +
+
+
+
+ Message line 2 +
+
+ {{:helper.link(data.records.message2 + ' (set)', 'pencil', {'choice' : "Status", 'statdisp' : "setmsg2"}, null, 'pdalink fixedLeftWide')}} +
+
+ +
+
+
+ ALERT!: +
+
+ {{:helper.link('None', 'bell', {'choice' : "Status", 'statdisp' : "alert", 'alert' : "default"}, null, 'pdalink fixedLeftWide')}} + {{:helper.link('Red Alert', 'bell', {'choice' : "Status", 'statdisp' : "alert", 'alert' : "redalert"}, null, 'pdalink fixedLeftWide')}} + {{:helper.link('Lockdown', 'exclamation-circle', {'choice' : "Status", 'statdisp' : "alert", 'alert' : "lockdown"}, null, 'pdalink fixedLeftWide')}} + {{:helper.link('Biohazard', 'exclamation-circle', {'choice' : "Status", 'statdisp' : "alert", 'alert' : "biohazard"}, null, 'pdalink fixedLeftWide')}} +
+
\ No newline at end of file diff --git a/nano/templates/pda_supply.tmpl b/nano/templates/pda_supply.tmpl new file mode 100644 index 00000000000..810fc193769 --- /dev/null +++ b/nano/templates/pda_supply.tmpl @@ -0,0 +1,39 @@ +
+
+ Location: +
+
+ + {{if data.supply.shuttle_moving}} + Moving to {{:data.supply.shuttle_loc}} + {{else}} + Shuttle at {{:data.supply.shuttle_loc}} + {{/if}} +
+ {{:data.supply.shuttle_time}} +
+
+
+
+
+
+ Current Approved Orders
+ {{if data.supply.approved_count == 0}} + No current approved orders

+ {{else}} + {{for data.supply.approved}} + #{{:value.Number}} - {{:value.Name}} approved by {{:value.OrderedBy}}
{{if value.Comment != ""}} {{:value.Comment}}
{{/if}}
+ {{/for}} + {{/if}} +

+ Current Requested Orders
+ {{if data.supply.requests_count == 0}} + No current requested orders

+ {{else}} + {{for data.supply.requests}} + #{{:value.Number}} - {{:value.Name}} requested by {{:value.OrderedBy}}
{{if value.Comment != ""}} {{:value.Comment}}
{{/if}}
+ {{/for}} + {{/if}} +
+
+
\ No newline at end of file diff --git a/tgui/packages/tgui/interfaces/Pda.js b/tgui/packages/tgui/interfaces/Pda.js new file mode 100644 index 00000000000..18018a1c736 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Pda.js @@ -0,0 +1,17 @@ +import { round } from 'common/math'; +import { Fragment } from 'inferno'; +import { useBackend } from "../backend"; +import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section } from "../components"; +import { Window } from "../layouts"; + +export const Pda = (props, context) => { + const { act, data } = useBackend(context); + + return ( + + + PDA! + + + ); +}; \ No newline at end of file diff --git a/tgui/packages/tgui/interfaces/pda/pda_main_menu.js b/tgui/packages/tgui/interfaces/pda/pda_main_menu.js new file mode 100644 index 00000000000..f580c273b69 --- /dev/null +++ b/tgui/packages/tgui/interfaces/pda/pda_main_menu.js @@ -0,0 +1,14 @@ +import { round } from 'common/math'; +import { Fragment } from 'inferno'; +import { useBackend } from "../backend"; +import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section } from "../components"; + +export const pda_main_menu = (props, context) => { + const { act, data } = useBackend(context); + + return ( +
+ Main Menu +
+ ); +}; \ No newline at end of file diff --git a/tools/nano-tester/index.html b/tools/nano-tester/index.html index 70f5dfecd23..f3cf4ba8550 100644 --- a/tools/nano-tester/index.html +++ b/tools/nano-tester/index.html @@ -25,6 +25,7 @@ + diff --git a/vorestation.dme b/vorestation.dme index 16816e2506e..f87cd477563 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -65,6 +65,7 @@ #include "code\__defines\nifsoft.dm" #include "code\__defines\objects.dm" #include "code\__defines\overmap.dm" +#include "code\__defines\pda.dm" #include "code\__defines\planets.dm" #include "code\__defines\plants.dm" #include "code\__defines\preferences.dm" @@ -3067,11 +3068,17 @@ #include "code\modules\paperwork\stamps.dm" #include "code\modules\pda\app.dm" #include "code\modules\pda\cart.dm" +#include "code\modules\pda\cart_apps.dm" #include "code\modules\pda\cart_vr.dm" #include "code\modules\pda\chatroom.dm" +#include "code\modules\pda\core_apps.dm" +#include "code\modules\pda\messenger.dm" +#include "code\modules\pda\messenger_plugins.dm" #include "code\modules\pda\pda.dm" +#include "code\modules\pda\pda_tgui.dm" #include "code\modules\pda\pda_vr.dm" #include "code\modules\pda\radio.dm" +#include "code\modules\pda\utilities.dm" #include "code\modules\persistence\filth.dm" #include "code\modules\persistence\graffiti.dm" #include "code\modules\persistence\noticeboard.dm" From bec094251346794243e8eb37b0387bfcad47fe1c Mon Sep 17 00:00:00 2001 From: ShadowLarkens Date: Wed, 16 Sep 2020 01:52:45 -0700 Subject: [PATCH 3/8] TGUI PDAs, legacy code to-be-removed --- code/modules/events/money_spam.dm | 16 +- code/modules/pda/ai.dm | 95 +++ code/modules/pda/app.dm | 5 +- code/modules/pda/cart.dm | 520 +++------------- code/modules/pda/cart_apps.dm | 227 ++++--- code/modules/pda/cart_vr.dm | 13 +- code/modules/pda/core_apps.dm | 86 +-- code/modules/pda/messenger.dm | 42 +- code/modules/pda/pda.dm | 570 +----------------- code/modules/pda/pda_subtypes.dm | 282 +++++++++ code/modules/pda/pda_tgui.dm | 138 ++++- code/modules/pda/radio.dm | 241 +++++--- code/modules/pda/utilities.dm | 50 +- nano/js/nano_state_pda.js | 51 -- nano/templates/pda.tmpl | 156 ----- nano/templates/pda_atmos_scan.tmpl | 60 -- nano/templates/pda_janitor.tmpl | 66 -- nano/templates/pda_main_menu.tmpl | 76 --- nano/templates/pda_manifest.tmpl | 96 --- nano/templates/pda_medical.tmpl | 54 -- nano/templates/pda_messenger.tmpl | 90 --- nano/templates/pda_mob_hunt.tmpl | 91 --- nano/templates/pda_mule.tmpl | 118 ---- nano/templates/pda_notekeeper.tmpl | 21 - nano/templates/pda_power.tmpl | 49 -- nano/templates/pda_secbot.tmpl | 59 -- nano/templates/pda_security.tmpl | 50 -- nano/templates/pda_signaller.tmpl | 38 -- nano/templates/pda_status_display.tmpl | 44 -- nano/templates/pda_supply.tmpl | 39 -- tgui/packages/common/string.js | 3 +- tgui/packages/tgui/index.js | 1 + tgui/packages/tgui/interfaces/Pda.js | 143 ++++- .../tgui/interfaces/pda/pda_atmos_scan.js | 44 ++ .../tgui/interfaces/pda/pda_janitor.js | 89 +++ .../tgui/interfaces/pda/pda_main_menu.js | 63 +- .../tgui/interfaces/pda/pda_manifest.js | 15 + .../tgui/interfaces/pda/pda_medical.js | 113 ++++ .../tgui/interfaces/pda/pda_messenger.js | 261 ++++++++ .../tgui/interfaces/pda/pda_notekeeper.js | 26 + .../packages/tgui/interfaces/pda/pda_power.js | 8 + .../tgui/interfaces/pda/pda_security.js | 101 ++++ .../tgui/interfaces/pda/pda_status_display.js | 54 ++ .../tgui/interfaces/pda/pda_supply.js | 53 ++ tgui/packages/tgui/public/tgui.bundle.css | 2 +- tgui/packages/tgui/routes.js | 2 +- .../tgui/styles/themes/pda-retro.scss | 61 ++ tgui/packages/tgui/styles/themes/retro.scss | 1 + vorestation.dme | 2 + 49 files changed, 2023 insertions(+), 2462 deletions(-) create mode 100644 code/modules/pda/ai.dm create mode 100644 code/modules/pda/pda_subtypes.dm delete mode 100644 nano/js/nano_state_pda.js delete mode 100644 nano/templates/pda.tmpl delete mode 100644 nano/templates/pda_atmos_scan.tmpl delete mode 100644 nano/templates/pda_janitor.tmpl delete mode 100644 nano/templates/pda_main_menu.tmpl delete mode 100644 nano/templates/pda_manifest.tmpl delete mode 100644 nano/templates/pda_medical.tmpl delete mode 100644 nano/templates/pda_messenger.tmpl delete mode 100644 nano/templates/pda_mob_hunt.tmpl delete mode 100644 nano/templates/pda_mule.tmpl delete mode 100644 nano/templates/pda_notekeeper.tmpl delete mode 100644 nano/templates/pda_power.tmpl delete mode 100644 nano/templates/pda_secbot.tmpl delete mode 100644 nano/templates/pda_security.tmpl delete mode 100644 nano/templates/pda_signaller.tmpl delete mode 100644 nano/templates/pda_status_display.tmpl delete mode 100644 nano/templates/pda_supply.tmpl create mode 100644 tgui/packages/tgui/interfaces/pda/pda_atmos_scan.js create mode 100644 tgui/packages/tgui/interfaces/pda/pda_janitor.js create mode 100644 tgui/packages/tgui/interfaces/pda/pda_manifest.js create mode 100644 tgui/packages/tgui/interfaces/pda/pda_medical.js create mode 100644 tgui/packages/tgui/interfaces/pda/pda_messenger.js create mode 100644 tgui/packages/tgui/interfaces/pda/pda_notekeeper.js create mode 100644 tgui/packages/tgui/interfaces/pda/pda_power.js create mode 100644 tgui/packages/tgui/interfaces/pda/pda_security.js create mode 100644 tgui/packages/tgui/interfaces/pda/pda_status_display.js create mode 100644 tgui/packages/tgui/interfaces/pda/pda_supply.js create mode 100644 tgui/packages/tgui/styles/themes/pda-retro.scss diff --git a/code/modules/events/money_spam.dm b/code/modules/events/money_spam.dm index 0b877cef3d7..dd0119a11d4 100644 --- a/code/modules/events/money_spam.dm +++ b/code/modules/events/money_spam.dm @@ -112,17 +112,5 @@ //Commented out because we don't send messages like this anymore. Instead it will just popup in their chat window. //P.tnote += "← From [sender] (Unknown / spam?):
[message]
" - if (!P.message_silent) - playsound(P, 'sound/machines/twobeep.ogg', 50, 1) - for (var/mob/O in hearers(3, P.loc)) - if(!P.message_silent) O.show_message(text("[bicon(P)] *[P.ttone]*")) - //Search for holder of the PDA. - var/mob/living/L = null - if(P.loc && isliving(P.loc)) - L = P.loc - //Maybe they are a pAI! - else - L = get(P, /mob/living/silicon) - - if(L) - to_chat(L, "[bicon(P)] Message from [sender] (Unknown / spam?), \"[message]\" (Unable to Reply)") + var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger) + PM.notify("Message from [sender] (Unknown / spam?), \"[message]\" (Unable to Reply)", 0) diff --git a/code/modules/pda/ai.dm b/code/modules/pda/ai.dm new file mode 100644 index 00000000000..4a11b242ffe --- /dev/null +++ b/code/modules/pda/ai.dm @@ -0,0 +1,95 @@ + +// Special AI/pAI PDAs that cannot explode. +/obj/item/device/pda/ai + icon_state = "NONE" + ttone = "data" + newstone = "news" + detonate = 0 + + +/obj/item/device/pda/ai/proc/set_name_and_job(newname as text, newjob as text, newrank as null|text) + owner = newname + ownjob = newjob + if(newrank) + ownrank = newrank + else + ownrank = ownjob + name = newname + " (" + ownjob + ")" + +//AI verb and proc for sending PDA messages. +/obj/item/device/pda/ai/verb/cmd_send_pdamesg() + set category = "AI IM" + set name = "Send PDA Message" + set src in usr + + if(!can_use()) + return + var/datum/data/pda/app/messenger/M = find_program(/datum/data/pda/app/messenger) + if(!M) + to_chat(usr, "Cannot use messenger!") + var/list/plist = M.available_pdas() + if(plist) + var/c = input(usr, "Please select a PDA") as null|anything in sortList(plist) + if(!c) // if the user hasn't selected a PDA file we can't send a message + return + var/selected = plist[c] + M.create_message(usr, selected) + +/obj/item/device/pda/ai/verb/cmd_toggle_pda_receiver() + set category = "AI IM" + set name = "Toggle Sender/Receiver" + set src in usr + + if(!can_use()) + return + var/datum/data/pda/app/messenger/M = find_program(/datum/data/pda/app/messenger) + M.toff = !M.toff + to_chat(usr, "PDA sender/receiver toggled [(M.toff ? "Off" : "On")]!") + +/obj/item/device/pda/ai/verb/cmd_toggle_pda_silent() + set category = "AI IM" + set name = "Toggle Ringer" + set src in usr + + if(!can_use()) + return + var/datum/data/pda/app/messenger/M = find_program(/datum/data/pda/app/messenger) + M.notify_silent = !M.notify_silent + to_chat(usr, "PDA ringer toggled [(M.notify_silent ? "Off" : "On")]!") + +/obj/item/device/pda/ai/verb/cmd_show_message_log() + set category = "AI IM" + set name = "Show Message Log" + set src in usr + + if(!can_use()) + return + var/datum/data/pda/app/messenger/M = find_program(/datum/data/pda/app/messenger) + if(!M) + to_chat(usr, "Cannot use messenger!") + var/HTML = "AI PDA Message Log" + for(var/index in M.tnote) + if(index["sent"]) + HTML += addtext("→ To ", index["owner"],":
", index["message"], "
") + else + HTML += addtext("← From ", index["owner"],":
", index["message"], "
") + HTML +="" + usr << browse(HTML, "window=log;size=400x444;border=1;can_resize=1;can_close=1;can_minimize=0") + + +/obj/item/device/pda/ai/can_use() + return 1 + + +/obj/item/device/pda/ai/attack_self(mob/user as mob) + if ((honkamt > 0) && (prob(60)))//For clown virus. + honkamt-- + playsound(src, 'sound/items/bikehorn.ogg', 30, 1) + return + + +/obj/item/device/pda/ai/pai + ttone = "assist" + +/obj/item/device/pda/ai/shell + spam_proof = TRUE // Since empty shells get a functional PDA. diff --git a/code/modules/pda/app.dm b/code/modules/pda/app.dm index 055e302e101..eb64125ee9b 100644 --- a/code/modules/pda/app.dm +++ b/code/modules/pda/app.dm @@ -35,7 +35,7 @@ if(L) to_chat(L, "[bicon(pda)] [message]") - SSnanoui.update_user_uis(L, pda) // Update the receiving user's PDA UI so that they can see the new message + SStgui.update_user_uis(L, pda) // Update the receiving user's PDA UI so that they can see the new message if(!notify_silent) pda.play_ringtone() @@ -59,6 +59,9 @@ var/update = PDA_APP_UPDATE var/has_back = 0 +/datum/data/pda/app/tgui_host(mob/user) + return pda || src + /datum/data/pda/app/New() if(!title) title = name diff --git a/code/modules/pda/cart.dm b/code/modules/pda/cart.dm index 75fdc28c31e..b8917b0f527 100644 --- a/code/modules/pda/cart.dm +++ b/code/modules/pda/cart.dm @@ -55,30 +55,9 @@ var/list/civilian_cartridges = list( pickup_sound = 'sound/items/pickup/component.ogg' var/obj/item/radio/integrated/radio = null - var/access_security = 0 - var/access_engine = 0 - var/access_atmos = 0 - var/access_medical = 0 - var/access_clown = 0 - var/access_mime = 0 - var/access_janitor = 0 -// var/access_flora = 0 - var/access_reagent_scanner = 0 - var/access_remote_door = 0 // Control some blast doors remotely!! - var/remote_door_id = "" - var/access_status_display = 0 - var/access_quartermaster = 0 - var/access_detonate_pda = 0 - var/access_hydroponics = 0 + var/charges = 0 - var/mode = null - var/menu - var/datum/data/record/active1 = null //General - var/datum/data/record/active2 = null //Medical - var/datum/data/record/active3 = null //Security - var/selected_sensor = null // Power Sensor - var/message1 // used for status_displays - var/message2 + var/list/stored_data = list() var/list/programs = list() var/list/messenger_plugins = list() @@ -89,31 +68,47 @@ var/list/civilian_cartridges = list( QDEL_LIST(messenger_plugins) return ..() +/obj/item/weapon/cartridge/proc/update_programs(obj/item/device/pda/pda) + for(var/A in programs) + var/datum/data/pda/P = A + P.pda = pda + for(var/A in messenger_plugins) + var/datum/data/pda/messenger_plugin/P = A + P.pda = pda + /obj/item/weapon/cartridge/engineering name = "\improper Power-ON cartridge" icon_state = "cart-e" - access_engine = 1 + programs = list( + new/datum/data/pda/app/power, + new/datum/data/pda/utility/scanmode/halogen) /obj/item/weapon/cartridge/atmos name = "\improper BreatheDeep cartridge" icon_state = "cart-a" - access_atmos = 1 + programs = list(new/datum/data/pda/utility/scanmode/gas) /obj/item/weapon/cartridge/medical name = "\improper Med-U cartridge" icon_state = "cart-m" - access_medical = 1 + programs = list( + new/datum/data/pda/app/crew_records/medical, + new/datum/data/pda/utility/scanmode/medical) /obj/item/weapon/cartridge/chemistry name = "\improper ChemWhiz cartridge" icon_state = "cart-chem" - access_reagent_scanner = 1 - access_medical = 1 + programs = list( + new/datum/data/pda/app/crew_records/medical, + new/datum/data/pda/utility/scanmode/medical, + new/datum/data/pda/utility/scanmode/reagent) /obj/item/weapon/cartridge/security name = "\improper R.O.B.U.S.T. cartridge" icon_state = "cart-s" - access_security = 1 + programs = list( + new/datum/data/pda/app/crew_records/security, + new/datum/data/pda/app/secbot_control) /obj/item/weapon/cartridge/security/Initialize() radio = new /obj/item/radio/integrated/beepsky(src) @@ -122,38 +117,36 @@ var/list/civilian_cartridges = list( /obj/item/weapon/cartridge/detective name = "\improper D.E.T.E.C.T. cartridge" icon_state = "cart-s" - access_security = 1 - access_medical = 1 + programs = list( + new/datum/data/pda/app/crew_records/medical, + new/datum/data/pda/utility/scanmode/medical, + + new/datum/data/pda/app/crew_records/security) /obj/item/weapon/cartridge/janitor name = "\improper CustodiPRO cartridge" desc = "The ultimate in clean-room design." icon_state = "cart-j" - access_janitor = 1 + programs = list(new/datum/data/pda/app/janitor) /obj/item/weapon/cartridge/lawyer name = "\improper P.R.O.V.E. cartridge" icon_state = "cart-s" - access_security = 1 + programs = list(new/datum/data/pda/app/crew_records/security) /obj/item/weapon/cartridge/clown name = "\improper Honkworks 5.0 cartridge" icon_state = "cart-clown" - access_clown = 1 charges = 5 + programs = list(new/datum/data/pda/utility/honk) + messenger_plugins = list(new/datum/data/pda/messenger_plugin/virus/clown) /obj/item/weapon/cartridge/mime name = "\improper Gestur-O 1000 cartridge" icon_state = "cart-mi" - access_mime = 1 charges = 5 -/* -/obj/item/weapon/cartridge/botanist - name = "Green Thumb v4.20" - icon_state = "cart-b" - access_flora = 1 -*/ + messenger_plugins = list(new/datum/data/pda/messenger_plugin/virus/mime) /obj/item/weapon/cartridge/service name = "\improper Serv-U Pro cartridge" @@ -162,24 +155,34 @@ var/list/civilian_cartridges = list( /obj/item/weapon/cartridge/signal name = "generic signaler cartridge" desc = "A data cartridge with an integrated radio signaler module." - var/qdeled = 0 + programs = list(new/datum/data/pda/app/signaller) + +/obj/item/weapon/cartridge/signal/Initialize() + radio = new /obj/item/radio/integrated/signal(src) + ..() /obj/item/weapon/cartridge/signal/science name = "\improper Signal Ace 2 cartridge" desc = "Complete with integrated radio signaler!" icon_state = "cart-tox" - access_reagent_scanner = 1 - access_atmos = 1 + programs = list( + new/datum/data/pda/utility/scanmode/gas, -/obj/item/weapon/cartridge/signal/Initialize() - radio = new /obj/item/radio/integrated/signal(src) - . = ..() + new/datum/data/pda/utility/scanmode/reagent, + + new/datum/data/pda/app/signaller) /obj/item/weapon/cartridge/quartermaster name = "\improper Space Parts & Space Vendors cartridge" desc = "Perfect for the Quartermaster on the go!" icon_state = "cart-q" - access_quartermaster = 1 + programs = list( + new/datum/data/pda/app/supply, + new/datum/data/pda/app/mule_control) + +/obj/item/weapon/cartridge/quartermaster/Initialize() + radio = new /obj/item/radio/integrated/mule(src) + ..() /obj/item/weapon/cartridge/miner name = "\improper Drill-Jockey 4.5 cartridge" @@ -189,21 +192,33 @@ var/list/civilian_cartridges = list( /obj/item/weapon/cartridge/head name = "\improper Easy-Record DELUXE cartridge" icon_state = "cart-h" - access_status_display = 1 + programs = list(new/datum/data/pda/app/status_display) /obj/item/weapon/cartridge/hop name = "\improper HumanResources9001 cartridge" icon_state = "cart-h" - access_status_display = 1 - access_quartermaster = 1 - access_janitor = 1 - access_security = 1 + programs = list( + new/datum/data/pda/app/crew_records/security, + + new/datum/data/pda/app/janitor, + + new/datum/data/pda/app/supply, + new/datum/data/pda/app/mule_control, + + new/datum/data/pda/app/status_display) + +/obj/item/weapon/cartridge/hop/Initialize() + radio = new /obj/item/radio/integrated/mule(src) + ..() /obj/item/weapon/cartridge/hos name = "\improper R.O.B.U.S.T. DELUXE cartridge" icon_state = "cart-hos" - access_status_display = 1 - access_security = 1 + programs = list( + new/datum/data/pda/app/crew_records/security, + new/datum/data/pda/app/secbot_control, + + new/datum/data/pda/app/status_display) /obj/item/weapon/cartridge/hos/Initialize() radio = new /obj/item/radio/integrated/beepsky(src) @@ -212,23 +227,36 @@ var/list/civilian_cartridges = list( /obj/item/weapon/cartridge/ce name = "\improper Power-On DELUXE cartridge" icon_state = "cart-ce" - access_status_display = 1 - access_engine = 1 - access_atmos = 1 + programs = list( + new/datum/data/pda/app/power, + new/datum/data/pda/utility/scanmode/halogen, + + new/datum/data/pda/utility/scanmode/gas, + + new/datum/data/pda/app/status_display) /obj/item/weapon/cartridge/cmo name = "\improper Med-U DELUXE cartridge" icon_state = "cart-cmo" - access_status_display = 1 - access_reagent_scanner = 1 - access_medical = 1 + programs = list( + new/datum/data/pda/app/crew_records/medical, + new/datum/data/pda/utility/scanmode/medical, + + new/datum/data/pda/utility/scanmode/reagent, + + new/datum/data/pda/app/status_display) /obj/item/weapon/cartridge/rd name = "\improper Signal Ace DELUXE cartridge" icon_state = "cart-rd" - access_status_display = 1 - access_reagent_scanner = 1 - access_atmos = 1 + programs = list( + new/datum/data/pda/utility/scanmode/gas, + + new/datum/data/pda/utility/scanmode/reagent, + + new/datum/data/pda/app/signaller, + + new/datum/data/pda/app/status_display) /obj/item/weapon/cartridge/rd/Initialize() radio = new /obj/item/radio/integrated/signal(src) @@ -261,10 +289,15 @@ var/list/civilian_cartridges = list( /obj/item/weapon/cartridge/syndicate name = "\improper Detomatix cartridge" icon_state = "cart" - access_remote_door = 1 - access_detonate_pda = 1 - remote_door_id = "smindicate" //Make sure this matches the syndicate shuttle's shield/door id!! //don't ask about the name, testing. + var/initial_remote_door_id = "smindicate" //Make sure this matches the syndicate shuttle's shield/door id!! //don't ask about the name, testing. charges = 4 + programs = list(new/datum/data/pda/utility/toggle_door) + messenger_plugins = list(new/datum/data/pda/messenger_plugin/virus/detonate) + +/obj/item/weapon/cartridge/syndicate/New() + var/datum/data/pda/utility/toggle_door/D = programs[1] + if(istype(D)) + D.remote_door_id = initial_remote_door_id /obj/item/weapon/cartridge/proc/post_status(var/command, var/data1, var/data2) @@ -297,356 +330,3 @@ var/list/civilian_cartridges = list( charges = 5 var/telecrystals = 0 messenger_plugins = list(new/datum/data/pda/messenger_plugin/virus/frame) - - -/* - This generates the nano values of the cart menus. - Because we close the UI when we insert a new cart - we don't have to worry about null values on items - the user can't access. Well, unless they are href hacking. - But in that case their UI will just lock up. -*/ - - -/obj/item/weapon/cartridge/proc/create_NanoUI_values(mob/user as mob) - var/values[0] - - /* Signaler (Mode: 40) */ - - - if(istype(radio,/obj/item/radio/integrated/signal) && (mode==40)) - var/obj/item/radio/integrated/signal/R = radio - values["signal_freq"] = format_frequency(R.frequency) - values["signal_code"] = R.code - - - /* Station Display (Mode: 42) */ - - if(mode==42) - values["message1"] = message1 ? message1 : "(none)" - values["message2"] = message2 ? message2 : "(none)" - - - - /* Power Monitor (Mode: 43 / 433) */ - - if(mode==43 || mode==433) - var/list/sensors = list() - var/obj/machinery/power/sensor/MS = null - var/my_z = get_z(user) - var/list/levels = using_map.get_map_levels(my_z) - - for(var/obj/machinery/power/sensor/S in machines) - if(!(get_z(S) in levels)) - continue - sensors.Add(list(list("name_tag" = S.name_tag))) - if(S.name_tag == selected_sensor) - MS = S - values["power_sensors"] = sensors - if(selected_sensor && MS) - values["sensor_reading"] = MS.return_reading_data() - - - /* General Records (Mode: 44 / 441 / 45 / 451) */ - if(mode == 44 || mode == 441 || mode == 45 || mode ==451) - if(istype(active1, /datum/data/record) && (active1 in data_core.general)) - values["general"] = active1.fields - values["general_exists"] = 1 - - else - values["general_exists"] = 0 - - - - /* Medical Records (Mode: 44 / 441) */ - - if(mode == 44 || mode == 441) - var/medData[0] - for(var/datum/data/record/R in sortRecord(data_core.general)) - medData[++medData.len] = list(Name = R.fields["name"],"ref" = "\ref[R]") - values["medical_records"] = medData - - if(istype(active2, /datum/data/record) && (active2 in data_core.medical)) - values["medical"] = active2.fields - values["medical_exists"] = 1 - else - values["medical_exists"] = 0 - - /* Security Records (Mode:45 / 451) */ - - if(mode == 45 || mode == 451) - var/secData[0] - for (var/datum/data/record/R in sortRecord(data_core.general)) - secData[++secData.len] = list(Name = R.fields["name"], "ref" = "\ref[R]") - values["security_records"] = secData - - if(istype(active3, /datum/data/record) && (active3 in data_core.security)) - values["security"] = active3.fields - values["security_exists"] = 1 - else - values["security_exists"] = 0 - - /* Security Bot Control (Mode: 46) */ - - if(mode==46) - var/botsData[0] - var/beepskyData[0] - if(istype(radio,/obj/item/radio/integrated/beepsky)) - var/obj/item/radio/integrated/beepsky/SC = radio - beepskyData["active"] = SC.active - if(SC.active && !isnull(SC.botstatus)) - var/area/loca = SC.botstatus["loca"] - var/loca_name = sanitize(loca.name) - beepskyData["botstatus"] = list("loca" = loca_name, "mode" = SC.botstatus["mode"]) - else - beepskyData["botstatus"] = list("loca" = null, "mode" = -1) - var/botsCount=0 - if(SC.botlist && SC.botlist.len) - for(var/mob/living/bot/B in SC.botlist) - botsCount++ - if(B.loc) - botsData[++botsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]") - - if(!botsData.len) - botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) - - beepskyData["bots"] = botsData - beepskyData["count"] = botsCount - - else - beepskyData["active"] = 0 - botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) - beepskyData["botstatus"] = list("loca" = null, "mode" = null) - beepskyData["bots"] = botsData - beepskyData["count"] = 0 - - values["beepsky"] = beepskyData - - - /* MULEBOT Control (Mode: 48) */ - - if(mode==48) - var/mulebotsData[0] - var/count = 0 - - for(var/mob/living/bot/mulebot/M in living_mob_list) - if(!M.on) - continue - ++count - var/muleData[0] - muleData["name"] = M.suffix - muleData["location"] = get_area(M) - muleData["paused"] = M.paused - muleData["home"] = M.homeName - muleData["target"] = M.targetName - muleData["ref"] = "\ref[M]" - muleData["load"] = M.load ? M.load.name : "Nothing" - - mulebotsData[++mulebotsData.len] = muleData.Copy() - - values["mulebotcount"] = count - values["mulebots"] = mulebotsData - - - - /* Supply Shuttle Requests Menu (Mode: 47) */ - - if(mode==47) - var/supplyData[0] - var/datum/shuttle/autodock/ferry/supply/shuttle = SSsupply.shuttle - if (shuttle) - supplyData["shuttle_moving"] = shuttle.has_arrive_time() - supplyData["shuttle_eta"] = shuttle.eta_minutes() - supplyData["shuttle_loc"] = shuttle.at_station() ? "Station" : "Dock" - var/supplyOrderCount = 0 - var/supplyOrderData[0] - for(var/S in SSsupply.shoppinglist) - var/datum/supply_order/SO = S - - supplyOrderData[++supplyOrderData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "ApprovedBy" = SO.ordered_by, "Comment" = html_encode(SO.comment)) - if(!supplyOrderData.len) - supplyOrderData[++supplyOrderData.len] = list("Number" = null, "Name" = null, "OrderedBy"=null) - - supplyData["approved"] = supplyOrderData - supplyData["approved_count"] = supplyOrderCount - - var/requestCount = 0 - var/requestData[0] - for(var/S in SSsupply.order_history) - var/datum/supply_order/SO = S - if(SO.status != SUP_ORDER_REQUESTED) - continue - - requestCount++ - requestData[++requestData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "OrderedBy" = SO.ordered_by, "Comment" = html_encode(SO.comment)) - if(!requestData.len) - requestData[++requestData.len] = list("Number" = null, "Name" = null, "orderedBy" = null, "Comment" = null) - - supplyData["requests"] = requestData - supplyData["requests_count"] = requestCount - - - values["supply"] = supplyData - - - - /* Janitor Supplies Locator (Mode: 49) */ - if(mode==49) - var/JaniData[0] - var/turf/cl = get_turf(src) - - if(cl) - JaniData["user_loc"] = list("x" = cl.x, "y" = cl.y) - else - JaniData["user_loc"] = list("x" = 0, "y" = 0) - var/MopData[0] - for(var/obj/item/weapon/mop/M in all_mops) - var/turf/ml = get_turf(M) - if(ml) - if(ml.z != cl.z) - continue - var/direction = get_dir(src, M) - MopData[++MopData.len] = list ("x" = ml.x, "y" = ml.y, "dir" = uppertext(dir2text(direction)), "status" = M.reagents.total_volume ? "Wet" : "Dry") - - if(!MopData.len) - MopData[++MopData.len] = list("x" = 0, "y" = 0, dir=null, status = null) - - - var/BucketData[0] - for(var/obj/structure/mopbucket/B in all_mopbuckets) - var/turf/bl = get_turf(B) - if(bl) - if(bl.z != cl.z) - continue - var/direction = get_dir(src,B) - BucketData[++BucketData.len] = list ("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.reagents.total_volume/100) - - if(!BucketData.len) - BucketData[++BucketData.len] = list("x" = 0, "y" = 0, dir=null, status = null) - - var/CbotData[0] - for(var/mob/living/bot/cleanbot/B in mob_list) - var/turf/bl = get_turf(B) - if(bl) - if(bl.z != cl.z) - continue - var/direction = get_dir(src,B) - CbotData[++CbotData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.on ? "Online" : "Offline") - - - if(!CbotData.len) - CbotData[++CbotData.len] = list("x" = 0, "y" = 0, dir=null, status = null) - var/CartData[0] - for(var/obj/structure/janitorialcart/B in all_janitorial_carts) - var/turf/bl = get_turf(B) - if(bl) - if(bl.z != cl.z) - continue - var/direction = get_dir(src,B) - var/status = "No Bucket" - if(B.mybucket) - status = B.mybucket.reagents.total_volume / 100 - CartData[++CartData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = status) - if(!CartData.len) - CartData[++CartData.len] = list("x" = 0, "y" = 0, dir=null, status = null) - - - - - JaniData["mops"] = MopData - JaniData["buckets"] = BucketData - JaniData["cleanbots"] = CbotData - JaniData["carts"] = CartData - values["janitor"] = JaniData - - return values - - - - - -/obj/item/weapon/cartridge/Topic(href, href_list) - ..() - - if (!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) - usr.unset_machine() - usr << browse(null, "window=pda") - return - - - - - switch(href_list["choice"]) - if("Medical Records") - var/datum/data/record/R = locate(href_list["target"]) - var/datum/data/record/M = locate(href_list["target"]) - loc:mode = 441 - mode = 441 - if (R in data_core.general) - for (var/datum/data/record/E in data_core.medical) - if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) - M = E - break - active1 = R - active2 = M - - if("Security Records") - var/datum/data/record/R = locate(href_list["target"]) - var/datum/data/record/S = locate(href_list["target"]) - loc:mode = 451 - mode = 451 - if (R in data_core.general) - for (var/datum/data/record/E in data_core.security) - if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) - S = E - break - active1 = R - active3 = S - - if("Send Signal") - if(is_jammed(src)) - return - spawn( 0 ) - radio:send_signal("ACTIVATE") - return - - if("Signal Frequency") - var/new_frequency = sanitize_frequency(radio:frequency + text2num(href_list["sfreq"])) - radio:set_frequency(new_frequency) - - if("Signal Code") - radio:code += text2num(href_list["scode"]) - radio:code = round(radio:code) - radio:code = min(100, radio:code) - radio:code = max(1, radio:code) - - if("Status") - switch(href_list["statdisp"]) - if("message") - post_status("message", message1, message2) - if("alert") - post_status("alert", href_list["alert"]) - if("setmsg1") - message1 = reject_bad_text(sanitize(input("Line 1", "Enter Message Text", message1) as text|null, 40), 40) - updateSelfDialog() - if("setmsg2") - message2 = reject_bad_text(sanitize(input("Line 2", "Enter Message Text", message2) as text|null, 40), 40) - updateSelfDialog() - else - post_status(href_list["statdisp"]) - - if("Power Select") - selected_sensor = href_list["target"] - loc:mode = 433 - mode = 433 - if("Power Clear") - selected_sensor = null - loc:mode = 43 - mode = 43 - - if("MULEbot") - var/mob/living/bot/mulebot/M = locate(href_list["ref"]) - if(istype(M)) - M.obeyCommand(href_list["command"]) - - return 1 diff --git a/code/modules/pda/cart_apps.dm b/code/modules/pda/cart_apps.dm index 0754e7fb924..af41d666ad7 100644 --- a/code/modules/pda/cart_apps.dm +++ b/code/modules/pda/cart_apps.dm @@ -12,20 +12,23 @@ "message1" = message1 ? message1 : "(none)", "message2" = message2 ? message2 : "(none)") -/datum/data/pda/app/status_display/Topic(href, list/href_list) - switch(href_list["choice"]) +/datum/data/pda/app/status_display/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + switch(action) if("Status") - switch(href_list["statdisp"]) + switch(params["statdisp"]) if("message") post_status("message", message1, message2) if("alert") - post_status("alert", href_list["alert"]) + post_status("alert", params["alert"]) if("setmsg1") message1 = clean_input("Line 1", "Enter Message Text", message1) if("setmsg2") message2 = clean_input("Line 2", "Enter Message Text", message2) else - post_status(href_list["statdisp"]) + post_status(params["statdisp"]) + return TRUE /datum/data/pda/app/status_display/proc/post_status(var/command, var/data1, var/data2) var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435) @@ -43,7 +46,7 @@ status_signal.data["msg2"] = data2 var/mob/user = pda.fingerprintslast if(istype(pda.loc, /mob/living)) - name = pda.loc + user = pda.loc log_admin("STATUS: [user] set status screen with [pda]. Message: [data1] [data2]") message_admins("STATUS: [user] set status screen with [pda]. Message: [data1] [data2]") @@ -66,21 +69,23 @@ data["signal_freq"] = format_frequency(R.frequency) data["signal_code"] = R.code -/datum/data/pda/app/signaller/Topic(href, list/href_list) +/datum/data/pda/app/signaller/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/radio/integrated/signal)) var/obj/item/radio/integrated/signal/R = pda.cartridge.radio - switch(href_list["choice"]) + switch(action) if("Send Signal") spawn(0) R.send_signal("ACTIVATE") if("Signal Frequency") - var/new_frequency = sanitize_frequency(R.frequency + text2num(href_list["sfreq"])) + var/new_frequency = sanitize_frequency(R.frequency + text2num(params["sfreq"])) R.set_frequency(new_frequency) if("Signal Code") - R.code += text2num(href_list["scode"]) + R.code += text2num(params["scode"]) R.code = round(R.code) R.code = min(100, R.code) R.code = max(1, R.code) @@ -90,36 +95,29 @@ icon = "exclamation-triangle" template = "pda_power" category = "Engineering" - update = PDA_APP_UPDATE_SLOW -// var/obj/machinery/computer/monitor/powmonitor = null + var/datum/tgui_module/power_monitor/power_monitor -// /datum/data/pda/app/power/update_ui(mob/user as mob, list/data) -// update = PDA_APP_UPDATE_SLOW +/datum/data/pda/app/power/New() + power_monitor = new(src) + . = ..() -// if(powmonitor && !isnull(powmonitor.powernet)) -// data["records"] = list( -// "powerconnected" = 1, -// "poweravail" = powmonitor.powernet.avail, -// "powerload" = num2text(powmonitor.powernet.viewload, 10), -// "powerdemand" = powmonitor.powernet.load, -// "apcs" = GLOB.apc_repository.apc_data(powmonitor.powernet)) -// has_back = 1 -// else -// data["records"] = list( -// "powerconnected" = 0, -// "powermonitors" = GLOB.powermonitor_repository.powermonitor_data()) -// has_back = 0 +/datum/data/pda/app/power/Destroy() + QDEL_NULL(power_monitor) + return ..() -// /datum/data/pda/app/power/Topic(href, list/href_list) -// switch(href_list["choice"]) -// if("Power Select") -// var/pref = href_list["target"] -// powmonitor = locate(pref) -// update = PDA_APP_UPDATE -// if("Back") -// powmonitor = null -// update = PDA_APP_UPDATE +/datum/data/pda/app/power/update_ui(mob/user as mob, list/data) + data.Add(power_monitor.tgui_data(user)) + +/datum/data/pda/app/power/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + if(power_monitor.tgui_act(action, params, ui, state)) + return TRUE + switch(action) + if("Back") + power_monitor.active_sensor = null + return TRUE /datum/data/pda/app/crew_records var/datum/data/record/general_records = null @@ -137,17 +135,22 @@ if(R) records += list(list(Name = R.fields["name"], "ref" = "\ref[R]")) data["recordsList"] = records + data["records"] = null return null -/datum/data/pda/app/crew_records/Topic(href, list/href_list) - switch(href_list["choice"]) +/datum/data/pda/app/crew_records/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + switch(action) if("Records") - var/datum/data/record/R = locate(href_list["target"]) + var/datum/data/record/R = locate(params["target"]) if(R && (R in data_core.general)) load_records(R) + return TRUE if("Back") general_records = null has_back = 0 + return TRUE /datum/data/pda/app/crew_records/proc/load_records(datum/data/record/R) general_records = R @@ -247,11 +250,14 @@ data["beepsky"] = beepskyData -/datum/data/pda/app/secbot_control/Topic(href, list/href_list) - switch(href_list["choice"]) +/datum/data/pda/app/secbot_control/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + switch(action) if("Back") if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/radio/integrated/beepsky)) pda.cartridge.radio.Topic(null, list(radiomenu = "1", op = "botlist")) + return TRUE /datum/data/pda/app/mule_control name = "Delivery Bot Control" @@ -259,104 +265,97 @@ template = "pda_mule" category = "Quartermaster" -// /datum/data/pda/app/mule_control/update_ui(mob/user as mob, list/data) -// var/muleData[0] -// var/mulebotsData[0] -// if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/radio/integrated/mule)) -// var/obj/item/radio/integrated/mule/QC = pda.cartridge.radio -// muleData["active"] = QC.active ? sanitize(QC.active.name) : null -// has_back = QC.active ? 1 : 0 -// if(QC.active && !isnull(QC.botstatus)) -// var/area/loca = QC.botstatus["loca"] -// var/loca_name = sanitize(loca.name) -// muleData["botstatus"] = list("loca" = loca_name, "mode" = QC.botstatus["mode"],"home"=QC.botstatus["home"],"powr" = QC.botstatus["powr"],"retn" =QC.botstatus["retn"], "pick"=QC.botstatus["pick"], "load" = QC.botstatus["load"], "dest" = sanitize(QC.botstatus["dest"])) +/datum/data/pda/app/mule_control/update_ui(mob/user as mob, list/data) + var/muleData[0] + var/mulebotsData[0] + if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/radio/integrated/mule)) + var/obj/item/radio/integrated/mule/QC = pda.cartridge.radio + muleData["active"] = QC.active ? sanitize(QC.active.name) : null + has_back = QC.active ? 1 : 0 + if(QC.active && !isnull(QC.botstatus)) + var/area/loca = QC.botstatus["loca"] + var/loca_name = sanitize(loca.name) + muleData["botstatus"] = list("loca" = loca_name, "mode" = QC.botstatus["mode"],"home"=QC.botstatus["home"],"powr" = QC.botstatus["powr"],"retn" =QC.botstatus["retn"], "pick"=QC.botstatus["pick"], "load" = QC.botstatus["load"], "dest" = sanitize(QC.botstatus["dest"])) -// else -// muleData["botstatus"] = list("loca" = null, "mode" = -1,"home"=null,"powr" = null,"retn" =null, "pick"=null, "load" = null, "dest" = null) + else + muleData["botstatus"] = list("loca" = null, "mode" = -1,"home"=null,"powr" = null,"retn" =null, "pick"=null, "load" = null, "dest" = null) -// var/mulebotsCount=0 -// for(var/mob/living/bot/B in QC.botlist) -// mulebotsCount++ -// if(B.loc) -// mulebotsData[++mulebotsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]") + var/mulebotsCount=0 + for(var/mob/living/bot/B in QC.botlist) + mulebotsCount++ + if(B.loc) + mulebotsData[++mulebotsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]") -// if(!mulebotsData.len) -// mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) + if(!mulebotsData.len) + mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) -// muleData["bots"] = mulebotsData -// muleData["count"] = mulebotsCount + muleData["bots"] = mulebotsData + muleData["count"] = mulebotsCount -// else -// muleData["botstatus"] = list("loca" = null, "mode" = -1,"home"=null,"powr" = null,"retn" =null, "pick"=null, "load" = null, "dest" = null) -// muleData["active"] = 0 -// mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) -// muleData["bots"] = mulebotsData -// muleData["count"] = 0 -// has_back = 0 + else + muleData["botstatus"] = list("loca" = null, "mode" = -1,"home"=null,"powr" = null,"retn" =null, "pick"=null, "load" = null, "dest" = null) + muleData["active"] = 0 + mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) + muleData["bots"] = mulebotsData + muleData["count"] = 0 + has_back = 0 -// data["mulebot"] = muleData + data["mulebot"] = muleData -// /datum/data/pda/app/mule_control/Topic(href, list/href_list) -// switch(href_list["choice"]) -// if("Back") -// if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/radio/integrated/mule)) -// pda.cartridge.radio.Topic(null, list(radiomenu = "1", op = "botlist")) +/datum/data/pda/app/mule_control/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + switch(action) + if("Back") + if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/radio/integrated/mule)) + pda.cartridge.radio.Topic(null, list(radiomenu = "1", op = "botlist")) + return TRUE /datum/data/pda/app/supply name = "Supply Records" - icon = "file-text-o" + icon = "file-word-o" template = "pda_supply" category = "Quartermaster" - update = PDA_APP_UPDATE_SLOW -// /datum/data/pda/app/supply/update_ui(mob/user as mob, list/data) -// var/supplyData[0] +/datum/data/pda/app/supply/update_ui(mob/user as mob, list/data) + var/supplyData[0] + var/datum/shuttle/autodock/ferry/supply/shuttle = SSsupply.shuttle + if (shuttle) + supplyData["shuttle_moving"] = shuttle.has_arrive_time() + supplyData["shuttle_eta"] = shuttle.eta_minutes() + supplyData["shuttle_loc"] = shuttle.at_station() ? "Station" : "Dock" + var/supplyOrderCount = 0 + var/supplyOrderData[0] + for(var/S in SSsupply.shoppinglist) + var/datum/supply_order/SO = S -// if(SSshuttle.supply.mode == SHUTTLE_CALL) -// supplyData["shuttle_moving"] = 1 + supplyOrderCount++ + supplyOrderData[++supplyOrderData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "ApprovedBy" = SO.ordered_by, "Comment" = html_encode(SO.comment)) -// if(is_station_level(SSshuttle.supply.z)) -// supplyData["shuttle_loc"] = "Station" -// else -// supplyData["shuttle_loc"] = "CentCom" + supplyData["approved"] = supplyOrderData + supplyData["approved_count"] = supplyOrderCount -// supplyData["shuttle_time"] = "([SSshuttle.supply.timeLeft(600)] Mins)" + var/requestCount = 0 + var/requestData[0] + for(var/S in SSsupply.order_history) + var/datum/supply_order/SO = S + if(SO.status != SUP_ORDER_REQUESTED) + continue -// var/supplyOrderCount = 0 -// var/supplyOrderData[0] -// for(var/S in SSshuttle.shoppinglist) -// var/datum/supply_order/SO = S -// supplyOrderCount++ -// supplyOrderData[++supplyOrderData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "ApprovedBy" = SO.orderedby, "Comment" = html_encode(SO.comment)) + requestCount++ + requestData[++requestData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "OrderedBy" = SO.ordered_by, "Comment" = html_encode(SO.comment)) -// if(!supplyOrderData.len) -// supplyOrderData[++supplyOrderData.len] = list("Number" = null, "Name" = null, "OrderedBy"=null) + supplyData["requests"] = requestData + supplyData["requests_count"] = requestCount -// supplyData["approved"] = supplyOrderData -// supplyData["approved_count"] = supplyOrderCount - -// var/requestCount = 0 -// var/requestData[0] -// for(var/S in SSshuttle.requestlist) -// var/datum/supply_order/SO = S -// requestCount++ -// requestData[++requestData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "OrderedBy" = SO.orderedby, "Comment" = html_encode(SO.comment)) - -// if(!requestData.len) -// requestData[++requestData.len] = list("Number" = null, "Name" = null, "orderedBy" = null, "Comment" = null) - -// supplyData["requests"] = requestData -// supplyData["requests_count"] = requestCount - -// data["supply"] = supplyData + data["supply"] = supplyData /datum/data/pda/app/janitor name = "Custodial Locator" - icon = "trash-o" + icon = "trash-alt-o" template = "pda_janitor" category = "Utilities" - update = PDA_APP_UPDATE_SLOW /datum/data/pda/app/janitor/update_ui(mob/user as mob, list/data) var/JaniData[0] diff --git a/code/modules/pda/cart_vr.dm b/code/modules/pda/cart_vr.dm index fc4e3d098a4..1f1a1cbe520 100644 --- a/code/modules/pda/cart_vr.dm +++ b/code/modules/pda/cart_vr.dm @@ -6,12 +6,15 @@ var/list/exploration_cartridges = list( /obj/item/weapon/cartridge/explorer name = "\improper Explorator cartridge" icon_state = "cart-e" - access_reagent_scanner = 1 - access_atmos = 1 + programs = list( + new/datum/data/pda/utility/scanmode/reagent, + new/datum/data/pda/utility/scanmode/gas) /obj/item/weapon/cartridge/sar name = "\improper Med-Exp cartridge" icon_state = "cart-m" - access_medical = 1 - access_reagent_scanner = 1 - access_atmos = 1 + programs = list( + new/datum/data/pda/app/crew_records/medical, + new/datum/data/pda/utility/scanmode/medical, + new/datum/data/pda/utility/scanmode/reagent, + new/datum/data/pda/utility/scanmode/gas) diff --git a/code/modules/pda/core_apps.dm b/code/modules/pda/core_apps.dm index 468b9005f53..6151ac87e4c 100644 --- a/code/modules/pda/core_apps.dm +++ b/code/modules/pda/core_apps.dm @@ -17,18 +17,21 @@ notifying["\ref[P]"] = 1 data["notifying"] = notifying -/datum/data/pda/app/main_menu/Topic(href, list/href_list) - switch(href_list["choice"]) +/datum/data/pda/app/main_menu/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + switch(action) if("UpdateInfo") pda.ownjob = pda.id.assignment pda.ownrank = pda.id.rank pda.name = "PDA-[pda.owner] ([pda.ownjob])" + return TRUE if("pai") if(pda.pai) if(pda.pai.loc != pda) pda.pai = null else - switch(href_list["option"]) + switch(params["option"]) if("1") // Configure pAI device pda.pai.attack_self(usr) if("2") // Eject pAI device @@ -36,6 +39,7 @@ if(T) pda.pai.loc = T pda.pai = null + return TRUE /datum/data/pda/app/notekeeper name = "Notekeeper" @@ -53,8 +57,10 @@ /datum/data/pda/app/notekeeper/update_ui(mob/user as mob, list/data) data["note"] = note // current pda notes -/datum/data/pda/app/notekeeper/Topic(href, list/href_list) - switch(href_list["choice"]) +/datum/data/pda/app/notekeeper/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + switch(action) if("Edit") var/n = input("Please enter message", name, notehtml) as message if(pda.loc == usr) @@ -63,49 +69,59 @@ note = replacetext(note, "\n", "
") else pda.close(usr) + return TRUE /datum/data/pda/app/manifest name = "Crew Manifest" icon = "user" template = "pda_manifest" - update = PDA_APP_UPDATE_SLOW -// /datum/data/pda/app/manifest/update_ui(mob/user as mob, list/data) - // data_core.get_manifest_json() - // data["manifest"] = PDA_Manifest +/datum/data/pda/app/manifest/update_ui(mob/user as mob, list/data) + if(data_core) + data_core.get_manifest_list() + data["manifest"] = PDA_Manifest -/datum/data/pda/app/manifest/Topic(href, list/href_list) +/datum/data/pda/app/manifest/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE /datum/data/pda/app/atmos_scanner name = "Atmospheric Scan" icon = "fire" template = "pda_atmos_scan" category = "Utilities" - update = PDA_APP_UPDATE_SLOW -// /datum/data/pda/app/atmos_scanner/update_ui(mob/user as mob, list/data) -// var/turf/T = get_turf(user.loc) -// if(!isnull(T)) -// var/datum/gas_mixture/environment = T.return_air() +/datum/data/pda/app/atmos_scanner/update_ui(mob/user as mob, list/data) + var/list/results = list() + var/turf/T = get_turf(user) + if(!isnull(T)) + var/datum/gas_mixture/environment = T.return_air() + var/pressure = environment.return_pressure() + var/total_moles = environment.total_moles + if (total_moles) + var/o2_level = environment.gas["oxygen"]/total_moles + var/n2_level = environment.gas["nitrogen"]/total_moles + var/co2_level = environment.gas["carbon_dioxide"]/total_moles + var/phoron_level = environment.gas["phoron"]/total_moles + var/unknown_level = 1-(o2_level+n2_level+co2_level+phoron_level) -// var/pressure = environment.return_pressure() -// var/total_moles = environment.total_moles + // entry is what the element is describing + // Type identifies which unit or other special characters to use + // Val is the information reported + // Bad_high/_low are the values outside of which the entry reports as dangerous + // Poor_high/_low are the values outside of which the entry reports as unideal + // Values were extracted from the template itself + results = list( + list("entry" = "Pressure", "units" = "kPa", "val" = "[round(pressure,0.1)]", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80), + list("entry" = "Temperature", "units" = "°C", "val" = "[round(environment.temperature-T0C,0.1)]", "bad_high" = 35, "poor_high" = 25, "poor_low" = 15, "bad_low" = 5), + list("entry" = "Oxygen", "units" = "kPa", "val" = "[round(o2_level*100,0.1)]", "bad_high" = 140, "poor_high" = 135, "poor_low" = 19, "bad_low" = 17), + list("entry" = "Nitrogen", "units" = "kPa", "val" = "[round(n2_level*100,0.1)]", "bad_high" = 105, "poor_high" = 85, "poor_low" = 50, "bad_low" = 40), + list("entry" = "Carbon Dioxide", "units" = "kPa", "val" = "[round(co2_level*100,0.1)]", "bad_high" = 10, "poor_high" = 5, "poor_low" = 0, "bad_low" = 0), + list("entry" = "Phoron", "units" = "kPa", "val" = "[round(phoron_level*100,0.01)]", "bad_high" = 0.5, "poor_high" = 0, "poor_low" = 0, "bad_low" = 0), + list("entry" = "Other", "units" = "kPa", "val" = "[round(unknown_level, 0.01)]", "bad_high" = 1, "poor_high" = 0.5, "poor_low" = 0, "bad_low" = 0) + ) -// if(total_moles) -// var/o2_level = environment.oxygen/total_moles -// var/n2_level = environment.nitrogen/total_moles -// var/co2_level = environment.carbon_dioxide/total_moles -// var/plasma_level = environment.toxins/total_moles -// var/unknown_level = 1-(o2_level+n2_level+co2_level+plasma_level) -// data["aircontents"] = list( -// "pressure" = pressure, -// "nitrogen" = n2_level*100, -// "oxygen" = o2_level*100, -// "carbon_dioxide" = co2_level*100, -// "plasma" = plasma_level*100, -// "other" = unknown_level, -// "temp" = environment.temperature-T0C, -// "reading" = 1 -// ) -// if(isnull(data["aircontents"])) -// data["aircontents"] = list("reading" = 0) + if(isnull(results)) + results = list(list("entry" = "pressure", "units" = "kPa", "val" = "0", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80)) + + data["aircontents"] = results \ No newline at end of file diff --git a/code/modules/pda/messenger.dm b/code/modules/pda/messenger.dm index 578ab9fcfbc..e1b4571ac02 100644 --- a/code/modules/pda/messenger.dm +++ b/code/modules/pda/messenger.dm @@ -12,13 +12,10 @@ var/m_hidden = 0 // Is the PDA hidden from the PDA list? var/active_conversation = null // New variable that allows us to only view a single conversation. var/list/conversations = list() // For keeping up with who we have PDA messsages from. - var/latest_post = 0 - var/auto_scroll = 1 /datum/data/pda/app/messenger/start() . = ..() unnotify() - latest_post = 0 /datum/data/pda/app/messenger/update_ui(mob/user as mob, list/data) data["silent"] = notify_silent // does the pda make noise when it receives a message? @@ -33,9 +30,6 @@ data["convo_name"] = sanitize(c["owner"]) data["convo_job"] = sanitize(c["job"]) break - data["auto_scroll"] = auto_scroll - data["latest_post"] = latest_post - latest_post = tnote.len else var/convopdas[0] var/pdas[0] @@ -63,21 +57,23 @@ if(pda.cartridge) data["charges"] = pda.cartridge.charges ? pda.cartridge.charges : 0 -/datum/data/pda/app/messenger/Topic(href, list/href_list) - if(!pda.can_use()) - return +/datum/data/pda/app/messenger/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + unnotify() - switch(href_list["choice"]) + . = TRUE + switch(action) if("Toggle Messenger") toff = !toff if("Toggle Ringer")//If viewing texts then erase them, if not then toggle silent status notify_silent = !notify_silent if("Clear")//Clears messages - if(href_list["option"] == "All") + if(params["option"] == "All") tnote.Cut() conversations.Cut() - if(href_list["option"] == "Convo") + if(params["option"] == "Convo") var/new_tnote[0] for(var/i in tnote) if(i["target"] != active_conversation) @@ -86,36 +82,30 @@ conversations.Remove(active_conversation) active_conversation = null - latest_post = 0 if("Message") - var/obj/item/device/pda/P = locate(href_list["target"]) + var/obj/item/device/pda/P = locate(params["target"]) create_message(usr, P) - if(href_list["target"] in conversations) // Need to make sure the message went through, if not welp. - active_conversation = href_list["target"] - latest_post = 0 + if(params["target"] in conversations) // Need to make sure the message went through, if not welp. + active_conversation = params["target"] if("Select Conversation") - var/P = href_list["convo"] + var/P = params["target"] for(var/n in conversations) if(P == n) active_conversation = P - latest_post = 0 if("Messenger Plugin") - if(!href_list["target"] || !href_list["plugin"]) + if(!params["target"] || !params["plugin"]) return - var/obj/item/device/pda/P = locate(href_list["target"]) + var/obj/item/device/pda/P = locate(params["target"]) if(!P) to_chat(usr, "PDA not found.") - var/datum/data/pda/messenger_plugin/plugin = locate(href_list["plugin"]) + var/datum/data/pda/messenger_plugin/plugin = locate(params["plugin"]) if(plugin && (plugin in pda.cartridge.messenger_plugins)) plugin.messenger = src plugin.user_act(usr, P) if("Back") active_conversation = null - latest_post = 0 - if("Autoscroll") - auto_scroll = !auto_scroll /datum/data/pda/app/messenger/proc/create_message(var/mob/living/U, var/obj/item/device/pda/P) var/t = input(U, "Please enter message", name, null) as text|null @@ -178,7 +168,7 @@ if(!PM.conversations.Find("\ref[pda]")) PM.conversations.Add("\ref[pda]") - SSnanoui.update_user_uis(U, P) // Update the sending user's PDA UI so that they can see the new message + SStgui.update_user_uis(U, P) // Update the sending user's PDA UI so that they can see the new message PM.notify("Message from [pda.owner] ([pda.ownjob]), \"[t]\" (Reply)") log_pda("(PDA: [src.name]) sent \"[t]\" to [P.name]", usr) else diff --git a/code/modules/pda/pda.dm b/code/modules/pda/pda.dm index bbb27f9a78e..7c8b2d89ac6 100644 --- a/code/modules/pda/pda.dm +++ b/code/modules/pda/pda.dm @@ -18,7 +18,6 @@ var/global/list/obj/item/device/pda/PDAs = list() var/owner = null var/default_cartridge = 0 // Access level defined by cartridge var/obj/item/weapon/cartridge/cartridge = null //current cartridge - var/ui_tick = 0 //Secondary variables // var/scanmode = 0 //1 is medical scanner, 2 is forensics, 3 is reagent scanner. @@ -144,347 +143,6 @@ var/global/list/obj/item/device/pda/PDAs = list() close(usr) return 0 -/obj/item/device/pda/medical - default_cartridge = /obj/item/weapon/cartridge/medical - icon_state = "pda-m" - -/obj/item/device/pda/viro - default_cartridge = /obj/item/weapon/cartridge/medical - icon_state = "pda-v" - -/obj/item/device/pda/engineering - default_cartridge = /obj/item/weapon/cartridge/engineering - icon_state = "pda-e" - -/obj/item/device/pda/security - default_cartridge = /obj/item/weapon/cartridge/security - icon_state = "pda-s" - -/obj/item/device/pda/detective - default_cartridge = /obj/item/weapon/cartridge/detective - icon_state = "pda-det" - -/obj/item/device/pda/warden - default_cartridge = /obj/item/weapon/cartridge/security - icon_state = "pda-warden" - -/obj/item/device/pda/janitor - default_cartridge = /obj/item/weapon/cartridge/janitor - icon_state = "pda-j" - ttone = "slip" - -/obj/item/device/pda/science - default_cartridge = /obj/item/weapon/cartridge/signal/science - icon_state = "pda-tox" - ttone = "boom" - -/obj/item/device/pda/clown - default_cartridge = /obj/item/weapon/cartridge/clown - icon_state = "pda-clown" - desc = "A portable microcomputer by Thinktronic Systems, LTD. The surface is coated with polytetrafluoroethylene and banana drippings." - ttone = "honk" - -/obj/item/device/pda/mime - default_cartridge = /obj/item/weapon/cartridge/mime - icon_state = "pda-mime" - message_silent = 1 - news_silent = 1 - ttone = "silence" - newstone = "silence" - -/obj/item/device/pda/heads - default_cartridge = /obj/item/weapon/cartridge/head - icon_state = "pda-h" - news_silent = 1 - -/obj/item/device/pda/heads/hop - default_cartridge = /obj/item/weapon/cartridge/hop - icon_state = "pda-hop" - -/obj/item/device/pda/heads/hos - default_cartridge = /obj/item/weapon/cartridge/hos - icon_state = "pda-hos" - -/obj/item/device/pda/heads/ce - default_cartridge = /obj/item/weapon/cartridge/ce - icon_state = "pda-ce" - -/obj/item/device/pda/heads/cmo - default_cartridge = /obj/item/weapon/cartridge/cmo - icon_state = "pda-cmo" - -/obj/item/device/pda/heads/rd - default_cartridge = /obj/item/weapon/cartridge/rd - icon_state = "pda-rd" - -/obj/item/device/pda/captain - default_cartridge = /obj/item/weapon/cartridge/captain - icon_state = "pda-c" - detonate = 0 - //toff = 1 - -/obj/item/device/pda/ert - default_cartridge = /obj/item/weapon/cartridge/captain - icon_state = "pda-h" - detonate = 0 -// hidden = 1 - -/obj/item/device/pda/cargo - default_cartridge = /obj/item/weapon/cartridge/quartermaster - icon_state = "pda-cargo" - -/obj/item/device/pda/quartermaster - default_cartridge = /obj/item/weapon/cartridge/quartermaster - icon_state = "pda-q" - -/obj/item/device/pda/shaftminer - icon_state = "pda-miner" - default_cartridge = /obj/item/weapon/cartridge/miner - -/obj/item/device/pda/syndicate - default_cartridge = /obj/item/weapon/cartridge/syndicate - icon_state = "pda-syn" -// name = "Military PDA" // Vorestation Edit -// owner = "John Doe" - hidden = 1 - -/obj/item/device/pda/chaplain - default_cartridge = /obj/item/weapon/cartridge/service - icon_state = "pda-holy" - ttone = "holy" - -/obj/item/device/pda/lawyer - default_cartridge = /obj/item/weapon/cartridge/lawyer - icon_state = "pda-lawyer" - ttone = "..." - -/obj/item/device/pda/botanist - default_cartridge = /obj/item/weapon/cartridge/service - icon_state = "pda-hydro" - -/obj/item/device/pda/roboticist - default_cartridge = /obj/item/weapon/cartridge/signal/science - icon_state = "pda-robot" - -/obj/item/device/pda/librarian - default_cartridge = /obj/item/weapon/cartridge/service - icon_state = "pda-libb" - desc = "A portable microcomputer by Thinktronic Systems, LTD. This is model is a WGW-11 series e-reader." - note = "Congratulations, your station has chosen the Thinktronic 5290 WGW-11 Series E-reader and Personal Data Assistant!" - message_silent = 1 //Quiet in the library! - news_silent = 0 // Librarian is above the law! (That and alt job title is reporter) - -/obj/item/device/pda/clear - icon_state = "pda-transp" - desc = "A portable microcomputer by Thinktronic Systems, LTD. This is model is a special edition with a transparent case." - note = "Congratulations, you have chosen the Thinktronic 5230 Personal Data Assistant Deluxe Special Max Turbo Limited Edition!" - -/obj/item/device/pda/chef - default_cartridge = /obj/item/weapon/cartridge/service - icon_state = "pda-chef" - -/obj/item/device/pda/bar - default_cartridge = /obj/item/weapon/cartridge/service - icon_state = "pda-bar" - -/obj/item/device/pda/atmos - default_cartridge = /obj/item/weapon/cartridge/atmos - icon_state = "pda-atmo" - -/obj/item/device/pda/chemist - default_cartridge = /obj/item/weapon/cartridge/chemistry - icon_state = "pda-chem" - -/obj/item/device/pda/geneticist - default_cartridge = /obj/item/weapon/cartridge/medical - icon_state = "pda-gene" - - -// Special AI/pAI PDAs that cannot explode. -/obj/item/device/pda/ai - icon_state = "NONE" - ttone = "data" - newstone = "news" - detonate = 0 - - -/obj/item/device/pda/ai/proc/set_name_and_job(newname as text, newjob as text, newrank as null|text) - owner = newname - ownjob = newjob - if(newrank) - ownrank = newrank - else - ownrank = ownjob - name = newname + " (" + ownjob + ")" - -//AI verb and proc for sending PDA messages. -/obj/item/device/pda/ai/verb/cmd_send_pdamesg() - set category = "AI IM" - set name = "Send Message" - set src in usr - if(usr.stat == 2) - to_chat(usr, "You can't send PDA messages because you are dead!") - return - var/list/plist = available_pdas() - if (plist) - var/c = input(usr, "Please select a PDA") as null|anything in sortList(plist) - if (!c) // if the user hasn't selected a PDA file we can't send a message - return - var/selected = plist[c] - create_message(usr, selected, 0) - -/obj/item/device/pda/ai/verb/cmd_toggle_pda_receiver() - set category = "AI IM" - set name = "Toggle Sender/Receiver" - set src in usr - if(usr.stat == 2) - to_chat(usr, "You can't send PDA messages because you are dead!") - return - toff = !toff - to_chat(usr, "PDA sender/receiver toggled [(toff ? "Off" : "On")]!") - -/obj/item/device/pda/ai/verb/cmd_toggle_pda_silent() - set category = "AI IM" - set name = "Toggle Ringer" - set src in usr - if(usr.stat == 2) - to_chat(usr, "You can't send PDA messages because you are dead!") - return - message_silent=!message_silent - to_chat(usr, "PDA ringer toggled [(message_silent ? "Off" : "On")]!") - -/obj/item/device/pda/ai/verb/cmd_show_message_log() - set category = "AI IM" - set name = "Show Message Log" - set src in usr - if(usr.stat == 2) - to_chat(usr, "You can't send PDA messages because you are dead!") - return - var/HTML = "AI PDA Message Log" - for(var/index in tnote) - if(index["sent"]) - HTML += addtext("→ To ", index["owner"],":
", index["message"], "
") - else - HTML += addtext("← From ", index["owner"],":
", index["message"], "
") - HTML +="" - usr << browse(HTML, "window=log;size=400x444;border=1;can_resize=1;can_close=1;can_minimize=0") - - -/obj/item/device/pda/ai/can_use() - return 1 - - -/obj/item/device/pda/ai/attack_self(mob/user as mob) - if ((honkamt > 0) && (prob(60)))//For clown virus. - honkamt-- - playsound(src, 'sound/items/bikehorn.ogg', 30, 1) - return - - -/obj/item/device/pda/ai/pai - ttone = "assist" - -/obj/item/device/pda/ai/shell - spam_proof = TRUE // Since empty shells get a functional PDA. - -// Used for the PDA multicaster, which mirrors messages sent to it to a specific department, -/obj/item/device/pda/multicaster - ownjob = "Relay" - icon_state = "NONE" - ttone = "data" - detonate = 0 - news_silent = 1 - spam_proof = TRUE // Spam messages don't actually work and its difficult to disable these. - var/list/cartridges_to_send_to = list() - -// This is what actually mirrors the message, -/obj/item/device/pda/multicaster/new_message(var/sending_unit, var/sender, var/sender_job, var/message) - if(sender) - var/list/targets = list() - for(var/obj/item/device/pda/pda in PDAs) - if(pda.cartridge && pda.owner && is_type_in_list(pda.cartridge, cartridges_to_send_to)) - targets |= pda - if(targets.len) - for(var/obj/item/device/pda/target in targets) - create_message(target, sender, sender_job, message) - -// This has so much copypasta, -/obj/item/device/pda/multicaster/create_message(var/obj/item/device/pda/P, var/original_sender, var/original_job, var/t) - t = sanitize(t, MAX_MESSAGE_LEN, 0) - t = replace_characters(t, list(""" = "\"")) - if (!t || !istype(P)) - return - - if (isnull(P)||P.toff || toff) - return - - last_text = world.time - var/datum/reception/reception = get_reception(src, P, t) - t = reception.message - - if(reception.message_server && (reception.telecomms_reception & TELECOMMS_RECEPTION_SENDER)) // only send the message if it's stable, - if(reception.telecomms_reception & TELECOMMS_RECEPTION_RECEIVER == 0) // Does our recipient have a broadcaster on their level?, - return - var/send_result = reception.message_server.send_pda_message("[P.owner]","[owner]","[t]") - if (send_result) - return - - P.tnote.Add(list(list("sent" = 0, "owner" = "[owner]", "job" = "[ownjob]", "message" = "[t]", "target" = "\ref[src]"))) - - if(!P.conversations.Find("\ref[src]")) - P.conversations.Add("\ref[src]") - - P.new_message(src, "[original_sender] \[Relayed\]", original_job, t, 0) - - else - return - -/obj/item/device/pda/multicaster/command/New() - ..() - owner = "Command Department" - name = "Command Department (Relay)" - cartridges_to_send_to = command_cartridges - -/obj/item/device/pda/multicaster/security/New() - ..() - owner = "Security Department" - name = "Security Department (Relay)" - cartridges_to_send_to = security_cartridges - -/obj/item/device/pda/multicaster/engineering/New() - ..() - owner = "Engineering Department" - name = "Engineering Department (Relay)" - cartridges_to_send_to = engineering_cartridges - -/obj/item/device/pda/multicaster/medical/New() - ..() - owner = "Medical Department" - name = "Medical Department (Relay)" - cartridges_to_send_to = medical_cartridges - -/obj/item/device/pda/multicaster/research/New() - ..() - owner = "Research Department" - name = "Research Department (Relay)" - cartridges_to_send_to = research_cartridges - -/obj/item/device/pda/multicaster/cargo/New() - ..() - owner = "Cargo Department" - name = "Cargo Department (Relay)" - cartridges_to_send_to = cargo_cartridges - -/obj/item/device/pda/multicaster/civilian/New() - ..() - owner = "Civilian Services Department" - name = "Civilian Services Department (Relay)" - cartridges_to_send_to = civilian_cartridges - -/* - * The Actual PDA - */ - /obj/item/device/pda/New(var/mob/living/carbon/human/H) ..() PDAs += src @@ -492,6 +150,7 @@ var/global/list/obj/item/device/pda/PDAs = list() update_programs() if(default_cartridge) cartridge = new default_cartridge(src) + cartridge.update_programs(src) new /obj/item/weapon/pen(src) pdachoice = isnull(H) ? 1 : (ishuman(H) ? H.pdachoice : 1) switch(pdachoice) @@ -519,19 +178,16 @@ var/global/list/obj/item/device/pda/PDAs = list() log_debug("Invalid switch for PDA, defaulting to old PDA icons. [pdachoice] chosen.") start_program(find_program(/datum/data/pda/app/main_menu)) - /obj/item/device/pda/proc/can_use() - if(!ismob(loc)) - return 0 + return FALSE var/mob/M = loc - if(M.stat || M.restrained() || M.paralysis || M.stunned || M.weakened) - return 0 - if((src in M.contents) || ( istype(loc, /turf) && in_range(src, M) )) - return 1 - else - return 0 + if(M.incapacitated(INCAPACITATION_ALL)) + return FALSE + if(src in M.contents) + return TRUE + return FALSE /obj/item/device/pda/GetAccess() if(id) @@ -549,97 +205,14 @@ var/global/list/obj/item/device/pda/PDAs = list() return /obj/item/device/pda/proc/close(mob/user) - var/datum/nanoui/ui = SSnanoui.get_open_ui(user, src, "main") - ui.close() - SStgui.close_uis(src) -/obj/item/device/pda/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - ui_tick++ - var/datum/nanoui/old_ui = SSnanoui.get_open_ui(user, src, "main") - var/auto_update = 1 - if(!current_app) - return - - if(current_app.update == PDA_APP_NOUPDATE && current_app == lastapp) - auto_update = 0 - if(old_ui && (current_app == lastapp && ui_tick % 5 && current_app.update == PDA_APP_UPDATE_SLOW)) - return - - lastapp = current_app - - var/title = "Personal Data Assistant" - - var/data[0] // This is the data that will be sent to the PDA - - data["owner"] = owner // Who is your daddy... - data["ownjob"] = ownjob // ...and what does he do? - - // update list of shortcuts, only if they changed - if(!shortcut_cache.len) - shortcut_cache = list() - shortcut_cat_order = list() - var/prog_list = programs.Copy() - if(cartridge) - prog_list |= cartridge.programs - - for(var/A in prog_list) - var/datum/data/pda/P = A - - if(P.hidden) - continue - var/list/cat - if(P.category in shortcut_cache) - cat = shortcut_cache[P.category] - else - cat = list() - shortcut_cache[P.category] = cat - shortcut_cat_order += P.category - cat |= list(list(name = P.name, icon = P.icon, notify_icon = P.notify_icon, ref = "\ref[P]")) - - // force the order of a few core categories - shortcut_cat_order = list("General") \ - + sortList(shortcut_cat_order - list("General", "Scanners", "Utilities")) \ - + list("Scanners", "Utilities") - - data["idInserted"] = (id ? 1 : 0) - data["idLink"] = (id ? text("[id.registered_name], [id.assignment]") : "--------") - - data["useRetro"] = retro_mode - - data["cartridge_name"] = cartridge ? cartridge.name : "" - data["stationTime"] = worldtime2stationtime(world.time) - - data["app"] = list() - current_app.update_ui(user, data) - data["app"] |= list( - "name" = current_app.title, - "icon" = current_app.icon, - "template" = current_app.template, - "has_back" = current_app.has_back) - - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - - if(!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "pda.tmpl", title, 520, 400, state = inventory_state) - ui.set_state_key("pda") - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window - ui.open() - // auto update every Master Controller tick - ui.set_auto_update(auto_update) - /obj/item/device/pda/attack_self(mob/user as mob) user.set_machine(src) if(active_uplink_check(user)) return - ui_interact(user) //NanoUI requires this proc tgui_interact(user) return @@ -667,76 +240,6 @@ var/global/list/obj/item/device/pda/PDAs = list() var/datum/data/pda/P = A P.pda = src -/obj/item/device/pda/Topic(href, href_list) - . = ..() - if(.) - return - - var/mob/user = usr - var/datum/nanoui/ui = SSnanoui.get_open_ui(user, src, "main") - var/mob/living/U = usr - if(usr.stat == DEAD) - return 0 - if(!can_use()) //Why reinvent the wheel? There's a proc that does exactly that. - U.unset_machine() - if(ui) - ui.close() - return 0 - - add_fingerprint(U) - U.set_machine(src) - - if(href_list["radiomenu"] && !isnull(cartridge) && !isnull(cartridge.radio)) - cartridge.radio.Topic(href, href_list) - return 1 - - . = 1 - - switch(href_list["choice"]) - if("Home")//Go home, largely replaces the old Return - var/datum/data/pda/app/main_menu/A = find_program(/datum/data/pda/app/main_menu) - if(A) - start_program(A) - if("StartProgram") - if(href_list["program"]) - var/datum/data/pda/app/A = locate(href_list["program"]) - if(A) - start_program(A) - if("Eject")//Ejects the cart, only done from hub. - if(!isnull(cartridge)) - var/turf/T = loc - if(ismob(T)) - T = T.loc - var/obj/item/weapon/cartridge/C = cartridge - C.forceMove(T) - if(scanmode in C.programs) - scanmode = null - if(current_app in C.programs) - start_program(find_program(/datum/data/pda/app/main_menu)) - if(C.radio) - C.radio.hostpda = null - for(var/datum/data/pda/P in notifying_programs) - if(P in C.programs) - P.unnotify() - cartridge = null - update_shortcuts() - if("Authenticate")//Checks for ID - id_check(usr, 1) - if("Retro") - retro_mode = !retro_mode - if("Ringtone") - return set_ringtone() - else - if(current_app) - . = current_app.Topic(href, href_list) - -//EXTRA FUNCTIONS=================================== - if((honkamt > 0) && (prob(60)))//For clown virus. - honkamt-- - playsound(loc, 'sound/items/bikehorn.ogg', 30, 1) - - return // return 1 tells it to refresh the UI in NanoUI - /obj/item/device/pda/update_icon() ..() @@ -895,7 +398,7 @@ var/global/list/obj/item/device/pda/PDAs = list() ai.show_message("Intercepted message from [who]: [t]") P.new_message_from_pda(src, t) - SSnanoui.update_user_uis(U, src) // Update the sending user's PDA UI so that they can see the new message + SStgui.update_user_uis(U, src) // Update the sending user's PDA UI so that they can see the new message else to_chat(U, "ERROR: Messaging server is not responding.") @@ -915,7 +418,7 @@ var/global/list/obj/item/device/pda/PDAs = list() if(L) if(reception_message) to_chat(L,reception_message) - SSnanoui.update_user_uis(L, src) // Update the receiving user's PDA UI so that they can see the new message + SStgui.update_user_uis(L, src) // Update the receiving user's PDA UI so that they can see the new message /obj/item/device/pda/proc/new_news(var/message) new_info(news_silent, newstone, news_silent ? "" : "[bicon(src)] [message]") @@ -924,9 +427,6 @@ var/global/list/obj/item/device/pda/PDAs = list() new_news = 1 update_icon() -/obj/item/device/pda/ai/new_news(var/message) - // Do nothing - /obj/item/device/pda/proc/new_message_from_pda(var/obj/item/device/pda/sending_device, var/message) if (is_jammed(src)) return @@ -940,17 +440,6 @@ var/global/list/obj/item/device/pda/PDAs = list() new_message = 1 update_icon() -/obj/item/device/pda/ai/new_message(var/atom/movable/sending_unit, var/sender, var/sender_job, var/message) - var/track = "" - if(ismob(sending_unit.loc) && isAI(loc)) - track = "(Follow)" - - var/reception_message = "[bicon(src)] Message from [sender] ([sender_job]), \"[message]\" (Reply) [track]" - new_info(message_silent, newstone, reception_message) - - log_pda("(PDA: [sending_unit]) sent \"[message]\" to [name]",usr) - new_message = 1 - /obj/item/device/pda/proc/spam_message(sender, message) var/reception_message = "\icon[src] Message from [sender] (Unknown / spam?), \"[message]\" (Unable to Reply)" new_info(message_silent, ttone, reception_message) @@ -1062,8 +551,9 @@ var/global/list/obj/item/device/pda/PDAs = list() cartridge = C user.drop_item() cartridge.loc = src + cartridge.update_programs(src) + update_shortcuts() to_chat(usr, "You insert [cartridge] into [src].") - SSnanoui.update_uis(src) // update all UIs attached to src if(cartridge.radio) cartridge.radio.hostpda = src @@ -1091,7 +581,7 @@ var/global/list/obj/item/device/pda/PDAs = list() C.loc = src pai = C to_chat(user, "You slot \the [C] into \the [src].") - SSnanoui.update_uis(src) // update all UIs attached to src + SStgui.update_uis(src) // update all UIs attached to src else if(istype(C, /obj/item/weapon/pen)) var/obj/item/weapon/pen/O = locate() in src if(O) @@ -1253,16 +743,6 @@ var/global/list/obj/item/device/pda/PDAs = list() QDEL_NULL(cartridge) return ..() -/obj/item/device/pda/clown/Crossed(atom/movable/AM as mob|obj) //Clown PDA is slippery. - if(AM.is_incorporeal()) - return - if (istype(AM, /mob/living)) - var/mob/living/M = AM - - if(M.slip("the PDA",8) && M.real_name != src.owner && istype(src.cartridge, /obj/item/weapon/cartridge/clown)) - if(src.cartridge.charges < 5) - src.cartridge.charges++ - /obj/item/device/pda/proc/available_pdas() var/list/names = list() var/list/plist = list() @@ -1301,20 +781,20 @@ var/global/list/obj/item/device/pda/PDAs = list() icon = 'icons/obj/pda.dmi' icon_state = "pdabox" - New() - ..() - new /obj/item/device/pda(src) - new /obj/item/device/pda(src) - new /obj/item/device/pda(src) - new /obj/item/device/pda(src) - new /obj/item/weapon/cartridge/head(src) +/obj/item/weapon/storage/box/PDAs/New() + ..() + new /obj/item/device/pda(src) + new /obj/item/device/pda(src) + new /obj/item/device/pda(src) + new /obj/item/device/pda(src) + new /obj/item/weapon/cartridge/head(src) - var/newcart = pick( /obj/item/weapon/cartridge/engineering, - /obj/item/weapon/cartridge/security, - /obj/item/weapon/cartridge/medical, - /obj/item/weapon/cartridge/signal/science, - /obj/item/weapon/cartridge/quartermaster) - new newcart(src) + var/newcart = pick( /obj/item/weapon/cartridge/engineering, + /obj/item/weapon/cartridge/security, + /obj/item/weapon/cartridge/medical, + /obj/item/weapon/cartridge/signal/science, + /obj/item/weapon/cartridge/quartermaster) + new newcart(src) // Pass along the pulse to atoms in contents, largely added so pAIs are vulnerable to EMP /obj/item/device/pda/emp_act(severity) diff --git a/code/modules/pda/pda_subtypes.dm b/code/modules/pda/pda_subtypes.dm new file mode 100644 index 00000000000..800ed029b80 --- /dev/null +++ b/code/modules/pda/pda_subtypes.dm @@ -0,0 +1,282 @@ + +/obj/item/device/pda/medical + default_cartridge = /obj/item/weapon/cartridge/medical + icon_state = "pda-m" + +/obj/item/device/pda/viro + default_cartridge = /obj/item/weapon/cartridge/medical + icon_state = "pda-v" + +/obj/item/device/pda/engineering + default_cartridge = /obj/item/weapon/cartridge/engineering + icon_state = "pda-e" + +/obj/item/device/pda/security + default_cartridge = /obj/item/weapon/cartridge/security + icon_state = "pda-s" + +/obj/item/device/pda/detective + default_cartridge = /obj/item/weapon/cartridge/detective + icon_state = "pda-det" + +/obj/item/device/pda/warden + default_cartridge = /obj/item/weapon/cartridge/security + icon_state = "pda-warden" + +/obj/item/device/pda/janitor + default_cartridge = /obj/item/weapon/cartridge/janitor + icon_state = "pda-j" + ttone = "slip" + +/obj/item/device/pda/science + default_cartridge = /obj/item/weapon/cartridge/signal/science + icon_state = "pda-tox" + ttone = "boom" + +/obj/item/device/pda/clown + default_cartridge = /obj/item/weapon/cartridge/clown + icon_state = "pda-clown" + desc = "A portable microcomputer by Thinktronic Systems, LTD. The surface is coated with polytetrafluoroethylene and banana drippings." + ttone = "honk" + +/obj/item/device/pda/mime + default_cartridge = /obj/item/weapon/cartridge/mime + icon_state = "pda-mime" + message_silent = 1 + news_silent = 1 + ttone = "silence" + newstone = "silence" + +/obj/item/device/pda/heads + default_cartridge = /obj/item/weapon/cartridge/head + icon_state = "pda-h" + news_silent = 1 + +/obj/item/device/pda/heads/hop + default_cartridge = /obj/item/weapon/cartridge/hop + icon_state = "pda-hop" + +/obj/item/device/pda/heads/hos + default_cartridge = /obj/item/weapon/cartridge/hos + icon_state = "pda-hos" + +/obj/item/device/pda/heads/ce + default_cartridge = /obj/item/weapon/cartridge/ce + icon_state = "pda-ce" + +/obj/item/device/pda/heads/cmo + default_cartridge = /obj/item/weapon/cartridge/cmo + icon_state = "pda-cmo" + +/obj/item/device/pda/heads/rd + default_cartridge = /obj/item/weapon/cartridge/rd + icon_state = "pda-rd" + +/obj/item/device/pda/captain + default_cartridge = /obj/item/weapon/cartridge/captain + icon_state = "pda-c" + detonate = 0 + //toff = 1 + +/obj/item/device/pda/ert + default_cartridge = /obj/item/weapon/cartridge/captain + icon_state = "pda-h" + detonate = 0 +// hidden = 1 + +/obj/item/device/pda/cargo + default_cartridge = /obj/item/weapon/cartridge/quartermaster + icon_state = "pda-cargo" + +/obj/item/device/pda/quartermaster + default_cartridge = /obj/item/weapon/cartridge/quartermaster + icon_state = "pda-q" + +/obj/item/device/pda/shaftminer + icon_state = "pda-miner" + default_cartridge = /obj/item/weapon/cartridge/miner + +/obj/item/device/pda/syndicate + default_cartridge = /obj/item/weapon/cartridge/syndicate + icon_state = "pda-syn" +// name = "Military PDA" // Vorestation Edit +// owner = "John Doe" + hidden = 1 + +/obj/item/device/pda/chaplain + default_cartridge = /obj/item/weapon/cartridge/service + icon_state = "pda-holy" + ttone = "holy" + +/obj/item/device/pda/lawyer + default_cartridge = /obj/item/weapon/cartridge/lawyer + icon_state = "pda-lawyer" + ttone = "..." + +/obj/item/device/pda/botanist + default_cartridge = /obj/item/weapon/cartridge/service + icon_state = "pda-hydro" + +/obj/item/device/pda/roboticist + default_cartridge = /obj/item/weapon/cartridge/signal/science + icon_state = "pda-robot" + +/obj/item/device/pda/librarian + default_cartridge = /obj/item/weapon/cartridge/service + icon_state = "pda-libb" + desc = "A portable microcomputer by Thinktronic Systems, LTD. This is model is a WGW-11 series e-reader." + note = "Congratulations, your station has chosen the Thinktronic 5290 WGW-11 Series E-reader and Personal Data Assistant!" + message_silent = 1 //Quiet in the library! + news_silent = 0 // Librarian is above the law! (That and alt job title is reporter) + +/obj/item/device/pda/clear + icon_state = "pda-transp" + desc = "A portable microcomputer by Thinktronic Systems, LTD. This is model is a special edition with a transparent case." + note = "Congratulations, you have chosen the Thinktronic 5230 Personal Data Assistant Deluxe Special Max Turbo Limited Edition!" + +/obj/item/device/pda/chef + default_cartridge = /obj/item/weapon/cartridge/service + icon_state = "pda-chef" + +/obj/item/device/pda/bar + default_cartridge = /obj/item/weapon/cartridge/service + icon_state = "pda-bar" + +/obj/item/device/pda/atmos + default_cartridge = /obj/item/weapon/cartridge/atmos + icon_state = "pda-atmo" + +/obj/item/device/pda/chemist + default_cartridge = /obj/item/weapon/cartridge/chemistry + icon_state = "pda-chem" + +/obj/item/device/pda/geneticist + default_cartridge = /obj/item/weapon/cartridge/medical + icon_state = "pda-gene" + + +// Used for the PDA multicaster, which mirrors messages sent to it to a specific department, +/obj/item/device/pda/multicaster + ownjob = "Relay" + icon_state = "NONE" + ttone = "data" + detonate = 0 + news_silent = 1 + spam_proof = TRUE // Spam messages don't actually work and its difficult to disable these. + var/list/cartridges_to_send_to = list() + +// This is what actually mirrors the message, +/obj/item/device/pda/multicaster/new_message(var/sending_unit, var/sender, var/sender_job, var/message) + if(sender) + var/list/targets = list() + for(var/obj/item/device/pda/pda in PDAs) + if(pda.cartridge && pda.owner && is_type_in_list(pda.cartridge, cartridges_to_send_to)) + targets |= pda + if(targets.len) + for(var/obj/item/device/pda/target in targets) + create_message(target, sender, sender_job, message) + +// This has so much copypasta, +/obj/item/device/pda/multicaster/create_message(var/obj/item/device/pda/P, var/original_sender, var/original_job, var/t) + t = sanitize(t, MAX_MESSAGE_LEN, 0) + t = replace_characters(t, list(""" = "\"")) + if (!t || !istype(P)) + return + + if (isnull(P)||P.toff || toff) + return + + last_text = world.time + var/datum/reception/reception = get_reception(src, P, t) + t = reception.message + + if(reception.message_server && (reception.telecomms_reception & TELECOMMS_RECEPTION_SENDER)) // only send the message if it's stable, + if(reception.telecomms_reception & TELECOMMS_RECEPTION_RECEIVER == 0) // Does our recipient have a broadcaster on their level?, + return + var/send_result = reception.message_server.send_pda_message("[P.owner]","[owner]","[t]") + if (send_result) + return + + P.tnote.Add(list(list("sent" = 0, "owner" = "[owner]", "job" = "[ownjob]", "message" = "[t]", "target" = "\ref[src]"))) + + if(!P.conversations.Find("\ref[src]")) + P.conversations.Add("\ref[src]") + + P.new_message(src, "[original_sender] \[Relayed\]", original_job, t, 0) + + else + return + +/obj/item/device/pda/multicaster/command/New() + ..() + owner = "Command Department" + name = "Command Department (Relay)" + cartridges_to_send_to = command_cartridges + +/obj/item/device/pda/multicaster/security/New() + ..() + owner = "Security Department" + name = "Security Department (Relay)" + cartridges_to_send_to = security_cartridges + +/obj/item/device/pda/multicaster/engineering/New() + ..() + owner = "Engineering Department" + name = "Engineering Department (Relay)" + cartridges_to_send_to = engineering_cartridges + +/obj/item/device/pda/multicaster/medical/New() + ..() + owner = "Medical Department" + name = "Medical Department (Relay)" + cartridges_to_send_to = medical_cartridges + +/obj/item/device/pda/multicaster/research/New() + ..() + owner = "Research Department" + name = "Research Department (Relay)" + cartridges_to_send_to = research_cartridges + +/obj/item/device/pda/multicaster/cargo/New() + ..() + owner = "Cargo Department" + name = "Cargo Department (Relay)" + cartridges_to_send_to = cargo_cartridges + +/obj/item/device/pda/multicaster/civilian/New() + ..() + owner = "Civilian Services Department" + name = "Civilian Services Department (Relay)" + cartridges_to_send_to = civilian_cartridges + +/obj/item/device/pda/clown/Crossed(atom/movable/AM as mob|obj) //Clown PDA is slippery. + if(AM.is_incorporeal()) + return + if (istype(AM, /mob/living)) + var/mob/living/M = AM + + if(M.slip("the PDA",8) && M.real_name != src.owner && istype(src.cartridge, /obj/item/weapon/cartridge/clown)) + if(src.cartridge.charges < 5) + src.cartridge.charges++ + +//Some spare PDAs in a box +/obj/item/weapon/storage/box/PDAs + name = "box of spare PDAs" + desc = "A box of spare PDA microcomputers." + icon = 'icons/obj/pda.dmi' + icon_state = "pdabox" + +/obj/item/weapon/storage/box/PDAs/New() + ..() + new /obj/item/device/pda(src) + new /obj/item/device/pda(src) + new /obj/item/device/pda(src) + new /obj/item/device/pda(src) + new /obj/item/weapon/cartridge/head(src) + + var/newcart = pick( /obj/item/weapon/cartridge/engineering, + /obj/item/weapon/cartridge/security, + /obj/item/weapon/cartridge/medical, + /obj/item/weapon/cartridge/signal/science, + /obj/item/weapon/cartridge/quartermaster) + new newcart(src) diff --git a/code/modules/pda/pda_tgui.dm b/code/modules/pda/pda_tgui.dm index 532c31fc80f..e55a49ed444 100644 --- a/code/modules/pda/pda_tgui.dm +++ b/code/modules/pda/pda_tgui.dm @@ -2,6 +2,11 @@ /obj/item/device/pda/tgui_state(mob/user) return GLOB.tgui_inventory_state +/obj/item/device/pda/tgui_status(mob/user, datum/tgui_state/state) + . = ..() + if(!can_use()) + . = min(., STATUS_UPDATE) + /obj/item/device/pda/tgui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) @@ -47,13 +52,142 @@ data["useRetro"] = retro_mode data["cartridge_name"] = cartridge ? cartridge.name : "" - data["stationTime"] = worldtime2stationtime(world.time) + data["stationTime"] = stationtime2text() //worldtime2stationtime(world.time) // Aaa which fucking one is canonical there's SO MANY data["app"] = list( "name" = current_app.title, "icon" = current_app.icon, "template" = current_app.template, "has_back" = current_app.has_back) + current_app.update_ui(user, data) - return data \ No newline at end of file + return data + +/obj/item/device/pda/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + + if(!can_use()) + usr.unset_machine() + if(ui) + ui.close() + return FALSE + + add_fingerprint(usr) + usr.set_machine(src) + + . = TRUE + switch(action) + if("Home") //Go home, largely replaces the old Return + var/datum/data/pda/app/main_menu/A = find_program(/datum/data/pda/app/main_menu) + if(A) + start_program(A) + if("StartProgram") + if(params["program"]) + var/datum/data/pda/app/A = locate(params["program"]) + if(A) + start_program(A) + if("Eject")//Ejects the cart, only done from hub. + if(!isnull(cartridge)) + var/turf/T = loc + if(ismob(T)) + T = T.loc + var/obj/item/weapon/cartridge/C = cartridge + C.forceMove(T) + if(scanmode in C.programs) + scanmode = null + if(current_app in C.programs) + start_program(find_program(/datum/data/pda/app/main_menu)) + if(C.radio) + C.radio.hostpda = null + for(var/datum/data/pda/P in notifying_programs) + if(P in C.programs) + P.unnotify() + cartridge = null + update_shortcuts() + if("Authenticate")//Checks for ID + id_check(usr, 1) + if("Retro") + retro_mode = !retro_mode + if("Ringtone") + return set_ringtone() + else + if(current_app) + . = current_app.tgui_act(action, params, ui, state) + + if((honkamt > 0) && (prob(60)))//For clown virus. + honkamt-- + playsound(loc, 'sound/items/bikehorn.ogg', 30, 1) + + +// Reference only, TODO: Remove +/obj/item/device/pda/Topic(href, href_list) + . = ..() + if(.) + return + + var/mob/user = usr + var/datum/nanoui/ui = SSnanoui.get_open_ui(user, src, "main") + var/mob/living/U = usr + if(usr.stat == DEAD) + return 0 + if(!can_use()) //Why reinvent the wheel? There's a proc that does exactly that. + U.unset_machine() + if(ui) + ui.close() + return 0 + + add_fingerprint(U) + U.set_machine(src) + + if(href_list["radiomenu"] && !isnull(cartridge) && !isnull(cartridge.radio)) + cartridge.radio.Topic(href, href_list) + return 1 + + . = 1 + + switch(href_list["choice"]) + if("Home")//Go home, largely replaces the old Return + var/datum/data/pda/app/main_menu/A = find_program(/datum/data/pda/app/main_menu) + if(A) + start_program(A) + if("StartProgram") + if(href_list["program"]) + var/datum/data/pda/app/A = locate(href_list["program"]) + if(A) + start_program(A) + if("Eject")//Ejects the cart, only done from hub. + if(!isnull(cartridge)) + var/turf/T = loc + if(ismob(T)) + T = T.loc + var/obj/item/weapon/cartridge/C = cartridge + C.forceMove(T) + if(scanmode in C.programs) + scanmode = null + if(current_app in C.programs) + start_program(find_program(/datum/data/pda/app/main_menu)) + if(C.radio) + C.radio.hostpda = null + for(var/datum/data/pda/P in notifying_programs) + if(P in C.programs) + P.unnotify() + cartridge = null + update_shortcuts() + if("Authenticate")//Checks for ID + id_check(usr, 1) + if("Retro") + retro_mode = !retro_mode + if("Ringtone") + return set_ringtone() + else + if(current_app) + . = current_app.Topic(href, href_list) + +//EXTRA FUNCTIONS=================================== + if((honkamt > 0) && (prob(60)))//For clown virus. + honkamt-- + playsound(loc, 'sound/items/bikehorn.ogg', 30, 1) + + return // return 1 tells it to refresh the UI in NanoUI diff --git a/code/modules/pda/radio.dm b/code/modules/pda/radio.dm index 133798e4b18..44a42c01232 100644 --- a/code/modules/pda/radio.dm +++ b/code/modules/pda/radio.dm @@ -5,122 +5,170 @@ icon_state = "power_mod" var/obj/item/device/pda/hostpda = null - var/on = 0 //Are we currently active?? - var/menu_message = "" - - New() - ..() - if (istype(loc.loc, /obj/item/device/pda)) - hostpda = loc.loc - - proc/post_signal(var/freq, var/key, var/value, var/key2, var/value2, var/key3, var/value3, s_filter) - - //to_world("Post: [freq]: [key]=[value], [key2]=[value2]") - var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq) - - if(!frequency) return - - var/datum/signal/signal = new() - signal.source = src - signal.transmission_method = TRANSMISSION_RADIO - signal.data[key] = value - if(key2) - signal.data[key2] = value2 - if(key3) - signal.data[key3] = value3 - - frequency.post_signal(src, signal, radio_filter = s_filter) - - return - - proc/generate_menu() - -/obj/item/radio/integrated/beepsky var/list/botlist = null // list of bots - var/mob/living/bot/secbot/active // the active bot; if null, show bot list + var/mob/living/bot/active // the active bot; if null, show bot list var/list/botstatus // the status signal sent by the bot + + var/bot_type //The type of bot it is. + var/bot_filter //Determines which radio filter to use. var/control_freq = BOT_FREQ - // create a new QM cartridge, and register to receive bot control & beacon message - New() - ..() + var/on = 0 //Are we currently active?? + var/menu_message = "" + +/obj/item/radio/integrated/New() + ..() + if(istype(loc.loc, /obj/item/device/pda)) + hostpda = loc.loc + if(bot_filter) spawn(5) - if(radio_controller) - radio_controller.add_object(src, control_freq, radio_filter = RADIO_SECBOT) + add_to_radio(bot_filter) - // receive radio signals - // can detect bot status signals - // create/populate list as they are recvd - - receive_signal(datum/signal/signal) -// var/obj/item/device/pda/P = src.loc - - /* - to_world("recvd:[P] : [signal.source]") - for(var/d in signal.data) - to_world("- [d] = [signal.data[d]]") - */ - if (signal.data["type"] == "secbot") - if(!botlist) - botlist = new() - - if(!(signal.source in botlist)) - botlist += signal.source - - if(active == signal.source) - var/list/b = signal.data - botstatus = b.Copy() - -// if (istype(P)) P.updateSelfDialog() - - Topic(href, href_list) - ..() - var/obj/item/device/pda/PDA = src.hostpda - - switch(href_list["op"]) - - if("control") - active = locate(href_list["bot"]) - post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT) - - if("scanbots") // find all bots - botlist = null - post_signal(control_freq, "command", "bot_status", s_filter = RADIO_SECBOT) - - if("botlist") - active = null - - if("stop", "go") - post_signal(control_freq, "command", href_list["op"], "active", active, s_filter = RADIO_SECBOT) - post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT) - - if("summon") - post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(PDA) , s_filter = RADIO_SECBOT) - post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT) - - -/obj/item/radio/integrated/beepsky/Destroy() +/obj/item/radio/integrated/Destroy() if(radio_controller) radio_controller.remove_object(src, control_freq) + hostpda = null return ..() +/obj/item/radio/integrated/proc/post_signal(var/freq, var/key, var/value, var/key2, var/value2, var/key3, var/value3, s_filter) + + //to_world("Post: [freq]: [key]=[value], [key2]=[value2]") + var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq) + + if(!frequency) + return + + var/datum/signal/signal = new() + signal.source = src + signal.transmission_method = TRANSMISSION_RADIO + signal.data[key] = value + if(key2) + signal.data[key2] = value2 + if(key3) + signal.data[key3] = value3 + + frequency.post_signal(src, signal, radio_filter = s_filter) + +/obj/item/radio/integrated/Topic(href, href_list) + ..() + switch(href_list["op"]) + if("control") + active = locate(href_list["bot"]) + spawn(0) + post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) + + if("scanbots") // find all bots + botlist = null + spawn(0) + post_signal(control_freq, "command", "bot_status", s_filter = bot_filter) + + if("botlist") + active = null + + if("stop", "go", "home") + spawn(0) + post_signal(control_freq, "command", href_list["op"], "active", active, s_filter = bot_filter) + post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) + + if("summon") + spawn(0) + post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(hostpda), "useraccess", hostpda.GetAccess(), "user", usr, s_filter = bot_filter) + post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) + +/obj/item/radio/integrated/receive_signal(datum/signal/signal) + if(bot_type && istype(signal.source, /mob/living/bot) && signal.data["type"] == bot_type) + if(!botlist) + botlist = new() + + botlist |= signal.source + + if(active == signal.source) + var/list/b = signal.data + botstatus = b.Copy() + +/obj/item/radio/integrated/proc/add_to_radio(bot_filter) //Master filter control for bots. Must be placed in the bot's local New() to support map spawned bots. + if(radio_controller) + radio_controller.add_object(src, control_freq, radio_filter = bot_filter) + +/obj/item/radio/integrated/beepsky + bot_filter = RADIO_SECBOT + bot_type = "secbot" + +/obj/item/radio/integrated/mule + bot_filter = RADIO_MULEBOT + bot_type = "mulebot" + +/obj/item/radio/integrated/mule/proc/GetBeaconList() + var/list/beaconlist = list() + for(var/obj/machinery/navbeacon/N in navbeacons) + if(!N.codes["delivery"]) + continue + beaconlist.Add(N.location) + beaconlist[N.location] = N + return beaconlist + +/obj/item/radio/integrated/mule/Topic(href, href_list) + ..() + switch(href_list["op"]) + if("start") + spawn(0) + post_signal(control_freq, "command", "start", "active", active, s_filter = RADIO_MULEBOT) + + if("unload") + spawn(0) + post_signal(control_freq, "command", "unload", "active", active, s_filter = RADIO_MULEBOT) + + if("setdest") + var/dest + var/list/beaconlist = GetBeaconList() + if(LAZYLEN(beaconlist)) + dest = input("Select Bot Destination", "Mulebot [active.suffix] Interlink", active.target) as null|anything in beaconlist + else + alert("No destination beacons available.") + if(dest) + spawn(0) + post_signal(control_freq, "command", "target", "active", active, "destination", dest, s_filter = RADIO_MULEBOT) + + if("retoff") + spawn(0) + post_signal(control_freq, "command", "autoret", "active", active, "value", 0, s_filter = RADIO_MULEBOT) + + if("reton") + spawn(0) + post_signal(control_freq, "command", "autoret", "active", active, "value", 1, s_filter = RADIO_MULEBOT) + + if("pickoff") + spawn(0) + post_signal(control_freq, "command", "autopick", "active", active, "value", 0, s_filter = RADIO_MULEBOT) + + if("pickon") + spawn(0) + post_signal(control_freq, "command", "autopick", "active", active, "value", 1, s_filter = RADIO_MULEBOT) + + spawn(10) + post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_MULEBOT) + /* * Radio Cartridge, essentially a signaler. */ - - /obj/item/radio/integrated/signal var/frequency = 1457 var/code = 30.0 var/last_transmission var/datum/radio_frequency/radio_connection +/obj/item/radio/integrated/signal/Destroy() + if(radio_controller) + radio_controller.remove_object(src, frequency) + radio_connection = null + return ..() + /obj/item/radio/integrated/signal/Initialize() if(!radio_controller) return - if (src.frequency < PUBLIC_LOW_FREQ || src.frequency > PUBLIC_HIGH_FREQ) + if(src.frequency < PUBLIC_LOW_FREQ || src.frequency > PUBLIC_HIGH_FREQ) src.frequency = sanitize_frequency(src.frequency) set_frequency(frequency) @@ -131,7 +179,6 @@ radio_connection = radio_controller.add_object(src, frequency) /obj/item/radio/integrated/signal/proc/send_signal(message="ACTIVATE") - if(last_transmission && world.time < (last_transmission + 5)) return last_transmission = world.time @@ -145,9 +192,5 @@ signal.encryption = code signal.data["message"] = message - radio_connection.post_signal(src, signal) - -/obj/item/radio/integrated/signal/Destroy() - if(radio_controller) - radio_controller.remove_object(src, frequency) - return ..() + spawn(0) + radio_connection.post_signal(src, signal) diff --git a/code/modules/pda/utilities.dm b/code/modules/pda/utilities.dm index dee706b88af..be8bb8f4445 100644 --- a/code/modules/pda/utilities.dm +++ b/code/modules/pda/utilities.dm @@ -43,22 +43,28 @@ /datum/data/pda/utility/scanmode/medical/scan_mob(mob/living/C as mob, mob/living/user as mob) C.visible_message("[user] has analyzed [C]'s vitals!") - user.show_message("Analyzing Results for [C]:") - user.show_message("\t Overall Status: [C.stat > 1 ? "dead" : "[C.health]% healthy"]", 1) - user.show_message("\t Damage Specifics: [C.getOxyLoss() > 50 ? "" : ""][C.getOxyLoss()]-[C.getToxLoss() > 50 ? "" : ""][C.getToxLoss()]-[C.getFireLoss() > 50 ? "" : ""][C.getFireLoss()]-[C.getBruteLoss() > 50 ? "" : ""][C.getBruteLoss()]", 1) - user.show_message("\t Key: Suffocation/Toxin/Burns/Brute", 1) - user.show_message("\t Body Temperature: [C.bodytemperature-T0C]°C ([C.bodytemperature*1.8-459.67]°F)", 1) + user.show_message("Analyzing Results for [C]:") + user.show_message(" Overall Status: [C.stat > 1 ? "dead" : "[C.health - C.halloss]% healthy"]", 1) + user.show_message(text(" Damage Specifics: []-[]-[]-[]", + (C.getOxyLoss() > 50) ? "warning" : "", C.getOxyLoss(), + (C.getToxLoss() > 50) ? "warning" : "", C.getToxLoss(), + (C.getFireLoss() > 50) ? "warning" : "", C.getFireLoss(), + (C.getBruteLoss() > 50) ? "warning" : "", C.getBruteLoss() + ), 1) + user.show_message(" Key: Suffocation/Toxin/Burns/Brute", 1) + user.show_message(" Body Temperature: [C.bodytemperature-T0C]°C ([C.bodytemperature*1.8-459.67]°F)", 1) if(C.tod && (C.stat == DEAD || (C.status_flags & FAKEDEATH))) - user.show_message("\t Time of Death: [C.tod]") + user.show_message(" Time of Death: [C.tod]") if(istype(C, /mob/living/carbon/human)) var/mob/living/carbon/human/H = C var/list/damaged = H.get_damaged_organs(1,1) - user.show_message("Localized Damage, Brute/Burn:",1) + user.show_message("Localized Damage, Brute/Burn:",1) if(length(damaged)>0) for(var/obj/item/organ/external/org in damaged) - user.show_message("\t [capitalize(org.name)]: [org.brute_dam > 0 ? "[org.brute_dam]" : "0"]-[org.burn_dam > 0 ? "[org.burn_dam]" : "0"]", 1) + user.show_message(text(" []: []-[]", + capitalize(org.name), (org.brute_dam > 0) ? "warning" : "notice", org.brute_dam, (org.burn_dam > 0) ? "warning" : "notice", org.burn_dam),1) else - user.show_message("\t Limbs are OK.",1) + user.show_message(" Limbs are OK.",1) /datum/data/pda/utility/scanmode/dna base_name = "DNA Scanner" @@ -118,32 +124,10 @@ /datum/data/pda/utility/scanmode/gas base_name = "Gas Scanner" - icon = "tachometer" + icon = "tachometer-alt" /datum/data/pda/utility/scanmode/gas/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob) - // if(istype(A, /obj/item/tank)) - // var/obj/item/tank/T = A - // pda.atmosanalyzer_scan(T.air_contents, user, T) - // else if(istype(A, /obj/machinery/portable_atmospherics)) - // var/obj/machinery/portable_atmospherics/T = A - // pda.atmosanalyzer_scan(T.air_contents, user, T) - // else if(istype(A, /obj/machinery/atmospherics/pipe)) - // var/obj/machinery/atmospherics/pipe/T = A - // pda.atmosanalyzer_scan(T.parent.air, user, T) - // else if(istype(A, /obj/machinery/power/rad_collector)) - // var/obj/machinery/power/rad_collector/T = A - // if(T.P) - // pda.atmosanalyzer_scan(T.P.air_contents, user, T) - // else if(istype(A, /obj/item/flamethrower)) - // var/obj/item/flamethrower/T = A - // if(T.ptank) - // pda.atmosanalyzer_scan(T.ptank.air_contents, user, T) - // else if(istype(A, /obj/machinery/portable_atmospherics/scrubber/huge)) - // var/obj/machinery/portable_atmospherics/scrubber/huge/T = A - // pda.atmosanalyzer_scan(T.air_contents, user, T) - // else if(istype(A, /obj/machinery/atmospherics/unary/tank)) - // var/obj/machinery/atmospherics/unary/tank/T = A - // pda.atmosanalyzer_scan(T.air_contents, user, T) + pda.analyze_gases(A, user) /datum/data/pda/utility/scanmode/notes base_name = "Note Scanner" diff --git a/nano/js/nano_state_pda.js b/nano/js/nano_state_pda.js deleted file mode 100644 index a27da2e1c12..00000000000 --- a/nano/js/nano_state_pda.js +++ /dev/null @@ -1,51 +0,0 @@ -NanoStatePDAClass.inheritsFrom(NanoStateClass); -var NanoStatePDA = new NanoStatePDAClass(); - -function NanoStatePDAClass() { - this.key = 'pda'; - this.key = this.key.toLowerCase(); - this.current_template = ""; - - NanoStateManager.addState(this); -} - -NanoStatePDAClass.prototype.onUpdate = function(data) { - NanoStateClass.prototype.onUpdate.call(this, data); - var state = this; - - try { - if(data['data']['app'] != null) { - var template = data['data']['app']['template']; - if(template != null && template != state.current_template) { - var templateMarkup = nanouiTemplateBundle()[template + ".tmpl"]; - if (templateMarkup) { - templateMarkup += '
'; - - try { - NanoTemplate.addTemplate('app', templateMarkup); - NanoTemplate.resetTemplate('app'); - $("#uiApp").html(NanoTemplate.parse('app', data)); - state.current_template = template; - - if(data['config']['status'] == 2) { - $('#uiApp .linkActive').addClass('linkPending'); - $('#uiApp .linkActive').oneTime(400, 'linkPending', function () { - $('#uiApp .linkActive').removeClass('linkPending inactive'); - }); - } - } catch(error) { - reportError('ERROR: An error occurred while loading the PDA App UI: ' + error.message); - return; - } - } - } else { - if (NanoTemplate.templateExists('app')) { - $("#uiApp").html(NanoTemplate.parse('app', data)); - } - } - } - } catch(error) { - reportError('ERROR: An error occurred while rendering the PDA App UI: ' + error.message); - return; - } -} \ No newline at end of file diff --git a/nano/templates/pda.tmpl b/nano/templates/pda.tmpl deleted file mode 100644 index 61579d0fb6d..00000000000 --- a/nano/templates/pda.tmpl +++ /dev/null @@ -1,156 +0,0 @@ - -{{if data.useRetro}} - - - -{{/if}} -{{if data.owner}} -
-
- {{if data.idInserted}} - {{:helper.link(data.idLink, 'eject', {'choice' : "Authenticate"}, null, 'pdalink fixedLeftWide')}} - {{/if}} - {{if data.cartridge_name}} - {{:helper.link(data.cartridge_name, 'eject', {'choice' : "Eject"}, null, 'pdalink fixedLeftWidest')}} - {{/if}} - {{:helper.link('Toggle R.E.T.R.O. mode', 'gear', {'choice': "Retro"}, null, 'pdalink fixedLeftWide')}} -
-
- {{:data.stationTime}} -
-
- - {{if data.app}} -

 {{:data.app.name}}

-
-
 
- {{/if}} - -
- {{:helper.link("", 'back', {'choice' : "Back"}, data.app.has_back ? null : 'disabled', 'link pdaFooterButton')}} - {{:helper.link("", 'home', {'choice' : "Home"}, data.app.is_home ? 'disabled' : null, 'link pdaFooterButton')}} -
-{{else}} -
-






No Owner information found, please swipe ID -
-{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_atmos_scan.tmpl b/nano/templates/pda_atmos_scan.tmpl deleted file mode 100644 index 57f0a356a16..00000000000 --- a/nano/templates/pda_atmos_scan.tmpl +++ /dev/null @@ -1,60 +0,0 @@ - -
-
- {{if data.aircontents.reading == 1}} -
- Pressure: -
-
- {{:helper.string('{1} kPa', data.aircontents.pressure < 80 || data.aircontents.pressure > 120 ? 'bad' : data.aircontents.pressure < 95 || data.aircontents.pressure > 110 ? 'average' : 'good', helper.smoothRound(data.aircontents.pressure, 1))}} -
-
- Temperature: -
-
- {{:helper.string('{1} °C', data.aircontents.temp < 5 || data.aircontents.temp > 35 ? 'bad' : data.aircontents.temp < 15 || data.aircontents.temp > 25 ? 'average' : 'good' , helper.smoothRound(data.aircontents.temp, 1))}} -
-
-
- Oxygen: -
-
- {{:helper.string('{1}%', data.aircontents.oxygen < 17 ? 'bad' : data.aircontents.oxygen < 19 ? 'average' : 'good', helper.smoothRound(data.aircontents.oxygen, 1))}} -
-
- Nitrogen: -
-
- {{:helper.string('{1}%', data.aircontents.nitrogen > 82 ? 'bad' : data.aircontents.nitrogen > 80 ? 'average' : 'good', helper.smoothRound(data.aircontents.nitrogen, 1))}} -
-
- Carbon Dioxide: -
-
- {{:helper.string('{1}%', data.aircontents.carbon_dioxide > 5 ? 'bad' : 'good', helper.smoothRound(data.aircontents.carbon_dioxide, 1))}} -
-
- Plasma: -
-
- {{:helper.string('{1}%', data.aircontents.plasma > 0 ? 'bad' : 'good', helper.smoothRound(data.aircontents.plasma, 1))}} - -
- {{if data.aircontents.other > 0}} -
- Unknown: -
-
- {{:helper.smoothRound(data.aircontents.other, 1)}}% -
- {{/if}} - {{else}} -
- Unable to get air reading -
- {{/if}} -
-
\ No newline at end of file diff --git a/nano/templates/pda_janitor.tmpl b/nano/templates/pda_janitor.tmpl deleted file mode 100644 index 864692d8a04..00000000000 --- a/nano/templates/pda_janitor.tmpl +++ /dev/null @@ -1,66 +0,0 @@ -
-
- Current Location: - {{if data.janitor.user_loc.x == 0}} - Unknown - {{else}} - {{:data.janitor.user_loc.x}} / {{:data.janitor.user_loc.y}} - {{/if}} -
-
- {{if data.janitor.mops}} - Mop Locations: -
    - {{for data.janitor.mops}} -
  • - ({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Status: {{:value.status}} -
  • - {{/for}} -
- {{else}} - Unable to locate Mops - {{/if}} -
-
- {{if data.janitor.buckets}} - Mop Bucket Locations: -
    - {{for data.janitor.buckets}} -
  • - ({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Capacity: {{:value.volume}}/{{:value.max_volume}} -
  • - {{/for}} -
- {{else}} - Unable to locate Mop Buckets - {{/if}} -
-
- {{if data.janitor.cleanbots}} - Cleanbot Locations: -
    - {{for data.janitor.cleanbots}} -
  • - ({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Status: {{:value.status}} -
  • - {{/for}} -
- {{else}} - Unable to locate Cleanbots - {{/if}} -
-
- {{if data.janitor.carts}} - Janitorial Cart Locations: -
    - {{for data.janitor.carts}} -
  • - ({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Water Level: {{:value.volume}}/{{:value.max_volume}} -
  • - {{/for}} -
- {{else}} - Unable to locate Janitorial Carts - {{/if}} -
-
diff --git a/nano/templates/pda_main_menu.tmpl b/nano/templates/pda_main_menu.tmpl deleted file mode 100644 index 692cdb7039d..00000000000 --- a/nano/templates/pda_main_menu.tmpl +++ /dev/null @@ -1,76 +0,0 @@ - - - - -
-
- Owner: -
-
- {{:data.owner}}, {{:data.ownjob}} -
-
-
-
- ID: -
-
- {{:helper.link('Update PDA Info', 'refresh', {'choice' : "UpdateInfo"}, data.idInserted ? null : 'disabled', 'pdalink fixedLeftWide')}} -
-
- -
-

Functions

-
-{{for data.categories : cat : i}} - -{{/for}} - -{{if data.pai}} -
-
- PAI Utilities: -
-
- {{:helper.link('Configuration', 'gear', {'choice' : "pai", 'option' : "1"}, null, 'pdalink fixedLeft')}} - {{:helper.link('Eject pAI', 'eject', {'choice' : "pai", 'option' : "2"}, null, 'pdalink fixedLeft')}} -
-
-{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_manifest.tmpl b/nano/templates/pda_manifest.tmpl deleted file mode 100644 index ef9e91a088f..00000000000 --- a/nano/templates/pda_manifest.tmpl +++ /dev/null @@ -1,96 +0,0 @@ - -
-
- {{if data.manifest.heads}} - - {{for data.manifest["heads"]}} - {{if value.rank == "Captain"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.sec}} - - {{for data.manifest["sec"]}} - {{if value.rank == "Head of Security"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.eng}} - - {{for data.manifest["eng"]}} - {{if value.rank == "Chief Engineer"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.med}} - - {{for data.manifest["med"]}} - {{if value.rank == "Chief Medical Officer"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.sci}} - - {{for data.manifest["sci"]}} - {{if value.rank == "Research Director"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.ser}} - - {{for data.manifest["ser"]}} - {{if value.rank == "Head of Personnel"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.sup}} - - {{for data.manifest["sup"]}} - {{if value.rank == "Head of Personnel"}} - - {{else value.rank == "Quartermaster"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.civ}} - - {{for data.manifest["civ"]}} - {{if value.rank == "Head of Personnel"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.misc}} - - {{for data.manifest["misc"]}} - - {{/for}} - {{/if}} -
Command
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Security
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Engineering
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Medical
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Science
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Service
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Supply
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Civilian
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Misc
{{:value.name}}{{:value.rank}}{{:value.active}}
-
\ No newline at end of file diff --git a/nano/templates/pda_medical.tmpl b/nano/templates/pda_medical.tmpl deleted file mode 100644 index 777fb91f4b8..00000000000 --- a/nano/templates/pda_medical.tmpl +++ /dev/null @@ -1,54 +0,0 @@ -{{if !data.records}} -
-
Select a record:
-
- {{for data.recordsList}} -
- {{:helper.link(value.Name, 'user', {'choice' : "Records", 'target' : value.ref}, null, 'pdalink fixedLeftWidest')}} -
- {{empty}} -
- No records found. -
- {{/for}} -{{else}} -
-
-
- {{if data.records.general}} - Name: {{:data.records.general.name}}
- Sex: {{:data.records.general.sex}}
- Species: {{:data.records.general.species}}
- Age: {{:data.records.general.age}}
- Rank: {{:data.records.general.rank}}
- Fingerprint: {{:data.records.general.fingerprint}}
- Physical Status: {{:data.records.general.p_stat}}
- Mental Status: {{:data.records.general.m_stat}}

- {{else}} - - General Record Lost!

-
- {{/if}} - {{if data.records.medical}} -
-
Medical Data:
-
- Blood Type: {{:data.records.medical.b_type}}

- Minor Disabilities: {{:data.records.medical.mi_dis}}
- Details: {{:data.records.medical.mi_dis_d}}

- Major Disabilities: {{:data.records.medical.ma_dis}}
- Details: {{:data.records.medical.ma_dis_d}}

- Allergies: {{:data.records.medical.alg}}
- Details: {{:data.records.medical.alg_d}}

- Current Disease: {{:data.records.medical.cdi}}
- Details: {{:data.records.medical.alg_d}}

- Important Notes: {{:data.records.medical.notes}} - {{else}} - - Medical Record Lost! - - {{/if}} -
-
-
-{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_messenger.tmpl b/nano/templates/pda_messenger.tmpl deleted file mode 100644 index 4871934e4e9..00000000000 --- a/nano/templates/pda_messenger.tmpl +++ /dev/null @@ -1,90 +0,0 @@ - -{{if data.active_conversation}} -
-
- Messenger Functions: -
-
- {{:helper.link('Delete Conversation', 'trash', {'choice' : "Clear", 'option' : "Convo"}, null, 'pdalink fixedLeftWide')}} - {{:helper.link(data.auto_scroll ? 'Autoscroll: On' : 'Autoscroll: Off', 'level-down', {'choice' : "Autoscroll"}, null, 'pdalink fixedLeftWide')}} -
-
-
-
-

Conversation with: {{:data.convo_name}} ({{:data.convo_job}})

-
-
-
- {{for data.messages}} - {{if data.active_conversation == value.target}} - {{if value.sent==0}} - Them: {{:value.message}}
- {{else}} - You: {{:value.message}}
- {{/if}} - {{/if}} - {{/for}} -
-
-
- {{:helper.link('Reply', 'comment', {'choice' : "Message", 'target': data.active_conversation}, null, 'pdalink fixedLeftWidest')}} - -{{else}} -
-
- Messenger Functions: -
-
- {{:helper.link(data.silent==1 ? 'Ringer: Off' : 'Ringer: On', data.silent==1 ? 'volume-off' : 'volume-up', {'choice' : "Toggle Ringer"}, null, 'pdalink fixedLeftWide')}} - {{:helper.link(data.toff==1 ? 'Messenger: Off' : 'Messenger: On',data.toff==1 ? 'close':'check', {'choice' : "Toggle Messenger"}, null, 'pdalink fixedLeftWide')}} - {{:helper.link('Set Ringtone', 'bell-o', {'choice' : "Ringtone"}, null, 'pdalink fixedLeftWide')}} - {{:helper.link('Delete all Conversations', 'trash', {'choice' : "Clear", 'option' : "All"}, null, 'pdalink fixedLeftWider')}} -
-
- {{if data.toff == 0}} -
- {{if data.charges}} -
- {{:data.charges}} charges left. -

-
- {{/if}} - - {{if !data.convopdas.length && !data.pdas.length}} - No other PDAS located - {{else}} -

Current Conversations

- {{for data.convopdas}} -
- {{:helper.link(value.Name, 'arrow-circle-down', {'choice' : "Select Conversation", 'convo' : value.Reference } , null, 'pdalink')}} - {{if data.charges}} - {{for data.plugins : plugin : i}} - {{:helper.link(plugin.name, plugin.icon, {'choice' : "Messenger Plugin", 'plugin' : plugin.ref, 'target' : value.Reference}, null, 'pdalink fixedLeft')}} - {{/for}} - {{/if}} -
- {{/for}} -

Other PDAs

- {{for data.pdas}} -
- {{:helper.link(value.Name, 'arrow-circle-down', {'choice' : "Message", 'target' : value.Reference}, null, 'pdalink')}} - {{if data.charges}} - {{for data.plugins : plugin : i}} - {{:helper.link(plugin.name, plugin.icon, {'choice' : "Messenger Plugin", 'plugin' : plugin.ref, 'target' : value.Reference}, null, 'pdalink fixedLeft')}} - {{/for}} - {{/if}} -
- {{/for}} - {{/if}} - {{/if}} -{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_mob_hunt.tmpl b/nano/templates/pda_mob_hunt.tmpl deleted file mode 100644 index dde4ab82a5c..00000000000 --- a/nano/templates/pda_mob_hunt.tmpl +++ /dev/null @@ -1,91 +0,0 @@ -
-
- - - - {{if data.connected}} - - - {{else}} - - - {{/if}} - -
- Connection Status: - - Connected - - {{:helper.link('Disconnect', 'sign-out', {'choice': 'Disconnect'})}} - - No Connection - - {{:helper.link('Connect', 'sign-in', {'choice': 'Reconnect'})}} -
-
-
-
-
My Collection:
-{{if data.no_collection}} -
-
- Your collection is empty! Go capture some Nano-Mobs! -
-
-
- Wild mobs captured: {{:data.wild_captures}} -{{else}} -
-
-
- {{if data.entry}} - {{if data.entry.nickname}} - Name: {{:data.entry.nickname}}
- {{/if}} - Species: {{:data.entry.real_name}}
- Level: {{:data.entry.level}}
- Primary Type: {{:data.entry.type1}}
- {{if data.entry.type2}} - Secondary Type: {{:data.entry.type2}}
- {{/if}} - {{if data.entry.sprite}} - - {{else}} - Mob Image Missing! - {{/if}} - {{else}} - - Mob Data Missing!

-
- {{/if}} -
-
-
-
- Wild mobs captured: {{:data.wild_captures}} -
- - - - - - - - -
- {{:helper.link('Previous Mob', 'arrow-left', {'choice': 'Prev'})}} - - {{:helper.link('Transfer Mob', 'exchange', {'choice': 'Transfer'})}} - - {{:helper.link('Rename Mob', 'pencil', {'choice': 'Rename'})}} - - {{:helper.link('Release Mob', 'tree', {'choice': 'Release'})}} - - {{:helper.link('Next Mob', 'arrow-right', {'choice': 'Next'})}} -
- {{if data.entry.is_hacked}} -
- {{:helper.link('Set Trap', 'bolt', {'choice': 'Set_Trap'})}} - {{/if}} -
-{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_mule.tmpl b/nano/templates/pda_mule.tmpl deleted file mode 100644 index 369d0830aa5..00000000000 --- a/nano/templates/pda_mule.tmpl +++ /dev/null @@ -1,118 +0,0 @@ -{{if !data.mulebot.active}} - {{if data.mulebot.count == 0}} -

No bots found.

- {{else}} -
- Select a MULE: -
-
- {{for data.mulebot.bots}} -
- {{:helper.link(value.Name, 'gear', {'radiomenu' : "1", 'op' : "control",'bot' : value.ref}, null, 'pdalink fixedLeftWidest')}} (Location: {{:value.Location}}) -
- {{/for}} - {{/if}} -
- {{:helper.link('Scan for Bots','rss', {'radiomenu' : "1", 'op' : "scanbots"}, null, 'pdalink fixedLeftWidest')}} -{{else}} -

{{:data.mulebot.active}}

- {{if data.mulebot.botstatus.mode == -1}} -

Waiting for response...

- {{else}} -

Status:

-
-
- Location: -
-
- {{:data.mulebot.botstatus.loca}} -
-
-
-
- Mode: -
-
- - {{if data.mulebot.botstatus.mode == 0}} - Ready - {{else data.mulebot.botstatus.mode == 1}} - Loading/Unloading - {{else data.mulebot.botstatus.mode == 2}} - Navigating to Delivery Location - {{else data.mulebot.botstatus.mode == 3}} - Navigating to Home - {{else data.mulebot.botstatus.mode == 4}} - Waiting for Clear Path - {{else data.mulebot.botstatus.mode == 5 || data.mulebot.botstatus.mode == 6}} - Calculating navigation Path - {{else data.mulebot.botstatus.mode == 7}} - Unable to locate destination - {{/if}} - -
-
-
-
- Current Load: -
-
- - {{:helper.link(data.mulebot.botstatus.load == null ? 'None (Unload)' : data.mulebot.botstatus.load + ' (Unload)', 'archive', {'radiomenu' : "1", 'op' : "unload"},data.mulebot.botstatus.load == null ? 'disabled' : null, 'pdalink fixedLeftWidest')}} - -
-
-
-
- Power: -
-
- - {{:data.mulebot.botstatus.powr}}% - -
-
-
-
- Destination: -
-
- {{:helper.link(data.mulebot.botstatus.dest == null || data.mulebot.botstatus.dest == "" ? 'None (Set)' : data.mulebot.botstatus.dest + ' (Set)', 'gear', {'radiomenu' : "1", 'op' : "setdest"}, null, 'pdalink fixedLeftWidest')}} -
-
-
-
- Home: -
-
- {{if data.mulebot.botstatus.home == null}} None {{else}} {{:data.mulebot.botstatus.home}} {{/if}} -
-
-
-
- Auto Return: -
-
- {{:helper.link(data.mulebot.botstatus.retn == 1 ? 'ON' : 'OFF', 'gear', {'radiomenu' : "1", 'op' : (data.mulebot.botstatus.retn==1 ? "retoff" : "reton")}, null, 'pdalink fixedLeftWidest')}} -
-
-
-
- Auto Pickup: -
-
- {{:helper.link(data.mulebot.botstatus.pick==1? 'ON' : 'OFF', 'gear', {'radiomenu' : "1", 'op' : (data.mulebot.botstatus.pick==1 ? "pickoff" : "pickon")}, null, 'pdalink fixedLeftWidest')}} -
-
-
-
- Functions: -
-
- {{:helper.link('Stop', 'gear', {'radiomenu' : "1", 'op' : "stop"}, null, 'pdalink fixedLeft')}} - {{:helper.link('Proceed', 'gear', {'radiomenu' : "1", 'op' : "start"}, null, 'pdalink fixedLeft')}} - {{:helper.link('Return Home', 'gear', {'radiomenu' : "1", 'op' : "home"}, null, 'pdalink fixedLeft')}} -
-
- {{/if}} -{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_notekeeper.tmpl b/nano/templates/pda_notekeeper.tmpl deleted file mode 100644 index 53db3be6438..00000000000 --- a/nano/templates/pda_notekeeper.tmpl +++ /dev/null @@ -1,21 +0,0 @@ - -
-
- Notes: -
-
-
-
-
- {{:data.note}} -
-
-
-
-
- {{:helper.link('Edit Notes', 'pencil-square-o', {'choice': "Edit"}, null, 'pdalink')}} -
-
\ No newline at end of file diff --git a/nano/templates/pda_power.tmpl b/nano/templates/pda_power.tmpl deleted file mode 100644 index 7ba04188b71..00000000000 --- a/nano/templates/pda_power.tmpl +++ /dev/null @@ -1,49 +0,0 @@ -{{if !data.records.powerconnected}} -
-
Select a power monitor:
-
- {{for data.records.powermonitors}} -
- {{:helper.link(value.Name, 'exclamation-circle', {'choice' : "Power Select", 'target' : value.ref}, null, 'pdalink fixedLeftWidest')}} -
- {{/for}} -{{else}} -
-
- Total Power: -
-
- {{:data.records.poweravail}} W -
-
-
-
- Total Load: -
-
- {{:data.records.powerload}} W -
-
-
-
- Total Demand: -
-
- {{:data.records.powerdemand}} W -
-
-
- - - {{for data.records.apcs}} - - {{:helper.string('', value.Equipment == "On" || value.Equipment == "AOn" ? '#4f7529' : '#8f1414', value.Equipment)}} - {{:helper.string('', value.Lights == "On" || value.Lights == "AOn" ? '#4f7529' : '#8f1414', value.Lights)}} - {{:helper.string('', value.Environment == "On" || value.Environment == "AOn" ? '#4f7529' : '#8f1414', value.Environment)}} - {{:helper.string('', value.CellStatus == "F" ? '#4f7529' : value.CellStatus == "C" ? '#cd6500' : '#8f1414', value.CellStatus == "M" ? 'No Cell' : value.CellPct + '%', value.CellStatus == "M" ? '' : ' (' + value.CellStatus + ')')}} - - - {{/for}} -
AreaEquip.LightingEnviron.CellLoad
{{:value.Name}}{1}{1}{1}{1}{2}{{:value.Load}}W
-
-{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_secbot.tmpl b/nano/templates/pda_secbot.tmpl deleted file mode 100644 index 6ff8c98e147..00000000000 --- a/nano/templates/pda_secbot.tmpl +++ /dev/null @@ -1,59 +0,0 @@ -{{if !data.beepsky.active}} - {{if data.beepsky.count == 0}} -

No bots found.

- {{else}} -
- Select a bot: -
-
- {{for data.beepsky.bots}} -
- {{:helper.link(value.Name, 'gear', {'radiomenu' : "1", 'op' : "control",'bot' : value.ref}, null, 'pdalink fixedLeftWidest')}} (Location: {{:value.Location}}) -
- {{/for}} - {{/if}} -
- {{:helper.link('Scan for Bots','rss', {'radiomenu' : "1", 'op' : "scanbots"}, null, 'pdalink fixedLeftWidest')}} -{{else}} -

{{:data.beepsky.active}}

- {{if data.beepsky.botstatus.mode == -1}} -

Waiting for response...

- {{else}} -

Status:

-
-
- Location: -
-
- {{:data.beepsky.botstatus.loca}} -
-
-
-
- Mode: -
-
- - {{if data.beepsky.botstatus.mode ==0}} - Ready - {{else data.beepsky.botstatus.mode == 1}} - Apprehending target - {{else data.beepsky.botstatus.mode ==2 || data.beepsky.botstatus.mode == 3}} - Arresting target - {{else data.beepsky.botstatus.mode ==4}} - Starting patrol - {{else data.beepsky.botstatus.mode ==5}} - On Patrol - {{else data.beepsky.botstatus.mode ==6}} - Responding to summons - {{/if}} - -
-
-
- {{:helper.link('Stop Patrol', 'gear', {'radiomenu' : "1", 'op' : "stop"}, null, 'pdalink fixedLeftWide')}} - {{:helper.link('Start Patrol', 'gear', {'radiomenu' : "1", 'op' : "go"}, null, 'pdalink fixedLeftWide')}} - {{:helper.link('Summon Bot', 'gear', {'radiomenu' : "1", 'op' : "summon"}, null, 'pdalink fixedLeftWide')}} -
- {{/if}} -{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_security.tmpl b/nano/templates/pda_security.tmpl deleted file mode 100644 index 53d40185e05..00000000000 --- a/nano/templates/pda_security.tmpl +++ /dev/null @@ -1,50 +0,0 @@ -{{if !data.records}} -
-
Select a record:
-
- {{for data.recordsList}} -
- {{:helper.link(value.Name, 'user', {'choice' : "Records", 'target' : value.ref}, null, 'pdalink fixedLeftWidest')}} -
- {{empty}} -
- No records found. -
- {{/for}} -{{else}} -
-
-
- {{if data.records.general}} - Name: {{:data.records.general.name}}
- Sex: {{:data.records.general.sex}}
- Species: {{:data.records.general.species}}
- Age: {{:data.records.general.age}}
- Rank: {{:data.records.general.rank}}
- Fingerprint: {{:data.records.general.fingerprint}}
- Physical Status: {{:data.records.general.p_stat}}
- Mental Status: {{:data.records.general.m_stat}}

- {{else}} - - General Record Lost!

-
- {{/if}} - {{if data.records.security}} -
-
Security Data:
-
- Criminal Status: {{:data.records.security.criminal}}

- Minor Crimes: {{:data.records.security.mi_crim}}
- Details: {{:data.records.security.mi_crim_d}}

- Major Crimes: {{:data.records.security.ma_crim}}
- Details: {{:data.records.security.ma_crim_d}}

- Important Notes: {{:data.records.security.notes}} - {{else}} - - Security Record Lost!

-
- {{/if}} -
-
-
-{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_signaller.tmpl b/nano/templates/pda_signaller.tmpl deleted file mode 100644 index 2b5f148b025..00000000000 --- a/nano/templates/pda_signaller.tmpl +++ /dev/null @@ -1,38 +0,0 @@ - -
-
- Frequency: -
-
- {{:data.signal_freq}} -
-   - {{:helper.link('-1', null, {'choice' : "Signal Frequency", 'sfreq' : "-10"}, null, null)}}  - {{:helper.link('-.2', null, {'choice' : "Signal Frequency", 'sfreq' : "-2"}, null, null)}}  - - {{:helper.link('+.2', null, {'choice' : "Signal Frequency", 'sfreq' : "2"}, null, null)}}  - {{:helper.link('+1', null, {'choice' : "Signal Frequency", 'sfreq' : "10"}, null, null)}} -
-
-
-
-
-
- Code: -
-
- - {{:data.signal_code}}
-
- {{:helper.link('-5', null, {'choice' : "Signal Code", 'scode' : "-5"}, null, null)}} - {{:helper.link('-1', null, {'choice' : "Signal Code", 'scode' : "-1"}, null, null)}} - {{:helper.link('+1', null, {'choice' : "Signal Code", 'scode' : "1"}, null, null)}} - {{:helper.link('+5', null, {'choice' : "Signal Code", 'scode' : "5"}, null, null)}} -
-
-
- {{:helper.link('Send Signal', 'exclamation-circle', {'choice' : "Send Signal"}, null, null)}} -
\ No newline at end of file diff --git a/nano/templates/pda_status_display.tmpl b/nano/templates/pda_status_display.tmpl deleted file mode 100644 index 8b153ad0ffd..00000000000 --- a/nano/templates/pda_status_display.tmpl +++ /dev/null @@ -1,44 +0,0 @@ - -
-
- Code: -
-
- {{:helper.link('Clear', 'trash', {'choice' : "Status", 'statdisp' : "blank"}, null, 'pdalink fixedLeftWide')}} - {{:helper.link('Shuttle ETA', 'gear', {'cartmenu' : "1", 'choice' : "Status", 'statdisp' : "shuttle"}, null, 'pdalink fixedLeftWide')}} - {{:helper.link('Message', 'gear', {'choice' : "Status", 'statdisp' : "message"}, null, 'pdalink fixedLeftWide')}} -
-
-
-
-
- Message line 1 -
-
- {{:helper.link(data.records.message1 + ' (set)', 'pencil', {'choice' : "Status", 'statdisp' : "setmsg1"}, null, 'pdalink fixedLeftWide')}} -
-
-
-
- Message line 2 -
-
- {{:helper.link(data.records.message2 + ' (set)', 'pencil', {'choice' : "Status", 'statdisp' : "setmsg2"}, null, 'pdalink fixedLeftWide')}} -
-
- -
-
-
- ALERT!: -
-
- {{:helper.link('None', 'bell', {'choice' : "Status", 'statdisp' : "alert", 'alert' : "default"}, null, 'pdalink fixedLeftWide')}} - {{:helper.link('Red Alert', 'bell', {'choice' : "Status", 'statdisp' : "alert", 'alert' : "redalert"}, null, 'pdalink fixedLeftWide')}} - {{:helper.link('Lockdown', 'exclamation-circle', {'choice' : "Status", 'statdisp' : "alert", 'alert' : "lockdown"}, null, 'pdalink fixedLeftWide')}} - {{:helper.link('Biohazard', 'exclamation-circle', {'choice' : "Status", 'statdisp' : "alert", 'alert' : "biohazard"}, null, 'pdalink fixedLeftWide')}} -
-
\ No newline at end of file diff --git a/nano/templates/pda_supply.tmpl b/nano/templates/pda_supply.tmpl deleted file mode 100644 index 810fc193769..00000000000 --- a/nano/templates/pda_supply.tmpl +++ /dev/null @@ -1,39 +0,0 @@ -
-
- Location: -
-
- - {{if data.supply.shuttle_moving}} - Moving to {{:data.supply.shuttle_loc}} - {{else}} - Shuttle at {{:data.supply.shuttle_loc}} - {{/if}} -
- {{:data.supply.shuttle_time}} -
-
-
-
-
-
- Current Approved Orders
- {{if data.supply.approved_count == 0}} - No current approved orders

- {{else}} - {{for data.supply.approved}} - #{{:value.Number}} - {{:value.Name}} approved by {{:value.OrderedBy}}
{{if value.Comment != ""}} {{:value.Comment}}
{{/if}}
- {{/for}} - {{/if}} -

- Current Requested Orders
- {{if data.supply.requests_count == 0}} - No current requested orders

- {{else}} - {{for data.supply.requests}} - #{{:value.Number}} - {{:value.Name}} requested by {{:value.OrderedBy}}
{{if value.Comment != ""}} {{:value.Comment}}
{{/if}}
- {{/for}} - {{/if}} -
-
-
\ No newline at end of file diff --git a/tgui/packages/common/string.js b/tgui/packages/common/string.js index a3da0885a19..405693a0d2f 100644 --- a/tgui/packages/common/string.js +++ b/tgui/packages/common/string.js @@ -120,10 +120,11 @@ export const decodeHtmlEntities = str => { if (!str) { return str; } - const translate_re = /&(nbsp|amp|quot|lt|gt|apos|trade);/g; + const translate_re = /&(nbsp|amp|deg|quot|lt|gt|apos|trade);/g; const translate = { nbsp: ' ', amp: '&', + deg: '°', quot: '"', lt: '<', gt: '>', diff --git a/tgui/packages/tgui/index.js b/tgui/packages/tgui/index.js index 16720fa2a6e..462934fd245 100644 --- a/tgui/packages/tgui/index.js +++ b/tgui/packages/tgui/index.js @@ -24,6 +24,7 @@ import './styles/themes/hackerman.scss'; import './styles/themes/malfunction.scss'; import './styles/themes/ntos.scss'; import './styles/themes/paper.scss'; +import './styles/themes/pda-retro.scss'; import './styles/themes/retro.scss'; import './styles/themes/syndicate.scss'; diff --git a/tgui/packages/tgui/interfaces/Pda.js b/tgui/packages/tgui/interfaces/Pda.js index 18018a1c736..6396fa865b8 100644 --- a/tgui/packages/tgui/interfaces/Pda.js +++ b/tgui/packages/tgui/interfaces/Pda.js @@ -4,14 +4,153 @@ import { useBackend } from "../backend"; import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section } from "../components"; import { Window } from "../layouts"; +/* This is all basically stolen from routes.js. */ +import { routingError } from "../routes"; + +const requirePdaInterface = require.context('./pda', false, /\.js$/); + +const getPdaApp = name => { + let appModule; + try { + appModule = requirePdaInterface(`./${name}.js`); + } catch (err) { + if (err.code === 'MODULE_NOT_FOUND') { + return routingError('notFound', name); + } + throw err; + } + const Component = appModule[name]; + if (!Component) { + return routingError('missingExport', name); + } + return Component; +}; + export const Pda = (props, context) => { const { act, data } = useBackend(context); + const { + app, + owner, + useRetro, + } = data; + + if (!owner) { + return ( + + +
+ Warning: No ID information found! Please swipe ID! +
+
+
+ ); + } + + let App = getPdaApp(app.template); + return ( - + - PDA! + +
+ + {app.name} + + } + p={1}> + +
+ +
); +}; + +const PDAHeader = (props, context) => { + const { act, data } = useBackend(context); + + const { + idInserted, + idLink, + cartridge_name, + stationTime, + } = data; + + return ( + + + {!!idInserted && ( + + + + + {body} + + ); +}; + +const MessengerList = (props, context) => { + const { act, data } = useBackend(context); + + const { + auto_scroll, + convopdas, + pdas, + charges, + plugins, + silent, + toff, + } = data; + + return ( + + + + + + + + + + {!toff && ( + + {!!charges && ( + + {charges} charges left. + + )} + {!convopdas.length && !pdas.length && ( + + No other PDAs located. + + ) || ( + + + + + )} + + )} + + ); +}; + +const PDAList = (props, context) => { + const { act, data } = useBackend(context); + + const { + pdas, + title, + msgAct, + } = props; + + const { + charges, + plugins, + } = data; + + if (!pdas || !pdas.length) { + return ( +
+ No PDAs found. +
+ ); + } + + return ( +
+ {pdas.map(pda => ( + +
+ ); +}; \ No newline at end of file diff --git a/tgui/packages/tgui/interfaces/pda/pda_notekeeper.js b/tgui/packages/tgui/interfaces/pda/pda_notekeeper.js new file mode 100644 index 00000000000..5accbfcb3b1 --- /dev/null +++ b/tgui/packages/tgui/interfaces/pda/pda_notekeeper.js @@ -0,0 +1,26 @@ +/* eslint react/no-danger: "off" */ +import { useBackend } from "../../backend"; +import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section } from "../../components"; + +export const pda_notekeeper = (props, context) => { + const { act, data } = useBackend(context); + + const { + note, + } = data; + + return ( + +
+ { /* As usual with dangerouslySetInnerHTML, + this notekeeper was designed to use HTML injection. + Fix when markdown is easier. */ } +
+
+