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();
464 QVector<var8> moveIDList;
465 for (
var8 i = 0; i < 4; i++) {
466 var8 moveID = it->getByte();
470 moveIDList.append(moveID);
474 it->pop()->offsetBy(0x4);
476 otID = it->getWord();
480 auto expRaw = it->getRange(3);
488 hpExp = it->getWord();
500 spExp = it->getWord();
503 var16 dvTotal = it->getWord();
513 QVector<var8> ppList;
514 for (
var8 i = 0; i < moveIDList.size(); i++) {
515 var8 ppListEntry = it->getByte();
516 ppList.append(ppListEntry);
520 for (
var8 i = 0; i < moveIDList.size(); i++) {
521 var8 moveID = moveIDList.at(i);
523 moves[i]->moveID = moveID;
524 moves[i]->moveIDChanged();
526 moves[i]->pp = pp & 0b00111111;
527 moves[i]->ppChanged();
529 moves[i]->ppUp = (pp & 0b11000000) >> 6;
530 moves[i]->ppUpChanged();
535 it->pop()->offsetBy(0x4);
539 var16 otNameOffset = (index * 0xB) + otNameStartOffset;
540 otName = toolset->getStr(otNameOffset, 0xB, 7+1);
543 var16 nicknameOffset = (index * 0xB) + nicknameStartOffset;
544 nickname = toolset->getStr(nicknameOffset, 0xB, 10);
553 svar32 speciesStartOffset,
554 var16 nicknameStartOffset,
555 var16 otNameStartOffset,
559 auto toolset = saveFile->
toolset;
562 var16 offset = (recordSize * index) + startOffset;
564 var16 otNameOffset = (index * 0xB) + otNameStartOffset;
565 var16 nicknameOffset = (index * 0xB) + nicknameStartOffset;
568 if(speciesStartOffset > 0) {
569 var16 speciesOffset = index + speciesStartOffset;
570 toolset->setByte(speciesOffset,
species);
580 if (recordSize == 0x21) {
595 }
else if (
type2 == 0xFF) {
606 for(
var8 i = 0; i < 4; i++) {
607 it->setByte(
moves[i]->moveID);
609 it->pop()->offsetBy(4);
613 it->setByte((
exp & 0xFF0000) >> 16);
614 it->setByte((
exp & 0x00FF00) >> 8);
615 it->setByte(
exp & 0x0000FF);
631 for (
var8 i = 0; i < 4; i++) {
633 it->setByte(ppCombined);
635 it->pop()->offsetBy(4);
637 toolset->setStr(otNameOffset, 0xB, 10+1,
otName);
638 toolset->setStr(nicknameOffset, 0xB, 10+1,
nickname);
748 update(
true,
true,
true,
true);
772 this->type2 =
type2->ind;
780 for(
int i = 0; i < 4; i++) {
781 moves[i]->moveID = 0;
782 moves[i]->moveIDChanged();
785 moves[i]->ppChanged();
788 moves[i]->ppUpChanged();
804 if(record ==
nullptr || record->glitch || !(record->pokedex))
824 if(record ==
nullptr)
828 var8 gr = *record->growthRate;
885 return static_cast<float>(curExp) /
static_cast<float>(expEnd);
921 if(record ==
nullptr || !(record->baseHp))
924 return qFloor((((*record->baseHp +
hpDV())*2+qFloor(qFloor(qSqrt(
hpExp))/4))*
level)/100) +
level + 10;
932 if(record ==
nullptr)
940 baseStat = *record->baseAttack;
945 baseStat = *record->baseDefense;
950 baseStat = *record->baseSpeed;
955 baseStat = *record->baseSpecial;
960 return qFloor((((baseStat+dvLocal)*2+qFloor(qFloor(qSqrt(evLocal))/4))*
level)/100) + 5;
970 if(record ==
nullptr)
978 if(resetType && record->toType1) {
979 type1 = (*record).toType1->ind;
990 type2 = (*record).toType2->ind;
991 else if(record->toType1)
992 type2 = (*record).toType1->ind;
1003 if(resetCatchRate && record->catchRate) {
1025 if(record ==
nullptr || !record->toType1)
1028 type1 = record->toType1->ind;
1032 type2 = record->toType2->ind;
1034 type2 = record->toType1->ind;
1069 for(
int i = 0; i < 4; i++)
1070 moves[i]->restorePP();
1077 if(record ==
nullptr)
1092 else if(removeNickname)
1110 if(basics ==
nullptr)
1137 if(record ==
nullptr)
1140 if(record->evolution.size() == 0)
1150 if(record ==
nullptr)
1153 if(record->toDeEvolution ==
nullptr)
1170 if(record->evolution.size() > 1) {
1172 species = record->evolution.at(ind)->toEvolution->ind;
1175 species = record->evolution.at(0)->toEvolution->ind;
1184 update(
true,
true,
true,
true);
1197 species = record->toDeEvolution->ind;
1205 update(
true,
true,
true,
true);
1214 return level >= 100;
1225 for(
int i = 0; i < 4; i++)
1237 for(
int i = 0; i < 4; i++)
1246 return atkExp == 0xFFFF &&
1270 for(
var8 i = 0; i < 4; i++)
1271 if(
dv[i] < 15) ret =
false;
1280 for(
var8 i = 0; i < 4; i++)
1281 if(
dv[i] > 0) ret =
false;
1296 for(
int i = 0; i < 4; i++)
1297 moves[i]->maxPpUp();
1302 for(
var8 i = 0; i < 4; i++)
1310 for(
var8 i = 0; i < 4; i++)
1318 for(
var8 i = 0; i < 4; i++)
1399 for(
var8 i = 0; i < 4; i++) {
1400 moves[i]->randomize();
1410 if(record ==
nullptr)
1413 bool movesReset =
true;
1421 int initialCount = record->toInitial.size();
1422 if(initialCount > 4)
1425 for(
int i = 0; i < 4; i++) {
1426 auto move =
moves[i];
1429 if(i >= initialCount) {
1430 if(move->moveID != 0)
1437 if(move->toMove() ==
nullptr)
1442 if(move->moveID != record->toInitial.at(i)->ind)
1462 for(
int i = 0; i < 4; i++) {
1470 for(
int i = 0; i < 4; i++) {
1491 if(record ==
nullptr)
1497 if(record->toType1 !=
nullptr) {
1498 if(record->toType1->ind !=
type1)
1516 bool dualType = record->toType2 !=
nullptr &&
1517 record->toType1 !=
nullptr &&
1518 record->toType2->ind != record->toType1->ind;
1521 if(record->toType2->ind !=
type2)
1527 if(record->catchRate) {
1541 if(record ==
nullptr)
1544 return *record->pokedex;
1550 if(record ==
nullptr)
1553 if(record->readable ==
"")
1554 return record->name;
1556 return record->readable;
1566 return atkChk && defChk && spdChk && spChk;
1589 var8 offset = qAbs(nature - cur);
1611 else if(
exp >= max) {
1619 QVector<PokemonMove*> movesNew;
1622 for(
int i = 0; i < 4; i++) {
1623 if(
moves[i]->moveID <= 0)
1633 movesNew.append(newMoveEl);
1637 for(
int i = 0; i < 4; i++) {
1638 moves[i]->moveID = 0;
1644 for(
int i = 0; i < movesNew.size(); i++) {
1645 moves[i]->moveID = movesNew.at(i)->moveID;
1646 moves[i]->pp = movesNew.at(i)->pp;
1647 moves[i]->ppUp = movesNew.at(i)->ppUp;
1651 for(
int i = 0; i < 4; i++) {
1652 moves[i]->moveIDChanged();
1653 moves[i]->ppChanged();
1654 moves[i]->ppUpChanged();
1660 for(
int i = 0; i < 4; i++)
1661 moves[i]->correctMove();
1713 moves[ind]->changeMove(moveID, pp, ppUp);
1723 moves[ind]->moveID = 0;
1725 moves[ind]->ppUp = 0;
1737 for(
int i = 1; i <
maxMoves; i++) {
1738 moves[i]->moveID = 0;
1739 moves[i]->moveIDChanged();
1742 moves[i]->ppChanged();
1745 moves[i]->ppUpChanged();
1758 moves[ind]->correctMove();
1768 struct MoveVals {
int id;
int pp;
int ppUp; };
1773 QVector<MoveVals> vec;
1774 for(
int i = 0; i <
maxMoves; i++) {
1775 if(
moves[i]->moveID <= 0)
1780 if(from < 0 || from >= vec.size())
1783 MoveVals moved = vec.at(from);
1789 for(
int i = qBound(0, to, vec.size()); i < vec.size(); i++) {
1795 int anchorShift = (anchorIdx > from) ? 1 : 0;
1801 vec.insert(anchorIdx - anchorShift, moved);
1806 for(
int i = 0; i <
maxMoves; i++) {
1808 moves[i]->changeMove(vec.at(i).id, vec.at(i).pp, vec.at(i).ppUp);
1810 moves[i]->changeMove(0, 0, 0);
1822 if(record ==
nullptr)
1827 for(
int i = 0; i < 4 && i < record->toInitial.size(); i++) {
1828 auto moveData = record->toInitial.at(i);
1829 moves[i]->moveID = moveData->ind;
1830 moves[i]->moveIDChanged();
1832 moves[i]->pp = *moveData->pp;
1833 moves[i]->ppChanged();
1836 moves[i]->ppUpChanged();
1843 update(
true,
true,
true,
true);
1896 dv[0] = pkmn->
dv[0];
1897 dv[1] = pkmn->
dv[1];
1898 dv[2] = pkmn->
dv[2];
1899 dv[3] = pkmn->
dv[3];
1904 for(
int i = 0; i < 4; i++) {
1906 moves[i]->moveIDChanged();
1909 moves[i]->ppChanged();
1912 moves[i]->ppUpChanged();
1932 for(
int i = 0; i < 4; i++) {
1933 if(
moves[i]->moveID <= 0)
1970 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.