Mirai's Miscellaneous Misadventures

M16 / game.c

1// copyright 2022 zamfofex
2// license: AGPLv3 or later
3
4#include "mimimi.h"
5#include "math.c"
6
7
8// types
9
10struct mirai_animation
11{
12	int count;
13	struct mirai_image *images;
14};
15
16struct mirai_direction_animation_set
17{
18	int count;
19	struct mirai_animation *standing;
20	struct mirai_animation knocked;
21};
22
23struct mirai_animation_set
24{
25	struct mirai_direction_animation_set left, right;
26};
27
28struct mirai_sprite_type
29{
30	struct mirai_animation_set animations;
31	int width;
32	int height;
33};
34
35struct mirai_sprite
36{
37	struct mirai_sprite_type *type;
38	
39	int x, y;
40	int dx, dy;
41	int ax;
42	
43	char airborne;
44	char moving_direction;
45	char facing_direction;
46	
47	void (*behave)(struct mirai_game *game, struct mirai_sprite *sprite);
48	
49	unsigned char animation_time;
50	
51	unsigned char knocked_time;
52	
53	struct mirai_sprite *ai_target;
54	int ai_target_x;
55	int ai_target_y;
56	unsigned char ai_attack_time;
57	
58	unsigned char immunity_time;
59	
60	unsigned char pristinity;
61};
62
63struct mirai_rotating_image_row
64{
65	int size;
66	unsigned char count;
67	unsigned char colors[64];
68};
69
70struct mirai_rotating_image
71{
72	int count;
73	int oy;
74	int oz;
75	struct mirai_rotating_image_row rows[];
76};
77
78struct mirai_model_layer
79{
80	int count;
81	struct mirai_rotating_image *images[];
82};
83
84struct mirai_model
85{
86	struct mirai_model_layer *head;
87	struct mirai_model_layer *torso;
88	struct mirai_model_layer *left_arm;
89	struct mirai_model_layer *right_arm;
90	struct mirai_model_layer *left_leg;
91	struct mirai_model_layer *right_leg;
92};
93
94
95// constants
96
97#include "assets.c"
98
99static int mirai_gravity = 4;
100
101static unsigned char mirai_ground_colors[8][16 * 16];
102
103static unsigned char mirai_colors[230416];
104
105static struct mirai_image mirai_images[312];
106
107static struct mirai_animation mirai_animations[25];
108
109static struct mirai_image *mirai_glyphs[26 * 2 + 10];
110
111static struct mirai_sprite_type mirai_mirai = {{}, 80, 250};
112
113static struct mirai_sprite_type mirai_ryoubi = {{}, 80, 250};
114static struct mirai_sprite_type mirai_ryouna = {{}, 80, 250};
115
116
117// state
118
119struct mirai_game
120{
121	struct mirai_engine engine;
122	struct mirai_sprite sprites[256];
123	unsigned char sprite_count;
124	
125	unsigned int left_history:16;
126	unsigned int right_history:16;
127	
128	struct mirai_sprite *camera_sprite;
129	int camera_x;
130	int camera_y;
131};
132
133
134// functions
135
136static void mirai_stamp(struct mirai_game *game, int x, int y, struct mirai_image *image)
137{
138	x -= game->camera_x;
139	x += mirai_width * 4;
140	y -= game->camera_y;
141	y += mirai_height * 4;
142	
143	x -= image->width * 4;
144	y -= image->height * 8;
145	
146	(*game->engine.stamp)(game->engine.data, x / 8, y / 8, image);
147}
148
149static int mirai_text(struct mirai_game *game, int x, int y, char *text)
150{
151	for (int i = 0 ; *text != '\0' ; i++)
152	{
153		char ch = *text++;
154		
155		if (ch == ' ')
156		{
157			x += 4;
158			continue;
159		}
160		
161		struct mirai_image *image;
162		
163		if (ch >= '0' && ch <= '9')
164			image = mirai_glyphs[ch - '0' + 0];
165		else if (ch >= 'A' && ch <= 'Z')
166			image = mirai_glyphs[ch - 'A' + 10];
167		else if (ch >= 'a' && ch <= 'z')
168			image = mirai_glyphs[ch - 'a' + 36];
169		else
170			continue;
171		
172		(*game->engine.stamp)(game->engine.data, x - 1, y - image->height + 5, image);
173		x += image->width - 1;
174	}
175	
176	return x;
177}
178
179static void mirai_wall_physics(struct mirai_sprite *sprite)
180{
181	int x0 = sprite->x;
182	int x1 = sprite->type->width / 2;
183	int y0 = sprite->y;
184	int y1 = sprite->type->height;
185	
186	int top = (y0 - y1) / 128;
187	int top2 = top - 1;
188	int bottom = (y0 - 127) / 128;
189	int bottom2 = bottom - 1;
190	int left = (x0 - x1) / 128;
191	int right = (x0 + x1) / 128;
192	
193	if (
194		mirai_ground[bottom][left] != 0 && mirai_ground[bottom2][left] != 0 ||
195		mirai_ground[top][left] != 0 && mirai_ground[top2][left]
196	)
197	{
198		if (sprite->dx < 0) sprite->dx = 0;
199		sprite->x = (left + 1) * 128 + x1;
200	}
201	if (
202		mirai_ground[bottom][right] != 0 && mirai_ground[bottom2][right] != 0 ||
203		mirai_ground[top][right] != 0 && mirai_ground[top2][right]
204	)
205	{
206		if (sprite->dx > 0) sprite->dx = 0;
207		sprite->x = right * 128 - x1 - 1;
208	}
209}
210
211static void mirai_step_physics(struct mirai_sprite *sprite)
212{
213	int x0 = sprite->x;
214	int x1 = sprite->type->width / 2;
215	int y0 = sprite->y;
216	int y1 = sprite->type->height;
217	
218	int top = (y0 - y1) / 128;
219	int bottom = (y0 - 127) / 128;
220	int left = (x0 - x1) / 128;
221	int right = (x0 + x1) / 128;
222	
223	if (mirai_ground[bottom][left] != 0 && mirai_ground[top][left] == 0)
224		sprite->y = bottom * 128;
225	if (mirai_ground[bottom][right] != 0 && mirai_ground[top][right] == 0)
226		sprite->y = bottom * 128;
227}
228
229static void mirai_ceiling_physics(struct mirai_sprite *sprite)
230{
231	int x0 = sprite->x;
232	int x1 = sprite->type->width / 2;
233	int y0 = sprite->y;
234	int y1 = sprite->type->height;
235	
236	int top = (y0 - y1) / 128;
237	int top2 = top - 1;
238	int left = (x0 - x1) / 128;
239	int right = (x0 + x1) / 128;
240	
241	if (sprite->dy > 0) return;
242	
243	if (mirai_ground[top][left] != 0)
244	if (mirai_ground[top][right] != 0)
245	if (mirai_ground[top2][left] != 0 || mirai_ground[top2][right] != 0)
246	{
247		sprite->dy = 0;
248		sprite->y = (top + 1) * 128 + y1;
249	}
250}
251
252static void mirai_landing_physics(struct mirai_sprite *sprite)
253{
254	int x0 = sprite->x;
255	int x1 = sprite->type->width / 2;
256	int y0 = sprite->y;
257	
258	int bottom = y0 / 128;
259	int left = (x0 - x1) / 128;
260	int right = (x0 + x1) / 128;
261	
262	if (sprite->dy < 0) return;
263	
264	if (mirai_ground[bottom][left] != 0 || mirai_ground[bottom][right] != 0)
265	{
266		sprite->airborne = 0;
267		sprite->dy = 0;
268		sprite->y = bottom * 128;
269	}
270}
271
272static void mirai_fall_physics(struct mirai_sprite *sprite)
273{
274	int x0 = sprite->x;
275	int x1 = sprite->type->width / 2;
276	int y0 = sprite->y;
277	
278	int bottom = y0 / 128;
279	int center = x0 / 128;
280	int left = (x0 - x1) / 128;
281	int right = (x0 + x1) / 128;
282	
283	if (mirai_ground[bottom][left] == 0 && mirai_ground[bottom][right] == 0)
284	{
285		if (mirai_ground[bottom + 1][center] == 0)
286			// fall
287			sprite->airborne = 1;
288		else
289			// step down
290			sprite->y = (bottom + 1) * 128;
291	}
292}
293
294static void mirai_physics_dynamics(struct mirai_sprite *sprite)
295{
296	sprite->dx += sprite->ax;
297	sprite->x += sprite->dx;
298	sprite->y += sprite->dy;
299}
300
301static void mirai_ground_physics(struct mirai_sprite *sprite)
302{
303	sprite->dx *= 7;
304	sprite->dx /= 8;
305	sprite->dy = 0;
306	
307	mirai_physics_dynamics(sprite);
308	
309	mirai_step_physics(sprite);
310	mirai_wall_physics(sprite);
311	mirai_fall_physics(sprite);
312}
313
314static void mirai_airborne_physics(struct mirai_sprite *sprite)
315{
316	sprite->dx *= 15;
317	sprite->dx /= 16;
318	sprite->dy += mirai_gravity;
319	
320	mirai_physics_dynamics(sprite);
321	
322	mirai_ceiling_physics(sprite);
323	mirai_wall_physics(sprite);
324	mirai_landing_physics(sprite);
325}
326
327static void mirai_jump(struct mirai_sprite *sprite)
328{
329	if (sprite->airborne) return;
330	sprite->airborne = 1;
331	sprite->dy = -64;
332}
333
334static void mirai_damage(struct mirai_game *game, struct mirai_sprite *sprite, int damage, int attack_y, int attack_width, int attack_height)
335{
336	sprite->ai_attack_time = 32;
337	
338	int x1 = sprite->x - attack_width;
339	int y1 = sprite->y + attack_y;
340	
341	if (sprite->facing_direction == 2) x1 += attack_width;
342	
343	int x2 = x1 + attack_width;
344	int y2 = y1 + attack_height;
345	
346	for (int i = 0 ; i < game->sprite_count ; i++)
347	{
348		struct mirai_sprite *other = game->sprites + i;
349		if (other == sprite) continue;
350		if (other->immunity_time != 0) continue;
351		
352		int x = other->x;
353		int y = other->y;
354		
355		if (x > x1 && x < x2)
356		if (y > y1 && y < y2)
357		{
358			other->airborne = 1;
359			other->dy -= 32;
360			if (other->x > sprite->x)
361				other->dx += 32;
362			else
363				other->dx -= 32;
364			
365			if (other->pristinity < damage)
366				other->knocked_time = 128;
367			else
368				other->pristinity -= damage;
369		}
370	}
371}
372
373static void mirai_attack(struct mirai_game *game, struct mirai_sprite *sprite)
374{
375	mirai_damage(game, sprite, 64, -256, 512, 512);
376}
377
378static void mirai_rapid_attack(struct mirai_game *game, struct mirai_sprite *sprite)
379{
380	// todo
381}
382
383static unsigned char mirai_count_oscillations(unsigned int history)
384{
385	unsigned char count = 0;
386	unsigned char prev = history&1;
387	for (int i = 0 ; i < 16 ; i++)
388	{
389		if ((history&1) != prev) count++;
390		prev = history&1;
391		history >>= 1;
392	}
393	return count;
394}
395
396static void mirai_controls(struct mirai_game *game, struct mirai_sprite *sprite)
397{
398	unsigned char left_oscillations = mirai_count_oscillations(game->left_history);
399	unsigned char right_oscillations = mirai_count_oscillations(game->right_history);
400	
401	switch (sprite->moving_direction)
402	{
403	case 0:
404		if ((game->left_history&1) != 0)
405			sprite->moving_direction = 1;
406		if ((game->right_history&1) != 0)
407			sprite->moving_direction = 2;
408		break;
409	case 1:
410		if ((game->left_history&1) == 0)
411			sprite->moving_direction = 0;
412		else if (left_oscillations > 1)
413			mirai_jump(sprite);
414		if ((game->right_history&1) != 0)
415		{
416			if (right_oscillations == 0)
417				mirai_rapid_attack(game, sprite);
418		}
419		if ((game->right_history&1) != 0 && (game->right_history&2) == 0)
420			mirai_attack(game, sprite);
421		break;
422	case 2:
423		if ((game->right_history&1) == 0)
424			sprite->moving_direction = 0;
425		else if (right_oscillations > 1)
426			mirai_jump(sprite);
427		if ((game->left_history&1) != 0)
428		{
429			if (left_oscillations == 0)
430				mirai_rapid_attack(game, sprite);
431		}
432		if ((game->left_history&1) != 0 && (game->left_history&2) == 0)
433			mirai_attack(game, sprite);
434		break;
435	}
436}
437
438static void mirai_enemy_ai(struct mirai_game *game, struct mirai_sprite *sprite)
439{
440	int x = sprite->x - sprite->ai_target->x;
441	int y = sprite->y - sprite->ai_target->y;
442	
443	int abs_x = x;
444	int abs_y = y;
445	
446	if (abs_x < 0) abs_x = -abs_x;
447	if (abs_y < 0) abs_y = -abs_y;
448	
449	char attack = 1;
450	
451	if (abs_x > 2048 || abs_y > 2048)
452	{
453		int distance_x = sprite->ai_target->x - sprite->ai_target_x;
454		int distance_y = sprite->ai_target->y - sprite->ai_target_y;
455		
456		if (distance_x < 0) distance_x = -distance_x;
457		if (distance_y < 0) distance_y = -distance_y;
458		
459		if (distance_x > 4096 || distance_y > 4096)
460		{
461			attack = 0;
462			x = sprite->x - sprite->ai_target_x;
463			y = sprite->y - sprite->ai_target_y;
464		}
465	}
466	
467	sprite->moving_direction = 0;
468	if (x > 256)
469		sprite->moving_direction = 1;
470	else if (x < -256)
471		sprite->moving_direction = 2;
472	else if (attack && sprite->ai_attack_time == 0)
473		mirai_attack(game, sprite);
474	
475	if (y > 512) mirai_jump(sprite);
476}
477
478static void mirai_stationary_ai(struct mirai_game *game, struct mirai_sprite *sprite)
479{
480	int x = sprite->x - sprite->ai_target->x;
481	
482	if (x > 0) sprite->facing_direction = 1;
483	else sprite->facing_direction = 2;
484}
485
486static void mirai_spawn(struct mirai_game *game, int x, int y, struct mirai_sprite_type *type, void (*behave)(struct mirai_game *game, struct mirai_sprite *sprite))
487{
488	if (game->sprite_count == 0xFF) return;
489	struct mirai_sprite *sprite = game->sprites + game->sprite_count;
490	game->sprite_count++;
491	sprite->type = type;
492	sprite->x = x;
493	sprite->y = y;
494	sprite->dx = 0;
495	sprite->dy = 0;
496	sprite->ax = 0;
497	sprite->airborne = 1;
498	sprite->moving_direction = 0;
499	sprite->facing_direction = 1;
500	sprite->animation_time = 0;
501	sprite->behave = behave;
502	sprite->ai_target_x = x;
503	sprite->ai_target_y = y;
504	sprite->ai_attack_time = -1;
505	sprite->immunity_time = 0;
506	sprite->pristinity = -1;
507}
508
509static unsigned char mirai_rotating_image_pixel(struct mirai_rotating_image *rotating_image, unsigned char angle, int x, int y)
510{
511	y += rotating_image->oy;
512	
513	int h = rotating_image->count;
514	if (y < 0) return 0;
515	if (y >= h) return 0;
516	
517	int w = rotating_image->rows[y].size;
518	if (x < -w / 2) return 0;
519	if (x >= w / 2) return 0;
520	
521	x += w / 2;
522	
523	int count = rotating_image->rows[y].count;
524	
525	int a = angle;
526	a *= count;
527	a += 128;
528	a /= 256;
529	a += x;
530	a %= count;
531	
532	return rotating_image->rows[y].colors[a];
533}
534
535static void mirai_rotating_image_stamp(struct mirai_image *image, struct mirai_rotating_image *rotating_image, unsigned char y_angle, unsigned char z_angle, int x0, int y0, int behind)
536{
537	int width = image->width;
538	int height = image->height;
539	
540	x0 += rotating_image->oz * mirai_cosine[y_angle] / 256;
541	
542	if (behind != 0) y_angle += 128;
543	
544	for (int x = 0 ; x < width ; x++)
545	for (int y = 0 ; y < height ; y++)
546	{
547		if (behind != 0 && image->colors[x + y * width] != 0) continue;
548		
549		int x1 = x - x0;
550		int y1 = y - y0;
551		
552		int x2 = x1 + y1 * mirai_sine[z_angle] / 127;
553		
554		if (behind != 0) x2 = -x2 - 1;
555		
556		unsigned char color = mirai_rotating_image_pixel(rotating_image, y_angle, x2, y1);
557		if (color == 0) continue;
558		
559		image->colors[x + y * width] = color;
560	}
561}
562
563static void mirai_animation_layer(struct mirai_image *image, struct mirai_model_layer *layer, unsigned char y_angle, unsigned char z_angle, int x0, int y0)
564{
565	for (int i = 0 ; i < layer->count ; i++)
566	{
567		mirai_rotating_image_stamp(image, layer->images[i], y_angle, z_angle, x0, y0, 0);
568		mirai_rotating_image_stamp(image, layer->images[i], y_angle, z_angle, x0, y0, 1);
569	}
570}
571
572static void mirai_animation_frame(struct mirai_image *image, unsigned char **colors, struct mirai_model *model, unsigned char y_angle, unsigned char z_angle, unsigned char arm_angle)
573{
574	image->colors = *colors;
575	image->width = 26;
576	image->height = 36;
577	
578	*colors += image->width * image->height;
579	
580	for (int x = 0 ; x < image->width ; x++)
581	for (int y = 0 ; y < image->height ; y++)
582		image->colors[x + y * image->width] = 0;
583	
584	int x = image->width / 2;
585	
586	int head_y = 13;
587	int head_x = x + mirai_sine[z_angle] * (image->height - head_y) / 127;
588	
589	int arm_y = 16;
590	int arm_x = x + mirai_sine[z_angle] * (image->height - arm_y) / 127;
591	int left_arm_x = arm_x + 10 * mirai_sine[y_angle] / 256;
592	int right_arm_x = arm_x - 10 * mirai_sine[y_angle] / 256;
593	
594	int leg_y = 24;
595	int leg_x = x + mirai_sine[z_angle] * (image->height - leg_y) / 127;
596	int left_leg_x = leg_x + 6 * mirai_sine[y_angle] / 256;
597	int right_leg_x = leg_x - 6 * mirai_sine[y_angle] / 256;
598	
599	int torso_y = 24;
600	int torso_x = x + mirai_sine[z_angle] * (image->height - torso_y) / 127;
601	
602	mirai_animation_layer(image, model->left_leg, y_angle, -arm_angle, left_leg_x, leg_y);
603	mirai_animation_layer(image, model->right_leg, y_angle, arm_angle, right_leg_x, leg_y);
604	if ((y_angle + 64) % 256 < 128)
605	{
606		mirai_animation_layer(image, model->left_arm, y_angle, arm_angle, left_arm_x, arm_y);
607		mirai_animation_layer(image, model->torso, y_angle, z_angle, torso_x, torso_y);
608		mirai_animation_layer(image, model->right_arm, y_angle, -arm_angle, right_arm_x, arm_y);
609	}
610	else
611	{
612		mirai_animation_layer(image, model->right_arm, y_angle, -arm_angle, right_arm_x, arm_y);
613		mirai_animation_layer(image, model->torso, y_angle, z_angle, torso_x, torso_y);
614		mirai_animation_layer(image, model->left_arm, y_angle, arm_angle, left_arm_x, arm_y);
615	}
616	mirai_animation_layer(image, model->head, y_angle, 0, head_x, head_y);
617}
618
619static void mirai_animation(struct mirai_animation *animation, struct mirai_image **images, unsigned char **colors, struct mirai_model *model, int count, unsigned char y_angle, unsigned char z_angle, unsigned char arm_angle)
620{
621	animation->count = count;
622	animation->images = *images;
623	
624	for (int i = 0 ; i < count ; i++)
625		mirai_animation_frame((*images)++, colors, model, y_angle, z_angle, arm_angle * mirai_sine[i * 255 / count] / 127);
626}
627
628static void mirai_animation_set(struct mirai_animation **animations, struct mirai_image **images, unsigned char **colors, struct mirai_model *model, int coefficient, int count, int count2, unsigned char z_angle, unsigned char arm_angle)
629{
630	for (int i = 0 ; i < count ; i++)
631		mirai_animation((*animations)++, images, colors, model, count2, 64 + (12 + 34 * i / count) * coefficient, -z_angle * i / count * coefficient, arm_angle * i / count);
632}
633
634
635// adapted from https://rosettacode.org/wiki/Matrix_transposition#C
636static void mirai_transpose_image(struct mirai_image *image)
637{
638	int width = image->width;
639	int height = image->height;
640	image->width = height;
641	image->height = width;
642	
643	for (int start = 0 ; start < width * height ; start++)
644	{
645		int next = start;
646		int i = 0;
647		for (;;)
648		{
649			i++;
650			next = (next % height) * width + next / height;
651			if (next <= start) break;
652		}
653		
654		if (i == 1) continue;
655		if (next < start) continue;
656		
657		char tmp = image->colors[next = start];
658		for (;;)
659		{
660			int i = (next % height) * width + next / height;
661			image->colors[next] = (i == start) ? tmp : image->colors[i];
662			next = i;
663			if (next <= start) break;
664		}
665	}
666}
667
668static void mirai_flip_image(struct mirai_image *image)
669{
670	for (int x = 0 ; x < image->width / 2 ; x++)
671	for (int y = 0 ; y < image->height ; y++)
672	{
673		unsigned char color = image->colors[image->width - x - 1 + y * image->width];
674		image->colors[image->width - x - 1 + y * image->width] = image->colors[x + y * image->width];
675		image->colors[x + y * image->width] = color;
676	}
677}
678
679static void mirai_rotate_image_cw(struct mirai_image *image)
680{
681	mirai_transpose_image(image);
682	mirai_flip_image(image);
683}
684
685static void mirai_rotate_image_ccw(struct mirai_image *image)
686{
687	mirai_flip_image(image);
688	mirai_transpose_image(image);
689}
690
691static void mirai_model(struct mirai_sprite_type *type, struct mirai_model *model, struct mirai_animation **animations, struct mirai_image **images, unsigned char **colors, int count, int count2, unsigned char z_angle, unsigned char arm_angle, unsigned char arm_flail_angle)
692{
693	type->animations.left.standing = *animations;
694	type->animations.left.count = 4;
695	mirai_animation_set(animations, images, colors, model, 1, count, count2, z_angle, arm_angle);
696	
697	type->animations.right.standing = *animations;
698	type->animations.right.count = 4;
699	mirai_animation_set(animations, images, colors, model, -1, count, count2, z_angle, arm_angle);
700	
701	struct mirai_image *rotated_cw = *images;
702	mirai_animation(&type->animations.left.knocked, images, colors, model, count2, 64 + 16, 0, arm_flail_angle);
703	while (rotated_cw != *images) mirai_rotate_image_cw(rotated_cw++);
704
705	struct mirai_image *rotated_ccw = *images;
706	mirai_animation(&type->animations.right.knocked, images, colors, model, count2, 64 - 16, 0, arm_flail_angle);
707	while (rotated_ccw != *images) mirai_rotate_image_ccw(rotated_ccw++);
708}
709
710
711// constant exports
712
713int mirai_game_size = sizeof (struct mirai_game);
714int mirai_width = 512;
715int mirai_height = 256;
716
717
718// function exports
719
720void mirai_start(struct mirai_game *game, struct mirai_engine *engine)
721{
722	game->engine = *engine;
723	
724	game->left_history = 0;
725	game->right_history = 0;
726	game->sprite_count = 0;
727	
728	mirai_assets();
729	
730	struct mirai_sprite *player = game->sprites + game->sprite_count;
731	mirai_spawn(game, 11776, 5248, &mirai_mirai, &mirai_controls);
732	game->camera_sprite = player;
733	game->camera_x = player->x;
734	game->camera_y = player->y - 512;
735	
736	struct mirai_sprite *ryoubi = game->sprites + game->sprite_count;
737	mirai_spawn(game, 10000, 5120, &mirai_ryoubi, &mirai_stationary_ai);
738	ryoubi->ai_target = player;
739	
740	struct mirai_sprite *ryouna = game->sprites + game->sprite_count;
741	mirai_spawn(game, 11000, 5376, &mirai_ryouna, &mirai_stationary_ai);
742	ryouna->ai_target = player;
743}
744
745void mirai_step(struct mirai_game *game, struct mirai_keys keys)
746{
747	game->left_history <<= 1;
748	game->left_history |= keys.left;
749	game->right_history <<= 1;
750	game->right_history |= keys.right;
751	
752	game->camera_x *= 3;
753	game->camera_y *= 3;
754	game->camera_x += game->camera_sprite->x;
755	game->camera_y += game->camera_sprite->y - 512;
756	game->camera_x /= 4;
757	game->camera_y /= 4;
758	
759	for (int x0 = -16 ; x0 <= 16 ; x0++)
760	for (int y0 = -8 ; y0 <= 8 ; y0++)
761	{
762		int x = x0 + game->camera_x / 128;
763		int y = y0 + game->camera_y / 128;
764		if (mirai_ground[y][x] != 0)
765			mirai_stamp(game, x * 128 + 64, y * 128 + 128, mirai_images + mirai_ground[y][x]);
766	}
767	
768	for (int i = 0 ; i < game->sprite_count ; i++)
769	{
770		struct mirai_sprite *sprite = game->sprites + i;
771		
772		if (sprite->dy > 128)
773		if (sprite->knocked_time < 64)
774			sprite->knocked_time = 64;
775		
776		if (sprite->knocked_time != 0)
777		{
778			sprite->knocked_time--;
779			sprite->immunity_time = 64;
780		}
781		
782		if (sprite->immunity_time != 0)
783		{
784			sprite->pristinity = -1;
785			sprite->immunity_time--;
786		}
787		
788		if (sprite->pristinity != 0xFF)
789			sprite->pristinity++;
790		
791		if (sprite->ai_attack_time != 0)
792			sprite->ai_attack_time--;
793		
794		sprite->ax = 0;
795		if (sprite->knocked_time == 0)
796		{
797			(*sprite->behave)(game, sprite);
798			
799			if (sprite->moving_direction != 0)
800				sprite->facing_direction = sprite->moving_direction;
801			
802			if (sprite->airborne)
803			{
804				if (sprite->moving_direction == 1)
805					sprite->ax = -3;
806				if (sprite->moving_direction == 2)
807					sprite->ax = 3;
808			}
809			else
810			{
811				if (sprite->moving_direction == 1)
812					sprite->ax = -4;
813				if (sprite->moving_direction == 2)
814					sprite->ax = 4;
815			}
816		}
817		
818		if (sprite->airborne == 0)
819			mirai_ground_physics(sprite);
820		else
821			mirai_airborne_physics(sprite);
822		
823		int dx;
824		int dy = sprite->dy;
825		
826		struct mirai_direction_animation_set *animations;
827		
828		if (sprite->facing_direction == 1)
829		{
830			dx = -sprite->dx;
831			animations = &sprite->type->animations.left;
832		}
833		if (sprite->facing_direction == 2)
834		{
835			dx = sprite->dx;
836			animations = &sprite->type->animations.right;
837		}
838		
839		struct mirai_animation *animation;
840		
841		if (dx > 32) dx = 32;
842		if (dx < 0) dx = 0;
843		if (dy < 0) dy = 0;
844		
845		if (sprite->knocked_time == 0)
846		{
847			animation = animations->standing + dx * (animations->count - 1) / 32;
848			sprite->animation_time += dx / 4;
849		}
850		else
851		{
852			animation = &animations->knocked;
853			if (dy == 0) sprite->animation_time = 0;
854			else sprite->animation_time += dy / 8;
855		}
856		
857		struct mirai_image *image = animation->images + sprite->animation_time * (animation->count - 1) / 256;
858		int y = 0;
859		if (sprite->knocked_time != 0) y = image->height * 4 - 56;
860		
861		mirai_stamp(game, sprite->x, sprite->y + y, image);
862	}
863	
864	mirai_text(game, 16, 16, "Mirai's Miscellaneous Misadventures M16");
865	mirai_text(game, 16, 32, "a Senran Kagura fangame by zamfofex");
866	mirai_text(game, 16, 48, "January 19 2022");
867}
868
869struct mirai_image *mirai_assets(void)
870{
871	static char done = 0;
872	if (done != 0) return mirai_images;
873	
874	int color_count = sizeof mirai_colors / sizeof *mirai_colors;
875	unsigned char *last_color = mirai_colors + color_count - 1;
876	
877	int image_count = sizeof mirai_images / sizeof *mirai_images;
878	struct mirai_image *last_image = mirai_images + image_count - 1;
879	
880	int animation_count = sizeof mirai_animations / sizeof *mirai_animations;
881	struct mirai_animation *last_animation = mirai_animations + animation_count - 1;
882	
883	last_image->width = 0;
884	last_image->height = 0;
885	
886	static unsigned char ground_colors[sizeof mirai_ground_colors / sizeof *mirai_ground_colors] = {0x00, 0x3B, 0x1C, 0x21, 0x82, 0x56, 0x43, 0x25};
887	
888	for (int i = 0 ; i < sizeof ground_colors ; i++)
889	{
890		struct mirai_image image = {16, 16, mirai_ground_colors[i]};
891		mirai_images[i] = image;
892		for (int j = 0 ; j < 256 ; j++)
893			mirai_ground_colors[i][j] = ground_colors[i];
894	}
895	
896	unsigned char *colors = mirai_colors;
897	struct mirai_image *images = mirai_images + sizeof ground_colors;
898	struct mirai_animation *animations = mirai_animations;
899	
900	mirai_model(&mirai_mirai, &mirai_mirai_yang, &animations, &images, &colors, 4, 8, 9, 16, 32);
901	
902	mirai_model(&mirai_ryoubi, &mirai_ryoubi_flash, &animations, &images, &colors, 4, 8, 9, 16, 32);
903	mirai_model(&mirai_ryouna, &mirai_ryouna_flash, &animations, &images, &colors, 4, 8, 9, 16, 32);
904	
905	for (int i = 0 ; i < 10 ; i++)
906	{
907		mirai_glyphs[i] = images;
908		images->colors = colors;
909		images->height = 15;
910		
911		for (int x = 1 ; x < 12 ; x++)
912		{
913			int done = 1;
914			for (int y = 0 ; y < images->height ; y++)
915			{
916				if (mirai_digits[i][y][x] != 0)
917				{
918					done = 0;
919					break;
920				}
921			}
922			if (done == 0) continue;
923			images->width = x + 1;
924			break;
925		}
926		
927		for (int y = 0 ; y < images->height ; y++)
928		for (int x = 0 ; x < images->width ; x++)
929			*colors++ = mirai_digits[i][y][x] == 0 ? 0 : 0x6C;
930		
931		images++;
932	}
933	
934	for (int c = 0 ; c < 2 ; c++)
935	for (int i = 0 ; i < 26 ; i++)
936	{
937		mirai_glyphs[i + 26 * c + 10] = images;
938		images->colors = colors;
939		images->height = 15;
940		
941		for (int x = 1 ; x < 12 ; x++)
942		{
943			int done = 1;
944			for (int y = 0 ; y < images->height ; y++)
945			{
946				if (mirai_letters[i][y * 2 + c][x] != 0)
947				{
948					done = 0;
949					break;
950				}
951			}
952			if (done == 0) continue;
953			images->width = x + 1;
954			break;
955		}
956		
957		for (int y = 0 ; y < images->height ; y++)
958		for (int x = 0 ; x < images->width ; x++)
959			*colors++ = mirai_letters[i][y * 2 + c][x] == 0 ? 0 : 0x6C;
960		
961		images++;
962	}
963	
964	if (colors != last_color) return 0;
965	if (images != last_image - 1) return 0;
966	if (animations != last_animation) return 0;
967	
968	done = 1;
969	return mirai_images;
970}