#include "animation.h" #include "asset.h" #include "game.h" #include "plat.h" #include "render.h" #include "str.h" const Rect logo_rect = { 47, 0, 54, 16 }; void init_game(Game* g, Game_State s) { World* w = &g->w; g->st = s; g->frame = 0; g->want_next = 0; g->kills = 0; g->cfloor = 0; init_world(w); } void update_menu(Game* g, App* a) { int i; for (i = 0; i < btn_count; i++) if (a->btn_states[i] & btn_state_pressed) { queue_gs(g, game_state_fade_out); queue_gs(g, game_state_reset); queue_gs(g, game_state_compute_ec); queue_gs(g, game_state_reset); queue_gs(g, game_state_restart); queue_gs(g, game_state_generate_intro); queue_gs(g, game_state_fade_in); queue_gs(g, game_state_intro); g->want_next = 1; return; } } void update_gameover(Game* g, App* a) { int i; for (i = 0; i < btn_count; i++) if (a->btn_states[i] & btn_state_pressed) { queue_gs(g, game_state_fade_out); queue_gs(g, game_state_reset); queue_gs(g, game_state_compute_ec); queue_gs(g, game_state_reset); queue_gs(g, game_state_restart); queue_gs(g, game_state_generate_intro); queue_gs(g, game_state_fade_in); queue_gs(g, game_state_intro); g->want_next = 1; return; } } void queue_gs(Game* g, Game_State s) { assert(g->qt < game_max_state_queue); g->sq[g->qt++] = s; } void on_transition(Game* g) { g->ff = 0; } void next_gs(Game* g) { int i, e = --g->qt; g->ps = g->st; g->st = g->sq[0]; for (i = 0; i < e; i++) g->sq[i] = g->sq[i + 1]; on_transition(g); } int detect_next(Game* g, const World* w) { const Player* p = &w->player; if (p->y < 0) /* next level */ { queue_gs(g, game_state_fade_out); queue_gs(g, game_state_next); queue_gs(g, game_state_reset); queue_gs(g, game_state_restore_player); if (g->cfloor + 1 >= room_count()) { queue_gs(g, game_state_generate_outro); queue_gs(g, game_state_fade_in); queue_gs(g, game_state_outro); } else { queue_gs(g, game_state_generate); queue_gs(g, game_state_fade_in); queue_gs(g, game_state_play); } g->want_next = 1; return 1; } return 0; } int detect_gameover(Game* g, const World* w) { const Player* p = &w->player; if (p->hp <= 0) { queue_gs(g, game_state_fade_out); queue_gs(g, game_state_generate); queue_gs(g, game_state_fade_in); queue_gs(g, game_state_over); g->want_next = 1; return 1; } return 0; } int detect_start(Game* g, const World* w) { if (w->player.x < (30 << fbits)) { queue_gs(g, game_state_fade_out); queue_gs(g, game_state_reset); queue_gs(g, game_state_generate); queue_gs(g, game_state_fade_in); queue_gs(g, game_state_play); g->want_next = 1; return 1; } return 0; } int compute_ec(World* w) { int i, e = room_count(); int c = 0; for (i = 0; i < e; i++) { init_world(w); generate_floor(&w->map, w, i); c += w->enemy_count; } return c; } void update_game(Game* g, App* a) { const Animation* fa; if (g->want_next) { next_gs(g); g->want_next = 0; } switch (g->st) { case game_state_menu: update_menu(g, a); break; case game_state_over: update_gameover(g, a); break; case game_state_fade_in: fa = get_animation(asset_id_fade_in_anm); if (g->ff < fa->fc * fa->s - 1) update_anim(fa, &g->ff, &g->fr); else g->want_next = 1; break; case game_state_fade_out: fa = get_animation(asset_id_fade_out_anm); if (g->ff < fa->fc * fa->s - 1) update_anim(fa, &g->ff, &g->fr); else g->want_next = 1; break; case game_state_restart: g->cfloor = 0; g->kills = 0; g->want_next = 1; break; case game_state_reset: g->hp = g->w.player.hp; g->ch = g->w.player.charge; init_world(&g->w); g->want_next = 1; break; case game_state_restore_player: g->w.player.hp = g->hp; g->w.player.charge = g->ch; g->hp = -1; g->want_next = 1; break; case game_state_next: g->cfloor++; g->kills += g->w.kills; g->want_next = 1; break; case game_state_generate: generate_floor(&g->w.map, &g->w, g->cfloor); g->want_next = 1; break; case game_state_play: update_world(&g->w, a); if (detect_next(g, &g->w)) break; detect_gameover(g, &g->w); break; case game_state_generate_intro: generate_intro(&g->w.map, &g->w); g->want_next = 1; break; case game_state_generate_outro: generate_outro(&g->w.map, &g->w); g->want_next = 1; break; case game_state_compute_ec: g->me = compute_ec(&g->w); g->want_next = 1; break; case game_state_intro: update_world(&g->w, a); detect_start(g, &g->w); break; case game_state_outro: update_world(&g->w, a); break; } g->frame++; } void ren_menu(const Game* g, Renderer* r) { const Bitmap* bm = get_bitmap(asset_id_hud_img); const int hv = viewport_w >> 1; ren_map( r, hv - (logo_rect.w >> 1), 100, &logo_rect, bm ); if (g->frame & 3) ren_text( r, hv - 38, 155, "ANY BUTTON TO START" ); ren_text( r, hv - 24, 200, "made by quou" ); ren_text( r, hv - 44, 205, "public domain software" ); ren_text( r, hv - 16, 210, "quou.xyz" ); } void ren_gameover(const Game* g, Renderer* r) { const int hv = viewport_w >> 1; ren_text( r, hv - 32, 100, "G A M E O V E R" ); if (g->frame & 3) ren_text( r, hv - 38, 155, "ANY BUTTON TO RESET" ); } void ren_state(const Game* g, Game_State s, Renderer* r) { switch (s) { case game_state_menu: ren_menu(g, r); break; case game_state_over: ren_gameover(g, r); break; case game_state_generate: break; case game_state_outro: { char buf[32]; int x = 228; ren_text(r, 200, 100, "YOU REACHED THE TOP!"); ren_text(r, 200, 105, "Kills: "); int_to_buf(g->kills, buf); ren_text(r, x, 105, buf); x += string_len(buf) * 4; ren_text(r, x, 105, "/"); int_to_buf(g->me, buf); ren_text(r, x + 4, 105, buf); } /* fall through */ case game_state_intro: case game_state_play: ren_world(&g->w, r); break; default: break; } } void ren_fade(const Game* g, Renderer* r) { const Bitmap* bm = get_bitmap(asset_id_hud_img); const Rect* re = &g->fr; int x, y; for (y = 0; y < viewport_h; y += re->h) for (x = 0; x < viewport_w; x += re->w) ren_cmap(r, x, y, re, bm); } void ren_game(const Game* g, Renderer* r) { switch (g->st) { case game_state_fade_in: ren_state(g, g->sq[1], r); ren_fade(g, r); break; case game_state_fade_out: ren_state(g, g->ps, r); ren_fade(g, r); break; default: ren_state(g, g->st, r); } }