Merge pull request #92 from cellos51/joker_pooling
Joker pooling + Shop code refactor
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
#ifndef LIST_H
|
||||
#define LIST_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Defining an int list for simplicity
|
||||
* If another list is needed, a generic void*
|
||||
* list should be defined....
|
||||
*/
|
||||
typedef struct IntList
|
||||
{
|
||||
int* _array;
|
||||
int size;
|
||||
int allocated_size;
|
||||
} IntList;
|
||||
|
||||
IntList *int_list_new(int init_size);
|
||||
void int_list_destroy(IntList **list);
|
||||
bool int_list_append(IntList *list, int value);
|
||||
bool int_list_remove_by_idx(IntList *list, int index);
|
||||
int int_list_get(IntList *list, int index);
|
||||
int int_list_get_size(IntList *list);
|
||||
bool int_list_remove_by_value(IntList *list, int value);
|
||||
|
||||
#endif
|
||||
+143
-87
@@ -23,6 +23,8 @@
|
||||
|
||||
#include "soundbank.h"
|
||||
|
||||
#include "list.h"
|
||||
|
||||
// This seed system is temporary.
|
||||
static uint rng_seed = 2048;
|
||||
static bool seeded = false;
|
||||
@@ -171,6 +173,8 @@ int get_jokers_top(void) {
|
||||
return jokers_top;
|
||||
}
|
||||
|
||||
IntList* jokers_available_to_shop; // List of joker IDs
|
||||
|
||||
// Consts
|
||||
|
||||
// Rects left top right bottom
|
||||
@@ -998,8 +1002,21 @@ void game_set_state(enum GameState new_game_state)
|
||||
game_state = new_game_state;
|
||||
}
|
||||
|
||||
void jokers_avialable_to_shop_init()
|
||||
{
|
||||
int num_defined_jokers = get_joker_registry_size();
|
||||
jokers_available_to_shop = int_list_new(num_defined_jokers);
|
||||
for (int i = 0; i < num_defined_jokers; i++)
|
||||
{
|
||||
// Add all joker IDs sequentially
|
||||
int_list_append(jokers_available_to_shop, i);
|
||||
}
|
||||
}
|
||||
|
||||
void game_init()
|
||||
{
|
||||
jokers_avialable_to_shop_init();
|
||||
|
||||
hands = max_hands;
|
||||
discards = max_discards;
|
||||
|
||||
@@ -1818,41 +1835,6 @@ static void game_round_end_cashout()
|
||||
display_score(score); // Set the score display
|
||||
}
|
||||
|
||||
static void game_shop_create_items(JokerObject *shop_jokers[], bool first_time)
|
||||
{
|
||||
tte_erase_rect_wrapper(SHOP_PRICES_TEXT_RECT);
|
||||
|
||||
for (int i = 0; i < MAX_SHOP_JOKERS; i++)
|
||||
{
|
||||
if (shop_jokers[i] != NULL)
|
||||
{
|
||||
joker_object_destroy(&shop_jokers[i]); // Destroy the joker object if it exists
|
||||
}
|
||||
|
||||
u8 joker_id = random() % get_joker_registry_size();
|
||||
// TODO: don't pick a joker that we already own
|
||||
// TODO: weight the random choice by joker rarity
|
||||
|
||||
shop_jokers[i] = joker_object_new(joker_new(joker_id));
|
||||
shop_jokers[i]->sprite_object->x = int2fx(120 + i * 32);
|
||||
shop_jokers[i]->sprite_object->y = int2fx(160);
|
||||
shop_jokers[i]->sprite_object->tx = shop_jokers[i]->sprite_object->x;
|
||||
shop_jokers[i]->sprite_object->ty = int2fx(71);
|
||||
|
||||
int x = fx2int(shop_jokers[i]->sprite_object->tx) + TILE_SIZE - (get_digits_even(shop_jokers[i]->joker->value) - 1) * TILE_SIZE;
|
||||
int y = fx2int(shop_jokers[i]->sprite_object->ty) + CARD_SPRITE_SIZE + TILE_SIZE;
|
||||
tte_printf("#{P:%d,%d; cx:0xC000}$%d", x, y, shop_jokers[i]->joker->value);
|
||||
|
||||
if (first_time == false)
|
||||
{
|
||||
shop_jokers[i]->sprite_object->y = shop_jokers[i]->sprite_object->ty; // If it's not the first time, set the y position to the target position
|
||||
joker_object_shake(shop_jokers[i], UNDEFINED); // Give the joker a little wiggle animation
|
||||
}
|
||||
|
||||
sprite_position(joker_object_get_sprite(shop_jokers[i]), fx2int(shop_jokers[i]->sprite_object->x), fx2int(shop_jokers[i]->sprite_object->y));
|
||||
}
|
||||
}
|
||||
|
||||
void game_playing()
|
||||
{
|
||||
// TODO: Blind rect sliding into view animation...
|
||||
@@ -2155,13 +2137,44 @@ void game_round_end()
|
||||
}
|
||||
}
|
||||
|
||||
void game_shop_intro(JokerObject* shop_jokers[])
|
||||
static void game_shop_create_items(JokerObject *shop_jokers[])
|
||||
{
|
||||
tte_erase_rect_wrapper(SHOP_PRICES_TEXT_RECT);
|
||||
if (int_list_get_size(jokers_available_to_shop) == 0)
|
||||
{
|
||||
// No jokers to create
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_SHOP_JOKERS; i++)
|
||||
{
|
||||
// TODO: weight the random choice by joker rarity
|
||||
int joker_idx = random() % int_list_get_size(jokers_available_to_shop);
|
||||
int joker_id = int_list_get(jokers_available_to_shop, joker_idx);
|
||||
int_list_remove_by_idx(jokers_available_to_shop, joker_idx);
|
||||
|
||||
shop_jokers[i] = joker_object_new(joker_new(joker_id));
|
||||
shop_jokers[i]->sprite_object->x = int2fx(120 + i * 32);
|
||||
shop_jokers[i]->sprite_object->y = int2fx(160);
|
||||
shop_jokers[i]->sprite_object->tx = shop_jokers[i]->sprite_object->x;
|
||||
shop_jokers[i]->sprite_object->ty = int2fx(71);
|
||||
|
||||
int x = fx2int(shop_jokers[i]->sprite_object->tx) + TILE_SIZE - (get_digits_even(shop_jokers[i]->joker->value) - 1) * TILE_SIZE;
|
||||
int y = fx2int(shop_jokers[i]->sprite_object->ty) + CARD_SPRITE_SIZE + TILE_SIZE;
|
||||
tte_printf("#{P:%d,%d; cx:0xC000}$%d", x, y, shop_jokers[i]->joker->value);
|
||||
|
||||
sprite_position(joker_object_get_sprite(shop_jokers[i]), fx2int(shop_jokers[i]->sprite_object->x), fx2int(shop_jokers[i]->sprite_object->y));
|
||||
}
|
||||
}
|
||||
|
||||
// Intro sequence (menu and shop icon coming into frame)
|
||||
static void game_shop_intro(JokerObject* shop_jokers[])
|
||||
{
|
||||
main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT, SE_UP);
|
||||
|
||||
if (timer == 1)
|
||||
{
|
||||
game_shop_create_items(shop_jokers, true);
|
||||
game_shop_create_items(shop_jokers);
|
||||
}
|
||||
|
||||
if (timer >= 7) // Shift the shop icon
|
||||
@@ -2188,59 +2201,44 @@ void game_shop_intro(JokerObject* shop_jokers[])
|
||||
}
|
||||
}
|
||||
|
||||
void game_shop()
|
||||
static void game_shop_reroll(JokerObject** shop_jokers, int *reroll_cost)
|
||||
{
|
||||
change_background(BG_ID_SHOP);
|
||||
money -= *reroll_cost;
|
||||
display_money(money); // Update the money display
|
||||
for (int i = 0; i < MAX_SHOP_JOKERS; i++)
|
||||
{
|
||||
if (shop_jokers[i] != NULL)
|
||||
{
|
||||
int_list_append(jokers_available_to_shop, shop_jokers[i]->joker->id);
|
||||
joker_object_destroy(&shop_jokers[i]); // Destroy the joker object if it exists
|
||||
}
|
||||
}
|
||||
|
||||
static JokerObject *shop_jokers[MAX_SHOP_JOKERS] = {NULL};
|
||||
game_shop_create_items(shop_jokers);
|
||||
|
||||
for (int i = 0; i < MAX_SHOP_JOKERS; i++)
|
||||
{
|
||||
if (shop_jokers[i] != NULL)
|
||||
{
|
||||
joker_object_update(shop_jokers[i]);
|
||||
shop_jokers[i]->sprite_object->y = shop_jokers[i]->sprite_object->ty; // Set the y position to the target position
|
||||
joker_object_shake(shop_jokers[i], UNDEFINED); // Give the joker a little wiggle animation
|
||||
}
|
||||
}
|
||||
|
||||
const int reroll_base_cost = 5; // Base cost for rerolling the shop items
|
||||
static int reroll_cost = reroll_base_cost;
|
||||
(*reroll_cost)++;
|
||||
tte_printf("#{P:%d,%d; cx:0xF000}$%d", SHOP_REROLL_RECT.left, SHOP_REROLL_RECT.top, *reroll_cost);
|
||||
}
|
||||
|
||||
// Shop menu input and selection
|
||||
static void game_shop_process_user_input(JokerObject** shop_jokers)
|
||||
{
|
||||
static const int REROLL_BASE_COST = 5; // Base cost for rerolling the shop items
|
||||
static int reroll_cost = REROLL_BASE_COST;
|
||||
|
||||
// temp variables for future implementation
|
||||
const ushort max_items_top = MAX_SHOP_JOKERS;
|
||||
const ushort max_items_bottom = 0;
|
||||
|
||||
if (timer % 20 == 0) // Shift palette around the border of the shop icon
|
||||
{
|
||||
COLOR shifted_palette[4];
|
||||
memcpy16(&shifted_palette[0], &pal_bg_mem[14], 1);
|
||||
memcpy16(&shifted_palette[1], &pal_bg_mem[17], 1);
|
||||
memcpy16(&shifted_palette[2], &pal_bg_mem[22], 1);
|
||||
memcpy16(&shifted_palette[3], &pal_bg_mem[8], 1);
|
||||
|
||||
// Circularly shift the palette
|
||||
int last = shifted_palette[3];
|
||||
|
||||
for (int i = 3; i > 0; --i) {
|
||||
shifted_palette[i] = shifted_palette[i - 1];
|
||||
}
|
||||
|
||||
shifted_palette[0] = last;
|
||||
|
||||
memcpy16(&pal_bg_mem[14], &shifted_palette[0], 1); // Copy the shifted palette to the next 4 slots
|
||||
memcpy16(&pal_bg_mem[17], &shifted_palette[1], 1);
|
||||
memcpy16(&pal_bg_mem[22], &shifted_palette[2], 1);
|
||||
memcpy16(&pal_bg_mem[8], &shifted_palette[3], 1);
|
||||
}
|
||||
|
||||
switch (state) // I'm only using magic numbers here for the sake of simplicity since it's just sequential, but you can replace them with named constants or enums if it makes it clearer
|
||||
{
|
||||
case 0: // Intro sequence (menu and shop icon coming into frame)
|
||||
{
|
||||
game_shop_intro(shop_jokers);
|
||||
break;
|
||||
}
|
||||
case 1: // Shop menu input and selection
|
||||
{
|
||||
if (timer == 1)
|
||||
{
|
||||
tte_printf("#{P:%d,%d; cx:0xF000}$%d", SHOP_REROLL_RECT.left, SHOP_REROLL_RECT.top, reroll_cost);
|
||||
@@ -2274,6 +2272,7 @@ void game_shop()
|
||||
}
|
||||
else if (key_hit(KEY_RIGHT))
|
||||
{
|
||||
// TODO: Don't allow cursor on sold items
|
||||
if (selection_y == 0 && selection_x < max_items_top)
|
||||
{
|
||||
selection_x++;
|
||||
@@ -2288,7 +2287,7 @@ void game_shop()
|
||||
memcpy16(&pal_bg_mem[5], &pal_bg_mem[16], 1);
|
||||
|
||||
// Shop selection logic
|
||||
if (selection_x == 0 && selection_y == 0)
|
||||
if (selection_x == 0 && selection_y == 0) // Next round button
|
||||
{
|
||||
memset16(&pal_bg_mem[5], 0xFFFF, 1);
|
||||
|
||||
@@ -2297,6 +2296,7 @@ void game_shop()
|
||||
// Go to next blind selection game state
|
||||
state = 2; // Go to the outro sequence state
|
||||
timer = 0; // Reset the timer
|
||||
reroll_cost = REROLL_BASE_COST;
|
||||
|
||||
memcpy16(&pal_bg_mem[5], &pal_bg_mem[6], 1);
|
||||
|
||||
@@ -2306,23 +2306,17 @@ void game_shop()
|
||||
// And I don't care enough to fix it right now.
|
||||
}
|
||||
}
|
||||
else if (selection_x == 0 && selection_y == 1)
|
||||
else if (selection_x == 0 && selection_y == 1) // Reroll button
|
||||
{
|
||||
memset16(&pal_bg_mem[7], 0xFFFF, 1);
|
||||
|
||||
if (key_hit(SELECT_CARD) && money >= reroll_cost)
|
||||
{
|
||||
money -= reroll_cost;
|
||||
display_money(money); // Update the money display
|
||||
|
||||
game_shop_create_items(shop_jokers, false);
|
||||
|
||||
reroll_cost++;
|
||||
tte_printf("#{P:%d,%d; cx:0xF000}$%d", SHOP_REROLL_RECT.left, SHOP_REROLL_RECT.top, reroll_cost);
|
||||
game_shop_reroll(shop_jokers, &reroll_cost);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_SHOP_JOKERS; i++)
|
||||
for (int i = 0; i < MAX_SHOP_JOKERS; i++) // Item selection logic
|
||||
{
|
||||
if (shop_jokers[i] != NULL)
|
||||
{
|
||||
@@ -2354,7 +2348,63 @@ void game_shop()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void game_shop_lights_anim_frame()
|
||||
{
|
||||
// Shift palette around the border of the shop icon
|
||||
COLOR shifted_palette[4];
|
||||
memcpy16(&shifted_palette[0], &pal_bg_mem[14], 1);
|
||||
memcpy16(&shifted_palette[1], &pal_bg_mem[17], 1);
|
||||
memcpy16(&shifted_palette[2], &pal_bg_mem[22], 1);
|
||||
memcpy16(&shifted_palette[3], &pal_bg_mem[8], 1);
|
||||
|
||||
// Circularly shift the palette
|
||||
int last = shifted_palette[3];
|
||||
|
||||
for (int i = 3; i > 0; --i)
|
||||
{
|
||||
shifted_palette[i] = shifted_palette[i - 1];
|
||||
}
|
||||
|
||||
shifted_palette[0] = last;
|
||||
|
||||
memcpy16(&pal_bg_mem[14], &shifted_palette[0], 1); // Copy the shifted palette to the next 4 slots
|
||||
memcpy16(&pal_bg_mem[17], &shifted_palette[1], 1);
|
||||
memcpy16(&pal_bg_mem[22], &shifted_palette[2], 1);
|
||||
memcpy16(&pal_bg_mem[8], &shifted_palette[3], 1);
|
||||
}
|
||||
|
||||
|
||||
void game_shop()
|
||||
{
|
||||
change_background(BG_ID_SHOP);
|
||||
|
||||
static JokerObject *shop_jokers[MAX_SHOP_JOKERS] = {NULL};
|
||||
|
||||
for (int i = 0; i < MAX_SHOP_JOKERS; i++)
|
||||
{
|
||||
if (shop_jokers[i] != NULL)
|
||||
{
|
||||
joker_object_update(shop_jokers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (timer % 20 == 0)
|
||||
{
|
||||
game_shop_lights_anim_frame();
|
||||
}
|
||||
|
||||
switch (state) // I'm only using magic numbers here for the sake of simplicity since it's just sequential, but you can replace them with named constants or enums if it makes it clearer
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
game_shop_intro(shop_jokers);
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
game_shop_process_user_input(shop_jokers);
|
||||
break;
|
||||
}
|
||||
case 2: // Outro sequence (menu and shop icon going out of frame)
|
||||
@@ -2402,23 +2452,29 @@ void game_shop()
|
||||
}
|
||||
default:
|
||||
state = 0; // Reset the state
|
||||
reroll_cost = reroll_base_cost;
|
||||
|
||||
selection_x = 0; // Reset the selection
|
||||
selection_y = 0; // Reset the selection
|
||||
|
||||
for (int i = 0; i < MAX_SHOP_JOKERS; i++)
|
||||
{
|
||||
if (shop_jokers[i] != NULL)
|
||||
{
|
||||
// Make the joker available back to shop
|
||||
int_list_append(jokers_available_to_shop, shop_jokers[i]->joker->id);
|
||||
}
|
||||
joker_object_destroy(&shop_jokers[i]); // Destroy the joker objects
|
||||
}
|
||||
|
||||
increment_blind(BLIND_DEFEATED);
|
||||
increment_blind(BLIND_DEFEATED); // TODO: Move to game_round_end()?
|
||||
game_set_state(GAME_BLIND_SELECT); // If we reach here, we should go to the blind select state
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void game_blind_select()
|
||||
{
|
||||
switch (state) // I'm only using magic numbers here for the sake of simplicity since it's just sequential, but you can replace them with named constants or enums if it makes it clearer
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include "list.h"
|
||||
#include "util.h"
|
||||
|
||||
IntList *int_list_new(int init_size) {
|
||||
IntList *list = (IntList *)malloc(sizeof(IntList));
|
||||
if (list == NULL) return NULL;
|
||||
list->_array = (int *)malloc(sizeof(int) * init_size);
|
||||
if (!list->_array)
|
||||
{
|
||||
free(list);
|
||||
return NULL;
|
||||
}
|
||||
list->size = 0;
|
||||
list->allocated_size = init_size;
|
||||
return list;
|
||||
}
|
||||
|
||||
void int_list_destroy(IntList **list) {
|
||||
if (list == NULL || *list == NULL)
|
||||
return;
|
||||
{
|
||||
free((*list)->_array);
|
||||
free(*list);
|
||||
}
|
||||
|
||||
*list = NULL;
|
||||
}
|
||||
|
||||
bool int_list_append(IntList *list, int value)
|
||||
{
|
||||
if (list->size >= list->allocated_size)
|
||||
{
|
||||
int new_size = list->allocated_size * 2;
|
||||
int *new_arr = (int *)realloc(list->_array, sizeof(int) * new_size);
|
||||
if (new_arr == NULL)
|
||||
return false;
|
||||
list->_array = new_arr;
|
||||
list->allocated_size = new_size;
|
||||
}
|
||||
list->_array[list->size++] = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool int_list_remove_by_idx(IntList *list, int index) {
|
||||
if (index < 0 || index >= list->size)
|
||||
return false;
|
||||
for (int i = index; i < list->size - 1; ++i)
|
||||
{
|
||||
list->_array[i] = list->_array[i + 1];
|
||||
}
|
||||
list->size--;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool int_list_remove_by_value(IntList *list, int value)
|
||||
{
|
||||
for (int i = 0; i < list->size; i++)
|
||||
{
|
||||
if (list->_array[i] == value)
|
||||
{
|
||||
return int_list_remove_by_idx(list, i);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int int_list_get(IntList *list, int index)
|
||||
{
|
||||
if (index < 0 || index >= list->size)
|
||||
return 0;
|
||||
return list->_array[index];
|
||||
}
|
||||
|
||||
int int_list_get_size(IntList *list)
|
||||
{
|
||||
if (list == NULL)
|
||||
{
|
||||
return UNDEFINED;
|
||||
}
|
||||
return list->size;
|
||||
}
|
||||
Reference in New Issue
Block a user