Mirai's Miscellaneous Misadventures

M55 / core / effects.c

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