Files
wwdpublic/Content.Shared/Movement/Systems/MovementSpeedModifierSystem.cs
Angelo Fallaria f4d2e3551b Make Dionas Slow And Steady (#704)
# Description

Dionas now have 25% slower movement speed in exchange for total slip
immunity and slow immunity (except lying down).

Note that this also prevents slowdowns from hunger and thirst.

This also fixes an existing bug with Sluggish and Snail-Paced related to
`TraitSpeedModifierSystem`, as it was not applying the reduced movement
speed upon spawning, only when the movement speed has been modified by
another source. `TraitSpeedModifierSystem` has been moved from
`Content.Server` to `Content.Shared`.

This used to be a trait costing 3 points, but is now given for free to
all Dionas per request of @VMSolidus.

## Media

<details><summary>Expand</summary>

**Speed with no items**


![image](https://github.com/user-attachments/assets/b723614a-79fe-401c-ae53-2ad98ff9a6d3)

**Speed wearing a jugsuit, wearing a duffel bag, holding one duffel bag
in each arm, and walking through a puddle of glue covered in spider
webs.**


![image](https://github.com/user-attachments/assets/a934d2c1-437f-463c-8fe3-63b7b54a1f58)

</details>

# Changelog

🆑 Skubman
- add: Dionas have been given a 25% slower movement speed. In exchange
for that, they gain absolute slip immunity and movement speed modifier
immunity. This makes them immune to slowdown from things like
duffelbags, hardsuits, and spider webs.
- fix: Sluggish and Snail-Paced will now properly apply their movement
penalties upon joining.
2024-08-09 13:28:01 -04:00

93 lines
3.4 KiB
C#

using Content.Shared.Inventory;
using Content.Shared.Movement.Components;
using Content.Shared.Traits.Assorted.Components;
using Robust.Shared.Timing;
namespace Content.Shared.Movement.Systems
{
public sealed class MovementSpeedModifierSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _timing = default!;
public void RefreshMovementSpeedModifiers(EntityUid uid, MovementSpeedModifierComponent? move = null)
{
if (!Resolve(uid, ref move, false))
return;
if (_timing.ApplyingState)
return;
var isImmune = false;
if (HasComp<SpeedModifierImmunityComponent>(uid))
isImmune = true;
var ev = new RefreshMovementSpeedModifiersEvent(isImmune);
RaiseLocalEvent(uid, ev);
if (MathHelper.CloseTo(ev.WalkSpeedModifier, move.WalkSpeedModifier) &&
MathHelper.CloseTo(ev.SprintSpeedModifier, move.SprintSpeedModifier))
return;
move.WalkSpeedModifier = ev.WalkSpeedModifier;
move.SprintSpeedModifier = ev.SprintSpeedModifier;
Dirty(uid, move);
}
public void ChangeBaseSpeed(EntityUid uid, float baseWalkSpeed, float baseSprintSpeed, float acceleration, MovementSpeedModifierComponent? move = null)
{
if (!Resolve(uid, ref move, false))
return;
move.BaseWalkSpeed = baseWalkSpeed;
move.BaseSprintSpeed = baseSprintSpeed;
move.Acceleration = acceleration;
Dirty(uid, move);
}
// We might want to create separate RefreshMovementFrictionModifiersEvent and RefreshMovementFrictionModifiers function that will call it
public void ChangeFriction(EntityUid uid, float friction, float? frictionNoInput, float acceleration, MovementSpeedModifierComponent? move = null)
{
if (!Resolve(uid, ref move, false))
return;
move.Friction = friction;
move.FrictionNoInput = frictionNoInput;
move.Acceleration = acceleration;
Dirty(uid, move);
}
}
/// <summary>
/// Raised on an entity to determine its new movement speed. Any system that wishes to change movement speed
/// should hook into this event and set it then. If you want this event to be raised,
/// call <see cref="MovementSpeedModifierSystem.RefreshMovementSpeedModifiers"/>.
/// </summary>
public sealed class RefreshMovementSpeedModifiersEvent : EntityEventArgs, IInventoryRelayEvent
{
public SlotFlags TargetSlots { get; } = ~SlotFlags.POCKET;
public float WalkSpeedModifier { get; private set; } = 1.0f;
public float SprintSpeedModifier { get; private set; } = 1.0f;
/// <summary>
/// Whether this entity is immune to most movement speed modifiers.
/// Bypassable by setting bypassImmunity to true.
/// </summary
private bool IsImmune = false;
public void ModifySpeed(float walk, float sprint, bool bypassImmunity = false)
{
if (IsImmune && !bypassImmunity)
return;
WalkSpeedModifier *= walk;
SprintSpeedModifier *= sprint;
}
public RefreshMovementSpeedModifiersEvent(bool isImmune = false)
{
IsImmune = isImmune;
}
}
}