Alchemy
Loading...
Searching...
No Matches

djinn.c

Go to the documentation of this file.
1/// @file
2/// The Djinn menu: its screen, the Djinn list, help, and choosing the Djinn to
3/// set, put on standby, give or trade.
4/// Part of menu.c, the menu object, compiled only through it.
5
6#include "../menu_internal.h"
7
8// The international editions widen the Djinn list's highlight, show a trade
9// preview's second side in another mode and lay the stat preview out for
10// fewer digits.
11//
12// The highlight over a row of the Djinn list, in tiles.
13#if TBS_PATCH_1
14#define DJINN_CURSOR_WIDTH 6
15#else
16#define DJINN_CURSOR_WIDTH 5
17#endif
18
19#if TBS_PATCH_1
20#define DJINN_SWAP_PREVIEW_MODE 2
21#else
22#define DJINN_SWAP_PREVIEW_MODE 4
23#endif
24
25// The stat preview's columns; an arrow stands at x (in tiles) or, in the
26// international editions, at the pixel column iconX the preview sets.
27#if TBS_PATCH_1
28#define DJINN_PREVIEW_DIGITS 3
29#define DJINN_PREVIEW_CURRENT_X 48
30#define DJINN_PREVIEW_MAX_X 80
31#define DJINN_PREVIEW_SLASH_X 72
32#define DJINN_PREVIEW_LUCK_X 56
33#define DJINN_PREVIEW_ARROW_X(x, iconX) (iconX)
34#define DJINN_PREVIEW_PP_X 88
35#else
36#define DJINN_PREVIEW_DIGITS 4
37#define DJINN_PREVIEW_CURRENT_X 32
38#define DJINN_PREVIEW_MAX_X 72
39#define DJINN_PREVIEW_SLASH_X 64
40#define DJINN_PREVIEW_LUCK_X 48
41#define DJINN_PREVIEW_ARROW_X(x, iconX) ((x) * 8 + 64)
42#define DJINN_PREVIEW_PP_X 56
43#endif
44
45/// Wraps a cursor index that has stepped one past either end of modulus
46/// entries: -1 becomes modulus - 1 and modulus becomes 0.
47s32 Menu_WrapIndex(s32 value, s32 modulus) {
48 return (value + modulus) % modulus;
49}
50
51/// Places the Djinn menu's first row at its normal height plus yOffset.
53 struct DjinnMenuWork *menu;
54 s32 ownerX;
55 s32 ownerIndex;
56 menu = gMenuWork;
57 yOffset += 0x3D;
58 ownerX = 0x20;
59 for (ownerIndex = 0; ownerIndex < 4; ownerIndex++) {
60 menu->ownerX[ownerIndex] = ownerX;
61 menu->ownerY[ownerIndex] = yOffset;
62 ownerX += 0x38;
63 }
64 return yOffset;
65}
66
67/// Runs the Djinn menu, preserving field tiles and the message speed.
69 struct DjinnMenuWork *menu;
70 u32 savedMessageSpeed;
71 s32 enabled;
72 struct DjinnMenuBackdrop *backdrop;
73 s32 zero;
74
76 savedMessageSpeed = gGameState.messageSpeed;
78 enabled = gMenuCtrlWork->suspended = 1;
79 UiWindow_DrawFrameFar(0, 0, 30, 20);
80 WaitFrames(1);
82 backdrop = Runtime_BumpAllocateAlternatePool(0x2130);
83 menu->backdrop = backdrop;
84 backdrop->tutorialTimer = 0;
85 backdrop->tutorialStep = 0;
87 if (!GameFlag_TestFar(0x16f)) {
88 if (!GameFlag_TestFar(0x171))
89 backdrop->tutorialStep = enabled;
90 else
91 backdrop->tutorialStep = 14;
92 } else {
93 if (!GameFlag_TestFar(0x171))
94 backdrop->tutorialStep = 27;
95 else
96 backdrop->tutorialStep = 28;
97 }
98 }
104 ItemMenu_Initialize(0, 3, 0, 7);
107 menu->helpWindow = UiWindow_CreateFar(13, 0, 17, 5, 2);
108 menu->pairEntries[0] = 255;
109 zero = 0;
110 menu->selectedColumn[0] = zero;
111 menu->selectedColumn[1] = zero;
112 menu->selection[0] = 0;
113 menu->selection[1] = 0;
118 WaitFrames(1);
120 UiWindow_DrawFrameFar(0, 0, 30, 20);
124 Iwram_CopyWords(BG_CHAR_BLOCK(1), backdrop->tiles, 0x2000);
125 Iwram_CopyWords((void *)&BG_PLTT_COLOR(4, 0), backdrop->palette, 128);
126 WaitFrames(1);
128 UiWindow_EraseBorderRectFar(0, 0, 30, 20);
129 MemFree(menu->backdrop);
132 gGameState.messageSpeed = savedMessageSpeed;
133 return 1;
134}
135
136/// Finds the moved Djinni in the list and selects its new position.
137/* FAKEMATCH(one-pass): the do { } while (0) ends the selection store's
138 * scheduling region at both uses; as a plain { } block, 4 of 560 instructions
139 * differ in tbs-en. */
140#define DJINN_RESELECT_PAIR_ENTRY(menu, i) \
141 do { \
142 s32 column; \
143 s32 found; \
144 u8 entry; \
145 \
146 column = (u16)((u32)(menu)->selection[1] % DJINN_LIST_ROWS); \
147 found = 0; \
148 entry = (menu)->pairEntries[0]; \
149 for ((i) = 0; (i) < (menu)->backdrop->list.counts[column]; (i)++) { \
150 if (entry == (u8)(menu)->backdrop->list.ids[column][(i)]) { \
151 found = (i); \
152 break; \
153 } \
154 } \
155 (menu)->selection[0] = column + found * DJINN_LIST_ROWS; \
156 } while (0)
157
158/// The screen chooses an operation, optionally previews it, then commits it.
176};
177
178/// Chooses a Djinni, previews changes, then sets, stands by, gives or trades
179/// it. Confirmation states fall through to their matching commit states on
180/// success.
182 struct DjinnMenuWork *menu;
183 struct RenderOutput *cursor;
184 s32 result;
185 s32 step;
186 s32 menuResult;
187 s32 done;
188 s32 listIndex;
189
190 done = 0;
191 result = 0;
192 menuResult = 0;
193 menu = gMenuWork;
194 cursor = menu->cursor;
195 cursor->active = ICON_HIDDEN;
196 cursor->animStep = 0;
198 WaitFrames(1);
200 do {
201 switch (step) {
203 if (result < 0) {
204 menuResult = -1;
205 done = 1;
206 }
208 break;
210 break;
214 result = DjinnMenu_SelectDjinn(0);
216 if (result == 10)
217 break;
219 if (result < 0)
220 break;
221 menu->selection[1] = menu->selectedColumn[0];
223 if (result == 7)
224 break;
226 break;
228 menu->owner = menu->owners[menu->selectedColumn[0]];
229 menu->shownOwner[0] = menu->owners[menu->selectedColumn[0]];
230 result = DjinnMenu_ShowOwnerStatus();
231 if (result == -2)
232 done = 1;
234 break;
236 result = DjinnMenu_ShowHelp();
237 if (result == -2)
238 done = 1;
240 break;
243 if (menu->pairCount == 0)
244 break;
245 result = DjinnMenu_SelectDjinn(1);
246 if (result == -2)
247 done = 1;
249 if (result < 0)
250 break;
252 break;
256 menu->owner = menu->owners[menu->selectedColumn[0]];
257 menu->shownOwner[0] = menu->owners[menu->selectedColumn[0]];
258 FourObjectMotion_SetSlotPosition(0, menu->selectedColumn[0] * 56 + 48, 54,
259 0);
260 result = DjinnMenu_SelectDjinn(1);
261 for (listIndex = 0; listIndex < menu->ownerCount; listIndex++)
262 menu->ownerY[listIndex] += 8;
263 if (result == -2)
264 done = 1;
265 if (result < 0) {
267 break;
268 }
269 if (result == 3 || result == 4 || result == 8 || result == 9)
270 menu->shownOwner[1] = menu->owners[menu->selectedColumn[1]];
271 if (result < 0)
273 else if (result == 1)
275 else if (result == 2)
277 else if (result == 3) {
278 menu->pending = 2;
280 } else if (result == 4) {
281 menu->pending = 2;
283 } else if (result == 5)
285 else if (result == 6)
287 else if (result == 8) {
288 menu->pending = 2;
290 } else if (result == 9) {
291 menu->pending = 2;
293 }
294 break;
297 if (result == -2)
298 done = 1;
300 if (result < 0)
301 break;
302 // Confirmed: apply it at once.
303 // Fall through.
306 result = Djinn_TransferFar(menu->shownOwner[0], menu->pairElement[0],
307 menu->pairIndex[0], menu->shownOwner[1]);
308 UnitCalcFar(menu->shownOwner[0]);
309 UnitCalcFar(menu->shownOwner[1]);
310 menu->cursor->active = ICON_HIDDEN;
313 DJINN_RESELECT_PAIR_ENTRY(menu, listIndex);
314 menu->cursor->active = ICON_SHOWN;
316 break;
319 if (result == -2)
320 done = 1;
322 if (result < 0)
323 break;
324 // Confirmed: apply it at once.
325 // Fall through.
328 Djinn_DeactivateFar(menu->shownOwner[0], menu->pairElement[0],
329 menu->pairIndex[0]);
331 menu->shownOwner[0], menu->pairElement[0], menu->pairIndex[0]);
332 UnitCalcFar(menu->shownOwner[0]);
333 menu->cursor->active = ICON_HIDDEN;
335 menu->cursor->active = ICON_SHOWN;
337 break;
340 if (result == -2)
341 done = 1;
343 if (result < 0)
344 break;
345 // Confirmed: apply it at once.
346 // Fall through.
349 Djinn_TransferFar(menu->shownOwner[0], menu->pairElement[0],
350 menu->pairIndex[0], menu->shownOwner[1]);
351 result = Djinn_TransferFar(menu->shownOwner[1], menu->pairElement[1],
352 menu->pairIndex[1], menu->shownOwner[0]);
353 UnitCalcFar(menu->shownOwner[0]);
354 UnitCalcFar(menu->shownOwner[1]);
356 DJINN_RESELECT_PAIR_ENTRY(menu, listIndex);
357 menu->cursor->active = ICON_SHOWN;
359 break;
361 if (result == -1) {
362 menuResult = result;
364 } else if (menu->pending & 1)
366 else if (menu->pending & 2)
368 break;
371 if (result == -2)
372 done = 1;
374 if (result < 0)
375 break;
376 // Confirmed: apply it at once.
377 // Fall through.
380 Djinn_ActivateFar(menu->shownOwner[0], menu->pairElement[0],
381 menu->pairIndex[0]);
383 menu->shownOwner[0], menu->pairElement[0], menu->pairIndex[0]);
384 UnitCalcFar(menu->shownOwner[0]);
385 menu->cursor->active = ICON_HIDDEN;
387 menu->cursor->active = ICON_SHOWN;
389 break;
390 default:
391 done = 1;
392 break;
393 }
394 } while (done == 0);
395 return menuResult;
396}
397
398/// Writes copies of background palettes 15, 5 and 7, each brightnessDelta
399/// lighter in every channel (clamped to 0-31), into palettes 14, 4 and 6.
400/// Palette 7's copy is 12 darker instead.
401void Graphics_AdjustPaletteBank(s32 brightnessDelta) {
402 s32 bankIndex;
403 s32 bank;
404 s32 colorIndex;
405 s32 mask;
406 s32 paletteIndex;
407
408 bank = 15;
409 bankIndex = 0;
410 mask = 31;
411 do {
412 for (colorIndex = 0; colorIndex <= 15; colorIndex++) {
413 u32 color;
414 s32 blue;
415 s32 green;
416 s32 red;
417 s32 adjustedColor;
418
419 paletteIndex = bank * 16 + colorIndex;
420 color = ((u16 *)BG_PLTT)[paletteIndex];
421 blue = (color >> 10) & mask;
422 green = (color >> 5) & mask;
423 red = color & mask;
424 blue += brightnessDelta;
425 green += brightnessDelta;
426 red += brightnessDelta;
427 if (blue > 31)
428 blue = 31;
429 if (green > 31)
430 green = 31;
431 if (red > 31)
432 red = 31;
433 if (blue < 0)
434 blue = 0;
435 if (green < 0)
436 green = 0;
437 if (red < 0)
438 red = 0;
439 adjustedColor = blue << 10;
440 adjustedColor |= green << 5;
441 adjustedColor |= red;
442 // Into the palette before this one.
443 ((s16 *)BG_PLTT - 16)[paletteIndex] = adjustedColor;
444 }
445 if (bankIndex == 0) {
446 bank = 5;
447 } else {
448 bank = 7;
449 brightnessDelta = -12;
450 }
451 bankIndex++;
452 } while (bankIndex <= 2);
453}
454
455#define DJINN_BACKDROP_FRAME_TILE 150
456
457#define DJINN_PREVIEW_GAINED 0x8000
458#define DJINN_PREVIEW_LOST 0x4000
459
460/// Draws the backdrop behind the Djinn menu's list: its window, tiles and
461/// palettes.
463 // UB: the implicit int call conflicts with DrawElementList's void definition.
464 // The sole caller ignores this wrapper's result. Plain void changes the
465 // native tbs-en return from pop {r1}; bx r1 to pop {r0}; bx r0.
466 struct DjinnMenuWork *menu = gMenuWork;
467 struct DjinnMenuBackdrop *backdrop = menu->backdrop;
468
469 UiWindow_UpdateOrCreate(&menu->listWindow, 0, 5, 30, 15, 2);
470 WaitFrames(1);
471 Iwram_CopyWords(backdrop->tiles, BG_CHAR_BLOCK(1), 0x2000);
472 Iwram_CopyWords(backdrop->palette, (void *)&BG_PLTT_COLOR(4, 0), 128);
473 Iwram_FillWords(BG_CHAR_BLOCK(1), 0x2000, 0x33333333);
474 Iwram_FillWords((void *)&BG_PLTT_COLOR(4, 0), 128, 0x55555555);
478 Dma_Set((const void *)Palette_GetBasicObjColors(),
479 (void *)&BG_PLTT_COLOR(5, 0), DMA_ENABLE << 16 | 16, REG_DMA3);
480 BG_PLTT_COLOR(5, 14) = BG_PLTT_COLOR(15, 4);
481 Dma_Set((void *)&BG_PLTT_COLOR(15, 0), (void *)&BG_PLTT_COLOR(7, 0),
482 DMA_ENABLE << 16 | 16, REG_DMA3);
484 BG_PLTT_COLOR(7, 4) = BG_PLTT_COLOR(15, 4);
485 BG_PLTT_COLOR(6, 4) = BG_PLTT_COLOR(15, 4);
486#ifdef UBFIX
488#else
489 return DjinnMenu_DrawElementList(&backdrop->list);
490#endif
491}
492
493/// Lists the actions after a preview, marking gains, then appends the losses.
494/// The two output counts distinguish gained and lost actions.
496 struct OwnerActionSlot *after, u16 *actionsOut,
497 s32 *gainedCountOut, s32 *lostCountOut) {
498 s32 actionIndex;
499 s32 otherIndex;
500 s32 actionCount;
501 s32 gainedCount;
502 s32 lostCount;
503
504 actionCount = 0;
505 gainedCount = 0;
506 lostCount = 0;
507 for (actionIndex = 0;
508 actionIndex < 32 && after[actionIndex].encodedAction != 0;
509 actionIndex++) {
510 actionsOut[actionCount] =
511 after[actionIndex].encodedAction & OWNER_ACTION_ID_MASK;
512 actionCount++;
513 for (otherIndex = 0; otherIndex < 32; otherIndex++) {
514 if (((after[actionIndex].encodedAction ^
515 before[otherIndex].encodedAction) &
517 break;
518 }
519 if (otherIndex == 32) {
520 gainedCount++;
521 actionsOut[actionCount - 1] |= DJINN_PREVIEW_GAINED;
522 }
523 }
524 for (actionIndex = 0;
525 actionIndex < 32 && before[actionIndex].encodedAction != 0;
526 actionIndex++) {
527 for (otherIndex = 0; otherIndex < 32; otherIndex++) {
528 if (((before[actionIndex].encodedAction ^
529 after[otherIndex].encodedAction) &
531 break;
532 }
533 if (otherIndex == 32) {
534 lostCount++;
535 actionsOut[actionCount] =
536 (before[actionIndex].encodedAction & OWNER_ACTION_ID_MASK) |
538 actionCount++;
539 }
540 }
541 *gainedCountOut = gainedCount;
542 *lostCountOut = lostCount;
543 return actionCount;
544}
545
546/// Rebuilds the Djinn lists in table: each owner's packed Djinn entries and
547/// their count.
549 struct DjinnMenuWork *menu;
550 s32 ownerIndex;
551 u16 (*entries)[DJINN_LIST_ROWS];
552 u16 *owners;
553 s8 *counts;
554 s16 entryCount;
556
557 menu = gMenuWork;
558 ownerIndex = 0;
559 if (ownerIndex < menu->ownerCount) {
560 counts = ((struct DjinnListTable *)table)->counts;
561 owners = menu->owners;
562 entries = ((struct DjinnListTable *)table)->ids;
563 do {
564 entryCount = Djinn_ListOwnerEntries(*entries, *owners, -1);
565 ownerCount = menu->ownerCount;
566 ownerIndex += 1;
567 *counts = entryCount;
568 owners += 1;
569 counts += 1;
570 entries++;
571 } while (ownerIndex < ownerCount);
572 }
573#ifdef UBFIX
574 return 0;
575#endif
576}
577
578/// The window map entry of the first element icon, in palette 5; the four
579/// elements follow it in order.
580#define DJINN_ELEMENT_TILE 0x5001
581
582/// Draws each owner's Djinn column, including set and recovering entries.
584 struct DjinnMenuWork *menu;
585 s32 listIndex;
586 s32 row;
587 s32 element;
588 struct UiWork *ui;
589 s32 lineIndex;
590 s32 canChangeState;
591 u16 *entries;
592
595 ui->menuBusy = 1;
596 listIndex = 0;
597 if (menu->ownerCount != 0) {
598 do {
599 table->counts[listIndex] = Djinn_ListOwnerEntries(
600 table->ids[listIndex], menu->owners[listIndex], -1);
601 listIndex++;
602 } while (listIndex < menu->ownerCount);
603 }
605 UiText_DrawCharacterAtOffsetFar(MsgUnleashEffect, menu->listWindow, 0, 80);
606 for (row = 0; row < menu->ownerCount; row++) {
607 entries = table->ids[row];
608 lineIndex = 0;
609 for (element = 0; element < DJINN_ELEMENTS; element++) {
610 for (listIndex = 0; listIndex < table->counts[row]; listIndex++) {
611 if (element != (entries[listIndex] & DJINN_ENTRY_ELEMENT) >> 5)
612 continue;
613 if ((entries[listIndex] & DJINN_ENTRY_IS_SET) == 0)
615 canChangeState = 0;
616 if (Djinn_IsReadyFar((entries[listIndex] & DJINN_ENTRY_OWNER) >> 8,
617 (entries[listIndex] & DJINN_ENTRY_ELEMENT) >> 5,
618 entries[listIndex] & DJINN_ENTRY_INDEX) ||
619 Djinn_IsActiveFar((entries[listIndex] & DJINN_ENTRY_OWNER) >> 8,
620 (entries[listIndex] & DJINN_ENTRY_ELEMENT) >> 5,
621 entries[listIndex] & DJINN_ENTRY_INDEX))
622 canChangeState = 1;
623 if (!canChangeState)
626 menu->listWindow,
627 ((entries[listIndex] & DJINN_ENTRY_ELEMENT) >> 5) +
629 row * 7 + 1, lineIndex + 2, 0);
631 MsgDjinnName +
632 ((entries[listIndex] & DJINN_ENTRY_ELEMENT) >> 5) *
634 (entries[listIndex] & DJINN_ENTRY_INDEX),
635 menu->listWindow, row * 56 + 16, lineIndex * 8 + 16);
636 lineIndex++;
638 }
639 }
640 }
641 UiWindow_DrawDividerLineFar(menu->listWindow, 0, 10, 28, 10);
642 ((struct UiWork *)WORK_SLOT(HEAP_SLOT_WINDOW))->dirty = 1;
643 ui->menuBusy = 0;
644}
645
646/// Sets the palette of a rectangle of window's interior, (x, y) and its size in
647/// tiles from the interior's corner, through UiWindow_SetPaletteBitRectFar.
649 s32 y, s32 width, s32 height,
650 s32 palette) {
651 UiWindow_SetPaletteBitRectFar(window->x + x + 1, window->y + y + 1, width,
652 height, palette);
653#ifdef UBFIX
654 return 0;
655#endif
656}
657
658/// Moves each tile of a screen rectangle (in tiles, clipped to the screen) that
659/// shows palette 15 to palette.
660void UiWindow_SetRectPalette(s32 x, s32 y, s32 width, s32 height, s32 palette) {
661 struct UiRenderWork *render;
663 s32 column;
664 u32 tile;
665 u32 masked;
666
667 render = (struct UiRenderWork *)gWindowWork[0];
668 palette <<= 12;
669 if (x < 0) {
670 width += x;
671 x = 0;
672 }
673 if (x + width > 29)
674 width = 30 - x;
675 if (y < 0) {
676 height += y;
677 y = 0;
678 }
679 if (y + height > 29)
680 height = 20 - y;
681
682 if (width > 0 && height > 0) {
683 do {
684 tileCursor = &((u16 (*)[32])render->tilemap)[y][x];
685 for (column = width; column != 0; column--) {
686 tile = *tileCursor;
687 if (((tile >> 12) & 15) == 15) {
688 masked = tile & 0xffff0fff;
689 *tileCursor = masked | palette;
690 }
691 tileCursor++;
692 }
693 UiRender_MarkRow(render, y);
694 height--;
695 y++;
696 } while (height != 0);
697 }
698}
699
700/// UiWindow_SetRectPalette on a rectangle of window's interior, (x, y) and its
701/// size in tiles from the interior's corner.
702void UiWindow_SetInteriorRectPalette(void *window, s32 x, s32 y, s32 width,
703 s32 height, s32 palette) {
704 UiWindow_SetRectPalette(((struct UiWindow *)window)->x + x + 1,
705 ((struct UiWindow *)window)->y + y + 1, width, height,
706 palette);
707}
708
709/// Runs the Djinn help choices and restores the list when the player leaves.
711 struct UiWindow *helpWindow;
712 struct UiWindow *statusWindow;
713 struct DjinnMenuWork *menu;
714 struct UiRenderWork *render;
715 s32 result;
716 s32 previous;
717 s32 selection;
718 struct UiWindow *list;
719 struct UiChannelSlot *channel;
720 s32 message;
721 s32 helpIndex;
722 s32 listMessage;
723
725 render = WORK_SLOT(HEAP_SLOT_WINDOW);
726 result = 0;
727 previous = 0;
728 selection = 0;
730 WaitFrames(1);
732 message = MsgDjinnInfoPrompt;
733 UiText_DrawCharacterAtOffsetFar(message, menu->helpWindow, 0, 0);
734 message++;
735 UiText_DrawCharacterAtOffsetFar(message, menu->helpWindow, 0, 16);
736 UiWindow_SetRectPalette(1, 1, 11, 3, 6);
737 UiWindow_SetInteriorRectPalette((void *)menu->listWindow, 0, 0, 28, 10, 6);
738 list = UiWindow_CreateFar(0, 9, 8, 10, 6);
739 helpWindow = UiWindow_CreateFar(8, 12, 22, 7, 2);
740 statusWindow = UiWindow_CreateFar(8, 9, 22, 3, 2);
742 helpIndex = 0;
743 listMessage = MsgDjinnInfoTopic;
744 do {
745 UiText_DrawCharacterAtOffsetFar(helpIndex + listMessage, list, 0,
746 helpIndex * 8);
747 helpIndex++;
748 } while (helpIndex <= 6);
749 do {
751 UiText_DrawResourceFar(selection + MsgDjinnInfoTopic, statusWindow, 0, 0);
752 channel = (struct UiChannelSlot *)UiText_OpenEntryMessageFar(
753 helpWindow, selection + MsgDjinnInfoText);
754 UiWindow_SetInteriorPaletteBitRect(list, 0, previous, 6, 1, 15);
755 UiWindow_SetInteriorPaletteBitRect(list, 0, selection, 6, 1, 14);
756 previous = selection;
757 for (;;) {
758 UiMenu_PositionCursor(-12, (list->y + selection) * 8 + 8);
759 WaitFrames(1);
760 if (gKeysRepeat & (KEY_RIGHT | KEY_DOWN)) {
761 selection++;
762 selection = Menu_WrapIndex(selection, 7);
764 break;
765 }
766 if (gKeysRepeat & (KEY_LEFT | KEY_UP)) {
767 selection--;
768 selection = Menu_WrapIndex(selection, 7);
770 break;
771 } else if (gKeysPressed & KEY_START) {
773 result = -2;
774 break;
775 } else if (gKeysPressed & (KEY_B | KEY_SELECT)) {
777 result = -1;
778 break;
779 } else if (gKeysPressed & KEY_A) {
780 if (UiWork_IsCompleteFar()) {
781 selection++;
782 selection = Menu_WrapIndex(selection, 7);
784 break;
785 }
787 }
788 }
789 if (render->glyphResource != 99) {
791 render->glyphResource = 99;
792 }
793 ((struct UiRenderWork *)gWindowWork[0])->pageArrowShown = 0;
795 {
796 struct UiWindow *window = channel->work;
797
798 window->frame = 0;
799 window->duration = 0;
800 window->state = 0;
801 }
802 channel->work = NULL;
803 } while (result == 0);
804 ((struct UiRenderWork *)gWindowWork[0])->menuBusy = 1;
805 RenderOutput_ClearListFar(statusWindow);
806 RenderOutput_ClearListFar(helpWindow);
807 WaitFrames(1);
808 UiWork_FinalizeFar(statusWindow, 1);
809 UiWork_FinalizeFar(list, 1);
810 UiWork_FinalizeFar(helpWindow, 1);
812 if (result == -2) {
816 ((struct UiRenderWork *)gWindowWork[0])->menuBusy = 0;
817 }
819 return result;
820}
821
822#define DJINN_ENTRY_SET (-0x8000)
823
824#define DJINN_OWNER(v) (((v) & 0xf00) >> 8)
825#define DJINN_ELEMENT(v) (((v) & 0xe0) >> 5)
826#define DJINN_NUMBER(v) ((v) & 0x1f)
827
828/// Chooses an owner and Djinni, or a set, standby, give or trade action.
829/// The tutorial can replace the sampled input without changing the input order.
831 s8 columnFlags[8];
832 u8 requiresTrade[16];
833 struct DjinnMenuWork *menu = gMenuWork;
834 struct DjinnMenuBackdrop *backdrop = menu->backdrop;
835 struct BattleUnit *unit;
836 struct UiWindow *window;
837 s32 redraw = 1;
838 u32 refresh;
839 s32 i;
840 s32 j;
841 s32 selectedRow;
842 s32 ownerColumn = (u16)(menu->selection[mode] % 10);
843 s32 djinnRow = (u16)(menu->selection[mode] / 10);
844 s32 savedRow = 0;
845 u32 djinn = 0;
846 s32 groupMode = 0;
847 s32 setAll = 0;
848 s32 result;
849 s32 message;
850 u32 pressed;
851 s32 count;
852 u32 repeat;
853 struct UiWindow *messageWindow;
854 s32 tutorialStep;
855 s8 *status;
856
857 selectedRow = -1;
858 status = columnFlags;
859 for (i = 7; i >= 0; i--)
860 status[i] = 0;
861 if (mode == 0) {
863 for (i = 0; i < menu->ownerCount; i++) {
864 if (backdrop->list.counts[i] == 0)
865 status[i] = 4;
866 }
867 savedRow = djinnRow;
868 for (i = 0; i < menu->ownerCount; i++) {
869 if (status[ownerColumn] == 4) {
870 ownerColumn++;
871 ownerColumn = Menu_WrapIndex(ownerColumn, menu->ownerCount);
872 }
873 }
874 } else {
875 Djinn_MarkBalancedEntries((s8 *)requiresTrade, menu->selectedColumn[0]);
876 for (i = 0; i < menu->ownerCount; i++) {
877 if (i == menu->selectedColumn[0]) {
878 columnFlags[i] = 7;
879 } else if (requiresTrade[i] != 0) {
880 columnFlags[i] = 0;
881 } else {
882 columnFlags[i] = 3;
883 if (backdrop->list.counts[i] == 0)
884 status[i] = columnFlags[i] | 4;
885 }
886 }
887 }
888 if (mode == 1) {
889 s32 fromX;
890 s32 fromY;
891 u16 sourceCursor;
892 s32 n;
893 sourceCursor = menu->selection[0];
894 fromX = (u16)((u32)sourceCursor % (u32)10);
895 fromY = (u16)((u32)sourceCursor / (u32)10);
897 fromY + 2, DJINN_CURSOR_WIDTH, 1, 14);
898 UiWindow_SetInteriorRectPalette(menu->listWindow, fromX * 7 + 1, 2,
899 DJINN_CURSOR_WIDTH, 7, 6);
900 for (n = 0; n < menu->ownerCount; n++) {
901 if (n == menu->selectedColumn[0]) {
902 if (menu->pairEntries[0] & DJINN_ENTRY_IS_SET)
903 message = MsgDjinnStandbyAction;
904 else
905 message = MsgDjinnSetAction;
906 } else if (columnFlags[n] & 2) {
907 message = MsgDjinnGiveAction;
908 } else {
909 message = MsgDjinnTradeAction;
910 }
911 UiText_DrawCharacterAtOffsetFar(message, menu->listWindow, n * 56 + 8, 8);
912 }
913 }
915 menu->cursor->active = ICON_SHOWN;
916 for (;;) {
917 if (redraw != 0) {
918 refresh = redraw;
919 redraw = 0;
920 selectedRow = -1;
921 if (!(columnFlags[ownerColumn] & 1))
922 selectedRow = djinnRow;
923 window = menu->statusWindow;
924 unit = UnitGetFar(menu->owners[ownerColumn]);
926 UiText_DrawStringAtOffsetFar(unit->name, window, 0, 0);
927 UiText_DrawCharacterAtOffsetFar(unit->classIndex + MsgClassName, window,
928 0, 8);
930 UiText_DrawNumberInWindowFar(unit->level, 2, window, 72, 0);
931 if (mode == 0)
932 UiText_DrawCharacterAtOffsetFar(MsgDjinnCharacterStatus, window, 0, 16);
933 if (selectedRow != -1)
934 djinn = backdrop->list.ids[ownerColumn][selectedRow];
936 if (mode == 1) {
937#if LANGUAGE == LANGUAGE_SPANISH || LANGUAGE == LANGUAGE_FRENCH || \
938 LANGUAGE == LANGUAGE_ITALIAN
940 menu->helpWindow,
941 DJINN_ELEMENT(menu->pairEntries[0]) + DJINN_ELEMENT_TILE, 0, 0, 0);
944 DJINN_NUMBER(menu->pairEntries[0]) + 300,
945 4);
946 UiText_DrawCharacterAtOffsetFar(MsgDjinnOwnerLabel, menu->helpWindow, 8,
947 0);
948#else
950 UiText_DrawCharacterAtOffsetFar(MsgDjinnOwnerLabel, menu->helpWindow, 0,
951 0);
953 DJINN_NUMBER(menu->pairEntries[0]) + 300,
954 4);
956 menu->helpWindow,
957 DJINN_ELEMENT(menu->pairEntries[0]) + DJINN_ELEMENT_TILE, 6, 0, 0);
958 UiText_DrawCharacterAtOffsetFar(MsgDjinnOwnerLabel + 1,
959 menu->helpWindow, 56, 0);
960#endif
961 UiText_DrawCharacterAtOffsetFar(MsgDjinnOwnerLabel + 2,
962 menu->helpWindow, 0, 8);
963 }
964 if (selectedRow == -1) {
965 FourObjectMotion_SetSlotPosition(mode, 0, 200, 0);
966 } else if (mode == 0) {
967 if (groupMode) {
968 if (setAll == 0) {
969 UiText_DrawCharacterAtOffsetFar(MsgDjinnSetAll, menu->helpWindow, 0,
970 0);
971 } else {
972 UiText_DrawCharacterAtOffsetFar(MsgDjinnAllStandby,
973 menu->helpWindow, 0, 0);
974 }
975 if (Djinn_IsReadyFar(DJINN_OWNER(djinn), DJINN_ELEMENT(djinn),
976 DJINN_NUMBER(djinn)) ||
978 DJINN_NUMBER(djinn))) {
979 if (Djinn_IsReadyFar(DJINN_OWNER(djinn), DJINN_ELEMENT(djinn),
980 DJINN_NUMBER(djinn)))
982 else
984 FourObjectMotion_SetSlotPosition(mode, ownerColumn * 56 + 48, 62,
985 0);
986 } else {
987 UiText_DrawCharacterAtOffsetFar(MsgDjinnRecovering,
988 menu->helpWindow, 0, 16);
990 FourObjectMotion_SetSlotPosition(mode, ownerColumn * 56 + 48, 62,
991 1);
992 }
993 if (refresh & 2)
995 } else {
996 UiText_DrawCharacterAtOffsetFar(MsgDjinnChoose, menu->helpWindow, 0,
997 0);
998 if (Djinn_IsReadyFar(DJINN_OWNER(djinn), DJINN_ELEMENT(djinn),
999 DJINN_NUMBER(djinn)) ||
1001 DJINN_NUMBER(djinn))) {
1002 if (Djinn_IsReadyFar(DJINN_OWNER(djinn), DJINN_ELEMENT(djinn),
1003 DJINN_NUMBER(djinn))) {
1004 UiText_DrawCharacterAtOffsetFar(MsgDjinnChoose + 3,
1005 menu->helpWindow, 0, 16);
1007 } else {
1008 UiText_DrawCharacterAtOffsetFar(MsgDjinnChoose + 2,
1009 menu->helpWindow, 0, 16);
1011 }
1012 FourObjectMotion_SetSlotPosition(mode, ownerColumn * 56 + 48, 62,
1013 0);
1014 } else {
1015 UiText_DrawCharacterAtOffsetFar(MsgDjinnChoose + 4,
1016 menu->helpWindow, 0, 16);
1018 FourObjectMotion_SetSlotPosition(mode, ownerColumn * 56 + 48, 62,
1019 1);
1020 }
1021 if (refresh & 2)
1023 }
1024 } else {
1025 if (Djinn_IsReadyFar(DJINN_OWNER(djinn), DJINN_ELEMENT(djinn),
1026 DJINN_NUMBER(djinn)) ||
1028 DJINN_NUMBER(djinn))) {
1029 if (Djinn_IsReadyFar(DJINN_OWNER(djinn), DJINN_ELEMENT(djinn),
1030 DJINN_NUMBER(djinn)))
1032 else
1034 FourObjectMotion_SetSlotPosition(mode, ownerColumn * 56 + 48, 54, 0);
1035 } else {
1037 FourObjectMotion_SetSlotPosition(mode, ownerColumn * 56 + 48, 54, 1);
1038 }
1039 if (refresh & 2)
1041 }
1043 if (selectedRow != -1) {
1044 UiText_DrawCharacterAtOffsetFar(MsgUnleashEffect, menu->listWindow, 0,
1045 80);
1046#if TBS_PATCH_1
1047 UiWindow_ClearInteriorTilesFar(menu->listWindow, 0, 96, 224, 104);
1049 DJINN_ELEMENT(djinn) * 20 + DJINN_NUMBER(djinn) + MsgDjinnEffect,
1050 menu->listWindow, 0, 96);
1051#else
1053 MsgDjinnEffect,
1054 menu->listWindow, 0, 96);
1055#endif
1056 }
1057 if (!(columnFlags[ownerColumn] & 1))
1059 ownerColumn * 7 + 1, djinnRow + 2,
1060 DJINN_CURSOR_WIDTH, 1, 14);
1061 ((struct UiWork *)gWindowWork[0])->dirty = 1;
1062 }
1063 if (columnFlags[ownerColumn] & 1)
1064 UiMenu_PositionCursor(ownerColumn * 56 - 8, 52);
1065 else
1066 UiMenu_PositionCursor(ownerColumn * 56 - 8, djinnRow * 8 + 60);
1067 WaitFrames(1);
1068 if (!(gKeysHeld & KEY_R) || (gKeysPressedLatch & 0x100)) {
1069 if (groupMode)
1070 redraw = 1;
1071 groupMode = 0;
1072 setAll = 0;
1073 }
1074 repeat = gKeysRepeat;
1075 pressed = gKeysPressed;
1076 tutorialStep = backdrop->tutorialStep;
1077 if (tutorialStep != 0) {
1078 pressed = 0;
1079 backdrop->tutorialTimer++;
1080 repeat = 0;
1081 switch (tutorialStep) {
1082 case 28:
1083 while (!(gKeysPressed & KEY_A)) {
1084 UiMenu_PositionCursor(150, 26);
1085 WaitFrames(1);
1086 }
1087 pressed = 2;
1088 repeat = 2;
1089 break;
1090 case 27:
1091 if (backdrop->tutorialTimer == 60) {
1092 messageWindow =
1093 UiText_OpenMessageWindowFar(MsgDjinnTutorialRecovery, 9, 9, 1);
1095 while (UiWork_IsCompleteFar() == 0)
1096 WaitFrames(1);
1097 UiWork_FinalizeFar(messageWindow, 1);
1098 DjinnMenu_DrawElementList(&backdrop->list);
1099 WaitFrames(1);
1100 messageWindow =
1101 UiText_OpenMessageWindowFar(MsgDjinnTutorialSetAgain, 9, 9, 1);
1103 while (UiWork_IsCompleteFar() == 0)
1104 WaitFrames(1);
1105 UiWork_FinalizeFar(messageWindow, 1);
1106 DjinnMenu_DrawElementList(&backdrop->list);
1107 backdrop->tutorialTimer = 0;
1111 Djinn_DeactivateFar(0, 0, 0);
1113 UnitCalcFar(0);
1114 repeat = 2;
1115 pressed = 2;
1116 }
1117 break;
1118 case 1:
1119 if (backdrop->tutorialTimer == 60) {
1120 messageWindow =
1121 UiText_OpenMessageWindowFar(MsgDjinnTutorialGive, 9, 9, 1);
1123 while (UiWork_IsCompleteFar() == 0)
1124 WaitFrames(1);
1125 UiWork_FinalizeFar(messageWindow, 1);
1126 DjinnMenu_DrawElementList(&backdrop->list);
1127 backdrop->tutorialTimer = 0;
1128 backdrop->tutorialStep = 2;
1129 }
1130 break;
1131 case 2:
1132 case 4:
1133 case 8:
1134 case 9:
1135 case 22:
1136 if (backdrop->tutorialTimer == 90) {
1137 repeat = 1;
1138 pressed = 1;
1139 backdrop->tutorialTimer = 0;
1140 backdrop->tutorialStep++;
1141 }
1142 break;
1143 case 3:
1144 if (backdrop->tutorialTimer == 90) {
1145 repeat = 16;
1146 pressed = 16;
1147 backdrop->tutorialTimer = 0;
1148 backdrop->tutorialStep = 4;
1149 }
1150 break;
1151 case 6:
1152 case 7:
1153 if (backdrop->tutorialTimer == 60) {
1154 messageWindow = UiText_OpenMessageWindowFar(
1155 MsgDjinnTutorialSetAfterGive, 9, 9, 1);
1157 while (UiWork_IsCompleteFar() == 0)
1158 WaitFrames(1);
1159 UiWork_FinalizeFar(messageWindow, 1);
1160 DjinnMenu_DrawElementList(&backdrop->list);
1161 backdrop->tutorialTimer = 0;
1162 backdrop->tutorialStep = 8;
1163 }
1164 break;
1165 case 13:
1166 if (backdrop->tutorialTimer == 40) {
1167 backdrop->tutorialTimer = 0;
1168 repeat = 2;
1169 pressed = 2;
1170 backdrop->tutorialStep++;
1171 }
1172 break;
1173 case 14:
1174 case 16:
1175 case 17:
1176 if (backdrop->tutorialTimer == 40) {
1177 backdrop->tutorialTimer = 0;
1178 backdrop->tutorialStep++;
1179 }
1180 break;
1181 case 15:
1182 if (backdrop->tutorialTimer == 60) {
1184 messageWindow =
1185 UiText_OpenMessageWindowFar(MsgDjinnTutorialPowers, 9, 9, 1);
1186 UiMenu_SlideCursor(2, 146);
1187 while (UiWork_IsCompleteFar() == 0)
1188 WaitFrames(1);
1189 while (!(gKeysPressed & KEY_A)) {
1190 UiMenu_PositionCursor(2, 146);
1191 WaitFrames(1);
1192 }
1193 UiWork_FinalizeFar(messageWindow, 1);
1194 DjinnMenu_DrawElementList(&backdrop->list);
1195 WaitFrames(1);
1196 messageWindow =
1197 UiText_OpenMessageWindowFar(MsgDjinnTutorialUnleash, 9, 9, 1);
1198 while (UiWork_IsCompleteFar() == 0)
1199 WaitFrames(1);
1200 while (!(gKeysPressed & KEY_A)) {
1201 UiMenu_PositionCursor(2, 146);
1202 WaitFrames(1);
1203 }
1204 UiWork_FinalizeFar(messageWindow, 1);
1205 DjinnMenu_DrawElementList(&backdrop->list);
1206 WaitFrames(1);
1207 messageWindow =
1208 UiText_OpenMessageWindowFar(MsgDjinnTutorialDemonstrate, 9, 9, 1);
1209 while (UiWork_IsCompleteFar() == 0)
1210 WaitFrames(1);
1211 while (!(gKeysPressed & KEY_A)) {
1212 UiMenu_PositionCursor(2, 146);
1213 WaitFrames(1);
1214 }
1215 UiWork_FinalizeFar(messageWindow, 1);
1216 DjinnMenu_DrawElementList(&backdrop->list);
1217 WaitFrames(1);
1218 backdrop->tutorialTimer = 0;
1219 backdrop->tutorialStep = 16;
1220 }
1221 break;
1222 case 18:
1223 case 20:
1224 if (backdrop->tutorialTimer == 90) {
1225 repeat = 1;
1226 pressed = 1;
1227 backdrop->tutorialTimer = 0;
1228 backdrop->tutorialStep = 21;
1229 }
1230 break;
1231 case 21:
1232 if (backdrop->tutorialTimer == 90) {
1233 backdrop->tutorialTimer = 0;
1234 repeat = 32;
1235 pressed = 32;
1236 backdrop->tutorialStep = 22;
1237 }
1238 break;
1239 case 24:
1240 if (backdrop->tutorialTimer == 60) {
1241 backdrop->tutorialTimer = 0;
1242 backdrop->tutorialStep = 25;
1243 repeat = 2;
1244 pressed = 2;
1245 }
1246 break;
1247 }
1248 }
1249 if (mode == 0 && (pressed & KEY_R)) {
1250 if (selectedRow == -1) {
1252 continue;
1253 }
1254 i = 0;
1255 if (Djinn_IsReadyFar(DJINN_OWNER(djinn), DJINN_ELEMENT(djinn),
1256 DJINN_NUMBER(djinn)) ||
1258 DJINN_NUMBER(djinn)))
1259 i = 1;
1260 groupMode = 1;
1262 if (i == 0) {
1265 UiWindow_ClearInteriorTilesFar(menu->listWindow, 0, 80, 216, 104);
1266 UiText_DrawResourceFar(MsgDjinnNowRecovering, menu->listWindow, 0, 96);
1267 redraw = 1;
1268 continue;
1269 }
1270 if (djinn & DJINN_ENTRY_IS_SET) {
1273 DJINN_NUMBER(djinn));
1275 DJINN_NUMBER(djinn));
1276 } else {
1279 DJINN_NUMBER(djinn));
1281 DJINN_NUMBER(djinn));
1282 }
1283 UnitCalcFar(DJINN_OWNER(djinn));
1284 DjinnMenu_DrawElementList(&backdrop->list);
1285 redraw = 1;
1286 }
1287 if (mode == 0 && (pressed & KEY_L)) {
1288 result = 7;
1290 break;
1291 }
1292 if ((pressed & KEY_A) || (mode == 1 && (pressed & KEY_R))) {
1293 i = 1;
1294 if (!(columnFlags[ownerColumn] & 1)) {
1295 if (selectedRow == -1) {
1297 continue;
1298 }
1299 i = 0;
1300 if (Djinn_IsReadyFar(DJINN_OWNER(djinn), DJINN_ELEMENT(djinn),
1301 DJINN_NUMBER(djinn)) ||
1303 DJINN_NUMBER(djinn)))
1304 i = 1;
1305 }
1306 if (i == 0) {
1309 UiWindow_ClearInteriorTilesFar(menu->listWindow, 0, 80, 216, 104);
1310 UiText_DrawResourceFar(MsgDjinnNowRecovering, menu->listWindow, 0, 96);
1311 continue;
1312 }
1313 if (mode == 1) {
1314 if (columnFlags[ownerColumn] & 1) {
1315 if (ownerColumn == menu->selectedColumn[0]) {
1316 if (menu->pairEntries[0] & DJINN_ENTRY_IS_SET)
1317 result = 2;
1318 else
1319 result = 1;
1320 } else {
1321 result = 3;
1322 }
1323 } else {
1324 result = 4;
1325 }
1326 } else {
1327 result = 1;
1328 }
1330 break;
1331 }
1332 if (pressed & KEY_START) {
1334 result = -2;
1335 break;
1336 }
1337 if (pressed & KEY_B) {
1339 result = -1;
1340 break;
1341 }
1342 if (mode == 0 && (pressed & KEY_SELECT)) {
1343 if (groupMode) {
1344 setAll ^= 1;
1345 if (setAll)
1347 else
1349 for (i = 0; i < menu->ownerCount; i++) {
1350 for (j = 0; j < backdrop->list.counts[i]; j++) {
1351 u32 entry = backdrop->list.ids[i][j];
1352 s32 usable;
1353 usable = 0;
1354 if (Djinn_IsReadyFar(DJINN_OWNER(entry), DJINN_ELEMENT(entry),
1355 DJINN_NUMBER(entry)) ||
1357 DJINN_NUMBER(entry)))
1358 usable = 1;
1359 if (usable) {
1360 if (setAll) {
1361 if (!(entry & DJINN_ENTRY_IS_SET)) {
1363 DJINN_NUMBER(entry));
1365 DJINN_ELEMENT(entry),
1366 DJINN_NUMBER(entry));
1367 UnitCalcFar(DJINN_OWNER(entry));
1368 }
1369 } else if (entry & DJINN_ENTRY_IS_SET) {
1371 DJINN_NUMBER(entry));
1373 DJINN_ELEMENT(entry),
1374 DJINN_NUMBER(entry));
1375 UnitCalcFar(DJINN_OWNER(entry));
1376 }
1377 }
1378 }
1379 }
1380 DjinnMenu_DrawElementList(&backdrop->list);
1381 redraw = 1;
1382 } else {
1383 result = 10;
1385 ownerColumn * 7 + 1, djinnRow + 2,
1386 DJINN_CURSOR_WIDTH, 1, 15);
1388 break;
1389 }
1390 }
1391 if (repeat & KEY_UP) {
1393 if (columnFlags[ownerColumn] & 4)
1394 continue;
1395 UiWindow_SetInteriorPaletteBitRect(menu->listWindow, ownerColumn * 7 + 1,
1396 djinnRow + 2, DJINN_CURSOR_WIDTH, 1,
1397 15);
1398 if (columnFlags[ownerColumn] & 4)
1399 continue;
1400 if (columnFlags[ownerColumn] & 1) {
1401 columnFlags[ownerColumn] &= ~1;
1402 djinnRow = 0;
1403 } else if (djinnRow == 0 && (columnFlags[ownerColumn] & 2)) {
1404 columnFlags[ownerColumn] |= 1;
1405 redraw = 2;
1406 continue;
1407 }
1408 djinnRow--;
1409 count = backdrop->list.counts[ownerColumn];
1410 if (count == 0)
1411 count = 1;
1412 djinnRow = Menu_WrapIndex(djinnRow, count);
1413 savedRow = djinnRow;
1414 redraw = 2;
1415 continue;
1416 }
1417 if (repeat & KEY_DOWN) {
1419 if (columnFlags[ownerColumn] & 4)
1420 continue;
1421 UiWindow_SetInteriorPaletteBitRect(menu->listWindow, ownerColumn * 7 + 1,
1422 djinnRow + 2, DJINN_CURSOR_WIDTH, 1,
1423 15);
1424 djinnRow++;
1425 count = backdrop->list.counts[ownerColumn];
1426 if (count == 0)
1427 count = 1;
1428 djinnRow = Menu_WrapIndex(djinnRow, count);
1429 if ((columnFlags[ownerColumn] & 1) && !(columnFlags[ownerColumn] & 4)) {
1430 columnFlags[ownerColumn] &= ~1;
1431 djinnRow = 0;
1432 } else if (djinnRow == 0 && (columnFlags[ownerColumn] & 2)) {
1433 columnFlags[ownerColumn] |= 1;
1434 }
1435 savedRow = djinnRow;
1436 redraw = 2;
1437 continue;
1438 }
1439 if (repeat & KEY_LEFT) {
1441 if (!(columnFlags[ownerColumn] & 4))
1443 ownerColumn * 7 + 1, djinnRow + 2,
1444 DJINN_CURSOR_WIDTH, 1, 15);
1445 ownerColumn--;
1446 ownerColumn = Menu_WrapIndex(ownerColumn, menu->ownerCount);
1447 if (mode == 0) {
1448 for (i = 0; i < menu->ownerCount; i++) {
1449 if (columnFlags[ownerColumn] == 4) {
1450 ownerColumn--;
1451 ownerColumn = Menu_WrapIndex(ownerColumn, menu->ownerCount);
1452 }
1453 }
1454 }
1455 djinnRow = savedRow;
1456 count = backdrop->list.counts[ownerColumn];
1457 if (count == 0)
1458 count = 1;
1459 djinnRow = Menu_WrapIndex(djinnRow, count);
1460 redraw = 2;
1461 continue;
1462 }
1463 if (repeat & KEY_RIGHT) {
1465 if (!(columnFlags[ownerColumn] & 4))
1467 ownerColumn * 7 + 1, djinnRow + 2,
1468 DJINN_CURSOR_WIDTH, 1, 15);
1469 ownerColumn++;
1470 ownerColumn = Menu_WrapIndex(ownerColumn, menu->ownerCount);
1471 if (mode == 0) {
1472 for (i = 0; i < menu->ownerCount; i++) {
1473 if (columnFlags[ownerColumn] == 4) {
1474 ownerColumn++;
1475 ownerColumn = Menu_WrapIndex(ownerColumn, menu->ownerCount);
1476 }
1477 }
1478 }
1479 djinnRow = savedRow;
1480 count = backdrop->list.counts[ownerColumn];
1481 if (count == 0)
1482 count = 1;
1483 djinnRow = Menu_WrapIndex(djinnRow, count);
1484 redraw = 2;
1485 }
1486 }
1487 menu->selectedColumn[mode] = ownerColumn;
1488 if (selectedRow != -1) {
1489 u32 entry;
1490 menu->pairEntries[mode] = entry =
1491 backdrop->list.ids[ownerColumn][selectedRow];
1492 menu->pairIndex[mode] = entry % 32;
1493 menu->pairElement[mode] = DJINN_ELEMENT(entry);
1494 menu->pairOwner[mode] = DJINN_OWNER(entry);
1495 /* FAKEMATCH(barrier): an empty asm keeps entry live past the owner's
1496 * extraction, so the owner mask keeps its register; without it, 48 of
1497 * 2058 instructions differ in tbs-en. */
1498 asm("" : "+r"(result) : "r"(entry));
1499 }
1500 menu->selection[mode] = ownerColumn + djinnRow * 10;
1501 return result;
1502}
1503
1504/// Lists owned Djinn by element and index, marking those that are set.
1505/// For element -1, entries also encode their owner.
1506s32 Djinn_ListOwnerEntries(u16 *entriesOut, s32 ownerId, s32 element) {
1507 struct BattleUnit *unit = UnitGetFar(ownerId);
1508 s32 count = 0;
1509 s32 elementIndex;
1510 s32 djinnIndex;
1511 s32 encodedDjinn;
1512
1513 if (element == -1) {
1514 for (elementIndex = 0; elementIndex < 4; elementIndex++) {
1515 for (djinnIndex = 0; djinnIndex < 20; djinnIndex++) {
1516 if (unit->djinnActive[elementIndex] & (1 << djinnIndex)) {
1517 encodedDjinn = (elementIndex << 5) | djinnIndex | DJINN_ENTRY_SET;
1518 encodedDjinn |= ownerId << 8;
1519 entriesOut[count++] = encodedDjinn;
1520 } else if (unit->djinnAvailable[elementIndex] & (1 << djinnIndex)) {
1521 entriesOut[count++] =
1522 (elementIndex << 5) | djinnIndex | (ownerId << 8);
1523 }
1524 }
1525 }
1526 } else {
1527 for (djinnIndex = 0; djinnIndex < 20; djinnIndex++) {
1528 if (unit->djinnActive[element] & (1 << djinnIndex))
1529 entriesOut[count++] = (element << 5) | djinnIndex | DJINN_ENTRY_SET;
1530 else if (unit->djinnAvailable[element] & (1 << djinnIndex))
1531 entriesOut[count++] = (element << 5) | djinnIndex;
1532 }
1533 }
1534 return count;
1535}
1536
1537/// Draws both sides of the give or trade preview for the selected page.
1539 struct DjinnMenuWork *menu;
1540
1541 menu = gMenuWork;
1542 if (mode == DJINN_COMPARE_TRADE) {
1543 DjinnMenu_DrawStatPreview(menu->secondWindow, 0, 0, menu->pairOwner[1], 1,
1544 mode, 2, pageIndex, 1);
1545 DjinnMenu_DrawStatPreview(menu->window, 0, 0, menu->pairOwner[0], mode, 1,
1546 2, pageIndex, mode);
1547 } else {
1548 DjinnMenu_DrawStatPreview(menu->secondWindow, 0, 0, menu->shownOwner[1], 1,
1549 0, DJINN_SWAP_PREVIEW_MODE, pageIndex, 1);
1550 DjinnMenu_DrawStatPreview(menu->window, 0, 0, menu->shownOwner[0], 0, 0, 1,
1551 pageIndex, 0);
1552 }
1553 return 1;
1554}
1555
1556/// Copies a full unit for a temporary Djinn-stat preview.
1557static __inline__ void Unit_Copy(struct BattleUnit *destination,
1558 struct BattleUnit *source) {
1559 Iwram_CopyWords(destination, source, sizeof(struct BattleUnit));
1560}
1561
1562/// Saves the unit, applies a hypothetical Djinn change, draws its differences
1563/// and restores the original unit before returning.
1565 s32 ownerId, s32 removePairSlot, s32 addPairSlot,
1566 s32 previewMode, s32 page, s32 side) {
1567 struct BattleUnit *unit;
1568 struct BattleUnit *originalUnit;
1569 s32 giveElement;
1570 s32 giveIndex;
1571 s32 giveSet;
1572 s32 takeElement;
1573 s32 takeIndex;
1574 s32 takeSet;
1575 s32 lost;
1576 s32 gained;
1577 u16 actions[48];
1578 struct DjinnMenuWork *menu;
1579
1580 unit = UnitGetFar(ownerId);
1581 menu = gMenuWork;
1582 giveElement = menu->pairElement[removePairSlot];
1583 giveIndex = menu->pairIndex[removePairSlot];
1584 giveSet = menu->pairEntries[removePairSlot] & 0x8000;
1585 takeElement = menu->pairElement[addPairSlot];
1586 takeIndex = menu->pairIndex[addPairSlot];
1587 takeSet = menu->pairEntries[addPairSlot] & 0x8000;
1588 originalUnit = MemAlloc(sizeof(struct BattleUnit));
1589 Unit_Copy(originalUnit, unit);
1590
1591 if (page == 0) {
1592 if (previewMode == 3) {
1594 x * 8 + DJINN_PREVIEW_MAX_X, y * 8 + 56);
1596 x * 8 + DJINN_PREVIEW_MAX_X, y * 8 + 64);
1598 x * 8 + DJINN_PREVIEW_CURRENT_X, y * 8 + 56);
1600 x * 8 + DJINN_PREVIEW_CURRENT_X, y * 8 + 64);
1602 x * 8 + DJINN_PREVIEW_SLASH_X, y * 8 + 56);
1604 x * 8 + DJINN_PREVIEW_SLASH_X, y * 8 + 64);
1605 } else {
1607 x * 8 + DJINN_PREVIEW_CURRENT_X, y * 8 + 56);
1609 x * 8 + DJINN_PREVIEW_CURRENT_X, y * 8 + 64);
1610 }
1612 x * 8 + DJINN_PREVIEW_CURRENT_X, y * 8 + 72);
1614 x * 8 + DJINN_PREVIEW_CURRENT_X, y * 8 + 80);
1616 x * 8 + DJINN_PREVIEW_CURRENT_X, y * 8 + 88);
1618 x * 8 + DJINN_PREVIEW_LUCK_X, y * 8 + 96);
1619 }
1620
1621 // Only the temporary unit changes; the saved record is restored below.
1622 switch (previewMode) {
1623 case 0:
1624 Djinn_AddToOwnerFar(ownerId, takeElement, takeIndex & 31);
1625 Djinn_ActivateFar(ownerId, takeElement, takeIndex & 31);
1626 break;
1627 case 1:
1628 giveIndex &= 31;
1629 Djinn_DeactivateFar(ownerId, giveElement, giveIndex);
1630 break;
1631 case 2:
1632 if (giveSet) {
1633 giveIndex &= 31;
1634 Djinn_DeactivateFar(ownerId, giveElement, giveIndex);
1635 }
1636 Djinn_AddToOwnerFar(ownerId, takeElement, takeIndex & 31);
1637 if (takeSet)
1638 Djinn_ActivateFar(ownerId, takeElement, takeIndex & 31);
1639 break;
1640 case 4:
1641 Djinn_AddToOwnerFar(ownerId, takeElement, takeIndex & 31);
1642 if (takeSet)
1643 Djinn_ActivateFar(ownerId, takeElement, takeIndex & 31);
1644 break;
1645 }
1646
1647 UnitCalcFar(ownerId);
1648 unit = UnitGetFar(ownerId);
1649
1650 if (page == 0) {
1651 s32 label;
1652
1653 UiText_DrawStringAtOffsetFar(unit->name, window, x * 8 + 40, y * 8);
1655 y * 8 + 16);
1656 UiText_DrawNumberInWindowFar(unit->level, 2, window, x * 8 + 88,
1657 y * 8 + 16);
1658 label = MsgPreviewStatLabel;
1659 UiText_DrawCharacterAtOffsetFar(label, window, x * 8, y * 8 + 56);
1660 UiText_DrawCharacterAtOffsetFar(label + 1, window, x * 8, y * 8 + 64);
1661 UiText_DrawCharacterAtOffsetFar(label + 2, window, x * 8, y * 8 + 72);
1662 UiText_DrawCharacterAtOffsetFar(label + 3, window, x * 8, y * 8 + 80);
1663 UiText_DrawCharacterAtOffsetFar(label + 4, window, x * 8, y * 8 + 88);
1664 UiText_DrawCharacterAtOffsetFar(label + 5, window, x * 8, y * 8 + 96);
1665 UiText_DrawCharacterAtOffsetFar(MsgClassName + originalUnit->classIndex,
1666 window, x * 8, y * 8 + 32);
1667 }
1668
1669 {
1670 s32 i = 0;
1671
1672 if (page == 0) {
1673 s32 column;
1674#if TBS_PATCH_1
1675 s32 iconX;
1676#endif
1677 s32 px;
1678
1679 if (originalUnit->classIndex != unit->classIndex) {
1680 px = x * 8;
1682 px, y * 8 + 48);
1683 UiWindow_SetTilemapEntryFar(window, 0xf296, x + 2, 5, 0);
1684 }
1685 column = x;
1686 if (originalUnit->classIndex != unit->classIndex)
1687 column += 5;
1688 for (i = 0; i < 4; i++) {
1690 column + i * 2, y + 5, 0);
1692 column + i * 2 + 1, y + 5, 0);
1693 }
1694#if TBS_PATCH_1
1695 iconX = x * 8 + 70;
1696#endif
1697 if (unit->hp != originalUnit->hp) {
1698 UiText_DrawNumberInWindowFar(unit->hp, 4, window, x * 8 + 72,
1699 y * 8 + 56);
1700 if (unit->hp > originalUnit->hp)
1702 window, DJINN_PREVIEW_ARROW_X(x, iconX), y * 8 + 56, 0);
1703 else
1705 window, DJINN_PREVIEW_ARROW_X(x, iconX), y * 8 + 56, 1);
1706 }
1707 if (unit->pp != originalUnit->pp) {
1708 UiText_DrawNumberInWindowFar(unit->pp, 4, window, x * 8 + 72,
1709 y * 8 + 64);
1710 if (unit->pp > originalUnit->pp)
1712 window, DJINN_PREVIEW_ARROW_X(x, iconX), y * 8 + 64, 0);
1713 else
1715 window, DJINN_PREVIEW_ARROW_X(x, iconX), y * 8 + 64, 1);
1716 }
1717 if (unit->atk != originalUnit->atk) {
1718 UiText_DrawNumberInWindowFar(unit->atk, 4, window, x * 8 + 72,
1719 y * 8 + 72);
1720 if (unit->atk > originalUnit->atk)
1722 window, DJINN_PREVIEW_ARROW_X(x, iconX), y * 8 + 72, 0);
1723 else
1725 window, DJINN_PREVIEW_ARROW_X(x, iconX), y * 8 + 72, 1);
1726 }
1727 if (unit->def != originalUnit->def) {
1728 UiText_DrawNumberInWindowFar(unit->def, 4, window, x * 8 + 72,
1729 y * 8 + 80);
1730 if (unit->def > originalUnit->def)
1732 window, DJINN_PREVIEW_ARROW_X(x, iconX), y * 8 + 80, 0);
1733 else
1735 window, DJINN_PREVIEW_ARROW_X(x, iconX), y * 8 + 80, 1);
1736 }
1737 if (unit->agi != originalUnit->agi) {
1738 UiText_DrawNumberInWindowFar(unit->agi, 4, window, x * 8 + 72,
1739 y * 8 + 88);
1740 if (unit->agi > originalUnit->agi)
1742 window, DJINN_PREVIEW_ARROW_X(x, iconX), y * 8 + 88, 0);
1743 else
1745 window, DJINN_PREVIEW_ARROW_X(x, iconX), y * 8 + 88, 1);
1746 }
1747 if (unit->luck != originalUnit->luck) {
1748 UiText_DrawNumberInWindowFar(unit->luck, 2, window, x * 8 + 88,
1749 y * 8 + 96);
1750 if (unit->luck > originalUnit->luck)
1752 window, DJINN_PREVIEW_ARROW_X(x, iconX), y * 8 + 96, 0);
1753 else
1755 window, DJINN_PREVIEW_ARROW_X(x, iconX), y * 8 + 96, 1);
1756 }
1757 }
1758 }
1759
1760 if (page > 0) {
1761 s32 rows;
1762 s32 first;
1763 s8 count;
1764 s8 row;
1765 s8 line;
1766
1767 rows = 6 - (previewMode != 3);
1768 first = rows * (page - 1);
1769 count = OwnerAction_DiffSlots(originalUnit->actionSlots, unit->actionSlots,
1770 actions, &gained, &lost);
1771 line = 0;
1772 for (row = 0; first < count && row < rows; row++, first++) {
1773 UiIcon_CreateWithLoadedResource(window, x * 8, (y + line * 2) * 8 + 4,
1774 actions[first] & OWNER_ACTION_ID_MASK);
1775 if (actions[first] & 0x8000)
1777 else if (actions[first] & 0x4000)
1779 else
1782 MsgAbilityName + (actions[first] & OWNER_ACTION_ID_MASK), window,
1783 x * 8 + 16, (y + line * 2) * 8 + 8);
1784 UiText_DrawNumberAtOffsetFar(BattleActGet(actions[first])->ppCost, 2,
1785 window, x * 8 + 88, (y + line * 2) * 8 + 8);
1786 line++;
1787 }
1790 x * 8 + DJINN_PREVIEW_PP_X, y * 8);
1791 if (previewMode != 3) {
1792 s32 lines;
1793
1794 lines = 0;
1795 if (gained) {
1797 UiText_DrawCharacterAtOffsetFar(MsgPsynergyGained, window, x * 8,
1798 y * 8 + 88);
1799 lines = 1;
1800 }
1801 if (lost) {
1803 UiText_DrawCharacterAtOffsetFar(MsgPsynergyLost, window, x * 8,
1804 (y + lines) * 8 + 88);
1805 lines++;
1806 }
1807 if (lines == 0)
1808 UiText_DrawCharacterAtOffsetFar(MsgPsynergyUnchanged, window, x * 8,
1809 y * 8 + 88);
1811 UiWindow_DrawDividerLineFar(window, 0, 11, 13, 11);
1812 }
1813 ((struct UiWork *)gWindowWork[0])->dirty = 1;
1814 }
1815
1816 if (page == 0)
1817 SideObject_CreateFar(ownerId, 0, side, window, 0, 0);
1818 // None of the preview's class, stat or action changes escape this call.
1819 Unit_Copy(unit, originalUnit);
1820 MemFree(originalUnit);
1821 return 1;
1822}
1823
1824#undef DJINN_CURSOR_WIDTH
1825#undef DJINN_SWAP_PREVIEW_MODE
1826#undef DJINN_PREVIEW_DIGITS
1827#undef DJINN_PREVIEW_CURRENT_X
1828#undef DJINN_PREVIEW_MAX_X
1829#undef DJINN_PREVIEW_SLASH_X
1830#undef DJINN_PREVIEW_LUCK_X
1831#undef DJINN_PREVIEW_ARROW_X
1832#undef DJINN_PREVIEW_PP_X
1833#undef DJINN_RESELECT_PAIR_ENTRY
1834#undef DJINN_BACKDROP_FRAME_TILE
1835#undef DJINN_PREVIEW_GAINED
1836#undef DJINN_PREVIEW_LOST
1837#undef DJINN_ELEMENT_TILE
1838#undef DJINN_ENTRY_SET
1839#undef DJINN_OWNER
1840#undef DJINN_ELEMENT
1841#undef DJINN_NUMBER
#define DJINN_PER_ELEMENT
@ 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 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 Menu_UpdateEntryObjectTransforms(void)
Scheduler callback: each frame, places every party member sprite created by PsynergyMenu_InitializeEn...
Definition common.c:580
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
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
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
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
void FourObjectMotion_ClearSlotsAndScheduleAlt(void)
s32 FourObjectMotion_ReplaceSlot(s32 index, s32 resourceKind, s32 value)
Replaces one displayed object and selects its animation.
void FourObjectMotion_InitializeBottomRow(s32 unused0, s32 unused1)
Replaces the bottom row's four objects and starts its easing task.
s32 FourObjectMotion_SetSlotPosition(s32 index, s32 x, s32 y, s32 negative)
Updates one object's saved position and its signed y marker.
s32 FourObjectMotion_SetSlotPhase(s32 index, s32 phase)
#define DJINN_ENTRY_OWNER
Definition djinn_menu.h:14
#define DJINN_LIST_ROWS
Definition djinn_menu.h:20
#define DJINN_ENTRY_ELEMENT
Definition djinn_menu.h:13
#define DJINN_ENTRY_INDEX
Definition djinn_menu.h:12
#define DJINN_ENTRY_IS_SET
Definition djinn_menu.h:15
#define DJINN_ELEMENTS
Definition djinn_menu.h:17
static __inline__ void Dma_Set(const volatile void *source, volatile void *destination, u32 control, volatile u32 *channel)
Starts a DMA transfer: stores the source, destination and control words into channel's registers with...
Definition dma.h:62
s32 DjinnRecovery_TickFar(void)
struct BattleUnit * UnitGetFar(u32 owner)
s32 Party_ListActiveOwnersFar(s16 *owners)
s32 GameFlag_TestFar(s32 flag)
u32 * DjinnRecovery_AddStandbyFar(u32 kind, u32 first, u32 second)
struct BattleAct * BattleActGet(s32 actionId)
Far call to BattleAction_GetDirect.
u32 Djinn_IsActiveFar(s32 owner, s32 index, s32 bit)
s32 Djinn_TransferFar(s32 source, s32 index, s32 bit, s32 target)
s32 DjinnRecovery_RemoveFar(s32 owner, s32 index, s32 bit)
u32 Djinn_DeactivateFar(s32 owner, s32 index, s32 bit)
s32 Djinn_AddToOwnerFar(s32 owner, s32 index, s32 bit)
s32 Djinn_IsReadyFar(s32 owner, s32 index, s32 bit)
s32 Djinn_ActivateFar(s32 owner, s32 index, s32 bit)
void UnitCalcFar(s32 owner)
void Event_ClearInvalidPackedValuesFar(void)
void AudioCommand_PlayFar(s32 id)
void RenderOutput_PrepareForRedrawFar(struct UiWindow *window)
struct UiWindow * UiWindow_CreateFar(s32 x, s32 y, s32 width, s32 height, s32 attrs)
void UiWindow_SetPaletteBitRectFar(s32 x, s32 y, s32 width, s32 height, s32 alt)
Far call to Ui_SetRectHighlight.
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 UiText_DrawNumberInWindowFar(s32 arg0, s32 arg1, struct UiWindow *arg2, s32 arg3, s32 arg4)
s32 UiText_OpenEntryMessageFar(struct UiWindow *window, s32 argument)
void UiWork_SetParamNibbleFar(s32 param)
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 Graphics_ExpandVramTilesByColorTableFar(u16 *dst)
void UiText_DrawResourceFar(s32 arg0, struct UiWindow *arg1, s32 arg2, s32 arg3)
void UiWork_FinalizeFar(struct UiWindow *work, s32 release)
void UiText_DrawStringAtOffsetFar(const u8 *text, const struct UiWindow *work, s32 offsetX, s32 offsetY)
void UiWork_PushValueSlotFar(u32 value, u32 kind)
s32 UiWork_IsCompleteFar(void)
void UiWork_SetAltFlagAndClearTableFar(s32 flag)
void UiWindow_SetTilemapEntryFar(struct UiWindow *window, s32 value, s32 x, s32 y, u32 mode)
void RenderOutput_RedrawSavedRectFar(struct UiWindow *window)
struct UiWindow * UiText_OpenMessageWindowFar(s32 message, s32 x, s32 y, u32 packed)
#define FLAG_DJINN_TUTORIAL
Definition flags.h:69
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_WINDOW
Definition heap_state.h:39
#define WORK_SLOT(n)
Reads slots through their own addresses; adjacent slots are reached by offsets.
Definition heap_state.h:14
#define BG_CHAR_BLOCK(n)
Definition io_reg.h:166
#define TILE_SIZE_4BPP
Definition io_reg.h:168
@ KEY_UP
Definition io_reg.h:249
@ KEY_B
Definition io_reg.h:244
@ KEY_SELECT
Definition io_reg.h:245
@ KEY_LEFT
Definition io_reg.h:248
@ KEY_START
Definition io_reg.h:246
@ KEY_RIGHT
Definition io_reg.h:247
@ KEY_R
Definition io_reg.h:251
@ KEY_A
Definition io_reg.h:243
@ KEY_DOWN
Definition io_reg.h:250
@ KEY_L
Definition io_reg.h:252
#define REG_DMA3
Definition io_reg.h:153
#define BG_PLTT
Definition io_reg.h:157
#define BG_PLTT_COLOR(palette, color)
Definition io_reg.h:158
#define DMA_ENABLE
Definition io_reg.h:217
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_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
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.
u32 gKeysPressedLatch
Presses since a reader last cleared it.
volatile u32 gKeysRepeat
Pressed keys, repeating while held: after 19 frames, then every 6.
s32 Palette_GetBasicObjColors(void)
Definition math.c:151
void Runtime_ReleaseHeapBlock(s32 slot)
void MemFree(void *buffer)
#define DJINN_CURSOR_WIDTH
Definition djinn.c:14
static __inline__ void Unit_Copy(struct BattleUnit *destination, struct BattleUnit *source)
Copies a full unit for a temporary Djinn-stat preview.
Definition djinn.c:1557
s32 Menu_WrapIndex(s32 value, s32 modulus)
Wraps a cursor index that has stepped one past either end of modulus entries: -1 becomes modulus - 1 ...
Definition djinn.c:47
s32 DjinnMenu_SelectDjinn(s32 mode)
Chooses an owner and Djinni, or a set, standby, give or trade action.
Definition djinn.c:830
s32 DjinnMenu_RunScreen(void)
Chooses a Djinni, previews changes, then sets, stands by, gives or trades it.
Definition djinn.c:181
void UiWindow_SetRectPalette(s32 x, s32 y, s32 width, s32 height, s32 palette)
Moves each tile of a screen rectangle (in tiles, clipped to the screen) that shows palette 15 to pale...
Definition djinn.c:660
s32 DjinnMenu_Run(void)
Runs the Djinn menu, preserving field tiles and the message speed.
Definition djinn.c:68
#define DJINN_NUMBER(v)
Definition djinn.c:826
void Graphics_AdjustPaletteBank(s32 brightnessDelta)
Writes copies of background palettes 15, 5 and 7, each brightnessDelta lighter in every channel (clam...
Definition djinn.c:401
void UiWindow_SetInteriorRectPalette(void *window, s32 x, s32 y, s32 width, s32 height, s32 palette)
UiWindow_SetRectPalette on a rectangle of window's interior, (x, y) and its size in tiles from the in...
Definition djinn.c:702
s32 Menu_SetFirstObjectRowCoordinates(s32 yOffset)
Places the Djinn menu's first row at its normal height plus yOffset.
Definition djinn.c:52
s32 DjinnMenu_ShowHelp(void)
Runs the Djinn help choices and restores the list when the player leaves.
Definition djinn.c:710
s32 DjinnMenu_DrawStatPreview(struct UiWindow *window, s32 x, s32 y, s32 ownerId, s32 removePairSlot, s32 addPairSlot, s32 previewMode, s32 page, s32 side)
Saves the unit, applies a hypothetical Djinn change, draws its differences and restores the original ...
Definition djinn.c:1564
#define DJINN_PREVIEW_LUCK_X
Definition djinn.c:32
MenuBackdropResult Menu_OpenBackdropScreen(void)
Draws the backdrop behind the Djinn menu's list: its window, tiles and palettes.
Definition djinn.c:462
#define DJINN_PREVIEW_DIGITS
Definition djinn.c:28
void DjinnMenu_DrawElementList(struct DjinnListTable *table)
Draws each owner's Djinn column, including set and recovering entries.
Definition djinn.c:583
s32 Djinn_ListOwnerEntries(u16 *entriesOut, s32 ownerId, s32 element)
Lists owned Djinn by element and index, marking those that are set.
Definition djinn.c:1506
#define DJINN_PREVIEW_SLASH_X
Definition djinn.c:31
DjinnMenuStep
The screen chooses an operation, optionally previews it, then commits it.
Definition djinn.c:159
@ DJINN_STEP_CONFIRM_SET
Definition djinn.c:165
@ DJINN_STEP_CONFIRM_GIVE
Definition djinn.c:167
@ DJINN_STEP_SELECT_SECOND
Definition djinn.c:168
@ DJINN_STEP_SELECT_ACTION
Definition djinn.c:163
@ DJINN_STEP_SHOW_STATUS
Definition djinn.c:170
@ DJINN_STEP_CONFIRM_TRADE
Definition djinn.c:169
@ DJINN_STEP_HANDLE_PAIR_RESULT
Definition djinn.c:164
@ DJINN_STEP_RESERVED
Definition djinn.c:161
@ DJINN_STEP_APPLY_TRADE
Definition djinn.c:174
@ DJINN_STEP_CONFIRM_STANDBY
Definition djinn.c:166
@ DJINN_STEP_APPLY_SET
Definition djinn.c:171
@ DJINN_STEP_HANDLE_RESULT
Definition djinn.c:160
@ DJINN_STEP_APPLY_GIVE
Definition djinn.c:173
@ DJINN_STEP_SELECT_DJINN
Definition djinn.c:162
@ DJINN_STEP_APPLY_STANDBY
Definition djinn.c:172
@ DJINN_STEP_SHOW_HELP
Definition djinn.c:175
#define DJINN_SWAP_PREVIEW_MODE
Definition djinn.c:20
#define DJINN_ENTRY_SET
Definition djinn.c:822
#define DJINN_OWNER(v)
Definition djinn.c:824
#define DJINN_PREVIEW_LOST
Definition djinn.c:458
s32 OwnerAction_DiffSlots(struct OwnerActionSlot *before, struct OwnerActionSlot *after, u16 *actionsOut, s32 *gainedCountOut, s32 *lostCountOut)
Lists the actions after a preview, marking gains, then appends the losses.
Definition djinn.c:495
#define DJINN_PREVIEW_MAX_X
Definition djinn.c:30
#define DJINN_PREVIEW_PP_X
Definition djinn.c:34
#define DJINN_PREVIEW_CURRENT_X
Definition djinn.c:29
s32 DjinnMenu_BuildLists(void *table)
Rebuilds the Djinn lists in table: each owner's packed Djinn entries and their count.
Definition djinn.c:548
#define DJINN_BACKDROP_FRAME_TILE
Definition djinn.c:455
#define DJINN_PREVIEW_GAINED
Definition djinn.c:457
#define DJINN_RESELECT_PAIR_ENTRY(menu, i)
Finds the moved Djinni in the list and selects its new position.
Definition djinn.c:140
s32 DjinnMenu_DrawPairPreview(s32 mode, s32 pageIndex)
Draws both sides of the give or trade preview for the selected page.
Definition djinn.c:1538
s32 UiWindow_SetInteriorPaletteBitRect(const struct UiWindow *window, s32 x, s32 y, s32 width, s32 height, s32 palette)
Sets the palette of a rectangle of window's interior, (x, y) and its size in tiles from the interior'...
Definition djinn.c:648
#define DJINN_PREVIEW_ARROW_X(x, iconX)
Definition djinn.c:33
#define DJINN_ELEMENT_TILE
The window map entry of the first element icon, in palette 5; the four elements follow it in order.
Definition djinn.c:580
s32 DjinnMenu_ShowOwnerStatus(void)
Shows the chosen owner's current stats and paged Psynergy list.
s32 Djinn_MarkBalancedEntries(s8 *requiresTrade, s32 sourceOwnerColumn)
Marks recipients that would leave unequal Djinn totals after a direct give.
s32 OwnerAction_RunCompareLoop(u32 mode)
Previews a give, trade, set or standby change without committing it.
s32 UiIcon_DrawVariantWithTileOffset(struct UiWindow *window, s32 x, s32 y, s32 variant)
Creates an arrow with the vertical adjustment for its resource variant.
Definition icons.c:97
void Resource_LoadPairedBlocksIfAvailable(void)
Loads each menu icon resource whose cache slot was acquired.
Definition icons.c:8
void Menu_ResetTwoResourceEntries(void)
Releases both cached icon resources used by the menu.
Definition icons.c:27
s32 UiIcon_CreateWithLoadedResource(struct UiWindow *window, s32 x, s32 y, s32 resourceId)
Loads an icon into a free cache slot and creates its sprite when possible.
Definition icons.c:51
const char gDjinnMenu_TextLevel[]
const char gDjinnMenu_TextSlash[]
const u8 gMenu_BackdropFrameTile[]
struct ObjectSystemWork * gMenuCtrlWork
What every part of the menu object shares: its includes, and the macros and types more than one part ...
#define MENU_WORK_SIZE
The bytes of the menu work, heap block HEAP_SLOT_MENU.
#define ICON_HIDDEN
#define ICON_SHOWN
RenderOutput.active as the menu sets it: shown, or hidden but kept.
#define TEXT_COLOR_NORMAL
@ DJINN_COMPARE_GIVE
@ DJINN_COMPARE_STANDBY
@ DJINN_COMPARE_TRADE
@ DJINN_COMPARE_SET
#define DJINN_ELEMENT(v)
Definition plan.c:85
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
#define SE_RECOVERY
Definition songs.h:119
#define SE_MENU_CANCEL
Definition songs.h:106
#define SE_MENU_CURSOR_MOVE
Definition songs.h:104
#define SE_139
Definition songs.h:132
#define SE_175
Definition songs.h:170
#define SE_MENU_ERROR
Definition songs.h:107
#define SE_MENU_CONFIRM
Definition songs.h:105
#define NULL
Definition bilibin.h:6
u8 gWindowWork[]
A unit in battle: a party member's or an enemy's stats, Psynergy, items, Djinn and ailments.
u8 luck
0 to 99 (UnitCalc)
u32 djinnActive[4]
The Djinn set, one bit per Djinni; only these add their stat bonuses.
s16 maxPp
0 to 1999 for a character, 9999 for an enemy (UnitCalc)
u8 djinnActiveCounts[4]
the Djinn set in each element; the class's element levels are read from these
u8 name[0x0f]
The name, one byte a character, ending in 0.
s16 hp
current HP, 0 when downed
struct BattleElementStats element[4]
Power and resistance in each element, 0 to 200, after equipment, element levels and Resistance stages...
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...
s16 maxHp
0 to 1999 for a character, 9999 for an enemy (UnitCalc)
u8 classIndex
The character's class, worked out from its Djinn (Unit_UpdateClass); 0 marks an enemy,...
u16 atk
Attack, 0 to 999 (UnitCalc).
u8 level
1 to 99 for a character
u16 agi
Agility, 0 to 999: the order of the round's actions.
u16 def
Defense, 0 to 999 (UnitCalc).
u32 djinnAvailable[4]
The Djinn held, one bit per Djinni (by its index) in each element's word.
The Djinn menu's lists: each party member's Djinn entries and their count.
Definition djinn_menu.h:23
u16 ids[DJINN_LIST_OWNERS][DJINN_LIST_ROWS]
Definition djinn_menu.h:24
s8 counts[DJINN_LIST_OWNERS]
Definition djinn_menu.h:25
The Djinn menu's lists, the field tiles and palette it restores on closing, and the tutorial's state.
Definition djinn_menu.h:30
u8 tiles[0x2000]
Definition djinn_menu.h:32
long tutorialStep
The Djinn tutorial's step: 0 outside it, else 1, 14, 27 or 28 to start, by flags 0x16f and 0x171.
Definition djinn_menu.h:37
struct DjinnListTable list
Definition djinn_menu.h:31
s32 tutorialTimer
frames into the tutorial's current step
Definition djinn_menu.h:34
The Djinn menu's work, in the HEAP_SLOT_MENU work slot.
Definition djinn_menu.h:41
struct UiWindow * listWindow
Definition djinn_menu.h:53
u16 pairEntries[2]
255 at first
Definition djinn_menu.h:62
struct UiWindow * secondWindow
Definition djinn_menu.h:54
struct DjinnMenuBackdrop * backdrop
Definition djinn_menu.h:65
u16 pending
bits: 1 a give or trade awaits its confirmation | 0 a second Djinni is to be chosen
Definition djinn_menu.h:74
u8 pairOwner[2]
not named by TBS code
Definition djinn_menu.h:83
struct RenderOutput * cursor
Definition djinn_menu.h:46
struct UiWindow * window
Definition djinn_menu.h:50
struct UiWindow * helpWindow
Definition djinn_menu.h:56
struct UiWindow * statusWindow
Definition djinn_menu.h:45
u16 owners[DJINN_LIST_OWNERS]
the party in order
Definition djinn_menu.h:67
u16 selection[2]
each pane's Djinni row chosen
Definition djinn_menu.h:61
s16 ownerX[8]
screen pixels
Definition djinn_menu.h:58
s8 selectedColumn[2]
each pane's member, in owners
Definition djinn_menu.h:48
u8 pairIndex[2]
The Djinn chosen in each pane: index in their element, element, owner.
Definition djinn_menu.h:81
u8 pairElement[2]
Definition djinn_menu.h:82
s16 ownerY[8]
screen pixels
Definition djinn_menu.h:59
u8 shownOwner[2]
the member giving and the one receiving
Definition djinn_menu.h:70
u8 messageSpeed
0 to 2; 1 on a new game
Definition game_state.h:66
s16 suspended
nonzero while a menu has suspended sprite projection
Definition animspr.h:69
An entry in a unit's action list: the action's id (OWNER_ACTION_ID_MASK) and marks for an action its ...
Definition battle_unit.h:19
u16 encodedAction
bits: 15 from the class | 14 from an equipped item | 13..0 action id.
Definition battle_unit.h:22
A render output: a sprite in a window's output list (a character, an icon or a portrait),...
s8 active
its UI_SPRITE_ motion; 0 while free
u16 animStep
step of its motion's animation
A text channel, one of three, which types decoded text into a window a few characters a frame and run...
Definition uiwindow.h:43
struct UiWindow * work
the window typed into; NULL when free
Definition uiwindow.h:44
The window system's work: the windows' tilemap, the windows, the three text channels,...
Definition window.h:19
u8 mode
Set while Mind Read shows thoughts: round frame corners, colour 8 text with no shadow,...
Definition window.h:35
u16 tilemap[640]
the windows' BG tilemap, 32 by 20 tiles
Definition window.h:20
u16 tileCursor
the text tile the next search for a free one starts at
Definition window.h:29
u16 glyphResource
VRAM cache slot of the page arrow; 99 when none.
Definition window.h:50
u8 pageArrowShown
1 while the next-page arrow is shown
Definition window.h:62
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 frame
The zoom's step: counts down from 7 to 0 while opening, and up from 0 to duration while closing.
Definition uiwindow.h:28
u16 y
tiles
Definition uiwindow.h:16
u16 state
0 while a message channel is typing into the window; 1 once its text has ended or closed the window,...
Definition uiwindow.h:24
u16 x
tiles
Definition uiwindow.h:15
s16 duration
frames of the zoom under way; 0 when none
Definition uiwindow.h:29
A view of the window system's work that names only its dirty bits and its menu busy flag.
Definition ui.h:14
unsigned dirty
Definition ui.h:16
unsigned menuBusy
Definition ui.h:18
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
signed char s8
Definition types.h:10
signed short s16
Definition types.h:12
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
s32 MenuBackdropResult
Definition menu.h:243
#define UI_PAGE_ARROW_VRAM
Definition window.h:64
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