diff --git a/aurorastation.dme b/aurorastation.dme
index aed35498254..88763b1ef8b 100644
--- a/aurorastation.dme
+++ b/aurorastation.dme
@@ -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"
diff --git a/code/_helpers/maths.dm b/code/_helpers/maths.dm
index d0fd58fb4ee..441188a5adb 100644
--- a/code/_helpers/maths.dm
+++ b/code/_helpers/maths.dm
@@ -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))
\ No newline at end of file
diff --git a/code/controllers/subsystems/processing/ntsl2.dm b/code/controllers/subsystems/processing/ntsl2.dm
new file mode 100644
index 00000000000..5323bd05be6
--- /dev/null
+++ b/code/controllers/subsystems/processing/ntsl2.dm
@@ -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
+
+ . = ..()
\ No newline at end of file
diff --git a/code/datums/radio/signal.dm b/code/datums/radio/signal.dm
index 39ce0e953eb..ee1f71c00ce 100644
--- a/code/datums/radio/signal.dm
+++ b/code/datums/radio/signal.dm
@@ -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
\ No newline at end of file
diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm
index 468060cc3ce..d3f2e2b29c0 100644
--- a/code/game/machinery/telecomms/telecomunications.dm
+++ b/code/game/machinery/telecomms/telecomunications.dm
@@ -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
+
+
+
+
+
+
diff --git a/code/game/objects/items/weapons/manuals.dm b/code/game/objects/items/weapons/manuals.dm
index d63d5a975f0..6595a549afa 100644
--- a/code/game/objects/items/weapons/manuals.dm
+++ b/code/game/objects/items/weapons/manuals.dm
@@ -12,7 +12,7 @@
dat = {"
-
+
diff --git a/code/modules/admin/verbs/ntsl.dm b/code/modules/admin/verbs/ntsl.dm
index 7a8f54f261f..97f0b80ca3b 100644
--- a/code/modules/admin/verbs/ntsl.dm
+++ b/code/modules/admin/verbs/ntsl.dm
@@ -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
diff --git a/code/modules/integrated_electronics/subtypes/data_transfer.dm b/code/modules/integrated_electronics/subtypes/data_transfer.dm
index 783d34705a0..4abd687a87e 100644
--- a/code/modules/integrated_electronics/subtypes/data_transfer.dm
+++ b/code/modules/integrated_electronics/subtypes/data_transfer.dm
@@ -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
diff --git a/code/modules/modular_computers/file_system/programs/generic/ntsl2_interpreter.dm b/code/modules/modular_computers/file_system/programs/generic/ntsl2_interpreter.dm
index a00f0192ea5..7c466fc4455 100644
--- a/code/modules/modular_computers/file_system/programs/generic/ntsl2_interpreter.dm
+++ b/code/modules/modular_computers/file_system/programs/generic/ntsl2_interpreter.dm
@@ -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)
\ No newline at end of file
diff --git a/code/modules/modular_computers/file_system/programs/system/file_browser.dm b/code/modules/modular_computers/file_system/programs/system/file_browser.dm
index 238b9b24044..d440f1b57eb 100644
--- a/code/modules/modular_computers/file_system/programs/system/file_browser.dm
+++ b/code/modules/modular_computers/file_system/programs/system/file_browser.dm
@@ -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]"
diff --git a/code/modules/modular_computers/file_system/script.dm b/code/modules/modular_computers/file_system/script.dm
new file mode 100644
index 00000000000..6e766bd2105
--- /dev/null
+++ b/code/modules/modular_computers/file_system/script.dm
@@ -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))
\ No newline at end of file
diff --git a/code/modules/ntsl2/guide.dm b/code/modules/ntsl2/guide.dm
index bde2e34eff3..fe065920d04 100644
--- a/code/modules/ntsl2/guide.dm
+++ b/code/modules/ntsl2/guide.dm
@@ -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 = {"
-
-
-
-
-
NTSL2+ For Dummies
-
- So you want to write NTSL2+ huh?
- 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.
-
-
Installing
- Firstly, if you're running this on a Telecommunications server, skip this step. It's already installed. Just, skip ahead to the Telecomms section...
- 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.
-
- Step One: Launch your computer or laptop.
- Step Two: 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.
- Step Three: Download NTSL2+ Interpreter. Patiently wait for the download. You've got time, right?
- Step Four: You're done. Either learn to program or download someone else's code.
-
-
Running basic programs
- When inside the Interpreter, you'll be given a list of programs you can run that are stored on your harddrive. Programs on your USB stick have to be copied over first.
- Find a file you want to run, and click EXEC. This will cause the program to run.
- Programs have Refresh and Exit 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..
- 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.
- Finally, is the big black previously mentioned Terminal. All your program output and interaction happens here.
- 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.
- This will either run something within the program, ask you for input, or do nothing.
- This encompasses the limitations of your interactions with the average program.
-
-
Running complicated programs
- You are not ready. Go back to Running basic programs.
-
-
Writing your first program.
- For this guide, I'll boldly assume you already know some amount of programming. If you can't program at all, avoid touching NTSL2+, this is not an entry level language. This is a bad language. Please. Run.
- If you're still boldly willing to learn this language, we can begin with the most basic of programs. Hello world.
- Firstly, create a new file in your File Browser. Call it whatever you want, but I recommend Hello World. Then open up the text editor.
- Your basic Hello World is the following:
- print("Hello, World!")
- If you've programmed before, you already know what this does. If you haven't, see the start of this section, but for convenience...
- This program outputs the following text into the terminal when ran:
- Hello, World!
- Simple enough. this demonstrates calling a function, print, and a raw string argument, "Hello, World!"
- 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.
- If you spent long enough following my last instruction, you probably noticed something strange. print "Hello, World!" worked.
- 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...).
- This is because functions can implicitly be called with string or table constructors as an argument. This will make more sense later, hopefully.
- Next, is a For loop. Like wise, make a new program, or edit your old one. I'm not your boss.
- Fill it with:
-for(i=0; i < 10; i++){
- print `Number: \[i]`
-}
- This code prints all the numbers from 0 to 9, with the text "Number: " in front of it.
- Like last time, a lot of that code can still function if changed, play around with it.
- Different this time, however, is the use of backticks. `Number: \[i]`
- These allow you to put expressions within your string constructor. Anything in square brackets, in this case, \[i] will be added to the string as the result of it's expression. So, the value of i.
- You can also escape these square brackets with a backslash, if you ever wanted to use them raw like that.
- Your last tutorial: User Input.
- 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.
- The Code:
-term.set_cursor(0,0)
-term.write("PROMPT")
-term.set_topic(0,0,#"PROMPT",1,"?prompt")
-term.set_cursor(0,1)
-
-when term.topic{
- print(topic::sub(#"?prompt"))
-}
- Don't worry, Don't be scared, I'll step through this with you.
- I'll be gentle.
- First thing that happens is term.set_cursor(0,0). We've got another function call here, but with term. ahead it. This means that the function being run, set_cursor, is inside the table called term.
- 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.
- term.write is a lot like print but instead of writing a line, it just writes what you put in. Doesn't move the cursor down for next time.
- term.set_topic is the way you make fun buttons! 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 term.topic 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 ?prompt when pushed, and the text "hi" is entered, will return with prompt?hi
- Confusing? Probably. Don't stress.
- We then move the cursor again, this time one line down.
- Next, is this "when", thing. When is used to Hook to events, with term.topic being the most commonly used event for standard computers.
- In this case, it means the stuff in the block is executed when term.topic is called, and it sets the topic 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?
- Now what about topic::sub(#"?prompt")? Once again, easier than it looks. Firstly, ::sub 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 topic.sub(topic....
- "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.
- This gets a substring from the input string, in the form of sub(string, start, length). If the start and length aren't in the actual string, fuckery happens.
- #"?prompt" 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.
- 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.
-
-
The Whole Syntax
- 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...
-
- The rest of this page appears to be nothing but mad scribbles...
-
-
Telecomms
- 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.
-
-
Receiving
- To receive messages, hook into the tcomm.onmessage event. This gives you access to:
-
-
content: The message sent; converted to text for convenience.
-
source: The name of the person who sent the message.
-
job: What their job is.
-
freq: What radio frequency they think they wanted
-
pass: Is it actually being sent? Probably going to be 1.
-
ref: A signal reference. This is only important if you plan to play with people's voices.
-
verb: How the message is enunciated.
-
language: What language they spoke.
-
-
-
Sending
- To send messages, just use the tcomm.broadcast function. This takes the following arguments, all of which are optional.
-
-
content: The message sent; Converted to someone's voice.
-
source: Name of the voice to mimic.
-
job: What job to emulate.
-
freq: What radio frequency you want
-
pass: 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.
-
ref: 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.
-
verb: How the message is enunciated.
-
language: What language to output in.
-
-
-
Special Notes
- 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.
-
-
Networking
- 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.
- 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.
-
-
Receiving
- Unlike telecomms, you've got to use a special hook name. So this time, hooking is like so: when net.subscribe("something"){}
- 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.
- net.subscribe events are given access to one variable, message. This is whatever the other side of it, net.message, sends.
-
-
Sending
- Sending is easier, just call net.message("something", data) Data is optional, and "something" should be exactly what you've hooked to in your other program.
- This will send this message to Any program listening, including malicious ones or ones you own. 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.
-
-
Special Notes
- 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.
-
-
Final Notes
- 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.
- Think HTML but it hates you more.
- 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.
- Most importantly, Stay sane, try not to die.
-
-
-
- "}
+ author = "Collaborative author group"
+ title = "Guide to NTSL2++"
+ sub_page = "Guide_to_NTSL2%2B%2B"
\ No newline at end of file
diff --git a/code/modules/ntsl2/ntsl2.dm b/code/modules/ntsl2/ntsl2.dm
deleted file mode 100644
index da2405b082a..00000000000
--- a/code/modules/ntsl2/ntsl2.dm
+++ /dev/null
@@ -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
\ No newline at end of file
diff --git a/code/modules/ntsl2/ntsl2_program.dm b/code/modules/ntsl2/ntsl2_program.dm
new file mode 100644
index 00000000000..695fd9a870f
--- /dev/null
+++ b/code/modules/ntsl2/ntsl2_program.dm
@@ -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)
\ No newline at end of file
diff --git a/code/modules/ntsl2/ntsl2_types.dm b/code/modules/ntsl2/ntsl2_types.dm
new file mode 100644
index 00000000000..16110229e3f
--- /dev/null
+++ b/code/modules/ntsl2/ntsl2_types.dm
@@ -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()
\ No newline at end of file
diff --git a/code/modules/ntsl2/program.dm b/code/modules/ntsl2/program.dm
deleted file mode 100644
index 3f840b53870..00000000000
--- a/code/modules/ntsl2/program.dm
+++ /dev/null
@@ -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"]
- ))))
diff --git a/code/modules/ntsl2/telecomms.dm b/code/modules/ntsl2/telecomms.dm
deleted file mode 100644
index 193749fc585..00000000000
--- a/code/modules/ntsl2/telecomms.dm
+++ /dev/null
@@ -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"])
diff --git a/code/modules/paperwork/faxmachine.dm b/code/modules/paperwork/faxmachine.dm
index 407e2332a02..9beee7a17f2 100644
--- a/code/modules/paperwork/faxmachine.dm
+++ b/code/modules/paperwork/faxmachine.dm
@@ -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
diff --git a/code/modules/scripting/Implementations/Telecomms.dm b/code/modules/scripting/Implementations/Telecomms.dm
index 3c8e7ddd010..1bd09ceba4b 100644
--- a/code/modules/scripting/Implementations/Telecomms.dm
+++ b/code/modules/scripting/Implementations/Telecomms.dm
@@ -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
-
diff --git a/code/modules/scripting/Implementations/_Logic.dm b/code/modules/scripting/Implementations/_Logic.dm
index 4cd617a2641..ce11d7dd37d 100644
--- a/code/modules/scripting/Implementations/_Logic.dm
+++ b/code/modules/scripting/Implementations/_Logic.dm
@@ -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
diff --git a/html/changelogs/alberyk-love.yml b/html/changelogs/alberyk-love.yml
new file mode 100644
index 00000000000..6b7d8e9be5d
--- /dev/null
+++ b/html/changelogs/alberyk-love.yml
@@ -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."
diff --git a/maps/aurora/aurora-4_mainlevel.dmm b/maps/aurora/aurora-4_mainlevel.dmm
index 3bc5d44a908..f6706c37e00 100644
--- a/maps/aurora/aurora-4_mainlevel.dmm
+++ b/maps/aurora/aurora-4_mainlevel.dmm
@@ -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" = (
diff --git a/maps/aurora/aurora-6_surface.dmm b/maps/aurora/aurora-6_surface.dmm
index 3d5f2130863..b1ced109b98 100644
--- a/maps/aurora/aurora-6_surface.dmm
+++ b/maps/aurora/aurora-6_surface.dmm
@@ -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
},
diff --git a/maps/runtime/runtime-2.dmm b/maps/runtime/runtime-2.dmm
index 2f9166e96e7..a9f50c8785e 100644
--- a/maps/runtime/runtime-2.dmm
+++ b/maps/runtime/runtime-2.dmm
@@ -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
diff --git a/nano/templates/file_manager.tmpl b/nano/templates/file_manager.tmpl
index 9d0f0c5985d..82b9cb6b789 100644
--- a/nano/templates/file_manager.tmpl
+++ b/nano/templates/file_manager.tmpl
@@ -6,12 +6,20 @@
{{else}}
{{if data.filename}}
+
+
+
\ No newline at end of file
diff --git a/vueui/src/components/view/mcomputer/ntsl/program.vue b/vueui/src/components/view/mcomputer/ntsl/program.vue
new file mode 100644
index 00000000000..9b8b6c381d6
--- /dev/null
+++ b/vueui/src/components/view/mcomputer/ntsl/program.vue
@@ -0,0 +1,65 @@
+
+
+ Stop
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vueui/src/components/view/records/field.vue b/vueui/src/components/view/records/field.vue
index 5d40103038d..ff90b47a305 100644
--- a/vueui/src/components/view/records/field.vue
+++ b/vueui/src/components/view/records/field.vue
@@ -11,7 +11,7 @@