Mirai's Miscellaneous Misadventures
M6 / game.c
1#include "game.h"
2#include "math.c"
3
4
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
20 int dx, dy;
21
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
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
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
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
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
315
316int mirai_game_size = sizeof (struct mirai_game);
317int mirai_width = 512;
318int mirai_height = 256;
319
320
321
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}