Mirai's Miscellaneous Misadventures
M51 / core / sprites.c
1
2
3
4#include <mimimi.h>
5
6
7 todo: Physics behaves strangely near the left and top edges of a given ground.
8 That is because division rounds towards zero rather than towards negative infinity.
9 Is this worhtwhile fixing?
10 It is usually easy to avoid this by simply having the leftmost and topmost edges be zeroed out or inaccessible.
11*/
12
13static void mimimi_wall_physics(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
14{
15 int x0, y0;
16 int x1, y1;
17 int left, right;
18 int top, bottom;
19 int top2, bottom2;
20
21 x0 = position->x;
22 y0 = position->y;
23 x1 = physics->width / 2;
24 y1 = physics->height;
25
26 top = (y0 - y1) / 128;
27 top2 = top - 1;
28 bottom = (y0 - 127) / 128;
29 bottom2 = bottom + 1;
30 left = (x0 - x1) / 128;
31 right = (x0 + x1) / 128;
32
33 if (
34 (mimimi_ground_tile(ground, left, bottom) != 0 && mimimi_ground_tile(ground, left, bottom2) != 0) ||
35 (mimimi_ground_tile(ground, left, top) != 0 && mimimi_ground_tile(ground, left, top2) != 0)
36 )
37 {
38 if (physics->dx < 0) physics->dx = 0;
39 position->x = (left + 1) * 128 + x1;
40 }
41
42 if (
43 (mimimi_ground_tile(ground, right, bottom) != 0 && mimimi_ground_tile(ground, right, bottom2) != 0) ||
44 (mimimi_ground_tile(ground, right, top) != 0 && mimimi_ground_tile(ground, right, top2) != 0)
45 )
46 {
47 if (physics->dx > 0) physics->dx = 0;
48 position->x = right * 128 - x1 - 1;
49 }
50}
51
52static void mimimi_slope_physics(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
53{
54 int x0, y0;
55 int x1, y1;
56 int top, bottom;
57 int left, right;
58
59 x0 = position->x;
60 y0 = position->y;
61 x1 = physics->width / 2;
62 y1 = physics->height;
63
64 top = (y0 - y1) / 128;
65 bottom = (y0 - 127) / 128;
66 left = (x0 - x1) / 128;
67 right = (x0 + x1) / 128;
68
69 if (mimimi_ground_tile(ground, left, bottom) != 0)
70 if (mimimi_ground_tile(ground, left, top) == 0)
71 position->y = bottom * 128;
72
73 if (mimimi_ground_tile(ground, right, bottom) != 0)
74 if (mimimi_ground_tile(ground, right, top) == 0)
75 position->y = bottom * 128;
76}
77
78static void mimimi_ceiling_physics(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
79{
80 int x0, y0;
81 int x1, y1;
82 int top, top2;
83 int left, right;
84
85 x0 = position->x;
86 y0 = position->y;
87 x1 = physics->width / 2;
88 y1 = physics->height;
89
90 top = (y0 - y1) / 128;
91 top2 = top - 1;
92 left = (x0 - x1) / 128;
93 right = (x0 + x1) / 128;
94
95 if (mimimi_ground_tile(ground, left, top) != 0 && mimimi_ground_tile(ground, right, top) != 0)
96 if (mimimi_ground_tile(ground, left, top2) != 0 || mimimi_ground_tile(ground, right, top2) != 0)
97 {
98 if (physics->dy < 0) physics->dy = 0;
99 position->y = (top + 1) * 128 + y1;
100 }
101}
102
103static void mimimi_landing_physics(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
104{
105 int x0, y0;
106 int x1;
107 int left, right;
108 int bottom;
109
110 x0 = position->x;
111 y0 = position->y;
112 x1 = physics->width / 2;
113
114 bottom = y0 / 128;
115 left = (x0 - x1) / 128;
116 right = (x0 + x1) / 128;
117
118 if (physics->dy < 0) return;
119
120 if (mimimi_ground_tile(ground, left, bottom) != 0 || mimimi_ground_tile(ground, right, bottom) != 0)
121 {
122 physics->airborne = 0;
123 physics->dy = 0;
124 position->y = bottom * 128;
125 }
126}
127
128static void mimimi_fall_physics(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
129{
130 int x0, y0;
131 int x1;
132 int bottom, bottom2;
133 int center;
134 int left, right;
135
136 x0 = position->x;
137 y0 = position->y;
138 x1 = physics->width / 2;
139
140 bottom = y0 / 128;
141 bottom2 = bottom + 1;
142 center = x0 / 128;
143 left = (x0 - x1) / 128;
144 right = (x0 + x1) / 128;
145
146 if (mimimi_ground_tile(ground, left, bottom) == 0 && mimimi_ground_tile(ground, right, bottom) == 0)
147 {
148 if (mimimi_ground_tile(ground, center, bottom2) == 0)
149
150 physics->airborne = 1;
151 else
152
153 position->y = bottom2 * 128;
154 }
155}
156
157static void mimimi_physics_dynamics(struct mimimi_physics *physics, struct mimimi_position *position)
158{
159 position->x += physics->dx / 256;
160 position->y += physics->dy / 256;
161}
162
163static void mimimi_ground_collision_physics(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
164{
165 mimimi_slope_physics(physics, position, ground);
166 mimimi_wall_physics(physics, position, ground);
167 mimimi_fall_physics(physics, position, ground);
168
169 if (physics->airborne == 0)
170 {
171 position->y /= 128;
172 position->y *= 128;
173 }
174}
175
176static void mimimi_airborne_collision_physics(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
177{
178 mimimi_ceiling_physics(physics, position, ground);
179 mimimi_wall_physics(physics, position, ground);
180 mimimi_landing_physics(physics, position, ground);
181}
182
183static void mimimi_ground_physics(struct mimimi_physics *physics, struct mimimi_position *position)
184{
185 physics->dx *= 4;
186 physics->dx /= 5;
187 physics->dy = 0;
188 mimimi_physics_dynamics(physics, position);
189}
190
191static void mimimi_airborne_physics(struct mimimi_physics *physics, struct mimimi_position *position)
192{
193 physics->dx *= 13;
194 physics->dx /= 14;
195 physics->dy += physics->gravity;
196 mimimi_physics_dynamics(physics, position);
197}
198
199void mimimi_collision_physics_tick(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
200{
201 if (physics->airborne == 0)
202 mimimi_ground_collision_physics(physics, position, ground);
203 else
204 mimimi_airborne_collision_physics(physics, position, ground);
205}
206
207void mimimi_dynamics_tick(struct mimimi_physics *physics, struct mimimi_position *position)
208{
209 if (physics->airborne == 0)
210 mimimi_ground_physics(physics, position);
211 else
212 mimimi_airborne_physics(physics, position);
213}
214
215void mimimi_physics_tick(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
216{
217 mimimi_dynamics_tick(physics, position);
218 mimimi_collision_physics_tick(physics, position, ground);
219}
220
221void mimimi_physics(struct mimimi_physics *physics, int width, int height)
222{
223 physics->dx = 0;
224 physics->dy = 0;
225 physics->airborne = 1;
226 physics->width = width;
227 physics->height = height;
228 physics->gravity = 768;
229}
230
231void mimimi_life_tick(struct mimimi_life *life)
232{
233 if (life->knocked_time != 0)
234 {
235 life->knocked_time--;
236 life->immunity_time = life->recovery_time;
237 }
238
239 if (life->immunity_time != 0)
240 {
241 life->pristinity = life->max_pristinity;
242 life->immunity_time--;
243 }
244
245 if (life->pristinity < life->max_pristinity)
246 life->pristinity++;
247}
248
249void mimimi_fall_tick(struct mimimi_fall *fall, struct mimimi_physics *physics, struct mimimi_life *life)
250{
251 if (physics->dy > fall->max_speed && life->knocked_time < fall->knocked_time)
252 life->knocked_time = fall->knocked_time;
253}
254
255void mimimi_walk_tick(struct mimimi_walk *walk, struct mimimi_physics *physics)
256{
257 int ax;
258
259 if (walk->direction == 0) return;
260
261 if (physics->airborne == 0)
262 ax = walk->ground_speed;
263 else
264 ax = walk->airborne_speed;
265
266 if (walk->direction == 1)
267 physics->dx -= ax;
268 if (walk->direction == 2)
269 physics->dx += ax;
270}
271
272void mimimi_sprite(struct mimimi_sprite *sprite, struct mimimi_ground *ground, int x, int y, int width, int height)
273{
274 sprite->position.x = x;
275 sprite->position.y = y;
276
277 mimimi_physics(&sprite->physics, width, height);
278
279 sprite->life.knocked_time = 0;
280 sprite->life.immunity_time = 0;
281 sprite->life.pristinity = 256;
282 sprite->life.max_pristinity = 256;
283 sprite->life.recovery_time = 64;
284
285 sprite->fall.max_speed = 28672;
286 sprite->fall.knocked_time = 64;
287
288 sprite->walk.ground_speed = 2048;
289 sprite->walk.airborne_speed = 768;
290 sprite->walk.direction = 0;
291
292 sprite->offset.x = 0;
293 sprite->offset.y = 0;
294
295 sprite->ground = ground;
296}
297
298void mimimi_sprite_tick(struct mimimi_sprite *sprite)
299{
300 struct mimimi_position position;
301
302 mimimi_life_tick(&sprite->life);
303 if (sprite->life.knocked_time == 0) mimimi_walk_tick(&sprite->walk, &sprite->physics);
304
305 position = sprite->position;
306 position.x -= sprite->offset.x;
307 position.y -= sprite->offset.y;
308 mimimi_physics_tick(&sprite->physics, &position, sprite->ground);
309 position.x += sprite->offset.x;
310 position.y += sprite->offset.y;
311 sprite->position = position;
312
313 mimimi_fall_tick(&sprite->fall, &sprite->physics, &sprite->life);
314}
315
316void mimimi_jump(void *data)
317{
318 struct mimimi_sprite *sprite;
319 sprite = data;
320 if (sprite->life.knocked_time != 0) return;
321 if (sprite->physics.airborne != 0) return;
322 sprite->physics.airborne = 1;
323 sprite->physics.dy = -14336;
324}