From 112523086b2b8e4a76c59e6502263cd6d8c0ea97 Mon Sep 17 00:00:00 2001 From: FalseIncarnate Date: Mon, 28 Mar 2016 00:53:21 -0400 Subject: [PATCH 1/9] Logic Gates WIP Commit --- code/__DEFINES/stat.dm | 14 +- code/controllers/communications.dm | 1 + code/game/machinery/constructable_frame.dm | 40 ++- code/modules/logic/logic_base.dm | 277 +++++++++++++++++++++ code/modules/logic/logic_gate.dm | 165 ++++++++++++ paradise.dme | 2 + 6 files changed, 497 insertions(+), 2 deletions(-) create mode 100644 code/modules/logic/logic_base.dm create mode 100644 code/modules/logic/logic_gate.dm diff --git a/code/__DEFINES/stat.dm b/code/__DEFINES/stat.dm index 756ae54765f..3da3a84455f 100644 --- a/code/__DEFINES/stat.dm +++ b/code/__DEFINES/stat.dm @@ -40,4 +40,16 @@ #define SHUTTLE_DOCKED 3 #define SHUTTLE_STRANDED 4 #define SHUTTLE_ESCAPE 5 -#define SHUTTLE_ENDGAME 6 \ No newline at end of file +#define SHUTTLE_ENDGAME 6 + + +/* + Logic +*/ +// State When to Use Example +#define LOGIC_OFF 0 //Use this for when you want it to stay off (continuous signal, lever) +#define LOGIC_ON 1 //Use this for when you want it to stay on (continuous signal, lever) +#define LOGIC_FLICKER 2 //Use this for when you want it to turn on and then turn off (buttons, clocks) + +//Logic-related stuff (Misc. defines for logic things, to keep it organized or something) +#define LOGIC_FLICKER_TIME 10 //number of deciseconds LOGIC_TEMP_ON will remain active before turning off \ No newline at end of file diff --git a/code/controllers/communications.dm b/code/controllers/communications.dm index fd3fa222c82..43bee48f267 100644 --- a/code/controllers/communications.dm +++ b/code/controllers/communications.dm @@ -202,6 +202,7 @@ var/const/RADIO_CLEANBOT = "10" var/const/RADIO_FLOORBOT = "11" var/const/RADIO_MEDBOT = "12" var/const/RADIO_MAGNETS = "radio_magnet" +var/const/RADIO_LOGIC = "radio_logic" var/global/datum/controller/radio/radio_controller diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index 62b090ba1db..9e65a9fc2ac 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -878,4 +878,42 @@ obj/item/weapon/circuitboard/rdserver req_components = list( /obj/item/weapon/stock_parts/matter_bin = 1, /obj/item/weapon/stock_parts/manipulator = 1, - /obj/item/weapon/stock_parts/console_screen = 1) \ No newline at end of file + /obj/item/weapon/stock_parts/console_screen = 1) + + +//Selectable mode board, like vending machine boards +/obj/item/weapon/circuitboard/logic_gate + name = "circuit board (Logic Connector)" + build_path = /obj/machinery/logic + board_type = "machine" + origin_tech = "programming=1" //This stuff is pretty much the absolute basis of programming, so it's mostly useless for research + req_components = list(/obj/item/stack/cable_coil = 1) + + var/list/names_paths = list( + "NOT Gate" = /obj/machinery/logic_gate/not, + "OR Gate" = /obj/machinery/logic_gate/or, + "AND Gate" = /obj/machinery/logic_gate/and, + "NAND Gate" = /obj/machinery/logic_gate/nand, + "NOR Gate" = /obj/machinery/logic_gate/nor, + "XOR Gate" = /obj/machinery/logic_gate/xor, + "XNOR Gate" = /obj/machinery/logic_gate/xnor + ) + +/obj/item/weapon/circuitboard/logic_gate/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/weapon/screwdriver)) + set_type(null, user) + +/obj/item/weapon/circuitboard/logic_gate/proc/set_type(typepath, mob/user) + var/new_name = "Logic Base" + if(!typepath) + new_name = input("Circuit Setting", "What would you change the board setting to?") in names_paths + typepath = names_paths[new_name] + else + for(var/name in names_paths) + if(names_paths[name] == typepath) + new_name = name + break + build_path = typepath + name = "circuit board ([new_name])" + if(user) + user << "You set the board to [new_name]." diff --git a/code/modules/logic/logic_base.dm b/code/modules/logic/logic_base.dm new file mode 100644 index 00000000000..00f50313819 --- /dev/null +++ b/code/modules/logic/logic_base.dm @@ -0,0 +1,277 @@ + +/obj/machinery/logic_gate + name = "Logic Base" + desc = "This does nothing except connect to things. Highly illogical, report to a coder at once if you see this in-game." + icon = 'icons/obj/computer3.dmi' + icon_state = "serverframe" + density = 1 + anchored = 1 + + settagwhitelist = list("input1_id_tag", "input2_id_tag", "output_id_tag") + + var/tamperproof = 0 //if set, will make the machine unable to be destroyed, adjusted, etc. via in-game interaction (USE ONLY FOR MAPPING STUFF) + var/mono_input = 0 //if set, will ignore input2 + + var/datum/radio_frequency/radio_connection + var/frequency = 0 + + /* + Some notes on Input/Output: + - Multiple things can be linked to the same input or output tag, just like how wires can connect multiple sources and receivers. + - For inputs, only the last signal received BEFORE a process() call will be used in the logic handling. + - Input states are updated immediately whenever an input signal is received, so it is possible to update multiple times within a single process cycle. + - This means if you have multiple connected inputs, but the last signal received before the process() call is OFF, it won't matter if the others are both ON. + - For this reason, please set up your logic properly. You can theoretically chain these infinitely, so there's no need to link multiple things to a single input. + - For outputs, the signal will attempt to be sent out every process() call, to ensure newly connected things are updated within one process cycle + - Connecting an output to multiple inputs should not cause issues, as long as you don't have multiple connections to a given input (see previous notes on inputs). + - The output state is determined immediately preceeding the signal broadcast, using the input states at the time of the process() call, not when a signal is received. + - Because of how the process cycle works, it is possible that it may take multiple cycles for a signal to fully propogate through a logic chain. + - This is because machines attempt to process in the order they were added to the scheduler. + - Building the logic gates at the end of the chain first may cause delays in signal propogation. + If you take all this into consideration when linking and using logic machinery, you should have no unexpected issues with input/output. Your design flaws are on you though. + */ + + var/input1_id_tag = null + var/input1_state = LOGIC_OFF + var/input2_id_tag = null + var/input2_state = LOGIC_OFF + var/output_id_tag = null + var/output_state = LOGIC_OFF + +/obj/machinery/logic_gate/New() + if(tamperproof) //doing this during New so we don't have to worry about forgetting to set these vars during editting / defining + unacidable = 1 + ..() + if(!radio_controller) + spawn(40) + set_frequency(frequency) + else + spawn(1) // For things that set the frequency directly + set_frequency(frequency) + component_parts = list() + var/obj/item/weapon/circuitboard/logic_gate/LG = new(null) + LG.set_type(type) + component_parts += LG + component_parts += new /obj/item/stack/cable_coil(null, 1) + +/obj/machinery/logic_gate/proc/set_frequency(new_frequency) + if(!radio_controller) + sleep(20) + if(!radio_controller) + return + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_LOGIC) + return + +/obj/machinery/logic_gate/Destroy() + if(radio_controller) + radio_controller.remove_object(src,frequency) + return ..() + +/obj/machinery/logic_gate/process() + handle_logic() + handle_output() //All output will send for at least one cycle, and will attempt to send every cycle. Hopefully this won't be too taxing. + return + +/obj/machinery/logic_gate/proc/handle_logic() + return + +/obj/machinery/logic_gate/proc/handle_output() + if(!radio_connection) //can't output without this + return + + if(output_id_tag == null) //Don't output to an undefined id_tag + return + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data = list( + "tag" = output_id_tag, + "sigtype" = "logic", + "state" = output_state, + ) + + radio_connection.post_signal(src, signal) + return + +/obj/machinery/logic_gate/receive_signal(datum/signal/signal, receive_method, receive_param) + if(!signal.data["tag"] || ((signal.data["tag"] != input1_id_tag) && (signal.data["tag"] != input2_id_tag)) || (signal.data["sigtype"] != "logic")) + //If the signal lacks tag data, the signal's tag data doesn't match either input id tag, or is not a "logic" signal, ignore it since it's not for us + return + + if(signal.data["tag"] == input1_id_tag) //If the signal is for input1 + if(signal.data["state"] == input1_state) //If we already match, ignore the new signal since nothing changes + return + if(signal.data["state"] == LOGIC_OFF) //Shut it down and keep it off + input1_state = LOGIC_OFF + return + if(signal.data["state"] == LOGIC_ON) //Turn it on and keep it on + input1_state = LOGIC_ON + return + if(signal.data["state"] == LOGIC_FLICKER) //Turn it on then turn it off + if(input1_state == LOGIC_ON) //An existing continuous ON state overrides new flicker signals + return + input1_state = LOGIC_FLICKER + spawn(LOGIC_FLICKER_TIME) + if(input1_state == LOGIC_FLICKER) //Make sure we didn't get a new continuous signal set while we waited (those take priority) + input1_state = LOGIC_OFF + return + + //Now, you may be wondering why I included those returns. + //The answer is "If you link both inputs to the same source, you're an idiot and deserve to have it break", so yeah. Deal with it. + + if(mono_input) + //We only care about input1, so if we didn't receive a signal for that, we're done. + return + + if(signal.data["tag"] == input2_id_tag) //If the signal is for input2 (reaching this point assumes mono_input is not set) + if(signal.data["state"] == input2_state) //If we already match, ignore the new signal since nothing changes + return + if(signal.data["state"] == LOGIC_OFF) //Shut it down and keep it off + input2_state = LOGIC_OFF + return + if(signal.data["state"] == LOGIC_ON) //Turn it on and keep it on + input2_state = LOGIC_ON + return + if(signal.data["state"] == LOGIC_FLICKER) //Turn it on then turn it off + if(input2_state == LOGIC_ON) //An existing continuous ON state overrides new flicker signals + return + input2_state = LOGIC_FLICKER + spawn(LOGIC_FLICKER_TIME) + if(input2_state == LOGIC_FLICKER) //Make sure we didn't get a new continuous signal set while we waited (those take priority) + input2_state = LOGIC_OFF + return + +/obj/machinery/logic_gate/multitool_menu(var/mob/user, var/obj/item/device/multitool/P) + var/input1_state_string + var/input2_state_string + var/output_state_string + + switch(input1_state) + if(LOGIC_OFF) + input1_state_string = "OFF" + if(LOGIC_ON) + input1_state_string = "ON" + if(LOGIC_FLICKER) + input1_state_string = "FLICKER" + else + input1_state_string = "ERROR: UNKNOWN STATE" + + switch(input2_state) + if(LOGIC_OFF) + input2_state_string = "OFF" + if(LOGIC_ON) + input2_state_string = "ON" + if(LOGIC_FLICKER) + input2_state_string = "FLICKER" + else + input2_state_string = "ERROR: UNKNOWN STATE" + + switch(output_state) + if(LOGIC_OFF) + output_state_string = "OFF" + if(LOGIC_ON) + output_state_string = "ON" + if(LOGIC_FLICKER) + output_state_string = "FLICKER" + else + output_state_string = "ERROR: UNKNOWN STATE" + var/menu_contents = {" +
+
Input: [format_tag("ID Tag","input1_id_tag")]
+
Input State: [input1_state_string]
+ "} + if(!mono_input) + menu_contents = {" +
Input 1: [format_tag("ID Tag","input1_id_tag")]
+
Input 1 State: [input1_state_string]
+
Input 2: [format_tag("ID Tag","input2_id_tag")]
+
Input 2 State: [input2_state_string]
+ "} + menu_contents += {" +
Output: [format_tag("ID Tag","output_id_tag")]
+
Output State: [output_state_string]
+
+ "} + return menu_contents + +/obj/machinery/logic_gate/attackby(obj/item/O, mob/user, params) + if(tamperproof) + user << "The [src] appears to be tamperproofed! You can't interact with it!" + return 0 + if(istype(O, /obj/item/device/multitool)) + update_multitool_menu(user) + return 1 + if(istype(O, /obj/item/weapon/screwdriver)) + panel_open = !panel_open + user << "You [panel_open ? "open" : "close"] the access panel." + return 1 + if(panel_open && istype(O, /obj/item/weapon/crowbar)) + default_deconstruction_crowbar(O) + return 1 + +////////////////////////////////////// +// Attack procs // +////////////////////////////////////// + +/obj/machinery/logic_gate/attack_ai(mob/user) + if(tamperproof) + user << "The [src] appears to be tamperproofed! You can't interface with it!" + return 0 + add_hiddenprint(user) + return ui_interact(user) + +/obj/machinery/logic_gate/attack_ghost(mob/user) + if(tamperproof) + user << "The [src] appears to be tamperproofed! You can't haunt it!" + return 0 + return ui_interact(user) + +/obj/machinery/logic_gate/attack_hand(mob/user) + if(tamperproof) + user << "The [src] appears to be tamperproofed! You can't interact with it!" + return 0 + . = ..() + if(.) + return 0 + return interact(user) + +/obj/machinery/logic_gate/attack_alien(mob/user) //No xeno logic, that's too silly. + user << "The [src] appears to be too complex! You can't comprehend it and back off in fear!" + return 0 + +/obj/machinery/logic_gate/attack_animal(mob/user) //No animal logic either. + user << "The [src] appears to be beyond your comprehension! You can't fathom it!" + return 0 + +/obj/machinery/logic_gate/attack_slime(mob/user) //No slime logic. Seriously. + user << "The [src] appears to be beyond your gelatinous understanding! You ignore it!" + return 0 + +/obj/machinery/logic_gate/emp_act(severity) + if(tamperproof) + return 0 + ..() + +/obj/machinery/logic_gate/ex_act(severity) + if(tamperproof) + return 0 + ..() + +/obj/machinery/logic_gate/blob_act() + if(tamperproof) + return 0 + ..() + +/obj/machinery/logic_gate/singularity_act() + if(tamperproof) + //This is some top-level tamperproofing right here, that's for sure. It can even defy a singularity! + return 0 + +/obj/machinery/logic_gate/bullet_act() + if(tamperproof) + return 0 + ..() \ No newline at end of file diff --git a/code/modules/logic/logic_gate.dm b/code/modules/logic/logic_gate.dm new file mode 100644 index 00000000000..75a4ca489dc --- /dev/null +++ b/code/modules/logic/logic_gate.dm @@ -0,0 +1,165 @@ + +////////////////////////////////// +// Mono-Input Gates // +////////////////////////////////// + +//NOT Gate +/obj/machinery/logic_gate/not + name = "NOT Gate" + desc = "Accepts one input and outputs the reverse state." + mono_input = 1 //NOT Gates are the simplest logic gate because they only utilize one input. + output_state = LOGIC_ON //Starts with an active output, since the input will be OFF at start + +/obj/machinery/logic_gate/not/process() //This gate only handles its logic when it receives a signal, and outputs both on the process and when it receives the signal + handle_output() + return +/* + A quick note regarding NOT Gates: + - Connecting multiple things to the input of a NOT Gate can cause weird behaviour due to updating both when it receives a signal and when it calls process(). + - This means it will attempt to output once for every logic machine connected to its input's own process() call. + - It will then attempt to output an additional time based on the current state when it comes to its own process() call. + - For this reason, it is HIGHLY RECOMMENDED that you only connect a single signal source to the input of a NOT Gate to avoid signal spasms. + - Connecting multiple things to the output of a NOT Gate should not cause this unusual behavior. +*/ +/obj/machinery/logic_gate/not/receive_signal(datum/signal/signal, receive_method, receive_param) + ..() + handle_logic() + return + +/obj/machinery/logic_gate/not/handle_logic() //Our output will always be a continuous signal, even with a FLICKER, it just will update the output when the FLICKER ends + if(input1_state == LOGIC_ON) //Output is OFF while input is ON + output_state = LOGIC_OFF + else if(input1_state == LOGIC_FLICKER) //Output is OFF while input is FLICKER, then output returns to ON when input returns to OFF + output_state = LOGIC_OFF + spawn(LOGIC_FLICKER_TIME + 1) //Call handle_logic again after this delay (the input should update from the spawn(LOGIC_FLICKER_TIME) in receive_signal() by then) + handle_logic() + else //Output is ON while input is OFF + output_state = LOGIC_ON + handle_output() + return + +//STATUS Gate +/obj/machinery/logic_gate/status + name = "Status Gate" + desc = "Accepts one input and outputs the same state, showing a colored light based on current state." + mono_input = 1 //STATUS Gate doesn't actually perform logic operations, but instead acts as a testing conduit. + +/* + STATUS Gates are largely a diagnostics tool, but I'm sure someone will still make a logic gate rave with them anyways. + - There is no need to actually connect an output for these to work, they just need an input to sample from. + - STATUS Gates attempt to output both on the process cycle and whenever a signal is received. + - This may seem a little spammy, but ensures they don't hold anything up signal-wise. +*/ + +/obj/machinery/logic_gate/status/receive_signal(datum/signal/signal, receive_method, receive_params) + ..() + handle_logic() //STATUS Gate calls handle_logic() when it receives a signal to update its light and output_state + handle_output() //STATUS Gate outputs when it receives a signal, since it is just a connector piece (like a wire for power) + +/obj/machinery/logic_gate/status/handle_logic() + output_state = input1_state //Output is equal to input, since it is simply a connection with an attached light + if(output_state == LOGIC_OFF) //Red light when OFF + set_light(2,2,"#ff0000") + return + if(output_state == LOGIC_ON) //Green light when ON + set_light(2,2,"#009933") + return + if(output_state == LOGIC_FLICKER) //Orange light when FLICKER, then update after LOGIC_FLICKER_TIME + 1 to reflect the changed state + set_light(2,2,"#ff9900") + spawn(LOGIC_FLICKER_TIME + 1) + handle_logic() + handle_output() + return + +////////////////////////////////// +// Dual-Input Gates // +////////////////////////////////// + + +// OR Gate +/obj/machinery/logic_gate/or + name = "OR Gate" + desc = "Outputs ON when at least one input is ON." + +/obj/machinery/logic_gate/or/handle_logic() + if(input1_state == LOGIC_ON || input1_state == LOGIC_FLICKER || input2_state == LOGIC_ON || input2_state == LOGIC_FLICKER) + if(input1_state == LOGIC_ON || input2_state == LOGIC_ON) //continuous signal takes priority in determining what to output + output_state = LOGIC_ON + else + output_state = LOGIC_FLICKER + else //Both inputs were off, so input is off + output_state = LOGIC_OFF + return + +// AND Gate +/obj/machinery/logic_gate/and + name = "AND Gate" + desc = "Outputs ON only when both inputs are ON." + +/obj/machinery/logic_gate/and/handle_logic() + if((input1_state == LOGIC_ON || input1_state == LOGIC_FLICKER) && (input2_state == LOGIC_ON || input2_state == LOGIC_FLICKER)) + if(input1_state == LOGIC_ON && input2_state == LOGIC_ON) //only output a continuous signal when both inputs are continuous signals + output_state = LOGIC_ON + else + output_state = LOGIC_FLICKER + else //At least one input was off, so output is off + output_state = LOGIC_OFF + return + +// NAND Gate +/obj/machinery/logic_gate/nand + name = "NAND Gate" + desc = "Outputs OFF only when both inputs are ON." + output_state = LOGIC_ON + +/obj/machinery/logic_gate/nand/handle_logic() + if((input1_state == LOGIC_ON || input1_state == LOGIC_FLICKER) && (input2_state == LOGIC_ON || input2_state == LOGIC_FLICKER)) + output_state = LOGIC_OFF //This can only output continuous signals + else //At least one input was ON/FLICKER, so output is off + output_state = LOGIC_OFF + return + +// NOR Gate +/obj/machinery/logic_gate/nor + name = "NOR Gate" + desc = "Outputs OFF when at least one input is ON." + output_state = LOGIC_ON + +/obj/machinery/logic_gate/nor/handle_logic() + if(input1_state == LOGIC_OFF ||input2_state == LOGIC_OFF) + output_state = LOGIC_ON //This can only output continuous signals + else //Both inputs are ON, so output is OFF + output_state = LOGIC_OFF + return + +// XOR Gate +/obj/machinery/logic_gate/xor + name = "XOR Gate" + desc = "Outputs ON when only one input is ON." + +/obj/machinery/logic_gate/xor/handle_logic() + if((input1_state == LOGIC_ON || input1_state == LOGIC_FLICKER) || input2_state == LOGIC_OFF) //Only input1 is ON/FLICKER, so output matches input1 + output_state = input1_state + else if((input2_state == LOGIC_ON || input2_state == LOGIC_FLICKER) || input1_state == LOGIC_OFF) //Only input2 is ON/FLICKER, so output matches input2 + output_state = input2_state + else //Both inputs are ON or OFF, so output is OFF + output_state = LOGIC_OFF + return + +// XNOR Gate +/obj/machinery/logic_gate/xnor + name = "XNOR Gate" + desc = "Outputs ON when both inputs are ON or OFF." + output_state = LOGIC_ON + +/obj/machinery/logic_gate/xnor/handle_logic() + if((input1_state == LOGIC_ON || input1_state == LOGIC_FLICKER) && (input2_state == LOGIC_ON || input2_state == LOGIC_FLICKER)) //Both inputs are ON/FLICKER + if(input1_state == LOGIC_ON && input2_state == LOGIC_ON) //Only continuous signal when both inputs are ON + output_state = LOGIC_ON + else //If at least one input is FLICKER, output FLICKER + output_state = LOGIC_FLICKER + else if(input1_state == LOGIC_OFF && input2_state == LOGIC_OFF) //Both inputs are OFF + output_state = LOGIC_ON //Always continuous in this case + else //Only one input is ON/FLICKER + output_state = LOGIC_OFF + return diff --git a/paradise.dme b/paradise.dme index a05cd77e6f4..c4c7bfc1545 100644 --- a/paradise.dme +++ b/paradise.dme @@ -1272,6 +1272,8 @@ #include "code\modules\lighting\lighting_process.dm" #include "code\modules\lighting\lighting_system.dm" #include "code\modules\lighting\lighting_turf.dm" +#include "code\modules\logic\logic_base.dm" +#include "code\modules\logic\logic_gate.dm" #include "code\modules\media\jukebox.dm" #include "code\modules\media\machinery.dm" #include "code\modules\media\mediamanager.dm" From 333698171b638a04e9b42e4638452aa96da64c1a Mon Sep 17 00:00:00 2001 From: FalseIncarnate Date: Mon, 28 Mar 2016 03:06:55 -0400 Subject: [PATCH 2/9] Logic Gates WIP 2 - Fixes signal Del() messages - Allows driver buttons to send logic signals - Moves a driver button var into the buttons.dm file - Need to move the procs there for organization still --- code/game/machinery/buttons.dm | 10 +++++- code/game/machinery/door_control.dm | 50 +++++++++++++++++++++++++++-- code/modules/logic/logic_base.dm | 19 ++++------- code/modules/logic/logic_gate.dm | 14 +------- 4 files changed, 64 insertions(+), 29 deletions(-) diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index b38830b4b44..8dcb8a9ce63 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -5,11 +5,17 @@ desc = "A remote control switch for a mass driver." var/id_tag = "default" var/active = 0 - settagwhitelist = list("id_tag") + settagwhitelist = list("id_tag", "logic_id_tag") anchored = 1.0 use_power = 1 idle_power_usage = 2 active_power_usage = 4 + var/range = 7 + + var/datum/radio_frequency/radio_connection + var/frequency = 0 + var/logic_id_tag = "default" //Defines the ID tag to send logic signals to, so you don't have to unlink from doors and stuff + var/logic_connect = 0 //Set this to allow the button to send out logic signals when pressed in addition to normal stuff /obj/machinery/driver_button/New(turf/loc, var/w_dir=null) ..() @@ -22,6 +28,8 @@ pixel_x = 25 if(WEST) pixel_x = -25 + if(radio_controller) + set_frequency(frequency) /obj/machinery/ignition_switch name = "ignition switch" diff --git a/code/game/machinery/door_control.dm b/code/game/machinery/door_control.dm index 304e38118db..d8e7060d09a 100644 --- a/code/game/machinery/door_control.dm +++ b/code/game/machinery/door_control.dm @@ -132,7 +132,25 @@ else icon_state = "doorctrl0" -/obj/machinery/driver_button/var/range = 7 +////////////////////////////////////// +// Driver Button // +////////////////////////////////////// + +/obj/machinery/driver_button/initialize() + ..() + set_frequency(frequency) + +/obj/machinery/driver_button/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_LOGIC) + return + +/obj/machinery/driver_button/Destroy() + if(radio_controller) + radio_controller.remove_object(src,frequency) + return ..() + /obj/machinery/driver_button/attack_ai(mob/user as mob) return src.attack_hand(user) @@ -159,7 +177,9 @@ /obj/machinery/driver_button/multitool_menu(var/mob/user, var/obj/item/device/multitool/P) return {" "} /obj/machinery/driver_button/attack_hand(mob/user as mob) @@ -181,6 +201,25 @@ active = 1 icon_state = "launcheract" + if(logic_connect) + if(!radio_connection) //can't output without this + return + + if(logic_id_tag == null) //Don't output to an undefined id_tag + return + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data = list( + "tag" = logic_id_tag, + "sigtype" = "logic", + "state" = LOGIC_FLICKER, //Buttons are a FLICKER source, since they only register as ON when you press it, then turn OFF after you release + ) + + radio_connection.post_signal(src, signal, filter = RADIO_LOGIC) + for(var/obj/machinery/door/poddoor/M in range(src,range)) if (M.id_tag == src.id_tag && !M.protected) spawn() @@ -201,4 +240,9 @@ return icon_state = "launcherbtt" - active = 0 \ No newline at end of file + active = 0 + +/obj/machinery/driver_button/multitool_topic(var/mob/user,var/list/href_list,var/obj/O) + ..() + if("toggle_logic" in href_list) + logic_connect = !logic_connect \ No newline at end of file diff --git a/code/modules/logic/logic_base.dm b/code/modules/logic/logic_base.dm index 00f50313819..9e93942935f 100644 --- a/code/modules/logic/logic_base.dm +++ b/code/modules/logic/logic_base.dm @@ -42,23 +42,19 @@ if(tamperproof) //doing this during New so we don't have to worry about forgetting to set these vars during editting / defining unacidable = 1 ..() - if(!radio_controller) - spawn(40) - set_frequency(frequency) - else - spawn(1) // For things that set the frequency directly - set_frequency(frequency) + if(radio_controller) + set_frequency(frequency) component_parts = list() var/obj/item/weapon/circuitboard/logic_gate/LG = new(null) LG.set_type(type) component_parts += LG component_parts += new /obj/item/stack/cable_coil(null, 1) +/obj/machinery/logic_gate/initialize() + ..() + set_frequency(frequency) + /obj/machinery/logic_gate/proc/set_frequency(new_frequency) - if(!radio_controller) - sleep(20) - if(!radio_controller) - return radio_controller.remove_object(src, frequency) frequency = new_frequency radio_connection = radio_controller.add_object(src, frequency, RADIO_LOGIC) @@ -94,8 +90,7 @@ "state" = output_state, ) - radio_connection.post_signal(src, signal) - return + radio_connection.post_signal(src, signal, filter = RADIO_LOGIC) /obj/machinery/logic_gate/receive_signal(datum/signal/signal, receive_method, receive_param) if(!signal.data["tag"] || ((signal.data["tag"] != input1_id_tag) && (signal.data["tag"] != input2_id_tag)) || (signal.data["sigtype"] != "logic")) diff --git a/code/modules/logic/logic_gate.dm b/code/modules/logic/logic_gate.dm index 75a4ca489dc..5a4c8e2c221 100644 --- a/code/modules/logic/logic_gate.dm +++ b/code/modules/logic/logic_gate.dm @@ -9,10 +9,6 @@ desc = "Accepts one input and outputs the reverse state." mono_input = 1 //NOT Gates are the simplest logic gate because they only utilize one input. output_state = LOGIC_ON //Starts with an active output, since the input will be OFF at start - -/obj/machinery/logic_gate/not/process() //This gate only handles its logic when it receives a signal, and outputs both on the process and when it receives the signal - handle_output() - return /* A quick note regarding NOT Gates: - Connecting multiple things to the input of a NOT Gate can cause weird behaviour due to updating both when it receives a signal and when it calls process(). @@ -21,11 +17,6 @@ - For this reason, it is HIGHLY RECOMMENDED that you only connect a single signal source to the input of a NOT Gate to avoid signal spasms. - Connecting multiple things to the output of a NOT Gate should not cause this unusual behavior. */ -/obj/machinery/logic_gate/not/receive_signal(datum/signal/signal, receive_method, receive_param) - ..() - handle_logic() - return - /obj/machinery/logic_gate/not/handle_logic() //Our output will always be a continuous signal, even with a FLICKER, it just will update the output when the FLICKER ends if(input1_state == LOGIC_ON) //Output is OFF while input is ON output_state = LOGIC_OFF @@ -47,14 +38,12 @@ /* STATUS Gates are largely a diagnostics tool, but I'm sure someone will still make a logic gate rave with them anyways. - There is no need to actually connect an output for these to work, they just need an input to sample from. - - STATUS Gates attempt to output both on the process cycle and whenever a signal is received. - - This may seem a little spammy, but ensures they don't hold anything up signal-wise. + - STATUS Gates attempt to update their lights whenever they receive a signal. */ /obj/machinery/logic_gate/status/receive_signal(datum/signal/signal, receive_method, receive_params) ..() handle_logic() //STATUS Gate calls handle_logic() when it receives a signal to update its light and output_state - handle_output() //STATUS Gate outputs when it receives a signal, since it is just a connector piece (like a wire for power) /obj/machinery/logic_gate/status/handle_logic() output_state = input1_state //Output is equal to input, since it is simply a connection with an attached light @@ -68,7 +57,6 @@ set_light(2,2,"#ff9900") spawn(LOGIC_FLICKER_TIME + 1) handle_logic() - handle_output() return ////////////////////////////////// From 1caf39230ad7503ecdc135dfb768caf160cd8da4 Mon Sep 17 00:00:00 2001 From: FalseIncarnate Date: Tue, 29 Mar 2016 03:11:42 -0400 Subject: [PATCH 3/9] Logic Gates WIP 3 Allows mass driver buttons to send logic signals - They send LOGIC_FLICKER, since they are only on when pressed, then turn off when released - Can send logic signals to a different ID tag than their associated driver/door ID tag, configurable from the multitool menu Allows light switches to send logic signals - Will send LOGIC_ON or LOGIC_OFF signals to match their current state - Send both when toggled and on the process() cycle - Light control can be toggled via the multitool menu, so you can use them as purely light switches, purely logic switches, or as dual switches Allows light switches to be made from metal sheets, just like mass driver buttons (1 sheet per button) - Fixes a resource duplication bug where driver buttons can be disassembled for more metal than it takes to build them Begins to move some code for various button types into the buttons.dm file, rather than being scattered across multiple files - Driver buttons code moved from door_control.dm - Ignition switch code moved from igniter.dm Renames driver_button.dm to buttons_switches.dm - This is the file that contained the mountable frames for driver buttons, and now also contains the frame for light switches. --- code/game/machinery/buttons.dm | 164 ++++++++++++++++++ code/game/machinery/door_control.dm | 115 ------------ code/game/machinery/igniter.dm | 36 ---- code/game/machinery/lightswitch.dm | 119 ++++++++++++- .../mountable_frames/buttons_switches.dm | 23 +++ .../items/mountable_frames/driver_button.dm | 10 -- .../items/stacks/sheets/sheet_types.dm | 1 + code/modules/logic/logic_base.dm | 7 + paradise.dme | 2 +- 9 files changed, 306 insertions(+), 171 deletions(-) create mode 100644 code/game/objects/items/mountable_frames/buttons_switches.dm delete mode 100644 code/game/objects/items/mountable_frames/driver_button.dm diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index 8dcb8a9ce63..0934959d20f 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -1,3 +1,8 @@ + +////////////////////////////////////// +// Driver Button // +////////////////////////////////////// + /obj/machinery/driver_button name = "mass driver button" icon = 'icons/obj/objects.dmi' @@ -31,6 +36,121 @@ if(radio_controller) set_frequency(frequency) +/obj/machinery/driver_button/initialize() + ..() + set_frequency(frequency) + +/obj/machinery/driver_button/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_LOGIC) + return + +/obj/machinery/driver_button/Destroy() + if(radio_controller) + radio_controller.remove_object(src,frequency) + return ..() + + +/obj/machinery/driver_button/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/driver_button/attackby(obj/item/weapon/W, mob/user as mob, params) + + if(istype(W, /obj/item/device/detective_scanner)) + return + + if(istype(W, /obj/item/device/multitool)) + update_multitool_menu(user) + return 1 + + if(istype(W, /obj/item/weapon/wrench)) + playsound(get_turf(src), 'sound/items/Ratchet.ogg', 50, 1) + if(do_after(user, 30, target = src)) + user << "You detach \the [src] from the wall." + new/obj/item/mounted/frame/driver_button(get_turf(src)) + qdel(src) + return 1 + + return src.attack_hand(user) + +/obj/machinery/driver_button/multitool_menu(var/mob/user, var/obj/item/device/multitool/P) + return {" +
    +
  • ID Tag: [format_tag("ID Tag","id_tag")]
  • +
  • Logic Connection: [logic_connect ? "On" : "Off"]
  • +
  • Logic ID Tag: [format_tag("Logic ID Tag", "logic_id_tag")]
  • +
