diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index 9a00c826d3..4282731dd8 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -113,6 +113,7 @@
#define MAX_RECORD_LENGTH 24576
#define MAX_LNAME_LEN 64
#define MAX_NAME_LEN 52
+#define MAX_TEXTFILE_LENGTH 128000 // 512GQ file
// Event defines.
#define EVENT_LEVEL_MUNDANE 1
diff --git a/code/_macros.dm b/code/_macros.dm
index 4549e01079..3860f63434 100644
--- a/code/_macros.dm
+++ b/code/_macros.dm
@@ -11,6 +11,7 @@
#define log_world(message) world.log << message
#define to_file(file_entry, source_var) file_entry << source_var
#define from_file(file_entry, target_var) file_entry >> target_var
+#define show_browser(target, browser_content, browser_name) target << browse(browser_content, browser_name)
// From TG, might be useful to have.
// Didn't port SEND_TEXT() since to_chat() appears to serve the same purpose.
diff --git a/code/modules/client/preference_setup/loadout/gear_tweaks.dm b/code/modules/client/preference_setup/loadout/gear_tweaks.dm
index 7ddb6957a8..2b86685f17 100644
--- a/code/modules/client/preference_setup/loadout/gear_tweaks.dm
+++ b/code/modules/client/preference_setup/loadout/gear_tweaks.dm
@@ -289,3 +289,151 @@
if(ValidTeslaLinks[metadata[7]])
var/t = ValidTeslaLinks[metadata[7]]
I.tesla_link = new t(I)
+
+/datum/gear_tweak/laptop
+ var/list/ValidProcessors = list(/obj/item/weapon/computer_hardware/processor_unit/small, /obj/item/weapon/computer_hardware/processor_unit)
+ var/list/ValidBatteries = list(/obj/item/weapon/computer_hardware/battery_module, /obj/item/weapon/computer_hardware/battery_module/advanced, /obj/item/weapon/computer_hardware/battery_module/super)
+ var/list/ValidHardDrives = list(/obj/item/weapon/computer_hardware/hard_drive, /obj/item/weapon/computer_hardware/hard_drive/advanced, /obj/item/weapon/computer_hardware/hard_drive/super)
+ var/list/ValidNetworkCards = list(/obj/item/weapon/computer_hardware/network_card, /obj/item/weapon/computer_hardware/network_card/advanced)
+ var/list/ValidNanoPrinters = list(null, /obj/item/weapon/computer_hardware/nano_printer)
+ var/list/ValidCardSlots = list(null, /obj/item/weapon/computer_hardware/card_slot)
+ var/list/ValidTeslaLinks = list(null, /obj/item/weapon/computer_hardware/tesla_link)
+
+/datum/gear_tweak/laptop/get_contents(var/list/metadata)
+ var/list/names = list()
+ var/obj/O = ValidProcessors[metadata[1]]
+ if(O)
+ names += initial(O.name)
+ O = ValidBatteries[metadata[2]]
+ if(O)
+ names += initial(O.name)
+ O = ValidHardDrives[metadata[3]]
+ if(O)
+ names += initial(O.name)
+ O = ValidNetworkCards[metadata[4]]
+ if(O)
+ names += initial(O.name)
+ O = ValidNanoPrinters[metadata[5]]
+ if(O)
+ names += initial(O.name)
+ O = ValidCardSlots[metadata[6]]
+ if(O)
+ names += initial(O.name)
+ O = ValidTeslaLinks[metadata[7]]
+ if(O)
+ names += initial(O.name)
+ return "[english_list(names, and_text = ", ")]"
+
+/datum/gear_tweak/laptop/get_metadata(var/user, var/metadata)
+ . = list()
+
+ var/list/names = list()
+ var/counter = 1
+ for(var/i in ValidProcessors)
+ if(i)
+ var/obj/O = i
+ names[initial(O.name)] = counter++
+ else
+ names["None"] = counter++
+
+ var/entry = input(user, "Choose a processor.", "Character Preference") in names
+ . += names[entry]
+
+ names = list()
+ counter = 1
+ for(var/i in ValidBatteries)
+ if(i)
+ var/obj/O = i
+ names[initial(O.name)] = counter++
+ else
+ names["None"] = counter++
+
+ entry = input(user, "Choose a battery.", "Character Preference") in names
+ . += names[entry]
+
+ names = list()
+ counter = 1
+ for(var/i in ValidHardDrives)
+ if(i)
+ var/obj/O = i
+ names[initial(O.name)] = counter++
+ else
+ names["None"] = counter++
+
+ entry = input(user, "Choose a hard drive.", "Character Preference") in names
+ . += names[entry]
+
+ names = list()
+ counter = 1
+ for(var/i in ValidNetworkCards)
+ if(i)
+ var/obj/O = i
+ names[initial(O.name)] = counter++
+ else
+ names["None"] = counter++
+
+ entry = input(user, "Choose a network card.", "Character Preference") in names
+ . += names[entry]
+
+ names = list()
+ counter = 1
+ for(var/i in ValidNanoPrinters)
+ if(i)
+ var/obj/O = i
+ names[initial(O.name)] = counter++
+ else
+ names["None"] = counter++
+
+ entry = input(user, "Choose a nanoprinter.", "Character Preference") in names
+ . += names[entry]
+
+ names = list()
+ counter = 1
+ for(var/i in ValidCardSlots)
+ if(i)
+ var/obj/O = i
+ names[initial(O.name)] = counter++
+ else
+ names["None"] = counter++
+
+ entry = input(user, "Choose a card slot.", "Character Preference") in names
+ . += names[entry]
+
+ names = list()
+ counter = 1
+ for(var/i in ValidTeslaLinks)
+ if(i)
+ var/obj/O = i
+ names[initial(O.name)] = counter++
+ else
+ names["None"] = counter++
+
+ entry = input(user, "Choose a tesla link.", "Character Preference") in names
+ . += names[entry]
+
+/datum/gear_tweak/laptop/get_default()
+ return list(1, 1, 1, 1, 1, 1, 1)
+
+/datum/gear_tweak/laptop/tweak_item(var/obj/item/modular_computer/laptop/preset/I, var/list/metadata)
+ if(ValidProcessors[metadata[1]])
+ var/t = ValidProcessors[metadata[1]]
+ I.processor_unit = new t(I)
+ if(ValidBatteries[metadata[2]])
+ var/t = ValidBatteries[metadata[2]]
+ I.battery_module = new t(I)
+ I.battery_module.charge_to_full()
+ if(ValidHardDrives[metadata[3]])
+ var/t = ValidHardDrives[metadata[3]]
+ I.hard_drive = new t(I)
+ if(ValidNetworkCards[metadata[4]])
+ var/t = ValidNetworkCards[metadata[4]]
+ I.network_card = new t(I)
+ if(ValidNanoPrinters[metadata[5]])
+ var/t = ValidNanoPrinters[metadata[5]]
+ I.nano_printer = new t(I)
+ if(ValidCardSlots[metadata[6]])
+ var/t = ValidCardSlots[metadata[6]]
+ I.card_slot = new t(I)
+ if(ValidTeslaLinks[metadata[7]])
+ var/t = ValidTeslaLinks[metadata[7]]
+ I.tesla_link = new t(I)
diff --git a/code/modules/client/preference_setup/loadout/loadout_utility.dm b/code/modules/client/preference_setup/loadout/loadout_utility.dm
index 091d732299..bd2977a94f 100644
--- a/code/modules/client/preference_setup/loadout/loadout_utility.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_utility.dm
@@ -158,23 +158,47 @@
..()
gear_tweaks = list(gear_tweak_free_color_choice)
+/****************
+modular computers
+****************/
+
/datum/gear/utility/cheaptablet
- display_name = "cheap tablet computer"
display_name = "tablet computer: cheap"
+ display_name = "tablet computer, cheap"
path = /obj/item/modular_computer/tablet/preset/custom_loadout/cheap
cost = 3
/datum/gear/utility/normaltablet
- display_name = "tablet computer"
display_name = "tablet computer: advanced"
+ display_name = "tablet computer, advanced"
path = /obj/item/modular_computer/tablet/preset/custom_loadout/advanced
cost = 4
/datum/gear/utility/customtablet
display_name = "tablet computer: custom"
+ display_name = "tablet computer, custom"
path = /obj/item/modular_computer/tablet
cost = 4
/datum/gear/utility/customtablet/New()
..()
- gear_tweaks += new /datum/gear_tweak/tablet()
\ No newline at end of file
+ gear_tweaks += new /datum/gear_tweak/tablet()
+
+/datum/gear/utility/cheaplaptop
+ display_name = "laptop computer, cheap"
+ path = /obj/item/modular_computer/laptop/preset/custom_loadout/cheap
+ cost = 4
+
+/datum/gear/utility/normallaptop
+ display_name = "laptop computer, advanced"
+ path = /obj/item/modular_computer/laptop/preset/custom_loadout/advanced
+ cost = 5
+
+/datum/gear/utility/customlaptop
+ display_name = "laptop computer, custom"
+ path = /obj/item/modular_computer/laptop/preset/
+ cost = 6
+
+/datum/gear/utility/customlaptop/New()
+ ..()
+ gear_tweaks += new /datum/gear_tweak/laptop()
diff --git a/code/modules/modular_computers/computers/modular_computer/core.dm b/code/modules/modular_computers/computers/modular_computer/core.dm
index 5474fb1f40..30d9cf6039 100644
--- a/code/modules/modular_computers/computers/modular_computer/core.dm
+++ b/code/modules/modular_computers/computers/modular_computer/core.dm
@@ -82,6 +82,8 @@
set_light(light_strength)
if(active_program)
overlays.Add(active_program.program_icon_state ? active_program.program_icon_state : icon_state_menu)
+ if(active_program.program_key_state)
+ overlays.Add(active_program.program_key_state)
else
overlays.Add(icon_state_menu)
diff --git a/code/modules/modular_computers/computers/modular_computer/interaction.dm b/code/modules/modular_computers/computers/modular_computer/interaction.dm
index 89c35a56cf..bf70bb7d28 100644
--- a/code/modules/modular_computers/computers/modular_computer/interaction.dm
+++ b/code/modules/modular_computers/computers/modular_computer/interaction.dm
@@ -136,7 +136,7 @@
update_uis()
to_chat(user, "You insert \the [I] into \the [src].")
return
- if(istype(W, /obj/item/weapon/paper))
+ if(istype(W, /obj/item/weapon/paper) || istype(W, /obj/item/weapon/paper_bundle))
if(!nano_printer)
return
nano_printer.attackby(W, user)
diff --git a/code/modules/modular_computers/computers/modular_computer/ui.dm b/code/modules/modular_computers/computers/modular_computer/ui.dm
index cc4d23a4f4..81081c0cb1 100644
--- a/code/modules/modular_computers/computers/modular_computer/ui.dm
+++ b/code/modules/modular_computers/computers/modular_computer/ui.dm
@@ -31,6 +31,7 @@
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
diff --git a/code/modules/modular_computers/computers/subtypes/dev_laptop.dm b/code/modules/modular_computers/computers/subtypes/dev_laptop.dm
index 4aef23213f..eddae93f74 100644
--- a/code/modules/modular_computers/computers/subtypes/dev_laptop.dm
+++ b/code/modules/modular_computers/computers/subtypes/dev_laptop.dm
@@ -34,4 +34,4 @@
icon_state = icon_state_closed
/obj/item/modular_computer/laptop/preset
- anchored = FALSE
\ No newline at end of file
+ anchored = FALSE
diff --git a/code/modules/modular_computers/computers/subtypes/dev_tablet.dm b/code/modules/modular_computers/computers/subtypes/dev_tablet.dm
index 7ebf646e10..62d12ba545 100644
--- a/code/modules/modular_computers/computers/subtypes/dev_tablet.dm
+++ b/code/modules/modular_computers/computers/subtypes/dev_tablet.dm
@@ -8,4 +8,9 @@
hardware_flag = PROGRAM_TABLET
max_hardware_size = 1
w_class = ITEMSIZE_SMALL
- light_strength = 2 // Same as PDAs
\ No newline at end of file
+ light_strength = 2 // Same as PDAs
+
+/obj/item/modular_computer/tablet/lease
+ desc = "A small portable microcomputer. This one has a gold and blue stripe, and a serial number stamped into the case."
+ icon_state = "tabletsol"
+ icon_state_unpowered = "tabletsol"
\ No newline at end of file
diff --git a/code/modules/modular_computers/computers/subtypes/dev_telescreen.dm b/code/modules/modular_computers/computers/subtypes/dev_telescreen.dm
index 95df05320d..1f88ed6cb2 100644
--- a/code/modules/modular_computers/computers/subtypes/dev_telescreen.dm
+++ b/code/modules/modular_computers/computers/subtypes/dev_telescreen.dm
@@ -1,6 +1,6 @@
/obj/item/modular_computer/telescreen
name = "telescreen"
- desc = "A stationary wall-mounted touchscreen"
+ desc = "A wall-mounted touchscreen computer."
icon = 'icons/obj/modular_telescreen.dmi'
icon_state = "telescreen"
icon_state_unpowered = "telescreen"
diff --git a/code/modules/modular_computers/computers/subtypes/preset_console.dm b/code/modules/modular_computers/computers/subtypes/preset_console.dm
index 5b8735d79e..6bdb081202 100644
--- a/code/modules/modular_computers/computers/subtypes/preset_console.dm
+++ b/code/modules/modular_computers/computers/subtypes/preset_console.dm
@@ -20,6 +20,7 @@
..()
hard_drive.store_file(new/datum/computer_file/program/suit_sensors())
hard_drive.store_file(new/datum/computer_file/program/camera_monitor())
+ hard_drive.store_file(new/datum/computer_file/program/wordprocessor())
set_autorun("sensormonitor")
// Research
@@ -35,6 +36,7 @@
hard_drive.store_file(new/datum/computer_file/program/camera_monitor())
//hard_drive.store_file(new/datum/computer_file/program/aidiag())
hard_drive.store_file(new/datum/computer_file/program/email_client())
+ hard_drive.store_file(new/datum/computer_file/program/wordprocessor())
// Administrator
/obj/item/modular_computer/console/preset/sysadmin/install_default_hardware()
@@ -50,6 +52,7 @@
//hard_drive.store_file(new/datum/computer_file/program/aidiag())
hard_drive.store_file(new/datum/computer_file/program/email_client())
hard_drive.store_file(new/datum/computer_file/program/email_administration())
+ hard_drive.store_file(new/datum/computer_file/program/wordprocessor())
// Command
/obj/item/modular_computer/console/preset/command/install_default_hardware()
@@ -70,6 +73,7 @@
..()
hard_drive.store_file(new/datum/computer_file/program/camera_monitor())
hard_drive.store_file(new/datum/computer_file/program/digitalwarrant())
+ hard_drive.store_file(new/datum/computer_file/program/wordprocessor())
// Civilian
/obj/item/modular_computer/console/preset/civilian/install_default_programs()
@@ -79,6 +83,7 @@
hard_drive.store_file(new/datum/computer_file/program/newsbrowser())
hard_drive.store_file(new/datum/computer_file/program/camera_monitor())
hard_drive.store_file(new/datum/computer_file/program/email_client())
+ hard_drive.store_file(new/datum/computer_file/program/wordprocessor())
// ERT
/obj/item/modular_computer/console/preset/ert/install_default_hardware()
@@ -114,4 +119,14 @@
// Merchant
/obj/item/modular_computer/console/preset/merchant/install_default_programs()
..()
- //hard_drive.store_file(new/datum/computer_file/program/merchant())
\ No newline at end of file
+ //hard_drive.store_file(new/datum/computer_file/program/merchant())
+ hard_drive.store_file(new/datum/computer_file/program/wordprocessor())
+
+// Library
+/obj/item/modular_computer/console/preset/library/install_default_programs()
+ ..()
+ hard_drive.store_file(new/datum/computer_file/program/nttransfer())
+ hard_drive.store_file(new/datum/computer_file/program/newsbrowser())
+ hard_drive.store_file(new/datum/computer_file/program/email_client())
+ hard_drive.store_file(new/datum/computer_file/program/wordprocessor())
+ hard_drive.store_file(new/datum/computer_file/program/library())
diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm
index e699b009d8..7124bdcd03 100644
--- a/code/modules/modular_computers/file_system/program.dm
+++ b/code/modules/modular_computers/file_system/program.dm
@@ -12,6 +12,8 @@
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.
@@ -125,6 +127,7 @@
if(can_run(user, 1) || !requires_access_to_run)
if(nanomodule_path)
NM = new nanomodule_path(src, new /datum/topic_manager/program(src), src)
+ NM.using_access = user.GetAccess()
if(requires_ntnet && network_destination)
generate_network_log("Connection opened to [network_destination].")
program_state = PROGRAM_STATE_ACTIVE
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 44e5fd8cfe..0e0a1381bd 100644
--- a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm
+++ b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm
@@ -2,6 +2,8 @@
filename = "ntn_dos"
filedesc = "DoS Traffic Generator"
program_icon_state = "hostile"
+ program_key_state = "security_key"
+ 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
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 4d224a5bed..27e5a26c3f 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
@@ -3,6 +3,8 @@
filedesc = "Camera Decryption Tool"
nanomodule_path = /datum/nano_module/camera_monitor/hacked
program_icon_state = "hostile"
+ program_key_state = "security_key"
+ program_menu_icon = "zoomin"
extended_desc = "This very advanced piece of software uses adaptive programming and large database of cipherkeys to bypass most encryptions used on camera networks. Be warned that system administrator may notice this."
size = 73 // Very large, a price for bypassing ID checks completely.
available_on_ntnet = 0
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 1a5659d743..17199c3b18 100644
--- a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm
+++ b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm
@@ -2,6 +2,8 @@
filename = "revelation"
filedesc = "Revelation"
program_icon_state = "hostile"
+ program_key_state = "security_key"
+ 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
@@ -48,6 +50,10 @@
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
/datum/computer_file/program/revelation/clone()
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 8aaab7ea0d..2b5c3a6047 100644
--- a/code/modules/modular_computers/file_system/programs/command/card.dm
+++ b/code/modules/modular_computers/file_system/programs/command/card.dm
@@ -3,7 +3,9 @@
filedesc = "ID card modification program"
nanomodule_path = /datum/nano_module/program/card_mod
program_icon_state = "id"
- extended_desc = "Program for programming employee ID cards to access parts of the station."
+ program_key_state = "id_key"
+ program_menu_icon = "key"
+ extended_desc = "Program for programming crew ID cards."
required_access = access_hop
requires_ntnet = 0
size = 8
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 2089c987f3..8de74ed700 100644
--- a/code/modules/modular_computers/file_system/programs/command/comm.dm
+++ b/code/modules/modular_computers/file_system/programs/command/comm.dm
@@ -5,15 +5,17 @@
#define STATE_ALERT_LEVEL 5
/datum/computer_file/program/comm
filename = "comm"
- filedesc = "Command and communications program."
+ filedesc = "Command and Communications Program"
program_icon_state = "comm"
+ program_key_state = "med_key"
+ program_menu_icon = "flag"
nanomodule_path = /datum/nano_module/program/comm
- extended_desc = "Used to command and control the station. Can relay long-range communications. This program can not be run on tablet computers."
+ extended_desc = "Used to command and control. Can relay long-range communications. This program can not be run on tablet computers."
required_access = access_heads
requires_ntnet = 1
size = 12
usage_flags = PROGRAM_CONSOLE | PROGRAM_LAPTOP
- network_destination = "station long-range communication array"
+ network_destination = "long-range communication array"
var/datum/comm_message_listener/message_core = new
/datum/computer_file/program/comm/clone()
@@ -23,7 +25,7 @@
return temp
/datum/nano_module/program/comm
- name = "Command and communications program"
+ name = "Command and Communications Program"
//available_to_ai = TRUE
var/current_status = STATE_DEFAULT
var/msg_line1 = ""
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 b4d5635ffd..cfd9353eee 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
@@ -4,6 +4,8 @@
nanomodule_path = /datum/nano_module/alarm_monitor/engineering
ui_header = "alarm_green.gif"
program_icon_state = "alert-green"
+ program_key_state = "atmos_key"
+ program_menu_icon = "alert"
extended_desc = "This program provides visual interface for the alarm system."
requires_ntnet = 1
network_destination = "alarm monitoring network"
@@ -43,7 +45,7 @@
/datum/nano_module/alarm_monitor/engineering/New()
..()
- alarm_handlers = list(atmosphere_alarm, fire_alarm, power_alarm)
+ alarm_handlers = list(atmosphere_alarm, camera_alarm, fire_alarm, power_alarm)
/datum/nano_module/alarm_monitor/security/New()
..()
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 fa3d43176b..3f88029713 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
@@ -3,6 +3,8 @@
filedesc = "Atmosphere Control"
nanomodule_path = /datum/nano_module/atmos_control
program_icon_state = "atmos_control"
+ program_key_state = "atmos_key"
+ 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_atmospherics
requires_ntnet = 1
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 475a03cfdb..32117e845c 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
@@ -3,6 +3,8 @@
filedesc = "Power Monitoring"
nanomodule_path = /datum/nano_module/power_monitor/
program_icon_state = "power_monitor"
+ program_key_state = "power_key"
+ program_menu_icon = "battery-3"
extended_desc = "This program connects to sensors to provide information about electrical systems"
ui_header = "power_norm.gif"
required_access = access_engine
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 0e22a3ba1e..d5ee88b670 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
@@ -3,6 +3,8 @@
filedesc = "RCON Remote Control"
nanomodule_path = /datum/nano_module/rcon
program_icon_state = "generic"
+ program_key_state = "rd_key"
+ program_menu_icon = "power"
extended_desc = "This program allows remote control of power distribution systems. This program can not be run on tablet computers."
required_access = access_engine
requires_ntnet = 1
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 bd60780c78..af0489a953 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
@@ -3,6 +3,8 @@
filedesc = "Supermatter Monitoring"
nanomodule_path = /datum/nano_module/supermatter_monitor/
program_icon_state = "smmon_0"
+ program_key_state = "tech_key"
+ program_menu_icon = "notice"
extended_desc = "This program connects to specially calibrated supermatter sensors to provide information on the status of supermatter-based engines."
ui_header = "smmon_0.gif"
required_access = access_engine
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 7dde9c0d3f..47ac48eb40 100644
--- a/code/modules/modular_computers/file_system/programs/generic/camera.dm
+++ b/code/modules/modular_computers/file_system/programs/generic/camera.dm
@@ -29,6 +29,8 @@
filedesc = "Camera Monitoring"
nanomodule_path = /datum/nano_module/camera_monitor
program_icon_state = "cameras"
+ program_key_state = "generic_key"
+ program_menu_icon = "search"
extended_desc = "This program allows remote access to the camera system. Some camera networks may have additional access requirements."
size = 12
available_on_ntnet = 1
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 5867efbdcb..c3ce1e358a 100644
--- a/code/modules/modular_computers/file_system/programs/generic/configurator.dm
+++ b/code/modules/modular_computers/file_system/programs/generic/configurator.dm
@@ -7,6 +7,8 @@
filedesc = "Computer Configuration Tool"
extended_desc = "This program allows configuration of computer's hardware"
program_icon_state = "generic"
+ program_key_state = "generic_key"
+ program_menu_icon = "gear"
unsendable = 1
undeletable = 1
size = 4
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 429a68c3a4..3e2f979bb5 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
@@ -3,6 +3,8 @@
filedesc = "Email Client"
extended_desc = "This program may be used to log in into your email account."
program_icon_state = "generic"
+ program_key_state = "generic_key"
+ program_menu_icon = "mail-closed"
size = 7
requires_ntnet = 1
available_on_ntnet = 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 4311c2dedd..42dfdd622d 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
@@ -1,10 +1,10 @@
-#define MAX_TEXTFILE_LENGTH 128000 // 512GQ file
-
/datum/computer_file/program/filemanager
filename = "filemanager"
filedesc = "NTOS File Manager"
extended_desc = "This program allows management of files."
program_icon_state = "generic"
+ program_key_state = "generic_key"
+ program_menu_icon = "folder-collapsed"
size = 8
requires_ntnet = 0
available_on_ntnet = 0
@@ -89,9 +89,9 @@
return 1
var/oldtext = html_decode(F.stored_data)
- oldtext = replacetext(oldtext, "\[editorbr\]", "\n")
+ 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", "\[editorbr\]"), MAX_TEXTFILE_LENGTH)
+ 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
@@ -204,5 +204,4 @@
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()
-#undef MAX_TEXTFILE_LENGTH
\ No newline at end of file
+ ui.open()
\ No newline at end of file
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 e947bea365..b4c0688c29 100644
--- a/code/modules/modular_computers/file_system/programs/generic/game.dm
+++ b/code/modules/modular_computers/file_system/programs/generic/game.dm
@@ -6,6 +6,7 @@
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...
diff --git a/code/modules/modular_computers/file_system/programs/generic/library.dm b/code/modules/modular_computers/file_system/programs/generic/library.dm
new file mode 100644
index 0000000000..b686cda14e
--- /dev/null
+++ b/code/modules/modular_computers/file_system/programs/generic/library.dm
@@ -0,0 +1,191 @@
+/*
+In reply to this set of comments on lib_machines.dm:
+// TODO: Make this an actual /obj/machinery/computer that can be crafted from circuit boards and such
+// It is August 22nd, 2012... This TODO has already been here for months.. I wonder how long it'll last before someone does something about it.
+
+The answer was five and a half years -ZeroBits
+*/
+
+/datum/computer_file/program/library
+ filename = "library"
+ filedesc = "Library"
+ extended_desc = "This program can be used to view e-books from an external archive."
+ program_icon_state = "word"
+ program_key_state = "atmos_key"
+ program_menu_icon = "note"
+ size = 6
+ requires_ntnet = 1
+ available_on_ntnet = 1
+
+ nanomodule_path = /datum/nano_module/library
+
+/datum/nano_module/library
+ name = "Library"
+ var/error_message = ""
+ var/current_book
+ var/obj/machinery/libraryscanner/scanner
+ var/sort_by = "id"
+
+/datum/nano_module/library/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(error_message)
+ data["error"] = error_message
+ else if(current_book)
+ data["current_book"] = current_book
+ else
+ var/list/all_entries[0]
+ establish_old_db_connection()
+ if(!dbcon_old.IsConnected())
+ error_message = "Unable to contact External Archive. Please contact your system administrator for assistance."
+ else
+ var/DBQuery/query = dbcon_old.NewQuery("SELECT id, author, title, category FROM library ORDER BY "+sanitizeSQL(sort_by))
+ query.Execute()
+
+ while(query.NextRow())
+ all_entries.Add(list(list(
+ "id" = query.item[1],
+ "author" = query.item[2],
+ "title" = query.item[3],
+ "category" = query.item[4]
+ )))
+ data["book_list"] = all_entries
+ data["scanner"] = istype(scanner)
+
+ ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
+ if (!ui)
+ ui = new(user, src, ui_key, "library.tmpl", "Library Program", 575, 700, state = state)
+ ui.auto_update_layout = 1
+ ui.set_initial_data(data)
+ ui.open()
+
+/datum/nano_module/library/Topic(href, href_list)
+ if(..())
+ return 1
+ if(href_list["viewbook"])
+ view_book(href_list["viewbook"])
+ return 1
+ if(href_list["viewid"])
+ view_book(sanitizeSQL(input("Enter USBN:") as num|null))
+ return 1
+ if(href_list["closebook"])
+ current_book = null
+ return 1
+ if(href_list["connectscanner"])
+ if(!nano_host())
+ return 1
+ for(var/d in GLOB.cardinal)
+ var/obj/machinery/libraryscanner/scn = locate(/obj/machinery/libraryscanner, get_step(nano_host(), d))
+ if(scn && scn.anchored)
+ scanner = scn
+ return 1
+ if(href_list["uploadbook"])
+ if(!scanner || !scanner.anchored)
+ scanner = null
+ error_message = "Hardware Error: No scanner detected. Unable to access cache."
+ return 1
+ if(!scanner.cache)
+ error_message = "Interface Error: Scanner cache does not contain any data. Please scan a book."
+ return 1
+
+ var/obj/item/weapon/book/B = scanner.cache
+
+ if(B.unique)
+ error_message = "Interface Error: Cached book is copy-protected."
+ return 1
+
+ //B.SetName(input(usr, "Enter Book Title", "Title", B.name) as text|null)
+ B.author = input(usr, "Enter Author Name", "Author", B.author) as text|null
+
+ if(!B.author)
+ B.author = "Anonymous"
+ else if(lowertext(B.author) == "edgar allen poe" || lowertext(B.author) == "edgar allan poe")
+ error_message = "User Error: Upload something original."
+ return 1
+
+ if(!B.title)
+ B.title = "Untitled"
+
+ var/choice = input(usr, "Upload [B.name] by [B.author] to the External Archive?") in list("Yes", "No")
+ if(choice == "Yes")
+ establish_old_db_connection()
+ if(!dbcon_old.IsConnected())
+ error_message = "Network Error: Connection to the Archive has been severed."
+ return 1
+
+ var/upload_category = input(usr, "Upload to which category?") in list("Fiction", "Non-Fiction", "Reference", "Religion")
+
+ var/sqltitle = sanitizeSQL(B.name)
+ var/sqlauthor = sanitizeSQL(B.author)
+ var/sqlcontent = sanitizeSQL(B.dat)
+ var/sqlcategory = sanitizeSQL(upload_category)
+ var/DBQuery/query = dbcon_old.NewQuery("INSERT INTO library (author, title, content, category) VALUES ('[sqlauthor]', '[sqltitle]', '[sqlcontent]', '[sqlcategory]')")
+ if(!query.Execute())
+ to_chat(usr, query.ErrorMsg())
+ error_message = "Network Error: Unable to upload to the Archive. Contact your system Administrator for assistance."
+ return 1
+ else
+ log_and_message_admins("has uploaded the book titled [B.name], [length(B.dat)] signs")
+ log_game("[usr.name]/[usr.key] has uploaded the book titled [B.name], [length(B.dat)] signs")
+ alert("Upload Complete.")
+ return 1
+
+ return 0
+
+ if(href_list["printbook"])
+ if(!current_book)
+ error_message = "Software Error: Unable to print; book not found."
+ return 1
+
+ //PRINT TO BINDER
+ if(!nano_host())
+ return 1
+ for(var/d in GLOB.cardinal)
+ var/obj/machinery/bookbinder/bndr = locate(/obj/machinery/bookbinder, get_step(nano_host(), d))
+ if(bndr && bndr.anchored)
+ var/obj/item/weapon/book/B = new(bndr.loc)
+ //B.SetName(current_book["title"])
+ B.title = current_book["title"]
+ B.author = current_book["author"]
+ B.dat = current_book["content"]
+ B.icon_state = "book[rand(1,7)]"
+ B.desc = current_book["author"]+", "+current_book["title"]+", "+"USBN "+current_book["id"]
+ bndr.visible_message("\The [bndr] whirs as it prints and binds a new book.")
+ return 1
+
+ //Regular printing
+ print_text("Author: [current_book["author"]]
USBN: [current_book["id"]]