Equipment verbs & admin inventory access. (#14315)

This commit is contained in:
Leon Friedrich
2023-03-06 06:12:08 +13:00
committed by GitHub
parent a9b268af49
commit b148bebd60
29 changed files with 499 additions and 141 deletions

View File

@@ -57,4 +57,19 @@ public sealed class ToggleableClothingComponent : Component
/// </summary>
[DataField("clothingUid")]
public EntityUid? ClothingUid;
/// <summary>
/// Time it takes for this clothing to be toggled via the stripping menu verbs. Null prevents the verb from even showing up.
/// </summary>
[DataField("stripDelay")]
public TimeSpan? StripDelay = TimeSpan.FromSeconds(3);
/// <summary>
/// Text shown in the toggle-clothing verb. Defaults to using the name of the <see cref="ToggleAction"/> action.
/// </summary>
[DataField("verbText")]
public string? VerbText;
// prevent duplicate doafters
public byte? DoAfterId;
}

View File

@@ -1,12 +1,16 @@
using Content.Shared.Actions;
using Content.Shared.Actions.ActionTypes;
using Content.Shared.Clothing.Components;
using Content.Shared.DoAfter;
using Content.Shared.IdentityManagement;
using Content.Shared.Interaction;
using Content.Shared.Inventory;
using Content.Shared.Inventory.Events;
using Content.Shared.Popups;
using Content.Shared.Strip;
using Content.Shared.Verbs;
using Robust.Shared.Containers;
using Robust.Shared.Player;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
@@ -18,7 +22,10 @@ public sealed class ToggleableClothingSystem : EntitySystem
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly SharedStrippableSystem _strippable = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly INetManager _net = default!;
private Queue<EntityUid> _toInsert = new();
@@ -36,6 +43,103 @@ public sealed class ToggleableClothingSystem : EntitySystem
SubscribeLocalEvent<AttachedClothingComponent, InteractHandEvent>(OnInteractHand);
SubscribeLocalEvent<AttachedClothingComponent, GotUnequippedEvent>(OnAttachedUnequip);
SubscribeLocalEvent<AttachedClothingComponent, ComponentRemove>(OnRemoveAttached);
SubscribeLocalEvent<ToggleableClothingComponent, InventoryRelayedEvent<GetVerbsEvent<EquipmentVerb>>>(GetRelayedVerbs);
SubscribeLocalEvent<ToggleableClothingComponent, GetVerbsEvent<EquipmentVerb>>(OnGetVerbs);
SubscribeLocalEvent<AttachedClothingComponent, GetVerbsEvent<EquipmentVerb>>(OnGetAttachedStripVerbsEvent);
SubscribeLocalEvent<ToggleableClothingComponent, DoAfterEvent<ToggleClothingEvent>>(OnDoAfterComplete);
}
private void GetRelayedVerbs(EntityUid uid, ToggleableClothingComponent component, InventoryRelayedEvent<GetVerbsEvent<EquipmentVerb>> args)
{
OnGetVerbs(uid, component, args.Args);
}
private void OnGetVerbs(EntityUid uid, ToggleableClothingComponent component, GetVerbsEvent<EquipmentVerb> args)
{
if (!args.CanAccess || !args.CanInteract || component.ClothingUid == null || component.Container == null)
return;
var text = component.VerbText ?? component.ToggleAction?.DisplayName;
if (text == null)
return;
if (!_inventorySystem.InSlotWithFlags(uid, component.RequiredFlags))
return;
var wearer = Transform(uid).ParentUid;
if (args.User != wearer && component.StripDelay == null)
return;
var verb = new EquipmentVerb()
{
Icon = new SpriteSpecifier.Texture(new ResourcePath("/Textures/Interface/VerbIcons/outfit.svg.192dpi.png")),
Text = Loc.GetString(text),
};
if (args.User == wearer)
{
verb.EventTarget = uid;
verb.ExecutionEventArgs = new ToggleClothingEvent() { Performer = args.User };
}
else
{
verb.Act = () => StartDoAfter(args.User, uid, Transform(uid).ParentUid, component);
}
args.Verbs.Add(verb);
}
private void StartDoAfter(EntityUid user, EntityUid item, EntityUid wearer, ToggleableClothingComponent component)
{
// TODO predict do afters & networked clothing toggle.
if (_net.IsClient)
return;
if (component.DoAfterId != null || component.StripDelay == null)
return;
var (time, stealth) = _strippable.GetStripTimeModifiers(user, wearer, (float) component.StripDelay.Value.TotalSeconds);
if (!stealth)
{
var popup = Loc.GetString("strippable-component-alert-owner-interact", ("user", Identity.Entity(user, EntityManager)), ("item", item));
_popupSystem.PopupEntity(popup, wearer, wearer, PopupType.Large);
}
var args = new DoAfterEventArgs(user, time, default, wearer, item)
{
BreakOnDamage = true,
BreakOnStun = true,
BreakOnTargetMove = true,
RaiseOnTarget = false,
RaiseOnUsed = true,
RaiseOnUser = false,
// This should just re-use the BUI range checks & cancel the do after if the BUI closes. But that is all
// server-side at the moment.
// TODO BUI REFACTOR.
DistanceThreshold = 2,
};
var doAfter = _doAfter.DoAfter(args, new ToggleClothingEvent() { Performer = user });
component.DoAfterId = doAfter.ID;
}
private void OnGetAttachedStripVerbsEvent(EntityUid uid, AttachedClothingComponent component, GetVerbsEvent<EquipmentVerb> args)
{
// redirect to the attached entity.
OnGetVerbs(component.AttachedUid, Comp<ToggleableClothingComponent>(component.AttachedUid), args);
}
private void OnDoAfterComplete(EntityUid uid, ToggleableClothingComponent component, DoAfterEvent<ToggleClothingEvent> args)
{
DebugTools.Assert(component.DoAfterId == args.Id);
component.DoAfterId = null;
if (args.Cancelled)
return;
OnToggleClothing(uid, component, args.AdditionalData);
}
public override void Update(float frameTime)