use bevy hierarchy system

This commit is contained in:
TotallyNot 2025-11-03 18:54:07 +01:00
parent 35413b563c
commit cfe2631578
Signed by: pyrite
GPG key ID: 7F1BA9170CD35D15
15 changed files with 246 additions and 643 deletions

View file

@ -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<NeedsReload>, Option<&Children>), With<Usable>>,
) -> Option<(Entity, Option<Children>)> {
usable_q: &'a Query<(Has<NeedsReload>, Option<&Children>), With<Usable>>,
) -> 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() {

View file

@ -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<Stat: StatMarker>(
In(entities): In<Vec<Entity>>,
effect_q: Query<(&AdditiveBonus<Stat>, &Parent)>,
effect_q: Query<(&AdditiveBonus<Stat>, &ChildOf)>,
mut stat_q: Query<(
&BaselineStat<Stat>,
&mut AdditiveBonuses<Stat>,
@ -24,7 +21,7 @@ fn add_additive_bonus<Stat: StatMarker>(
)>,
) {
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<Stat: StatMarker>(
fn revert_additive_bonus<Stat: StatMarker>(
In(entities): In<Vec<Entity>>,
effect_q: Query<(&AdditiveBonus<Stat>, &Parent)>,
effect_q: Query<(&AdditiveBonus<Stat>, &ChildOf)>,
mut stat_q: Query<(
&BaselineStat<Stat>,
&mut AdditiveBonuses<Stat>,
@ -41,7 +38,7 @@ fn revert_additive_bonus<Stat: StatMarker>(
)>,
) {
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<Stat: StatMarker>(
fn add_multiplicative_bonus<Stat: StatMarker>(
In(entities): In<Vec<Entity>>,
effect_q: Query<(&MultiplicativeBonus<Stat>, &Parent)>,
effect_q: Query<(&MultiplicativeBonus<Stat>, &ChildOf)>,
mut stat_q: Query<(
&BaselineStat<Stat>,
&AdditiveBonuses<Stat>,
@ -58,7 +55,7 @@ fn add_multiplicative_bonus<Stat: StatMarker>(
)>,
) {
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<Stat: StatMarker>(
fn revert_multiplicative_bonus<Stat: StatMarker>(
In(entities): In<Vec<Entity>>,
effect_q: Query<(&MultiplicativeBonus<Stat>, &Parent)>,
effect_q: Query<(&MultiplicativeBonus<Stat>, &ChildOf)>,
mut stat_q: Query<(
&BaselineStat<Stat>,
&AdditiveBonuses<Stat>,
@ -75,7 +72,7 @@ fn revert_multiplicative_bonus<Stat: StatMarker>(
)>,
) {
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<Stat: StatMarker>(
fn apply_simple_stat_bonus<Stat: SimpleStatMarker>(
In(entities): In<Vec<Entity>>,
effect_q: Query<(&SimpleStatBonus<Stat>, &Parent)>,
effect_q: Query<(&SimpleStatBonus<Stat>, &ChildOf)>,
mut stat_q: Query<&mut SimpleStatEffective<Stat>>,
) {
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<Stat: SimpleStatMarker>(
In(entities): In<Vec<Entity>>,
effect_q: Query<(&SimpleStatBonus<Stat>, &Parent)>,
effect_q: Query<(&SimpleStatBonus<Stat>, &ChildOf)>,
mut stat_q: Query<&mut SimpleStatEffective<Stat>>,
) {
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);
}
}

View file

@ -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<const N: usize, M: AdditiveStatusEffectMarker<N>>(
In(entities): In<Vec<Entity>>,
effect_q: Query<(Entity, &Parent, &AdditiveStatusEffect<N, M>)>,
effect_q: Query<(Entity, &ChildOf, &AdditiveStatusEffect<N, M>)>,
mut parent_q: Query<Option<&mut StatusEffectStack<M>>>,
mut commands: Commands,
mut effects: Effects,
@ -353,15 +350,15 @@ fn apply_additive_status_effect<const N: usize, M: AdditiveStatusEffectMarker<N>
) {
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::<M>(),
});
let stack = parent_q.get_mut(player.get()).unwrap();
let stack = parent_q.get_mut(player.parent()).unwrap();
let new_effects = <M::AffectedStats as Stats<N>>::spawn_additive_effects(
&mut effects,
player.get(),
player.parent(),
M::factor() * (1.0 + effect.extra_effectiveness),
std::any::type_name::<M>(),
);
@ -389,13 +386,13 @@ fn apply_additive_status_effect<const N: usize, M: AdditiveStatusEffectMarker<N>
fn remove_additive_status_effect<const N: usize, M: AdditiveStatusEffectMarker<N>>(
In(entities): In<Vec<Entity>>,
effect_q: Query<(Entity, &Parent)>,
effect_q: Query<(Entity, &ChildOf)>,
mut parent_q: Query<Option<&mut StatusEffectStack<M>>>,
linked_q: Query<&LinkedComponents<N>>,
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<const N: usize, M: AdditiveStatusEffectMarker<N
fn apply_temp_debuff_effect<Temp: DebuffingTempMarker>(
In(entities): In<Vec<Entity>>,
mut rng: ResMut<Rng>,
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<Temp>>,
Has<TempDebuffImmunity<Temp>>,
@ -422,14 +419,14 @@ fn apply_temp_debuff_effect<Temp: DebuffingTempMarker>(
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<Temp: DebuffingTempMarker>(
let bonus = effects.spawn(
MultiplicativeBonus::<Temp::Stat>::new(std::any::type_name::<Temp>(), effective_factor),
player.get(),
player.parent(),
);
if let Some(mut stack) = stack {
@ -456,7 +453,7 @@ fn apply_temp_debuff_effect<Temp: DebuffingTempMarker>(
stack.effects.push_back(effect);
} else {
commands
.entity(player.get())
.entity(player.parent())
.insert(StatusEffectStack::<Temp> {
effects: VecDeque::from([effect]),
bonus,
@ -465,8 +462,8 @@ fn apply_temp_debuff_effect<Temp: DebuffingTempMarker>(
}
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<Temp: DebuffingTempMarker>(
fn remove_temp_debuff_effect<Temp: DebuffingTempMarker>(
In(entities): In<Vec<Entity>>,
temp_q: Query<&Parent>,
temp_q: Query<&ChildOf>,
mut parent_q: Query<(&mut StatusEffectStack<Temp>, Has<TempDebuffImmunity<Temp>>)>,
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<Temp: DebuffingTempMarker>(
std::any::type_name::<Temp>(),
effective_factor,
),
player.get(),
player.parent(),
);
stack.effects.pop_front();
} else {
commands
.entity(player.get())
.entity(player.parent())
.remove::<StatusEffectStack<Temp>>();
}
}