TGUI NTOS - Total Conversion

This commit is contained in:
ShadowLarkens
2020-09-05 16:09:15 -07:00
parent d8c7593395
commit dd4f9c9967
166 changed files with 6765 additions and 4894 deletions

View File

@@ -181,5 +181,8 @@ var/global/datum/ntnet/ntnet_global = new()
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

View File

@@ -119,7 +119,7 @@
active_program = null
var/mob/user = usr
if(user && istype(user))
ui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
tgui_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)
@@ -154,7 +154,7 @@
run_program(autorun.stored_data)
if(user)
ui_interact(user)
tgui_interact(user)
/obj/item/modular_computer/proc/minimize_program(mob/user)
if(!active_program || !processor_unit)
@@ -162,12 +162,11 @@
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))
ui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
tgui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
/obj/item/modular_computer/proc/run_program(prog)
@@ -207,12 +206,12 @@
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 = 0

View File

@@ -99,7 +99,7 @@
/obj/item/modular_computer/attack_ghost(var/mob/observer/ghost/user)
if(enabled)
ui_interact(user)
tgui_interact(user)
else if(check_rights(R_ADMIN|R_EVENT, 0, user))
var/response = alert(user, "This computer is turned off. Would you like to turn it on?", "Admin Override", "Yes", "No")
if(response == "Yes")
@@ -116,7 +116,7 @@
// On-click handling. Turns on the computer if it's off and opens the GUI.
/obj/item/modular_computer/attack_self(var/mob/user)
if(enabled && screen_on)
ui_interact(user)
tgui_interact(user)
else if(!enabled && screen_on)
turn_on(user)

View File

@@ -1,5 +1,10 @@
// Operates NanoUI
/obj/item/modular_computer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/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/tgui_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.ui_interact(user)
active_program.tgui_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,100 @@
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")
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["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 = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "NtosMain")
ui.set_autoupdate(TRUE)
ui.open()
ui.set_auto_update(1)
/obj/item/modular_computer/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/list/data = get_header_data()
data["device_theme"] = device_theme
data["login"] = list()
var/obj/item/weapon/computer_hardware/card_slot/cardholder = card_slot
if(cardholder)
var/obj/item/weapon/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["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/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return 1
if( href_list["PC_exit"] )
kill_program()
return 1
if( href_list["PC_enable_component"] )
var/obj/item/weapon/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/weapon/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
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( 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)
if(!istype(P) || P.program_state == PROGRAM_STATE_KILLED)
return
if(!istype(P) || P.program_state == PROGRAM_STATE_KILLED)
P.kill_program(1)
to_chat(user, "<span class='notice'>Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.</span>")
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, "<span class='notice'>Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.</span>")
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()
@@ -152,4 +177,4 @@
data["PC_stationtime"] = stationtime2text()
data["PC_hasheader"] = 1
data["PC_showexitprogram"] = active_program ? 1 : 0 // Hides "Exit Program" button on mainscreen
return data
return data

View File

@@ -6,6 +6,7 @@
var/enabled = 0 // Whether the computer is turned on.
var/screen_on = 1 // Whether the computer is active/opened/it's screen is on.
var/device_theme = "ntos" // Sets the theme for the main menu, hardware config, and file browser apps. Overridden by certain non-NT devices.
var/datum/computer_file/program/active_program = null // A currently active program running on the computer.
var/hardware_flag = 0 // A flag that describes this device type
var/last_power_usage = 0 // Last tick power usage of this computer

View File

@@ -17,7 +17,7 @@
// 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'

View File

@@ -5,9 +5,6 @@
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.
// NanoModule
var/datum/nano_module/NM = null // If the program uses NanoModule, put it here and it will be automagically opened. Otherwise implement ui_interact.
var/nanomodule_path = null // Path to nanomodule, make sure to set this if implementing new program.
// TGUIModule
var/datum/tgui_module/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.
@@ -29,6 +26,8 @@
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
/datum/computer_file/program/New(var/obj/item/modular_computer/comp = null)
..()
@@ -39,16 +38,12 @@
computer = null
. = ..()
/datum/computer_file/program/nano_host()
return computer.nano_host()
/datum/computer_file/program/tgui_host()
return computer.tgui_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
@@ -134,13 +129,9 @@
/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.tgui_interact(user)
if(requires_ntnet && network_destination)
generate_network_log("Connection opened to [network_destination].")
program_state = PROGRAM_STATE_ACTIVE
@@ -152,26 +143,28 @@
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
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 1 continue with UI initialisation.
// It returns 0 if it can't run or if NanoModule was used instead. I suggest using NanoModules where applicable.
/datum/computer_file/program/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
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/tgui_interact(mob/user, datum/tgui/ui)
if(program_state != PROGRAM_STATE_ACTIVE)
if(ui)
ui.close()
return computer.ui_interact(user)
if(istype(NM))
NM.ui_interact(user, ui_key, null, force_open)
return 0
return computer.tgui_interact(user)
if(istype(TM))
TM.tgui_interact(user)
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:
@@ -185,10 +178,43 @@
if(computer)
return computer.Topic(href, href_list)
// 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/tgui_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.tgui_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(NM)
return NM.check_eye(user)
if(TM)
return TM.check_eye(user)
else
@@ -200,34 +226,14 @@
/obj/item/modular_computer/update_layout()
return TRUE
/datum/nano_module/program
//available_to_ai = FALSE
var/datum/computer_file/program/program = null // Program-Based computer program that runs this nano module. Defaults to null.
/datum/nano_module/program/New(var/host, var/topic_manager, var/program)
..()
src.program = program
/datum/topic_manager/program
var/datum/program
/datum/topic_manager/program/New(var/datum/program)
..()
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)
/datum/computer_file/program/apply_visual(mob/M)
if(NM)
return NM.apply_visual(M)
if(TM)
return TM.apply_visual(M)
/datum/computer_file/program/remove_visual(mob/M)
if(NM)
return NM.remove_visual(M)
if(TM)
return TM.remove_visual(M)
/datum/computer_file/program/proc/relaymove(var/mob/M, direction)
if(NM)
return NM.relaymove(M, direction)
if(TM)
return TM.relaymove(M, direction)

