Mirai's Miscellaneous Misadventures

M54 / core / sprites.c

1/* license: AGPLv3 or later */
2/* copyright 2024 zamfofex */
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, top2;
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	top2 = top - 1;
86	left = mimimi_div_down(x0 - x1, 128);
87	right = mimimi_div_down(x0 + x1, 128);
88	
89	if (mimimi_ground_tile(ground, left, top) != 0 && mimimi_ground_tile(ground, right, top) != 0) {
90		if (mimimi_ground_tile(ground, left, top2) != 0 || mimimi_ground_tile(ground, right, top2) != 0) {
91			if (physics->dy < 0) physics->dy = 0;
92			position->y = (top + 1) * 128 + y1;
93		}
94	}
95}
96
97static void mimimi_landing_physics(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
98{
99	int x0, y0;
100	int x1, y1;
101	int left, right;
102	int bottom, bottom1;
103	
104	if (physics->dy < 0) return;
105	
106	y0 = position->y - mimimi_div(physics->dy, 256) - 1;
107	x0 = position->x;
108	x1 = physics->width / 2;
109	y1 = position->y;
110	
111	bottom = mimimi_div_down(y0, 128);
112	bottom1 = mimimi_div_down(y1, 128);
113	left = mimimi_div_down(x0 - x1, 128);
114	right = mimimi_div_down(x0 + x1, 128);
115	
116	while (bottom <= bottom1) {
117		if (mimimi_ground_tile(ground, left, bottom) != 0 || mimimi_ground_tile(ground, right, bottom) != 0) {
118			physics->airborne = 0;
119			physics->dy = 0;
120			position->y = bottom * 128;
121			return;
122		}
123		bottom++;
124	}
125}
126
127static void mimimi_fall_physics(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
128{
129	int x0, y0;
130	int x1;
131	int bottom, bottom2;
132	int center;
133	int left, right;
134	
135	x0 = position->x;
136	y0 = position->y;
137	x1 = physics->width / 2;
138	
139	bottom = mimimi_div_down(y0, 128);
140	bottom2 = bottom + 1;
141	center = mimimi_div_down(x0, 128);
142	left = mimimi_div_down(x0 - x1, 128);
143	right = mimimi_div_down(x0 + x1, 128);
144	
145	if (mimimi_ground_tile(ground, left, bottom) == 0 && mimimi_ground_tile(ground, right, bottom) == 0) {
146		if (mimimi_ground_tile(ground, center, bottom2) == 0) {
147			physics->airborne = 1;
148		}
149		else {
150			if (physics->sprite != NULL) physics->sprite->trail = 0xFF;
151			position->y = bottom2 * 128;
152		}
153	}
154}
155
156static void mimimi_physics_dynamics(struct mimimi_physics *physics, struct mimimi_position *position)
157{
158	position->x += mimimi_div(physics->dx, 256);
159	position->y += mimimi_div(physics->dy, 256);
160}
161
162static void mimimi_ground_collision_physics(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
163{
164	mimimi_slope_physics(physics, position, ground);
165	mimimi_wall_physics(physics, position, ground);
166	mimimi_fall_physics(physics, position, ground);
167	if (physics->airborne == 0) position->y = mimimi_div_down(position->y, 128) * 128;
168}
169
170static void mimimi_airborne_collision_physics(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
171{
172	mimimi_ceiling_physics(physics, position, ground);
173	mimimi_wall_physics(physics, position, ground);
174	mimimi_landing_physics(physics, position, ground);
175}
176
177static void mimimi_ground_physics(struct mimimi_physics *physics)
178{
179	physics->dx -= mimimi_div(physics->dx, 5);
180	physics->dy = 0;
181}
182
183static void mimimi_airborne_physics(struct mimimi_physics *physics)
184{
185	physics->dy += physics->gravity;
186	physics->dx -= mimimi_div(physics->dx, 7);
187	physics->dy -= mimimi_div(physics->dy, 32);
188}
189
190void mimimi_collision_physics_tick(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
191{
192	if (physics->airborne == 0) mimimi_ground_collision_physics(physics, position, ground);
193	else mimimi_airborne_collision_physics(physics, position, ground);
194}
195
196void mimimi_physics_tick(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground)
197{
198	if (physics->airborne == 0) mimimi_ground_physics(physics);
199	else mimimi_airborne_physics(physics);
200	mimimi_physics_dynamics(physics, position);
201	mimimi_collision_physics_tick(physics, position, ground);
202}
203
204void mimimi_physics(struct mimimi_physics *physics, int width, int height)
205{
206	physics->dx = 0;
207	physics->dy = 0;
208	physics->airborne = 1;
209	physics->width = width;
210	physics->height = height;
211	physics->gravity = 2048;
212	physics->sprite = NULL;
213}
214
215static void mimimi_walk_tick(struct mimimi_walk *walk, struct mimimi_physics *physics)
216{
217	int ax;
218	
219	if (walk->direction == 0) return;
220	
221	if (physics->airborne == 0) ax = walk->ground_speed;
222	else ax = walk->airborne_speed;
223	
224	if (walk->direction == 1) physics->dx -= ax;
225	if (walk->direction == 2) physics->dx += ax;
226}
227
228void mimimi_sprite(struct mimimi_sprite *sprite, struct mimimi_model *model, struct mimimi_ground *ground, int x, int y, int width, int height)
229{
230	sprite->position.x = x;
231	sprite->position.y = y;
232	
233	sprite->trailing_y = y;
234	sprite->trail = 0;
235	
236	sprite->ground = ground;
237	mimimi_physics(&sprite->physics, width, height);
238	sprite->physics.sprite = sprite;
239	
240	sprite->walk.ground_speed = 4096;
241	sprite->walk.airborne_speed = 2048;
242	sprite->walk.direction = 0;
243	
244	sprite->offset.x = 0;
245	sprite->offset.y = 0;
246	
247	sprite->animation_time = 0;
248	sprite->landing_time = 0;
249	sprite->direction = 1;
250	sprite->model = model;
251}
252
253void mimimi_sprite_tick(struct mimimi_sprite *sprite)
254{
255	mimimi_walk_tick(&sprite->walk, &sprite->physics);
256	sprite->position.x -= sprite->offset.x;
257	sprite->position.y -= sprite->offset.y;
258	mimimi_physics_tick(&sprite->physics, &sprite->position, sprite->ground);
259	sprite->position.x += sprite->offset.x;
260	sprite->position.y += sprite->offset.y;
261}
262
263void mimimi_jump(void *data)
264{
265	struct mimimi_sprite *sprite;
266	sprite = data;
267	if (sprite->physics.airborne != 0) return;
268	sprite->physics.airborne = 1;
269	sprite->physics.dy = -0x6800;
270}