diff --git a/citadel.dme b/citadel.dme index 2e319a7c3c0..dd1dedf0320 100644 --- a/citadel.dme +++ b/citadel.dme @@ -2114,6 +2114,7 @@ #include "code\modules\asset_cache\assets\fish.dm" #include "code\modules\asset_cache\assets\fontawesome.dm" #include "code\modules\asset_cache\assets\genetics.dm" +#include "code\modules\asset_cache\assets\headers.dm" #include "code\modules\asset_cache\assets\inventory.dm" #include "code\modules\asset_cache\assets\jquery.dm" #include "code\modules\asset_cache\assets\legacy_nanomaps.dm" @@ -3804,6 +3805,7 @@ #include "code\modules\nano\interaction\remote.dm" #include "code\modules\nano\interaction\self.dm" #include "code\modules\nano\interaction\zlevel.dm" +#include "code\modules\nano\modules\alarm_monitor.dm" #include "code\modules\nano\modules\human_appearance.dm" #include "code\modules\nano\modules\law_manager.dm" #include "code\modules\nano\modules\nano_module.dm" @@ -3975,7 +3977,6 @@ #include "code\modules\power\fission\carry.dm" #include "code\modules\power\fission\computer.dm" #include "code\modules\power\fission\engine.dm" -#include "code\modules\power\fission\modular_computer.dm" #include "code\modules\power\fission\rods.dm" #include "code\modules\power\fusion\_setup.dm" #include "code\modules\power\fusion\fusion_circuits.dm" @@ -4598,12 +4599,17 @@ #include "code\modules\tgui\modules\alarm.dm" #include "code\modules\tgui\modules\atmos_control.dm" #include "code\modules\tgui\modules\camera.dm" +#include "code\modules\tgui\modules\communications.dm" +#include "code\modules\tgui\modules\crew_manifest.dm" #include "code\modules\tgui\modules\crew_monitor.dm" #include "code\modules\tgui\modules\overmap.dm" #include "code\modules\tgui\modules\power_monitor.dm" #include "code\modules\tgui\modules\rcon.dm" #include "code\modules\tgui\modules\supermatter_monitor.dm" #include "code\modules\tgui\modules\general\cardmod.dm" +#include "code\modules\tgui\modules\ntos-only\cardmod.dm" +#include "code\modules\tgui\modules\ntos-only\configurator.dm" +#include "code\modules\tgui\modules\ntos-only\email.dm" #include "code\modules\tgui\modules\specific\lathe_control.dm" #include "code\modules\tgui\states\admin.dm" #include "code\modules\tgui\states\always.dm" diff --git a/code/__DEFINES/access.dm b/code/__DEFINES/access.dm index ba1ff0ad226..83a45bff88d 100644 --- a/code/__DEFINES/access.dm +++ b/code/__DEFINES/access.dm @@ -431,3 +431,8 @@ STANDARD_ACCESS_DATUM(ACCESS_MISC_CASHCRATE, misc/cashcrate, "Cash Crates") #define ACCESS_SPECIAL_SILICONS 199 STANDARD_ACCESS_DATUM(ACCESS_SPECIAL_SILICONS, special/silicons, "Synthetic") + +// Network + +#define ACCESS_NETWORK 404 +STANDARD_ACCESS_DATUM(ACCESS_NETWORK, misc/network, "Network") diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index f2f291c5745..dfe4a49e34c 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -167,6 +167,10 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s #define MAX_NTNET_LOGS 500 #define MIN_NTNET_LOGS 10 +#define NTOS_EMAIL_NONEWMESSAGES 0 +#define NTOS_EMAIL_NOTIFALREADY 1 +#define NTOS_EMAIL_NEWMESSAGE 2 + // Special return values from bullet_act(). Positive return values are already used to indicate the blocked level of the projectile. /// If the projectile should continue flying after calling bullet_act() diff --git a/code/modules/hydroponics/trays/tray_tools.dm b/code/modules/hydroponics/trays/tray_tools.dm index f4c2dd3b102..4bb1cc6b0c8 100644 --- a/code/modules/hydroponics/trays/tray_tools.dm +++ b/code/modules/hydroponics/trays/tray_tools.dm @@ -152,9 +152,9 @@ dat += "

Other Data

