--- /dev/null
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Traits.Assorted;
+
+/// <summary>
+/// Used for the Impaired Mobility disability trait.
+/// Applies a base movement speed reduction as determined by the SpeedModifier field.
+/// Also increases the time it takes to stand up after falling, as determined by the StandUpTimeModifier field.
+/// When an entity holds an item with the MobilityAidComponent, the speed penalty is nullified.
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class ImpairedMobilityComponent : Component
+{
+ /// <summary>
+ /// The movement speed modifier applied to the player (0.4 is 40% slower)
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public float SpeedModifier = 0.4f;
+
+ /// <summary>
+ /// The doAfter modifier when getting up after falling (1.4 is 40% slower)
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public float StandUpTimeModifier = 1.4f;
+}
--- /dev/null
+using Content.Shared.Movement.Systems;
+using Content.Shared.Stunnable;
+using Content.Shared.Hands.EntitySystems;
+using Content.Shared.Hands.Components;
+using Content.Shared.Wieldable.Components;
+
+namespace Content.Shared.Traits.Assorted;
+
+/// <summary>
+/// Handles <see cref="ImpairedMobilityComponent"/>
+/// </summary>
+public sealed class ImpairedMobilitySystem : EntitySystem
+{
+ [Dependency] private readonly SharedHandsSystem _hands = default!;
+ [Dependency] private readonly MovementSpeedModifierSystem _speedModifier = default!;
+ public override void Initialize()
+ {
+ SubscribeLocalEvent<ImpairedMobilityComponent, ComponentInit>(OnInit);
+ SubscribeLocalEvent<ImpairedMobilityComponent, ComponentShutdown>(OnShutdown);
+ SubscribeLocalEvent<ImpairedMobilityComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeed);
+ SubscribeLocalEvent<ImpairedMobilityComponent, GetStandUpTimeEvent>(OnGetStandUpTime);
+ }
+
+ private void OnInit(Entity<ImpairedMobilityComponent> ent, ref ComponentInit args)
+ {
+ _speedModifier.RefreshMovementSpeedModifiers(ent);
+ }
+
+ private void OnShutdown(Entity<ImpairedMobilityComponent> ent, ref ComponentShutdown args)
+ {
+ _speedModifier.RefreshMovementSpeedModifiers(ent);
+ }
+
+ // Handles movement speed for entities with impaired mobility.
+ // Applies a speed penalty, but counteracts it if the entity is holding a non-wielded mobility aid.
+ private void OnRefreshMovementSpeed(Entity<ImpairedMobilityComponent> ent, ref RefreshMovementSpeedModifiersEvent args)
+ {
+ if (HasMobilityAid(ent.Owner))
+ return;
+
+ args.ModifySpeed(ent.Comp.SpeedModifier);
+ }
+
+ // Increases the time it takes for entities to stand up from being knocked down.
+ private void OnGetStandUpTime(Entity<ImpairedMobilityComponent> ent, ref GetStandUpTimeEvent args)
+ {
+ args.DoAfterTime *= ent.Comp.StandUpTimeModifier;
+ }
+
+ // Checks if the entity is holding any non-wielded mobility aids.
+ private bool HasMobilityAid(Entity<HandsComponent?> entity)
+ {
+ if (!Resolve(entity, ref entity.Comp, false))
+ return false;
+
+ foreach (var held in _hands.EnumerateHeld(entity))
+ {
+ if (!HasComp<MobilityAidComponent>(held))
+ continue;
+
+ // Makes sure it's not wielded yet
+ if (TryComp<WieldableComponent>(held, out var wieldable) && wieldable.Wielded)
+ continue;
+
+ return true;
+ }
+
+ return false;
+ }
+}
--- /dev/null
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Traits.Assorted;
+
+/// <summary>
+/// Component to mark items that restore normal movement speed when held in-hand for entities with the impaired mobility trait.
+/// The speed is automatically calculated to nullify the entity's speed penalty.
+/// Should be used on items that act as mobility aids, such as canes.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+public sealed partial class MobilityAidComponent : Component;
--- /dev/null
+using Content.Shared.Hands;
+using Content.Shared.Movement.Systems;
+using Content.Shared.Wieldable;
+
+namespace Content.Shared.Traits.Assorted;
+
+/// <summary>
+/// Handles <see cref="MobilityAidComponent"/>
+/// </summary>
+public sealed class MobilityAidSystem : EntitySystem
+{
+ [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!;
+
+ /// <inheritdoc/>
+ public override void Initialize()
+ {
+ SubscribeLocalEvent<MobilityAidComponent, GotEquippedHandEvent>(OnGotEquippedHand);
+ SubscribeLocalEvent<MobilityAidComponent, GotUnequippedHandEvent>(OnGotUnequippedHand);
+ SubscribeLocalEvent<MobilityAidComponent, ItemWieldedEvent>(OnMobilityAidWielded);
+ SubscribeLocalEvent<MobilityAidComponent, ItemUnwieldedEvent>(OnMobilityAidUnwielded);
+ }
+
+ private void OnGotEquippedHand(Entity<MobilityAidComponent> ent, ref GotEquippedHandEvent args)
+ {
+ _movementSpeedModifier.RefreshMovementSpeedModifiers(args.User);
+ }
+
+ private void OnGotUnequippedHand(Entity<MobilityAidComponent> ent, ref GotUnequippedHandEvent args)
+ {
+ _movementSpeedModifier.RefreshMovementSpeedModifiers(args.User);
+ }
+
+ private void OnMobilityAidWielded(Entity<MobilityAidComponent> ent, ref ItemWieldedEvent args)
+ {
+ _movementSpeedModifier.RefreshMovementSpeedModifiers(args.User);
+ }
+
+ private void OnMobilityAidUnwielded(Entity<MobilityAidComponent> ent, ref ItemUnwieldedEvent args)
+ {
+ _movementSpeedModifier.RefreshMovementSpeedModifiers(args.User);
+ }
+}
trait-painnumbness-name = Numb
trait-painnumbness-desc = You lack any sense of feeling pain, being unaware of how hurt you may be.
+
+trait-impaired-mobility-name = Impaired Mobility
+trait-impaired-mobility-desc = You have difficulty moving without a mobility aid.
# traits
- BlackAndWhiteOverlay
- Clumsy
+ - ImpairedMobility
# - LegsParalyzed (you get healed)
- LightweightDrunk
- Muted
size: Normal
sprite: Objects/Weapons/Melee/cane.rsi
- type: Appearance
+ - type: MobilityAid
- type: MeleeWeapon
wideAnimationRotation: 45
damage:
- type: Item
size: Normal
sprite: Objects/Weapons/Melee/offset_canes/standard.rsi
+ - type: MobilityAid
# - type: RandomSprite # Ideally I'd rather these be their own selectable item instead of randomly picked.
# available:
# - color: "#91949C" # standard gray
Blunt: 3
- type: UseDelay
delay: 1
-
category: Disabilities
components:
- type: PainNumbness
+
+- type: trait
+ id: ImpairedMobility
+ name: trait-impaired-mobility-name
+ description: trait-impaired-mobility-desc
+ traitGear: OffsetCane
+ category: Disabilities
+ components:
+ - type: ImpairedMobility