View File

@@ -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_change_ids, 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.desc]"
target_access = null
/datum/computer_file/program/access_decrypter/Topic(href, href_list)
/datum/computer_file/program/access_decrypter/tgui_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/weapon/computer_hardware/processor_unit/CPU = computer.processor_unit
var/obj/item/weapon/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/weapon/computer_hardware/processor_unit/CPU = computer.processor_unit
var/obj/item/weapon/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_change_ids, access_network) // access codes that are not hackable due to balance reasons
/datum/nano_module/program/access_decrypter/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/tgui_data(mob/user, datum/tgui/ui, datum/tgui_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/weapon/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/weapon/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), " ", "&nbsp"),
"desc" = replacetext(get_access_desc(access), " ", "&nbsp;"),
"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

View File

@@ -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/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/tgui_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/tgui_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/weapon/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

View File

@@ -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/tgui_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/tgui_data(mob/user)
var/list/data = get_header_data()
/datum/nano_module/program/revelation/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

View File

@@ -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
tguimodule_path = /datum/tgui_module/cardmod
program_icon_state = "id"
program_key_state = "id_key"
program_menu_icon = "key"
@@ -9,220 +9,3 @@
required_access = access_change_ids
requires_ntnet = 0
size = 8
/datum/nano_module/program/card_mod
name = "ID card modification program"
var/mod_mode = 1
var/is_centcom = 0
var/show_assignments = 0
/datum/nano_module/program/card_mod/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["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
if(program && program.computer && program.computer.card_slot)
var/obj/item/weapon/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 : "-----"
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[++departments.len] = list("department_name" = dept.name, "jobs" = format_jobs(SSjob.get_job_titles_in_department(dept.name)) )
data["departments"] = departments
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/weapon/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), " ", "&nbsp"),
"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), " ", "&nbsp"),
"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/weapon/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, " ", "&nbsp"),
"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/weapon/card/id/user_id_card = user.GetIdCard()
var/obj/item/weapon/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 = {"<h4>Access Report</h4>
<u>Prepared By:</u> [user_id_card.registered_name ? user_id_card.registered_name : "Unknown"]<br>
<u>For:</u> [id_card.registered_name ? id_card.registered_name : "Unregistered"]<br>
<hr>
<u>Assignment:</u> [id_card.assignment]<br>
<u>Account Number:</u> #[id_card.associated_account_number]<br>
<u>Blood Type:</u> [id_card.blood_type]<br><br>
<u>Access:</u><br>
"}
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, "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>")
return
else
computer.visible_message("<span class='notice'>\The [computer] prints out paper.</span>")
else
var/contents = {"<h4>Crew Manifest</h4>
<br>
[data_core ? data_core.get_manifest(0) : ""]
"}
if(!computer.nano_printer.print_text(contents,text("crew manifest ([])", stationtime2text())))
to_chat(usr, "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>")
return
else
computer.visible_message("<span class='notice'>\The [computer] prints out paper.</span>")
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" //VOREStation Edit: setting adjustment
id_card.access = list()
callHook("terminate_employee", list(id_card))
if("edit")
if(computer && can_run(user, 1))
if(href_list["name"])
var/temp_name = sanitizeName(input("Enter name.", "Name", id_card.registered_name),allow_numbers=TRUE)
if(temp_name)
id_card.registered_name = temp_name
else
computer.visible_message("<span class='notice'>[computer] buzzes rudely.</span>")
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/job/jobdatum
for(var/jobtype in typesof(/datum/job))
var/datum/job/J = new jobtype
if(ckey(J.title) == ckey(t1))
jobdatum = J
break
if(!jobdatum)
to_chat(usr, "<span class='warning'>No log exists for this job: [t1]</span>")
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 = text("[id_card.registered_name]'s ID Card ([id_card.assignment])")
SSnanoui.update_uis(NM)
return 1

View File

@@ -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/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_heads
requires_ntnet = 1
@@ -24,269 +24,6 @@
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/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/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"] = security_level
data["current_security_level_title"] = num2seclevel(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(emergency_shuttle.location())
data["have_shuttle"] = 1
if(emergency_shuttle.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_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/weapon/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|message
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, "<span class='warning'>Arrays recycling. Please stand by.</span>")
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
Syndicate_announce(input, usr)
to_chat(usr, "<span class='notice'>Message transmitted.</span>")
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, "<span class='warning'>Arrays recycling. Please stand by.</span>")
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, "<span class='warning'>No Emergency Bluespace Relay detected. Unable to transmit message.</span>")
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.", "Central Command Quantum Messaging") as null|message)
if(!input || !can_still_topic())
return 1
CentCom_announce(input, usr)
to_chat(usr, "<span class='notice'>Message transmitted.</span>")
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 = 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(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(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, "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>")
else
program.computer.visible_message("<span class='notice'>\The [program.computer] prints out paper.</span>")
/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 = TRANSMISSION_RADIO
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
*/
@@ -304,19 +41,9 @@ proc/post_comm_message(var/message_title, var/message_text)
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 machines)
if (!(comm.stat & (BROKEN | NOPOWER)) && comm.prints_intercept)
var/obj/item/weapon/paper/intercept = new /obj/item/weapon/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

