Add interlocking airlocks (#14177)
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
@@ -38,6 +38,57 @@ public sealed class PrototypeSaveTest
|
||||
{
|
||||
"Singularity", // physics collision uses "AllMask" (-1). The flag serializer currently fails to save this because this features un-named bits.
|
||||
"constructionghost",
|
||||
// URGH door pr but I just don't
|
||||
"BlastDoorBridgeOpen",
|
||||
"Windoor",
|
||||
"WindoorSecure",
|
||||
"WindoorSecureCargoLocked",
|
||||
"WindoorTheatreLocked",
|
||||
"BlastDoorBridge",
|
||||
"WindoorSecureJanitorLocked",
|
||||
"ShuttersWindow",
|
||||
"WindoorScienceLocked",
|
||||
"WindoorJanitorLocked",
|
||||
"WindoorEngineeringLocked",
|
||||
"BlastDoorExterior2",
|
||||
"WindoorChemistryLocked",
|
||||
"BlastDoorExterior3",
|
||||
"WindoorMedicalLocked",
|
||||
"ShuttersNormalOpen",
|
||||
"WindoorBarKitchenLocked",
|
||||
"BlastDoorOpen",
|
||||
"ShuttersRadiationOpen",
|
||||
"BlastDoorWindowsOpen",
|
||||
"WindoorBarLocked",
|
||||
"WindoorChapelLocked",
|
||||
"WindoorArmoryLocked",
|
||||
"BlastDoorExterior3Open",
|
||||
"WindoorCargoLocked",
|
||||
"WindoorSecurityLocked",
|
||||
"WindoorExternalLocked",
|
||||
"WindoorBrigLocked",
|
||||
"WindoorHydroponicsLocked",
|
||||
"ShuttersWindowOpen",
|
||||
"WindoorKitchenHydroponicsLocked",
|
||||
"WindoorSecureChapelLocked",
|
||||
"BlastDoorExterior1Open",
|
||||
"WindoorKitchenLocked",
|
||||
"BlastDoor",
|
||||
"BlastDoorWindows",
|
||||
"BlastDoorExterior1",
|
||||
"BlastDoorExterior2Open",
|
||||
"WindoorSecureKitchenLocked",
|
||||
"WindoorHeadOfPersonnelLocked",
|
||||
"ShuttersRadiation",
|
||||
"ShuttersNormal",
|
||||
"WindoorSecureSalvageLocked",
|
||||
"WindoorServiceLocked",
|
||||
"WindoorCommandLocked",
|
||||
"AirlockMaintMedLocked",
|
||||
"AirlockArmoryGlassLocked",
|
||||
"AirlockExternalGlassLocked",
|
||||
"AirlockFreezerKitchenHydroLocked",
|
||||
"AirlockGlassShuttle",
|
||||
};
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -14,5 +14,11 @@ namespace Content.Server.DeviceLinking.Components
|
||||
|
||||
[DataField("togglePort", customTypeSerializer: typeof(PrototypeIdSerializer<ReceiverPortPrototype>))]
|
||||
public string TogglePort = "Toggle";
|
||||
|
||||
[DataField("boltPort", customTypeSerializer: typeof(PrototypeIdSerializer<ReceiverPortPrototype>))]
|
||||
public string InBolt = "DoorBolt";
|
||||
|
||||
[DataField("onOpenPort", customTypeSerializer: typeof(PrototypeIdSerializer<TransmitterPortPrototype>))]
|
||||
public string OutOpen = "DoorStatus";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,37 @@
|
||||
using Content.Server.DeviceLinking.Components;
|
||||
using Content.Server.DeviceLinking.Events;
|
||||
using Content.Server.DeviceNetwork;
|
||||
using Content.Server.Doors.Systems;
|
||||
using Content.Server.MachineLinking.Events;
|
||||
using Content.Server.MachineLinking.System;
|
||||
using Content.Shared.Doors.Components;
|
||||
using Content.Shared.Doors;
|
||||
using JetBrains.Annotations;
|
||||
using SignalReceivedEvent = Content.Server.DeviceLinking.Events.SignalReceivedEvent;
|
||||
|
||||
namespace Content.Server.DeviceLinking.Systems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed class DoorSignalControlSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly AirlockSystem _airlockSystem = default!;
|
||||
[Dependency] private readonly DoorSystem _doorSystem = default!;
|
||||
[Dependency] private readonly DeviceLinkSystem _signalSystem = default!;
|
||||
|
||||
private const string DoorSignalState = "DoorState";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<DoorSignalControlComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<DoorSignalControlComponent, SignalReceivedEvent>(OnSignalReceived);
|
||||
SubscribeLocalEvent<DoorSignalControlComponent, DoorStateChangedEvent>(OnStateChanged);
|
||||
}
|
||||
|
||||
private void OnInit(EntityUid uid, DoorSignalControlComponent component, ComponentInit args)
|
||||
{
|
||||
|
||||
_signalSystem.EnsureSinkPorts(uid, component.OpenPort, component.ClosePort, component.TogglePort);
|
||||
_signalSystem.EnsureSourcePorts(uid, component.OutOpen);
|
||||
}
|
||||
|
||||
private void OnSignalReceived(EntityUid uid, DoorSignalControlComponent component, ref SignalReceivedEvent args)
|
||||
@@ -30,19 +39,67 @@ namespace Content.Server.DeviceLinking.Systems
|
||||
if (!TryComp(uid, out DoorComponent? door))
|
||||
return;
|
||||
|
||||
var state = SignalState.Momentary;
|
||||
args.Data?.TryGetValue(DoorSignalState, out state);
|
||||
|
||||
|
||||
if (args.Port == component.OpenPort)
|
||||
{
|
||||
if (door.State != DoorState.Open)
|
||||
_doorSystem.TryOpen(uid, door);
|
||||
if (state == SignalState.High || state == SignalState.Momentary)
|
||||
{
|
||||
if (door.State != DoorState.Open)
|
||||
_doorSystem.TryOpen(uid, door);
|
||||
}
|
||||
}
|
||||
else if (args.Port == component.ClosePort)
|
||||
{
|
||||
if (door.State != DoorState.Closed)
|
||||
_doorSystem.TryClose(uid, door);
|
||||
if (state == SignalState.High || state == SignalState.Momentary)
|
||||
{
|
||||
if (door.State != DoorState.Closed)
|
||||
_doorSystem.TryClose(uid, door);
|
||||
}
|
||||
}
|
||||
else if (args.Port == component.TogglePort)
|
||||
{
|
||||
_doorSystem.TryToggleDoor(uid, door);
|
||||
if (state == SignalState.High || state == SignalState.Momentary)
|
||||
{
|
||||
_doorSystem.TryToggleDoor(uid, door);
|
||||
}
|
||||
}
|
||||
else if (args.Port == component.InBolt)
|
||||
{
|
||||
if (state == SignalState.High)
|
||||
{
|
||||
if(TryComp<AirlockComponent>(uid, out var airlockComponent))
|
||||
_airlockSystem.SetBoltsWithAudio(uid, airlockComponent, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(TryComp<AirlockComponent>(uid, out var airlockComponent))
|
||||
_airlockSystem.SetBoltsWithAudio(uid, airlockComponent, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnStateChanged(EntityUid uid, DoorSignalControlComponent door, DoorStateChangedEvent args)
|
||||
{
|
||||
var data = new NetworkPayload()
|
||||
{
|
||||
{ DoorSignalState, SignalState.Momentary }
|
||||
};
|
||||
|
||||
if (args.State == DoorState.Closed)
|
||||
{
|
||||
data[DoorSignalState] = SignalState.Low;
|
||||
_signalSystem.InvokePort(uid, door.OutOpen, data);
|
||||
}
|
||||
else if (args.State == DoorState.Open
|
||||
|| args.State == DoorState.Opening
|
||||
|| args.State == DoorState.Closing
|
||||
|| args.State == DoorState.Emagging)
|
||||
{
|
||||
data[DoorSignalState] = SignalState.High;
|
||||
_signalSystem.InvokePort(uid, door.OutOpen, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Server.Access;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Construction;
|
||||
using Content.Server.MachineLinking.System;
|
||||
using Content.Server.Tools.Systems;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Access.Systems;
|
||||
@@ -30,9 +30,7 @@ public sealed class DoorSystem : SharedDoorSystem
|
||||
[Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!;
|
||||
[Dependency] private readonly AirlockSystem _airlock = default!;
|
||||
[Dependency] private readonly AirtightSystem _airtightSystem = default!;
|
||||
[Dependency] private readonly ConstructionSystem _constructionSystem = default!;
|
||||
[Dependency] private readonly SharedToolSystem _toolSystem = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
|
||||
28
Content.Server/MachineLinking/Components/OrGateComponent.cs
Normal file
28
Content.Server/MachineLinking/Components/OrGateComponent.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using Content.Server.MachineLinking.Events;
|
||||
using Content.Shared.MachineLinking;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server.MachineLinking.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;
|
||||
}
|
||||
@@ -20,5 +20,16 @@ namespace Content.Server.MachineLinking.Components
|
||||
[DataField("requiredQuality", customTypeSerializer: typeof(PrototypeIdSerializer<ToolQualityPrototype>))]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public string? RequiredQuality;
|
||||
|
||||
// Utility functions below to deal with linking entities with both Transmit and Receive components.
|
||||
public bool LinkTX()
|
||||
{
|
||||
return SavedTransmitter == null;
|
||||
}
|
||||
|
||||
public bool LinkRX()
|
||||
{
|
||||
return SavedTransmitter != null && SavedReceiver == null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Server.MachineLinking.Events;
|
||||
using Content.Server.MachineLinking.System;
|
||||
|
||||
namespace Content.Server.MachineLinking.Components
|
||||
@@ -31,6 +32,13 @@ namespace Content.Server.MachineLinking.Components
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float TransmissionRange = 30f;
|
||||
|
||||
/*
|
||||
* Remember last output state to avoid re-raising a SignalChangedEvent if the signal
|
||||
* level hasn't actually changed.
|
||||
*/
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public SignalState LastState = SignalState.Low;
|
||||
|
||||
[DataField("outputs")]
|
||||
[Access(typeof(SignalLinkerSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
|
||||
public Dictionary<string, List<PortIdentifier>> Outputs = new();
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace Content.Server.MachineLinking.Events
|
||||
{
|
||||
public enum SignalState
|
||||
{
|
||||
Momentary, // Instantaneous pulse high, compatibility behavior
|
||||
Low,
|
||||
High
|
||||
}
|
||||
|
||||
public sealed class SignalReceivedEvent : EntityEventArgs
|
||||
{
|
||||
public readonly string Port;
|
||||
public readonly SignalState State;
|
||||
public readonly EntityUid? Trigger;
|
||||
|
||||
public SignalReceivedEvent(string port, EntityUid? trigger, SignalState state)
|
||||
{
|
||||
Port = port;
|
||||
Trigger = trigger;
|
||||
State = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
63
Content.Server/MachineLinking/System/OrGateSystem.cs
Normal file
63
Content.Server/MachineLinking/System/OrGateSystem.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using Content.Server.MachineLinking.Components;
|
||||
using Content.Server.MachineLinking.Events;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.MachineLinking.System
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed class OrGateSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SignalLinkerSystem _signalSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<OrGateComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<OrGateComponent, SignalReceivedEvent>(OnSignalReceived);
|
||||
}
|
||||
|
||||
private void OnInit(EntityUid uid, OrGateComponent component, ComponentInit args)
|
||||
{
|
||||
_signalSystem.EnsureReceiverPorts(uid, "A1", "B1", "A2", "B2");
|
||||
_signalSystem.EnsureTransmitterPorts(uid, "O1", "O2");
|
||||
}
|
||||
|
||||
private void OnSignalReceived(EntityUid uid, OrGateComponent component, SignalReceivedEvent args)
|
||||
{
|
||||
if (args.Port == "A1")
|
||||
{
|
||||
component.StateA1 = args.State;
|
||||
}
|
||||
else if (args.Port == "B1")
|
||||
{
|
||||
component.StateB1 = args.State;
|
||||
}
|
||||
else if (args.Port == "A2")
|
||||
{
|
||||
component.StateA2 = args.State;
|
||||
}
|
||||
else if (args.Port == "B2")
|
||||
{
|
||||
component.StateB2 = args.State;
|
||||
}
|
||||
|
||||
// O1 = A1 || B1
|
||||
var v1 = SignalState.Low;
|
||||
if (component.StateA1 == SignalState.High || component.StateB1 == SignalState.High)
|
||||
v1 = SignalState.High;
|
||||
|
||||
if (v1 != component.LastO1)
|
||||
_signalSystem.InvokePort(uid, "O1", v1);
|
||||
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)
|
||||
_signalSystem.InvokePort(uid, "O2", v2);
|
||||
component.LastO2 = v2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Linq;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Server.DeviceLinking.Events;
|
||||
using Content.Server.MachineLinking.Components;
|
||||
using Content.Server.MachineLinking.Events;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.Tools;
|
||||
using Content.Shared.DeviceLinking.Events;
|
||||
@@ -11,6 +11,7 @@ using Content.Shared.Popups;
|
||||
using Robust.Server.GameObjects;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Prototypes;
|
||||
using SignalReceivedEvent = Content.Server.DeviceLinking.Events.SignalReceivedEvent;
|
||||
|
||||
namespace Content.Server.MachineLinking.System
|
||||
{
|
||||
@@ -49,7 +50,7 @@ namespace Content.Server.MachineLinking.System
|
||||
var comp = EnsureComp<SignalReceiverComponent>(uid);
|
||||
foreach (var port in ports)
|
||||
{
|
||||
comp.Inputs.TryAdd(port, new());
|
||||
comp.Inputs.TryAdd(port, new List<PortIdentifier>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +59,7 @@ namespace Content.Server.MachineLinking.System
|
||||
var comp = EnsureComp<SignalTransmitterComponent>(uid);
|
||||
foreach (var port in ports)
|
||||
{
|
||||
comp.Outputs.TryAdd(port, new());
|
||||
comp.Outputs.TryAdd(port, new List<PortIdentifier>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,9 +73,11 @@ namespace Content.Server.MachineLinking.System
|
||||
|
||||
if (!TryComp(args.Using, out SignalLinkerComponent? linker) ||
|
||||
!IsLinkerInteractable(args.Using.Value, linker))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AlternativeVerb verb = new()
|
||||
var verb = new AlternativeVerb()
|
||||
{
|
||||
Text = Loc.GetString("signal-linking-verb-text-link-default"),
|
||||
IconEntity = args.Using
|
||||
@@ -130,13 +133,25 @@ namespace Content.Server.MachineLinking.System
|
||||
}
|
||||
|
||||
public void InvokePort(EntityUid uid, string port, SignalTransmitterComponent? component = null)
|
||||
{
|
||||
InvokePort(uid, port, SignalState.Momentary, component);
|
||||
}
|
||||
|
||||
public void InvokePort(EntityUid uid, string port, SignalState state, SignalTransmitterComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
|
||||
if (state != SignalState.Momentary && state == component.LastState)
|
||||
{
|
||||
// no change in output signal
|
||||
return;
|
||||
}
|
||||
|
||||
if (!component.Outputs.TryGetValue(port, out var receivers))
|
||||
return;
|
||||
|
||||
component.LastState = state;
|
||||
foreach (var receiver in receivers)
|
||||
{
|
||||
var eventArgs = new SignalReceivedEvent(receiver.Port, uid);
|
||||
@@ -149,6 +164,7 @@ namespace Content.Server.MachineLinking.System
|
||||
// validate links
|
||||
Dictionary<EntityUid, SignalReceiverComponent?> uidCache = new();
|
||||
foreach (var tport in transmitter.Outputs)
|
||||
{
|
||||
foreach (var rport in tport.Value)
|
||||
{
|
||||
if (!uidCache.TryGetValue(rport.Uid, out var receiver))
|
||||
@@ -158,6 +174,7 @@ namespace Content.Server.MachineLinking.System
|
||||
else if (!rpv.Contains(new(uid, tport.Key)))
|
||||
rpv.Add(new(uid, tport.Key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnReceiverStartup(EntityUid uid, SignalReceiverComponent receiver, ComponentStartup args)
|
||||
@@ -208,12 +225,16 @@ namespace Content.Server.MachineLinking.System
|
||||
|
||||
private void OnTransmitterInteractUsing(EntityUid uid, SignalTransmitterComponent transmitter, InteractUsingEvent args)
|
||||
{
|
||||
if (args.Handled) return;
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (!TryComp(args.Used, out SignalLinkerComponent? linker) || !IsLinkerInteractable(args.Used, linker) ||
|
||||
!TryComp(args.User, out ActorComponent? actor))
|
||||
return;
|
||||
|
||||
if (!linker.LinkTX())
|
||||
return;
|
||||
|
||||
linker.SavedTransmitter = uid;
|
||||
|
||||
if (!TryComp(linker.SavedReceiver, out SignalReceiverComponent? receiver))
|
||||
@@ -233,12 +254,16 @@ namespace Content.Server.MachineLinking.System
|
||||
|
||||
private void OnReceiverInteractUsing(EntityUid uid, SignalReceiverComponent receiver, InteractUsingEvent args)
|
||||
{
|
||||
if (args.Handled) return;
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (!TryComp(args.Used, out SignalLinkerComponent? linker) || !IsLinkerInteractable(args.Used, linker) ||
|
||||
!TryComp(args.User, out ActorComponent? actor))
|
||||
return;
|
||||
|
||||
if (!linker.LinkRX())
|
||||
return;
|
||||
|
||||
linker.SavedReceiver = uid;
|
||||
|
||||
if (!TryComp(linker.SavedTransmitter, out SignalTransmitterComponent? transmitter))
|
||||
@@ -274,10 +299,14 @@ namespace Content.Server.MachineLinking.System
|
||||
var outKeys = transmitter.Outputs.Keys.ToList();
|
||||
var inKeys = receiver.Inputs.Keys.ToList();
|
||||
List<(int, int)> links = new();
|
||||
for (int i = 0; i < outKeys.Count; i++)
|
||||
for (var i = 0; i < outKeys.Count; i++)
|
||||
{
|
||||
foreach (var re in transmitter.Outputs[outKeys[i]])
|
||||
{
|
||||
if (re.Uid == receiver.Owner)
|
||||
links.Add((i, inKeys.IndexOf(re.Port)));
|
||||
}
|
||||
}
|
||||
|
||||
bui.SetState(new SignalPortsState($"{Name(transmitter.Owner)} ({transmitter.Owner})", outKeys,
|
||||
$"{Name(receiver.Owner)} ({receiver.Owner})", inKeys, links));
|
||||
@@ -289,7 +318,9 @@ namespace Content.Server.MachineLinking.System
|
||||
{
|
||||
if (!transmitter.Outputs.TryGetValue(args.TransmitterPort, out var linkedReceivers) ||
|
||||
!receiver.Inputs.TryGetValue(args.ReceiverPort, out var linkedTransmitters))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
quiet |= !user.HasValue;
|
||||
|
||||
@@ -328,10 +359,12 @@ namespace Content.Server.MachineLinking.System
|
||||
linkedReceivers.Add(new(receiver.Owner, args.ReceiverPort));
|
||||
linkedTransmitters.Add(new(transmitter.Owner, args.TransmitterPort));
|
||||
if (!quiet)
|
||||
{
|
||||
_popupSystem.PopupCursor(Loc.GetString("signal-linker-component-linked-port",
|
||||
("machine1", transmitter.Owner), ("port1", PortName<TransmitterPortPrototype>(args.TransmitterPort)),
|
||||
("machine2", receiver.Owner), ("port2", PortName<ReceiverPortPrototype>(args.ReceiverPort))),
|
||||
("machine1", transmitter.Owner), ("port1", PortName<TransmitterPortPrototype>(args.TransmitterPort)),
|
||||
("machine2", receiver.Owner), ("port2", PortName<ReceiverPortPrototype>(args.ReceiverPort))),
|
||||
user!.Value, PopupType.Medium);
|
||||
}
|
||||
|
||||
var newLink = new NewLinkEvent(user, transmitter.Owner, args.TransmitterPort, receiver.Owner, args.ReceiverPort);
|
||||
RaiseLocalEvent(receiver.Owner, newLink);
|
||||
@@ -353,12 +386,14 @@ namespace Content.Server.MachineLinking.System
|
||||
|
||||
if (receivers.Contains(new(receiver.Owner, args.ReceiverPort)) ||
|
||||
transmitters.Contains(new(transmitter.Owner, args.TransmitterPort)))
|
||||
{ // link already exists, remove it
|
||||
{
|
||||
// link already exists, remove it
|
||||
if (receivers.Remove(new(receiver.Owner, args.ReceiverPort)) &&
|
||||
transmitters.Remove(new(transmitter.Owner, args.TransmitterPort)))
|
||||
{
|
||||
RaiseLocalEvent(receiver.Owner, new PortDisconnectedEvent(args.ReceiverPort), true);
|
||||
RaiseLocalEvent(transmitter.Owner, new PortDisconnectedEvent(args.TransmitterPort), true);
|
||||
|
||||
_popupSystem.PopupCursor(Loc.GetString("signal-linker-component-unlinked-port",
|
||||
("machine1", transmitter.Owner), ("port1", PortName<TransmitterPortPrototype>(args.TransmitterPort)),
|
||||
("machine2", receiver.Owner), ("port2", PortName<ReceiverPortPrototype>(args.ReceiverPort))),
|
||||
@@ -397,12 +432,16 @@ namespace Content.Server.MachineLinking.System
|
||||
return;
|
||||
|
||||
foreach (var (port, receivers) in transmitter.Outputs)
|
||||
{
|
||||
if (receivers.RemoveAll(id => id.Uid == receiver.Owner) > 0)
|
||||
RaiseLocalEvent(transmitter.Owner, new PortDisconnectedEvent(port), true);
|
||||
}
|
||||
|
||||
foreach (var (port, transmitters) in receiver.Inputs)
|
||||
{
|
||||
if (transmitters.RemoveAll(id => id.Uid == transmitter.Owner) > 0)
|
||||
RaiseLocalEvent(receiver.Owner, new PortDisconnectedEvent(port), true);
|
||||
}
|
||||
|
||||
TryUpdateUI(linker, transmitter, receiver);
|
||||
}
|
||||
@@ -437,12 +476,16 @@ namespace Content.Server.MachineLinking.System
|
||||
|
||||
// First, disconnect existing links.
|
||||
foreach (var (port, receivers) in transmitter.Outputs)
|
||||
{
|
||||
if (receivers.RemoveAll(id => id.Uid == receiver.Owner) > 0)
|
||||
RaiseLocalEvent(transmitter.Owner, new PortDisconnectedEvent(port), true);
|
||||
}
|
||||
|
||||
foreach (var (port, transmitters) in receiver.Inputs)
|
||||
{
|
||||
if (transmitters.RemoveAll(id => id.Uid == transmitter.Owner) > 0)
|
||||
RaiseLocalEvent(receiver.Owner, new PortDisconnectedEvent(port), true);
|
||||
}
|
||||
|
||||
// Then make any valid default connections.
|
||||
foreach (var outPort in transmitter.Outputs.Keys)
|
||||
@@ -474,6 +517,7 @@ namespace Content.Server.MachineLinking.System
|
||||
transmitterPower.Provider?.Net == receiverPower.Provider?.Net)
|
||||
return true;
|
||||
|
||||
// TODO: As elsewhere don't use mappos inrange.
|
||||
return Comp<TransformComponent>(transmitterComponent.Owner).MapPosition.InRange(
|
||||
Comp<TransformComponent>(receiverComponent.Owner).MapPosition, transmitterComponent.TransmissionRange);
|
||||
}
|
||||
|
||||
@@ -442,6 +442,7 @@ public abstract class SharedDeviceLinkSystem : EntitySystem
|
||||
|
||||
private bool InRange(EntityUid sourceUid, EntityUid sinkUid, float range)
|
||||
{
|
||||
// TODO: This should be using an existing method and also coordinates inrange instead.
|
||||
return Transform(sourceUid).MapPosition.InRange(Transform(sinkUid).MapPosition, range);
|
||||
}
|
||||
|
||||
|
||||
@@ -131,6 +131,10 @@ public abstract class SharedDoorSystem : EntitySystem
|
||||
if (!Resolve(uid, ref door))
|
||||
return;
|
||||
|
||||
// If no change, return to avoid firing a new DoorStateChangedEvent.
|
||||
if (state == door.State)
|
||||
return;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case DoorState.Opening:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
signal-port-name-toggle = Autoclose
|
||||
signal-port-description-toggle = Toggles whether the device should automatically close.
|
||||
signal-port-name-autoclose = Autoclose
|
||||
signal-port-description-autoclose = Toggles whether the device should automatically close.
|
||||
|
||||
signal-port-name-toggle = Toggle
|
||||
signal-port-description-toggle = Toggles the state of a device.
|
||||
@@ -22,6 +22,9 @@ signal-port-description-open = Opens a device.
|
||||
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-name-trigger = Trigger
|
||||
signal-port-description-trigger = Triggers some mechanism on the device.
|
||||
|
||||
|
||||
@@ -13,6 +13,9 @@ signal-port-description-left = This port is invoked whenever the lever is moved
|
||||
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-name-middle = Middle
|
||||
signal-port-description-middle = This port is invoked whenever the lever is moved to the neutral position.
|
||||
|
||||
|
||||
@@ -38,6 +38,11 @@
|
||||
name: signal-port-name-close
|
||||
description: signal-port-description-close
|
||||
|
||||
- type: sinkPort
|
||||
id: DoorBolt
|
||||
name: signal-port-name-doorbolt
|
||||
description: signal-port-description-doorbolt
|
||||
|
||||
- type: sinkPort
|
||||
id: Trigger
|
||||
name: signal-port-name-trigger
|
||||
|
||||
@@ -34,6 +34,11 @@
|
||||
description: signal-port-description-middle
|
||||
defaultLinks: [ Off, Close ]
|
||||
|
||||
- type: sourcePort
|
||||
id: DoorStatus
|
||||
name: signal-port-name-doorstatus
|
||||
description: signal-port-description-status
|
||||
|
||||
- type: sourcePort
|
||||
id: OrderSender
|
||||
name: signal-port-name-order-sender
|
||||
|
||||
@@ -89,6 +89,10 @@
|
||||
- Close
|
||||
- Toggle
|
||||
- AutoClose
|
||||
- DoorBolt
|
||||
- type: DeviceLinkSource
|
||||
ports:
|
||||
- DoorStatus
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
- key: enum.WiresUiKey.Key
|
||||
|
||||
26
Resources/Prototypes/Entities/Structures/gates.yml
Normal file
26
Resources/Prototypes/Entities/Structures/gates.yml
Normal file
@@ -0,0 +1,26 @@
|
||||
- type: entity
|
||||
id: OrGate
|
||||
name: MS7432
|
||||
description: Dual 2-Input OR Gate
|
||||
parent: BaseItem
|
||||
placement:
|
||||
mode: SnapgridCenter
|
||||
snap:
|
||||
- Wallmount
|
||||
components:
|
||||
- type: Anchorable
|
||||
- type: Sprite
|
||||
sprite: Objects/Devices/gates.rsi
|
||||
state: or
|
||||
- type: Rotatable
|
||||
- type: OrGate
|
||||
- type: SignalReceiver
|
||||
inputs:
|
||||
A1: []
|
||||
B1: []
|
||||
A2: []
|
||||
B2: []
|
||||
- type: SignalTransmitter
|
||||
outputs:
|
||||
O1: []
|
||||
O2: []
|
||||
@@ -72,3 +72,28 @@
|
||||
id: ArtifactAnalyzerReceiver
|
||||
name: signal-port-name-artifact-analyzer-receiver
|
||||
description: signal-port-description-artifact-analyzer-receiver
|
||||
|
||||
- type: receiverPort
|
||||
id: DoorBolt
|
||||
name: "Bolt"
|
||||
description: "Bolt door when HIGH."
|
||||
|
||||
- type: receiverPort
|
||||
id: A1
|
||||
name: "Input A1"
|
||||
description: "Input A1"
|
||||
|
||||
- type: receiverPort
|
||||
id: B1
|
||||
name: "Input B1"
|
||||
description: "Input B1"
|
||||
|
||||
- type: receiverPort
|
||||
id: A2
|
||||
name: "Input A2"
|
||||
description: "Input A2"
|
||||
|
||||
- type: receiverPort
|
||||
id: B2
|
||||
name: "Input B2"
|
||||
description: "Input B2"
|
||||
|
||||
@@ -67,3 +67,18 @@
|
||||
name: signal-port-name-artifact-analyzer-sender
|
||||
description: signal-port-description-artifact-analyzer-sender
|
||||
defaultLinks: [ ArtifactAnalyzerReceiver ]
|
||||
|
||||
- type: transmitterPort
|
||||
id: DoorStatus
|
||||
name: "Door Status"
|
||||
description: "HIGH when door is open, LOW when door is closed."
|
||||
|
||||
- type: transmitterPort
|
||||
id: O1
|
||||
name: "Output 1"
|
||||
description: "Output 1"
|
||||
|
||||
- type: transmitterPort
|
||||
id: O2
|
||||
name: "Output 2"
|
||||
description: "Output 2"
|
||||
|
||||
14
Resources/Textures/Objects/Devices/gates.rsi/meta.json
Normal file
14
Resources/Textures/Objects/Devices/gates.rsi/meta.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Kevin Zheng 2022",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "or"
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
Resources/Textures/Objects/Devices/gates.rsi/or.png
Normal file
BIN
Resources/Textures/Objects/Devices/gates.rsi/or.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
Reference in New Issue
Block a user