Added greedy joker and refactor joker system

This commit is contained in:
cellos51
2025-07-22 20:00:05 -04:00
parent 62db2815dd
commit 1b4267893d
6 changed files with 109 additions and 77 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 864 B

After

Width:  |  Height:  |  Size: 1.5 KiB

+3 -3
View File
@@ -8,8 +8,8 @@
// Card suits
#define HEARTS 0
#define DIAMONDS 1
#define CLUBS 2
#define CLUBS 1
#define DIAMONDS 2
#define SPADES 3
#define NUM_SUITS 4
@@ -66,6 +66,6 @@ CardObject *card_object_new(Card *card);
void card_object_destroy(CardObject **card_object);
void card_object_update(CardObject *card_object); // Update the card object position and scale
void card_object_set_sprite(CardObject *card_object, int layer);
void card_object_score(CardObject *card_object, mm_word sound_id); // This doesn't actually score anything, it just performs an animation and plays a sound effect
void card_object_shake(CardObject *card_object, mm_word sound_id); // This doesn't actually score anything, it just performs an animation and plays a sound effect
#endif // CARD_H
+4 -13
View File
@@ -62,16 +62,7 @@ typedef struct // These jokers are triggered after the played hand has finished
int 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)
} IndependentEffect;
typedef struct
{
int chips;
int mult;
int xmult;
int money;
bool retrigger; // Retrigger scored card
} OnScoredEffect;
} JokerEffect;
void joker_init();
@@ -80,12 +71,12 @@ 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
IndependentEffect joker_independent_effect(Joker *joker);
OnScoredEffect joker_on_scored(Joker *joker, Card *scored_card);
JokerEffect joker_get_score_effect(Joker *joker, Card *scored_card);
JokerObject *joker_object_new(Joker *joker);
void joker_object_destroy(JokerObject **joker_object);
void joker_object_update(JokerObject *joker_object);
void joker_object_score(JokerObject *joker_object, mm_word sound_id); // 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); // This doesn't actually score anything, it just performs an animation and plays a sound effect
bool joker_object_score(JokerObject *joker_object, Card* scored_card, int *chips, int *mult, int *xmult, int *money, bool *retrigger); // This scores the joker and returns true if it was scored successfully (Card = NULL means the joker is independent and not scored by a card)
#endif // JOKER_H
+1 -1
View File
@@ -153,7 +153,7 @@ void card_object_set_sprite(CardObject *card_object, int layer)
card_object->sprite = sprite_new(ATTR0_SQUARE | ATTR0_4BPP | ATTR0_AFF, ATTR1_SIZE_32, card_sprite_lut[card_object->card->suit][card_object->card->rank], 0, layer);
}
void card_object_score(CardObject *card_object, mm_word sound_id)
void card_object_shake(CardObject *card_object, mm_word sound_id)
{
card_object->vscale = float2fx(0.3f); // Scale down the card when it's scored
card_object->vrotation = float2fx(8.0f); // Rotate the card when it's scored
+45 -55
View File
@@ -1549,82 +1549,70 @@ static void played_cards_update_loop(bool* discarded_card, int* played_selection
{
// So pretend "played_selections" is now called "scored_cards" and it counts the number of cards that have been scored
int scored_cards = 0;
for (int j = played_top; j >= 0; j--)
for (int j = 0; j <= played_top; j++)
{
if (played[played_top - j]->selected)
tte_erase_rect_wrapper(PLAYED_CARDS_SCORES_RECT);
if (*played_selections > 0)
{
scored_cards++;
for (int k = 0; k <= jokers_top; k++)
{
if (joker_object_score(jokers[k], played[*played_selections - 1]->card, &chips, &mult, NULL, &money, NULL)) // NULLs aren't implemented yet
{
set_chips(chips);
set_mult(mult);
set_money(money);
return;
}
}
}
if (played[j]->selected)
{
scored_cards = j + 1; // Count the number of cards that have been scored
if (scored_cards > *played_selections)
{
tte_erase_rect_wrapper(PLAYED_CARDS_SCORES_RECT);
tte_set_pos(fx2int(played[played_top - j]->x) + 8, 48); // Offset of 16 pixels to center the text on the card
for (int k = 0; k <= jokers_top; k++)
{
if (jokers[k] != NULL)
{
jokers[k]->joker->processed = false; // Reset the joker's processed state for the next score
}
}
tte_set_pos(fx2int(played[j]->x) + 8, 48); // Offset of 16 pixels to center the text on the card
tte_set_special(0xD000); // Set text color to blue from background memory
// Write the score to a character buffer variable
char score_buffer[5]; // Assuming the maximum score is 99, we need 4 characters (2 digits + null terminator)
snprintf(score_buffer, sizeof(score_buffer), "+%d", card_get_value(played[played_top - j]->card));
snprintf(score_buffer, sizeof(score_buffer), "+%d", card_get_value(played[j]->card));
tte_write(score_buffer);
*played_selections = scored_cards;
card_object_score(played[played_top - j], SFX_CARD_SELECT);
card_object_shake(played[j], SFX_CARD_SELECT);
// Relocated card scoring logic here
chips += card_get_value(played[played_top - j]->card);
chips += card_get_value(played[j]->card);
set_chips(chips);
break;
}
}
if (j == 0 && scored_cards == *played_selections) // Check if it's the last card
if (j == played_top && scored_cards == *played_selections) // Check if it's the last card
{
tte_erase_rect_wrapper(PLAYED_CARDS_SCORES_RECT);
for (int k = 0; k <= jokers_top; k++)
for (int k = 0; k <= jokers_top; k++) // Independent joker scoring loop
{
if (jokers[k]->joker->processed == false)
{
IndependentEffect joker_effect = joker_independent_effect(jokers[k]->joker);
IndependentEffect zero_effect = {0};
if (joker_object_score(jokers[k], NULL, &chips, &mult, NULL, &money, NULL)) // NULLs aren't implemented yet
{
set_chips(chips);
set_mult(mult);
set_money(money);
if (memcmp(&joker_effect, &zero_effect, sizeof(IndependentEffect)) != 0)
{
chips += joker_effect.chips;
set_chips(chips);
mult += joker_effect.mult;
set_mult(mult);
// TODO: XMult
money += joker_effect.money;
set_money(money);
// TODO: Retrigger
tte_set_pos(fx2int(jokers[k]->x) + 8, 48); // Offset of 16 pixels to center the text on the card
char score_buffer[12];
if (joker_effect.chips > 0)
{
tte_set_special(0xD000); // Blue
snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.chips);
}
else if (joker_effect.mult > 0)
{
tte_set_special(0xE000); // Red
snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.mult);
}
else if (joker_effect.money > 0)
{
tte_set_special(0xC000); // Yellow
snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.money);
}
tte_write(score_buffer);
jokers[k]->joker->processed = true; // Mark the joker as processed
joker_object_score(jokers[k], SFX_CARD_SELECT);
return; // Returning was just the easiest way to break out of the loop
}
return; // Returning was just the easiest way to break out of the loop
}
}
@@ -1805,7 +1793,9 @@ static void game_shop_create_items(JokerObject *shop_jokers[], bool first_time)
joker_object_destroy(&shop_jokers[i]); // Destroy the joker object if it exists
}
shop_jokers[i] = joker_object_new(joker_new(DEFAULT_JOKER_ID));
u8 joker_id = random() % MAX_JOKERS;
shop_jokers[i] = joker_object_new(joker_new(joker_id));
shop_jokers[i]->x = int2fx(120 + i * 32);
shop_jokers[i]->y = int2fx(160);
shop_jokers[i]->tx = shop_jokers[i]->x;
@@ -1818,7 +1808,7 @@ static void game_shop_create_items(JokerObject *shop_jokers[], bool first_time)
if (first_time == false)
{
shop_jokers[i]->y = shop_jokers[i]->ty; // If it's not the first time, set the y position to the target position
joker_object_score(shop_jokers[i], UNDEFINED); // Give the joker a little wiggle animation
joker_object_shake(shop_jokers[i], UNDEFINED); // Give the joker a little wiggle animation
}
sprite_position(shop_jokers[i]->sprite, fx2int(shop_jokers[i]->x), fx2int(shop_jokers[i]->y));
+56 -5
View File
@@ -4,9 +4,11 @@
#include "joker_gfx.h"
#include "graphic_utils.h"
#include "card.h"
#include "soundbank.h"
#include <maxmod.h>
#include <stdlib.h>
#include <string.h>
const static u8 joker_data_lut[MAX_JOKERS][2] = // Rarity, Value
{
@@ -58,17 +60,21 @@ void joker_destroy(Joker **joker)
*joker = NULL;
}
IndependentEffect joker_independent_effect(Joker *joker)
JokerEffect joker_get_score_effect(Joker *joker, Card *scored_card)
{
IndependentEffect effect = {0};
JokerEffect effect = {0};
switch (joker->id)
{
case DEFAULT_JOKER_ID: // Default Joker
if (scored_card != NULL) break; // Joker is independent, no effect
effect.mult = 4;
break;
case GREEDY_JOKER_ID: // Greedy Joker
// Nothing because this joker is a scored type
if (scored_card->suit == DIAMONDS) // If the scored card is a diamond
{
effect.mult = 3;
}
break;
default:
break;
@@ -139,8 +145,53 @@ void joker_object_update(JokerObject *joker_object)
card_object_update(card_object);
}
void joker_object_score(JokerObject *joker_object, mm_word sound_id) // Another derived function of card_object
void joker_object_shake(JokerObject *joker_object, mm_word sound_id)
{
CardObject *card_object = (CardObject *)joker_object;
card_object_score(card_object, sound_id);
card_object_shake(card_object, sound_id);
}
bool joker_object_score(JokerObject *joker_object, Card* scored_card, int *chips, int *mult, int *xmult, int *money, bool *retrigger)
{
if (joker_object->joker->processed == true) return false; // If the joker has already been processed, return false
JokerEffect joker_effect = joker_get_score_effect(joker_object->joker, scored_card);
if (memcmp(&joker_effect, &(JokerEffect){0}, sizeof(JokerEffect)) != 0)
{
*chips += joker_effect.chips;
*mult += joker_effect.mult;
// TODO: XMult
*money += joker_effect.money;
// TODO: Retrigger
tte_set_pos(fx2int(joker_object->x) + 8, 48); // Offset of 16 pixels to center the text on the card
char score_buffer[12];
if (joker_effect.chips > 0)
{
tte_set_special(0xD000); // Blue
snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.chips);
}
else if (joker_effect.mult > 0)
{
tte_set_special(0xE000); // Red
snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.mult);
}
else if (joker_effect.money > 0)
{
tte_set_special(0xC000); // Yellow
snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.money);
}
tte_write(score_buffer);
joker_object->joker->processed = true; // Mark the joker as processed
joker_object_shake(joker_object, SFX_CARD_SELECT); // TODO: Add a sound effect for scoring the joker
return true;
}
return false;
}