diff --git a/Content.Server/DeviceLinking/Components/EdgeDetectorComponent.cs b/Content.Server/DeviceLinking/Components/EdgeDetectorComponent.cs new file mode 100644 index 0000000000..8e372302fc --- /dev/null +++ b/Content.Server/DeviceLinking/Components/EdgeDetectorComponent.cs @@ -0,0 +1,36 @@ +using Content.Server.DeviceLinking.Systems; +using Content.Shared.DeviceLinking; +using Content.Shared.MachineLinking; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Server.DeviceLinking.Components; + +/// +/// An edge detector that pulses high or low output ports when the input port gets a rising or falling edge respectively. +/// +[RegisterComponent] +[Access(typeof(EdgeDetectorSystem))] +public sealed class EdgeDetectorComponent : Component +{ + /// + /// Name of the input port. + /// + [DataField("inputPort", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string InputPort = "Input"; + + /// + /// Name of the rising edge output port. + /// + [DataField("outputHighPort", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string OutputHighPort = "OutputHigh"; + + /// + /// Name of the falling edge output port. + /// + [DataField("outputLowPort", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string OutputLowPort = "OutputLow"; + + // Initial state + [ViewVariables] + public SignalState State = SignalState.Low; +} diff --git a/Content.Server/DeviceLinking/Components/LogicGateComponent.cs b/Content.Server/DeviceLinking/Components/LogicGateComponent.cs new file mode 100644 index 0000000000..21c9b27009 --- /dev/null +++ b/Content.Server/DeviceLinking/Components/LogicGateComponent.cs @@ -0,0 +1,73 @@ +using Content.Server.DeviceLinking.Systems; +using Content.Shared.DeviceLinking; +using Content.Shared.MachineLinking; +using Content.Shared.Tools; +using Robust.Shared.Audio; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Server.DeviceLinking.Components; + +/// +/// A logic gate that sets its output port by doing an operation on its 2 input ports, A and B. +/// +[RegisterComponent] +[Access(typeof(LogicGateSystem))] +public sealed class LogicGateComponent : Component +{ + /// + /// The logic gate operation to use. + /// + [DataField("gate")] + public LogicGate Gate = LogicGate.Or; + + /// + /// Tool quality to use for cycling logic gate operations. + /// Cannot be pulsing since linking uses that. + /// + [DataField("cycleQuality", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string CycleQuality = "Screwing"; + + /// + /// Sound played when cycling logic gate operations. + /// + [DataField("cycleSound")] + public SoundSpecifier CycleSound = new SoundPathSpecifier("/Audio/Machines/lightswitch.ogg"); + + /// + /// Name of the first input port. + /// + [DataField("inputPortA", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string InputPortA = "InputA"; + + /// + /// Name of the second input port. + /// + [DataField("inputPortB", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string InputPortB = "InputB"; + + /// + /// Name of the output port. + /// + [DataField("outputPort", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string OutputPort = "Output"; + + // Initial state + [ViewVariables] + public SignalState StateA = SignalState.Low; + + [ViewVariables] + public SignalState StateB = SignalState.Low; + + [ViewVariables] + public bool LastOutput; +} + +/// +/// Last state of a signal port, used to not spam invoking ports. +/// +public enum SignalState : byte +{ + Momentary, // Instantaneous pulse high, compatibility behavior + Low, + High +} diff --git a/Content.Server/DeviceLinking/Components/OrGateComponent.cs b/Content.Server/DeviceLinking/Components/OrGateComponent.cs deleted file mode 100644 index f3e2f18379..0000000000 --- a/Content.Server/DeviceLinking/Components/OrGateComponent.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Content.Server.MachineLinking.Events; - -namespace Content.Server.DeviceLinking.Components; - -[RegisterComponent] -public sealed class OrGateComponent : Component -{ - // Initial state - [ViewVariables] - public SignalState StateA1 = SignalState.Low; - - [ViewVariables] - public SignalState StateB1 = SignalState.Low; - - [ViewVariables] - public SignalState LastO1 = SignalState.Low; - - [ViewVariables] - public SignalState StateA2 = SignalState.Low; - - [ViewVariables] - public SignalState StateB2 = SignalState.Low; - - [ViewVariables] - public SignalState LastO2 = SignalState.Low; -} - -public enum SignalState -{ - Momentary, // Instantaneous pulse high, compatibility behavior - Low, - High -} - diff --git a/Content.Server/DeviceLinking/Systems/DoorSignalControlSystem.cs b/Content.Server/DeviceLinking/Systems/DoorSignalControlSystem.cs index 54b5c36f35..56a754a756 100644 --- a/Content.Server/DeviceLinking/Systems/DoorSignalControlSystem.cs +++ b/Content.Server/DeviceLinking/Systems/DoorSignalControlSystem.cs @@ -65,21 +65,21 @@ namespace Content.Server.DeviceLinking.Systems } else if (args.Port == component.InBolt) { - if (state == SignalState.High) + if (!TryComp(uid, out var bolts)) + return; + + // if its a pulse toggle, otherwise set bolts to high/low + bool bolt; + if (state == SignalState.Momentary) { - if(TryComp(uid, out var bolts)) - _bolts.SetBoltsWithAudio(uid, bolts, true); - } - else if (state == SignalState.Momentary) - { - if (TryComp(uid, out var bolts)) - _bolts.SetBoltsWithAudio(uid, bolts, newBolts: !bolts.BoltsDown); + bolt = !bolts.BoltsDown; } else { - if(TryComp(uid, out var bolts)) - _bolts.SetBoltsWithAudio(uid, bolts, false); + bolt = state == SignalState.High; } + + _bolts.SetBoltsWithAudio(uid, bolts, bolt); } } diff --git a/Content.Server/DeviceLinking/Systems/EdgeDetectorSystem.cs b/Content.Server/DeviceLinking/Systems/EdgeDetectorSystem.cs new file mode 100644 index 0000000000..32b0af1709 --- /dev/null +++ b/Content.Server/DeviceLinking/Systems/EdgeDetectorSystem.cs @@ -0,0 +1,47 @@ +using Content.Server.DeviceLinking.Components; +using Content.Server.DeviceNetwork; +using Content.Server.MachineLinking.Events; +using SignalReceivedEvent = Content.Server.DeviceLinking.Events.SignalReceivedEvent; + +namespace Content.Server.DeviceLinking.Systems; + +public sealed class EdgeDetectorSystem : EntitySystem +{ + [Dependency] private readonly DeviceLinkSystem _deviceLink = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnSignalReceived); + } + + private void OnInit(EntityUid uid, EdgeDetectorComponent comp, ComponentInit args) + { + _deviceLink.EnsureSinkPorts(uid, comp.InputPort); + _deviceLink.EnsureSourcePorts(uid, comp.OutputHighPort, comp.OutputLowPort); + } + + private void OnSignalReceived(EntityUid uid, EdgeDetectorComponent comp, ref SignalReceivedEvent args) + { + // only handle signals with edges + var state = SignalState.Momentary; + if (args.Data == null || + !args.Data.TryGetValue(DeviceNetworkConstants.LogicState, out state) || + state == SignalState.Momentary) + return; + + if (args.Port != comp.InputPort) + return; + + // make sure the level changed, multiple devices sending the same level are treated as one spamming + if (comp.State != state) + { + comp.State = state; + + var port = state == SignalState.High ? comp.OutputHighPort : comp.OutputLowPort; + _deviceLink.InvokePort(uid, port); + } + } +} diff --git a/Content.Server/DeviceLinking/Systems/LogicGateSystem.cs b/Content.Server/DeviceLinking/Systems/LogicGateSystem.cs new file mode 100644 index 0000000000..70e9ede1f2 --- /dev/null +++ b/Content.Server/DeviceLinking/Systems/LogicGateSystem.cs @@ -0,0 +1,133 @@ +using Content.Server.DeviceLinking.Components; +using Content.Server.DeviceNetwork; +using Content.Server.MachineLinking.Events; +using Content.Shared.DeviceLinking; +using Content.Shared.Examine; +using Content.Shared.Interaction; +using Content.Shared.Tools; +using Content.Shared.Popups; +using Robust.Shared.Audio; +using Robust.Shared.Utility; +using SignalReceivedEvent = Content.Server.DeviceLinking.Events.SignalReceivedEvent; + +namespace Content.Server.DeviceLinking.Systems; + +public sealed class LogicGateSystem : EntitySystem +{ + [Dependency] private readonly DeviceLinkSystem _deviceLink = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedToolSystem _tool = default!; + + private readonly int GateCount = Enum.GetValues(typeof(LogicGate)).Length; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnInteractUsing); + SubscribeLocalEvent(OnSignalReceived); + } + + private void OnInit(EntityUid uid, LogicGateComponent comp, ComponentInit args) + { + _deviceLink.EnsureSinkPorts(uid, comp.InputPortA, comp.InputPortB); + _deviceLink.EnsureSourcePorts(uid, comp.OutputPort); + } + + private void OnExamined(EntityUid uid, LogicGateComponent comp, ExaminedEvent args) + { + if (!args.IsInDetailsRange) + return; + + args.PushMarkup(Loc.GetString("logic-gate-examine", ("gate", comp.Gate.ToString().ToUpper()))); + } + + private void OnInteractUsing(EntityUid uid, LogicGateComponent comp, InteractUsingEvent args) + { + if (args.Handled || !_tool.HasQuality(args.Used, comp.CycleQuality)) + return; + + // cycle through possible gates + var gate = (int) comp.Gate; + gate = ++gate % GateCount; + comp.Gate = (LogicGate) gate; + + // since gate changed the output probably has too, update it + UpdateOutput(uid, comp); + + // notify the user + _audio.PlayPvs(comp.CycleSound, uid); + var msg = Loc.GetString("logic-gate-cycle", ("gate", comp.Gate.ToString().ToUpper())); + _popup.PopupEntity(msg, uid, args.User); + _appearance.SetData(uid, LogicGateVisuals.Gate, comp.Gate); + } + + private void OnSignalReceived(EntityUid uid, LogicGateComponent comp, ref SignalReceivedEvent args) + { + // default to momentary for compatibility with non-logic signals. + // currently only door status and logic gates have logic signal state. + var state = SignalState.Momentary; + args.Data?.TryGetValue(DeviceNetworkConstants.LogicState, out state); + + // update the state for the correct port + if (args.Port == comp.InputPortA) + { + comp.StateA = state; + } + else if (args.Port == comp.InputPortB) + { + comp.StateB = state; + } + + UpdateOutput(uid, comp); + } + + /// + /// Handle the logic for a logic gate, invoking the port if the output changed. + /// + private void UpdateOutput(EntityUid uid, LogicGateComponent comp) + { + // get the new output value now that it's changed + var a = comp.StateA == SignalState.High; + var b = comp.StateB == SignalState.High; + var output = false; + switch (comp.Gate) + { + case LogicGate.Or: + output = a || b; + break; + case LogicGate.And: + output = a && b; + break; + case LogicGate.Xor: + output = a != b; + break; + case LogicGate.Nor: + output = !(a || b); + break; + case LogicGate.Nand: + output = !(a && b); + break; + case LogicGate.Xnor: + output = a == b; + break; + } + + // only send a payload if it actually changed + if (output != comp.LastOutput) + { + comp.LastOutput = output; + + var data = new NetworkPayload + { + [DeviceNetworkConstants.LogicState] = output ? SignalState.High : SignalState.Low + }; + + _deviceLink.InvokePort(uid, comp.OutputPort, data); + } + } +} diff --git a/Content.Server/DeviceLinking/Systems/OrGateSystem.cs b/Content.Server/DeviceLinking/Systems/OrGateSystem.cs deleted file mode 100644 index d47c281036..0000000000 --- a/Content.Server/DeviceLinking/Systems/OrGateSystem.cs +++ /dev/null @@ -1,84 +0,0 @@ -using Content.Server.DeviceLinking.Components; -using Content.Server.DeviceNetwork; -using Content.Server.MachineLinking.Events; -using JetBrains.Annotations; -using Robust.Shared.Utility; -using SignalReceivedEvent = Content.Server.DeviceLinking.Events.SignalReceivedEvent; - -namespace Content.Server.DeviceLinking.Systems -{ - [UsedImplicitly] - public sealed class OrGateSystem : EntitySystem - { - - [Dependency] private readonly DeviceLinkSystem _signalSystem = default!; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnSignalReceived); - } - - private void OnInit(EntityUid uid, OrGateComponent component, ComponentInit args) - { - _signalSystem.EnsureSinkPorts(uid, "A1", "B1", "A2", "B2"); - _signalSystem.EnsureSourcePorts(uid, "O1", "O2"); - } - - private void OnSignalReceived(EntityUid uid, OrGateComponent component, ref SignalReceivedEvent args) - { - var state = SignalState.Momentary; - args.Data?.TryGetValue(DeviceNetworkConstants.LogicState, out state); - - switch (args.Port) - { - case "A1": - component.StateA1 = state; - break; - case "B1": - component.StateB1 = state; - break; - case "A2": - component.StateA2 = state; - break; - case "B2": - component.StateB2 = state; - break; - } - - // O1 = A1 || B1 - var v1 = SignalState.Low; - if (component.StateA1 == SignalState.High || component.StateB1 == SignalState.High) - v1 = SignalState.High; - - if (v1 != component.LastO1) - { - var data = new NetworkPayload - { - [DeviceNetworkConstants.LogicState] = v1 - }; - - _signalSystem.InvokePort(uid, "O1", data); - } - - component.LastO1 = v1; - - // O2 = A2 || B2 - var v2 = SignalState.Low; - if (component.StateA2 == SignalState.High || component.StateB2 == SignalState.High) - v2 = SignalState.High; - - if (v2 != component.LastO2) - { - var data = new NetworkPayload - { - [DeviceNetworkConstants.LogicState] = v2 - }; - - _signalSystem.InvokePort(uid, "O2", data); - } - component.LastO2 = v2; - } - } -} diff --git a/Content.Shared/DeviceLinking/SharedLogicGate.cs b/Content.Shared/DeviceLinking/SharedLogicGate.cs new file mode 100644 index 0000000000..8d814f461f --- /dev/null +++ b/Content.Shared/DeviceLinking/SharedLogicGate.cs @@ -0,0 +1,36 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.DeviceLinking; + + +/// +/// Types of logic gates that can be used, determines how the output port is set. +/// +[Serializable, NetSerializable] +public enum LogicGate : byte +{ + Or, + And, + Xor, + Nor, + Nand, + Xnor +} + +/// +/// Tells clients which logic gate layer to draw. +/// +[Serializable, NetSerializable] +public enum LogicGateVisuals : byte +{ + Gate +} + +/// +/// Sprite layer for the logic gate. +/// +[Serializable, NetSerializable] +public enum LogicGateLayers : byte +{ + Gate +} diff --git a/Resources/Locale/en-US/logic-gates/logic-gates.ftl b/Resources/Locale/en-US/logic-gates/logic-gates.ftl new file mode 100644 index 0000000000..1195670e7f --- /dev/null +++ b/Resources/Locale/en-US/logic-gates/logic-gates.ftl @@ -0,0 +1,3 @@ +logic-gate-examine = It is currently {INDEFINITE($gate)} {$gate} gate. + +logic-gate-cycle = Switched to {INDEFINITE($gate)} {$gate} gate diff --git a/Resources/Locale/en-US/machine-linking/receiver_ports.ftl b/Resources/Locale/en-US/machine-linking/receiver_ports.ftl index b5becc5f5d..4d2dd25af2 100644 --- a/Resources/Locale/en-US/machine-linking/receiver_ports.ftl +++ b/Resources/Locale/en-US/machine-linking/receiver_ports.ftl @@ -23,7 +23,7 @@ signal-port-name-close = Close signal-port-description-close = Closes a device. signal-port-name-doorbolt = Door bolt -signal-port-description-doorbolt = Toggles door bolt. +signal-port-description-doorbolt = Bolts door when HIGH. signal-port-name-trigger = Trigger signal-port-description-trigger = Triggers some mechanism on the device. @@ -69,3 +69,12 @@ signal-port-description-set-particle-epsilon = Sets the type of particle this de signal-port-name-set-particle-zeta = Set particle type: zeta signal-port-description-set-particle-zeta = Sets the type of particle this device emits to zeta. + +signal-port-name-logic-input-a = Input A +signal-port-description-logic-input-a = First input of a logic gate. + +signal-port-name-logic-input-b = Input B +signal-port-description-logic-input-b = Second input of a logic gate. + +signal-port-name-logic-input = Input +signal-port-description-logic-input = Input to the edge detector, cannot be a pulse signal. diff --git a/Resources/Locale/en-US/machine-linking/transmitter_ports.ftl b/Resources/Locale/en-US/machine-linking/transmitter_ports.ftl index 2b61bd4e11..909c0dae87 100644 --- a/Resources/Locale/en-US/machine-linking/transmitter_ports.ftl +++ b/Resources/Locale/en-US/machine-linking/transmitter_ports.ftl @@ -14,7 +14,7 @@ signal-port-name-right = Right signal-port-description-right = This port is invoked whenever the lever is moved to the rightmost position. signal-port-name-doorstatus = Door status -signal-port-description-doorstatus = This port is invoked whenever the door's status changes. +signal-port-description-doorstatus = This port is invoked with HIGH when the door opens and LOW when the door closes. signal-port-name-middle = Middle signal-port-description-middle = This port is invoked whenever the lever is moved to the neutral position. @@ -24,3 +24,12 @@ signal-port-description-timer-trigger = This port is invoked whenever the timer signal-port-name-timer-start = Timer Start signal-port-description-timer-start = This port is invoked whenever the timer starts. + +signal-port-name-logic-output = Output +signal-port-description-logic-output = This port is invoked with HIGH or LOW depending on the selected gate and inputs. + +signal-port-name-logic-output-high = High Output +signal-port-description-logic-output-high = This port is invoked whenever the input has a rising edge. + +signal-port-name-logic-output-low = Low Output +signal-port-description-logic-output-low = This port is invoked whenever the input has a falling edge. diff --git a/Resources/Prototypes/DeviceLinking/sink_ports.yml b/Resources/Prototypes/DeviceLinking/sink_ports.yml index 8a52ebbc0d..f05934f3ba 100644 --- a/Resources/Prototypes/DeviceLinking/sink_ports.yml +++ b/Resources/Prototypes/DeviceLinking/sink_ports.yml @@ -79,24 +79,19 @@ description: signal-port-description-artifact-analyzer-receiver - type: sinkPort - id: A1 - name: "Input A1" - description: "Input A1" + id: InputA + name: signal-port-name-logic-input-a + description: signal-port-description-logic-input-a - type: sinkPort - id: B1 - name: "Input B1" - description: "Input B1" + id: InputB + name: signal-port-name-logic-input-b + description: signal-port-description-logic-input-b - type: sinkPort - id: A2 - name: "Input A2" - description: "Input A2" - -- type: sinkPort - id: B2 - name: "Input B2" - description: "Input B2" + id: Input + name: signal-port-name-logic-input + description: signal-port-description-logic-input - type: sinkPort id: SetParticleDelta diff --git a/Resources/Prototypes/DeviceLinking/source_ports.yml b/Resources/Prototypes/DeviceLinking/source_ports.yml index 823e4a164a..151ba9c26f 100644 --- a/Resources/Prototypes/DeviceLinking/source_ports.yml +++ b/Resources/Prototypes/DeviceLinking/source_ports.yml @@ -37,7 +37,8 @@ - type: sourcePort id: DoorStatus name: signal-port-name-doorstatus - description: signal-port-description-status + description: signal-port-description-doorstatus + defaultLinks: [ DoorBolt ] - type: sourcePort id: OrderSender @@ -74,11 +75,16 @@ defaultLinks: [ Close, Off ] - type: sourcePort - id: O1 - name: "Output 1" - description: "Output 1" + id: Output + name: signal-port-name-logic-output + description: signal-port-description-logic-output - type: sourcePort - id: O2 - name: "Output 2" - description: "Output 2" + id: OutputHigh + name: signal-port-name-logic-output-high + description: signal-port-description-logic-output-high + +- type: sourcePort + id: OutputLow + name: signal-port-name-logic-output-low + description: signal-port-description-logic-output-low diff --git a/Resources/Prototypes/Entities/Structures/gates.yml b/Resources/Prototypes/Entities/Structures/gates.yml index 6d487c338a..8e5b1595c8 100644 --- a/Resources/Prototypes/Entities/Structures/gates.yml +++ b/Resources/Prototypes/Entities/Structures/gates.yml @@ -1,31 +1,68 @@ - type: entity - id: OrGate - name: MS7432 - description: Dual 2-Input OR Gate + abstract: true parent: BaseItem - placement: - mode: SnapgridCenter - snap: - - Wallmount + id: BaseLogicItem components: - - type: Anchorable - type: Sprite sprite: Objects/Devices/gates.rsi - state: or + - type: Anchorable - type: Rotatable - - type: OrGate - type: DeviceNetwork deviceNetId: Wireless receiveFrequencyId: BasicDevice - type: WirelessNetworkConnection range: 200 + +- type: entity + parent: BaseLogicItem + id: LogicGate + name: logic gate + description: A logic gate with two inputs and one output. Technicians can change its mode of operation using a screwdriver. + components: + - type: Sprite + layers: + - state: base + - state: or + map: [ "enum.LogicGateLayers.Gate" ] + - type: LogicGate - type: DeviceLinkSink ports: - - A1 - - B1 - - A2 - - B2 + - InputA + - InputB - type: DeviceLinkSource ports: - - O1 - - O2 + - Output + - type: Construction + graph: LogicGate + node: logic_gate + - type: Appearance + - type: GenericVisualizer + visuals: + enum.LogicGateVisuals.Gate: + enum.LogicGateLayers.Gate: + Or: { state: or } + And: { state: and } + Xor: { state: xor } + Nor: { state: nor } + Nand: { state: nand } + Xnor: { state: xnor } + +- type: entity + parent: BaseLogicItem + id: EdgeDetector + name: edge detector + description: Splits rising and falling edges into unique pulses and detects how edgy you are. + components: + - type: Sprite + state: edge_detector + - type: EdgeDetector + - type: DeviceLinkSink + ports: + - Input + - type: DeviceLinkSource + ports: + - OutputHigh + - OutputLow + - type: Construction + graph: LogicGate + node: edge_detector diff --git a/Resources/Prototypes/MachineLinking/receiver_ports.yml b/Resources/Prototypes/MachineLinking/receiver_ports.yml index 9156fd2b59..86e61604cb 100644 --- a/Resources/Prototypes/MachineLinking/receiver_ports.yml +++ b/Resources/Prototypes/MachineLinking/receiver_ports.yml @@ -75,25 +75,20 @@ - type: receiverPort id: DoorBolt - name: "Bolt" - description: "Bolt door when HIGH." + name: signal-port-name-doorbolt + description: signal-port-description-doorbolt - type: receiverPort - id: A1 - name: "Input A1" - description: "Input A1" + id: InputA + name: signal-port-name-logic-input-a + description: signal-port-description-logic-input-a - type: receiverPort - id: B1 - name: "Input B1" - description: "Input B1" + id: InputB + name: signal-port-name-logic-input-b + description: signal-port-description-logic-input-b - type: receiverPort - id: A2 - name: "Input A2" - description: "Input A2" - -- type: receiverPort - id: B2 - name: "Input B2" - description: "Input B2" + id: Input + name: signal-port-name-logic-input + description: signal-port-description-logic-input diff --git a/Resources/Prototypes/MachineLinking/transmitter_ports.yml b/Resources/Prototypes/MachineLinking/transmitter_ports.yml index 41a6a80307..4949097134 100644 --- a/Resources/Prototypes/MachineLinking/transmitter_ports.yml +++ b/Resources/Prototypes/MachineLinking/transmitter_ports.yml @@ -34,6 +34,12 @@ description: signal-port-description-middle defaultLinks: [ Off, Close ] +- type: transmitterPort + id: DoorStatus + name: signal-port-name-doorstatus + description: signal-port-description-doorstatus + defaultLinks: [ DoorBolt ] + - type: transmitterPort id: OrderSender name: signal-port-name-order-sender @@ -49,7 +55,7 @@ id: MedicalScannerSender name: signal-port-name-med-scanner-sender description: signal-port-description-med-scanner-sender - + - type: transmitterPort id: Timer name: signal-port-name-timer-trigger @@ -69,16 +75,16 @@ defaultLinks: [ ArtifactAnalyzerReceiver ] - type: transmitterPort - id: DoorStatus - name: "Door Status" - description: "HIGH when door is open, LOW when door is closed." + id: Output + name: signal-port-name-logic-output + description: signal-port-description-logic-output - type: transmitterPort - id: O1 - name: "Output 1" - description: "Output 1" + id: OutputHigh + name: signal-port-name-logic-output-high + description: signal-port-description-logic-output-high - type: transmitterPort - id: O2 - name: "Output 2" - description: "Output 2" + id: OutputLow + name: signal-port-name-logic-output-low + description: signal-port-description-logic-output-low diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/tools/logic_gate.yml b/Resources/Prototypes/Recipes/Construction/Graphs/tools/logic_gate.yml new file mode 100644 index 0000000000..cf620eaaca --- /dev/null +++ b/Resources/Prototypes/Recipes/Construction/Graphs/tools/logic_gate.yml @@ -0,0 +1,26 @@ +- type: constructionGraph + id: LogicGate + start: start + graph: + - node: start + edges: + - to: logic_gate + steps: + - material: Steel + amount: 3 + doAfter: 1 + - material: Cable + amount: 2 + doAfter: 1 + - to: edge_detector + steps: + - material: Steel + amount: 3 + doAfter: 1 + - material: Cable + amount: 2 + doAfter: 1 + - node: logic_gate + entity: LogicGate + - node: edge_detector + entity: EdgeDetector diff --git a/Resources/Prototypes/Recipes/Construction/tools.yml b/Resources/Prototypes/Recipes/Construction/tools.yml index adb6e5bdf0..cfa968b6ec 100644 --- a/Resources/Prototypes/Recipes/Construction/tools.yml +++ b/Resources/Prototypes/Recipes/Construction/tools.yml @@ -8,3 +8,25 @@ description: A torch fashioned from some wood. icon: { sprite: Objects/Misc/torch.rsi, state: icon } objectType: Item + +- type: construction + name: logic gate + id: LogicGate + graph: LogicGate + startNode: start + targetNode: logic_gate + category: construction-category-tools + description: A binary logic gate for signals. + icon: { sprite: Objects/Devices/gates.rsi, state: or_icon } + objectType: Item + +- type: construction + name: edge detector + id: EdgeDetector + graph: LogicGate + startNode: start + targetNode: edge_detector + category: construction-category-tools + description: An edge detector for signals. + icon: { sprite: Objects/Devices/gates.rsi, state: edge_detector } + objectType: Item diff --git a/Resources/Textures/Objects/Devices/gates.rsi/and.png b/Resources/Textures/Objects/Devices/gates.rsi/and.png new file mode 100644 index 0000000000..426db363ca Binary files /dev/null and b/Resources/Textures/Objects/Devices/gates.rsi/and.png differ diff --git a/Resources/Textures/Objects/Devices/gates.rsi/base.png b/Resources/Textures/Objects/Devices/gates.rsi/base.png new file mode 100644 index 0000000000..946bfb4a29 Binary files /dev/null and b/Resources/Textures/Objects/Devices/gates.rsi/base.png differ diff --git a/Resources/Textures/Objects/Devices/gates.rsi/edge_detector.png b/Resources/Textures/Objects/Devices/gates.rsi/edge_detector.png new file mode 100644 index 0000000000..9985c8b30d Binary files /dev/null and b/Resources/Textures/Objects/Devices/gates.rsi/edge_detector.png differ diff --git a/Resources/Textures/Objects/Devices/gates.rsi/meta.json b/Resources/Textures/Objects/Devices/gates.rsi/meta.json index b71ae48098..1a4ca51419 100644 --- a/Resources/Textures/Objects/Devices/gates.rsi/meta.json +++ b/Resources/Textures/Objects/Devices/gates.rsi/meta.json @@ -1,14 +1,38 @@ { - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Kevin Zheng 2022", - "size": { - "x": 32, - "y": 32 + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "or.png originally created by Kevin Zheng, 2022. All are modified by deltanedas (github) for SS14, 2023.", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "base" }, - "states": [ - { - "name": "or" - } - ] + { + "name": "or" + }, + { + "name": "and" + }, + { + "name": "xor" + }, + { + "name": "nor" + }, + { + "name": "nand" + }, + { + "name": "xnor" + }, + { + "name": "edge_detector" + }, + { + "name": "or_icon" + } + ] } diff --git a/Resources/Textures/Objects/Devices/gates.rsi/nand.png b/Resources/Textures/Objects/Devices/gates.rsi/nand.png new file mode 100644 index 0000000000..3c1373f1ab Binary files /dev/null and b/Resources/Textures/Objects/Devices/gates.rsi/nand.png differ diff --git a/Resources/Textures/Objects/Devices/gates.rsi/nor.png b/Resources/Textures/Objects/Devices/gates.rsi/nor.png new file mode 100644 index 0000000000..a7a6ff845d Binary files /dev/null and b/Resources/Textures/Objects/Devices/gates.rsi/nor.png differ diff --git a/Resources/Textures/Objects/Devices/gates.rsi/or.png b/Resources/Textures/Objects/Devices/gates.rsi/or.png index 513d4f5aee..7a8cc0886f 100644 Binary files a/Resources/Textures/Objects/Devices/gates.rsi/or.png and b/Resources/Textures/Objects/Devices/gates.rsi/or.png differ diff --git a/Resources/Textures/Objects/Devices/gates.rsi/or_icon.png b/Resources/Textures/Objects/Devices/gates.rsi/or_icon.png new file mode 100644 index 0000000000..b81b390cac Binary files /dev/null and b/Resources/Textures/Objects/Devices/gates.rsi/or_icon.png differ diff --git a/Resources/Textures/Objects/Devices/gates.rsi/xnor.png b/Resources/Textures/Objects/Devices/gates.rsi/xnor.png new file mode 100644 index 0000000000..0517c09a4f Binary files /dev/null and b/Resources/Textures/Objects/Devices/gates.rsi/xnor.png differ diff --git a/Resources/Textures/Objects/Devices/gates.rsi/xor.png b/Resources/Textures/Objects/Devices/gates.rsi/xor.png new file mode 100644 index 0000000000..47a258c918 Binary files /dev/null and b/Resources/Textures/Objects/Devices/gates.rsi/xor.png differ diff --git a/Resources/migration.yml b/Resources/migration.yml index cf7b072a74..8960b593c3 100644 --- a/Resources/migration.yml +++ b/Resources/migration.yml @@ -53,7 +53,10 @@ FoodCondimentBottleSmallHotsauce: FoodCondimentBottleHotsauce FoodBakedCookieFortune: FoodSnackCookieFortune GunSafeSubMachineGunVector: GunSafeSubMachineGunDrozd +# 2023-05-29 +OrGate: null + # 2023-05-31 IHSVoidsuit: null ClothingHeadHelmetIHSVoidHelm: null -ClothingHandsGlovesIhscombat: null \ No newline at end of file +ClothingHandsGlovesIhscombat: null