10#include "background_shop_gfx.h"
31#define TM_END_GAME_SHOP_INTRO 12
32#define TM_CREATE_SHOP_ITEMS_WAIT 1
33#define TM_SHIFT_SHOP_ICON_WAIT 7
34#define TM_SHOW_CARD_DESC_WAIT 12
35#define TM_HIDE_DECK_WAIT 5
39#define OWNED_CARDS_HIDE_Y_OFFSET 50
42#define REROLL_BASE_COST 5
43#define NEXT_ROUND_BTN_SEL_X 0
46#define REROLL_BTN_PAL_IDX 3
47#define NEXT_ROUND_BTN_SELECTED_BORDER_PAL_IDX 5
48#define SHOP_PANEL_SHADOW_PAL_IDX 6
49#define REROLL_BTN_SELECTED_BORDER_PAL_IDX 7
50#define SHOP_LIGHTS_1_PAL_IDX 8
51#define SHOP_LIGHTS_2_PAL_IDX 14
52#define NEXT_ROUND_BTN_PAL_IDX 16
53#define SHOP_LIGHTS_3_PAL_IDX 17
54#define SHOP_LIGHTS_4_PAL_IDX 22
55#define SHOP_BOTTOM_PANEL_BORDER_PAL_IDX 26
56#define SHOP_DESC_RARITY_MAIN_COLOR_PAL_IDX 27
57#define SHOP_DESC_RARITY_SHADOW_COLOR_PAL_IDX 28
59#define SHOP_LIGHTS_1_CLR 0xFFFF
60#define SHOP_LIGHTS_2_CLR 0x32BE
61#define SHOP_LIGHTS_3_CLR 0x4B5F
62#define SHOP_LIGHTS_4_CLR 0x5F9F
66static const Rect SHOP_ICON_FROM_RECT = { 0, 26, 8, 26};
67static const BG_POINT SHOP_ICON_TO_POS = { 0, 0};
68static const BG_POINT OWNED_CARDS_PANEL_3X3_SRC_POS = { 29, 21};
69static const Rect OWNED_JOKERS_PANEL_RECT = { 9, 1, 21, 5};
70static const Rect OWNED_CONSUMABLES_PANEL_RECT = { 23, 1, 28, 5};
71static const Rect OWNED_CARDS_PANEL_RECT = { 9, 1, 28, 5};
72static const Rect OWNED_CARDS_PANEL_ANIM_CLEAR = { 9, 0, 28, 1};
73static const Rect CARD_DESC_9_PTCH_TO_RECT = { 9, 6, 28, 18};
75 .patch_rect = { 27, 25, 31, 31},
76 .margins = { 2, 3, 2, 3}
78static const int CARD_DESC_MAX_TEXT_HEIGHT = CARD_DESC_9_PTCH_TO_RECT.bottom -
79 CARD_DESC_9_PTCH_TO_RECT.top + 1 -
80 CARD_DESC_9_PTCH_SRC.margins.top -
81 CARD_DESC_9_PTCH_SRC.margins.bottom;
82static const Rect CARD_DESC_TEXT_RECT = { 11, 9, 26, 18};
83static const Rect CARD_NAME_TEXT_RECT = { 10, 7, 27, 7};
86static const BG_POINT SHOP_JOKER_SPRITES_INIT_POS = {120, 160};
87static const BG_POINT CARD_DESCRIPTION_SPRITE_POS = {135, 9};
88static const Rect SHOP_PRICES_TEXT_RECT = { 72, 56, 192, 160 };
89static const Rect SHOP_REROLL_RECT = { 88, 96, UNDEFINED, UNDEFINED };
98 GAME_SHOP_SHOW_CARD_DESC,
99 GAME_SHOP_HIDE_CARD_DESC,
106static void game_shop_show_card_desc(
void);
107static void game_shop_hide_card_desc(
void);
110static StateInfo shop_state_actions[GAME_SHOP_MAX] = {
113 STATE_INFO_UPDATE_FN_ONLY(game_shop_show_card_desc),
114 STATE_INFO_UPDATE_FN_ONLY(game_shop_hide_card_desc),
118static StateMachine shop_sm = STATE_MACHINE_DEFINE(shop_state_actions, GAME_SHOP_MAX);
126 const Selection* prev_selection,
127 const Selection* new_selection
134 const Selection* prev_selection,
135 const Selection* new_selection
145static const Selection SHOP_INIT_SEL = {-1, 1};
155static void next_round_on_pressed(
void);
156static void reroll_on_pressed(
void);
157static bool reroll_can_be_pressed(
void);
158static Button next_round_button =
159 {NEXT_ROUND_BTN_SELECTED_BORDER_PAL_IDX, NEXT_ROUND_BTN_PAL_IDX, next_round_on_pressed, NULL};
160static Button reroll_button = {
161 REROLL_BTN_SELECTED_BORDER_PAL_IDX,
164 reroll_can_be_pressed
171static int s_reroll_cost = REROLL_BASE_COST;
177static FIXED s_description_card_original_x_pos = UNDEFINED;
178static FIXED s_description_card_original_y_pos = UNDEFINED;
179static List* s_description_card_original_list = NULL;
180static int s_show_description_anim_progress = 0;
184 return s_description_card;
198 GRIT_CPY(pal_bg_mem, background_shop_gfxPal);
199 GRIT_CPY(&tile_mem[MAIN_BG_CBB], background_shop_gfxTiles);
200 GRIT_CPY(&se_mem[MAIN_BG_SBB], background_shop_gfxMap);
204 pal_bg_mem[SHOP_BOTTOM_PANEL_BORDER_PAL_IDX] = 0x213D;
205 pal_bg_mem[SHOP_PANEL_SHADOW_PAL_IDX] = 0x10B4;
208 pal_bg_mem[SHOP_LIGHTS_2_PAL_IDX] = SHOP_LIGHTS_2_CLR;
209 pal_bg_mem[SHOP_LIGHTS_3_PAL_IDX] = SHOP_LIGHTS_3_CLR;
210 pal_bg_mem[SHOP_LIGHTS_4_PAL_IDX] = SHOP_LIGHTS_4_CLR;
211 pal_bg_mem[SHOP_LIGHTS_1_PAL_IDX] = SHOP_LIGHTS_1_CLR;
214 pal_bg_mem[REROLL_BTN_SELECTED_BORDER_PAL_IDX] = pal_bg_mem[REROLL_BTN_PAL_IDX];
215 pal_bg_mem[NEXT_ROUND_BTN_SELECTED_BORDER_PAL_IDX] = pal_bg_mem[NEXT_ROUND_BTN_PAL_IDX];
229 shop_selection_grid.selection = SHOP_INIT_SEL;
251 List* shop_items_list = &s_shop_items_list;
256 for (
int i = 0; i < MAX_SHOP_ITEMS; i++)
262 MGBA_FUNC_WARN(
"Could not create shop item");
271 item->x = int2fx(SHOP_JOKER_SPRITES_INIT_POS.x + i * CARD_SPRITE_SIZE);
272 item->y = int2fx(SHOP_JOKER_SPRITES_INIT_POS.y);
274 item->ty = int2fx(ITEM_SHOP_Y);
289 if (s_timer == TM_CREATE_SHOP_ITEMS_WAIT)
294 if (s_timer >= TM_SHIFT_SHOP_ICON_WAIT)
296 int timer_offset = s_timer - 6;
299 for (
int y = 0; y < timer_offset; y++)
301 Rect from = SHOP_ICON_FROM_RECT;
302 from.top += y - timer_offset;
303 from.bottom += y - timer_offset;
305 BG_POINT to = SHOP_ICON_TO_POS;
312 if (s_timer == TM_END_GAME_SHOP_INTRO)
319 "#{P:%d,%d; cx:0x%X000}$%d",
320 SHOP_REROLL_RECT.left,
321 SHOP_REROLL_RECT.top,
343 List* shop_items_list = &s_shop_items_list;
359 if (!key_hit(SELECT_CARD))
362 if (selection->x == NEXT_ROUND_BTN_SEL_X)
368 int shop_item_idx = selection->x - 1;
386 const Selection* prev_selection,
387 const Selection* new_selection
390 List* shop_items_list = &s_shop_items_list;
392 if (new_selection->y > row_idx && prev_selection->x > 0)
398 if (prev_selection->y == row_idx && prev_selection->x >= 0 &&
401 if (prev_selection->x == NEXT_ROUND_BTN_SEL_X)
407 int idx = prev_selection->x - 1;
413 if (new_selection->y == row_idx)
415 if (new_selection->x == NEXT_ROUND_BTN_SEL_X)
421 int idx = new_selection->x - 1;
446 const Selection* prev_selection,
447 const Selection* new_selection
450 if (row_idx == prev_selection->y)
454 if (new_selection->x != NEXT_ROUND_BTN_SEL_X)
456 int idx = new_selection->x - 1;
461 else if (row_idx == new_selection->y)
475 g_game_vars.money -= s_reroll_cost;
478 List* shop_items_list = &s_shop_items_list;
484 if (item != NULL && item->
type == ITEM_TYPE_JOKER)
500 if (item_sprite_object != NULL)
502 item_sprite_object->y = item_sprite_object->ty;
510 "#{P:%d,%d; cx:0x%X000}$%d",
511 SHOP_REROLL_RECT.left,
512 SHOP_REROLL_RECT.top,
523 if (!key_hit(SELECT_CARD))
531static void next_round_on_pressed(
void)
536 s_reroll_cost = REROLL_BASE_COST;
538 pal_bg_mem[NEXT_ROUND_BTN_SELECTED_BORDER_PAL_IDX] = pal_bg_mem[SHOP_PANEL_SHADOW_PAL_IDX];
541static void reroll_on_pressed(
void)
547static bool reroll_can_be_pressed(
void)
549 return g_game_vars.money >= s_reroll_cost;
562 switch (shop_selection_grid.selection.y)
567 s_description_card_original_list = get_jokers_list();
568 tmp_card =
list_get_at_idx(get_jokers_list(), shop_selection_grid.selection.x);
575 s_description_card_original_list = &s_shop_items_list;
576 tmp_card = (shop_selection_grid.selection.x > 0)
577 ?
list_get_at_idx(&s_shop_items_list, shop_selection_grid.selection.x - 1)
586 s_description_card_original_list = NULL;
595 if (tmp_card != NULL && tmp_card->vx == 0 && tmp_card->vy == 0 && key_held(DESELECT_CARDS))
597 s_description_card = tmp_card;
598 s_description_card_original_x_pos = s_description_card->x;
599 s_description_card_original_y_pos = s_description_card->y;
606static void game_shop_show_card_desc(
void)
613 s_show_description_anim_progress = 0;
628 if (joker_object != s_description_card)
629 joker_object->ty -= int2fx(OWNED_CARDS_HIDE_Y_OFFSET);
636 if (joker_object != s_description_card)
637 joker_object->ty = int2fx(SHOP_JOKER_SPRITES_INIT_POS.y +
TILE_SIZE);
642 s_description_card->tx = int2fx(CARD_DESCRIPTION_SPRITE_POS.x);
643 s_description_card->ty = int2fx(CARD_DESCRIPTION_SPRITE_POS.y);
646 if (s_timer <= TM_SHOW_CARD_DESC_WAIT)
648 s_show_description_anim_progress++;
651 if (TM_SHOW_CARD_DESC_WAIT - s_timer < TM_HIDE_DECK_WAIT)
660 else if (s_timer == TM_SHOW_CARD_DESC_WAIT + 1)
663 const JokerInfo* info = get_joker_registry_entry(s_description_card->joker->id);
664 int desc_bottom_offset =
665 CARD_DESC_MAX_TEXT_HEIGHT -
666 info->joker_print_desc(s_description_card->joker, CARD_DESC_TEXT_RECT);
670 const char* rarity_str = joker_get_rarity_string(info->rarity);
672 TTE_WHITE_TAG
"#{P:%d,%d}%*s%s",
674 (CARD_DESC_TEXT_RECT.bottom - desc_bottom_offset - 1) *
TILE_SIZE,
675 (
rect_width(&CARD_DESC_TEXT_RECT) - strlen(rarity_str)) / 2,
679 pal_bg_mem[SHOP_DESC_RARITY_MAIN_COLOR_PAL_IDX] =
681 pal_bg_mem[SHOP_DESC_RARITY_SHADOW_COLOR_PAL_IDX] =
685 Rect actual_dest_rect = CARD_DESC_9_PTCH_TO_RECT;
686 actual_dest_rect.bottom -= desc_bottom_offset;
691 TTE_WHITE_TAG
"#{P:%d,%d}%*s%s",
694 (
rect_width(&CARD_NAME_TEXT_RECT) - strlen(info->name)) / 2,
701 if (!key_held(DESELECT_CARDS))
708static void game_shop_hide_card_desc(
void)
711 static bool owned_joker_price_printed =
false;
717 if (s_show_description_anim_progress >= TM_SHOW_CARD_DESC_WAIT)
735 OWNED_CONSUMABLES_PANEL_RECT,
736 OWNED_CARDS_PANEL_3X3_SRC_POS
746 if (joker_object != s_description_card)
747 joker_object->ty = int2fx(HELD_JOKERS_POS.y);
754 if (joker_object != s_description_card)
755 joker_object->ty = int2fx(ITEM_SHOP_Y);
758 s_description_card->tx = s_description_card_original_x_pos;
759 s_description_card->ty = s_description_card_original_y_pos;
762 if (s_timer <= s_show_description_anim_progress)
765 if (s_show_description_anim_progress > TM_HIDE_DECK_WAIT &&
766 s_timer < (s_show_description_anim_progress - (TM_HIDE_DECK_WAIT + 1)))
775 else if (s_timer == s_show_description_anim_progress + 1)
778 if (s_description_card_original_list == &s_shop_items_list)
779 s_description_card->ty += int2fx(
TILE_SIZE);
789 if (s_description_card_original_list == &s_shop_items_list)
790 s_description_card->ty -= int2fx(
TILE_SIZE);
794 "#{P:%d,%d; cx:0x%X000}$%d",
795 SHOP_REROLL_RECT.left,
796 SHOP_REROLL_RECT.top,
802 display_deck_size_max();
806 else if (s_description_card->vx == 0 && s_description_card->vy == 0)
808 owned_joker_price_printed =
false;
809 s_description_card = NULL;
816 else if (!owned_joker_price_printed && !key_held(SELECT_CARD) &&
817 s_description_card_original_list == get_jokers_list())
819 owned_joker_price_printed =
true;
822 joker_get_sell_value(s_description_card->joker)
846 if (shop_item != NULL)
848 shop_item->ty = int2fx(160);
854 else if (s_timer == 2)
859 memset16(&se_mat[MAIN_BG_SBB][y - 1][0], 0x0001, 1);
860 memset16(&se_mat[MAIN_BG_SBB][y - 1][1], 0x0002, 7);
861 memset16(&se_mat[MAIN_BG_SBB][y - 1][8], SE_HFLIP | 0x0001, 1);
864 if (s_timer >= MENU_POP_OUT_ANIM_FRAMES)
866 game_change_state(GAME_STATE_BLIND_SELECT);
876 COLOR shifted_palette[4];
877 shifted_palette[0] = pal_bg_mem[SHOP_LIGHTS_2_PAL_IDX];
878 shifted_palette[1] = pal_bg_mem[SHOP_LIGHTS_3_PAL_IDX];
879 shifted_palette[2] = pal_bg_mem[SHOP_LIGHTS_4_PAL_IDX];
880 shifted_palette[3] = pal_bg_mem[SHOP_LIGHTS_1_PAL_IDX];
883 int last = shifted_palette[3];
885 for (
int i = 3; i > 0; --i)
887 shifted_palette[i] = shifted_palette[i - 1];
890 shifted_palette[0] = last;
893 pal_bg_mem[SHOP_LIGHTS_2_PAL_IDX] = shifted_palette[0];
894 pal_bg_mem[SHOP_LIGHTS_3_PAL_IDX] = shifted_palette[1];
895 pal_bg_mem[SHOP_LIGHTS_4_PAL_IDX] = shifted_palette[2];
896 pal_bg_mem[SHOP_LIGHTS_1_PAL_IDX] = shifted_palette[3];
903 if (s_timer % 20 == 0)
911 List* shop_items_list = &s_shop_items_list;
922 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.
void item_dispose(Item **item)
Destroys an item, freeing underlying resources, and manages rollable items sets if needed....
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...
void item_acquire(Item *item)
Acquires the item, adding to inventory if applicable. Called when it is purchased from the shop,...
int item_get_buy_price(Item *item)
Returns the buy price of the item.
Functions relative to the handling of Jokers.
u16 joker_get_rarity_color(u8 rarity, bool main_color)
Get Joker rarity panel color.
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 save_game(void)
Save current run data to 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.
JokerObject * game_shop_get_description_card(void)
Get a pointer to the Card we are currently showing the description of.
void game_shop_on_exit(void)
Shop cleanup.
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.
static void game_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 game_shop_process_user_input(void)
Handle user inputs logic in the Shop though a SelectionGrid.
static void game_shop_intro(void)
Intro sequence (menu and shop icon coming into frame)
static void game_shop_lights_anim_frame(void)
Cycling shop lights animation substate update.
void game_shop_reset(void)
Initialize the shop for a run. Resets all the shop data for the run, needs to be called once per run.
void game_shop_on_init(void)
Shop state initialization.
static int shop_reroll_row_get_size(void)
Get size of the row with the "Reroll" button.
static void game_shop_buy_item(int shop_item_idx)
Called when pressing A on a Shop Joker to buy it.
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...
static void shop_reroll_row_on_key_transit(SelectionGrid *selection_grid, Selection *selection)
Handle button inputs for the "Reroll" button's row.
static void game_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 ...
static void game_shop_outro(void)
Outro sequence substate update. This makes the menu and shop icon go out of frame.
void game_shop_on_update(void)
Shop state update.
void game_shop_change_background(void)
Change to the shop background.
static Item * game_shop_create_top_row_item(void)
Create a shop top row item - jokers, consumables, and possibly playing cards Currently only jokers ar...
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.
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.