use bevy::{
ecs::component::{ComponentHooks, StorageType},
prelude::*,
};
use crate::{
ecs::{CommandsExt, TriggerGetEntity},
event::{OnPick, OnPicked},
picking::Picker,
scoring::Score,
};
#[derive(Reflect)]
#[derive(Clone, Copy, PartialEq, Debug, Default)]
#[reflect(Component)]
pub struct FirstToScore {
threshold: Score,
}
impl FirstToScore {
pub fn new(threshold: impl Into<Score>) -> Self {
Self {
threshold: threshold.into(),
}
}
pub fn threshold(&self) -> Score {
self.threshold
}
pub fn set_threshold(&mut self, threshold: impl Into<Score>) {
self.threshold = threshold.into();
}
fn observer(
trigger: Trigger<OnPick>,
mut commands: Commands,
mut targets: Query<(Entity, &Children, &mut Picker, &FirstToScore)>,
scores: Query<(Entity, &Score)>,
) {
fn run(
target: Entity,
mut commands: Commands,
children: &Children,
mut picker: Mut<Picker>,
settings: &FirstToScore,
scores: &Query<(Entity, &Score)>,
) {
for (score_entity, score) in scores.iter_many(children) {
if *score >= settings.threshold() {
picker.pick(Some(score_entity));
return;
}
}
let action = picker.pick(None);
commands.trigger_targets(OnPicked { action }, target);
}
if let Some(target) = trigger.get_entity() {
let Ok((target, children, picker, settings)) = targets.get_mut(target) else {
return;
};
run(target, commands.reborrow(), children, picker, settings, &scores);
} else {
for (target, children, picker, settings) in targets.iter_mut() {
run(target, commands.reborrow(), children, picker, settings, &scores);
}
}
}
}
impl Component for FirstToScore {
const STORAGE_TYPE: StorageType = StorageType::Table;
fn register_component_hooks(hooks: &mut ComponentHooks) {
hooks.on_add(|mut world, _entity, _component| {
#[derive(Resource, Default)]
struct FirstToScoreObserverSpawned;
world
.commands()
.once::<FirstToScoreObserverSpawned>()
.observe(Self::observer);
});
}
}