Makes the traffic control console less terrible to use (#22478)

* AHAHAHAHAHAHAHAHAHAHAHAHAHA

* VESTIGIAL CODE THAT MUST BE DESTROYED

* E

* FIXES STUFF

* Update NtslEditor.js

* USELESS VARIABLE THAT DOES NOTHING BUT THE LINTER WANTS IT

* IS THIS WHAT IT WANTS

* MADE THE SCROLLING NOT TERRIBLY CODED

* YES

* NOT USED

* Update traffic_control.dm

* SCROLL BAR
This commit is contained in:
SapphicOverload
2024-08-07 16:12:59 -04:00
committed by GitHub
parent 4358185ed1
commit c2fc857532
5 changed files with 356 additions and 632 deletions

View File

@@ -359,99 +359,3 @@ window "statwindow"
background-color = none
is-visible = false
saved-params = ""
window "Telecomms IDE"
elem "Telecomms IDE"
type = MAIN
pos = 281,0
size = 569x582
anchor1 = none
anchor2 = none
text-color = #eeeeee
background-color = #222222
is-visible = false
saved-params = "pos;size;is-minimized;is-maximized"
title = "TCS IDE"
statusbar = false
on-close = "exittcs"
elem "button5"
type = BUTTON
pos = 209,464
size = 70x20
anchor1 = 37,80
anchor2 = 49,83
text-color = #eeeeee
background-color = #555555
saved-params = "is-checked"
text = "Clear Memory"
command = "tcsclearmem"
elem "button4"
type = BUTTON
pos = 157,464
size = 52x20
anchor1 = 28,80
anchor2 = 37,83
text-color = #eeeeee
background-color = #555555
saved-params = "is-checked"
text = "Revert"
command = "tcsrevert"
elem "button3"
type = BUTTON
pos = 105,464
size = 52x20
anchor1 = 18,80
anchor2 = 28,83
text-color = #eeeeee
background-color = #555555
saved-params = "is-checked"
text = "Execute"
command = "tcsrun"
elem "tcserror"
type = OUTPUT
pos = 0,488
size = 566x94
anchor1 = 0,84
anchor2 = 99,100
font-family = "sans-serif"
font-size = 9
text-color = #eeeeee
background-color = #333334
saved-params = "max-lines"
elem "button2"
type = BUTTON
pos = 53,464
size = 52x20
anchor1 = 9,80
anchor2 = 18,83
text-color = #eeeeee
background-color = #555555
saved-params = "is-checked"
text = "Compile"
command = "tcscompile"
elem "button1"
type = BUTTON
pos = 0,464
size = 53x20
anchor1 = 0,80
anchor2 = 9,83
text-color = #eeeeee
background-color = #555555
saved-params = "is-checked"
text = "Save"
command = "tcssave"
elem "tcscode"
type = INPUT
pos = 0,0
size = 569x464
anchor1 = 0,0
anchor2 = 100,80
font-family = "Courier"
font-size = 10
text-color = #eeeeee
background-color = #333334
saved-params = ""
command = "cancel"
multi-line = true
no-command = true

View File

@@ -0,0 +1,204 @@
import { useBackend, useLocalState } from '../backend';
import { Box, Button, Divider, Input, Tabs, TextArea, Section, Stack } from '../components';
import { Window } from '../layouts';
export const NtslEditor = (props, context) => {
// Make sure we don't start larger than 50%/80% of screen width/height.
const winWidth = Math.min(900, window.screen.availWidth * 0.5);
const winHeight = Math.min(600, window.screen.availHeight * 0.8);
return (
<Window
title="Traffic Control Console"
width={winWidth}
height={winHeight}
>
<Window.Content>
<Stack fill>
<Stack.Item width={winWidth-240}>
<ScriptEditor />
</Stack.Item>
<Stack.Item>
<MainMenu />
</Stack.Item>
</Stack>
</Window.Content>
</Window>
);
};
const ScriptEditor = (props, context) => {
const { act, data } = useBackend(context);
const { stored_code, user_name } = data;
return (
<Box width="100%" height="100%">
{user_name ?
<TextArea
noborder
scrollbar
value={stored_code}
width="100%"
height="100%"
onChange={(e, value) => act('save_code', {
saved_code: value,
})}
onEnter={(e, value) => act('save_code', {
saved_code: value+"\n",
})}
/> :
<Section width="100%" height="100%">
{stored_code}
</Section>
}
</Box>
);
};
const MainMenu = (props, context) => {
const { act, data } = useBackend(context);
const { emagged, user_name } = data;
const [tabIndex, setTabIndex] = useLocalState(context, "tab-index", 1);
return (
<>
<Section width="240px">
{user_name ?
<Stack>
<Stack.Item>
<Button
icon="power-off"
color="purple"
content="Log Out"
disabled={emagged}
onClick={() => act('log_out')}
/>
</Stack.Item>
<Stack.Item verticalAlign="middle">
{user_name}
</Stack.Item>
</Stack> : <Button
icon="power-off"
color="green"
content="Log In"
onClick={() => act('log_in')}
/>}
</Section>
{user_name &&
<Section width="240px" height="90%" fill>
<Tabs>
<Tabs.Tab
selected={tabIndex === 1}
onClick={() => setTabIndex(1)}>
Compile
</Tabs.Tab>
<Tabs.Tab
selected={tabIndex === 2}
onClick={() => setTabIndex(2)}>
Network
</Tabs.Tab>
<Tabs.Tab
selected={tabIndex === 3}
onClick={() => setTabIndex(3)}>
Logs
</Tabs.Tab>
</Tabs>
{ tabIndex === 1 && <CompilerOutput /> }
{ tabIndex === 2 && <ServerList /> }
{ tabIndex === 3 && <LogViewer /> }
</Section>
}
</>
);
};
const CompilerOutput = (props, context) => {
const { act, data } = useBackend(context);
const { compiler_output } = data;
return (
<>
<Box>
<Button
mb={1}
icon="save"
content='Compile & Run'
onClick={() => act('compile_code')}
/>
</Box>
<Divider />
<Section fill scrollable height="87.2%">
{compiler_output ? compiler_output.map((error_message, index) => (
<Box key={index}>
{error_message}
</Box>
)) : "No compile errors."}
</Section>
</>
);
};
const ServerList = (props, context) => {
const { act, data } = useBackend(context);
const { network, server_data } = data;
return (
<>
<Box>
<Button
mb={1}
icon="sync"
content='Reconnect to Network'
onClick={() => act('refresh_servers')}
/>
</Box>
<Box>
<Input
mb={1}
value={network}
onChange={(e, value) => act('set_network', {
new_network: value,
})}
/>
</Box>
<Divider />
<Section fill scrollable height="82%">
{server_data.map((nt_server, index) => (
<Box key={index}>
<Button.Checkbox
mb={0.5}
checked={nt_server.run_code}
content={nt_server.server_name}
onClick={() => act('toggle_code_execution', {
selected_server: nt_server.server,
})}
/>
</Box>
))}
</Section>
</>
);
};
const LogViewer = (props, context) => {
const { act, data } = useBackend(context);
const { access_log } = data;
// This is terrible but nothing else will work
return (
<>
<Box>
<Button
mb={1}
icon='trash'
content='Clear Logs'
onClick={() => act('clear_logs')}
/>
</Box>
<Divider />
<Section fill scrollable height="87.2%">
{access_log ? access_log.map((access_message, index) => (
<Box key={index}>
{access_message}
</Box>
)) : "Access log could not be found. Please contact an administrator."}
</Section>
</>
);
};

View File

@@ -4544,7 +4544,6 @@
#include "yogstation\code\modules\research\techweb\all_nodes.dm"
#include "yogstation\code\modules\ruins\ivymen_den.dm"
#include "yogstation\code\modules\ruins\lavaland_ruin_code.dm"
#include "yogstation\code\modules\scripting\client_verbs.dm"
#include "yogstation\code\modules\scripting\Errors.dm"
#include "yogstation\code\modules\scripting\Options.dm"
#include "yogstation\code\modules\scripting\stack.dm"

View File

@@ -1,23 +1,21 @@
/obj/machinery/computer/telecomms/traffic
name = "telecommunications traffic control console"
var/screen = 0 // the screen number:
var/emagged = FALSE
var/list/servers = list() // the servers located by the computer
var/mob/editingcode
var/mob/lasteditor
var/list/viewingcode = list()
var/obj/machinery/telecomms/server/SelectedServer
var/network = "NULL" // the network to probe
var/temp = "" // temporary feedback messages
var/storedcode = "" // code stored
var/obj/item/card/id/auth = null
/// The servers located by the computer
var/list/obj/machinery/telecomms/server/servers = list()
/// The network to probe
var/network = "NULL"
/// The current code being used
var/storedcode = ""
/// The ID currently inserted
var/obj/item/card/id/inserted_id
/// The name and job on the ID used to log in
var/user_name = ""
/// Logs for users logging in/out or compiling code
var/list/access_log = list()
var/process = 0
/// Output from compiling to the servers
var/list/compiler_output = list()
circuit = /obj/item/circuitboard/computer/telecomms/comm_traffic
req_access = list(ACCESS_TCOM_ADMIN)
@@ -28,305 +26,165 @@
GLOB.traffic_comps += src
if(mapload)
unlimited_range = TRUE
return INITIALIZE_HINT_LATELOAD
/obj/machinery/computer/telecomms/traffic/LateInitialize()
. = ..()
refresh_servers()
for(var/obj/machinery/telecomms/server/new_server in servers)
new_server.autoruncode = TRUE
/obj/machinery/computer/telecomms/traffic/Destroy()
GLOB.traffic_comps -= src
return ..()
/obj/machinery/computer/telecomms/traffic/proc/stop_editing()
if(editingcode)
if(editingcode.client)
winshow(editingcode, "Telecomms IDE", 0) // hide the window!
editingcode.unset_machine()
editingcode = null
/obj/machinery/computer/telecomms/traffic/proc/create_log(entry)
if(!user_name)
CRASH("[type] tried to create a log with no user_name!")
access_log += "\[[get_timestamp()]\] [user_name] [entry]"
/obj/machinery/computer/telecomms/traffic/process()
/obj/machinery/computer/telecomms/traffic/ui_interact(mob/user, datum/tgui/ui)
if(is_banned_from(user.ckey, "Network Admin"))
return "You are banned from using NTSL."
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "NtslEditor", name)
ui.open()
if(stat & (NOPOWER|BROKEN))
stop_editing()
/obj/machinery/computer/telecomms/traffic/ui_data(mob/user)
var/list/data = list()
var/list/server_data = list()
for(var/obj/machinery/telecomms/server/server in servers)
server_data.Add(list(list(
"server" = REF(server),
"server_id" = server.id,
"server_name" = server.name,
"run_code" = server.autoruncode,
)))
data["server_data"] = server_data
data["stored_code"] = storedcode
data["network"] = network
data["user_name"] = user_name
data["has_access"] = inserted_id
data["access_log"] = access_log.Copy()
data["compiler_output"] = compiler_output.Copy()
data["emagged"] = ((obj_flags & EMAGGED) > 0)
return data
/obj/machinery/computer/telecomms/traffic/ui_act(action, list/params)
. = ..()
if(.)
return
if(editingcode && editingcode.machine != src)
stop_editing()
return
if(!editingcode)
if(length(viewingcode) > 0)
editingcode = pick(viewingcode)
viewingcode.Remove(editingcode)
return
process = !process
if(!process)
return
// loop if there's someone manning the keyboard
if(!editingcode.client)
stop_editing()
return
// For the typer, the input is enabled. Buffer the typed text
storedcode = "[winget(editingcode, "tcscode", "text")]"
winset(editingcode, "tcscode", "is-disabled=false")
// If the player's not manning the keyboard anymore, adjust everything
if(!in_range(editingcode, src) && !issilicon(editingcode) || editingcode.machine != src)
winshow(editingcode, "Telecomms IDE", 0) // hide the window!
editingcode = null
return
// For other people viewing the typer type code, the input is disabled and they can only view the code
// (this is put in place so that there's not any magical shenanigans with 50 people inputting different code all at once)
if(length(viewingcode))
// This piece of code is very important - it escapes quotation marks so string aren't cut off by the input element
var/showcode = replacetext(storedcode, "\\\"", "\\\\\"")
showcode = replacetext(storedcode, "\"", "\\\"")
for(var/mob/M in viewingcode)
if( (M.machine == src && in_range(M, src) ) || issilicon(M))
winset(M, "tcscode", "is-disabled=true")
winset(M, "tcscode", "text=\"[showcode]\"")
switch(action)
if("refresh_servers")
refresh_servers()
return TRUE
if("toggle_code_execution")
var/obj/machinery/telecomms/server/selected_server = locate(params["selected_server"])
selected_server.autoruncode = !selected_server.autoruncode
return TRUE
if("save_code")
storedcode = params["saved_code"]
return TRUE
if("compile_code")
if(!user_name)
message_admins("[key_name_admin(usr)] attempted compiling NTSL without being logged in.") // tell admins that someone tried a javascript injection
return
for(var/obj/machinery/telecomms/server/server as anything in servers)
server.setcode(storedcode)
qdel(compiler_output)
compiler_output = compile_all(usr)
return TRUE
if("set_network")
if(!user_name)
return
network = params["new_network"]
return TRUE
if("log_in")
var/mob/usr_mob = usr
if(usr_mob.has_unlimited_silicon_privilege)
user_name = "System Administrator"
else if(check_access(inserted_id))
user_name = "[inserted_id?.registered_name] ([inserted_id?.assignment])"
else
viewingcode.Remove(M)
winshow(M, "Telecomms IDE", 0) // hide the windows
/obj/machinery/computer/telecomms/traffic/ui_interact(mob/user)
if(..())
return
user.set_machine(src)
var/dat = "<HTML><HEAD><meta charset='UTF-8'><TITLE>Telecommunication Traffic Control</TITLE></HEAD><BODY><center><b>Telecommunications Traffic Control</b></center>"
dat += "<br><b><font color='[(auth ? "green" : "red")]'>[(auth ? "AUTHED" : "NOT AUTHED")]:</font></b> <A href='?src=\ref[src];auth=1'>[(!auth ? "Insert ID" : auth)]</A><BR>"
dat += "<A href='?src=\ref[src];print=1'>View System Log</A><HR>"
if(issilicon(user) || auth)
switch(screen)
// --- Main Menu ---
if(0)
dat += "<br>[temp]<br>"
dat += "<br>Current Network: <a href='?src=\ref[src];network=1'>[network]</a><br>"
if(servers.len)
dat += "<br>Detected Telecommunication Servers:<ul>"
for(var/obj/machinery/telecomms/T in servers)
dat += "<li><a href='?src=\ref[src];viewserver=[T.id]'>\ref[T] [T.name]</a> ([T.id])</li>"
dat += "</ul>"
dat += "<br><a href='?src=\ref[src];operation=release'>\[Flush Buffer\]</a>"
else
dat += "<br>No servers detected. Scan for servers: <a href='?src=\ref[src];operation=scan'>\[Scan\]</a>"
// --- Viewing Server ---
if(1)
if(SelectedServer)
dat += "<br>[temp]<br>"
dat += "<center><a href='?src=\ref[src];operation=mainmenu'>\[Main Menu\]</a> <a href='?src=\ref[src];operation=refresh'>\[Refresh\]</a></center>"
dat += "<br>Current Network: [network]"
dat += "<br>Selected Server: [SelectedServer.id]"
dat += "<br><br>"
dat += "<br><a href='?src=\ref[src];operation=editcode'>\[Edit Code\]</a>"
dat += "<br>Signal Execution: "
if(SelectedServer.autoruncode)
dat += "<a href='?src=\ref[src];operation=togglerun'>ALWAYS</a>"
else
dat += "<a href='?src=\ref[src];operation=togglerun'>NEVER</a>"
else
screen = 0
var/obj/item/card/id/user_id = usr_mob.get_idcard(TRUE)
if(!check_access(user_id))
return
user_name = "[user_id?.registered_name] ([user_id?.assignment])"
create_log("has logged in.")
return TRUE
if("log_out")
if(obj_flags & EMAGGED)
return TRUE
create_log("has logged out.")
user_name = null
return TRUE
if("clear_logs")
if(!user_name)
message_admins("[key_name_admin(usr)] attempted clearing NTSL logs without being logged in.")
return
qdel(access_log)
access_log = list()
create_log("cleared access logs.")
return TRUE
dat += "</BODY></HTML>"
user << browse(dat, "window=traffic_control;size=575x400")
onclose(user, "server_control")
/obj/machinery/computer/telecomms/traffic/ui_close(mob/user)
return ..()
temp = ""
return
/obj/machinery/computer/telecomms/traffic/proc/refresh_servers()
qdel(servers)
servers = list()
for(var/obj/machinery/telecomms/server/new_server as anything in GLOB.tcomms_servers)
if(new_server.network != network)
continue
if(!unlimited_range && get_dist(src, new_server))
continue
servers.Add(new_server)
/obj/machinery/computer/telecomms/traffic/proc/create_log(entry, mob/user)
var/id = null
if(issilicon(user) || isAI(user))
id = "System Administrator"
else if(ispAI(user))
id = "[user.name] (pAI)"
else
if(auth)
id = "[auth.registered_name] ([auth.assignment])"
else
return
access_log += "\[[get_timestamp()]\] [id] [entry]"
/obj/machinery/computer/telecomms/traffic/proc/compile_all(mob/user)
if(is_banned_from(user.ckey, "Network Admin"))
return list("You are banned from using NTSL.")
if(!servers.len)
return list("No servers detected.")
for(var/obj/machinery/telecomms/server/server as anything in servers)
var/list/compile_errors = server.compile(user)
if(!compile_errors)
return list("A fatal error has occured. Please contact your local network adminstrator.")
if(istext(compile_errors))
return splittext(compile_errors, "\n")
var/list/text_list = list()
for(var/datum/scriptError/error in compile_errors)
text_list.Add(error.message)
if(text_list.len)
return text_list
create_log("compiled to all linked servers on [network].")
return list("Compiling finished.")
/obj/machinery/computer/telecomms/traffic/proc/print_logs()
. = "<HTML><HEAD><meta charset='UTF-8'></HEAD><BODY><center><h2>Traffic Control Telecomms System Log</h2></center><HR>"
for(var/entry in access_log)
. += entry + "<BR>"
. += "</BODY></HTML>"
return .
/obj/machinery/computer/telecomms/traffic/Topic(href, href_list)
if(..())
/obj/machinery/computer/telecomms/traffic/attackby(obj/item/item, mob/user, params)
if(istype(item, /obj/item/card/id) && check_access(item) && user.transferItemToLoc(item, src))
inserted_id = item
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
return
add_fingerprint(usr)
usr.set_machine(src)
if(href_list["auth"])
if(iscarbon(usr))
var/mob/living/carbon/C = usr
if(!auth)
var/obj/item/card/id/I = C.get_active_held_item()
if(istype(I))
if(check_access(I))
if(!C.transferItemToLoc(I, src))
return
auth = I
create_log("has logged in.", usr)
else
create_log("has logged out.", usr)
auth.loc = src.loc
C.put_in_hands(auth)
auth = null
updateUsrDialog()
return
if(href_list["print"])
usr << browse(print_logs(), "window=traffic_logs")
return
if(!auth && !issilicon(usr) && !emagged)
to_chat(usr, span_danger("ACCESS DENIED."))
return
if(href_list["viewserver"])
screen = 1
for(var/obj/machinery/telecomms/T in servers)
if(T.id == href_list["viewserver"])
SelectedServer = T
create_log("selected server [T.name]", usr)
break
if(href_list["operation"])
create_log("has performed action: [href_list["operation"]].", usr)
switch(href_list["operation"])
if("release")
servers = list()
screen = 0
if("mainmenu")
screen = 0
if("scan")
if(servers.len > 0)
temp = "<font color = #D70B00>- FAILED: CANNOT PROBE WHEN BUFFER FULL -</font color>"
else
if(unlimited_range)
for(var/obj/machinery/telecomms/server/T as anything in GLOB.tcomms_servers)
if(T.network == network)
servers.Add(T)
else
for(var/obj/machinery/telecomms/server/T in range(25, src))
if(T.network == network)
servers.Add(T)
if(!servers.len)
temp = "<font color = #D70B00>- FAILED: UNABLE TO LOCATE SERVERS IN \[[network]\] -</font color>"
else
temp = "<font color = #336699>- [servers.len] SERVERS PROBED & BUFFERED -</font color>"
screen = 0
if("editcode")
if(is_banned_from(usr.ckey, "Network Admin"))
to_chat(usr, span_warning("You are banned from using NTSL."))
return
if(editingcode == usr)
return
if(usr in viewingcode)
return
if(!editingcode)
lasteditor = usr
editingcode = usr
winshow(editingcode, "Telecomms IDE", 1) // show the IDE
winset(editingcode, "tcscode", "is-disabled=false")
winset(editingcode, "tcscode", "text=\"\"")
var/showcode = replacetext(storedcode, "\\\"", "\\\\\"")
showcode = replacetext(storedcode, "\"", "\\\"")
winset(editingcode, "tcscode", "text=\"[showcode]\"")
else
viewingcode.Add(usr)
winshow(usr, "Telecomms IDE", 1) // show the IDE
winset(usr, "tcscode", "is-disabled=true")
winset(editingcode, "tcscode", "text=\"\"")
var/showcode = replacetext(storedcode, "\"", "\\\"")
winset(usr, "tcscode", "text=\"[showcode]\"")
if("togglerun")
SelectedServer.autoruncode = !(SelectedServer.autoruncode)
if(href_list["network"])
var/newnet = stripped_input(usr, "Which network do you want to view?", "Comm Monitor", network)
if(newnet && canAccess(usr))
if(length(newnet) > 15)
temp = "<font color = #D70B00>- FAILED: NETWORK TAG STRING TOO LONG -</font color>"
else
network = newnet
screen = 0
servers = list()
temp = "<font color = #336699>- NEW NETWORK TAG SET IN ADDRESS \[[network]\] -</font color>"
create_log("has set the network to [network].", usr)
updateUsrDialog()
return
/obj/machinery/computer/telecomms/traffic/attackby(obj/O, mob/user, params)
src.updateUsrDialog()
if(istype(O, /obj/item/card/id) && check_access(O) && user.transferItemToLoc(O, src))
auth = O
create_log("has logged in.", usr)
else
..()
return ..()
/obj/machinery/computer/telecomms/traffic/emag_act(mob/user, obj/item/card/emag/emag_card)
if(emagged)
if(obj_flags & EMAGGED)
return FALSE
obj_flags |= EMAGGED
user_name = "System Administrator"
create_log("has logged in.")
playsound(src.loc, 'sound/effects/sparks4.ogg', 75, 1)
emagged = TRUE
to_chat(user, span_notice("You you disable the security protocols."))
/obj/machinery/computer/telecomms/traffic/proc/canAccess(mob/user)
if(issilicon(user) || in_range(user, src))
return 1
return 0
to_chat(user, span_notice("You bypass the console's security protocols."))
/obj/machinery/computer/telecomms/traffic/AltClick(mob/user)
. = ..()
if(!user.canUseTopic(src, BE_CLOSE))
return
if(iscarbon(user))
var/mob/living/carbon/C = user
if(!auth)
var/obj/item/card/id/I = C.get_active_held_item()
if(istype(I))
if(check_access(I))
if(!C.transferItemToLoc(I, src))
return
auth = I
create_log("has logged in.", user)
else
create_log("has logged out.", user)
auth.forceMove(drop_location())
C.put_in_hands(auth)
auth = null
updateUsrDialog()
return
var/mob/living/carbon/carbon_user = user
if(inserted_id)
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
inserted_id.forceMove(drop_location())
carbon_user.put_in_hands(inserted_id)
inserted_id = null

