forked from diasurgical/devilutionX
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make invalid items unusable (diasurgical#7506)
- Loading branch information
1 parent
f92ef8e
commit e7d61f2
Showing
14 changed files
with
224 additions
and
153 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
/** | ||
* @file items/validation.cpp | ||
* | ||
* Implementation of functions for validation of player and item data. | ||
*/ | ||
|
||
#include "items/validation.h" | ||
|
||
#include <cstdint> | ||
|
||
#include "items.h" | ||
#include "monstdat.h" | ||
#include "player.h" | ||
|
||
namespace devilution { | ||
|
||
namespace { | ||
|
||
bool hasMultipleFlags(uint16_t flags) | ||
{ | ||
return (flags & (flags - 1)) > 0; | ||
} | ||
|
||
} // namespace | ||
|
||
bool IsCreationFlagComboValid(uint16_t iCreateInfo) | ||
{ | ||
iCreateInfo = iCreateInfo & ~CF_LEVEL; | ||
const bool isTownItem = (iCreateInfo & CF_TOWN) != 0; | ||
const bool isPregenItem = (iCreateInfo & CF_PREGEN) != 0; | ||
const bool isUsefulItem = (iCreateInfo & CF_USEFUL) == CF_USEFUL; | ||
|
||
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)) { | ||
// Items from town can only have 1 towner flag | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
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 <= maxTownItemLevel; | ||
} | ||
|
||
bool IsShopPriceValid(const Item &item) | ||
{ | ||
const int boyPriceLimit = gbIsHellfire ? MaxBoyValueHf : MaxBoyValue; | ||
if ((item._iCreateInfo & CF_BOY) != 0 && item._iIvalue > boyPriceLimit) | ||
return false; | ||
|
||
const uint16_t smithOrWitch = CF_SMITH | CF_SMITHPREMIUM | CF_WITCH; | ||
const int smithAndWitchPriceLimit = gbIsHellfire ? MaxVendorValueHf : MaxVendorValue; | ||
if ((item._iCreateInfo & smithOrWitch) != 0 && item._iIvalue > smithAndWitchPriceLimit) | ||
return false; | ||
|
||
return true; | ||
} | ||
|
||
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 (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; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
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; | ||
} | ||
} | ||
|
||
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 IsItemValid(const Item &item) | ||
{ | ||
if (item.IDidx != IDI_GOLD && !IsCreationFlagComboValid(item._iCreateInfo)) | ||
return false; | ||
|
||
if ((item._iCreateInfo & CF_TOWN) != 0) { | ||
if (!IsTownItemValid(item._iCreateInfo) || !IsShopPriceValid(item)) | ||
return false; | ||
} else if ((item._iCreateInfo & CF_USEFUL) == CF_UPER15) { | ||
if (!IsUniqueMonsterItemValid(item._iCreateInfo, item.dwBuff)) | ||
return false; | ||
} | ||
|
||
if (!IsDungeonItemValid(item._iCreateInfo, item.dwBuff)) | ||
return false; | ||
|
||
return true; | ||
} | ||
|
||
} // namespace devilution |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/** | ||
* @file items/validation.h | ||
* | ||
* Interface of functions for validation of player and item data. | ||
*/ | ||
#pragma once | ||
|
||
#include <cstdint> | ||
|
||
// Forward declared structs to avoid circular dependencies | ||
struct Item; | ||
struct Player; | ||
|
||
namespace devilution { | ||
|
||
bool IsCreationFlagComboValid(uint16_t iCreateInfo); | ||
bool IsTownItemValid(uint16_t iCreateInfo); | ||
bool IsShopPriceValid(const Item &item); | ||
bool IsUniqueMonsterItemValid(uint16_t iCreateInfo, uint32_t dwBuff); | ||
bool IsDungeonItemValid(uint16_t iCreateInfo, uint32_t dwBuff); | ||
bool IsItemValid(const Item &item); | ||
|
||
} // namespace devilution |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.