Mirai's Miscellaneous Misadventures

M2 / game.c

1#include "game.h"
2
3// types
4
5struct mirai_sprite_type
6{
7	struct mirai_image *image;
8	int radius;
9	int height;
10};
11
12struct mirai_sprite
13{
14	struct mirai_sprite_type *type;
15	
16	int x, y;
17	// speed
18	int dx, dy;
19	// acceleration
20	int ax;
21	
22	char airborne;
23	char moving_direction;
24	
25	int attack_y;
26	int attack_width;
27	int attack_height;
28	int attack_time;
29	
30	void (*behave)(struct mirai_game *game, struct mirai_sprite *sprite);
31};
32
33
34// constants
35
36static int mirai_gravity = 4;
37
38static struct mirai_image mirai_mirai_image = {20, 34};
39static struct mirai_image mirai_ground_image = {16, 16};
40static struct mirai_sprite_type mirai_mirai = {&mirai_mirai_image, 80, 544};
41
42static char mirai_ground[][20] =
43{
44	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
45	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
46	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
47	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
48	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
49	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
50	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
51	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
52	{0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
53	{0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
54	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
55	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
56	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
57	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
58	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
59	{0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
60	{0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
61	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
62	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
63	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
64	{0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
65	{0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
66	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
67	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1},
68	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1},
69	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1},
70	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1},
71	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1},
72	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1},
73	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
74	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1},
75	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
76};
77
78
79// state
80
81struct mirai_game
82{
83	struct mirai_engine engine;
84	struct mirai_sprite sprites[256];
85	unsigned char sprite_count;
86	
87	unsigned int left_history:16;
88	unsigned int right_history:16;
89};
90
91
92// functions
93
94static void mirai_physics(struct mirai_sprite *sprite)
95{
96	sprite->dx += sprite->ax;
97	sprite->x += sprite->dx;
98	sprite->y += sprite->dy;
99	
100	int x0 = sprite->x;
101	int x1 = sprite->type->radius;
102	int y0 = sprite->y;
103	int y1 = sprite->type->height;
104	
105	if (mirai_ground[(x0 + x1) / 128][(y0 - 127) / 128] != 0)
106	{
107		if (mirai_ground[(x0 + x1) / 128][(y0 - y1 / 2) / 128] == 0)
108		{
109			sprite->y = (y0 / 128 - 1) * 128;
110		}
111		else
112		{
113			sprite->dx = 0;
114			sprite->x = (x0 + x1) / 128 * 128 - x1;
115		}
116	}
117	if (mirai_ground[(x0 - x1) / 128][(y0 - 127) / 128] != 0)
118	{
119		if (mirai_ground[(x0 - x1) / 128][(y0 - y1 / 2) / 128] == 0)
120		{
121			sprite->y = (y0 / 128 - 1) * 128;
122		}
123		else
124		{
125			sprite->dx = 0;
126			sprite->x = ((x0 - x1) / 128 + 1) * 128 + x1;
127		}
128	}
129	
130	x0 = sprite->x;
131	y0 = sprite->y;
132	
133	if (mirai_ground[(x0 - x1) / 128][y0 / 128] != 0 || mirai_ground[(x0 + x1 - 1) / 128][y0 / 128] != 0)
134	{
135		sprite->y = y0 / 128 * 128;
136		sprite->dy = 0;
137		sprite->airborne = 0;
138	}
139	else if (!sprite->airborne)
140	{
141		if (mirai_ground[x0 / 128][y0 / 128 + 1] == 0)
142			sprite->airborne = 1;
143		else
144			sprite->y = (y0 / 128 + 1) * 128;
145	}
146}
147
148static void mirai_ground_physics(struct mirai_sprite *sprite)
149{
150	sprite->dx *= 1;
151	sprite->dx /= 2;
152	sprite->dy = 0;
153	mirai_physics(sprite);
154}
155
156static void mirai_airborne_physics(struct mirai_sprite *sprite)
157{
158	sprite->dx *= 3;
159	sprite->dx /= 4;
160	sprite->dy += mirai_gravity;
161	mirai_physics(sprite);
162}
163
164static void mirai_jump(struct mirai_sprite *sprite)
165{
166	if (sprite->airborne) return;
167	sprite->airborne = 1;
168	sprite->dy = -64;
169}
170
171static void mirai_damage(struct mirai_game *game, struct mirai_sprite *sprite)
172{
173	struct mirai_image area = {sprite->attack_width / 16, sprite->attack_height / 8};
174	int x = sprite->x / 8 + sprite->attack_width / 32;
175	int y = (sprite->y + sprite->attack_y) / 8;
176	
177	if (sprite->moving_direction == 1) x -= sprite->attack_width / 16;
178	
179	(*game->engine.stamp)(game->engine.data, x, y, &area);
180}
181
182static void mirai_attack(struct mirai_game *game, struct mirai_sprite *sprite)
183{
184	sprite->attack_y = -16;
185	sprite->attack_width = 512;
186	sprite->attack_height = 256;
187	mirai_damage(game, sprite);
188}
189
190static void mirai_rapid_attack(struct mirai_game *game, struct mirai_sprite *sprite)
191{
192	sprite->attack_y = -128;
193	sprite->attack_width = sprite->attack_time * 16 + 64;
194	sprite->attack_height = 64;
195	if (sprite->attack_time != 0x7F) sprite->attack_time++;
196	mirai_damage(game, sprite);
197}
198
199static unsigned char mirai_count_oscillations(unsigned int history)
200{
201	unsigned char count = 0;
202	unsigned char prev = history&1;
203	for (int i = 0 ; i < 16 ; i++)
204	{
205		if ((history&1) != prev) count++;
206		prev = history&1;
207		history >>= 1;
208	}
209	return count;
210}
211
212static void mirai_controls(struct mirai_game *game, struct mirai_sprite *sprite)
213{
214	unsigned char left_oscillations = mirai_count_oscillations(game->left_history);
215	unsigned char right_oscillations = mirai_count_oscillations(game->right_history);
216	
217	switch (sprite->moving_direction)
218	{
219	case 0:
220		if (left_oscillations > 0 || game->left_history != 0)
221			sprite->moving_direction = 1;
222		if (right_oscillations > 0)
223			sprite->moving_direction = 2;
224		else if (game->right_history != 0)
225			sprite->moving_direction = 2;
226		break;
227	case 1:
228		if ((game->left_history&1) == 0)
229			sprite->moving_direction = 0;
230		else if (left_oscillations > 1)
231			mirai_jump(sprite);
232		if ((game->right_history&1) != 0)
233			if (right_oscillations == 0)
234				mirai_rapid_attack(game, sprite);
235			else
236				sprite->attack_time = 0;
237		if ((game->right_history&1) != 0 && (game->right_history&2) == 0)
238			mirai_attack(game, sprite);
239		break;
240	case 2:
241		if ((game->right_history&1) == 0)
242			sprite->moving_direction = 0;
243		else if (right_oscillations > 1)
244			mirai_jump(sprite);
245		if ((game->left_history&1) != 0)
246			if (left_oscillations == 0)
247				mirai_rapid_attack(game, sprite);
248			else
249				sprite->attack_time = 0;
250		if ((game->left_history&1) != 0 && (game->left_history&2) == 0)
251			mirai_attack(game, sprite);
252		break;
253	}
254}
255
256static 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))
257{
258	struct mirai_sprite *sprite = game->sprites + game->sprite_count;
259	game->sprite_count++;
260	sprite->type = type;
261	sprite->x = x;
262	sprite->y = y;
263	sprite->dx = 0;
264	sprite->dy = 0;
265	sprite->ax = 0;
266	sprite->airborne = 1;
267	sprite->moving_direction = 0;
268	sprite->attack_time = 0;
269	sprite->behave = behave;
270}
271
272
273// constant exports
274
275int mirai_game_size = sizeof (struct mirai_game);
276int mirai_width = 512;
277int mirai_height = 256;
278
279
280// function exports
281
282void mirai_start(struct mirai_game *game, struct mirai_engine *engine)
283{
284	game->engine = *engine;
285	
286	game->left_history = 0;
287	game->right_history = 0;
288	game->sprite_count = 0;
289	
290	mirai_spawn(game, 500, 1500, &mirai_mirai, &mirai_controls);
291}
292
293void mirai_step(struct mirai_game *game, struct mirai_keys keys)
294{
295	game->left_history <<= 1;
296	game->left_history |= keys.left;
297	game->right_history <<= 1;
298	game->right_history |= keys.right;
299	
300	for (int i = 0 ; i < sizeof mirai_ground / sizeof *mirai_ground ; i++)
301	for (int j = 0 ; j < sizeof *mirai_ground / sizeof **mirai_ground ; j++)
302	{
303		if (mirai_ground[i][j])
304		{
305			(*game->engine.stamp)(game->engine.data, i * 16 + 8, j * 16 + 16, &mirai_ground_image);
306		}
307	}
308	
309	for (int i = 0 ; i < game->sprite_count ; i++)
310	{
311		struct mirai_sprite *sprite = game->sprites + i;
312		
313		if (game->sprites->airborne == 0)
314			mirai_ground_physics(sprite);
315		else
316			mirai_airborne_physics(sprite);
317		
318		(*sprite->behave)(game, sprite);
319		
320		game->sprites[i].ax = 0;
321		if (sprite->moving_direction == 1)
322			sprite->ax = -8;
323		if (sprite->moving_direction == 2)
324			sprite->ax = 8;
325		
326		(*game->engine.stamp)(game->engine.data, sprite->x / 8, sprite->y / 8, sprite->type->image);
327	}
328}