Alchemy
Loading...
Searching...
No Matches

sell.c

Go to the documentation of this file.
1/// @file
2/// Selling: choosing a party member, the item grid and the sale.
3/// Part of shop.c, the shop object, compiled only through it.
4
5#include "../shop_internal.h"
6
7/// Lets the player choose whose items to sell or repair, with the coins
8/// window and the member's item grid, and runs Shop_SelectSell or
9/// Shop_SelectRepair for each member chosen until B. Called by Shop_Run for
10/// Sell and Repair.
12 struct ShopRuntime *shop = gMenuWork;
13 struct UiWindow *listWindow;
14 s32 memberIndex = 0;
15 s32 redraw = 1;
16 s32 unitId = 0;
17
20 shop->itemWindow = UiWindow_CreateFar(16, 12, 14, 8, 2);
21 listWindow = UiWindow_CreateFar(0, 14, 13, 3, 2);
22 shop->cursor.anchor->active = 4;
23 shop->mode = 12;
24 PsynergyMenu_InitializeEntryObjectsFar(listWindow, 2, 0, 8, 0);
25
26 for (;;) {
27 if (redraw != 0) {
28 redraw = 0;
29 memberIndex =
30 (memberIndex + shop->partyMemberCount) % shop->partyMemberCount;
31 unitId = shop->partyMemberIds[memberIndex];
32 Shop_PlaceCursor(listWindow, memberIndex * 24 - 12, 0);
33 shop->mode = 3;
34 Shop_DrawParty(listWindow, memberIndex, 0);
35 Shop_DrawUnitGrid(shop->itemWindow, unitId);
36 }
37
38 if ((gKeysPressed & KEY_A) != 0) {
39 WaitFrames(1);
40 if (Inventory_CountFar(unitId) == 0) {
42 } else {
44 if (shop->partyAction == SHOP_ACTION_SELL)
45 Shop_SelectSell(unitId);
46 else
47 Shop_SelectRepair(unitId);
48 shop->cursor.anchor->active = 4;
49 shop->mode = 12;
50 redraw = 1;
51 }
52 continue;
53 }
54
55 if ((gKeysPressed & KEY_B) != 0) {
58 UiWork_FinalizeFar(listWindow, 2);
61 WaitFrames(1);
62 return 0;
63 }
64
65 if ((gKeysRepeat & KEY_LEFT) != 0) {
67 memberIndex--;
68 redraw = 1;
69 }
70 if ((gKeysRepeat & KEY_RIGHT) != 0) {
72 memberIndex++;
73 redraw = 1;
74 }
75 WaitFrames(1);
76 }
77}
78
79/// Lets the player choose items to sell from the member's grid, one at a
80/// time, with each one's price and description, until B or the inventory is
81/// empty. Returns -1 when cancelled, 0 when the inventory ran out. Called by
82/// Shop_PickUnit.
84 // Shared previous/next-row inlines added four bytes to each sell, repair and
85 // use picker in the English native build; the direct row arithmetic remains.
86 struct UiWindow *descriptionWindow;
87 struct ShopRuntime *shop;
88 struct UiWindow *priceWindow;
89 struct BattleUnit *unit;
90 s32 slot;
91 s32 inventoryCount;
92 s32 redraw;
93 s32 result;
94 s32 itemId;
95 s32 quantity;
96 struct UiWindow *window;
97 s32 x;
98
99 shop = gMenuWork;
100 unit = UnitGetFar(unitId);
101 inventoryCount = 1;
102 priceWindow = UiWindow_CreateFar(SHOP_LIST_X, 8, SHOP_LIST_WIDTH, 4, 2);
103 slot = 0;
104
105 for (;;) {
106 descriptionWindow = UiWindow_CreateFar(0, 5, 30, 3, 2);
107 shop->cursor.anchor->active = 18;
108 shop->mode = 12;
109 redraw = 1;
110
111 while (1) {
112 if (redraw != 0) {
113 redraw = 0;
114 inventoryCount = Inventory_CountFar(unitId);
115 if (slot > inventoryCount - 1)
116 slot = inventoryCount - 1;
117 itemId = ITEM_ID_MASK & unit->inventory[slot];
118 window = shop->itemWindow;
119 x = slot % SHOP_INVENTORY_COLUMNS * 16;
120 Shop_PlaceCursor(window, x, slot / SHOP_INVENTORY_COLUMNS * 16 + 8);
121 shop->mode = 3;
122 Shop_DrawItemPrice(priceWindow, itemId,
123 Shop_SalePrice(unit->inventory[slot]), 1);
124 Shop_DrawMsg(descriptionWindow, itemId + MsgItemPlainName);
125 }
126
127 if ((gKeysPressed & KEY_A) != 0) {
129 result = 0;
130 break;
131 }
132 if ((gKeysPressed & KEY_B) != 0) {
134 result = -1;
135 break;
136 }
137 if ((gKeysRepeat & KEY_LEFT) != 0) {
139 slot -= 1;
140 slot = (slot + inventoryCount) % inventoryCount;
141 redraw = 1;
142 }
143 if ((gKeysRepeat & KEY_RIGHT) != 0) {
145 slot += 1;
146 slot = (slot + inventoryCount) % inventoryCount;
147 redraw = 1;
148 }
149 if ((gKeysRepeat & KEY_UP) != 0) {
151 if (slot < 0)
152 slot += INVENTORY_SLOTS;
153 while (slot >= inventoryCount)
156 redraw = 1;
157 }
158 if ((gKeysRepeat & KEY_DOWN) != 0) {
160 if (slot >= inventoryCount)
161 slot -= INVENTORY_SLOTS;
162 while (slot < 0)
165 redraw = 1;
166 }
167 WaitFrames(1);
168 }
169
170 UiWork_FinalizeFar(descriptionWindow, 2);
171 WaitFrames(1);
172 if (result != 0)
173 break;
174
175 quantity = Shop_SelectSellNum(unitId, slot);
176 if (quantity != -1)
177 Shop_SellItem(unitId, slot, quantity);
178 UiMessage_ShowAndWait(MsgSellAnythingElse);
179 if (Inventory_CountFar(unitId) == 0)
180 break;
181 }
182
183 UiWork_FinalizeFar(priceWindow, 2);
184 return result;
185}
186
187/// Draws the member's items as icons in rows of five, or a line saying it has
188/// none. Called by the sell, repair and drop screens each time the
189/// member changes, and after a sale.
190void Shop_DrawUnitGrid(struct UiWindow *window, s32 unitId) {
191 struct BattleUnit *unit;
192 s32 x;
193 s32 y;
194 s32 slot;
195 struct RenderOutput *icon;
196
197 unit = UnitGetFar(unitId);
198 x = 8;
199 y = 0;
200 if (window != 0) {
202 if (Inventory_CountFar(unitId) == 0) {
203 UiText_DrawResourceFar(MsgNoItems, window, SHOP_EMPTY_GRID_X,
205 } else {
206 slot = 0;
207 do {
208 if (unit->inventory[slot] != 0) {
209 icon = RenderOutput_CreateLoadedFar(unit->inventory[slot], 27, window,
210 x, y);
211 icon->sentinel = 252;
212 }
213 x += 16;
214 if (slot == 4) {
215 x = 8;
216 y += 16;
217 }
218 if (slot == 9) {
219 x = 8;
220 y += 16;
221 }
222 slot++;
223 } while (slot < INVENTORY_SLOTS);
224 }
225 }
226}
227
228/// Asks how many to sell when the item is a stack of more than one, and
229/// returns the count (1 otherwise, -1 when cancelled), putting the cursor
230/// back after. Called by Shop_SelectSell.
232 s32 result;
233 s16 savedX;
234 s16 savedY;
235 s32 unitSalePrice;
236 s32 stackQuantity;
237 s32 quantityLimit;
238 struct ItemDefinition *item;
239 struct ShopRuntime *shop;
240 struct BattleUnit *unit;
241
242 shop = gMenuWork;
243 unit = UnitGetFar(unitId);
244 item = Item_GetDirectFar(unit->inventory[slot]);
245 result = 1;
246 unitSalePrice = Shop_SalePrice(unit->inventory[slot]);
247 stackQuantity = Shop_GetSelectionState(unitId, slot);
248 quantityLimit = stackQuantity;
249 if ((item->flags & ITEM_STACKABLE) && stackQuantity > 1) {
250 UiMessage_ShowAndWait(MsgHowManyToSell);
251 savedX = shop->cursor.targetX;
252 savedY = shop->cursor.targetY;
253 shop->cursor.anchor->active = 4;
254 shop->mode = 0xc;
256 result = Shop_SelectQuantity(0, quantityLimit, unitSalePrice);
257 WaitFrames(1);
259 Shop_PlaceCursor(NULL, savedX, savedY);
260 }
261 return result;
262}
263
264/// Sells `count` of the item in `slot`: refuses an item the shop does not buy
265/// or one equipped and cursed on, asks with the offer that fits (an old item
266/// the player just replaced, a broken one, a stack, a rare one), then
267/// discards them, pays the coins and redraws. `count` -1 is the old
268/// equipment the equip prompt offers to sell (Shop_SellOld).
269void Shop_SellItem(s32 unitId, s32 slot, s32 count) {
270 struct ShopRuntime *shop = gMenuWork;
271 struct BattleUnit *unit = UnitGetFar(unitId);
272 s32 itemId = unit->inventory[slot] & ITEM_ID_MASK;
273 struct ItemDefinition *item = Item_GetDirectFar(itemId);
274 u8 rare = item->flags & ITEM_RARE;
275 s32 sellingReplacedItem = 0;
276 s32 total;
277 s32 message;
278 s32 soldCount;
279
280 if (count == -1) {
281 sellingReplacedItem = 1;
282 count = 1;
283 }
284 total = Shop_SalePrice(unit->inventory[slot]) * count;
285 if (total == 0) {
286 UiWork_PushValueSlotFar(itemId, 2);
287 UiMessage_ShowAndRestoreState(MsgWeDoNotBuy);
288 return;
289 }
290 if ((unit->inventory[slot] & INVENTORY_EQUIPPED) &&
291 (item->flags & ITEM_CANNOT_UNEQUIP)) {
292 UiWork_PushValueSlotFar(itemId, 2);
293 UiMessage_ShowAndRestoreState(MsgCannotSellEquipped);
294 return;
295 }
296 if (sellingReplacedItem)
297 message = MsgOldItemSellOffer;
298 else if (unit->inventory[slot] & INVENTORY_BROKEN)
299 message = MsgDamagedSellOffer;
300 else if (count > 1)
301 message = MsgSellTotal;
302 else if (rare)
303 message = MsgRareSellOffer;
304 else
305 message = MsgSellOffer;
306 UiWork_PushValueSlotFar(itemId, 2);
307 UiWork_PushValueSlotFar(total, 5);
309 if (UiMessage_ShowChoice(0) != 0) {
310 if (rare || sellingReplacedItem)
311 message = MsgKeepIt;
312 else
313 message = MsgChangedMind;
315 return;
316 }
317 // Discard each item before crediting coins and rebuilding the inventory grid.
319 for (soldCount = 0; soldCount < count; soldCount++)
320 Inventory_DiscardFar(unitId, slot);
323 Shop_DrawUnitGrid(shop->itemWindow, unitId);
324 if (rare || sellingReplacedItem)
325 message = MsgSold;
326 else
327 message = MsgDeal;
329}
void Shop_DrawParty(struct UiWindow *window, s32 selected, s32 itemId)
Shows the chosen member walking and the others standing, and draws at four fifths of their size the m...
Definition buy.c:382
s32 Shop_SalePrice(s32 inventoryEntry)
Returns what the shops pay for an inventory entry: nothing for an indispensable item,...
Definition buy.c:803
void Shop_DrawMoney(void)
Draws the party's coins in the coins window, in the edition's layout.
Definition buy.c:305
void Shop_DrawMsg(struct UiWindow *window, s32 message)
Shows message, an item's description, in the help window; a NULL window is ignored.
Definition buy.c:367
s32 Shop_SelectQuantity(s32 minimum, s32 maximum, s32 price)
Chooses how many items to buy or sell, returning the quantity above minimum or -1 when cancelled.
Definition buy.c:611
void Shop_DrawItemPrice(struct UiWindow *window, s32 itemId, s32 price, s32 priceKind)
Draws the item's name and below it its price.
Definition buy.c:328
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
struct BattleUnit * UnitGetFar(u32 owner)
struct ItemDefinition * Item_GetDirectFar(s32 item)
s32 Inventory_CountFar(s32 owner)
s32 Shop_GetSelectionState(s32 owner, s32 slot)
Far call to Inventory_GetQuantity.
s32 Inventory_DiscardFar(s32 owner, s32 slot)
s32 Party_AdjustCoinsFar(s32 amount)
void Menu_ReleaseEntryObjectsFar(void)
void UiIcon_PrepareObjectFar(struct RenderOutput *object)
void PsynergyMenu_InitializeEntryObjectsFar(void *source, s32 originX, s32 originY, s32 spacing, s32 unused)
void AudioCommand_PlayFar(s32 id)
void RenderOutput_PrepareForRedrawFar(struct UiWindow *window)
struct UiWindow * UiWindow_CreateFar(s32 x, s32 y, s32 width, s32 height, s32 attrs)
struct RenderOutput * RenderOutput_CreateLoadedFar(s32 code, s32 layers, struct UiWindow *input, s32 x, s32 y)
void UiText_DrawResourceFar(s32 arg0, struct UiWindow *arg1, s32 arg2, s32 arg3)
void UiWork_FinalizeFar(struct UiWindow *work, s32 release)
void UiWork_PushValueSlotFar(u32 value, u32 kind)
void WaitFrames(s32 frames)
The game's frame loop: runs frames frames and returns.
Definition frame.c:97
void * gMenuWork
@ 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
@ INVENTORY_EQUIPPED
Definition item.h:17
@ INVENTORY_SLOTS
Definition item.h:23
@ ITEM_ID_MASK
Definition item.h:16
@ INVENTORY_BROKEN
Definition item.h:18
@ ITEM_CANNOT_UNEQUIP
Definition item.h:28
@ ITEM_STACKABLE
Definition item.h:31
@ ITEM_RARE
selects the shop's rare item offers
Definition item.h:29
volatile u32 gKeysPressed
Keys that went down this frame.
volatile u32 gKeysRepeat
Pressed keys, repeating while held: after 19 frames, then every 6.
s32 Shop_SelectRepair(s32 unitId)
Lets the player choose items to repair from the member's grid, one at a time, with each one's repair ...
Definition repair.c:30
void UiMessage_ShowAndRestoreState(s32 messageId)
Shows a shopkeeper's line as UiMessage_ShowAndWait does, hiding the hand cursor while it shows and pu...
Definition run.c:239
s32 UiMessage_ShowChoice(s32 choice)
Runs the Yes or No choice beside the shopkeeper's line and returns it, keeping the hand cursor's moti...
Definition run.c:278
void UiMessage_ShowAndWait(s32 messageId)
Shows a shopkeeper's line and waits for its window to finish, one more frame included.
Definition run.c:214
s32 Shop_SelectSellNum(s32 unitId, s32 slot)
Asks how many to sell when the item is a stack of more than one, and returns the count (1 otherwise,...
Definition sell.c:231
s32 Shop_SelectSell(s32 unitId)
Lets the player choose items to sell from the member's grid, one at a time, with each one's price and...
Definition sell.c:83
s32 Shop_PickUnit(void)
Lets the player choose whose items to sell or repair, with the coins window and the member's item gri...
Definition sell.c:11
void Shop_SellItem(s32 unitId, s32 slot, s32 count)
Sells count of the item in slot: refuses an item the shop does not buy or one equipped and cursed on,...
Definition sell.c:269
void Shop_DrawUnitGrid(struct UiWindow *window, s32 unitId)
Draws the member's items as icons in rows of five, or a line saying it has none.
Definition sell.c:190
What every part of the shop object shares: its includes, the shop actions and sanctum services,...
#define SHOP_QUANTITY_CURSOR_X
#define SHOP_EMPTY_GRID_X
@ SHOP_INVENTORY_COLUMNS
#define SHOP_MONEY_WINDOW_WIDTH
@ SHOP_ACTION_SELL
#define SHOP_EMPTY_GRID_Y
#define SE_102
Definition songs.h:95
#define SE_MENU_CANCEL
Definition songs.h:106
#define SE_MENU_CURSOR_MOVE
Definition songs.h:104
#define SE_MENU_CONFIRM
Definition songs.h:105
#define NULL
Definition bilibin.h:6
A unit in battle: a party member's or an enemy's stats, Psynergy, items, Djinn and ailments.
u16 inventory[15]
Items held, one entry each: bits 15..11 quantity | 10 broken | 9 equipped | 8..0 item id (INVENTORY_*...
An item's definition: its price, type, who can equip it, its bonuses and unleash, its effects and the...
Definition item.h:104
u8 flags
enum ItemFlags
Definition item.h:107
A render output: a sprite in a window's output list (a character, an icon or a portrait),...
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 x
screen pixels
s16 targetY
screen pixels
Definition cursor.h:18
struct RenderOutput * anchor
the cursor's sprite, moved with its OAM
Definition cursor.h:14
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
s8 partyMemberCount
Definition shop.h:47
struct UiWindow * itemWindow
Definition shop.h:22
struct ShopCursor cursor
the hand cursor
Definition shop.h:31
s16 partyMemberIds[9]
the party in order (Party_ListActiveOwners)
Definition shop.h:30
struct UiWindow * moneyWindow
the coins window
Definition shop.h:20
s8 partyAction
the counter chosen (enum ShopAction)
Definition shop.h:50
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 x
tiles
Definition uiwindow.h:15
#define SHOP_LIST_X
#define SHOP_LIST_WIDTH
signed int s32
Definition types.h:14
signed short s16
Definition types.h:12
unsigned char u8
Definition types.h:11