Files
voxelforge/core/src/LootTables.cpp
T

153 lines
4.9 KiB
C++

#include "vf/LootTables.h"
#include <algorithm>
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<int>(xorshift(rng) % static_cast<uint32_t>(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<BlockDropRule> buildBlockRules() {
std::vector<BlockDropRule> rules;
rules.reserve(static_cast<std::size_t>(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);