test: cover makeShopWorld and makeLibrarian
This commit is contained in:
1 parent
522662ded6
commit
5fba3c338a
1 file changed
+159
@@ -0,0 +1,159 @@
|
||||
#include "testHarness.h"
|
||||
#include "vf/Trade.h"
|
||||
|
||||
using namespace vf;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int groundTop = 4;
|
||||
constexpr int walkY = groundTop + 1;
|
||||
const Vec3i villageCenter{0, walkY, 0};
|
||||
|
||||
// Index of the fixed "4 emeralds for one comparator" librarian offer: the one
|
||||
// entry whose counts the seed jitter leaves alone, so prices are exact.
|
||||
constexpr int comparatorOffer = 5;
|
||||
|
||||
World makeShopWorld() {
|
||||
World world;
|
||||
for (int x = -12; x <= 12; ++x)
|
||||
for (int z = -12; z <= 12; ++z)
|
||||
for (int y = 0; y <= groundTop; ++y)
|
||||
world.setBlock(x, y, z, Block::Stone);
|
||||
world.setBlock(-4, walkY, 0, Block::Lectern);
|
||||
world.setBlock(4, walkY, 0, Block::Bed);
|
||||
return world;
|
||||
}
|
||||
|
||||
Villager makeLibrarian(int level) {
|
||||
Villager villager = makeVillager(1, {-1.5f, static_cast<float>(walkY), 0.5f}, 17u);
|
||||
villager.profession = VillagerProfession::Librarian;
|
||||
villager.level = level;
|
||||
villager.experience = villagerExperienceForLevel(level);
|
||||
return villager;
|
||||
}
|
||||
|
||||
Container makeWallet(int emeralds) {
|
||||
Container inventory(27);
|
||||
inventory.insert(ItemId::EmeraldGem, emeralds);
|
||||
return inventory;
|
||||
}
|
||||
|
||||
int stockOf(const Container& inventory, ItemId item) {
|
||||
int total = 0;
|
||||
for (int i = 0; i < inventory.size(); ++i) {
|
||||
const ItemSlot& slot = inventory.slot(i);
|
||||
if (!slot.empty() && slot.item == item) total += slot.count;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
int firstOfferWithTier(const TradeOfferList& list, TradeTier tier) {
|
||||
for (int i = 0; i < list.size(); ++i)
|
||||
if (list.at(i).tier == tier) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
VF_TEST(offerTableIsIdenticalForTheSameProfessionAndSeedAndMovesWithTheSeed) {
|
||||
TradeOfferList a = buildTradeOffers(VillagerProfession::Librarian, 99u);
|
||||
TradeOfferList b = buildTradeOffers(VillagerProfession::Librarian, 99u);
|
||||
CHECK_EQ(a.size(), b.size());
|
||||
bool identical = true;
|
||||
for (int i = 0; i < a.size(); ++i) {
|
||||
if (a.at(i).inputACount != b.at(i).inputACount) identical = false;
|
||||
if (a.at(i).outputCount != b.at(i).outputCount) identical = false;
|
||||
if (a.at(i).output != b.at(i).output) identical = false;
|
||||
}
|
||||
CHECK(identical);
|
||||
|
||||
TradeOfferList other = buildTradeOffers(VillagerProfession::Librarian, 4242u);
|
||||
bool differs = false;
|
||||
for (int i = 0; i < a.size(); ++i)
|
||||
if (a.at(i).inputACount != other.at(i).inputACount ||
|
||||
a.at(i).outputCount != other.at(i).outputCount) differs = true;
|
||||
CHECK(differs);
|
||||
|
||||
for (int i = 0; i < a.size(); ++i) {
|
||||
CHECK(a.at(i).inputACount >= 1);
|
||||
CHECK(a.at(i).outputCount >= 1);
|
||||
CHECK(a.at(i).output != ItemId::None);
|
||||
CHECK(a.at(i).inputA != ItemId::None);
|
||||
}
|
||||
}
|
||||
|
||||
VF_TEST(everyTradingProfessionCoversAllFiveTiersWhileNitwitsOfferNothing) {
|
||||
for (int raw = 2; raw < static_cast<int>(VillagerProfession::Count); ++raw) {
|
||||
VillagerProfession profession = static_cast<VillagerProfession>(raw);
|
||||
TradeOfferList list = buildTradeOffers(profession, 7u);
|
||||
CHECK_EQ(list.size(), 8);
|
||||
CHECK(list.profession == profession);
|
||||
for (int tier = 0; tier < static_cast<int>(TradeTier::Count); ++tier)
|
||||
CHECK(list.countForTier(static_cast<TradeTier>(tier)) >= 1);
|
||||
CHECK_EQ(list.unlockedCount(1), list.countForTier(TradeTier::Novice));
|
||||
CHECK_EQ(list.unlockedCount(villagerMaxLevel), list.size());
|
||||
}
|
||||
|
||||
CHECK_EQ(buildTradeOffers(VillagerProfession::Nitwit, 7u).size(), 0);
|
||||
CHECK_EQ(buildTradeOffers(VillagerProfession::Unemployed, 7u).size(), 0);
|
||||
}
|
||||
|
||||
VF_TEST(lockedTiersRefuseTheTradeUntilTheVillagerHasLevelledUp) {
|
||||
Villager villager = makeLibrarian(1);
|
||||
TradeOfferList offers = buildTradeOffers(VillagerProfession::Librarian, 1u);
|
||||
Container wallet = makeWallet(200);
|
||||
TradeSession session(villager, offers, wallet);
|
||||
|
||||
int masterOffer = firstOfferWithTier(offers, TradeTier::Master);
|
||||
CHECK(masterOffer >= 0);
|
||||
CHECK(!session.available(masterOffer));
|
||||
TradeResult locked = session.trade(masterOffer);
|
||||
CHECK(!locked.success);
|
||||
CHECK(locked.reason == TradeResult::Reason::LevelLocked);
|
||||
CHECK_EQ(stockOf(wallet, ItemId::EmeraldGem), 200);
|
||||
|
||||
villager.level = villagerMaxLevel;
|
||||
CHECK(session.available(masterOffer));
|
||||
TradeResult unlocked = session.trade(masterOffer);
|
||||
CHECK(unlocked.success);
|
||||
CHECK(unlocked.received == ItemId::DiamondGem);
|
||||
CHECK_EQ(stockOf(wallet, ItemId::DiamondGem), unlocked.receivedCount);
|
||||
}
|
||||
|
||||
VF_TEST(repeatedTradesRaiseThePriceThroughRisingDemand) {
|
||||
Villager villager = makeLibrarian(3);
|
||||
TradeOfferList offers = buildTradeOffers(VillagerProfession::Librarian, 1u);
|
||||
Container wallet = makeWallet(400);
|
||||
TradeSession session(villager, offers, wallet);
|
||||
|
||||
CHECK(offers.at(comparatorOffer).tier == TradeTier::Journeyman);
|
||||
CHECK(offers.at(comparatorOffer).output == ItemId::Comparator);
|
||||
int basePrice = offers.at(comparatorOffer).basePrice();
|
||||
CHECK_EQ(session.priceOf(comparatorOffer), basePrice);
|
||||
|
||||
int firstPrice = session.priceOf(comparatorOffer);
|
||||
int trades = 0;
|
||||
int lastPrice = firstPrice;
|
||||
while (session.available(comparatorOffer)) {
|
||||
int price = session.priceOf(comparatorOffer);
|
||||
CHECK(price >= lastPrice);
|
||||
lastPrice = price;
|
||||
TradeResult outcome = session.trade(comparatorOffer);
|
||||
CHECK(outcome.success);
|
||||
CHECK_EQ(outcome.pricePaid, price);
|
||||
++trades;
|
||||
}
|
||||
|
||||
CHECK_EQ(trades, offers.at(comparatorOffer).maxUses);
|
||||
CHECK_EQ(offers.at(comparatorOffer).demand, trades * tradeDemandPerUse);
|
||||
CHECK(lastPrice > firstPrice);
|
||||
CHECK_EQ(stockOf(wallet, ItemId::Comparator), trades);
|
||||
CHECK(session.trade(comparatorOffer).reason == TradeResult::Reason::OfferExhausted);
|
||||
}
|
||||
|
||||
VF_TEST(restockRefillsUsesAndLetsDemandAndPriceFallBack) {
|
||||
Villager villager = makeLibrarian(3);
|
||||
TradeOfferList offers = buildTradeOffers(VillagerProfession::Librarian, 1u);
|
||||
Container wallet = makeWallet(400);
|
||||
TradeSession session(villager, offers, wallet);
|
||||
|
||||
Reference in new issue
Block a user