Alchemy
Loading...
Searching...
No Matches

item_menu.c

Go to the documentation of this file.
1/// @file
2/// The battle item menu.
3/// Part of battle_command.c, the menu object, compiled only through it.
4
6
7/// Checks whether an item can be used in battle.
8/// Return: 0 usable, 1 unusable, 2 unusable in battle.
9/// unit: character index
10/// item: inventory item value
12 s32 itemUseStatus;
13 struct ItemDefinition *definition;
14
15 if (item == 0) {
16 return 1;
17 }
18 definition = Item_GetDirectFar(item);
19 itemUseStatus = 1;
20 // Equipment that grants Psynergy.
21 if (definition->useType == 3) {
22 return itemUseStatus;
23 }
24 if (definition->actionId == 0) {
25 return itemUseStatus;
26 }
27 if ((definition->type != 0) && (Item_CanOwnerEquip(unit, item) == 0)) {
28 return itemUseStatus;
29 }
30 if ((BATTLE_OK & BattleActGet(definition->actionId)->flags) == 0) {
31 return 2;
32 }
33 return 0;
34}
35
36/// Copies one 4bpp VRAM tile, ignoring the palette and flip bits of each
37/// entry.
38void Vram_CopyTile(u32 sourceTile, u32 destinationTile) {
39 Dma_Set(BG_CHAR_BLOCK(0) + (sourceTile & 0x3ff) * TILE_SIZE_4BPP,
40 BG_CHAR_BLOCK(0) + (destinationTile & 0x3ff) * TILE_SIZE_4BPP,
42}
43
44/// Chooses an inventory-list position for battle use, or -1 on cancel. Keeps
45/// unavailable items visible with their help text, but rejects confirmation.
46s32 ItemList_SelectEntry(s32 owner, u16 *entries, s32 count) {
47 struct UiRenderWork *render;
48 s32 drawnFirstEntry;
49 s32 drawnRow;
50 s32 cursorHandle;
51 struct UiWindow *messageWindow;
52 s32 iconCount;
53 s32 preferredRow;
54 struct MenuPoint cursorPosition;
55 struct BattleMenuWork *navigation;
56 struct UiWindow *window;
57 s32 firstEntry;
58 s32 selectedRow;
59 s32 item;
60 s32 iconTile;
61 s32 pageTile;
62 s32 unusableReason;
63 s32 result;
64 s32 i;
65 struct CursorSprite cursor;
66 struct MenuSprite *iconSprite;
67 struct CursorSprite *cursorSprite;
68 u16 messageText[64];
69 s32 iconSlots[BATTLE_LIST_ROWS];
70 struct MenuSprite sprites[BATTLE_LIST_ROWS];
71
72 render = UI_WORK;
73 drawnFirstEntry = -1;
74 drawnRow = -1;
75 cursorHandle = VramCache_AllocEntry(128);
76 messageWindow = UiWindow_Create(0, 5, 30, 4, 42);
77 iconCount = 0;
78 BATTLE_MENU_GET_CURSOR(firstEntry, selectedRow, preferredRow);
79 window = UiWindow_Create(15, 9, 15, BATTLE_LIST_ROWS * 2 + 1, 6);
80
81 for (i = 0; i < BATTLE_LIST_ROWS; i++) {
82 s32 y = i * 2;
83
84 iconSprite = &sprites[i];
86 iconSprite->oam.f.x = window->x * 8 + 8;
87 iconSprite->oam.f.y = (y + window->y) * 8 + 4;
88 }
89
90 // Reserve one glyph slot per visible row; paging reloads these same slots.
91 for (i = 0; i < BATTLE_LIST_ROWS; i++) {
92 iconSlots[i] = VramCache_AllocEntry(128);
93 sprites[i].oam.f.tile = VramCache_Reload(iconSlots[i], -1);
94 }
95
100
101 cursorSprite = &cursor;
102 for (;;) {
103 if (firstEntry != drawnFirstEntry || selectedRow != drawnRow) {
104 render->menuBusy = 1;
105 Ui_SetRectHighlight(window->x + 1, window->y + drawnRow * 2 + 1,
106 window->width - 2, 1, 15);
108 if (count != 0) {
109 if (Item_ClassifyUseAbility(owner, entries[firstEntry + selectedRow]) ==
110 2) {
111 BATTLE_MENU_MESSAGE_COPY(MsgBattleItemUnavailable, messageText,
113 } else {
115 (entries[firstEntry + selectedRow] & ITEM_ID_MASK) +
116 MsgItemPlainName,
117 messageText, BATTLE_MENU_MESSAGE_CAPACITY);
118 }
119 } else {
120 BATTLE_MENU_MESSAGE_COPY(MsgBattleNoItems, messageText,
122 }
123 UiText_RenderWideStringAtOffset(messageText, messageWindow, 0, 4);
124 drawnRow = selectedRow;
125
126 // Cursor moves update help; only a page change reloads the row icons.
127 if (firstEntry != drawnFirstEntry) {
129 for (i = 0; i < BATTLE_LIST_ROWS; i++) {
130 item = entries[firstEntry + i];
131 if (item == 0) {
132 break;
133 }
134 Item_GetDirectFar(item);
136 if (Item_ClassifyUseAbility(owner, item) != 0) {
138 } else if ((item & INVENTORY_BROKEN) != 0) {
140 }
141 UiText_DrawCharacterAtOffset((item & ITEM_ID_MASK) + MsgItemName,
142 window, 16, i * 16);
144 sprites[i].oam.f.tile = ItemIcon_LoadIntoSlot(item, iconSlots[i]);
145 }
146 iconCount = i;
147 drawnFirstEntry = firstEntry;
148 }
149
150 if (count > BATTLE_LIST_ROWS) {
151 for (i = 0; i < (count + 4) / BATTLE_LIST_ROWS; i++) {
152 iconTile = i + LIST_TILE_PAGE_NUMBER;
153 if (i == firstEntry / BATTLE_LIST_ROWS) {
154 iconTile = i + LIST_TILE_PAGE_NUMBER_LIT;
155 }
157 window, iconTile,
158 window->width - (count + 4) / BATTLE_LIST_ROWS + i - 2, -1, 0);
159 }
160 }
161
162 Ui_SetRectHighlight(window->x + 1, window->y + selectedRow * 2 + 1,
163 window->width - 2, 1, 14);
164 render->dirty = 1;
165 render->menuBusy = 0;
166 }
167
168 if (count > BATTLE_LIST_ROWS) {
169 for (i = 0; i < (count + 4) / BATTLE_LIST_ROWS; i++) {
170 iconTile = i + LIST_TILE_PAGE_NUMBER;
171 if ((gFrameCount & 15) <= 11) {
172 if (i == firstEntry / BATTLE_LIST_ROWS) {
173 iconTile = i + LIST_TILE_PAGE_NUMBER_LIT;
174 }
175 }
177 window, iconTile,
178 window->width - (count + 4) / BATTLE_LIST_ROWS + i - 2, -1, 0);
179 }
180 pageTile = -1;
182 window, LIST_TILE_PAGES_LEFT,
183 window->width - (count + 4) / BATTLE_LIST_ROWS - 3, pageTile, 0);
185 pageTile, 0);
186 UiRender_MarkRow(render, window->y - 1);
187 }
188
189 for (i = 0; i < iconCount; i++) {
190 iconSprite = &sprites[i];
191 Runtime_PushSlotEntry(iconSprite, 240);
192 }
193
194 cursorPosition.x = window->x * 8 - 2;
195 cursorPosition.y = (selectedRow * 2 + window->y) * 8 + 20;
196 /* FAKEMATCH(dead): cursorSprite set again to the cursor each frame orders
197 * the spill slots of the cursor address and row * 2 as the native frame
198 * does; without it, 28 of 770 instructions differ in tbs-en. */
199 cursorSprite = &cursor;
200 ((u32 *)cursorSprite)[1] = MENU_SPRITE_SIZE_16;
201 ((u32 *)cursorSprite)[2] = 0;
202 cursorSprite->tile =
204 cursorSprite->x = cursorPosition.x + ((gFrameCount & 4) >> 1) - 4;
205 cursorSprite->y = cursorPosition.y - ((gFrameCount & 4) >> 2) - 8;
206 if (count != 0) {
207 Runtime_PushSlotEntry(cursorSprite, 242);
208 }
209
210 BATTLE_MENU_SET_CURSOR(firstEntry, selectedRow, preferredRow);
211 navigation = gLinkCountdownWork;
212
213 if ((gKeysPressed & KEY_A) != 0) {
214 if (count != 0) {
215 result = firstEntry + selectedRow;
216 Item_GetDirectFar(entries[result]);
217 unusableReason = 0;
218 if ((entries[result] & INVENTORY_BROKEN) == 0) {
219 unusableReason = Item_ClassifyUseAbility(owner, entries[result]);
220 if (unusableReason == 0) {
221 break;
222 }
223 }
225 if (unusableReason == 2) {
226 BATTLE_MENU_MESSAGE_COPY(MsgBattleItemUnavailable, messageText,
228 } else if ((entries[result] & INVENTORY_BROKEN) != 0) {
229 BATTLE_MENU_MESSAGE_COPY(MsgBattleItemBroken, messageText,
231 } else {
232 BATTLE_MENU_MESSAGE_COPY(MsgBattleItemNoEffect, messageText,
234 }
236 UiText_RenderWideStringAtOffset(messageText, messageWindow, 0, 4);
237 } else {
238 result = -1;
239 break;
240 }
241 } else if (navigation->timer == 0 || (gKeysPressed & KEY_B) != 0) {
243 result = -1;
244 break;
245 }
246
247 if (count != 0) {
248 if ((gKeysRepeat & KEY_DOWN) != 0) {
250 selectedRow++;
251 if (selectedRow == BATTLE_LIST_ROWS ||
252 firstEntry + selectedRow == count) {
253 selectedRow = 0;
254 }
255 preferredRow = selectedRow;
256 } else if ((gKeysRepeat & KEY_UP) != 0) {
258 selectedRow--;
259 if (selectedRow < 0) {
260 if (firstEntry == (count - 1) / BATTLE_LIST_ROWS * BATTLE_LIST_ROWS) {
261 selectedRow = count - firstEntry - 1;
262 } else {
263 selectedRow = BATTLE_LIST_ROWS - 1;
264 }
265 }
266 preferredRow = selectedRow;
267 } else if ((gKeysRepeat & KEY_RIGHT) != 0) {
270 if (firstEntry + BATTLE_LIST_ROWS >= count) {
271 if (firstEntry != 0) {
272 firstEntry = 0;
273 selectedRow = preferredRow;
274 }
275 } else {
276 firstEntry += BATTLE_LIST_ROWS;
277 selectedRow = preferredRow;
278 if (firstEntry == (count - 1) / BATTLE_LIST_ROWS * BATTLE_LIST_ROWS) {
279 selectedRow = count - firstEntry - 1;
280 if (selectedRow > preferredRow) {
281 selectedRow = preferredRow;
282 }
283 }
284 }
285 } else if ((gKeysRepeat & KEY_LEFT) != 0) {
288 if (firstEntry != 0) {
289 firstEntry -= BATTLE_LIST_ROWS;
290 selectedRow = preferredRow;
291 } else {
292 firstEntry = (count - 1) / BATTLE_LIST_ROWS * BATTLE_LIST_ROWS;
293 selectedRow = preferredRow;
294 if (firstEntry != 0) {
295 selectedRow = count - firstEntry - 1;
296 if (selectedRow > preferredRow) {
297 selectedRow = preferredRow;
298 }
299 }
300 }
301 }
302 }
303 WaitFrames(1);
304 }
305
306 UiWork_Finalize(messageWindow, 1);
307 UiWork_Finalize(window, 1);
308 WaitFrames(1);
309 Resource_ResetEntry(cursorHandle);
310 for (i = 0; i < BATTLE_LIST_ROWS; i++) {
311 Resource_ResetEntry(iconSlots[i]);
312 }
313 WaitFrames(1);
314 return result;
315}
What every part of the menu object shares: its includes, edition values, macros and the link round st...
#define BATTLE_MENU_MESSAGE_COPY
@ LIST_TILE_PAGES_RIGHT
Right arrow.
@ LIST_TILE_PAGE_NUMBER
Page number.
@ LIST_TILE_PAGES_LEFT
Left arrow.
@ LIST_TILE_PAGE_NUMBER_LIT
Current page number.
#define BATTLE_MENU_MESSAGE_CAPACITY
#define BATTLE_OK
flags: usable in battle
void Ui_SetRectHighlight(s32 x, s32 y, s32 width, s32 height, s32 paletteBit)
Sets bit 12 of each tile in a screen-space rectangle, preserving the other tile attributes.
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
struct ItemDefinition * Item_GetDirectFar(s32 item)
struct BattleAct * BattleActGet(s32 actionId)
Far call to BattleAction_GetDirect.
s32 Item_CanOwnerEquip(s32 unit, s32 item)
Far call to Item_CanOwnerEquipDirect.
void AudioCommand_PlayFar(s32 id)
void Input_ResetKeyRepeat(void)
Restarts the key repeat delay, so held keys wait the full delay again.
Definition frame.c:289
void WaitFrames(s32 frames)
The game's frame loop: runs frames frames and returns.
Definition frame.c:97
volatile u32 gFrameCount
Frames WaitFrames has finished.
void UiText_RenderWideStringAtOffset(u16 *text, struct UiWindow *window, s32 x, s32 y)
Draws a zero-terminated string of 16-bit character codes into a text canvas window at pixel (x,...
Definition glyphs.c:258
u8 gResource_FixedBlockBTiles[]
#define BG_CHAR_BLOCK(n)
Definition io_reg.h:166
#define TILE_SIZE_4BPP
Definition io_reg.h:168
@ KEY_UP
Definition io_reg.h:249
@ KEY_B
Definition io_reg.h:244
@ KEY_LEFT
Definition io_reg.h:248
@ KEY_RIGHT
Definition io_reg.h:247
@ KEY_A
Definition io_reg.h:243
@ KEY_DOWN
Definition io_reg.h:250
#define REG_DMA3
Definition io_reg.h:153
@ ITEM_ID_MASK
Definition item.h:16
@ INVENTORY_BROKEN
Definition item.h:18
s32 Item_ClassifyUseAbility(s32 unit, s32 item)
Checks whether an item can be used in battle.
Definition item_menu.c:11
s32 ItemList_SelectEntry(s32 owner, u16 *entries, s32 count)
Chooses an inventory-list position for battle use, or -1 on cancel.
Definition item_menu.c:46
void Vram_CopyTile(u32 sourceTile, u32 destinationTile)
Copies one 4bpp VRAM tile, ignoring the palette and flip bits of each entry.
Definition item_menu.c:38
volatile u32 gKeysPressed
Keys that went down this frame.
volatile u32 gKeysRepeat
Pressed keys, repeating while held: after 19 frames, then every 6.
struct BattleMenuWork * gLinkCountdownWork
#define MenuSprite_Init(sprite, shape)
Sets sprite shape (attr0/attr1) and clears the remaining fields.
Definition menu_list.h:76
#define MENU_SPRITE_SIZE_16
Definition menu_list.h:67
#define BATTLE_MENU_SET_CURSOR(page_, row_, preferred_)
Saves the selection: page, row and return row.
Definition menu_list.h:183
#define BATTLE_MENU_GET_CURSOR(page_, row_, preferred_)
Restores the previous selection: page, row and return row.
Definition menu_list.h:163
@ BATTLE_LIST_ROWS
Definition menu_list.h:20
s32 ItemIcon_LoadIntoSlot(s32 resource, s32 index)
Composes the item icon with style 0x1a in temporary transfer work and reload the requested cache slot...
Definition pictures.c:312
void Runtime_PushSlotEntry(void *slotEntry, s32 slot)
Links a sprite entry into depth slot slot (clamped to 0..255) for this frame.
Definition render.c:79
#define SE_MENU_CANCEL
Definition songs.h:106
#define SE_MENU_CURSOR_MOVE
Definition songs.h:104
#define SE_MENU_ERROR
Definition songs.h:107
u8 flags
bits: 7 usable in battle | 6 usable in the field | 5..4 clear in every row | 3..0 kind (ABILITY_KIND_...
The battle command menus' work, heap slot 57 (0x104 bytes), reached as gLinkCountdownWork.
Definition menu_list.h:107
s32 timer
Frames left to choose commands in a link battle; -1 outside link battles.
Definition menu_list.h:131
A cursor or prompt sprite: a list link and its OAM attributes as fields.
Definition menu_list.h:50
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
u8 type
enum ItemType; 0 for an item that is not equipment
Definition item.h:106
u16 actionId
the ability used, or taught as Psynergy
Definition item.h:120
A point on the screen where a menu shows its cursor.
Definition menu_list.h:97
s32 y
screen pixels
Definition menu_list.h:99
s32 x
screen pixels
Definition menu_list.h:98
A menu sprite: a list link and its OAM attributes, as two words or as fields.
Definition menu_list.h:24
union MenuSprite::@002225022013150231017316170057321303227123371224 oam
The window system's work: the windows' tilemap, the windows, the three text channels,...
Definition window.h:19
u8 dirty
The tilemap's 4-row bands to upload: bit 0 for all, bit n + 1 for band n.
Definition window.h:32
u8 menuBusy
while set, the tilemap is not uploaded
Definition window.h:40
A window: a framed rectangle of the tilemap with its sprite outputs, its opening or closing animation...
Definition uiwindow.h:11
u16 y
tiles
Definition uiwindow.h:16
u16 x
tiles
Definition uiwindow.h:15
u16 width
tiles
Definition uiwindow.h:13
void UiWork_SetParamNibble(s32 param)
Sets the text colour (0 to 15) of drawn text.
Definition text_tiles.c:524
void UiText_DrawCharacterAtOffset(s32 message, const struct UiWindow *window, u32 offsetX, u32 offsetY)
Decodes a message and draws it as tiles in a window at pixel (offsetX, offsetY) of its interior.
Definition text_tiles.c:552
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
unsigned short u16
Definition types.h:13
#define UiRender_MarkRow(render, y)
Requests transfer of the four-row tilemap band containing window row y.
Definition uiwindow.h:73
#define UI_WORK
Definition window.h:267
#define DMA_COPY32(count)
The DMA control word that copies count words.
Definition window.h:112
@ UI_TILE_FRAME_BOTTOM_TEE
the bottom edge meeting a line
Definition window.h:94
@ UI_TILE_FRAME_TOP_TEE
the top edge meeting a line
Definition window.h:93
s32 VramCache_AllocEntry(s32 size)
Takes a free cache entry, gives it size bytes of sprite VRAM and returns its number.
Definition vram_cache.c:227
s32 VramCache_Reload(s32 no, s32 src)
Copies src again into entry no's VRAM, keeping its size.
Definition vram_cache.c:238
s32 Resource_ResetEntry(u32 no)
Frees cache entry no: its blocks go back and the entry is marked free (offset 0xffff).
Definition vram_cache.c:106
void UiWindow_SetTilemapEntry(struct UiWindow *window, s32 value, s32 x, s32 y, u32 mode)
Writes value into a window's tilemap at tile (x, y) of its interior, with the palette mode names (TIL...
Definition sprites.c:345
s32 Ui_FillVramBlockPattern(void)
Fills the text canvas with the window background colour (4).
Definition windows.c:619
void UiWork_Finalize(struct UiWindow *window, s32 instant)
Closes a window: clears its contents and remembers its last rectangle.
Definition windows.c:349
void RenderOutput_RedrawSavedRect(struct UiWindow *window)
Redraws a window's empty frame at its current rectangle.
Definition windows.c:400
struct UiWindow * UiWindow_Create(s32 x, s32 y, s32 width, s32 height, s32 attrs)
Opens a window at tile (x, y) of width by height tiles in the first free window slot,...
Definition windows.c:279