diff --git a/core/src/LootTables.cpp b/core/src/LootTables.cpp index 912565f..357bd05 100644 --- a/core/src/LootTables.cpp +++ b/core/src/LootTables.cpp @@ -471,3 +471,162 @@ std::vector buildChestFills() { chestEntry(ItemId::GoldSword, 5, 1, 1), chestEntry(ItemId::DiamondGem, 2, 1, 3)})); + fills.push_back(chestFillOf(Structure::EndShip, "endShip", 2, 3, 1, 1, + {chestEntry(ItemId::DiamondGem, 5, 1, 3), + chestEntry(ItemId::EmeraldGem, 5, 1, 3), + chestEntry(ItemId::GoldIngot, 5, 1, 6), + chestEntry(ItemId::IronIngot, 5, 1, 6), + chestEntry(ItemId::DiamondSword, 2, 1, 1), + chestEntry(ItemId::DiamondPickaxe, 2, 1, 1)})); + return fills; +} + +std::vector buildFishingTables() { + std::vector tables; + + LootPool fish; + fish.entries = {chestEntry(ItemId::RawPorkchop, 34, 1, 1), chestEntry(ItemId::RawBeef, 33, 1, 1), + chestEntry(ItemId::RawMutton, 33, 1, 1)}; + + LootPool treasure; + treasure.entries = {chestEntry(ItemId::GoldIngot, 25, 1, 1), + chestEntry(ItemId::LapisLazuli, 25, 1, 3), + chestEntry(ItemId::EmeraldGem, 20, 1, 1), + chestEntry(ItemId::IronIngot, 20, 1, 2), + chestEntry(ItemId::DiamondGem, 10, 1, 1)}; + + LootPool junk; + junk.entries = {chestEntry(ItemId::Stick, 30, 1, 2), chestEntry(ItemId::RottenFlesh, 25, 1, 1), + chestEntry(ItemId::Gravel, 20, 1, 1), chestEntry(ItemId::Leaves, 15, 1, 1), + chestEntry(ItemId::WoodHoe, 10, 1, 1)}; + + for (const LootPool& pool : {fish, treasure, junk}) { + LootTable table; + table.pools.push_back(pool); + tables.push_back(table); + } + return tables; +} + +const LootTable& emptyLootTable() { + static const LootTable table; + return table; +} + +} // namespace + +int toolHarvestLevel(ToolTier tier) { + switch (tier) { + case ToolTier::None: return 0; + case ToolTier::Wood: return 1; + case ToolTier::Gold: return 1; + case ToolTier::Stone: return 2; + case ToolTier::Iron: return 3; + case ToolTier::Diamond: return 4; + } + return 0; +} + +bool toolAllows(const BlockDropRule& rule, ItemId tool) { + if (!rule.toolRequiredForDrop) return true; + const ItemInfo& info = itemInfo(tool); + if (info.toolType != rule.harvestTool) return false; + return toolHarvestLevel(info.toolTier) >= toolHarvestLevel(rule.minimumTier); +} + +LootTable blockRuleTable(const BlockDropRule& rule) { + LootTable table; + + ItemId harvested = rule.silkTouchDrop(); + if (harvested != ItemId::None) { + LootEntry silk; + silk.item = harvested; + silk.conditions = LootEntry::SilkTouched; + appendPool(table, silk); + } + + if (rule.drop != ItemId::None) { + LootEntry broken; + broken.item = rule.drop; + broken.minCount = rule.minCount; + broken.maxCount = rule.maxCount; + broken.chance = rule.dropChance; + broken.conditions = LootEntry::NotSilkTouched; + if (rule.firedDrop != ItemId::None) broken.conditions |= LootEntry::NotFiery; + if (rule.minCount != rule.maxCount) broken.functions |= LootEntry::CountRange; + if (rule.fortuneMultiplies) broken.functions |= LootEntry::OreFortune; + if (rule.chancePerFortune > 0.0f) { + broken.functions |= LootEntry::ChanceFortune; + broken.chancePerLevel = rule.chancePerFortune; + } + appendPool(table, broken); + } + + if (rule.firedDrop != ItemId::None) { + LootEntry burned; + burned.item = rule.firedDrop; + burned.minCount = rule.minCount; + burned.maxCount = rule.maxCount; + burned.conditions = LootEntry::NotSilkTouched | LootEntry::Fiery; + if (rule.minCount != rule.maxCount) burned.functions |= LootEntry::CountRange; + appendPool(table, burned); + } + + if (rule.bonusDrop != ItemId::None) { + LootEntry bonus; + bonus.item = rule.bonusDrop; + bonus.minCount = rule.bonusMin; + bonus.maxCount = rule.bonusMax; + bonus.chance = rule.bonusChance; + bonus.conditions = LootEntry::NotSilkTouched; + if (rule.bonusMin != rule.bonusMax) bonus.functions |= LootEntry::CountRange; + appendPool(table, bonus); + } + return table; +} + +LootTable mobRuleTable(const MobDropRule& rule) { + LootTable table; + if (rule.drop != ItemId::None) { + LootEntry common; + common.item = rule.drop; + common.minCount = rule.minCount; + common.maxCount = rule.maxCount; + if (rule.minCount != rule.maxCount) common.functions |= LootEntry::CountRange; + if (rule.lootingRaisesCount) common.functions |= LootEntry::LootingBonus; + if (rule.dropNeedsPlayerKill) common.conditions |= LootEntry::PlayerKill; + if (rule.firedDrop != ItemId::None) common.conditions |= LootEntry::NotFiery; + appendPool(table, common); + + if (rule.firedDrop != ItemId::None) { + LootEntry cooked = common; + cooked.item = rule.firedDrop; + cooked.conditions = (common.conditions & ~LootEntry::NotFiery) | LootEntry::Fiery; + appendPool(table, cooked); + } + } + + if (rule.rareDrop != ItemId::None) { + LootEntry rare; + rare.item = rule.rareDrop; + rare.chance = rule.rareChance; + rare.chancePerLevel = rule.rareChancePerLooting; + if (rule.rareChancePerLooting > 0.0f) rare.functions |= LootEntry::ChanceLooting; + if (rule.rareNeedsPlayerKill) rare.conditions |= LootEntry::PlayerKill; + appendPool(table, rare); + } + return table; +} + +LootTableId LootTableId::ofBlock(Block block) { + return LootTableId{Domain::Block, static_cast(block)}; +} + +LootTableId LootTableId::ofMob(MobDropRule::Species species) { + return LootTableId{Domain::Mob, static_cast(species)}; +} + +LootTableId LootTableId::ofChest(ChestFill::Structure structure) { + return LootTableId{Domain::Chest, static_cast(structure)}; +} +