Mirai's Miscellaneous Misadventures
M2 / game.c
1#include "game.h"
2
3
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
18 int dx, dy;
19
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
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
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
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
274
275int mirai_game_size = sizeof (struct mirai_game);
276int mirai_width = 512;
277int mirai_height = 256;
278
279
280
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}