Add WieldingBlockerComponent (#37778)

initial commit
This commit is contained in:
slarticodefast
2025-05-26 05:50:30 +02:00
committed by GitHub
parent 68d5d940cf
commit e8bc811f7a
6 changed files with 124 additions and 12 deletions

View File

@@ -4,6 +4,7 @@ using Content.Shared.Hands.Components;
using Content.Shared.Movement.Systems; using Content.Shared.Movement.Systems;
using Content.Shared.Projectiles; using Content.Shared.Projectiles;
using Content.Shared.Weapons.Ranged.Events; using Content.Shared.Weapons.Ranged.Events;
using Content.Shared.Wieldable;
namespace Content.Shared.Hands.EntitySystems; namespace Content.Shared.Hands.EntitySystems;
@@ -19,6 +20,8 @@ public abstract partial class SharedHandsSystem
SubscribeLocalEvent<HandsComponent, ExtinguishEvent>(RefRelayEvent); SubscribeLocalEvent<HandsComponent, ExtinguishEvent>(RefRelayEvent);
SubscribeLocalEvent<HandsComponent, ProjectileReflectAttemptEvent>(RefRelayEvent); SubscribeLocalEvent<HandsComponent, ProjectileReflectAttemptEvent>(RefRelayEvent);
SubscribeLocalEvent<HandsComponent, HitScanReflectAttemptEvent>(RefRelayEvent); SubscribeLocalEvent<HandsComponent, HitScanReflectAttemptEvent>(RefRelayEvent);
SubscribeLocalEvent<HandsComponent, WieldAttemptEvent>(RefRelayEvent);
SubscribeLocalEvent<HandsComponent, UnwieldAttemptEvent>(RefRelayEvent);
} }
private void RelayEvent<T>(Entity<HandsComponent> entity, ref T args) where T : EntityEventArgs private void RelayEvent<T>(Entity<HandsComponent> entity, ref T args) where T : EntityEventArgs

View File

