Merge branch 'main' of https://github.com/cellos51/balatro-gba into boss_backgrounds
This commit is contained in:
+65
-49
@@ -30,7 +30,7 @@ static uint timer = 0; // This might already exist in libtonc but idk so i'm jus
|
||||
static int game_speed = 1;
|
||||
static int background = 0;
|
||||
|
||||
static enum GameState game_state = GAME_BLIND_SELECT; // The current game state, this is used to determine what the game is doing at any given time
|
||||
static enum GameState game_state = GAME_SHOP; // The current game state, this is used to determine what the game is doing at any given time
|
||||
static enum HandState hand_state = HAND_DRAW;
|
||||
static enum PlayState play_state = PLAY_PLAYING;
|
||||
static int state = 0; // General state variable, used for switch statements in each game state related function
|
||||
@@ -140,6 +140,31 @@ static inline Card *discard_pop()
|
||||
return discard_pile[discard_top--];
|
||||
}
|
||||
|
||||
// get-functions, for other files to view game state (mainly for jokers)
|
||||
CardObject **get_hand_array(void) {
|
||||
return hand;
|
||||
}
|
||||
|
||||
int get_hand_top(void) {
|
||||
return hand_top;
|
||||
}
|
||||
|
||||
CardObject **get_played_array(void) {
|
||||
return played;
|
||||
}
|
||||
|
||||
int get_played_top(void) {
|
||||
return played_top;
|
||||
}
|
||||
|
||||
JokerObject **get_jokers(void) {
|
||||
return jokers;
|
||||
}
|
||||
|
||||
int get_jokers_top(void) {
|
||||
return jokers_top;
|
||||
}
|
||||
|
||||
// Consts
|
||||
|
||||
// Rects left top right bottom
|
||||
@@ -291,22 +316,6 @@ void sort_cards()
|
||||
}
|
||||
}
|
||||
|
||||
CardObject **get_hand_array(void) {
|
||||
return hand;
|
||||
}
|
||||
|
||||
int get_hand_top(void) {
|
||||
return hand_top;
|
||||
}
|
||||
|
||||
CardObject **get_played_array(void) {
|
||||
return played;
|
||||
}
|
||||
|
||||
int get_played_top(void) {
|
||||
return played_top;
|
||||
}
|
||||
|
||||
enum HandType hand_get_type()
|
||||
{
|
||||
enum HandType res_hand_type = NONE;
|
||||
@@ -1831,6 +1840,8 @@ static void game_shop_create_items(JokerObject *shop_jokers[], bool first_time)
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -1839,7 +1850,7 @@ static void game_shop_create_items(JokerObject *shop_jokers[], bool first_time)
|
||||
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);
|
||||
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)
|
||||
@@ -2153,6 +2164,39 @@ void game_round_end()
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (timer >= 7) // Shift the shop icon
|
||||
{
|
||||
int timer_offset = timer - 6;
|
||||
|
||||
// TODO: Extract to generic function?
|
||||
for (int y = 0; y < timer_offset; y++)
|
||||
{
|
||||
int y_from = 26 + y - timer_offset;
|
||||
int y_to = 0 + y;
|
||||
|
||||
Rect from = { 0, y_from, 8, y_from };
|
||||
BG_POINT to = { 0, y_to };
|
||||
|
||||
main_bg_se_copy_rect(from, to);
|
||||
}
|
||||
}
|
||||
|
||||
if (timer == 12)
|
||||
{
|
||||
state = 1;
|
||||
timer = 0; // Reset the timer
|
||||
}
|
||||
}
|
||||
|
||||
void game_shop()
|
||||
{
|
||||
change_background(BG_ID_SHOP);
|
||||
@@ -2201,36 +2245,7 @@ void game_shop()
|
||||
{
|
||||
case 0: // Intro sequence (menu and shop icon coming into frame)
|
||||
{
|
||||
main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT, SE_UP);
|
||||
|
||||
if (timer == 1)
|
||||
{
|
||||
game_shop_create_items(shop_jokers, true);
|
||||
}
|
||||
|
||||
if (timer >= 7) // Shift the shop icon
|
||||
{
|
||||
int timer_offset = timer - 6;
|
||||
|
||||
// TODO: Extract to generic function?
|
||||
for (int y = 0; y < timer_offset; y++)
|
||||
{
|
||||
int y_from = 26 + y - timer_offset;
|
||||
int y_to = 0 + y;
|
||||
|
||||
Rect from = {0, y_from, 8, y_from};
|
||||
BG_POINT to = {0, y_to};
|
||||
|
||||
main_bg_se_copy_rect(from, to);
|
||||
}
|
||||
}
|
||||
|
||||
if (timer == 12)
|
||||
{
|
||||
state = 1;
|
||||
timer = 0; // Reset the timer
|
||||
}
|
||||
|
||||
game_shop_intro(shop_jokers);
|
||||
break;
|
||||
}
|
||||
case 1: // Shop menu input and selection
|
||||
@@ -2332,7 +2347,8 @@ void game_shop()
|
||||
|
||||
Rect joker_price_rect;
|
||||
joker_price_rect.left = fx2int(shop_jokers[i]->sprite_object->tx);
|
||||
joker_price_rect.top = fx2int(shop_jokers[i]->sprite_object->ty) + TILE_SIZE;
|
||||
// 2*TILE_SIZE because the item is highlighted and raised by 1 additional tile
|
||||
joker_price_rect.top = fx2int(shop_jokers[i]->sprite_object->ty) + CARD_SPRITE_SIZE + 2*TILE_SIZE;
|
||||
joker_price_rect.right = joker_price_rect.left + TILE_SIZE * 3;
|
||||
joker_price_rect.bottom = joker_price_rect.top + TILE_SIZE;
|
||||
|
||||
|
||||
+57
-21
@@ -39,16 +39,52 @@ static bool used_layers[MAX_JOKER_OBJECTS] = {false}; // Track used layers for j
|
||||
// Maps the spritesheet index to the palette bank index allocated to it.
|
||||
// Spritesheets that were not allocated are
|
||||
static int* joker_spritesheet_pb_map;
|
||||
static int joker_pb_num_sprite_users[JOKER_LAST_PB - JOKER_BASE_PB + 1] = { 0 };
|
||||
|
||||
static int get_num_spritesheets()
|
||||
{
|
||||
return (get_joker_registry_size() + NUM_JOKERS_PER_SPRITESHEET - 1) / NUM_JOKERS_PER_SPRITESHEET;
|
||||
}
|
||||
|
||||
static int joker_get_spritesheet_idx(u8 joker_id)
|
||||
|
||||
{
|
||||
return joker_id / NUM_JOKERS_PER_SPRITESHEET;
|
||||
}
|
||||
|
||||
// TODO: This should be generalized so any sprite can have dynamic swapping
|
||||
static void joker_pb_add_sprite_user(int pb)
|
||||
{
|
||||
joker_pb_num_sprite_users[pb - JOKER_BASE_PB]++;
|
||||
}
|
||||
|
||||
static void joker_pb_remove_sprite_user(int pb)
|
||||
{
|
||||
int num_sprite_users = joker_pb_num_sprite_users[pb - JOKER_BASE_PB];
|
||||
joker_pb_num_sprite_users[pb - JOKER_BASE_PB] = max(0, num_sprite_users - 1);
|
||||
}
|
||||
|
||||
static int joker_pb_get_num_sprite_users(int joker_pb)
|
||||
{
|
||||
return joker_pb_num_sprite_users[joker_pb - JOKER_BASE_PB];
|
||||
}
|
||||
|
||||
static int get_unused_joker_pb()
|
||||
{
|
||||
for (int i = 0; i < NUM_ELEM_IN_ARR(joker_pb_num_sprite_users); i++)
|
||||
{
|
||||
if (joker_pb_num_sprite_users[i] == 0)
|
||||
{
|
||||
return (i + JOKER_BASE_PB);
|
||||
}
|
||||
}
|
||||
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
static int allocate_pb_if_needed(u8 joker_id)
|
||||
{
|
||||
int joker_spritesheet_idx = joker_id / NUM_JOKERS_PER_SPRITESHEET;
|
||||
int joker_spritesheet_idx = joker_get_spritesheet_idx(joker_id);
|
||||
int joker_pb = joker_spritesheet_pb_map[joker_spritesheet_idx];
|
||||
if (joker_pb != UNDEFINED)
|
||||
{
|
||||
@@ -57,23 +93,9 @@ static int allocate_pb_if_needed(u8 joker_id)
|
||||
}
|
||||
|
||||
// Allocate a new palette
|
||||
joker_pb = int_arr_max(joker_spritesheet_pb_map, get_num_spritesheets());
|
||||
joker_pb = get_unused_joker_pb();
|
||||
|
||||
if (joker_pb == UNDEFINED)
|
||||
{
|
||||
// This is the first palette loaded
|
||||
joker_pb = JOKER_BASE_PB;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The new palette bank is a 1 increment of the last allocated one
|
||||
/* TODO: This doesn't account for removal, we need to address that,
|
||||
* track sprite usage and remove palettes for unused sprites
|
||||
*/
|
||||
joker_pb = joker_pb + 1;
|
||||
}
|
||||
|
||||
if (joker_pb == NUM_PALETTES)
|
||||
{
|
||||
// Ran out of palettes, default to base and pray
|
||||
joker_pb = JOKER_BASE_PB;
|
||||
@@ -104,6 +126,7 @@ void joker_init()
|
||||
joker_gfxTiles[5] = joker_gfx5Tiles;
|
||||
joker_gfxTiles[6] = joker_gfx6Tiles;
|
||||
joker_gfxTiles[7] = joker_gfx7Tiles;
|
||||
joker_gfxTiles[8] = joker_gfx8Tiles;
|
||||
|
||||
joker_gfxPal[0] = joker_gfx0Pal;
|
||||
joker_gfxPal[1] = joker_gfx1Pal;
|
||||
@@ -113,6 +136,7 @@ void joker_init()
|
||||
joker_gfxPal[5] = joker_gfx5Pal;
|
||||
joker_gfxPal[6] = joker_gfx6Pal;
|
||||
joker_gfxPal[7] = joker_gfx7Pal;
|
||||
joker_gfxPal[8] = joker_gfx8Pal;
|
||||
|
||||
for (int i = 0; i < num_spritesheets; i++)
|
||||
{
|
||||
@@ -129,7 +153,7 @@ Joker *joker_new(u8 id)
|
||||
|
||||
joker->id = id;
|
||||
joker->modifier = BASE_EDITION; // TODO: Make this a parameter
|
||||
joker->value = jinfo->base_value + edition_price_lut[joker->modifier]; // Base value + edition price
|
||||
joker->value = jinfo->base_value + edition_price_lut[joker->modifier];
|
||||
joker->rarity = jinfo->rarity;
|
||||
joker->processed = false;
|
||||
|
||||
@@ -172,12 +196,13 @@ JokerObject *joker_object_new(Joker *joker)
|
||||
|
||||
int tile_index = JOKER_TID + (layer * JOKER_SPRITE_OFFSET);
|
||||
|
||||
int joker_spritesheet_idx = joker->id / NUM_JOKERS_PER_SPRITESHEET;
|
||||
int joker_spritesheet_idx = joker_get_spritesheet_idx(joker->id);
|
||||
int joker_idx = joker->id % NUM_JOKERS_PER_SPRITESHEET;
|
||||
int joker_pb = allocate_pb_if_needed(joker->id);
|
||||
joker_pb_add_sprite_user(joker_pb);
|
||||
|
||||
memcpy32(&tile_mem[4][tile_index], &joker_gfxTiles[joker_spritesheet_idx][joker_idx * TILE_SIZE * JOKER_SPRITE_OFFSET], TILE_SIZE * JOKER_SPRITE_OFFSET);
|
||||
|
||||
|
||||
sprite_object_set_sprite
|
||||
(
|
||||
joker_object->sprite_object,
|
||||
@@ -198,10 +223,16 @@ JokerObject *joker_object_new(Joker *joker)
|
||||
|
||||
void joker_object_destroy(JokerObject **joker_object)
|
||||
{
|
||||
if (*joker_object == NULL) return;
|
||||
if (joker_object == NULL || *joker_object == NULL) return;
|
||||
|
||||
int layer = sprite_get_layer(joker_object_get_sprite(*joker_object)) - JOKER_STARTING_LAYER;
|
||||
used_layers[layer] = false;
|
||||
joker_pb_remove_sprite_user(sprite_get_pb(joker_object_get_sprite(*joker_object)));
|
||||
if (joker_pb_get_num_sprite_users((sprite_get_pb(joker_object_get_sprite(*joker_object)))) == 0)
|
||||
{
|
||||
joker_spritesheet_pb_map[joker_get_spritesheet_idx((*joker_object)->joker->id)] = UNDEFINED;
|
||||
}
|
||||
|
||||
sprite_object_destroy(&(*joker_object)->sprite_object); // Destroy the sprite
|
||||
joker_destroy(&(*joker_object)->joker); // Destroy the joker
|
||||
free(*joker_object);
|
||||
@@ -229,7 +260,7 @@ bool joker_object_score(JokerObject *joker_object, Card* scored_card, int *chips
|
||||
{
|
||||
*chips += joker_effect.chips;
|
||||
*mult += joker_effect.mult;
|
||||
// TODO: XMult
|
||||
*mult *= joker_effect.xmult > 0 ? joker_effect.xmult : 1; // if xmult is zero, DO NOT multiply by it
|
||||
*money += joker_effect.money;
|
||||
// TODO: Retrigger
|
||||
|
||||
@@ -247,6 +278,11 @@ bool joker_object_score(JokerObject *joker_object, Card* scored_card, int *chips
|
||||
tte_set_special(0xE000); // Red
|
||||
snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.mult);
|
||||
}
|
||||
else if (joker_effect.xmult > 0)
|
||||
{
|
||||
tte_set_special(0xE000); // Red
|
||||
snprintf(score_buffer, sizeof(score_buffer), "X%d", joker_effect.xmult);
|
||||
}
|
||||
else if (joker_effect.money > 0)
|
||||
{
|
||||
tte_set_special(0xC000); // Yellow
|
||||
|
||||
+34
-1
@@ -1,7 +1,7 @@
|
||||
#include "joker.h"
|
||||
#include "util.h"
|
||||
#include "hand_analysis.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static JokerEffect default_joker_effect(Joker *joker, Card *scored_card) {
|
||||
JokerEffect effect = {0};
|
||||
@@ -184,6 +184,37 @@ static JokerEffect half_joker_effect(Joker *joker, Card *scored_card) {
|
||||
return effect;
|
||||
}
|
||||
|
||||
static JokerEffect joker_stencil_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 empty joker slot...
|
||||
int jokers_top = get_jokers_top();
|
||||
effect.xmult = (MAX_JOKERS_HELD_SIZE-1) - jokers_top;
|
||||
|
||||
// ...and also each stencil_joker adds +1 xmult
|
||||
JokerObject** jokers = get_jokers();
|
||||
for (int i = 0; i < jokers_top; i++ )
|
||||
{
|
||||
if (jokers[i]->joker->id == JOKER_STENCIL_ID)
|
||||
effect.xmult++;
|
||||
}
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
#define MISPRINT_MAX_MULT 23
|
||||
static JokerEffect misprint_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.mult = random() % (MISPRINT_MAX_MULT + 1);
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
const JokerInfo joker_registry[] = {
|
||||
{ COMMON_JOKER, 2, default_joker_effect }, // DEFAULT_JOKER_ID = 0
|
||||
{ COMMON_JOKER, 5, greedy_joker_effect }, // GREEDY_JOKER_ID = 1
|
||||
@@ -201,6 +232,8 @@ const JokerInfo joker_registry[] = {
|
||||
{ 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, 4, misprint_joker_effect },
|
||||
};
|
||||
|
||||
static const size_t joker_registry_size = NUM_ELEM_IN_ARR(joker_registry);
|
||||
|
||||
+11
-2
@@ -1,5 +1,6 @@
|
||||
#include "sprite.h"
|
||||
#include "util.h"
|
||||
#include "audio_utils.h"
|
||||
|
||||
#include <tonc.h>
|
||||
#include <stdlib.h>
|
||||
@@ -100,6 +101,15 @@ void sprite_draw()
|
||||
oam_copy(oam_mem, obj_buffer, MAX_SPRITES);
|
||||
}
|
||||
|
||||
int sprite_get_pb(const Sprite *sprite)
|
||||
{
|
||||
if (sprite == NULL)
|
||||
{
|
||||
return UNDEFINED;
|
||||
}
|
||||
return (sprite->obj->attr2 & ATTR2_PALBANK_MASK) >> ATTR2_PALBANK_SHIFT;
|
||||
}
|
||||
|
||||
// SpriteObject methods
|
||||
SpriteObject* sprite_object_new()
|
||||
{
|
||||
@@ -206,8 +216,7 @@ void sprite_object_shake(SpriteObject* sprite_object, mm_word sound_id)
|
||||
|
||||
if (sound_id == UNDEFINED) return; // If no sound ID is provided, do nothing
|
||||
|
||||
mm_sound_effect sfx_select = { {sound_id}, 1024, 0, 255, 128, };
|
||||
mmEffectEx(&sfx_select);
|
||||
play_sfx(sound_id, MM_BASE_PITCH_RATE);
|
||||
}
|
||||
|
||||
void sprite_object_set_selected(SpriteObject* sprite_object, bool selected)
|
||||
|
||||
Reference in New Issue
Block a user