Alchemy
Loading...
Searching...
No Matches

psynergy.c

Go to the documentation of this file.
1/// @file
2/// The Psynergy menu: the screen events open, the member and Psynergy lists,
3/// targets, and the L and R shortcuts.
4/// Part of menu.c, the menu object, compiled only through it.
5
6#include "../menu_internal.h"
7
8// The German, Spanish, French and Italian Psynergy menus save the window
9// tiles they draw over and restore them after.
10#if TBS_PATCH_2
11#define PSYNERGY_PROMPT_TILES BG_CHAR_BLOCK(1)
12#define PSYNERGY_PROMPT_TILES_SIZE 0x2000
13#endif
14
15// The highlight over the Psynergy list's rows.
16#if TBS_PATCH_1
17#define PSYNERGY_DETAIL_ROW_X 0
18#define PSYNERGY_DETAIL_ROW_WIDTH 15
19#else
20#define PSYNERGY_DETAIL_ROW_X 1
21#define PSYNERGY_DETAIL_ROW_WIDTH 14
22#endif
23
24// The Psynergy list's page icons, "PP" label, names and hand cursor.
25#if TBS_PATCH_1
26#define PSYNERGY_PAGE_ICONS_X 112
27#define PSYNERGY_PP_LABEL_X 96
28#define PSYNERGY_NAME_X 16
29#define PSYNERGY_LIST_CURSOR_X 88
30#else
31#define PSYNERGY_PAGE_ICONS_X 120
32#define PSYNERGY_PP_LABEL_X 72
33#define PSYNERGY_NAME_X 32
34#define PSYNERGY_LIST_CURSOR_X 98
35#endif
36
37/// The Psynergy menu an event opens (window command 1): the field menu's
38/// Psynergy screen over the field, which stops meanwhile. When the player picks
39/// Psynergy to use on the field, it is recorded in the event work's
40/// psynergyRequest (owner << 10 | Psynergy) and 1 is returned; -1 when the
41/// player backs out.
43#if TBS_PATCH_2
44 void *saved = Runtime_BumpAllocateAlternatePool(PSYNERGY_PROMPT_TILES_SIZE);
45#endif
46 struct PsynergyMenuState *state =
48 s32 owner;
49 s32 unused;
50 s32 psynergy;
51 s32 result;
52
54 UiWindow_DrawFrameFar(0, 0, 30, 20);
55 WaitFrames(1);
58 ItemMenu_Initialize(0, 3, 0, 7);
59 state->messageWindow = UiWindow_CreateFar(13, 0, 17, 3, 2);
62#if TBS_PATCH_2
64 Iwram_CopyWords(saved, PSYNERGY_PROMPT_TILES, PSYNERGY_PROMPT_TILES_SIZE);
65 Iwram_FillWords(PSYNERGY_PROMPT_TILES, PSYNERGY_PROMPT_TILES_SIZE,
66 0x33333333);
68#endif
69 // Let the player choose.
71 result = Menu_ResolveSelectedAction(&owner, &unused, &psynergy);
73 if (result == 1) {
74 struct EventWork *target = WORK_SLOT(HEAP_SLOT_EVENT);
75 u16 request;
77 request = psynergy | (owner << 10);
78 target->psynergyRequest = request;
79 }
80 // Close the menu and give the screen back to the field.
84 UiWindow_DrawFrameFar(0, 0, 30, 20);
87#if TBS_PATCH_2
90 Iwram_CopyWords(PSYNERGY_PROMPT_TILES, saved, PSYNERGY_PROMPT_TILES_SIZE);
92 MemFree(saved);
93 WaitFrames(1);
95#endif
96 WaitFrames(1);
97 UiWindow_EraseBorderRectFar(0, 0, 30, 20);
100 return result;
101}
102
103/// The steps of the Psynergy menu (Menu_ResolveSelectedAction).
110};
111
112/// Runs the Psynergy menu: choose a party member and one of their Psynergy,
113/// then use it on a member (or the whole party), or, in the shortcut modes, set
114/// it as the L or R shortcut. Returns 1 with the owner and Psynergy in the out
115/// parameters when the chosen Psynergy works on the field, to be used once the
116/// menu closes; -1 when the player backs out or presses Start; otherwise the
117/// result of the last use.
118s32 Menu_ResolveSelectedAction(s32 *outOwner, s32 *unused, s32 *outAction) {
119 struct PsynergyMenuState *menu;
121 s32 step;
122 s32 done;
123 s32 chosenAction;
124 s32 targetMode;
125 s32 actionEntry;
126 s32 chosenTarget;
127 struct BattleAct *action;
128
129 step = PSYNERGY_STEP_OWNER;
130 done = 0;
131 menu = gMenuWork;
132 useResult = 0;
133
134 while (done == 0 && GameFlag_TestFar(FLAG_MENU_START_PRESSED) == 0) {
135 switch (step) {
136 // Choose whose Psynergy to look at.
137 case PSYNERGY_STEP_OWNER: {
138 s32 cancelled;
139 s32 chosen;
140
141 menu->paneRow[0] = 0;
142 ItemMenu_DrawMessage(0, MsgPsynergyChooseOwner);
144 cancelled = -1;
145 /* FAKEMATCH(dead): a redundant copy of -1 and an XOR test give -1 and 1
146 * the ROM's registers; as if (chosen == -1) setting done and useResult,
147 * 6 of 317 instructions differ in tbs-en. */
148 if (chosen == -1)
149 cancelled = chosen;
150 if (((u32)chosen ^ (u32)cancelled) == 0) {
151 done = 1;
152 useResult = cancelled;
153 }
155 step = PSYNERGY_STEP_LIST;
156 break;
157 }
158
159 // Choose one of their Psynergy; in the shortcut modes, set it as the L or
160 // R shortcut and start again.
162 WaitFrames(1);
163 UnitGetFar(menu->ownerIds[0]);
164 step = PSYNERGY_STEP_OWNER;
165 if (menu->psynergyCount != 0) {
166 {
167 struct PsynergyMenuState *savedWork = menu;
168
169 /* FAKEMATCH(dead): menu cleared and restored under a false test, so
170 * the mode's offset is built from its own constant; without the two
171 * tests, 2 of 317 instructions differ in tbs-en. */
172 if (done)
173 menu = NULL;
174 if (done)
175 menu = savedWork;
176 }
177 switch (menu->mode) {
178 case 0: // use
179 ItemMenu_DrawMessage(0, MsgPsynergyChooseAbility);
180 break;
181 case 1: // set the L shortcut
182 ItemMenu_DrawMessage(0, MsgPsynergyChooseForL);
183 break;
184 case 2: // set the R shortcut
185 ItemMenu_DrawMessage(0, MsgPsynergyChooseForR);
186 break;
187 }
191 chosenAction = PsynergyMenu_RunList(0);
192 step = PSYNERGY_STEP_OWNER;
193 if (chosenAction != -1) {
195 if (menu->mode != 0) {
196 if (menu->mode == 1) {
197 PsynergyMenu_SetShortcut(menu->ownerIds[0], chosenAction, 0);
199 InventoryMenu_ShowModalMessage(MsgShortcutSetL, -1, -1);
200#if !TBS_PATCH_1
202#endif
203 } else {
204 PsynergyMenu_SetShortcut(menu->ownerIds[0], chosenAction, 1);
206 InventoryMenu_ShowModalMessage(MsgShortcutSetR, -1, -1);
207#if !TBS_PATCH_1
209#endif
210 }
211 step = PSYNERGY_STEP_OWNER;
212 }
213 }
214 }
215 break;
216
217 // Choose the member to use it on.
219 ItemMenu_DrawMessage(0, MsgPsynergyChooseTarget);
220 chosenTarget = PsynergyMenu_SelectTarget(0);
221 step = PSYNERGY_STEP_APPLY;
222 if (chosenTarget == -1) {
223 menu->flags |= 1;
224 step = PSYNERGY_STEP_LIST;
225 }
226 break;
227
228 // How is it used? On one member, on the whole party, or on the field
229 // once the menu closes.
232 if (targetMode == 1) {
234 break;
235 }
236 if (targetMode == 2) {
238 step = PSYNERGY_STEP_APPLY;
239 break;
240 }
241 done = 1;
242 useResult = 1;
243 *outOwner = menu->ownerIds[0];
244 *outAction = menu->paneAction[0] & OWNER_ACTION_ID_MASK;
245 break;
246
247 // Use it: pay its PP, show the result and go back to the list, or to the
248 // target when it failed on one member.
250 chosenTarget = 0;
251 actionEntry = menu->paneAction[0];
252 useResult = BattleEffect_ApplyToTargets(actionEntry, menu->ownerIds[0],
253 menu->ownerIds[1], 0);
254 if (menu->ownerIds[1] == MENU_TARGET_WHOLE_PARTY) {
255 menu->ownerIds[1] = menu->ownerIds[0];
256 chosenTarget = MENU_TARGET_WHOLE_PARTY;
257 }
258 if (useResult != -1) {
259 action = BattleActGet(menu->paneAction[0] & OWNER_ACTION_ID_MASK);
260 Unit_AddPpFar(menu->ownerIds[0], -action->ppCost);
261 }
262 UnitCalcFar(menu->ownerIds[0]);
263 if (useResult != -1) {
268 InventoryMenu_ShowModalMessage(menu->useResult + MsgItemUseResult, 0,
269 -1);
270 } else {
273 InventoryMenu_ShowModalMessage(menu->useResult + MsgItemUseResult,
275 }
276 if (useResult != -1) {
277 useResult = 1;
278 menu->flags |= 1;
279 step = PSYNERGY_STEP_LIST;
280 } else {
281 menu->skipSlide = 1;
282 if (chosenTarget == MENU_TARGET_WHOLE_PARTY) {
283 menu->flags |= 1;
284 step = PSYNERGY_STEP_LIST;
285 } else {
287 }
288 }
289 break;
290
291 default:
292 done = 1;
293 break;
294 }
295 }
296
298 useResult = -1;
299 }
300 return useResult;
301}
302
303/// Says how the selected Psynergy is used from the menu: 0 on the field once
304/// the menu closes (its effect has a field event), 2 on the whole party (range
305/// 0xff), 1 on one chosen member when its target mode is 2, and 0 otherwise.
307 struct BattleAct *action;
308 s32 targetModeDifference;
309 s32 classification;
310
312 ((struct PsynergyMenuState *)gMenuWork)->paneAction[0]);
313 if (BattleFx_HasMatchingEvent5Far(action->type0c) != 0) {
314 return 0;
315 }
316 classification = 2;
317 if (action->range != 0xff) {
318 u8 kind = action->targetMode;
319 // 1 when kind is 2, else 0.
320 targetModeDifference = kind ^ 2;
321 classification = (0 - targetModeDifference) | targetModeDifference;
322 classification = (u32)classification >> 0x1f;
323 classification = 1 - classification;
324 }
325 return classification;
326}
327
328/// Lets the player choose a party member in pane partySlot (0 or 1), starting
329/// from the one chosen last, with each member's Psynergy shown as the cursor
330/// passes. Returns the chosen member's id, or -1 when the player backs out.
332 /* FAKEMATCH(temporary): byte offsets held in scalars keep partySlot in its
333 * own register; as menu->paneIcon[partySlot] and the other indexed fields,
334 * 19 of 75 instructions differ in tbs-en. */
335 struct PsynergyMenuState *menu = gMenuWork;
336 s32 tabOffset = partySlot + ((u8 *)menu->tabIndex - (u8 *)menu);
337 s32 iconOffset = partySlot * sizeof(menu->paneIcon[0]) +
338 ((u8 *)menu->paneIcon - (u8 *)menu);
339 struct RenderOutput *icon;
340 u8 ownerCount;
341 s32 ownerIndex;
342 s32 ownerOffset;
343 s32 tableOffset;
344 s32 ownerId;
345 struct BattleUnit *unit;
346 u16 *actions;
347 u8 *counts;
348 s32 actionCount;
349 s32 result;
350 s32 iconOffset2;
351
352 result = 0;
353 icon = *(struct RenderOutput **)((u8 *)menu + iconOffset);
354 icon->active = ICON_SHOWN;
355 icon->animStep = result;
357 counts = (u8 *)menu + ((u8 *)menu->tabCounts - (u8 *)menu->tabIndex);
358 ownerIndex = *(s8 *)((u8 *)menu + tabOffset);
359 ownerCount = menu->ownerCount;
360 counts[tabOffset] = ownerCount;
361
362 if (ownerIndex == -1) {
363 *((u8 *)menu + tabOffset) = 0;
364 ownerOffset = 0;
365 } else {
366 ownerOffset = ownerIndex * sizeof(menu->ownerTable[0]);
367 UiMenu_SlideCursor(ownerIndex * 24 - 10, 16);
368 }
369
370 tableOffset = ownerOffset + ((u8 *)menu->ownerTable - (u8 *)menu);
371 ownerId = *(u16 *)((u8 *)menu + tableOffset);
372 unit = UnitGetFar(ownerId);
373 actions = menu->psynergies;
374 actionCount = PsynergyMenu_CollectActions(unit, actions, 2);
375 menu->psynergyCount = actionCount;
376 result = PsynergyMenu_SelectMember(menu->ownerTable, actions);
377
378 iconOffset2 = partySlot * sizeof(menu->paneIcon[0]) +
379 ((u8 *)menu->paneIcon - (u8 *)menu);
380 icon = *(struct RenderOutput **)((u8 *)menu + iconOffset2);
382 WaitFrames(1);
383 return result;
384}
385
386/// The party member row of the Psynergy menu. Left and Right move between
387/// members, showing each one's Psynergy, status and shortcuts; A chooses a
388/// member who has Psynergy to use, L or R one who has field Psynergy to set as
389/// that shortcut (menu mode 1 or 2), and B backs out. Returns the chosen
390/// member's id, or -1.
392 struct PsynergyMenuState *menu;
393 s32 selection;
395 s32 redraw;
396 s32 result;
397 struct BattleUnit *unit;
398 struct UiWindow *window;
399 s32 shown;
400 s32 i;
401 u16 *actions;
402 s32 shortcutCount;
403 s8 fieldCount;
404
405 menu = gMenuWork;
406 selection = menu->tabIndex[0];
407 ownerCount = menu->tabCounts[0];
408 redraw = 1;
409 result = 0;
410 shown = 0;
411 menu->mode = result;
412 unit = UnitGetFar(ownerIds[selection]);
413 if (UiWindow_UpdateOrCreate(&menu->psynergyWindow, 13, 3, 17, 10, 2))
415 menu->psynergyWindow);
416 if (UiWindow_UpdateOrCreate(&menu->shortcutWindow, 13, 13, 17, 4, 2)) {
418 2, 0, menu->shortcutWindow, 0, result);
420 }
422 if (redraw) {
423 redraw = 0;
424 selection = (ownerCount + selection) % ownerCount;
425 window = menu->statusWindow;
426 unit = UnitGetFar(ownerIds[selection]);
427 PsynergyMenu_RefreshOwnerPsynergy(ownerIds[selection]);
428 Menu_DrawOwnerStatusPanel(window, ownerIds[selection], 0,
430 PsynergyMenu_DrawShortcuts(menu->shortcutWindow, ownerIds[selection]);
431 PsynergyMenu_CallIconRoutineWithValue(menu, ownerIds[selection]);
432 for (i = 3; i >= 0; i--)
433 menu->rowPositions[i] = 30;
434 // Raise the chosen member.
435 menu->rowPositions[selection] = 26;
436 if (!GameFlag_TestFar(FLAG_MENU_INFO_KEPT) && !shown) {
438#if TBS_PATCH_1
440#endif
442 shown = 1;
443 } else {
445 }
446 }
447 UiMenu_PositionCursor(selection * 24 - 10, 16);
448 WaitFrames(1);
449 if (gKeysPressed & KEY_A) {
450 if (menu->psynergyCount) {
452 result = ownerIds[selection];
453 break;
454 }
456 }
457 // L or R: set that shortcut, if the member has field Psynergy for it.
458 if ((gKeysPressed & KEY_L) || (gKeysPressed & KEY_R)) {
459 result = ownerIds[selection];
460 if (gKeysPressed & KEY_L)
461 menu->mode = 1;
462 else
463 menu->mode = 2;
464 actions = MemAlloc(32 * sizeof(u16));
465 fieldCount =
466 PsynergyMenu_CollectActions((struct BattleUnit *)unit, actions, 1);
467 MemFree(actions);
468 shortcutCount = fieldCount;
469 if (shortcutCount == 0) {
470 menu->mode = shortcutCount;
472 } else {
474 break;
475 }
476 }
477 if (gKeysPressed & KEY_B) {
479 result = -1;
480 break;
481 }
482 if (gKeysRepeat & KEY_LEFT) {
484 selection--;
485 redraw = 1;
486 }
487 if (gKeysRepeat & KEY_RIGHT) {
489 selection++;
490 redraw = 1;
491 }
492 }
493 menu->tabIndex[0] = selection;
494 menu->selectedOwner = ownerIds[selection];
495 menu->ownerIds[0] = ownerIds[selection];
496 return result;
497}
498
499/// Shows member ownerId's Psynergy icons in the Psynergy window, eight to a
500/// row, or "no Psynergy" when they have none.
502 u16 *psynergies;
503 struct PsynergyMenuState *menu;
504 struct BattleUnit *owner;
505
506 menu = gMenuWork;
507 owner = UnitGetFar(ownerId);
508 psynergies = menu->psynergies;
509 menu->psynergyCount = PsynergyMenu_CollectActions(owner, psynergies, 2);
513 if (menu->psynergyCount == 0) {
514 UiText_DrawCharacterAtOffsetFar(MsgPsynergyMenuEmpty, menu->psynergyWindow,
515 0, 24);
516 }
517}
518
519/// Nothing calls them.
521
523
524/// Chooses the party member to use the selected Psynergy on. In mode 0 each
525/// member's status shows as the cursor passes, with the Psynergy's description
526/// once. Returns the chosen member's id, or -1 when the player backs out.
528
529 struct PsynergyMenuState *menu;
530 s32 selection;
531 s32 count;
532 s32 redraw;
533 s32 result;
534 s32 shown;
535 struct RenderOutput *marker;
536
537 menu = gMenuWork;
538 selection = menu->tabIndex[1];
539 count = menu->ownerCount;
540 redraw = 1;
541 result = 0;
542 shown = 0;
543 UnitGetFar(menu->ownerTable[menu->tabIndex[0]]);
544 UiMenu_SlideCursor(selection * 24 - 10, 16);
546 if (redraw) {
547 redraw = 0;
548 selection = (selection + count) % count;
549 UnitGetFar(menu->ownerTable[selection]);
550 marker = menu->paneIcon[1];
551 marker->oam.x = marker->x =
552 (((menu->auxiliaryWindow)->x + selection * 3) << 3) - 2;
553 if (targetMode == 0) {
555 menu->ownerTable[selection], 0,
558 menu->ownerTable[selection]);
559 if (!GameFlag_TestFar(FLAG_MENU_INFO_KEPT) && !shown) {
560 MENU_RESET_INFO_WINDOW((void *)menu->infoWindow);
562 MsgAbilityDescription,
563 menu->infoWindow, 0, 0);
564 shown = 1;
565 } else {
567 }
568 }
569 }
570 UiMenu_PositionCursor(selection * 24 - 10, 16);
571 WaitFrames(1);
572 if (gKeysPressed & KEY_A) {
574 result = menu->ownerTable[selection];
575 break;
576 }
577 if (gKeysPressed & KEY_B) {
579 result = -1;
580 break;
581 }
582 if (gKeysRepeat & KEY_LEFT) {
584 selection--;
585 redraw = 1;
586 }
587 if (gKeysRepeat & KEY_RIGHT) {
589 selection++;
590 redraw = 1;
591 }
592 }
593 marker = menu->paneIcon[1];
594 menu->tabIndex[1] = selection;
595 UiIcon_PrepareObject(marker);
596 marker->active = ICON_HIDDEN;
597 WaitFrames(1);
598 menu->tabIndex[1] = selection;
599 menu->selectedOwner = menu->ownerTable[selection];
600 menu->ownerIds[1] = menu->ownerTable[selection];
601 return result;
602}
603
604/// A Psynergy shortcut: its owner above bit 10, the Psynergy's id below.
605#define PSYNERGY_SHORTCUT_OWNER_SHIFT 10
606#define PSYNERGY_SHORTCUT_ID_MASK 0x3ff
607
608/// Sets the L (shortcutIndex 0) or R (shortcutIndex 1) Psynergy shortcut:
609/// ownerId << 10 | the Psynergy's id. Returns 1.
610s32 PsynergyMenu_SetShortcut(s32 ownerId, s32 actionId, s32 shortcutIndex) {
611 s32 id = actionId & OWNER_ACTION_ID_MASK;
612 s32 code = (ownerId << PSYNERGY_SHORTCUT_OWNER_SHIFT) | id;
613
614 if (shortcutIndex == 0) {
616 } else {
618 }
619 return 1;
620}
621
622// Writes the L and R Psynergy shortcuts into window: each one's Psynergy and
623// owner, or that it is empty, under a heading that says how to change them.
624// A name too wide for the line hides the owner (international) or drops the
625// colon after "L" and "R" (Japanese). Returns 1.
626#if LANGUAGE != LANGUAGE_JAPANESE
627
628s32 PsynergyMenu_DrawShortcuts(struct UiWindow *window, s32 ownerId) {
629 s32 left;
630 s32 top;
631 s32 width;
632 s32 height;
633 s32 wide;
634
636 UiText_DrawCharacterAtOffsetFar(MsgShortcutChangeHelp, window, 0, -8);
637 else
638 UiText_DrawCharacterAtOffsetFar(MsgShortcutLabel, window, 0, -8);
639
642 &left, &top, &width, &height);
643 if (width < 0 || width > 10)
644 wide = 1;
645 else
646 wide = 0;
647 if (gGameState.firstShortcut != 0) {
650 UiText_DrawCharacterAtOffsetFar(MsgShortcutNameL, window, 0, 0);
651 if (wide == 0)
654 ->name,
655 window, 80, 0);
656 } else {
657 UiText_DrawCharacterAtOffsetFar(MsgShortcutEmptyL, window, 0, 0);
658 }
659
662 &left, &top, &width, &height);
663 if (width < 0 || width > 10)
664 wide = 1;
665 else
666 wide = 0;
667 if (gGameState.secondShortcut != 0) {
670 UiText_DrawCharacterAtOffsetFar(MsgShortcutNameR, window, 0, 8);
671 if (wide == 0)
674 ->name,
675 window, 80, 8);
677 } else {
678 UiText_DrawCharacterAtOffsetFar(MsgShortcutEmptyR, window, 0, 8);
679 }
680 return 1;
681}
682#else
683
684s32 PsynergyMenu_DrawShortcuts(struct UiWindow *window, s32 owner) {
685 s32 left;
686 s32 top;
687 s32 width;
688 s32 height;
689 u16 wide;
690
692 UiText_DrawCharacterAtOffsetFar(MsgShortcutChangeHelp, window, 0, -8);
693 else
694 UiText_DrawCharacterAtOffsetFar(MsgShortcutLabel, window, 0, -8);
695
698 &left, &top, &width, &height);
699 if (width < 0 || width > 11)
700 wide = 1;
701 else
702 wide = 0;
703 if (wide)
705 else
707 0);
708 if (gGameState.firstShortcut != 0) {
709 if (wide)
712 MsgAbilityName,
713 window, 8, 0);
714 else
717 MsgAbilityName,
718 window, 16, 0);
721 ->name,
722 window, 80, 0);
723 } else {
724 UiText_DrawCharacterAtOffsetFar(MsgShortcutEmptyL, window, 24, 0);
725 }
726
729 &left, &top, &width, &height);
730 if (width < 0 || width > 11)
731 wide = 1;
732 else
733 wide = 0;
734 if (wide)
736 else
738 8);
739 if (gGameState.secondShortcut != 0) {
740 if (wide)
743 MsgAbilityName,
744 window, 8, 8);
745 else
748 MsgAbilityName,
749 window, 16, 8);
752 ->name,
753 window, 80, 8);
755 } else {
756 UiText_DrawCharacterAtOffsetFar(MsgShortcutEmptyR, window, 24, 8);
757 }
758 return 1;
759}
760#endif
761
762/// Sets up a Psynergy grid screen: the cursor window with the party's figures,
763/// a 30 by 15 window below with a hidden grid cursor and a portrait, and 16
764/// Psynergy icon sprites in two rows of eight from (96, 8), on an 8 by 2 grid.
766 struct UiWindow *window;
767 struct PsynergyMenuState *menu;
768 struct RenderOutput *cursor;
769 s32 index;
770 s32 x;
771 s32 y;
772 struct RenderOutput **output;
773
774 menu = gMenuWork;
775 window = UiMenu_CreateCursor(menu);
776 PsynergyMenu_InitializeEntryObjects((void *)window, 2, 2, 8, 0);
777
778 window = UiWindow_CreateFar(0, 5, 30, 15, 2);
779 menu->psynergyWindow = window;
780 menu->selectedColumn = 0;
781 menu->selectedRow = 0;
782 menu->columnCount = 8;
783 menu->rowCount = 2;
784
785 cursor =
786 (struct RenderOutput *)UiIcon_CreateWithResourceVariant(window, 0, 4);
787 cursor->active = ICON_HIDDEN;
788 menu->entryGridCursor = cursor;
789 SideObject_CreateFar(0, 0, 0, window, 0, 0);
790
791 y = 8;
792 index = 0;
793 output = &menu->entryIcons[0];
794 x = 96;
795 do {
796 *output++ = RenderOutput_CreateFromResourceFar(4, index, window, x, y);
797 index++;
798 x += 16;
799 } while (index <= 7);
800
801 index = 8;
802 y = 24;
803 output = &menu->entryIcons[8];
804 x = 96;
805 do {
806 *output++ = RenderOutput_CreateFromResourceFar(4, index, window, x, y);
807 index++;
808 x += 16;
809 } while (index <= 15);
810}
811
812/// Releases the party figures and closes the Psynergy grid screen's windows.
814 struct PsynergyMenuState *menu;
815
816 menu = gMenuWork;
818 UiWork_FinalizeFar((void *)menu->auxiliaryWindow, 1);
819 UiWork_FinalizeFar((void *)menu->psynergyWindow, 1);
820 UiWork_FinalizeFar((void *)menu->messageWindow, 1);
821}
822
823/// Loads each listed Psynergy's icon into its icon sprite (32 entries) and
824/// hides the icons of empty entries.
826 s32 remaining;
827 struct RenderOutput **icons;
828 u16 *p;
829 s32 psynergyId;
830
831 icons = ((struct PsynergyMenuState *)gMenuWork)->entryIcons;
832 p = psynergies;
833 remaining = 31;
834 do {
835 psynergyId = *p++;
836 if (psynergyId != 0) {
837 Resource_LoadByModeIntoSlotFar(4, psynergyId, (u8)(*icons)->index, 0);
838 }
839 icons++;
840 remaining--;
841 } while (remaining >= 0);
843}
844
845/// Lists unit's Psynergy into actions (32 entries, cleared first) and returns
846/// how many there are. mode 1 lists only the Psynergy that work on the field
847/// (those that can be shortcuts); mode 2 those with a field effect or usable
848/// in the field; any other mode those first, then the rest.
850 s32 mode) {
851 /* FAKEMATCH(dead): each entry cleared twice through the byte-offset
852 * pointer, which makes loop.c replace the counter with the pointer as the
853 * ROM does; with a single store, 15 of 129 instructions differ in tbs-en. */
854 s32 clearOffset;
855 s32 passCount;
856 s32 actionCount;
857 s32 slotIndex;
858 s32 passIndex;
859
860 passCount = (mode != 2) ? 4 : 3;
861 for (clearOffset = 62; clearOffset >= 0; clearOffset -= 2) {
862 u16 *q = (u16 *)((u8 *)actions + clearOffset);
863 *q = 0;
864 *q = 0;
865 }
866 actionCount = 0;
867
868 // type0c is the Psynergy's field effect. Passes 1 and 2 add nothing.
869 if (mode == 1) {
870 for (slotIndex = 0; slotIndex < 32; slotIndex++) {
871 if (unit->actionSlots[slotIndex].encodedAction != 0) {
872 if (BattleActGet(unit->actionSlots[slotIndex].encodedAction &
874 ->type0c != 0) {
875 actions[actionCount] = unit->actionSlots[slotIndex].encodedAction;
876 actionCount++;
877 }
878 }
879 }
880 } else {
881 for (passIndex = 0; passIndex < passCount; passIndex++) {
882 for (slotIndex = 0; slotIndex < 32; slotIndex++) {
883 if (unit->actionSlots[slotIndex].encodedAction != 0) {
884 struct BattleAct *ability =
885 BattleActGet(unit->actionSlots[slotIndex].encodedAction &
887
888 if (passIndex == 0 &&
889 (ability->type0c != 0 ||
890 (ability->flags & ACTION_USABLE_IN_FIELD) != 0)) {
891 actions[actionCount] = unit->actionSlots[slotIndex].encodedAction;
892 actionCount++;
893 } else if (passIndex == 1) {
894 } else if (passIndex == 2) {
895 } else if (passIndex == 3 && ability->type0c == 0 &&
896 (ability->flags & ACTION_USABLE_IN_FIELD) == 0) {
897 actions[actionCount] = unit->actionSlots[slotIndex].encodedAction;
898 actionCount++;
899 }
900 }
901 }
902 }
903 }
904
905 return actionCount;
906}
907
908/// Fills result with the Psynergy list of the member in pane index: their unit,
909/// how many Psynergy are listed, and the page and row of the one chosen last
910/// for them (kept within the list), five to a page. Returns 1.
912 s32 unitBits;
913 struct PsynergyMenuState *menu = gMenuWork;
914 s32 entryCount;
915 s32 row;
916 s32 page;
917 s32 pageCount;
918 s32 selectedIndex;
919 s32 ownerId;
920
921 unitBits = (s32)UnitGetFar(menu->ownerIds[index]);
922 entryCount = menu->psynergyCount;
923 ownerId = menu->ownerIds[index];
924 selectedIndex = menu->selectedIndexByOwner[ownerId];
925 if ((selectedIndex + 1) > entryCount) {
926 selectedIndex = entryCount - 1;
927 }
928 page = selectedIndex / LIST_PAGE_SIZE;
929 row = selectedIndex % LIST_PAGE_SIZE;
930 pageCount = entryCount / LIST_PAGE_SIZE;
931 if (entryCount % LIST_PAGE_SIZE != 0) {
932 pageCount++;
933 }
934 result->ownerState = unitBits;
935 result->page = page;
936 result->pageCount = pageCount;
937 result->row = row;
938 result->entryCount = entryCount;
939 result->selectedIndex = selectedIndex;
940 return 1;
941}
942
943/// PsynergyMenuState.flags: the Psynergy list shows the shortcut help (Select
944/// held).
945#define PSYNERGY_MENU_SHORTCUT_HELP 2
946
947/// Updates the Psynergy list for the row under the cursor: puts the Psynergy's
948/// description in the info window, unless a kept message is there, and
949/// highlights its row of the five. window and work are not used.
951 struct MenuResult *state) {
952 struct PsynergyMenuState *menu;
953 s32 actionIndex;
954 s32 rowIndex;
955
956 menu = gMenuWork;
957 actionIndex = state->page * LIST_PAGE_SIZE;
958 actionIndex += state->row;
959 state->selectedIndex = actionIndex;
960
963 WaitFrames(1);
964
965 actionIndex = state->selectedIndex;
966 if (menu->psynergies[actionIndex] != 0) {
967 s32 description =
968 (menu->psynergies[actionIndex] & 0x1ff) + MsgAbilityDescription;
969 MENU_DRAW_INFO_TEXT(description, menu->infoWindow, 0, 0);
970 }
971 } else {
972 // BUG: clears scene flag 0x2ff instead of FLAG_MENU_INFO_KEPT, so a kept
973 // message keeps the descriptions away until another screen clears it.
974#ifdef BUGFIX
976#else
978#endif
979 }
980
981 rowIndex = 0;
982 do {
983 if (rowIndex == state->row) {
985 PSYNERGY_DETAIL_ROW_X, rowIndex * 2 + 1,
987 14); // highlighted
988 } else {
990 PSYNERGY_DETAIL_ROW_X, rowIndex * 2 + 1,
992 15); // normal
993 }
994 rowIndex++;
995 } while (rowIndex < LIST_PAGE_SIZE);
996
997 WaitFrames(1);
998 return 1;
999}
1000
1001/// Draws one page of the Psynergy list into window: up to five names with their
1002/// icons and PP costs, Psynergy the member cannot afford in the no-HP colour
1003/// and one restricted here in the low-HP colour, the page numbers, and the help
1004/// line (how to set a shortcut while Select is held, else how to change
1005/// member).
1007 const struct MenuResult *pageState) {
1008 u32 firstEntry;
1009 u32 visibleCount;
1010 u8 row;
1011 s32 cursor;
1012 struct BattleUnit *owner;
1013 struct BattleAct *ability;
1014 struct PsynergyMenuState *menu = gMenuWork;
1015
1016 (void)unused;
1017
1018 RenderOutput_RedrawSavedRectFar((void *)window);
1019 UiWindow_DrawDividerLineFar(window, 0, 11, 16, 11);
1020
1021 if (PSYNERGY_MENU_SHORTCUT_HELP & menu->flags) {
1022 UiText_DrawCharacterAtOffsetFar(MsgShortcutHelp, window, 0, 88);
1023 } else {
1024 UiText_DrawCharacterAtOffsetFar(MsgChangeCharacterHelp, window, HELP_TEXT_X,
1025 88);
1026 }
1027
1028 firstEntry = pageState->page * LIST_PAGE_SIZE;
1029 visibleCount = (u8)(pageState->entryCount - firstEntry);
1030 if (visibleCount > LIST_PAGE_SIZE) {
1031 visibleCount = LIST_PAGE_SIZE;
1032 }
1033
1035 34);
1037 pageState->page, 15);
1039 0);
1040
1041 row = 0;
1042 if (visibleCount > row) {
1043 cursor = firstEntry;
1044 do {
1045 owner = UnitGetFar(menu->ownerIds[0]);
1046 ability = BattleActGet(OWNER_ACTION_ID_MASK & menu->psynergies[cursor]);
1047
1048 if (ability->ppCost > owner->pp) {
1051 OWNER_ACTION_ID_MASK & menu->psynergies[cursor]) != 0) {
1053 } else {
1055 }
1056
1058 (OWNER_ACTION_ID_MASK & menu->psynergies[cursor]) + MsgAbilityName,
1059 window, PSYNERGY_NAME_X, row * 16 + 8);
1060 UiText_DrawNumberAtOffsetFar(ability->ppCost, 2, window, 104,
1061 row * 16 + 8);
1063
1064 row++;
1065 cursor++;
1066 } while (visibleCount > row);
1067 }
1068
1069 return 1;
1070}
1071
1072/// The Psynergy list of the member in paneIndex, five a page. The cursor's
1073/// Psynergy is described in the info window and its icon animates; L and R
1074/// switch to the previous or next member who has Psynergy to list. In the use
1075/// mode (menu mode 0), A chooses Psynergy the member can use and afford;
1076/// holding Select shows the shortcut help, and L or R with Select set the
1077/// Psynergy as that shortcut. In the shortcut modes (1 and 2) only field
1078/// Psynergy are listed and A chooses one. Returns the chosen Psynergy, or -1
1079/// when the player backs out.
1081 struct PsynergyMenuState *menu;
1082 struct BattleAct *ability;
1083 struct RenderOutput *icon;
1084 struct UiWindow *window;
1085 s32 changed;
1086 s32 moved;
1087 s8 listMode;
1088 s32 member;
1089 u8 i;
1090 s32 result;
1091 s32 redraw;
1092 s32 done;
1093 struct BattleUnit *owner;
1094 s32 previous;
1095 s32 shortcutHelp;
1096 s32 work[5];
1097 struct MenuResult state;
1098
1099 menu = gMenuWork;
1100 result = 0;
1101 previous = 0;
1102 shortcutHelp = 0;
1103 menu->paneIcon[paneIndex]->active = ICON_HIDDEN;
1104 UiWindow_UpdateOrCreate(&menu->listWindow, 13, 3, 17, 14, 2);
1105 window = menu->listWindow;
1106 done = 0;
1107
1108 while (done == 0 && GameFlag_TestFar(FLAG_MENU_START_PRESSED) == 0) {
1109 owner = UnitGetFar(menu->ownerIds[paneIndex]);
1110 if (menu->mode != 0) {
1111 menu->psynergyCount =
1112 PsynergyMenu_CollectActions(owner, menu->psynergies, 1);
1113 } else {
1114 menu->psynergyCount =
1115 PsynergyMenu_CollectActions(owner, menu->psynergies, 2);
1116 }
1118 PsynergyMenu_BuildPageResult(&state, paneIndex);
1119 redraw = 1;
1120 changed = 1;
1121 menu->paneIcon[paneIndex]->active = ICON_SHOWN;
1122
1125
1126 if (changed != 0) {
1127 changed = 0;
1128 if (menu->psynergies[previous] != 0) {
1129 icon = menu->entryIcons[previous];
1131 }
1132 if (redraw != 0) {
1133 redraw = 0;
1134 WaitFrames(1);
1135 PsynergyMenu_DrawActionPage(window, 0, &state);
1136 }
1137 PsynergyMenu_DrawDetailPage(window, work, &state);
1138 menu->paneAction[paneIndex] = menu->psynergies[state.selectedIndex];
1139 menu->cursorIcon->active = ICON_HIDDEN;
1140 if (menu->psynergies[state.selectedIndex] != 0) {
1141 icon = menu->entryIcons[state.selectedIndex];
1142 // Animate the selected icon.
1143 icon->active = 9;
1144 icon->animStep = 0;
1145 icon->sentinel = 250;
1146 }
1147 for (i = 0; i < menu->ownerCount; i++) {
1149 }
1150 }
1151
1152 WaitFrames(1);
1153 previous = state.selectedIndex;
1154
1155 if ((gKeysHeld & KEY_SELECT) == 0) {
1157 &state.row, &state.page);
1158 } else {
1159 moved = -1;
1160 }
1161 if (moved == 1) {
1162 redraw = 1;
1163 changed = 1;
1164 }
1165 if (moved == 0) {
1166 changed = 1;
1167 }
1168 if (moved == -1) {
1169 changed = 0;
1170 }
1171
1172 // Select shows the shortcut help while held, for field Psynergy.
1173 if (menu->mode == 0) {
1174 if ((gKeysPressed & KEY_SELECT) != 0 && shortcutHelp == 0) {
1175 ability = BattleActGet(menu->psynergies[state.selectedIndex] &
1177 if (ability->type0c == 0) {
1179 } else {
1180 AudioCommand_PlayFar(SE_174); // the Use sound
1181 shortcutHelp = 1;
1183 UiWindow_ClearInteriorTilesFar((void *)window, 0, 88, 120, 96);
1184 UiText_DrawCharacterAtOffsetFar(MsgShortcutHelp, window, 0, 88);
1185 }
1186 }
1187 if ((gKeysHeld & KEY_SELECT) == 0 && shortcutHelp == 1) {
1188 shortcutHelp = 0;
1190 UiWindow_ClearInteriorTilesFar((void *)window, 0, 88, 120, 96);
1191 UiText_DrawCharacterAtOffsetFar(MsgChangeCharacterHelp, window,
1192 HELP_TEXT_X, 88);
1193 }
1194 }
1195
1196 // A: set the shortcut (modes 1 and 2), or use the Psynergy if allowed
1197 // and affordable.
1198 if ((gKeysPressed & KEY_A) != 0) {
1199 if (menu->mode != 0) {
1200 AudioCommand_PlayFar(SE_130); // the shortcut sound
1201 result = menu->psynergies[state.selectedIndex];
1202 done = 1;
1203 break;
1204 }
1205 if (menu->psynergies[state.selectedIndex] != 0) {
1207 menu->psynergies[state.selectedIndex]) != 0) {
1209 continue;
1210 }
1211 ability = BattleActGet(menu->psynergies[state.selectedIndex] &
1213 if (ability->ppCost > owner->pp) {
1215 } else {
1216 AudioCommand_PlayFar(SE_173); // the choice sound
1217 result = menu->psynergies[state.selectedIndex];
1218 done = 1;
1219 break;
1220 }
1221 }
1222 }
1223
1224 if ((gKeysPressed & KEY_B) != 0) {
1226 result = -1;
1227 done = 1;
1228 break;
1229 }
1230
1231 // L and R: the previous or next member with Psynergy to list.
1232 if (((gKeysRepeat & KEY_R) != 0 || (gKeysRepeat & KEY_L) != 0) &&
1233 (gKeysHeld & KEY_SELECT) == 0) {
1234 listMode = menu->mode != 0 ? 1 : 2;
1236 menu->selectedIndexByOwner[menu->ownerIds[paneIndex]] =
1237 state.selectedIndex;
1238 member = menu->tabIndex[paneIndex];
1239 do {
1240 if ((gKeysRepeat & KEY_R) != 0) {
1241 member++;
1242 } else {
1243 member--;
1244 }
1245 member = (member + menu->ownerCount) % menu->ownerCount;
1246 menu->selectedOwner = menu->ownerTable[member];
1247 menu->ownerIds[0] = menu->ownerTable[member];
1249 UnitGetFar(menu->ownerIds[0]), menu->psynergies, listMode);
1250 } while (menu->psynergyCount == 0);
1251 menu->tabIndex[paneIndex] = member;
1252 for (i = 0; i < 4; i++) {
1253 menu->rowPositions[i] = 30;
1254 }
1255 menu->rowPositions[member] = 26;
1259 break;
1260 }
1261
1262 // Select + L or R: make the field Psynergy that shortcut.
1263 if ((gKeysPressed & KEY_L) != 0 && (gKeysHeld & KEY_SELECT) != 0) {
1264 ability = BattleActGet(menu->psynergies[state.selectedIndex] &
1266 if (ability->type0c == 0) {
1268 } else {
1269 AudioCommand_PlayFar(SE_130); // the shortcut sound
1270 if (PsynergyMenu_SetShortcut(menu->ownerIds[paneIndex],
1271 menu->psynergies[state.selectedIndex],
1272 0) != 0) {
1273 result = menu->psynergies[state.selectedIndex];
1274 menu->mode = 1;
1275 done = 1;
1276 break;
1277 }
1278 }
1279 }
1280
1281 if ((gKeysPressed & KEY_R) != 0 && (gKeysHeld & KEY_SELECT) != 0) {
1282 ability = BattleActGet(menu->psynergies[state.selectedIndex] &
1284 if (ability->type0c == 0) {
1286 } else {
1287 if (PsynergyMenu_SetShortcut(menu->ownerIds[paneIndex],
1288 menu->psynergies[state.selectedIndex],
1289 1) != 0) {
1290 AudioCommand_PlayFar(SE_130); // the shortcut sound
1291 result = menu->psynergies[state.selectedIndex];
1292 menu->mode = 2;
1293 done = 1;
1294 break;
1295 }
1296 }
1297 }
1298 }
1299 }
1300
1303 menu->paneRow[paneIndex] = state.selectedIndex;
1304 menu->selectedIndexByOwner[menu->ownerIds[paneIndex]] = state.selectedIndex;
1305 menu->paneAction[paneIndex] = result;
1307 result = -1;
1308 }
1309 WaitFrames(1);
1310 return result;
1311}
1312
1313/// Returns 1 when actionEntry cannot be used from the
1314/// menu: it has no field effect and is not usable both in the field and in
1315/// battle.
1317 // Mask the unsigned entry without overflowing a signed left shift.
1318 struct BattleAct *action = BattleActGet(((u32)actionEntry << 18) >> 18);
1319
1320 if (action->type0c != 0 ||
1323 return 0;
1324 return 1;
1325}
1326
1327#undef PSYNERGY_PROMPT_TILES
1328#undef PSYNERGY_PROMPT_TILES_SIZE
1329#undef PSYNERGY_DETAIL_ROW_X
1330#undef PSYNERGY_DETAIL_ROW_WIDTH
1331#undef PSYNERGY_PAGE_ICONS_X
1332#undef PSYNERGY_PP_LABEL_X
1333#undef PSYNERGY_NAME_X
1334#undef PSYNERGY_LIST_CURSOR_X
1335#undef PSYNERGY_SHORTCUT_OWNER_SHIFT
1336#undef PSYNERGY_SHORTCUT_ID_MASK
1337#undef PSYNERGY_MENU_SHORTCUT_HELP
@ OWNER_ACTION_ID_MASK
Definition battle_unit.h:14
void UiMenu_SlideCursor(s32 x, s32 y)
Slides the hand cursor from where it is to (x, y) inside the menu's top-left window over two frames,...
Definition common.c:625
void Menu_ReleaseEntryObjects(void)
Releases the party figures PsynergyMenu_InitializeEntryObjects created and stops their placement call...
Definition common.c:555
struct UiWindow * UiMenu_CreateCursor(void *source)
Opens the menu's top-left window (13 by 5 tiles) and puts the hand cursor in it, hidden for now.
Definition common.c:483
void UiIcon_PrepareObject(struct RenderOutput *object)
Shows a menu icon at its stored position, without rotation or scaling.
Definition common.c:465
void UiText_DrawWorkValueWithLabel(struct UiWindow *window)
Writes the party's coins and the "Coins" label into window.
Definition common.c:1154
void Palette_LightenBankHighlight(s32 bank)
Copies the last background palette (15) into background palette bank and lightens its colour 4 by 9 s...
Definition common.c:1012
void PsynergyMenu_CallIconRoutineWithValue(const void *unused, s32 unit)
Loads the graphics of character unit into menu entry slot 0.
Definition common.c:477
void Render_SetTilemapFlagRect(const struct UiWindow *window, s32 x, s32 y, s32 width, s32 height, u32 palette)
Switches a rectangle of a window's text between palette 15 (normal) and 14 (the highlight made by Pal...
Definition common.c:1075
void PsynergyMenu_RefreshOwnerEntries(s32 originX, s32 originY, s32 columns)
Lays the menu's entry icons (up to 32) out in a grid of 16x16 cells, columns wide,...
Definition common.c:689
s32 UiIcon_CreateWithResourceVariant(struct UiWindow *window, s32 x, s32 y)
Creates the menu's hand cursor sprite in window at (x, y), loading the hand's tiles into a free VRAM ...
Definition common.c:451
void Menu_DrawPageIndicator(struct UiWindow *window, s32 itemCount, s32 pageSize, s32 selectedPage, s32 rightEdge)
Draws a paged list's page numbers on the top border of window, ending at tile rightEdge: one digit pe...
Definition common.c:1040
void UiMenu_PositionCursor(s32 xOffset, s32 yOffset)
Places the hand cursor at (xOffset, yOffset) inside the menu's top-left window, bobbing.
Definition common.c:611
void Menu_CancelSoundReset(void)
Starts watching for Start: clears FLAG_MENU_START_PRESSED and adds Menu_CancelSoundTick.
Definition common.c:1199
s32 Menu_SuspendFieldTasks(void)
Suspends the overlay tasks and tile animations while a menu is open, and sets flags 0x152 and 0x166.
Definition common.c:52
void UiWindow_InitializeWork(s32 unused)
Clears the whole menu work and sets its defaults: no pane selected, one entry in each pane,...
Definition common.c:61
void PsynergyMenu_InitializeEntryObjects(void *source, s32 originX, s32 originY, s32 spacing, s32 unused)
Creates a walking figure for each active party member, side by side under the window source: origin (...
Definition common.c:511
void Menu_EnsureCancelSound(void)
Stops watching for Start, if Start has not removed the watch already.
Definition common.c:1205
s32 Menu_ResumeFieldTasks(void)
Resumes the overlay tasks and tile animations when a menu closes, and clears game flags 0x166 and 0x1...
Definition common.c:38
void Menu_DrawOwnerStatusPanel(struct UiWindow *unused, s32 owner, s32 slot, s32 mode)
Draws the item menu's status panel for the party member owner (window at tile 0,5,...
Definition common.c:117
void InventoryMenu_ShowModalMessage(s32 message, s32 x, s32 y)
Shows message in the item menu, with the hand cursor hidden meanwhile.
Definition common.c:770
s32 Menu_HandlePageInput(s32 horizontal, s32 count, s32 pageSize, s32 *cursor, s32 *page)
Moves a paged list's cursor and page with the d-pad's repeating keys.
Definition common.c:931
void Menu_SetPageIcons(s32 pageSize, s32 first, struct UiWindow *window, s32 x, s32 y)
Shows the item icons of one page of the item list: entries first to first + pageSize - 1,...
Definition common.c:1131
s32 UiWindow_UpdateOrCreate(struct UiWindow **handle, s32 x, s32 y, s32 w, s32 h, s32 flags)
Opens the window kept in *handle, or redraws it if it is already open.
Definition common.c:78
s32 AnimationObjects_SelectAnimationFar(struct AnimationObject *state, s32 flags)
struct BattleUnit * UnitGetFar(u32 owner)
s32 Party_ListActiveOwnersFar(s16 *owners)
s16 Unit_AddPpFar(s32 owner, s32 delta)
s32 GameFlag_TestFar(s32 flag)
struct BattleAct * BattleActGet(s32 actionId)
Far call to BattleAction_GetDirect.
void GameFlag_ClearBitFar(s32 flag)
void UnitCalcFar(s32 owner)
void Event_ClearInvalidPackedValuesFar(void)
s32 BattleFx_HasMatchingEvent5Far(s32 group)
void AudioCommand_PlayFar(s32 id)
struct UiWindow * UiWindow_CreateFar(s32 x, s32 y, s32 width, s32 height, s32 attrs)
void UiWindow_DrawFrameFar(s32 x, s32 y, u32 width, u32 height)
void UiWindow_MarkVisibleTileAttributesFar(void)
void RenderOutput_ClearListFar(void *work)
void UiWindow_EraseBorderRectFar(s32 x, s32 y, u32 width, u32 height)
void UiWork_SetParamNibbleFar(s32 param)
s32 UiText_GetResourceDimensionsFar(s32 no, s32 *x, s32 *y, u32 *width, u32 *height)
s32 Resource_LoadByModeIntoSlotFar(s32 mode, s32 value, s32 result, s32 option)
void Link_DrawShiftedTilePairFar(s32 offset)
struct RenderOutput * SideObject_CreateFar(s32 object_kind, s32 position, s32 side, struct UiWindow *arg3, s32 arg4, s32 arg5)
Far call to CreateSideObject.
void UiText_DrawNumberAtOffsetFar(s32 arg0, s32 arg1, const struct UiWindow *arg2, s32 arg3, s32 arg4)
void UiWindow_ClearInteriorTilesFar(const struct UiWindow *window, u32 left, u32 top, u32 right, u32 bottom)
void UiWindow_DrawDividerLineFar(struct UiWindow *win, u32 x1, u32 y1, u32 x2, u32 y2)
void UiText_DrawCharacterAtOffsetFar(s32 character, const struct UiWindow *position, u32 offsetX, u32 offsetY)
void UiWork_FinalizeFar(struct UiWindow *work, s32 release)
void UiText_DrawStringAtOffsetFar(const u8 *text, const struct UiWindow *work, s32 offsetX, s32 offsetY)
struct RenderOutput * RenderOutput_CreateFromResourceFar(s32 mode, s32 resource, struct UiWindow *input, s32 x, s32 y)
void UiWork_PushValueSlotFar(u32 value, u32 kind)
void UiWork_SetAltFlagAndClearTableFar(s32 flag)
void RenderOutput_RedrawSavedRectFar(struct UiWindow *window)
void UiText_DrawStringInWindowFar(const u8 *text, struct UiWindow *arg1, u32 x, u32 y)
void WaitFrames(s32 frames)
The game's frame loop: runs frames frames and returns.
Definition frame.c:97
struct GameState gGameState
void * gMenuWork
void * Runtime_BumpAllocateAlternatePool(s32 size)
As MemAlloc, but tries EWRAM first.
Definition heap.c:140
void * MemAlloc(s32 size)
Allocates size bytes (rounded up to words) with no slot, from IWRAM when they fit and EWRAM otherwise...
Definition heap.c:115
void * Runtime_AllocateHeapBlock(s32 kind, s32 size)
Returns heap slot kind's block, first allocating size bytes for it (rounded up to words),...
Definition heap.c:47
@ HEAP_SLOT_MENU
Definition heap_state.h:55
@ HEAP_SLOT_MENU_CONTROL
Definition heap_state.h:35
@ HEAP_SLOT_WINDOW
Definition heap_state.h:39
@ HEAP_SLOT_EVENT
Definition heap_state.h:40
#define WORK_SLOT(n)
Reads slots through their own addresses; adjacent slots are reached by offsets.
Definition heap_state.h:14
@ KEY_B
Definition io_reg.h:244
@ KEY_SELECT
Definition io_reg.h:245
@ KEY_LEFT
Definition io_reg.h:248
@ KEY_RIGHT
Definition io_reg.h:247
@ KEY_R
Definition io_reg.h:251
@ KEY_A
Definition io_reg.h:243
@ KEY_L
Definition io_reg.h:252
void ItemMenu_Close(void)
Closes the item menu: releases the party figures, hides the icons and the cursor, and closes every wi...
Definition item.c:962
void ItemMenu_DrawMessage(s32 unused, s32 message)
Clears the message window and writes message into it.
Definition item.c:1335
void ItemMenu_Initialize(s32 x, s32 y, s32 mode, s32 columns)
Sets up the item menu's first screen: the cursor window with the party's figures, the info window alo...
Definition item.c:860
void Menu_SpawnIconEntries(struct InventoryMenuState *state, struct UiWindow *window)
Creates the 32 item icon sprites in window, off screen until placed: slots 0 to 7 at x 248,...
Definition item.c:886
void Menu_HideEmptyEntryIcons(const u16 *items)
Hides the icon of each of the 32 list entries whose item is 0.
Definition item.c:1344
static s32 Iwram_CopyWords(volatile void *destination, const volatile void *source, s32 size)
Definition iwram_call.h:85
static s32 Iwram_FillWords(void *destination, s32 size, u32 value)
Definition iwram_call.h:59
volatile u32 gKeysHeld
Keys down now.
volatile u32 gKeysPressed
Keys that went down this frame.
volatile u32 gKeysRepeat
Pressed keys, repeating while held: after 19 frames, then every 6.
void Runtime_ReleaseHeapBlock(s32 slot)
void MemFree(void *buffer)
s32 PsynergyMenu_SelectPartySlot(s32 partySlot)
Lets the player choose a party member in pane partySlot (0 or 1), starting from the one chosen last,...
Definition psynergy.c:331
void PsynergyMenu_CreateEntryGrid(void)
Sets up a Psynergy grid screen: the cursor window with the party's figures, a 30 by 15 window below w...
Definition psynergy.c:765
#define PSYNERGY_SHORTCUT_ID_MASK
Definition psynergy.c:606
#define PSYNERGY_PAGE_ICONS_X
Definition psynergy.c:26
#define PSYNERGY_DETAIL_ROW_WIDTH
Definition psynergy.c:18
s32 PsynergyMenu_Run(void)
The Psynergy menu an event opens (window command 1): the field menu's Psynergy screen over the field,...
Definition psynergy.c:42
#define PSYNERGY_NAME_X
Definition psynergy.c:28
UNUSED void PsynergyMenu_NoOp(void)
Definition psynergy.c:522
#define PSYNERGY_MENU_SHORTCUT_HELP
PsynergyMenuState.flags: the Psynergy list shows the shortcut help (Select held).
Definition psynergy.c:945
s32 PsynergyMenu_DrawActionPage(struct UiWindow *window, s32 unused, const struct MenuResult *pageState)
Draws one page of the Psynergy list into window: up to five names with their icons and PP costs,...
Definition psynergy.c:1006
s32 PsynergyMenu_DrawShortcuts(struct UiWindow *window, s32 ownerId)
Definition psynergy.c:628
s32 PsynergyMenu_BuildPageResult(struct MenuResult *result, s32 index)
Fills result with the Psynergy list of the member in pane index: their unit, how many Psynergy are li...
Definition psynergy.c:911
#define PSYNERGY_PP_LABEL_X
Definition psynergy.c:27
s32 PsynergyMenu_SelectMember(u16 *ownerIds, u16 *unused)
The party member row of the Psynergy menu.
Definition psynergy.c:391
void PsynergyMenu_RefreshOwnerPsynergy(s32 ownerId)
Shows member ownerId's Psynergy icons in the Psynergy window, eight to a row, or "no Psynergy" when t...
Definition psynergy.c:501
s32 PsynergyMenu_IsActionRestricted(s32 actionEntry)
Returns 1 when actionEntry cannot be used from the menu: it has no field effect and is not usable bot...
Definition psynergy.c:1316
s32 PsynergyMenu_ClassifySelectedPsynergy(void)
Says how the selected Psynergy is used from the menu: 0 on the field once the menu closes (its effect...
Definition psynergy.c:306
#define PSYNERGY_DETAIL_ROW_X
Definition psynergy.c:17
s32 PsynergyMenu_RunList(s32 paneIndex)
The Psynergy list of the member in paneIndex, five a page.
Definition psynergy.c:1080
s32 PsynergyMenu_CollectActions(struct BattleUnit *unit, u16 *actions, s32 mode)
Lists unit's Psynergy into actions (32 entries, cleared first) and returns how many there are.
Definition psynergy.c:849
#define PSYNERGY_SHORTCUT_OWNER_SHIFT
A Psynergy shortcut: its owner above bit 10, the Psynergy's id below.
Definition psynergy.c:605
s32 PsynergyMenu_DrawDetailPage(struct UiWindow *window, s32 *work, struct MenuResult *state)
Updates the Psynergy list for the row under the cursor: puts the Psynergy's description in the info w...
Definition psynergy.c:950
void PsynergyMenu_CloseWindows(void)
Releases the party figures and closes the Psynergy grid screen's windows.
Definition psynergy.c:813
void PsynergyMenu_DrawPsynergyIcons(u16 *psynergies)
Loads each listed Psynergy's icon into its icon sprite (32 entries) and hides the icons of empty entr...
Definition psynergy.c:825
UNUSED s32 PsynergyMenu_ReturnTrue(void)
Nothing calls them.
Definition psynergy.c:520
s32 Menu_ResolveSelectedAction(s32 *outOwner, s32 *unused, s32 *outAction)
Runs the Psynergy menu: choose a party member and one of their Psynergy, then use it on a member (or ...
Definition psynergy.c:118
#define PSYNERGY_LIST_CURSOR_X
Definition psynergy.c:29
s32 PsynergyMenu_SelectTarget(s32 targetMode)
Chooses the party member to use the selected Psynergy on.
Definition psynergy.c:527
s32 PsynergyMenu_SetShortcut(s32 ownerId, s32 actionId, s32 shortcutIndex)
Sets the L (shortcutIndex 0) or R (shortcutIndex 1) Psynergy shortcut: ownerId << 10 | the Psynergy's...
Definition psynergy.c:610
PsynergyMenuStep
The steps of the Psynergy menu (Menu_ResolveSelectedAction).
Definition psynergy.c:104
@ PSYNERGY_STEP_LIST
Definition psynergy.c:106
@ PSYNERGY_STEP_OWNER
Definition psynergy.c:105
@ PSYNERGY_STEP_CLASSIFY
Definition psynergy.c:107
@ PSYNERGY_STEP_APPLY
Definition psynergy.c:109
@ PSYNERGY_STEP_TARGET
Definition psynergy.c:108
void ItemMenu_PosCategory(void)
Moves all entry sprites off screen before arranging another category.
Definition status.c:2001
const u8 gMenu_ShortcutLColonString[]
const u8 gMenu_ShortcutRString[]
const u8 gMenu_ShortcutLString[]
const u8 gMenu_ShortcutRColonString[]
What every part of the menu object shares: its includes, and the macros and types more than one part ...
#define TEXT_COLOR_LOW_HP
HP under a quarter of the maximum.
#define ACTION_USABLE_IN_FIELD
BattleAct.flags: where an ability or item can be used, as the Psynergy list says ("Usable in the fiel...
#define MENU_WORK_SIZE
The bytes of the menu work, heap block HEAP_SLOT_MENU.
#define ICON_HIDDEN
#define TEXT_COLOR_NO_HP
HP 0.
#define ACTION_USABLE_IN_BATTLE
#define FLAG_MENU_INFO_KEPT
The info window holds a message the next selection must not draw over.
#define ICON_SHOWN
RenderOutput.active as the menu sets it: shown, or hidden but kept.
#define TEXT_COLOR_NORMAL
#define FLAG_MENU_START_PRESSED
Game flags of the menus.
#define MENU_DRAW_INFO_TEXT
#define MENU_RESET_INFO_WINDOW
@ STATUS_PANEL_EXPERIENCE
class, HP, PP and experience
#define MENU_TARGET_WHOLE_PARTY
The target id of Psynergy or an item used on the whole party.
#define SE_173
Definition songs.h:168
#define SE_MENU_CANCEL
Definition songs.h:106
#define SE_MENU_CURSOR_MOVE
Definition songs.h:104
#define SE_174
Definition songs.h:169
#define SE_MENU_ERROR
Definition songs.h:107
#define SE_130
Definition songs.h:123
#define SE_MENU_CONFIRM
Definition songs.h:105
#define NULL
Definition bilibin.h:6
An ability's definition, a row of gBattleAction_DefinitionTable: its targeting, kind,...
u8 type0c
The field Psynergy the ability works as, 1 (Move) to 16 (Avoid); 0 for none.
u8 ppCost
PP the ability costs.
u8 range
the aimed unit and range - 1 either side, or ABILITY_RANGE_ALL
u8 targetMode
TARGET_MODE_NONE, _FOES, _ALLIES or _SELF.
u8 flags
bits: 7 usable in battle | 6 usable in the field | 5..4 clear in every row | 3..0 kind (ABILITY_KIND_...
A unit in battle: a party member's or an enemy's stats, Psynergy, items, Djinn and ailments.
u8 name[0x0f]
The name, one byte a character, ending in 0.
s16 pp
current PP
struct OwnerActionSlot actionSlots[32]
The action list: Psynergy taught for good, then the class's and the equipment's (Unit_RefreshPsynergy...
The running scene's event work: its placement and event tables, its actors, the triggers and exit it ...
Definition event_work.h:20
s16 psynergyRequest
a field Psynergy to use, as owner << 10 | Psynergy
Definition event_work.h:33
u16 firstShortcut
The shortcuts' assignments.
Definition game_state.h:86
u16 secondShortcut
Definition game_state.h:87
The item menu's work, in the HEAP_SLOT_MENU work slot: its windows, the party figures,...
A paged list for one party member: their unit, the list's length and pages, and the page and row of t...
Definition menu_result.h:12
s32 selectedIndex
Definition menu_result.h:19
The object system's work: the flag that suspends sprite projection, the outline's edge and fill colou...
Definition animspr.h:66
s16 suspended
nonzero while a menu has suspended sprite projection
Definition animspr.h:69
u16 encodedAction
bits: 15 from the class | 14 from an equipped item | 13..0 action id.
Definition battle_unit.h:22
The Psynergy menu: its windows, icons and cursors, the party members' tabs and the Psynergy listed fo...
struct UiWindow * psynergyWindow
struct UiWindow * shortcutWindow
the L and R shortcuts
u16 paneAction[2]
each pane's Psynergy chosen, as an owner action entry
u16 paneRow[2]
each pane's Psynergy row chosen
s8 tabCounts[2]
members each pane chooses from
struct RenderOutput * entryIcons[32]
u16 psynergies[32]
the chosen member's Psynergy listed
struct RenderOutput * paneIcon[2]
each pane's cursor
u8 mode
0 to use Psynergy; 1 or 2 to set the L or R shortcut
struct UiWindow * messageWindow
u16 flags
bits: 1 the list shows the shortcut help | 0 set after a use or a cancelled target
struct UiWindow * statusWindow
s32 selectedOwner
the party member chosen
u16 skipSlide
1 skips the cursor's next slide once
s8 selectedIndexByOwner[8]
each member's entry chosen last
struct UiWindow * auxiliaryWindow
s8 tabIndex[2]
each pane's member, in ownerTable
u8 ownerIds[2]
The user and the target: [1] is MENU_TARGET_WHOLE_PARTY for Psynergy on the whole party.
s16 useResult
the use's result message, after MsgItemUseResult
struct UiWindow * infoWindow
struct AnimationObject * tabObjects[8]
the party members' figures
struct UiWindow * listWindow
u16 ownerTable[8]
the party in order (Party_ListActiveOwners)
s16 rowPositions[8]
screen pixels
struct RenderOutput * cursorIcon
struct RenderOutput * entryGridCursor
u8 selectedColumn
The cursor grid: its place and its size.
A render output: a sprite in a window's output list (a character, an icon or a portrait),...
struct RenderOam oam
u16 y
screen pixels
u8 sentinel
depth slot it is drawn at (254 for glyphs)
s8 active
its UI_SPRITE_ motion; 0 while free
u16 animStep
step of its motion's animation
u16 x
screen pixels
s8 index
VRAM cache slot, or a glyph's tile after glyphTiles.
The window system's work: the windows' tilemap, the windows, the three text channels,...
Definition window.h:19
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
#define HELP_TEXT_X
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
signed char s8
Definition types.h:10
unsigned short u16
Definition types.h:13
#define UNUSED
Definition types.h:22
unsigned char u8
Definition types.h:11
#define LIST_PAGE_SIZE
Definition menu.h:83
#define UI_PAGE_ARROW_VRAM
Definition window.h:64
void Ability_PlayUseAnimation(s32 action)
Starts the action's menu animation and waits for its completion.
Definition use.c:317
s32 BattleEffect_ApplyToTargets(s32 effectId, s32 sourceId, s32 targetId, s32 fixedScale)
Applies healing or permanent-stat effects to one member or the whole party.
Definition use.c:51