GBAlatro
A Demake of Balatro for the GBA
Loading...
Searching...
No Matches
blind.c
Go to the documentation of this file.
1
6#include "blind.h"
7
8#include "blind_gfx.h"
9#include "game.h"
10#include "game/common_ui.h"
11#include "graphic_utils.h"
12#include "hand.h"
13#include "list.h"
14#include "random.h"
15#include "stdbool.h"
16#include "util.h"
17
18#include <stdlib.h>
19#include <tonc.h>
20
21#define BLIND_SPRITE_COPY_SIZE (BLIND_SPRITE_TILES * TILE_SIZE)
22
23#define BLIND_TOKENS_PER_SPRITESHEET 2
24#define BLIND_TOKEN_PALETTE_SIZE 8
25
26#define SMALL_BLIND_REWARD 3
27#define BIG_BLIND_REWARD 4
28#define BOSS_BLIND_REWARD 5
29#define SHOWDOWN_BLIND_REWARD 8
30
31static const unsigned int* blind_gfxTiles[] = {
32#define DEF_BLIND_GFX(idx) blind_gfx##idx##Tiles,
33#include "../include/def_blind_gfx_table.h"
34#undef DEF_BLIND_GFX
35};
36
37static const unsigned short* blind_gfxPal[] = {
38#define DEF_BLIND_GFX(idx) blind_gfx##idx##Pal,
39#include "../include/def_blind_gfx_table.h"
40#undef DEF_BLIND_GFX
41};
42
43// Bitfields storing blinds we have yet to beat during the current run
44static List s_unbeaten_boss_blinds = LIST_DEFAULT;
45static List s_unbeaten_showdown_blinds = LIST_DEFAULT;
46
47// Maps the ante number to the base blind requirement for that ante.
48// The game starts at ante 1 which is at index 1 for base requirement 300.
49// Ante 0 is also there in case it is ever reached.
50static const u32 ANTE_LUT[] = {100, 300, 800, 2000, 5000, 11000, 20000, 35000, 50000};
51
52// clang-format off
58static Blind s_blind_type_map[BLIND_TYPE_MAX] = {
59 {BLIND_TYPE_SMALL, FIX_ONE },
60 {BLIND_TYPE_BIG, (FIX_ONE * 3) / 2},
61 {BLIND_TYPE_HOOK, FIX_ONE * 2 },
62 {BLIND_TYPE_OX, FIX_ONE * 2 },
63 {BLIND_TYPE_HOUSE, FIX_ONE * 2 },
64 {BLIND_TYPE_WHEEL, FIX_ONE * 2 },
65 {BLIND_TYPE_WALL, FIX_ONE * 2 }, // x4 score requirement will be part of the effect
66 {BLIND_TYPE_ARM, FIX_ONE * 2 },
67 {BLIND_TYPE_CLUB, FIX_ONE * 2 },
68 {BLIND_TYPE_FISH, FIX_ONE * 2 },
69 {BLIND_TYPE_PSYCHIC, FIX_ONE * 2 },
70 {BLIND_TYPE_GOAD, FIX_ONE * 2 },
71 {BLIND_TYPE_WATER, FIX_ONE * 2 },
72 {BLIND_TYPE_WINDOW, FIX_ONE * 2 },
73 {BLIND_TYPE_MANACLE, FIX_ONE * 2 },
74 {BLIND_TYPE_EYE, FIX_ONE * 2 },
75 {BLIND_TYPE_MOUTH, FIX_ONE * 2 },
76 {BLIND_TYPE_PLANT, FIX_ONE * 2 },
77 {BLIND_TYPE_SERPENT, FIX_ONE * 2 },
78 {BLIND_TYPE_PILLAR, FIX_ONE * 2 },
79 {BLIND_TYPE_NEEDLE, FIX_ONE * 2 }, // Same as the Wall with normal requirement
80 {BLIND_TYPE_HEAD, FIX_ONE * 2 },
81 {BLIND_TYPE_TOOTH, FIX_ONE * 2 },
82 {BLIND_TYPE_FLINT, FIX_ONE * 2 },
83 {BLIND_TYPE_MARK, FIX_ONE * 2 },
84 {BLIND_TYPE_ACORN, FIX_ONE * 2 },
85 {BLIND_TYPE_LEAF, FIX_ONE * 2 },
86 {BLIND_TYPE_VESSEL, FIX_ONE * 2 }, // Same as the Wall with x6 requirement
87 {BLIND_TYPE_HEART, FIX_ONE * 2 },
88 {BLIND_TYPE_BELL, FIX_ONE * 2 }
89};
90// clang-format on
91
92void blind_init()
93{
94 // Set up the palette used by normal blind tokens.
95 // We will never need to edit it ever again.
96 memcpy16(&pal_obj_bank[NORMAL_BLIND_PB], blind_gfxPal[0], NUM_ELEM_IN_ARR(blind_gfx0Pal));
97
98 return;
99}
100
101u32 blind_get_requirement(enum BlindType type, int ante)
102{
103 // Ensure ante is within valid range
104 if (ante < 0 || ante > MAX_ANTE)
105 ante = 0;
106
107 return fx2int(s_blind_type_map[type].score_req_multiplier * ANTE_LUT[ante]);
108}
109
111{
112 switch (type)
113 {
114 case BLIND_TYPE_SMALL:
115 return SMALL_BLIND_REWARD;
116 case BLIND_TYPE_BIG:
117 return BIG_BLIND_REWARD;
118 case BLIND_TYPE_BOSS ...(BLIND_TYPE_SHOWDOWN - 1):
119 return BOSS_BLIND_REWARD;
120 default:
121 return SHOWDOWN_BLIND_REWARD;
122 }
123}
124
135static void init_unbeaten_blinds_list(bool showdown)
136{
137 List* p_unbeaten_blinds = showdown ? &s_unbeaten_showdown_blinds : &s_unbeaten_boss_blinds;
138
139 // empty the list just to be sure
140 list_clear(p_unbeaten_blinds);
141
142 int lower_blind = showdown ? BLIND_TYPE_SHOWDOWN : BLIND_TYPE_BOSS;
143 int upper_blind = showdown ? BLIND_TYPE_MAX - 1 : BLIND_TYPE_SHOWDOWN - 1;
144
145 for (int i = lower_blind; i <= upper_blind; i++)
146 {
147 list_push_back(p_unbeaten_blinds, &s_blind_type_map[i]);
148 }
149}
150
156
157enum BlindType roll_blind_type(bool showdown)
158{
159 List* p_unbeaten_blinds = showdown ? &s_unbeaten_showdown_blinds : &s_unbeaten_boss_blinds;
160
161 // Fill the list with all blinds if it is empty
162 // (happens on startup or if we have beaten all blinds)
163 if (list_is_empty(p_unbeaten_blinds))
164 {
166 }
167
168 // roll a random blind among the unbeaten ones
169 int random_blind_idx = rng_get_u32(RNG_SEQ_BLIND) % list_get_len(p_unbeaten_blinds);
170 Blind* random_blind = list_get_at_idx(p_unbeaten_blinds, random_blind_idx);
171
172 return random_blind->type;
173}
174
176{
177 bool showdown = (type >= BLIND_TYPE_SHOWDOWN);
178 List* p_unbeaten_blinds = showdown ? &s_unbeaten_showdown_blinds : &s_unbeaten_boss_blinds;
179
180 // find the beaten blind idx in the list
181 int beaten_idx = 0;
182 Blind* beaten_blind = NULL;
183 ListItr itr = list_itr_create(p_unbeaten_blinds);
184
185 while ((beaten_blind = list_itr_next(&itr)))
186 {
187 if (beaten_blind->type == type)
188 {
189 break;
190 }
191 beaten_idx++;
192 }
193
194 if (beaten_idx < list_get_len(p_unbeaten_blinds))
195 {
196 list_remove_at_idx(p_unbeaten_blinds, beaten_idx);
197 }
198}
199
200static u32 get_blind_pb(enum BlindType type)
201{
202 return (type <= BLIND_TYPE_BIG) ? NORMAL_BLIND_PB : BOSS_BLIND_PB;
203}
204
205static u32 get_blind_spritesheet_idx(enum BlindType type)
206{
207 // See comment below in blind_get_color why we differenciate before/after the Mark
208 return (type < BLIND_TYPE_MARK)
209 ? type / BLIND_TOKENS_PER_SPRITESHEET
210 : BLIND_TYPE_MARK / BLIND_TOKENS_PER_SPRITESHEET + type - BLIND_TYPE_MARK;
211}
212
213u16 blind_get_color(enum BlindType type, enum BlindColorIndex index)
214{
215 // Do a little translation of palette idx -> custom array idx
216 // All blinds before the Mark are arranged in pairs with their palettte split in two
217 // | XX | 1 | 2 | 3 | 4 | 5 | 6 | 7 | -> first sprite
218 // | XX | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -> second sprite
219 // so we need to offset the color indices by 8 for blinds with an odd type
220 // From the Mark onwards, all sprites are alone in their spritesheet, so no need to offset
221 u32 color_idx = index + ((type < BLIND_TYPE_MARK)
222 ? BLIND_TOKEN_PALETTE_SIZE * (type % BLIND_TOKENS_PER_SPRITESHEET)
223 : 0);
224 return blind_gfxPal[get_blind_spritesheet_idx(type)][color_idx];
225}
226
228{
229 // keep track of active boss blind spritesheet to copy colors only when changing
230 static u32 active_boss_spritesheet = BLIND_TYPE_MAX;
231 u32 new_spritesheet = get_blind_spritesheet_idx(type);
232
233 // No need to update normal blind palette
234 if (type < BLIND_TYPE_BOSS || active_boss_spritesheet == new_spritesheet)
235 {
236 return;
237 }
238
239 active_boss_spritesheet = new_spritesheet;
240
241 // Just copy the palette as is to the sprite palette bank
242 memcpy16(
243 &pal_obj_bank[BOSS_BLIND_PB],
244 blind_gfxPal[active_boss_spritesheet],
245 NUM_ELEM_IN_ARR(blind_gfx0Pal)
246 );
247}
248
250{
251 int tile_index = sprite_get_tid(BLIND_TOKEN_SPRITE, layer);
252 u32 spritesheet_idx = get_blind_spritesheet_idx(type);
253 u32 sprite_idx = (type < BLIND_TYPE_MARK) ? type % BLIND_TOKENS_PER_SPRITESHEET : 0;
254 memcpy32(
255 &tile_mem[TILE_MEM_OBJ_CHARBLOCK0_IDX][tile_index],
256 &blind_gfxTiles[spritesheet_idx][sprite_idx * BLIND_SPRITE_COPY_SIZE],
257 BLIND_SPRITE_COPY_SIZE
258 );
259
260 apply_blind_colors(type);
261}
262
263Sprite* blind_token_new(enum BlindType type, int x, int y, enum BlindTokenLayers layer)
264{
265 apply_blind_tiles(type, layer);
266
267 Sprite* sprite = sprite_new(
268 ATTR0_SQUARE | ATTR0_4BPP,
269 ATTR1_SIZE_32x32,
270 sprite_get_tid(BLIND_TOKEN_SPRITE, layer),
271 get_blind_pb(type),
272 sprite_get_starting_layer(BLIND_TOKEN_SPRITE) + layer
273 );
274 sprite_position(sprite, x, y);
275
276 return sprite;
277}
void apply_blind_tiles(enum BlindType type, enum BlindTokenLayers layer)
Change the tiles of the BlindToken Sprite at a given layer to that of the given BlindType.
Definition blind.c:249
enum BlindType roll_blind_type(bool showdown)
Choose a random Blind among the ones that haven't been beaten yet.
Definition blind.c:157
void apply_blind_colors(enum BlindType type)
Copy the palette associated with the given Blind and copy it in the right spot in the palette memory.
Definition blind.c:227
static void init_unbeaten_blinds_list(bool showdown)
Fill Lists of unbeaten Boss and Showdown Blinds.
Definition blind.c:135
Sprite * blind_token_new(enum BlindType type, int x, int y, enum BlindTokenLayers layer)
Create a new BlindToken sprite.
Definition blind.c:263
static Blind s_blind_type_map[BLIND_TYPE_MAX]
Stores an instance of the Blind struct for each BlindType value, ordered in the same way....
Definition blind.c:58
u16 blind_get_color(enum BlindType type, enum BlindColorIndex index)
Get the color associated with a given Blind.
Definition blind.c:213
u32 blind_get_requirement(enum BlindType type, int ante)
Get the score required to beat a certain blind (either the Small, Big, or any Boss/Showdown blind) at...
Definition blind.c:101
void set_blind_beaten(enum BlindType type)
Remove the given Blind from the corresponding List so that we don't roll it again in the future.
Definition blind.c:175
void init_unbeaten_blinds_lists(void)
Initialize Boss and Showdown Blinds lists to roll from.
Definition blind.c:151
int blind_get_reward(enum BlindType type)
Get the amount of money gained from beating a certain Blind.
Definition blind.c:110
Data structures and functions relative to the behaviour and graphics of Blinds.
BlindType
All Blind types in the game are listed here.
Definition blind.h:69
BlindTokenLayers
Sprite IDs of the various Blind Tokens used in the game, expressed as an offset relative to the start...
Definition blind.h:36
BlindColorIndex
Indices of the Blind sprites' colors as encoded in the files' palettes with Aseprite.
Definition blind.h:49
Common functions to render UI elements.
Graphic utility functions.
#define TILE_MEM_OBJ_CHARBLOCK0_IDX
The index for the first charblock of the object memory in tonc's tile_mem.
Functions relative to manipulating and analyzing the contents of the Hand, a.k.a. the Cards we hold a...
A doubly-linked list.
bool list_is_empty(const List *list)
Definition list.c:62
void * list_get_at_idx(List *list, unsigned int idx)
Definition list.c:219
int list_get_len(const List *list)
Definition list.c:214
void list_clear(List *list)
Definition list.c:44
void * list_itr_next(ListItr *itr)
Definition list.c:281
bool list_remove_at_idx(List *list, unsigned int idx)
Definition list.c:237
#define LIST_DEFAULT
Default list declaration for empty lists.
Definition list.h:30
void list_push_back(List *list, void *data)
Definition list.c:89
ListItr list_itr_create(List *list)
Definition list.c:257
Common functions to handle RNG manipulation. Using this interface has three goals:
u32 rng_get_u32(enum RngSequence key)
Get the next "randomly" generated number in the sequence corresponding to the given type.
Definition random.c:56
INLINE void sprite_position(Sprite *sprite, int x, int y)
Set sprite position. Inlined for efficiency.
Definition sprite.h:466
int sprite_get_tid(enum SpriteType sprite_type, s16 layer)
Get the tile index of a certain SpriteType at a certain layer.
Definition sprite.c:66
Sprite * sprite_new(u16 a0, u16 a1, u32 tid, u32 pb, s16 sprite_index)
Allocate and retrieve a pointer to a valid Sprite.
Definition sprite.c:77
int sprite_get_starting_layer(enum SpriteType sprite_type)
Get the starting layer of a certain type of sprite.
Definition sprite.c:71
Data structure containing data about a BlindType.
Definition blind.h:137
An iterator into a list.
Definition list.h:91
A doubly-linked list.
Definition list.h:61
Sprite struct for GBA hardware specifics.
Definition sprite.h:54
Utilities relating around number string representation and protected arithmatic helper functions.
#define NUM_ELEM_IN_ARR(arr)
Get the number of elements in an array.
Definition util.h:55