Implement all needed features

+ Multiple/Random inheritance for loadout configs
+ Using ItemSpecNew in Hands
+ Rename Hands::Specific to Hands::InHands to represent non-random
  combination
This commit is contained in:
juliancoffee 2022-02-18 20:31:48 +02:00
parent 5e07875be9
commit 3f7bfff8d7
6 changed files with 102 additions and 31 deletions

View File

@ -0,0 +1,7 @@
#![enable(implicit_some)]
(
inherit: Choice([
(1, Asset("common.loadout_new.test.rings")),
(1, Asset("common.loadout_new.test.choice_hands")),
]),
)

View File

@ -0,0 +1,17 @@
#![enable(implicit_some)]
(
active_hands: Choice([
(1, InHands((
Item("common.items.axe_1h.orichalcum"),
Item("common.items.axe_1h.orichalcum"),
))),
(1, InHands((
Item("common.items.hammer_1h.orichalcum"),
Item("common.items.axe_1h.orichalcum"),
))),
(1, InHands((
Item("common.items.sword.cultist"),
None,
))),
]),
)

View File

@ -0,0 +1,7 @@
#![enable(implicit_some)]
(
inherit: Combine([
Asset("common.loadout_new.test.rings"),
Asset("common.loadout_new.test.choice_hands"),
]),
)

View File

@ -0,0 +1,5 @@
#![enable(implicit_some)]
(
ring1: Item("common.items.armor.cultist.ring"),
ring2: Item("common.items.armor.cultist.ring"),
)

View File

@ -0,0 +1,12 @@
#![enable(implicit_some)]
(
inherit: Asset("common.loadout_new.rings"),
head: Item("common.items.armor.cultist.bandana"),
active_hands: InHands((
Item("common.items.axe_1h.orichalcum"),
Choice([
(1, Item("common.items.hammer_1h.orichalcum")),
(1, Item("common.items.axe_1h.orichalcum")),
]),
)),
)

View File

