50 QQmlEngine::setObjectOwnership(
this, QQmlEngine::CppOwnership);
86 for(
var8 i = 0; i < 4; i++) {
91 QString::number(
Random::inst()->rangeExclusive(0, moveListSize))));
92 while(moveData ==
nullptr || moveData->
glitch ==
true);
143 if(moveData ==
nullptr || !moveData->pp)
146 var8 basePP = *moveData->pp;
148 var8 ppUpSteps = basePP / 5;
150 return basePP + (ppUpSteps * ppUps);
190 for(
auto el : monData->toInitial) {
191 if(!ret.contains(el->ind))
195 for(
auto el : monData->moves) {
196 if(el->toMove !=
nullptr && !ret.contains(el->toMove->ind))
197 ret.append(el->toMove->ind);
200 for(
auto el : monData->toTmHmMove) {
201 if(!ret.contains(el->ind))
215 for(
int i = 0 ; i < 4; i++) {
217 ret.removeAll(
parentMon->moves[i]->moveID);
227 for(
int i = 0 ; i < 4; i++) {
228 if(
parentMon->moves[i]->moveID == this->moveID)
266 for(
int i = 0; i < 4; i++) {
272 if(rowCount >= 1 &&
moveID <= 0)
280 moveID = validMovesLeftList.at(0);
292 var16 nicknameStartOffset,
293 var16 otNameStartOffset,
309 QQmlEngine::setObjectOwnership(
this, QQmlEngine::CppOwnership);
311 for(
int i = 0; i < 4; i++) {
354 for(
int i = 0; i < 4; i++) {
355 moves[i]->deleteLater();
387 pkmn->species = pkmnData->
ind;
393 pkmn->changeName(noNick);
398 if(basics !=
nullptr && !isTrade)
399 pkmn->changeTrade(
true, basics);
403 pkmn->resetPokemon();
404 pkmn->update(
true,
true,
true,
true);
411 var16 nicknameStartOffset,
412 var16 otNameStartOffset,
418 if(saveFile ==
nullptr) {
423 var16 offset = (recordSize * index) + startOffset;
425 auto toolset = saveFile->
toolset;
434 level = it->getByte();
440 type1 = it->getByte();
443 type2 = it->getByte();
469 QVector<var8> moveIDList;
470 for (
var8 i = 0; i < 4; i++) {
471 var8 moveID = it->getByte();
475 moveIDList.append(moveID);
479 it->pop()->offsetBy(0x4);
481 otID = it->getWord();
485 auto expRaw = it->getRange(3);
493 hpExp = it->getWord();
505 spExp = it->getWord();
508 var16 dvTotal = it->getWord();
518 QVector<var8> ppList;
519 for (
var8 i = 0; i < moveIDList.size(); i++) {
520 var8 ppListEntry = it->getByte();
521 ppList.append(ppListEntry);
525 for (
var8 i = 0; i < moveIDList.size(); i++) {
526 var8 moveID = moveIDList.at(i);
528 moves[i]->moveID = moveID;
529 moves[i]->moveIDChanged();
531 moves[i]->pp = pp & 0b00111111;
532 moves[i]->ppChanged();
534 moves[i]->ppUp = (pp & 0b11000000) >> 6;
535 moves[i]->ppUpChanged();
540 it->pop()->offsetBy(0x4);
544 var16 otNameOffset = (index * 0xB) + otNameStartOffset;
545 otName = toolset->getStr(otNameOffset, 0xB, 7+1);
548 var16 nicknameOffset = (index * 0xB) + nicknameStartOffset;
549 nickname = toolset->getStr(nicknameOffset, 0xB, 10);
558 svar32 speciesStartOffset,
559 var16 nicknameStartOffset,
560 var16 otNameStartOffset,
564 auto toolset = saveFile->
toolset;
567 var16 offset = (recordSize * index) + startOffset;
569 var16 otNameOffset = (index * 0xB) + otNameStartOffset;
570 var16 nicknameOffset = (index * 0xB) + nicknameStartOffset;
573 if(speciesStartOffset > 0) {
574 var16 speciesOffset = index + speciesStartOffset;
575 toolset->setByte(speciesOffset,
species);
585 if (recordSize == 0x21) {
610 }
else if (
type2 == 0xFF) {
619 for(
var8 i = 0; i < 4; i++) {
620 it->setByte(
moves[i]->moveID);
622 it->pop()->offsetBy(4);
626 it->setByte((
exp & 0xFF0000) >> 16);
627 it->setByte((
exp & 0x00FF00) >> 8);
628 it->setByte(
exp & 0x0000FF);
644 for (
var8 i = 0; i < 4; i++) {
646 it->setByte(ppCombined);
648 it->pop()->offsetBy(4);
650 toolset->setStr(otNameOffset, 0xB, 10+1,
otName);
651 toolset->setStr(nicknameOffset, 0xB, 10+1,
nickname);
761 update(
true,
true,
true,
true);
785 this->type2 =
type2->ind;
801 for(
int i = 0; i < 4; i++) {
802 moves[i]->moveID = 0;
803 moves[i]->moveIDChanged();
806 moves[i]->ppChanged();
809 moves[i]->ppUpChanged();
825 if(record ==
nullptr || record->glitch || !(record->pokedex))
845 if(record ==
nullptr)
849 var8 gr = *record->growthRate;
906 return static_cast<float>(curExp) /
static_cast<float>(expEnd);
942 if(record ==
nullptr || !(record->baseHp))
945 return qFloor((((*record->baseHp +
hpDV())*2+qFloor(qFloor(qSqrt(
hpExp))/4))*
level)/100) +
level + 10;
953 if(record ==
nullptr)
961 baseStat = *record->baseAttack;
966 baseStat = *record->baseDefense;
971 baseStat = *record->baseSpeed;
976 baseStat = *record->baseSpecial;
981 return qFloor((((baseStat+dvLocal)*2+qFloor(qFloor(qSqrt(evLocal))/4))*
level)/100) + 5;
991 if(record ==
nullptr)
999 if(resetType && record->toType1) {
1000 type1 = (*record).toType1->ind;
1011 type2 = (*record).toType2->ind;
1012 else if(record->toType1)
1013 type2 = (*record).toType1->ind;
1031 if(resetCatchRate && record->catchRate) {
1053 if(record ==
nullptr || !record->toType1)
1056 type1 = record->toType1->ind;
1060 type2 = record->toType2->ind;
1062 type2 = record->toType1->ind;
1104 for(
int i = 0; i < 4; i++)
1105 moves[i]->restorePP();
1112 if(record ==
nullptr)
1127 else if(removeNickname)
1145 if(basics ==
nullptr)
1172 if(record ==
nullptr)
1175 if(record->evolution.size() == 0)
1185 if(record ==
nullptr)
1188 if(record->toDeEvolution ==
nullptr)
1205 if(record->evolution.size() > 1) {
1207 species = record->evolution.at(ind)->toEvolution->ind;
1210 species = record->evolution.at(0)->toEvolution->ind;
1219 update(
true,
true,
true,
true);
1232 species = record->toDeEvolution->ind;
1240 update(
true,
true,
true,
true);
1249 return level >= 100;
1260 for(
int i = 0; i < 4; i++)
1272 for(
int i = 0; i < 4; i++)
1281 return atkExp == 0xFFFF &&
1305 for(
var8 i = 0; i < 4; i++)
1306 if(
dv[i] < 15) ret =
false;
1315 for(
var8 i = 0; i < 4; i++)
1316 if(
dv[i] > 0) ret =
false;
1331 for(
int i = 0; i < 4; i++)
1332 moves[i]->maxPpUp();
1337 for(
var8 i = 0; i < 4; i++)
1345 for(
var8 i = 0; i < 4; i++)
1353 for(
var8 i = 0; i < 4; i++)
1434 for(
var8 i = 0; i < 4; i++) {
1435 moves[i]->randomize();
1445 if(record ==
nullptr)
1448 bool movesReset =
true;
1456 int initialCount = record->toInitial.size();
1457 if(initialCount > 4)
1460 for(
int i = 0; i < 4; i++) {
1461 auto move =
moves[i];
1464 if(i >= initialCount) {
1465 if(move->moveID != 0)
1472 if(move->toMove() ==
nullptr)
1477 if(move->moveID != record->toInitial.at(i)->ind)
1497 for(
int i = 0; i < 4; i++) {
1505 for(
int i = 0; i < 4; i++) {
1526 if(record ==
nullptr)
1532 if(record->toType1 !=
nullptr) {
1533 if(record->toType1->ind !=
type1)
1550 bool dualType = record->toType2 !=
nullptr &&
1551 record->toType1 !=
nullptr &&
1552 record->toType2->ind != record->toType1->ind;
1555 if(record->toType2->ind !=
type2)
1561 if(record->catchRate) {
1575 if(record ==
nullptr)
1578 return *record->pokedex;
1584 if(record ==
nullptr)
1587 if(record->readable ==
"")
1588 return record->name;
1590 return record->readable;
1600 return atkChk && defChk && spdChk && spChk;
1623 var8 offset = qAbs(nature - cur);
1645 else if(
exp >= max) {
1653 QVector<PokemonMove*> movesNew;
1656 for(
int i = 0; i < 4; i++) {
1657 if(
moves[i]->moveID <= 0)
1667 movesNew.append(newMoveEl);
1671 for(
int i = 0; i < 4; i++) {
1672 moves[i]->moveID = 0;
1678 for(
int i = 0; i < movesNew.size(); i++) {
1679 moves[i]->moveID = movesNew.at(i)->moveID;
1680 moves[i]->pp = movesNew.at(i)->pp;
1681 moves[i]->ppUp = movesNew.at(i)->ppUp;
1685 for(
int i = 0; i < 4; i++) {
1686 moves[i]->moveIDChanged();
1687 moves[i]->ppChanged();
1688 moves[i]->ppUpChanged();
1694 for(
int i = 0; i < 4; i++)
1695 moves[i]->correctMove();
1747 moves[ind]->changeMove(moveID, pp, ppUp);
1757 moves[ind]->moveID = 0;
1759 moves[ind]->ppUp = 0;
1771 for(
int i = 1; i <
maxMoves; i++) {
1772 moves[i]->moveID = 0;
1773 moves[i]->moveIDChanged();
1776 moves[i]->ppChanged();
1779 moves[i]->ppUpChanged();
1792 moves[ind]->correctMove();
1802 struct MoveVals {
int id;
int pp;
int ppUp; };
1807 QVector<MoveVals> vec;
1808 for(
int i = 0; i <
maxMoves; i++) {
1809 if(
moves[i]->moveID <= 0)
1814 if(from < 0 || from >= vec.size())
1817 MoveVals moved = vec.at(from);
1823 for(
int i = qBound(0, to, vec.size()); i < vec.size(); i++) {
1829 int anchorShift = (anchorIdx > from) ? 1 : 0;
1835 vec.insert(anchorIdx - anchorShift, moved);
1840 for(
int i = 0; i <
maxMoves; i++) {
1842 moves[i]->changeMove(vec.at(i).id, vec.at(i).pp, vec.at(i).ppUp);
1844 moves[i]->changeMove(0, 0, 0);
1856 if(record ==
nullptr)
1861 for(
int i = 0; i < 4 && i < record->toInitial.size(); i++) {
1862 auto moveData = record->toInitial.at(i);
1863 moves[i]->moveID = moveData->ind;
1864 moves[i]->moveIDChanged();
1866 moves[i]->pp = *moveData->pp;
1867 moves[i]->ppChanged();
1870 moves[i]->ppUpChanged();
1877 update(
true,
true,
true,
true);
1930 dv[0] = pkmn->
dv[0];
1931 dv[1] = pkmn->
dv[1];
1932 dv[2] = pkmn->
dv[2];
1933 dv[3] = pkmn->
dv[3];
1938 for(
int i = 0; i < 4; i++) {
1940 moves[i]->moveIDChanged();
1943 moves[i]->ppChanged();
1946 moves[i]->ppUpChanged();
1966 for(
int i = 0; i < 4; i++) {
1967 if(
moves[i]->moveID <= 0)
2004 update(
true,
true,
true,
true);
QString randomExample()
A random string from the list.
int getStoreSize() const
Move count.
MoveDBEntry * getIndAt(const QString &key) const
Move by name key (for QML).
static MovesDB * inst()
< Number of moves.
NamesPlayer * player() const
The player-name source (backs player).
NamesPokemon * pokemon() const
The Pokemon-name source (backs pokemon).
static Names * inst()
< Random player-name source.
The trainer's headline values: name, ID, money, coins, badges, starter.
int playerID
Trainer ID (backs the property).
QString playerName
Trainer name (backs the property).
A single Pokemon record – the most property-rich object in the tree.
PokemonMove * movesAt(int ind)
Move slot ind (GC-protected return).
bool isMaxPpUps()
All moves at max PP-Ups.
PokemonMove * moves[4]
The four move slots.
void rollShiny()
Randomize DVs until shiny.
void rollNonShiny()
Randomize DVs until not shiny.
void resetDVs()
Zero all DVs.
void type2ExplicitChanged()
void heal()
Pokecenter heal: full HP, clear status.
bool isValidBool()
Convenience bool form of isValid().
int dvAt(int ind)
DV value at ind.
void reRollDVs()
Randomize DVs.
void manualLevelChanged()
UI hook: level edited directly.
virtual void randomize(PlayerBasics *basics=nullptr)
Randomize this Pokemon (constrained).
void dvSet(int ind, int val)
Set DV ind.
void makeShiny()
Force DVs to a shiny combination.
bool isHealed()
Fully healed (HP + status). (heal() performs a Pokecenter heal.).
bool isMinEvs()
All stat-exp zero.
bool hasEvolution()
Species can evolve.
void reorderMove(int from, int to)
Reorder the filled move slots: take the move at from and re-insert it before slot to (drop-slot conve...
void resetEVs()
Zero all stat-exp.
int dvCount()
Number of stored DVs (maxDV).
bool hasDeEvolution()
Species has a pre-evolution.
int spdStat()
Computed Speed stat.
unsigned int expLevelRangeStart()
EXP at the start of the current level.
void maxLevel()
Set to level 100.
void evolve()
Evolve to the next species.
void cleanupMoves()
Remove invalid/duplicate moves.
bool hasTradeStatus(PlayerBasics *basics=nullptr)
Counts as traded relative to basics.
bool isMaxHp()
HP equals computed max.
bool isMaxedOut()
Level/EV/DV/PP all maxed.
protected::void speciesChanged()
int spStat()
Computed Special stat.
virtual void update(bool resetHp=false, bool resetExp=false, bool resetType=false, bool resetCatchRate=false, bool correctMoves=false)
Recompute derived stats.
void changeMove(int ind, int moveID=0, int pp=0, int ppUp=0)
Set move slot ind.
void pokemonResetChanged()
virtual SaveFileIterator * save(SaveFile *saveFile=nullptr, var16 startOffset=0, svar32 speciesStartOffset=0, var16 nicknameStartOffset=0, var16 otNameStartOffset=0, var8 index=0, var8 recordSize=0x21)
Flatten one Pokemon back to the save.
unsigned int levelToExp(int level=-1)
EXP needed for level (current level if -1).
void resetExp()
Reset EXP to the current level's baseline.
void randomizeMoves()
Randomize the move set.
int dexNum()
Pokedex number.
void correctTypes()
Reset type1/type2 to this species' DB-default type(s) (e.g.
void maxOut()
Max level/EV/DV/PP at once.
void manualSpeciesChanged()
UI hook: species edited directly.
void changeName(bool removeNickname=false)
Randomize or (if true) remove the nickname.
void correctMoves()
Repair move/PP inconsistencies.
void clearMoves()
Empty all move slots.
void changeTrade(bool removeTradeStatus=false, PlayerBasics *basics=nullptr)
Toggle traded status.
void unmakeShiny()
Force DVs to a non-shiny combination.
int movesCount()
Number of non-empty move slots.
void hasNicknameChanged()
void reRollEVs()
Randomize stat-exp.
void clearMovesButFirst()
Remove every move except the first one (slots 1..3 cleared).
bool isPokemonReset()
Matches the reset baseline.
virtual SaveFileIterator * load(SaveFile *saveFile=nullptr, var16 startOffset=0, var16 nicknameStartOffset=0, var16 otNameStartOffset=0, var8 index=0, var8 recordSize=0x21)
Expand one Pokemon from the save.
PokemonDBEntry * toData()
The species' DB entry for this mon.
PokemonDBEntry * isValid()
The species' DB entry, or null if not a real Pokedex species.
unsigned int expLevelRangeEnd()
EXP at the next level.
virtual void copyFrom(PokemonBox *pkmn)
Deep-copy another mon's values into this one.
void correctMoveAt(int ind)
Make the move in slot ind valid (PokemonMove::correctMove) THEN compact: correctMove can clear an inv...
static PokemonBox * newPokemon(PokemonRandom::PokemonRandom_ list=PokemonRandom::Random_Starters, PlayerBasics *basics=nullptr)
void maxEVs()
Max all stat-exp.
bool isMaxLevel()
Level 100.
bool hasNickname()
Carries a real nickname.
void resetPokemon()
Reset to the baseline state.
bool isShiny()
Shiny per the VC-era DV formula (see disclaimer above).
void changeOtData(bool removeOtData=false, PlayerBasics *basics=nullptr)
Randomize or remove OT data.
void setNature(int nature)
QString speciesName()
Species display name.
int atkStat()
Computed Attack stat.
void deleteMoveAt(int ind)
Delete the move in slot ind, then compact so there is no gap in the move list (the slots after it sli...
void deEvolve()
Revert to the prior species.
float expLevelRangePercent()
Fractional progress through the level.
var8 dv[maxDV]
Stored DVs (Atk/Def/Spd/Spc); HP DV is derived.
void maxDVs()
Max all DVs.
virtual bool isBoxMon()
True for a pure box mon; PokemonParty overrides to false.
void maxPpUps()
Max every move's PP-Ups.
int defStat()
Computed Defense stat.
bool isMaxDVs()
All DVs maxed.
int nonHpStat(PokemonStats::PokemonStats_ stat)
PokemonBox(SaveFile *saveFile=nullptr, var16 startOffset=0, var16 nicknameStartOffset=0, var16 otNameStartOffset=0, var8 index=0, var8 recordSize=0x21)
< Species id (raw save value).
bool isCorrected()
Values internally consistent (see correct* slots).
bool isMaxEVs()
All stat-exp maxed.
virtual void reset()
Blank this Pokemon.
int movesMax()
Move-slot capacity (maxMoves).
bool isAfflicted()
Has any status condition.
bool isMinDVs()
All DVs zero.
bool isMaxPP()
All moves at max PP.
static PokemonDB * inst()
< Number of species.
PokemonDBEntry * getStoreAt(int idx) const
Species by store index (for QML).
int getStoreSize() const
Species count.
PokemonDBEntry * getIndAt(const QString &key) const
Species by name key (for QML).
One of a Pokemon's four move slots: move id, PP, and PP-Ups.
int pp
Current PP (backs property).
protected::void moveIDChanged()
void raisePpUp()
+1 PP-Up.
PokemonBox * parentMon
Owning Pokemon (for cross-slot validation).
PokemonMove(PokemonBox *parentMon, var8 move=0, var8 pp=0, var8 ppUp=0)
< Move id (indexes the moves DB).
MoveDBEntry * toMove()
Resolve moveID to its DB entry.
bool isMaxPpUps()
Are PP-Ups at max?
void lowerPpUp()
-1 PP-Up.
QString moveType()
The move's elemental type name.
int moveID
Move id (backs property).
QVector< int > validMovesLeft()
Legal moves not already used by the mon.
int getMaxPP()
PP cap for this move given PP-Ups.
void resetPpUp()
PP-Ups to 0.
bool isInvalid()
Is the move id out of range / not a real move?
void randomize()
Pick a random valid move.
void maxPpUp()
Set PP-Ups to max.
bool isDuplicateMove()
Is this move a duplicate within the mon's set?
void onMoveIdChanged()
Recompute derived state after the move id changes.
int ppUp
PP-Ups (backs property).
QVector< int > allValidMoves()
Every legal move id for this slot.
void restorePP()
Refill PP to the cap.
bool isMaxPP()
Is current PP at the cap?
void correctMove()
Clamp/repair inconsistent values.
void changeMove(int move=0, int pp=0, int ppUp=0)
Replace this slot's values.
bool chanceSuccess(const int percent) const
Did a percent chance succeed?
bool flipCoin() const
50/50 coin flip via the integer path (chanceSuccess(50)).
int rangeInclusive(const int start, const int end) const
Random integer in the closed interval [start, end].
static Random * inst()
< Convenience 50% coin flip (integer path), readable from QML.
int rangeExclusive(const int start, const int end) const
Random integer in the half-open interval [start, end).
A moving cursor over a SaveFile, layering auto-advancing reads/writes on top of SaveFileToolset.
SaveFileIterator * offsetTo(var16 val)
Move the cursor to an absolute offset. Returns this for chaining.
One loaded save: the raw 32 KB bytes, their expanded object tree, and the tools that move between the...
SaveFileToolset * toolset
Tools to operate directly on the raw sav file data.
SaveFileIterator * iterator()
Returns a unique iterator that's setup to iterate over the raw sav file data.
PokemonDBEntry * random3Starter() const
A random one of the 3 canonical starters.
static StarterPokemonDB * inst()
< Number of starter choices.
PokemonDBEntry * randomAnyStarter() const
A random "startery" species.
static TypesDB * inst()
< Number of types.
TypeDBEntry * getStoreAt(int idx) const
Type by store index (for QML).
svar32e svar32
Signed, exactly 32-bit (shorthand for svar32e).
var8e var8
Everyday 8-bit alias. Exact (not "fastest") to dodge the pointer-width bug noted above.
var16e var16
Everyday 16-bit alias. Exact width to avoid the "fastest" widening bug.
var32e var32
Everyday 32-bit alias. Exact width to avoid the "fastest" widening bug.
constexpr var8 pokemonDexCount
Number of species.
constexpr var8 pokemonLevelMax
Maximum level.
constexpr var8 maxMoves
Move slots per Pokemon.
constexpr var8 maxDV
DV entries stored (Atk/Def/Spd/Spc; HP DV is derived).
qmlCppOwned() – protect Q_INVOKABLE QObject returns from QML's GC.
static T * qmlCppOwned(T *obj)
Hand QML CppOwnership of a C++-owned QObject returned from a Q_INVOKABLE.
One move's static data (type, power, accuracy, PP, TM/HM), with links.
TypeDBEntry * toType
Resolved type entry (deepLink).
bool glitch
Whether this is a glitch move.
One species' complete static data – the richest entry in the db layer.
QString name
Internal species name (key).
var8 ind
Internal species index.
@ Random_Starters
A "startery"-feeling Pokemon (non-legendary base evo).
@ Random_All
Any species at all, including MissingNo / glitch mons.
@ Random_Pokedex
Any Pokedex species.
@ Special
Special (single stat in Gen 1).
@ Defense
Physical defense.
One elemental type: its name plus the moves and Pokemon of that type.
QString readable
Human-readable type name.