From 658735fd4509fc3e0be331686399990ee9c73874 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Sun, 23 Aug 2026 09:46:27 -0700 Subject: [PATCH] feat: paragons scale the movement clock by SpeedBuff RunUO had no deliberate paragon movement policy: dividing by 1.2 knocked most speeds off TransformMoveDelay's exact-equality table, so those paragons moved at the raw divided delay (2x+ faster than their transformed base), while 0.3/0.6 creatures landed back on the table (0.25/0.5 are exact in IEEE) for only a ~1.33x buff. This applies the uniform 1.2x the buff always claimed: Convert/UnConvert scale movement overrides alongside the think clock; inheriting values stay inheriting, since they already follow the scaled think values. Co-Authored-By: Claude Fable 5 --- .../Tests/Mobiles/AI/MoveSpeedTests.cs | 12 ++++++++++++ Projects/UOContent/Mobiles/BaseCreature.cs | 17 +++++++++++++++++ Projects/UOContent/Mobiles/Special/Paragon.cs | 2 ++ 3 files changed, 31 insertions(+) diff --git a/Projects/UOContent.Tests/Tests/Mobiles/AI/MoveSpeedTests.cs b/Projects/UOContent.Tests/Tests/Mobiles/AI/MoveSpeedTests.cs index bea4e5396..5fd594ad8 100644 --- a/Projects/UOContent.Tests/Tests/Mobiles/AI/MoveSpeedTests.cs +++ b/Projects/UOContent.Tests/Tests/Mobiles/AI/MoveSpeedTests.cs @@ -112,6 +112,18 @@ public class MoveSpeedTests : IDisposable Assert.Equal(0.9, bc.PassiveMoveSpeed); // other override untouched } + [Fact] + public void ScaleMoveSpeed_ScalesOverrides_LeavesInheritAlone() + { + var bc = NewCreature(); + bc.ActiveMoveSpeed = 0.6; // passive left inheriting + + bc.ScaleMoveSpeed(1.0 / 1.2); + + Assert.Equal(0.5, bc.ActiveMoveSpeed); + Assert.Equal(bc.PassiveSpeed, bc.PassiveMoveSpeed); // still inheriting, not 0 * scalar + } + [Fact] public void Migration_MatchingThinkSpeeds_AdoptTableMoveValues() { diff --git a/Projects/UOContent/Mobiles/BaseCreature.cs b/Projects/UOContent/Mobiles/BaseCreature.cs index 4ca1b9ae2..5e001fdbf 100644 --- a/Projects/UOContent/Mobiles/BaseCreature.cs +++ b/Projects/UOContent/Mobiles/BaseCreature.cs @@ -4674,6 +4674,23 @@ namespace Server.Mobiles _passiveMoveSpeed = 0; } + /// + /// Scales movement overrides (paragon and similar buffs). Inheriting values stay + /// inheriting — they already follow the scaled think clock. + /// + public void ScaleMoveSpeed(double scalar) + { + if (_activeMoveSpeed > 0) + { + _activeMoveSpeed *= scalar; + } + + if (_passiveMoveSpeed > 0) + { + _passiveMoveSpeed *= scalar; + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SetCurrentSpeedToActive() => CurrentSpeed = ActiveSpeed; diff --git a/Projects/UOContent/Mobiles/Special/Paragon.cs b/Projects/UOContent/Mobiles/Special/Paragon.cs index 825609e22..12a21882e 100644 --- a/Projects/UOContent/Mobiles/Special/Paragon.cs +++ b/Projects/UOContent/Mobiles/Special/Paragon.cs @@ -79,6 +79,7 @@ public static class Paragon bc.PassiveSpeed /= SpeedBuff; bc.ActiveSpeed /= SpeedBuff; + bc.ScaleMoveSpeed(1.0 / SpeedBuff); bc.CurrentSpeed = bc.PassiveSpeed; bc.DamageMin += DamageBuff; @@ -143,6 +144,7 @@ public static class Paragon bc.PassiveSpeed *= SpeedBuff; bc.ActiveSpeed *= SpeedBuff; + bc.ScaleMoveSpeed(SpeedBuff); bc.CurrentSpeed = bc.PassiveSpeed; bc.DamageMin -= DamageBuff;