namespace AcDream.Core.Physics; /// /// IWeenieObject implementation for the local player. Provides skill-based /// run rate and jump velocity calculations. /// /// Formulas from decompiled acclient.exe, cross-referenced against /// ACE MovementSystem.GetRunRate and MovementSystem.GetJumpHeight. /// public sealed class PlayerWeenie : IWeenieObject { private int _runSkill; private int _jumpSkill; private float _burden; public PlayerWeenie(int runSkill = 0, int jumpSkill = 0, float burden = 0f) { _runSkill = runSkill; _jumpSkill = jumpSkill; _burden = burden; } public void SetSkills(int runSkill, int jumpSkill) { _runSkill = runSkill; _jumpSkill = jumpSkill; } public void SetBurden(float burden) => _burden = burden; public bool InqRunRate(out float rate) { rate = GetRunRate(_burden, _runSkill); return true; } public bool InqJumpVelocity(float extent, out float vz) { float height = GetJumpHeight(_burden, _jumpSkill, extent); vz = MathF.Sqrt(height * 19.6f); return true; } public bool CanJump(float extent) => true; // burden/stamina checks deferred /// /// RunRate = (burdenMod * (runSkill / (runSkill + 200)) * 11 + 4) / 4 /// Capped at 4.5 when runSkill >= 800. /// Source: decompiled + ACE MovementSystem.GetRunRate /// public static float GetRunRate(float burden, int runSkill) { if (runSkill >= 800) return 18f / 4f; float loadMod = GetBurdenMod(burden); return (loadMod * ((float)runSkill / (runSkill + 200) * 11f) + 4f) / 4f; } /// /// JumpHeight = burdenMod * (jumpSkill / (jumpSkill + 1300) * 22.2 + 0.05) * extent /// Clamped to minimum 0.35m. /// Source: decompiled + ACE MovementSystem.GetJumpHeight /// public static float GetJumpHeight(float burden, int jumpSkill, float extent) { extent = Math.Clamp(extent, 0f, 1f); float loadMod = GetBurdenMod(burden); float height = loadMod * ((float)jumpSkill / (jumpSkill + 1300f) * 22.2f + 0.05f) * extent; return MathF.Max(height, 0.35f); } /// /// Encumbrance modifier: 1.0 when unloaded, linearly decreasing to 0 at 200%. /// Source: decompiled + ACE EncumbranceSystem.GetBurdenMod /// public static float GetBurdenMod(float burden) { if (burden < 1f) return 1f; if (burden < 2f) return 2f - burden; return 0f; } }