Mirai's Miscellaneous Misadventures

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