@@ -24,6 +24,7 @@ using Content.Shared.Strip.Components;
using Content.Shared.Temperature; using Content.Shared.Temperature;
using Content.Shared.Verbs; using Content.Shared.Verbs;
using Content.Shared.Weapons.Ranged.Events; using Content.Shared.Weapons.Ranged.Events;
using Content.Shared.Wieldable;
using Content.Shared.Zombies; using Content.Shared.Zombies;
namespace Content.Shared.Inventory; namespace Content.Shared.Inventory;
@@ -63,6 +64,8 @@ public partial class InventorySystem
SubscribeLocalEvent<InventoryComponent, ProjectileReflectAttemptEvent>(RefRelayInventoryEvent); SubscribeLocalEvent<InventoryComponent, ProjectileReflectAttemptEvent>(RefRelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, HitScanReflectAttemptEvent>(RefRelayInventoryEvent); SubscribeLocalEvent<InventoryComponent, HitScanReflectAttemptEvent>(RefRelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, GetContrabandDetailsEvent>(RefRelayInventoryEvent); SubscribeLocalEvent<InventoryComponent, GetContrabandDetailsEvent>(RefRelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, WieldAttemptEvent>(RefRelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, UnwieldAttemptEvent>(RefRelayInventoryEvent);
// Eye/vision events // Eye/vision events
SubscribeLocalEvent<InventoryComponent, CanSeeAttemptEvent>(RelayInventoryEvent); SubscribeLocalEvent<InventoryComponent, CanSeeAttemptEvent>(RelayInventoryEvent);

View File

@@ -0,0 +1,23 @@
using Robust.Shared.GameStates;
namespace Content.Shared.Wieldable.Components;
/// <summary>
/// Blocks an entity from wielding items.
/// When added to an item, it will block wielding when held in hand or equipped.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class WieldingBlockerComponent : Component
{
/// <summary>
/// Block wielding when this item is held in a hand?
/// </summary>
[DataField, AutoNetworkedField]
public bool BlockInHand = true;
/// <summary>
/// Block wielding when this item is equipped?
/// </summary>
[DataField, AutoNetworkedField]
public bool BlockEquipped = true;
}

View File

@@ -1,3 +1,5 @@
using Content.Shared.Inventory;
namespace Content.Shared.Wieldable; namespace Content.Shared.Wieldable;
/// <summary> /// <summary>
@@ -14,12 +16,18 @@ public readonly record struct ItemWieldedEvent(EntityUid User);
public readonly record struct ItemUnwieldedEvent(EntityUid User, bool Force); public readonly record struct ItemUnwieldedEvent(EntityUid User, bool Force);
/// <summary> /// <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. /// If this event is cancelled wielding will not happen.
/// </summary> /// </summary>
[ByRefEvent] [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() public void Cancel()
{ {
Cancelled = true; Cancelled = true;
@@ -27,15 +35,21 @@ public record struct WieldAttemptEvent(EntityUid User, bool Cancelled = false)
} }
/// <summary> /// <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. /// If this event is cancelled unwielding will not happen.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This event is not raised if the user is forced to unwield the item. /// This event is not raised if the user is forced to unwield the item.
/// </remarks> /// </remarks>
[ByRefEvent] [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() public void Cancel()
{ {
Cancelled = true; Cancelled = true;

View File

@@ -1,11 +1,12 @@
using System.Linq; using System.Linq;
using Content.Shared.Camera;
using Content.Shared.Examine; using Content.Shared.Examine;
using Content.Shared.Hands; using Content.Shared.Hands;
using Content.Shared.Hands.Components; using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems; using Content.Shared.Hands.EntitySystems;
using Content.Shared.IdentityManagement; using Content.Shared.IdentityManagement;
using Content.Shared.Interaction.Events; using Content.Shared.Interaction.Events;
using Content.Shared.Inventory;
using Content.Shared.Inventory.Events;
using Content.Shared.Inventory.VirtualItem; using Content.Shared.Inventory.VirtualItem;
using Content.Shared.Item; using Content.Shared.Item;
using Content.Shared.Movement.Components; using Content.Shared.Movement.Components;
@@ -22,7 +23,6 @@ using Content.Shared.Weapons.Ranged.Systems;
using Content.Shared.Wieldable.Components; using Content.Shared.Wieldable.Components;
using Robust.Shared.Audio.Systems; using Robust.Shared.Audio.Systems;
using Robust.Shared.Collections; using Robust.Shared.Collections;
using Robust.Shared.Network;
using Robust.Shared.Timing; using Robust.Shared.Timing;
namespace Content.Shared.Wieldable; namespace Content.Shared.Wieldable;
@@ -51,6 +51,12 @@ public abstract class SharedWieldableSystem : EntitySystem
SubscribeLocalEvent<WieldableComponent, GetVerbsEvent<InteractionVerb>>(AddToggleWieldVerb); SubscribeLocalEvent<WieldableComponent, GetVerbsEvent<InteractionVerb>>(AddToggleWieldVerb);
SubscribeLocalEvent<WieldableComponent, HandDeselectedEvent>(OnDeselectWieldable); 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<MeleeRequiresWieldComponent, AttemptMeleeEvent>(OnMeleeAttempt);
SubscribeLocalEvent<GunRequiresWieldComponent, ExaminedEvent>(OnExamineRequires); SubscribeLocalEvent<GunRequiresWieldComponent, ExaminedEvent>(OnExamineRequires);
SubscribeLocalEvent<GunRequiresWieldComponent, ShotAttemptedEvent>(OnShootAttempt); SubscribeLocalEvent<GunRequiresWieldComponent, ShotAttemptedEvent>(OnShootAttempt);
@@ -186,14 +192,55 @@ public abstract class SharedWieldableSystem : EntitySystem
return; return;
if (!component.Wielded) 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) 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) if (HasComp<UseDelayComponent>(uid) && !component.UseDelayOnWield)
args.ApplyDelay = false; 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) public bool CanWield(EntityUid uid, WieldableComponent component, EntityUid user, bool quiet = false)
{ {
// Do they have enough hands free? // Do they have enough hands free?
@@ -242,11 +289,15 @@ public abstract class SharedWieldableSystem : EntitySystem
return false; return false;
} }
var attemptEv = new WieldAttemptEvent(user); var attemptEv = new WieldAttemptEvent(user, used);
RaiseLocalEvent(used, ref attemptEv); RaiseLocalEvent(user, ref attemptEv);
if (attemptEv.Cancelled) if (attemptEv.Cancelled)
{
if (attemptEv.Message != null)
_popup.PopupClient(attemptEv.Message, user, user);
return false; return false;
}
if (TryComp<ItemComponent>(used, out var item)) if (TryComp<ItemComponent>(used, out var item))
{ {
@@ -298,12 +349,16 @@ public abstract class SharedWieldableSystem : EntitySystem
if (!force) if (!force)
{ {
var attemptEv = new UnwieldAttemptEvent(user); var attemptEv = new UnwieldAttemptEvent(user, used);
RaiseLocalEvent(used, ref attemptEv); RaiseLocalEvent(user, ref attemptEv);
if (attemptEv.Cancelled) if (attemptEv.Cancelled)
{
if (attemptEv.Message != null)
_popup.PopupClient(attemptEv.Message, user, user);
return false; return false;
} }
}
SetWielded((used, component), false); SetWielded((used, component), false);
@@ -312,6 +367,19 @@ public abstract class SharedWieldableSystem : EntitySystem
return true; 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> /// <summary>
/// Sets wielded without doing any checks. /// Sets wielded without doing any checks.
/// </summary> /// </summary>

View File

@@ -7,6 +7,7 @@ wieldable-component-successful-wield = You wield { THE($item) }.
wieldable-component-failed-wield = You unwield { THE($item) }. wieldable-component-failed-wield = You unwield { THE($item) }.
wieldable-component-successful-wield-other = { CAPITALIZE(THE($user)) } wields { THE($item) }. wieldable-component-successful-wield-other = { CAPITALIZE(THE($user)) } wields { THE($item) }.
wieldable-component-failed-wield-other = { CAPITALIZE(THE($user)) } unwields { THE($item) }. wieldable-component-failed-wield-other = { CAPITALIZE(THE($user)) } unwields { THE($item) }.
wieldable-component-blocked-wield = { CAPITALIZE(THE($blocker)) } blocks you from wielding { THE($item) }.
wieldable-component-no-hands = You don't have enough hands! wieldable-component-no-hands = You don't have enough hands!
wieldable-component-not-enough-free-hands = {$number -> wieldable-component-not-enough-free-hands = {$number ->