diff --git a/include/joker.h b/include/joker.h index cf9a04a..9a21249 100644 --- a/include/joker.h +++ b/include/joker.h @@ -35,6 +35,14 @@ #define RARE_JOKER 2 #define LEGENDARY_JOKER 3 +// 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 + #define MAX_JOKER_OBJECTS 32 // The maximum number of joker objects that can be created at once #define DEFAULT_JOKER_ID 0 @@ -96,5 +104,6 @@ void joker_object_set_selected(JokerObject* joker_object, bool selected); bool joker_object_is_selected(JokerObject* joker_object); Sprite* joker_object_get_sprite(JokerObject* joker_object); +int joker_get_random_rarity(); #endif // JOKER_H diff --git a/source/game.c b/source/game.c index c3e8363..b0927d2 100644 --- a/source/game.c +++ b/source/game.c @@ -2476,6 +2476,42 @@ void erase_price_under_sprite_object(SpriteObject *sprite_object) tte_erase_rect_wrapper(price_rect); } +static int game_shop_get_random_joker_idx() +{ + // Roll for what rarity the joker will be + int joker_rarity = joker_get_random_rarity(); + + // Now determine how many jokers are available based on the rarity + int jokers_avail_size = list_get_size(jokers_available_to_shop); + int matching_indices[jokers_avail_size]; + int match_count = 0; + + for (int i = 0; i < jokers_avail_size; i++) + { + intptr_t joker_id = int_list_get(jokers_available_to_shop, i); + const JokerInfo *info = get_joker_registry_entry(joker_id); + if (info->rarity == joker_rarity) + { + matching_indices[match_count] = i; + match_count++; + } + } + + int selected_joker_idx = 0; + if (match_count > 0) + { + // If we counted at least one joker with matching rarity, pick one of them randomly + selected_joker_idx = matching_indices[random() % match_count]; + } + else + { + // Didn't find any jokers of matching rarity, just pick one at random instead + selected_joker_idx = random() % jokers_avail_size; + } + + return selected_joker_idx; +} + static void game_shop_create_items() { tte_erase_rect_wrapper(SHOP_PRICES_TEXT_RECT); @@ -2489,7 +2525,6 @@ static void game_shop_create_items() for (int i = 0; i < MAX_SHOP_JOKERS; i++) { - int joker_idx = 0; intptr_t joker_id = 0; #ifdef TEST_JOKER_ID0 // Allow defining an ID for a joker to always appear in shop and be tested if (int_list_exists(jokers_available_to_shop, TEST_JOKER_ID0)) @@ -2508,9 +2543,8 @@ static void game_shop_create_items() else #endif { - joker_idx = random() % list_get_size(jokers_available_to_shop); - joker_id = int_list_get(jokers_available_to_shop, joker_idx); - // TODO: weight the random choice by joker rarity + int joker_idx = game_shop_get_random_joker_idx(); + joker_id = int_list_get(jokers_available_to_shop, joker_idx); list_remove_by_idx(jokers_available_to_shop, joker_idx); } diff --git a/source/joker.c b/source/joker.c index c0d1b7e..b248a87 100644 --- a/source/joker.c +++ b/source/joker.c @@ -332,3 +332,27 @@ Sprite* joker_object_get_sprite(JokerObject* joker_object) return NULL; return sprite_object_get_sprite(joker_object->sprite_object); } + +int joker_get_random_rarity() +{ + int joker_rarity = 0; + int rarity_roll = random() % 100; + if (rarity_roll < COMMON_JOKER_CHANCE) + { + joker_rarity = COMMON_JOKER; + } + else if (rarity_roll < COMMON_JOKER_CHANCE + UNCOMMON_JOKER_CHANCE) + { + joker_rarity = UNCOMMON_JOKER; + } + else if (rarity_roll < COMMON_JOKER_CHANCE + UNCOMMON_JOKER_CHANCE + RARE_JOKER_CHANCE) + { + joker_rarity = RARE_JOKER; + } + else if (rarity_roll < COMMON_JOKER_CHANCE + UNCOMMON_JOKER_CHANCE + RARE_JOKER_CHANCE + LEGENDARY_JOKER_CHANCE) + { + joker_rarity = LEGENDARY_JOKER; + } + + return joker_rarity; +}