[Tweak] Immersive Interactions (#288)

* no interacting with items inside containers

* no inventory interactions

* the backpackening

* item slots no swap

* bags slow in hands

* update sounds

* oops

* fix

* fix linter

---------

Co-authored-by: vanx <discord@vanxxxx>
This commit is contained in:
vanx
2025-03-15 12:46:56 +03:00
committed by GitHub
parent 0f1d0d9cfe
commit ed2f2b9555
16 changed files with 99 additions and 21 deletions

View File

@@ -83,7 +83,7 @@ namespace Content.Shared.ActionBlocker
/// check other blockers like <see cref="CanPickup(EntityUid)"/>
/// </remarks>
/// <returns></returns>
public bool CanInteract(EntityUid user, EntityUid? target)
public bool CanInteract(EntityUid user, EntityUid? target, bool showFailedPopup = false)
{
if (!CanConsciouslyPerformAction(user))
return false;
@@ -97,7 +97,7 @@ namespace Content.Shared.ActionBlocker
if (target == null || target == user)
return true;
var targetEv = new GettingInteractedWithAttemptEvent(user, target);
var targetEv = new GettingInteractedWithAttemptEvent(user, target, showFailedPopup);
RaiseLocalEvent(target.Value, ref targetEv);
return !targetEv.Cancelled;

View File

@@ -221,7 +221,7 @@ namespace Content.Shared.Containers.ItemSlots
/// </remarks>
[DataField]
[Access(typeof(ItemSlotsSystem), Other = AccessPermissions.ReadWriteExecute)]
public bool Swap = true;
public bool Swap = false; // WWDP immersive interactions
public string? ID => ContainerSlot?.ID;

View File

@@ -85,7 +85,7 @@ public abstract partial class SharedHandsSystem : EntitySystem
RemComp<HoldingDropComponent>(uid);
return false;
}
private readonly Angle _dropRotationIncrement = Angle.FromDegrees(5);
private bool PreciseDropMWheelUp(in PointerInputCmdHandler.PointerInputCmdArgs args)
{
@@ -163,7 +163,7 @@ public abstract partial class SharedHandsSystem : EntitySystem
if (!TryComp(session?.AttachedEntity, out HandsComponent? component))
return;
if (!_actionBlocker.CanInteract(session.AttachedEntity.Value, null))
if (!_actionBlocker.CanInteract(session.AttachedEntity.Value, null, true))
return;
if (component.ActiveHand == null || component.Hands.Count < 2)

View File

@@ -26,9 +26,11 @@
/// generic interaction.
/// </summary>
[ByRefEvent]
public struct GettingInteractedWithAttemptEvent(EntityUid uid, EntityUid? target)
public struct GettingInteractedWithAttemptEvent(EntityUid uid, EntityUid? target, bool showFailedPopup = false)
{
public bool Cancelled;
public bool Handled;
public bool ShowFailedPopup = showFailedPopup;
public readonly EntityUid Uid = uid;
public readonly EntityUid? Target = target;
}

View File

@@ -161,7 +161,7 @@ namespace Content.Shared.Interaction
private void OnBoundInterfaceInteractAttempt(BoundUserInterfaceMessageAttempt ev)
{
_uiQuery.TryComp(ev.Target, out var uiComp);
if (!_actionBlockerSystem.CanInteract(ev.Actor, ev.Target))
if (!_actionBlockerSystem.CanInteract(ev.Actor, ev.Target, true)) // WWDP interaction popups
{
// We permit ghosts to open uis unless explicitly blocked
if (ev.Message is not OpenBoundInterfaceMessage || !HasComp<GhostComponent>(ev.Actor) || uiComp?.BlockSpectators == true)
@@ -381,7 +381,7 @@ namespace Content.Shared.Interaction
if (_relayQuery.TryComp(user, out var relay) && relay.RelayEntity is not null)
{
// TODO this needs to be handled better. This probably bypasses many complex can-interact checks in weird roundabout ways.
if (_actionBlockerSystem.CanInteract(user, target))
if (_actionBlockerSystem.CanInteract(user, target, true)) // WWDP interaction popups
{
UserInteraction(relay.RelayEntity.Value,
coordinates,
@@ -414,7 +414,7 @@ namespace Content.Shared.Interaction
return;
}
if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, target))
if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, target, true)) // WWDP interaction popups
return;
// Check if interacted entity is in the same container, the direct child, or direct parent of the user.
@@ -988,10 +988,7 @@ namespace Content.Shared.Interaction
if (IsDeleted(user) || IsDeleted(used) || IsDeleted(target))
return false;
if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, target))
return false;
if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, target))
if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, target, true)) // WWDP interaction popups
return false;
if (checkCanUse && !_actionBlockerSystem.CanUseHeldEntity(user, used))
@@ -1005,7 +1002,9 @@ namespace Content.Shared.Interaction
if (RangedInteractDoBefore(user, used, target, clickLocation, true))
return true;
// all interactions should only happen when in range / unobstructed, so no range check is needed
if (!InRangeAndAccessible(user, target)) // WWDP no interacting with items inside containers
return false;
var interactUsingEvent = new InteractUsingEvent(user, used, target, clickLocation);
RaiseLocalEvent(target, interactUsingEvent, true);
DoContactInteraction(user, used, interactUsingEvent);
@@ -1107,7 +1106,7 @@ namespace Content.Shared.Interaction
if (checkUseDelay && delayComponent != null && _useDelay.IsDelayed((used, delayComponent)))
return false;
if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, used))
if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, used, true)) // WWDP interaction popups
return false;
if (checkAccess && !InRangeUnobstructed(user, used))
@@ -1161,7 +1160,7 @@ namespace Content.Shared.Interaction
if (checkUseDelay && delayComponent != null && _useDelay.IsDelayed((used, delayComponent)))
return true; // if the item is on cooldown, we consider this handled.
if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, used))
if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, used, true)) // WWDP interaction popups
return false;
if (checkCanUse && !_actionBlockerSystem.CanUseHeldEntity(user, used))
@@ -1212,7 +1211,7 @@ namespace Content.Shared.Interaction
if (ev.Handled)
return true;
// WD EDIT END
// Get list of alt-interact verbs
var verbs = _verbSystem.GetLocalVerbs(target, user, typeof(AlternativeVerb)).Where(verb => ((AlternativeVerb) verb).InActiveHandOnly == false); // WD EDIT
@@ -1301,7 +1300,7 @@ namespace Content.Shared.Interaction
if (_containerSystem.IsInSameOrParentContainer(user, target, out _, out var container))
return true;
return container != null && CanAccessViaStorage(user, target, container);
return false; // WWDP no interacting with items inside containers
}
/// <summary>

