10#include "background_shop_gfx.h"
32#define TM_END_GAME_SHOP_INTRO 12
33#define TM_CREATE_SHOP_ITEMS_WAIT 1
34#define TM_SHIFT_SHOP_ICON_WAIT 7
35#define TM_SHOW_ITEM_DESC_WAIT 12
36#define TM_HIDE_DECK_WAIT 5
40#define OWNED_ITEMS_HIDE_Y_OFFSET 50
43#define REROLL_BASE_COST 5
44#define NEXT_ROUND_BTN_SEL_X 0
47#define REROLL_BTN_PAL_IDX 3
48#define NEXT_ROUND_BTN_SELECTED_BORDER_PAL_IDX 5
49#define SHOP_PANEL_SHADOW_PAL_IDX 6
50#define REROLL_BTN_SELECTED_BORDER_PAL_IDX 7
51#define SHOP_LIGHTS_1_PAL_IDX 8
52#define SHOP_LIGHTS_2_PAL_IDX 14
53#define NEXT_ROUND_BTN_PAL_IDX 16
54#define SHOP_LIGHTS_3_PAL_IDX 17
55#define SHOP_LIGHTS_4_PAL_IDX 22
56#define SHOP_BOTTOM_PANEL_BORDER_PAL_IDX 26
57#define SHOP_DESC_RARITY_MAIN_COLOR_PAL_IDX 27
58#define SHOP_DESC_RARITY_SHADOW_COLOR_PAL_IDX 28
60#define SHOP_LIGHTS_1_CLR 0xFFFF
61#define SHOP_LIGHTS_2_CLR 0x32BE
62#define SHOP_LIGHTS_3_CLR 0x4B5F
63#define SHOP_LIGHTS_4_CLR 0x5F9F
67static const Rect SHOP_ICON_FROM_RECT = { 0, 26, 8, 26};
68static const BG_POINT SHOP_ICON_TO_POS = { 0, 0};
69static const BG_POINT OWNED_ITEMS_PANEL_3X3_SRC_POS = { 29, 21};
70static const Rect OWNED_JOKERS_PANEL_RECT = { 9, 1, 21, 5};
71static const Rect OWNED_CONSUMABLES_PANEL_RECT = { 23, 1, 28, 5};
72static const Rect OWNED_ITEMS_PANEL_RECT = { 9, 1, 28, 5};
73static const Rect OWNED_ITEMS_PANEL_ANIM_CLEAR = { 9, 0, 28, 1};
74static const Rect ITEM_DESC_9_PTCH_TO_RECT = { 9, 6, 28, 18};
76 .patch_rect = { 27, 25, 31, 31},
77 .margins = { 2, 3, 2, 3}
79static const int ITEM_DESC_MAX_TEXT_HEIGHT = ITEM_DESC_9_PTCH_TO_RECT.bottom -
80 ITEM_DESC_9_PTCH_TO_RECT.top + 1 -
81 ITEM_DESC_9_PTCH_SRC.margins.top -
82 ITEM_DESC_9_PTCH_SRC.margins.bottom;
83static const Rect ITEM_DESC_TEXT_RECT = { 11, 9, 26, 18};
84static const Rect ITEM_NAME_TEXT_RECT = { 10, 7, 27, 7};
87static const BG_POINT SHOP_JOKER_SPRITES_INIT_POS = {120, 160};
88static const BG_POINT ITEM_DESCRIPTION_SPRITE_POS = {135, 9};
89static const Rect SHOP_PRICES_TEXT_RECT = { 72, 56, 192, 160 };
90static const Rect SHOP_REROLL_RECT = { 88, 96, UNDEFINED, UNDEFINED };
100 GAME_SHOP_SHOW_ITEM_DESC,
101 GAME_SHOP_HIDE_ITEM_DESC,
106static void shop_redeem_skip_tags(
void);
109static void shop_show_item_desc_on_init(
void);
110static void shop_show_item_desc_on_update(
void);
111static void shop_hide_item_desc_on_init(
void);
112static void shop_hide_item_desc_on_update(
void);
113static void shop_hide_item_desc_on_exit(
void);
117static StateInfo shop_state_actions[GAME_SHOP_MAX] = {
118 [GAME_SHOP_SKIP_TAGS] = STATE_INFO_UPDATE_FN_ONLY(shop_redeem_skip_tags),
119 [GAME_SHOP_INTRO] = STATE_INFO_UPDATE_FN_ONLY(
shop_intro),
121 [GAME_SHOP_SHOW_ITEM_DESC] = STATE_INFO_INIT_UPDATE_FN(
122 shop_show_item_desc_on_init,
123 shop_show_item_desc_on_update),
124 [GAME_SHOP_HIDE_ITEM_DESC] = {.on_init = shop_hide_item_desc_on_init,
125 .on_update = shop_hide_item_desc_on_update,
126 .on_exit = shop_hide_item_desc_on_exit},
127 [GAME_SHOP_EXIT] = STATE_INFO_UPDATE_FN_ONLY(
shop_outro),
131static StateMachine shop_sm = STATE_MACHINE_DEFINE(shop_state_actions, GAME_SHOP_MAX);
135#define SHOP_GRID_OWNED_ROW 0
136#define SHOP_GRID_FOR_SALE_ROW 1
142 const Selection* prev_selection,
143 const Selection* new_selection
150 const Selection* prev_selection,
151 const Selection* new_selection
161static const Selection SHOP_INIT_SEL = {-1, 1};
171static void next_round_on_pressed(
void);
172static void reroll_on_pressed(
void);
173static bool reroll_can_be_pressed(
void);
174static Button next_round_button =
175 {NEXT_ROUND_BTN_SELECTED_BORDER_PAL_IDX, NEXT_ROUND_BTN_PAL_IDX, next_round_on_pressed, NULL};
176static Button reroll_button = {
177 REROLL_BTN_SELECTED_BORDER_PAL_IDX,
180 reroll_can_be_pressed
187static int s_reroll_cost = REROLL_BASE_COST;
191static Item* s_description_item = NULL;
192static FIXED s_description_item_original_x_pos = UNDEFINED;
193static FIXED s_description_item_original_y_pos = UNDEFINED;
194static int s_show_description_anim_progress = 0;
198 return s_description_item;
203 return s_reroll_cost;
208 s_reroll_cost = cost;
222 GRIT_CPY(pal_bg_mem, background_shop_gfxPal);
223 GRIT_CPY(&tile_mem[MAIN_BG_CBB], background_shop_gfxTiles);
224 GRIT_CPY(&se_mem[MAIN_BG_SBB], background_shop_gfxMap);
228 pal_bg_mem[SHOP_BOTTOM_PANEL_BORDER_PAL_IDX] = 0x213D;
229 pal_bg_mem[SHOP_PANEL_SHADOW_PAL_IDX] = 0x10B4;
232 pal_bg_mem[SHOP_LIGHTS_2_PAL_IDX] = SHOP_LIGHTS_2_CLR;
233 pal_bg_mem[SHOP_LIGHTS_3_PAL_IDX] = SHOP_LIGHTS_3_CLR;
234 pal_bg_mem[SHOP_LIGHTS_4_PAL_IDX] = SHOP_LIGHTS_4_CLR;
235 pal_bg_mem[SHOP_LIGHTS_1_PAL_IDX] = SHOP_LIGHTS_1_CLR;
238 pal_bg_mem[REROLL_BTN_SELECTED_BORDER_PAL_IDX] = pal_bg_mem[REROLL_BTN_PAL_IDX];
239 pal_bg_mem[NEXT_ROUND_BTN_SELECTED_BORDER_PAL_IDX] = pal_bg_mem[NEXT_ROUND_BTN_PAL_IDX];
255 shop_selection_grid.selection = SHOP_INIT_SEL;
259static void shop_redeem_skip_tags(
void)
286 List* shop_items_list = &s_shop_items_list;
291 for (
int i = 0; i < MAX_SHOP_ITEMS; i++)
297 MGBA_FUNC_WARN(
"Could not create shop item");
306 item->x = int2fx(SHOP_JOKER_SPRITES_INIT_POS.x + i * CARD_SPRITE_SIZE_PX);
307 item->y = int2fx(SHOP_JOKER_SPRITES_INIT_POS.y);
309 item->ty = int2fx(ITEM_SHOP_Y);
324 if (s_timer == TM_CREATE_SHOP_ITEMS_WAIT)
329 if (s_timer >= TM_SHIFT_SHOP_ICON_WAIT)
331 int timer_offset = s_timer - 6;
334 for (
int y = 0; y < timer_offset; y++)
336 Rect from = SHOP_ICON_FROM_RECT;
337 from.top += y - timer_offset;
338 from.bottom += y - timer_offset;
340 BG_POINT to = SHOP_ICON_TO_POS;
347 if (s_timer == TM_END_GAME_SHOP_INTRO)
354 "#{P:%d,%d; cx:0x%X000}$%d",
355 SHOP_REROLL_RECT.left,
356 SHOP_REROLL_RECT.top,
378 List* shop_items_list = &s_shop_items_list;
394 if (!key_hit(SELECT_CARD))
397 if (selection->x == NEXT_ROUND_BTN_SEL_X)
403 int shop_item_idx = selection->x - 1;
421 const Selection* prev_selection,
422 const Selection* new_selection
425 List* shop_items_list = &s_shop_items_list;
427 if (new_selection->y > row_idx && prev_selection->x > 0)
433 if (prev_selection->y == row_idx && prev_selection->x >= 0 &&
436 if (prev_selection->x == NEXT_ROUND_BTN_SEL_X)
442 int idx = prev_selection->x - 1;
448 if (new_selection->y == row_idx)
450 if (new_selection->x == NEXT_ROUND_BTN_SEL_X)
456 int idx = new_selection->x - 1;
481 const Selection* prev_selection,
482 const Selection* new_selection
485 if (row_idx == prev_selection->y)
489 if (new_selection->x != NEXT_ROUND_BTN_SEL_X)
491 int idx = new_selection->x - 1;
496 else if (row_idx == new_selection->y)
510 g_game_vars.money -= s_reroll_cost;
513 List* shop_items_list = &s_shop_items_list;
519 if (item != NULL && item->
type == ITEM_TYPE_JOKER)
535 if (item_sprite_object != NULL)
537 item_sprite_object->y = item_sprite_object->ty;
545 "#{P:%d,%d; cx:0x%X000}$%d",
546 SHOP_REROLL_RECT.left,
547 SHOP_REROLL_RECT.top,
558 if (!key_hit(SELECT_CARD))
566static void next_round_on_pressed(
void)
571 s_reroll_cost = REROLL_BASE_COST;
573 pal_bg_mem[NEXT_ROUND_BTN_SELECTED_BORDER_PAL_IDX] = pal_bg_mem[SHOP_PANEL_SHADOW_PAL_IDX];
576static void reroll_on_pressed(
void)
582static bool reroll_can_be_pressed(
void)
584 return g_game_vars.money >= s_reroll_cost;
594 static Item* new_description_item = NULL;
597 switch (shop_selection_grid.selection.y)
599 case SHOP_GRID_OWNED_ROW:
601 new_description_item =
606 case SHOP_GRID_FOR_SALE_ROW:
610 new_description_item =
611 (shop_selection_grid.selection.x != NEXT_ROUND_BTN_SEL_X)
612 ?
list_get_at_idx(&s_shop_items_list, shop_selection_grid.selection.x - 1)
621 new_description_item = NULL;
627 if (new_description_item != NULL && key_held(DESELECT_CARDS))
629 s_description_item = new_description_item;
630 s_description_item_original_x_pos = s_description_item->tx;
631 s_description_item_original_y_pos = s_description_item->ty;
638static void shop_show_item_desc_on_init(
void)
642 s_show_description_anim_progress = 0;
649 Item* tmp_item = NULL;
655 if (tmp_item != s_description_item)
656 tmp_item->ty -= int2fx(OWNED_ITEMS_HIDE_Y_OFFSET);
663 if (tmp_item != s_description_item)
664 tmp_item->ty = int2fx(SHOP_JOKER_SPRITES_INIT_POS.y +
TILE_SIZE);
671 s_description_item->tx = int2fx(ITEM_DESCRIPTION_SPRITE_POS.x);
672 s_description_item->ty = int2fx(ITEM_DESCRIPTION_SPRITE_POS.y);
675static void shop_show_item_desc_on_update(
void)
677 if (s_timer <= TM_SHOW_ITEM_DESC_WAIT)
679 s_show_description_anim_progress++;
682 if (TM_SHOW_ITEM_DESC_WAIT - s_timer < TM_HIDE_DECK_WAIT)
691 else if (s_timer == TM_SHOW_ITEM_DESC_WAIT + 1)
696 TTE_WHITE_TAG
"#{P:%d,%d}%*s%s",
699 (
rect_width(&ITEM_NAME_TEXT_RECT) - strlen(item_name)) / 2,
706 int desc_bottom_offset = ITEM_DESC_MAX_TEXT_HEIGHT - nb_printed_lines;
711 const char* subtype_str = item_subtype_info.name_str;
713 TTE_WHITE_TAG
"#{P:%d,%d}%*s%s",
715 (ITEM_DESC_TEXT_RECT.bottom - desc_bottom_offset - 1) *
TILE_SIZE,
716 (
rect_width(&ITEM_DESC_TEXT_RECT) - strlen(subtype_str)) / 2,
721 pal_bg_mem[SHOP_DESC_RARITY_MAIN_COLOR_PAL_IDX] = item_subtype_info.main_color;
722 pal_bg_mem[SHOP_DESC_RARITY_SHADOW_COLOR_PAL_IDX] = item_subtype_info.shadow_color;
725 Rect actual_dest_rect = ITEM_DESC_9_PTCH_TO_RECT;
726 actual_dest_rect.bottom -= desc_bottom_offset;
731 if (!key_held(DESELECT_CARDS))
738static void shop_hide_item_desc_on_init(
void)
741 if (s_show_description_anim_progress >= TM_SHOW_ITEM_DESC_WAIT)
759 Item* tmp_item = NULL;
765 if (tmp_item != s_description_item)
766 tmp_item->ty = int2fx(HELD_JOKERS_POS.y);
773 if (tmp_item != s_description_item)
774 tmp_item->ty = int2fx(ITEM_SHOP_Y);
779 s_description_item->tx = s_description_item_original_x_pos;
780 s_description_item->ty = s_description_item_original_y_pos;
783static void shop_hide_item_desc_on_update(
void)
785 if (s_timer <= s_show_description_anim_progress)
788 if (s_show_description_anim_progress > TM_HIDE_DECK_WAIT &&
789 s_timer < (s_show_description_anim_progress - (TM_HIDE_DECK_WAIT + 1)))
798 else if (s_timer == s_show_description_anim_progress + 1)
805static void shop_hide_item_desc_on_exit(
void)
813 s_description_item->ty += int2fx(
TILE_SIZE);
825 s_description_item->ty -= int2fx(
TILE_SIZE);
829 "#{P:%d,%d; cx:0x%X000}$%d",
830 SHOP_REROLL_RECT.left,
831 SHOP_REROLL_RECT.top,
837 display_deck_size_max();
840 if (!key_held(SELECT_CARD) &&
item_is_owned(s_description_item))
848 s_description_item = NULL;
870 if (shop_item != NULL)
872 shop_item->ty = int2fx(160);
878 else if (s_timer == 2)
883 memset16(&se_mat[MAIN_BG_SBB][y - 1][0], 0x0001, 1);
884 memset16(&se_mat[MAIN_BG_SBB][y - 1][1], 0x0002, 7);
885 memset16(&se_mat[MAIN_BG_SBB][y - 1][8], SE_HFLIP | 0x0001, 1);
888 if (s_timer >= MENU_POP_OUT_ANIM_FRAMES)
890 game_change_state(GAME_STATE_BLIND_SELECT);
900 COLOR shifted_palette[4];
901 shifted_palette[0] = pal_bg_mem[SHOP_LIGHTS_2_PAL_IDX];
902 shifted_palette[1] = pal_bg_mem[SHOP_LIGHTS_3_PAL_IDX];
903 shifted_palette[2] = pal_bg_mem[SHOP_LIGHTS_4_PAL_IDX];
904 shifted_palette[3] = pal_bg_mem[SHOP_LIGHTS_1_PAL_IDX];
907 int last = shifted_palette[3];
909 for (
int i = 3; i > 0; --i)
911 shifted_palette[i] = shifted_palette[i - 1];
914 shifted_palette[0] = last;
917 pal_bg_mem[SHOP_LIGHTS_2_PAL_IDX] = shifted_palette[0];
918 pal_bg_mem[SHOP_LIGHTS_3_PAL_IDX] = shifted_palette[1];
919 pal_bg_mem[SHOP_LIGHTS_4_PAL_IDX] = shifted_palette[2];
920 pal_bg_mem[SHOP_LIGHTS_1_PAL_IDX] = shifted_palette[3];
927 if (s_timer % 20 == 0)
935 List* shop_items_list = &s_shop_items_list;
946 increment_blind(BLIND_STATE_DEFEATED);
Utilities for using maxmod to play sound effects.
A bitset for operating on flags.
Blind select state functions.
void reset_top_left_panel_bottom_row(void)
Restores the bottom row of the top-left panel from the background map.
Game global game variables struct definition.
void main_bg_se_move_rect_1_tile_vert(Rect se_rect, enum ScreenVertDir direction)
Moves a rect in the main background vertically in direction by a single tile.
void main_bg_se_copy_rect_1_tile_vert(Rect se_rect, enum ScreenVertDir direction)
Copies a rect in the main background vertically in direction by a single tile.
void main_bg_se_clear_rect(Rect se_rect)
Clears a rect in the main background.
void main_bg_se_copy_rect(Rect se_rect, BG_POINT dest_pos)
Copies a rect in the main background from se_rect to the position (x, y).
void toggle_windows(bool win0, bool win1)
Toggles the visibility of the window layers.
#define TILE_SIZE
Tile size in pixels, both height and width as tiles are square.
void main_bg_se_copy_expand_3x3_rect(Rect se_rect_dest, BG_POINT se_rect_src_3x3_top_left)
Copies a 3x3 rect and expands it to fit a passed rect. Special case of the 9-patch.
void tte_erase_rect_wrapper(Rect rect)
A wrapper for tte_erase_rect that would use the rect struct.
void main_bg_se_copy_expand_9_patch(Rect se_dest_rect, const NinePatchRect *src_9_ptch)
Copies a 9-patch and expands it to fit a passed rect.
INLINE int rect_width(const Rect *rect)
Get the width of a rectangle.
bool item_is_owned(Item *item)
Returns whether or not the given Item is in the player's possession.
int item_get_sell_price(Item *item)
Returns the sell price of the item.
void item_dispose(Item **item)
Destroys an item, freeing underlying resources, and manages rollable items sets if needed....
const char * item_get_name(Item *item)
Returns the name of the Item.
void item_print_buy_price_under(Item *item)
Prints the buy price under the item Relies on the fact item is a SpriteObject.
Item * item_roll_new(enum ItemType item_type, enum RngSequence key)
Rolls a random item of type item_type and returns a newly created one. Manages rollable items set if ...
bool item_can_acquire(Item *item)
Returns true if the item can be acquired, i.e. added to inventory. Does not check if the player has e...
ItemDescSubtypeInfo item_get_subtype_info(Item *item)
Returns the colors and name of the Item's subtype.
void item_acquire(Item *item)
Acquires the item, adding to inventory if applicable. Called when it is purchased from the shop,...
int item_print_description(Item *item, Rect dest_rect)
Prints the item's description inside the given rectangle.
int item_get_buy_price(Item *item)
Returns the buy price of the item.
Functions relative to the handling of Jokers.
void joker_reset_rollable_jokers(void)
Reset rollable jokers to include all jokers in the registry.
All the functions used specifically to interact with Jokers. This includes browsing,...
bool jokers_sel_row_on_selection_changed(SelectionGrid *selection_grid, int row_idx, const Selection *prev_selection, const Selection *new_selection)
Handle directional inputs on the Jokers' row at the top of the game screen.
void jokers_sel_row_on_key_transit(SelectionGrid *selection_grid, Selection *selection)
Handle button inputs on the Jokers' row at the top of the game screen.
int jokers_sel_row_get_size(void)
Returns the size of the Jokers' row at the top of the game screen. Is equal to the number of Jokers o...
Header of shared rects and points needed for ui.
void * list_get_at_idx(List *list, unsigned int idx)
int list_get_len(const List *list)
void list_clear(List *list)
void * list_itr_next(ListItr *itr)
bool list_remove_at_idx(List *list, unsigned int idx)
#define LIST_DEFAULT
Default list declaration for empty lists.
void list_push_back(List *list, void *data)
ListItr list_itr_create(List *list)
Interface to interact with the mgba logger.
Common functions to handle RNG manipulation. Using this interface has three goals:
Utils functions to save/load data structures from/to the SRAM.
void selection_grid_move_selection_horz(SelectionGrid *selection_grid, int direction_tribool)
Moves the selection horizontally within the selection grid.
void selection_grid_process_input(SelectionGrid *selection_grid)
Processes user input for the selection grid.
static bool shop_reroll_row_on_selection_changed(SelectionGrid *selection_grid, int row_idx, const Selection *prev_selection, const Selection *new_selection)
Handle d-pad inputs for the "Reroll" button's row.
static void shop_top_row_on_key_transit(SelectionGrid *selection_grid, Selection *selection)
Handle button inputs for the "Next Round" button and shop Jokers.
static bool shop_top_row_on_selection_changed(SelectionGrid *selection_grid, int row_idx, const Selection *prev_selection, const Selection *new_selection)
Handle d-pad inputs for the "Next Round" button and shop Jokers' row.
void shop_on_exit(void)
Shop cleanup.
void shop_on_update(void)
Shop state update.
static void shop_reroll(void)
Reroll items up for sale in the Shop. Reroll cost will go up by a rate that increases by 1 each rerol...
static void shop_outro(void)
Outro sequence substate update. This makes the menu and shop icon go out of frame.
static int shop_reroll_row_get_size(void)
Get size of the row with the "Reroll" button.
int shop_get_reroll_cost(void)
Get the current cost to reroll the items sold in the shop.
static int shop_top_row_get_size(void)
Computes the number of Jokers up for sale, aka the number of "buttons" there are on the top row of th...
void shop_on_init(void)
Shop state initialization.
static void shop_reroll_row_on_key_transit(SelectionGrid *selection_grid, Selection *selection)
Handle button inputs for the "Reroll" button's row.
static void shop_intro(void)
Intro sequence (menu and shop icon coming into frame)
void shop_change_background(void)
Change to the shop background.
Item * shop_get_description_item(void)
Get a pointer to the Card we are currently showing the description of.
void shop_set_reroll_cost(int cost)
Set the current cost to reroll the items sold in the shop to the given value.
void shop_reset(void)
Initialize the shop for a run. Resets all the shop data for the run, needs to be called once per run.
static void shop_buy_item(int shop_item_idx)
Called when pressing A on a Shop Joker to buy it.
static Item * shop_create_top_row_item(void)
Create a shop top row item - jokers, consumables, and possibly playing cards Currently only jokers ar...
static void shop_lights_anim_frame(void)
Cycling shop lights animation substate update.
static void shop_process_user_input(void)
Handle user inputs logic in the Shop though a SelectionGrid.
static void shop_create_top_row_items(void)
Setup for the lists of items we can purchase in the top row of the Shop. i.e. Jokers and consumables ...
Data structures and functions related to the handling of Skip Tags.
void set_owned_skip_tags_moved_offscreen(bool move_offscreen)
Show or hide the owned SkipTag sprites by moving them offscreen to the right.
void skip_tag_process_start(enum SkipTagEvent checked_tag_event)
Start Skip Tag processing for the specified event.
enum SkipTagProcStage skip_tag_process_get_proc_stage(void)
Recover the current stage of the Tag processing.
void sprite_object_set_focus(SpriteObject *sprite_object, bool focus)
Set the focus for SpriteObject Raises the object by SPRITE_FOCUS_RAISE_PX.
void sprite_object_print_price_under(SpriteObject *sprite_object, int price)
Print the price string directly beneath a SpriteObject. More specialized version of sprite_object_pri...
void sprite_object_shake(SpriteObject *sprite_object, mm_word sound_id)
Shake SpriteObject on screen and play a sound.
void sprite_object_erase_text_under(SpriteObject *sprite_object)
Erase the text within the Rect directly beneath a SpriteObject. This is used only for Cards for now.
void state_machine_remove(StateMachine *state_machine)
Remove a statemachine's update function.
void state_machine_register(StateMachine *state_machine)
Register a statemachine to run it's update function once per frame.
void state_machine_change_state(StateMachine *state_machine, int new_state)
Calls the current state's on_exit, the new state's on_init, and sets the active update fn.
Structure containing the main and shadow colors, and the name string associated with an Item's subtyp...
A generic interface for all items that can appear in the shop or be in the inventory....
enum ItemType type
The item type - used to dispatch the function implementations for inheriting types.
Structure to represent arbitrary-sized 9-patches.
The core selection grid struct, represents the grid itself and its state.
A sprite object is a sprite that is focusable and movable in animation.
Utilities relating around number string representation and protected arithmatic helper functions.
#define NUM_ELEM_IN_ARR(arr)
Get the number of elements in an array.