View File

@@ -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/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/weapon/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/computer_configurator

View File

@@ -11,15 +11,15 @@
var/stored_login = ""
var/stored_password = ""
nanomodule_path = /datum/nano_module/email_client
tguimodule_path = /datum/tgui_module/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/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/email_client/TME = TM
TME.stored_login = stored_login
TME.stored_password = stored_password
TME.log_in()
TME.error = ""
TME.check_for_new_messages(1)
/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("<span class='notice'>[computer] beeps softly, indicating a new email has been received.</span>")
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/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)
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/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

View File

@@ -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/tgui_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/weapon/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/weapon/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/weapon/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/weapon/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/weapon/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/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
var/obj/item/weapon/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:<br><br>[html_decode(F.stored_data)]<br><br>"
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/weapon/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/tgui_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/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
var/obj/item/weapon/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:<br><br>[html_decode(F.stored_data)]<br><br>"
HDD.store_file(backup)
if(href_list["PRG_printfile"])
. = 1
if(!open_file)
return 1
var/obj/item/weapon/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/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
var/obj/item/weapon/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/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
var/obj/item/weapon/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."
data["filedata"] = null
data["filename"] = null
data["files"] = list()
data["usbconnected"] = FALSE
data["usbfiles"] = list()
/datum/nano_module/program/computer_filemanager
name = "NTOS File Manager"
/datum/nano_module/program/computer_filemanager/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/weapon/computer_hardware/hard_drive/HDD
var/obj/item/weapon/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

