diff --git a/include/game/entity.hpp b/include/game/entity.hpp index 57147902..a05ff782 100644 --- a/include/game/entity.hpp +++ b/include/game/entity.hpp @@ -135,6 +135,13 @@ public: bool isEntityMoving() const { return isMoving_; } + /// True only during the active interpolation phase (before reaching destination). + /// Unlike isEntityMoving(), this does NOT include the dead-reckoning overrun window, + /// so animations (Run/Walk) should use this to avoid "running in place" after arrival. + bool isActivelyMoving() const { + return isMoving_ && moveElapsed_ < moveDuration_; + } + // Returns the latest server-authoritative position: destination if moving, current if not. // Unlike getX/Y/Z (which only update via updateMovement), this always reflects the // last known server position regardless of distance culling. diff --git a/src/core/application.cpp b/src/core/application.cpp index d26be986..45a97cac 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -1647,7 +1647,11 @@ void Application::update(float deltaTime) { // startMoveTo() in handleMonsterMove, regardless of distance-cull. // This correctly detects movement for distant creatures (> 150u) // where updateMovement() is not called and getX/Y/Z() stays stale. - const bool entityIsMoving = entity->isEntityMoving(); + // Use isActivelyMoving() (not isEntityMoving()) so the + // Run/Walk animation stops when the creature reaches its + // destination, rather than persisting through the dead- + // reckoning overrun window. + const bool entityIsMoving = entity->isActivelyMoving(); const bool isMovingNow = !deadOrCorpse && (entityIsMoving || planarDist > 0.03f || dz > 0.08f); if (deadOrCorpse || largeCorrection) { charRenderer->setInstancePosition(instanceId, renderPos);