Browse Source

add continue / save-game feature

Thomas B 2 weeks ago
parent
commit
bc8b857641
16 changed files with 420 additions and 379 deletions
  1. BIN
      data/sfx_damage.wav
  2. BIN
      data/sfx_heal.wav
  3. 0
    8
      docs/index.html
  4. 2
    0
      src/config.ba0.c
  5. 23
    11
      src/config.h
  6. 116
    183
      src/game.c
  7. 17
    7
      src/game.h
  8. 72
    8
      src/main.c
  9. 5
    5
      src/map_data.h
  10. 95
    139
      src/obj.c
  11. 55
    3
      src/obj.h
  12. 8
    0
      src/strings.c
  13. 4
    0
      src/strings.h
  14. 6
    7
      src/timer.c
  15. 16
    8
      src/window.c
  16. 1
    0
      src/window.h

BIN
data/sfx_damage.wav View File


BIN
data/sfx_heal.wav View File


+ 0
- 8
docs/index.html View File

@@ -157,14 +157,6 @@
157 157
                 2: {},
158 158
                 3: {}
159 159
             };
160
-            EJS_onGameStart = function(e) {
161
-                setTimeout(function() {
162
-                    window.EJS_emulator.gameManager.simulateInput(0, 3, 1);
163
-                    setTimeout(function() {
164
-                        window.EJS_emulator.gameManager.simulateInput(0, 3, 0);
165
-                    }, 42);
166
-                }, 420);
167
-            };
168 160
             EJS_startButtonName = "Start Duality";
169 161
         </script>
170 162
         <script src="https://cdn.emulatorjs.org/stable/data/loader.js"></script>

+ 2
- 0
src/config.ba0.c View File

@@ -65,6 +65,8 @@ void conf_init(void) BANKED {
65 65
         mem.config.dmg_bg_inv = 1;
66 66
 
67 67
         score_reset();
68
+
69
+        mem.state.in_progress = 0;
68 70
     }
69 71
 }
70 72
 

+ 23
- 11
src/config.h View File

@@ -23,33 +23,42 @@
23 23
 #include <gbdk/platform.h>
24 24
 #include <stdint.h>
25 25
 
26
+#include "game.h"
26 27
 #include "score.h"
28
+#include "obj.h"
27 29
 
28 30
 enum debug_flag {
29 31
     DBG_NONE = 0,
30 32
 
31
-    DBG_MENU        = (1 << 0),
32
-    DBG_MARKER      = (1 << 1),
33
-    DBG_GOD_MODE    = (1 << 2),
34
-    DBG_NO_OBJ      = (1 << 3),
35
-    DBG_NO_FUEL     = (1 << 4),
36
-    DBG_FAST        = (1 << 5),
37
-    DBG_SHOW_FPS    = (1 << 6),
38
-    DBG_SHOW_FRAMES = (1 << 7),
39
-    DBG_SHOW_TIMER  = (1 << 8),
40
-    DBG_SHOW_STACK  = (1 << 9),
33
+    DBG_MENU        = (1U << 0),
34
+    DBG_MARKER      = (1U << 1),
35
+    DBG_GOD_MODE    = (1U << 2),
36
+    DBG_NO_OBJ      = (1U << 3),
37
+    DBG_NO_FUEL     = (1U << 4),
38
+    DBG_FAST        = (1U << 5),
39
+    DBG_SHOW_FPS    = (1U << 6),
40
+    DBG_SHOW_FRAMES = (1U << 7),
41
+    DBG_SHOW_TIMER  = (1U << 8),
42
+    DBG_SHOW_STACK  = (1U << 9),
41 43
 };
42 44
 
43 45
 #define DBG_OUT_ON (DBG_SHOW_FPS | DBG_SHOW_FRAMES | DBG_SHOW_TIMER | DBG_SHOW_STACK)
44 46
 
45 47
 struct config {
46 48
     enum debug_flag debug_flags;
49
+
47 50
     //uint8_t sfx_vol;
48 51
     uint8_t music_vol;
49 52
     uint8_t game_bg;
50 53
     uint8_t dmg_bg_inv;
51 54
 };
52 55
 
56
+struct state {
57
+    uint8_t in_progress;
58
+    struct game_state state_game;
59
+    struct obj_state state_obj;
60
+};
61
+
53 62
 void conf_init(void) BANKED;
54 63
 void conf_write_crc(void) BANKED;
55 64
 
@@ -58,12 +67,15 @@ BANKREF_EXTERN(config)
58 67
 struct config_mem {
59 68
     struct config config;
60 69
     struct scores scores[SCORE_NUM * 2];
70
+    struct state state;
61 71
 
62 72
     uint32_t crc; // needs to be last
63 73
 };
64 74
 
65 75
 extern struct config_mem mem;
76
+
77
+#define conf_get()    (&mem.config)
66 78
 #define conf_scores() (mem.scores)
67
-#define conf_get() (&mem.config)
79
+#define conf_state()  (&mem.state)
68 80
 
69 81
 #endif // __CONFIG_H__

+ 116
- 183
src/game.c View File

@@ -18,6 +18,7 @@
18 18
  */
19 19
 
20 20
 #include <gbdk/metasprites.h>
21
+#include <string.h>
21 22
 #include <rand.h>
22 23
 #include <stdint.h>
23 24
 
@@ -45,10 +46,6 @@
45 46
 #define SPEED_INC 1
46 47
 #define SPEED_DEC 1
47 48
 
48
-#define SPEED_MAX_ACC 23
49
-#define SPEED_MAX_ACC_DIAG 16
50
-#define SPEED_MAX_ACC_D_LO 9
51
-#define SPEED_MAX_ACC_D_HI 21
52 49
 #define SPEED_MAX_IDLE 16
53 50
 #define SPEED_MAX_DBG 256
54 51
 
@@ -60,22 +57,37 @@
60 57
 
61 58
 BANKREF(game)
62 59
 
60
+const int8_t table_shot_offsets[ROT_INVALID * 2] = {
61
+    0,                 -SHIP_OFF,         // 0.0
62
+    SHIP_OFF / 2 - 1,  -SHIP_OFF / 2 - 4, // 22.5
63
+    SHIP_OFF / 2 + 3,  -SHIP_OFF / 2 - 2, // 45.0
64
+    SHIP_OFF / 2 + 5,  -SHIP_OFF / 2 + 2, // 67.5
65
+    SHIP_OFF,          0,                 // 90.0
66
+    SHIP_OFF / 2 + 5,  SHIP_OFF / 2 + 0,  // 112.5
67
+    SHIP_OFF / 2 + 3,  SHIP_OFF / 2 + 2,  // 135.0
68
+    SHIP_OFF / 2 + 1,  SHIP_OFF / 2 + 4,  // 157.5
69
+    0,                 SHIP_OFF,          // 180.0
70
+    -SHIP_OFF / 2 + 2, SHIP_OFF / 2 + 3,  // 202.5
71
+    -SHIP_OFF / 2 - 3, SHIP_OFF / 2 + 2,  // 225.0
72
+    -SHIP_OFF / 2 - 5, SHIP_OFF / 2 - 1,  // 247.5
73
+    -SHIP_OFF,         0,                 // 270.0
74
+    -SHIP_OFF / 2 - 2, -SHIP_OFF / 2 + 2, // 292.5
75
+    -SHIP_OFF / 2 - 3, -SHIP_OFF / 2 - 2, // 315.0
76
+    -SHIP_OFF / 2 + 1, -SHIP_OFF / 2 - 4, // 337.5
77
+};
78
+
63 79
 enum ACCELERATION {
64
-    ACC_X = 1,
65
-    ACC_Y = 2,
66
-    ACC_R = 4,
80
+    ACC_X = (1U << 1),
81
+    ACC_Y = (1U << 2),
82
+    ACC_R = (1U << 3),
67 83
 };
68 84
 
69
-static int16_t spd_x = 0, spd_y = 0;
70
-static enum SPRITE_ROT rot = 0;
71
-static enum ACCELERATION acc = 0;
72
-static uint16_t health = HEALTH_MAX;
73
-static uint16_t power = POWER_MAX;
74
-static int32_t score = 0;
75
-static uint16_t frame_count = 0;
76 85
 static uint8_t fps_count = 0;
77 86
 static uint16_t prev_fps_start = 0;
78
-static uint8_t prev_fps = 0;
87
+
88
+struct game_state game_state;
89
+uint16_t frame_count = 0;
90
+uint8_t game_fps = 0;
79 91
 
