Browse Source

Use StaticVector for all vendors

pull/8262/head
Yggdrasill 4 months ago committed by GitHub
parent
commit
753b566350
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 101
      Source/items.cpp
  2. 1
      Source/items.h
  3. 105
      Source/stores.cpp
  4. 9
      Source/stores.h
  5. 316
      test/vendor_test.cpp

101
Source/items.cpp

@ -1901,13 +1901,13 @@ _item_indexes RndSmithItem(const Player &player, int lvl)
return RndVendorItem<SmithItemOk, true>(player, 0, lvl);
}
void SortVendor(Item *itemList, size_t count)
void SortVendor(std::span<Item> itemList, size_t PinnedItemCount)
{
auto cmp = [](const Item &a, const Item &b) {
return a.IDidx < b.IDidx;
};
std::sort(itemList, itemList + count, cmp);
std::sort(itemList.begin() + PinnedItemCount, itemList.end(), cmp);
}
bool PremiumItemOk(const Player & /*player*/, const ItemData &item)
@ -4388,10 +4388,11 @@ void SpawnSmith(int lvl)
maxItems = NumSmithBasicItemsHf;
}
const int iCnt = RandomIntBetween(10, maxItems);
for (int i = 0; i < iCnt; i++) {
Item &newItem = SmithItems[i];
const size_t iCnt = RandomIntBetween(10, maxItems);
SmithItems.clear();
while (SmithItems.size() < iCnt) {
Item newItem;
do {
newItem = {};
newItem._iSeed = AdvanceRndSeed();
@ -4402,41 +4403,46 @@ void SpawnSmith(int lvl)
newItem._iCreateInfo = lvl | CF_SMITH;
newItem._iIdentified = true;
SmithItems.push_back(newItem);
}
for (int i = iCnt; i < NumSmithBasicItemsHf; i++)
SmithItems[i].clear();
SortVendor(SmithItems + PinnedItemCount, iCnt - PinnedItemCount);
SortVendor(SmithItems, PinnedItemCount);
}
void ReplacePremium(const Player &player, int idx)
{
int plvl = gbIsHellfire ? itemLevelAddHf[idx] : itemLevelAdd[idx];
plvl += player.getCharacterLevel();
SpawnOnePremium(PremiumItems[idx], plvl, player);
}
void SpawnPremium(const Player &player)
{
const int lvl = player.getCharacterLevel();
const int maxItems = gbIsHellfire ? NumSmithItemsHf : NumSmithItems;
if (PremiumItemCount < maxItems) {
for (int i = 0; i < maxItems; i++) {
if (PremiumItems[i].isEmpty()) {
const int plvl = PremiumItemLevel + (gbIsHellfire ? itemLevelAddHf[i] : itemLevelAdd[i]);
SpawnOnePremium(PremiumItems[i], plvl, player);
}
}
PremiumItemCount = maxItems;
const size_t maxItems = gbIsHellfire ? NumSmithItemsHf : NumSmithItems;
while (PremiumItems.size() < maxItems) {
int plvl = PremiumItemLevel + (gbIsHellfire ? itemLevelAddHf[PremiumItems.size()] : itemLevelAdd[PremiumItems.size()]);
Item item = {};
SpawnOnePremium(item, plvl, player);
PremiumItems.push_back(item);
}
while (PremiumItemLevel < lvl) {
PremiumItemLevel++;
Item *ptr = PremiumItems.begin();
if (gbIsHellfire) {
// Discard first 3 items and shift next 10
std::move(&PremiumItems[3], &PremiumItems[12] + 1, &PremiumItems[0]);
SpawnOnePremium(PremiumItems[10], PremiumItemLevel + itemLevelAddHf[10], player);
std::move(ptr + 3, ptr + 13, ptr);
PremiumItems[11] = PremiumItems[13];
SpawnOnePremium(PremiumItems[12], PremiumItemLevel + itemLevelAddHf[12], player);
PremiumItems[13] = PremiumItems[14];
SpawnOnePremium(PremiumItems[10], PremiumItemLevel + itemLevelAddHf[10], player);
SpawnOnePremium(PremiumItems[12], PremiumItemLevel + itemLevelAddHf[12], player);
SpawnOnePremium(PremiumItems[14], PremiumItemLevel + itemLevelAddHf[14], player);
} else {
// Discard first 2 items and shift next 3
std::move(&PremiumItems[2], &PremiumItems[4] + 1, &PremiumItems[0]);
SpawnOnePremium(PremiumItems[3], PremiumItemLevel + itemLevelAdd[3], player);
std::move(ptr + 2, ptr + 5, ptr);
PremiumItems[4] = PremiumItems[5];
SpawnOnePremium(PremiumItems[3], PremiumItemLevel + itemLevelAdd[3], player);
SpawnOnePremium(PremiumItems[5], PremiumItemLevel + itemLevelAdd[5], player);
}
}
@ -4453,16 +4459,17 @@ void SpawnWitch(int lvl)
const int pinnedBookCount = gbIsHellfire ? RandomIntLessThan(MaxPinnedBookCount) : 0;
const int itemCount = RandomIntBetween(10, gbIsHellfire ? NumWitchItemsHf : NumWitchItems);
const int maxValue = gbIsHellfire ? MaxVendorValueHf : MaxVendorValue;
WitchItems.clear();
for (int i = 0; i < NumWitchItemsHf; i++) {
Item &item = WitchItems[i];
item = {};
for (int i = 0; i < itemCount; i++) {
Item item = {};
if (i < PinnedItemCount) {
item._iSeed = AdvanceRndSeed();
GetItemAttrs(item, PinnedItemTypes[i], 1);
item._iCreateInfo = lvl;
item._iStatFlag = true;
WitchItems.push_back(item);
continue;
}
@ -4477,16 +4484,12 @@ void SpawnWitch(int lvl)
item._iCreateInfo = lvl | CF_WITCH;
item._iIdentified = true;
bookCount++;
WitchItems.push_back(item);
continue;
}
}
}
if (i >= itemCount) {
item.clear();
continue;
}
do {
item = {};
item._iSeed = AdvanceRndSeed();
@ -4504,9 +4507,11 @@ void SpawnWitch(int lvl)
item._iCreateInfo = lvl | CF_WITCH;
item._iIdentified = true;
WitchItems.push_back(item);
}
SortVendor(WitchItems + PinnedItemCount, itemCount - PinnedItemCount);
SortVendor(WitchItems, PinnedItemCount);
}
void SpawnBoy(int lvl)
@ -4629,34 +4634,30 @@ void SpawnHealer(int lvl)
{
constexpr size_t PinnedItemCount = NumHealerPinnedItems;
constexpr std::array<_item_indexes, PinnedItemCount + 1> PinnedItemTypes = { IDI_HEAL, IDI_FULLHEAL, IDI_RESURRECT };
const auto itemCount = static_cast<size_t>(RandomIntBetween(10, gbIsHellfire ? NumHealerItemsHf : NumHealerItems));
const size_t itemCount = static_cast<size_t>(RandomIntBetween(10, gbIsHellfire ? NumHealerItemsHf : NumHealerItems));
HealerItems.clear();
for (size_t i = 0; i < sizeof(HealerItems) / sizeof(HealerItems[0]); ++i) {
Item &item = HealerItems[i];
item = {};
for (size_t i = 0; i < itemCount; i++) {
Item item = {};
if (i < PinnedItemCount || (gbIsMultiplayer && i < NumHealerPinnedItemsMp)) {
item._iSeed = AdvanceRndSeed();
GetItemAttrs(item, PinnedItemTypes[i], 1);
item._iCreateInfo = lvl;
item._iStatFlag = true;
continue;
}
if (i >= itemCount) {
item.clear();
continue;
} else {
item._iSeed = AdvanceRndSeed();
SetRndSeed(item._iSeed);
const _item_indexes itype = RndHealerItem(*MyPlayer, lvl);
GetItemAttrs(item, itype, lvl);
item._iCreateInfo = lvl | CF_HEALER;
item._iIdentified = true;
}
item._iSeed = AdvanceRndSeed();
SetRndSeed(item._iSeed);
const _item_indexes itype = RndHealerItem(*MyPlayer, lvl);
GetItemAttrs(item, itype, lvl);
item._iCreateInfo = lvl | CF_HEALER;
item._iIdentified = true;
HealerItems.push_back(item);
}
SortVendor(HealerItems + PinnedItemCount, itemCount - PinnedItemCount);
SortVendor(HealerItems, PinnedItemCount);
}
void MakeGoldStack(Item &goldItem, int value)

1
Source/items.h

@ -557,6 +557,7 @@ void UseItem(Player &player, item_misc_id Mid, SpellID spellID, int spellFrom);
bool UseItemOpensHive(const Item &item, Point position);
bool UseItemOpensGrave(const Item &item, Point position);
void SpawnSmith(int lvl);
void ReplacePremium(const Player &player, int idx);
void SpawnPremium(const Player &player);
void SpawnWitch(int lvl);
void SpawnBoy(int lvl);

105
Source/stores.cpp

@ -40,14 +40,14 @@ int CurrentItemIndex;
int8_t PlayerItemIndexes[48];
Item PlayerItems[48];
Item SmithItems[NumSmithBasicItemsHf];
StaticVector<Item, NumSmithBasicItemsHf> SmithItems;
int PremiumItemCount;
int PremiumItemLevel;
Item PremiumItems[NumSmithItemsHf];
StaticVector<Item, NumSmithItemsHf> PremiumItems;
Item HealerItems[20];
StaticVector<Item, NumHealerItemsHf> HealerItems;
Item WitchItems[NumWitchItemsHf];
StaticVector<Item, NumWitchItemsHf> WitchItems;
int BoyItemLevel;
Item BoyItem;
@ -354,22 +354,18 @@ bool StoreAutoPlace(Item &item, bool persistItem)
return CanFitItemInInventory(player, item);
}
void ScrollVendorStore(Item *itemData, int storeLimit, int idx, int selling = true)
void ScrollVendorStore(std::span<Item> itemData, int storeLimit, int idx, int selling = true)
{
ClearSText(5, 21);
PreviousScrollPos = 5;
for (int l = 5; l < 20 && idx < storeLimit; l += 4) {
const Item &item = itemData[idx];
if (!item.isEmpty()) {
const UiFlags itemColor = item.getTextColorWithStatCheck();
AddSText(20, l, item.getName(), itemColor, true, item._iCurs, true);
AddSTextVal(l, item._iIdentified ? item._iIvalue : item._ivalue);
PrintStoreItem(item, l + 1, itemColor, true);
NextScrollPos = l;
} else {
l -= 4;
}
const UiFlags itemColor = item.getTextColorWithStatCheck();
AddSText(20, l, item.getName(), itemColor, true, item._iCurs, true);
AddSTextVal(l, item._iIdentified ? item._iIvalue : item._ivalue);
PrintStoreItem(item, l + 1, itemColor, true);
NextScrollPos = l;
idx++;
}
if (selling) {
@ -399,7 +395,7 @@ void StartSmith()
void ScrollSmithBuy(int idx)
{
ScrollVendorStore(SmithItems, static_cast<int>(std::size(SmithItems)), idx);
ScrollVendorStore(SmithItems, static_cast<int>(SmithItems.size()), idx);
}
uint32_t TotalPlayerGold()
@ -427,9 +423,6 @@ void StartSmithBuy()
CurrentItemIndex = 0;
for (Item &item : SmithItems) {
if (item.isEmpty())
continue;
item._iStatFlag = MyPlayer->CanUseItem(item);
CurrentItemIndex++;
}
@ -445,16 +438,13 @@ void ScrollSmithPremiumBuy(int boughtitems)
boughtitems--;
}
ScrollVendorStore(PremiumItems, static_cast<int>(std::size(PremiumItems)), idx);
ScrollVendorStore(PremiumItems, static_cast<int>(PremiumItems.size()), idx);
}
bool StartSmithPremiumBuy()
{
CurrentItemIndex = 0;
for (Item &item : PremiumItems) {
if (item.isEmpty())
continue;
item._iStatFlag = MyPlayer->CanUseItem(item);
CurrentItemIndex++;
}
@ -695,7 +685,7 @@ void StartWitch()
void ScrollWitchBuy(int idx)
{
ScrollVendorStore(WitchItems, static_cast<int>(std::size(WitchItems)), idx);
ScrollVendorStore(WitchItems, static_cast<int>(WitchItems.size()), idx);
}
void WitchBookLevel(Item &bookItem)
@ -729,9 +719,6 @@ void StartWitchBuy()
CurrentItemIndex = 0;
for (Item &item : WitchItems) {
if (item.isEmpty())
continue;
WitchBookLevel(item);
item._iStatFlag = MyPlayer->CanUseItem(item);
CurrentItemIndex++;
@ -1044,7 +1031,7 @@ void StartHealer()
void ScrollHealerBuy(int idx)
{
ScrollVendorStore(HealerItems, static_cast<int>(std::size(HealerItems)), idx);
ScrollVendorStore(HealerItems, static_cast<int>(HealerItems.size()), idx);
}
void StartHealerBuy()
@ -1062,9 +1049,6 @@ void StartHealerBuy()
CurrentItemIndex = 0;
for (Item &item : HealerItems) {
if (item.isEmpty())
continue;
item._iStatFlag = MyPlayer->CanUseItem(item);
CurrentItemIndex++;
}
@ -1322,14 +1306,7 @@ void SmithBuyItem(Item &item)
item._iIdentified = false;
StoreAutoPlace(item, true);
int idx = OldScrollPos + ((OldTextLine - PreviousScrollPos) / 4);
if (idx == NumSmithBasicItemsHf - 1) {
SmithItems[NumSmithBasicItemsHf - 1].clear();
} else {
for (; !SmithItems[idx + 1].isEmpty(); idx++) {
SmithItems[idx] = std::move(SmithItems[idx + 1]);
}
SmithItems[idx].clear();
}
SmithItems.erase(SmithItems.begin() + idx);
CalcPlrInv(*MyPlayer, true);
}
@ -1371,17 +1348,7 @@ void SmithBuyPItem(Item &item)
StoreAutoPlace(item, true);
int idx = OldScrollPos + ((OldTextLine - PreviousScrollPos) / 4);
int xx = 0;
for (int i = 0; idx >= 0; i++) {
if (!PremiumItems[i].isEmpty()) {
idx--;
xx = i;
}
}
PremiumItems[xx].clear();
PremiumItemCount--;
SpawnPremium(*MyPlayer);
ReplacePremium(*MyPlayer, idx);
}
void SmithPremiumBuyEnter()
@ -1396,14 +1363,7 @@ void SmithPremiumBuyEnter()
OldTextLine = CurrentTextLine;
OldScrollPos = ScrollPos;
int xx = ScrollPos + ((CurrentTextLine - PreviousScrollPos) / 4);
int idx = 0;
for (int i = 0; xx >= 0; i++) {
if (!PremiumItems[i].isEmpty()) {
xx--;
idx = i;
}
}
int idx = ScrollPos + ((CurrentTextLine - PreviousScrollPos) / 4);
if (!PlayerCanAfford(PremiumItems[idx]._iIvalue)) {
StartStore(TalkID::NoMoney);
@ -1574,14 +1534,7 @@ void WitchBuyItem(Item &item)
StoreAutoPlace(item, true);
if (idx >= 3) {
if (idx == NumWitchItemsHf - 1) {
WitchItems[NumWitchItemsHf - 1].clear();
} else {
for (; !WitchItems[idx + 1].isEmpty(); idx++) {
WitchItems[idx] = std::move(WitchItems[idx + 1]);
}
WitchItems[idx].clear();
}
WitchItems.erase(WitchItems.begin() + idx);
}
CalcPlrInv(*MyPlayer, true);
@ -1747,14 +1700,7 @@ void HealerBuyItem(Item &item)
return;
}
idx = OldScrollPos + ((OldTextLine - PreviousScrollPos) / 4);
if (idx == 19) {
HealerItems[19].clear();
} else {
for (; !HealerItems[idx + 1].isEmpty(); idx++) {
HealerItems[idx] = std::move(HealerItems[idx + 1]);
}
HealerItems[idx].clear();
}
HealerItems.erase(HealerItems.begin() + idx);
CalcPlrInv(*MyPlayer, true);
}
@ -2121,8 +2067,10 @@ void InitStores()
PremiumItemCount = 0;
PremiumItemLevel = 1;
for (auto &premiumitem : PremiumItems)
premiumitem.clear();
SmithItems.clear();
WitchItems.clear();
HealerItems.clear();
PremiumItems.clear();
BoyItem.clear();
BoyItemLevel = 0;
@ -2271,12 +2219,7 @@ void StartStore(TalkID s)
StartSmith();
break;
case TalkID::SmithBuy: {
bool hasAnyItems = false;
for (int i = 0; !SmithItems[i].isEmpty(); i++) {
hasAnyItems = true;
break;
}
if (hasAnyItems)
if (!SmithItems.empty())
StartSmithBuy();
else {
ActiveStore = TalkID::SmithBuy;

9
Source/stores.h

@ -14,6 +14,7 @@
#include "engine/surface.hpp"
#include "game_mode.hpp"
#include "utils/attributes.h"
#include "utils/static_vector.hpp"
namespace devilution {
@ -72,19 +73,19 @@ extern int8_t PlayerItemIndexes[48];
extern DVL_API_FOR_TEST Item PlayerItems[48];
/** Items sold by Griswold */
extern DVL_API_FOR_TEST Item SmithItems[NumSmithBasicItemsHf];
extern DVL_API_FOR_TEST StaticVector<Item, NumSmithBasicItemsHf> SmithItems;
/** Number of premium items for sale by Griswold */
extern DVL_API_FOR_TEST int PremiumItemCount;
/** Base level of current premium items sold by Griswold */
extern DVL_API_FOR_TEST int PremiumItemLevel;
/** Premium items sold by Griswold */
extern DVL_API_FOR_TEST Item PremiumItems[NumSmithItemsHf];
extern DVL_API_FOR_TEST StaticVector<Item, NumSmithItemsHf> PremiumItems;
/** Items sold by Pepin */
extern DVL_API_FOR_TEST Item HealerItems[20];
extern DVL_API_FOR_TEST StaticVector<Item, NumHealerItemsHf> HealerItems;
/** Items sold by Adria */
extern DVL_API_FOR_TEST Item WitchItems[NumWitchItemsHf];
extern DVL_API_FOR_TEST StaticVector<Item, NumWitchItemsHf> WitchItems;
/** Current level of the item sold by Wirt */
extern int BoyItemLevel;

316
test/vendor_test.cpp

@ -81,6 +81,7 @@ public:
Players.resize(1);
MyPlayer = &Players[0];
gbIsHellfire = false;
PremiumItemLevel = 1;
CreatePlayer(*MyPlayer, HeroClass::Warrior);
SetRndSeed(SEED);
}
@ -149,62 +150,45 @@ std::string misctype_str(item_misc_id type)
TEST_F(VendorTest, SmithGen)
{
MyPlayer->setCharacterLevel(25);
// Clear global state for test, and force Diablo game mode
for (int i = 0; i < NumSmithBasicItemsHf; i++) {
SmithItems[i].clear();
}
gbIsHellfire = false;
SmithItems.clear();
SpawnSmith(16);
SetRndSeed(SEED);
const int N_ITEMS = RandomIntBetween(10, NumSmithBasicItems);
int n_items = 0;
EXPECT_EQ(SmithItems.size(), N_ITEMS);
EXPECT_LE(SmithItems.size(), NumSmithBasicItems);
for (int i = 0; i < NumSmithBasicItems; i++) {
if (SmithItems[i].isEmpty()) break;
for (size_t i = 0; i < SmithItems.size(); i++) {
EXPECT_THAT(SmithItems[i]._itype, SmithTypeMatch(i));
n_items++;
}
EXPECT_EQ(n_items, N_ITEMS);
}
TEST_F(VendorTest, SmithGenHf)
{
MyPlayer->setCharacterLevel(25);
// Clear global state for test, and force Hellfire game mode
for (int i = 0; i < NumSmithBasicItemsHf; i++) {
SmithItems[i].clear();
}
SmithItems.clear();
gbIsHellfire = true;
SpawnSmith(16);
SetRndSeed(SEED);
const int N_ITEMS = RandomIntBetween(10, NumSmithBasicItemsHf);
int n_items = 0;
EXPECT_EQ(SmithItems.size(), N_ITEMS);
EXPECT_LE(SmithItems.size(), NumSmithBasicItemsHf);
for (int i = 0; i < NumSmithBasicItemsHf; i++) {
if (SmithItems[i].isEmpty()) break;
for (size_t i = 0; i < SmithItems.size(); i++) {
EXPECT_THAT(SmithItems[i]._itype, SmithTypeMatchHf(i));
n_items++;
}
EXPECT_EQ(n_items, N_ITEMS);
}
TEST_F(VendorTest, PremiumQlvl1to5)
{
for (int i = 0; i < NumSmithItems; i++) {
PremiumItems[i].clear();
}
PremiumItemLevel = 1;
// Test level 1 character item qlvl
// Test starting the game as a level 1 character
MyPlayer->setCharacterLevel(1);
PremiumItems.clear();
SpawnPremium(*MyPlayer);
for (int i = 0; i < NumSmithItems; i++) {
EXPECT_EQ(PremiumItems.size(), NumSmithItems);
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_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatch(i), PremiumTypeMatch(i)));
@ -213,7 +197,9 @@ TEST_F(VendorTest, PremiumQlvl1to5)
// Test level ups
MyPlayer->setCharacterLevel(5);
SpawnPremium(*MyPlayer);
for (int i = 0; i < NumSmithItems; i++) {
EXPECT_EQ(PremiumItems.size(), NumSmithItems);
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_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatch(i), PremiumTypeMatch(i)));
@ -224,26 +210,24 @@ TEST_F(VendorTest, PremiumQlvl25)
{
constexpr int QLVLS[] = { 24, 24, 25, 25, 26, 27 };
for (int i = 0; i < NumSmithItems; i++) {
PremiumItems[i].clear();
}
PremiumItemLevel = 1;
// Test starting game as a level 25 character
// Test starting the game as a level 25 character
MyPlayer->setCharacterLevel(25);
PremiumItems.clear();
SpawnPremium(*MyPlayer);
for (int i = 0; i < NumSmithItems; i++) {
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_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatch(i), PremiumTypeMatch(i)));
}
// Test buying select items
PremiumItems[0].clear();
PremiumItems[3].clear();
PremiumItems[5].clear();
PremiumItemCount -= 3;
SpawnPremium(*MyPlayer);
for (int i = 0; i < NumSmithItems; i++) {
ReplacePremium(*MyPlayer, 0);
ReplacePremium(*MyPlayer, 3);
ReplacePremium(*MyPlayer, 5);
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_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatch(i), PremiumTypeMatch(i)));
}
@ -253,26 +237,24 @@ TEST_F(VendorTest, PremiumQlvl30Plus)
{
constexpr int QLVLS[] = { 30, 30, 30, 30, 30, 30 };
for (int i = 0; i < NumSmithItems; i++) {
PremiumItems[i].clear();
}
PremiumItemLevel = 1;
// Finally test level 30+ characters
MyPlayer->setCharacterLevel(31);
PremiumItems.clear();
SpawnPremium(*MyPlayer);
for (int i = 0; i < NumSmithItems; i++) {
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_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatch(i), PremiumTypeMatch(i)));
}
// Test buying select items
PremiumItems[0].clear();
PremiumItems[3].clear();
PremiumItems[5].clear();
PremiumItemCount -= 3;
SpawnPremium(*MyPlayer);
for (int i = 0; i < NumSmithItems; i++) {
ReplacePremium(*MyPlayer, 0);
ReplacePremium(*MyPlayer, 3);
ReplacePremium(*MyPlayer, 5);
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_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatch(i), PremiumTypeMatch(i)));
}
@ -280,18 +262,20 @@ TEST_F(VendorTest, PremiumQlvl30Plus)
// Test 30+ levelling
MyPlayer->setCharacterLevel(35);
SpawnPremium(*MyPlayer);
for (int i = 0; i < NumSmithItems; i++) {
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_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatch(i), PremiumTypeMatch(i)));
}
// Test buying select items
PremiumItems[0].clear();
PremiumItems[3].clear();
PremiumItems[5].clear();
PremiumItemCount -= 3;
SpawnPremium(*MyPlayer);
for (int i = 0; i < NumSmithItems; i++) {
ReplacePremium(*MyPlayer, 0);
ReplacePremium(*MyPlayer, 3);
ReplacePremium(*MyPlayer, 5);
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_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatch(i), PremiumTypeMatch(i)));
}
@ -299,16 +283,14 @@ TEST_F(VendorTest, PremiumQlvl30Plus)
TEST_F(VendorTest, HfPremiumQlvl1to5)
{
for (int i = 0; i < NumSmithItemsHf; i++) {
PremiumItems[i].clear();
}
PremiumItemLevel = 1;
gbIsHellfire = true;
// Test level 1 character item qlvl
MyPlayer->setCharacterLevel(1);
PremiumItems.clear();
gbIsHellfire = true;
SpawnPremium(*MyPlayer);
for (int i = 0; i < NumSmithItemsHf; i++) {
EXPECT_EQ(PremiumItems.size(), NumSmithItemsHf);
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_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatchHf(i), PremiumTypeMatch(i)));
@ -317,7 +299,9 @@ TEST_F(VendorTest, HfPremiumQlvl1to5)
// Test level ups
MyPlayer->setCharacterLevel(5);
SpawnPremium(*MyPlayer);
for (int i = 0; i < NumSmithItemsHf; i++) {
EXPECT_EQ(PremiumItems.size(), NumSmithItemsHf);
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_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatchHf(i), PremiumTypeMatch(i)));
@ -326,28 +310,26 @@ TEST_F(VendorTest, HfPremiumQlvl1to5)
TEST_F(VendorTest, HfPremiumQlvl25)
{
for (int i = 0; i < NumSmithItemsHf; i++) {
PremiumItems[i].clear();
}
PremiumItemLevel = 1;
gbIsHellfire = true;
// Test starting game as a level 25 character
MyPlayer->setCharacterLevel(25);
PremiumItems.clear();
gbIsHellfire = true;
SpawnPremium(*MyPlayer);
for (int i = 0; i < NumSmithItemsHf; i++) {
EXPECT_EQ(PremiumItems.size(), NumSmithItemsHf);
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_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatchHf(i), PremiumTypeMatch(i)));
}
// Test buying select items
PremiumItems[0].clear();
PremiumItems[7].clear();
PremiumItems[14].clear();
PremiumItemCount -= 3;
SpawnPremium(*MyPlayer);
for (int i = 0; i < NumSmithItemsHf; i++) {
ReplacePremium(*MyPlayer, 0);
ReplacePremium(*MyPlayer, 7);
ReplacePremium(*MyPlayer, 14);
EXPECT_EQ(PremiumItems.size(), NumSmithItemsHf);
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_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatchHf(i), PremiumTypeMatch(i)));
@ -356,28 +338,26 @@ TEST_F(VendorTest, HfPremiumQlvl25)
TEST_F(VendorTest, HfPremiumQlvl30Plus)
{
for (int i = 0; i < NumSmithItemsHf; i++) {
PremiumItems[i].clear();
}
PremiumItemLevel = 1;
gbIsHellfire = true;
// Finally test level 30+ characters
MyPlayer->setCharacterLevel(31);
PremiumItems.clear();
gbIsHellfire = true;
SpawnPremium(*MyPlayer);
for (int i = 0; i < NumSmithItemsHf; i++) {
EXPECT_EQ(PremiumItems.size(), NumSmithItemsHf);
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_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatchHf(i), PremiumTypeMatch(i)));
}
// Test buying select items
PremiumItems[0].clear();
PremiumItems[7].clear();
PremiumItems[14].clear();
PremiumItemCount -= 3;
SpawnPremium(*MyPlayer);
for (int i = 0; i < NumSmithItemsHf; i++) {
ReplacePremium(*MyPlayer, 0);
ReplacePremium(*MyPlayer, 7);
ReplacePremium(*MyPlayer, 14);
EXPECT_EQ(PremiumItems.size(), NumSmithItemsHf);
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_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatchHf(i), PremiumTypeMatch(i)));
@ -388,18 +368,20 @@ TEST_F(VendorTest, HfPremiumQlvl30Plus)
// Test 30+ levelling
MyPlayer->setCharacterLevel(35);
SpawnPremium(*MyPlayer);
for (int i = 0; i < NumSmithItems; i++) {
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_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatchHf(i), PremiumTypeMatch(i)));
}
// Test buying select items
PremiumItems[0].clear();
PremiumItems[7].clear();
PremiumItems[14].clear();
PremiumItemCount -= 3;
SpawnPremium(*MyPlayer);
for (int i = 0; i < NumSmithItems; i++) {
ReplacePremium(*MyPlayer, 0);
ReplacePremium(*MyPlayer, 7);
ReplacePremium(*MyPlayer, 14);
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_THAT(PremiumItems[i]._itype, AnyOf(SmithTypeMatchHf(i), PremiumTypeMatch(i)));
}
@ -410,34 +392,24 @@ TEST_F(VendorTest, WitchGen)
constexpr _item_indexes PINNED_ITEMS[] = { IDI_MANA, IDI_FULLMANA, IDI_PORTAL };
MyPlayer->setCharacterLevel(25);
// Clear global state for test, and force Diablo game mode
for (int i = 0; i < NumWitchItemsHf; i++) {
WitchItems[i].clear();
}
gbIsHellfire = false;
WitchItems.clear();
SpawnWitch(16);
SetRndSeed(SEED);
const int N_ITEMS = RandomIntBetween(10, NumWitchItems);
int n_items = NumWitchPinnedItems;
for (int i = 0; i < NumWitchPinnedItems; i++) {
EXPECT_EQ(WitchItems[i].IDidx, PINNED_ITEMS[i]) << "Index: " << i;
}
for (int i = NumWitchPinnedItems; i < NumWitchItems; i++) {
if (WitchItems[i].isEmpty()) break;
EXPECT_THAT(WitchItems[i]._itype, WitchTypeMatch(i));
if (WitchItems[i]._itype == ItemType::Misc) {
EXPECT_THAT(WitchItems[i]._iMiscId, WitchMiscMatch(i));
EXPECT_EQ(WitchItems.size(), N_ITEMS);
EXPECT_LE(WitchItems.size(), NumWitchItems);
for (size_t i = 0; i < WitchItems.size(); i++) {
if (i < NumWitchPinnedItems) {
EXPECT_EQ(WitchItems[i].IDidx, PINNED_ITEMS[i]) << "Index: " << i;
} else {
EXPECT_THAT(WitchItems[i]._itype, WitchTypeMatch(i));
if (WitchItems[i]._itype == ItemType::Misc) {
EXPECT_THAT(WitchItems[i]._iMiscId, WitchMiscMatch(i));
}
}
n_items++;
}
EXPECT_EQ(n_items, N_ITEMS);
}
TEST_F(VendorTest, WitchGenHf)
@ -446,38 +418,29 @@ TEST_F(VendorTest, WitchGenHf)
constexpr int MAX_PINNED_BOOKS = 4;
MyPlayer->setCharacterLevel(25);
WitchItems.clear();
gbIsHellfire = true;
// Clear global state for test, and force Hellfire game mode
for (int i = 0; i < NumWitchItemsHf; i++) {
WitchItems[i].clear();
}
SpawnWitch(16);
SetRndSeed(SEED);
const int N_PINNED_BOOKS = RandomIntLessThan(MAX_PINNED_BOOKS);
const int N_ITEMS = RandomIntBetween(10, NumWitchItemsHf);
EXPECT_EQ(WitchItems.size(), N_ITEMS);
EXPECT_LE(WitchItems.size(), NumWitchItemsHf);
int n_books = 0;
int n_items = NumWitchPinnedItems;
for (int i = 0; i < NumWitchPinnedItems; i++) {
EXPECT_EQ(WitchItems[i].IDidx, PINNED_ITEMS[i]) << "Index: " << i;
}
for (int i = NumWitchPinnedItems; i < NumWitchItemsHf; i++) {
if (WitchItems[i].isEmpty()) break;
EXPECT_THAT(WitchItems[i]._itype, WitchTypeMatch(i));
if (WitchItems[i]._itype == ItemType::Misc) {
EXPECT_THAT(WitchItems[i]._iMiscId, WitchMiscMatch(i));
for (size_t i = 0; i < WitchItems.size(); i++) {
if (i < NumWitchPinnedItems) {
EXPECT_EQ(WitchItems[i].IDidx, PINNED_ITEMS[i]) << "Index: " << i;
} else {
EXPECT_THAT(WitchItems[i]._itype, WitchTypeMatch(i));
if (WitchItems[i]._itype == ItemType::Misc) {
EXPECT_THAT(WitchItems[i]._iMiscId, WitchMiscMatch(i));
}
if (WitchItems[i]._iMiscId == IMISC_BOOK) n_books++;
}
if (WitchItems[i]._iMiscId == IMISC_BOOK) n_books++;
n_items++;
}
EXPECT_GE(n_books, N_PINNED_BOOKS);
EXPECT_EQ(n_items, N_ITEMS);
}
TEST_F(VendorTest, HealerGen)
@ -485,30 +448,22 @@ TEST_F(VendorTest, HealerGen)
constexpr _item_indexes PINNED_ITEMS[] = { IDI_HEAL, IDI_FULLHEAL, IDI_RESURRECT };
MyPlayer->setCharacterLevel(25);
// Clear global state for test, and force Diablo game mode
for (int i = 0; i < NumHealerItemsHf; i++) {
HealerItems[i].clear();
}
gbIsHellfire = false;
HealerItems.clear();
SpawnHealer(16);
SetRndSeed(SEED);
const int N_ITEMS = RandomIntBetween(10, NumHealerItems);
int n_items = NumHealerPinnedItems;
for (int i = 0; i < NumHealerPinnedItems; i++) {
EXPECT_EQ(HealerItems[i].IDidx, PINNED_ITEMS[i]) << "Index: " << i;
}
for (int i = NumHealerPinnedItems; i < NumHealerItems; i++) {
if (HealerItems[i].isEmpty()) break;
EXPECT_THAT(HealerItems[i]._itype, Eq(ItemType::Misc));
EXPECT_THAT(HealerItems[i]._iMiscId, HealerMiscMatch(i));
n_items++;
EXPECT_EQ(HealerItems.size(), N_ITEMS);
EXPECT_LE(HealerItems.size(), NumHealerItems);
for (size_t i = 0; i < HealerItems.size(); i++) {
if (i < NumHealerPinnedItems) {
EXPECT_EQ(HealerItems[i].IDidx, PINNED_ITEMS[i]) << "Index: " << i;
} else {
EXPECT_THAT(HealerItems[i]._itype, Eq(ItemType::Misc));
EXPECT_THAT(HealerItems[i]._iMiscId, HealerMiscMatch(i));
}
}
EXPECT_EQ(n_items, N_ITEMS);
}
TEST_F(VendorTest, HealerGenHf)
@ -516,30 +471,23 @@ TEST_F(VendorTest, HealerGenHf)
constexpr _item_indexes PINNED_ITEMS[] = { IDI_HEAL, IDI_FULLHEAL, IDI_RESURRECT };
MyPlayer->setCharacterLevel(25);
// Clear global state for test, and force Hellfire game mode
for (int i = 0; i < NumHealerItemsHf; i++) {
HealerItems[i].clear();
}
HealerItems.clear();
gbIsHellfire = true;
SpawnHealer(16);
SetRndSeed(SEED);
const int N_ITEMS = RandomIntBetween(10, NumHealerItemsHf);
int n_items = NumHealerPinnedItems;
for (int i = 0; i < NumHealerPinnedItems; i++) {
EXPECT_EQ(HealerItems[i].IDidx, PINNED_ITEMS[i]) << "Index: " << i;
}
for (int i = NumHealerPinnedItems; i < NumHealerItemsHf; i++) {
if (HealerItems[i].isEmpty()) break;
EXPECT_THAT(HealerItems[i]._itype, Eq(ItemType::Misc));
EXPECT_THAT(HealerItems[i]._iMiscId, HealerMiscMatch(i));
n_items++;
EXPECT_EQ(HealerItems.size(), N_ITEMS);
EXPECT_LE(HealerItems.size(), NumHealerItemsHf);
for (size_t i = 0; i < HealerItems.size(); i++) {
if (i < NumHealerPinnedItems) {
EXPECT_EQ(HealerItems[i].IDidx, PINNED_ITEMS[i]) << "Index: " << i;
} else {
EXPECT_THAT(HealerItems[i]._itype, Eq(ItemType::Misc));
EXPECT_THAT(HealerItems[i]._iMiscId, HealerMiscMatch(i));
}
}
EXPECT_EQ(n_items, N_ITEMS);
}
} // namespace

Loading…
Cancel
Save