View File

@@ -127,6 +127,9 @@ public sealed class SmartEquipSystem : EntitySystem
// case 2 (storage item):
if (TryComp<StorageComponent>(slotItem, out var storage))
{
if (!_actionBlocker.CanInteract(uid, slotItem, true)) // WWDP Interactions
return;
switch (handItem)
{
case null when storage.Container.ContainedEntities.Count == 0:
@@ -159,6 +162,9 @@ public sealed class SmartEquipSystem : EntitySystem
// case 3 (itemslot item):
if (TryComp<ItemSlotsComponent>(slotItem, out var slots))
{
if (!_actionBlocker.CanInteract(uid, slotItem, true)) // WWDP Interactions
return;
if (handItem == null)
{
ItemSlot? toEjectFrom = null;

View File

@@ -10,6 +10,7 @@ using Content.Shared.Inventory.Events;
using Content.Shared.Item;
using Content.Shared.Movement.Systems;
using Content.Shared.Popups;
using Content.Shared.Storage;
using Content.Shared.Strip;
using Content.Shared.Strip.Components;
using Content.Shared.Whitelist;
@@ -30,6 +31,7 @@ public abstract partial class InventorySystem
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
[Dependency] private readonly SharedUserInterfaceSystem _interface = default!; // WWDP
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
@@ -44,6 +46,8 @@ public abstract partial class InventorySystem
SubscribeLocalEvent<InventoryComponent, EntInsertedIntoContainerMessage>(OnEntInserted);
SubscribeLocalEvent<InventoryComponent, EntRemovedFromContainerMessage>(OnEntRemoved);
SubscribeLocalEvent<ItemComponent, GotEquippedEvent>(OnEquipped); // WWDP
SubscribeAllEvent<UseSlotNetworkMessage>(OnUseSlot);
}
@@ -124,6 +128,15 @@ public abstract partial class InventorySystem
TryEquip(actor, actor, held.Value, ev.Slot, predicted: true, inventory: inventory, force: true, checkDoafter:true);
}
// WWDP IF WE PUT IT ON AND ITS NOT ACCESSIBLE CLOSE THE UI
private void OnEquipped(Entity<ItemComponent> item, ref GotEquippedEvent args)
{
if (item.Comp.CanBeUsedWhileWorn)
return;
_interface.CloseUis(item.Owner);
}
public bool TryEquip(EntityUid uid, EntityUid itemUid, string slot, bool silent = false, bool force = false, bool predicted = false,
InventoryComponent? inventory = null, ClothingComponent? clothing = null, bool checkDoafter = false) =>
TryEquip(uid, uid, itemUid, slot, silent, force, predicted, inventory, clothing, checkDoafter);
@@ -173,7 +186,7 @@ public abstract partial class InventorySystem
{
BlockDuplicate = true,
BreakOnHandChange = true,
BreakOnMove = true,
BreakOnMove = false, // WWDP no breaking on move
BreakOnDamage = false, // White Dream: Do not break on recieving damage
CancelDuplicate = true,
RequireCanInteract = true,
@@ -422,7 +435,7 @@ public abstract partial class InventorySystem
{
BlockDuplicate = true,
BreakOnHandChange = true,
BreakOnMove = true,
BreakOnMove = false, // WWDP no breaking on move
BreakOnDamage = false, // White Dream: Do not break on recieving damage
CancelDuplicate = true,
RequireCanInteract = true,

View File

@@ -29,6 +29,12 @@ public sealed partial class ItemComponent : Component
[DataField, AutoNetworkedField]
public string? HeldPrefix;
/// <summary>
/// WWDP - Can this item be used while equipped in someone's inventory, including pockets
/// </summary>
[DataField, AutoNetworkedField]
public bool CanBeUsedWhileWorn;
/// <summary>
/// Rsi of the sprite shown on the player when this item is in their hands. Used to generate a default entry for <see cref="InhandVisuals"/>
/// </summary>

View File

@@ -2,7 +2,10 @@ using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction;
using Content.Shared.Verbs;
using Content.Shared.Examine;
using Content.Shared.Interaction.Events;
using Content.Shared.Inventory;
using Content.Shared.Item.ItemToggle.Components;
using Content.Shared.Popups;
using Content.Shared.Storage;
using JetBrains.Annotations;
using Robust.Shared.Containers;
@@ -16,6 +19,8 @@ public abstract class SharedItemSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
[Dependency] private readonly InventorySystem _inventory = default!; // WWDP
[Dependency] private readonly SharedPopupSystem _popup = default!; // WWDP
[Dependency] protected readonly SharedContainerSystem Container = default!;
public override void Initialize()
@@ -24,6 +29,7 @@ public abstract class SharedItemSystem : EntitySystem
SubscribeLocalEvent<ItemComponent, GetVerbsEvent<InteractionVerb>>(AddPickupVerb);
SubscribeLocalEvent<ItemComponent, InteractHandEvent>(OnHandInteract);
SubscribeLocalEvent<ItemComponent, AfterAutoHandleStateEvent>(OnItemAutoState);
SubscribeLocalEvent<ItemComponent, GettingInteractedWithAttemptEvent>(OnItemInteracted); // WWDP
SubscribeLocalEvent<ItemComponent, ExaminedEvent>(OnExamine);
@@ -94,6 +100,28 @@ public abstract class SharedItemSystem : EntitySystem
args.Handled = _handsSystem.TryPickup(args.User, uid, animateUser: false);
}
/// <summary>
/// WWDP - Handle attempt to interact with this item
/// Block interactions if it is equipped unless CanBeUsedWhileWorn
/// </summary>
private void OnItemInteracted(EntityUid uid, ItemComponent component, ref GettingInteractedWithAttemptEvent args)
{
if (uid != args.Target || args.Handled)
return;
if (!_inventory.TryGetContainingSlot(uid, out _))
return;
if (component.CanBeUsedWhileWorn)
return;
if (args.ShowFailedPopup)
_popup.PopupClient(Loc.GetString("must-be-in-hand"), args.Uid);
args.Cancelled = true;
args.Handled = true;
}
private void AddPickupVerb(EntityUid uid, ItemComponent component, GetVerbsEvent<InteractionVerb> args)
{
if (args.Hands == null ||

View File

@@ -15,6 +15,7 @@ using Content.Shared.Input;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Components;
using Content.Shared.Inventory;
using Content.Shared.Inventory.Events;
using Content.Shared.Item;
using Content.Shared.Lock;
using Content.Shared.Materials;

View File

@@ -0,0 +1 @@
must-be-in-hand = Must be in hand!

View File

@@ -0,0 +1 @@
must-be-in-hand = Должно быть в руке!

View File

@@ -8,6 +8,7 @@
sprite: Clothing/Back/Backpacks/backpack.rsi
state: icon
- type: Item
canBeUsedWhileWorn: false # WWDP
size: Huge
- type: Clothing
equipSound: /Audio/_White/Equip/clothingrustle4.ogg # WWDP
@@ -34,6 +35,10 @@
- type: ExplosionResistance
damageCoefficient: 0.9
- type: AllowsSleepInside # DeltaV - enable sleeping inside bags
- type: HeldSpeedModifier # WWDP slow down with bags in hand
mirrorClothingModifier: false
sprintModifier: 0.85
walkModifier: 0.85
- type: entity
parent: ClothingBackpack

View File

@@ -13,7 +13,18 @@
- type: ClothingSpeedModifier
walkModifier: 1
sprintModifier: 0.9
- type: HeldSpeedModifier
- type: HeldSpeedModifier # WWDP slow down with bags in hand
mirrorClothingModifier: false
sprintModifier: 0.8
walkModifier: 0.8
- type: Clothing
equipDelay: 1
unequipDelay: 1
equipSound: /Audio/_White/Equip/clothingrustle2.ogg # WWDP
- type: EmitSoundOnPickup # WWDP
sound: /Audio/_White/Equip/clothingrustle2.ogg
- type: Item
canBeUsedWhileWorn: false # WWDP
- type: entity
parent: ClothingBackpackDuffel

View File

@@ -11,6 +11,8 @@
- 0,0,1,3
- 3,0,6,3
- 8,0,9,3
- type: Clothing # WWDP
#equipSound: /Audio/_White/Equip/clothingrustle4.ogg todo sounds from the gunnening
- type: entity
parent: ClothingBackpackSatchel

View File

@@ -5,6 +5,7 @@
components:
- type: Item
size: Normal
canBeUsedWhileWorn: true # WWDP
- type: Sprite
- type: Tag
tags:
@@ -12,6 +13,8 @@
- type: StaticPrice
price: 10
- type: Clothing
equipDelay: 0.5 # WWDP
unequipDelay: 0.5 # WWDP
- type: entity
abstract: true