Merge branch 'main' into start_music_after_splashscreen

This commit is contained in:
MeirGavish
2025-10-21 12:25:07 +03:00
18 changed files with 479 additions and 35 deletions
+6 -6
View File
@@ -9,6 +9,8 @@
// Audio
#include "soundbank.h"
#include "pool.h"
// Card sprites lookup table. First index is the suit, second index is the rank. The value is the tile index.
const static u16 card_sprite_lut[NUM_SUITS][NUM_RANKS] = {
{0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192},
@@ -25,7 +27,7 @@ void card_init()
// Card methods
Card *card_new(u8 suit, u8 rank)
{
Card *card = malloc(sizeof(Card));
Card *card = POOL_GET(Card);
card->suit = suit;
card->rank = rank;
@@ -35,8 +37,7 @@ Card *card_new(u8 suit, u8 rank)
void card_destroy(Card **card)
{
if (*card == NULL) return;
free(*card);
POOL_FREE(Card, *card);
*card = NULL;
}
@@ -61,7 +62,7 @@ u8 card_get_value(Card *card)
// CardObject methods
CardObject *card_object_new(Card *card)
{
CardObject *card_object = malloc(sizeof(CardObject));
CardObject *card_object = POOL_GET(CardObject);
card_object->card = card;
card_object->sprite_object = sprite_object_new();
@@ -73,8 +74,7 @@ void card_object_destroy(CardObject **card_object)
{
if (*card_object == NULL) return;
sprite_object_destroy(&((*card_object)->sprite_object));
//card_destroy(&(*card_object)->card); // In practice, this is unnecessary because the card will be inserted into the discard pile and then back into the deck. If you need to destroy the card, you can do it manually before calling this function.
free(*card_object);
POOL_FREE(CardObject, *card_object);
*card_object = NULL;
}
+9 -8
View File
@@ -11,10 +11,13 @@
#include <stdlib.h>
#include <string.h>
#include "pool.h"
#define JOKER_SCORE_TEXT_Y 48
#define NUM_JOKERS_PER_SPRITESHEET 2
#define MAX_DEFINABLE_JOKERS 150
static const unsigned int *joker_gfxTiles[] =
static const unsigned int *joker_gfxTiles[] =
{
#define DEF_JOKER_GFX(idx) joker_gfx##idx##Tiles,
#include "../include/def_joker_gfx_table.h"
@@ -48,7 +51,7 @@ static bool used_layers[MAX_JOKER_OBJECTS] = {false}; // Track used layers for j
// Maps the spritesheet index to the palette bank index allocated to it.
// Spritesheets that were not allocated are
static int* joker_spritesheet_pb_map;
static int joker_spritesheet_pb_map[(MAX_DEFINABLE_JOKERS + 1) / NUM_JOKERS_PER_SPRITESHEET];
static int joker_pb_num_sprite_users[JOKER_LAST_PB - JOKER_BASE_PB + 1] = { 0 };
static int get_num_spritesheets()
@@ -123,7 +126,6 @@ void joker_init()
{
// This should init once only so no need to free
int num_spritesheets = get_num_spritesheets();
joker_spritesheet_pb_map = (int*)malloc(sizeof(int) * num_spritesheets);
for (int i = 0; i < num_spritesheets; i++)
{
@@ -135,7 +137,7 @@ Joker *joker_new(u8 id)
{
if (id >= get_joker_registry_size()) return NULL;
Joker *joker = (Joker*)malloc(sizeof(Joker));
Joker *joker = POOL_GET(Joker);
const JokerInfo *jinfo = get_joker_registry_entry(id);
joker->id = id;
@@ -149,8 +151,7 @@ Joker *joker_new(u8 id)
void joker_destroy(Joker **joker)
{
if (*joker == NULL) return;
free(*joker);
POOL_FREE(Joker, *joker);
*joker = NULL;
}
@@ -175,7 +176,7 @@ int joker_get_sell_value(const Joker* joker)
// JokerObject methods
JokerObject *joker_object_new(Joker *joker)
{
JokerObject *joker_object = malloc(sizeof(JokerObject));
JokerObject *joker_object = POOL_GET(JokerObject);
int layer = 0;
for (int i = 0; i < MAX_JOKER_OBJECTS; i++)
@@ -232,7 +233,7 @@ void joker_object_destroy(JokerObject **joker_object)
sprite_object_destroy(&(*joker_object)->sprite_object); // Destroy the sprite
joker_destroy(&(*joker_object)->joker); // Destroy the joker
free(*joker_object);
POOL_FREE(JokerObject, *joker_object);
*joker_object = NULL;
}
+49
View File
@@ -0,0 +1,49 @@
#include "pool.h"
#include "util.h"
void pool_bm_clear_idx(PoolBitmap *bm, int idx)
{
uint32_t i = idx / POOL_BITS_PER_WORD;
uint32_t b = idx % POOL_BITS_PER_WORD;
// Below are the "fast" forms of the above operations, respectively.
// These are more efficient, but removed for readability
// See: https://github.com/cellos51/balatro-gba/pull/132#discussion_r2365966071
// Divide by 32 to get the word index
//uint32_t i = idx >> 5;
// Get last 5-bits, same as a modulo (% 32) operation on positive numbers
//uint32_t b = idx & 0x1F;
bm->w[i] &= ~((uint32_t)1 << b);
}
int pool_bm_get_free_idx(PoolBitmap *bm)
{
for (uint32_t i = 0; i < bm->nwords; i++)
{
uint32_t inv = ~bm->w[i];
// guard so we don't call `ctz` with 0, since __builtin_ctz(0) is undefined
// https://gcc.gnu.org/onlinedocs/gcc/Bit-Operation-Builtins.html#index-_005f_005fbuiltin_005fctz
//
// By using the bitwise inverse of the word, you can skip words that are full
// quickly (where the value is 0 or 'false' since all bits are '1', or 'in use'). Any value greater
// than 0 indicates there is a free slot. Then, when counting the trailing 0's, you can test very quickly
// where the first free slot is. This operation prevents looping through every bit of filled flags, and
// will instead operate only on the first word with free slots.
if (inv)
{
int bit = __builtin_ctz(inv);
bm->w[i] |= ((uint32_t)1 << bit);
int idx = i * POOL_BITS_PER_WORD + bit;
return (idx < bm->cap) ? idx : -1;
}
}
return UNDEFINED;
}
#define POOL_ENTRY(name, capacity) \
POOL_DEFINE_TYPE(name, capacity);
#include POOLS_DEF_FILE
#undef POOL_ENTRY
+19 -11
View File
@@ -3,6 +3,7 @@
#include "util.h"
#include "audio_utils.h"
#include "soundbank.h"
#include "pool.h"
#include <tonc.h>
#include <stdlib.h>
@@ -21,7 +22,7 @@ static bool free_affines[MAX_AFFINES] = {false};
// Sprite methods
Sprite *sprite_new(u16 a0, u16 a1, u32 tid, u32 pb, int sprite_index)
{
Sprite *sprite = malloc(sizeof(Sprite));
Sprite* sprite = POOL_GET(Sprite);
sprite->obj = NULL;
sprite->aff = NULL;
@@ -32,7 +33,7 @@ Sprite *sprite_new(u16 a0, u16 a1, u32 tid, u32 pb, int sprite_index)
}
else
{
free(sprite);
POOL_FREE(Sprite, sprite);
return NULL;
}
@@ -52,7 +53,7 @@ Sprite *sprite_new(u16 a0, u16 a1, u32 tid, u32 pb, int sprite_index)
if (aff_index == MAX_AFFINES)
{
free(sprite);
POOL_FREE(Sprite, sprite);
return NULL;
}
@@ -62,32 +63,39 @@ Sprite *sprite_new(u16 a0, u16 a1, u32 tid, u32 pb, int sprite_index)
sprite->aff = &obj_aff_buffer[aff_index];
obj_set_attr(sprite->obj, a0, a1, ATTR2_PALBANK(pb) | tid);
obj_aff_identity(&obj_aff_buffer[aff_index]);
return sprite;
}
else
{
sprite->obj = &obj_buffer[sprite_index];
obj_set_attr(sprite->obj, a0, a1, ATTR2_PALBANK(pb) | tid);
return sprite;
}
sprite->idx = sprite_index;
return sprite;
}
void sprite_destroy(Sprite **sprite)
{
if (*sprite == NULL) return;
obj_hide((*sprite)->obj);
free_sprites[(*sprite)->obj - obj_buffer] = NULL;
if ((*sprite)->aff != NULL)
{
free_affines[(*sprite)->aff - obj_aff_buffer] = false;
}
free(*sprite);
free_sprites[(*sprite)->idx] = NULL;
POOL_FREE(Sprite, *sprite);
*sprite = NULL;
}
int sprite_get_layer(Sprite *sprite)
{
if (sprite == NULL || sprite->obj == NULL) return -1;
if (sprite == NULL || sprite->obj == NULL) return UNDEFINED;
return sprite->obj - obj_buffer;
}
@@ -115,7 +123,7 @@ int sprite_get_pb(const Sprite *sprite)
// SpriteObject methods
SpriteObject* sprite_object_new()
{
SpriteObject* sprite_object = (SpriteObject*)malloc(sizeof(SpriteObject));
SpriteObject* sprite_object = POOL_GET(SpriteObject);
sprite_object->sprite = NULL;
sprite_object_reset_transform(sprite_object);
sprite_object->selected = false;
@@ -127,8 +135,8 @@ SpriteObject* sprite_object_new()
void sprite_object_destroy(SpriteObject** sprite_object)
{
if (*sprite_object == NULL) return;
sprite_destroy(&((*sprite_object)->sprite));
free(*sprite_object);
sprite_destroy(&(*sprite_object)->sprite);
POOL_FREE(SpriteObject, *sprite_object);
*sprite_object = NULL;
}