Mirai's Miscellaneous Misadventures

M13 / game.c

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