Add utility verbs (#6473)

This commit is contained in:
Leon Friedrich
2022-02-24 23:48:53 +13:00
committed by GitHub
parent 8ae2ba9fa5
commit 53c9ecbf6a
7 changed files with 156 additions and 10 deletions

View File

@@ -41,6 +41,18 @@ namespace Content.Client.Verbs.UI
ExpansionIndicator.Visible = true; ExpansionIndicator.Visible = true;
} }
if (verb.Icon == null && verb.IconEntity != null)
{
var spriteView = new SpriteView()
{
OverrideDirection = Direction.South,
Sprite = IoCManager.Resolve<IEntityManager>().GetComponentOrNull<ISpriteComponent>(verb.IconEntity.Value)
};
Icon.AddChild(spriteView);
return;
}
Icon.AddChild(new TextureRect() Icon.AddChild(new TextureRect()
{ {
Texture = verb.Icon?.Frame0(), Texture = verb.Icon?.Frame0(),

View File

@@ -107,7 +107,7 @@ namespace Content.Client.Verbs.UI
if (verb.Category?.Text == category.Text) if (verb.Category?.Text == category.Text)
{ {
verbsInCategory.Add(verb); verbsInCategory.Add(verb);
drawIcons = drawIcons || verb.Icon != null; drawIcons = drawIcons || verb.Icon != null || verb.IconEntity != null;
} }
} }

View File

@@ -1,4 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Content.Server.Disposal.Unit.Components;
using Content.Server.Disposal.Unit.EntitySystems;
using Content.Server.Hands.Components; using Content.Server.Hands.Components;
using Content.Server.Storage.Components; using Content.Server.Storage.Components;
using Content.Shared.Interaction; using Content.Shared.Interaction;
@@ -8,9 +11,6 @@ using JetBrains.Annotations;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Server.Player; using Robust.Server.Player;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Timing; using Robust.Shared.Timing;
@@ -21,6 +21,7 @@ namespace Content.Server.Storage.EntitySystems
{ {
[Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly DisposalUnitSystem _disposalSystem = default!;
private readonly List<IPlayerSession> _sessionCache = new(); private readonly List<IPlayerSession> _sessionCache = new();
@@ -33,9 +34,11 @@ namespace Content.Server.Storage.EntitySystems
SubscribeLocalEvent<EntInsertedIntoContainerMessage>(HandleEntityInsertedIntoContainer); SubscribeLocalEvent<EntInsertedIntoContainerMessage>(HandleEntityInsertedIntoContainer);
SubscribeLocalEvent<EntityStorageComponent, GetVerbsEvent<InteractionVerb>>(AddToggleOpenVerb); SubscribeLocalEvent<EntityStorageComponent, GetVerbsEvent<InteractionVerb>>(AddToggleOpenVerb);
SubscribeLocalEvent<ServerStorageComponent, GetVerbsEvent<ActivationVerb>>(AddOpenUiVerb);
SubscribeLocalEvent<EntityStorageComponent, RelayMovementEntityEvent>(OnRelayMovement); SubscribeLocalEvent<EntityStorageComponent, RelayMovementEntityEvent>(OnRelayMovement);
SubscribeLocalEvent<ServerStorageComponent, GetVerbsEvent<ActivationVerb>>(AddOpenUiVerb);
SubscribeLocalEvent<ServerStorageComponent, GetVerbsEvent<UtilityVerb>>(AddTransferVerbs);
SubscribeLocalEvent<StorageFillComponent, MapInitEvent>(OnStorageFillMapInit); SubscribeLocalEvent<StorageFillComponent, MapInitEvent>(OnStorageFillMapInit);
} }
@@ -117,6 +120,97 @@ namespace Content.Server.Storage.EntitySystems
args.Verbs.Add(verb); args.Verbs.Add(verb);
} }
private void AddTransferVerbs(EntityUid uid, ServerStorageComponent component, GetVerbsEvent<UtilityVerb> args)
{
if (!args.CanAccess || !args.CanInteract)
return;
var entities = component.Storage?.ContainedEntities;
if (entities == null || entities.Count == 0)
return;
if (TryComp(uid, out LockComponent? lockComponent) && lockComponent.Locked)
return;
// if the target is storage, add a verb to transfer storage.
if (TryComp(args.Target, out ServerStorageComponent? targetStorage)
&& (!TryComp(uid, out LockComponent? targetLock) || !targetLock.Locked))
{
UtilityVerb verb = new()
{
Text = Loc.GetString("storage-component-transfer-verb"),
IconEntity = args.Using,
Act = () => TransferEntities(uid, args.Target, component, lockComponent, targetStorage, targetLock)
};
args.Verbs.Add(verb);
}
// if the target is a disposal unit, add a verb to transfer storage into the unit (e.g., empty a trash bag).
if (!TryComp(args.Target, out DisposalUnitComponent? disposal))
return;
UtilityVerb dispose = new()
{
Text = Loc.GetString("storage-component-dispose-verb"),
IconEntity = args.Using,
Act = () => DisposeEntities(args.User, uid, args.Target, component, lockComponent, disposal)
};
args.Verbs.Add(dispose);
}
/// <summary>
/// Move entities from one storage to another.
/// </summary>
public void TransferEntities(EntityUid source, EntityUid target,
ServerStorageComponent? sourceComp = null, LockComponent? sourceLock = null,
ServerStorageComponent? targetComp = null, LockComponent? targetLock = null)
{
if (!Resolve(source, ref sourceComp) || !Resolve(target, ref targetComp))
return;
var entities = sourceComp.Storage?.ContainedEntities;
if (entities == null || entities.Count == 0)
return;
if (Resolve(source, ref sourceLock, false) && sourceLock.Locked
|| Resolve(target, ref targetLock, false) && targetLock.Locked)
return;
foreach (var entity in entities.ToList())
{
targetComp.Insert(entity);
}
}
/// <summary>
/// Move entities from storage into a disposal unit.
/// </summary>
public void DisposeEntities(EntityUid user, EntityUid source, EntityUid target,
ServerStorageComponent? sourceComp = null, LockComponent? sourceLock = null,
DisposalUnitComponent? disposalComp = null)
{
if (!Resolve(source, ref sourceComp) || !Resolve(target, ref disposalComp))
return;
var entities = sourceComp.Storage?.ContainedEntities;
if (entities == null || entities.Count == 0)
return;
if (Resolve(source, ref sourceLock, false) && sourceLock.Locked)
return;
foreach (var entity in entities.ToList())
{
if (_disposalSystem.CanInsert(disposalComp, entity)
&& disposalComp.Container.Insert(entity))
{
_disposalSystem.AfterInsert(disposalComp, entity);
}
}
}
private void HandleEntityRemovedFromContainer(EntRemovedFromContainerMessage message) private void HandleEntityRemovedFromContainer(EntRemovedFromContainerMessage message)
{ {
var oldParentEntity = message.Container.Owner; var oldParentEntity = message.Container.Owner;

View File

@@ -404,6 +404,7 @@ namespace Content.Shared.Containers.ItemSlots
: EntityManager.GetComponent<MetaDataComponent>(slot.Item!.Value).EntityName ?? string.Empty; : EntityManager.GetComponent<MetaDataComponent>(slot.Item!.Value).EntityName ?? string.Empty;
AlternativeVerb verb = new(); AlternativeVerb verb = new();
verb.IconEntity = slot.Item;
verb.Act = () => TryEjectToHands(uid, slot, args.User, excludeUserAudio: true); verb.Act = () => TryEjectToHands(uid, slot, args.User, excludeUserAudio: true);
if (slot.EjectVerbText == null) if (slot.EjectVerbText == null)
@@ -414,7 +415,6 @@ namespace Content.Shared.Containers.ItemSlots
else else
{ {
verb.Text = Loc.GetString(slot.EjectVerbText); verb.Text = Loc.GetString(slot.EjectVerbText);
verb.IconTexture = "/Textures/Interface/VerbIcons/eject.svg.192dpi.png";
} }
args.Verbs.Add(verb); args.Verbs.Add(verb);
@@ -439,8 +439,8 @@ namespace Content.Shared.Containers.ItemSlots
: EntityManager.GetComponent<MetaDataComponent>(slot.Item!.Value).EntityName ?? string.Empty; : EntityManager.GetComponent<MetaDataComponent>(slot.Item!.Value).EntityName ?? string.Empty;
InteractionVerb takeVerb = new(); InteractionVerb takeVerb = new();
takeVerb.IconEntity = slot.Item;
takeVerb.Act = () => TryEjectToHands(uid, slot, args.User, excludeUserAudio: true); takeVerb.Act = () => TryEjectToHands(uid, slot, args.User, excludeUserAudio: true);
takeVerb.IconTexture = "/Textures/Interface/VerbIcons/pickup.svg.192dpi.png";
if (slot.EjectVerbText == null) if (slot.EjectVerbText == null)
takeVerb.Text = Loc.GetString("take-item-verb-text", ("subject", verbSubject)); takeVerb.Text = Loc.GetString("take-item-verb-text", ("subject", verbSubject));
@@ -465,6 +465,7 @@ namespace Content.Shared.Containers.ItemSlots
: Name(args.Using.Value) ?? string.Empty; : Name(args.Using.Value) ?? string.Empty;
InteractionVerb insertVerb = new(); InteractionVerb insertVerb = new();
insertVerb.IconEntity = args.Using;
insertVerb.Act = () => Insert(uid, slot, args.Using.Value, args.User, excludeUserAudio: true); insertVerb.Act = () => Insert(uid, slot, args.Using.Value, args.User, excludeUserAudio: true);
if (slot.InsertVerbText != null) if (slot.InsertVerbText != null)

View File

@@ -47,16 +47,16 @@ namespace Content.Shared.Verbs
/// Raises a number of events in order to get all verbs of the given type(s) defined in local systems. This /// Raises a number of events in order to get all verbs of the given type(s) defined in local systems. This
/// does not request verbs from the server. /// does not request verbs from the server.
/// </summary> /// </summary>
public SortedSet<Verb> GetLocalVerbs(EntityUid target, EntityUid user, Type type, bool force = false, bool all = false) public SortedSet<Verb> GetLocalVerbs(EntityUid target, EntityUid user, Type type, bool force = false)
{ {
return GetLocalVerbs(target, user, new List<Type>() { type }, force, all); return GetLocalVerbs(target, user, new List<Type>() { type }, force);
} }
/// <summary> /// <summary>
/// Raises a number of events in order to get all verbs of the given type(s) defined in local systems. This /// Raises a number of events in order to get all verbs of the given type(s) defined in local systems. This
/// does not request verbs from the server. /// does not request verbs from the server.
/// </summary> /// </summary>
public SortedSet<Verb> GetLocalVerbs(EntityUid target, EntityUid user, List<Type> types, bool force = false, bool all = false) public SortedSet<Verb> GetLocalVerbs(EntityUid target, EntityUid user, List<Type> types, bool force = false)
{ {
SortedSet<Verb> verbs = new(); SortedSet<Verb> verbs = new();
@@ -99,6 +99,15 @@ namespace Content.Shared.Verbs
verbs.UnionWith(verbEvent.Verbs); verbs.UnionWith(verbEvent.Verbs);
} }
if (types.Contains(typeof(UtilityVerb))
&& @using != null
&& @using != target)
{
var verbEvent = new GetVerbsEvent<UtilityVerb>(user, target, @using, hands, canInteract, canAccess);
RaiseLocalEvent(@using.Value, verbEvent); // directed at used, not at target
verbs.UnionWith(verbEvent.Verbs);
}
if (types.Contains(typeof(AlternativeVerb))) if (types.Contains(typeof(AlternativeVerb)))
{ {
var verbEvent = new GetVerbsEvent<AlternativeVerb>(user, target, @using, hands, canInteract, canAccess); var verbEvent = new GetVerbsEvent<AlternativeVerb>(user, target, @using, hands, canInteract, canAccess);

View File

@@ -121,6 +121,12 @@ namespace Content.Shared.Verbs
/// </summary> /// </summary>
public string? IconTexture; public string? IconTexture;
/// <summary>
/// If this is not null, and no icon or icon texture were specified, a sprite view of this entity will be
/// used as the icon for this verb.
/// </summary>
public EntityUid? IconEntity;
/// <summary> /// <summary>
/// Whether or not to close the context menu after using it to run this verb. /// Whether or not to close the context menu after using it to run this verb.
/// </summary> /// </summary>
@@ -200,6 +206,7 @@ namespace Content.Shared.Verbs
{ {
{ typeof(Verb) }, { typeof(Verb) },
{ typeof(InteractionVerb) }, { typeof(InteractionVerb) },
{ typeof(UtilityVerb) },
{ typeof(AlternativeVerb) }, { typeof(AlternativeVerb) },
{ typeof(ActivationVerb) }, { typeof(ActivationVerb) },
{ typeof(ExamineVerb) } { typeof(ExamineVerb) }
@@ -226,6 +233,27 @@ namespace Content.Shared.Verbs
} }
} }
/// <summary>
/// These verbs are similar to the normal interaction verbs, except these interactions are facilitated by the
/// currently held entity.
/// </summary>
/// <remarks>
/// The only notable difference between these and InteractionVerbs is that they are obtained by raising an event
/// directed at the currently held entity. Distinguishing between utility and interaction verbs helps avoid
/// confusion if a component enables verbs both when the item is used on something else, or when it is the
/// target of an interaction. These verbs are only obtained if the target and the held entity are NOT the same.
/// </remarks>
[Serializable, NetSerializable]
public sealed class UtilityVerb : Verb
{
public override int TypePriority => 3;
public UtilityVerb() : base()
{
TextStyleClass = InteractionVerb.DefaultTextStyleClass;
}
}
/// <summary> /// <summary>
/// Verbs for alternative-interactions. /// Verbs for alternative-interactions.
/// </summary> /// </summary>

View File

@@ -0,0 +1,2 @@
storage-component-transfer-verb = Transfer contents
storage-component-dispose-verb = Dispose of contents