From 6146c1d6f965f8aa1051716173035477bf499d08 Mon Sep 17 00:00:00 2001 From: Maksim Chugunov Date: Sun, 7 Jan 2024 16:02:20 +0300 Subject: [PATCH] Unit stacking by drag in shop; Ability use Stacks var; Show all enemy cards in preview always; --- assets/ron/heroes/bolla.unit.ron | 2 +- assets/ron/heroes/hound.unit.ron | 77 ------------------- assets/ron/heroes/mentalist.unit.ron | 2 +- assets/ron/heroes/priest.unit.ron | 2 +- assets/ron/heroes/protector.unit.ron | 2 +- assets/ron/heroes/scavenger.unit.ron | 2 +- assets/ron/heroes/wizard.unit.ron | 2 +- assets/ron/houses/demons.house.ron | 58 -------------- assets/ron/scenarios/devour.scenario.ron | 57 -------------- .../scenarios/devour_each_other.scenario.ron | 42 ---------- .../ron/scenarios/devour_first.scenario.ron | 41 ---------- assets/ron/unit.rep.ron | 19 +++++ src/plugins/shop.rs | 21 ++--- src/plugins/ui.rs | 2 +- src/plugins/unit.rs | 68 +++++++++++----- src/resourses/effect.rs | 11 ++- src/resourses/packed_team.rs | 16 +--- src/resourses/packed_unit.rs | 8 ++ src/resourses/unit_card.rs | 6 +- src/resourses/vars.rs | 1 + 20 files changed, 112 insertions(+), 327 deletions(-) delete mode 100644 assets/ron/heroes/hound.unit.ron delete mode 100644 assets/ron/houses/demons.house.ron delete mode 100644 assets/ron/scenarios/devour.scenario.ron delete mode 100644 assets/ron/scenarios/devour_each_other.scenario.ron delete mode 100644 assets/ron/scenarios/devour_first.scenario.ron diff --git a/assets/ron/heroes/bolla.unit.ron b/assets/ron/heroes/bolla.unit.ron index e674b73f9..9be5ae99a 100644 --- a/assets/ron/heroes/bolla.unit.ron +++ b/assets/ron/heroes/bolla.unit.ron @@ -5,7 +5,7 @@ house: "Dragons", trigger: TurnEnd(UseAbility("Grow")), name: "Bolla", - description: "Turn End: [Grow]", + description: "Turn End: [Grow] ({Stacks})", representation: ( material: Shape( shape: Circle, diff --git a/assets/ron/heroes/hound.unit.ron b/assets/ron/heroes/hound.unit.ron deleted file mode 100644 index 616f4ef72..000000000 --- a/assets/ron/heroes/hound.unit.ron +++ /dev/null @@ -1,77 +0,0 @@ -#![enable(implicit_some)] -( - hp: 1, - atk: 1, - house: "Demons", - trigger: BattleStart( - ListSpread( - [ - WithVar( - Faction, - OppositeFaction, - WithTarget( - RandomUnit, - UseAbility( - "Devour", - ), - ), - ), - WithTarget( - RandomAdjacentUnit, - UseAbility("Devour"), - ), - WithTarget( - RandomAdjacentUnit, - UseAbility("Devour"), - ), - ], - ), - ), - name: "Hound", - description: "Battle Start: [Devour] adjacent ally twice and random enemy once", - representation: ( - material: Shape( - shape: Circle, - fill: Line, - size: Vec2E( - Sub( - Float(0.9), - Mul( - IntFloat( - State(Index), - ), - Mul( - Abs( - Sin( - Mul( - Float( - 0.78, - ), - Sum( - GameTime, - Mul( - RandomFloat, - Float( - 5.91, - ), - ), - ), - ), - ), - ), - Float(0.05), - ), - ), - ), - ), - thickness: Float(5.5), - alpha: Float(0.3), - color: State(Color), - ), - children: [], - mapping: {}, - count: 8, - ), - state: (history: {}, birth: 0.0), - statuses: [], -) \ No newline at end of file diff --git a/assets/ron/heroes/mentalist.unit.ron b/assets/ron/heroes/mentalist.unit.ron index 027f883a1..796038921 100644 --- a/assets/ron/heroes/mentalist.unit.ron +++ b/assets/ron/heroes/mentalist.unit.ron @@ -5,7 +5,7 @@ house: "Meta", trigger: BeforeDeath(UseAbility("Amnesia")), name: "Mentalist", - description: "Before Death: use [Amnesia]", + description: "Before Death: use [Amnesia] ({Stacks})", representation: ( material: Shape( shape: Circle, diff --git a/assets/ron/heroes/priest.unit.ron b/assets/ron/heroes/priest.unit.ron index 7f834a4f3..76a85b9fc 100644 --- a/assets/ron/heroes/priest.unit.ron +++ b/assets/ron/heroes/priest.unit.ron @@ -4,7 +4,7 @@ hp: 1, atk: 1, house: "Holy", - description: "Battle Start: apply [Blessing] to all allies", + description: "Battle Start: apply [Blessing] ({Stacks}) to all allies", trigger: BattleStart( AoeFaction( OwnerFaction, diff --git a/assets/ron/heroes/protector.unit.ron b/assets/ron/heroes/protector.unit.ron index 4b92efbe2..10db85dd8 100644 --- a/assets/ron/heroes/protector.unit.ron +++ b/assets/ron/heroes/protector.unit.ron @@ -9,7 +9,7 @@ ), ), name: "Protector", - description: "Battle Start: give [Shield] to front ally", + description: "Battle Start: give [Shield] ({Stacks}) to front ally", representation: ( material: Shape( shape: Circle, diff --git a/assets/ron/heroes/scavenger.unit.ron b/assets/ron/heroes/scavenger.unit.ron index 43270f879..df4cf97b7 100644 --- a/assets/ron/heroes/scavenger.unit.ron +++ b/assets/ron/heroes/scavenger.unit.ron @@ -5,7 +5,7 @@ house: "Dragons", trigger: AnyDeath(UseAbility("Grow")), name: "Scavenger", - description: "Any Unit died: [Grow] ", + description: "Any Unit died: [Grow] ({Stacks})", representation: ( material: Shape( shape: Rectangle, diff --git a/assets/ron/heroes/wizard.unit.ron b/assets/ron/heroes/wizard.unit.ron index 6becb700c..48780907e 100644 --- a/assets/ron/heroes/wizard.unit.ron +++ b/assets/ron/heroes/wizard.unit.ron @@ -4,7 +4,7 @@ hp: 3, atk: 1, house: "Mages", - description: "Turn End: use [Magic Missile]", + description: "Turn End: use [Magic Missile] ({Stacks})", trigger: TurnEnd(UseAbility("Magic Missile")), representation: ( material: Shape( diff --git a/assets/ron/houses/demons.house.ron b/assets/ron/houses/demons.house.ron deleted file mode 100644 index c70c3ad39..000000000 --- a/assets/ron/houses/demons.house.ron +++ /dev/null @@ -1,58 +0,0 @@ -#![enable(implicit_some)] -( - name: "Demons", - color: ("#880E4F"), - statuses: [ - ( - name: "Dark Satiety", - description: "+{Charges}/+{Charges}\nTurn End: lose 2 charges", - trigger: List( - [ - DeltaVar( - Hp, - Context(Charges), - ), - DeltaVar( - Atk, - Context(Charges), - ), - TurnEnd( - WithTarget( - Owner, - WithVar( - Charges, - Int(-2), - AddStatus( - "Dark Satiety", - ), - ), - ), - ), - ], - ), - shop_charges: 4, - ), - ], - abilities: [ - ( - name: "Devour", - description: "Kill target and gain [Dark Satiety] {2} for each HP", - effect: List( - [ - WithVar( - Charges, - TargetState(Hp), - WithTarget( - Owner, - AddStatus( - "Dark Satiety", - ), - ), - ), - Kill, - Vfx("apply_status"), - ], - ), - ), - ], -) \ No newline at end of file diff --git a/assets/ron/scenarios/devour.scenario.ron b/assets/ron/scenarios/devour.scenario.ron deleted file mode 100644 index 9d67eb82e..000000000 --- a/assets/ron/scenarios/devour.scenario.ron +++ /dev/null @@ -1,57 +0,0 @@ -#![enable(implicit_some)] -( - left: ( - units: [ - ( - hp: 1, - atk: 1, - trigger: BattleStart( - List( - [ - WithVar( - Faction, - OppositeFaction, - WithTarget( - RandomUnit, - UseAbility( - "Devour", - ), - ), - ), - WithTarget( - RandomAdjacentUnit, - UseAbility( - "Devour", - ), - ), - WithTarget( - RandomAdjacentUnit, - UseAbility( - "Devour", - ), - ), - ], - ), - ), - ), - (hp: 3, atk: 1), - ], - ), - right: ( - units: [ - (hp: 5, atk: 1), - (hp: 5, atk: 1), - (hp: 5, atk: 1), - ], - ), - condition: And( - Equals( - FactionCount(Faction(Left)), - Int(1), - ), - Equals( - FactionCount(Faction(Right)), - Int(0), - ), - ), -) \ No newline at end of file diff --git a/assets/ron/scenarios/devour_each_other.scenario.ron b/assets/ron/scenarios/devour_each_other.scenario.ron deleted file mode 100644 index a9706bd42..000000000 --- a/assets/ron/scenarios/devour_each_other.scenario.ron +++ /dev/null @@ -1,42 +0,0 @@ -#![enable(implicit_some)] -( - left: ( - units: [ - ( - hp: 1, - atk: 1, - trigger: BattleStart( - WithTarget( - RandomAdjacentUnit, - UseAbility( - "Devour", - ), - ), - ), - ), - ( - hp: 1, - atk: 1, - trigger: BattleStart( - WithTarget( - RandomAdjacentUnit, - UseAbility( - "Devour", - ), - ), - ), - ), - ], - ), - right: (units: [(hp: 2, atk: 2)]), - condition: And( - Equals( - FactionCount(Faction(Left)), - Int(0), - ), - Equals( - FactionCount(Faction(Right)), - Int(0), - ), - ), -) \ No newline at end of file diff --git a/assets/ron/scenarios/devour_first.scenario.ron b/assets/ron/scenarios/devour_first.scenario.ron deleted file mode 100644 index 9dc002eb9..000000000 --- a/assets/ron/scenarios/devour_first.scenario.ron +++ /dev/null @@ -1,41 +0,0 @@ -#![enable(implicit_some)] -( - left: ( - units: [ - ( - hp: 1, - atk: 1, - trigger: BattleStart( - WithVar( - Faction, - OppositeFaction, - WithTarget( - SlotUnit( - Int(1), - ), - UseAbility( - "Devour", - ), - ), - ), - ), - ), - ], - ), - right: ( - units: [ - (hp: 5, atk: 1), - (hp: 5, atk: 1), - ], - ), - condition: And( - Equals( - FactionCount(Faction(Left)), - Int(1), - ), - Equals( - FactionCount(Faction(Right)), - Int(0), - ), - ), -) \ No newline at end of file diff --git a/assets/ron/unit.rep.ron b/assets/ron/unit.rep.ron index 59beb55b7..c73deb335 100644 --- a/assets/ron/unit.rep.ron +++ b/assets/ron/unit.rep.ron @@ -60,5 +60,24 @@ ), ], ), + ( + material: Shape( + shape: Circle, + color: Hex("#B0BEC5"), + size: Vec2E(Float(0.3)), + ), + mapping: {Position: Vec2(0.9, 0.6), Visible: GreaterThen(State(Stacks), Int(1))}, + children: [ + ( + material: Text( + text: Sum(String("x"), StringInt( + State(Stacks), + )), + size: Float(0.4), + color: Hex("#ffffff"), + ), + ), + ], + ), ], ) \ No newline at end of file diff --git a/src/plugins/shop.rs b/src/plugins/shop.rs index f284daa1f..07d9c62a6 100644 --- a/src/plugins/shop.rs +++ b/src/plugins/shop.rs @@ -13,7 +13,7 @@ pub struct ShopPlugin; #[derive(Resource, Clone)] pub struct ShopData { pub next_team: PackedTeam, - pub next_team_cards: Vec<(UnitCard, usize)>, + pub next_team_cards: Vec, pub next_level_num: usize, pub bottom_expanded: bool, pub tower_teams: Vec, @@ -404,15 +404,12 @@ impl ShopPlugin { .rich_text(), ); ui.add_space(20.0); - fn show_card(card: &UnitCard, count: &usize, data: &ShopData, ui: &mut Ui) { - if *count > 1 { - ui.label(format!("x{count}").add_color(white()).rich_text()); - } + fn show_card(card: &UnitCard, data: &ShopData, ui: &mut Ui) { card.show_ui(data.bottom_expanded, false, ui); } if data.next_team_cards.len() <= 5 || !data.bottom_expanded { - for (card, count) in data.next_team_cards.iter().rev() { - show_card(card, count, data, ui); + for card in data.next_team_cards.iter().rev() { + show_card(card, data, ui); } } else { let mut it = data.next_team_cards.iter().peekable(); @@ -420,8 +417,8 @@ impl ShopPlugin { while it.peek().is_some() { ui.horizontal(|ui| { for _ in 0..5 { - if let Some((card, count)) = it.next() { - show_card(card, count, data, ui); + if let Some(card) = it.next() { + show_card(card, data, ui); } else { break; } @@ -430,9 +427,7 @@ impl ShopPlugin { } }); } - if !data.bottom_expanded { - ui.label("NEXT ENEMY:"); - } + ui.label("NEXT ENEMY:"); }); }) .response; @@ -446,7 +441,7 @@ impl ShopPlugin { let ctx = &egui_context(world); for entity in UnitPlugin::collect_faction(Faction::Team, world) { window("SELL") - .id(&entity) + .id(entity) .set_width(120.0) .title_bar(false) .stroke(false) diff --git a/src/plugins/ui.rs b/src/plugins/ui.rs index d2fc46a6a..13a7b50ec 100644 --- a/src/plugins/ui.rs +++ b/src/plugins/ui.rs @@ -180,7 +180,7 @@ impl GameWindow<'_> { let mut stroke = style.visuals.window_stroke; stroke.color = self.color.unwrap_or(style.visuals.window_stroke.color); self.frame - .unwrap_or(Frame::window(&style).stroke(stroke)) + .unwrap_or(Frame::window(style).stroke(stroke)) .show(ui, |ui| { ui.set_width(self.width); if self.title_bar { diff --git a/src/plugins/unit.rs b/src/plugins/unit.rs index 2a82e65d7..7dd8fc671 100644 --- a/src/plugins/unit.rs +++ b/src/plugins/unit.rs @@ -12,8 +12,8 @@ impl Plugin for UnitPlugin { pub const TEAM_SLOTS: usize = 7; -#[derive(Resource, Debug)] -pub struct ClosestSlot(usize, f32); +#[derive(Resource, Debug, Copy, Clone)] +pub struct ClosestSlot(usize, f32, bool); impl UnitPlugin { pub fn get_unit_position(entity: Entity, world: &World) -> Result { @@ -231,33 +231,47 @@ impl UnitPlugin { for entity in team.iter_mut() { commands.entity(entity).insert(Pickable::IGNORE); } - commands.insert_resource(ClosestSlot(0, f32::MAX)); + commands.insert_resource(ClosestSlot(0, f32::MAX, false)); + } + + pub fn change_stacks(unit: Entity, delta: i32, world: &mut World) { + VarState::change_int(unit, VarName::Stacks, delta, world).unwrap(); + VarState::change_int(unit, VarName::Hp, delta, world).unwrap(); + VarState::change_int(unit, VarName::Atk, delta, world).unwrap(); } pub fn drag_unit_end( event: Listener>, - mut dragged: ResMut, - closest_slot: Res, - timer: Res, mut team: Query>, - mut state: Query<&mut VarState>, mut commands: Commands, ) { debug!("Drag unit end {:?}", event.target); - let unit = event.target; - dragged.0 = None; for entity in team.iter_mut() { commands.entity(entity).insert(Pickable::default()); } - let mut state = state.get_mut(unit).unwrap(); - state.insert_simple( - VarName::Slot, - VarValue::Int(closest_slot.0 as i32), - timer.insert_head(), - ); + commands.add(|world: &mut World| { + let dragged = world.resource::().0.unwrap(); + let ClosestSlot(slot, _, stackable) = *world.resource::(); + if stackable { + world.entity_mut(dragged).despawn_recursive(); + Self::change_stacks( + Self::find_unit(Faction::Team, slot, world).unwrap(), + 1, + world, + ); + } else { + let t = GameTimer::get(world).insert_head(); + VarState::get_mut(dragged, world).insert_simple( + VarName::Slot, + VarValue::Int(slot as i32), + t, + ); + } Self::fill_slot_gaps(Faction::Team, world); Self::translate_to_slots(world); + + world.resource_mut::().0 = None; }); } @@ -271,9 +285,27 @@ impl UnitPlugin { if let Some(prev_closest) = world.get_resource::() { let closest_slot = Self::get_closest_slot(cursor_pos, Faction::Team); if prev_closest.0 != closest_slot.0 { - Self::make_slot_gap(Faction::Team, closest_slot.0 as i32, world); - Self::translate_to_slots(world); - world.insert_resource(ClosestSlot(closest_slot.0, closest_slot.1)); + let name = VarState::get(dragged, world) + .get_string(VarName::Name) + .unwrap(); + let stackable = if Self::find_unit(Faction::Team, closest_slot.0, world) + .is_some_and(|entity| { + VarState::get(entity, world) + .get_string(VarName::Name) + .unwrap() + .eq(&name) + }) { + true + } else { + Self::make_slot_gap(Faction::Team, closest_slot.0 as i32, world); + Self::translate_to_slots(world); + false + }; + world.insert_resource(ClosestSlot( + closest_slot.0, + closest_slot.1, + stackable, + )); } } } diff --git a/src/resourses/effect.rs b/src/resourses/effect.rs index b4534dad6..5cae9b840 100644 --- a/src/resourses/effect.rs +++ b/src/resourses/effect.rs @@ -115,7 +115,16 @@ impl Effect { .with_context(|| format!("Ability not found {ability}"))? .effect .clone(); - ActionCluster::current(world).push_action_front(effect, context.clone()); + { + let mut context = context.clone(); + if context.get_var(VarName::Charges, world).is_none() { + context.set_var( + VarName::Charges, + context.get_var(VarName::Stacks, world).unwrap(), + ); + } + ActionCluster::current(world).push_action_front(effect, context); + } Pools::get_vfx("text", world) .clone() .set_var( diff --git a/src/resourses/packed_team.rs b/src/resourses/packed_team.rs index f82c05857..bd7a88346 100644 --- a/src/resourses/packed_team.rs +++ b/src/resourses/packed_team.rs @@ -103,18 +103,10 @@ impl PackedTeam { pub fn state_mut(faction: Faction, world: &mut World) -> Option> { Self::find_entity(faction, world).map(|e| VarState::get_mut(e, world)) } - pub fn get_cards(&self, world: &mut World) -> Vec<(UnitCard, usize)> { - let mut result: Vec<(PackedUnit, usize)> = default(); - for unit in &self.units { - if result.last().map(|(u, _)| u.eq(unit)).unwrap_or_default() { - result.last_mut().unwrap().1 += 1; - } else { - result.push((unit.clone(), 1)); - } - } - result - .into_iter() - .map(|(u, c)| (UnitCard::from_packed(u, world).unwrap().set_open(false), c)) + pub fn get_cards(&self, world: &mut World) -> Vec { + self.units + .iter() + .map(|unit| UnitCard::from_packed(unit.clone(), world).unwrap()) .collect_vec() } } diff --git a/src/resourses/packed_unit.rs b/src/resourses/packed_unit.rs index 1a9a6076a..4f987b3b1 100644 --- a/src/resourses/packed_unit.rs +++ b/src/resourses/packed_unit.rs @@ -8,6 +8,8 @@ use super::*; pub struct PackedUnit { pub hp: i32, pub atk: i32, + #[serde(default = "default_stacks")] + pub stacks: i32, #[serde(default = "default_house")] pub house: String, #[serde(default)] @@ -30,6 +32,9 @@ fn default_house() -> String { fn default_text() -> String { "empty".to_owned() } +fn default_stacks() -> i32 { + 1 +} pub const LOCAL_TRIGGER: &str = "_local"; @@ -71,6 +76,7 @@ impl PackedUnit { self.state .init(VarName::Hp, VarValue::Int(self.hp)) .init(VarName::Atk, VarValue::Int(self.atk)) + .init(VarName::Stacks, VarValue::Int(self.stacks)) .init(VarName::House, VarValue::String(self.house.clone())) .init(VarName::Name, VarValue::String(self.name.clone())) .init(VarName::Position, VarValue::Vec2(default())) @@ -138,6 +144,7 @@ impl PackedUnit { let state = VarState::get(entity, world).clone(); let hp = state.get_int(VarName::Hp).unwrap(); let atk = state.get_int(VarName::Atk).unwrap(); + let stacks = state.get_int(VarName::Stacks).unwrap(); let name = state.get_string(VarName::Name).unwrap(); let description = state.get_string(VarName::Description).unwrap(); let house = state.get_string(VarName::House).unwrap(); @@ -168,6 +175,7 @@ impl PackedUnit { state, description, statuses, + stacks, } } diff --git a/src/resourses/unit_card.rs b/src/resourses/unit_card.rs index 152efea21..d28f73fa3 100644 --- a/src/resourses/unit_card.rs +++ b/src/resourses/unit_card.rs @@ -102,10 +102,14 @@ impl UnitCard { .inject_definitions(world); let hp = VarState::find_value(entity, VarName::Hp, t, world)?.get_int()?; let atk = VarState::find_value(entity, VarName::Atk, t, world)?.get_int()?; + let stacks = VarState::find_value(entity, VarName::Stacks, t, world)?.get_int()?; let name = state .get_string_at(VarName::Name, t)? .add_color(state.get_color_at(VarName::HouseColor, t)?.c32()); - let stats = format!(" {atk}/{hp}").add_color(white()); + let mut stats = format!(" {atk}/{hp}").add_color(white()); + if stacks > 1 { + stats.push(format!(" x{stacks} stacks"), light_gray()); + } Ok(Self { name, diff --git a/src/resourses/vars.rs b/src/resourses/vars.rs index 3c8cab239..4d2962b39 100644 --- a/src/resourses/vars.rs +++ b/src/resourses/vars.rs @@ -56,6 +56,7 @@ pub enum VarName { Index, IncomingDamage, OutgoingDamage, + Stacks, } #[derive(Serialize, Deserialize, Clone, Debug, Reflect, PartialEq)]