Browse Source

Safer access to Item members: _iCreateInfo and dwBuff

pull/8306/head
Eric Robinson 3 months ago
parent
commit
8cd0d78cfe
  1. 4
      Source/inv.cpp
  2. 86
      Source/items.cpp
  3. 74
      Source/items.h
  4. 25
      Source/items/validation.cpp
  5. 12
      Source/loadsave.cpp
  6. 24
      Source/lua/modules/dev/items.cpp
  7. 4
      Source/lua/modules/items.cpp
  8. 10
      Source/msg.cpp
  9. 10
      Source/pack.cpp
  10. 5
      Source/player.cpp
  11. 4
      Source/sync.cpp
  12. 52
      test/pack_test.cpp
  13. 32
      test/vendor_test.cpp

4
Source/inv.cpp

@ -1669,7 +1669,7 @@ void InvGetItem(Player &player, int ii)
if (dItem[item.position.x][item.position.y] == 0)
return;
item._iCreateInfo &= ~CF_PREGEN;
item.clearCreationFlag(CF_PREGEN);
CheckQuestItem(player, item);
item.updateRequiredStatsCacheForPlayer(player);
@ -1740,7 +1740,7 @@ void AutoGetItem(Player &player, Item *itemPointer, int ii)
if (dItem[item.position.x][item.position.y] == 0)
return;
item._iCreateInfo &= ~CF_PREGEN;
item.clearCreationFlag(CF_PREGEN);
CheckQuestItem(player, item);
item.updateRequiredStatsCacheForPlayer(player);

86
Source/items.cpp

