From 05f4cc2abb2096964ec8efdf0a2f5c098ec0e46b Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Thu, 10 Jul 2025 20:59:04 +0300 Subject: [PATCH] Fixed generic main_bg_se_copy_rect_1_tile_vert() function and replaced some code with it --- include/graphic_utils.h | 13 +++++---- source/game.c | 63 ++++++++++++++++------------------------- source/graphic_utils.c | 36 ++++++++++++----------- 3 files changed, 51 insertions(+), 61 deletions(-) diff --git a/include/graphic_utils.h b/include/graphic_utils.h index 796c773b..e505f743 100644 --- a/include/graphic_utils.h +++ b/include/graphic_utils.h @@ -31,6 +31,10 @@ #define SE_ROW_LEN 32 #define SE_COL_LEN 32 +// Since y direction goes from the top of the screen to the bottom +#define SE_UP -1 +#define SE_DOWN 1 + typedef struct { int left; @@ -46,12 +50,11 @@ typedef struct */ void main_bg_se_clear_rect(Rect se_rect); -/* Copies a rect in the main background a single tile up. - * The se_rect dimensions need to be in number of tiles. - * This is for the pop menu animation, can later be generalized to more tiles - * or other directions +/* Copies a rect in the main background vertically in direction by a single tile. + * direction must be either SE_UP or SE_DOWN. + * se_rect dimensions are in number of tiles. */ -void main_bg_se_copy_rect_1_tile_up(Rect se_rect); +void main_bg_se_copy_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); diff --git a/source/game.c b/source/game.c index d43bdba2..9195bab4 100644 --- a/source/game.c +++ b/source/game.c @@ -113,14 +113,18 @@ static inline Card *discard_pop() // Rects left top right bottom // Screenblock rects -static const Rect ROUND_END_MENU_RECT = {9, 7, 25, 21 }; +static const Rect ROUND_END_MENU_RECT = {9, 7, 24, 21 }; -static const Rect POP_MENU_ANIM_RECT = {9, 7, 25, 32 }; -// The rect for popping menu animations - includes both the target and source position -// rects. The source position extends beyond the visible screen to the end -// of the screenblock -// The target position is blank so we just animate the whole thing so we don't -// have to track its position +static const Rect POP_MENU_ANIM_RECT = {9, 6, 24, 32 }; +// The rect for popping menu animations (round end, shop, blinds) - includes both the +// target and source position rects. +// Extends beyond the visible screen to the end of the screenblock +// This is because when popping, the target position is blank so we just animate the whole thing +// so we don't have to track its position +// +// When unpopping we include another row above the menu assuming it's blank so it's copied into it + +static const Rect SHOP_ICON_RECT = { 0, 0, 8, 4 }; // Rects for TTE (in pixels) static const Rect HAND_SIZE_RECT = {128, 128, 152, 160 }; // Seems to include both SELECT and PLAYING @@ -373,7 +377,7 @@ void change_background(int id) // Incoming hack! Clear the round end menu so that we can slowly display it with an animation later. The reason this isn't optimal is because the full background is already loaded into the vram at this point. // I'm just doing it this way because it's easier than doing some weird shit with Grit in order to get a proper tilemap. I'm not the biggest fan of Grit. - // TODO: See TODO comment in game_round_end(), once that is properly done, remove this. + // TODO: Remove this if game_round_end() is fixed to use main_bg_se_copy_rect_1_tile_vert() for the pop menu main_bg_se_clear_rect(ROUND_END_MENU_RECT); //tte_erase_rect(0, 0, 64, 48); // Clear top left corner where the blind stats are displayed @@ -1460,9 +1464,11 @@ void game_playing() void game_round_end() // Writing this kind a made me want to kms. If somewone wants to rewrite this, please do so. { - /* TODO: The correct way to do this is the same as game_shop(), - * put the menu in VRAM outside the screen and copy it from there. - * That code needs to be extracted to a function and reused here. + /* TODO: I could use main_bg_se_copy_rect_1_tile_vert() to replace the menu pop up here + * But there are a bunch of other manual hard-coded tilemap animations in here that + * are very hard to understand, and if I change the background image for the pop up + * it will change the tile charblock layout and screw them up so it's all or nothing... + * - Meir */ static int state = 0; static int sequence_step = 0; // Reusable variable for the animations in states @@ -1799,12 +1805,7 @@ void game_round_end() // Writing this kind a made me want to kms. If somewone wa case 8: { sequence_step++; - int x = 9; - - for (int y = 19; y > 5; y--) - { - memcpy16(&se_mem[MAIN_BG_SBB][x + 32 * (y + 1)], &se_mem[MAIN_BG_SBB][x + 32 * y], 16); - } + main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT, SE_DOWN); if (sequence_step >= 20) { @@ -1868,16 +1869,13 @@ void game_shop() { case 0: // Intro sequence (menu and shop icon coming into frame) { - for (int y = 7; y < 40; y++) // Shift the shop panel - { - int x = 9; - memcpy16(&se_mem[MAIN_BG_SBB][x + 32 * (y - 1)], &se_mem[MAIN_BG_SBB][x + 32 * y], 16); - } + main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT, SE_UP); if (timer >= 7) // Shift the shop icon { int timer_offset = timer - 6; + // TODO: Extract to generic function? for (int y = 0; y < timer_offset; y++) { int y_from = 26 + y - timer_offset; @@ -1969,19 +1967,10 @@ void game_shop() } case 2: // Outro sequence (menu and shop icon going out of frame) { - // This is reused from game_round_end() // Shift the shop panel - int x = 9; - for (int y = 19; y > 5; y--) - { - memcpy16(&se_mem[MAIN_BG_SBB][x + 32 * (y + 1)], &se_mem[MAIN_BG_SBB][x + 32 * y], 16); - } + main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT, SE_DOWN); - // Shift the shop icon - for (int y = 0; y < 5; y++) - { - memcpy16(&se_mem[MAIN_BG_SBB][32 * (y - 1)], &se_mem[MAIN_BG_SBB][32 * y], 9); - } + main_bg_se_copy_rect_1_tile_vert(SHOP_ICON_RECT, SE_UP); if (timer == 1) { @@ -2033,13 +2022,9 @@ void game_blind_select() switch (state) // I'm only using magic numbers here for the sake of simplicity since it's just sequential, but you can replace them with named constants or enums if it makes it clearer { - case 0: // Intro sequence (menu and shop icon coming into frame) + case 0: // Intro sequence (menu coming into frame) { - for (int y = 7; y < 40; y++) - { - int x = 9; - memcpy16(&se_mem[MAIN_BG_SBB][x + 32 * (y - 1)], &se_mem[MAIN_BG_SBB][x + 32 * y], 16); - } + main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT, SE_UP); if (timer == 12) { diff --git a/source/graphic_utils.c b/source/graphic_utils.c index 21925ef9..48fa2431 100644 --- a/source/graphic_utils.c +++ b/source/graphic_utils.c @@ -4,19 +4,15 @@ #include "graphic_utils.h" -/* - * - */ const Rect FULL_SCREENBLOCK_RECT = { 0, 0, SE_ROW_LEN, SE_COL_LEN }; - // Clips a rect of screenblock entries to a specified rect static void clip_se_rect_to_bounding_rect(Rect* rect, const Rect* bounding_rect) { - rect->right = min(rect->right, SE_ROW_LEN); - rect->bottom = min(rect->bottom, SE_COL_LEN); - rect->left = max(rect->left, 0); - rect->top = max(rect->top, 0); + rect->right = min(rect->right, bounding_rect->right); + rect->bottom = min(rect->bottom, bounding_rect->bottom); + rect->left = max(rect->left, bounding_rect->left); + rect->top = max(rect->top, bounding_rect->top); } // Can be unstaticed if needed @@ -32,29 +28,35 @@ void main_bg_se_clear_rect(Rect se_rect) { if (se_rect.left > se_rect.right) return; - // Just to make sure we're not overflowing the boundaries + // Clip to avoid screenblock overflow clip_se_rect_to_screenblock(&se_rect); for (int y = se_rect.top; y < se_rect.bottom; y++) { - memset16(&(se_mem[MAIN_BG_SBB][se_rect.left + SE_ROW_LEN * y]), 0x0000, se_rect.right - se_rect.left); + memset16(&(se_mem[MAIN_BG_SBB][se_rect.left + SE_ROW_LEN * y]), 0x0000, se_rect.right - se_rect.left + 1); } } -void main_bg_se_copy_rect_1_tile_up(Rect se_rect) +void main_bg_se_copy_rect_1_tile_vert(Rect se_rect, int direction) { - if (se_rect.left > se_rect.right) + if (se_rect.left > se_rect.right + || (direction != SE_UP && direction != SE_DOWN)) return; - + + // Clip to avoid read/write overflow of the screenblock Rect bounding_rect = FULL_SCREENBLOCK_RECT; - bounding_rect.top = 1; // Since we're going up, need to clip to 1 to not overflow + bounding_rect.top = 1; + bounding_rect.bottom = SE_COL_LEN - 1; clip_se_rect_to_bounding_rect(&se_rect, &bounding_rect); - for (int y = se_rect.top; y < se_rect.bottom; y++) + int start = (direction == SE_UP) ? se_rect.top : se_rect.bottom; + int end = (direction == SE_UP) ? se_rect.bottom : se_rect.top; + + for (int y = start; y != end - direction; y -= direction) { - memcpy16(&se_mem[MAIN_BG_SBB][se_rect.left + SE_ROW_LEN * (y - 1)], + 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_rect.right - se_rect.left); + se_rect.right - se_rect.left + 1); } }