summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMenase Teshale <osome3717@gmail.com>2026-09-22 00:07:27 +0300
committerMenase Teshale <osome3717@gmail.com>2026-09-22 00:08:45 +0300
commitb2b814b95769a2085652b2a51e766c4f240769d6 (patch)
treeaf3e4a5e019f5c03aca0605f8214e0ccbb3b2b13
parent2b0803a7802b2fc842f8bdc881f5b92d8b45896d (diff)
Added game over menu
-rw-r--r--src/game.c121
-rw-r--r--src/menu.c2
2 files changed, 118 insertions, 5 deletions
diff --git a/src/game.c b/src/game.c
index 82f3b48..eef1328 100644
--- a/src/game.c
+++ b/src/game.c
@@ -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;
diff --git a/src/menu.c b/src/menu.c
index ebf5718..74e91ef 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -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;
}