diff --git a/include/graphic_utils.h b/include/graphic_utils.h index 757c6d67..06683ea1 100644 --- a/include/graphic_utils.h +++ b/include/graphic_utils.h @@ -36,6 +36,9 @@ #define SE_UP -1 #define SE_DOWN 1 +#define OVERFLOW_LEFT -1 +#define OVERFLOW_RIGHT 1 + // Tile size in pixels, both height and width as tiles are square #define TILE_SIZE 8 @@ -101,4 +104,18 @@ void main_bg_se_move_rect_1_tile_vert(Rect se_rect, int direction); // A wrapper for tte_erase_rect that would use the rect struct void tte_erase_rect_wrapper(Rect rect); +/* Changes rect->left so it fits the digits of num exactly when right aligned to rect->right. + * Assumes num is not negative. + * + * overflow_direction determines the direction the number will overflow + * if it's too large to fit inside the rect. + * Should be either OVERFLOW_LEFT or OVERFLOW_RIGHT. + * + * The rect is in number of pixels but should be a multiple of TILE_SIZE + * so it's a whole number of tiles to fit TTE characters + * + * Note that both rect->left and rect-right need to be defined, top and bottom don't matter + */ +void update_text_rect_to_right_align_num(Rect* rect, int num, int overflow_direction); + #endif //GRAPHIC_UTILS_H \ No newline at end of file diff --git a/source/game.c b/source/game.c index 381d7e2f..9a397493 100644 --- a/source/game.c +++ b/source/game.c @@ -140,10 +140,7 @@ static inline JokerObject *joker_pop() // Screenblock rects static const Rect ROUND_END_MENU_RECT = {9, 7, 24, 20 }; -// These need to be here because moving tiles down below 30 bleeds memory into the next screenblock I think -static const Rect POP_MENU_ANIM_RECT_DOWN = {9, 6, 24, 30 }; -static const Rect POP_MENU_ANIM_RECT_UP = {9, 7, 24, 31 }; - +static const Rect POP_MENU_ANIM_RECT = {9, 7, 24, 31 }; // The rect for popping menu animations (round end, shop, blinds) // - extends beyond the visible screen to the end of the screenblock // It includes both the target and source position rects. @@ -177,7 +174,7 @@ static const Rect HAND_SIZE_RECT_PLAYING = {128, 152, 152, 160 }; static const Rect HAND_TYPE_RECT = {8, 64, 64, 72 }; // Score displayed in the same place as the hand type static const Rect TEMP_SCORE_RECT = {8, 64, 64, 72 }; -static const Rect SCORE_RECT = {32, 48, 64, 56 }; +static const Rect SCORE_RECT = {32, 48, 64, 56 }; static const Rect PLAYED_CARDS_SCORES_RECT = {72, 48, 240, 56 }; static const Rect BLIND_TOKEN_TEXT_RECT = {80, 72, 200, 160 }; @@ -185,7 +182,7 @@ static const Rect MONEY_TEXT_RECT = {8, 120, 64, 120 }; 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 = {40, 24, 64, 32 }; +static const Rect BLIND_REQ_TEXT_RECT = {32, 24, 64, 32 }; // Rects with UNDEFINED are only used in tte_printf, they need to be fully defined // to be used with tte_erase_rect_wrapper() @@ -194,7 +191,7 @@ static const Rect DISCARDS_TEXT_RECT = {48, 104, UNDEFINED, UNDEF static const Rect DECK_SIZE_RECT = {200, 152, UNDEFINED, UNDEFINED }; 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 = {112, 96, UNDEFINED, UNDEFINED }; +static const Rect ROUND_END_BLIND_REQ_RECT = {112, 96, 136, UNDEFINED }; static const Rect ROUND_END_BLIND_REWARD_RECT = { 168, 96, UNDEFINED, UNDEFINED }; static const Rect ROUND_END_NUM_HANDS_RECT = {88, 116, UNDEFINED, UNDEFINED }; static const Rect HAND_REWARD_RECT = {168, UNDEFINED, UNDEFINED, UNDEFINED }; @@ -612,7 +609,7 @@ void change_background(int id) void set_temp_score(int value) { - int x_offset = 40 - get_digits_even(value) * 8; + int x_offset = 40 - get_digits_even(value) * TILE_SIZE; tte_erase_rect_wrapper(TEMP_SCORE_RECT); tte_printf("#{P:%d,%d; cx:0xF000}%d", x_offset, TEMP_SCORE_RECT.top, value); } @@ -632,16 +629,17 @@ void set_score(int value) void set_money(int value) { - int x_offset = 32 - get_digits_odd(value) * 8; + int x_offset = 32 - get_digits_odd(value) * TILE_SIZE; tte_erase_rect_wrapper(MONEY_TEXT_RECT); tte_printf("#{P:%d,%d; cx:0xC000}$%d", x_offset, MONEY_TEXT_RECT.top, value); } void set_chips(int value) { - int x_offset = 32 - get_digits(value) * 8; // Adjust the x offset based on the number of digits in chips + Rect chips_text_rect = CHIPS_TEXT_RECT; tte_erase_rect_wrapper(CHIPS_TEXT_RECT); - tte_printf("#{P:%d,%d; cx:0xF000;}%d", x_offset, CHIPS_TEXT_RECT.top, value); + update_text_rect_to_right_align_num(&chips_text_rect, value, OVERFLOW_LEFT); + tte_printf("#{P:%d,%d; cx:0xF000;}%d", chips_text_rect.left, chips_text_rect.top, value); } void set_mult(int value) @@ -906,7 +904,11 @@ void game_round_init() obj_hide(round_end_blind_token->obj); // Hide the blind token sprite for now } - tte_printf("#{P:%d,%d; cx:0xE000}%d", BLIND_REQ_TEXT_RECT.left, BLIND_REQ_TEXT_RECT.top, blind_get_requirement(current_blind, ante)); // Blind requirement + Rect blind_req_text_rect = BLIND_REQ_TEXT_RECT; + int blind_requirement = blind_get_requirement(current_blind, ante); + update_text_rect_to_right_align_num(&blind_req_text_rect, blind_requirement, OVERFLOW_RIGHT); + + tte_printf("#{P:%d,%d; cx:0xE000}%d", blind_req_text_rect.left, blind_req_text_rect.top, blind_requirement); // Blind requirement tte_printf("#{P:%d,%d; cx:0xC000}$%d", BLIND_REWARD_RECT.left, BLIND_REWARD_RECT.top, blind_get_reward(current_blind)); // Blind reward deck_shuffle(); // Shuffle the deck at the start of the round @@ -1747,7 +1749,7 @@ void game_round_end() } case 1: // This creates the top 16 by 7 tiles of the pop up. It places it in vram, moving it up one tile each frame, not clearing the previous row of tiles so they fill the blank space as it moves up. { - main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT_UP, SE_UP); + main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT, SE_UP); if (timer == 13) { @@ -1763,7 +1765,11 @@ void game_round_end() int current_ante = ante; if (current_blind == BOSS_BLIND) current_ante--; // Beating the boss blind increases the ante, so we need to display the previous ante value - tte_printf("#{P:%d,%d; cx:0xE000}%d", ROUND_END_BLIND_REQ_RECT.left, ROUND_END_BLIND_REQ_RECT.top, blind_get_requirement(current_blind, current_ante)); + Rect blind_req_rect = ROUND_END_BLIND_REQ_RECT; + int blind_req = blind_get_requirement(current_blind, current_ante); + update_text_rect_to_right_align_num(&blind_req_rect, blind_req, OVERFLOW_RIGHT); + + tte_printf("#{P:%d,%d; cx:0xE000}%d", blind_req_rect.left, blind_req_rect.top, blind_req); if (timer == 1) { @@ -1809,7 +1815,7 @@ void game_round_end() { blind_reward--; tte_printf("#{P:%d,%d; cx:0xC000}$%d", BLIND_REWARD_RECT.left , BLIND_REWARD_RECT.top, blind_reward); - tte_printf("#{P:%d,%d; cx:0xC000}$%d", ROUND_END_BLIND_REWARD_RECT.left, ROUND_END_BLIND_REQ_RECT.top, blind_get_reward(current_blind) - blind_reward); + tte_printf("#{P:%d,%d; cx:0xC000}$%d", ROUND_END_BLIND_REWARD_RECT.left, ROUND_END_BLIND_REWARD_RECT.top, blind_get_reward(current_blind) - blind_reward); } else if (timer > FRAMES(20)) { @@ -2027,7 +2033,7 @@ void game_shop() { case 0: // Intro sequence (menu and shop icon coming into frame) { - main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT_UP, SE_UP); + main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT, SE_UP); if (timer == 1) { @@ -2158,7 +2164,7 @@ void game_shop() case 2: // Outro sequence (menu and shop icon going out of frame) { // Shift the shop panel - main_bg_se_move_rect_1_tile_vert(POP_MENU_ANIM_RECT_DOWN, SE_DOWN); + main_bg_se_move_rect_1_tile_vert(POP_MENU_ANIM_RECT, SE_DOWN); main_bg_se_copy_rect_1_tile_vert(TOP_LEFT_PANEL_ANIM_RECT, SE_UP); @@ -2225,7 +2231,7 @@ void game_blind_select() case 0: // Intro sequence (menu coming into frame) { change_background(BG_ID_BLIND_SELECT); - main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT_UP, SE_UP); + main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT, SE_UP); for (int i = 0; i < MAX_BLINDS; i++) { @@ -2269,7 +2275,7 @@ void game_blind_select() // TODO: Create a generic vertical move by any number of tiles to avoid for loops? for (int i = 0; i < 12; i++) { - main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT_UP, SE_UP); + main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT, SE_UP); } for (int i = 0; i < MAX_BLINDS; i++) @@ -2298,7 +2304,9 @@ void game_blind_select() { if (timer < 15) { - main_bg_se_move_rect_1_tile_vert(POP_MENU_ANIM_RECT_DOWN, SE_DOWN); + Rect blinds_rect = POP_MENU_ANIM_RECT; + blinds_rect.top -= 1; // Because of the raised blind + main_bg_se_move_rect_1_tile_vert(blinds_rect, SE_DOWN); for (int i = 0; i < MAX_BLINDS; i++) { diff --git a/source/graphic_utils.c b/source/graphic_utils.c index b48707dd..884d26b6 100644 --- a/source/graphic_utils.c +++ b/source/graphic_utils.c @@ -2,9 +2,10 @@ #include #include +#include "util.h" #include "graphic_utils.h" -const Rect FULL_SCREENBLOCK_RECT = { 0, 0, SE_ROW_LEN, SE_COL_LEN }; +const Rect FULL_SCREENBLOCK_RECT = { 0, 0, SE_ROW_LEN - 1, SE_COL_LEN - 1}; // Clips a rect of screenblock entries to a specified rect // The bounding rect is not required to be within screenblock boundaries @@ -29,12 +30,19 @@ u16 main_bg_se_get_tile(BG_POINT pos) } // Clips a rect of screenblock entries to be within one step of -// screenblock boundaries vertically (1 step from top, 1 step from bottom. -static void clip_se_rect_within_step_of_full_screen_vert(Rect* se_rect) +// screenblock boundaries vertically depending on direction. +static void clip_se_rect_within_step_of_full_screen_vert(Rect* se_rect, int direction) { Rect bounding_rect = FULL_SCREENBLOCK_RECT; - bounding_rect.top += 1; - bounding_rect.bottom -= -1; + if (direction == SE_UP) + { + bounding_rect.top += 1; + } + else if (direction == SE_DOWN) + { + bounding_rect.bottom -= 1; + } + clip_se_rect_to_bounding_rect(se_rect, &bounding_rect); } @@ -51,7 +59,9 @@ void main_bg_se_clear_rect(Rect se_rect) } } -void main_bg_se_copy_rect_1_tile_vert(Rect se_rect, int direction) + +// Internal static function to merge implementation of move/copy functions. +static void main_bg_se_copy_or_move_rect_1_tile_vert(Rect se_rect, int direction, bool move) { if (se_rect.left > se_rect.right || (direction != SE_UP && direction != SE_DOWN)) @@ -60,7 +70,7 @@ void main_bg_se_copy_rect_1_tile_vert(Rect se_rect, int direction) } // Clip to avoid read/write overflow of the screenblock - clip_se_rect_within_step_of_full_screen_vert(&se_rect); + clip_se_rect_within_step_of_full_screen_vert(&se_rect, direction); int start = (direction == SE_UP) ? se_rect.top : se_rect.bottom; int end = (direction == SE_UP) ? se_rect.bottom : se_rect.top; @@ -68,27 +78,24 @@ void main_bg_se_copy_rect_1_tile_vert(Rect se_rect, int direction) for (int y = start; y != end - direction; y -= direction) { memcpy16(&se_mem[MAIN_BG_SBB][se_rect.left + SE_ROW_LEN * (y + direction)], - &se_mem[MAIN_BG_SBB][se_rect.left + SE_ROW_LEN * y], + &se_mem[MAIN_BG_SBB][se_rect.left + SE_ROW_LEN * y], rect_width(&se_rect)); } + + if (move) + { + memset16(&se_mem[MAIN_BG_SBB][se_rect.left + SE_ROW_LEN * (end)], 0x0000, rect_width(&se_rect)); + } +} + +void main_bg_se_copy_rect_1_tile_vert(Rect se_rect, int direction) +{ + main_bg_se_copy_or_move_rect_1_tile_vert(se_rect, direction, false); } void main_bg_se_move_rect_1_tile_vert(Rect se_rect, int direction) { - if (se_rect.left > se_rect.right - || (direction != SE_UP && direction != SE_DOWN)) - { - return; - } - - // Clip to avoid read/write overflow of the screenblock - clip_se_rect_within_step_of_full_screen_vert(&se_rect); - - int deleted_y = (direction == SE_UP) ? se_rect.bottom : se_rect.top; - - main_bg_se_copy_rect_1_tile_vert(se_rect, direction); - - memset16(&se_mem[MAIN_BG_SBB][se_rect.left + SE_ROW_LEN * (deleted_y)], 0x0000, rect_width(&se_rect)); + main_bg_se_copy_or_move_rect_1_tile_vert(se_rect, direction, true); } void main_bg_se_copy_rect(Rect se_rect, BG_POINT pos) @@ -145,3 +152,19 @@ void tte_erase_rect_wrapper(Rect rect) tte_erase_rect(rect.left, rect.top, rect.right, rect.bottom); } +void update_text_rect_to_right_align_num(Rect* rect, int num, int overflow_direction) +{ + int num_digits = get_digits(num); + if (overflow_direction == OVERFLOW_RIGHT) + { + rect->left = max(0, rect->right - num_digits * TILE_SIZE); + } + else if (overflow_direction == OVERFLOW_LEFT) + { + int num_fitting_digits = rect_width(rect) / TILE_SIZE; + if (num_digits < num_fitting_digits) + rect->left += (num_fitting_digits - num_digits) * TILE_SIZE; + //else nothing is to be updated, entire rect is filled and may overflow + } +} +