1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//! [`Event`]: what happened in a step, for animation, sound and effects.
use super::CustomId;
/// How a jump left the ground (or the wall, or the air).
/// New kinds may come with new moves, so matches need a `_` arm.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum JumpKind {
/// From standing or running on the ground.
Ground,
/// Just after walking off a ledge, within coyote time.
Coyote,
/// Out of a landing roll, keeping the roll's speed.
Roll,
/// Off a wall, away from it.
Wall,
/// Straight up a wall while holding on, at a stamina cost.
Climb,
/// In the air, spending an air jump.
Double,
}
/// Something that happened in one step. New moves bring new events, so matches need a
/// `_` arm.
#[derive(Clone, Copy, Debug, PartialEq)]
#[non_exhaustive]
pub enum Event {
/// The hero jumped. `buffered`: the press came before the jump was possible and waited
/// in the jump buffer.
Jumped {
/// Which kind of jump.
kind: JumpKind,
/// Whether the press was queued.
buffered: bool,
},
/// The hero let go of jump while rising and the jump was cut short.
JumpCut,
/// Vertical speed crossed zero going up to down in the air.
Apex,
/// The hero walked or rolled off the ground (not by jumping).
LeftGround,
/// Down + jump on a one-way platform: dropping through it.
DroppedThrough,
/// The hero touched down.
Landed {
/// Downward speed at contact, units/s (pixels/s from a scaled
/// [`crate::Platformer`]).
impact: f32,
/// Units fallen from the highest point of the airtime (pixels from a scaled
/// [`crate::Platformer`]).
drop: i32,
},
/// A landing turned into a roll.
RollStarted,
/// The roll ran out (not by jumping).
RollEnded,
/// A landing from high up without moving: a heavy landing that costs control.
HardLanded,
/// A heavy landing or a dive impact is over.
Recovered,
/// A dash started, in direction `dx, dy` (8-way, normalized, y down).
Dashed {
/// Horizontal direction.
dx: f32,
/// Vertical direction.
dy: f32,
},
/// The dash ran out and handed over its leftover speed.
DashEnded,
/// Dashes were refilled, on the ground or by a crystal.
Recharged {
/// By a crystal (in the air), not by the ground.
crystal: bool,
},
/// Grabbed a wall.
Grabbed,
/// Let go of a wall (released grab, wall ended, or out of stamina).
LetGo,
/// Climbed over the top of a wall with a small hop.
ClimbHop,
/// Stamina ran out on a wall.
StaminaOut,
/// A dive started: a short hang, then straight down.
DiveStarted,
/// The super dash finished charging: release to launch.
SuperCharged,
/// The super dash launched.
SuperDashStarted {
/// Direction, -1 or 1.
dir: i32,
},
/// The super dash is over.
SuperDashEnded {
/// It hit a wall (otherwise it was cancelled).
bonk: bool,
},
/// The cloak opened: gliding.
GlideStarted,
/// The glide is over (jump released, landed, a wall, a dash).
GlideEnded,
/// A dive hit the ground.
DiveImpact {
/// Units fallen from the dive's start (pixels from a scaled [`crate::Platformer`]).
drop: i32,
},
/// The head hit a ceiling.
Bonked,
/// The head clipped a ceiling corner and was nudged past it.
CornerCorrected {
/// Units nudged, signed (pixels from a scaled [`crate::Platformer`]).
dx: i32,
},
/// The character fell out of the world (the terrain said so).
FellOut,
/// Something of your own happened (an [`Ability`](super::Ability) reported it). Make
/// one with [`Event::custom`] and add numbers with [`Event::with`].
Custom {
/// Which of your events (see [`CustomId`]).
id: CustomId,
/// Up to four numbers of your own: a knockback's speed, a hit target's index, a
/// charge level. Zero when unused.
data: [f32; 4],
},
/// Something solid moved into the character (moving ground carried it into a
/// ceiling, a moving solid hit it): it's stuck inside. Reported every step it stays
/// so; usually a respawn.
Squished,
/// It was put back at its spawn point (after falling out, unless respawning is off).
Respawned,
}
impl Event {
/// A custom event `id` without data.
pub const fn custom(id: CustomId) -> Self {
Event::Custom { id, data: [0.0; 4] }
}
/// This event with `data` (only for [`Event::Custom`]; other events stay as they are).
pub const fn with(self, data: [f32; 4]) -> Self {
match self {
Event::Custom { id, .. } => Event::Custom { id, data },
other => other,
}
}
/// This event with its distances and speeds in pixels, `k` per unit: a landing's
/// `drop` and `impact`, a dive impact's `drop`, a corner correction's `dx`. What a
/// [`crate::Platformer`] with a [`crate::Builder::scale`] hands out; directions and
/// [`Event::Custom`] data (yours, in units) stay as they are.
pub fn in_pixels(self, k: i32) -> Self {
match self {
Event::Landed { impact, drop } => Event::Landed {
impact: impact * k as f32,
drop: drop * k,
},
Event::DiveImpact { drop } => Event::DiveImpact { drop: drop * k },
Event::CornerCorrected { dx } => Event::CornerCorrected { dx: dx * k },
other => other,
}
}
/// The data of custom event `id`, if this is one.
pub fn custom_data(&self, id: CustomId) -> Option<[f32; 4]> {
match *self {
Event::Custom { id: i, data } if i == id => Some(data),
_ => None,
}
}
}