Mirai's Miscellaneous Misadventures

M53 / core / stages.c

1/* license: AGPLv3 or later */
2/* copyright 2024 zamfofex */
3
4#include <stdlib.h>
5#include "../mimimi.h"
6
7static int mimimi_ground_floor(struct mimimi_ground *ground, int x)
8{
9    int y;
10    for (y = ground->height; y > 0; y--)
11        if (mimimi_ground_tile(ground, x, y - 1) == 0)
12            return y;
13    return 0;
14}
15
16static void mimimi_origin(struct mimimi_ground *ground,
17    struct mimimi_position *position)
18{
19    for (position->y = 0; position->y < ground->height; position->y++)
20        for (position->x = 0; position->x < ground->width; position->x++)
21            if (ground->tiles[position->x + position->y * ground->width] == 2)
22                return;
23}
24
25void mimimi_stage(struct mimimi_stage *stage,
26    struct mimimi_ground **grounds, int count)
27{
28    int i;
29    struct mimimi_position offset;
30    int left_floor_y, right_floor_y;
31    struct mimimi_area *area;
32
33    stage->sprite_count = 0;
34    stage->area_count = count;
35    stage->areas = malloc(sizeof *stage->areas * count);
36    if (stage->areas == NULL)
37        exit(1);
38    stage->clamped_camera.input = &stage->camera;
39    stage->platform_set_count = 0;
40
41    for (i = 0; i < count; i++) {
42        area = stage->areas + i;
43        area->ground = grounds[i];
44        area->background_count = 0;
45        area->foreground_count = 0;
46    }
47
48    mimimi_origin(grounds[0], &offset);
49    offset.x *= -1;
50    offset.y *= -1;
51    stage->areas[0].ground = grounds[0];
52    stage->areas[0].offset = offset;
53
54    left_floor_y = mimimi_ground_floor(grounds[0], 0);
55
56    for (i = 1; i < count; i++) {
57        area = stage->areas + i;
58        area->ground = grounds[i];
59        right_floor_y =
60            mimimi_ground_floor(grounds[i], grounds[i]->width - 1);
61        offset.x -= grounds[i]->width;
62        offset.y -= right_floor_y - left_floor_y;
63        left_floor_y = mimimi_ground_floor(grounds[i], 0);
64        area->offset = offset;
65    }
66}
67
68void mimimi_stage_tick(struct mimimi_stage *stage,
69    struct mimimi_image *image)
70{
71    struct mimimi_sprite *sprite, *player;
72    int i, j, k;
73    int x, y;
74
75    player = stage->sprites;
76
77    j = 0;
78    while (player->position.x < stage->areas[j].offset.x * 128)
79        j++;
80
81    for (i = 0; i < stage->sprite_count; i++) {
82        sprite = stage->sprites + i;
83
84        k = 0;
85        while (sprite->position.x < stage->areas[k].offset.x * 128)
86            k++;
87        sprite->ground = stage->areas[k].ground;
88        sprite->offset = stage->areas[k].offset;
89        sprite->offset.x *= 128;
90        sprite->offset.y *= 128;
91
92        stage->clamped_camera.offset = stage->areas[k].offset;
93        stage->clamped_camera.size.width = stage->areas[k].ground->width;
94        stage->clamped_camera.size.height = stage->areas[k].ground->height;
95
96        mimimi_sprite_tick(sprite);
97    }
98
99    for (i = 0; i < stage->platform_set_count; i++)
100        mimimi_platform_set_tick(stage->platform_sets + i);
101
102    x = player->physics.dx / 42;
103    y = player->physics.dy / 64 - 256;
104    mimimi_camera_tick(&stage->camera, &player->position, x, y);
105    mimimi_clamped_camera_tick(&stage->clamped_camera, image->width,
106        image->height);
107
108    for (i = 0; i < stage->areas[j].background_count; i++)
109        mimimi_background_tick(stage->areas[j].backgrounds + i, image,
110            &stage->clamped_camera.output, &player->offset);
111    for (i = 0; i < stage->platform_set_count; i++)
112        mimimi_platform_set_display_tick(stage->platform_sets + i, image,
113            &stage->clamped_camera.output);
114    for (i = 0; i < stage->sprite_count; i++)
115        mimimi_display_tick(image, stage->sprites + i,
116            &stage->clamped_camera.output);
117    for (i = 0; i < stage->areas[j].foreground_count; i++)
118        mimimi_background_tick(stage->areas[j].foregrounds + i, image,
119            &stage->clamped_camera.output, &player->offset);
120
121    mimimi_boxing(&stage->clamped_camera.size, image);
122}
123
124struct mimimi_sprite *mimimi_spawn(struct mimimi_stage *stage,
125    struct mimimi_model *model, int x, int y, int width, int height)
126{
127    int i;
128
129    if (stage->sprite_count == 0)
130        stage->sprites = NULL;
131
132    i = stage->sprite_count++;
133
134    stage->sprites =
135        realloc(stage->sprites,
136        sizeof *stage->sprites * stage->sprite_count);
137    if (stage->sprites == NULL)
138        exit(1);
139
140    mimimi_sprite(stage->sprites + i, model, NULL, x, y, width, height);
141
142    if (i == 0) {
143        stage->camera = stage->sprites[i].position;
144        stage->camera.y -= 256;
145    }
146
147    return stage->sprites + i;
148}
149
150void mimimi_background(struct mimimi_image *image,
151    struct mimimi_ground *ground, unsigned char *colors)
152{
153    int x, y;
154    unsigned char color;
155
156    image->width = ground->width * 16;
157    image->height = ground->height * 16;
158    image->colors = malloc(image->width * image->height);
159    if (image->colors == NULL)
160        exit(1);
161
162    for (y = 0; y < image->height; y++) {
163        for (x = 0; x < image->width; x++) {
164            color = colors[mimimi_ground_tile(ground, x / 16, y / 16)];
165            image->colors[x + y * image->width] = color;
166        }
167    }
168}