Refactor/round end (#479)

* Initial round_end extraction

* move hands to game vars

* Checkpoint

* Finish removing all variables for state fns

* Move over round_end substate functions

* Move over round_end with compile

* working in general

* Fix round start state issue

* clang-format

* Fix clang format issue

* PR fixes and standardize types in game vars struct

* Clang-format
This commit is contained in:
Rickey
2026-05-13 18:22:02 -07:00
committed by GitHub
parent 57ec84fcc7
commit b1c2b7f35e
10 changed files with 606 additions and 547 deletions
+66 -532
View File
@@ -15,6 +15,7 @@
#include "game/game_over.h"
#include "game/main_menu.h"
#include "game/options_menu.h"
#include "game/round_end.h"
#include "game_variables.h"
#include "graphic_utils.h"
#include "hand_analysis.h"
@@ -38,13 +39,10 @@
#define STRAIGHT_AND_FLUSH_SIZE_DEFAULT 5
// Pixel sizes
#define ITEM_SHOP_Y 71
#define ROUND_END_REWARD_AMOUNT_X 168
#define ROUND_END_REWARD_TEXT_X 88
#define SCORED_CARD_TEXT_Y 48
#define ITEM_SHOP_Y 71
#define SCORED_CARD_TEXT_Y 48
// SE sizes
#define ROUND_END_BLACK_PANEL_INIT_BOTTOM_SE 12
#define SHOP_LIGHTS_1_CLR 0xFFFF
#define SHOP_LIGHTS_2_CLR 0x32BE
@@ -65,22 +63,10 @@
#define CARD_FOCUSED_SEL_Y 20
// Timer defs
#define TM_RESET_STATIC_VARS 30
#define TM_END_POP_MENU_ANIM 13
#define TM_START_ROUND_END_REWARDS_ANIM 1
#define TM_END_DISPLAY_FIN_BLIND 30
#define TM_END_DISPLAY_SCORE_MIN 4
#define TM_REWARDS_ELLIPSIS_PRINT_START 2
#define TM_REWARDS_ELLIPSIS_PRINT_END 16
#define TM_REWARD_DISPLAY_INTERVAL 15
#define TM_DISPLAY_REWARDS_CONT_WAIT (TM_REWARDS_ELLIPSIS_PRINT_END + TM_REWARD_DISPLAY_INTERVAL)
#define TM_HAND_REWARD_INCR_WAIT (TM_DISPLAY_REWARDS_CONT_WAIT + TM_REWARD_DISPLAY_INTERVAL)
#define TM_REWARD_INCREMENT_INTERVAL 20
#define TM_DISMISS_ROUND_END_TM 20
#define TM_CREATE_SHOP_ITEMS_WAIT 1
#define TM_SHIFT_SHOP_ICON_WAIT 7
#define TM_END_GAME_SHOP_INTRO 12
#define TM_SHOP_PRC_INPUT_START 1
#define TM_CREATE_SHOP_ITEMS_WAIT 1
#define TM_SHIFT_SHOP_ICON_WAIT 7
#define TM_END_GAME_SHOP_INTRO 12
#define TM_SHOP_PRC_INPUT_START 1
// TODO: Rename "PID" to "PAL_IDX"
// Palette IDs
@@ -98,7 +84,6 @@
#define SHOP_LIGHTS_3_PID 17
#define BLIND_BG_SECONDARY_PID 18
#define BLIND_BG_PRIMARY_PID 19
#define REWARD_PANEL_BORDER_PID 19
#define SHOP_LIGHTS_4_PID 22
#define SHOP_BOTTOM_PANEL_BORDER_PID 26
@@ -140,20 +125,6 @@ enum GameShopStates
GAME_SHOP_MAX
};
enum GameRoundEndStates
{
ROUND_END_START,
START_EXPAND_POPUP,
DISPLAY_FINISHED_BLIND,
DISPLAY_SCORE_MIN,
UPDATE_BLIND_REWARD,
BLIND_PANEL_EXIT,
DISPLAY_REWARDS,
DISPLAY_CASHOUT,
DISMISS_ROUND_END_PANEL,
ROUND_END_EXIT
};
typedef struct
{
u32 chips;
@@ -178,29 +149,15 @@ static void noop(void)
// reviewer(s).
static void game_round_on_init(void);
static void game_playing_on_update(void);
static void game_round_end_on_update(void);
static void game_round_end_on_exit(void);
static void game_shop_on_update(void);
static void game_shop_on_exit(void);
static void game_shop_intro(void);
static void game_shop_process_user_input(void);
static void game_shop_outro(void);
static void game_round_end_start(void);
static void game_round_end_start_expand_popup(void);
static void game_round_end_display_finished_blind(void);
static void game_round_end_display_score_min(void);
static void game_round_end_update_blind_reward(void);
static void game_round_end_panel_exit(void);
static void game_round_end_display_rewards(void);
static void game_round_end_display_cashout(void);
static void game_round_end_dismiss_round_end_panel(void);
static void sort_cards(void);
static void display_temp_score(u32 value);
static void display_score(u32 value);
static void check_flaming_score(void);
static void display_hands(int value);
static void display_discards(int value);
static void set_hand(void);
static int deck_get_size(void);
static int deck_get_max_size(void);
@@ -209,7 +166,6 @@ static bool check_and_score_joker_for_event(
CardObject* card_object,
enum JokerEvent joker_event
);
static int calculate_interest_reward(void);
static void game_playing_discard_on_pressed(void);
static void game_playing_execute_discard(void);
@@ -269,7 +225,6 @@ static void game_shop_create_items(void);
static void erase_price_under_sprite_object(SpriteObject* sprite_object);
static void print_price_under_sprite_object(SpriteObject* sprite_object, int price);
static void game_round_end_extend_black_panel_down(int black_panel_bottom);
static void remove_owned_joker(int owned_joker_idx);
@@ -292,8 +247,6 @@ static bool can_discard_hand(void);
// This is because when popping, the target position is blank so we just animate
// the whole rect so we don't have to track its position
static const Rect ROUND_END_MENU_RECT = {9, 7, 24, 20 };
static const Rect HAND_BG_RECT_SELECTING = {9, 11, 24, 17 };
/* Contains the shop icon/current blind etc.
@@ -306,9 +259,6 @@ static const Rect HAND_BG_RECT_SELECTING = {9, 11, 24, 17 };
static const BG_POINT TOP_LEFT_BLIND_TITLE_POINT = {0, 21, };
static const Rect BIG_BLIND_TITLE_SRC_RECT = {0, 26, 8, 26 };
static const Rect BOSS_BLIND_TITLE_SRC_RECT = {0, 27, 8, 27 };
static const Rect CASHOUT_DEST_RECT = {10, 8, 23, 10 };
static const BG_POINT CASHOUT_SRC_3X3_RECT_POS = {5, 29};
static const BG_POINT ROUND_END_REWARDS_ELLIPSIS_POS = {10, 13};
// Flaming score animation frames
#define SCORE_FLAMES_ANIM_FREQ 5 // animation will run at 12FPS
@@ -320,7 +270,6 @@ static const BG_POINT SCORE_FLAME_CHIPS_POS = {1, 9};
static const BG_POINT SCORE_FLAME_MULT_POS = {5, 9};
// Rects for TTE (in pixels)
static const Rect HAND_SIZE_RECT = {128, 128, 152, 160 }; // Seems to include both SELECT and PLAYING
static const Rect HAND_SIZE_RECT_SELECT = {128, 128, 152, 136 };
static const Rect HAND_SIZE_RECT_PLAYING = {128, 152, 152, 160 };
static const Rect HAND_TYPE_RECT = {8, 64, 64, 72 };
@@ -330,12 +279,9 @@ static const Rect SCORE_RECT = {24, 48, 64, 56 };
static const Rect PLAYED_CARDS_SCORES_RECT = {72, 48, 240, 56 };
static const Rect HELD_CARDS_SCORES_RECT = {72, 108, 240, 116 };
static const Rect BLIND_TOKEN_TEXT_RECT = {80, 72, 200, 160 };
static const Rect MONEY_TEXT_RECT = {8, 120, 64, 128 };
static const Rect CHIPS_TEXT_RECT = {8, 80, 32, 88 };
static const Rect MULT_TEXT_RECT = {40, 80, 64, 88 };
static const Rect BLIND_REWARD_RECT = {40, 32, 64, 40 };
static const Rect BLIND_REQ_TEXT_RECT = {32, 24, 64, 32 };
static const Rect SHOP_PRICES_TEXT_RECT = {72, 56, 192, 160 };
// Rects with UNDEFINED are only used in tte_printf, they need to be fully defined
@@ -345,9 +291,6 @@ static const Rect DISCARDS_TEXT_RECT = {48, 104, UNDEFINED, UNDEF
static const Rect DECK_SIZE_RECT = {200, 152, 240, 160 };
static const Rect ROUND_TEXT_RECT = {48, 144, UNDEFINED, UNDEFINED };
static const Rect ANTE_TEXT_RECT = {8, 144, UNDEFINED, UNDEFINED };
static const Rect ROUND_END_BLIND_REQ_RECT = {104, 96, 136, UNDEFINED };
static const Rect ROUND_END_BLIND_REWARD_RECT = { 168, 96, UNDEFINED, UNDEFINED };
static const Rect CASHOUT_TEXT_RECT = {88, 72, UNDEFINED, UNDEFINED };
static const Rect SHOP_REROLL_RECT = {88, 96, UNDEFINED, UNDEFINED };
static const BG_POINT HELD_JOKERS_POS = {108, 10};
@@ -452,18 +395,6 @@ static const SubStateActionFn shop_state_actions[] = {
game_shop_outro
};
static const SubStateActionFn round_end_state_actions[] = {
game_round_end_start,
game_round_end_start_expand_popup,
game_round_end_display_finished_blind,
game_round_end_display_score_min,
game_round_end_update_blind_reward,
game_round_end_panel_exit,
game_round_end_display_rewards,
game_round_end_display_cashout,
game_round_end_dismiss_round_end_panel
};
static int reroll_cost = REROLL_BASE_COST;
// The current game state, this is used to determine what the game is doing at any given time
@@ -490,6 +421,13 @@ GameVariables g_game_vars = {
BLIND_STATE_UPCOMING
},
.hands = 0,
.discards = 0,
.score = 0,
.playing_blind_token = NULL,
.round_end_blind_token = NULL,
.game_speed = DEFAULT_GAME_SPEED,
.high_contrast = DEFAULT_HIGH_CONTRAST,
.music_volume = DEFAULT_MUSIC_VOLUME,
@@ -498,27 +436,12 @@ GameVariables g_game_vars = {
// clang-format on
// The sprite that displays the blind when in "GAME_PLAYING/GAME_ROUND_END" state
static Sprite* playing_blind_token = NULL;
// The sprite that displays the blind when in "GAME_ROUND_END" state
static Sprite* round_end_blind_token = NULL;
// Will be rolled later, just giving it a valid value
static int blind_reward = 0;
static int hand_reward = 0;
static int interest_reward = 0;
static int interest_to_count = 0;
static int interest_start_time = UNDEFINED;
// Red deck default (can later be moved to a deck.h file or something)
static int max_hands = 4;
static int max_discards = 4;
// Set in game_init and game_round_init
static int hands = 0;
static int discards = 0;
static u32 score = 0;
static u32 temp_score = 0; // This is the score that shows in the same spot as the hand type.
static bool score_flames_active = false;
static FIXED lerped_score = 0;
@@ -661,8 +584,8 @@ void game_init()
jokers_available_to_shop_init();
hands = max_hands;
discards = max_discards;
g_game_vars.hands = MAX_HANDS;
g_game_vars.discards = MAX_DISCARDS;
g_game_vars.timer = TM_ZERO;
g_game_vars.current_blind = BLIND_TYPE_SMALL;
g_game_vars.blinds_states[0] = BLIND_STATE_CURRENT;
@@ -670,7 +593,7 @@ void game_init()
g_game_vars.blinds_states[2] = BLIND_STATE_UPCOMING;
g_game_vars.ante = STARTING_ANTE;
g_game_vars.money = STARTING_MONEY;
score = STARTING_SCORE;
g_game_vars.score = STARTING_SCORE;
g_game_vars.round = 0;
// Initialize/reset unbeaten Boss/Showdown Blinds so they are all available
@@ -692,8 +615,8 @@ void game_reset()
// For some reason that I haven't figured out yet,
// if I don't destroy the blind tokens they won't
// show up on the next run.
sprite_destroy(&playing_blind_token);
sprite_destroy(&round_end_blind_token);
sprite_destroy(&g_game_vars.playing_blind_token);
sprite_destroy(&g_game_vars.round_end_blind_token);
list_clear(&_owned_jokers_list);
list_clear(&_discarded_jokers_list);
@@ -703,15 +626,15 @@ void game_reset()
game_init();
display_round();
display_score(score);
display_score(g_game_vars.score);
display_chips();
display_mult();
display_hands(hands);
display_discards(discards);
display_hands();
display_discards();
display_money();
// Ante
tte_printf(
"#{P:%d,%d; cx:0x%X000}%d#{cx:0x%X000}/%d",
"#{P:%d,%d; cx:0x%X000}%ld#{cx:0x%X000}/%d",
ANTE_TEXT_RECT.left,
ANTE_TEXT_RECT.top,
TTE_YELLOW_PB,
@@ -957,12 +880,12 @@ int get_deck_top(void)
int get_num_discards_remaining(void)
{
return discards;
return g_game_vars.discards;
}
int get_num_hands_remaining(void)
{
return hands;
return g_game_vars.hands;
}
u32 get_chips(void)
@@ -996,7 +919,7 @@ void display_money()
tte_erase_rect_wrapper(MONEY_TEXT_RECT);
char money_str_buff[INT_MAX_DIGITS + 2]; // + 2 for null terminator and "$" sign
snprintf(money_str_buff, sizeof(money_str_buff), "$%d", g_game_vars.money);
snprintf(money_str_buff, sizeof(money_str_buff), "$%ld", g_game_vars.money);
// Bias left so the number is centered and the "$" sign is on the left
update_text_rect_to_center_str(&money_text_rect, money_str_buff, SCREEN_LEFT);
@@ -1431,20 +1354,6 @@ void change_background_legacy(enum BackgroundId id)
tte_erase_rect_wrapper(HAND_SIZE_RECT_SELECT);
}
else if (id == BG_ROUND_END)
{
if (background_legacy != BG_CARD_SELECTING && background_legacy != BG_CARD_PLAYING)
{
change_background(BG_CARD_SELECTING, false);
background_legacy = BG_ROUND_END;
}
// Disable window 0 so it doesn't make the cashout menu transparent
toggle_windows(false, true);
main_bg_se_clear_rect(ROUND_END_MENU_RECT);
tte_erase_rect_wrapper(HAND_SIZE_RECT);
}
else if (id == BG_SHOP)
{
toggle_windows(false, true);
@@ -1472,7 +1381,7 @@ void change_background_legacy(enum BackgroundId id)
1
);
}
else if (id == BG_BLIND_SELECT || id == BG_MAIN_MENU)
else if (id == BG_BLIND_SELECT || id == BG_MAIN_MENU || id == BG_ROUND_END)
{
// do nothing, just don't return early!
}
@@ -1510,7 +1419,7 @@ static void display_temp_score(u32 value)
);
}
static void display_score(u32 value)
void display_score(u32 value)
{
Rect score_rect = SCORE_RECT;
// Clear the existing text before redrawing
@@ -1559,7 +1468,7 @@ void display_round(void)
{
// tte_erase_rect_wrapper(ROUND_TEXT_RECT);
tte_printf(
"#{P:%d,%d; cx:0x%X000}%d",
"#{P:%d,%d; cx:0x%X000}%ld",
ROUND_TEXT_RECT.left,
ROUND_TEXT_RECT.top,
TTE_YELLOW_PB,
@@ -1567,21 +1476,23 @@ void display_round(void)
);
}
static void display_hands(int value)
void display_hands(void)
{
// tte_erase_rect_wrapper(HANDS_TEXT_RECT);
tte_printf("#{P:%d,%d; cx:0xD000}%d", HANDS_TEXT_RECT.left, HANDS_TEXT_RECT.top, hands); // Hand
tte_printf(
"#{P:%d,%d; cx:0xD000}%ld",
HANDS_TEXT_RECT.left,
HANDS_TEXT_RECT.top,
g_game_vars.hands
);
}
static void display_discards(int value)
void display_discards(void)
{
// tte_erase_rect_wrapper(DISCARDS_TEXT_RECT);
// Discard
tte_printf(
"#{P:%d,%d; cx:0xE000}%d",
"#{P:%d,%d; cx:0xE000}%ld",
DISCARDS_TEXT_RECT.left,
DISCARDS_TEXT_RECT.top,
discards
g_game_vars.discards
);
}
@@ -1619,7 +1530,7 @@ static void set_hand(void)
static bool can_discard_hand(void)
{
return (discards > 0 && hand_state == HAND_SELECT && hand_selections > 0);
return (g_game_vars.discards > 0 && hand_state == HAND_SELECT && hand_selections > 0);
}
static int deck_get_size(void)
@@ -1650,29 +1561,29 @@ static void game_round_on_init(void)
cards_drawn = 0;
hand_selections = 0;
sprite_destroy(&playing_blind_token);
playing_blind_token = blind_token_new(
sprite_destroy(&g_game_vars.playing_blind_token);
g_game_vars.playing_blind_token = blind_token_new(
g_game_vars.current_blind,
CUR_BLIND_TOKEN_POS.x,
CUR_BLIND_TOKEN_POS.y,
PLAYING_BLIND_TOKEN_LAYER
); // Create the blind token sprite at the top left corner
// TODO: Hide blind token and display it after sliding blind rect animation
// if (playing_blind_token != NULL)
// if (g_game_vars.playing_blind_token != NULL)
//{
// obj_hide(playing_blind_token->obj); // Hide the blind token sprite for now
// obj_hide(g_game_vars.playing_blind_token->obj); // Hide the blind token sprite for now
//}
sprite_destroy(&round_end_blind_token);
round_end_blind_token = blind_token_new(
sprite_destroy(&g_game_vars.round_end_blind_token);
g_game_vars.round_end_blind_token = blind_token_new(
g_game_vars.current_blind,
81,
86,
ROUND_END_BLIND_TOKEN_LAYER
); // Create the blind token sprite for round end
if (round_end_blind_token != NULL)
if (g_game_vars.round_end_blind_token != NULL)
{
obj_hide(round_end_blind_token->obj); // Hide the blind token sprite for now
obj_hide(g_game_vars.round_end_blind_token->obj); // Hide the blind token sprite for now
}
Rect blind_req_text_rect = BLIND_REQ_TEXT_RECT;
@@ -1739,7 +1650,8 @@ static void game_playing_execute_discard(void)
return;
hand_state = HAND_DISCARD;
display_discards(--discards);
--g_game_vars.discards;
display_discards();
set_hand();
}
@@ -1804,7 +1716,8 @@ static void game_playing_execute_play_hand(void)
return;
hand_state = HAND_PLAY;
display_hands(--hands);
--g_game_vars.hands;
display_hands();
}
static int game_playing_hand_row_get_size(void)
@@ -2058,7 +1971,7 @@ static inline void game_playing_handle_round_over(void)
{
enum GameState next_state = GAME_STATE_ROUND_END;
if (score >= blind_get_requirement(g_game_vars.current_blind, g_game_vars.ante))
if (g_game_vars.score >= blind_get_requirement(g_game_vars.current_blind, g_game_vars.ante))
{
if (g_game_vars.current_blind > BLIND_TYPE_BIG)
{
@@ -2075,7 +1988,7 @@ static inline void game_playing_handle_round_over(void)
}
}
}
else if (hands == 0)
else if (g_game_vars.hands == 0)
{
next_state = GAME_STATE_LOSE;
}
@@ -2386,8 +2299,8 @@ static bool check_and_score_joker_for_event(
static inline bool game_round_is_over(void)
{
return hands == 0 ||
score >= blind_get_requirement(g_game_vars.current_blind, g_game_vars.ante);
return g_game_vars.hands == 0 ||
g_game_vars.score >= blind_get_requirement(g_game_vars.current_blind, g_game_vars.ante);
}
// Basically a copy of HAND_DISCARD
@@ -2827,7 +2740,7 @@ static inline void game_playing_process_input_and_state(void)
// protect against score overflow
temp_score = u32_protected_mult(chips, mult);
lerped_temp_score = int2fx(temp_score);
lerped_score = int2fx(score);
lerped_score = int2fx(g_game_vars.score);
display_temp_score(temp_score);
@@ -2867,14 +2780,14 @@ static inline void game_playing_process_input_and_state(void)
}
else
{
score = u32_protected_add(score, temp_score);
g_game_vars.score = u32_protected_add(g_game_vars.score, temp_score);
temp_score = 0;
lerped_temp_score = 0;
lerped_score = 0;
tte_erase_rect_wrapper(TEMP_SCORE_RECT); // Just erase the temp score
display_score(score);
display_score(g_game_vars.score);
}
}
}
@@ -3216,385 +3129,6 @@ static void game_playing_on_update(void)
game_playing_process_flaming_score();
}
static int calculate_interest_reward(void)
{
int reward = (g_game_vars.money / 5) * INTEREST_PER_5;
if (reward > MAX_INTEREST)
reward = MAX_INTEREST;
return reward;
}
static void game_round_end_on_exit(void)
{
// Cleanup blind tokens from this round to avoid accumulating
// allocated blind sprites each round
blind_reward = 0;
hand_reward = 0;
interest_reward = 0;
sprite_destroy(&playing_blind_token);
sprite_destroy(&round_end_blind_token);
// TODO: Reuse sprites for blind selection?
}
static void game_round_end_on_update(void)
{
if (state_info[game_state].substate == ROUND_END_EXIT)
{
game_change_state(GAME_STATE_SHOP);
return;
}
int substate = state_info[game_state].substate;
round_end_state_actions[substate]();
}
static void game_round_end_start()
{
// Reset static variables to default values upon re-entering the round end state
if (g_game_vars.timer == TM_RESET_STATIC_VARS)
{
change_background(BG_ROUND_END, false); // Change the background to the round end background
state_info[game_state].substate = START_EXPAND_POPUP; // Change the state to the next one
g_game_vars.timer = TM_ZERO; // Reset the timer
blind_reward = blind_get_reward(g_game_vars.current_blind);
hand_reward = hands;
interest_reward = calculate_interest_reward();
interest_to_count = interest_reward;
interest_start_time = UNDEFINED;
}
}
static void game_round_end_start_expand_popup()
{
main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT, SCREEN_UP);
if (g_game_vars.timer == TM_END_POP_MENU_ANIM)
{
state_info[game_state].substate = DISPLAY_FINISHED_BLIND;
g_game_vars.timer = TM_ZERO;
}
}
static void game_round_end_extend_black_panel_down(int black_panel_bottom)
{
Rect single_line_rect = ROUND_END_MENU_RECT;
single_line_rect.bottom = black_panel_bottom;
single_line_rect.top = single_line_rect.bottom - 1;
main_bg_se_copy_rect_1_tile_vert(single_line_rect, SCREEN_DOWN);
}
static void game_round_end_display_finished_blind()
{
obj_unhide(round_end_blind_token->obj, 0);
int current_ante = g_game_vars.ante;
// Beating the boss blind increases the ante, so we need to display the previous ante value
if (g_game_vars.current_blind > BLIND_TYPE_BIG)
current_ante--;
Rect blind_req_rect = ROUND_END_BLIND_REQ_RECT;
u32 blind_req = blind_get_requirement(g_game_vars.current_blind, current_ante);
/* Not bothering to truncate here because there are 8 tiles
* and the blind requirement will not increase past ante 8
* so there's enough room for sure.
*/
char blind_req_str_buff[UINT_MAX_DIGITS + 1];
snprintf(blind_req_str_buff, sizeof(blind_req_str_buff), "%lu", blind_req);
update_text_rect_to_right_align_str(&blind_req_rect, blind_req_str_buff, OVERFLOW_RIGHT);
tte_printf(
"#{P:%d,%d; cx:0x%X000}%s",
blind_req_rect.left,
blind_req_rect.top,
TTE_RED_PB,
blind_req_str_buff
);
if (g_game_vars.timer == TM_START_ROUND_END_REWARDS_ANIM)
{
game_round_end_extend_black_panel_down(ROUND_END_BLACK_PANEL_INIT_BOTTOM_SE);
}
if (g_game_vars.timer >= TM_END_DISPLAY_FIN_BLIND)
{
state_info[game_state].substate = DISPLAY_SCORE_MIN;
g_game_vars.timer = TM_ZERO;
}
}
static void game_round_end_display_score_min()
{
const int timer_offset = g_game_vars.timer - 1;
const int x_from = 0;
const int y_from = 29;
const int x_to = 13;
const int y_to = 11;
memcpy16(
&se_mem[MAIN_BG_SBB][x_to + timer_offset + 32 * y_to],
&se_mem[MAIN_BG_SBB][x_from + timer_offset + 32 * y_from],
1
);
if (g_game_vars.timer >= TM_END_DISPLAY_SCORE_MIN)
{
state_info[game_state].substate = UPDATE_BLIND_REWARD;
g_game_vars.timer = TM_ZERO;
}
}
static void game_round_end_update_blind_reward()
{
if (g_game_vars.timer % FRAMES(20) != 0)
return;
// TODO: Add sound effect here
if (blind_reward > 0)
{
blind_reward--;
tte_printf(
"#{P:%d,%d; cx:0x%X000}$%d",
BLIND_REWARD_RECT.left,
BLIND_REWARD_RECT.top,
TTE_YELLOW_PB,
blind_reward
);
tte_printf(
"#{P:%d,%d; cx:0x%X000}$%d",
ROUND_END_BLIND_REWARD_RECT.left,
ROUND_END_BLIND_REWARD_RECT.top,
TTE_YELLOW_PB,
blind_get_reward(g_game_vars.current_blind) - blind_reward
);
}
else if (g_game_vars.timer > FRAMES(20))
{
tte_erase_rect_wrapper(BLIND_REWARD_RECT);
tte_erase_rect_wrapper(BLIND_REQ_TEXT_RECT);
obj_hide(playing_blind_token->obj);
affine_background_load_palette(affine_background_gfxPal);
state_info[game_state].substate = BLIND_PANEL_EXIT;
g_game_vars.timer = TM_ZERO;
}
}
static void game_round_end_panel_exit()
{
// TODO: make heads or tails of what's going on here and replace
// magic numbers.
if (g_game_vars.timer < 8)
{
main_bg_se_copy_rect_1_tile_vert(TOP_LEFT_PANEL_ANIM_RECT, SCREEN_UP);
if (g_game_vars.timer == 1)
{
reset_top_left_panel_bottom_row();
}
else if (g_game_vars.timer == 2)
{
int y = 5;
memset16(&se_mem[MAIN_BG_SBB][32 * (y - 1)], 0x0001, 1);
memset16(&se_mem[MAIN_BG_SBB][1 + 32 * (y - 1)], 0x0002, 7);
memset16(&se_mem[MAIN_BG_SBB][8 + 32 * (y - 1)], 0x0401, 1);
}
}
else if (g_game_vars.timer > FRAMES(20))
{
memset16(&pal_bg_mem[REWARD_PANEL_BORDER_PID], 0x1483, 1);
state_info[game_state].substate = DISPLAY_REWARDS;
g_game_vars.timer = TM_ZERO;
}
}
static inline void game_round_end_print_separator_ellipsis(void)
{
int x =
(ROUND_END_REWARDS_ELLIPSIS_POS.x + g_game_vars.timer - TM_REWARDS_ELLIPSIS_PRINT_START) *
TILE_SIZE;
int y = (ROUND_END_REWARDS_ELLIPSIS_POS.y) * TILE_SIZE;
tte_printf("#{P:%d,%d; cx:0x%X000}.", x, y, TTE_WHITE_PB);
}
// TODO: Allow for more generic rewards and consolidate with game_round_end_print_interest_reward()
static inline void game_round_end_print_hand_reward(int hand_y_offset)
{
int hand_y = ROUND_END_REWARDS_ELLIPSIS_POS.y + hand_y_offset;
if (g_game_vars.timer == TM_DISPLAY_REWARDS_CONT_WAIT)
{
game_round_end_extend_black_panel_down(hand_y);
tte_printf(
"#{P:%d,%d; cx:0x%X000}%d #{cx:0x%X000}Hands",
ROUND_END_REWARD_TEXT_X,
hand_y * TILE_SIZE,
TTE_BLUE_PB,
hand_reward,
TTE_WHITE_PB
);
}
// Increment the hand reward text until the hand reward variable is depleted
else if (g_game_vars.timer > TM_HAND_REWARD_INCR_WAIT &&
g_game_vars.timer % FRAMES(TM_REWARD_INCREMENT_INTERVAL) == 0)
{
hand_reward--;
tte_printf(
"#{P:%d, %d; cx:0x%X000}$%d",
ROUND_END_REWARD_AMOUNT_X,
hand_y * TILE_SIZE,
TTE_YELLOW_PB,
hands - hand_reward
);
if (hand_reward == 0)
{
interest_start_time = g_game_vars.timer + TM_REWARD_DISPLAY_INTERVAL;
}
}
}
static inline void game_round_end_print_interest_reward(int interest_y_offset)
{
int interest_y = ROUND_END_REWARDS_ELLIPSIS_POS.y + interest_y_offset;
if (g_game_vars.timer == interest_start_time)
{
game_round_end_extend_black_panel_down(interest_y);
tte_printf(
"#{P:%d,%d; cx:0x%X000}%d #{cx:0x%X000}Interest",
ROUND_END_REWARD_TEXT_X,
interest_y * TILE_SIZE,
TTE_YELLOW_PB,
interest_reward,
TTE_WHITE_PB
);
}
// Increment the interest reward text until the interest reward variable is depleted
else if (g_game_vars.timer > interest_start_time + TM_REWARD_DISPLAY_INTERVAL &&
g_game_vars.timer % FRAMES(TM_REWARD_INCREMENT_INTERVAL) == 0)
{
interest_to_count--;
tte_printf(
"#{P:%d, %d; cx:0x%X000}$%d",
ROUND_END_REWARD_AMOUNT_X,
interest_y * TILE_SIZE,
TTE_YELLOW_PB,
interest_reward - interest_to_count
);
}
}
static void game_round_end_display_rewards()
{
int hand_y_offset = 0;
int interest_y_offset = 0;
if (hands > 0)
{
hand_y_offset = 1;
}
else
{
interest_start_time = TM_DISPLAY_REWARDS_CONT_WAIT;
}
if (interest_reward > 0)
{
interest_y_offset = hand_y_offset + 1;
}
// Once all rewards are accounted for go to the next state
if (hand_reward <= 0 && interest_to_count <= 0)
{
g_game_vars.timer = TM_ZERO;
state_info[game_state].substate = DISPLAY_CASHOUT;
}
else if (g_game_vars.timer == TM_START_ROUND_END_REWARDS_ANIM)
{
game_round_end_extend_black_panel_down(ROUND_END_REWARDS_ELLIPSIS_POS.y);
}
else if (g_game_vars.timer < TM_REWARDS_ELLIPSIS_PRINT_END)
{
game_round_end_print_separator_ellipsis();
}
else if (g_game_vars.timer >= TM_DISPLAY_REWARDS_CONT_WAIT && hand_reward > 0)
{
game_round_end_print_hand_reward(hand_y_offset);
}
else if (interest_start_time != UNDEFINED && g_game_vars.timer >= interest_start_time &&
interest_to_count > 0)
{
game_round_end_print_interest_reward(interest_y_offset);
}
}
static inline void game_round_end_cashout(void)
{
// Reward the player
g_game_vars.money +=
hands + blind_get_reward(g_game_vars.current_blind) + calculate_interest_reward();
display_money();
hands = max_hands; // Reset the hands to the maximum
discards = max_discards; // Reset the discards to the maximum
display_hands(hands); // Set the hands display
display_discards(discards); // Set the discards display
score = 0;
display_score(score); // Set the score display
}
static void game_round_end_display_cashout()
{
if (g_game_vars.timer == FRAMES(40))
{
// Put the "cash out" button onto the round end panel
main_bg_se_copy_expand_3x3_rect(CASHOUT_DEST_RECT, CASHOUT_SRC_3X3_RECT_POS);
int cashout_amount =
hands + blind_get_reward(g_game_vars.current_blind) + calculate_interest_reward();
bool omit_space = cashout_amount >= 10;
tte_printf(
"#{P:%d, %d; cx:0x%X000}Cash Out:%s$%d",
CASHOUT_TEXT_RECT.left,
CASHOUT_TEXT_RECT.top,
TTE_WHITE_PB,
omit_space ? "" : " ",
cashout_amount
);
}
// Wait until the player presses A to cash out
else if (g_game_vars.timer > FRAMES(40) && key_hit(SELECT_CARD))
{
game_round_end_cashout();
state_info[game_state].substate = DISMISS_ROUND_END_PANEL; // Go to the next state
g_game_vars.timer = TM_ZERO;
obj_hide(round_end_blind_token->obj); // Hide the blind token object
tte_erase_rect_wrapper(BLIND_TOKEN_TEXT_RECT); // Erase the blind token text
}
}
static void game_round_end_dismiss_round_end_panel()
{
Rect round_end_down = ROUND_END_MENU_RECT;
round_end_down.top--;
main_bg_se_copy_rect_1_tile_vert(round_end_down, SCREEN_DOWN);
if (g_game_vars.timer >= TM_DISMISS_ROUND_END_TM)
{
g_game_vars.timer = TM_ZERO;
state_info[game_state].substate = ROUND_END_EXIT;
}
}
static Rect get_text_rect_under_sprite_object(SpriteObject* sprite_object)
{
int height = 0;
@@ -4248,8 +3782,8 @@ void game_start(void)
affine_background_change_background(AFFINE_BG_GAME);
hands = max_hands;
discards = max_discards;
g_game_vars.hands = MAX_HANDS;
g_game_vars.discards = MAX_DISCARDS;
// Activate high contrast palette for cards if loaded settings tell us to
toggle_high_contrast_cards(g_game_vars.high_contrast);
@@ -4278,19 +3812,19 @@ void game_start(void)
deck_get_max_size()
);
display_round(); // Set the round display
display_score(score); // Set the score display
display_round(); // Set the round display
display_score(g_game_vars.score); // Set the score display
display_chips(); // Set the chips display
display_mult(); // Set the multiplier display
display_hands(hands); // Hand
display_discards(discards); // Discard
display_hands(); // Hand
display_discards(); // Discard
display_money(); // Set the money display
tte_printf(
"#{P:%d,%d; cx:0x%X000}%d#{cx:0x%X000}/%d",
"#{P:%d,%d; cx:0x%X000}%ld#{cx:0x%X000}/%d",
ANTE_TEXT_RECT.left,
ANTE_TEXT_RECT.top,
TTE_YELLOW_PB,
+2 -1
View File
@@ -4,6 +4,7 @@
#include "game.h"
#include "game/main_menu.h"
#include "game/options_menu.h"
#include "game/round_end.h"
typedef void (*BackgroundRenderCallback)(void);
@@ -14,7 +15,7 @@ static const BackgroundRenderCallback bgCallbacks[] = {
[BG_NONE] = NULL,
[BG_CARD_SELECTING] = NULL,
[BG_CARD_PLAYING] = NULL,
[BG_ROUND_END] = NULL,
[BG_ROUND_END] = game_round_end_change_background,
[BG_SHOP] = NULL,
[BG_BLIND_SELECT] = game_blind_select_change_background,
[BG_OPTIONS_MENU] = game_options_menu_change_background,
+473
View File
@@ -0,0 +1,473 @@
#include "round_end.h"
#include "affine_background.h"
#include "affine_background_gfx.h"
#include "game_variables.h"
#include "layout.h"
#include "timer.h"
#include "util.h"
enum GameRoundEndStates
{
ROUND_END_START,
START_EXPAND_POPUP,
DISPLAY_FINISHED_BLIND,
DISPLAY_SCORE_MIN,
UPDATE_BLIND_REWARD,
BLIND_PANEL_EXIT,
DISPLAY_REWARDS,
DISPLAY_CASHOUT,
DISMISS_ROUND_END_PANEL,
ROUND_END_EXIT
};
static const u32 TM_RESET_STATIC_VARS = 30;
static const u32 TM_END_POP_MENU_ANIM = 13;
static const u32 TM_START_ROUND_END_REWARDS_ANIM = 1;
static const u32 TM_END_DISPLAY_FIN_BLIND = 30;
static const u32 TM_END_DISPLAY_SCORE_MIN = 4;
static const u32 TM_DISMISS_ROUND_END_TM = 20;
static const u32 REWARD_PANEL_BORDER_PID = 19;
static const u32 ROUND_END_BLACK_PANEL_INIT_BOTTOM_SE = 12;
static const u32 ROUND_END_REWARD_TEXT_X = 88;
static const u32 ROUND_END_REWARD_AMOUNT_X = 168;
// clang-format off
static const Rect ROUND_END_BLIND_REQ_RECT = {104, 96, 136, UNDEFINED};
static const Rect ROUND_END_BLIND_REWARD_RECT = {168, 96, UNDEFINED, UNDEFINED};
static const Rect CASHOUT_DEST_RECT = {10, 8, 23, 10 };
static const Rect CASHOUT_TEXT_RECT = {88, 72, UNDEFINED, UNDEFINED};
static const Rect BLIND_TOKEN_TEXT_RECT = {80, 72, 200, 160 };
static const Rect ROUND_END_MENU_RECT = {9, 7, 24, 20 };
static const BG_POINT CASHOUT_SRC_3X3_RECT_POS = {5, 29};
// clang-format on
static int substate;
static int blind_reward = 0;
static int hand_reward = 0;
static int interest_reward = 0;
static int interest_to_count = 0;
static int interest_start_time = UNDEFINED;
static int calculate_interest_reward(void);
static void game_round_end_start(void);
static void game_round_end_start_expand_popup(void);
static void game_round_end_display_finished_blind(void);
static void game_round_end_display_score_min(void);
static void game_round_end_update_blind_reward(void);
static void game_round_end_panel_exit(void);
static void game_round_end_display_rewards(void);
static void game_round_end_display_cashout(void);
static void game_round_end_dismiss_round_end_panel(void);
static void game_round_end_extend_black_panel_down(int black_panel_bottom);
static const SubStateActionFn round_end_state_actions[] = {
game_round_end_start,
game_round_end_start_expand_popup,
game_round_end_display_finished_blind,
game_round_end_display_score_min,
game_round_end_update_blind_reward,
game_round_end_panel_exit,
game_round_end_display_rewards,
game_round_end_display_cashout,
game_round_end_dismiss_round_end_panel
};
static int calculate_interest_reward(void)
{
int reward = (g_game_vars.money / 5) * INTEREST_PER_5;
if (reward > MAX_INTEREST)
reward = MAX_INTEREST;
return reward;
}
static void game_round_end_start(void)
{
// Reset static variables to default values upon re-entering the round end state
if (g_game_vars.timer == TM_RESET_STATIC_VARS)
{
change_background(BG_ROUND_END, false); // Change the background to the round end background
substate = START_EXPAND_POPUP; // Change the state to the next one
g_game_vars.timer = TM_ZERO; // Reset the timer
blind_reward = blind_get_reward(g_game_vars.current_blind);
hand_reward = g_game_vars.hands;
interest_reward = calculate_interest_reward();
interest_to_count = interest_reward;
interest_start_time = UNDEFINED;
}
}
static void game_round_end_start_expand_popup(void)
{
main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT, SCREEN_UP);
if (g_game_vars.timer == TM_END_POP_MENU_ANIM)
{
substate = DISPLAY_FINISHED_BLIND;
g_game_vars.timer = TM_ZERO;
}
}
static void game_round_end_display_finished_blind(void)
{
obj_unhide(g_game_vars.round_end_blind_token->obj, 0);
int current_ante = g_game_vars.ante;
// Beating the boss blind increases the ante, so we need to display the previous ante value
if (g_game_vars.current_blind > BLIND_TYPE_BIG)
current_ante--;
Rect blind_req_rect = ROUND_END_BLIND_REQ_RECT;
u32 blind_req = blind_get_requirement(g_game_vars.current_blind, current_ante);
/* Not bothering to truncate here because there are 8 tiles
* and the blind requirement will not increase past ante 8
* so there's enough room for sure.
*/
char blind_req_str_buff[UINT_MAX_DIGITS + 1];
snprintf(blind_req_str_buff, sizeof(blind_req_str_buff), "%lu", blind_req);
update_text_rect_to_right_align_str(&blind_req_rect, blind_req_str_buff, OVERFLOW_RIGHT);
tte_printf(
"#{P:%d,%d; cx:0x%X000}%s",
blind_req_rect.left,
blind_req_rect.top,
TTE_RED_PB,
blind_req_str_buff
);
if (g_game_vars.timer == TM_START_ROUND_END_REWARDS_ANIM)
{
game_round_end_extend_black_panel_down(ROUND_END_BLACK_PANEL_INIT_BOTTOM_SE);
}
if (g_game_vars.timer >= TM_END_DISPLAY_FIN_BLIND)
{
substate = DISPLAY_SCORE_MIN;
g_game_vars.timer = TM_ZERO;
}
}
static void game_round_end_display_score_min(void)
{
const int timer_offset = g_game_vars.timer - 1;
const int x_from = 0;
const int y_from = 29;
const int x_to = 13;
const int y_to = 11;
memcpy16(
&se_mem[MAIN_BG_SBB][x_to + timer_offset + 32 * y_to],
&se_mem[MAIN_BG_SBB][x_from + timer_offset + 32 * y_from],
1
);
if (g_game_vars.timer >= TM_END_DISPLAY_SCORE_MIN)
{
substate = UPDATE_BLIND_REWARD;
g_game_vars.timer = TM_ZERO;
}
}
static void game_round_end_update_blind_reward(void)
{
if (g_game_vars.timer % FRAMES(20) != 0)
return;
// TODO: Add sound effect here
if (blind_reward > 0)
{
blind_reward--;
tte_printf(
"#{P:%d,%d; cx:0x%X000}$%d",
BLIND_REWARD_RECT.left,
BLIND_REWARD_RECT.top,
TTE_YELLOW_PB,
blind_reward
);
tte_printf(
"#{P:%d,%d; cx:0x%X000}$%d",
ROUND_END_BLIND_REWARD_RECT.left,
ROUND_END_BLIND_REWARD_RECT.top,
TTE_YELLOW_PB,
blind_get_reward(g_game_vars.current_blind) - blind_reward
);
}
else if (g_game_vars.timer > FRAMES(20))
{
tte_erase_rect_wrapper(BLIND_REWARD_RECT);
tte_erase_rect_wrapper(BLIND_REQ_TEXT_RECT);
obj_hide(g_game_vars.playing_blind_token->obj);
affine_background_load_palette(affine_background_gfxPal);
substate = BLIND_PANEL_EXIT;
g_game_vars.timer = TM_ZERO;
}
}
static void game_round_end_panel_exit(void)
{
// TODO: make heads or tails of what's going on here and replace
// magic numbers.
if (g_game_vars.timer < 8)
{
main_bg_se_copy_rect_1_tile_vert(TOP_LEFT_PANEL_ANIM_RECT, SCREEN_UP);
if (g_game_vars.timer == 1)
{
reset_top_left_panel_bottom_row();
}
else if (g_game_vars.timer == 2)
{
int y = 5;
memset16(&se_mem[MAIN_BG_SBB][32 * (y - 1)], 0x0001, 1);
memset16(&se_mem[MAIN_BG_SBB][1 + 32 * (y - 1)], 0x0002, 7);
memset16(&se_mem[MAIN_BG_SBB][8 + 32 * (y - 1)], 0x0401, 1);
}
}
else if (g_game_vars.timer > FRAMES(20))
{
memset16(&pal_bg_mem[REWARD_PANEL_BORDER_PID], 0x1483, 1);
substate = DISPLAY_REWARDS;
g_game_vars.timer = TM_ZERO;
}
}
static inline void game_round_end_print_separator_ellipsis(void)
{
int x =
(ROUND_END_REWARDS_ELLIPSIS_POS.x + g_game_vars.timer - TM_REWARDS_ELLIPSIS_PRINT_START) *
TILE_SIZE;
int y = (ROUND_END_REWARDS_ELLIPSIS_POS.y) * TILE_SIZE;
tte_printf("#{P:%d,%d; cx:0x%X000}.", x, y, TTE_WHITE_PB);
}
// TODO: Allow for more generic rewards and consolidate with game_round_end_print_interest_reward()
static inline void game_round_end_print_hand_reward(int hand_y_offset)
{
int hand_y = ROUND_END_REWARDS_ELLIPSIS_POS.y + hand_y_offset;
if (g_game_vars.timer == TM_DISPLAY_REWARDS_CONT_WAIT)
{
game_round_end_extend_black_panel_down(hand_y);
tte_printf(
"#{P:%lu,%d; cx:0x%X000}%d #{cx:0x%X000}Hands",
ROUND_END_REWARD_TEXT_X,
hand_y * TILE_SIZE,
TTE_BLUE_PB,
hand_reward,
TTE_WHITE_PB
);
}
// Increment the hand reward text until the hand reward variable is depleted
else if (g_game_vars.timer > TM_HAND_REWARD_INCR_WAIT &&
g_game_vars.timer % FRAMES(TM_REWARD_INCREMENT_INTERVAL) == 0)
{
hand_reward--;
tte_printf(
"#{P:%lu, %d; cx:0x%X000}$%ld",
ROUND_END_REWARD_AMOUNT_X,
hand_y * TILE_SIZE,
TTE_YELLOW_PB,
g_game_vars.hands - hand_reward
);
if (hand_reward == 0)
{
interest_start_time = g_game_vars.timer + TM_REWARD_DISPLAY_INTERVAL;
}
}
}
static inline void game_round_end_print_interest_reward(int interest_y_offset)
{
int interest_y = ROUND_END_REWARDS_ELLIPSIS_POS.y + interest_y_offset;
if (g_game_vars.timer == interest_start_time)
{
game_round_end_extend_black_panel_down(interest_y);
tte_printf(
"#{P:%lu,%d; cx:0x%X000}%d #{cx:0x%X000}Interest",
ROUND_END_REWARD_TEXT_X,
interest_y * TILE_SIZE,
TTE_YELLOW_PB,
interest_reward,
TTE_WHITE_PB
);
}
// Increment the interest reward text until the interest reward variable is depleted
else if (g_game_vars.timer > interest_start_time + TM_REWARD_DISPLAY_INTERVAL &&
g_game_vars.timer % FRAMES(TM_REWARD_INCREMENT_INTERVAL) == 0)
{
interest_to_count--;
tte_printf(
"#{P:%lu, %d; cx:0x%X000}$%d",
ROUND_END_REWARD_AMOUNT_X,
interest_y * TILE_SIZE,
TTE_YELLOW_PB,
interest_reward - interest_to_count
);
}
}
static void game_round_end_display_rewards(void)
{
int hand_y_offset = 0;
int interest_y_offset = 0;
if (g_game_vars.hands > 0)
{
hand_y_offset = 1;
}
else
{
interest_start_time = TM_DISPLAY_REWARDS_CONT_WAIT;
}
if (interest_reward > 0)
{
interest_y_offset = hand_y_offset + 1;
}
// Once all rewards are accounted for go to the next state
if (hand_reward <= 0 && interest_to_count <= 0)
{
g_game_vars.timer = TM_ZERO;
substate = DISPLAY_CASHOUT;
}
else if (g_game_vars.timer == TM_START_ROUND_END_REWARDS_ANIM)
{
game_round_end_extend_black_panel_down(ROUND_END_REWARDS_ELLIPSIS_POS.y);
}
else if (g_game_vars.timer < TM_REWARDS_ELLIPSIS_PRINT_END)
{
game_round_end_print_separator_ellipsis();
}
else if (g_game_vars.timer >= TM_DISPLAY_REWARDS_CONT_WAIT && hand_reward > 0)
{
game_round_end_print_hand_reward(hand_y_offset);
}
else if (interest_start_time != UNDEFINED && g_game_vars.timer >= interest_start_time &&
interest_to_count > 0)
{
game_round_end_print_interest_reward(interest_y_offset);
}
}
static inline void game_round_end_cashout(void)
{
// Reward the player
g_game_vars.money += g_game_vars.hands + blind_get_reward(g_game_vars.current_blind) +
calculate_interest_reward();
display_money();
g_game_vars.hands = MAX_HANDS; // Reset the hands to the maximum
g_game_vars.discards = MAX_DISCARDS; // Reset the discards to the maximum
// TODO: these can just be in one spot, passing global to global
display_hands(); // Set the hands display
display_discards(); // Set the discards display
g_game_vars.score = 0;
display_score(g_game_vars.score); // Set the score display
}
static void game_round_end_display_cashout()
{
if (g_game_vars.timer == FRAMES(40))
{
// Put the "cash out" button onto the round end panel
main_bg_se_copy_expand_3x3_rect(CASHOUT_DEST_RECT, CASHOUT_SRC_3X3_RECT_POS);
int cashout_amount = g_game_vars.hands + blind_get_reward(g_game_vars.current_blind) +
calculate_interest_reward();
bool omit_space = cashout_amount >= 10;
tte_printf(
"#{P:%d, %d; cx:0x%X000}Cash Out:%s$%d",
CASHOUT_TEXT_RECT.left,
CASHOUT_TEXT_RECT.top,
TTE_WHITE_PB,
omit_space ? "" : " ",
cashout_amount
);
}
// Wait until the player presses A to cash out
else if (g_game_vars.timer > FRAMES(40) && key_hit(SELECT_CARD))
{
game_round_end_cashout();
substate = DISMISS_ROUND_END_PANEL; // Go to the next state
g_game_vars.timer = TM_ZERO;
obj_hide(g_game_vars.round_end_blind_token->obj); // Hide the blind token object
tte_erase_rect_wrapper(BLIND_TOKEN_TEXT_RECT); // Erase the blind token text
}
}
static void game_round_end_dismiss_round_end_panel(void)
{
Rect round_end_down = ROUND_END_MENU_RECT;
round_end_down.top--;
main_bg_se_copy_rect_1_tile_vert(round_end_down, SCREEN_DOWN);
if (g_game_vars.timer >= TM_DISMISS_ROUND_END_TM)
{
g_game_vars.timer = TM_ZERO;
substate = ROUND_END_EXIT;
}
}
static void game_round_end_extend_black_panel_down(int black_panel_bottom)
{
Rect single_line_rect = ROUND_END_MENU_RECT;
single_line_rect.bottom = black_panel_bottom;
single_line_rect.top = single_line_rect.bottom - 1;
main_bg_se_copy_rect_1_tile_vert(single_line_rect, SCREEN_DOWN);
}
void game_round_end_change_background(void)
{
// Disable window 0 so it doesn't make the cashout menu transparent
toggle_windows(false, true);
main_bg_se_clear_rect(ROUND_END_MENU_RECT);
tte_erase_rect_wrapper(HAND_SIZE_RECT);
}
void game_round_end_on_init(void)
{
substate = ROUND_END_START;
g_game_vars.timer = 0;
}
void game_round_end_on_update(void)
{
if (substate == ROUND_END_EXIT)
{
game_change_state(GAME_STATE_SHOP);
return;
}
round_end_state_actions[substate]();
}
void game_round_end_on_exit(void)
{
// Cleanup blind tokens from this round to avoid accumulating
// allocated blind sprites each round
blind_reward = 0;
hand_reward = 0;
interest_reward = 0;
sprite_destroy(&g_game_vars.playing_blind_token);
sprite_destroy(&g_game_vars.round_end_blind_token);
// TODO: Reuse sprites for blind selection?
}