Merge remote-tracking branch 'upstream/master' into to_chat

Conflicts:
	code/game/machinery/door_control.dm
This commit is contained in:
Tigercat2000
2016-04-05 21:10:36 -07:00
21 changed files with 1125 additions and 274 deletions
+137 -136
View File
@@ -18,149 +18,150 @@
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)
set_frequency(frequency)
/obj/item/device/assembly/signaler/initialize()
if(radio_controller)
set_frequency(frequency)
/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("-------<BR>\nGreen Wire: []<BR>\nRed Wire: []<BR>\nBlue Wire: []<BR>\n", (src.wires & 4 ? text("<A href='?src=\ref[];wires=4'>Cut Wire</A>", src) : text("<A href='?src=\ref[];wires=4'>Mend Wire</A>", src)), (src.wires & 2 ? text("<A href='?src=\ref[];wires=2'>Cut Wire</A>", src) : text("<A href='?src=\ref[];wires=2'>Mend Wire</A>", src)), (src.wires & 1 ? text("<A href='?src=\ref[];wires=1'>Cut Wire</A>", src) : text("<A href='?src=\ref[];wires=1'>Mend Wire</A>", src)))
// else
// t1 = "-------" Speaker: [src.listening ? "<A href='byond://?src=\ref[src];listen=0'>Engaged</A>" : "<A href='byond://?src=\ref[src];listen=1'>Disengaged</A>"]<BR>
var/dat = {"
<TT>
"}
if(!flag1)
dat += {"
<A href='byond://?src=\ref[src];send=1'>Send Signal</A><BR>
Reciever is <A href='byond://?src=\ref[src];receive=1'>[receiving?"on":"off"]</A><BR>
"}
dat += {"
<B>Frequency/Code</B> for signaler:<BR>
Frequency:
<A href='byond://?src=\ref[src];freq=-10'>-</A>
<A href='byond://?src=\ref[src];freq=-2'>-</A>
[format_frequency(src.frequency)]
<A href='byond://?src=\ref[src];freq=2'>+</A>
<A href='byond://?src=\ref[src];freq=10'>+</A><BR>
Code:
<A href='byond://?src=\ref[src];code=-5'>-</A>
<A href='byond://?src=\ref[src];code=-1'>-</A>
[src.code]
<A href='byond://?src=\ref[src];code=1'>+</A>
<A href='byond://?src=\ref[src];code=5'>+</A><BR>
[t1]
</TT>
"}
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("-------<BR>\nGreen Wire: []<BR>\nRed Wire: []<BR>\nBlue Wire: []<BR>\n", (src.wires & 4 ? text("<A href='?src=\ref[];wires=4'>Cut Wire</A>", src) : text("<A href='?src=\ref[];wires=4'>Mend Wire</A>", src)), (src.wires & 2 ? text("<A href='?src=\ref[];wires=2'>Cut Wire</A>", src) : text("<A href='?src=\ref[];wires=2'>Mend Wire</A>", src)), (src.wires & 1 ? text("<A href='?src=\ref[];wires=1'>Cut Wire</A>", src) : text("<A href='?src=\ref[];wires=1'>Mend Wire</A>", src)))
// else
// t1 = "-------" Speaker: [src.listening ? "<A href='byond://?src=\ref[src];listen=0'>Engaged</A>" : "<A href='byond://?src=\ref[src];listen=1'>Disengaged</A>"]<BR>
var/dat = {"
<TT>
<A href='byond://?src=\ref[src];send=1'>Send Signal</A><BR>
Reciever is <A href='byond://?src=\ref[src];receive=1'>[receiving?"on":"off"]</A><BR>
<B>Frequency/Code</B> for signaler:<BR>
Frequency:
<A href='byond://?src=\ref[src];freq=-10'>-</A>
<A href='byond://?src=\ref[src];freq=-2'>-</A>
[format_frequency(src.frequency)]
<A href='byond://?src=\ref[src];freq=2'>+</A>
<A href='byond://?src=\ref[src];freq=10'>+</A><BR>
Code:
<A href='byond://?src=\ref[src];code=-5'>-</A>
<A href='byond://?src=\ref[src];code=-1'>-</A>
[src.code]
<A href='byond://?src=\ref[src];code=1'>+</A>
<A href='byond://?src=\ref[src];code=5'>+</A><BR>
[t1]
</TT>"}
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] <B>:</B> [usr.key] used [src] @ location ([T.x],[T.y],[T.z]) <B>:</B> [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] <B>:</B> [usr.key] used [src] @ location ([T.x],[T.y],[T.z]) <B>:</B> [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
+143
View File
@@ -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 << "<span class='warning'>The [S] is already secured.</span>"
return
if(attached_signaler)
user << "<span class='warning'>There is already a device attached, remove it first.</span>"
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 << "<span class='notice'>You attach \the [S] to the I/O connection port and secure it.</span>"
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 << "<span class='notice'>You unsecure and detach \the [S] from the I/O connection port.</span>"
return
..()
/obj/machinery/logic_gate/convert/multitool_menu(var/mob/user, var/obj/item/device/multitool/P)
var/logic_state_string
var/menu_contents = {"
<dl>
"}
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 += {"
<dt><b>Output:</b> [format_tag("ID Tag","output_id_tag")]</dt>
<dd>Output State: [logic_state_string]</dd>
"}
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 += {"
<dt><b>Input:</b> [format_tag("ID Tag","input1_id_tag")]</dt>
<dd>Input State: [logic_state_string]</dd>
"}
menu_contents += {"
<dt><b>Logic Signal Designation:</b> <a href='?src=\ref[src];toggle_logic=1'>[logic_output ? "Output" : "Input"]</a></dt>
"}
if(attached_signaler)
menu_contents += "<dt><a href='?src=\ref[src];adjust_signaler=1'>Adjust Signaler Settings</a></dt>"
else
menu_contents += "<dt><b>NO SIGNALER ATTACHED!</b></dt>"
menu_contents += {"
</dl>
"}
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
+99
View File
@@ -0,0 +1,99 @@
//////////////////////////////////
// Dual-Input Gates //
//////////////////////////////////
// OR Gate
/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)
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."
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))
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
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))
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."
icon_state = "logic_nor"
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."
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
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."
icon_state = "logic_xnor"
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
+283
View File
@@ -0,0 +1,283 @@
/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)
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)
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, 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"))
//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 = {"
<dl>
<dt><b>Input:</b> [format_tag("ID Tag","input1_id_tag")]</dt>
<dd>Input State: [input1_state_string]</dd>
"}
if(!mono_input)
menu_contents = {"
<dt><b>Input 1:</b> [format_tag("ID Tag","input1_id_tag")]</dt>
<dd>Input 1 State: [input1_state_string]</dd>
<dt><b>Input 2:</b> [format_tag("ID Tag","input2_id_tag")]</dt>
<dd>Input 2 State: [input2_state_string]</dd>
"}
menu_contents += {"
<dt><b>Output:</b> [format_tag("ID Tag","output_id_tag")]</dt>
<dd>Output State: [output_state_string]</dd>
</dl>
"}
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 << "<span class='warning'>The [src] appears to be tamperproofed! You can't interact with it!</span>"
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 << "<span class='notice'>You [panel_open ? "open" : "close"] the access panel.</span>"
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 << "<span class='warning'>The [src] appears to be tamperproofed! You can't interface with it!</span>"
return 0
add_hiddenprint(user)
return ui_interact(user)
/obj/machinery/logic_gate/attack_ghost(mob/user)
if(tamperproof)
user << "<span class='warning'>The [src] appears to be tamperproofed! You can't haunt it!</span>"
return 0
return ui_interact(user)
/obj/machinery/logic_gate/attack_hand(mob/user)
if(tamperproof)
user << "<span class='warning'>The [src] appears to be tamperproofed! You can't interact with it!</span>"
return 0
. = ..()
if(.)
return 0
return interact(user)
/obj/machinery/logic_gate/attack_alien(mob/user) //No xeno logic, that's too silly.
user << "<span class='warning'>The [src] appears to be too complex! You can't comprehend it and back off in fear!</span>"
return 0
/obj/machinery/logic_gate/attack_animal(mob/user) //No animal logic either.
user << "<span class='warning'>The [src] appears to be beyond your comprehension! You can't fathom it!</span>"
return 0
/obj/machinery/logic_gate/attack_slime(mob/user) //No slime logic. Seriously.
user << "<span class='warning'>The [src] appears to be beyond your gelatinous understanding! You ignore it!</span>"
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
..()
/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
..()
+62
View File
@@ -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
@@ -638,4 +638,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")