@ -468,7 +468,7 @@ void AddInitItems()
GetItemAttrs(item, PickRandomlyAmong({ IDI_MANA, IDI_HEAL }), curlv);
item._iCreateInfo = curlv | CF_PREGEN;
item.setAllCreationFlags(curlv | CF_PREGEN);
SetupItem(item);
item.AnimInfo.currentFrame = static_cast<int8_t>(item.AnimInfo.numberOfFrames - 1);
item._iAnimFlag = false;
@ -1471,7 +1471,7 @@ void GetUniqueItem(const Player &player, Item &item, _unique_items uid)
item._iUid = uid;
item._iMagical = ITEM_QUALITY_UNIQUE;
item._iCreateInfo |= CF_UNIQUE;
item.setCreationFlag(CF_UNIQUE);
}
void ItemRndDur(Item &item)
@ -1555,7 +1555,7 @@ void SetupAllUseful(Item &item, int iseed, int lvl)
}
GetItemAttrs(item, idx, lvl);
item._iCreateInfo = lvl | CF_USEFUL;
item.setAllCreationFlags(lvl | CF_USEFUL);
SetupItem(item);
}
@ -1604,7 +1604,7 @@ void SpawnRock()
item._iPostDraw = true;
item.AnimInfo.currentFrame = 10;
item._iAnimFlag = true;
item._iCreateInfo |= CF_PREGEN;
item.setCreationFlag(CF_PREGEN);
DeltaAddItem(ii);
}
@ -2004,7 +2004,7 @@ void SpawnOnePremium(Item &premiumItem, int plvl, const Player &player)
}
}
}
premiumItem._iCreateInfo = plvl | CF_SMITHPREMIUM;
premiumItem.setAllCreationFlags(plvl | CF_SMITHPREMIUM);
premiumItem._iIdentified = true;
premiumItem._iStatFlag = player.CanUseItem(premiumItem);
}
@ -2084,7 +2084,7 @@ void RecreateSmithItem(const Player &player, Item &item, int lvl, int iseed)
GetItemAttrs(item, itype, lvl);
item._iSeed = iseed;
item._iCreateInfo = lvl | CF_SMITH;
item.setAllCreationFlags(lvl | CF_SMITH);
item._iIdentified = true;
}
@ -2096,7 +2096,7 @@ void RecreatePremiumItem(const Player &player, Item &item, int plvl, int iseed)
GetItemBonus(player, item, plvl / 2, plvl, true, !gbIsHellfire);
item._iSeed = iseed;
item._iCreateInfo = plvl | CF_SMITHPREMIUM;
item.setAllCreationFlags(plvl | CF_SMITHPREMIUM);
item._iIdentified = true;
}
@ -2108,7 +2108,7 @@ void RecreateBoyItem(const Player &player, Item &item, int lvl, int iseed)
GetItemBonus(player, item, lvl, 2 * lvl, true, true);
item._iSeed = iseed;
item._iCreateInfo = lvl | CF_BOY;
item.setAllCreationFlags(lvl | CF_BOY);
item._iIdentified = true;
}
@ -2134,7 +2134,7 @@ void RecreateWitchItem(const Player &player, Item &item, _item_indexes idx, int
}
item._iSeed = iseed;
item._iCreateInfo = lvl | CF_WITCH;
item.setAllCreationFlags(lvl | CF_WITCH);
item._iIdentified = true;
}
@ -2149,7 +2149,7 @@ void RecreateHealerItem(const Player &player, Item &item, _item_indexes idx, int
}
item._iSeed = iseed;
item._iCreateInfo = lvl | CF_HEALER;
item.setAllCreationFlags(lvl | CF_HEALER);
item._iIdentified = true;
}
@ -2214,7 +2214,7 @@ StringOrView GetTranslatedItemName(const Item &item)
{
const auto &baseItemData = AllItemsList[static_cast<size_t>(item.IDidx)];
if (item._iCreateInfo == 0) {
if (item.getAllCreationFlags() == 0) {
return _(baseItemData.iName);
}
if (item._iMiscId == IMISC_BOOK) {
@ -2243,23 +2243,23 @@ std::string GetTranslatedItemNameMagical(const Item &item, bool hellfireItem, bo
std::string identifiedName;
const auto &baseItemData = AllItemsList[static_cast<size_t>(item.IDidx)];
const int lvl = item._iCreateInfo & CF_LEVEL;
const bool onlygood = (item._iCreateInfo & (CF_ONLYGOOD | CF_SMITHPREMIUM | CF_BOY | CF_WITCH)) != 0;
const int lvl = item.getItemLevel();
const bool onlygood = item.hasCreationFlag(CF_ONLYGOOD | CF_SMITHPREMIUM | CF_BOY | CF_WITCH);
const uint32_t currentSeed = GetLCGEngineState();
SetRndSeed(item._iSeed);
int minlvl;
int maxlvl;
if ((item._iCreateInfo & CF_SMITHPREMIUM) != 0) {
if (item.hasCreationFlag(CF_SMITHPREMIUM)) {
DiscardRandomValues(2); // RndVendorItem and GetItemAttrs
minlvl = lvl / 2;
maxlvl = lvl;
} else if ((item._iCreateInfo & CF_BOY) != 0) {
} else if (item.hasCreationFlag(CF_BOY)) {
DiscardRandomValues(2); // RndVendorItem and GetItemAttrs
minlvl = lvl;
maxlvl = lvl * 2;
} else if ((item._iCreateInfo & CF_WITCH) != 0) {
} else if (item.hasCreationFlag(CF_WITCH)) {
DiscardRandomValues(2); // RndVendorItem and GetItemAttrs
int iblvl = -1;
if (GenerateRnd(100) <= 5)
@ -2270,7 +2270,7 @@ std::string GetTranslatedItemNameMagical(const Item &item, bool hellfireItem, bo
maxlvl = iblvl;
} else {
DiscardRandomValues(1); // GetItemAttrs
const int iblvl = GetItemBLevel(lvl, item._iMiscId, onlygood, (item._iCreateInfo & CF_UPER15) != 0);
const int iblvl = GetItemBLevel(lvl, item._iMiscId, onlygood, item.hasCreationFlag(CF_UPER15));
minlvl = iblvl / 2;
maxlvl = iblvl;
DiscardRandomValues(1); // CheckUnique
@ -2299,7 +2299,7 @@ std::string GetTranslatedItemNameMagical(const Item &item, bool hellfireItem, bo
affixItemType = AffixItemType::Armor;
break;
case ItemType::Staff: {
const bool allowspells = !hellfireItem || ((item._iCreateInfo & CF_SMITHPREMIUM) == 0);
const bool allowspells = !hellfireItem || !item.hasCreationFlag(CF_SMITHPREMIUM);
if (!allowspells)
affixItemType = AffixItemType::Staff;
@ -2948,7 +2948,7 @@ void InitializeItem(Item &item, _item_indexes itemData)
item._iMagical = ITEM_QUALITY_NORMAL;
item.IDidx = itemData;
if (gbIsHellfire)
item.dwBuff |= CF_HELLFIRE;
item.setCreationFlag2(CF_HELLFIRE);
}
void GenerateNewSeed(Item &item)
@ -3137,7 +3137,7 @@ void GetItemAttrs(Item &item, _item_indexes itemData, int lvl)
item._iMinDex = baseItemData.iMinDex;
item.IDidx = itemData;
if (gbIsHellfire)
item.dwBuff |= CF_HELLFIRE;
item.setCreationFlag2(CF_HELLFIRE);
item._iPrePower = IPL_INVALID;
item._iSufPower = IPL_INVALID;
@ -3255,17 +3255,17 @@ void SetupAllItems(const Player &player, Item &item, _item_indexes idx, uint32_t
item._iSeed = iseed;
SetRndSeed(iseed);
GetItemAttrs(item, idx, lvl / 2);
item._iCreateInfo = lvl;
item.setAllCreationFlags(lvl);
if (pregen)
item._iCreateInfo |= CF_PREGEN;
item.setCreationFlag(CF_PREGEN);
if (onlygood)
item._iCreateInfo |= CF_ONLYGOOD;
item.setCreationFlag(CF_ONLYGOOD);
if (uper == 15)
item._iCreateInfo |= CF_UPER15;
item.setCreationFlag(CF_UPER15);
else if (uper == 1)
item._iCreateInfo |= CF_UPER1;
item.setCreationFlag(CF_UPER1);
if (item._iMiscId != IMISC_UNIQUE) {
const int iblvl = GetItemBLevel(lvl, item._iMiscId, onlygood, uper == 15);
@ -3299,7 +3299,7 @@ void SetupAllItems(const Player &player, Item &item, _item_indexes idx, uint32_t
void TryRandomUniqueItem(Item &item, _item_indexes idx, int8_t mLevel, int uper, bool onlygood, bool pregen)
{
// If the item is a non-quest unique, find a random valid uid and force generate items to get an item with that uid.
if ((item._iCreateInfo & CF_UNIQUE) == 0 || item._iMiscId == IMISC_UNIQUE)
if (!item.hasCreationFlag(CF_UNIQUE) || item._iMiscId == IMISC_UNIQUE)
return;
SetRndSeed(item._iSeed);
@ -3393,7 +3393,7 @@ void TryRandomUniqueItem(Item &item, _item_indexes idx, int8_t mLevel, int uper,
item = {}; // Reset item data
item.position = itemPos;
SetupAllItems(*MyPlayer, item, idx, seed, mLevel, uper, onlygood, pregen, uidOffset);
item.dwBuff |= (uidOffset << 1) & CF_UIDOFFSET;
item.setCreationFlag2((uidOffset << 1) & CF_UIDOFFSET);
assert(item._iUid == uid);
}
@ -3502,13 +3502,13 @@ void CreateTypeItem(Point position, bool onlygood, ItemType itemType, int imisc,
void RecreateItem(const Player &player, Item &item, _item_indexes idx, uint16_t icreateinfo, uint32_t iseed, int ivalue, uint32_t dwBuff)
{
const bool tmpIsHellfire = gbIsHellfire;
item.dwBuff = dwBuff;
gbIsHellfire = (item.dwBuff & CF_HELLFIRE) != 0;
item.setAllCreationFlags2(dwBuff);
gbIsHellfire = item.hasCreationFlag2(CF_HELLFIRE);
if (idx == IDI_GOLD) {
InitializeItem(item, IDI_GOLD);
item._iSeed = iseed;
item._iCreateInfo = icreateinfo;
item.setAllCreationFlags(icreateinfo);
item._ivalue = ivalue;
SetPlrHandGoldCurs(item);
gbIsHellfire = tmpIsHellfire;
@ -3547,7 +3547,7 @@ void RecreateItem(const Player &player, Item &item, _item_indexes idx, uint16_t
const bool onlygood = (icreateinfo & CF_ONLYGOOD) != 0;
const bool forceNotUnique = (icreateinfo & CF_UNIQUE) == 0;
const bool pregen = (icreateinfo & CF_PREGEN) != 0;
auto uidOffset = static_cast<int>((item.dwBuff & CF_UIDOFFSET) >> 1);
auto uidOffset = static_cast<int>((item.getAllCreationFlags2() & CF_UIDOFFSET) >> 1);
SetupAllItems(player, item, idx, iseed, level, uper, onlygood, pregen, uidOffset, forceNotUnique);
SetupItem(item);
@ -3565,7 +3565,7 @@ void RecreateEar(Item &item, uint16_t ic, uint32_t iseed, uint8_t bCursval, std:
item._iCurs = ((bCursval >> 6) & 3) + ICURS_EAR_SORCERER;
item._ivalue = bCursval & 0x3F;
item._iCreateInfo = ic;
item.setAllCreationFlags(ic);
item._iSeed = iseed;
}
@ -3575,7 +3575,7 @@ void CornerstoneSave()
return;
if (!CornerStone.item.isEmpty()) {
ItemPack id;
PackItem(id, CornerStone.item, (CornerStone.item.dwBuff & CF_HELLFIRE) != 0);
PackItem(id, CornerStone.item, CornerStone.item.hasCreationFlag2(CF_HELLFIRE));
const auto *buffer = reinterpret_cast<uint8_t *>(&id);
for (size_t i = 0; i < sizeof(ItemPack); i++) {
BufCopy(&GetOptions().Hellfire.szItem[i * 2], AsHexPad2(buffer[i], /*uppercase=*/true));
@ -3672,7 +3672,7 @@ void SpawnQuestItem(_item_indexes itemid, Point position, int randarea, Selectio
if (sendmsg)
NetSendCmdPItem(true, CMD_SPAWNITEM, item.position, item);
else {
item._iCreateInfo |= CF_PREGEN;
item.setCreationFlag(CF_PREGEN);
DeltaAddItem(ii);
}
}
@ -4401,7 +4401,7 @@ void SpawnSmith(int lvl)
GetItemAttrs(newItem, itemData, lvl);
} while (newItem._iIvalue > maxValue);
newItem._iCreateInfo = lvl | CF_SMITH;
newItem.setAllCreationFlags(lvl | CF_SMITH);
newItem._iIdentified = true;
SmithItems.push_back(newItem);
@ -4467,7 +4467,7 @@ void SpawnWitch(int lvl)
if (i < PinnedItemCount) {
item._iSeed = AdvanceRndSeed();
GetItemAttrs(item, PinnedItemTypes[i], 1);
item._iCreateInfo = lvl;
item.setAllCreationFlags(lvl);
item._iStatFlag = true;
WitchItems.push_back(item);
continue;
@ -4481,7 +4481,7 @@ void SpawnWitch(int lvl)
SetRndSeed(item._iSeed);
DiscardRandomValues(1);
GetItemAttrs(item, bookType, lvl);
item._iCreateInfo = lvl | CF_WITCH;
item.setAllCreationFlags(lvl | CF_WITCH);
item._iIdentified = true;
bookCount++;
WitchItems.push_back(item);
@ -4505,7 +4505,7 @@ void SpawnWitch(int lvl)
GetItemBonus(*MyPlayer, item, maxlvl / 2, maxlvl, true, true);
} while (item._iIvalue > maxValue);
item._iCreateInfo = lvl | CF_WITCH;
item.setAllCreationFlags(lvl | CF_WITCH);
item._iIdentified = true;
WitchItems.push_back(item);
@ -4625,7 +4625,7 @@ void SpawnBoy(int lvl)
|| BoyItem._iMinDex > dexterity
|| BoyItem._iIvalue < ivalue)
&& count < 250));
BoyItem._iCreateInfo = lvl | CF_BOY;
BoyItem.setAllCreationFlags(lvl | CF_BOY);
BoyItem._iIdentified = true;
BoyItemLevel = lvl / 2;
}
@ -4643,14 +4643,14 @@ void SpawnHealer(int lvl)
if (i < PinnedItemCount || (gbIsMultiplayer && i < NumHealerPinnedItemsMp)) {
item._iSeed = AdvanceRndSeed();
GetItemAttrs(item, PinnedItemTypes[i], 1);
item._iCreateInfo = lvl;
item.setAllCreationFlags(lvl);
item._iStatFlag = true;
} else {
item._iSeed = AdvanceRndSeed();
SetRndSeed(item._iSeed);
const _item_indexes itype = RndHealerItem(*MyPlayer, lvl);
GetItemAttrs(item, itype, lvl);
item._iCreateInfo = lvl | CF_HEALER;
item.setAllCreationFlags(lvl | CF_HEALER);
item._iIdentified = true;
}
@ -5028,7 +5028,7 @@ void UpdateHellfireFlag(Item &item, const char *identifiedItemName)
// But vanilla hellfire items don't have CF_HELLFIRE set in Item::dwBuff
// This functions tries to set this flag for vanilla hellfire items based on the item name
// This ensures that Item::getName() returns the correct translated item name
if ((item.dwBuff & CF_HELLFIRE) != 0U)
if (item.hasCreationFlag2(CF_HELLFIRE))
return; // Item is already a hellfire item
if (item._iMagical != ITEM_QUALITY_MAGIC)
return; // Only magic item's name can differ between diablo and hellfire
@ -5045,7 +5045,7 @@ void UpdateHellfireFlag(Item &item, const char *identifiedItemName)
const std::string hellfireItemNameLong = GetTranslatedItemNameMagical(item, true, false, true);
if (hellfireItemNameShort == identifiedItemName || hellfireItemNameLong == identifiedItemName) {
// This item should be a vanilla hellfire item that has CF_HELLFIRE missing, cause only then the item name matches
item.dwBuff |= CF_HELLFIRE;
item.setCreationFlag2(CF_HELLFIRE);
}
}

74
Source/items.h

@ -188,7 +188,11 @@ struct Player;
struct Item {
/** Randomly generated identifier */
uint32_t _iSeed = 0;
private:
uint16_t _iCreateInfo = 0;
public:
ItemType _itype = ItemType::None;
bool _iAnimFlag = false;
Point position = { 0, 0 };
@ -254,8 +258,11 @@ struct Item {
int8_t _iMinDex = 0;
bool _iStatFlag = false;
ItemSpecialEffectHf _iDamAcFlags = ItemSpecialEffectHf::None;
private:
uint32_t dwBuff = 0;
public:
/**
* @brief Clears this item and returns the old value
*/
@ -466,6 +473,73 @@ struct Item {
{
return { -CalculateSpriteTileCenterX(sprite.width()), 0 };
}
bool hasCreationFlag(uint16_t flag) const
{
return (_iCreateInfo & flag) != 0;
}
bool matchesCreationFlags(uint16_t mask, uint16_t value) const
{
return (_iCreateInfo & mask) == value;
}
void setCreationFlag(uint16_t flag)
{
_iCreateInfo |= flag;
}
void clearCreationFlag(uint16_t flag)
{
_iCreateInfo &= ~flag;
}
void setAllCreationFlags(uint16_t value)
{
_iCreateInfo = value;
}
uint16_t getAllCreationFlags() const
{
return _iCreateInfo;
}
void setItemLevel(uint8_t level)
{
std::min(level, static_cast<uint8_t>(63)); // ilvl is only a 6-bit integer
_iCreateInfo &= ~CF_LEVEL;
_iCreateInfo |= (level & CF_LEVEL);
}
int getItemLevel() const
{
return _iCreateInfo & CF_LEVEL;
}
bool hasCreationFlag2(uint16_t flag) const
{
return (dwBuff & flag) != 0;
}
void setCreationFlag2(uint16_t flag)
{
dwBuff |= flag;
}
void clearCreationFlag2(uint16_t flag)
{
dwBuff &= ~flag;
}
void setAllCreationFlags2(uint16_t value)
{
dwBuff = value;
}
uint16_t getAllCreationFlags2() const
{
return dwBuff;
}
};
struct ItemGetRecordStruct {

25
Source/items/validation.cpp

@ -63,16 +63,15 @@ bool IsTownItemValid(uint16_t iCreateInfo, const Player &player)
bool IsShopPriceValid(const Item &item)
{
const int boyPriceLimit = MaxBoyValue;
if (!gbIsHellfire && (item._iCreateInfo & CF_BOY) != 0 && item._iIvalue > boyPriceLimit)
if (!gbIsHellfire && item.hasCreationFlag(CF_BOY) && item._iIvalue > boyPriceLimit)
return false;
const int premiumPriceLimit = MaxVendorValue;
if (!gbIsHellfire && (item._iCreateInfo & CF_SMITHPREMIUM) != 0 && item._iIvalue > premiumPriceLimit)
if (!gbIsHellfire && item.hasCreationFlag(CF_SMITHPREMIUM) && item._iIvalue > premiumPriceLimit)
return false;
const uint16_t smithOrWitch = CF_SMITH | CF_WITCH;
const int smithAndWitchPriceLimit = gbIsHellfire ? MaxVendorValueHf : MaxVendorValue;
if ((item._iCreateInfo & smithOrWitch) != 0 && item._iIvalue > smithAndWitchPriceLimit)
if ((item.hasCreationFlag(CF_SMITH) || item.hasCreationFlag(CF_WITCH)) && item._iIvalue > smithAndWitchPriceLimit)
return false;
return true;
@ -150,12 +149,12 @@ bool IsHellfireSpellBookValid(const Item &spellBook)
// CreateSpellBook() adds 1 to the spell level for ilvl
spellBookLevel++;
if (spellBookLevel >= 1 && (spellBook._iCreateInfo & CF_LEVEL) == spellBookLevel * 2) {
if (spellBookLevel >= 1 && spellBook.getItemLevel() == spellBookLevel * 2) {
// The ilvl matches the result for a spell book drop, so we confirm the item is legitimate
return true;
}
return IsDungeonItemValid(spellBook._iCreateInfo, spellBook.dwBuff);
return IsDungeonItemValid(spellBook.getAllCreationFlags(), spellBook.getAllCreationFlags2());
}
bool IsItemValid(const Player &player, const Item &item)
@ -165,16 +164,16 @@ bool IsItemValid(const Player &player, const Item &item)
if (item.IDidx == IDI_EAR)
return true;
if (item.IDidx != IDI_GOLD && !IsCreationFlagComboValid(item._iCreateInfo))
if (item.IDidx != IDI_GOLD && !IsCreationFlagComboValid(item.getAllCreationFlags()))
return false;
if ((item._iCreateInfo & CF_TOWN) != 0)
return IsTownItemValid(item._iCreateInfo, player) && IsShopPriceValid(item);
if ((item._iCreateInfo & CF_USEFUL) == CF_UPER15)
return IsUniqueMonsterItemValid(item._iCreateInfo, item.dwBuff);
if ((item.dwBuff & CF_HELLFIRE) != 0 && AllItemsList[item.IDidx].iMiscId == IMISC_BOOK)
if (item.hasCreationFlag(CF_TOWN))
return IsTownItemValid(item.getAllCreationFlags(), player) && IsShopPriceValid(item);
if (item.matchesCreationFlags(CF_USEFUL, CF_UPER15))
return IsUniqueMonsterItemValid(item.getAllCreationFlags(), item.getAllCreationFlags2());
if (item.hasCreationFlag2(CF_HELLFIRE) && AllItemsList[item.IDidx].iMiscId == IMISC_BOOK)
return IsHellfireSpellBookValid(item);
return IsDungeonItemValid(item._iCreateInfo, item.dwBuff);
return IsDungeonItemValid(item.getAllCreationFlags(), item.getAllCreationFlags2());
}
bool IsItemDeltaValid(const TCmdPItem &itemDelta)

12
Source/loadsave.cpp

@ -268,7 +268,7 @@ struct LevelConversionData {
[[nodiscard]] bool LoadItemData(LoadHelper &file, Item &item)
{
item._iSeed = file.NextLE<uint32_t>();
item._iCreateInfo = file.NextLE<uint16_t>();
item.setAllCreationFlags(file.NextLE<uint16_t>());
file.Skip(2); // Alignment
item._itype = static_cast<ItemType>(file.NextLE<uint32_t>());
item.position.x = file.NextLE<int32_t>();
@ -369,7 +369,7 @@ struct LevelConversionData {
const _item_indexes itemIndex = static_cast<_item_indexes>(findIt->second);
item.IDidx = itemIndex;
item.dwBuff = file.NextLE<uint32_t>();
item.setAllCreationFlags2(file.NextLE<uint32_t>());
if (gbIsHellfireSaveGame)
item._iDamAcFlags = static_cast<ItemSpecialEffectHf>(file.NextLE<uint32_t>());
else
@ -1096,9 +1096,9 @@ void LoadMatchingItems(LoadHelper &file, const Player &player, const int n, Item
if (gbIsMultiplayer) {
// Ensure that the unpacked item was regenerated using the appropriate
// game's item generation logic before attempting to use it for validation
if ((heroItem.dwBuff & CF_HELLFIRE) != (unpackedItem.dwBuff & CF_HELLFIRE)) {
if (heroItem.hasCreationFlag2(CF_HELLFIRE) != unpackedItem.hasCreationFlag2(CF_HELLFIRE)) {
unpackedItem = {};
RecreateItem(player, unpackedItem, heroItem.IDidx, heroItem._iCreateInfo, heroItem._iSeed, heroItem._ivalue, heroItem.dwBuff);
RecreateItem(player, unpackedItem, heroItem.IDidx, heroItem.getAllCreationFlags(), heroItem._iSeed, heroItem._ivalue, heroItem.getAllCreationFlags2());
unpackedItem._iIdentified = heroItem._iIdentified;
unpackedItem._iMaxDur = heroItem._iMaxDur;
unpackedItem._iDurability = ClampDurability(unpackedItem, heroItem._iDurability);
@ -1169,7 +1169,7 @@ void SaveItem(SaveHelper &file, const Item &item)
}
file.WriteLE<uint32_t>(item._iSeed);
file.WriteLE<int16_t>(item._iCreateInfo);
file.WriteLE<int16_t>(item.getAllCreationFlags());
file.Skip(2); // Alignment
file.WriteLE<int32_t>(static_cast<int32_t>(iType));
file.WriteLE<int32_t>(item.position.x);
@ -1243,7 +1243,7 @@ void SaveItem(SaveHelper &file, const Item &item)
file.Skip(1); // Alignment
file.WriteLE<uint32_t>(item._iStatFlag ? 1 : 0);
file.WriteLE<int32_t>(idx);
file.WriteLE<uint32_t>(item.dwBuff);
file.WriteLE<uint32_t>(item.getAllCreationFlags2());
if (gbIsHellfire)
file.WriteLE<uint32_t>(static_cast<uint32_t>(item._iDamAcFlags));
}

24
Source/lua/modules/dev/items.cpp

@ -54,18 +54,18 @@ std::string DebugCmdItemInfo()
return StrCat("Name: ", pItem->_iIName,
"\nIDidx: ", pItem->IDidx, " (", AllItemsList[pItem->IDidx].iName, ")",
"\nSeed: ", pItem->_iSeed,
"\nCreateInfo: ", pItem->_iCreateInfo,
"\nLevel: ", pItem->_iCreateInfo & CF_LEVEL,
"\nOnly Good: ", ((pItem->_iCreateInfo & CF_ONLYGOOD) == 0) ? "False" : "True",
"\nUnique Monster: ", ((pItem->_iCreateInfo & CF_UPER15) == 0) ? "False" : "True",
"\nDungeon Item: ", ((pItem->_iCreateInfo & CF_UPER1) == 0) ? "False" : "True",
"\nUnique Item: ", ((pItem->_iCreateInfo & CF_UNIQUE) == 0) ? "False" : "True",
"\nSmith: ", ((pItem->_iCreateInfo & CF_SMITH) == 0) ? "False" : "True",
"\nSmith Premium: ", ((pItem->_iCreateInfo & CF_SMITHPREMIUM) == 0) ? "False" : "True",
"\nBoy: ", ((pItem->_iCreateInfo & CF_BOY) == 0) ? "False" : "True",
"\nWitch: ", ((pItem->_iCreateInfo & CF_WITCH) == 0) ? "False" : "True",
"\nHealer: ", ((pItem->_iCreateInfo & CF_HEALER) == 0) ? "False" : "True",
"\nPregen: ", ((pItem->_iCreateInfo & CF_PREGEN) == 0) ? "False" : "True",
"\nCreateInfo: ", pItem->getAllCreationFlags(),
"\nLevel: ", pItem->getItemLevel(),
"\nOnly Good: ", pItem->hasCreationFlag(CF_ONLYGOOD) ? "False" : "True",
"\nUnique Monster: ", pItem->hasCreationFlag(CF_UPER15) ? "False" : "True",
"\nDungeon Item: ", pItem->hasCreationFlag(CF_UPER1) ? "False" : "True",
"\nUnique Item: ", pItem->hasCreationFlag(CF_UNIQUE) ? "False" : "True",
"\nSmith: ", pItem->hasCreationFlag(CF_SMITH) ? "False" : "True",
"\nSmith Premium: ", pItem->hasCreationFlag(CF_SMITHPREMIUM) ? "False" : "True",
"\nBoy: ", pItem->hasCreationFlag(CF_BOY) ? "False" : "True",
"\nWitch: ", pItem->hasCreationFlag(CF_WITCH) ? "False" : "True",
"\nHealer: ", pItem->hasCreationFlag(CF_HEALER) ? "False" : "True",
"\nPregen: ", pItem->hasCreationFlag(CF_PREGEN) ? "False" : "True",
"\nNet Validation: ", netPackValidation);
}
return StrCat("Num items: ", ActiveItemCount);

4
Source/lua/modules/items.cpp

@ -23,7 +23,7 @@ void InitItemUserType(sol::state_view &lua)
// Member variables
LuaSetDocProperty(itemType, "seed", "number", "Randomly generated identifier", &Item::_iSeed);
LuaSetDocProperty(itemType, "createInfo", "number", "Creation flags", &Item::_iCreateInfo);
LuaSetDocProperty(itemType, "createInfo", "number", "Creation flags", &Item::getAllCreationFlags);
LuaSetDocProperty(itemType, "type", "ItemType", "Item type", &Item::_itype);
LuaSetDocProperty(itemType, "animFlag", "boolean", "Animation flag", &Item::_iAnimFlag);
LuaSetDocProperty(itemType, "position", "Point", "Item world position", &Item::position);
@ -86,7 +86,7 @@ void InitItemUserType(sol::state_view &lua)
LuaSetDocProperty(itemType, "minDex", "number", "Minimum dexterity required", &Item::_iMinDex);
LuaSetDocProperty(itemType, "statFlag", "boolean", "Equippable flag", &Item::_iStatFlag);
LuaSetDocProperty(itemType, "damAcFlags", "ItemSpecialEffectHf", "Secondary special effect flags", &Item::_iDamAcFlags);
LuaSetDocProperty(itemType, "buff", "number", "Secondary creation flags", &Item::dwBuff);
LuaSetDocProperty(itemType, "buff", "number", "Secondary creation flags", &Item::getAllCreationFlags2);
// Member functions
LuaSetDocFn(itemType, "pop", "() -> Item", "Clears this item and returns the old value", &Item::pop);

10
Source/msg.cpp

@ -1313,7 +1313,7 @@ bool IsPItemValid(const TCmdPItem &message, const Player &player)
void PrepareItemForNetwork(const Item &item, TCmdGItem &message)
{
message.def.wIndx = static_cast<_item_indexes>(Swap16LE(item.IDidx));
message.def.wCI = Swap16LE(item._iCreateInfo);
message.def.wCI = Swap16LE(item.getAllCreationFlags());
message.def.dwSeed = Swap32LE(item._iSeed);
if (item.IDidx == IDI_EAR)
@ -1325,7 +1325,7 @@ void PrepareItemForNetwork(const Item &item, TCmdGItem &message)
void PrepareItemForNetwork(const Item &item, TCmdPItem &message)
{
message.def.wIndx = static_cast<_item_indexes>(Swap16LE(item.IDidx));
message.def.wCI = Swap16LE(item._iCreateInfo);
message.def.wCI = Swap16LE(item.getAllCreationFlags());
message.def.dwSeed = Swap32LE(item._iSeed);
if (item.IDidx == IDI_EAR)
@ -1337,7 +1337,7 @@ void PrepareItemForNetwork(const Item &item, TCmdPItem &message)
void PrepareItemForNetwork(const Item &item, TCmdChItem &message)
{
message.def.wIndx = static_cast<_item_indexes>(Swap16LE(item.IDidx));
message.def.wCI = Swap16LE(item._iCreateInfo);
message.def.wCI = Swap16LE(item.getAllCreationFlags());
message.def.dwSeed = Swap32LE(item._iSeed);
if (item.IDidx == IDI_EAR)
@ -2662,7 +2662,7 @@ void PrepareItemForNetwork(const Item &item, TItem &messageItem)
messageItem.wValue = Swap16LE(item._ivalue);
messageItem.wToHit = Swap16LE(item._iPLToHit);
messageItem.wMaxDam = Swap16LE(item._iMaxDam);
messageItem.dwBuff = Swap32LE(item.dwBuff);
messageItem.dwBuff = Swap32LE(item.getAllCreationFlags2());
}
void PrepareEarForNetwork(const Item &item, TEar &ear)
@ -2876,7 +2876,7 @@ void DeltaAddItem(int ii)
for (const TCmdPItem &item : deltaLevel.item) {
if (item.bCmd != CMD_INVALID
&& static_cast<_item_indexes>(Swap16LE(item.def.wIndx)) == Items[ii].IDidx
&& Swap16LE(item.def.wCI) == Items[ii]._iCreateInfo
&& Swap16LE(item.def.wCI) == Items[ii].getAllCreationFlags()
&& static_cast<uint32_t>(Swap32LE(item.def.dwSeed)) == Items[ii]._iSeed
&& IsAnyOf(item.bCmd, TCmdPItem::PickedUpItem, TCmdPItem::FloorItem)) {
return;

10
Source/pack.cpp

@ -91,14 +91,14 @@ bool RecreateHellfireSpellBook(const Player &player, const TItem &packedItem, It
// CreateSpellBook() adds 1 to the spell level for ilvl
spellBookLevel++;
if (spellBookLevel >= 1 && (spellBook._iCreateInfo & CF_LEVEL) == spellBookLevel * 2) {
if (spellBookLevel >= 1 && spellBook.getItemLevel() == spellBookLevel * 2) {
// The ilvl matches the result for a spell book drop, so we confirm the item is legitimate
if (item != nullptr)
*item = spellBook;
return true;
}
ValidateFields(spellBook._iCreateInfo, spellBook.dwBuff, IsDungeonItemValid(spellBook._iCreateInfo, spellBook.dwBuff));
ValidateFields(spellBook.getAllCreationFlags(), spellBook.getAllCreationFlags2(), IsDungeonItemValid(spellBook.getAllCreationFlags(), spellBook.getAllCreationFlags2()));
if (item != nullptr)
*item = spellBook;
return true;
@ -131,7 +131,7 @@ void PackItem(ItemPack &packedItem, const Item &item, bool isHellfire)
packedItem.dwBuff = Swap32LE(LoadBE32(&item._iIName[12]));
} else {
packedItem.iSeed = Swap32LE(item._iSeed);
packedItem.iCreateInfo = Swap16LE(item._iCreateInfo);
packedItem.iCreateInfo = Swap16LE(item.getAllCreationFlags());
packedItem.bId = (item._iMagical << 1) | (item._iIdentified ? 1 : 0);
if (item._iMaxDur > 255)
packedItem.bMDur = 254;
@ -143,7 +143,7 @@ void PackItem(ItemPack &packedItem, const Item &item, bool isHellfire)
packedItem.bMCh = item._iMaxCharges;
if (item.IDidx == IDI_GOLD)
packedItem.wValue = Swap16LE(item._ivalue);
packedItem.dwBuff = item.dwBuff;
packedItem.dwBuff = item.getAllCreationFlags2();
}
}
}
@ -208,7 +208,7 @@ void PackNetItem(const Item &item, ItemNetPack &packedItem)
return;
}
packedItem.def.wIndx = static_cast<_item_indexes>(Swap16LE(item.IDidx));
packedItem.def.wCI = Swap16LE(item._iCreateInfo);
packedItem.def.wCI = Swap16LE(item.getAllCreationFlags());
packedItem.def.dwSeed = Swap32LE(item._iSeed);
if (item.IDidx != IDI_EAR)
PrepareItemForNetwork(item, packedItem.item);

5
Source/player.cpp

@ -2767,11 +2767,12 @@ StartPlayerKill(Player &player, DeathReason deathReason)
break;
}
ear._iCreateInfo = player._pName[0] << 8 | player._pName[1];
// This is a hack that uses creation bits, seed, and value as characters for storing the name of the player.
ear.setAllCreationFlags(player._pName[0] << 8 | player._pName[1]);
ear._iSeed = player._pName[2] << 24 | player._pName[3] << 16 | player._pName[4] << 8 | player._pName[5];
ear._ivalue = player.getCharacterLevel();
if (FindGetItem(ear._iSeed, IDI_EAR, ear._iCreateInfo) == -1) {
if (FindGetItem(ear._iSeed, IDI_EAR, ear.getAllCreationFlags()) == -1) {
DeadItem(player, std::move(ear), { 0, 0 });
}
}

4
Source/sync.cpp

@ -124,7 +124,7 @@ void SyncPlrInv(TSyncHeader *pHdr)
pHdr->wItemVal = Swap16LE((item._iIName[11] << 8) | ((item._iCurs - ICURS_EAR_SORCERER) << 6) | item._ivalue);
pHdr->dwItemBuff = Swap32LE((item._iIName[12] << 24) | (item._iIName[13] << 16) | (item._iIName[14] << 8) | item._iIName[15]);
} else {
pHdr->wItemCI = Swap16LE(item._iCreateInfo);
pHdr->wItemCI = Swap16LE(item.getAllCreationFlags());
pHdr->dwItemSeed = Swap32LE(item._iSeed);
pHdr->bItemId = item._iIdentified ? 1 : 0;
pHdr->bItemDur = item._iDurability;
@ -143,7 +143,7 @@ void SyncPlrInv(TSyncHeader *pHdr)
if (!item.isEmpty()) {
pHdr->bPInvLoc = sgnSyncPInv;
pHdr->wPInvIndx = Swap16LE(item.IDidx);
pHdr->wPInvCI = Swap16LE(item._iCreateInfo);
pHdr->wPInvCI = Swap16LE(item.getAllCreationFlags());
pHdr->dwPInvSeed = Swap32LE(item._iSeed);
pHdr->bPInvId = item._iIdentified ? 1 : 0;
}

52
test/pack_test.cpp

@ -1335,10 +1335,10 @@ TEST_F(NetPackTest, UnPackNetPlayer_invalid_pregenItemFlags)
continue;
if (IsAnyOf(item.IDidx, IDI_GOLD, IDI_EAR))
continue;
const uint16_t createInfo = item._iCreateInfo;
item._iCreateInfo |= CF_PREGEN;
const uint16_t createInfo = item.getAllCreationFlags();
item.setCreationFlag(CF_PREGEN);
ASSERT_FALSE(TestNetPackValidation());
item._iCreateInfo = createInfo;
item.setAllCreationFlags(createInfo);
count++;
}
ASSERT_GT(count, 0);
@ -1353,12 +1353,12 @@ TEST_F(NetPackTest, UnPackNetPlayer_invalid_usefulItemFlags)
continue;
if (IsAnyOf(item.IDidx, IDI_GOLD, IDI_EAR))
continue;
if ((item._iCreateInfo & CF_USEFUL) != CF_USEFUL)
if (!item.matchesCreationFlags(CF_USEFUL, CF_USEFUL))
continue;
const uint16_t createInfo = item._iCreateInfo;
item._iCreateInfo |= CF_ONLYGOOD;
const uint16_t createInfo = item.getAllCreationFlags();
item.setCreationFlag(CF_ONLYGOOD);
ASSERT_FALSE(TestNetPackValidation());
item._iCreateInfo = createInfo;
item.setAllCreationFlags(createInfo);
count++;
}
ASSERT_GT(count, 0);
@ -1373,12 +1373,12 @@ TEST_F(NetPackTest, UnPackNetPlayer_invalid_townItemFlags)
continue;
if (IsAnyOf(item.IDidx, IDI_GOLD, IDI_EAR))
continue;
if ((item._iCreateInfo & CF_TOWN) == 0)
if (!item.hasCreationFlag(CF_TOWN))
continue;
const uint16_t createInfo = item._iCreateInfo;
item._iCreateInfo |= CF_ONLYGOOD;
const uint16_t createInfo = item.getAllCreationFlags();
item.setCreationFlag(CF_ONLYGOOD);
ASSERT_FALSE(TestNetPackValidation());
item._iCreateInfo = createInfo;
item.setAllCreationFlags(createInfo);
count++;
}
ASSERT_GT(count, 0);
@ -1394,14 +1394,14 @@ TEST_F(NetPackTest, UnPackNetPlayer_invalid_townItemLevel)
continue;
if (IsAnyOf(item.IDidx, IDI_GOLD, IDI_EAR))
continue;
if ((item._iCreateInfo & CF_TOWN) == 0)
if (!item.hasCreationFlag(CF_TOWN))
continue;
const uint16_t createInfo = item._iCreateInfo;
const bool BoyItem = (item._iCreateInfo & CF_BOY) != 0;
item._iCreateInfo &= ~CF_LEVEL;
item._iCreateInfo |= BoyItem ? MyPlayer->getMaxCharacterLevel() + 1 : 31;
const uint16_t createInfo = item.getAllCreationFlags();
const bool BoyItem = item.hasCreationFlag(CF_BOY);
item.clearCreationFlag(CF_LEVEL);
item.setCreationFlag(BoyItem ? MyPlayer->getMaxCharacterLevel() + 1 : 31);
ASSERT_FALSE(TestNetPackValidation());
item._iCreateInfo = createInfo;
item.setAllCreationFlags(createInfo);
size_t &count = BoyItem ? boyCount : otherCount;
count++;
@ -1419,13 +1419,12 @@ TEST_F(NetPackTest, UnPackNetPlayer_invalid_uniqueMonsterItemLevel)
continue;
if (IsAnyOf(item.IDidx, IDI_GOLD, IDI_EAR))
continue;
if ((item._iCreateInfo & CF_USEFUL) != CF_UPER15)
if (!item.matchesCreationFlags(CF_USEFUL, CF_UPER15))
continue;
const uint16_t createInfo = item._iCreateInfo;
item._iCreateInfo &= ~CF_LEVEL;
item._iCreateInfo |= 31;
const uint16_t createInfo = item.getAllCreationFlags();
item.setItemLevel(31);
ASSERT_FALSE(TestNetPackValidation());
item._iCreateInfo = createInfo;
item.setAllCreationFlags(createInfo);
count++;
}
ASSERT_GT(count, 0);
@ -1440,15 +1439,14 @@ TEST_F(NetPackTest, UnPackNetPlayer_invalid_monsterItemLevel)
continue;
if (IsAnyOf(item.IDidx, IDI_GOLD, IDI_EAR))
continue;
if ((item._iCreateInfo & CF_TOWN) != 0)
if (item.hasCreationFlag(CF_TOWN))
continue;
if ((item._iCreateInfo & CF_USEFUL) == CF_UPER15)
if (item.matchesCreationFlags(CF_USEFUL, CF_UPER15))
continue;
const uint16_t createInfo = item._iCreateInfo;
item._iCreateInfo &= ~CF_LEVEL;
item._iCreateInfo |= 31;
item.setItemLevel(31);
ASSERT_FALSE(TestNetPackValidation());
item._iCreateInfo = createInfo;
item.setAllCreationFlags(createInfo);
count++;
}
ASSERT_GT(count, 0);

32
test/vendor_test.cpp

@ -203,7 +203,7 @@ TEST_F(VendorTest, PremiumQlvl1to5)
for (size_t i = 0; i < PremiumItems.size(); i++) {
constexpr int QLVLS[] = { 1, 1, 1, 1, 2, 3 };
EXPECT_EQ(PremiumItems[i]._iCreateInfo & CF_LEVEL, QLVLS[i]) << "Index: " << i;
EXPECT_EQ(PremiumItems[i].getItemLevel(), QLVLS[i]) << "Index: " << i;
EXPECT_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatch(i), PremiumTypeMatch(i)));
}
@ -214,7 +214,7 @@ TEST_F(VendorTest, PremiumQlvl1to5)
for (size_t i = 0; i < PremiumItems.size(); i++) {
constexpr int QLVLS[] = { 4, 4, 5, 5, 6, 7 };
EXPECT_EQ(PremiumItems[i]._iCreateInfo & CF_LEVEL, QLVLS[i]) << "Index: " << i;
EXPECT_EQ(PremiumItems[i].getItemLevel(), QLVLS[i]) << "Index: " << i;
EXPECT_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatch(i), PremiumTypeMatch(i)));
}
}
@ -230,7 +230,7 @@ TEST_F(VendorTest, PremiumQlvl25)
EXPECT_EQ(PremiumItems.size(), NumSmithItems);
for (size_t i = 0; i < PremiumItems.size(); i++) {
EXPECT_EQ(PremiumItems[i]._iCreateInfo & CF_LEVEL, QLVLS[i]) << "Index: " << i;
EXPECT_EQ(PremiumItems[i].getItemLevel(), QLVLS[i]) << "Index: " << i;
EXPECT_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatch(i), PremiumTypeMatch(i)));
}
@ -241,7 +241,7 @@ TEST_F(VendorTest, PremiumQlvl25)
EXPECT_EQ(PremiumItems.size(), NumSmithItems);
for (size_t i = 0; i < PremiumItems.size(); i++) {
EXPECT_EQ(PremiumItems[i]._iCreateInfo & CF_LEVEL, QLVLS[i]) << "Index: " << i;
EXPECT_EQ(PremiumItems[i].getItemLevel(), QLVLS[i]) << "Index: " << i;
EXPECT_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatch(i), PremiumTypeMatch(i)));
}
}
@ -257,7 +257,7 @@ TEST_F(VendorTest, PremiumQlvl30Plus)
EXPECT_EQ(PremiumItems.size(), NumSmithItems);
for (size_t i = 0; i < PremiumItems.size(); i++) {
EXPECT_EQ(PremiumItems[i]._iCreateInfo & CF_LEVEL, QLVLS[i]) << "Index: " << i;
EXPECT_EQ(PremiumItems[i].getItemLevel(), QLVLS[i]) << "Index: " << i;
EXPECT_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatch(i), PremiumTypeMatch(i)));
}
@ -268,7 +268,7 @@ TEST_F(VendorTest, PremiumQlvl30Plus)
EXPECT_EQ(PremiumItems.size(), NumSmithItems);
for (size_t i = 0; i < PremiumItems.size(); i++) {
EXPECT_EQ(PremiumItems[i]._iCreateInfo & CF_LEVEL, QLVLS[i]) << "Index: " << i;
EXPECT_EQ(PremiumItems[i].getItemLevel(), QLVLS[i]) << "Index: " << i;
EXPECT_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatch(i), PremiumTypeMatch(i)));
}
@ -278,7 +278,7 @@ TEST_F(VendorTest, PremiumQlvl30Plus)
EXPECT_EQ(PremiumItems.size(), NumSmithItems);
for (size_t i = 0; i < PremiumItems.size(); i++) {
EXPECT_EQ(PremiumItems[i]._iCreateInfo & CF_LEVEL, QLVLS[i]) << "Index: " << i;
EXPECT_EQ(PremiumItems[i].getItemLevel(), QLVLS[i]) << "Index: " << i;
EXPECT_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatch(i), PremiumTypeMatch(i)));
}
@ -289,7 +289,7 @@ TEST_F(VendorTest, PremiumQlvl30Plus)
EXPECT_EQ(PremiumItems.size(), NumSmithItems);
for (size_t i = 0; i < PremiumItems.size(); i++) {
EXPECT_EQ(PremiumItems[i]._iCreateInfo & CF_LEVEL, QLVLS[i]) << "Index: " << i;
EXPECT_EQ(PremiumItems[i].getItemLevel(), QLVLS[i]) << "Index: " << i;
EXPECT_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatch(i), PremiumTypeMatch(i)));
}
}
@ -305,7 +305,7 @@ TEST_F(VendorTest, HfPremiumQlvl1to5)
for (size_t i = 0; i < PremiumItems.size(); i++) {
constexpr int QLVLS[] = { 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 4 };
EXPECT_EQ(PremiumItems[i]._iCreateInfo & CF_LEVEL, QLVLS[i]) << "Index: " << i;
EXPECT_EQ(PremiumItems[i].getItemLevel(), QLVLS[i]) << "Index: " << i;
EXPECT_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatchHf(i), PremiumTypeMatch(i)));
}
@ -316,7 +316,7 @@ TEST_F(VendorTest, HfPremiumQlvl1to5)
for (size_t i = 0; i < PremiumItems.size(); i++) {
constexpr int QLVLS[] = { 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8 };
EXPECT_EQ(PremiumItems[i]._iCreateInfo & CF_LEVEL, QLVLS[i]) << "Index: " << i;
EXPECT_EQ(PremiumItems[i].getItemLevel(), QLVLS[i]) << "Index: " << i;
EXPECT_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatchHf(i), PremiumTypeMatch(i)));
}
}
@ -332,7 +332,7 @@ TEST_F(VendorTest, HfPremiumQlvl25)
for (size_t i = 0; i < PremiumItems.size(); i++) {
constexpr int QLVLS[] = { 23, 23, 23, 24, 24, 24, 25, 25, 25, 26, 26, 26, 27, 27, 28 };
EXPECT_EQ(PremiumItems[i]._iCreateInfo & CF_LEVEL, QLVLS[i]) << "Index: " << i;
EXPECT_EQ(PremiumItems[i].getItemLevel(), QLVLS[i]) << "Index: " << i;
EXPECT_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatchHf(i), PremiumTypeMatch(i)));
}
@ -344,7 +344,7 @@ TEST_F(VendorTest, HfPremiumQlvl25)
for (size_t i = 0; i < PremiumItems.size(); i++) {
constexpr int QLVLS[] = { 24, 23, 23, 24, 24, 24, 25, 26, 25, 26, 26, 26, 27, 27, 28 };
EXPECT_EQ(PremiumItems[i]._iCreateInfo & CF_LEVEL, QLVLS[i]) << "Index: " << i;
EXPECT_EQ(PremiumItems[i].getItemLevel(), QLVLS[i]) << "Index: " << i;
EXPECT_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatchHf(i), PremiumTypeMatch(i)));
}
}
@ -360,7 +360,7 @@ TEST_F(VendorTest, HfPremiumQlvl30Plus)
for (size_t i = 0; i < PremiumItems.size(); i++) {
constexpr int QLVLS[] = { 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30 };
EXPECT_EQ(PremiumItems[i]._iCreateInfo & CF_LEVEL, QLVLS[i]) << "Index: " << i;
EXPECT_EQ(PremiumItems[i].getItemLevel(), QLVLS[i]) << "Index: " << i;
EXPECT_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatchHf(i), PremiumTypeMatch(i)));
}
@ -372,7 +372,7 @@ TEST_F(VendorTest, HfPremiumQlvl30Plus)
for (size_t i = 0; i < PremiumItems.size(); i++) {
constexpr int QLVLS[] = { 30, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30 };
EXPECT_EQ(PremiumItems[i]._iCreateInfo & CF_LEVEL, QLVLS[i]) << "Index: " << i;
EXPECT_EQ(PremiumItems[i].getItemLevel(), QLVLS[i]) << "Index: " << i;
EXPECT_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatchHf(i), PremiumTypeMatch(i)));
}
@ -384,7 +384,7 @@ TEST_F(VendorTest, HfPremiumQlvl30Plus)
EXPECT_EQ(PremiumItems.size(), NumSmithItemsHf);
for (size_t i = 0; i < PremiumItems.size(); i++) {
EXPECT_EQ(PremiumItems[i]._iCreateInfo & CF_LEVEL, QLVLS[i]) << "Index: " << i;
EXPECT_EQ(PremiumItems[i].getItemLevel(), QLVLS[i]) << "Index: " << i;
EXPECT_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatchHf(i), PremiumTypeMatch(i)));
}
@ -395,7 +395,7 @@ TEST_F(VendorTest, HfPremiumQlvl30Plus)
EXPECT_EQ(PremiumItems.size(), NumSmithItemsHf);
for (size_t i = 0; i < PremiumItems.size(); i++) {
EXPECT_EQ(PremiumItems[i]._iCreateInfo & CF_LEVEL, QLVLS[i]) << "Index: " << i;
EXPECT_EQ(PremiumItems[i].getItemLevel(), QLVLS[i]) << "Index: " << i;
EXPECT_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatchHf(i), PremiumTypeMatch(i)));
}
}

Loading…
Cancel
Save