diff --git a/include/graphic_utils.h b/include/graphic_utils.h index 121b83b..796c773 100644 --- a/include/graphic_utils.h +++ b/include/graphic_utils.h @@ -4,6 +4,11 @@ /* This file contains general utils and wrappers that relate to * graphics/video/vram and generally displaying things on the screen. * Mostly wrappers and defines for using tonc. + * + * Note: the code here assumes we're working with a single screenblock + * which should be true for this entire game since a screenblock + * is enough to contain a full screen (and more) + * and there isn't any scrolling etc. */ /* Reminder: @@ -17,13 +22,14 @@ #define AFFINE_BG_SBB 2 #define AFFINE_BG_CBB 2 -/* A 1024 size screenblock is arranged in a grid of 32x32 block entries +/* Dimensions for a screenblock. + * A 1024 size screenblock is arranged in a grid of 32x32 screen entries * Interestingly since each block is 8x8 pixels, the 240x160 GBA screen * is smaller than the screenblock, only the top left part of the screenblock * is displayed on the screen. */ -#define SCREENBLOCK_ROW_LEN 32 - +#define SE_ROW_LEN 32 +#define SE_COL_LEN 32 typedef struct { @@ -35,10 +41,17 @@ typedef struct #define UNDEFINED -1 -/* Clears a rect in the main background screenblock. - * The rect needs to be in screenblocks +/* Clears a rect in the main background. + * The se_rect dimensions need to be in number of tiles. */ -void main_bg_se_clear_rect(Rect rect); +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 + */ +void main_bg_se_copy_rect_1_tile_up(Rect se_rect); // 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 44b2a4a..df4ed41 100644 --- a/source/game.c +++ b/source/game.c @@ -108,36 +108,46 @@ static inline Card *discard_pop() // Consts -static const Rect ROUND_END_MENU_RECT = { 9, 7, 25, 21 }; // In screenblocks -// Rects for TTE -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 }; +// Rects left top right bottom +// Screenblock rects +static const Rect ROUND_END_MENU_RECT = {9, 7, 25, 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 + +// 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 }; // Score displayed in the same place as the hand type -static const Rect TEMP_SCORE_RECT = { 8, 64, 64, 72 }; +static const Rect TEMP_SCORE_RECT = {8, 64, 64, 72 }; -static const Rect PLAYED_CARDS_SCORES_RECT = { 72, 48, 240, 56 }; -static const Rect BLIND_TOKEN_TEXT_RECT = { 80, 72, 200, 160 }; -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 PLAYED_CARDS_SCORES_RECT = {72, 48, 240, 56 }; +static const Rect BLIND_TOKEN_TEXT_RECT = {80, 72, 200, 160 }; +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 }; // Rects with UNDEFINED are only used in tte_printf, they need to be fully defined // to be used with tte_erase_rect_wrapper() -static const Rect HANDS_TEXT_RECT = { 16, 104, UNDEFINED, UNDEFINED }; -static const Rect DISCARDS_TEXT_RECT = { 48, 104, UNDEFINED, UNDEFINED }; -static const Rect BLIND_REQUIREMENT_TEXT_RECT = { 40, 24, UNDEFINED, UNDEFINED }; -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_REQUIREMENT_RECT = { 112, 96, UNDEFINED, 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 }; -static const Rect CASHOUT_RECT = { 88, 72, UNDEFINED, UNDEFINED }; +static const Rect HANDS_TEXT_RECT = {16, 104, UNDEFINED, UNDEFINED }; +static const Rect DISCARDS_TEXT_RECT = {48, 104, UNDEFINED, UNDEFINED }; +static const Rect BLIND_REQ_TEXT_RECT = {40, 24, UNDEFINED, UNDEFINED }; +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_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 }; +static const Rect CASHOUT_RECT = {88, 72, UNDEFINED, UNDEFINED }; // General functions void sort_hand_by_suit() @@ -172,7 +182,6 @@ void sort_hand_by_rank() } } - void sort_cards() { if (sort_by_suit) @@ -656,7 +665,7 @@ void game_init() tte_printf("#{P:%d,%d; cx:0xF000}%d/%d", HAND_SIZE_RECT.left, HAND_SIZE_RECT.top, hand_get_size(), hand_get_max_size()); // Hand size/max size tte_printf("#{P:%d,%d; cx:0xF000}%d/%d", DECK_SIZE_RECT.left, DECK_SIZE_RECT.top, deck_get_size(), deck_get_max_size()); // Deck size/max size - tte_printf("#{P:%d,%d; cx:0xE000}%d", BLIND_REQUIREMENT_TEXT_RECT.left, BLIND_REQUIREMENT_TEXT_RECT.top, blind_get_requirement(current_blind, ante)); // Blind requirement + 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 tte_printf("#{P:%d,%d; cx:0xC000}$%d", BLIND_REWARD_RECT.left, BLIND_REWARD_RECT.top, blind_get_reward(current_blind)); // Blind reward set_score(score); // Set the score display @@ -1427,7 +1436,7 @@ void game_round_end() // Writing this kind a made me want to kms. If somewone wa { obj_unhide(round_end_blind_token->obj, 0); - tte_printf("#{P:%d,%d; cx:0xE000}%d", ROUND_END_BLIND_REQUIREMENT_RECT.left, ROUND_END_BLIND_REQUIREMENT_RECT.top, blind_get_requirement(current_blind, ante)); + 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, ante)); int y = 13; @@ -1469,7 +1478,7 @@ void game_round_end() // Writing this kind a made me want to kms. If somewone wa 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_REQUIREMENT_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_REQ_RECT.top, blind_get_reward(current_blind) - blind_reward); if (blind_reward <= 0) { @@ -1741,11 +1750,7 @@ void game_shop() if (timer < 13) { - 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_up(POP_MENU_ANIM_RECT); if (timer >= 7) { @@ -1763,7 +1768,7 @@ void game_shop() // { // int y_from = 26; // int y_to = 0; - // memcpy16(&se_mem[MAIN_BG_SE_BASE][32 * y_to], &se_mem[MAIN_BG_SE_BASE][32 * y_from], 9); + // memcpy16(&se_mem[MAIN_BG_SBB][32 * y_to], &se_mem[MAIN_BG_SBB][32 * y_from], 9); // } } } diff --git a/source/graphic_utils.c b/source/graphic_utils.c index a42a877..21925ef 100644 --- a/source/graphic_utils.c +++ b/source/graphic_utils.c @@ -1,22 +1,65 @@ -#include -#include - -#include "graphic_utils.h" - -void main_bg_se_clear_rect(Rect rect) -{ - for (int y = rect.top; y < rect.bottom; y++) - { - for (int x = rect.left; x < rect.right; x++) - { - // I also tried to use se_mat and it didn't work - memset16(&se_mem[MAIN_BG_SBB][x + SCREENBLOCK_ROW_LEN * y], 0x000, 1); - } - } -} - -void tte_erase_rect_wrapper(Rect rect) -{ - tte_erase_rect(rect.left, rect.top, rect.right, rect.bottom); -} - +#include +#include +#include + +#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); +} + +// Can be unstaticed if needed +// Clips a rect of screenblock entries to screenblock boundaries +// The bounding rect is not required to be within screenblock boundaries +static void clip_se_rect_to_screenblock(Rect* rect) +{ + clip_se_rect_to_bounding_rect(rect, &FULL_SCREENBLOCK_RECT); +} + + +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_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); + } +} + +void main_bg_se_copy_rect_1_tile_up(Rect se_rect) +{ + if (se_rect.left > se_rect.right) + return; + + Rect bounding_rect = FULL_SCREENBLOCK_RECT; + bounding_rect.top = 1; // Since we're going up, need to clip to 1 to not overflow + clip_se_rect_to_bounding_rect(&se_rect, &bounding_rect); + + for (int y = se_rect.top; y < se_rect.bottom; y++) + { + memcpy16(&se_mem[MAIN_BG_SBB][se_rect.left + SE_ROW_LEN * (y - 1)], + &se_mem[MAIN_BG_SBB][se_rect.left + SE_ROW_LEN * y], + se_rect.right - se_rect.left); + } +} + +void tte_erase_rect_wrapper(Rect rect) +{ + tte_erase_rect(rect.left, rect.top, rect.right, rect.bottom); +} +