16#include "card_rarity_pal_gfx.h"
25#define MAX_NUM_JOKERS_SPRITESHEETS 75
27static const unsigned int* joker_gfxTiles[] = {
28#define DEF_JOKER_GFX(idx) joker_gfx##idx##Tiles,
29#include "../include/def_joker_gfx_table.h"
32static const unsigned short* joker_gfxPal[] = {
33#define DEF_JOKER_GFX(idx) joker_gfx##idx##Pal,
34#include "def_joker_gfx_table.h"
45static bool s_used_layers[MAX_JOKER_OBJECTS] = {
false};
50static int s_joker_spritesheet_pb_map[MAX_NUM_JOKERS_SPRITESHEETS];
51static int s_joker_pb_num_sprite_users[JOKER_LAST_PB - JOKER_BASE_PB + 1] = {0};
60static const int JOKER_ID_TO_SPRITE_MAP[] = {
61 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
85static const int SPRITESHEET_IDX_TO_STARTING_JOKER_ID[] = {
86 0, 18, 20, 22, 27, 32, 36, 40, 42, 44,
87 45, 46, 47, 48, 49, 50, 51, 52
91static const char* JOKER_RARITY_STRINGS_LUT[MAX_RARITIES] = {
92 "Common",
"Uncommon",
"Rare",
"Legendary"
96static int s_get_num_spritesheets(
void);
97static int s_joker_get_spritesheet_idx(u8 joker_id);
98static int s_joker_get_sprite_idx_in_sheet(u8 joker_id,
int spritesheet_idx);
99static void s_joker_pb_add_sprite_user(
int pb);
100static void s_joker_pb_remove_sprite_user(
int pb);
101static int s_joker_pb_get_num_sprite_users(
int joker_pb);
102static int s_get_unused_joker_pb(
void);
103static int s_allocate_pb_if_needed(u8 joker_id);
104static enum JokerRarity joker_get_random_rarity(
enum RngSequence key);
109 int num_spritesheets = s_get_num_spritesheets();
111 for (
int i = 0; i < num_spritesheets; i++)
113 s_joker_spritesheet_pb_map[i] = UNDEFINED;
117Joker* joker_new(u8
id)
119 if (
id >= get_joker_registry_size())
123 const JokerInfo* jinfo = get_joker_registry_entry(
id);
126 joker->value = jinfo->base_value;
127 joker->rarity = jinfo->rarity;
128 joker->scoring_state = 0;
129 joker->persistent_state = 0;
133 jinfo->joker_effect_func(joker, NULL, JOKER_EVENT_ON_JOKER_CREATED, &joker_effect);
138void joker_destroy(
Joker** joker)
140 POOL_FREE(
Joker, *joker);
144u32 joker_get_score_effect(
147 enum JokerEvent joker_event,
151 const JokerInfo* jinfo = get_joker_registry_entry(joker->id);
153 return JOKER_EFFECT_FLAG_NONE;
155 return jinfo->joker_effect_func(joker, scored_card, joker_event, joker_effect);
162 const JokerInfo* info = get_joker_registry_entry(joker->id);
178 const JokerInfo* info = get_joker_registry_entry(joker->id);
181 u8 rarity = joker->rarity;
182 if (rarity >= MAX_RARITIES)
185 "Invalid Joker rarity value %d, should not exceed %d",
193 u32 pal_base = 1 + 2 * rarity;
194 subtype_info.main_color = card_rarity_pal_gfxPal[pal_base];
195 subtype_info.shadow_color = card_rarity_pal_gfxPal[pal_base + 1];
196 subtype_info.name_str = JOKER_RARITY_STRINGS_LUT[rarity];
212 return joker->value / 2;
224 for (s16 i = 0; i < MAX_JOKER_OBJECTS; i++)
226 if (!s_used_layers[i])
229 s_used_layers[i] =
true;
234 joker_object->joker = joker;
235 joker_object->type = ITEM_TYPE_JOKER;
236 joker_object->is_owned =
false;
239 int joker_spritesheet_idx = s_joker_get_spritesheet_idx(joker->id);
240 int joker_idx = s_joker_get_sprite_idx_in_sheet(joker->id, joker_spritesheet_idx);
241 int joker_pb = s_allocate_pb_if_needed(joker->id);
242 s_joker_pb_add_sprite_user(joker_pb);
246 &joker_gfxTiles[joker_spritesheet_idx][joker_idx *
TILE_SIZE * JOKER_SPRITE_TILES],
253 ATTR0_SQUARE | ATTR0_4BPP | ATTR0_AFF,
264void joker_object_destroy(
JokerObject** joker_object)
266 if (joker_object == NULL || *joker_object == NULL)
271 s_used_layers[layer] =
false;
272 s_joker_pb_remove_sprite_user(
sprite_get_pb(joker_object_get_sprite(*joker_object)));
273 if (s_joker_pb_get_num_sprite_users((
sprite_get_pb(joker_object_get_sprite(*joker_object)))) ==
276 s_joker_spritesheet_pb_map[s_joker_get_spritesheet_idx((*joker_object)->joker->id)] =
281 joker_destroy(&(*joker_object)->joker);
283 *joker_object = NULL;
297 joker_object_destroy(&joker_object);
298 *joker_object_item = NULL;
309 Joker* joker = joker_object->joker;
310 const JokerInfo* info = get_joker_registry_entry(joker->id);
313 return info->joker_print_desc(joker, dest_rect);
316void joker_object_shake(
JokerObject* joker_object, mm_word sound_id)
354static inline int get_num_rollable_jokers(
void)
362static inline bool no_rollable_jokers(
void)
368static inline bool joker_is_rollable(
int joker_id)
375 int num_jokers = get_joker_registry_size();
378 for (
int i = 0; i < num_jokers; i++)
387 int jokers_avail_size = get_num_rollable_jokers();
389 if (jokers_avail_size == 0)
392 int matching_joker_ids[jokers_avail_size];
393 int fallback_random_idx =
rng_get_u32(key) % jokers_avail_size;
394 int fallback_random_joker_id = UNDEFINED;
400 int joker_id = UNDEFINED;
403 if (i++ == fallback_random_idx)
404 fallback_random_joker_id = joker_id;
405 const JokerInfo* info = get_joker_registry_entry(joker_id);
406 if (info->rarity == joker_rarity)
408 matching_joker_ids[match_count++] = joker_id;
412 int selected_joker_id = (match_count > 0) ? matching_joker_ids[
rng_get_u32(key) % match_count]
413 : fallback_random_joker_id;
415 return selected_joker_id;
420 if (no_rollable_jokers())
425 if (joker_is_rollable(TEST_JOKER_ID0))
427 joker_id = TEST_JOKER_ID0;
432 if (joker_is_rollable(TEST_JOKER_ID1))
434 joker_id = TEST_JOKER_ID1;
443 if (joker_id == UNDEFINED)
448 return (
Item*)joker_object_new(joker_new(joker_id));
457static inline enum JokerRarity joker_get_random_rarity(
enum RngSequence key)
459 enum JokerRarity joker_rarity = 0;
461 if (rarity_roll < COMMON_JOKER_CHANCE)
463 joker_rarity = COMMON_JOKER;
465 else if (rarity_roll < COMMON_JOKER_CHANCE + UNCOMMON_JOKER_CHANCE)
467 joker_rarity = UNCOMMON_JOKER;
469 else if (rarity_roll < COMMON_JOKER_CHANCE + UNCOMMON_JOKER_CHANCE + RARE_JOKER_CHANCE)
471 joker_rarity = RARE_JOKER;
473 else if (rarity_roll < COMMON_JOKER_CHANCE + UNCOMMON_JOKER_CHANCE + RARE_JOKER_CHANCE +
474 LEGENDARY_JOKER_CHANCE)
476 joker_rarity = LEGENDARY_JOKER;
484 if (joker_object == NULL)
489static int s_get_num_spritesheets()
491 return MAX_NUM_JOKERS_SPRITESHEETS;
494static int s_joker_get_spritesheet_idx(u8 joker_id)
496 return JOKER_ID_TO_SPRITE_MAP[joker_id];
499static int s_joker_get_sprite_idx_in_sheet(u8 joker_id,
int spritesheet_idx)
501 return joker_id - SPRITESHEET_IDX_TO_STARTING_JOKER_ID[JOKER_ID_TO_SPRITE_MAP[joker_id]];
504static void s_joker_pb_add_sprite_user(
int pb)
506 s_joker_pb_num_sprite_users[pb - JOKER_BASE_PB]++;
509static void s_joker_pb_remove_sprite_user(
int pb)
511 int num_sprite_users = s_joker_pb_num_sprite_users[pb - JOKER_BASE_PB];
512 s_joker_pb_num_sprite_users[pb - JOKER_BASE_PB] = max(0, num_sprite_users - 1);
515static int s_joker_pb_get_num_sprite_users(
int joker_pb)
517 return s_joker_pb_num_sprite_users[joker_pb - JOKER_BASE_PB];
520static int s_get_unused_joker_pb()
524 if (s_joker_pb_num_sprite_users[i] == 0)
526 return (i + JOKER_BASE_PB);
533static int s_allocate_pb_if_needed(u8 joker_id)
535 int joker_spritesheet_idx = s_joker_get_spritesheet_idx(joker_id);
536 int joker_pb = s_joker_spritesheet_pb_map[joker_spritesheet_idx];
537 if (joker_pb != UNDEFINED)
544 joker_pb = s_get_unused_joker_pb();
546 if (joker_pb == UNDEFINED)
549 joker_pb = JOKER_BASE_PB;
553 s_joker_spritesheet_pb_map[joker_spritesheet_idx] = joker_pb;
555 &pal_obj_mem[PAL_ROW_LEN * joker_pb],
556 joker_gfxPal[joker_spritesheet_idx],
bool bitset_get_idx(Bitset *bitset, int idx)
Get the value of a flag.
bool bitset_is_empty(Bitset *bitset)
Check if a bitset is empty (all 0's)
void bitset_clear(Bitset *bitset)
Clear the bitset, all to 0.
int bitset_num_set_bits(Bitset *bitset)
Count how many bits are set to 1 in a bitset.
#define BITSET_DEFINE(name, capacity)
Make a standard bitset.
BitsetItr bitset_itr_create(const Bitset *bitset)
Declare a BitsetItr.
int bitset_itr_next(BitsetItr *itr)
Get the index of the next set bit in the bitset from a BitsetItr.
void bitset_set_idx(Bitset *bitset, int idx, bool on)
Set a flag in a bitset to a value.
Game global game variables struct definition.
Graphic utility functions.
#define TILE_SIZE
Tile size in pixels, both height and width as tiles are square.
#define TILE_MEM_OBJ_CHARBLOCK0_IDX
The index for the first charblock of the object memory in tonc's tile_mem.
The core structure for items in the shop and inventory. Provides a common API for the shop and invent...
#define ITEM_SUBTYPE_INFO_DEFAULT
Default subtype info struct declaration.
Functions relative to the handling of Jokers.
void joker_object_dispose(Item **joker_object)
Destroy a JokerObject item, free its resources, and make it available to be rolled.
int joker_get_buy_price(const Joker *joker)
Returns the buy price of the joker.
Item * joker_object_roll_new(enum RngSequence key)
Roll and create a new JokerObject item.
int joker_object_print_description(Item *joker_object, Rect dest_rect)
Print the description of the requested Joker centered within the specified Rect.
int joker_object_get_buy_price(Item *joker_object)
Returns the buy price of the joker object.
const char * joker_object_get_name(Item *joker_object)
Get Joker name.
void joker_object_add_to_owned(Item *joker_object)
Add a Joker to the list of owned Jokers and place it in the joker row.
int joker_roll_id(enum JokerRarity joker_rarity, enum RngSequence key)
Rolls a random Joker among the available ones of a certain rarity.
ItemDescSubtypeInfo joker_object_get_rarity_info(Item *joker_object)
Get Joker rarity name and associated panel color.
void joker_reset_rollable_jokers(void)
Reset rollable jokers to include all jokers in the registry.
int joker_get_sell_value(const Joker *joker)
Returns the sell value of the joker.
int joker_object_get_sell_price(Item *joker_object)
Returns the sell price of the joker object.
void joker_set_rollable(int joker_id, bool rollable)
Set whether a Joker is available to be rolled for the shop, packs, etc.
Header of shared rects and points needed for ui.
Interface to interact with the mgba logger.
Common functions to handle RNG manipulation. Using this interface has three goals:
u32 rng_get_u32(enum RngSequence key)
Get the next "randomly" generated number in the sequence corresponding to the given type.
RngSequence
Keys to different independent RNG sequences.
API relative to the Rounds we play.
void sprite_object_init(SpriteObject *sprite_object)
Initialize a SpriteObject to a default state. Must be called only once per SpriteObject when it is cr...
void sprite_object_destroy(SpriteObject *sprite_object)
Destroy SpriteObject.
s16 sprite_get_layer(Sprite *sprite)
Get index of Sprite in the GBA object buffer.
int sprite_get_tid(enum SpriteType sprite_type, s16 layer)
Get the tile index of a certain SpriteType at a certain layer.
int sprite_get_pb(const Sprite *sprite)
Get the palette bank of a Sprite.
void sprite_object_set_sprite(SpriteObject *sprite_object, Sprite *sprite)
Register a Sprite to an associated SpriteObject.
void sprite_object_shake(SpriteObject *sprite_object, mm_word sound_id)
Shake SpriteObject on screen and play a sound.
Sprite * sprite_new(u16 a0, u16 a1, u32 tid, u32 pb, s16 sprite_index)
Allocate and retrieve a pointer to a valid Sprite.
Sprite * sprite_object_get_sprite(SpriteObject *sprite_object)
Get a SpriteObject's registered Sprite.
int sprite_get_starting_layer(enum SpriteType sprite_type)
Get the starting layer of a certain type of sprite.
An iterator into a Bitset.
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.
A sprite object is a sprite that is focusable and movable in animation.
Sprite struct for GBA hardware specifics.
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.
#define GBAL_RETURN_IF_NULL(param, ret_val)
Returns ret_val and prints a default error message if param is equal to NULL. Useful for checking arg...
#define GBAL_RETURN_IF_ASSERT_FAILS(expression, ret_val)
Returns ret_val and logs a default error message if expression is false.
#define GBAL_UNUSED
Wrapper around the "unused" attribute.
#define RET_NONE
An empty return value for RETURN_IF macros when used in void functions Expands to nothing because mac...