47const QSet<QString>& healingNames()
49 static const QSet<QString> s = {
50 "POTION",
"SUPER POTION",
"HYPER POTION",
"MAX POTION",
"FULL RESTORE",
51 "FULL HEAL",
"REVIVE",
"MAX REVIVE",
"ANTIDOTE",
"BURN HEAL",
"ICE HEAL",
52 "AWAKENING",
"PARLYZ HEAL",
"ETHER",
"MAX ETHER",
"ELIXER",
"MAX ELIXER",
53 "FRESH WATER",
"SODA POP",
"LEMONADE",
60const QStringList& healingSourcePref()
62 static const QStringList s = {
63 "POTION",
"SUPER POTION",
"HYPER POTION",
"MAX POTION",
"FULL RESTORE",
64 "FULL HEAL",
"REVIVE",
"MAX REVIVE",
65 "ELIXER",
"MAX ELIXER",
"ETHER",
"MAX ETHER",
71const QStringList& healingTargetPref()
73 static const QStringList s = {
"FRESH WATER",
"SODA POP",
"LEMONADE" };
77int ceilDiv(
int a,
int b) {
return (b <= 0) ? 0 : ((a + b - 1) / b); }
83 : bag(bag), storage(storage), basics(basics)
87 const int ind = entry->getInd();
91 in.name = entry->getName();
92 in.readable = entry->getReadable();
93 in.buy = entry->buyPriceMoney();
94 in.healing = healingNames().contains(in.name);
95 m_info.insert(ind, in);
109int ItemExchangeModel::buyOf(
int ind)
const
111 auto it = m_info.constFind(ind);
112 return (it == m_info.constEnd()) ? 0 : it->buy;
115QString ItemExchangeModel::readableOf(
int ind)
const
117 auto it = m_info.constFind(ind);
118 return (it == m_info.constEnd()) ? QString() : it->readable;
121bool ItemExchangeModel::isHealing(
int ind)
const
123 auto it = m_info.constFind(ind);
124 return (it != m_info.constEnd()) && it->healing;
127int ItemExchangeModel::indOfName(
const QString& name)
const
129 for(
auto it = m_info.constBegin(); it != m_info.constEnd(); ++it) {
136void ItemExchangeModel::sortByName(QVariantList& list)
139 col.setNumericMode(
true);
140 col.setCaseSensitivity(Qt::CaseInsensitive);
141 std::sort(list.begin(), list.end(), [&col](
const QVariant& a,
const QVariant& b) {
142 return col.compare(a.toMap().value(
"name").toString(),
143 b.toMap().value(
"name").toString()) < 0;
149int ItemExchangeModel::combinedAmount(
int ind)
const
154 if(bag) total += bag->amountOfInd(ind);
155 if(storage) total += storage->amountOfInd(ind);
159int ItemExchangeModel::combinedCapacity(
int ind)
const
164 if(bag) room += bag->capacityForInd(ind);
165 if(storage) room += storage->capacityForInd(ind);
171 return basics ?
static_cast<int>(basics->money) : 0;
178 return m_itemAInd >= 0 && m_itemBInd >= 0
179 && m_itemAInd != m_itemBInd
188 if(!
valid() || steps <= 0 || dir == 0)
190 return (dir > 0) ? ceilDiv(steps *
aBuy(),
bBuy())
196 if(!
valid() || steps <= 0 || dir == 0)
202int ItemExchangeModel::aAfterFor(
int m)
const
207int ItemExchangeModel::bAfterFor(
int m)
const
212int ItemExchangeModel::moneyAfterFor(
int m)
const
219bool ItemExchangeModel::stateValid(
int m)
const
224 const int aA = aAfterFor(m);
225 const int bA = bAfterFor(m);
226 const int moneyA = moneyAfterFor(m);
230 if(aA >
aStart() + combinedCapacity(m_itemAInd))
232 if(bA >
bStart() + combinedCapacity(m_itemBInd))
240void ItemExchangeModel::clampNet()
242 while(m_net > 0 && !stateValid(m_net)) --m_net;
243 while(m_net < 0 && !stateValid(m_net)) ++m_net;
250void ItemExchangeModel::emitChanged()
309 for(
int pass = 0; pass < 2 && out.isEmpty(); ++pass) {
310 const bool ownedOnly = (pass == 0);
311 for(
auto it = m_info.constBegin(); it != m_info.constEnd(); ++it) {
312 const int ind = it.key();
313 if(ind == excludeInd)
317 if(healingOnly && !it->healing)
319 if(ownedOnly && combinedAmount(ind) <= 0)
322 m.insert(
"name", it->readable);
323 m.insert(
"ind", ind);
337 for(
auto it = m_info.constBegin(); it != m_info.constEnd(); ++it) {
338 const int ind = it.key();
339 if(ind == excludeInd)
343 if(healingOnly && !it->healing)
346 m.insert(
"name", it->readable);
347 m.insert(
"ind", ind);
360 if(m_itemAInd < 0 || bInd < 0 || bInd == m_itemAInd)
363 const int aB = buyOf(m_itemAInd);
364 const int bB = buyOf(bInd);
365 if(aB <= 0 || bB <= 0)
368 const int give = ceilDiv(bB, aB);
369 const int refund = give * aB - bB;
371 if(combinedAmount(m_itemAInd) < give)
return false;
372 if(combinedCapacity(bInd) < 1)
return false;
387 for(
const QString& n : healingSourcePref()) {
388 const int ind = indOfName(n);
389 if(ind >= 0 && buyOf(ind) > 0 && combinedAmount(ind) > 0) {
396 const QVariantList src =
sourceItems(healingOnly, -1);
398 a = src.first().toMap().value(
"ind").toInt();
406 for(
const QString& n : healingTargetPref()) {
407 const int ind = indOfName(n);
415 const QVariantList tgt =
targetItems(healingOnly, a);
416 for(
const QVariant& v : tgt) {
417 const QVariantMap m = v.toMap();
418 if(m.value(
"affordable").toBool()) {
419 b = m.value(
"ind").toInt();
424 if(b < 0 && !tgt.isEmpty())
425 b = tgt.first().toMap().value(
"ind").toInt();
435 if(!
valid() || m_net == 0)
438 const int steps = (m_net > 0) ? m_net : -m_net;
439 const int dir = (m_net > 0) ? 1 : -1;
442 const int give =
giveFor(dir, steps);
443 const int refund =
refundFor(dir, steps);
445 const int gainInd = (dir > 0) ? m_itemAInd : m_itemBInd;
446 const int giveInd = (dir > 0) ? m_itemBInd : m_itemAInd;
450 int rem = bag ? bag->removeAmount(giveInd, give) : 0;
451 if(rem < give && storage)
452 storage->removeAmount(giveInd, give - rem);
454 int added = bag ? bag->addAmount(gainInd, steps) : 0;
455 if(added < steps && storage)
456 storage->addAmount(gainInd, steps - added);
459 const int m =
static_cast<int>(basics->money) + refund;
464 basics->moneyChanged();
QVariantList targetItems(bool healingOnly, int excludeInd) const
RIGHT list – what you can GET: EVERY exchangeable item (owned or not), optionally healing-only,...
bool canGainTarget(int bInd) const
Can we gain at least one of item bInd right now, paying with the selected source?
void changed()
Any derived value changed.
ItemExchangeModel(ItemStorageBox *bag, ItemStorageBox *storage, PlayerBasics *basics)
int giveFor(int dir, int steps) const
How many of the OTHER item steps of this direction consume, priced as ONE whole trade rather than ste...
void refresh()
Re-read counts/money + re-emit (tab open / external edit).
void pickDefaults(bool healingOnly)
Choose a sensible starting pair.
void adjust(int dir)
+1 = one gained-A step, -1 = one gained-B step (gated).
QVariantList sourceItems(bool healingOnly, int excludeInd) const
LEFT list – what you can GIVE: items you actually own (amount > 0) and that are exchangeable (buy pri...
static constexpr int MoneyCap
< Both picked, distinct, both have a buy price.
void reset()
Clear the net axis.
protected::void selectionChanged()
A or B selection changed.
void checkout()
Apply the previewed trade to the save.
int refundFor(int dir, int steps) const
The leftover value of steps in direction dir, refunded as money – i.e.
A container of Items – either the trainer's bag or a PC item box.
void itemsChanged()
Box contents changed.
static ItemsDB * inst()
< Number of items.
The trainer's headline values: name, ID, money, coins, badges, starter.