diff --git a/Source/msg.cpp b/Source/msg.cpp index c915fffd8..2fc0ae500 100644 --- a/Source/msg.cpp +++ b/Source/msg.cpp @@ -73,6 +73,18 @@ Item ItemLimbo; /** @brief Last sent player command for the local player. */ TCmdLocParam4 lastSentPlayerCmd; +/** @brief Gets a delta level. */ +DLevel &GetDeltaLevel(uint8_t level) +{ + return sgLevels[level]; +} + +/** @brief Gets a delta level. */ +DLevel &GetDeltaLevel(const Player &player) +{ + return GetDeltaLevel(player.plrlevel); +} + /** * @brief Throttles that a player command is only sent once per game tick. * This is a workaround for a desync that happens when a command is processed in different game ticks for different clients. See https://github.com/diasurgical/devilutionX/issues/2681 for details. @@ -362,9 +374,10 @@ void DeltaImportData(_cmd_id cmd, DWORD recvOffset) DeltaImportJunk(src); } else if (cmd >= CMD_DLEVEL_0 && cmd <= CMD_DLEVEL_24) { uint8_t i = cmd - CMD_DLEVEL_0; - src += DeltaImportItem(src, sgLevels[i].item); - src += DeltaImportObject(src, sgLevels[i].object); - DeltaImportMonster(src, sgLevels[i].monster); + DLevel &deltaLevel = GetDeltaLevel(i); + src += DeltaImportItem(src, deltaLevel.item); + src += DeltaImportObject(src, deltaLevel.object); + DeltaImportMonster(src, deltaLevel.monster); } else { app_fatal("Unkown network message type: %i", cmd); } @@ -420,7 +433,7 @@ void DeltaSyncGolem(const TCmdGolem &message, int pnum, uint8_t level) return; sgbDeltaChanged = true; - DMonsterStr &monster = sgLevels[level].monster[pnum]; + DMonsterStr &monster = GetDeltaLevel(level).monster[pnum]; monster._mx = message._mx; monster._my = message._my; monster._mactive = UINT8_MAX; @@ -438,13 +451,15 @@ void DeltaLeaveSync(uint8_t bLevel) return; } + DLevel &deltaLevel = GetDeltaLevel(bLevel); + for (int i = 0; i < ActiveMonsterCount; i++) { int ma = ActiveMonsters[i]; auto &monster = Monsters[ma]; if (monster._mhitpoints == 0) continue; sgbDeltaChanged = true; - DMonsterStr &delta = sgLevels[bLevel].monster[ma]; + DMonsterStr &delta = deltaLevel.monster[ma]; delta._mx = monster.position.tile.x; delta._my = monster.position.tile.y; delta._mdir = monster._mdir; @@ -462,7 +477,7 @@ void DeltaSyncObject(int oi, _cmd_id bCmd, uint8_t bLevel) return; sgbDeltaChanged = true; - sgLevels[bLevel].object[oi].bCmd = bCmd; + GetDeltaLevel(bLevel).object[oi].bCmd = bCmd; } bool DeltaGetItem(const TCmdGItem &message, uint8_t bLevel) @@ -470,7 +485,9 @@ bool DeltaGetItem(const TCmdGItem &message, uint8_t bLevel) if (!gbIsMultiplayer) return true; - for (TCmdPItem &item : sgLevels[bLevel].item) { + DLevel &deltaLevel = GetDeltaLevel(bLevel); + + for (TCmdPItem &item : deltaLevel.item) { if (item.bCmd == CMD_INVALID || item.wIndx != message.wIndx || item.wCI != message.wCI || item.dwSeed != message.dwSeed) continue; @@ -494,7 +511,7 @@ bool DeltaGetItem(const TCmdGItem &message, uint8_t bLevel) if ((message.wCI & CF_PREGEN) == 0) return false; - for (TCmdPItem &item : sgLevels[bLevel].item) { + for (TCmdPItem &item : deltaLevel.item) { if (item.bCmd == CMD_INVALID) { sgbDeltaChanged = true; item.bCmd = TCmdPItem::PickedUpItem; @@ -527,7 +544,9 @@ void DeltaPutItem(const TCmdPItem &message, Point position, uint8_t bLevel) if (!gbIsMultiplayer) return; - for (const TCmdPItem &item : sgLevels[bLevel].item) { + DLevel &deltaLevel = GetDeltaLevel(bLevel); + + for (const TCmdPItem &item : deltaLevel.item) { if (item.bCmd != TCmdPItem::PickedUpItem && item.bCmd != CMD_INVALID && item.wIndx == message.wIndx @@ -539,7 +558,7 @@ void DeltaPutItem(const TCmdPItem &message, Point position, uint8_t bLevel) } } - for (TCmdPItem &item : sgLevels[bLevel].item) { + for (TCmdPItem &item : deltaLevel.item) { if (item.bCmd == CMD_INVALID) { sgbDeltaChanged = true; memcpy(&item, &message, sizeof(TCmdPItem)); @@ -2084,9 +2103,10 @@ void DeltaExportData(int pnum) for (int i = 0; i < NUMLEVELS; i++) { std::unique_ptr dst { new byte[sizeof(DLevel) + 1] }; byte *dstEnd = &dst.get()[1]; - dstEnd = DeltaExportItem(dstEnd, sgLevels[i].item); - dstEnd = DeltaExportObject(dstEnd, sgLevels[i].object); - dstEnd = DeltaExportMonster(dstEnd, sgLevels[i].monster); + DLevel &deltaLevel = sgLevels[i]; + dstEnd = DeltaExportItem(dstEnd, deltaLevel.item); + dstEnd = DeltaExportObject(dstEnd, deltaLevel.object); + dstEnd = DeltaExportMonster(dstEnd, deltaLevel.monster); uint32_t size = CompressData(dst.get(), dstEnd); dthread_send_delta(pnum, static_cast<_cmd_id>(i + CMD_DLEVEL_0), std::move(dst), size); } @@ -2117,7 +2137,7 @@ void delta_kill_monster(int mi, Point position, uint8_t bLevel) return; sgbDeltaChanged = true; - DMonsterStr *pD = &sgLevels[bLevel].monster[mi]; + DMonsterStr *pD = &GetDeltaLevel(bLevel).monster[mi]; pD->_mx = position.x; pD->_my = position.y; pD->_mdir = Monsters[mi]._mdir; @@ -2130,7 +2150,7 @@ void delta_monster_hp(int mi, int hp, uint8_t bLevel) return; sgbDeltaChanged = true; - DMonsterStr *pD = &sgLevels[bLevel].monster[mi]; + DMonsterStr *pD = &GetDeltaLevel(bLevel).monster[mi]; if (pD->_mhitpoints > hp) pD->_mhitpoints = hp; } @@ -2143,7 +2163,7 @@ void delta_sync_monster(const TSyncMonster &monsterSync, uint8_t level) assert(level < NUMLEVELS); sgbDeltaChanged = true; - DMonsterStr &monster = sgLevels[level].monster[monsterSync._mndx]; + DMonsterStr &monster = GetDeltaLevel(level).monster[monsterSync._mndx]; if (monster._mhitpoints == 0) return; @@ -2190,7 +2210,9 @@ void DeltaAddItem(int ii) if (!gbIsMultiplayer) return; - for (const TCmdPItem &item : sgLevels[currlevel].item) { + DLevel &deltaLevel = GetDeltaLevel(currlevel); + + for (const TCmdPItem &item : deltaLevel.item) { if (item.bCmd != CMD_INVALID && item.wIndx == Items[ii].IDidx && item.wCI == Items[ii]._iCreateInfo @@ -2200,7 +2222,7 @@ void DeltaAddItem(int ii) } } - for (TCmdPItem &item : sgLevels[currlevel].item) { + for (TCmdPItem &item : deltaLevel.item) { if (item.bCmd != CMD_INVALID) continue; @@ -2270,23 +2292,24 @@ void DeltaLoadLevel() return; deltaload = true; + DLevel &deltaLevel = GetDeltaLevel(currlevel); if (leveltype != DTYPE_TOWN) { for (int i = 0; i < ActiveMonsterCount; i++) { - if (sgLevels[currlevel].monster[i]._mx == 0xFF) + if (deltaLevel.monster[i]._mx == 0xFF) continue; M_ClearSquares(i); - int x = sgLevels[currlevel].monster[i]._mx; - int y = sgLevels[currlevel].monster[i]._my; + int x = deltaLevel.monster[i]._mx; + int y = deltaLevel.monster[i]._my; auto &monster = Monsters[i]; monster.position.tile = { x, y }; monster.position.old = { x, y }; monster.position.future = { x, y }; - if (sgLevels[currlevel].monster[i]._mhitpoints != -1) { - monster._mhitpoints = sgLevels[currlevel].monster[i]._mhitpoints; - monster.mWhoHit = sgLevels[currlevel].monster[i].mWhoHit; + if (deltaLevel.monster[i]._mhitpoints != -1) { + monster._mhitpoints = deltaLevel.monster[i]._mhitpoints; + monster.mWhoHit = deltaLevel.monster[i].mWhoHit; } - if (sgLevels[currlevel].monster[i]._mhitpoints == 0) { + if (deltaLevel.monster[i]._mhitpoints == 0) { M_ClearSquares(i); if (monster._mAi != AI_DIABLO) { if (monster._uniqtype == 0) { @@ -2299,7 +2322,7 @@ void DeltaLoadLevel() monster._mDelFlag = true; M_UpdateLeader(i); } else { - decode_enemy(monster, sgLevels[currlevel].monster[i]._menemy); + decode_enemy(monster, deltaLevel.monster[i]._menemy); if (monster.position.tile != Point { 0, 0 } && monster.position.tile != GolemHoldingCell) dMonster[monster.position.tile.x][monster.position.tile.y] = i + 1; if (monster.MType->mtype == MT_GOLEM) { @@ -2308,21 +2331,21 @@ void DeltaLoadLevel() } else { M_StartStand(monster, monster._mdir); } - monster._msquelch = sgLevels[currlevel].monster[i]._mactive; + monster._msquelch = deltaLevel.monster[i]._mactive; } } memcpy(AutomapView, &sgLocals[currlevel], sizeof(AutomapView)); } for (int i = 0; i < MAXITEMS; i++) { - if (sgLevels[currlevel].item[i].bCmd == CMD_INVALID) + if (deltaLevel.item[i].bCmd == CMD_INVALID) continue; - if (sgLevels[currlevel].item[i].bCmd == TCmdPItem::PickedUpItem) { + if (deltaLevel.item[i].bCmd == TCmdPItem::PickedUpItem) { int activeItemIndex = FindGetItem( - sgLevels[currlevel].item[i].dwSeed, - sgLevels[currlevel].item[i].wIndx, - sgLevels[currlevel].item[i].wCI); + deltaLevel.item[i].dwSeed, + deltaLevel.item[i].wIndx, + deltaLevel.item[i].wCI); if (activeItemIndex != -1) { const auto &position = Items[ActiveItems[activeItemIndex]].position; if (dItem[position.x][position.y] == ActiveItems[activeItemIndex] + 1) @@ -2330,46 +2353,46 @@ void DeltaLoadLevel() DeleteItem(activeItemIndex); } } - if (sgLevels[currlevel].item[i].bCmd == TCmdPItem::DroppedItem) { + if (deltaLevel.item[i].bCmd == TCmdPItem::DroppedItem) { int ii = AllocateItem(); auto &item = Items[ii]; - if (sgLevels[currlevel].item[i].wIndx == IDI_EAR) { + if (deltaLevel.item[i].wIndx == IDI_EAR) { RecreateEar( item, - sgLevels[currlevel].item[i].wCI, - sgLevels[currlevel].item[i].dwSeed, - sgLevels[currlevel].item[i].bId, - sgLevels[currlevel].item[i].bDur, - sgLevels[currlevel].item[i].bMDur, - sgLevels[currlevel].item[i].bCh, - sgLevels[currlevel].item[i].bMCh, - sgLevels[currlevel].item[i].wValue, - sgLevels[currlevel].item[i].dwBuff); + deltaLevel.item[i].wCI, + deltaLevel.item[i].dwSeed, + deltaLevel.item[i].bId, + deltaLevel.item[i].bDur, + deltaLevel.item[i].bMDur, + deltaLevel.item[i].bCh, + deltaLevel.item[i].bMCh, + deltaLevel.item[i].wValue, + deltaLevel.item[i].dwBuff); } else { RecreateItem( item, - sgLevels[currlevel].item[i].wIndx, - sgLevels[currlevel].item[i].wCI, - sgLevels[currlevel].item[i].dwSeed, - sgLevels[currlevel].item[i].wValue, - (sgLevels[currlevel].item[i].dwBuff & CF_HELLFIRE) != 0); - if (sgLevels[currlevel].item[i].bId != 0) + deltaLevel.item[i].wIndx, + deltaLevel.item[i].wCI, + deltaLevel.item[i].dwSeed, + deltaLevel.item[i].wValue, + (deltaLevel.item[i].dwBuff & CF_HELLFIRE) != 0); + if (deltaLevel.item[i].bId != 0) item._iIdentified = true; - item._iDurability = sgLevels[currlevel].item[i].bDur; - item._iMaxDur = sgLevels[currlevel].item[i].bMDur; - item._iCharges = sgLevels[currlevel].item[i].bCh; - item._iMaxCharges = sgLevels[currlevel].item[i].bMCh; - item._iPLToHit = sgLevels[currlevel].item[i].wToHit; - item._iMaxDam = sgLevels[currlevel].item[i].wMaxDam; - item._iMinStr = sgLevels[currlevel].item[i].bMinStr; - item._iMinMag = sgLevels[currlevel].item[i].bMinMag; - item._iMinDex = sgLevels[currlevel].item[i].bMinDex; - item._iAC = sgLevels[currlevel].item[i].bAC; - item.dwBuff = sgLevels[currlevel].item[i].dwBuff; + item._iDurability = deltaLevel.item[i].bDur; + item._iMaxDur = deltaLevel.item[i].bMDur; + item._iCharges = deltaLevel.item[i].bCh; + item._iMaxCharges = deltaLevel.item[i].bMCh; + item._iPLToHit = deltaLevel.item[i].wToHit; + item._iMaxDam = deltaLevel.item[i].wMaxDam; + item._iMinStr = deltaLevel.item[i].bMinStr; + item._iMinMag = deltaLevel.item[i].bMinMag; + item._iMinDex = deltaLevel.item[i].bMinDex; + item._iAC = deltaLevel.item[i].bAC; + item.dwBuff = deltaLevel.item[i].dwBuff; } - int x = sgLevels[currlevel].item[i].x; - int y = sgLevels[currlevel].item[i].y; + int x = deltaLevel.item[i].x; + int y = deltaLevel.item[i].y; item.position = GetItemPosition({ x, y }); dItem[item.position.x][item.position.y] = ii + 1; RespawnItem(Items[ii], false); @@ -2378,12 +2401,12 @@ void DeltaLoadLevel() if (leveltype != DTYPE_TOWN) { for (int i = 0; i < MAXOBJECTS; i++) { - switch (sgLevels[currlevel].object[i].bCmd) { + switch (deltaLevel.object[i].bCmd) { case CMD_OPENDOOR: case CMD_CLOSEDOOR: case CMD_OPERATEOBJ: case CMD_PLROPOBJ: - SyncOpObject(-1, sgLevels[currlevel].object[i].bCmd, i); + SyncOpObject(-1, deltaLevel.object[i].bCmd, i); break; case CMD_BREAKOBJ: SyncBreakObj(-1, Objects[i]);