@ -54,14 +54,36 @@ type Weight = u8;
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Clone)]
enum Base { enum Base {
One(String), Asset(String),
/// NOTE: If you have the same item in multiple configs,
/// first one will have the priority
Combine(Vec<Base>),
Choice(Vec<(Weight, Base)>),
} }
impl Base { impl Base {
fn to_spec(&self) -> Result<LoadoutSpecNew, LoadoutBuilderError> { fn to_spec(&self, rng: &mut impl Rng) -> Result<LoadoutSpecNew, LoadoutBuilderError> {
match self { match self {
Base::One(asset_specifier) => LoadoutSpecNew::load_cloned(asset_specifier) Base::Asset(asset_specifier) => LoadoutSpecNew::load_cloned(asset_specifier)
.map_err(LoadoutBuilderError::LoadoutAssetError), .map_err(LoadoutBuilderError::LoadoutAssetError),
Base::Combine(bases) => {
let bases = bases.iter().map(|b| b.to_spec(rng)?.eval(rng));
// Get first base of combined
let mut current = LoadoutSpecNew::default();
for base in bases {
current = current.merge(base?);
}
Ok(current)
},
Base::Choice(choice) => {
let (_, base) = choice
.choose_weighted(rng, |(weight, _)| *weight)
.map_err(LoadoutBuilderError::BaseChoiceError)?;
base.to_spec(rng)
},
} }
} }
} }
@ -69,25 +91,10 @@ impl Base {
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Clone)]
enum Hands { enum Hands {
/// Allows to specify one pair /// Allows to specify one pair
/// Example // TODO: add link to tests with example
/// ```text InHands((Option<ItemSpecNew>, Option<ItemSpecNew>)),
/// Specific(("common.items.axe_1h.orichalcum", "common.items.axe_1h.orichalcum"))
/// ```
Specific((Option<String>, Option<String>)),
/// Allows specify range of choices /// Allows specify range of choices
/// Choice([ // TODO: add link to tests with example
/// (1, Specific(
/// ("common.items.axe_1h.orichalcum",
/// "common.items.axe_1h.orichalcum")),
/// (1, Specific(
/// ("common.items.hammer_1h.orichalcum",
/// "common.items.hammer_1h.orichalcum")),
/// (1, Specific(
/// ("common.items.hammer_1h.orichalcum",
/// "common.items.axe_1h.orichalcum")),
/// (1, Specific(
/// ("common.items.sword.cultist")),
/// ])
Choice(Vec<(Weight, Hands)>), Choice(Vec<(Weight, Hands)>),
} }
@ -96,15 +103,20 @@ impl Hands {
&self, &self,
rng: &mut impl Rng, rng: &mut impl Rng,
) -> Result<(Option<Item>, Option<Item>), LoadoutBuilderError> { ) -> Result<(Option<Item>, Option<Item>), LoadoutBuilderError> {
use std::ops::Deref;
match self { match self {
Hands::Specific((mainhand, offhand)) => { Hands::InHands((mainhand, offhand)) => {
let from_asset = |i: &String| { let mut from_spec = |i: &ItemSpecNew| i.try_to_item(rng);
Item::new_from_asset(i.deref()).map_err(LoadoutBuilderError::ItemAssetError)
};
let mainhand = mainhand.as_ref().map(from_asset).transpose()?; let mainhand = mainhand
let offhand = offhand.as_ref().map(from_asset).transpose()?; .as_ref()
.map(|i| from_spec(i))
.transpose()?
.flatten();
let offhand = offhand
.as_ref()
.map(|i| from_spec(i))
.transpose()?
.flatten();
Ok((mainhand, offhand)) Ok((mainhand, offhand))
}, },
Hands::Choice(pairs) => { Hands::Choice(pairs) => {
@ -237,10 +249,10 @@ impl LoadoutSpecNew {
/// ring1: b, /// ring1: b,
/// ring2: c, /// ring2: c,
/// ``` /// ```
fn eval(self) -> Result<Self, LoadoutBuilderError> { fn eval(self, rng: &mut impl Rng) -> Result<Self, LoadoutBuilderError> {
// Iherit loadout if needed // Iherit loadout if needed
if let Some(ref base) = self.inherit { if let Some(ref base) = self.inherit {
let base = base.to_spec()?.eval(); let base = base.to_spec(rng)?.eval(rng);
Ok(self.merge(base?)) Ok(self.merge(base?))
} else { } else {
Ok(self) Ok(self)
@ -248,10 +260,12 @@ impl LoadoutSpecNew {
} }
} }
#[derive(Debug)]
pub enum LoadoutBuilderError { pub enum LoadoutBuilderError {
LoadoutAssetError(assets::Error), LoadoutAssetError(assets::Error),
ItemAssetError(assets::Error), ItemAssetError(assets::Error),
ItemChoiceError(WeightedError), ItemChoiceError(WeightedError),
BaseChoiceError(WeightedError),
} }
impl assets::Asset for LoadoutSpecNew { impl assets::Asset for LoadoutSpecNew {
@ -752,7 +766,7 @@ impl LoadoutBuilder {
rng: &mut R, rng: &mut R,
) -> Result<Self, LoadoutBuilderError> { ) -> Result<Self, LoadoutBuilderError> {
// Include any inheritance // Include any inheritance
let spec = spec.eval()?; let spec = spec.eval(rng)?;
// Utility function to unwrap our itemspec // Utility function to unwrap our itemspec
let mut to_item = |maybe_item: Option<ItemSpecNew>| { let mut to_item = |maybe_item: Option<ItemSpecNew>| {
@ -1118,4 +1132,13 @@ mod tests {
} }
} }
} }
#[test]
fn test_new_config() {
let dummy_rng = &mut rand::thread_rng();
let new_spec =
LoadoutSpecNew::load_expect_cloned("common.loadout_new.test.choice_base");
let new_spec = new_spec.eval(dummy_rng).unwrap();
panic!("{new_spec:#?}");
}
} }