diff --git a/Content.Server/MachineLinking/Components/SignalLinkerComponent.cs b/Content.Server/MachineLinking/Components/SignalLinkerComponent.cs index 110f9981f5..6af33f2259 100644 --- a/Content.Server/MachineLinking/Components/SignalLinkerComponent.cs +++ b/Content.Server/MachineLinking/Components/SignalLinkerComponent.cs @@ -1,15 +1,12 @@ -using Robust.Shared.GameObjects; -using Robust.Shared.ViewVariables; - namespace Content.Server.MachineLinking.Components { [RegisterComponent] public sealed class SignalLinkerComponent : Component { [ViewVariables] - public EntityUid? savedTransmitter; + public EntityUid? SavedTransmitter; [ViewVariables] - public EntityUid? savedReceiver; + public EntityUid? SavedReceiver; } } diff --git a/Content.Server/MachineLinking/System/SignalLinkerSystem.cs b/Content.Server/MachineLinking/System/SignalLinkerSystem.cs index 9061377d81..1ab2fd68c3 100644 --- a/Content.Server/MachineLinking/System/SignalLinkerSystem.cs +++ b/Content.Server/MachineLinking/System/SignalLinkerSystem.cs @@ -9,6 +9,7 @@ using Content.Shared.Popups; using Robust.Server.GameObjects; using Robust.Shared.Utility; using Robust.Shared.Player; +using Content.Shared.Verbs; namespace Content.Server.MachineLinking.System { @@ -37,10 +38,12 @@ namespace Content.Server.MachineLinking.System SubscribeLocalEvent(OnTransmitterStartup); SubscribeLocalEvent(OnTransmitterRemoved); SubscribeLocalEvent(OnTransmitterInteractUsing); + SubscribeLocalEvent>(OnGetTransmitterVerbs); SubscribeLocalEvent(OnReceiverStartup); SubscribeLocalEvent(OnReceiverRemoved); SubscribeLocalEvent(OnReceiverInteractUsing); + SubscribeLocalEvent>(OnGetReceiverVerbs); SubscribeLocalEvent(OnSignalPortSelected); SubscribeLocalEvent(OnLinkerClearSelected); @@ -48,6 +51,71 @@ namespace Content.Server.MachineLinking.System SubscribeLocalEvent(OnLinkerUIClosed); } + /// + /// Add an alt-click verb to allow users to link the default ports, without needing to open the UI. + /// + private void OnGetReceiverVerbs(EntityUid uid, SignalReceiverComponent component, GetVerbsEvent args) + { + if (!args.CanAccess || !args.CanInteract) + return; + + if (!TryComp(args.Using, out SignalLinkerComponent? linker)) + return; + + AlternativeVerb verb = new() + { + Text = Loc.GetString("signal-linking-verb-text-link-default"), + IconEntity = args.Using + }; + args.Verbs.Add(verb); + + if (linker.SavedTransmitter != null) + { + verb.Act = () => + { + var msg = TryLinkDefaults(uid, linker.SavedTransmitter.Value, component) + ? Loc.GetString("signal-linking-verb-success", ("machine", linker.SavedTransmitter.Value)) + : Loc.GetString("signal-linking-verb-fail", ("machine", linker.SavedTransmitter.Value)); + _popupSystem.PopupEntity(msg, uid, Filter.Entities(args.User)); + }; + return; + } + + verb.Disabled = true; + verb.Message = Loc.GetString("signal-linking-verb-disabled-no-transmitter"); + } + + private void OnGetTransmitterVerbs(EntityUid uid, SignalTransmitterComponent component, GetVerbsEvent args) + { + if (!args.CanAccess || !args.CanInteract) + return; + + if (!TryComp(args.Using, out SignalLinkerComponent? linker)) + return; + + AlternativeVerb verb = new() + { + Text = Loc.GetString("signal-linking-verb-text-link-default"), + IconEntity = args.Using + }; + args.Verbs.Add(verb); + + if (linker.SavedReceiver != null) + { + verb.Act = () => + { + var msg = TryLinkDefaults(linker.SavedReceiver.Value, uid, null, component) + ? Loc.GetString("signal-linking-verb-success", ("machine", linker.SavedReceiver.Value)) + : Loc.GetString("signal-linking-verb-fail", ("machine", linker.SavedReceiver.Value)); + _popupSystem.PopupEntity(msg, uid, Filter.Entities(args.User)); + }; + return; + } + + verb.Disabled = true; + verb.Message = Loc.GetString("signal-linking-verb-disabled-no-receiver"); + } + private void OnTransmitterInvokePort(EntityUid uid, SignalTransmitterComponent component, InvokePortEvent args) { foreach (var receiver in component.Outputs[args.Port]) @@ -120,9 +188,9 @@ namespace Content.Server.MachineLinking.System !TryComp(args.User, out ActorComponent? actor)) return; - linker.savedTransmitter = uid; + linker.SavedTransmitter = uid; - if (!TryComp(linker.savedReceiver, out SignalReceiverComponent? receiver)) + if (!TryComp(linker.SavedReceiver, out SignalReceiverComponent? receiver)) { _popupSystem.PopupCursor(Loc.GetString("signal-linker-component-saved", ("machine", uid)), Filter.Entities(args.User)); @@ -146,9 +214,9 @@ namespace Content.Server.MachineLinking.System !TryComp(args.User, out ActorComponent? actor)) return; - linker.savedReceiver = uid; + linker.SavedReceiver = uid; - if (!TryComp(linker.savedTransmitter, out SignalTransmitterComponent? transmitter)) + if (!TryComp(linker.SavedTransmitter, out SignalTransmitterComponent? transmitter)) { _popupSystem.PopupCursor(Loc.GetString("signal-linker-component-saved", ("machine", uid)), Filter.Entities(args.User)); @@ -193,13 +261,13 @@ namespace Content.Server.MachineLinking.System } - private bool TryLink(SignalTransmitterComponent transmitter, SignalReceiverComponent receiver, SignalPortSelected args, EntityUid? popupUid = null) + private bool TryLink(SignalTransmitterComponent transmitter, SignalReceiverComponent receiver, SignalPortSelected args, EntityUid? popupUid = null, bool checkRange = true) { if (!transmitter.Outputs.TryGetValue(args.TransmitterPort, out var receivers) || !receiver.Inputs.TryGetValue(args.ReceiverPort, out var transmitters)) return false; - if (!IsInRange(transmitter, receiver)) + if (checkRange && !IsInRange(transmitter, receiver)) { if (popupUid.HasValue) _popupSystem.PopupCursor(Loc.GetString("signal-linker-component-out-of-range"), @@ -239,8 +307,8 @@ namespace Content.Server.MachineLinking.System private void OnSignalPortSelected(EntityUid uid, SignalLinkerComponent linker, SignalPortSelected args) { - if (!TryComp(linker.savedTransmitter, out SignalTransmitterComponent? transmitter) || - !TryComp(linker.savedReceiver, out SignalReceiverComponent? receiver) || + if (!TryComp(linker.SavedTransmitter, out SignalTransmitterComponent? transmitter) || + !TryComp(linker.SavedReceiver, out SignalReceiverComponent? receiver) || !transmitter.Outputs.TryGetValue(args.TransmitterPort, out var receivers) || !receiver.Inputs.TryGetValue(args.ReceiverPort, out var transmitters)) return; @@ -277,8 +345,8 @@ namespace Content.Server.MachineLinking.System private void OnLinkerClearSelected(EntityUid uid, SignalLinkerComponent linker, LinkerClearSelected args) { - if (!TryComp(linker.savedTransmitter, out SignalTransmitterComponent? transmitter) || - !TryComp(linker.savedReceiver, out SignalReceiverComponent? receiver)) + if (!TryComp(linker.SavedTransmitter, out SignalTransmitterComponent? transmitter) || + !TryComp(linker.SavedReceiver, out SignalReceiverComponent? receiver)) return; foreach (var (port, receivers) in transmitter.Outputs) @@ -294,12 +362,28 @@ namespace Content.Server.MachineLinking.System private void OnLinkerLinkDefaultSelected(EntityUid uid, SignalLinkerComponent linker, LinkerLinkDefaultSelected args) { - if (!TryComp(linker.savedTransmitter, out SignalTransmitterComponent? transmitter) || - !TryComp(linker.savedReceiver, out SignalReceiverComponent? receiver) || - args.Session.AttachedEntity is not EntityUid attached || attached == default || - !TryComp(attached, out ActorComponent? actor)) + if (!TryComp(linker.SavedTransmitter, out SignalTransmitterComponent? transmitter) || + !TryComp(linker.SavedReceiver, out SignalReceiverComponent? receiver)) return; + TryLinkDefaults(linker.SavedReceiver!.Value, linker.SavedTransmitter!.Value, receiver, transmitter); + TryUpdateUI(linker, transmitter, receiver); + } + + /// + /// Attempt to link all default ports connections. Returns true if all links succeeded. Otherwise returns + /// false. + /// + public bool TryLinkDefaults(EntityUid receiverUid, EntityUid transmitterUid, SignalReceiverComponent? receiver = null, SignalTransmitterComponent? transmitter = null) + { + if (!Resolve(receiverUid, ref receiver, false) || !Resolve(transmitterUid, ref transmitter, false)) + return false; + + if (!IsInRange(transmitter, receiver)) + return false; + + var allLinksSucceeded = true; + if (_defaultMappings.TryFirstOrDefault(map => !map.ExceptBy(transmitter.Outputs.Keys, item => item.Item1).Any() && !map.ExceptBy(receiver.Inputs.Keys, item => item.Item2).Any(), out var mapping)) { @@ -312,16 +396,16 @@ namespace Content.Server.MachineLinking.System RaiseLocalEvent(receiver.Owner, new PortDisconnectedEvent(port)); foreach (var (t, r) in mapping) - TryLink(transmitter, receiver, new(t, r)); + allLinksSucceeded &= TryLink(transmitter, receiver, new(t, r), checkRange: false); } - TryUpdateUI(linker, transmitter, receiver); + return allLinksSucceeded; } private void OnLinkerUIClosed(EntityUid uid, SignalLinkerComponent component, BoundUIClosedEvent args) { - component.savedTransmitter = null; - component.savedReceiver = null; + component.SavedTransmitter = null; + component.SavedReceiver = null; } private bool IsInRange(SignalTransmitterComponent transmitterComponent, SignalReceiverComponent receiverComponent) diff --git a/Resources/Locale/en-US/machine-linking/components/signal-linker-component.ftl b/Resources/Locale/en-US/machine-linking/components/signal-linker-component.ftl index 5a1a642af5..00eb817794 100644 --- a/Resources/Locale/en-US/machine-linking/components/signal-linker-component.ftl +++ b/Resources/Locale/en-US/machine-linking/components/signal-linker-component.ftl @@ -8,3 +8,10 @@ signal-linker-component-max-connections-transmitter = Maximum connections reache signal-linker-component-type-mismatch = The port's type does not match the type of the saved port! signal-linker-component-out-of-range = Connection is out of range! + +# Verbs +signal-linking-verb-text-link-default = Link default ports +signal-linking-verb-success = Connected all default {$machine} links. +signal-linking-verb-fail = Failed to connect all default {$machine} links. +signal-linking-verb-disabled-no-transmitter = You first need to interact with a transmitter. +signal-linking-verb-disabled-no-receiver = You first need to interact with a receiver. \ No newline at end of file