mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-20 04:26:03 +01:00
first attempt. partial copy and stuff.
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
var/global/file_uid = 0
|
||||
|
||||
/datum/computer_file/
|
||||
var/filename = "NewFile" // Placeholder. No spacebars
|
||||
var/filetype = "XXX" // File full names are [filename].[filetype] so like NewFile.XXX in this case
|
||||
var/size = 1 // File size in GQ. Integers only!
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/holder // Holder that contains this file.
|
||||
var/unsendable = 0 // Whether the file may be sent to someone via NTNet transfer or other means.
|
||||
var/undeletable = 0 // Whether the file may be deleted. Setting to 1 prevents deletion/renaming/etc.
|
||||
var/uid // UID of this file
|
||||
|
||||
/datum/computer_file/New()
|
||||
..()
|
||||
uid = file_uid
|
||||
file_uid++
|
||||
|
||||
/datum/computer_file/Destroy()
|
||||
if(!holder)
|
||||
return ..()
|
||||
|
||||
holder.remove_file(src)
|
||||
// holder.holder is the computer that has drive installed. If we are Destroy()ing program that's currently running kill it.
|
||||
if(holder.holder2 && holder.holder2.active_program == src)
|
||||
holder.holder2.kill_program(1)
|
||||
holder = null
|
||||
..()
|
||||
|
||||
// Returns independent copy of this file.
|
||||
/datum/computer_file/proc/clone(var/rename = 0)
|
||||
var/datum/computer_file/temp = new type
|
||||
temp.unsendable = unsendable
|
||||
temp.undeletable = undeletable
|
||||
temp.size = size
|
||||
if(rename)
|
||||
temp.filename = filename + "(Copy)"
|
||||
else
|
||||
temp.filename = filename
|
||||
temp.filetype = filetype
|
||||
return temp
|
||||
@@ -0,0 +1,20 @@
|
||||
// /data/ files store data in string format.
|
||||
// They don't contain other logic for now.
|
||||
/datum/computer_file/data
|
||||
var/stored_data = "" // Stored data in string format.
|
||||
filetype = "DAT"
|
||||
var/block_size = 250
|
||||
var/do_not_edit = 0 // Whether the user will be reminded that the file probably shouldn't be edited.
|
||||
|
||||
/datum/computer_file/data/clone()
|
||||
var/datum/computer_file/data/temp = ..()
|
||||
temp.stored_data = stored_data
|
||||
return temp
|
||||
|
||||
// Calculates file size from amount of characters in saved string
|
||||
/datum/computer_file/data/proc/calculate_size()
|
||||
size = max(1, round(length(stored_data) / block_size))
|
||||
|
||||
/datum/computer_file/data/logfile
|
||||
filetype = "LOG"
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// /data/ files store data in string format.
|
||||
// They don't contain other logic for now.
|
||||
/datum/computer_file/data/news_article
|
||||
filetype = "XNML"
|
||||
filename = "Unknown News Entry"
|
||||
block_size = 1000 // Results in smaller files
|
||||
do_not_edit = 1 // Editing the file breaks most formatting due to some HTML tags not being accepted as input from average user.
|
||||
var/server_file_path // File path to HTML file that will be loaded on server start. Example: '/news_articles/space_magazine_1.html'. Use the /news_articles/ folder!
|
||||
|
||||
/datum/computer_file/data/news_article/New(var/load_from_file = 0)
|
||||
..()
|
||||
if(server_file_path && load_from_file)
|
||||
stored_data = file2text(server_file_path)
|
||||
calculate_size()
|
||||
|
||||
|
||||
// NEWS DEFINITIONS BELOW THIS LINE
|
||||
|
||||
/datum/computer_file/data/news_article/space/vol_one
|
||||
filename = "SPACE Magazine vol. 1"
|
||||
server_file_path = 'news_articles/space_magazine_1.html'
|
||||
|
||||
/datum/computer_file/data/news_article/space/vol_two
|
||||
filename = "SPACE Magazine vol. 2"
|
||||
server_file_path = 'news_articles/space_magazine_2.html'
|
||||
|
||||
/datum/computer_file/data/news_article/space/vol_three
|
||||
filename = "SPACE Magazine vol. 3"
|
||||
server_file_path = 'news_articles/space_magazine_3.html'
|
||||
@@ -0,0 +1,145 @@
|
||||
// /program/ files are executable programs that do things.
|
||||
/datum/computer_file/program
|
||||
filetype = "PRG"
|
||||
filename = "UnknownProgram" // File name. FILE NAME MUST BE UNIQUE IF YOU WANT THE PROGRAM TO BE DOWNLOADABLE FROM NTNET!
|
||||
var/required_access = null // List of required accesses to *run* the program.
|
||||
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.
|
||||
var/program_state = PROGRAM_STATE_KILLED// PROGRAM_STATE_KILLED or PROGRAM_STATE_BACKGROUND or PROGRAM_STATE_ACTIVE - specifies whether this program is running.
|
||||
var/obj/item/modular_computer/computer // Device that runs this program.
|
||||
var/filedesc = "Unknown Program" // User-friendly name of this program.
|
||||
var/extended_desc = "N/A" // Short description of this program's function.
|
||||
var/program_icon_state = null // Program-specific screen icon state
|
||||
var/requires_ntnet = 0 // Set to 1 for program to require nonstop NTNet connection to run. If NTNet connection is lost program crashes.
|
||||
var/requires_ntnet_feature = 0 // Optional, if above is set to 1 checks for specific function of NTNet (currently NTNET_SOFTWAREDOWNLOAD, NTNET_PEERTOPEER, NTNET_SYSTEMCONTROL and NTNET_COMMUNICATION)
|
||||
var/ntnet_status = 1 // NTNet status, updated every tick by computer running this program. Don't use this for checks if NTNet works, computers do that. Use this for calculations, etc.
|
||||
var/usage_flags = PROGRAM_ALL // Bitflags (PROGRAM_CONSOLE, PROGRAM_LAPTOP, PROGRAM_TABLET combination) or PROGRAM_ALL
|
||||
var/network_destination = null // Optional string that describes what NTNet server/system this program connects to. Used in default logging.
|
||||
var/available_on_ntnet = 1 // Whether the program can be downloaded from NTNet. Set to 0 to disable.
|
||||
var/available_on_syndinet = 0 // Whether the program can be downloaded from SyndiNet (accessible via emagging the computer). Set to 1 to enable.
|
||||
var/computer_emagged = 0 // Set to 1 if computer that's running us was emagged. Computer updates this every Process() tick
|
||||
var/ui_header = null // Example: "something.gif" - a header image that will be rendered in computer's UI when this program is running at background. Images are taken from /nano/images/status_icons. Be careful not to use too large images!
|
||||
|
||||
/datum/computer_file/program/New(var/obj/item/modular_computer/comp = null)
|
||||
..()
|
||||
if(comp && istype(comp))
|
||||
computer = comp
|
||||
|
||||
/datum/computer_file/program/Destroy()
|
||||
computer = null
|
||||
. = ..()
|
||||
|
||||
/datum/computer_file/program/nano_host()
|
||||
return computer.nano_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
|
||||
temp.requires_ntnet_feature = requires_ntnet_feature
|
||||
temp.usage_flags = usage_flags
|
||||
return temp
|
||||
|
||||
// Relays icon update to the computer.
|
||||
/datum/computer_file/program/proc/update_computer_icon()
|
||||
if(computer)
|
||||
computer.update_icon()
|
||||
|
||||
// Attempts to create a log in global ntnet datum. Returns 1 on success, 0 on fail.
|
||||
/datum/computer_file/program/proc/generate_network_log(var/text)
|
||||
if(computer)
|
||||
return computer.add_log(text)
|
||||
return 0
|
||||
|
||||
/datum/computer_file/program/proc/is_supported_by_hardware(var/hardware_flag = 0, var/loud = 0, var/mob/user = null)
|
||||
if(!(hardware_flag & usage_flags))
|
||||
if(loud && computer && user)
|
||||
user << "<span class='danger'>\The [computer] flashes an \"Hardware Error - Incompatible software\" warning.</span>"
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/computer_file/program/proc/get_signal(var/specific_action = 0)
|
||||
if(computer)
|
||||
return computer.get_ntnet_status(specific_action)
|
||||
return 0
|
||||
|
||||
// Called by Process() on device that runs us, once every tick.
|
||||
/datum/computer_file/program/proc/process_tick()
|
||||
return 1
|
||||
|
||||
// Check if the user can run program. Only humans can operate computer. Automatically called in run_program()
|
||||
// User has to wear their ID or have it inhand for ID Scan to work.
|
||||
// Can also be called manually, with optional parameter being access_to_check to scan the user's ID
|
||||
/datum/computer_file/program/proc/can_run(mob/living/user, loud = 0, access_to_check)
|
||||
// Defaults to required_access
|
||||
if(!access_to_check)
|
||||
access_to_check = required_access
|
||||
if(!access_to_check) // No required_access, allow it.
|
||||
return 1
|
||||
|
||||
var/obj/item/weapon/card/id/I = user.GetIdCard()
|
||||
if(!I)
|
||||
if(loud)
|
||||
user << "<span class='danger'>\The [computer] flashes an \"RFID Error - Unable to scan ID\" warning.</span>"
|
||||
return 0
|
||||
|
||||
if(access_to_check in I.access)
|
||||
return 1
|
||||
else if(loud)
|
||||
user << "<span class='danger'>\The [computer] flashes an \"Access Denied\" warning.</span>"
|
||||
|
||||
// This attempts to retrieve header data for NanoUIs. If implementing completely new device of different type than existing ones
|
||||
// always include the device here in this proc. This proc basically relays the request to whatever is running the program.
|
||||
/datum/computer_file/program/proc/get_header_data()
|
||||
if(computer)
|
||||
return computer.get_header_data()
|
||||
return list()
|
||||
|
||||
// This is performed on program startup. May be overriden to add extra logic. Remember to include ..() call. Return 1 on success, 0 on failure.
|
||||
// When implementing new program based device, use this to run the program.
|
||||
/datum/computer_file/program/proc/run_program(mob/living/user)
|
||||
if(can_run(user, 1))
|
||||
if(nanomodule_path)
|
||||
NM = new nanomodule_path(src, new /datum/topic_manager/program(src), src)
|
||||
if(requires_ntnet && network_destination)
|
||||
generate_network_log("Connection opened to [network_destination].")
|
||||
program_state = PROGRAM_STATE_ACTIVE
|
||||
return 1
|
||||
return 0
|
||||
|
||||
// Use this proc to kill the program. Designed to be implemented by each program if it requires on-quit logic, such as the NTNRC client.
|
||||
/datum/computer_file/program/proc/kill_program(var/forced = 0)
|
||||
program_state = PROGRAM_STATE_KILLED
|
||||
if(network_destination)
|
||||
generate_network_log("Connection to [network_destination] closed.")
|
||||
if(NM)
|
||||
qdel(NM)
|
||||
NM = null
|
||||
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.
|
||||
if(ui)
|
||||
ui.close()
|
||||
return computer.ui_interact(user)
|
||||
if(istype(NM))
|
||||
NM.ui_interact(user, ui_key, null, force_open)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
// CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC:
|
||||
// Topic calls are automagically forwarded from NanoModule this program contains.
|
||||
// Calls beginning with "PRG_" are reserved for programs handling.
|
||||
// Calls beginning with "PC_" are reserved for computer handling (by whatever runs the program)
|
||||
// ALWAYS INCLUDE PARENT CALL ..() OR DIE IN FIRE.
|
||||
/datum/computer_file/program/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
if(computer)
|
||||
return computer.Topic(href, href_list)
|
||||
@@ -0,0 +1,18 @@
|
||||
// Events are sent to the program by the computer.
|
||||
// Always include a parent call when overriding an event.
|
||||
|
||||
// Called when the ID card is removed from computer. ID is removed AFTER this proc.
|
||||
/datum/computer_file/program/proc/event_idremoved(var/background)
|
||||
return
|
||||
|
||||
// Called when the computer fails due to power loss. Override when program wants to specifically react to power loss.
|
||||
/datum/computer_file/program/proc/event_powerfailure(var/background)
|
||||
kill_program(1)
|
||||
|
||||
// Called when the network connectivity fails. Computer does necessary checks and only calls this when requires_ntnet_feature and similar variables are not met.
|
||||
/datum/computer_file/program/proc/event_networkfailure(var/background)
|
||||
kill_program(1)
|
||||
if(background)
|
||||
computer.visible_message("<span class='danger'>\The [computer]'s screen displays an \"Process [filename].[filetype] (PID [rand(100,999)]) terminated - Network Error\" error</span>")
|
||||
else
|
||||
computer.visible_message("<span class='danger'>\The [computer]'s screen briefly freezes and then shows \"NETWORK ERROR - NTNet connection lost. Please retry. If problem persists contact your system administrator.\" error.</span>")
|
||||
@@ -0,0 +1,85 @@
|
||||
// These programs are associated with engineering.
|
||||
|
||||
/datum/computer_file/program/power_monitor
|
||||
filename = "powermonitor"
|
||||
filedesc = "Power Monitoring"
|
||||
nanomodule_path = /datum/nano_module/power_monitor/
|
||||
program_icon_state = "power_monitor"
|
||||
extended_desc = "This program connects to sensors around the station to provide information about electrical systems"
|
||||
ui_header = "power_norm.gif"
|
||||
required_access = access_engine
|
||||
requires_ntnet = 1
|
||||
network_destination = "power monitoring system"
|
||||
size = 9
|
||||
var/has_alert = 0
|
||||
|
||||
/datum/computer_file/program/power_monitor/process_tick()
|
||||
..()
|
||||
var/datum/nano_module/power_monitor/NMA = NM
|
||||
if(istype(NMA) && NMA.has_alarm())
|
||||
if(!has_alert)
|
||||
program_icon_state = "power_monitor_warn"
|
||||
ui_header = "power_warn.gif"
|
||||
update_computer_icon()
|
||||
has_alert = 1
|
||||
else
|
||||
if(has_alert)
|
||||
program_icon_state = "power_monitor"
|
||||
ui_header = "power_norm.gif"
|
||||
update_computer_icon()
|
||||
has_alert = 0
|
||||
|
||||
/datum/computer_file/program/alarm_monitor
|
||||
filename = "alarmmonitor"
|
||||
filedesc = "Alarm Monitoring"
|
||||
nanomodule_path = /datum/nano_module/alarm_monitor/engineering
|
||||
ui_header = "alarm_green.gif"
|
||||
program_icon_state = "alert-green"
|
||||
extended_desc = "This program provides visual interface for station's alarm system."
|
||||
requires_ntnet = 1
|
||||
network_destination = "alarm monitoring network"
|
||||
size = 5
|
||||
var/has_alert = 0
|
||||
|
||||
/datum/computer_file/program/alarm_monitor/process_tick()
|
||||
..()
|
||||
var/datum/nano_module/alarm_monitor/NMA = NM
|
||||
if(istype(NMA) && NMA.has_major_alarms())
|
||||
if(!has_alert)
|
||||
program_icon_state = "alert-red"
|
||||
ui_header = "alarm_red.gif"
|
||||
update_computer_icon()
|
||||
has_alert = 1
|
||||
else
|
||||
if(has_alert)
|
||||
program_icon_state = "alert-green"
|
||||
ui_header = "alarm_green.gif"
|
||||
update_computer_icon()
|
||||
has_alert = 0
|
||||
return 1
|
||||
|
||||
/datum/computer_file/program/atmos_control
|
||||
filename = "atmoscontrol"
|
||||
filedesc = "Atmosphere Control"
|
||||
nanomodule_path = /datum/nano_module/atmos_control
|
||||
program_icon_state = "atmos_control"
|
||||
extended_desc = "This program allows remote control of air alarms around the station. This program can not be run on tablet computers."
|
||||
required_access = access_atmospherics
|
||||
requires_ntnet = 1
|
||||
network_destination = "atmospheric control system"
|
||||
requires_ntnet_feature = NTNET_SYSTEMCONTROL
|
||||
usage_flags = PROGRAM_LAPTOP | PROGRAM_CONSOLE
|
||||
size = 17
|
||||
|
||||
/datum/computer_file/program/rcon_console
|
||||
filename = "rconconsole"
|
||||
filedesc = "RCON Remote Control"
|
||||
nanomodule_path = /datum/nano_module/rcon
|
||||
program_icon_state = "generic"
|
||||
extended_desc = "This program allows remote control of power distribution systems around the station. This program can not be run on tablet computers."
|
||||
required_access = access_engine
|
||||
requires_ntnet = 1
|
||||
network_destination = "RCON remote control system"
|
||||
requires_ntnet_feature = NTNET_SYSTEMCONTROL
|
||||
usage_flags = PROGRAM_LAPTOP | PROGRAM_CONSOLE
|
||||
size = 19
|
||||
@@ -0,0 +1,10 @@
|
||||
/datum/computer_file/program/suit_sensors
|
||||
filename = "sensormonitor"
|
||||
filedesc = "Suit Sensors Monitoring"
|
||||
nanomodule_path = /datum/nano_module/crew_monitor
|
||||
program_icon_state = "crew"
|
||||
extended_desc = "This program connects to life signs monitoring system to provide basic information on crew health."
|
||||
required_access = access_medical
|
||||
requires_ntnet = 1
|
||||
network_destination = "crew lifesigns monitoring system"
|
||||
size = 11
|
||||
@@ -0,0 +1,31 @@
|
||||
/obj/machinery/modular_computer/initial_data()
|
||||
return cpu ? cpu.get_header_data() : ..()
|
||||
|
||||
/obj/item/modular_computer/initial_data()
|
||||
return get_header_data()
|
||||
|
||||
/obj/machinery/modular_computer/update_layout()
|
||||
return TRUE
|
||||
|
||||
/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)
|
||||
@@ -0,0 +1,105 @@
|
||||
/datum/computer_file/program/ntnet_dos
|
||||
filename = "ntn_dos"
|
||||
filedesc = "DoS Traffic Generator"
|
||||
program_icon_state = "hostile"
|
||||
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/
|
||||
var/obj/machinery/ntnet_relay/target = null
|
||||
var/dos_speed = 0
|
||||
var/error = ""
|
||||
var/executed = 0
|
||||
|
||||
/datum/computer_file/program/ntnet_dos/process_tick()
|
||||
dos_speed = 0
|
||||
switch(ntnet_status)
|
||||
if(1)
|
||||
dos_speed = NTNETSPEED_LOWSIGNAL * 10
|
||||
if(2)
|
||||
dos_speed = NTNETSPEED_HIGHSIGNAL * 10
|
||||
if(3)
|
||||
dos_speed = NTNETSPEED_ETHERNET * 10
|
||||
if(target && executed)
|
||||
target.dos_overload += dos_speed
|
||||
if(!target.is_operational())
|
||||
target.dos_sources.Remove(src)
|
||||
target = null
|
||||
error = "Connection to destination relay lost."
|
||||
|
||||
/datum/computer_file/program/ntnet_dos/kill_program(var/forced)
|
||||
target.dos_sources.Remove(src)
|
||||
target = null
|
||||
executed = 0
|
||||
|
||||
..(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)
|
||||
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
|
||||
|
||||
// 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
|
||||
else
|
||||
var/list/relays[0]
|
||||
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
|
||||
|
||||
ui = nanomanager.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)
|
||||
|
||||
/datum/computer_file/program/ntnet_dos/Topic(href, href_list)
|
||||
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
|
||||
@@ -0,0 +1,79 @@
|
||||
/datum/computer_file/program/revelation
|
||||
filename = "revelation"
|
||||
filedesc = "Revelation"
|
||||
program_icon_state = "hostile"
|
||||
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/
|
||||
var/armed = 0
|
||||
|
||||
/datum/computer_file/program/revelation/run_program(var/mob/living/user)
|
||||
. = ..(user)
|
||||
if(armed)
|
||||
activate()
|
||||
|
||||
/datum/computer_file/program/revelation/proc/activate()
|
||||
if(computer)
|
||||
computer.visible_message("<span class='notice'>\The [computer]'s screen brightly flashes and loud electrical buzzing is heard.</span>")
|
||||
computer.enabled = 0
|
||||
computer.update_icon()
|
||||
qdel(computer.hard_drive)
|
||||
if(computer.battery_module && prob(25))
|
||||
qdel(computer.battery_module)
|
||||
computer.visible_message("<span class='notice'>\The [computer]'s battery explodes in rain of sparks.</span>")
|
||||
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
|
||||
s.set_up(10, 1, computer.loc)
|
||||
s.start()
|
||||
if(istype(computer, /obj/item/modular_computer/processor))
|
||||
var/obj/item/modular_computer/processor/P = computer
|
||||
if(P.machinery_computer.tesla_link && prob(50))
|
||||
qdel(P.machinery_computer.tesla_link)
|
||||
computer.visible_message("<span class='notice'>\The [computer]'s tesla link explodes in rain of sparks.</span>")
|
||||
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
|
||||
s.set_up(10, 1, computer.loc)
|
||||
s.start()
|
||||
|
||||
/datum/computer_file/program/revelation/Topic(href, href_list)
|
||||
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
|
||||
return 1
|
||||
|
||||
/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/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 = nanomanager.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)
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
/datum/computer_file/program/card_mod
|
||||
filename = "cardmod"
|
||||
filedesc = "ID card modification program"
|
||||
nanomodule_path = /datum/nano_module/program/card_mod
|
||||
program_icon_state = "id"
|
||||
extended_desc = "Program for programming employee ID cards to access parts of the station."
|
||||
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 : "-----"
|
||||
|
||||
|
||||
data["engineering_jobs"] = format_jobs(engineering_positions)
|
||||
data["medical_jobs"] = format_jobs(medical_positions)
|
||||
data["science_jobs"] = format_jobs(science_positions)
|
||||
data["security_jobs"] = format_jobs(security_positions)
|
||||
data["cargo_jobs"] = format_jobs(cargo_positions)
|
||||
data["civilian_jobs"] = format_jobs(civilian_positions)
|
||||
data["centcom_jobs"] = format_jobs(get_all_centcom_jobs())
|
||||
|
||||
data["all_centcom_access"] = is_centcom ? get_accesses(1) : null
|
||||
data["regions"] = get_accesses()
|
||||
|
||||
if(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), " ", " "),
|
||||
"ref" = access,
|
||||
"allowed" = (access in id_card.access) ? 1 : 0)))
|
||||
data["all_centcom_access"] = all_centcom_access
|
||||
else
|
||||
var/list/regions = list()
|
||||
for(var/i = 1; i <= 7; i++)
|
||||
var/list/accesses = list()
|
||||
for(var/access in get_region_accesses(i))
|
||||
if (get_access_desc(access))
|
||||
accesses.Add(list(list(
|
||||
"desc" = replacetext(get_access_desc(access), " ", " "),
|
||||
"ref" = access,
|
||||
"allowed" = (access in id_card.access) ? 1 : 0)))
|
||||
|
||||
regions.Add(list(list(
|
||||
"name" = get_region_accesses_name(i),
|
||||
"accesses" = accesses)))
|
||||
data["regions"] = regions
|
||||
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "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.stored_card
|
||||
var/list/formatted = list()
|
||||
for(var/job in jobs)
|
||||
formatted.Add(list(list(
|
||||
"display_name" = replacetext(job, " ", " "),
|
||||
"target_rank" = id_card && id_card.assignment ? id_card.assignment : "Unassigned",
|
||||
"job" = job)))
|
||||
|
||||
return formatted
|
||||
|
||||
/datum/nano_module/program/card_mod/proc/get_accesses(var/is_centcom = 0)
|
||||
return null
|
||||
|
||||
|
||||
/datum/computer_file/program/card_mod/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
var/mob/user = usr
|
||||
var/obj/item/weapon/card/id/user_id_card = user.GetIdCard()
|
||||
var/obj/item/weapon/card/id/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"))
|
||||
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())))
|
||||
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 = "Terminated"
|
||||
remove_nt_access(id_card)
|
||||
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))
|
||||
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)
|
||||
usr << "<span class='warning'>No log exists for this job: [t1]</span>"
|
||||
return
|
||||
|
||||
access = jobdatum.get_access()
|
||||
|
||||
remove_nt_access(id_card)
|
||||
apply_access(id_card, 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])")
|
||||
|
||||
nanomanager.update_uis(NM)
|
||||
return 1
|
||||
|
||||
/datum/computer_file/program/card_mod/proc/remove_nt_access(var/obj/item/weapon/card/id/id_card)
|
||||
id_card.access -= get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM)
|
||||
|
||||
/datum/computer_file/program/card_mod/proc/apply_access(var/obj/item/weapon/card/id/id_card, var/list/accesses)
|
||||
id_card.access |= accesses
|
||||
@@ -0,0 +1,417 @@
|
||||
#define STATE_DEFAULT 1
|
||||
#define STATE_MESSAGELIST 2
|
||||
#define STATE_VIEWMESSAGE 3
|
||||
#define STATE_STATUSDISPLAY 4
|
||||
#define STATE_ALERT_LEVEL 5
|
||||
/datum/computer_file/program/comm
|
||||
filename = "comm"
|
||||
filedesc = "Command and communications program."
|
||||
program_icon_state = "comm"
|
||||
nanomodule_path = /datum/nano_module/program/comm
|
||||
extended_desc = "Used to command and control the station. Can relay long-range communications. This program can not be run on tablet computers."
|
||||
required_access = access_heads
|
||||
requires_ntnet = 1
|
||||
size = 12
|
||||
usage_flags = PROGRAM_CONSOLE | PROGRAM_LAPTOP
|
||||
network_destination = "station long-range communication array"
|
||||
var/datum/comm_message_listener/message_core = new
|
||||
|
||||
/datum/computer_file/program/comm/clone()
|
||||
var/datum/computer_file/program/comm/temp = ..()
|
||||
temp.message_core.messages = null
|
||||
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"] = is_autenthicated(user)
|
||||
data["boss_short"] = boss_short
|
||||
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_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 = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "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/is_autenthicated(var/mob/user)
|
||||
if(program)
|
||||
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(is_autenthicated(user) && !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)
|
||||
usr << "Please allow at least one minute to pass between announcements"
|
||||
return TRUE
|
||||
var/input = input(usr, "Please write a message to announce to the station crew.", "Priority Announcement") as null|text
|
||||
if(!input || !can_still_topic())
|
||||
return 1
|
||||
crew_announcement.Announce(input)
|
||||
announcment_cooldown = 1
|
||||
spawn(600)//One minute cooldown
|
||||
announcment_cooldown = 0
|
||||
if("message")
|
||||
. = 1
|
||||
if(href_list["target"] == "emagged")
|
||||
if(program)
|
||||
if(is_autenthicated(user) && program.computer_emagged && !issilicon(usr) && ntn_comm)
|
||||
if(centcomm_message_cooldown)
|
||||
usr << "<span class='warning'>Arrays recycling. Please stand by.</span>"
|
||||
nanomanager.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)
|
||||
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(is_autenthicated(user) && !issilicon(usr) && ntn_comm)
|
||||
if(centcomm_message_cooldown)
|
||||
usr << "<span class='warning'>Arrays recycling. Please stand by.</span>"
|
||||
nanomanager.update_uis(src)
|
||||
return
|
||||
if(!is_relay_online())//Contact Centcom has a check, Syndie doesn't to allow for Traitor funs.
|
||||
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 [boss_short] 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
|
||||
Centcomm_announce(input, usr)
|
||||
usr << "<span class='notice'>Message transmitted.</span>"
|
||||
log_say("[key_name(usr)] has made an IA [boss_short] announcement: [input]")
|
||||
centcomm_message_cooldown = 1
|
||||
spawn(300) //30 second cooldown
|
||||
centcomm_message_cooldown = 0
|
||||
if("shuttle")
|
||||
. = 1
|
||||
if(is_autenthicated(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(is_autenthicated(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(is_autenthicated(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_BLUE)
|
||||
feedback_inc("alert_comms_blue",1)
|
||||
else
|
||||
usr << "You press button, but red light flashes and nothing happens." //This should never happen
|
||||
current_status = STATE_DEFAULT
|
||||
if("viewmessage")
|
||||
. = 1
|
||||
if(is_autenthicated(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(is_autenthicated(user) && ntn_comm && l != global_message_listener)
|
||||
l.Remove(current_viewing_message)
|
||||
current_status = STATE_MESSAGELIST
|
||||
if("printmessage")
|
||||
. = 1
|
||||
if(is_autenthicated(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"]))
|
||||
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>")
|
||||
|
||||
#undef STATE_DEFAULT
|
||||
#undef STATE_MESSAGELIST
|
||||
#undef STATE_VIEWMESSAGE
|
||||
#undef STATE_STATUSDISPLAY
|
||||
#undef STATE_ALERT_LEVEL
|
||||
|
||||
/*
|
||||
General message handling stuff
|
||||
*/
|
||||
var/list/comm_message_listeners = list() //We first have to initialize list then we can use it.
|
||||
var/datum/comm_message_listener/global_message_listener = new //May be used by admins
|
||||
var/last_message_id = 0
|
||||
|
||||
/proc/get_comm_message_id()
|
||||
last_message_id = last_message_id + 1
|
||||
return last_message_id
|
||||
|
||||
/proc/post_comm_message(var/message_title, var/message_text)
|
||||
var/list/message = list()
|
||||
message["id"] = get_comm_message_id()
|
||||
message["title"] = message_title
|
||||
message["contents"] = message_text
|
||||
|
||||
for (var/datum/comm_message_listener/l in comm_message_listeners)
|
||||
l.Add(message)
|
||||
|
||||
for (var/obj/machinery/modular_computer/console/preset/command/main/computer in global_modular_computers)
|
||||
if(!(computer.stat & (BROKEN | NOPOWER)) && computer.cpu)
|
||||
if(computer.cpu.hard_drive)
|
||||
var/datum/computer_file/program/comm/C = locate(/datum/computer_file/program/comm) in computer.cpu.hard_drive.stored_files
|
||||
if(C)
|
||||
var/obj/item/weapon/paper/intercept = new /obj/item/weapon/paper(computer.loc)
|
||||
intercept.name = message_title
|
||||
intercept.info = message_text
|
||||
|
||||
/datum/comm_message_listener
|
||||
var/list/messages
|
||||
|
||||
/datum/comm_message_listener/New()
|
||||
..()
|
||||
messages = list()
|
||||
comm_message_listeners.Add(src)
|
||||
|
||||
/datum/comm_message_listener/proc/Add(var/list/message)
|
||||
messages[++messages.len] = message
|
||||
|
||||
/datum/comm_message_listener/proc/Remove(var/list/message)
|
||||
messages -= list(message)
|
||||
|
||||
/proc/post_status(var/command, var/data1, var/data2)
|
||||
|
||||
var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435)
|
||||
|
||||
if(!frequency) return
|
||||
|
||||
|
||||
var/datum/signal/status_signal = new
|
||||
status_signal.source = src
|
||||
status_signal.transmission_method = 1
|
||||
status_signal.data["command"] = command
|
||||
|
||||
switch(command)
|
||||
if("message")
|
||||
status_signal.data["msg1"] = data1
|
||||
status_signal.data["msg2"] = data2
|
||||
log_admin("STATUS: [key_name(usr)] set status screen message with [src]: [data1] [data2]")
|
||||
if("alert")
|
||||
status_signal.data["picture_state"] = data1
|
||||
|
||||
frequency.post_signal(src, status_signal)
|
||||
|
||||
/proc/cancel_call_proc(var/mob/user)
|
||||
if (!( ticker ) || !emergency_shuttle.can_recall())
|
||||
return
|
||||
if((ticker.mode.name == "blob")||(ticker.mode.name == "Meteor"))
|
||||
return
|
||||
|
||||
if(!emergency_shuttle.going_to_centcom()) //check that shuttle isn't already heading to centcomm
|
||||
emergency_shuttle.recall()
|
||||
log_game("[key_name(user)] has recalled the shuttle.")
|
||||
message_admins("[key_name_admin(user)] has recalled the shuttle.", 1)
|
||||
return
|
||||
|
||||
|
||||
/proc/is_relay_online()
|
||||
for(var/obj/machinery/bluespacerelay/M in machines)
|
||||
if(M.stat == 0)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/proc/enable_prison_shuttle(var/mob/user)
|
||||
for(var/obj/machinery/computer/prison_shuttle/PS in machines)
|
||||
PS.allowedtocall = !(PS.allowedtocall)
|
||||
|
||||
/proc/call_shuttle_proc(var/mob/user)
|
||||
if ((!( ticker ) || !emergency_shuttle.location()))
|
||||
return
|
||||
|
||||
if(!universe.OnShuttleCall(usr))
|
||||
user << "<span class='notice'>Cannot establish a bluespace connection.</span>"
|
||||
return
|
||||
|
||||
if(deathsquad.deployed)
|
||||
user << "[boss_short] will not allow the shuttle to be called. Consider all contracts terminated."
|
||||
return
|
||||
|
||||
if(emergency_shuttle.deny_shuttle)
|
||||
user << "The emergency shuttle may not be sent at this time. Please try again later."
|
||||
return
|
||||
|
||||
if(world.time < 6000) // Ten minute grace period to let the game get going without lolmetagaming. -- TLE
|
||||
user << "The emergency shuttle is refueling. Please wait another [round((6000-world.time)/600)] minute\s before trying again."
|
||||
return
|
||||
|
||||
if(emergency_shuttle.going_to_centcom())
|
||||
user << "The emergency shuttle may not be called while returning to [boss_short]."
|
||||
return
|
||||
|
||||
if(emergency_shuttle.online())
|
||||
user << "The emergency shuttle is already on its way."
|
||||
return
|
||||
|
||||
if(ticker.mode.name == "blob" || ticker.mode.name == "epidemic")
|
||||
user << "Under directive 7-10, [station_name()] is quarantined until further notice."
|
||||
return
|
||||
|
||||
if(!emergency_shuttle.call_evac(user))
|
||||
return
|
||||
log_and_message_admins("has called the shuttle.")
|
||||
|
||||
/proc/init_shift_change(var/mob/user, var/force = 0)
|
||||
if ((!( ticker ) || !emergency_shuttle.location()))
|
||||
return
|
||||
|
||||
if(emergency_shuttle.going_to_centcom())
|
||||
user << "The shuttle may not be called while returning to [boss_short]."
|
||||
return
|
||||
|
||||
if(emergency_shuttle.online())
|
||||
user << "The shuttle is already on its way."
|
||||
return
|
||||
|
||||
// if force is 0, some things may stop the shuttle call
|
||||
if(!force)
|
||||
if(emergency_shuttle.deny_shuttle)
|
||||
user << "[boss_short] does not currently have a shuttle available in your sector. Please try again later."
|
||||
return
|
||||
|
||||
if(deathsquad.deployed == 1)
|
||||
user << "[boss_short] will not allow the shuttle to be called. Consider all contracts terminated."
|
||||
return
|
||||
|
||||
if(world.time < 54000) // 30 minute grace period to let the game get going
|
||||
user << "The shuttle is refueling. Please wait another [round((54000-world.time)/60)] minutes before trying again."
|
||||
return
|
||||
|
||||
if(ticker.mode.auto_recall_shuttle)
|
||||
//New version pretends to call the shuttle but cause the shuttle to return after a random duration.
|
||||
emergency_shuttle.auto_recall = 1
|
||||
|
||||
if(ticker.mode.name == "blob" || ticker.mode.name == "epidemic")
|
||||
user << "Under directive 7-10, [station_name()] is quarantined until further notice."
|
||||
return
|
||||
|
||||
emergency_shuttle.call_transfer()
|
||||
|
||||
//delay events in case of an autotransfer
|
||||
if (isnull(user))
|
||||
event_manager.delay_events(EVENT_LEVEL_MODERATE, 10200) //17 minutes
|
||||
event_manager.delay_events(EVENT_LEVEL_MAJOR, 10200)
|
||||
|
||||
log_game("[user? key_name(user) : "Autotransfer"] has called the shuttle.")
|
||||
message_admins("[user? key_name_admin(user) : "Autotransfer"] has called the shuttle.", 1)
|
||||
|
||||
return
|
||||
@@ -0,0 +1,62 @@
|
||||
// This is special hardware configuration program.
|
||||
// It is to be used only with modular computers.
|
||||
// It allows you to toggle components of your device.
|
||||
|
||||
/datum/computer_file/program/computerconfig
|
||||
filename = "compconfig"
|
||||
filedesc = "Computer Configuration Tool"
|
||||
extended_desc = "This program allows configuration of computer's hardware"
|
||||
program_icon_state = "generic"
|
||||
unsendable = 1
|
||||
undeletable = 1
|
||||
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 = nanomanager.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()
|
||||
@@ -0,0 +1,241 @@
|
||||
/datum/computer_file/program/filemanager
|
||||
filename = "filemanager"
|
||||
filedesc = "NTOS File Manager"
|
||||
extended_desc = "This program allows management of files."
|
||||
program_icon_state = "generic"
|
||||
size = 8
|
||||
requires_ntnet = 0
|
||||
available_on_ntnet = 0
|
||||
undeletable = 1
|
||||
nanomodule_path = /datum/nano_module/program/computer_filemanager/
|
||||
var/open_file
|
||||
var/error
|
||||
|
||||
/datum/computer_file/program/filemanager/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
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)
|
||||
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
|
||||
// 16384 is the limit for file length in characters. Currently, papers have value of 2048 so this is 8 times as long, since we can't edit parts of the file independently.
|
||||
var/newtext = sanitize(html_decode(input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", F.stored_data) as message|null), 16384)
|
||||
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>[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(parse_tags(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(.)
|
||||
nanomanager.update_uis(NM)
|
||||
|
||||
/datum/computer_file/program/filemanager/proc/parse_tags(var/t)
|
||||
t = replacetext(t, "\[center\]", "<center>")
|
||||
t = replacetext(t, "\[/center\]", "</center>")
|
||||
t = replacetext(t, "\[br\]", "<BR>")
|
||||
t = replacetext(t, "\[b\]", "<B>")
|
||||
t = replacetext(t, "\[/b\]", "</B>")
|
||||
t = replacetext(t, "\[i\]", "<I>")
|
||||
t = replacetext(t, "\[/i\]", "</I>")
|
||||
t = replacetext(t, "\[u\]", "<U>")
|
||||
t = replacetext(t, "\[/u\]", "</U>")
|
||||
t = replacetext(t, "\[time\]", "[stationtime2text()]")
|
||||
t = replacetext(t, "\[date\]", "[stationdate2text()]")
|
||||
t = replacetext(t, "\[large\]", "<font size=\"4\">")
|
||||
t = replacetext(t, "\[/large\]", "</font>")
|
||||
t = replacetext(t, "\[h1\]", "<H1>")
|
||||
t = replacetext(t, "\[/h1\]", "</H1>")
|
||||
t = replacetext(t, "\[h2\]", "<H2>")
|
||||
t = replacetext(t, "\[/h2\]", "</H2>")
|
||||
t = replacetext(t, "\[h3\]", "<H3>")
|
||||
t = replacetext(t, "\[/h3\]", "</H3>")
|
||||
t = replacetext(t, "\[*\]", "<li>")
|
||||
t = replacetext(t, "\[hr\]", "<HR>")
|
||||
t = replacetext(t, "\[small\]", "<font size = \"1\">")
|
||||
t = replacetext(t, "\[/small\]", "</font>")
|
||||
t = replacetext(t, "\[list\]", "<ul>")
|
||||
t = replacetext(t, "\[/list\]", "</ul>")
|
||||
t = replacetext(t, "\[table\]", "<table border=1 cellspacing=0 cellpadding=3 style='border: 1px solid black;'>")
|
||||
t = replacetext(t, "\[/table\]", "</td></tr></table>")
|
||||
t = replacetext(t, "\[grid\]", "<table>")
|
||||
t = replacetext(t, "\[/grid\]", "</td></tr></table>")
|
||||
t = replacetext(t, "\[row\]", "</td><tr>")
|
||||
t = replacetext(t, "\[tr\]", "</td><tr>")
|
||||
t = replacetext(t, "\[td\]", "<td>")
|
||||
t = replacetext(t, "\[cell\]", "<td>")
|
||||
t = replacetext(t, "\[logo\]", "<img src = ntlogo.png>")
|
||||
return t
|
||||
|
||||
|
||||
/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)
|
||||
var/datum/computer_file/data/file
|
||||
|
||||
if(!PRG.computer || !PRG.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)
|
||||
if(!istype(file))
|
||||
data["error"] = "I/O ERROR: Unable to open file."
|
||||
else
|
||||
data["filedata"] = PRG.parse_tags(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(
|
||||
"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
|
||||
|
||||
ui = nanomanager.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()
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/datum/computer_file/program/newsbrowser
|
||||
filename = "newsbrowser"
|
||||
filedesc = "NTNet/ExoNet News Browser"
|
||||
extended_desc = "This program may be used to view and download news articles from the network."
|
||||
program_icon_state = "generic"
|
||||
size = 8
|
||||
requires_ntnet = 1
|
||||
available_on_ntnet = 1
|
||||
|
||||
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/message = ""
|
||||
|
||||
/datum/computer_file/program/newsbrowser/process_tick()
|
||||
if(!downloading)
|
||||
return
|
||||
download_netspeed = 0
|
||||
// Speed defines are found in misc.dm
|
||||
switch(ntnet_status)
|
||||
if(1)
|
||||
download_netspeed = NTNETSPEED_LOWSIGNAL
|
||||
if(2)
|
||||
download_netspeed = NTNETSPEED_HIGHSIGNAL
|
||||
if(3)
|
||||
download_netspeed = NTNETSPEED_ETHERNET
|
||||
download_progress += download_netspeed
|
||||
if(download_progress >= loaded_article.size)
|
||||
downloading = 0
|
||||
requires_ntnet = 0 // Turn off NTNet requirement as we already loaded the file into local memory.
|
||||
nanomanager.update_uis(NM)
|
||||
|
||||
/datum/computer_file/program/newsbrowser/kill_program()
|
||||
..()
|
||||
requires_ntnet = 1
|
||||
loaded_article = null
|
||||
download_progress = 0
|
||||
downloading = 0
|
||||
|
||||
/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(.)
|
||||
nanomanager.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["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
|
||||
else // Viewing list of articles
|
||||
var/list/all_articles[0]
|
||||
for(var/datum/computer_file/data/news_article/F in ntnet_global.available_news)
|
||||
all_articles.Add(list(list(
|
||||
"name" = F.filename,
|
||||
"size" = F.size,
|
||||
"uid" = F.uid
|
||||
)))
|
||||
data["all_articles"] = all_articles
|
||||
|
||||
ui = nanomanager.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, 700, state = state)
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
/datum/computer_file/program/ntnetdownload
|
||||
filename = "ntndownloader"
|
||||
filedesc = "NTNet Software Download Tool"
|
||||
program_icon_state = "generic"
|
||||
extended_desc = "This program allows downloads of software from official NT repositories"
|
||||
unsendable = 1
|
||||
undeletable = 1
|
||||
size = 4
|
||||
requires_ntnet = 1
|
||||
requires_ntnet_feature = NTNET_SOFTWAREDOWNLOAD
|
||||
available_on_ntnet = 0
|
||||
nanomodule_path = /datum/nano_module/program/computer_ntnetdownload/
|
||||
ui_header = "downloader_finished.gif"
|
||||
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 = ""
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/proc/begin_file_download(var/filename)
|
||||
if(downloaded_file)
|
||||
return 0
|
||||
|
||||
var/datum/computer_file/program/PRG = ntnet_global.find_ntnet_file_by_name(filename)
|
||||
|
||||
if(!PRG || !istype(PRG))
|
||||
return 0
|
||||
|
||||
// Attempting to download antag only program, but without having emagged computer. No.
|
||||
if(PRG.available_on_syndinet && !computer_emagged)
|
||||
return 0
|
||||
|
||||
if(!computer || !computer.hard_drive || !computer.hard_drive.try_store_file(PRG))
|
||||
return 0
|
||||
|
||||
ui_header = "downloader_running.gif"
|
||||
|
||||
if(PRG in ntnet_global.available_station_software)
|
||||
generate_network_log("Began downloading file [PRG.filename].[PRG.filetype] from NTNet Software Repository.")
|
||||
hacked_download = 0
|
||||
else if(PRG in ntnet_global.available_antag_software)
|
||||
generate_network_log("Began downloading file **ENCRYPTED**.[PRG.filetype] from unspecified server.")
|
||||
hacked_download = 1
|
||||
else
|
||||
generate_network_log("Began downloading file [PRG.filename].[PRG.filetype] from unspecified server.")
|
||||
hacked_download = 0
|
||||
|
||||
downloaded_file = PRG.clone()
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/proc/abort_file_download()
|
||||
if(!downloaded_file)
|
||||
return
|
||||
generate_network_log("Aborted download of file [hacked_download ? "**ENCRYPTED**" : downloaded_file.filename].[downloaded_file.filetype].")
|
||||
downloaded_file = null
|
||||
download_completion = 0
|
||||
ui_header = "downloader_finished.gif"
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/proc/complete_file_download()
|
||||
if(!downloaded_file)
|
||||
return
|
||||
generate_network_log("Completed download of file [hacked_download ? "**ENCRYPTED**" : downloaded_file.filename].[downloaded_file.filetype].")
|
||||
if(!computer || !computer.hard_drive || !computer.hard_drive.store_file(downloaded_file))
|
||||
// The download failed
|
||||
downloaderror = "I/O ERROR - Unable to save file. Check whether you have enough free space on your hard drive and whether your hard drive is properly connected. If the issue persists contact your system administrator for assistance."
|
||||
downloaded_file = null
|
||||
download_completion = 0
|
||||
ui_header = "downloader_finished.gif"
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/process_tick()
|
||||
if(!downloaded_file)
|
||||
return
|
||||
if(download_completion >= downloaded_file.size)
|
||||
complete_file_download()
|
||||
// Download speed according to connectivity state. NTNet server is assumed to be on unlimited speed so we're limited by our local connectivity
|
||||
download_netspeed = 0
|
||||
// Speed defines are found in misc.dm
|
||||
switch(ntnet_status)
|
||||
if(1)
|
||||
download_netspeed = NTNETSPEED_LOWSIGNAL
|
||||
if(2)
|
||||
download_netspeed = NTNETSPEED_HIGHSIGNAL
|
||||
if(3)
|
||||
download_netspeed = NTNETSPEED_ETHERNET
|
||||
download_completion += download_netspeed
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
if(href_list["PRG_downloadfile"])
|
||||
if(!downloaded_file)
|
||||
begin_file_download(href_list["PRG_downloadfile"])
|
||||
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
|
||||
|
||||
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()
|
||||
|
||||
// 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
|
||||
else 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)
|
||||
else // No download running, pick file.
|
||||
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))
|
||||
continue
|
||||
all_entries.Add(list(list(
|
||||
"filename" = P.filename,
|
||||
"filedesc" = P.filedesc,
|
||||
"fileinfo" = P.extended_desc,
|
||||
"size" = P.size
|
||||
)))
|
||||
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,
|
||||
"size" = P.size
|
||||
)))
|
||||
data["hacked_programs"] = hacked_programs
|
||||
|
||||
data["downloadable_programs"] = all_entries
|
||||
ui = nanomanager.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)
|
||||
@@ -0,0 +1,89 @@
|
||||
/datum/computer_file/program/ntnetmonitor
|
||||
filename = "ntmonitor"
|
||||
filedesc = "NTNet Diagnostics and Monitoring"
|
||||
program_icon_state = "comm_monitor"
|
||||
extended_desc = "This program monitors stationwide NTNet network, provides access to logging systems, and allows for configuration changes"
|
||||
size = 12
|
||||
requires_ntnet = 1
|
||||
required_access = access_network
|
||||
available_on_ntnet = 1
|
||||
nanomodule_path = /datum/nano_module/computer_ntnetmonitor/
|
||||
|
||||
/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)
|
||||
if(!ntnet_global)
|
||||
return
|
||||
var/list/data = host.initial_data()
|
||||
|
||||
data["ntnetstatus"] = ntnet_global.check_function()
|
||||
data["ntnetrelays"] = ntnet_global.relays.len
|
||||
data["idsstatus"] = ntnet_global.intrusion_detection_enabled
|
||||
data["idsalarm"] = ntnet_global.intrusion_detection_alarm
|
||||
|
||||
data["config_softwaredownload"] = ntnet_global.setting_softwaredownload
|
||||
data["config_peertopeer"] = ntnet_global.setting_peertopeer
|
||||
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
|
||||
|
||||
|
||||
ui = nanomanager.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)
|
||||
|
||||
/datum/nano_module/computer_ntnetmonitor/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
if(href_list["resetIDS"])
|
||||
. = 1
|
||||
if(ntnet_global)
|
||||
ntnet_global.resetIDS()
|
||||
return 1
|
||||
if(href_list["toggleIDS"])
|
||||
. = 1
|
||||
if(ntnet_global)
|
||||
ntnet_global.toggleIDS()
|
||||
return 1
|
||||
if(href_list["toggleWireless"])
|
||||
. = 1
|
||||
if(!ntnet_global)
|
||||
return 1
|
||||
|
||||
// NTNet is disabled. Enabling can be done without user prompt
|
||||
if(ntnet_global.setting_disabled)
|
||||
ntnet_global.setting_disabled = 0
|
||||
return 1
|
||||
|
||||
// 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)
|
||||
var/mob/user = usr
|
||||
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"])
|
||||
. = 1
|
||||
if(ntnet_global)
|
||||
ntnet_global.purge_logs()
|
||||
if(href_list["updatemaxlogs"])
|
||||
. = 1
|
||||
var/mob/user = usr
|
||||
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)
|
||||
if(href_list["toggle_function"])
|
||||
. = 1
|
||||
if(!ntnet_global)
|
||||
return 1
|
||||
ntnet_global.toggle_function(href_list["toggle_function"])
|
||||
@@ -0,0 +1,230 @@
|
||||
/datum/computer_file/program/chatclient
|
||||
filename = "ntnrc_client"
|
||||
filedesc = "NTNet Relay Chat Client"
|
||||
program_icon_state = "command"
|
||||
extended_desc = "This program allows communication over NTNRC network"
|
||||
size = 8
|
||||
requires_ntnet = 1
|
||||
requires_ntnet_feature = NTNET_COMMUNICATION
|
||||
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
|
||||
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)
|
||||
|
||||
/datum/computer_file/program/chatclient/New()
|
||||
username = "DefaultUser[rand(100, 999)]"
|
||||
|
||||
/datum/computer_file/program/chatclient/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
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: "))
|
||||
if(!message || !channel)
|
||||
return
|
||||
channel.add_message(message, username)
|
||||
|
||||
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
|
||||
|
||||
if(!C)
|
||||
return 1
|
||||
|
||||
if(netadmin_mode)
|
||||
channel = C // Bypasses normal leave/join and passwords. Technically makes the user invisible to others.
|
||||
return 1
|
||||
|
||||
if(C.password)
|
||||
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 = sanitize(input(user,"Enter channel name or leave blank to cancel:"))
|
||||
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:"))
|
||||
if(!newname)
|
||||
return 1
|
||||
if(channel)
|
||||
channel.add_status_message("[username] is now known as [newname].")
|
||||
username = newname
|
||||
|
||||
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:"))
|
||||
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/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
|
||||
|
||||
/datum/computer_file/program/chatclient/process_tick()
|
||||
..()
|
||||
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
|
||||
else
|
||||
last_message = null
|
||||
return 1
|
||||
if(channel && channel.messages && 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)
|
||||
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
|
||||
|
||||
var/list/data = list()
|
||||
if(program)
|
||||
data = program.get_header_data()
|
||||
|
||||
var/datum/computer_file/program/chatclient/C = program
|
||||
if(!istype(C))
|
||||
return
|
||||
|
||||
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
|
||||
)))
|
||||
data["messages"] = messages
|
||||
var/list/clients[0]
|
||||
for(var/datum/computer_file/program/chatclient/cl in C.channel.clients)
|
||||
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["all_channels"] = all_channels
|
||||
|
||||
ui = nanomanager.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)
|
||||
@@ -0,0 +1,194 @@
|
||||
var/global/nttransfer_uid = 0
|
||||
|
||||
/datum/computer_file/program/nttransfer
|
||||
filename = "nttransfer"
|
||||
filedesc = "NTNet P2P Transfer Client"
|
||||
extended_desc = "This program allows for simple file transfer via direct peer to peer connection."
|
||||
program_icon_state = "comm_logs"
|
||||
size = 7
|
||||
requires_ntnet = 1
|
||||
requires_ntnet_feature = NTNET_PEERTOPEER
|
||||
network_destination = "other device via P2P tunnel"
|
||||
available_on_ntnet = 1
|
||||
nanomodule_path = /datum/nano_module/program/computer_nttransfer/
|
||||
|
||||
var/error = "" // Error screen
|
||||
var/server_password = "" // Optional password to download the file.
|
||||
var/datum/computer_file/provided_file = null // File which is provided to clients.
|
||||
var/datum/computer_file/downloaded_file = null // File which is being downloaded
|
||||
var/list/connected_clients = list() // List of connected clients.
|
||||
var/datum/computer_file/program/nttransfer/remote // Client var, specifies who are we downloading from.
|
||||
var/download_completion = 0 // Download progress in GQ
|
||||
var/download_netspeed = 0 // Our connectivity speed in GQ/s
|
||||
var/actual_netspeed = 0 // Displayed in the UI, this is the actual transfer speed.
|
||||
var/unique_token // UID of this program
|
||||
var/upload_menu = 0 // Whether we show the program list and upload menu
|
||||
|
||||
/datum/computer_file/program/nttransfer/New()
|
||||
unique_token = nttransfer_uid
|
||||
nttransfer_uid++
|
||||
..()
|
||||
|
||||
/datum/computer_file/program/nttransfer/process_tick()
|
||||
// Server mode
|
||||
update_netspeed()
|
||||
if(provided_file)
|
||||
for(var/datum/computer_file/program/nttransfer/C in connected_clients)
|
||||
// Transfer speed is limited by device which uses slower connectivity.
|
||||
// We can have multiple clients downloading at same time, but let's assume we use some sort of multicast transfer
|
||||
// so they can all run on same speed.
|
||||
C.actual_netspeed = min(C.download_netspeed, download_netspeed)
|
||||
C.download_completion += C.actual_netspeed
|
||||
if(C.download_completion >= provided_file.size)
|
||||
C.finish_download()
|
||||
else if(downloaded_file) // Client mode
|
||||
if(!remote)
|
||||
crash_download("Connection to remote server lost")
|
||||
|
||||
/datum/computer_file/program/nttransfer/kill_program(var/forced = 0)
|
||||
if(downloaded_file) // Client mode, clean up variables for next use
|
||||
finalize_download()
|
||||
|
||||
if(provided_file) // Server mode, disconnect all clients
|
||||
for(var/datum/computer_file/program/nttransfer/P in connected_clients)
|
||||
P.crash_download("Connection terminated by remote server")
|
||||
downloaded_file = null
|
||||
..(forced)
|
||||
|
||||
|
||||
|
||||
/datum/computer_file/program/nttransfer/proc/update_netspeed()
|
||||
download_netspeed = 0
|
||||
switch(ntnet_status)
|
||||
if(1)
|
||||
download_netspeed = NTNETSPEED_LOWSIGNAL
|
||||
if(2)
|
||||
download_netspeed = NTNETSPEED_HIGHSIGNAL
|
||||
if(3)
|
||||
download_netspeed = NTNETSPEED_ETHERNET
|
||||
|
||||
// Finishes download and attempts to store the file on HDD
|
||||
/datum/computer_file/program/nttransfer/proc/finish_download()
|
||||
if(!computer || !computer.hard_drive || !computer.hard_drive.store_file(downloaded_file))
|
||||
error = "I/O Error: Unable to save file. Check your hard drive and try again."
|
||||
finalize_download()
|
||||
|
||||
// Crashes the download and displays specific error message
|
||||
/datum/computer_file/program/nttransfer/proc/crash_download(var/message)
|
||||
error = message ? message : "An unknown error has occured during download"
|
||||
finalize_download()
|
||||
|
||||
// Cleans up variables for next use
|
||||
/datum/computer_file/program/nttransfer/proc/finalize_download()
|
||||
if(remote)
|
||||
remote.connected_clients.Remove(src)
|
||||
downloaded_file = null
|
||||
remote = null
|
||||
download_completion = 0
|
||||
|
||||
|
||||
/datum/nano_module/program/computer_nttransfer
|
||||
name = "NTNet P2P Transfer Client"
|
||||
|
||||
/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)
|
||||
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]
|
||||
for(var/datum/computer_file/program/nttransfer/P in ntnet_global.fileservers)
|
||||
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
|
||||
)))
|
||||
data["servers"] = all_servers
|
||||
|
||||
ui = nanomanager.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)
|
||||
|
||||
/datum/computer_file/program/nttransfer/Topic(href, href_list)
|
||||
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
|
||||
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."
|
||||
return
|
||||
provided_file = F
|
||||
ntnet_global.fileservers.Add(src)
|
||||
return
|
||||
error = "I/O Error: Unable to locate file on hard drive."
|
||||
return 1
|
||||
if(href_list["PRG_uploadmenu"])
|
||||
upload_menu = 1
|
||||
return 0
|
||||
Reference in New Issue
Block a user