test: add more cases for testLootTables
This commit is contained in:
1 parent
2d5ad51975
commit
d87424e3c4
1 file changed
+165
@@ -478,3 +478,168 @@ VF_TEST(ironGolemsIgnoreLootingWhileZombiesDoNot) {
|
||||
LootContext looted = plain;
|
||||
addEnchant(looted.toolEnchants, EnchantKind::Looting, 3);
|
||||
|
||||
int golem = registry.rollMob(Species::IronGolem, plain).countOf(ItemId::IronIngot);
|
||||
golemLowest = std::min(golemLowest, golem);
|
||||
golemHighest = std::max(golemHighest, golem);
|
||||
golemLootedHighest = std::max(golemLootedHighest,
|
||||
registry.rollMob(Species::IronGolem, looted)
|
||||
.countOf(ItemId::IronIngot));
|
||||
|
||||
zombieHighest = std::max(zombieHighest,
|
||||
registry.rollMob(Species::Zombie, plain)
|
||||
.countOf(ItemId::RottenFlesh));
|
||||
zombieLootedHighest = std::max(zombieLootedHighest,
|
||||
registry.rollMob(Species::Zombie, looted)
|
||||
.countOf(ItemId::RottenFlesh));
|
||||
}
|
||||
CHECK_EQ(golemLowest, 3);
|
||||
CHECK_EQ(golemHighest, 5);
|
||||
CHECK_EQ(golemLootedHighest, 5);
|
||||
CHECK_EQ(zombieHighest, 2);
|
||||
CHECK_EQ(zombieLootedHighest, 5);
|
||||
}
|
||||
|
||||
VF_TEST(villagersLeaveNothingBehindAndSayItInTheirRule) {
|
||||
const LootRegistry& registry = lootRegistry();
|
||||
const MobDropRule& villager = registry.mobRule(Species::Villager);
|
||||
CHECK_EQ(villager.drop, ItemId::None);
|
||||
CHECK_EQ(villager.rareDrop, ItemId::None);
|
||||
CHECK(!villager.hostile);
|
||||
CHECK(mobRuleTable(villager).empty());
|
||||
|
||||
for (int i = 0; i < 200; ++i) {
|
||||
LootContext context = enchantedWith(ItemId::DiamondSword, EnchantKind::Looting, 3,
|
||||
seedFor(i));
|
||||
context.playerKill = true;
|
||||
CHECK(registry.rollMob(Species::Villager, context).empty());
|
||||
}
|
||||
}
|
||||
|
||||
VF_TEST(everyStructureChestFillsInsideItsDeclaredBoundsAndOnlyFromItsOwnPool) {
|
||||
const LootRegistry& registry = lootRegistry();
|
||||
const struct { Structure structure; int lowest; int highest; } bounds[] = {
|
||||
{Structure::Village, 3, 20}, {Structure::Dungeon, 2, 16},
|
||||
{Structure::Mineshaft, 3, 40}, {Structure::Temple, 2, 32},
|
||||
{Structure::NetherFortress, 2, 20}, {Structure::EndShip, 2, 18},
|
||||
};
|
||||
for (const auto& entry : bounds) {
|
||||
const ChestFill& fill = registry.chestFill(entry.structure);
|
||||
CHECK_EQ(fill.structure, entry.structure);
|
||||
CHECK(!fill.pool.entries.empty());
|
||||
|
||||
int seenLowest = 1000;
|
||||
int seenHighest = 0;
|
||||
int strayItems = 0;
|
||||
for (int i = 0; i < 700; ++i) {
|
||||
LootRoll roll = registry.rollChest(entry.structure, contextWith(ItemId::None,
|
||||
seedFor(i)));
|
||||
seenLowest = std::min(seenLowest, roll.totalCount());
|
||||
seenHighest = std::max(seenHighest, roll.totalCount());
|
||||
for (const ItemSlot& stack : roll.items) {
|
||||
if (!poolCanYield(fill.pool, stack.item)) ++strayItems;
|
||||
}
|
||||
}
|
||||
CHECK_EQ(strayItems, 0);
|
||||
CHECK(seenLowest >= entry.lowest);
|
||||
CHECK(seenHighest <= entry.highest);
|
||||
CHECK(seenHighest > seenLowest);
|
||||
}
|
||||
CHECK(registry.rollChest(Structure::Count, contextWith(ItemId::None, 1u)).empty());
|
||||
}
|
||||
|
||||
VF_TEST(structureChestCountsStayInsideTheRangeTheStructureDeclares) {
|
||||
const LootRegistry& registry = lootRegistry();
|
||||
for (int index = 0; index < static_cast<int>(Structure::Count); ++index) {
|
||||
Structure structure = static_cast<Structure>(index);
|
||||
const ChestFill& fill = registry.chestFill(structure);
|
||||
CHECK(fill.chestsMin >= 1);
|
||||
CHECK(fill.chestsMax >= fill.chestsMin);
|
||||
|
||||
int seenLowest = 1000;
|
||||
int seenHighest = 0;
|
||||
for (int i = 0; i < 400; ++i) {
|
||||
int count = registry.chestCountFor(structure, seedFor(i));
|
||||
seenLowest = std::min(seenLowest, count);
|
||||
seenHighest = std::max(seenHighest, count);
|
||||
}
|
||||
CHECK_EQ(seenLowest, fill.chestsMin);
|
||||
CHECK_EQ(seenHighest, fill.chestsMax);
|
||||
CHECK_EQ(registry.chestCountFor(structure, 77u), registry.chestCountFor(structure, 77u));
|
||||
}
|
||||
CHECK_EQ(registry.chestCountFor(Structure::Count, 5u), 0);
|
||||
}
|
||||
|
||||
VF_TEST(diamondGearOnlyTurnsUpInTheEndShipAndPickaxesOnlyInMineshafts) {
|
||||
const LootRegistry& registry = lootRegistry();
|
||||
int endShipSwords = 0;
|
||||
int mineshaftPickaxes = 0;
|
||||
int elsewhereGear = 0;
|
||||
|
||||
for (int index = 0; index < static_cast<int>(Structure::Count); ++index) {
|
||||
Structure structure = static_cast<Structure>(index);
|
||||
for (int i = 0; i < 600; ++i) {
|
||||
LootRoll roll = registry.rollChest(structure, contextWith(ItemId::None, seedFor(i)));
|
||||
int swords = roll.countOf(ItemId::DiamondSword);
|
||||
int pickaxes = roll.countOf(ItemId::IronPickaxe);
|
||||
if (structure == Structure::EndShip) {
|
||||
endShipSwords += swords;
|
||||
} else {
|
||||
elsewhereGear += swords;
|
||||
}
|
||||
if (structure == Structure::Mineshaft) {
|
||||
mineshaftPickaxes += pickaxes;
|
||||
} else {
|
||||
elsewhereGear += pickaxes;
|
||||
}
|
||||
}
|
||||
}
|
||||
CHECK(endShipSwords > 0);
|
||||
CHECK(mineshaftPickaxes > 0);
|
||||
CHECK_EQ(elsewhereGear, 0);
|
||||
}
|
||||
|
||||
VF_TEST(fishingSplitsIntoThreePoolsAndLuckShiftsTheWeightsAwayFromJunk) {
|
||||
const LootRegistry& registry = lootRegistry();
|
||||
int plainFish = 0;
|
||||
int plainTreasure = 0;
|
||||
int plainJunk = 0;
|
||||
int luckyTreasure = 0;
|
||||
int luckyJunk = 0;
|
||||
|
||||
for (int i = 0; i < 4000; ++i) {
|
||||
FishingLoot plain = registry.rollFishing(contextWith(ItemId::WoodHoe, seedFor(i)));
|
||||
CHECK_EQ(plain.fishWeight, fishingFishWeight);
|
||||
CHECK_EQ(plain.treasureWeight, fishingTreasureWeight);
|
||||
CHECK_EQ(plain.junkWeight, fishingJunkWeight);
|
||||
if (plain.pool == FishingLoot::Pool::Fish) ++plainFish;
|
||||
if (plain.pool == FishingLoot::Pool::Treasure) ++plainTreasure;
|
||||
if (plain.pool == FishingLoot::Pool::Junk) ++plainJunk;
|
||||
|
||||
FishingLoot lucky = registry.rollFishing(
|
||||
enchantedWith(ItemId::WoodHoe, EnchantKind::Fortune, 3, seedFor(i)));
|
||||
CHECK_EQ(lucky.treasureWeight, fishingTreasureWeight + 3 * fishingLuckWeightShift);
|
||||
CHECK_EQ(lucky.junkWeight, fishingJunkWeight - 3 * fishingLuckWeightShift);
|
||||
if (lucky.pool == FishingLoot::Pool::Treasure) ++luckyTreasure;
|
||||
if (lucky.pool == FishingLoot::Pool::Junk) ++luckyJunk;
|
||||
}
|
||||
CHECK(plainFish > plainTreasure + plainJunk);
|
||||
CHECK(plainTreasure > 0);
|
||||
CHECK(plainJunk > 0);
|
||||
CHECK(luckyTreasure > plainTreasure);
|
||||
CHECK(luckyJunk < plainJunk);
|
||||
|
||||
// An over-cap Fortune cannot come from addEnchant, but it can be placed on
|
||||
// a set by hand, and it must clamp the junk weight at nothing rather than
|
||||
// going negative and eating the treasure band.
|
||||
int junkAtHighLuck = 0;
|
||||
for (int i = 0; i < 500; ++i) {
|
||||
LootContext overCharged = contextWith(ItemId::WoodHoe, seedFor(i));
|
||||
overCharged.toolEnchants.entries.push_back({EnchantKind::Fortune, 9});
|
||||
FishingLoot outcome = registry.rollFishing(overCharged);
|
||||
CHECK_EQ(outcome.junkWeight, 0);
|
||||
CHECK_EQ(outcome.treasureWeight, fishingTreasureWeight + 9 * fishingLuckWeightShift);
|
||||
if (outcome.pool == FishingLoot::Pool::Junk) ++junkAtHighLuck;
|
||||
}
|
||||
CHECK_EQ(junkAtHighLuck, 0);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user