From e42fab04c4966714922f56ed86641fe83a51ec72 Mon Sep 17 00:00:00 2001 From: Eric Robinson <68359262+kphoenix137@users.noreply.github.com> Date: Thu, 19 Oct 2023 03:34:09 -0400 Subject: [PATCH] Fix Item Validation (#6723) --- Source/pack.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 6 deletions(-) diff --git a/Source/pack.cpp b/Source/pack.cpp index 85f37c978..3640768a7 100644 --- a/Source/pack.cpp +++ b/Source/pack.cpp @@ -87,12 +87,16 @@ bool IsCreationFlagComboValid(uint16_t iCreateInfo) const bool isPregenItem = (iCreateInfo & CF_PREGEN) != 0; const bool isUsefulItem = (iCreateInfo & CF_USEFUL) == CF_USEFUL; - if (isPregenItem) + if (isPregenItem) { + // Pregen flags are discarded when an item is picked up, therefore impossible to have in the inventory return false; + } if (isUsefulItem && (iCreateInfo & ~CF_USEFUL) != 0) return false; - if (isTownItem && hasMultipleFlags(iCreateInfo)) + if (isTownItem && hasMultipleFlags(iCreateInfo)) { + // Items from town can only have 1 towner flag return false; + } return true; } @@ -100,11 +104,13 @@ bool IsTownItemValid(uint16_t iCreateInfo) { const uint8_t level = iCreateInfo & CF_LEVEL; const bool isBoyItem = (iCreateInfo & CF_BOY) != 0; + const uint8_t maxTownItemLevel = 30; + // Wirt items in multiplayer are equal to the level of the player, therefore they cannot exceed the max character level if (isBoyItem && level <= MaxCharacterLevel) return true; - return level <= 30; + return level <= maxTownItemLevel; } bool IsUniqueMonsterItemValid(uint16_t iCreateInfo, uint32_t dwBuff) @@ -112,16 +118,18 @@ bool IsUniqueMonsterItemValid(uint16_t iCreateInfo, uint32_t dwBuff) const uint8_t level = iCreateInfo & CF_LEVEL; const bool isHellfireItem = (dwBuff & CF_HELLFIRE) != 0; + // Check all unique monster levels to see if they match the item level for (int i = 0; UniqueMonstersData[i].mName != nullptr; i++) { const auto &uniqueMonsterData = UniqueMonstersData[i]; const auto &uniqueMonsterLevel = static_cast(MonstersData[uniqueMonsterData.mtype].level); - if (!isHellfireItem && IsAnyOf(uniqueMonsterData.mtype, MT_HORKDMN, MT_DEFILER, MT_NAKRUL)) { - // These monsters don't appear in Diablo + if (IsAnyOf(uniqueMonsterData.mtype, MT_DEFILER, MT_NAKRUL, MT_HORKDMN)) { + // These monsters don't use their mlvl for item generation continue; } if (level == uniqueMonsterLevel) { + // If the ilvl matches the mlvl, we confirm the item is legitimate return true; } } @@ -134,24 +142,62 @@ bool IsDungeonItemValid(uint16_t iCreateInfo, uint32_t dwBuff) const uint8_t level = iCreateInfo & CF_LEVEL; const bool isHellfireItem = (dwBuff & CF_HELLFIRE) != 0; + // Check all monster levels to see if they match the item level for (int16_t i = 0; i < static_cast(NUM_MTYPES); i++) { const auto &monsterData = MonstersData[i]; auto monsterLevel = static_cast(monsterData.level); if (i != MT_DIABLO && monsterData.availability == MonsterAvailability::Never) { + // Skip monsters that are unable to appear in the game continue; } if (i == MT_DIABLO && !isHellfireItem) { + // Adjust The Dark Lord's mlvl if the item isn't a Hellfire item to match the Diablo mlvl monsterLevel -= 15; } if (level == monsterLevel) { + // If the ilvl matches the mlvl, we confirm the item is legitimate return true; } } - return level <= 30; + if (isHellfireItem) { + uint8_t hellfireMaxDungeonLevel = 24; + + // Hellfire adjusts the currlevel minus 7 in dungeon levels 20-24 for generating items + hellfireMaxDungeonLevel -= 7; + return level <= (hellfireMaxDungeonLevel * 2); + } + + uint8_t diabloMaxDungeonLevel = 16; + + // Diablo doesn't have containers that drop items in dungeon level 16, therefore we decrement by 1 + diabloMaxDungeonLevel--; + return level <= (diabloMaxDungeonLevel * 2); +} + +bool RecreateHellfireSpellBook(const Player &player, const ItemNetPack &packedItem, Item &item) +{ + Item spellBook {}; + RecreateItem(player, packedItem.item, spellBook); + + // Hellfire uses the spell book level when generating items via CreateSpellBook() + int spellBookLevel = GetSpellBookLevel(spellBook._iSpell); + + // CreateSpellBook() adds 1 to the spell level for ilvl + spellBookLevel++; + + if (spellBookLevel >= 1 && (spellBook._iCreateInfo & CF_LEVEL) == spellBookLevel * 2) { + // The ilvl matches the result for a spell book drop, so we confirm the item is legitimate + item = spellBook; + return true; + } + + ValidateFields(spellBook._iCreateInfo, spellBook.dwBuff, IsDungeonItemValid(spellBook._iCreateInfo, spellBook.dwBuff)); + item = spellBook; + return true; } } // namespace @@ -490,6 +536,8 @@ bool UnPackNetItem(const Player &player, const ItemNetPack &packedItem, Item &it ValidateField(creationFlags, IsTownItemValid(creationFlags)); else if ((creationFlags & CF_USEFUL) == CF_UPER15) ValidateFields(creationFlags, dwBuff, IsUniqueMonsterItemValid(creationFlags, dwBuff)); + else if ((dwBuff & CF_HELLFIRE) != 0 && AllItemsList[idx].iMiscId == IMISC_BOOK) + return RecreateHellfireSpellBook(player, packedItem, item); else ValidateFields(creationFlags, dwBuff, IsDungeonItemValid(creationFlags, dwBuff));