1use std::borrow::Cow;
27
28use game_toolkit::prelude::*;
29
30use crate::sim::{Intent, Preset};
31
32const DEADZONE: f32 = 0.25;
34
35#[derive(Clone, Debug)]
37pub struct Scheme {
38 pub jump: &'static [Key],
40 pub jump_pad: &'static [Button],
42 pub dash: &'static [Key],
44 pub dash_pad: &'static [Button],
46 pub grab: &'static [Key],
48 pub grab_pad: &'static [Button],
50 pub cast: &'static [Key],
52 pub cast_pad: &'static [Button],
54 pub sprint: &'static [Key],
56 pub sprint_pad: &'static [Button],
58 pub super_dash: &'static [Key],
60 pub super_dash_pad: &'static [Button],
62 pub custom: Cow<'static, [Custom]>,
67}
68
69#[derive(Clone, Debug, PartialEq)]
93pub struct Custom {
94 pub bit: u8,
96 pub keys: Cow<'static, [Key]>,
98 pub pad: Cow<'static, [Button]>,
100}
101
102impl Custom {
103 pub const fn new(bit: u8, keys: &'static [Key], pad: &'static [Button]) -> Self {
105 Self {
106 bit,
107 keys: Cow::Borrowed(keys),
108 pad: Cow::Borrowed(pad),
109 }
110 }
111}
112
113impl Scheme {
117 pub const SNAPPY: Scheme = Scheme {
120 jump: &[Key::KeyZ, Key::Space],
121 jump_pad: &[Button::South],
122 dash: &[Key::KeyC],
123 dash_pad: &[Button::RightTrigger2],
124 grab: &[Key::KeyD],
125 grab_pad: &[Button::LeftTrigger],
126 cast: &[Key::KeyA],
127 cast_pad: &[Button::East, Button::RightTrigger],
128 sprint: &[Key::ShiftLeft, Key::ShiftRight],
129 sprint_pad: &[Button::West],
130 super_dash: &[Key::KeyS],
131 super_dash_pad: &[Button::LeftTrigger2],
132 custom: Cow::Borrowed(&[]),
133 };
134
135 pub const PRECISE: Scheme = Scheme {
137 jump: &[Key::KeyC, Key::Space],
138 jump_pad: &[Button::South, Button::North],
139 dash: &[Key::KeyX],
140 dash_pad: &[Button::West, Button::East],
141 grab: &[Key::KeyZ],
142 grab_pad: &[
143 Button::RightTrigger2,
144 Button::LeftTrigger2,
145 Button::RightTrigger,
146 Button::LeftTrigger,
147 ],
148 cast: &[],
149 cast_pad: &[],
150 sprint: &[],
151 sprint_pad: &[],
152 super_dash: &[],
153 super_dash_pad: &[],
154 custom: Cow::Borrowed(&[]),
155 };
156
157 pub const MOMENTUM: Scheme = Scheme {
159 jump: &[Key::Space, Key::KeyZ],
160 jump_pad: &[Button::South],
161 dash: &[],
162 dash_pad: &[],
163 grab: &[],
164 grab_pad: &[],
165 cast: &[],
166 cast_pad: &[],
167 sprint: &[Key::ShiftLeft, Key::ShiftRight, Key::KeyX],
168 sprint_pad: &[Button::West, Button::RightTrigger2],
169 super_dash: &[],
170 super_dash_pad: &[],
171 custom: Cow::Borrowed(&[]),
172 };
173
174 pub fn bind(
177 &mut self,
178 bit: u8,
179 keys: impl Into<Cow<'static, [Key]>>,
180 pad: impl Into<Cow<'static, [Button]>>,
181 ) {
182 let button = Custom {
183 bit,
184 keys: keys.into(),
185 pad: pad.into(),
186 };
187 let custom = self.custom.to_mut();
188 match custom.iter_mut().find(|c| c.bit == bit) {
189 Some(c) => *c = button,
190 None => custom.push(button),
191 }
192 }
193
194 pub fn of(preset: Option<Preset>) -> Self {
196 match preset {
197 Some(Preset::Precise) => Self::PRECISE,
198 Some(Preset::Momentum) => Self::MOMENTUM,
199 Some(Preset::Hybrid | Preset::Snappy | Preset::Drifter) | None => Self::SNAPPY,
200 }
201 }
202}
203
204#[derive(Clone, Copy, Debug, Default)]
207pub struct Triggers {
208 left: bool,
210 right: bool,
212}
213
214const TRIGGER: f32 = 0.5;
216
217pub fn read_intent(input: &Input, scheme: &Scheme, triggers: &mut Triggers) -> Intent {
219 let pressed = |ks: &[Key]| ks.iter().any(|&k| input.key_pressed(k));
220 let held = |ks: &[Key]| ks.iter().any(|&k| input.key_held(k));
221 let axis =
222 |neg: Key, pos: Key| (input.key_held(pos) as i32 - input.key_held(neg) as i32) as f32;
223 let mut i = Intent {
224 move_x: axis(Key::ArrowLeft, Key::ArrowRight),
225 move_y: axis(Key::ArrowUp, Key::ArrowDown),
226 jump_pressed: pressed(scheme.jump),
227 jump_held: held(scheme.jump),
228 dash_pressed: pressed(scheme.dash),
229 grab: held(scheme.grab),
230 dive_pressed: false,
231 sprint: held(scheme.sprint),
232 super_dash: held(scheme.super_dash),
233 custom: 0,
234 custom_pressed: 0,
235 };
236 for c in scheme.custom.iter() {
237 let bit = 1 << c.bit;
238 if held(&c.keys) {
239 i.custom |= bit;
240 }
241 if pressed(&c.keys) {
242 i.custom_pressed |= bit;
243 }
244 }
245 let mut cast = pressed(scheme.cast);
246 if let Some(g) = input.first_gamepad() {
247 let lt = g.button_held(Button::LeftTrigger2) || g.axis(Axis::LeftZ) > TRIGGER;
249 let rt = g.button_held(Button::RightTrigger2) || g.axis(Axis::RightZ) > TRIGGER;
250 let (lt_pressed, rt_pressed) = (lt && !triggers.left, rt && !triggers.right);
251 *triggers = Triggers {
252 left: lt,
253 right: rt,
254 };
255 let held_b = |b: Button| match b {
256 Button::LeftTrigger2 => lt,
257 Button::RightTrigger2 => rt,
258 _ => g.button_held(b),
259 };
260 let pressed_b = |b: Button| match b {
261 Button::LeftTrigger2 => lt_pressed,
262 Button::RightTrigger2 => rt_pressed,
263 _ => g.button_pressed(b),
264 };
265 let pressed = |bs: &[Button]| bs.iter().any(|&b| pressed_b(b));
266 let held = |bs: &[Button]| bs.iter().any(|&b| held_b(b));
267 let dz = |v: f32| if v.abs() < DEADZONE { 0.0 } else { v };
268 let dpad = |neg, pos| (g.button_held(pos) as i32 - g.button_held(neg) as i32) as f32;
269 let sx = dz(g.axis(Axis::LeftStickX)) + dpad(Button::DPadLeft, Button::DPadRight);
270 let sy = -dz(g.axis(Axis::LeftStickY)) + dpad(Button::DPadUp, Button::DPadDown);
272 if sx != 0.0 {
273 i.move_x = sx.clamp(-1.0, 1.0);
274 }
275 if sy != 0.0 {
276 i.move_y = sy.clamp(-1.0, 1.0);
277 }
278 i.jump_pressed |= pressed(scheme.jump_pad);
279 i.jump_held |= held(scheme.jump_pad);
280 i.dash_pressed |= pressed(scheme.dash_pad);
281 i.grab |= held(scheme.grab_pad);
282 i.sprint |= held(scheme.sprint_pad);
283 i.super_dash |= held(scheme.super_dash_pad);
284 cast |= pressed(scheme.cast_pad);
285 for c in scheme.custom.iter() {
286 let bit = 1 << c.bit;
287 if held(&c.pad) {
288 i.custom |= bit;
289 }
290 if pressed(&c.pad) {
291 i.custom_pressed |= bit;
292 }
293 }
294 }
295 i.dive_pressed = cast && i.down();
296 i
297}
298
299#[derive(Clone, Debug)]
302pub struct Controls {
303 pub scheme: Scheme,
305 triggers: Triggers,
307}
308
309impl Controls {
310 pub fn new(scheme: Scheme) -> Self {
312 Self {
313 scheme,
314 triggers: Triggers::default(),
315 }
316 }
317
318 pub fn for_preset(preset: Preset) -> Self {
320 Self::new(Scheme::of(Some(preset)))
321 }
322
323 pub fn read(&mut self, input: &Input) -> Intent {
325 read_intent(input, &self.scheme, &mut self.triggers)
326 }
327}
328
329impl Default for Controls {
330 fn default() -> Self {
331 Self::new(Scheme::SNAPPY)
332 }
333}