diff --git a/Cargo.toml b/Cargo.toml index f9792060b..9310b788e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,6 +59,7 @@ kira = "0.8.5" ordered_hash_map = "0.4.0" home = "0.5.5" lazy_static = "1.4.0" +convert_case = "0.6.0" [dependencies.winit] # version = "*" diff --git a/assets/ron/heroes/bolla.unit.ron b/assets/ron/heroes/bolla.unit.ron index a8674d9d8..2268a771c 100644 --- a/assets/ron/heroes/bolla.unit.ron +++ b/assets/ron/heroes/bolla.unit.ron @@ -5,7 +5,6 @@ atk: 1, houses: "Dragons", trigger: Fire(trigger: TurnEnd, effect: UseAbility("Grow")), - description: "use [Ability] ({Level})", representation: ( material: Shape( shape: Circle, diff --git a/assets/ron/heroes/doppelganger.unit.ron b/assets/ron/heroes/doppelganger.unit.ron index 93d7b87e6..a7fb8dd9f 100644 --- a/assets/ron/heroes/doppelganger.unit.ron +++ b/assets/ron/heroes/doppelganger.unit.ron @@ -5,7 +5,6 @@ atk: 3, houses: "Shifters", trigger: Fire(trigger: BattleStart, target: RandomAdjacentUnit, effect: UseAbility("Copy")), - description: "use [Ability] on random adjacent ally", representation: ( material: Shape( shape: Circle, diff --git a/assets/ron/heroes/mentalist.unit.ron b/assets/ron/heroes/mentalist.unit.ron index 2607a80d4..edfbe1121 100644 --- a/assets/ron/heroes/mentalist.unit.ron +++ b/assets/ron/heroes/mentalist.unit.ron @@ -5,7 +5,6 @@ atk: 2, houses: "Meta", trigger: Fire(trigger: BeforeDeath, effect: UseAbility("Amnesia")), - description: "use [Ability] ({Level})", representation: ( material: Shape( shape: Circle, diff --git a/assets/ron/heroes/priest.unit.ron b/assets/ron/heroes/priest.unit.ron index 9ccfbf278..8f11365a6 100644 --- a/assets/ron/heroes/priest.unit.ron +++ b/assets/ron/heroes/priest.unit.ron @@ -4,7 +4,6 @@ hp: 1, atk: 1, houses: "Holy", - description: "use [Ability] ({Level}) on all allies", trigger: Fire(trigger: BattleStart, target: AllyUnits, effect: UseAbility("Blessing")), representation: ( count: 4, diff --git a/assets/ron/heroes/protector.unit.ron b/assets/ron/heroes/protector.unit.ron index 533c2c54f..4c32770f9 100644 --- a/assets/ron/heroes/protector.unit.ron +++ b/assets/ron/heroes/protector.unit.ron @@ -4,7 +4,7 @@ atk: 2, houses: "Paladins", trigger: Fire(trigger: BattleStart, target: SlotUnit(Int(1)), effect: UseAbility("Shield")), - description: "use [Ability] ({Level}) on front ally", + description: "%trigger → use %effect on front ally", representation: ( material: Shape( shape: Circle, diff --git a/assets/ron/heroes/scavenger.unit.ron b/assets/ron/heroes/scavenger.unit.ron index b17360d3e..0304513cc 100644 --- a/assets/ron/heroes/scavenger.unit.ron +++ b/assets/ron/heroes/scavenger.unit.ron @@ -5,7 +5,6 @@ atk: 1, houses: "Dragons", trigger: Fire(trigger: AnyDeath, effect: UseAbility("Grow")), - description: "use [Ability] ({Level})", representation: ( material: Shape( shape: Rectangle, diff --git a/assets/ron/heroes/wizard.unit.ron b/assets/ron/heroes/wizard.unit.ron index f9a5ecea2..a96d442ee 100644 --- a/assets/ron/heroes/wizard.unit.ron +++ b/assets/ron/heroes/wizard.unit.ron @@ -4,7 +4,6 @@ hp: 3, atk: 1, houses: "Mages", - description: "use [Ability] ({Level})", trigger: Fire(trigger: TurnEnd, target: RandomEnemy, effect: UseAbility("Magic Missile")), representation: ( material: Shape( diff --git a/src/resourses/colored_string.rs b/src/resourses/colored_string.rs index 52fa324be..187a12da0 100644 --- a/src/resourses/colored_string.rs +++ b/src/resourses/colored_string.rs @@ -86,6 +86,38 @@ impl ColoredString { self } + pub fn inject_trigger(mut self, state: &VarState) -> Self { + if let Ok(trigger) = state.get_string(VarName::TriggerDescription) { + self.lines = self + .lines + .drain(..) + .flat_map(|(line, color)| match line.find("%trigger") { + Some(_) => line + .replace("%trigger", &format!("<{trigger}>")) + .split_by_brackets(("<", ">")) + .into_iter() + .map(|(line, t)| match t { + true => (line, Some(white())), + false => (line, color), + }) + .collect_vec(), + None => vec![(line, color)], + }) + .collect_vec(); + } + if let Ok(effect) = state.get_string(VarName::EffectDescription) { + for (line, _) in self.lines.iter_mut() { + *line = line.replace("%effect", &effect); + } + } + if let Ok(target) = state.get_string(VarName::TargetDescription) { + for (line, _) in self.lines.iter_mut() { + *line = line.replace("%target", &target); + } + } + self + } + pub fn inject_vars(mut self, state: &VarState) -> Self { let mut result: Vec<(String, Option)> = default(); for (s, color) in self.lines.drain(..) { diff --git a/src/resourses/expression.rs b/src/resourses/expression.rs index 15f66996c..2988e8099 100644 --- a/src/resourses/expression.rs +++ b/src/resourses/expression.rs @@ -1,6 +1,7 @@ use std::f32::consts::PI; use bevy_egui::egui::{ComboBox, DragValue}; +use convert_case::{Case, Casing}; use hex::encode; use rand::{ seq::{IteratorRandom, SliceRandom}, @@ -735,4 +736,83 @@ impl Expression { Expression::If(_, _, _) => hex_color!("#BA68C8"), } } + + pub fn get_description_string(&self) -> String { + match self { + Expression::Zero + | Expression::GameTime + | Expression::RandomFloat + | Expression::PI + | Expression::Age + | Expression::SlotPosition + | Expression::OwnerFaction + | Expression::OppositeFaction + | Expression::Beat + | Expression::Owner + | Expression::Caster + | Expression::Target + | Expression::RandomUnit + | Expression::RandomAdjacentUnit + | Expression::RandomAlly + | Expression::RandomEnemy + | Expression::AllyUnits + | Expression::EnemyUnits + | Expression::AllUnits + | Expression::AdjacentUnits => self.to_string().to_case(Case::Lower), + Expression::Float(v) => v.to_string(), + Expression::Int(v) => v.to_string(), + Expression::Bool(v) => v.to_string(), + Expression::String(v) => v.to_string(), + Expression::Hex(v) => v.to_string(), + Expression::Faction(v) => v.to_string(), + Expression::State(v) => format!("{self}({v})"), + Expression::TargetState(v) => format!("{self}({v})"), + Expression::StateLast(v) => format!("{self}({v})"), + Expression::Context(v) => format!("{self}({v})"), + Expression::Value(v) => format!("{self}({v})"), + Expression::Vec2(x, y) => format!("({x}, {y})"), + Expression::Vec2E(x) => format!("({x}, {x})"), + Expression::StringInt(v) + | Expression::StringFloat(v) + | Expression::StringVec(v) + | Expression::IntFloat(v) + | Expression::Sin(v) + | Expression::Cos(v) + | Expression::Sign(v) + | Expression::Fract(v) + | Expression::Floor(v) + | Expression::UnitVec(v) + | Expression::Even(v) + | Expression::Abs(v) + | Expression::SlotUnit(v) + | Expression::FactionCount(v) + | Expression::StatusCharges(v) => format!( + "{} ({})", + self.to_string().to_case(Case::Lower), + v.get_description_string().to_case(Case::Title) + ), + Expression::Vec2EE(x, y) + | Expression::Sum(x, y) + | Expression::Sub(x, y) + | Expression::Mul(x, y) + | Expression::Div(x, y) + | Expression::GreaterThen(x, y) + | Expression::LessThen(x, y) + | Expression::Min(x, y) + | Expression::Max(x, y) + | Expression::Equals(x, y) + | Expression::And(x, y) + | Expression::Or(x, y) => format!( + "{self}({}, {})", + x.get_description_string().to_case(Case::Title), + y.get_description_string().to_case(Case::Title) + ), + Expression::If(x, y, z) => format!( + "{self}({}, {}, {})", + x.get_description_string().to_case(Case::Title), + y.get_description_string().to_case(Case::Title), + z.get_description_string().to_case(Case::Title), + ), + } + } } diff --git a/src/resourses/packed_unit.rs b/src/resourses/packed_unit.rs index 5132b56bf..c021448ef 100644 --- a/src/resourses/packed_unit.rs +++ b/src/resourses/packed_unit.rs @@ -18,7 +18,7 @@ pub struct PackedUnit { pub level: i32, #[serde(default = "default_houses")] pub houses: String, - #[serde(default)] + #[serde(default = "default_description ")] pub description: String, #[serde(default)] pub trigger: Trigger, @@ -30,6 +30,9 @@ pub struct PackedUnit { pub statuses: Vec<(String, i32)>, } +fn default_description() -> String { + "%trigger → %effect on %target".to_owned() +} fn default_houses() -> String { "Default".to_owned() } @@ -119,11 +122,8 @@ impl PackedUnit { VarName::Description, VarValue::String(self.description.clone()), ) - .init(VarName::AbilityDescription, VarValue::String(description)) - .init( - VarName::TriggerDescription, - VarValue::String(self.trigger.get_description_string()), - ); + .init(VarName::Description, VarValue::String(description)); + self.trigger.inject_description(&mut state); let house_colors = self .houses .split("+") @@ -188,7 +188,8 @@ impl PackedUnit { .clear_value(VarName::Level) .clear_value(VarName::Stacks) .clear_value(VarName::Name) - .clear_value(VarName::AbilityDescription) + .clear_value(VarName::EffectDescription) + .clear_value(VarName::TargetDescription) .clear_value(VarName::TriggerDescription) .clear_value(VarName::Houses) .simplify(); diff --git a/src/resourses/trigger.rs b/src/resourses/trigger.rs index 1db407ecb..23708a661 100644 --- a/src/resourses/trigger.rs +++ b/src/resourses/trigger.rs @@ -283,29 +283,40 @@ impl Trigger { }); } - pub fn get_description_string(&self) -> String { + pub fn inject_description(&self, state: &mut VarState) { match self { Trigger::Fire { trigger, target, effect, - } => format!( - "{} → {} on {}", - trigger.get_description_string(), - effect.to_string(), - target.to_string() - ), - Trigger::Change { - trigger, - expr: expression, - } => match trigger { - DeltaTrigger::Var(var) => format!("Stat {var} +{expression}"), - DeltaTrigger::IncomingDamage => format!("{trigger} +{expression}"), - }, - Trigger::List(list) => list - .into_iter() - .map(|t| t.get_description_string()) - .join(" | "), + } => { + state + .init( + VarName::TriggerDescription, + VarValue::String(trigger.get_description_string()), + ) + .init( + VarName::EffectDescription, + VarValue::String( + effect + .find_all_abilities() + .into_iter() + .map(|a| match a { + Effect::UseAbility(ability) => { + format!("[{ability}] ({{Level}})") + } + _ => default(), + }) + .join(" + "), + ), + ) + .init( + VarName::TargetDescription, + VarValue::String(target.get_description_string()), + ); + } + Trigger::Change { .. } => {} + Trigger::List(list) => list.into_iter().for_each(|t| t.inject_description(state)), } } } diff --git a/src/resourses/unit_card.rs b/src/resourses/unit_card.rs index 2d82aeed9..78391084b 100644 --- a/src/resourses/unit_card.rs +++ b/src/resourses/unit_card.rs @@ -28,16 +28,13 @@ impl VarState { } fn description(&self, world: &World) -> Result { let t = get_play_head(); - let ability = self.get_string_at(VarName::AbilityDescription, t)?; - if ability.is_empty() { - return Err(anyhow!("No description")); - } - let ability = ability + let description = self + .get_string_at(VarName::Description, t)? .to_colored() + .inject_trigger(self) .inject_vars(self) .inject_definitions(world); - let trigger = self.get_string_at(VarName::TriggerDescription, t)?; - Ok(trigger.add_color(white()).join(ability).take()) + Ok(description) } fn extra_lines(&self) -> Result> { let t = get_play_head(); @@ -83,7 +80,7 @@ impl VarState { } fn definitions(&self, world: &World) -> Result> { let t = get_play_head(); - let description = self.get_string_at(VarName::AbilityDescription, t)?; + let description = self.get_string_at(VarName::EffectDescription, t)?; let mut definitions: Vec<(ColoredString, ColoredString)> = default(); let mut added_definitions: HashSet = default(); let mut raw_definitions = VecDeque::from_iter(description.extract_bracketed(("[", "]"))); diff --git a/src/resourses/vars.rs b/src/resourses/vars.rs index 5ed88cbfc..8f0477d5f 100644 --- a/src/resourses/vars.rs +++ b/src/resourses/vars.rs @@ -40,8 +40,9 @@ pub enum VarName { Dmg, Name, Description, - AbilityDescription, + EffectDescription, TriggerDescription, + TargetDescription, Text, Spawn, Slot,