GBAlatro
A Demake of Balatro for the GBA
Loading...
Searching...
No Matches
blind_select.c
1#include "blind_select.h"
2
3#include "affine_background.h"
4#include "audio_utils.h"
5#include "background_blind_select_gfx.h"
6#include "blind.h"
7#include "button.h"
8#include "game.h"
9#include "game_variables.h"
10#include "graphic_utils.h"
11#include "layout.h"
12#include "soundbank.h"
13#include "sprite.h"
14#include "state_machine.h"
15#include "timer.h"
16#include "util.h"
17
18#include <maxmod.h>
19
20static const u32 BLIND_SELECT_BTN_PID = 15;
21static const u32 BLIND_SKIP_BTN_PID = 5;
22static const u32 BLIND_SKIP_BTN_SELECTED_BORDER_PID = 10;
23static const u32 BLIND_SELECT_BTN_SELECTED_BORDER_PID = 18;
24
25static const u32 TM_DISP_BLIND_PANEL_FINISH = 7;
26static const u32 TM_DISP_BLIND_PANEL_START = 1;
27
28static int s_timer;
29
30static void game_blind_select_start_anim_seq(void);
31static void game_blind_select_handle_input(void);
32static void game_blind_select_selected_anim_seq(void);
33static void game_blind_select_display_blind_panel(void);
34static void game_blind_select_exit(void);
35static Rect game_blind_select_get_req_score_rect(enum BlindTokens blind);
36static void game_blind_select_print_blinds_reqs_and_rewards(void);
37static enum BlindType get_blind_type_from_token(enum BlindTokens blind);
38static void blind_tokens_init(void);
39
40enum BlindSelectState
41{
42 START_ANIM_SEQ,
43 BLIND_SELECT,
44 BLIND_SELECTED_ANIM_SEQ,
45 DISPLAY_BLIND_PANEL,
46 BLIND_SELECT_EXIT,
47 BLIND_SELECT_MAX,
48};
49
50// TODO: this will be refactored into common state machine
51static StateInfo state_info[] = {
52 STATE_INFO_UPDATE_FN_ONLY(game_blind_select_start_anim_seq),
53 STATE_INFO_UPDATE_FN_ONLY(game_blind_select_handle_input),
54 STATE_INFO_UPDATE_FN_ONLY(game_blind_select_selected_anim_seq),
55 STATE_INFO_UPDATE_FN_ONLY(game_blind_select_display_blind_panel),
56 STATE_INFO_UPDATE_FN_ONLY(game_blind_select_exit),
57};
58
59static StateMachine blind_select_sm = STATE_MACHINE_DEFINE(state_info, BLIND_SELECT_MAX);
60
61// clang-format off
62// Points x y
63static const BG_POINT TOP_LEFT_PANEL_EMPTY_3W_ROW_POS = {29, 31};
64// Rects left top right bottom
65static const Rect BLIND_SKIP_BTN_GRAY_RECT = {0, 24, 4, 27};
66static const Rect BLIND_SKIP_BTN_PREANIM_DEST_RECT = {9, 29, 19, 31};
67static const Rect SINGLE_BLIND_SEL_REQ_SCORE_RECT = {80, 120, 104, 128};
68static const Rect SINGLE_BLIND_SELECT_RECT = {9, 7, 13, 31};
69// clang-format on
70
71static const u32 TM_END_ANIM_SEQ = 12;
72static const u32 TM_BLIND_SELECT_START = 1;
73
74static const u32 BLIND_LEFT_X = 80;
75static const u32 BLIND_CENTER_X = 120;
76static const u32 BLIND_RIGHT_X = 160;
77
78static const u32 BLIND_ROW = 0;
79static const u32 SKIP_ROW = 1;
80
81static int selection_x = 0;
82static int selection_y = 0;
83
84static Sprite* blind_select_tokens[NUM_BLINDS_PER_ANTE] = {NULL};
85
86static void game_blind_select_start_anim_seq()
87{
88 // main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT, SCREEN_UP);
89 main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT, SCREEN_UP);
90
91 for (int i = 0; i < NUM_BLINDS_PER_ANTE; i++)
92 {
94 blind_select_tokens[i],
95 blind_select_tokens[i]->pos.x,
96 blind_select_tokens[i]->pos.y - TILE_SIZE
97 );
98 }
99
100 if (s_timer == TM_END_ANIM_SEQ)
101 {
102 game_blind_select_print_blinds_reqs_and_rewards();
103 state_machine_change_state(&blind_select_sm, BLIND_SELECT);
104 s_timer = TM_ZERO; // Reset the timer
105 }
106}
107
108static inline void game_blind_select_erase_blind_reqs_and_rewards()
109{
110 for (enum BlindTokens curr_blind = SMALL_BLIND; curr_blind < NUM_BLINDS_PER_ANTE; curr_blind++)
111 {
112 Rect blind_req_and_reward_rect = SINGLE_BLIND_SEL_REQ_SCORE_RECT;
113
114 // To account for both raised blind and reward
115 blind_req_and_reward_rect.top -= TILE_SIZE;
116 blind_req_and_reward_rect.bottom += TILE_SIZE;
117
118 // To account for overflow
119 blind_req_and_reward_rect.right += TILE_SIZE;
120
121 blind_req_and_reward_rect.left +=
122 curr_blind * rect_width(&SINGLE_BLIND_SELECT_RECT) * TILE_SIZE;
123 blind_req_and_reward_rect.right +=
124 curr_blind * rect_width(&SINGLE_BLIND_SELECT_RECT) * TILE_SIZE;
125
126 tte_erase_rect_wrapper(blind_req_and_reward_rect);
127 }
128}
129
130void increment_blind(enum BlindState increment_reason)
131{
132 switch (g_game_vars.current_blind)
133 {
134 // defeated small blind: go to big
135 case BLIND_TYPE_SMALL:
136 g_game_vars.current_blind = BLIND_TYPE_BIG;
137 g_game_vars.blinds_states[SMALL_BLIND] = increment_reason;
138 g_game_vars.blinds_states[BIG_BLIND] = BLIND_STATE_CURRENT;
139 break;
140 // defeated big blind: go to next boss
141 case BLIND_TYPE_BIG:
142 g_game_vars.current_blind = g_game_vars.next_boss_blind;
143 g_game_vars.blinds_states[BIG_BLIND] = increment_reason;
144 g_game_vars.blinds_states[BOSS_BLIND] = BLIND_STATE_CURRENT;
145 break;
146 // defeated a boss: reset everything
147 default:
148 g_game_vars.current_blind = BLIND_TYPE_SMALL;
149 g_game_vars.blinds_states[SMALL_BLIND] = BLIND_STATE_CURRENT;
150 g_game_vars.blinds_states[BIG_BLIND] = BLIND_STATE_UPCOMING;
151 g_game_vars.blinds_states[BOSS_BLIND] = BLIND_STATE_UPCOMING;
152 break;
153 }
154}
155
156// TODO: convert these to proper buttons.
157static inline void highlight_select_button(void)
158{
159 memset16(&pal_bg_mem[BLIND_SELECT_BTN_SELECTED_BORDER_PID], 0xFFFF, 1);
160 memcpy16(&pal_bg_mem[BLIND_SKIP_BTN_SELECTED_BORDER_PID], &pal_bg_mem[BLIND_SKIP_BTN_PID], 1);
161}
162
163static inline void highlight_skip_button(void)
164{
165 memcpy16(
166 &pal_bg_mem[BLIND_SELECT_BTN_SELECTED_BORDER_PID],
167 &pal_bg_mem[BLIND_SELECT_BTN_PID],
168 1
169 );
170 memset16(&pal_bg_mem[BLIND_SKIP_BTN_SELECTED_BORDER_PID], 0xFFFF, 1);
171}
172
173static void game_blind_select_handle_input()
174{
175 if (s_timer == TM_BLIND_SELECT_START && g_game_vars.current_blind == BLIND_TYPE_BOSS)
176 {
177 selection_y = BLIND_ROW;
178 }
179
180 // Blind select input logic
181 if (key_hit(KEY_UP))
182 {
183 selection_y = BLIND_ROW;
184 highlight_select_button();
185 }
186 else if (key_hit(KEY_DOWN) && g_game_vars.current_blind <= BLIND_TYPE_BIG)
187 {
188 selection_y = SKIP_ROW;
189 highlight_skip_button();
190 }
191 else if (key_hit(SELECT_CARD))
192 {
193 game_blind_select_erase_blind_reqs_and_rewards();
194
195 switch (selection_y)
196 {
197 case BLIND_ROW:
198 play_sfx(SFX_BUTTON, MM_BASE_PITCH_RATE, BUTTON_SFX_VOLUME);
199 state_machine_change_state(&blind_select_sm, BLIND_SELECTED_ANIM_SEQ);
200 s_timer = TM_ZERO;
201 ++g_game_vars.round;
202 display_round();
203 break;
204 case SKIP_ROW:
205 if (g_game_vars.current_blind <= BLIND_TYPE_BIG)
206 {
207 play_sfx(SFX_BUTTON, MM_BASE_PITCH_RATE, BUTTON_SFX_VOLUME);
208 increment_blind(BLIND_STATE_SKIPPED);
209
210 selection_y = BLIND_ROW; // Reset selection to first option
211
212 change_background(BG_BLIND_SELECT, true);
213
214 // TODO: Create a generic vertical move by any number of tiles to avoid for
215 // loops?
216 for (int i = 0; i < 12; i++)
217 {
218 main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT, SCREEN_UP);
219 }
220
221 for (int i = 0; i < NUM_BLINDS_PER_ANTE; i++)
222 {
224 blind_select_tokens[i],
225 blind_select_tokens[i]->pos.x,
226 blind_select_tokens[i]->pos.y - (TILE_SIZE * 12)
227 );
228 }
229
230 game_blind_select_print_blinds_reqs_and_rewards();
231 highlight_select_button();
232
233 s_timer = TM_ZERO;
234 }
235 break;
236 default:
237 break;
238 }
239 }
240}
241
242static void game_blind_select_selected_anim_seq()
243{
244 if (s_timer < 15)
245 {
246 Rect blinds_rect = POP_MENU_ANIM_RECT;
247 blinds_rect.top -= 1; // Because of the raised blind
248 main_bg_se_move_rect_1_tile_vert(blinds_rect, SCREEN_DOWN);
249
250 for (int i = 0; i < NUM_BLINDS_PER_ANTE; i++)
251 {
253 blind_select_tokens[i],
254 blind_select_tokens[i]->pos.x,
255 blind_select_tokens[i]->pos.y + TILE_SIZE
256 );
257 }
258 }
259 else if (s_timer >= MENU_POP_OUT_ANIM_FRAMES)
260 {
261 for (int i = 0; i < NUM_BLINDS_PER_ANTE; i++)
262 {
263 sprite_hide(blind_select_tokens[i]);
264 }
265
266 s_timer = TM_ZERO;
267 state_machine_change_state(&blind_select_sm, DISPLAY_BLIND_PANEL);
268 }
269}
270
271static void game_blind_select_display_blind_panel()
272{
273 if (s_timer >= TM_DISP_BLIND_PANEL_FINISH)
274 {
275 state_machine_change_state(&blind_select_sm, BLIND_SELECT_EXIT);
276 return;
277 }
278
279 // Switches to the selecting background and clears the blind panel area
280 if (s_timer == TM_DISP_BLIND_PANEL_START)
281 {
282 change_background(BG_CARD_SELECTING, false);
283
284 // Need to clear the top left panel as a side effect of change_background()
285 main_bg_se_copy_expand_3w_row(TOP_LEFT_PANEL_ANIM_RECT, TOP_LEFT_PANEL_EMPTY_3W_ROW_POS);
286
288
289 if (g_game_vars.current_blind >= BLIND_TYPE_BOSS)
290 {
292 blind_get_color(g_game_vars.current_blind, BLIND_SHADOW_COLOR_INDEX)
293 );
294 }
295 }
296
297 // Shift the blind panel down onto screen
298 for (int y = 0; y < s_timer; y++)
299 {
300 int y_from = 26 + y - s_timer;
301 int y_to = 0 + y;
302
303 Rect from = {0, y_from, 8, y_from};
304 BG_POINT to = {0, y_to};
305
306 main_bg_se_copy_rect(from, to);
307 }
308}
309
310static void game_blind_select_exit(void)
311{
312 change_background(BG_NONE, false);
313 game_change_state(GAME_STATE_ROUND);
314}
315
316static Rect game_blind_select_get_req_score_rect(enum BlindTokens blind)
317{
318 Rect blind_req_score_rect = SINGLE_BLIND_SEL_REQ_SCORE_RECT;
319
320 blind_req_score_rect.left += blind * rect_width(&SINGLE_BLIND_SELECT_RECT) * TILE_SIZE;
321 blind_req_score_rect.right += blind * rect_width(&SINGLE_BLIND_SELECT_RECT) * TILE_SIZE;
322
323 if (g_game_vars.blinds_states[blind] == BLIND_STATE_CURRENT)
324 {
325 // Current blind is raised
326 blind_req_score_rect.top -= TILE_SIZE;
327 blind_req_score_rect.bottom -= TILE_SIZE;
328 }
329
330 return blind_req_score_rect;
331}
332
333static enum BlindType get_blind_type_from_token(enum BlindTokens blind)
334{
335 enum BlindType blind_type;
336 switch (blind)
337 {
338 case SMALL_BLIND:
339 blind_type = BLIND_TYPE_SMALL;
340 break;
341 case BIG_BLIND:
342 blind_type = BLIND_TYPE_BIG;
343 break;
344 default:
345 blind_type = g_game_vars.next_boss_blind;
346 break;
347 }
348 return blind_type;
349}
350
351static inline void game_blind_select_print_blind_req(enum BlindTokens blind)
352{
353 Rect blind_req_score_rect = game_blind_select_get_req_score_rect(blind);
354
355 u32 blind_req = blind_get_requirement(get_blind_type_from_token(blind), g_game_vars.ante);
356
357 char blind_req_str_buff[UINT_MAX_DIGITS + 1];
359 blind_req,
360 rect_width(&blind_req_score_rect) / TTE_CHAR_SIZE,
361 blind_req_str_buff
362 );
363
364 update_text_rect_to_right_align_str(&blind_req_score_rect, blind_req_str_buff, OVERFLOW_RIGHT);
365
366 tte_printf(
367 "#{P:%d,%d; cx:0x%X000}%s",
368 blind_req_score_rect.left,
369 blind_req_score_rect.top,
370 TTE_RED_PB,
371 blind_req_str_buff
372 );
373}
374
375static inline void game_blind_select_print_blind_reward(enum BlindTokens blind)
376{
377 int blind_reward = blind_get_reward(get_blind_type_from_token(blind));
378 Rect blind_reward_rect = game_blind_select_get_req_score_rect(blind);
379
380 // The reward is right below the score.
381 blind_reward_rect.top += TILE_SIZE;
382 blind_reward_rect.bottom += TILE_SIZE;
383
384 char blind_reward_str_buff[UINT_MAX_DIGITS + 2]; // +2 for null terminator and "$"
385 snprintf(blind_reward_str_buff, sizeof(blind_reward_str_buff), "$%d", blind_reward);
386
387 update_text_rect_to_right_align_str(&blind_reward_rect, blind_reward_str_buff, OVERFLOW_RIGHT);
388
389 tte_printf(
390 "#{P:%d,%d; cx:0x%X000}%s",
391 blind_reward_rect.left,
392 blind_reward_rect.top,
393 TTE_YELLOW_PB,
394 blind_reward_str_buff
395 );
396}
397
398static void game_blind_select_print_blinds_reqs_and_rewards(void)
399{
400 for (enum BlindTokens curr_blind = 0; curr_blind < NUM_BLINDS_PER_ANTE; curr_blind++)
401 {
402 game_blind_select_print_blind_req(curr_blind);
403 game_blind_select_print_blind_reward(curr_blind);
404 }
405}
406
407static inline void reroll_boss_blind(bool no_tiles)
408{
409 // Showdown blinds only show up on ante 8, 16, etc...
410 g_game_vars.next_boss_blind =
411 roll_blind_type((g_game_vars.ante % 8 == 0) && (g_game_vars.ante > 0));
412 if (!no_tiles)
413 {
414 apply_blind_tiles(g_game_vars.next_boss_blind, BOSS_BLIND_TOKEN_LAYER);
415 }
416}
417
418static void blind_tokens_init()
419{
420 if (g_game_vars.current_blind == BLIND_TYPE_SMALL)
421 reroll_boss_blind(true);
422
423 sprite_destroy(&blind_select_tokens[SMALL_BLIND]);
424 sprite_destroy(&blind_select_tokens[BIG_BLIND]);
425 sprite_destroy(&blind_select_tokens[BOSS_BLIND]);
426
427 blind_select_tokens[SMALL_BLIND] = blind_token_new(
428 BLIND_TYPE_SMALL,
429 CUR_BLIND_TOKEN_POS.x,
430 CUR_BLIND_TOKEN_POS.y,
431 SMALL_BLIND_TOKEN_LAYER
432 );
433 blind_select_tokens[BIG_BLIND] = blind_token_new(
434 BLIND_TYPE_BIG,
435 CUR_BLIND_TOKEN_POS.x,
436 CUR_BLIND_TOKEN_POS.y,
437 BIG_BLIND_TOKEN_LAYER
438 );
439 blind_select_tokens[BOSS_BLIND] = blind_token_new(
440 g_game_vars.next_boss_blind,
441 CUR_BLIND_TOKEN_POS.x,
442 CUR_BLIND_TOKEN_POS.y,
443 BOSS_BLIND_TOKEN_LAYER
444 );
445
446 for (int i = 0; i < NUM_BLINDS_PER_ANTE; i++)
447 {
448 sprite_hide(blind_select_tokens[i]);
449 }
450}
451
453{
454 s_timer = TM_ZERO;
455 state_machine_register(&blind_select_sm);
456 state_machine_change_state(&blind_select_sm, START_ANIM_SEQ);
457
458 selection_x = 0;
459 selection_y = 0;
460
461 blind_tokens_init();
462
463 // TODO: silly bug rn, the sprite tokens are unhidden on a background change.
464 // this probably shouldn't be here. also need to force redraw or the callback
465 // doesn't run that moves the tokens. that should probably happen here.
466 change_background(BG_BLIND_SELECT, true);
467
468 highlight_select_button();
469
471}
472
474{
475 s_timer++;
476}
477
479{
480 // For some reason that I haven't figured out yet,
481 // if I don't destroy the blind tokens they won't
482 // show up on the next run.
483 sprite_destroy(&blind_select_tokens[SMALL_BLIND]);
484 sprite_destroy(&blind_select_tokens[BIG_BLIND]);
485 sprite_destroy(&blind_select_tokens[BOSS_BLIND]);
486
487 change_background(BG_NONE, false);
488 selection_y = 0;
489
490 state_machine_remove(&blind_select_sm);
491}
492
494{
495 for (int i = 0; i < NUM_BLINDS_PER_ANTE; i++)
496 {
497 sprite_unhide(blind_select_tokens[i]);
498 }
499
500 // Default y position for the blind select tokens. 12 is the amount of tiles the background
501 // is shifted down by
502 const int default_y = 89 + (TILE_SIZE * 12);
503 // TODO refactor magic numbers '80/120/160' into a map to loop with
504 sprite_position(blind_select_tokens[SMALL_BLIND], BLIND_LEFT_X, default_y);
505 sprite_position(blind_select_tokens[BIG_BLIND], BLIND_CENTER_X, default_y);
506 sprite_position(blind_select_tokens[BOSS_BLIND], BLIND_RIGHT_X, default_y);
507
508 toggle_windows(false, true);
509
510 GRIT_CPY(pal_bg_mem, background_blind_select_gfxPal);
511 GRIT_CPY(&tile_mem[MAIN_BG_CBB], background_blind_select_gfxTiles);
512 GRIT_CPY(&se_mem[MAIN_BG_SBB], background_blind_select_gfxMap);
513
514 // Copy boss blind colors to blind select palette
515 memset16(
516 &pal_bg_mem[1],
517 blind_get_color(g_game_vars.next_boss_blind, BLIND_BACKGROUND_MAIN_COLOR_INDEX),
518 1
519 );
520 memset16(
521 &pal_bg_mem[7],
522 blind_get_color(g_game_vars.next_boss_blind, BLIND_BACKGROUND_SHADOW_COLOR_INDEX),
523 1
524 );
525
526 // Disable the button highlight colors
527 // Select button PID is 15 and the outline is 18
528 memcpy16(
529 &pal_bg_mem[BLIND_SELECT_BTN_SELECTED_BORDER_PID],
530 &pal_bg_mem[BLIND_SELECT_BTN_PID],
531 1
532 );
533 // It seems the skip button (and score multiplier and deck) PB idx is
534 // actually 5, not 10. 10 is the selected border color
535 // Setting this palette value though doesn't seem to have an
536 // effect.
537 memcpy16(&pal_bg_mem[BLIND_SKIP_BTN_SELECTED_BORDER_PID], &pal_bg_mem[BLIND_SKIP_BTN_PID], 1);
538
539 for (int i = 0; i < NUM_BLINDS_PER_ANTE; i++)
540 {
541 Rect curr_blind_rect = SINGLE_BLIND_SELECT_RECT;
542
543 // There's no gap between them
544 curr_blind_rect.left += i * rect_width(&SINGLE_BLIND_SELECT_RECT);
545 curr_blind_rect.right += i * rect_width(&SINGLE_BLIND_SELECT_RECT);
546
547 if (g_game_vars.blinds_states[i] != BLIND_STATE_CURRENT &&
548 (i == BLIND_TYPE_SMALL || i == BLIND_TYPE_BIG)) // Make the skip button gray
549 {
550 BG_POINT skip_blind_btn_pos_dest = {
551 BLIND_SKIP_BTN_PREANIM_DEST_RECT.left,
552 BLIND_SKIP_BTN_PREANIM_DEST_RECT.top
553 };
554 skip_blind_btn_pos_dest.x = curr_blind_rect.left;
555
556 Rect skip_blind_btn_rect_src = BLIND_SKIP_BTN_GRAY_RECT;
557 skip_blind_btn_rect_src.top += i * rect_height(&BLIND_SKIP_BTN_GRAY_RECT);
558 skip_blind_btn_rect_src.bottom += i * rect_height(&BLIND_SKIP_BTN_GRAY_RECT);
559
560 main_bg_se_copy_rect(skip_blind_btn_rect_src, skip_blind_btn_pos_dest);
561 }
562
563 switch (g_game_vars.blinds_states[i])
564 {
565 case BLIND_STATE_CURRENT: // Raise the blind panel up a bit
566 {
567 // TODO: Replace copies with main_bg_se_copy_rect() of named rects
568 int x_from = 0;
569 int y_from = 27;
570
571 main_bg_se_copy_rect_1_tile_vert(curr_blind_rect, SCREEN_UP);
572
573 int x_to = curr_blind_rect.left;
574 int y_to = 31;
575
576 if (i == BLIND_TYPE_BIG)
577 {
578 y_from = 31;
579 }
580 else if (i > BLIND_TYPE_BIG)
581 {
582 x_from = x_to;
583 y_from = 30;
584 }
585
586 // Copy plain tiles onto the bottom of the raised blind panel to fill the gap
587 // created by the raise
588 Rect gap_fill_rect =
589 {x_from, y_from, x_from + rect_width(&SINGLE_BLIND_SELECT_RECT) - 1, y_from};
590 BG_POINT gap_fill_point = {x_to, y_to};
591 main_bg_se_copy_rect(gap_fill_rect, gap_fill_point);
592
593 // Move token up by a tile
595 blind_select_tokens[i],
596 blind_select_tokens[i]->pos.x,
597 blind_select_tokens[i]->pos.y - TILE_SIZE
598 );
599 break;
600 }
601 case BLIND_STATE_UPCOMING: // Change the select icon to "NEXT"
602 {
603 int x_from = 0;
604 int y_from = 20;
605
606 int x_to = 10 + (i * rect_width(&SINGLE_BLIND_SELECT_RECT));
607 int y_to = 20;
608
609 memcpy16(
610 &se_mem[MAIN_BG_SBB][x_to + 32 * y_to],
611 &se_mem[MAIN_BG_SBB][x_from + 32 * y_from],
612 3
613 );
614 break;
615 }
616 case BLIND_STATE_SKIPPED: // Change the select icon to "SKIP"
617 {
618 int x_from = 3;
619 int y_from = 20;
620
621 int x_to = 10 + (i * 5);
622 int y_to = 20;
623
624 memcpy16(
625 &se_mem[MAIN_BG_SBB][x_to + 32 * y_to],
626 &se_mem[MAIN_BG_SBB][x_from + 32 * y_from],
627 3
628 );
629 break;
630 }
631 case BLIND_STATE_DEFEATED: // Change the select icon to "DEFEATED"
632 {
633 int x_from = 6;
634 int y_from = 20;
635
636 int x_to = 10 + (i * 5);
637 int y_to = 20;
638
639 memcpy16(
640 &se_mem[MAIN_BG_SBB][x_to + 32 * y_to],
641 &se_mem[MAIN_BG_SBB][x_from + 32 * y_from],
642 3
643 );
644 break;
645 }
646 default:
647 break;
648 }
649 }
650}
Utilities for affine background on GBA.
void affine_background_set_color(COLOR color)
Update the affine background color.
Utilities for using maxmod to play sound effects.
#define MM_BASE_PITCH_RATE
The default pitch rate for the sound effect played.
Definition audio_utils.h:37
void play_sfx(mm_word id, mm_word rate, mm_byte volume)
Play a sound effect, wrapper for mmEffectEx() See https://maxmod.org/ref/functions/mm_sound_effect....
#define SFX_DEFAULT_VOLUME
Default volume for sound effects.
Definition audio_utils.h:43
Data structures and functions relative to the behaviour and graphics of Blinds.
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:268
enum BlindType roll_blind_type(bool showdown)
Choose a random Blind among the ones that haven't been beaten yet.
Definition blind.c:162
BlindType
All Blind types in the game are listed here.
Definition blind.h:69
BlindState
All the possible states an Ante's Blinds can be in when viewed in the "Blind Select" screen.
Definition blind.h:121
u16 blind_get_color(enum BlindType type, enum BlindColorIndex index)
Get the color associated with a given Blind.
Definition blind.c:218
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:106
BlindTokens
The sprites that display the blinds when in "GAME_BLIND_SELECT" state. There are only 3 blinds per An...
Definition blind.h:21
Sprite * blind_token_new(enum BlindType type, int x, int y, enum BlindTokenLayers sprite_index)
Create a new BlindToken sprite.
Definition blind.c:281
int blind_get_reward(enum BlindType type)
Get the amount of money gained from beating a certain Blind.
Definition blind.c:115
Blind select state functions.
void game_blind_select_on_exit(void)
Blind select cleanup.
void game_blind_select_on_update(void)
Blind select state update.
void game_blind_select_on_init(void)
Blind select state initialization.
void game_blind_select_change_background(void)
Change to the blind select background.
A button structure containing the common button functionalities Including highlight and pressing func...
void change_background(enum BackgroundId id, bool force_redraw)
Definition common_ui.c:35
void reset_top_left_panel_bottom_row(void)
Restores the bottom row of the top-left panel from the background map.
Definition common_ui.c:48
Game global game variables struct definition.
Graphic utility functions.
void main_bg_se_move_rect_1_tile_vert(Rect se_rect, enum ScreenVertDir direction)
Moves a rect in the main background vertically in direction by a single tile.
INLINE int rect_height(const Rect *rect)
Get the height of a rectangle.
void main_bg_se_copy_rect_1_tile_vert(Rect se_rect, enum ScreenVertDir direction)
Copies a rect in the main background vertically in direction by a single tile.
void main_bg_se_copy_rect(Rect se_rect, BG_POINT dest_pos)
Copies a rect in the main background from se_rect to the position (x, y).
void toggle_windows(bool win0, bool win1)
Toggles the visibility of the window layers.
void update_text_rect_to_right_align_str(Rect *rect, const char *str, enum OverflowDir overflow_direction)
Changes rect->left so it fits the digits of num exactly when right aligned to rect->right....
#define TILE_SIZE
Tile size in pixels, both height and width as tiles are square.
#define TTE_CHAR_SIZE
By default TTE characters occupy a single tile.
void tte_erase_rect_wrapper(Rect rect)
A wrapper for tte_erase_rect that would use the rect struct.
void main_bg_se_copy_expand_3w_row(Rect se_dest_rect, BG_POINT src_row_left_pnt)
Copies a 3-width SE rect and expands it to fit a passed rect.
INLINE int rect_width(const Rect *rect)
Get the width of a rectangle.
Header of shared rects and points needed for ui.
Sprite system for Gbalatro.
INLINE void sprite_position(Sprite *sprite, int x, int y)
Set sprite position. Inlined for efficiency.
Definition sprite.h:400
void sprite_destroy(Sprite **sprite)
Destroy Sprite.
Definition sprite.c:93
void sprite_hide(Sprite *sprite)
Hides the sprite by manipulating ATTR0_HIDE in OAM.
Definition sprite.c:171
void sprite_unhide(Sprite *sprite)
Unhides the sprite by manipulating ATTR0_HIDE in OAM. The sprite's ATTR0_MODE is maintained from the ...
Definition sprite.c:178
State Machine.
void state_machine_remove(StateMachine *state_machine)
Remove a statemachine's update function.
void state_machine_register(StateMachine *state_machine)
Register a statemachine to run it's update function once per frame.
void state_machine_change_state(StateMachine *state_machine, int new_state)
Calls the current state's on_exit, the new state's on_init, and sets the active update fn.
Sprite struct for GBA hardware specifics.
Definition sprite.h:29
POINT pos
Sprite position on screen in pixels.
Definition sprite.h:43
State machine callbacks.
State machine instance.
Timer constants.
Utilities relating around number string representation and protected arithmatic helper functions.
void truncate_uint_to_suffixed_str(uint32_t num, int num_req_chars, char out_str_buff[UINT_MAX_DIGITS+1])
Truncate an unsigned number into a suffixed string representation e.g. 12000 -> "12K" The least signi...
Definition util.c:116