View File

@@ -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 = 10)
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 = 10)
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()
// 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/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 = 10)
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 = 10)
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 = 10)
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/tgui_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/tgui_act(action, list/params)
if(..()) // Always call parent in tgui_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/weapon/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 = 10)
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 = 10)
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 = 10)
player_mp += rechargeamt
sleep(10)
game_check()
enemy_check()
return TRUE
if("Dispense_Tickets")
if(!printer)
to_chat(usr, "<span class='notice'>Hardware error: A printer is required to redeem tickets.</span>")
return
if(printer.stored_paper <= 0)
to_chat(usr, "<span class='notice'>Hardware error: Printer is out of paper.</span>")
return
else
computer.visible_message("<span class='notice'>\The [computer] prints out paper.</span>")
if(ticket_count >= 1)
new /obj/item/stack/arcadeticket((get_turf(computer)), 1)
to_chat(usr, "<span class='notice'>[src] dispenses a ticket!</span>")
ticket_count -= 1
printer.stored_paper -= 1
else
to_chat(usr, "<span class='notice'>You don't have any stored tickets!</span>")
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()

View File

@@ -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/tgui_data(mob/user, datum/tgui/ui, datum/tgui_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/weapon/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/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/tgui_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/weapon/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()

View File

@@ -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/tgui_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/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/tgui_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!"

View File

@@ -11,222 +11,220 @@
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)
/datum/computer_file/program/chatclient/New()
username = "DefaultUser[rand(100, 999)]"
/datum/computer_file/program/chatclient/Topic(href, href_list)
/datum/computer_file/program/chatclient/tgui_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_network))
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("<span class='warning'>\The [computer] shows an \"I/O Error - Hard drive connection error\" warning.</span>")
else // In 99.9% cases this will mean our HDD is full
computer.visible_message("<span class='warning'>\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.</span>")
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.
CRASH("Var computer is null!")
return 1
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/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/tgui_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
/datum/computer_file/program/chatclient/tgui_data(mob/user)
if(!ntnet_global || !ntnet_global.chat_channels)
return list()
var/datum/computer_file/program/chatclient/C = program
if(!istype(C))
return
var/list/data = get_header_data()
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/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

View File

