game_toolkit_platformer/anim/
cond.rs1use super::{ParamId, Params};
4
5#[derive(Clone, Debug, PartialEq)]
8pub enum Cond<P = ParamId> {
9 Always,
11 Is(P),
13 Trigger(P),
15 Above(P, f32),
17 Below(P, f32),
19 Finished,
21 After(f32),
23 Not(Box<Cond<P>>),
25 All(Vec<Cond<P>>),
27 Any(Vec<Cond<P>>),
29}
30
31impl<P> Cond<P> {
32 #[allow(clippy::should_implement_trait)]
34 pub fn not(c: Cond<P>) -> Self {
35 Cond::Not(Box::new(c))
36 }
37
38 pub fn and(self, o: Cond<P>) -> Self {
40 match self {
41 Cond::All(mut v) => {
42 v.push(o);
43 Cond::All(v)
44 }
45 c => Cond::All(vec![c, o]),
46 }
47 }
48
49 pub fn resolve<Q, E>(&self, f: &mut dyn FnMut(&P, Use) -> Result<Q, E>) -> Result<Cond<Q>, E> {
51 Ok(match self {
52 Cond::Always => Cond::Always,
53 Cond::Is(p) => Cond::Is(f(p, Use::Bool)?),
54 Cond::Trigger(p) => Cond::Trigger(f(p, Use::Trigger)?),
55 Cond::Above(p, v) => Cond::Above(f(p, Use::Float)?, *v),
56 Cond::Below(p, v) => Cond::Below(f(p, Use::Float)?, *v),
57 Cond::Finished => Cond::Finished,
58 Cond::After(s) => Cond::After(*s),
59 Cond::Not(c) => Cond::Not(Box::new(c.resolve(f)?)),
60 Cond::All(v) => Cond::All(v.iter().map(|c| c.resolve(f)).collect::<Result<_, E>>()?),
61 Cond::Any(v) => Cond::Any(v.iter().map(|c| c.resolve(f)).collect::<Result<_, E>>()?),
62 })
63 }
64}
65
66#[derive(Clone, Copy, Debug, PartialEq, Eq)]
68pub enum Use {
69 Bool,
71 Float,
73 Trigger,
75}
76
77impl Cond {
78 pub fn eval(&self, p: &Params, finished: bool, time: f32) -> bool {
81 match self {
82 Cond::Always => true,
83 Cond::Is(id) => p.get_bool(*id),
84 Cond::Trigger(id) => p.pending(*id),
85 Cond::Above(id, v) => p.get_float(*id) > *v,
86 Cond::Below(id, v) => p.get_float(*id) < *v,
87 Cond::Finished => finished,
88 Cond::After(s) => time >= *s,
89 Cond::Not(c) => !c.eval(p, finished, time),
90 Cond::All(v) => v.iter().all(|c| c.eval(p, finished, time)),
91 Cond::Any(v) => v.iter().any(|c| c.eval(p, finished, time)),
92 }
93 }
94
95 pub fn used_triggers(&self, p: &Params, out: &mut Vec<ParamId>) {
98 match self {
99 Cond::Trigger(id) if p.pending(*id) => out.push(*id),
100 Cond::All(v) | Cond::Any(v) => v.iter().for_each(|c| c.used_triggers(p, out)),
101 _ => {}
102 }
103 }
104}