From 2fb9e6d633cfcec81b434fe7b856d0970dd29568 Mon Sep 17 00:00:00 2001 From: Rickey Date: Tue, 9 Dec 2025 23:41:24 -0800 Subject: [PATCH] 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 --- .../workflows/clang_format_ci_workflow.yml | 19 +- include/def_balatro_mempool.h | 4 +- include/def_joker_gfx_table.h | 2 +- include/def_state_info_table.h | 2 + include/joker.h | 138 +- include/joker_gfx.h | 4 +- include/selection_grid.h | 20 +- source/blind.c | 3 +- source/joker.c | 308 +- source/joker_effects.c | 2859 ++++++++++------- source/main.c | 55 +- source/version.c | 3 +- 12 files changed, 2014 insertions(+), 1403 deletions(-) diff --git a/.github/workflows/clang_format_ci_workflow.yml b/.github/workflows/clang_format_ci_workflow.yml index 73b3df6..40ab941 100644 --- a/.github/workflows/clang_format_ci_workflow.yml +++ b/.github/workflows/clang_format_ci_workflow.yml @@ -17,21 +17,4 @@ jobs: uses: actions/checkout@v5 - name: Run clang-format - run: > - 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 + run: clang-format --dry-run -Werror include/*.h source/*.c diff --git a/include/def_balatro_mempool.h b/include/def_balatro_mempool.h index 99b887f..1483d79 100644 --- a/include/def_balatro_mempool.h +++ b/include/def_balatro_mempool.h @@ -1,7 +1,7 @@ -#include "sprite.h" -#include "joker.h" #include "card.h" +#include "joker.h" #include "list.h" +#include "sprite.h" POOL_ENTRY(Sprite, MAX_SPRITES); POOL_ENTRY(SpriteObject, MAX_SPRITE_OBJECTS); diff --git a/include/def_joker_gfx_table.h b/include/def_joker_gfx_table.h index a71d523..c43e82b 100644 --- a/include/def_joker_gfx_table.h +++ b/include/def_joker_gfx_table.h @@ -23,4 +23,4 @@ DEF_JOKER_GFX(21) DEF_JOKER_GFX(22) DEF_JOKER_GFX(23) DEF_JOKER_GFX(24) -DEF_JOKER_GFX(25) \ No newline at end of file +DEF_JOKER_GFX(25) diff --git a/include/def_state_info_table.h b/include/def_state_info_table.h index 89693a2..616eb96 100644 --- a/include/def_state_info_table.h +++ b/include/def_state_info_table.h @@ -1,3 +1,4 @@ +// clang-format off // (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_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_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) +// clang-format on diff --git a/include/joker.h b/include/joker.h index 7abd765..0460d23 100644 --- a/include/joker.h +++ b/include/joker.h @@ -1,12 +1,12 @@ #ifndef JOKER_H #define JOKER_H -#include - -#include "sprite.h" #include "card.h" #include "game.h" #include "graphic_utils.h" +#include "sprite.h" + +#include // 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... @@ -14,51 +14,59 @@ #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_BASE_PB 4 // The starting palette index for the jokers -#define JOKER_LAST_PB (NUM_PALETTES - 1) +#define JOKER_BASE_PB 4 // The starting palette index for the jokers +#define JOKER_LAST_PB (NUM_PALETTES - 1) // Currently allocating the rest of the palettes for the jokers. // This number needs to be decreased once we need to allocated palettes for other sprites // such as planet cards etc. #define JOKER_STARTING_LAYER 27 -#define BASE_EDITION 0 -#define FOIL_EDITION 1 -#define HOLO_EDITION 2 -#define POLY_EDITION 3 +#define BASE_EDITION 0 +#define FOIL_EDITION 1 +#define HOLO_EDITION 2 +#define POLY_EDITION 3 #define NEGATIVE_EDITION 4 #define MAX_EDITIONS 5 -#define COMMON_JOKER 0 -#define UNCOMMON_JOKER 1 -#define RARE_JOKER 2 +#define COMMON_JOKER 0 +#define UNCOMMON_JOKER 1 +#define RARE_JOKER 2 #define LEGENDARY_JOKER 3 // Percent chance to get a joker of each rarity // Note that this deviates slightly from the Balatro wiki to allow legendary // jokers to appear without spectral cards implemented -#define COMMON_JOKER_CHANCE 70 -#define UNCOMMON_JOKER_CHANCE 25 -#define RARE_JOKER_CHANCE 5 +#define COMMON_JOKER_CHANCE 70 +#define UNCOMMON_JOKER_CHANCE 25 +#define RARE_JOKER_CHANCE 5 #define LEGENDARY_JOKER_CHANCE 0 // These are the common Joker Events. Special Joker behaviour will be checked on a // Joker per Joker basis (see if it's there, then do something, e.g. Pareidolia, Baseball Card) enum JokerEvent { - JOKER_EVENT_ON_JOKER_CREATED, // Triggers only once when the Joker is created, mainly used for data initialization - JOKER_EVENT_ON_HAND_PLAYED, // Triggers only once when the hand is played and before the cards 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_JOKER_CREATED, // Triggers only once when the Joker is created, mainly used for + // data initialization + JOKER_EVENT_ON_HAND_PLAYED, // Triggers only once when the hand is played and before the cards + // 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_INDEPENDENT, // Joker will trigger normally, when Jokers are scored (e.g. base Joker) - JOKER_EVENT_ON_HAND_SCORED_END, // Triggers when entire hand has finished scoring (e.g. food Jokers) + JOKER_EVENT_INDEPENDENT, // Joker will trigger normally, when Jokers are scored (e.g. base + // 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_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 @@ -76,49 +84,59 @@ enum JokerEvent #define MAX_JOKER_OBJECTS 32 // The maximum number of joker objects that can be created at once // Jokers in the game -#define DEFAULT_JOKER_ID 0 -#define GREEDY_JOKER_ID 1 -#define STENCIL_JOKER_ID 16 -#define SHORTCUT_JOKER_ID 26 -#define PAREIDOLIA_JOKER_ID 30 -#define BLUEPRINT_JOKER_ID 39 -#define BRAINSTORM_JOKER_ID 40 +#define DEFAULT_JOKER_ID 0 +#define GREEDY_JOKER_ID 1 +#define STENCIL_JOKER_ID 16 +#define SHORTCUT_JOKER_ID 26 +#define PAREIDOLIA_JOKER_ID 30 +#define BLUEPRINT_JOKER_ID 39 +#define BRAINSTORM_JOKER_ID 40 #define FOUR_FINGERS_JOKER_ID 48 -typedef struct +typedef struct { - u8 id; // Unique ID for the joker, used to identify different jokers + u8 id; // Unique ID for the joker, used to identify different jokers u8 modifier; // base, foil, holo, poly, negative u8 value; 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 persistent_state; } Joker; typedef struct JokerObject { - Joker *joker; + Joker* joker; SpriteObject* sprite_object; } JokerObject; -typedef struct // These jokers are triggered after the played hand has finished scoring. +typedef struct // These jokers are triggered after the played hand has finished scoring. { u32 chips; u32 mult; u32 xmult; 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 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!" + 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 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!" } 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 -// They 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); +// 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 They +// 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 base_value; JokerEffectFunc joker_effect_func; @@ -128,23 +146,35 @@ size_t get_joker_registry_size(void); void joker_init(); -Joker *joker_new(u8 id); -void joker_destroy(Joker **joker); +Joker* joker_new(u8 id); +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 -// 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 -u32 joker_get_score_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect); +// 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 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 +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); -JokerObject *joker_object_new(Joker *joker); -void joker_object_destroy(JokerObject **joker_object); -void joker_object_update(JokerObject *joker_object); +JokerObject* joker_object_new(Joker* joker); +void joker_object_destroy(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 -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 -// card_object = NULL means the joker_event does not concern a particular Card, i.e. Independend or On_Blind_Selected -// as opposed to events that concern a particular card, i.e. On_Card_Scored or On_Card_Held -bool joker_object_score(JokerObject *joker_object, CardObject* card_object, enum JokerEvent joker_event); +// card_object = NULL means the joker_event does not concern a particular Card, i.e. Independend or +// On_Blind_Selected as opposed to events that concern a particular card, i.e. On_Card_Scored or +// 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); bool joker_object_is_selected(JokerObject* joker_object); diff --git a/include/joker_gfx.h b/include/joker_gfx.h index 69ebb35..a6f97f2 100644 --- a/include/joker_gfx.h +++ b/include/joker_gfx.h @@ -1,3 +1,4 @@ +// clang-format off #ifndef JOKER_GFX_H #define JOKER_GFX_H @@ -28,4 +29,5 @@ #include "joker_gfx24.h" #include "joker_gfx25.h" -#endif \ No newline at end of file +#endif +// clang-format on diff --git a/include/selection_grid.h b/include/selection_grid.h index 2294a38..fd80d67 100644 --- a/include/selection_grid.h +++ b/include/selection_grid.h @@ -10,18 +10,25 @@ typedef struct SelectionGridRow SelectionGridRow; typedef struct SelectionGrid SelectionGrid; // 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. -typedef void (*RowOnSelectionChangedFunc)(SelectionGrid* selection_grid, int row_idx, const Selection* prev_selection, const Selection* new_selection); +// 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. +typedef void (*RowOnSelectionChangedFunc)( + SelectionGrid* selection_grid, + int row_idx, + const Selection* prev_selection, + const Selection* new_selection +); typedef int (*RowGetSizeFunc)(); // 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); struct SelectionGridRow { int row_idx; - RowGetSizeFunc get_size; - RowOnSelectionChangedFunc on_selection_changed; + RowGetSizeFunc get_size; + RowOnSelectionChangedFunc on_selection_changed; RowOnKeyTransitFunc on_key_transit; }; @@ -30,8 +37,7 @@ struct SelectionGrid const SelectionGridRow* rows; const int num_rows; Selection selection; - }; - +}; void selection_grid_process_input(SelectionGrid* selection_grid); diff --git a/source/blind.c b/source/blind.c index 55326c1..024fa09 100644 --- a/source/blind.c +++ b/source/blind.c @@ -45,7 +45,8 @@ static Blind _blind_type_map[BLIND_TYPE_MAX] = { 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. // We need to support more boss blind graphics in the future. diff --git a/source/joker.c b/source/joker.c index 28213c9..fbc8cbf 100644 --- a/source/joker.c +++ b/source/joker.c @@ -1,38 +1,35 @@ -#include - #include "joker.h" -#include "joker_gfx.h" -#include "graphic_utils.h" + #include "card.h" +#include "graphic_utils.h" +#include "joker_gfx.h" +#include "pool.h" #include "soundbank.h" #include "util.h" #include #include #include +#include -#include "pool.h" - -#define JOKER_SCORE_TEXT_Y 48 -#define HELD_CARD_SCORE_TEXT_Y 108 -#define MAX_CARD_SCORE_STR_LEN 2 +#define JOKER_SCORE_TEXT_Y 48 +#define HELD_CARD_SCORE_TEXT_Y 108 +#define MAX_CARD_SCORE_STR_LEN 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, #include "../include/def_joker_gfx_table.h" #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, -#include "../include/def_joker_gfx_table.h" +#include "def_joker_gfx_table.h" #undef DEF_JOKER_GFX }; -const static u8 edition_price_lut[MAX_EDITIONS] = -{ +const static u8 edition_price_lut[MAX_EDITIONS] = { 0, // BASE_EDITION 2, // FOIL_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 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. - The joker objects are functionally identical to card objects, so they use the same logic. - But I'm going to use a simpler approach for the joker objects - since I'm lazy and sorting them wouldn't look good enough to warrant the effort. + Since the cards would overlap a lot in your hand, If they weren't sorted properly, it would look + like a mess. The joker objects are functionally identical to card objects, so they use the same + logic. But I'm going to use a simpler approach for the joker objects since I'm lazy and sorting + 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? // Maps the spritesheet index to the palette bank index allocated to it. // Spritesheets that were not allocated are -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_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() -{ - return (get_joker_registry_size() + NUM_JOKERS_PER_SPRITESHEET - 1) / NUM_JOKERS_PER_SPRITESHEET; -} - -static int joker_get_spritesheet_idx(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; -} +static int s_get_num_spritesheets(void); +static int s_joker_get_spritesheet_idx(u8 joker_id); +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 s_get_unused_joker_pb(void); +static int s_allocate_pb_if_needed(u8 joker_id); void joker_init() { // 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++) { - 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); - const JokerInfo *jinfo = get_joker_registry_entry(id); + Joker* joker = POOL_GET(Joker); + const JokerInfo* jinfo = get_joker_registry_entry(id); joker->id = id; joker->modifier = BASE_EDITION; // TODO: Make this a parameter @@ -149,22 +87,28 @@ Joker *joker_new(u8 id) joker->persistent_state = 0; // 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); return joker; } -void joker_destroy(Joker **joker) +void joker_destroy(Joker** joker) { POOL_FREE(Joker, *joker); *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); - if (!jinfo) return JOKER_EFFECT_FLAG_NONE; + const JokerInfo* jinfo = get_joker_registry_entry(joker->id); + if (!jinfo) + return JOKER_EFFECT_FLAG_NONE; 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 joker->value/2; + return joker->value / 2; } // 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; for (int i = 0; i < MAX_JOKER_OBJECTS; i++) { - if (!used_layers[i]) + if (!_used_layers[i]) { layer = i; - used_layers[i] = true; // Mark this layer as used + _used_layers[i] = true; // Mark this layer as used break; } } @@ -199,57 +143,60 @@ JokerObject *joker_object_new(Joker *joker) joker_object->sprite_object = sprite_object_new(); 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_pb = allocate_pb_if_needed(joker->id); - joker_pb_add_sprite_user(joker_pb); + int joker_pb = s_allocate_pb_if_needed(joker->id); + 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 - ( - joker_object->sprite_object, - sprite_new - ( - ATTR0_SQUARE | ATTR0_4BPP | ATTR0_AFF, - ATTR1_SIZE_32, - tile_index, + sprite_object_set_sprite( + joker_object->sprite_object, + sprite_new( + ATTR0_SQUARE | ATTR0_4BPP | ATTR0_AFF, + ATTR1_SIZE_32, + tile_index, joker_pb, JOKER_STARTING_LAYER + layer ) ); - - 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; - used_layers[layer] = false; - 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) + _used_layers[layer] = false; + s_joker_pb_remove_sprite_user(sprite_get_pb(joker_object_get_sprite(*joker_object))); + 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 - joker_destroy(&(*joker_object)->joker); // Destroy the joker + joker_destroy(&(*joker_object)->joker); // Destroy the joker POOL_FREE(JokerObject, *joker_object); *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); } -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); } @@ -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; } -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) { @@ -273,16 +224,17 @@ bool joker_object_score(JokerObject *joker_object, CardObject* card_object, enum } 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) { return false; } - u32 chips = get_chips(); - u32 mult = get_mult(); - int money = get_money(); + u32 chips = get_chips(); + u32 mult = get_mult(); + int money = get_money(); if (effect_flags_ret & JOKER_EFFECT_FLAG_RETRIGGER) { @@ -317,7 +269,7 @@ bool joker_object_score(JokerObject *joker_object, CardObject* card_object, enum } if (effect_flags_ret & JOKER_EFFECT_FLAG_MULT) { - mult = u32_protected_add(mult, joker_effect->mult); + mult = u32_protected_add(mult, joker_effect->mult); char score_buffer[INT_MAX_DIGITS + 2]; snprintf(score_buffer, sizeof(score_buffer), "+%lu", joker_effect->mult); set_and_shift_text(score_buffer, &cursorPosX, &cursorPosY, TTE_RED_PB); @@ -326,7 +278,7 @@ bool joker_object_score(JokerObject *joker_object, CardObject* card_object, enum // if xmult is zero, DO NOT multiply by it if (effect_flags_ret & JOKER_EFFECT_FLAG_XMULT && joker_effect->xmult > 0) { - mult = u32_protected_mult(mult, joker_effect->xmult); + mult = u32_protected_mult(mult, joker_effect->xmult); char score_buffer[INT_MAX_DIGITS + 2]; snprintf(score_buffer, sizeof(score_buffer), "X%lu", joker_effect->xmult); set_and_shift_text(score_buffer, &cursorPosX, &cursorPosY, TTE_RED_PB); @@ -392,12 +344,12 @@ Sprite* joker_object_get_sprite(JokerObject* joker_object) int joker_get_random_rarity() { int joker_rarity = 0; - int rarity_roll = random() % 100; - if (rarity_roll < COMMON_JOKER_CHANCE) + int rarity_roll = random() % 100; + if (rarity_roll < COMMON_JOKER_CHANCE) { joker_rarity = COMMON_JOKER; } - else if (rarity_roll < COMMON_JOKER_CHANCE + UNCOMMON_JOKER_CHANCE) + else if (rarity_roll < COMMON_JOKER_CHANCE + UNCOMMON_JOKER_CHANCE) { joker_rarity = UNCOMMON_JOKER; } @@ -405,10 +357,82 @@ int joker_get_random_rarity() { 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; } 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; +} diff --git a/source/joker_effects.c b/source/joker_effects.c index 3cb8285..20a475a 100644 --- a/source/joker_effects.c +++ b/source/joker_effects.c @@ -1,1169 +1,336 @@ #include "game.h" -#include "joker.h" -#include "util.h" #include "hand_analysis.h" +#include "joker.h" #include "list.h" #include "pool.h" +#include "util.h" + #include +#define MISPRINT_MAX_MULT 23 #define SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, restricted_event, checked_event) \ -if (checked_event != restricted_event || scored_card == NULL) \ -{ \ - return JOKER_EFFECT_FLAG_NONE; \ -} + if (checked_event != restricted_event || scored_card == NULL) \ + { \ + return JOKER_EFFECT_FLAG_NONE; \ + } #define SCORE_ON_EVENT_ONLY(restricted_event, checked_event) \ -if (checked_event != restricted_event) \ -{ \ - return JOKER_EFFECT_FLAG_NONE; \ -} + if (checked_event != restricted_event) \ + { \ + return JOKER_EFFECT_FLAG_NONE; \ + } static JokerEffect shared_joker_effect = {0}; // Joker Effect functions - -static u32 joker_effect_noop(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - return JOKER_EFFECT_FLAG_NONE; -} - -static u32 default_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - *joker_effect = &shared_joker_effect; - - (*joker_effect)->mult = 4; - - return JOKER_EFFECT_FLAG_MULT; -} - -static u32 sinful_joker_effect(Card *scored_card, u8 sinful_suit, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - if (scored_card->suit == sinful_suit) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->mult = 3; - effect_flags_ret = JOKER_EFFECT_FLAG_MULT; - } - return effect_flags_ret; -} - -static u32 greedy_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - return sinful_joker_effect(scored_card, DIAMONDS, joker_event, joker_effect); -} - -static u32 lusty_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - return sinful_joker_effect(scored_card, HEARTS, joker_event, joker_effect); -} - -static u32 wrathful_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - return sinful_joker_effect(scored_card, SPADES, joker_event, joker_effect); -} - -static u32 gluttonous_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - return sinful_joker_effect(scored_card, CLUBS, joker_event, joker_effect); -} - -static u32 jolly_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - // This is really inefficient but the only way at the moment to check for whole-hand conditions - u8 suits[NUM_SUITS]; - u8 ranks[NUM_RANKS]; - get_played_distribution(ranks, suits); - - if (hand_contains_n_of_a_kind(ranks) >= 2) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->mult = 8; - effect_flags_ret = JOKER_EFFECT_FLAG_MULT; - } - - return effect_flags_ret; -} - -static u32 zany_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - // This is really inefficient but the only way at the moment to check for whole-hand conditions - u8 suits[NUM_SUITS]; - u8 ranks[NUM_RANKS]; - get_played_distribution(ranks, suits); - - if (hand_contains_n_of_a_kind(ranks) >= 3) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->mult = 12; - effect_flags_ret = JOKER_EFFECT_FLAG_MULT; - } - - return effect_flags_ret; -} - -static u32 mad_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - u8 suits[NUM_SUITS]; - u8 ranks[NUM_RANKS]; - get_played_distribution(ranks, suits); - - if (hand_contains_two_pair(ranks)) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->mult = 10; - effect_flags_ret = JOKER_EFFECT_FLAG_MULT; - } - - return effect_flags_ret; -} - -static u32 crazy_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - u8 suits[NUM_SUITS]; - u8 ranks[NUM_RANKS]; - get_played_distribution(ranks, suits); - - if (hand_contains_straight(ranks)) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->mult = 12; - effect_flags_ret = JOKER_EFFECT_FLAG_MULT; - } - - return effect_flags_ret; -} - -static u32 droll_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - u8 suits[NUM_SUITS]; - u8 ranks[NUM_RANKS]; - get_played_distribution(ranks, suits); - - if (hand_contains_flush(suits)) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->mult = 10; - effect_flags_ret = JOKER_EFFECT_FLAG_MULT; - } - - return effect_flags_ret; -} - -static u32 sly_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - u8 suits[NUM_SUITS]; - u8 ranks[NUM_RANKS]; - get_played_distribution(ranks, suits); - - if (hand_contains_n_of_a_kind(ranks) >= 2) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->chips = 50; - effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS; - } - - return effect_flags_ret; -} - -static u32 wily_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - u8 suits[NUM_SUITS]; - u8 ranks[NUM_RANKS]; - get_played_distribution(ranks, suits); - - if (hand_contains_n_of_a_kind(ranks) >= 3) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->chips = 100; - effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS; - } - - return effect_flags_ret; -} - -static u32 clever_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - u8 suits[NUM_SUITS]; - u8 ranks[NUM_RANKS]; - get_played_distribution(ranks, suits); - - if (hand_contains_two_pair(ranks)) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->chips = 80; - effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS; - } - - return effect_flags_ret; -} - -static u32 devious_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - u8 suits[NUM_SUITS]; - u8 ranks[NUM_RANKS]; - get_played_distribution(ranks, suits); - - if (hand_contains_straight(ranks)) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->chips = 100; - effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS; - } - - return effect_flags_ret; -} - -static u32 crafty_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - u8 suits[NUM_SUITS]; - u8 ranks[NUM_RANKS]; - get_played_distribution(ranks, suits); - - if (hand_contains_flush(suits)) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->chips = 80; - effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS; - } - - return effect_flags_ret; -} - -static u32 half_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - int played_size = get_played_top() + 1; - if (played_size <= 3) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->mult = 20; - effect_flags_ret = JOKER_EFFECT_FLAG_MULT; - } - - return effect_flags_ret; -} - -static u32 joker_stencil_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - *joker_effect = &shared_joker_effect; - - List* jokers = get_jokers_list(); - - // +1 xmult per empty joker slot... - int num_jokers = list_get_len(jokers); - - (*joker_effect)->xmult = (MAX_JOKERS_HELD_SIZE) - num_jokers; - - // ...and also each stencil_joker adds +1 xmult - ListItr itr = list_itr_create(jokers); - JokerObject* joker_object; - - while((joker_object = list_itr_next(&itr))) - { - if (joker_object->joker->id == STENCIL_JOKER_ID) (*joker_effect)->xmult++; - } - - return JOKER_EFFECT_FLAG_XMULT; -} - -#define MISPRINT_MAX_MULT 23 -static u32 misprint_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - *joker_effect = &shared_joker_effect; - - (*joker_effect)->mult = random() % (MISPRINT_MAX_MULT + 1); - - return JOKER_EFFECT_FLAG_MULT; -} - -static u32 walkie_talkie_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - if (scored_card->rank == TEN || scored_card->rank == FOUR) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->chips = 10; - (*joker_effect)->mult = 4; - effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS | JOKER_EFFECT_FLAG_MULT; - } - - return effect_flags_ret; -} - -static u32 fibonnaci_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - switch (scored_card->rank) - { - case ACE: - case TWO: - case THREE: - case FIVE: - case EIGHT: - *joker_effect = &shared_joker_effect; - (*joker_effect)->mult = 8; - effect_flags_ret = JOKER_EFFECT_FLAG_MULT; - break; - default: - break; - } - - return effect_flags_ret; -} - -static u32 banner_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - if (get_num_discards_remaining() > 0) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->chips = 30 * get_num_discards_remaining(); - effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS; - } - - return effect_flags_ret; -} - -static u32 mystic_summit_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - if (get_num_discards_remaining() == 0) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->mult = 15; - effect_flags_ret = JOKER_EFFECT_FLAG_MULT; - } - - return effect_flags_ret; -} - -static u32 blackboard_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - bool all_cards_are_spades_or_clubs = true; - CardObject** hand = get_hand_array(); - int hand_size = hand_get_size(); - for (int i = 0; i < hand_size; i++ ) - { - u8 suit = hand[i]->card->suit; - if (suit == HEARTS || suit == DIAMONDS) - { - all_cards_are_spades_or_clubs = false; - break; - } - } - - if (all_cards_are_spades_or_clubs) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->xmult = 3; - effect_flags_ret = JOKER_EFFECT_FLAG_XMULT; - } - - return effect_flags_ret; -} - -static u32 blue_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - *joker_effect = &shared_joker_effect; - - (*joker_effect)->chips = (get_deck_top() + 1) * 2; - - return JOKER_EFFECT_FLAG_CHIPS; -} - -static u32 raised_fist_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - s32* p_lowest_value_index = &(joker->scoring_state); - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - switch (joker_event) - { - // Use this event to compute the index of the lowest value card only once. - // Aces are always considered high value, even in an ace-low straight - case JOKER_EVENT_ON_HAND_PLAYED: - // index initialized at 0 but accessed only if - // hand_size > 0 so we're never out of bounds - *p_lowest_value_index = 0; - u8 lowest_value = IMPOSSIBLY_HIGH_CARD_VALUE; - CardObject** hand = get_hand_array(); - int hand_size = hand_get_size(); - for (int i = 0; i < hand_size; i++ ) - { - u8 value = card_get_value(hand[i]->card); - if (lowest_value > value) - { - *p_lowest_value_index = i; - lowest_value = value; - } - } - break; - - case JOKER_EVENT_ON_CARD_HELD: - if (get_scored_card_index() == *p_lowest_value_index) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->mult = 2 * card_get_value(scored_card); - effect_flags_ret = JOKER_EFFECT_FLAG_MULT; - } - break; - - default: - break; - } - - return effect_flags_ret; -} - -static u32 reserved_parking_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_ON_CARD_HELD, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - if ((random() % 2 == 0) && card_is_face(scored_card)) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->money = 1; - effect_flags_ret = JOKER_EFFECT_FLAG_MONEY; - } - - return effect_flags_ret; -}; - -static u32 business_card_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - if ((random() % 2 == 0) && card_is_face(scored_card)) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->money = 2; - effect_flags_ret = JOKER_EFFECT_FLAG_MONEY; - } - - return effect_flags_ret; -} - -static u32 scholar_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - if (scored_card->rank == ACE) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->chips = 20; - (*joker_effect)->mult = 4; - effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS | JOKER_EFFECT_FLAG_MULT; - } - - return effect_flags_ret; -} - -static u32 scary_face_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - if (card_is_face(scored_card)) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->chips = 30; - effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS; - } - - return effect_flags_ret; -} - -static u32 abstract_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - *joker_effect = &shared_joker_effect; - - // +1 xmult per occupied joker slot - int num_jokers = list_get_len(get_jokers_list()); - - (*joker_effect)->mult = num_jokers * 3; - - return JOKER_EFFECT_FLAG_MULT; -} - -static u32 bull_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - // The wiki says it does nothing if money is 0 or below - // This allows us to avoid scoring negative Chips - if (get_money() > 0) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->chips = get_money() * 2; - effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS; - } - - return effect_flags_ret; -} - -static u32 smiley_face_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - if (card_is_face(scored_card)) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->mult = 5; - effect_flags_ret = JOKER_EFFECT_FLAG_MULT; - } - - return effect_flags_ret; -} - -static u32 even_steven_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - switch (scored_card->rank) - { - case KING: - case QUEEN: - case JACK: - break; - default: - if (card_get_value(scored_card) % 2 == 0) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->mult = 4; - effect_flags_ret = JOKER_EFFECT_FLAG_MULT; - } - break; - } - - return effect_flags_ret; -} - - -static u32 odd_todd_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - if (card_get_value(scored_card) % 2 == 1) // todo test ace - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->chips = 31; - effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS; - } - - return effect_flags_ret; -} - - -static u32 acrobat_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - // 0 remaining hands mean we're scoring the last hand - if (get_num_hands_remaining() == 0) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->xmult = 3; - effect_flags_ret = JOKER_EFFECT_FLAG_XMULT; - } - - return effect_flags_ret; -} - - -static u32 hanging_chad_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - s32* p_remaining_retriggers = &(joker->scoring_state); - - switch (joker_event) - { - case JOKER_EVENT_ON_HAND_PLAYED: - *p_remaining_retriggers = 2; - break; - - // No need to check if this is the first card scored or not - // p_remaining_retriggers will always reach 0 on the first card, then retrigger - // will be false and scoring will go onto the next card - case JOKER_EVENT_ON_CARD_SCORED_END: - *joker_effect = &shared_joker_effect; - - (*joker_effect)->retrigger = (*p_remaining_retriggers > 0); - if ((*joker_effect)->retrigger) - { - *p_remaining_retriggers -= 1; - (*joker_effect)->message = "Again!"; - effect_flags_ret = JOKER_EFFECT_FLAG_RETRIGGER | JOKER_EFFECT_FLAG_MESSAGE; - } - break; - - default: - break; - } - - return effect_flags_ret; -} - - -static u32 the_duo_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - // This is really inefficient but the only way at the moment to check for whole-hand conditions - u8 suits[NUM_SUITS]; - u8 ranks[NUM_RANKS]; - get_played_distribution(ranks, suits); - - if (hand_contains_n_of_a_kind(ranks) >= 2) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->xmult = 2; - effect_flags_ret = JOKER_EFFECT_FLAG_XMULT; - } - - return effect_flags_ret; -} - - -static u32 the_trio_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - // This is really inefficient but the only way at the moment to check for whole-hand conditions - u8 suits[NUM_SUITS]; - u8 ranks[NUM_RANKS]; - get_played_distribution(ranks, suits); - - if (hand_contains_n_of_a_kind(ranks) >= 3) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->xmult = 3; - effect_flags_ret = JOKER_EFFECT_FLAG_XMULT; - } - - return effect_flags_ret; -} - - -static u32 the_family_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - // This is really inefficient but the only way at the moment to check for whole-hand conditions - u8 suits[NUM_SUITS]; - u8 ranks[NUM_RANKS]; - get_played_distribution(ranks, suits); - - if (hand_contains_n_of_a_kind(ranks) >= 4) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->xmult = 4; - effect_flags_ret = JOKER_EFFECT_FLAG_XMULT; - } - - return effect_flags_ret; - } - - -static u32 the_order_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - u8 suits[NUM_SUITS]; - u8 ranks[NUM_RANKS]; - get_played_distribution(ranks, suits); - - if (hand_contains_straight(ranks)) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->xmult = 3; - effect_flags_ret = JOKER_EFFECT_FLAG_XMULT; - } - - return effect_flags_ret; -} - - -static u32 the_tribe_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - u8 suits[NUM_SUITS]; - u8 ranks[NUM_RANKS]; - get_played_distribution(ranks, suits); - - if (hand_contains_flush(suits)) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->xmult = 2; - effect_flags_ret = JOKER_EFFECT_FLAG_XMULT; - } - - return effect_flags_ret; -} - - -static u32 bootstraps_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - // Same protection as the Bull Joker - if (get_money() > 0) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->mult = (get_money() / 5) * 2; - effect_flags_ret = JOKER_EFFECT_FLAG_MULT; - } - - return effect_flags_ret; -} - - -// Using GBLA_UNUSED, aka __attribute__((unused)), for jokers with no sprites yet to avoid warning -// Remove the attribute once they have sprites -// no graphics available but ready to be used if wanted when graphics available -GBLA_UNUSED -static u32 shoot_the_moon_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - SCORE_ON_EVENT_ONLY(JOKER_EVENT_ON_CARD_HELD, joker_event) - - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - if (scored_card->rank == QUEEN) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->mult = 13; - effect_flags_ret = JOKER_EFFECT_FLAG_MULT; - } - - return effect_flags_ret; -} - - -GBLA_UNUSED -static u32 photograph_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - s32* p_first_face_index = &(joker->scoring_state); - - switch (joker_event) - { - case JOKER_EVENT_ON_HAND_PLAYED: - *p_first_face_index = UNDEFINED; - break; - - case JOKER_EVENT_ON_CARD_SCORED: - // has a face card been encountered already, and if not, is the current scoring card a face card? - if (*p_first_face_index == UNDEFINED && card_is_face(scored_card)) - { - *p_first_face_index = get_scored_card_index(); - } - // if we have a face card index saved, check against it and give mult accordingly - // Doing this now will trigger the effect the first time we encounter the face card, - // and we will catch potential retriggers - if (*p_first_face_index == get_scored_card_index()) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->xmult = 2; - effect_flags_ret = JOKER_EFFECT_FLAG_XMULT; - } - break; - default: - break; - } - - return effect_flags_ret; -} - -static u32 dusk_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - s32* p_last_retriggered_index = &(joker->scoring_state); - - switch (joker_event) - { - case JOKER_EVENT_ON_HAND_PLAYED: - // start at -1 so that a first index of 0 can satisfy the retrigger condition below - *p_last_retriggered_index = UNDEFINED; - break; - - case JOKER_EVENT_ON_CARD_SCORED_END: - // Only retrigger current card if it's strictly after the last one we retriggered - if (get_num_hands_remaining() == 0) - { - *joker_effect = &shared_joker_effect; - - (*joker_effect)->retrigger = (*p_last_retriggered_index < get_scored_card_index()); - if ((*joker_effect)->retrigger) - { - *p_last_retriggered_index = get_scored_card_index(); - (*joker_effect)->message = "Again!"; - effect_flags_ret = JOKER_EFFECT_FLAG_RETRIGGER | JOKER_EFFECT_FLAG_MESSAGE; - } - } - - break; - - default: - break; - } - - return effect_flags_ret; -} - - -static u32 blueprint_brainstorm_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect** joker_effect) -{ - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - // No need for this kind of init since these Jokers - // will have their data copied when needed - if (joker_event == JOKER_EVENT_ON_JOKER_CREATED || - joker_event == JOKER_EVENT_ON_HAND_SCORED_END || - joker_event == JOKER_EVENT_ON_ROUND_END) - { - return effect_flags_ret; - } - - // find ourselves in the Jokers list - List* jokers = get_jokers_list(); - ListItr itr = list_itr_create(jokers); - JokerObject* copied_joker_object; - while((copied_joker_object = list_itr_next(&itr))) - { - if (copied_joker_object->joker == joker) - { - break; - } - } - - // This shouldn't happen since if we are a scoring Joker, we should always - // be part of the Jokers list, but being extra careful doesn't cost much - if (copied_joker_object == NULL) - { - return effect_flags_ret; - } - - // find the copied Joker, may need to bounce around Blueprints and a Brainstorm - // If we encounter NULL, we have a Blueprint at the end of the list that can't copy anything. - // If we go through a Brainstorms twice, we will be in a loop and need to exit - u8 brainstorm_counter = 0; - do - { - switch (copied_joker_object->joker->id) - { - // get the next Joker for Blueprint - case BLUEPRINT_JOKER_ID: - copied_joker_object = list_itr_next(&itr); - break; - - // Get the first (leftmost) Joker for Brainstorm - case BRAINSTORM_JOKER_ID: - brainstorm_counter++; - itr = list_itr_create(jokers); - copied_joker_object = list_itr_next(&itr); - break; - - // We encountered a Joker that isn't a Copying Joker and copy it now - // but how we copy it depends on this Joker's ID because they don't - // all handle data the same way. - default: - u8 copied_joker_id = copied_joker_object->joker->id; - const JokerInfo* copied_joker_info = get_joker_registry_entry(copied_joker_id); - - // Copy the persistent data - joker->persistent_state = copied_joker_object->joker->persistent_state; - - // Then regardless of if we copied the data above, apply the - // copied JokerEffect function to the local data - effect_flags_ret = copied_joker_info->joker_effect_func(joker, scored_card, joker_event, joker_effect); - - // make also sure we don't expire - effect_flags_ret &= ~JOKER_EFFECT_FLAG_EXPIRE; - - // exit the loop - copied_joker_object = NULL; - - break; - } - } - while(copied_joker_object != NULL && brainstorm_counter < 2); - - return effect_flags_ret; -} - - -static u32 hack_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - s32* p_last_retriggered_index = &(joker->scoring_state); - - switch (joker_event) - { - case JOKER_EVENT_ON_HAND_PLAYED: - *p_last_retriggered_index = UNDEFINED; - break; - - case JOKER_EVENT_ON_CARD_SCORED_END: - // Works the same way as Dusk, but check what rank the card is - switch (scored_card->rank) - { - case TWO: - case THREE: - case FOUR: - case FIVE: - *joker_effect = &shared_joker_effect; - - (*joker_effect)->retrigger = (*p_last_retriggered_index < get_scored_card_index()); - if ((*joker_effect)->retrigger) - { - *p_last_retriggered_index = get_scored_card_index(); - (*joker_effect)->message = "Again!"; - effect_flags_ret = JOKER_EFFECT_FLAG_RETRIGGER | JOKER_EFFECT_FLAG_MESSAGE; - } - break; - } - break; - - default: - break; - } - - return effect_flags_ret; -} - - -static u32 seltzer_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - s32* p_last_retriggered_idx = &(joker->scoring_state); - s32* p_hands_left_until_exp = &(joker->persistent_state); - - switch (joker_event) - { - case JOKER_EVENT_ON_JOKER_CREATED: - *p_hands_left_until_exp = 10; // remaining retriggered hands - break; - - case JOKER_EVENT_ON_HAND_PLAYED: - *p_last_retriggered_idx = UNDEFINED; - break; - - case JOKER_EVENT_ON_CARD_SCORED_END: - // Works the same way as Dusk - // No need to check for p_hands_left_until_exp because the Joker - // will be destroyed the moment we hit 0 - *joker_effect = &shared_joker_effect; - - (*joker_effect)->retrigger = ((*p_last_retriggered_idx) < get_scored_card_index()); - if ((*joker_effect)->retrigger) - { - *p_last_retriggered_idx = get_scored_card_index(); - (*joker_effect)->message = "Again!"; - effect_flags_ret = JOKER_EFFECT_FLAG_RETRIGGER | JOKER_EFFECT_FLAG_MESSAGE; - } - break; - - case JOKER_EVENT_ON_HAND_SCORED_END: - *joker_effect = &shared_joker_effect; - effect_flags_ret = JOKER_EFFECT_FLAG_MESSAGE; - - (*p_hands_left_until_exp)--; - if (*p_hands_left_until_exp > 0) - { - // Need to do this for now because the message's memory can't really be allocated - // So we can't use snprintf to craft a message depending on the number of hands left - static const char* seltzer_messages[] = { - "1", "2", "3", "4", "5", "6", "7", "8", "9" - }; - (*joker_effect)->message = (char*)seltzer_messages[(*p_hands_left_until_exp) - 1]; - } - else - { - (*joker_effect)->message = "Drank!"; - (*joker_effect)->expire = true; - effect_flags_ret |= JOKER_EFFECT_FLAG_EXPIRE; - } - break; - - default: - break; - } - - return effect_flags_ret; -} - - -static u32 sock_and_buskin_joker_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event, JokerEffect **joker_effect) -{ - u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; - - s32* p_last_retriggered_face_index = &(joker->scoring_state); - - switch (joker_event) - { - case JOKER_EVENT_ON_HAND_PLAYED: - *p_last_retriggered_face_index = UNDEFINED; - break; - - case JOKER_EVENT_ON_CARD_SCORED_END: - *joker_effect = &shared_joker_effect; - - // Works the same way as Dusk, but for face cards - (*joker_effect)->retrigger = ((*p_last_retriggered_face_index < get_scored_card_index()) && card_is_face(scored_card)); - if ((*joker_effect)->retrigger) - { - *p_last_retriggered_face_index = get_scored_card_index(); - (*joker_effect)->message = "Again!"; - effect_flags_ret = JOKER_EFFECT_FLAG_RETRIGGER | JOKER_EFFECT_FLAG_MESSAGE; - } - break; - - default: - break; - } - - return effect_flags_ret; -} - - +static u32 joker_effect_noop( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 default_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 sinful_joker_effect( + Card* scored_card, + u8 sinful_suit, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 greedy_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 lusty_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 wrathful_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 gluttonous_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 jolly_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 zany_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 mad_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 crazy_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 droll_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 sly_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 wily_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 clever_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 devious_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 crafty_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 half_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 joker_stencil_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 misprint_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 walkie_talkie_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 fibonnaci_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 banner_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 mystic_summit_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 blackboard_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 blue_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 raised_fist_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 reserved_parking_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 business_card_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 scholar_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 scary_face_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 abstract_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 bull_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 smiley_face_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 even_steven_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 odd_todd_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 acrobat_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 hanging_chad_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 the_duo_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 the_trio_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 the_family_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 the_order_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 the_tribe_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 bootstraps_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 shoot_the_moon_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 photograph_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 dusk_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 blueprint_brainstorm_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 hack_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 seltzer_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); +static u32 sock_and_buskin_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +); + +// clang-format off /* The index of a joker in the registry matches its ID. * The joker sprites are matched by ID so the position in the registry * determines the joker's sprite. @@ -1235,6 +402,7 @@ const JokerInfo joker_registry[] = { COMMON_JOKER, 5, shoot_the_moon_joker_effect, }, #endif }; +// clang-format on static const size_t joker_registry_size = NUM_ELEM_IN_ARR(joker_registry); @@ -1251,3 +419,1388 @@ size_t get_joker_registry_size(void) { return joker_registry_size; } + +static u32 joker_effect_noop( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + return JOKER_EFFECT_FLAG_NONE; +} + +static u32 default_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + *joker_effect = &shared_joker_effect; + + (*joker_effect)->mult = 4; + + return JOKER_EFFECT_FLAG_MULT; +} + +static u32 sinful_joker_effect( + Card* scored_card, + u8 sinful_suit, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + if (scored_card->suit == sinful_suit) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->mult = 3; + effect_flags_ret = JOKER_EFFECT_FLAG_MULT; + } + return effect_flags_ret; +} + +static u32 greedy_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + return sinful_joker_effect(scored_card, DIAMONDS, joker_event, joker_effect); +} + +static u32 lusty_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + return sinful_joker_effect(scored_card, HEARTS, joker_event, joker_effect); +} + +static u32 wrathful_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + return sinful_joker_effect(scored_card, SPADES, joker_event, joker_effect); +} + +static u32 gluttonous_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + return sinful_joker_effect(scored_card, CLUBS, joker_event, joker_effect); +} + +static u32 jolly_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + // This is really inefficient but the only way at the moment to check for whole-hand conditions + u8 suits[NUM_SUITS]; + u8 ranks[NUM_RANKS]; + get_played_distribution(ranks, suits); + + if (hand_contains_n_of_a_kind(ranks) >= 2) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->mult = 8; + effect_flags_ret = JOKER_EFFECT_FLAG_MULT; + } + + return effect_flags_ret; +} + +static u32 zany_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + // This is really inefficient but the only way at the moment to check for whole-hand conditions + u8 suits[NUM_SUITS]; + u8 ranks[NUM_RANKS]; + get_played_distribution(ranks, suits); + + if (hand_contains_n_of_a_kind(ranks) >= 3) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->mult = 12; + effect_flags_ret = JOKER_EFFECT_FLAG_MULT; + } + + return effect_flags_ret; +} + +static u32 mad_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + u8 suits[NUM_SUITS]; + u8 ranks[NUM_RANKS]; + get_played_distribution(ranks, suits); + + if (hand_contains_two_pair(ranks)) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->mult = 10; + effect_flags_ret = JOKER_EFFECT_FLAG_MULT; + } + + return effect_flags_ret; +} + +static u32 crazy_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + u8 suits[NUM_SUITS]; + u8 ranks[NUM_RANKS]; + get_played_distribution(ranks, suits); + + if (hand_contains_straight(ranks)) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->mult = 12; + effect_flags_ret = JOKER_EFFECT_FLAG_MULT; + } + + return effect_flags_ret; +} + +static u32 droll_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + u8 suits[NUM_SUITS]; + u8 ranks[NUM_RANKS]; + get_played_distribution(ranks, suits); + + if (hand_contains_flush(suits)) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->mult = 10; + effect_flags_ret = JOKER_EFFECT_FLAG_MULT; + } + + return effect_flags_ret; +} + +static u32 sly_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + u8 suits[NUM_SUITS]; + u8 ranks[NUM_RANKS]; + get_played_distribution(ranks, suits); + + if (hand_contains_n_of_a_kind(ranks) >= 2) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->chips = 50; + effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS; + } + + return effect_flags_ret; +} + +static u32 wily_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + u8 suits[NUM_SUITS]; + u8 ranks[NUM_RANKS]; + get_played_distribution(ranks, suits); + + if (hand_contains_n_of_a_kind(ranks) >= 3) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->chips = 100; + effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS; + } + + return effect_flags_ret; +} + +static u32 clever_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + u8 suits[NUM_SUITS]; + u8 ranks[NUM_RANKS]; + get_played_distribution(ranks, suits); + + if (hand_contains_two_pair(ranks)) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->chips = 80; + effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS; + } + + return effect_flags_ret; +} + +static u32 devious_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + u8 suits[NUM_SUITS]; + u8 ranks[NUM_RANKS]; + get_played_distribution(ranks, suits); + + if (hand_contains_straight(ranks)) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->chips = 100; + effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS; + } + + return effect_flags_ret; +} + +static u32 crafty_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + u8 suits[NUM_SUITS]; + u8 ranks[NUM_RANKS]; + get_played_distribution(ranks, suits); + + if (hand_contains_flush(suits)) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->chips = 80; + effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS; + } + + return effect_flags_ret; +} + +static u32 half_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + int played_size = get_played_top() + 1; + if (played_size <= 3) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->mult = 20; + effect_flags_ret = JOKER_EFFECT_FLAG_MULT; + } + + return effect_flags_ret; +} + +static u32 joker_stencil_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + *joker_effect = &shared_joker_effect; + + List* jokers = get_jokers_list(); + + // +1 xmult per empty joker slot... + int num_jokers = list_get_len(jokers); + + (*joker_effect)->xmult = (MAX_JOKERS_HELD_SIZE)-num_jokers; + + // ...and also each stencil_joker adds +1 xmult + ListItr itr = list_itr_create(jokers); + JokerObject* joker_object; + + while ((joker_object = list_itr_next(&itr))) + { + if (joker_object->joker->id == STENCIL_JOKER_ID) + (*joker_effect)->xmult++; + } + + return JOKER_EFFECT_FLAG_XMULT; +} + +#define MISPRINT_MAX_MULT 23 +static u32 misprint_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + *joker_effect = &shared_joker_effect; + + (*joker_effect)->mult = random() % (MISPRINT_MAX_MULT + 1); + + return JOKER_EFFECT_FLAG_MULT; +} + +static u32 walkie_talkie_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + if (scored_card->rank == TEN || scored_card->rank == FOUR) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->chips = 10; + (*joker_effect)->mult = 4; + effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS | JOKER_EFFECT_FLAG_MULT; + } + + return effect_flags_ret; +} + +static u32 fibonnaci_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + switch (scored_card->rank) + { + case ACE: + case TWO: + case THREE: + case FIVE: + case EIGHT: + *joker_effect = &shared_joker_effect; + (*joker_effect)->mult = 8; + effect_flags_ret = JOKER_EFFECT_FLAG_MULT; + break; + default: + break; + } + + return effect_flags_ret; +} + +static u32 banner_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + if (get_num_discards_remaining() > 0) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->chips = 30 * get_num_discards_remaining(); + effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS; + } + + return effect_flags_ret; +} + +static u32 mystic_summit_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + if (get_num_discards_remaining() == 0) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->mult = 15; + effect_flags_ret = JOKER_EFFECT_FLAG_MULT; + } + + return effect_flags_ret; +} + +static u32 blackboard_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + bool all_cards_are_spades_or_clubs = true; + CardObject** hand = get_hand_array(); + int hand_size = hand_get_size(); + for (int i = 0; i < hand_size; i++) + { + u8 suit = hand[i]->card->suit; + if (suit == HEARTS || suit == DIAMONDS) + { + all_cards_are_spades_or_clubs = false; + break; + } + } + + if (all_cards_are_spades_or_clubs) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->xmult = 3; + effect_flags_ret = JOKER_EFFECT_FLAG_XMULT; + } + + return effect_flags_ret; +} + +static u32 blue_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + *joker_effect = &shared_joker_effect; + + (*joker_effect)->chips = (get_deck_top() + 1) * 2; + + return JOKER_EFFECT_FLAG_CHIPS; +} + +static u32 raised_fist_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + s32* p_lowest_value_index = &(joker->scoring_state); + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + switch (joker_event) + { + // Use this event to compute the index of the lowest value card only once. + // Aces are always considered high value, even in an ace-low straight + case JOKER_EVENT_ON_HAND_PLAYED: + // index initialized at 0 but accessed only if + // hand_size > 0 so we're never out of bounds + *p_lowest_value_index = 0; + u8 lowest_value = IMPOSSIBLY_HIGH_CARD_VALUE; + CardObject** hand = get_hand_array(); + int hand_size = hand_get_size(); + for (int i = 0; i < hand_size; i++) + { + u8 value = card_get_value(hand[i]->card); + if (lowest_value > value) + { + *p_lowest_value_index = i; + lowest_value = value; + } + } + break; + + case JOKER_EVENT_ON_CARD_HELD: + if (get_scored_card_index() == *p_lowest_value_index) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->mult = 2 * card_get_value(scored_card); + effect_flags_ret = JOKER_EFFECT_FLAG_MULT; + } + break; + + default: + break; + } + + return effect_flags_ret; +} + +static u32 reserved_parking_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_ON_CARD_HELD, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + if ((random() % 2 == 0) && card_is_face(scored_card)) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->money = 1; + effect_flags_ret = JOKER_EFFECT_FLAG_MONEY; + } + + return effect_flags_ret; +}; + +static u32 business_card_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + if ((random() % 2 == 0) && card_is_face(scored_card)) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->money = 2; + effect_flags_ret = JOKER_EFFECT_FLAG_MONEY; + } + + return effect_flags_ret; +} + +static u32 scholar_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + if (scored_card->rank == ACE) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->chips = 20; + (*joker_effect)->mult = 4; + effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS | JOKER_EFFECT_FLAG_MULT; + } + + return effect_flags_ret; +} + +static u32 scary_face_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + if (card_is_face(scored_card)) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->chips = 30; + effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS; + } + + return effect_flags_ret; +} + +static u32 abstract_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + *joker_effect = &shared_joker_effect; + + // +1 xmult per occupied joker slot + int num_jokers = list_get_len(get_jokers_list()); + + (*joker_effect)->mult = num_jokers * 3; + + return JOKER_EFFECT_FLAG_MULT; +} + +static u32 bull_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + // The wiki says it does nothing if money is 0 or below + // This allows us to avoid scoring negative Chips + if (get_money() > 0) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->chips = get_money() * 2; + effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS; + } + + return effect_flags_ret; +} + +static u32 smiley_face_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + if (card_is_face(scored_card)) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->mult = 5; + effect_flags_ret = JOKER_EFFECT_FLAG_MULT; + } + + return effect_flags_ret; +} + +static u32 even_steven_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + switch (scored_card->rank) + { + case KING: + case QUEEN: + case JACK: + break; + default: + if (card_get_value(scored_card) % 2 == 0) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->mult = 4; + effect_flags_ret = JOKER_EFFECT_FLAG_MULT; + } + break; + } + + return effect_flags_ret; +} + +static u32 odd_todd_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + if (card_get_value(scored_card) % 2 == 1) // todo test ace + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->chips = 31; + effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS; + } + + return effect_flags_ret; +} + +static u32 acrobat_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + // 0 remaining hands mean we're scoring the last hand + if (get_num_hands_remaining() == 0) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->xmult = 3; + effect_flags_ret = JOKER_EFFECT_FLAG_XMULT; + } + + return effect_flags_ret; +} + +static u32 hanging_chad_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + s32* p_remaining_retriggers = &(joker->scoring_state); + + switch (joker_event) + { + case JOKER_EVENT_ON_HAND_PLAYED: + *p_remaining_retriggers = 2; + break; + + // No need to check if this is the first card scored or not + // p_remaining_retriggers will always reach 0 on the first card, then retrigger + // will be false and scoring will go onto the next card + case JOKER_EVENT_ON_CARD_SCORED_END: + *joker_effect = &shared_joker_effect; + + (*joker_effect)->retrigger = (*p_remaining_retriggers > 0); + if ((*joker_effect)->retrigger) + { + *p_remaining_retriggers -= 1; + (*joker_effect)->message = "Again!"; + effect_flags_ret = JOKER_EFFECT_FLAG_RETRIGGER | JOKER_EFFECT_FLAG_MESSAGE; + } + break; + + default: + break; + } + + return effect_flags_ret; +} + +static u32 the_duo_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + // This is really inefficient but the only way at the moment to check for whole-hand conditions + u8 suits[NUM_SUITS]; + u8 ranks[NUM_RANKS]; + get_played_distribution(ranks, suits); + + if (hand_contains_n_of_a_kind(ranks) >= 2) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->xmult = 2; + effect_flags_ret = JOKER_EFFECT_FLAG_XMULT; + } + + return effect_flags_ret; +} + +static u32 the_trio_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + // This is really inefficient but the only way at the moment to check for whole-hand conditions + u8 suits[NUM_SUITS]; + u8 ranks[NUM_RANKS]; + get_played_distribution(ranks, suits); + + if (hand_contains_n_of_a_kind(ranks) >= 3) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->xmult = 3; + effect_flags_ret = JOKER_EFFECT_FLAG_XMULT; + } + + return effect_flags_ret; +} + +static u32 the_family_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + // This is really inefficient but the only way at the moment to check for whole-hand conditions + u8 suits[NUM_SUITS]; + u8 ranks[NUM_RANKS]; + get_played_distribution(ranks, suits); + + if (hand_contains_n_of_a_kind(ranks) >= 4) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->xmult = 4; + effect_flags_ret = JOKER_EFFECT_FLAG_XMULT; + } + + return effect_flags_ret; +} + +static u32 the_order_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + u8 suits[NUM_SUITS]; + u8 ranks[NUM_RANKS]; + get_played_distribution(ranks, suits); + + if (hand_contains_straight(ranks)) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->xmult = 3; + effect_flags_ret = JOKER_EFFECT_FLAG_XMULT; + } + + return effect_flags_ret; +} + +static u32 the_tribe_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + u8 suits[NUM_SUITS]; + u8 ranks[NUM_RANKS]; + get_played_distribution(ranks, suits); + + if (hand_contains_flush(suits)) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->xmult = 2; + effect_flags_ret = JOKER_EFFECT_FLAG_XMULT; + } + + return effect_flags_ret; +} + +static u32 bootstraps_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + // Same protection as the Bull Joker + if (get_money() > 0) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->mult = (get_money() / 5) * 2; + effect_flags_ret = JOKER_EFFECT_FLAG_MULT; + } + + return effect_flags_ret; +} + +// Using GBLA_UNUSED, aka __attribute__((unused)), for jokers with no sprites yet to avoid warning +// Remove the attribute once they have sprites +// no graphics available but ready to be used if wanted when graphics available +GBLA_UNUSED +static u32 shoot_the_moon_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + SCORE_ON_EVENT_ONLY(JOKER_EVENT_ON_CARD_HELD, joker_event) + + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + if (scored_card->rank == QUEEN) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->mult = 13; + effect_flags_ret = JOKER_EFFECT_FLAG_MULT; + } + + return effect_flags_ret; +} + +GBLA_UNUSED +static u32 photograph_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + s32* p_first_face_index = &(joker->scoring_state); + + switch (joker_event) + { + case JOKER_EVENT_ON_HAND_PLAYED: + *p_first_face_index = UNDEFINED; + break; + + case JOKER_EVENT_ON_CARD_SCORED: + // has a face card been encountered already, and if not, is the current scoring card a + // face card? + if (*p_first_face_index == UNDEFINED && card_is_face(scored_card)) + { + *p_first_face_index = get_scored_card_index(); + } + // if we have a face card index saved, check against it and give mult accordingly + // Doing this now will trigger the effect the first time we encounter the face card, + // and we will catch potential retriggers + if (*p_first_face_index == get_scored_card_index()) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->xmult = 2; + effect_flags_ret = JOKER_EFFECT_FLAG_XMULT; + } + break; + default: + break; + } + + return effect_flags_ret; +} + +static u32 dusk_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + s32* p_last_retriggered_index = &(joker->scoring_state); + + switch (joker_event) + { + case JOKER_EVENT_ON_HAND_PLAYED: + // start at -1 so that a first index of 0 can satisfy the retrigger condition below + *p_last_retriggered_index = UNDEFINED; + break; + + case JOKER_EVENT_ON_CARD_SCORED_END: + // Only retrigger current card if it's strictly after the last one we retriggered + if (get_num_hands_remaining() == 0) + { + *joker_effect = &shared_joker_effect; + + (*joker_effect)->retrigger = (*p_last_retriggered_index < get_scored_card_index()); + if ((*joker_effect)->retrigger) + { + *p_last_retriggered_index = get_scored_card_index(); + (*joker_effect)->message = "Again!"; + effect_flags_ret = JOKER_EFFECT_FLAG_RETRIGGER | JOKER_EFFECT_FLAG_MESSAGE; + } + } + + break; + + default: + break; + } + + return effect_flags_ret; +} + +static u32 blueprint_brainstorm_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + // No need for this kind of init since these Jokers + // will have their data copied when needed + if (joker_event == JOKER_EVENT_ON_JOKER_CREATED || + joker_event == JOKER_EVENT_ON_HAND_SCORED_END || joker_event == JOKER_EVENT_ON_ROUND_END) + { + return effect_flags_ret; + } + + // find ourselves in the Jokers list + List* jokers = get_jokers_list(); + ListItr itr = list_itr_create(jokers); + JokerObject* copied_joker_object; + while ((copied_joker_object = list_itr_next(&itr))) + { + if (copied_joker_object->joker == joker) + { + break; + } + } + + // This shouldn't happen since if we are a scoring Joker, we should always + // be part of the Jokers list, but being extra careful doesn't cost much + if (copied_joker_object == NULL) + { + return effect_flags_ret; + } + + // find the copied Joker, may need to bounce around Blueprints and a Brainstorm + // If we encounter NULL, we have a Blueprint at the end of the list that can't copy anything. + // If we go through a Brainstorms twice, we will be in a loop and need to exit + u8 brainstorm_counter = 0; + do + { + switch (copied_joker_object->joker->id) + { + // get the next Joker for Blueprint + case BLUEPRINT_JOKER_ID: + copied_joker_object = list_itr_next(&itr); + break; + + // Get the first (leftmost) Joker for Brainstorm + case BRAINSTORM_JOKER_ID: + brainstorm_counter++; + itr = list_itr_create(jokers); + copied_joker_object = list_itr_next(&itr); + break; + + // We encountered a Joker that isn't a Copying Joker and copy it now + // but how we copy it depends on this Joker's ID because they don't + // all handle data the same way. + default: + u8 copied_joker_id = copied_joker_object->joker->id; + const JokerInfo* copied_joker_info = get_joker_registry_entry(copied_joker_id); + + // Copy the persistent data + joker->persistent_state = copied_joker_object->joker->persistent_state; + + // Then regardless of if we copied the data above, apply the + // copied JokerEffect function to the local data + effect_flags_ret = + copied_joker_info + ->joker_effect_func(joker, scored_card, joker_event, joker_effect); + + // make also sure we don't expire + effect_flags_ret &= ~JOKER_EFFECT_FLAG_EXPIRE; + + // exit the loop + copied_joker_object = NULL; + + break; + } + } while (copied_joker_object != NULL && brainstorm_counter < 2); + + return effect_flags_ret; +} + +static u32 hack_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + s32* p_last_retriggered_index = &(joker->scoring_state); + + switch (joker_event) + { + case JOKER_EVENT_ON_HAND_PLAYED: + *p_last_retriggered_index = UNDEFINED; + break; + + case JOKER_EVENT_ON_CARD_SCORED_END: + // Works the same way as Dusk, but check what rank the card is + switch (scored_card->rank) + { + case TWO: + case THREE: + case FOUR: + case FIVE: + *joker_effect = &shared_joker_effect; + + (*joker_effect)->retrigger = + (*p_last_retriggered_index < get_scored_card_index()); + if ((*joker_effect)->retrigger) + { + *p_last_retriggered_index = get_scored_card_index(); + (*joker_effect)->message = "Again!"; + effect_flags_ret = JOKER_EFFECT_FLAG_RETRIGGER | JOKER_EFFECT_FLAG_MESSAGE; + } + break; + } + break; + + default: + break; + } + + return effect_flags_ret; +} + +static u32 seltzer_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + s32* p_last_retriggered_idx = &(joker->scoring_state); + s32* p_hands_left_until_exp = &(joker->persistent_state); + + switch (joker_event) + { + case JOKER_EVENT_ON_JOKER_CREATED: + *p_hands_left_until_exp = 10; // remaining retriggered hands + break; + + case JOKER_EVENT_ON_HAND_PLAYED: + *p_last_retriggered_idx = UNDEFINED; + break; + + case JOKER_EVENT_ON_CARD_SCORED_END: + // Works the same way as Dusk + // No need to check for p_hands_left_until_exp because the Joker + // will be destroyed the moment we hit 0 + *joker_effect = &shared_joker_effect; + + (*joker_effect)->retrigger = ((*p_last_retriggered_idx) < get_scored_card_index()); + if ((*joker_effect)->retrigger) + { + *p_last_retriggered_idx = get_scored_card_index(); + (*joker_effect)->message = "Again!"; + effect_flags_ret = JOKER_EFFECT_FLAG_RETRIGGER | JOKER_EFFECT_FLAG_MESSAGE; + } + break; + + case JOKER_EVENT_ON_HAND_SCORED_END: + *joker_effect = &shared_joker_effect; + effect_flags_ret = JOKER_EFFECT_FLAG_MESSAGE; + + (*p_hands_left_until_exp)--; + if (*p_hands_left_until_exp > 0) + { + // Need to do this for now because the message's memory can't really be allocated + // So we can't use snprintf to craft a message depending on the number of hands left + static const char* seltzer_messages[] = + {"1", "2", "3", "4", "5", "6", "7", "8", "9"}; + (*joker_effect)->message = (char*)seltzer_messages[(*p_hands_left_until_exp) - 1]; + } + else + { + (*joker_effect)->message = "Drank!"; + (*joker_effect)->expire = true; + effect_flags_ret |= JOKER_EFFECT_FLAG_EXPIRE; + } + break; + + default: + break; + } + + return effect_flags_ret; +} + +static u32 sock_and_buskin_joker_effect( + Joker* joker, + Card* scored_card, + enum JokerEvent joker_event, + JokerEffect** joker_effect +) +{ + u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE; + + s32* p_last_retriggered_face_index = &(joker->scoring_state); + + switch (joker_event) + { + case JOKER_EVENT_ON_HAND_PLAYED: + *p_last_retriggered_face_index = UNDEFINED; + break; + + case JOKER_EVENT_ON_CARD_SCORED_END: + *joker_effect = &shared_joker_effect; + + // Works the same way as Dusk, but for face cards + (*joker_effect)->retrigger = + ((*p_last_retriggered_face_index < get_scored_card_index()) && + card_is_face(scored_card)); + if ((*joker_effect)->retrigger) + { + *p_last_retriggered_face_index = get_scored_card_index(); + (*joker_effect)->message = "Again!"; + effect_flags_ret = JOKER_EFFECT_FLAG_RETRIGGER | JOKER_EFFECT_FLAG_MESSAGE; + } + break; + + default: + break; + } + + return effect_flags_ret; +} diff --git a/source/main.c b/source/main.c index 9191cb2..cb3145c 100644 --- a/source/main.c +++ b/source/main.c @@ -1,18 +1,18 @@ -#include -#include -#include - -#include "sprite.h" +#include "affine_background.h" +#include "blind.h" #include "card.h" #include "game.h" -#include "blind.h" -#include "joker.h" -#include "affine_background.h" #include "graphic_utils.h" +#include "joker.h" +#include "sprite.h" + +#include +#include +#include // Graphics -#include "background_gfx.h" #include "affine_background_gfx.h" +#include "background_gfx.h" // Audio #include "soundbank.h" @@ -25,14 +25,22 @@ void init() irq_add(II_HBLANK, affine_background_hblank); // 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_init_con(); // TTE palette setup pal_bg_bank[TTE_YELLOW_PB][TTE_BIT_ON_CLR_IDX] = TEXT_CLR_YELLOW; - pal_bg_bank[TTE_BLUE_PB][TTE_BIT_ON_CLR_IDX] = TEXT_CLR_BLUE; - pal_bg_bank[TTE_RED_PB][TTE_BIT_ON_CLR_IDX] = TEXT_CLR_RED; + pal_bg_bank[TTE_BLUE_PB][TTE_BIT_ON_CLR_IDX] = TEXT_CLR_BLUE; + pal_bg_bank[TTE_RED_PB][TTE_BIT_ON_CLR_IDX] = TEXT_CLR_RED; pal_bg_bank[TTE_WHITE_PB][TTE_BIT_ON_CLR_IDX] = TEXT_CLR_WHITE; // Set up the video mode @@ -40,7 +48,7 @@ void init() REG_BG0CNT = BG_PRIO(0) | BG_CBB(TTE_CBB) | BG_SBB(TTE_SBB) | BG_4BPP; // BG1 is the main background layer REG_BG1CNT = BG_PRIO(1) | BG_CBB(MAIN_BG_CBB) | BG_SBB(MAIN_BG_SBB) | BG_8BPP; - // BG2 is the affine background layer + // BG2 is the affine background layer REG_BG2CNT = BG_PRIO(2) | BG_CBB(AFFINE_BG_CBB) | BG_SBB(AFFINE_BG_SBB) | BG_8BPP | BG_WRAP; int win1_left = 72; @@ -53,20 +61,21 @@ void init() int win2_right = 232; int win2_bottom = 44; - REG_WIN0H = win1_left<<8 | win1_right; - REG_WIN0V = win1_top<<8 | win1_bottom; - REG_WIN0CNT = WIN_ALL | WIN_BLD; - REG_WINOUTCNT = WIN_ALL; + REG_WIN0H = win1_left << 8 | win1_right; + REG_WIN0V = win1_top << 8 | win1_bottom; + REG_WIN0CNT = WIN_ALL | WIN_BLD; + REG_WINOUTCNT = WIN_ALL; - REG_WIN1H = win2_left<<8 | win2_right; - REG_WIN1V = win2_top<<8 | win2_bottom; + REG_WIN1H = win2_left << 8 | win2_right; + REG_WIN1V = win2_top << 8 | win2_bottom; REG_WIN1CNT = WIN_ALL | WIN_BLD; REG_BLDCNT = BLD_BUILD(BLD_BG1, BLD_BG2, 1); 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 mmInitDefault((mm_addr)soundbank_bin, 12); @@ -94,14 +103,14 @@ int main() { init(); - while(true) + while (true) { VBlankIntrWait(); mmFrame(); - key_poll(); + key_poll(); update(); draw(); } - return 0; + return 0; } diff --git a/source/version.c b/source/version.c index 0546e67..3a57fbb 100644 --- a/source/version.c +++ b/source/version.c @@ -6,4 +6,5 @@ #define GIT_DIRTY "-dirty" #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;