diff --git a/Source/inv.cpp b/Source/inv.cpp index 8143912d0..bf2f89964 100644 --- a/Source/inv.cpp +++ b/Source/inv.cpp @@ -1721,37 +1721,26 @@ void AutoGetItem(int pnum, Item *item, int ii) player.HoldItem._itype = ItemType::None; } -int FindGetItem(int idx, uint16_t ci, int iseed) +int FindGetItem(int32_t iseed, _item_indexes idx, uint16_t createInfo) { - if (ActiveItemCount <= 0) - return -1; - - int ii; - int i = 0; - while (true) { - ii = ActiveItems[i]; - if (Items[ii].IDidx == idx && Items[ii]._iSeed == iseed && Items[ii]._iCreateInfo == ci) - break; - - i++; - - if (i >= ActiveItemCount) - return -1; + for (uint8_t i = 0; i < ActiveItemCount; i++) { + auto &item = Items[ActiveItems[i]]; + if (item.KeyAttributesMatch(iseed, idx, createInfo)) { + return i; + } } - return ii; + return -1; } -void SyncGetItem(Point position, int idx, uint16_t ci, int iseed) +void SyncGetItem(Point position, int32_t iseed, _item_indexes idx, uint16_t ci) { // Check what the local client has at the target position int ii = dItem[position.x][position.y] - 1; if (ii >= 0 && ii < MAXITEMS) { // If there was an item there, check that it's the same item as the remote player has - if (Items[ii].IDidx != idx - || Items[ii]._iSeed != iseed - || Items[ii]._iCreateInfo != ci) { + if (Items[ii].KeyAttributesMatch(iseed, idx, ci)) { // Key attributes don't match so we must've desynced, ignore this index and try find a matching item via lookup ii = -1; } @@ -1759,7 +1748,12 @@ void SyncGetItem(Point position, int idx, uint16_t ci, int iseed) if (ii == -1) { // Either there's no item at the expected position or it doesn't match what is being picked up, so look for an item that matches the key attributes - ii = FindGetItem(idx, ci, iseed); + ii = FindGetItem(iseed, idx, ci); + + if (ii != -1) { + // Translate to Items index for CleanupItems, FindGetItem returns an ActiveItems index + ii = ActiveItems[ii]; + } } if (ii == -1) { diff --git a/Source/inv.h b/Source/inv.h index 7a6ccaf15..5bb3a2cbe 100644 --- a/Source/inv.h +++ b/Source/inv.h @@ -161,8 +161,16 @@ void CheckInvScrn(bool isShiftHeld, bool isCtrlHeld); void CheckItemStats(Player &player); void InvGetItem(int pnum, int ii); void AutoGetItem(int pnum, Item *item, int ii); -int FindGetItem(int idx, uint16_t ci, int iseed); -void SyncGetItem(Point position, int idx, uint16_t ci, int iseed); + +/** + * @brief Searches for a dropped item with the same type/createInfo/seed + * @param iseed The value used to initialise the RNG when generating the item + * @param idx The overarching type of the target item + * @param createInfo Flags used to describe the specific subtype of the target item + * @return An index into ActiveItems or -1 if no matching item was found +*/ +int FindGetItem(int32_t iseed, _item_indexes idx, uint16_t ci); +void SyncGetItem(Point position, int32_t iseed, _item_indexes idx, uint16_t ci); bool CanPut(Point position); bool TryInvPut(); int InvPutItem(Player &player, Point position); diff --git a/Source/items.h b/Source/items.h index ae0bd7e6d..f695ecd2d 100644 --- a/Source/items.h +++ b/Source/items.h @@ -367,7 +367,7 @@ struct Item { return IsScroll() && _iSpell == spellId; } - [[nodiscard]] bool KeyAttributesMatch(int32_t seed, _item_indexes itemIndex, uint16_t createInfo) + [[nodiscard]] bool KeyAttributesMatch(int32_t seed, _item_indexes itemIndex, uint16_t createInfo) const { return _iSeed == seed && IDidx == itemIndex && _iCreateInfo == createInfo; } diff --git a/Source/msg.cpp b/Source/msg.cpp index 67a23ff87..57831b651 100644 --- a/Source/msg.cpp +++ b/Source/msg.cpp @@ -715,14 +715,18 @@ DWORD OnRequestGetItem(const TCmd *pCmd, Player &player) } } - if (ii == -1) { // No item at the target position or the key attributes don't match, so try find a matching item. - ii = FindGetItem(message.wIndx, message.wCI, message.dwSeed); + if (ii == -1) { + // No item at the target position or the key attributes don't match, so try find a matching item. + int activeItemIndex = FindGetItem(message.dwSeed, message.wIndx, message.wCI); + if (activeItemIndex != -1) { + ii = ActiveItems[activeItemIndex]; + } } if (ii != -1) { NetSendCmdGItem2(false, CMD_GETITEM, MyPlayerId, message.bPnum, message); if (message.bPnum != MyPlayerId) - SyncGetItem(position, message.wIndx, message.wCI, message.dwSeed); + SyncGetItem(position, message.dwSeed, message.wIndx, message.wCI); else InvGetItem(MyPlayerId, ii); SetItemRecord(message.dwSeed, message.wCI, message.wIndx); @@ -743,20 +747,20 @@ DWORD OnGetItem(const TCmd *pCmd, int pnum) SendPacket(pnum, &message, sizeof(message)); } else if (IsGItemValid(message)) { const Point position { message.x, message.y }; - int ii = FindGetItem(message.wIndx, message.wCI, message.dwSeed); if (DeltaGetItem(message, message.bLevel)) { if ((currlevel == message.bLevel || message.bPnum == MyPlayerId) && message.bMaster != MyPlayerId) { if (message.bPnum == MyPlayerId) { if (currlevel != message.bLevel) { auto &player = Players[MyPlayerId]; - ii = SyncPutItem(player, player.position.tile, message.wIndx, message.wCI, message.dwSeed, message.bId, message.bDur, message.bMDur, message.bCh, message.bMCh, message.wValue, message.dwBuff, message.wToHit, message.wMaxDam, message.bMinStr, message.bMinMag, message.bMinDex, message.bAC); + int ii = SyncPutItem(player, player.position.tile, message.wIndx, message.wCI, message.dwSeed, message.bId, message.bDur, message.bMDur, message.bCh, message.bMCh, message.wValue, message.dwBuff, message.wToHit, message.wMaxDam, message.bMinStr, message.bMinMag, message.bMinDex, message.bAC); if (ii != -1) InvGetItem(MyPlayerId, ii); } else { - InvGetItem(MyPlayerId, ii); + int activeItemIndex = FindGetItem(message.dwSeed, message.wIndx, message.wCI); + InvGetItem(MyPlayerId, ActiveItems[activeItemIndex]); } } else { - SyncGetItem(position, message.wIndx, message.wCI, message.dwSeed); + SyncGetItem(position, message.dwSeed, message.wIndx, message.wCI); } } } else { @@ -788,11 +792,10 @@ DWORD OnRequestAutoGetItem(const TCmd *pCmd, Player &player) if (gbBufferMsgs != 1 && IOwnLevel(player.plrlevel) && IsGItemValid(message)) { const Point position { message.x, message.y }; if (GetItemRecord(message.dwSeed, message.wCI, message.wIndx)) { - int ii = FindGetItem(message.wIndx, message.wCI, message.dwSeed); - if (ii != -1) { + if (FindGetItem(message.dwSeed, message.wIndx, message.wCI) != -1) { NetSendCmdGItem2(false, CMD_AGETITEM, MyPlayerId, message.bPnum, message); if (message.bPnum != MyPlayerId) - SyncGetItem(position, message.wIndx, message.wCI, message.dwSeed); + SyncGetItem(position, message.dwSeed, message.wIndx, message.wCI); else AutoGetItem(MyPlayerId, &Items[message.bCursitem], message.bCursitem); SetItemRecord(message.dwSeed, message.wCI, message.wIndx); @@ -825,7 +828,7 @@ DWORD OnAutoGetItem(const TCmd *pCmd, int pnum) AutoGetItem(MyPlayerId, &Items[message.bCursitem], message.bCursitem); } } else { - SyncGetItem(position, message.wIndx, message.wCI, message.dwSeed); + SyncGetItem(position, message.dwSeed, message.wIndx, message.wCI); } } } else { @@ -843,10 +846,11 @@ DWORD OnItemExtra(const TCmd *pCmd, int pnum) if (gbBufferMsgs == 1) { SendPacket(pnum, &message, sizeof(message)); } else if (IsGItemValid(message)) { - const Point position { message.x, message.y }; DeltaGetItem(message, message.bLevel); - if (currlevel == Players[pnum].plrlevel) - SyncGetItem(position, message.wIndx, message.wCI, message.dwSeed); + if (currlevel == Players[pnum].plrlevel) { + const Point position { message.x, message.y }; + SyncGetItem(position, message.dwSeed, message.wIndx, message.wCI); + } } return sizeof(message); @@ -2223,14 +2227,15 @@ void DeltaLoadLevel() continue; if (sgLevels[currlevel].item[i].bCmd == CMD_WALKXY) { - int ii = FindGetItem( + int activeItemIndex = FindGetItem( + sgLevels[currlevel].item[i].dwSeed, sgLevels[currlevel].item[i].wIndx, - sgLevels[currlevel].item[i].wCI, - sgLevels[currlevel].item[i].dwSeed); - if (ii != -1) { - if (dItem[Items[ii].position.x][Items[ii].position.y] == ii + 1) - dItem[Items[ii].position.x][Items[ii].position.y] = 0; - DeleteItem(ii, i); + sgLevels[currlevel].item[i].wCI); + if (activeItemIndex != -1) { + const auto &position = Items[ActiveItems[activeItemIndex]].position; + if (dItem[position.x][position.y] == ActiveItems[activeItemIndex] + 1) + dItem[position.x][position.y] = 0; + DeleteItem(ActiveItems[activeItemIndex], activeItemIndex); } } if (sgLevels[currlevel].item[i].bCmd == CMD_ACK_PLRINFO) { diff --git a/Source/msg.h b/Source/msg.h index f01a928aa..1d3652d82 100644 --- a/Source/msg.h +++ b/Source/msg.h @@ -230,7 +230,7 @@ struct TCmdGItem { uint8_t bLevel; uint8_t x; uint8_t y; - uint16_t wIndx; + _item_indexes wIndx; uint16_t wCI; int32_t dwSeed; uint8_t bId; @@ -256,7 +256,7 @@ struct TCmdPItem { _cmd_id bCmd; uint8_t x; uint8_t y; - uint16_t wIndx; + _item_indexes wIndx; uint16_t wCI; /** * Item identifier diff --git a/Source/player.cpp b/Source/player.cpp index f516d4a7f..be6bcb1d3 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -3022,7 +3022,7 @@ StartPlayerKill(int pnum, int earflag) ear._iSeed = player._pName[2] << 24 | player._pName[3] << 16 | player._pName[4] << 8 | player._pName[5]; ear._ivalue = player._pLevel; - if (FindGetItem(IDI_EAR, ear._iCreateInfo, ear._iSeed) == -1) { + if (FindGetItem(ear._iSeed, IDI_EAR, ear._iCreateInfo) == -1) { DeadItem(player, &ear, { 0, 0 }); } } else {