" - var/list/tgui_data = grown_seed.get_tgui_analyzer_data() + var/list/ui_data = grown_seed.get_tgui_analyzer_data() - dat += jointext(tgui_data["trait_info"], "
\n") + dat += jointext(ui_data["trait_info"], "
\n") var/obj/item/paper/P = new /obj/item/paper(get_turf(src)) P.name = "paper - [form_title]" diff --git a/code/modules/modular_computers/NTNet/NTNet.dm b/code/modules/modular_computers/NTNet/NTNet.dm index 159e5764207..1c5f96b523b 100644 --- a/code/modules/modular_computers/NTNet/NTNet.dm +++ b/code/modules/modular_computers/NTNet/NTNet.dm @@ -179,3 +179,8 @@ var/global/datum/ntnet/ntnet_global = new() if(A.login == login) return 1 return 0 + +/datum/ntnet/proc/get_chat_channel_by_id(id) + for(var/datum/ntnet_conversation/chan in chat_channels) + if(chan.id == id) + return chan diff --git a/code/modules/modular_computers/README.md b/code/modules/modular_computers/README.md new file mode 100644 index 00000000000..2335ce08e73 --- /dev/null +++ b/code/modules/modular_computers/README.md @@ -0,0 +1,121 @@ +/* +Program-based computers, designed to replace computer3 project and eventually most consoles on station + + +1. Basic information +Program based computers will allow you to do multiple things from single computer. Each computer will have programs, with more being downloadable from NTNet (stationwide network with wireless coverage) +if user has apropriate ID card access. It will be possible to hack the computer by using an emag on it - the emag will have to be completely new and will be consumed on use, but it will +lift ALL locks on ALL installed programs, and allow download of programs even if your ID doesn't have access to them. Computers will have hard drives that can store files. +Files can be programs (datum/computer_file/program/ subtype) or data files (datum/computer_file/data/ subtypes). Program for sending files will be available that will allow transfer via NTNet. +NTNet coverage will be limited to station's Z level, but better network card (=more expensive and higher power use) will allow usage everywhere. Hard drives will have limited capacity for files +which will be related to how good hard drive you buy when purchasing the laptop. For storing more files USB-style drives will be buildable with Protolathe in research. + +2. Available devices +CONSOLES +Consoles will come in various pre-fabricated loadouts, each loadout starting with certain set of programs (aka Engineering console, Medical console, etc.), of course, more software may be downloaded. +Consoles won't usually have integrated battery, but the possibility to install one will exist for critical applications. Consoles are considered hardwired into NTNet network which means they +will have working coverage on higher speed (Ethernet is faster than Wi-Fi) and won't require wireless coverage to exist. +LAPTOPS +Laptops are middle ground between actual portable devices and full consoles. They offer certain level of mobility, as they can be closed, moved somewhere else and then opened again. +Laptops will by default have internal battery to power them, and may be recharged with rechargers. However, laptops rely on wireless NTNet coverage. Laptop HDDs are also designed with power efficiency +in mind, which means they sacrifice some storage space for higher battery life. Laptops may be dispensed from computer vendor machine, and may be customised before vending. For people which don't +want to rely on internal battery, tesla link exists that connects to APC, if one exists. +TABLETS +Tablets are smallest available devices, designed with full mobility in mind. Tablets have only weak CPU which means the software they can run is somewhat limited. They are also designed with high +battery life in mind, which means the hardware focuses on power efficiency rather than high performance. This is most visible with hard drives which have quite small storage capacity. +Tablets can't be equipped with tesla link, which means they have to be recharged manually. + + +3. Computer Hardware +Computers will come with basic hardware installed, with upgrades being selectable when purchasing the device. +Hard Drive: Stores data, mandatory for the computer to work +Network Card: Connects to NTNet +Battery: Internal power source that ensures the computer operates when not connected to APC. +Extras (those won't be installed by default, but can be bought) +ID Card Slot: Required for HoP-style programs to work. Access for security record-style programs is read from ID of user [RFID?] without requiring this +APC Tesla Relay: Wirelessly powers the device from APC. Consoles have it by default. Laptops can buy it. +Disk Drive: Allows usage of portable data disks. +Nano Printer: Allows the computer to scan paper contents and save them to file, as well as recycle papers and print stuff on it. + +4. NTNet +NTNet is stationwide network that allows users to download programs needed for their work. It will be possible to send any files to other active computers using relevant program (NTN Transfer). +NTNet is under jurisdiction of both Engineering and Research. Engineering is responsible for any repairs if necessary and research is responsible for monitoring. It is similar to PDA messaging. +Operation requires functional "NTNet Relay" which is by default placed on tcommsat. If the relay is damaged NTNet will be offline until it is replaced. Multiple relays bring extra redundancy, +if one is destroyed the second will take over. If all relays are gone it stops working, simple as that. NTNet may be altered via administration console available to Research Director. It is +possible to enable/disable Software Downloading, P2P file transfers and Communication (IC version of IRC, PDA messages for more than two people) + +5. Software +Software would almost exclusively use NanoUI modules. Few exceptions are text editor (uses similar screen as TCS IDE used for editing and classic HTML for previewing as Nano looks differently) +and similar programs which for some reason require HTML UI. Most software will be highly dependent on NTNet to work as laptops are not physically connected to the station's network. +What i plan to add: + +Note: XXXXDB programs will use ingame_manuals to display basic help for players, similar to how books, etc. do + +Basic - Software in this bundle is automagically preinstalled in every new computer + NTN Transfer - Allows P2P transfer of files to other computers that run this. + Configurator - Allows configuration of computer's hardware, basically status screen. + File Browser - Allows you to browse all files stored on the computer. Allows renaming/deleting of files. + TXT Editor - Allows you editing data files in text editor mode. + NanoPrint - Allows you to operate NanoPrinter hardware to print text files. + NTNRC Chat - NTNet Relay Chat client. Allows PDA-messaging style messaging for more than two users. Person which created the conversation is Host and has administrative privilegies (kicking, etc.) + NTNet News - Allows reading news from newscaster network. + +Engineering - Requires "Engineering" access on ID card (ie. CE, Atmostech, Engineer) + Alarm Monitor - Allows monitoring alarms, same as the stationbound one. + Power Monitor - Power monitoring computer, connects to sensors in same way as regular one does. + Atmospheric Control - Allows access to the Atmospherics Monitor Console that operates air alarms. Requires extra access: "Atmospherics" + RCON Remote Control Console - Allows access to the RCON Remote Control Console. Requires extra access: "Power Equipment" + EngiDB - Allows accessing NTNet information repository for information about engineering-related things. + +Medical - Requires "Medbay" access on ID card (ie. CMO, Doctor,..) + Medical Records Uplink - Allows editing/reading of medical records. Printing requires NanoPrinter hardware. + MediDB - Allows accessing NTNet information repository for information about medical procedures + ChemDB - Requires extra access: "Chemistry" - Downloads basic information about recipes from NTNet + +Research - Requires "Research and Development" access on ID card (ie. RD, Roboticist, etc.) + Research Server Monitor - Allows monitoring of research levels on RnD servers. (read only) + Robotics Monitor Console - Allows monitoring of robots and exosuits. Lockdown/Self-Destruct options are unavailable [balance reasons for malf/traitor AIs]. Requires extra access: "Robotics" + NTNRC Administration Console - Allows administrative access to NTNRC. This includes bypassing any channel passwords and enabling "invisible" mode for spying on conversations. Requires extra access: "Research Director" + NTNet Administration Console - Allows remote configuration of NTNet Relay - CAUTION: If NTNet is turned off it won't be possible to turn it on again from the computer, as operation requires NTNet to work! Requires extra access: "Research Director" + NTNet Monitor - Allows monitoring of NTNet and it's various components, including simplified network logs and system status. + +Security - Requires "Security" access on ID card (ie. HOS, Security officer, Detective) + Security Records Uplink - Allows editing/reading of security records. Printing requires Nanoprinter hardware. + LawDB - Allows accessing NTNet information repository for security information (corporate regulations) + Camera Uplink - Allows viewing cameras around the station. + +Command - Requires "Bridge" access on ID card (all heads) + Alertcon Access - Allows changing of alert levels. Red requires activation from two computers with two IDs similar to how those wall mounted devices do. + Employment Records Access - Allows reading of employment records. Printing requires NanoPrinter hardware. + Communication Console - Allows sending emergency messages to Central. + Emergency Shuttle Control Console - Allows calling/recalling the emergency shuttle. + Shuttle Control Console - Allows control of various shuttles around the station (mining, research, engineering) + +*REDACTED* - Can be downloaded from SyndiCorp servers, only via emagged devices. These files are very large and limited to laptops/consoles only. + SYSCRACK - Allows cracking of secure network terminals, such as, NTNet administration. The sysadmin will probably notice this. + SYSOVERRIDE - Allows hacking into any device connected to NTNet. User will notice this and may stop the hack by disconnecting from NTNet first. After hacking various options exist, such as stealing/deleting files. + SYSKILL - Tricks NTNet to force-disconnect a device. The sysadmin will probably notice this. + SYSDOS - Launches a Denial of Service attack on NTNet relay. Can DoS only one relay at once. Requires NTNet connection. After some time the relay crashes until attack stops. The sysadmin will probably notice this. + AIHACK - Hacks an AI, allowing you to upload/remove/modify a law even without relevant circuit board. The AI is alerted once the hack starts, and it takes a while for it to complete. Does not work on AIs with zeroth law. + COREPURGE - Deletes all files on the hard drive, including the undeletable ones. Something like software self-destruct for computer. + +6. Security +Laptops will be password-lockable. If password is set a MD5 hash of it is stored and password is required every time you turn on the laptop. +Passwords may be decrypted by using special Decrypter (protolathable, RDs office starts with one) device that will slowly decrypt the password. +Decryption time would be length_of_password * 30 seconds, with maximum being 9 minutes (due to battery life limitations, which is 10+ min). +If decrypted the password is cleared, so you can keep using your favorite password without people ever actually revealing it (for meta prevention reasons mostly). +Emagged laptops will have option to enable "Safe Encryption". If safely encrypted laptop is decrypted it loses it's emag status and 50% of files is deleted (randomly selected). + +7. System Administrator +System Administrator will be new job under Research. It's main specifics will be maintaining of computer systems on station, espicially from software side. +From IC perspective they'd probably know how to build a console or something given they work with computers, but they are mostly programmers/network experts. +They will have office in research, which will probably replace (and contain) the server room and part of the toxins storage which is currently oversized. +They will have access to DOWNLOAD (not run) all programs that exist on NTNet. They'll have fairly good amount of available programs, most of them being +administrative consoles and other very useful things. They'll also be able to monitor NTNet. There will probably be one or two job slots. + +8. IDS +With addition of various antag programs, IDS(Intrusion Detection System) will be added to NTNet. This system can be turned on/off via administration console. +If enabled, this system automatically detects any abnormality and triggers a warning that's visible on the NTNet status screen, as well as generating a security log. +IDS can be disabled by simple on/off switch in the configuration. + +*/ \ No newline at end of file diff --git a/code/modules/modular_computers/computers/modular_computer/core.dm b/code/modules/modular_computers/computers/modular_computer/core.dm index 049013530c1..82f9efad0dd 100644 --- a/code/modules/modular_computers/computers/modular_computer/core.dm +++ b/code/modules/modular_computers/computers/modular_computer/core.dm @@ -1,14 +1,13 @@ -/obj/item/modular_computer/process(delta_time) +/obj/item/modular_computer/process() if(!enabled) // The computer is turned off last_power_usage = 0 - return FALSE + return 0 if(damage > broken_damage) shutdown_computer() - return FALSE + return 0 - // Active program requires NTNet to run but we've just lost connection. Crash. - if(active_program && active_program.requires_ntnet && !get_ntnet_status(active_program.requires_ntnet_feature)) + if(active_program && active_program.requires_ntnet && !get_ntnet_status(active_program.requires_ntnet_feature)) // Active program requires NTNet to run but we've just lost connection. Crash. active_program.event_networkfailure(0) for(var/datum/computer_file/program/P in idle_threads) @@ -34,22 +33,22 @@ handle_power() // Handles all computer power interaction check_update_ui_need() -/// Used to perform preset-specific hardware changes. +// Used to perform preset-specific hardware changes. /obj/item/modular_computer/proc/install_default_hardware() - return TRUE + return 1 -/// Used to install preset-specific programs +// Used to install preset-specific programs /obj/item/modular_computer/proc/install_default_programs() - return TRUE + return 1 -/obj/item/modular_computer/Initialize(mapload) - . = ..() +/obj/item/modular_computer/Initialize() START_PROCESSING(SSobj, src) install_default_hardware() if(hard_drive) install_default_programs() update_icon() update_verbs() + . = ..() /obj/item/modular_computer/Destroy() kill_program(1) @@ -64,9 +63,9 @@ to_chat(user, "\The [src] was already emagged.") return //NO_EMAG_ACT else - computer_emagged = TRUE + computer_emagged = 1 to_chat(user, "You emag \the [src]. It's screen briefly shows a \"OVERRIDE ACCEPTED: New software downloads available.\" message.") - return TRUE + return 1 /obj/item/modular_computer/update_icon() icon_state = icon_state_unpowered @@ -91,11 +90,11 @@ add_overlay(overlays_to_add) -/obj/item/modular_computer/proc/turn_on(mob/user) +/obj/item/modular_computer/proc/turn_on(var/mob/user) if(bsod) return if(tesla_link) - tesla_link.enabled = TRUE + tesla_link.enabled = 1 var/issynth = issilicon(user) // Robots and AIs get different activation messages. if(damage > broken_damage) if(issynth) @@ -116,39 +115,39 @@ else to_chat(user, "You press the power button but \the [src] does not respond") -/// Relays kill program request to currently active program. Use this to quit current program. -/obj/item/modular_computer/proc/kill_program(forced = FALSE) +// Relays kill program request to currently active program. Use this to quit current program. +/obj/item/modular_computer/proc/kill_program(var/forced = 0) if(active_program) active_program.kill_program(forced) active_program = null var/mob/user = usr if(user && istype(user)) - nano_ui_interact(user) // Re-open the UI on this computer. It should show the main screen now. + ui_interact(user) // Re-open the UI on this computer. It should show the main screen now. update_icon() // Returns 0 for No Signal, 1 for Low Signal and 2 for Good Signal. 3 is for wired connection (always-on) -/obj/item/modular_computer/proc/get_ntnet_status(specific_action = 0) +/obj/item/modular_computer/proc/get_ntnet_status(var/specific_action = 0) if(network_card) return network_card.get_signal(specific_action) else - return FALSE + return 0 -/obj/item/modular_computer/proc/add_log(text) +/obj/item/modular_computer/proc/add_log(var/text) if(!get_ntnet_status()) - return FALSE + return 0 return ntnet_global.add_log(text, network_card) -/obj/item/modular_computer/proc/shutdown_computer(loud = TRUE) +/obj/item/modular_computer/proc/shutdown_computer(var/loud = 1) kill_program(1) for(var/datum/computer_file/program/P in idle_threads) P.kill_program(1) idle_threads.Remove(P) if(loud) visible_message("\The [src] shuts down.") - enabled = FALSE + enabled = 0 update_icon() -/obj/item/modular_computer/proc/enable_computer(mob/user = null) +/obj/item/modular_computer/proc/enable_computer(var/mob/user = null) enabled = 1 update_icon() @@ -158,7 +157,7 @@ run_program(autorun.stored_data) if(user) - nano_ui_interact(user) + ui_interact(user) /obj/item/modular_computer/proc/minimize_program(mob/user) if(!active_program || !processor_unit) @@ -166,12 +165,12 @@ idle_threads.Add(active_program) active_program.program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs - SSnanoui.close_uis(active_program.NM ? active_program.NM : active_program) SStgui.close_uis(active_program.TM ? active_program.TM : active_program) active_program = null update_icon() if(istype(user)) - nano_ui_interact(user) // Re-open the UI on this computer. It should show the main screen now. + ui_interact(user) // Re-open the UI on this computer. It should show the main screen now. + /obj/item/modular_computer/proc/run_program(prog) var/datum/computer_file/program/P = null @@ -180,7 +179,7 @@ P = hard_drive.find_file_by_name(prog) if(!P || !istype(P)) // Program not found or it's not executable program. - to_chat(user, SPAN_DANGER("\The [src]'s screen shows \"I/O ERROR - Unable to run [prog]\" warning.")) + to_chat(user, "\The [src]'s screen shows \"I/O ERROR - Unable to run [prog]\" warning.") return P.computer = src @@ -195,11 +194,11 @@ return if(idle_threads.len >= processor_unit.max_idle_programs+1) - to_chat(user, SPAN_NOTICE("\The [src] displays a \"Maximal CPU load reached. Unable to run another program.\" error")) + to_chat(user, "\The [src] displays a \"Maximal CPU load reached. Unable to run another program.\" error") return if(P.requires_ntnet && !get_ntnet_status(P.requires_ntnet_feature)) // The program requires NTNet connection, but we are not connected to NTNet. - to_chat(user, SPAN_DANGER("\The [src]'s screen shows \"NETWORK ERROR - Unable to connect to NTNet. Please retry. If problem persists contact your system administrator.\" warning.")) + to_chat(user, "\The [src]'s screen shows \"NETWORK ERROR - Unable to connect to NTNet. Please retry. If problem persists contact your system administrator.\" warning.") return if(active_program) @@ -207,15 +206,15 @@ if(P.run_program(user)) update_icon() - return TRUE + return 1 /obj/item/modular_computer/proc/update_uis() - if(active_program) //Should we update program ui or computer ui? - SSnanoui.update_uis(active_program) - if(active_program.NM) - SSnanoui.update_uis(active_program.NM) + if(active_program) + SStgui.update_uis(active_program) + if(active_program.TM) + SStgui.update_uis(active_program.TM) else - SSnanoui.update_uis(src) + SStgui.update_uis(src) /obj/item/modular_computer/proc/check_update_ui_need() var/ui_update_needed = FALSE @@ -252,12 +251,16 @@ update_uis() // Used by camera monitor program -/obj/item/modular_computer/check_eye(mob/user) +/obj/item/modular_computer/check_eye(var/mob/user) if(active_program) return active_program.check_eye(user) else return ..() +/obj/item/modular_computer/relaymove(var/mob/user, direction) + if(active_program) + return active_program.relaymove(user, direction) + /obj/item/modular_computer/proc/set_autorun(program) if(!hard_drive) return diff --git a/code/modules/modular_computers/computers/modular_computer/interaction.dm b/code/modules/modular_computers/computers/modular_computer/interaction.dm index 8e357fdc180..f2ddbc5e9e0 100644 --- a/code/modules/modular_computers/computers/modular_computer/interaction.dm +++ b/code/modules/modular_computers/computers/modular_computer/interaction.dm @@ -120,7 +120,7 @@ if(.) return if(enabled && screen_on) - nano_ui_interact(user) + ui_interact(user) else if(!enabled && screen_on) turn_on(user) diff --git a/code/modules/modular_computers/computers/modular_computer/ui.dm b/code/modules/modular_computers/computers/modular_computer/ui.dm index e397b4a9dec..8affd685289 100644 --- a/code/modules/modular_computers/computers/modular_computer/ui.dm +++ b/code/modules/modular_computers/computers/modular_computer/ui.dm @@ -1,5 +1,10 @@ -// Operates NanoUI -/obj/item/modular_computer/nano_ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1) +// Operates TGUI +/obj/item/modular_computer/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/simple/headers) + ) + +/obj/item/modular_computer/ui_interact(mob/user, datum/tgui/ui) if(!screen_on || !enabled) if(ui) ui.close() @@ -13,7 +18,7 @@ if(active_program) if(ui) // This is the main laptop screen. Since we are switching to program's UI close it for now. ui.close() - active_program.nano_ui_interact(user) + active_program.ui_interact(user) return // We are still here, that means there is no program loaded. Load the BIOS/ROM/OS/whatever you want to call it. @@ -22,80 +27,99 @@ visible_message("\The [src] beeps three times, it's screen displaying \"DISK ERROR\" warning.") return // No HDD, No HDD files list or no stored files. Something is very broken. - var/datum/computer_file/data/autorun = hard_drive.find_file_by_name("autorun") + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "NtosMain") + ui.set_autoupdate(TRUE) + ui.open() +/obj/item/modular_computer/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) var/list/data = get_header_data() - var/list/programs = list() - for(var/datum/computer_file/program/P in hard_drive.stored_files) - var/list/program = list() - program["name"] = P.filename - program["desc"] = P.filedesc - program["icon"] = P.program_menu_icon - program["autorun"] = (istype(autorun) && (autorun.stored_data == P.filename)) ? 1 : 0 - if(P in idle_threads) - program["running"] = 1 - programs.Add(list(program)) + data["login"] = list() + var/obj/item/computer_hardware/card_slot/cardholder = card_slot + if(cardholder) + var/obj/item/card/id/stored_card = cardholder.stored_card + if(stored_card) + var/stored_name = stored_card.registered_name + var/stored_title = stored_card.assignment + if(!stored_name) + stored_name = "Unknown" + if(!stored_title) + stored_title = "Unknown" + data["login"] = list( + IDName = stored_name, + IDJob = stored_title, + ) - data["programs"] = programs - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "laptop_mainscreen.tmpl", "NTOS Main Menu", 400, 500) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + data["removable_media"] = list() + + var/datum/computer_file/data/autorun = hard_drive.find_file_by_name("autorun") + data["programs"] = list() + for(var/datum/computer_file/program/P in hard_drive.stored_files) + var/running = FALSE + if(P in idle_threads) + running = TRUE + + data["programs"] += list(list( + "name" = P.filename, + "desc" = P.filedesc, + "icon" = P.program_menu_icon, + "running" = running, + "autorun" = (istype(autorun) && (autorun.stored_data == P.filename)) ? 1 : 0 + )) + + data["has_light"] = FALSE // has_light + data["light_on"] = FALSE // light_on + data["comp_light_color"] = null // comp_light_color + + return data // Handles user's GUI input -/obj/item/modular_computer/Topic(href, href_list) +/obj/item/modular_computer/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) if(..()) - return 1 - if( href_list["PC_exit"] ) - kill_program() - return 1 - if( href_list["PC_enable_component"] ) - var/obj/item/computer_hardware/H = find_hardware_by_name(href_list["PC_enable_component"]) - if(H && istype(H) && !H.enabled) - H.enabled = 1 - . = 1 - if( href_list["PC_disable_component"] ) - var/obj/item/computer_hardware/H = find_hardware_by_name(href_list["PC_disable_component"]) - if(H && istype(H) && H.enabled) - H.enabled = 0 - . = 1 - if( href_list["PC_shutdown"] ) - shutdown_computer() - return 1 - if( href_list["PC_minimize"] ) - var/mob/user = usr - minimize_program(user) + return TRUE - if( href_list["PC_killprogram"] ) - var/prog = href_list["PC_killprogram"] - var/datum/computer_file/program/P = null - var/mob/user = usr - if(hard_drive) - P = hard_drive.find_file_by_name(prog) + switch(action) + if("PC_exit") + kill_program() + return TRUE + if("PC_shutdown") + shutdown_computer() + return TRUE + if("PC_minimize") + var/mob/user = usr + minimize_program(user) + if("PC_killprogram") + var/prog = params["name"] + var/datum/computer_file/program/P = null + var/mob/user = usr + if(hard_drive) + P = hard_drive.find_file_by_name(prog) - if(!istype(P) || P.program_state == PROGRAM_STATE_KILLED) + if(!istype(P) || P.program_state == PROGRAM_STATE_KILLED) + return + + P.kill_program(1) + to_chat(user, "Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.") + return TRUE + if("PC_runprogram") + return run_program(params["name"]) + if("PC_setautorun") + if(!hard_drive) + return + set_autorun(params["name"]) + return TRUE + if("PC_Eject_Disk") + var/param = params["name"] + switch(param) + if("ID") + proc_eject_id(usr) + return TRUE + else return - P.kill_program(1) - update_uis() - to_chat(user, "Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.") - - if( href_list["PC_runprogram"] ) - return run_program(href_list["PC_runprogram"]) - - if( href_list["PC_setautorun"] ) - if(!hard_drive) - return - set_autorun(href_list["PC_setautorun"]) - - if(.) - update_uis() - -// Function used by NanoUI's to obtain data for header. All relevant entries begin with "PC_" +// Function used by TGUI's to obtain data for header. All relevant entries begin with "PC_" /obj/item/modular_computer/proc/get_header_data() var/list/data = list() diff --git a/code/modules/modular_computers/file_system/computer_file.dm b/code/modules/modular_computers/file_system/computer_file.dm index 0e5b45a1219..ef886b871ed 100644 --- a/code/modules/modular_computers/file_system/computer_file.dm +++ b/code/modules/modular_computers/file_system/computer_file.dm @@ -1,20 +1,13 @@ var/global/file_uid = 0 -/datum/computer_file - /// Placeholder. No spacebars - var/filename = "NewFile" - /// File full names are [filename].[filetype] so like NewFile.XXX in this case. - var/filetype = "XXX" - /// File size in GQ. Integers only! - var/size = 1 - /// Holder that contains this file. - var/obj/item/computer_hardware/hard_drive/holder - /// Whether the file may be sent to someone via NTNet transfer or other means. - var/unsendable = FALSE - /// Whether the file may be deleted. Setting to 1 prevents deletion/renaming/etc. - var/undeletable = FALSE - /// UID of this file. - var/uid +/datum/computer_file/ + var/filename = "NewFile" // Placeholder. No spacebars + var/filetype = "XXX" // File full names are [filename].[filetype] so like NewFile.XXX in this case + var/size = 1 // File size in GQ. Integers only! + var/obj/item/computer_hardware/hard_drive/holder // Holder that contains this file. + var/unsendable = 0 // Whether the file may be sent to someone via NTNet transfer or other means. + var/undeletable = 0 // Whether the file may be deleted. Setting to 1 prevents deletion/renaming/etc. + var/uid // UID of this file /datum/computer_file/New() ..() @@ -30,9 +23,9 @@ var/global/file_uid = 0 if(holder.holder2 && holder.holder2.active_program == src) holder.holder2.kill_program(1) holder = null - ..() + return ..() -/// Returns independent copy of this file. +// Returns independent copy of this file. /datum/computer_file/proc/clone(var/rename = 0) var/datum/computer_file/temp = new type temp.unsendable = unsendable @@ -44,3 +37,5 @@ var/global/file_uid = 0 temp.filename = filename temp.filetype = filetype return temp + + diff --git a/code/modules/modular_computers/file_system/data.dm b/code/modules/modular_computers/file_system/data.dm index 70bb3560d04..7ad48bea54b 100644 --- a/code/modules/modular_computers/file_system/data.dm +++ b/code/modules/modular_computers/file_system/data.dm @@ -1,22 +1,17 @@ -/** - * /data/ files store data in string format. - * They don't contain other logic for now. - */ +// /data/ files store data in string format. +// They don't contain other logic for now. /datum/computer_file/data + var/stored_data = "" // Stored data in string format. filetype = "DAT" - /// Whether the user will be reminded that the file probably shouldn't be edited. - var/do_not_edit = 0 - /// Stored data in string format. - var/stored_data = "" - /// The file size of this bit of data. var/block_size = 250 + var/do_not_edit = 0 // Whether the user will be reminded that the file probably shouldn't be edited. /datum/computer_file/data/clone() var/datum/computer_file/data/temp = ..() temp.stored_data = stored_data return temp -/// Calculates file size from amount of characters in saved string +// Calculates file size from amount of characters in saved string /datum/computer_file/data/proc/calculate_size() size = max(1, round(length(stored_data) / block_size)) diff --git a/code/modules/modular_computers/file_system/news_article.dm b/code/modules/modular_computers/file_system/news_article.dm index f2095ffe4e5..4231a5330ac 100644 --- a/code/modules/modular_computers/file_system/news_article.dm +++ b/code/modules/modular_computers/file_system/news_article.dm @@ -1,31 +1,16 @@ -/** - * /data/ files store data in string format. - * They don't contain other logic for now. - */ +// /data/ files store data in string format. +// They don't contain other logic for now. /datum/computer_file/data/news_article filetype = "XNML" filename = "Unknown News Entry" - /// Results in smaller files. - block_size = 5000 - /// Editing the file breaks most formatting due to some HTML tags not being accepted as input from average user. - do_not_edit = 1 - /// File path to HTML file that will be loaded on server start. Example: '/news_articles/space_magazine_1.html'. Use the /news_articles/ folder! - var/server_file_path - /// Set to 1 for older stuff. - var/archived - /// Filename of cover. - var/cover + block_size = 5000 // Results in smaller files + do_not_edit = 1 // Editing the file breaks most formatting due to some HTML tags not being accepted as input from average user. + var/server_file_path // File path to HTML file that will be loaded on server start. Example: '/news_articles/space_magazine_1.html'. Use the /news_articles/ folder! + var/archived // Set to 1 for older stuff + var/cover //filename of cover. -/datum/computer_file/data/news_article/New(var/load_FROM_FILE = 0) +/datum/computer_file/data/news_article/New(var/load_file = 0) ..() - if(server_file_path && load_FROM_FILE) + if(server_file_path && load_file) stored_data = file2text(server_file_path) calculate_size() - - -//! ## NEWS DEFINITIONS BELOW THIS LINE -/* KEPT HERE AS AN EXAMPLE -/datum/computer_file/data/news_article/space/vol_one - filename = "SPACE Magazine vol. 1" - server_file_path = 'news_articles/space_magazine_1.html' -*/ diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm index 737d5a4781e..3e0b98ee803 100644 --- a/code/modules/modular_computers/file_system/program.dm +++ b/code/modules/modular_computers/file_system/program.dm @@ -1,64 +1,35 @@ // /program/ files are executable programs that do things. /datum/computer_file/program filetype = "PRG" - //! File name. FILE NAME MUST BE UNIQUE IF YOU WANT THE PROGRAM TO BE DOWNLOADABLE FROM NTNET! - filename = "UnknownProgram" - /// List of required accesses to run/download the program. - var/required_access = null - /// Whether the program checks for required_access when run. - var/requires_access_to_run = TRUE - /// Whether the program checks for required_access when downloading. - var/requires_access_to_download = TRUE + filename = "UnknownProgram" // File name. FILE NAME MUST BE UNIQUE IF YOU WANT THE PROGRAM TO BE DOWNLOADABLE FROM NTNET! + var/required_access = null // List of required accesses to run/download the program. + var/requires_access_to_run = 1 // Whether the program checks for required_access when run. + var/requires_access_to_download = 1 // Whether the program checks for required_access when downloading. + // TGUIModule + var/datum/tgui_module_old/TM = null // If the program uses TGUIModule, put it here and it will be automagically opened. Otherwise implement tgui_interact. + var/tguimodule_path = null // Path to tguimodule, make sure to set this if implementing new program. + // Etc Program stuff + var/program_state = PROGRAM_STATE_KILLED// PROGRAM_STATE_KILLED or PROGRAM_STATE_BACKGROUND or PROGRAM_STATE_ACTIVE - specifies whether this program is running. + var/obj/item/modular_computer/computer // Device that runs this program. + var/filedesc = "Unknown Program" // User-friendly name of this program. + var/extended_desc = "N/A" // Short description of this program's function. + var/program_icon_state = null // Program-specific screen icon state + var/program_key_state = "standby_key" // Program-specific keyboard icon state + var/program_menu_icon = "newwin" // Icon to use for program's link in main menu + var/requires_ntnet = 0 // Set to 1 for program to require nonstop NTNet connection to run. If NTNet connection is lost program crashes. + var/requires_ntnet_feature = 0 // Optional, if above is set to 1 checks for specific function of NTNet (currently NTNET_SOFTWAREDOWNLOAD, NTNET_PEERTOPEER, NTNET_SYSTEMCONTROL and NTNET_COMMUNICATION) + var/ntnet_status = 1 // NTNet status, updated every tick by computer running this program. Don't use this for checks if NTNet works, computers do that. Use this for calculations, etc. + var/usage_flags = PROGRAM_ALL // Bitflags (PROGRAM_CONSOLE, PROGRAM_LAPTOP, PROGRAM_TABLET combination) or PROGRAM_ALL + var/network_destination = null // Optional string that describes what NTNet server/system this program connects to. Used in default logging. + var/available_on_ntnet = 1 // Whether the program can be downloaded from NTNet. Set to 0 to disable. + var/available_on_syndinet = 0 // Whether the program can be downloaded from SyndiNet (accessible via emagging the computer). Set to 1 to enable. + var/computer_emagged = 0 // Set to 1 if computer that's running us was emagged. Computer updates this every Process() tick + var/ui_header = null // Example: "something.gif" - a header image that will be rendered in computer's UI when this program is running at background. Images are taken from /nano/images/status_icons. Be careful not to use too large images! + var/ntnet_speed = 0 // GQ/s - current network connectivity transfer rate + /// Name of the tgui interface + var/tgui_id -//! ## Nanoui - /// If the program uses NanoModule, put it here and it will be automagically opened. Otherwise implement nano_ui_interact. - var/datum/nano_module/NM = null - /// Path to nanomodule, make sure to set this if implementing new program. - var/nanomodule_path = null - -//! ## TGUI - /// If the program uses TGUIModule, put it here and it will be automagically opened. Otherwise implement ui_interact. - var/datum/tgui_module_old/TM = null - /// Path to tguimodule, make sure to set this if implementing new program. - var/tguimodule_path = null - -//! ## Misc Program Stuff - /// PROGRAM_STATE_KILLED or PROGRAM_STATE_BACKGROUND or PROGRAM_STATE_ACTIVE - specifies whether this program is running. - var/program_state = PROGRAM_STATE_KILLED - /// Device that runs this program. - var/obj/item/modular_computer/computer - /// User-friendly name of this program. - var/filedesc = "Unknown Program" - /// Short description of this program's function. - var/extended_desc = "N/A" - /// Program-specific screen icon state. - var/program_icon_state = null - /// Program-specific keyboard icon state. - var/program_key_state = "standby_key" - /// Icon to use for program's link in main menu. - var/program_menu_icon = "newwin" - /// Set to TRUE for program to require nonstop NTNet connection to run. If NTNet connection is lost program crashes. - var/requires_ntnet = FALSE - /// Optional, if above is set to TRUE checks for specific function of NTNet (currently NTNET_SOFTWAREDOWNLOAD, NTNET_PEERTOPEER, NTNET_SYSTEMCONTROL and NTNET_COMMUNICATION) - var/requires_ntnet_feature = FALSE - /// NTNet status, updated every tick by computer running this program. Don't use this for checks if NTNet works, computers do that. Use this for calculations, etc. - var/ntnet_status = 1 - /// Bitflags (PROGRAM_CONSOLE, PROGRAM_LAPTOP, PROGRAM_TABLET combination) or PROGRAM_ALL - var/usage_flags = PROGRAM_ALL - /// Optional string that describes what NTNet server/system this program connects to. Used in default logging. - var/network_destination = null - /// Whether the program can be downloaded from NTNet. Set to FALSE to disable. - var/available_on_ntnet = TRUE - /// Whether the program can be downloaded from SyndiNet (accessible via emagging the computer). Set to TRUE to enable. - var/available_on_syndinet = FALSE - /// Set to TRUE if computer that's running us was emagged. Computer updates this every Process() tick - var/computer_emagged = FALSE - /// Example: "something.gif" - a header image that will be rendered in computer's UI when this program is running at background. Images are taken from /nano/images/status_icons. Be careful not to use too large images! - var/ui_header = null - /// GQ/s - current network connectivity transfer rate. - var/ntnet_speed = 0 - -/datum/computer_file/program/New(obj/item/modular_computer/comp = null) +/datum/computer_file/program/New(var/obj/item/modular_computer/comp = null) ..() if(comp && istype(comp)) computer = comp @@ -67,13 +38,15 @@ computer = null . = ..() -/datum/computer_file/program/nano_host() - return computer.nano_host() +/datum/computer_file/program/ui_host() + return computer.ui_host() + +/datum/computer_file/program/ui_host() + return computer.ui_host() /datum/computer_file/program/clone() var/datum/computer_file/program/temp = ..() temp.required_access = required_access - temp.nanomodule_path = nanomodule_path temp.filedesc = filedesc temp.program_icon_state = program_icon_state temp.requires_ntnet = requires_ntnet @@ -81,33 +54,33 @@ temp.usage_flags = usage_flags return temp -/// Relays icon update to the computer. +// Relays icon update to the computer. /datum/computer_file/program/proc/update_computer_icon() if(computer) computer.update_icon() -/// Attempts to create a log in global ntnet datum. Returns TRUE on success, FALSE on fail. -/datum/computer_file/program/proc/generate_network_log(text) +// Attempts to create a log in global ntnet datum. Returns 1 on success, 0 on fail. +/datum/computer_file/program/proc/generate_network_log(var/text) if(computer) return computer.add_log(text) - return FALSE + return 0 -/datum/computer_file/program/proc/is_supported_by_hardware(hardware_flag = 0, loud = FALSE, mob/user = null) +/datum/computer_file/program/proc/is_supported_by_hardware(var/hardware_flag = 0, var/loud = 0, var/mob/user = null) if(!(hardware_flag & usage_flags)) if(loud && computer && user) - to_chat(user, SPAN_WARNING("\The [computer] flashes: \"Hardware Error - Incompatible software\".")) - return FALSE - return TRUE + to_chat(user, "\The [computer] flashes: \"Hardware Error - Incompatible software\".") + return 0 + return 1 -/datum/computer_file/program/proc/get_signal(specific_action = 0) +/datum/computer_file/program/proc/get_signal(var/specific_action = 0) if(computer) return computer.get_ntnet_status(specific_action) - return FALSE + return 0 -/// Called by Process() on device that runs us, once every tick. +// Called by Process() on device that runs us, once every tick. /datum/computer_file/program/proc/process_tick() update_netspeed() - return TRUE + return 1 /datum/computer_file/program/proc/update_netspeed() ntnet_speed = 0 @@ -119,113 +92,134 @@ if(3) ntnet_speed = NTNETSPEED_ETHERNET -/** - * Check if the user can run program. Only humans can operate computer. Automatically called in run_program() - * User has to wear their ID or have it inhand for ID Scan to work. - * Can also be called manually, with optional parameter being access_to_check to scan the user's ID - */ -/datum/computer_file/program/proc/can_run(mob/living/user, loud = FALSE, access_to_check) +// Check if the user can run program. Only humans can operate computer. Automatically called in run_program() +// User has to wear their ID or have it inhand for ID Scan to work. +// Can also be called manually, with optional parameter being access_to_check to scan the user's ID +/datum/computer_file/program/proc/can_run(var/mob/living/user, var/loud = 0, var/access_to_check) // Defaults to required_access if(!access_to_check) access_to_check = required_access if(!access_to_check) // No required_access, allow it. - return TRUE + return 1 // Admin override - allows operation of any computer as aghosted admin, as if you had any required access. - if(istype(user, /mob/observer/dead) && check_rights(R_ADMIN, 0, user)) - return TRUE + if(istype(user, /mob/observer/dead) && check_rights(R_ADMIN|R_EVENT, 0, user)) + return 1 if(!istype(user)) - return FALSE + return 0 var/obj/item/card/id/I = user.GetIdCard() if(!I) if(loud) - to_chat(user, SPAN_NOTICE("\The [computer] flashes an \"RFID Error - Unable to scan ID\" warning.")) - return FALSE + to_chat(user, "\The [computer] flashes an \"RFID Error - Unable to scan ID\" warning.") + return 0 if(access_to_check in I.access) - return TRUE + return 1 else if(loud) - to_chat(user, SPAN_NOTICE("\The [computer] flashes an \"Access Denied\" warning.")) + to_chat(user, "\The [computer] flashes an \"Access Denied\" warning.") -/** - * This attempts to retrieve header data for NanoUIs. If implementing completely new device of different type than existing ones - * always include the device here in this proc. This proc basically relays the request to whatever is running the program. - */ +// This attempts to retrieve header data for NanoUIs. If implementing completely new device of different type than existing ones +// always include the device here in this proc. This proc basically relays the request to whatever is running the program. /datum/computer_file/program/proc/get_header_data() if(computer) return computer.get_header_data() return list() -/** - * This is performed on program startup. May be overriden to add extra logic. Remember to include ..() call. Return 1 on success, 0 on failure. - * When implementing new program based device, use this to run the program. - */ -/datum/computer_file/program/proc/run_program(mob/living/user) +// This is performed on program startup. May be overridden to add extra logic. Remember to include ..() call. Return 1 on success, 0 on failure. +// When implementing new program based device, use this to run the program. +/datum/computer_file/program/proc/run_program(var/mob/living/user) if(can_run(user, 1) || !requires_access_to_run) computer.active_program = src - if(nanomodule_path) - NM = new nanomodule_path(src, new /datum/topic_manager/program(src), src) - NM.using_access = user.GetAccess() if(tguimodule_path) TM = new tguimodule_path(src) TM.using_access = user.GetAccess() - TM.ui_interact(user) if(requires_ntnet && network_destination) generate_network_log("Connection opened to [network_destination].") program_state = PROGRAM_STATE_ACTIVE - return TRUE - return FALSE + return 1 + return 0 -/// Use this proc to kill the program. Designed to be implemented by each program if it requires on-quit logic, such as the NTNRC client. -/datum/computer_file/program/proc/kill_program(forced = FALSE) +// Use this proc to kill the program. Designed to be implemented by each program if it requires on-quit logic, such as the NTNRC client. +/datum/computer_file/program/proc/kill_program(var/forced = 0) program_state = PROGRAM_STATE_KILLED if(network_destination) generate_network_log("Connection to [network_destination] closed.") - QDEL_NULL(NM) if(TM) SStgui.close_uis(TM) - qdel(TM) - TM = null - return TRUE + QDEL_NULL(TM) + return 1 -/** - * This is called every tick when the program is enabled. Ensure you do parent call if you override it. If parent returns TRUE continue with UI initialisation. - * It returns FALSE if it can't run or if NanoModule was used instead. I suggest using NanoModules where applicable. - */ -/datum/computer_file/program/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, force_open = TRUE) - if(program_state != PROGRAM_STATE_ACTIVE) // Our program was closed. Close the ui if it exists. +/datum/computer_file/program/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/simple/headers) + ) + +/datum/computer_file/program/ui_interact(mob/user, datum/tgui/ui) + if(program_state != PROGRAM_STATE_ACTIVE) if(ui) ui.close() - return computer.nano_ui_interact(user) - if(istype(NM)) - NM.nano_ui_interact(user, ui_key, null, force_open) - return FALSE + return computer.ui_interact(user) if(istype(TM)) TM.ui_interact(user) - return FALSE - return TRUE + return 0 + ui = SStgui.try_update_ui(user, src, ui) + if(!ui && tgui_id) + ui = new(user, src, tgui_id, filedesc) + ui.open() + return 1 -/** - *! CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC: - * - * Topic calls are automagically forwarded from NanoModule this program contains. - * Calls beginning with "PRG_" are reserved for programs handling. - * Calls beginning with "PC_" are reserved for computer handling (by whatever runs the program) - * - *! ALWAYS INCLUDE PARENT CALL ..() OR DIE IN FIRE. - */ +// CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC: +// Topic calls are automagically forwarded from NanoModule this program contains. +// Calls beginning with "PRG_" are reserved for programs handling. +// Calls beginning with "PC_" are reserved for computer handling (by whatever runs the program) +// ALWAYS INCLUDE PARENT CALL ..() OR DIE IN FIRE. /datum/computer_file/program/Topic(href, href_list) if(..()) return 1 if(computer) return computer.Topic(href, href_list) -/// Relays the call to nano module, if we have one -/datum/computer_file/program/proc/check_eye(mob/user) - if(NM) - return NM.check_eye(user) +// CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC: +// Topic calls are automagically forwarded from NanoModule this program contains. +// Calls beginning with "PRG_" are reserved for programs handling. +// Calls beginning with "PC_" are reserved for computer handling (by whatever runs the program) +// ALWAYS INCLUDE PARENT CALL ..() OR DIE IN FIRE. +/datum/computer_file/program/ui_act(action,list/params, datum/tgui/ui) + if(..()) + return 1 + if(computer) + switch(action) + if("PC_exit") + computer.kill_program() + ui.close() + return 1 + if("PC_shutdown") + computer.shutdown_computer() + ui.close() + return 1 + if("PC_minimize") + var/mob/user = usr + if(!computer.active_program) + return + + computer.idle_threads.Add(computer.active_program) + program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs + + computer.active_program = null + computer.update_icon() + ui.close() + + if(user && istype(user)) + computer.ui_interact(user) // Re-open the UI on this computer. It should show the main screen now. + + + +// Relays the call to nano module, if we have one +/datum/computer_file/program/proc/check_eye(var/mob/user) + if(TM) + return TM.check_eye(user) else return -1 @@ -235,6 +229,10 @@ /obj/item/modular_computer/update_layout() return TRUE +/datum/computer_file/program/proc/relaymove(var/mob/M, direction) + if(TM) + return TM.relaymove(M, direction) + /datum/nano_module/program /// Program-Based computer program that runs this nano module. Defaults to null. var/datum/computer_file/program/program = null @@ -251,9 +249,5 @@ ..() src.program = program -/** - * Calls forwarded to PROGRAM itself should begin with "PRG_" - * Calls forwarded to COMPUTER running the program should begin with "PC_" - */ /datum/topic_manager/program/Topic(href, href_list) return program && program.Topic(href, href_list) diff --git a/code/modules/modular_computers/file_system/program_events.dm b/code/modules/modular_computers/file_system/program_events.dm index 02d196ba618..ef1eac09aa9 100644 --- a/code/modules/modular_computers/file_system/program_events.dm +++ b/code/modules/modular_computers/file_system/program_events.dm @@ -1,20 +1,18 @@ -/** - * Events are sent to the program by the computer. - * Always include a parent call when overriding an event. - */ +// Events are sent to the program by the computer. +// Always include a parent call when overriding an event. -/// Called when the ID card is removed from computer. ID is removed AFTER this proc. -/datum/computer_file/program/proc/event_idremoved(background) +// Called when the ID card is removed from computer. ID is removed AFTER this proc. +/datum/computer_file/program/proc/event_idremoved(var/background) return -/// Called when the computer fails due to power loss. Override when program wants to specifically react to power loss. -/datum/computer_file/program/proc/event_powerfailure(background) +// Called when the computer fails due to power loss. Override when program wants to specifically react to power loss. +/datum/computer_file/program/proc/event_powerfailure(var/background) kill_program(1) -/// Called when the network connectivity fails. Computer does necessary checks and only calls this when requires_ntnet_feature and similar variables are not met. -/datum/computer_file/program/proc/event_networkfailure(background) +// Called when the network connectivity fails. Computer does necessary checks and only calls this when requires_ntnet_feature and similar variables are not met. +/datum/computer_file/program/proc/event_networkfailure(var/background) kill_program(1) if(background) - computer.visible_message(SPAN_WARNING("\The [computer]'s screen displays an error: \"Network connectivity lost - process [filename].[filetype] (PID [rand(100,999)]) terminated.\"")) + computer.visible_message("\The [computer]'s screen displays an error: \"Network connectivity lost - process [filename].[filetype] (PID [rand(100,999)]) terminated.\"") else - computer.visible_message(SPAN_WARNING("\The [computer]'s screen briefly freezes and then shows: \"FATAL NETWORK ERROR - NTNet connection lost. Please try again later. If problem persists, please contact your system administrator.\"")) + computer.visible_message("\The [computer]'s screen briefly freezes and then shows: \"FATAL NETWORK ERROR - NTNet connection lost. Please try again later. If problem persists, please contact your system administrator.\"") diff --git a/code/modules/modular_computers/file_system/programs/antagonist/access_decrypter.dm b/code/modules/modular_computers/file_system/programs/antagonist/access_decrypter.dm index aeef84be9ed..959ee3ee218 100644 --- a/code/modules/modular_computers/file_system/programs/antagonist/access_decrypter.dm +++ b/code/modules/modular_computers/file_system/programs/antagonist/access_decrypter.dm @@ -6,15 +6,17 @@ program_menu_icon = "unlocked" extended_desc = "This highly advanced script can very slowly decrypt operational codes used in almost any network. These codes can be downloaded to an ID card to expand the available access. The system administrator will probably notice this." size = 34 - requires_ntnet = 1 - available_on_ntnet = 0 - available_on_syndinet = 1 - nanomodule_path = /datum/nano_module/program/access_decrypter/ + requires_ntnet = TRUE + available_on_ntnet = FALSE + available_on_syndinet = TRUE + tgui_id = "NtosAccessDecrypter" + var/message = "" var/running = FALSE var/progress = 0 var/target_progress = 300 var/datum/access/target_access = null + var/list/restricted_access_codes = list(ACCESS_COMMAND_CARDMOD, ACCESS_NETWORK) // access codes that are not hackable due to balance reasons /datum/computer_file/program/access_decrypter/kill_program(var/forced) reset() @@ -48,82 +50,63 @@ message = "Successfully decrypted and saved operational key codes. Downloaded access codes for: [target_access.access_name]" target_access = null -/datum/computer_file/program/access_decrypter/Topic(href, href_list) +/datum/computer_file/program/access_decrypter/ui_act(action, list/params, datum/tgui/ui) if(..()) - return 1 - if(href_list["PRG_reset"]) - reset() - return 1 - if(href_list["PRG_execute"]) - if(running) - return 1 - if(text2num(href_list["allowed"])) - return 1 - var/obj/item/computer_hardware/processor_unit/CPU = computer.processor_unit - var/obj/item/computer_hardware/card_slot/RFID = computer.card_slot - if(!istype(CPU) || !CPU.check_functionality() || !istype(RFID) || !RFID.check_functionality()) - message = "A fatal hardware error has been detected." - return - if(!istype(RFID.stored_card)) - message = "RFID card is not present in the device. Operation aborted." - return - running = TRUE - target_access = get_access_by_id(href_list["PRG_execute"]) - if(ntnet_global.intrusion_detection_enabled) - ntnet_global.add_log("IDS WARNING - Unauthorised access attempt to primary keycode database from device: [computer.network_card.get_network_tag()]") - ntnet_global.intrusion_detection_alarm = 1 - return 1 + return TRUE + switch(action) + if("PRG_reset") + reset() + return TRUE + if("PRG_execute") + if(running) + return TRUE + if(text2num(params["allowed"])) + return TRUE + var/obj/item/computer_hardware/processor_unit/CPU = computer.processor_unit + var/obj/item/computer_hardware/card_slot/RFID = computer.card_slot + if(!istype(CPU) || !CPU.check_functionality() || !istype(RFID) || !RFID.check_functionality()) + message = "A fatal hardware error has been detected." + return + if(!istype(RFID.stored_card)) + message = "RFID card is not present in the device. Operation aborted." + return + running = TRUE + target_access = get_access_by_id("[params["access_target"]]") + if(ntnet_global.intrusion_detection_enabled) + ntnet_global.add_log("IDS WARNING - Unauthorised access attempt to primary keycode database from device: [computer.network_card.get_network_tag()]") + ntnet_global.intrusion_detection_alarm = TRUE + return TRUE -/datum/nano_module/program/access_decrypter - name = "NTNet Access Decrypter" - var/list/restricted_access_codes = list(ACCESS_COMMAND_CARDMOD, ACCESS_SCIENCE_EXONET) // access codes that are not hackable due to balance reasons - -/datum/nano_module/program/access_decrypter/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) +/datum/computer_file/program/access_decrypter/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) if(!ntnet_global) return - var/datum/computer_file/program/access_decrypter/PRG = program - var/list/data = list() - if(!istype(PRG)) - return - data = PRG.get_header_data() + var/list/data = get_header_data() - if(PRG.message) - data["message"] = PRG.message - else if(PRG.running) + var/list/regions = list() + data["message"] = null + data["running"] = running + if(message) + data["message"] = message + else if(running) data["running"] = 1 - data["rate"] = PRG.computer.processor_unit.max_idle_programs - - // Stolen from DOS traffic generator, generates strings of 1s and 0s - var/percentage = (PRG.progress / PRG.target_progress) * 100 - var/list/strings[0] - for(var/j, j<10, j++) - var/string = "" - for(var/i, i<20, i++) - string = "[string][prob(percentage)]" - strings.Add(string) - data["dos_strings"] = strings - else if(program.computer.card_slot && program.computer.card_slot.stored_card) - var/obj/item/card/id/id_card = program.computer.card_slot.stored_card - var/list/regions = list() + data["rate"] = computer.processor_unit.max_idle_programs + data["factor"] = (progress / target_progress) + else if(computer?.card_slot?.stored_card) + var/obj/item/card/id/id_card = computer.card_slot.stored_card for(var/i = 1; i <= 7; i++) var/list/accesses = list() for(var/access in get_region_accesses(i)) - if (get_access_desc(access)) + if(get_access_desc(access) && !(access in restricted_access_codes)) accesses.Add(list(list( - "desc" = replacetext(get_access_desc(access), " ", " "), + "desc" = replacetext(get_access_desc(access), " ", " "), "ref" = access, - "allowed" = (access in id_card.access) ? 1 : 0, - "blocked" = (access in restricted_access_codes) ? 1 : 0))) + "allowed" = (access in id_card.access) ? 1 : 0 + ))) regions.Add(list(list( "name" = get_region_accesses_name(i), - "accesses" = accesses))) - data["regions"] = regions + "accesses" = accesses + ))) + data["regions"] = regions - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "access_decrypter.tmpl", "NTNet Access Decrypter", 550, 400, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data diff --git a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm index 43edc387015..a329f183466 100644 --- a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm +++ b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm @@ -6,10 +6,11 @@ program_menu_icon = "arrow-4-diag" extended_desc = "This advanced script can perform denial of service attacks against NTNet quantum relays. The system administrator will probably notice this. Multiple devices can run this program together against same relay for increased effect" size = 20 - requires_ntnet = 1 - available_on_ntnet = 0 - available_on_syndinet = 1 - nanomodule_path = /datum/nano_module/program/computer_dos/ + requires_ntnet = TRUE + available_on_ntnet = FALSE + available_on_syndinet = TRUE + tgui_id = "NtosNetDos" + var/obj/machinery/ntnet_relay/target = null var/dos_speed = 0 var/error = "" @@ -39,70 +40,51 @@ ..(forced) -/datum/nano_module/program/computer_dos - name = "DoS Traffic Generator" - -/datum/nano_module/program/computer_dos/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) +/datum/computer_file/program/ntnet_dos/ui_data(mob/user) if(!ntnet_global) return - var/datum/computer_file/program/ntnet_dos/PRG = program - var/list/data = list() - if(!istype(PRG)) - return - data = PRG.get_header_data() - if(PRG.error) - data["error"] = PRG.error - else if(PRG.target && PRG.executed) - data["target"] = 1 - data["speed"] = PRG.dos_speed + var/list/data = get_header_data() - // This is mostly visual, generate some strings of 1s and 0s - // Probability of 1 is equal of completion percentage of DoS attack on this relay. - // Combined with UI updates this adds quite nice effect to the UI - var/percentage = PRG.target.dos_overload * 100 / PRG.target.dos_capacity - var/list/strings[0] - for(var/j, j<10, j++) - var/string = "" - for(var/i, i<20, i++) - string = "[string][prob(percentage)]" - strings.Add(string) - data["dos_strings"] = strings + data["error"] = error + if(target && executed) + data["target"] = TRUE + data["speed"] = dos_speed + + data["overload"] = target.dos_overload + data["capacity"] = target.dos_capacity else - var/list/relays[0] + data["target"] = FALSE + data["relays"] = list() for(var/obj/machinery/ntnet_relay/R in ntnet_global.relays) - relays.Add(R.uid) - data["relays"] = relays - data["focus"] = PRG.target ? PRG.target.uid : null + data["relays"] += list(list("id" = R.uid)) + data["focus"] = target ? target.uid : null - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "ntnet_dos.tmpl", "DoS Traffic Generator", 400, 250, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data -/datum/computer_file/program/ntnet_dos/Topic(href, href_list) +/datum/computer_file/program/ntnet_dos/ui_act(action, params) if(..()) - return 1 - if(href_list["PRG_target_relay"]) - for(var/obj/machinery/ntnet_relay/R in ntnet_global.relays) - if("[R.uid]" == href_list["PRG_target_relay"]) - target = R - return 1 - if(href_list["PRG_reset"]) - if(target) - target.dos_sources.Remove(src) - target = null - executed = 0 - error = "" - return 1 - if(href_list["PRG_execute"]) - if(target) - executed = 1 - target.dos_sources.Add(src) - if(ntnet_global.intrusion_detection_enabled) - ntnet_global.add_log("IDS WARNING - Excess traffic flood targeting relay [target.uid] detected from device: [computer.network_card.get_network_tag()]") - ntnet_global.intrusion_detection_alarm = 1 - return 1 + return TRUE + switch(action) + if("PRG_target_relay") + for(var/obj/machinery/ntnet_relay/R in ntnet_global.relays) + if(R.uid == text2num(params["targid"])) + target = R + break + return TRUE + if("PRG_reset") + if(target) + target.dos_sources.Remove(src) + target = null + executed = FALSE + error = "" + return TRUE + if("PRG_execute") + if(target) + executed = TRUE + target.dos_sources.Add(src) + if(ntnet_global.intrusion_detection_enabled) + var/obj/item/computer_hardware/network_card/network_card = computer.network_card + ntnet_global.add_log("IDS WARNING - Excess traffic flood targeting relay [target.uid] detected from device: [network_card.get_network_tag()]") + ntnet_global.intrusion_detection_alarm = TRUE + return TRUE diff --git a/code/modules/modular_computers/file_system/programs/antagonist/hacked_camera.dm b/code/modules/modular_computers/file_system/programs/antagonist/hacked_camera.dm index bb00c6eee13..7ce78726350 100644 --- a/code/modules/modular_computers/file_system/programs/antagonist/hacked_camera.dm +++ b/code/modules/modular_computers/file_system/programs/antagonist/hacked_camera.dm @@ -15,7 +15,6 @@ if(program_state != PROGRAM_STATE_ACTIVE) // Background programs won't trigger alarms. return - // The program is active and connected to one of the station's networks. Has a very small chance to trigger IDS alarm every tick. if(prob(0.1)) if(ntnet_global.intrusion_detection_enabled) diff --git a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm index 7f19e365e35..595c79f6cfd 100644 --- a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm +++ b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm @@ -6,10 +6,10 @@ program_menu_icon = "home" extended_desc = "This virus can destroy hard drive of system it is executed on. It may be obfuscated to look like another non-malicious program. Once armed, it will destroy the system upon next execution." size = 13 - requires_ntnet = 0 - available_on_ntnet = 0 - available_on_syndinet = 1 - nanomodule_path = /datum/nano_module/program/revelation/ + requires_ntnet = FALSE + available_on_ntnet = FALSE + available_on_syndinet = TRUE + tgui_id = "NtosRevelation" var/armed = 0 /datum/computer_file/program/revelation/run_program(var/mob/living/user) @@ -37,48 +37,31 @@ if(computer.tesla_link && prob(50)) qdel(computer.tesla_link) -/datum/computer_file/program/revelation/Topic(href, href_list) +/datum/computer_file/program/revelation/ui_act(action, params) if(..()) - return 1 - else if(href_list["PRG_arm"]) - armed = !armed - else if(href_list["PRG_activate"]) - activate() - else if(href_list["PRG_obfuscate"]) - var/mob/living/user = usr - var/newname = sanitize(input(user, "Enter new program name: ")) - if(!newname) - return - filedesc = newname - for(var/datum/computer_file/program/P in ntnet_global.available_station_software) - if(filedesc == P.filedesc) - program_menu_icon = P.program_menu_icon - break - return 1 + return + switch(action) + if("PRG_arm") + armed = !armed + return TRUE + if("PRG_activate") + activate() + return TRUE + if("PRG_obfuscate") + var/newname = params["new_name"] + if(!newname) + return + filedesc = newname + return TRUE /datum/computer_file/program/revelation/clone() var/datum/computer_file/program/revelation/temp = ..() temp.armed = armed return temp -/datum/nano_module/program/revelation - name = "Revelation Virus" +/datum/computer_file/program/revelation/ui_data(mob/user) + var/list/data = get_header_data() -/datum/nano_module/program/revelation/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = list() - var/datum/computer_file/program/revelation/PRG = program - if(!istype(PRG)) - return - - data = PRG.get_header_data() - - data["armed"] = PRG.armed - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "revelation.tmpl", "Revelation Virus", 400, 250, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + data["armed"] = armed + return data diff --git a/code/modules/modular_computers/file_system/programs/command/card.dm b/code/modules/modular_computers/file_system/programs/command/card.dm index 83aacbfa7d5..3036fab9d87 100644 --- a/code/modules/modular_computers/file_system/programs/command/card.dm +++ b/code/modules/modular_computers/file_system/programs/command/card.dm @@ -1,7 +1,7 @@ /datum/computer_file/program/card_mod filename = "cardmod" filedesc = "ID card modification program" - nanomodule_path = /datum/nano_module/program/card_mod + tgui_id = "NtosIdentificationComputer" program_icon_state = "id" program_key_state = "id_key" program_menu_icon = "key" @@ -9,217 +9,30 @@ required_access = ACCESS_COMMAND_CARDMOD requires_ntnet = 0 size = 8 + var/datum/tgui_module/card_mod/standard/id_computer/ntos/tgui_cardmod -/datum/nano_module/program/card_mod - name = "ID card modification program" - var/mod_mode = 1 - var/is_centcom = 0 - var/show_assignments = 0 +/datum/computer_file/program/card_mod/New() + tgui_cardmod = new(src) -/datum/nano_module/program/card_mod/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() +/datum/computer_file/program/card_mod/Destroy() + . = ..() + QDEL_NULL(tgui_cardmod) - data["src"] = "\ref[src]" - data["station_name"] = station_name() - data["manifest"] = data_core ? data_core.get_manifest(0) : null - data["assignments"] = show_assignments - if(program && program.computer) - data["have_id_slot"] = !!program.computer.card_slot - data["have_printer"] = !!program.computer.nano_printer - data["authenticated"] = program.can_run(user) - if(!program.computer.card_slot) - mod_mode = 0 //We can't modify IDs when there is no card reader - else - data["have_id_slot"] = 0 - data["have_printer"] = 0 - data["authenticated"] = 0 - data["mmode"] = mod_mode - data["centcom_access"] = is_centcom +/datum/computer_file/program/card_mod/ui_static_data(mob/user, datum/tgui/ui, datum/ui_state/state) + . = get_header_data() - if(program && program.computer && program.computer.card_slot) - var/obj/item/card/id/id_card = program.computer.card_slot.stored_card - data["has_id"] = !!id_card - data["id_account_number"] = id_card ? id_card.associated_account_number : null - data["id_rank"] = id_card && id_card.assignment ? id_card.assignment : "Unassigned" - data["id_owner"] = id_card && id_card.registered_name ? id_card.registered_name : "-----" - data["id_name"] = id_card ? id_card.name : "-----" +/datum/computer_file/program/card_mod/ui_module_route(action, list/params, datum/tgui/ui, id) + . = ..() + if(.) + return + switch(id) + if("modify") + return tgui_cardmod.ui_act(action, params, ui) - data["command_jobs"] = format_jobs(SSjob.get_job_titles_in_department(DEPARTMENT_COMMAND)) - data["engineering_jobs"] = format_jobs(SSjob.get_job_titles_in_department(DEPARTMENT_ENGINEERING)) - data["medical_jobs"] = format_jobs(SSjob.get_job_titles_in_department(DEPARTMENT_MEDICAL)) - data["science_jobs"] = format_jobs(SSjob.get_job_titles_in_department(DEPARTMENT_RESEARCH)) - data["security_jobs"] = format_jobs(SSjob.get_job_titles_in_department(DEPARTMENT_SECURITY)) - data["cargo_jobs"] = format_jobs(SSjob.get_job_titles_in_department(DEPARTMENT_CARGO)) - data["civilian_jobs"] = format_jobs(SSjob.get_job_titles_in_department(DEPARTMENT_CIVILIAN)) - data["centcom_jobs"] = format_jobs(get_all_centcom_jobs()) +/datum/computer_file/program/card_mod/ui_module_data(mob/user, datum/tgui/ui, datum/ui_state/state) + . = ..() + .["modify"] = tgui_cardmod.data(user, computer.card_slot.stored_card, user.GetIdCard()) - data["all_centcom_access"] = is_centcom ? get_accesses(1) : null - data["regions"] = get_accesses() - - if(program.computer.card_slot && program.computer.card_slot.stored_card) - var/obj/item/card/id/id_card = program.computer.card_slot.stored_card - if(is_centcom) - var/list/all_centcom_access = list() - for(var/access in get_all_centcom_access()) - all_centcom_access.Add(list(list( - "desc" = replacetext(get_centcom_access_desc(access), " ", " "), - "ref" = access, - "allowed" = (access in id_card.access) ? 1 : 0))) - data["all_centcom_access"] = all_centcom_access - else - var/list/regions = list() - for(var/i = 1; i <= 7; i++) - var/list/accesses = list() - for(var/access in get_region_accesses(i)) - if (get_access_desc(access)) - accesses.Add(list(list( - "desc" = replacetext(get_access_desc(access), " ", " "), - "ref" = access, - "allowed" = (access in id_card.access) ? 1 : 0))) - - regions.Add(list(list( - "name" = get_region_accesses_name(i), - "accesses" = accesses))) - data["regions"] = regions - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "mod_identification_computer.tmpl", name, 600, 700, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - -/datum/nano_module/program/card_mod/proc/format_jobs(list/jobs) - var/obj/item/card/id/id_card = program.computer.card_slot ? program.computer.card_slot.stored_card : null - var/list/formatted = list() - for(var/job in jobs) - formatted.Add(list(list( - "display_name" = replacetext(job, " ", " "), - "target_rank" = id_card && id_card.assignment ? id_card.assignment : "Unassigned", - "job" = job))) - - return formatted - -/datum/nano_module/program/card_mod/proc/get_accesses(var/is_centcom = 0) - return null - - -/datum/computer_file/program/card_mod/Topic(href, href_list) - if(..()) - return 1 - - var/mob/user = usr - var/obj/item/card/id/user_id_card = user.GetIdCard() - var/obj/item/card/id/id_card - if (computer.card_slot) - id_card = computer.card_slot.stored_card - - var/datum/nano_module/program/card_mod/module = NM - switch(href_list["action"]) - if("switchm") - if(href_list["target"] == "mod") - module.mod_mode = 1 - else if (href_list["target"] == "manifest") - module.mod_mode = 0 - if("togglea") - if(module.show_assignments) - module.show_assignments = 0 - else - module.show_assignments = 1 - if("print") - if(computer && computer.nano_printer) //This option should never be called if there is no printer - if(module.mod_mode) - if(can_run(user, 1)) - var/contents = {"

