Alchemy
Loading...
Searching...
No Matches

cursor.c

Go to the documentation of this file.
1/// @file
2/// The selection frame and price digit tiles, and the hand cursor.
3/// Part of shop.c, the shop object, compiled only through it.
4
5#include "../shop_internal.h"
6
7/// Where each of the quantity bar's 30 segments starts in its tile buffer.
8// clang-format off
9static const u16 sSelectorTileOffsets[30] = {
10 0x00, 0x01, 0x02, 0x03,
11 0x20, 0x21, 0x22, 0x23,
12 0x40, 0x41, 0x42, 0x43,
13 0x60, 0x61, 0x62, 0x63,
14 0x80, 0x81, 0x82, 0x83,
15 0xa0, 0xa1, 0xa2, 0xa3,
16 0xc0, 0xc1, 0xc2, 0xc3,
17 0xe0, 0xe1,
18};
19// clang-format on
20
21/// Colours the first `itemCount` segments of the quantity bar with palette
22/// `paletteSelector`, writing six pixels a segment in `tileBuffer`. Called by
23/// the shop's quantity choice and, through SHOP.S, by the item menu's
24/// quantity bar, which draws its bar in four colours this way.
25void Shop_FillSelector(s32 itemCount, s32 paletteSelector, u8 *tileBuffer) {
26 const u16 *tileOffset;
27
28 paletteSelector = (paletteSelector << 4) + 1;
29
30 if (itemCount > 0) {
31 tileOffset = sSelectorTileOffsets;
32 do {
33 struct SelectorRecord *record =
34 (struct SelectorRecord *)(tileBuffer + *tileOffset++);
35 record->values[0] = paletteSelector;
36 record->values[4] = paletteSelector;
37 record->values[8] = paletteSelector;
38 record->values[12] = paletteSelector;
39 record->values[16] = paletteSelector;
40 record->values[20] = paletteSelector;
41 itemCount--;
42 } while (itemCount != 0);
43 }
44}
45
46/// Where each of a price's five digits starts in its tile buffer, ones first.
47// clang-format off
48static const u16 sPriceDigitTileOffsets[5] = {
49 0xc0, 0x90, 0x80, 0x50, 0x40,
50};
51// clang-format on
52
53/// Copies decimal glyph `digit` into its price-tile position, stopping at
54/// zero source bytes. Called by Shop_CreatePriceSprite.
55void Shop_CopyGlyphs(s32 digit, u8 *tileBuffer, u32 digitPosition) {
56 u8 *src = gShop_GlyphBytes + (digit << 5);
57 u8 *dst = tileBuffer + sPriceDigitTileOffsets[digitPosition] + 2;
58 s32 count = 3;
59
60 do {
61 if (*src != 0) {
62 dst[0] = *src++;
63 if (*src != 0) {
64 dst[1] = *src++;
65 if (*src != 0) {
66 dst[30] = *src++;
67 if (*src != 0)
68 dst[31] = *src++;
69 }
70 }
71 }
72 dst += 4;
73 count--;
74 } while (count >= 0);
75}
76
77/// Builds a price of up to five digits in scratch tiles (heap slot 14), loads
78/// them into a free VRAM cache slot and attaches them to `window` as one
79/// sprite at (x, y). Returns the sprite, or NULL with no free slot. Called by
80/// Shop_DrawStock for each item on sale.
81struct RenderOutput *Shop_CreatePriceSprite(s32 value, struct UiWindow *window,
82 s32 x, s32 y) {
83 u8 *tileBuffer;
84 s32 resourceSlot;
85 struct RenderOutput *priceSprite;
86
87 tileBuffer = Runtime_AllocateBlock(14, 0x400);
88 priceSprite = 0;
89 Dma_Set(gShop_PriceTiles, tileBuffer, (DMA_ENABLE | DMA_32BIT) << 16 | 0x40,
90 REG_DMA3);
91 Shop_CopyGlyphs(value % 10, tileBuffer, 0);
92 value = value / 10;
93 if (value != 0) {
94 Shop_CopyGlyphs(value % 10, tileBuffer, 1);
95 value = value / 10;
96 if (value != 0) {
97 Shop_CopyGlyphs(value % 10, tileBuffer, 2);
98 value = value / 10;
99 if (value != 0) {
100 s32 remainingDigits;
101
102 Shop_CopyGlyphs(value % 10, tileBuffer, 3);
103 remainingDigits = value / 10;
104 if (remainingDigits != 0)
105 Shop_CopyGlyphs(remainingDigits % 10, tileBuffer, 4);
106 }
107 }
108 }
109 resourceSlot = Resource_FindFreeEntry();
110 if (resourceSlot != VRAM_CACHE_ENTRY_COUNT) {
111 VramCache_Load(resourceSlot, 0x100, tileBuffer);
112 priceSprite =
113 RenderOutput_CreateFar(resourceSlot, 0x80008000, window, x, y);
114 }
116 return priceSprite;
117}
118
119/// Saves the field colours in event work and fades to `layer` over 16 frames.
120/// Called before sanctum and Djinn capture effects and Altmiller's wall burst;
121/// Shop_RestoreFieldPalette restores the saved colours afterward.
123 // UB: slot 32 lies past scalar gEventWork. Its named load adds eight
124 // bytes in the native EN trial (0x54 to 0x5c).
125#ifdef UBFIX
126 struct BattleEffectBuffers *paletteBuffers = gPaletteBufferWork;
127 u8 *eventBytes = (u8 *)gEventWork;
128#else
129 u32 *workCells = (u32 *)&gEventWork;
130 struct BattleEffectBuffers *paletteBuffers =
131 (struct BattleEffectBuffers *)workCells[5];
132 u8 *eventBytes = (u8 *)workCells[0];
133#endif
134 u16 *savedPalette = paletteBuffers->target;
135
136 Dma_Set(savedPalette, eventBytes + 0x236,
137 (DMA_ENABLE | DMA_32BIT) << 16 | 0x150, REG_DMA3);
138 Dma_Set(savedPalette, paletteBuffers->current,
139 (DMA_ENABLE | DMA_32BIT) << 16 | 0x2a0, REG_DMA3);
142}
143
144/// Fades back to the colours Shop_SaveAndTintFieldPalette saved, over 16
145/// frames. Called when the sanctum, Djinn capture or Altmiller wall effect
146/// ends.
150}
151
152/// Moves the cursor from its saved position toward its target, in a straight
153/// line over `kind` frames, one frame a call; `active` counts the frames and
154/// both go back to 0 on arrival. Runs every frame from Shop_StepCursor, and
155/// from the option, name entry and save menus' cursor tasks.
156void ShopCursor_Advance(struct ShopCursor *cursor) {
157 struct RenderOutput *sprite;
158 s32 durationFrames;
159 s32 frame;
160 s32 cursorX;
161 s32 cursorY;
162
163 if (cursor == NULL)
164 return;
165 durationFrames = cursor->kind;
166 if (durationFrames == 0)
167 return;
168 sprite = cursor->anchor;
169 frame = ++cursor->active;
170 cursorX =
171 cursor->x + (cursor->targetX - (s16)cursor->x) * frame / durationFrames;
172 sprite->x = cursorX;
173 sprite->oam.x = cursorX;
174 cursorY =
175 cursor->y + (cursor->targetY - (s16)cursor->y) * frame / durationFrames;
176 sprite->y = cursorY;
177 sprite->oam.y = cursorY;
178 if (frame == durationFrames) {
179 cursor->kind = 0;
180 cursor->active = 0;
181 }
182}
183
184/// Moves each cursor axis one quarter of the remaining distance, with a minimum
185/// one-pixel step. Called each frame by the option menu and name entry.
187 struct RenderOutput *sprite;
188 s32 delta;
189 s32 step;
190
191 sprite = cursor->anchor;
192 if (sprite != NULL) {
193 delta = sprite->x - cursor->targetX;
194 step = delta / 4;
195 if (step < 0)
196 step = -step;
197 if (delta > 0) {
198 if (step != 0)
199 sprite->x = sprite->x - step;
200 else
201 sprite->x = sprite->x - 1;
202 sprite->oam.x = sprite->x;
203 } else if (delta < 0) {
204 if (step != 0)
205 sprite->x = sprite->x + step;
206 else
207 sprite->x = sprite->x + 1;
208 sprite->oam.x = sprite->x;
209 }
210
211 delta = sprite->y - cursor->targetY;
212 step = delta / 4;
213 if (step < 0)
214 step = -step;
215 if (delta > 0) {
216 if (step != 0)
217 sprite->y = sprite->y - step;
218 else
219 sprite->y = sprite->y - 1;
220 sprite->oam.y = sprite->y;
221 } else if (delta < 0) {
222 if (step != 0)
223 sprite->y = sprite->y + step;
224 else
225 sprite->y = sprite->y + 1;
226 sprite->oam.y = sprite->y;
227 }
228 }
229}
230
231/// Starts a glide of the cursor from where it is to (targetX, targetY) over
232/// `kind` frames, for ShopCursor_Advance to run. Called by Shop_PlaceCursor
233/// and, through SHOP.S, by name entry and the Colosso choice.
234void Shop_SetCursor(struct ShopCursor *cursor, s32 targetX, s32 targetY,
235 s32 kind) {
236 struct RenderOutput *anchor = cursor->anchor;
237
238 cursor->x = anchor->x;
239 cursor->y = anchor->y;
240 cursor->targetX = targetX;
241 cursor->targetY = targetY;
242 cursor->kind = kind;
243 cursor->active = 0;
244}
245
246/// Places the cursor and its sprite at (x, y) at once, with a one-frame glide
247/// that has already arrived. Called when a counter, the option and system
248/// menus or name entry opens.
250
251 {
252 struct RenderOutput *sprite = cursor->anchor;
253
254 cursor->targetX = x;
255 cursor->kind = 1;
256 cursor->active = 0;
257 cursor->x = x;
258 sprite->oam.x = sprite->x = x;
259 }
260 {
261 struct RenderOutput *sprite;
262
263 cursor->targetY = y;
264 cursor->y = y;
265 sprite = cursor->anchor;
266 sprite->oam.y = sprite->y = y;
267 }
268}
269
270/// Starts the hand cursor's glide to (x, y) pixels inside `window` (the
271/// screen when it is NULL), over the frames shop->mode holds. Called by every
272/// counter's lists.
273void Shop_PlaceCursor(struct UiWindow *window, s32 x, s32 y) {
274 s32 cursorX;
275 s32 cursorY;
276 struct ShopRuntime *shop;
277
278 cursorX = x;
279 cursorY = y;
280 shop = gMenuWork;
281 if (window != NULL) {
282 cursorX = cursorX + (window->x * 8) + 8;
283 cursorY = cursorY + (window->y * 8) + 8;
284 }
285 Shop_SetCursor(&shop->cursor, cursorX, cursorY, (s8)shop->mode);
286}
struct BattleEffectBuffers * gPaletteBufferWork
static const u16 sSelectorTileOffsets[30]
Where each of the quantity bar's 30 segments starts in its tile buffer.
Definition cursor.c:9
void Shop_SetCursor(struct ShopCursor *cursor, s32 targetX, s32 targetY, s32 kind)
Starts a glide of the cursor from where it is to (targetX, targetY) over kind frames,...
Definition cursor.c:234
void Shop_PlaceCursor(struct UiWindow *window, s32 x, s32 y)
Starts the hand cursor's glide to (x, y) pixels inside window (the screen when it is NULL),...
Definition cursor.c:273
void ShopCursor_Advance(struct ShopCursor *cursor)
Moves the cursor from its saved position toward its target, in a straight line over kind frames,...
Definition cursor.c:156
void Shop_CopyGlyphs(s32 digit, u8 *tileBuffer, u32 digitPosition)
Copies decimal glyph digit into its price-tile position, stopping at zero source bytes.
Definition cursor.c:55
void Shop_RestoreFieldPalette(void)
Fades back to the colours Shop_SaveAndTintFieldPalette saved, over 16 frames.
Definition cursor.c:147
static const u16 sPriceDigitTileOffsets[5]
Where each of a price's five digits starts in its tile buffer, ones first.
Definition cursor.c:48
struct RenderOutput * Shop_CreatePriceSprite(s32 value, struct UiWindow *window, s32 x, s32 y)
Builds a price of up to five digits in scratch tiles (heap slot 14), loads them into a free VRAM cach...
Definition cursor.c:81
void Shop_SaveAndTintFieldPalette(s32 layer)
Saves the field colours in event work and fades to layer over 16 frames.
Definition cursor.c:122
void ShopCursor_SetPositionImmediate(struct ShopCursor *cursor, s32 x, s32 y)
Places the cursor and its sprite at (x, y) at once, with a one-frame glide that has already arrived.
Definition cursor.c:249
void ShopCursor_MoveTowardTarget(struct ShopCursor *cursor)
Moves each cursor axis one quarter of the remaining distance, with a minimum one-pixel step.
Definition cursor.c:186
void Shop_FillSelector(s32 itemCount, s32 paletteSelector, u8 *tileBuffer)
Colours the first itemCount segments of the quantity bar with palette paletteSelector,...
Definition cursor.c:25
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
void BattleFx_ApplyColorToTargetBufferFar(s32 mode, s32 half)
void BattleFx_StartBufferInterpolationFar(s32 frames)
struct RenderOutput * RenderOutput_CreateFar(s32 slot, s32 flags, struct UiWindow *input, s32 offsetX, s32 offsetY)
void * gMenuWork
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 DMA_32BIT
Definition io_reg.h:210
#define REG_DMA3
Definition io_reg.h:153
#define DMA_ENABLE
Definition io_reg.h:217
void Runtime_ReleaseHeapBlock(s32 slot)
u8 gShop_GlyphBytes[]
const u8 gShop_PriceTiles[]
What every part of the shop object shares: its includes, the shop actions and sanctum services,...
struct EventWork * gEventWork
#define NULL
Definition bilibin.h:6
The colour buffer (heap block 32) that fades the BG and OBJ palettes: the source palette,...
Definition palbuf.h:40
u16 current[0x540]
The shown colours, as B, G and R channels shifted up 10 bits, three a colour.
Definition palbuf.h:46
u16 target[0x540]
the colours current moves toward, as current
Definition palbuf.h:47
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
u16 x
screen pixels
s8 kind
0 for a glyph; otherwise it owns VRAM cache slot index, freed with it, and 2 (a portrait) also its pa...
Byte view of the six colour writes in a quantity-bar segment.
Definition run.c:205
u8 values[21]
palette bytes at indices 0, 4, 8, 12, 16 and 20
Definition run.c:207
Cursor that approaches its target, shared by shop, name entry and settings.
Definition cursor.h:13
s16 targetY
screen pixels
Definition cursor.h:18
u16 x
screen pixels: where the current move started
Definition cursor.h:15
s8 kind
frames the move takes; 0 when the cursor is still
Definition cursor.h:20
u16 y
screen pixels: where the current move started
Definition cursor.h:16
struct RenderOutput * anchor
the cursor's sprite, moved with its OAM
Definition cursor.h:14
s8 active
frames of the current move done; reset when it ends
Definition cursor.h:19
s16 targetX
screen pixels
Definition cursor.h:17
A shop's work: its windows, the party members' icons, the stock, the cursor and its icons,...
Definition shop.h:18
struct ShopCursor cursor
the hand cursor
Definition shop.h:31
u8 mode
passed on as the hand cursor's kind; set to 12 at first
Definition shop.h:48
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
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
signed char s8
Definition types.h:10
signed short s16
Definition types.h:12
unsigned short u16
Definition types.h:13
unsigned char u8
Definition types.h:11
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
@ VRAM_CACHE_ENTRY_COUNT
Definition vram_tab.h:12