@@ -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.
@@ -75,111 +75,101 @@ var/global/nttransfer_uid = 0
remote = null
download_completion = 0
/datum/computer_file/program/nttransfer/tgui_data(mob/user, datum/tgui/ui, datum/tgui_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/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
var/list/data = program.get_header_data()
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["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]"
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]"
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/tgui_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

View File

@@ -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,255 +12,3 @@
size = 12
available_on_ntnet = 1
//requires_ntnet = 1
/datum/nano_module/uav
name = "UAV Control program"
var/obj/item/device/uav/current_uav = null //The UAV we're watching
var/signal_strength = 0 //Our last signal strength report (cached for a few seconds)
var/signal_test_counter = 0 //How long until next signal strength check
var/list/viewers //Who's viewing a UAV through us
var/adhoc_range = 30 //How far we can operate on a UAV without NTnet
/datum/nano_module/uav/Destroy()
if(LAZYLEN(viewers))
for(var/weakref/W in viewers)
var/M = W.resolve()
if(M)
unlook(M)
. = ..()
/datum/nano_module/uav/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = default_state)
var/list/data = host.initial_data()
if(current_uav)
if(QDELETED(current_uav))
set_current(null)
else if(signal_test_counter-- <= 0)
signal_strength = get_signal_to(current_uav)
if(!signal_strength)
set_current(null)
else // Don't reset counter until we find a UAV that's actually in range we can stay connected to
signal_test_counter = 20
data["current_uav"] = null
if(current_uav)
data["current_uav"] = list("status" = current_uav.get_status_string(), "power" = current_uav.state == 1 ? 1 : null)
data["signal_strength"] = signal_strength ? signal_strength >= 2 ? "High" : "Low" : "None"
data["in_use"] = LAZYLEN(viewers)
var/list/paired_map = list()
var/obj/item/modular_computer/mc_host = nano_host()
if(istype(mc_host))
for(var/puav in mc_host.paired_uavs)
var/weakref/wr = puav
var/obj/item/device/uav/U = wr.resolve()
paired_map[++paired_map.len] = list("name" = "[U ? U.nickname : "!!Missing!!"]", "uavref" = "\ref[U]")
data["paired_uavs"] = paired_map
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "mod_uav.tmpl", "UAV Control", 600, 500, state = state)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
/datum/nano_module/uav/Topic(var/href, var/href_list = list(), var/datum/topic_state/state)
if((. = ..()))
return
state = state || DefaultTopicState() || global.default_state
if(CanUseTopic(usr, state, href_list) == STATUS_INTERACTIVE)
CouldUseTopic(usr)
return OnTopic(usr, href_list, state)
CouldNotUseTopic(usr)
return TRUE
/datum/nano_module/uav/proc/OnTopic(var/mob/user, var/list/href_list)
if(href_list["switch_uav"])
var/obj/item/device/uav/U = locate(href_list["switch_uav"]) //This is a \ref to the UAV itself
if(!istype(U))
to_chat(usr,"<span class='warning'>Something is blocking the connection to that UAV. In-person investigation is required.</span>")
return TOPIC_NOACTION
if(!get_signal_to(U))
to_chat(usr,"<span class='warning'>The screen freezes for a moment, before returning to the UAV selection menu. It's not able to connect to that UAV.</span>")
return TOPIC_NOACTION
set_current(U)
return TOPIC_REFRESH
if(href_list["del_uav"])
var/refstring = href_list["del_uav"] //This is a \ref to the UAV itself
var/obj/item/modular_computer/mc_host = nano_host()
//This is so we can really scrape up any weakrefs that can't resolve
for(var/weakref/wr in mc_host.paired_uavs)
if(wr.ref == refstring)
if(current_uav?.weakref == wr)
set_current(null)
LAZYREMOVE(mc_host.paired_uavs, wr)
else if(href_list["view_uav"])
if(!current_uav)
return TOPIC_NOACTION
if(current_uav.check_eye(user) < 0)
to_chat(usr,"<span class='warning'>The screen freezes for a moment, before returning to the UAV selection menu. It's not able to connect to that UAV.</span>")
else
viewing_uav(user) ? unlook(user) : look(user)
return TOPIC_NOACTION
else if(href_list["power_uav"])
if(!current_uav)
return TOPIC_NOACTION
else if(current_uav.toggle_power())
//Clean up viewers faster
if(LAZYLEN(viewers))
for(var/weakref/W in viewers)
var/M = W.resolve()
if(M)
unlook(M)
return TOPIC_REFRESH
/datum/nano_module/uav/proc/DefaultTopicState()
return global.default_state
/datum/nano_module/uav/proc/CouldNotUseTopic(mob/user)
. = ..()
unlook(user)
/datum/nano_module/uav/proc/CouldUseTopic(mob/user)
. = ..()
if(viewing_uav(user))
look(user)
/datum/nano_module/uav/proc/set_current(var/obj/item/device/uav/U)
if(current_uav == U)
return
signal_strength = 0
current_uav = U
if(LAZYLEN(viewers))
for(var/weakref/W in viewers)
var/M = W.resolve()
if(M)
if(current_uav)
to_chat(M, "<span class='warning'>You're disconnected from the UAV's camera!</span>")
unlook(M)
else
look(M)
////
//// Finding signal strength between us and the UAV
////
/datum/nano_module/uav/proc/get_signal_to(var/atom/movable/AM)
// Following roughly the ntnet signal levels
// 0 is none
// 1 is weak
// 2 is strong
var/obj/item/modular_computer/host = nano_host() //Better not add this to anything other than modular computers.
if(!istype(host))
return
var/our_signal = host.get_ntnet_status() //1 low, 2 good, 3 wired, 0 none
var/their_z = get_z(AM)
//If we have no NTnet connection don't bother getting theirs
if(!our_signal)
if(get_z(host) == their_z && (get_dist(host, AM) < adhoc_range))
return 1 //We can connect (with weak signal) in same z without ntnet, within 30 turfs
else
return 0
var/list/zlevels_in_range = using_map.get_map_levels(their_z, FALSE)
var/list/zlevels_in_long_range = using_map.get_map_levels(their_z, TRUE, om_range = DEFAULT_OVERMAP_RANGE) - zlevels_in_range
var/their_signal = 0
for(var/relay in ntnet_global.relays)
var/obj/machinery/ntnet_relay/R = relay
if(!R.operable())
continue
if(R.z == their_z)
their_signal = 2
break
if(R.z in zlevels_in_range)
their_signal = 2
break
if(R.z in zlevels_in_long_range)
their_signal = 1
break
if(!their_signal) //They have no NTnet at all
if(get_z(host) == their_z && (get_dist(host, AM) < adhoc_range))
return 1 //We can connect (with weak signal) in same z without ntnet, within 30 turfs
else
return 0
else
return max(our_signal, their_signal)
////
//// UAV viewer handling
////
/datum/nano_module/uav/proc/viewing_uav(mob/user)
return (weakref(user) in viewers)
/datum/nano_module/uav/proc/look(var/mob/user)
if(issilicon(user)) //Too complicated for me to want to mess with at the moment
to_chat(user, "<span class='warning'>Regulations prevent you from controlling several corporeal forms at the same time!</span>")
return
if(!current_uav)
return
user.set_machine(nano_host())
user.reset_view(current_uav)
current_uav.add_master(user)
LAZYDISTINCTADD(viewers, weakref(user))
/datum/nano_module/uav/proc/unlook(var/mob/user)
user.unset_machine()
user.reset_view()
if(current_uav)
current_uav.remove_master(user)
LAZYREMOVE(viewers, weakref(user))
/datum/nano_module/uav/check_eye(var/mob/user)
if(get_dist(user, nano_host()) > 1 || user.blinded || !current_uav)
unlook(user)
return -1
var/viewflag = current_uav.check_eye(user)
if (viewflag < 0) //camera doesn't work
unlook(user)
return -1
return viewflag
////
//// Relaying movements to the UAV
////
/datum/nano_module/uav/relaymove(var/mob/user, direction)
if(current_uav)
return current_uav.relaymove(user, direction, signal_strength)
////
//// The effects when looking through a UAV
////
/datum/nano_module/uav/apply_visual(var/mob/M)
if(!M.client)
return
if(weakref(M) in viewers)
M.overlay_fullscreen("fishbed",/obj/screen/fullscreen/fishbed)
M.overlay_fullscreen("scanlines",/obj/screen/fullscreen/scanline)
if(signal_strength <= 1)
M.overlay_fullscreen("whitenoise",/obj/screen/fullscreen/noise)
else
M.clear_fullscreen("whitenoise", 0)
else
remove_visual(M)
/datum/nano_module/uav/remove_visual(mob/M)
if(!M.client)
return
M.clear_fullscreen("fishbed",0)
M.clear_fullscreen("scanlines",0)
M.clear_fullscreen("whitenoise",0)

