diff --git a/Content.Server/Hands/Systems/HandsSystem.cs b/Content.Server/Hands/Systems/HandsSystem.cs index 5f8ee7dd42..ae73a9ebc6 100644 --- a/Content.Server/Hands/Systems/HandsSystem.cs +++ b/Content.Server/Hands/Systems/HandsSystem.cs @@ -190,7 +190,7 @@ namespace Content.Server.Hands.Systems player.IsInContainer() || !TryComp(player, out SharedHandsComponent? hands) || hands.ActiveHandEntity is not EntityUid throwEnt || - !_actionBlockerSystem.CanThrow(player)) + !_actionBlockerSystem.CanThrow(player, throwEnt)) return false; if (EntityManager.TryGetComponent(throwEnt, out StackComponent? stack) && stack.Count > 1 && stack.ThrowIndividually) @@ -202,8 +202,6 @@ namespace Content.Server.Hands.Systems throwEnt = splitStack.Value; } - else if (!TryDrop(player, throwEnt, handsComp: hands)) - return false; var direction = coords.ToMapPos(EntityManager) - Transform(player).WorldPosition; if (direction == Vector2.Zero) @@ -212,11 +210,23 @@ namespace Content.Server.Hands.Systems direction = direction.Normalized * Math.Min(direction.Length, hands.ThrowRange); var throwStrength = hands.ThrowForceMultiplier; - _throwingSystem.TryThrow(throwEnt, direction, throwStrength, player); + + // Let other systems change the thrown entity (useful for virtual items) + // or the throw strength. + var ev = new BeforeThrowEvent(throwEnt, direction, throwStrength, player); + RaiseLocalEvent(player, ev, false); + + if (ev.Handled) + return true; + + // This can grief the above event so we raise it afterwards + if (!TryDrop(player, throwEnt, handsComp: hands)) + return false; + + _throwingSystem.TryThrow(ev.ItemUid, ev.Direction, ev.ThrowStrength, ev.PlayerUid); return true; } - private void HandleSmartEquipBackpack(ICommonSession? session) { HandleSmartEquip(session, "back"); diff --git a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs index f2e47ad8eb..3c0161f2f5 100644 --- a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs +++ b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs @@ -97,9 +97,9 @@ namespace Content.Shared.ActionBlocker return !ev.Cancelled; } - public bool CanThrow(EntityUid user) + public bool CanThrow(EntityUid user, EntityUid itemUid) { - var ev = new ThrowAttemptEvent(user); + var ev = new ThrowAttemptEvent(user, itemUid); RaiseLocalEvent(user, ev, true); return !ev.Cancelled; diff --git a/Content.Shared/Throwing/BeforeThrowEvent.cs b/Content.Shared/Throwing/BeforeThrowEvent.cs new file mode 100644 index 0000000000..349a18c56d --- /dev/null +++ b/Content.Shared/Throwing/BeforeThrowEvent.cs @@ -0,0 +1,18 @@ +namespace Content.Shared.Throwing +{ + public sealed class BeforeThrowEvent : HandledEntityEventArgs + { + public BeforeThrowEvent(EntityUid itemUid, Vector2 direction, float throwStrength, EntityUid playerUid) + { + ItemUid = itemUid; + Direction = direction; + ThrowStrength = throwStrength; + PlayerUid = playerUid; + } + + public EntityUid ItemUid { get; set; } + public Vector2 Direction { get; } + public float ThrowStrength { get; set;} + public EntityUid PlayerUid { get; } + } +} diff --git a/Content.Shared/Throwing/ThrowAttemptEvent.cs b/Content.Shared/Throwing/ThrowAttemptEvent.cs index 23ef048b0a..bf8cad6c74 100644 --- a/Content.Shared/Throwing/ThrowAttemptEvent.cs +++ b/Content.Shared/Throwing/ThrowAttemptEvent.cs @@ -2,12 +2,15 @@ { public sealed class ThrowAttemptEvent : CancellableEntityEventArgs { - public ThrowAttemptEvent(EntityUid uid) + public ThrowAttemptEvent(EntityUid uid, EntityUid itemUid) { Uid = uid; + ItemUid = itemUid; } public EntityUid Uid { get; } + + public EntityUid ItemUid { get; } } ///