diff --git a/Content.Client/Silicons/Laws/Ui/SiliconLawMenu.xaml.cs b/Content.Client/Silicons/Laws/Ui/SiliconLawMenu.xaml.cs index 457be358e0..48adce87f8 100644 --- a/Content.Client/Silicons/Laws/Ui/SiliconLawMenu.xaml.cs +++ b/Content.Client/Silicons/Laws/Ui/SiliconLawMenu.xaml.cs @@ -2,15 +2,12 @@ using Content.Client.UserInterface.Controls; using Content.Shared.Silicons.Laws.Components; using Robust.Client.AutoGenerated; using Robust.Client.UserInterface.XAML; -using Robust.Shared.Prototypes; namespace Content.Client.Silicons.Laws.Ui; [GenerateTypedNameReferences] public sealed partial class SiliconLawMenu : FancyWindow { - [Dependency] private readonly IPrototypeManager _prototype = default!; - public SiliconLawMenu() { RobustXamlLoader.Load(this); @@ -20,6 +17,7 @@ public sealed partial class SiliconLawMenu : FancyWindow public void Update(SiliconLawBuiState state) { state.Laws.Sort(); + LawDisplayContainer.Children.Clear(); foreach (var law in state.Laws) { var control = new LawDisplay(law); diff --git a/Content.Server/Silicons/Borgs/BorgSystem.Modules.cs b/Content.Server/Silicons/Borgs/BorgSystem.Modules.cs index ee45757304..3e93933605 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.Modules.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.Modules.cs @@ -42,9 +42,6 @@ public sealed partial class BorgSystem { var chassis = args.Container.Owner; - if (Terminating(chassis)) - return; - if (!TryComp(chassis, out var chassisComp) || args.Container != chassisComp.ModuleContainer) return; @@ -232,7 +229,11 @@ public sealed partial class BorgSystem return false; if (component.ModuleContainer.ContainedEntities.Count >= component.MaxModules) + { + if (user != null) + Popup.PopupEntity(Loc.GetString("borg-module-too-many"), uid, user.Value); return false; + } if (component.ModuleWhitelist?.IsValid(module, EntityManager) == false) { diff --git a/Content.Server/Silicons/Borgs/BorgSystem.Ui.cs b/Content.Server/Silicons/Borgs/BorgSystem.Ui.cs index 4d79338db7..aefe91b07c 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.Ui.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.Ui.cs @@ -69,8 +69,14 @@ public sealed partial class BorgSystem if (TryComp(uid, out var identifier)) name = $"{name} {identifier.FullIdentifier}"; - _metaData.SetEntityName(uid, name); + var metaData = MetaData(uid); + + // don't change the name if the value doesn't actually change + if (metaData.EntityName.Equals(name, StringComparison.InvariantCulture)) + return; + _adminLog.Add(LogType.Action, LogImpact.High, $"{ToPrettyString(attachedEntity):player} set borg \"{ToPrettyString(uid)}\"'s name to: {name}"); + _metaData.SetEntityName(uid, name, metaData); } private void OnRemoveModuleBuiMessage(EntityUid uid, BorgChassisComponent component, BorgRemoveModuleBuiMessage args) diff --git a/Content.Server/Silicons/Laws/SiliconLawSystem.cs b/Content.Server/Silicons/Laws/SiliconLawSystem.cs index 7fbddb83a3..2862e5c1f5 100644 --- a/Content.Server/Silicons/Laws/SiliconLawSystem.cs +++ b/Content.Server/Silicons/Laws/SiliconLawSystem.cs @@ -1,8 +1,11 @@ -using Content.Server.Chat.Managers; +using Content.Server.Administration; +using Content.Server.Chat.Managers; +using Content.Server.GameTicking; using Content.Server.Mind.Components; using Content.Server.Station.Systems; using Content.Shared.Actions; using Content.Shared.Actions.ActionTypes; +using Content.Shared.Administration; using Content.Shared.Chat; using Content.Shared.Emag.Components; using Content.Shared.Emag.Systems; @@ -12,6 +15,7 @@ using Content.Shared.Silicons.Laws.Components; using Robust.Server.GameObjects; using Robust.Server.Player; using Robust.Shared.Prototypes; +using Robust.Shared.Toolshed; namespace Content.Server.Silicons.Laws; @@ -34,12 +38,12 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem SubscribeLocalEvent(OnMindAdded); SubscribeLocalEvent(OnToggleLawsScreen); SubscribeLocalEvent(OnBoundUIOpened); + SubscribeLocalEvent(OnPlayerSpawnComplete); SubscribeLocalEvent(OnDirectedGetLaws); SubscribeLocalEvent(OnDirectedEmagGetLaws); SubscribeLocalEvent(OnExamined); } - private void OnComponentStartup(EntityUid uid, SiliconLawBoundComponent component, ComponentStartup args) { component.ProvidedAction = new (_prototype.Index(component.ViewLawsAction)); @@ -78,6 +82,11 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem _userInterface.TrySetUiState(args.Entity, SiliconLawsUiKey.Key, state, (IPlayerSession) args.Session); } + private void OnPlayerSpawnComplete(EntityUid uid, SiliconLawBoundComponent component, PlayerSpawnCompleteEvent args) + { + component.LastLawProvider = args.Station; + } + private void OnDirectedGetLaws(EntityUid uid, SiliconLawProviderComponent component, ref GetSiliconLawsEvent args) { if (args.Handled || HasComp(uid) || component.Laws.Count == 0) @@ -117,28 +126,55 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem NotifyLawsChanged(uid); } - public List GetLaws(EntityUid uid) + public List GetLaws(EntityUid uid, SiliconLawBoundComponent? component = null) { + if (!Resolve(uid, ref component)) + return new List(); + var xform = Transform(uid); var ev = new GetSiliconLawsEvent(uid); RaiseLocalEvent(uid, ref ev); if (ev.Handled) + { + component.LastLawProvider = uid; return ev.Laws; + } if (_station.GetOwningStation(uid, xform) is { } station) { RaiseLocalEvent(station, ref ev); if (ev.Handled) + { + component.LastLawProvider = station; return ev.Laws; + } } if (xform.GridUid is { } grid) { RaiseLocalEvent(grid, ref ev); if (ev.Handled) + { + component.LastLawProvider = grid; return ev.Laws; + } + } + + if (component.LastLawProvider == null || + Deleted(component.LastLawProvider) || + Terminating(component.LastLawProvider.Value)) + { + component.LastLawProvider = null; + } + else + { + RaiseLocalEvent(component.LastLawProvider.Value, ref ev); + if (ev.Handled) + { + return ev.Laws; + } } RaiseLocalEvent(ref ev); @@ -155,3 +191,30 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem _chatManager.ChatMessageToOne(ChatChannel.Server, msg, wrappedMessage, default, false, actor.PlayerSession.ConnectedClient, colorOverride: Color.FromHex("#2ed2fd")); } } + +[ToolshedCommand, AdminCommand(AdminFlags.Admin)] +public sealed class LawsCommand : ToolshedCommand +{ + private SiliconLawSystem? _law; + + [CommandImplementation("list")] + public IEnumerable List() + { + var query = EntityManager.EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out _)) + { + yield return uid; + } + } + + [CommandImplementation("get")] + public IEnumerable Get([PipedArgument] EntityUid lawbound) + { + _law ??= GetSys(); + + foreach (var law in _law.GetLaws(lawbound)) + { + yield return $"law {law.LawIdentifierOverride ?? law.Order.ToString()}: {Loc.GetString(law.LawString)}"; + } + } +} diff --git a/Content.Server/Wires/WiresSystem.cs b/Content.Server/Wires/WiresSystem.cs index 5931c7dc13..f3f2ef4c6c 100644 --- a/Content.Server/Wires/WiresSystem.cs +++ b/Content.Server/Wires/WiresSystem.cs @@ -57,6 +57,7 @@ public sealed class WiresSystem : SharedWiresSystem SubscribeLocalEvent(OnWiresPowered); SubscribeLocalEvent(OnDoAfter); SubscribeLocalEvent(OnAttemptOpenActivatableUI); + SubscribeLocalEvent(OnActivatableUIPanelChanged); } private void SetOrCreateWireLayout(EntityUid uid, WiresComponent? wires = null) @@ -505,6 +506,17 @@ public sealed class WiresSystem : SharedWiresSystem args.Cancel(); } + private void OnActivatableUIPanelChanged(EntityUid uid, ActivatableUIRequiresPanelComponent component, ref PanelChangedEvent args) + { + if (args.Open == component.RequireOpen) + return; + + if (!TryComp(uid, out var ui) || ui.Key == null) + return; + + _uiSystem.TryCloseAll(uid, ui.Key); + } + private void OnMapInit(EntityUid uid, WiresComponent component, MapInitEvent args) { if (!string.IsNullOrEmpty(component.LayoutId)) @@ -641,6 +653,9 @@ public sealed class WiresSystem : SharedWiresSystem component.Open = open; UpdateAppearance(uid, component); Dirty(component); + + var ev = new PanelChangedEvent(component.Open); + RaiseLocalEvent(uid, ref ev); } public void SetWiresPanelSecurityData(EntityUid uid, WiresPanelComponent component, string wiresPanelSecurityLevelID) diff --git a/Content.Shared/Silicons/Laws/Components/SiliconLawBoundComponent.cs b/Content.Shared/Silicons/Laws/Components/SiliconLawBoundComponent.cs index 25c4772e52..3d8b5dbbad 100644 --- a/Content.Shared/Silicons/Laws/Components/SiliconLawBoundComponent.cs +++ b/Content.Shared/Silicons/Laws/Components/SiliconLawBoundComponent.cs @@ -22,6 +22,12 @@ public sealed class SiliconLawBoundComponent : Component /// [DataField("providedAction")] public InstantAction? ProvidedAction; + + /// + /// The last entity that provided laws to this entity. + /// + [DataField("lastLawProvider")] + public EntityUid? LastLawProvider; } [ByRefEvent] diff --git a/Content.Shared/Wires/WiresPanelComponent.cs b/Content.Shared/Wires/WiresPanelComponent.cs index 683bd3f830..db7d018625 100644 --- a/Content.Shared/Wires/WiresPanelComponent.cs +++ b/Content.Shared/Wires/WiresPanelComponent.cs @@ -34,3 +34,9 @@ public sealed partial class WiresPanelComponent : Component [AutoNetworkedField] public bool WiresAccessible = true; } + +/// +/// Event raised when a panel is opened or closed. +/// +[ByRefEvent] +public readonly record struct PanelChangedEvent(bool Open); diff --git a/Resources/Locale/en-US/borg/borg.ftl b/Resources/Locale/en-US/borg/borg.ftl index 805ee28620..2f51331a83 100644 --- a/Resources/Locale/en-US/borg/borg.ftl +++ b/Resources/Locale/en-US/borg/borg.ftl @@ -6,6 +6,7 @@ borg-panel-not-open = The cyborg's panel isn't open... borg-mind-added = {CAPITALIZE($name)} powered on! borg-mind-removed = {CAPITALIZE($name)} shut off! +borg-module-too-many = There's not enough room for another module... borg-module-whitelist-deny = This module doesn't fit in this type of cyborg... borg-construction-guide-string = The cyborg limbs and torso must be attached to the endoskeleton. diff --git a/Resources/Locale/en-US/commands/toolshed-commands.ftl b/Resources/Locale/en-US/commands/toolshed-commands.ftl index 3dcf56841c..bf0b93c3c5 100644 --- a/Resources/Locale/en-US/commands/toolshed-commands.ftl +++ b/Resources/Locale/en-US/commands/toolshed-commands.ftl @@ -18,6 +18,10 @@ command-description-jobs-set = Sets the number of slots for the given job. command-description-jobs-amount = Returns the number of slots for the given job. +command-description-laws-list = + Returns a list of all law bound entities. +command-description-laws-get = + Returns all of the laws for a given entity. command-description-stations-list = Returns a list of all stations. command-description-stations-get =