NTSL2++ sucessor to NTSL2+ (#9321)

This drastcly is meant to rework DM and Daemon code to allow further expansion and replacement of custom engine with JavaScript language based engine.

Daemon PR - Aurorastation/ByondInterpretedLanguage#7

Forums topic for discussion - https://forums.aurorastation.org/topic/14570-ntsl2-and-its-future/

Superseeds #8817
This commit is contained in:
Karolis
2021-02-05 16:05:21 +02:00
committed by GitHub
parent 12bb01ad57
commit 607b0eeeb8
38 changed files with 762 additions and 557 deletions
+4 -23
View File
@@ -254,6 +254,7 @@
#include "code\controllers\subsystems\processing\fast_process.dm"
#include "code\controllers\subsystems\processing\modifiers.dm"
#include "code\controllers\subsystems\processing\nanoui.dm"
#include "code\controllers\subsystems\processing\ntsl2.dm"
#include "code\controllers\subsystems\processing\pipenet.dm"
#include "code\controllers\subsystems\processing\processing.dm"
#include "code\controllers\subsystems\processing\projectiles.dm"
@@ -2206,6 +2207,7 @@
#include "code\modules\modular_computers\file_system\data.dm"
#include "code\modules\modular_computers\file_system\news_article.dm"
#include "code\modules\modular_computers\file_system\program.dm"
#include "code\modules\modular_computers\file_system\script.dm"
#include "code\modules\modular_computers\file_system\program_events.dm"
#include "code\modules\modular_computers\file_system\programs\_program.dm"
#include "code\modules\modular_computers\file_system\programs\app_presets.dm"
@@ -2310,9 +2312,8 @@
#include "code\modules\nano\modules\power_monitor.dm"
#include "code\modules\nano\modules\rcon.dm"
#include "code\modules\ntsl2\guide.dm"
#include "code\modules\ntsl2\ntsl2.dm"
#include "code\modules\ntsl2\program.dm"
#include "code\modules\ntsl2\telecomms.dm"
#include "code\modules\ntsl2\ntsl2_program.dm"
#include "code\modules\ntsl2\ntsl2_types.dm"
#include "code\modules\orbit\orbit.dm"
#include "code\modules\organs\blood.dm"
#include "code\modules\organs\misc.dm"
@@ -2682,26 +2683,6 @@
#include "code\modules\research\xenoarchaeology\tools\tools_depthscanner.dm"
#include "code\modules\research\xenoarchaeology\tools\tools_locater.dm"
#include "code\modules\research\xenoarchaeology\tools\tools_pickaxe.dm"
#include "code\modules\scripting\Errors.dm"
#include "code\modules\scripting\IDE.dm"
#include "code\modules\scripting\Options.dm"
#include "code\modules\scripting\stack.dm"
#include "code\modules\scripting\AST\AST Nodes.dm"
#include "code\modules\scripting\AST\Blocks.dm"
#include "code\modules\scripting\AST\Statements.dm"
#include "code\modules\scripting\AST\Operators\Binary Operators.dm"
#include "code\modules\scripting\AST\Operators\Unary Operators.dm"
#include "code\modules\scripting\Implementations\_Logic.dm"
#include "code\modules\scripting\Implementations\Telecomms.dm"
#include "code\modules\scripting\Interpreter\Evaluation.dm"
#include "code\modules\scripting\Interpreter\Interaction.dm"
#include "code\modules\scripting\Interpreter\Interpreter.dm"
#include "code\modules\scripting\Interpreter\Scope.dm"
#include "code\modules\scripting\Parser\Expressions.dm"
#include "code\modules\scripting\Parser\Keywords.dm"
#include "code\modules\scripting\Parser\Parser.dm"
#include "code\modules\scripting\Scanner\Scanner.dm"
#include "code\modules\scripting\Scanner\Tokens.dm"
#include "code\modules\security levels\keycard authentication.dm"
#include "code\modules\security levels\security levels.dm"
#include "code\modules\shareddream\area.dm"
+23
View File
@@ -139,3 +139,26 @@
for (var/i = 0, i < iterations, i++)
. = (1/3) * (num/(.**2)+2*.)
// Old scripting functions used by all over place.
// Round down
/proc/n_floor(var/num)
if(isnum(num))
return round(num)
// Round up
/proc/n_ceil(var/num)
if(isnum(num))
return round(num)+1
// Round to nearest integer
/proc/n_round(var/num)
if(isnum(num))
if(num-round(num)<0.5)
return round(num)
return n_ceil(num)
// Returns 1 if N is inbetween Min and Max
/proc/n_inrange(var/num, var/min=-1, var/max=1)
if(isnum(num)&&isnum(min)&&isnum(max))
return ((min <= num) && (num <= max))
@@ -0,0 +1,153 @@
var/datum/controller/subsystem/processing/ntsl2/SSntsl2
/*
NTSL2 deamon management subsystem, responsible for handling events from deamon and it's connection state.
*/
/datum/controller/subsystem/processing/ntsl2
name = "NTSL2"
flags = 0
init_order = SS_INIT_MISC
// priority = SS_PRIORITY_PROCESSING
var/connected = FALSE
var/list/programs = list()
var/list/tasks = list()
var/current_task_id = 1
/datum/controller/subsystem/processing/ntsl2/New()
NEW_SS_GLOBAL(SSntsl2)
/datum/controller/subsystem/processing/ntsl2/Initialize(timeofday)
attempt_connect()
..()
/*
* Builds request object meant to do certain action. Returns FALSE (0) when there was an issue.
*/
/datum/controller/subsystem/processing/ntsl2/proc/build_request(var/command, var/list/arguments, var/method = RUSTG_HTTP_METHOD_GET)
if(config.ntsl_hostname && config.ntsl_port) // Requires config to be set.
var/url = "http://[config.ntsl_hostname]:[config.ntsl_port]/[command]"
var/body = ""
switch(method)
if(RUSTG_HTTP_METHOD_GET)
if(arguments)
url += "?" + list2params(arguments)
if(RUSTG_HTTP_METHOD_POST)
if(arguments)
body = json_encode(arguments)
return http_create_request(method, url, body)
return FALSE
/*
* Handles errors from response and returns final response data.
*/
/datum/controller/subsystem/processing/ntsl2/proc/handle_response(var/datum/http_response/response, var/command)
if (response.errored)
log_debug("NTSL2++: Proc error while performing command '[command]': [response.error]")
return FALSE
else if (response.status_code != 200)
log_debug("NTSL2++: HTTP error while performing command '[command]': [response.status_code]")
return FALSE
else
return response.body
/*
* Synchronous command to NTSL2 daemon. DO NOT USE for like almost anything.
*/
/datum/controller/subsystem/processing/ntsl2/proc/sync_send(var/command, var/list/arguments, var/method = RUSTG_HTTP_METHOD_GET)
var/datum/http_request/request = build_request(command, arguments, method)
if(istype(request))
request.begin_async()
UNTIL(request.is_complete())
return handle_response(request.into_response(), command)
/*
* ASynchronous command to NTSL2 daemon. Returns id of task, meant to track progress of this task.
*/
/datum/controller/subsystem/processing/ntsl2/proc/send_task(var/command, var/list/arguments, var/method = RUSTG_HTTP_METHOD_GET, var/program = null, var/callback = null)
if(!connected)
return FALSE
var/datum/http_request/request = build_request(command, arguments, method)
if(istype(request))
request.begin_async()
var/task = list(request = request, program = program, command = command, callback = callback)
var/task_id = "[current_task_id++]"
tasks[task_id] = task
return task_id
return FALSE
/datum/controller/subsystem/processing/ntsl2/proc/handle_task_completion(var/response, var/list/task)
var/command = task["command"]
var/datum/ntsl2_program/program = task["program"]
switch(command)
if("new_program")
if(!response)
crash_with("NTSL2++: Program initialization failed, but program was handed out.")
program.id = response
for(var/c in program.ready_tasks)
var/datum/callback/callback = c
if(istype(callback))
callback.InvokeAsync()
return
if("execute")
log_debug("NTSL2++ Daemon could not be connected to. Functionality will not be enabled.")
// Not sure what to do with successful / unsuccessful execution
return
if("computer/get_buffer")
if(response)
var/datum/ntsl2_program/computer/P = program
if(istype(P))
P.buffer = response
if(istype(P.buffer_update_callback))
P.buffer_update_callback.InvokeAsync()
return
var/datum/callback/cb = task["callback"]
if(istype(cb))
cb.InvokeAsync(response)
/datum/controller/subsystem/processing/ntsl2/proc/is_complete(var/task_id)
if(!task_id)
return TRUE
if(tasks[task_id])
return FALSE
return TRUE
/datum/controller/subsystem/processing/ntsl2/proc/attempt_connect()
var/res = sync_send("clear")
if(!res)
log_debug("NTSL2++ Daemon could not be connected to. Functionality will not be enabled.")
return FALSE
else
connected = TRUE
log_debug("NTSL2++ Daemon connected successfully.")
return TRUE
/datum/controller/subsystem/processing/ntsl2/proc/disconnect()
connected = FALSE
sync_send("clear")
// TODO: Kill programs
for(var/p in programs)
var/datum/ntsl2_program/Prog = p
Prog.kill()
// INTERNAL. DO NOT USE
/datum/controller/subsystem/processing/ntsl2/proc/handle_termination(var/program)
programs -= program
/datum/controller/subsystem/processing/ntsl2/fire(resumed)
for(var/task_id in tasks)
var/task = tasks[task_id]
var/datum/http_request/req = task["request"]
if(req.is_complete())
var/datum/http_response/res = req.into_response()
var/result = handle_response(res, task["command"])
handle_task_completion(result, task)
tasks -= task_id
. = ..()
+58
View File
@@ -30,3 +30,61 @@
/datum/signal/Destroy()
..()
return QDEL_HINT_IWILLGC
/datum/signal/proc/tcombroadcast(var/message, var/freq, var/source, var/job, var/verb, var/language)
var/datum/signal/newsign = new
var/obj/machinery/telecomms/server/S = data["server"]
var/obj/item/device/radio/hradio = S.server_radio
if(!hradio)
error("[src] has no radio.")
return
if((!message || message == "") && message != 0)
message = "*beep*"
if(!source)
source = "[html_encode(uppertext(S.id))]"
hradio = new // sets the hradio as a radio intercom
if(!freq)
freq = PUB_FREQ
if(findtext(num2text(freq), ".")) // if the frequency has been set as a decimal
freq *= 10 // shift the decimal one place
if(!job)
job = "?"
if(!language || language == "")
language = LANGUAGE_TCB
var/datum/language/L = all_languages[language]
if(!L || !(L.flags & TCOMSSIM))
L = all_languages[LANGUAGE_TCB]
newsign.data["mob"] = null
newsign.data["mobtype"] = /mob/living/carbon/human
newsign.data["name"] = source
newsign.data["realname"] = newsign.data["name"]
newsign.data["job"] = job
newsign.data["compression"] = 0
newsign.data["message"] = message
newsign.data["language"] = L
newsign.data["type"] = 2 // artificial broadcast
if(!isnum(freq))
freq = text2num(freq)
newsign.frequency = freq
var/datum/radio_frequency/connection = SSradio.return_frequency(freq)
newsign.data["connection"] = connection
newsign.data["radio"] = hradio
newsign.data["vmessage"] = message
newsign.data["vname"] = source
newsign.data["vmask"] = 0
newsign.data["level"] = list()
newsign.data["verb"] = verb
var/pass = S.relay_information(newsign, "/obj/machinery/telecomms/hub")
if(!pass)
S.relay_information(newsign, "/obj/machinery/telecomms/broadcaster") // send this simple message to broadcasters
@@ -486,7 +486,7 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list()
var/list/memory = list() // stored memory
var/rawcode = "" // the code to compile (raw text)
var/datum/TCS_Compiler/ntsl2/Compiler // the compiler that compiles and runs the code
var/datum/ntsl2_program/tcomm/Program // NTSL2++ datum responsible for script execution
var/autoruncode = 0 // 1 if the code is set to run every time a signal is picked up
var/encryption = "null" // encryption key: ie "password"
@@ -497,8 +497,7 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list()
/obj/machinery/telecomms/server/Initialize()
. = ..()
Compiler = new()
Compiler.Holder = src
Program = SSntsl2.new_program_tcomm(src)
server_radio = new()
/obj/machinery/telecomms/server/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from)
@@ -574,30 +573,39 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list()
var/identifier = num2text( rand(-1000,1000) + world.time )
log.name = "data packet ([md5(identifier)])"
if(Compiler && autoruncode)
Compiler.Run(signal) // execute the code
if(istype(Program))
Program.process_message(signal, CALLBACK(src, .proc/program_receive_information, signal))
else
finish_receive_information(signal)
var/can_send = relay_information(signal, "/obj/machinery/telecomms/hub")
if(!can_send)
relay_information(signal, "/obj/machinery/telecomms/broadcaster")
/obj/machinery/telecomms/server/proc/program_receive_information(datum/signal/signal)
Program.retrieve_messages(CALLBACK(src, .proc/finish_receive_information, signal))
/obj/machinery/telecomms/server/proc/finish_receive_information(datum/signal/signal)
var/can_send = relay_information(signal, "/obj/machinery/telecomms/hub")
if(!can_send)
relay_information(signal, "/obj/machinery/telecomms/broadcaster")
/obj/machinery/telecomms/server/machinery_process()
. = ..()
if(Compiler)
Compiler.update_code()
if(istype(Program))
Program.retrieve_messages()
/*
/obj/machinery/telecomms/server/proc/setcode(var/t)
if(t)
if(istext(t))
rawcode = t
*/
/*
/obj/machinery/telecomms/server/proc/compile()
if(Compiler)
var/er = Compiler.Compile(rawcode)
if(istype(Compiler.running_code))
Compiler.running_code.S = src
return er
*/
/obj/machinery/telecomms/server/proc/update_logs()
// start deleting the very first log entry
@@ -628,3 +636,13 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list()
var/name = "data packet (#)"
var/garbage_collector = 1 // if set to 0, will not be garbage collected
var/input_type = "Speech File"
// NTSL2++ code
+1 -1
View File
@@ -12,7 +12,7 @@
dat = {"
<html>
<head></head>
<head><style>body {overflow: hidden;}</style></head>
<body>
<iframe width='100%' height='97%' src="[config.wikiurl][sub_page]&printable=yes&remove_links=1" frameborder="0" id="main_frame"></iframe>
+4 -4
View File
@@ -3,11 +3,11 @@
set category = "Debug"
if(!check_rights(R_DEBUG)) return
if(ntsl2.connected)
if(SSntsl2.connected)
log_admin("[key_name(src)] disabled NTSL",admin_key=key_name(src))
message_admins("[key_name_admin(src)] disabled NTSL", 1)
ntsl2.disconnect()
SSntsl2.disconnect()
feedback_add_details("admin_verb","DNT") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
else
@@ -18,11 +18,11 @@
set category = "Debug"
if(!check_rights(R_DEBUG)) return
if(!ntsl2.connected)
if(!SSntsl2.connected)
log_admin("[key_name(src)] enabled NTSL",admin_key=key_name(src))
message_admins("[key_name_admin(src)] enabled NTSL", 1)
ntsl2.attempt_connect()
SSntsl2.attempt_connect()
feedback_add_details("admin_verb","CNT") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
else
@@ -143,7 +143,7 @@
var/data = get_pin_data(IC_INPUT, 1)
if (data != null)
var/chan = "[WP_ELECTRONICS][get_pin_data(IC_INPUT, 2) || "default"]"
ntsl2.receive_subspace(chan, data)
// ntsl2.receive_subspace(chan, data) TODO: KAROLIS Re add messaging
for (var/thing in GET_LISTENERS(chan))
var/listener/L = thing
var/obj/item/integrated_circuit/transfer/wireless/W = L.target
@@ -1,100 +1,142 @@
/datum/computer_file/program/ntsl2_interpreter
filename = "ntslinterpreter"
filedesc = "NTSL2+ Interpreter"
extended_desc = "This program is used to run NTSL2+ programs."
filedesc = "NTSL2++ Interpreter"
extended_desc = "This program is used to run NTSL2++ scripts."
program_icon_state = "generic"
usage_flags = PROGRAM_ALL
size = 8
requires_ntnet = TRUE
available_on_ntnet = TRUE
nanomodule_path = /datum/nano_module/program/computer_ntsl2_interpreter
var/datum/ntsl_program/running
var/datum/ntsl2_program/computer/running
var/is_running = FALSE
var/datum/computer_file/script/opened
color = LIGHT_COLOR_GREEN
/datum/computer_file/program/ntsl2_interpreter/process_tick()
if(istype(running))
running.cycle(30000)
..()
/datum/computer_file/program/ntsl2_interpreter/kill_program()
..()
. = ..()
if(istype(running))
running.kill()
running = null
opened = null
is_running = FALSE
/datum/computer_file/program/ntsl2_interpreter/run_program(mob/user)
. = ..()
if(.)
running = SSntsl2.new_program_computer(CALLBACK(src, .proc/buffer_callback_handler))
/datum/computer_file/program/ntsl2_interpreter/Topic(href, href_list)
if(..())
return TRUE
if(href_list["PRG_execfile"])
var/datum/vueui/ui = href_list["vueui"]
if(!istype(ui))
return
if(href_list["execute_file"])
. = TRUE
var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive
var/datum/computer_file/data/F = HDD.find_file_by_name(href_list["PRG_execfile"])
var/datum/computer_file/script/F = HDD.find_file_by_name(href_list["execute_file"])
if(istype(F))
var/oldtext = html_decode(F.stored_data)
oldtext = replacetext(oldtext, "\[editorbr\]", "\n")
running = ntsl2.new_program(oldtext, src, usr)
var/code = F.code
if(istype(running))
running.name = href_list["PRG_execfile"]
running.execute(code, usr)
is_running = TRUE
if(href_list["PRG_closefile"])
if(href_list["stop"])
. = TRUE
if(istype(running))
running.kill()
running = null
// Prepare for next execution
running = SSntsl2.new_program_computer(CALLBACK(src, .proc/buffer_callback_handler))
is_running = FALSE
if(href_list["PRG_topic"])
if(istype(running))
var/topc = href_list["PRG_topic"]
if(copytext(topc, 1, 2) == "?")
topc = copytext(topc, 2) + "?" + input("", "Enter Data")
running.topic(topc)
running.cycle(5000)
. = 1
if(href_list["PRG_refresh"])
if(href_list["edit_file"])
. = TRUE
var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive
var/datum/computer_file/script/F = HDD.find_file_by_name(href_list["edit_file"])
if(istype(F))
opened = F
if(href_list["close"])
. = TRUE
if(istype(opened))
opened.code = href_list["code"]
opened.calculate_size()
opened = null
if(href_list["new"])
. = TRUE
if(!opened)
var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive
opened = new()
opened.filename = sanitize(href_list["new"])
HDD.store_file(opened)
if(href_list["execute"])
. = TRUE
if(istype(opened))
opened.code = href_list["code"]
opened.calculate_size()
if(istype(running))
running.execute(opened.code, usr)
is_running = TRUE
if(href_list["terminal_topic"])
if(istype(running))
running.handle_topic(href_list["terminal_topic"])
. = TRUE
if(.)
SSnanoui.update_uis(NM)
SSvueui.check_uis_for_change(src)
return FALSE
/datum/nano_module/program/computer_ntsl2_interpreter
name = "NTSL2+ Interpreter"
/datum/nano_module/program/computer_ntsl2_interpreter/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/ntsl2_interpreter/PRG
if(program)
PRG = program
else
return
var/obj/item/computer_hardware/hard_drive/HDD
if(!PRG.computer || !PRG.computer.hard_drive)
data["error"] = "I/O ERROR: Unable to access hard drive."
else if(istype(PRG.running))
data["running"] = PRG.running.name
data["terminal"] = PRG.running.get_terminal()
else
HDD = PRG.computer.hard_drive
var/list/files[0]
for(var/datum/computer_file/F in HDD.stored_files)
if(F.filetype == "TXT" && !F.password)
files.Add(list(list(
"name" = F.filename,
"type" = F.filetype,
"size" = F.size,
"undeletable" = F.undeletable
)))
data["files"] = files
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
/datum/computer_file/program/ntsl2_interpreter/ui_interact(mob/user)
var/datum/vueui/ui = SSvueui.get_open_ui(user, src)
if (!ui)
ui = new(user, src, ui_key, "ntsl_interpreter.tmpl", "NTSL2+ Interpreter", 575, 700, state = state)
ui.auto_update_layout = 1
ui.set_initial_data(data)
ui.open()
ui = new /datum/vueui/modularcomputer(user, src, "mcomputer-ntsl-main", 600, 520, filedesc)
ui.open()
/datum/computer_file/program/ntsl2_interpreter/vueui_transfer(oldobj)
SSvueui.transfer_uis(oldobj, src, "mcomputer-ntsl-main", 600, 520, filedesc)
return TRUE
/datum/computer_file/program/ntsl2_interpreter/vueui_data_change(list/data, mob/user, datum/vueui/ui)
. = ..()
data = . || data || list("mode" = "list", "terminal" = "", "code" = "", "files" = list())
// Gather data for computer header
var/headerdata = get_header_data(data["_PC"])
if(headerdata)
data["_PC"] = headerdata
. = data
var/obj/item/computer_hardware/hard_drive/hdd = computer?.hard_drive
if(is_running && istype(running))
data["mode"] = "program"
data["terminal"] = running.buffer
. = data
else if (istype(opened))
VUEUI_SET_CHECK(data["mode"], "edit", ., data)
VUEUI_SET_CHECK(data["code"], opened.code, ., data)
else
VUEUI_SET_CHECK(data["mode"], "list", ., data)
data["files"] = list()
for(var/datum/computer_file/script/F in hdd?.stored_files)
if(F.filetype == "NTS" && !F.password)
data["files"] += list(list(
"name" = F.filename,
"type" = F.filetype,
"size" = F.size,
"undeletable" = F.undeletable
))
/datum/computer_file/program/ntsl2_interpreter/proc/buffer_callback_handler()
SSvueui.check_uis_for_change(src)
@@ -120,15 +120,21 @@
var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive
if(!HDD)
return TRUE
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
if(!F || !istype(F))
return TRUE
if(!computer.nano_printer)
error = "Missing Hardware: Your computer does not have required hardware to complete this operation."
return TRUE
if(!computer.nano_printer.print_text(F.stored_data))
error = "Hardware error: Printer was unable to print the file. It may be out of paper."
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
var/datum/computer_file/script/S = F
if(!F)
return TRUE
if(istype(F))
if(!computer.nano_printer.print_text(F.stored_data))
error = "Hardware error: Printer was unable to print the file. It may be out of paper."
return TRUE
else if(istype(S))
if(!computer.nano_printer.print_text(S.code))
error = "Hardware error: Printer was unable to print the file. It may be out of paper."
return TRUE
if(href_list["PRG_copytousb"])
. = TRUE
var/obj/item/computer_hardware/hard_drive/HDD = computer.hard_drive
@@ -226,14 +232,20 @@
data["error"] = PRG.error
if(PRG.open_file)
var/datum/computer_file/data/file
var/datum/computer_file/script/script
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)
script = file
if(!istype(file))
data["error"] = "I/O ERROR: Unable to open file."
if(!istype(script))
data["error"] = "I/O ERROR: Unable to open file."
else
data["scriptdata"] = html_encode(script.code)
data["filename"] = "[script.filename].[script.filetype]"
else
data["filedata"] = pencode2html(file.stored_data)
data["filename"] = "[file.filename].[file.filetype]"
@@ -0,0 +1,14 @@
// Computer file types script, used by NTSL2++
/datum/computer_file/script
var/code = "" // Stored data in string format.
filetype = "NTS"
var/block_size = 1500
/datum/computer_file/script/clone()
var/datum/computer_file/script/temp = ..()
temp.code = code
return temp
/datum/computer_file/script/proc/calculate_size()
size = max(1, round(length(code) / block_size))
+5 -158
View File
@@ -1,160 +1,7 @@
/obj/item/book/manual/ntsl2
name = "NTSL2+ For Dummies"
/obj/item/book/manual/wiki/ntsl2
name = "Guide to NTSL2++"
icon_state ="bookNTSL"
item_state ="book3"
author = "Brogrammer George"
title = "NTSL2+ For Dummies"
dat = {"<html>
<head>
<style>
h1 {font-size: 18px; margin: 15px 0px 5px;}
h2 {font-size: 15px; margin: 15px 0px 5px;}
h3 {font-size: 13px; margin: 15px 0px 5px;}
li {margin: 2px 0px 2px 15px;}
ul {margin: 5px; padding: 0px;}
ol {margin: 5px; padding: 0px 15px;}
body {font-size: 13px; font-family: Verdana;}
code {font-size: 8pt; line-spacing: 8pt; font-family: monospace; color: white; background-color:black;}
</style>
</head>
<body>
<h1>NTSL2+ For Dummies</h1>
So you want to write NTSL2+ huh?<br>
Well good luck to you. Over this short guide, we'll be detailing the setup and execution of basic programs, as well as documenting some more complicated functions.<br>
<h2>Installing</h2>
Firstly, if you're running this on a Telecommunications server, skip this step. It's already installed. Just, skip ahead to the Telecomms section...<br>
Secondly, if you're running this on a Telecommunications server and this book is your only guide, re-evaluate touching the Telecommunications server until later.<br><br>
<b>Step One:</b> Launch your computer or laptop.<br>
<b>Step Two:</b> Configure it for private use. Anything with access to the NT/Net Software Download Tool will technically work, but you're clearly new here, so don't push your luck.<br>
<b>Step Three:</b> Download <i>NTSL2+ Interpreter</i>. Patiently wait for the download. You've got time, right?<br>
<b>Step Four:</b> You're done. Either learn to program or download someone else's code.<br>
<h2>Running basic programs</h2>
When inside the Interpreter, you'll be given a list of programs you can run that are stored on your harddrive. <b>Programs on your USB stick have to be copied over first.</b><br>
Find a file you want to run, and click <b>EXEC</b>. This will cause the program to run.<br>
Programs have <B>Refresh</B> and <B>Exit</B> buttons. These buttons cause the program to either refresh its terminal, or exit respectively. This isn't rocket science, but you are reading this guide for dummies..<br>
Next is a big bold text that will be the title of the program. This isn't interactive, but makes it easier to tell your running programs apart.<br><br>
Finally, is the big black previously mentioned <b>Terminal</b>. All your program output and interaction happens here.<br>
Programs can output text here, in pretty patterns or whatever, but they can also output "Buttons". Parts of the terminal can be clicked to do things.<br>
This will either run something within the program, ask you for input, or do nothing.<br><br>
This encompasses the limitations of your interactions with the average program.<br>
<h2>Running complicated programs</h2>
You are not ready. Go back to Running basic programs.<br>
<h2>Writing your first program.</h2>
For this guide, I'll boldly assume you <b>already know some amount of programming.</b> If you can't program at all, avoid touching NTSL2+, this is not an entry level language. This is a bad language. Please. Run.<br><br>
If you're still boldly willing to learn this language, we can begin with the most basic of programs. <b>Hello world</b>.<br><br>
Firstly, create a new file in your File Browser. Call it whatever you want, but I recommend <B>Hello World</B>. Then open up the text editor.<br>
Your basic Hello World is the following:<br>
<code>print("Hello, World!")</code><br>
If you've programmed before, you already know what this does. If you haven't, see the start of this section, but for convenience...<br>
This program outputs the following text into the terminal when ran:<br>
<code>Hello, World!</code><br>
Simple enough. this demonstrates calling a function, <code>print</code>, and a raw string argument, <code>"Hello, World!"</code><br>
NTSL2+ has a habit of hating people, so make sure you fully understand this. Play with that raw string argument, understand it. Test the limitations of this simple program, don't be afraid to break it.<br><br><br><br><br>
If you spent long enough following my last instruction, you probably noticed something strange. <code>print "Hello, World!"</code> worked.<br>
If you're new here, that's probably perfectly logical. If you've been programming for a while, this might be really weird. (Unless you still write python 2...).<br>
This is because functions can <i>implicitly</i> be called with string or table <b>constructors</b> as an argument. This will make more sense later, hopefully.<br><br>
Next, is a <b>For loop</b>. Like wise, make a new program, or edit your old one. I'm not your boss.<br>
Fill it with:<br>
<code>for(i=0; i < 10; i++){<br>
&ensp;print `Number: \[i]`<br>
}</code><br>
This code prints all the numbers from 0 to 9, with the text "Number: " in front of it.<br>
Like last time, a lot of that code can still function if changed, play around with it.<br>
Different this time, however, is the use of backticks. <code>`Number: \[i]`</code><br>
These allow you to put <b>expressions</b> within your <b>string constructor</b>. Anything in square brackets, in this case, <code>\[i]</code> will be added to the string as the result of it's expression. So, the value of i.<br>
You can also escape these square brackets with a backslash, if you ever wanted to use them raw like that.<br><br>
Your last tutorial: User Input.<br>
I'm going to throw a program at you, it'll contain a lot of words you've not been taught yet. But you might be ready now. Just try it out, play with the code, see what you can change.<br>
The Code:<br>
<code>term.set_cursor(0,0)<br>
term.write("PROMPT")<br>
term.set_topic(0,0,#"PROMPT",1,"?prompt")<br>
term.set_cursor(0,1)<br>
<br>
when term.topic{<br>
&ensp;print(topic::sub(#"?prompt"))<br>
}</code><br>
Don't worry, Don't be scared, I'll step through this with you.<br>
<font size=4px>I'll be gentle.</font><br>
First thing that happens is <code>term.set_cursor(0,0)</code>. We've got another function call here, but with <code>term.</code> ahead it. This means that the function being run, set_cursor, is inside the table called term.<br>
The function itself moves the terminal cursor to position 0,0. You know how when stuff was printed it appeared on a new line? You can change where that starts with this.<br>
<code>term.write</code> is a lot like <code>print</code> but instead of writing a line, it just writes what you put in. Doesn't move the cursor down for next time.<br>
<code>term.set_topic</code> is the way you make <i>fun buttons!</i> The first two arguments are an x and y coordinate, just like what we did when we moved the cursor. The second two are width and height, they're the size of the button. Lastly, is the topic value. This is what we'll get back when <code>term.topic</code> is called. if this starts with a question mark like it does here, it'll ask for user input, and change how it's returned to compensate. so <code>?prompt</code> when pushed, and the text "hi" is entered, will return with <code>prompt?hi</code><br>
Confusing? Probably. Don't stress.<br>
We then move the cursor again, this time one line down.<br>
Next, is this "when", thing. When is used to <b>Hook to events</b>, with <code>term.topic</code> being the most commonly used event for standard computers.<br>
In this case, it means the stuff in the block is executed when term.topic is called, and it sets the <code>topic</code> value to whatever the topic stuff was, which was talked about in the term.set_topic section. That's where you get that. Not so confusing, was it?<br>
Now what about <code>topic::sub(#"?prompt")</code>? Once again, easier than it looks. Firstly, <code>::sub</code> Just like how . was used to get something in a table, :: can be used to too. But in this case, it makes whatever asked for it the first argument. So, this becomes <code>topic.sub(topic...</code>.<br>
"sub" itself is a string function, this can either be accessed from strings themselves, like above, or through literally asking the string table via string.sub. The string library has a whole bunch of fun things relating to text.<br>
This gets a substring from the input string, in the form of <code>sub(string, start, length)</code>. If the start and length aren't in the actual string, fuckery happens.<br>
<code>#"?prompt"</code> gets the length of the string "?prompt", which we use to only get the parts of the string we care about, because in this case, we don't need the actual topic string.<br><br>
This is all still probably a little confusing, but as always, just play with the code, edit it till it breaks, then fix it again, you'll get the hang of it.<br><br>
<h2>The Whole Syntax</h2>
Wow, you really got this far, huh? Bold. You uh, sure you don't want to go back..? Play with the examples some more? No..? Alright...<br><br>
<i>The rest of this page appears to be nothing but mad scribbles...</i><br><br>
<h2>Telecomms</h2>
So you've mastered the syntax, and the libraries, and you're finally ready for telecomms? Alright, don't say I didn't warn you.<br><br>
<h3>Receiving</h3>
To receive messages, hook into the <code>tcomm.onmessage</code> event. This gives you access to:<br>
<ul>
<li><b>content</b>: The message sent; converted to text for convenience.</li>
<li><b>source</b>: The name of the person who sent the message.</li>
<li><b>job</b>: What their job is.</li>
<li><b>freq</b>: What radio frequency they think they wanted</li>
<li><b>pass</b>: Is it actually being sent? Probably going to be 1.</li>
<li><b>ref</b>: A signal reference. This is only important if you plan to play with people's voices.</li>
<li><b>verb</b>: How the message is enunciated.</li>
<li><b>language</b>: What language they spoke.</li>
</ul>
<h3>Sending</h3>
To send messages, just use the <code>tcomm.broadcast</code> function. This takes the following arguments, all of which are optional.<br>
<ul>
<li><b>content</b>: The message sent; Converted to someone's voice.</li>
<li><b>source</b>: Name of the voice to mimic.</li>
<li><b>job</b>: What job to emulate.</li>
<li><b>freq</b>: What radio frequency you want</li>
<li><b>pass</b>: Is it actually being sent? Probably going to be 1, if you actually want the message sent. This is used to silence ref'd messages.</li>
<li><b>ref</b>: A signal reference. Set this to the one you were given in the onmessage function to modify it. Doesn't do anything if it wasn't that.</li>
<li><b>verb</b>: How the message is enunciated.</li>
<li><b>language</b>: What language to output in.</li>
</ul><br><br>
<h3>Special Notes</h3>
If your program is too slow, then a message might get out before your code can tell the server what it should actually say. If changes to people's voices don't seem to do anything, try immediently stopping the message when you get it handed, then just send out a fake one with broadcast later.<br><br>
<h2>Networking</h2>
Networking is important if you want two programs to talk to each other. Even more important if you want to control Telecomms from your personal laptop, ignoring the dangers of that.<br><br>
Networking is just like Telecomms, simple sending and hooking. Because NTSL2+ is written by the lowest bidder, security functions aren't default. Write your own.<br><br>
<h3>Receiving</h3>
Unlike telecomms, you've got to use a special hook name. So this time, hooking is like so: <code>when net.subscribe("something"){}</code><br>
You can still use that as many times as you like, but make sure your hook name is important. You'll be sending messages to that.<br>
net.subscribe events are given access to one variable, <code>message</code>. This is whatever the other side of it, net.message, sends.<br><br>
<h3>Sending</h3>
Sending is easier, just call <code>net.message("something", data)</code> Data is optional, and "something" should be exactly what you've hooked to in your other program.<br>
This will send this message to <b>Any program listening, including malicious ones or ones you own.</b> Ensuring communication is done securely is left as an exercise to the reader, but I recommend randomly generating new hook names and handing them back and forth with each message.<br><br>
<h3>Special Notes</h3>
Net messages can't contain complicated data. You can send a list over, or a list of lists, and so on, or strings or numbers, but that's it. No functions nor events. Mutating a message on one side can never effect it on the other.</br><br><br>
<h2>Final Notes</h2>
This is a language with a lot of "guessing". It will try to run your code no-matter how broken it is, and it will never tell you what you've done wrong.<br>
Think HTML but it hates you more.<br><br>
That being said, when in doubt, keep poking the language. Break it into little pieces and try those. NTSL2+ is a lot more usable than NTSL, take that and run with it.<br><br>
Most importantly, <b>Stay sane, try not to die.</b>
</body>
</html>
"}
author = "Collaborative author group"
title = "Guide to NTSL2++"
sub_page = "Guide_to_NTSL2%2B%2B"
-86
View File
@@ -1,86 +0,0 @@
/datum/NTSL_interpreter
var/connected = 0
var/locked = 0 // Due to the psudo-threaded nature of Byond, two messages could be sent at the same time. This is a measure against that.
var/list/programs = list()
/datum/NTSL_interpreter/proc/attempt_connect()
locked = 0
var/res = send(list(action="clear"))
if(!res)
log_debug("NTSL2+ Daemon could not be connected to. Functionality will not be enabled.")
else
START_PROCESSING(SSfast_process, src)
connected = 1
log_debug("NTSL2+ Daemon connected successfully.")
/datum/NTSL_interpreter/proc/disconnect()
connected = 0
send(list(action="clear"))
STOP_PROCESSING(SSfast_process, src)
for(var/datum/ntsl_program/P in programs)
P.kill()
/datum/NTSL_interpreter/process()
if(connected)
var/received_message = send(list(action="subspace_transmit"))
if(received_message && received_message!="0")
var/messages = splittext(received_message, "\n")
for(var/individual_message in messages)
var/list/message_info = params2list(individual_message);
var/channel = "[WP_ELECTRONICS][message_info["channel"]]"
var/message_type = message_info["type"]
var/message_body = message_info["data"]
var/message = 0
if(message_type == "num")
message = text2num(message_body)
else if(message_type == "text")
message = html_encode(message_body)
else if(message_type == "ref")
message = locate(message_body)
for (var/thing in GET_LISTENERS(channel))
var/listener/L = thing
var/obj/item/integrated_circuit/transfer/wireless/W = L.target
if (W != src)
W.receive(message)
/datum/NTSL_interpreter/proc/new_program(var/code, var/computer, var/mob/user)
if(!connected)
return 0
log_ntsl("[user.name]/[user.key] uploaded script to [computer] : [code]", istype(computer, /datum/TCS_Compiler/) ? SEVERITY_ALERT : SEVERITY_NOTICE, user.ckey)
var/program_id = send(list(action="new_program", code=code, ref = "\ref[computer]"))
if(connected) // Because both new program and error can send 0.
var/datum/ntsl_program/P = new(program_id)
programs += P
return P
return 0
/datum/NTSL_interpreter/proc/receive_subspace(var/channel, var/data)
if(istext(data))
ntsl2.send(list(action="subspace_receive", channel=copytext(channel, length(WP_ELECTRONICS)+1), type="text", data=html_decode(data)))
else if(isnum(data))
ntsl2.send(list(action="subspace_receive", channel=copytext(channel, length(WP_ELECTRONICS)+1), type="num", data="[data]"))
else // Probably an object or something, just get a ref to it.
ntsl2.send(list(action="subspace_receive", channel=copytext(channel, length(WP_ELECTRONICS)+1), type="ref", data="\ref[data]"))
/*
Sends a command to the Daemon. This is an internal function, and should be avoided when used externally.
*/
/datum/NTSL_interpreter/proc/send(var/list/commands)
while(locked) // Prevent multiple requests being sent simultaneously and thus collisions.
sleep(1)
if(config.ntsl_hostname && config.ntsl_port) // Requires config to be set.
locked = 1
var/http[] = world.Export("http://[config.ntsl_hostname]:[config.ntsl_port]/[list2params(commands)]")
locked = 0
if(http)
return file2text(http["CONTENT"])
return 0
var/datum/NTSL_interpreter/ntsl2 = new()
/hook/startup/proc/init_ntsl2()
ntsl2.attempt_connect()
return 1
+27
View File
@@ -0,0 +1,27 @@
/*
Datum representing program state on deamon and exposing apropriate procs to DM.
*/
/datum/ntsl2_program/
var/id = 0
var/name = "Base NTSL2++ program"
var/list/ready_tasks = list()
/datum/ntsl2_program/New()
..()
/datum/ntsl2_program/proc/is_ready()
return !!id
/datum/ntsl2_program/proc/kill()
if(is_ready())
SSntsl2.send_task("remove", list(id = id))
SSntsl2.handle_termination(src)
qdel(src)
/datum/ntsl2_program/proc/execute(var/script, var/mob/user)
if(!is_ready())
ready_tasks += CALLBACK(src, .proc/execute, script, user)
return FALSE // We are not ready to run code
log_ntsl("[user.name]/[user.key] uploaded script to [src] : [script]", SEVERITY_NOTICE, user.ckey)
return SSntsl2.send_task("execute", list(id = id, code = script), program = src)
+117
View File
@@ -0,0 +1,117 @@
/datum/controller/subsystem/processing/ntsl2/proc/new_program_computer(var/buffer_callback)
var/datum/ntsl2_program/computer/P = new()
var/res = send_task("new_program", list(type = "Computer"), program = P)
if(res)
programs += P
START_PROCESSING(SSntsl2, P)
P.buffer_update_callback = buffer_callback
return P
qdel(P)
return FALSE
/datum/controller/subsystem/processing/ntsl2/proc/new_program_tcomm(var/server)
var/datum/ntsl2_program/tcomm/P = new(server)
var/res = send_task("new_program", list(type = "TCom"), program = P)
if(res)
programs += P
START_PROCESSING(SSntsl2, P)
return P
qdel(P)
return FALSE
// Modular computer interpreter
/datum/ntsl2_program/computer
name = "NTSL2++ interpreter"
var/buffer = ""
var/last_buffer_task = 0
var/datum/callback/buffer_update_callback
/datum/ntsl2_program/computer/proc/handle_topic(var/topic)
if(!is_ready())
return FALSE // We are not ready to run code
if(copytext(topic, 1, 2) == "?")
var/data = input("", "Enter Data")
if(!data)
data = ""
SSntsl2.send_task("computer/topic", list(id = id, topic = copytext(topic, 2), data = data))
else
SSntsl2.send_task("computer/topic", list(id = id, topic = topic))
/datum/ntsl2_program/computer/process()
if(SSntsl2.is_complete(last_buffer_task) && is_ready())
last_buffer_task = SSntsl2.send_task("computer/get_buffer", list(id = id), program = src)
// Currently unused
// Telecommunications program
/datum/ntsl2_program/tcomm
name = "NTSL2++ comm program"
var/obj/machinery/telecomms/server/server
/datum/ntsl2_program/tcomm/New(var/server)
. = ..()
src.server = server
/datum/ntsl2_program/tcomm/proc/process_message(var/datum/signal/signal, var/callback = null)
var/datum/language/signal_language = signal.data["language"]
SSntsl2.send_task("tcom/process", list(
id = id,
signal = list(
content = html_decode(signal.data["message"]),
freq = signal.frequency,
source = html_decode(signal.data["name"]),
job = html_decode(signal.data["job"]),
pass = !(signal.data["reject"]),
verb = signal.data["verb"],
language = signal_language.name,
reference = ref(signal)
)
), RUSTG_HTTP_METHOD_POST, callback = callback)
/* [
{
"content": "AAAAA",
"freq": "1459",
"source": "Telecomms Broadcaster",
"job": "Machine",
"pass": true,
"verb": "says",
"language": "Ceti Basic",
"reference": null
}
]*/
/datum/ntsl2_program/tcomm/proc/retrieve_messages(var/callback = null)
SSntsl2.send_task("tcom/get", callback = CALLBACK(src, .proc/_finish_retrieve_messages, callback))
/datum/ntsl2_program/tcomm/proc/_finish_retrieve_messages(var/callback = null, var/data)
if(data)
var/list/signals = json_decode(data)
for(var/sl in signals)
var/list/S = sl
var/datum/signal/sig = null
if(S["reference"])
sig = locate(S["reference"])
if(istype(sig))
var/datum/language/L = all_languages[S["language"]]
if(!L || !(L.flags & TCOMSSIM))
L = all_languages[LANGUAGE_TCB]
sig.data["message"] = S["content"]
sig.frequency = S["freq"] || PUB_FREQ
sig.data["name"] = html_encode(S["source"])
sig.data["realname"] = html_encode(S["source"])
sig.data["job"] = html_encode(S["job"])
sig.data["reject"] = !S["pass"]
sig.data["verb"] = html_encode(S["verb"])
sig.data["language"] = L
sig.data["vmessage"] = html_encode(S["content"])
sig.data["vname"] = html_encode(S["source"])
sig.data["vmask"] = 0
else
sig = new()
sig.data["server"] = server
sig.tcombroadcast(html_encode(S["content"]), S["freq"], html_encode(S["source"]), html_encode(S["job"]), html_encode(S["verb"]), S["language"])
var/datum/callback/cb = callback
if(istype(cb))
cb.InvokeAsync()
-44
View File
@@ -1,44 +0,0 @@
/datum/ntsl_program/
var/id = -1
var/name = "NTSL Program"
var/obj/machinery/telecomms/server/S = null
/datum/ntsl_program/New(var/my_id)
id = my_id
// Failsafe, kill any obsolete programs.
for(var/datum/ntsl_program/P in ntsl2.programs)
if(P.id == id)
P.kill()
..()
/datum/ntsl_program/proc/cycle(var/amount)
if(ntsl2.connected)
ntsl2.send(list(action = "execute", id = id, cycles = amount))
/datum/ntsl_program/proc/get_terminal()
return ntsl2.send(list(action = "get_buffered", id = id))
/datum/ntsl_program/proc/topic(var/message)
if(ntsl2.connected)
ntsl2.send(list(action = "topic", id = id, topic = message))
/datum/ntsl_program/proc/kill()
if(ntsl2.connected)
ntsl2.send(list(action = "remove", id = id))
ntsl2.programs -= src
qdel(src)
/datum/ntsl_program/proc/tc_message(var/datum/signal/signal)
if(ntsl2.connected)
var/datum/language/signal_language = signal.data["language"]
ntsl2.send(list(action = "message", id = id, sig_ref = "\ref[signal]", signal = list2params(list(
content = html_decode(signal.data["message"]),
source = html_decode(signal.data["name"]),
job = html_decode(signal.data["job"]),
freq = signal.frequency,
pass = !(signal.data["reject"]),
language = signal_language.name,
verb = signal.data["verb"]
))))
-47
View File
@@ -1,47 +0,0 @@
/datum/TCS_Compiler/ntsl2
var/datum/ntsl_program/running_code = null
/datum/TCS_Compiler/ntsl2/Compile(code)
var/list/errors = list()
if(istype(running_code))
running_code.kill()
running_code = ntsl2.new_program(code, src, usr)
if(!istype(running_code))
errors += "The code failed to compile."
return errors
/datum/TCS_Compiler/ntsl2/Run(var/datum/signal/signal)
if(istype(running_code))
running_code.tc_message(signal)
running_code.cycle(100000)
update_code()
/datum/TCS_Compiler/ntsl2/proc/update_code()
if(istype(running_code))
running_code.cycle(100000)
var/list/dat = json_decode(ntsl2.send(list(action="get_signals",id=running_code.id)))
if(istype(dat) && ("content" in dat))
var/datum/signal/sig = null
if(dat["reference"])
sig = locate(dat["reference"])
if(istype(sig))
var/datum/language/L = all_languages[dat["language"]]
if(!L || !(L.flags & TCOMSSIM))
L = all_languages[LANGUAGE_TCB]
sig.data["message"] = dat["content"]
sig.frequency = text2num(dat["freq"]) || PUB_FREQ
sig.data["name"] = html_encode(dat["source"])
sig.data["realname"] = html_encode(dat["source"])
sig.data["job"] = html_encode(dat["job"])
sig.data["reject"] = !dat["pass"]
sig.data["verb"] = html_encode(dat["verb"])
sig.data["language"] = L
sig.data["vmessage"] = html_encode(dat["content"])
sig.data["vname"] = html_encode(dat["source"])
sig.data["vmask"] = 0
else
sig = new()
sig.data["server"] = running_code.S
sig.tcombroadcast(html_encode(dat["content"]), dat["freq"], html_encode(dat["source"]), html_encode(dat["job"]), html_encode(dat["verb"]), dat["language"])
+1 -1
View File
@@ -234,7 +234,7 @@ var/list/admin_departments
var success = 1
for (var/dest in (alldepartments - department))
// Send to everyone except this department
delay(1)
sleep(1)
success &= sendfax(dest, 0) // 0: don't display success/error messages
if(!success)// Stop on first error
@@ -236,61 +236,5 @@ datum/signal
S.memory[address] = value
proc/tcombroadcast(var/message, var/freq, var/source, var/job, var/verb, var/language)
var/datum/signal/newsign = new
var/obj/machinery/telecomms/server/S = data["server"]
var/obj/item/device/radio/hradio = S.server_radio
if(!hradio)
error("[src] has no radio.")
return
if((!message || message == "") && message != 0)
message = "*beep*"
if(!source)
source = "[html_encode(uppertext(S.id))]"
hradio = new // sets the hradio as a radio intercom
if(!freq)
freq = PUB_FREQ
if(findtext(num2text(freq), ".")) // if the frequency has been set as a decimal
freq *= 10 // shift the decimal one place
if(!job)
job = "?"
if(!language || language == "")
language = LANGUAGE_TCB
var/datum/language/L = all_languages[language]
if(!L || !(L.flags & TCOMSSIM))
L = all_languages[LANGUAGE_TCB]
newsign.data["mob"] = null
newsign.data["mobtype"] = /mob/living/carbon/human
newsign.data["name"] = source
newsign.data["realname"] = newsign.data["name"]
newsign.data["job"] = job
newsign.data["compression"] = 0
newsign.data["message"] = message
newsign.data["language"] = L
newsign.data["type"] = 2 // artificial broadcast
if(!isnum(freq))
freq = text2num(freq)
newsign.frequency = freq
var/datum/radio_frequency/connection = SSradio.return_frequency(freq)
newsign.data["connection"] = connection
newsign.data["radio"] = hradio
newsign.data["vmessage"] = message
newsign.data["vname"] = source
newsign.data["vmask"] = 0
newsign.data["level"] = list()
newsign.data["verb"] = verb
var/pass = S.relay_information(newsign, "/obj/machinery/telecomms/hub")
if(!pass)
S.relay_information(newsign, "/obj/machinery/telecomms/broadcaster") // send this simple message to broadcasters
@@ -213,37 +213,7 @@ proc/n_abs(var/num)
if(isnum(num))
return abs(num)
// Round down
proc/n_floor(var/num)
if(isnum(num))
return round(num)
// Round up
proc/n_ceil(var/num)
if(isnum(num))
return round(num)+1
// Round to nearest integer
proc/n_round(var/num)
if(isnum(num))
if(num-round(num)<0.5)
return round(num)
return n_ceil(num)
// Clamps N between min and max
proc/n_clamp(var/num, var/min=-1, var/max=1)
if(isnum(num)&&isnum(min)&&isnum(max))
if(num<=min)
return min
if(num>=max)
return max
return num
// Returns 1 if N is inbetween Min and Max
proc/n_inrange(var/num, var/min=-1, var/max=1)
if(isnum(num)&&isnum(min)&&isnum(max))
return ((min <= num) && (num <= max))
// END OF BY DONKIE :(
// Non-recursive
// Imported from Mono string.ReplaceUnchecked
+4
View File
@@ -0,0 +1,4 @@
author: Karolis2011
delete-after: True
changes:
- experiment: "Upgraded NTSL2+ to NTSL2++. New scripting environment, better error messages, space for future expansion."
+1 -1
View File
@@ -888,7 +888,7 @@
/obj/item/device/radio/intercom{
pixel_y = -26
},
/obj/item/book/manual/ntsl2,
/obj/item/book/manual/wiki/ntsl2,
/turf/simulated/floor/wood,
/area/library)
"abY" = (
+1 -1
View File
@@ -24239,7 +24239,7 @@
pixel_y = 2
},
/obj/item/paper_bin,
/obj/item/book/manual/ntsl2,
/obj/item/book/manual/wiki/ntsl2,
/obj/machinery/light_switch{
pixel_y = 26
},
+1 -1
View File
@@ -371,7 +371,7 @@
/area/tcommsat/chamber)
"pY" = (
/obj/structure/table/standard,
/obj/item/book/manual/ntsl2,
/obj/item/book/manual/wiki/ntsl2,
/turf/simulated/floor/tiled{
name = "cooled floor";
temperature = 278
+14 -6
View File
@@ -6,12 +6,20 @@
{{else}}
{{if data.filename}}
<h2>Viewing file {{:data.filename}}</h2>
<div class='item'>
{{:helper.link('CLOSE', null, { "PRG_closefile" : 1 })}}
{{:helper.link('EDIT', null, { "PRG_edit" : 1 })}}
{{:helper.link('PRINT', null, { "PRG_printfile" : 1 })}}
</div><hr>
{{:data.filedata}}
{{if data.scriptdata}}
<div class='item'>
{{:helper.link('CLOSE', null, { "PRG_closefile" : 1 })}}
{{:helper.link('PRINT', null, { "PRG_printfile" : 1 })}}
</div><hr>
{{:data.scriptdata}}
{{else}}
<div class='item'>
{{:helper.link('CLOSE', null, { "PRG_closefile" : 1 })}}
{{:helper.link('EDIT', null, { "PRG_edit" : 1 })}}
{{:helper.link('PRINT', null, { "PRG_printfile" : 1 })}}
</div><hr>
{{:data.filedata}}
{{/if}}
{{else}}
<h2>Available files (local):</h2>
<table>
+1
View File
@@ -13,6 +13,7 @@
"core-js": "^3.7.0",
"core-js-compat": "^3.7.0",
"fuse.js": "^3.6.1",
"vue2-ace-editor": "0.0.15",
"vue": "^2.6.12",
"webpack": "^4.43.0"
},
@@ -49,14 +49,14 @@
</template>
<script>
import Utils from "../../../../utils.js";
import Utils from "@/utils"
export default {
data() {
return this.$root.$data;
return this.$root.$data
},
methods: {
s(parameters) {
Utils.sendToTopic(parameters);
Utils.sendToTopic(parameters)
}
}
};
@@ -49,14 +49,14 @@
</template>
<script>
import Utils from '../../../../utils';
import Utils from "@/utils"
export default {
data() {
return this.$root.$data;
return this.$root.$data
},
methods: {
s(parameters) {
Utils.sendToTopic(parameters);
Utils.sendToTopic(parameters)
}
}
};
@@ -21,7 +21,7 @@
</template>
<script>
import Utils from '../../../../utils.js'
import Utils from "@/utils"
export default {
data() {
return this.$root.$data.state;
@@ -0,0 +1,33 @@
<template>
<div>
<vui-button :params="{close: 1, code: code}">Save and Close</vui-button>
<vui-button :params="{execute: 1, code: code}">Save and Execute</vui-button>
<vui-button :params="{close: 1, code: s.code}">Close</vui-button>
<editor v-model="code" @init="editorInit" lang="javascript" theme="monokai" width="100%" height="50em"/>
</div>
</template>
<script>
export default {
data() {
return {
s: this.$root.$data.state,
code: "Term.write(\"AAA\")"
}
},
components: {
editor: require("vue2-ace-editor"),
},
created() {
this.code = this.s.code
},
methods: {
editorInit: function() {
require("brace/ext/language_tools") //language extension prerequsite...
require("brace/mode/javascript") //language
require("brace/theme/monokai")
require("brace/snippets/javascript") //snippet
},
},
}
</script>
@@ -0,0 +1,50 @@
<template>
<div>
<vui-button v-show="!creating" @click="creating = true">New</vui-button>
<template v-if="creating">
<input type="text" v-model="newname" >
<vui-button @click="newFile()">Create</vui-button>
</template>
<h2>Available files:</h2>
<table>
<tr>
<th>File name</th>
<th>File type</th>
<th>File size (GQ)</th>
<th>Operations</th>
</tr>
<tr v-for="f in s.files" :key="f.name">
<td>{{ f.name }}</td>
<td>{{ f.type }}</td>
<td>{{ f.size }}GQ</td>
<td>
<vui-button :params="{execute_file: f.name}">Execute</vui-button>
<vui-button :params="{edit_file: f.name}">Edit</vui-button>
</td>
</tr>
</table>
</div>
</template>
<script>
import Utils from "@/utils"
export default {
data() {
return {
s: this.$root.$data.state,
creating: false,
newname: "",
}
},
methods: {
newFile() {
Utils.sendToTopic({
new: this.newname,
})
this.newname = ""
this.creating = false
},
},
}
</script>
@@ -0,0 +1,15 @@
<template>
<div>
<component :is="&quot;view-mcomputer-ntsl-&quot; + s.mode"/>
</div>
</template>
<script>
export default {
data() {
return {
s: this.$root.$data.state
}
}
}
</script>
@@ -0,0 +1,65 @@
<template>
<div>
<vui-button :params="{stop: 1}">Stop</vui-button>
<br>
<component class="terminal" :is="term"/>
</div>
</template>
<script>
import Utils from "@/utils"
const co = {
props: ['fg', 'bg'],
computed: {
style() {
return {
color: '#' + this.fg,
'background-color': '#' + this.bg
}
}
},
template: '<span :style="style"><slot/></span>'
}
const to = {
props: ['to'],
methods: {
invoke() {
Utils.sendToTopic({
terminal_topic: this.to
})
}
},
template: '<span style="cursor: pointer;" @click.prevent="invoke"><slot/></span>'
}
export default {
data() {
return {
s: this.$root.$data.state,
}
},
computed: {
term() {
return {
components: {
co, to
},
template: `<div>${this.s.terminal}</div>`
}
}
}
}
</script>
<style lang="scss" scoped>
.terminal {
width: 100%;
font-family: monospace;
line-height: 1em;
font-size: 1em;
text-align: center;
}
</style>
+1 -1
View File
@@ -11,7 +11,7 @@
</template>
<script>
import Utils from '../../../utils.js'
import Utils from "@/utils"
export default {
data() {
return {
@@ -23,7 +23,7 @@
</template>
<script>
import Utils from '../../../utils.js'
import Utils from "@/utils"
export default {
data() {
return this.$root.$data.state
@@ -25,7 +25,7 @@
</template>
<script>
import Utils from '../../../utils.js'
import Utils from "@/utils"
export default {
data() {
return this.$root.$data.state
+2 -2
View File
@@ -6,8 +6,8 @@
</template>
<script>
import Store from '../../store.js'
import Utils from '../../utils.js'
import Store from "@/store"
import Utils from "@/utils"
export default {
props: {
icon: {
+1 -1
View File
@@ -7,7 +7,7 @@
</template>
<script>
import Store from '../../../store.js'
import Store from '@/store'
export default {
props: {
value: {