Pokered Save Editor 2
Pokemon Red & Blue save file editor - Qt 6 C++/QML
Loading...
Searching...
No Matches
itemmarketentrystoreitem.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2020 Twilight
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15*/
16
21
22#include <QDebug>
23
25#include <pse-db/itemsdb.h>
30
35 : ItemMarketEntry(CompatEither, CompatEither), // Any currency; buying, but coexists
36 // with sells in the unified cart, so it
37 // no longer mode-gates on the buy flag.
38 data(data),
39 toBag(toBag),
41{
42 cartSignVal = -1; // buying spends the active currency
44}
45
47
49{
50 return (data != nullptr) ? data->getInfo() : QString();
51}
52
54{
55 if(!requestFilter())
56 return StackReturn();
57
58 // Temp copy of on cart, we don't want to change the actual onCart
59 int _onCart = onCart;
60
61 // Start off with no counted stacks. This represents the number of full new
62 // stacks required by the cart items.
63 int stacks = 0;
64
65 // and no counted partial stacks. This represents the space left on the stack
66 // as required by the cart items.
67 // If there are 25 stack items left, all 25, or maybe 20, 15, or 5 may be
68 // required. This is the required amount that can be given to a partial
69 // stack before moving to new full stacks if need be.
70 int stackPartialBag = 0;
71 int stackPartialBox = 0;
72
73 // See if there's already an existing stack
74 Item* currentStackBag = nullptr;
75 Item* currentStackBox = nullptr;
76
77 // Basically look for first occurence in both the bag and box that have a
78 // stack of less than 99 (Indeed a true partial stack)
79 for(auto el : toBag->items) {
80 if(el->ind == data->getInd() && el->amount < 99) {
81 currentStackBag = el;
82 break;
83 }
84 }
85
86 for(auto el : toBox->items) {
87 if(el->ind == data->getInd() && el->amount < 99) {
88 currentStackBox = el;
89 break;
90 }
91 }
92
93 // Add what we can to the current stack if there is one
94 // Start with bag. This proceeds only if there is actually a partial stack
95 if(currentStackBag != nullptr) {
96 // We get the space leftover in the partial stack
97 int totalStackLeft = 99 - currentStackBag->amount;
98
99 // If the cart amount is bigger than the partial stack free space, just
100 // assign the rest of the free space.
101 // (A partial stack of 99 or a full partial stack)
102 if(_onCart > totalStackLeft) {
103 stackPartialBag = totalStackLeft;
104 _onCart -= totalStackLeft;
105 }
106
107 // If the entire cart can be placed onto the partial stack then things are
108 // simple, place the whole cart and empty the cart out.
109 else {
110 stackPartialBag = _onCart;
111 _onCart = 0;
112 }
113 }
114
115 // Partial stacks are always the highest priority and the bag comes first.
116 // Here, we do the same thing but for the box next, filling up the partial
117 // stack there, if any.
118 if(currentStackBox != nullptr && _onCart > 0) {
119 int totalStackLeft = 99 - currentStackBox->amount;
120 if(_onCart > totalStackLeft) {
121 stackPartialBox = totalStackLeft;
122 _onCart -= totalStackLeft;
123 }
124 else {
125 stackPartialBox = _onCart;
126 _onCart = 0;
127 }
128 }
129
130 // Finish the rest off in seperate stacks. We must now calculate how many
131 // more stacks we require. We do this only if there are items left in the
132 // cart.
133 while(_onCart > 0) {
134 // We immidiately increase the full stack count
135 stacks++;
136
137 // If there is more than 99 items on the cart still, we subtract 99 and
138 // continue on. Otherwise we count the cart as empty and in need of no more
139 // stacks.
140 if(_onCart > 99) {
141 _onCart -= 99;
142 }
143 else {
144 _onCart = 0;
145 }
146 }
147
148 // We return the results which is largely helpful to a number of methods
149 StackReturn stk;
150 stk.full = stacks;
151 stk.partialBag = stackPartialBag;
152 stk.partialElBag = currentStackBag;
153 stk.partialBox = stackPartialBox;
154 stk.partialElBox = currentStackBox;
155
156 return stk;
157}
158
160{
161 if(!requestFilter())
162 return "";
163
164 return data->getReadable();
165}
166
168{
169 // There's no merchant inventory limit
170 return 0;
171}
172
174{
175 // There's nothing a merchant can't sell
176 return true;
177}
178
180{
181 if(!requestFilter())
182 return 0;
183
184 // Buying is intrinsic to a store row now (no longer gated on the buy flag);
185 // the currency is the active venue.
186 if(*isMoneyCurrency)
187 return data->buyPriceMoney();
188
189 return data->buyPriceCoins();
190}
191
193{
194 return type;
195}
196
197// This is a bit tricky because we have to see how many the player can buy if
198// they already have the item and, regardless, how many stacks they can
199// accumulate
201{
202 if(!requestFilter())
203 return 0;
204
205 // Calculate stacks this item takes up
206 auto stk = calculateStacks();
207
208 // Final value to return, a representation of items left that can go onto the
209 // cart
210 int ret = 0;
211
212 // Calculate stacks others take up
213 int totalStackFromOthers = totalStackCount() - stk.full;
214
215 // Calculate inventory space used and free combined from both bag and box
216 int combinedBoxSpace = toBox->itemsMax() + toBag->itemsMax();
217 int combinedBoxUsed = toBox->itemsCount() + toBag->itemsCount();
218
219 // Stack space left before requested transaction
220 int stackSpaceBefore = combinedBoxSpace - combinedBoxUsed;
221
222 // Stack space after requested transactions
223 int stackSpaceLeftAfter = stackSpaceBefore - totalStackFromOthers - stk.full;
224
225 // Calculate whole stack items remaining. There are 99 items max per stack
226 // This is the whole new stacks converted to item count.
227 ret = stackSpaceLeftAfter * 99;
228
229 // Now figure out partial stacks which we calculate only if there is a partial
230 // stack. The stack represents number of additional used space. We determine
231 // the rest available.
232 // 99 (Max) - 20 (On Cart) - 50 (Already there) = 29 items left in partial
233 // or
234 // 99 (Max) - 5 (On Cart) - 94 (Already there) = 0 Items Left in partial
235 if(stk.partialElBag != nullptr) {
236 ret += 99 - stk.partialBag - stk.partialElBag->amount;
237
238 if((99 - stk.partialBag - stk.partialElBag->amount) < 0)
239 qDebug() << "Negative Amount" << (99 - stk.partialBag - stk.partialElBag->amount);
240 }
241
242 if(stk.partialElBox != nullptr) {
243 ret += 99 - stk.partialBox - stk.partialElBox->amount;
244
245 if((99 - stk.partialBox - stk.partialElBox->amount) < 0)
246 qDebug() << "Negative Amount" << (99 - stk.partialBox - stk.partialElBox->amount);
247 }
248
249 // Ret Now contains the maximum items possible left but it doesn't take
250 // into consideration how much money is left. We do a quick calculation for
251 // that
252 int maxAmountFromMoney = moneyLeftover() / itemWorth();
253
254 // Return the smallest of the calculations
255 return qMin(ret, maxAmountFromMoney);
256}
257
259{
260 if(!requestFilter())
261 return 0;
262
263 return calculateStacks().full;
264}
265
267{
268 if(!requestFilter() ||
269 !canCheckout())
270 return;
271
272 // Copy checkout money to take or give as we're going to be modifying onCart
273 int origCartWorth = cartWorth();
274
275 // Calculate stack information
276 auto stk = calculateStacks();
277
278 // Add what we can to the current stack if there is one
279 if(stk.partialElBag != nullptr) {
280 stk.partialElBag->amount += stk.partialBag;
281 stk.partialElBag->amountChanged();
282 }
283
284 if(stk.partialElBox != nullptr) {
285 stk.partialElBox->amount += stk.partialBox;
286 stk.partialElBox->amountChanged();
287 }
288
289 onCart -= stk.partialBag;
290 onCart -= stk.partialBox;
291
292 // Stack item's we've completed used as an offset for box if needed
293 int stkFullUsed = 0;
294
295 // Create stacks for the rest. Start with the bag
296 // Stop when we've processed all the stack items or when the cart is empty
297 // or when the bag fills up
298 for(int i = 0; i < stk.full && onCart > 0 && (toBag->itemsCount() < toBag->itemsMax()); i++) {
299 if(onCart > 99) {
300 toBag->items.append(new Item(data->getInd(), 99));
301 toBag->itemInsertChange();
302 toBag->itemsChanged();
303 onCart -= 99;
304 }
305 else {
306 toBag->items.append(new Item(data->getInd(), onCart));
307 toBag->itemInsertChange();
308 toBag->itemsChanged();
309 onCart = 0;
310 }
311
312 stkFullUsed++;
313 }
314
315 stk.full -= stkFullUsed;
316
317 // Create stacks for the rest. Continue with box
318 // Stop when we've processed all the stack items or when the cart is empty
319 // or when the box fills up
320 for(int i = 0; i < stk.full && onCart > 0 && (toBox->itemsCount() < toBox->itemsMax()); i++) {
321 if(onCart > 99) {
322 toBox->items.append(new Item(data->getInd(), 99));
323 toBox->itemInsertChange();
324 toBox->itemsChanged();
325 onCart -= 99;
326 }
327 else {
328 toBox->items.append(new Item(data->getInd(), onCart));
329 toBox->itemInsertChange();
330 toBox->itemsChanged();
331 onCart = 0;
332 }
333 }
334
335 // Remove players money
336 if(*isMoneyCurrency) {
337 player->money -= origCartWorth;
338 player->moneyChanged();
339 }
340
341 // Remove players coins
342 else {
343 player->coins -= origCartWorth;
344 player->coinsChanged();
345 }
346}
virtual void checkout() override
Buy the item (into bag/box).
virtual QString _whichType() override
Subtype: report the type label.
ItemStorageBox * toBox
Overflow PC item box.
static constexpr const char * type
This row's type key.
virtual bool _canSell() override
Subtype: compute sellability.
virtual int _itemWorth() override
Subtype: compute the unit value.
ItemMarketEntryStoreItem(ItemDBEntry *data, ItemStorageBox *toBag, ItemStorageBox *toBox)
StackReturn calculateStacks()
Work out the full/partial bag-and-box landing for the cart qty.
ItemDBEntry * data
The item being sold.
virtual int _inStockCount() override
Subtype: compute the owned/sellable count.
ItemStorageBox * toBag
Destination bag.
virtual int stackCount() override
Subtype: new stack slots needed (see note above).
virtual QString infoText() override
Detailed-tooltip body (default none).
virtual QString _name() override
Subtype: compute the display name.
virtual int onCartLeft() override
Subtype: how many more may be added.
ItemMarketEntry(int compatMoneyCurrency=CompatEither, int compatBuyMode=CompatEither)
int totalStackCount()
Stacks across all rows of this type.
int cartSignVal
Net contribution sign (-1 buy / +1 sell).
int moneyLeftover()
Money remaining if this checks out.
bool requestFilter()
Helper: does this row pass the current mode filter?
static bool * isMoneyCurrency
Shared: current currency mode.
int itemWorth()
Cached unit value.
static PlayerBasics * player
Shared: player money/coins.
void finishConstruction()
Finalise construction (register the instance).
int onCart
Backing cart quantity.
int cartWorth()
Value of the cart quantity.
virtual bool canCheckout()
Can this row alone check out?
A container of Items – either the trainer's bag or a PC item box.
One inventory slot: an item index and an amount, with live pricing.
Definition item.h:36
int amount
Item amount (max 99 in Gen 1; backs property).
Definition item.h:109
One item's static data: name/flags, pricing, and where it's used.
Definition itemdbentry.h:46
Result of working out where a bought stack lands (full stacks + partial in bag/box).
Item * partialElBox
The PC-box item a partial merges into.
int partialBox
Remainder added to an existing PC-box stack.
int partialBag
Remainder added to an existing bag stack.
int full
Number of full new stacks.
Item * partialElBag
The bag item a partial merges into.