diff --git a/graphics/joker_gfx11.png b/graphics/joker_gfx11.png index 07b537c..2bc36d4 100644 Binary files a/graphics/joker_gfx11.png and b/graphics/joker_gfx11.png differ diff --git a/graphics/joker_gfx12.grit b/graphics/joker_gfx12.grit new file mode 100644 index 0000000..a8ac3f6 --- /dev/null +++ b/graphics/joker_gfx12.grit @@ -0,0 +1 @@ +-gB4 -Mw4 -Mh4 -m! -pn 16 \ No newline at end of file diff --git a/graphics/joker_gfx12.png b/graphics/joker_gfx12.png new file mode 100644 index 0000000..5d78c20 Binary files /dev/null and b/graphics/joker_gfx12.png differ diff --git a/graphics/joker_gfx13.grit b/graphics/joker_gfx13.grit new file mode 100644 index 0000000..a8ac3f6 --- /dev/null +++ b/graphics/joker_gfx13.grit @@ -0,0 +1 @@ +-gB4 -Mw4 -Mh4 -m! -pn 16 \ No newline at end of file diff --git a/graphics/joker_gfx13.png b/graphics/joker_gfx13.png new file mode 100644 index 0000000..ce7f8fe Binary files /dev/null and b/graphics/joker_gfx13.png differ diff --git a/include/card.h b/include/card.h index 2b003b6..e403b33 100644 --- a/include/card.h +++ b/include/card.h @@ -35,6 +35,8 @@ #define NUM_RANKS 13 #define RANK_OFFSET 2 // Because the first rank is 2 and ranks start at 0 +#define IMPOSSIBLY_HIGH_CARD_VALUE 100 + // Card types typedef struct { diff --git a/include/game.h b/include/game.h index c4789ac..01c7d3d 100644 --- a/include/game.h +++ b/include/game.h @@ -89,6 +89,8 @@ CardObject** get_played_array(void); int get_played_top(void); List* get_jokers(void); +int get_deck_top(void); int get_num_discards_remaining(void); +int get_money(void); #endif // GAME_H diff --git a/include/graphic_utils.h b/include/graphic_utils.h index 5162b16..2f32db5 100644 --- a/include/graphic_utils.h +++ b/include/graphic_utils.h @@ -47,6 +47,7 @@ // Tile size in pixels, both height and width as tiles are square #define TILE_SIZE 8 +#define EFFECT_TEXT_SEPARATION_AMOUNT 32; // If we need to show multiple effects at once // By default TTE characters occupy a single tile #define TTE_CHAR_SIZE TILE_SIZE diff --git a/include/joker_gfx.h b/include/joker_gfx.h index 75cfbbc..ce1c916 100644 --- a/include/joker_gfx.h +++ b/include/joker_gfx.h @@ -13,5 +13,7 @@ #include "joker_gfx9.h" #include "joker_gfx10.h" #include "joker_gfx11.h" +#include "joker_gfx12.h" +#include "joker_gfx13.h" #endif \ No newline at end of file diff --git a/source/game.c b/source/game.c index dac13ea..dd19796 100644 --- a/source/game.c +++ b/source/game.c @@ -78,6 +78,7 @@ static bool sort_by_suit = false; static List *jokers = NULL; static List *discarded_jokers = NULL; +static List* jokers_available_to_shop; // List of joker IDs // Stacks static CardObject *played[MAX_SELECTION_SIZE] = {NULL}; @@ -157,7 +158,20 @@ List *get_jokers(void) { return jokers; } -List *jokers_available_to_shop; // List of joker IDs + + +int get_deck_top(void) { + return deck_top; +} + +int get_num_discards_remaining(void) { + return discards; +} + +int get_money(void) { + return money; +} + // Consts @@ -241,10 +255,6 @@ static const BG_POINT JOKER_DISCARD_TARGET = {240, 30}; #define PITCH_STEP_UNDISCARD_SFX 2*PITCH_STEP_DRAW_SFX // Naming the stage where cards return from the discard pile to the deck "undiscard" -int get_num_discards_remaining(void) { - return discards; -} - // General functions void set_seed(int seed) { diff --git a/source/joker.c b/source/joker.c index 867d608..6ec320b 100644 --- a/source/joker.c +++ b/source/joker.c @@ -130,6 +130,8 @@ void joker_init() joker_gfxTiles[9] = joker_gfx9Tiles; joker_gfxTiles[10] = joker_gfx10Tiles; joker_gfxTiles[11] = joker_gfx11Tiles; + joker_gfxTiles[12] = joker_gfx12Tiles; + joker_gfxTiles[13] = joker_gfx13Tiles; joker_gfxPal[0] = joker_gfx0Pal; joker_gfxPal[1] = joker_gfx1Pal; @@ -143,6 +145,8 @@ void joker_init() joker_gfxPal[9] = joker_gfx9Pal; joker_gfxPal[10] = joker_gfx10Pal; joker_gfxPal[11] = joker_gfx11Pal; + joker_gfxPal[12] = joker_gfx12Pal; + joker_gfxPal[13] = joker_gfx13Pal; for (int i = 0; i < num_spritesheets; i++) { diff --git a/source/joker_effects.c b/source/joker_effects.c index 84d3046..155c850 100644 --- a/source/joker_effects.c +++ b/source/joker_effects.c @@ -294,30 +294,228 @@ static JokerEffect blackboard_joker_effect(Joker *joker, Card *scored_card) { return effect; } +static JokerEffect blue_joker_effect(Joker *joker, Card *scored_card) { + JokerEffect effect = {0}; + if (scored_card != NULL) + return effect; // if card != null, we are not at the end-phase of scoring yet + + effect.chips = (get_deck_top() + 1) * 2; + + return effect; +} + +// Using __attribute__((unused)) for jokers with no sprites yet to avoid warning +// Remove the attribute once they have sprites +__attribute__((unused)) +static JokerEffect raised_fist_joker_effect(Joker *joker, Card *scored_card) +{ + JokerEffect effect = {0}; + if (scored_card != NULL) + return effect; // if card != null, we are not at the end-phase of scoring yet + + // Find the lowest rank card in hand + // Aces are always considered high value, even in an ace-low straight + 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) + lowest_value = value; + } + + if (lowest_value != IMPOSSIBLY_HIGH_CARD_VALUE) + effect.mult = lowest_value * 2; + + return effect; +} + +__attribute__((unused)) +static JokerEffect reserved_parking_joker_effect(Joker *joker, Card *scored_card) { + JokerEffect effect = {0}; + if (scored_card != NULL) + return effect; // if card != null, we are not at the end-phase of scoring yet + + CardObject** hand = get_hand_array(); + int hand_size = hand_get_size(); + for (int i = 0; i < hand_size; i++ ) + { + switch (hand[i]->card->rank) { + case KING: case QUEEN: case JACK: + if (random() % 2 == 0) + effect.money += 1; + default: + break; + } + } + + return effect; +}; + +static JokerEffect business_card_joker_effect(Joker *joker, Card *scored_card) { + JokerEffect effect = {0}; + if (scored_card == NULL) + return effect; + + switch (scored_card->rank) { + case KING: case QUEEN: case JACK: + if (random() % 2 == 0) + effect.money = 2; + default: + break; + } + + return effect; +} + +static JokerEffect scholar_joker_effect(Joker *joker, Card *scored_card) { + JokerEffect effect = {0}; + if (scored_card == NULL) + return effect; + + if (scored_card->rank == ACE) { + effect.chips = 20; + effect.mult = 4; + } + + return effect; +} + +__attribute__((unused)) +static JokerEffect scary_face_joker_effect(Joker *joker, Card *scored_card) { + JokerEffect effect = {0}; + if (scored_card == NULL) + return effect; + + switch (scored_card->rank) { + case KING: case QUEEN: case JACK: + effect.chips = 30; + default: + break; + } + + return effect; +} + + __attribute__((unused)) +static JokerEffect abstract_joker_effect(Joker *joker, Card *scored_card) { + JokerEffect effect = {0}; + if (scored_card != NULL) + return effect; // if card != null, we are not at the end-phase of scoring yet + + // +1 xmult per occupied joker slot + int num_jokers = list_get_size(get_jokers()); + effect.mult = num_jokers * 3; + + return effect; +} + +__attribute__((unused)) +static JokerEffect bull_joker_effect(Joker *joker, Card *scored_card) { + JokerEffect effect = {0}; + if (scored_card != NULL) + return effect; // if card != null, we are not at the end-phase of scoring yet + + effect.chips = get_money() * 2; + + return effect; +} + +__attribute__((unused)) +static JokerEffect smiley_face_joker_effect(Joker *joker, Card *scored_card) { + JokerEffect effect = {0}; + if (scored_card == NULL) + return effect; + + switch (scored_card->rank) { + case KING: case QUEEN: case JACK: + effect.mult = 5; + default: + break; + } + + return effect; +} + +static JokerEffect even_steven_joker_effect(Joker *joker, Card *scored_card) { + JokerEffect effect = {0}; + if (scored_card == NULL) + return effect; + + if (card_get_value(scored_card) % 2 == 0) { + switch (scored_card->rank) { + case KING: case QUEEN: case JACK: + break; + default: + effect.mult = 4; + } + } + + return effect; +} + +static JokerEffect odd_todd_joker_effect(Joker *joker, Card *scored_card) { + JokerEffect effect = {0}; + if (scored_card == NULL) + return effect; + + if (card_get_value(scored_card) % 2 == 1) // todo test ace + effect.chips = 31; + + return effect; +} + +/* 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. + * Each consecutive NUM_JOKERS_PER_SPRITESHEET (defined in joker.c) jokers + * share a spritesheet and thus a color palette. + * To make better use of color palettes jokers may be rearranged here + * (and put together in the matching spritesheet) to share a color palette. + * Otherwise the order is similar to the wiki. + */ const JokerInfo joker_registry[] = { { COMMON_JOKER, 2, default_joker_effect }, // DEFAULT_JOKER_ID = 0 - { COMMON_JOKER, 5, greedy_joker_effect }, // GREEDY_JOKER_ID = 1 - { COMMON_JOKER, 5, lusty_joker_effect }, // etc... - { COMMON_JOKER, 5, wrathful_joker_effect }, - { COMMON_JOKER, 5, gluttonous_joker_effect }, - { COMMON_JOKER, 3, jolly_joker_effect }, - { COMMON_JOKER, 4, zany_joker_effect }, - { COMMON_JOKER, 4, mad_joker_effect }, - { COMMON_JOKER, 4, crazy_joker_effect }, - { COMMON_JOKER, 4, droll_joker_effect }, - { COMMON_JOKER, 3, sly_joker_effect }, - { COMMON_JOKER, 4, wily_joker_effect }, - { COMMON_JOKER, 4, clever_joker_effect }, - { COMMON_JOKER, 4, devious_joker_effect }, - { COMMON_JOKER, 4, crafty_joker_effect }, - { COMMON_JOKER, 5, half_joker_effect }, - { UNCOMMON_JOKER, 8, joker_stencil_effect }, - { COMMON_JOKER, 5, banner_joker_effect }, - { COMMON_JOKER, 4, walkie_talkie_joker_effect }, - { UNCOMMON_JOKER, 8, fibonnaci_joker_effect }, - { UNCOMMON_JOKER, 6, blackboard_joker_effect }, - { COMMON_JOKER, 5, mystic_summit_joker_effect }, - { COMMON_JOKER, 4, misprint_joker_effect }, + { COMMON_JOKER, 5, greedy_joker_effect }, // GREEDY_JOKER_ID = 1 + { COMMON_JOKER, 5, lusty_joker_effect }, // etc... 2 + { COMMON_JOKER, 5, wrathful_joker_effect }, // 3 + { COMMON_JOKER, 5, gluttonous_joker_effect }, // 4 + { COMMON_JOKER, 3, jolly_joker_effect }, // 5 + { COMMON_JOKER, 4, zany_joker_effect }, // 6 + { COMMON_JOKER, 4, mad_joker_effect }, // 7 + { COMMON_JOKER, 4, crazy_joker_effect }, // 8 + { COMMON_JOKER, 4, droll_joker_effect }, // 9 + { COMMON_JOKER, 3, sly_joker_effect }, // 10 + { COMMON_JOKER, 4, wily_joker_effect }, // 11 + { COMMON_JOKER, 4, clever_joker_effect }, // 12 + { COMMON_JOKER, 4, devious_joker_effect }, // 13 + { COMMON_JOKER, 4, crafty_joker_effect }, // 14 + { COMMON_JOKER, 5, half_joker_effect }, // 15 + { UNCOMMON_JOKER, 8, joker_stencil_effect }, // 16 + { COMMON_JOKER, 5, banner_joker_effect }, // 17 + { COMMON_JOKER, 4, walkie_talkie_joker_effect }, // 18 + { UNCOMMON_JOKER, 8, fibonnaci_joker_effect }, // 19 + { UNCOMMON_JOKER, 6, blackboard_joker_effect }, // 20 + { COMMON_JOKER, 5, mystic_summit_joker_effect }, // 21 + { COMMON_JOKER, 4, misprint_joker_effect }, // 22 + { COMMON_JOKER, 4, even_steven_joker_effect }, // 23 + { COMMON_JOKER, 5, blue_joker_effect }, // 24 + { COMMON_JOKER, 4, odd_todd_joker_effect }, // 25 + { COMMON_JOKER, 4, scholar_joker_effect }, // 26 + { COMMON_JOKER, 4, business_card_joker_effect }, // 27 + // Business card should be paired with Shortcut for palette optimization when it's added + + // The following jokers don't have sprites yet, + // uncomment them when their sprites are added. +#if 0 + { COMMON_JOKER, 5, raised_fist_joker_effect }, + { COMMON_JOKER, 6, reserved_parking_joker_effect }, + { COMMON_JOKER, 4, scary_face_joker_effect }, + { COMMON_JOKER, 4, abstract_joker_effect }, + { UNCOMMON_JOKER, 6, bull_joker_effect}, + { COMMON_JOKER, 4, smiley_face_joker_effect }, +#endif }; static const size_t joker_registry_size = NUM_ELEM_IN_ARR(joker_registry);