[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:
@@ -0,0 +1 @@
|
||||
-gB8 -mR8 -mLs -mRtf -pn 160
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
@@ -0,0 +1 @@
|
||||
-gB4 -Mw4 -Mh4 -m! -pn 16
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 872 B |
@@ -1,6 +1,7 @@
|
||||
#ifndef CARD_H
|
||||
#define CARD_H
|
||||
|
||||
#include "deck_types.h"
|
||||
#include "sprite.h"
|
||||
|
||||
#include <maxmod.h>
|
||||
@@ -58,6 +59,8 @@ typedef struct CardObject
|
||||
bool selected;
|
||||
} CardObject;
|
||||
|
||||
void card_init(void);
|
||||
|
||||
// Card sprites accessibility functions
|
||||
void set_cards_high_contrast(bool enable);
|
||||
void set_cards_more_readable(bool enable);
|
||||
@@ -74,6 +77,7 @@ CardObject* card_object_new(Card* card);
|
||||
void card_object_destroy(CardObject** card_object);
|
||||
void card_object_update(CardObject* card_object); // Update the card object position and scale
|
||||
void card_object_set_sprite(CardObject* card_object, int layer);
|
||||
void card_object_set_sprite_face_down(CardObject* card_object, enum DeckType deck, int layer);
|
||||
void card_object_shake(CardObject* card_object, mm_word sound_id);
|
||||
|
||||
void card_object_set_selected(CardObject* card_object, bool selected);
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @file deck_types.h
|
||||
*
|
||||
* @brief Functions related to the different types of Decks.
|
||||
*/
|
||||
#ifndef DECK_TYPES_H
|
||||
#define DECK_TYPES_H
|
||||
|
||||
#include "graphic_utils.h"
|
||||
|
||||
#define DECK_SPRITES_PB 1
|
||||
|
||||
#define DECK_NAME_LENGTH 14 // 13 chars + '\0'
|
||||
#define DECK_DESC_WIDTH DECK_NAME_LENGTH
|
||||
#define DECK_DESC_HEIGHT 5
|
||||
|
||||
enum DeckType
|
||||
{
|
||||
DECK_TYPE_RED,
|
||||
DECK_TYPE_BLUE,
|
||||
DECK_TYPE_YELLOW,
|
||||
DECK_TYPE_GREEN,
|
||||
DECK_TYPE_BLACK,
|
||||
DECK_TYPE_PAINTED,
|
||||
DECK_TYPE_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Prints the Deck name string to the screen at the given position.
|
||||
*
|
||||
* @param deck Decktype we want the name of.
|
||||
* @param pos screen position in pixels to print the name at.
|
||||
*/
|
||||
void print_deck_name(enum DeckType deck, BG_POINT pos);
|
||||
|
||||
/**
|
||||
* @brief Prints the Deck description string to the screen at the given position.
|
||||
*
|
||||
* @param deck DeckType we want the description of.
|
||||
* @param pos screen position in pixels of the top-left corner of the rectangle
|
||||
* we'll print the Deck description into
|
||||
*/
|
||||
void print_deck_description(enum DeckType deck, BG_POINT pos);
|
||||
|
||||
#endif // DECK_TYPES_H
|
||||
@@ -3,6 +3,7 @@
|
||||
DEF_STATE_INFO(GAME_STATE_SPLASH_SCREEN, splash_screen_on_init, splash_screen_on_update, splash_screen_on_exit )
|
||||
DEF_STATE_INFO(GAME_STATE_MAIN_MENU, game_main_menu_on_init, game_main_menu_on_update, game_main_menu_on_exit )
|
||||
DEF_STATE_INFO(GAME_STATE_OPTIONS_MENU, game_options_menu_on_init, game_options_menu_on_update, game_options_menu_on_exit)
|
||||
DEF_STATE_INFO(GAME_STATE_RUN_SETUP , game_run_setup_on_init, game_run_setup_on_update, game_run_setup_on_exit )
|
||||
DEF_STATE_INFO(GAME_STATE_GAME_START, noop, game_start, noop )
|
||||
DEF_STATE_INFO(GAME_STATE_PLAYING, game_round_on_init, game_playing_on_update, noop )
|
||||
DEF_STATE_INFO(GAME_STATE_ROUND_END, game_round_end_on_init, game_round_end_on_update, game_round_end_on_exit )
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#define SORT_HAND KEY_R
|
||||
#define PAUSE_GAME KEY_START // Not implemented
|
||||
#define SELL_KEY KEY_L
|
||||
#define TAB_LEFT KEY_L
|
||||
#define TAB_RIGHT KEY_R
|
||||
|
||||
// Matching the position of the on-screen buttons
|
||||
#define PLAY_HAND_KEY KEY_L
|
||||
|
||||
@@ -19,6 +19,7 @@ enum BackgroundId
|
||||
BG_ROUND_END,
|
||||
BG_SHOP,
|
||||
BG_BLIND_SELECT,
|
||||
BG_RUN_SETUP,
|
||||
BG_OPTIONS_MENU,
|
||||
BG_MAIN_MENU
|
||||
};
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @file run_setup.h
|
||||
*
|
||||
* @brief Setup Run menu state functions.
|
||||
*/
|
||||
#ifndef GAME_RUN_SETUP_H
|
||||
#define GAME_RUN_SETUP_H
|
||||
|
||||
/**
|
||||
* @brief Change to the Run Setup menu background
|
||||
*/
|
||||
void game_run_setup_change_background(void);
|
||||
|
||||
/**
|
||||
* @brief Run Setup menu state initialization
|
||||
*/
|
||||
void game_run_setup_on_init(void);
|
||||
|
||||
/**
|
||||
* @brief Run Setup menu state update
|
||||
*/
|
||||
void game_run_setup_on_update(void);
|
||||
|
||||
/**
|
||||
* @brief Run Setup menu cleanup
|
||||
*/
|
||||
void game_run_setup_on_exit(void);
|
||||
|
||||
#endif // GAME_RUN_SETUP_H
|
||||
@@ -47,6 +47,7 @@ typedef struct
|
||||
s32 ante;
|
||||
s32 money;
|
||||
s32 hand_size;
|
||||
s32 deck;
|
||||
|
||||
// Blind variables
|
||||
|
||||
|
||||
+61
-1
@@ -63,6 +63,9 @@
|
||||
/** @def TTE_BIT_ON_CLR_IDX */
|
||||
#define TTE_BIT_ON_CLR_IDX TTE_BIT_UNPACK_OFFSET + 1
|
||||
|
||||
/** @def TTE_BLACK_PB */
|
||||
#define TTE_BLACK_PB 0 // 0x0
|
||||
|
||||
/** @def TTE_YELLOW_PB */
|
||||
#define TTE_YELLOW_PB 12 // 0xC
|
||||
|
||||
@@ -149,6 +152,37 @@ enum OverflowDir
|
||||
// When making this, missed that it already exists in tonc_math.h
|
||||
typedef RECT Rect;
|
||||
|
||||
// clang-format off
|
||||
/**
|
||||
* @brief Structure to represent arbitrary-sized 9-patches.
|
||||
*
|
||||
* While expanding a 3x3 rect is simple enough and has its purpose, this is an attempt
|
||||
* to generalize the idea to a struct representing a 9-patch like this, such that areas
|
||||
* 1, 2, 3 and 4 have no null dimensions and don't overlap:
|
||||
* ```
|
||||
* margins.left margins.right │ Such as:
|
||||
* ╭───┴───╮ ╭─┴─╮ │
|
||||
* ╔═══════╤═════╤═══╗ ╮ │ 1) margins.left + margins.right <= width (patch_rect)
|
||||
* ║ 1 │ 6 │ 2 ║ ├─ margins.top │
|
||||
* ╟───────┼─────┼───╢ ╯ │ 2) margins.top + margins.bottom <= height(patch_rect)
|
||||
* ║ 5 │ 0 │ 7 ║ │
|
||||
* ║ │ │ ║ │ 3) margins values are inclusive, in number of tiles
|
||||
* ╟───────┼─────┼───╢ ╮ │
|
||||
* ║ │ │ ║ │ │
|
||||
* ║ 4 │ 8 │ 3 ║ ├─ margins.bottom │
|
||||
* ║ │ │ ║ │ │
|
||||
* ╚═══════╧═════╧═══╝ ╯ │
|
||||
* ╰────────┬────────╯ │
|
||||
* patch_rect │
|
||||
* ```
|
||||
*/
|
||||
// clang-format on
|
||||
typedef struct NinePatchRect
|
||||
{
|
||||
Rect patch_rect;
|
||||
Rect margins;
|
||||
} NinePatchRect;
|
||||
|
||||
/**
|
||||
* @brief Get the width of a rectangle
|
||||
*
|
||||
@@ -218,7 +252,33 @@ void main_bg_se_copy_rect_1_tile_vert(Rect se_rect, enum ScreenVertDir direction
|
||||
void main_bg_se_copy_rect(Rect se_rect, BG_POINT dest_pos);
|
||||
|
||||
/**
|
||||
* @brief Copies a 3x3 rect and expands it to fit a passed rect.
|
||||
* @brief Copies a tile in the main background at se_tile_src to fill se_rect_dest.
|
||||
*
|
||||
* @param se_rect_dest dimensions are in number of tiles.
|
||||
* @param se_tile_src x and y are the coordinates in number of tiles.
|
||||
*/
|
||||
void main_bg_se_copy_expand_tile(Rect se_rect_dest, BG_POINT se_tile_src);
|
||||
|
||||
/**
|
||||
* @brief Copies a 9-patch and expands it to fit a passed rect.
|
||||
*
|
||||
* Performs the following operation:
|
||||
*
|
||||
* 1. The corners are copied
|
||||
* 2. The sides are stretched
|
||||
* 3. The center is stretched to fill `se_rect_dest` minus the patch's margins.
|
||||
*
|
||||
* @param se_rect_dest Destination for the 9-patch copy. Needs to be at least large enough to fit
|
||||
* the corners and sides of the patch, (`margins.left + margins.right` by
|
||||
* `margins.top + margins.bottom`) in which case only the corners are copied.
|
||||
* @param src_9_ptch Pointer to the properties of the 9-patch we want to stretch.
|
||||
*
|
||||
* @sa NinePatchRect
|
||||
*/
|
||||
void main_bg_se_copy_expand_9_patch(Rect se_dest_rect, const NinePatchRect* src_9_ptch);
|
||||
|
||||
/**
|
||||
* @brief Copies a 3x3 rect and expands it to fit a passed rect. Special case of the 9-patch.
|
||||
*
|
||||
* Performs the following operation:
|
||||
*
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
#define JOKER_STARTING_LAYER 26
|
||||
// Tile ID for the starting index in the tile memory
|
||||
#define JOKER_TID (JOKER_STARTING_LAYER * JOKER_SPRITE_OFFSET)
|
||||
#define JOKER_BASE_PB 3 // The starting palette index for the jokers
|
||||
#define JOKER_BASE_PB 4 // The starting palette index for the jokers, after the boss blind tokens
|
||||
#define JOKER_LAST_PB (NUM_PALETTES - 1)
|
||||
// Currently allocating the rest of the palettes for the jokers.
|
||||
// This number needs to be decreased once we need to allocated palettes for other sprites
|
||||
|
||||
+1
-6
@@ -12,11 +12,6 @@
|
||||
|
||||
#include <tonc.h>
|
||||
|
||||
/**
|
||||
* @brief Hex value of "ZZZZZZ" in base 36
|
||||
*/
|
||||
#define MAX_SEED 0x81BF0FFF
|
||||
|
||||
/**
|
||||
* @brief Information to track and restore RNG state
|
||||
*/
|
||||
@@ -41,7 +36,7 @@ void rng_update(void);
|
||||
|
||||
/**
|
||||
* @brief Set the rng seed to the chosen value, and reset the step counter to 0.
|
||||
* The seed will be capped at `MAX_SEED` for compatibility with the Seed Input screen
|
||||
* The seed will be capped at `MAX_BASE36` for compatibility with the Seed Input screen
|
||||
* used to choose a seed for seeded runs.
|
||||
*
|
||||
* @param seed the new RNG seed
|
||||
|
||||
@@ -31,6 +31,13 @@
|
||||
|
||||
#include <tonc.h>
|
||||
|
||||
/**
|
||||
* @brief Checks whether the SaveGame section is present and valid.
|
||||
*
|
||||
* @returns true if it is, false if not.
|
||||
*/
|
||||
bool is_game_data_valid(void);
|
||||
|
||||
/**
|
||||
* @brief Save current run data to SRAM.
|
||||
*/
|
||||
|
||||
@@ -106,15 +106,14 @@ void state_machine_change_state(StateMachine* state_machine, int new_state);
|
||||
void noop(void);
|
||||
|
||||
// clang-format off
|
||||
#define STATE_INFO_UPDATE_FN_ONLY(fn) {.on_init = noop, .on_update = fn, .on_exit = noop}
|
||||
|
||||
#define STATE_INFO_UPDATE_FN_ONLY(fn) {.on_init = noop, .on_update = fn, .on_exit = noop}
|
||||
#define STATE_INFO_INIT_UPDATE_FN(init_fn, update_fn) {.on_init = init_fn, .on_update = update_fn, .on_exit = noop}
|
||||
#define STATE_MACHINE_DEFINE(infos, num) \
|
||||
{ \
|
||||
.state_infos = &infos[0], \
|
||||
.num_infos = num, \
|
||||
.registered = false, \
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
|
||||
#endif // STATE_MACHINE_H
|
||||
|
||||
+52
-3
@@ -17,6 +17,12 @@
|
||||
|
||||
#define UNDEFINED -1
|
||||
|
||||
/**
|
||||
* @def MAX_BASE36
|
||||
* @brief Hex value of "ZZZZZZ" in base 36
|
||||
*/
|
||||
#define MAX_BASE36 0x81BF0FFF
|
||||
|
||||
/**
|
||||
* @def SIGN
|
||||
* @brief Get the sign (signum) of an integer
|
||||
@@ -33,9 +39,10 @@
|
||||
*/
|
||||
#define NUM_ELEM_IN_ARR(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
#define INT_MAX_DIGITS 11 // strlen(str(INT_MAX)) = strlen("-2147483647")
|
||||
#define UINT_MAX_DIGITS 10 // strlen(str(UINT32_MAX)) = strlen("4294967295")
|
||||
#define UINT8_MAX_DIGITS 3 // strlen(str(UINT8_MAX)) = strlen("255")
|
||||
#define INT_MAX_DIGITS 11 // strlen(str(INT_MAX)) = strlen("-2147483647")
|
||||
#define UINT_MAX_DIGITS 10 // strlen(str(UINT32_MAX)) = strlen("4294967295")
|
||||
#define UINT8_MAX_DIGITS 3 // strlen(str(UINT8_MAX)) = strlen("255")
|
||||
#define BASE36_MAX_DIGITS 6 // strlen("ZZZZZZ")
|
||||
|
||||
#define ONE_K 1000
|
||||
#define ONE_M 1000000
|
||||
@@ -150,4 +157,46 @@ static inline int u32_get_digits(uint32_t n)
|
||||
return 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a base-36 string representation to a 32-bit unsigned integer.
|
||||
* Since we are dealing with base-36 instead of decimal, the 32-bit decimal
|
||||
* value of a base-36 string representation `b36` is equal to:
|
||||
*
|
||||
* \f( b36[0] * 36^0 + b36[1] * 36^1 + b36[2] * 36^2 ... \f)
|
||||
*
|
||||
* @param b36_str input char[] to convert to decimal, must be of size `BASE36_MAX_DIGITS+1`
|
||||
*
|
||||
* @returns the 32-bit unsigned value of `b36_str`
|
||||
*/
|
||||
uint32_t base36_to_u32(const char b36_str[]);
|
||||
|
||||
/**
|
||||
* @brief Convert a 32-bit unsigned integer to its base-36 string representation.
|
||||
* This will perform 6 divisions, so it will be significantly more expensive
|
||||
* than its `base36_to_u32` counterpart.
|
||||
*
|
||||
* We will iterate over all digits from `BASE36_MAX_DIGITS-1` to 0 and determine
|
||||
* their values in base-36, to then construct the string representation `b36_str`
|
||||
* in base-36 or the integer `n`
|
||||
*
|
||||
* Initially set to `n`, the variable `acc` will contain any given stage `i`:
|
||||
* ```
|
||||
* b32[i] * 36^i + b32[i-1] * 36^(i-1) + ... + b32[0]
|
||||
* ```
|
||||
*
|
||||
* And we can thus extract the two following values:
|
||||
* ```
|
||||
* b32[i] = acc / 36^i
|
||||
* acc = acc mod 36^i = b32[i-1] * 36^(i-1) + ... + b32[0]
|
||||
* ```
|
||||
*
|
||||
* So that acc can now be used for the following step, until `i` hits 0
|
||||
*
|
||||
* @param n integer value to convert to a base-36 representation
|
||||
* @param b36_str output char[], representation of `n` in base-36
|
||||
*
|
||||
* @sa base36_to_u32
|
||||
*/
|
||||
void u32_to_base36(uint32_t n, char b36_str[]);
|
||||
|
||||
#endif // UTIL_H
|
||||
|
||||
+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';
|
||||
}
|
||||
|
||||
+1
-1
@@ -17,6 +17,6 @@ run_test() {
|
||||
}
|
||||
|
||||
run_test bitset
|
||||
run_test pool
|
||||
run_test list
|
||||
run_test pool
|
||||
run_test util
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <font.h>
|
||||
#include <stdint.h>
|
||||
#include <util.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
@@ -213,8 +214,87 @@ void test_truncate_uint_to_suffixed_str()
|
||||
assert(strcmp(suffixed_str_buff, max_uint_str_buff) == 0);
|
||||
}
|
||||
|
||||
void test_base36_conversions(void)
|
||||
{
|
||||
char base36_str[BASE36_MAX_DIGITS + 1] = {'\0'};
|
||||
uint32_t base10_int;
|
||||
|
||||
// Base-36 Str => Int
|
||||
|
||||
snprintf(base36_str, sizeof(base36_str), "%s", "ZZZZZZ");
|
||||
assert(base36_to_u32(base36_str) == MAX_BASE36);
|
||||
|
||||
snprintf(base36_str, sizeof(base36_str), "%s", "000000");
|
||||
assert(base36_to_u32(base36_str) == 0);
|
||||
|
||||
snprintf(base36_str, sizeof(base36_str), "%s", "000001");
|
||||
assert(base36_to_u32(base36_str) == 1);
|
||||
|
||||
snprintf(base36_str, sizeof(base36_str), "%s", "000010");
|
||||
assert(base36_to_u32(base36_str) == 36);
|
||||
|
||||
snprintf(base36_str, sizeof(base36_str), "%s", "000100");
|
||||
assert(base36_to_u32(base36_str) == 1296);
|
||||
|
||||
snprintf(base36_str, sizeof(base36_str), "%s", "001000");
|
||||
assert(base36_to_u32(base36_str) == 46656);
|
||||
|
||||
snprintf(base36_str, sizeof(base36_str), "%s", "010000");
|
||||
assert(base36_to_u32(base36_str) == 1679616);
|
||||
|
||||
snprintf(base36_str, sizeof(base36_str), "%s", "100000");
|
||||
assert(base36_to_u32(base36_str) == 60466176);
|
||||
|
||||
// Base-36 Str => Int
|
||||
|
||||
base10_int = 0;
|
||||
u32_to_base36(base10_int, base36_str);
|
||||
assert(strcmp(base36_str, "000000") == 0);
|
||||
|
||||
base10_int = 1;
|
||||
u32_to_base36(base10_int, base36_str);
|
||||
assert(strcmp(base36_str, "000001") == 0);
|
||||
|
||||
base10_int = 36;
|
||||
u32_to_base36(base10_int, base36_str);
|
||||
assert(strcmp(base36_str, "000010") == 0);
|
||||
|
||||
base10_int = 1296;
|
||||
u32_to_base36(base10_int, base36_str);
|
||||
assert(strcmp(base36_str, "000100") == 0);
|
||||
|
||||
base10_int = 46656;
|
||||
u32_to_base36(base10_int, base36_str);
|
||||
assert(strcmp(base36_str, "001000") == 0);
|
||||
|
||||
base10_int = 1679616;
|
||||
u32_to_base36(base10_int, base36_str);
|
||||
assert(strcmp(base36_str, "010000") == 0);
|
||||
|
||||
base10_int = 60466176;
|
||||
u32_to_base36(base10_int, base36_str);
|
||||
assert(strcmp(base36_str, "100000") == 0);
|
||||
|
||||
base10_int = MAX_BASE36;
|
||||
u32_to_base36(base10_int, base36_str);
|
||||
assert(strcmp(base36_str, "ZZZZZZ") == 0);
|
||||
|
||||
base10_int = UINT32_MAX;
|
||||
u32_to_base36(base10_int, base36_str);
|
||||
assert(strcmp(base36_str, "ZZZZZZ") == 0);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("Testing Truncating UINT32.\n");
|
||||
test_truncate_uint_to_suffixed_str();
|
||||
|
||||
printf("Testing Base-36 conversions.\n");
|
||||
test_base36_conversions();
|
||||
|
||||
printf("-------------------------------------------------------------------------------\n");
|
||||
printf("Util Tests Passed :)\n");
|
||||
printf("-------------------------------------------------------------------------------\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user