+using Content.Shared.Inventory;
+
namespace Content.Shared.Wieldable;
/// <summary>
public readonly record struct ItemUnwieldedEvent(EntityUid User, bool Force);
/// <summary>
-/// Raised directed on an item before a user tries to wield it.
+/// Raised directed on an user and all the items in their inventory and hands before they wield an item.
/// If this event is cancelled wielding will not happen.
/// </summary>
[ByRefEvent]
-public record struct WieldAttemptEvent(EntityUid User, bool Cancelled = false)
+public record struct WieldAttemptEvent(EntityUid User, EntityUid Wielded, bool Cancelled = false) : IInventoryRelayEvent
{
+ /// <summary>
+ /// Popup message for the user to tell them why they cannot wield if Cancelled
+ /// </summary>
+ public string? Message;
+
+ SlotFlags IInventoryRelayEvent.TargetSlots => SlotFlags.WITHOUT_POCKET;
public void Cancel()
{
Cancelled = true;
}
/// <summary>
-/// Raised directed on an item before a user tries to stop wielding it willingly.
+/// Raised directed on an user and all the items in their inventory and hands before they unwield an item willingly.
/// If this event is cancelled unwielding will not happen.
/// </summary>
/// <remarks>
/// This event is not raised if the user is forced to unwield the item.
/// </remarks>
[ByRefEvent]
-public record struct UnwieldAttemptEvent(EntityUid User, bool Cancelled = false)
+public record struct UnwieldAttemptEvent(EntityUid User, EntityUid Wielded, bool Cancelled = false) : IInventoryRelayEvent
{
+ /// <summary>
+ /// Popup message for the user to tell them why they cannot unwield if Cancelled
+ /// </summary>
+ public string? Message;
+
+ SlotFlags IInventoryRelayEvent.TargetSlots => SlotFlags.WITHOUT_POCKET;
public void Cancel()
{
Cancelled = true;
using System.Linq;
-using Content.Shared.Camera;
using Content.Shared.Examine;
using Content.Shared.Hands;
using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.IdentityManagement;
using Content.Shared.Interaction.Events;
+using Content.Shared.Inventory;
+using Content.Shared.Inventory.Events;
using Content.Shared.Inventory.VirtualItem;
using Content.Shared.Item;
using Content.Shared.Movement.Components;
using Content.Shared.Wieldable.Components;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Collections;
-using Robust.Shared.Network;
using Robust.Shared.Timing;
namespace Content.Shared.Wieldable;
SubscribeLocalEvent<WieldableComponent, GetVerbsEvent<InteractionVerb>>(AddToggleWieldVerb);
SubscribeLocalEvent<WieldableComponent, HandDeselectedEvent>(OnDeselectWieldable);
+ SubscribeLocalEvent<WieldingBlockerComponent, GotEquippedEvent>(OnBlockerEquipped);
+ SubscribeLocalEvent<WieldingBlockerComponent, GotEquippedHandEvent>(OnBlockerEquippedHand);
+ SubscribeLocalEvent<WieldingBlockerComponent, WieldAttemptEvent>(OnBlockerAttempt);
+ SubscribeLocalEvent<WieldingBlockerComponent, InventoryRelayedEvent<WieldAttemptEvent>>(OnBlockerAttempt);
+ SubscribeLocalEvent<WieldingBlockerComponent, HeldRelayedEvent<WieldAttemptEvent>>(OnBlockerAttempt);
+
SubscribeLocalEvent<MeleeRequiresWieldComponent, AttemptMeleeEvent>(OnMeleeAttempt);
SubscribeLocalEvent<GunRequiresWieldComponent, ExaminedEvent>(OnExamineRequires);
SubscribeLocalEvent<GunRequiresWieldComponent, ShotAttemptedEvent>(OnShootAttempt);
return;
if (!component.Wielded)
- args.Handled = TryWield(uid, component, args.User);
+ {
+ TryWield(uid, component, args.User);
+ args.Handled = true; // always mark as handled or we will cycle ammo when wielding is blocked
+ }
else if (component.UnwieldOnUse)
- args.Handled = TryUnwield(uid, component, args.User);
+ {
+ TryUnwield(uid, component, args.User);
+ args.Handled = true;
+ }
if (HasComp<UseDelayComponent>(uid) && !component.UseDelayOnWield)
args.ApplyDelay = false;
}
+ private void OnBlockerEquipped(Entity<WieldingBlockerComponent> ent, ref GotEquippedEvent args)
+ {
+ if (ent.Comp.BlockEquipped)
+ UnwieldAll(args.Equipee, force: true);
+ }
+
+ private void OnBlockerEquippedHand(Entity<WieldingBlockerComponent> ent, ref GotEquippedHandEvent args)
+ {
+ if (ent.Comp.BlockInHand)
+ UnwieldAll(args.User, force: true);
+ }
+
+ private void OnBlockerAttempt(Entity<WieldingBlockerComponent> ent, ref InventoryRelayedEvent<WieldAttemptEvent> args)
+ {
+ if (ent.Comp.BlockEquipped)
+ {
+ args.Args.Message = Loc.GetString("wieldable-component-blocked-wield", ("blocker", ent.Owner), ("item", args.Args.Wielded));
+ args.Args.Cancelled = true;
+ }
+ }
+
+ private void OnBlockerAttempt(Entity<WieldingBlockerComponent> ent, ref HeldRelayedEvent<WieldAttemptEvent> args)
+ {
+ if (ent.Comp.BlockInHand)
+ {
+ args.Args.Message = Loc.GetString("wieldable-component-blocked-wield", ("blocker", ent.Owner), ("item", args.Args.Wielded));
+ args.Args.Cancelled = true;
+ }
+ }
+
+ private void OnBlockerAttempt(Entity<WieldingBlockerComponent> ent, ref WieldAttemptEvent args)
+ {
+ args.Cancelled = true;
+ }
+
public bool CanWield(EntityUid uid, WieldableComponent component, EntityUid user, bool quiet = false)
{
// Do they have enough hands free?
return false;
}
- var attemptEv = new WieldAttemptEvent(user);
- RaiseLocalEvent(used, ref attemptEv);
+ var attemptEv = new WieldAttemptEvent(user, used);
+ RaiseLocalEvent(user, ref attemptEv);
if (attemptEv.Cancelled)
+ {
+ if (attemptEv.Message != null)
+ _popup.PopupClient(attemptEv.Message, user, user);
return false;
+ }
if (TryComp<ItemComponent>(used, out var item))
{
if (!force)
{
- var attemptEv = new UnwieldAttemptEvent(user);
- RaiseLocalEvent(used, ref attemptEv);
+ var attemptEv = new UnwieldAttemptEvent(user, used);
+ RaiseLocalEvent(user, ref attemptEv);
if (attemptEv.Cancelled)
+ {
+ if (attemptEv.Message != null)
+ _popup.PopupClient(attemptEv.Message, user, user);
return false;
+ }
}
SetWielded((used, component), false);
return true;
}
+ /// <summary>
+ /// Makes an entity unwield all currently wielded items.
+ /// </summary>
+ /// <param name="force">If this is true we will bypass UnwieldAttemptEvent.</param>
+ public void UnwieldAll(Entity<HandsComponent?> wielder, bool force = false)
+ {
+ foreach (var held in _hands.EnumerateHeld(wielder.Owner, wielder.Comp))
+ {
+ if (TryComp<WieldableComponent>(held, out var wieldable))
+ TryUnwield(held, wieldable, wielder, force);
+ }
+ }
+
/// <summary>
/// Sets wielded without doing any checks.
/// </summary>