1use crate::anim::{Driver, ParamId, ParamKind, Params, SpecError};
4use crate::sim::{Event, JumpKind, Mode, World};
5
6#[derive(Clone, Debug)]
8pub struct HeroDriver {
9 grounded: ParamId,
11 skid: ParamId,
13 rolling: ParamId,
15 dashing: ParamId,
17 climbing: ParamId,
19 slipping: ParamId,
21 wall_slide: ParamId,
23 hard_landing: ParamId,
25 wings: ParamId,
27 wall_push: ParamId,
29 gliding: ParamId,
31 super_bonk: ParamId,
33 super_launch: ParamId,
35 super_flying: ParamId,
37 charged: ParamId,
39 charging: ParamId,
41 speed: ParamId,
43 vy: ParamId,
45 dash_y: ParamId,
47 look: ParamId,
49 jump: ParamId,
51 double: ParamId,
53 wall_jump: ParamId,
55 hop: ParamId,
57 drop: ParamId,
59 land: ParamId,
61 roll: ParamId,
63 hard: ParamId,
65 dash: ParamId,
67 grab: ParamId,
69 dive: ParamId,
71 impact: ParamId,
73}
74
75const SKID_SPEED: f32 = 30.0;
77
78impl HeroDriver {
79 pub fn new(params: &Params) -> Self {
83 Self::try_new(params).unwrap_or_else(|e| panic!("{e}"))
84 }
85
86 pub fn try_new(params: &Params) -> Result<Self, SpecError> {
90 Self::lookup(&mut params.clone(), false)
91 }
92
93 pub fn declaring(params: &mut Params) -> Self {
97 Self::lookup(params, true).expect("missing parameters are declared")
98 }
99
100 fn lookup(params: &mut Params, declare: bool) -> Result<Self, SpecError> {
102 const B: ParamKind = ParamKind::Bool;
103 const F: ParamKind = ParamKind::Float;
104 const T: ParamKind = ParamKind::Trigger { ttl: 0.0 };
105 let mut id = |n: &'static str, kind: ParamKind| match params.id(n) {
106 Some(id) => Ok(id),
107 None if declare => Ok(params.declare(n, kind)),
108 None => Err(SpecError::UnknownParam(n.into())),
109 };
110 Ok(Self {
111 grounded: id("grounded", B)?,
112 skid: id("skid", B)?,
113 rolling: id("rolling", B)?,
114 dashing: id("dashing", B)?,
115 climbing: id("climbing", B)?,
116 slipping: id("slipping", B)?,
117 wall_slide: id("wall_slide", B)?,
118 hard_landing: id("hard_landing", B)?,
119 wings: id("wings", B)?,
120 wall_push: id("wall_push", B)?,
121 gliding: id("gliding", B)?,
122 super_bonk: id("super_bonk", T)?,
123 super_launch: id("super_launch", T)?,
124 super_flying: id("super_flying", B)?,
125 charged: id("charged", B)?,
126 charging: id("charging", B)?,
127 speed: id("speed", F)?,
128 vy: id("vy", F)?,
129 dash_y: id("dash_y", F)?,
130 look: id("look", F)?,
131 jump: id("jump", T)?,
132 double: id("double", T)?,
133 wall_jump: id("wall_jump", T)?,
134 hop: id("hop", T)?,
135 drop: id("drop", T)?,
136 land: id("land", T)?,
137 roll: id("roll", T)?,
138 hard: id("hard", T)?,
139 dash: id("dash", T)?,
140 grab: id("grab", T)?,
141 dive: id("dive", T)?,
142 impact: id("impact", T)?,
143 })
144 }
145}
146
147impl Driver<World> for HeroDriver {
148 fn drive(&mut self, w: &World, p: &mut Params) {
149 let pl = &w.player;
150 p.set_bool(self.grounded, pl.grounded);
151 p.set_bool(
152 self.skid,
153 pl.grounded
154 && pl.mode == Mode::Normal
155 && pl.vx.abs() > SKID_SPEED
156 && pl.vx.signum() as i32 != pl.facing,
157 );
158 p.set_bool(self.rolling, matches!(pl.mode, Mode::Roll { .. }));
159 p.set_bool(self.dashing, matches!(pl.mode, Mode::Dash { .. }));
160 p.set_bool(self.climbing, pl.mode == Mode::Climb);
161 p.set_bool(self.slipping, pl.slipping);
162 p.set_bool(self.wall_slide, pl.wall_slide != 0);
163 p.set_bool(self.hard_landing, matches!(pl.mode, Mode::HardLand { .. }));
164 p.set_bool(self.slipping, pl.slipping);
165 p.set_bool(self.wings, w.tuning.wings);
166 p.set_bool(
168 self.wall_push,
169 pl.grounded && pl.mode == Mode::Normal && pl.contacts.wall != 0,
170 );
171 p.set_bool(self.gliding, pl.gliding);
172 let charge = match pl.mode {
173 Mode::SuperCharge { t, .. } => Some(t),
174 _ => None,
175 };
176 p.set_bool(self.charging, charge.is_some());
177 p.set_bool(
178 self.charged,
179 charge.is_some_and(|t| t >= w.tuning.super_charge),
180 );
181 p.set_bool(self.super_flying, matches!(pl.mode, Mode::SuperDash { .. }));
182 p.set_float(self.look, pl.look as f32 * pl.look_time);
184 p.set_float(self.speed, pl.vx.abs());
185 p.set_float(self.vy, pl.vy);
186 if let Mode::Dash { dy, .. } = pl.mode {
187 p.set_float(self.dash_y, dy);
188 }
189 for e in &w.events {
190 let t = match e {
191 Event::Jumped {
192 kind: JumpKind::Double,
193 ..
194 } => self.double,
195 Event::Jumped {
196 kind: JumpKind::Wall,
197 ..
198 } => self.wall_jump,
199 Event::Jumped { .. } => self.jump,
200 Event::Landed { .. } => self.land,
201 Event::RollStarted => self.roll,
202 Event::HardLanded => self.hard,
203 Event::Dashed { .. } => self.dash,
204 Event::Grabbed => self.grab,
205 Event::ClimbHop => self.hop,
206 Event::DroppedThrough => self.drop,
207 Event::DiveStarted => self.dive,
208 Event::DiveImpact { .. } => self.impact,
209 Event::SuperDashStarted { .. } => self.super_launch,
210 Event::SuperDashEnded { bonk: true } => self.super_bonk,
211 _ => continue,
212 };
213 p.fire(t);
214 }
215 }
216}