"} + +/obj/machinery/driver_button/attack_hand(mob/user as mob) + + src.add_fingerprint(usr) + if(stat & (NOPOWER|BROKEN)) + return + if(active) + return + add_fingerprint(user) + + use_power(5) + + launch_sequence() + + return + +/obj/machinery/driver_button/proc/launch_sequence() + active = 1 + icon_state = "launcheract" + + if(logic_connect) + if(!radio_connection) //can't output without this + return + + if(logic_id_tag == null) //Don't output to an undefined id_tag + return + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data = list( + "tag" = logic_id_tag, + "sigtype" = "logic", + "state" = LOGIC_FLICKER, //Buttons are a FLICKER source, since they only register as ON when you press it, then turn OFF after you release + ) + + radio_connection.post_signal(src, signal, filter = RADIO_LOGIC) + + for(var/obj/machinery/door/poddoor/M in range(src,range)) + if (M.id_tag == src.id_tag && !M.protected) + spawn() + M.open() + + sleep(20) + + for(var/obj/machinery/mass_driver/M in range(src,range)) + if(M.id_tag == src.id_tag) + M.drive() + + sleep(50) + + for(var/obj/machinery/door/poddoor/M in range(src,range)) + if (M.id_tag == src.id_tag && !M.protected) + spawn() + M.close() + return + + icon_state = "launcherbtt" + active = 0 + +/obj/machinery/driver_button/multitool_topic(var/mob/user,var/list/href_list,var/obj/O) + ..() + if("toggle_logic" in href_list) + logic_connect = !logic_connect + +////////////////////////////////////// +// Ignition Switch // +////////////////////////////////////// + /obj/machinery/ignition_switch name = "ignition switch" icon = 'icons/obj/objects.dmi' @@ -43,6 +163,46 @@ idle_power_usage = 2 active_power_usage = 4 +/obj/machinery/ignition_switch/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/ignition_switch/attackby(obj/item/weapon/W, mob/user as mob, params) + return src.attack_hand(user) + +/obj/machinery/ignition_switch/attack_hand(mob/user as mob) + + if(stat & (NOPOWER|BROKEN)) + return + if(active) + return + + use_power(5) + + active = 1 + icon_state = "launcheract" + + for(var/obj/machinery/sparker/M in world) + if (M.id == src.id) + spawn( 0 ) + M.spark() + + for(var/obj/machinery/igniter/M in world) + if(M.id == src.id) + use_power(50) + M.on = !( M.on ) + M.icon_state = text("igniter[]", M.on) + + sleep(50) + + icon_state = "launcherbtt" + active = 0 + + return + +////////////////////////////////////// +// Flasher Button // +////////////////////////////////////// + /obj/machinery/flasher_button name = "flasher button" desc = "A remote control switch for a mounted flasher." @@ -55,6 +215,10 @@ idle_power_usage = 2 active_power_usage = 4 +////////////////////////////////////// +// Crematorium Switch // +////////////////////////////////////// + /obj/machinery/crema_switch desc = "Burn baby burn!" name = "crematorium igniter" diff --git a/code/game/machinery/door_control.dm b/code/game/machinery/door_control.dm index d8e7060d09a..0e6834a3229 100644 --- a/code/game/machinery/door_control.dm +++ b/code/game/machinery/door_control.dm @@ -131,118 +131,3 @@ icon_state = "doorctrl-p" else icon_state = "doorctrl0" - -////////////////////////////////////// -// Driver Button // -////////////////////////////////////// - -/obj/machinery/driver_button/initialize() - ..() - set_frequency(frequency) - -/obj/machinery/driver_button/proc/set_frequency(new_frequency) - radio_controller.remove_object(src, frequency) - frequency = new_frequency - radio_connection = radio_controller.add_object(src, frequency, RADIO_LOGIC) - return - -/obj/machinery/driver_button/Destroy() - if(radio_controller) - radio_controller.remove_object(src,frequency) - return ..() - - -/obj/machinery/driver_button/attack_ai(mob/user as mob) - return src.attack_hand(user) - -/obj/machinery/driver_button/attackby(obj/item/weapon/W, mob/user as mob, params) - - if(istype(W, /obj/item/device/detective_scanner)) - return - - if(istype(W, /obj/item/device/multitool)) - update_multitool_menu(user) - return 1 - - if(istype(W, /obj/item/weapon/wrench)) - playsound(get_turf(src), 'sound/items/Ratchet.ogg', 50, 1) - if(do_after(user, 30, target = src)) - user << "You detach \the [src] from the wall." - new/obj/item/mounted/frame/driver_button(get_turf(src)) - qdel(src) - return 1 - - return src.attack_hand(user) - -/obj/machinery/driver_button/multitool_menu(var/mob/user, var/obj/item/device/multitool/P) - return {" -
    -
  • ID Tag: [format_tag("ID Tag","id_tag")]
  • -
  • Logic Connection: [logic_connect ? "On" : "Off"]
  • -
  • Logic ID Tag: [format_tag("Logic ID Tag", "logic_id_tag")]
  • -
