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