Mirai's Miscellaneous Misadventures

M6 / game.c

1#include "game.h"
2#include "math.c"
3
4// types
5
6struct mirai_sprite_type
7{
8	int image_count;
9	struct mirai_image *images;
10	int radius;
11	int height;
12};
13
14struct mirai_sprite
15{
16	struct mirai_sprite_type *type;
17	
18	int x, y;
19	// speed
20	int dx, dy;
21	// acceleration
22	int ax;
23	
24	char airborne;
25	char moving_direction;
26	
27	int attack_y;
28	int attack_width;
29	int attack_height;
30	int attack_time;
31	
32	void (*behave)(struct mirai_game *game, struct mirai_sprite *sprite);
33};
34
35struct mirai_rotating_image_row
36{
37	int size;
38	unsigned char count;
39	unsigned char colors[256];
40};
41
42struct mirai_rotating_image
43{
44	int count;
45	struct mirai_rotating_image_row rows[];
46};
47
48
49// constants
50
51#include "assets.c"
52
53static int mirai_gravity = 4;
54
55static unsigned char mirai_ground_colors[256];
56
57static unsigned char mirai_mirai_colors[256][936];
58
59static struct mirai_image mirai_images[258] =
60{
61	{16, 16, mirai_ground_colors},
62};
63
64static struct mirai_image *mirai_ground_image = mirai_images;
65
66static struct mirai_sprite_type mirai_mirai = {256, mirai_images + 1, 40, 544};
67
68
69// state
70
71struct mirai_game
72{
73	struct mirai_engine engine;
74	struct mirai_sprite sprites[256];
75	unsigned char sprite_count;
76	
77	unsigned int left_history:16;
78	unsigned int right_history:16;
79	
80	struct mirai_sprite *camera_sprite;
81	int camera_x;
82	int camera_y;
83	
84	struct mirai_image *images;
85};
86
87
88// functions
89
90static void mirai_stamp(struct mirai_game *game, int x, int y, struct mirai_image *image)
91{
92	x -= game->camera_x;
93	x += mirai_width * 4;
94	y -= game->camera_y;
95	y += mirai_height * 4;
96	(*game->engine.stamp)(game->engine.data, x / 8, y / 8, image);
97}
98
99static void mirai_physics(struct mirai_sprite *sprite)
100{
101	sprite->dx += sprite->ax;
102	sprite->x += sprite->dx;
103	sprite->y += sprite->dy;
104	
105	int x0 = sprite->x;
106	int x1 = sprite->type->radius;
107	int y0 = sprite->y;
108	int y1 = sprite->type->height;
109	
110	if (mirai_ground[(x0 + x1) / 128][(y0 - 127) / 128] != 0)
111	{
112		if (mirai_ground[(x0 + x1) / 128][(y0 - y1 / 2) / 128] == 0)
113		{
114			sprite->y = (y0 / 128 - 1) * 128;
115		}
116		else
117		{
118			sprite->dx = 0;
119			sprite->x = (x0 + x1) / 128 * 128 - x1;
120		}
121	}
122	if (mirai_ground[(x0 - x1) / 128][(y0 - 127) / 128] != 0)
123	{
124		if (mirai_ground[(x0 - x1) / 128][(y0 - y1 / 2) / 128] == 0)
125		{
126			sprite->y = (y0 / 128 - 1) * 128;
127		}
128		else
129		{
130			sprite->dx = 0;
131			sprite->x = ((x0 - x1) / 128 + 1) * 128 + x1;
132		}
133	}
134	
135	x0 = sprite->x;
136	y0 = sprite->y;
137	
138	if (mirai_ground[(x0 - x1) / 128][y0 / 128] != 0 || mirai_ground[(x0 + x1 - 1) / 128][y0 / 128] != 0)
139	{
140		sprite->y = y0 / 128 * 128;
141		sprite->dy = 0;
142		sprite->airborne = 0;
143	}
144	else if (!sprite->airborne)
145	{
146		if (mirai_ground[x0 / 128][y0 / 128 + 1] == 0)
147			sprite->airborne = 1;
148		else
149			sprite->y = (y0 / 128 + 1) * 128;
150	}
151}
152
153static void mirai_ground_physics(struct mirai_sprite *sprite)
154{
155	sprite->dx *= 7;
156	sprite->dx /= 8;
157	sprite->dy = 0;
158	mirai_physics(sprite);
159}
160
161static void mirai_airborne_physics(struct mirai_sprite *sprite)
162{
163	sprite->dx *= 15;
164	sprite->dx /= 16;
165	sprite->dy += mirai_gravity;
166	mirai_physics(sprite);
167}
168
169static void mirai_jump(struct mirai_sprite *sprite)
170{
171	if (sprite->airborne) return;
172	sprite->airborne = 1;
173	sprite->dy = -64;
174}
175
176static void mirai_damage(struct mirai_game *game, struct mirai_sprite *sprite)
177{
178	struct mirai_image area = {sprite->attack_width / 16, sprite->attack_height / 8};
179	int x = sprite->x + sprite->attack_width / 4;
180	int y = (sprite->y + sprite->attack_y);
181	
182	if (sprite->moving_direction == 1) x -= sprite->attack_width / 2;
183	
184	// mirai_stamp(game, x, y, &area);
185}
186
187static void mirai_attack(struct mirai_game *game, struct mirai_sprite *sprite)
188{
189	sprite->attack_y = -16;
190	sprite->attack_width = 512;
191	sprite->attack_height = 256;
192	mirai_damage(game, sprite);
193}
194
195static void mirai_rapid_attack(struct mirai_game *game, struct mirai_sprite *sprite)
196{
197	sprite->attack_y = -128;
198	sprite->attack_width = sprite->attack_time * 16 + 64;
199	sprite->attack_height = 64;
200	if (sprite->attack_time != 0x7F) sprite->attack_time++;
201	mirai_damage(game, sprite);
202}
203
204static unsigned char mirai_count_oscillations(unsigned int history)
205{
206	unsigned char count = 0;
207	unsigned char prev = history&1;
208	for (int i = 0 ; i < 16 ; i++)
209	{
210		if ((history&1) != prev) count++;
211		prev = history&1;
212		history >>= 1;
213	}
214	return count;
215}
216
217static void mirai_controls(struct mirai_game *game, struct mirai_sprite *sprite)
218{
219	unsigned char left_oscillations = mirai_count_oscillations(game->left_history);
220	unsigned char right_oscillations = mirai_count_oscillations(game->right_history);
221	
222	switch (sprite->moving_direction)
223	{
224	case 0:
225		if ((game->left_history&1) != 0)
226			sprite->moving_direction = 1;
227		if ((game->right_history&1) != 0)
228			sprite->moving_direction = 2;
229		break;
230	case 1:
231		if ((game->left_history&1) == 0)
232			sprite->moving_direction = 0;
233		else if (left_oscillations > 1)
234			mirai_jump(sprite);
235		if ((game->right_history&1) != 0)
236		{
237			if (right_oscillations == 0)
238				mirai_rapid_attack(game, sprite);
239			else
240				sprite->attack_time = 0;
241		}
242		if ((game->right_history&1) != 0 && (game->right_history&2) == 0)
243			mirai_attack(game, sprite);
244		break;
245	case 2:
246		if ((game->right_history&1) == 0)
247			sprite->moving_direction = 0;
248		else if (right_oscillations > 1)
249			mirai_jump(sprite);
250		if ((game->left_history&1) != 0)
251		{
252			if (left_oscillations == 0)
253				mirai_rapid_attack(game, sprite);
254			else
255				sprite->attack_time = 0;
256		}
257		if ((game->left_history&1) != 0 && (game->left_history&2) == 0)
258			mirai_attack(game, sprite);
259		break;
260	}
261}
262
263static 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))
264{
265	if (game->sprite_count == 0xFF) return;
266	struct mirai_sprite *sprite = game->sprites + game->sprite_count;
267	game->sprite_count++;
268	sprite->type = type;
269	sprite->x = x;
270	sprite->y = y;
271	sprite->dx = 0;
272	sprite->dy = 0;
273	sprite->ax = 0;
274	sprite->airborne = 1;
275	sprite->moving_direction = 0;
276	sprite->attack_time = 0;
277	sprite->behave = behave;
278}
279
280static void mirai_image_rotation(struct mirai_image *image, struct mirai_rotating_image *rotating_image, unsigned char angle, int x0, int y0, char flip)
281{
282	if (flip != 0) angle = 0x100 - angle;
283	
284	int width = image->width;
285	int height = image->height;
286	
287	for (int y = 0 ; y < rotating_image->count ; y++)
288	for (int x = 0 ; x < rotating_image->rows[y].size ; x++)
289	{
290		int size = rotating_image->rows[y].size;
291		int count = rotating_image->rows[y].count;
292		
293		unsigned int a = angle;
294		a *= count;
295		a--;
296		a /= 256;
297		a++;
298		a += x;
299		a %= count;
300		
301		if (flip) a = count - a - 1;
302		
303		int x1 = x + x0 + (width - size) / 2;
304		int y1 = y - y0 + height - rotating_image->count;
305		
306		unsigned char color = rotating_image->rows[y].colors[a];
307		if (color == 0) continue;
308		
309		image->colors[x1 + y1 * width] = color;
310	}
311}
312
313
314// constant exports
315
316int mirai_game_size = sizeof (struct mirai_game);
317int mirai_width = 512;
318int mirai_height = 256;
319
320
321// function exports
322
323void mirai_start(struct mirai_game *game, struct mirai_engine *engine)
324{
325	game->engine = *engine;
326	game->engine.stamp = engine->stamp;
327	
328	game->left_history = 0;
329	game->right_history = 0;
330	game->sprite_count = 0;
331	
332	mirai_spawn(game, 500, 1500, &mirai_mirai, &mirai_controls);
333	
334	game->camera_x = 500;
335	game->camera_y = 1500;
336	game->camera_sprite = game->sprites;
337	
338	game->images = mirai_assets();
339}
340
341void mirai_step(struct mirai_game *game, struct mirai_keys keys)
342{
343	game->left_history <<= 1;
344	game->left_history |= keys.left;
345	game->right_history <<= 1;
346	game->right_history |= keys.right;
347	
348	game->camera_x *= 3;
349	game->camera_y *= 3;
350	game->camera_x += game->camera_sprite->x;
351	game->camera_y += game->camera_sprite->y - 512;
352	game->camera_x /= 4;
353	game->camera_y /= 4;
354	
355	for (int i = 0 ; i < sizeof mirai_ground / sizeof *mirai_ground ; i++)
356	for (int j = 0 ; j < sizeof *mirai_ground / sizeof **mirai_ground ; j++)
357	{
358		if (mirai_ground[i][j])
359			mirai_stamp(game, i * 128 + 64, j * 128 + 128, mirai_ground_image);
360	}
361	
362	for (int i = 0 ; i < game->sprite_count ; i++)
363	{
364		struct mirai_sprite *sprite = game->sprites + i;
365		
366		if (game->sprites->airborne == 0)
367			mirai_ground_physics(sprite);
368		else
369			mirai_airborne_physics(sprite);
370		
371		(*sprite->behave)(game, sprite);
372		
373		game->sprites[i].ax = 0;
374		if (sprite->airborne)
375		{
376			if (sprite->moving_direction == 1)
377				sprite->ax = -3;
378			if (sprite->moving_direction == 2)
379				sprite->ax = 3;
380		}
381		else
382		{
383			if (sprite->moving_direction == 1)
384				sprite->ax = -4;
385			if (sprite->moving_direction == 2)
386				sprite->ax = 4;
387		}
388		
389		int image = 64;
390		if (sprite->moving_direction == 1)
391			image += 32;
392		if (sprite->moving_direction == 2)
393			image -= 32;
394		
395		mirai_stamp(game, sprite->x, sprite->y, sprite->type->images + image);
396	}
397}
398
399struct mirai_image *mirai_assets(void)
400{
401	static char done = 0;
402	if (done != 0) return mirai_images;
403	
404	mirai_images[257].width = 0;
405	mirai_images[257].height = 0;
406	
407	for (int i = 0 ; i < 256 ; i++)
408		mirai_ground_colors[i] = 0x3B;
409	
410	for (int i = 0 ; i < 256 ; i++)
411	{
412		struct mirai_image *image = mirai_images + i + 1;
413		image->width = 24;
414		image->height = 36;
415		image->colors = mirai_mirai_colors[i];
416		
417		for (int x = 0 ; x < 24 ; x++)
418		for (int y = 0 ; y < 36 ; y++)
419			image->colors[x + y * 24] = 0;
420		
421		int x = mirai_sine[i];
422		x *= 5;
423		x /= 128;
424		
425		mirai_image_rotation(image, &mirai_mirai_hair, i, 0, 7, 1);
426		if ((i + 64) % 256 < 128)
427		{
428			mirai_image_rotation(image, &mirai_mirai_left_arm, i, x, 10, 0);
429			mirai_image_rotation(image, &mirai_mirai_torso, i, 0, 0, 0);
430			mirai_image_rotation(image, &mirai_mirai_right_arm, i, -x, 10, 0);
431		}
432		else
433		{
434			mirai_image_rotation(image, &mirai_mirai_right_arm, i, -x, 10, 0);
435			mirai_image_rotation(image, &mirai_mirai_torso, i, 0, 0, 0);
436			mirai_image_rotation(image, &mirai_mirai_left_arm, i, x, 10, 0);
437		}
438		mirai_image_rotation(image, &mirai_mirai_hair, i, 0, 7, 0);
439		
440	}
441	
442	done = 1;
443	return mirai_images;
444}