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);
|
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