|
|
|
|
@ -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<uint8_t>(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<int16_t>(NUM_MTYPES); i++) { |
|
|
|
|
const auto &monsterData = MonstersData[i]; |
|
|
|
|
auto monsterLevel = static_cast<uint8_t>(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)); |
|
|
|
|
|
|
|
|
|
|