GBAlatro
A Demake of Balatro for the GBA
Loading...
Searching...
No Matches
joker.c
1#include "joker.h"
2
3#include "card.h"
4#include "game/round.h"
5#include "game_variables.h"
6#include "graphic_utils.h"
7#include "item.h"
8#include "layout.h"
9#include "mgba_logger.h"
10#include "pool.h"
11#include "random.h"
12#include "soundbank.h"
13#include "util.h"
14
15// Tiles and palettes
16#include "card_rarity_pal_gfx.h"
17#include "joker_gfx.h"
18
19#include <maxmod.h>
20#include <stdlib.h>
21#include <string.h>
22#include <tonc.h>
23
24// what it was before (MAX_DEFINEABLE_JOKERS / JOKERS_PER_SPRITESHEET)
25#define MAX_NUM_JOKERS_SPRITESHEETS 75
26
27static const unsigned int* joker_gfxTiles[] = {
28#define DEF_JOKER_GFX(idx) joker_gfx##idx##Tiles,
29#include "../include/def_joker_gfx_table.h"
30#undef DEF_JOKER_GFX
31};
32static const unsigned short* joker_gfxPal[] = {
33#define DEF_JOKER_GFX(idx) joker_gfx##idx##Pal,
34#include "def_joker_gfx_table.h"
35#undef DEF_JOKER_GFX
36};
37
38/* So for the card objects, I needed them to be properly sorted
39 which is why they let you specify the layer index when creating a new card object.
40 Since the cards would overlap a lot in your hand, If they weren't sorted properly, it would look
41 like a mess. The joker objects are functionally identical to card objects, so they use the same
42 logic. But I'm going to use a simpler approach for the joker objects since I'm lazy and sorting
43 them wouldn't look good enough to warrant the effort.
44*/
45static bool s_used_layers[MAX_JOKER_OBJECTS] = {false}; // Track used layers for joker sprites
46// TODO: Refactor sorting into SpriteObject?
47
48// Maps the spritesheet index to the palette bank index allocated to it.
49// Spritesheets that were not allocated are
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};
52
53BITSET_DEFINE(s_rollable_jokers_bitset, MAX_DEFINABLE_JOKERS)
54
55// See linked issue for context of maps
56// https://github.com/GBALATRO/balatro-gba/issues/274#issue-3685075538
57
58// clang-format off
59// Map of Joker ID -> Spritesheet idx
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,
62 1, 1,
63 2, 2,
64 3, 3, 3, 3, 3,
65 4, 4, 4, 4, 4,
66 5, 5, 5, 5,
67 6, 6, 6, 6,
68 7, 7,
69 8, 8,
70 9,
71 10,
72 11,
73 12,
74 13,
75 14,
76 15,
77 16,
78 17,
79};
80
81// Map of Spritesheet idx -> first Joker ID in sheet
82// This is used to determine the sprite index of a Joker's sprite
83// within its spritesheet by substracting its ID to this starting ID.
84// Notice how spritesheets with only one Joker have sequential starting IDs.
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
88};
89
90// Lookup table of Joker Rarity strings. Used to display at the bottom of the description screen.
91static const char* JOKER_RARITY_STRINGS_LUT[MAX_RARITIES] = {
92 "Common", "Uncommon", "Rare", "Legendary"
93};
94// clang-format on
95
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);
105
106void joker_init()
107{
108 // This should init once only so no need to free
109 int num_spritesheets = s_get_num_spritesheets();
110
111 for (int i = 0; i < num_spritesheets; i++)
112 {
113 s_joker_spritesheet_pb_map[i] = UNDEFINED;
114 }
115}
116
117Joker* joker_new(u8 id)
118{
119 if (id >= get_joker_registry_size())
120 return NULL;
121
122 Joker* joker = POOL_GET(Joker);
123 const JokerInfo* jinfo = get_joker_registry_entry(id);
124
125 joker->id = id;
126 joker->value = jinfo->base_value;
127 joker->rarity = jinfo->rarity;
128 joker->scoring_state = 0;
129 joker->persistent_state = 0;
130
131 // initialize persistent Joker data if needed
132 JokerEffect* joker_effect = NULL;
133 jinfo->joker_effect_func(joker, NULL, JOKER_EVENT_ON_JOKER_CREATED, &joker_effect);
134
135 return joker;
136}
137
138void joker_destroy(Joker** joker)
139{
140 POOL_FREE(Joker, *joker);
141 *joker = NULL;
142}
143
144u32 joker_get_score_effect(
145 Joker* joker,
146 Card* scored_card,
147 enum JokerEvent joker_event,
148 JokerEffect** joker_effect
149)
150{
151 const JokerInfo* jinfo = get_joker_registry_entry(joker->id);
152 if (!jinfo)
153 return JOKER_EFFECT_FLAG_NONE;
154
155 return jinfo->joker_effect_func(joker, scored_card, joker_event, joker_effect);
156}
157
158const char* joker_object_get_name(Item* joker_object)
159{
160 GBAL_RETURN_IF_NULL(joker_object, NULL);
161 Joker* joker = ((JokerObject*)joker_object)->joker;
162 const JokerInfo* info = get_joker_registry_entry(joker->id);
163 GBAL_RETURN_IF_NULL(info, NULL);
164
165 return info->name;
166}
167
169{
171
172 GBAL_RETURN_IF_NULL(joker_object, subtype_info);
173 GBAL_RETURN_IF_ASSERT_FAILS(joker_object->type == ITEM_TYPE_JOKER, subtype_info);
174
175 Joker* joker = ((JokerObject*)joker_object)->joker;
176 GBAL_RETURN_IF_NULL(joker, subtype_info);
177
178 const JokerInfo* info = get_joker_registry_entry(joker->id);
179 GBAL_RETURN_IF_NULL(info, subtype_info);
180
181 u8 rarity = joker->rarity;
182 if (rarity >= MAX_RARITIES)
183 {
184 MGBA_FUNC_ERROR(
185 "Invalid Joker rarity value %d, should not exceed %d",
186 rarity,
187 MAX_RARITIES
188 );
189 return subtype_info;
190 }
191
192 // +1 to account for the mandatory transparency in Asperite color palettes
193 u32 pal_base = 1 + 2 * rarity;
194 subtype_info.main_color = card_rarity_pal_gfxPal[pal_base]; // even indices for shadows
195 subtype_info.shadow_color = card_rarity_pal_gfxPal[pal_base + 1]; // odd ones for main colors
196 subtype_info.name_str = JOKER_RARITY_STRINGS_LUT[rarity];
197
198 return subtype_info;
199}
200
201int joker_get_buy_price(const Joker* joker)
202{
203 GBAL_RETURN_IF_NULL(joker, UNDEFINED);
204
205 return joker->value;
206}
207
209{
210 GBAL_RETURN_IF_NULL(joker, UNDEFINED);
211
212 return joker->value / 2;
213}
214
215// JokerObject methods
216JokerObject* joker_object_new(Joker* joker)
217{
218 GBAL_RETURN_IF_NULL(joker, NULL);
219 JokerObject* joker_object = POOL_GET(JokerObject);
220
221 sprite_object_init((SpriteObject*)joker_object);
222
223 s16 layer = 0;
224 for (s16 i = 0; i < MAX_JOKER_OBJECTS; i++)
225 {
226 if (!s_used_layers[i])
227 {
228 layer = i;
229 s_used_layers[i] = true; // Mark this layer as used
230 break;
231 }
232 }
233
234 joker_object->joker = joker;
235 joker_object->type = ITEM_TYPE_JOKER;
236 joker_object->is_owned = false;
237
238 int tile_index = sprite_get_tid(JOKER_SPRITE, layer);
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);
243
244 memcpy32(
245 &tile_mem[TILE_MEM_OBJ_CHARBLOCK0_IDX][tile_index],
246 &joker_gfxTiles[joker_spritesheet_idx][joker_idx * TILE_SIZE * JOKER_SPRITE_TILES],
247 TILE_SIZE * JOKER_SPRITE_TILES
248 );
249
251 (SpriteObject*)joker_object,
253 ATTR0_SQUARE | ATTR0_4BPP | ATTR0_AFF,
254 ATTR1_SIZE_32,
255 tile_index,
256 joker_pb,
257 sprite_get_starting_layer(JOKER_SPRITE) + layer
258 )
259 );
260
261 return joker_object;
262}
263
264void joker_object_destroy(JokerObject** joker_object)
265{
266 if (joker_object == NULL || *joker_object == NULL)
267 return;
268
269 s16 layer = sprite_get_layer(joker_object_get_sprite(*joker_object)) -
270 sprite_get_starting_layer(JOKER_SPRITE);
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)))) ==
274 0)
275 {
276 s_joker_spritesheet_pb_map[s_joker_get_spritesheet_idx((*joker_object)->joker->id)] =
277 UNDEFINED;
278 }
279
280 sprite_object_destroy((SpriteObject*)(*joker_object));
281 joker_destroy(&(*joker_object)->joker);
282 POOL_FREE(JokerObject, *joker_object);
283 *joker_object = NULL;
284}
285
286void joker_object_dispose(Item** joker_object_item)
287{
288 GBAL_RETURN_IF_NULL(joker_object_item, RET_NONE);
289 GBAL_RETURN_IF_NULL(*joker_object_item, RET_NONE);
290 GBAL_RETURN_IF_ASSERT_FAILS((*joker_object_item)->type == ITEM_TYPE_JOKER, RET_NONE);
291
292 JokerObject* joker_object = (JokerObject*)(*joker_object_item);
293 GBAL_RETURN_IF_NULL(joker_object->joker, RET_NONE);
294
295 joker_set_rollable(joker_object->joker->id, true);
296
297 joker_object_destroy(&joker_object);
298 *joker_object_item = NULL;
299}
300
301int joker_object_print_description(Item* joker_object_item, Rect dest_rect)
302{
303 GBAL_RETURN_IF_NULL(joker_object_item, 0);
304 GBAL_RETURN_IF_ASSERT_FAILS(joker_object_item->type == ITEM_TYPE_JOKER, 0);
305
306 JokerObject* joker_object = (JokerObject*)(joker_object_item);
307 GBAL_RETURN_IF_NULL(joker_object->joker, 0);
308
309 Joker* joker = joker_object->joker;
310 const JokerInfo* info = get_joker_registry_entry(joker->id);
311 GBAL_RETURN_IF_NULL(info, 0);
312
313 return info->joker_print_desc(joker, dest_rect);
314}
315
316void joker_object_shake(JokerObject* joker_object, mm_word sound_id)
317{
318 sprite_object_shake((SpriteObject*)joker_object, sound_id);
319}
320
322{
323 GBAL_RETURN_IF_NULL(joker_object, UNDEFINED);
324 GBAL_RETURN_IF_ASSERT_FAILS(joker_object->type == ITEM_TYPE_JOKER, UNDEFINED);
325
326 return joker_get_buy_price(((JokerObject*)joker_object)->joker);
327}
328
330{
331 GBAL_RETURN_IF_NULL(joker_object, UNDEFINED);
332 GBAL_RETURN_IF_ASSERT_FAILS(joker_object->type == ITEM_TYPE_JOKER, UNDEFINED);
333
334 return joker_get_sell_value(((JokerObject*)joker_object)->joker);
335}
336
338{
339 GBAL_RETURN_IF_NULL(joker_object, RET_NONE);
340 GBAL_RETURN_IF_ASSERT_FAILS(joker_object->type == ITEM_TYPE_JOKER, RET_NONE);
341
342 add_joker((JokerObject*)joker_object);
343}
344
345void joker_set_rollable(int joker_id, bool rollable)
346{
347 bitset_set_idx(&s_rollable_jokers_bitset, joker_id, rollable);
348}
349
354static inline int get_num_rollable_jokers(void)
355{
356 return bitset_num_set_bits(&s_rollable_jokers_bitset);
357}
358
362static inline bool no_rollable_jokers(void)
363{
364 return bitset_is_empty(&s_rollable_jokers_bitset);
365}
366
368static inline bool joker_is_rollable(int joker_id)
369{
370 return bitset_get_idx(&s_rollable_jokers_bitset, joker_id);
371}
372
374{
375 int num_jokers = get_joker_registry_size();
376
377 bitset_clear(&s_rollable_jokers_bitset);
378 for (int i = 0; i < num_jokers; i++)
379 {
380 bitset_set_idx(&s_rollable_jokers_bitset, i, true);
381 }
382}
383
384int joker_roll_id(enum JokerRarity joker_rarity, enum RngSequence key)
385{
386 // Now determine how many jokers are available based on the rarity
387 int jokers_avail_size = get_num_rollable_jokers();
388
389 if (jokers_avail_size == 0)
390 return UNDEFINED;
391
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;
395 int match_count = 0;
396
397 BitsetItr itr = bitset_itr_create(&s_rollable_jokers_bitset);
398
399 int i = 0;
400 int joker_id = UNDEFINED;
401 while ((joker_id = bitset_itr_next(&itr)) != UNDEFINED)
402 {
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)
407 {
408 matching_joker_ids[match_count++] = joker_id;
409 }
410 }
411
412 int selected_joker_id = (match_count > 0) ? matching_joker_ids[rng_get_u32(key) % match_count]
413 : fallback_random_joker_id;
414
415 return selected_joker_id;
416}
417
419{
420 if (no_rollable_jokers())
421 return NULL;
422
423 int joker_id = 0;
424#ifdef TEST_JOKER_ID0 // Allow defining an ID for a joker to always appear in shop and be tested
425 if (joker_is_rollable(TEST_JOKER_ID0))
426 {
427 joker_id = TEST_JOKER_ID0;
428 }
429 else
430#endif
431#ifdef TEST_JOKER_ID1
432 if (joker_is_rollable(TEST_JOKER_ID1))
433 {
434 joker_id = TEST_JOKER_ID1;
435 }
436 else
437#endif
438 {
439 joker_id = joker_roll_id(joker_get_random_rarity(key), key);
440 }
441
442 // If for some reason only no joker is left, don't make another
443 if (joker_id == UNDEFINED)
444 return NULL;
445
446 joker_set_rollable(joker_id, false);
447
448 return (Item*)joker_object_new(joker_new(joker_id));
449}
450
457static inline enum JokerRarity joker_get_random_rarity(enum RngSequence key)
458{
459 enum JokerRarity joker_rarity = 0;
460 int rarity_roll = rng_get_u32(key) % 100;
461 if (rarity_roll < COMMON_JOKER_CHANCE)
462 {
463 joker_rarity = COMMON_JOKER;
464 }
465 else if (rarity_roll < COMMON_JOKER_CHANCE + UNCOMMON_JOKER_CHANCE)
466 {
467 joker_rarity = UNCOMMON_JOKER;
468 }
469 else if (rarity_roll < COMMON_JOKER_CHANCE + UNCOMMON_JOKER_CHANCE + RARE_JOKER_CHANCE)
470 {
471 joker_rarity = RARE_JOKER;
472 }
473 else if (rarity_roll < COMMON_JOKER_CHANCE + UNCOMMON_JOKER_CHANCE + RARE_JOKER_CHANCE +
474 LEGENDARY_JOKER_CHANCE)
475 {
476 joker_rarity = LEGENDARY_JOKER;
477 }
478
479 return joker_rarity;
480}
481
482Sprite* joker_object_get_sprite(JokerObject* joker_object)
483{
484 if (joker_object == NULL)
485 return NULL;
486 return sprite_object_get_sprite((SpriteObject*)joker_object);
487}
488
489static int s_get_num_spritesheets()
490{
491 return MAX_NUM_JOKERS_SPRITESHEETS;
492}
493
494static int s_joker_get_spritesheet_idx(u8 joker_id)
495{
496 return JOKER_ID_TO_SPRITE_MAP[joker_id];
497}
498
499static int s_joker_get_sprite_idx_in_sheet(u8 joker_id, int spritesheet_idx)
500{
501 return joker_id - SPRITESHEET_IDX_TO_STARTING_JOKER_ID[JOKER_ID_TO_SPRITE_MAP[joker_id]];
502}
503
504static void s_joker_pb_add_sprite_user(int pb)
505{
506 s_joker_pb_num_sprite_users[pb - JOKER_BASE_PB]++;
507}
508
509static void s_joker_pb_remove_sprite_user(int pb)
510{
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);
513}
514
515static int s_joker_pb_get_num_sprite_users(int joker_pb)
516{
517 return s_joker_pb_num_sprite_users[joker_pb - JOKER_BASE_PB];
518}
519
520static int s_get_unused_joker_pb()
521{
522 for (int i = 0; i < NUM_ELEM_IN_ARR(s_joker_pb_num_sprite_users); i++)
523 {
524 if (s_joker_pb_num_sprite_users[i] == 0)
525 {
526 return (i + JOKER_BASE_PB);
527 }
528 }
529
530 return UNDEFINED;
531}
532
533static int s_allocate_pb_if_needed(u8 joker_id)
534{
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)
538 {
539 // Already allocated
540 return joker_pb;
541 }
542
543 // Allocate a new palette
544 joker_pb = s_get_unused_joker_pb();
545
546 if (joker_pb == UNDEFINED)
547 {
548 // Ran out of palettes, default to base and pray
549 joker_pb = JOKER_BASE_PB;
550 }
551 else
552 {
553 s_joker_spritesheet_pb_map[joker_spritesheet_idx] = joker_pb;
554 memcpy16(
555 &pal_obj_mem[PAL_ROW_LEN * joker_pb],
556 joker_gfxPal[joker_spritesheet_idx],
557 NUM_ELEM_IN_ARR(joker_gfx0Pal)
558 );
559 }
560
561 return joker_pb;
562}
bool bitset_get_idx(Bitset *bitset, int idx)
Get the value of a flag.
Definition bitset.c:72
bool bitset_is_empty(Bitset *bitset)
Check if a bitset is empty (all 0's)
Definition bitset.c:62
void bitset_clear(Bitset *bitset)
Clear the bitset, all to 0.
Definition bitset.c:54
int bitset_num_set_bits(Bitset *bitset)
Count how many bits are set to 1 in a bitset.
Definition bitset.c:80
#define BITSET_DEFINE(name, capacity)
Make a standard bitset.
Definition bitset.h:198
BitsetItr bitset_itr_create(const Bitset *bitset)
Declare a BitsetItr.
Definition bitset.c:128
int bitset_itr_next(BitsetItr *itr)
Get the index of the next set bit in the bitset from a BitsetItr.
Definition bitset.c:140
void bitset_set_idx(Bitset *bitset, int idx, bool on)
Set a flag in a bitset to a value.
Definition bitset.c:5
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.
Definition item.h:44
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.
Definition joker.c:286
int joker_get_buy_price(const Joker *joker)
Returns the buy price of the joker.
Definition joker.c:201
Item * joker_object_roll_new(enum RngSequence key)
Roll and create a new JokerObject item.
Definition joker.c:418
int joker_object_print_description(Item *joker_object, Rect dest_rect)
Print the description of the requested Joker centered within the specified Rect.
Definition joker.c:301
int joker_object_get_buy_price(Item *joker_object)
Returns the buy price of the joker object.
Definition joker.c:321
const char * joker_object_get_name(Item *joker_object)
Get Joker name.
Definition joker.c:158
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.
Definition joker.c:337
int joker_roll_id(enum JokerRarity joker_rarity, enum RngSequence key)
Rolls a random Joker among the available ones of a certain rarity.
Definition joker.c:384
ItemDescSubtypeInfo joker_object_get_rarity_info(Item *joker_object)
Get Joker rarity name and associated panel color.
Definition joker.c:168
void joker_reset_rollable_jokers(void)
Reset rollable jokers to include all jokers in the registry.
Definition joker.c:373
int joker_get_sell_value(const Joker *joker)
Returns the sell value of the joker.
Definition joker.c:208
int joker_object_get_sell_price(Item *joker_object)
Returns the sell price of the joker object.
Definition joker.c:329
void joker_set_rollable(int joker_id, bool rollable)
Set whether a Joker is available to be rolled for the shop, packs, etc.
Definition joker.c:345
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.
Definition random.c:56
RngSequence
Keys to different independent RNG sequences.
Definition random.h:19
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...
Definition sprite.c:237
void sprite_object_destroy(SpriteObject *sprite_object)
Destroy SpriteObject.
Definition sprite.c:248
s16 sprite_get_layer(Sprite *sprite)
Get index of Sprite in the GBA object buffer.
Definition sprite.c:157
int sprite_get_tid(enum SpriteType sprite_type, s16 layer)
Get the tile index of a certain SpriteType at a certain layer.
Definition sprite.c:66
int sprite_get_pb(const Sprite *sprite)
Get the palette bank of a Sprite.
Definition sprite.c:215
void sprite_object_set_sprite(SpriteObject *sprite_object, Sprite *sprite)
Register a Sprite to an associated SpriteObject.
Definition sprite.c:256
void sprite_object_shake(SpriteObject *sprite_object, mm_word sound_id)
Shake SpriteObject on screen and play a sound.
Definition sprite.c:403
Sprite * sprite_new(u16 a0, u16 a1, u32 tid, u32 pb, s16 sprite_index)
Allocate and retrieve a pointer to a valid Sprite.
Definition sprite.c:77
Sprite * sprite_object_get_sprite(SpriteObject *sprite_object)
Get a SpriteObject's registered Sprite.
Definition sprite.c:439
int sprite_get_starting_layer(enum SpriteType sprite_type)
Get the starting layer of a certain type of sprite.
Definition sprite.c:71
An iterator into a Bitset.
Definition bitset.h:73
Definition card.h:46
Structure containing the main and shadow colors, and the name string associated with an Item's subtyp...
Definition item.h:65
A generic interface for all items that can appear in the shop or be in the inventory....
Definition item.h:83
enum ItemType type
The item type - used to dispatch the function implementations for inheriting types.
Definition item.h:94
Definition joker.h:83
A sprite object is a sprite that is focusable and movable in animation.
Definition sprite.h:86
Sprite struct for GBA hardware specifics.
Definition sprite.h:54
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.
Definition util.h:55
#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...
Definition util.h:138
#define GBAL_RETURN_IF_ASSERT_FAILS(expression, ret_val)
Returns ret_val and logs a default error message if expression is false.
Definition util.h:109
#define GBAL_UNUSED
Wrapper around the "unused" attribute.
Definition util.h:25
#define RET_NONE
An empty return value for RETURN_IF macros when used in void functions Expands to nothing because mac...
Definition util.h:146