d24b0b5619
* Turned SpriteObject into a member of JokerObject and CardObject and expiremented with casting * Extracted shop code to use generic `SpriteObject` * Extracted shop joker generation to a function * Renamed object -> item * Added setters and getters for `SpriteObject` members and updated all accesses to use them with casting (AI used for tedious work and reviewed - model Raptor mini) * Added sprite_object_set_vx() because sprite_object_set_vy() exists and reordered the function order to have x,y parameters first, then targets * Added Item object to act as a purchasable interface for the shop - AI used (model Raptor mini) * Added -fms-extensions and switched to anonymous inheritance * Fixed anonymous inheritance for joker and added direct access for that too * fix build error from previous commit + clang-format * Fixed build errors + clang-format for real this time (I hope...) * clang-format one last time, I don't understand it anymore * clang-format is annoying * Added uses of CHECK_NULL_ARG macros * Merged item_defs.h into item.h and fixed build error from previous commit * clang-format...? * Changed sprite_object_new() into sprite_object_init() and made it accept a parameter instead of returning one to make it less awkward * Updated sprite_object_init() documentation * Updated sprite_object_destroy documentation * More clang-format * Renamed add_to_inventory to acquire and updated documentation * Added function documentations * Update documentation + swap order of consumable and playing card types * Added documentation for new files (+ small addition to button.h) * clang-format * Used typedef * A bit more documentation * Changed sho pcode to use generic Item instead of SpriteObject * clang-format + fixed NULL-check error * Revert weird clang-format...? * clang-format for real * Fixed errors from rebase on log_function_name * Fixed build errors from rebase on main * Added some more documentation about first member struct inheritance * typo fix * typo fix for real * Removed SpriteObject field getters/setters (AI used - model Raptor mini) * Renamed item_acquire -> item_on_acquired * Added item_can_acquire() * clang-format * Fixed some sprite issues but not all... * Fixed some more issues * Cleanup JokerObject some more JokerObjects in the shop * Added `item_destroy()` * Added item_set_available_to_shop, CHECK_ITEM_TYPE macros + small documentation updates * Another small JokerObject->Item replacement * Removed item_set_available_to_shop and replaced with item_roll_new() and item_dispose(), also changed "available_to_shop" semantics to "rollable" * Re-applied changes from game.c to round.c after rebase on main * Added partial implementations of item functions for playing cards * Line endings fix... * Macro renames, function documentations * Updated documentations * Apply fixes from Copilot review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Fix card_object_get_buy_price type checking Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Avoid double pointer cast on dispose Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Apply suggestions from @ricfehr3's code review Co-authored-by: Rickey <ric@rf3.xyz> * Remove redundant comments * Moved error checking before joker_get_random_rarity Co-authored-by: Rickey <ric@rf3.xyz> * Fixed build error from rebase * clang-format * Added doxygen documentation for Item explaining inheritance * Removed unnecessary comment --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Rickey <ric@rf3.xyz>
259 lines
9.0 KiB
C
259 lines
9.0 KiB
C
/**
|
|
* @file joker.h
|
|
*
|
|
* @brief Functions relative to the handling of Jokers
|
|
*/
|
|
#ifndef JOKER_H
|
|
#define JOKER_H
|
|
|
|
#include "card.h"
|
|
#include "game.h"
|
|
#include "graphic_utils.h"
|
|
#include "item.h"
|
|
|
|
#include <maxmod.h>
|
|
|
|
// 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...
|
|
#define MAX_ACTIVE_JOKERS 8
|
|
|
|
#define MAX_DEFINABLE_JOKERS 150
|
|
|
|
#define JOKER_SPRITE_OFFSET 16 // Offset for the joker sprites
|
|
#define JOKER_STARTING_LAYER 26
|
|
// Tile ID for the starting index in the tile memory
|
|
#define JOKER_TID (JOKER_STARTING_LAYER * JOKER_SPRITE_OFFSET)
|
|
#define JOKER_BASE_PB 4 // The starting palette index for the jokers, after the boss blind tokens
|
|
#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 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 LEGENDARY_JOKER 3
|
|
|
|
#define MAX_RARITIES (LEGENDARY_JOKER + 1)
|
|
|
|
// 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 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_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_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..)
|
|
};
|
|
|
|
// These are flags that can be combined into a single u32 and returned by
|
|
// JokerEffect functions to indicate which fields of the output JokerEffect are valid
|
|
|
|
#define JOKER_EFFECT_FLAG_NONE 0
|
|
#define JOKER_EFFECT_FLAG_CHIPS (1 << 0)
|
|
#define JOKER_EFFECT_FLAG_MULT (1 << 1)
|
|
#define JOKER_EFFECT_FLAG_XMULT (1 << 2)
|
|
#define JOKER_EFFECT_FLAG_MONEY (1 << 3)
|
|
#define JOKER_EFFECT_FLAG_RETRIGGER (1 << 4)
|
|
#define JOKER_EFFECT_FLAG_EXPIRE (1 << 5)
|
|
#define JOKER_EFFECT_FLAG_MESSAGE (1 << 6)
|
|
|
|
#define MAX_JOKER_OBJECTS 32 // The maximum number of joker objects that can be created at once
|
|
|
|
// Jokers in the game
|
|
#define STENCIL_JOKER_ID 15
|
|
#define SHORTCUT_JOKER_ID 48
|
|
#define BRAINSTORM_JOKER_ID 41
|
|
#define PAREIDOLIA_JOKER_ID 46
|
|
#define FOUR_FINGERS_JOKER_ID 50
|
|
#define BLUEPRINT_JOKER_ID 52
|
|
|
|
typedef struct
|
|
{
|
|
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...)
|
|
s32 scoring_state;
|
|
s32 persistent_state;
|
|
} Joker;
|
|
|
|
typedef struct JokerObject
|
|
{
|
|
Item; // First member struct inheritance
|
|
Joker* joker;
|
|
} JokerObject;
|
|
|
|
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!"
|
|
} 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
|
|
);
|
|
|
|
typedef int (*JokerDescFunc)(Joker* joker, Rect dest_rect);
|
|
|
|
typedef struct
|
|
{
|
|
const char* name;
|
|
u8 rarity;
|
|
u8 base_value;
|
|
bool is_desc_dynamic; // Is the little variable description at the bottom dynamic?
|
|
// Only used by the Misprint joker for now
|
|
JokerDescFunc joker_print_desc;
|
|
JokerEffectFunc joker_effect_func;
|
|
} JokerInfo;
|
|
const JokerInfo* get_joker_registry_entry(int joker_id);
|
|
size_t get_joker_registry_size(void);
|
|
|
|
void joker_init();
|
|
|
|
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
|
|
);
|
|
|
|
const char* joker_get_rarity_string(u8 rarity);
|
|
|
|
/**
|
|
* @brief Get Joker rarity panel color.
|
|
*
|
|
* The colors are organized in the `card_rarity_pal_gfx.png` file which is organized like this:
|
|
* - 0 -> transparency
|
|
* - 1,2 -> Common Joker
|
|
* - 3,4 -> Uncommon Joker
|
|
* - 5,6 -> Rare Joker
|
|
* - 7,8 -> Legendary Joker / Tarot Card
|
|
* - 9,10 -> Planet Card
|
|
* - 11,12 -> Spectral Card
|
|
* - 13,14 -> Voucher
|
|
*
|
|
* @param rarity Value of the rarity (Common, Rare...)
|
|
* @param main_color Whether we want the main or shadow color
|
|
* @return u16 value of the color, not a pointer
|
|
*/
|
|
u16 joker_get_rarity_color(u8 rarity, bool main_color);
|
|
|
|
int joker_get_sell_value(const Joker* joker);
|
|
|
|
JokerObject* joker_object_new(Joker* joker);
|
|
void joker_object_destroy(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);
|
|
|
|
/**
|
|
* @brief Returns the buy price of the joker object.
|
|
*
|
|
* @param joker_object the joker object whose price to return.
|
|
*
|
|
* @return UNDEFINED in case of error, the buy price of the joker otherwise.
|
|
*/
|
|
int joker_object_get_buy_price(Item* joker_object);
|
|
|
|
// TODO: Move to an owned_jokers.c/.h file?
|
|
/**
|
|
* @brief Add a Joker to the list of owned Jokers and place it in the joker row.
|
|
*
|
|
* @param joker_object The JokerObject to add cast to Item*
|
|
*/
|
|
void joker_object_add_to_owned(Item* joker_object);
|
|
|
|
/**
|
|
* @brief Destroy a JokerObject item, free its resources, and make it available to be rolled.
|
|
*
|
|
* @param joker_object Pointer to the JokerObject Item* to destroy; set to NULL.
|
|
*/
|
|
void joker_object_dispose(Item** joker_object);
|
|
|
|
/**
|
|
* @brief Set whether a Joker is available to be rolled for the shop, packs, etc.
|
|
*
|
|
* @param joker_id The ID of the joker whose availability to set.
|
|
* @param rollable true to make it rollable, false otherwise.
|
|
*/
|
|
void joker_set_rollable(int joker_id, bool rollable);
|
|
|
|
/**
|
|
* @brief Reset rollable jokers to include all jokers in the registry.
|
|
*/
|
|
void joker_reset_rollable_jokers(void);
|
|
|
|
/**
|
|
* @brief Roll and create a new JokerObject item.
|
|
*
|
|
* @return Newly created `Item*` (JokerObject) or NULL if none available.
|
|
*/
|
|
Item* joker_object_roll_new(void);
|
|
|
|
// 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
|
|
);
|
|
|
|
Sprite* joker_object_get_sprite(JokerObject* joker_object);
|
|
int joker_get_random_rarity();
|
|
|
|
#endif // JOKER_H
|