Mirai's Miscellaneous Misadventures
M55 / core / sprites.c
1
2
3
4#include <stdlib.h>
5#include "../mimimi.h"
6
7static int mimimi_wall_tile(struct mimimi_ground *ground, int x, int y)
8{
9 if (mimimi_ground_tile(ground, x, y + 1) == 0 && mimimi_ground_tile(ground, x, y - 1) == 0) return 0;
10 return mimimi_ground_tile(ground, x, y);
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;
19
20 x0 = position->x;
21 y0 = position->y;
22 x1 = physics->width / 2;
23 y1 = physics->height;
24
25 top = mimimi_div_down(y0 - y1, 128);
26 left = mimimi_div_down(x0 - x1, 128);
27 right = mimimi_div_down(x0 + x1, 128);
28
29 if (mimimi_wall_tile(ground, left, top) != 0) {
30 if (physics->dx < 0) physics->dx = 0;
31 position->x = (left + 1) * 128 + x1;
32 }
33
34 if (mimimi_wall_tile(ground, right, top) != 0) {
35 if (physics->dx > 0) physics->dx = 0;
36 position->x = right * 128 - x1 - 1;
37 }
38}
39
40static void mimimi_slope_physics(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
41{
42 int x0, y0;
43 int x1, y1;
44 int top, bottom;
45 int left, right;
46
47 x0 = position->x;
48 y0 = position->y;
49 x1 = physics->width / 2;
50 y1 = physics->height;
51
52 top = mimimi_div_down(y0 - y1, 128);
53 bottom = mimimi_div_down(y0 - 1, 128);
54 left = mimimi_div_down(x0 - x1, 128);
55 right = mimimi_div_down(x0 + x1, 128);
56
57 if (mimimi_ground_tile(ground, left, bottom) != 0) {
58 if (mimimi_ground_tile(ground, left, top) == 0) {
59 position->y = bottom * 128;
60 if (physics->sprite != NULL) physics->sprite->trail = 0xFF;
61 }
62 }
63
64 if (mimimi_ground_tile(ground, right, bottom) != 0) {
65 if (mimimi_ground_tile(ground, right, top) == 0) {
66 position->y = bottom * 128;
67 if (physics->sprite != NULL) physics->sprite->trail = 0xFF;
68 }
69 }
70}
71
72static void mimimi_ceiling_physics(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
73{
74 int x0, y0;
75 int x1, y1;
76 int top;
77 int left, right;
78
79 x0 = position->x;
80 y0 = position->y;
81 x1 = physics->width / 2;
82 y1 = physics->height;
83
84 top = mimimi_div_down(y0 - y1, 128);
85 left = mimimi_div_down(x0 - x1, 128);
86 right = mimimi_div_down(x0 + x1, 128);
87
88 if (mimimi_wall_tile(ground, left, top) != 0 && mimimi_wall_tile(ground, right, top) != 0) {
89 if (physics->dy < 0) physics->dy = 0;
90 position->y = (top + 1) * 128 + y1;
91 }
92}
93
94static void mimimi_landing_physics(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
95{
96 int x0, y0;
97 int x1, y1;
98 int left, right;
99 int bottom, bottom1;
100 unsigned char tile1, tile2;
101 int restitution;
102
103 if (physics->dy < 0) return;
104
105 y0 = position->y - mimimi_div(physics->dy, 256) - 1;
106 x0 = position->x;
107 x1 = physics->width / 2;
108 y1 = position->y;
109
110 bottom = mimimi_div_down(y0, 128);
111 bottom1 = mimimi_div_down(y1, 128);
112 left = mimimi_div_down(x0 - x1, 128);
113 right = mimimi_div_down(x0 + x1, 128);
114
115 while (bottom <= bottom1) {
116
117 tile1 = mimimi_ground_tile(ground, left, bottom);
118 tile2 = mimimi_ground_tile(ground, right, bottom);
119 if (tile1 == 0 && tile2 == 0) {
120 bottom++;
121 continue;
122 }
123
124 if (ground->restitution[tile1] < ground->restitution[tile2]) {
125 restitution = ground->restitution[tile1];
126 }
127 else {
128 restitution = ground->restitution[tile2];
129 }
130
131 position->y = bottom * 128;
132 physics->dy = -mimimi_div(physics->dy * restitution, 256);
133 if (physics->dy > -2048) {
134 physics->airborne = 0;
135 physics->dy = 0;
136 }
137
138 break;
139 }
140}
141
142static void mimimi_fall_physics(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
143{
144 int x0, y0;
145 int x1;
146 int bottom, bottom2;
147 int center;
148 int left, right;
149
150 x0 = position->x;
151 y0 = position->y;
152 x1 = physics->width / 2;
153
154 bottom = mimimi_div_down(y0, 128);
155 bottom2 = bottom + 1;
156 center = mimimi_div_down(x0, 128);
157 left = mimimi_div_down(x0 - x1, 128);
158 right = mimimi_div_down(x0 + x1, 128);
159
160 if (mimimi_ground_tile(ground, left, bottom) == 0 && mimimi_ground_tile(ground, right, bottom) == 0) {
161 if (mimimi_ground_tile(ground, center, bottom2) == 0) {
162 physics->airborne = 1;
163 }
164 else {
165 if (physics->sprite != NULL) physics->sprite->trail = 0xFF;
166 position->y = bottom2 * 128;
167 }
168 }
169}
170
171static void mimimi_physics_dynamics(struct mimimi_physics *physics, struct mimimi_position *position)
172{
173 position->x += mimimi_div(physics->dx, 256);
174 position->y += mimimi_div(physics->dy, 256);
175}
176
177static void mimimi_ground_collision_physics(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
178{
179 mimimi_slope_physics(physics, position, ground);
180 mimimi_wall_physics(physics, position, ground);
181 mimimi_fall_physics(physics, position, ground);
182 if (physics->airborne == 0) position->y = mimimi_div_down(position->y, 128) * 128;
183}
184
185static void mimimi_airborne_collision_physics(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
186{
187 mimimi_ceiling_physics(physics, position, ground);
188 mimimi_wall_physics(physics, position, ground);
189 mimimi_landing_physics(physics, position, ground);
190}
191
192static void mimimi_ground_physics(struct mimimi_physics *physics)
193{
194 physics->dx -= mimimi_div(physics->dx, 5);
195 physics->dy = 0;
196}
197
198static void mimimi_airborne_physics(struct mimimi_physics *physics)
199{
200 physics->dy += physics->gravity;
201 physics->dx -= mimimi_div(physics->dx, 7);
202 physics->dy -= mimimi_div(physics->dy, 32);
203}
204
205void mimimi_collision_physics_tick(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
206{
207 if (physics->airborne == 0) mimimi_ground_collision_physics(physics, position, ground);
208 else mimimi_airborne_collision_physics(physics, position, ground);
209}
210
211void mimimi_physics_tick(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
212{
213 if (physics->airborne == 0) mimimi_ground_physics(physics);
214 else mimimi_airborne_physics(physics);
215 mimimi_physics_dynamics(physics, position);
216 mimimi_collision_physics_tick(physics, position, ground);
217}
218
219void mimimi_physics(struct mimimi_physics *physics, int width, int height)
220{
221 physics->dx = 0;
222 physics->dy = 0;
223 physics->airborne = 1;
224 physics->width = width;
225 physics->height = height;
226 physics->gravity = 2048;
227 physics->sprite = NULL;
228}
229
230static void mimimi_walk_tick(struct mimimi_walk *walk, struct mimimi_physics *physics)
231{
232 int ax;
233
234 if (walk->direction == 0) return;
235
236 if (physics->airborne == 0) ax = walk->ground_speed;
237 else ax = walk->airborne_speed;
238
239 if (walk->direction == 1) physics->dx -= ax;
240 if (walk->direction == 2) physics->dx += ax;
241}
242
243void mimimi_sprite(struct mimimi_sprite *sprite, struct mimimi_model *model, struct mimimi_ground *ground, int x, int y, int width, int height)
244{
245 sprite->position.x = x;
246 sprite->position.y = y;
247
248 sprite->trailing_y = y;
249 sprite->trail = 0;
250
251 sprite->ground = ground;
252 mimimi_physics(&sprite->physics, width, height);
253 sprite->physics.sprite = sprite;
254
255 sprite->walk.ground_speed = 4096;
256 sprite->walk.airborne_speed = 2048;
257 sprite->walk.direction = 0;
258
259 sprite->offset.x = 0;
260 sprite->offset.y = 0;
261
262 sprite->animation_time = 0;
263 sprite->landing_time = 0;
264 sprite->direction = 1;
265 sprite->model = model;
266}
267
268void mimimi_sprite_tick(struct mimimi_sprite *sprite)
269{
270 mimimi_walk_tick(&sprite->walk, &sprite->physics);
271 sprite->position.x -= sprite->offset.x;
272 sprite->position.y -= sprite->offset.y;
273 mimimi_physics_tick(&sprite->physics, &sprite->position, sprite->ground);
274 sprite->position.x += sprite->offset.x;
275 sprite->position.y += sprite->offset.y;
276}
277
278void mimimi_jump(void *data)
279{
280 struct mimimi_sprite *sprite;
281 sprite = data;
282 if (sprite->physics.airborne != 0) return;
283 sprite->physics.airborne = 1;
284 sprite->physics.dy = -0x6800;
285}