Refactor JokerEffect scoring (#245)

* Remove usage of memcmp for JokerEffect null check

* Added suggestions from @ricfehr3

* Add suggestions from @MeirGavish


---------

Co-authored-by: MathisMartin31 <mathis.martin31@gmail.com>
Co-authored-by: MeirGavish <meir.gavish@gmail.com>
This commit is contained in:
Geralt
2025-11-28 18:03:47 +01:00
committed by GitHub
parent 1cacabdff6
commit 435a9a0a1d
3 changed files with 462 additions and 302 deletions
+20 -5
View File
@@ -61,6 +61,18 @@ enum JokerEvent
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
@@ -98,15 +110,18 @@ typedef struct // These jokers are triggered after the played hand has finished
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; // Joker is destroyed (food jokers)
char* message; // Used to send custom messages e.g. "Extinct" or "-1" (Bananas and food Jokers)
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;
typedef JokerEffect (*JokerEffectFunc)(Joker *joker, Card *scored_card, enum JokerEvent joker_event);
// 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 {
u8 rarity;
u8 base_value;
JokerEffectFunc joker_effect;
JokerEffectFunc joker_effect_func;
} JokerInfo;
const JokerInfo* get_joker_registry_entry(int joker_id);
size_t get_joker_registry_size(void);
@@ -118,7 +133,7 @@ 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
JokerEffect joker_get_score_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event);
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);
+27 -28
View File
@@ -149,7 +149,8 @@ Joker *joker_new(u8 id)
joker->persistent_state = 0;
// initialize persistent Joker data if needed
jinfo->joker_effect(joker, NULL, JOKER_EVENT_ON_JOKER_CREATED);
JokerEffect *joker_effect = NULL;
jinfo->joker_effect_func(joker, NULL, JOKER_EVENT_ON_JOKER_CREATED, &joker_effect);
return joker;
}
@@ -160,12 +161,12 @@ void joker_destroy(Joker **joker)
*joker = NULL;
}
JokerEffect joker_get_score_effect(Joker *joker, Card *scored_card, enum JokerEvent joker_event)
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 (JokerEffect){0};
if (!jinfo) return JOKER_EFFECT_FLAG_NONE;
return jinfo->joker_effect(joker, scored_card, joker_event);
return jinfo->joker_effect_func(joker, scored_card, joker_event, joker_effect);
}
int joker_get_sell_value(const Joker* joker)
@@ -271,25 +272,18 @@ bool joker_object_score(JokerObject *joker_object, CardObject* card_object, enum
return false;
}
JokerEffect joker_effect = joker_get_score_effect(joker_object->joker, card_object->card, joker_event);
JokerEffect* joker_effect = NULL;
u32 effect_flags_ret = joker_get_score_effect(joker_object->joker, card_object->card, joker_event, &joker_effect);
if (memcmp(&joker_effect, &(JokerEffect){0}, sizeof(JokerEffect)) == 0)
if (effect_flags_ret == JOKER_EFFECT_FLAG_NONE)
{
return false;
}
// protect chips and mult against overflow
*chips = u32_protected_add(*chips, joker_effect.chips);
*mult = u32_protected_add(*mult, joker_effect.mult);
// If xMult is 0 DON'T multiply by it!
if (joker_effect.xmult > 0)
if (effect_flags_ret & JOKER_EFFECT_FLAG_RETRIGGER)
{
*mult = u32_protected_mult(*mult, joker_effect.xmult);
*retrigger = joker_effect->retrigger;
}
*money += joker_effect.money;
*retrigger = joker_effect.retrigger;
// joker_effect.message will have been set if the Joker had anything custom to say
int cursorPosX = TILE_SIZE; // Offset of one tile to better center the text on the card
int cursorPosY = 0;
@@ -307,41 +301,46 @@ bool joker_object_score(JokerObject *joker_object, CardObject* card_object, enum
}
mm_word sfx_id;
if (joker_effect.chips > 0)
if (effect_flags_ret & JOKER_EFFECT_FLAG_CHIPS)
{
*chips = u32_protected_add(*chips, joker_effect->chips);
char score_buffer[INT_MAX_DIGITS + 2]; // For '+' and null terminator
snprintf(score_buffer, sizeof(score_buffer), "+%lu", joker_effect.chips);
snprintf(score_buffer, sizeof(score_buffer), "+%lu", joker_effect->chips);
set_and_shift_text(score_buffer, &cursorPosX, &cursorPosY, TTE_BLUE_PB);
sfx_id = SFX_CHIPS_GENERIC; // The joker chips effect is "generic"
}
if (joker_effect.mult > 0)
if (effect_flags_ret & JOKER_EFFECT_FLAG_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);
snprintf(score_buffer, sizeof(score_buffer), "+%lu", joker_effect->mult);
set_and_shift_text(score_buffer, &cursorPosX, &cursorPosY, TTE_RED_PB);
sfx_id = SFX_MULT;
}
if (joker_effect.xmult > 0)
// 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);
char score_buffer[INT_MAX_DIGITS + 2];
snprintf(score_buffer, sizeof(score_buffer), "X%lu", joker_effect.xmult);
snprintf(score_buffer, sizeof(score_buffer), "X%lu", joker_effect->xmult);
set_and_shift_text(score_buffer, &cursorPosX, &cursorPosY, TTE_RED_PB);
sfx_id = SFX_XMULT;
}
if (joker_effect.money > 0)
if (effect_flags_ret & JOKER_EFFECT_FLAG_MONEY)
{
*money += joker_effect->money;
char score_buffer[INT_MAX_DIGITS + 2];
snprintf(score_buffer, sizeof(score_buffer), "%d$", joker_effect.money);
snprintf(score_buffer, sizeof(score_buffer), "%d$", joker_effect->money);
set_and_shift_text(score_buffer, &cursorPosX, &cursorPosY, TTE_YELLOW_PB);
// TODO: Money sound effect
}
// custom message for Jokers (including retriggers where Jokers will say "Again!")
if (joker_effect.message != NULL && joker_effect.message[0] != '\0') // Message is not empty
// joker_effect->message will have been set if the Joker had anything custom to say
if (effect_flags_ret & JOKER_EFFECT_FLAG_MESSAGE)
{
set_and_shift_text(joker_effect.message, &cursorPosX, &cursorPosY, TTE_WHITE_PB);
set_and_shift_text(joker_effect->message, &cursorPosX, &cursorPosY, TTE_WHITE_PB);
}
if (joker_effect.expire)
if (effect_flags_ret & JOKER_EFFECT_FLAG_EXPIRE && joker_effect->expire)
{
// TODO make Jokers expire
}
+415 -269
View File
File diff suppressed because it is too large Load Diff