test: cover testLootTables
This commit is contained in:
1 parent
ad73588190
commit
b4aae0528a
1 file changed
+157
@@ -160,3 +160,160 @@ VF_TEST(theRegistryIsNeverMorePermissiveThanTheSalvagedToolCheck) {
|
||||
CHECK(gatedCases > 100);
|
||||
}
|
||||
|
||||
VF_TEST(harvestLevelsGateTheOresExactlyWhereTheTiersSay) {
|
||||
CHECK_EQ(toolHarvestLevel(ToolTier::None), 0);
|
||||
CHECK_EQ(toolHarvestLevel(ToolTier::Wood), 1);
|
||||
CHECK_EQ(toolHarvestLevel(ToolTier::Gold), 1);
|
||||
CHECK_EQ(toolHarvestLevel(ToolTier::Stone), 2);
|
||||
CHECK_EQ(toolHarvestLevel(ToolTier::Iron), 3);
|
||||
CHECK_EQ(toolHarvestLevel(ToolTier::Diamond), 4);
|
||||
|
||||
const LootRegistry& registry = lootRegistry();
|
||||
const struct { Block block; ItemId tool; bool allowed; } cases[] = {
|
||||
{Block::Stone, ItemId::None, false},
|
||||
{Block::Stone, ItemId::DiamondShovel, false},
|
||||
{Block::Stone, ItemId::WoodPickaxe, true},
|
||||
{Block::IronOre, ItemId::WoodPickaxe, false},
|
||||
{Block::IronOre, ItemId::GoldPickaxe, false},
|
||||
{Block::IronOre, ItemId::StonePickaxe, true},
|
||||
{Block::DiamondOre, ItemId::StonePickaxe, false},
|
||||
{Block::DiamondOre, ItemId::IronPickaxe, true},
|
||||
{Block::Obsidian, ItemId::IronPickaxe, false},
|
||||
{Block::Obsidian, ItemId::DiamondPickaxe, true},
|
||||
{Block::CryingObsidian, ItemId::IronPickaxe, false},
|
||||
{Block::CopperOre, ItemId::WoodPickaxe, false},
|
||||
{Block::CopperOre, ItemId::StonePickaxe, true},
|
||||
{Block::Dirt, ItemId::None, true},
|
||||
{Block::Wood, ItemId::None, true},
|
||||
};
|
||||
for (const auto& item : cases) {
|
||||
CHECK_EQ(toolAllows(registry.blockRule(item.block), item.tool), item.allowed);
|
||||
}
|
||||
|
||||
CHECK(registry.rollBlock(Block::Obsidian, contextWith(ItemId::IronPickaxe, 9u)).empty());
|
||||
CHECK_EQ(registry.rollBlock(Block::Obsidian, contextWith(ItemId::DiamondPickaxe, 9u))
|
||||
.countOf(ItemId::Obsidian),
|
||||
1);
|
||||
}
|
||||
|
||||
VF_TEST(stoneBecomesCobblestoneUnlessItIsTakenWholeOrBrokenInsideFire) {
|
||||
const LootRegistry& registry = lootRegistry();
|
||||
|
||||
LootContext plain = contextWith(ItemId::IronPickaxe, 17u);
|
||||
CHECK_EQ(registry.rollBlock(Block::Stone, plain).countOf(ItemId::Cobblestone), 1);
|
||||
|
||||
LootContext silk = enchantedWith(ItemId::IronPickaxe, EnchantKind::SilkTouch, 1, 17u);
|
||||
LootRoll harvested = registry.rollBlock(Block::Stone, silk);
|
||||
CHECK_EQ(harvested.countOf(ItemId::Stone), 1);
|
||||
CHECK_EQ(harvested.totalCount(), 1);
|
||||
|
||||
LootContext burning = contextWith(ItemId::IronPickaxe, 17u);
|
||||
burning.fiery = true;
|
||||
LootRoll melted = registry.rollBlock(Block::Stone, burning);
|
||||
CHECK_EQ(melted.countOf(ItemId::Stone), 1);
|
||||
CHECK_EQ(melted.countOf(ItemId::Cobblestone), 0);
|
||||
|
||||
// Cobblestone bakes back into stone the same way, and iron and gold ore
|
||||
// come out as ingots.
|
||||
LootRoll cobble = registry.rollBlock(Block::Cobblestone, burning);
|
||||
CHECK_EQ(cobble.countOf(ItemId::Stone), 1);
|
||||
CHECK_EQ(registry.rollBlock(Block::IronOre, burning).countOf(ItemId::IronIngot), 1);
|
||||
CHECK_EQ(registry.rollBlock(Block::GoldOre, burning).countOf(ItemId::GoldIngot), 1);
|
||||
CHECK_EQ(registry.rollBlock(Block::IronOre, plain).countOf(ItemId::IronOre), 1);
|
||||
}
|
||||
|
||||
VF_TEST(oreRulesMultiplyWithFortuneAndHandBackTheOreBlockUnderSilkTouch) {
|
||||
const LootRegistry& registry = lootRegistry();
|
||||
const struct { Block block; ItemId raw; int lowest; int highest; } ores[] = {
|
||||
{Block::CoalOre, ItemId::CoalLump, 1, 1},
|
||||
{Block::DiamondOre, ItemId::DiamondGem, 1, 1},
|
||||
{Block::RedstoneOre, ItemId::RedstoneDust, 4, 5},
|
||||
{Block::LapisOre, ItemId::LapisLazuli, 4, 9},
|
||||
{Block::Glowstone, ItemId::Glowstone, 2, 4},
|
||||
};
|
||||
for (const auto& ore : ores) {
|
||||
int seenLowest = 1000;
|
||||
int seenHighest = 0;
|
||||
int fortuneHighest = 0;
|
||||
for (int i = 0; i < 500; ++i) {
|
||||
LootContext plain = contextWith(ItemId::DiamondPickaxe, seedFor(i));
|
||||
int count = registry.rollBlock(ore.block, plain).countOf(ore.raw);
|
||||
seenLowest = std::min(seenLowest, count);
|
||||
seenHighest = std::max(seenHighest, count);
|
||||
|
||||
LootContext lucky = enchantedWith(ItemId::DiamondPickaxe, EnchantKind::Fortune, 3,
|
||||
seedFor(i));
|
||||
fortuneHighest = std::max(fortuneHighest,
|
||||
registry.rollBlock(ore.block, lucky).countOf(ore.raw));
|
||||
}
|
||||
CHECK_EQ(seenLowest, ore.lowest);
|
||||
CHECK_EQ(seenHighest, ore.highest);
|
||||
CHECK_EQ(fortuneHighest, ore.highest * 4);
|
||||
|
||||
LootContext silk = enchantedWith(ItemId::DiamondPickaxe, EnchantKind::SilkTouch, 1, 5u);
|
||||
LootRoll whole = registry.rollBlock(ore.block, silk);
|
||||
CHECK_EQ(whole.countOf(itemForBlock(ore.block)), 1);
|
||||
CHECK_EQ(whole.totalCount(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
VF_TEST(shearClassToolsTakeTheBlockItselfWithoutNeedingSilkTouch) {
|
||||
const LootRegistry& registry = lootRegistry();
|
||||
|
||||
for (ItemId hoe : {ItemId::WoodHoe, ItemId::DiamondHoe}) {
|
||||
LootRoll sheared = registry.rollBlock(Block::Leaves, contextWith(hoe, 42u));
|
||||
CHECK_EQ(sheared.countOf(ItemId::Leaves), 1);
|
||||
CHECK_EQ(sheared.totalCount(), 1);
|
||||
}
|
||||
|
||||
// A pickaxe falls through to the chance table instead.
|
||||
int leafBlocks = 0;
|
||||
int cuttings = 0;
|
||||
for (int i = 0; i < 800; ++i) {
|
||||
LootRoll roll = registry.rollBlock(Block::Leaves,
|
||||
contextWith(ItemId::IronPickaxe, seedFor(i)));
|
||||
leafBlocks += roll.countOf(ItemId::Leaves);
|
||||
cuttings += roll.countOf(ItemId::Wood);
|
||||
}
|
||||
CHECK_EQ(leafBlocks, 0);
|
||||
CHECK(cuttings > 0);
|
||||
|
||||
// Shearing a block the palette has no item for still yields nothing.
|
||||
for (Block block : {Block::Wool, Block::Cobweb, Block::Vine, Block::Kelp, Block::Moss}) {
|
||||
CHECK(registry.blockRule(block).shearHarvest);
|
||||
CHECK(registry.rollBlock(block, contextWith(ItemId::DiamondHoe, 8u)).empty());
|
||||
}
|
||||
}
|
||||
|
||||
VF_TEST(everyBlockRuleOnlyEverProducesItemsItDeclaredUpFront) {
|
||||
const LootRegistry& registry = lootRegistry();
|
||||
int strayItems = 0;
|
||||
int rollsMade = 0;
|
||||
|
||||
for (int index = 0; index < static_cast<int>(Block::Count); ++index) {
|
||||
Block block = static_cast<Block>(index);
|
||||
const BlockDropRule& rule = registry.blockRule(block);
|
||||
|
||||
for (int sample = 0; sample < 12; ++sample) {
|
||||
LootContext context = contextWith(bestToolFor(rule.harvestTool), seedFor(sample));
|
||||
if (sample % 3 == 1) addEnchant(context.toolEnchants, EnchantKind::SilkTouch, 1);
|
||||
if (sample % 3 == 2) addEnchant(context.toolEnchants, EnchantKind::Fortune, 3);
|
||||
if (sample % 4 == 3) context.fiery = true;
|
||||
|
||||
LootRoll roll = registry.rollBlock(block, context);
|
||||
++rollsMade;
|
||||
for (const ItemSlot& stack : roll.items) {
|
||||
if (!ruleCanYield(rule, stack.item)) ++strayItems;
|
||||
if (stack.count <= 0) ++strayItems;
|
||||
}
|
||||
}
|
||||
}
|
||||
CHECK_EQ(strayItems, 0);
|
||||
CHECK_EQ(rollsMade, static_cast<int>(Block::Count) * 12);
|
||||
}
|
||||
|
||||
VF_TEST(everyBlockThatDeclaresACertainDropActuallyHandsItOver) {
|
||||
const LootRegistry& registry = lootRegistry();
|
||||
int certainDrops = 0;
|
||||
int missed = 0;
|
||||
|
||||
Reference in new issue
Block a user