View File

@@ -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,142 +65,144 @@
if(HDD.store_file(F))
return F
/datum/computer_file/program/wordprocessor/Topic(href, href_list)
/datum/computer_file/program/wordprocessor/tgui_act(action, list/params, datum/tgui/ui)
if(..())
return 1
return TRUE
if(href_list["PRG_txtrpeview"])
show_browser(usr,"<HTML><HEAD><TITLE>[open_file]</TITLE></HEAD>[pencode2html(loaded_data)]</BODY></HTML>", "window=[open_file]")
return 1
switch(action)
if("PRG_txtrpeview")
show_browser(usr,"<HTML><HEAD><TITLE>[open_file]</TITLE></HEAD>[pencode2html(loaded_data)]</BODY></HTML>", "window=[open_file]")
return TRUE
if(href_list["PRG_taghelp"])
to_chat(usr, "<span class='notice'>The hologram of a googly-eyed paper clip helpfully tells you:</span>")
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."}
if("PRG_taghelp")
to_chat(usr, "<span class='notice'>The hologram of a googly-eyed paper clip helpfully tells you:</span>")
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/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/list/data = get_header_data()
/datum/nano_module/program/computer_wordprocessor/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/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive
data["error"] = null
if(error)
data["error"] = error
var/obj/item/weapon/computer_hardware/hard_drive/HDD
var/obj/item/weapon/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")
@@ -209,7 +212,6 @@
)))
data["files"] = files
RHDD = PRG.computer.portable_drive
if(RHDD)
data["usbconnected"] = 1
var/list/usbfiles[0]
@@ -220,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

