summaryrefslogtreecommitdiff
path: root/arm9/src
diff options
context:
space:
mode:
Diffstat (limited to 'arm9/src')
-rw-r--r--arm9/src/pokemon.c3741
-rw-r--r--arm9/src/string_util.c3
2 files changed, 3741 insertions, 3 deletions
diff --git a/arm9/src/pokemon.c b/arm9/src/pokemon.c
new file mode 100644
index 00000000..4a4b8a6d
--- /dev/null
+++ b/arm9/src/pokemon.c
@@ -0,0 +1,3741 @@
+#include "global.h"
+#define IN_POKEMON_C
+#include "proto.h"
+#include "party.h"
+#include "pokemon.h"
+#include "filesystem.h"
+#include "heap.h"
+#include "MI_memory.h"
+#include "math_util.h"
+#include "move_data.h"
+#include "string_util.h"
+#include "text.h"
+#include "constants/abilities.h"
+#include "constants/items.h"
+#include "constants/moves.h"
+#include "constants/sinnoh_dex.h"
+
+#pragma thumb on
+
+u32 GetMonDataInternal(struct Pokemon * pokemon, int attr, void * ptr);
+u32 GetBoxMonDataInternal(struct BoxPokemon * pokemon, int attr, void * ptr);
+void SetMonDataInternal(struct Pokemon * pokemon, int attr, void * ptr);
+void SetBoxMonDataInternal(struct BoxPokemon * pokemon, int attr, void * ptr);
+void AddMonDataInternal(struct Pokemon * pokemon, int attr, int amount);
+void AddBoxMonData(struct BoxPokemon * pokemon, int attr, int amount);
+u32 CalcBoxMonExpToNextLevel(struct BoxPokemon * boxmon);
+u16 ModifyStatByNature(u8 nature, u16 statval, u8 statno);
+u8 GetGenderBySpeciesAndPersonality_PreloadedPersonal(struct BaseStats * personal, u16 species, u32 pid);
+u8 BoxMonIsShiny(struct BoxPokemon * boxmon);
+u8 CalcShininessByOtIdAndPersonality(u32 otid, u32 pid);
+void InitBoxMonMoveset(struct BoxPokemon * boxmon);
+u32 FUN_020696A8(struct BoxPokemon * boxmon, u16 move);
+void FUN_02069718(struct BoxPokemon * boxmon, u16 move);
+void FUN_020697D4(struct BoxPokemon * boxmon, u16 move, u8 slot);
+void FUN_020698E8(struct BoxPokemon * boxmon, int slot1, int slot2);
+s8 FUN_02069BD0(struct BoxPokemon * boxmon, int flavor);
+s8 FUN_02069BE4(u32 personality, int flavor);
+u8 FUN_02069CF4(struct PlayerParty * party_p, u8 mask);
+BOOL FUN_02069E7C(struct BoxPokemon * boxmon);
+BOOL FUN_02069E9C(struct BoxPokemon * boxmon);
+void FUN_02069ECC(struct BoxPokemon * boxmon);
+void LoadWotbl_HandleAlternateForme(int species, int forme, u16 * wotbl);
+void FUN_0206A054(struct BoxPokemon * boxmon, u32 a1, u32 pokeball, u32 a3, u32 encounterType, u32 a5);
+BOOL MonHasMove(struct Pokemon * pokemon, u16 move);
+BOOL FUN_0206A144(struct BoxPokemon * boxmon, u32 a1);
+BOOL FUN_0206A16C(u16 species, int forme, u32 a2);
+void FUN_0206A1CC(struct BoxPokemon * boxmon);
+u32 MaskOfFlagNo(int flagno);
+void LoadMonPersonal(int species, struct BaseStats * personal);
+void LoadMonEvolutionTable(u16 species, struct Evolution * dest);
+
+int ResolveMonForme(int species, int forme);
+void MonEncryptSegment(u16 * datap, u32 size, u32 key);
+void MonDecryptSegment(u16 * datap, u32 size, u32 key);
+u16 MonEncryptionLCRNG(u32 * seed);
+u16 CalcMonChecksum(u16 * datap, u32 size);
+PokemonDataBlock * GetSubstruct(struct BoxPokemon * boxmon, u32 personality, u8 which_struct);
+void LoadMonBaseStats_HandleAlternateForme(int species, int forme, struct BaseStats * baseStats);
+u8 FUN_020690D4(struct BoxPokemon * boxmon);
+
+#define ENCRY_ARGS_PTY(mon) (u16 *)&(mon)->party, sizeof((mon)->party), (mon)->box.pid
+#define ENCRY_ARGS_BOX(boxmon) (u16 *)&(boxmon)->substructs, sizeof((boxmon)->substructs), (boxmon)->checksum
+#define ENCRYPT_PTY(mon) MonEncryptSegment(ENCRY_ARGS_PTY(mon))
+#define ENCRYPT_BOX(boxmon) MonEncryptSegment(ENCRY_ARGS_BOX(boxmon))
+#define DECRYPT_PTY(mon) MonDecryptSegment(ENCRY_ARGS_PTY(mon))
+#define DECRYPT_BOX(boxmon) MonDecryptSegment(ENCRY_ARGS_BOX(boxmon))
+#define CHECKSUM(boxmon) CalcMonChecksum((u16 *)(boxmon)->substructs, sizeof((boxmon)->substructs))
+#define SHINY_CHECK(otid, pid) (( \
+ ((((otid) & 0xFFFF0000u) >> 16u)) ^ \
+ (((otid) & 0xFFFFu)) ^ \
+ ((((pid) & 0xFFFF0000u) >> 16u))^ \
+ (((pid) & 0xFFFFu))) \
+ < 8u)
+#define CALC_UNOWN_LETTER(pid) ((u32)((((pid) & 0x3000000) >> 18) | (((pid) & 0x30000) >> 12) | (((pid) & 0x300) >> 6) | (((pid) & 0x3) >> 0)) % 28u)
+
+const u16 sItemOdds[2][2] = {
+ { 45, 95 },
+ { 20, 80 },
+};
+
+const s8 sFriendshipModTable[][3] = {
+ { 5, 3, 2 },
+ { 5, 3, 2 },
+ { 1, 1, 0 },
+ { 3, 2, 1 },
+ { 1, 1, 0 },
+ { 1, 1, 1 },
+ { -1, -1, -1 },
+ { -5, -5, -10 },
+ { -5, -5, -10 },
+ { 3, 2, 1 },
+};
+
+const u16 sLegendaryMonsList[] = {
+ SPECIES_MEWTWO,
+ SPECIES_MEW,
+ SPECIES_HO_OH,
+ SPECIES_LUGIA,
+ SPECIES_CELEBI,
+ SPECIES_KYOGRE,
+ SPECIES_GROUDON,
+ SPECIES_RAYQUAZA,
+ SPECIES_JIRACHI,
+ SPECIES_DEOXYS,
+ SPECIES_DIALGA,
+ SPECIES_PALKIA,
+ SPECIES_GIRATINA,
+ SPECIES_PHIONE,
+ SPECIES_MANAPHY,
+ SPECIES_DARKRAI,
+ SPECIES_SHAYMIN,
+ SPECIES_ARCEUS,
+};
+
+const s8 UNK_020F7F16[][5] = {
+ // Atk, Def, Spd, SpA, SpD
+ { 0, 0, 0, 0, 0},
+ { 1, 0, 0, 0, -1},
+ { 1, 0, -1, 0, 0},
+ { 1, -1, 0, 0, 0},
+ { 1, 0, 0, -1, 0},
+ { -1, 0, 0, 0, 1},
+ { 0, 0, 0, 0, 0},
+ { 0, 0, -1, 0, 1},
+ { 0, -1, 0, 0, 1},
+ { 0, 0, 0, -1, 1},
+ { -1, 0, 1, 0, 0},
+ { 0, 0, 1, 0, -1},
+ { 0, 0, 0, 0, 0},
+ { 0, -1, 1, 0, 0},
+ { 0, 0, 1, -1, 0},
+ { -1, 1, 0, 0, 0},
+ { 0, 1, 0, 0, -1},
+ { 0, 1, -1, 0, 0},
+ { 0, 0, 0, 0, 0},
+ { 0, 1, 0, -1, 0},
+ { -1, 0, 0, 1, 0},
+ { 0, 0, 0, 1, -1},
+ { 0, 0, -1, 1, 0},
+ { 0, -1, 0, 1, 0},
+ { 0, 0, 0, 0, 0},
+};
+
+const s8 sNatureStatMods[][5] = {
+ { 0, 0, 0, 0, 0 },
+ { 1, -1, 0, 0, 0 },
+ { 1, 0, -1, 0, 0 },
+ { 1, 0, 0, -1, 0 },
+ { 1, 0, 0, 0, -1 },
+ { -1, 1, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { 0, 1, -1, 0, 0 },
+ { 0, 1, 0, -1, 0 },
+ { 0, 1, 0, 0, -1 },
+ { -1, 0, 1, 0, 0 },
+ { 0, -1, 1, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 1, -1, 0 },
+ { 0, 0, 1, 0, -1 },
+ { -1, 0, 0, 1, 0 },
+ { 0, -1, 0, 1, 0 },
+ { 0, 0, -1, 1, 0 },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 1, -1 },
+ { -1, 0, 0, 0, 1 },
+ { 0, -1, 0, 0, 1 },
+ { 0, 0, -1, 0, 1 },
+ { 0, 0, 0, -1, 1 },
+ { 0, 0, 0, 0, 0 },
+};
+
+void ZeroMonData(struct Pokemon * pokemon)
+{
+ MIi_CpuClearFast(0, pokemon, sizeof(struct Pokemon));
+ ENCRYPT_BOX(&pokemon->box);
+ ENCRYPT_PTY(pokemon);
+}
+
+void ZeroBoxMonData(struct BoxPokemon * boxmon)
+{
+ MIi_CpuClearFast(0, boxmon, sizeof(struct BoxPokemon));
+ ENCRYPT_BOX(boxmon);
+}
+
+u32 SizeOfStructPokemon(void)
+{
+ return sizeof(struct Pokemon);
+}
+
+struct Pokemon * AllocMonZeroed(u32 heap_id)
+{
+ struct Pokemon * pokemon = (struct Pokemon *)AllocFromHeap(heap_id, sizeof(struct Pokemon));
+ ZeroMonData(pokemon);
+ return pokemon;
+}
+
+BOOL AcquireMonLock(struct Pokemon * mon)
+{
+ BOOL ret = FALSE;
+
+ if (!mon->box.party_lock)
+ {
+ ret = TRUE;
+ GF_ASSERT(!mon->box.box_lock);
+ mon->box.party_lock = TRUE;
+ mon->box.box_lock = TRUE;
+ DECRYPT_PTY(mon);
+ DECRYPT_BOX(&mon->box);
+ }
+ return ret;
+}
+
+BOOL ReleaseMonLock(struct Pokemon * mon, BOOL decrypt_result)
+{
+ BOOL ret = FALSE;
+ if (mon->box.party_lock == TRUE && decrypt_result == TRUE)
+ {
+ ret = TRUE;
+ mon->box.party_lock = FALSE;
+ mon->box.box_lock = FALSE;
+ ENCRYPT_PTY(mon);
+ mon->box.checksum = CHECKSUM(&mon->box);
+ ENCRYPT_BOX(&mon->box);
+ }
+ return ret;
+}
+
+BOOL AcquireBoxMonLock(struct BoxPokemon * mon)
+{
+ BOOL ret = FALSE;
+
+ if (!mon->box_lock)
+ {
+ ret = TRUE;
+ mon->box_lock = TRUE;
+ DECRYPT_BOX(mon);
+ }
+ return ret;
+}
+
+BOOL ReleaseBoxMonLock(struct BoxPokemon * mon, BOOL decrypt_result)
+{
+ BOOL ret = FALSE;
+ if (mon->box_lock == TRUE && decrypt_result == TRUE)
+ {
+ ret = TRUE;
+ mon->box_lock = FALSE;
+ mon->checksum = CHECKSUM(mon);
+ ENCRYPT_BOX(mon);
+ }
+ return ret;
+}
+
+void CreateMon(struct Pokemon * pokemon, int species, int level, int fixedIV, int hasFixedPersonality, int fixedPersonality, int otIdType, int fixedOtId)
+{
+ struct SealStruct * seal;
+ u32 capsule;
+ u8 seal_coords[0x18];
+ ZeroMonData(pokemon);
+ CreateBoxMon(&pokemon->box, species, level, fixedIV, hasFixedPersonality, fixedPersonality, otIdType, fixedOtId);
+ // Not your average encryption call
+ MonEncryptSegment((u16 *)&pokemon->party, sizeof(pokemon->party), 0);
+ ENCRYPT_PTY(pokemon);
+ SetMonData(pokemon, MON_DATA_LEVEL, &level);
+ seal = CreateNewSealsObject(0);
+ SetMonData(pokemon, MON_DATA_SEAL_STRUCT, seal);
+ FreeToHeap(seal);
+ capsule = 0;
+ SetMonData(pokemon, MON_DATA_CAPSULE, &capsule);
+ MIi_CpuClearFast(0, seal_coords, sizeof(seal_coords));
+ SetMonData(pokemon, MON_DATA_SEAL_COORDS, seal_coords);
+ CalcMonLevelAndStats(pokemon);
+}
+
+void CreateBoxMon(struct BoxPokemon * boxPokemon, int species, int level, int fixedIV, int hasFixedPersonality, int fixedPersonality, int otIdType, int fixedOtId)
+{
+ BOOL decry;
+ u32 exp;
+ u32 iv;
+ ZeroBoxMonData(boxPokemon);
+ decry = AcquireBoxMonLock(boxPokemon);
+ if (hasFixedPersonality == 0)
+ {
+ fixedPersonality = (rand_LC() | (rand_LC() << 16));
+ }
+ SetBoxMonData(boxPokemon, MON_DATA_PERSONALITY, &fixedPersonality);
+ if (otIdType == 2)
+ {
+ do
+ {
+ fixedOtId = (rand_LC() | (rand_LC() << 16));
+ } while (SHINY_CHECK(fixedOtId, fixedPersonality));
+ }
+ else if (otIdType != 1)
+ fixedOtId = 0;
+ SetBoxMonData(boxPokemon, MON_DATA_OTID, &fixedOtId);
+ SetBoxMonData(boxPokemon, MON_DATA_GAME_LANGUAGE, (void *)&gGameLanguage);
+ SetBoxMonData(boxPokemon, MON_DATA_SPECIES, &species);
+ SetBoxMonData(boxPokemon, MON_DATA_SPECIES_NAME, NULL);
+ exp = GetMonExpBySpeciesAndLevel(species, level);
+ SetBoxMonData(boxPokemon, MON_DATA_EXPERIENCE, &exp);
+ exp = (u32)GetMonBaseStat(species, BASE_FRIENDSHIP);
+ SetBoxMonData(boxPokemon, MON_DATA_FRIENDSHIP, &exp);
+ SetBoxMonData(boxPokemon, MON_DATA_MET_LEVEL, &level);
+ SetBoxMonData(boxPokemon, MON_DATA_GAME_VERSION, (void *)&gGameVersion);
+ exp = ITEM_POKE_BALL;
+ SetBoxMonData(boxPokemon, MON_DATA_POKEBALL, &exp);
+ if (fixedIV < 0x20)
+ {
+ SetBoxMonData(boxPokemon, MON_DATA_HP_IV, &fixedIV);
+ SetBoxMonData(boxPokemon, MON_DATA_ATK_IV, &fixedIV);
+ SetBoxMonData(boxPokemon, MON_DATA_DEF_IV, &fixedIV);
+ SetBoxMonData(boxPokemon, MON_DATA_SPEED_IV, &fixedIV);
+ SetBoxMonData(boxPokemon, MON_DATA_SPATK_IV, &fixedIV);
+ SetBoxMonData(boxPokemon, MON_DATA_SPDEF_IV, &fixedIV);
+ }
+ else
+ {
+ exp = rand_LC();
+ iv = exp & 0x1F;
+ SetBoxMonData(boxPokemon, MON_DATA_HP_IV, &iv);
+ iv = (exp & 0x3E0) >> 5;
+ SetBoxMonData(boxPokemon, MON_DATA_ATK_IV, &iv);
+ iv = (exp & 0x7C00) >> 10;
+ SetBoxMonData(boxPokemon, MON_DATA_DEF_IV, &iv);
+ exp = rand_LC();
+ iv = exp & 0x1F;
+ SetBoxMonData(boxPokemon, MON_DATA_SPEED_IV, &iv);
+ iv = (exp & 0x3E0) >> 5;
+ SetBoxMonData(boxPokemon, MON_DATA_SPATK_IV, &iv);
+ iv = (exp & 0x7C00) >> 10;
+ SetBoxMonData(boxPokemon, MON_DATA_SPDEF_IV, &iv);
+ }
+ exp = (u32)GetMonBaseStat(species, BASE_ABILITY_1);
+ iv = (u32)GetMonBaseStat(species, BASE_ABILITY_2);
+ if (iv != 0)
+ {
+ if (fixedPersonality & 1)
+ SetBoxMonData(boxPokemon, MON_DATA_ABILITY, &iv);
+ else
+ SetBoxMonData(boxPokemon, MON_DATA_ABILITY, &exp);
+ }
+ else
+ SetBoxMonData(boxPokemon, MON_DATA_ABILITY, &exp);
+ exp = GetBoxMonGender(boxPokemon);
+ SetBoxMonData(boxPokemon, MON_DATA_GENDER, &exp);
+ InitBoxMonMoveset(boxPokemon);
+ ReleaseBoxMonLock(boxPokemon, decry);
+}
+
+void CreateMonWithNature(struct Pokemon * pokemon, u16 species, u8 level, u8 fixedIv, u8 nature)
+{
+ u32 personality;
+ do
+ {
+ personality = (u32)(rand_LC() | (rand_LC() << 16));
+ } while (nature != GetNatureFromPersonality(personality));
+ CreateMon(pokemon, (int)species, (int)level, (int)fixedIv, 1, (int)personality, (int)0, (int)0);
+}
+
+// FIXME: stack storage of pokemon, fixedIv swapped
+void CreateMonWithGenderNatureLetter(struct Pokemon * pokemon, u16 species, u8 level, u8 fixedIv, u8 gender, u8 nature, u8 letter)
+{
+ u32 pid = 0;
+ u16 test = 0;
+ if (letter != 0 && letter < 29)
+ {
+ do {
+ pid = (u32)(rand_LC() | (rand_LC() << 16));
+ test = (u16)CALC_UNOWN_LETTER(pid);
+ } while (nature != GetNatureFromPersonality(pid) || gender != GetGenderBySpeciesAndPersonality(species, pid) || test != letter - 1);
+ }
+ else
+ {
+ pid = GenPersonalityByGenderAndNature(species, gender, nature);
+ }
+ CreateMon(pokemon, (int)species, (int)level, (int)fixedIv, 1, (int)pid, 0, 0);
+}
+
+u32 GenPersonalityByGenderAndNature(u16 species, u8 gender, u8 nature)
+{
+ int pid = nature;
+ u8 ratio = (u8)GetMonBaseStat(species, BASE_GENDER_RATIO);
+ switch (ratio)
+ {
+ case MON_RATIO_MALE:
+ case MON_RATIO_FEMALE:
+ case MON_RATIO_UNKNOWN:
+ break;
+ default:
+ if (gender == MON_MALE)
+ {
+ // Smallest increment that forces the low byte to exceed the
+ // gender ratio, thus making the mon male
+ pid = 25 * ((ratio / 25) + 1);
+ pid += nature;
+ }
+ break;
+ }
+ return (u32)pid;
+}
+
+void CreateMonWithFixedIVs(struct Pokemon * pokemon, int species, int level, int ivs, int personality)
+{
+ CreateMon(pokemon, species, level, 0, 1, personality, 0, 0);
+ SetMonData(pokemon, MON_DATA_IVS_WORD, &ivs);
+ CalcMonLevelAndStats(pokemon);
+}
+
+void CalcMonLevelAndStats(struct Pokemon * pokemon)
+{
+ BOOL decry = AcquireMonLock(pokemon);
+ u32 level = (u32)CalcMonLevel(pokemon);
+ SetMonData(pokemon, MON_DATA_LEVEL, &level);
+ CalcMonStats(pokemon);
+ ReleaseMonLock(pokemon, decry);
+}
+
+void CalcMonStats(struct Pokemon * pokemon)
+{
+ struct BaseStats * baseStats;
+ int level;
+ int maxHp;
+ int hpIv;
+ int hpEv;
+ int atkIv;
+ int defIv;
+ int speedIv;
+ int spatkIv;
+ int spdefIv;
+ int atkEv;
+ int defEv;
+ int speedEv;
+ int spatkEv;
+ int spdefEv;
+ int forme;
+ int hp;
+ int species;
+ int newMaxHp;
+ int newAtk;
+ int newDef;
+ int newSpeed;
+ int newSpatk;
+ int newSpdef;
+ BOOL decry = AcquireMonLock(pokemon);
+ level = (int)GetMonData(pokemon, MON_DATA_LEVEL, NULL);
+ maxHp = (int)GetMonData(pokemon, MON_DATA_MAXHP, NULL);
+ hp = (int)GetMonData(pokemon, MON_DATA_HP, NULL);
+ hpIv = (int)GetMonData(pokemon, MON_DATA_HP_IV, NULL);
+ hpEv = (int)GetMonData(pokemon, MON_DATA_HP_EV, NULL);
+ atkIv = (int)GetMonData(pokemon, MON_DATA_ATK_IV, NULL);
+ atkEv = (int)GetMonData(pokemon, MON_DATA_ATK_EV, NULL);
+ defIv = (int)GetMonData(pokemon, MON_DATA_DEF_IV, NULL);
+ defEv = (int)GetMonData(pokemon, MON_DATA_DEF_EV, NULL);
+ speedIv = (int)GetMonData(pokemon, MON_DATA_SPEED_IV, NULL);
+ speedEv = (int)GetMonData(pokemon, MON_DATA_SPEED_EV, NULL);
+ spatkIv = (int)GetMonData(pokemon, MON_DATA_SPATK_IV, NULL);
+ spatkEv = (int)GetMonData(pokemon, MON_DATA_SPATK_EV, NULL);
+ spdefIv = (int)GetMonData(pokemon, MON_DATA_SPDEF_IV, NULL);
+ spdefEv = (int)GetMonData(pokemon, MON_DATA_SPDEF_EV, NULL);
+ forme = (int)GetMonData(pokemon, MON_DATA_FORME, NULL);
+ species = (int)GetMonData(pokemon, MON_DATA_SPECIES, NULL);
+
+ baseStats = (struct BaseStats *)AllocFromHeap(0, sizeof(struct BaseStats));
+ LoadMonBaseStats_HandleAlternateForme(species, forme, baseStats);
+
+ if (species == SPECIES_SHEDINJA)
+ newMaxHp = 1;
+ else
+ {
+ newMaxHp = (baseStats->hp * 2 + hpIv + hpEv / 4) * level / 100 + level + 10;
+ }
+ SetMonData(pokemon, MON_DATA_MAXHP, &newMaxHp);
+
+ newAtk = (baseStats->atk * 2 + atkIv + atkEv / 4) * level / 100 + 5;
+ newAtk = ModifyStatByNature(GetMonNature(pokemon), (u16)newAtk, 1);
+ SetMonData(pokemon, MON_DATA_ATK, &newAtk);
+
+ newDef = (baseStats->def * 2 + defIv + defEv / 4) * level / 100 + 5;
+ newDef = ModifyStatByNature(GetMonNature(pokemon), (u16)newDef, 2);
+ SetMonData(pokemon, MON_DATA_DEF, &newDef);
+
+ newSpeed = (baseStats->speed * 2 + speedIv + speedEv / 4) * level / 100 + 5;
+ newSpeed = ModifyStatByNature(GetMonNature(pokemon), (u16)newSpeed, 3);
+ SetMonData(pokemon, MON_DATA_SPEED, &newSpeed);
+
+ newSpatk = (baseStats->spatk * 2 + spatkIv + spatkEv / 4) * level / 100 + 5;
+ newSpatk = ModifyStatByNature(GetMonNature(pokemon), (u16)newSpatk, 4);
+ SetMonData(pokemon, MON_DATA_SPATK, &newSpatk);
+
+ newSpdef = (baseStats->spdef * 2 + spdefIv + spdefEv / 4) * level / 100 + 5;
+ newSpdef = ModifyStatByNature(GetMonNature(pokemon), (u16)newSpdef, 5);
+ SetMonData(pokemon, MON_DATA_SPDEF, &newSpdef);
+
+ FreeToHeap(baseStats);
+
+ if (hp != 0 || maxHp == 0)
+ {
+ if (species == SPECIES_SHEDINJA)
+ hp = 1;
+ else if (hp == 0)
+ hp = newMaxHp;
+ else
+ hp += newMaxHp - maxHp;
+ }
+ if (hp != 0)
+ SetMonData(pokemon, MON_DATA_HP, &hp);
+ ReleaseMonLock(pokemon, decry);
+}
+
+u32 GetMonData(struct Pokemon * pokemon, int attr, void * dest)
+{
+ u32 ret;
+ u32 checksum;
+ if (!pokemon->box.party_lock)
+ {
+ DECRYPT_PTY(pokemon);
+ DECRYPT_BOX(&pokemon->box);
+ checksum = CHECKSUM(&pokemon->box);
+ if (checksum != pokemon->box.checksum)
+ {
+ GF_ASSERT(checksum == pokemon->box.checksum);
+ pokemon->box.checksum_fail = TRUE;
+ }
+ }
+ ret = GetMonDataInternal(pokemon, attr, dest);
+ if (!pokemon->box.party_lock)
+ {
+ ENCRYPT_PTY(pokemon);
+ ENCRYPT_BOX(&pokemon->box);
+ }
+ return ret;
+}
+
+u32 GetMonDataInternal(struct Pokemon * pokemon, int attr, void * dest)
+{
+ switch (attr)
+ {
+ case MON_DATA_STATUS:
+ return pokemon->party.status;
+ case MON_DATA_LEVEL:
+ return pokemon->party.level;
+ case MON_DATA_CAPSULE:
+ return pokemon->party.capsule;
+ case MON_DATA_HP:
+ return pokemon->party.hp;
+ case MON_DATA_MAXHP:
+ return pokemon->party.maxHp;
+ case MON_DATA_ATK:
+ return pokemon->party.atk;
+ case MON_DATA_DEF:
+ return pokemon->party.def;
+ case MON_DATA_SPEED:
+ return pokemon->party.speed;
+ case MON_DATA_SPATK:
+ return pokemon->party.spatk;
+ case MON_DATA_SPDEF:
+ return pokemon->party.spdef;
+ case MON_DATA_SEAL_STRUCT:
+ CopySealsObject(&pokemon->party.seal_something, dest);
+ return 1;
+ case MON_DATA_SEAL_COORDS:
+ FUN_02029C74(pokemon->party.sealCoords, dest);
+ return 1;
+ default:
+ return GetBoxMonDataInternal(&pokemon->box, attr, dest);
+ }
+}
+
+u32 GetBoxMonData(struct BoxPokemon * boxmon, int attr, void * dest)
+{
+ u32 ret;
+ u32 checksum;
+ if (!boxmon->box_lock)
+ {
+ DECRYPT_BOX(boxmon);
+ checksum = CHECKSUM(boxmon);
+ if (checksum != boxmon->checksum)
+ {
+ GF_ASSERT(checksum == boxmon->checksum);
+ boxmon->checksum_fail = TRUE;
+ }
+ }
+ ret = GetBoxMonDataInternal(boxmon, attr, dest);
+ if (!boxmon->box_lock)
+ {
+ ENCRYPT_BOX(boxmon);
+ }
+ return ret;
+}
+
+u32 GetBoxMonDataInternal(struct BoxPokemon * boxmon, int attr, void * dest)
+{
+ u32 ret = 0;
+ PokemonDataBlockA * blockA = &GetSubstruct(boxmon, boxmon->pid, 0)->blockA;
+ PokemonDataBlockB * blockB = &GetSubstruct(boxmon, boxmon->pid, 1)->blockB;
+ PokemonDataBlockC * blockC = &GetSubstruct(boxmon, boxmon->pid, 2)->blockC;
+ PokemonDataBlockD * blockD = &GetSubstruct(boxmon, boxmon->pid, 3)->blockD;
+
+ switch (attr)
+ {
+ default:
+ ret = 0;
+ break;
+ case MON_DATA_PERSONALITY:
+ ret = boxmon->pid;
+ break;
+ case MON_DATA_PARTY_LOCK:
+ ret = boxmon->party_lock;
+ break;
+ case MON_DATA_BOX_LOCK:
+ ret = boxmon->box_lock;
+ break;
+ case MON_DATA_CHECKSUM_FAILED:
+ ret = boxmon->checksum_fail;
+ break;
+ case MON_DATA_CHECKSUM:
+ ret = boxmon->checksum;
+ break;
+ case MON_DATA_SPECIES_EXISTS:
+ if (blockA->species != SPECIES_NONE)
+ ret = TRUE;
+ else
+ ret = FALSE;
+ break;
+ case MON_DATA_SANITY_IS_EGG:
+ ret = boxmon->checksum_fail;
+ if (!ret)
+ ret = blockB->isEgg;
+ break;
+ case MON_DATA_SPECIES2:
+ ret = blockA->species;
+ if (ret != SPECIES_NONE && (blockB->isEgg || boxmon->checksum_fail))
+ ret = SPECIES_EGG;
+ break;
+ case MON_DATA_LEVEL:
+ ret = (u32)CalcLevelBySpeciesAndExp(blockA->species, blockA->exp);
+ break;
+ case MON_DATA_SPECIES:
+ if (boxmon->checksum_fail)
+ ret = SPECIES_EGG;
+ else
+ ret = blockA->species;
+ break;
+ case MON_DATA_HELD_ITEM:
+ ret = blockA->heldItem;
+ break;
+ case MON_DATA_OTID:
+ ret = blockA->otID;
+ break;
+ case MON_DATA_EXPERIENCE:
+ ret = blockA->exp;
+ break;
+ case MON_DATA_FRIENDSHIP:
+ ret = blockA->friendship;
+ break;
+ case MON_DATA_ABILITY:
+ ret = blockA->ability;
+ break;
+ case MON_DATA_MARKINGS:
+ ret = blockA->markings;
+ break;
+ case MON_DATA_GAME_LANGUAGE:
+ ret = blockA->originLanguage;
+ break;
+ case MON_DATA_HP_EV:
+ ret = blockA->hpEV;
+ break;
+ case MON_DATA_ATK_EV:
+ ret = blockA->atkEV;
+ break;
+ case MON_DATA_DEF_EV:
+ ret = blockA->defEV;
+ break;
+ case MON_DATA_SPEED_EV:
+ ret = blockA->spdEV;
+ break;
+ case MON_DATA_SPATK_EV:
+ ret = blockA->spatkEV;
+ break;
+ case MON_DATA_SPDEF_EV:
+ ret = blockA->spdefEV;
+ break;
+ case MON_DATA_COOL:
+ ret = blockA->coolStat;
+ break;
+ case MON_DATA_BEAUTY:
+ ret = blockA->beautyStat;
+ break;
+ case MON_DATA_CUTE:
+ ret = blockA->cuteStat;
+ break;
+ case MON_DATA_SMART:
+ ret = blockA->smartStat;
+ break;
+ case MON_DATA_TOUGH:
+ ret = blockA->toughStat;
+ break;
+ case MON_DATA_SHEEN:
+ ret = blockA->sheen;
+ break;
+ case MON_DATA_SINNOH_CHAMP_RIBBON:
+ case MON_DATA_SINNOH_RIBBON_26:
+ case MON_DATA_SINNOH_RIBBON_27:
+ case MON_DATA_SINNOH_RIBBON_28:
+ case MON_DATA_SINNOH_RIBBON_29:
+ case MON_DATA_SINNOH_RIBBON_30:
+ case MON_DATA_SINNOH_RIBBON_31:
+ case MON_DATA_SINNOH_RIBBON_32:
+ case MON_DATA_SINNOH_RIBBON_33:
+ case MON_DATA_SINNOH_RIBBON_34:
+ case MON_DATA_SINNOH_RIBBON_35:
+ case MON_DATA_SINNOH_RIBBON_36:
+ case MON_DATA_SINNOH_RIBBON_37:
+ case MON_DATA_SINNOH_RIBBON_38:
+ case MON_DATA_SINNOH_RIBBON_39:
+ case MON_DATA_SINNOH_RIBBON_40:
+ case MON_DATA_SINNOH_RIBBON_41:
+ case MON_DATA_SINNOH_RIBBON_42:
+ case MON_DATA_SINNOH_RIBBON_43:
+ case MON_DATA_SINNOH_RIBBON_44:
+ case MON_DATA_SINNOH_RIBBON_45:
+ case MON_DATA_SINNOH_RIBBON_46:
+ case MON_DATA_SINNOH_RIBBON_47:
+ case MON_DATA_SINNOH_RIBBON_48:
+ case MON_DATA_SINNOH_RIBBON_49:
+ case MON_DATA_SINNOH_RIBBON_50:
+ case MON_DATA_SINNOH_RIBBON_51:
+ case MON_DATA_SINNOH_RIBBON_52:
+ case MON_DATA_SINNOH_RIBBON_53:
+ {
+ if (blockA->sinnohRibbons & (1ll << (attr - MON_DATA_SINNOH_CHAMP_RIBBON)))
+ {
+ ret = TRUE;
+ }
+ else
+ {
+ ret = FALSE;
+ }
+ }
+ break;
+ case MON_DATA_MOVE1:
+ case MON_DATA_MOVE2:
+ case MON_DATA_MOVE3:
+ case MON_DATA_MOVE4:
+ ret = blockB->moves[attr - MON_DATA_MOVE1];
+ break;
+ case MON_DATA_MOVE1PP:
+ case MON_DATA_MOVE2PP:
+ case MON_DATA_MOVE3PP:
+ case MON_DATA_MOVE4PP:
+ ret = blockB->movePP[attr - MON_DATA_MOVE1PP];
+ break;
+ case MON_DATA_MOVE1PPUP:
+ case MON_DATA_MOVE2PPUP:
+ case MON_DATA_MOVE3PPUP:
+ case MON_DATA_MOVE4PPUP:
+ ret = blockB->movePpUps[attr - MON_DATA_MOVE1PPUP];
+ break;
+ case MON_DATA_MOVE1MAXPP:
+ case MON_DATA_MOVE2MAXPP:
+ case MON_DATA_MOVE3MAXPP:
+ case MON_DATA_MOVE4MAXPP:
+ ret = (u32)FUN_0206AB30(blockB->moves[attr - MON_DATA_MOVE1MAXPP], blockB->movePpUps[attr - MON_DATA_MOVE1MAXPP]);
+ break;
+ case MON_DATA_HP_IV:
+ ret = blockB->hpIV;
+ break;
+ case MON_DATA_ATK_IV:
+ ret = blockB->atkIV;
+ break;
+ case MON_DATA_DEF_IV:
+ ret = blockB->defIV;
+ break;
+ case MON_DATA_SPEED_IV:
+ ret = blockB->spdIV;
+ break;
+ case MON_DATA_SPATK_IV:
+ ret = blockB->spatkIV;
+ break;
+ case MON_DATA_SPDEF_IV:
+ ret = blockB->spdefIV;
+ break;
+ case MON_DATA_IS_EGG:
+ ret = boxmon->checksum_fail;
+ if (!ret)
+ ret = blockB->isEgg;
+ break;
+ case MON_DATA_HAS_NICKNAME:
+ ret = blockB->isNicknamed;
+ break;
+ case MON_DATA_COOL_RIBBON:
+ case MON_DATA_HOENN_RIBBON_79:
+ case MON_DATA_HOENN_RIBBON_80:
+ case MON_DATA_HOENN_RIBBON_81:
+ case MON_DATA_HOENN_RIBBON_82:
+ case MON_DATA_HOENN_RIBBON_83:
+ case MON_DATA_HOENN_RIBBON_84:
+ case MON_DATA_HOENN_RIBBON_85:
+ case MON_DATA_HOENN_RIBBON_86:
+ case MON_DATA_HOENN_RIBBON_87:
+ case MON_DATA_HOENN_RIBBON_88:
+ case MON_DATA_HOENN_RIBBON_89:
+ case MON_DATA_HOENN_RIBBON_90:
+ case MON_DATA_HOENN_RIBBON_91:
+ case MON_DATA_HOENN_RIBBON_92:
+ case MON_DATA_HOENN_RIBBON_93:
+ case MON_DATA_HOENN_RIBBON_94:
+ case MON_DATA_HOENN_RIBBON_95:
+ case MON_DATA_HOENN_RIBBON_96:
+ case MON_DATA_HOENN_RIBBON_97:
+ case MON_DATA_HOENN_RIBBON_98:
+ case MON_DATA_HOENN_RIBBON_99:
+ case MON_DATA_HOENN_RIBBON_100:
+ case MON_DATA_HOENN_RIBBON_101:
+ case MON_DATA_HOENN_RIBBON_102:
+ case MON_DATA_HOENN_RIBBON_103:
+ case MON_DATA_HOENN_RIBBON_104:
+ case MON_DATA_HOENN_RIBBON_105:
+ case MON_DATA_HOENN_RIBBON_106:
+ case MON_DATA_HOENN_RIBBON_107:
+ case MON_DATA_HOENN_RIBBON_108:
+ case MON_DATA_HOENN_RIBBON_109:
+ if (blockB->ribbonFlags & (1ll << (attr - MON_DATA_COOL_RIBBON)))
+ ret = TRUE;
+ else
+ ret = FALSE;
+ break;
+ case MON_DATA_FATEFUL_ENCOUNTER:
+ ret = blockB->fatefulEncounter;
+ break;
+ case MON_DATA_GENDER:
+ ret = blockB->gender;
+ break;
+ case MON_DATA_FORME:
+ ret = blockB->alternateForm;
+ break;
+ case MON_DATA_RESERVED_113:
+ ret = blockB->HGSS_shinyLeaves;
+ break;
+ case MON_DATA_RESERVED_114:
+ ret = blockB->Unused;
+ break;
+ case MON_DATA_NICKNAME:
+ if (boxmon->checksum_fail)
+ GetSpeciesName(SPECIES_MANAPHY_EGG, 0, dest);
+ else
+ {
+ u16 * dest16 = (u16 *)dest;
+ for (ret = 0; ret < POKEMON_NAME_LENGTH; ret++)
+ {
+ dest16[ret] = blockC->nickname[ret];
+ }
+ dest16[ret] = EOS;
+ }
+ break;
+ case MON_DATA_NICKNAME_4:
+ ret = blockB->isNicknamed;
+ // fallthrough
+ case MON_DATA_NICKNAME_3:
+ if (boxmon->checksum_fail)
+ {
+ u16 * buffer = FUN_0200AA50(SPECIES_MANAPHY_EGG, 0);
+ FUN_02021A74(dest, buffer);
+ FUN_02021A20(buffer);
+ }
+ else
+ {
+ FUN_02021E28(dest, blockC->nickname);
+ }
+ break;
+ case MON_DATA_UNK_120:
+ ret = blockC->Unused;
+ break;
+ case MON_DATA_GAME_VERSION:
+ ret = blockC->originGame;
+ break;
+ case MON_DATA_SINNOH_RIBBON_122:
+ case MON_DATA_SINNOH_RIBBON_123:
+ case MON_DATA_SINNOH_RIBBON_124:
+ case MON_DATA_SINNOH_RIBBON_125:
+ case MON_DATA_SINNOH_RIBBON_126:
+ case MON_DATA_SINNOH_RIBBON_127:
+ case MON_DATA_SINNOH_RIBBON_128:
+ case MON_DATA_SINNOH_RIBBON_129:
+ case MON_DATA_SINNOH_RIBBON_130:
+ case MON_DATA_SINNOH_RIBBON_131:
+ case MON_DATA_SINNOH_RIBBON_132:
+ case MON_DATA_SINNOH_RIBBON_133:
+ case MON_DATA_SINNOH_RIBBON_134:
+ case MON_DATA_SINNOH_RIBBON_135:
+ case MON_DATA_SINNOH_RIBBON_136:
+ case MON_DATA_SINNOH_RIBBON_137:
+ case MON_DATA_SINNOH_RIBBON_138:
+ case MON_DATA_SINNOH_RIBBON_139:
+ case MON_DATA_SINNOH_RIBBON_140:
+ case MON_DATA_SINNOH_RIBBON_141:
+ case MON_DATA_SINNOH_RIBBON_142:
+ if (blockC->sinnohRibbons2 & (1ll << (attr - MON_DATA_SINNOH_RIBBON_122)))
+ ret = TRUE;
+ else
+ ret = FALSE;
+ break;
+ case MON_DATA_OT_NAME:
+ {
+ u16 * dest16 = (u16 *)dest;
+ for (ret = 0; ret < OT_NAME_LENGTH; ret++)
+ dest16[ret] = blockD->otTrainerName[ret];
+ dest16[ret] = EOS;
+ }
+ break;
+ case MON_DATA_OT_NAME_2:
+ FUN_02021E28(dest, blockD->otTrainerName);
+ break;
+ case MON_DATA_EGG_MET_YEAR:
+ ret = blockD->dateEggReceived[0];
+ break;
+ case MON_DATA_EGG_MET_MONTH:
+ ret = blockD->dateEggReceived[1];
+ break;
+ case MON_DATA_EGG_MET_DAY:
+ ret = blockD->dateEggReceived[2];
+ break;
+ case MON_DATA_MET_YEAR:
+ ret = blockD->dateMet[0];
+ break;
+ case MON_DATA_MET_MONTH:
+ ret = blockD->dateMet[1];
+ break;
+ case MON_DATA_MET_DAY:
+ ret = blockD->dateMet[2];
+ break;
+ case MON_DATA_EGG_MET_LOCATION:
+ ret = blockD->DP_EggLocation;
+ break;
+ case MON_DATA_MET_LOCATION:
+ ret = blockD->DP_MetLocation;
+ break;
+ case MON_DATA_POKERUS:
+ ret = blockD->pokerus;
+ break;
+ case MON_DATA_POKEBALL:
+ ret = blockD->pokeball;
+ break;
+ case MON_DATA_MET_LEVEL:
+ ret = blockD->metLevel;
+ break;
+ case MON_DATA_MET_GENDER:
+ ret = blockD->metGender;
+ break;
+ case MON_DATA_ENCOUNTER_TYPE:
+ ret = blockD->encounterType;
+ break;
+ case MON_DATA_RESERVED_158:
+ ret = blockD->HGSS_Pokeball;
+ break;
+ case MON_DATA_IVS_WORD:
+ ret = (blockB->hpIV) | \
+ (blockB->atkIV << 5) | \
+ (blockB->defIV << 10) | \
+ (blockB->spdIV << 15) | \
+ (blockB->spatkIV << 20) | \
+ (blockB->spdefIV << 25);
+ break;
+ case MON_DATA_UNK_175:
+ if ((blockA->species == SPECIES_NIDORAN_F || blockA->species == SPECIES_NIDORAN_M) && !blockB->isNicknamed)
+ ret = FALSE;
+ else
+ ret = TRUE;
+ break;
+ case MON_DATA_TYPE_1:
+ case MON_DATA_TYPE_2:
+ if (blockA->species == SPECIES_ARCEUS && blockA->ability == ABILITY_MULTITYPE)
+ ret = (u32)GetArceusTypeByHeldItemEffect((u16)FUN_0206E7B8(blockA->heldItem, 1, 0));
+ else
+ {
+ ret = (u32)GetMonBaseStat_HandleFormeConversion(blockA->species, blockB->alternateForm, (enum BaseStat)(attr - MON_DATA_TYPE_1 + BASE_TYPE1));
+ }
+ break;
+ case MON_DATA_SPECIES_NAME:
+ GetSpeciesName(blockA->species, 0, dest);
+ break;
+ }
+ return ret;
+}
+
+void SetMonData(struct Pokemon * pokemon, int attr, void * value)
+{
+ u16 checksum;
+ if (!pokemon->box.party_lock)
+ {
+ DECRYPT_PTY(pokemon);
+ DECRYPT_BOX(&pokemon->box);
+ checksum = CHECKSUM(&pokemon->box);
+ if (checksum != pokemon->box.checksum)
+ {
+ GF_ASSERT(checksum == pokemon->box.checksum);
+ pokemon->box.checksum_fail = TRUE;
+ ENCRYPT_BOX(&pokemon->box);
+ return;
+ }
+ }
+ SetMonDataInternal(pokemon, attr, value);
+ if (!pokemon->box.party_lock)
+ {
+ ENCRYPT_PTY(pokemon);
+ pokemon->box.checksum = CHECKSUM(&pokemon->box);
+ ENCRYPT_BOX(&pokemon->box);
+ }
+}
+
+void SetMonDataInternal(struct Pokemon * pokemon, int attr, void * value)
+{
+#define VALUE(type) (*(const type *)value)
+ switch (attr)
+ {
+ case MON_DATA_STATUS:
+ pokemon->party.status = VALUE(u32);
+ break;
+ case MON_DATA_LEVEL:
+ pokemon->party.level = VALUE(u8);
+ break;
+ case MON_DATA_CAPSULE:
+ pokemon->party.capsule = VALUE(u8);
+ break;
+ case MON_DATA_HP:
+ pokemon->party.hp = VALUE(u16);
+ break;
+ case MON_DATA_MAXHP:
+ pokemon->party.maxHp = VALUE(u16);
+ break;
+ case MON_DATA_ATK:
+ pokemon->party.atk = VALUE(u16);
+ break;
+ case MON_DATA_DEF:
+ pokemon->party.def = VALUE(u16);
+ break;
+ case MON_DATA_SPEED:
+ pokemon->party.speed = VALUE(u16);
+ break;
+ case MON_DATA_SPATK:
+ pokemon->party.spatk = VALUE(u16);
+ break;
+ case MON_DATA_SPDEF:
+ pokemon->party.spdef = VALUE(u16);
+ break;
+ case MON_DATA_SEAL_STRUCT:
+ CopySealsObject((const struct SealStruct *)value, &pokemon->party.seal_something);
+ break;
+ case MON_DATA_SEAL_COORDS:
+ FUN_02029C74((const u8 *)value, pokemon->party.sealCoords);
+ break;
+ default:
+ SetBoxMonDataInternal(&pokemon->box, attr, value);
+ break;
+ }
+#undef VALUE
+}
+
+void SetBoxMonData(struct BoxPokemon * boxmon, int attr, void * value)
+{
+ u16 checksum;
+ if (!boxmon->box_lock)
+ {
+ DECRYPT_BOX(boxmon);
+ checksum = CHECKSUM(boxmon);
+ if (checksum != boxmon->checksum)
+ {
+ GF_ASSERT(checksum == boxmon->checksum);
+ boxmon->checksum_fail = TRUE;
+ ENCRYPT_BOX(boxmon);
+ return;
+ }
+ }
+ SetBoxMonDataInternal(boxmon, attr, value);
+ if (!boxmon->box_lock)
+ {
+ boxmon->checksum = CHECKSUM(boxmon);
+ ENCRYPT_BOX(boxmon);
+ }
+}
+
+
+void SetBoxMonDataInternal(struct BoxPokemon * boxmon, int attr, void * value)
+{
+#define VALUE(type) (*(const type *)value)
+ u8 flag;
+ u64 mask;
+ u32 i;
+ u16 namebuf[POKEMON_NAME_LENGTH + 1];
+ u16 namebuf2[POKEMON_NAME_LENGTH + 1];
+ u16 namebuf3[POKEMON_NAME_LENGTH + 1];
+ u16 * speciesName;
+
+ PokemonDataBlockA *blockA = &GetSubstruct(boxmon, boxmon->pid, 0)->blockA;
+ PokemonDataBlockB *blockB = &GetSubstruct(boxmon, boxmon->pid, 1)->blockB;
+ PokemonDataBlockC *blockC = &GetSubstruct(boxmon, boxmon->pid, 2)->blockC;
+ PokemonDataBlockD *blockD = &GetSubstruct(boxmon, boxmon->pid, 3)->blockD;
+
+ switch (attr)
+ {
+ case MON_DATA_PERSONALITY:
+ boxmon->pid = VALUE(u32);
+ break;
+ case MON_DATA_PARTY_LOCK:
+ GF_ASSERT(0);
+ boxmon->party_lock = VALUE(u8);
+ break;
+ case MON_DATA_BOX_LOCK:
+ GF_ASSERT(0);
+ boxmon->box_lock = VALUE(u8);
+ break;
+ case MON_DATA_CHECKSUM_FAILED:
+ boxmon->checksum_fail = VALUE(u8);
+ break;
+ case MON_DATA_CHECKSUM:
+ boxmon->checksum = VALUE(u16);
+ break;
+ case MON_DATA_SPECIES:
+ blockA->species = VALUE(u16);
+ break;
+ case MON_DATA_HELD_ITEM:
+ blockA->heldItem = VALUE(u16);
+ break;
+ case MON_DATA_OTID:
+ blockA->otID = VALUE(u32);
+ break;
+ case MON_DATA_EXPERIENCE:
+ blockA->exp = VALUE(u32);
+ break;
+ case MON_DATA_FRIENDSHIP:
+ blockA->friendship = VALUE(u8);
+ break;
+ case MON_DATA_ABILITY:
+ blockA->ability = VALUE(u8);
+ break;
+ case MON_DATA_MARKINGS:
+ blockA->markings = VALUE(u8);
+ break;
+ case MON_DATA_GAME_LANGUAGE:
+ blockA->originLanguage = VALUE(u8);
+ break;
+ case MON_DATA_HP_EV:
+ blockA->hpEV = VALUE(u8);
+ break;
+ case MON_DATA_ATK_EV:
+ blockA->atkEV = VALUE(u8);
+ break;
+ case MON_DATA_DEF_EV:
+ blockA->defEV = VALUE(u8);
+ break;
+ case MON_DATA_SPEED_EV:
+ blockA->spdEV = VALUE(u8);
+ break;
+ case MON_DATA_SPATK_EV:
+ blockA->spatkEV = VALUE(u8);
+ break;
+ case MON_DATA_SPDEF_EV:
+ blockA->spdefEV = VALUE(u8);
+ break;
+ case MON_DATA_COOL:
+ blockA->coolStat = VALUE(u8);
+ break;
+ case MON_DATA_BEAUTY:
+ blockA->beautyStat = VALUE(u8);
+ break;
+ case MON_DATA_CUTE:
+ blockA->cuteStat = VALUE(u8);
+ break;
+ case MON_DATA_SMART:
+ blockA->smartStat = VALUE(u8);
+ break;
+ case MON_DATA_TOUGH:
+ blockA->toughStat = VALUE(u8);
+ break;
+ case MON_DATA_SHEEN:
+ blockA->sheen = VALUE(u8);
+ break;
+ case MON_DATA_SINNOH_CHAMP_RIBBON:
+ case MON_DATA_SINNOH_RIBBON_26:
+ case MON_DATA_SINNOH_RIBBON_27:
+ case MON_DATA_SINNOH_RIBBON_28:
+ case MON_DATA_SINNOH_RIBBON_29:
+ case MON_DATA_SINNOH_RIBBON_30:
+ case MON_DATA_SINNOH_RIBBON_31:
+ case MON_DATA_SINNOH_RIBBON_32:
+ case MON_DATA_SINNOH_RIBBON_33:
+ case MON_DATA_SINNOH_RIBBON_34:
+ case MON_DATA_SINNOH_RIBBON_35:
+ case MON_DATA_SINNOH_RIBBON_36:
+ case MON_DATA_SINNOH_RIBBON_37:
+ case MON_DATA_SINNOH_RIBBON_38:
+ case MON_DATA_SINNOH_RIBBON_39:
+ case MON_DATA_SINNOH_RIBBON_40:
+ case MON_DATA_SINNOH_RIBBON_41:
+ case MON_DATA_SINNOH_RIBBON_42:
+ case MON_DATA_SINNOH_RIBBON_43:
+ case MON_DATA_SINNOH_RIBBON_44:
+ case MON_DATA_SINNOH_RIBBON_45:
+ case MON_DATA_SINNOH_RIBBON_46:
+ case MON_DATA_SINNOH_RIBBON_47:
+ case MON_DATA_SINNOH_RIBBON_48:
+ case MON_DATA_SINNOH_RIBBON_49:
+ case MON_DATA_SINNOH_RIBBON_50:
+ case MON_DATA_SINNOH_RIBBON_51:
+ case MON_DATA_SINNOH_RIBBON_52:
+ case MON_DATA_SINNOH_RIBBON_53:
+ flag = VALUE(u8);
+ mask = (u64)flag << (attr - MON_DATA_SINNOH_CHAMP_RIBBON);
+ if (flag)
+ blockA->sinnohRibbons |= mask;
+ else
+ blockA->sinnohRibbons &= -1ull ^ mask;
+ break;
+ case MON_DATA_MOVE1:
+ case MON_DATA_MOVE2:
+ case MON_DATA_MOVE3:
+ case MON_DATA_MOVE4:
+ blockB->moves[attr - MON_DATA_MOVE1] = VALUE(u16);
+ break;
+ case MON_DATA_MOVE1PP:
+ case MON_DATA_MOVE2PP:
+ case MON_DATA_MOVE3PP:
+ case MON_DATA_MOVE4PP:
+ blockB->movePP[attr - MON_DATA_MOVE1PP] = VALUE(u8);
+ break;
+ case MON_DATA_MOVE1PPUP:
+ case MON_DATA_MOVE2PPUP:
+ case MON_DATA_MOVE3PPUP:
+ case MON_DATA_MOVE4PPUP:
+ blockB->movePpUps[attr - MON_DATA_MOVE1PPUP] = VALUE(u8);
+ break;
+ case MON_DATA_HP_IV:
+ blockB->hpIV = VALUE(u8);
+ break;
+ case MON_DATA_ATK_IV:
+ blockB->atkIV = VALUE(u8);
+ break;
+ case MON_DATA_DEF_IV:
+ blockB->defIV = VALUE(u8);
+ break;
+ case MON_DATA_SPEED_IV:
+ blockB->spdIV = VALUE(u8);
+ break;
+ case MON_DATA_SPATK_IV:
+ blockB->spatkIV = VALUE(u8);
+ break;
+ case MON_DATA_SPDEF_IV:
+ blockB->spdefIV = VALUE(u8);
+ break;
+ case MON_DATA_IS_EGG:
+ blockB->isEgg = VALUE(u8);
+ break;
+ case MON_DATA_HAS_NICKNAME:
+ blockB->isNicknamed = VALUE(u8);
+ break;
+ case MON_DATA_COOL_RIBBON:
+ case MON_DATA_HOENN_RIBBON_79:
+ case MON_DATA_HOENN_RIBBON_80:
+ case MON_DATA_HOENN_RIBBON_81:
+ case MON_DATA_HOENN_RIBBON_82:
+ case MON_DATA_HOENN_RIBBON_83:
+ case MON_DATA_HOENN_RIBBON_84:
+ case MON_DATA_HOENN_RIBBON_85:
+ case MON_DATA_HOENN_RIBBON_86:
+ case MON_DATA_HOENN_RIBBON_87:
+ case MON_DATA_HOENN_RIBBON_88:
+ case MON_DATA_HOENN_RIBBON_89:
+ case MON_DATA_HOENN_RIBBON_90:
+ case MON_DATA_HOENN_RIBBON_91:
+ case MON_DATA_HOENN_RIBBON_92:
+ case MON_DATA_HOENN_RIBBON_93:
+ case MON_DATA_HOENN_RIBBON_94:
+ case MON_DATA_HOENN_RIBBON_95:
+ case MON_DATA_HOENN_RIBBON_96:
+ case MON_DATA_HOENN_RIBBON_97:
+ case MON_DATA_HOENN_RIBBON_98:
+ case MON_DATA_HOENN_RIBBON_99:
+ case MON_DATA_HOENN_RIBBON_100:
+ case MON_DATA_HOENN_RIBBON_101:
+ case MON_DATA_HOENN_RIBBON_102:
+ case MON_DATA_HOENN_RIBBON_103:
+ case MON_DATA_HOENN_RIBBON_104:
+ case MON_DATA_HOENN_RIBBON_105:
+ case MON_DATA_HOENN_RIBBON_106:
+ case MON_DATA_HOENN_RIBBON_107:
+ case MON_DATA_HOENN_RIBBON_108:
+ case MON_DATA_HOENN_RIBBON_109:
+ flag = VALUE(u8);
+ mask = (u64)flag << (attr - MON_DATA_COOL_RIBBON);
+ if (flag)
+ blockB->ribbonFlags |= mask;
+ else
+ blockB->ribbonFlags &= -1ull ^ mask;
+ break;
+ case MON_DATA_FATEFUL_ENCOUNTER:
+ blockB->fatefulEncounter = VALUE(u8);
+ break;
+ case MON_DATA_GENDER:
+ blockB->gender = VALUE(u8);
+ break;
+ case MON_DATA_FORME:
+ blockB->alternateForm = VALUE(u8);
+ break;
+ case MON_DATA_RESERVED_113:
+ blockB->HGSS_shinyLeaves = VALUE(u8);
+ break;
+ case MON_DATA_RESERVED_114:
+ blockB->Unused = VALUE(u16);
+ break;
+ case MON_DATA_NICKNAME_2:
+ GetSpeciesName(blockA->species, 0, namebuf);
+ blockB->isNicknamed = StringNotEqual(namebuf, value);
+ // fallthrough
+ case MON_DATA_NICKNAME:
+ for (i = 0; i < POKEMON_NAME_LENGTH + 1; i++)
+ {
+ blockC->nickname[i] = VALUE(u16); value = (void *const )((char *)value + 2);
+ }
+ break;
+ case MON_DATA_NICKNAME_4:
+ GetSpeciesName(blockA->species, 0, namebuf2);
+ FUN_02021EF0(value, namebuf3, POKEMON_NAME_LENGTH + 1);
+ blockB->isNicknamed = StringNotEqual(namebuf2, namebuf3);
+ // fallthrough
+ case MON_DATA_NICKNAME_3:
+ FUN_02021EF0(value, blockC->nickname, POKEMON_NAME_LENGTH + 1);
+ break;
+ case MON_DATA_UNK_120:
+ blockC->Unused = VALUE(u8);
+ break;
+ case MON_DATA_GAME_VERSION:
+ blockC->originGame = VALUE(u8);
+ break;
+ case MON_DATA_SINNOH_RIBBON_122:
+ case MON_DATA_SINNOH_RIBBON_123:
+ case MON_DATA_SINNOH_RIBBON_124:
+ case MON_DATA_SINNOH_RIBBON_125:
+ case MON_DATA_SINNOH_RIBBON_126:
+ case MON_DATA_SINNOH_RIBBON_127:
+ case MON_DATA_SINNOH_RIBBON_128:
+ case MON_DATA_SINNOH_RIBBON_129:
+ case MON_DATA_SINNOH_RIBBON_130:
+ case MON_DATA_SINNOH_RIBBON_131:
+ case MON_DATA_SINNOH_RIBBON_132:
+ case MON_DATA_SINNOH_RIBBON_133:
+ case MON_DATA_SINNOH_RIBBON_134:
+ case MON_DATA_SINNOH_RIBBON_135:
+ case MON_DATA_SINNOH_RIBBON_136:
+ case MON_DATA_SINNOH_RIBBON_137:
+ case MON_DATA_SINNOH_RIBBON_138:
+ case MON_DATA_SINNOH_RIBBON_139:
+ case MON_DATA_SINNOH_RIBBON_140:
+ case MON_DATA_SINNOH_RIBBON_141:
+ case MON_DATA_SINNOH_RIBBON_142:
+ flag = VALUE(u8);
+ mask = (u64)flag << (attr - MON_DATA_SINNOH_RIBBON_122);
+ if (flag)
+ blockC->sinnohRibbons2 |= mask;
+ else
+ blockC->sinnohRibbons2 &= -1ull ^ mask;
+ break;
+ case MON_DATA_OT_NAME:
+ for (i = 0; i < OT_NAME_LENGTH + 1; i++)
+ {
+ blockD->otTrainerName[i] = VALUE(u16); value = (void *)((char *)value + 2);
+ }
+ break;
+ case MON_DATA_OT_NAME_2:
+ FUN_02021EF0(value, blockD->otTrainerName, OT_NAME_LENGTH + 1);
+ break;
+ case MON_DATA_EGG_MET_YEAR:
+ blockD->dateEggReceived[0] = VALUE(u8);
+ break;
+ case MON_DATA_EGG_MET_MONTH:
+ blockD->dateEggReceived[1] = VALUE(u8);
+ break;
+ case MON_DATA_EGG_MET_DAY:
+ blockD->dateEggReceived[2] = VALUE(u8);
+ break;
+ case MON_DATA_MET_YEAR:
+ blockD->dateMet[0] = VALUE(u8);
+ break;
+ case MON_DATA_MET_MONTH:
+ blockD->dateMet[1] = VALUE(u8);
+ break;
+ case MON_DATA_MET_DAY:
+ blockD->dateMet[2] = VALUE(u8);
+ break;
+ case MON_DATA_EGG_MET_LOCATION:
+ blockD->DP_EggLocation = VALUE(u16);
+ break;
+ case MON_DATA_MET_LOCATION:
+ blockD->DP_MetLocation = VALUE(u16);
+ break;
+ case MON_DATA_POKERUS:
+ blockD->pokerus = VALUE(u8);
+ break;
+ case MON_DATA_POKEBALL:
+ blockD->pokeball = VALUE(u8);
+ break;
+ case MON_DATA_MET_LEVEL:
+ blockD->metLevel = VALUE(u8);
+ break;
+ case MON_DATA_MET_GENDER:
+ blockD->metGender = VALUE(u8);
+ break;
+ case MON_DATA_ENCOUNTER_TYPE:
+ blockD->encounterType = VALUE(u8);
+ break;
+ case MON_DATA_RESERVED_158:
+ blockD->HGSS_Pokeball = VALUE(u16);
+ break;
+ case MON_DATA_IVS_WORD:
+ blockB->hpIV = (VALUE(u32) >> 0) & 0x1F;
+ blockB->atkIV = (VALUE(u32) >> 5) & 0x1F;
+ blockB->defIV = (VALUE(u32) >> 10) & 0x1F;
+ blockB->spdIV = (VALUE(u32) >> 15) & 0x1F;
+ blockB->spatkIV = (VALUE(u32) >> 20) & 0x1F;
+ blockB->spdefIV = (VALUE(u32) >> 25) & 0x1F;
+ break;
+ case MON_DATA_SPECIES_NAME:
+ speciesName = FUN_0200AA50(blockA->species, 0);
+ FUN_02021EF0(speciesName, blockC->nickname, POKEMON_NAME_LENGTH + 1);
+ FUN_02021A20(speciesName);
+ break;
+ }
+#undef VALUE
+}
+
+void AddMonData(struct Pokemon * pokemon, int attr, int value)
+{
+ u16 checksum;
+ if (!pokemon->box.party_lock)
+ {
+ DECRYPT_PTY(pokemon);
+ DECRYPT_BOX(&pokemon->box);
+ checksum = CHECKSUM(&pokemon->box);
+ if (checksum != pokemon->box.checksum)
+ {
+ GF_ASSERT(checksum == pokemon->box.checksum);
+ ENCRYPT_BOX(&pokemon->box);
+ return;
+ }
+ }
+ AddMonDataInternal(pokemon, attr, value);
+ if (!pokemon->box.party_lock)
+ {
+ ENCRYPT_PTY(pokemon);
+ pokemon->box.checksum = CHECKSUM(&pokemon->box);
+ ENCRYPT_BOX(&pokemon->box);
+ }
+}
+
+void AddMonDataInternal(struct Pokemon * pokemon, int attr, int value)
+{
+ s32 maxHp;
+ switch (attr)
+ {
+ case MON_DATA_HP:
+ maxHp = pokemon->party.maxHp;
+ if ((s32)(pokemon->party.hp + value) > maxHp)
+ pokemon->party.hp = (u16)maxHp;
+ else
+ pokemon->party.hp += value;
+ break;
+ case MON_DATA_STATUS:
+ case MON_DATA_LEVEL:
+ case MON_DATA_CAPSULE:
+ case MON_DATA_MAXHP:
+ case MON_DATA_ATK:
+ case MON_DATA_DEF:
+ case MON_DATA_SPEED:
+ case MON_DATA_SPATK:
+ case MON_DATA_SPDEF:
+ case MON_DATA_SEAL_STRUCT:
+ // case MON_DATA_SEAL_COORDS:
+ GF_ASSERT(0);
+ break;
+ default:
+ AddBoxMonData(&pokemon->box, attr, value);
+ break;
+ }
+}
+
+void AddBoxMonData(struct BoxPokemon * boxmon, int attr, int value)
+{
+ PokemonDataBlockA *blockA = &GetSubstruct(boxmon, boxmon->pid, 0)->blockA;
+ PokemonDataBlockB *blockB = &GetSubstruct(boxmon, boxmon->pid, 1)->blockB;
+ PokemonDataBlockC *blockC = &GetSubstruct(boxmon, boxmon->pid, 2)->blockC;
+ PokemonDataBlockD *blockD = &GetSubstruct(boxmon, boxmon->pid, 3)->blockD;
+
+ switch (attr)
+ {
+ case MON_DATA_EXPERIENCE:
+ if (blockA->exp + value > GetMonExpBySpeciesAndLevel(blockA->species, 100))
+ blockA->exp = GetMonExpBySpeciesAndLevel(blockA->species, 100);
+ else
+ blockA->exp += value;
+ break;
+ case MON_DATA_FRIENDSHIP:
+ if (blockA->friendship + value > 255)
+ blockA->friendship = 255;
+ else
+ blockA->friendship += value;
+ break;
+ case MON_DATA_HP_EV:
+ blockA->hpEV += value;
+ break;
+ case MON_DATA_ATK_EV:
+ blockA->atkEV += value;
+ break;
+ case MON_DATA_DEF_EV:
+ blockA->defEV += value;
+ break;
+ case MON_DATA_SPEED_EV:
+ blockA->spdEV += value;
+ break;
+ case MON_DATA_SPATK_EV:
+ blockA->spatkEV += value;
+ break;
+ case MON_DATA_SPDEF_EV:
+ blockA->spdefEV += value;
+ break;
+ case MON_DATA_COOL:
+ if (blockA->coolStat + value > 255)
+ blockA->coolStat = 255;
+ else
+ blockA->coolStat += value;
+ break;
+ case MON_DATA_BEAUTY:
+ if (blockA->beautyStat + value > 255)
+ blockA->beautyStat = 255;
+ else
+ blockA->beautyStat += value;
+ break;
+ case MON_DATA_CUTE:
+ if (blockA->cuteStat + value > 255)
+ blockA->cuteStat = 255;
+ else
+ blockA->cuteStat += value;
+ break;
+ case MON_DATA_SMART:
+ if (blockA->smartStat + value > 255)
+ blockA->smartStat = 255;
+ else
+ blockA->smartStat += value;
+ break;
+ case MON_DATA_TOUGH:
+ if (blockA->toughStat + value > 255)
+ blockA->toughStat = 255;
+ else
+ blockA->toughStat += value;
+ break;
+ case MON_DATA_SHEEN:
+ if (blockA->sheen + value > 255)
+ blockA->sheen = 255;
+ else
+ blockA->sheen += value;
+ break;
+ case MON_DATA_MOVE1PP:
+ case MON_DATA_MOVE2PP:
+ case MON_DATA_MOVE3PP:
+ case MON_DATA_MOVE4PP:
+ if (blockB->movePP[attr - MON_DATA_MOVE1PP] + value > FUN_0206AB30(blockB->moves[attr - MON_DATA_MOVE1PP], blockB->movePpUps[attr - MON_DATA_MOVE1PP]))
+ blockB->movePP[attr - MON_DATA_MOVE1PP] = (u8)FUN_0206AB30(blockB->moves[attr - MON_DATA_MOVE1PP], blockB->movePpUps[attr - MON_DATA_MOVE1PP]);
+ else
+ blockB->movePP[attr - MON_DATA_MOVE1PP] += value;
+ break;
+ case MON_DATA_MOVE1PPUP:
+ case MON_DATA_MOVE2PPUP:
+ case MON_DATA_MOVE3PPUP:
+ case MON_DATA_MOVE4PPUP:
+ if (blockB->movePpUps[attr - MON_DATA_MOVE1PPUP] + value > 3)
+ blockB->movePpUps[attr - MON_DATA_MOVE1PPUP] = 3;
+ else
+ blockB->movePpUps[attr - MON_DATA_MOVE1PPUP] += value;
+ break;
+ case MON_DATA_MOVE1MAXPP:
+ case MON_DATA_MOVE2MAXPP:
+ case MON_DATA_MOVE3MAXPP:
+ case MON_DATA_MOVE4MAXPP:
+ break;
+ case MON_DATA_HP_IV:
+ if (blockB->hpIV + value > 31)
+ blockB->hpIV = 31;
+ else
+ blockB->hpIV += value;
+ break;
+ case MON_DATA_ATK_IV:
+ if (blockB->atkIV + value > 31)
+ blockB->atkIV = 31;
+ else
+ blockB->atkIV += value;
+ break;
+ case MON_DATA_DEF_IV:
+ if (blockB->defIV + value > 31)
+ blockB->defIV = 31;
+ else
+ blockB->defIV += value;
+ break;
+ case MON_DATA_SPEED_IV:
+ if (blockB->spdIV + value > 31)
+ blockB->spdIV = 31;
+ else
+ blockB->spdIV += value;
+ break;
+ case MON_DATA_SPATK_IV:
+ if (blockB->spatkIV + value > 31)
+ blockB->spatkIV = 31;
+ else
+ blockB->spatkIV += value;
+ break;
+ case MON_DATA_SPDEF_IV:
+ if (blockB->spdefIV + value > 31)
+ blockB->spdefIV = 31;
+ else
+ blockB->spdefIV += value;
+ break;
+ case MON_DATA_PERSONALITY:
+ case MON_DATA_PARTY_LOCK:
+ case MON_DATA_BOX_LOCK:
+ case MON_DATA_CHECKSUM_FAILED:
+ case MON_DATA_CHECKSUM:
+ case MON_DATA_SPECIES:
+ case MON_DATA_HELD_ITEM:
+ case MON_DATA_OTID:
+ case MON_DATA_ABILITY:
+ case MON_DATA_MARKINGS:
+ case MON_DATA_GAME_LANGUAGE:
+ case MON_DATA_SINNOH_CHAMP_RIBBON:
+ case MON_DATA_SINNOH_RIBBON_26:
+ case MON_DATA_SINNOH_RIBBON_27:
+ case MON_DATA_SINNOH_RIBBON_28:
+ case MON_DATA_SINNOH_RIBBON_29:
+ case MON_DATA_SINNOH_RIBBON_30:
+ case MON_DATA_SINNOH_RIBBON_31:
+ case MON_DATA_SINNOH_RIBBON_32:
+ case MON_DATA_SINNOH_RIBBON_33:
+ case MON_DATA_SINNOH_RIBBON_34:
+ case MON_DATA_SINNOH_RIBBON_35:
+ case MON_DATA_SINNOH_RIBBON_36:
+ case MON_DATA_SINNOH_RIBBON_37:
+ case MON_DATA_SINNOH_RIBBON_38:
+ case MON_DATA_SINNOH_RIBBON_39:
+ case MON_DATA_SINNOH_RIBBON_40:
+ case MON_DATA_SINNOH_RIBBON_41:
+ case MON_DATA_SINNOH_RIBBON_42:
+ case MON_DATA_SINNOH_RIBBON_43:
+ case MON_DATA_SINNOH_RIBBON_44:
+ case MON_DATA_SINNOH_RIBBON_45:
+ case MON_DATA_SINNOH_RIBBON_46:
+ case MON_DATA_SINNOH_RIBBON_47:
+ case MON_DATA_SINNOH_RIBBON_48:
+ case MON_DATA_SINNOH_RIBBON_49:
+ case MON_DATA_SINNOH_RIBBON_50:
+ case MON_DATA_SINNOH_RIBBON_51:
+ case MON_DATA_SINNOH_RIBBON_52:
+ case MON_DATA_SINNOH_RIBBON_53:
+ case MON_DATA_MOVE1:
+ case MON_DATA_MOVE2:
+ case MON_DATA_MOVE3:
+ case MON_DATA_MOVE4:
+ case MON_DATA_IS_EGG:
+ case MON_DATA_HAS_NICKNAME:
+ case MON_DATA_COOL_RIBBON:
+ case MON_DATA_HOENN_RIBBON_79:
+ case MON_DATA_HOENN_RIBBON_80:
+ case MON_DATA_HOENN_RIBBON_81:
+ case MON_DATA_HOENN_RIBBON_82:
+ case MON_DATA_HOENN_RIBBON_83:
+ case MON_DATA_HOENN_RIBBON_84:
+ case MON_DATA_HOENN_RIBBON_85:
+ case MON_DATA_HOENN_RIBBON_86:
+ case MON_DATA_HOENN_RIBBON_87:
+ case MON_DATA_HOENN_RIBBON_88:
+ case MON_DATA_HOENN_RIBBON_89:
+ case MON_DATA_HOENN_RIBBON_90:
+ case MON_DATA_HOENN_RIBBON_91:
+ case MON_DATA_HOENN_RIBBON_92:
+ case MON_DATA_HOENN_RIBBON_93:
+ case MON_DATA_HOENN_RIBBON_94:
+ case MON_DATA_HOENN_RIBBON_95:
+ case MON_DATA_HOENN_RIBBON_96:
+ case MON_DATA_HOENN_RIBBON_97:
+ case MON_DATA_HOENN_RIBBON_98:
+ case MON_DATA_HOENN_RIBBON_99:
+ case MON_DATA_HOENN_RIBBON_100:
+ case MON_DATA_HOENN_RIBBON_101:
+ case MON_DATA_HOENN_RIBBON_102:
+ case MON_DATA_HOENN_RIBBON_103:
+ case MON_DATA_HOENN_RIBBON_104:
+ case MON_DATA_HOENN_RIBBON_105:
+ case MON_DATA_HOENN_RIBBON_106:
+ case MON_DATA_HOENN_RIBBON_107:
+ case MON_DATA_HOENN_RIBBON_108:
+ case MON_DATA_HOENN_RIBBON_109:
+ case MON_DATA_FATEFUL_ENCOUNTER:
+ case MON_DATA_GENDER:
+ case MON_DATA_FORME:
+ case MON_DATA_RESERVED_113:
+ case MON_DATA_RESERVED_114:
+ case MON_DATA_UNUSED_115:
+ case MON_DATA_NICKNAME:
+ case MON_DATA_NICKNAME_2:
+ case MON_DATA_NICKNAME_3:
+ case MON_DATA_NICKNAME_4:
+ case MON_DATA_UNK_120:
+ case MON_DATA_GAME_VERSION:
+ case MON_DATA_SINNOH_RIBBON_122:
+ case MON_DATA_SINNOH_RIBBON_123:
+ case MON_DATA_SINNOH_RIBBON_124:
+ case MON_DATA_SINNOH_RIBBON_125:
+ case MON_DATA_SINNOH_RIBBON_126:
+ case MON_DATA_SINNOH_RIBBON_127:
+ case MON_DATA_SINNOH_RIBBON_128:
+ case MON_DATA_SINNOH_RIBBON_129:
+ case MON_DATA_SINNOH_RIBBON_130:
+ case MON_DATA_SINNOH_RIBBON_131:
+ case MON_DATA_SINNOH_RIBBON_132:
+ case MON_DATA_SINNOH_RIBBON_133:
+ case MON_DATA_SINNOH_RIBBON_134:
+ case MON_DATA_SINNOH_RIBBON_135:
+ case MON_DATA_SINNOH_RIBBON_136:
+ case MON_DATA_SINNOH_RIBBON_137:
+ case MON_DATA_SINNOH_RIBBON_138:
+ case MON_DATA_SINNOH_RIBBON_139:
+ case MON_DATA_SINNOH_RIBBON_140:
+ case MON_DATA_SINNOH_RIBBON_141:
+ case MON_DATA_SINNOH_RIBBON_142:
+ case MON_DATA_OT_NAME:
+ case MON_DATA_OT_NAME_2:
+ case MON_DATA_EGG_MET_YEAR:
+ case MON_DATA_EGG_MET_MONTH:
+ case MON_DATA_EGG_MET_DAY:
+ case MON_DATA_MET_YEAR:
+ case MON_DATA_MET_MONTH:
+ case MON_DATA_MET_DAY:
+ case MON_DATA_EGG_MET_LOCATION:
+ case MON_DATA_MET_LOCATION:
+ case MON_DATA_POKERUS:
+ case MON_DATA_POKEBALL:
+ case MON_DATA_MET_LEVEL:
+ case MON_DATA_MET_GENDER:
+ case MON_DATA_ENCOUNTER_TYPE:
+ case MON_DATA_RESERVED_158:
+ case MON_DATA_STATUS:
+ case MON_DATA_LEVEL:
+ case MON_DATA_CAPSULE:
+ case MON_DATA_HP:
+ case MON_DATA_MAXHP:
+ case MON_DATA_ATK:
+ case MON_DATA_DEF:
+ case MON_DATA_SPEED:
+ case MON_DATA_SPATK:
+ case MON_DATA_SPDEF:
+ case MON_DATA_SEAL_STRUCT:
+ case MON_DATA_SEAL_COORDS:
+ case MON_DATA_SPECIES_EXISTS:
+ case MON_DATA_SANITY_IS_EGG:
+ case MON_DATA_SPECIES2:
+ case MON_DATA_IVS_WORD:
+ case MON_DATA_UNK_175:
+ case MON_DATA_TYPE_1:
+ case MON_DATA_TYPE_2:
+ case MON_DATA_SPECIES_NAME:
+ default:
+ GF_ASSERT(0);
+ }
+}
+
+struct BaseStats * AllocAndLoadMonPersonal(int species, u32 heap_id)
+{
+ struct BaseStats * baseStats = (struct BaseStats *)AllocFromHeap(heap_id, sizeof(struct BaseStats));
+ LoadMonPersonal(species, baseStats);
+ return baseStats;
+}
+
+int GetPersonalAttr(struct BaseStats * baseStats, enum BaseStat attr)
+{
+ int ret;
+ GF_ASSERT(baseStats != NULL);
+ switch (attr)
+ {
+ case BASE_HP:
+ ret = baseStats->hp;
+ break;
+ case BASE_ATK:
+ ret = baseStats->atk;
+ break;
+ case BASE_DEF:
+ ret = baseStats->def;
+ break;
+ case BASE_SPEED:
+ ret = baseStats->speed;
+ break;
+ case BASE_SPATK:
+ ret = baseStats->spatk;
+ break;
+ case BASE_SPDEF:
+ ret = baseStats->spdef;
+ break;
+ case BASE_TYPE1:
+ ret = baseStats->types[0];
+ break;
+ case BASE_TYPE2:
+ ret = baseStats->types[1];
+ break;
+ case BASE_CATCH_RATE:
+ ret = baseStats->catchRate;
+ break;
+ case BASE_EXP_YIELD:
+ ret = baseStats->expYield;
+ break;
+ case BASE_HP_YIELD:
+ ret = baseStats->hp_yield;
+ break;
+ case BASE_ATK_YIELD:
+ ret = baseStats->atk_yield;
+ break;
+ case BASE_DEF_YIELD:
+ ret = baseStats->def_yield;
+ break;
+ case BASE_SPEED_YIELD:
+ ret = baseStats->speed_yield;
+ break;
+ case BASE_SPATK_YIELD:
+ ret = baseStats->spatk_yield;
+ break;
+ case BASE_SPDEF_YIELD:
+ ret = baseStats->spdef_yield;
+ break;
+ case BASE_ITEM_1:
+ ret = baseStats->item1;
+ break;
+ case BASE_ITEM_2:
+ ret = baseStats->item2;
+ break;
+ case BASE_GENDER_RATIO:
+ ret = baseStats->genderRatio;
+ break;
+ case BASE_EGG_CYCLES:
+ ret = baseStats->eggCycles;
+ break;
+ case BASE_FRIENDSHIP:
+ ret = baseStats->friendship;
+ break;
+ case BASE_GROWTH_RATE:
+ ret = baseStats->growthRate;
+ break;
+ case BASE_EGG_GROUP_1:
+ ret = baseStats->eggGroups[0];
+ break;
+ case GASE_EGG_GROUP_2:
+ ret = baseStats->eggGroups[1];
+ break;
+ case BASE_ABILITY_1:
+ ret = baseStats->abilities[0];
+ break;
+ case BASE_ABILITY_2:
+ ret = baseStats->abilities[1];
+ break;
+ case BASE_GREAT_MARSH_RATE:
+ ret = baseStats->greatMarshRate;
+ break;
+ case BASE_COLOR:
+ ret = baseStats->color;
+ break;
+ case BASE_FLIP:
+ ret = baseStats->flip;
+ break;
+ case BASE_UNKNOWN_29:
+ ret = (int)baseStats->unk1C;
+ break;
+ case BASE_UNKNOWN_30:
+ ret = (int)baseStats->unk20;
+ break;
+ case BASE_UNKNOWN_31:
+ ret = (int)baseStats->unk24;
+ break;
+ case BASE_UNKNOWN_32:
+ ret = (int)baseStats->unk28;
+ break;
+ }
+ return ret;
+}
+
+void FreeMonPersonal(struct BaseStats * personal)
+{
+ GF_ASSERT(personal != NULL);
+ FreeToHeap(personal);
+}
+
+int GetMonBaseStat_HandleFormeConversion(int species, int forme, enum BaseStat attr)
+{
+ int ret;
+ struct BaseStats * personal = AllocAndLoadMonPersonal(ResolveMonForme(species, forme), 0);
+ ret = GetPersonalAttr(personal, attr);
+ FreeMonPersonal(personal);
+ return ret;
+}
+
+int GetMonBaseStat(int species, enum BaseStat attr)
+{
+ int ret;
+ struct BaseStats * personal = AllocAndLoadMonPersonal(species, 0);
+ ret = GetPersonalAttr(personal, attr);
+ FreeMonPersonal(personal);
+ return ret;
+}
+
+u8 GetPercentProgressTowardsNextLevel(struct Pokemon * pokemon)
+{
+ BOOL decry = AcquireMonLock(pokemon);
+ u16 species = (u16)GetMonData(pokemon, MON_DATA_SPECIES, NULL);
+ u8 level = (u8)GetMonData(pokemon, MON_DATA_LEVEL, NULL);
+ u32 lo = GetMonExpBySpeciesAndLevel(species, level);
+ u32 hi = GetMonExpBySpeciesAndLevel(species, level + 1);
+ u32 cur = GetMonData(pokemon, MON_DATA_EXPERIENCE, NULL);
+ ReleaseMonLock(pokemon, decry);
+ return (u8)(100 * (cur - lo) / (hi - lo));
+}
+
+u32 CalcMonExpToNextLevel(struct Pokemon * pokemon)
+{
+ return CalcBoxMonExpToNextLevel(&pokemon->box);
+}
+
+u32 CalcBoxMonExpToNextLevel(struct BoxPokemon * boxmon)
+{
+ u16 species = (u16)GetBoxMonData(boxmon, MON_DATA_SPECIES, NULL);
+ u16 level = (u16)(CalcBoxMonLevel(boxmon) + 1);
+ u32 cur = GetBoxMonData(boxmon, MON_DATA_EXPERIENCE, NULL);
+ u32 hi = GetMonExpBySpeciesAndLevel(species, level);
+ return hi - cur;
+}
+
+u32 GetMonBaseExperienceAtCurrentLevel(struct Pokemon * pokemon)
+{
+ int species = (int)GetMonData(pokemon, MON_DATA_SPECIES, NULL);
+ int level = (int)GetMonData(pokemon, MON_DATA_LEVEL, NULL);
+ return GetMonExpBySpeciesAndLevel(species, level);
+}
+
+u32 GetMonExpBySpeciesAndLevel(int species, int level)
+{
+ return GetExpByGrowthRateAndLevel(GetMonBaseStat(species, BASE_GROWTH_RATE), level);
+}
+
+void LoadGrowthTable(int growthRate, u32 * dest)
+{
+ GF_ASSERT(growthRate < 8);
+ ReadWholeNarcMemberByIdPair(dest, NARC_POKETOOL_PERSONAL_GROWTBL, growthRate);
+}
+
+u32 GetExpByGrowthRateAndLevel(int growthRate, int level)
+{
+ u32 * table;
+ u32 ret;
+ GF_ASSERT(growthRate < 8);
+ GF_ASSERT(level <= 101);
+ table = (u32 *)AllocFromHeap(0, 101 * sizeof(u32));
+ LoadGrowthTable(growthRate, table);
+ ret = table[level];
+ FreeToHeap(table);
+ return ret;
+}
+
+int CalcMonLevel(struct Pokemon * pokemon)
+{
+ return CalcBoxMonLevel(&pokemon->box);
+}
+
+int CalcBoxMonLevel(struct BoxPokemon * boxmon)
+{
+ BOOL decry = AcquireBoxMonLock(boxmon);
+ int species = (int)GetBoxMonData(boxmon, MON_DATA_SPECIES, NULL);
+ int exp = (int)GetBoxMonData(boxmon, MON_DATA_EXPERIENCE, NULL);
+ ReleaseBoxMonLock(boxmon, decry);
+ return CalcLevelBySpeciesAndExp((u16)species, (u32)exp);
+}
+
+int CalcLevelBySpeciesAndExp(u16 species, u32 exp)
+{
+ int level;
+ struct BaseStats * personal = AllocAndLoadMonPersonal(species, 0);
+ level = CalcLevelBySpeciesAndExp_PreloadedPersonal(personal, species, exp);
+ FreeMonPersonal(personal);
+ return level;
+}
+
+int CalcLevelBySpeciesAndExp_PreloadedPersonal(struct BaseStats * personal, u16 species, u32 exp)
+{
+#pragma unused(species)
+ static u32 table[101];
+ int i;
+ LoadGrowthTable(GetPersonalAttr(personal, BASE_GROWTH_RATE), table);
+ for (i = 1; i < 101; i++)
+ {
+ if (table[i] > exp)
+ break;
+ }
+ return i - 1;
+}
+
+u8 GetMonNature(struct Pokemon * pokemon)
+{
+ return GetBoxMonNature(&pokemon->box);
+}
+
+u8 GetBoxMonNature(struct BoxPokemon * boxmon)
+{
+ BOOL decry = AcquireBoxMonLock(boxmon);
+ u32 personality = GetBoxMonData(boxmon, MON_DATA_PERSONALITY, NULL);
+ ReleaseBoxMonLock(boxmon, decry);
+ return GetNatureFromPersonality(personality);
+}
+
+u8 GetNatureFromPersonality(u32 pid)
+{
+ return (u8)(pid % 25);
+}
+
+u16 ModifyStatByNature(u8 nature, u16 n, u8 statIndex)
+{
+ u16 retVal;
+
+ // Dont modify HP, Accuracy, or Evasion by nature
+ if (statIndex < 1 || statIndex > 5)
+ return n;
+
+ switch (sNatureStatMods[nature][statIndex - 1])
+ {
+ case 1:
+ retVal = (u16)((u16)(n * 110) / 100); // NOTE: will overflow for n > 595 because the intermediate value is cast to u16 before the division. Fix by removing (u16) cast
+ break;
+ case -1:
+ retVal = (u16)((u16)(n * 90) / 100); // NOTE: will overflow for n > 728, see above
+ break;
+ default:
+ retVal = n;
+ break;
+ }
+ return retVal;
+}
+
+void MonApplyFriendshipMod(struct Pokemon * pokemon, u32 kind, u32 location)
+{
+ u16 species;
+ u8 effect;
+ u8 r4;
+ s16 friendship;
+ s8 mod;
+
+ if (kind == 5 && (rand_LC() & 1))
+ return;
+
+ species = (u16)GetMonData(pokemon, MON_DATA_SPECIES2, NULL);
+ if (species == SPECIES_NONE || species == SPECIES_EGG)
+ return;
+
+ effect = (u8)FUN_0206E7B8((u16)GetMonData(pokemon, MON_DATA_HELD_ITEM, NULL), 1, 0);
+ r4 = 0;
+ friendship = (s16)GetMonData(pokemon, MON_DATA_FRIENDSHIP, NULL);
+ if (friendship >= 100)
+ r4++;
+ if (friendship >= 200)
+ r4++;
+ mod = sFriendshipModTable[kind][r4];
+ if (mod > 0 && GetMonData(pokemon, MON_DATA_POKEBALL, NULL) == ITEM_LUXURY_BALL)
+ mod++;
+ if (mod > 0 && GetMonData(pokemon, MON_DATA_EGG_MET_LOCATION, NULL) == location)
+ mod++;
+ if (mod > 0 && effect == 52) // Soothe Bell effect?
+ mod = (s8)(mod * 150 / 100);
+ friendship += mod;
+ if (friendship < 0)
+ friendship = 0;
+ if (friendship > 255)
+ friendship = 255;
+ SetMonData(pokemon, MON_DATA_FRIENDSHIP, &friendship);
+}
+
+u8 GetMonGender(struct Pokemon * pokemon)
+{
+ return GetBoxMonGender(&pokemon->box);
+}
+
+u8 GetBoxMonGender(struct BoxPokemon * boxmon)
+{
+ BOOL decry = AcquireBoxMonLock(boxmon);
+ u16 species = (u16)GetBoxMonData(boxmon, MON_DATA_SPECIES, NULL);
+ u32 personality = GetBoxMonData(boxmon, MON_DATA_PERSONALITY, NULL);
+ ReleaseBoxMonLock(boxmon, decry);
+ return GetGenderBySpeciesAndPersonality(species, personality);
+}
+
+u8 GetGenderBySpeciesAndPersonality(u16 species, u32 pid)
+{
+ struct BaseStats * personal = AllocAndLoadMonPersonal(species, 0);
+ u8 gender = GetGenderBySpeciesAndPersonality_PreloadedPersonal(personal, species, pid);
+ FreeMonPersonal(personal);
+ return gender;
+}
+
+u8 GetGenderBySpeciesAndPersonality_PreloadedPersonal(struct BaseStats * personal, u16 species, u32 pid)
+{
+#pragma unused(species)
+ u8 ratio = (u8)GetPersonalAttr(personal, BASE_GENDER_RATIO);
+ switch (ratio)
+ {
+ case MON_RATIO_MALE:
+ return MON_MALE;
+ case MON_RATIO_FEMALE:
+ return MON_FEMALE;
+ case MON_RATIO_UNKNOWN:
+ return MON_GENDERLESS;
+ default:
+ if (ratio > (u8)pid)
+ return MON_FEMALE;
+ else
+ return MON_MALE;
+ }
+}
+
+u8 MonIsShiny(struct Pokemon * pokemon)
+{
+ return BoxMonIsShiny(&pokemon->box);
+}
+
+u8 BoxMonIsShiny(struct BoxPokemon * boxmon)
+{
+ u32 otid = GetBoxMonData(boxmon, MON_DATA_OTID, NULL);
+ u32 pid = GetBoxMonData(boxmon, MON_DATA_PERSONALITY, NULL);
+ return CalcShininessByOtIdAndPersonality(otid, pid);
+}
+
+u8 CalcShininessByOtIdAndPersonality(u32 otid, u32 pid)
+{
+ return SHINY_CHECK(otid, pid);
+}
+
+u32 GenerateShinyPersonality(u32 otid)
+{
+ int r4;
+ u16 r6;
+ u16 r5;
+ otid = (u32)((((otid & 0xFFFF0000) >> 16) ^ (otid & 0xFFFF)) >> 3u);
+ r6 = (u16)(rand_LC() & 7);
+ r5 = (u16)(rand_LC() & 7);
+ for (r4 = 0; r4 < 13; r4++)
+ {
+ if (MaskOfFlagNo(r4) & otid)
+ {
+ if (rand_LC() & 1)
+ r6 |= MaskOfFlagNo(r4 + 3);
+ else
+ r5 |= MaskOfFlagNo(r4 + 3);
+ }
+ else if (rand_LC() & 1)
+ {
+ r6 |= MaskOfFlagNo(r4 + 3);
+ r5 |= MaskOfFlagNo(r4 + 3);
+ }
+ }
+ return (u32)((r5 << 16) | r6);
+}
+
+void FUN_02068B68(struct SomeDrawPokemonStruct * spC, struct Pokemon * pokemon, u8 sp10)
+{
+ FUN_02068B70(spC, &pokemon->box, sp10);
+}
+
+void FUN_02068B70(struct SomeDrawPokemonStruct * spC, struct BoxPokemon * boxmon, u8 sp10)
+{
+ BOOL decry = AcquireBoxMonLock(boxmon);
+ u16 species = (u16)GetBoxMonData(boxmon, MON_DATA_SPECIES2, NULL);
+ u8 gender = GetBoxMonGender(boxmon);
+ u8 shiny = BoxMonIsShiny(boxmon);
+ u32 personality = GetBoxMonData(boxmon, MON_DATA_PERSONALITY, NULL);
+ u8 forme;
+ if (species == SPECIES_EGG)
+ {
+ if (GetBoxMonData(boxmon, MON_DATA_SPECIES, NULL) == SPECIES_MANAPHY)
+ forme = 1;
+ else
+ forme = 0;
+ }
+ else
+ forme = (u8)GetBoxMonData(boxmon, MON_DATA_FORME, NULL);
+ FUN_02068C00(spC, species, gender, sp10, shiny, forme, personality);
+ ReleaseBoxMonLock(boxmon, decry);
+}
+
+void FUN_02068C00(struct SomeDrawPokemonStruct * spC, int species, u8 gender, u8 sp10, u8 shiny, u8 forme, u32 personality)
+{
+ spC->unk6 = 0;
+ spC->unk8 = 0;
+ spC->unkC = 0;
+ switch (species)
+ {
+ case SPECIES_BURMY:
+ if (forme > 2)
+ forme = 0;
+ spC->unk0 = 0x75;
+ spC->unk2 = (u16)(sp10 / 2 + 0x48 + forme * 2);
+ spC->unk4 = (u16)(shiny + 0x92 + forme * 2);
+ break;
+ case SPECIES_WORMADAM:
+ if (forme > 2)
+ forme = 0;
+ spC->unk0 = 0x75;
+ spC->unk2 = (u16)(sp10 / 2 + 0x4E + forme * 2);
+ spC->unk4 = (u16)(shiny + 0x98 + forme * 2);
+ break;
+ case SPECIES_SHELLOS:
+ if (forme > 1)
+ forme = 0;
+ spC->unk0 = 0x75;
+ spC->unk2 = (u16)(sp10 + 0x54 + forme);
+ spC->unk4 = (u16)(shiny + 0x9E + forme * 2);
+ break;
+ case SPECIES_GASTRODON:
+ if (forme > 1)
+ forme = 0;
+ spC->unk0 = 0x75;
+ spC->unk2 = (u16)(sp10 + 0x58 + forme);
+ spC->unk4 = (u16)(shiny + 0xA2 + forme * 2);
+ break;
+ case SPECIES_CHERRIM:
+ if (forme > 1)
+ forme = 0;
+ spC->unk0 = 0x75;
+ spC->unk2 = (u16)(sp10 + 0x5C + forme);
+ spC->unk4 = (u16)(shiny * 2 + 0xA6 + forme);
+ break;
+ case SPECIES_ARCEUS:
+ if (forme > 17)
+ forme = 0;
+ spC->unk0 = 0x75;
+ spC->unk2 = (u16)(sp10 / 2 + 0x60 + forme * 2);
+ spC->unk4 = (u16)(shiny + 0xAA + forme * 2);
+ break;
+ case SPECIES_CASTFORM:
+ if (forme > 3)
+ forme = 0;
+ spC->unk0 = 0x75;
+ spC->unk2 = (u16)(sp10 * 2 + 0x40 + forme);
+ spC->unk4 = (u16)(shiny * 4 + 0x8A + forme);
+ break;
+ case SPECIES_DEOXYS:
+ if (forme > 3)
+ forme = 0;
+ spC->unk0 = 0x75;
+ spC->unk2 = (u16)(sp10 / 2 + forme * 2);
+ spC->unk4 = (u16)(shiny + 0x86);
+ break;
+ case SPECIES_UNOWN:
+ if (forme >= 28)
+ forme = 0;
+ spC->unk0 = 0x75;
+ spC->unk2 = (u16)(sp10 / 2 + 0x8 + forme * 2);
+ spC->unk4 = (u16)(shiny + 0x88);
+ break;
+ case SPECIES_EGG:
+ if (forme > 1)
+ forme = 0;
+ spC->unk0 = 0x75;
+ spC->unk2 = (u16)(0x84 + forme);
+ spC->unk4 = (u16)(0xCE + forme);
+ break;
+ case SPECIES_MANAPHY_EGG:
+ spC->unk0 = 0x75;
+ spC->unk2 = 0x84;
+ spC->unk4 = 0xCE;
+ break;
+ default:
+ spC->unk0 = 0x4;
+ spC->unk2 = (u16)(species * 6 + sp10 + (gender == MON_FEMALE ? 0 : 1));
+ spC->unk4 = (u16)(shiny + (species * 6 + 4));
+ if (species == SPECIES_SPINDA && sp10 == 2)
+ {
+ spC->unk6 = SPECIES_SPINDA;
+ spC->unk8 = 0;
+ spC->unkC = personality;
+ }
+ break;
+ }
+}
+
+u8 FUN_02068E14(struct Pokemon * pokemon, u32 a1)
+{
+ return FUN_02068E1C(&pokemon->box, a1);
+}
+
+u8 FUN_02068E1C(struct BoxPokemon * boxmon, u32 a1)
+{
+ u16 species = (u16)GetBoxMonData(boxmon, MON_DATA_SPECIES2, NULL);
+ u8 gender = GetBoxMonGender(boxmon);
+ u32 pid = GetBoxMonData(boxmon, MON_DATA_PERSONALITY, NULL);
+ u8 forme;
+ if (species == SPECIES_EGG)
+ {
+ if (GetBoxMonData(boxmon, MON_DATA_SPECIES, NULL) == SPECIES_MANAPHY)
+ forme = 1;
+ else
+ forme = 0;
+ }
+ else
+ forme = (u8)GetBoxMonData(boxmon, MON_DATA_FORME, NULL);
+ return FUN_02068E88(species, gender, a1, forme, pid);
+}
+
+u8 FUN_02068E88(int species, u8 gender, u32 a1, u8 forme, u32 pid)
+{
+#pragma unused(pid)
+ u8 ret;
+ s32 fileId;
+ enum NarcId narc;
+ switch (species)
+ {
+ case SPECIES_BURMY:
+ if (forme > 2)
+ forme = 0;
+ narc = NARC_POKETOOL_POKEGRA_HEIGHT_O;
+ fileId = (s32)(a1 / 2 + 0x48 + forme * 2);
+ break;
+ case SPECIES_WORMADAM:
+ if (forme > 2)
+ forme = 0;
+ narc = NARC_POKETOOL_POKEGRA_HEIGHT_O;
+ fileId = (s32)(a1 / 2 + 0x4E + forme * 2);
+ break;
+ case SPECIES_SHELLOS:
+ if (forme > 1)
+ forme = 0;
+ narc = NARC_POKETOOL_POKEGRA_HEIGHT_O;
+ fileId = (s32)(a1 + 0x54 + forme);
+ break;
+ case SPECIES_GASTRODON:
+ if (forme > 1)
+ forme = 0;
+ narc = NARC_POKETOOL_POKEGRA_HEIGHT_O;
+ fileId = (s32)(a1 + 0x58 + forme);
+ break;
+ case SPECIES_CHERRIM:
+ if (forme > 1)
+ forme = 0;
+ narc = NARC_POKETOOL_POKEGRA_HEIGHT_O;
+ fileId = (s32)(a1 + 0x5C + forme);
+ break;
+ case SPECIES_ARCEUS:
+ if (forme > 17)
+ forme = 0;
+ narc = NARC_POKETOOL_POKEGRA_HEIGHT_O;
+ fileId = (s32)(a1 / 2 + 0x60 + 2 * forme);
+ break;
+ case SPECIES_CASTFORM:
+ if (forme > 3)
+ forme = 0;
+ narc = NARC_POKETOOL_POKEGRA_HEIGHT_O;
+ fileId = (s32)(a1 * 2 + 0x40 + forme);
+ break;
+ case SPECIES_DEOXYS:
+ if (forme > 3)
+ forme = 0;
+ narc = NARC_POKETOOL_POKEGRA_HEIGHT_O;
+ fileId = (s32)(a1 / 2 + forme * 2);
+ break;
+ case SPECIES_UNOWN:
+ if (forme >= 28)
+ forme = 0;
+ narc = NARC_POKETOOL_POKEGRA_HEIGHT_O;
+ fileId = (s32)(a1 / 2 + 0x8 + forme * 2);
+ break;
+ case SPECIES_EGG:
+ if (forme > 1)
+ forme = 0;
+ narc = NARC_POKETOOL_POKEGRA_HEIGHT_O;
+ fileId = (s32)(0x84 + forme);
+ break;
+ case SPECIES_MANAPHY_EGG:
+ narc = NARC_POKETOOL_POKEGRA_HEIGHT_O;
+ fileId = 0x84;
+ break;
+ default:
+ narc = NARC_POKETOOL_POKEGRA_HEIGHT;
+ fileId = (s32)(4 * species + a1 + (gender != MON_FEMALE ? 1 : 0));
+ break;
+ }
+ ReadWholeNarcMemberByIdPair(&ret, narc, fileId);
+ return ret;
+}
+
+void FUN_02068FE0(struct SomeDrawPokemonStruct * a0, u16 a1, int a2)
+{
+ if (a2 == 2)
+ a0->unk0 = 60;
+ else
+ {
+ a0->unk0 = 6;
+ a1 = (u16)FUN_0206AA30(a1);
+ }
+ a0->unk2 = (u16)(a1 * 2);
+ a0->unk4 = (u16)(a1 * 2 + 1);
+ a0->unk6 = 0;
+ a0->unk8 = 0;
+ a0->unkC = 0;
+}
+
+void FUN_02069010(void * dest, int a1)
+{
+ struct Pokeanm buffer;
+ ReadFromNarcMemberByIdPair(&buffer, NARC_POKETOOL_POKEANM_POKEANM, 0, (u32)(28 * a1), 28);
+ MI_CpuCopy8(buffer.unk8, dest, 20);
+}
+
+void FUN_02069038(u32 a0, u32 a1, u32 a2, s32 a3, u32 a4, u32 a5, u32 a6)
+{
+ struct UnkStruct_02069038 sp4;
+ ReadFromNarcMemberByIdPair(&sp4.anim, NARC_POKETOOL_POKEANM_POKEANM, 0, (u32)(a2 * 28), 28);
+ if (a3 == 2)
+ {
+ sp4.unk0 = sp4.anim.unk0[0].unk0;
+ sp4.unk2 = sp4.anim.unk0[0].unk1;
+ sp4.unk4 = (u8)a5;
+ }
+ else
+ {
+ a3 = FUN_02014C3C((u8)a4);
+ GF_ASSERT(a3 < 3);
+ sp4.unk0 = sp4.anim.unk0[a3 + 1].unk0;
+ sp4.unk2 = sp4.anim.unk0[a3 + 1].unk1;
+ sp4.unk4 = (u8)a5;
+ }
+ FUN_02014C54((int)a0, (int)a1, &sp4, (u8)a6);
+}
+
+void FUN_020690AC(struct SomeDrawPokemonStruct * a0, u32 a1)
+{
+ a0->unk0 = 60;
+ a0->unk2 = (u16)(a1 * 2);
+ a0->unk4 = (u16)(a1 * 2 + 1);
+ a0->unk6 = 0;
+ a0->unk8 = 0;
+ a0->unkC = 0;
+}
+
+u32 FUN_020690C4(void)
+{
+ return sizeof(struct Pokemon);
+}
+
+u32 FUN_020690C8(void)
+{
+ return sizeof(struct BoxPokemon);
+}
+
+u8 FUN_020690CC(struct Pokemon * pokemon)
+{
+ return FUN_020690D4(&pokemon->box);
+}
+
+u8 FUN_020690D4(struct BoxPokemon * boxmon)
+{
+ return (u8)GetBoxMonData(boxmon, MON_DATA_FORME, NULL);
+}
+
+struct BoxPokemon * FUN_020690E4(struct Pokemon * pokemon)
+{
+ return &pokemon->box;
+}
+
+BOOL FUN_020690E8(struct Pokemon * pokemon)
+{
+ u16 species = (u16)GetMonData(pokemon, MON_DATA_SPECIES, NULL);
+ u8 level = (u8)(GetMonData(pokemon, MON_DATA_LEVEL, NULL) + 1);
+ u32 exp = GetMonData(pokemon, MON_DATA_EXPERIENCE, NULL);
+ u32 growthrate = (u32)GetMonBaseStat(species, BASE_GROWTH_RATE);
+ u32 maxexp = GetExpByGrowthRateAndLevel((int)growthrate, 100);
+ if (exp > maxexp)
+ {
+ exp = maxexp;
+ SetMonData(pokemon, MON_DATA_EXPERIENCE, &exp);
+ }
+ if (level > 100)
+ return FALSE;
+ if (exp >= GetExpByGrowthRateAndLevel((int)growthrate, level))
+ {
+ SetMonData(pokemon, MON_DATA_LEVEL, &level);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+u16 GetMonEvolution(struct PlayerParty * party, struct Pokemon * pokemon, u32 context, u32 usedItem, u32 * method_ret)
+{
+ u16 target = SPECIES_NONE;
+ u32 sp40;
+ u16 species;
+ u16 heldItem;
+ u32 personality;
+ int i;
+ u8 beauty;
+ u8 level;
+ u16 friendship;
+ u16 pid_hi;
+ struct Evolution * evoTable;
+ u8 r1;
+
+ species = (u16)GetMonData(pokemon, MON_DATA_SPECIES, NULL);
+ heldItem = (u16)GetMonData(pokemon, MON_DATA_HELD_ITEM, NULL);
+ personality = GetMonData(pokemon, MON_DATA_PERSONALITY, NULL);
+ beauty = (u8)GetMonData(pokemon, MON_DATA_BEAUTY, NULL);
+ pid_hi = (u16)((personality & 0xFFFF0000) >> 16);
+ r1 = (u8)FUN_0206E7B8(heldItem, 1, 0);
+ if (species != SPECIES_KADABRA && r1 == 0x3F && context != 3)
+ return SPECIES_NONE;
+ if (method_ret == NULL)
+ method_ret = &sp40;
+ evoTable = AllocFromHeap(0, 7 * sizeof(struct Evolution));
+ LoadMonEvolutionTable(species, evoTable);
+ switch (context)
+ {
+ case 0:
+ level = (u8)GetMonData(pokemon, MON_DATA_LEVEL, NULL);
+ friendship = (u16)GetMonData(pokemon, MON_DATA_FRIENDSHIP, NULL);
+ for (i = 0; i < 7; i++)
+ {
+ switch (evoTable[i].method)
+ {
+ case EVO_NONE:
+ break;
+ case EVO_FRIENDSHIP:
+ if (friendship >= 220)
+ {
+ target = evoTable[i].target;
+ *method_ret = EVO_FRIENDSHIP;
+ }
+ break;
+ case EVO_FRIENDSHIP_DAY:
+ if (IsNighttime() == 0 && friendship >= 220)
+ {
+ target = evoTable[i].target;
+ *method_ret = EVO_FRIENDSHIP_DAY;
+ }
+ break;
+ case EVO_FRIENDSHIP_NIGHT:
+ if (IsNighttime() == 1 && friendship >= 220)
+ {
+ target = evoTable[i].target;
+ *method_ret = EVO_FRIENDSHIP_NIGHT;
+ }
+ break;
+ case EVO_LEVEL:
+ if (evoTable[i].param <= level)
+ {
+ target = evoTable[i].target;
+ *method_ret = EVO_LEVEL;
+ }
+ break;
+ case EVO_TRADE:
+ break;
+ case EVO_TRADE_ITEM:
+ break;
+ case EVO_STONE:
+ break;
+ case EVO_LEVEL_ATK_GT_DEF:
+ if (evoTable[i].param <= level && GetMonData(pokemon, MON_DATA_ATK, NULL) > GetMonData(pokemon, MON_DATA_DEF, NULL))
+ {
+ target = evoTable[i].target;
+ *method_ret = EVO_LEVEL_ATK_GT_DEF;
+ }
+ break;
+ case EVO_LEVEL_ATK_EQ_DEF:
+ if (evoTable[i].param <= level && GetMonData(pokemon, MON_DATA_ATK, NULL) == GetMonData(pokemon, MON_DATA_DEF, NULL))
+ {
+ target = evoTable[i].target;
+ *method_ret = EVO_LEVEL_ATK_EQ_DEF;
+ }
+ break;
+ case EVO_LEVEL_ATK_LT_DEF:
+ if (evoTable[i].param <= level && GetMonData(pokemon, MON_DATA_ATK, NULL) < GetMonData(pokemon, MON_DATA_DEF, NULL))
+ {
+ target = evoTable[i].target;
+ *method_ret = EVO_LEVEL_ATK_LT_DEF;
+ }
+ break;
+ case EVO_LEVEL_PID_LO:
+ if (evoTable[i].param <= level && pid_hi % 10 < 5)
+ {
+ target = evoTable[i].target;
+ *method_ret = EVO_LEVEL_PID_LO;
+ }
+ break;
+ case EVO_LEVEL_PID_HI:
+ if (evoTable[i].param <= level && pid_hi % 10 >= 5)
+ {
+ target = evoTable[i].target;
+ *method_ret = EVO_LEVEL_PID_HI;
+ }
+ break;
+ case EVO_LEVEL_NINJASK:
+ if (evoTable[i].param <= level)
+ {
+ target = evoTable[i].target;
+ *method_ret = EVO_LEVEL_NINJASK;
+ }
+ break;
+ case EVO_LEVEL_SHEDINJA:
+ *method_ret = EVO_LEVEL_SHEDINJA;
+ break;
+ case EVO_BEAUTY:
+ if (evoTable[i].param <= beauty)
+ {
+ target = evoTable[i].target;
+ *method_ret = EVO_BEAUTY;
+ }
+ break;
+ case EVO_STONE_MALE:
+ break;
+ case EVO_STONE_FEMALE:
+ break;
+ case EVO_ITEM_DAY:
+ if (IsNighttime() == 0 && evoTable[i].param == heldItem)
+ {
+ target = evoTable[i].target;
+ *method_ret = EVO_ITEM_DAY;
+ }
+ break;
+ case EVO_ITEM_NIGHT:
+ if (IsNighttime() == 1 && evoTable[i].param == heldItem)
+ {
+ target = evoTable[i].target;
+ *method_ret = EVO_ITEM_NIGHT;
+ }
+ break;
+ case EVO_HAS_MOVE:
+ if (MonHasMove(pokemon, evoTable[i].param) == TRUE)
+ {
+ target = evoTable[i].target;
+ *method_ret = EVO_HAS_MOVE;
+ }
+ break;
+ case EVO_OTHER_PARTY_MON:
+ if (party != NULL && PartyHasMon(party, evoTable[i].param) == 1)
+ {
+ target = evoTable[i].target;
+ *method_ret = EVO_OTHER_PARTY_MON;
+ }
+ break;
+ case EVO_LEVEL_MALE:
+ if (GetMonData(pokemon, MON_DATA_GENDER, NULL) == MON_MALE && evoTable[i].param <= level)
+ {
+ target = evoTable[i].target;
+ *method_ret = EVO_LEVEL_MALE;
+ }
+ break;
+ case EVO_LEVEL_FEMALE:
+ if (GetMonData(pokemon, MON_DATA_GENDER, NULL) == MON_FEMALE && evoTable[i].param <= level)
+ {
+ target = evoTable[i].target;
+ *method_ret = EVO_LEVEL_FEMALE;
+ }
+ break;
+ case EVO_CORONET:
+ if (usedItem == evoTable[i].method)
+ {
+ target = evoTable[i].target;
+ *method_ret = EVO_CORONET;
+ }
+ break;
+ case EVO_ETERNA:
+ if (usedItem == evoTable[i].method)
+ {
+ target = evoTable[i].target;
+ *method_ret = EVO_ETERNA;
+ }
+ break;
+ case EVO_ROUTE217:
+ if (usedItem == evoTable[i].method)
+ {
+ target = evoTable[i].target;
+ *method_ret = EVO_ROUTE217;
+ }
+ break;
+ }
+ if (target != SPECIES_NONE)
+ break;
+ }
+ break;
+ case 1:
+ for (i = 0; i < 7; i++)
+ {
+ switch (evoTable[i].method)
+ {
+ case EVO_TRADE:
+ target = evoTable[i].target;
+ *method_ret = EVO_TRADE;
+ break;
+ case EVO_TRADE_ITEM:
+ if (heldItem == evoTable[i].param)
+ {
+ target = evoTable[i].target;
+ *method_ret = EVO_TRADE_ITEM;
+ }
+ break;
+ }
+ if (target != SPECIES_NONE)
+ break;
+ }
+ break;
+ case 2:
+ case 3:
+ for (i = 0; i < 7; i++)
+ {
+ if (evoTable[i].method == EVO_STONE && usedItem == evoTable[i].param)
+ {
+ target = evoTable[i].target;
+ *method_ret = 0;
+ break;
+ }
+ if (evoTable[i].method == EVO_STONE_MALE && GetMonData(pokemon, MON_DATA_GENDER, NULL) == MON_MALE && usedItem == evoTable[i].param)
+ {
+ target = evoTable[i].target;
+ *method_ret = 0;
+ break;
+ }
+ if (evoTable[i].method == EVO_STONE_FEMALE && GetMonData(pokemon, MON_DATA_GENDER, NULL) == MON_FEMALE && usedItem == evoTable[i].param)
+ {
+ target = evoTable[i].target;
+ *method_ret = 0;
+ break;
+ }
+ }
+ break;
+ }
+ FreeToHeap(evoTable);
+ return target;
+}
+
+u16 ReadFromPersonalPmsNarc(u16 species)
+{
+ u16 ret = SPECIES_NONE;
+ GF_ASSERT(species < SPECIES_EGG);
+ {
+ FSFile file;
+ FS_InitFile(&file);
+ FS_OpenFile(&file, "poketool/personal/pms.narc");
+ FS_SeekFile(&file, (s32)(species * sizeof(u16)), FS_SEEK_SET);
+ FS_ReadFile(&file, &ret, sizeof(u16));
+ FS_CloseFile(&file);
+ }
+ return ret;
+}
+
+u16 GetEggSpecies(u16 species)
+{
+ switch (species)
+ {
+ case SPECIES_SUDOWOODO:
+ case SPECIES_MARILL:
+ case SPECIES_MR_MIME:
+ case SPECIES_CHANSEY:
+ case SPECIES_SNORLAX:
+ case SPECIES_MANTINE:
+ case SPECIES_WOBBUFFET:
+ case SPECIES_ROSELIA:
+ case SPECIES_CHIMECHO:
+ return species;
+ default:
+ return ReadFromPersonalPmsNarc(species);
+ }
+}
+
+#define WOTBL_END 0xFFFF
+#define WOTBL_MOVE_MASK 0x01FF
+#define WOTBL_MOVE_SHIFT 0
+#define WOTBL_LVL_MASK 0xFE00
+#define WOTBL_LVL_SHIFT 9
+#define WOTBL_MOVE(x) ((u16)(((x) & WOTBL_MOVE_MASK) >> WOTBL_MOVE_SHIFT))
+#define WOTBL_LVL(x) ((u8)(((x) & WOTBL_LVL_MASK) >> WOTBL_LVL_SHIFT))
+
+void InitBoxMonMoveset(struct BoxPokemon * boxmon)
+{
+ BOOL decry;
+ u16 * wotbl;
+ int i;
+ u16 species;
+ u32 forme;
+ u8 level;
+ u16 move;
+ wotbl = AllocFromHeap(0, 22 * sizeof(u16));
+ decry = AcquireBoxMonLock(boxmon);
+ species = (u16)GetBoxMonData(boxmon, MON_DATA_SPECIES, NULL);
+ forme = GetBoxMonData(boxmon, MON_DATA_FORME, NULL);
+ level = (u8)CalcBoxMonLevel(boxmon);
+ LoadWotbl_HandleAlternateForme(species, (int)forme, wotbl);
+ for (i = 0; wotbl[i] != WOTBL_END; i++)
+ {
+ if ((wotbl[i] & WOTBL_LVL_MASK) > (level << WOTBL_LVL_SHIFT))
+ break;
+ move = WOTBL_MOVE(wotbl[i]);
+ if (FUN_020696A8(boxmon, move) == 0xFFFF)
+ FUN_02069718(boxmon, move);
+ }
+ FreeToHeap(wotbl);
+ ReleaseBoxMonLock(boxmon, decry);
+}
+
+u32 FUN_02069698(struct Pokemon * pokemon, u16 move)
+{
+ return FUN_020696A8(FUN_020690E4(pokemon), move);
+}
+
+u32 FUN_020696A8(struct BoxPokemon * boxmon, u16 move)
+{
+ u32 ret = 0xFFFF;
+ int i;
+ BOOL decry = AcquireBoxMonLock(boxmon);
+ u16 cur_move;
+ for (i = 0; i < 4; i++)
+ {
+ cur_move = (u16)GetBoxMonData(boxmon, MON_DATA_MOVE1 + i, NULL);
+ if (cur_move == MOVE_NONE)
+ {
+ FUN_020697D4(boxmon, move, (u8)i);
+ ret = move;
+ break;
+ }
+ if (cur_move == move)
+ {
+ ret = 0xFFFE;
+ break;
+ }
+ }
+ ReleaseBoxMonLock(boxmon, decry);
+ return ret;
+}
+
+void FUN_02069708(struct Pokemon * pokemon, u16 move)
+{
+ FUN_02069718(FUN_020690E4(pokemon), move);
+}
+
+void FUN_02069718(struct BoxPokemon * boxmon, u16 move)
+{
+ BOOL decry = AcquireBoxMonLock(boxmon);
+ int i;
+ u16 moves[4];
+ u8 pp[4];
+ u8 ppUp[4];
+
+ for (i = 0; i < 3; i++)
+ {
+ moves[i] = (u16)GetBoxMonData(boxmon, MON_DATA_MOVE1 + i + 1, NULL);
+ pp[i] = (u8)GetBoxMonData(boxmon, MON_DATA_MOVE1PP + i + 1, NULL);
+ ppUp[i] = (u8)GetBoxMonData(boxmon, MON_DATA_MOVE1PPUP + i + 1, NULL);
+ }
+
+ moves[3] = move;
+ pp[3] = (u8)FUN_0206AB18(move, 5);
+ ppUp[3] = 0;
+
+ for (i = 0; i < 4; i++)
+ {
+ SetBoxMonData(boxmon, MON_DATA_MOVE1 + i, &moves[i]);
+ SetBoxMonData(boxmon, MON_DATA_MOVE1PP + i, &pp[i]);
+ SetBoxMonData(boxmon, MON_DATA_MOVE1PPUP + i, &ppUp[i]);
+ }
+
+ ReleaseBoxMonLock(boxmon, decry);
+}
+
+void FUN_020697CC(struct Pokemon * pokemon, u16 move, u8 slot)
+{
+ FUN_020697D4(&pokemon->box, move, slot);
+}
+
+void FUN_020697D4(struct BoxPokemon * boxmon, u16 move, u8 slot)
+{
+ u8 ppUp;
+ u8 pp;
+
+ SetBoxMonData(boxmon, MON_DATA_MOVE1 + slot, &move);
+ ppUp = (u8)GetBoxMonData(boxmon, MON_DATA_MOVE1PPUP + slot, NULL);
+ pp = (u8)FUN_0206AB30(move, ppUp);
+ SetBoxMonData(boxmon, MON_DATA_MOVE1PP + slot, &pp);
+}
+
+u32 FUN_02069818(struct Pokemon * pokemon, u32 * r5, u16 * sp0)
+{
+ u32 ret = 0;
+ u16 * wotbl = AllocFromHeap(0, 22 * sizeof(u16));
+ u16 species = (u16)GetMonData(pokemon, MON_DATA_SPECIES, NULL);
+ u32 forme = GetMonData(pokemon, MON_DATA_FORME, NULL);
+ u8 level = (u8)GetMonData(pokemon, MON_DATA_LEVEL, NULL);
+ LoadWotbl_HandleAlternateForme(species, (int)forme, wotbl);
+
+
+ if (wotbl[*r5] == 0xFFFF)
+ {
+ FreeToHeap(wotbl);
+ return 0;
+ }
+ while ((wotbl[*r5] & WOTBL_LVL_MASK) != (level << WOTBL_LVL_SHIFT))
+ {
+ (*r5)++;
+ if (wotbl[*r5] == 0xFFFF)
+ {
+ FreeToHeap(wotbl);
+ return 0;
+ }
+ }
+ if ((wotbl[*r5] & WOTBL_LVL_MASK) == (level << WOTBL_LVL_SHIFT))
+ {
+ *sp0 = WOTBL_MOVE(wotbl[*r5]);
+ (*r5)++;
+ ret = FUN_02069698(pokemon, *sp0);
+ }
+ FreeToHeap(wotbl);
+ return ret;
+}
+
+void FUN_020698E0(struct Pokemon * pokemon, int slot1, int slot2)
+{
+ FUN_020698E8(&pokemon->box, slot1, slot2);
+}
+
+void FUN_020698E8(struct BoxPokemon * boxmon, int slot1, int slot2)
+{
+ u16 moves[2];
+ u8 pp[2];
+ u8 ppUp[2];
+
+ moves[0] = (u16)GetBoxMonData(boxmon, MON_DATA_MOVE1 + slot1, NULL);
+ pp[0] = (u8)GetBoxMonData(boxmon, MON_DATA_MOVE1PP + slot1, NULL);
+ ppUp[0] = (u8)GetBoxMonData(boxmon, MON_DATA_MOVE1PPUP + slot1, NULL);
+ moves[1] = (u16)GetBoxMonData(boxmon, MON_DATA_MOVE1 + slot2, NULL);
+ pp[1] = (u8)GetBoxMonData(boxmon, MON_DATA_MOVE1PP + slot2, NULL);
+ ppUp[1] = (u8)GetBoxMonData(boxmon, MON_DATA_MOVE1PPUP + slot2, NULL);
+
+ SetBoxMonData(boxmon, MON_DATA_MOVE1 + slot1, &moves[1]);
+ SetBoxMonData(boxmon, MON_DATA_MOVE1PP + slot1, &pp[1]);
+ SetBoxMonData(boxmon, MON_DATA_MOVE1PPUP + slot1, &ppUp[1]);
+ SetBoxMonData(boxmon, MON_DATA_MOVE1 + slot2, &moves[0]);
+ SetBoxMonData(boxmon, MON_DATA_MOVE1PP + slot2, &pp[0]);
+ SetBoxMonData(boxmon, MON_DATA_MOVE1PPUP + slot2, &ppUp[0]);
+}
+
+void FUN_020699A4(struct Pokemon * pokemon, u32 slot)
+{
+ u16 move;
+ u8 pp;
+ u8 ppUp;
+ for (; slot < 3; slot++)
+ {
+ move = (u16)GetMonData(pokemon, (int)(MON_DATA_MOVE1 + slot + 1), NULL);
+ pp = (u8)GetMonData(pokemon, (int)(MON_DATA_MOVE1PP + slot + 1), NULL);
+ ppUp = (u8)GetMonData(pokemon, (int)(MON_DATA_MOVE1PPUP + slot + 1), NULL);
+ SetMonData(pokemon, (int)(MON_DATA_MOVE1 + slot), &move);
+ SetMonData(pokemon, (int)(MON_DATA_MOVE1PP + slot), &pp);
+ SetMonData(pokemon, (int)(MON_DATA_MOVE1PPUP + slot), &ppUp);
+ }
+ move = MOVE_NONE;
+ pp = 0;
+ ppUp = 0;
+ SetMonData(pokemon, MON_DATA_MOVE1 + 3, &move);
+ SetMonData(pokemon, MON_DATA_MOVE1PP + 3, &pp);
+ SetMonData(pokemon, MON_DATA_MOVE1PPUP + 3, &ppUp);
+}
+
+BOOL MonHasMove(struct Pokemon * pokemon, u16 move)
+{
+ int i;
+ for (i = 0; i < 4; i++)
+ {
+ if (GetMonData(pokemon, MON_DATA_MOVE1 + i, NULL) == move)
+ break;
+ }
+ if (i != 4)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+void FUN_02069A64(struct BoxPokemon * src, struct Pokemon * dest)
+{
+ u32 sp0 = 0;
+ u8 sp4[12][2];
+ struct SealStruct * seals;
+ dest->box = *src;
+ if (dest->box.box_lock)
+ dest->box.party_lock = TRUE;
+ SetMonData(dest, MON_DATA_STATUS, &sp0);
+ SetMonData(dest, MON_DATA_HP, &sp0);
+ SetMonData(dest, MON_DATA_MAXHP, &sp0);
+ seals = CreateNewSealsObject(0);
+ SetMonData(dest, MON_DATA_SEAL_STRUCT, seals);
+ FreeToHeap(seals);
+ SetMonData(dest, MON_DATA_CAPSULE, &sp0);
+ MIi_CpuClearFast(0, sp4, sizeof(sp4));
+ SetMonData(dest, MON_DATA_SEAL_COORDS, sp4);
+ CalcMonLevelAndStats(dest);
+}
+
+u8 FUN_02069AEC(struct PlayerParty * party)
+{
+ int i;
+ int r7 = GetPartyCount(party);
+ u8 ret = 1;
+ u8 level;
+ for (i = 0; i < r7; i++)
+ {
+ struct Pokemon * pokemon = GetPartyMonByIndex(party, i);
+ if (GetMonData(pokemon, MON_DATA_SPECIES, NULL) != SPECIES_NONE
+ && !GetMonData(pokemon, MON_DATA_IS_EGG, NULL))
+ {
+ level = (u8)GetMonData(pokemon, MON_DATA_LEVEL, NULL);
+ if (level > ret)
+ ret = level;
+ }
+ }
+ return ret;
+}
+
+u16 FUN_02069B40(u16 species)
+{
+ u16 ret;
+ ReadFromNarcMemberByIdPair(&ret, NARC_POKETOOL_POKEZUKAN, 0, species * sizeof(u16), sizeof(u16));
+ return ret;
+}
+
+u16 FUN_02069B60(u16 sinnoh_dex)
+{
+ u16 ret = SPECIES_NONE;
+ if (sinnoh_dex <= SINNOH_DEX_COUNT)
+ ReadFromNarcMemberByIdPair(&ret, NARC_POKETOOL_SHINZUKAN, 0, sinnoh_dex * sizeof(u16), sizeof(u16));
+ return ret;
+}
+
+void FUN_02069B88(struct Pokemon * src, struct Pokemon * dest)
+{
+ *dest = *src;
+}
+
+void FUN_02069BA0(struct Pokemon * src, struct BoxPokemon * dest)
+{
+ *dest = src->box;
+}
+
+void FUN_02069BB4(struct BoxPokemon * src, struct BoxPokemon * dest)
+{
+ *dest = *src;
+}
+
+s8 FUN_02069BC8(struct Pokemon * pokemon, int flavor)
+{
+ return FUN_02069BD0(&pokemon->box, flavor);
+}
+
+s8 FUN_02069BD0(struct BoxPokemon * boxmon, int flavor)
+{
+ u32 personality = GetBoxMonData(boxmon, MON_DATA_PERSONALITY, NULL);
+ return FUN_02069BE4(personality, flavor);
+}
+
+s8 FUN_02069BE4(u32 personality, int flavor)
+{
+ return UNK_020F7F16[GetNatureFromPersonality(personality)][flavor];
+}
+
+int FUN_02069BFC(u16 species, u32 forme, u16 * dest)
+{
+ int i;
+ u16 * wotbl = AllocFromHeap(0, 22 * sizeof(u16));
+ LoadWotbl_HandleAlternateForme(species, (int)forme, wotbl);
+ for (i = 0; wotbl[i] != WOTBL_END; i++)
+ {
+ dest[i] = WOTBL_MOVE(wotbl[i]);
+ }
+ FreeToHeap(wotbl);
+ return i;
+}
+
+void FUN_02069C4C(struct PlayerParty * party)
+{
+ int count = GetPartyCount(party);
+ int idx;
+ struct Pokemon * pokemon;
+ u8 sp0;
+ switch (rand_LC())
+ {
+ case 0x4000:
+ case 0x8000:
+ case 0xC000:
+ do
+ {
+ idx = rand_LC() % count;
+ pokemon = GetPartyMonByIndex(party, idx);
+ } while (GetMonData(pokemon, MON_DATA_SPECIES, NULL) == SPECIES_NONE || GetMonData(pokemon, MON_DATA_IS_EGG, NULL));
+ if (!FUN_02069CF4(party, (u8)MaskOfFlagNo(idx)))
+ {
+ do
+ {
+ sp0 = (u8)rand_LC();
+ } while (!(sp0 & 7));
+ if (sp0 & 0xF0)
+ sp0 &= 7;
+ sp0 |= sp0 << 4;
+ sp0 &= 0xF3;
+ sp0++;
+ SetMonData(pokemon, MON_DATA_POKERUS, &sp0);
+ }
+ }
+}
+
+u8 FUN_02069CF4(struct PlayerParty * party, u8 mask)
+{
+ int i = 0;
+ u32 flag = 1;
+ u8 ret = 0;
+ struct Pokemon * pokemon;
+ if (mask != 0)
+ {
+ do
+ {
+ if (mask & 1)
+ {
+ pokemon = GetPartyMonByIndex(party, i);
+ if (GetMonData(pokemon, MON_DATA_POKERUS, NULL))
+ ret |= flag;
+ }
+ i++;
+ flag <<= 1;
+ mask >>= 1;
+ }
+ while (mask != 0);
+ }
+ else
+ {
+ pokemon = GetPartyMonByIndex(party, 0);
+ if (GetMonData(pokemon, MON_DATA_POKERUS, NULL))
+ ret++;
+ }
+ return ret;
+}
+
+void FUN_02069D50(struct PlayerParty * party, int r5)
+{
+ int i;
+ u8 pokerus;
+ struct Pokemon * pokemon;
+ int count = GetPartyCount(party);
+ for (i = 0; i < count; i++)
+ {
+ pokemon = GetPartyMonByIndex(party, i);
+ if (GetMonData(pokemon, MON_DATA_SPECIES, NULL) != SPECIES_NONE)
+ {
+ pokerus = (u8)GetMonData(pokemon, MON_DATA_POKERUS, NULL);
+ if (pokerus & 0xF)
+ {
+ if ((pokerus & 0xF) < r5 || r5 > 4)
+ pokerus &= 0xF0;
+ else
+ pokerus -= r5;
+ if (pokerus == 0)
+ pokerus = 0x10; // immune
+ SetMonData(pokemon, MON_DATA_POKERUS, &pokerus);
+ }
+ }
+ }
+}
+
+void FUN_02069DC8(struct PlayerParty * party)
+{
+ int count = GetPartyCount(party);
+ int i;
+ struct Pokemon * pokemon;
+ u8 pokerus;
+ if ((rand_LC() % 3) == 0)
+ {
+ for (i = 0; i < count; i++)
+ {
+ pokemon = GetPartyMonByIndex(party, i);
+ if (GetMonData(pokemon, MON_DATA_SPECIES, NULL) != SPECIES_NONE)
+ {
+ pokerus = (u8)GetMonData(pokemon, MON_DATA_POKERUS, NULL);
+ if (pokerus & 0xF)
+ {
+ if (i != 0)
+ {
+ pokemon = GetPartyMonByIndex(party, i - 1);
+ if (!(GetMonData(pokemon, MON_DATA_POKERUS, NULL) & 0xF0))
+ SetMonData(pokemon, MON_DATA_POKERUS, &pokerus);
+ }
+ if (i < count - 1)
+ {
+ pokemon = GetPartyMonByIndex(party, i + 1);
+ if (!(GetMonData(pokemon, MON_DATA_POKERUS, NULL) & 0xF0))
+ {
+ SetMonData(pokemon, MON_DATA_POKERUS, &pokerus);
+ i++; // don't infect the rest of the party
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+BOOL FUN_02069E74(struct Pokemon * pokemon)
+{
+ return FUN_02069E7C(&pokemon->box);
+}
+
+BOOL FUN_02069E7C(struct BoxPokemon * boxmon)
+{
+ return !!(GetBoxMonData(boxmon, MON_DATA_POKERUS, NULL) & 0xF);
+}
+
+BOOL FUN_02069E94(struct Pokemon * pokemon)
+{
+ return FUN_02069E9C(&pokemon->box);
+}
+
+BOOL FUN_02069E9C(struct BoxPokemon * boxmon)
+{
+ u8 pokerus = (u8)GetBoxMonData(boxmon, MON_DATA_POKERUS, NULL);
+ if (pokerus & 0xF)
+ return FALSE;
+ if (pokerus & 0xF0)
+ return TRUE;
+ return FALSE;
+}
+
+void FUN_02069EC4(struct Pokemon * pokemon)
+{
+ FUN_02069ECC(&pokemon->box);
+}
+
+void FUN_02069ECC(struct BoxPokemon * boxmon)
+{
+ u32 species = GetBoxMonData(boxmon, MON_DATA_SPECIES, NULL);
+ u32 ability = GetBoxMonData(boxmon, MON_DATA_ABILITY, NULL);
+ u32 heldItem = GetBoxMonData(boxmon, MON_DATA_HELD_ITEM, NULL);
+ u32 forme;
+ if (species == SPECIES_ARCEUS && ability == ABILITY_MULTITYPE)
+ {
+ forme = GetArceusTypeByHeldItemEffect((u16)FUN_0206E7B8((u16)heldItem, 1, 0));
+ SetBoxMonData(boxmon, MON_DATA_FORME, &forme);
+ }
+}
+
+u32 GetArceusTypeByHeldItemEffect(u16 heldEffect)
+{
+ switch (heldEffect)
+ {
+ case 0x7D:
+ return TYPE_FIRE;
+ case 0x7E:
+ return TYPE_WATER;
+ case 0x7F:
+ return TYPE_ELECTRIC;
+ case 0x80:
+ return TYPE_GRASS;
+ case 0x81:
+ return TYPE_ICE;
+ case 0x82:
+ return TYPE_FIGHTING;
+ case 0x83:
+ return TYPE_POISON;
+ case 0x84:
+ return TYPE_GROUND;
+ case 0x85:
+ return TYPE_FLYING;
+ case 0x86:
+ return TYPE_PSYCHIC;
+ case 0x87:
+ return TYPE_BUG;
+ case 0x88:
+ return TYPE_ROCK;
+ case 0x89:
+ return TYPE_GHOST;
+ case 0x8A:
+ return TYPE_DRAGON;
+ case 0x8B:
+ return TYPE_DARK;
+ case 0x8C:
+ return TYPE_STEEL;
+ default:
+ return TYPE_NORMAL;
+ }
+}
+
+void LoadWotbl_HandleAlternateForme(int species, int forme, u16 * wotbl)
+{
+ ReadWholeNarcMemberByIdPair(wotbl, NARC_POKETOOL_PERSONAL_WOTBL, ResolveMonForme(species, forme));
+}
+
+void FUN_02069FB0(u32 r7, u32 r5, u32 r4, u32 r6, u32 sp18, u32 sp1C, u32 sp20)
+{
+ if (r4 == SPECIES_CHATOT)
+ {
+ if (!FUN_02005F14((int)r5))
+ {
+ FUN_02005E80(1);
+ FUN_020056AC((int)r5, (int)r4, (int)r6, (int)sp18, (int)sp20);
+ }
+ else
+ {
+ if (sp1C)
+ FUN_02005E80(1);
+ FUN_02005E90((int)r7, 0, (int)sp18, (int)r6);
+ }
+ }
+ else
+ {
+ FUN_020056AC((int)r5, (int)r4, (int)r6, (int)sp18, (int)sp20);
+ }
+}
+
+void FUN_0206A014(struct Pokemon * pokemon, u32 a1, u32 pokeball, u32 a3, u32 encounterType, u32 a5)
+{
+ u32 hp;
+ FUN_0206A054(&pokemon->box, a1, pokeball, a3, encounterType, a5);
+ if (pokeball == ITEM_HEAL_BALL)
+ {
+ hp = GetMonData(pokemon, MON_DATA_MAXHP, NULL);
+ SetMonData(pokemon, MON_DATA_HP, &hp);
+ hp = 0;
+ SetMonData(pokemon, MON_DATA_STATUS, &hp);
+ }
+}
+
+void FUN_0206A054(struct BoxPokemon * boxmon, u32 a1, u32 pokeball, u32 a3, u32 encounterType, u32 a5)
+{
+ FUN_020808AC(boxmon, (int)a1, 0, (int)a3, (int)a5);
+ SetBoxMonData(boxmon, MON_DATA_GAME_VERSION, (void *)&gGameVersion);
+ SetBoxMonData(boxmon, MON_DATA_POKEBALL, &pokeball);
+ SetBoxMonData(boxmon, MON_DATA_ENCOUNTER_TYPE, &encounterType);
+}
+
+void FUN_0206A094(struct Pokemon * pokemon, u32 a1, u32 a2)
+{
+ u32 chance;
+ u16 species;
+ u16 forme;
+ u16 item1;
+ u16 item2;
+ if (!(a1 & 0x81)) {
+ chance = (u32)(rand_LC() % 100);
+ species = (u16)GetMonData(pokemon, MON_DATA_SPECIES, 0);
+ forme = (u16)GetMonData(pokemon, MON_DATA_FORME, 0);
+ item1 = (u16)GetMonBaseStat_HandleFormeConversion(species, forme, BASE_ITEM_1);
+ item2 = (u16)GetMonBaseStat_HandleFormeConversion(species, forme, BASE_ITEM_2);
+ if (item1 == item2 && item1 != ITEM_NONE)
+ {
+ SetMonData(pokemon, MON_DATA_HELD_ITEM, &item1);
+ }
+ else
+ {
+ if (chance >= sItemOdds[a2][0])
+ {
+ if (chance < sItemOdds[a2][1])
+ {
+ SetMonData(pokemon, MON_DATA_HELD_ITEM, &item1);
+ }
+ else
+ {
+ SetMonData(pokemon, MON_DATA_HELD_ITEM, &item2);
+ }
+ }
+ }
+ }
+}
+
+BOOL FUN_0206A13C(struct Pokemon * pokemon, u32 a1)
+{
+ return FUN_0206A144(&pokemon->box, a1);
+}
+
+BOOL FUN_0206A144(struct BoxPokemon * boxmon, u32 a1)
+{
+ u16 species = (u16)GetBoxMonData(boxmon, MON_DATA_SPECIES2, NULL);
+ int forme = (int)GetBoxMonData(boxmon, MON_DATA_FORME, NULL);
+ return FUN_0206A16C(species, forme, a1);
+}
+
+BOOL FUN_0206A16C(u16 species, int forme, u32 a2)
+{
+ u32 r4;
+ enum BaseStat r2;
+ if (species == SPECIES_EGG)
+ return FALSE;
+ if (a2 < 32)
+ {
+ r4 = 1ul << a2;
+ r2 = BASE_UNKNOWN_29;
+ }
+ else if (a2 < 64)
+ {
+ r4 = 1ul << (a2 - 32);
+ r2 = BASE_UNKNOWN_30;
+ }
+ else if (a2 < 96)
+ {
+ r4 = 1ul << (a2 - 64);
+ r2 = BASE_UNKNOWN_31;
+ }
+ else
+ {
+ r4 = 1ul << (a2 - 96);
+ r2 = BASE_UNKNOWN_32;
+ }
+ return !!(GetMonBaseStat_HandleFormeConversion(species, forme, r2) & r4);
+}
+
+void FUN_0206A1C4(struct Pokemon * pokemon)
+{
+ FUN_0206A1CC(&pokemon->box);
+}
+
+void FUN_0206A1CC(struct BoxPokemon * boxmon)
+{
+ BOOL decry = AcquireBoxMonLock(boxmon);
+ int species = (int)GetBoxMonData(boxmon, MON_DATA_SPECIES, NULL);
+ int pid = (int)GetBoxMonData(boxmon, MON_DATA_PERSONALITY, NULL);
+ int ability1 = (int)GetMonBaseStat(species, BASE_ABILITY_1);
+ int ability2 = (int)GetMonBaseStat(species, BASE_ABILITY_2);
+
+ if (ability2 != ABILITY_NONE)
+ {
+ if (pid & 1)
+ SetBoxMonData(boxmon, MON_DATA_ABILITY, &ability2);
+ else
+ SetBoxMonData(boxmon, MON_DATA_ABILITY, &ability1);
+ }
+ else
+ SetBoxMonData(boxmon, MON_DATA_ABILITY, &ability1);
+ ReleaseBoxMonLock(boxmon, decry);
+}
+
+void FUN_0206A23C(struct Pokemon * r5, u32 personality)
+{
+ PokemonDataBlockA * r4;
+ PokemonDataBlockB * r6;
+ PokemonDataBlockC * r7;
+ PokemonDataBlockD * sp8;
+ PokemonDataBlockA * spC;
+ PokemonDataBlockB * sp10;
+ PokemonDataBlockC * sp14;
+ PokemonDataBlockD * sp18;
+ struct Pokemon * sp4;
+
+ sp4 = AllocMonZeroed(0);
+ FUN_02069B88(r5, sp4);
+ r4 = &GetSubstruct(&sp4->box, r5->box.pid, 0)->blockA;
+ r6 = &GetSubstruct(&sp4->box, r5->box.pid, 1)->blockB;
+ r7 = &GetSubstruct(&sp4->box, r5->box.pid, 2)->blockC;
+ sp8 = &GetSubstruct(&sp4->box, r5->box.pid, 3)->blockD;
+ spC = &GetSubstruct(&r5->box, personality, 0)->blockA;
+ sp10 = &GetSubstruct(&r5->box, personality, 1)->blockB;
+ sp14 = &GetSubstruct(&r5->box, personality, 2)->blockC;
+ sp18 = &GetSubstruct(&r5->box, personality, 3)->blockD;
+
+ DECRYPT_BOX(&sp4->box);
+ DECRYPT_PTY(r5);
+ DECRYPT_BOX(&r5->box);
+ r5->box.pid = personality;
+ *spC = *r4;
+ *sp10 = *r6;
+ *sp14 = *r7;
+ *sp18 = *sp8;
+ r5->box.checksum = CHECKSUM(&r5->box);
+ ENCRYPT_BOX(&r5->box);
+ ENCRYPT_PTY(r5);
+ FreeToHeap(sp4);
+}
+
+void LoadMonPersonal(int species, struct BaseStats * personal)
+{
+ ReadWholeNarcMemberByIdPair(personal, NARC_POKETOOL_PERSONAL_PERSONAL, species);
+}
+
+void LoadMonBaseStats_HandleAlternateForme(int species, int forme, struct BaseStats * personal)
+{
+ ReadWholeNarcMemberByIdPair(personal, NARC_POKETOOL_PERSONAL_PERSONAL, ResolveMonForme(species, forme));
+}
+
+void LoadMonEvolutionTable(u16 species, struct Evolution * evo)
+{
+ ReadWholeNarcMemberByIdPair(evo, NARC_POKETOOL_PERSONAL_EVO, species);
+}
+
+
+void MonEncryptSegment(u16 * data, u32 size, u32 seed) {
+ int i;
+ for (i = 0; i < size / 2; i++)
+ {
+ data[i] ^= MonEncryptionLCRNG(&seed);
+ }
+}
+
+void MonDecryptSegment(u16 * data, u32 size, u32 seed) {
+ MonEncryptSegment(data, size, seed);
+}
+
+u16 MonEncryptionLCRNG(u32 * seed)
+{
+ *seed = *seed * 1103515245 + 24691;
+ return (u16)(*seed >> 16);
+}
+
+u16 CalcMonChecksum(u16 * data, u32 size)
+{
+ int i;
+ u16 ret = 0;
+ for (i = 0; i < size / 2; i++)
+ {
+ ret += data[i];
+ }
+ return ret;
+}
+
+#define SUBSTRUCT_CASE(v1, v2, v3, v4) \
+{ \
+ PokemonDataBlock *substructs = boxMon->substructs; \
+ switch (substructType) \
+ { \
+ case 0: \
+ result = &substructs[v1]; \
+ break; \
+ case 1: \
+ result = &substructs[v2]; \
+ break; \
+ case 2: \
+ result = &substructs[v3]; \
+ break; \
+ case 3: \
+ result = &substructs[v4]; \
+ break; \
+ } \
+ \
+ break; \
+}
+
+PokemonDataBlock *GetSubstruct(struct BoxPokemon *boxMon, u32 personality, u8 substructType)
+{
+ PokemonDataBlock *result;
+
+ switch ((personality & 0x3E000) >> 13)
+ {
+ case 0:
+ case 24:
+ SUBSTRUCT_CASE(0,1,2,3)
+ case 1:
+ case 25:
+ SUBSTRUCT_CASE(0,1,3,2)
+ case 2:
+ case 26:
+ SUBSTRUCT_CASE(0,2,1,3)
+ case 3:
+ case 27:
+ SUBSTRUCT_CASE(0,3,1,2)
+ case 4:
+ case 28:
+ SUBSTRUCT_CASE(0,2,3,1)
+ case 5:
+ case 29:
+ SUBSTRUCT_CASE(0,3,2,1)
+ case 6:
+ case 30:
+ SUBSTRUCT_CASE(1,0,2,3)
+ case 7:
+ case 31:
+ SUBSTRUCT_CASE(1,0,3,2)
+ case 8:
+ SUBSTRUCT_CASE(2,0,1,3)
+ case 9:
+ SUBSTRUCT_CASE(3,0,1,2)
+ case 10:
+ SUBSTRUCT_CASE(2,0,3,1)
+ case 11:
+ SUBSTRUCT_CASE(3,0,2,1)
+ case 12:
+ SUBSTRUCT_CASE(1,2,0,3)
+ case 13:
+ SUBSTRUCT_CASE(1,3,0,2)
+ case 14:
+ SUBSTRUCT_CASE(2,1,0,3)
+ case 15:
+ SUBSTRUCT_CASE(3,1,0,2)
+ case 16:
+ SUBSTRUCT_CASE(2,3,0,1)
+ case 17:
+ SUBSTRUCT_CASE(3,2,0,1)
+ case 18:
+ SUBSTRUCT_CASE(1,2,3,0)
+ case 19:
+ SUBSTRUCT_CASE(1,3,2,0)
+ case 20:
+ SUBSTRUCT_CASE(2,1,3,0)
+ case 21:
+ SUBSTRUCT_CASE(3,1,2,0)
+ case 22:
+ SUBSTRUCT_CASE(2,3,1,0)
+ case 23:
+ SUBSTRUCT_CASE(3,2,1,0)
+ }
+ return result;
+}
+
+int ResolveMonForme(int species, int forme)
+{
+ switch (species)
+ {
+ case SPECIES_DEOXYS:
+ if (forme != 0 && forme <= 3)
+ return SPECIES_DEOXYS_ATK + forme - 1;
+ break;
+ case SPECIES_WORMADAM:
+ if (forme != 0 && forme <= 2)
+ return SPECIES_WORMADAM_SANDY + forme - 1;
+ break;
+ }
+ return species;
+}
+
+u32 MaskOfFlagNo(int flagno)
+{
+ // This is completely inane.
+ int i;
+ u32 ret = 1;
+ GF_ASSERT(flagno < 32);
+ for (i = 0; i < flagno; i++)
+ ret <<= 1;
+ return ret;
+}
+
+int LowestFlagNo(u32 mask)
+{
+ int i;
+ u32 bit = 1;
+ for (i = 0; i < 32; i++)
+ {
+ if (mask & bit)
+ break;
+ bit <<= 1;
+ }
+ return i;
+}
+
+BOOL IsPokemonLegendaryOrMythical(u16 species)
+{
+ int i;
+ for (i = 0; i < NELEMS(sLegendaryMonsList); i++)
+ {
+ if (species == sLegendaryMonsList[i])
+ return TRUE;
+ }
+ return FALSE;
+}
+
+u16 GetLegendaryMon(u32 idx)
+{
+ if (idx >= NELEMS(sLegendaryMonsList))
+ idx = 0;
+ return sLegendaryMonsList[idx];
+}
+
+BOOL FUN_0206A998(struct Pokemon * pokemon)
+{
+ u16 species = (u16)GetMonData(pokemon, MON_DATA_SPECIES, NULL);
+ return IsPokemonLegendaryOrMythical(species);
+}
+
+BOOL FUN_0206A9AC(struct BoxPokemon * boxmon, struct SaveBlock2 * sb2, u32 heap_id)
+{
+ u32 myId = FUN_020239BC(sb2);
+ u32 otId = GetBoxMonData(boxmon, MON_DATA_OTID, NULL);
+ u32 myGender = FUN_020239CC(sb2);
+ u32 otGender = GetBoxMonData(boxmon, MON_DATA_MET_GENDER, NULL);
+ struct String * r7 = FUN_020239A0(sb2, heap_id);
+ struct String * r6 = FUN_020219F4(OT_NAME_LENGTH + 1, heap_id);
+ BOOL ret = FALSE;
+ GetBoxMonData(boxmon, MON_DATA_OT_NAME_2, r6);
+ if (myId == otId && myGender == otGender && FUN_02021CE0(r7, r6) == 0)
+ ret = TRUE;
+ FUN_02021A20(r6);
+ FUN_02021A20(r7);
+ return ret;
+}
+
+int FUN_0206AA30(int x)
+{
+ switch (x)
+ {
+ case 63:
+ return 2;
+ case 90:
+ case 91:
+ case 92:
+ case 93:
+ case 94:
+ return x - 87;
+ default:
+ if (FUN_0206AE00(x) == 1)
+ return 1;
+ else
+ return 0;
+ case 0:
+ case 1:
+ return x;
+ }
+}
+
+void FUN_0206AA84(struct Pokemon * pokemon)
+{
+ u8 sp0 = 0;
+ u8 sp1[12][2];
+ MIi_CpuClearFast(0, sp1, sizeof(sp1));
+ SetMonData(pokemon, MON_DATA_CAPSULE, &sp0);
+ SetMonData(pokemon, MON_DATA_SEAL_COORDS, sp1);
+}
+
+void FUN_0206AAB4(struct BoxPokemon * boxmon)
+{
+ int i;
+ u8 pp;
+ BOOL decry = AcquireBoxMonLock(boxmon);
+ for (i = 0; i < 4; i++)
+ {
+ if (GetBoxMonData(boxmon, MON_DATA_MOVE1 + i, NULL) != MOVE_NONE)
+ {
+ pp = (u8)GetBoxMonData(boxmon, MON_DATA_MOVE1MAXPP + i, NULL);
+ SetBoxMonData(boxmon, MON_DATA_MOVE1PP + i, &pp);
+ }
+ }
+ ReleaseBoxMonLock(boxmon, decry);
+}
diff --git a/arm9/src/string_util.c b/arm9/src/string_util.c
index e36f1a30..54ad61fc 100644
--- a/arm9/src/string_util.c
+++ b/arm9/src/string_util.c
@@ -1,8 +1,5 @@
#include "string_util.h"
-#define EOS 0xFFFF
-#define NON_DIGIT 0xE2
-
const u16 gDigitTable[] = {
0xA2,
0xA3,