Mirai's Miscellaneous Misadventures

M52 / core / effects.c

1/* license: AGPLv3 or later */
2/* copyright 2024 zamfofex */
3
4#include <stdlib.h>
5#include "../mimimi.h"
6
7void mimimi_conveyor_tick(struct mimimi_conveyor *conveyor)
8{
9	struct mimimi_sprite *sprite;
10	struct mimimi_ground *ground;
11	unsigned char was_airborne;
12	int x1, x2, y;
13	
14	sprite = conveyor->sprite;
15	ground = conveyor->ground;
16	was_airborne = conveyor->was_airborne;
17	
18	conveyor->was_airborne = sprite->physics.airborne;
19	
20	if (sprite->physics.airborne != 0)
21	{
22		if (was_airborne == 0)
23			sprite->physics.dx += conveyor->speed;
24		return;
25	}
26	
27	x1 = (sprite->position.x - sprite->physics.width / 2) / 128;
28	x2 = (sprite->position.x + sprite->physics.width / 2) / 128;
29	y = (sprite->position.y + 64) / 128;
30	
31	if (mimimi_ground_tile(ground, x1, y) != 0 || mimimi_ground_tile(ground, x2, y) != 0)
32		sprite->position.x += conveyor->speed;
33}
34
35void mimimi_positioned_physics_tick(struct mimimi_positioned_physics *physics, struct mimimi_ground *ground)
36{
37	int dx, dy;
38	unsigned char was_airborne;
39	struct mimimi_position other_position;
40	unsigned char airborne;
41	
42	dx = physics->transform.x - physics->previous.x;
43	dy = physics->transform.y - physics->previous.y;
44	
45	physics->previous = physics->transform;
46	
47	was_airborne = physics->was_airborne;
48	physics->was_airborne = physics->other.airborne;
49	
50	airborne = physics->physics->airborne;
51	
52	physics->other.dx = physics->physics->dx;
53	physics->other.dy = physics->physics->dy;
54	physics->other.width = physics->physics->width;
55	physics->other.height = physics->physics->height;
56	
57	other_position = *physics->position;
58	other_position.x -= physics->transform.x;
59	other_position.y -= physics->transform.y;
60	
61	if (physics->other.airborne == 0)
62	{
63		other_position.x += dx;
64		other_position.y += dy;
65	}
66	
67	if (physics->physics->airborne != 0) physics->other.airborne = 1;
68	mimimi_collision_physics_tick(&physics->other, &other_position, ground);
69	if (physics->other.airborne == 0) physics->physics->airborne = 0;
70	
71	if (airborne == 0) return;
72	
73	other_position.x += physics->transform.x;
74	other_position.y += physics->transform.y;
75	
76	*physics->position = other_position;
77	
78	physics->physics->dx = physics->other.dx;
79	physics->physics->dy = physics->other.dy;
80	
81	if (physics->other.airborne != 0 && was_airborne == 0)
82	{
83		/* physics->physics->dx += dx; */
84		/* physics->physics->dy += dy; */
85	}
86}
87
88void mimimi_positioned_physics(struct mimimi_positioned_physics *physics, struct mimimi_physics *other, struct mimimi_position *position)
89{
90	mimimi_physics(&physics->other, 0, 0);
91	physics->physics = other;
92	physics->position = position;
93	physics->transform.x = 0;
94	physics->transform.y = 0;
95	physics->previous = *position;
96	physics->was_airborne = other->airborne;
97}
98
99void mimimi_trampoline_tick(struct mimimi_trampoline *trampoline)
100{
101	struct mimimi_sprite *sprite;
102	struct mimimi_ground *ground;
103	int dy;
104	int x1, x2, y;
105	
106	sprite = trampoline->sprite;
107	ground = trampoline->ground;
108	
109	dy = trampoline->dy;
110	trampoline->dy = 0;
111	
112	if (sprite->physics.airborne != 0)
113	{
114		trampoline->dy = sprite->physics.dy;
115		return;
116	}
117	
118	if (dy == 0) return;
119	
120	x1 = (sprite->position.x - sprite->physics.width / 2) / 128;
121	x2 = (sprite->position.x + sprite->physics.width / 2) / 128;
122	y = (sprite->position.y + 64) / 128;
123	
124	if (mimimi_ground_tile(ground, x1, y) != 0) return;
125	if (mimimi_ground_tile(ground, x2, y) != 0) return;
126	
127	sprite->physics.airborne = 1;
128	sprite->physics.dy -= dy * trampoline->restitution / 256;
129}
130
131void mimimi_platform_display_tick(struct mimimi_platform *platform, struct mimimi_position *camera, struct mimimi_image *image)
132{
133	mimimi_camera_stamp(image, camera, platform->physics.transform.x, platform->physics.transform.y, 0, platform->image);
134}
135
136struct mimimi_platform_set *mimimi_add_platform_set(struct mimimi_stage *stage)
137{
138	int i;
139	struct mimimi_platform_set *platforms;
140	
141	if (stage->platform_set_count == 0)
142		stage->platform_sets = NULL;
143	
144	i = stage->platform_set_count++;
145	stage->platform_sets = realloc(stage->platform_sets, sizeof *stage->platform_sets * stage->platform_set_count);
146	if (stage->platform_sets == NULL) exit(1);
147	
148	platforms = stage->platform_sets + i;
149	
150	platforms->angular_platform_count = 0;
151	platforms->linear_platform_count = 0;
152	platforms->momentum.x = 0;
153	platforms->momentum.dx = 0;
154	platforms->balance = 0;
155	platforms->strength = 0;
156	platforms->linear_weight = 1024;
157	platforms->angular_weight = 1024;
158	platforms->min = -0x10000000;
159	platforms->max = 0x10000000;
160	
161	return platforms;
162}
163
164void mimimi_spawn_linear_platform(struct mimimi_stage *stage, struct mimimi_platform_set *platforms, struct mimimi_ground *ground, struct mimimi_image *image, int x, int y, int scale)
165{
166	int i;
167	
168	if (platforms->linear_platform_count == 0)
169	{
170		platforms->linear_platforms = NULL;
171		platforms->linear_motions = NULL;
172	}
173	
174	i = platforms->linear_platform_count++;
175	platforms->linear_platforms = realloc(platforms->linear_platforms, sizeof *platforms->linear_platforms * platforms->linear_platform_count);
176	platforms->linear_motions = realloc(platforms->linear_motions, sizeof *platforms->linear_motions * platforms->linear_platform_count);
177	
178	if (platforms->linear_platforms == NULL) exit(1);
179	if (platforms->linear_motions == NULL) exit(1);
180	
181	mimimi_positioned_physics(&platforms->linear_platforms[i].physics, &stage->sprites[0].physics, &stage->sprites[0].position);
182	platforms->linear_platforms[i].ground = ground;
183	platforms->linear_platforms[i].image = image;
184	
185	platforms->linear_platforms[i].physics.transform.x = x;
186	mimimi_linear_motion(platforms->linear_motions + i, &platforms->linear_platforms[i].physics.transform.y, y, scale);
187	mimimi_linear_motion_apply(platforms->linear_motions + i, &platforms->momentum);
188	
189	for (i = 0 ; i < platforms->linear_platform_count ; i++)
190		platforms->linear_motions[i].value = &platforms->linear_platforms[i].physics.transform.y;
191}
192
193void mimimi_spawn_angular_platform(struct mimimi_stage *stage, struct mimimi_platform_set *platforms, struct mimimi_ground *ground, struct mimimi_image *image, int x, int y, int a, int scale, int height)
194{
195	int i;
196	
197	if (platforms->angular_platform_count == 0)
198	{
199		platforms->angular_platforms = NULL;
200		platforms->angular_motions = NULL;
201	}
202	
203	i = platforms->angular_platform_count++;
204	platforms->angular_platforms = realloc(platforms->angular_platforms, sizeof *platforms->angular_platforms * platforms->angular_platform_count);
205	platforms->angular_motions = realloc(platforms->angular_motions, sizeof *platforms->angular_motions * platforms->angular_platform_count);
206	
207	if (platforms->angular_platforms == NULL) exit(1);
208	if (platforms->angular_motions == NULL) exit(1);
209	
210	mimimi_positioned_physics(&platforms->angular_platforms[i].physics, &stage->sprites[0].physics, &stage->sprites[0].position);
211	platforms->angular_platforms[i].ground = ground;
212	platforms->angular_platforms[i].image = image;
213	
214	mimimi_angular_motion(platforms->angular_motions + i, &platforms->angular_platforms[i].physics.transform, x, y, a, scale, height);
215	mimimi_angular_motion_apply(platforms->angular_motions + i, &platforms->momentum);
216	
217	for (i = 0 ; i < platforms->angular_platform_count ; i++)
218		platforms->angular_motions[i].value = &platforms->angular_platforms[i].physics.transform;
219}
220
221static void mimimi_platforms_propagate(struct mimimi_platform_set *platforms)
222{
223	int i;
224	for (i = 0 ; i < platforms->linear_platform_count ; i++)
225		if (platforms->linear_platforms[i].physics.other.airborne == 0)
226			mimimi_linear_motion_propagate(platforms->linear_motions + i, &platforms->momentum);
227	for (i = 0 ; i < platforms->angular_platform_count ; i++)
228		if (platforms->angular_platforms[i].physics.other.airborne == 0)
229			mimimi_angular_motion_propagate(platforms->angular_motions + i, &platforms->momentum);
230}
231
232static void mimimi_platforms_apply(struct mimimi_platform_set *platforms)
233{
234	int i;
235	for (i = 0 ; i < platforms->linear_platform_count ; i++)
236		mimimi_linear_motion_apply(platforms->linear_motions + i, &platforms->momentum);
237	for (i = 0 ; i < platforms->angular_platform_count ; i++)
238		mimimi_angular_motion_apply(platforms->angular_motions + i, &platforms->momentum);
239}
240
241void mimimi_platform_set_tick(struct mimimi_platform_set *platforms)
242{
243	int i;
244	int diff;
245	
246	for (i = 0 ; i < platforms->linear_platform_count ; i++)
247		if (platforms->linear_platforms[i].physics.other.airborne == 0)
248			platforms->linear_platforms[i].physics.transform.y += platforms->linear_weight;
249	
250	for (i = 0 ; i < platforms->angular_platform_count ; i++)
251		if (platforms->angular_platforms[i].physics.other.airborne == 0)
252			platforms->angular_platforms[i].physics.transform.y += platforms->angular_weight * platforms->angular_motions[i].height / 2048;
253	
254	mimimi_platforms_propagate(platforms);
255	
256	platforms->momentum.dx *= 31;
257	platforms->momentum.dx /= 32;
258	platforms->momentum.x += platforms->momentum.dx / 256;
259	
260	if (platforms->momentum.x < platforms->min)
261	{
262		platforms->momentum.x = platforms->min;
263		platforms->momentum.dx = 0;
264	}
265	if (platforms->momentum.x > platforms->max)
266	{
267		platforms->momentum.x = platforms->max;
268		platforms->momentum.dx = 0;
269	}
270	
271	mimimi_platforms_apply(platforms);
272	
273	for (i = 0 ; i < platforms->linear_platform_count ; i++)
274		mimimi_positioned_physics_tick(&platforms->linear_platforms[i].physics, platforms->linear_platforms[i].ground);
275	for (i = 0 ; i < platforms->angular_platform_count ; i++)
276		mimimi_positioned_physics_tick(&platforms->angular_platforms[i].physics, platforms->angular_platforms[i].ground);
277	
278	diff = platforms->balance - platforms->momentum.x;
279	platforms->momentum.dx += platforms->strength * diff / 256;
280}
281
282void mimimi_platform_set_display_tick(struct mimimi_platform_set *platforms, struct mimimi_image *image, struct mimimi_position *camera)
283{
284	int i;
285	for (i = 0 ; i < platforms->linear_platform_count ; i++)
286		mimimi_platform_display_tick(platforms->linear_platforms + i, camera, image);
287	for (i = 0 ; i < platforms->angular_platform_count ; i++)
288		mimimi_platform_display_tick(platforms->angular_platforms + i, camera, image);
289}