#include "vf/LootTables.h" #include namespace vf { namespace { constexpr uint32_t defaultLootSeed = 0x9e3779b9u; uint32_t xorshift(uint32_t& state) { state ^= state << 13; state ^= state >> 17; state ^= state << 5; return state; } int rollBelow(uint32_t& rng, int bound) { if (bound <= 1) return 0; return static_cast(xorshift(rng) % static_cast(bound)); } int rollBetween(uint32_t& rng, int low, int high) { if (high <= low) return low; return low + rollBelow(rng, high - low + 1); } void appendPool(LootTable& table, const LootEntry& entry) { LootPool pool; pool.entries.push_back(entry); table.pools.push_back(pool); } BlockDropRule plainRule(Block block, ItemId drop, ToolType tool) { BlockDropRule rule; rule.block = block; rule.drop = drop; rule.harvestTool = tool; return rule; } BlockDropRule selfRule(Block block, ToolType tool) { return plainRule(block, itemForBlock(block), tool); } BlockDropRule gatedRule(Block block, ItemId drop, ToolType tool, ToolTier tier) { BlockDropRule rule = plainRule(block, drop, tool); rule.minimumTier = tier; rule.toolRequiredForDrop = true; return rule; } BlockDropRule selfGatedRule(Block block, ToolType tool, ToolTier tier) { return gatedRule(block, itemForBlock(block), tool, tier); } BlockDropRule oreRule(Block block, ItemId raw, int minCount, int maxCount, ToolTier tier) { BlockDropRule rule = gatedRule(block, raw, ToolType::Pickaxe, tier); rule.minCount = minCount; rule.maxCount = maxCount; rule.silkDrop = itemForBlock(block); rule.fortuneMultiplies = true; return rule; } // Blocks the palette has no item for still carry a rule: it names the tool class // and harvest level, and records that the block yields nothing rather than // inventing an item that Item.h does not have. BlockDropRule barrenRule(Block block, ToolType tool) { return plainRule(block, ItemId::None, tool); } BlockDropRule barrenGatedRule(Block block, ToolType tool, ToolTier tier) { return gatedRule(block, ItemId::None, tool, tier); } // Wooden crafted blocks salvage back to the planks they were built from. BlockDropRule plankSalvage(Block block, int count = 1) { BlockDropRule rule = plainRule(block, ItemId::Planks, ToolType::Axe); rule.minCount = count; rule.maxCount = count; return rule; } // The palette carries exactly one broken stone item, so the overworld stone // family salvages to cobblestone. BlockDropRule stoneSalvage(Block block) { return gatedRule(block, ItemId::Cobblestone, ToolType::Pickaxe, ToolTier::Wood); } std::vector buildBlockRules() { std::vector rules; rules.reserve(static_cast(Block::Count)); auto add = [&rules](const BlockDropRule& rule) { rules.push_back(rule); }; add(barrenRule(Block::Air, ToolType::None)); BlockDropRule grass = plainRule(Block::Grass, ItemId::Dirt, ToolType::Shovel); grass.silkDrop = ItemId::Grass; add(grass); add(selfRule(Block::Dirt, ToolType::Shovel)); BlockDropRule stone = gatedRule(Block::Stone, ItemId::Cobblestone, ToolType::Pickaxe, ToolTier::Wood); stone.silkDrop = ItemId::Stone; stone.firedDrop = ItemId::Stone; add(stone); add(selfRule(Block::Sand, ToolType::Shovel)); add(selfRule(Block::Wood, ToolType::Axe)); // No sapling in the palette, so a wood cutting stands in as the replantable // drop, the way the salvaged leaf table already does. BlockDropRule leaves = plainRule(Block::Leaves, ItemId::Wood, shearToolType); leaves.dropChance = 0.05f; leaves.chancePerFortune = 0.04f; leaves.silkDrop = ItemId::Leaves; leaves.shearHarvest = true; leaves.bonusDrop = ItemId::Stick; leaves.bonusChance = 0.02f; leaves.bonusMax = 2; add(leaves); add(barrenRule(Block::Water, ToolType::None)); add(selfRule(Block::Snow, ToolType::Shovel)); add(oreRule(Block::CoalOre, ItemId::CoalLump, 1, 1, ToolTier::Wood)); BlockDropRule ironOre = oreRule(Block::IronOre, ItemId::IronOre, 1, 1, ToolTier::Stone); ironOre.firedDrop = ItemId::IronIngot; add(ironOre); BlockDropRule goldOre = oreRule(Block::GoldOre, ItemId::GoldOre, 1, 1, ToolTier::Iron); goldOre.firedDrop = ItemId::GoldIngot; add(goldOre); add(selfRule(Block::Gravel, ToolType::Shovel)); BlockDropRule glowstone = oreRule(Block::Glowstone, ItemId::Glowstone, 2, 4, ToolTier::None); glowstone.toolRequiredForDrop = false; add(glowstone); BlockDropRule cobblestone = selfGatedRule(Block::Cobblestone, ToolType::Pickaxe, ToolTier::Wood); cobblestone.firedDrop = ItemId::Stone; add(cobblestone); add(selfRule(Block::Planks, ToolType::Axe)); add(selfGatedRule(Block::Sandstone, ToolType::Pickaxe, ToolTier::Wood)); // Ice melts away unless it is taken whole. BlockDropRule ice = barrenRule(Block::Ice, ToolType::Pickaxe); ice.silkDrop = ItemId::Ice; add(ice);