Mirai's Miscellaneous Misadventures

M55 / 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) return y;
12	}
13	return 0;
14}
15
16static void mimimi_origin(struct mimimi_ground *ground, struct mimimi_position *position)
17{
18	for (position->y = 0 ; position->y < ground->height ; position->y++) {
19		for (position->x = 0 ; position->x < ground->width ; position->x++) {
20			if (ground->tiles[position->x + position->y * ground->width] == 2) return;
21		}
22	}
23}
24
25void mimimi_stage(struct mimimi_stage *stage, struct mimimi_ground **grounds, int count)
26{
27	int i, k;
28	struct mimimi_position offset;
29	int left_floor_y, right_floor_y;
30	struct mimimi_area *area;
31	
32	stage->sprite_count = 0;
33	stage->area_count = count;
34	stage->areas = malloc(sizeof *stage->areas * count);
35	if (stage->areas == NULL) exit(1);
36	stage->clamped_camera.input = &stage->camera;
37	stage->platform_set_count = 0;
38	
39	for (i = 0 ; i < count ; i++) {
40		area = stage->areas + i;
41		area->ground = grounds[i];
42		area->background_count = 0;
43		area->foreground_count = 0;
44	}
45	
46	mimimi_origin(grounds[0], &offset);
47	offset.x *= -1;
48	offset.y *= -1;
49	stage->areas[0].ground = grounds[0];
50	stage->areas[0].offset = offset;
51	
52	left_floor_y = mimimi_ground_floor(grounds[0], 0);
53	
54	for (i = 1 ; i < count ; i++) {
55		area = stage->areas + i;
56		area->ground = grounds[i];
57		right_floor_y = mimimi_ground_floor(grounds[i], grounds[i]->width - 1);
58		offset.x -= grounds[i]->width;
59		offset.y -= right_floor_y - left_floor_y;
60		left_floor_y = mimimi_ground_floor(grounds[i], 0);
61		area->offset = offset;
62	}
63	
64	k = sizeof stage->sounds / sizeof *stage->sounds;
65	
66	for (i = 0 ; i < k ; i++) {
67		stage->sounds[i].sound.count = 0;
68		stage->sounds[i].current = 0;
69	}
70}
71
72void mimimi_stage_tick(struct mimimi_stage *stage, struct mimimi_input *input)
73{
74	struct mimimi_sprite *sprite, *player;
75	int i, j, k;
76	int x, y;
77	int count;
78	struct mimimi_image *image;
79	struct mimimi_played_sound *sound;
80	
81	image = &input->image;
82	player = stage->sprites;
83	
84	j = 0;
85	while (player->position.x < stage->areas[j].offset.x * 128) j++;
86	stage->area_index = j;
87	
88	for (i = 0 ; i < stage->sprite_count ; i++) {
89		
90		sprite = stage->sprites + i;
91		
92		k = 0;
93		while (sprite->position.x < stage->areas[k].offset.x * 128) k++;
94		sprite->ground = stage->areas[k].ground;
95		sprite->offset = stage->areas[k].offset;
96		sprite->offset.x *= 128;
97		sprite->offset.y *= 128;
98		
99		stage->clamped_camera.offset = stage->areas[k].offset;
100		stage->clamped_camera.size.width = stage->areas[k].ground->width;
101		stage->clamped_camera.size.height = stage->areas[k].ground->height;
102		
103		mimimi_sprite_tick(sprite);
104	}
105	
106	for (i = 0 ; i < stage->platform_set_count ; i++) mimimi_platform_set_tick(stage->platform_sets + i);
107	
108	x = player->physics.dx / 42;
109	y = player->physics.dy / 64 - 256;
110	mimimi_camera_tick(&stage->camera, &player->position, x, y);
111	mimimi_clamped_camera_tick(&stage->clamped_camera, image->width, image->height);
112	
113	for (i = 0 ; i < stage->areas[j].background_count ; i++) {
114		mimimi_background_tick(stage->areas[j].backgrounds + i, image, &stage->clamped_camera.output, &player->offset);
115	}
116	for (i = 0 ; i < stage->platform_set_count ; i++) {
117		mimimi_platform_set_display_tick(stage->platform_sets + i, image, &stage->clamped_camera.output);
118	}
119	for (i = 0 ; i < stage->sprite_count ; i++) {
120		mimimi_display_tick(image, stage->sprites + i, &stage->clamped_camera.output);
121	}
122	for (i = 0 ; i < stage->areas[j].foreground_count ; i++) {
123		mimimi_background_tick(stage->areas[j].foregrounds + i, image, &stage->clamped_camera.output, &player->offset);
124	}
125	
126	mimimi_boxing(&stage->clamped_camera.size, image);
127	
128	count = sizeof stage->sounds / sizeof *stage->sounds;
129	k = sizeof input->notes / sizeof *input->notes;
130	
131	for (i = 0 ; i < k ; i++) input->notes[i].volume = 0;
132	
133	for (i = 0 ; i < count ; i++) {
134		sound = stage->sounds + i;
135		if (sound->current >= sound->sound.count) continue;
136		for (k = 0 ; k < 16 ; k++) input->notes[i * 16 + k] = sound->sound.notes[sound->current][k];
137		sound->current++;
138	}
139}
140
141struct mimimi_sprite *mimimi_spawn(struct mimimi_stage *stage, struct mimimi_model *model, int x, int y, int width, int height)
142{
143	int i;
144	
145	if (stage->sprite_count == 0) stage->sprites = NULL;
146	
147	i = stage->sprite_count++;
148	
149	stage->sprites = realloc(stage->sprites, sizeof *stage->sprites * stage->sprite_count);
150	if (stage->sprites == NULL) exit(1);
151	
152	mimimi_sprite(stage->sprites + i, model, NULL, x, y, width, height);
153	
154	if (i == 0) {
155		stage->camera = stage->sprites[i].position;
156		stage->camera.y -= 256;
157	}
158	
159	return stage->sprites + i;
160}
161
162void mimimi_background(struct mimimi_image *image, struct mimimi_ground *ground)
163{
164	int x, y;
165	unsigned char color;
166	
167	image->width = ground->width * 16;
168	image->height = ground->height * 16;
169	image->colors = malloc(image->width * image->height);
170	if (image->colors == NULL) exit(1);
171	
172	for (y = 0 ; y < image->height ; y++) {
173		for (x = 0 ; x < image->width ; x++) {
174			color = ground->colors[mimimi_ground_tile(ground, x / 16, y / 16)];
175			image->colors[x + y * image->width] = color;
176		}
177	}
178}
179
180void mimimi_play_sound(struct mimimi_stage *stage, struct mimimi_sound *sound)
181{
182	int i;
183	int count;
184	
185	count = sizeof stage->sounds / sizeof *stage->sounds;
186	
187	for (i = 0 ; i < count ; i++) {
188		if (stage->sounds[i].current >= stage->sounds[i].sound.count) break;
189	}
190	
191	if (i == count) return;
192	
193	stage->sounds[i].sound = *sound;
194	stage->sounds[i].current = 0;
195}
196
197void mimimi_stage_jump(void *data)
198{
199	static struct mimimi_sound sound = {{0}, 0};
200	
201	struct mimimi_stage_jump *jump;
202	
203	jump = data;
204	if (jump->sprite->physics.airborne == 0) mimimi_play_sound(jump->stage, &sound);
205	mimimi_jump(jump->sprite);
206}