New Feature: Slot blockers (#35172)

* First commit

* More comments

* Update

* Update

* For Beloved Maintainers

* Beck T, my beloved

* Update

* Old stuff

* Update EquipAttemptEvents.cs

* Update UnequipAttemptEvent.cs

---------

Co-authored-by: beck-thompson <107373427+beck-thompson@users.noreply.github.com>
This commit is contained in:
Winkarst
2025-05-12 20:35:42 +03:00
committed by GitHub
parent 410d8087c6
commit 08d9d46b46
8 changed files with 71 additions and 3 deletions

View File

@@ -1,8 +1,10 @@
namespace Content.Shared.Inventory.Events; namespace Content.Shared.Inventory.Events;
public abstract class EquipAttemptBase(EntityUid equipee, EntityUid equipTarget, EntityUid equipment, public abstract class EquipAttemptBase(EntityUid equipee, EntityUid equipTarget, EntityUid equipment,
SlotDefinition slotDefinition) : CancellableEntityEventArgs SlotDefinition slotDefinition) : CancellableEntityEventArgs, IInventoryRelayEvent
{ {
public SlotFlags TargetSlots { get; } = SlotFlags.WITHOUT_POCKET;
/// <summary> /// <summary>
/// The entity performing the action. NOT necessarily the one actually "receiving" the equipment. /// The entity performing the action. NOT necessarily the one actually "receiving" the equipment.
/// </summary> /// </summary>

View File

@@ -1,8 +1,10 @@
namespace Content.Shared.Inventory.Events; namespace Content.Shared.Inventory.Events;
public abstract class UnequipAttemptEventBase(EntityUid unequipee, EntityUid unEquipTarget, EntityUid equipment, public abstract class UnequipAttemptEventBase(EntityUid unequipee, EntityUid unEquipTarget, EntityUid equipment,
SlotDefinition slotDefinition) : CancellableEntityEventArgs SlotDefinition slotDefinition) : CancellableEntityEventArgs, IInventoryRelayEvent
{ {
public SlotFlags TargetSlots { get; } = SlotFlags.WITHOUT_POCKET;
/// <summary> /// <summary>
/// The entity performing the action. NOT necessarily the same as the entity whose equipment is being removed.. /// The entity performing the action. NOT necessarily the same as the entity whose equipment is being removed..
/// </summary> /// </summary>

View File

@@ -48,6 +48,8 @@ public partial class InventorySystem
SubscribeLocalEvent<InventoryComponent, SelfBeforeClimbEvent>(RelayInventoryEvent); SubscribeLocalEvent<InventoryComponent, SelfBeforeClimbEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, CoefficientQueryEvent>(RelayInventoryEvent); SubscribeLocalEvent<InventoryComponent, CoefficientQueryEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, ZombificationResistanceQueryEvent>(RelayInventoryEvent); SubscribeLocalEvent<InventoryComponent, ZombificationResistanceQueryEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, IsEquippingTargetAttemptEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, IsUnequippingTargetAttemptEvent>(RelayInventoryEvent);
// by-ref events // by-ref events
SubscribeLocalEvent<InventoryComponent, RefreshFrictionModifiersEvent>(RefRelayInventoryEvent); SubscribeLocalEvent<InventoryComponent, RefreshFrictionModifiersEvent>(RefRelayInventoryEvent);

View File

@@ -0,0 +1,16 @@
using Robust.Shared.GameStates;
namespace Content.Shared.Inventory;
/// <summary>
/// Used to prevent items from being unequipped and equipped from slots that are listed in <see cref="Slots"/>.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SlotBlockSystem))]
public sealed partial class SlotBlockComponent : Component
{
/// <summary>
/// Slots that this entity should block.
/// </summary>
[DataField(required: true), AutoNetworkedField]
public SlotFlags Slots = SlotFlags.NONE;
}

View File

@@ -0,0 +1,35 @@
using Content.Shared.Inventory.Events;
namespace Content.Shared.Inventory;
/// <summary>
/// Handles prevention of items being unequipped and equipped from slots that are blocked by <see cref="SlotBlockComponent"/>.
/// </summary>
public sealed partial class SlotBlockSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SlotBlockComponent, InventoryRelayedEvent<IsEquippingTargetAttemptEvent>>(OnEquipAttempt);
SubscribeLocalEvent<SlotBlockComponent, InventoryRelayedEvent<IsUnequippingTargetAttemptEvent>>(OnUnequipAttempt);
}
private void OnEquipAttempt(Entity<SlotBlockComponent> ent, ref InventoryRelayedEvent<IsEquippingTargetAttemptEvent> args)
{
if (args.Args.Cancelled || (args.Args.SlotFlags & ent.Comp.Slots) == 0)
return;
args.Args.Reason = Loc.GetString("slot-block-component-blocked", ("item", ent));
args.Args.Cancel();
}
private void OnUnequipAttempt(Entity<SlotBlockComponent> ent, ref InventoryRelayedEvent<IsUnequippingTargetAttemptEvent> args)
{
if (args.Args.Cancelled || (args.Args.SlotFlags & ent.Comp.Slots) == 0)
return;
args.Args.Reason = Loc.GetString("slot-block-component-blocked", ("item", ent));
args.Args.Cancel();
}
}

View File

@@ -0,0 +1 @@
slot-block-component-blocked = This slot is blocked by {$item}!

View File

@@ -105,6 +105,8 @@
id: ClothingHeadEVAHelmetBase id: ClothingHeadEVAHelmetBase
name: base space helmet name: base space helmet
components: components:
- type: SlotBlock
slots: [ears, eyes, mask]
- type: BreathMask - type: BreathMask
- type: Item - type: Item
size: Normal size: Normal
@@ -140,6 +142,8 @@
name: base hardsuit helmet name: base hardsuit helmet
categories: [ HideSpawnMenu ] categories: [ HideSpawnMenu ]
components: components:
- type: SlotBlock
slots: [ears, eyes, mask]
- type: BreathMask - type: BreathMask
- type: Sprite - type: Sprite
state: icon # default state used by most inheritors state: icon # default state used by most inheritors
@@ -186,6 +190,8 @@
name: base hardsuit helmet with light name: base hardsuit helmet with light
categories: [ HideSpawnMenu ] categories: [ HideSpawnMenu ]
components: components:
- type: SlotBlock
slots: [ears, eyes, mask]
- type: Sprite - type: Sprite
layers: layers:
- state: icon - state: icon

View File

@@ -105,6 +105,8 @@
id: ClothingOuterHardsuitBase id: ClothingOuterHardsuitBase
name: base hardsuit name: base hardsuit
components: components:
- type: SlotBlock
slots: [innerclothing, feet]
- type: PressureProtection - type: PressureProtection
highPressureMultiplier: 0.3 highPressureMultiplier: 0.3
lowPressureMultiplier: 1000 lowPressureMultiplier: 1000
@@ -149,6 +151,8 @@
id: ClothingOuterEVASuitBase id: ClothingOuterEVASuitBase
name: base EVA Suit name: base EVA Suit
components: components:
- type: SlotBlock
slots: [innerclothing, feet]
- type: PressureProtection - type: PressureProtection
highPressureMultiplier: 0.6 highPressureMultiplier: 0.6
lowPressureMultiplier: 1000 lowPressureMultiplier: 1000