From fc276c5c09ddb98c5dc226daf35012c78a2d8b92 Mon Sep 17 00:00:00 2001 From: kane-f <57303506+kane-f@users.noreply.github.com> Date: Sun, 10 Jul 2022 17:37:14 +0100 Subject: [PATCH] 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 --- code/datums/uplink_item.dm | 9 + .../machinery/telecomms/telecomunications.dm | 4 +- .../items/weapons/implants/implanter.dm | 34 ++ .../weapons/implants/types/vocal_implant.dm | 53 +++ .../items/weapons/storage/uplink_kits.dm | 4 + code/modules/mob/living/say.dm | 26 +- .../scripting/Implementations/Telecomms.dm | 358 ------------------ .../Implementations/Telecomms/Compiler.dm | 210 ++++++++++ .../{ => Implementations/Telecomms}/IDE.dm | 0 .../Implementations/vocalimplant/Compiler.dm | 93 +++++ .../Implementations/vocalimplant/IDE.dm | 117 ++++++ .../scripting/Interpreter/Interpreter.dm | 18 +- code/modules/scripting/compiler.dm | 175 +++++++++ interface/skin.dmf | 80 ++++ interface/skin_azerty.dmf | 80 ++++ vgstation13.dme | 8 +- 16 files changed, 893 insertions(+), 376 deletions(-) create mode 100644 code/game/objects/items/weapons/implants/types/vocal_implant.dm delete mode 100644 code/modules/scripting/Implementations/Telecomms.dm create mode 100644 code/modules/scripting/Implementations/Telecomms/Compiler.dm rename code/modules/scripting/{ => Implementations/Telecomms}/IDE.dm (100%) create mode 100644 code/modules/scripting/Implementations/vocalimplant/Compiler.dm create mode 100644 code/modules/scripting/Implementations/vocalimplant/IDE.dm create mode 100644 code/modules/scripting/compiler.dm diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm index 89e7a82f252..aa60537828c 100644 --- a/code/datums/uplink_item.dm +++ b/code/datums/uplink_item.dm @@ -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" diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm index 4b67ca8ccb6..37ce414ec25 100644 --- a/code/game/machinery/telecomms/telecomunications.dm +++ b/code/game/machinery/telecomms/telecomunications.dm @@ -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" diff --git a/code/game/objects/items/weapons/implants/implanter.dm b/code/game/objects/items/weapons/implants/implanter.dm index 651393e4de3..e4866c5fb7c 100644 --- a/code/game/objects/items/weapons/implants/implanter.dm +++ b/code/game/objects/items/weapons/implants/implanter.dm @@ -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]\"") diff --git a/code/game/objects/items/weapons/implants/types/vocal_implant.dm b/code/game/objects/items/weapons/implants/types/vocal_implant.dm new file mode 100644 index 00000000000..80bd4595ab8 --- /dev/null +++ b/code/game/objects/items/weapons/implants/types/vocal_implant.dm @@ -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]
[rawcode]
") + + 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 {" +Implant Specifications:
+Name: Chameleon Voice-Changing Implant
+Life: ???
+Important Notes: 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.
+
+Implant Details:
+Function: Contains a small pod of nanobots that manipulate the host's mental speech functions and processing.
+Special Features: Vocal manipulation.
+Integrity: Implant will last so long as the subject is speaking."} diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm index f3e77241968..41c5461145f 100644 --- a/code/game/objects/items/weapons/storage/uplink_kits.dm +++ b/code/game/objects/items/weapons/storage/uplink_kits.dm @@ -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) diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 44a4a060406..eed35f60573 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -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 \ No newline at end of file + return output diff --git a/code/modules/scripting/Implementations/Telecomms.dm b/code/modules/scripting/Implementations/Telecomms.dm deleted file mode 100644 index a9e82ee961f..00000000000 --- a/code/modules/scripting/Implementations/Telecomms.dm +++ /dev/null @@ -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) diff --git a/code/modules/scripting/Implementations/Telecomms/Compiler.dm b/code/modules/scripting/Implementations/Telecomms/Compiler.dm new file mode 100644 index 00000000000..272d49227fc --- /dev/null +++ b/code/modules/scripting/Implementations/Telecomms/Compiler.dm @@ -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) diff --git a/code/modules/scripting/IDE.dm b/code/modules/scripting/Implementations/Telecomms/IDE.dm similarity index 100% rename from code/modules/scripting/IDE.dm rename to code/modules/scripting/Implementations/Telecomms/IDE.dm diff --git a/code/modules/scripting/Implementations/vocalimplant/Compiler.dm b/code/modules/scripting/Implementations/vocalimplant/Compiler.dm new file mode 100644 index 00000000000..8525fde0000 --- /dev/null +++ b/code/modules/scripting/Implementations/vocalimplant/Compiler.dm @@ -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)]") diff --git a/code/modules/scripting/Implementations/vocalimplant/IDE.dm b/code/modules/scripting/Implementations/vocalimplant/IDE.dm new file mode 100644 index 00000000000..73249fa624b --- /dev/null +++ b/code/modules/scripting/Implementations/vocalimplant/IDE.dm @@ -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("Failed to save: Unable to locate vocal implant. (Back up your code before exiting the window!)", "vierror") + else + src << output(null, "vierror") + src << output("Failed to save: Unable to locate implant. (Back up your code before exiting the window!)", "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("Please wait, compiling...", "vierror") + + var/list/compileerrors = VI.compile(mob) // then compile the code! + if(!implant_check(mob)) + return + + if(compileerrors.len) + src << output("Compile Errors", "vierror") + for(var/datum/scriptError/e in compileerrors) + src << output("\t>[e.message]", "vierror") + src << output("([compileerrors.len] errors)", "vierror") + + else + src << output("vi compilation successful!", "vierror") + src << output("(0 errors)", "vierror") + + else + src << output(null, "vierror") + src << output("Failed to compile: Unable to locate vocal implant. (Back up your code before exiting the window!)", "vierror") + else + src << output(null, "vierror") + src << output("Failed to compile: Unable to locate implant. (Back up your code before exiting the window!)", "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("Failed to run: Unable to locate vocal implant. (Back up your code before exiting the window!)", "vierror") + else + src << output(null, "vierror") + src << output("Failed to run: Unable to locate implant. (Back up your code before exiting the window!)", "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("Failed to revert: Unable to locate vocal implant.", "vierror") + else + src << output(null, "vierror") + src << output("Failed to revert: Unable to locate implant.", "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("Implant memory cleared!", "vierror") + else + src << output(null, "vierror") + src << output("Failed to clear memory: Unable to locate vocal implant.", "vierror") + else + src << output(null, "vierror") + src << output("Failed to clear memory: Unable to locate implant.", "vierror") + +/proc/implant_check(var/mob/mob) + if(mob && istype(mob.get_active_hand(),/obj/item/weapon/implanter/vocal)) + return 1 + return 0 diff --git a/code/modules/scripting/Interpreter/Interpreter.dm b/code/modules/scripting/Interpreter/Interpreter.dm index 1cefba4aec3..77876ba5a7a 100644 --- a/code/modules/scripting/Interpreter/Interpreter.dm +++ b/code/modules/scripting/Interpreter/Interpreter.dm @@ -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 . @@ -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. diff --git a/code/modules/scripting/compiler.dm b/code/modules/scripting/compiler.dm new file mode 100644 index 00000000000..0330d1e8d5e --- /dev/null +++ b/code/modules/scripting/compiler.dm @@ -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) diff --git a/interface/skin.dmf b/interface/skin.dmf index 2003f9bcf56..6519c8746da 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -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 diff --git a/interface/skin_azerty.dmf b/interface/skin_azerty.dmf index f078e3ed5d8..19dcf8c8263 100644 --- a/interface/skin_azerty.dmf +++ b/interface/skin_azerty.dmf @@ -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 diff --git a/vgstation13.dme b/vgstation13.dme index d9834575bf5..d2c80f01a82 100644 --- a/vgstation13.dme +++ b/vgstation13.dme @@ -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"