diff --git a/src/AcDream.App/Input/PlayerMovementController.cs b/src/AcDream.App/Input/PlayerMovementController.cs
index 469a74f..faa0b7f 100644
--- a/src/AcDream.App/Input/PlayerMovementController.cs
+++ b/src/AcDream.App/Input/PlayerMovementController.cs
@@ -64,8 +64,14 @@ public sealed class PlayerMovementController
public float VerticalVelocity { get; private set; }
public bool IsAirborne { get; private set; }
- public float JumpImpulse { get; set; } = 3.5f; // placeholder; retail scales by Jump skill
- public float GravityAccel { get; set; } = 20f;
+ ///
+ /// Jump velocity Z. AC formula: sqrt(height * 19.6) where
+ /// height = BurdenMod * (JumpSkill / (JumpSkill + 1300) * 22.2 + 0.05) * power.
+ /// For a typical new char (skill=100, burden=50%, power=1.0) ≈ 5.07.
+ ///
+ public float JumpImpulse { get; set; } = 5.0f;
+ /// AC's gravity constant (F_GRAVITY = 9.8 m/s²).
+ public float GravityAccel { get; set; } = 9.8f;
public float AirControlFactor { get; set; } = 0.2f;
///
diff --git a/src/AcDream.App/Rendering/GameWindow.cs b/src/AcDream.App/Rendering/GameWindow.cs
index 833e93c..8bc256f 100644
--- a/src/AcDream.App/Rendering/GameWindow.cs
+++ b/src/AcDream.App/Rendering/GameWindow.cs
@@ -1562,11 +1562,22 @@ public sealed class GameWindow : IDisposable
int observerCx = _liveCenterX;
int observerCy = _liveCenterY;
- if (_liveSession is not null
+ if (_playerMode && _playerController is not null)
+ {
+ // Player mode: follow the physics-resolved player position.
+ // The player walks via the local physics engine; the server
+ // doesn't echo back our autonomous moves, so _lastLivePlayer*
+ // stays at the login position. Compute the landblock from the
+ // controller's current world-space position instead.
+ var pp = _playerController.Position;
+ observerCx = _liveCenterX + (int)System.Math.Floor(pp.X / 192f);
+ observerCy = _liveCenterY + (int)System.Math.Floor(pp.Y / 192f);
+ }
+ else if (_liveSession is not null
&& _liveSession.CurrentState == AcDream.Core.Net.WorldSession.State.InWorld
&& _lastLivePlayerLandblockId is { } lid)
{
- // Live mode: follow the server's last-known player position.
+ // Live mode (fly camera): follow the server's last-known player position.
observerCx = (int)((lid >> 24) & 0xFFu);
observerCy = (int)((lid >> 16) & 0xFFu);
}