5#include "background_game_over_gfx.h"
22#define RED_BTN_MAIN_COLOR_PAL_IDX 6
23#define BLUE_BTN_MAIN_COLOR_PAL_IDX 7
24#define REUSE_SEED_BTN_OUTLINE_PAL_IDX 8
25#define NEW_RUN_BTN_OUTLINE_PAL_IDX 9
26#define MAIN_MENU_BTN_OUTLINE_PAL_IDX 10
27#define ENDLESS_BTN_OUTLINE_PAL_IDX 11
37static const Rect GAME_OVER_ANIM_RECT = { 3, 5, 26, 31};
39static const Rect GAME_OVER_TEXT_TILES_SRC_RECT_1 = { 27, 24, 31, 25};
40static const Rect GAME_OVER_TEXT_TILES_SRC_RECT_2 = { 27, 26, 31, 27};
41static const BG_POINT GAME_OVER_TEXT_TILES_DEST_POS_1 = { 10, 21};
42static const BG_POINT GAME_OVER_TEXT_TILES_DEST_POS_2 = { 15, 21};
44static const Rect DEFEATED_BY_TEXT_SRC_RECT = { 28, 30, 31, 31};
45static const BG_POINT DEFEATED_BY_TEXT_DEST_POS = { 22, 24};
46static const BG_POINT DEFEATED_BY_TOKEN_INIT_POS = {180, 207};
48static const Rect REUSE_SEED_BTN_OFF_SRC_RECT = { 28, 28, 29, 29};
49static const Rect REUSE_SEED_BTN_ON_SRC_RECT = { 30, 28, 31, 29};
50static const BG_POINT REUSE_SEED_BTN_DEST_POS = { 4, 11};
52static const Rect BEST_HAND_SCORE_RECT = {126, 64, 166, 72};
53static const Rect MOST_PLAYED_HAND_RECT = {112, 80, 168, 88};
54static const BG_POINT SEED_VALUE_POS = {112, 96};
56static const BG_POINT NEW_RUN_BTN_TEXT_POS = { 48, 112};
57static const BG_POINT MAIN_MENU_BTN_TEXT_POS = {120, 112};
60static const u32 GAME_OVER_ANIM_FRAMES = 17;
61static const mm_byte GAME_OVER_SFX_VOL = 178;
62static const mm_word GAME_OVER_WHOOSH_RATE = 922;
69 GAME_OVER_RUN_MENU_ROW,
73#define GAME_OVER_SEED_BTN_COL 0
74#define GAME_OVER_NEW_RUN_BTN_COL 0
75#define GAME_OVER_MAIN_MENU_BTN_COL 1
77static int game_over_get_row_size1(
void)
81static int game_over_get_row_size2(
void)
86static void game_over_on_key_transit(
SelectionGrid* selection_grid, Selection* selection);
87static bool game_over_on_selection_changed(
90 const Selection* prev_selection,
91 const Selection* new_selection
95 {GAME_OVER_SEED_ROW, game_over_get_row_size1, game_over_on_selection_changed, game_over_on_key_transit, {.wrap =
false}},
96 {GAME_OVER_RUN_MENU_ROW, game_over_get_row_size2, game_over_on_selection_changed, game_over_on_key_transit, {.wrap =
false}}
99static const Selection GAME_OVER_INIT_SEL = {0, GAME_OVER_RUN_MENU_ROW};
101 game_over_selection_rows,
108static void reuse_seed_on_pressed(
void);
109static void new_run_on_pressed(
void);
110static void main_menu_on_pressed(
void);
111static Button* game_over_get_button_from_sel(
const Selection* selection);
114static Button game_over_buttons[GAME_OVER_ROW_MAX][2] = {
117 { REUSE_SEED_BTN_OUTLINE_PAL_IDX, RED_BTN_MAIN_COLOR_PAL_IDX, reuse_seed_on_pressed, NULL }
121 { NEW_RUN_BTN_OUTLINE_PAL_IDX, RED_BTN_MAIN_COLOR_PAL_IDX, new_run_on_pressed, NULL },
122 { MAIN_MENU_BTN_OUTLINE_PAL_IDX, RED_BTN_MAIN_COLOR_PAL_IDX, main_menu_on_pressed, NULL }
129static enum EndCondition s_end_condition = END_CONDITION_NONE;
130static u32 s_timer = TM_ZERO;
131static bool s_reuse_seed =
false;
132static bool s_continue_run =
false;
134static void game_over_common_init(
enum EndCondition init_condition)
136 s_end_condition = init_condition;
138 s_reuse_seed =
false;
139 s_continue_run =
false;
146 obj_hide(joker_object->sprite->obj);
151 while (get_deck_top() >= 0)
159 GRIT_CPY(pal_bg_mem, background_game_over_gfxPal);
160 GRIT_CPY(&tile_mem[MAIN_BG_CBB], background_game_over_gfxTiles);
161 GRIT_CPY(&se_mem[MAIN_BG_SBB], background_game_over_gfxMap);
165 g_game_vars.playing_blind_token,
166 DEFEATED_BY_TOKEN_INIT_POS.x,
167 DEFEATED_BY_TOKEN_INIT_POS.y
171 game_over_selection_grid.selection = GAME_OVER_INIT_SEL;
174 &game_over_buttons[GAME_OVER_RUN_MENU_ROW][GAME_OVER_NEW_RUN_BTN_COL],
178 &game_over_buttons[GAME_OVER_RUN_MENU_ROW][GAME_OVER_MAIN_MENU_BTN_COL],
187 game_over_common_init(END_CONDITION_WIN);
194 play_sfx(SFX_WHOOSH2_LOSE, GAME_OVER_WHOOSH_RATE, GAME_OVER_SFX_VOL);
198 game_over_common_init(END_CONDITION_LOSS);
218 if (s_timer < GAME_OVER_ANIM_FRAMES)
223 g_game_vars.playing_blind_token,
224 g_game_vars.playing_blind_token->
pos.x,
230 else if (s_timer == GAME_OVER_ANIM_FRAMES)
232 char best_hand_str[UINT_MAX_DIGITS + 1];
234 g_game_vars.best_hand_score,
238 Rect best_hand_rect = BEST_HAND_SCORE_RECT;
241 "#{P:%d,%d; cx:0x%X000}%s",
249 enum HandType most_played_hand = HIGH_CARD;
250 for (
enum HandType hand_type = PAIR; hand_type <= HAND_TYPE_MAX; hand_type++)
252 if (g_game_vars.nb_played_hands[hand_type - 1] >
253 g_game_vars.nb_played_hands[most_played_hand - 1])
254 most_played_hand = hand_type;
257 const char* hand_name_str = get_hand_type_name(most_played_hand);
258 Rect hand_type_rect = MOST_PLAYED_HAND_RECT;
261 "#{P:%d,%d; cx:0x%X000}%s",
269 char seed_str[BASE36_MAX_DIGITS + 1] = {
'\0'};
272 "#{P:%d,%d; cx:0x%X000}%s",
281 "#{P:%d,%d; cx:0x%X000}New Run",
282 NEW_RUN_BTN_TEXT_POS.x,
283 NEW_RUN_BTN_TEXT_POS.y,
287 "#{P:%d,%d; cx:0x%X000}Main Menu",
288 MAIN_MENU_BTN_TEXT_POS.x,
289 MAIN_MENU_BTN_TEXT_POS.y,
294 if (s_timer >= GAME_OVER_ANIM_FRAMES)
303 s_end_condition = END_CONDITION_NONE;
305 u32 previous_seed = g_game_vars.rng_info.
seed;
313 g_game_vars.rng_info.
seed = UNDEFINED;
318static Button* game_over_get_button_from_sel(
const Selection* selection)
320 return &game_over_buttons[selection->y][selection->x];
323static void game_over_on_key_transit(
SelectionGrid* selection_grid, Selection* selection)
325 if (key_hit(SELECT_CARD))
326 button_press(&game_over_buttons[selection->y][selection->x]);
329static bool game_over_on_selection_changed(
332 const Selection* prev_selection,
333 const Selection* new_selection
336 if (row_idx == prev_selection->y)
339 if (row_idx == new_selection->y)
347static void reuse_seed_on_pressed(
void)
349 s_reuse_seed = !s_reuse_seed;
351 s_reuse_seed ? REUSE_SEED_BTN_ON_SRC_RECT : REUSE_SEED_BTN_OFF_SRC_RECT,
352 REUSE_SEED_BTN_DEST_POS
356static void new_run_on_pressed(
void)
358 game_change_state(GAME_STATE_RUN_SETUP);
361static void main_menu_on_pressed(
void)
363 game_change_state(GAME_STATE_MAIN_MENU);
Utilities for affine background on GBA.
void affine_background_set_color(COLOR color)
Update the affine background color.
Utilities for using maxmod to play sound effects.
void play_regular_music(void)
Play music at a normal pitch and tempo.
void play_lose_music(void)
Play music at a low pitch and slow tempo (lose screen)
#define MM_BASE_PITCH_RATE
The default pitch rate for the sound effect played.
void play_sfx(mm_word id, mm_word rate, mm_byte volume)
Play a sound effect, wrapper for mmEffectEx() See https://maxmod.org/ref/functions/mm_sound_effect....
#define SFX_DEFAULT_VOLUME
Default volume for sound effects.
Game Over screen state functions.
void game_lose_on_init(void)
Game Over screen state initialization when losing.
void game_over_on_update(void)
Game Over screen state update.
void game_over_on_exit(void)
Game Over screen cleanup, common to both losing and winning.
void game_win_on_init(void)
Game Over screen state initialization when winning.
Graphic utility functions.
void main_bg_se_move_rect_1_tile_vert(Rect se_rect, enum ScreenVertDir direction)
Moves a rect in the main background vertically in direction by a single tile.
void main_bg_se_copy_rect(Rect se_rect, BG_POINT dest_pos)
Copies a rect in the main background from se_rect to the position (x, y).
void toggle_windows(bool win0, bool win1)
Toggles the visibility of the window layers.
void update_text_rect_to_center_str(Rect *rect, const char *str, enum ScreenHorzDir bias_direction)
Updates a rect so a string is centered within it.
#define TILE_SIZE
Tile size in pixels, both height and width as tiles are square.
#define TTE_CHAR_SIZE
By default TTE characters occupy a single tile.
INLINE int rect_width(const Rect *rect)
Get the width of a rectangle.
Functions relative to manipulating and analyzing the contents of the Hand, a.k.a. the Cards we hold a...
Functions relative to the handling of Jokers.
Header of shared rects and points needed for ui.
void * list_itr_next(ListItr *itr)
ListItr list_itr_create(List *list)
Common functions to handle RNG manipulation. Using this interface has three goals:
void rng_set_seed(u32 seed)
Set the rng seed to the chosen value, and reset the step counter to 0. The seed will be capped at MAX...
An implementation for a selection grid that handles directional selection.
void selection_grid_process_input(SelectionGrid *selection_grid)
Processes user input for the selection grid.
INLINE void sprite_position(Sprite *sprite, int x, int y)
Set sprite position. Inlined for efficiency.
The core selection grid struct, represents the grid itself and its state.
POINT pos
Sprite position on screen in pixels.
Utilities relating around number string representation and protected arithmatic helper functions.
void truncate_uint_to_suffixed_str(uint32_t num, int num_req_chars, char out_str_buff[UINT_MAX_DIGITS+1])
Truncate an unsigned number into a suffixed string representation e.g. 12000 -> "12K" The least signi...
void u32_to_base36(uint32_t n, char b36_str[])
Convert a 32-bit unsigned integer to its base-36 string representation. This will perform 6 divisions...