Access Report

- Prepared By: [user_id_card.registered_name ? user_id_card.registered_name : "Unknown"]
- For: [id_card.registered_name ? id_card.registered_name : "Unregistered"]
-
- Assignment: [id_card.assignment]
- Account Number: #[id_card.associated_account_number]
- Blood Type: [id_card.blood_type]

- Access:
- "} - - var/known_access_rights = get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM) - for(var/A in id_card.access) - if(A in known_access_rights) - contents += " [get_access_desc(A)]" - - if(!computer.nano_printer.print_text(contents,"access report")) - to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.") - return - else - computer.visible_message("\The [computer] prints out paper.") - else - var/contents = {"

Crew Manifest

-
- [data_core ? data_core.get_manifest(0) : ""] - "} - if(!computer.nano_printer.print_text(contents, "crew manifest ([stationtime2text()])")) - to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.") - return - else - computer.visible_message("\The [computer] prints out paper.") - if("eject") - if(computer && computer.card_slot) - if(id_card) - data_core.manifest_modify(id_card.registered_name, id_card.assignment) - computer.proc_eject_id(user) - if("terminate") - if(computer && can_run(user, 1)) - id_card.assignment = "Dismissed" - id_card.access = list() - if("edit") - if(computer && can_run(user, 1)) - if(href_list["name"]) - var/temp_name = sanitizeName(input("Enter name.", "Name", id_card.registered_name)) - if(temp_name) - id_card.registered_name = temp_name - else - computer.visible_message("[computer] buzzes rudely.") - else if(href_list["account"]) - var/account_num = text2num(input("Enter account number.", "Account", id_card.associated_account_number)) - id_card.associated_account_number = account_num - if("assign") - if(computer && can_run(user, 1) && id_card) - var/t1 = href_list["assign_target"] - if(t1 == "Custom") - var/temp_t = sanitize(input("Enter a custom job assignment.","Assignment", id_card.assignment), 45) - //let custom jobs function as an impromptu alt title, mainly for sechuds - if(temp_t) - id_card.assignment = temp_t - else - var/list/access = list() - if(module.is_centcom) - access = get_centcom_access(t1) - else - var/datum/role/job/jobdatum - for(var/jobtype in typesof(/datum/role/job)) - var/datum/role/job/J = new jobtype - if(ckey(J.title) == ckey(t1)) - jobdatum = J - break - if(!jobdatum) - to_chat(usr, "No log exists for this job: [t1]") - return - - access = jobdatum.get_access() - - id_card.access = access - id_card.assignment = t1 - id_card.rank = t1 - - callHook("reassign_employee", list(id_card)) - if("access") - if(href_list["allowed"] && computer && can_run(user, 1)) - var/access_type = text2num(href_list["access_target"]) - var/access_allowed = text2num(href_list["allowed"]) - if(access_type in get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM)) - id_card.access -= access_type - if(!access_allowed) - id_card.access += access_type - if(id_card) - id_card.name = "[id_card.registered_name]'s ID Card ([id_card.assignment])" - - SSnanoui.update_uis(NM) - return 1 +/datum/computer_file/program/card_mod/ui_module_static(mob/user, datum/tgui/ui, datum/ui_state/state) + . = ..() + .["modify"] = tgui_cardmod.static_data(user, computer.card_slot.stored_card, user.GetIdCard()) diff --git a/code/modules/modular_computers/file_system/programs/command/comm.dm b/code/modules/modular_computers/file_system/programs/command/comm.dm index f1581da60aa..38c846e67bb 100644 --- a/code/modules/modular_computers/file_system/programs/command/comm.dm +++ b/code/modules/modular_computers/file_system/programs/command/comm.dm @@ -9,7 +9,7 @@ program_icon_state = "comm" program_key_state = "med_key" program_menu_icon = "flag" - nanomodule_path = /datum/nano_module/program/comm + tguimodule_path = /datum/tgui_module_old/communications/ntos extended_desc = "Used to command and control. Can relay long-range communications. This program can not be run on tablet computers." required_access = ACCESS_COMMAND_BRIDGE requires_ntnet = 1 @@ -24,272 +24,12 @@ temp.message_core.messages = message_core.messages.Copy() return temp -/datum/nano_module/program/comm - name = "Command and Communications Program" - //available_to_ai = TRUE - var/current_status = STATE_DEFAULT - var/msg_line1 = "" - var/msg_line2 = "" - var/centcomm_message_cooldown = 0 - var/announcment_cooldown = 0 - var/datum/legacy_announcement/priority/crew_announcement = new - var/current_viewing_message_id = 0 - var/current_viewing_message = null - -/datum/nano_module/program/comm/New() - ..() - crew_announcement.newscast = 1 - -/datum/nano_module/program/comm/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() - - if(program) - data["emagged"] = program.computer_emagged - data["net_comms"] = !!program.get_signal(NTNET_COMMUNICATION) //Double !! is needed to get 1 or 0 answer - data["net_syscont"] = !!program.get_signal(NTNET_SYSTEMCONTROL) - if(program.computer) - data["have_printer"] = !!program.computer.nano_printer - else - data["have_printer"] = 0 - else - data["emagged"] = 0 - data["net_comms"] = 1 - data["net_syscont"] = 1 - data["have_printer"] = 0 - - data["message_line1"] = msg_line1 - data["message_line2"] = msg_line2 - data["state"] = current_status - data["isAI"] = issilicon(usr) - data["authenticated"] = get_authentication_level(user) - data["current_security_level"] = GLOB.security_level - data["current_security_level_title"] = num2seclevel(GLOB.security_level) - - data["def_SEC_LEVEL_DELTA"] = SEC_LEVEL_DELTA - data["def_SEC_LEVEL_YELLOW"] = SEC_LEVEL_YELLOW - data["def_SEC_LEVEL_ORANGE"] = SEC_LEVEL_ORANGE - data["def_SEC_LEVEL_VIOLET"] = SEC_LEVEL_VIOLET - data["def_SEC_LEVEL_BLUE"] = SEC_LEVEL_BLUE - data["def_SEC_LEVEL_GREEN"] = SEC_LEVEL_GREEN - - var/datum/comm_message_listener/l = obtain_message_listener() - data["messages"] = l.messages - data["message_deletion_allowed"] = l != global_message_listener - data["message_current_id"] = current_viewing_message_id - if(current_viewing_message) - data["message_current"] = current_viewing_message - - if(SSemergencyshuttle.location()) - data["have_shuttle"] = 1 - if(SSemergencyshuttle.online()) - data["have_shuttle_called"] = 1 - else - data["have_shuttle_called"] = 0 - else - data["have_shuttle"] = 0 - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "mod_communication.tmpl", name, 550, 420, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - -/datum/nano_module/program/comm/proc/get_authentication_level(var/mob/user) - if(program) - if(program.can_run(user, 0, ACCESS_COMMAND_CAPTAIN)) - return 2 - else - return program.can_run(user) - return 1 - -/datum/nano_module/program/comm/proc/obtain_message_listener() - if(program) - var/datum/computer_file/program/comm/P = program - return P.message_core - return global_message_listener - -/datum/nano_module/program/comm/Topic(href, href_list) - if(..()) - return 1 - var/mob/user = usr - var/ntn_comm = program ? !!program.get_signal(NTNET_COMMUNICATION) : 1 - var/ntn_cont = program ? !!program.get_signal(NTNET_SYSTEMCONTROL) : 1 - var/datum/comm_message_listener/l = obtain_message_listener() - switch(href_list["action"]) - if("sw_menu") - . = 1 - current_status = text2num(href_list["target"]) - if("announce") - . = 1 - if(get_authentication_level(user) == 2 && !issilicon(usr) && ntn_comm) - if(user) - var/obj/item/card/id/id_card = user.GetIdCard() - crew_announcement.announcer = GetNameAndAssignmentFromId(id_card) - else - crew_announcement.announcer = "Unknown" - if(announcment_cooldown) - to_chat(usr, "Please allow at least one minute to pass between announcements") - return TRUE - var/input = input(usr, "Please write a message to announce to the station crew.", "Priority Announcement") as null|text - if(!input || !can_still_topic()) - return 1 - crew_announcement.Announce(input) - announcment_cooldown = 1 - spawn(600)//One minute cooldown - announcment_cooldown = 0 - if("message") - . = 1 - if(href_list["target"] == "emagged") - if(program) - if(get_authentication_level(user) == 2 && program.computer_emagged && !issilicon(usr) && ntn_comm) - if(centcomm_message_cooldown) - to_chat(usr, "Arrays recycling. Please stand by.") - SSnanoui.update_uis(src) - return - var/input = sanitize(input(usr, "Please choose a message to transmit to \[ABNORMAL ROUTING CORDINATES\] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", "") as null|text) - if(!input || !can_still_topic()) - return 1 - message_syndicate(input, usr) - to_chat(usr, "Message transmitted.") - log_say("[key_name(usr)] has made an illegal announcement: [input]") - centcomm_message_cooldown = 1 - spawn(300)//30 second cooldown - centcomm_message_cooldown = 0 - else if(href_list["target"] == "regular") - if(get_authentication_level(user) == 2 && !issilicon(usr) && ntn_comm) - if(centcomm_message_cooldown) - to_chat(usr, "Arrays recycling. Please stand by.") - SSnanoui.update_uis(src) - return - if(!is_relay_online())//Contact Centcom has a check, Syndie doesn't to allow for Traitor funs. - to_chat(usr, "No Emergency Bluespace Relay detected. Unable to transmit message.") - return 1 - var/input = sanitize(input("Please choose a message to transmit to Centcomm via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", "") as null|text) - if(!input || !can_still_topic()) - return 1 - message_centcom(input, usr) - to_chat(usr, "Message transmitted.") - log_say("[key_name(usr)] has made an IA Centcomm announcement: [input]") - centcomm_message_cooldown = 1 - spawn(300) //30 second cooldown - centcomm_message_cooldown = 0 - if("shuttle") - . = 1 - if(get_authentication_level(user) && ntn_cont) - if(href_list["target"] == "call") - var/confirm = alert("Are you sure you want to call the shuttle?", name, "No", "Yes") - if(confirm == "Yes" && can_still_topic()) - call_shuttle_proc(usr) - - if(href_list["target"] == "cancel" && !issilicon(usr)) - var/confirm = alert("Are you sure you want to cancel the shuttle?", name, "No", "Yes") - if(confirm == "Yes" && can_still_topic()) - cancel_call_proc(usr) - if("setstatus") - . = 1 - if(get_authentication_level(user) && ntn_cont) - switch(href_list["target"]) - if("line1") - var/linput = reject_bad_text(sanitize(input("Line 1", "Enter Message Text", msg_line1) as text|null, 40), 40) - if(can_still_topic()) - msg_line1 = linput - if("line2") - var/linput = reject_bad_text(sanitize(input("Line 2", "Enter Message Text", msg_line2) as text|null, 40), 40) - if(can_still_topic()) - msg_line2 = linput - if("message") - post_status("message", msg_line1, msg_line2) - if("alert") - post_status("alert", href_list["alert"]) - else - post_status(href_list["target"]) - if("setalert") - . = 1 - if(get_authentication_level(user) && !issilicon(usr) && ntn_cont && ntn_comm) - var/current_level = text2num(href_list["target"]) - var/confirm = alert("Are you sure you want to change alert level to [num2seclevel(current_level)]?", name, "No", "Yes") - if(confirm == "Yes" && can_still_topic()) - var/old_level = GLOB.security_level - if(!current_level) current_level = SEC_LEVEL_GREEN - if(current_level < SEC_LEVEL_GREEN) current_level = SEC_LEVEL_GREEN - if(current_level > SEC_LEVEL_BLUE) current_level = SEC_LEVEL_BLUE //Cannot engage delta with this - set_security_level(current_level) - if(GLOB.security_level != old_level) - log_game("[key_name(usr)] has changed the security level to [get_security_level()].") - message_admins("[key_name_admin(usr)] has changed the security level to [get_security_level()].") - switch(GLOB.security_level) - if(SEC_LEVEL_GREEN) - feedback_inc("alert_comms_green",1) - if(SEC_LEVEL_YELLOW) - feedback_inc("alert_comms_yellow",1) - if(SEC_LEVEL_ORANGE) - feedback_inc("alert_comms_orange",1) - if(SEC_LEVEL_VIOLET) - feedback_inc("alert_comms_violet",1) - if(SEC_LEVEL_BLUE) - feedback_inc("alert_comms_blue",1) - else - to_chat(usr, "You press button, but red light flashes and nothing happens.")//This should never happen - - current_status = STATE_DEFAULT - if("viewmessage") - . = 1 - if(get_authentication_level(user) && ntn_comm) - current_viewing_message_id = text2num(href_list["target"]) - for(var/list/m in l.messages) - if(m["id"] == current_viewing_message_id) - current_viewing_message = m - current_status = STATE_VIEWMESSAGE - if("delmessage") - . = 1 - if(get_authentication_level(user) && ntn_comm && l != global_message_listener) - l.Remove(current_viewing_message) - current_status = STATE_MESSAGELIST - if("printmessage") - . = 1 - if(get_authentication_level(user) && ntn_comm) - if(program && program.computer && program.computer.nano_printer) - if(!program.computer.nano_printer.print_text(current_viewing_message["contents"],current_viewing_message["title"])) - to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.") - else - program.computer.visible_message("\The [program.computer] prints out paper.") - - -/datum/nano_module/program/comm/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 - log_admin("STATUS: [key_name(usr)] set status screen message with [src]: [data1] [data2]") - if("alert") - status_signal.data["picture_state"] = data1 - - frequency.post_signal(src, status_signal) - -#undef STATE_DEFAULT -#undef STATE_MESSAGELIST -#undef STATE_VIEWMESSAGE -#undef STATE_STATUSDISPLAY -#undef STATE_ALERT_LEVEL - /* General message handling stuff */ -var/list/comm_message_listeners = list() //We first have to initialize list then we can use it. -var/datum/comm_message_listener/global_message_listener = new //May be used by admins -var/last_message_id = 0 +var/global/list/comm_message_listeners = list() //We first have to initialize list then we can use it. +var/global/datum/comm_message_listener/global_message_listener = new //May be used by admins +var/global/last_message_id = 0 /proc/get_comm_message_id() last_message_id = last_message_id + 1 @@ -301,19 +41,9 @@ var/last_message_id = 0 message["title"] = message_title message["contents"] = message_text - for (var/datum/comm_message_listener/l in comm_message_listeners) + for(var/datum/comm_message_listener/l in comm_message_listeners) l.Add(message) - //Old console support - for (var/obj/machinery/computer/communications/comm in GLOB.machines) - if (!(comm.machine_stat & (BROKEN | NOPOWER)) && comm.prints_intercept) - var/obj/item/paper/intercept = new /obj/item/paper( comm.loc ) - intercept.name = message_title - intercept.info = message_text - - comm.messagetitle.Add(message_title) - comm.messagetext.Add(message_text) - /datum/comm_message_listener var/list/messages diff --git a/code/modules/modular_computers/file_system/programs/engineering/alarm_monitor.dm b/code/modules/modular_computers/file_system/programs/engineering/alarm_monitor.dm index c0289401afe..49b812da82d 100644 --- a/code/modules/modular_computers/file_system/programs/engineering/alarm_monitor.dm +++ b/code/modules/modular_computers/file_system/programs/engineering/alarm_monitor.dm @@ -1,7 +1,7 @@ /datum/computer_file/program/alarm_monitor filename = "alarmmonitoreng" filedesc = "Alarm Monitoring (Engineering)" - nanomodule_path = /datum/nano_module/alarm_monitor/engineering + tguimodule_path = /datum/tgui_module_old/alarm_monitor/engineering/ntos ui_header = "alarm_green.gif" program_icon_state = "alert-green" program_key_state = "atmos_key" @@ -15,8 +15,8 @@ /datum/computer_file/program/alarm_monitor/process_tick() ..() - var/datum/nano_module/alarm_monitor/NMA = NM - if(istype(NMA) && NMA.has_major_alarms()) + var/datum/tgui_module_old/alarm_monitor/TMA = TM + if(istype(TMA) && TMA.has_major_alarms()) if(!has_alert) program_icon_state = "alert-red" ui_header = "alarm_red.gif" @@ -29,107 +29,3 @@ update_computer_icon() has_alert = 0 return 1 - -/datum/nano_module/alarm_monitor - name = "Alarm monitor" - var/list_cameras = 0 // Whether or not to list camera references. A future goal would be to merge this with the enginering/security camera console. Currently really only for AI-use. - var/list/datum/alarm_handler/alarm_handlers // The particular list of alarm handlers this alarm monitor should present to the user. - //available_to_ai = FALSE - -/datum/nano_module/alarm_monitor/New() - ..() - alarm_handlers = list() - -/datum/nano_module/alarm_monitor/all/New() - ..() - alarm_handlers = SSalarms.all_handlers - -/datum/nano_module/alarm_monitor/engineering/New() - ..() - alarm_handlers = list(atmosphere_alarm, fire_alarm, power_alarm) - -/datum/nano_module/alarm_monitor/security/New() - ..() - alarm_handlers = list(camera_alarm, motion_alarm) - -/datum/nano_module/alarm_monitor/proc/register_alarm(var/object, var/procName) - for(var/datum/alarm_handler/AH in alarm_handlers) - AH.register_alarm(object, procName) - -/datum/nano_module/alarm_monitor/proc/unregister_alarm(var/object) - for(var/datum/alarm_handler/AH in alarm_handlers) - AH.unregister_alarm(object) - -/datum/nano_module/alarm_monitor/proc/all_alarms() - var/list/all_alarms = new() - for(var/datum/alarm_handler/AH in alarm_handlers) - all_alarms += AH.visible_alarms() - - return all_alarms - -/datum/nano_module/alarm_monitor/proc/major_alarms() - var/list/all_alarms = new() - for(var/datum/alarm_handler/AH in alarm_handlers) - all_alarms += AH.major_alarms() - - return all_alarms - -// Modified version of above proc that uses slightly less resources, returns 1 if there is a major alarm, 0 otherwise. -/datum/nano_module/alarm_monitor/proc/has_major_alarms() - for(var/datum/alarm_handler/AH in alarm_handlers) - if(AH.has_major_alarms()) - return 1 - - return 0 - -/datum/nano_module/alarm_monitor/proc/minor_alarms() - var/list/all_alarms = new() - for(var/datum/alarm_handler/AH in alarm_handlers) - all_alarms += AH.minor_alarms() - - return all_alarms - -/datum/nano_module/alarm_monitor/Topic(ref, href_list) - if(..()) - return 1 - if(href_list["switchTo"]) - var/obj/machinery/camera/C = locate(href_list["switchTo"]) in GLOB.cameranet.cameras - if(!C) - return - - usr.switch_to_camera(C) - return 1 - -/datum/nano_module/alarm_monitor/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() - - var/categories[0] - for(var/datum/alarm_handler/AH in alarm_handlers) - categories[++categories.len] = list("category" = AH.category, "alarms" = list()) - for(var/datum/alarm/A in AH.major_alarms()) - var/cameras[0] - var/lost_sources[0] - - if(isAI(user)) - for(var/obj/machinery/camera/C in A.cameras()) - cameras[++cameras.len] = C.ui_structure() - for(var/datum/alarm_source/AS in A.sources) - if(!AS.source) - lost_sources[++lost_sources.len] = AS.source_name - - categories[categories.len]["alarms"] += list(list( - "name" = sanitize(A.alarm_name()), - "origin_lost" = A.origin == null, - "has_cameras" = cameras.len, - "cameras" = cameras, - "lost_sources" = lost_sources.len ? sanitize(english_list(lost_sources, nothing_text = "", and_text = ", ")) : "")) - data["categories"] = categories - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "alarm_monitor.tmpl", "Alarm Monitoring Console", 800, 800, state = state) - if(host.update_layout()) // This is necessary to ensure the status bar remains updated along with rest of the UI. - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) diff --git a/code/modules/modular_computers/file_system/programs/engineering/atmos_control.dm b/code/modules/modular_computers/file_system/programs/engineering/atmos_control.dm index a905c427e71..920fef2558f 100644 --- a/code/modules/modular_computers/file_system/programs/engineering/atmos_control.dm +++ b/code/modules/modular_computers/file_system/programs/engineering/atmos_control.dm @@ -7,7 +7,7 @@ program_menu_icon = "shuffle" extended_desc = "This program allows remote control of air alarms. This program can not be run on tablet computers." required_access = ACCESS_ENGINEERING_ATMOS - requires_ntnet = TRUE + requires_ntnet = 1 network_destination = "atmospheric control system" requires_ntnet_feature = NTNET_SYSTEMCONTROL usage_flags = PROGRAM_LAPTOP | PROGRAM_CONSOLE diff --git a/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm b/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm index e6081fc0e75..4839bec0f56 100644 --- a/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm +++ b/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm @@ -1,7 +1,7 @@ /datum/computer_file/program/power_monitor filename = "powermonitor" filedesc = "Power Monitoring" - nanomodule_path = /datum/nano_module/power_monitor/ + tguimodule_path = /datum/tgui_module_old/power_monitor/ntos program_icon_state = "power_monitor" program_key_state = "power_key" program_menu_icon = "battery-3" @@ -15,8 +15,8 @@ /datum/computer_file/program/power_monitor/process_tick() ..() - var/datum/nano_module/power_monitor/NMA = NM - if(istype(NMA) && NMA.has_alarm()) + var/datum/tgui_module_old/power_monitor/TMA = TM + if(istype(TMA) && TMA.has_alarm()) if(!has_alert) program_icon_state = "power_monitor_warn" ui_header = "power_warn.gif" @@ -28,86 +28,3 @@ ui_header = "power_norm.gif" update_computer_icon() has_alert = 0 - -/datum/nano_module/power_monitor - name = "Power monitor" - var/list/grid_sensors - var/active_sensor = null //name_tag of the currently selected sensor - -/datum/nano_module/power_monitor/New() - ..() - refresh_sensors() - -// Checks whether there is an active alarm, if yes, returns 1, otherwise returns 0. -/datum/nano_module/power_monitor/proc/has_alarm() - for(var/obj/machinery/power/sensor/S in grid_sensors) - if(S.check_grid_warning()) - return 1 - return 0 - -// If PC is not null header template is loaded. Use PC.get_header_data() to get relevant nanoui data from it. All data entries begin with "PC_...." -// In future it may be expanded to other modular computer devices. -/datum/nano_module/power_monitor/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() - - var/list/sensors = list() - // Focus: If it remains null if no sensor is selected and UI will display sensor list, otherwise it will display sensor reading. - var/obj/machinery/power/sensor/focus = null - var/turf/T = get_turf(nano_host()) - - // Build list of data from sensor readings. - for(var/obj/machinery/power/sensor/S in grid_sensors) - sensors.Add(list(list( - "name" = S.name_tag, - "alarm" = S.check_grid_warning() - ))) - if(S.name_tag == active_sensor) - focus = S - - data["all_sensors"] = sensors - if(focus) - data["focus"] = focus.return_reading_data() - data["map_levels"] = (LEGACY_MAP_DATUM).get_map_levels(T.z) - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "power_monitor.tmpl", "Power Monitoring Console", 800, 500, state = state) - if(host.update_layout()) // This is necessary to ensure the status bar remains updated along with rest of the UI. - ui.auto_update_layout = 1 - // adding a template with the key "mapContent" enables the map ui functionality - ui.add_template("mapContent", "power_monitor_map_content.tmpl") - // adding a template with the key "mapHeader" replaces the map header content - ui.add_template("mapHeader", "power_monitor_map_header.tmpl") - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -// Refreshes list of active sensors kept on this computer. -/datum/nano_module/power_monitor/proc/refresh_sensors() - grid_sensors = list() - var/turf/T = get_turf(nano_host()) - var/list/levels = list() - if(!T) // Safety check - return - if(T) - levels += (LEGACY_MAP_DATUM).get_map_levels(T.z, FALSE) - for(var/obj/machinery/power/sensor/S in GLOB.machines) - if(T && (S.loc.z == T.z) || (S.loc.z in levels) || (S.long_range)) // Consoles have range on their Z-Level. Sensors with long_range var will work between Z levels. - if(S.name_tag == "#UNKN#") // Default name. Shouldn't happen! - warning("Powernet sensor with unset ID Tag! [S.x]X [S.y]Y [S.z]Z") - else - grid_sensors += S - -// Allows us to process UI clicks, which are relayed in form of hrefs. -/datum/nano_module/power_monitor/Topic(href, href_list) - if(..()) - return TRUE - if(href_list["clear"] ) - active_sensor = null - . = TRUE - if(href_list["refresh"] ) - refresh_sensors() - . = TRUE - else if(href_list["setsensor"] ) - active_sensor = href_list["setsensor"] - . = TRUE diff --git a/code/modules/modular_computers/file_system/programs/engineering/rcon_console.dm b/code/modules/modular_computers/file_system/programs/engineering/rcon_console.dm index ca5c60f5a2b..9dedede0353 100644 --- a/code/modules/modular_computers/file_system/programs/engineering/rcon_console.dm +++ b/code/modules/modular_computers/file_system/programs/engineering/rcon_console.dm @@ -1,7 +1,7 @@ /datum/computer_file/program/rcon_console filename = "rconconsole" filedesc = "RCON Remote Control" - nanomodule_path = /datum/nano_module/rcon + tguimodule_path = /datum/tgui_module_old/rcon/ntos program_icon_state = "generic" program_key_state = "rd_key" program_menu_icon = "power" @@ -12,131 +12,3 @@ requires_ntnet_feature = NTNET_SYSTEMCONTROL usage_flags = PROGRAM_LAPTOP | PROGRAM_CONSOLE size = 19 - -GLOBAL_LIST_EMPTY(rcon_nano_modules) - -/datum/nano_module/rcon - name = "Power RCON" - var/list/known_SMESs = null - var/list/known_breakers = null - // Allows you to hide specific parts of the UI - var/hide_SMES = 0 - var/hide_SMES_details = 0 - var/hide_breakers = 0 - -/datum/nano_module/rcon/New() - . = ..() - GLOB.rcon_nano_modules += src - -/datum/nano_module/rcon/Destroy() - . = ..() - GLOB.rcon_nano_modules -= src - -/datum/nano_module/rcon/nano_ui_interact(mob/user, ui_key = "rcon", datum/nanoui/ui=null, force_open=1, var/datum/topic_state/state = default_state) - FindDevices() // Update our devices list - var/list/data = host.initial_data() - - // SMES DATA (simplified view) - var/list/smeslist[0] - for(var/obj/machinery/power/smes/buildable/SMES in known_SMESs) - smeslist.Add(list(list( - "charge" = round(SMES.Percentage()), - "input_set" = SMES.input_attempt, - "input_val" = round(SMES.input_level/1000, 0.1), - "output_set" = SMES.output_attempt, - "output_val" = round(SMES.output_level/1000, 0.1), - "output_load" = round(SMES.output_used/1000, 0.1), - "RCON_tag" = SMES.RCon_tag - ))) - - data["smes_info"] = sortByKey(smeslist, "RCON_tag") - - // BREAKER DATA (simplified view) - var/list/breakerlist[0] - for(var/obj/machinery/power/breakerbox/BR in known_breakers) - breakerlist.Add(list(list( - "RCON_tag" = BR.RCon_tag, - "enabled" = BR.on - ))) - data["breaker_info"] = breakerlist - data["hide_smes"] = hide_SMES - data["hide_smes_details"] = hide_SMES_details - data["hide_breakers"] = hide_breakers - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "rcon.tmpl", "RCON Console", 600, 400, state = state) - if(host.update_layout()) // This is necessary to ensure the status bar remains updated along with rest of the UI. - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -// Proc: Topic() -// Parameters: 2 (href, href_list - allows us to process UI clicks) -// Description: Allows us to process UI clicks, which are relayed in form of hrefs. -/datum/nano_module/rcon/Topic(href, href_list) - if(..()) - return - - if(href_list["smes_in_toggle"]) - var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(href_list["smes_in_toggle"]) - if(SMES) - SMES.toggle_input() - if(href_list["smes_out_toggle"]) - var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(href_list["smes_out_toggle"]) - if(SMES) - SMES.toggle_output() - if(href_list["smes_in_set"]) - var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(href_list["smes_in_set"]) - if(SMES) - var/inputset = (input(usr, "Enter new input level (0-[SMES.input_level_max/1000] kW)", "SMES Input Power Control", SMES.input_level/1000) as num) * 1000 - SMES.set_input(inputset) - if(href_list["smes_out_set"]) - var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(href_list["smes_out_set"]) - if(SMES) - var/outputset = (input(usr, "Enter new output level (0-[SMES.output_level_max/1000] kW)", "SMES Output Power Control", SMES.output_level/1000) as num) * 1000 - SMES.set_output(outputset) - - if(href_list["toggle_breaker"]) - var/obj/machinery/power/breakerbox/toggle = null - for(var/obj/machinery/power/breakerbox/breaker in known_breakers) - if(breaker.RCon_tag == href_list["toggle_breaker"]) - toggle = breaker - if(toggle) - if(toggle.update_locked) - to_chat(usr, "The breaker box was recently toggled. Please wait before toggling it again.") - else - toggle.auto_toggle() - if(href_list["hide_smes"]) - hide_SMES = !hide_SMES - if(href_list["hide_smes_details"]) - hide_SMES_details = !hide_SMES_details - if(href_list["hide_breakers"]) - hide_breakers = !hide_breakers - - -// Proc: GetSMESByTag() -// Parameters: 1 (tag - RCON tag of SMES we want to look up) -// Description: Looks up and returns SMES which has matching RCON tag -/datum/nano_module/rcon/proc/GetSMESByTag(var/tag) - if(!tag) - return - - for(var/obj/machinery/power/smes/buildable/S in known_SMESs) - if(S.RCon_tag == tag) - return S - -// Proc: FindDevices() -// Parameters: None -// Description: Refreshes local list of known devices. -/datum/nano_module/rcon/proc/FindDevices() - known_SMESs = new /list() - for(var/obj/machinery/power/smes/buildable/SMES in GLOB.smeses) - if(SMES.RCon_tag && (SMES.RCon_tag != "NO_TAG") && SMES.RCon) - known_SMESs.Add(SMES) - - known_breakers = new /list() - for(var/obj/machinery/power/breakerbox/breaker in GLOB.machines) - if(breaker.RCon_tag != "NO_TAG") - known_breakers.Add(breaker) diff --git a/code/modules/modular_computers/file_system/programs/engineering/shutoff_monitor.dm b/code/modules/modular_computers/file_system/programs/engineering/shutoff_monitor.dm new file mode 100644 index 00000000000..28820c567e2 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/engineering/shutoff_monitor.dm @@ -0,0 +1,13 @@ +/datum/computer_file/program/shutoff_monitor + filename = "shutoffmonitor" + filedesc = "Shutoff Valve Monitoring" + tguimodule_path = /datum/tgui_module/shutoff_monitor/ntos + program_icon_state = "atmos_control" + program_key_state = "atmos_key" + program_menu_icon = "wrench" + extended_desc = "This program allows for remote monitoring and control of emergency shutoff valves." + required_access = ACCESS_ENGINEERING_MAIN + requires_ntnet = 1 + network_destination = "shutoff valve control computer" + size = 5 + var/has_alert = 0 diff --git a/code/modules/modular_computers/file_system/programs/engineering/supermatter_monitor.dm b/code/modules/modular_computers/file_system/programs/engineering/supermatter_monitor.dm index 66c6781beac..b1ddc97698a 100644 --- a/code/modules/modular_computers/file_system/programs/engineering/supermatter_monitor.dm +++ b/code/modules/modular_computers/file_system/programs/engineering/supermatter_monitor.dm @@ -1,7 +1,7 @@ /datum/computer_file/program/supermatter_monitor filename = "supmon" filedesc = "Supermatter Monitoring" - nanomodule_path = /datum/nano_module/supermatter_monitor/ + tguimodule_path = /datum/tgui_module_old/supermatter_monitor/ntos program_icon_state = "smmon_0" program_key_state = "tech_key" program_menu_icon = "notice" @@ -15,119 +15,11 @@ /datum/computer_file/program/supermatter_monitor/process_tick() ..() - var/datum/nano_module/supermatter_monitor/NMS = NM - var/new_status = istype(NMS) ? NMS.get_status() : 0 + var/datum/tgui_module_old/supermatter_monitor/TMS = TM + var/new_status = istype(TMS) ? TMS.get_status() : 0 if(last_status != new_status) last_status = new_status ui_header = "smmon_[last_status].gif" program_icon_state = "smmon_[last_status]" if(istype(computer)) computer.update_icon() - -/datum/nano_module/supermatter_monitor - name = "Supermatter monitor" - var/list/supermatters - var/obj/machinery/power/supermatter/active = null // Currently selected supermatter crystal. - -/datum/nano_module/supermatter_monitor/Destroy() - . = ..() - active = null - supermatters = null - -/datum/nano_module/supermatter_monitor/New() - ..() - refresh() - -// Refreshes list of active supermatter crystals -/datum/nano_module/supermatter_monitor/proc/refresh() - supermatters = list() - var/turf/T = get_turf(nano_host()) - if(!T) - return - var/valid_z_levels = (GetConnectedZlevels(T.z) & (LEGACY_MAP_DATUM).station_levels) - for(var/obj/machinery/power/supermatter/S in GLOB.machines) - // Delaminating, not within coverage, not on a tile. - if(S.grav_pulling || S.exploded || !(S.z in valid_z_levels) || !istype(S.loc, /turf/)) - continue - supermatters.Add(S) - - if(!(active in supermatters)) - active = null - -/datum/nano_module/supermatter_monitor/proc/get_status() - . = SUPERMATTER_INACTIVE - for(var/obj/machinery/power/supermatter/S in supermatters) - . = max(., S.get_status()) - -/datum/nano_module/supermatter_monitor/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() - - if(istype(active)) - var/turf/T = get_turf(active) - if(!T) - active = null - return - var/datum/gas_mixture/air = T.return_air() - if(!istype(air)) - active = null - return - - data["active"] = 1 - data["SM_integrity"] = active.get_integrity() - data["SM_power"] = active.power - data["SM_ambienttemp"] = air.temperature - data["SM_ambientpressure"] = air.return_pressure() - data["SM_EPR"] = active.get_epr() - //data["SM_EPR"] = active.get_epr() - if(air.total_moles) - data["SM_gas_O2"] = round(100*air.gas[/datum/gas/oxygen]/air.total_moles,0.01) - data["SM_gas_CO2"] = round(100*air.gas[/datum/gas/carbon_dioxide]/air.total_moles,0.01) - data["SM_gas_N2"] = round(100*air.gas[/datum/gas/nitrogen]/air.total_moles,0.01) - data["SM_gas_PH"] = round(100*air.gas[/datum/gas/phoron]/air.total_moles,0.01) - data["SM_gas_N2O"] = round(100*air.gas[/datum/gas/nitrous_oxide]/air.total_moles,0.01) - else - data["SM_gas_O2"] = 0 - data["SM_gas_CO2"] = 0 - data["SM_gas_N2"] = 0 - data["SM_gas_PH"] = 0 - data["SM_gas_N2O"] = 0 - else - var/list/SMS = list() - for(var/obj/machinery/power/supermatter/S in supermatters) - var/area/A = get_area(S) - if(!A) - continue - - SMS.Add(list(list( - "area_name" = A.name, - "integrity" = S.get_integrity(), - "uid" = S.uid - ))) - - data["active"] = 0 - data["supermatters"] = SMS - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "supermatter_monitor.tmpl", "Supermatter Monitoring", 600, 400, state = state) - if(host.update_layout()) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/datum/nano_module/supermatter_monitor/Topic(href, href_list) - if(..()) - return 1 - if( href_list["clear"] ) - active = null - return 1 - if( href_list["refresh"] ) - refresh() - return 1 - if( href_list["set"] ) - var/newuid = text2num(href_list["set"]) - for(var/obj/machinery/power/supermatter/S in supermatters) - if(S.uid == newuid) - active = S - return 1 diff --git a/code/modules/modular_computers/file_system/programs/generic/camera.dm b/code/modules/modular_computers/file_system/programs/generic/camera.dm index 50360dd2fd8..53caa5a38d1 100644 --- a/code/modules/modular_computers/file_system/programs/generic/camera.dm +++ b/code/modules/modular_computers/file_system/programs/generic/camera.dm @@ -17,7 +17,7 @@ return ACCESS_CENTCOM_ERT if(network in (LEGACY_MAP_DATUM).station_networks) - return ACCESS_SECURITY_EQUIPMENT // Default for all other station networks + return ACCESS_SECURITY_MAIN // Default for all other station networks else return 999 //Inaccessible if not a station network and not mentioned above diff --git a/code/modules/modular_computers/file_system/programs/generic/configurator.dm b/code/modules/modular_computers/file_system/programs/generic/configurator.dm index 31ab6810fd7..d6b3704474c 100644 --- a/code/modules/modular_computers/file_system/programs/generic/configurator.dm +++ b/code/modules/modular_computers/file_system/programs/generic/configurator.dm @@ -14,51 +14,4 @@ size = 4 available_on_ntnet = 0 requires_ntnet = 0 - nanomodule_path = /datum/nano_module/program/computer_configurator/ - -/datum/nano_module/program/computer_configurator - name = "NTOS Computer Configuration Tool" - var/obj/item/modular_computer/movable = null - -/datum/nano_module/program/computer_configurator/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - if(program) - movable = program.computer - if(!istype(movable)) - movable = null - - // No computer connection, we can't get data from that. - if(!movable) - return 0 - - var/list/data = list() - - if(program) - data = program.get_header_data() - - var/list/hardware = movable.get_all_components() - - data["disk_size"] = movable.hard_drive.max_capacity - data["disk_used"] = movable.hard_drive.used_capacity - data["power_usage"] = movable.last_power_usage - data["battery_exists"] = movable.battery_module ? 1 : 0 - if(movable.battery_module) - data["battery_rating"] = movable.battery_module.battery.maxcharge - data["battery_percent"] = round(movable.battery_module.battery.percent()) - - var/list/all_entries[0] - for(var/obj/item/computer_hardware/H in hardware) - all_entries.Add(list(list( - "name" = H.name, - "desc" = H.desc, - "enabled" = H.enabled, - "critical" = H.critical, - "powerusage" = H.power_usage - ))) - - data["hardware"] = all_entries - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "laptop_configuration.tmpl", "NTOS Configuration Utility", 575, 700, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() + tguimodule_path = /datum/tgui_module_old/computer_configurator diff --git a/code/modules/modular_computers/file_system/programs/generic/email_client.dm b/code/modules/modular_computers/file_system/programs/generic/email_client.dm index 9ab0d70dcd8..6385307fc9f 100644 --- a/code/modules/modular_computers/file_system/programs/generic/email_client.dm +++ b/code/modules/modular_computers/file_system/programs/generic/email_client.dm @@ -11,15 +11,15 @@ var/stored_login = "" var/stored_password = "" - nanomodule_path = /datum/nano_module/email_client + tguimodule_path = /datum/tgui_module_old/email_client // Persistency. Unless you log out, or unless your password changes, this will pre-fill the login data when restarting the program /datum/computer_file/program/email_client/kill_program() - if(NM) - var/datum/nano_module/email_client/NME = NM - if(NME.current_account) - stored_login = NME.stored_login - stored_password = NME.stored_password + if(TM) + var/datum/tgui_module_old/email_client/TME = TM + if(TME.current_account) + stored_login = TME.stored_login + stored_password = TME.stored_password else stored_login = "" stored_password = "" @@ -27,473 +27,31 @@ /datum/computer_file/program/email_client/run_program() . = ..() - if(NM) - var/datum/nano_module/email_client/NME = NM - NME.stored_login = stored_login - NME.stored_password = stored_password - NME.log_in() - NME.error = "" - NME.check_for_new_messages(1) + if(TM) + var/datum/tgui_module_old/email_client/TME = TM + TME.stored_login = stored_login + TME.stored_password = stored_password + TME.log_in() + TME.error = "" + TME.check_for_new_messages(TRUE) /datum/computer_file/program/email_client/proc/new_mail_notify() - computer.visible_message("\The [computer] beeps softly, indicating a new email has been received.", 1) + var/turf/T = get_turf(computer) // Because visible_message is being a butt + if(T) + T.visible_message("[computer] beeps softly, indicating a new email has been received.") + playsound(computer, 'sound/misc/server-ready.ogg', 100, 0) /datum/computer_file/program/email_client/process_tick() ..() - var/datum/nano_module/email_client/NME = NM - if(!istype(NME)) + var/datum/tgui_module_old/email_client/TME = TM + if(!istype(TME)) return - NME.relayed_process(ntnet_speed) + TME.relayed_process(ntnet_speed) - var/check_count = NME.check_for_new_messages() + var/check_count = TME.check_for_new_messages() if(check_count) - if(check_count == 2) + if(check_count == NTOS_EMAIL_NEWMESSAGE) new_mail_notify() ui_header = "ntnrc_new.gif" else ui_header = "ntnrc_idle.gif" - -/datum/nano_module/email_client/ - name = "Email Client" - var/stored_login = "" - var/stored_password = "" - var/error = "" - - var/msg_title = "" - var/msg_body = "" - var/msg_recipient = "" - var/datum/computer_file/msg_attachment = null - var/folder = "Inbox" - var/addressbook = FALSE - var/new_message = FALSE - - var/last_message_count = 0 // How many messages were there during last check. - var/read_message_count = 0 // How many messages were there when user has last accessed the UI. - - var/datum/computer_file/downloading = null - var/download_progress = 0 - var/download_speed = 0 - - var/datum/computer_file/data/email_account/current_account = null - var/datum/computer_file/data/email_message/current_message = null - -/datum/nano_module/email_client/proc/log_in() - for(var/datum/computer_file/data/email_account/account in ntnet_global.email_accounts) - if(!account.can_login) - continue - if(account.login == stored_login) - if(account.password == stored_password) - if(account.suspended) - error = "This account has been suspended. Please contact the system administrator for assistance." - return 0 - current_account = account - return 1 - else - error = "Invalid Password" - return 0 - error = "Invalid Login" - return 0 - -// Returns 0 if no new messages were received, 1 if there is an unread message but notification has already been sent. -// and 2 if there is a new message that appeared in this tick (and therefore notification should be sent by the program). -/datum/nano_module/email_client/proc/check_for_new_messages(var/messages_read = FALSE) - if(!current_account) - return 0 - - var/list/allmails = current_account.all_emails() - - if(allmails.len > last_message_count) - . = 2 - else if(allmails.len > read_message_count) - . = 1 - else - . = 0 - - last_message_count = allmails.len - if(messages_read) - read_message_count = allmails.len - - -/datum/nano_module/email_client/proc/log_out() - current_account = null - downloading = null - download_progress = 0 - last_message_count = 0 - read_message_count = 0 - -/datum/nano_module/email_client/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() - - // Password has been changed by other client connected to this email account - if(current_account) - if(current_account.password != stored_password) - log_out() - error = "Invalid Password" - // Banned. - if(current_account.suspended) - log_out() - error = "This account has been suspended. Please contact the system administrator for assistance." - - if(error) - data["error"] = error - else if(downloading) - data["downloading"] = 1 - data["down_filename"] = "[downloading.filename].[downloading.filetype]" - data["down_progress"] = download_progress - data["down_size"] = downloading.size - data["down_speed"] = download_speed - - else if(istype(current_account)) - data["current_account"] = current_account.login - if(addressbook) - var/list/all_accounts = list() - for(var/datum/computer_file/data/email_account/account in ntnet_global.email_accounts) - if(!account.can_login) - continue - all_accounts.Add(list(list( - "login" = account.login - ))) - data["addressbook"] = 1 - data["accounts"] = all_accounts - else if(new_message) - data["new_message"] = 1 - data["msg_title"] = msg_title - data["msg_body"] = pencode2html(msg_body) - data["msg_recipient"] = msg_recipient - if(msg_attachment) - data["msg_hasattachment"] = 1 - data["msg_attachment_filename"] = "[msg_attachment.filename].[msg_attachment.filetype]" - data["msg_attachment_size"] = msg_attachment.size - else if (current_message) - data["cur_title"] = current_message.title - data["cur_body"] = pencode2html(current_message.stored_data) - data["cur_timestamp"] = current_message.timestamp - data["cur_source"] = current_message.source - data["cur_uid"] = current_message.uid - if(istype(current_message.attachment)) - data["cur_hasattachment"] = 1 - data["cur_attachment_filename"] = "[current_message.attachment.filename].[current_message.attachment.filetype]" - data["cur_attachment_size"] = current_message.attachment.size - else - data["label_inbox"] = "Inbox ([current_account.inbox.len])" - data["label_spam"] = "Spam ([current_account.spam.len])" - data["label_deleted"] = "Deleted ([current_account.deleted.len])" - var/list/message_source - if(folder == "Inbox") - message_source = current_account.inbox - else if(folder == "Spam") - message_source = current_account.spam - else if(folder == "Deleted") - message_source = current_account.deleted - - if(message_source) - data["folder"] = folder - var/list/all_messages = list() - for(var/datum/computer_file/data/email_message/message in message_source) - all_messages.Add(list(list( - "title" = message.title, - "body" = pencode2html(message.stored_data), - "source" = message.source, - "timestamp" = message.timestamp, - "uid" = message.uid - ))) - data["messages"] = all_messages - data["messagecount"] = all_messages.len - else - data["stored_login"] = stored_login - data["stored_password"] = stars(stored_password, 0) - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "email_client.tmpl", "Email Client", 600, 450, state = state) - if(host.update_layout()) - ui.auto_update_layout = 1 - ui.set_auto_update(1) - ui.set_initial_data(data) - ui.open() - -/datum/nano_module/email_client/proc/find_message_by_fuid(var/fuid) - if(!istype(current_account)) - return - - // href_list works with strings, so this makes it a bit easier for us - if(istext(fuid)) - fuid = text2num(fuid) - - for(var/datum/computer_file/data/email_message/message in current_account.all_emails()) - if(message.uid == fuid) - return message - -/datum/nano_module/email_client/proc/clear_message() - new_message = FALSE - msg_title = "" - msg_body = "" - msg_recipient = "" - msg_attachment = null - current_message = null - -/datum/nano_module/email_client/proc/relayed_process(var/netspeed) - download_speed = netspeed - if(!downloading) - return - download_progress = min(download_progress + netspeed, downloading.size) - if(download_progress >= downloading.size) - var/obj/item/modular_computer/MC = nano_host() - if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality()) - error = "Error uploading file. Are you using a functional and NTOSv2-compliant device?" - downloading = null - download_progress = 0 - return 1 - - if(MC.hard_drive.store_file(downloading)) - error = "File successfully downloaded to local device." - else - error = "Error saving file: I/O Error: The hard drive may be full or nonfunctional." - downloading = null - download_progress = 0 - return 1 - - -/datum/nano_module/email_client/Topic(href, href_list) - if(..()) - return 1 - var/mob/living/user = usr - check_for_new_messages(1) // Any actual interaction (button pressing) is considered as acknowledging received message, for the purpose of notification icons. - if(href_list["login"]) - log_in() - return 1 - - if(href_list["logout"]) - log_out() - return 1 - - if(href_list["reset"]) - error = "" - return 1 - - if(href_list["new_message"]) - new_message = TRUE - return 1 - - if(href_list["cancel"]) - if(addressbook) - addressbook = FALSE - else - clear_message() - return 1 - - if(href_list["addressbook"]) - addressbook = TRUE - return 1 - - if(href_list["set_recipient"]) - msg_recipient = sanitize(href_list["set_recipient"]) - addressbook = FALSE - return 1 - - if(href_list["edit_title"]) - var/newtitle = sanitize(input(user,"Enter title for your message:", "Message title", msg_title), 100) - if(newtitle) - msg_title = newtitle - return 1 - - // This uses similar editing mechanism as the FileManager program, therefore it supports various paper tags and remembers formatting. - if(href_list["edit_body"]) - var/oldtext = html_decode(msg_body) - oldtext = replacetext(oldtext, "\[editorbr\]", "\n") - - var/newtext = sanitize(replacetext(input(usr, "Enter your message. You may use most tags from paper formatting", "Message Editor", oldtext) as message|null, "\n", "\[editorbr\]"), 20000) - if(newtext) - msg_body = newtext - return 1 - - if(href_list["edit_recipient"]) - var/newrecipient = sanitize(input(user,"Enter recipient's email address:", "Recipient", msg_recipient), 100) - if(newrecipient) - msg_recipient = newrecipient - return 1 - - if(href_list["edit_login"]) - var/newlogin = sanitize(input(user,"Enter login", "Login", stored_login), 100) - if(newlogin) - stored_login = newlogin - return 1 - - if(href_list["edit_password"]) - var/newpass = sanitize(input(user,"Enter password", "Password"), 100) - if(newpass) - stored_password = newpass - return 1 - - if(href_list["delete"]) - if(!istype(current_account)) - return 1 - var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["delete"]) - if(!istype(M)) - return 1 - if(folder == "Deleted") - current_account.deleted.Remove(M) - qdel(M) - else - current_account.deleted.Add(M) - current_account.inbox.Remove(M) - current_account.spam.Remove(M) - if(current_message == M) - current_message = null - return 1 - - if(href_list["send"]) - if(!current_account) - return 1 - if((msg_title == "") || (msg_body == "") || (msg_recipient == "")) - error = "Error sending mail: Title or message body is empty!" - return 1 - - var/datum/computer_file/data/email_message/message = new() - message.title = msg_title - message.stored_data = msg_body - message.source = current_account.login - message.attachment = msg_attachment - if(!current_account.send_mail(msg_recipient, message)) - error = "Error sending email: this address doesn't exist." - return 1 - else - error = "Email successfully sent." - clear_message() - return 1 - - if(href_list["set_folder"]) - folder = href_list["set_folder"] - return 1 - - if(href_list["reply"]) - var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["reply"]) - if(!istype(M)) - return 1 - - new_message = TRUE - msg_recipient = M.source - msg_title = "Re: [M.title]" - msg_body = "\[editorbr\]\[editorbr\]\[editorbr\]\[br\]==============================\[br\]\[editorbr\]" - msg_body += "Received by [current_account.login] at [M.timestamp]\[br\]\[editorbr\][M.stored_data]" - return 1 - - if(href_list["view"]) - var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["view"]) - if(istype(M)) - current_message = M - return 1 - - if(href_list["changepassword"]) - var/oldpassword = sanitize(input(user,"Please enter your old password:", "Password Change"), 100) - if(!oldpassword) - return 1 - var/newpassword1 = sanitize(input(user,"Please enter your new password:", "Password Change"), 100) - if(!newpassword1) - return 1 - var/newpassword2 = sanitize(input(user,"Please re-enter your new password:", "Password Change"), 100) - if(!newpassword2) - return 1 - - if(!istype(current_account)) - error = "Please log in before proceeding." - return 1 - - if(current_account.password != oldpassword) - error = "Incorrect original password" - return 1 - - if(newpassword1 != newpassword2) - error = "The entered passwords do not match." - return 1 - - current_account.password = newpassword1 - stored_password = newpassword1 - error = "Your password has been successfully changed!" - return 1 - - // The following entries are Modular Computer framework only, and therefore won't do anything in other cases (like AI View) - - if(href_list["save"]) - // Fully dependant on modular computers here. - var/obj/item/modular_computer/MC = nano_host() - - if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality()) - error = "Error exporting file. Are you using a functional and NTOS-compliant device?" - return 1 - - var/filename = sanitize(input(user,"Please specify file name:", "Message export"), 100) - if(!filename) - return 1 - - var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["save"]) - var/datum/computer_file/data/mail = istype(M) ? M.export() : null - if(!istype(mail)) - return 1 - mail.filename = filename - if(!MC.hard_drive || !MC.hard_drive.store_file(mail)) - error = "Internal I/O error when writing file, the hard drive may be full." - else - error = "Email exported successfully" - return 1 - - if(href_list["addattachment"]) - var/obj/item/modular_computer/MC = nano_host() - msg_attachment = null - - if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality()) - error = "Error uploading file. Are you using a functional and NTOSv2-compliant device?" - return 1 - - var/list/filenames = list() - for(var/datum/computer_file/CF in MC.hard_drive.stored_files) - if(CF.unsendable) - continue - filenames.Add(CF.filename) - var/picked_file = input(user, "Please pick a file to send as attachment (max 32GQ)") as null|anything in filenames - - if(!picked_file) - return 1 - - if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality()) - error = "Error uploading file. Are you using a functional and NTOSv2-compliant device?" - return 1 - - for(var/datum/computer_file/CF in MC.hard_drive.stored_files) - if(CF.unsendable) - continue - if(CF.filename == picked_file) - msg_attachment = CF.clone() - break - if(!istype(msg_attachment)) - msg_attachment = null - error = "Unknown error when uploading attachment." - return 1 - - if(msg_attachment.size > 32) - error = "Error uploading attachment: File exceeds maximal permitted file size of 32GQ." - msg_attachment = null - else - error = "File [msg_attachment.filename].[msg_attachment.filetype] has been successfully uploaded." - return 1 - - if(href_list["downloadattachment"]) - if(!current_account || !current_message || !current_message.attachment) - return 1 - var/obj/item/modular_computer/MC = nano_host() - if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality()) - error = "Error downloading file. Are you using a functional and NTOSv2-compliant device?" - return 1 - - downloading = current_message.attachment.clone() - download_progress = 0 - return 1 - - if(href_list["canceldownload"]) - downloading = null - download_progress = 0 - return 1 - - if(href_list["remove_attachment"]) - msg_attachment = null - return 1 diff --git a/code/modules/modular_computers/file_system/programs/generic/file_browser.dm b/code/modules/modular_computers/file_system/programs/generic/file_browser.dm index c9797134da5..034bf6a6f83 100644 --- a/code/modules/modular_computers/file_system/programs/generic/file_browser.dm +++ b/code/modules/modular_computers/file_system/programs/generic/file_browser.dm @@ -6,202 +6,190 @@ program_key_state = "generic_key" program_menu_icon = "folder-collapsed" size = 8 - requires_ntnet = 0 - available_on_ntnet = 0 - undeletable = 1 - nanomodule_path = /datum/nano_module/program/computer_filemanager/ + requires_ntnet = FALSE + available_on_ntnet = FALSE + undeletable = TRUE + tgui_id = "NtosFileManager" + var/open_file var/error -/datum/computer_file/program/filemanager/Topic(href, href_list) +/datum/computer_file/program/filemanager/ui_act(action, list/params, datum/tgui/ui) if(..()) - return 1 + return TRUE - if(href_list["PRG_openfile"]) - . = 1 - open_file = href_list["PRG_openfile"] - if(href_list["PRG_newtextfile"]) - . = 1 - var/newname = sanitize(input(usr, "Enter file name or leave blank to cancel:", "File rename")) - if(!newname) - return 1 - var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive - if(!HDD) - return 1 - var/datum/computer_file/data/F = new/datum/computer_file/data() - F.filename = newname - F.filetype = "TXT" - HDD.store_file(F) - if(href_list["PRG_deletefile"]) - . = 1 - var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive - if(!HDD) - return 1 - var/datum/computer_file/file = HDD.find_file_by_name(href_list["PRG_deletefile"]) - if(!file || file.undeletable) - return 1 - HDD.remove_file(file) - if(href_list["PRG_usbdeletefile"]) - . = 1 - var/obj/item/computer_hardware/hard_drive/RHDD = computer.portable_drive - if(!RHDD) - return 1 - var/datum/computer_file/file = RHDD.find_file_by_name(href_list["PRG_usbdeletefile"]) - if(!file || file.undeletable) - return 1 - RHDD.remove_file(file) - if(href_list["PRG_closefile"]) - . = 1 - open_file = null - error = null - if(href_list["PRG_clone"]) - . = 1 - var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive - if(!HDD) - return 1 - var/datum/computer_file/F = HDD.find_file_by_name(href_list["PRG_clone"]) - if(!F || !istype(F)) - return 1 - var/datum/computer_file/C = F.clone(1) - HDD.store_file(C) - if(href_list["PRG_rename"]) - . = 1 - var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive - if(!HDD) - return 1 - var/datum/computer_file/file = HDD.find_file_by_name(href_list["PRG_rename"]) - if(!file || !istype(file)) - return 1 - var/newname = sanitize(input(usr, "Enter new file name:", "File rename", file.filename)) - if(file && newname) + var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive + var/obj/item/computer_hardware/hard_drive/RHDD = computer.portable_drive + + switch(action) + if("PRG_openfile") + open_file = params["name"] + return TRUE + if("PRG_newtextfile") + if(!HDD) + return + var/newname = sanitize(input(usr, "Enter file name or leave blank to cancel:", "File rename")) + if(!newname) + return + var/datum/computer_file/data/F = new/datum/computer_file/data() + F.filename = newname + F.filetype = "TXT" + HDD.store_file(F) + return TRUE + if("PRG_closefile") + open_file = null + error = null + return TRUE + if("PRG_clone") + if(!HDD) + return + var/datum/computer_file/F = HDD.find_file_by_name(params["name"]) + if(!F || !istype(F)) + return + var/datum/computer_file/C = F.clone(1) + HDD.store_file(C) + return TRUE + if("PRG_edit") + if(!HDD) + return + if(!open_file) + return + var/datum/computer_file/data/F = HDD.find_file_by_name(open_file) + if(!F || !istype(F)) + return + if(F.do_not_edit && (alert("WARNING: This file is not compatible with editor. Editing it may result in permanently corrupted formatting or damaged data consistency. Edit anyway?", "Incompatible File", "No", "Yes") == "No")) + return + + var/oldtext = html_decode(F.stored_data) + oldtext = replacetext(oldtext, "\[br\]", "\n") + + var/newtext = sanitize(replacetext(input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[br\]"), MAX_TEXTFILE_LENGTH) + if(!newtext) + return + + if(F) + var/datum/computer_file/data/backup = F.clone() + HDD.remove_file(F) + F.stored_data = newtext + F.calculate_size() + // We can't store the updated file, it's probably too large. Print an error and restore backed up version. + // This is mostly intended to prevent people from losing texts they spent lot of time working on due to running out of space. + // They will be able to copy-paste the text from error screen and store it in notepad or something. + if(!HDD.store_file(F)) + error = "I/O error: Unable to overwrite file. Hard drive is probably full. You may want to backup your changes before closing this window:

[html_decode(F.stored_data)]

" + HDD.store_file(backup) + return TRUE + if("PRG_printfile") + if(!HDD) + return + if(!open_file) + return + var/datum/computer_file/data/F = HDD.find_file_by_name(open_file) + if(!F || !istype(F)) + return + if(!computer.nano_printer) + error = "Missing Hardware: Your computer does not have required hardware to complete this operation." + return + if(!computer.nano_printer.print_text(pencode2html(F.stored_data))) + error = "Hardware error: Printer was unable to print the file. It may be out of paper." + return + return TRUE + if("PRG_deletefile") + if(!HDD) + return + var/datum/computer_file/file = HDD.find_file_by_name(params["name"]) + if(!file || file.undeletable) + return + HDD.remove_file(file) + return TRUE + if("PRG_usbdeletefile") + if(!RHDD) + return + var/datum/computer_file/file = RHDD.find_file_by_name(params["name"]) + if(!file || file.undeletable) + return + RHDD.remove_file(file) + return TRUE + if("PRG_rename") + if(!HDD) + return + var/datum/computer_file/file = HDD.find_file_by_name(params["name"]) + if(!file) + return + var/newname = params["new_name"] + if(!newname) + return file.filename = newname - if(href_list["PRG_edit"]) - . = 1 - if(!open_file) - return 1 - var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive - if(!HDD) - return 1 - var/datum/computer_file/data/F = HDD.find_file_by_name(open_file) - if(!F || !istype(F)) - return 1 - if(F.do_not_edit && (alert("WARNING: This file is not compatible with editor. Editing it may result in permanently corrupted formatting or damaged data consistency. Edit anyway?", "Incompatible File", "No", "Yes") == "No")) - return 1 + return TRUE + if("PRG_copytousb") + if(!HDD || !RHDD) + return + var/datum/computer_file/F = HDD.find_file_by_name(params["name"]) + if(!F) + return + var/datum/computer_file/C = F.clone(FALSE) + RHDD.store_file(C) + return TRUE + if("PRG_copyfromusb") + if(!HDD || !RHDD) + return + var/datum/computer_file/F = RHDD.find_file_by_name(params["name"]) + if(!F || !istype(F)) + return + var/datum/computer_file/C = F.clone(FALSE) + HDD.store_file(C) + return TRUE - var/oldtext = html_decode(F.stored_data) - oldtext = replacetext(oldtext, "\[br\]", "\n") +/datum/computer_file/program/filemanager/ui_data(mob/user) + var/list/data = get_header_data() - var/newtext = sanitize(replacetext(input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[br\]"), MAX_TEXTFILE_LENGTH) - if(!newtext) - return + var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive + var/obj/item/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive - if(F) - var/datum/computer_file/data/backup = F.clone() - HDD.remove_file(F) - F.stored_data = newtext - F.calculate_size() - // We can't store the updated file, it's probably too large. Print an error and restore backed up version. - // This is mostly intended to prevent people from losing texts they spent lot of time working on due to running out of space. - // They will be able to copy-paste the text from error screen and store it in notepad or something. - if(!HDD.store_file(F)) - error = "I/O error: Unable to overwrite file. Hard drive is probably full. You may want to backup your changes before closing this window:

[html_decode(F.stored_data)]

" - HDD.store_file(backup) - if(href_list["PRG_printfile"]) - . = 1 - if(!open_file) - return 1 - var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive - if(!HDD) - return 1 - var/datum/computer_file/data/F = HDD.find_file_by_name(open_file) - if(!F || !istype(F)) - return 1 - if(!computer.nano_printer) - error = "Missing Hardware: Your computer does not have required hardware to complete this operation." - return 1 - if(!computer.nano_printer.print_text(pencode2html(F.stored_data))) - error = "Hardware error: Printer was unable to print the file. It may be out of paper." - return 1 - if(href_list["PRG_copytousb"]) - . = 1 - var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive - var/obj/item/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive - if(!HDD || !RHDD) - return 1 - var/datum/computer_file/F = HDD.find_file_by_name(href_list["PRG_copytousb"]) - if(!F || !istype(F)) - return 1 - var/datum/computer_file/C = F.clone(0) - RHDD.store_file(C) - if(href_list["PRG_copyfromusb"]) - . = 1 - var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive - var/obj/item/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive - if(!HDD || !RHDD) - return 1 - var/datum/computer_file/F = RHDD.find_file_by_name(href_list["PRG_copyfromusb"]) - if(!F || !istype(F)) - return 1 - var/datum/computer_file/C = F.clone(0) - HDD.store_file(C) - if(.) - SSnanoui.update_uis(NM) + data["error"] = null + if(error) + data["error"] = error + if(!computer || !HDD) + data["error"] = "I/O ERROR: Unable to access hard drive." -/datum/nano_module/program/computer_filemanager - name = "NTOS File Manager" + data["filedata"] = null + data["filename"] = null + data["files"] = list() + data["usbconnected"] = FALSE + data["usbfiles"] = list() -/datum/nano_module/program/computer_filemanager/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() - var/datum/computer_file/program/filemanager/PRG - PRG = program - - var/obj/item/computer_hardware/hard_drive/HDD - var/obj/item/computer_hardware/hard_drive/portable/RHDD - if(PRG.error) - data["error"] = PRG.error - if(PRG.open_file) + if(open_file) var/datum/computer_file/data/file - if(!PRG.computer || !PRG.computer.hard_drive) + if(!computer || !computer.hard_drive) data["error"] = "I/O ERROR: Unable to access hard drive." else - HDD = PRG.computer.hard_drive - file = HDD.find_file_by_name(PRG.open_file) + file = HDD.find_file_by_name(open_file) if(!istype(file)) data["error"] = "I/O ERROR: Unable to open file." else data["filedata"] = pencode2html(file.stored_data) data["filename"] = "[file.filename].[file.filetype]" else - if(!PRG.computer || !PRG.computer.hard_drive) - data["error"] = "I/O ERROR: Unable to access hard drive." - else - HDD = PRG.computer.hard_drive - RHDD = PRG.computer.portable_drive - var/list/files[0] - for(var/datum/computer_file/F in HDD.stored_files) - files.Add(list(list( + var/list/files = list() + for(var/datum/computer_file/F in HDD.stored_files) + files += list(list( + "name" = F.filename, + "type" = F.filetype, + "size" = F.size, + "undeletable" = F.undeletable + )) + data["files"] = files + if(RHDD) + data["usbconnected"] = TRUE + var/list/usbfiles = list() + for(var/datum/computer_file/F in RHDD.stored_files) + usbfiles += list(list( "name" = F.filename, "type" = F.filetype, "size" = F.size, "undeletable" = F.undeletable - ))) - data["files"] = files - if(RHDD) - data["usbconnected"] = 1 - var/list/usbfiles[0] - for(var/datum/computer_file/F in RHDD.stored_files) - usbfiles.Add(list(list( - "name" = F.filename, - "type" = F.filetype, - "size" = F.size, - "undeletable" = F.undeletable - ))) - data["usbfiles"] = usbfiles + )) + data["usbfiles"] = usbfiles - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "file_manager.tmpl", "NTOS File Manager", 575, 700, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() + return data diff --git a/code/modules/modular_computers/file_system/programs/generic/game.dm b/code/modules/modular_computers/file_system/programs/generic/game.dm index de2f379995b..fa7bba9c1ea 100644 --- a/code/modules/modular_computers/file_system/programs/generic/game.dm +++ b/code/modules/modular_computers/file_system/programs/generic/game.dm @@ -1,152 +1,188 @@ // This file is used as a reference for Modular Computers Development guide on the wiki. It contains a lot of excess comments, as it is intended as explanation // for someone who may not be as experienced in coding. When making changes, please try to keep it this way. -// An actual program definition. /datum/computer_file/program/game - filename = "arcadec" // File name, as shown in the file browser program. - filedesc = "Unknown Game" // User-Friendly name. In this case, we will generate a random name in constructor. - program_icon_state = "game" // Icon state of this program's screen. - program_menu_icon = "script" - extended_desc = "Fun for the whole family! Probably not an AAA title, but at least you can download it on the corporate network.." // A nice description. - size = 5 // Size in GQ. Integers only. Smaller sizes should be used for utility/low use programs (like this one), while large sizes are for important programs. - requires_ntnet = 0 // This particular program does not require NTNet network conectivity... - available_on_ntnet = 1 // ... but we want it to be available for download. - nanomodule_path = /datum/nano_module/arcade_classic/ // Path of relevant nano module. The nano module is defined further in the file. - var/picked_enemy_name + filename = "dsarcade" // File name, as shown in the file browser program. + filedesc = "Donksoft Micro Arcade" // User-Friendly name. + program_icon_state = "arcade" // Icon state of this program's screen. + extended_desc = "This is a port of the classic game 'Outbomb Cuban Pete', redesigned to run on tablets; Now with thrilling graphics and chilling storytelling." // A nice description. + size = 6 // Size in GQ. Integers only. Smaller sizes should be used for utility/low use programs (like this one), while large sizes are for important programs. + requires_ntnet = FALSE // This particular program does not require NTNet network conectivity... + available_on_ntnet = TRUE // ... but we want it to be available for download. + tgui_id = "NtosArcade" // Path of relevant tgui template.js file. -// Blatantly stolen and shortened version from arcade machines. Generates a random enemy name -/datum/computer_file/program/game/proc/random_enemy_name() - var/name_part1 = pick("the Automatic ", "Farmer ", "Lord ", "Professor ", "the Cuban ", "the Evil ", "the Dread King ", "the Space ", "Lord ", "the Great ", "Duke ", "General ") - var/name_part2 = pick("Melonoid", "Murdertron", "Sorcerer", "Ruin", "Jeff", "Ectoplasm", "Crushulon", "Uhangoid", "Vhakoid", "Peteoid", "Slime", "Lizard Man", "Unicorn") - return "[name_part1] [name_part2]" + ///Returns TRUE if the game is being played. + var/game_active = TRUE + ///This disables buttom actions from having any impact if TRUE. Resets to FALSE when the player is allowed to make an action again. + var/pause_state = FALSE + var/boss_hp = 45 + var/boss_mp = 15 + var/player_hp = 30 + var/player_mp = 10 + var/ticket_count = 0 + ///Shows what text is shown on the app, usually showing the log of combat actions taken by the player. + var/heads_up = "Nanotrasen says, winners make us money." + var/boss_name = "Cuban Pete's Minion" + ///Determines which boss image to use on the UI. + var/boss_id = 1 -// When the program is first created, we generate a new enemy name and name ourselves accordingly. -/datum/computer_file/program/game/New() - ..() - picked_enemy_name = random_enemy_name() - filedesc = "Defeat [picked_enemy_name]" +// This is the primary game loop, which handles the logic of being defeated or winning. +/datum/computer_file/program/game/proc/game_check(mob/user) + sleep(5) + if(boss_hp <= 0) + heads_up = "You have crushed [boss_name]! Rejoice!" + playsound(computer.loc, 'sound/arcade/win.ogg', 50, TRUE, extrarange = -3, falloff = 0.1) + game_active = FALSE + program_icon_state = "arcade_off" + if(istype(computer)) + computer.update_icon() + ticket_count += 1 + // user?.mind?.adjust_experience(/datum/skill/gaming, 50) + sleep(10) + else if(player_hp <= 0 || player_mp <= 0) + heads_up = "You have been defeated... how will the station survive?" + playsound(computer.loc, 'sound/arcade/lose.ogg', 50, TRUE, extrarange = -3, falloff = 0.1) + game_active = FALSE + program_icon_state = "arcade_off" + if(istype(computer)) + computer.update_icon() + // user?.mind?.adjust_experience(/datum/skill/gaming, 10) + sleep(10) -// Important in order to ensure that copied versions will have the same enemy name. -/datum/computer_file/program/game/clone() - var/datum/computer_file/program/game/G = ..() - G.picked_enemy_name = picked_enemy_name - return G - -// When running the program, we also want to pass our enemy name to the nano module. -/datum/computer_file/program/game/run_program() - . = ..() - if(. && NM) - var/datum/nano_module/arcade_classic/NMC = NM - NMC.enemy_name = picked_enemy_name - - -// Nano module the program uses. -// This can be either /datum/nano_module/ or /datum/nano_module/program. The latter is intended for nano modules that are suposed to be exclusively used with modular computers, -// and should generally not be used, as such nano modules are hard to use on other places. -/datum/nano_module/arcade_classic/ - name = "Classic Arcade" - var/player_mana // Various variables specific to the nano module. In this case, the nano module is a simple arcade game, so the variables store health and other stats. - var/player_health - var/enemy_mana - var/enemy_health - var/enemy_name = "Greytide Horde" - var/gameover - var/information - -/datum/nano_module/arcade_classic/New() - ..() - new_game() - -// nano_ui_interact handles transfer of data to NanoUI. Keep in mind that data you pass from here is actually sent to the client. In other words, don't send anything you don't want a client -// to see, and don't send unnecessarily large amounts of data (due to laginess). -/datum/nano_module/arcade_classic/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() - - data["player_health"] = player_health - data["player_mana"] = player_mana - data["enemy_health"] = enemy_health - data["enemy_mana"] = enemy_mana - data["enemy_name"] = enemy_name - data["gameover"] = gameover - data["information"] = information - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "arcade_classic.tmpl", "Defeat [enemy_name]", 500, 350, state = state) - if(host.update_layout()) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - -// Three helper procs i've created. These are unique to this particular nano module. If you are creating your own nano module, you'll most likely create similar procs too. -/datum/nano_module/arcade_classic/proc/enemy_play() - if((enemy_mana < 5) && prob(60)) - var/steal = rand(2, 3) - player_mana -= steal - enemy_mana += steal - information += "[enemy_name] steals [steal] of your power!" - else if((enemy_health < 15) && (enemy_mana > 3) && prob(80)) - var/healamt = min(rand(3, 5), enemy_mana) - enemy_mana -= healamt - enemy_health += healamt - information += "[enemy_name] heals for [healamt] health!" +// This handles the boss "AI". +/datum/computer_file/program/game/proc/enemy_check(mob/user) + var/boss_attackamt = 0 //Spam protection from boss attacks as well. + var/boss_mpamt = 0 + var/bossheal = 0 + if(pause_state == TRUE) + boss_attackamt = rand(3,6) + boss_mpamt = rand (2,4) + bossheal = rand (4,6) + if(game_active == FALSE) + return + if(boss_mp <= 5) + heads_up = "[boss_mpamt] magic power has been stolen from you!" + playsound(computer.loc, 'sound/arcade/steal.ogg', 50, TRUE, extrarange = -3, falloff = 0.1) + player_mp -= boss_mpamt + boss_mp += boss_mpamt + else if(boss_mp > 5 && boss_hp <12) + heads_up = "[boss_name] heals for [bossheal] health!" + playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3, falloff = 0.1) + boss_hp += bossheal + boss_mp -= boss_mpamt else - var/dam = rand(3,6) - player_health -= dam - information += "[enemy_name] attacks for [dam] damage!" + heads_up = "[boss_name] attacks you for [boss_attackamt] damage!" + playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3, falloff = 0.1) + player_hp -= boss_attackamt -/datum/nano_module/arcade_classic/proc/check_gameover() - if((player_health <= 0) || player_mana <= 0) - if(enemy_health <= 0) - information += "You have defeated [enemy_name], but you have died in the fight!" - else - information += "You have been defeated by [enemy_name]!" - gameover = 1 + pause_state = FALSE + game_check() + +/** + * UI assets define a list of asset datums to be sent with the UI. + * In this case, it's a bunch of cute enemy sprites. + */ +/datum/computer_file/program/game/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/simple/arcade), + ) + +/** + * This provides all of the relevant data to the UI in a list(). + */ +/datum/computer_file/program/game/ui_data(mob/user) + var/list/data = get_header_data() + data["Hitpoints"] = boss_hp + data["PlayerHitpoints"] = player_hp + data["PlayerMP"] = player_mp + data["TicketCount"] = ticket_count + data["GameActive"] = game_active + data["PauseState"] = pause_state + data["Status"] = heads_up + data["BossID"] = "boss[boss_id].gif" + return data + +/** + * This is tgui's replacement for Topic(). It handles any user input from the UI. + */ +/datum/computer_file/program/game/ui_act(action, list/params) + if(..()) // Always call parent in ui_act, it handles making sure the user is allowed to interact with the UI. return TRUE - else if(enemy_health <= 0) - gameover = 1 - information += "Congratulations! You have defeated [enemy_name]!" - return TRUE - return FALSE -/datum/nano_module/arcade_classic/proc/new_game() - player_mana = 10 - player_health = 30 - enemy_mana = 20 - enemy_health = 45 - gameover = FALSE - information = "A new game has started!" + var/obj/item/computer_hardware/nano_printer/printer + if(computer) + printer = computer.nano_printer - - -/datum/nano_module/arcade_classic/Topic(href, href_list) - if(..()) // Always begin your Topic() calls with a parent call! - return 1 - if(href_list["new_game"]) - new_game() - return 1 // Returning 1 (TRUE) in Topic automatically handles UI updates. - if(gameover) // If the game has already ended, we don't want the following three topic calls to be processed at all. - return 1 // Instead of adding checks into each of those three, we can easily add this one check here to reduce on code copy-paste. - if(href_list["attack"]) - var/damage = rand(2, 6) - information = "You attack for [damage] damage." - enemy_health -= damage - enemy_play() - check_gameover() - return 1 - if(href_list["heal"]) - var/healfor = rand(6, 8) - var/cost = rand(1, 3) - information = "You heal yourself for [healfor] damage, using [cost] energy in the process." - player_health += healfor - player_mana -= cost - enemy_play() - check_gameover() - return 1 - if(href_list["regain_mana"]) - var/regen = rand(4, 7) - information = "You rest of a while, regaining [regen] energy." - player_mana += regen - enemy_play() - check_gameover() - return 1 + // var/gamerSkillLevel = usr.mind?.get_skill_level(/datum/skill/gaming) + // var/gamerSkill = usr.mind?.get_skill_modifier(/datum/skill/gaming, SKILL_RANDS_MODIFIER) + switch(action) + if("Attack") + var/attackamt = 0 //Spam prevention. + if(pause_state == FALSE) + attackamt = rand(2,6) // + rand(0, gamerSkill) + pause_state = TRUE + heads_up = "You attack for [attackamt] damage." + playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3, falloff = 0.1) + boss_hp -= attackamt + sleep(10) + game_check() + enemy_check() + return TRUE + if("Heal") + var/healamt = 0 //More Spam Prevention. + var/healcost = 0 + if(pause_state == FALSE) + healamt = rand(6,8) // + rand(0, gamerSkill) + var/maxPointCost = 3 + // if(gamerSkillLevel >= SKILL_LEVEL_JOURNEYMAN) + // maxPointCost = 2 + healcost = rand(1, maxPointCost) + pause_state = TRUE + heads_up = "You heal for [healamt] damage." + playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3, falloff = 0.1) + player_hp += healamt + player_mp -= healcost + sleep(10) + game_check() + enemy_check() + return TRUE + if("Recharge_Power") + var/rechargeamt = 0 //As above. + if(pause_state == FALSE) + rechargeamt = rand(4,7) // + rand(0, gamerSkill) + pause_state = TRUE + heads_up = "You regain [rechargeamt] magic power." + playsound(computer.loc, 'sound/arcade/mana.ogg', 50, TRUE, extrarange = -3, falloff = 0.1) + player_mp += rechargeamt + sleep(10) + game_check() + enemy_check() + return TRUE + if("Dispense_Tickets") + if(!printer) + to_chat(usr, "Hardware error: A printer is required to redeem tickets.") + return + if(printer.stored_paper <= 0) + to_chat(usr, "Hardware error: Printer is out of paper.") + return + else + computer.visible_message("\The [computer] prints out paper.") + if(ticket_count >= 1) + new /obj/item/stack/arcadeticket((get_turf(computer)), 1) + to_chat(usr, "[src] dispenses a ticket!") + ticket_count -= 1 + printer.stored_paper -= 1 + else + to_chat(usr, "You don't have any stored tickets!") + return TRUE + if("Start_Game") + game_active = TRUE + boss_hp = 45 + player_hp = 30 + player_mp = 10 + heads_up = "You stand before [boss_name]! Prepare for battle!" + program_icon_state = "arcade" + boss_id = rand(1,6) + pause_state = FALSE + if(istype(computer)) + computer.update_icon() diff --git a/code/modules/modular_computers/file_system/programs/generic/news_browser.dm b/code/modules/modular_computers/file_system/programs/generic/news_browser.dm index ae03b2c1bd4..4e8f4c3ad9a 100644 --- a/code/modules/modular_computers/file_system/programs/generic/news_browser.dm +++ b/code/modules/modular_computers/file_system/programs/generic/news_browser.dm @@ -6,16 +6,17 @@ program_key_state = "generic_key" program_menu_icon = "contact" size = 4 - requires_ntnet = 1 - available_on_ntnet = 1 + requires_ntnet = TRUE + available_on_ntnet = TRUE + + tgui_id = "NtosNewsBrowser" - nanomodule_path = /datum/nano_module/program/computer_newsbrowser/ var/datum/computer_file/data/news_article/loaded_article var/download_progress = 0 var/download_netspeed = 0 - var/downloading = 0 + var/downloading = FALSE var/message = "" - var/show_archived = 0 + var/show_archived = FALSE /datum/computer_file/program/newsbrowser/process_tick() if(!downloading) @@ -33,86 +34,31 @@ if(download_progress >= loaded_article.size) downloading = 0 requires_ntnet = 0 // Turn off NTNet requirement as we already loaded the file into local memory. - SSnanoui.update_uis(NM) + SStgui.update_uis(src) -/datum/computer_file/program/newsbrowser/kill_program() - ..() - requires_ntnet = 1 - loaded_article = null - download_progress = 0 - downloading = 0 - show_archived = 0 +/datum/computer_file/program/newsbrowser/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = get_header_data() -/datum/computer_file/program/newsbrowser/Topic(href, href_list) - if(..()) - return 1 - if(href_list["PRG_openarticle"]) - . = 1 - if(downloading || loaded_article) - return 1 - - for(var/datum/computer_file/data/news_article/N in ntnet_global.available_news) - if(N.uid == text2num(href_list["PRG_openarticle"])) - loaded_article = N.clone() - downloading = 1 - break - if(href_list["PRG_reset"]) - . = 1 - downloading = 0 - download_progress = 0 - requires_ntnet = 1 - loaded_article = null - if(href_list["PRG_clearmessage"]) - . = 1 - message = "" - if(href_list["PRG_savearticle"]) - . = 1 - if(downloading || !loaded_article) - return - - var/savename = sanitize(input(usr, "Enter file name or leave blank to cancel:", "Save article", loaded_article.filename)) - if(!savename) - return 1 - var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive - if(!HDD) - return 1 - var/datum/computer_file/data/news_article/N = loaded_article.clone() - N.filename = savename - HDD.store_file(N) - if(href_list["PRG_toggle_archived"]) - . = 1 - show_archived = !show_archived - if(.) - SSnanoui.update_uis(NM) - - -/datum/nano_module/program/computer_newsbrowser - name = "NTNet/ExoNet News Browser" - -/datum/nano_module/program/computer_newsbrowser/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - - var/datum/computer_file/program/newsbrowser/PRG - var/list/data = list() - if(program) - data = program.get_header_data() - PRG = program - else - return - - data["message"] = PRG.message - if(PRG.loaded_article && !PRG.downloading) // Viewing an article. - data["title"] = PRG.loaded_article.filename - data["cover"] = PRG.loaded_article.cover - data["article"] = PRG.loaded_article.stored_data - else if(PRG.downloading) // Downloading an article. - data["download_running"] = 1 - data["download_progress"] = PRG.download_progress - data["download_maxprogress"] = PRG.loaded_article.size - data["download_rate"] = PRG.download_netspeed + var/list/all_articles = list() + data["message"] = message + data["showing_archived"] = show_archived + data["download"] = null + data["article"] = null + if(loaded_article && !downloading) // Viewing an article. + data["article"] = list( + "title" = loaded_article.filename, + "cover" = loaded_article.cover, + "content" = loaded_article.stored_data, + ) + else if(downloading) // Downloading an article. + data["download"] = list( + "download_progress" = download_progress, + "download_maxprogress" = loaded_article.size, + "download_rate" = download_netspeed + ) else // Viewing list of articles - var/list/all_articles[0] for(var/datum/computer_file/data/news_article/F in ntnet_global.available_news) - if(!PRG.show_archived && F.archived) + if(!show_archived && F.archived) continue all_articles.Add(list(list( "name" = F.filename, @@ -120,12 +66,56 @@ "uid" = F.uid, "archived" = F.archived ))) - data["all_articles"] = all_articles - data["showing_archived"] = PRG.show_archived + data["all_articles"] = all_articles + + return data + +/datum/computer_file/program/newsbrowser/kill_program() + ..() + requires_ntnet = TRUE + loaded_article = null + download_progress = 0 + downloading = FALSE + show_archived = FALSE + +/datum/computer_file/program/newsbrowser/ui_act(action, list/params, datum/tgui/ui) + if(..()) + return TRUE + switch(action) + if("PRG_openarticle") + . = TRUE + if(downloading || loaded_article) + return TRUE + + for(var/datum/computer_file/data/news_article/N in ntnet_global.available_news) + if(N.uid == text2num(params["uid"])) + loaded_article = N.clone() + downloading = 1 + break + if("PRG_reset") + . = TRUE + downloading = 0 + download_progress = 0 + requires_ntnet = 1 + loaded_article = null + if("PRG_clearmessage") + . = TRUE + message = "" + if("PRG_savearticle") + . = TRUE + if(downloading || !loaded_article) + return + + var/savename = sanitize(input(usr, "Enter file name or leave blank to cancel:", "Save article", loaded_article.filename)) + if(!savename) + return TRUE + var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive + if(!HDD) + return TRUE + var/datum/computer_file/data/news_article/N = loaded_article.clone() + N.filename = savename + HDD.store_file(N) + if("PRG_toggle_archived") + . = TRUE + show_archived = !show_archived - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "news_browser.tmpl", "NTNet/ExoNet News Browser", 575, 750, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() diff --git a/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm b/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm index 6929a7cc3df..310a7a7bce3 100644 --- a/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm +++ b/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm @@ -5,29 +5,26 @@ program_key_state = "generic_key" program_menu_icon = "arrowthickstop-1-s" extended_desc = "This program allows downloads of software from official NT repositories" - unsendable = 1 - undeletable = 1 + unsendable = TRUE + undeletable = TRUE size = 4 - requires_ntnet = 1 + requires_ntnet = TRUE requires_ntnet_feature = NTNET_SOFTWAREDOWNLOAD - available_on_ntnet = 0 - nanomodule_path = /datum/nano_module/program/computer_ntnetdownload/ + available_on_ntnet = FALSE ui_header = "downloader_finished.gif" + tgui_id = "NtosNetDownloader" + var/datum/computer_file/program/downloaded_file = null var/hacked_download = 0 var/download_completion = 0 //GQ of downloaded data. var/download_netspeed = 0 var/downloaderror = "" + var/obj/item/modular_computer/my_computer = null var/list/downloads_queue[0] /datum/computer_file/program/ntnetdownload/kill_program() ..() - downloaded_file = null - download_completion = 0 - download_netspeed = 0 - downloaderror = "" - ui_header = "downloader_finished.gif" - + abort_file_download() /datum/computer_file/program/ntnetdownload/proc/begin_file_download(var/filename) if(downloaded_file) @@ -108,93 +105,85 @@ download_netspeed = NTNETSPEED_ETHERNET download_completion += download_netspeed -/datum/computer_file/program/ntnetdownload/Topic(href, href_list) +/datum/computer_file/program/ntnetdownload/ui_act(action, params) if(..()) - return 1 - if(href_list["PRG_downloadfile"]) - if(!downloaded_file) - begin_file_download(href_list["PRG_downloadfile"]) - else if(check_file_download(href_list["PRG_downloadfile"]) && !downloads_queue.Find(href_list["PRG_downloadfile"]) && downloaded_file.filename != href_list["PRG_downloadfile"]) - downloads_queue += href_list["PRG_downloadfile"] - return 1 - if(href_list["PRG_removequeued"]) - downloads_queue.Remove(href_list["PRG_removequeued"]) - return 1 - if(href_list["PRG_reseterror"]) - if(downloaderror) - download_completion = 0 - download_netspeed = 0 - downloaded_file = null - downloaderror = "" - return 1 - return 0 - -/datum/nano_module/program/computer_ntnetdownload - name = "Network Downloader" - var/obj/item/modular_computer/my_computer = null - -/datum/nano_module/program/computer_ntnetdownload/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - if(program) - my_computer = program.computer + return TRUE + switch(action) + if("PRG_downloadfile") + if(!downloaded_file) + begin_file_download(params["filename"]) + else if(check_file_download(params["filename"]) && !downloads_queue.Find(params["filename"]) && downloaded_file.filename != params["filename"]) + downloads_queue += params["filename"] + return TRUE + if("PRG_removequeued") + downloads_queue.Remove(params["filename"]) + return TRUE + if("PRG_reseterror") + if(downloaderror) + download_completion = 0 + download_netspeed = 0 + downloaded_file = null + downloaderror = "" + return TRUE + return FALSE +/datum/computer_file/program/ntnetdownload/ui_data(mob/user) + my_computer = computer if(!istype(my_computer)) return - var/list/data = list() - var/datum/computer_file/program/ntnetdownload/prog = program - // For now limited to execution by the downloader program - if(!prog || !istype(prog)) - return - if(program) - data = program.get_header_data() + var/list/data = get_header_data() - // This IF cuts on data transferred to client, so i guess it's worth it. - if(prog.downloaderror) // Download errored. Wait until user resets the program. - data["error"] = prog.downloaderror - if(prog.downloaded_file) // Download running. Wait please.. - data["downloadname"] = prog.downloaded_file.filename - data["downloaddesc"] = prog.downloaded_file.filedesc - data["downloadsize"] = prog.downloaded_file.size - data["downloadspeed"] = prog.download_netspeed - data["downloadcompletion"] = round(prog.download_completion, 0.1) + data["downloading"] = !!downloaded_file + data["error"] = downloaderror || FALSE + + if(downloaded_file) // Download running. Wait please.. + data["downloadname"] = downloaded_file.filename + data["downloaddesc"] = downloaded_file.filedesc + data["downloadsize"] = downloaded_file.size + data["downloadspeed"] = download_netspeed + data["downloadcompletion"] = round(download_completion, 0.1) data["disk_size"] = my_computer.hard_drive.max_capacity data["disk_used"] = my_computer.hard_drive.used_capacity var/list/all_entries[0] for(var/datum/computer_file/program/P in ntnet_global.available_station_software) // Only those programs our user can run will show in the list - if(!P.can_run(user) && P.requires_access_to_download) + if(!P.can_run(user) && P.requires_access_to_download || my_computer.hard_drive.find_file_by_name(P.filename)) continue all_entries.Add(list(list( - "filename" = P.filename, - "filedesc" = P.filedesc, - "fileinfo" = P.extended_desc, - "size" = P.size, - "icon" = P.program_menu_icon - ))) - data["hackedavailable"] = 0 - if(prog.computer_emagged) // If we are running on emagged computer we have access to some "bonus" software - var/list/hacked_programs[0] - for(var/datum/computer_file/program/P in ntnet_global.available_antag_software) - data["hackedavailable"] = 1 - hacked_programs.Add(list(list( "filename" = P.filename, "filedesc" = P.filedesc, "fileinfo" = P.extended_desc, + "compatibility" = check_compatibility(P), "size" = P.size, "icon" = P.program_menu_icon + ))) + data["hackedavailable"] = FALSE + if(computer_emagged) // If we are running on emagged computer we have access to some "bonus" software + var/list/hacked_programs[0] + for(var/datum/computer_file/program/P in ntnet_global.available_antag_software) + if(my_computer.hard_drive.find_file_by_name(P.filename)) + continue + data["hackedavailable"] = TRUE + hacked_programs.Add(list(list( + "filename" = P.filename, + "filedesc" = P.filedesc, + "fileinfo" = P.extended_desc, + "compatibility" = check_compatibility(P), + "size" = P.size, + "icon" = P.program_menu_icon ))) data["hacked_programs"] = hacked_programs data["downloadable_programs"] = all_entries + data["downloads_queue"] = downloads_queue - if(prog.downloads_queue.len > 0) - data["downloads_queue"] = prog.downloads_queue + return data - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "ntnet_downloader.tmpl", "NTNet Download Program", 575, 700, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) +/datum/computer_file/program/ntnetdownload/proc/check_compatibility(datum/computer_file/program/P) + var/hardflag = computer.hardware_flag + + if(P && P.is_supported_by_hardware(hardflag,0)) + return "Compatible" + return "Incompatible!" diff --git a/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm b/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm index 40bc8e273f8..23374990a50 100644 --- a/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm +++ b/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm @@ -11,222 +11,222 @@ network_destination = "NTNRC server" ui_header = "ntnrc_idle.gif" available_on_ntnet = 1 - nanomodule_path = /datum/nano_module/program/computer_chatclient/ - var/last_message = null // Used to generate the toolbar icon + tgui_id = "NtosNetChat" + var/last_message // Used to generate the toolbar icon var/username - var/datum/ntnet_conversation/channel = null - var/operator_mode = 0 // Channel operator mode - var/netadmin_mode = 0 // Administrator mode (invisible to other users + bypasses passwords) + var/active_channel + var/list/channel_history = list() + var/operator_mode = FALSE // Channel operator mode + var/netadmin_mode = FALSE // Administrator mode (invisible to other users + bypasses passwords) + var/ntnet /datum/computer_file/program/chatclient/New() username = "DefaultUser[rand(100, 999)]" + ntnet = ntnet_global -/datum/computer_file/program/chatclient/Topic(href, href_list) +/datum/computer_file/program/chatclient/ui_act(action, params) if(..()) - return 1 + return - if(href_list["PRG_speak"]) - . = 1 - if(!channel) - return 1 - var/mob/living/user = usr - var/message = sanitize(input(user, "Enter message or leave blank to cancel: "), 512) - if(!message || !channel) - return - channel.add_message(message, username) + var/datum/ntnet_conversation/channel = ntnet_global.get_chat_channel_by_id(active_channel) + var/authed = FALSE + if(channel && ((channel.operator == src) || netadmin_mode)) + authed = TRUE + switch(action) + if("PRG_speak") + if(!channel || isnull(active_channel)) + return + var/message = reject_bad_text(params["message"]) + if(!message) + return + if(channel.password && !(src in channel.clients)) + if(channel.password == message) + channel.add_client(src) + return TRUE - if(href_list["PRG_joinchannel"]) - . = 1 - var/datum/ntnet_conversation/C - for(var/datum/ntnet_conversation/chan in ntnet_global.chat_channels) - if(chan.id == text2num(href_list["PRG_joinchannel"])) - C = chan - break + channel.add_message(message, username) + // var/mob/living/user = usr + // user.log_talk(message, LOG_CHAT, tag="as [username] to channel [channel.title]") + return TRUE + if("PRG_joinchannel") + var/new_target = text2num(params["id"]) + if(isnull(new_target) || new_target == active_channel) + return - if(!C) - return 1 + if(netadmin_mode) + active_channel = new_target // Bypasses normal leave/join and passwords. Technically makes the user invisible to others. + return TRUE - if(netadmin_mode) - channel = C // Bypasses normal leave/join and passwords. Technically makes the user invisible to others. - return 1 - - if(C.password) + active_channel = new_target + channel = ntnet_global.get_chat_channel_by_id(new_target) + if(!(src in channel.clients) && !channel.password) + channel.add_client(src) + return TRUE + if("PRG_leavechannel") + if(channel) + channel.remove_client(src) + active_channel = null + return TRUE + if("PRG_newchannel") + var/channel_title = reject_bad_text(params["new_channel_name"]) + if(!channel_title) + return + var/datum/ntnet_conversation/C = new /datum/ntnet_conversation() + C.add_client(src) + C.operator = src + C.title = channel_title + active_channel = C.id + return TRUE + if("PRG_toggleadmin") + if(netadmin_mode) + netadmin_mode = FALSE + if(channel) + channel.remove_client(src) // We shouldn't be in channel's user list, but just in case... + return TRUE var/mob/living/user = usr - var/password = sanitize(input(user,"Access Denied. Enter password:")) - if(C && (password == C.password)) - C.add_client(src) - channel = C - return 1 - C.add_client(src) - channel = C - if(href_list["PRG_leavechannel"]) - . = 1 - if(channel) - channel.remove_client(src) - channel = null - if(href_list["PRG_newchannel"]) - . = 1 - var/mob/living/user = usr - var/channel_title = sanitizeSafe(input(user,"Enter channel name or leave blank to cancel:"), 64) - if(!channel_title) - return - var/datum/ntnet_conversation/C = new/datum/ntnet_conversation() - C.add_client(src) - C.operator = src - channel = C - C.title = channel_title - if(href_list["PRG_toggleadmin"]) - . = 1 - if(netadmin_mode) - netadmin_mode = 0 - if(channel) - channel.remove_client(src) // We shouldn't be in channel's user list, but just in case... - channel = null - return 1 - var/mob/living/user = usr - if(can_run(usr, 1, ACCESS_SCIENCE_EXONET)) - if(channel) - var/response = alert(user, "Really engage admin-mode? You will be disconnected from your current channel!", "NTNRC Admin mode", "Yes", "No") - if(response == "Yes") - if(channel) - channel.remove_client(src) - channel = null - else - return - netadmin_mode = 1 - if(href_list["PRG_changename"]) - . = 1 - var/mob/living/user = usr - var/newname = sanitize(input(user,"Enter new nickname or leave blank to cancel:"), 20) - if(!newname) - return 1 - if(channel) - channel.add_status_message("[username] is now known as [newname].") - username = newname + if(can_run(user, TRUE, ACCESS_NETWORK)) + for(var/C in ntnet_global.chat_channels) + var/datum/ntnet_conversation/chan = C + chan.remove_client(src) + netadmin_mode = TRUE + return TRUE + if("PRG_changename") + var/newname = sanitize(params["new_name"]) + if(!newname) + return + for(var/C in ntnet_global.chat_channels) + var/datum/ntnet_conversation/chan = C + if(src in chan.clients) + chan.add_status_message("[username] is now known as [newname].") + username = newname + return TRUE + if("PRG_savelog") + if(!channel) + return + var/logname = stripped_input(params["log_name"]) + if(!logname) + return + var/datum/computer_file/data/logfile = new /datum/computer_file/data/logfile() + // Now we will generate HTML-compliant file that can actually be viewed/printed. + logfile.filename = logname + logfile.stored_data = "\[b\]Logfile dump from NTNRC channel [channel.title]\[/b\]\[BR\]" + for(var/logstring in channel.messages) + logfile.stored_data = "[logfile.stored_data][logstring]\[BR\]" + logfile.stored_data = "[logfile.stored_data]\[b\]Logfile dump completed.\[/b\]" + logfile.calculate_size() + if(!computer || !computer.hard_drive || !computer.hard_drive.store_file(logfile)) + if(!computer) + // This program shouldn't even be runnable without computer. + CRASH("Var computer is null!") + if(!computer.hard_drive) + computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive connection error\" warning.") + else // In 99.9% cases this will mean our HDD is full + computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive may be full. Please free some space and try again. Required space: [logfile.size]GQ\" warning.") + return TRUE + if("PRG_renamechannel") + if(!authed) + return + var/newname = reject_bad_text(params["new_name"]) + if(!newname || !channel) + return + channel.add_status_message("Channel renamed from [channel.title] to [newname] by operator.") + channel.title = newname + return TRUE + if("PRG_deletechannel") + if(authed) + qdel(channel) + active_channel = null + return TRUE + if("PRG_setpassword") + if(!authed) + return - if(href_list["PRG_savelog"]) - . = 1 - if(!channel) - return - var/mob/living/user = usr - var/logname = input(user,"Enter desired logfile name (.log) or leave blank to cancel:") - if(!logname || !channel) - return 1 - var/datum/computer_file/data/logfile = new/datum/computer_file/data/logfile() - // Now we will generate HTML-compliant file that can actually be viewed/printed. - logfile.filename = logname - logfile.stored_data = "\[b\]Logfile dump from NTNRC channel [channel.title]\[/b\]\[BR\]" - for(var/logstring in channel.messages) - logfile.stored_data += "[logstring]\[BR\]" - logfile.stored_data += "\[b\]Logfile dump completed.\[/b\]" - logfile.calculate_size() - if(!computer || !computer.hard_drive || !computer.hard_drive.store_file(logfile)) - if(!computer) - // This program shouldn't even be runnable without computer. - . = TRUE - CRASH("Var computer is null!") - if(!computer.hard_drive) - computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive connection error\" warning.") - else // In 99.9% cases this will mean our HDD is full - computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive may be full. Please free some space and try again. Required space: [logfile.size]GQ\" warning.") - if(href_list["PRG_renamechannel"]) - . = 1 - if(!operator_mode || !channel) - return 1 - var/mob/living/user = usr - var/newname = sanitize(input(user, "Enter new channel name or leave blank to cancel:"), 64) - if(!newname || !channel) - return - channel.add_status_message("Channel renamed from [channel.title] to [newname] by operator.") - channel.title = newname - if(href_list["PRG_deletechannel"]) - . = 1 - if(channel && ((channel.operator == src) || netadmin_mode)) - qdel(channel) - channel = null - if(href_list["PRG_setpassword"]) - . = 1 - if(!channel || ((channel.operator != src) && !netadmin_mode)) - return 1 + var/new_password = sanitize(params["new_password"]) + if(!authed) + return - var/mob/living/user = usr - var/newpassword = sanitize(input(user, "Enter new password for this channel. Leave blank to cancel, enter 'nopassword' to remove password completely:")) - if(!channel || !newpassword || ((channel.operator != src) && !netadmin_mode)) - return 1 - - if(newpassword == "nopassword") - channel.password = "" - else - channel.password = newpassword + channel.password = new_password + return TRUE /datum/computer_file/program/chatclient/process_tick() ..() + var/datum/ntnet_conversation/channel = ntnet_global.get_chat_channel_by_id(active_channel) if(program_state != PROGRAM_STATE_KILLED) ui_header = "ntnrc_idle.gif" if(channel) // Remember the last message. If there is no message in the channel remember null. - last_message = channel.messages.len ? channel.messages[channel.messages.len - 1] : null + last_message = length(channel.messages) ? channel.messages[channel.messages.len - 1] : null else last_message = null return 1 - if(channel && channel.messages && channel.messages.len) + if(channel?.messages?.len) ui_header = last_message == channel.messages[channel.messages.len - 1] ? "ntnrc_idle.gif" : "ntnrc_new.gif" else ui_header = "ntnrc_idle.gif" -/datum/computer_file/program/chatclient/kill_program(var/forced = 0) - if(channel) +/datum/computer_file/program/chatclient/kill_program(forced = FALSE) + for(var/C in ntnet_global.chat_channels) + var/datum/ntnet_conversation/channel = C channel.remove_client(src) - channel = null - ..(forced) - -/datum/nano_module/program/computer_chatclient - name = "NTNet Relay Chat Client" - -/datum/nano_module/program/computer_chatclient/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - if(!ntnet_global || !ntnet_global.chat_channels) - return + ..() +/datum/computer_file/program/chatclient/ui_static_data(mob/user) var/list/data = list() - if(program) - data = program.get_header_data() + data["can_admin"] = can_run(user, FALSE, ACCESS_NETWORK) + return data - var/datum/computer_file/program/chatclient/C = program - if(!istype(C)) - return +/datum/computer_file/program/chatclient/ui_data(mob/user) + if(!ntnet_global || !ntnet_global.chat_channels) + return list() - data["adminmode"] = C.netadmin_mode - if(C.channel) - data["title"] = C.channel.title - var/list/messages[0] - for(var/M in C.channel.messages) - messages.Add(list(list( - "msg" = M + var/list/data = get_header_data() + + var/list/all_channels = list() + for(var/C in ntnet_global.chat_channels) + var/datum/ntnet_conversation/conv = C + if(conv && conv.title) + all_channels.Add(list(list( + "chan" = conv.title, + "id" = conv.id ))) - data["messages"] = messages - var/list/clients[0] - for(var/datum/computer_file/program/chatclient/cl in C.channel.clients) + data["all_channels"] = all_channels + + data["active_channel"] = active_channel + data["username"] = username + data["adminmode"] = netadmin_mode + var/datum/ntnet_conversation/channel = ntnet_global.get_chat_channel_by_id(active_channel) + if(channel) + data["title"] = channel.title + var/authed = FALSE + if(!channel.password) + authed = TRUE + if(netadmin_mode) + authed = TRUE + var/list/clients = list() + for(var/C in channel.clients) + if(C == src) + authed = TRUE + var/datum/computer_file/program/chatclient/cl = C clients.Add(list(list( "name" = cl.username ))) - data["clients"] = clients - C.operator_mode = (C.channel.operator == C) ? 1 : 0 - data["is_operator"] = C.operator_mode || C.netadmin_mode - - else // Channel selection screen - var/list/all_channels[0] - for(var/datum/ntnet_conversation/conv in ntnet_global.chat_channels) - if(conv && conv.title) - all_channels.Add(list(list( - "chan" = conv.title, - "id" = conv.id + data["authed"] = authed + //no fishing for ui data allowed + if(authed) + data["clients"] = clients + var/list/messages = list() + for(var/M in channel.messages) + messages.Add(list(list( + "msg" = M ))) - data["all_channels"] = all_channels + data["messages"] = messages + data["is_operator"] = (channel.operator == src) || netadmin_mode + else + data["clients"] = list() + data["messages"] = list() + else + data["clients"] = list() + data["authed"] = FALSE + data["messages"] = list() - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "ntnet_chat.tmpl", "NTNet Relay Chat Client", 575, 700, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data diff --git a/code/modules/modular_computers/file_system/programs/generic/nttransfer.dm b/code/modules/modular_computers/file_system/programs/generic/nttransfer.dm index 7072fe5c6ae..b5fff1167ee 100644 --- a/code/modules/modular_computers/file_system/programs/generic/nttransfer.dm +++ b/code/modules/modular_computers/file_system/programs/generic/nttransfer.dm @@ -12,7 +12,7 @@ var/global/nttransfer_uid = 0 requires_ntnet_feature = NTNET_PEERTOPEER network_destination = "other device via P2P tunnel" available_on_ntnet = 1 - nanomodule_path = /datum/nano_module/program/computer_nttransfer/ + tgui_id = "NtosNetTransfer" var/error = "" // Error screen var/server_password = "" // Optional password to download the file. @@ -64,7 +64,7 @@ var/global/nttransfer_uid = 0 // Crashes the download and displays specific error message /datum/computer_file/program/nttransfer/proc/crash_download(var/message) - error = message ? message : "An unknown error has occured during download" + error = message ? message : "An unknown error has occurred during download" finalize_download() // Cleans up variables for next use @@ -75,111 +75,101 @@ var/global/nttransfer_uid = 0 remote = null download_completion = 0 +/datum/computer_file/program/nttransfer/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = get_header_data() -/datum/nano_module/program/computer_nttransfer - name = "NTNet P2P Transfer Client" + data["error"] = error -/datum/nano_module/program/computer_nttransfer/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - if(!program) - return - var/datum/computer_file/program/nttransfer/PRG = program - if(!istype(PRG)) - return + data["downloading"] = !!downloaded_file + if(downloaded_file) + data["download_size"] = downloaded_file.size + data["download_progress"] = download_completion + data["download_netspeed"] = actual_netspeed + data["download_name"] = "[downloaded_file.filename].[downloaded_file.filetype]" - var/list/data = program.get_header_data() + data["uploading"] = !!provided_file + if(provided_file) + data["upload_uid"] = unique_token + data["upload_clients"] = connected_clients.len + data["upload_haspassword"] = server_password ? 1 : 0 + data["upload_filename"] = "[provided_file.filename].[provided_file.filetype]" - if(PRG.error) - data["error"] = PRG.error - else if(PRG.downloaded_file) - data["downloading"] = 1 - data["download_size"] = PRG.downloaded_file.size - data["download_progress"] = PRG.download_completion - data["download_netspeed"] = PRG.actual_netspeed - data["download_name"] = "[PRG.downloaded_file.filename].[PRG.downloaded_file.filetype]" - else if (PRG.provided_file) - data["uploading"] = 1 - data["upload_uid"] = PRG.unique_token - data["upload_clients"] = PRG.connected_clients.len - data["upload_haspassword"] = PRG.server_password ? 1 : 0 - data["upload_filename"] = "[PRG.provided_file.filename].[PRG.provided_file.filetype]" - else if (PRG.upload_menu) - var/list/all_files[0] - for(var/datum/computer_file/F in PRG.computer.hard_drive.stored_files) + data["upload_filelist"] = list() + if(upload_menu) + var/list/all_files = list() + for(var/datum/computer_file/F in computer.hard_drive.stored_files) all_files.Add(list(list( "uid" = F.uid, "filename" = "[F.filename].[F.filetype]", "size" = F.size ))) data["upload_filelist"] = all_files - else - var/list/all_servers[0] + + data["servers"] = list() + if(!(downloaded_file || provided_file || upload_menu)) + var/list/all_servers = list() for(var/datum/computer_file/program/nttransfer/P in ntnet_global.fileservers) if(!P.provided_file) continue all_servers.Add(list(list( - "uid" = P.unique_token, - "filename" = "[P.provided_file.filename].[P.provided_file.filetype]", - "size" = P.provided_file.size, - "haspassword" = P.server_password ? 1 : 0 + "uid" = P.unique_token, + "filename" = "[P.provided_file.filename].[P.provided_file.filetype]", + "size" = P.provided_file.size, + "haspassword" = P.server_password ? 1 : 0 ))) data["servers"] = all_servers - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "ntnet_transfer.tmpl", "NTNet P2P Transfer Client", 575, 700, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data -/datum/computer_file/program/nttransfer/Topic(href, href_list) +/datum/computer_file/program/nttransfer/ui_act(action, list/params, datum/tgui/ui) if(..()) - return 1 - if(href_list["PRG_downloadfile"]) - for(var/datum/computer_file/program/nttransfer/P in ntnet_global.fileservers) - if("[P.unique_token]" == href_list["PRG_downloadfile"]) - remote = P - break - if(!remote || !remote.provided_file) - return - if(remote.server_password) - var/pass = sanitize(input(usr, "Code 401 Unauthorized. Please enter password:", "Password required")) - if(pass != remote.server_password) - error = "Incorrect Password" + return TRUE + switch(action) + if("PRG_downloadfile") + for(var/datum/computer_file/program/nttransfer/P in ntnet_global.fileservers) + if(P.unique_token == text2num(params["uid"])) + remote = P + break + if(!remote || !remote.provided_file) return - downloaded_file = remote.provided_file.clone() - remote.connected_clients.Add(src) - return 1 - if(href_list["PRG_reset"]) - error = "" - upload_menu = 0 - finalize_download() - if(src in ntnet_global.fileservers) - ntnet_global.fileservers.Remove(src) - for(var/datum/computer_file/program/nttransfer/T in connected_clients) - T.crash_download("Remote server has forcibly closed the connection") - provided_file = null - return 1 - if(href_list["PRG_setpassword"]) - var/pass = sanitize(input(usr, "Enter new server password. Leave blank to cancel, input 'none' to disable password.", "Server security", "none")) - if(!pass) - return - if(pass == "none") - server_password = "" - return - server_password = pass - return 1 - if(href_list["PRG_uploadfile"]) - for(var/datum/computer_file/F in computer.hard_drive.stored_files) - if("[F.uid]" == href_list["PRG_uploadfile"]) - if(F.unsendable) - error = "I/O Error: File locked." + if(remote.server_password) + var/pass = sanitize(input(usr, "Code 401 Unauthorized. Please enter password:", "Password required")) + if(pass != remote.server_password) + error = "Incorrect Password" return - provided_file = F - ntnet_global.fileservers.Add(src) + downloaded_file = remote.provided_file.clone() + remote.connected_clients.Add(src) + return TRUE + if("PRG_reset") + error = "" + upload_menu = 0 + finalize_download() + if(src in ntnet_global.fileservers) + ntnet_global.fileservers.Remove(src) + for(var/datum/computer_file/program/nttransfer/T in connected_clients) + T.crash_download("Remote server has forcibly closed the connection") + provided_file = null + return TRUE + if("PRG_setpassword") + var/pass = sanitize(input(usr, "Enter new server password. Leave blank to cancel, input 'none' to disable password.", "Server security", "none")) + if(!pass) return - error = "I/O Error: Unable to locate file on hard drive." - return 1 - if(href_list["PRG_uploadmenu"]) - upload_menu = 1 - return 0 + if(pass == "none") + server_password = "" + return + server_password = pass + return TRUE + if("PRG_uploadfile") + for(var/datum/computer_file/F in computer.hard_drive.stored_files) + if(F.uid == text2num(params["uid"])) + if(F.unsendable) + error = "I/O Error: File locked." + return + provided_file = F + ntnet_global.fileservers |= src + return + error = "I/O Error: Unable to locate file on hard drive." + return TRUE + if("PRG_uploadmenu") + upload_menu = 1 + return TRUE diff --git a/code/modules/modular_computers/file_system/programs/generic/uav.dm b/code/modules/modular_computers/file_system/programs/generic/uav.dm index 06504deaf97..bf909e4d792 100644 --- a/code/modules/modular_computers/file_system/programs/generic/uav.dm +++ b/code/modules/modular_computers/file_system/programs/generic/uav.dm @@ -4,7 +4,7 @@ /datum/computer_file/program/uav filename = "rigger" filedesc = "UAV Control" - nanomodule_path = /datum/nano_module/uav + tguimodule_path = /datum/tgui_module/uav program_icon_state = "comm_monitor" program_key_state = "generic_key" program_menu_icon = "link" @@ -12,6 +12,8 @@ size = 12 available_on_ntnet = 1 //requires_ntnet = 1 +<<<<<<< HEAD +======= /datum/nano_module/uav name = "UAV Control program" @@ -264,3 +266,4 @@ M.clear_fullscreen("fishbed",0) M.clear_fullscreen("scanlines",0) M.clear_fullscreen("whitenoise",0) +>>>>>>> 787c6065a7ab2843080de41ea1d62e0322e8dd9c diff --git a/code/modules/modular_computers/file_system/programs/generic/wordprocessor.dm b/code/modules/modular_computers/file_system/programs/generic/wordprocessor.dm index fe1b8972fd4..0170a4dd30e 100644 --- a/code/modules/modular_computers/file_system/programs/generic/wordprocessor.dm +++ b/code/modules/modular_computers/file_system/programs/generic/wordprocessor.dm @@ -5,9 +5,10 @@ program_icon_state = "word" program_key_state = "atmos_key" size = 4 - requires_ntnet = 0 - available_on_ntnet = 1 - nanomodule_path = /datum/nano_module/program/computer_wordprocessor/ + requires_ntnet = FALSE + available_on_ntnet = TRUE + tgui_id = "NtosWordProcessor" + var/browsing var/open_file var/loaded_data @@ -28,7 +29,7 @@ if(F) open_file = F.filename loaded_data = F.stored_data - return 1 + return TRUE /datum/computer_file/program/wordprocessor/proc/save_file(var/filename) var/datum/computer_file/data/F = get_file(filename) @@ -46,7 +47,7 @@ HDD.store_file(backup) return 0 is_edited = 0 - return 1 + return TRUE /datum/computer_file/program/wordprocessor/proc/create_file(var/newname, var/data = "") if(!newname) @@ -64,141 +65,144 @@ if(HDD.store_file(F)) return F -/datum/computer_file/program/wordprocessor/Topic(href, href_list) +/datum/computer_file/program/wordprocessor/ui_act(action, list/params, datum/tgui/ui) if(..()) - return 1 + return TRUE - if(href_list["PRG_txtrpeview"]) - show_browser(usr,"[open_file][pencode2html(loaded_data)]", "window=[open_file]") - return 1 + switch(action) + if("PRG_txtrpeview") + show_browser(usr,"[open_file][pencode2html(loaded_data)]", "window=[open_file]") + return TRUE - if(href_list["PRG_taghelp"]) - to_chat(usr, "The hologram of a googly-eyed paper clip helpfully tells you:") - var/help = {" - \[br\] : Creates a linebreak. - \[center\] - \[/center\] : Centers the text. - \[h1\] - \[/h1\] : First level heading. - \[h2\] - \[/h2\] : Second level heading. - \[h3\] - \[/h3\] : Third level heading. - \[b\] - \[/b\] : Bold. - \[i\] - \[/i\] : Italic. - \[u\] - \[/u\] : Underlined. - \[small\] - \[/small\] : Decreases the size of the text. - \[large\] - \[/large\] : Increases the size of the text. - \[field\] : Inserts a blank text field, which can be filled later. Useful for forms. - \[date\] : Current station date. - \[time\] : Current station time. - \[list\] - \[/list\] : Begins and ends a list. - \[*\] : A list item. - \[hr\] : Horizontal rule. - \[table\] - \[/table\] : Creates table using \[row\] and \[cell\] tags. - \[grid\] - \[/grid\] : Table without visible borders, for layouts. - \[row\] - New table row. - \[cell\] - New table cell. - \[logo\] - Inserts NT logo image. - \[redlogo\] - Inserts red NT logo image."} + if("PRG_taghelp") + to_chat(usr, "The hologram of a googly-eyed paper clip helpfully tells you:") + var/help = {" + \[br\] : Creates a linebreak. + \[center\] - \[/center\] : Centers the text. + \[h1\] - \[/h1\] : First level heading. + \[h2\] - \[/h2\] : Second level heading. + \[h3\] - \[/h3\] : Third level heading. + \[b\] - \[/b\] : Bold. + \[i\] - \[/i\] : Italic. + \[u\] - \[/u\] : Underlined. + \[small\] - \[/small\] : Decreases the size of the text. + \[large\] - \[/large\] : Increases the size of the text. + \[field\] : Inserts a blank text field, which can be filled later. Useful for forms. + \[date\] : Current station date. + \[time\] : Current station time. + \[list\] - \[/list\] : Begins and ends a list. + \[*\] : A list item. + \[hr\] : Horizontal rule. + \[table\] - \[/table\] : Creates table using \[row\] and \[cell\] tags. + \[grid\] - \[/grid\] : Table without visible borders, for layouts. + \[row\] - New table row. + \[cell\] - New table cell. + \[logo\] - Inserts NT logo image. + \[redlogo\] - Inserts red NT logo image. + \[sglogo\] - Inserts Solgov insignia image."} - to_chat(usr, help) - return 1 + to_chat(usr, help) + return TRUE - if(href_list["PRG_closebrowser"]) - browsing = 0 - return 1 + if("PRG_closebrowser") + browsing = 0 + return TRUE - if(href_list["PRG_backtomenu"]) - error = null - return 1 + if("PRG_backtomenu") + error = null + return TRUE - if(href_list["PRG_loadmenu"]) - browsing = 1 - return 1 + if("PRG_loadmenu") + browsing = 1 + return TRUE - if(href_list["PRG_openfile"]) - . = 1 - if(is_edited) - if(alert("Would you like to save your changes first?",,"Yes","No") == "Yes") - save_file(open_file) - browsing = 0 - if(!open_file(href_list["PRG_openfile"])) - error = "I/O error: Unable to open file '[href_list["PRG_openfile"]]'." + if("PRG_openfile") + if(is_edited) + if(alert("Would you like to save your changes first?",,"Yes","No") == "Yes") + save_file(open_file) + browsing = 0 + if(!open_file(params["PRG_openfile"])) + error = "I/O error: Unable to open file '[params["PRG_openfile"]]'." + return TRUE - if(href_list["PRG_newfile"]) - . = 1 - if(is_edited) - if(alert("Would you like to save your changes first?",,"Yes","No") == "Yes") - save_file(open_file) + if("PRG_newfile") + if(is_edited) + if(alert("Would you like to save your changes first?",,"Yes","No") == "Yes") + save_file(open_file) - var/newname = sanitize(input(usr, "Enter file name:", "New File") as text|null) - if(!newname) - return 1 - var/datum/computer_file/data/F = create_file(newname) - if(F) - open_file = F.filename - loaded_data = "" - return 1 - else - error = "I/O error: Unable to create file '[href_list["PRG_saveasfile"]]'." + var/newname = sanitize(input(usr, "Enter file name:", "New File") as text|null) + if(!newname) + return TRUE + var/datum/computer_file/data/F = create_file(newname) + if(F) + open_file = F.filename + loaded_data = "" + return TRUE + else + error = "I/O error: Unable to create file '[params["PRG_saveasfile"]]'." + return TRUE - if(href_list["PRG_saveasfile"]) - . = 1 - var/newname = sanitize(input(usr, "Enter file name:", "Save As") as text|null) - if(!newname) - return 1 - var/datum/computer_file/data/F = create_file(newname, loaded_data) - if(F) - open_file = F.filename - else - error = "I/O error: Unable to create file '[href_list["PRG_saveasfile"]]'." - return 1 + if("PRG_saveasfile") + var/newname = sanitize(input(usr, "Enter file name:", "Save As") as text|null) + if(!newname) + return TRUE + var/datum/computer_file/data/F = create_file(newname, loaded_data) + if(F) + open_file = F.filename + else + error = "I/O error: Unable to create file '[params["PRG_saveasfile"]]'." + return TRUE - if(href_list["PRG_savefile"]) - . = 1 - if(!open_file) - open_file = sanitize(input(usr, "Enter file name:", "Save As") as text|null) + if("PRG_savefile") if(!open_file) - return 0 - if(!save_file(open_file)) - error = "I/O error: Unable to save file '[open_file]'." - return 1 + open_file = sanitize(input(usr, "Enter file name:", "Save As") as text|null) + if(!open_file) + return 0 + if(!save_file(open_file)) + error = "I/O error: Unable to save file '[open_file]'." + return TRUE - if(href_list["PRG_editfile"]) - var/oldtext = html_decode(loaded_data) - oldtext = replacetext(oldtext, "\[br\]", "\n") + if("PRG_editfile") + var/oldtext = html_decode(loaded_data) + oldtext = replacetext(oldtext, "\[br\]", "\n") - var/newtext = sanitize(replacetext(input(usr, "Editing file '[open_file]'. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[br\]"), MAX_TEXTFILE_LENGTH) - if(!newtext) - return - loaded_data = newtext - is_edited = 1 - return 1 + var/newtext = sanitize(replacetext(input(usr, "Editing file '[open_file]'. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[br\]"), MAX_TEXTFILE_LENGTH) + if(!newtext) + return + loaded_data = newtext + is_edited = 1 + return TRUE - if(href_list["PRG_printfile"]) - . = 1 - if(!computer.nano_printer) - error = "Missing Hardware: Your computer does not have the required hardware to complete this operation." - return 1 - if(!computer.nano_printer.print_text(pencode2html(loaded_data))) - error = "Hardware error: Printer was unable to print the file. It may be out of paper." - return 1 + if("PRG_printfile") + if(!computer.nano_printer) + error = "Missing Hardware: Your computer does not have the required hardware to complete this operation." + return TRUE + if(!computer.nano_printer.print_text(pencode2html(loaded_data))) + error = "Hardware error: Printer was unable to print the file. It may be out of paper." + return TRUE + return TRUE -/datum/nano_module/program/computer_wordprocessor - name = "Word Processor" +/datum/computer_file/program/wordprocessor/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = get_header_data() -/datum/nano_module/program/computer_wordprocessor/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() - var/datum/computer_file/program/wordprocessor/PRG - PRG = program + var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive + var/obj/item/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive + data["error"] = null + if(error) + data["error"] = error - var/obj/item/computer_hardware/hard_drive/HDD - var/obj/item/computer_hardware/hard_drive/portable/RHDD - if(PRG.error) - data["error"] = PRG.error - if(PRG.browsing) - data["browsing"] = PRG.browsing - if(!PRG.computer || !PRG.computer.hard_drive) + data["browsing"] = null + data["files"] = list() + data["usbconnected"] = FALSE + data["usbfiles"] = list() + data["filedata"] = null + data["filename"] = null + + if(browsing) + data["browsing"] = browsing + if(!computer || !HDD) data["error"] = "I/O ERROR: Unable to access hard drive." else - HDD = PRG.computer.hard_drive var/list/files[0] for(var/datum/computer_file/F in HDD.stored_files) if(F.filetype == "TXT") @@ -208,7 +212,6 @@ ))) data["files"] = files - RHDD = PRG.computer.portable_drive if(RHDD) data["usbconnected"] = 1 var/list/usbfiles[0] @@ -219,16 +222,11 @@ "size" = F.size, ))) data["usbfiles"] = usbfiles - else if(PRG.open_file) - data["filedata"] = pencode2html(PRG.loaded_data) - data["filename"] = PRG.is_edited ? "[PRG.open_file]*" : PRG.open_file + else if(open_file) + data["filedata"] = pencode2html(loaded_data) + data["filename"] = is_edited ? "[open_file]*" : open_file else - data["filedata"] = pencode2html(PRG.loaded_data) + data["filedata"] = pencode2html(loaded_data) data["filename"] = "UNNAMED" - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "word_processor.tmpl", "Word Processor", 575, 700, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() + return data diff --git a/code/modules/modular_computers/file_system/programs/research/email_administration.dm b/code/modules/modular_computers/file_system/programs/research/email_administration.dm index 1e68a00102e..40d58b1ec7d 100644 --- a/code/modules/modular_computers/file_system/programs/research/email_administration.dm +++ b/code/modules/modular_computers/file_system/programs/research/email_administration.dm @@ -8,29 +8,34 @@ size = 12 requires_ntnet = 1 available_on_ntnet = 1 - nanomodule_path = /datum/nano_module/email_administration - required_access = ACCESS_SCIENCE_EXONET + tgui_id = "NtosEmailAdministration" + required_access = ACCESS_NETWORK - - - -/datum/nano_module/email_administration/ - name = "Email Client" var/datum/computer_file/data/email_account/current_account = null var/datum/computer_file/data/email_message/current_message = null var/error = "" -/datum/nano_module/email_administration/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() +/datum/computer_file/program/email_administration/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = get_header_data() - if(error) - data["error"] = error - else if(istype(current_message)) - data["msg_title"] = current_message.title - data["msg_body"] = pencode2html(current_message.stored_data) - data["msg_timestamp"] = current_message.timestamp - data["msg_source"] = current_message.source - else if(istype(current_account)) + data["error"] = error + + data["cur_title"] = null + data["cur_body"] = null + data["cur_timestamp"] = null + data["cur_source"] = null + + if(istype(current_message)) + data["cur_title"] = current_message.title + data["cur_body"] = pencode2html(current_message.stored_data) + data["cur_timestamp"] = current_message.timestamp + data["cur_source"] = current_message.source + + data["current_account"] = null + data["cur_suspended"] = null + data["messages"] = null + + if(istype(current_account)) data["current_account"] = current_account.login data["cur_suspended"] = current_account.suspended var/list/all_messages = list() @@ -42,103 +47,90 @@ "uid" = message.uid ))) data["messages"] = all_messages - data["messagecount"] = all_messages.len - else - var/list/all_accounts = list() - for(var/datum/computer_file/data/email_account/account in ntnet_global.email_accounts) - if(!account.can_login) - continue - all_accounts.Add(list(list( - "login" = account.login, - "uid" = account.uid - ))) - data["accounts"] = all_accounts - data["accountcount"] = all_accounts.len - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "email_administration.tmpl", "Email Administration Utility", 600, 450, state = state) - if(host.update_layout()) - ui.auto_update_layout = 1 - ui.set_auto_update(1) - ui.set_initial_data(data) - ui.open() + var/list/all_accounts = list() + for(var/datum/computer_file/data/email_account/account in ntnet_global.email_accounts) + if(!account.can_login) + continue + all_accounts.Add(list(list( + "login" = account.login, + "uid" = account.uid + ))) + data["accounts"] = all_accounts + return data -/datum/nano_module/email_administration/Topic(href, href_list) +/datum/computer_file/program/email_administration/ui_act(action, list/params, datum/tgui/ui) if(..()) - return 1 - - var/mob/user = usr - if(!istype(user)) - return 1 + return TRUE // High security - can only be operated when the user has an ID with access on them. - var/obj/item/card/id/I = user.GetIdCard() - if(!istype(I) || !(ACCESS_SCIENCE_EXONET in I.access)) - return 1 + var/obj/item/card/id/I = usr.GetIdCard() + if(!istype(I) || !(ACCESS_NETWORK in I.access)) + return TRUE - if(href_list["back"]) - if(error) - error = "" - else if(current_message) - current_message = null - else - current_account = null - return 1 + switch(action) + if("back") + if(error) + error = "" + else if(current_message) + current_message = null + else + current_account = null + return TRUE - if(href_list["ban"]) - if(!current_account) - return 1 + if("ban") + if(!current_account) + return TRUE - current_account.suspended = !current_account.suspended - ntnet_global.add_log_with_ids_check("EMAIL LOG: SA-EDIT Account [current_account.login] has been [current_account.suspended ? "" : "un" ]suspended by SA [I.registered_name] ([I.assignment]).") - error = "Account [current_account.login] has been [current_account.suspended ? "" : "un" ]suspended." - return 1 + current_account.suspended = !current_account.suspended + ntnet_global.add_log_with_ids_check("EMAIL LOG: SA-EDIT Account [current_account.login] has been [current_account.suspended ? "" : "un" ]suspended by SA [I.registered_name] ([I.assignment]).") + error = "Account [current_account.login] has been [current_account.suspended ? "" : "un" ]suspended." + return TRUE - if(href_list["changepass"]) - if(!current_account) - return 1 + if("changepass") + if(!current_account) + return TRUE - var/newpass = sanitize(input(user,"Enter new password for account [current_account.login]", "Password"), 100) - if(!newpass) - return 1 - current_account.password = newpass - ntnet_global.add_log_with_ids_check("EMAIL LOG: SA-EDIT Password for account [current_account.login] has been changed by SA [I.registered_name] ([I.assignment]).") - return 1 + var/newpass = sanitize(input(usr,"Enter new password for account [current_account.login]", "Password"), 100) + if(!newpass) + return TRUE + current_account.password = newpass + ntnet_global.add_log_with_ids_check("EMAIL LOG: SA-EDIT Password for account [current_account.login] has been changed by SA [I.registered_name] ([I.assignment]).") + return TRUE - if(href_list["viewmail"]) - if(!current_account) - return 1 + if("viewmail") + if(!current_account) + return TRUE - for(var/datum/computer_file/data/email_message/received_message in (current_account.inbox | current_account.spam | current_account.deleted)) - if(received_message.uid == text2num(href_list["viewmail"])) - current_message = received_message - break - return 1 + for(var/datum/computer_file/data/email_message/received_message in (current_account.inbox | current_account.spam | current_account.deleted)) + if(received_message.uid == text2num(params["viewmail"])) + current_message = received_message + break + return TRUE - if(href_list["viewaccount"]) - for(var/datum/computer_file/data/email_account/email_account in ntnet_global.email_accounts) - if(email_account.uid == text2num(href_list["viewaccount"])) - current_account = email_account - break - return 1 + if("viewaccount") + for(var/datum/computer_file/data/email_account/email_account in ntnet_global.email_accounts) + if(email_account.uid == text2num(params["viewaccount"])) + current_account = email_account + break + return TRUE - if(href_list["newaccount"]) - var/newdomain = sanitize(input(user,"Pick domain:", "Domain name") as null|anything in (LEGACY_MAP_DATUM).usable_email_tlds) - if(!newdomain) - return 1 - var/newlogin = sanitize(input(user,"Pick account name (@[newdomain]):", "Account name"), 100) - if(!newlogin) - return 1 + if("newaccount") + var/newdomain = sanitize(input(usr,"Pick domain:", "Domain name") as null|anything in (LEGACY_MAP_DATUM).usable_email_tlds) + if(!newdomain) + return TRUE + var/newlogin = sanitize(input(usr,"Pick account name (@[newdomain]):", "Account name"), 100) + if(!newlogin) + return TRUE - var/complete_login = "[newlogin]@[newdomain]" - if(ntnet_global.does_email_exist(complete_login)) - error = "Error creating account: An account with same address already exists." - return 1 + var/complete_login = "[newlogin]@[newdomain]" + if(ntnet_global.does_email_exist(complete_login)) + error = "Error creating account: An account with same address already exists." + return TRUE - var/datum/computer_file/data/email_account/new_account = new/datum/computer_file/data/email_account() - new_account.login = complete_login - new_account.password = GenerateKey() - error = "Email [new_account.login] has been created, with generated password [new_account.password]" - return 1 + var/datum/computer_file/data/email_account/new_account = new/datum/computer_file/data/email_account() + new_account.login = complete_login + new_account.password = GenerateKey() + error = "Email [new_account.login] has been created, with generated password [new_account.password]" + return TRUE diff --git a/code/modules/modular_computers/file_system/programs/research/ntmonitor.dm b/code/modules/modular_computers/file_system/programs/research/ntmonitor.dm index dc07ef74c3e..cd734a9c4b5 100644 --- a/code/modules/modular_computers/file_system/programs/research/ntmonitor.dm +++ b/code/modules/modular_computers/file_system/programs/research/ntmonitor.dm @@ -6,19 +6,15 @@ program_menu_icon = "wrench" extended_desc = "This program monitors the local NTNet network, provides access to logging systems, and allows for configuration changes" size = 12 - requires_ntnet = 1 - required_access = ACCESS_SCIENCE_EXONET - available_on_ntnet = 1 - nanomodule_path = /datum/nano_module/computer_ntnetmonitor/ + requires_ntnet = TRUE + required_access = ACCESS_NETWORK + available_on_ntnet = TRUE + tgui_id = "NtosNetMonitor" -/datum/nano_module/computer_ntnetmonitor - name = "NTNet Diagnostics and Monitoring" - //available_to_ai = TRUE - -/datum/nano_module/computer_ntnetmonitor/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) +/datum/computer_file/program/ntnetmonitor/ui_data(mob/user) if(!ntnet_global) return - var/list/data = host.initial_data() + var/list/data = get_header_data() data["ntnetstatus"] = ntnet_global.check_function() data["ntnetrelays"] = ntnet_global.relays.len @@ -30,73 +26,68 @@ data["config_communication"] = ntnet_global.setting_communication data["config_systemcontrol"] = ntnet_global.setting_systemcontrol - data["ntnetlogs"] = ntnet_global.logs - data["ntnetmaxlogs"] = ntnet_global.setting_maxlogcount + data["ntnetlogs"] = list() + data["minlogs"] = MIN_NTNET_LOGS + data["maxlogs"] = MAX_NTNET_LOGS data["banned_nids"] = list(ntnet_global.banned_nids) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "ntnet_monitor.tmpl", "NTNet Diagnostics and Monitoring Tool", 575, 700, state = state) - if(host.update_layout()) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + for(var/i in ntnet_global.logs) + data["ntnetlogs"] += list(list("entry" = i)) + data["ntnetmaxlogs"] = ntnet_global.setting_maxlogcount -/datum/nano_module/computer_ntnetmonitor/Topic(href, href_list, state) - var/mob/user = usr + return data + +/datum/computer_file/program/ntnetmonitor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) if(..()) - return 1 - if(href_list["resetIDS"]) - if(ntnet_global) - ntnet_global.resetIDS() - return 1 - if(href_list["toggleIDS"]) - if(ntnet_global) - ntnet_global.toggleIDS() - return 1 - if(href_list["toggleWireless"]) - if(!ntnet_global) - return 1 + return + switch(action) + if("resetIDS") + if(ntnet_global) + ntnet_global.resetIDS() + return TRUE + if("toggleIDS") + if(ntnet_global) + ntnet_global.toggleIDS() + return TRUE + if("toggleWireless") + if(!ntnet_global) + return - // NTNet is disabled. Enabling can be done without user prompt - if(ntnet_global.setting_disabled) - ntnet_global.setting_disabled = 0 - return 1 + // NTNet is disabled. Enabling can be done without user prompt + if(ntnet_global.setting_disabled) + ntnet_global.setting_disabled = FALSE + return TRUE - // NTNet is enabled and user is about to shut it down. Let's ask them if they really want to do it, as wirelessly connected computers won't connect without NTNet being enabled (which may prevent people from turning it back on) - if(!user) - return 1 - var/response = alert(user, "Really disable NTNet wireless? If your computer is connected wirelessly you won't be able to turn it back on! This will affect all connected wireless devices.", "NTNet shutdown", "Yes", "No") - if(response == "Yes") - ntnet_global.setting_disabled = 1 - return 1 - if(href_list["purgelogs"]) - if(ntnet_global) - ntnet_global.purge_logs() - return 1 - if(href_list["updatemaxlogs"]) - var/logcount = text2num(input(user,"Enter amount of logs to keep in memory ([MIN_NTNET_LOGS]-[MAX_NTNET_LOGS]):")) - if(ntnet_global) - ntnet_global.update_max_log_count(logcount) - return 1 - if(href_list["toggle_function"]) - if(!ntnet_global) - return 1 - ntnet_global.toggle_function(href_list["toggle_function"]) - return 1 - if(href_list["ban_nid"]) - if(!ntnet_global) - return 1 - var/nid = input(user,"Enter NID of device which you want to block from the network:", "Enter NID") as null|num - if(nid && CanUseTopic(user, state)) - ntnet_global.banned_nids |= nid - return 1 - if(href_list["unban_nid"]) - if(!ntnet_global) - return 1 - var/nid = input(user,"Enter NID of device which you want to unblock from the network:", "Enter NID") as null|num - if(nid && CanUseTopic(user, state)) - ntnet_global.banned_nids -= nid - return 1 + var/response = alert(usr, "Really disable NTNet wireless? If your computer is connected wirelessly you won't be able to turn it back on! This will affect all connected wireless devices.", "NTNet shutdown", "Yes", "No") + if(response == "Yes" && ui_status(usr, state) == UI_INTERACTIVE) + ntnet_global.setting_disabled = TRUE + return TRUE + if("purgelogs") + if(ntnet_global) + ntnet_global.purge_logs() + return TRUE + if("updatemaxlogs") + var/logcount = params["new_number"] + if(ntnet_global) + ntnet_global.update_max_log_count(logcount) + return TRUE + if("toggle_function") + if(!ntnet_global) + return + ntnet_global.toggle_function(text2num(params["id"])) + return TRUE + if("ban_nid") + if(!ntnet_global) + return + var/nid = input(usr,"Enter NID of device which you want to block from the network:", "Enter NID") as null|num + if(nid && ui_status(usr, state) == UI_INTERACTIVE) + ntnet_global.banned_nids |= nid + return TRUE + if("unban_nid") + if(!ntnet_global) + return + var/nid = input(usr,"Enter NID of device which you want to unblock from the network:", "Enter NID") as null|num + if(nid && ui_status(usr, state) == UI_INTERACTIVE) + ntnet_global.banned_nids -= nid + return TRUE diff --git a/code/modules/modular_computers/file_system/programs/security/alarm_monitor.dm b/code/modules/modular_computers/file_system/programs/security/alarm_monitor.dm index bbd4e434911..6c4d94a8460 100644 --- a/code/modules/modular_computers/file_system/programs/security/alarm_monitor.dm +++ b/code/modules/modular_computers/file_system/programs/security/alarm_monitor.dm @@ -2,5 +2,5 @@ filename = "alarmmonitorsec" filedesc = "Alarm Monitoring (Security)" extended_desc = "This program provides visual interface for the security alarm system." - nanomodule_path = /datum/nano_module/alarm_monitor/security - required_access = ACCESS_SECURITY_EQUIPMENT + tguimodule_path = /datum/tgui_module_old/alarm_monitor/security/ntos + required_access = ACCESS_SECURITY_MAIN diff --git a/code/modules/modular_computers/file_system/programs/security/digitalwarrant.dm b/code/modules/modular_computers/file_system/programs/security/digitalwarrant.dm index 54cb6ea92b3..1b2c0edd1f9 100644 --- a/code/modules/modular_computers/file_system/programs/security/digitalwarrant.dm +++ b/code/modules/modular_computers/file_system/programs/security/digitalwarrant.dm @@ -1,5 +1,7 @@ -var/warrant_uid = 0 -/datum/datacore/var/list/warrants[] = list() +var/global/warrant_uid = 0 +/datum/datacore + var/list/warrants = list() + /datum/data/record/warrant var/warrant_id @@ -7,7 +9,6 @@ var/warrant_uid = 0 ..() warrant_id = warrant_uid++ - /datum/computer_file/program/digitalwarrant filename = "digitalwarrant" filedesc = "Warrant Assistant" @@ -18,126 +19,119 @@ var/warrant_uid = 0 program_menu_icon = "star" requires_ntnet = 1 available_on_ntnet = 1 - required_access = ACCESS_SECURITY_EQUIPMENT + required_access = ACCESS_SECURITY_MAIN usage_flags = PROGRAM_ALL - nanomodule_path = /datum/nano_module/program/digitalwarrant/ + tgui_id = "NtosDigitalWarrant" -/datum/nano_module/program/digitalwarrant/ - name = "Warrant Assistant" var/datum/data/record/warrant/activewarrant -/datum/nano_module/program/digitalwarrant/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() +/datum/computer_file/program/digitalwarrant/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = get_header_data() + + data["warrantname"] = null + data["warrantcharges"] = null + data["warrantauth"] = null + data["type"] = null if(activewarrant) data["warrantname"] = activewarrant.fields["namewarrant"] data["warrantcharges"] = activewarrant.fields["charges"] data["warrantauth"] = activewarrant.fields["auth"] data["type"] = activewarrant.fields["arrestsearch"] - else - var/list/allwarrants = list() - for(var/datum/data/record/warrant/W in data_core.warrants) - allwarrants.Add(list(list( + + var/list/allwarrants = list() + for(var/datum/data/record/warrant/W in data_core.warrants) + allwarrants.Add(list(list( "warrantname" = W.fields["namewarrant"], "charges" = "[copytext(W.fields["charges"],1,min(length(W.fields["charges"]) + 1, 50))]...", "auth" = W.fields["auth"], "id" = W.warrant_id, "arrestsearch" = W.fields["arrestsearch"] ))) - data["allwarrants"] = allwarrants + data["allwarrants"] = allwarrants - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "digitalwarrant.tmpl", name, 500, 350, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() + return data -/datum/nano_module/program/digitalwarrant/Topic(href, href_list) +/datum/computer_file/program/digitalwarrant/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) if(..()) - return 1 + return TRUE - if(href_list["sw_menu"]) - activewarrant = null + switch(action) + if("back") + . = TRUE + activewarrant = null - if(href_list["editwarrant"]) - . = 1 - for(var/datum/data/record/warrant/W in data_core.warrants) - if(W.warrant_id == text2num(href_list["editwarrant"])) - activewarrant = W - break + if("editwarrant") + . = TRUE + for(var/datum/data/record/warrant/W in data_core.warrants) + if(W.warrant_id == text2num(params["id"])) + activewarrant = W + break // The following actions will only be possible if the user has an ID with security access equipped. This is in line with modular computer framework's authentication methods, // which also use RFID scanning to allow or disallow access to some functions. Anyone can view warrants, editing requires ID. This also prevents situations where you show a tablet // to someone who is to be arrested, which allows them to change the stuff there. - - var/mob/user = usr - if(!istype(user)) - return - var/obj/item/card/id/I = user.GetIdCard() - if(!istype(I) || !I.registered_name || !(ACCESS_SECURITY_EQUIPMENT in I.access)) - to_chat(user, "Authentication error: Unable to locate ID with apropriate access to allow this operation.") + var/obj/item/card/id/I = usr.GetIdCard() + if(!istype(I) || !I.registered_name || !(ACCESS_SECURITY_MAIN in I.access)) + to_chat(usr, "Authentication error: Unable to locate ID with appropriate access to allow this operation.") return - if(href_list["addwarrant"]) - . = 1 - var/datum/data/record/warrant/W = new() - var/temp = sanitize(input(usr, "Do you want to create a search-, or an arrest warrant?") as null|anything in list("search","arrest")) - if(CanInteract(user, default_state)) - if(temp == "arrest") - W.fields["namewarrant"] = "Unknown" - W.fields["charges"] = "No charges present" - W.fields["auth"] = "Unauthorized" - W.fields["arrestsearch"] = "arrest" - if(temp == "search") - W.fields["namewarrant"] = "No location given" - W.fields["charges"] = "No reason given" - W.fields["auth"] = "Unauthorized" - W.fields["arrestsearch"] = "search" - activewarrant = W + switch(action) + if("addwarrant") + . = TRUE + var/datum/data/record/warrant/W = new() + var/temp = sanitize(input(usr, "Do you want to create a search-, or an arrest warrant?") as null|anything in list("search","arrest")) + if(ui_status(usr, state) == UI_INTERACTIVE) + if(temp == "arrest") + W.fields["namewarrant"] = "Unknown" + W.fields["charges"] = "No charges present" + W.fields["auth"] = "Unauthorized" + W.fields["arrestsearch"] = "arrest" + if(temp == "search") + W.fields["namewarrant"] = "No suspect/location given" + W.fields["charges"] = "No reason given" + W.fields["auth"] = "Unauthorized" + W.fields["arrestsearch"] = "search" + activewarrant = W - if(href_list["savewarrant"]) - . = 1 - data_core.warrants |= activewarrant - activewarrant = null + if("savewarrant") + . = TRUE + data_core.warrants |= activewarrant + activewarrant = null - if(href_list["deletewarrant"]) - . = 1 - data_core.warrants -= activewarrant - activewarrant = null + if("deletewarrant") + . = TRUE + data_core.warrants -= activewarrant + activewarrant = null - if(href_list["editwarrantname"]) - . = 1 - var/namelist = list() - for(var/datum/data/record/t in data_core.general) - namelist += t.fields["name"] - var/new_name = sanitize(input(usr, "Please input name") as null|anything in namelist) - if(CanInteract(user, default_state)) - if (!new_name) - return - activewarrant.fields["namewarrant"] = new_name + if("editwarrantname") + . = TRUE + var/namelist = list() + for(var/datum/data/record/t in data_core.general) + namelist += t.fields["name"] + var/new_name = sanitize(input(usr, "Please input name") as null|anything in namelist) + if(ui_status(usr, state) == UI_INTERACTIVE) + if (!new_name) + return + activewarrant.fields["namewarrant"] = new_name - if(href_list["editwarrantnamecustom"]) - . = 1 - var/new_name = sanitize(input("Please input name") as null|text) - if(CanInteract(user, default_state)) - if (!new_name) - return - activewarrant.fields["namewarrant"] = new_name + if("editwarrantnamecustom") + . = TRUE + var/new_name = sanitize(input("Please input name") as null|text) + if(ui_status(usr, state) == UI_INTERACTIVE) + if (!new_name) + return + activewarrant.fields["namewarrant"] = new_name - if(href_list["editwarrantcharges"]) - . = 1 - var/new_charges = sanitize(input("Please input charges", "Charges", activewarrant.fields["charges"]) as null|text) - if(CanInteract(user, default_state)) - if (!new_charges) - return - activewarrant.fields["charges"] = new_charges + if("editwarrantcharges") + . = TRUE + var/new_charges = sanitize(input("Please input charges", "Charges", activewarrant.fields["charges"]) as null|text) + if(ui_status(usr, state) == UI_INTERACTIVE) + if (!new_charges) + return + activewarrant.fields["charges"] = new_charges - if(href_list["editwarrantauth"]) - . = 1 + if("editwarrantauth") + . = TRUE - activewarrant.fields["auth"] = "[I.registered_name] - [I.assignment ? I.assignment : "(Unknown)"]" - - if(href_list["back"]) - . = 1 - activewarrant = null + activewarrant.fields["auth"] = "[I.registered_name] - [I.assignment ? I.assignment : "(Unknown)"]" diff --git a/code/modules/nano/modules/alarm_monitor.dm b/code/modules/nano/modules/alarm_monitor.dm new file mode 100644 index 00000000000..f6016011950 --- /dev/null +++ b/code/modules/nano/modules/alarm_monitor.dm @@ -0,0 +1,103 @@ +/datum/nano_module/alarm_monitor + name = "Alarm monitor" + var/list_cameras = 0 // Whether or not to list camera references. A future goal would be to merge this with the enginering/security camera console. Currently really only for AI-use. + var/list/datum/alarm_handler/alarm_handlers // The particular list of alarm handlers this alarm monitor should present to the user. + //available_to_ai = FALSE + +/datum/nano_module/alarm_monitor/New() + ..() + alarm_handlers = list() + +/datum/nano_module/alarm_monitor/all/New() + ..() + alarm_handlers = SSalarms.all_handlers + +/datum/nano_module/alarm_monitor/engineering/New() + ..() + alarm_handlers = list(atmosphere_alarm, fire_alarm, power_alarm) + +/datum/nano_module/alarm_monitor/security/New() + ..() + alarm_handlers = list(camera_alarm, motion_alarm) + +/datum/nano_module/alarm_monitor/proc/register_alarm(var/object, var/procName) + for(var/datum/alarm_handler/AH in alarm_handlers) + AH.register_alarm(object, procName) + +/datum/nano_module/alarm_monitor/proc/unregister_alarm(var/object) + for(var/datum/alarm_handler/AH in alarm_handlers) + AH.unregister_alarm(object) + +/datum/nano_module/alarm_monitor/proc/all_alarms() + var/list/all_alarms = new() + for(var/datum/alarm_handler/AH in alarm_handlers) + all_alarms += AH.visible_alarms() + + return all_alarms + +/datum/nano_module/alarm_monitor/proc/major_alarms() + var/list/all_alarms = new() + for(var/datum/alarm_handler/AH in alarm_handlers) + all_alarms += AH.major_alarms() + + return all_alarms + +// Modified version of above proc that uses slightly less resources, returns 1 if there is a major alarm, 0 otherwise. +/datum/nano_module/alarm_monitor/proc/has_major_alarms() + for(var/datum/alarm_handler/AH in alarm_handlers) + if(AH.has_major_alarms()) + return 1 + + return 0 + +/datum/nano_module/alarm_monitor/proc/minor_alarms() + var/list/all_alarms = new() + for(var/datum/alarm_handler/AH in alarm_handlers) + all_alarms += AH.minor_alarms() + + return all_alarms + +/datum/nano_module/alarm_monitor/Topic(ref, href_list) + if(..()) + return 1 + if(href_list["switchTo"]) + var/obj/machinery/camera/C = locate(href_list["switchTo"]) in GLOB.cameranet.cameras + if(!C) + return + + usr.switch_to_camera(C) + return 1 + +/datum/nano_module/alarm_monitor/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) + var/list/data = host.initial_data() + + var/categories[0] + for(var/datum/alarm_handler/AH in alarm_handlers) + categories[++categories.len] = list("category" = AH.category, "alarms" = list()) + for(var/datum/alarm/A in AH.major_alarms()) + var/cameras[0] + var/lost_sources[0] + + if(isAI(user)) + for(var/obj/machinery/camera/C in A.cameras()) + cameras[++cameras.len] = C.ui_structure() + for(var/datum/alarm_source/AS in A.sources) + if(!AS.source) + lost_sources[++lost_sources.len] = AS.source_name + + categories[categories.len]["alarms"] += list(list( + "name" = sanitize(A.alarm_name()), + "origin_lost" = A.origin == null, + "has_cameras" = cameras.len, + "cameras" = cameras, + "lost_sources" = lost_sources.len ? sanitize(english_list(lost_sources, nothing_text = "", and_text = ", ")) : "")) + data["categories"] = categories + + ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "alarm_monitor.tmpl", "Alarm Monitoring Console", 800, 800, state = state) + if(host.update_layout()) // This is necessary to ensure the status bar remains updated along with rest of the UI. + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) diff --git a/code/modules/nifsoft/nif_tgui.dm b/code/modules/nifsoft/nif_tgui.dm index 818362e0c30..559dd4073e9 100644 --- a/code/modules/nifsoft/nif_tgui.dm +++ b/code/modules/nifsoft/nif_tgui.dm @@ -109,7 +109,7 @@ ui.open() /** - * tgui_data gives the UI any relevant data it needs. + * ui_data gives the UI any relevant data it needs. * In our case, that's basically everything from our statpanel. */ /obj/item/nif/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) @@ -150,7 +150,7 @@ return data /** - * tgui_act handles all user input in the UI. + * ui_act handles all user input in the UI. */ /obj/item/nif/ui_act(action, list/params, datum/tgui/ui) if(..()) diff --git a/code/modules/power/antimatter/computer.dm b/code/modules/power/antimatter/computer.dm index aa9067bb23e..23d25beed55 100644 --- a/code/modules/power/antimatter/computer.dm +++ b/code/modules/power/antimatter/computer.dm @@ -8,7 +8,7 @@ name = "Antimatter Engine Console" icon = 'icons/obj/stationobjs.dmi' icon_state = "comm_computer" - req_access = list(ACCESS_ENGINE) + req_access = list(ACCESS_ENGINEERING_MAIN) var/engine_id = 0 var/authenticated = 0 var/obj/machinery/power/am_engine/engine/connected_E = null diff --git a/code/modules/power/breaker_box.dm b/code/modules/power/breaker_box.dm index 2c02209b324..591cc56f449 100644 --- a/code/modules/power/breaker_box.dm +++ b/code/modules/power/breaker_box.dm @@ -26,7 +26,7 @@ for(var/obj/structure/cable/C in loc) qdel(C) . = ..() - for(var/datum/nano_module/rcon/R in world) + for(var/datum/tgui_module_old/rcon/R in world) R.FindDevices() /obj/machinery/power/breakerbox/Initialize(mapload) diff --git a/code/modules/power/smes/smes_construction.dm b/code/modules/power/smes/smes_construction.dm index e875d36c8bd..1f31d68d47f 100644 --- a/code/modules/power/smes/smes_construction.dm +++ b/code/modules/power/smes/smes_construction.dm @@ -60,7 +60,7 @@ /obj/machinery/power/smes/buildable/Destroy() QDEL_NULL(wires) - for(var/datum/nano_module/rcon/R in GLOB.rcon_nano_modules) + for(var/datum/tgui_module_old/rcon/R in GLOB.tgui_old_rcon_modules) R.FindDevices() return ..() diff --git a/code/modules/tgui/modules/communications.dm b/code/modules/tgui/modules/communications.dm index 93b106eeb4d..475a72c5792 100644 --- a/code/modules/tgui/modules/communications.dm +++ b/code/modules/tgui/modules/communications.dm @@ -33,13 +33,10 @@ var/datum/legacy_announcement/priority/crew_announcement - var/datum/lore/atc_controller/ATC - var/list/req_access = list() /datum/tgui_module_old/communications/New(host) . = ..() - ATC = atc crew_announcement = new() crew_announcement.newscast = TRUE @@ -68,7 +65,7 @@ var/old_level = GLOB.security_level if(!tmp_alertlevel) tmp_alertlevel = SEC_LEVEL_GREEN if(tmp_alertlevel < SEC_LEVEL_GREEN) tmp_alertlevel = SEC_LEVEL_GREEN - if(tmp_alertlevel > SEC_LEVEL_BLUE) tmp_alertlevel = SEC_LEVEL_BLUE //Cannot engage delta with this + if(tmp_alertlevel > SEC_LEVEL_ORANGE) tmp_alertlevel = SEC_LEVEL_ORANGE //cannot engage red/delta. this code was never updated with the fact that blue is lower than orange/violet/etc set_security_level(tmp_alertlevel) if(GLOB.security_level != old_level) //Only notify the admins if an actual change happened @@ -94,7 +91,7 @@ data["emagged"] = emagged data["authenticated"] = is_authenticated(user, 0) data["authmax"] = data["authenticated"] == COMM_AUTHENTICATION_MAX ? TRUE : FALSE - data["atcsquelch"] = ATC.squelched + data["atcsquelch"] = SSlegacy_atc.squelched data["boss_short"] = (LEGACY_MAP_DATUM).boss_short data["stat_display"] = list( @@ -146,12 +143,12 @@ data["msg_cooldown"] = message_cooldown ? (round((message_cooldown - world.time) / 10)) : 0 data["cc_cooldown"] = centcomm_message_cooldown ? (round((centcomm_message_cooldown - world.time) / 10)) : 0 - data["esc_callable"] = emergency_shuttle.location() && !emergency_shuttle.online() ? TRUE : FALSE - data["esc_recallable"] = emergency_shuttle.location() && emergency_shuttle.online() ? TRUE : FALSE + data["esc_callable"] = SSemergencyshuttle.location() && !SSemergencyshuttle.online() ? TRUE : FALSE + data["esc_recallable"] = SSemergencyshuttle.location() && SSemergencyshuttle.online() ? TRUE : FALSE data["esc_status"] = FALSE - if(emergency_shuttle.has_eta()) - var/timeleft = emergency_shuttle.estimate_arrival_time() - data["esc_status"] = emergency_shuttle.online() ? "ETA:" : "RECALLING:" + if(SSemergencyshuttle.has_eta()) + var/timeleft = SSemergencyshuttle.estimate_arrival_time() + data["esc_status"] = SSemergencyshuttle.online() ? "ETA:" : "RECALLING:" data["esc_status"] += " [timeleft / 60 % 60]:[add_zero(num2text(timeleft % 60), 2)]" return data @@ -200,7 +197,7 @@ /datum/tgui_module_old/communications/ui_act(action, params) if(..()) return TRUE - if(using_map && !(get_z(usr) in using_map.contact_levels)) + if((LEGACY_MAP_DATUM) && !(get_z(usr) in (LEGACY_MAP_DATUM).contact_levels)) to_chat(usr, SPAN_DANGER("Unable to establish a connection: You're too far away from the station!")) return FALSE @@ -274,7 +271,7 @@ return call_shuttle_proc(usr) - if(emergency_shuttle.online()) + if(SSemergencyshuttle.online()) post_status(src, "shuttle", user = usr) setMenuState(usr, COMM_SCREEN_MAIN) @@ -295,7 +292,7 @@ setMenuState(usr, COMM_SCREEN_MESSAGES) if("toggleatc") - ATC.squelched = !ATC.squelched + SSlegacy_atc.squelched = !SSlegacy_atc.squelched if("delmessage") var/datum/comm_message_listener/l = obtain_message_listener() @@ -348,7 +345,7 @@ return message_centcom(input, usr) to_chat(usr, SPAN_NOTICE("Message transmitted.")) - log_game("[key_name(usr)] has made an IA [using_map.boss_short] announcement: [input]") + log_game("[key_name(usr)] has made an IA [(LEGACY_MAP_DATUM).boss_short] announcement: [input]") centcomm_message_cooldown = world.time + 300 // 30 seconds setMenuState(usr, COMM_SCREEN_MAIN) @@ -364,7 +361,7 @@ if(length(input) < COMM_CCMSGLEN_MINIMUM) to_chat(usr, SPAN_WARNING("Message '[input]' is too short. [COMM_CCMSGLEN_MINIMUM] character minimum.")) return - Syndicate_announce(input, usr) + message_syndicate(input, usr) to_chat(usr, SPAN_NOTICE("Message transmitted.")) log_game("[key_name(usr)] has made an illegal announcement: [input]") centcomm_message_cooldown = world.time + 300 // 30 seconds @@ -376,112 +373,3 @@ /datum/tgui_module_old/communications/ntos ntos = TRUE - -/* Etc global procs */ -/proc/enable_prison_shuttle(var/mob/user) - for(var/obj/machinery/computer/prison_shuttle/PS in GLOB.machines) - PS.allowedtocall = !(PS.allowedtocall) - -/proc/call_shuttle_proc(var/mob/user) - if ((!( ticker ) || !emergency_shuttle.location())) - return - - if(!universe.OnShuttleCall(usr)) - to_chat(user, SPAN_NOTICE("Cannot establish a bluespace connection.")) - return - - if(deathsquad.deployed) - to_chat(user, "[(LEGACY_MAP_DATUM).boss_short] will not allow the shuttle to be called. Consider all contracts terminated.") - return - - if(emergency_shuttle.deny_shuttle) - to_chat(user, "The emergency shuttle may not be sent at this time. Please try again later.") - return - - if(world.time < 6000) // Ten minute grace period to let the game get going without lolmetagaming. -- TLE - to_chat(user, "The emergency shuttle is refueling. Please wait another [round((6000-world.time)/600)] minute\s before trying again.") - return - - if(emergency_shuttle.going_to_centcom()) - to_chat(user, "The emergency shuttle may not be called while returning to [(LEGACY_MAP_DATUM).boss_short].") - return - - if(emergency_shuttle.online()) - to_chat(user, "The emergency shuttle is already on its way.") - return - - if(ticker.mode.name == "blob") - to_chat(user, "Under directive 7-10, [station_name()] is quarantined until further notice.") - return - - emergency_shuttle.call_evac() - log_game("[key_name(user)] has called the shuttle.") - message_admins("[key_name_admin(user)] has called the shuttle.", 1) - admin_chat_message(message = "Emergency evac beginning! Called by [key_name(user)]!", color = "#CC2222") - - return - -/proc/init_shift_change(var/mob/user, var/force = 0) - if ((!( ticker ) || !emergency_shuttle.location())) - return - - if(emergency_shuttle.going_to_centcom()) - to_chat(user, "The shuttle may not be called while returning to [(LEGACY_MAP_DATUM).boss_short].") - return - - if(emergency_shuttle.online()) - to_chat(user, "The shuttle is already on its way.") - return - - // if force is 0, some things may stop the shuttle call - if(!force) - if(emergency_shuttle.deny_shuttle) - to_chat(user, "[(LEGACY_MAP_DATUM).boss_short] does not currently have a shuttle available in your sector. Please try again later.") - return - - if(deathsquad.deployed == 1) - to_chat(user, "[(LEGACY_MAP_DATUM).boss_short] will not allow the shuttle to be called. Consider all contracts terminated.") - return - - if(world.time < 54000) // 30 minute grace period to let the game get going - to_chat(user, "The shuttle is refueling. Please wait another [round((54000-world.time)/60)] minutes before trying again.") - return - - if(ticker.mode.auto_recall_shuttle) - //New version pretends to call the shuttle but cause the shuttle to return after a random duration. - emergency_shuttle.auto_recall = 1 - - if(ticker.mode.name == "blob" || ticker.mode.name == "epidemic") - to_chat(user, "Under directive 7-10, [station_name()] is quarantined until further notice.") - return - - emergency_shuttle.call_transfer() - - //delay events in case of an autotransfer - if (isnull(user)) - SSevents.delay_events(EVENT_LEVEL_MODERATE, 9000) //15 minutes - SSevents.delay_events(EVENT_LEVEL_MAJOR, 9000) - - log_game("[user? key_name(user) : "Autotransfer"] has called the shuttle.") - message_admins("[user? key_name_admin(user) : "Autotransfer"] has called the shuttle.", 1) - admin_chat_message(message = "Autotransfer shuttle dispatched, shift ending soon.", color = "#2277BB") - - return - -/proc/cancel_call_proc(var/mob/user) - if (!( ticker ) || !emergency_shuttle.can_recall()) - return - if((ticker.mode.name == "blob")||(ticker.mode.name == "Meteor")) - return - - if(!emergency_shuttle.going_to_centcom()) //check that shuttle isn't already heading to CentCom - emergency_shuttle.recall() - log_game("[key_name(user)] has recalled the shuttle.") - message_admins("[key_name_admin(user)] has recalled the shuttle.", 1) - return - -/proc/is_relay_online() - for(var/obj/machinery/telecomms/relay/M in world) - if(M.stat == 0) - return 1 - return 0 diff --git a/code/modules/tgui/modules/general/cardmod.dm b/code/modules/tgui/modules/general/cardmod.dm index 044330a26ac..6038b1d7c13 100644 --- a/code/modules/tgui/modules/general/cardmod.dm +++ b/code/modules/tgui/modules/general/cardmod.dm @@ -168,10 +168,10 @@ /** * return source id to auth with */ -/datum/tgui_module/card_mod/proc/auth_source() +/datum/tgui_module/card_mod/proc/auth_source(var/user) return null -/datum/tgui_module/card_mod/static_data(mob/user, obj/item/card/id/editing = edit_target(), obj/item/card/id/authing = auth_source()) +/datum/tgui_module/card_mod/static_data(mob/user, obj/item/card/id/editing = edit_target(), obj/item/card/id/authing = auth_source(user)) . = ..() .["access"] = SSjob.tgui_access_data() var/list/direct_cache = ((authing?.access || list()) & SSjob.cached_access_edit_relevant) @@ -191,7 +191,7 @@ "ranks" = ranks_by_department[department], )) -/datum/tgui_module/card_mod/data(mob/user, obj/item/card/id/editing = edit_target(), obj/item/card/id/authing = auth_source()) +/datum/tgui_module/card_mod/data(mob/user, obj/item/card/id/editing = edit_target(), obj/item/card/id/authing = auth_source(user)) . = ..() .["card_account"] = editing?.associated_account_number .["card_name"] = editing?.registered_name @@ -203,7 +203,7 @@ /datum/tgui_module/card_mod/ui_act(action, list/params, datum/tgui/ui) . = ..() var/obj/item/card/id/target = edit_target() - var/obj/item/card/id/source = auth_source() + var/obj/item/card/id/source = auth_source(usr) switch(action) if("account") if(!target) @@ -398,10 +398,31 @@ var/obj/machinery/computer/card/target = host return target.editing -/datum/tgui_module/card_mod/standard/id_computer/auth_source() +/datum/tgui_module/card_mod/standard/id_computer/auth_source(mob/user) var/obj/machinery/computer/card/target = host return target.authing +/datum/tgui_module/card_mod/standard/id_computer/ntos + expected_type = /datum/computer_file/program/card_mod + var/datum/computer_file/program/program + + +/datum/tgui_module/card_mod/standard/id_computer/ntos/New(datum/host) + . = ..() + program = host + +/datum/tgui_module/card_mod/standard/id_computer/ntos/Destroy() + . = ..() + program = null + +/datum/tgui_module/card_mod/standard/id_computer/ntos/edit_target() + return program.computer.card_slot.stored_card + +/datum/tgui_module/card_mod/standard/id_computer/ntos/auth_source(mob/user) + if(isliving(user)) + var/mob/living/L = user + return L.GetIdCard() + /** * admin implementation of card_mod modules * allows editing of anything. diff --git a/code/modules/tgui/modules/ntos-only/cardmod.dm b/code/modules/tgui/modules/ntos-only/cardmod.dm index b8e5ba2faf4..7ba9bdc8869 100644 --- a/code/modules/tgui/modules/ntos-only/cardmod.dm +++ b/code/modules/tgui/modules/ntos-only/cardmod.dm @@ -6,232 +6,3 @@ tgui_id = "IdentificationComputer" var/mod_mode = 1 var/is_centcom = 0 - -/datum/tgui_module_old/cardmod/ui_static_data(mob/user) - var/list/data = ..() - if(data_core) - data_core.get_manifest_list() - data["manifest"] = GLOB.PDA_Manifest - return data - -#warn demote function if not global cardmod -#warn better tgui -#warn bank account check - -/datum/tgui_module_old/cardmod/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) - var/datum/computer_file/program/card_mod/program = host - if(!istype(program)) - return 0 - var/list/data = ..() - data["station_name"] = station_name() - data["mode"] = mod_mode - data["printing"] = FALSE - if(program && program.computer) - data["have_id_slot"] = !!program.computer.card_slot - data["have_printer"] = !!program.computer.nano_printer - data["authenticated"] = program.can_run(user) - if(!program.computer.card_slot) - mod_mode = 0 //We can't modify IDs when there is no card reader - else - data["have_id_slot"] = 0 - data["have_printer"] = 0 - data["authenticated"] = 0 - data["centcom_access"] = is_centcom - - - data["has_modify"] = null - data["account_number"] = null - data["id_rank"] = null - data["target_owner"] = null - data["target_name"] = null - if(program && program.computer && program.computer.card_slot) - var/obj/item/card/id/id_card = program.computer.card_slot.stored_card - data["has_modify"] = !!id_card - data["account_number"] = id_card ? id_card.associated_account_number : null - data["id_rank"] = id_card && id_card.assignment ? id_card.assignment : "Unassigned" - data["target_owner"] = id_card && id_card.registered_name ? id_card.registered_name : "-----" - data["target_name"] = id_card ? id_card.name : "-----" - - var/list/departments = list() - for(var/D in SSjob.get_all_department_datums()) - var/datum/department/dept = D - if(!dept.assignable) // No AI ID cards for you. - continue - if(dept.centcom_only && !is_centcom) - continue - departments.Add(list(list( - "department_name" = dept.name, - "jobs" = format_jobs(SSjob.get_job_titles_in_department(dept.name)), - ))) - - data["departments"] = departments - - var/list/all_centcom_access = list() - var/list/regions = list() - if(program.computer.card_slot && program.computer.card_slot.stored_card) - var/obj/item/card/id/id_card = program.computer.card_slot.stored_card - if(is_centcom) - for(var/access in get_all_centcom_access()) - all_centcom_access.Add(list(list( - "desc" = replacetext(get_centcom_access_desc(access), " ", " "), - "ref" = access, - "allowed" = (access in id_card.access) ? 1 : 0))) - data["all_centcom_access"] = all_centcom_access - else - for(var/i in DUMB_OLD_ACCESS_REGION_LIST) - var/list/accesses = list() - for(var/access in get_region_accesses(i)) - if(get_access_desc(access)) - accesses.Add(list(list( - "desc" = replacetext(get_access_desc(access), " ", " "), - "ref" = access, - "allowed" = (access in id_card.access) ? 1 : 0))) - - regions.Add(list(list( - "name" = get_region_accesses_name(i), - "accesses" = accesses))) - data["regions"] = regions - - data["regions"] = regions - data["all_centcom_access"] = all_centcom_access - - return data - -/datum/tgui_module_old/cardmod/proc/format_jobs(list/jobs) - var/datum/computer_file/program/card_mod/program = host - if(!istype(program)) - return null - - var/obj/item/card/id/id_card = program.computer.card_slot ? program.computer.card_slot.stored_card : null - var/list/formatted = list() - for(var/job in jobs) - formatted.Add(list(list( - "display_name" = replacetext(job, " ", " "), - "target_rank" = id_card && id_card.assignment ? id_card.assignment : "Unassigned", - "job" = job))) - - return formatted - -/datum/tgui_module_old/cardmod/ui_act(action, list/params, datum/tgui/ui) - if(..()) - return TRUE - - - var/datum/computer_file/program/card_mod/program = host - if(!istype(program)) - return TRUE - var/obj/item/modular_computer/computer = ui_host() - if(!istype(computer)) - return TRUE - - var/obj/item/card/id/user_id_card = usr.GetIdCard() - var/obj/item/card/id/id_card - if(computer.card_slot) - id_card = computer.card_slot.stored_card - - switch(action) - if("mode") - mod_mode = clamp(text2num(params["mode_target"]), 0, 1) - . = TRUE - if("print") - if(computer && computer.nano_printer) //This option should never be called if there is no printer - if(!mod_mode) - if(program.can_run(usr, 1)) - var/contents = {"

