Mirai's Miscellaneous Misadventures

M51 / core / effects.c

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