diff --git a/Content.Server/Administration/Commands/StripAllCommand.cs b/Content.Server/Administration/Commands/StripAllCommand.cs new file mode 100644 index 0000000000..ee3e595595 --- /dev/null +++ b/Content.Server/Administration/Commands/StripAllCommand.cs @@ -0,0 +1,68 @@ +using Content.Shared.Administration; +using Content.Shared.Hands.Components; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Inventory; +using Robust.Shared.Console; + +namespace Content.Server.Administration.Commands; + +[AdminCommand(AdminFlags.Debug)] +public sealed class StripAllCommand : LocalizedEntityCommands +{ + [Dependency] private readonly SharedHandsSystem _handsSystem = default!; + [Dependency] private readonly InventorySystem _inventorySystem = default!; + + public override string Command => "stripall"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) + { + if (args.Length != 1) + { + shell.WriteLine(Loc.GetString("shell-need-exactly-one-argument")); + return; + } + + if (!NetEntity.TryParse(args[0], out var targetUidNet) || !EntityManager.TryGetEntity(targetUidNet, out var targetEntity)) + { + shell.WriteLine(Loc.GetString("shell-entity-uid-must-be-number")); + return; + } + + if (!EntityManager.TryGetComponent(targetEntity, out var inventory)) + { + shell.WriteLine(Loc.GetString("shell-entity-target-lacks-component", ("componentName", nameof(InventoryComponent)))); + return; + } + + var slots = _inventorySystem.GetSlotEnumerator((targetEntity.Value, inventory)); + while (slots.NextItem(out _, out var slot)) + { + _inventorySystem.TryUnequip(targetEntity.Value, targetEntity.Value, slot.Name, true, true, inventory: inventory); + } + + if (EntityManager.TryGetComponent(targetEntity, out var hands)) + { + foreach (var hand in _handsSystem.EnumerateHands(targetEntity.Value, hands)) + { + _handsSystem.TryDrop(targetEntity.Value, + hand, + checkActionBlocker: false, + doDropInteraction: false, + handsComp: hands); + } + } + } + + public override CompletionResult GetCompletion(IConsoleShell shell, string[] args) + { + if (args.Length == 1) + { + return CompletionResult.FromHintOptions( + CompletionHelper.Components(args[0]), + Loc.GetString("cmd-stripall-player-completion")); + } + + return CompletionResult.Empty; + } +} + diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.cs b/Content.Server/Administration/Systems/AdminVerbSystem.cs index b445b499f9..15ec7da467 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.cs @@ -4,9 +4,10 @@ using Content.Server.Administration.UI; using Content.Server.Disposal.Tube; using Content.Server.EUI; using Content.Server.Ghost.Roles; -using Content.Server.Mind; using Content.Server.Mind.Commands; +using Content.Server.Mind; using Content.Server.Prayer; +using Content.Server.Silicons.Laws; using Content.Server.Station.Systems; using Content.Shared.Administration; using Content.Shared.Chemistry.Components.SolutionManager; @@ -15,26 +16,26 @@ using Content.Shared.Configurable; using Content.Shared.Database; using Content.Shared.Examine; using Content.Shared.GameTicking; +using Content.Shared.Hands.Components; using Content.Shared.Inventory; using Content.Shared.Mind.Components; +using Content.Shared.Movement.Components; using Content.Shared.Popups; +using Content.Shared.Silicons.Laws.Components; +using Content.Shared.Silicons.StationAi; using Content.Shared.Verbs; using Robust.Server.Console; using Robust.Server.GameObjects; +using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Map.Components; +using Robust.Shared.Physics.Components; using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Timing; using Robust.Shared.Toolshed; using Robust.Shared.Utility; using System.Linq; -using Content.Server.Silicons.Laws; -using Content.Shared.Movement.Components; -using Content.Shared.Silicons.Laws.Components; -using Robust.Server.Player; -using Content.Shared.Silicons.StationAi; -using Robust.Shared.Physics.Components; using static Content.Shared.Configurable.ConfigurationComponent; namespace Content.Server.Administration.Systems @@ -463,19 +464,34 @@ namespace Content.Server.Administration.Systems args.Verbs.Add(verb); } - // Set clothing verb - if (_groupController.CanCommand(player, "setoutfit") && - EntityManager.HasComponent(args.Target)) + if (TryComp(args.Target, out var inventoryComponent)) { - Verb verb = new() + // Strip all verb + if (_groupController.CanCommand(player, "stripall")) { - Text = Loc.GetString("set-outfit-verb-get-data-text"), - Category = VerbCategory.Debug, - Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/outfit.svg.192dpi.png")), - Act = () => _euiManager.OpenEui(new SetOutfitEui(GetNetEntity(args.Target)), player), - Impact = LogImpact.Medium - }; - args.Verbs.Add(verb); + args.Verbs.Add(new Verb + { + Text = Loc.GetString("strip-all-verb-get-data-text"), + Category = VerbCategory.Debug, + Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/outfit.svg.192dpi.png")), + Act = () => _console.RemoteExecuteCommand(player, $"stripall \"{args.Target}\""), + Impact = LogImpact.Medium + }); + } + + // set outfit verb + if (_groupController.CanCommand(player, "setoutfit")) + { + Verb verb = new() + { + Text = Loc.GetString("set-outfit-verb-get-data-text"), + Category = VerbCategory.Debug, + Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/outfit.svg.192dpi.png")), + Act = () => _euiManager.OpenEui(new SetOutfitEui(GetNetEntity(args.Target)), player), + Impact = LogImpact.Medium + }; + args.Verbs.Add(verb); + } } // In range unoccluded verb diff --git a/Resources/Locale/en-US/objectives/commands/stripall.ftl b/Resources/Locale/en-US/objectives/commands/stripall.ftl new file mode 100644 index 0000000000..bb7512838e --- /dev/null +++ b/Resources/Locale/en-US/objectives/commands/stripall.ftl @@ -0,0 +1,5 @@ +# stripall +cmd-stripall-desc = Strips an entity of all their inventory and hands. +cmd-stripall-help = Usage: stripall + +cmd-stripall-player-completion = diff --git a/Resources/Locale/en-US/shell.ftl b/Resources/Locale/en-US/shell.ftl index 957d3d3c02..3f4aea5ed2 100644 --- a/Resources/Locale/en-US/shell.ftl +++ b/Resources/Locale/en-US/shell.ftl @@ -34,6 +34,7 @@ shell-entity-uid-must-be-number = EntityUid must be a number. shell-could-not-find-entity = Could not find entity {$entity} shell-could-not-find-entity-with-uid = Could not find entity with uid {$uid} shell-entity-with-uid-lacks-component = Entity with uid {$uid} doesn't have {INDEFINITE($componentName)} {$componentName} component +shell-entity-target-lacks-component = Target entity doesn't have {INDEFINITE($componentName)} {$componentName} component shell-invalid-color-hex = Invalid color hex! shell-target-player-does-not-exist = Target player does not exist! shell-target-entity-does-not-have-message = Target entity does not have {INDEFINITE($missing)} {$missing}! diff --git a/Resources/Locale/en-US/strip/strippable-component.ftl b/Resources/Locale/en-US/strip/strippable-component.ftl index 7022319d22..91fd8d1de1 100644 --- a/Resources/Locale/en-US/strip/strippable-component.ftl +++ b/Resources/Locale/en-US/strip/strippable-component.ftl @@ -16,6 +16,7 @@ strippable-component-alert-owner-interact = {CAPITALIZE(THE($user))} is fumbling # StripVerb strip-verb-get-data-text = Strip +strip-all-verb-get-data-text = Strip All ## UI