namespace Content.Shared.Movement.Components;
-[NetworkedComponent, RegisterComponent]
-[AutoGenerateComponentState]
-[Access(typeof(SpeedModifierContactsSystem))]
+/// <summary>
+/// Component that modifies the movement speed of other entities that come into contact with the entity this component is added to.
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SpeedModifierContactsSystem))]
public sealed partial class SpeedModifierContactsComponent : Component
{
- [DataField("walkSpeedModifier"), ViewVariables(VVAccess.ReadWrite)]
- [AutoNetworkedField]
+ /// <summary>
+ /// The modifier applied to the walk speed of entities that come into contact with the entity this component is added to.
+ /// </summary>
+ [DataField, AutoNetworkedField]
public float WalkSpeedModifier = 1.0f;
- [AutoNetworkedField]
- [DataField("sprintSpeedModifier"), ViewVariables(VVAccess.ReadWrite)]
+ /// <summary>
+ /// The modifier applied to the sprint speed of entities that come into contact with the entity this component is added to.
+ /// </summary>
+ [DataField, AutoNetworkedField]
public float SprintSpeedModifier = 1.0f;
- [DataField("ignoreWhitelist")]
+ /// <summary>
+ /// Indicates whether this component affects the movement speed of airborne entities that come into contact with the entity this component is added to.
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public bool AffectAirborne;
+
+ /// <summary>
+ /// A whitelist of entities that should be ignored by this component's speed modifiers.
+ /// </summary>
+ [DataField]
public EntityWhitelist? IgnoreWhitelist;
}
using Content.Shared.Inventory;
using Content.Shared.Movement.Components;
using Content.Shared.Movement.Events;
+using Content.Shared.Gravity;
using Content.Shared.Slippery;
using Content.Shared.Whitelist;
using Robust.Shared.Physics.Components;
public sealed class SpeedModifierContactsSystem : EntitySystem
{
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
+ [Dependency] private readonly SharedGravitySystem _gravity = default!;
[Dependency] private readonly MovementSpeedModifierSystem _speedModifierSystem = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
var walkSpeed = 0.0f;
var sprintSpeed = 0.0f;
+ // Cache the result of the airborne check, as it's expensive and independent of contacting entities, hence need only be done once.
+ var isAirborne = physicsComponent.BodyStatus == BodyStatus.InAir || _gravity.IsWeightless(uid, physicsComponent);
+
bool remove = true;
var entries = 0;
foreach (var ent in _physics.GetContactingEntities(uid, physicsComponent))
if (_whitelistSystem.IsWhitelistPass(slowContactsComponent.IgnoreWhitelist, uid))
continue;
+ // Entities that are airborne should not be affected by contact slowdowns that are specified to not affect airborne entities.
+ if (isAirborne && !slowContactsComponent.AffectAirborne)
+ continue;
+
walkSpeed += slowContactsComponent.WalkSpeedModifier;
sprintSpeed += slowContactsComponent.SprintSpeedModifier;
speedModified = true;