summaryrefslogtreecommitdiff
path: root/arm9/src
diff options
context:
space:
mode:
Diffstat (limited to 'arm9/src')
-rw-r--r--arm9/src/pokemon.c2118
-rw-r--r--arm9/src/string_util.c3
2 files changed, 2118 insertions, 3 deletions
diff --git a/arm9/src/pokemon.c b/arm9/src/pokemon.c
new file mode 100644
index 00000000..58030ee1
--- /dev/null
+++ b/arm9/src/pokemon.c
@@ -0,0 +1,2118 @@
+#include "global.h"
+#define IN_POKEMON_C
+#include "proto.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"
+
+#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 LoadMonPersonal(int species, struct BaseStats * personal);
+
+int ResolveMonForme(int species, int forme);
+void MonEncryptSegment(void * datap, u32 size, u32 key);
+void MonDecryptSegment(void * datap, u32 size, u32 key);
+u16 MonEncryptionLCRNG(u32 * seed);
+u16 CalcMonChecksum(void * datap, u32 size);
+void InitBoxMonMoveset(struct BoxPokemon * boxmon);
+PokemonDataBlock * GetSubstruct(struct BoxPokemon * boxmon, u32 personality, u32 which_struct);
+void LoadMonBaseStats_HandleAlternateForme(u32 species, u32 forme, struct BaseStats * baseStats);
+
+#define ENCRY_ARGS_PTY(mon) &(mon)->party, sizeof((mon)->party), (mon)->box.pid
+#define ENCRY_ARGS_BOX(boxmon) &(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((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(&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 = 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 = 4;
+ 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 = GetMonBaseStat(species, BASE_ABILITY_1);
+ iv = 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 = 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), newAtk, 1);
+ SetMonData(pokemon, MON_DATA_ATK, &newAtk);
+
+ newDef = (baseStats->def * 2 + defIv + defEv / 4) * level / 100 + 5;
+ newDef = ModifyStatByNature(GetMonNature(pokemon), newDef, 2);
+ SetMonData(pokemon, MON_DATA_DEF, &newDef);
+
+ newSpeed = (baseStats->speed * 2 + speedIv + speedEv / 4) * level / 100 + 5;
+ newSpeed = ModifyStatByNature(GetMonNature(pokemon), newSpeed, 3);
+ SetMonData(pokemon, MON_DATA_SPEED, &newSpeed);
+
+ newSpatk = (baseStats->spatk * 2 + spatkIv + spatkEv / 4) * level / 100 + 5;
+ newSpatk = ModifyStatByNature(GetMonNature(pokemon), newSpatk, 4);
+ SetMonData(pokemon, MON_DATA_SPATK, &newSpatk);
+
+ newSpdef = (baseStats->spdef * 2 + spdefIv + spdefEv / 4) * level / 100 + 5;
+ newSpdef = ModifyStatByNature(GetMonNature(pokemon), 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 = 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 = 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 = GetArceusTypeByPlate(FUN_0206E7B8(blockA->heldItem, 1, 0));
+ else
+ {
+ ret = GetMonBaseStat_HandleFormeConversion(blockA->species, blockB->alternateForm, 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;
+ u8 iv;
+
+ 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 = 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] = 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 = baseStats->unk1C;
+ break;
+ case BASE_UNKNOWN_30:
+ ret = baseStats->unk20;
+ break;
+ case BASE_UNKNOWN_31:
+ ret = baseStats->unk24;
+ break;
+ case BASE_UNKNOWN_32:
+ ret = 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 = GetMonData(pokemon, MON_DATA_SPECIES, NULL);
+ u8 level = 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 100 * (cur - lo) / (hi - lo);
+}
+
+u32 CalcMonExpToNextLevel(struct Pokemon * pokemon)
+{
+ return CalcBoxMonExpToNextLevel(&pokemon->box);
+}
+
+u32 CalcBoxMonExpToNextLevel(struct BoxPokemon * boxmon)
+{
+ u16 species = GetBoxMonData(boxmon, MON_DATA_SPECIES, NULL);
+ u16 level = 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 = GetMonData(pokemon, MON_DATA_SPECIES, NULL);
+ int level = 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 = GetBoxMonData(boxmon, MON_DATA_SPECIES, NULL);
+ int exp = GetBoxMonData(boxmon, MON_DATA_EXPERIENCE, NULL);
+ ReleaseBoxMonLock(boxmon, decry);
+ return CalcLevelBySpeciesAndExp(species, 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)
+{
+ 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 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)(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)(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 = GetMonData(pokemon, MON_DATA_SPECIES2, NULL);
+ if (species == SPECIES_NONE || species == SPECIES_EGG)
+ return;
+
+ effect = FUN_0206E7B8(GetMonData(pokemon, MON_DATA_HELD_ITEM, NULL), 1, 0);
+ r4 = 0;
+ friendship = 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 = 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 = 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)
+{
+ u8 ratio = 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);
+}
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,