diff --git a/assets/ron/custom.battle.ron b/assets/ron/custom.battle.ron index 50a8bc910..e1514a44e 100644 --- a/assets/ron/custom.battle.ron +++ b/assets/ron/custom.battle.ron @@ -3,12 +3,143 @@ left: ( units: [ ( - hp: 15, - atk: 3, - description: "Test description. I have {Hp} hp and {Atk} atk", + name: "Wizard", + hp: 3, + atk: 1, + house: "Mages", + description: "use [Magic Missile] ({Level})", + trigger: TurnEnd(UseAbility("Magic Missile")), + representation: ( + material: Shape( + shape: Circle, + thickness: Sum( + Float(2.5), + Cos(GameTime), + ), + size: Vec2E( + Sum( + Float(0.7), + Mul( + Beat, + Float(0.3), + ), + ), + ), + ), + children: [ + ( + count: 5, + material: Shape( + shape: Circle, + fill: Opaque, + size: Vec2E(Float(0.2)), + ), + mapping: { + Position: Mul( + Vec2EE( + Sin( + Sum( + GameTime, + IntFloat( + State( + Index, + ), + ), + ), + ), + Cos( + GameTime, + ), + ), + Mul( + Cos( + Mul( + Sum( + GameTime, + IntFloat( + State( + Index, + ), + ), + ), + Float( + 1.3, + ), + ), + ), + Sum( + Float( + 0.5, + ), + Beat, + ), + ), + ), + }, ), ], ), +),( + name: "Priest", + hp: 1, + atk: 1, + house: "Holy", + description: "use [Blessing] ({Level}) on all allies", + trigger: BattleStart( + AoeFaction( + OwnerFaction, + UseAbility("Blessing"), + ), + ), + representation: ( + count: 4, + material: Shape( + shape: Circle, + thickness: Sum( + Float(2.5), + Cos(GameTime), + ), + size: Vec2E( + Sum( + Float(0.5), + Mul( + Beat, + Float(0.3), + ), + ), + ), + ), + mapping: { + Position: Mul( + UnitVec( + Mul( + Sum( + GameTime, + Mul( + Mul( + PI, + Float( + 0.5, + ), + ), + IntFloat( + State( + Index, + ), + ), + ), + ), + Float(3.0), + ), + ), + Float(0.3), + ), + }, + children: [], + ), +) + ], + ), right: ( units: [ ( diff --git a/src/plugins/battle.rs b/src/plugins/battle.rs index 559ab97fe..a79508700 100644 --- a/src/plugins/battle.rs +++ b/src/plugins/battle.rs @@ -35,6 +35,11 @@ impl BattlePlugin { } pub fn load_teams(left: PackedTeam, right: PackedTeam, world: &mut World) { + dbg!(PackedUnit::fuse( + left.units[0].clone(), + left.units[1].clone() + )); + world.send_event(AppExit); world.insert_resource(BattleData { left: Some(left), right: Some(right), diff --git a/src/resourses/effect.rs b/src/resourses/effect.rs index 6e798896c..a823877ee 100644 --- a/src/resourses/effect.rs +++ b/src/resourses/effect.rs @@ -1,4 +1,4 @@ -use std::ops::Deref; +use std::{collections::VecDeque, ops::Deref}; use super::*; @@ -291,6 +291,39 @@ impl Effect { Ok(()) } + pub fn get_inner(&mut self) -> Vec<&mut Self> { + match self { + Effect::Noop + | Effect::Kill + | Effect::FullCopy + | Effect::Debug(..) + | Effect::Text(..) + | Effect::Damage(..) + | Effect::UseAbility(..) + | Effect::AddStatus(..) + | Effect::Vfx(..) + | Effect::SendEvent(..) => default(), + Effect::AoeFaction(_, e) + | Effect::WithTarget(_, e) + | Effect::WithOwner(_, e) + | Effect::WithVar(_, _, e) => vec![e], + Effect::List(list) | Effect::ListSpread(list) => { + list.into_iter().map(|e| e.as_mut()).collect_vec() + } + } + } + + pub fn find_ability(&mut self) -> Option<&mut Self> { + let mut queue = VecDeque::from([self]); + while let Some(e) = queue.pop_front() { + if matches!(e, Effect::UseAbility(..)) { + return Some(e); + } + queue.extend(e.get_inner()); + } + None + } + pub fn show_editor( &mut self, editing_data: &mut EditingData, diff --git a/src/resourses/expression.rs b/src/resourses/expression.rs index 1206a3095..9e57c46b9 100644 --- a/src/resourses/expression.rs +++ b/src/resourses/expression.rs @@ -293,67 +293,67 @@ impl Expression { } } - pub fn get_inner(&mut self) -> Vec<&mut Box> { + pub fn get_inner(&mut self) -> Vec<&mut Box> { match self { - Expression::Zero - | Expression::GameTime - | Expression::RandomFloat - | Expression::PI - | Expression::Owner - | Expression::Caster - | Expression::Target - | Expression::RandomUnit - | Expression::RandomAdjacentUnit - | Expression::Age - | Expression::SlotPosition - | Expression::OwnerFaction - | Expression::OppositeFaction - | Expression::Beat - | Expression::Float(..) - | Expression::Int(..) - | Expression::Bool(..) - | Expression::String(..) - | Expression::Hex(..) - | Expression::Faction(..) - | Expression::State(..) - | Expression::TargetState(..) - | Expression::StateLast(..) - | Expression::Context(..) - | Expression::Vec2(..) => default(), - Expression::StringInt(x) - | Expression::StringFloat(x) - | Expression::StringVec(x) - | Expression::IntFloat(x) - | Expression::Sin(x) - | Expression::Cos(x) - | Expression::Sign(x) - | Expression::Fract(x) - | Expression::Floor(x) - | Expression::UnitVec(x) - | Expression::Even(x) - | Expression::Abs(x) - | Expression::SlotUnit(x) - | Expression::FactionCount(x) - | Expression::StatusCharges(x) - | Expression::Vec2E(x) => vec![x], + Self::Zero + | Self::GameTime + | Self::RandomFloat + | Self::PI + | Self::Owner + | Self::Caster + | Self::Target + | Self::RandomUnit + | Self::RandomAdjacentUnit + | Self::Age + | Self::SlotPosition + | Self::OwnerFaction + | Self::OppositeFaction + | Self::Beat + | Self::Float(..) + | Self::Int(..) + | Self::Bool(..) + | Self::String(..) + | Self::Hex(..) + | Self::Faction(..) + | Self::State(..) + | Self::TargetState(..) + | Self::StateLast(..) + | Self::Context(..) + | Self::Vec2(..) => default(), + Self::StringInt(x) + | Self::StringFloat(x) + | Self::StringVec(x) + | Self::IntFloat(x) + | Self::Sin(x) + | Self::Cos(x) + | Self::Sign(x) + | Self::Fract(x) + | Self::Floor(x) + | Self::UnitVec(x) + | Self::Even(x) + | Self::Abs(x) + | Self::SlotUnit(x) + | Self::FactionCount(x) + | Self::StatusCharges(x) + | Self::Vec2E(x) => vec![x], - Expression::Vec2EE(a, b) - | Expression::Sum(a, b) - | Expression::Sub(a, b) - | Expression::Mul(a, b) - | Expression::Div(a, b) - | Expression::GreaterThen(a, b) - | Expression::LessThen(a, b) - | Expression::Min(a, b) - | Expression::Equals(a, b) - | Expression::And(a, b) - | Expression::Or(a, b) - | Expression::Max(a, b) => vec![a, b], - Expression::If(a, b, c) => vec![a, b, c], + Self::Vec2EE(a, b) + | Self::Sum(a, b) + | Self::Sub(a, b) + | Self::Mul(a, b) + | Self::Div(a, b) + | Self::GreaterThen(a, b) + | Self::LessThen(a, b) + | Self::Min(a, b) + | Self::Equals(a, b) + | Self::And(a, b) + | Self::Or(a, b) + | Self::Max(a, b) => vec![a, b], + Self::If(a, b, c) => vec![a, b, c], } } - pub fn set_inner(mut self, mut other: Expression) -> Self { + pub fn set_inner(mut self, mut other: Self) -> Self { let inner_self = self.get_inner(); let inner_other = other.get_inner(); for (i, e) in inner_self.into_iter().enumerate() { diff --git a/src/resourses/packed_unit.rs b/src/resourses/packed_unit.rs index c595bab4e..e5b837efc 100644 --- a/src/resourses/packed_unit.rs +++ b/src/resourses/packed_unit.rs @@ -196,6 +196,49 @@ impl PackedUnit { } } + pub fn fuse(a: Self, b: Self) -> Vec { + let mut result: Vec = default(); + let mut trigger_a = a.trigger; + let mut trigger_b = b.trigger; + + if std::mem::discriminant(&trigger_a) != std::mem::discriminant(&trigger_b) { + { + if let Some(effect_a) = trigger_a.get_inner_effect().cloned() { + let mut trigger_b = trigger_b.clone(); + trigger_b.set_inner_effect(effect_a); + result.push(Trigger::List( + [Box::new(trigger_a.clone()), Box::new(trigger_b)].into(), + )); + } + if let Some(effect_b) = trigger_b.get_inner_effect().cloned() { + let mut trigger_a = trigger_a.clone(); + trigger_a.set_inner_effect(effect_b); + result.push(Trigger::List( + [Box::new(trigger_b.clone()), Box::new(trigger_a)].into(), + )); + } + } + } else { + let mut result_a = trigger_a.clone(); + let mut result_b = trigger_b.clone(); + if let Some(ability_a) = trigger_a.get_inner_effect().and_then(|e| e.find_ability()) { + if let Some(ability_b) = trigger_b.get_inner_effect().and_then(|e| e.find_ability()) + { + *result_a.get_inner_effect().unwrap().find_ability().unwrap() = Effect::List( + [Box::new(ability_a.clone()), Box::new(ability_b.clone())].into(), + ); + result.push(result_a); + *result_b.get_inner_effect().unwrap().find_ability().unwrap() = Effect::List( + [Box::new(ability_a.clone()), Box::new(ability_b.clone())].into(), + ); + result.push(result_b); + } + } + } + + result + } + pub fn show_editor( &mut self, entity: Option, diff --git a/src/resourses/trigger.rs b/src/resourses/trigger.rs index ceca252fa..607d794ec 100644 --- a/src/resourses/trigger.rs +++ b/src/resourses/trigger.rs @@ -230,4 +230,28 @@ impl Trigger { s.push_str(" → "); s } + + pub fn get_inner_effect(&mut self) -> Option<&mut Effect> { + match self { + Trigger::AfterIncomingDamage(effect) + | Trigger::AfterDamageTaken(effect) + | Trigger::AfterDamageDealt(effect) + | Trigger::BattleStart(effect) + | Trigger::TurnStart(effect) + | Trigger::TurnEnd(effect) + | Trigger::BeforeStrike(effect) + | Trigger::AfterStrike(effect) + | Trigger::AllyDeath(effect) + | Trigger::AnyDeath(effect) + | Trigger::BeforeDeath(effect) + | Trigger::AfterKill(effect) => Some(effect), + _ => None, + } + } + + pub fn set_inner_effect(&mut self, effect: Effect) { + if let Some(inner) = self.get_inner_effect() { + *inner = effect; + } + } }