[Feature] Implement seeded runs by adding a Seed selection menu (#482)
* initial commit * wip * WIP * WIP * clang format * Choose Seed navigation mostly done * seed input navigation done * seed input done * cleanup and clang format * Implement base 10 to 36 conversions * Enable seeded runs * clang format * show default deck sprite, name and description * Rename Deck enum to DeckType * Implement arbitrary 9-patch expand system * Make 9-patch example smaller in the docs * Improve NinePatchRect docs * fix Deck back side sprite palette * clang format * Add last deck description * clang format * Fix 'Z' in seed input keyboard * Fix rebase issue * fix deck sprite not updating * Documents static funcs in run_setup.c * more documentation * clang format * Move Play button to the left in its row * Tests WIP * removing tests for random.h * use the new StateMachine struct * First wave of fixes * Fix the 9-patch again * Changed the base 36 logic so it's in big endian * properly set end of base 36 string to '\0' * typos * fix cursor position after rolling a seed + fix random seed generation * Make keyboard more intuitive to use * static const var * Address more comment from @ricfehr3 * clang format * clang format * clang format * clang format * clang format * clang format * clang format * fix deck palette * create the `DEF_SEED_KEYBOARD_BUTTON_OBJECT` macro * Replace `expand_3x3` by a call to `expand_9-patch` * clang format * clang format * clang format * fix rebase iussue in state_machine.h --------- Co-authored-by: MathisMartin31 <mathis.martin31@gmail.com>
This commit is contained in:
+2
-2
@@ -12,8 +12,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <tonc.h>
|
||||
|
||||
#define NORMAL_BLIND_PB 1
|
||||
#define BOSS_BLIND_PB 2
|
||||
#define NORMAL_BLIND_PB 2
|
||||
#define BOSS_BLIND_PB 3
|
||||
|
||||
#define BLIND_BASE_LAYER (MAX_HAND_SIZE + MAX_SELECTION_SIZE)
|
||||
|
||||
|
||||
+29
-3
@@ -12,6 +12,7 @@
|
||||
// Card Sprites and Palettes
|
||||
#include "deck_big_gfx.h"
|
||||
#include "deck_gfx.h"
|
||||
#include "decks_face_down_gfx.h"
|
||||
#include "high_contrast_deck_pal_gfx.h"
|
||||
|
||||
// Card sprites lookup table. First index is the suit, second index is the rank. The value is the
|
||||
@@ -22,20 +23,27 @@ const static u16 _card_sprite_lut[NUM_SUITS][NUM_RANKS] = {
|
||||
{416, 432, 448, 464, 480, 496, 512, 528, 544, 560, 576, 592, 608},
|
||||
{624, 640, 656, 672, 688, 704, 720, 736, 752, 768, 784, 800, 816}
|
||||
};
|
||||
// Deck sprites lookup table. Index is the deck Id. The value is the tile index.
|
||||
const static u16 _deck_sprite_lut[DECK_TYPE_MAX] = {0, 16, 32, 48, 64, 80};
|
||||
|
||||
bool high_contrast = DEFAULT_HIGH_CONTRAST;
|
||||
bool more_readable = DEFAULT_MORE_READABLE;
|
||||
|
||||
void card_init()
|
||||
{
|
||||
GRIT_CPY(&pal_obj_mem[DECK_SPRITES_PB * PAL_ROW_LEN], decks_face_down_gfxPal);
|
||||
}
|
||||
|
||||
void set_cards_high_contrast(bool enable)
|
||||
{
|
||||
high_contrast = enable;
|
||||
if (high_contrast)
|
||||
{
|
||||
GRIT_CPY(&pal_obj_mem[CARD_PB], high_contrast_deck_pal_gfxPal);
|
||||
GRIT_CPY(&pal_obj_mem[CARD_PB * PAL_ROW_LEN], high_contrast_deck_pal_gfxPal);
|
||||
}
|
||||
else
|
||||
{
|
||||
GRIT_CPY(&pal_obj_mem[CARD_PB], deck_gfxPal);
|
||||
GRIT_CPY(&pal_obj_mem[CARD_PB * PAL_ROW_LEN], deck_gfxPal);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +138,25 @@ void card_object_set_sprite(CardObject* card_object, int layer)
|
||||
ATTR0_SQUARE | ATTR0_4BPP | ATTR0_AFF,
|
||||
ATTR1_SIZE_32,
|
||||
tile_index,
|
||||
0,
|
||||
CARD_PB,
|
||||
layer + CARD_STARTING_LAYER
|
||||
);
|
||||
sprite_object_set_sprite(card_object->sprite_object, sprite);
|
||||
}
|
||||
|
||||
void card_object_set_sprite_face_down(CardObject* card_object, enum DeckType deck, int layer)
|
||||
{
|
||||
int tile_index = CARD_TID + (layer * CARD_SPRITE_OFFSET);
|
||||
memcpy32(
|
||||
&tile_mem[TILE_MEM_OBJ_CHARBLOCK0_IDX][tile_index],
|
||||
&decks_face_down_gfxTiles[_deck_sprite_lut[deck] * TILE_SIZE],
|
||||
TILE_SIZE * CARD_SPRITE_OFFSET
|
||||
);
|
||||
Sprite* sprite = sprite_new(
|
||||
ATTR0_SQUARE | ATTR0_4BPP | ATTR0_AFF,
|
||||
ATTR1_SIZE_32,
|
||||
tile_index,
|
||||
DECK_SPRITES_PB,
|
||||
layer + CARD_STARTING_LAYER
|
||||
);
|
||||
sprite_object_set_sprite(card_object->sprite_object, sprite);
|
||||
|
||||
@@ -0,0 +1,300 @@
|
||||
/**
|
||||
* @file deck_types.c
|
||||
*
|
||||
* @brief Implementation of functions related to the different types of Decks.
|
||||
*/
|
||||
#include "deck_types.h"
|
||||
|
||||
#include "game.h"
|
||||
|
||||
#include <tonc.h>
|
||||
|
||||
#define TTE_COLOR_TEXT_FORMAT "#{cx:0x%X000}%s"
|
||||
|
||||
/**
|
||||
* @brief List of DeckType names, all formatted to be centered in a string of 13 characters.
|
||||
*/
|
||||
static const char deck_names[DECK_TYPE_MAX][DECK_NAME_LENGTH] = {
|
||||
" Red Deck ",
|
||||
" Blue Deck ",
|
||||
" Yellow Deck ",
|
||||
" Green Deck ",
|
||||
" Black Deck ",
|
||||
"Painted Deck "
|
||||
};
|
||||
|
||||
static void print_desc_red_deck(BG_POINT pos);
|
||||
static void print_desc_blue_deck(BG_POINT pos);
|
||||
static void print_desc_yellow_deck(BG_POINT pos);
|
||||
static void print_desc_green_deck(BG_POINT pos);
|
||||
static void print_desc_black_deck(BG_POINT pos);
|
||||
static void print_desc_painted_deck(BG_POINT pos);
|
||||
|
||||
typedef void (*PrintDescCallback)(BG_POINT);
|
||||
static const PrintDescCallback deck_description_functions[DECK_TYPE_MAX] = {
|
||||
print_desc_red_deck,
|
||||
print_desc_blue_deck,
|
||||
print_desc_yellow_deck,
|
||||
print_desc_green_deck,
|
||||
print_desc_black_deck,
|
||||
print_desc_painted_deck
|
||||
};
|
||||
|
||||
void print_deck_name(enum DeckType deck, BG_POINT pos)
|
||||
{
|
||||
tte_printf("#{P:%d,%d; cx:0x%X000}%s", pos.x, pos.y, TTE_WHITE_PB, deck_names[deck]);
|
||||
}
|
||||
|
||||
void print_deck_description(enum DeckType deck, BG_POINT pos)
|
||||
{
|
||||
if (deck_description_functions[deck] == NULL)
|
||||
return;
|
||||
|
||||
deck_description_functions[deck](pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print an empty string of 13 characters long at given coordinates.
|
||||
* Reduces boilerplate in deck descriptions functions.
|
||||
*
|
||||
* @param pos_x
|
||||
* @param pos_y
|
||||
*/
|
||||
static inline void print_empty_desc_line(int pos_x, int pos_y)
|
||||
{
|
||||
tte_printf("#{P:%d,%d}" TTE_COLOR_TEXT_FORMAT, pos_x, pos_y, TTE_BLACK_PB, " ");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print the decription of the Red Deck
|
||||
* ```
|
||||
* " "
|
||||
* " +1 discard "
|
||||
* " every Round "
|
||||
* " "
|
||||
* " "
|
||||
* ```
|
||||
* @param pos position of the rectagle to print the description to
|
||||
*/
|
||||
static void print_desc_red_deck(BG_POINT pos)
|
||||
{
|
||||
print_empty_desc_line(pos.x, pos.y);
|
||||
tte_printf(
|
||||
"#{P:%d,%d}" TTE_COLOR_TEXT_FORMAT TTE_COLOR_TEXT_FORMAT,
|
||||
pos.x,
|
||||
pos.y + TILE_SIZE,
|
||||
TTE_RED_PB,
|
||||
" +1 ",
|
||||
TTE_BLACK_PB,
|
||||
"discard "
|
||||
);
|
||||
tte_printf(
|
||||
"#{P:%d,%d}" TTE_COLOR_TEXT_FORMAT,
|
||||
pos.x,
|
||||
pos.y + 2 * TILE_SIZE,
|
||||
TTE_BLACK_PB,
|
||||
" every Round "
|
||||
);
|
||||
print_empty_desc_line(pos.x, pos.y + 3 * TILE_SIZE);
|
||||
print_empty_desc_line(pos.x, pos.y + 4 * TILE_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print the decription of the Blue Deck
|
||||
* ```
|
||||
* " "
|
||||
* " +1 hand "
|
||||
* " every Round "
|
||||
* " "
|
||||
* " "
|
||||
* ```
|
||||
* @param pos position of the rectagle to print the description to
|
||||
*/
|
||||
static void print_desc_blue_deck(BG_POINT pos)
|
||||
{
|
||||
print_empty_desc_line(pos.x, pos.y);
|
||||
tte_printf(
|
||||
"#{P:%d,%d}" TTE_COLOR_TEXT_FORMAT TTE_COLOR_TEXT_FORMAT,
|
||||
pos.x,
|
||||
pos.y + TILE_SIZE,
|
||||
TTE_BLUE_PB,
|
||||
" +1 ",
|
||||
TTE_BLACK_PB,
|
||||
"hand "
|
||||
);
|
||||
tte_printf(
|
||||
"#{P:%d,%d}" TTE_COLOR_TEXT_FORMAT,
|
||||
pos.x,
|
||||
pos.y + 2 * TILE_SIZE,
|
||||
TTE_BLACK_PB,
|
||||
" every Round "
|
||||
);
|
||||
print_empty_desc_line(pos.x, pos.y + 3 * TILE_SIZE);
|
||||
print_empty_desc_line(pos.x, pos.y + 4 * TILE_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print the decription of the Yellow Deck
|
||||
* ```
|
||||
* " "
|
||||
* " Start with "
|
||||
* "an extra $10 "
|
||||
* " "
|
||||
* " "
|
||||
* ```
|
||||
* @param pos position of the rectagle to print the description to
|
||||
*/
|
||||
static void print_desc_yellow_deck(BG_POINT pos)
|
||||
{
|
||||
print_empty_desc_line(pos.x, pos.y);
|
||||
tte_printf(
|
||||
"#{P:%d,%d}" TTE_COLOR_TEXT_FORMAT,
|
||||
pos.x,
|
||||
pos.y + TILE_SIZE,
|
||||
TTE_BLACK_PB,
|
||||
" Start with "
|
||||
);
|
||||
tte_printf(
|
||||
"#{P:%d,%d}" TTE_COLOR_TEXT_FORMAT TTE_COLOR_TEXT_FORMAT,
|
||||
pos.x,
|
||||
pos.y + 2 * TILE_SIZE,
|
||||
TTE_BLACK_PB,
|
||||
"an extra",
|
||||
TTE_YELLOW_PB,
|
||||
" $10 "
|
||||
);
|
||||
print_empty_desc_line(pos.x, pos.y + 3 * TILE_SIZE);
|
||||
print_empty_desc_line(pos.x, pos.y + 4 * TILE_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print the decription of the Green Deck
|
||||
* ```
|
||||
* "End of Round:"
|
||||
* " "
|
||||
* "-$2 per Hand "
|
||||
* "-$2 per Disc."
|
||||
* "-No Interest "
|
||||
* ```
|
||||
* @param pos position of the rectagle to print the description to
|
||||
*/
|
||||
static void print_desc_green_deck(BG_POINT pos)
|
||||
{
|
||||
tte_printf("#{P:%d,%d; cx:0x%X000}%s", pos.x, pos.y, TTE_BLACK_PB, "End of Round:");
|
||||
print_empty_desc_line(pos.x, pos.y + TILE_SIZE);
|
||||
tte_printf(
|
||||
"#{P:%d,%d}" TTE_COLOR_TEXT_FORMAT TTE_COLOR_TEXT_FORMAT TTE_COLOR_TEXT_FORMAT
|
||||
TTE_COLOR_TEXT_FORMAT,
|
||||
pos.x,
|
||||
pos.y + 2 * TILE_SIZE,
|
||||
TTE_BLACK_PB,
|
||||
"-",
|
||||
TTE_YELLOW_PB,
|
||||
"$2 ",
|
||||
TTE_BLACK_PB,
|
||||
"per ",
|
||||
TTE_RED_PB,
|
||||
"Hand "
|
||||
);
|
||||
tte_printf(
|
||||
"#{P:%d,%d}" TTE_COLOR_TEXT_FORMAT TTE_COLOR_TEXT_FORMAT TTE_COLOR_TEXT_FORMAT
|
||||
TTE_COLOR_TEXT_FORMAT,
|
||||
pos.x,
|
||||
pos.y + 3 * TILE_SIZE,
|
||||
TTE_BLACK_PB,
|
||||
"-",
|
||||
TTE_YELLOW_PB,
|
||||
"$1 ",
|
||||
TTE_BLACK_PB,
|
||||
"per ",
|
||||
TTE_BLUE_PB,
|
||||
"Disc."
|
||||
);
|
||||
tte_printf(
|
||||
"#{P:%d,%d}" TTE_COLOR_TEXT_FORMAT TTE_COLOR_TEXT_FORMAT,
|
||||
pos.x,
|
||||
pos.y + 4 * TILE_SIZE,
|
||||
TTE_BLACK_PB,
|
||||
"-No ",
|
||||
TTE_YELLOW_PB,
|
||||
"Interest "
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print the decription of the Black Deck
|
||||
* ```
|
||||
* "+1 Joker slot"
|
||||
* " "
|
||||
* " -1 hand "
|
||||
* " every Round "
|
||||
* " "
|
||||
* ```
|
||||
* @param pos position of the rectagle to print the description to
|
||||
*/
|
||||
static void print_desc_black_deck(BG_POINT pos)
|
||||
{
|
||||
tte_printf(
|
||||
"#{P:%d,%d}" TTE_COLOR_TEXT_FORMAT TTE_COLOR_TEXT_FORMAT,
|
||||
pos.x,
|
||||
pos.y,
|
||||
TTE_YELLOW_PB,
|
||||
"+1 ",
|
||||
TTE_BLACK_PB,
|
||||
"Joker slot"
|
||||
);
|
||||
print_empty_desc_line(pos.x, pos.y + TILE_SIZE);
|
||||
tte_printf(
|
||||
"#{P:%d,%d}" TTE_COLOR_TEXT_FORMAT TTE_COLOR_TEXT_FORMAT,
|
||||
pos.x,
|
||||
pos.y + 2 * TILE_SIZE,
|
||||
TTE_BLUE_PB,
|
||||
" -1 ",
|
||||
TTE_BLACK_PB,
|
||||
"hand "
|
||||
);
|
||||
tte_printf(
|
||||
"#{P:%d,%d}" TTE_COLOR_TEXT_FORMAT,
|
||||
pos.x,
|
||||
pos.y + 3 * TILE_SIZE,
|
||||
TTE_BLACK_PB,
|
||||
" every Round "
|
||||
);
|
||||
print_empty_desc_line(pos.x, pos.y + 4 * TILE_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print the decription of the Painted Deck
|
||||
* ```
|
||||
* " "
|
||||
* "+2 Hand size "
|
||||
* "-1 Joker slot"
|
||||
* " "
|
||||
* " "
|
||||
* ```
|
||||
* @param pos position of the rectagle to print the description to
|
||||
*/
|
||||
static void print_desc_painted_deck(BG_POINT pos)
|
||||
{
|
||||
print_empty_desc_line(pos.x, pos.y);
|
||||
tte_printf(
|
||||
"#{P:%d,%d}" TTE_COLOR_TEXT_FORMAT TTE_COLOR_TEXT_FORMAT,
|
||||
pos.x,
|
||||
pos.y + TILE_SIZE,
|
||||
TTE_YELLOW_PB,
|
||||
"+2 ",
|
||||
TTE_BLACK_PB,
|
||||
"Hand size "
|
||||
);
|
||||
tte_printf(
|
||||
"#{P:%d,%d}" TTE_COLOR_TEXT_FORMAT TTE_COLOR_TEXT_FORMAT,
|
||||
pos.x,
|
||||
pos.y + 2 * TILE_SIZE,
|
||||
TTE_RED_PB,
|
||||
"-1 ",
|
||||
TTE_BLACK_PB,
|
||||
"Joker slot"
|
||||
);
|
||||
print_empty_desc_line(pos.x, pos.y + 3 * TILE_SIZE);
|
||||
print_empty_desc_line(pos.x, pos.y + 4 * TILE_SIZE);
|
||||
}
|
||||
+3
-4
@@ -14,6 +14,7 @@
|
||||
#include "game/main_menu.h"
|
||||
#include "game/options_menu.h"
|
||||
#include "game/round_end.h"
|
||||
#include "game/run_setup.h"
|
||||
#include "game/shop.h"
|
||||
#include "game_variables.h"
|
||||
#include "graphic_utils.h"
|
||||
@@ -266,8 +267,8 @@ static enum PlayState play_state = PLAY_STARTING;
|
||||
GameVariables g_game_vars = {
|
||||
.timer = 0, .rng_info = {0, 0},
|
||||
|
||||
.round = 0, .ante = 0, .money = 0,
|
||||
.hand_size = DEFAULT_HAND_SIZE,
|
||||
.round = 0, .ante = 0, .money = 0, .hand_size = DEFAULT_HAND_SIZE,
|
||||
.deck = DECK_TYPE_RED,
|
||||
|
||||
.current_blind = BLIND_TYPE_SMALL,
|
||||
.next_boss_blind = BLIND_TYPE_BIG,
|
||||
@@ -2547,8 +2548,6 @@ static void game_playing_on_update(void)
|
||||
|
||||
void game_start(void)
|
||||
{
|
||||
rng_shuffle_seed();
|
||||
|
||||
affine_background_change_background(AFFINE_BG_GAME);
|
||||
|
||||
g_game_vars.hands = MAX_HANDS;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "game/main_menu.h"
|
||||
#include "game/options_menu.h"
|
||||
#include "game/round_end.h"
|
||||
#include "game/run_setup.h"
|
||||
#include "game/shop.h"
|
||||
|
||||
typedef void (*BackgroundRenderCallback)(void);
|
||||
@@ -19,6 +20,7 @@ static const BackgroundRenderCallback bgCallbacks[] = {
|
||||
[BG_ROUND_END] = game_round_end_change_background,
|
||||
[BG_SHOP] = game_shop_change_background,
|
||||
[BG_BLIND_SELECT] = game_blind_select_change_background,
|
||||
[BG_RUN_SETUP] = game_run_setup_change_background,
|
||||
[BG_OPTIONS_MENU] = game_options_menu_change_background,
|
||||
[BG_MAIN_MENU] = game_main_menu_change_background,
|
||||
};
|
||||
|
||||
@@ -102,7 +102,7 @@ void game_main_menu_change_background(void)
|
||||
void game_main_menu_on_init(void)
|
||||
{
|
||||
affine_background_change_background(AFFINE_BG_MAIN_MENU);
|
||||
change_background(BG_MAIN_MENU, false);
|
||||
change_background(BG_MAIN_MENU, true);
|
||||
main_menu_ace = card_object_new(card_new(SPADES, ACE));
|
||||
card_object_set_sprite(main_menu_ace, 0);
|
||||
main_menu_ace->sprite_object->sprite->obj->attr0 |= ATTR0_AFF_DBL;
|
||||
@@ -208,7 +208,7 @@ static void main_menu_on_key_transit(SelectionGrid* selection_grid, Selection* s
|
||||
|
||||
static void play_on_pressed(void)
|
||||
{
|
||||
game_change_state(GAME_STATE_GAME_START);
|
||||
game_change_state(GAME_STATE_RUN_SETUP);
|
||||
}
|
||||
|
||||
static void options_on_pressed(void)
|
||||
|
||||
@@ -359,7 +359,6 @@ static void update_volume_slider_graphics(enum OptionButtonRows sel_row)
|
||||
void game_options_menu_change_background(void)
|
||||
{
|
||||
tte_erase_screen();
|
||||
CBB_CLEAR(MAIN_BG_CBB);
|
||||
|
||||
GRIT_CPY(pal_bg_mem, background_options_menu_gfxPal);
|
||||
GRIT_CPY(&tile_mem[MAIN_BG_CBB], background_options_menu_gfxTiles);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+183
-95
@@ -69,9 +69,7 @@ static void bg_se_copy_or_move_rect_1_tile_vert(
|
||||
)
|
||||
{
|
||||
if (se_rect.left > se_rect.right || (direction != SCREEN_UP && direction != SCREEN_DOWN))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Clip to avoid read/write overflow of the screenblock
|
||||
clip_se_rect_within_step_of_full_screen_vert(&se_rect, direction);
|
||||
@@ -166,51 +164,27 @@ static inline void main_bg_se_fill_rect_with_se(SE se, Rect se_rect)
|
||||
}
|
||||
}
|
||||
|
||||
// Helper: Copy the corners of a 3x3 tile block
|
||||
static inline void main_bg_se_expand_3x3_copy_corners(
|
||||
const Rect* se_dest_rect,
|
||||
const BG_POINT* src_top_left_pnt,
|
||||
int dest_rect_width,
|
||||
int dest_rect_height
|
||||
)
|
||||
void main_bg_se_copy_expand_tile(Rect se_rect_dest, BG_POINT se_tile_src)
|
||||
{
|
||||
SE top_left_se = se_mat[MAIN_BG_SBB][src_top_left_pnt->y][src_top_left_pnt->x];
|
||||
se_mat[MAIN_BG_SBB][se_dest_rect->top][se_dest_rect->left] = top_left_se;
|
||||
|
||||
SE top_right_se = se_mat[MAIN_BG_SBB][src_top_left_pnt->y][src_top_left_pnt->x + 2];
|
||||
se_mat[MAIN_BG_SBB][se_dest_rect->top][se_dest_rect->left + dest_rect_width - 1] = top_right_se;
|
||||
|
||||
SE bottom_left_se = se_mat[MAIN_BG_SBB][src_top_left_pnt->y + 2][src_top_left_pnt->x];
|
||||
se_mat[MAIN_BG_SBB][se_dest_rect->top + dest_rect_height - 1][se_dest_rect->left] =
|
||||
bottom_left_se;
|
||||
|
||||
SE bottom_right_se = se_mat[MAIN_BG_SBB][src_top_left_pnt->y + 2][src_top_left_pnt->x + 2];
|
||||
se_mat[MAIN_BG_SBB][se_dest_rect->top + dest_rect_height - 1]
|
||||
[se_dest_rect->left + dest_rect_width - 1] = bottom_right_se;
|
||||
main_bg_se_fill_rect_with_se(se_mat[MAIN_BG_SBB][se_tile_src.y][se_tile_src.x], se_rect_dest);
|
||||
}
|
||||
|
||||
// Helper: Copy the top and bottom sides of a 3x3 tile block
|
||||
static inline void main_bg_se_expand_3x3_copy_top_bottom(
|
||||
const Rect* se_dest_rect,
|
||||
const BG_POINT* src_top_left_pnt,
|
||||
int dest_rect_width
|
||||
)
|
||||
void main_bg_se_copy_expand_3x3_rect(Rect se_dest_rect, BG_POINT src_top_left_pnt)
|
||||
{
|
||||
if (dest_rect_width > 2)
|
||||
{
|
||||
SE top_middle_se = se_mat[MAIN_BG_SBB][src_top_left_pnt->y][src_top_left_pnt->x + 1];
|
||||
SE bottom_middle_se = se_mat[MAIN_BG_SBB][src_top_left_pnt->y + 2][src_top_left_pnt->x + 1];
|
||||
memset16(
|
||||
&se_mat[MAIN_BG_SBB][se_dest_rect->top][se_dest_rect->left + 1],
|
||||
top_middle_se,
|
||||
dest_rect_width - 2
|
||||
);
|
||||
memset16(
|
||||
&se_mat[MAIN_BG_SBB][se_dest_rect->bottom][se_dest_rect->left + 1],
|
||||
bottom_middle_se,
|
||||
dest_rect_width - 2
|
||||
);
|
||||
}
|
||||
// New implementation: uses a 9-patch to factorize as much code as we can
|
||||
// clang-format off
|
||||
NinePatchRect src_9_ptch = {
|
||||
.patch_rect =
|
||||
{
|
||||
src_top_left_pnt.x,
|
||||
src_top_left_pnt.y,
|
||||
src_top_left_pnt.x + 2,
|
||||
src_top_left_pnt.y + 2
|
||||
},
|
||||
.margins = {1, 1, 1, 1}
|
||||
};
|
||||
// clang-format on
|
||||
main_bg_se_copy_expand_9_patch(se_dest_rect, &src_9_ptch);
|
||||
}
|
||||
|
||||
// Helper: Copy the left and right sides of a 3x3 tile block
|
||||
@@ -232,62 +206,12 @@ static inline void main_bg_se_3w_copy_expand_left_right_sides(
|
||||
}
|
||||
}
|
||||
|
||||
void main_bg_se_copy_expand_3x3_rect(Rect se_dest_rect, BG_POINT src_top_left_pnt)
|
||||
{
|
||||
clip_se_rect_to_screenblock(&se_dest_rect);
|
||||
|
||||
int dest_rect_width = rect_width(&se_dest_rect);
|
||||
int dest_rect_height = rect_height(&se_dest_rect);
|
||||
|
||||
// Verify the dest rect is at least 2x2
|
||||
if (dest_rect_width < 2 || dest_rect_height < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy the corners
|
||||
main_bg_se_expand_3x3_copy_corners(
|
||||
&se_dest_rect,
|
||||
&src_top_left_pnt,
|
||||
dest_rect_width,
|
||||
dest_rect_height
|
||||
);
|
||||
|
||||
// Copy top and bottom sides
|
||||
main_bg_se_expand_3x3_copy_top_bottom(&se_dest_rect, &src_top_left_pnt, dest_rect_width);
|
||||
|
||||
BG_POINT src_middle_left_pnt = {src_top_left_pnt.x, src_top_left_pnt.y + 1};
|
||||
|
||||
// Avoid the corners when copying the sides
|
||||
Rect dest_sides_rect = se_dest_rect;
|
||||
dest_sides_rect.top += 1;
|
||||
dest_sides_rect.bottom -= 1;
|
||||
|
||||
// Copy left and right sides
|
||||
main_bg_se_3w_copy_expand_left_right_sides(&dest_sides_rect, &src_middle_left_pnt);
|
||||
|
||||
// Fill the center if needed
|
||||
if (dest_rect_width > 2 && dest_rect_height > 2)
|
||||
{
|
||||
SE middle_fill_se = se_mat[MAIN_BG_SBB][src_top_left_pnt.y + 1][src_top_left_pnt.x + 1];
|
||||
Rect dest_inner_fill_rect = {
|
||||
se_dest_rect.left + 1,
|
||||
se_dest_rect.top + 1,
|
||||
se_dest_rect.right - 1,
|
||||
se_dest_rect.bottom - 1
|
||||
};
|
||||
main_bg_se_fill_rect_with_se(middle_fill_se, dest_inner_fill_rect);
|
||||
}
|
||||
}
|
||||
|
||||
void main_bg_se_copy_expand_3w_row(Rect se_dest_rect, BG_POINT src_row_left_pnt)
|
||||
{
|
||||
clip_se_rect_to_screenblock(&se_dest_rect);
|
||||
int dest_rect_width = rect_width(&se_dest_rect);
|
||||
if (dest_rect_width < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy left and right sides
|
||||
main_bg_se_3w_copy_expand_left_right_sides(&se_dest_rect, &src_row_left_pnt);
|
||||
@@ -304,6 +228,172 @@ void main_bg_se_copy_expand_3w_row(Rect se_dest_rect, BG_POINT src_row_left_pnt)
|
||||
}
|
||||
}
|
||||
|
||||
// Helper: Copy the four corners of a 9-patch
|
||||
static inline void main_bg_se_expand_9_patch_copy_corners(
|
||||
Rect se_dest_rect,
|
||||
const NinePatchRect* src_9_ptch
|
||||
)
|
||||
{
|
||||
BG_POINT top_left_dest_pos = {se_dest_rect.left, se_dest_rect.top};
|
||||
Rect top_left_src = {
|
||||
src_9_ptch->patch_rect.left,
|
||||
src_9_ptch->patch_rect.top,
|
||||
src_9_ptch->patch_rect.left + src_9_ptch->margins.left - 1,
|
||||
src_9_ptch->patch_rect.top + src_9_ptch->margins.top - 1
|
||||
};
|
||||
|
||||
BG_POINT top_right_dest_pos = {
|
||||
se_dest_rect.right - src_9_ptch->margins.right + 1,
|
||||
se_dest_rect.top
|
||||
};
|
||||
Rect top_right_src = {
|
||||
src_9_ptch->patch_rect.right - src_9_ptch->margins.right + 1,
|
||||
src_9_ptch->patch_rect.top,
|
||||
src_9_ptch->patch_rect.right,
|
||||
src_9_ptch->patch_rect.top + src_9_ptch->margins.top - 1
|
||||
};
|
||||
|
||||
BG_POINT bottom_right_dest_pos = {
|
||||
se_dest_rect.right - src_9_ptch->margins.right + 1,
|
||||
se_dest_rect.bottom - src_9_ptch->margins.bottom + 1
|
||||
};
|
||||
Rect bottom_right_src = {
|
||||
src_9_ptch->patch_rect.right - src_9_ptch->margins.right + 1,
|
||||
src_9_ptch->patch_rect.bottom - src_9_ptch->margins.bottom + 1,
|
||||
src_9_ptch->patch_rect.right,
|
||||
src_9_ptch->patch_rect.bottom
|
||||
};
|
||||
|
||||
BG_POINT bottom_left_dest_pos = {
|
||||
se_dest_rect.left,
|
||||
se_dest_rect.bottom - src_9_ptch->margins.bottom + 1
|
||||
};
|
||||
Rect bottom_left_src = {
|
||||
src_9_ptch->patch_rect.left,
|
||||
src_9_ptch->patch_rect.bottom - src_9_ptch->margins.bottom + 1,
|
||||
src_9_ptch->patch_rect.left + src_9_ptch->margins.left - 1,
|
||||
src_9_ptch->patch_rect.bottom
|
||||
};
|
||||
|
||||
main_bg_se_copy_rect(top_left_src, top_left_dest_pos);
|
||||
main_bg_se_copy_rect(top_right_src, top_right_dest_pos);
|
||||
main_bg_se_copy_rect(bottom_right_src, bottom_right_dest_pos);
|
||||
main_bg_se_copy_rect(bottom_left_src, bottom_left_dest_pos);
|
||||
}
|
||||
|
||||
// Helper: Copy the four sides of a 9-patch
|
||||
static inline void main_bg_se_expand_9_patch_stretch_sides(
|
||||
Rect se_dest_rect,
|
||||
const NinePatchRect* src_9_ptch,
|
||||
int top_bottom_width,
|
||||
int left_right_height
|
||||
)
|
||||
{
|
||||
// We can take the Top and Bottom sides' tiles 1 by 1 and stretch them horizontally
|
||||
|
||||
// Top side
|
||||
for (int i = 0; i < src_9_ptch->margins.top; i++)
|
||||
{
|
||||
SE top_side_tile = se_mat[MAIN_BG_SBB][src_9_ptch->patch_rect.top + i]
|
||||
[src_9_ptch->patch_rect.left + src_9_ptch->margins.left];
|
||||
memset16(
|
||||
&se_mat[MAIN_BG_SBB][se_dest_rect.top + i]
|
||||
[se_dest_rect.left + src_9_ptch->margins.left],
|
||||
top_side_tile,
|
||||
top_bottom_width
|
||||
);
|
||||
}
|
||||
|
||||
// Bottom side side
|
||||
for (int i = 0; i < src_9_ptch->margins.bottom; i++)
|
||||
{
|
||||
SE bottom_side_tile = se_mat[MAIN_BG_SBB][src_9_ptch->patch_rect.bottom - i]
|
||||
[src_9_ptch->patch_rect.left + src_9_ptch->margins.left];
|
||||
memset16(
|
||||
&se_mat[MAIN_BG_SBB][se_dest_rect.bottom - i]
|
||||
[se_dest_rect.left + src_9_ptch->margins.left],
|
||||
bottom_side_tile,
|
||||
top_bottom_width
|
||||
);
|
||||
}
|
||||
|
||||
// Can't stretch the Left and Right sides with a wide memset16, and
|
||||
// main_bg_se_fill_rect_with_se` does it rows-wise too. We'll have to copy rects by hand.
|
||||
|
||||
Rect left_side_tiles_src = {
|
||||
src_9_ptch->patch_rect.left,
|
||||
src_9_ptch->patch_rect.top + src_9_ptch->margins.top,
|
||||
src_9_ptch->patch_rect.left + src_9_ptch->margins.left - 1,
|
||||
src_9_ptch->patch_rect.top + src_9_ptch->margins.top
|
||||
};
|
||||
BG_POINT left_side_tiles_dest_pos = {
|
||||
se_dest_rect.left,
|
||||
se_dest_rect.top + src_9_ptch->margins.top
|
||||
};
|
||||
|
||||
Rect right_side_tiles_src = {
|
||||
src_9_ptch->patch_rect.right - src_9_ptch->margins.right + 1,
|
||||
src_9_ptch->patch_rect.top + src_9_ptch->margins.top,
|
||||
src_9_ptch->patch_rect.right,
|
||||
src_9_ptch->patch_rect.top + src_9_ptch->margins.top
|
||||
};
|
||||
BG_POINT right_side_tiles_dest_pos = {
|
||||
se_dest_rect.right - src_9_ptch->margins.right + 1,
|
||||
se_dest_rect.top + src_9_ptch->margins.top
|
||||
};
|
||||
|
||||
for (int i = 0; i < left_right_height; i++)
|
||||
{
|
||||
main_bg_se_copy_rect(left_side_tiles_src, left_side_tiles_dest_pos);
|
||||
left_side_tiles_dest_pos.y++;
|
||||
|
||||
main_bg_se_copy_rect(right_side_tiles_src, right_side_tiles_dest_pos);
|
||||
right_side_tiles_dest_pos.y++;
|
||||
}
|
||||
}
|
||||
|
||||
void main_bg_se_copy_expand_9_patch(Rect se_dest_rect, const NinePatchRect* src_9_ptch)
|
||||
{
|
||||
clip_se_rect_to_screenblock(&se_dest_rect);
|
||||
|
||||
int dest_rect_width = rect_width(&se_dest_rect);
|
||||
int dest_rect_height = rect_height(&se_dest_rect);
|
||||
|
||||
int src_9ptch_min_width = src_9_ptch->margins.left + src_9_ptch->margins.right;
|
||||
int src_9ptch_min_height = src_9_ptch->margins.top + src_9_ptch->margins.bottom;
|
||||
|
||||
// Verify the dest rect is big enough to fit at least the 9-patch's corners
|
||||
if (dest_rect_width < src_9ptch_min_width || dest_rect_height < src_9ptch_min_height)
|
||||
return;
|
||||
|
||||
// Copy the corners
|
||||
main_bg_se_expand_9_patch_copy_corners(se_dest_rect, src_9_ptch);
|
||||
|
||||
// Fill the sides and center if needed
|
||||
if (dest_rect_width > src_9ptch_min_width && dest_rect_height > src_9ptch_min_height)
|
||||
{
|
||||
// Stretch sides
|
||||
main_bg_se_expand_9_patch_stretch_sides(
|
||||
se_dest_rect,
|
||||
src_9_ptch,
|
||||
dest_rect_width - src_9ptch_min_width,
|
||||
dest_rect_height - src_9ptch_min_height
|
||||
);
|
||||
|
||||
// Fill center
|
||||
SE middle_fill_se =
|
||||
se_mat[MAIN_BG_SBB][src_9_ptch->patch_rect.top + src_9_ptch->margins.top]
|
||||
[src_9_ptch->patch_rect.left + src_9_ptch->margins.left];
|
||||
Rect dest_inner_fill_rect = {
|
||||
se_dest_rect.left + src_9_ptch->margins.left,
|
||||
se_dest_rect.top + src_9_ptch->margins.top,
|
||||
se_dest_rect.right - src_9_ptch->margins.right,
|
||||
se_dest_rect.bottom - src_9_ptch->margins.bottom
|
||||
};
|
||||
main_bg_se_fill_rect_with_se(middle_fill_se, dest_inner_fill_rect);
|
||||
}
|
||||
}
|
||||
|
||||
void tte_erase_rect_wrapper(Rect rect)
|
||||
{
|
||||
tte_erase_rect(rect.left, rect.top, rect.right, rect.bottom);
|
||||
@@ -333,9 +423,7 @@ void update_text_rect_to_right_align_str(
|
||||
void update_text_rect_to_center_str(Rect* rect, const char* str, enum ScreenHorzDir bias_direction)
|
||||
{
|
||||
if (rect == NULL || str == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int text_width_chars = strlen(str);
|
||||
int rect_width_chars = rect_width(rect) / TTE_CHAR_SIZE;
|
||||
|
||||
@@ -96,6 +96,7 @@ void init()
|
||||
load_options();
|
||||
affine_background_init();
|
||||
sprite_init();
|
||||
card_init();
|
||||
blind_init();
|
||||
joker_init();
|
||||
game_init();
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
#include "random.h"
|
||||
|
||||
#include "game_variables.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <tonc.h>
|
||||
@@ -22,7 +23,7 @@ void rng_update(void)
|
||||
|
||||
void rng_set_seed(u32 seed)
|
||||
{
|
||||
g_game_vars.rng_info.seed = seed % (MAX_SEED + 1);
|
||||
g_game_vars.rng_info.seed = seed % (MAX_BASE36 + 1);
|
||||
g_game_vars.rng_info.step = 0;
|
||||
srand(g_game_vars.rng_info.seed);
|
||||
}
|
||||
|
||||
@@ -332,6 +332,12 @@ void load_options(void)
|
||||
set_cards_more_readable(options.cards_more_readable);
|
||||
}
|
||||
|
||||
bool is_game_data_valid(void)
|
||||
{
|
||||
SaveHeader header;
|
||||
return get_save_header(&header) && (header.valid_sections & SAVE_SECTION_FLAG_GAME);
|
||||
}
|
||||
|
||||
void save_game(void)
|
||||
{
|
||||
SaveGame game = SaveGame_default;
|
||||
|
||||
@@ -191,3 +191,94 @@ uint16_t u16_protected_mult(uint16_t a, uint16_t b)
|
||||
{
|
||||
return (a == 0 || b == 0) ? 0 : (a > (UINT16_MAX / b) ? UINT16_MAX : a * b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the numerical value of a base-36 digit.
|
||||
* Allowed values are [0-9, A-Z], with letters mapped to values of 10-35.
|
||||
* Lowercase letters are mapped to the same values as the uppercase ones.
|
||||
* Any other char is invalid and will be attributed a value of 0.
|
||||
*
|
||||
* @param c the char representing a digit in base-36
|
||||
* @return u32
|
||||
*/
|
||||
static inline uint32_t base36_digit_value(char c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '0' ... '9':
|
||||
return c - '0';
|
||||
case 'A' ... 'Z':
|
||||
return 10 + c - 'A';
|
||||
case 'a' ... 'z':
|
||||
return 10 + c - 'a';
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the char corresponding to a base-36 digit's numerical value.
|
||||
* Inverse operation of base36_digit_value
|
||||
*
|
||||
* @param n decimal value of the base-36 char we want to get
|
||||
* @return char
|
||||
*
|
||||
* @sa base36_digit_value
|
||||
*/
|
||||
static inline char base36_digit_char(uint32_t n)
|
||||
{
|
||||
switch (n)
|
||||
{
|
||||
case 0 ... 9:
|
||||
return n + '0';
|
||||
case 10 ... 35:
|
||||
return n - 10 + 'A';
|
||||
default:
|
||||
return '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get 36 to the power `i`
|
||||
*
|
||||
* @param i power of 36 we want, between 0 and `BASE36_MAX_DIGITS - 1`
|
||||
* @return 36 to the power `i`
|
||||
*
|
||||
* @sa base36_digit_value
|
||||
*/
|
||||
static inline uint32_t get_base36_power(uint8_t i)
|
||||
{
|
||||
if (i >= BASE36_MAX_DIGITS)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const uint32_t powers_of_36[BASE36_MAX_DIGITS] = {1, 36, 1296, 46656, 1679616, 60466176};
|
||||
return powers_of_36[i];
|
||||
}
|
||||
|
||||
uint32_t base36_to_u32(const char b36_str[])
|
||||
{
|
||||
uint32_t res = 0;
|
||||
|
||||
for (uint8_t i = 0; i < BASE36_MAX_DIGITS; i++)
|
||||
{
|
||||
res += base36_digit_value(b36_str[i]) * get_base36_power(BASE36_MAX_DIGITS - i - 1);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void u32_to_base36(const uint32_t n, char b36_str[])
|
||||
{
|
||||
uint32_t power;
|
||||
uint32_t acc = (n > MAX_BASE36) ? MAX_BASE36 : n;
|
||||
for (int i = 0; i < BASE36_MAX_DIGITS; i++)
|
||||
{
|
||||
power = get_base36_power(BASE36_MAX_DIGITS - i - 1);
|
||||
b36_str[i] = base36_digit_char(acc / power);
|
||||
acc = acc % power;
|
||||
}
|
||||
// Properly end the string
|
||||
b36_str[BASE36_MAX_DIGITS] = '\0';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user