View File

@@ -1,241 +0,0 @@
/client/verb/tcssave()
set hidden = 1
if(is_banned_from(usr.ckey, "Network Admin"))
to_chat(usr, span_warning("You are banned from using NTSL."))
return
if(!mob.machine && !issilicon(mob))
src << output(null, "tcserror")
src << output("<font color = red>Failed to save: Unable to locate machine. (Back up your code before exiting the window!)</font color>", "tcserror")
if(!telecomms_check(mob))
src << output(null, "tcserror")
src << output("<font color = red>Failed to save: Unable to locate machine. (Back up your code before exiting the window!)</font color>", "tcserror")
return
var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine
if(Machine.editingcode != mob)
return
if(Machine.SelectedServer)
var/obj/machinery/telecomms/server/Server = Machine.SelectedServer
var/tcscode=winget(src, "tcscode", "text")
Server.setcode( tcscode ) // this actually saves the code from input to the server
src << output(null, "tcserror") // clear the errors
else
src << output(null, "tcserror")
src << output("<font color = red>Failed to save: Unable to locate server machine. (Back up your code before exiting the window!)</font color>", "tcserror")
/client/verb/tcscompile()
set hidden = 1
if(is_banned_from(usr.ckey, "Network Admin"))
to_chat(usr, span_warning("You are banned from using NTSL."))
return
if(!mob.machine && !issilicon(mob))
src << output(null, "tcserror")
src << output("<font color = red>Failed to compile: Unable to locate machine. (Back up your code before exiting the window!)</font color>", "tcserror")
return
if(!telecomms_check(mob))
src << output(null, "tcserror")
src << output("<font color = red>Failed to compile: Unable to locate machine. (Back up your code before exiting the window!)</font color>", "tcserror")
return
var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine
if(Machine.editingcode != mob)
return
if(!Machine.SelectedServer)
src << output(null, "tcserror")
src << output("<font color = red>Failed to compile: Unable to locate server machine. (Back up your code before exiting the window!)</font color>", "tcserror")
return
var/obj/machinery/telecomms/server/Server = Machine.SelectedServer
Server.setcode( winget(src, "tcscode", "text") ) // save code first
spawn(0)
// Output all the compile-time errors
src << output(null, "tcserror")
src << output("Compiling on [Server.name]...", "tcserror")
var/list/compileerrors = Server.compile(mob) // then compile the code! this can return a string or a list.
if(!telecomms_check(mob))
return
if(!compileerrors)
src << output("<b>NTSL.exe Error</b>", "tcserror")
src << output("<font color = red>\t><b>A fatal error has occured. Please contact your local network adminstrator.</b></font color>", "tcserror")
else if(istext(compileerrors))
src << output("<b>NTSL.exe Error</b>", "tcserror")
src << output("<font color = red>\t><b>[compileerrors]</b></font color>", "tcserror")
else if(length(compileerrors))
src << output("<b>Compile Errors</b>", "tcserror")
var/i = 1
for(var/datum/scriptError/e in compileerrors)
if(i) //. Bold the first one, since it's probably important
src << output("<font color = red>\t><b>[e.message]</b></font color>", "tcserror")
i = 0
else
src << output("<font color = red>\t>[e.message]</font color>", "tcserror")
src << output("([compileerrors.len] errors)", "tcserror")
// Output compile errors to all other people viewing the code too
for(var/mob/M in Machine.viewingcode)
if(M.client)
M << output(null, "tcserror")
M << output("<b>Compile Errors</b>", "tcserror")
i = 1 //. Still using var/i from above
for(var/datum/scriptError/e in compileerrors)
if(i)
M << output("<font color = red>\t><b>[e.message]</b></font color>", "tcserror")
i = 0
else
M << output("<font color = red>\t>[e.message]</font color>", "tcserror")
M << output("([compileerrors.len] errors)", "tcserror")
else // Returned a blank list, means no errors.
src << output("<font color = blue>TCS compilation successful!</font color>", "tcserror")
src << output("Time of compile: [gameTimestamp("hh:mm:ss")]","tcserror")
//. ^ To make it obvious that it's done a new compile
src << output("(0 errors)", "tcserror")
for(var/mob/M in Machine.viewingcode)
if(M.client)
M << output("<font color = blue>TCS compilation successful!</font color>", "tcserror")
M << output("Time of compile: [gameTimestamp("hh:mm:ss")]","tcserror")
M << output("(0 errors)", "tcserror")
if(Server.compile_warnings.len)
src << output("<b>Compile Warnings</b>", "tcserror")
for(var/datum/scriptError/e in Server.compile_warnings)
src << output("<font color = yellow>\t>[e.message]</font color>", "tcserror")
src << output("([Server.compile_warnings.len] warnings)", "tcserror")
for(var/fuck_you_for_making_me_do_this_altoids in Machine.viewingcode)
var/mob/M = fuck_you_for_making_me_do_this_altoids
if(M.client)
M << output("<b>Compile Warnings</b>", "tcserror")
for(var/datum/scriptError/e in Server.compile_warnings)
M << output("<font color = yellow>\t>[e.message]</font color>", "tcserror")
M << output("([Server.compile_warnings.len] warnings)", "tcserror")
/client/verb/tcsrun()
set hidden = 1
if(is_banned_from(usr.ckey, "Network Admin"))
to_chat(usr, span_warning("You are banned from using NTSL."))
return
if(!mob.machine && !issilicon(mob))
src << output(null, "tcserror")
src << output("<font color = red>Failed to run: Unable to locate machine. (Back up your code before exiting the window!)</font color>", "tcserror")
return
if(!telecomms_check(mob))
src << output(null, "tcserror")
src << output("<font color = red>Failed to run: Unable to locate machine. (Back up your code before exiting the window!)</font color>", "tcserror")
return
var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine
if(Machine.editingcode != mob)
return
if(!Machine.SelectedServer)
src << output(null, "tcserror")
src << output("<font color = red>Failed to run: Unable to locate server machine. (Back up your code before exiting the window!)</font color>", "tcserror")
return
var/obj/machinery/telecomms/server/Server = Machine.SelectedServer
var/datum/signal/signal = new()
signal.data["message"] = ""
if(Server.freq_listening.len > 0)
signal.frequency = Server.freq_listening[1]
else
signal.frequency = 1459
signal.data["name"] = ""
signal.data["job"] = ""
signal.data["reject"] = FALSE
signal.data["server"] = Server
Server.Compiler.Run(signal)
/client/verb/exittcs()
set hidden = 1
if(is_banned_from(usr.ckey, "Network Admin"))
to_chat(usr, span_warning("You are banned from using NTSL."))
return
if(!mob.machine && !issilicon(mob))
return
if(!telecomms_check(mob))
return
var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine
if(Machine.editingcode == mob)
Machine.storedcode = "[winget(mob, "tcscode", "text")]"
Machine.editingcode = null
else if(mob in Machine.viewingcode)
Machine.viewingcode.Remove(mob)
/client/verb/tcsrevert()
set hidden = 1
if(is_banned_from(usr.ckey, "Network Admin"))
to_chat(usr, span_warning("You are banned from using NTSL."))
return
if(!mob.machine && !issilicon(mob))
src << output(null, "tcserror")
src << output("<font color = red>Failed to revert: Unable to locate machine.</font color>", "tcserror")
return
if(!telecomms_check(mob))
src << output(null, "tcserror")
src << output("<font color = red>Failed to revert: Unable to locate machine.</font color>", "tcserror")
return
var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine
if(Machine.editingcode != mob)
return
if(!Machine.SelectedServer)
src << output(null, "tcserror")
src << output("<font color = red>Failed to revert: Unable to locate server machine.</font color>", "tcserror")
return
var/obj/machinery/telecomms/server/Server = Machine.SelectedServer
// Replace quotation marks with quotation macros for proper winset() compatibility
var/showcode = replacetext(Server.rawcode, "\\\"", "\\\\\"")
showcode = replacetext(showcode, "\"", "\\\"")
winset(mob, "tcscode", "text=\"[showcode]\"")
src << output(null, "tcserror") // clear the errors
/client/verb/tcsclearmem()
set hidden = 1
if(is_banned_from(usr.ckey, "Network Admin"))
to_chat(usr, span_warning("You are banned from using NTSL."))
return
if(!mob.machine && !issilicon(mob))
src << output(null, "tcserror")
src << output("<font color = red>Failed to clear memory: Unable to locate machine.</font color>", "tcserror")
return
if(!telecomms_check(mob))
src << output(null, "tcserror")
src << output("<font color = red>Failed to clear memory: Unable to locate machine.</font color>", "tcserror")
return
var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine
if(Machine.editingcode != mob)
return
if(!Machine.SelectedServer)
src << output(null, "tcserror")
src << output("<font color = red>Failed to clear memory: Unable to locate server machine.</font color>", "tcserror")
return
var/obj/machinery/telecomms/server/Server = Machine.SelectedServer
Server.memory = list() // clear the memory
// Show results
//// Write shitty code comments
src << output(null, "tcserror")
src << output("<font color = blue>Server memory cleared!</font color>", "tcserror")
for(var/mob/M in Machine.viewingcode)
if(M.client)
M << output("<font color = blue>Server memory cleared!</font color>", "tcserror")
/**
* Checks to see if 'mob_checking''s machine is a traffic control computer they can access.
*/
/proc/telecomms_check(mob/mob_checking)
if(!mob_checking)
return FALSE
if(!istype(mob_checking.machine, /obj/machinery/computer/telecomms/traffic))
return FALSE
if(!issilicon(mob_checking) && !in_range(mob_checking.machine, mob_checking))
return FALSE
return TRUE