diff options
| author | Menase Teshale <osome3717@gmail.com> | 2026-09-22 00:07:27 +0300 |
|---|---|---|
| committer | Menase Teshale <osome3717@gmail.com> | 2026-09-22 00:08:45 +0300 |
| commit | b2b814b95769a2085652b2a51e766c4f240769d6 (patch) | |
| tree | af3e4a5e019f5c03aca0605f8214e0ccbb3b2b13 | |
| parent | 2b0803a7802b2fc842f8bdc881f5b92d8b45896d (diff) | |
Added game over menu
| -rw-r--r-- | src/game.c | 121 | ||||
| -rw-r--r-- | src/menu.c | 2 |
2 files changed, 118 insertions, 5 deletions
@@ -47,6 +47,8 @@ #define TIME_ADDED_SPRITE_START_SCALE 1.2 #define TIME_ADDED_SPRITE_MINIMUM_SCALE 0.9 +#define GAME_OVER_OPTIONS_COUNT 2 + typedef enum { linear_move_state, fall_state, @@ -108,16 +110,28 @@ typedef struct { typedef struct { float time_remaining; + float initial_time; text_sprite time_added_sprites[TIMED_MODE_NUM_TIME_ADDED_SPRITES]; int tiles_cleared; } timed_mode_data; +typedef enum { + restart_option = 0, + main_menu_option +} game_over_options; + +typedef struct { + game_over_options selected_option; +} game_over_menu; + typedef struct { bool inited; SDL_Texture* spritesheet; game_scene_state state; game_mode mode; + game_over_menu game_over_menu; + piece pieces[MAX_PIECES]; int num_pieces; @@ -143,11 +157,10 @@ typedef struct { timed_mode_data timed_mode_data; } s_game; -extern SDL_Window* window; - s_game game = {0}; extern SDL_Window* window; +extern application_state app_state; static inline float get_aspect_ratio() { return get_window_relative_ypos(1) / get_window_relative_xpos(1); @@ -311,6 +324,10 @@ void init_game(SDL_Renderer* renderer, MIX_Mixer* mixer) { game.state = intro_state; game.selected_piece_id = -1; + game.game_over_menu = (game_over_menu) { + .selected_option = restart_option + }; + fill_board(); } @@ -320,6 +337,7 @@ void init_timed_game(SDL_Renderer* renderer, MIX_Mixer* mixer, float time_remain game.mode = timed_mode; game.timed_mode_data = (timed_mode_data) { .time_remaining = time_remaining, + .initial_time = time_remaining, .tiles_cleared = 0 }; } @@ -732,6 +750,48 @@ void draw_text_sprite void draw_timed_mode(SDL_Renderer* renderer); +void draw_game_over(SDL_Renderer* renderer) { + draw_text_with_spritefont_extended(renderer, + &game.text_font, + (unsigned char*)"Game Over!", + get_window_relative_xpos(0.5), + get_window_relative_ypos(0.3), + 3 + ); + + if (game.mode == timed_mode) { + timed_mode_data* timed_mode_data = &game.timed_mode_data; + + char subheading[100]; + snprintf(subheading, 100, "Score: %d", timed_mode_data->tiles_cleared); + + draw_text_with_spritefont_extended(renderer, + &game.text_font, + (unsigned char*)subheading, + get_window_relative_xpos(0.5), + get_window_relative_ypos(0.34), + 2 + ); + } + + const game_over_menu* game_over_menu = &game.game_over_menu; + char* menu_options[] = {"Restart", "Main Menu"}; + float xpos_rel = 0.4; + for (game_over_options i = restart_option; i < GAME_OVER_OPTIONS_COUNT; i++) { + float scale = game_over_menu->selected_option == i ? 2.5 : 2; + + draw_text_with_spritefont_extended(renderer, + &game.text_font, + (unsigned char*)menu_options[i], + get_window_relative_xpos(xpos_rel), + get_window_relative_ypos(0.4), + scale + ); + + xpos_rel += 0.3; + } +} + void draw_game(SDL_Renderer* renderer) { SDL_RenderClear(renderer); @@ -755,6 +815,10 @@ void draw_game(SDL_Renderer* renderer) { draw_timed_mode(renderer); } + if (game.state == game_over_state) { + draw_game_over(renderer); + } + SDL_RenderPresent(renderer); } @@ -829,11 +893,58 @@ void piece_held_event(SDL_Event* e) { } } +static inline void game_over_select_next_option() { + game_over_menu* menu = &game.game_over_menu; + + menu->selected_option = + SDL_min((menu->selected_option + 1), GAME_OVER_OPTIONS_COUNT-1); +} + +static inline void game_over_select_previous_option() { + game_over_menu* menu = &game.game_over_menu; + + menu->selected_option = + SDL_max((menu->selected_option - 1), 0); +} + +static inline void game_over_menu_execute_action() { + game_over_menu* menu = &game.game_over_menu; + + switch (menu->selected_option) { + case main_menu_option: + app_state = menu_state; + break; + + case restart_option: + init_timed_game(NULL, NULL, game.timed_mode_data.initial_time); + break; + + default: + break; + } +} + +void game_over_event(SDL_Event* e) { + if (e->type == SDL_EVENT_KEY_DOWN) { + SDL_Scancode pressed_button = e->key.scancode; + + if (pressed_button == SDL_SCANCODE_RETURN) { + return game_over_menu_execute_action(); + } else if (pressed_button == SDL_SCANCODE_RIGHT) { + game_over_select_next_option(); + } else if (pressed_button == SDL_SCANCODE_LEFT) { + game_over_select_previous_option(); + } + } +} + void game_event(SDL_Event* e) { if (game.state == neutral_state) { neutral_state_event(e); } else if (game.state == piece_held_state) { piece_held_event(e); + } else if (game.state == game_over_state) { + game_over_event(e); } } @@ -844,8 +955,10 @@ void game_event(SDL_Event* e) { void update_timed_mode(float dt) { timed_mode_data* timed_mode_data = &game.timed_mode_data; - timed_mode_data->time_remaining = - SDL_max(timed_mode_data->time_remaining - dt, 0); + if (game.state != intro_state && game.state != swap_animation_state) { + timed_mode_data->time_remaining = + SDL_max(timed_mode_data->time_remaining - dt, 0); + } if (timed_mode_data->time_remaining <= 0) { game.state = game_over_state; @@ -66,7 +66,7 @@ SDL_AppResult menu_execute_action() { if (selected_option == exit_option) { return SDL_APP_SUCCESS; } if (selected_option == timed_mode_option) { - init_timed_game(NULL, NULL, 40); + init_timed_game(NULL, NULL, 5); app_state = game_state; } |
