mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-17 05:27:38 +03:00
## Mirror of PR #24494: [Thrown soap/banana/(etc?) will fail to slip until it lands](https://github.com/space-wizards/space-station-14/pull/24494) from <img src="https://avatars.githubusercontent.com/u/10567778?v=4" alt="space-wizards" width="22"/> [space-wizards](https://github.com/space-wizards)/[space-station-14](https://github.com/space-wizards/space-station-14) ###### `e061cb3f8c9dc8ddc26624ead2086dfb41465aae` PR opened by <img src="https://avatars.githubusercontent.com/u/35878406?v=4" width="16"/><a href="https://github.com/Errant-4"> Errant-4</a> at 2024-01-25 00:04:36 UTC --- PR changed 1 files with 21 additions and 1 deletions. The PR had the following labels: - Status: Awaiting Changes --- <details open="true"><summary><h1>Original Body</h1></summary> > ## About the PR > Thrown objects can no longer slip until they have landed. For a succesful slip, the attacker must now calculate how to throw the soap in front of/on the target. If the target is chasing and very close, it might be more effective to drop the soap/banana rather than throw it, but then this choice is another decision that must be quickly made to carry out the slip (also you can mess that up and slip yourself) > > A "MISS" popup is displayed mostly just to communicate that this was not a glitch until players get used to the idea. This popup can be removed later if we don't want it > > I tested what I could think of, but might have missed something, more eyes would be good on this one > > fixes #18027 > > ## Why / Balance > Slips are too easy for how annoying (or potentially lethal) they are. Currently, slip throws are heavily slanted to succeed at short range, where they will nearly always hit. As the range increases, it becomes more and more possible to dodge. But it's basically impossible to _fail_ the attack, the question is, will the target be able to anticipate and slow down to dodge it. This change is intended to make thrown slips, especially at short range, difficult for the attacker too, not just the target. > > If the argument for the current state is that the target should git gud, why should that not also apply to the attacker? > > > (Also if we want to talk about what's "realistic", it also makes very little sense to yeet a banana peel at someone and have them fall over from that, unless one tacitly agrees that the attack automatically always hits right under their feet (yet keeps flying anyway) ) > > ## Media > > https://github.com/space-wizards/space-station-14/assets/35878406/9e548b2d-ab99-4cbf-98b8-9ecd7cd14711 > > - [X] I have added screenshots/videos to this PR showcasing its changes ingame, **or** this PR does not require an ingame showcase > > **Changelog** > > Make sure to take this Changelog template out of the comment block in order for it to show up. > 🆑 Errant > - tweak: Thrown objects can no longer slip while they are still in flight. > </details> Co-authored-by: SimpleStation14 <Unknown>
134 lines
5.0 KiB
C#
134 lines
5.0 KiB
C#
using Content.Shared.Administration.Logs;
|
|
using Content.Shared.Database;
|
|
using Content.Shared.Inventory;
|
|
using Robust.Shared.Network;
|
|
using Content.Shared.Popups;
|
|
using Content.Shared.StatusEffect;
|
|
using Content.Shared.StepTrigger.Systems;
|
|
using Content.Shared.Stunnable;
|
|
using Content.Shared.Throwing;
|
|
using JetBrains.Annotations;
|
|
using Robust.Shared.Audio.Systems;
|
|
using Robust.Shared.Containers;
|
|
using Robust.Shared.Physics.Components;
|
|
using Robust.Shared.Physics.Systems;
|
|
using Robust.Shared.Utility;
|
|
|
|
namespace Content.Shared.Slippery;
|
|
|
|
[UsedImplicitly]
|
|
public sealed class SlipperySystem : EntitySystem
|
|
{
|
|
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
|
[Dependency] private readonly SharedStunSystem _stun = default!;
|
|
[Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
|
|
[Dependency] private readonly SharedContainerSystem _container = default!;
|
|
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
|
|
SubscribeLocalEvent<SlipperyComponent, StepTriggerAttemptEvent>(HandleAttemptCollide);
|
|
SubscribeLocalEvent<SlipperyComponent, StepTriggeredEvent>(HandleStepTrigger);
|
|
SubscribeLocalEvent<NoSlipComponent, SlipAttemptEvent>(OnNoSlipAttempt);
|
|
SubscribeLocalEvent<ThrownItemComponent, SlipCausingAttemptEvent>(OnThrownSlipAttempt);
|
|
// as long as slip-resistant mice are never added, this should be fine (otherwise a mouse-hat will transfer it's power to the wearer).
|
|
SubscribeLocalEvent<NoSlipComponent, InventoryRelayedEvent<SlipAttemptEvent>>((e, c, ev) => OnNoSlipAttempt(e, c, ev.Args));
|
|
}
|
|
|
|
private void HandleStepTrigger(EntityUid uid, SlipperyComponent component, ref StepTriggeredEvent args)
|
|
{
|
|
TrySlip(uid, component, args.Tripper);
|
|
}
|
|
|
|
private void HandleAttemptCollide(
|
|
EntityUid uid,
|
|
SlipperyComponent component,
|
|
ref StepTriggerAttemptEvent args)
|
|
{
|
|
args.Continue |= CanSlip(uid, args.Tripper);
|
|
}
|
|
|
|
private static void OnNoSlipAttempt(EntityUid uid, NoSlipComponent component, SlipAttemptEvent args)
|
|
{
|
|
args.Cancel();
|
|
}
|
|
|
|
private void OnThrownSlipAttempt(EntityUid uid, ThrownItemComponent comp, ref SlipCausingAttemptEvent args)
|
|
{
|
|
args.Cancelled = true;
|
|
}
|
|
|
|
private bool CanSlip(EntityUid uid, EntityUid toSlip)
|
|
{
|
|
return !_container.IsEntityInContainer(uid)
|
|
&& _statusEffects.CanApplyEffect(toSlip, "Stun"); //Should be KnockedDown instead?
|
|
}
|
|
|
|
private void TrySlip(EntityUid uid, SlipperyComponent component, EntityUid other)
|
|
{
|
|
if (HasComp<KnockedDownComponent>(other) && !component.SuperSlippery)
|
|
return;
|
|
|
|
var attemptEv = new SlipAttemptEvent();
|
|
RaiseLocalEvent(other, attemptEv);
|
|
if (attemptEv.Cancelled)
|
|
return;
|
|
|
|
var attemptCausingEv = new SlipCausingAttemptEvent();
|
|
RaiseLocalEvent(uid, ref attemptCausingEv);
|
|
if (attemptCausingEv.Cancelled)
|
|
return;
|
|
|
|
var ev = new SlipEvent(other);
|
|
RaiseLocalEvent(uid, ref ev);
|
|
|
|
if (TryComp(other, out PhysicsComponent? physics) && !HasComp<SlidingComponent>(other))
|
|
{
|
|
_physics.SetLinearVelocity(other, physics.LinearVelocity * component.LaunchForwardsMultiplier, body: physics);
|
|
|
|
if (component.SuperSlippery)
|
|
{
|
|
var sliding = EnsureComp<SlidingComponent>(other);
|
|
sliding.CollidingEntities.Add(uid);
|
|
DebugTools.Assert(_physics.GetContactingEntities(other, physics).Contains(uid));
|
|
}
|
|
}
|
|
|
|
var playSound = !_statusEffects.HasStatusEffect(other, "KnockedDown");
|
|
|
|
_stun.TryParalyze(other, TimeSpan.FromSeconds(component.ParalyzeTime), true);
|
|
|
|
// Preventing from playing the slip sound when you are already knocked down.
|
|
if (playSound)
|
|
{
|
|
_audio.PlayPredicted(component.SlipSound, other, other);
|
|
}
|
|
|
|
_adminLogger.Add(LogType.Slip, LogImpact.Low,
|
|
$"{ToPrettyString(other):mob} slipped on collision with {ToPrettyString(uid):entity}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Raised on an entity to determine if it can slip or not.
|
|
/// </summary>
|
|
public sealed class SlipAttemptEvent : CancellableEntityEventArgs, IInventoryRelayEvent
|
|
{
|
|
public SlotFlags TargetSlots { get; } = SlotFlags.FEET;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Raised on an entity that is causing the slip event (e.g, the banana peel), to determine if the slip attempt should be cancelled.
|
|
/// </summary>
|
|
/// <param name="Cancelled">If the slip should be cancelled</param>
|
|
[ByRefEvent]
|
|
public record struct SlipCausingAttemptEvent (bool Cancelled);
|
|
|
|
/// Raised on an entity that CAUSED some other entity to slip (e.g., the banana peel).
|
|
/// <param name="Slipped">The entity being slipped</param>
|
|
[ByRefEvent]
|
|
public readonly record struct SlipEvent(EntityUid Slipped);
|