diff --git a/assets/common/entity/dungeon/myrmidon/cyclops.ron b/assets/common/entity/dungeon/myrmidon/cyclops.ron index 04999d2ee4..8163e6c8cf 100644 --- a/assets/common/entity/dungeon/myrmidon/cyclops.ron +++ b/assets/common/entity/dungeon/myrmidon/cyclops.ron @@ -3,12 +3,7 @@ name: Automatic, body: RandomWith("cyclops"), alignment: Alignment(Enemy), - loot: All([ - // Hat, wood and lantern, has a lower chance of dropping - LootTable("common.loot_tables.dungeon.myrmidon.miniboss"), - // Materials, always dropped - LootTable("common.loot_tables.dungeon.myrmidon.miniboss_extra"), - ]), + loot: LootTable("common.loot_tables.dungeon.myrmidon.miniboss"), inventory: ( loadout: FromBody, ), diff --git a/assets/common/entity/wild/aggressive/phoenix.ron b/assets/common/entity/wild/aggressive/phoenix.ron index 509430eaad..8806159572 100644 --- a/assets/common/entity/wild/aggressive/phoenix.ron +++ b/assets/common/entity/wild/aggressive/phoenix.ron @@ -3,14 +3,9 @@ name: Automatic, body: RandomWith("phoenix"), alignment: Alignment(Wild), - loot: All([ - // Bow and glider, has a lower chance of dropping - LootTable("common.loot_tables.creature.bird_large.phoenix"), - // Phoenix feathers and food, always dropped - LootTable("common.loot_tables.creature.bird_large.phoenix_extra") - ]), + loot: LootTable("common.loot_tables.creature.bird_large.phoenix"), inventory: ( loadout: FromBody, ), meta: [], -) \ No newline at end of file +) diff --git a/assets/common/loot_tables/creature/bird_large/phoenix.ron b/assets/common/loot_tables/creature/bird_large/phoenix.ron index c7a0994b80..66dd97249c 100644 --- a/assets/common/loot_tables/creature/bird_large/phoenix.ron +++ b/assets/common/loot_tables/creature/bird_large/phoenix.ron @@ -1,4 +1,12 @@ [ - (1.6, Nothing), - (0.4, Item("common.items.weapons.bow.sagitta")), -] \ No newline at end of file + (1, All([ + MultiDrop(Item("common.items.food.meat.bird_large_raw"), 3, 4), + MultiDrop(Item("common.items.crafting_ing.animal_misc.phoenix_feather"), 1, 3), + + // Special Drop + Lottery([ + (0.4, Item("common.items.weapons.bow.sagitta")), + (1.6, Nothing), + ]), + ])), +] diff --git a/assets/common/loot_tables/creature/bird_large/phoenix_extra.ron b/assets/common/loot_tables/creature/bird_large/phoenix_extra.ron deleted file mode 100644 index 3c36790632..0000000000 --- a/assets/common/loot_tables/creature/bird_large/phoenix_extra.ron +++ /dev/null @@ -1,7 +0,0 @@ -[ - // Extra materials dropped by phoenix - (1.0, All([ - MultiDrop(Item("common.items.food.meat.bird_large_raw"), 3, 4), - MultiDrop(Item("common.items.crafting_ing.animal_misc.phoenix_feather"), 1, 3), - ])), -] \ No newline at end of file diff --git a/assets/common/loot_tables/dungeon/adlet/elder.ron b/assets/common/loot_tables/dungeon/adlet/elder.ron index 8959606c3e..4b6767cb2e 100644 --- a/assets/common/loot_tables/dungeon/adlet/elder.ron +++ b/assets/common/loot_tables/dungeon/adlet/elder.ron @@ -3,7 +3,16 @@ Item("common.items.keys.bone_key"), MultiDrop(Item("common.items.crafting_ing.animal_misc.fur"), 1, 2), MultiDrop(Item("common.items.crafting_ing.leather.thick_leather"), 1, 2), - LootTable("common.loot_tables.dungeon.adlet.elder_extra"), + + Lottery([ + // Weapons + (4.0, LootTable("common.loot_tables.weapons.tier-2")), + // Armor + (4.0, LootTable("common.loot_tables.armor.tier-2")), + // Misc + (2.0, Item("common.items.armor.misc.neck.pendant_of_protection")), + (0.5, Item("common.items.tool.instruments.wildskin_drum")), + ]), ], )), -] \ No newline at end of file +] diff --git a/assets/common/loot_tables/dungeon/adlet/elder_extra.ron b/assets/common/loot_tables/dungeon/adlet/elder_extra.ron deleted file mode 100644 index 414283ba42..0000000000 --- a/assets/common/loot_tables/dungeon/adlet/elder_extra.ron +++ /dev/null @@ -1,9 +0,0 @@ -[ - // Weapons - (4.0, LootTable("common.loot_tables.weapons.tier-2")), - // Armor - (4.0, LootTable("common.loot_tables.armor.tier-2")), - // Misc - (2.0, Item("common.items.armor.misc.neck.pendant_of_protection")), - (0.5, Item("common.items.tool.instruments.wildskin_drum")), -] \ No newline at end of file diff --git a/assets/common/loot_tables/dungeon/myrmidon/miniboss.ron b/assets/common/loot_tables/dungeon/myrmidon/miniboss.ron index 529b8f9277..1fea377a73 100644 --- a/assets/common/loot_tables/dungeon/myrmidon/miniboss.ron +++ b/assets/common/loot_tables/dungeon/myrmidon/miniboss.ron @@ -1,9 +1,18 @@ [ - (1.05, Nothing), - // Lantern drop - (0.15, Item("common.items.lantern.blue_0")), - // Hat drop - (0.3, Item("common.items.armor.misc.head.mitre")), - // Allow for Eldwood to drop until entity droppers are implemented - (0.5, Item("common.items.log.eldwood")), + (1.0, All([ + MultiDrop(Item("common.items.utility.coins"), 200, 500), + MultiDrop(Item("common.items.mineral.ingot.iron"), 5, 10), + MultiDrop(Item("common.items.consumable.potion_minor"), 4, 8), + + // Special drop + Lottery([ + // Lantern drop + (0.15, Item("common.items.lantern.blue_0")), + // Hat drop + (0.3, Item("common.items.armor.misc.head.mitre")), + // Allow for Eldwood to drop until entity droppers are implemented + (0.5, Item("common.items.log.eldwood")), + (1.05, Nothing), + ]), + ])) ] diff --git a/assets/common/loot_tables/dungeon/myrmidon/miniboss_extra.ron b/assets/common/loot_tables/dungeon/myrmidon/miniboss_extra.ron deleted file mode 100644 index 8995c51482..0000000000 --- a/assets/common/loot_tables/dungeon/myrmidon/miniboss_extra.ron +++ /dev/null @@ -1,8 +0,0 @@ -[ - // Mats, always dropped - (1.0, All([ - MultiDrop(Item("common.items.utility.coins"), 200, 500), - MultiDrop(Item("common.items.mineral.ingot.iron"), 5, 10), - MultiDrop(Item("common.items.consumable.potion_minor"), 4, 8), - ])), -] diff --git a/assets/common/loot_tables/dungeon/terracotta/cursekeeper.ron b/assets/common/loot_tables/dungeon/terracotta/cursekeeper.ron index cfc7ffca14..67da3d9573 100644 --- a/assets/common/loot_tables/dungeon/terracotta/cursekeeper.ron +++ b/assets/common/loot_tables/dungeon/terracotta/cursekeeper.ron @@ -1,7 +1,15 @@ [ (1, All([ Item("common.items.keys.terracotta_key_door"), - LootTable("common.loot_tables.dungeon.terracotta.cursekeeper_extra"), + + Lottery([ + // Weapons + (3.0, LootTable("common.loot_tables.weapons.tier-5")), + // Armor + (3.0, LootTable("common.loot_tables.armor.tier-5")), + // Misc + (0.25, Item("common.items.tool.instruments.steeltonguedrum")), + ]), ], )), -] \ No newline at end of file +] diff --git a/assets/common/loot_tables/dungeon/terracotta/cursekeeper_extra.ron b/assets/common/loot_tables/dungeon/terracotta/cursekeeper_extra.ron deleted file mode 100644 index 554b4c62b5..0000000000 --- a/assets/common/loot_tables/dungeon/terracotta/cursekeeper_extra.ron +++ /dev/null @@ -1,8 +0,0 @@ -[ - // Weapons - (3.0, LootTable("common.loot_tables.weapons.tier-5")), - // Armor - (3.0, LootTable("common.loot_tables.armor.tier-5")), - // Misc - (0.25, Item("common.items.tool.instruments.steeltonguedrum")), -] \ No newline at end of file diff --git a/common/src/bin/csv_export/main.rs b/common/src/bin/csv_export/main.rs index 2bca80ff20..047c1fc08e 100644 --- a/common/src/bin/csv_export/main.rs +++ b/common/src/bin/csv_export/main.rs @@ -301,6 +301,11 @@ fn loot_table(loot_table: &str) -> Result<(), Box> { write_loot_spec(wtr, spec, chance)?; } }, + LootSpec::Lottery(lottery) => { + for (_weight, spec) in lottery { + write_loot_spec(wtr, spec, "")?; + } + }, } Ok(()) } @@ -480,6 +485,7 @@ fn entity_drops(entity_config: &str) -> Result<(), Box> { } }, LootSpec::LootTable(_) => unreachable!(), + LootSpec::Lottery(_) => todo!(), LootSpec::MultiDrop(_, _, _) => todo!(), LootSpec::All(_) => todo!(), } diff --git a/common/src/comp/inventory/trade_pricing.rs b/common/src/comp/inventory/trade_pricing.rs index 7c49c7bf65..77440d6679 100644 --- a/common/src/comp/inventory/trade_pricing.rs +++ b/common/src/comp/inventory/trade_pricing.rs @@ -379,6 +379,15 @@ impl From)>> for ProbabilityFile { .map(|(p1, asset, amount)| (*p1 * scale, asset.clone(), *amount)) .collect::>() }, + LootSpec::Lottery(table) => { + let unscaled = ProbabilityFile::from(table); + let scale = p0 * rescale; + unscaled + .content + .into_iter() + .map(|(p1, asset, amount)| (p1 * scale, asset, amount)) + .collect::>() + }, LootSpec::ModularWeapon { tool, material, diff --git a/common/src/lottery.rs b/common/src/lottery.rs index d7e1098fcb..9b5433c8c9 100644 --- a/common/src/lottery.rs +++ b/common/src/lottery.rs @@ -207,7 +207,7 @@ pub fn distribute_many( } } -#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub enum LootSpec> { /// Asset specifier Item(T), @@ -232,6 +232,8 @@ pub enum LootSpec> { /// Each category is evaluated, often used to have guaranteed quest Item + /// random reward All(Vec>), + /// Like a `LootTable` but inline + Lottery(Vec<(f32, LootSpec)>), } impl> LootSpec { @@ -291,6 +293,18 @@ impl> LootSpec { loot_spec.choose().to_items_inner(rng, 1, items) } }, + Self::Lottery(table) => { + let lottery = Lottery::from( + table + .iter() + .map(|(weight, spec)| (*weight, spec)) + .collect::>(), + ); + + for _ in 0..amount { + lottery.choose().to_items_inner(rng, 1, items) + } + }, Self::Nothing => {}, Self::ModularWeapon { tool, @@ -368,6 +382,8 @@ impl Default for LootSpec { #[cfg(test)] pub mod tests { + use std::borrow::Borrow; + use super::*; use crate::{assets, comp::Item}; use assets::AssetExt; @@ -426,12 +442,22 @@ pub mod tests { validate_loot_spec(loot_spec); } }, + LootSpec::Lottery(table) => { + let lottery = Lottery::from( + table + .iter() + .map(|(weight, spec)| (*weight, spec)) + .collect::>(), + ); + + validate_table_contents(&lottery); + }, } } - fn validate_table_contents(table: &Lottery>) { + fn validate_table_contents>>(table: &Lottery) { for (_, item) in table.iter() { - validate_loot_spec(item); + validate_loot_spec(item.borrow()); } }