diff --git a/Source/cursor.cpp b/Source/cursor.cpp index 99f219ae7..ea626b2ea 100644 --- a/Source/cursor.cpp +++ b/Source/cursor.cpp @@ -276,8 +276,12 @@ void CheckCursMove() // Adjust by player offset and tile grid alignment CalcTileOffset(&xo, &yo); - sx -= ScrollInfo.offset.x - xo; - sy -= ScrollInfo.offset.y - yo; + PlayerStruct *pPlayer = &plr[myplr]; + Point offset = ScrollInfo.offset; + if (pPlayer->IsWalking()) + offset = GetOffsetForWalking(pPlayer->AnimInfo, pPlayer->_pdir, true); + sx -= offset.x - xo; + sy -= offset.y - yo; // Predict the next frame when walking to avoid input jitter fx = plr[myplr].position.offset2.x / 256; diff --git a/Source/scrollrt.cpp b/Source/scrollrt.cpp index 8ffe21e8a..064f2a79b 100644 --- a/Source/scrollrt.cpp +++ b/Source/scrollrt.cpp @@ -124,6 +124,36 @@ const char *const szPlrModeAssert[] = { "quitting" }; +Point GetOffsetForWalking(const AnimationInfo &animationInfo, const direction dir, bool cameraMode /*= false*/) +{ + // clang-format off + // DIR_S, DIR_SW, DIR_W, DIR_NW, DIR_N, DIR_NE, DIR_E, DIR_SE, + constexpr Point startOffset[8] = { { 0, -32 }, { 32, -16 }, { 32, -16 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { -32, -16 }, { -32, -16 } }; + constexpr Point movingOffset[8] = { { 0, 32 }, { -32, 16 }, { -64, 0 }, { -32, -16 }, { 0, -32 }, { 32, -16 }, { 64, 0 }, { 32, 16 } }; + constexpr bool isDiagionalWalk[8] = { false, true, false, true, false, true, false, true }; + // clang-format on + + float fAnimationProgress = animationInfo.GetAnimationProgress(); + Point offset = movingOffset[dir]; + offset *= fAnimationProgress; + + // In diagonal walks the offset for y is smaller then x. + // This means that sometimes x is updated but y not. + // That result in a small stuttering. + // To fix this we disallow odd x as this is the only case where y is not updated. + if (isDiagionalWalk[dir] && ((offset.x % 2) != 0)) { + offset.x -= offset.x > 0 ? 1 : -1; + } + + if (cameraMode) { + offset = -offset; + } else { + offset += startOffset[dir]; + } + + return offset; +} + /** * @brief Clear cursor state */ @@ -677,8 +707,12 @@ static void DrawPlayerHelper(const CelOutputBuffer &out, int x, int y, int sx, i } PlayerStruct *pPlayer = &plr[p]; - int px = sx + pPlayer->position.offset.x - CalculateWidth2(pPlayer->_pAnimWidth); - int py = sy + pPlayer->position.offset.y; + Point offset = ScrollInfo.offset; + if (pPlayer->IsWalking()) { + offset = GetOffsetForWalking(pPlayer->AnimInfo, pPlayer->_pdir); + } + int px = sx + offset.x - CalculateWidth2(pPlayer->_pAnimWidth); + int py = sy + offset.y; DrawPlayer(out, p, x, y, px, py); } @@ -1107,8 +1141,12 @@ static void DrawGame(const CelOutputBuffer &full_out, int x, int y) : full_out.subregionY(0, (gnViewportHeight + 1) / 2); // Adjust by player offset and tile grid alignment - sx = ScrollInfo.offset.x + tileOffsetX; - sy = ScrollInfo.offset.y + tileOffsetY; + PlayerStruct *pPlayer = &plr[myplr]; + Point offset = ScrollInfo.offset; + if (pPlayer->IsWalking()) + offset = GetOffsetForWalking(pPlayer->AnimInfo, pPlayer->_pdir, true); + sx = offset.x + tileOffsetX; + sy = offset.y + tileOffsetY; columns = tileColums; rows = tileRows; diff --git a/Source/scrollrt.h b/Source/scrollrt.h index e76e99c07..1cc30202e 100644 --- a/Source/scrollrt.h +++ b/Source/scrollrt.h @@ -7,6 +7,7 @@ #include +#include "engine/animationinfo.h" #include "engine.h" namespace devilution { @@ -35,6 +36,14 @@ extern bool cel_foliage_active; extern int level_piece_id; extern bool AutoMapShowItems; +/** + * @brief Returns the offset for the walking animation + * @param animationInfo the current active walking animation + * @param dir walking direction + * @param cameraMode Adjusts the offset relative to the camera + */ +Point GetOffsetForWalking(const AnimationInfo &animationInfo, const direction dir, bool cameraMode = false); + void ClearCursor(); void ShiftGrid(int *x, int *y, int horizontal, int vertical); int RowsCoveredByPanel();