From 414bfa2a328f27f515a0b57c91d462e9bc2691f8 Mon Sep 17 00:00:00 2001 From: cellos51 Date: Sun, 20 Jul 2025 20:55:11 -0400 Subject: [PATCH] Semi functional jokers --- include/game.h | 2 +- include/graphic_utils.h | 2 +- include/joker.h | 1 + source/game.c | 126 ++++++++++++++++++++++++++++++---------- source/joker.c | 21 +++++++ 5 files changed, 119 insertions(+), 33 deletions(-) diff --git a/include/game.h b/include/game.h index 818ae41..e830ecd 100644 --- a/include/game.h +++ b/include/game.h @@ -3,7 +3,7 @@ #define MAX_HAND_SIZE 16 #define MAX_DECK_SIZE 52 -#define MAX_JOKERS_SIZE 5 // This doesn't account for negatives right now. +#define MAX_JOKERS_HELD_SIZE 5 // This doesn't account for negatives right now. #define MAX_SHOP_JOKERS 2 // TODO: Make this dynamic and allow for other items besides jokers #define MAX_SELECTION_SIZE 5 #define FRAMES(x) (((x) + game_speed - 1) / game_speed) diff --git a/include/graphic_utils.h b/include/graphic_utils.h index 06683ea..1ef76c4 100644 --- a/include/graphic_utils.h +++ b/include/graphic_utils.h @@ -15,7 +15,7 @@ * Screen Base Block is the base for the screenblock entries i.e. tilemap * Character Base Block is the base for the tiles themselves */ -#define MAIN_BG_SBB 29 +#define MAIN_BG_SBB 31 #define MAIN_BG_CBB 1 #define TTE_SBB 30 #define TTE_CBB 0 diff --git a/include/joker.h b/include/joker.h index 4f60e76..38948db 100644 --- a/include/joker.h +++ b/include/joker.h @@ -34,6 +34,7 @@ typedef struct u8 modifier; // base, foil, holo, poly, negative u8 value; u8 rarity; + bool proccessed; } Joker; typedef struct // copy of CardObject in card.h diff --git a/source/game.c b/source/game.c index 9a39749..73234e4 100644 --- a/source/game.c +++ b/source/game.c @@ -68,6 +68,9 @@ static int card_focused = 0; static bool sort_by_suit = false; // Stacks +static JokerObject *jokers[MAX_JOKERS_HELD_SIZE] = {NULL}; +static int jokers_top = -1; + static CardObject *played[MAX_SELECTION_SIZE] = {NULL}; static int played_top = -1; @@ -80,8 +83,18 @@ static int deck_top = -1; static Card *discard_pile[MAX_DECK_SIZE] = {NULL}; static int discard_top = -1; -static JokerObject *jokers[MAX_JOKERS] = {NULL}; -static int jokers_top = -1; +// Joker stack +static inline void joker_push(JokerObject *joker) +{ + if (jokers_top >= MAX_JOKERS_HELD_SIZE - 1) return; + jokers[++jokers_top] = joker; +} + +static inline JokerObject *joker_pop() +{ + if (jokers_top < 0) return NULL; + return jokers[jokers_top--]; +} // Played stack static inline void played_push(CardObject *card_object) @@ -122,18 +135,6 @@ static inline Card *discard_pop() return discard_pile[discard_top--]; } -static inline void joker_push(JokerObject *joker) -{ - if (jokers_top >= MAX_JOKERS_SIZE - 1) return; - jokers[++jokers_top] = joker; -} - -static inline JokerObject *joker_pop() -{ - if (jokers_top < 0) return NULL; - return jokers[jokers_top--]; -} - // Consts // Rects left top right bottom @@ -1156,15 +1157,15 @@ static void cards_in_hand_update_loop(bool* discarded_card, int* played_selectio case HAND_SELECT: if (i == card_focused && !hand[i]->selected) { - hand_y -= (10 << FIX_SHIFT); + hand_y -= int2fx(10); } else if (i != card_focused && hand[i]->selected) { - hand_y -= (15 << FIX_SHIFT); + hand_y -= int2fx(15); } else if (i == card_focused && hand[i]->selected) { - hand_y -= (20 << FIX_SHIFT); + hand_y -= int2fx(20); } if (i != card_focused && hand[i]->y > hand_y) @@ -1214,11 +1215,11 @@ static void cards_in_hand_update_loop(bool* discarded_card, int* played_selectio { if (hand_state == HAND_DISCARD) { - hand_y -= (15 << FIX_SHIFT); // Don't raise the card if we're mass discarding, it looks stupid. + hand_y -= int2fx(15); // Don't raise the card if we're mass discarding, it looks stupid. } else { - hand_y += (24 << FIX_SHIFT); + hand_y += int2fx(24); } hand_x = hand_x + (int2fx(i) - int2fx(hand_top) / 2) * -spacing_lut[hand_top]; } @@ -1241,7 +1242,7 @@ static void cards_in_hand_update_loop(bool* discarded_card, int* played_selectio break; case HAND_PLAY: hand_x = hand_x + (int2fx(i) - int2fx(hand_top) / 2) * -spacing_lut[hand_top]; - hand_y += (24 << FIX_SHIFT); + hand_y += int2fx(24); if (hand[i]->selected && *discarded_card == false && timer % FRAMES(10) == 0) { @@ -1417,7 +1418,7 @@ static void cards_in_hand_update_loop(bool* discarded_card, int* played_selectio break; case HAND_PLAYING: // Don't need to do anything here, just wait for the player to select cards hand_x = hand_x + (int2fx(i) - int2fx(hand_top) / 2) * -spacing_lut[hand_top]; - hand_y += (24 << FIX_SHIFT); + hand_y += int2fx(24); break; } @@ -1464,7 +1465,7 @@ static void played_cards_update_loop(bool* discarded_card, int* played_selection if (played[i]->selected && played_top - i >= *played_selections) { - played_y -= (10 << FIX_SHIFT); + played_y -= int2fx(10); } break; case PLAY_SCORING: @@ -1501,6 +1502,64 @@ static void played_cards_update_loop(bool* discarded_card, int* played_selection if (j == 0 && 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++) + { + if (jokers[k]->joker->proccessed == false) + { + IndependentEffect joker_effect = joker_independent_effect(jokers[k]->joker); + IndependentEffect zero_effect = {0}; + + 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->proccessed = 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 + } + } + } + + for (int k = 0; k <= jokers_top; k++) + { + if (jokers[k] != NULL) + { + jokers[k]->joker->proccessed = false; // Reset the joker's processed state for the next round + } + } + play_state = PLAY_ENDING; timer = 0; *played_selections = played_top + 1; // Reset the played selections to the top of the played stack @@ -1511,7 +1570,7 @@ static void played_cards_update_loop(bool* discarded_card, int* played_selection if (played[i]->selected) { - played_y -= (10 << FIX_SHIFT); + played_y -= int2fx(10); } break; case PLAY_ENDING: // This is the reverse of PLAY_PLAYING. The cards get reset back to their neutral position sequentially @@ -1528,7 +1587,7 @@ static void played_cards_update_loop(bool* discarded_card, int* played_selection if (played[i]->selected && played_top - i <= *played_selections - 1) { - played_y -= (10 << FIX_SHIFT); + played_y -= int2fx(10); } break; case PLAY_ENDED: // Basically a copy of HAND_DISCARD @@ -1596,21 +1655,26 @@ static void played_cards_update_loop(bool* discarded_card, int* played_selection static void held_jokers_update_loop() { - const int spacing_lut[MAX_HAND_SIZE] = { 26, 26, 26, 26, 20 }; + const int spacing_lut[MAX_JOKERS_HELD_SIZE][MAX_JOKERS_HELD_SIZE] = + { + {0, 0, 0, 0, 0}, + {13, -13, 0, 0, 0}, + {26, 0, -26, 0, 0}, + {39, 13, -13, -39, 0}, + {40, 20, 0, -20, -40} + }; FIXED hand_x = int2fx(108); FIXED hand_y = int2fx(10); - for (int i = 0; i < jokers_top + 1; i++) + for (int i = jokers_top; i >= 0; i--) { - if (jokers[i] == NULL) continue; - - jokers[i]->tx = hand_x + (int2fx(i) - int2fx(jokers_top) / 2) * -spacing_lut[jokers_top]; + jokers[i]->tx = hand_x - int2fx(spacing_lut[jokers_top][i]); jokers[i]->ty = hand_y; if (jokers[i]->selected) { - jokers[i]->ty -= (10 << FIX_SHIFT); + jokers[i]->ty -= int2fx(10); } joker_object_update(jokers[i]); @@ -2146,7 +2210,7 @@ void game_shop() { shop_jokers[i]->ty = int2fx(61); - if (key_hit(KEY_A) && jokers_top < MAX_JOKERS_SIZE - 1) + if (key_hit(KEY_A) && jokers_top < MAX_JOKERS_HELD_SIZE - 1) { joker_push(shop_jokers[i]); shop_jokers[i] = NULL; // Remove the joker from the shop diff --git a/source/joker.c b/source/joker.c index 8e6f392..e5eabd1 100644 --- a/source/joker.c +++ b/source/joker.c @@ -37,6 +37,7 @@ Joker *joker_new(u8 id) joker->modifier = BASE_EDITION; // TODO: Make this random later joker->value = joker_data_lut[id][1]; joker->rarity = joker_data_lut[id][0]; + joker->proccessed = false; return joker; } @@ -48,6 +49,25 @@ void joker_destroy(Joker **joker) *joker = NULL; } +IndependentEffect joker_independent_effect(Joker *joker) +{ + IndependentEffect effect = {0}; + + switch (joker->id) + { + case DEFAULT_JOKER_ID: // Default Joker + effect.mult = 4; + break; + case GREEDY_JOKER_ID: // Greedy Joker + // Nothing because this joker is a scored type + break; + default: + break; + } + + return effect; +} + // JokerObject methods JokerObject *joker_object_new(Joker *joker) { @@ -85,6 +105,7 @@ JokerObject *joker_object_new(Joker *joker) joker_object->trotation = float2fx(0.0f); // Target rotation joker_object->rotation = float2fx(0.0f); joker_object->vrotation = float2fx(0.0f); + joker_object->selected = false; return joker_object; }