diff --git a/Source/multi.cpp b/Source/multi.cpp index 427398fc6..6916fbc24 100644 --- a/Source/multi.cpp +++ b/Source/multi.cpp @@ -114,6 +114,8 @@ static BYTE *multi_recv_packet(TBuffer *pBuf, BYTE *body, DWORD *size) static void NetRecvPlrData(TPkt *pkt) { + plr[myplr].UpdateTargetPosition(); + pkt->hdr.wCheck = LOAD_BE32("\0\0ip"); pkt->hdr.px = plr[myplr]._px; pkt->hdr.py = plr[myplr]._py; diff --git a/Source/player.cpp b/Source/player.cpp index c95eb20b5..5db877d09 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -224,6 +224,24 @@ int PlayerStruct::GetMaximumAttributeValue(CharacterAttribute attribute) const return MaxStats[static_cast(_pClass)][static_cast(attribute)]; } +void PlayerStruct::UpdateTargetPosition() +{ + // clang-format off + int directionOffsetX[8] = { 0,-1, 1, 0,-1, 1, 1,-1 }; + int directionOffsetY[8] = { -1, 0, 0, 1,-1,-1, 1, 1 }; + // clang-format on + _ptargx = _pfutx; + _ptargy = _pfuty; + for (auto step : walkpath) { + if (step == WALK_NONE) + break; + if (step > 0) { + _ptargx += directionOffsetX[step - 1]; + _ptargy += directionOffsetY[step - 1]; + } + } +} + void SetPlayerGPtrs(BYTE *pData, BYTE **pAnim) { int i; @@ -1182,8 +1200,6 @@ void FixPlayerLocation(int pnum, direction bDir) plr[pnum]._pfutx = plr[pnum]._px; plr[pnum]._pfuty = plr[pnum]._py; - plr[pnum]._ptargx = plr[pnum]._px; - plr[pnum]._ptargy = plr[pnum]._py; plr[pnum]._pxoff = 0; plr[pnum]._pyoff = 0; plr[pnum]._pdir = bDir; @@ -3805,8 +3821,6 @@ void MakePlrPath(int pnum, int xx, int yy, bool endspace) app_fatal("MakePlrPath: illegal player %d", pnum); } - plr[pnum]._ptargx = xx; - plr[pnum]._ptargy = yy; if (plr[pnum]._pfutx == xx && plr[pnum]._pfuty == yy) { return; } @@ -3849,9 +3863,6 @@ void MakePlrPath(int pnum, int xx, int yy, bool endspace) yy--; break; } - - plr[pnum]._ptargx = xx; - plr[pnum]._ptargy = yy; } plr[pnum].walkpath[path] = WALK_NONE; diff --git a/Source/player.h b/Source/player.h index 7cc76e773..b553d8d45 100644 --- a/Source/player.h +++ b/Source/player.h @@ -156,12 +156,16 @@ struct PlayerStruct { direction destParam3; int destParam4; int plrlevel; - int _px; // Tile X-position of player - int _py; // Tile Y-position of player - int _pfutx; // Future tile X-position of player. Set at start of walking animation - int _pfuty; // Future tile Y-position of player. Set at start of walking animation - int _ptargx; // Target tile X-position for player movment. Set during pathfinding - int _ptargy; // Target tile Y-position for player movment. Set during pathfinding + int _px; // Tile X-position of player + int _py; // Tile Y-position of player + int _pfutx; // Future tile X-position of player. Set at start of walking animation + int _pfuty; + /* + * These values store the target position for non-local players during network play. + * This is needed because player positions drift over time due to desyncs, so we have + * clients try to pathfind non-local players to this position. + */ + int _ptargx, _ptargy; int _pownerx; // Tile X-position of player. Set via network on player input int _pownery; // Tile X-position of player. Set via network on player input int _poldx; // Most recent X-position in dPlayer. @@ -357,15 +361,20 @@ struct PlayerStruct { * @brief Gets the base value of the player's specified attribute. * @param attribute The attribute to retrieve the base value for * @return The base value for the requested attribute. - */ + */ int GetBaseAttributeValue(CharacterAttribute attribute) const; /** * @brief Gets the maximum value of the player's specified attribute. * @param attribute The attribute to retrieve the maximum value for * @return The maximum value for the requested attribute. - */ + */ int GetMaximumAttributeValue(CharacterAttribute attribute) const; + + /** + * @brief Update tile coordinates a player is moving to (if not moving, then it corresponds to current position). + */ + void UpdateTargetPosition(); }; extern int myplr; diff --git a/Source/track.cpp b/Source/track.cpp index dbabf7de0..091cfeb22 100644 --- a/Source/track.cpp +++ b/Source/track.cpp @@ -28,6 +28,7 @@ void track_process() if (plr[myplr]._pVar8 <= 6 && plr[myplr]._pmode != PM_STAND) return; + plr[myplr].UpdateTargetPosition(); if (cursmx != plr[myplr]._ptargx || cursmy != plr[myplr]._ptargy) { Uint32 tick = SDL_GetTicks(); if ((int)(tick - sgdwLastWalk) >= gnTickDelay * 6) {