Skip to content
Snippets Groups Projects
scorers.rs 4.78 KiB
Newer Older
use std::sync::Arc;

use bevy::prelude::*;
Kat Marchán's avatar
Kat Marchán committed
use crate::thinker::{Actor, ScorerEnt};
#[derive(Debug, Clone, Default)]
pub struct Score(pub(crate) f32);

impl Score {
Kat Marchán's avatar
Kat Marchán committed
    pub fn get(&self) -> f32 {
        self.0
    }
    pub fn set(&mut self, value: f32) {
        if !(0.0..=100.0).contains(&value) {
            panic!("Score value must be between 0.0 and 100.0");
        }
        self.0 = value;
    }
}
pub trait ScorerBuilder: std::fmt::Debug + Sync + Send {
    fn build(&self, cmd: &mut Commands, scorer: Entity, actor: Entity);
    fn attach(&self, cmd: &mut Commands, actor: Entity) -> Entity {
        let scorer_ent = cmd.spawn().id();
        cmd.entity(scorer_ent)
            .insert(Score::default())
            .insert(Actor(actor));
        self.build(cmd, scorer_ent, actor);
        scorer_ent
    }
Kat Marchán's avatar
Kat Marchán committed
}
#[derive(Debug, Clone)]
Kat Marchán's avatar
Kat Marchán committed
pub struct FixedScore(f32);

impl FixedScore {
    pub fn build(score: f32) -> FixedScoreBuilder {
        FixedScoreBuilder(score)
    }
}

Kat Marchán's avatar
Kat Marchán committed
pub fn fixed_score_system(mut query: Query<(&FixedScore, &mut Score)>) {
    for (FixedScore(fixed), mut score) in query.iter_mut() {
        score.set(*fixed);
    }
}

#[derive(Debug, Clone)]
pub struct FixedScoreBuilder(f32);
impl ScorerBuilder for FixedScoreBuilder {
    fn build(&self, cmd: &mut Commands, action: Entity, _actor: Entity) {
        cmd.entity(action).insert(FixedScore(self.0));
Kat Marchán's avatar
Kat Marchán committed
    }
}

#[derive(Debug)]
pub struct AllOrNothing {
    threshold: f32,
    scorers: Vec<ScorerEnt>,
}

impl AllOrNothing {
    pub fn build(threshold: f32) -> AllOrNothingBuilder {
        AllOrNothingBuilder {
            threshold,
            scorers: Vec::new(),
        }
    }
}

Kat Marchán's avatar
Kat Marchán committed
pub fn all_or_nothing_system(query: Query<(Entity, &AllOrNothing)>, mut scores: Query<&mut Score>) {
    for (
        aon_ent,
        AllOrNothing {
            threshold,
            scorers: children,
        },
    ) in query.iter()
    {
        let mut sum = 0.0;
        for ScorerEnt(child) in children.iter() {
            let score = scores.get_mut(*child).expect("where is it?");
            if score.0 < *threshold {
                sum = 0.0;
                break;
            } else {
                sum += score.0;
            }
        }
        let mut score = scores.get_mut(aon_ent).expect("where did it go?");
        score.set(crate::evaluators::clamp(sum, 0.0, 100.0));
    }
}
#[derive(Debug, Clone)]
pub struct AllOrNothingBuilder {
    threshold: f32,
    scorers: Vec<Arc<dyn ScorerBuilder>>,
}
impl AllOrNothingBuilder {
    pub fn when(&mut self, scorer: impl ScorerBuilder + 'static) -> &mut Self {
        self.scorers.push(Arc::new(scorer));
        self
impl ScorerBuilder for AllOrNothingBuilder {
    fn build(&self, cmd: &mut Commands, scorer: Entity, actor: Entity) {
        let scorers: Vec<_> = self
            .scorers
            .iter()
            .map(|scorer| scorer.attach(cmd, actor))
            .collect();
        cmd.entity(scorer)
            .insert(Score::default())
            .push_children(&scorers[..])
Kat Marchán's avatar
Kat Marchán committed
            .insert(AllOrNothing {
                threshold: self.threshold,
                scorers: scorers.into_iter().map(ScorerEnt).collect(),
            });
Kat Marchán's avatar
Kat Marchán committed
    }
}

#[derive(Debug)]
pub struct SumOfScorers {
    threshold: f32,
    scorers: Vec<ScorerEnt>,
}

impl SumOfScorers {
    pub fn build(threshold: f32) -> SumOfScorersBuilder {
        SumOfScorersBuilder {
            threshold,
            scorers: Vec::new(),
        }
    }
}

Kat Marchán's avatar
Kat Marchán committed
pub fn sum_of_scorers_system(query: Query<(Entity, &SumOfScorers)>, mut scores: Query<&mut Score>) {
    for (
        sos_ent,
        SumOfScorers {
            threshold,
            scorers: children,
        },
    ) in query.iter()
    {
        let mut sum = 0.0;
        for ScorerEnt(child) in children.iter() {
            let score = scores.get_mut(*child).expect("where is it?");
            sum += score.0;
        }
        if sum < *threshold {
            sum = 0.0;
        }
        let mut score = scores.get_mut(sos_ent).expect("where did it go?");
        score.set(crate::evaluators::clamp(sum, 0.0, 100.0));
    }
}

#[derive(Debug, Clone)]
pub struct SumOfScorersBuilder {
    threshold: f32,
    scorers: Vec<Arc<dyn ScorerBuilder>>,
}
impl SumOfScorersBuilder {
    pub fn when(&mut self, scorer: impl ScorerBuilder + 'static) -> &mut Self {
        self.scorers.push(Arc::new(scorer));
        self
impl ScorerBuilder for SumOfScorersBuilder {
    fn build(&self, cmd: &mut Commands, scorer: Entity, actor: Entity) {
        let scorers: Vec<_> = self
            .scorers
            .iter()
            .map(|scorer| scorer.attach(cmd, actor))
            .collect();
        cmd.entity(scorer).insert(AllOrNothing {
            threshold: self.threshold,
            scorers: scorers.into_iter().map(ScorerEnt).collect(),
        });