Alchemy
Loading...
Searching...
No Matches

command_row.c

Go to the documentation of this file.
1/// @file
2/// The row of command icons the player picks a command from.
3/// Part of battle_command.c, the menu object, compiled only through it.
4
6
7/// Opens a message at (x, y), waits for its text to finish, and returns its
8/// window so the caller can hold it open for a separate prompt.
10 struct UiWindow *result;
11
12 result = UiText_OpenMessageWindow(message, x, y, 1);
13 while (UiWork_IsComplete() == 0)
14 WaitFrames(1);
15 return result;
16}
17
18#if TBS_PATCH_1
19#define WINDOW_X 22 /* Window X position */
20#else
21#define WINDOW_X 23
22#endif
23
24/// Selects a command icon, returning its kind, -1 for cancel or -2 for a
25/// shoulder-button switch. Mode 0 is the top menu; the other mode selects
26/// a battle command and remembers its own cursor. Tutorial input is replayed
27/// through the same selection path.
29 u8 party[4];
30 struct UiRenderWork *render;
31 struct SelectionWork *selectionUi;
32 struct BattleMenuWork *navigation;
33 s32 stripDirty, tradeCount, pulseScale, command;
34 s32 entryIndex;
35 s32 keys, repeat;
36 s32 iconSlot;
37 s32 i, kindCount;
38
39 render = UI_WORK;
40 iconSlot = VramCache_AllocEntry(0x400);
41 stripDirty = 1;
42 tradeCount = 0;
43 selectionUi = Runtime_BumpAllocateAlternatePool(sizeof(*selectionUi));
44 for (i = 255; i >= 0; i--)
45 selectionUi->palette.slot[i] = 255;
46 selectionUi->palette.count = 1;
47 if (mode == 0)
48 selectionUi->window = UiWindow_Create(20, 17, 10, 3, 6);
49 else
50 selectionUi->window = UiWindow_Create(WINDOW_X, 17, 30 - WINDOW_X, 3, 6);
51 selectionUi->drawnIndex = -1;
52 if (mode == 0) {
53 kindCount = 0;
54 selectionUi->commandKinds[kindCount++] = 14;
55 selectionUi->commandKinds[kindCount++] = 4;
56 selectionUi->commandKinds[kindCount++] = 7;
57 selectionUi->commandKinds[kindCount] = -1;
59 } else {
61 kindCount = 0;
62 selectionUi->commandKinds[kindCount++] = 0;
63 selectionUi->commandKinds[kindCount++] = 1;
64 if (*((s32 *)Djinn_GetRecoveryTableFar(0)) != 0) {
66 for (i = 0; i <= 3; i++)
67 tradeCount += party[i];
68 selectionUi->commandKinds[kindCount++] = 15;
69 if (tradeCount != 0)
70 selectionUi->commandKinds[kindCount++] = 16;
71 }
72 selectionUi->commandKinds[kindCount++] = 2;
73 selectionUi->commandKinds[kindCount++] = 3;
74 selectionUi->commandKinds[kindCount] = -1;
75 }
76 // Decode each visible command through one shared remapped palette.
77 for (entryIndex = 0; entryIndex <= 5; entryIndex++) {
78 selectionUi->entries[entryIndex].resource = iconSlot;
79 if (selectionUi->commandKinds[entryIndex] == -1)
80 break;
81 UiText_DrawCharacter(selectionUi, entryIndex,
82 selectionUi->commandKinds[entryIndex]);
83 }
84 selectionUi->iconCount = entryIndex;
85 selectionUi->affine.scaleX = 320;
86 selectionUi->affine.scaleY = 304;
87 selectionUi->affine.angle = 0;
88 entryIndex = 0;
89 if (entryIndex < selectionUi->iconCount) {
90 do {
91 s32 x = (entryIndex - selectionUi->iconCount) * 24;
92 selectionUi->entries[entryIndex].posX = x + 155;
93 if (mode != 0)
94 selectionUi->entries[entryIndex].posX = x + WINDOW_X * 8 - 5;
95 selectionUi->entries[entryIndex].posY = 136;
96 entryIndex++;
97 } while (entryIndex < selectionUi->iconCount);
98 }
101
102 for (;;) {
103 pulseScale = gUi_BounceScales[(gFrameCount * 2) & 31];
104 pulseScale = (pulseScale - 256) / 4 + 304;
105 selectionUi->affine.scaleY = selectionUi->affine.scaleX = pulseScale;
106 gBgScroll[1].x = 0;
107 gBgScroll[1].y = 32;
108 if (stripDirty != 0) {
109 stripDirty = 0;
110 render->menuBusy = 1;
111 if (mode) {
112 s32 panel;
113 s32 count;
114 for (panel = 0; panel < 6 - selectionUi->iconCount; panel++) {
115 for (entryIndex = 0; entryIndex <= 2; entryIndex++) {
116 s32 col;
117 for (col = 0; col <= 2; col++)
118 *(render->tilemap + (entryIndex + 17) * 32 + panel * 3 +
119 WINDOW_X - 18 + (col & 3)) = UI_TILE(0x7f);
120 }
121 }
122 for (panel = 0; panel < selectionUi->iconCount; panel++) {
123 count = selectionUi->iconCount;
124 for (entryIndex = 0; entryIndex <= 2; entryIndex++) {
125 s32 col;
126 for (col = 0; col <= 2; col++) {
127 s32 tmp;
128 /* FAKEMATCH: vram, offset and mask keep the row loop's index
129 * and tile pattern in the order the bytes show; as constants in
130 * place, 24 instructions differ in tbs-en. */
131 volatile u16 *vram =
132 (volatile u16 *)0x0600f800 + 21 * 32 + WINDOW_X;
133 s32 offset = 0x100;
134 s32 mask = 3;
135 /* FAKEMATCH: tmp, set twice, is no giv, so the tile is
136 * recomputed in the column loop as the bytes show; as no tmp,
137 * 267 instructions differ in tbs-en. */
138 vram[panel * 3 + entryIndex * 32 + (col & mask) - count * 3] =
139 tmp = panel * 16 + entryIndex * 4 + col + offset;
140 tmp = col & mask;
141 *(render->tilemap + (entryIndex + 17) * 32 + panel * 3 + tmp -
142 count * 3 + WINDOW_X) = 0;
143 }
144 }
145 }
146 } else {
147 s32 panel;
148 s32 count;
149 for (panel = 0; panel < 6 - selectionUi->iconCount; panel++) {
150 for (entryIndex = 0; entryIndex <= 2; entryIndex++) {
151 s32 col;
152 for (col = 0; col <= 2; col++)
153 *(render->tilemap + (entryIndex + 17) * 32 + panel * 3 + 2 +
154 (col & 3)) = UI_TILE(0x7f);
155 }
156 }
157 for (panel = 0; panel < selectionUi->iconCount; panel++) {
158 /* FAKEMATCH(one-pass): the exit test compares count instead of
159 * reloading work->count; as no block, 99 of 1037 instructions
160 * differ in tbs-en. */
161 do {
162 } while (0);
163 count = selectionUi->iconCount;
164 for (entryIndex = 0; entryIndex <= 2; entryIndex++) {
165 s32 col;
166 for (col = 0; col <= 2; col++) {
167 s32 tmp;
168 /* FAKEMATCH: as in mode 1: vram, offset and mask keep the tile
169 * pattern in the column loop through loop.c's first pass,
170 * volatile keeps the VRAM add apart from its store. */
171 volatile u16 *vram = (volatile u16 *)0x0600f800 + 21 * 32 + 20;
172 s32 offset = 0x100;
173 s32 mask = 3;
174 /* FAKEMATCH: needed to match: tmp, as in mode 1 (271 differ
175 * without it, 846 in both modes). */
176 vram[panel * 3 + entryIndex * 32 + (col & mask) - count * 3] =
177 tmp = panel * 16 + entryIndex * 4 + col + offset;
178 tmp = col & mask;
179 *(render->tilemap + (entryIndex + 17) * 32 + panel * 3 + tmp -
180 count * 3 + 20) = 0;
181 }
182 }
183 }
184 }
185 }
186 if (selectionUi->drawnIndex != selectionUi->selectedIndex) {
189 selectionUi->entries[selectionUi->selectedIndex].kind +
190 MsgCommandName,
191 selectionUi->window, 0, 0);
192 selectionUi->drawnIndex = selectionUi->selectedIndex;
194 selectionUi, selectionUi->selectedIndex,
195 selectionUi->commandKinds[selectionUi->selectedIndex]);
196 }
197 selectionUi->affineIndex =
198 AffineMatrix_BuildForEffect(&selectionUi->affine);
199 for (entryIndex = 0; entryIndex < selectionUi->iconCount; entryIndex++) {
200 struct SelectionEntry *entry = &selectionUi->entries[entryIndex];
201 if (entryIndex == selectionUi->selectedIndex) {
202 entry->sprite.oam.f.affineIndex = selectionUi->affineIndex;
203 entry->sprite.oam.f.affine = 3;
204 entry->sprite.oam.f.x = entry->posX + pulseScale * 7 / 512 - 14;
205 entry->sprite.oam.f.y = entry->posY + pulseScale * 3 / 256 - 20;
206 Runtime_PushSlotEntry(entry, 0xf1);
207 } else {
208 entry->sprite.oam.f.x = entry->posX;
209 entry->sprite.oam.f.y = entry->posY;
210 entry->sprite.oam.f.affineIndex = 0;
211 entry->sprite.oam.f.affine = 0;
212 }
213 }
214 // The tutorial drives the same command selection using synthetic keys.
215 keys = gKeysPressed;
216 repeat = gKeysRepeat;
217 navigation = gLinkCountdownWork;
218 if (navigation->tutorialStep != 0) {
219 keys = repeat = 0;
220 if (navigation->tutorialDelay == 0) {
221 if (navigation->commandActor == 1) {
222 if (selectionUi->commandKinds[selectionUi->selectedIndex] == 3)
223 keys = repeat = 1;
224 else
225 keys = repeat = 32;
226 navigation->tutorialDelay = 30;
227 } else if (navigation->commandActor == 0) {
228 s32 kind = selectionUi->commandKinds[selectionUi->selectedIndex];
229 if (kind == 16 || (tradeCount == 0 && kind == 15)) {
230 if (navigation->tutorialStep == 1) {
231 struct UiWindow *message;
232 if (kind == 15)
234 MsgDjinnTutorialUnleashCommand, 15, 8);
235 else if (kind == 16)
237 MsgDjinnTutorialSummon, 15, 8);
239 UiWork_Finalize(message, 1);
240 navigation->tutorialStep++;
241 navigation->tutorialDelay = 45;
242 } else {
243 keys = repeat = 1;
244 navigation->tutorialDelay = 200;
245 }
246 } else {
247 keys = repeat = 16;
248 navigation->tutorialDelay = 40;
249 }
250 } else {
251 navigation->tutorialDelay = 60;
252 keys = repeat = 1;
253 }
254 } else {
255 navigation->tutorialDelay--;
256 }
257 }
258 if ((keys & KEYS_SHOULDERS) && mode != 0) {
259 command = -2;
260 break;
261 }
262 if (keys & KEY_A) {
263 command = selectionUi->commandKinds[selectionUi->selectedIndex];
264 break;
265 }
266 if (mode != 0 && (keys & KEY_B)) {
268 command = -1;
269 break;
270 }
271 if (repeat & (KEY_DOWN | KEY_RIGHT)) {
273 selectionUi->selectedIndex =
274 (selectionUi->selectedIndex + 1) % selectionUi->iconCount;
275 } else if (repeat & (KEY_UP | KEY_LEFT)) {
277 selectionUi->selectedIndex =
278 (selectionUi->selectedIndex + selectionUi->iconCount - 1) %
279 selectionUi->iconCount;
280 } else if (gLinkCountdownWork->timer == 0) {
281 command = selectionUi->commandKinds[0];
282 break;
283 }
287 render->menuBusy = 0;
288 WaitFrames(1);
289 }
290 if (mode != 0)
292 else
294 for (entryIndex = 0; entryIndex < selectionUi->iconCount; entryIndex++)
295 Resource_ResetEntry(selectionUi->entries[entryIndex].resource);
296 render->menuBusy = 1;
297 UiWork_Finalize(selectionUi->window, 1);
298 {
299 s32 panel;
300 for (panel = 0; panel <= 6; panel++) {
301 for (entryIndex = 0; entryIndex <= 2; entryIndex++) {
302 s32 col;
303 /* FAKEMATCH(volatile): the add of 0x44a stays apart from the store it
304 * addresses; as a plain store, 2 of 1037 instructions differ in
305 * tbs-en. */
306 for (col = 0; col <= 2; col++)
307 *(volatile u16 *)(render->tilemap + (entryIndex + 17) * 32 +
308 panel * 3 + 5 + (col & 3)) = UI_TILE(0x7f);
309 }
310 }
311 }
312 // Restore the normal BG1 handler after clearing the command strip.
313 render->dirty = 1;
314 WaitFrames(1);
316 Runtime_SetIrqHandler(2, 0, 0);
320 0x20000);
321 MemFree(selectionUi);
322 render->menuBusy = 0;
323 WaitFrames(1);
324 return command;
325}
326
327/// Sets bit 12 of each tile in a screen-space rectangle, preserving the other
328/// tile attributes. Keep the original bottom-edge test (29) and height (20).
330 struct UiRenderWork *render = UI_WORK;
331
332 paletteBit &= 1;
333 paletteBit <<= 12;
334
335 if (x < 0) {
336 width += x;
337 x = 0;
338 }
339 if (x + width > 29) {
340 width = 30 - x;
341 }
342 if (y < 0) {
343 height += y;
344 y = 0;
345 }
346 if (y + height > 29) {
347 height = 20 - y;
348 }
349
350 if (width > 0 && height > 0) {
351 do {
352 u16 *cell = &((u16 (*)[32])render->tilemap)[y][x];
353 s32 remaining = width;
354
355 if (remaining != 0) {
356 do {
357 u32 tile = *cell;
358 tile = (tile & ~0x1000) | paletteBit;
359 remaining--;
360 *cell = tile;
361 cell++;
362 } while (remaining != 0);
363 }
364
365 UiRender_MarkRow(render, y);
366 height--;
367 y++;
368 } while (height != 0);
369 }
370}
371
372/// Dims the party strip, then highlight the actor IDs up to the 0xff
373/// terminator.
374/// Missing IDs are ignored; the search stops at the party's own terminator.
376 struct BattleWork *battle = gBattleWork;
377 s32 count;
378 s32 i;
379 s32 j;
380
381 count = BattleParty_ListActorIdsFar(1, 0);
382 Ui_SetRectHighlight(29 - count * 6, 0, 25, 5, 15);
383 i = 0;
384 if (ids[0] != 0xff) {
385 next_id:
386 for (j = 0; j < 4 && battle->partyUnits[j] != ids[i]; j++) {
387 if (battle->partyUnits[j] == 0xff) {
388 j = 4;
389 break;
390 }
391 }
392 if (j != 4)
393 Ui_SetRectHighlight(29 - (count - j) * 6, 0, 7, 5, 14);
394 if (++i < 4 && ids[i] != 0xff)
395 goto next_id;
396 }
397 return 0;
398}
What every part of the menu object shares: its includes, edition values, macros and the link round st...
struct BattleWork * gBattleWork
s32 Menu_RunCommandRow(s32 mode)
Selects a command icon, returning its kind, -1 for cancel or -2 for a shoulder-button switch.
Definition command_row.c:28
struct UiWindow * UiText_ShowMessageAndWaitComplete(s32 message, s32 x, s32 y)
Opens a message at (x, y), waits for its text to finish, and returns its window so the caller can hol...
Definition command_row.c:9
s32 BattleLayout_HighlightPartyPanels(u16 *ids)
Dims the party strip, then highlight the actor IDs up to the 0xff terminator.
#define WINDOW_X
Definition command_row.c:19
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.
s32 BattleParty_ListActorIdsFar(s32 groups, u16 *dst)
s32 BattleParty_CountStandbyDjinnFar(u32 unitId, u8 *counts)
s32 BattlePresentation_WaitForPromptAtFar(s32 x, s32 y)
void * Djinn_GetRecoveryTableFar(s32 arg0)
void AudioCommand_PlayFar(s32 id)
void Runtime_SetIrqHandler(u32 irq, s32 vcount, InterruptHandler handler)
Installs handler for interrupt irq and enables that interrupt, or with a null handler disables it and...
Definition frame.c:37
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.
struct UiWindow * UiText_OpenMessageWindow(s32 message, s32 x, s32 y, u32 packed)
Opens a window sized to a message near tile (x, y) and starts typing the message into it.
Definition frames.c:396
s32 UiWork_IsComplete(void)
Returns 1 when every message channel has finished its text (or is idle), and 0 while one is still typ...
Definition frames.c:210
void * Runtime_BumpAllocateAlternatePool(s32 size)
As MemAlloc, but tries EWRAM first.
Definition heap.c:140
void IoWriteQueue_Store16(u32 address, u32 value)
Queues a halfword store.
Definition io_queue.c:21
@ DISPCNT_OBJ_ON
Definition io_reg.h:44
@ DISPCNT_BG0_ON
Definition io_reg.h:40
@ DISPCNT_OBJ_1D_MAP
Definition io_reg.h:39
@ DISPCNT_MODE_1
BG0 and BG1 text, BG2 affine.
Definition io_reg.h:37
@ DISPCNT_BG2_ON
Definition io_reg.h:42
@ DISPCNT_BG1_ON
Definition io_reg.h:41
@ 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
@ KEYS_SHOULDERS
Definition io_reg.h:256
#define REG_DISPCNT
Definition io_reg.h:9
#define IO_WRITE_QUEUE_PUSH(address, value, control)
Disables interrupts to add one register write or DMA to the queue; a write to a full queue is dropped...
volatile u32 gKeysPressed
Keys that went down this frame.
volatile u32 gKeysRepeat
Pressed keys, repeating while held: after 19 frames, then every 6.
struct BgScroll gBgScroll[]
void MemFree(void *buffer)
struct BattleMenuWork * gLinkCountdownWork
void UiText_DrawCharacter(struct SelectionWork *work, s32 index, u32 icon)
Loads a selection icon, initializes its sprite and binds the decoded tiles.
Definition pictures.c:454
void Graphics_SetBg1Priority3(void)
Puts BG1 behind the other priority levels while the command strip is active.
Definition pictures.c:465
void Graphics_SetBg1Priority0(void)
Restores BG1 priority 0; the VCount handler applies this below the strip.
Definition pictures.c:474
s32 AffineMatrix_BuildForEffect(struct AffineTransform *source)
Hands out the next OAM affine matrix for a sprite drawn with source's scale and rotation and fills it...
Definition render.c:27
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
const u16 gUi_BounceScales[32]
A sprite's pulse, as a scale where 256 is its normal size: it swells to 1.5 times and back over 32 st...
Definition scales.c:10
s32 Scheduler_AddOrUpdateCallback(SchedulerCallback callback, s32 order)
Schedules callback with order, or gives a task already running it the new order, and re-sorts the tab...
Definition scheduler.c:102
s32 Scheduler_RemoveCallback(SchedulerCallback callback)
Unschedules the task running callback: clears its routine and gives it order 0x7fff,...
Definition scheduler.c:146
#define SE_MENU_CANCEL
Definition songs.h:106
#define SE_MENU_CURSOR_MOVE
Definition songs.h:104
u16 angle
1/65536 turns
Definition affine.h:16
u16 scaleY
8.8 fixed point, read signed
Definition affine.h:15
u16 scaleX
8.8 fixed point, read signed: negative mirrors the sprite
Definition affine.h:14
The battle command menus' work, heap slot 57 (0x104 bytes), reached as gLinkCountdownWork.
Definition menu_list.h:107
s32 tutorialDelay
frames until the tutorial's next key press
Definition menu_list.h:142
s32 commandActor
The member whose commands are being chosen; -1 between members.
Definition menu_list.h:144
s32 timer
Frames left to choose commands in a link battle; -1 outside link battles.
Definition menu_list.h:131
s32 commandSelection[2]
The command row's choice: [0] for the party's row (fight, flee, status), [1] for a member's commands.
Definition menu_list.h:122
s32 tutorialStep
The Djinn tutorial's step: 0 off, 1 from the start of each round while FLAG_DJINN_TUTORIAL is set,...
Definition menu_list.h:141
The battle's own work: its enemies, units and their objects, the turn's actions, the spoils,...
Definition battle_work.h:71
s16 partyUnits[7]
ends with BATTLE_UNIT_LIST_END
u16 y
pixels
Definition map_scroll.h:65
s32 count
Definition glyph.h:21
u8 slot[256]
Definition glyph.h:20
union MenuSprite::@002225022013150231017316170057321303227123371224 oam
The command icon row's work block and one of its icons: pictures.c loads the icons,...
struct MenuSprite sprite
The command icon row's work block: the icons' shared palette, up to six icons, the label window,...
struct GlyphPalette palette
struct SelectionEntry entries[6]
struct UiWindow * window
struct AffineTransform affine
The window system's work: the windows' tilemap, the windows, the three text channels,...
Definition window.h:19
u16 tilemap[640]
the windows' BG tilemap, 32 by 20 tiles
Definition window.h:20
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 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 height
tiles
Definition uiwindow.h:14
u16 width
tiles
Definition uiwindow.h:13
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
unsigned char u8
Definition types.h:11
#define UiRender_MarkRow(render, y)
Requests transfer of the four-row tilemap band containing window row y.
Definition uiwindow.h:73
#define UI_WORK
Definition window.h:267
#define UI_TILE(tile)
A tilemap entry of palette 15, the UI palette.
Definition window.h:54
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 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 RenderOutput_PrepareForRedraw(struct UiWindow *window)
Clears a window's contents: redraws its empty frame and releases the render outputs it carries.
Definition windows.c:392
void UiWork_Finalize(struct UiWindow *window, s32 instant)
Closes a window: clears its contents and remembers its last rectangle.
Definition windows.c:349
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