Access Report

- Prepared By: [user_id_card.registered_name ? user_id_card.registered_name : "Unknown"]
- For: [id_card.registered_name ? id_card.registered_name : "Unregistered"]
-
- Assignment: [id_card.assignment]
- Account Number: #[id_card.associated_account_number]
- Blood Type: [id_card.blood_type]

- Access:
- "} - - var/known_access_rights = get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM) - for(var/A in id_card.access) - if(A in known_access_rights) - contents += " [get_access_desc(A)]" - - if(!computer.nano_printer.print_text(contents,"access report")) - to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.") - return - else - computer.visible_message("\The [computer] prints out paper.") - else - var/contents = {"

Crew Manifest

-
- [data_core ? data_core.get_manifest(0) : ""] - "} - if(!computer.nano_printer.print_text(contents, "crew manifest ([stationtime2text()])")) - to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.") - return - else - computer.visible_message("\The [computer] prints out paper.") - . = TRUE - if("modify") - if(computer && computer.card_slot) - if(id_card) - data_core.manifest_modify(id_card.registered_name, id_card.assignment, id_card.rank) - computer.proc_eject_id(usr) - . = TRUE - if("terminate") - if(computer && program.can_run(usr, 1)) - id_card.assignment = "Dismissed" - id_card.access = list() - . = TRUE - if("reg") - if(computer && program.can_run(usr, 1)) - var/temp_name = sanitizeName(params["reg"], allow_numbers = TRUE) - if(temp_name) - id_card.registered_name = temp_name - else - computer.visible_message("[computer] buzzes rudely.") - . = TRUE - if("account") - if(computer && program.can_run(usr, 1)) - var/account_num = text2num(params["account"]) - id_card.associated_account_number = account_num - . = TRUE - if("assign") - if(computer && program.can_run(usr, 1) && id_card) - var/t1 = params["assign_target"] - if(t1 == "Custom") - var/temp_t = sanitize(input("Enter a custom job assignment.","Assignment", id_card.assignment), 45) - //let custom jobs function as an impromptu alt title, mainly for sechuds - if(temp_t) - id_card.assignment = temp_t - else - var/list/access = list() - if(is_centcom) - access = get_centcom_access(t1) - else - var/datum/role/job/jobdatum - for(var/jobtype in typesof(/datum/role/job)) - var/datum/role/job/J = new jobtype - if(ckey(J.title) == ckey(t1)) - jobdatum = J - break - if(!jobdatum) - to_chat(usr, "No log exists for this job: [t1]") - return - - access = jobdatum.get_access() - - id_card.access = access - id_card.assignment = t1 - id_card.rank = t1 - - callHook("reassign_employee", list(id_card)) - . = TRUE - if("access") - if(computer && program.can_run(usr, 1)) - var/access_type = text2num(params["access_target"]) - var/access_allowed = text2num(params["allowed"]) - if(access_type in get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM)) - id_card.access -= access_type - if(!access_allowed) - id_card.access += access_type - . = TRUE - - if(id_card) - id_card.name = "[id_card.registered_name]'s ID Card ([id_card.assignment])" diff --git a/code/modules/tgui/modules/rcon.dm b/code/modules/tgui/modules/rcon.dm index 1fb08c42784..5e59aec524f 100644 --- a/code/modules/tgui/modules/rcon.dm +++ b/code/modules/tgui/modules/rcon.dm @@ -1,3 +1,5 @@ +GLOBAL_LIST_EMPTY(tgui_old_rcon_modules) + /datum/tgui_module_old/rcon name = "Power RCON" tgui_id = "RCON" @@ -5,6 +7,15 @@ var/list/known_SMESs = null var/list/known_breakers = null +/datum/tgui_module_old/rcon/New(host) + . = ..() + GLOB.tgui_old_rcon_modules += src + +/datum/tgui_module_old/rcon/Destroy(force, ...) + . = ..() + GLOB.tgui_old_rcon_modules -= src + + /datum/tgui_module_old/rcon/ui_data(mob/user) FindDevices() // Update our devices list var/list/data = ..() diff --git a/config/access levels.txt b/config/access levels.txt new file mode 100644 index 00000000000..b74b6b4b020 --- /dev/null +++ b/config/access levels.txt @@ -0,0 +1,79 @@ +HOW TO CONVERT A MAP TO THE NEW (june 2008) ACCESS LEVEL SYSTEM +1. Open the .dmp file up in Notepad +2. Find all the "access = blahblah" attributes of doors. +3. Delete them. +4. Open the map up in Dream Maker. If you didn't get them all, it'll tell you so. +5. Assign the existing doors new access permissions using the method below. + +HOW TO MAKE A MAP USING THE NEW (june 2008) ACCESS LEVEL SYSTEM +1. Make a map as normal +2. Select a door that you want to not be accessible to everybody +3. Right click on it and edit its attributes +4. Make the "req_access_txt" attribute be a semicolon-separated list of the permissions required to open the doors +5. Repeat for all doors. + +For example, a brig door would have it be "2" while a door that requires you have toxins and teleporter access (for whatever reason) would have it be "9;20" + +Here is a list of the permissions and their numbers (this may be out of date, see code/game/access.dm for an updated version): + +access_security = 1 +access_brig = 2 +access_armory = 3 +access_forensics_lockers= 4 +access_medical = 5 +access_morgue = 6 +access_tox = 7 +access_tox_storage = 8 +access_genetics = 9 +ACCESS_ENGINEERING_MAIN = 10 +access_engine_equip= 11 +access_maint_tunnels = 12 +access_external_airlocks = 13 +access_emergency_storage = 14 +access_change_ids = 15 +access_ai_upload = 16 +access_teleporter = 17 +access_eva = 18 +access_heads = 19 +access_captain = 20 +access_all_personal_lockers = 21 +access_chapel_office = 22 +access_tech_storage = 23 +access_atmospherics = 24 +access_bar = 25 +access_janitor = 26 +access_crematorium = 27 +access_kitchen = 28 +access_robotics = 29 +access_rd = 30 +access_cargo = 31 +access_construction = 32 +access_chemistry = 33 +access_cargo_bot = 34 +access_hydroponics = 35 +access_manufacturing = 36 +access_library = 37 +access_lawyer = 38 +access_virology = 39 +access_cmo = 40 +access_qm = 41 +access_court = 42 +access_clown = 43 +access_mime = 44 +access_surgery = 45 +access_theatre = 46 +access_research = 47 +access_mining = 48 +access_mining_office = 49 //not in use +access_mailsorting = 50 +access_mint = 51 +access_mint_vault = 52 +access_heads_vault = 53 +access_mining_station = 54 +access_xenobiology = 55 +access_ce = 56 +access_hop = 57 +access_hos = 58 +access_RC_announce = 59 //Request console announcements +access_keycard_auth = 60 //Used for events which require at least two people to confirm them +access_tcomsat = 61 // has access to the entire telecomms satellite / machinery diff --git a/tgui/packages/tgui/interfaces/CameraConsole.js b/tgui/packages/tgui/interfaces/CameraConsole.js index c2a4a23ef9b..68e2b0b8bbd 100644 --- a/tgui/packages/tgui/interfaces/CameraConsole.js +++ b/tgui/packages/tgui/interfaces/CameraConsole.js @@ -2,6 +2,7 @@ import { filter, sortBy } from 'common/collections'; import { flow } from 'common/fp'; import { classes } from 'common/react'; import { createSearch } from 'common/string'; +import { Fragment } from 'inferno'; import { useBackend, useLocalState } from '../backend'; import { Button, ByondUi, Flex, Input, Section } from '../components'; import { Window } from '../layouts'; @@ -116,7 +117,7 @@ export const CameraConsoleContent = (props, context) => { scrollable> {cameras.map(camera => ( // We're not using the component here because performance - // would be absolutely abysmal (50+ ms for each re-render). + // would be absolutely abysmal (50+ ms for each re-render)
{ ); }; + +export const CameraConsoleNTOS = (props, context) => { + const { act, data } = useBackend(context); + const { mapRef, activeCamera } = data; + const cameras = selectCameras(data.cameras); + const [ + prevCameraName, + nextCameraName, + ] = prevNextCamera(cameras, activeCamera); + return ( + +
+ + + +
+
+
+ Camera: + {activeCamera + && activeCamera.name + || '—'} +
+
+
+ +
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/CommunicationsConsole.js b/tgui/packages/tgui/interfaces/CommunicationsConsole.js index 2a3bc90151b..e59380daa30 100644 --- a/tgui/packages/tgui/interfaces/CommunicationsConsole.js +++ b/tgui/packages/tgui/interfaces/CommunicationsConsole.js @@ -1,754 +1,347 @@ -import { sortBy } from "common/collections"; -import { capitalize } from "common/string"; -import { useBackend, useLocalState } from "../backend"; -import { Blink, Box, Button, Dimmer, Flex, Icon, Input, Modal, Section, TextArea } from "../components"; -import { Window } from "../layouts"; -import { sanitizeText } from "../sanitize"; - -const STATE_BUYING_SHUTTLE = "buying_shuttle"; -const STATE_CHANGING_STATUS = "changing_status"; -const STATE_MAIN = "main"; -const STATE_MESSAGES = "messages"; - -// Used for whether or not you need to swipe to confirm an alert level change -const SWIPE_NEEDED = "SWIPE_NEEDED"; - -const EMAG_SHUTTLE_NOTICE - = "This shuttle is deemed significantly dangerous to the crew, and is only supplied by the Syndicate."; - -const sortShuttles = sortBy( - shuttle => !shuttle.emagOnly, - shuttle => shuttle.creditCost -); - -const AlertButton = (props, context) => { - const { act, data } = useBackend(context); - const { alertLevelTick, canSetAlertLevel } = data; - const { alertLevel, setShowAlertLevelConfirm } = props; - - const thisIsCurrent = data.alertLevel === alertLevel; - - return ( -