Alchemy
Loading...
Searching...
No Matches

party_status.c

Go to the documentation of this file.
1/// @file
2/// The party status window.
3/// Part of battle_command.c, the menu object, compiled only through it.
4
6
7// UB: the standby counts pass four of UiWindow_PutGlyph's five arguments, so
8// its mode is whatever the stack slot of the fifth holds; UBFIX passes 0, as
9// the summon lists do.
10#ifdef UBFIX
11#define PARTY_STATUS_PUT_DIGIT(window, glyph, x, y) \
12 UiWindow_PutGlyph(window, glyph, x, y, 0)
13#else
14#define PARTY_STATUS_PUT_DIGIT(window, glyph, x, y) \
15 UiWindow_PutGlyph(window, glyph, x, y)
16#endif
17
18// The party status window: one column of six tiles per party member (name,
19// HP and, when shown, PP with a bar under each), and in battle an optional
20// five-tile column of standby Djinn counts on its left. It sits at the top
21// right of the screen. Its flags:
22#define PARTY_STATUS_SHOW_PP 1 ///< add the PP row
23#define PARTY_STATUS_SHOW_DJINN 2 ///< add the Djinn column (needs the PP row)
24#define PARTY_STATUS_CLOSED 9 ///< erase the window
25#define PARTY_STATUS_KEEP_FLAGS -1 ///< redraw with the flags it has
26#define PARTY_STATUS_COLUMN_WIDTH 6
27#define PARTY_STATUS_DJINN_WIDTH 5
28
29/// The heap block the party status window's layout lives in.
30#define PARTY_STATUS_BLOCK 16
31
32/// The address of pixel row 7 - `up` of BG tile `tile` (4bpp, 32 bytes a tile,
33/// 4 bytes a row): the status bars are drawn from a tile's bottom row up.
34#define TILE_ROW_FROM_BOTTOM(tile, up) \
35 ((u32 *)((tile) * 32 - (up) * 4 + 0x0600001c))
36
37/// Works out where the party status window goes for `flags`: one column per
38/// party member (those in battle when a battle is on), plus the Djinn column,
39/// right-aligned on the 30-tile screen row at the top. It is four tiles high
40/// outside battle and three in battle, plus one with the PP row.
42 // UB: slot[-1] steps before the single party-status work slot. Reading
43 // the actual owners grows the EN function from 0x68 to 0x6c bytes.
44 // Keep the original address formation only in the matching build.
45#ifdef UBFIX
47 struct UiRenderWork *work = UI_WORK;
48#else
49 void **slot = (void **)&gPartyStatusWork;
50 struct PartyStatusWindow *layout = *slot;
51 struct UiRenderWork *work = slot[-1];
52#endif
53 s32 height = 4;
54 s32 members;
55 s32 width;
56 s32 x;
57
58 if (work->menuState != 0) {
60 height = 3;
61 } else {
63 }
64 if (flags & PARTY_STATUS_SHOW_PP)
65 height++;
66 else
68
70 width = members + 1;
71 if (flags & PARTY_STATUS_SHOW_DJINN)
73
74 x = 30;
75 x -= width;
76 layout->x = x;
77 layout->y = 0;
78 layout->width = width;
79 layout->height = height;
80 layout->flags = flags;
81}
82
83/// Opens the party status window with `flags` (see PARTY_STATUS_*) in a new
84/// heap block and draws it. The UI is held busy while it is drawn.
86 s32 zero;
87 struct PartyStatusWindow *layout;
88 s8 *busy;
89
90 layout = Runtime_AllocateBlock(PARTY_STATUS_BLOCK, sizeof(*layout));
91 busy = (s8 *)&UI_WORK->menuBusy;
92 zero = 0;
93 *busy = 1;
95 layout->window =
96 UiWindow_Create(layout->x, layout->y, layout->width, layout->height, 6);
98 *busy = zero;
99}
100
101/// Draws the vertical lines between the members' columns of the party status
102/// `window`, with their top and bottom joints, at the offsets listed in
103/// gUiWindow_PartyColumnOffsets (shifted right past the Djinn column, whose own
104/// line comes first in the list). In battle it also draws the window's bottom
105/// edge.
107 struct UiRenderWork *work = UI_WORK;
108 s32 first = 1;
109 s32 shift = 0;
110 u32 lastColumn = window->width - 1;
111 s32 i;
112 u32 rows = window->height;
113 u32 column;
114 u32 row;
115 u16 *cell;
116
117 if ((flags & PARTY_STATUS_SHOW_PP) == 0)
119 if (flags & PARTY_STATUS_SHOW_DJINN) {
121 first = 0;
122 }
123 i = first;
124 while (gUiWindow_PartyColumnOffsets[i] >= 0) {
125 column = gUiWindow_PartyColumnOffsets[i] + shift;
126 if (column < lastColumn) {
127 for (row = 0; row != rows; row++) {
128 cell = (u16 *)(((window->y + row) * 32 + (window->x + column)) * 2 +
129 (u32)work->tilemap);
130 if (row == 0)
131 *cell = UI_TILE_FRAME_TOP_TEE;
132 else if (row == rows - 1)
134 else
136 }
137 }
138 i++;
139 }
140 if (work->menuState) {
141 cell = work->tilemap + (window->y + window->height - 1) * 32 + window->x;
142 column = 1;
144 while (column < lastColumn) {
145 column++;
147 }
149 }
150 work->dirty = 1;
151}
152
153// Recolours the five bar tiles at (x, y) in `window` to show a bar `length`
154// pixels long (0-40). The bar tiles are drawn in colour 14 with a colour 1
155// shadow; each pixel left of the length becomes colour 8 (shadow 13), the
156// rest colour 2 (shadow 12). Only the bottom row of each tile changes for an
157// empty bar, the bottom three otherwise. Outside battle it first loads the
158// basic colours into BG palette 14, its colour 14 taken from colour 4 of
159// palette 15.
160// The matching return type keeps pop {r1}; bx r1; void uses r0 instead.
161#ifdef UBFIX
162void UiWindow_DrawStatusBarTiles(struct UiWindow *window, s32 x, s32 y,
163 s32 length) {
164#else
166 s32 length) {
167#endif
168 s32 i;
169 struct UiRenderWork *work = UI_WORK;
170 s32 fullLength = length;
171 s32 row;
172 s32 column;
173 u32 tile;
174 u32 bar;
175 u32 shadow;
176 u32 pixels;
177 u32 recoloured;
178
179 if (work->menuState == 0) {
180 Dma_Set((const void *)Palette_GetBasicObjColors(),
181 (void *)&BG_PLTT_COLOR(14, 0), DMA_COPY16(16), REG_DMA3);
182 BG_PLTT_COLOR(14, 14) = BG_PLTT_COLOR(15, 4);
183 }
184 x += window->x;
185 y += window->y;
186 for (i = 0; i < 5; i++, x++) {
187 // This tile's eight pixels: filled up to `length`, empty after.
188 tile = work->tilemap[y * 32 + x];
189 bar = 0x22222222;
190 shadow = 0xcccccccc;
191 tile &= 0x3ff;
192 if (length > 7) {
193 bar = 0x88888888;
194 shadow = 0xdddddddd;
195#ifdef UBFIX
196 // At zero (including a multiple-of-eight remainder), the native
197 // right shifts by 32 yield zero. Keep the empty patterns without
198 // evaluating those undefined C shifts.
199 } else if (length > 0) {
200#else
201 } else if (length >= 0) {
202#endif
203 bar <<= length * 4;
204 bar |= 0x88888888U >> (32 - length * 4);
205 shadow <<= length * 4;
206 shadow |= 0xddddddddU >> (32 - length * 4);
207 }
208 for (row = 0; row <= (fullLength != 0 ? 2 : 0); row++) {
209 pixels = *TILE_ROW_FROM_BOTTOM(tile, row);
210 recoloured = 0;
211 for (column = 0; column <= 7; column++) {
212 u32 colour = pixels & 15;
213
214 if (colour == 14)
215 recoloured |= bar & (15U << (column * 4));
216 else if (colour == 1)
217 recoloured |= shadow & (15U << (column * 4));
218 else
219 recoloured |= colour << (column * 4);
220 pixels >>= 4;
221 }
222 *TILE_ROW_FROM_BOTTOM(tile, row) = recoloured;
223 }
224 length -= 8;
225 }
226}
227
228/// Draws the party status window with `flags` (see PARTY_STATUS_*): each
229/// member's name, HP and optionally PP with their bars, and in battle the
230/// standby Djinn of each element. The HP is drawn in text colour 2 at zero and
231/// colour 4 at a quarter or less. When the flags change, the window is erased
232/// and laid out again first.
233void PartyStatusDraw(s32 flags) {
234 // UB: the negative indices leave the single party-status work slot.
235 // Named owners grow the EN function from 0x3d4 to 0x3dc bytes. Keep the
236 // original address formation and load order in the matching build.
237#ifdef UBFIX
239 struct BattleWork *battle = gBattleWork;
240 struct UiWindow *window = layout->window;
241 struct UiRenderWork *work = UI_WORK;
242#else
243 void **slot = (void **)gPartyStatusWork;
244 struct PartyStatusWindow *layout = slot[0];
245 struct BattleWork *battle = slot[-7];
246 struct UiWindow *window = layout->window;
247 struct UiRenderWork *work = slot[-1];
248#endif
249 s32 x = 0;
250 u32 count;
251 s32 y = 0;
252 u32 i;
253 u16 members[5];
254 u8 standbyDjinn[4];
255
256 // List the members shown: those fighting in battle, the party otherwise.
257 if (work->menuState != 0) {
259 y = -1;
260 for (i = 0; i < count; i++) {
261 members[i] = battle->partyUnits[i];
262 if (members[i] == 255)
263 break;
264 }
265 } else {
267 for (i = 0; i < count; i++)
268 members[i] = gGameState.activeOwners[i];
269 members[i] = 255;
270 }
271 count = i;
272
273 if (flags == PARTY_STATUS_KEEP_FLAGS)
274 flags = layout->flags;
275 if (!(flags & PARTY_STATUS_SHOW_PP))
277 if (work->menuState == 0 || BattleParty_CountStandbyDjinnFar(0, 0) == 0)
279 if (flags == PARTY_STATUS_CLOSED) {
280 UiWindow_EraseBorderRect(layout->x, layout->y, layout->width,
281 layout->height);
282 return;
283 }
284
285 // Redraw the frame, laying it out again when the flags changed.
286 work->menuBusy = 1;
287 if (layout->flags == flags) {
289 UiWindow_DrawColumnBorders(window, flags);
290 } else {
291 UiWindow_EraseBorderRect(layout->x, layout->y, layout->width,
292 layout->height);
294 window->width = layout->width;
295 window->height = layout->height;
296 window->x = layout->x;
297 UiWindow_DrawFrame(layout->x, layout->y, layout->width, layout->height);
298 UiWindow_DrawColumnBorders(window, flags);
299 }
300
301 // Each member's column: name, HP and PP, each bar 40 pixels at full.
302 if (flags & PARTY_STATUS_SHOW_DJINN)
304 for (i = 0; i != count; i++) {
305 struct BattleUnit *unit = UnitGetFar(members[i]);
306 s32 hp = unit->hp;
307 s32 maxHp = unit->maxHp;
308 s32 barLength;
309 s32 current;
310
311 if (hp == 0)
313 else if (hp <= maxHp / 4)
315 else
317 work->level = 14;
318 if (work->menuState != 0)
319 work->level = 5;
321 hp, window, (x + i * PARTY_STATUS_COLUMN_WIDTH) * 8, y * 8 + 8, 0);
322 work->level = 15;
323 UiText_DrawStringAtOffset(unit->name, window,
324 (x + i * PARTY_STATUS_COLUMN_WIDTH) * 8, y * 8);
326 if (unit->maxHp != 0) {
327 // A member with any HP left shows at least one pixel of bar.
328 current = unit->hp;
329 barLength = ((current * 40) / unit->maxHp);
330 if (barLength == 0 && current != 0)
331 barLength = 1;
333 y + 2, barLength);
334 }
335 if (flags & PARTY_STATUS_SHOW_PP) {
336 work->level = 14;
337 if (work->menuState != 0)
338 work->level = 5;
340 (x + i * PARTY_STATUS_COLUMN_WIDTH) * 8,
341 y * 8 + 16, 1);
342 if (unit->maxPp != 0) {
343 current = unit->pp;
344 barLength = ((current * 40) / unit->maxPp);
345 if (barLength == 0 && current != 0)
346 barLength = 1;
348 window, x + i * PARTY_STATUS_COLUMN_WIDTH + 1, y + 3, barLength);
349 }
350 }
351 }
352 work->level = 15;
353
354 // The Djinn column: each element's icon and its count of standby Djinn.
355 if (work->menuState != 0 && (flags & PARTY_STATUS_SHOW_DJINN)) {
356 s32 row = y;
357
358 if (flags & PARTY_STATUS_SHOW_PP)
359 row++;
360 BattleParty_CountStandbyDjinnFar(0, standbyDjinn);
362 row, 0);
364 row, 0);
366 row + 1, 0);
368 row + 1, 0);
369 PARTY_STATUS_PUT_DIGIT(window, standbyDjinn[0] + '0', 1, row);
370 PARTY_STATUS_PUT_DIGIT(window, standbyDjinn[1] + '0', 3, row);
371 PARTY_STATUS_PUT_DIGIT(window, standbyDjinn[2] + '0', 1, row + 1);
372 PARTY_STATUS_PUT_DIGIT(window, standbyDjinn[3] + '0', 3, row + 1);
373 }
374 work->menuBusy = 0;
375}
376
377/// Closes the party status window and frees its heap block.
379 // UB: reads the work slot's pointer through an s32 pointer; UBFIX reads
380 // the window through the block's own struct.
381#ifdef UBFIX
382 UiWork_Finalize(((struct PartyStatusWindow *)gWindowWork[1])->window, 1);
383#else
384 UiWork_Finalize((struct UiWindow *)**(s32 **)(u32)&gWindowWork[1], 1);
385#endif
387}
388
389/// Sets (`set` 1) or clears (0) bit 12 of the tilemap entries of the
390/// `width` x `height` tile rectangle at (x, y) inside `window`, clipped to the
391/// screen: bit 12 is the lowest bit of the entry's palette number, so this
392/// switches the rectangle between two palettes. The clip uses 29 for the
393/// bottom edge test and 20 for the clipped height.
394void UiWindow_SetTileAttributeBitRect(const struct UiWindow *window, s32 x,
395 s32 y, s32 width, s32 height, u32 set) {
396 struct UiRenderWork *work = UI_WORK;
397
398 x += window->x + 1;
399 y += window->y + 1;
400 set &= 1;
401 set <<= 12;
402 if (x < 0) {
403 width += x;
404 x = 0;
405 }
406 if (x + width > 29) {
407 width = 30 - x;
408 }
409 if (y < 0) {
410 height += y;
411 y = 0;
412 }
413 if (y + height > 29) {
414 height = 20 - y;
415 }
416 if (width > 0 && height > 0) {
417 // The byte offset of the first cell: 32 entries of 2 bytes a row.
418 y <<= 6;
419 x = y + (x << 1);
420 do {
421 u16 *cell = (u16 *)(x + (u32)work->tilemap);
422 s32 remaining = width;
423 while (remaining != 0) {
424 u32 entry = *cell;
425 entry &= ~0x1000;
426 entry |= set;
427 remaining--;
428 *cell = entry;
429 cell++;
430 }
431 height--;
432 x += 64;
433 } while (height != 0);
434 work->dirty = 1;
435 }
436}
437
438#undef PARTY_STATUS_PUT_DIGIT
What every part of the menu object shares: its includes, edition values, macros and the link round st...
@ SUMMON_ELEMENT_TILE
Element icon.
@ ELEMENT_MARS
Definition battle_unit.h:38
@ ELEMENT_MERCURY
Definition battle_unit.h:37
@ ELEMENT_VENUS
Definition battle_unit.h:36
@ ELEMENT_JUPITER
Definition battle_unit.h:39
struct BattleWork * gBattleWork
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 BattleParty_PrepareActiveOwnersFar(u16 *owners)
s32 BattleParty_CountStandbyDjinnFar(u32 unitId, u8 *counts)
struct BattleUnit * UnitGetFar(u32 owner)
s32 Party_CountActiveOwnersFar(void)
void UiWindow_DrawFrame(s32 x, s32 y, u32 width, u32 height)
Draws an empty window: a frame around a filled interior, at tile (x, y) of width by height tiles.
Definition frames.c:131
struct GameState gGameState
u8 gPartyStatusWork[]
const s8 gUiWindow_PartyColumnOffsets[]
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
#define WORK_SLOT(n)
Reads slots through their own addresses; adjacent slots are reached by offsets.
Definition heap_state.h:14
#define REG_DMA3
Definition io_reg.h:153
#define BG_PLTT_COLOR(palette, color)
Definition io_reg.h:158
s32 Palette_GetBasicObjColors(void)
Definition math.c:151
void Runtime_ReleaseHeapBlock(s32 slot)
void UiWindow_SetTileAttributeBitRect(const struct UiWindow *window, s32 x, s32 y, s32 width, s32 height, u32 set)
Sets (set 1) or clears (0) bit 12 of the tilemap entries of the width x height tile rectangle at (x,...
void UiWindow_BuildLayoutBounds(s32 flags)
Works out where the party status window goes for flags: one column per party member (those in battle ...
#define PARTY_STATUS_KEEP_FLAGS
redraw with the flags it has
s32 UiWindow_DrawStatusBarTiles(struct UiWindow *window, s32 x, s32 y, s32 length)
void UiWindow_CreateWithLayoutBounds(s32 flags)
Opens the party status window with flags (see PARTY_STATUS_*) in a new heap block and draws it.
#define PARTY_STATUS_CLOSED
erase the window
#define PARTY_STATUS_PUT_DIGIT(window, glyph, x, y)
void PartyStatusDraw(s32 flags)
Draws the party status window with flags (see PARTY_STATUS_*): each member's name,...
#define PARTY_STATUS_COLUMN_WIDTH
#define PARTY_STATUS_SHOW_DJINN
add the Djinn column (needs the PP row)
#define TILE_ROW_FROM_BOTTOM(tile, up)
The address of pixel row 7 - up of BG tile tile (4bpp, 32 bytes a tile, 4 bytes a row): the status ba...
void PartyStatus_Close(void)
Closes the party status window and frees its heap block.
#define PARTY_STATUS_DJINN_WIDTH
#define PARTY_STATUS_SHOW_PP
add the PP row
#define PARTY_STATUS_BLOCK
The heap block the party status window's layout lives in.
void UiWindow_DrawColumnBorders(struct UiWindow *window, u32 flags)
Draws the vertical lines between the members' columns of the party status window, with their top and ...
u8 gWindowWork[]
A unit in battle: a party member's or an enemy's stats, Psynergy, items, Djinn and ailments.
s16 maxPp
0 to 1999 for a character, 9999 for an enemy (UnitCalc)
u8 name[0x0f]
The name, one byte a character, ending in 0.
s16 hp
current HP, 0 when downed
s16 pp
current PP
s16 maxHp
0 to 1999 for a character, 9999 for an enemy (UnitCalc)
The battle's own work: its enemies, units and their objects, the turn's actions, the spoils,...
Definition battle_work.h:71
s16 partyUnits[7]
ends with BATTLE_UNIT_LIST_END
u8 activeOwners[8]
the party in order
Definition game_state.h:60
The party status window's layout: its window, its place and size, and what it shows (PARTY_STATUS_ fl...
Definition menu_list.h:84
u16 height
tiles
Definition menu_list.h:89
u16 flags
PARTY_STATUS_ flags.
Definition menu_list.h:90
struct UiWindow * window
Definition menu_list.h:85
The window system's work: the windows' tilemap, the windows, the three text channels,...
Definition window.h:19
u16 tilemap[640]
the windows' BG tilemap, 32 by 20 tiles
Definition window.h:20
u8 dirty
The tilemap's 4-row bands to upload: bit 0 for all, bit n + 1 for band n.
Definition window.h:32
u8 level
text tiles' palette; 15 by default, 14 or 5 for low HP
Definition window.h:41
u16 count
where the next code goes in entries
Definition window.h:48
u16 colour
the current channel's, copied in to draw
Definition window.h:45
u8 menuState
1 from the work's setup; 2 while a battle message is decoded.
Definition window.h:39
u8 menuBusy
while set, the tilemap is not uploaded
Definition window.h:40
A window: a framed rectangle of the tilemap with its sprite outputs, its opening or closing animation...
Definition uiwindow.h:11
u16 y
tiles
Definition uiwindow.h:16
u16 x
tiles
Definition uiwindow.h:15
u16 height
tiles
Definition uiwindow.h:14
u16 width
tiles
Definition uiwindow.h:13
void UiText_DrawPrefixedNumberAtOffset(s32 value, const struct UiWindow *work, s32 offsetX, s32 offsetY, s32 variant)
Draws a four-digit number after a two-glyph sign (window tiles 0x1d and 0x1e, or 0x1f and 0x1e with v...
Definition text_tiles.c:689
void UiText_DrawStringAtOffset(const u8 *text, const struct UiWindow *work, s32 offsetX, s32 offsetY)
Draws a byte string as tiles in window work at pixel (offsetX, offsetY) of its interior.
Definition text_tiles.c:614
void UiWork_SetParamNibble(s32 param)
Sets the text colour (0 to 15) of drawn text.
Definition text_tiles.c:524
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
unsigned char u8
Definition types.h:11
#define UI_WORK
Definition window.h:267
#define DMA_COPY16(count)
The DMA control word that copies count halfwords.
Definition window.h:114
@ UI_TILE_BATTLE_FRAME_BOTTOM_LEFT
In battle, the bottom frame tiles' lower rows, which UiWork_Initialize copies to tiles 128 to 130.
Definition window.h:99
@ UI_TILE_FRAME_BOTTOM_TEE
the bottom edge meeting a line
Definition window.h:94
@ UI_TILE_BATTLE_FRAME_BOTTOM
Definition window.h:100
@ UI_TILE_BATTLE_FRAME_BOTTOM_RIGHT
Definition window.h:101
@ UI_TILE_FRAME_TOP_TEE
the top edge meeting a line
Definition window.h:93
@ UI_TILE_DIVIDER_VERTICAL
Definition window.h:92
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
void UiWindow_EraseBorderRect(s32 x, s32 y, u32 width, u32 height)
Erases a window's rectangle of the tilemap (x, y, width and height in tiles), clamped to the screen.
Definition windows.c:187
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