View File

@@ -8,29 +8,34 @@
size = 12
requires_ntnet = 1
available_on_ntnet = 1
nanomodule_path = /datum/nano_module/email_administration
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/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/tgui_data(mob/user, datum/tgui/ui, datum/tgui_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/tgui_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/weapon/card/id/I = user.GetIdCard()
var/obj/item/weapon/card/id/I = usr.GetIdCard()
if(!istype(I) || !(access_network in I.access))
return 1
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 using_map.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 using_map.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

View File

@@ -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
requires_ntnet = TRUE
required_access = access_network
available_on_ntnet = 1
nanomodule_path = /datum/nano_module/computer_ntnetmonitor/
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/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/tgui_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/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_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" && tgui_status(usr, state) == STATUS_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 && tgui_status(usr, state) == STATUS_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 && tgui_status(usr, state) == STATUS_INTERACTIVE)
ntnet_global.banned_nids -= nid
return TRUE

View File

@@ -1,5 +1,7 @@
var/warrant_uid = 0
/datum/datacore/var/list/warrants[] = list()
/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"
@@ -20,126 +21,119 @@ var/warrant_uid = 0
available_on_ntnet = 1
required_access = access_security
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/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/tgui_data(mob/user, datum/tgui/ui, datum/tgui_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/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_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/weapon/card/id/I = user.GetIdCard()
var/obj/item/weapon/card/id/I = usr.GetIdCard()
if(!istype(I) || !I.registered_name || !(access_security in I.access))
to_chat(user, "Authentication error: Unable to locate ID with apropriate access to allow this operation.")
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 suspect/location given" // VOREStation edit
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(tgui_status(usr, state) == STATUS_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" // VOREStation edit
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(tgui_status(usr, state) == STATUS_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(tgui_status(usr, state) == STATUS_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(tgui_status(usr, state) == STATUS_INTERACTIVE)
if (!new_charges)
return
activewarrant.fields["charges"] = new_charges
if(href_list["editwarrantauth"])
. = 1
if(!(access_hos in I.access)) // VOREStation edit begin
to_chat(user, "<span class='warning'>You don't have the access to do this!</span>")
return // VOREStation edit end
activewarrant.fields["auth"] = "[I.registered_name] - [I.assignment ? I.assignment : "(Unknown)"]"
if(href_list["back"])
. = 1
activewarrant = null
if("editwarrantauth")
. = TRUE
if(!(access_hos in I.access)) // VOREStation edit begin
to_chat(usr, "<span class='warning'>You don't have the access to do this!</span>")
return // VOREStation edit end
activewarrant.fields["auth"] = "[I.registered_name] - [I.assignment ? I.assignment : "(Unknown)"]"

View File

@@ -6,8 +6,8 @@
icon = 'icons/obj/vending.dmi'
icon_state = "robotics"
layer = OBJ_LAYER - 0.1
anchored = 1
density = 1
anchored = TRUE
density = TRUE
// The actual laptop/tablet
var/obj/item/modular_computer/laptop/fabricated_laptop = null
@@ -160,70 +160,77 @@
return total_price
return 0
/obj/machinery/lapvend/Topic(href, href_list)
/obj/machinery/lapvend/tgui_act(action, params)
if(..())
return 1
return TRUE
if(href_list["pick_device"])
if(state) // We've already picked a device type
return 0
devtype = text2num(href_list["pick_device"])
state = 1
fabricate_and_recalc_price(0)
return 1
if(href_list["clean_order"])
reset_order()
return 1
switch(action)
if("pick_device")
if(state) // We've already picked a device type
return FALSE
devtype = text2num(params["pick"])
state = 1
fabricate_and_recalc_price(FALSE)
return TRUE
if("clean_order")
reset_order()
return TRUE
if((state != 1) && devtype) // Following IFs should only be usable when in the Select Loadout mode
return 0
if(href_list["confirm_order"])
state = 2 // Wait for ID swipe for payment processing
fabricate_and_recalc_price(0)
return 1
if(href_list["hw_cpu"])
dev_cpu = text2num(href_list["hw_cpu"])
fabricate_and_recalc_price(0)
return 1
if(href_list["hw_battery"])
dev_battery = text2num(href_list["hw_battery"])
fabricate_and_recalc_price(0)
return 1
if(href_list["hw_disk"])
dev_disk = text2num(href_list["hw_disk"])
fabricate_and_recalc_price(0)
return 1
if(href_list["hw_netcard"])
dev_netcard = text2num(href_list["hw_netcard"])
fabricate_and_recalc_price(0)
return 1
if(href_list["hw_tesla"])
dev_tesla = text2num(href_list["hw_tesla"])
fabricate_and_recalc_price(0)
return 1
if(href_list["hw_nanoprint"])
dev_nanoprint = text2num(href_list["hw_nanoprint"])
fabricate_and_recalc_price(0)
return 1
if(href_list["hw_card"])
dev_card = text2num(href_list["hw_card"])
fabricate_and_recalc_price(0)
return 1
return 0
return FALSE
switch(action)
if("confirm_order")
state = 2 // Wait for ID swipe for payment processing
fabricate_and_recalc_price(FALSE)
return TRUE
if("hw_cpu")
dev_cpu = text2num(params["cpu"])
fabricate_and_recalc_price(FALSE)
return TRUE
if("hw_battery")
dev_battery = text2num(params["battery"])
fabricate_and_recalc_price(FALSE)
return TRUE
if("hw_disk")
dev_disk = text2num(params["disk"])
fabricate_and_recalc_price(FALSE)
return TRUE
if("hw_netcard")
dev_netcard = text2num(params["netcard"])
fabricate_and_recalc_price(FALSE)
return TRUE
if("hw_tesla")
dev_tesla = text2num(params["tesla"])
fabricate_and_recalc_price(FALSE)
return TRUE
if("hw_nanoprint")
dev_nanoprint = text2num(params["print"])
fabricate_and_recalc_price(FALSE)
return TRUE
if("hw_card")
dev_card = text2num(params["card"])
fabricate_and_recalc_price(FALSE)
return TRUE
return FALSE
/obj/machinery/lapvend/attack_hand(var/mob/user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/lapvend/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
/obj/machinery/lapvend/tgui_interact(mob/user, datum/tgui/ui)
if(stat & (BROKEN | NOPOWER | MAINT))
if(ui)
ui.close()
return 0
return FALSE
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ComputerFabricator")
ui.open()
/obj/machinery/lapvend/tgui_data(mob/user)
var/list/data = list()
var/list/data[0]
data["state"] = state
if(state == 1)
data["devtype"] = devtype
@@ -237,13 +244,7 @@
if(state == 1 || state == 2)
data["totalprice"] = total_price
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "computer_fabricator.tmpl", "Personal Computer Vendor", 500, 400)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
return data
obj/machinery/lapvend/attackby(obj/item/weapon/W as obj, mob/user as mob)
var/obj/item/weapon/card/id/I = W.GetID()
@@ -272,7 +273,6 @@ obj/machinery/lapvend/attackby(obj/item/weapon/W as obj, mob/user as mob)
return 0
return ..()
// Simplified payment processing, returns 1 on success.
/obj/machinery/lapvend/proc/process_payment(var/obj/item/weapon/card/id/I, var/obj/item/ID_container)
if(I==ID_container || ID_container == null)
@@ -305,4 +305,4 @@ obj/machinery/lapvend/attackby(obj/item/weapon/W as obj, mob/user as mob)
T.date = current_date_string
T.time = stationtime2text()
customer_account.transaction_log.Add(T)
return 1
return 1