mirror of
https://github.com/vgstation-coders/vgstation13.git
synced 2025-12-09 16:14:13 +00:00
Vocal Implants (#32837)
* Vocal Implants * Thing itself * Attempt at NTSL compiler/interpereter refactor, revert commit if goes awry * I always forget this * Moves this here * Removing this var, redundant * Skeleton code for this * Super call * File itself, again * Option to go into this, no code yet * Dots, not commas * Start on window and editor itself * Start on window and editor itself * Some vars for this, don't even know if I'll need this proc * In action here too, after any word filters * Vars and procs beginning work * Broadcast function * Way to test it * Some error feedback * This should be an alert * Some admin logging * Clarity Co-authored-by: kanef <kanef9x@protonmail.com>
This commit is contained in:
@@ -860,6 +860,15 @@ var/list/uplink_items = list()
|
||||
discounted_cost = 6
|
||||
jobs_with_discount = list("Mechanic")
|
||||
|
||||
// A telecomms technician traitor item
|
||||
/datum/uplink_item/jobspecific/engineering/vocal
|
||||
name = "Vocal Implant"
|
||||
desc = "An implant usable after being injected into one's body. Settings can be input to modify speech patterns in the affected's voice once implanted."
|
||||
item = /obj/item/weapon/storage/box/syndie_kit/imp_vocal
|
||||
cost = 8
|
||||
discounted_cost = 6
|
||||
jobs_with_discount = list("Mechanic", "Chief Engineer")
|
||||
|
||||
/datum/uplink_item/jobspecific/cargo
|
||||
category = "Cargo and Mining Specials"
|
||||
|
||||
|
||||
@@ -313,7 +313,7 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list()
|
||||
|
||||
/obj/machinery/telecomms/receiver/Destroy()
|
||||
if(blackout_active)
|
||||
malf_radio_blackout = FALSE
|
||||
malf_radio_blackout = FALSE
|
||||
..()
|
||||
|
||||
/obj/machinery/telecomms/receiver/receive_signal(datum/signal/signal)
|
||||
@@ -642,7 +642,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/Compiler // the compiler that compiles and runs the code
|
||||
var/datum/n_Compiler/TCS_Compiler/Compiler // the compiler that compiles and runs the code
|
||||
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"
|
||||
|
||||
@@ -142,3 +142,37 @@
|
||||
c.scanned = I
|
||||
c.scanned.forceMove(c)
|
||||
update()
|
||||
|
||||
/obj/item/weapon/implanter/vocal
|
||||
name = "implanter (V)"
|
||||
desc = "A small device used to apply implants to people."
|
||||
imp_type = /obj/item/weapon/implant/vocal
|
||||
var/storedcode = "" // code stored
|
||||
|
||||
/obj/item/weapon/implanter/vocal/attack_self(mob/user)
|
||||
if(istype(imp,imp_type))
|
||||
var/uselevel = alert(user, "Which level of complexity do you want to work with? Basic is a simple word replacement with regex, advanced is an implementation of NTSL as found in telecomms servers.", "Level of vocal manipulation", "Basic", "Advanced")
|
||||
if(uselevel == "Basic")
|
||||
var/obj/item/weapon/implant/vocal/V = imp
|
||||
var/input = input(user, "Enter an input phrase, regex works here:", "Input phrase") as text
|
||||
if(!input)
|
||||
return
|
||||
var/keepgoing = FALSE
|
||||
var/list/outputs = list()
|
||||
do
|
||||
var/output = input(user, "Enter an output phrase:", "Output phrase") as text
|
||||
if(!output)
|
||||
return
|
||||
outputs.Add(output)
|
||||
keepgoing = alert(user, "Add another output?", "Output phrase", "Yes", "No") == "Yes"
|
||||
while(keepgoing)
|
||||
var/casesense = alert(user, "Case sensitive?", "Case sensitivity","Yes","No") == "Yes"
|
||||
if(input && outputs.len)
|
||||
V.filter.addPickReplacement(input,outputs,casesense)
|
||||
else if(uselevel == "Advanced")
|
||||
winshow(user, "Vocal Implant IDE", 1) // show the IDE
|
||||
winset(user, "vicode", "is-disabled=false")
|
||||
winset(user, "vicode", "text=\"\"")
|
||||
var/showcode = replacetext(storedcode, "\\\"", "\\\\\"")
|
||||
showcode = replacetext(storedcode, "\"", "\\\"")
|
||||
winset(user, "vicode", "text=\"[showcode]\"")
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/obj/item/weapon/implant/vocal
|
||||
name = "vocal implant"
|
||||
icon_state = "implant_evil"
|
||||
var/datum/speech_filter/filter
|
||||
var/list/memory = list() // stored memory
|
||||
var/rawcode = "" // the code to compile (raw text)
|
||||
var/datum/n_Compiler/vocal_implant/Compiler // the compiler that compiles and runs the code
|
||||
|
||||
/obj/item/weapon/implant/vocal/New()
|
||||
..()
|
||||
filter = new
|
||||
Compiler = new
|
||||
Compiler.Holder = src
|
||||
|
||||
/obj/item/weapon/implant/vocal/Destroy()
|
||||
// Garbage collects all the NTSL datums.
|
||||
if(Compiler)
|
||||
Compiler.GC()
|
||||
Compiler = null
|
||||
..()
|
||||
|
||||
/obj/item/weapon/implant/vocal/proc/setcode(var/t)
|
||||
if(t)
|
||||
if(istext(t))
|
||||
rawcode = t
|
||||
|
||||
/obj/item/weapon/implant/vocal/proc/compile(var/mob/user)
|
||||
if(Compiler)
|
||||
admin_log(user)
|
||||
return Compiler.Compile(rawcode)
|
||||
|
||||
/obj/item/weapon/implant/vocal/proc/admin_log(var/mob/mob)
|
||||
var/msg = "[key_name(mob)] has compiled a script to a vocal implant"
|
||||
|
||||
diary << msg
|
||||
diary << rawcode
|
||||
|
||||
investigation_log(I_NTSL, "[msg]<br /><pre>[rawcode]</pre>")
|
||||
|
||||
if (length(rawcode)) // Let's not bother the admins for empty code.
|
||||
message_admins("[msg] ([formatJumpTo(mob)])", 0, 1)
|
||||
|
||||
/obj/item/weapon/implant/vocal/get_data()
|
||||
return {"
|
||||
<b>Implant Specifications:</b><BR>
|
||||
<b>Name:</b> Chameleon Voice-Changing Implant<BR>
|
||||
<b>Life:</b> ??? <BR>
|
||||
<b>Important Notes:</b> Any humanoid injected with this implant will have their vocal chords muted and replaced with a replica of their own voice on the reception of key phrases.<BR>
|
||||
<HR>
|
||||
<b>Implant Details:</b><BR>
|
||||
<b>Function:</b> Contains a small pod of nanobots that manipulate the host's mental speech functions and processing.<BR>
|
||||
<b>Special Features:</b> Vocal manipulation.<BR>
|
||||
<b>Integrity:</b> Implant will last so long as the subject is speaking."}
|
||||
@@ -260,6 +260,10 @@
|
||||
name = "box (E)"
|
||||
items_to_spawn = list(/obj/item/weapon/implanter/explosive)
|
||||
|
||||
/obj/item/weapon/storage/box/syndie_kit/imp_vocal
|
||||
name = "box (V)"
|
||||
items_to_spawn = list(/obj/item/weapon/implanter/vocal)
|
||||
|
||||
/obj/item/weapon/storage/box/syndie_kit/imp_uplink
|
||||
name = "Uplink Implant (with injector)"
|
||||
items_to_spawn = list(/obj/item/weapon/implanter/uplink)
|
||||
|
||||
@@ -218,7 +218,9 @@ var/list/headset_modes = list(
|
||||
|
||||
var/message_range = 7
|
||||
treat_speech(speech)
|
||||
|
||||
if(!speech.message)
|
||||
qdel(speech)
|
||||
return
|
||||
var/radio_return = get_speech_flags(message_mode)
|
||||
if (speech_was_spoken_into_radio(message_mode))
|
||||
speech.wrapper_classes.Add("spoken_into_radio")
|
||||
@@ -513,6 +515,20 @@ var/list/headset_modes = list(
|
||||
speech.message = replacetext(speech.message,";","") // motor mouth
|
||||
speech.message = replacetext(speech.message,"-","") // motor mouth
|
||||
|
||||
for(var/obj/item/weapon/implant/vocal/VI in src)
|
||||
if(VI.imp_in == src)
|
||||
var/original_message = speech.message
|
||||
speech.message = VI.filter.FilterSpeech(speech.message)
|
||||
var/datum/signal/signal = new /datum/signal
|
||||
signal.data["message"] = speech.message
|
||||
signal.data["reject"] = 0
|
||||
signal.data["mob"] = src
|
||||
signal.data["implant"] = VI
|
||||
VI.Compiler.Run(signal)
|
||||
speech.message = signal.data["reject"] ? null : signal.data["message"]
|
||||
if(speech.message != original_message)
|
||||
message_admins("The [VI] in [src] made \him say \"[speech.message]\" instead of \"[original_message]\" [formatJumpTo(src)]")
|
||||
|
||||
/mob/living/proc/get_speech_flags(var/message_mode)
|
||||
switch(message_mode)
|
||||
if(MODE_WHISPER, SPEECH_MODE_FINAL)
|
||||
@@ -702,6 +718,9 @@ var/list/headset_modes = list(
|
||||
|
||||
log_whisper("[key_name(src)] ([formatLocation(src)]): [message]")
|
||||
treat_speech(speech)
|
||||
if(!speech.message)
|
||||
qdel(speech)
|
||||
return
|
||||
|
||||
// If whispering your last words, limit the whisper based on how close you are to death.
|
||||
if(critical && !said_last_words)
|
||||
@@ -714,6 +733,9 @@ var/list/headset_modes = list(
|
||||
whispers = "whispers with their final breath"
|
||||
said_last_words = src.stat
|
||||
treat_speech(speech)
|
||||
if(!speech.message)
|
||||
qdel(speech)
|
||||
return
|
||||
|
||||
var/listeners = get_hearers_in_view(1, src) | observers
|
||||
var/eavesdroppers = get_hearers_in_view(2, src) - listeners
|
||||
@@ -766,4 +788,4 @@ var/list/headset_modes = list(
|
||||
output += uppertext(pick(muffle_syllables))
|
||||
else
|
||||
output += pick(muffle_syllables)
|
||||
return output
|
||||
return output
|
||||
|
||||
@@ -1,358 +0,0 @@
|
||||
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
|
||||
|
||||
|
||||
/* --- Traffic Control Scripting Language --- */
|
||||
// Nanotrasen TCS Language - Made by Doohl
|
||||
|
||||
/datum/n_Interpreter/TCS_Interpreter
|
||||
var/datum/TCS_Compiler/Compiler
|
||||
|
||||
/datum/n_Interpreter/TCS_Interpreter/HandleError(datum/runtimeError/e)
|
||||
Compiler.Holder.add_entry(e.ToString(), "Execution Error")
|
||||
|
||||
/datum/n_Interpreter/TCS_Interpreter/GC()
|
||||
..()
|
||||
Compiler = null
|
||||
|
||||
/datum/TCS_Compiler
|
||||
var/datum/n_Interpreter/TCS_Interpreter/interpreter
|
||||
var/obj/machinery/telecomms/server/Holder // the server that is running the code
|
||||
var/ready = 1 // 1 if ready to run code
|
||||
|
||||
/* -- Set ourselves to Garbage Collect -- */
|
||||
|
||||
/datum/TCS_Compiler/proc/GC()
|
||||
Holder = null
|
||||
if(interpreter)
|
||||
interpreter.GC()
|
||||
|
||||
|
||||
/* -- Compile a raw block of text -- */
|
||||
|
||||
/datum/TCS_Compiler/proc/Compile(code as message)
|
||||
var/datum/n_scriptOptions/nS_Options/options = new()
|
||||
var/datum/n_Scanner/nS_Scanner/scanner = new(code, options)
|
||||
var/list/tokens = scanner.Scan()
|
||||
var/datum/n_Parser/nS_Parser/parser = new(tokens, options)
|
||||
var/datum/node/BlockDefinition/GlobalBlock/program = parser.Parse()
|
||||
|
||||
var/list/returnerrors = list()
|
||||
|
||||
returnerrors += scanner.errors
|
||||
returnerrors += parser.errors
|
||||
|
||||
if(returnerrors.len)
|
||||
return returnerrors
|
||||
|
||||
interpreter = new(program)
|
||||
interpreter.persist = 1
|
||||
interpreter.Compiler= src
|
||||
|
||||
return returnerrors
|
||||
|
||||
/* -- Execute the compiled code -- */
|
||||
|
||||
/datum/TCS_Compiler/proc/Run(var/datum/signal/signal)
|
||||
if(!ready)
|
||||
return
|
||||
|
||||
if(!interpreter)
|
||||
return
|
||||
|
||||
interpreter.container = src
|
||||
|
||||
interpreter.SetVar("TAU", TAU) // value of tau
|
||||
interpreter.SetVar("PI", PI) // value of pi
|
||||
interpreter.SetVar("E", E) // value of e
|
||||
interpreter.SetVar("SQURT2", Sqrt2) // value of the square root of 2
|
||||
interpreter.SetVar("FALSE", 0) // boolean shortcut to 0
|
||||
interpreter.SetVar("false", 0) // boolean shortcut to 0
|
||||
interpreter.SetVar("TRUE", 1) // boolean shortcut to 1
|
||||
interpreter.SetVar("true", 1) // boolean shortcut to 1
|
||||
|
||||
interpreter.SetVar("NORTH", NORTH) // NORTH (1)
|
||||
interpreter.SetVar("SOUTH", SOUTH) // SOUTH (2)
|
||||
interpreter.SetVar("EAST", EAST) // EAST (4)
|
||||
interpreter.SetVar("WEST", WEST) // WEST (8)
|
||||
|
||||
// Channel macros
|
||||
interpreter.SetVar("$common", COMMON_FREQ)
|
||||
interpreter.SetVar("$science", SCI_FREQ)
|
||||
interpreter.SetVar("$command", COMM_FREQ)
|
||||
interpreter.SetVar("$medical", MED_FREQ)
|
||||
interpreter.SetVar("$engineering", ENG_FREQ)
|
||||
interpreter.SetVar("$security", SEC_FREQ)
|
||||
interpreter.SetVar("$supply", SUP_FREQ)
|
||||
|
||||
// Signal data
|
||||
|
||||
interpreter.SetVar("$content", signal.data["message"])
|
||||
interpreter.SetVar("$freq", signal.frequency)
|
||||
interpreter.SetVar("$source", signal.data["name"])
|
||||
interpreter.SetVar("$job", signal.data["job"])
|
||||
interpreter.SetVar("$sign", signal)
|
||||
interpreter.SetVar("$pass", !(signal.data["reject"])) // if the signal isn't rejected, pass = 1; if the signal IS rejected, pass = 0
|
||||
|
||||
// Set up the script procs
|
||||
|
||||
/*
|
||||
-> Send another signal to a server
|
||||
@format: broadcast(content, frequency, source, job)
|
||||
|
||||
@param content: Message to broadcast
|
||||
@param frequency: Frequency to broadcast to
|
||||
@param source: The name of the source you wish to imitate. Must be stored in stored_names list.
|
||||
@param job: The name of the job.
|
||||
*/
|
||||
interpreter.SetProc("broadcast", "tcombroadcast", signal, list("message", "freq", "source", "job"))
|
||||
|
||||
/*
|
||||
-> Send a code signal.
|
||||
@format: signal(frequency, code)
|
||||
|
||||
@param frequency: Frequency to send the signal to
|
||||
@param code: Encryption code to send the signal with
|
||||
*/
|
||||
interpreter.SetProc("signal", "signaler", signal, list("freq", "code"))
|
||||
|
||||
/*
|
||||
-> Store a value permanently to the server machine (not the actual game hosting machine, the ingame machine)
|
||||
@format: mem(address, value)
|
||||
|
||||
@param address: The memory address (string index) to store a value to
|
||||
@param value: The value to store to the memory address
|
||||
*/
|
||||
interpreter.SetProc("mem", "mem", signal, list("address", "value"))
|
||||
|
||||
/*
|
||||
-> Delay code for a given amount of deciseconds
|
||||
@format: sleep(time)
|
||||
|
||||
@param time: time to sleep in deciseconds (1/10th second)
|
||||
*/
|
||||
interpreter.SetProc("sleep", /proc/delay)
|
||||
|
||||
/*
|
||||
-> Replaces a string with another string
|
||||
@format: replace(string, substring, replacestring)
|
||||
|
||||
@param string: the string to search for substrings (best used with $content$ constant)
|
||||
@param substring: the substring to search for
|
||||
@param replacestring: the string to replace the substring with
|
||||
|
||||
*/
|
||||
interpreter.SetProc("replace", /proc/n_replacetext)
|
||||
|
||||
/*
|
||||
-> Locates an element/substring inside of a list or string
|
||||
@format: find(haystack, needle, start = 1, end = 0)
|
||||
|
||||
@param haystack: the container to search
|
||||
@param needle: the element to search for
|
||||
@param start: the position to start in
|
||||
@param end: the position to end in
|
||||
|
||||
*/
|
||||
interpreter.SetProc("find", /proc/smartfind)
|
||||
|
||||
/*
|
||||
-> Finds the length of a string or list
|
||||
@format: length(container)
|
||||
|
||||
@param container: the list or container to measure
|
||||
|
||||
*/
|
||||
interpreter.SetProc("length", /proc/smartlength)
|
||||
|
||||
/* -- Clone functions, carried from default BYOND procs --- */
|
||||
|
||||
// vector namespace
|
||||
interpreter.SetProc("vector", /proc/n_list)
|
||||
interpreter.SetProc("at", /proc/n_listpos)
|
||||
interpreter.SetProc("copy", /proc/n_listcopy)
|
||||
interpreter.SetProc("push_back", /proc/n_listadd)
|
||||
interpreter.SetProc("remove", /proc/n_listremove)
|
||||
interpreter.SetProc("cut", /proc/n_listcut)
|
||||
interpreter.SetProc("swap", /proc/n_listswap)
|
||||
interpreter.SetProc("insert", /proc/n_listinsert)
|
||||
|
||||
interpreter.SetProc("pick", /proc/n_pick)
|
||||
interpreter.SetProc("prob", /proc/prob_chance)
|
||||
interpreter.SetProc("substr", /proc/docopytext)
|
||||
|
||||
interpreter.SetProc("shuffle", /proc/shuffle)
|
||||
interpreter.SetProc("uniquevector", /proc/uniquelist)
|
||||
|
||||
interpreter.SetProc("text2vector", /proc/n_splittext)
|
||||
interpreter.SetProc("text2vectorEx",/proc/splittextEx)
|
||||
interpreter.SetProc("vector2text", /proc/vg_jointext)
|
||||
|
||||
// Strings
|
||||
interpreter.SetProc("lower", /proc/n_lower)
|
||||
interpreter.SetProc("upper", /proc/n_upper)
|
||||
interpreter.SetProc("explode", /proc/string_explode)
|
||||
interpreter.SetProc("repeat", /proc/n_repeat)
|
||||
interpreter.SetProc("reverse", /proc/reverse_text)
|
||||
interpreter.SetProc("tonum", /proc/n_str2num)
|
||||
interpreter.SetProc("capitalize", /proc/capitalize)
|
||||
//interpreter.SetProc("replacetextEx",/proc/n_replacetextEx)
|
||||
|
||||
// Numbers
|
||||
interpreter.SetProc("tostring", /proc/n_num2str)
|
||||
interpreter.SetProc("sqrt", /proc/n_sqrt)
|
||||
interpreter.SetProc("abs", /proc/n_abs)
|
||||
interpreter.SetProc("floor", /proc/Floor)
|
||||
interpreter.SetProc("ceil", /proc/Ceiling)
|
||||
interpreter.SetProc("round", /proc/n_round)
|
||||
interpreter.SetProc("clamp", /proc/n_clamp)
|
||||
interpreter.SetProc("inrange", /proc/IsInRange)
|
||||
interpreter.SetProc("rand", /proc/rand_chance)
|
||||
interpreter.SetProc("arctan", /proc/Atan2)
|
||||
interpreter.SetProc("lcm", /proc/Lcm)
|
||||
interpreter.SetProc("gcd", /proc/Gcd)
|
||||
interpreter.SetProc("mean", /proc/Mean)
|
||||
interpreter.SetProc("root", /proc/Root)
|
||||
interpreter.SetProc("sin", /proc/n_sin)
|
||||
interpreter.SetProc("cos", /proc/n_cos)
|
||||
interpreter.SetProc("arcsin", /proc/n_asin)
|
||||
interpreter.SetProc("arccos", /proc/n_acos)
|
||||
interpreter.SetProc("tan", /proc/Tan)
|
||||
interpreter.SetProc("csc", /proc/Csc)
|
||||
interpreter.SetProc("cot", /proc/Cot)
|
||||
interpreter.SetProc("sec", /proc/Sec)
|
||||
interpreter.SetProc("todegrees", /proc/ToDegrees)
|
||||
interpreter.SetProc("toradians", /proc/ToRadians)
|
||||
interpreter.SetProc("lerp", /proc/mix)
|
||||
interpreter.SetProc("max", /proc/n_max)
|
||||
interpreter.SetProc("min", /proc/n_min)
|
||||
|
||||
// End of Donkie~
|
||||
|
||||
// Time
|
||||
interpreter.SetProc("time", /proc/time)
|
||||
interpreter.SetProc("timestamp", /proc/timestamp)
|
||||
|
||||
// Run the compiled code
|
||||
interpreter.Run()
|
||||
|
||||
// Backwards-apply variables onto signal data
|
||||
/* sanitize (almost) EVERYTHING. fucking players can't be trusted with SHIT */
|
||||
|
||||
signal.data["message"] = interpreter.GetVar("$content")
|
||||
signal.frequency = interpreter.GetCleanVar("$freq", signal.frequency)
|
||||
|
||||
var/setname = interpreter.GetCleanVar("$source", signal.data["name"])
|
||||
|
||||
if(signal.data["name"] != setname)
|
||||
signal.data["realname"] = setname
|
||||
signal.data["name"] = setname
|
||||
signal.data["job"] = interpreter.GetCleanVar("$job", signal.data["job"])
|
||||
signal.data["reject"] = !(interpreter.GetCleanVar("$pass")) // set reject to the opposite of $pass
|
||||
|
||||
// If the message is invalid, just don't broadcast it!
|
||||
if(signal.data["message"] == "" || !signal.data["message"])
|
||||
signal.data["reject"] = 1
|
||||
|
||||
/* -- Actual language proc code -- */
|
||||
|
||||
/var/const/SIGNAL_COOLDOWN = 20 // 2 seconds
|
||||
|
||||
/datum/signal/proc/mem(var/address, var/value)
|
||||
if(istext(address))
|
||||
var/obj/machinery/telecomms/server/S = data["server"]
|
||||
|
||||
if(!value && value != 0)
|
||||
return S.memory[address]
|
||||
|
||||
else
|
||||
S.memory[address] = value
|
||||
|
||||
/datum/signal/proc/signaler(var/freq = COMMON_FREQ, var/code = 30)
|
||||
if(isnum(freq) && isnum(code))
|
||||
|
||||
var/obj/machinery/telecomms/server/S = data["server"]
|
||||
|
||||
if(S.last_signal + SIGNAL_COOLDOWN > world.timeofday && S.last_signal < MIDNIGHT_ROLLOVER)
|
||||
return
|
||||
S.last_signal = world.timeofday
|
||||
|
||||
var/datum/radio_frequency/connection = radio_controller.return_frequency(freq)
|
||||
|
||||
if(findtext(num2text(freq), ".")) // if the frequency has been set as a decimal
|
||||
freq *= 10 // shift the decimal one place
|
||||
|
||||
freq = sanitize_frequency(freq)
|
||||
|
||||
code = round(code)
|
||||
code = clamp(code, 0, 100)
|
||||
|
||||
var/datum/signal/signal = new /datum/signal
|
||||
signal.source = S
|
||||
signal.encryption = code
|
||||
signal.data["message"] = "ACTIVATE"
|
||||
|
||||
connection.post_signal(S, signal)
|
||||
|
||||
S.investigation_log(I_WIRES, "NTSL-triggered signaler activated by [S.id] - [format_frequency(frequency)]/[code]")
|
||||
|
||||
|
||||
/datum/signal/proc/tcombroadcast(var/message, var/freq, var/source, var/job)
|
||||
var/datum/signal/newsign = new /datum/signal
|
||||
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 || (!isnum(freq) && text2num(freq) == null))
|
||||
freq = COMMON_FREQ
|
||||
if(findtext(num2text(freq), ".")) // if the frequency has been set as a decimal
|
||||
freq *= 10 // shift the decimal one place
|
||||
|
||||
if(!job)
|
||||
job = "Unknown"
|
||||
|
||||
//SAY REWRITE RELATED CODE.
|
||||
//This code is a little hacky, but it *should* work. Even though it'll result in a virtual speaker referencing another virtual speaker. vOv
|
||||
var/atom/movable/virtualspeaker/virt = new /atom/movable/virtualspeaker(null)
|
||||
virt.name = source
|
||||
virt.job = job
|
||||
//END SAY REWRITE RELATED CODE.
|
||||
|
||||
|
||||
newsign.data["mob"] = virt
|
||||
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["type"] = 2 // artificial broadcast
|
||||
if(!isnum(freq))
|
||||
freq = text2num(freq)
|
||||
newsign.frequency = freq
|
||||
|
||||
var/datum/radio_frequency/connection = radio_controller.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"] = data["level"]
|
||||
|
||||
newsign.sanitize_data()
|
||||
|
||||
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
|
||||
|
||||
spawn(50)
|
||||
qdel(virt)
|
||||
210
code/modules/scripting/Implementations/Telecomms/Compiler.dm
Normal file
210
code/modules/scripting/Implementations/Telecomms/Compiler.dm
Normal file
@@ -0,0 +1,210 @@
|
||||
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
|
||||
|
||||
|
||||
/* --- Traffic Control Scripting Language --- */
|
||||
// Nanotrasen TCS Language - Made by Doohl
|
||||
|
||||
/datum/n_Interpreter/TCS_Interpreter/HandleError(datum/runtimeError/e)
|
||||
if(istype(Compiler,/datum/n_Compiler/TCS_Compiler))
|
||||
var/datum/n_Compiler/TCS_Compiler/TCS = Compiler
|
||||
TCS.Holder.add_entry(e.ToString(), "Execution Error")
|
||||
|
||||
/datum/n_Interpreter/TCS_Interpreter/AlertAdmins()
|
||||
if(Compiler && !alertadmins)
|
||||
if(istype(Compiler, /datum/n_Compiler/TCS_Compiler))
|
||||
var/datum/n_Compiler/TCS_Compiler/TCS = Compiler
|
||||
var/obj/machinery/telecomms/server/Holder = TCS.Holder
|
||||
var/message = "Potential crash-inducing NTSL script detected at telecommunications server [Holder] ([Holder.x], [Holder.y], [Holder.z])."
|
||||
|
||||
alertadmins = 1
|
||||
message_admins(message, 1)
|
||||
|
||||
/datum/n_Compiler/TCS_Compiler
|
||||
var/obj/machinery/telecomms/server/Holder // the server that is running the code
|
||||
interptype = /datum/n_Interpreter/TCS_Interpreter
|
||||
|
||||
/datum/n_Compiler/TCS_Compiler/GC()
|
||||
Holder = null
|
||||
..()
|
||||
|
||||
/datum/n_Compiler/TCS_Compiler/SetVars(var/datum/signal/signal)
|
||||
..()
|
||||
|
||||
// Channel macros
|
||||
interpreter.SetVar("$common", COMMON_FREQ)
|
||||
interpreter.SetVar("$science", SCI_FREQ)
|
||||
interpreter.SetVar("$command", COMM_FREQ)
|
||||
interpreter.SetVar("$medical", MED_FREQ)
|
||||
interpreter.SetVar("$engineering", ENG_FREQ)
|
||||
interpreter.SetVar("$security", SEC_FREQ)
|
||||
interpreter.SetVar("$supply", SUP_FREQ)
|
||||
|
||||
// Signal data
|
||||
|
||||
interpreter.SetVar("$content", signal.data["message"])
|
||||
interpreter.SetVar("$freq", signal.frequency)
|
||||
interpreter.SetVar("$source", signal.data["name"])
|
||||
interpreter.SetVar("$job", signal.data["job"])
|
||||
interpreter.SetVar("$sign", signal)
|
||||
interpreter.SetVar("$pass", !(signal.data["reject"])) // if the signal isn't rejected, pass = 1; if the signal IS rejected, pass = 0
|
||||
|
||||
/datum/n_Compiler/TCS_Compiler/SetProcs(var/datum/signal/signal)
|
||||
// Set up the script procs
|
||||
|
||||
/*
|
||||
-> Send another signal to a server
|
||||
@format: broadcast(content, frequency, source, job)
|
||||
|
||||
@param content: Message to broadcast
|
||||
@param frequency: Frequency to broadcast to
|
||||
@param source: The name of the source you wish to imitate. Must be stored in stored_names list.
|
||||
@param job: The name of the job.
|
||||
*/
|
||||
interpreter.SetProc("broadcast", "tcombroadcast", signal, list("message", "freq", "source", "job"))
|
||||
|
||||
/*
|
||||
-> Send a code signal.
|
||||
@format: signal(frequency, code)
|
||||
|
||||
@param frequency: Frequency to send the signal to
|
||||
@param code: Encryption code to send the signal with
|
||||
*/
|
||||
interpreter.SetProc("signal", "tcs_signaler", signal, list("freq", "code"))
|
||||
|
||||
/*
|
||||
-> Store a value permanently to the server machine (not the actual game hosting machine, the ingame machine)
|
||||
@format: tcs_mem(address, value)
|
||||
|
||||
@param address: The memory address (string index) to store a value to
|
||||
@param value: The value to store to the memory address
|
||||
*/
|
||||
interpreter.SetProc("mem", "tcs_mem", signal, list("address", "value"))
|
||||
|
||||
..()
|
||||
|
||||
/* -- Execute the compiled code -- */
|
||||
|
||||
/datum/n_Compiler/TCS_Compiler/Run(var/datum/signal/signal)
|
||||
..(signal)
|
||||
|
||||
// Backwards-apply variables onto signal data
|
||||
/* sanitize (almost) EVERYTHING. fucking players can't be trusted with SHIT */
|
||||
|
||||
signal.data["message"] = interpreter.GetVar("$content")
|
||||
signal.frequency = interpreter.GetCleanVar("$freq", signal.frequency)
|
||||
|
||||
var/setname = interpreter.GetCleanVar("$source", signal.data["name"])
|
||||
|
||||
if(signal.data["name"] != setname)
|
||||
signal.data["realname"] = setname
|
||||
signal.data["name"] = setname
|
||||
signal.data["job"] = interpreter.GetCleanVar("$job", signal.data["job"])
|
||||
signal.data["reject"] = !(interpreter.GetCleanVar("$pass")) // set reject to the opposite of $pass
|
||||
|
||||
// If the message is invalid, just don't broadcast it!
|
||||
if(signal.data["message"] == "" || !signal.data["message"])
|
||||
signal.data["reject"] = 1
|
||||
|
||||
/* -- Actual language proc code -- */
|
||||
|
||||
/var/const/SIGNAL_COOLDOWN = 20 // 2 seconds
|
||||
|
||||
/datum/signal/proc/tcs_mem(var/address, var/value)
|
||||
if(istext(address))
|
||||
var/obj/machinery/telecomms/server/S = data["server"]
|
||||
|
||||
if(!value && value != 0)
|
||||
return S.memory[address]
|
||||
|
||||
else
|
||||
S.memory[address] = value
|
||||
|
||||
/datum/signal/proc/tcs_signaler(var/freq = COMMON_FREQ, var/code = 30)
|
||||
if(isnum(freq) && isnum(code))
|
||||
|
||||
var/obj/machinery/telecomms/server/S = data["server"]
|
||||
|
||||
if(S.last_signal + SIGNAL_COOLDOWN > world.timeofday && S.last_signal < MIDNIGHT_ROLLOVER)
|
||||
return
|
||||
S.last_signal = world.timeofday
|
||||
|
||||
var/datum/radio_frequency/connection = radio_controller.return_frequency(freq)
|
||||
|
||||
if(findtext(num2text(freq), ".")) // if the frequency has been set as a decimal
|
||||
freq *= 10 // shift the decimal one place
|
||||
|
||||
freq = sanitize_frequency(freq)
|
||||
|
||||
code = round(code)
|
||||
code = clamp(code, 0, 100)
|
||||
|
||||
var/datum/signal/signal = new /datum/signal
|
||||
signal.source = S
|
||||
signal.encryption = code
|
||||
signal.data["message"] = "ACTIVATE"
|
||||
|
||||
connection.post_signal(S, signal)
|
||||
|
||||
S.investigation_log(I_WIRES, "NTSL-triggered signaler activated by [S.id] - [format_frequency(frequency)]/[code]")
|
||||
|
||||
|
||||
/datum/signal/proc/tcombroadcast(var/message, var/freq, var/source, var/job)
|
||||
var/datum/signal/newsign = new /datum/signal
|
||||
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 || (!isnum(freq) && text2num(freq) == null))
|
||||
freq = COMMON_FREQ
|
||||
if(findtext(num2text(freq), ".")) // if the frequency has been set as a decimal
|
||||
freq *= 10 // shift the decimal one place
|
||||
|
||||
if(!job)
|
||||
job = "Unknown"
|
||||
|
||||
//SAY REWRITE RELATED CODE.
|
||||
//This code is a little hacky, but it *should* work. Even though it'll result in a virtual speaker referencing another virtual speaker. vOv
|
||||
var/atom/movable/virtualspeaker/virt = new /atom/movable/virtualspeaker(null)
|
||||
virt.name = source
|
||||
virt.job = job
|
||||
//END SAY REWRITE RELATED CODE.
|
||||
|
||||
|
||||
newsign.data["mob"] = virt
|
||||
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["type"] = 2 // artificial broadcast
|
||||
if(!isnum(freq))
|
||||
freq = text2num(freq)
|
||||
newsign.frequency = freq
|
||||
|
||||
var/datum/radio_frequency/connection = radio_controller.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"] = data["level"]
|
||||
|
||||
newsign.sanitize_data()
|
||||
|
||||
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
|
||||
|
||||
spawn(50)
|
||||
qdel(virt)
|
||||
@@ -0,0 +1,93 @@
|
||||
/datum/n_Interpreter/vocal_implant/HandleError(datum/runtimeError/e)
|
||||
if(istype(Compiler,/datum/n_Compiler/vocal_implant))
|
||||
var/datum/n_Compiler/vocal_implant/VI = Compiler
|
||||
if(istype(VI.Holder.loc,/obj/item/weapon/implanter/vocal))
|
||||
var/obj/item/weapon/implanter/vocal/V = VI.Holder.loc
|
||||
V.say(e.ToString())
|
||||
|
||||
/datum/n_Interpreter/vocal_implant/AlertAdmins()
|
||||
if(Compiler && !alertadmins)
|
||||
if(istype(Compiler, /datum/n_Compiler/vocal_implant))
|
||||
var/datum/n_Compiler/vocal_implant/V = Compiler
|
||||
var/obj/item/weapon/implant/vocal/VI = V.Holder
|
||||
if(VI)
|
||||
var/turf/T = get_turf(VI)
|
||||
var/mob/M = get_holder_of_type(VI,/mob)
|
||||
var/message = "Potential crash-inducing NTSL script detected in vocal implant[M ? " held by [M]" :""] at [T.x], [T.y], [T.z]."
|
||||
|
||||
alertadmins = 1
|
||||
message_admins(message, 1)
|
||||
|
||||
/datum/n_Compiler/vocal_implant
|
||||
var/obj/item/weapon/implant/vocal/Holder // the implant that is running the code
|
||||
interptype = /datum/n_Interpreter/vocal_implant
|
||||
|
||||
/datum/n_Compiler/vocal_implant/GC()
|
||||
Holder = null
|
||||
..()
|
||||
|
||||
/datum/n_Compiler/vocal_implant/SetVars(var/datum/signal/signal)
|
||||
..()
|
||||
// Signal data
|
||||
interpreter.SetVar("$content", signal.data["message"])
|
||||
interpreter.SetVar("$pass", !(signal.data["reject"])) // if the signal isn't rejected, pass = 1; if the signal IS rejected, pass = 0
|
||||
|
||||
/datum/n_Compiler/vocal_implant/SetProcs(var/datum/signal/signal)
|
||||
// Set up the script procs
|
||||
|
||||
/*
|
||||
-> Send another signal to a speaker, same name as telecomms proc for ease of memory.
|
||||
@format: broadcast(content)
|
||||
|
||||
@param content: Message to broadcast
|
||||
*/
|
||||
interpreter.SetProc("broadcast", "vibroadcast", signal, list("message"))
|
||||
|
||||
/*
|
||||
-> Store a value permanently to the server machine (not the actual game hosting machine, the ingame machine)
|
||||
@format: tcs_mem(address, value)
|
||||
|
||||
@param address: The memory address (string index) to store a value to
|
||||
@param value: The value to store to the memory address
|
||||
*/
|
||||
interpreter.SetProc("mem", "vi_mem", signal, list("address", "value"))
|
||||
|
||||
..()
|
||||
|
||||
/* -- Execute the compiled code -- */
|
||||
|
||||
/datum/n_Compiler/vocal_implant/Run(var/datum/signal/signal)
|
||||
..(signal)
|
||||
|
||||
// Backwards-apply variables onto signal data
|
||||
|
||||
signal.data["message"] = interpreter.GetVar("$content")
|
||||
signal.data["reject"] = !(interpreter.GetCleanVar("$pass")) // set reject to the opposite of $pass
|
||||
|
||||
// If the message is invalid, just don't broadcast it!
|
||||
if(signal.data["message"] == "" || !signal.data["message"])
|
||||
signal.data["reject"] = 1
|
||||
|
||||
/datum/signal/proc/vi_mem(var/address, var/value)
|
||||
if(istext(address))
|
||||
var/obj/item/weapon/implant/vocal/V = data["implant"]
|
||||
|
||||
if(!value && value != 0)
|
||||
return V.memory[address]
|
||||
|
||||
else
|
||||
V.memory[address] = value
|
||||
|
||||
/datum/signal/proc/vibroadcast(var/message)
|
||||
var/obj/item/weapon/implant/vocal/V = data["implant"]
|
||||
var/atom/movable/speaker = V.imp_in || V.loc
|
||||
|
||||
if(!ismob(speaker) || !istype(speaker,/obj/item/weapon/implanter/vocal))
|
||||
error("[src] is not implanted or in an implanter.")
|
||||
return
|
||||
|
||||
if((!message || message == "") && message != 0)
|
||||
message = "*beep*"
|
||||
|
||||
speaker.say(message)
|
||||
message_admins("The [V] in [speaker] made \him say \"[message]\" [formatJumpTo(speaker)]")
|
||||
117
code/modules/scripting/Implementations/vocalimplant/IDE.dm
Normal file
117
code/modules/scripting/Implementations/vocalimplant/IDE.dm
Normal file
@@ -0,0 +1,117 @@
|
||||
/client/verb/visave()
|
||||
set hidden = 1
|
||||
if(implant_check(mob))
|
||||
var/obj/item/weapon/implanter/vocal/V = mob.get_active_hand()
|
||||
if(V.imp)
|
||||
var/obj/item/weapon/implant/vocal/VI = V.imp
|
||||
var/vicode = winget(src, "vicode", "text")
|
||||
VI.setcode( vicode ) // this actually saves the code from input to the implant
|
||||
src << output(null, "vierror") // clear the errors
|
||||
else
|
||||
src << output(null, "vierror")
|
||||
src << output("<font color = red>Failed to save: Unable to locate vocal implant. (Back up your code before exiting the window!)</font color>", "vierror")
|
||||
else
|
||||
src << output(null, "vierror")
|
||||
src << output("<font color = red>Failed to save: Unable to locate implant. (Back up your code before exiting the window!)</font color>", "vierror")
|
||||
|
||||
|
||||
/client/verb/vicompile()
|
||||
set hidden = 1
|
||||
if(implant_check(mob))
|
||||
var/obj/item/weapon/implanter/vocal/V = mob.get_active_hand()
|
||||
if(V.imp)
|
||||
var/obj/item/weapon/implant/vocal/VI = V.imp
|
||||
VI.setcode( winget(src, "vicode", "text") ) // save code first
|
||||
|
||||
spawn(0)
|
||||
// Output all the compile-time errors
|
||||
src << output(null, "vierror")
|
||||
src << output("<font color = black>Please wait, compiling...</font>", "vierror")
|
||||
|
||||
var/list/compileerrors = VI.compile(mob) // then compile the code!
|
||||
if(!implant_check(mob))
|
||||
return
|
||||
|
||||
if(compileerrors.len)
|
||||
src << output("<b>Compile Errors</b>", "vierror")
|
||||
for(var/datum/scriptError/e in compileerrors)
|
||||
src << output("<font color = red>\t>[e.message]</font color>", "vierror")
|
||||
src << output("([compileerrors.len] errors)", "vierror")
|
||||
|
||||
else
|
||||
src << output("<font color = blue>vi compilation successful!</font color>", "vierror")
|
||||
src << output("(0 errors)", "vierror")
|
||||
|
||||
else
|
||||
src << output(null, "vierror")
|
||||
src << output("<font color = red>Failed to compile: Unable to locate vocal implant. (Back up your code before exiting the window!)</font color>", "vierror")
|
||||
else
|
||||
src << output(null, "vierror")
|
||||
src << output("<font color = red>Failed to compile: Unable to locate implant. (Back up your code before exiting the window!)</font color>", "vierror")
|
||||
|
||||
/client/verb/virun()
|
||||
set hidden = 1
|
||||
if(implant_check(mob))
|
||||
var/obj/item/weapon/implanter/vocal/V = mob.get_active_hand()
|
||||
if(V.imp)
|
||||
var/obj/item/weapon/implant/vocal/VI = V.imp
|
||||
|
||||
var/datum/signal/signal = new /datum/signal
|
||||
signal.data["message"] = ""
|
||||
signal.data["reject"] = 0
|
||||
signal.data["implant"] = VI
|
||||
|
||||
VI.Compiler.Run(signal)
|
||||
if(!signal.data["reject"])
|
||||
V.say(signal.data["message"])
|
||||
|
||||
else
|
||||
src << output(null, "vierror")
|
||||
src << output("<font color = red>Failed to run: Unable to locate vocal implant. (Back up your code before exiting the window!)</font color>", "vierror")
|
||||
else
|
||||
src << output(null, "vierror")
|
||||
src << output("<font color = red>Failed to run: Unable to locate implant. (Back up your code before exiting the window!)</font color>", "vierror")
|
||||
|
||||
/client/verb/virevert()
|
||||
set hidden = 1
|
||||
if(implant_check(mob))
|
||||
var/obj/item/weapon/implanter/vocal/V = mob.get_active_hand()
|
||||
if(V.imp)
|
||||
var/obj/item/weapon/implant/vocal/VI = V.imp
|
||||
|
||||
// Replace quotation marks with quotation macros for proper winset() compatibility
|
||||
var/showcode = replacetext(VI.rawcode, "\\\"", "\\\\\"")
|
||||
showcode = replacetext(showcode, "\"", "\\\"")
|
||||
|
||||
winset(mob, "vicode", "text=\"[showcode]\"")
|
||||
|
||||
src << output(null, "vierror") // clear the errors
|
||||
else
|
||||
src << output(null, "vierror")
|
||||
src << output("<font color = red>Failed to revert: Unable to locate vocal implant.</font color>", "vierror")
|
||||
else
|
||||
src << output(null, "vierror")
|
||||
src << output("<font color = red>Failed to revert: Unable to locate implant.</font color>", "vierror")
|
||||
|
||||
|
||||
/client/verb/viclearmem()
|
||||
set hidden = 1
|
||||
if(implant_check(mob))
|
||||
var/obj/item/weapon/implanter/vocal/V = mob.get_active_hand()
|
||||
if(V.imp)
|
||||
var/obj/item/weapon/implant/vocal/VI = V.imp
|
||||
VI.memory = list() // clear the memory
|
||||
// Show results
|
||||
src << output(null, "vierror")
|
||||
src << output("<font color = blue>Implant memory cleared!</font color>", "vierror")
|
||||
else
|
||||
src << output(null, "vierror")
|
||||
src << output("<font color = red>Failed to clear memory: Unable to locate vocal implant.</font color>", "vierror")
|
||||
else
|
||||
src << output(null, "vierror")
|
||||
src << output("<font color = red>Failed to clear memory: Unable to locate implant.</font color>", "vierror")
|
||||
|
||||
/proc/implant_check(var/mob/mob)
|
||||
if(mob && istype(mob.get_active_hand(),/obj/item/weapon/implanter/vocal))
|
||||
return 1
|
||||
return 0
|
||||
@@ -18,12 +18,13 @@
|
||||
var/datum/scope/curScope
|
||||
var/datum/scope/globalScope
|
||||
|
||||
var/datum/node/BlockDefinition/program
|
||||
var/datum/node/statement/FunctionDefinition/curFunction
|
||||
var/datum/node/BlockDefinition/program
|
||||
var/datum/node/statement/FunctionDefinition/curFunction
|
||||
var/datum/stack/scopes = new()
|
||||
var/datum/stack/functions = new()
|
||||
|
||||
var/datum/container // associated container for interpeter
|
||||
var/datum/n_Compiler/Compiler
|
||||
|
||||
/*
|
||||
Var: status
|
||||
A variable indicating that the rest of the current block should be skipped. This may be set to any combination of <Status Macros>.
|
||||
@@ -57,7 +58,7 @@
|
||||
Set ourselves to Garbage Collect
|
||||
*/
|
||||
/datum/n_Interpreter/proc/GC()
|
||||
container = null
|
||||
Compiler = null
|
||||
|
||||
/*
|
||||
Proc: RaiseError
|
||||
@@ -85,14 +86,7 @@ Proc: AlertAdmins
|
||||
Alerts the admins of a script that is bad.
|
||||
*/
|
||||
/datum/n_Interpreter/proc/AlertAdmins()
|
||||
if(container && !alertadmins)
|
||||
if(istype(container, /datum/TCS_Compiler))
|
||||
var/datum/TCS_Compiler/Compiler = container
|
||||
var/obj/machinery/telecomms/server/Holder = Compiler.Holder
|
||||
var/message = "Potential crash-inducing NTSL script detected at telecommunications server [Compiler.Holder] ([Holder.x], [Holder.y], [Holder.z])."
|
||||
|
||||
alertadmins = 1
|
||||
message_admins(message, 1)
|
||||
return
|
||||
/*
|
||||
Proc: RunBlock
|
||||
Runs each statement in a block of code.
|
||||
|
||||
175
code/modules/scripting/compiler.dm
Normal file
175
code/modules/scripting/compiler.dm
Normal file
@@ -0,0 +1,175 @@
|
||||
/datum/n_Compiler
|
||||
var/datum/n_Interpreter/interpreter
|
||||
var/ready = 1 // 1 if ready to run code
|
||||
var/interptype = /datum/n_Interpreter
|
||||
|
||||
/* -- Set ourselves to Garbage Collect -- */
|
||||
|
||||
/datum/n_Compiler/proc/GC()
|
||||
if(interpreter)
|
||||
interpreter.GC()
|
||||
|
||||
|
||||
/* -- Compile a raw block of text -- */
|
||||
|
||||
/datum/n_Compiler/proc/Compile(code as message)
|
||||
var/datum/n_scriptOptions/nS_Options/options = new()
|
||||
var/datum/n_Scanner/nS_Scanner/scanner = new(code, options)
|
||||
var/list/tokens = scanner.Scan()
|
||||
var/datum/n_Parser/nS_Parser/parser = new(tokens, options)
|
||||
var/datum/node/BlockDefinition/GlobalBlock/program = parser.Parse()
|
||||
|
||||
var/list/returnerrors = list()
|
||||
|
||||
returnerrors += scanner.errors
|
||||
returnerrors += parser.errors
|
||||
|
||||
if(returnerrors.len)
|
||||
return returnerrors
|
||||
|
||||
interpreter = new interptype(program)
|
||||
interpreter.persist = 1
|
||||
interpreter.Compiler= src
|
||||
|
||||
return returnerrors
|
||||
|
||||
/* -- Execute the compiled code -- */
|
||||
|
||||
/datum/n_Compiler/proc/Run(var/datum/signal/signal)
|
||||
if(!ready)
|
||||
return
|
||||
|
||||
if(!interpreter)
|
||||
return
|
||||
|
||||
SetVars(signal)
|
||||
SetProcs(signal)
|
||||
|
||||
// Run the compiled code
|
||||
interpreter.Run()
|
||||
|
||||
/datum/n_Compiler/proc/SetProcs(var/datum/signal/signal)
|
||||
// Set up the script procs
|
||||
|
||||
/*
|
||||
-> Delay code for a given amount of deciseconds
|
||||
@format: sleep(time)
|
||||
|
||||
@param time: time to sleep in deciseconds (1/10th second)
|
||||
*/
|
||||
interpreter.SetProc("sleep", /proc/delay)
|
||||
|
||||
/*
|
||||
-> Replaces a string with another string
|
||||
@format: replace(string, substring, replacestring)
|
||||
|
||||
@param string: the string to search for substrings (best used with $content$ constant)
|
||||
@param substring: the substring to search for
|
||||
@param replacestring: the string to replace the substring with
|
||||
|
||||
*/
|
||||
interpreter.SetProc("replace", /proc/n_replacetext)
|
||||
|
||||
/*
|
||||
-> Locates an element/substring inside of a list or string
|
||||
@format: find(haystack, needle, start = 1, end = 0)
|
||||
|
||||
@param haystack: the container to search
|
||||
@param needle: the element to search for
|
||||
@param start: the position to start in
|
||||
@param end: the position to end in
|
||||
|
||||
*/
|
||||
interpreter.SetProc("find", /proc/smartfind)
|
||||
|
||||
/*
|
||||
-> Finds the length of a string or list
|
||||
@format: length(container)
|
||||
|
||||
@param container: the list or container to measure
|
||||
|
||||
*/
|
||||
interpreter.SetProc("length", /proc/smartlength)
|
||||
|
||||
/* -- Clone functions, carried from default BYOND procs --- */
|
||||
|
||||
// vector namespace
|
||||
interpreter.SetProc("vector", /proc/n_list)
|
||||
interpreter.SetProc("at", /proc/n_listpos)
|
||||
interpreter.SetProc("copy", /proc/n_listcopy)
|
||||
interpreter.SetProc("push_back", /proc/n_listadd)
|
||||
interpreter.SetProc("remove", /proc/n_listremove)
|
||||
interpreter.SetProc("cut", /proc/n_listcut)
|
||||
interpreter.SetProc("swap", /proc/n_listswap)
|
||||
interpreter.SetProc("insert", /proc/n_listinsert)
|
||||
|
||||
interpreter.SetProc("pick", /proc/n_pick)
|
||||
interpreter.SetProc("prob", /proc/prob_chance)
|
||||
interpreter.SetProc("substr", /proc/docopytext)
|
||||
|
||||
interpreter.SetProc("shuffle", /proc/shuffle)
|
||||
interpreter.SetProc("uniquevector", /proc/uniquelist)
|
||||
|
||||
interpreter.SetProc("text2vector", /proc/n_splittext)
|
||||
interpreter.SetProc("text2vectorEx",/proc/splittextEx)
|
||||
interpreter.SetProc("vector2text", /proc/vg_jointext)
|
||||
|
||||
// Strings
|
||||
interpreter.SetProc("lower", /proc/n_lower)
|
||||
interpreter.SetProc("upper", /proc/n_upper)
|
||||
interpreter.SetProc("explode", /proc/string_explode)
|
||||
interpreter.SetProc("repeat", /proc/n_repeat)
|
||||
interpreter.SetProc("reverse", /proc/reverse_text)
|
||||
interpreter.SetProc("tonum", /proc/n_str2num)
|
||||
interpreter.SetProc("capitalize", /proc/capitalize)
|
||||
//interpreter.SetProc("replacetextEx",/proc/n_replacetextEx)
|
||||
|
||||
// Numbers
|
||||
interpreter.SetProc("tostring", /proc/n_num2str)
|
||||
interpreter.SetProc("sqrt", /proc/n_sqrt)
|
||||
interpreter.SetProc("abs", /proc/n_abs)
|
||||
interpreter.SetProc("floor", /proc/Floor)
|
||||
interpreter.SetProc("ceil", /proc/Ceiling)
|
||||
interpreter.SetProc("round", /proc/n_round)
|
||||
interpreter.SetProc("clamp", /proc/n_clamp)
|
||||
interpreter.SetProc("inrange", /proc/IsInRange)
|
||||
interpreter.SetProc("rand", /proc/rand_chance)
|
||||
interpreter.SetProc("arctan", /proc/Atan2)
|
||||
interpreter.SetProc("lcm", /proc/Lcm)
|
||||
interpreter.SetProc("gcd", /proc/Gcd)
|
||||
interpreter.SetProc("mean", /proc/Mean)
|
||||
interpreter.SetProc("root", /proc/Root)
|
||||
interpreter.SetProc("sin", /proc/n_sin)
|
||||
interpreter.SetProc("cos", /proc/n_cos)
|
||||
interpreter.SetProc("arcsin", /proc/n_asin)
|
||||
interpreter.SetProc("arccos", /proc/n_acos)
|
||||
interpreter.SetProc("tan", /proc/Tan)
|
||||
interpreter.SetProc("csc", /proc/Csc)
|
||||
interpreter.SetProc("cot", /proc/Cot)
|
||||
interpreter.SetProc("sec", /proc/Sec)
|
||||
interpreter.SetProc("todegrees", /proc/ToDegrees)
|
||||
interpreter.SetProc("toradians", /proc/ToRadians)
|
||||
interpreter.SetProc("lerp", /proc/mix)
|
||||
interpreter.SetProc("max", /proc/n_max)
|
||||
interpreter.SetProc("min", /proc/n_min)
|
||||
|
||||
// End of Donkie~
|
||||
|
||||
// Time
|
||||
interpreter.SetProc("time", /proc/time)
|
||||
interpreter.SetProc("timestamp", /proc/timestamp)
|
||||
|
||||
/datum/n_Compiler/proc/SetVars(var/datum/signal/signal)
|
||||
interpreter.SetVar("TAU", TAU) // value of tau
|
||||
interpreter.SetVar("PI", PI) // value of pi
|
||||
interpreter.SetVar("E", E) // value of e
|
||||
interpreter.SetVar("SQURT2", Sqrt2) // value of the square root of 2
|
||||
interpreter.SetVar("FALSE", 0) // boolean shortcut to 0
|
||||
interpreter.SetVar("false", 0) // boolean shortcut to 0
|
||||
interpreter.SetVar("TRUE", 1) // boolean shortcut to 1
|
||||
interpreter.SetVar("true", 1) // boolean shortcut to 1
|
||||
|
||||
interpreter.SetVar("NORTH", NORTH) // NORTH (1)
|
||||
interpreter.SetVar("SOUTH", SOUTH) // SOUTH (2)
|
||||
interpreter.SetVar("EAST", EAST) // EAST (4)
|
||||
interpreter.SetVar("WEST", WEST) // WEST (8)
|
||||
@@ -778,6 +778,86 @@ window "Telecomms IDE"
|
||||
multi-line = true
|
||||
no-command = true
|
||||
|
||||
window "Vocal Implant IDE"
|
||||
elem "Vocal Implant IDE"
|
||||
type = MAIN
|
||||
pos = 281,0
|
||||
size = 569x582
|
||||
anchor1 = none
|
||||
anchor2 = none
|
||||
background-color = #ffffff
|
||||
is-visible = false
|
||||
saved-params = "pos;size;is-minimized;is-maximized"
|
||||
title = "Vocal Implant IDE"
|
||||
statusbar = false
|
||||
on-close = "exitvi"
|
||||
elem "button5"
|
||||
type = BUTTON
|
||||
pos = 209,464
|
||||
size = 70x20
|
||||
anchor1 = 37,80
|
||||
anchor2 = 49,83
|
||||
saved-params = "is-checked"
|
||||
text = "Clear Memory"
|
||||
command = "viclearmem"
|
||||
elem "button4"
|
||||
type = BUTTON
|
||||
pos = 157,464
|
||||
size = 52x20
|
||||
anchor1 = 28,80
|
||||
anchor2 = 37,83
|
||||
saved-params = "is-checked"
|
||||
text = "Revert"
|
||||
command = "virevert"
|
||||
elem "button3"
|
||||
type = BUTTON
|
||||
pos = 105,464
|
||||
size = 52x20
|
||||
anchor1 = 18,80
|
||||
anchor2 = 28,83
|
||||
saved-params = "is-checked"
|
||||
text = "Execute"
|
||||
command = "virun"
|
||||
elem "vierror"
|
||||
type = OUTPUT
|
||||
pos = 0,488
|
||||
size = 566x94
|
||||
anchor1 = 0,84
|
||||
anchor2 = 99,100
|
||||
font-family = "sans-serif"
|
||||
font-size = 9
|
||||
saved-params = "max-lines"
|
||||
elem "button2"
|
||||
type = BUTTON
|
||||
pos = 53,464
|
||||
size = 52x20
|
||||
anchor1 = 9,80
|
||||
anchor2 = 18,83
|
||||
saved-params = "is-checked"
|
||||
text = "Compile"
|
||||
command = "vicompile"
|
||||
elem "button1"
|
||||
type = BUTTON
|
||||
pos = 0,464
|
||||
size = 53x20
|
||||
anchor1 = 0,80
|
||||
anchor2 = 9,83
|
||||
saved-params = "is-checked"
|
||||
text = "Save"
|
||||
command = "visave"
|
||||
elem "vicode"
|
||||
type = INPUT
|
||||
pos = 0,0
|
||||
size = 569x464
|
||||
anchor1 = 0,0
|
||||
anchor2 = 100,80
|
||||
font-family = "Courier"
|
||||
font-size = 10
|
||||
saved-params = ""
|
||||
command = "cancel"
|
||||
multi-line = true
|
||||
no-command = true
|
||||
|
||||
window "mainwindow"
|
||||
elem "mainwindow"
|
||||
type = MAIN
|
||||
|
||||
@@ -760,6 +760,86 @@ window "Telecomms IDE"
|
||||
multi-line = true
|
||||
no-command = true
|
||||
|
||||
window "Vocal Implant IDE"
|
||||
elem "Vocal Implant IDE"
|
||||
type = MAIN
|
||||
pos = 281,0
|
||||
size = 569x582
|
||||
anchor1 = none
|
||||
anchor2 = none
|
||||
background-color = #ffffff
|
||||
is-visible = false
|
||||
saved-params = "pos;size;is-minimized;is-maximized"
|
||||
title = "Vocal Implant IDE"
|
||||
statusbar = false
|
||||
on-close = "exitvi"
|
||||
elem "button5"
|
||||
type = BUTTON
|
||||
pos = 209,464
|
||||
size = 70x20
|
||||
anchor1 = 37,80
|
||||
anchor2 = 49,83
|
||||
saved-params = "is-checked"
|
||||
text = "Clear Memory"
|
||||
command = "viclearmem"
|
||||
elem "button4"
|
||||
type = BUTTON
|
||||
pos = 157,464
|
||||
size = 52x20
|
||||
anchor1 = 28,80
|
||||
anchor2 = 37,83
|
||||
saved-params = "is-checked"
|
||||
text = "Revert"
|
||||
command = "virevert"
|
||||
elem "button3"
|
||||
type = BUTTON
|
||||
pos = 105,464
|
||||
size = 52x20
|
||||
anchor1 = 18,80
|
||||
anchor2 = 28,83
|
||||
saved-params = "is-checked"
|
||||
text = "Execute"
|
||||
command = "virun"
|
||||
elem "vierror"
|
||||
type = OUTPUT
|
||||
pos = 0,488
|
||||
size = 566x94
|
||||
anchor1 = 0,84
|
||||
anchor2 = 99,100
|
||||
font-family = "sans-serif"
|
||||
font-size = 9
|
||||
saved-params = "max-lines"
|
||||
elem "button2"
|
||||
type = BUTTON
|
||||
pos = 53,464
|
||||
size = 52x20
|
||||
anchor1 = 9,80
|
||||
anchor2 = 18,83
|
||||
saved-params = "is-checked"
|
||||
text = "Compile"
|
||||
command = "vicompile"
|
||||
elem "button1"
|
||||
type = BUTTON
|
||||
pos = 0,464
|
||||
size = 53x20
|
||||
anchor1 = 0,80
|
||||
anchor2 = 9,83
|
||||
saved-params = "is-checked"
|
||||
text = "Save"
|
||||
command = "visave"
|
||||
elem "vicode"
|
||||
type = INPUT
|
||||
pos = 0,0
|
||||
size = 569x464
|
||||
anchor1 = 0,0
|
||||
anchor2 = 100,80
|
||||
font-family = "Courier"
|
||||
font-size = 10
|
||||
saved-params = ""
|
||||
command = "cancel"
|
||||
multi-line = true
|
||||
no-command = true
|
||||
|
||||
window "mainwindow"
|
||||
elem "mainwindow"
|
||||
type = MAIN
|
||||
|
||||
@@ -1148,6 +1148,7 @@
|
||||
#include "code\game\objects\items\weapons\implants\types\pax_implant.dm"
|
||||
#include "code\game\objects\items\weapons\implants\types\tracking_implant.dm"
|
||||
#include "code\game\objects\items\weapons\implants\types\uplink_implant.dm"
|
||||
#include "code\game\objects\items\weapons\implants\types\vocal_implant.dm"
|
||||
#include "code\game\objects\items\weapons\melee\energy.dm"
|
||||
#include "code\game\objects\items\weapons\melee\misc.dm"
|
||||
#include "code\game\objects\items\weapons\storage\backpack.dm"
|
||||
@@ -2589,8 +2590,8 @@
|
||||
#include "code\modules\research\xenoarchaeology\tools\tools_locater.dm"
|
||||
#include "code\modules\research\xenoarchaeology\tools\tools_pickaxe.dm"
|
||||
#include "code\modules\runescape\runescape_pvp.dm"
|
||||
#include "code\modules\scripting\compiler.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"
|
||||
@@ -2599,7 +2600,10 @@
|
||||
#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\Implementations\Telecomms\Compiler.dm"
|
||||
#include "code\modules\scripting\Implementations\Telecomms\IDE.dm"
|
||||
#include "code\modules\scripting\Implementations\vocalimplant\Compiler.dm"
|
||||
#include "code\modules\scripting\Implementations\vocalimplant\IDE.dm"
|
||||
#include "code\modules\scripting\Interpreter\Evaluation.dm"
|
||||
#include "code\modules\scripting\Interpreter\Interaction.dm"
|
||||
#include "code\modules\scripting\Interpreter\Interpreter.dm"
|
||||
|
||||
Reference in New Issue
Block a user