diff --git a/models/src/dto/armour.rs b/models/src/dto/armour.rs index a05e02d..cf052c8 100644 --- a/models/src/dto/armour.rs +++ b/models/src/dto/armour.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use bevy_ecs::{entity::Entity, world::World}; +use bevy_ecs::{prelude::*, relationship::RelatedSpawner}; use strum::Display; use crate::{ @@ -186,8 +186,8 @@ impl ArmourDto { .collect() } - pub fn spawn(self, world: &mut World) -> Entity { - let mut commands = world.spawn(draw_id()); + pub fn spawn(self, spawner: &mut RelatedSpawner<'_, ChildOf>) -> Entity { + let mut commands = spawner.spawn(draw_id()); commands.insert(( Name(self.name.to_string()), diff --git a/models/src/dto/player.rs b/models/src/dto/player.rs index 41b49fc..377df11 100644 --- a/models/src/dto/player.rs +++ b/models/src/dto/player.rs @@ -52,19 +52,6 @@ pub struct PlayerDto { impl PlayerDto { pub fn spawn(self, world: &mut World) -> EntityWorldMut<'_> { - let primary = self.weapons.primary.map(|p| p.spawn(world)); - let secondary = self.weapons.secondary.map(|s| s.spawn(world)); - let melee = self.weapons.melee.map(|m| m.spawn(world)); - let temporary = self.weapons.temporary.map(|m| m.spawn(world)); - let fists = WeaponDto::FISTS.spawn(world); - let kick = WeaponDto::KITCHEN_KNIFE.spawn(world); - - let head = self.armour.helmet.map(|a| a.spawn(world)); - let torso = self.armour.body.map(|a| a.spawn(world)); - let legs = self.armour.pants.map(|a| a.spawn(world)); - let hands = self.armour.gloves.map(|a| a.spawn(world)); - let feet = self.armour.boots.map(|a| a.spawn(world)); - let mut commands = world.spawn(draw_id()); commands.insert(( @@ -85,22 +72,48 @@ impl PlayerDto { faction, }); - commands.insert(Weapons { - primary, - secondary, - melee, - temporary, - kick, - fists, + let mut weapons = None; + commands.with_children(|spawner| { + let primary = self.weapons.primary.map(|p| p.spawn(spawner)); + let secondary = self.weapons.secondary.map(|s| s.spawn(spawner)); + let melee = self.weapons.melee.map(|m| m.spawn(spawner)); + let temporary = self.weapons.temporary.map(|m| m.spawn(spawner)); + let fists = WeaponDto::FISTS.spawn(spawner); + let kick = WeaponDto::KICK.spawn(spawner); + + weapons = Some(Weapons { + primary, + secondary, + melee, + temporary, + kick, + fists, + }); + }); + if let Some(weapons) = weapons { + commands.insert(weapons); + } + + let mut armour = None; + commands.with_children(|spawner| { + let head = self.armour.helmet.map(|a| a.spawn(spawner)); + let torso = self.armour.body.map(|a| a.spawn(spawner)); + let legs = self.armour.pants.map(|a| a.spawn(spawner)); + let hands = self.armour.gloves.map(|a| a.spawn(spawner)); + let feet = self.armour.boots.map(|a| a.spawn(spawner)); + + armour = Some(PlayerArmour { + torso, + head, + legs, + feet, + hands, + }) }); - commands.insert(PlayerArmour { - torso, - head, - legs, - feet, - hands, - }); + if let Some(armour) = armour { + commands.insert(armour); + } commands } diff --git a/models/src/dto/weapon.rs b/models/src/dto/weapon.rs index 62bb65b..a2f76f0 100644 --- a/models/src/dto/weapon.rs +++ b/models/src/dto/weapon.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use bevy_ecs::prelude::*; +use bevy_ecs::{prelude::*, relationship::RelatedSpawner}; use crate::{ bundle::{ @@ -252,8 +252,8 @@ impl WeaponDto { }) } - pub fn spawn(self, world: &mut World) -> Entity { - let mut commands = world.spawn(draw_id()); + pub fn spawn(self, spawner: &mut RelatedSpawner<'_, ChildOf>) -> Entity { + let mut commands = spawner.spawn(draw_id()); let verb = match self.kind { WeaponSlot::Primary | WeaponSlot::Secondary => WeaponVerb::Fired, diff --git a/models/src/hierarchy.rs b/models/src/hierarchy.rs deleted file mode 100644 index 48c8803..0000000 --- a/models/src/hierarchy.rs +++ /dev/null @@ -1,178 +0,0 @@ -use bevy_ecs::{ - prelude::*, - system::{Command, EntityCommands}, -}; - -#[derive(Component, Debug, Clone, Copy)] -pub struct Parent(Entity); - -impl Parent { - pub fn get(&self) -> Entity { - self.0 - } -} - -#[derive(Component, Debug, Clone, Default)] -pub struct Children(Vec); - -impl Children { - pub fn get(&self) -> &[Entity] { - &self.0 - } -} - -struct AddChild { - parent: Entity, - child: Entity, -} - -impl Command for AddChild { - fn apply(self, world: &mut World) { - let mut parent = world.entity_mut(self.parent); - if let Some(mut children) = parent.get_mut::() { - children.0.push(self.child); - } else { - parent.insert(Children(vec![self.child])); - } - } -} - -struct AddChildren { - parent: Entity, - children: Vec, -} - -impl Command for AddChildren { - fn apply(mut self, world: &mut World) { - let mut parent = world.entity_mut(self.parent); - if let Some(mut children) = parent.get_mut::() { - children.0.append(&mut self.children); - } else { - parent.insert(Children(self.children)); - } - } -} - -struct RemoveChild { - parent: Entity, - child: Entity, -} - -impl Command for RemoveChild { - fn apply(self, world: &mut World) { - let mut parent = world.entity_mut(self.parent); - let mut children = parent - .get_mut::() - .expect("Parent component has no children"); - children.0.retain(|child| *child != self.child); - } -} - -pub trait HierarchyBuilder { - fn add_child(&mut self, child: Entity) -> &mut Self; - - fn add_children(&mut self, children: impl AsRef<[Entity]>) -> &mut Self; - - fn remove_child(&mut self, child: Entity) -> &mut Self; - - fn set_parent(&mut self, parent: Entity) -> &mut Self; -} - -impl<'a> HierarchyBuilder for EntityCommands<'a> { - fn add_child(&mut self, child: Entity) -> &mut Self { - let parent = self.id(); - self.commands().queue(AddChild { parent, child }); - self.commands().entity(child).insert(Parent(parent)); - self - } - - fn add_children(&mut self, children: impl AsRef<[Entity]>) -> &mut Self { - let children = children.as_ref(); - let parent = self.id(); - self.commands().queue(AddChildren { - parent, - children: children.to_owned(), - }); - self.commands().insert_batch( - children - .iter() - .map(|e| (*e, Parent(parent))) - .collect::>(), - ); - self - } - - fn remove_child(&mut self, child: Entity) -> &mut Self { - let parent = self.id(); - self.commands().queue(RemoveChild { parent, child }); - self.commands().entity(child).remove::(); - self - } - - fn set_parent(&mut self, parent: Entity) -> &mut Self { - let child = self.id(); - self.commands().queue(AddChild { parent, child }); - self.commands().entity(child).insert(Parent(parent)); - self - } -} - -impl<'w> HierarchyBuilder for EntityWorldMut<'w> { - fn add_child(&mut self, child: Entity) -> &mut Self { - let parent_id = self.id(); - unsafe { - self.world_mut() - .entity_mut(child) - .insert(Parent(parent_id)) - .update_location(); - } - if let Some(mut children) = self.get_mut::() { - children.0.push(child); - self - } else { - self.insert(Children(vec![child])) - } - } - - fn add_children(&mut self, children: impl AsRef<[Entity]>) -> &mut Self { - let parent_id = self.id(); - unsafe { - for child in children.as_ref() { - self.world_mut() - .entity_mut(*child) - .insert(Parent(parent_id)) - .update_location(); - } - } - if let Some(mut old_children) = self.get_mut::() { - old_children.0.append(&mut children.as_ref().to_owned()); - self - } else { - self.insert(Children(children.as_ref().to_owned())) - } - } - - fn remove_child(&mut self, child: Entity) -> &mut Self { - unsafe { - self.world_mut() - .entity_mut(child) - .remove::() - .update_location(); - } - if let Some(mut children) = self.get_mut::() { - children.0.retain(|c| *c != child); - } - self - } - - fn set_parent(&mut self, parent: Entity) -> &mut Self { - let child_id = self.id(); - unsafe { - self.world_mut() - .entity_mut(parent) - .add_child(child_id) - .update_location() - } - self - } -} diff --git a/models/src/lib.rs b/models/src/lib.rs index 38a09f9..c883773 100644 --- a/models/src/lib.rs +++ b/models/src/lib.rs @@ -1,3 +1,2 @@ pub mod bundle; pub mod dto; -// pub mod hierarchy; diff --git a/src/armour/mod.rs b/src/armour/mod.rs index bc3b2a1..5b8fd54 100644 --- a/src/armour/mod.rs +++ b/src/armour/mod.rs @@ -1,18 +1,15 @@ use bevy_ecs::prelude::*; -use proxisim_models::{ - bundle::armour::{ - ArmourBodyPart, ArmourBodyPartSlot, ArmourBodyParts, ArmourCoverage, ArmourValue, - ArmourVec, BodyPartCoverage, Immunities, Immunity, PlayerArmour, - }, - hierarchy::HierarchyBuilder, +use proxisim_models::bundle::armour::{ + ArmourBodyPart, ArmourBodyPartSlot, ArmourBodyParts, ArmourCoverage, ArmourValue, ArmourVec, + BodyPartCoverage, Immunities, Immunity, PlayerArmour, }; use strum::IntoEnumIterator; use crate::{ + Stages, player::status_effect::{ ConcussionGrenade, FlashGrenade, PepperSpray, TearGas, TempDebuffImmunity, }, - Stages, }; fn generate_body_parts( @@ -24,7 +21,7 @@ fn generate_body_parts( let mut parts = ArmourVec::::default(); for (armour, coverage, armour_value, immunities) in armour_q.iter_many(equipped_armour) { - commands.entity(armour).set_parent(player); + // commands.entity(player).add_child(armour); if let Some(immunities) = immunities { let mut player = commands.entity(player); diff --git a/src/effect.rs b/src/effect.rs index aa371a1..6dfa64e 100644 --- a/src/effect.rs +++ b/src/effect.rs @@ -1,10 +1,7 @@ use std::{any::TypeId, collections::HashMap, sync::Mutex}; use bevy_ecs::{prelude::*, system::SystemParam}; -use proxisim_models::{ - bundle::player::{Current, Defender, Player}, - hierarchy::{HierarchyBuilder, Parent}, -}; +use proxisim_models::bundle::player::{Current, Defender, Player}; use crate::Stages; @@ -77,13 +74,9 @@ impl<'w, 's> Effects<'w, 's> { ) -> Entity { let id = self.registry.type_map.get(&TypeId::of::()).unwrap(); - let spawned_effect = self - .commands - .spawn(effect) - .insert(*id) - .insert(addins) - .set_parent(to) - .id(); + let spawned_effect = self.commands.spawn(effect).insert(*id).insert(addins).id(); + + self.commands.entity(to).add_child(spawned_effect); self.scheduled .create @@ -202,7 +195,7 @@ pub(crate) fn run_effects(world: &mut World) { }; for entity in entities { - let parent = world.entity(entity).get::().unwrap().get(); + let parent = world.entity(entity).get::().unwrap().parent(); world.entity_mut(parent).remove_child(entity); world.despawn(entity); } @@ -277,12 +270,12 @@ fn mark_permanent_effects(effect_q: Query>, mut commands: } fn remove_transient_effects( - effect_q: Query<(Entity, &Parent), (With, Without)>, + effect_q: Query<(Entity, &ChildOf), (With, Without)>, mut commands: Commands, ) { for (effect, target) in effect_q.iter() { commands.entity(effect).despawn(); - commands.entity(target.get()).remove_child(effect); + commands.entity(target.parent()).remove_child(effect); } } diff --git a/src/entity_registry.rs b/src/entity_registry.rs index eb0022f..1604260 100644 --- a/src/entity_registry.rs +++ b/src/entity_registry.rs @@ -3,12 +3,11 @@ use std::collections::HashMap; use bevy_ecs::prelude::*; use proxisim_models::{ bundle::{ + Id, Name, player::{Attacker, Player}, weapon::Weapon, - Id, Name, }, dto::metrics::EntityInfo, - hierarchy::Parent, }; use crate::Stages; @@ -18,7 +17,7 @@ pub struct EntityRegistry(pub HashMap); fn read_entities( player_q: Query<(Entity, &Name, &Id, Has), With>, - weapon_q: Query<(Entity, &Parent, &Name, &Id), With>, + weapon_q: Query<(Entity, &ChildOf, &Name, &Id), With>, mut registry: ResMut, ) { for (player, name, id, is_attacker) in player_q.iter() { @@ -33,7 +32,7 @@ fn read_entities( } for (weapon, player, name, id) in weapon_q.iter() { - let (_, _, player_id, _) = player_q.get(player.get()).unwrap(); + let (_, _, player_id, _) = player_q.get(player.parent()).unwrap(); registry.0.insert( weapon, EntityInfo::Weapon { diff --git a/src/hierarchy.rs b/src/hierarchy.rs deleted file mode 100644 index 0d20a7a..0000000 --- a/src/hierarchy.rs +++ /dev/null @@ -1,178 +0,0 @@ -use bevy_ecs::{ - prelude::*, - system::{Command, EntityCommands}, -}; - -#[derive(Component, Clone, Copy)] -pub struct Parent(Entity); - -impl Parent { - pub fn get(&self) -> Entity { - self.0 - } -} - -#[derive(Component, Clone, Default)] -pub struct Children(Vec); - -impl Children { - pub fn get(&self) -> &[Entity] { - &self.0 - } -} - -struct AddChild { - parent: Entity, - child: Entity, -} - -impl Command for AddChild { - fn apply(self, world: &mut World) { - let mut parent = world.entity_mut(self.parent); - if let Some(mut children) = parent.get_mut::() { - children.0.push(self.child); - } else { - parent.insert(Children(vec![self.child])); - } - } -} - -struct AddChildren { - parent: Entity, - children: Vec, -} - -impl Command for AddChildren { - fn apply(mut self, world: &mut World) { - let mut parent = world.entity_mut(self.parent); - if let Some(mut children) = parent.get_mut::() { - children.0.append(&mut self.children); - } else { - parent.insert(Children(self.children)); - } - } -} - -struct RemoveChild { - parent: Entity, - child: Entity, -} - -impl Command for RemoveChild { - fn apply(self, world: &mut World) { - let mut parent = world.entity_mut(self.parent); - let mut children = parent - .get_mut::() - .expect("Parent component has no children"); - children.0.retain(|child| *child != self.child); - } -} - -pub trait HierarchyBuilder { - fn add_child(&mut self, child: Entity) -> &mut Self; - - fn add_children(&mut self, children: impl AsRef<[Entity]>) -> &mut Self; - - fn remove_child(&mut self, child: Entity) -> &mut Self; - - fn set_parent(&mut self, parent: Entity) -> &mut Self; -} - -impl<'a> HierarchyBuilder for EntityCommands<'a> { - fn add_child(&mut self, child: Entity) -> &mut Self { - let parent = self.id(); - self.commands().queue(AddChild { parent, child }); - self.commands().entity(child).insert(Parent(parent)); - self - } - - fn add_children(&mut self, children: impl AsRef<[Entity]>) -> &mut Self { - let children = children.as_ref(); - let parent = self.id(); - self.commands().queue(AddChildren { - parent, - children: children.to_owned(), - }); - self.commands().insert_batch( - children - .iter() - .map(|e| (*e, Parent(parent))) - .collect::>(), - ); - self - } - - fn remove_child(&mut self, child: Entity) -> &mut Self { - let parent = self.id(); - self.commands().queue(RemoveChild { parent, child }); - self.commands().entity(child).remove::(); - self - } - - fn set_parent(&mut self, parent: Entity) -> &mut Self { - let child = self.id(); - self.commands().queue(AddChild { parent, child }); - self.commands().entity(child).insert(Parent(parent)); - self - } -} - -impl<'w> HierarchyBuilder for EntityWorldMut<'w> { - fn add_child(&mut self, child: Entity) -> &mut Self { - let parent_id = self.id(); - unsafe { - self.world_mut() - .entity_mut(child) - .insert(Parent(parent_id)) - .update_location(); - } - if let Some(mut children) = self.get_mut::() { - children.0.push(child); - self - } else { - self.insert(Children(vec![child])) - } - } - - fn add_children(&mut self, children: impl AsRef<[Entity]>) -> &mut Self { - let parent_id = self.id(); - unsafe { - for child in children.as_ref() { - self.world_mut() - .entity_mut(*child) - .insert(Parent(parent_id)) - .update_location(); - } - } - if let Some(mut old_children) = self.get_mut::() { - old_children.0.append(&mut children.as_ref().to_owned()); - self - } else { - self.insert(Children(children.as_ref().to_owned())) - } - } - - fn remove_child(&mut self, child: Entity) -> &mut Self { - unsafe { - self.world_mut() - .entity_mut(child) - .remove::() - .update_location(); - } - if let Some(mut children) = self.get_mut::() { - children.0.retain(|c| *c != child); - } - self - } - - fn set_parent(&mut self, parent: Entity) -> &mut Self { - let child_id = self.id(); - unsafe { - self.world_mut() - .entity_mut(parent) - .add_child(child_id) - .update_location() - } - self - } -} diff --git a/src/log.rs b/src/log.rs index 4773fa9..c6652a4 100644 --- a/src/log.rs +++ b/src/log.rs @@ -1,16 +1,13 @@ use std::sync::Mutex; use bevy_ecs::{prelude::*, query::QuerySingleError, system::SystemParam}; -use proxisim_models::{ - bundle::{ - stat::{ - AdditiveBonus, BaselineStat, ClipSize, Clips, CritRate, DamageBonus, Defence, - Dexterity, EffectiveStat, MultiplicativeBonus, SimpleStatBaseline, SimpleStatBonus, - SimpleStatEffective, SimpleStatMarker, Speed, StatMarker, Strength, WeaponAccuracy, - }, - weapon::WeaponVerb, +use proxisim_models::bundle::{ + stat::{ + AdditiveBonus, BaselineStat, ClipSize, Clips, CritRate, DamageBonus, Defence, Dexterity, + EffectiveStat, MultiplicativeBonus, SimpleStatBaseline, SimpleStatBonus, + SimpleStatEffective, SimpleStatMarker, Speed, StatMarker, Strength, WeaponAccuracy, }, - hierarchy::Children, + weapon::WeaponVerb, }; use crate::{Stages, entity_registry::EntityRegistry}; @@ -533,11 +530,11 @@ fn log_stat_changes( ) { for (player, baseline, effective, children) in stat_q.iter() { let effects_add: Vec<_> = add_q - .iter_many(children.get()) + .iter_many(children) .map(|bonus| (bonus.label, 100.0 * bonus.value)) .collect(); let effects_mult: Vec<_> = mult_q - .iter_many(children.get()) + .iter_many(children) .map(|bonus| (bonus.label, 100.0 * bonus.value)) .collect(); @@ -570,7 +567,7 @@ fn log_simple_stat_changes( { for (target, baseline, effective, children) in stat_q.iter() { let bonuses: Vec<_> = bonus_q - .iter_many(children.get()) + .iter_many(children) .map(|bonus| (bonus.label, Stat::denormalise_bonus(bonus.value))) .collect(); diff --git a/src/player/mod.rs b/src/player/mod.rs index d6884ef..4799998 100644 --- a/src/player/mod.rs +++ b/src/player/mod.rs @@ -1,23 +1,18 @@ use bevy_ecs::prelude::*; -use proxisim_models::{ - bundle::{ - armour::{ArmourBodyPart, ArmourBodyParts}, - passive::{FactionUpgrades, Merits}, - player::{ - Attacker, BodyPart, ChooseWeapon, CombatTurns, Current, CurrentTarget, Defeated, - Defender, FightEndType, Level, MaxHealth, PartDamageBonus, Player, PlayerStrategy, - Weapons, - }, - stat::{ - AmmoControl, Clips, CritRate, DamageBonus, Defence, Dexterity, EffectiveStat, Health, - SimpleStatBundle, SimpleStatEffective, Speed, Strength, WeaponAccuracy, - }, - weapon::{ - Ammo, DamageStat, NeedsReload, NonTargeted, RateOfFire, Usable, Uses, Weapon, - WeaponSlot, - }, +use proxisim_models::bundle::{ + armour::{ArmourBodyPart, ArmourBodyParts}, + passive::{FactionUpgrades, Merits}, + player::{ + Attacker, BodyPart, ChooseWeapon, CombatTurns, Current, CurrentTarget, Defeated, Defender, + FightEndType, Level, MaxHealth, PartDamageBonus, Player, PlayerStrategy, Weapons, + }, + stat::{ + AmmoControl, Clips, CritRate, DamageBonus, Defence, Dexterity, EffectiveStat, Health, + SimpleStatBundle, SimpleStatEffective, Speed, Strength, WeaponAccuracy, + }, + weapon::{ + Ammo, DamageStat, NeedsReload, NonTargeted, RateOfFire, Usable, Uses, Weapon, WeaponSlot, }, - hierarchy::Children, }; use rand::Rng as _; @@ -33,12 +28,12 @@ use crate::{ pub mod stats; pub mod status_effect; -fn select_weapon( +fn select_weapon<'a>( weapons: &Weapons, slot: WeaponSlot, reload: bool, - usable_q: &Query<(Has, Option<&Children>), With>, -) -> Option<(Entity, Option)> { + usable_q: &'a Query<(Has, Option<&Children>), With>, +) -> Option<(Entity, Option<&'a Children>)> { let id = match slot { WeaponSlot::Primary => weapons.primary?, WeaponSlot::Secondary => weapons.secondary?, @@ -53,7 +48,7 @@ fn select_weapon( if !reload && needs_reload { None } else { - Some((id, children.cloned())) + Some((id, children)) } } @@ -155,7 +150,7 @@ pub fn pick_action( let target = target_q.single().unwrap(); if let Some(children) = children { - for effect in weapon_trigger_q.iter_many(children.get()) { + for effect in weapon_trigger_q.iter_many(children) { effect.trigger(&mut effects, current, target); } } @@ -357,7 +352,7 @@ pub fn use_damaging_weapon( let mut dmg_bonus = dmg_bonus + p_dmg_bonus; - for part_bonus in part_bonus_q.iter_many(children.get()) { + for part_bonus in part_bonus_q.iter_many(children) { if let Some(bonus) = part_bonus.dmg_bonus(body_part) { dmg_bonus.value += bonus; } @@ -378,7 +373,7 @@ pub fn use_damaging_weapon( metrics.record_histogram(Some(weapon), "dmg", dmg); if dmg > 0 { - for effect in damage_proc_q.iter_many(children.get()) { + for effect in damage_proc_q.iter_many(children) { match *effect { DamageProcEffect::MultiTurn { value, bonus } => { if multi_attack_proc.is_some() { diff --git a/src/player/stats.rs b/src/player/stats.rs index bf823b5..6041010 100644 --- a/src/player/stats.rs +++ b/src/player/stats.rs @@ -1,21 +1,18 @@ use std::marker::PhantomData; use bevy_ecs::prelude::*; -use proxisim_models::{ - bundle::stat::{ - AdditiveBonus, AdditiveBonuses, AmmoControl, BaselineStat, ClipSize, Clips, CritRate, - DamageBonus, Defence, Dexterity, EffectiveStat, Health, MultiplicativeBonus, - MultiplicativeBonuses, SimpleStatBonus, SimpleStatEffective, SimpleStatMarker, - SimpleStatSnapshot, Speed, StatMarker, StatSnapshot, Strength, WeaponAccuracy, - }, - hierarchy::Parent, +use proxisim_models::bundle::stat::{ + AdditiveBonus, AdditiveBonuses, AmmoControl, BaselineStat, ClipSize, Clips, CritRate, + DamageBonus, Defence, Dexterity, EffectiveStat, Health, MultiplicativeBonus, + MultiplicativeBonuses, SimpleStatBonus, SimpleStatEffective, SimpleStatMarker, + SimpleStatSnapshot, Speed, StatMarker, StatSnapshot, Strength, WeaponAccuracy, }; use crate::Stages; fn add_additive_bonus( In(entities): In>, - effect_q: Query<(&AdditiveBonus, &Parent)>, + effect_q: Query<(&AdditiveBonus, &ChildOf)>, mut stat_q: Query<( &BaselineStat, &mut AdditiveBonuses, @@ -24,7 +21,7 @@ fn add_additive_bonus( )>, ) { for (bonus, player) in effect_q.iter_many(entities) { - let (baseline, mut add, mult, mut eff) = stat_q.get_mut(player.get()).unwrap(); + let (baseline, mut add, mult, mut eff) = stat_q.get_mut(player.parent()).unwrap(); add.factor += bonus.value; eff.value = baseline.value * add.factor * mult.factor; } @@ -32,7 +29,7 @@ fn add_additive_bonus( fn revert_additive_bonus( In(entities): In>, - effect_q: Query<(&AdditiveBonus, &Parent)>, + effect_q: Query<(&AdditiveBonus, &ChildOf)>, mut stat_q: Query<( &BaselineStat, &mut AdditiveBonuses, @@ -41,7 +38,7 @@ fn revert_additive_bonus( )>, ) { for (bonus, player) in effect_q.iter_many(entities) { - let (baseline, mut add, mult, mut eff) = stat_q.get_mut(player.get()).unwrap(); + let (baseline, mut add, mult, mut eff) = stat_q.get_mut(player.parent()).unwrap(); add.factor -= bonus.value; eff.value = baseline.value * add.factor * mult.factor; } @@ -49,7 +46,7 @@ fn revert_additive_bonus( fn add_multiplicative_bonus( In(entities): In>, - effect_q: Query<(&MultiplicativeBonus, &Parent)>, + effect_q: Query<(&MultiplicativeBonus, &ChildOf)>, mut stat_q: Query<( &BaselineStat, &AdditiveBonuses, @@ -58,7 +55,7 @@ fn add_multiplicative_bonus( )>, ) { for (bonus, player) in effect_q.iter_many(entities) { - let (baseline, add, mut mult, mut eff) = stat_q.get_mut(player.get()).unwrap(); + let (baseline, add, mut mult, mut eff) = stat_q.get_mut(player.parent()).unwrap(); mult.factor *= bonus.value; eff.value = baseline.value * add.factor * mult.factor; } @@ -66,7 +63,7 @@ fn add_multiplicative_bonus( fn revert_multiplicative_bonus( In(entities): In>, - effect_q: Query<(&MultiplicativeBonus, &Parent)>, + effect_q: Query<(&MultiplicativeBonus, &ChildOf)>, mut stat_q: Query<( &BaselineStat, &AdditiveBonuses, @@ -75,7 +72,7 @@ fn revert_multiplicative_bonus( )>, ) { for (bonus, player) in effect_q.iter_many(entities) { - let (baseline, add, mut mult, mut eff) = stat_q.get_mut(player.get()).unwrap(); + let (baseline, add, mut mult, mut eff) = stat_q.get_mut(player.parent()).unwrap(); mult.factor /= bonus.value; eff.value = baseline.value * add.factor * mult.factor; } @@ -117,22 +114,22 @@ fn restore_stats( fn apply_simple_stat_bonus( In(entities): In>, - effect_q: Query<(&SimpleStatBonus, &Parent)>, + effect_q: Query<(&SimpleStatBonus, &ChildOf)>, mut stat_q: Query<&mut SimpleStatEffective>, ) { for (bonus, target) in effect_q.iter_many(&entities) { - let mut effective = stat_q.get_mut(target.get()).unwrap(); + let mut effective = stat_q.get_mut(target.parent()).unwrap(); effective.value = Stat::apply_bonus(effective.value, bonus.value); } } fn revert_simple_stat_bonus( In(entities): In>, - effect_q: Query<(&SimpleStatBonus, &Parent)>, + effect_q: Query<(&SimpleStatBonus, &ChildOf)>, mut stat_q: Query<&mut SimpleStatEffective>, ) { for (bonus, target) in effect_q.iter_many(entities) { - let mut effective = stat_q.get_mut(target.get()).unwrap(); + let mut effective = stat_q.get_mut(target.parent()).unwrap(); effective.value = Stat::revert_bonus(effective.value, bonus.value); } } diff --git a/src/player/status_effect.rs b/src/player/status_effect.rs index 918d4a2..e4e3c5f 100644 --- a/src/player/status_effect.rs +++ b/src/player/status_effect.rs @@ -1,11 +1,8 @@ use std::{collections::VecDeque, marker::PhantomData}; use bevy_ecs::prelude::*; -use proxisim_models::{ - bundle::stat::{ - AdditiveBonus, Defence, Dexterity, MultiplicativeBonus, Speed, StatMarker, Strength, - }, - hierarchy::Parent, +use proxisim_models::bundle::stat::{ + AdditiveBonus, Defence, Dexterity, MultiplicativeBonus, Speed, StatMarker, Strength, }; use rand::Rng as _; @@ -345,7 +342,7 @@ impl AdditiveStatusEffectMarker<2> for Frozen { fn apply_additive_status_effect>( In(entities): In>, - effect_q: Query<(Entity, &Parent, &AdditiveStatusEffect)>, + effect_q: Query<(Entity, &ChildOf, &AdditiveStatusEffect)>, mut parent_q: Query>>, mut commands: Commands, mut effects: Effects, @@ -353,15 +350,15 @@ fn apply_additive_status_effect ) { for (entity, player, effect) in effect_q.iter_many(entities) { log!(logger, "apply_status_effect", { - recipient: player.get(), + recipient: player.parent(), effect: std::any::type_name::(), }); - let stack = parent_q.get_mut(player.get()).unwrap(); + let stack = parent_q.get_mut(player.parent()).unwrap(); let new_effects = >::spawn_additive_effects( &mut effects, - player.get(), + player.parent(), M::factor() * (1.0 + effect.extra_effectiveness), std::any::type_name::(), ); @@ -389,13 +386,13 @@ fn apply_additive_status_effect fn remove_additive_status_effect>( In(entities): In>, - effect_q: Query<(Entity, &Parent)>, + effect_q: Query<(Entity, &ChildOf)>, mut parent_q: Query>>, linked_q: Query<&LinkedComponents>, mut effects: Effects, ) { for (effect, player) in effect_q.iter_many(entities) { - if let Some(mut stack) = parent_q.get_mut(player.get()).unwrap() + if let Some(mut stack) = parent_q.get_mut(player.parent()).unwrap() && stack.effects.front() == Some(&effect) { stack.effects.pop_front(); @@ -412,8 +409,8 @@ fn remove_additive_status_effect( In(entities): In>, mut rng: ResMut, - temp_q: Query<(Entity, &Parent, &AssociatedWeapon)>, - weapon_q: Query<&Parent>, + temp_q: Query<(Entity, &ChildOf, &AssociatedWeapon)>, + weapon_q: Query<&ChildOf>, mut parent_q: Query<( Option<&mut StatusEffectStack>, Has>, @@ -422,14 +419,14 @@ fn apply_temp_debuff_effect( mut logger: Logger, ) { for (effect, player, weapon) in temp_q.iter_many(entities) { - let (stack, immunity) = parent_q.get_mut(player.get()).unwrap(); + let (stack, immunity) = parent_q.get_mut(player.parent()).unwrap(); let user = weapon_q.get(weapon.0).unwrap(); if immunity { commands.entity(effect).despawn(); - commands.entity(player.get()).remove_child(effect); + commands.entity(player.parent()).remove_child(effect); log!(logger, "used_debuff_temp", { - actor: user.get(), - recipient: player.get(), + actor: user.parent(), + recipient: player.parent(), weapon: weapon.0, immune: true, }); @@ -447,7 +444,7 @@ fn apply_temp_debuff_effect( let bonus = effects.spawn( MultiplicativeBonus::::new(std::any::type_name::(), effective_factor), - player.get(), + player.parent(), ); if let Some(mut stack) = stack { @@ -456,7 +453,7 @@ fn apply_temp_debuff_effect( stack.effects.push_back(effect); } else { commands - .entity(player.get()) + .entity(player.parent()) .insert(StatusEffectStack:: { effects: VecDeque::from([effect]), bonus, @@ -465,8 +462,8 @@ fn apply_temp_debuff_effect( } log!(logger, "used_debuff_temp", { - actor: user.get(), - recipient: player.get(), + actor: user.parent(), + recipient: player.parent(), weapon: weapon.0, immune: false, }); @@ -475,14 +472,14 @@ fn apply_temp_debuff_effect( fn remove_temp_debuff_effect( In(entities): In>, - temp_q: Query<&Parent>, + temp_q: Query<&ChildOf>, mut parent_q: Query<(&mut StatusEffectStack, Has>)>, mut commands: Commands, _logger: Logger, mut effects: Effects, ) { for player in temp_q.iter_many(entities) { - let (mut stack, immunity) = parent_q.get_mut(player.get()).unwrap(); + let (mut stack, immunity) = parent_q.get_mut(player.parent()).unwrap(); if immunity { continue; } @@ -501,13 +498,13 @@ fn remove_temp_debuff_effect( std::any::type_name::(), effective_factor, ), - player.get(), + player.parent(), ); stack.effects.pop_front(); } else { commands - .entity(player.get()) + .entity(player.parent()) .remove::>(); } } diff --git a/src/weapon/bonus.rs b/src/weapon/bonus.rs index ebd1f46..424d2e0 100644 --- a/src/weapon/bonus.rs +++ b/src/weapon/bonus.rs @@ -1,14 +1,11 @@ use bevy_ecs::prelude::*; -use proxisim_models::{ - bundle::{ - bonus::{BonusPartDamageBonus, BonusValue, WeaponBonusType}, - player::PartDamageBonus, - stat::{ - AdditiveBonus, AmmoControl, Clips, CritRate, DamageBonus, SimpleStatBonus, - SimpleStatEffective, Speed, Strength, WeaponAccuracy, - }, +use proxisim_models::bundle::{ + bonus::{BonusPartDamageBonus, BonusValue, WeaponBonusType}, + player::PartDamageBonus, + stat::{ + AdditiveBonus, AmmoControl, Clips, CritRate, DamageBonus, SimpleStatBonus, + SimpleStatEffective, Speed, Strength, WeaponAccuracy, }, - hierarchy::{HierarchyBuilder, Parent}, }; use crate::{ @@ -197,7 +194,7 @@ impl BonusPartDamageBonus { } */ pub(crate) fn prepare_bonuses( - bonus_q: Query<(&Parent, &WeaponBonusType, &BonusValue)>, + bonus_q: Query<(&ChildOf, &WeaponBonusType, &BonusValue)>, clips_q: Query<&SimpleStatEffective>, mut effects: Effects, mut commands: Commands, @@ -207,227 +204,227 @@ pub(crate) fn prepare_bonuses( WeaponBonusType::Berserk => { effects.spawn( SimpleStatBonus::::new("beserk", value.0 / 100.0), - weapon.get(), + weapon.parent(), ); effects.spawn( SimpleStatBonus::::new("beserk", -value.0 / 2.0 / 50.0), - weapon.get(), + weapon.parent(), ); } WeaponBonusType::Conserve => { effects.spawn( SimpleStatBonus::::new("conserve", value.0 / 100.0), - weapon.get(), + weapon.parent(), ); } WeaponBonusType::Expose => { effects.spawn( SimpleStatBonus::::new("expose", (value.0 / 0.5) as u16), - weapon.get(), + weapon.parent(), ); } WeaponBonusType::Grace => { effects.spawn( SimpleStatBonus::::new("grace", -value.0 / 2.0 / 100.0), - weapon.get(), + weapon.parent(), ); effects.spawn( SimpleStatBonus::::new("grace", value.0 / 50.0), - weapon.get(), + weapon.parent(), ); } WeaponBonusType::Powerful => { effects.spawn( SimpleStatBonus::::new("powerful", value.0 / 100.0), - weapon.get(), + weapon.parent(), ); } WeaponBonusType::Specialist => { effects.spawn( SimpleStatBonus::::new("specialist", value.0 / 100.0), - weapon.get(), + weapon.parent(), ); - if let Ok(clips) = clips_q.get(weapon.get()) { + if let Ok(clips) = clips_q.get(weapon.parent()) { effects.spawn( SimpleStatBonus::::new("specialist", -(clips.value as i16)), - weapon.get(), + weapon.parent(), ); } } WeaponBonusType::Empower => { commands - .spawn(TurnTriggeredEffect::Bonus { + .entity(weapon.parent()) + .with_child(TurnTriggeredEffect::Bonus { value: value.0, bonus: TurnTriggeredBonus::Empower, - }) - .set_parent(weapon.get()); + }); } WeaponBonusType::Quicken => { commands - .spawn(TurnTriggeredEffect::Bonus { + .entity(weapon.parent()) + .with_child(TurnTriggeredEffect::Bonus { value: value.0, bonus: TurnTriggeredBonus::Quicken, - }) - .set_parent(weapon.get()); + }); } WeaponBonusType::Assassinate => { commands - .spawn(FirstTurnEffect::Bonus { + .entity(weapon.parent()) + .with_child(FirstTurnEffect::Bonus { value: value.0, bonus: FirstTurnBonus::Assassinate, - }) - .set_parent(weapon.get()); + }); } WeaponBonusType::Blindfire => { commands - .spawn(DamageProcEffect::MultiTurn { + .entity(weapon.parent()) + .with_child(DamageProcEffect::MultiTurn { value: value.0, bonus: MultiTurnBonus::Blindfire, - }) - .set_parent(weapon.get()); + }); } WeaponBonusType::Fury => { commands - .spawn(DamageProcEffect::MultiTurn { + .entity(weapon.parent()) + .with_child(DamageProcEffect::MultiTurn { value: value.0, bonus: MultiTurnBonus::Fury, - }) - .set_parent(weapon.get()); + }); } WeaponBonusType::Rage => { commands - .spawn(DamageProcEffect::MultiTurn { + .entity(weapon.parent()) + .with_child(DamageProcEffect::MultiTurn { value: value.0, bonus: MultiTurnBonus::Rage, - }) - .set_parent(weapon.get()); + }); } WeaponBonusType::DoubleTap => { commands - .spawn(DamageProcEffect::MultiTurn { + .entity(weapon.parent()) + .with_child(DamageProcEffect::MultiTurn { value: value.0, bonus: MultiTurnBonus::DoubleTap, - }) - .set_parent(weapon.get()); + }); } WeaponBonusType::Achilles => { commands - .spawn(PartDamageBonus::WeaponBonus { + .entity(weapon.parent()) + .with_child(PartDamageBonus::WeaponBonus { value: value.0 / 100.0, bonus: BonusPartDamageBonus::Achilles, - }) - .set_parent(weapon.get()); + }); } WeaponBonusType::Cupid => { commands - .spawn(PartDamageBonus::WeaponBonus { + .entity(weapon.parent()) + .with_child(PartDamageBonus::WeaponBonus { value: value.0 / 100.0, bonus: BonusPartDamageBonus::Cupid, - }) - .set_parent(weapon.get()); + }); } WeaponBonusType::Crusher => { commands - .spawn(PartDamageBonus::WeaponBonus { + .entity(weapon.parent()) + .with_child(PartDamageBonus::WeaponBonus { value: value.0 / 100.0, bonus: BonusPartDamageBonus::Crusher, - }) - .set_parent(weapon.get()); + }); } WeaponBonusType::Deadeye => { commands - .spawn(PartDamageBonus::WeaponBonus { + .entity(weapon.parent()) + .with_child(PartDamageBonus::WeaponBonus { value: value.0 / 100.0, bonus: BonusPartDamageBonus::Deadeye, - }) - .set_parent(weapon.get()); + }); } WeaponBonusType::Throttle => { commands - .spawn(PartDamageBonus::WeaponBonus { + .entity(weapon.parent()) + .with_child(PartDamageBonus::WeaponBonus { value: value.0 / 100.0, bonus: BonusPartDamageBonus::Throttle, - }) - .set_parent(weapon.get()); + }); } WeaponBonusType::Roshambo => { commands - .spawn(PartDamageBonus::WeaponBonus { + .entity(weapon.parent()) + .with_child(PartDamageBonus::WeaponBonus { value: value.0 / 100.0, bonus: BonusPartDamageBonus::Roshambo, - }) - .set_parent(weapon.get()); + }); } WeaponBonusType::Cripple => { commands - .spawn(DamageProcEffect::OpponentEffect { + .entity(weapon.parent()) + .with_child(DamageProcEffect::OpponentEffect { value: value.0, bonus: OpponentStatusEffect::Cripple, - }) - .set_parent(weapon.get()); + }); } WeaponBonusType::Demoralise => { commands - .spawn(DamageProcEffect::OpponentEffect { + .entity(weapon.parent()) + .with_child(DamageProcEffect::OpponentEffect { value: value.0, bonus: OpponentStatusEffect::Demoralise, - }) - .set_parent(weapon.get()); + }); } WeaponBonusType::Freeze => { commands - .spawn(DamageProcEffect::OpponentEffect { + .entity(weapon.parent()) + .with_child(DamageProcEffect::OpponentEffect { value: value.0, bonus: OpponentStatusEffect::Freeze, - }) - .set_parent(weapon.get()); + }); } WeaponBonusType::Slow => { commands - .spawn(DamageProcEffect::OpponentEffect { + .entity(weapon.parent()) + .with_child(DamageProcEffect::OpponentEffect { value: value.0, bonus: OpponentStatusEffect::Slow, - }) - .set_parent(weapon.get()); + }); } WeaponBonusType::Toxin => { commands - .spawn(DamageProcEffect::OpponentEffect { + .entity(weapon.parent()) + .with_child(DamageProcEffect::OpponentEffect { value: value.0, bonus: OpponentStatusEffect::Toxin, - }) - .set_parent(weapon.get()); + }); } WeaponBonusType::Weaken => { commands - .spawn(DamageProcEffect::OpponentEffect { + .entity(weapon.parent()) + .with_child(DamageProcEffect::OpponentEffect { value: value.0, bonus: OpponentStatusEffect::Weaken, - }) - .set_parent(weapon.get()); + }); } WeaponBonusType::Wither => { commands - .spawn(DamageProcEffect::OpponentEffect { + .entity(weapon.parent()) + .with_child(DamageProcEffect::OpponentEffect { value: value.0, bonus: OpponentStatusEffect::Wither, - }) - .set_parent(weapon.get()); + }); } WeaponBonusType::Motivate => { commands - .spawn(DamageProcEffect::SelfEffect { + .entity(weapon.parent()) + .with_child(DamageProcEffect::SelfEffect { value: value.0, bonus: SelfStatusEffect::Motivate, - }) - .set_parent(weapon.get()); + }); } val => unimplemented!("{val:?}"), diff --git a/src/weapon/mod.rs b/src/weapon/mod.rs index 64599eb..cfc2869 100644 --- a/src/weapon/mod.rs +++ b/src/weapon/mod.rs @@ -1,25 +1,22 @@ use bevy_ecs::prelude::*; -use proxisim_models::{ - bundle::{ - passive::{Education, EducationPartDamageBonus, FactionUpgrades, Merits}, - player::{Current, PartDamageBonus, Weapons}, - stat::{ - AdditiveBonus, AmmoControl, ClipSize, Clips, CritRate, DamageBonus, Dexterity, - SimpleStatBonus, SimpleStatEffective, WeaponAccuracy, - }, - weapon::{ - Ammo, EquippedMods, Experience, Japanese, NeedsReload, Usable, Weapon, WeaponCategory, - WeaponMod, WeaponSlot, - }, +use proxisim_models::bundle::{ + passive::{Education, EducationPartDamageBonus, FactionUpgrades, Merits}, + player::{Current, PartDamageBonus, Weapons}, + stat::{ + AdditiveBonus, AmmoControl, ClipSize, Clips, CritRate, DamageBonus, Dexterity, + SimpleStatBonus, SimpleStatEffective, WeaponAccuracy, + }, + weapon::{ + Ammo, EquippedMods, Experience, Japanese, NeedsReload, Usable, Weapon, WeaponCategory, + WeaponMod, WeaponSlot, }, - hierarchy::{HierarchyBuilder, Parent}, }; use crate::{ + Stages, effect::{Effects, TurnLimitedEffect}, log, log::Logger, - Stages, }; use self::bonus::{ @@ -157,25 +154,6 @@ pub enum DamageProcEffect { }, } -fn set_owner(weapons_q: Query<(Entity, &Weapons)>, mut commands: Commands) { - for (player, weapons) in weapons_q.iter() { - if let Some(primary) = weapons.primary { - commands.entity(primary).set_parent(player); - } - if let Some(secondary) = weapons.secondary { - commands.entity(secondary).set_parent(player); - } - if let Some(melee) = weapons.melee { - commands.entity(melee).set_parent(player); - } - if let Some(temp) = weapons.temporary { - commands.entity(temp).set_parent(player); - } - commands.entity(weapons.fists).set_parent(player); - commands.entity(weapons.kick).set_parent(player); - } -} - fn apply_passives( weapon_q: Query<( Entity, @@ -184,7 +162,7 @@ fn apply_passives( &WeaponCategory, &WeaponSlot, Has, - &Parent, + &ChildOf, )>, player_q: Query<(&Merits, &Education, &FactionUpgrades)>, mut effects: Effects, @@ -331,8 +309,8 @@ fn apply_passives( weapon, ); commands - .spawn(TurnTriggeredEffect::Mod(TurnTriggeredMod::Bipod)) - .set_parent(weapon); + .entity(weapon) + .with_child(TurnTriggeredEffect::Mod(TurnTriggeredMod::Bipod)); } WeaponMod::Tripod => { effects.spawn( @@ -340,40 +318,38 @@ fn apply_passives( weapon, ); commands - .spawn(TurnTriggeredEffect::Mod(TurnTriggeredMod::Tripod)) - .set_parent(weapon); + .entity(weapon) + .with_child(TurnTriggeredEffect::Mod(TurnTriggeredMod::Tripod)); } WeaponMod::SmallLight => { commands - .spawn(TurnTriggeredEffect::Mod(TurnTriggeredMod::SmallLight)) - .set_parent(weapon); + .entity(weapon) + .with_child(TurnTriggeredEffect::Mod(TurnTriggeredMod::SmallLight)); } WeaponMod::PrecisionLight => { commands - .spawn(TurnTriggeredEffect::Mod(TurnTriggeredMod::PrecisionLight)) - .set_parent(weapon); + .entity(weapon) + .with_child(TurnTriggeredEffect::Mod(TurnTriggeredMod::PrecisionLight)); } WeaponMod::TacticalIlluminator => { - commands - .spawn(TurnTriggeredEffect::Mod( - TurnTriggeredMod::TacticalIlluminator, - )) - .set_parent(weapon); + commands.entity(weapon).with_child(TurnTriggeredEffect::Mod( + TurnTriggeredMod::TacticalIlluminator, + )); } WeaponMod::AdjustableTrigger => { commands - .spawn(FirstTurnEffect::Mod(FirstTurnMod::AdjustableTrigger)) - .set_parent(weapon); + .entity(weapon) + .with_child(FirstTurnEffect::Mod(FirstTurnMod::AdjustableTrigger)); } WeaponMod::HairTrigger => { commands - .spawn(FirstTurnEffect::Mod(FirstTurnMod::HairTrigger)) - .set_parent(weapon); + .entity(weapon) + .with_child(FirstTurnEffect::Mod(FirstTurnMod::HairTrigger)); } } } - let (merits, education, faction) = player_q.get(player.get()).unwrap(); + let (merits, education, faction) = player_q.get(player.parent()).unwrap(); let (mastery, edu_acc) = match cat { WeaponCategory::HeavyArtillery => ( @@ -445,10 +421,10 @@ fn apply_passives( if education.bio2380 { commands - .spawn(PartDamageBonus::Education( + .entity(weapon) + .with_child(PartDamageBonus::Education( EducationPartDamageBonus::Bio2380, - )) - .set_parent(weapon); + )); } if mastery > 0 { @@ -490,7 +466,7 @@ fn reload_weapon( mut weapon_q: Query< ( Entity, - &Parent, + &ChildOf, &mut Ammo, &mut SimpleStatEffective, &SimpleStatEffective, @@ -505,7 +481,7 @@ fn reload_weapon( clips.value -= 1; log!(logger, "reload_weapon", { - actor: player.get(), + actor: player.parent(), weapon }); @@ -530,18 +506,17 @@ fn restore_ammo( } fn apply_first_turn_effects( - effect_q: Query<(&Parent, &FirstTurnEffect)>, - player_q: Query<&Parent>, + effect_q: Query<(&ChildOf, &FirstTurnEffect)>, + player_q: Query<&ChildOf>, mut effects: Effects, ) { for (weapon, effect) in effect_q.iter() { - let player = player_q.get(weapon.get()).unwrap(); - effect.spawn(&mut effects, weapon.get(), player.get()); + let player = player_q.get(weapon.parent()).unwrap(); + effect.spawn(&mut effects, weapon.parent(), player.parent()); } } pub(crate) fn configure(stages: &mut Stages) { - stages.equip.add_systems(set_owner); // running this in the snapshot layer ensures that the stat increases aren't restored at the // end of the run stages.snapshot.add_systems(apply_first_turn_effects);