80 92
 static void calc_fps(void) {
81 93
     frame_count++;
@@ -83,19 +95,11 @@ static void calc_fps(void) {
83 95
     uint16_t diff = timer_get() - prev_fps_start;
84 96
     if (diff >= TIMER_HZ) {
85 97
         prev_fps_start = timer_get();
86
-        prev_fps = fps_count;
98
+        game_fps = fps_count;
87 99
         fps_count = 0;
88 100
     }
89 101
 }
90 102
 
91
-uint8_t game_get_fps(void) BANKED {
92
-    return prev_fps;
93
-}
94
-
95
-uint16_t game_get_framecount(void) BANKED {
96
-    return frame_count;
97
-}
98
-
99 103
 static uint8_t pause_screen(void) {
100 104
     snd_music_off();
101 105
     snd_note_off();
@@ -118,8 +122,9 @@ static uint8_t pause_screen(void) {
118 122
         hide_sprites_range(hiwater, MAX_HARDWARE_SPRITES);
119 123
 
120 124
         if ((_cpu == CGB_TYPE) && (conf_get()->debug_flags & DBG_OUT_ON)) {
121
-            uint8_t x_off = win_game_draw(score, 0);
122
-            move_win(MINWNDPOSX + DEVICE_SCREEN_PX_WIDTH - x_off, MINWNDPOSY + DEVICE_SCREEN_PX_HEIGHT - 16);
125
+            uint8_t x_off = win_game_draw(game_state.score, 0);
126
+            move_win(MINWNDPOSX + DEVICE_SCREEN_PX_WIDTH - x_off,
127
+                     MINWNDPOSY + DEVICE_SCREEN_PX_HEIGHT - 16);
123 128
         }
124 129
 
125 130
         calc_fps();
@@ -182,16 +187,16 @@ static void show_explosion(uint16_t power) {
182 187
 }
183 188
 
184 189
 void game_get_mp_state(void) BANKED {
185
-    static struct mp_player_state state;
190
+    static struct mp_player_state mps;
186 191
 
187 192
     // TODO pass own pos to mp
188 193
 
189 194
     // TODO scale?
190
-    state.spd_x = spd_x;
191
-    state.spd_y = spd_y;
195
+    mps.spd_x = game_state.spd_x;
196
+    mps.spd_y = game_state.spd_y;
192 197
 
193
-    state.rot = rot;
194
-    mp_new_state(&state);
198
+    mps.rot = game_state.rot;
199
+    mp_new_state(&mps);
195 200
 }
196 201
 
197 202
 void game_set_mp_player2(struct mp_player_state *state) BANKED {
@@ -204,19 +209,29 @@ void game_set_mp_shot(struct mp_shot_state *state) BANKED {
204 209
 
205 210
 static void get_max_spd(int16_t *max_spd_x, int16_t *max_spd_y) NONBANKED {
206 211
     START_ROM_BANK(BANK(table_speed_move)) {
207
-        *max_spd_x = table_speed_move[(rot * table_speed_move_WIDTH) + 0];
208
-        *max_spd_y = -table_speed_move[(rot * table_speed_move_WIDTH) + 1];
212
+        *max_spd_x = table_speed_move[(game_state.rot * table_speed_move_WIDTH) + 0];
213
+        *max_spd_y = -table_speed_move[(game_state.rot * table_speed_move_WIDTH) + 1];
209 214
     } END_ROM_BANK;
210 215
 }
211 216
 
212 217
 static void get_shot_spd(int16_t *shot_spd_x, int16_t *shot_spd_y) NONBANKED {
213 218
     START_ROM_BANK(BANK(table_speed_shot)) {
214
-        *shot_spd_x = table_speed_shot[(rot * table_speed_move_WIDTH) + 0];
215
-        *shot_spd_y = -table_speed_shot[(rot * table_speed_move_WIDTH) + 1];
219
+        *shot_spd_x = table_speed_shot[(game_state.rot * table_speed_move_WIDTH) + 0];
220
+        *shot_spd_y = -table_speed_shot[(game_state.rot * table_speed_move_WIDTH) + 1];
216 221
     } END_ROM_BANK;
217 222
 }
218 223
 
219
-int32_t game(enum GAME_MODE mode) BANKED {
224
+void game_init(void) BANKED {
225
+    game_state.spd_x = 0;
226
+    game_state.spd_y = 0;
227
+    game_state.rot = 0;
228
+    game_state.health = HEALTH_MAX;
229
+    game_state.power = POWER_MAX;
230
+    game_state.score = 0;
231
+    memset(&obj_state, 0, sizeof(struct obj_state));
232
+}
233
+
234
+uint8_t game(enum GAME_MODE mode) BANKED {
220 235
     snd_music_off();
221 236
     snd_note_off();
222 237
 
@@ -229,15 +244,9 @@ int32_t game(enum GAME_MODE mode) BANKED {
229 244
     SHOW_SPRITES;
230 245
     SPRITES_8x8;
231 246
 
232
-    spd_x = 0;
233
-    spd_y = 0;
234
-    rot = 0;
235
-    health = HEALTH_MAX;
236
-    power = POWER_MAX;
237
-    score = 0;
238 247
     frame_count = 0;
239
-
240
-    obj_init();
248
+    fps_count = 0;
249
+    prev_fps_start = 0;
241 250
 
242 251
     if (mode == GM_SINGLE) {
243 252
         if (!(conf_get()->debug_flags & DBG_NO_OBJ)) {
@@ -245,8 +254,9 @@ int32_t game(enum GAME_MODE mode) BANKED {
245 254
         }
246 255
     }
247 256
 
248
-    uint8_t x_off = win_game_draw(score, 1);
249
-    move_win(MINWNDPOSX + DEVICE_SCREEN_PX_WIDTH - x_off, MINWNDPOSY + DEVICE_SCREEN_PX_HEIGHT - 16);
257
+    uint8_t x_off = win_game_draw(game_state.score, 1);
258
+    move_win(MINWNDPOSX + DEVICE_SCREEN_PX_WIDTH - x_off,
259
+             MINWNDPOSY + DEVICE_SCREEN_PX_HEIGHT - 16);
250 260
 
251 261
     SHOW_WIN;
252 262
     DISPLAY_ON;
@@ -254,6 +264,7 @@ int32_t game(enum GAME_MODE mode) BANKED {
254 264
 
255 265
     snd_music(SND_GAME);
256 266
 
267
+    uint8_t return_value = 0xFF;
257 268
     while(1) {
258 269
         key_read();
259 270
 
@@ -261,18 +272,18 @@ int32_t game(enum GAME_MODE mode) BANKED {
261 272
             mp_handle();
262 273
         }
263 274
 
264
-        acc = 0;
265
-        int32_t prev_score = score;
275
+        enum ACCELERATION acc = 0;
276
+        int32_t prev_score = game_state.score;
266 277
 
267 278
         if (key_pressed(J_LEFT)) {
268
-            rot = (rot - 1) & (ROT_INVALID - 1);
279
+            game_state.rot = (game_state.rot - 1) & (ROT_INVALID - 1);
269 280
             acc |= ACC_R;
270 281
         } else if (key_pressed(J_RIGHT)) {
271
-            rot = (rot + 1) & (ROT_INVALID - 1);
282
+            game_state.rot = (game_state.rot + 1) & (ROT_INVALID - 1);
272 283
             acc |= ACC_R;
273 284
         }
274 285
 
275
-        if (key_down(J_A) && (power > 0)) {
286
+        if (key_down(J_A) && (game_state.power > 0)) {
276 287
             int16_t max_spd_x;
277 288
             int16_t max_spd_y;
278 289
             get_max_spd(&max_spd_x, &max_spd_y);
@@ -293,14 +304,14 @@ int32_t game(enum GAME_MODE mode) BANKED {
293 304
 
294 305
             if (max_spd_x != 0) {
295 306
                 if (max_spd_x > 0) {
296
-                    spd_x += SPEED_INC;
297
-                    if (spd_x > max_spd_x) {
298
-                        spd_x = max_spd_x;
307
+                    game_state.spd_x += SPEED_INC;
308
+                    if (game_state.spd_x > max_spd_x) {
309
+                        game_state.spd_x = max_spd_x;
299 310
                     }
300 311
                 } else {
301
-                    spd_x -= SPEED_INC;
302
-                    if (spd_x < max_spd_x) {
303
-                        spd_x = max_spd_x;
312
+                    game_state.spd_x -= SPEED_INC;
313
+                    if (game_state.spd_x < max_spd_x) {
314
+                        game_state.spd_x = max_spd_x;
304 315
                     }
305 316
                 }
306 317
 
@@ -309,14 +320,14 @@ int32_t game(enum GAME_MODE mode) BANKED {
309 320
 
310 321
             if (max_spd_y != 0) {
311 322
                 if (max_spd_y > 0) {
312
-                    spd_y += SPEED_INC;
313
-                    if (spd_y > max_spd_y) {
314
-                        spd_y = max_spd_y;
323
+                    game_state.spd_y += SPEED_INC;
324
+                    if (game_state.spd_y > max_spd_y) {
325
+                        game_state.spd_y = max_spd_y;
315 326
                     }
316 327
                 } else {
317
-                    spd_y -= SPEED_INC;
318
-                    if (spd_y < max_spd_y) {
319
-                        spd_y = max_spd_y;
328
+                    game_state.spd_y -= SPEED_INC;
329
+                    if (game_state.spd_y < max_spd_y) {
330
+                        game_state.spd_y = max_spd_y;
320 331
                     }
321 332
                 }
322 333
 
@@ -324,38 +335,38 @@ int32_t game(enum GAME_MODE mode) BANKED {
324 335
             }
325 336
 
326 337
             if (!(conf_get()->debug_flags & DBG_NO_FUEL)) {
327
-                if (power >= POWER_DEC) {
328
-                    power -= POWER_DEC;
338
+                if (game_state.power >= POWER_DEC) {
339
+                    game_state.power -= POWER_DEC;
329 340
                 } else {
330
-                    power = 0;
341
+                    game_state.power = 0;
331 342
                 }
332 343
             }
333
-        } else if (!key_down(J_A) && (power < POWER_MAX)) {
334
-            if (power <= (POWER_MAX - POWER_INC)) {
335
-                power += POWER_INC;
344
+        } else if (!key_down(J_A) && (game_state.power < POWER_MAX)) {
345
+            if (game_state.power <= (POWER_MAX - POWER_INC)) {
346
+                game_state.power += POWER_INC;
336 347
             } else {
337
-                power = POWER_MAX;
348
+                game_state.power = POWER_MAX;
338 349
             }
339 350
         }
340 351
 
341 352
         // adjust speed down when not moving
342 353
         if (!(acc & ACC_X)) {
343
-            if (spd_x != 0) {
354
+            if (game_state.spd_x != 0) {
344 355
                 if (!(conf_get()->debug_flags & DBG_FAST)) {
345
-                    if (spd_x > SPEED_MAX_IDLE) spd_x -= SPEED_DEC;
346
-                    else if (spd_x < -SPEED_MAX_IDLE) spd_x += SPEED_DEC;
356
+                    if (game_state.spd_x > SPEED_MAX_IDLE) game_state.spd_x -= SPEED_DEC;
357
+                    else if (game_state.spd_x < -SPEED_MAX_IDLE) game_state.spd_x += SPEED_DEC;
347 358
                 } else {
348
-                    spd_x = 0;
359
+                    game_state.spd_x = 0;
349 360
                 }
350 361
             }
351 362
         }
352 363
         if (!(acc & ACC_Y)) {
353
-            if (spd_y != 0) {
364
+            if (game_state.spd_y != 0) {
354 365
                 if (!(conf_get()->debug_flags & DBG_FAST)) {
355
-                    if (spd_y > SPEED_MAX_IDLE) spd_y -= SPEED_DEC;
356
-                    else if (spd_y < -SPEED_MAX_IDLE) spd_y += SPEED_DEC;
366
+                    if (game_state.spd_y > SPEED_MAX_IDLE) game_state.spd_y -= SPEED_DEC;
367
+                    else if (game_state.spd_y < -SPEED_MAX_IDLE) game_state.spd_y += SPEED_DEC;
357 368
                 } else {
358
-                    spd_y = 0;
369
+                    game_state.spd_y = 0;
359 370
                 }
360 371
             }
361 372
         }
@@ -364,92 +375,11 @@ int32_t game(enum GAME_MODE mode) BANKED {
364 375
             int16_t shot_spd_x;
365 376
             int16_t shot_spd_y;
366 377
             get_shot_spd(&shot_spd_x, &shot_spd_y);
367
-            shot_spd_x += spd_x;
368
-            shot_spd_y += spd_y;
369
-
370
-            // TODO ugly hard-coded offsets?!
371
-            int16_t shot_pos_x = 0, shot_pos_y = 0;
372
-            switch (rot) {
373
-                case ROT_0:
374
-                    shot_pos_x = 0;
375
-                    shot_pos_y = -SHIP_OFF;
376
-                    break;
377
-
378
-                case ROT_22_5:
379
-                    shot_pos_x = SHIP_OFF / 2 - 1;
380
-                    shot_pos_y = -SHIP_OFF / 2 - 4;
381
-                    break;
382
-
383
-                case ROT_45:
384
-                    shot_pos_x = SHIP_OFF / 2 + 3;
385
-                    shot_pos_y = -SHIP_OFF / 2 - 2;
386
-                    break;
387
-
388
-                case ROT_67_5:
389
-                    shot_pos_x = SHIP_OFF / 2 + 5;
390
-                    shot_pos_y = -SHIP_OFF / 2 + 2;
391
-                    break;
392
-
393
-                case ROT_90:
394
-                    shot_pos_x = SHIP_OFF;
395
-                    shot_pos_y = 0;
396
-                    break;
397
-
398
-                case ROT_112_5:
399
-                    shot_pos_x = SHIP_OFF / 2 + 5;
400
-                    shot_pos_y = SHIP_OFF / 2 + 0;
401
-                    break;
402
-
403
-                case ROT_135:
404
-                    shot_pos_x = SHIP_OFF / 2 + 3;
405
-                    shot_pos_y = SHIP_OFF / 2 + 2;
406
-                    break;
407
-
408
-                case ROT_157_5:
409
-                    shot_pos_x = SHIP_OFF / 2 + 1;
410
-                    shot_pos_y = SHIP_OFF / 2 + 4;
411
-                    break;
412
-
413
-                case ROT_180:
414
-                    shot_pos_x = 0;
415
-                    shot_pos_y = SHIP_OFF;
416
-                    break;
417
-
418
-                case ROT_202_5:
419
-                    shot_pos_x = -SHIP_OFF / 2 + 2;
420
-                    shot_pos_y = SHIP_OFF / 2 + 3;
421
-                    break;
422
-
423
-                case ROT_225:
424
-                    shot_pos_x = -SHIP_OFF / 2 - 3;
425
-                    shot_pos_y = SHIP_OFF / 2 + 2;
426
-                    break;
427
-
428
-                case ROT_247_5:
429
-                    shot_pos_x = -SHIP_OFF / 2 - 5;
430
-                    shot_pos_y = SHIP_OFF / 2 - 1;
431
-                    break;
432
-
433
-                case ROT_270:
434
-                    shot_pos_x = -SHIP_OFF;
435
-                    shot_pos_y = 0;
436
-                    break;
437
-
438
-                case ROT_292_5:
439
-                    shot_pos_x = -SHIP_OFF / 2 - 2;
440
-                    shot_pos_y = -SHIP_OFF / 2 + 2;
441
-                    break;
442
-
443
-                case ROT_315:
444
-                    shot_pos_x = -SHIP_OFF / 2 - 3;
445
-                    shot_pos_y = -SHIP_OFF / 2 - 2;
446
-                    break;
447
-
448
-                case ROT_337_5:
449
-                    shot_pos_x = -SHIP_OFF / 2 + 1;
450
-                    shot_pos_y = -SHIP_OFF / 2 - 4;
451
-                    break;
452
-            }
378
+            shot_spd_x += game_state.spd_x;
379
+            shot_spd_y += game_state.spd_y;
380
+
381
+            int16_t shot_pos_x = table_shot_offsets[(game_state.rot * 2) + 0];
382
+            int16_t shot_pos_y = table_shot_offsets[(game_state.rot * 2) + 1];
453 383
 
454 384
             int8_t ret = obj_add(SPR_SHOT,
455 385
                                  shot_pos_x, shot_pos_y,
@@ -459,8 +389,8 @@ int32_t game(enum GAME_MODE mode) BANKED {
459 389
                 sample_play(SFX_SHOT);
460 390
 
461 391
                 if (mode == GM_SINGLE) {
462
-                    if (score > 0) {
463
-                        score--;
392
+                    if (game_state.score > 0) {
393
+                        game_state.score--;
464 394
                     }
465 395
                 } else {
466 396
                     static struct mp_shot_state state;
@@ -480,6 +410,7 @@ int32_t game(enum GAME_MODE mode) BANKED {
480 410
 
481 411
         if (key_pressed(J_START)) {
482 412
             if (pause_screen()) {
413
+                return_value = 1;
483 414
                 break;
484 415
             }
485 416
 
@@ -491,43 +422,44 @@ int32_t game(enum GAME_MODE mode) BANKED {
491 422
             map_dbg_reset();
492 423
         }
493 424
 
494
-        map_move(spd_x, spd_y);
425
+        map_move(game_state.spd_x, game_state.spd_y);
495 426
 
496 427
         uint8_t hiwater = SPR_NUM_START;
497
-        status(health >> HEALTH_SHIFT, power >> POWER_SHIFT, &hiwater);
428
+        status(game_state.health >> HEALTH_SHIFT, game_state.power >> POWER_SHIFT, &hiwater);
498 429
 
499 430
         if (conf_get()->debug_flags & DBG_MARKER) {
500 431
             spr_draw(SPR_DEBUG, FLIP_NONE, 0, 0, 0, &hiwater);
501 432
             spr_draw(SPR_DEBUG_LARGE, FLIP_NONE, 0, 0, 0, &hiwater);
502 433
         }
503 434
 
504
-        spr_ship(rot, acc & (ACC_X | ACC_Y), &hiwater);
435
+        spr_ship(game_state.rot, acc & (ACC_X | ACC_Y), &hiwater);
505 436
 
506
-        int16_t damage = obj_do(&spd_x, &spd_y, &score, &hiwater,
437
+        int16_t damage = obj_do(&game_state.spd_x, &game_state.spd_y, &game_state.score, &hiwater,
507 438
                                 (conf_get()->debug_flags & DBG_NO_OBJ) ? 1 : 0);
508 439
         if (damage > 0) {
509 440
             if (conf_get()->debug_flags & DBG_GOD_MODE) {
510 441
                 damage = 0;
511 442
             }
512 443
 
513
-            if (health > damage) {
514
-                health -= damage;
444
+            if (game_state.health > damage) {
445
+                game_state.health -= damage;
515 446
                 if ((!sample_running()) && (sample_last() != SFX_DAMAGE)) {
516 447
                     sample_play(SFX_DAMAGE);
517 448
                 }
518
-            } else if (health <= damage) {
519
-                health = 0;
520
-                show_explosion(power);
449
+            } else if (game_state.health <= damage) {
450
+                game_state.health = 0;
451
+                show_explosion(game_state.power);
452
+                return_value = 0;
521 453
                 break;
522 454
             }
523
-        } else if ((damage < 0) && (health < HEALTH_MAX)) {
455
+        } else if ((damage < 0) && (game_state.health < HEALTH_MAX)) {
524 456
             if ((!sample_running()) && (sample_last() != SFX_HEAL)) {
525 457
                 sample_play(SFX_HEAL);
526 458
             }
527 459
 
528
-            health += -damage;
529
-            if (health > HEALTH_MAX) {
530
-                health = HEALTH_MAX;
460
+            game_state.health += -damage;
461
+            if (game_state.health > HEALTH_MAX) {
462
+                game_state.health = HEALTH_MAX;
531 463
             }
532 464
         } else if (damage == 0) {
533 465
             sample_last_reset();
@@ -535,15 +467,16 @@ int32_t game(enum GAME_MODE mode) BANKED {
535 467
 
536 468
         hide_sprites_range(hiwater, MAX_HARDWARE_SPRITES);
537 469
 
538
-        if ((score != prev_score)
470
+        if ((game_state.score != prev_score)
539 471
                 || ((_cpu == CGB_TYPE) && (conf_get()->debug_flags & DBG_OUT_ON))) {
540
-            uint8_t x_off = win_game_draw(score, 0);
541
-            move_win(MINWNDPOSX + DEVICE_SCREEN_PX_WIDTH - x_off, MINWNDPOSY + DEVICE_SCREEN_PX_HEIGHT - 16);
472
+            uint8_t x_off = win_game_draw(game_state.score, 0);
473
+            move_win(MINWNDPOSX + DEVICE_SCREEN_PX_WIDTH - x_off,
474
+                     MINWNDPOSY + DEVICE_SCREEN_PX_HEIGHT - 16);
542 475
         }
543 476
 
544 477
         calc_fps();
545 478
         vsync();
546 479
     }
547 480
 
548
-    return score;
481
+    return return_value;
549 482
 }

+ 17
- 7
src/game.h View File

@@ -22,7 +22,9 @@
22 22
 
23 23
 #include <gbdk/platform.h>
24 24
 #include <stdint.h>
25
+
25 26
 #include "multiplayer.h"
27
+#include "sprites.h"
26 28
 
27 29
 #define HEALTH_MAX 0x1FF
28 30
 #define HEALTH_SHIFT 1
@@ -30,22 +32,30 @@
30 32
 #define SHOT_SPEED 42 //23
31 33
 #define MAX_TRAVEL 64 //128
32 34
 
33
-#define SHOT_SPEED_DIAG 30
34
-#define SHOT_SPEED_D_HI 39
35
-#define SHOT_SPEED_D_LO 16
36
-
37 35
 enum GAME_MODE {
38 36
     GM_SINGLE = 0,
39 37
     GM_MULTI,
40 38
 };
41 39
 
40
+struct game_state {
41
+    int16_t spd_x;
42
+    int16_t spd_y;
43
+    enum SPRITE_ROT rot;
44
+    uint16_t health;
45
+    uint16_t power;
46
+    int32_t score;
47
+};
48
+
42 49
 void game_get_mp_state(void) BANKED;
43 50
 void game_set_mp_player2(struct mp_player_state *state) BANKED;
44 51
 void game_set_mp_shot(struct mp_shot_state *state) BANKED;
45 52
 
46
-uint8_t game_get_fps(void) BANKED;
47
-uint16_t game_get_framecount(void) BANKED;
48
-int32_t game(enum GAME_MODE mode) BANKED;
53
+void game_init(void) BANKED;
54
+uint8_t game(enum GAME_MODE mode) BANKED;
55
+
56
+extern struct game_state game_state;
57
+extern uint16_t frame_count;
58
+extern uint8_t game_fps;
49 59
 
50 60
 BANKREF_EXTERN(game)
51 61
 

+ 72
- 8
src/main.c View File

@@ -21,10 +21,12 @@
21 21
  */
22 22
 
23 23
 #include <gbdk/metasprites.h>
24
+#include <string.h>
24 25
 #include <rand.h>
25 26
 
26 27
 #include "banks.h"
27 28
 #include "config.h"
29
+#include "gb/gb.h"
28 30
 #include "gb/hardware.h"
29 31
 #include "maps.h"
30 32
 #include "obj.h"
@@ -164,6 +166,7 @@ static void about_screen(void) {
164 166
 static void conf_screen(void) {
165 167
     HIDE_WIN;
166 168
 
169
+    uint8_t changed = 0;
167 170
     debug_menu_index = 0;
168 171
 
169 172
     move_win(MINWNDPOSX, MINWNDPOSY);
@@ -176,6 +179,10 @@ static void conf_screen(void) {
176 179
         key_read();
177 180
 
178 181
         if (key_pressed(J_SELECT)) {
182
+            if (changed) {
183
+                conf_write_crc();
184
+                changed = 0;
185
+            }
179 186
             about_screen();
180 187
             break;
181 188
         } else if (key_pressed(J_UP)) {
@@ -204,16 +211,16 @@ static void conf_screen(void) {
204 211
             } else {
205 212
                 *conf_entries[debug_menu_index].var = conf_entries[debug_menu_index].max;
206 213
             }
207
-            conf_write_crc();
208 214
             win_conf();
215
+            changed = 1;
209 216
         } else if (key_pressed(J_RIGHT)) {
210 217
             if (*conf_entries[debug_menu_index].var < conf_entries[debug_menu_index].max) {
211 218
                 (*conf_entries[debug_menu_index].var)++;
212 219
             } else {
213 220
                 *conf_entries[debug_menu_index].var = 0;
214 221
             }
215
-            conf_write_crc();
216 222
             win_conf();
223
+            changed = 1;
217 224
         } else if (key_pressed(J_A) || key_pressed(J_B) || key_pressed(J_START)) {
218 225
             break;
219 226
         }
@@ -221,6 +228,10 @@ static void conf_screen(void) {
221 228
         vsync();
222 229
     }
223 230
 
231
+    if (changed) {
232
+        conf_write_crc();
233
+    }
234
+
224 235
     debug_menu_index = 0;
225 236
 }
226 237
 
@@ -344,7 +355,7 @@ void splash(void) BANKED {
344 355
     anim_frame = 0;
345 356
     anim_state = 0;
346 357
 
347
-    obj_init();
358
+    memset(&obj_state, 0, sizeof(struct obj_state));
348 359
     obj_add(SPR_LIGHT, 42, -42, 0, 0);
349 360
     obj_add(SPR_DARK, -42, -42, 0, 0);
350 361
 
@@ -572,6 +583,34 @@ uint16_t ask_name(int32_t score) BANKED {
572 583
     return convert_name(name[0], name[1], name[2]);
573 584
 }
574 585
 
586
+uint8_t ask_continue(void) BANKED {
587
+    HIDE_WIN;
588
+
589
+    uint8_t r = 0;
590
+
591
+    move_win(MINWNDPOSX, MINWNDPOSY);
592
+    hide_sprites_range(SPR_NUM_START, MAX_HARDWARE_SPRITES);
593
+    win_continue();
594
+
595
+    SHOW_WIN;
596
+
597
+    while (1) {
598
+        key_read();
599
+
600
+        if (key_pressed(J_A)) {
601
+            r = 1;
602
+            break;
603
+        } else if (key_pressed(J_B)) {
604
+            r = 0;
605
+            break;
606
+        }
607
+
608
+        vsync();
609
+    }
610
+
611
+    return r;
612
+}
613
+
575 614
 static void sgb_init(void) NONBANKED {
576 615
     // Wait 4 frames
577 616
     // For SGB on PAL SNES this delay is required on startup, otherwise borders don't show up
@@ -607,6 +646,12 @@ void main(void) NONBANKED {
607 646
         cpu_fast();
608 647
     }
609 648
 
649
+    DISPLAY_OFF;
650
+    map_load(1);
651
+    map_fill(MAP_TITLE, 1);
652
+    SHOW_BKG;
653
+    DISPLAY_ON;
654
+
610 655
     conf_init();
611 656
     timer_init();
612 657
     spr_init();
@@ -620,12 +665,31 @@ void main(void) NONBANKED {
620 665
     initarand(seed);
621 666
 
622 667
     while (1) {
623
-        int32_t score = game(GM_SINGLE);
668
+        if (conf_state()->in_progress && ask_continue()) {
669
+            game_state = conf_state()->state_game;
670
+            obj_state = conf_state()->state_obj;
671
+        } else {
672
+            game_init();
673
+        }
624 674
 
625
-        if ((!(conf_get()->debug_flags)) && (score != 0) && score_ranking(score)) {
626
-            uint16_t name = ask_name(score);
627
-            struct scores s = { .name = name, .score = score };
628
-            score_add(s);
675
+        if (game(GM_SINGLE)) {
676
+            // game was exited via pause menu
677
+            conf_state()->in_progress = 1;
678
+            conf_state()->state_game = game_state;
679
+            conf_state()->state_obj = obj_state;
680
+            conf_write_crc();
681
+        } else {
682
+            // game ended with player death
683
+            conf_state()->in_progress = 0;
684
+            conf_write_crc();
685
+
686
+            if ((!(conf_get()->debug_flags))
687
+                    && (game_state.score != 0)
688
+                    && score_ranking(game_state.score)) {
689
+                uint16_t name = ask_name(game_state.score);
690
+                struct scores s = { .name = name, .score = game_state.score };
691
+                score_add(s);
692
+            }
629 693
         }
630 694
 
631 695
         splash();

+ 5
- 5
src/map_data.h View File

@@ -28,12 +28,12 @@
28 28
 // background tiles are loaded into VRAM starting at tile number 0
29 29
 #define BG_TILE_NUM_START 0
30 30
 
31
-#define BG_COPY_NONE 0xFF
31
+#define BG_COPY_NONE 0xFFU
32 32
 
33
-#define BG_LOAD_GAME     (0 << 0)
34
-#define BG_LOAD_SPLASH   (1 << 0)
35
-#define BG_LOAD_ALL      (1 << 6)
36
-#define BG_LOAD_GBC_ONLY (1 << 7)
33
+#define BG_LOAD_GAME     (0U << 0)
34
+#define BG_LOAD_SPLASH   (1U << 0)
35
+#define BG_LOAD_ALL      (1U << 6)
36
+#define BG_LOAD_GBC_ONLY (1U << 7)
37 37
 
38 38
 struct maps {
39 39
     uint8_t width;

+ 95
- 139
src/obj.c View File

@@ -18,7 +18,6 @@
18 18
  */
19 19
 
20 20
 #include <stdint.h>
21
-#include <string.h>
22 21
 #include <stdlib.h>
23 22
 #include <rand.h>
24 23
 
@@ -27,35 +26,6 @@
27 26
 #include "sample.h"
28 27
 #include "obj.h"
29 28
 
30
-/*
31
- * sprite budget:
32
- *
33
- * fixed:
34
- * status bars: 8
35
- * ship + thruster: 7
36
- * --> 15 fixed
37
- *
38
- * hardware tiles: 40 - 15 = 25
39
- *
40
- * dynamic:
41
- * shot / small: 1
42
- * expl: 4
43
- * light: 4
44
- * dark: 4
45
- * --> 2x dark & 2x light & 1x expl = 20
46
- * --> 2x shot & 4x small = 6
47
- * --> 20 + 6 = 26
48
- *
49
- * TODO we will sometimes have glitches
50
- * 1 sprite tile too much
51
- */
52
-#define MAX_DARK 2
53
-#define MAX_LIGHT 2
54
-#define MAX_SHOT 2
55
-#define MAX_SHOT_DARK 2
56
-#define MAX_SHOT_LIGHT 2
57
-#define MAX_OBJ ((4 * MAX_DARK) + (4 * MAX_LIGHT) + MAX_SHOT + MAX_SHOT_DARK + MAX_SHOT_LIGHT)
58
-
59 29
 #define POS_SCALE_OBJS 5
60 30
 #define POS_OBJS_MAX (INT16_MAX >> (8 - POS_SCALE_OBJS))
61 31
 #define POS_OBJS_MIN (-(INT16_MAX >> (8 - POS_SCALE_OBJS)) - 1)
@@ -83,20 +53,7 @@
83 53
 
84 54
 #define CHECK_COL_AT_SHOTS
85 55
 
86
-struct obj {
87
-    uint8_t active;
88
-    enum SPRITES sprite;
89
-    int16_t off_x, off_y;
90
-    int16_t spd_x, spd_y;
91
-    uint8_t travel;
92
-    uint8_t frame;
93
-    uint8_t frame_index;
94
-    uint8_t frame_count;
95
-    uint8_t frame_duration;
96
-};
97
-
98
-static struct obj objs[MAX_OBJ];
99
-static uint8_t obj_cnt[SPRITE_COUNT];
56
+struct obj_state obj_state;
100 57
 
101 58
 static const uint8_t obj_max[SPRITE_COUNT] = {
102 59
     1, // SPR_SHIP
@@ -113,23 +70,18 @@ static const uint8_t obj_max[SPRITE_COUNT] = {
113 70
     1, // SPR_DEBUG_LARGE
114 71
 };
115 72
 
116
-void obj_init(void) BANKED {
117
-    memset(objs, 0, sizeof(objs));
118
-    memset(obj_cnt, 0, sizeof(obj_cnt));
119
-}
120
-
121 73
 static uint8_t is_too_close(int8_t x, int8_t y, int8_t center_dist) {
122 74
     if ((abs(x) < center_dist) && (abs(y) < center_dist)) {
123 75
         return 1;
124 76
     }
125 77
 
126 78
     for (uint8_t i = 0; i < MAX_OBJ; i++) {
127
-        if (!objs[i].active) {
79
+        if (!obj_state.objs[i].active) {
128 80
             continue;
129 81
         }
130 82
 
131
-        int dst_x = abs((objs[i].off_x >> POS_SCALE_OBJS) - x);
132
-        int dst_y = abs((objs[i].off_y >> POS_SCALE_OBJS) - y);
83
+        int dst_x = abs((obj_state.objs[i].off_x >> POS_SCALE_OBJS) - x);
84
+        int dst_y = abs((obj_state.objs[i].off_y >> POS_SCALE_OBJS) - y);
133 85
 
134 86
         if ((dst_x < PLACEMENT_DISTANCE) && (dst_y < PLACEMENT_DISTANCE)) {
135 87
             return 1;
@@ -153,7 +105,7 @@ static void generate_coords(int8_t *x_c, int8_t *y_c, int8_t center_dist) {
153 105
 }
154 106
 
155 107
 static void obj_respawn_type(enum SPRITES spr, int8_t center_dist) {
156
-    while (obj_cnt[spr] < obj_max[spr]) {
108
+    while (obj_state.obj_cnt[spr] < obj_max[spr]) {
157 109
         int8_t x, y;
158 110
         generate_coords(&x, &y, center_dist);
159 111
         obj_add(spr, x, y, 0, 0);
@@ -170,7 +122,7 @@ void obj_spawn(void) BANKED {
170 122
 enum OBJ_STATE obj_add(enum SPRITES sprite, int16_t off_x, int16_t off_y, int16_t spd_x, int16_t spd_y) BANKED {
171 123
     uint8_t next = 0xFF;
172 124
     for (uint8_t i = 0; i < MAX_OBJ; i++) {
173
-        if (!objs[i].active) {
125
+        if (!obj_state.objs[i].active) {
174 126
             next = i;
175 127
             break;
176 128
         }
@@ -179,58 +131,58 @@ enum OBJ_STATE obj_add(enum SPRITES sprite, int16_t off_x, int16_t off_y, int16_
179 131
         return OBJ_LIST_FULL;
180 132
     }
181 133
 
182
-    if (obj_cnt[sprite] >= obj_max[sprite]) {
134
+    if (obj_state.obj_cnt[sprite] >= obj_max[sprite]) {
183 135
         return OBJ_TYPE_FULL;
184 136
     }
185 137
 
186
-    obj_cnt[sprite]++;
138
+    obj_state.obj_cnt[sprite]++;
187 139
 
188
-    objs[next].active = 1;
189
-    objs[next].sprite = sprite;
190
-    objs[next].off_x = off_x << POS_SCALE_OBJS;
191
-    objs[next].off_y = off_y << POS_SCALE_OBJS;
192
-    objs[next].spd_x = spd_x;
193
-    objs[next].spd_y = spd_y;
194
-    objs[next].travel = 0;
195
-    objs[next].frame = 0;
196
-    objs[next].frame_index = 0;
197
-    objs[next].frame_count = 1;
198
-    objs[next].frame_duration = 0;
140
+    obj_state.objs[next].active = 1;
141
+    obj_state.objs[next].sprite = sprite;
142
+    obj_state.objs[next].off_x = off_x << POS_SCALE_OBJS;
143
+    obj_state.objs[next].off_y = off_y << POS_SCALE_OBJS;
144
+    obj_state.objs[next].spd_x = spd_x;
145
+    obj_state.objs[next].spd_y = spd_y;
146
+    obj_state.objs[next].travel = 0;
147
+    obj_state.objs[next].frame = 0;
148
+    obj_state.objs[next].frame_index = 0;
149
+    obj_state.objs[next].frame_count = 1;
150
+    obj_state.objs[next].frame_duration = 0;
199 151
 
200 152
     return OBJ_ADDED;
201 153
 }
202 154
 
203 155
 static uint8_t handle_shot_col(uint8_t shot, uint8_t orb, int32_t *score, uint8_t is_splash) {
204
-    if ((abs(objs[shot].off_x - objs[orb].off_x) <= SHOT_RANGE)
205
-            && (abs(objs[shot].off_y - objs[orb].off_y) <= SHOT_RANGE)) {
156
+    if ((abs(obj_state.objs[shot].off_x - obj_state.objs[orb].off_x) <= SHOT_RANGE)
157
+            && (abs(obj_state.objs[shot].off_y - obj_state.objs[orb].off_y) <= SHOT_RANGE)) {
206 158
         sample_play(SFX_EXPL_ORB);
207 159
 
208
-        objs[orb].active = 0;
160
+        obj_state.objs[orb].active = 0;
209 161
 
210
-        obj_cnt[objs[shot].sprite]--;
211
-        obj_cnt[objs[orb].sprite]--;
162
+        obj_state.obj_cnt[obj_state.objs[shot].sprite]--;
163
+        obj_state.obj_cnt[obj_state.objs[orb].sprite]--;
212 164
 
213
-        objs[shot].sprite = SPR_EXPL;
214
-        objs[shot].travel = 0;
215
-        objs[shot].frame = 0;
216
-        objs[shot].frame_index = 0;
217
-        objs[shot].frame_count = 4;
218
-        objs[shot].frame_duration = 4;
219
-        obj_cnt[SPR_EXPL]++;
165
+        obj_state.objs[shot].sprite = SPR_EXPL;
166
+        obj_state.objs[shot].travel = 0;
167
+        obj_state.objs[shot].frame = 0;
168
+        obj_state.objs[shot].frame_index = 0;
169
+        obj_state.objs[shot].frame_count = 4;
170
+        obj_state.objs[shot].frame_duration = 4;
171
+        obj_state.obj_cnt[SPR_EXPL]++;
220 172
 
221 173
         // move explosion to center of orb instead of shot
222
-        objs[shot].off_x = objs[orb].off_x;
223
-        objs[shot].off_y = objs[orb].off_y;
174
+        obj_state.objs[shot].off_x = obj_state.objs[orb].off_x;
175
+        obj_state.objs[shot].off_y = obj_state.objs[orb].off_y;
224 176
 
225 177
         // also would look kinda cool with shot speed still applied?
226
-        objs[shot].spd_x = 0;
227
-        objs[shot].spd_y = 0;
178
+        obj_state.objs[shot].spd_x = 0;
179
+        obj_state.objs[shot].spd_y = 0;
228 180
 
229 181
         if (!is_splash) {
230
-            obj_respawn_type(objs[orb].sprite, RESPAWN_DISTANCE);
182
+            obj_respawn_type(obj_state.objs[orb].sprite, RESPAWN_DISTANCE);
231 183
         }
232 184
 
233
-        if (objs[orb].sprite == SPR_LIGHT) {
185
+        if (obj_state.objs[orb].sprite == SPR_LIGHT) {
234 186
             (*score) += SCORE_LARGE;
235 187
         } else {
236 188
             (*score) -= SCORE_LARGE;
@@ -250,42 +202,42 @@ int16_t obj_do(int16_t *spd_off_x, int16_t *spd_off_y, int32_t *score, uint8_t *
250 202
     int16_t spd_y = *spd_off_y;
251 203
 
252 204
     for (uint8_t i = 0; i < MAX_OBJ; i++) {
253
-        if (!objs[i].active) {
205
+        if (!obj_state.objs[i].active) {
254 206
             continue;
255 207
         }
256 208
 
257 209
         // move objects by their speed and compensate for movement of the background / ship
258
-        objs[i].off_x = objs[i].off_x + objs[i].spd_x - spd_x;
259
-        objs[i].off_y = objs[i].off_y + objs[i].spd_y - spd_y;
210
+        obj_state.objs[i].off_x = obj_state.objs[i].off_x + obj_state.objs[i].spd_x - spd_x;
211
+        obj_state.objs[i].off_y = obj_state.objs[i].off_y + obj_state.objs[i].spd_y - spd_y;
260 212
 
261
-        if (objs[i].off_x > POS_OBJS_MAX) {
262
-            objs[i].off_x -= POS_OBJS_MAX - POS_OBJS_MIN + 1;
263
-        } else if (objs[i].off_x < POS_OBJS_MIN) {
264
-            objs[i].off_x += POS_OBJS_MAX - POS_OBJS_MIN + 1;
213
+        if (obj_state.objs[i].off_x > POS_OBJS_MAX) {
214
+            obj_state.objs[i].off_x -= POS_OBJS_MAX - POS_OBJS_MIN + 1;
215
+        } else if (obj_state.objs[i].off_x < POS_OBJS_MIN) {
216
+            obj_state.objs[i].off_x += POS_OBJS_MAX - POS_OBJS_MIN + 1;
265 217
         }
266
-        if (objs[i].off_y > POS_OBJS_MAX) {
267
-            objs[i].off_y -= POS_OBJS_MAX - POS_OBJS_MIN + 1;
268
-        } else if (objs[i].off_y < POS_OBJS_MIN) {
269
-            objs[i].off_y += POS_OBJS_MAX - POS_OBJS_MIN + 1;
218
+        if (obj_state.objs[i].off_y > POS_OBJS_MAX) {
219
+            obj_state.objs[i].off_y -= POS_OBJS_MAX - POS_OBJS_MIN + 1;
220
+        } else if (obj_state.objs[i].off_y < POS_OBJS_MIN) {
221
+            obj_state.objs[i].off_y += POS_OBJS_MAX - POS_OBJS_MIN + 1;
270 222
         }
271 223
 
272 224
         // only update travel time if we're actually moving
273
-        if ((objs[i].spd_x != 0) || (objs[i].spd_y != 0)) {
274
-            objs[i].travel += 1;
225
+        if ((obj_state.objs[i].spd_x != 0) || (obj_state.objs[i].spd_y != 0)) {
226
+            obj_state.objs[i].travel += 1;
275 227
         }
276 228
 
277 229
         // remove objects that have traveled for too long
278
-        if (objs[i].travel >= MAX_TRAVEL) {
279
-            objs[i].active = 0;
280
-            obj_cnt[objs[i].sprite]--;
230
+        if (obj_state.objs[i].travel >= MAX_TRAVEL) {
231
+            obj_state.objs[i].active = 0;
232
+            obj_state.obj_cnt[obj_state.objs[i].sprite]--;
281 233
             continue;
282 234
         }
283 235
 
284
-        int abs_off_x = abs(objs[i].off_x);
285
-        int abs_off_y = abs(objs[i].off_y);
236
+        int abs_off_x = abs(obj_state.objs[i].off_x);
237
+        int abs_off_y = abs(obj_state.objs[i].off_y);
286 238
 
287 239
         // handle collision
288
-        switch (objs[i].sprite) {
240
+        switch (obj_state.objs[i].sprite) {
289 241
             case SPR_DARK:
290 242
 #ifdef DESPAWN_RANGE
291 243
                 if ((abs_off_x >= DESPAWN_RANGE) || (abs_off_y >= DESPAWN_RANGE)) {
@@ -296,15 +248,15 @@ int16_t obj_do(int16_t *spd_off_x, int16_t *spd_off_y, int32_t *score, uint8_t *
296 248
 #endif // DESPAWN_RANGE
297 249
 
298 250
                 if ((abs_off_x <= GRAVITY_RANGE) && (abs_off_y <= GRAVITY_RANGE)) {
299
-                    if (objs[i].off_x > 0) {
300
-                        *spd_off_x += (GRAVITY_RANGE - objs[i].off_x) >> GRAVITY_SHIFT;
301
-                    } else if (objs[i].off_x < 0) {
302
-                        *spd_off_x += (-GRAVITY_RANGE - objs[i].off_x) >> GRAVITY_SHIFT;
251
+                    if (obj_state.objs[i].off_x > 0) {
252
+                        *spd_off_x += (GRAVITY_RANGE - obj_state.objs[i].off_x) >> GRAVITY_SHIFT;
253
+                    } else if (obj_state.objs[i].off_x < 0) {
254
+                        *spd_off_x += (-GRAVITY_RANGE - obj_state.objs[i].off_x) >> GRAVITY_SHIFT;
303 255
                     }
304
-                    if (objs[i].off_y > 0) {
305
-                        *spd_off_y += (GRAVITY_RANGE - objs[i].off_y) >> GRAVITY_SHIFT;
306
-                    } else if (objs[i].off_y < 0) {
307
-                        *spd_off_y += (-GRAVITY_RANGE - objs[i].off_y) >> GRAVITY_SHIFT;
256
+                    if (obj_state.objs[i].off_y > 0) {
257
+                        *spd_off_y += (GRAVITY_RANGE - obj_state.objs[i].off_y) >> GRAVITY_SHIFT;
258
+                    } else if (obj_state.objs[i].off_y < 0) {
259
+                        *spd_off_y += (-GRAVITY_RANGE - obj_state.objs[i].off_y) >> GRAVITY_SHIFT;
308 260
                     }
309 261
                 }
310 262
 
@@ -335,15 +287,15 @@ int16_t obj_do(int16_t *spd_off_x, int16_t *spd_off_y, int32_t *score, uint8_t *
335 287
 #endif // DESPAWN_RANGE
336 288
 
337 289
                 if ((abs_off_x <= GRAVITY_RANGE) && (abs_off_y <= GRAVITY_RANGE)) {
338
-                    if (objs[i].off_x > 0) {
339
-                        *spd_off_x -= (GRAVITY_RANGE - objs[i].off_x) >> GRAVITY_SHIFT;
340
-                    } else if (objs[i].off_x < 0) {
341
-                        *spd_off_x -= (-GRAVITY_RANGE - objs[i].off_x) >> GRAVITY_SHIFT;
290
+                    if (obj_state.objs[i].off_x > 0) {
291
+                        *spd_off_x -= (GRAVITY_RANGE - obj_state.objs[i].off_x) >> GRAVITY_SHIFT;
292
+                    } else if (obj_state.objs[i].off_x < 0) {
293
+                        *spd_off_x -= (-GRAVITY_RANGE - obj_state.objs[i].off_x) >> GRAVITY_SHIFT;
342 294
                     }
343
-                    if (objs[i].off_y > 0) {
344
-                        *spd_off_y -= (GRAVITY_RANGE - objs[i].off_y) >> GRAVITY_SHIFT;
345
-                    } else if (objs[i].off_y < 0) {
346
-                        *spd_off_y -= (-GRAVITY_RANGE - objs[i].off_y) >> GRAVITY_SHIFT;
295
+                    if (obj_state.objs[i].off_y > 0) {
296
+                        *spd_off_y -= (GRAVITY_RANGE - obj_state.objs[i].off_y) >> GRAVITY_SHIFT;
297
+                    } else if (obj_state.objs[i].off_y < 0) {
298
+                        *spd_off_y -= (-GRAVITY_RANGE - obj_state.objs[i].off_y) >> GRAVITY_SHIFT;
347 299
                     }
348 300
                 }
349 301
 
@@ -375,8 +327,8 @@ int16_t obj_do(int16_t *spd_off_x, int16_t *spd_off_y, int32_t *score, uint8_t *
375 327
 
376 328
                 if ((abs_off_x <= PICKUP_SMALL_RANGE) && (abs_off_y <= PICKUP_SMALL_RANGE)) {
377 329
                     (*score) -= SCORE_SMALL;
378
-                    objs[i].active = 0;
379
-                    obj_cnt[SPR_SHOT_DARK]--;
330
+                    obj_state.objs[i].active = 0;
331
+                    obj_state.obj_cnt[SPR_SHOT_DARK]--;
380 332
                     obj_respawn_type(SPR_SHOT_DARK, RESPAWN_DISTANCE);
381 333
                 }
382 334
                 break;
@@ -392,8 +344,8 @@ int16_t obj_do(int16_t *spd_off_x, int16_t *spd_off_y, int32_t *score, uint8_t *
392 344
 
393 345
                 if ((abs_off_x <= PICKUP_SMALL_RANGE) && (abs_off_y <= PICKUP_SMALL_RANGE)) {
394 346
                     (*score) += SCORE_SMALL;
395
-                    objs[i].active = 0;
396
-                    obj_cnt[SPR_SHOT_LIGHT]--;
347
+                    obj_state.objs[i].active = 0;
348
+                    obj_state.obj_cnt[SPR_SHOT_LIGHT]--;
397 349
                     obj_respawn_type(SPR_SHOT_LIGHT, RESPAWN_DISTANCE);
398 350
                 }
399 351
                 break;
@@ -401,8 +353,9 @@ int16_t obj_do(int16_t *spd_off_x, int16_t *spd_off_y, int32_t *score, uint8_t *
401 353
 #ifdef CHECK_COL_AT_SHOTS
402 354
             case SPR_SHOT:
403 355
                 for (uint8_t orb = 0; orb < MAX_OBJ; orb++) {
404
-                    if ((!objs[orb].active)
405
-                            || ((objs[orb].sprite != SPR_LIGHT) && (objs[orb].sprite != SPR_DARK))) {
356
+                    if ((!obj_state.objs[orb].active)
357
+                            || ((obj_state.objs[orb].sprite != SPR_LIGHT)
358
+                                && (obj_state.objs[orb].sprite != SPR_DARK))) {
406 359
                         continue;
407 360
                     }
408 361
 
@@ -417,22 +370,25 @@ int16_t obj_do(int16_t *spd_off_x, int16_t *spd_off_y, int32_t *score, uint8_t *
417 370
                 break;
418 371
         }
419 372
 
420
-        if (!objs[i].active) {
373
+        if (!obj_state.objs[i].active) {
421 374
             continue;
422 375
         }
423 376
 
424
-        spr_draw(objs[i].sprite, FLIP_NONE, objs[i].off_x >> POS_SCALE_OBJS, objs[i].off_y >> POS_SCALE_OBJS, objs[i].frame_index, hiwater);
425
-
426
-        objs[i].frame++;
427
-        if (objs[i].frame >= objs[i].frame_duration) {
428
-            objs[i].frame = 0;
429
-            objs[i].frame_index++;
430
-            if (objs[i].frame_index >= objs[i].frame_count) {
431
-                objs[i].frame_index = 0;
432
-
433
-                if (objs[i].sprite == SPR_EXPL) {
434
-                    objs[i].active = 0;
435
-                    obj_cnt[SPR_EXPL]--;
377
+        spr_draw(obj_state.objs[i].sprite, FLIP_NONE,
378
+                 obj_state.objs[i].off_x >> POS_SCALE_OBJS,
379
+                 obj_state.objs[i].off_y >> POS_SCALE_OBJS,
380
+                 obj_state.objs[i].frame_index, hiwater);
381
+
382
+        obj_state.objs[i].frame++;
383
+        if (obj_state.objs[i].frame >= obj_state.objs[i].frame_duration) {
384
+            obj_state.objs[i].frame = 0;
385
+            obj_state.objs[i].frame_index++;
386
+            if (obj_state.objs[i].frame_index >= obj_state.objs[i].frame_count) {
387
+                obj_state.objs[i].frame_index = 0;
388
+
389
+                if (obj_state.objs[i].sprite == SPR_EXPL) {
390
+                    obj_state.objs[i].active = 0;
391
+                    obj_state.obj_cnt[SPR_EXPL]--;
436 392
                 }
437 393
             }
438 394
         }

+ 55
- 3
src/obj.h View File

@@ -25,15 +25,67 @@
25 25
 
26 26
 #include "sprites.h"
27 27
 
28
+/*
29
+ * sprite budget:
30
+ *
31
+ * fixed:
32
+ * status bars: 8
33
+ * ship + thruster: 7
34
+ * --> 15 fixed
35
+ *
36
+ * hardware tiles: 40 - 15 = 25
37
+ *
38
+ * dynamic:
39
+ * shot / small: 1
40
+ * expl: 4
41
+ * light: 4
42
+ * dark: 4
43
+ * --> 2x dark & 2x light & 1x expl = 20
44
+ * --> 2x shot & 4x small = 6
45
+ * --> 20 + 6 = 26
46
+ *
47
+ * TODO we will sometimes have glitches
48
+ * 1 sprite tile too much
49
+ */
50
+#define MAX_DARK 2
51
+#define MAX_LIGHT 2
52
+#define MAX_SHOT 2
53
+#define MAX_SHOT_DARK 2
54
+#define MAX_SHOT_LIGHT 2
55
+#define MAX_OBJ ((4 * MAX_DARK) + (4 * MAX_LIGHT) + MAX_SHOT + MAX_SHOT_DARK + MAX_SHOT_LIGHT)
56
+
57
+struct obj {
58
+    uint8_t active;
59
+    enum SPRITES sprite;
60
+    int16_t off_x, off_y;
61
+    int16_t spd_x, spd_y;
62
+    uint8_t travel;
63
+    uint8_t frame;
64
+    uint8_t frame_index;
65
+    uint8_t frame_count;
66
+    uint8_t frame_duration;
67
+};
68
+
69
+struct obj_state {
70
+    struct obj objs[MAX_OBJ];
71
+    uint8_t obj_cnt[SPRITE_COUNT];
72
+};
73
+
28 74
 enum OBJ_STATE {
29 75
     OBJ_ADDED = 0,
30 76
     OBJ_LIST_FULL,
31 77
     OBJ_TYPE_FULL,
32 78
 };
33 79
 
34
-void obj_init(void) BANKED;
35 80
 void obj_spawn(void) BANKED;
36
-enum OBJ_STATE obj_add(enum SPRITES sprite, int16_t off_x, int16_t off_y, int16_t spd_x, int16_t spd_y) BANKED;
37
-int16_t obj_do(int16_t *spd_off_x, int16_t *spd_off_y, int32_t *score, uint8_t *hiwater, uint8_t is_splash) BANKED;
81
+
82
+enum OBJ_STATE obj_add(enum SPRITES sprite,
83
+                       int16_t off_x, int16_t off_y,
84
+                       int16_t spd_x, int16_t spd_y) BANKED;
85
+
86
+int16_t obj_do(int16_t *spd_off_x, int16_t *spd_off_y,
87
+               int32_t *score, uint8_t *hiwater, uint8_t is_splash) BANKED;
88
+
89
+extern struct obj_state obj_state;
38 90
 
39 91
 #endif // __OBJ_H__

+ 8
- 0
src/strings.c View File

@@ -55,6 +55,10 @@ static const char   string_printf_timer[] = " Timer: 0x%x";
55 55
 static const char   string_printf_stack[] = " Stack: 0x%x";
56 56
 static const char     string_printf_fps[] = "   FPS: %hd";
57 57
 static const char        string_spinner[] = "/-\\|";
58
+static const char        string_game_in[] = "Game in";
59
+static const char       string_progress[] = "Progress";
60
+static const char     string_a_continue[] = "A Continue";
61
+static const char     string_b_new_game[] = "B New Game";
58 62
 
59 63
 static const char * const strings[COUNT_STRINGS] = {
60 64
     string_top,            // STR_TOP
@@ -88,6 +92,10 @@ static const char * const strings[COUNT_STRINGS] = {
88 92
     string_printf_stack,   // STR_PRINTF_STACK
89 93
     string_printf_fps,     // STR_PRINTF_FPS
90 94
     string_spinner,        // STR_SPINNER
95
+    string_game_in,        // STR_GAME_IN
96
+    string_progress,       // STR_PROGRESS
97
+    string_a_continue,     // STR_A_CONTINUE
98
+    string_b_new_game,     // STR_B_NEW_GAME
91 99
 };
92 100
 
93 101
 #define MAX_STR_LEN 32

+ 4
- 0
src/strings.h View File

@@ -54,6 +54,10 @@ enum STRINGS {
54 54
     STR_PRINTF_STACK,
55 55
     STR_PRINTF_FPS,
56 56
     STR_SPINNER,
57
+    STR_GAME_IN,
58
+    STR_PROGRESS,
59
+    STR_A_CONTINUE,
60
+    STR_B_NEW_GAME,
57 61
 
58 62
     COUNT_STRINGS
59 63
 };

+ 6
- 7
src/timer.c View File

@@ -21,23 +21,22 @@
21 21
 #include "sound.h"
22 22
 #include "timer.h"
23 23
 
24
+#define DMG_TMA_VAL (0x100UL -  64UL) // 16.384kHz /  64 = 256Hz
25
+#define CGB_TMA_VAL (0x100UL - 128UL) // 32.768kHz / 128 = 256Hz
26
+
24 27
 static uint16_t count = 0;
25 28
 
26 29
 static void timer_isr(void) NONBANKED {
27 30
     sample_isr();
28 31
     snd_play();
29
-    count += 4;
32
+    count++;
30 33
 }
31 34
 
32 35
 void timer_init(void) BANKED {
33 36
     CRITICAL {
34 37
         count = 0;
35 38
         add_TIM(timer_isr);
36
-        if (_cpu == CGB_TYPE) {
37
-            TMA_REG = 0x100 - 128; // 32.768kHz / 128 = 256Hz
38
-        } else {
39
-            TMA_REG = 0x100 - 64; // 16.384kHz / 64 = 256Hz
40
-        }
39
+        TMA_REG = (_cpu == CGB_TYPE) ? CGB_TMA_VAL : DMG_TMA_VAL;
41 40
         TAC_REG = TACF_16KHZ | TACF_START;
42 41
 
43 42
         set_interrupts(TIM_IFLAG | VBL_IFLAG);
@@ -49,5 +48,5 @@ uint16_t timer_get(void) NONBANKED {
49 48
     CRITICAL {
50 49
         r = count;
51 50
     }
52
-    return r;
51
+    return r << 2;
53 52
 }

+ 16
- 8
src/window.c View File

@@ -273,6 +273,16 @@ void win_name_draw(uint16_t name, uint8_t is_black, uint8_t pos) BANKED {
273 273
          (pos == 2) ? !is_black : is_black);
274 274
 }
275 275
 
276
+void win_continue(void) BANKED {
277
+    map_fill(MAP_TITLE, 0);
278
+
279
+    str_center(get_string(STR_GAME_IN), 1, 0);
280
+    str_center(get_string(STR_PROGRESS), 3, 0);
281
+
282
+    str_center(get_string(STR_A_CONTINUE), 13, 1);
283
+    str_center(get_string(STR_B_NEW_GAME), 15, 1);
284
+}
285
+
276 286
 uint8_t win_game_draw(int32_t score, uint8_t initial) BANKED {
277 287
     uint8_t is_black = 0;
278 288
     if (score < 0) {
@@ -298,10 +308,9 @@ uint8_t win_game_draw(int32_t score, uint8_t initial) BANKED {
298 308
 
299 309
         if ((conf_get()->debug_flags & DBG_SHOW_FPS) && (y_off < 2)) {
300 310
             static uint8_t prev_fps = 0;
301
-            uint8_t fps = game_get_fps();
302
-            if ((fps != prev_fps) || redraw) {
303
-                prev_fps = fps;
304
-                sprintf(str_buff, get_string(STR_PRINTF_FPS), (uint8_t)fps);
311
+            if ((game_fps != prev_fps) || redraw) {
312
+                prev_fps = game_fps;
313
+                sprintf(str_buff, get_string(STR_PRINTF_FPS), (uint8_t)game_fps);
305 314
                 str_ascii(str_buff, x_off, y_off, 1);
306 315
             }
307 316
             y_off++;
@@ -309,10 +318,9 @@ uint8_t win_game_draw(int32_t score, uint8_t initial) BANKED {
309 318
 
310 319
         if ((conf_get()->debug_flags & DBG_SHOW_FRAMES) && (y_off < 2)) {
311 320
             static uint16_t prev_framecount = 0;
312
-            uint16_t framecount = game_get_framecount();
313
-            if ((framecount != prev_framecount) || redraw) {
314
-                prev_framecount = framecount;
315
-                sprintf(str_buff, get_string(STR_PRINTF_FRAMES), (uint16_t)framecount);
321
+            if ((frame_count != prev_framecount) || redraw) {
322
+                prev_framecount = frame_count;
323
+                sprintf(str_buff, get_string(STR_PRINTF_FRAMES), (uint16_t)frame_count);
316 324
                 str_ascii(str_buff, x_off, y_off, 1);
317 325
             }
318 326
             y_off++;

+ 1
- 0
src/window.h View File

@@ -37,6 +37,7 @@ void win_conf(void) BANKED;
37 37
 void win_debug(void) BANKED;
38 38
 void win_name(int32_t score) BANKED;
39 39
 void win_name_draw(uint16_t name, uint8_t is_black, uint8_t pos) BANKED;
40
+void win_continue(void) BANKED;
40 41
 uint8_t win_game_draw(int32_t score, uint8_t initial) BANKED;
41 42
 
42 43
 void fill_win(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t tile, uint8_t attr) BANKED;

Loading…
Cancel
Save