feat: add lootContextFor and smeltedForm to Loot

This commit is contained in:
dualfroz committed 2026-09-08 16:10:36 +02:00
1 parent ff147c2440
commit 35644f9771
1 file changed
+111
+111
View File
@@ -314,3 +314,114 @@ int LootRoll::totalCount() const {
return total; return total;
} }
LootContext lootContextFor(const HurtSource& source, ItemId tool, const EnchantSet& toolEnchants,
uint32_t seed) {
LootContext context;
context.seed = seed != 0 ? seed : 0x9e3779b9u;
context.killedBy = source.type;
context.fiery = source.fiery || isFireDamage(source.type);
context.playerKill = source.byPlayer;
context.tool = tool;
context.toolEnchants = toolEnchants;
return context;
}
ItemId smeltedForm(ItemId raw) {
switch (raw) {
case ItemId::RawPorkchop: return ItemId::CookedPorkchop;
case ItemId::RawBeef: return ItemId::CookedBeef;
case ItemId::RawMutton: return ItemId::CookedMutton;
case ItemId::IronOre: return ItemId::IronIngot;
case ItemId::GoldOre: return ItemId::GoldIngot;
default: return raw;
}
}
bool toolQualifiesFor(Block block, ItemId tool) {
if (correctToolFor(block) != ToolType::Pickaxe) return true;
const ItemInfo& info = itemInfo(tool);
if (info.toolType != ToolType::Pickaxe) return false;
switch (block) {
case Block::DiamondOre:
case Block::EmeraldOre:
case Block::GoldOre:
return info.toolTier == ToolTier::Iron || info.toolTier == ToolTier::Diamond;
case Block::IronOre:
case Block::LapisOre:
case Block::RedstoneOre:
return info.toolTier != ToolTier::Wood && info.toolTier != ToolTier::Gold;
default:
return true;
}
}
const LootTable& blockLootTable(Block block) {
static const std::vector<LootTable> tables = buildBlockTables();
if (block >= Block::Count) return emptyTable();
return tables[static_cast<std::size_t>(block)];
}
const LootTable& mobLootTable(LootTable::MobKind kind) {
static const std::vector<LootTable> tables = {
zombieTable(),
skeletonTable(),
creeperTable(),
meatTable(ItemId::RawMutton, 1, 2),
meatTable(ItemId::RawBeef, 1, 3),
meatTable(ItemId::RawPorkchop, 1, 3),
};
if (kind >= LootTable::MobKind::Count) return emptyTable();
return tables[static_cast<std::size_t>(kind)];
}
const LootTable& chestLootTable(LootTable::ChestKind kind) {
static const std::vector<LootTable> tables = {
dungeonChestTable(),
villageChestTable(),
templeChestTable(),
};
if (kind >= LootTable::ChestKind::Count) return emptyTable();
return tables[static_cast<std::size_t>(kind)];
}
LootRoll rollLootTable(const LootTable& table, const LootContext& context) {
LootRoll roll;
uint32_t rng = context.seed != 0 ? context.seed : 0x9e3779b9u;
for (const LootPool& pool : table.pools) {
int rolls = rollBetween(rng, pool.minRolls, pool.maxRolls);
rolls += pool.bonusRollsPerLooting * context.looting();
for (int r = 0; r < rolls; ++r) {
int totalWeight = 0;
for (const LootEntry& entry : pool.entries) {
if (conditionsPass(entry, context)) totalWeight += entry.weight;
}
if (totalWeight <= 0) continue;
int pick = rollBelow(rng, totalWeight);
for (const LootEntry& entry : pool.entries) {
if (!conditionsPass(entry, context)) continue;
pick -= entry.weight;
if (pick >= 0) continue;
emitEntry(roll, entry, context, rng);
break;
}
}
}
return roll;
}
LootRoll rollBlockDrops(Block block, const LootContext& context) {
if (!toolQualifiesFor(block, context.tool)) return {};
return rollLootTable(blockLootTable(block), context);
}
LootRoll rollMobDrops(LootTable::MobKind kind, const LootContext& context) {
return rollLootTable(mobLootTable(kind), context);
}
LootRoll rollChestContents(LootTable::ChestKind kind, const LootContext& context) {
return rollLootTable(chestLootTable(kind), context);
}
} // namespace vf