"} - -/obj/machinery/driver_button/attack_hand(mob/user as mob) - - src.add_fingerprint(usr) - if(stat & (NOPOWER|BROKEN)) - return - if(active) - return - add_fingerprint(user) - - use_power(5) - - launch_sequence() - - return - -/obj/machinery/driver_button/proc/launch_sequence() - active = 1 - icon_state = "launcheract" - - if(logic_connect) - if(!radio_connection) //can't output without this - return - - if(logic_id_tag == null) //Don't output to an undefined id_tag - return - - var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal - signal.source = src - - signal.data = list( - "tag" = logic_id_tag, - "sigtype" = "logic", - "state" = LOGIC_FLICKER, //Buttons are a FLICKER source, since they only register as ON when you press it, then turn OFF after you release - ) - - radio_connection.post_signal(src, signal, filter = RADIO_LOGIC) - - for(var/obj/machinery/door/poddoor/M in range(src,range)) - if (M.id_tag == src.id_tag && !M.protected) - spawn() - M.open() - - sleep(20) - - for(var/obj/machinery/mass_driver/M in range(src,range)) - if(M.id_tag == src.id_tag) - M.drive() - - sleep(50) - - for(var/obj/machinery/door/poddoor/M in range(src,range)) - if (M.id_tag == src.id_tag && !M.protected) - spawn() - M.close() - return - - icon_state = "launcherbtt" - active = 0 - -/obj/machinery/driver_button/multitool_topic(var/mob/user,var/list/href_list,var/obj/O) - ..() - if("toggle_logic" in href_list) - logic_connect = !logic_connect \ No newline at end of file diff --git a/code/game/machinery/igniter.dm b/code/game/machinery/igniter.dm index 25989db9e0f..d6e41d29fa2 100755 --- a/code/game/machinery/igniter.dm +++ b/code/game/machinery/igniter.dm @@ -114,39 +114,3 @@ return spark() ..(severity) - -/obj/machinery/ignition_switch/attack_ai(mob/user as mob) - return src.attack_hand(user) - -/obj/machinery/ignition_switch/attackby(obj/item/weapon/W, mob/user as mob, params) - return src.attack_hand(user) - -/obj/machinery/ignition_switch/attack_hand(mob/user as mob) - - if(stat & (NOPOWER|BROKEN)) - return - if(active) - return - - use_power(5) - - active = 1 - icon_state = "launcheract" - - for(var/obj/machinery/sparker/M in world) - if (M.id == src.id) - spawn( 0 ) - M.spark() - - for(var/obj/machinery/igniter/M in world) - if(M.id == src.id) - use_power(50) - M.on = !( M.on ) - M.icon_state = text("igniter[]", M.on) - - sleep(50) - - icon_state = "launcherbtt" - active = 0 - - return \ No newline at end of file diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm index 839c63a6bc9..47a3d48e19c 100644 --- a/code/game/machinery/lightswitch.dm +++ b/code/game/machinery/lightswitch.dm @@ -11,9 +11,27 @@ var/area/area = null var/otherarea = null // luminosity = 1 + settagwhitelist = list("logic_id_tag") + var/light_connect = 1 //Allows the switch to control lights in its associated areas. When set to 0, using the switch won't affect the lights. + var/datum/radio_frequency/radio_connection + var/frequency = 0 + var/logic_id_tag = "default" //Defines the ID tag to send logic signals to. + var/logic_connect = 0 //Set this to allow the switch to send out logic signals. -/obj/machinery/light_switch/New() + +/obj/machinery/light_switch/New(turf/loc, var/w_dir=null) ..() + switch(w_dir) + if(NORTH) + pixel_y = 25 + if(SOUTH) + pixel_y = -25 + if(EAST) + pixel_x = 25 + if(WEST) + pixel_x = -25 + if(radio_controller) + set_frequency(frequency) spawn(5) src.area = src.loc.loc @@ -26,7 +44,20 @@ src.on = src.area.lightswitch updateicon() +/obj/machinery/light_switch/initialize() + ..() + set_frequency(frequency) +/obj/machinery/light_switch/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_LOGIC) + return + +/obj/machinery/light_switch/Destroy() + if(radio_controller) + radio_controller.remove_object(src,frequency) + return ..() /obj/machinery/light_switch/proc/updateicon() if(stat & NOPOWER) @@ -41,22 +72,55 @@ if(..(user, 1)) user << "A light switch. It is [on? "on" : "off"]." - /obj/machinery/light_switch/attack_hand(mob/user) on = !on + updateicon() - area.lightswitch = on - area.updateicon() + if(light_connect) + area.lightswitch = on + area.updateicon() - for(var/obj/machinery/light_switch/L in area) - L.on = on - L.updateicon() + if(logic_connect && powered(LIGHT)) //Don't bother sending a signal if we aren't set to send them or we have no power to send with. + handle_output() - area.power_change() + if(light_connect) + for(var/obj/machinery/light_switch/L in area) + L.on = on + L.updateicon() + + area.power_change() + +/obj/machinery/light_switch/proc/handle_output() + if(!radio_connection) //can't output without this + return + + if(logic_id_tag == null) //Don't output to an undefined id_tag + return + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + //Light switches are continuous signal sources, since they register as ON or OFF and stay that way until adjusted again + if(on) + signal.data = list( + "tag" = logic_id_tag, + "sigtype" = "logic", + "state" = LOGIC_ON, + ) + else + signal.data = list( + "tag" = logic_id_tag, + "sigtype" = "logic", + "state" = LOGIC_OFF, + ) + + radio_connection.post_signal(src, signal, filter = RADIO_LOGIC) + if(on) + use_power(5, LIGHT) //Use a tiny bit of power every time we send an ON signal. Draws from the local APC's lighting circuit, since this is a LIGHT switch. /obj/machinery/light_switch/power_change() - if(!otherarea) if(powered(LIGHT)) stat &= ~NOPOWER @@ -71,3 +135,40 @@ return power_change() ..(severity) + +/obj/machinery/light_switch/process() + if(logic_connect && powered(LIGHT)) //We won't send signals while unpowered, but the last signal will remain valid for anything that received it before we went dark + handle_output() + +/obj/machinery/light_switch/attackby(obj/item/weapon/W as obj, mob/user as mob, params) + if(istype(W, /obj/item/device/detective_scanner)) + return + + if(istype(W, /obj/item/device/multitool)) + update_multitool_menu(user) + return 1 + + if(istype(W, /obj/item/weapon/wrench)) + playsound(get_turf(src), 'sound/items/Ratchet.ogg', 50, 1) + if(do_after(user, 30, target = src)) + user << "You detach \the [src] from the wall." + new/obj/item/mounted/frame/light_switch(get_turf(src)) + qdel(src) + return 1 + + return src.attack_hand(user) + +/obj/machinery/light_switch/multitool_menu(var/mob/user, var/obj/item/device/multitool/P) + return {" + "} + +/obj/machinery/light_switch/multitool_topic(var/mob/user,var/list/href_list,var/obj/O) + ..() + if("toggle_light_connect" in href_list) + light_connect = !light_connect + if("toggle_logic" in href_list) + logic_connect = !logic_connect diff --git a/code/game/objects/items/mountable_frames/buttons_switches.dm b/code/game/objects/items/mountable_frames/buttons_switches.dm new file mode 100644 index 00000000000..b1e3fabbb86 --- /dev/null +++ b/code/game/objects/items/mountable_frames/buttons_switches.dm @@ -0,0 +1,23 @@ +/obj/item/mounted/frame/driver_button + name = "mass driver button frame" + desc = "Used for repairing or building mass driver buttons" + icon = 'icons/obj/objects.dmi' + icon_state = "launcherbtt_frame" + mount_reqs = list("simfloor") + sheets_refunded = 1 + +/obj/item/mounted/frame/driver_button/do_build(turf/on_wall, mob/user) + new /obj/machinery/driver_button(get_turf(user), get_dir(user, on_wall)) + qdel(src) + +/obj/item/mounted/frame/light_switch + name = "light switch frame" + desc = "Used for repairing or building light switches" + icon = 'icons/obj/power.dmi' + icon_state = "light-p" + mount_reqs = list("simfloor", "nospace") + sheets_refunded = 1 + +/obj/item/mounted/frame/light_switch/do_build(turf/on_wall, mob/user) + new /obj/machinery/light_switch(get_turf(user), get_dir(user, on_wall)) + qdel(src) \ No newline at end of file diff --git a/code/game/objects/items/mountable_frames/driver_button.dm b/code/game/objects/items/mountable_frames/driver_button.dm deleted file mode 100644 index 7c888b48c95..00000000000 --- a/code/game/objects/items/mountable_frames/driver_button.dm +++ /dev/null @@ -1,10 +0,0 @@ -/obj/item/mounted/frame/driver_button - name = "mass driver button frame" - desc = "Used for repairing or building mass driver buttons" - icon = 'icons/obj/objects.dmi' - icon_state = "launcherbtt_frame" - mount_reqs = list("simfloor") - -/obj/item/mounted/frame/driver_button/do_build(turf/on_wall, mob/user) - new /obj/machinery/driver_button(get_turf(user), get_dir(user, on_wall)) - qdel(src) \ No newline at end of file diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 11db68ec671..a5f7575a34a 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -72,6 +72,7 @@ var/global/list/datum/stack_recipe/metal_recipes = list ( \ ), 4), \ null, \ new/datum/stack_recipe("mass driver button frame", /obj/item/mounted/frame/driver_button, 1, time = 50, one_per_turf = 0, on_floor = 1), \ + new/datum/stack_recipe("light switch frame", /obj/item/mounted/frame/light_switch, 1, time = 50, one_per_turf = 0, on_floor = 1), \ null, \ new/datum/stack_recipe("grenade casing", /obj/item/weapon/grenade/chem_grenade), \ new/datum/stack_recipe("light fixture frame", /obj/item/mounted/frame/light_fixture, 2), \ diff --git a/code/modules/logic/logic_base.dm b/code/modules/logic/logic_base.dm index 9e93942935f..129a243c37b 100644 --- a/code/modules/logic/logic_base.dm +++ b/code/modules/logic/logic_base.dm @@ -265,8 +265,15 @@ if(tamperproof) //This is some top-level tamperproofing right here, that's for sure. It can even defy a singularity! return 0 + ..() /obj/machinery/logic_gate/bullet_act() if(tamperproof) return 0 + ..() + +/obj/machinery/logic_gate/tesla_act(var/power) + if(tamperproof) + tesla_zap(src, 3, power) //If we're tamperproof, we'll just bounce the full shock of the tesla zap we got hit by, so it continues on normally without diminishing + return 0 ..() \ No newline at end of file diff --git a/paradise.dme b/paradise.dme index c4c7bfc1545..2dea07e765d 100644 --- a/paradise.dme +++ b/paradise.dme @@ -684,7 +684,7 @@ #include "code\game\objects\items\devices\radio\radio.dm" #include "code\game\objects\items\mountable_frames\air_alarm.dm" #include "code\game\objects\items\mountable_frames\apc_frame.dm" -#include "code\game\objects\items\mountable_frames\driver_button.dm" +#include "code\game\objects\items\mountable_frames\buttons_switches.dm" #include "code\game\objects\items\mountable_frames\fire_alarm.dm" #include "code\game\objects\items\mountable_frames\frames.dm" #include "code\game\objects\items\mountable_frames\intercom.dm" From b91740b19b127fc3d3225d5a7c21106993ba4da6 Mon Sep 17 00:00:00 2001 From: FalseIncarnate Date: Wed, 30 Mar 2016 02:21:10 -0400 Subject: [PATCH 4/9] Logic Gates Adds CONVERT Gates, for converting a signaler signal to logic or vice-versa. Restructured/renamed some of the new logic files - Split up the logic_gates.dm file into three files - mono_input.dm - dual_input.dm - converter.dm Made the logic_gate machines auto-update their multitool menu when you click the links Made the logic gate circuit boards a product of the autolathe - Take that science. Quit hogging all the boards, nerds. Removed relative pathing from signaler.dm --- code/game/machinery/constructable_frame.dm | 12 +- code/modules/assembly/signaler.dm | 274 +++++++++--------- code/modules/logic/converter.dm | 143 +++++++++ .../logic/{logic_gate.dm => dual_input.dm} | 66 +---- code/modules/logic/logic_base.dm | 4 + code/modules/logic/mono_input.dm | 62 ++++ .../research/designs/autolathe_designs.dm | 8 + icons/obj/computer3.dmi | Bin 37029 -> 39447 bytes paradise.dme | 4 +- 9 files changed, 374 insertions(+), 199 deletions(-) create mode 100644 code/modules/logic/converter.dm rename code/modules/logic/{logic_gate.dm => dual_input.dm} (53%) create mode 100644 code/modules/logic/mono_input.dm diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index 9e65a9fc2ac..ba0145fbcd9 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -884,7 +884,7 @@ obj/item/weapon/circuitboard/rdserver //Selectable mode board, like vending machine boards /obj/item/weapon/circuitboard/logic_gate name = "circuit board (Logic Connector)" - build_path = /obj/machinery/logic + build_path = /obj/machinery/logic_gate board_type = "machine" origin_tech = "programming=1" //This stuff is pretty much the absolute basis of programming, so it's mostly useless for research req_components = list(/obj/item/stack/cable_coil = 1) @@ -896,9 +896,17 @@ obj/item/weapon/circuitboard/rdserver "NAND Gate" = /obj/machinery/logic_gate/nand, "NOR Gate" = /obj/machinery/logic_gate/nor, "XOR Gate" = /obj/machinery/logic_gate/xor, - "XNOR Gate" = /obj/machinery/logic_gate/xnor + "XNOR Gate" = /obj/machinery/logic_gate/xnor, + "STATUS Gate" = /obj/machinery/logic_gate/status, + "CONVERT Gate" = /obj/machinery/logic_gate/convert ) +/obj/item/weapon/circuitboard/logic_gate/New() + ..() + if(build_path == /obj/machinery/logic_gate) //If we spawn the base type board (determined by the base type machine as the build path), become a random gate board + var/new_path = names_paths[pick(names_paths)] + set_type(new_path) + /obj/item/weapon/circuitboard/logic_gate/attackby(obj/item/I, mob/user, params) if(istype(I, /obj/item/weapon/screwdriver)) set_type(null, user) diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm index fe33be50f48..2902e3b59c2 100644 --- a/code/modules/assembly/signaler.dm +++ b/code/modules/assembly/signaler.dm @@ -18,149 +18,151 @@ var/datum/radio_frequency/radio_connection var/airlock_wire = null - New() - ..() - if(!radio_controller) - spawn(40) - set_frequency(frequency) - else - spawn(1) // For things that set the frequency directly - set_frequency(frequency) +/obj/item/device/assembly/signaler/New() + ..() + if(!radio_controller) + spawn(40) + set_frequency(frequency) + else + spawn(1) // For things that set the frequency directly + set_frequency(frequency) + return + +/obj/item/device/assembly/signaler/Destroy() + if(radio_controller) + radio_controller.remove_object(src,frequency) + return ..() + +/obj/item/device/assembly/signaler/describe() + return "\The [src]'s power light is [receiving?"on":"off"]" + +/obj/item/device/assembly/signaler/activate() + if(cooldown > 0) return 0 + cooldown = 2 + spawn(10) + process_cooldown() + + signal() + return 1 + +/obj/item/device/assembly/signaler/update_icon() + if(holder) + holder.update_icon() + return + +/obj/item/device/assembly/signaler/interact(mob/user as mob, flag1) + var/t1 = "-------" +// if ((src.b_stat && !( flag1 ))) +// t1 = text("-------
\nGreen Wire: []
\nRed Wire: []
\nBlue Wire: []
\n", (src.wires & 4 ? text("Cut Wire", src) : text("Mend Wire", src)), (src.wires & 2 ? text("Cut Wire", src) : text("Mend Wire", src)), (src.wires & 1 ? text("Cut Wire", src) : text("Mend Wire", src))) +// else +// t1 = "-------" Speaker: [src.listening ? "Engaged" : "Disengaged"]
+ var/dat = {" + + "} + if(!flag1) + dat += {" + Send Signal
+ Reciever is [receiving?"on":"off"]
+ "} + dat += {" + Frequency/Code for signaler:
+ Frequency: + - + - + [format_frequency(src.frequency)] + + + +
+ + Code: + - + - + [src.code] + + + +
+ [t1] +
+ "} + user << browse(dat, "window=radio") + onclose(user, "radio") + return + + +/obj/item/device/assembly/signaler/Topic(href, href_list) + ..() + + if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) + usr << browse(null, "window=radio") + onclose(usr, "radio") return - Destroy() - if(radio_controller) - radio_controller.remove_object(src,frequency) - return ..() + if (href_list["freq"]) + var/new_frequency = (frequency + text2num(href_list["freq"])) + if(new_frequency < RADIO_LOW_FREQ || new_frequency > RADIO_HIGH_FREQ) + new_frequency = sanitize_frequency(new_frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ) + set_frequency(new_frequency) - describe() - return "\The [src]'s power light is [receiving?"on":"off"]" - - activate() - if(cooldown > 0) return 0 - cooldown = 2 - spawn(10) - process_cooldown() + if(href_list["code"]) + src.code += text2num(href_list["code"]) + src.code = round(src.code) + src.code = min(100, src.code) + src.code = max(1, src.code) + if(href_list["receive"]) + receiving = !receiving + if(href_list["send"]) + spawn( 0 ) signal() - return 1 - update_icon() - if(holder) - holder.update_icon() - return - - interact(mob/user as mob, flag1) - var/t1 = "-------" -// if ((src.b_stat && !( flag1 ))) -// t1 = text("-------
\nGreen Wire: []
\nRed Wire: []
\nBlue Wire: []
\n", (src.wires & 4 ? text("Cut Wire", src) : text("Mend Wire", src)), (src.wires & 2 ? text("Cut Wire", src) : text("Mend Wire", src)), (src.wires & 1 ? text("Cut Wire", src) : text("Mend Wire", src))) -// else -// t1 = "-------" Speaker: [src.listening ? "Engaged" : "Disengaged"]
- var/dat = {" - - - Send Signal
- Reciever is [receiving?"on":"off"]
- Frequency/Code for signaler:
- Frequency: - - - - - [format_frequency(src.frequency)] - + - +
- - Code: - - - - - [src.code] - + - +
- [t1] -
"} - user << browse(dat, "window=radio") - onclose(user, "radio") - return - - - Topic(href, href_list) - ..() - - if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) - usr << browse(null, "window=radio") - onclose(usr, "radio") - return - - if (href_list["freq"]) - var/new_frequency = (frequency + text2num(href_list["freq"])) - if(new_frequency < RADIO_LOW_FREQ || new_frequency > RADIO_HIGH_FREQ) - new_frequency = sanitize_frequency(new_frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ) - set_frequency(new_frequency) - - if(href_list["code"]) - src.code += text2num(href_list["code"]) - src.code = round(src.code) - src.code = min(100, src.code) - src.code = max(1, src.code) - if(href_list["receive"]) - receiving = !receiving - - if(href_list["send"]) - spawn( 0 ) - signal() - - if(usr) - attack_self(usr) - - return - - - proc/signal() - if(!radio_connection) return - - var/datum/signal/signal = new - signal.source = src - signal.encryption = code - signal.data["message"] = "ACTIVATE" - radio_connection.post_signal(src, signal) - - var/time = time2text(world.realtime,"hh:mm:ss") - var/turf/T = get_turf(src) - if(usr) - lastsignalers.Add("[time] : [usr.key] used [src] @ location ([T.x],[T.y],[T.z]) : [format_frequency(frequency)]/[code]") - - return - - - pulse(var/radio = 0) - if(src.connected && src.wires) - connected.Pulse(src) - else - return ..(radio) - - - receive_signal(datum/signal/signal) - if( !receiving || !signal ) - return 0 - - if(signal.encryption != code) - return 0 - if(!(src.wires & WIRE_RADIO_RECEIVE)) return 0 - - pulse(1) - for(var/mob/O in hearers(1, src.loc)) - O.show_message(text("\icon[] *beep* *beep*", src), 3, "*beep* *beep*", 2) - return - - - proc/set_frequency(new_frequency) - if(!radio_controller) - sleep(20) - if(!radio_controller) - return - radio_controller.remove_object(src, frequency) - frequency = new_frequency - radio_connection = radio_controller.add_object(src, frequency, RADIO_CHAT) + if(usr) + attack_self(usr) + + return + +/obj/item/device/assembly/signaler/proc/signal() + if(!radio_connection) return + + var/datum/signal/signal = new + signal.source = src + signal.encryption = code + signal.data["message"] = "ACTIVATE" + radio_connection.post_signal(src, signal) + + var/time = time2text(world.realtime,"hh:mm:ss") + var/turf/T = get_turf(src) + if(usr) + lastsignalers.Add("[time] : [usr.key] used [src] @ location ([T.x],[T.y],[T.z]) : [format_frequency(frequency)]/[code]") + + return + +/obj/item/device/assembly/signaler/pulse(var/radio = 0) + if(src.connected && src.wires) + connected.Pulse(src) + else + return ..(radio) + +/obj/item/device/assembly/signaler/receive_signal(datum/signal/signal) + if( !receiving || !signal ) + return 0 + + if(signal.encryption != code) + return 0 + + if(!(src.wires & WIRE_RADIO_RECEIVE)) return 0 + pulse(1) + + for(var/mob/O in hearers(1, src.loc)) + O.show_message(text("\icon[] *beep* *beep*", src), 3, "*beep* *beep*", 2) + return + +/obj/item/device/assembly/signaler/proc/set_frequency(new_frequency) + if(!radio_controller) + sleep(20) + if(!radio_controller) return + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_CHAT) + return // Embedded signaller used in anomalies. /obj/item/device/assembly/signaler/anomaly diff --git a/code/modules/logic/converter.dm b/code/modules/logic/converter.dm new file mode 100644 index 00000000000..3c9266b6c88 --- /dev/null +++ b/code/modules/logic/converter.dm @@ -0,0 +1,143 @@ + +////////////////////////////////// +// Converter Gate // +////////////////////////////////// + +/* + This gate is special enough to warrant its own file, as it overrides a lot of the logic_gate procs as well as adds a new one. + - CONVERT Gates convert signaler and logic signals, to allow logic gates to actually be used in tandem with assemblies and station equipment like doors. + - While technically a mono-input device, the input and output are actually completely different types of signals, and thus incompatible without this gate. + - A signaler must be attached manually before the gate is fully functional, and will retain any frequency and code settings it had when attached. + - You can adjust these settings through a link in the multitool menu, but the receiving mode is automatically controlled by the converter. + - While attached, the ability to manually send the signal on the signaler through its menu is also disabled, to avoid messing up the logic system. +*/ + +//CONVERT Gate +/obj/machinery/logic_gate/convert + name = "CONVERT Gate" + desc = "Converts signals between radio and logic types, allowing for signaller input/output from logic systems." + icon_state = "logic_convert" + mono_input = 1 + + var/logic_output = 0 //When set to 1, the logic signal is the output. When set to 0, the logic signal is the input. + var/obj/item/device/assembly/signaler/attached_signaler = null + +/obj/machinery/logic_gate/convert/handle_logic() + output_state = input1_state + return + +/obj/machinery/logic_gate/convert/attackby(obj/item/O, mob/user, params) + if(tamperproof) //Extra precaution to avoid people attaching/removing signalers from tamperproofed converters + return + if(istype(O, /obj/item/device/assembly/signaler)) + var/obj/item/device/assembly/signaler/S = O + if(S.secured) + user << "The [S] is already secured." + return + if(attached_signaler) + user << "There is already a device attached, remove it first." + return + user.unEquip(S) + S.forceMove(src) + S.holder = src + S.toggle_secure() + if(logic_output) //Make sure we are set to receive if the converter is set to output logic, and send if the converter is set to accept logic input + S.receiving = 1 + else + S.receiving = 0 + attached_signaler = S + user << "You attach \the [S] to the I/O connection port and secure it." + return + if(attached_signaler && istype(O, /obj/item/weapon/screwdriver)) //Makes sure we remove the attached signaler before we can open up and deconstruct the machine + var/obj/item/device/assembly/signaler/S = attached_signaler + attached_signaler = null + S.forceMove(get_turf(src)) + S.holder = null + S.toggle_secure() + user << "You unsecure and detach \the [S] from the I/O connection port." + return + ..() + +/obj/machinery/logic_gate/convert/multitool_menu(var/mob/user, var/obj/item/device/multitool/P) + var/logic_state_string + var/menu_contents = {" +
+ "} + if(logic_output) + switch(output_state) + if(LOGIC_OFF) + logic_state_string = "OFF" + if(LOGIC_ON) + logic_state_string = "ON" + if(LOGIC_FLICKER) + logic_state_string = "FLICKER" + else + logic_state_string = "ERROR: UNKNOWN STATE" + menu_contents += {" +
Output: [format_tag("ID Tag","output_id_tag")]
+
Output State: [logic_state_string]
+ "} + else + switch(input1_state) + if(LOGIC_OFF) + logic_state_string = "OFF" + if(LOGIC_ON) + logic_state_string = "ON" + if(LOGIC_FLICKER) + logic_state_string = "FLICKER" + else + logic_state_string = "ERROR: UNKNOWN STATE" + menu_contents += {" +
Input: [format_tag("ID Tag","input1_id_tag")]
+
Input State: [logic_state_string]
+ "} + menu_contents += {" +
Logic Signal Designation: [logic_output ? "Output" : "Input"]
+ "} + if(attached_signaler) + menu_contents += "
Adjust Signaler Settings
" + else + menu_contents += "
NO SIGNALER ATTACHED!
" + menu_contents += {" +
+ "} + return menu_contents + +/obj/machinery/logic_gate/convert/multitool_topic(var/mob/user,var/list/href_list,var/obj/O) + ..() + if("toggle_logic" in href_list) + logic_output = !logic_output + if(attached_signaler) //If we have a signaler attached, make sure we update it to send/receive when we change the logic signal desgination + if(logic_output) + attached_signaler.receiving = 1 + else + attached_signaler.receiving = 0 + if("adjust_signaler" in href_list && attached_signaler) //Make sure that we have a signaler attached to handle this one, otherwise ignore this command + attached_signaler.interact(user, 1) + update_multitool_menu(user) + +/obj/machinery/logic_gate/convert/receive_signal(datum/signal/signal, receive_method, receive_param) + if(logic_output) + if(attached_signaler) + attached_signaler.receive_signal(signal) + return + else + ..() + +/obj/machinery/logic_gate/convert/handle_output() + if(logic_output) + ..() + else + if(attached_signaler && (output_state == LOGIC_ON || output_state == LOGIC_FLICKER)) + attached_signaler.signal() + return + +/obj/machinery/logic_gate/convert/proc/process_activation(var/obj/item/device/D) + if(!logic_output) //Don't bother if our input is a logic signal + return + if(D == attached_signaler) //Ignore if we somehow got called by a device that isn't what we have attached + input1_state = LOGIC_FLICKER + spawn(LOGIC_FLICKER_TIME) + if(input1_state == LOGIC_FLICKER) + input1_state = LOGIC_OFF + return diff --git a/code/modules/logic/logic_gate.dm b/code/modules/logic/dual_input.dm similarity index 53% rename from code/modules/logic/logic_gate.dm rename to code/modules/logic/dual_input.dm index 5a4c8e2c221..03bfa4f1688 100644 --- a/code/modules/logic/logic_gate.dm +++ b/code/modules/logic/dual_input.dm @@ -1,64 +1,4 @@ -////////////////////////////////// -// Mono-Input Gates // -////////////////////////////////// - -//NOT Gate -/obj/machinery/logic_gate/not - name = "NOT Gate" - desc = "Accepts one input and outputs the reverse state." - mono_input = 1 //NOT Gates are the simplest logic gate because they only utilize one input. - output_state = LOGIC_ON //Starts with an active output, since the input will be OFF at start -/* - A quick note regarding NOT Gates: - - Connecting multiple things to the input of a NOT Gate can cause weird behaviour due to updating both when it receives a signal and when it calls process(). - - This means it will attempt to output once for every logic machine connected to its input's own process() call. - - It will then attempt to output an additional time based on the current state when it comes to its own process() call. - - For this reason, it is HIGHLY RECOMMENDED that you only connect a single signal source to the input of a NOT Gate to avoid signal spasms. - - Connecting multiple things to the output of a NOT Gate should not cause this unusual behavior. -*/ -/obj/machinery/logic_gate/not/handle_logic() //Our output will always be a continuous signal, even with a FLICKER, it just will update the output when the FLICKER ends - if(input1_state == LOGIC_ON) //Output is OFF while input is ON - output_state = LOGIC_OFF - else if(input1_state == LOGIC_FLICKER) //Output is OFF while input is FLICKER, then output returns to ON when input returns to OFF - output_state = LOGIC_OFF - spawn(LOGIC_FLICKER_TIME + 1) //Call handle_logic again after this delay (the input should update from the spawn(LOGIC_FLICKER_TIME) in receive_signal() by then) - handle_logic() - else //Output is ON while input is OFF - output_state = LOGIC_ON - handle_output() - return - -//STATUS Gate -/obj/machinery/logic_gate/status - name = "Status Gate" - desc = "Accepts one input and outputs the same state, showing a colored light based on current state." - mono_input = 1 //STATUS Gate doesn't actually perform logic operations, but instead acts as a testing conduit. - -/* - STATUS Gates are largely a diagnostics tool, but I'm sure someone will still make a logic gate rave with them anyways. - - There is no need to actually connect an output for these to work, they just need an input to sample from. - - STATUS Gates attempt to update their lights whenever they receive a signal. -*/ - -/obj/machinery/logic_gate/status/receive_signal(datum/signal/signal, receive_method, receive_params) - ..() - handle_logic() //STATUS Gate calls handle_logic() when it receives a signal to update its light and output_state - -/obj/machinery/logic_gate/status/handle_logic() - output_state = input1_state //Output is equal to input, since it is simply a connection with an attached light - if(output_state == LOGIC_OFF) //Red light when OFF - set_light(2,2,"#ff0000") - return - if(output_state == LOGIC_ON) //Green light when ON - set_light(2,2,"#009933") - return - if(output_state == LOGIC_FLICKER) //Orange light when FLICKER, then update after LOGIC_FLICKER_TIME + 1 to reflect the changed state - set_light(2,2,"#ff9900") - spawn(LOGIC_FLICKER_TIME + 1) - handle_logic() - return - ////////////////////////////////// // Dual-Input Gates // ////////////////////////////////// @@ -68,6 +8,7 @@ /obj/machinery/logic_gate/or name = "OR Gate" desc = "Outputs ON when at least one input is ON." + icon_state = "logic_or" /obj/machinery/logic_gate/or/handle_logic() if(input1_state == LOGIC_ON || input1_state == LOGIC_FLICKER || input2_state == LOGIC_ON || input2_state == LOGIC_FLICKER) @@ -83,6 +24,7 @@ /obj/machinery/logic_gate/and name = "AND Gate" desc = "Outputs ON only when both inputs are ON." + icon_state = "logic_and" /obj/machinery/logic_gate/and/handle_logic() if((input1_state == LOGIC_ON || input1_state == LOGIC_FLICKER) && (input2_state == LOGIC_ON || input2_state == LOGIC_FLICKER)) @@ -99,6 +41,7 @@ name = "NAND Gate" desc = "Outputs OFF only when both inputs are ON." output_state = LOGIC_ON + icon_state = "logic_nand" /obj/machinery/logic_gate/nand/handle_logic() if((input1_state == LOGIC_ON || input1_state == LOGIC_FLICKER) && (input2_state == LOGIC_ON || input2_state == LOGIC_FLICKER)) @@ -111,6 +54,7 @@ /obj/machinery/logic_gate/nor name = "NOR Gate" desc = "Outputs OFF when at least one input is ON." + icon_state = "logic_nor" output_state = LOGIC_ON /obj/machinery/logic_gate/nor/handle_logic() @@ -124,6 +68,7 @@ /obj/machinery/logic_gate/xor name = "XOR Gate" desc = "Outputs ON when only one input is ON." + icon_state = "logic_xor" /obj/machinery/logic_gate/xor/handle_logic() if((input1_state == LOGIC_ON || input1_state == LOGIC_FLICKER) || input2_state == LOGIC_OFF) //Only input1 is ON/FLICKER, so output matches input1 @@ -138,6 +83,7 @@ /obj/machinery/logic_gate/xnor name = "XNOR Gate" desc = "Outputs ON when both inputs are ON or OFF." + icon_state = "logic_xnor" output_state = LOGIC_ON /obj/machinery/logic_gate/xnor/handle_logic() diff --git a/code/modules/logic/logic_base.dm b/code/modules/logic/logic_base.dm index 129a243c37b..b126b1af214 100644 --- a/code/modules/logic/logic_base.dm +++ b/code/modules/logic/logic_base.dm @@ -193,6 +193,10 @@ "} return menu_contents +/obj/machinery/logic_gate/convert/multitool_topic(var/mob/user,var/list/href_list,var/obj/O) + ..() + update_multitool_menu(user) + /obj/machinery/logic_gate/attackby(obj/item/O, mob/user, params) if(tamperproof) user << "The [src] appears to be tamperproofed! You can't interact with it!" diff --git a/code/modules/logic/mono_input.dm b/code/modules/logic/mono_input.dm new file mode 100644 index 00000000000..58b76232fa0 --- /dev/null +++ b/code/modules/logic/mono_input.dm @@ -0,0 +1,62 @@ + +////////////////////////////////// +// Mono-Input Gates // +////////////////////////////////// + +//NOT Gate +/obj/machinery/logic_gate/not + name = "NOT Gate" + desc = "Accepts one input and outputs the reverse state." + icon_state = "logic_not" + mono_input = 1 //NOT Gates are the simplest logic gate because they only utilize one input. + output_state = LOGIC_ON //Starts with an active output, since the input will be OFF at start +/* + A quick note regarding NOT Gates: + - Connecting multiple things to the input of a NOT Gate can cause weird behaviour due to updating both when it receives a signal and when it calls process(). + - This means it will attempt to output once for every logic machine connected to its input's own process() call. + - It will then attempt to output an additional time based on the current state when it comes to its own process() call. + - For this reason, it is HIGHLY RECOMMENDED that you only connect a single signal source to the input of a NOT Gate to avoid signal spasms. + - Connecting multiple things to the output of a NOT Gate should not cause this unusual behavior. +*/ +/obj/machinery/logic_gate/not/handle_logic() //Our output will always be a continuous signal, even with a FLICKER, it just will update the output when the FLICKER ends + if(input1_state == LOGIC_ON) //Output is OFF while input is ON + output_state = LOGIC_OFF + else if(input1_state == LOGIC_FLICKER) //Output is OFF while input is FLICKER, then output returns to ON when input returns to OFF + output_state = LOGIC_OFF + spawn(LOGIC_FLICKER_TIME + 1) //Call handle_logic again after this delay (the input should update from the spawn(LOGIC_FLICKER_TIME) in receive_signal() by then) + handle_logic() + else //Output is ON while input is OFF + output_state = LOGIC_ON + handle_output() + return + +//STATUS Gate +/obj/machinery/logic_gate/status + name = "Status Gate" + desc = "Accepts one input and outputs the same state, showing a colored light based on current state." + icon_state = "logic_status" + mono_input = 1 //STATUS Gate doesn't actually perform logic operations, but instead acts as a testing conduit. + +/* + STATUS Gates are largely a diagnostics tool, but I'm sure someone will still make a logic gate rave with them anyways. + - There is no need to actually connect an output for these to work, they just need an input to sample from. + - STATUS Gates attempt to update their lights whenever they receive a signal. +*/ + +/obj/machinery/logic_gate/status/receive_signal(datum/signal/signal, receive_method, receive_params) + ..() + handle_logic() //STATUS Gate calls handle_logic() when it receives a signal to update its light and output_state + +/obj/machinery/logic_gate/status/handle_logic() + output_state = input1_state //Output is equal to input, since it is simply a connection with an attached light + if(output_state == LOGIC_OFF) //Red light when OFF + set_light(2,2,"#ff0000") + return + if(output_state == LOGIC_ON) //Green light when ON + set_light(2,2,"#009933") + return + if(output_state == LOGIC_FLICKER) //Orange light when FLICKER, then update after LOGIC_FLICKER_TIME + 1 to reflect the changed state + set_light(2,2,"#ff9900") + spawn(LOGIC_FLICKER_TIME + 1) + handle_logic() + return diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm index aa9437d13e5..53f641a35e1 100644 --- a/code/modules/research/designs/autolathe_designs.dm +++ b/code/modules/research/designs/autolathe_designs.dm @@ -614,4 +614,12 @@ build_type = AUTOLATHE materials = list(MAT_METAL = 150, MAT_GLASS = 125) build_path = /obj/item/weapon/hand_labeler + category = list("initial", "Electronics") + +/datum/design/logic_board + name = "Logic Circuit" + id = "logic_board" + build_type = AUTOLATHE + materials = list(MAT_METAL = 50, MAT_GLASS = 50) + build_path = /obj/item/weapon/circuitboard/logic_gate category = list("initial", "Electronics") \ No newline at end of file diff --git a/icons/obj/computer3.dmi b/icons/obj/computer3.dmi index 7c87ec36102e2bbd7714d176a8cff49ac93531c7..30705076d62a5e2b2785b07a16ff1d103d3cc5f4 100644 GIT binary patch literal 39447 zcmce;XFyY1w>Ap$V%#cbyA@FoP(eXaqJjcaf&~;%P?TPxTWL}vT>>O1Dq9c{5Re+A z_b4q=qaxA?MF=E>AT6|jB#;nN)?Mh{@A=Mm&yV}#p7%#s$yzIO&CJoB@r*Hfe%H>1YcoWHiKs_zG`QQh=>`WZdv#B6<^e(N6pbNC?5*H&;HK;1lf0hnqyV2 z=WJUoN-4f~LxtXdEk!9xLrEfy7L#d{+j~*h>%H-wGp^iNuRi<9LsAoev@hnC_J^Hu z^s}^=O=u_#d@y{!CMAXk-JT~QKk?ApyL!+3P72=C{aJq5fb#R_&qH<}a@-`Ls&kw^ zaOT60S86qXp8d=Gb!@CyO~R*4Y*k0nA;e3YKU6!SW~2A29%iUz9drBG)(P2n>x?N) zg6TA~aQxzjDDlNhs_U@WEz)Z8C#5R}hE9e&zio>&%>5&pFbH5 zqxMEtUNSFBYIyQ{uCjsN!*(;`3Vvz^e-pbo;Ks@h(@VyxZIbyJQ68R$-;!y0SqCZ? zg^engklG|muM?-GN?e|%Sm#iP2SWpf_g&oY(fjJt+4fDlQsK_s``^=p?M0+=$~Su) z$jjX?J4S%V1|r%LPt9;Fv#nZ!m=dzqX0jKw0u^I34fIK-8N_Q>!X%9+20GuFi?6|1JZ z3cng!*v)O#5}^&}Ot~{}Ftg720phP?i7tJReYITa2hUV0FK6z7nU(eDlUi1mr?j}@ zy;R3+8M-Vo(WUdZ9;Pi&gVXl=r!N74T~`kr{H;c0+o#Nte<>EYq?f4lCVZcM zZgfRm)G0~lqnK7(t!SXb?>DYL-W;u(wtDc=HPgv0knYcqF8vWV{K5Y82RVI>3b^%l zm4bhHs~_0wb6E8BO#-}@aE4Y^Hdj_uWLCJ~X!vn`mNeQHFV3FAIILBO~buE$CyUWp4>95FIe z77@|kwrxT5Of&t-Z@bKY3u07}Rv1VOMdgC1h)7TE1=t1S;ov!Uao13(G&%ry*#9mJ;%NH`bPCsZ**lhM-Cu3n@ z zu4y?DJn{g~i3ewdIN8JqL`I6_RlQDlOutnq%5bv)8&5;Kn?`L|+Jj?I@bg_7v=U9okEtX?nQg&E;LQku$cxpf@?>iJ@ouB3tiC&IE+@cyz5u@X-p_jQ|kLITx z(%r4)H54>gm~Ri5-O^qCcGC-qM9$z0b3W}412|KZRkAxS2!c3D6FW)4GKg#!9=^zu zDwK^|0axdWna&OA3BtAW4V%6Qp+-VVNktn>4`E(2l%8ljef@5CQx)`r^N1EbExzNl z&Pvb4xrK$28PV2V{|uF7IVzOhScd6?Ra;+`u;wMs=vf$%rMJ>R~EZEkAgeq3FrSM<&CZpJ}sLyQZ-|KmH1P_O|Z`r*78kNswvmj%L z@S3!)fg~Q9&@FllwKMi@AIa0q!jso~GbcjsPaZUILkR6Hz=oswnAu>bmkqvduKbyK zVB^BF3-(3}_PxN)qSzC&^}71gN>$YTTRlrzJ6bvqzzBSwI~||dFuA|if&LsfCTg-1 zazWeoD!2NtaPx}#-*!I-RWfo^h*Y7K3!*-;iBjUqDW4gHwM)HG2MXUzeOT!;NvC+# zmGZ+|lU{rI=*fEg z@3#ItZP3sRU}B(SvE3qd5cF6FtafLDpZ;-5lBk`1ZvZuCx5*m6xgV(b1+5?=;&O&O z_bENlKf2~%_sZ(Z%0dlVc?#?Ib)QCFGBA=I<7gu6X*JWTZVyhS2*|L^eW+M+{=)O=*U=@e8@YE1x!gIla*L#|0EV(FufF3 z_AN3+&9T5hlGE|j^nRl7PT`SjDZAI#oCHY{^L&Sx(X7#`z}dfgA@didIujHHlcQ%) zPD?T=zQdUQvZKRg7^6A=Y=MqV{)FW<%B(s+?}n?e(kT}z8skv$&JXC6)2%Kvk+Cf8 z>lEKs&wD$OB!T|xBJwnN9M7@^{b)tHKB1inA-JSwPV4lelrLA%3iQ?9~#(8i@Q`zn%PyG!_w-?b#xwz zP~P272v`_;D^YA|bgnm5&ov}2ylk20csYG)$JnT2i^>Jxj==pmpoZjKe@Gq2Kiqu_ zhIy_wpmKrL4&8Mab3VwvmunQ+t{ zbi~TCRnhTx8I9wdNB#Q)+F+BlW&2x}y?}?jqjAPhtp>TfU_xS~2g$!m@G@{Jk><)% zkjliYHL1kqz`5}X7xI5Q<|lm=y)cdhe{$TdioKnu;gOXr&XV_PFROc?UCQ3SGCEGN zG~}&=nhUmA5L`sF@9R$59DJY&wby<1dfu>@?X5-{7%J4!{D+L8_t}eUhQT7OO4tx) z8%z~m^5gWv_hLY z-w!dfuV~Y#RdzhXmjj;^WCb`U6GbDekZI1KP85X#i=C|8_Cu-#nH^cJ?$7uwWi|zF z9h)O0d|%1H(IL$%=O<*eX5^@|MI?@7NEx@R*pX)SBWN1ttzi`^j&(urW!fpgOCYCl z{C9FgIwXKAm4;}y65*kOikz@!p(5JMBr zA<~hZn1z(57LfPJ+xEEf*OpUiZl9+v_a~OF2;($s`%9Jee2Ib7$Z@qL{^7;xpU19L zjbJ+Aa2r195&xm%(E8)WI*uMSa4A%hes?+nv*6ug$)8GxRk7Jgk#M12X!FvpRT1fY z-2RExP0k5ODRkc6E;Sk=Nl+gBh<7Z>XDg` z^L=m38Z$;Et8fKM1hV#M&|~3}?7TYtam);q5MrFI#D6|I0wfNWE)E9QcDLyuigX~m zM8Yhu<2Ytp$uQXSQ7jh{p%+M#^UQ zW)T6k%cY5cGhK2$Gsg-!lnL0%aawS?Sy1CX37ONxB@5i7hur>do1MvqeK^n0Uj*u= zdfdr)GxRC$jc+PFeVP#85A=vVncJicX}8nUb1xh$7&Ef{S1iHFX0+DL9TYxD0NFmVL20II908L(B_*Q98r=$dg4{g89;s_x@C>7kxee@Gg zze>0QZ~7M)%5whB0J22HL9AY;tPe)HS1Mb7g6YU#$-)2cm*%!ebD82&A$n2o6qXt| zGB@%RHY`_(aE5ib(4G1lDL0v_#v_?1xWFm?*HVT@Pp6Gkya4ZzpIlj4x%J}R4!uX) z>Pj0N;@5fclL&>zaYVrFV5xHI~|jMa_GRXDKs-1##xhX=h*Wt;-;+6Qq_jtY#j<` zpv+(C($a5?7n-z$zR0J2pH16r?nNW4QJpf2(TxS(tg4fr{q{{msu4x@kQ?-*1B6*J z5>FXH<}&271$V?qBO`KkW8 zEWf%deOZncQk!mU4d2bQQV!pA(h%*+bBd0#6KQV6-N#%PeXW0yfqXz|X_IefKu_rB zwu^Q4Tk-WCq&$}b^7psI&ezt`GlEyz%+ThPrH4s5eUI{Y-e5xOCZ&8FNOqfByjNN% zW^E^EUWA&i3ISBE{t}iysbp6zh?3JRy+0DkLTA_s?&S5+4*=*9?fywAI= z_9BrNDOd~9y=UOXo0RXPEyZtt3n3%uG9pL)0Gv&j@pp(^6Cz|t{FUH0%|aAc=us!q zu0WV!^P-5B?wAun49v3$&A3ZEUoS%2D$Go!5;J$mjTPC>1DK!s-ciNUEYO1tjjK!a zY+ViQ^>6w1yiRctOp&B1tqh2SiDf5*A1?$tsIk+bW+fnhOG zH|z$pVnOsp9M%c?AdOAoozGz4a(m@63+6#7L6nV!EctWhEx_bdq<4@PkVQef->!1( z+*jKyLGCCq*#DEb)XZqGNi&_T{n`$l$cRC`zi}Oxe`{DFWvG39X(SmfE`1Q*j|+?V zlXnfhRs8li+oW)J*n5h6g~(L}coOKdza10l*MS^;0q23?ySHYlh1p6hhp2B%?xQya z@r9jatcyM0rvo{8HBt9AxVYo}2$9Lvb+t%WAS-Mln=27(=}K6R_Jo&7YkZ?1`W-5A zqXrWa-x}gvE+PoHSLcFrM}3yZ<8Js06}Ax^|aW!@nR5~?_cqcQ{*4|^Bzz2 zRfK-;Uqg1?HF~3A%Da#i78QAVUi8HqtPS+G0wYO!N%Sh1n+J+;R) zI<2S+sZ2yc3a-LM<3Sf##k#2pdH0r|MKKfhbmRQ}gG=4`c%$ThkEtS}FzsR~a>Naj zA`T90mM!9Ok4Ir$u@yO6D-f{SlnJp&kqg^;Pz1^zULf_)L;pBt6_i#~k3037^y2Xb zF6?9#7f_i9J#>-ftpfD1 z1L@w*L0=zYxpF@kbM?SEB^GV%@mXfA9{*gM!6>rZ2*r)3Lf8E?x)!2kG|qYF{S2@h ze(XX#19?W3bDmaHfJuFg;4!42*F<7XtH;4gnp8pK6hA|EOdx zMKW$rfbmOR!G(lKMWpkpRC(ml@~b-~Z#_A&KP{v=a_*Hu6sqb^gZw?ESFej#qc$eB z`Tm~FxSXfya}Gnr-3g83Uyr%&F|z$u9QkL#ioLt0m*8$B$#lM2V@%lo$vbL~c*Jqr zZ!!cCuhkHcMtkw?gg#@u0&h?ATaQeR1am<@asyWQS$!k2CB&g}6P&FFI9961qbq`e zt2k^ZcH>*q*YP4%!FqzH`8$WiQb0$uYOJE2TP+r0(tx`^5DX>hw-n#ke(-^eK30mt z8FMhU(o3*%Y1LX=U66%3ps-4K9P?oD_Lx@YGc76gMXQffvyhehW2L7ut%^}1x$TZ0 zFEv{S1qjkL+Giamr&4%9Q;;ee!~Xk;i_Tn7C-xQEgt5zhS+M7X{Midc(KGFcT`f*q zOHp|92eAXL-v?fB69i2|QQb_T%GfTn ztbElPE3t_*VdX7%?{V?RF1{crXgZ=w!__{8n{60n!*vz0MOQ&@+ZWD(-m4GO25PG{!Q?zM~p*+Q-B&myPp__69&DFGSqI<)) zc8w;3X_toWH&_*9Id5jygI=y%SyT?!`9mvTJ@H^P-*6DZAm$6ci@W0dZ@PcD`Ml8) zr?RNiFHC;Bhlmf%Jhb)gp(q$ej{&O|7#!cm?PXTjX1slaoi2Yxdx%!(xX5F<5&HZ4 zZ=NZi0Srv_fNgRjBHI!FfW9AqILLd7+zb0(LU#X?S^akudG52^8@#))@GBQ5?2<5Sj;z02oR$Cy*uUN-D{e{hb`4E5R#bA9#GS|g^{(a@E z|Mu;R+d$abgIdTqQTRRs#%zOL+#rp0&KnrW=^`ibmU>p7KrZJW4#&b(bPf(Vfc*RE z8zVu9{GLtUFj;P+zjDc+)+(RDeJgbkpczXVOok~It1$$-`NU0FG!K}tG7eJm{r2MnR5Ag60-Spo%@c+g{{V!jVy#u|9 z)uUcha|M}l)3n*Y{n&;?z~wPDGc&urwxRGwpuxoLW7D9h<82rI58=?xao_4@vOD=| zWvkY<|JUM*7dQ;3WacCw|M>5sxT2eRexkgn{{MW~DA#^Nga2I!cq?82><_E|1^@ri zB2W*2=XpWDl8V0_?lh@>>u8#*wBPE@L8VWF9YoZ=tZ7QWWCHS8RJWP0gJKtGnsklY zBB$MS^nfxK2d+ z*|-8d?wFKk#%N3M9Y}L^`SRWJ_yrw*tYKe)5)3POAgKc$|F1H}e^i79FcFd4Jyvp> z++v$fP6u6=cX%Tn@txZOQ7F_VrHr3ux%Q7)qGP!(Y2MFNHbmM7%C>%)Ey!%?Yey!s zWsE54>I56Iyg!d*2f4xOfB^HK?Q$KVCcfQeHI%L$BG7xA(+<~5ORU}kyzw9;|4YQa; zS~pt9srxQ7J6VjD7djOA*VxNElD)Q(ZwF-*i}2%BbR$Bkid}ZKrE~A=nN4yEa7Xlv z)sLzj<CK0* z_G{1cVisD}f$ynGvkNMC3teaXfWe1G=A35>WT5q0yx*V&<(QmWxfiCVG6;`|lWTN~ z>sG~u*K^>2U(hs(0+e?{gO4xq4e=OPQQH-nliW$EWHZsBTJhVxmJa@}6=#c<2)9

F3%xw0@wfqX!HPJUtjTqZ_ zBnp0bw!FgGx*?N0NgqZBuh&x$?mQU-1}13I9X7Ocsq%p8yd&|WpU_< zgIN9{)=`lguf;VIA_*2&vQrW=t0;Y!&a}Kmi5R!9oo;bC8*ditqrNqKe{an_KYX4W zfV^eP)o|F8#vmemJ^i8gq`BU~2jm-PmD589OdN&vDs{eHczL@}*7mNta=T(=#zCW$ zKqvg!{%WQya99G&J^&@4>Ay-5G=Str;Z}QwB2uj(8UZp zAap4YXTy0~MojL$yx$Et`mtuv1GYDI@s;io!uft+yMSaV<&cX}Q zS5de7TcI7@Duh_yu&7pi@W*L~;Zji7iZvmFFHE#)1lfgZGX10T0NU4`6Xr6E?*FPx zfiu{YeQt7?3&HvoGZvBIKbaIs7Go5GL1t3L?w~R|ec4O2A^{JNqC1q@geHONGaVh1 ziYSJhozZfeCe1%O!`FT1Hrc{>bWIy>3@yRzD<2ZxAS2;Q^C1}My;1>YdVDIS=3&r% zu2AlZnnRBezdpUsk!MBI$^OpI1S!EB{*d_0p2)H3j%_iXNnA zR2Z6{bLh`w76oiA zWCF;1)@>cUhpR1O9vgbc@90i>d#1QJB7TxG9Cv8Sq`%~>naKzm6L7t;X3G% zN8mjMqK;!NOLu|cBT^6lZicnr4TKd~{$P8I&kpjil~=!wm63}{+~!~xMT<1wglTR} z0Q6RA2rmu)flhcj#S6}4dSI?YZ#i=B=w1(+B&|z60c(VUtrrrxcZMe~cf_#Pp#rNk zkuZK$AMki12eZ?_{z87^f&U4j?|*`WV3sxcD+oOa<<`3pb~~N>8HTc$@H(HRDw|1Q z;&ZP?+|O8!82`!lDa-S5+fv)yDME)`M;c%&?`@A1gTYi1w9(}7zui(Y zozzt@Q43x^f&pEXW7)o+>8HFY_mOVqgwhk@9m-&-H2lsFiQB7H@#;%oJxA|;9SM>$ ziW@9x>_7$lkh!eD&2`c=W_g7a9>O#+o8xklqmo=QkZ|Y8VPPg;hfJ6z8>QHdvV~x# zjrAAK%^z_a?enyVnM#mn@8w3*muLhFU%JDjE@^uV_D5sniw}k`byR&C)k{NEkeWpP znPR+UY11JlOxwLaaC?XL#zWSH3fi{Sg2{NSKl-+4?L-w>Z5i&h2ob;J>GzrsI^o

U|IIbS_R2exHxRT@g3nd-h(lDdB(VmBmZPl#9v$3g1W=o1U zCmoDpQ--&Bp$hNwC{1p78rJjlLT3arC8wfe{y>)ircA*u(M;W@Xnr;is?!ljz(fJO zhYm4PgDYz*!=o6;jJt5s%l>JELyOri$g?nroC@ zczR_}?9X!Cy3oYYEbP{>mSIG9 zwB2#T`BLD@gkE;)I1#&HiPD}xQSr;IosDxmn8nJ+0kY6Ajve8Y`l6m0UVZU3Qh&o# z*>qe@KwQpB47{sHY-mpRT>|&m0R+fQj`7=(-&*mW){P&=wI)f#m~UdWb4A$~f-@Ip z8STS*nD&szFWPBhQiEbnX6|~jdC5z}jlrsGA*W0EnI4$NWcK&emwm%l4U<#Ey7IcW zV9}>QSvNC}etWe`O))`lXR_J#8&925w_~807{I+!APn)P(Zv1J-9K5iUwk3PYk1( z6ZF*C$X1Od4R4yebeBer;fNfwRyR|_!E#QbJa`{p_d1kz4;!x4Rh)Skb4Hc`>FM6l zt|9*MHq`ap&u~7Wv_?GdsY6@&D871$LO*a$L!zu$9dve{bQvfO6cAf*IlvVVmO4TU z_L-Io=BH9OwT^0l8vSgrM3rjHd`2qq(gA-L(#&NLW698HcpLzI(9@V~z`IsW74u-j zgV!q&fY2j;r{50O6dp!xMWh-9Eorl_sQnPqPw6jWC}CzMFVF7lJ_I+7@f(-Bj)7T~ z`kw5{HwZ=nA5foBLkk<)uSh4i&-Qgg@4Ga}4XHDm%31Bm$^B!8m<+j-EVnK_$k|1u z{sOL$aT`AXekf+A+SNgHI@qaa4TpuGIdr$Kuk~-&4J#cLGug-i0e*^Z<|^tymzMRk z7F)|&Xhu9d%h7j^mCuFr6)ZmT)Pb8q@A-r4G!MVpvkpB6fe}MkY4xmYP><`41dd`f z7!ijCNR~?&nM4?y$@pFwd|S}(G9X0hzMIx^t0L?}iP$wj5;u}3Ay|)beO-LJ33VX1 zPqJrv&Lvp0NYm=m=Bd=#$Ir62fM5W8S|$Mu6(PYqita0r6Vc5dV1}b^=k~!4{7XV3 zMc!}6yITzcnNR^_3ie?(x0Ud?*OdqAN7g{_?G1qc9V>4gmclB{S`m>BfPNVR16>oy zH*cPTX0R-^(yXBN*Ov?|x#xA?1x&!6rYb`1V*qXs2X-eT@U-&?DZeb zlFlpq3PVo>8)3*W`Q=XtW5H6omf~lzhYJ?0>z?!1YtQP7K0l67eZu>3qCBJeZK zDGtsf(U>v5U^aEk@HH5c{>IBjah*TFgs2~kUk$NNAIe70zX1n@>Cq;QnTdA`@PNG3 z%YeCSH&@nSQV8HW($JUQJzzyxx44$9Z53DP)Fs_@0t&IIaE{Kqn#`<08CZ|-HOpJ^ z6u49S>z-M>$M7FV3H)h7i6i;~>6^-?RwY6Y-+Y-Hvu_GBh*W02t)J zeBi4)i00yQmUoTjd)ncTn974m&6WOGv&OchoHNBs$Bq*~hZ;C)00z!(HAISKV}izr ztI)+tF3|I}V`~-(Fj7k2eaBH@m5nDj)M+3S6&oD-rkM}2$0q|#(~lX=QR{8e)6?Jf zbJ%R>IAq?4fQ_FA#l0h4k6p{n%UMc@0Lap3Ii9p_d+8WH_u=xn(Iks|LQY7`RI+^K zcCG0^p?^MVAQgk|<qNbofGU$C(IMqN znm{El+q!*71QQ7*#1&?$9(*p<)s|~sC^9$t!}=h%l#J#LZl@>H8or;xi7bHU7P$sx z09fzx`tj1?mM*VE;{ygjH>{0Ec?XN!B+A=00^?Dz`}b@1N|fhyGY@xRyt||;L~QRq z6RQVrie(+PXe>^D+H*Z=Qt7J)LE@l<_SbC`HTE$fy z;x{2&p{`EQC-rh$`ek4>;k%Ck~Akuei!21HKkGuIX=&JNy1`yvyV=A z2_o1cwi6o_nRu)_)I%S=NB3RavEcM9wmvuNS>|Ym`YSk}mFfhjHPfe``sACI9y>zq z{sc`oMb4g5yH@(Se+xtOjPCDA>1P~SWea69kE}ykFM9SpTkUC{O;#Y(u$tb?N)K$; zy=_Fs8Z>@G{d9u75nrMOo4?PLyL-?D+f@lUX^M8%eYcZUG4rUj*b@4UGk5i}9`~Xm zNX^+t5+`)NKk5##$TDpFQpZR)`{U+GmtHZILT6~-(WQWf?}&v2IU(+4 zcihTfyC2SnXf!mJv$F5O56v!sJvwHjZk2Puf_%+6rk;8k*kNS6^U#XO7shO)wk~&) z)J~MHlH+l7=VJ9&QVrkxm(-(*vki{)^1JI+x=Ii4Ab6leK zy1`Da+w|ZNaI8A$igPyaY2c?=i;(-Q3x!saQVIieqN{mEePXtL&`S*=EQ^ZS=M@B0 z2AE6@gfb(n(0@!qqvbwYEyJ)o%pyZVq)T7^C9Kj9Kctf%H;m`DCJd$W7E*x8vSLR3SED9=PL6yQ} z<_!ZyTaD+H68Io(C;3An{pb8E=&6nkD7?*-N#9(m%dN>bvt6aL&(%5oozOYaGePI^ zHkEKyW`rU1b}{FpWty1V>bga@O1|&O`AHYFWJo%{v+ObOx`?nzmR^U|V5Ta-p;+@Z zVbZRpLy9y_`tXmaOo7!$B|S*xjNBHcI~}sBPo}%9BO}0SVrxF6`bY8DyzE&F}AN@g$PF`f;FRw6razOWRyRWN(8_Y*{3@v?d9gzN20g!6n&nfh4mocx2T zm9La~x{wwXQ=CFmS{ypo;+ZtRedgQEBLmdm+RU^8apZ@BkQPssNVxKzMNjyLN=EbD@rzEcyBa=&~H)BT;|!jP*6a zkKf2=(WPjOMf5dY*1ZP5Au-hKUl8@xw24)rui3Yc`cseuGyd)P9Y6(i?k^7J3id;2 zyrSEsmaxs=V5Df_+aspJzg~()&+Jt`4%Yff9Z8BU(Sdm;wOp@H3?ze}#ex4~HM`6h z`+GnF|MZWgFPMie<3Y7id4?GQxl6DFzGp0|#H3&KxWK6IIq;+V8Iv+O(w6O zV~outC9)M(D_CVsNa?#x$AHrV7b^oM*#P|HrZrs9U7Nn`z7^o@^sFnC@>qOZrQfW% zQD0xKNyB&bHQ(^WJ9oIm;~n4yb7D2iv%9?y+k2&PzIJ^G>Q5eoex7G{iZDRJjIc=|8#BA(1eM{W2jfgbnCa)(Lw8p{Z-af? zezhHI_x`HNS$BgMqkV=IO2C`7Bte&GcQ zQg3V3eV$z?NK^6b(142oTF53H*QY+sy`WNnC+axYferD8)M5K7whO1;Cmk$K>A||d zqIz4c1ZZFa!#^;%k|&b3%Ek2M7qwE)#tY5@PumQ;GyeY{Faix)LFo33Xd$OQqB1=HZUKyI`P@ugK*l1eexl zE?_jhUG5`lNbNg1l3v>i$4`~X?Hwu}_RMbZo^R)bdqsn9bE$&$7y`l29m1aDS6`fL z?RHaO2PPo{gE-MzQ%?SY9QRq8!`orTUH?W3 zu1X9yU$LvR^77?&fU+#O?@Lz1!_DhVhI5@9>U@)g6HB<*w6oDOG=~)Sbv4g=zQ3Su zvsx&FgSVR_ksmdrGz3>}+|*mkTt{gCs5RC6c2!mv6Z(bW={V{R32-x|%tWrjv+6@l zH7nIUM;P+o(6GADlF1#dv6TV0ad^4Tb%e${D~0y{Bg4Y;3_RsT{xu&+Wp{_1JzxSX zZZ+!ri&;6pgGzb8Q=w2{TAsEfLhw84)G8r>t_q`h07O&e(&7RxM(t~)z_ zVSIFS%Rg2PEL8XQJ*l?l27uqyz3#X{cacRvKWYBDtjH_Ze}+s zoL-w~H>wnJ%D!;uR{4oD83r^d6WUms>D=lX8F;1F+X|_woMxWqDwH z5%?djkDlA|P?y{yU&vf@SpvXP-8`*hho%rb11u9qf%tkMe+iRNQ@1Gw5DLH(O=JXT zf6qG>JiJ@Y|%ctlnsOW}g8U*gpSS*_lwch!|kjByPuAlGbEE0B@-8JT8rq zvhb+EXQWR_z2aXLNC!rW}yrORPrr^ueLeBEn>0@HD}mF&%qg@6u{SFpS~*XSx#D+5wRQK?^W zVlv}BfmwEKWenY)%vev0Q<*{Uo8px%e(ts%U1puOIuM;+9`?qkNE>NAasrM6YasC>_tR!>mPGdVwI z``ZKeCtxrg(pHV~e(rkvLQC#?G_T0d?=1#a2TiX%ARn8S4AL5TRCEU@70mWeFD3sa zb-Yc2sE(iBmD!MXXV@!^odkkK%0&GFll_29&Y44=%$mB~S=~YzM!zQ`VaDkm*;&+S zt)qCjX*B{|s)5BYHg1Vl8mJC`oL5{wKns>vAO5%oPhESY_| zjh*pFk1#Uh{TmA5Z9tuvt@b;-pN{D}0C}9VA}&X|!1l#dV}|4R0~cc4!Nro50@o^* zZ#z7C^8(pZQCFyRA72I3iHWr_6`W1JFBt@&_xEdmy-$7g#FITmq6n8^v0ImmiGtIm zHbIXgJMCFY;`Y-C7tw@yQ@Ey-F{?dO-hxw>VM+2z6x+@Hi z(~#2%niS4+O;etG;Xv`MC$eAdl@HI|IrYy@l1h>#Z{l7)Rd{9Cu$^HRmu|_UzrhKz z@9`4f_OgQweD%={3z=*)qle#$jQr&lU6KMhdRWWh%ufK+ReAz4b@zE=^{_a(` zV=V)MDcPxsX_cKuKK5-47~;wI9gE*~CZ`jHku8|UXvL-GQ~92L&7a!6A?nvh#dvqC zg>Qwr%N4nw_{^H4x%9-uJ9mMMR*))NU3!l7w4T5HG3}xx>#4_JYVn+JT9$LL?zgE0 zfxq6Be?3p|r1Q#ohyAN$vsx6U?BkK^}J z1E3!SDb!Pj^E(z^4xo`hMWa(es%K*V+$k*_SWwAemT~N$;_1A1d3n6FNmu%?% zkwFp@!?`>2hOAq#qBTBq^#}{6RMziZ^VK64t!x3)BJPcHlElJ5kY_}zo4d(t*wG(N zX0Fv*rgpmVVm=Lg&BtVfhEYFOSmGhdUP?bJIxF#@G6md}R=C%@d5Tmc)rBqA4d%>@g+t>M z3cI}3PxinnI3NDs*m%$$2Zm3&XgaDrr&jwQchV)EhP!E|Rr{3kv!FqnvO;1VWCz|%?j ze4FTv-Z2{dWM(&1wzyDU?>yxzZeZyv6<6qzQIfPHSRW?49F~{iTR)0fd@jAWfS z$od=0F52|Grg{R{G~HCU3dM|L;f|+>%FfX;bgJP#Q%Z^VM2<}Y=KKUmsvp>QzKa+O$iKbmaDV|C^WE)oP^+X=z-i&$D<%gA+a%9fkg8+nP@ zhb^RXo%s*w_pVP$KMHQiXb4{UQL8jn+xMnA#yAeW!Y8=B&^y-R*55=#-T+fFS|jPO z5mHup;61W&Igdmv8xKw9|-VT_$>w!4%pw4@2anc#hRT0#i{ z1GyHg8U8QHw{E8!lJ8uN$)~d1pl}rDZEi---p61c*_pHen5zZ)BcI_W-3AJa0D@xm zth@S1Syxsq$y2!OOt!%SAkq0PPsZ!R4Np%`>AfFX=Hp_*`G!A1@rHtwrV^Kt1#}r3 zsiYfk98EC?ZRZ;`>L0xI<4|)c^1_oo)9dNl3Jwon8!Yd8jrB`W-n6ZUAWOroiUpsk z^Q;_{SXlj<%B!FlnwX|e?r^1kbnJ4IDXkK#Q_uIT9QhkN`;gVMFoAC5-*VkByS?9< zYWgKP<6{PDg`doJxM113kLg9<@!Xal<^U z<2CT+>le^4%zq(knAOWcS=*Gero7^EN{jKLehsy*e)SI7lSx_}nJNWXRCKBALkDd7 z$+MPVlkyO|x&jA$4R8oxvXI@xA@=wLvD&p12Z z6kEiGR|sT02_wQ!3t<8pTENAFKn%HUh{)LZl(5|k$Ydvd>Cm9i2mqyHiUz`K`1k8- z^fmBA1A_#Te~>CfoT=um!Ucdm4_jDs$73!9p*N;9xUAs{;1QTREr>cnoce|PGiyjT z#>hX05CBeAp#@U`1P`Bi34W@&DIpJpJN|uVPWo0IVGC8ro;NceTPArCcKY#S>V(lZ zpsEGhU5&n0%_%PX17h;94sXaY6yk8>R11o8;_`fN#bV+PJ;dF9%wwqL$a}t~iCZ1ohjxdm@rNx4lV{(ZsZL#7yXa3E)u>u?ssMa?SZ{D;^&ZBn4j5b)GvwIcUQJq2fUK8rT4oZp>@SxQPT< zi%Lk~yr`B1-swg)P{MwXI_cF2FYXr7El(hhh6eDgC9b?@USxTkr_e}35MfW9^DJ7t z99iJVlYGEGK|{$$?nVOJs6cpP;ql|zMrc>lFKnWhyxppB*X04Be6`LVFm~z*aWX^2 z1&6Opk`VfJ4F**&0WdRjPh7R04ACxrIo!xiU0sq~`t8e6RoY;1Rkd+SSya`{zLk8~ zprsL#f~rE3xLudHRo%;#+lZOC+4)d^gh>TPd@1h@=w-Z)ONER^X^sspt}esnzFZsH zg@94u4u6azQ~v1%X#P-rwnpr?9RkzJ1r(#2)$fYA4)z#u(yGrMM$xyqVoC!@wtKQ; z*(5vq9m>II_GRj56+85(4UZxBRdd+Q1Mr7rIq_N|u2nQ*0w*=bqVw`gO#@0N;?;+Q zAk05gq3|{JcI!M?&h@Z)Q8lG81{P+#%ey=ch#_eq2;Te&Gi!Fsxvyva_}koFtn;i^ zUL!OlWC5yci!~sKB$XtI>i4-B<|QD1bg+*^{DH-kRDrBVg7LA<3P1e(CrZ267gg#OhevHuR z23g+k-Fs~O6dRZ1sTf@{Anfs=tqA4bs*@3Flx_{mfo3+Ti+v)TAn2#GxZW&pexA-i z0$}2eQv2Hej`9@#)#Q7mw!L!CXO8{E1X_1D2+eo){CYEFL0fPsf*r4zY?4A+` zf*n~_-HsH3_B8Pow3;TIwA7$vq?^cAN-ygc=u1Aub6RS7q*zR~SSBG}QZWXBnR zcQt`3R2+7$=@JskFo7i@{pf_?j|xsElEcyaf$sY-U3dw-z%ig_8D=UB8|hnC8q<0^ z>< zPRm!hPm+#o?A&hqk5mx{Zfw*nZ>PdBjj7EcOZ6<%2>vt?s~zZdgzG+7^89s7h~__= z$>WThiC_usbz40)c(JC|poh<8QJbX#oZ|@m#nCI=V$0I4p&=jvvEI~*71v`c@o2bM zh0D+M0zW+#m!O;U$zy{KKj7cVm%G6Vy1}G(r_VQHcLlmUmtzMnq@E&UIG>mT3Jd(6>1+IEHW6YTl;MdZa45x*j3MD zT9L)%gIRwGQ#xc1V-`nh7VkvJ=0%~oCg~69>FWc0t_9vm=Z?hXqZf!|A7R4t#}{-? zPc^1aTt(bNlkAWV@y^w~YJYw?4SXoVjdeh25jP7IXi~RE$ho;Op<-Sd8j!X{Az{&8d1Jtd*!vNUkPqMl=amFX(aI zrc%dQIq{}_O;Gs$pvD_~E*7W(w;0u=^ba-DU695afIRM;T@1XY%B%6Huv?cia*HJo zny~pY`3pB-If(vT$=D?E%6a^6oxlL@SY(fFdo%6Y^T(g*`)alvKTWU?LF;yTxQ|*G zxPluTD!~6I;>>L+yq~7n<>OEqxEX%+jaWj>wL_NZPL1yesuH;EgkHtNS zON+`9Dc?J8{D%nCs$TlKWXp}AMs6K^kAv-fW=^3?;A z*CAKAGCX#ZUQ=wGeH5OaeZvj6TRE|?&k-$|`%Mc5gJ-p~hM37+63DeaPRK{Y;K>ej z%aoO)LIcJ#ETuIi^L(J@Dz8oRe$THt^Gt6IbJR7#;N&LqQbL$UH2B^WxDPfkjPWc) z_9hxFPKk(7?9%vO7@p0`-iFah1M0Q!$p~8!! zZO;nBZubfd(C*1wl6I5nv&dY&k~XuuZ9kjeLlpI%_9mZn-W$kHam{&;zU=EuwSrte zF0LU5mr`hD-ee@50^b)5LNR1=jXSHFrr{pJ+-_s~ z>({OW;u&st9$g+7aSDAQ89qg(0+kSex-7GU$MA4su#d{edod}yrU<%Z7nqq!det>x zz!XAVIC5@g@1FiL@+I@{njHQnvx+Vyz!ZdmaiSEHEfmOHxqczIFp`7uol zcRX@;v1$KF*aAcO5P|ScYb<^nI8e#`RPzhefkLctj!AEQwQRn;bm7V)655&qS!hOsJ`x+?YUelkwJR)Y z7IHayk(a%OPLcT7i1R!8&cvE&m(Kbt=m(qXJw@(^2MQ{dmQE%Rh)~npC3!e(3d@$z z{AKki{Svq6WA?n`iR@DE_Ik#A(`MR_u~0=uwpl$)*v{1z?itvgTOT`q9dX!<*TS{t zIKc~7#{e19c?-Q6%Ex^{82)+GC7J6-Sgo98l(eb2EoD6y0jwB0P2mY=_7ZC9gJCe& z$3XRFtC-s{1+?!RApP>Ap6;6LF+yGc?U)@gnmVLgF1*fNgDx3@fSXE5F;dS;q@k+c zOGziyoN#D3++fuij0u`ddqRnYk{@9UWqPj~Y&RSiNv_(&3NE8KxKh!8H!d%!neDm; z2K1u|nf#*V_fJxP5ZLBYKLU)#C{ZBUSG6BG!+i-fRAVZ&)rZo}iB2uu#B4z@$0RYy1ojLIoToqO(p>*#u2kp~ zzt@RSB#!g=L`f52bs8ukl??2w#6WgGHQbCRH0N#(UKT~?V+KW(tgpL#b$73WH@qoR zt+)2hIsW_Bo4wV31XdNOBBZ#I`0{oyjvL+^EB&y$zJ59?DW_XP6`H8<CcDA^C7?Wyhn63cHOsSExPWEEVPcL=Qc5 zvr58^``W-!Ceij(&sozE&XJLkd1FRv!NFHi~%y z_yp{D?-HS_c*Z9o3;PvSpjwQCpv2J7QQ#f5LC#p5QS(gU(Rzs#u7PWRqcFu8d^Clo z7560I_nFRBQ}(+6L6H5ZVNXS2VfP*C!@;HgRHZT2WVuH$Gb$J7`gdSFvh)Ut z$5@CI?%T0o%**dt88w|m?>GcX|JdI^)G~iOJ=pRAW3-OLo>4H zcNphL1f=^+xYu1ZzRGYpmrT_P|Ayw77RT{13@;an`P46N>X|bjeNi{I7XkzVp&%mW z+A#{F^t4kKW*S@B(hL%N-b|%Mob+=0iqSF9W6L`w4Gj(Jd%btlz2`P?EBDw%LFxMU zxOwlGT?;1v0~zr9vIG`iudy_#m(Me?R8e_s5(FI2_|-rLju~4z#A$uLSjlo8(Hrz{ z$+&{zwG-K)n*GT@|DPo=#COE;fCsF<9$A`p_Uc#76Fs2$U1|h_2<%oQ$-EEXl5eaq zgVZd5igd@lxJ}bw_ohSR8Tsdb^^Xz)0OOpC)2qF;rwfTbnhMJH2J4+=0@*TU0RC%5 zssE$$7d>vcvX_7->FwKOs8dAQvq6$)qs(5Vr&R3~FM&d*OW#)HQ6J+WL_4@4pssO! z?mgzPp6NbV&=J4LeM6A1#@f5l0R*~jydSm(fC`sX?@o3)v^7S4ES1M+WYpyuPqgLT z1tm}Ke%4K)LL1R4D31k$j8tRk3xVQ6N~t%?$dR;pwJtYoPkqK8vfS+7dxs`BkKn5& z>~oI>q$lCRo@aRcbBo&L`lZ?OmgN@mvatVtDt2H5MT%-Z?(;mQ3OkgBbK0ryo6MXe zN<7QQ9|5|#xJ>TX#RIS*;yNpMCpuz1^aT;Ku#cb~BZMCclGn6@MA#&5iYWsZ5ZxCT z&`SJ^n5qHMekDUKal4^OU`~rA`^Y9^?Py8`kr9&n92bzB28n=x)V_3OGsxyw`hdQO z*OOg*0;IR<^*wRZ7}iat)jQt+Ain581q8F>p#8>xBB^|*?>6%cM|E(!ni5frZ+@NW;_n2GDn1&(4i;Qf) z)3kX};Pvv!>5Qlw1o(3R5=fjRgJ?i)mew>(=~X@d4IUWeWGU@Snr9{8 z3Rfje6z}XqwhX4|!@B)fB)^TR?@*0uWzlY0O8?) z!x!pQ^VJavJ94a*CA{ff8|z?^aO%c^-jqcC5av)oeh8-+G<5XHsNc78btM^tI-XQ* z!d31nE|dmcdx#|M>go9s0)Fy&J}A~imfLJ@`fSbcD;`UGJcvyrkL~(wtSY@*YVdip z0$wyjr<<1_=vino$xLtOD8+jiCUd| zbR>^Nfi3;M`^;!=yfc0fD^H?IqKx77_@5`U*0g=)VL@UawK2u_aY+)j57C&ehnmh3 zreZCyhc!z<>>E9vY3orq^SxFEotoy=i`#csH$r){w88FbW2l`k$;TMalEGYvFS41q zpL?)AG+SuThRAw_bYgCDMpJU^>%TVD>&3q7o&RzWofc&@G+pxf!xa1{yJDluy%-fj zKAlm2{OR1NK?)~O_K@4+ZD5-B%B2|qebC<@VKA%3QxK%H%hNZFqrA1bESTV<>769Bug%#5(JkrazZ23THDvRiGB? zoiWqNO>`P0?vQ$dKb1VTcD8dZ{V4i_=+S2@c^$c8vaI`wNk9zxD0>Wwyzuaj6-^Fa zaX-~&gW&c)vOk?xH^SJ@NwHdEY-}8KuOm0B)%;<%)lAOGBb$R@Rw5nY7UQP8>wCm>tsB9^wf$Ik$(tfSvZWKvJFVU^k z3aFYFwD=7u z0dS-I(*Sq#4!!5rc$v>`2e&~g_Aj6?Yw*BO(X$iUolj(gU@ zeUAKf@AikSP_L_uLQ z-}3pB+c|Uk-*xwge`KzQKBzv$^*Q2|ue*>9R-_ZLk%dk~lUpn*GLLOy9<4q*sl=p#~`(MF7Ki<0d;l94%HF3$8f0crIu7nEw_N(ugnUcG_Cq>$~9fj@RQm@t%;l`vu~ITie_MOc^e zaW3X#K$kDx(C&=p%0o8_@+%pyl~lm?VKc`p>A@W8;lT=cWd3BR3b{A&j`W1RSS2`k zn`@?kBZs?r&9jqwvpI-&m(_^zJNhpC$*oeLZ9U9)+X)43y3c>&nDT5H+9lE@oP8KU zaT%&b0kL-K3VhM5tnA;5D$h@5T+$+&M{SF@P)dV2WbQL^Ec!T5S~KIkl}fOwWw6|7 z57Og$3_f-CG!jhx;F8{CPbRiYn!@6h;H)=FNFx+`njkE<`l>mqoZs=Nx~&J8rI)`Ey}mas z$rG^c%yO{;L;#H5u#)w3ciD^Ob6aRnMhRo7KbET$|FCzfG6CnHmw0&IGlt(z3f06Y zGBGpX@;!1GY3%EJJR%E05&H+7bzdL0gao0*mTVsI<(Ax;ttlxi>wZ^PTidp-8sNPw zU-xK=6UF+v9D0B`KLSy+q?sAA$b6%8?t?W%yOBvelu%0h$n_%-3DAG@+c0o(xfKx^ z89%h?`pfU&kM>JAu?Eh|p^^KoUCF6=X%!T}0Bs&zl@z-6ftRb)fn?=f1w%HOp`cTr zB(SIpN>jIPv28gd7wS5{xnv}so~rbS!`8Uwm7xCZ;y=b$D$ZnO3g$IRoyg-n#M>IAFG%cVcRnnqX z|1kNj0v~TOE~se6=@i(QF#KzN|M&xPVK0+mhtzIDp1l!^ycWG03Q1j;xtNQf*lmw( zZihqWz?o;Sw!0b0uX|~{ja`}*? zmX_ArgS96^92@N(;i?&~99&ol4mc`WKqW$#Ht&gO&-DNvBQC zFX@Nh(BtW}Q31j_lykuAz$`q0A!?k_s+gmsB{>*4G6hB;ANU^M@XDt3>ENb99DWnX z7eBm9FRvG%(^dqjU6K|{Tx-WImTkVscgP`~wY|?Ai=+oxO`JE10 z7KJ`bJtzLEz5LgotKnK##pXFdY%0yP&kot`^w7Zn1>a>rrb%+vdj;nh%5<0VIQ8(*|#>y?y(3;O4l` zCDrb(E7PLrW92VMe4p9a{b>DJm%;!-4?j<8>21;3ORm zH%7wmUlEm-_I&3>!n?4rvgSX&*KH-;mOJD}S`;+-35Ap0LF>pO6C=2!AxO}7OS@|w z-MtHXoTmIi7(2CM%Xp5DU?B6g(b>Gb%X4i^p>F4)Nn!eXz%5NTP7=i6Cf@7fy2ef| z8zY5Jj(QHqOXn5mUfBfYT91`j*6u$x>GL@oIsLYcRjlUW)!-%hMngGMd6lwPhdVXJzk zF~@PxWy&$&$9qQlleqM$XSwv%fAs{?$ZD^xuhV?mqOK2f1lZx-2&&(FYPnPchj(tI z6~#GLjT8={w0=di@|I{!$c!}zaA^K&aB4eETDyf%&pWT$bcI_y9dc zz>%zNP~i6qcrcFnw-*7J^yrdeU=ljKwY9aVsd{XFejO@dTNvO(-wqgB(55)TW90eI zWli?<_G^9-j-383508|AtKPbGUdXVg0T9oVre)P1q_u&P=~&p==(1C(6*)fi=3keG%vNej749|NK0XatwU9ZQ|MU%Xk*%6s$nLN8gaqr(KG|McmL z@yE^doGus6D$~a(?=b=-*me>cQ=%69Y5F~lEW=wRhiqmzj9B4_y?8wrPOep-7WEVF z=4T1_kve-cT|f7zbjg3}rmAXmAbYjw4Bvrz-nc++O-P`zAW|Zo#K)LqdNY9V5gikB zFolrFQX(_AYa}P+!nL)uZWz(cFowI17y9L%(TS*et~8w=$`6?1PU}*w6{EX^-?^8K zMFHhVF(H|l3eqe{oup;qlD2(5eJmH=Tm6vj9{@=08jQ=;HLlULxzn|@FqkW|!on!S zMU$R2Z6a;#Lcw0_bfQUr!iP|k1K&Ghn7;jyyUWkf#NuoG8K=TsEdqUx(oqkG?wnUn z`m;n>hhpUF$|TFLCj3YnFR_>qkl&SHEJq6qwM##v5x)Opa|o5>^u>JY3SZrYBUeY? z=^x0;wLm$n7GQ-la2kw4PCuALg?L=cuB>U^xygOxma||3HarRx4#v|+qzA8kisWjw zn7p9QD0GdNcIGv^mZ3Az4 zg9(2F`jHX=$T`6Neb^sExSoBgp0)>?+x>hM0I{Q%y8y7&;nlZz>aSfd9|-fMa7iRs zQ=2uOmAQU!N+A>3mJcaI5UTFcJ`n;YA3)?$PV|*|3huKHuD#EEL1qPj>kUUxI+ftJ zgUpArsBKUId{lCVPxV|c z;GlHQY$V6Vl=Oz+&{#AWMfRXlE*YyybO&7wzh73XsM>Q#Z6P0-UxkxpnrJKca>9UJ zR&gGAgPj(1`pT30-)9LD-HX7T4ge5xIL-b~H5CS@jQ)axQPe&-_4Zu~K)(Uk%Q<>d z>F_Nw@Rx1h@p8W?_beO*r;>nXgP7Llck|Zapj1iWXJ7Hs*SINkY3r1Ag5W0un8 z6ngzd$PXBMC@11n!}Wo3 z7pcjH>rb2EK3or^$(d0pFcccDqOD38I-=oP^f~j)>UGq#&fMc;8z1@>o&)p4ZmK^w zmoL^Co7~cugQrnD@|-q$PatX;I_|qr5BW%x)omgI39DE{rceSOD0^MrD%z}s+D3MF#mdm7X{utys;LBxhYuaCj0{8+jIVN3eqO=^o$ zvW`9iFCEMUqMoe8QarRo%|o_dlU)6z9|tuT+Sw%I?5T%eO@WmnQG8d?Ll*BZ&JlJY zhJsbF%d_;-X!7lK@lu&}9K<>4&h5Maz|zErv`kvvWgEsAbam>PiUeWaN$CGJ^%FQ} zh+8@P*E}^~5hr9#l4gf*Z`7e}sY;%4))Omdji&raB$>l~B9^aiPM%0+mo2Or>c&!a zcXPYJPPls`3+{pzGN{?x4Hu2oGzD31ImQLdY|!Nhj}g=R4wwS&tkrBlaAeM@wNV^0 z-{0^KrV3CW9*UPfCRXhb!GPQgMl9xoE1AdIfW95&5-F<<=nXWq1#x1hldpiej{kFg z4$rmoz3VoTN(aq3W)I*3ttLjpP+&Nc^e<>l1eF&3CSsvd_|MO_!=UUiDj7#4AN!KY z=BHa?7O}cGIyK87#_O`(uVbOkNi!(8Sj@ty*P|5={+FLv#~qvQ{Pi%wwZBba&Y%+? z^Vcz-J8?1`kmsQPPY1+AC;Io(yXQ~q|NZcS*xx7;@LL8K)y|x}7oK}F;Qv=cHpC{H zzume$|5jn;Krt*V?9a>$|68A?c7eYadB8TOwH7;3Wj|KQ2+hzJt@gl}X^(jWSZ8>2 z^vZdrj*IGUL290!HRvfdU?4rVC!u3?^{A0H1QKJ%=)cp-V9DAdkM?t$oLe3o! z>@IfRf>ZpqW}8yt2l&+F17;gMTQN?*wyoT^U=ocPYG)8* zN?X)GQ${Wt!(bE;!D=r9Q4?rEXy8VG&%8WSx+~uAaKwcF5b8A_0$P}#+)`oWH}{c` zW<`Jb)5RTU=2$0e$*30$ZhL7c*V(!dyD>EsqK_ok`>RDp7_3GC08@OFJLdkC@u9Oc zpjUY@l+Dx~^B@>O(nS#T4Yvz1b9Cq{X#K;`Wv0e_`25g$E-n< zoh}B-S_GF<9ezo!7;VxQq>BIb=<#-iovn8cH)%k?hLm9T4~*nKh2&Ke`Dw69AGBP* z-*H=9Y%Jh zMR&$86$_`e&+HQ|X{@}5G(hPr6^D^jzY8XvVOB)>QLc=9|MLJR^5XLCjeO|N&rReU z7>;O05Tbqw^3C2c3e@_bfD>YNW z69kx_-DU&+_b6^r#1~BuY9te_NCd~jRt5b05=CjgKb~Cks2M}0`a=ni^yjg$Gs4Sg z>UuL37N)-dMiB96zkhDrgH-PScILCVmS9EcA+zkc<+At`r08 zJEcpWMYJ29^lt&1?Hb4fwk%-pqt5TzYH{i3k^ye&gg*lQC0>LadRE6-n+}CbP;_f= z{nL2EG_VYQxo2sPm+{oVTCG4;$YNLwaPxFaSSezcFU>4aF9tT~=WyC0F&ae#1skpP)y6F>Q~+$Jk#! zr}?C;8CCI0YNIBq{tts;>kVtB`-cXRoUI~Xf{;U8moGWu{i@k><~e^g)3V@ERFkoP zMy=Saj}MNggamQWl8D>EeW0bGtq%q}=DS97(w}{ptPItbyKy- z`E7+k4Z*#nOvQ~Xu)!#BV*^l26hr^q%T2WIN28Hjob2+4lO%TiA9d zcnC}{&7gP7={s$GzOVqPGJc?A8;mA9gUQi3=N(; zT3dFEejWk=UTdcUxKSja8vh|7U{dWHOMY0#&w>3AxNht?eK&f@Rm@1RwQ~ zlv!L)o09ampGps<@S5xV0UP26ef+|VvV~Li^Z$hw@}XMIdFnB62#dU*s(TVASK??W z{@%#OfE}tfZw2}82njJO(N@Kv`1hVubsjtXL9l~F&b93ejyf*hrys|X<=fV-2w(Qp z$g5>oQEBsMJZ`!*6wVEWpDkP7UHyLQ0H6(><~|C;7-&zUM0~RNR=YpDN`@-1dB`S! z!tFo@n!XucMWE$!!!JAY#}d%RHFwk{^^vtb$(8Tw1fV5sX=i2nCL z;KB;9V97xEg6qc~xXsb83v`?TwZUO!yc-Ir=}2Is7mvvpHdZ?kcaCq@o{^F*EtM+3h?(XD;%7!(2pN3&vMQ*P4GIwr1Mqz2p4&s^eywfHO z5ckS>t#JHH&O^M;hKGiQxxhuwYuM#yJC-)+?QP!1*o%qBy+7XnlG_7_rx4}SPD-&# z|DrC{bnYJY41EX8WYr1&sOOA-^rWumAoG&9<>av%X}H#Wq*GV=;1*N(9tllak+0n- zD2%ha>tN=n?aJ_Xkk=SETJ@DIlk+UzB-s3L1KlTAR92o)Y6U}kPM;oH%M}E4S@`XC zeEpF%;?WNM7xf{|gs9&-%R-->Y_Kx9{w}dt=aWRul|f_4s%I)8eFm7Jf7@=?j^q7f zUvg^fu}#~~PU$&y;D%OfYxSuuqJHJMZUVP811j|r%*iKMaYD5&Cd zo|#+f6v$lT_|R-gV#_V0u%!NxJCCJr*EgUwc2(vRL)bklkGwy2TUq&=!MuTT)NjUI zi6jjT4Up^VLSYgM5U~T$Hpa{Qp1xEF^?5e4 zma4JirGEjj-(^0w&VqshmIR2N-gAI?Y?IuJ{>xwhM*Ar#v=(IF_w8;y*ucP`pjy?b zK;l368Q;F0>q!?51^mIOprD|wziX>?}@Vm{`RkY+(>(m^2ENMn*Ib3!{cak zJ8d8WC$2IC{1A}?FJ$@dP4dhCGYGp*WJZinZ)KTJhB_XsHlwjvFnN}Uv~Ur=DWYm+ zYWg8CFfdMzTH$regN;?F(q0<``WhxE5+X%It=M3>wYt|P8V)}-mqDUN0*Tk4$oA{&8^X=4SCYv zBsM3OZ(Xej1P>r?m1()lF<1Vy*o{m-1DY(HkNP130!GJa*J9Gxq};S@anSy^EW2 zhW0kg)wrh1ccx~d9dOVF{-iJ0?@PV0S98|L$*y8~z*)QIIpJKo0dJHDKt80gSs0=@ zPxjS4EC*f?NaJ~Vrv-elQPkm$O6(H`j%EeK;HDa^Ljd15PT{W?;H+!T%7FYBh2t3yQ7ncQ6Bd-7@ zi3jw6)GHVhy>SdsQ3U{t{`N7k_ek(Tv0BNqx>H0P|Br}x9T4c`NiyLOi1|KA!0MXD zC@Q`A2$UdEn%G1jxy|E{h1vHV`=vzLA?EVsfHI+acBdj`6}^N z@p)cG@mbq&6XmL3`wk`=yxA_P5ow>PGHV)Bs0WxWf+H3V`lNaeNsh*#s(Aw{&s>=U zwZsI(SrtMXq|@w}s%a7(A&3uf4BBtP1!YA)_zSN1^_x?J#5#2n)hY3*dLX}r=Q!#J zoC=;%QA@o)4HpB;J4R;6RIX;MwT>Q?IXF<>V z;r>aOWhDNuy<0R5vk3d@HRMW#^?z`Y0 zoabEpz0uX~)yN|zesj-nmy_k|OCVY*fZ6!$4`v)j!t%Od`>yk_w|xek))gZ<7wbytkl{1wd6N zTMn{nt^f3p0saE%1@D$~SYFGB>_scCt0rUj$L(zG4fUkoRCsGfp(&b!1D97<4=M5w z+CqmX3L-7iw_`+eI%4==MA3}IsGa{=1(Td00BbKuuBxg^1jAL|*xT=Bu=_u_bN*vg zR7QFEId^yWyuv~QD^J3~dL?FSXK8@N?N403hX58$FGvy{r9WZI$eKAM;u? zzi%)-vx$TW%KpLX3e>o9m3|x*L^j8R!XI+g*19e0vENh#zu%Gs$_Nu}!ucQDpBW@7efkh-ir)I_Av~7T`9n0jO0@Bd3eofl2wr#o# z;EkPM&XrU%xP}Jn+p&Wq+`&Pju^P?XH@CjlmKL=x6?IQ=lX+dp7t;n^yNW$uY4Xb) z6Pl5fuMd5Jy9lK7iJ7zl9{XOp>5P@R_aJZ0doEOUY98n=2COWA;u^{M`sX|<{kyl+ z*E><-X;JQ)T_a_a02u=o?O#D`Iru=P=as$$azGP$YYn)kv|mxpedE zx2uEi9k$oi?zPjW+_b>lH2ZYNW)jdW=0kQslm5WE>YFaRtv!Py5<`iI= zhEx;H;N|@YpXqgSzY&TXftqHxjfPW!$~{pxH=Wnj>Gf;S*ZzDm*7A3Jq}4s@;XB=YFnIskWTQs-UV>EGmF zz+{k+$AL#d&#enTrudZ@m>HTkPv5~XYM z27#fzp~2vFU%O4&AdoU~`37UFzucz%yzd|CN7w~|F2Kf;bJ0quTGlVzCau)n7`Wj~ zs2xE6ZMl4l{*JrhHS?dO&a}p#gJC7o~t(2gk*=H^4p&*j1&DfHs8d zbLajgREbLqMmtu3g5o5|S>UYm;cA@vpBPc?+PT)_RYXjnpy(QLkXVRnY zKV)w>WJlcVKV)y?zcEv=*JcQct`P(jMW4*F+1psrp z>&->_pA7Ra-B)kla&U5Tu3@pA!^3fJLYJO}14I78Ewuc@ZI0&hz|0H=CwCIM1^0*os7hB=rKE|rIWzOe!LTxD znUZEa32-cR9I7KxxpQ5g=r#A8~CV zjQo5rQ429KCFA_?D>wD5a&L7f}Dr2 zm2iW$r?32Mrdl1y&-8siukUr^F3cYrael4AKI?autf5bz#5IW=(SnS7&EqE&|6!p} zQjTcI01zCh#edGN8kQXv1@9><4FHBJGYtLWXQ`*b`qS7lohRZ|#i$W2=)xVTr!bJU z!w7wspE*Oh@@@irGqRar?_{}ML45@!Bd5(43*p)Qlx)GnpQy@tp=Ir5XRlwJ)XitP zq+b+0Rvkx%b%|tHA?eqU7$%LtQsT8CQ{dt~>A0fY$mb?t<)r8ooXz_ulCIajxTzp0 zIuTY}Ws)>D_Lax|aOD+1Vh@4$Nek}&j{XV^yYS48oBaFC6z&`cQvjAzbjfb83p$S* zM^?!c>L&ZL$w~;d?rWrOZv62kEL*8WK2d>f`rsvsw+vnO)yCX ziaO)l4Eu6hs-JVn<5OGigz^($<3{ZH$>>U?BYdz-pcWk)a2TY?GvxMp(S70c_&^Zo zg5|^e_Y9%lY$gC8VTKLp9*x{HygInM(QY?o1*ids(W=@7pv-BqMqCBbhbQeR9yq92wGXnuF( zCbqbzjClvFAz_kW$i;qZW-ReIF#O*Udi%c+rIbRS$xg{m3xM~jH|V(t`)z_L`{B1| zSA(b$_`oGpFpN-fWd5pu%=t$$RyFP^=KTIv@RJJW=*sSs^#W!wy}+Yu==D9|dew(j z*)s#7$){ggAZat@9l3xUGkk?mwP|2vJk)4>(7F*{&)9PxzLWw!Y!^&1C^EZF@<;1H z>0N%XPm4tfej+8{H>gXvaxmSeC^({@66Acm1XMt7^zeg z2h;v;5i`-4;+Yy4;Gs@A8}9bh(=vgIi;Hu*m)SK9RV$4+K-J=xK?6tX5--le$sm@R zRteM}Ij{AxsnbaEq~lJTv~v&?R>le=(4=SlR6$v39*%q%sx7sZOA}0Lx$6tJ!A~+r zzFr)0kKcV1{IJ1q7iCGf^-6gmh#J!&Xx#J_n8q3`5{9aR^K}?)_ZJhnPK;Shqpasi z7I@h;-e3xC&?Cc~`BOf#f2lrDH48PO=J&lA%?PNt)^pKf00jmkxJ^qt-AAP#U9tFc zV6Hso`q_0;_!h;YThjwe_lB%>a3>!}HO$dA&M1~NrKt*TrSO`l$w)pMM^*yzbRb%8 zP(4ZIQ|uPNqx;lEOQAJ(JR{_Y=)ED(1iY*Uu3mfMgq#&4EgzCLKqA1|_|>b2u*JSnMCea!2GXO|k^ zu@5T7r7z|;i>%4~jB8>Sh7-P|I@a>vWY5^^^YrkTbh%jWFmYS=@#D;j z3eH!rUI9YbAHdPEr>fxtgV{9;+^EunuydfD<9?g+ODRJk1MRKSj`}sf9oO0Z%?(oS z<4Iq2D9$;|86SXOUo1+@l2MYyk)j1XjfLyIrc4zD58TH$%2XKTE>9V&+g>5n9uX6y zPW{0m;4@WGWk0N0_WOu#Iua7!?l8B`-T3A?OAiW=pT+ZM{t?rCthZjx&+E$xSGX0O zn`S%0n(j(@+;=+a=V^!9R^Y`skrLgmz@34J|XF|*9`eVu)fUFj;V!( z!^HESc)Wt5l2REk%1z*2gf|kbSo!=$XG4=d&qGHm5B>l)KJ*jSf@g`6jApgTK{h?O zM4b(+0|l5T#E9=pq0NI=P4u3P;Ye~g+h%EC2Z2duV-D>qS$S>n+x~K42Y-P1M=H(y-o2e|~mgl(~|AVF-~vZL=Ib(@heg)|EZws=Ee*+L$Ah%M(Gfz@^pgGVn4E%%OI53q|!5M85|_ z7(vg1UROD)72Q)g1tMKL#Il3tbj%%&1HJHm6pRn3Wtle|!0WX>60Dxz)@bfDBkxeU5oYDGSWd1w4=r(uE1w#jkOQ)khWetv|F=9C$0 zw3|SNpsEPXT3A28x}Df29!q^p-hSPcBx3^t(bLlx*m+xBPn->X$Sc~Pn*8Izi`;hQ zq<2F@(b*;f>W62epiBm;U;RGdWSV`4A>_9s8W9}Gxa z1gc%W6YMj`eYfZi#{2F}*tf#OOAc-qlo^MrHi%K`bUDHFkvd(iJy9!=)BoaRxjo%29g zlb)By2;k+fE9RC?XB?NG6oB4HytR|a@SsiEu?w?0u8Qw;kSO&aD{@(zbLoeba;kp+ zBO2gE9dJ-^TlpyN72(q4ZT!$zP``r14hV==^;R$QDB*9=ewe;AMf=JEH{8(8rT@g` ztgXb&zyKI}AyI>?^d0OXem)-kJf{%KrTX$#r+9!Jx$K!TsWpisIUjr>QVdNaqMirb zHjD{Tc4HRq2+(=TTv64uOnE<6>$v@BoV6%JU(LHEYo_00;Z$OM_mLm@I;aJ}8^Hj) zdU%Ox)DI^#HET6&eU|4>zj#df;{f88Y+$c=sw_8)65%Y{%kCsHgwnT&6#O8_P6m5?+yhq z|~mo?108!+ao~J{e*2h~AJ5 zVR{nRgHgLS_;F84XJr)M%?>ZQ41>!A*wOVjznW|{^@`30s=a~gw;VIAb?K$VHGi8D zz&=)jI^U&iGaM~l=c?__f~#BE>ZD$<82yy!bn4T(zh(JOu0sqz>LL9&C-5-Ji3)Z2 zvAVQ$E%Q(QeWg{bvZ=m)x*`|iOb(#e&~|)f@Tr8hz_S0HNcAh7a@vA0Lz*bZ3Gv<< z6PgeUh4m1pL(Pw!*{9i3xDs{Ap$rx=q-dF5(&JEw5{%xFvC5RDW)pHI!|Iry1re}f z2(?E#9U6ROo-PPT25kG(FxQiYgExvd59rO#f-`fkn5b33;WDh53qLaBQ{?hHW&&BXdykpfdGr6N?+E173YM65qUx`0{v&l zt_`WqlmWvV2@PLGeVOMRxI2=RLpTFcD7-G9*fAjV@iB^S#i-vwBI8ck=>uVpN~FBY zeQ1`T+A@=^Ts)wYc7<=G_^utDZacm$9JmB#^PsaWa(P19ccvS-tatT}EzfC4U@DWv z)dlFcU}%!u+vL#s8>B9nJ;_WLO~(r>Hi1zO{U*u%qtb7$_-)K^4zsyt5B05ksN678 zqo0(RC^l4+Va;C9a|`-7mO77#e-SwR2zq%m@|pEnS`P|GlA-lKada6ok6xx7$48h~ zPrdY{`r0qduqhwaC|056$YQgz$wgA{yGETG_TCJk#gE1^aOfgh@$aYp+$iyozcRD# ziQ(Fr%y{;d)v;-pzbMdq@XhdVa&aKukE|rf^PM$*eWiQ6#OIOd^W1wftcy(PLLUF4 zsVk3%a_i%dZHA$`ic1vQtS@+N$wc3WDjYG$yh@fgH$eMxwiVy45|s)2PG4c zTuKeuGQx~4G-Y20?|DY=`}Xh5d7kr}-+6w&^E=<)_j?{y0y~~bx!*lQEi%2#vRgE0 zli!I)Yk4~FUafTD7{^Rt=(s5)SA;yFm7*Kk`f1`s{y+`j33d&)*;f$0cc!XIGO7o{ z)uw`%V=e!o0rE3VQo1JxWUdi&)Iw5CThY5SW#3wi&$lrzvrwTNh6epV;HJylt3sW&y`3HtnglW7{?(G1!Pv(@6DXy< z!>kKKeP8XrY8P60Qf(uZ)6$UWm_w8gI_9$WrGFD-UwN9zMckttjoA#@ucIZYXZ-m$ z3`LCqYb^b+>pg+qkx?uyw+qCVC@8l5jS5PAxL* zxA?)mjSNQ8ECSLL%K_Cy;e9Tp-}~P7+P&g>au-}($68k-7b~Qu8|629wMoEwz6*T8 z0-oc1L!&0mJ&~hXOOS+$fy;#pUnhkuc-P;znr8)eRK3VyA)xvL_{2wegPFz5iGaFU zJB%O$gdle$Na2x|FJ;J%E+8RqlFO2?8rRc#^76uh9-agB4@C?zgx_B4qSr; z*-63doAX#~{m@xBJ1Kb82H$ij8 zJTH>aD8zY~~lwE9GD+Ic=2Xb))unq3!7n!o;kSXU}UDhD|*8N<8> z8{=S4=ww{CA+W8s*d5Ft3F#}zbpfiRMF6-e5}>2wS%I3Gnxv>GzAhgCxyt&K*cY11 zRvv&2(W3L7KbN`8Ykv>G&; zYirvw;xMHE-@3&C9cb$4G!?eJEeEuwHV53cWe|%t_*=UW!y}sSZ%5-|zv0D17)aU(o?)#D_>WUR>6}MyXH5#23D2Zs zl}DBo!PxIdWg@Va4}w#`WkJ`jIqI*2qp3jk7zXzG8>S_0C`%DVx+x0Da)>F)id zsH8O0>yfB}H1XGw0J~MP0TIml8&PXMYoq1L>S_bkzUTf2bbWhCKyQ+omNroZ$EEeT zU9h7h&njc|wi6-7z`)h~0-);q`Ixl|9DHVOyRv(kGzx_xjJ@A2$j>JjW0LhpAOgZ- z!8fK`X~#Z_T&kP)%D(CwGeBG`+dEqYVdB^3a;ZY|OrrH8g;=Uu^detU= zbqn27P1pA!HSyAa5ALGU!?)K}HMNc(MqZ*W8U7x>?>Av(mc#Z(?oQ0NGe7E`Yp?GF z-o>r&xce0?sriM^#xXfSMy+d)QuXUe;!FD8*;QJoC96Z9+m{|Rm3TVOOg5}v1T4ss zXDjgLJ&LaaJ|~S7fz5 z`{`8+Fm_mDZ2J-zfy-s;w%tF17Q{&bW?#MqrV6}}{ShOaZQDR?*9Naz%DG3|DBz1i z+A=oLX|fT9cfoc?HG|2dR1cOj3ptu6*B(NI8;wnv3CAX?_U)=0AmU!` z4OtxYis%cojdp)RR2wj_Y63}VNrWzOGQNQpo7~L+g2PB{>pB{~_g`EJGsk=s;4u|h+ zL=j|Ql_eT+c1=nyazRc(ym;>B}sDOf_DC zqGL{OE`LnSjDR}uoF8N|9Jyp3^E=qsjK-BxD94xTw}>CSah~cz(g5NOFoFV9oOE}0 zcP^FMOhALm+}FuTExethV?2mTjlnQ3ys-iYiW00411PbedY}}y`Q$DPd3bm{pYJ$l zX=TL^wVM0@M+|r~9|M*zU~0istI*i3z-)UF`dJBs5D0{|THpHo)o1j}MOygI4`MJZ zW^4@Z&Xz2I^a0XeP@pOyDamKLc&>1(yd<`kpRFH^vMYYRlS(jK(5Hv=jr+js?h6)g zASXm9fWt8k^aT5p@3;-K+3aVq%IDTQ7;M|*f;qjDq0C3Ct=$8-GnqO*>2AXt8^lIW z_WnDduf`A%p)(&m=%AxA{{Q50llIfVkkrTXOG_SCu9)d$9l>oUEqgco8l0s}GAnnz zOMpT9{|2BABv{6}=T)8b4oCm;yEwqEP6IVp3w4}kH)LyVo%v8k5X5JOnSnnFdkhJq zgGqghc*T3 Yme_@ryNeybu{Y3JH0D(CiHp(y0Yz2-3;+NC literal 37029 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 Date: Wed, 30 Mar 2016 15:42:35 -0400 Subject: [PATCH 5/9] Fixes "Adjust Signaler Settings" option not working Window does show up behind the multi-tool menu, but that's not a huge issue. --- code/modules/assembly/signaler.dm | 13 ++++++------- code/modules/logic/converter.dm | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm index 2902e3b59c2..d6d6352f333 100644 --- a/code/modules/assembly/signaler.dm +++ b/code/modules/assembly/signaler.dm @@ -20,13 +20,12 @@ /obj/item/device/assembly/signaler/New() ..() - if(!radio_controller) - spawn(40) - set_frequency(frequency) - else - spawn(1) // For things that set the frequency directly - set_frequency(frequency) - return + if(radio_controller) + set_frequency(frequency) + +/obj/item/device/assembly/signaler/initialize() + if(radio_controller) + set_frequency(frequency) /obj/item/device/assembly/signaler/Destroy() if(radio_controller) diff --git a/code/modules/logic/converter.dm b/code/modules/logic/converter.dm index 3c9266b6c88..635bbf87176 100644 --- a/code/modules/logic/converter.dm +++ b/code/modules/logic/converter.dm @@ -112,7 +112,7 @@ attached_signaler.receiving = 1 else attached_signaler.receiving = 0 - if("adjust_signaler" in href_list && attached_signaler) //Make sure that we have a signaler attached to handle this one, otherwise ignore this command + if(("adjust_signaler" in href_list) && attached_signaler) //Make sure that we have a signaler attached to handle this one, otherwise ignore this command attached_signaler.interact(user, 1) update_multitool_menu(user) From 15786c718b0f1a4579c815b183db38e7029d1b65 Mon Sep 17 00:00:00 2001 From: Fox-McCloud Date: Sat, 2 Apr 2016 21:57:06 -0400 Subject: [PATCH 6/9] Maps in Xenobio Advanced Cams --- _maps/map_files/cyberiad/cyberiad.dmm | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm index dd810edfe60..c66079312ed 100644 --- a/_maps/map_files/cyberiad/cyberiad.dmm +++ b/_maps/map_files/cyberiad/cyberiad.dmm @@ -6977,7 +6977,7 @@ "cEi" = (/obj/machinery/light{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plasteel{dir = 4; icon_state = "blue"},/area/medical/patients_rooms) "cEj" = (/turf/simulated/wall/r_wall,/area/medical/patient_b) "cEk" = (/obj/structure/closet/l3closet/scientist,/obj/machinery/light{dir = 8},/turf/simulated/floor/plasteel{dir = 4; icon_state = "warning"},/area/toxins/xenobiology) -"cEl" = (/obj/structure/table,/obj/item/weapon/storage/box/monkeycubes,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/item/weapon/storage/box/monkeycubes,/obj/item/weapon/storage/box/monkeycubes,/obj/item/weapon/storage/box/monkeycubes,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) +"cEl" = (/obj/structure/table,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/item/weapon/storage/box/monkeycubes,/obj/item/weapon/storage/box/monkeycubes,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cEm" = (/obj/structure/table,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/item/stack/sheet/mineral/plasma{amount = 8; layer = 2.9},/obj/machinery/media/receiver/boombox,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cEn" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cEo" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) @@ -7098,7 +7098,7 @@ "cGz" = (/obj/structure/disposalpipe/segment{dir = 1; icon_state = "pipe-c"},/turf/simulated/floor/plating,/area/maintenance/asmaint) "cGA" = (/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "xenobio1"; name = "Containment Blast Doors"; opacity = 0},/obj/machinery/door/window/northleft{base_state = "right"; dir = 8; icon_state = "right"; name = "Containment Pen"; req_access_txt = "55"},/turf/simulated/floor/engine,/area/toxins/xenobiology) "cGB" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) -"cGC" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/hologram/holopad,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) +"cGC" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8; initialize_directions = 11; level = 1},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/computer/camera_advanced/xenobio,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cGD" = (/obj/machinery/camera{c_tag = "Xenobiology Module East"; dir = 8; network = list("Research","SS13"); pixel_y = -22},/obj/machinery/firealarm{dir = 4; pixel_x = 24},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cGE" = (/turf/simulated/floor/plating/airless,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0; tag = ""},/turf/simulated/floor/plating/airless/catwalk{tag = "icon-catwalk3"; icon_state = "catwalk3"},/area/solar/starboard) "cGF" = (/turf/simulated/floor/plating/airless,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/plating/airless/catwalk{tag = "icon-catwalk3"; icon_state = "catwalk3"},/area/solar/port) @@ -7260,14 +7260,14 @@ "cJF" = (/obj/machinery/air_sensor{frequency = 1441; id_tag = "n2o_sensor"},/turf/simulated/floor/engine/n20,/area/atmos) "cJG" = (/obj/machinery/portable_atmospherics/canister/sleeping_agent/roomfiller{valve_open = 0; volume = 1e+006},/turf/simulated/floor/engine/n20,/area/atmos) "cJH" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor/engine/n20,/area/atmos) -"cJI" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8; initialize_directions = 11; level = 1},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) -"cJJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/disposalpipe/segment{dir = 4; icon_state = "pipe-c"},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) +"cJI" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/disposalpipe/segment{dir = 4; icon_state = "pipe-c"},/obj/machinery/computer/camera_advanced/xenobio,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) +"cJJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/stool/bed/chair/comfy/blue{dir = 1},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cJK" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cJL" = (/obj/item/weapon/extinguisher,/obj/item/weapon/extinguisher{pixel_x = 4; pixel_y = 4},/obj/structure/table/glass,/obj/machinery/atmospherics/unary/vent_scrubber{dir = 8; on = 1; scrub_N2O = 1; scrub_Toxins = 1},/obj/structure/sign/deathsposal{pixel_y = -32},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cJM" = (/obj/structure/rack,/turf/simulated/floor/plating,/area/maintenance/asmaint2) "cJN" = (/turf/simulated/floor/plating/airless/catwalk{tag = "icon-catwalk0"; icon_state = "catwalk0"},/area/space) "cJO" = (/obj/structure/rack,/obj/effect/spawner/lootdrop/maintenance,/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/maintenance/asmaint) -"cJP" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/disposalpipe/segment,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) +"cJP" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/disposalpipe/segment,/obj/structure/stool/bed/chair/comfy/blue{dir = 1},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cJQ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4; level = 1},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4; level = 1},/turf/simulated/floor/plasteel{dir = 5; icon_state = "whitegreencorner"},/area/medical/virology) "cJR" = (/obj/structure/table,/obj/item/device/healthanalyzer,/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/asmaint) "cJS" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{level = 1},/obj/structure/disposalpipe/segment,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) @@ -8730,6 +8730,7 @@ "dlT" = (/obj/machinery/atmospherics/unary/vent_scrubber{on = 1; scrub_N2O = 1; scrub_Toxins = 1},/obj/machinery/power/treadmill{dir = 8},/obj/structure/cable/yellow,/obj/machinery/treadmill_monitor{id = "Cell 2"; pixel_y = -32},/turf/simulated/floor/plasteel,/area/security/prison/cell_block/A) "dlU" = (/obj/structure/stool/bed,/obj/machinery/flasher{id = "Cell 2"; pass_flags = 0; pixel_x = 0; pixel_y = -26},/turf/simulated/floor/plasteel{icon_state = "red"; dir = 4},/area/security/prison/cell_block/A) "dlV" = (/obj/machinery/power/treadmill{dir = 4},/obj/machinery/treadmill_monitor{on = 1; pixel_y = -32; redeem_immediately = 1},/obj/structure/cable/yellow,/turf/simulated/floor/plasteel,/area/security/prison/cell_block/C) +"dlW" = (/obj/machinery/hologram/holopad,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) (1,1,1) = {" bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik @@ -8905,8 +8906,8 @@ bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbi bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaahbikbikbikafxaabczocAkczqbikczocAkczqaabczocAkczqaabbikbikaabaabaabaabaabbikbikbikbikbikaabbikbikczscwWcvKcBecxjcBfcBgcBhcBicBjcBicBkcBicBlcBmcxfcBncztcztczxcBocBpcBqcBrcBscBtcBucBvcBwcBxcBycBzcBAcBBcBCcBDcBDcBEcBFcBGcBHcBIcBJcBKcBLcBMcrecBOcHucHtcDPcDPcDPcDPcDPcDPcHvcoAcEhclUclUclUclUclUclUcjmbEJcjmcFfclUclUcoAcoAcoAcoAcusbGycoAbikbikckPcxOcBZcxOcCacxRcqUcCbcCccCdcCecqUcqUcCgcqUcChckPbikaabaabcwGcwGcCscwGcwGbikbwobxXcvzcyJcHycHxbwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaabbikczocAkczqaabczocAkczqbikczocAkczqbikbikbikbikbikbikaabaabaabbikaabbikaabaabbikbikcybcCicvKcCjcCkcCkcClcvKcvKcvKcvKcvKcvKcvKcvKcvKcvKcvKcvKcvKcCmcCncCmcCocCmcrmcCpcCqcFbcCtcCtcCtcCucCvcBCcCwcCxcCycCzcCAcCBcBIcCCcCDcCEcCFcHzcCHcHAcCJaabcCKcCKcCKcCKcCKcHBcoAcHDcHCcIGcHHcIHctackycjocBWckuckycBXcCPcBYcCRcCQcoAcusbGycoAbikbikckPcxOcxOcxOcAQcCTczbcCUcCVcCWcCXcCZcCZcDacqUcDbckPaabaabbikbikbikcIKbikbikbikbwobxXcvzcyJbxXbxXbwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGacGafxaabbikczocAkczqaabczocAkczqbikczocAkczqaabbikbikbikbikbikbikbikbikaabcDccDdcDdcDdcDdcybcDecwWcDfcDgcDhcDhcDicDjcDkcDlcDlcDlcDlcDmcDncDocDncDncDpcDpcDncDqcDrcDscDtcDtctYcDvcDwcDxcDycDzcDzcDAcDBcDCcDDcDEcDFcCAcDGcBIcDHcDIcDJcDKcILcDMcIMcDOcDPcDQcDRcDScDTcCKcHBcoDcEhclUcvscvqcIOcINcxLckxckwdcrclUcCSczVcuqczVcDUcoAcusbGycoAcoAbikckPcwAcwAcwAcwAcEkcqUcCbcElcEmcCecqUcEncEocEocEpcEqcXYaabbikbikbikbikbikbikbikbwobxXcGybxXbxXcIPbwoaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGbikaabbikaabaabcEraabaabaabcEraabbikaabcEraabbikbikbikbikbikbikbikbikcDccDccDccEscEtcEucEvcEwcExcEycDfcDfcEzcEAcvKcvKcEBcECcECcECcECcEDcEEcEFcEEcEEcEEcDtcDtcEGcEHcEIcEJcEKcDzcELcDwcDzcDzcDzcDzcEMcBCcENcEOcCycDFcCAcDFcBIcDHcDIcEPcEQcERcEScETcEUaabcEVcEWcDTcEXcCKcHBcoDcHDcHCcxKcxJczVcxMclUcIIcDVdcsclUcDWcDYczVcEbcEaclUcusbGycITcoAbikckPcwtcwucwvcFjcARczbcFkcJJcJIcJKcJKcFocFpcFqcJLckPaabaabaabbikbikbikbikbikbikbwocJMcvzbwobwobwobwobwoaabaabaabcJNcJNcJNcJNcJNcJNaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikafxaabcFscFtcFtcFucFvcFwcFwcFwcFvcFwcFwcFwcFvcFwcFwcFxcFtcFtcFtcFtcFtcFycFzcFAcFBcFCcFDcFEcFFcFGcfRcwWcFHcDfcvKcvKcvKcFIcEBcECcFJcFKcFLcyrcFNcDucFPcFOcFQcFScFTcSpcFVcFWcFXcFScFYcFZcDwcGacDzcDzcDzcGbcBCcGccGccDFcGdcGecGfcGgcGhcGicGjcGkcGlcGmcGncDOcGocDQcGpcDTcDTcCKcHBcoDcEhclUcyMcyLcyNcFfclUcnkclTcFfclUcyQcyScyRcyTcyTclUcusbGycJOcoAbikckPcxOcxPcxOcGAcxRcqUcGBcJPcGCcqUcqUcGDcwAcwAcwAckPbikbikaabaabbikbikbikbikbikbwocyKcvzbwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGbikaabbikaabaabcEraabaabaabcEraabbikaabcEraabbikbikbikbikbikbikbikbikcDccDccDccEscEtcEucEvcEwcExcEycDfcDfcEzcEAcvKcvKcEBcECcECcECcECcEDcEEcEFcEEcEEcEEcDtcDtcEGcEHcEIcEJcEKcDzcELcDwcDzcDzcDzcDzcEMcBCcENcEOcCycDFcCAcDFcBIcDHcDIcEPcEQcERcEScETcEUaabcEVcEWcDTcEXcCKcHBcoDcHDcHCcxKcxJczVcxMclUcIIcDVdcsclUcDWcDYczVcEbcEaclUcusbGycITcoAbikckPcwtcwucwvcFjcARczbcFkcJIcGCcJKcJKcFocFpcFqcJLckPaabaabaabbikbikbikbikbikbikbwocJMcvzbwobwobwobwobwoaabaabaabcJNcJNcJNcJNcJNcJNaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikafxaabcFscFtcFtcFucFvcFwcFwcFwcFvcFwcFwcFwcFvcFwcFwcFxcFtcFtcFtcFtcFtcFycFzcFAcFBcFCcFDcFEcFFcFGcfRcwWcFHcDfcvKcvKcvKcFIcEBcECcFJcFKcFLcyrcFNcDucFPcFOcFQcFScFTcSpcFVcFWcFXcFScFYcFZcDwcGacDzcDzcDzcGbcBCcGccGccDFcGdcGecGfcGgcGhcGicGjcGkcGlcGmcGncDOcGocDQcGpcDTcDTcCKcHBcoDcEhclUcyMcyLcyNcFfclUcnkclTcFfclUcyQcyScyRcyTcyTclUcusbGycJOcoAbikckPcxOcxPcxOcGAcxRcqUcGBcJPcJJcqUdlWcGDcwAcwAcwAckPbikbikaabaabbikbikbikbikbikbwocyKcvzbwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGbikaabbikaabaabcGFaabbikaabcGFaabbikaabcGFaabbikbikbikbikbikbikbikbikcDccDccDccGGcGHcFMcDdcGJcfRcGKcExcExcExcExcGLcExcFGcECcGMcGNcGOcGPcGQcGRcGScGTcGUcGVcGWcGXcGYcGZcHacHbcFYcELcDwcHccHdcDzcDzcHecBCcHfcHgcDFcHhcCAcHicHjcHkcHlcHmcHncHocHpcHocHqaabcCKcCKcCKcCKcCKcHBcoAcEhclUcIJcyVcyYcyXcEecEccEgcEfcHwcGucHZczVcIRcIQclUcusbGycJRcoAbikckPcxOcxOcxOcFjcHEcHFcHGcJScHIcCZcCZcCZcHJcHKcHLcHMbikbikbikaabaabbikbikbikbikbwobwocvzbwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGacGafxaabaabczocHOczqbikczocHOczqbikczocHOczqaabbikbikbikbikbikbikbikaabaabcDccDdcDdcDdcDdcHPcHQcHRcfRcHScfRcfRcEBcHTcfRcECcHUcHVcGOcHWcFNcHXcHYcIacIacIbcIccIdcIecIfbRFcIbcIhcIicIjcIkcIlcImcIncIocIpcIqcGfcIrcIscItcIucIvcIwcIxcIycIzcIAcIBcICcIDcDPcDQcIEcIFcIFcCKcHBcoAcEhclUclUclUclUclUcJhcANcBRcJQcMccBScMecMdcMCcBVclUcuscGqcGrcGrcGrcJTcJTcJTcJTcJTcJUcKTcKbcKUcIUczbcIVczbcIWczbcIXcHMbikbikbikbikaabaabbikbikbikbikbwocvzbwoaabaabaabaabaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikczocHOczqaabczocHOczqbikczocHOczqbikbikbikaabbikbikbikbikaabaabaabbikbikaabaabcJbcJbcJbcJbcJbcJbcJbcJccJbcJbcECcJdcJecGOcHWcFNcJfcFNcJgcLhcDtcJicJjcFWcJkcFRcDtcJmcDzcDwcJncJocJpcIncJqcJrcJscJtcJucJvcJwcJtcJxcJycJzcJAcDFcJBcJCcJDcJEaabcEVcJFcJGcJHcCKcHBcoDcKWcKVcKVcKVcKXclUcFacyLcCLcFecyScCMcyTcyTcyScCNclUcuscGvbVibGycKYcKZcoAbikbikckPcJVcJWcJXcJYcJVcJWcJZcKacJVcJWcLackPaabaabaabaabaabaabaabaabaabaabbwocvzbwobwobwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjcbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik From afec3ba8fd43ce4138d07c63a97e6dce72b8bde9 Mon Sep 17 00:00:00 2001 From: FalseIncarnate Date: Tue, 5 Apr 2016 19:28:14 -0400 Subject: [PATCH 7/9] Conflict Fix --- code/__DEFINES/stat.dm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/code/__DEFINES/stat.dm b/code/__DEFINES/stat.dm index 3da3a84455f..fe780c5d154 100644 --- a/code/__DEFINES/stat.dm +++ b/code/__DEFINES/stat.dm @@ -34,10 +34,10 @@ #define WAIT_FINISH 3 //shuttle mode defines -#define SHUTTLE_IDLE 0 -#define SHUTTLE_RECALL 1 -#define SHUTTLE_CALL 2 -#define SHUTTLE_DOCKED 3 +#define SHUTTLE_IDLE 0 +#define SHUTTLE_RECALL 1 +#define SHUTTLE_CALL 2 +#define SHUTTLE_DOCKED 3 #define SHUTTLE_STRANDED 4 #define SHUTTLE_ESCAPE 5 #define SHUTTLE_ENDGAME 6 @@ -52,4 +52,4 @@ #define LOGIC_FLICKER 2 //Use this for when you want it to turn on and then turn off (buttons, clocks) //Logic-related stuff (Misc. defines for logic things, to keep it organized or something) -#define LOGIC_FLICKER_TIME 10 //number of deciseconds LOGIC_TEMP_ON will remain active before turning off \ No newline at end of file +#define LOGIC_FLICKER_TIME 10 //number of deciseconds LOGIC_TEMP_ON will remain active before turning off From a8a0ab317981a4fe8cc5b340d43d64f5ca3741ab Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Tue, 5 Apr 2016 19:43:25 -0400 Subject: [PATCH 8/9] Automatic changelog generation for PR #4075 --- html/changelogs/AutoChangeLog-pr-4075.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4075.yml diff --git a/html/changelogs/AutoChangeLog-pr-4075.yml b/html/changelogs/AutoChangeLog-pr-4075.yml new file mode 100644 index 00000000000..bd13595c356 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4075.yml @@ -0,0 +1,5 @@ +author: Fox McCloud +delete-after: True +changes: + - rscadd: "Maps in the slime management console to Xenobio" + - tweak: "Reduces Xenobio monkey box count from 4 to 2" From 702ac3d367abd0cc45abb206331993aabb448664 Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Tue, 5 Apr 2016 23:38:46 -0400 Subject: [PATCH 9/9] Automatic changelog generation for PR #4041 --- html/changelogs/AutoChangeLog-pr-4041.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4041.yml diff --git a/html/changelogs/AutoChangeLog-pr-4041.yml b/html/changelogs/AutoChangeLog-pr-4041.yml new file mode 100644 index 00000000000..5f208e673c7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4041.yml @@ -0,0 +1,6 @@ +author: FalseIncarnate +delete-after: True +changes: + - rscadd: "Adds logic gates, for doing illogical things in a logical manner." + - rscadd: "Adds buildable light switches, for all your light toggling needs." + - bugfix: "Fixes a resource duplication bug with mass driver buttons."