From b0e3ab339385713aa2d9be89d1ae7f05c0ed0032 Mon Sep 17 00:00:00 2001
From: 4dplanner <3combined@gmail.com>
Date: Sat, 22 Feb 2020 23:37:56 +0000
Subject: [PATCH] MovementSpeedModifierComponent (#721)
* movement modifier system
* update default exposedata values
* changing base speed marks as dirty
* formatting
* movement speed modifier component
* Moves slowdown component to the prototype
AIController respects slowdown
* reset dirty flag
---
.../Movement/AiControllerComponent.cs | 41 +++++++++--
.../MovementSpeedModifierComponent.cs | 68 +++++++++++++++++++
.../Movement/PlayerInputMoverComponent.cs | 58 +++++++++++++---
.../Movement/ShuttleControllerComponent.cs | 6 +-
.../Components/Nutrition/HungerComponent.cs | 46 +++++++++----
.../Components/Nutrition/ThirstComponent.cs | 46 +++++++++----
.../GameObjects/EntitySystems/MoverSystem.cs | 10 +--
.../Components/Movement/IMoverComponent.cs | 4 +-
Resources/Prototypes/Entities/mobs/human.yml | 1 +
9 files changed, 231 insertions(+), 49 deletions(-)
create mode 100644 Content.Server/GameObjects/Components/Movement/MovementSpeedModifierComponent.cs
diff --git a/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs b/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs
index d48a78b198..755d00dee7 100644
--- a/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs
+++ b/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs
@@ -57,16 +57,49 @@ namespace Content.Server.GameObjects.Components.Movement
}
///
- /// Movement speed (m/s) that the entity walks.
+ /// Movement speed (m/s) that the entity walks, before modifiers
///
[ViewVariables(VVAccess.ReadWrite)]
- public float WalkMoveSpeed { get; set; } = 4.0f;
+ public float BaseWalkSpeed { get; set; } = PlayerInputMoverComponent.DefaultBaseWalkSpeed;
///
- /// Movement speed (m/s) that the entity sprints.
+ /// Movement speed (m/s) that the entity sprints, before modifiers
///
[ViewVariables(VVAccess.ReadWrite)]
- public float SprintMoveSpeed { get; set; } = 10.0f;
+ public float BaseSprintSpeed { get; set; } = PlayerInputMoverComponent.DefaultBaseSprintSpeed;
+
+ ///
+ /// Movement speed (m/s) that the entity walks, after modifiers
+ ///
+ [ViewVariables]
+ public float CurrentWalkSpeed
+ {
+ get
+ {
+ float speed = BaseWalkSpeed;
+ if (Owner.TryGetComponent(out MovementSpeedModifierComponent component))
+ {
+ speed *= component.WalkSpeedModifier;
+ }
+ return speed;
+ }
+ }
+ ///
+ /// Movement speed (m/s) that the entity walks, after modifiers
+ ///
+ [ViewVariables]
+ public float CurrentSprintSpeed
+ {
+ get
+ {
+ float speed = BaseSprintSpeed;
+ if (Owner.TryGetComponent(out MovementSpeedModifierComponent component))
+ {
+ speed *= component.SprintSpeedModifier;
+ }
+ return speed;
+ }
+ }
///
/// Is the entity Sprinting (running)?
diff --git a/Content.Server/GameObjects/Components/Movement/MovementSpeedModifierComponent.cs b/Content.Server/GameObjects/Components/Movement/MovementSpeedModifierComponent.cs
new file mode 100644
index 0000000000..aaa6a38261
--- /dev/null
+++ b/Content.Server/GameObjects/Components/Movement/MovementSpeedModifierComponent.cs
@@ -0,0 +1,68 @@
+
+using Robust.Shared.GameObjects;
+
+namespace Content.Server.GameObjects.Components.Movement
+{
+ [RegisterComponent]
+ public class MovementSpeedModifierComponent : Component
+ {
+ public override string Name => "MovementSpeedModifier";
+
+ private float _cachedWalkSpeedModifier = 1.0f;
+ public float WalkSpeedModifier
+ {
+ get
+ {
+ RecalculateMovementSpeedModifiers();
+ return _cachedWalkSpeedModifier;
+ }
+ }
+ private float _cachedSprintSpeedModifier;
+ public float SprintSpeedModifier
+ {
+ get
+ {
+ RecalculateMovementSpeedModifiers();
+ return _cachedSprintSpeedModifier;
+ }
+ }
+
+ ///
+ /// set to warn us that a component's movespeed modifier has changed
+ ///
+ private bool _movespeedModifiersNeedRefresh = true;
+
+ public void RefreshMovementSpeedModifiers()
+ {
+ _movespeedModifiersNeedRefresh = true;
+ }
+
+ ///
+ /// Recalculate movement speed with current modifiers, or return early if no change
+ ///
+ private void RecalculateMovementSpeedModifiers()
+ {
+ {
+ if (!_movespeedModifiersNeedRefresh)
+ return;
+ var movespeedModifiers = Owner.GetAllComponents();
+ float walkSpeedModifier = 1.0f;
+ float sprintSpeedModifier = 1.0f;
+ foreach (var component in movespeedModifiers)
+ {
+ walkSpeedModifier *= component.WalkSpeedModifier;
+ sprintSpeedModifier *= component.SprintSpeedModifier;
+ }
+ _cachedWalkSpeedModifier = walkSpeedModifier;
+ _cachedSprintSpeedModifier = sprintSpeedModifier;
+ }
+ _movespeedModifiersNeedRefresh = false;
+ }
+ }
+
+ interface IMoveSpeedModifier
+ {
+ float WalkSpeedModifier { get; }
+ float SprintSpeedModifier { get; }
+ }
+}
diff --git a/Content.Server/GameObjects/Components/Movement/PlayerInputMoverComponent.cs b/Content.Server/GameObjects/Components/Movement/PlayerInputMoverComponent.cs
index 3b4708eec4..26d056ac17 100644
--- a/Content.Server/GameObjects/Components/Movement/PlayerInputMoverComponent.cs
+++ b/Content.Server/GameObjects/Components/Movement/PlayerInputMoverComponent.cs
@@ -22,6 +22,8 @@ namespace Content.Server.GameObjects.Components.Movement
[ComponentReference(typeof(IMoverComponent))]
public class PlayerInputMoverComponent : Component, IMoverComponent, ICollideSpecial
{
+ public const float DefaultBaseWalkSpeed = 4.0f;
+ public const float DefaultBaseSprintSpeed = 7.0f;
#pragma warning disable 649
[Dependency] private readonly IConfigurationManager _configurationManager;
@@ -35,17 +37,51 @@ namespace Content.Server.GameObjects.Components.Movement
///
public override string Name => "PlayerInputMover";
- ///
- /// Movement speed (m/s) that the entity walks.
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- public float WalkMoveSpeed { get; set; } = 4.0f;
///
- /// Movement speed (m/s) that the entity sprints.
+ /// Movement speed (m/s) that the entity walks, before modifiers
///
[ViewVariables(VVAccess.ReadWrite)]
- public float SprintMoveSpeed { get; set; } = 7.0f;
+ public float BaseWalkSpeed { get; set; } = DefaultBaseWalkSpeed;
+
+ ///
+ /// Movement speed (m/s) that the entity sprints, before modifiers
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float BaseSprintSpeed { get; set; } = DefaultBaseSprintSpeed;
+
+ ///
+ /// Movement speed (m/s) that the entity walks, after modifiers
+ ///
+ [ViewVariables]
+ public float CurrentWalkSpeed
+ {
+ get
+ {
+ float speed = BaseWalkSpeed;
+ if (Owner.TryGetComponent(out MovementSpeedModifierComponent component))
+ {
+ speed *= component.WalkSpeedModifier;
+ }
+ return speed;
+ }
+ }
+ ///
+ /// Movement speed (m/s) that the entity walks, after modifiers
+ ///
+ [ViewVariables]
+ public float CurrentSprintSpeed
+ {
+ get
+ {
+ float speed = BaseSprintSpeed;
+ if (Owner.TryGetComponent(out MovementSpeedModifierComponent component))
+ {
+ speed *= component.SprintSpeedModifier;
+ }
+ return speed;
+ }
+ }
///
/// Is the entity Sprinting (running)?
@@ -89,13 +125,15 @@ namespace Content.Server.GameObjects.Components.Movement
{
base.ExposeData(serializer);
- serializer.DataReadWriteFunction("wspd", 4.0f, value => WalkMoveSpeed = value, () => WalkMoveSpeed);
- serializer.DataReadWriteFunction("rspd", 10.0f, value => SprintMoveSpeed = value, () => SprintMoveSpeed);
+ //only save the base speeds - the current speeds are transient.
+ serializer.DataReadWriteFunction("wspd", DefaultBaseWalkSpeed, value => BaseWalkSpeed = value, () => BaseWalkSpeed);
+ serializer.DataReadWriteFunction("rspd", DefaultBaseSprintSpeed, value => BaseSprintSpeed = value, () => BaseSprintSpeed);
// The velocity and moving directions is usually set from player or AI input,
// so we don't want to save/load these derived fields.
}
+
///
/// Toggles one of the four cardinal directions. Each of the four directions are
/// composed into a single direction vector, . Enabling
@@ -150,7 +188,7 @@ namespace Content.Server.GameObjects.Components.Movement
///
bool ICollideSpecial.PreventCollide(IPhysBody collidedwith)
{
- // Don't collid with other mobs
+ // Don't collide with other mobs
if (collidedwith.Owner.TryGetComponent(out var collidedSpeciesComponent))
{
return true;
diff --git a/Content.Server/GameObjects/Components/Movement/ShuttleControllerComponent.cs b/Content.Server/GameObjects/Components/Movement/ShuttleControllerComponent.cs
index aa066e4732..82e3a479e4 100644
--- a/Content.Server/GameObjects/Components/Movement/ShuttleControllerComponent.cs
+++ b/Content.Server/GameObjects/Components/Movement/ShuttleControllerComponent.cs
@@ -32,8 +32,8 @@ namespace Content.Server.GameObjects.Components.Movement
public override string Name => "ShuttleController";
[ViewVariables(VVAccess.ReadWrite)]
- public float WalkMoveSpeed { get; set; } = 8;
- public float SprintMoveSpeed { get; set; }
+ public float CurrentWalkSpeed { get; set; } = 8;
+ public float CurrentSprintSpeed { get; set; }
public bool Sprinting { get; set; }
public Vector2 VelocityDir { get; } = Vector2.Zero;
public GridCoordinates LastPosition { get; set; }
@@ -61,7 +61,7 @@ namespace Content.Server.GameObjects.Components.Movement
collideComp.PhysicsShapes.Add(new PhysShapeGrid(grid));
}
- physComp.LinearVelocity = CalcNewVelocity(direction, enabled) * WalkMoveSpeed;
+ physComp.LinearVelocity = CalcNewVelocity(direction, enabled) * CurrentWalkSpeed;
}
}
diff --git a/Content.Server/GameObjects/Components/Nutrition/HungerComponent.cs b/Content.Server/GameObjects/Components/Nutrition/HungerComponent.cs
index 1b3d3cb21f..275384f317 100644
--- a/Content.Server/GameObjects/Components/Nutrition/HungerComponent.cs
+++ b/Content.Server/GameObjects/Components/Nutrition/HungerComponent.cs
@@ -14,11 +14,11 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Nutrition
{
[RegisterComponent]
- public sealed class HungerComponent : Component
+ public sealed class HungerComponent : Component, IMoveSpeedModifier
{
- #pragma warning disable 649
+#pragma warning disable 649
[Dependency] private readonly IRobustRandom _random;
- #pragma warning restore 649
+#pragma warning restore 649
public override string Name => "Hunger";
@@ -33,7 +33,7 @@ namespace Content.Server.GameObjects.Components.Nutrition
private HungerThreshold _currentHungerThreshold;
private HungerThreshold _lastHungerThreshold;
public float CurrentHunger => _currentHunger;
- [ViewVariables] private float _currentHunger;
+ [ViewVariables(VVAccess.ReadWrite)] private float _currentHunger;
public Dictionary HungerThresholds => _hungerThresholds;
private Dictionary _hungerThresholds = new Dictionary
@@ -53,16 +53,15 @@ namespace Content.Server.GameObjects.Components.Nutrition
public void HungerThresholdEffect(bool force = false)
{
- if (_currentHungerThreshold != _lastHungerThreshold || force) {
+ if (_currentHungerThreshold != _lastHungerThreshold || force)
+ {
Logger.InfoS("hunger", $"Updating hunger state for {Owner.Name}");
// Revert slow speed if required
if (_lastHungerThreshold == HungerThreshold.Starving && _currentHungerThreshold != HungerThreshold.Dead &&
- Owner.TryGetComponent(out PlayerInputMoverComponent playerSpeedupComponent))
+ Owner.TryGetComponent(out MovementSpeedModifierComponent movementSlowdownComponent))
{
- // TODO shitcode: Come up something better
- playerSpeedupComponent.WalkMoveSpeed = playerSpeedupComponent.WalkMoveSpeed * 2;
- playerSpeedupComponent.SprintMoveSpeed = playerSpeedupComponent.SprintMoveSpeed * 4;
+ movementSlowdownComponent.RefreshMovementSpeedModifiers();
}
// Update UI
@@ -91,9 +90,9 @@ namespace Content.Server.GameObjects.Components.Nutrition
case HungerThreshold.Starving:
// TODO: If something else bumps this could cause mega-speed.
// If some form of speed update system if multiple things are touching it use that.
- if (Owner.TryGetComponent(out PlayerInputMoverComponent playerInputMoverComponent)) {
- playerInputMoverComponent.WalkMoveSpeed = playerInputMoverComponent.WalkMoveSpeed / 2;
- playerInputMoverComponent.SprintMoveSpeed = playerInputMoverComponent.SprintMoveSpeed / 4;
+ if (Owner.TryGetComponent(out MovementSpeedModifierComponent movementSlowdownComponent1))
+ {
+ movementSlowdownComponent1.RefreshMovementSpeedModifiers();
}
_lastHungerThreshold = _currentHungerThreshold;
_actualDecayRate = _baseDecayRate * 0.6f;
@@ -169,6 +168,29 @@ namespace Content.Server.GameObjects.Components.Nutrition
{
_currentHunger = HungerThresholds[HungerThreshold.Okay];
}
+
+ float IMoveSpeedModifier.WalkSpeedModifier
+ {
+ get
+ {
+ if (_currentHungerThreshold == HungerThreshold.Starving)
+ {
+ return 0.5f;
+ }
+ return 1.0f;
+ }
+ }
+ float IMoveSpeedModifier.SprintSpeedModifier
+ {
+ get
+ {
+ if (_currentHungerThreshold == HungerThreshold.Starving)
+ {
+ return 0.5f;
+ }
+ return 1.0f;
+ }
+ }
}
public enum HungerThreshold
diff --git a/Content.Server/GameObjects/Components/Nutrition/ThirstComponent.cs b/Content.Server/GameObjects/Components/Nutrition/ThirstComponent.cs
index 76b7acf34e..807a52a151 100644
--- a/Content.Server/GameObjects/Components/Nutrition/ThirstComponent.cs
+++ b/Content.Server/GameObjects/Components/Nutrition/ThirstComponent.cs
@@ -14,11 +14,11 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Nutrition
{
[RegisterComponent]
- public sealed class ThirstComponent : Component
+ public sealed class ThirstComponent : Component, IMoveSpeedModifier
{
- #pragma warning disable 649
+#pragma warning disable 649
[Dependency] private readonly IRobustRandom _random;
- #pragma warning restore 649
+#pragma warning restore 649
public override string Name => "Thirst";
@@ -53,16 +53,15 @@ namespace Content.Server.GameObjects.Components.Nutrition
public void ThirstThresholdEffect(bool force = false)
{
- if (_currentThirstThreshold != _lastThirstThreshold || force) {
+ if (_currentThirstThreshold != _lastThirstThreshold || force)
+ {
Logger.InfoS("thirst", $"Updating Thirst state for {Owner.Name}");
// Revert slow speed if required
if (_lastThirstThreshold == ThirstThreshold.Parched && _currentThirstThreshold != ThirstThreshold.Dead &&
- Owner.TryGetComponent(out PlayerInputMoverComponent playerSpeedupComponent))
+ Owner.TryGetComponent(out MovementSpeedModifierComponent movementSlowdownComponent))
{
- // TODO shitcode: Come up something better
- playerSpeedupComponent.WalkMoveSpeed = playerSpeedupComponent.WalkMoveSpeed * 2;
- playerSpeedupComponent.SprintMoveSpeed = playerSpeedupComponent.SprintMoveSpeed * 4;
+ movementSlowdownComponent.RefreshMovementSpeedModifiers();
}
// Update UI
@@ -89,11 +88,9 @@ namespace Content.Server.GameObjects.Components.Nutrition
return;
case ThirstThreshold.Parched:
- // TODO: If something else bumps this could cause mega-speed.
- // If some form of speed update system if multiple things are touching it use that.
- if (Owner.TryGetComponent(out PlayerInputMoverComponent playerInputMoverComponent)) {
- playerInputMoverComponent.WalkMoveSpeed = playerInputMoverComponent.WalkMoveSpeed / 2;
- playerInputMoverComponent.SprintMoveSpeed = playerInputMoverComponent.SprintMoveSpeed / 4;
+ if (Owner.TryGetComponent(out MovementSpeedModifierComponent movementSlowdownComponent1))
+ {
+ movementSlowdownComponent1.RefreshMovementSpeedModifiers();
}
_lastThirstThreshold = _currentThirstThreshold;
_actualDecayRate = _baseDecayRate * 0.6f;
@@ -166,6 +163,29 @@ namespace Content.Server.GameObjects.Components.Nutrition
}
}
+ float IMoveSpeedModifier.SprintSpeedModifier
+ {
+ get
+ {
+ if (_currentThirstThreshold == ThirstThreshold.Parched)
+ {
+ return 0.25f;
+ }
+ return 1.0f;
+ }
+ }
+ float IMoveSpeedModifier.WalkSpeedModifier
+ {
+ get
+ {
+ if (_currentThirstThreshold == ThirstThreshold.Parched)
+ {
+ return 0.5f;
+ }
+ return 1.0f;
+ }
+ }
+
public void ResetThirst()
{
_currentThirst = ThirstThresholds[ThirstThreshold.Okay];
diff --git a/Content.Server/GameObjects/EntitySystems/MoverSystem.cs b/Content.Server/GameObjects/EntitySystems/MoverSystem.cs
index 1530112eaf..a2524b6204 100644
--- a/Content.Server/GameObjects/EntitySystems/MoverSystem.cs
+++ b/Content.Server/GameObjects/EntitySystems/MoverSystem.cs
@@ -90,7 +90,7 @@ namespace Content.Server.GameObjects.EntitySystems
private static void PlayerDetached(PlayerDetachedSystemMessage ev)
{
- if(ev.Entity.HasComponent())
+ if (ev.Entity.HasComponent())
{
ev.Entity.RemoveComponent();
}
@@ -136,7 +136,7 @@ namespace Content.Server.GameObjects.EntitySystems
}
else
{
- physics.LinearVelocity = mover.VelocityDir * (mover.Sprinting ? mover.SprintMoveSpeed : mover.WalkMoveSpeed);
+ physics.LinearVelocity = mover.VelocityDir * (mover.Sprinting ? mover.CurrentSprintSpeed : mover.CurrentWalkSpeed);
transform.LocalRotation = mover.VelocityDir.GetDir().ToAngle();
// Handle footsteps.
@@ -177,7 +177,7 @@ namespace Content.Server.GameObjects.EntitySystems
private static void HandleDirChange(ICommonSession session, Direction dir, bool state)
{
- if(!TryGetAttachedComponent(session as IPlayerSession, out IMoverComponent moverComp))
+ if (!TryGetAttachedComponent(session as IPlayerSession, out IMoverComponent moverComp))
return;
moverComp.SetVelocityDirection(dir, state);
@@ -185,14 +185,14 @@ namespace Content.Server.GameObjects.EntitySystems
private static void HandleRunChange(ICommonSession session, bool running)
{
- if(!TryGetAttachedComponent(session as IPlayerSession, out PlayerInputMoverComponent moverComp))
+ if (!TryGetAttachedComponent(session as IPlayerSession, out PlayerInputMoverComponent moverComp))
return;
moverComp.Sprinting = running;
}
private static bool TryGetAttachedComponent(IPlayerSession session, out T component)
- where T: IComponent
+ where T : IComponent
{
component = default;
diff --git a/Content.Server/Interfaces/GameObjects/Components/Movement/IMoverComponent.cs b/Content.Server/Interfaces/GameObjects/Components/Movement/IMoverComponent.cs
index d1f5cb9597..5e3ed05180 100644
--- a/Content.Server/Interfaces/GameObjects/Components/Movement/IMoverComponent.cs
+++ b/Content.Server/Interfaces/GameObjects/Components/Movement/IMoverComponent.cs
@@ -12,12 +12,12 @@ namespace Content.Server.Interfaces.GameObjects.Components.Movement
///
/// Movement speed (m/s) that the entity walks.
///
- float WalkMoveSpeed { get; set; }
+ float CurrentWalkSpeed { get; }
///
/// Movement speed (m/s) that the entity sprints.
///
- float SprintMoveSpeed { get; set; }
+ float CurrentSprintSpeed { get; }
///
/// Is the entity Sprinting (running)?
diff --git a/Resources/Prototypes/Entities/mobs/human.yml b/Resources/Prototypes/Entities/mobs/human.yml
index e8c810591b..e7b3c9c2c2 100644
--- a/Resources/Prototypes/Entities/mobs/human.yml
+++ b/Resources/Prototypes/Entities/mobs/human.yml
@@ -9,6 +9,7 @@
hands:
- left
- right
+ - type: MovementSpeedModifier
- type: Hunger
- type: Thirst
# Organs