Clang format joker files and def files (#257)

* Clang format joker files and def files

* Fix blind usage of GBLA_UNUSED macro

* Add final files for clang-format (main.c and selection_grid.h)

---------

Co-authored-by: MeirGavish <meir.gavish@gmail.com>
This commit is contained in:
Rickey
2025-12-10 09:41:24 +02:00
committed by GitHub
co-authored by MeirGavish
parent 35ecbf33ae
commit 2fb9e6d633
12 changed files with 2014 additions and 1403 deletions
+1 -18
View File
@@ -17,21 +17,4 @@ jobs:
uses: actions/checkout@v5 uses: actions/checkout@v5
- name: Run clang-format - name: Run clang-format
run: > run: clang-format --dry-run -Werror include/*.h source/*.c
clang-format --dry-run -Werror
include/bitset.h source/bitset.c
include/affine_background.h source/affine_background.c
include/audio_utils.h source/audio_utils.c
include/graphic_utils.h source/graphic_utils.c
include/util.h source/util.c
include/pool.h source/pool.c
include/card.h source/card.c
include/game.h source/game.c
include/hand_analysis.h source/hand_analysis.c
include/list.h source/list.c
include/sprite.h source/sprite.c
include/splash_screen.h source/splash_screen.c
include/blind.h source/blind.c
# Currently contains only the code that has been formatted to conform
# When all existing code conforms, change to this:
# run: clang-format --dry-run -Werror include/*.h source/*.c
+2 -2
View File
@@ -1,7 +1,7 @@
#include "sprite.h"
#include "joker.h"
#include "card.h" #include "card.h"
#include "joker.h"
#include "list.h" #include "list.h"
#include "sprite.h"
POOL_ENTRY(Sprite, MAX_SPRITES); POOL_ENTRY(Sprite, MAX_SPRITES);
POOL_ENTRY(SpriteObject, MAX_SPRITE_OBJECTS); POOL_ENTRY(SpriteObject, MAX_SPRITE_OBJECTS);
+2
View File
@@ -1,3 +1,4 @@
// clang-format off
// (stateEnum, on_init, on_update, on_exit) // (stateEnum, on_init, on_update, on_exit)
DEF_STATE_INFO(GAME_STATE_SPLASH_SCREEN, splash_screen_on_init, splash_screen_on_update, splash_screen_on_exit) DEF_STATE_INFO(GAME_STATE_SPLASH_SCREEN, splash_screen_on_init, splash_screen_on_update, splash_screen_on_exit)
DEF_STATE_INFO(GAME_STATE_MAIN_MENU, game_main_menu_on_init, game_main_menu_on_update, noop) DEF_STATE_INFO(GAME_STATE_MAIN_MENU, game_main_menu_on_init, game_main_menu_on_update, noop)
@@ -7,3 +8,4 @@ DEF_STATE_INFO(GAME_STATE_SHOP, noop, game_shop_on_update, game_shop_on_exit)
DEF_STATE_INFO(GAME_STATE_BLIND_SELECT, noop, game_blind_select_on_update, game_blind_select_on_exit) DEF_STATE_INFO(GAME_STATE_BLIND_SELECT, noop, game_blind_select_on_update, game_blind_select_on_exit)
DEF_STATE_INFO(GAME_STATE_LOSE, game_lose_on_init, game_lose_on_update, game_over_on_exit) DEF_STATE_INFO(GAME_STATE_LOSE, game_lose_on_init, game_lose_on_update, game_over_on_exit)
DEF_STATE_INFO(GAME_STATE_WIN, game_win_on_init, game_win_on_update, game_over_on_exit) DEF_STATE_INFO(GAME_STATE_WIN, game_win_on_init, game_win_on_update, game_over_on_exit)
// clang-format on
+61 -31
View File
@@ -1,12 +1,12 @@
#ifndef JOKER_H #ifndef JOKER_H
#define JOKER_H #define JOKER_H
#include <maxmod.h>
#include "sprite.h"
#include "card.h" #include "card.h"
#include "game.h" #include "game.h"
#include "graphic_utils.h" #include "graphic_utils.h"
#include "sprite.h"
#include <maxmod.h>
// This won't be more than the number of jokers in your current deck // This won't be more than the number of jokers in your current deck
// plus the amount that can fit in the shop, 8 should be fine. For now... // plus the amount that can fit in the shop, 8 should be fine. For now...
@@ -14,7 +14,8 @@
#define MAX_DEFINABLE_JOKERS 150 #define MAX_DEFINABLE_JOKERS 150
#define JOKER_TID (MAX_HAND_SIZE + MAX_SELECTION_SIZE) * JOKER_SPRITE_OFFSET // Tile ID for the starting index in the tile memory // Tile ID for the starting index in the tile memory
#define JOKER_TID (MAX_HAND_SIZE + MAX_SELECTION_SIZE) * JOKER_SPRITE_OFFSET
#define JOKER_SPRITE_OFFSET 16 // Offset for the joker sprites #define JOKER_SPRITE_OFFSET 16 // Offset for the joker sprites
#define JOKER_BASE_PB 4 // The starting palette index for the jokers #define JOKER_BASE_PB 4 // The starting palette index for the jokers
#define JOKER_LAST_PB (NUM_PALETTES - 1) #define JOKER_LAST_PB (NUM_PALETTES - 1)
@@ -49,16 +50,23 @@
// Joker per Joker basis (see if it's there, then do something, e.g. Pareidolia, Baseball Card) // Joker per Joker basis (see if it's there, then do something, e.g. Pareidolia, Baseball Card)
enum JokerEvent enum JokerEvent
{ {
JOKER_EVENT_ON_JOKER_CREATED, // Triggers only once when the Joker is created, mainly used for data initialization JOKER_EVENT_ON_JOKER_CREATED, // Triggers only once when the Joker is created, mainly used for
JOKER_EVENT_ON_HAND_PLAYED, // Triggers only once when the hand is played and before the cards are scored // data initialization
JOKER_EVENT_ON_CARD_SCORED, // Triggers when a played card scores (e.g. Walkie Talkie, Fibonnacci...) JOKER_EVENT_ON_HAND_PLAYED, // Triggers only once when the hand is played and before the cards
JOKER_EVENT_ON_CARD_SCORED_END, // Triggers after the card has finishd scoring (e.g. retrigger Jokers) // are scored
JOKER_EVENT_ON_CARD_SCORED, // Triggers when a played card scores (e.g. Walkie Talkie,
// Fibonnacci...)
JOKER_EVENT_ON_CARD_SCORED_END, // Triggers after the card has finishd scoring (e.g. retrigger
// Jokers)
JOKER_EVENT_ON_CARD_HELD, // Triggers when going through held cards JOKER_EVENT_ON_CARD_HELD, // Triggers when going through held cards
JOKER_EVENT_INDEPENDENT, // Joker will trigger normally, when Jokers are scored (e.g. base Joker) JOKER_EVENT_INDEPENDENT, // Joker will trigger normally, when Jokers are scored (e.g. base
JOKER_EVENT_ON_HAND_SCORED_END, // Triggers when entire hand has finished scoring (e.g. food Jokers) // Joker)
JOKER_EVENT_ON_HAND_SCORED_END, // Triggers when entire hand has finished scoring (e.g. food
// Jokers)
JOKER_EVENT_ON_HAND_DISCARDED, // Triggers when discarding a hand JOKER_EVENT_ON_HAND_DISCARDED, // Triggers when discarding a hand
JOKER_EVENT_ON_ROUND_END, // Triggers at the end of the round (e.g. Rocket) JOKER_EVENT_ON_ROUND_END, // Triggers at the end of the round (e.g. Rocket)
JOKER_EVENT_ON_BLIND_SELECTED, // Triggers when selecting a blind (e.g. Dagger, Riff Raff, Madness..) JOKER_EVENT_ON_BLIND_SELECTED, // Triggers when selecting a blind (e.g. Dagger, Riff Raff,
// Madness..)
}; };
// These are flags that can be combined into a single u32 and returned by // These are flags that can be combined into a single u32 and returned by
@@ -92,14 +100,15 @@ typedef struct
u8 value; u8 value;
u8 rarity; u8 rarity;
// General purpose values that are interpreted differently for each Joker (scaling, last retriggered card, etc...) // General purpose values that are interpreted differently for each Joker (scaling, last
// retriggered card, etc...)
s32 scoring_state; s32 scoring_state;
s32 persistent_state; s32 persistent_state;
} Joker; } Joker;
typedef struct JokerObject typedef struct JokerObject
{ {
Joker *joker; Joker* joker;
SpriteObject* sprite_object; SpriteObject* sprite_object;
} JokerObject; } JokerObject;
@@ -109,16 +118,25 @@ typedef struct // These jokers are triggered after the played hand has finished
u32 mult; u32 mult;
u32 xmult; u32 xmult;
int money; int money;
bool retrigger; // Retrigger played hand (e.g. "Dusk" joker, even though on the wiki it says "On Scored" it makes more sense to have it here) bool retrigger; // Retrigger played hand (e.g. "Dusk" joker, even though on the wiki it says "On
bool expire; // Will make the Joker expire/destry itself if true (i.e. Bananas and fully consumed Food Jokers) // Scored" it makes more sense to have it here)
bool expire; // Will make the Joker expire/destry itself if true (i.e. Bananas and fully
// consumed Food Jokers)
char* message; // Used to send custom messages e.g. "Extinct!" or "Again!" char* message; // Used to send custom messages e.g. "Extinct!" or "Again!"
} JokerEffect; } JokerEffect;
// JokerEffectFuncs take in a joker that will be scored, a scored_card that is not NULL when related to the given joker_event, and output a joker_effect storing the effects of the scored joker // JokerEffectFuncs take in a joker that will be scored, a scored_card that is not NULL when related
// They return a set of flags indicating what fields of the joker_effect are valid to access // to the given joker_event, and output a joker_effect storing the effects of the scored joker They
typedef u32 (*JokerEffectFunc)(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect); // return a set of flags indicating what fields of the joker_effect are valid to access
typedef u32 (*JokerEffectFunc)(
Joker* joker,
Card* scored_card,
enum JokerEvent joker_event,
JokerEffect** joker_effect
);
typedef struct { typedef struct
{
u8 rarity; u8 rarity;
u8 base_value; u8 base_value;
JokerEffectFunc joker_effect_func; JokerEffectFunc joker_effect_func;
@@ -128,23 +146,35 @@ size_t get_joker_registry_size(void);
void joker_init(); void joker_init();
Joker *joker_new(u8 id); Joker* joker_new(u8 id);
void joker_destroy(Joker **joker); void joker_destroy(Joker** joker);
// Unique effects like "Four Fingers" or "Credit Card" will be hard coded into game.c with a conditional check for the joker ID from the players owned jokers // Unique effects like "Four Fingers" or "Credit Card" will be hard coded into game.c with a
// game.c should probably be restructured so most of the variables in it are moved to some sort of global variable header file so they can be easily accessed and modified for the jokers // conditional check for the joker ID from the players owned jokers game.c should probably be
u32 joker_get_score_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect); // restructured so most of the variables in it are moved to some sort of global variable header file
// so they can be easily accessed and modified for the jokers
u32 joker_get_score_effect(
Joker* joker,
Card* scored_card,
enum JokerEvent joker_event,
JokerEffect** joker_effect
);
int joker_get_sell_value(const Joker* joker); int joker_get_sell_value(const Joker* joker);
JokerObject *joker_object_new(Joker *joker); JokerObject* joker_object_new(Joker* joker);
void joker_object_destroy(JokerObject **joker_object); void joker_object_destroy(JokerObject** joker_object);
void joker_object_update(JokerObject *joker_object); void joker_object_update(JokerObject* joker_object);
// This doesn't actually score anything, it just performs an animation and plays a sound effect // This doesn't actually score anything, it just performs an animation and plays a sound effect
void joker_object_shake(JokerObject *joker_object, mm_word sound_id); void joker_object_shake(JokerObject* joker_object, mm_word sound_id);
// This scores the joker and returns true if it was scored successfully // This scores the joker and returns true if it was scored successfully
// card_object = NULL means the joker_event does not concern a particular Card, i.e. Independend or On_Blind_Selected // card_object = NULL means the joker_event does not concern a particular Card, i.e. Independend or
// as opposed to events that concern a particular card, i.e. On_Card_Scored or On_Card_Held // On_Blind_Selected as opposed to events that concern a particular card, i.e. On_Card_Scored or
bool joker_object_score(JokerObject *joker_object, CardObject* card_object, enum JokerEvent joker_event); // On_Card_Held
bool joker_object_score(
JokerObject* joker_object,
CardObject* card_object,
enum JokerEvent joker_event
);
void joker_object_set_selected(JokerObject* joker_object, bool selected); void joker_object_set_selected(JokerObject* joker_object, bool selected);
bool joker_object_is_selected(JokerObject* joker_object); bool joker_object_is_selected(JokerObject* joker_object);
+2
View File
@@ -1,3 +1,4 @@
// clang-format off
#ifndef JOKER_GFX_H #ifndef JOKER_GFX_H
#define JOKER_GFX_H #define JOKER_GFX_H
@@ -29,3 +30,4 @@
#include "joker_gfx25.h" #include "joker_gfx25.h"
#endif #endif
// clang-format on
+11 -5
View File
@@ -10,11 +10,18 @@ typedef struct SelectionGridRow SelectionGridRow;
typedef struct SelectionGrid SelectionGrid; typedef struct SelectionGrid SelectionGrid;
// Called whenever there is a change in the selection cursor // Called whenever there is a change in the selection cursor
// row_idx is the index of the row whose function is invoked - can be used to identify whether it is the previous or new selection row. // row_idx is the index of the row whose function is invoked - can be used to identify whether it is
typedef void (*RowOnSelectionChangedFunc)(SelectionGrid* selection_grid, int row_idx, const Selection* prev_selection, const Selection* new_selection); // the previous or new selection row.
typedef void (*RowOnSelectionChangedFunc)(
SelectionGrid* selection_grid,
int row_idx,
const Selection* prev_selection,
const Selection* new_selection
);
typedef int (*RowGetSizeFunc)(); typedef int (*RowGetSizeFunc)();
// Called for any non-directional key hit // Called for any non-directional key hit
// The key will not be passed, the function will have to check key_hit() etc. for the key it wants to check // The key will not be passed, the function will have to check key_hit() etc. for the key it wants
// to check
typedef void (*RowOnKeyTransitFunc)(SelectionGrid* selection_grid, Selection* selection); typedef void (*RowOnKeyTransitFunc)(SelectionGrid* selection_grid, Selection* selection);
struct SelectionGridRow struct SelectionGridRow
@@ -30,8 +37,7 @@ struct SelectionGrid
const SelectionGridRow* rows; const SelectionGridRow* rows;
const int num_rows; const int num_rows;
Selection selection; Selection selection;
}; };
void selection_grid_process_input(SelectionGrid* selection_grid); void selection_grid_process_input(SelectionGrid* selection_grid);
+2 -1
View File
@@ -45,7 +45,8 @@ static Blind _blind_type_map[BLIND_TYPE_MAX] = {
static void s_blind_gfx_init(enum BlindType type); static void s_blind_gfx_init(enum BlindType type);
GBLA_UNUSED void blind_set_boss_graphics(const unsigned int* tiles, const u16* palette) GBLA_UNUSED
void blind_set_boss_graphics(const unsigned int* tiles, const u16* palette)
{ {
// TODO: This function is unused and not fully fleshed out. // TODO: This function is unused and not fully fleshed out.
// We need to support more boss blind graphics in the future. // We need to support more boss blind graphics in the future.
+149 -125
View File
@@ -1,38 +1,35 @@
#include <tonc.h>
#include "joker.h" #include "joker.h"
#include "joker_gfx.h"
#include "graphic_utils.h"
#include "card.h" #include "card.h"
#include "graphic_utils.h"
#include "joker_gfx.h"
#include "pool.h"
#include "soundbank.h" #include "soundbank.h"
#include "util.h" #include "util.h"
#include <maxmod.h> #include <maxmod.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <tonc.h>
#include "pool.h"
#define JOKER_SCORE_TEXT_Y 48 #define JOKER_SCORE_TEXT_Y 48
#define HELD_CARD_SCORE_TEXT_Y 108 #define HELD_CARD_SCORE_TEXT_Y 108
#define MAX_CARD_SCORE_STR_LEN 2 #define MAX_CARD_SCORE_STR_LEN 2
#define NUM_JOKERS_PER_SPRITESHEET 2 #define NUM_JOKERS_PER_SPRITESHEET 2
static const unsigned int *joker_gfxTiles[] = static const unsigned int* joker_gfxTiles[] = {
{
#define DEF_JOKER_GFX(idx) joker_gfx##idx##Tiles, #define DEF_JOKER_GFX(idx) joker_gfx##idx##Tiles,
#include "../include/def_joker_gfx_table.h" #include "../include/def_joker_gfx_table.h"
#undef DEF_JOKER_GFX #undef DEF_JOKER_GFX
}; };
static const unsigned short *joker_gfxPal[] =
{ static const unsigned short* joker_gfxPal[] = {
#define DEF_JOKER_GFX(idx) joker_gfx##idx##Pal, #define DEF_JOKER_GFX(idx) joker_gfx##idx##Pal,
#include "../include/def_joker_gfx_table.h" #include "def_joker_gfx_table.h"
#undef DEF_JOKER_GFX #undef DEF_JOKER_GFX
}; };
const static u8 edition_price_lut[MAX_EDITIONS] = const static u8 edition_price_lut[MAX_EDITIONS] = {
{
0, // BASE_EDITION 0, // BASE_EDITION
2, // FOIL_EDITION 2, // FOIL_EDITION
3, // HOLO_EDITION 3, // HOLO_EDITION
@@ -42,104 +39,45 @@ const static u8 edition_price_lut[MAX_EDITIONS] =
/* So for the card objects, I needed them to be properly sorted /* So for the card objects, I needed them to be properly sorted
which is why they let you specify the layer index when creating a new card object. which is why they let you specify the layer index when creating a new card object.
Since the cards would overlap a lot in your hand, If they weren't sorted properly, it would look like a mess. Since the cards would overlap a lot in your hand, If they weren't sorted properly, it would look
The joker objects are functionally identical to card objects, so they use the same logic. like a mess. The joker objects are functionally identical to card objects, so they use the same
But I'm going to use a simpler approach for the joker objects logic. But I'm going to use a simpler approach for the joker objects since I'm lazy and sorting
since I'm lazy and sorting them wouldn't look good enough to warrant the effort. them wouldn't look good enough to warrant the effort.
*/ */
static bool used_layers[MAX_JOKER_OBJECTS] = {false}; // Track used layers for joker sprites static bool _used_layers[MAX_JOKER_OBJECTS] = {false}; // Track used layers for joker sprites
// TODO: Refactor sorting into SpriteObject? // TODO: Refactor sorting into SpriteObject?
// Maps the spritesheet index to the palette bank index allocated to it. // Maps the spritesheet index to the palette bank index allocated to it.
// Spritesheets that were not allocated are // Spritesheets that were not allocated are
static int joker_spritesheet_pb_map[(MAX_DEFINABLE_JOKERS + 1) / NUM_JOKERS_PER_SPRITESHEET]; 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 _joker_pb_num_sprite_users[JOKER_LAST_PB - JOKER_BASE_PB + 1] = {0};
static int get_num_spritesheets() static int s_get_num_spritesheets(void);
{ static int s_joker_get_spritesheet_idx(u8 joker_id);
return (get_joker_registry_size() + NUM_JOKERS_PER_SPRITESHEET - 1) / NUM_JOKERS_PER_SPRITESHEET; static void s_joker_pb_add_sprite_user(int pb);
} static void s_joker_pb_remove_sprite_user(int pb);
static int s_joker_pb_get_num_sprite_users(int joker_pb);
static int joker_get_spritesheet_idx(u8 joker_id) static int s_get_unused_joker_pb(void);
static int s_allocate_pb_if_needed(u8 joker_id);
{
return joker_id / NUM_JOKERS_PER_SPRITESHEET;
}
// TODO: This should be generalized so any sprite can have dynamic swapping
static void joker_pb_add_sprite_user(int pb)
{
joker_pb_num_sprite_users[pb - JOKER_BASE_PB]++;
}
static void joker_pb_remove_sprite_user(int pb)
{
int num_sprite_users = joker_pb_num_sprite_users[pb - JOKER_BASE_PB];
joker_pb_num_sprite_users[pb - JOKER_BASE_PB] = max(0, num_sprite_users - 1);
}
static int joker_pb_get_num_sprite_users(int joker_pb)
{
return joker_pb_num_sprite_users[joker_pb - JOKER_BASE_PB];
}
static int get_unused_joker_pb()
{
for (int i = 0; i < NUM_ELEM_IN_ARR(joker_pb_num_sprite_users); i++)
{
if (joker_pb_num_sprite_users[i] == 0)
{
return (i + JOKER_BASE_PB);
}
}
return UNDEFINED;
}
static int allocate_pb_if_needed(u8 joker_id)
{
int joker_spritesheet_idx = joker_get_spritesheet_idx(joker_id);
int joker_pb = joker_spritesheet_pb_map[joker_spritesheet_idx];
if (joker_pb != UNDEFINED)
{
// Already allocated
return joker_pb;
}
// Allocate a new palette
joker_pb = get_unused_joker_pb();
if (joker_pb == UNDEFINED)
{
// Ran out of palettes, default to base and pray
joker_pb = JOKER_BASE_PB;
}
else
{
joker_spritesheet_pb_map[joker_spritesheet_idx] = joker_pb;
memcpy16(&pal_obj_mem[PAL_ROW_LEN * joker_pb], joker_gfxPal[joker_spritesheet_idx], NUM_ELEM_IN_ARR(joker_gfx0Pal));
}
return joker_pb;
}
void joker_init() void joker_init()
{ {
// This should init once only so no need to free // This should init once only so no need to free
int num_spritesheets = get_num_spritesheets(); int num_spritesheets = s_get_num_spritesheets();
for (int i = 0; i < num_spritesheets; i++) for (int i = 0; i < num_spritesheets; i++)
{ {
joker_spritesheet_pb_map[i] = UNDEFINED; _joker_spritesheet_pb_map[i] = UNDEFINED;
} }
} }
Joker *joker_new(u8 id) Joker* joker_new(u8 id)
{ {
if (id >= get_joker_registry_size()) return NULL; if (id >= get_joker_registry_size())
return NULL;
Joker *joker = POOL_GET(Joker); Joker* joker = POOL_GET(Joker);
const JokerInfo *jinfo = get_joker_registry_entry(id); const JokerInfo* jinfo = get_joker_registry_entry(id);
joker->id = id; joker->id = id;
joker->modifier = BASE_EDITION; // TODO: Make this a parameter joker->modifier = BASE_EDITION; // TODO: Make this a parameter
@@ -149,22 +87,28 @@ Joker *joker_new(u8 id)
joker->persistent_state = 0; joker->persistent_state = 0;
// initialize persistent Joker data if needed // initialize persistent Joker data if needed
JokerEffect *joker_effect = NULL; JokerEffect* joker_effect = NULL;
jinfo->joker_effect_func(joker, NULL, JOKER_EVENT_ON_JOKER_CREATED, &joker_effect); jinfo->joker_effect_func(joker, NULL, JOKER_EVENT_ON_JOKER_CREATED, &joker_effect);
return joker; return joker;
} }
void joker_destroy(Joker **joker) void joker_destroy(Joker** joker)
{ {
POOL_FREE(Joker, *joker); POOL_FREE(Joker, *joker);
*joker = NULL; *joker = NULL;
} }
u32 joker_get_score_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) u32 joker_get_score_effect(
Joker* joker,
Card* scored_card,
enum JokerEvent joker_event,
JokerEffect** joker_effect
)
{ {
const JokerInfo *jinfo = get_joker_registry_entry(joker->id); const JokerInfo* jinfo = get_joker_registry_entry(joker->id);
if (!jinfo) return JOKER_EFFECT_FLAG_NONE; if (!jinfo)
return JOKER_EFFECT_FLAG_NONE;
return jinfo->joker_effect_func(joker, scored_card, joker_event, joker_effect); return jinfo->joker_effect_func(joker, scored_card, joker_event, joker_effect);
} }
@@ -176,21 +120,21 @@ int joker_get_sell_value(const Joker* joker)
return UNDEFINED; return UNDEFINED;
} }
return joker->value/2; return joker->value / 2;
} }
// JokerObject methods // JokerObject methods
JokerObject *joker_object_new(Joker *joker) JokerObject* joker_object_new(Joker* joker)
{ {
JokerObject *joker_object = POOL_GET(JokerObject); JokerObject* joker_object = POOL_GET(JokerObject);
int layer = 0; int layer = 0;
for (int i = 0; i < MAX_JOKER_OBJECTS; i++) for (int i = 0; i < MAX_JOKER_OBJECTS; i++)
{ {
if (!used_layers[i]) if (!_used_layers[i])
{ {
layer = i; layer = i;
used_layers[i] = true; // Mark this layer as used _used_layers[i] = true; // Mark this layer as used
break; break;
} }
} }
@@ -200,18 +144,20 @@ JokerObject *joker_object_new(Joker *joker)
int tile_index = JOKER_TID + (layer * JOKER_SPRITE_OFFSET); int tile_index = JOKER_TID + (layer * JOKER_SPRITE_OFFSET);
int joker_spritesheet_idx = joker_get_spritesheet_idx(joker->id); int joker_spritesheet_idx = s_joker_get_spritesheet_idx(joker->id);
int joker_idx = joker->id % NUM_JOKERS_PER_SPRITESHEET; int joker_idx = joker->id % NUM_JOKERS_PER_SPRITESHEET;
int joker_pb = allocate_pb_if_needed(joker->id); int joker_pb = s_allocate_pb_if_needed(joker->id);
joker_pb_add_sprite_user(joker_pb); s_joker_pb_add_sprite_user(joker_pb);
memcpy32(&tile_mem[4][tile_index], &joker_gfxTiles[joker_spritesheet_idx][joker_idx * TILE_SIZE * JOKER_SPRITE_OFFSET], TILE_SIZE * JOKER_SPRITE_OFFSET); memcpy32(
&tile_mem[4][tile_index],
&joker_gfxTiles[joker_spritesheet_idx][joker_idx * TILE_SIZE * JOKER_SPRITE_OFFSET],
TILE_SIZE * JOKER_SPRITE_OFFSET
);
sprite_object_set_sprite sprite_object_set_sprite(
(
joker_object->sprite_object, joker_object->sprite_object,
sprite_new sprite_new(
(
ATTR0_SQUARE | ATTR0_4BPP | ATTR0_AFF, ATTR0_SQUARE | ATTR0_4BPP | ATTR0_AFF,
ATTR1_SIZE_32, ATTR1_SIZE_32,
tile_index, tile_index,
@@ -220,21 +166,22 @@ JokerObject *joker_object_new(Joker *joker)
) )
); );
return joker_object; return joker_object;
} }
void joker_object_destroy(JokerObject **joker_object) void joker_object_destroy(JokerObject** joker_object)
{ {
if (joker_object == NULL || *joker_object == NULL) return; if (joker_object == NULL || *joker_object == NULL)
return;
int layer = sprite_get_layer(joker_object_get_sprite(*joker_object)) - JOKER_STARTING_LAYER; int layer = sprite_get_layer(joker_object_get_sprite(*joker_object)) - JOKER_STARTING_LAYER;
used_layers[layer] = false; _used_layers[layer] = false;
joker_pb_remove_sprite_user(sprite_get_pb(joker_object_get_sprite(*joker_object))); s_joker_pb_remove_sprite_user(sprite_get_pb(joker_object_get_sprite(*joker_object)));
if (joker_pb_get_num_sprite_users((sprite_get_pb(joker_object_get_sprite(*joker_object)))) == 0) if (s_joker_pb_get_num_sprite_users((sprite_get_pb(joker_object_get_sprite(*joker_object)))) ==
0)
{ {
joker_spritesheet_pb_map[joker_get_spritesheet_idx((*joker_object)->joker->id)] = UNDEFINED; _joker_spritesheet_pb_map[s_joker_get_spritesheet_idx((*joker_object)->joker->id)] =
UNDEFINED;
} }
sprite_object_destroy(&(*joker_object)->sprite_object); // Destroy the sprite sprite_object_destroy(&(*joker_object)->sprite_object); // Destroy the sprite
@@ -243,13 +190,13 @@ void joker_object_destroy(JokerObject **joker_object)
*joker_object = NULL; *joker_object = NULL;
} }
void joker_object_update(JokerObject *joker_object) void joker_object_update(JokerObject* joker_object)
{ {
CardObject *card_object = (CardObject *)joker_object; CardObject* card_object = (CardObject*)joker_object;
card_object_update(card_object); card_object_update(card_object);
} }
void joker_object_shake(JokerObject *joker_object, mm_word sound_id) void joker_object_shake(JokerObject* joker_object, mm_word sound_id)
{ {
sprite_object_shake(joker_object->sprite_object, sound_id); sprite_object_shake(joker_object->sprite_object, sound_id);
} }
@@ -265,7 +212,11 @@ void set_and_shift_text(char* str, int* cursor_pos_x, int* cursor_pos_y, int col
*cursor_pos_x += joker_score_display_offset_px; *cursor_pos_x += joker_score_display_offset_px;
} }
bool joker_object_score(JokerObject *joker_object, CardObject* card_object, enum JokerEvent joker_event) bool joker_object_score(
JokerObject* joker_object,
CardObject* card_object,
enum JokerEvent joker_event
)
{ {
if (joker_object == NULL) if (joker_object == NULL)
{ {
@@ -273,7 +224,8 @@ bool joker_object_score(JokerObject *joker_object, CardObject* card_object, enum
} }
JokerEffect* joker_effect = NULL; JokerEffect* joker_effect = NULL;
u32 effect_flags_ret = joker_get_score_effect(joker_object->joker, card_object->card, joker_event, &joker_effect); u32 effect_flags_ret =
joker_get_score_effect(joker_object->joker, card_object->card, joker_event, &joker_effect);
if (effect_flags_ret == JOKER_EFFECT_FLAG_NONE) if (effect_flags_ret == JOKER_EFFECT_FLAG_NONE)
{ {
@@ -405,10 +357,82 @@ int joker_get_random_rarity()
{ {
joker_rarity = RARE_JOKER; joker_rarity = RARE_JOKER;
} }
else if (rarity_roll < COMMON_JOKER_CHANCE + UNCOMMON_JOKER_CHANCE + RARE_JOKER_CHANCE + LEGENDARY_JOKER_CHANCE) else if (rarity_roll < COMMON_JOKER_CHANCE + UNCOMMON_JOKER_CHANCE + RARE_JOKER_CHANCE +
LEGENDARY_JOKER_CHANCE)
{ {
joker_rarity = LEGENDARY_JOKER; joker_rarity = LEGENDARY_JOKER;
} }
return joker_rarity; return joker_rarity;
} }
static int s_get_num_spritesheets()
{
return (get_joker_registry_size() + NUM_JOKERS_PER_SPRITESHEET - 1) /
NUM_JOKERS_PER_SPRITESHEET;
}
static int s_joker_get_spritesheet_idx(u8 joker_id)
{
return joker_id / NUM_JOKERS_PER_SPRITESHEET;
}
static void s_joker_pb_add_sprite_user(int pb)
{
_joker_pb_num_sprite_users[pb - JOKER_BASE_PB]++;
}
static void s_joker_pb_remove_sprite_user(int pb)
{
int num_sprite_users = _joker_pb_num_sprite_users[pb - JOKER_BASE_PB];
_joker_pb_num_sprite_users[pb - JOKER_BASE_PB] = max(0, num_sprite_users - 1);
}
static int s_joker_pb_get_num_sprite_users(int joker_pb)
{
return _joker_pb_num_sprite_users[joker_pb - JOKER_BASE_PB];
}
static int s_get_unused_joker_pb()
{
for (int i = 0; i < NUM_ELEM_IN_ARR(_joker_pb_num_sprite_users); i++)
{
if (_joker_pb_num_sprite_users[i] == 0)
{
return (i + JOKER_BASE_PB);
}
}
return UNDEFINED;
}
static int s_allocate_pb_if_needed(u8 joker_id)
{
int joker_spritesheet_idx = s_joker_get_spritesheet_idx(joker_id);
int joker_pb = _joker_spritesheet_pb_map[joker_spritesheet_idx];
if (joker_pb != UNDEFINED)
{
// Already allocated
return joker_pb;
}
// Allocate a new palette
joker_pb = s_get_unused_joker_pb();
if (joker_pb == UNDEFINED)
{
// Ran out of palettes, default to base and pray
joker_pb = JOKER_BASE_PB;
}
else
{
_joker_spritesheet_pb_map[joker_spritesheet_idx] = joker_pb;
memcpy16(
&pal_obj_mem[PAL_ROW_LEN * joker_pb],
joker_gfxPal[joker_spritesheet_idx],
NUM_ELEM_IN_ARR(joker_gfx0Pal)
);
}
return joker_pb;
}
+1704 -1151
View File
File diff suppressed because it is too large Load Diff
+25 -16
View File
@@ -1,18 +1,18 @@
#include <tonc.h> #include "affine_background.h"
#include <maxmod.h> #include "blind.h"
#include <string.h>
#include "sprite.h"
#include "card.h" #include "card.h"
#include "game.h" #include "game.h"
#include "blind.h"
#include "joker.h"
#include "affine_background.h"
#include "graphic_utils.h" #include "graphic_utils.h"
#include "joker.h"
#include "sprite.h"
#include <maxmod.h>
#include <string.h>
#include <tonc.h>
// Graphics // Graphics
#include "background_gfx.h"
#include "affine_background_gfx.h" #include "affine_background_gfx.h"
#include "background_gfx.h"
// Audio // Audio
#include "soundbank.h" #include "soundbank.h"
@@ -25,7 +25,15 @@ void init()
irq_add(II_HBLANK, affine_background_hblank); irq_add(II_HBLANK, affine_background_hblank);
// Initialize text engine // Initialize text engine
tte_init_se(0, BG_CBB(TTE_CBB) | BG_SBB(TTE_SBB), 0, CLR_WHITE, TTE_BIT_UNPACK_OFFSET, NULL, NULL); tte_init_se(
0,
BG_CBB(TTE_CBB) | BG_SBB(TTE_SBB),
0,
CLR_WHITE,
TTE_BIT_UNPACK_OFFSET,
NULL,
NULL
);
tte_erase_screen(); tte_erase_screen();
tte_init_con(); tte_init_con();
@@ -53,20 +61,21 @@ void init()
int win2_right = 232; int win2_right = 232;
int win2_bottom = 44; int win2_bottom = 44;
REG_WIN0H = win1_left<<8 | win1_right; REG_WIN0H = win1_left << 8 | win1_right;
REG_WIN0V = win1_top<<8 | win1_bottom; REG_WIN0V = win1_top << 8 | win1_bottom;
REG_WIN0CNT = WIN_ALL | WIN_BLD; REG_WIN0CNT = WIN_ALL | WIN_BLD;
REG_WINOUTCNT = WIN_ALL; REG_WINOUTCNT = WIN_ALL;
REG_WIN1H = win2_left<<8 | win2_right; REG_WIN1H = win2_left << 8 | win2_right;
REG_WIN1V = win2_top<<8 | win2_bottom; REG_WIN1V = win2_top << 8 | win2_bottom;
REG_WIN1CNT = WIN_ALL | WIN_BLD; REG_WIN1CNT = WIN_ALL | WIN_BLD;
REG_BLDCNT = BLD_BUILD(BLD_BG1, BLD_BG2, 1); REG_BLDCNT = BLD_BUILD(BLD_BG1, BLD_BG2, 1);
REG_BLDALPHA = BLDA_BUILD(0, 13); REG_BLDALPHA = BLDA_BUILD(0, 13);
REG_DISPCNT = DCNT_MODE1 | DCNT_OBJ_1D | DCNT_BG0 | DCNT_BG1 | DCNT_BG2 | DCNT_OBJ | DCNT_WIN0 | DCNT_WIN1; REG_DISPCNT = DCNT_MODE1 | DCNT_OBJ_1D | DCNT_BG0 | DCNT_BG1 | DCNT_BG2 | DCNT_OBJ | DCNT_WIN0 |
DCNT_WIN1;
// Initialize subsystems // Initialize subsystems
mmInitDefault((mm_addr)soundbank_bin, 12); mmInitDefault((mm_addr)soundbank_bin, 12);
@@ -94,7 +103,7 @@ int main()
{ {
init(); init();
while(true) while (true)
{ {
VBlankIntrWait(); VBlankIntrWait();
mmFrame(); mmFrame();
+2 -1
View File
@@ -6,4 +6,5 @@
#define GIT_DIRTY "-dirty" #define GIT_DIRTY "-dirty"
#endif #endif
__attribute__((section(".version"), used)) const char balatro_version[] = "GBALATRO_VERSION:" GIT_HASH GIT_DIRTY; __attribute__((section(".version"), used)) const char balatro_version[] =
"GBALATRO_VERSION:" GIT_HASH GIT_DIRTY;