GBAlatro
A Demake of Balatro for the GBA
Loading...
Searching...
No Matches
main_menu.c
1#include "game/main_menu.h"
2
3#include "affine_background.h"
4#include "audio_utils.h"
5#include "background_main_menu_gfx.h"
6#include "button.h"
7#include "card.h"
8#include "game.h"
9#include "game/common_ui.h"
10#include "game_variables.h"
11#include "graphic_utils.h"
12#include "selection_grid.h"
13#include "soundbank.h"
14#include "sprite.h"
15#include "version.h"
16
17#include <stdint.h>
18#include <tonc.h>
19#include <tonc_math.h>
20#include <tonc_memdef.h>
21
22#define PLAY_BUTTON_MAIN_COLOR_PID 1
23#define PLAY_BUTTON_OUTLINE_PID 2
24#define OPTIONS_BUTTON_MAIN_COLOR_PID 3
25#define OPTIONS_BUTTON_OUTLINE_PID 4
26
27enum MainButtons
28{
29 PLAY_BTN_IDX,
30 OPTIONS_BTN_IDX,
31 MAIN_MENU_NB_BTN
32};
33
34// Pixel sizes
35#define MAIN_MENU_ACE_T_X 88
36#define MAIN_MENU_ACE_T_Y 26
37
38// clang-format off
39static const BG_POINT GBALATRO_VERSION_TEXT_POS = {0, 152};
40static const Rect GBALATRO_VERSION_TEXT_RECT = {0, 152, 240, 160};
41// clang-format on
42
43// Define SelectionGrid for the main menu buttons
44
45static int main_menu_return_row_size(void);
46static bool main_menu_on_selection_changed(
47 SelectionGrid* selection_grid,
48 int row_idx,
49 const Selection* prev_selection,
50 const Selection* new_selection
51);
52static void main_menu_on_key_transit(SelectionGrid* selection_grid, Selection* selection);
53
54static void play_on_pressed(void);
55static void options_on_pressed(void);
56
57// clang-format off
58static SelectionGridRow main_menu_selection_rows[] = {
59 {
60 0,
61 main_menu_return_row_size,
62 main_menu_on_selection_changed,
63 main_menu_on_key_transit,
64 {.wrap = false}
65 },
66};
67
68static Button main_menu_buttons[] = {
69 {PLAY_BUTTON_OUTLINE_PID, PLAY_BUTTON_MAIN_COLOR_PID, play_on_pressed, NULL},
70 {OPTIONS_BUTTON_OUTLINE_PID, OPTIONS_BUTTON_MAIN_COLOR_PID, options_on_pressed, NULL},
71};
72
73static SelectionGrid main_menu_selection_grid = {
74 main_menu_selection_rows,
75 1,
76 {0, 0}
77};
78// clang-format on
79
80// Main menu sprite - the ace of spades
81static CardObject* s_main_menu_ace = NULL;
82
83// Keep track of last highlighted button
84static enum MainButtons s_last_highlighted_button = PLAY_BTN_IDX;
85
87{
88 toggle_windows(false, false);
89
90 tte_erase_screen();
91 GRIT_CPY(pal_bg_mem, background_main_menu_gfxPal);
92 GRIT_CPY(&tile_mem[MAIN_BG_CBB], background_main_menu_gfxTiles);
93 GRIT_CPY(&se_mem[MAIN_BG_SBB], background_main_menu_gfxMap);
94
95 // Disable all button highlight colors
96 for (int i = 0; i < MAIN_MENU_NB_BTN; i++)
97 {
98 button_set_highlight(&main_menu_buttons[i], false);
99 }
100}
101
103{
105 change_background(BG_MAIN_MENU, true);
106 s_main_menu_ace = card_object_new(card_new(SPADES, ACE));
107 card_object_set_sprite(s_main_menu_ace, 0);
108 // TODO: NULL-check sprite
109 s_main_menu_ace->sprite->obj->attr0 |= ATTR0_AFF_DBL;
110 s_main_menu_ace->tscale = float2fx(0.8f);
111 sprite_object_position((SpriteObject*)s_main_menu_ace, MAIN_MENU_ACE_T_X, MAIN_MENU_ACE_T_Y);
112
113 // Select last highlighted button, Play button by default.
114 // e.g. if we return from the options menu, we want the Options button to be highlighted.
115 Selection sel_init = {s_last_highlighted_button, 0};
116 main_menu_selection_grid.selection = sel_init;
117
118 // Highlight current button
119 button_set_highlight(&main_menu_buttons[main_menu_selection_grid.selection.x], true);
120}
121
123{
124 s_main_menu_ace->trotation = lu_sin((g_game_vars.timer << 8) / 2) / 3;
125
126 selection_grid_process_input(&main_menu_selection_grid);
127}
128
130{
131 // Save selected button
132 s_last_highlighted_button = main_menu_selection_grid.selection.x;
133
134 // Normally I would just cache these and hide/unhide but I didn't feel like dealing with
135 // defining a layer for it
136 card_destroy(&s_main_menu_ace->card);
137 card_object_destroy(&s_main_menu_ace);
138}
139
140// Implement SelectionGrid handler functions
141
142static int main_menu_return_row_size(void)
143{
144 return MAIN_MENU_NB_BTN;
145}
146
147static bool main_menu_on_selection_changed(
148 SelectionGrid* selection_grid,
149 int row_idx,
150 const Selection* prev_selection,
151 const Selection* new_selection
152)
153{
154 if (prev_selection->x >= 0 && prev_selection->x < MAIN_MENU_NB_BTN)
155 {
156 button_set_highlight(&main_menu_buttons[prev_selection->x], false);
157 }
158
159 play_sfx(SFX_BUTTON, MM_BASE_PITCH_RATE, BUTTON_SFX_VOLUME);
160 button_set_highlight(&main_menu_buttons[new_selection->x], true);
161
162 return true;
163}
164
165static void main_menu_on_key_transit(SelectionGrid* selection_grid, Selection* selection)
166{
167 // DEBUG: toggle git hash display by pressing L+R+START+SELECT
168 static bool combo_pressed = false;
169 static bool show_version = false;
170 if (key_is_down(KEY_START) && key_is_down(KEY_SELECT) && key_is_down(KEY_L) &&
171 key_is_down(KEY_R))
172 {
173 if (!combo_pressed)
174 {
175 show_version = !show_version;
176 if (show_version)
177 {
178 tte_printf(
179 "#{P:%d,%d; cx:0x%X000}%s",
180 GBALATRO_VERSION_TEXT_POS.x,
181 GBALATRO_VERSION_TEXT_POS.y,
182 TTE_WHITE_PB,
183 gbalatro_version
184 );
185 }
186 else
187 {
188 tte_erase_rect_wrapper(GBALATRO_VERSION_TEXT_RECT);
189 }
190 }
191
192 combo_pressed = true;
193 }
194 else
195 {
196 combo_pressed = false;
197 }
198
199 if (key_hit(SELECT_CARD))
200 {
201 button_press(&main_menu_buttons[selection->x]);
202 }
203}
204
205static void play_on_pressed(void)
206{
207 game_change_state(GAME_STATE_RUN_SETUP);
208}
209
210static void options_on_pressed(void)
211{
212 game_change_state(GAME_STATE_OPTIONS_MENU);
213}
Utilities for affine background on GBA.
@ AFFINE_BG_MAIN_MENU
Display background for main menu.
void affine_background_change_background(enum AffineBackgroundID new_bg)
Update the background id.
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....
A button structure containing the common button functionalities Including highlight and pressing func...
void button_press(Button *button)
Execute a button press, by calling the button's on_pressed function. This checks the button's can_be_...
Definition button.c:18
void button_set_highlight(Button *button, bool highlight)
Set the button highlight on or off.
Definition button.c:8
Common functions to render UI elements.
void change_background(enum BackgroundId id, bool force_redraw)
Definition common_ui.c:35
Game global game variables struct definition.
Graphic utility functions.
void toggle_windows(bool win0, bool win1)
Toggles the visibility of the window layers.
void tte_erase_rect_wrapper(Rect rect)
A wrapper for tte_erase_rect that would use the rect struct.
Main menu state functions.
void game_main_menu_on_update(void)
Main menu state update.
Definition main_menu.c:122
void game_main_menu_on_exit(void)
Main menu cleanup (called when transitioning to game start)
Definition main_menu.c:129
void game_main_menu_change_background(void)
Change the main menu background.
Definition main_menu.c:86
void game_main_menu_on_init(void)
Main menu state initialization.
Definition main_menu.c:102
An implementation for a selection grid that handles directional selection.
void selection_grid_process_input(SelectionGrid *selection_grid)
Processes user input for the selection grid.
Sprite system for Gbalatro.
INLINE void sprite_object_position(SpriteObject *sprite_object, int x, int y)
Set sprite_object position. Inlined for efficiency.
Definition sprite.h:417
A button representation.
Definition button.h:31
The core selection grid struct, represents the grid itself and its state.
A sprite object is a sprite that is focusable and movable in animation.
Definition sprite.h:61
Game ROM version global var declaration.