#include #include #include "keyb.h" #include "vga.h" #include "sound.h" #include "text.h" #include "map.h" #include "data.h" #include "timer.h" #include "entities.h" #include "tmonster.h" #include "player.h" #include "game.h" #define GAME_LIVES_START 3 #define GAME_LIVES_MAX 9 #define GAME_TIME_MAX 60 #define GAME_MAX_PICKAXE 3 #define HUD_CLEAN 0 #define HUD_LIVES 1 #define HUD_SCORE 2 #define HUD_STAGE 4 #define HUD_TIME 8 #define HUD_PICKAXE 16 #define HUD_ALL 255 #define GAMEOVER_DELAY 96 #define STAGECLEAR_DELAY 96 static uint32_t hiscore = 15000; static uint8_t hud; static volatile uint8_t clock_updated; /* game variables */ static uint8_t lives; static uint32_t score; static uint8_t stage; static uint8_t time; static uint8_t pickaxe; static uint8_t stageclear; static uint8_t gameover; static uint8_t pause; static Entity *tmonster; static void hud_render() { char b[32]; if (hud & HUD_ALL) { Rect src = { 128, 32, 144, 144}; Rect dst = { 4, 0, 16, 16}; /* lives */ blitrc(binary_sprites_start, &src, &dst); /* pickaxe */ src.x = 112; dst.x = 90; blitrc(binary_sprites_start, &src, &dst); put_text(132, 4, "TIME", 1); put_text(249, 4, "STAGE", 1); } if (hud & HUD_LIVES) { sprintf(b, "%d", lives); put_text(18, 4, b, 1); } if (hud & HUD_SCORE) { sprintf(b, "%06li", score); put_text(34, 4, b, 5); } if (hud & HUD_PICKAXE) { sprintf(b, "%d", pickaxe); put_text(106, 4, b, 1); } if (hud & HUD_TIME) { sprintf(b, "%02d", time); put_text(172, 4, b, time > 10 || stageclear ? 1 : 15); if (!gameover && !stageclear && time <= 10) sound_queue_efx(EFX_TIME); } if (hud & HUD_STAGE) { sprintf(b, "%02d", stage + 1); put_text(297, 4, b, 1); } hud = HUD_CLEAN; } static void run_gameover() { blit_erase(0); /* restore the HUD after erasing the screen */ hud = HUD_ALL; hud_render(); put_text(124, 90, "GAME OVER", 1); wait_vsync(); blit_update(); /* wait some time */ wait_frames(255); } static void run_stageclear() { put_text(116, 100, "STAGE CLEAR", 1); wait_vsync(); blit_update(); /* wait some time */ wait_frames(96); while (time--) { add_score(25); hud |= HUD_TIME; sound_queue_efx(EFX_GOLD); hud_render(); wait_frames(4); blit_update(); sound_play_queue(); } /* wait some time */ wait_frames(64); blit_erase(0); /* restore the HUD after erasing the screen */ hud = HUD_ALL; hud_render(); wait_vsync(); blit_update(); wait_frames(32); } void run_game() { lives = GAME_LIVES_START; score = 0; stage = 0; next_stage: pause = 0; gameover = 0; stageclear = 0; pickaxe = 0; time = GAME_TIME_MAX; hud = HUD_ALL; tmonster = NULL; blit_erase(0); map_init(binary_stage_start); /* render the scene with the READY? text */ map_render(); entities_draw(); player_draw(); hud_render(); put_text(136, 100, "READY?", 1); wait_vsync(); blit_update(); /* wait some time */ wait_frames(96); /* erase the READY? text */ map_render(); entities_draw(); player_draw(); timer_start(GAME_TIME_MAX, &clock_updated); while (!keys[KEY_ESC]) { if (clock_updated) { time = timer_value(); hud |= HUD_TIME; } if (hud) hud_render(); if (keys[KEY_P]) { /* pause / resume */ pause ^= 1; /* wait for the key to be released */ while (keys[KEY_P]) wait_vsync(); if (pause) timer_stop(); else timer_resume(); } if (pause) continue; /* erase first the last we draw */ player_erase(); entities_erase(); if (map_is_complete()) { if (!stageclear) { timer_stop(); tmonster = NULL; entities_warp_out_all(); sound_queue_efx(EFX_WARP); stageclear = STAGECLEAR_DELAY; } else { stageclear--; if (stageclear == 1) { run_stageclear(); goto next_stage; } } } else { player_update(); /* time monster */ if (!time && !tmonster) { tmonster = entities_new(); if (tmonster) tmonster_init(tmonster); } if (time && tmonster) { tmonster->used = 0; tmonster = NULL; } } entities_update(); entities_draw(); player_draw(); wait_vsync(); blit_update(); sound_play_queue(); if (gameover) { gameover--; if (gameover == 1) { run_gameover(); break; } } } /* wait for ESC to be release */ while (keys[KEY_ESC]) wait_vsync(); } void add_score(uint8_t v) { score += v; hud |= HUD_SCORE; } uint32_t get_hiscore() { return hiscore; } uint8_t dec_lives() { lives--; if (lives == 0) { gameover = GAMEOVER_DELAY; timer_stop(); } hud |= HUD_LIVES; return lives; } void reset_time() { time = GAME_TIME_MAX; hud |= HUD_TIME; timer_start(GAME_TIME_MAX, &clock_updated); } void add_pickaxe() { if (pickaxe < GAME_MAX_PICKAXE) { pickaxe++; hud |= HUD_PICKAXE; } } uint8_t use_pickaxe() { if (pickaxe) { pickaxe--; hud |= HUD_PICKAXE; return 1; } return 0; }