Mirai's Miscellaneous Misadventures

M53 / 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)
22            sprite->physics.dx += conveyor->speed;
23        return;
24    }
25
26    x1 = (sprite->position.x - sprite->physics.width / 2) / 128;
27    x2 = (sprite->position.x + sprite->physics.width / 2) / 128;
28    y = (sprite->position.y + 64) / 128;
29
30    if (mimimi_ground_tile(ground, x1, y) != 0
31        || mimimi_ground_tile(ground, x2, y) != 0)
32        sprite->position.x += conveyor->speed;
33}
34
35void mimimi_positioned_physics_tick(struct mimimi_positioned_physics
36    *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        other_position.x += dx;
64        other_position.y += dy;
65    }
66
67    if (physics->physics->airborne != 0)
68        physics->other.airborne = 1;
69    mimimi_collision_physics_tick(&physics->other, &other_position, ground);
70    if (physics->other.airborne == 0)
71        physics->physics->airborne = 0;
72
73    if (airborne == 0)
74        return;
75
76    other_position.x += physics->transform.x;
77    other_position.y += physics->transform.y;
78
79    *physics->position = other_position;
80
81    physics->physics->dx = physics->other.dx;
82    physics->physics->dy = physics->other.dy;
83
84    if (physics->other.airborne != 0 && was_airborne == 0) {
85        /* physics->physics->dx += dx; */
86        /* physics->physics->dy += dy; */
87    }
88}
89
90void mimimi_positioned_physics(struct mimimi_positioned_physics *physics,
91    struct mimimi_physics *other, struct mimimi_position *position)
92{
93    mimimi_physics(&physics->other, 0, 0);
94    physics->other.sprite = other->sprite;
95    physics->physics = other;
96    physics->position = position;
97    physics->transform.x = 0;
98    physics->transform.y = 0;
99    physics->previous = *position;
100    physics->was_airborne = other->airborne;
101}
102
103void mimimi_trampoline_tick(struct mimimi_trampoline *trampoline)
104{
105    struct mimimi_sprite *sprite;
106    struct mimimi_ground *ground;
107    int dy;
108    int x1, x2, y;
109
110    sprite = trampoline->sprite;
111    ground = trampoline->ground;
112
113    dy = trampoline->dy;
114    trampoline->dy = 0;
115
116    if (sprite->physics.airborne != 0) {
117        trampoline->dy = sprite->physics.dy;
118        return;
119    }
120
121    if (dy == 0)
122        return;
123
124    x1 = (sprite->position.x - sprite->physics.width / 2) / 128;
125    x2 = (sprite->position.x + sprite->physics.width / 2) / 128;
126    y = (sprite->position.y + 64) / 128;
127
128    if (mimimi_ground_tile(ground, x1, y) != 0)
129        return;
130    if (mimimi_ground_tile(ground, x2, y) != 0)
131        return;
132
133    sprite->physics.airborne = 1;
134    sprite->physics.dy -= dy * trampoline->restitution / 256;
135}
136
137void mimimi_platform_display_tick(struct mimimi_platform *platform,
138    struct mimimi_position *camera, struct mimimi_image *image)
139{
140    mimimi_camera_stamp(image, camera, platform->physics.transform.x,
141        platform->physics.transform.y, 0, platform->image);
142}
143
144struct mimimi_platform_set *mimimi_add_platform_set(struct mimimi_stage
145    *stage)
146{
147    int i;
148    struct mimimi_platform_set *platforms;
149
150    if (stage->platform_set_count == 0)
151        stage->platform_sets = NULL;
152
153    i = stage->platform_set_count++;
154    stage->platform_sets =
155        realloc(stage->platform_sets,
156        sizeof *stage->platform_sets * stage->platform_set_count);
157    if (stage->platform_sets == NULL)
158        exit(1);
159
160    platforms = stage->platform_sets + i;
161
162    platforms->angular_platform_count = 0;
163    platforms->linear_platform_count = 0;
164    platforms->momentum.x = 0;
165    platforms->momentum.dx = 0;
166    platforms->balance = 0;
167    platforms->strength = 0;
168    platforms->linear_weight = 1024;
169    platforms->angular_weight = 1024;
170    platforms->min = -0x10000000;
171    platforms->max = 0x10000000;
172
173    return platforms;
174}
175
176void mimimi_spawn_linear_platform(struct mimimi_stage *stage,
177    struct mimimi_platform_set *platforms, struct mimimi_ground *ground,
178    struct mimimi_image *image, int x, int y, int scale)
179{
180    int i;
181
182    if (platforms->linear_platform_count == 0) {
183        platforms->linear_platforms = NULL;
184        platforms->linear_motions = NULL;
185    }
186
187    i = platforms->linear_platform_count++;
188    platforms->linear_platforms =
189        realloc(platforms->linear_platforms,
190        sizeof *platforms->linear_platforms *
191        platforms->linear_platform_count);
192    platforms->linear_motions =
193        realloc(platforms->linear_motions,
194        sizeof *platforms->linear_motions *
195        platforms->linear_platform_count);
196
197    if (platforms->linear_platforms == NULL)
198        exit(1);
199    if (platforms->linear_motions == NULL)
200        exit(1);
201
202    mimimi_positioned_physics(&platforms->linear_platforms[i].physics,
203        &stage->sprites[0].physics, &stage->sprites[0].position);
204    platforms->linear_platforms[i].ground = ground;
205    platforms->linear_platforms[i].image = image;
206
207    platforms->linear_platforms[i].physics.transform.x = x;
208    mimimi_linear_motion(platforms->linear_motions + i,
209        &platforms->linear_platforms[i].physics.transform.y, y, scale);
210    mimimi_linear_motion_apply(platforms->linear_motions + i,
211        &platforms->momentum);
212
213    for (i = 0; i < platforms->linear_platform_count; i++)
214        platforms->linear_motions[i].value =
215            &platforms->linear_platforms[i].physics.transform.y;
216}
217
218void mimimi_spawn_angular_platform(struct mimimi_stage *stage,
219    struct mimimi_platform_set *platforms, struct mimimi_ground *ground,
220    struct mimimi_image *image, int x, int y, int a, int scale, int height)
221{
222    int i;
223    struct mimimi_platform *platform;
224
225    if (platforms->angular_platform_count == 0) {
226        platforms->angular_platforms = NULL;
227        platforms->angular_motions = NULL;
228    }
229
230    i = platforms->angular_platform_count++;
231    platforms->angular_platforms =
232        realloc(platforms->angular_platforms,
233        sizeof *platforms->angular_platforms *
234        platforms->angular_platform_count);
235    platforms->angular_motions =
236        realloc(platforms->angular_motions,
237        sizeof *platforms->angular_motions *
238        platforms->angular_platform_count);
239
240    if (platforms->angular_platforms == NULL)
241        exit(1);
242    if (platforms->angular_motions == NULL)
243        exit(1);
244
245    platform = platforms->angular_platforms + i;
246
247    mimimi_positioned_physics(&platform->physics, &stage->sprites[0].physics,
248        &stage->sprites[0].position);
249    platform->ground = ground;
250    platform->image = image;
251
252    mimimi_angular_motion(platforms->angular_motions + i,
253        &platform->physics.transform, x, y, a, scale, height);
254    mimimi_angular_motion_apply(platforms->angular_motions + i,
255        &platforms->momentum);
256
257    for (i = 0; i < platforms->angular_platform_count; i++)
258        platforms->angular_motions[i].value =
259            &platforms->angular_platforms[i].physics.transform;
260}
261
262static void mimimi_platforms_propagate(struct mimimi_platform_set *platforms)
263{
264    int i;
265    for (i = 0; i < platforms->linear_platform_count; i++)
266        if (platforms->linear_platforms[i].physics.other.airborne == 0)
267            mimimi_linear_motion_propagate(platforms->linear_motions + i,
268                &platforms->momentum);
269    for (i = 0; i < platforms->angular_platform_count; i++)
270        if (platforms->angular_platforms[i].physics.other.airborne == 0)
271            mimimi_angular_motion_propagate(platforms->angular_motions + i,
272                &platforms->momentum);
273}
274
275static void mimimi_platforms_apply(struct mimimi_platform_set *platforms)
276{
277    int i;
278    for (i = 0; i < platforms->linear_platform_count; i++)
279        mimimi_linear_motion_apply(platforms->linear_motions + i,
280            &platforms->momentum);
281    for (i = 0; i < platforms->angular_platform_count; i++)
282        mimimi_angular_motion_apply(platforms->angular_motions + i,
283            &platforms->momentum);
284}
285
286void mimimi_platform_set_tick(struct mimimi_platform_set *platforms)
287{
288    int i;
289    int diff;
290
291    for (i = 0; i < platforms->linear_platform_count; i++)
292        if (platforms->linear_platforms[i].physics.other.airborne == 0)
293            platforms->linear_platforms[i].physics.transform.y +=
294                platforms->linear_weight;
295
296    for (i = 0; i < platforms->angular_platform_count; i++)
297        if (platforms->angular_platforms[i].physics.other.airborne == 0)
298            platforms->angular_platforms[i].physics.transform.y +=
299                platforms->angular_weight *
300                platforms->angular_motions[i].height / 2048;
301
302    mimimi_platforms_propagate(platforms);
303
304    platforms->momentum.dx *= 31;
305    platforms->momentum.dx /= 32;
306    platforms->momentum.x += platforms->momentum.dx / 256;
307
308    if (platforms->momentum.x < platforms->min) {
309        platforms->momentum.x = platforms->min;
310        platforms->momentum.dx = 0;
311    }
312    if (platforms->momentum.x > platforms->max) {
313        platforms->momentum.x = platforms->max;
314        platforms->momentum.dx = 0;
315    }
316
317    mimimi_platforms_apply(platforms);
318
319    for (i = 0; i < platforms->linear_platform_count; i++)
320        mimimi_positioned_physics_tick(&platforms->linear_platforms[i].
321            physics, platforms->linear_platforms[i].ground);
322    for (i = 0; i < platforms->angular_platform_count; i++)
323        mimimi_positioned_physics_tick(&platforms->angular_platforms[i].
324            physics, platforms->angular_platforms[i].ground);
325
326    diff = platforms->balance - platforms->momentum.x;
327    platforms->momentum.dx += platforms->strength * diff / 256;
328}
329
330void mimimi_platform_set_display_tick(struct mimimi_platform_set
331    *platforms, struct mimimi_image *image, struct mimimi_position *camera)
332{
333    int i;
334    for (i = 0; i < platforms->linear_platform_count; i++)
335        mimimi_platform_display_tick(platforms->linear_platforms + i,
336            camera, image);
337    for (i = 0; i < platforms->angular_platform_count; i++)
338        mimimi_platform_display_tick(platforms->angular_platforms + i,
339            camera, image);
340}