#include "asset.h" #include "enemy.h" #include "game.h" #include "input.h" #include "platform.h" #include "sound.h" #include "sprite.h" #include "standard.h" #include "systems.h" void gameplay_new(Game* game) { World* world; world = &game->world; seed_rng(platform_get_time()); init_world(&game->world); init_map(&world->map, world); init_player(&world->player, world); init_waver(&world->waver); world->gmemory = gmemory_max; if (game->first) { game->display_wave_text = 1; game->display_tutorial = 500; game->first = 0; } else { game->display_wave_text = 0; game->display_tutorial = 0; } set_song(song_main); } void gameplay_next_wave(Game* game) { World* world; world = &game->world; next_wave(&world->waver); game_change_state(game, game_state_game); } static void menu_start(Menu* menu) { Game* game; game = menu->ptr; gameplay_new(game); game_change_state(game, game_state_game); } static void menu_restart(Menu* menu) { Game* game; game = menu->ptr; gameplay_new(game); game_change_state(game, game_state_game); } static void menu_main_menu(Menu* menu) { Game* game; game = menu->ptr; game_change_state(game, game_state_menu); } static void menu_quit(Menu* menu) { (void)menu; platform_quit(); } static void menu_credits(Menu* menu) { Game* game; game = menu->ptr; game_change_state(game, game_state_credits); } static void menu_init(Game* game) { const BM_Font* font; font = get_default_font(); set_song(song_menu); init_menu(&game->menu, game); menu_add(&game->menu, "Play", menu_start, font); menu_add(&game->menu, "Credits", menu_credits, font); menu_add(&game->menu, "Quit", menu_quit, font); } static void menu_update(Game* game) { const Sprite* msg; const Bitmap* bmp; int y; update_menu(&game->menu); y = game->menu.y; msg = get_sprite(sprite_author); bmp = get_bitmap(msg->bitmap); render_bitmap( bmp, renderer_w / 2 - msg->rect.w / 2, renderer_h - 26, &msg->rect ); msg = get_sprite(sprite_free); bmp = get_bitmap(msg->bitmap); render_bitmap( bmp, renderer_w / 2 - msg->rect.w / 2, renderer_h - 15, &msg->rect ); /* Logo. */ msg = get_sprite(sprite_logo); bmp = get_bitmap(msg->bitmap); render_bitmap( bmp, renderer_w / 2 - msg->rect.w / 2, y - msg->rect.h - 8, &msg->rect ); render_menu(&game->menu, get_default_font()); } static void menu_deinit(Game* game) { } static void gameplay_init(Game* game) { if (!game->display_tutorial) { start_wave(&game->world); } game->want_next = 0; game->wave_timer = 0; if (!game->display_wave_text) { game->display_wave_text = 100; } } static void render_hud(Game* game) { int i, g; const Sprite* sprite; const Bitmap* bitmap; World* world; Player* player; world = &game->world; player = &world->player; sprite = get_sprite(sprite_heart_full); bitmap = get_bitmap(sprite->bitmap); for (i = 0; i < player->hp; i++) { render_bitmap( bitmap, 1 + i * (sprite->rect.w + 1), 1, &sprite->rect ); } sprite = get_sprite(sprite_heart_empty); bitmap = get_bitmap(sprite->bitmap); for (; i < player_max_hp; i++) { render_bitmap( bitmap, 1 + i * (sprite->rect.w + 1), 1, &sprite->rect ); } sprite = get_sprite(sprite_ram_full); bitmap = get_bitmap(sprite->bitmap); g = world->gmemory / gmemory_units; for (i = 0; i < g; i++) { render_bitmap( bitmap, 1 + i * (sprite->rect.w + 1), 8, &sprite->rect ); } sprite = get_sprite(sprite_ram_empty); bitmap = get_bitmap(sprite->bitmap); g = gmemory_max / gmemory_units; for (; i < g; i++) { render_bitmap( bitmap, 1 + i * (sprite->rect.w + 1), 8, &sprite->rect ); } } static void gameplay_update(Game* game) { int cx, cy, ec, l; World* world; Player* player; const Waver* waver; const BM_Font* font; Colour col; char buf[32]; world = &game->world; player = &world->player; waver = &world->waver; cx = world->cam_x; cy = world->cam_y; font = get_default_font(); if (world->wave_started) { update_waver(&world->waver, world); } ec = wave_enemy_count(&world->waver); if ( world->enemies_killed >= ec && !game->want_next ) { if (waver->idx >= get_wave_count() - 1) { game_change_state(game, game_state_win); } game->wave_timer = 0; game->want_next = 1; } if (game->want_next && game->wave_timer > 200) { gameplay_next_wave(game); } update_player(player, world); enemy_system(world); debris_system(world); bullet_system(world); collision_system(world); spawner_system(world); animation_system(world); update_camera(player, world); render_map(&world->map, cx, cy); sprite_system(world); if (game->display_wave_text) { col = make_colour(0x7f8dcf, 255); buf[0] = 'W'; buf[1] = 'a'; buf[2] = 'v'; buf[3] = 'e'; buf[4] = ' '; l = 5 + int_to_buf(world->waver.idx + 1, buf + 5); rfont_text_col( font, renderer_w / 2 - (l * font->char_w) / 2, renderer_h / 2, buf, col ); game->display_wave_text--; } if (game->display_tutorial) { col = make_colour(0x7f8dcf, 255); rfont_text_col( font, 100, 25, "^ Memory", col ); rfont_text_col( font, renderer_w / 2 - 115, renderer_h - 50, "Arrows/D-pad ~ Movement", col ); rfont_text_col( font, renderer_w / 2 - 115, renderer_h - 40, " X ~ Shoot", col ); col = make_colour(0xa7a6c1, 255); rfont_text_col( font, renderer_w / 2 - 135, renderer_h - 25, "Kill them; they use memory!", col ); game->display_tutorial--; if (!game->display_tutorial) { game->display_wave_text = 100; start_wave(world); } } game->wave_timer++; render_hud(game); if (world->gmemory <= 0) { world->oom = 1; game_change_state(game, game_state_dead); } } static void gameplay_deinit(Game* game) { } static void credits_init(Game* game) { } static void credits_update(Game* game) { const BM_Font* font; font = get_default_font(); if ( button_just_pressed(btn_shoot) || button_just_pressed(btn_jump) ) { game_change_state(game, game_state_menu); } rfont_text(font, 0, 0, "Programming: quou"); rfont_text(font, 0, 10, "Design: quou"); rfont_text(font, 0, 20, "Sound: quou"); rfont_text(font, 0, 30, "Graphics: quou"); rfont_text(font, 0, 40, "Music: tejeez"); rfont_text(font, 0, 50, "Source Code: git.quou.xyz"); } static void credits_deinit(Game* game) { } static void dead_init(Game* game) { const BM_Font* font; Menu* menu; set_song(song_dead); menu = &game->menu; font = get_default_font(); init_menu(menu, game); menu_add(menu, "Restart", menu_restart, font); menu_add(menu, "Main Menu", menu_main_menu, font); } static void dead_update(Game* game) { const BM_Font* font; int cx, cy; World* world; font = get_default_font(); world = &game->world; update_menu(&game->menu); cx = game->world.cam_x; cy = game->world.cam_y; render_map(&game->world.map, cx, cy); sprite_system(&game->world); render_hud(game); if (world->oom) { rfont_text( font, renderer_w / 2 - 65, game->menu.y - 15, "Out of Memory" ); } else { rfont_text( font, renderer_w / 2 - 40, game->menu.y - 15, "You died" ); } render_menu(&game->menu, get_default_font()); } static void dead_deinit(Game* game) { } static void win_init(Game* game) { const BM_Font* font; Menu* menu; set_song(song_win); menu = &game->menu; font = get_default_font(); init_menu(menu, game); menu_add(menu, "Main Menu", menu_main_menu, font); game->fading = 0; game->fade_frame = 0; game->fade_timer = 0; game->wait_timer = 50; game->wait_timer2 = 20; } static void update_fade(Game* game) { int x, y, w, h, w0, h0; const Bitmap* bitmap; const Animation* animation; const Rectangle* rect; bitmap = get_bitmap(asset_id_usr); animation = get_animation(animation_fade); rect = &animation->frames[game->fade_frame]; w0 = rect->w; h0 = rect->h; w = renderer_w / w0; h = renderer_h / h0; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { render_bitmap(bitmap, x * w0, y * h0, rect); } } game->fade_timer++; if (game->fade_timer >= animation->slowness) { game->fade_frame++; game->fade_timer = 0; if (game->fade_frame >= animation->frame_count) { game->fading = 0; game->wait_timer2 = 20; } } } static void win_update(Game* game) { const BM_Font* font; Menu* menu; int cx, cy; World* world; Colour col; font = get_default_font(); world = &game->world; menu = &game->menu; cx = game->world.cam_x; cy = game->world.cam_y; if (game->fading) { render_map(&game->world.map, cx, cy); sprite_system(&game->world); render_hud(game); update_fade(game); } else if (game->wait_timer > 0) { render_map(&game->world.map, cx, cy); sprite_system(&game->world); render_hud(game); } else { game->wait_timer2--; } col = make_colour(0xc00000, 255); rfont_text_col( font, renderer_w / 2 - 40, menu->y - 15, "YOU WIN", col ); if (game->wait_timer2 < 0) { rfont_text( font, renderer_w / 2 - 118, menu->y + menu->h + 15, "Thank-you for playing \177" ); col = make_colour(0x767593, 255); rfont_text_col( font, renderer_w / 2 - 70, menu->y + menu->h + 25, " ~ quou - quou.xyz", col ); update_menu(menu); render_menu(menu, font); } game->wait_timer--; if (game->wait_timer == 0) { game->fading = 1; game->wait_timer = -1; } } static void win_deinit(Game* game) { } static const Game_State_Fns game_state_fns[] = { /* game_state_menu */ { menu_init, menu_update, menu_deinit }, /* game_state_game */ { gameplay_init, gameplay_update, gameplay_deinit }, /* game_state_credits */ { credits_init, credits_update, credits_deinit }, /* game_state_dead */ { dead_init, dead_update, dead_deinit }, { win_init, win_update, win_deinit } }; static const Game_State_Fns* get_state_fns(Game_State state) { return &game_state_fns[state]; } void game_init(Game* game, Game_State state) { game->state = state; game->fns = get_state_fns(state); game->fns->state_init(game); game->first = 1; } void game_update(Game* game) { game->fns->state_update(game); } void game_deinit(Game* game) { game->fns->state_deinit(game); } void game_change_state(Game* game, Game_State state) { game->fns->state_deinit(game); game->state = state; game->fns = get_state_fns(state); game->fns->state_init(game); }