Files
voxelforge/core/include/vf/LootTables.h
T

188 lines
6.6 KiB
C++

#pragma once
#include <cstdint>
#include <vector>
#include "Loot.h"
namespace vf {
// The item palette carries no shears, and correctToolFor already treats leaves
// as a hoe block, so the hoe is the shear class tool throughout the registry.
constexpr ToolType shearToolType = ToolType::Hoe;
constexpr int fishingBaseWaitTicks = 600;
constexpr int fishingMinWaitTicks = 100;
constexpr int fishingLureTicksPerLevel = 100;
constexpr int fishingFishWeight = 85;
constexpr int fishingTreasureWeight = 5;
constexpr int fishingJunkWeight = 10;
constexpr int fishingLuckWeightShift = 2;
// Harvest level a tier reaches. Gold sits at the wooden level, which is why a
// golden pickaxe cannot take a diamond.
int toolHarvestLevel(ToolTier tier);
// One authored row per block in the palette. `harvestTool` always names the tool
// class the block is broken with, whether or not a drop depends on it;
// `toolRequiredForDrop` is what actually gates the drop.
struct BlockDropRule {
Block block = Block::Air;
// ItemId::None means the block yields nothing. For the blocks added after
// the item palette froze at ItemId::Ladder that is a decision, not a gap:
// there is no item to hand out and none is invented.
ItemId drop = ItemId::None;
int minCount = 1;
int maxCount = 1;
ToolType harvestTool = ToolType::None;
ToolTier minimumTier = ToolTier::None;
bool toolRequiredForDrop = false;
// What Silk Touch takes instead; ItemId::None falls back to `drop`.
ItemId silkDrop = ItemId::None;
// Shear class tools take the silk drop too, without the enchantment.
bool shearHarvest = false;
// What comes out when the block breaks inside fire; ItemId::None means fire
// changes nothing.
ItemId firedDrop = ItemId::None;
// Ore style: Fortune multiplies the whole count.
bool fortuneMultiplies = false;
// Leaf style: Fortune improves the odds instead of the count.
float dropChance = 1.0f;
float chancePerFortune = 0.0f;
ItemId bonusDrop = ItemId::None;
float bonusChance = 0.0f;
int bonusMin = 1;
int bonusMax = 1;
ItemId silkTouchDrop() const { return silkDrop != ItemId::None ? silkDrop : drop; }
// Ice yields nothing when it is smashed but something when it is taken
// whole, so the silk branch has to count here too.
bool yieldsNothing() const {
return silkTouchDrop() == ItemId::None && bonusDrop == ItemId::None;
}
};
struct MobDropRule {
enum class Species : uint8_t {
Zombie, Husk, Drowned, ZombiePigman, Skeleton, Stray, Creeper, Witch, Spider, CaveSpider,
Blaze, Ghast, IronGolem, Villager, Sheep, Cow, Pig,
Count
};
Species species = Species::Zombie;
const char* name = "";
ItemId drop = ItemId::None;
int minCount = 0;
int maxCount = 0;
bool lootingRaisesCount = true;
bool dropNeedsPlayerKill = false;
// Cooked counterpart when the kill was fiery; ItemId::None means fire
// changes nothing.
ItemId firedDrop = ItemId::None;
ItemId rareDrop = ItemId::None;
float rareChance = 0.0f;
float rareChancePerLooting = 0.0f;
bool rareNeedsPlayerKill = true;
int experience = 0;
bool undead = false;
bool arthropod = false;
bool hostile = true;
};
struct ChestFill {
enum class Structure : uint8_t {
Village, Dungeon, Mineshaft, Temple, NetherFortress, EndShip,
Count
};
Structure structure = Structure::Village;
const char* name = "";
LootPool pool;
// How many chests one generated structure of this kind holds.
int chestsMin = 1;
int chestsMax = 1;
};
struct FishingLoot {
// EnchantKind has no Luck of the Sea and no Lure, so Fortune on the rod
// shifts the pool weights and Efficiency shortens the wait. The palette has
// no fish either: the catch pool hands back the raw meats it does have.
enum class Pool : uint8_t { Fish, Treasure, Junk, Count };
Pool pool = Pool::Fish;
LootRoll caught;
int waitTicks = 0;
// The weights the roll actually used, after the luck shift.
int fishWeight = 0;
int treasureWeight = 0;
int junkWeight = 0;
};
// A handle to any table in the registry, so a caller can hold on to one without
// caring which family it came from.
struct LootTableId {
enum class Domain : uint8_t { Block, Mob, Chest, Fishing, Count };
Domain domain = Domain::Block;
uint16_t index = 0;
static LootTableId ofBlock(Block block);
static LootTableId ofMob(MobDropRule::Species species);
static LootTableId ofChest(ChestFill::Structure structure);
static LootTableId ofFishing(FishingLoot::Pool pool);
bool valid() const;
bool operator==(const LootTableId& other) const {
return domain == other.domain && index == other.index;
}
bool operator!=(const LootTableId& other) const { return !(*this == other); }
};
// Whether the tool in hand clears the rule's tool class and harvest level.
bool toolAllows(const BlockDropRule& rule, ItemId tool);
// Rules expressed as the pools the shared roller in Loot.cpp understands.
LootTable blockRuleTable(const BlockDropRule& rule);
LootTable mobRuleTable(const MobDropRule& rule);
// Every block, mob, structure chest and fishing pool as data, authored one row
// per enum value and in enum order.
class LootRegistry {
public:
LootRegistry();
const BlockDropRule& blockRule(Block block) const;
const MobDropRule& mobRule(MobDropRule::Species species) const;
const ChestFill& chestFill(ChestFill::Structure structure) const;
const std::vector<BlockDropRule>& blockRules() const { return blocks; }
const std::vector<MobDropRule>& mobRules() const { return mobs; }
const std::vector<ChestFill>& chestFills() const { return chests; }
// Each of these checks the authored table is complete and in enum order.
bool coversEveryBlock() const;
bool coversEveryMob() const;
bool coversEveryStructure() const;
const LootTable& tableFor(LootTableId id) const;
LootRoll rollBlock(Block block, const LootContext& context) const;
LootRoll rollMob(MobDropRule::Species species, const LootContext& context) const;
LootRoll rollChest(ChestFill::Structure structure, const LootContext& context) const;
int chestCountFor(ChestFill::Structure structure, uint32_t seed) const;
FishingLoot rollFishing(const LootContext& context) const;
private:
std::vector<BlockDropRule> blocks;
std::vector<MobDropRule> mobs;
std::vector<ChestFill> chests;
std::vector<LootTable> blockTables;
std::vector<LootTable> mobTables;
std::vector<LootTable> chestTables;
std::vector<LootTable> fishingTables;
};
const LootRegistry& lootRegistry();
} // namespace vf