Alchemy
Loading...
Searching...
No Matches

item.c

Go to the documentation of this file.
1/// @file
2/// The item menu: the item picker events open, the command loop, the member
3/// and item lists, and Use, Equip, Give, Drop, Remove and Details.
4/// Part of menu.c, the menu object, compiled only through it.
5
6#include "../menu_internal.h"
7
8// Where the edition's text goes. The international editions have longer
9// words, and some languages move a message to fit its own.
10//
11// The x of the small message windows "Dropped it.", "You were cursed!" and
12// "Removed".
13#if TBS_PATCH_1
14#define ITEM_MODAL_SHORT_X 14
15#define ITEM_MODAL_REMOVED_X 14
16#else
17#define ITEM_MODAL_SHORT_X 15
18#define ITEM_MODAL_REMOVED_X 17
19#endif
20
21#if LANGUAGE == LANGUAGE_FRENCH
22#define ITEM_CANNOT_TRADE_X 11
23#else
24#define ITEM_CANNOT_TRADE_X 15
25#endif
26
27#if LANGUAGE == LANGUAGE_ITALIAN
28#define ITEM_TRADED_X 13
29#else
30#define ITEM_TRADED_X 15
31#endif
32
33#if TBS_PATCH_1
34#define ITEM_TRADE_PROMPT_X 0
35#else
36#define ITEM_TRADE_PROMPT_X 16
37#endif
38
39// The x of the command grid's middle column.
40#if TBS_PATCH_1
41#define ITEM_COMMAND_TEXT_X 32
42#else
43#define ITEM_COMMAND_TEXT_X 40
44#endif
45
46#if TBS_PATCH_1
47#define ITEM_QUANTITY_WINDOW_WIDTH 30
48#else
49#define ITEM_QUANTITY_WINDOW_WIDTH 13
50#endif
51
52// The hand cursor and the "How many?" question of the quantity chooser.
53#if TBS_PATCH_1
54#define ITEM_GIVE_CURSOR_X 128
55#define ITEM_GIVE_ASK_X 32
56#define ITEM_GIVE_ASK_Y 0
57#else
58#define ITEM_GIVE_CURSOR_X 88
59#define ITEM_GIVE_ASK_X 0
60#define ITEM_GIVE_ASK_Y 32
61#endif
62
63#if TBS_PATCH_1
64#define ITEM_DROP_QUESTION_X 0
65#else
66#define ITEM_DROP_QUESTION_X 8
67#endif
68
69// The item list's icon column and name column.
70#if TBS_PATCH_1
71#define ITEM_LIST_PAGE_ICONS_X 116
72#define ITEM_LIST_NAME_X 24
73#else
74#define ITEM_LIST_PAGE_ICONS_X 120
75#define ITEM_LIST_NAME_X 32
76#endif
77
78/// The event work as the item picker sees it: what the player chose, for the
79/// event script. The shared header has no names for these two fields yet.
81 s32 unk000[0x60];
82 u16 chosenItem; ///< owner << 10 | item id
83 u8 unk182[0x18];
84 u16 chosenSlot; ///< the owner's inventory slot
85};
86
87/// The item picker an event script opens (window command 3): the item menu,
88/// in which the player chooses one party member's item. Records the choice in
89/// the event work and returns 1 if one was made.
91#if TBS_PATCH_1
92 void *backup;
93#endif
94 struct InventoryMenuState *screen;
95 s32 item;
96 s32 target;
97 s32 owner;
98 s32 result;
99#if TBS_PATCH_1
100 s32 size;
101#endif
102 void **process;
103 void **cache;
104
105 // Open the menu over the field, which stops moving.
106#if TBS_PATCH_1
107 size = 0x2000;
109#endif
111 cache = &((union HeapState *)gWorkSlot)->slots[HEAP_SLOT_MENU_CONTROL];
112 ((struct ObjectSystemWork *)cache[0])->suspended = 1;
113 UiWindow_DrawFrameFar(0, 0, 30, 20);
114 WaitFrames(1);
117 ItemMenu_Initialize(0, 3, 0, 7);
121 screen->messageWindow = UiWindow_CreateFar(13, 0, 17, 3, 2);
122#if TBS_PATCH_1
123 // Save the window tiles the menu draws over, and fill them with colour 3.
125 Iwram_CopyWords(backup, BG_CHAR_BLOCK(1), size);
126 Iwram_FillWords(BG_CHAR_BLOCK(1), size, 0x33333333);
128#endif
129
130 // Let the player choose.
132 result = ItemMenu_RunCommands(&owner, &target, &item);
134 if (result == 1) {
135 struct ItemPickerResult *selection =
137
138 selection->chosenItem = (owner << 10) | (item & ITEM_ID_MASK);
139 selection->chosenSlot = screen->selectedSlots[0];
140 }
141
142 // Close the menu and give the screen back to the field.
144 process = &cache[HEAP_SLOT_WINDOW - HEAP_SLOT_MENU_CONTROL];
145 ((struct UiRenderWork *)*process)->menuBusy = 1;
147 UiWindow_DrawFrameFar(0, 0, 30, 20);
150 ((struct ObjectSystemWork *)cache[0])->suspended = 0;
151#if TBS_PATCH_1
154 Iwram_CopyWords(BG_CHAR_BLOCK(1), backup, size);
155 ((struct UiRenderWork *)*process)->menuBusy = 0;
156 MemFree(backup);
157 WaitFrames(1);
159#endif
160 WaitFrames(1);
161 UiWindow_EraseBorderRectFar(0, 0, 30, 20);
162 ((struct UiRenderWork *)*process)->menuBusy = 0;
164 return result;
165}
166
167/// The most items of one kind a stack holds.
168#define ITEM_STACK_MAX 30
169
170/// The resident IWRAM word copy, called through its address.
171typedef s32 (*ItemWordCopyFn)(void *dst, const void *src, s32 size);
172
173#define ITEM_IWRAM_COPY_WORDS \
174 ((ItemWordCopyFn)(IwramIrqMain + Iwram_CopyWordsOffset))
175
176static __inline__ s32 Item_CopyWords(ItemWordCopyFn copy, void *dst,
177 const void *src, s32 size) {
178 /* FAKEMATCH(wrapper): the trade's unit copies call the routine through
179 * this helper, which takes its address first; through Iwram_CopyWords, 3 of
180 * 1269 instructions of ItemMenu_RunCommands differ in tbs-en. */
181 return copy(dst, src, size);
182}
183
184/// The steps of the item menu's command loop (ItemMenu_RunCommands).
194 ITEM_STEP_IDLE = 8, ///< nothing sets it
198 ITEM_STEP_QUANTITY = 12 ///< nothing sets it
199};
200
201/// Runs the item menu: choose a party member, one of their items and a command
202/// (Use, Equip, Give, Drop, Remove or Inspect), then carry it out, until the
203/// player backs out or presses Start. Returns 1 when an item is to be used
204/// outside the menu, with its owner, target and item id in the out parameters;
205/// -1 when the player backed out or pressed Start; 0 otherwise.
206s32 ItemMenu_RunCommands(s32 *ownerOut, s32 *targetOut, s32 *itemOut) {
207 s32 done;
208#if !TBS_PATCH_1
209 s32 owner;
210 s32 chosen;
211#endif
212 s32 selection;
213 s32 menuResult;
214 struct BattleUnit *sourceUnit;
215 struct BattleUnit *targetUnit;
216 struct InventoryMenuState *menu;
217 struct ItemDefinition *item;
218 struct BattleUnit *sourceCopy;
219 struct BattleUnit *targetCopy;
220 u32 state;
221 s32 command;
222 s32 result;
223 s32 heldCount;
224 s32 amount;
225 s32 transferFailed;
226 s32 removedCount;
227#if TBS_PATCH_1
228 s32 giveTarget;
229#endif
230 u8 sourceQuantity;
231 u8 targetQuantity;
232 s8 stackSize;
233
234 done = 0;
235#if !TBS_PATCH_1
236 owner = 0;
237 chosen = 0;
238#endif
239 selection = 0;
240 menuResult = 0;
241 state = ITEM_STEP_OWNER;
242 menu = gMenuWork;
243
244 while (done == 0 && GameFlag_TestFar(FLAG_MENU_START_PRESSED) == 0) {
245 switch (state) {
246 // Choose whose items to look at.
247 case ITEM_STEP_OWNER:
248 menu->selectedSlots[0] = 0;
252 ItemMenu_DrawMessage(0, MsgWhoseItem);
253#if TBS_PATCH_1
256 command = ItemMenu_SelectMember(0);
257 if (command == -1) {
258 selection = command = 0;
259 menuResult = -1;
260 done = 1;
261 }
262#else
264 owner = ItemMenu_SelectMember(0);
265 if (owner == -1) {
266 chosen = selection = owner = 0;
267 menuResult = -1;
268 done = 1;
269 }
270#endif
273 state = ITEM_STEP_ITEM;
274 break;
275
276 // Choose one of their items.
277 case ITEM_STEP_ITEM:
278 if (ItemMenu_CountItems(menu->paneOwner[0]) == 0) {
279 state = ITEM_STEP_OWNER;
280 break;
281 }
285 menu->paneIcons[0]->active = ICON_SHOWN;
286 ItemMenu_DrawMessage(0, MsgWhichItem);
287 selection = ItemMenu_RunList(0);
288 state = ITEM_STEP_OWNER;
289 if (selection == -1) {
290 break;
291 }
292 menu->listMode = 0xff;
293 state = ITEM_STEP_COMMAND;
294 break;
295
296 // Choose what to do with it. An item that starts an effect on the field
297 // (BattleFx_HasTriggerFar) closes the menu and is returned to the caller;
298 // other usable items are used here.
300 command = ItemMenu_ChooseCommand();
301 if (command == -1) {
302 state = ITEM_STEP_ITEM;
303 menu->completionFlag = 1;
304 }
305 if (command == ITEM_COMMAND_USE) {
307 0) {
308 done = 1;
309#if TBS_PATCH_1
310 *ownerOut = menu->paneOwner[0];
311 *targetOut = command;
312 *itemOut = menu->selectedItems[0] & ITEM_ID_MASK;
313#else
314 *ownerOut = owner;
315 *targetOut = chosen;
316 *itemOut = selection;
317#endif
318 menuResult = 1;
319 break;
320 }
321 result =
322 Item_ClassifyUseMode(menu->paneOwner[0], menu->selectedItems[0]);
323 if (result == 1) {
324 state = ITEM_STEP_USE;
325 }
326 if (result == 2) {
327 ItemMenu_Use();
329 InventoryMenu_ShowModalMessage(menu->messageOffset + MsgItemUseResult,
330 0, -1);
331#if !TBS_PATCH_1
333#endif
334 menu->paneIcons[0]->active = ICON_HIDDEN;
336 UnitGetFar(menu->paneOwner[0]), menu->items, 0);
337 ItemMenu_DrawIcons(menu->items, 0);
338 state = ITEM_STEP_OWNER;
339 }
340 if (result == -1 || result == 0) {
341 done = 1;
342 *ownerOut = menu->paneOwner[0];
343 *targetOut = menu->paneOwner[1];
344 *itemOut = menu->selectedItems[0] & ITEM_ID_MASK;
345 menuResult = 1;
346 }
347 }
348 if (command == ITEM_COMMAND_EQUIP) {
349 state = ITEM_STEP_EQUIP;
350 }
351 if (command == ITEM_COMMAND_GIVE) {
352 state = ITEM_STEP_TARGET;
353 }
354 if (command == ITEM_COMMAND_DROP) {
355 state = ITEM_STEP_DROP;
356 }
357 if (command == ITEM_COMMAND_REMOVE) {
358 state = ITEM_STEP_REMOVE;
359 }
360 if (command == ITEM_COMMAND_INSPECT) {
361 state = ITEM_STEP_INSPECT;
362 }
363 break;
364
365 // Use the item on the party member chosen.
366 case ITEM_STEP_USE:
372 UiText_DrawCharacterAtOffsetFar(MsgUseOnWhom, menu->messageWindow, 16,
373 16);
374#if TBS_PATCH_1
375 if (ItemMenu_SelectTarget(0) != -1) {
376#else
377 chosen = ItemMenu_SelectTarget(0);
378 if (chosen != -1) {
379#endif
380 command = 0;
381 if (ItemMenu_IsSpecial(menu->selectedItems[0] & ITEM_ID_MASK) != 0) {
382 command = STATUS_PANEL_STATS;
383 }
384 result = ItemMenu_Use();
386 command);
387 if (result != -1) {
389 InventoryMenu_ShowModalMessage(menu->messageOffset + MsgItemUseResult,
390 0, -1);
391#if !TBS_PATCH_1
393#endif
394 menu->paneIcons[0]->active = ICON_HIDDEN;
396 state = ITEM_STEP_ITEM;
397 }
399 menu->items, 0);
400 ItemMenu_DrawIcons(menu->items, 0);
401 menu->completionFlag = 1;
402 } else {
403 state = ITEM_STEP_COMMAND;
404 }
405 break;
406
407 // Give: choose to whom.
408 case ITEM_STEP_TARGET:
413 UiText_DrawCharacterAtOffsetFar(MsgGiveToWhom, menu->messageWindow, 16,
414 16);
415#if TBS_PATCH_1
416 giveTarget = ItemMenu_SelectTarget(1);
417 state = ITEM_STEP_GIVE;
418 if (giveTarget == -1) {
419#else
420 chosen = ItemMenu_SelectTarget(1);
421 state = ITEM_STEP_GIVE;
422 if (chosen == -1) {
423#endif
425 menu->paneOwner[0]);
426 state = ITEM_STEP_COMMAND;
427 }
428 break;
429
430 // Drop the item, or some of a stack, after confirming.
431 case ITEM_STEP_DROP:
434 result = 0;
435 if ((item->flags & ITEM_STACKABLE) != 0) {
436 heldCount = (menu->selectedItems[0] >> INVENTORY_QUANTITY_SHIFT) + 1;
437 if (heldCount > 1) {
439 result = ItemMenu_SelectGiveQuantity(0, heldCount, 1);
440 }
441 }
442 if (result == -1) {
443 state = ITEM_STEP_COMMAND;
444 break;
445 }
446 menu->paneOwner[1] = 0;
448 (menu->selectedItems[0] & ITEM_ID_MASK) |
449 (result << INVENTORY_QUANTITY_SHIFT),
450 (u8)menu->selectedItemIcon->index, 0);
452 menu->selectedItemIcon->x = 120;
453 menu->selectedItemIcon->y = 28;
455 UiWindow_ClearInteriorTilesFar((void *)menu->listWindow, 0, 72, 120, 96);
457 if (ItemMenu_ConfirmDrop(selection) == 0) {
458#if TBS_PATCH_1
459 command = menu->paneOwner[0];
460 UnitGetFar(command);
461 for (removedCount = 0; removedCount < result + 1; removedCount++) {
462 Inventory_RemoveFar(command, menu->selectedSlots[0]);
464 }
465 UnitCalcFar(command);
466#else
467 owner = menu->paneOwner[0];
468 UnitGetFar(owner);
469 for (removedCount = 0; removedCount < result + 1; removedCount++) {
470 Inventory_RemoveFar(owner, menu->selectedSlots[0]);
472 }
473 UnitCalcFar(owner);
474#endif
476 ItemMenu_RefreshOwner(menu->paneOwner[0], 0);
478 menu->paneIcons[0]->active = ICON_HIDDEN;
479 WaitFrames(1);
482 menu->completionFlag = 1;
483 state = ITEM_STEP_ITEM;
484 } else {
485 state = ITEM_STEP_COMMAND;
486 }
487 UnitCalcFar(menu->paneOwner[0]);
490 break;
491
492 // Give the item, or some of a stack, to the chosen member. A full
493 // inventory offers a trade instead; the new holder may equip it.
494 case ITEM_STEP_GIVE:
495 transferFailed = 0;
497 if ((item->flags & ITEM_STACKABLE) != 0) {
499 menu->paneOwner[1], menu->selectedItems[0] & ITEM_ID_MASK);
500 if (heldCount == ITEM_STACK_MAX) {
501 transferFailed = 1;
502 }
504 heldCount == 0) {
505 state = ITEM_STEP_TRADE;
506 break;
507 }
508 stackSize = (menu->selectedItems[0] >> INVENTORY_QUANTITY_SHIFT) + 1;
509 if (transferFailed == 0) {
510 if (heldCount + stackSize > ITEM_STACK_MAX) {
511 amount = ITEM_STACK_MAX - heldCount;
512 } else {
513 amount = stackSize;
514 }
515 if (stackSize > 1) {
516 result = ItemMenu_SelectGiveQuantity(0, amount, 0);
517 } else {
518 result = 0;
519 }
520 if (result == -1) {
521 state = ITEM_STEP_TARGET;
522 break;
523 }
524 for (command = 0; command < result + 1; command++) {
525 heldCount = Inventory_AddItemFar(
526 menu->paneOwner[1],
528 if (heldCount != -1) {
529 Inventory_RemoveFar(menu->paneOwner[0], menu->selectedSlots[0]);
530 menu->selectedSlots[1] = heldCount;
531 } else {
532 transferFailed = 1;
533 }
534 }
535 }
536 } else {
537 result = Inventory_AddItemFar(menu->paneOwner[1],
538 menu->selectedItems[0] &
540 if (result == -1) {
541 state = ITEM_STEP_TRADE;
542 break;
543 }
544 menu->selectedSlots[1] = result;
545 result =
546 Inventory_RemoveFar(menu->paneOwner[0], menu->selectedSlots[0]);
547 if (result == -1) {
548 transferFailed = 1;
549 }
550 }
551 UnitCalcFar(menu->paneOwner[0]);
552 UnitCalcFar(menu->paneOwner[1]);
555 result = 1;
556 if (transferFailed == 0) {
557 menu->paneOwner[0] = menu->paneOwner[1];
558 menu->selectedItems[0] &= ITEM_ID_MASK;
559#if TBS_PATCH_1
561#endif
564 result = ItemMenu_ConfirmEquip(0);
565 }
567 break;
568 }
569 ItemMenu_RefreshOwner(menu->paneOwner[1], 1);
570 menu->paneIcons[0]->active = ICON_HIDDEN;
571 WaitFrames(1);
572 // Commit recalculated stats only after every transfer has succeeded.
573 if (transferFailed == 1) {
575 InventoryMenu_ShowModalMessage(MsgCannotHoldMore, 15, 14);
576 } else {
578 if (result == 1) {
579 InventoryMenu_ShowModalMessage(MsgGiven, 15, 14);
580 } else {
582 0, menu->paneOwner[1]);
583 InventoryMenu_ShowModalMessage(MsgEquippedIt, 15, 14);
584 item = Item_GetDirectFar(menu->selectedItems[0]);
585 if ((item->flags & ITEM_CURSED) != 0) {
586 AudioCommand_PlayFar(SE_103); // the curse sound
588 InventoryMenu_ShowModalMessage(MsgEquippedIt +
589 7, // "You were cursed!"
591 }
592 }
593 }
595 state = ITEM_STEP_OWNER;
596 break;
597
598 // Trade: the receiver gives back one of their items. Both units are saved
599 // first and restored if any part of the swap fails.
600 case ITEM_STEP_TRADE:
601 transferFailed = 0;
604 ItemMenu_DrawMessage(0, MsgSwapForWhat);
605#if TBS_PATCH_4
606 if (ItemMenu_RunList(1) == -1) {
607#else
608 selection = ItemMenu_RunList(1);
609 if (selection == -1) {
610#endif
611 state = ITEM_STEP_TARGET;
612 break;
613 }
614 // Snapshot both inventories so any failed part of the trade can roll
615 // back.
616 sourceUnit = UnitGetFar(menu->paneOwner[0]);
617 targetUnit = UnitGetFar(menu->paneOwner[1]);
618 sourceCopy = MemAlloc(BATTLE_UNIT_SIZE);
619 targetCopy = MemAlloc(BATTLE_UNIT_SIZE);
620 Item_CopyWords(ITEM_IWRAM_COPY_WORDS, sourceCopy, sourceUnit,
622 Item_CopyWords(ITEM_IWRAM_COPY_WORDS, targetCopy, targetUnit,
624 sourceQuantity = 0;
625 while (sourceQuantity <= 29) {
626 result =
627 Inventory_RemoveFar(menu->paneOwner[0], menu->selectedSlots[0]);
628 if (result == 2) {
629 break;
630 }
631 if (result == -1) {
632 transferFailed = 1;
633 break;
634 }
635 sourceQuantity++;
636 }
637 sourceQuantity++;
638 targetQuantity = 0;
639 while (targetQuantity <= 29) {
640 if ((menu->selectedItems[1] & INVENTORY_EQUIPPED) != 0) {
642 if ((item->flags & ITEM_CANNOT_UNEQUIP) != 0) {
643 transferFailed = 1;
644 }
645 }
646 result =
647 Inventory_RemoveFar(menu->paneOwner[1], menu->selectedSlots[1]);
648 if (result == 2) {
649 break;
650 }
651 if (result == -1) {
652 transferFailed = 1;
653 break;
654 }
655 targetQuantity++;
656 }
657 targetQuantity++;
658 while (sourceQuantity != 0) {
659 result = Inventory_AddItemFar(menu->paneOwner[1],
660 menu->selectedItems[0] &
662 if (result == -1) {
663 transferFailed = 1;
664 break;
665 }
666 menu->selectedSlots[1] = result;
667 sourceQuantity--;
668 }
669 while (targetQuantity != 0) {
670 result = Inventory_AddItemFar(menu->paneOwner[0],
671 menu->selectedItems[1] &
673 if (result == -1) {
674 transferFailed = 1;
675 break;
676 }
677 menu->selectedSlots[0] = result;
678 targetQuantity--;
679 }
680 WaitFrames(1);
681 if (transferFailed == 1) {
682 Item_CopyWords(ITEM_IWRAM_COPY_WORDS, sourceUnit, sourceCopy,
684 Item_CopyWords(ITEM_IWRAM_COPY_WORDS, targetUnit, targetCopy,
688#if TBS_PATCH_LEVEL == 3
690#endif
691 } else {
692 UnitCalcFar(menu->paneOwner[0]);
693 UnitCalcFar(menu->paneOwner[1]);
697#if TBS_PATCH_1
700#endif
702 menu->paneOwner[0] = menu->paneOwner[1];
703 menu->selectedItems[0] &= ITEM_ID_MASK;
705 result = ItemMenu_ConfirmEquip(0);
709 ItemMenu_RefreshOwner(menu->paneOwner[1], 1);
710 if (result == 0) {
712 menu->selectedSlots[1], 0,
713 menu->paneOwner[1]);
714 InventoryMenu_ShowModalMessage(MsgEquippedIt, 15, 14);
715 item = Item_GetDirectFar(menu->selectedItems[0]);
716 if ((item->flags & ITEM_CURSED) != 0) {
717 AudioCommand_PlayFar(SE_103); // the curse sound
719 InventoryMenu_ShowModalMessage(MsgEquippedIt +
720 7, // "You were cursed!"
722 }
723 } else {
725 }
726 }
727 }
728 MemFree(targetCopy);
729 MemFree(sourceCopy);
731 state = ITEM_STEP_OWNER;
732 break;
733
734 case ITEM_STEP_EQUIP:
735 result = Inventory_EquipFar(menu->paneOwner[0], menu->selectedSlots[0]);
736 if (result == -1) {
737 state = ITEM_STEP_ITEM;
738 break;
739 }
740 if (result == -2) {
742 InventoryMenu_ShowModalMessage(MsgCannotRemoveItem, 0, -1);
743#if !TBS_PATCH_1
745#endif
746 state = ITEM_STEP_ITEM;
747 break;
748 }
749 UnitCalcFar(menu->paneOwner[0]);
751 menu->paneIcons[0]->active = ICON_HIDDEN;
752 menu->itemCount =
753 ItemMenu_CollectItems(UnitGetFar(menu->paneOwner[0]), menu->items, 0);
754 ItemMenu_DrawIcons(menu->items, 0);
755 WaitFrames(1);
757 menu->paneOwner[0]);
759 InventoryMenu_ShowModalMessage(MsgEquippedIt, 15, 8);
760 item = Item_GetDirectFar(menu->selectedItems[0]);
761 if ((item->flags & ITEM_CURSED) != 0) {
762 AudioCommand_PlayFar(SE_103); // the curse sound
764 InventoryMenu_ShowModalMessage(MsgEquippedIt + 7, // "You were cursed!"
766 }
767 state = ITEM_STEP_ITEM;
768 break;
769
770 // Unequip it.
771 case ITEM_STEP_REMOVE:
772 UnitGetFar(menu->paneOwner[0])->inventory[menu->selectedSlots[0]] &=
774 UnitCalcFar(menu->paneOwner[0]);
776 menu->paneIcons[0]->active = ICON_HIDDEN;
777 menu->itemCount =
778 ItemMenu_CollectItems(UnitGetFar(menu->paneOwner[0]), menu->items, 0);
779 ItemMenu_DrawIcons(menu->items, 0);
780 WaitFrames(1);
781 menu->equipPreview = 1;
783 menu->paneOwner[0]);
784 menu->equipPreview = 0;
788 state = ITEM_STEP_ITEM;
789 break;
790
791 // Show its description.
793 menu->paneIcons[0]->active = ICON_HIDDEN;
797 menu->paneOwner[0]);
798 menu->paneIcons[0]->active = ICON_SHOWN;
799 state = ITEM_STEP_COMMAND;
800 break;
801
802 // Not reached from any command: choose a quantity, then do nothing with
803 // it.
805 result = ItemMenu_SelectGiveQuantity(0, 30, 0);
806 if (result != -1) {
807 heldCount = result;
808 }
809 state = ITEM_STEP_ITEM;
810 break;
811
812 case ITEM_STEP_IDLE:
813 break;
814
815 default:
816 done = 1;
817 break;
818 }
819 }
820
822 menuResult = -1;
823 }
824 return menuResult;
825}
826
827/// Uses the selected item from the owner in pane 0 on the member in pane 1.
828/// On failure plays the error sound, shows why in the info window and returns
829/// -1; otherwise plays the item's animation, recalculates both members and
830/// returns 1.
832 struct InventoryMenuState *menu;
833 s32 result;
834
835 menu = gMenuWork;
836 result =
837 Item_Use(menu->selectedSlots[0], menu->paneOwner[0], menu->paneOwner[1]);
838
839 if (result == -1) {
842 InventoryMenu_ShowModalMessage(menu->messageOffset + MsgItemUseResult,
843 result, result);
844#if !TBS_PATCH_1
846#endif
847 menu->completionFlag = 1;
848 return result;
849 }
850
852 UnitCalcFar(menu->paneOwner[0]);
853 UnitCalcFar(menu->paneOwner[1]);
854 return 1;
855}
856
857/// Sets up the item menu's first screen: the cursor window with the party's
858/// figures, the info window along the bottom, and an 8 by 2 cursor grid. The
859/// parameters are not used.
860void ItemMenu_Initialize(s32 x, s32 y, s32 mode, s32 columns) {
861 struct InventoryMenuState *menu = gMenuWork;
862 s32 ownerIndex;
863
865 for (ownerIndex = 3; ownerIndex >= 0; ownerIndex--)
866 menu->ownerY[ownerIndex] = 30;
867
868 {
869 u8 zero = 0;
870 s32 style;
871 menu->helpWindow = NULL;
872 menu->statusWindow = NULL;
873 style = 2;
874 menu->infoWindow = UiWindow_CreateFar(0, 17, 30, 3, style);
875 menu->itemWindow = NULL;
876 menu->selectedColumn = zero;
877 menu->selectedRow = zero;
878 menu->columnCount = 8;
879 menu->rowCount = style;
880 }
881}
882
883/// Creates the 32 item icon sprites in window, off screen until placed: slots 0
884/// to 7 at x 248, the rest at x 256, all at y 168, each showing item graphic
885/// slot of the same number.
887 struct UiWindow *window) {
888 struct RenderOutput **firstIcons;
889 s32 firstSlot;
890 s32 firstY;
891 struct RenderOutput **secondIcons;
892 s32 secondSlot;
893 s32 secondY;
894 struct RenderOutput **remainingIcons;
895 s32 remainingSlot;
896 s32 remainingY;
897
898 firstSlot = 0;
899 firstY = 0xA8;
900 firstIcons = &state->entryIcons[0];
901 do {
902 *firstIcons++ =
903 RenderOutput_CreateFromResourceFar(2, firstSlot, window, 0xF8, firstY);
904 firstSlot++;
905 } while (firstSlot <= 7);
906
907 secondSlot = 8;
908 secondY = 0xA8;
909 secondIcons = &state->entryIcons[8];
910 do {
911 *secondIcons++ = RenderOutput_CreateFromResourceFar(2, secondSlot, window,
912 0x100, secondY);
913 secondSlot++;
914 } while (secondSlot <= 15);
915
916 remainingSlot = 16;
917 remainingY = 0xA8;
918 remainingIcons = &state->entryIcons[16];
919 do {
920 *remainingIcons++ = RenderOutput_CreateFromResourceFar(
921 2, remainingSlot, window, 0x100, remainingY);
922 remainingSlot++;
923 } while (remainingSlot <= 31);
924}
925
926/// Hides all 32 item icons.
928 s32 hiddenState = ICON_HIDDEN;
929 struct RenderOutput **icons =
931 s32 slot;
932
933 for (slot = 31; slot >= 0; slot--) {
934 struct RenderOutput *icon = *icons++;
935 if (icon != 0) {
936 icon->active = hiddenState;
937 }
938 }
939}
940
941#if TBS_PATCH_1
942/// Hides the item icons in the first column of the five-wide item grid.
944 struct InventoryMenuState *menu = gMenuWork;
945 s32 slot = 0;
946 s32 hiddenState = ICON_HIDDEN;
947 struct RenderOutput **iconSlot = menu->entryIcons;
948
949 do {
950 struct RenderOutput *icon = *iconSlot++;
951
952 if (icon != 0 && slot % MENU_ITEM_GRID_COLUMNS == 0) {
953 icon->active = hiddenState;
954 }
955 slot++;
956 } while (slot <= 31);
957}
958#endif
959
960/// Closes the item menu: releases the party figures, hides the icons and the
961/// cursor, and closes every window the menu opened.
962void ItemMenu_Close(void) {
963 struct InventoryMenuState *menu;
964 struct RenderOutput *cursor;
965
966 menu = gMenuWork;
969 WaitFrames(1);
970 cursor = menu->cursor;
971 cursor->active = ICON_HIDDEN;
983}
984
985/// Lets the player choose a party member in pane (0 or 1), starting from the
986/// member chosen last. Returns the member's id, or -1 when the player backs
987/// out.
989 struct InventoryMenuState *menu = gMenuWork;
990 s32 result = 0;
991 s32 ownerIndex;
992 struct BattleUnit *unit;
993
994 ownerIndex = menu->paneIndex[pane];
996 menu->paneCount[pane] = menu->partyCount;
997 if (ownerIndex == -1) {
998 menu->paneIndex[pane] = result;
999 ownerIndex = 0;
1000 } else {
1001 UiMenu_SlideCursor(ownerIndex * 24 - 10, 16);
1002 }
1003 unit = UnitGetFar(menu->ownerIds[ownerIndex]);
1004 menu->itemCount = ItemMenu_CollectItems(unit, menu->items, 0);
1005 result = ItemMenu_RunOwnerSelection(menu->ownerIds, menu->items);
1006 UiIcon_PrepareObject(menu->paneIcons[pane]);
1007 WaitFrames(1);
1008 return result;
1009}
1010
1011/// The party member row of the item menu. Left and Right move between members,
1012/// showing each one's items and status; holding R shows their equipment
1013/// instead; L + A sorts the member's items, a new sort order each press; A
1014/// chooses a member who has items and B backs out. Returns the chosen member's
1015/// id, or -1.
1017 struct InventoryMenuState *menu;
1018 s32 selection;
1019 s32 ownerCount;
1020 s32 result;
1021 struct BattleUnit *unit;
1022 u8 sortMode;
1023 s32 showEquipment;
1024 s32 redraw;
1025 struct UiWindow *window;
1026 s32 ownerIndex;
1027
1028 menu = gMenuWork;
1029 selection = menu->paneIndex[0];
1030 ownerCount = menu->paneCount[0];
1031 redraw = 1;
1032 result = 0;
1033 sortMode = 0;
1034 showEquipment = 0;
1035 unit = UnitGetFar(ownerIds[selection]);
1036 if (UiWindow_UpdateOrCreate(&menu->itemWindow, 13, 3, 17, 10, 2))
1037 Menu_SpawnIconEntries(menu, menu->itemWindow);
1038 if (UiWindow_UpdateOrCreate(&menu->helpWindow, 13, 13, 17, 4, 2)) {
1039 menu->selectedItemIcon =
1040 RenderOutput_CreateFromResourceFar(2, 0, menu->helpWindow, 0, result);
1042 }
1043 // The help text: L + A sorts, R shows the equipment.
1044#if LANGUAGE != LANGUAGE_JAPANESE
1045 UiText_DrawCharacterAtOffsetFar(MsgArrangeItemsHelp, menu->helpWindow, 0, 0);
1046 UiText_DrawCharacterAtOffsetFar(MsgArrangeItemsHelp + 1, menu->helpWindow, 0,
1047 8);
1048#else
1050 0);
1051 UiText_DrawCharacterAtOffsetFar(MsgArrangeItemsHelp, menu->helpWindow, 32, 0);
1053 16, 8);
1054 UiText_DrawCharacterAtOffsetFar(MsgArrangeItemsHelp + 1, menu->helpWindow, 32,
1055 8);
1056#endif
1057 menu->paneIcons[0]->active = redraw; // ICON_SHOWN
1059 selection = (selection + ownerCount) % ownerCount;
1060 UiMenu_PositionCursor(selection * 24 - 10, 16);
1061 if (redraw) {
1062 sortMode = 0;
1063 redraw = 0;
1064 window = menu->statusWindow;
1065 unit = UnitGetFar(ownerIds[selection]);
1066 if (showEquipment) {
1067 menu->itemCount = ItemMenu_CollectItems(UnitGetFar(ownerIds[selection]),
1068 menu->items, 0);
1069 ItemMenu_OpenCategory(ownerIds[selection]);
1070 Menu_DrawOwnerStatusPanel(window, ownerIds[selection], 0,
1072 } else {
1073 ItemMenu_RefreshOwner(ownerIds[selection], 0);
1074 Menu_DrawOwnerStatusPanel(window, ownerIds[selection], 0,
1076 }
1077 // Raise the chosen member's figure.
1078 for (ownerIndex = 3; ownerIndex >= 0; ownerIndex--)
1079 menu->ownerY[ownerIndex] = 30;
1080 menu->ownerY[selection] = 26;
1081 }
1082 WaitFrames(1);
1083 // L + A sorts, cycling through the four sort orders.
1084 if (gKeysPressed & KEY_A) {
1085 if (gKeysHeld & KEY_L) {
1086 sortMode = (sortMode + 4) % 4;
1088 sortMode++;
1089 ItemMenu_RefreshOwner(ownerIds[selection], 0);
1091 } else if (ItemMenu_CountItems(ownerIds[selection])) {
1093 result = ownerIds[selection];
1094 break;
1095 } else {
1097 }
1098 }
1099 if (gKeysPressed & KEY_B) {
1101 result = -1;
1102 break;
1103 }
1104 if (gKeysPressed & KEY_R) {
1105 showEquipment = 1;
1106 redraw = 1;
1107 }
1108 if (!(gKeysHeld & KEY_R) && showEquipment == 1) {
1109 showEquipment = 0;
1110 redraw = 1;
1111 }
1112 if (gKeysRepeat & KEY_LEFT) {
1114 selection--;
1115 redraw = 1;
1116 }
1117 if (gKeysRepeat & KEY_RIGHT) {
1119 selection++;
1120 redraw = 1;
1121 }
1122 }
1123 menu->paneIndex[0] = selection;
1124 menu->selectedOwner = ownerIds[selection];
1125 menu->paneOwner[0] = ownerIds[selection];
1126 return result;
1127}
1128
1129/// Shows the equipment view of member ownerId's items in the item window.
1131 struct InventoryMenuState *menu;
1132
1133 menu = gMenuWork;
1136 ItemMenu_DrawCategory(menu->itemWindow, ownerId, 0);
1137}
1138
1139/// Chooses the party member to use (mode 0) or give (mode 1) the selected item
1140/// to. Using shows each member's status as the cursor passes; giving shows each
1141/// member's items, how many of this item they already hold, or that they would
1142/// have to trade, and the equipment preview. The party members who can equip
1143/// the item move while the cursor is up. Returns the chosen member's id, or -1
1144/// when the player backs out; giving cannot choose the item's owner.
1146
1147 struct InventoryMenuState *menu;
1148 struct UiWindow *window;
1149 s32 ownerCount;
1150 s32 ownerIndex;
1151 s32 redraw;
1152 u8 result;
1153 s32 descriptionShown;
1154 s32 heldCount;
1155 struct RenderOutput *targetMarker;
1156
1157 menu = gMenuWork;
1158 window = menu->itemWindow;
1159 ownerIndex = menu->paneIndex[1];
1160 ownerCount = menu->partyCount;
1161 redraw = 1;
1162 result = 0;
1163 descriptionShown = 0;
1164 UiWindow_SetBounds(window, 13, 5, 17, 12);
1166 UnitGetFar(menu->ownerIds[menu->paneIndex[0]]);
1168 0xc80);
1170 if (redraw) {
1171 redraw = 0;
1172 ownerIndex = (ownerIndex + ownerCount) % ownerCount;
1173 window = menu->itemWindow;
1174 UnitGetFar(menu->ownerIds[ownerIndex]);
1175 // The marker over the chosen member.
1176 targetMarker = menu->paneIcons[1];
1177 targetMarker->oam.x = targetMarker->x =
1178 ((menu->mainWindow->x + ownerIndex * 3) << 3) - 2;
1179 // Giving: the member's items and how many of this one they hold.
1180 if (mode == 1) {
1181 ItemMenu_RefreshOwner(menu->ownerIds[ownerIndex], 1);
1182 UiWindow_DrawDividerLineFar(window, 0, 9, 16, 9);
1183 UiWindow_ClearInteriorTilesFar((void *)window, 0, 72, 120, 80);
1184 if (ownerIndex != menu->paneIndex[0]) {
1185 heldCount = InventoryMenu_GetItemQuantity(menu->ownerIds[ownerIndex],
1186 menu->selectedItems[0] &
1187 ITEM_ID_MASK);
1188#if LANGUAGE == LANGUAGE_SPANISH || LANGUAGE == LANGUAGE_FRENCH || \
1189 LANGUAGE == LANGUAGE_ITALIAN
1190 if (ItemMenu_CountItems(menu->ownerIds[ownerIndex]) ==
1192 heldCount == 0)
1193 UiText_DrawCharacterAtOffsetFar(MsgTradeForWhat, window, 0, 72);
1194 else if (heldCount != 0) {
1195 UiText_DrawNumberInWindowFar(heldCount, 2, window, 8, 72);
1197 72);
1198 } else {
1199 UiText_DrawCharacterAtOffsetFar(MsgNoneInStock, window, 16, 72);
1200 }
1201#else
1202 if (heldCount != 0) {
1203 UiText_DrawNumberInWindowFar(heldCount, 2, window, 8, 72);
1205 72);
1206 } else {
1207 UiText_DrawCharacterAtOffsetFar(MsgNoneInStock, window, 16, 72);
1208 }
1209 if (ItemMenu_CountItems(menu->ownerIds[ownerIndex]) ==
1211 heldCount == 0)
1212 UiText_DrawCharacterAtOffsetFar(MsgTradeForWhat, window,
1214#endif
1215 }
1217 menu->ownerIds[ownerIndex]);
1218 }
1219 // Using: the member's status, and the item's name once.
1220 if (mode == 0) {
1223 menu->ownerIds[ownerIndex],
1225 else
1227 menu->statusWindow, menu->ownerIds[ownerIndex],
1229 if (!GameFlag_TestFar(FLAG_MENU_INFO_KEPT) && !descriptionShown) {
1230 MENU_RESET_INFO_WINDOW((void *)menu->infoWindow);
1232 MsgItemPlainName,
1233 menu->infoWindow, 0, 0);
1234 descriptionShown = 1;
1235 } else {
1237 }
1238 }
1239 }
1240 UiMenu_PositionCursor(ownerIndex * 24 - 10, 16);
1241 WaitFrames(1);
1242 if (gKeysPressed & KEY_A) {
1243 if (mode == 1 && ownerIndex == menu->paneIndex[0]) {
1245 continue;
1246 }
1248 result = menu->ownerIds[ownerIndex];
1249 break;
1250 }
1251 if (gKeysPressed & KEY_B) {
1253 result = 255;
1254 break;
1255 }
1256 if (gKeysRepeat & KEY_LEFT) {
1258 ownerIndex--;
1259 redraw = 1;
1260 }
1261 if (gKeysRepeat & KEY_RIGHT) {
1263 redraw = 1;
1264 ownerIndex++;
1265 }
1266 }
1267 targetMarker = menu->paneIcons[1];
1268 menu->paneIndex[1] = ownerIndex;
1269 UiIcon_PrepareObject(targetMarker);
1270 targetMarker->active = ICON_HIDDEN;
1272 WaitFrames(1);
1273 menu->paneIndex[1] = ownerIndex;
1274 menu->selectedOwner = menu->ownerIds[ownerIndex];
1275 menu->paneOwner[1] = menu->ownerIds[ownerIndex];
1276 return (s8)result;
1277}
1278
1279/// Scheduler callback while choosing a member to give an item to: every 32
1280/// frames, sets each party figure's animation by whether that member can equip
1281/// the item (3) or not (1).
1283 struct InventoryMenuState *menu;
1284 s8 memberIndex;
1285
1286 menu = gMenuWork;
1287 if ((gFrameCount & 31) == 0 && menu->partyCount != 0) {
1288 memberIndex = 0;
1289 do {
1290 if (Item_CanOwnerEquip(menu->ownerIds[memberIndex],
1291 menu->selectedItems[0] & ITEM_ID_MASK) != 0) {
1292 struct AnimationObject *partyFigure = menu->ownerObjects[memberIndex];
1294 } else {
1295 struct AnimationObject *partyFigure = menu->ownerObjects[memberIndex];
1297 }
1298 memberIndex++;
1299 } while (memberIndex < menu->partyCount);
1300 }
1301}
1302
1303/// Ends EquipmentMenu_UpdateCompatibilityIndicators: puts every party figure
1304/// back to animation 1 and removes the callback.
1306 struct InventoryMenuState *menu;
1307 s8 memberIndex;
1308
1309 menu = gMenuWork;
1310 if (menu->partyCount != 0) {
1311 memberIndex = 0;
1312 do {
1313 struct AnimationObject *partyFigure = menu->ownerObjects[memberIndex];
1315 memberIndex++;
1316 } while (memberIndex < menu->partyCount);
1317 }
1319}
1320
1321/// Returns 1 for the items that raise a stat for good (Apple, Hard Nut, Mint
1322/// and Lucky Pepper), whose use shows the stats panel instead of HP and PP.
1324 switch (itemId) {
1325 case ITEM_APPLE:
1326 case ITEM_HARD_NUT:
1327 case ITEM_MINT:
1328 case ITEM_LUCKY_PEPPER:
1329 return 1;
1330 }
1331 return 0;
1332}
1333
1334/// Clears the message window and writes message into it.
1335void ItemMenu_DrawMessage(s32 unused, s32 message) {
1336 struct InventoryMenuState *menu;
1337
1338 menu = gMenuWork;
1340 UiText_DrawCharacterAtOffsetFar(message, menu->messageWindow, 0, 0);
1341}
1342
1343/// Hides the icon of each of the 32 list entries whose item is 0.
1345 struct InventoryMenuState *menu = gMenuWork;
1346 s32 slot;
1347
1348 for (slot = 0; slot < 32; slot++) {
1349 if (items[slot] == 0) {
1350 UiIcon_PrepareObject(menu->entryIcons[slot]);
1351 menu->entryIcons[slot]->active = ICON_HIDDEN;
1352 }
1353 }
1354}
1355
1356/// Returns how many of member ownerId's 15 inventory slots hold an item.
1358 s32 maskedItemId;
1359 s32 remainingSlots;
1360 s32 count;
1361 u16 *inventory;
1362
1363 count = 0;
1364 inventory = UnitGetFar(ownerId)->inventory;
1365 remainingSlots = INVENTORY_SLOTS - 1;
1366 do {
1367 maskedItemId = ITEM_ID_MASK & *inventory;
1368 inventory += 1;
1369 if (maskedItemId != 0) {
1370 count += 1;
1371 }
1372 remainingSlots -= 1;
1373 } while (remainingSlots >= 0);
1374 return count;
1375}
1376
1377/// Returns how many of itemId the unit ownerId holds: the quantity of
1378/// its first stack, or 0. The Spanish and Italian editions add up every stack
1379/// of it.
1381 struct BattleUnit *unit;
1382 s32 slotIndex;
1383 s32 quantity;
1384
1385 quantity = 0;
1386 unit = UnitGetFar(ownerId);
1387 slotIndex = 0;
1388 do {
1389 if (unit->inventory[slotIndex] != 0 &&
1390 (unit->inventory[slotIndex] & ITEM_ID_MASK) == itemId) {
1391#if TBS_PATCH_4
1392 quantity += (unit->inventory[slotIndex] & INVENTORY_QUANTITY_MASK) >>
1394 quantity++;
1395#else
1396 quantity = (unit->inventory[slotIndex] & INVENTORY_QUANTITY_MASK) >>
1398 quantity++;
1399 break;
1400#endif
1401 }
1402 slotIndex++;
1403 } while (slotIndex < INVENTORY_SLOTS);
1404 return quantity;
1405}
1406
1407/// Copies the unit's items into the list items (32 entries), skipping empty
1408/// slots and clearing the rest. Returns how many there are. mode is not used.
1409s32 ItemMenu_CollectItems(struct BattleUnit *unit, u16 *items, s32 mode) {
1410 s32 itemCount;
1411 s32 slotIndex;
1412
1413 for (slotIndex = 0; slotIndex < 32; slotIndex++) {
1414 items[slotIndex] = 0;
1415 }
1416 itemCount = 0;
1417 for (slotIndex = 0; slotIndex < INVENTORY_SLOTS; slotIndex++) {
1418 items[slotIndex] = 0;
1419 if (unit->inventory[slotIndex] != 0) {
1420 items[itemCount] = unit->inventory[slotIndex];
1421 itemCount++;
1422 }
1423 }
1424 return itemCount;
1425}
1426
1427/// Loads each listed item's icon into its item icon sprite, the first 15
1428/// entries of inventoryEntries, and hides the icons of empty entries. iconStyle
1429/// 0 draws the list's icons; any other iconStyle the equipment view's (graphics
1430/// kind 7).
1431void ItemMenu_DrawIcons(u16 *inventoryEntries, s32 iconStyle) {
1432 s32 remaining;
1433 u16 *entries;
1434 struct RenderOutput **icons;
1435 s32 itemId;
1436
1437 icons = ((struct InventoryMenuState *)gMenuWork)->entryIcons;
1438 entries = inventoryEntries;
1439 remaining = INVENTORY_SLOTS - 1;
1440 do {
1441 itemId = *entries++;
1442 if (itemId != 0) {
1443 if (iconStyle == 0) {
1444 Resource_LoadByModeIntoSlotFar(2, itemId, (u8)(*icons)->index, 0);
1445 } else {
1446 Resource_LoadByModeIntoSlotFar(7, itemId, (u8)(*icons)->index, 0);
1447 }
1448 }
1449 icons++;
1450 remaining--;
1451 } while (remaining >= 0);
1452 Menu_HideEmptyEntryIcons(inventoryEntries);
1453}
1454
1455/// Shows member ownerId's items in the item window, laid out for layout mode
1456/// (see ItemMenu_RefreshEntry), or "no items" when there are none.
1458 struct InventoryMenuState *menu;
1459 struct BattleUnit *owner;
1460 u16 *items;
1461
1462 menu = gMenuWork;
1463 owner = UnitGetFar(ownerId);
1464 items = menu->items;
1465 menu->itemCount = ItemMenu_CollectItems(owner, items, 0);
1468 ItemMenu_DrawIcons(items, 0);
1469 if (ItemMenu_CountItems(ownerId) == 0)
1470 UiText_DrawCharacterAtOffsetFar(MsgItemMenuEmpty, menu->itemWindow, 8, 24);
1471}
1472
1473/// Nothing calls it.
1475
1476/// Shows in the status panel what the item in owner's inventory slot would mean
1477/// to member target: for a usable item, target's status; for equipment,
1478/// target's stats with it equipped; for a Psynergy item, the Psynergy it
1479/// teaches. When target is someone else, the item is put into a copy of
1480/// target's inventory for the preview, making room first if it is full, and
1481/// target is restored after. mode 1 redraws only the lower part of the panel.
1482void ItemMenu_DrawEquipPreview(s32 owner, s32 slot, s32 mode, s32 target) {
1483 /* FAKEMATCH(temporary): the saved unit reuses owner (and buffer for
1484 * Psynergy items), keeping owner in r8 and panelStyle in r10; as a separate
1485 * void *saved, 22 of 172 instructions differ in tbs-en. */
1486 struct InventoryMenuState *menu = gMenuWork;
1487 s32 panelStyle = 0;
1488 struct BattleUnit *unit = UnitGetFar(owner);
1489 s32 inventoryEntry = unit->inventory[slot];
1490 s32 previewSlot;
1491
1492 if (mode == 1)
1493 panelStyle = STATUS_PANEL_LOWER_ONLY;
1494 switch (Item_GetDirectFar(inventoryEntry & ITEM_ID_MASK)->type) {
1495 case 0: // usable items
1496 Menu_DrawOwnerStatusPanel(menu->statusWindow, target, slot, panelStyle);
1497 break;
1498 case 1: // weapons
1499 case 2: // armor
1500 case 3: // shields, gloves and armlets
1501 case 4: // helmets
1502 case 5: // boots
1503 case 7:
1504 case 8: // rings
1505 case 9: // shirts
1506 if (owner == target) {
1507 panelStyle |= STATUS_PANEL_EQUIP;
1508 Menu_DrawOwnerStatusPanel(menu->statusWindow, target, slot, panelStyle);
1509 } else {
1510 s32 size;
1511
1512 unit = UnitGetFar(target);
1513 size = BATTLE_UNIT_SIZE;
1514 owner = (s32)MemAlloc(size);
1515 Iwram_CopyWords((void *)owner, unit, size);
1516 previewSlot = Inventory_RemoveFirstUnflagged(target);
1517 if (previewSlot != 0) {
1518 inventoryEntry &= ~INVENTORY_EQUIPPED;
1519 previewSlot = Inventory_AddItemFar(target, inventoryEntry);
1520 if (previewSlot != -1) {
1521 panelStyle |= STATUS_PANEL_EQUIP;
1522 Menu_DrawOwnerStatusPanel(menu->statusWindow, target, previewSlot,
1523 panelStyle);
1524 } else {
1525 Menu_DrawOwnerStatusPanel(menu->statusWindow, target, slot,
1526 panelStyle);
1527 }
1528 } else {
1529 Menu_DrawOwnerStatusPanel(menu->statusWindow, target, slot, panelStyle);
1530 }
1531 Iwram_CopyWords(unit, (void *)owner, size);
1532 MemFree((void *)owner);
1533 }
1534 break;
1535 case 6: // Psynergy items
1536 if (target == owner) {
1537 panelStyle |= STATUS_PANEL_LEARN;
1538 Menu_DrawOwnerStatusPanel(menu->statusWindow, target, slot, panelStyle);
1539 } else {
1540 s32 size;
1541 void *buffer;
1542
1543 unit = UnitGetFar(target);
1544 size = BATTLE_UNIT_SIZE;
1545 owner = (s32)MemAlloc(size);
1546 buffer = (void *)owner;
1547 Iwram_CopyWords(buffer, unit, size);
1548 previewSlot = Inventory_RemoveFirstUnflagged(target);
1549 if (previewSlot != 0) {
1550 previewSlot = Inventory_AddItemFar(target, inventoryEntry);
1551 if (previewSlot != -1) {
1552 panelStyle |= STATUS_PANEL_LEARN;
1553 Menu_DrawOwnerStatusPanel(menu->statusWindow, target, previewSlot,
1554 panelStyle);
1555 } else {
1556 Menu_DrawOwnerStatusPanel(menu->statusWindow, target, slot,
1557 panelStyle);
1558 }
1559 } else {
1560 Menu_DrawOwnerStatusPanel(menu->statusWindow, target, slot, panelStyle);
1561 }
1562 Iwram_CopyWords(unit, (void *)owner, size);
1563 buffer = (void *)owner;
1564 MemFree(buffer);
1565 }
1566 break;
1567 }
1568}
1569
1570/// Makes room in ownerId's inventory: if no slot is free, removes the whole
1571/// stack in the first slot that is not equipped. Returns 1 when a slot is free
1572/// (or was freed), 0 otherwise.
1574 struct BattleUnit *unit = UnitGetFar(ownerId);
1575 s32 result = 0;
1576 s32 slotIndex;
1577
1578 for (slotIndex = 0; slotIndex < INVENTORY_SLOTS; slotIndex++) {
1579 if (unit->inventory[slotIndex] == 0) {
1580 result = 1;
1581 break;
1582 }
1583 if ((unit->inventory[slotIndex] & INVENTORY_EQUIPPED) == 0) {
1584 s32 quantity = unit->inventory[slotIndex] >> INVENTORY_QUANTITY_SHIFT;
1585 s32 count = quantity + 1;
1586 s32 removedCount;
1587
1588 if (quantity == 0)
1589 count = 1;
1590 for (removedCount = 0; removedCount < count; removedCount++)
1591 result = Inventory_RemoveFar(ownerId, slotIndex);
1592 if (result != 2)
1593 return 0;
1594 result = 1;
1595 break;
1596 }
1597 }
1598 return result;
1599}
1600
1601#if TBS_PATCH_1
1602
1603/// The x and y of the item command cursor on column and row of the command grid
1604/// (three commands to a row).
1606 if (column > 2 || row > 2 || column < 0 || row < 0)
1607 return 0;
1608 return gItemMenu_CommandColumnXTable[row * 3 + column];
1609}
1610
1612 s32 y;
1613
1614 (void)column;
1615 y = 30;
1616 if (row != 0) {
1617 y = 38;
1618 }
1619 return y;
1620}
1621#endif
1622
1623/// Each item command's state in the grid.
1624#define ITEM_COMMAND_STATE_DISABLED (-1)
1625#define ITEM_COMMAND_STATE_AVAILABLE 1
1626
1627/// The item command grid: Use, Equip and Details on the top row, Give, Remove
1628/// and Drop below (grid index = row * 3 + column, as ItemMenuCommand counts
1629/// them). Disabled commands are grey and refuse A. The status panel follows the
1630/// cursor: the owner's status on Use, the stats with the item equipped on Equip
1631/// and Details, and without it on the bottom row, where Give also shows who can
1632/// equip it. The cursor starts on the command chosen last, or on the first
1633/// available one. Returns the command chosen, or -1 when the player backs out.
1635 struct InventoryMenuState *menu;
1636 s8 commandStorage[6];
1637 u16 *redrawFlag;
1638 s32 column;
1639 s32 lastCommand;
1640 s32 row;
1641 s32 commandIndex;
1642 s32 redraw;
1643 s8 *commandStates;
1644#if TBS_PATCH_1
1645 s32 cursorX;
1646 s32 cursorY;
1647#endif
1648
1649 commandIndex = 0;
1650 column = 0;
1651 row = 0;
1652 menu = gMenuWork;
1653 redraw = 1;
1654 commandStates = commandStorage;
1655 ItemMenu_BuildCommands(commandStates);
1656 redrawFlag = &menu->flags;
1657 // Draw the item's name and the command grid, unless they are up already.
1658 if (*redrawFlag != 1) {
1659 struct UiWindow *messageWindow;
1660
1663 messageWindow = menu->messageWindow;
1665 RenderOutput_RedrawSavedRectFar((void *)messageWindow);
1666 UiWindow_DrawDividerLineFar(messageWindow, 0, 3, 16, 3);
1668 ItemMenu_DrawCommands(commandStates, messageWindow);
1669 MENU_RESET_INFO_WINDOW((void *)menu->infoWindow);
1671 MsgItemPlainName,
1672 menu->infoWindow, 0, 0);
1673 }
1674 *redrawFlag = 0;
1675
1676 // Start on the command chosen last, or on the first one available.
1677 lastCommand = (s8)menu->listMode;
1678 if (lastCommand == -1) {
1679 if (commandStates[ITEM_COMMAND_INSPECT] == ITEM_COMMAND_STATE_AVAILABLE) {
1680 column = 2;
1681 row = 0;
1682 }
1683 if (commandStates[ITEM_COMMAND_GIVE] == ITEM_COMMAND_STATE_AVAILABLE) {
1684 column = 0;
1685 row = 1;
1686 }
1687 if (commandStates[ITEM_COMMAND_EQUIP] == ITEM_COMMAND_STATE_AVAILABLE) {
1688 column = 1;
1689 row = 0;
1690 }
1691 if (commandStates[ITEM_COMMAND_REMOVE] == ITEM_COMMAND_STATE_AVAILABLE) {
1692 column = 1;
1693 row = 1;
1694 }
1695 if (commandStates[ITEM_COMMAND_USE] == ITEM_COMMAND_STATE_AVAILABLE) {
1696 column = 0;
1697 row = 0;
1698 }
1699 } else {
1700 column = (s8)(lastCommand % 3);
1701 row = (s8)(lastCommand / 3);
1702 commandIndex = row * 3 + column;
1703 }
1704#if TBS_PATCH_1
1705 cursorX = ItemMenu_CommandCursorX(column, row);
1706 cursorY = ItemMenu_CommandCursorY(column, row);
1707 UiMenu_SlideCursor(cursorX, cursorY);
1708#else
1709 UiMenu_SlideCursor(column * 40 + 86, row * 8 + 30);
1710#endif
1711
1712 for (;;) {
1714 break;
1715 if (redraw != 0) {
1716 redraw = 0;
1717 column = (column + 3) % 3;
1718 row = (row + 2) % 2;
1719 commandIndex = row * 3 + column;
1721 // Preview the item in the status panel for the command under the cursor.
1722 if (commandIndex > 2) {
1723 menu->equipPreview = 1;
1725 menu->paneOwner[0]);
1726 if (commandIndex == ITEM_COMMAND_GIVE) {
1729 }
1730 } else if (commandIndex != 0) {
1731 menu->equipPreview = 0;
1733 menu->paneOwner[0]);
1734 } else {
1737 }
1738 }
1739#if TBS_PATCH_1
1740 cursorX = ItemMenu_CommandCursorX(column, row);
1741 cursorY = ItemMenu_CommandCursorY(column, row);
1742 UiMenu_PositionCursor(cursorX, cursorY);
1743#else
1744 UiMenu_PositionCursor(column * 40 + 86, row * 8 + 30);
1745#endif
1746 WaitFrames(1);
1747
1748 if ((gKeysPressed & KEY_A) != 0) {
1749 if (commandStates[commandIndex] == ITEM_COMMAND_STATE_DISABLED) {
1751 } else {
1752 switch (commandIndex) {
1753 case ITEM_COMMAND_USE:
1755 break;
1756 case ITEM_COMMAND_EQUIP:
1757 AudioCommand_PlayFar(SE_175); // Equip
1758 break;
1760 case ITEM_COMMAND_GIVE:
1761 case ITEM_COMMAND_DROP:
1763 break;
1765 AudioCommand_PlayFar(SE_117); // Remove
1766 break;
1767 default:
1769 break;
1770 }
1771 menu->listMode = commandIndex;
1772 break;
1773 }
1774 }
1775 if ((gKeysPressed & KEY_B) != 0) {
1777 commandIndex = -1;
1778 menu->listMode = commandIndex;
1779 break;
1780 }
1781
1782 if ((gKeysRepeat & KEY_UP) != 0) {
1783 row -= 1;
1784 redraw = 1;
1786 } else if ((gKeysRepeat & KEY_DOWN) != 0) {
1787 row += 1;
1788 redraw = 1;
1790 } else if ((gKeysRepeat & KEY_RIGHT) != 0) {
1791 column += 1;
1792 redraw = 1;
1794 } else if ((gKeysRepeat & KEY_LEFT) != 0) {
1795 column -= 1;
1796 redraw = 1;
1798 }
1799 }
1800
1801 menu->equipPreview = 0;
1803 return commandIndex;
1804}
1805
1806/// Fills commandStates (indexed by ItemMenuCommand) for the selected item:
1807/// Use for usable items the owner can use here and for field items, Equip for
1808/// equipment the owner can wear and is not wearing, Remove for worn equipment
1809/// that is not cursed, Give with someone to give to, Drop unless the item is
1810/// indispensable, and neither for cursed equipment being worn.
1811void ItemMenu_BuildCommands(s8 *commandStates) {
1812 struct InventoryMenuState *menu;
1813 struct ItemDefinition *item;
1814
1815 menu = gMenuWork;
1816 item = Item_GetDirectFar(ITEM_ID_MASK & menu->selectedItems[0]);
1817
1818 if (item->type == 0) { // usable items
1821 } else {
1824 }
1825
1826 if (Item_ClassifyUseMode(menu->paneOwner[0], menu->selectedItems[0]) != -1)
1828 else
1830
1831 if (menu->selectedItems[0] & INVENTORY_BROKEN)
1833
1834 if (Item_CanOwnerEquip(menu->paneOwner[0],
1835 menu->selectedItems[0] & ITEM_ID_MASK) == 0) {
1837 }
1838
1842
1843 if (menu->selectedItems[0] & INVENTORY_EQUIPPED) {
1846 } else {
1848 }
1849
1850 if (item->flags & ITEM_CANNOT_UNEQUIP) {
1852 if (menu->selectedItems[0] & INVENTORY_EQUIPPED) {
1855 }
1856 }
1857
1860
1861 if (menu->partyCount <= 1)
1863
1864 if (item->flags & ITEM_INDISPENSABLE)
1866}
1867
1868#define TEXT_COLOR_DISABLED 14
1869
1870/// Writes the six command names into window, the disabled ones in grey.
1871void ItemMenu_DrawCommands(const s8 *commandStates, struct UiWindow *window) {
1872 s32 disabled;
1873 s32 useState;
1874 u32 firstCommandMessage;
1875
1877 useState = commandStates[ITEM_COMMAND_USE];
1878 disabled = ITEM_COMMAND_STATE_DISABLED;
1879 if (useState == disabled)
1881
1882 firstCommandMessage = MsgItemCommandUse;
1883 UiText_DrawCharacterAtOffsetFar(firstCommandMessage, window, 0, 24); // "Use"
1885 if (commandStates[ITEM_COMMAND_EQUIP] == disabled)
1887 UiText_DrawCharacterAtOffsetFar(firstCommandMessage + 1, window,
1889 24); // "Equip"
1891 if (commandStates[ITEM_COMMAND_GIVE] == disabled)
1893 UiText_DrawCharacterAtOffsetFar(firstCommandMessage + 2, window, 0,
1894 32); // "Give"
1896 if (commandStates[ITEM_COMMAND_DROP] == disabled)
1898 UiText_DrawCharacterAtOffsetFar(firstCommandMessage + 3, window, 80,
1899 32); // "Drop"
1901 if (commandStates[ITEM_COMMAND_INSPECT] == disabled)
1903 UiText_DrawCharacterAtOffsetFar(firstCommandMessage + 4, window, 80,
1904 24); // "Details"
1906 if (commandStates[ITEM_COMMAND_REMOVE] == disabled)
1908 // "Remove"
1909 UiText_DrawCharacterAtOffsetFar(firstCommandMessage + 5, window,
1912}
1913
1914/// Says how ownerId can use inventoryEntry from the item menu:
1915/// 0 the item works on the field (BattleFx_HasTriggerFar), or its action is
1916/// usable neither in the field nor in battle, and is used once the menu
1917/// closes;
1918/// 1 usable in the field: choose a party member to use it on;
1919/// 2 usable in the field on the whole party at once (range 0xff);
1920/// -1 it cannot be used here: it has no action, it is equipment the owner
1921/// cannot wear or of use type 3, or its action is usable only in battle.
1922/// Usable items always qualify; equipment only when the owner can wear it.
1923s32 Item_ClassifyUseMode(s32 ownerId, s32 inventoryEntry) {
1924 s32 itemId = inventoryEntry;
1925 struct ItemDefinition *itemDefinition;
1926 s32 result = -1;
1927
1928 itemId &= ITEM_ID_MASK;
1929 itemDefinition = Item_GetDirectFar(itemId);
1930
1931 if (BattleFx_HasTriggerFar(itemId) != 0) {
1932 return 0;
1933 }
1934
1935 {
1936 struct BattleAct *action =
1937 BattleActGet(itemDefinition->actionId & OWNER_ACTION_ID_MASK);
1938
1939 if (itemDefinition->actionId != 0) {
1940 if (itemDefinition->type != 0) { // equipment
1941 if (itemDefinition->useType != 3) {
1942 if (Item_CanOwnerEquip(ownerId, itemId) != 0) {
1943 result = 1;
1944 }
1945 }
1946 } else {
1947 result = 1;
1948 }
1949
1950 if (result == 1) {
1952 u8 flags = action->flags;
1953
1954 if ((flags & ACTION_USABLE_IN_FIELD) != 0) {
1955 u8 range = action->range;
1956 result = (range == 0xff) ? 2 : 1;
1957 } else {
1958 result = (flags & mask) ? -1 : 0;
1959 }
1960 }
1961 }
1962 }
1963
1964 return result;
1965}
1966
1967/// After the selected item is used: an item of use type 2 breaks one time in
1968/// eight, with the break sound. "It broke!"
1970 struct InventoryMenuState *menu;
1971
1972 menu = gMenuWork;
1973 // One time in eight.
1975 2) &&
1976 (Random16() < 0x2000U)) {
1977 Inventory_BreakFar(menu->paneOwner[0], menu->selectedSlots[0]);
1979 InventoryMenu_ShowModalMessage(MsgItemBroke, 0, -1);
1980#if !TBS_PATCH_1
1982#endif
1983 }
1984}
1985
1986/// Opens the details window (top left, 13 by 10 tiles) and describes the item
1987/// in pane itemIndex there. Returns 1.
1989 struct InventoryMenuState *menu = gMenuWork;
1990
1991 UiWindow_UpdateOrCreate(&menu->equipWindow, 0, 0, 13, 10, 2);
1993
1994 if (menu->selectedItems[itemIndex] != 0)
1995 ItemMenu_DrawItemDetails(menu->equipWindow, menu->selectedItems[itemIndex]);
1996
1997 return 1;
1998}
1999
2000/// The item menu's Details screen: describes the item entry value in a large
2001/// window (the whole top half after patch 1) and waits for A or B. Up and Down
2002/// move an unused counter from 0 to 4. Returns the counter, or -1 after B.
2004#if TBS_PATCH_1
2005 s32 changed = 1;
2006 struct InventoryMenuState *menu = gMenuWork;
2007 struct RenderOutput *itemIcon = menu->selectedItemIcon;
2008#else
2009 struct InventoryMenuState *menu = gMenuWork;
2010 s32 changed = 1;
2011#endif
2012 struct UiWindow *window;
2013 s32 counter = 0;
2014
2015#if TBS_PATCH_1
2016 itemIcon->active = ICON_HIDDEN;
2017#endif
2018 window = UiWindow_CreateFar(0, 0, ITEM_QUANTITY_WINDOW_WIDTH, 10, 2);
2019 // Freeze the party figures and hide the cursor meanwhile.
2021
2022 {
2023 struct RenderOutput *cursor = menu->cursor;
2024 cursor->active = ICON_HIDDEN;
2025 }
2027 WaitFrames(1);
2028
2029 for (;;) {
2031 break;
2032
2033 if (changed != 0) {
2034 changed = 0;
2035 counter = (counter + 5) % 5;
2036 ItemMenu_DrawItemDetails(window, value);
2037 }
2038
2039 if (gKeysPressed & KEY_A)
2040 break;
2041 if (gKeysPressed & KEY_B) {
2042 counter = -1;
2043 break;
2044 }
2045
2046 if (gKeysRepeat & KEY_UP) {
2047 counter -= 1;
2048 changed = 1;
2049 }
2050 if (gKeysRepeat & KEY_DOWN) {
2051 counter += 1;
2052 changed = 1;
2053 }
2054 WaitFrames(1);
2055 }
2056
2057 // Close the window and bring the menu back.
2059 WaitFrames(1);
2060 UiWork_FinalizeFar((void *)window, 1);
2063 {
2064 s32 priority = 0xc80;
2065
2067 }
2068
2069 {
2070 struct RenderOutput *cursor = menu->cursor;
2071#if TBS_PATCH_1
2072 cursor->active = ICON_SHOWN;
2073#else
2074 u8 one = 1;
2075
2076 cursor->active = one;
2077 menu->flags = one;
2078#endif
2079 }
2080#if TBS_PATCH_1
2081 UiWindow_DrawFrameFar(13, 0, 17, 10);
2082#endif
2083
2084 return counter;
2085}
2086
2087/// Writes the description of the inventoryEntry into window, one line a row:
2088/// for equipment its Attack and Defense bonuses, then each of its effects
2089/// (flat bonuses, rates as multipliers, elemental Power and Resist with the
2090/// element's icon, and the effects that are only text), whether it is cursed or
2091/// bestows Psynergy, whether it is used up or may break, and for a stack how
2092/// many there are. An item with nothing to say is rare, important, or
2093/// undescribed.
2094void ItemMenu_DrawItemDetails(struct UiWindow *window, s32 inventoryEntry) {
2095 struct ItemDefinition *def;
2096 s32 i;
2097 s32 hasEffects;
2098 s32 amount;
2099 s32 bestowsPsynergy;
2100 s8 row;
2101
2102 row = 0;
2103 bestowsPsynergy = 0;
2104 def = Item_GetDirectFar(inventoryEntry & ITEM_ID_MASK);
2105 // Equipment: a heading, then its Attack and Defense bonuses.
2106 if (def->type != 0) {
2107 hasEffects = 0;
2108 if (def->primaryBonus == 0 && def->secondaryBonus == 0) {
2109 for (i = 0; i < 4; i++) {
2110 if (def->effects[i].kind != 0 || def->useType == 3) {
2111 hasEffects = 1;
2112 break;
2113 }
2114 }
2115 } else {
2116 hasEffects = 1;
2117 }
2118 if (hasEffects == 1) {
2119 UiText_DrawCharacterAtOffsetFar(MsgEquipEffectHeading, window, 16, 0);
2120 row = 1;
2121 }
2122 if (def->primaryBonus != 0) {
2123 UiText_DrawCharacterAtOffsetFar(MsgStatLabel, window, 0, row * 8);
2124 amount = def->primaryBonus;
2125 ItemMenu_DrawStat(amount, 3, window, 64, row * 8);
2126 row++;
2127 }
2128 if (def->secondaryBonus != 0) {
2129 UiText_DrawCharacterAtOffsetFar(MsgDefenseLabel, window, 0, row * 8);
2130 amount = def->secondaryBonus;
2131 ItemMenu_DrawStat(amount, 3, window, 64, row * 8);
2132 row++;
2133 }
2134 }
2135 // Each of its effects.
2136 for (i = 0; i < 4; i++) {
2137 if (def->effects[i].kind == 0)
2138 continue;
2139 amount = def->effects[i].amount;
2140 switch (def->effects[i].kind) {
2141 case ITEM_EFFECT_NONE:
2142 break;
2143 case ITEM_EFFECT_ADD_HP:
2145 case ITEM_EFFECT_ADD_PP:
2149 case 26: // Turns
2150 UiText_DrawCharacterAtOffsetFar(def->effects[i].kind + MsgEquipEffectName,
2151 window, 0, row * 8);
2152 ItemMenu_DrawStat(amount, 3, window, 64, row * 8);
2153 break;
2154 // Power (15 to 18) and Resist (19 to 22) of the four elements, after
2155 // the element's icon.
2156 case 15:
2157 case 16:
2158 case 17:
2159 case 18:
2160 case 19:
2161 case 20:
2162 case 21:
2163 case 22:
2165 window, (u8)((def->effects[i].kind - 15) % 4) + 1, 0, row, 2);
2166 UiText_DrawCharacterAtOffsetFar(def->effects[i].kind + MsgEquipEffectName,
2167 window, 8, row * 8);
2168 ItemMenu_DrawStat(amount, 3, window, 64, row * 8);
2169 break;
2170 // Rates, in tenths: shown as a multiplier from 0.0 to 1.9.
2179 UiText_DrawCharacterAtOffsetFar(def->effects[i].kind + MsgEquipEffectName,
2180 window, 0, row * 8);
2181#if LANGUAGE != LANGUAGE_JAPANESE
2182 UiText_DrawStringInWindowFar(gMenu_TimesString, window, 64, row * 8);
2183 if (amount > 9) {
2184 UiText_DrawNumberInWindowFar(1, 1, window, 72, row * 8);
2185 UiText_DrawStringInWindowFar(gMenu_PointString, window, 80, row * 8);
2186 UiText_DrawNumberInWindowFar(amount - 10, 1, window, 88, row * 8);
2187 } else {
2188 UiText_DrawNumberInWindowFar(0, 1, window, 72, row * 8);
2189 UiText_DrawStringInWindowFar(gMenu_PointString, window, 80, row * 8);
2190 UiText_DrawNumberInWindowFar(amount, 1, window, 88, row * 8);
2191 }
2192#else
2193 if (amount > 9) {
2194 UiText_DrawNumberInWindowFar(1, 1, window, 48, row * 8);
2195 UiText_DrawStringInWindowFar(gMenu_PointString, window, 56, row * 8);
2196 UiText_DrawNumberInWindowFar(amount - 10, 1, window, 64, row * 8);
2197 } else {
2198 UiText_DrawNumberInWindowFar(0, 1, window, 48, row * 8);
2199 UiText_DrawStringInWindowFar(gMenu_PointString, window, 56, row * 8);
2200 UiText_DrawNumberInWindowFar(amount, 1, window, 64, row * 8);
2201 }
2202 UiText_DrawCharacterAtOffsetFar(MsgEffectRateSuffix, window, 72, row * 8);
2203#endif
2204 break;
2205 case 23: // "Critical Hits increase"
2206 case 25: // "The curse can be removed"
2207 case 27: // "Boosts monster encounters"
2208 UiText_DrawCharacterAtOffsetFar(def->effects[i].kind + MsgEquipEffectName,
2209 window, 0, row * 8);
2210 break;
2211 }
2212 row++;
2213 }
2214 // Curses, bestowed Psynergy and how the item is used up.
2215 if (def->flags & ITEM_CURSED) {
2216 UiText_DrawCharacterAtOffsetFar(MsgItemCursed, window, 0, row * 8);
2217 row++;
2218 }
2219 if (def->useType == 3) { // bestows Psynergy
2220 UiText_DrawCharacterAtOffsetFar(MsgBestowsPsynergy, window, 0, row * 8);
2221 bestowsPsynergy = 1;
2222 row++;
2223 }
2224 if (def->useType != 4 && def->useType != 0) {
2225 if (!bestowsPsynergy) {
2226 UiText_DrawCharacterAtOffsetFar(MsgUsesHeading, window, 16, row * 8);
2227 row++;
2228 }
2229 switch (def->useType) {
2230 case 0:
2231 break;
2232 case 1: // used up
2233 UiText_DrawCharacterAtOffsetFar(MsgSingleUse, window, 0, row * 8);
2234 row++;
2235 break;
2236 case 2: { // may break
2237 s32 m;
2238
2239 if (inventoryEntry & INVENTORY_BROKEN) {
2240 m = MsgBrokenNotice;
2241 UiText_DrawCharacterAtOffsetFar(m, window, 0, row * 8);
2242 row++;
2243 m++;
2244 UiText_DrawCharacterAtOffsetFar(m, window, 0, row * 8);
2245 row++;
2246 } else {
2247 m = MsgMightBreak;
2248 UiText_DrawCharacterAtOffsetFar(m, window, 0, row * 8);
2249 row++;
2250 m++;
2251 UiText_DrawCharacterAtOffsetFar(m, window, 0, row * 8);
2252 row++;
2253 }
2254 break;
2255 }
2256 }
2257 }
2258 // How many there are in a stack.
2259 if (def->flags & ITEM_STACKABLE) {
2260 if (row != 0)
2261 row++;
2262 i = MsgNumberHeading;
2263 UiText_DrawCharacterAtOffsetFar(i, window, 16, row * 8);
2264 row++;
2265 amount =
2267#if LANGUAGE != LANGUAGE_JAPANESE
2268 UiWork_PushValueSlotFar(amount + 1, 5);
2269 UiText_DrawCharacterAtOffsetFar(i + 1, window, 0, row * 8);
2270#else
2271 UiText_DrawNumberInWindowFar(amount + 1, 2, window, 0, row * 8);
2272 UiText_DrawCharacterAtOffsetFar(i + 1, window, 16, row * 8);
2273#endif
2274 row++;
2275 }
2276 // Nothing written yet: rare, important, or nothing known.
2277 hasEffects = 0;
2278 if (row == 0) {
2279 if (def->flags & 4) { // rare
2280 UiText_DrawCharacterAtOffsetFar(MsgRareItem, window, 0, 0);
2281 hasEffects = 1;
2282 }
2283 if (!hasEffects) {
2284 if (def->flags & ITEM_INDISPENSABLE) {
2285 UiText_DrawCharacterAtOffsetFar(MsgImportantItem, window, 0, 0);
2286 hasEffects = 1;
2287 }
2288 if (!hasEffects)
2289 UiText_DrawCharacterAtOffsetFar(MsgDetailsUnknown, window, 0, 0);
2290 }
2291 }
2292}
2293
2294/// Writes a signed stat change at (x, y) of window: the number, with a plus or
2295/// minus sign just before its first digit.
2296void ItemMenu_DrawStat(s32 statChange, s32 unused, struct UiWindow *window,
2297 s32 x, s32 y) {
2298 s32 digits;
2299 s32 magnitude;
2300
2301 UiText_DrawNumberInWindowFar(statChange, 3, window, x, y);
2302 // Count the digits of |statChange| to place the sign.
2303 digits = 1;
2304 magnitude = statChange;
2305 if (statChange < 0) {
2306 magnitude = -statChange;
2307 }
2308 if (magnitude > 9) {
2309 digits = 2;
2310 }
2311 magnitude = statChange;
2312 if (statChange < 0) {
2313 magnitude = -statChange;
2314 }
2315 if (magnitude > 99) {
2316 digits = 3;
2317 }
2318 if (statChange > 0) {
2320 x - digits * 8 + 16, y);
2321 } else {
2323 x - digits * 8 + 16, y);
2324 }
2325}
2326
2327/// Moves the item window to row 5 of the right-hand side.
2330 (struct UiWindow *)((struct InventoryMenuState *)gMenuWork)->itemWindow,
2331 13, 5, 17, 10);
2332}
2333
2334/// Moves the item window to row 3 of the right-hand side.
2337 (struct UiWindow *)((struct InventoryMenuState *)gMenuWork)->itemWindow,
2338 13, 3, 17, 10);
2339}
2340
2341/// Makes the message window, along the top right, 5 rows tall.
2344 ->messageWindow,
2345 13, 0, 17, 5);
2346}
2347
2350 ->messageWindow,
2351 13, 0, 17, 6);
2352}
2353
2356 ->messageWindow,
2357 13, 0, 17, 7);
2358}
2359
2362 ->messageWindow,
2363 13, 0, 17, 3);
2364}
2365
2366/// Asks how many of the selected item stack to give or drop: Left and Right
2367/// choose a number from 1 to quantityRange (shown as baseQuantity + 1 up to
2368/// baseQuantity + quantityRange on a dial of digit sprites), with the owner's
2369/// remaining count and, when giving (dropMode 0), the receiver's new count
2370/// beside their names. Returns the number less one, or -1 when the player backs
2371/// out.
2372s32 ItemMenu_SelectGiveQuantity(s32 baseQuantity, s32 quantityRange,
2373 s32 dropMode) {
2374 s32 quantity = baseQuantity;
2375 s32 block;
2376 s32 changed;
2377 s32 receiverCount;
2378 s32 ownerCount;
2379 struct InventoryMenuState *menu = gMenuWork;
2380 void *tiles = Runtime_AllocateBlock(14, 0x400);
2381 struct UiWindow *window;
2382 struct RenderOutput *rightDial;
2383
2384 changed = 1;
2385 receiverCount = 0;
2386 window = menu->messageWindow;
2389 // How many each member holds now.
2390 if (dropMode == 0)
2391 receiverCount = InventoryMenu_GetItemQuantity(
2392 menu->paneOwner[1], menu->selectedItems[0] & ITEM_ID_MASK);
2393 ownerCount = InventoryMenu_GetItemQuantity(
2394 menu->paneOwner[0], menu->selectedItems[0] & ITEM_ID_MASK);
2395 // Two dial sprites, left and right of the number.
2396 block = Resource_FindFreeEntry();
2397 if (block != 96) { // 96: no free VRAM block
2398 VramCache_Load(block, 256, 0);
2399 RenderOutput_CreateFar(block, 0x40004000, window, 48, 32);
2400 rightDial = RenderOutput_CreateFar(block, 0x40004000, window, 80, 32);
2401 rightDial->oam.index += 4;
2404 if (changed) {
2405 changed = 0;
2406 quantity = (quantityRange + quantity) % quantityRange;
2408 UiText_DrawCharacterAtOffsetFar(MsgGiveHowMany, window, ITEM_GIVE_ASK_X,
2411 (DMA_ENABLE | DMA_32BIT) << 16 | 0x40, REG_DMA3);
2412 Shop_FillSelectorFar(30, 14, tiles);
2413 Shop_FillSelectorFar(quantityRange + baseQuantity, 0, tiles);
2414 Shop_FillSelectorFar(baseQuantity + quantity + 1, 10, tiles);
2415 Shop_FillSelectorFar(baseQuantity, 2, tiles);
2416 VramCache_Load(block, 256, tiles);
2417 UiText_DrawNumberInWindowFar(quantity + 1, 2, window, 32, 32);
2419 (menu->selectedItems[0] & ITEM_ID_MASK) + MsgItemName, window, 16,
2420 8);
2421 UiText_DrawNumberInWindowFar(ownerCount - quantity - 1, 2, window, 16,
2422 24);
2423#if LANGUAGE != LANGUAGE_JAPANESE
2424 if (dropMode == 0)
2425 UiText_DrawNumberInWindowFar(receiverCount + quantity + 1, 2, window,
2426 80, 24);
2427#else
2428 UiText_DrawCharacterAtOffsetFar(MsgItemCounter, window, 32, 24);
2429 if (dropMode == 0) {
2430 UiText_DrawNumberInWindowFar(receiverCount + quantity + 1, 2, window,
2431 80, 24);
2432 UiText_DrawCharacterAtOffsetFar(MsgItemCounter, window, 96, 24);
2433 }
2434#endif
2436 window, 16, 16);
2437 if (dropMode == 0)
2439 window, 80, 16);
2440 }
2441 // A confirms, B backs out, Left and Right change the number.
2442 if (gKeysPressed & KEY_A) {
2444 break;
2445 }
2446 if (gKeysPressed & KEY_B) {
2447 quantity = -1;
2449 break;
2450 }
2452 if (gKeysRepeat & KEY_LEFT) {
2453 quantity--;
2454 changed = 1;
2456 }
2457 if (gKeysRepeat & KEY_RIGHT) {
2458 quantity++;
2459 changed = 1;
2461 }
2462 WaitFrames(1);
2463 }
2464 }
2466 RenderOutput_ClearListFar((void *)window);
2470 quantity = -1;
2471 return quantity;
2472}
2473
2474/// Shows the selected item at the top of the message window: its icon, its
2475/// owner's name and its name.
2477 struct InventoryMenuState *menu = gMenuWork;
2478
2480 (u8)menu->selectedItemIcon->index, 0);
2482 menu->selectedItemIcon->x = 112;
2483 menu->selectedItemIcon->y = 8;
2486 menu->messageWindow, 16, 0);
2488 MsgItemName,
2489 menu->messageWindow, 16, 8);
2490}
2491
2492/// Asks whether to drop item (an inventory entry): its name, the question, and
2493/// Yes or No, No first. Returns 0 for Yes and 1 for No, B or Start.
2495 struct UiWindow *window;
2496 s32 itemId;
2497 s32 question;
2498 s32 answer;
2499 s32 rows = 2;
2500 s32 selection = 1;
2501 s32 changed = 1;
2502
2503 window = UiWindow_CreateFar(13, 3, 17, 10, 2);
2504 itemId = item & ITEM_ID_MASK;
2505 Item_GetDirectFar(itemId);
2506 UiText_DrawCharacterAtOffsetFar(itemId + MsgItemName, window, 24, 0);
2507 question = MsgConfirmDrop;
2509 question++;
2511 answer = MsgYes;
2512 UiText_DrawCharacterAtOffsetFar(answer, window, 24, 40);
2513 answer++;
2514 UiText_DrawCharacterAtOffsetFar(answer, window, 24, 56);
2515 UiMenu_SlideCursor(104, 86);
2516 for (;;) {
2518 break;
2519 if (changed) {
2520 changed = 0;
2521 selection = (selection + rows) % rows;
2522 }
2523 if (gKeysPressed & KEY_A) {
2525 break;
2526 }
2527 if (gKeysPressed & KEY_B) {
2529 selection = 1;
2530 break;
2531 }
2532 UiMenu_PositionCursor(104, (selection << 4) + 70);
2533 if (gKeysRepeat & KEY_UP) {
2534 selection--;
2535 changed = 1;
2537 }
2538 if (gKeysRepeat & KEY_DOWN) {
2539 selection++;
2540 changed = 1;
2542 }
2543 WaitFrames(1);
2544 }
2546 selection = 1;
2547 }
2548 UiWork_FinalizeFar((void *)window, 1);
2549 return selection;
2550}
2551
2552/// After giving or trading the selected item to the member in pane 1, offers to
2553/// equip it there, showing the stats it would give. Returns 0 when it is
2554/// equipped; 1 when the player says No, backs out, or the member cannot equip
2555/// it, and the member is left as before.
2557 s32 rows = 2;
2558 s32 selection = 0;
2559 s32 changed = 1;
2560 struct InventoryMenuState *menu = gMenuWork;
2561 struct BattleUnit *unit = UnitGetFar(menu->paneOwner[1]);
2562 struct BattleUnit *saved;
2563 struct UiWindow *window;
2564 s32 slot;
2565 s32 owner;
2566
2567 slot = menu->selectedSlots[1];
2568 owner = menu->paneOwner[1];
2569 ItemMenu_DrawEquipPreview(owner, slot, 0, owner);
2570 saved = MemAlloc(BATTLE_UNIT_SIZE);
2571 Iwram_CopyWords(saved, unit, BATTLE_UNIT_SIZE);
2572 window = menu->messageWindow;
2573 // Equip it now; a result of -1 or -2 means it cannot be equipped.
2574 if ((u32)(Inventory_EquipFar(menu->paneOwner[1], menu->selectedSlots[1]) +
2575 2) <= 1) {
2576 selection = 1;
2577 } else {
2578#if TBS_PATCH_1
2579 UiText_DrawCharacterAtOffsetFar(MsgYes, window, 24, 24);
2580 UiText_DrawCharacterAtOffsetFar(MsgYes + 1, window, 72, 24);
2581 UiWindow_ClearInteriorTilesFar((void *)window, 16, 16, 96, 24);
2582 UiText_DrawCharacterAtOffsetFar(MsgEquipThisItem, window, 0, 16);
2583 UiMenu_SlideCursor(110, 32);
2584#else
2585 UiText_DrawCharacterAtOffsetFar(MsgYes, window, 96, 0);
2586 UiText_DrawCharacterAtOffsetFar(MsgYes + 1, window, 96, 16);
2587 UiWindow_ClearInteriorTilesFar((void *)window, 16, 16, 96, 24);
2588 UiText_DrawCharacterAtOffsetFar(MsgEquipThisItem, window, 8, 16);
2589 UiMenu_SlideCursor(184, 5);
2590#endif
2591 for (;;) {
2593 break;
2594 if (changed) {
2595 changed = 0;
2596 selection = (selection + rows) % rows;
2597 }
2598 if (gKeysPressed & KEY_A) {
2599 AudioCommand_PlayFar(SE_175); // the Equip sound
2600 break;
2601 }
2602 if (gKeysPressed & KEY_B) {
2604 selection = 1;
2605 break;
2606 }
2607#if TBS_PATCH_1
2608 UiMenu_PositionCursor(selection * 48 + 110, 32);
2609 if (gKeysRepeat & KEY_LEFT) {
2610#else
2611 UiMenu_PositionCursor(184, (selection << 4) + 5);
2612 if (gKeysRepeat & KEY_UP) {
2613#endif
2614 selection--;
2615 changed = 1;
2617 }
2618#if TBS_PATCH_1
2619 if (gKeysRepeat & KEY_RIGHT) {
2620#else
2621 if (gKeysRepeat & KEY_DOWN) {
2622#endif
2623 selection++;
2624 changed = 1;
2626 }
2627 WaitFrames(1);
2628 }
2629 }
2631 selection = 1;
2632 // No: put the member back as they were.
2633 if (selection == 1)
2634 Iwram_CopyWords(unit, saved, BATTLE_UNIT_SIZE);
2635 MemFree(saved);
2636 UnitCalcFar(menu->paneOwner[1]);
2638 return selection;
2639}
2640
2641/// Loads the stat arrows (up and down) into two free VRAM blocks, kept in the
2642/// menu work's resource slots.
2644 struct InventoryMenuState *menu = gMenuWork;
2645 s32 block = Resource_FindFreeEntry();
2646
2647 menu->resourceSlots[0] = block;
2648 VramCache_Load(block, 128, gMenu_ArrowTiles);
2649 block = Resource_FindFreeEntry();
2650 menu->resourceSlots[1] = block;
2652}
2653
2654/// Fills result with the item list of the member in pane index: their unit,
2655/// how many items they hold, and the page and row of the item chosen last for
2656/// them (kept within the list), five items to a page. Returns 1.
2657s32 ItemMenu_PageResult(struct MenuResult *result, s32 index) {
2658 s32 unit;
2659 struct InventoryMenuState *menu = gMenuWork;
2660 s32 itemCount;
2661 s32 row;
2662 s32 page;
2663 s32 pageCount;
2664 s32 selected;
2665
2666 itemCount = ItemMenu_CountItems(menu->paneOwner[index]);
2667 unit = (s32)UnitGetFar(menu->paneOwner[index]);
2668 selected = menu->selectedIndexByOwner[menu->paneOwner[index]];
2669 if ((selected + 1) > itemCount) {
2670 selected = itemCount - 1;
2671 }
2672 page = selected / LIST_PAGE_SIZE;
2673 row = selected % LIST_PAGE_SIZE;
2674 pageCount = itemCount / LIST_PAGE_SIZE;
2675 if (itemCount % LIST_PAGE_SIZE != 0) {
2676 pageCount++;
2677 }
2678 result->ownerState = unit;
2679 result->page = page;
2680 result->pageCount = pageCount;
2681 result->row = row;
2682 result->entryCount = itemCount;
2683 result->selectedIndex = selected;
2684 return 1;
2685}
2686
2687/// Updates the item list for the row under the cursor: puts the selected item's
2688/// plain name in the info window and highlights its row of the five. window and
2689/// ownerWork are not used.
2690s32 ItemMenu_DrawItemDetailPage(struct UiWindow *window, void *ownerWork,
2691 struct MenuResult *pageState) {
2692 struct InventoryMenuState *menu;
2693 s32 page;
2694 s32 index;
2695 s32 row;
2696
2697 page = pageState->page;
2698 menu = gMenuWork;
2699 index = page * LIST_PAGE_SIZE;
2700 index += pageState->row;
2701 pageState->selectedIndex = index;
2702
2704 WaitFrames(1);
2705
2706 index = pageState->selectedIndex;
2707 if (menu->items[index] != 0) {
2708 s32 name = (menu->items[index] & ITEM_ID_MASK) + MsgItemPlainName;
2709 MENU_DRAW_INFO_TEXT(name, menu->infoWindow, 0, 0);
2710 }
2711
2712 row = 0;
2713 do {
2714 if (row == pageState->row) {
2715 Render_SetTilemapFlagRect((void *)menu->itemWindow, 1, row * 2 + 1, 14, 1,
2716 14); // highlighted
2717 } else {
2718 Render_SetTilemapFlagRect((void *)menu->itemWindow, 1, row * 2 + 1, 14, 1,
2719 15); // normal
2720 }
2721 row++;
2722 } while (row < LIST_PAGE_SIZE);
2723
2724 WaitFrames(1);
2725 return 1;
2726}
2727
2728/// Draws one page of the item list into window: up to five item names with
2729/// their icons, and the page numbers when there is more than one page.
2730s32 ItemMenu_DrawNamePage(struct UiWindow *window, s32 unused,
2731 const struct MenuResult *pageState) {
2732 struct InventoryMenuState *menu = gMenuWork;
2733 u32 page;
2734 u32 firstEntry;
2735 u32 visibleCount;
2736 u8 row;
2737 const u16 *entry;
2738
2739 (void)unused;
2740
2742 UiWindow_DrawDividerLineFar(window, 0, 11, 16, 11);
2743
2744 page = pageState->page;
2745 firstEntry = page * LIST_PAGE_SIZE;
2746 visibleCount = (u8)(pageState->entryCount - firstEntry);
2747 if (visibleCount > LIST_PAGE_SIZE) {
2748 visibleCount = LIST_PAGE_SIZE;
2749 }
2750
2752 34);
2754 pageState->page, 15);
2755
2756 row = 0;
2757 if (visibleCount > row) {
2758 entry = &menu->items[firstEntry];
2759 do {
2760 UiText_DrawCharacterAtOffsetFar((entry[0] & ITEM_ID_MASK) + MsgItemName,
2762 row * 16 + 8);
2763 row++;
2764 entry++;
2765 } while (visibleCount > row);
2766 }
2767
2768 return 1;
2769}
2770
2771/// Nothing calls it.
2773
2774/// Nothing calls it.
2776
2777/// The item list of the member in paneIndex (0: the owner, 1: the receiver of a
2778/// trade), five items a page. The cursor's item is named in the info window and
2779/// previewed in the status panel, its icon animates, and the party members who
2780/// can equip it move. Up and Down move the cursor, Left and Right turn pages,
2781/// and in paneIndex 0 L and R switch to the previous or next member who has
2782/// items. Returns the chosen inventory entry, or -1 when the player backs out.
2784 struct InventoryMenuState *menu;
2785 struct UiWindow *window;
2786 s32 changed;
2787 s32 moved;
2788 s32 member;
2789 u8 i;
2790 s32 result;
2791 s32 redraw;
2792 s32 done;
2793 struct BattleUnit *owner;
2794 s32 previous;
2795 struct RenderOutput *icon;
2796 s32 work[5];
2797 struct MenuResult state;
2798
2799 menu = gMenuWork;
2800 result = 0;
2801 previous = 0;
2802 menu->equipPreview = result;
2803 UiWindow_UpdateOrCreate(&menu->listWindow, 13, 3, 17, 14, 2);
2804 window = menu->listWindow;
2805 done = 0;
2806
2807 while (done == 0 && GameFlag_TestFar(FLAG_MENU_START_PRESSED) == 0) {
2808 owner = UnitGetFar(menu->paneOwner[paneIndex]);
2809 menu->itemCount = ItemMenu_CollectItems(owner, menu->items, 0);
2810 ItemMenu_DrawIcons(menu->items, 0);
2812 ItemMenu_PageResult(&state, paneIndex);
2813 UiMenu_PositionCursor(98, state.selectedIndex * 16 + 36);
2814 changed = 1;
2815 redraw = 1;
2816
2817 // One member's list, until an item is chosen or the member changes.
2819 UiMenu_PositionCursor(98, state.row * 16 + 36);
2820
2821 if (changed != 0) {
2822 changed = 0;
2823 if (owner->inventory[previous] != 0) {
2824 icon = menu->entryIcons[previous];
2826 }
2827 if (redraw != 0) {
2828 WaitFrames(1);
2829 ItemMenu_DrawNamePage(window, 0, &state);
2830 if (paneIndex == 0) {
2831 UiText_DrawCharacterAtOffsetFar(MsgChangeCharacterHelp, window,
2832 HELP_TEXT_X, 88);
2833 }
2834 redraw = 0;
2835 }
2836 ItemMenu_DrawItemDetailPage(window, work, &state);
2837 menu->selectedItems[paneIndex] = menu->items[state.selectedIndex];
2838 ItemMenu_DrawEquipPreview(menu->paneOwner[paneIndex],
2839 state.selectedIndex, 0,
2840 menu->paneOwner[paneIndex]);
2841 if (menu->items[state.selectedIndex] != 0) {
2842 icon = menu->entryIcons[state.selectedIndex];
2843 // Animate the selected icon.
2844 icon->active = 9;
2845 icon->animStep = 0;
2846 icon->sentinel = 250;
2847 }
2848 for (i = 0; i < menu->partyCount; i++) {
2850 }
2851 }
2852
2853 // Every 32 frames, the members who can equip the item move.
2854 if ((gFrameCount & 31) == 0) {
2855 for (i = 0; i < menu->partyCount; i++) {
2856 if (Item_CanOwnerEquip(menu->ownerIds[i],
2857 ITEM_ID_MASK &
2858 menu->items[state.selectedIndex]) != 0) {
2860 }
2861 }
2862 }
2863
2864 WaitFrames(1);
2865 previous = state.selectedIndex;
2867 &state.row, &state.page);
2868 if (moved == 1) {
2869 redraw = 1;
2870 changed = 1;
2871 }
2872 if (moved == 0) {
2873 changed = 1;
2874 }
2875 if (moved == -1) {
2876 changed = 0;
2877 }
2878
2879 if ((gKeysPressed & KEY_A) != 0 &&
2880 menu->items[state.selectedIndex] != 0) {
2881 AudioCommand_PlayFar(SE_173); // the item choice sound
2882 result = menu->items[state.selectedIndex];
2883 done = 1;
2884 break;
2885 }
2886 if ((gKeysPressed & KEY_B) != 0) {
2888 result = -1;
2889 done = 1;
2890 break;
2891 }
2892 // L and R: the previous or next member who has items (pane 0 only).
2893 if ((gKeysRepeat & KEY_R) != 0 || (gKeysRepeat & KEY_L) != 0) {
2894 if (paneIndex == 1) {
2896 WaitFrames(1);
2897 } else {
2899 menu->selectedIndexByOwner[menu->paneOwner[paneIndex]] =
2900 state.selectedIndex;
2901 member = menu->paneIndex[paneIndex];
2902 do {
2903 if ((gKeysRepeat & KEY_R) != 0) {
2904 member++;
2905 } else {
2906 member--;
2907 }
2908 member = (member + menu->partyCount) % menu->partyCount;
2909 menu->selectedOwner = menu->ownerIds[member];
2910 menu->paneOwner[paneIndex] = menu->ownerIds[member];
2911 menu->paneIndex[paneIndex] = member;
2913 UnitGetFar(menu->paneOwner[paneIndex]), menu->items, 0);
2914 } while (menu->itemCount == 0);
2915 for (i = 0; i <= 3; i++) {
2916 menu->ownerY[i] = 30;
2917 }
2918 menu->ownerY[member] = 26;
2919 break;
2920 }
2921 }
2922 }
2923 }
2924
2925 UiWindow_ClearInteriorTilesFar((void *)window, 0, 88, 120, 96);
2927 menu->selectedSlots[paneIndex] = state.selectedIndex;
2928 menu->selectedIndexByOwner[menu->paneOwner[paneIndex]] = state.selectedIndex;
2929 menu->selectedItems[paneIndex] = result;
2931 result = -1;
2932 }
2933 WaitFrames(1);
2934 return result;
2935}
2936
2937#undef ITEM_MODAL_SHORT_X
2938#undef ITEM_MODAL_REMOVED_X
2939#undef ITEM_CANNOT_TRADE_X
2940#undef ITEM_TRADED_X
2941#undef ITEM_TRADE_PROMPT_X
2942#undef ITEM_COMMAND_TEXT_X
2943#undef ITEM_QUANTITY_WINDOW_WIDTH
2944#undef ITEM_GIVE_CURSOR_X
2945#undef ITEM_GIVE_ASK_X
2946#undef ITEM_GIVE_ASK_Y
2947#undef ITEM_DROP_QUESTION_X
2948#undef ITEM_LIST_PAGE_ICONS_X
2949#undef ITEM_LIST_NAME_X
2950#undef ITEM_STACK_MAX
2951#undef ITEM_IWRAM_COPY_WORDS
2952#undef ITEM_COMMAND_STATE_DISABLED
2953#undef ITEM_COMMAND_STATE_AVAILABLE
2954#undef TEXT_COLOR_DISABLED
@ BATTLE_UNIT_SIZE
Definition battle_unit.h:13
@ 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
s32 InventoryMenu_SortByListOrder(u16 *inventory, s32 mode)
Sorts a party member's 15 inventory slots by the list order of mode (see Menu_CopyListOrder): items a...
Definition common.c:824
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 Menu_UpdateEntryObjectTransforms(void)
Scheduler callback: each frame, places every party member sprite created by PsynergyMenu_InitializeEn...
Definition common.c:580
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 Palette_CopyObjectBankToBackground14(void)
Copies the first sprite palette into background palette 14, then colour 4 of background palette 15 ov...
Definition common.c:1121
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 ItemMenu_RefreshEntry(s32 layout)
Lays the inventory's 15 item icons out five to a row from (116, y): y is 56 for layout 1 and 40 other...
Definition common.c:737
void Menu_CancelSoundReset(void)
Starts watching for Start: clears FLAG_MENU_START_PRESSED and adds Menu_CancelSoundTick.
Definition common.c:1199
void UiWindow_SetBounds(struct UiWindow *window, s32 x, s32 y, s32 width, s32 height)
Moves and resizes a window, in tiles.
Definition common.c:1163
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_CloseIfOpen(struct UiWindow **handle, s32 style)
Closes the window kept in *handle, if any, and clears the handle.
Definition common.c:98
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
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 AnimationObjects_SelectAnimationFar(struct AnimationObject *state, s32 flags)
struct BattleUnit * UnitGetFar(u32 owner)
struct ItemDefinition * Item_GetDirectFar(s32 item)
s32 Party_ListActiveOwnersFar(s16 *owners)
s32 Item_AdjustCounterFar(s32 item_id, s32 delta)
s32 GameFlag_TestFar(s32 flag)
s32 Inventory_AddItemFar(s32 owner_id, s32 item_id)
s32 Unit_RefreshPsynergyFar(s32 owner)
struct BattleAct * BattleActGet(s32 actionId)
Far call to BattleAction_GetDirect.
s32 Inventory_RemoveFar(s32 owner, s32 slot)
s32 Inventory_BreakFar(s32 owner, s32 slot)
s32 Inventory_EquipFar(s32 owner, s32 slot)
s32 Item_CanOwnerEquip(s32 unit, s32 item)
Far call to Item_CanOwnerEquipDirect.
void GameFlag_ClearBitFar(s32 flag)
void UnitCalcFar(s32 owner)
void Event_ClearInvalidPackedValuesFar(void)
u32 BattleFx_HasTriggerFar(u16 item)
void Shop_FillSelectorFar(s32 count, s32 selector, u8 *base)
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 UiText_DrawNumberInWindowFar(s32 arg0, s32 arg1, struct UiWindow *arg2, s32 arg3, s32 arg4)
void UiWork_SetParamNibbleFar(s32 param)
s32 Resource_LoadByModeIntoSlotFar(s32 mode, s32 value, s32 result, s32 option)
void Link_DrawShiftedTilePairFar(s32 offset)
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)
struct RenderOutput * RenderOutput_CreateFar(s32 slot, s32 flags, struct UiWindow *input, s32 offsetX, s32 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 UiWindow_SetTilemapEntryFar(struct UiWindow *window, s32 value, s32 x, s32 y, u32 mode)
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
volatile u32 gFrameCount
Frames WaitFrames has finished.
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_AllocateBlock(s32 kind, s32 size)
As Runtime_AllocateHeapBlock, but tries EWRAM first, for blocks that need room more than speed: the b...
Definition heap.c:80
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
@ ITEM_COMMAND_REMOVE
@ ITEM_COMMAND_GIVE
@ ITEM_COMMAND_DROP
@ ITEM_COMMAND_USE
@ ITEM_COMMAND_INSPECT
@ ITEM_COMMAND_EQUIP
#define BG_CHAR_BLOCK(n)
Definition io_reg.h:166
@ KEY_UP
Definition io_reg.h:249
@ KEY_B
Definition io_reg.h:244
@ KEY_LEFT
Definition io_reg.h:248
@ KEY_RIGHT
Definition io_reg.h:247
@ KEY_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 DMA_32BIT
Definition io_reg.h:210
#define REG_DMA3
Definition io_reg.h:153
#define DMA_ENABLE
Definition io_reg.h:217
s32 ItemMenu_RunOwnerSelection(u16 *ownerIds, u16 *items)
The party member row of the item menu.
Definition item.c:1016
#define ITEM_STACK_MAX
The most items of one kind a stack holds.
Definition item.c:168
s32(*) ItemWordCopyFn(void *dst, const void *src, s32 size)
The resident IWRAM word copy, called through its address.
Definition item.c:171
#define ITEM_COMMAND_TEXT_X
Definition item.c:41
s32 ItemMenu_Run(void)
The item picker an event script opens (window command 3): the item menu, in which the player chooses ...
Definition item.c:90
UNUSED s32 InventoryMenu_ItemNamePageReturnTrue(void)
Nothing calls it.
Definition item.c:2772
#define ITEM_TRADE_PROMPT_X
Definition item.c:34
s32 ItemMenu_DrawNamePage(struct UiWindow *window, s32 unused, const struct MenuResult *pageState)
Draws one page of the item list into window: up to five item names with their icons,...
Definition item.c:2730
void ItemMenu_SetItemWindowRow3(void)
Moves the item window to row 3 of the right-hand side.
Definition item.c:2335
s32 ItemMenu_DrawItemDetailPage(struct UiWindow *window, void *ownerWork, struct MenuResult *pageState)
Updates the item list for the row under the cursor: puts the selected item's plain name in the info w...
Definition item.c:2690
ItemMenuStep
The steps of the item menu's command loop (ItemMenu_RunCommands).
Definition item.c:185
@ ITEM_STEP_QUANTITY
nothing sets it
Definition item.c:198
@ ITEM_STEP_ITEM
Definition item.c:187
@ ITEM_STEP_OWNER
Definition item.c:186
@ ITEM_STEP_EQUIP
Definition item.c:189
@ ITEM_STEP_COMMAND
Definition item.c:195
@ ITEM_STEP_IDLE
nothing sets it
Definition item.c:194
@ ITEM_STEP_REMOVE
Definition item.c:197
@ ITEM_STEP_INSPECT
Definition item.c:196
@ ITEM_STEP_GIVE
Definition item.c:190
@ ITEM_STEP_TRADE
Definition item.c:193
@ ITEM_STEP_USE
Definition item.c:188
@ ITEM_STEP_DROP
Definition item.c:191
@ ITEM_STEP_TARGET
Definition item.c:192
#define ITEM_COMMAND_STATE_DISABLED
Each item command's state in the grid.
Definition item.c:1624
s32 ItemMenu_ChooseCommand(void)
The item command grid: Use, Equip and Details on the top row, Give, Remove and Drop below (grid index...
Definition item.c:1634
s32 Inventory_RemoveFirstUnflagged(s32 ownerId)
Makes room in ownerId's inventory: if no slot is free, removes the whole stack in the first slot that...
Definition item.c:1573
s32 ItemMenu_ConfirmDrop(s32 item)
Asks whether to drop item (an inventory entry): its name, the question, and Yes or No,...
Definition item.c:2494
static __inline__ s32 Item_CopyWords(ItemWordCopyFn copy, void *dst, const void *src, s32 size)
Definition item.c:176
#define ITEM_GIVE_CURSOR_X
Definition item.c:54
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
s32 ItemMenu_SelectTarget(s32 mode)
Chooses the party member to use (mode 0) or give (mode 1) the selected item to.
Definition item.c:1145
void ItemMenu_DrawItemDetails(struct UiWindow *window, s32 inventoryEntry)
Writes the description of the inventoryEntry into window, one line a row: for equipment its Attack an...
Definition item.c:2094
s32 ItemMenu_RunCommands(s32 *ownerOut, s32 *targetOut, s32 *itemOut)
Runs the item menu: choose a party member, one of their items and a command (Use, Equip,...
Definition item.c:206
s32 Menu_SelectQuantity(s32 value)
The item menu's Details screen: describes the item entry value in a large window (the whole top half ...
Definition item.c:2003
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
#define ITEM_QUANTITY_WINDOW_WIDTH
Definition item.c:47
void ItemMenu_DrawCommands(const s8 *commandStates, struct UiWindow *window)
Writes the six command names into window, the disabled ones in grey.
Definition item.c:1871
void EquipmentMenu_UpdateCompatibilityIndicators(void)
Scheduler callback while choosing a member to give an item to: every 32 frames, sets each party figur...
Definition item.c:1282
#define ITEM_MODAL_REMOVED_X
Definition item.c:15
void EquipmentMenu_StartCompatibilityIndicators(void)
Ends EquipmentMenu_UpdateCompatibilityIndicators: puts every party figure back to animation 1 and rem...
Definition item.c:1305
s32 InventoryMenu_GetItemQuantity(s32 ownerId, s32 itemId)
Returns how many of itemId the unit ownerId holds: the quantity of its first stack,...
Definition item.c:1380
#define ITEM_DROP_QUESTION_X
Definition item.c:64
UNUSED void InventoryMenu_NoOp(void)
Nothing calls it.
Definition item.c:1474
void ItemMenu_HidePageIcons(void)
Hides the item icons in the first column of the five-wide item grid.
Definition item.c:943
s32 ItemMenu_RunList(s32 paneIndex)
The item list of the member in paneIndex (0: the owner, 1: the receiver of a trade),...
Definition item.c:2783
#define ITEM_MODAL_SHORT_X
Definition item.c:14
s32 ItemMenu_Use(void)
Uses the selected item from the owner in pane 0 on the member in pane 1.
Definition item.c:831
void ItemMenu_TryBreak(void)
After the selected item is used: an item of use type 2 breaks one time in eight, with the break sound...
Definition item.c:1969
#define ITEM_TRADED_X
Definition item.c:30
s32 ItemMenu_IsSpecial(s32 itemId)
Returns 1 for the items that raise a stat for good (Apple, Hard Nut, Mint and Lucky Pepper),...
Definition item.c:1323
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
s32 ItemMenu_SelectMember(s32 pane)
Lets the player choose a party member in pane (0 or 1), starting from the member chosen last.
Definition item.c:988
s32 ItemMenu_SelectGiveQuantity(s32 baseQuantity, s32 quantityRange, s32 dropMode)
Asks how many of the selected item stack to give or drop: Left and Right choose a number from 1 to qu...
Definition item.c:2372
UNUSED void InventoryMenu_ItemNamePageNoOp(void)
Nothing calls it.
Definition item.c:2775
void ItemMenu_DrawItemHead(void)
Shows the selected item at the top of the message window: its icon, its owner's name and its name.
Definition item.c:2476
void ItemMenu_SetMessageWindowHeight3(void)
Definition item.c:2360
#define ITEM_LIST_PAGE_ICONS_X
Definition item.c:71
void ItemMenu_OpenCategory(s32 ownerId)
Shows the equipment view of member ownerId's items in the item window.
Definition item.c:1130
void ItemMenu_DrawIcons(u16 *inventoryEntries, s32 iconStyle)
Loads each listed item's icon into its item icon sprite, the first 15 entries of inventoryEntries,...
Definition item.c:1431
#define ITEM_GIVE_ASK_Y
Definition item.c:56
void Menu_HideEmptyEntryIcons(const u16 *items)
Hides the icon of each of the 32 list entries whose item is 0.
Definition item.c:1344
void ItemMenu_HideAllIcons(void)
Hides all 32 item icons.
Definition item.c:927
void ItemMenu_SetMessageWindowHeight5(void)
Makes the message window, along the top right, 5 rows tall.
Definition item.c:2342
#define ITEM_LIST_NAME_X
Definition item.c:72
#define ITEM_GIVE_ASK_X
Definition item.c:55
#define TEXT_COLOR_DISABLED
Definition item.c:1868
void Resource_LoadPairedBlocks(void)
Loads the stat arrows (up and down) into two free VRAM blocks, kept in the menu work's resource slots...
Definition item.c:2643
void ItemMenu_DrawEquipPreview(s32 owner, s32 slot, s32 mode, s32 target)
Shows in the status panel what the item in owner's inventory slot would mean to member target: for a ...
Definition item.c:1482
s32 ItemMenu_OpenDetail(s32 itemIndex)
Opens the details window (top left, 13 by 10 tiles) and describes the item in pane itemIndex there.
Definition item.c:1988
#define ITEM_CANNOT_TRADE_X
Definition item.c:24
void ItemMenu_RefreshOwner(s32 ownerId, s32 mode)
Shows member ownerId's items in the item window, laid out for layout mode (see ItemMenu_RefreshEntry)...
Definition item.c:1457
s32 Item_ClassifyUseMode(s32 ownerId, s32 inventoryEntry)
Says how ownerId can use inventoryEntry from the item menu: 0 the item works on the field (BattleFx_H...
Definition item.c:1923
s32 ItemMenu_CountItems(s32 ownerId)
Returns how many of member ownerId's 15 inventory slots hold an item.
Definition item.c:1357
s32 ItemMenu_ConfirmEquip(s32 unused)
After giving or trading the selected item to the member in pane 1, offers to equip it there,...
Definition item.c:2556
#define ITEM_IWRAM_COPY_WORDS
Definition item.c:173
s32 ItemMenu_CommandCursorX(s32 column, s32 row)
The x and y of the item command cursor on column and row of the command grid (three commands to a row...
Definition item.c:1605
#define ITEM_COMMAND_STATE_AVAILABLE
Definition item.c:1625
s32 ItemMenu_CommandCursorY(s32 column, s32 row)
Definition item.c:1611
void ItemMenu_SetMessageWindowHeight7(void)
Definition item.c:2354
s32 ItemMenu_CollectItems(struct BattleUnit *unit, u16 *items, s32 mode)
Copies the unit's items into the list items (32 entries), skipping empty slots and clearing the rest.
Definition item.c:1409
void ItemMenu_SetMessageWindowHeight6(void)
Definition item.c:2348
void ItemMenu_BuildCommands(s8 *commandStates)
Fills commandStates (indexed by ItemMenuCommand) for the selected item: Use for usable items the owne...
Definition item.c:1811
void ItemMenu_SetItemWindowRow5(void)
Moves the item window to row 5 of the right-hand side.
Definition item.c:2328
s32 ItemMenu_PageResult(struct MenuResult *result, s32 index)
Fills result with the item list of the member in pane index: their unit, how many items they hold,...
Definition item.c:2657
void ItemMenu_DrawStat(s32 statChange, s32 unused, struct UiWindow *window, s32 x, s32 y)
Writes a signed stat change at (x, y) of window: the number, with a plus or minus sign just before it...
Definition item.c:2296
@ ITEM_EFFECT_SCALE_HP_REGEN
Definition item.h:66
@ ITEM_EFFECT_SCALE_DEFENSE
Definition item.h:70
@ ITEM_EFFECT_SCALE_AGILITY
Definition item.h:71
@ ITEM_EFFECT_ADD_LUCK
Definition item.h:64
@ ITEM_EFFECT_ADD_HP
Definition item.h:59
@ ITEM_EFFECT_SCALE_HP
Definition item.h:65
@ ITEM_EFFECT_SCALE_LUCK
Definition item.h:72
@ ITEM_EFFECT_SCALE_ATTACK
Definition item.h:69
@ ITEM_EFFECT_ADD_AGILITY
Definition item.h:63
@ ITEM_EFFECT_ADD_HP_REGEN
Definition item.h:60
@ ITEM_EFFECT_ADD_PP_REGEN
Definition item.h:62
@ ITEM_EFFECT_SCALE_PP_REGEN
Definition item.h:68
@ ITEM_EFFECT_ADD_PP
Definition item.h:61
@ ITEM_EFFECT_SCALE_PP
Definition item.h:67
@ ITEM_EFFECT_NONE
Definition item.h:58
@ INVENTORY_QUANTITY_STEP
Definition item.h:21
@ INVENTORY_EQUIPPED
Definition item.h:17
@ INVENTORY_SLOTS
Definition item.h:23
@ INVENTORY_QUANTITY_MASK
Definition item.h:22
@ ITEM_ID_MASK
Definition item.h:16
@ INVENTORY_QUANTITY_SHIFT
Definition item.h:20
@ INVENTORY_BROKEN
Definition item.h:18
@ ITEM_CANNOT_UNEQUIP
Definition item.h:28
@ ITEM_STACKABLE
Definition item.h:31
@ ITEM_CURSED
Definition item.h:27
@ ITEM_INDISPENSABLE
Definition item.h:30
@ ITEM_LUCKY_PEPPER
Definition item_ids.h:55
@ ITEM_MINT
Definition item_ids.h:54
@ ITEM_APPLE
Definition item_ids.h:52
@ ITEM_HARD_NUT
Definition item_ids.h:53
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.
u32 Random16(void)
Advances the game's random number generator (the C library's classic linear congruential one),...
Definition math.c:10
void Runtime_ReleaseHeapBlock(s32 slot)
void MemFree(void *buffer)
void Menu_ResetTwoResourceEntries(void)
Releases both cached icon resources used by the menu.
Definition icons.c:27
void ItemMenu_DrawCategory(struct UiWindow *window, s32 ownerId, s32 mode)
Shows the owner's equipped items and optionally its category icons.
Definition status.c:1883
void ItemMenu_PosCategory(void)
Moves all entry sprites off screen before arranging another category.
Definition status.c:2001
u8 gItemMenu_EquipmentKeyString[]
const u8 gMenu_QuantityTiles[]
u8 gMenu_MinusSignString
u8 gMenu_SmallDownArrowTiles[]
u8 gItemMenu_ArrangeKeysString[]
u8 gMenu_ArrowTiles[]
u8 gMenu_PointString[]
u8 gMenu_PlusSignString
u8 gMenu_TimesString[]
What every part of the menu object shares: its includes, and the macros and types more than one part ...
#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 MENU_ITEM_GRID_COLUMNS
Inventory icons occupy five columns in the fifteen-slot list.
#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 STATUS_PANEL_LOWER_ONLY
Keeps the open window, the name and the ailments, and redraws only the part below them.
#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_STATS
Attack, Defense, Agility and Luck.
@ STATUS_PANEL_LEARN
the Psynergy a Psynergy item teaches
@ STATUS_PANEL_EQUIP
stats if the item were equipped
@ STATUS_PANEL_EXPERIENCE
class, HP, PP and experience
s32 gItemMenu_CommandColumnXTable[6]
The x of the item command cursor, three columns on each of two rows.
Definition menudata.c:37
s32 Scheduler_AddOrUpdateCallback(SchedulerCallback callback, s32 order)
Schedules callback with order, or gives a task already running it the new order, and re-sorts the tab...
Definition scheduler.c:102
s32 Scheduler_RemoveCallback(SchedulerCallback callback)
Unschedules the task running callback: clears its routine and gives it order 0x7fff,...
Definition scheduler.c:146
#define SE_173
Definition songs.h:168
#define SE_MENU_CANCEL
Definition songs.h:106
#define SE_MENU_CURSOR_MOVE
Definition songs.h:104
#define SE_117
Definition songs.h:110
#define SE_174
Definition songs.h:169
#define SE_175
Definition songs.h:170
#define SE_MENU_ERROR
Definition songs.h:107
#define SE_ITEM_BREAK
Definition songs.h:131
#define SE_MENU_CONFIRM
Definition songs.h:105
#define SE_103
Definition songs.h:96
#define NULL
Definition bilibin.h:6
void * gWorkSlot[]
An animated sprite: its image and shadow, scale, rotation, size and up to four animation layers.
Definition animspr.h:108
An ability's definition, a row of gBattleAction_DefinitionTable: its targeting, kind,...
u8 range
the aimed unit and range - 1 either side, or ABILITY_RANGE_ALL
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.
u16 inventory[15]
Items held, one entry each: bits 15..11 quantity | 10 broken | 9 equipped | 8..0 item id (INVENTORY_*...
The item menu's work, in the HEAP_SLOT_MENU work slot: its windows, the party figures,...
struct RenderOutput * cursor
struct UiWindow * unknownWindow38
only closed by name in TBS
struct UiWindow * equipWindow
struct UiWindow * modalWindow
s32 selectedOwner
the party member chosen
s16 completionFlag
set to 1 as item commands end; not read by name
struct UiWindow * unknownWindow40
only closed by name in TBS
s8 selectedIndexByOwner[8]
each member's entry chosen last
u16 selectedItems[2]
each pane's inventory entry chosen
s16 messageOffset
the item use's result, after MsgItemUseResult
struct RenderOutput * selectedItemIcon
struct UiWindow * helpWindow
struct UiWindow * infoWindow
struct RenderOutput * paneIcons[2]
The two panes: the member whose items are shown, and the one an item is given to.
struct RenderOutput * gridCursor
only prepared by name in TBS
s8 equipPreview
1 while the stats preview a removal, not an equip
u16 flags
1 while the item's name and command grid are drawn
s8 paneCount[2]
members to choose from; 1 at first
u16 items[32]
the inventory entries listed
struct UiWindow * listWindow
struct UiWindow * mainWindow
u8 paneOwner[2]
each pane's member
u16 selectedSlots[2]
each pane's inventory slot chosen
struct AnimationObject * ownerObjects[8]
the party members' figures
u8 listMode
the command chosen last; 0xff for none
s16 ownerY[8]
screen pixels
struct UiWindow * statusWindow
u16 ownerIds[8]
the party in order (Party_ListActiveOwners)
struct RenderOutput * entryIcons[32]
struct UiWindow * messageWindow
s16 resourceSlots[2]
VRAM cache slots of two arrow pictures.
u8 mode
not named through this struct; PsynergyMenuState.mode
s8 paneIndex[2]
the member chosen, in ownerIds; -1 for none at first
struct UiWindow * itemWindow
u8 selectedColumn
The cursor grid: its place and its size, 1 by 1 at first.
An item's definition: its price, type, who can equip it, its bonuses and unleash, its effects and the...
Definition item.h:104
u8 useType
what using it costs (ITEM_USE_), or 0 for nothing
Definition item.h:113
s8 secondaryBonus
Defense added while equipped.
Definition item.h:111
u8 type
enum ItemType; 0 for an item that is not equipment
Definition item.h:106
s16 primaryBonus
Attack added while equipped.
Definition item.h:110
u16 actionId
the ability used, or taught as Psynergy
Definition item.h:120
struct ItemEffect effects[4]
what it does while equipped
Definition item.h:119
u8 flags
enum ItemFlags
Definition item.h:107
u8 kind
enum ItemEffectKind; 0 for none
Definition item.h:93
s8 amount
what the kind adds or scales by
Definition item.h:94
The event work as the item picker sees it: what the player chose, for the event script.
Definition item.c:80
s32 unk000[0x60]
Definition item.c:81
u16 chosenItem
owner << 10 | item id
Definition item.c:82
u8 unk182[0x18]
Definition item.c:83
u16 chosenSlot
the owner's inventory slot
Definition item.c:84
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
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
u16 x
tiles
Definition uiwindow.h:15
#define HELP_TEXT_X
#define STOCK_LABEL_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
The heap's 64 work slots, the first two holding the next free EWRAM and IWRAM addresses.
Definition heap_state.h:18
void * slots[64]
Each slot's block once allocated, else null; slots 0 and 1 are the pool pointers.
Definition heap_state.h:26
#define LIST_PAGE_SIZE
Definition menu.h:83
#define UI_PAGE_ARROW_VRAM
Definition window.h:64
void Item_PlayUseAnimation(u32 item)
Runs the animation selected by the item's action definition.
Definition use.c:311
s32 Item_Use(s32 slot, s32 ownerId, s32 targetId)
Applies the slot's action, then consumes or transforms the item on success.
Definition use.c:18
s32 Resource_FindFreeEntry(void)
Returns the number of the first free cache entry, or VRAM_CACHE_ENTRY_COUNT when all are taken.
Definition vram_cache.c:211
s32 VramCache_Load(u32 no, u32 size, const void *src)
Gives cache entry no size bytes of sprite VRAM and copies src there.
Definition vram_cache.c:143