Alchemy
Loading...
Searching...
No Matches

psynergy_menu.c

Go to the documentation of this file.
1/// @file
2/// The battle Psynergy menu.
3/// Part of battle_command.c, the menu object, compiled only through it.
4
6
7/// Selects a Psynergy-list position, or -1 on cancel. The list shows PP cost
8/// and range, and confirmation rejects abilities the unit cannot use.
9s32 BattleMenu_RunActionSelection(s32 unitId, u16 *actions, s32 count) {
10 struct UiRenderWork *render;
11 s32 drawnFirstEntry;
12 s32 firstEntry;
13 s32 drawnRow;
14 s32 cursorHandle;
15 struct BattleUnit *unit;
16 struct UiWindow *messageWindow;
17 s32 iconCount;
18 s32 preferredRow;
19 struct MenuPoint cursorPosition;
20 struct BattleMenuWork *navigation;
21 struct UiWindow *window;
22 s32 selectedRow;
23 s32 encodedAction;
24 s32 iconTile;
25 s32 pageTile;
26 s32 rangePattern;
27 s32 result;
28 s32 i;
29 struct MenuSprite cursor;
30 struct MenuSprite *iconSprite;
31 u16 messageText[64];
32 s32 iconSlots[BATTLE_LIST_ROWS];
33 struct MenuSprite sprites[BATTLE_LIST_ROWS];
34 s32 glyph;
35
36 render = UI_WORK;
37 drawnRow = -1;
38 drawnFirstEntry = -1;
39 cursorHandle = VramCache_AllocEntry(128);
40 unit = UnitGetFar(unitId);
41 messageWindow = UiWindow_Create(0, 5, 30, 4, 42);
42 iconCount = BATTLE_LIST_ROWS;
43 BATTLE_MENU_GET_CURSOR(firstEntry, selectedRow, preferredRow);
44 window = UiWindow_Create(9, 9, 21, BATTLE_LIST_ROWS * 2 + 1, 6);
45
46 for (i = 0; i < BATTLE_LIST_ROWS; i++) {
47 s32 y = i * 2;
48
49 iconSprite = &sprites[i];
51 iconSprite->oam.f.x = window->x * 8 + 8;
52 iconSprite->oam.f.y = (y + window->y) * 8 + 4;
53 }
54
55 // Reserve one glyph slot per visible row; paging reloads these same slots.
56 for (i = 0; i < BATTLE_LIST_ROWS; i++) {
57 iconSlots[i] = VramCache_AllocEntry(128);
58 sprites[i].oam.f.tile = VramCache_Reload(iconSlots[i], -1);
59 }
60
65
66 iconSprite = &cursor;
67 for (;;) {
68 if (firstEntry != drawnFirstEntry || selectedRow != drawnRow) {
69 render->menuBusy = 1;
70 Ui_SetRectHighlight(window->x + 1, window->y + drawnRow * 2 + 1,
71 window->width - 2, 1, 15);
73 if (count != 0) {
75 (actions[firstEntry + selectedRow] & ACTION_ID_MASK) +
76 MsgAbilityDescription,
77 messageText, BATTLE_MENU_MESSAGE_CAPACITY);
78 } else {
79 BATTLE_MENU_MESSAGE_COPY(MSGNO(MsgBattleNoPsynergy), messageText,
81 }
82 UiText_RenderWideStringAtOffset(messageText, messageWindow, 0, 4);
83 drawnRow = selectedRow;
84
85 // Cursor moves update help; only a page change reloads the row icons.
86 if (firstEntry != drawnFirstEntry) {
88 for (i = 0; i < BATTLE_LIST_ROWS; i++) {
89 struct BattleAct *action;
90
91 encodedAction = actions[firstEntry + i];
92 if (encodedAction == 0) {
93 break;
94 }
95 action = BattleActGet(encodedAction);
96 UiWindow_SetTilemapEntry(window, 0xf01f, 11, i * 2, 0);
98 0);
99 Ability_LoadGlyph(encodedAction & ACTION_ID_MASK, 0, &iconSlots[i],
100 &glyph, 1);
101 sprites[i].oam.f.tile = glyph;
102
103 if ((action->flags & ACTION_USABLE_IN_BATTLE) == 0) {
105 } else if (action->ppCost > unit->pp) {
107 } else if (unit->psySeal != 0) {
109 }
110
111 render->level = 5;
112 UiText_DrawCharacterAtOffset(encodedAction + MsgAbilityName, window,
113 16, i * 16);
114 UiText_DrawNumberAtOffset(action->ppCost, 2, window, 104, i * 16);
116 render->level = 15;
117
118 if (action->element != 4) {
119 UiWindow_SetTilemapEntry(window, action->element + 0x5001, 15,
120 i * 2, 0);
121 }
122
123 rangePattern = action->range;
124 if (rangePattern == ABILITY_RANGE_ALL) {
125 rangePattern = 11;
126 } else {
127 rangePattern--;
128 }
129 UiWindow_DrawThreeTileColumn(window, 16, i * 2, rangePattern, 0);
130 }
131 iconCount = i;
132 drawnFirstEntry = firstEntry;
133 }
134
135 if (count > BATTLE_LIST_ROWS) {
136 for (i = 0; i < (count + 4) / BATTLE_LIST_ROWS; i++) {
137 iconTile = i + 0xf301;
138 if (i == firstEntry / BATTLE_LIST_ROWS) {
139 iconTile = i + 0xf30b;
140 }
142 window, iconTile,
143 window->width - (count + 4) / BATTLE_LIST_ROWS + i - 2, -1, 0);
144 }
145 }
146
147 Ui_SetRectHighlight(window->x + 1, window->y + selectedRow * 2 + 1,
148 window->width - 2, 1, 14);
149 render->dirty = 1;
150 render->menuBusy = 0;
151 }
152
153 if (count > BATTLE_LIST_ROWS) {
154 for (i = 0; i < (count + 4) / BATTLE_LIST_ROWS; i++) {
155 iconTile = i + 0xf301;
156 if ((gFrameCount & 15) <= 11) {
157 if (i == firstEntry / BATTLE_LIST_ROWS) {
158 iconTile = i + 0xf30b;
159 }
160 }
162 window, iconTile,
163 window->width - (count + 4) / BATTLE_LIST_ROWS + i - 2, -1, 0);
164 }
165 pageTile = -1;
167 window, 0xf334, window->width - (count + 4) / BATTLE_LIST_ROWS - 3,
168 pageTile, 0);
169 UiWindow_SetTilemapEntry(window, 0xf335, window->width - 2, pageTile, 0);
170 UiRender_MarkRow(render, window->y - 1);
171 }
172
173 for (i = 0; i < iconCount; i++) {
174 Runtime_PushSlotEntry(&sprites[i], 240);
175 }
176
177 cursorPosition.x = window->x * 8 - 4;
178 cursorPosition.y = (selectedRow * 2 + window->y) * 8 + 20;
179 ((u32 *)iconSprite)[1] = 0x40000000;
180 ((u32 *)iconSprite)[2] = 0;
181 iconSprite->oam.f.tile =
183 iconSprite->oam.f.x = cursorPosition.x + ((gFrameCount & 4) >> 1) - 4;
184 iconSprite->oam.f.y = cursorPosition.y - ((gFrameCount & 4) >> 2) - 8;
185 if (count != 0) {
186 Runtime_PushSlotEntry(iconSprite, 242);
187 }
188
189 BATTLE_MENU_SET_CURSOR(firstEntry, selectedRow, preferredRow);
190 navigation = gLinkCountdownWork;
191
192 if ((gKeysPressed & KEY_A) != 0) {
193 if (count != 0) {
194 result = firstEntry + selectedRow;
195 if ((BattleActGet(actions[result])->flags & ACTION_USABLE_IN_BATTLE) !=
196 0) {
197 break;
198 }
199 /* FAKEMATCH(dead): a dead store keeps the test above from being
200 * threaded past the break; without it, 2 of 794 instructions differ in
201 * tbs-en. */
202 result = -1;
203 } else {
204 result = -1;
205 break;
206 }
207 } else if (navigation->timer == 0 || (gKeysPressed & KEY_B) != 0) {
209 result = -1;
210 break;
211 }
212
213 if (count != 0) {
214 if ((gKeysRepeat & KEY_DOWN) != 0) {
216 selectedRow++;
217 if (selectedRow == BATTLE_LIST_ROWS ||
218 firstEntry + selectedRow == count) {
219 selectedRow = 0;
220 }
221 preferredRow = selectedRow;
222 } else if ((gKeysRepeat & KEY_UP) != 0) {
224 selectedRow--;
225 if (selectedRow < 0) {
226 if (firstEntry == (count - 1) / BATTLE_LIST_ROWS * BATTLE_LIST_ROWS) {
227 selectedRow = count - firstEntry - 1;
228 } else {
229 selectedRow = BATTLE_LIST_ROWS - 1;
230 }
231 }
232 preferredRow = selectedRow;
233 } else if ((gKeysRepeat & KEY_RIGHT) != 0) {
236 if (firstEntry + BATTLE_LIST_ROWS >= count) {
237 if (firstEntry != 0) {
238 firstEntry = 0;
239 selectedRow = preferredRow;
240 }
241 } else {
242 firstEntry += BATTLE_LIST_ROWS;
243 selectedRow = preferredRow;
244 if (firstEntry == (count - 1) / BATTLE_LIST_ROWS * BATTLE_LIST_ROWS) {
245 selectedRow = count - firstEntry - 1;
246 if (selectedRow > preferredRow) {
247 selectedRow = preferredRow;
248 }
249 }
250 }
251 } else if ((gKeysRepeat & KEY_LEFT) != 0) {
254 if (firstEntry != 0) {
255 selectedRow = preferredRow;
256 firstEntry -= BATTLE_LIST_ROWS;
257 } else {
258 firstEntry = (count - 1) / BATTLE_LIST_ROWS * BATTLE_LIST_ROWS;
259 selectedRow = preferredRow;
260 if (firstEntry != 0) {
261 selectedRow = count - firstEntry - 1;
262 if (selectedRow > preferredRow) {
263 selectedRow = preferredRow;
264 }
265 }
266 }
267 }
268 }
269 WaitFrames(1);
270 }
271
272 UiWork_Finalize(messageWindow, 1);
273 UiWork_Finalize(window, 1);
274 WaitFrames(1);
275 for (i = 0; i < BATTLE_LIST_ROWS; i++) {
276 Resource_ResetEntry(iconSlots[i]);
277 }
278 Resource_ResetEntry(cursorHandle);
279 WaitFrames(1);
280 return result;
281}
What every part of the menu object shares: its includes, edition values, macros and the link round st...
#define BATTLE_MENU_MESSAGE_COPY
#define PSYNERGY_COST_SECOND_TILE
#define BATTLE_MENU_MESSAGE_CAPACITY
#define ABILITY_RANGE_ALL
BattleAct.range of an ability that reaches every unit on the side, each as if aimed at.
Definition battle_unit.h:46
void Ui_SetRectHighlight(s32 x, s32 y, s32 width, s32 height, s32 paletteBit)
Sets bit 12 of each tile in a screen-space rectangle, preserving the other tile attributes.
struct BattleUnit * UnitGetFar(u32 owner)
struct BattleAct * BattleActGet(s32 actionId)
Far call to BattleAction_GetDirect.
void AudioCommand_PlayFar(s32 id)
void Input_ResetKeyRepeat(void)
Restarts the key repeat delay, so held keys wait the full delay again.
Definition frame.c:289
void WaitFrames(s32 frames)
The game's frame loop: runs frames frames and returns.
Definition frame.c:97
volatile u32 gFrameCount
Frames WaitFrames has finished.
void UiText_RenderWideStringAtOffset(u16 *text, struct UiWindow *window, s32 x, s32 y)
Draws a zero-terminated string of 16-bit character codes into a text canvas window at pixel (x,...
Definition glyphs.c:258
u8 gResource_FixedBlockBTiles[]
@ KEY_UP
Definition io_reg.h:249
@ KEY_B
Definition io_reg.h:244
@ KEY_LEFT
Definition io_reg.h:248
@ KEY_RIGHT
Definition io_reg.h:247
@ KEY_A
Definition io_reg.h:243
@ KEY_DOWN
Definition io_reg.h:250
void Vram_CopyTile(u32 sourceTile, u32 destinationTile)
Copies one 4bpp VRAM tile, ignoring the palette and flip bits of each entry.
Definition item_menu.c:38
volatile u32 gKeysPressed
Keys that went down this frame.
volatile u32 gKeysRepeat
Pressed keys, repeating while held: after 19 frames, then every 6.
#define ACTION_USABLE_IN_BATTLE
struct BattleMenuWork * gLinkCountdownWork
#define MenuSprite_Init(sprite, shape)
Sets sprite shape (attr0/attr1) and clears the remaining fields.
Definition menu_list.h:76
#define MENU_SPRITE_SIZE_16
Definition menu_list.h:67
#define BATTLE_MENU_SET_CURSOR(page_, row_, preferred_)
Saves the selection: page, row and return row.
Definition menu_list.h:183
#define BATTLE_MENU_GET_CURSOR(page_, row_, preferred_)
Restores the previous selection: page, row and return row.
Definition menu_list.h:163
@ BATTLE_LIST_ROWS
Definition menu_list.h:20
int UiWindow_DrawThreeTileColumn(struct UiWindow *window, s32 x, s32 y, s32 pattern, s32 unused)
Definition pictures.c:179
s32 BattleMenu_RunActionSelection(s32 unitId, u16 *actions, s32 count)
Selects a Psynergy-list position, or -1 on cancel.
void Runtime_PushSlotEntry(void *slotEntry, s32 slot)
Links a sprite entry into depth slot slot (clamped to 0..255) for this frame.
Definition render.c:79
#define SE_MENU_CANCEL
Definition songs.h:106
#define SE_MENU_CURSOR_MOVE
Definition songs.h:104
An ability's definition, a row of gBattleAction_DefinitionTable: its targeting, kind,...
u8 ppCost
PP the ability costs.
u8 range
the aimed unit and range - 1 either side, or ABILITY_RANGE_ALL
u8 element
enum Element
u8 flags
bits: 7 usable in battle | 6 usable in the field | 5..4 clear in every row | 3..0 kind (ABILITY_KIND_...
The battle command menus' work, heap slot 57 (0x104 bytes), reached as gLinkCountdownWork.
Definition menu_list.h:107
s32 timer
Frames left to choose commands in a link battle; -1 outside link battles.
Definition menu_list.h:131
A unit in battle: a party member's or an enemy's stats, Psynergy, items, Djinn and ailments.
u8 psySeal
bits: 7..3 Luff (16 when cast, minus 8 a turn) | 2..0 Bind's turns (7 when cast).
s16 pp
current PP
A point on the screen where a menu shows its cursor.
Definition menu_list.h:97
s32 y
screen pixels
Definition menu_list.h:99
s32 x
screen pixels
Definition menu_list.h:98
A menu sprite: a list link and its OAM attributes, as two words or as fields.
Definition menu_list.h:24
union MenuSprite::@002225022013150231017316170057321303227123371224 oam
The window system's work: the windows' tilemap, the windows, the three text channels,...
Definition window.h:19
u8 dirty
The tilemap's 4-row bands to upload: bit 0 for all, bit n + 1 for band n.
Definition window.h:32
u8 level
text tiles' palette; 15 by default, 14 or 5 for low HP
Definition window.h:41
u8 menuBusy
while set, the tilemap is not uploaded
Definition window.h:40
A window: a framed rectangle of the tilemap with its sprite outputs, its opening or closing animation...
Definition uiwindow.h:11
u16 y
tiles
Definition uiwindow.h:16
u16 x
tiles
Definition uiwindow.h:15
u16 width
tiles
Definition uiwindow.h:13
void UiText_DrawNumberAtOffset(s32 value, s32 width, const struct UiWindow *window, s32 x, s32 y)
Draws a number (width as UiText_FormatNumber) as tiles in a window at pixel (x, y) of its interior.
Definition text_tiles.c:668
void UiWork_SetParamNibble(s32 param)
Sets the text colour (0 to 15) of drawn text.
Definition text_tiles.c:524
void UiText_DrawCharacterAtOffset(s32 message, const struct UiWindow *window, u32 offsetX, u32 offsetY)
Decodes a message and draws it as tiles in a window at pixel (offsetX, offsetY) of its interior.
Definition text_tiles.c:552
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
unsigned short u16
Definition types.h:13
#define UiRender_MarkRow(render, y)
Requests transfer of the four-row tilemap band containing window row y.
Definition uiwindow.h:73
#define ACTION_ID_MASK
Definition window.h:269
#define UI_WORK
Definition window.h:267
@ UI_TILE_FRAME_BOTTOM_TEE
the bottom edge meeting a line
Definition window.h:94
@ UI_TILE_FRAME_TOP_TEE
the top edge meeting a line
Definition window.h:93
s32 VramCache_AllocEntry(s32 size)
Takes a free cache entry, gives it size bytes of sprite VRAM and returns its number.
Definition vram_cache.c:227
s32 VramCache_Reload(s32 no, s32 src)
Copies src again into entry no's VRAM, keeping its size.
Definition vram_cache.c:238
s32 Resource_ResetEntry(u32 no)
Frees cache entry no: its blocks go back and the entry is marked free (offset 0xffff).
Definition vram_cache.c:106
void Ability_LoadGlyph(s32 action, s32 withBase, s32 *slot, s32 *tile, s32 reuse)
Builds the Psynergy icon of a battle action, as UiIcon_BuildAbilityIconTiles.
Definition icons.c:234
void UiWindow_SetTilemapEntry(struct UiWindow *window, s32 value, s32 x, s32 y, u32 mode)
Writes value into a window's tilemap at tile (x, y) of its interior, with the palette mode names (TIL...
Definition sprites.c:345
s32 Ui_FillVramBlockPattern(void)
Fills the text canvas with the window background colour (4).
Definition windows.c:619
void UiWork_Finalize(struct UiWindow *window, s32 instant)
Closes a window: clears its contents and remembers its last rectangle.
Definition windows.c:349
void RenderOutput_RedrawSavedRect(struct UiWindow *window)
Redraws a window's empty frame at its current rectangle.
Definition windows.c:400
struct UiWindow * UiWindow_Create(s32 x, s32 y, s32 width, s32 height, s32 attrs)
Opens a window at tile (x, y) of width by height tiles in the first free window slot,...
Definition windows.c:279