diff options
Diffstat (limited to 'arm9/src')
-rw-r--r-- | arm9/src/pokemon.c | 201 | ||||
-rw-r--r-- | arm9/src/trainer_data.c | 403 | ||||
-rw-r--r-- | arm9/src/unk_0206B688.c | 185 | ||||
-rw-r--r-- | arm9/src/unk_0206BB28.c | 25 |
4 files changed, 713 insertions, 101 deletions
diff --git a/arm9/src/pokemon.c b/arm9/src/pokemon.c index 48b1a225..7fe8191a 100644 --- a/arm9/src/pokemon.c +++ b/arm9/src/pokemon.c @@ -10,7 +10,7 @@ #include "math_util.h" #include "move_data.h" #include "string_util.h" -#include "text.h" +#include "seal.h" #include "msgdata.h" #include "itemtool.h" #include "constants/abilities.h" @@ -21,8 +21,6 @@ #pragma thumb on -extern void FUN_02029C74(const u8 *, u8 *); - 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); @@ -39,12 +37,12 @@ u32 FUN_020696A8(struct BoxPokemon * boxmon, u16 move); void FUN_02069718(struct BoxPokemon * boxmon, u16 move); void BoxMonSetMoveInSlot(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); +s8 BoxMonGetFlavorPreference(struct BoxPokemon * boxmon, int flavor); +s8 GetFlavorPreferenceFromPID(u32 personality, int flavor); +u8 Party_MaskMonsWithPokerus(struct PlayerParty * party_p, u8 mask); +BOOL BoxMon_HasPokerus(struct BoxPokemon * boxmon); +BOOL BoxMon_IsImmuneToPokerus(struct BoxPokemon * boxmon); +void BoxMon_UpdateArceusForme(struct BoxPokemon * boxmon); void LoadWotbl_HandleAlternateForme(int species, int forme, u16 * wotbl); void FUN_0206A054(struct BoxPokemon * boxmon, struct PlayerData * a1, u32 pokeball, u32 a3, u32 encounterType, u32 heap_id); BOOL MonHasMove(struct Pokemon * pokemon, u16 move); @@ -118,61 +116,62 @@ const u16 sLegendaryMonsList[] = { 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 sFlavorPreferencesByNature[][5] = { + // Spicy, Dry, Sweet, Bitter, Sour + { 0, 0, 0, 0, 0 }, // NATURE_HARDY + { 1, 0, 0, 0, -1 }, // NATURE_LONELY + { 1, 0, -1, 0, 0 }, // NATURE_BRAVE + { 1, -1, 0, 0, 0 }, // NATURE_ADAMANT + { 1, 0, 0, -1, 0 }, // NATURE_NAUGHTY + { -1, 0, 0, 0, 1 }, // NATURE_BOLD + { 0, 0, 0, 0, 0 }, // NATURE_DOCILE + { 0, 0, -1, 0, 1 }, // NATURE_RELAXED + { 0, -1, 0, 0, 1 }, // NATURE_IMPISH + { 0, 0, 0, -1, 1 }, // NATURE_LAX + { -1, 0, 1, 0, 0 }, // NATURE_TIMID + { 0, 0, 1, 0, -1 }, // NATURE_HASTY + { 0, 0, 0, 0, 0 }, // NATURE_SERIOUS + { 0, -1, 1, 0, 0 }, // NATURE_JOLLY + { 0, 0, 1, -1, 0 }, // NATURE_NAIVE + { -1, 1, 0, 0, 0 }, // NATURE_MODEST + { 0, 1, 0, 0, -1 }, // NATURE_MILD + { 0, 1, -1, 0, 0 }, // NATURE_QUIET + { 0, 0, 0, 0, 0 }, // NATURE_BASHFUL + { 0, 1, 0, -1, 0 }, // NATURE_RASH + { -1, 0, 0, 1, 0 }, // NATURE_CALM + { 0, 0, 0, 1, -1 }, // NATURE_GENTLE + { 0, 0, -1, 1, 0 }, // NATURE_SASSY + { 0, -1, 0, 1, 0 }, // NATURE_CAREFUL + { 0, 0, 0, 0, 0 }, // NATURE_QUIRKY }; 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 }, + // Atk, Def, Speed, SpAtk, SpDef + { 0, 0, 0, 0, 0 }, // NATURE_HARDY + { 1, -1, 0, 0, 0 }, // NATURE_LONELY + { 1, 0, -1, 0, 0 }, // NATURE_BRAVE + { 1, 0, 0, -1, 0 }, // NATURE_ADAMANT + { 1, 0, 0, 0, -1 }, // NATURE_NAUGHTY + { -1, 1, 0, 0, 0 }, // NATURE_BOLD + { 0, 0, 0, 0, 0 }, // NATURE_DOCILE + { 0, 1, -1, 0, 0 }, // NATURE_RELAXED + { 0, 1, 0, -1, 0 }, // NATURE_IMPISH + { 0, 1, 0, 0, -1 }, // NATURE_LAX + { -1, 0, 1, 0, 0 }, // NATURE_TIMID + { 0, -1, 1, 0, 0 }, // NATURE_HASTY + { 0, 0, 0, 0, 0 }, // NATURE_SERIOUS + { 0, 0, 1, -1, 0 }, // NATURE_JOLLY + { 0, 0, 1, 0, -1 }, // NATURE_NAIVE + { -1, 0, 0, 1, 0 }, // NATURE_MODEST + { 0, -1, 0, 1, 0 }, // NATURE_MILD + { 0, 0, -1, 1, 0 }, // NATURE_QUIET + { 0, 0, 0, 0, 0 }, // NATURE_BASHFUL + { 0, 0, 0, 1, -1 }, // NATURE_RASH + { -1, 0, 0, 0, 1 }, // NATURE_CALM + { 0, -1, 0, 0, 1 }, // NATURE_GENTLE + { 0, 0, -1, 0, 1 }, // NATURE_SASSY + { 0, 0, 0, -1, 1 }, // NATURE_CAREFUL + { 0, 0, 0, 0, 0 }, // NATURE_QUIRKY }; void ZeroMonData(struct Pokemon * pokemon) @@ -563,10 +562,10 @@ u32 GetMonDataInternal(struct Pokemon * pokemon, int attr, void * dest) case MON_DATA_SPDEF: return pokemon->party.spdef; case MON_DATA_MAIL_STRUCT: - Mail_copy(&pokemon->party.seal_something, dest); + Mail_copy(&pokemon->party.mail, dest); return 1; case MON_DATA_SEAL_COORDS: - FUN_02029C74(pokemon->party.sealCoords, dest); + FUN_02029C74(&pokemon->party.sealCoords, dest); return 1; default: return GetBoxMonDataInternal(&pokemon->box, attr, dest); @@ -1051,10 +1050,10 @@ void SetMonDataInternal(struct Pokemon * pokemon, int attr, void * value) pokemon->party.spdef = VALUE(u16); break; case MON_DATA_MAIL_STRUCT: - Mail_copy((const struct Mail *)value, &pokemon->party.seal_something); + Mail_copy((const struct Mail *)value, &pokemon->party.mail); break; case MON_DATA_SEAL_COORDS: - FUN_02029C74((const u8 *)value, pokemon->party.sealCoords); + FUN_02029C74((CapsuleArray *)value, &pokemon->party.sealCoords); break; default: SetBoxMonDataInternal(&pokemon->box, attr, value); @@ -2990,10 +2989,10 @@ BOOL MonHasMove(struct Pokemon * pokemon, u16 move) return FALSE; } -void FUN_02069A64(struct BoxPokemon * src, struct Pokemon * dest) +void CopyBoxPokemonToPokemon(struct BoxPokemon * src, struct Pokemon * dest) { u32 sp0 = 0; - u8 sp4[12][2]; + CapsuleArray sp4; struct Mail * mail; dest->box = *src; if (dest->box.box_lock) @@ -3005,12 +3004,12 @@ void FUN_02069A64(struct BoxPokemon * src, struct Pokemon * dest) SetMonData(dest, MON_DATA_MAIL_STRUCT, mail); FreeToHeap(mail); SetMonData(dest, MON_DATA_CAPSULE, &sp0); - MIi_CpuClearFast(0, sp4, sizeof(sp4)); - SetMonData(dest, MON_DATA_SEAL_COORDS, sp4); + MIi_CpuClearFast(0, &sp4, sizeof(sp4)); + SetMonData(dest, MON_DATA_SEAL_COORDS, &sp4); CalcMonLevelAndStats(dest); } -u8 FUN_02069AEC(struct PlayerParty * party) +u8 Party_GetMaxLevel(struct PlayerParty * party) { int i; int r7 = GetPartyCount(party); @@ -3037,7 +3036,7 @@ u16 SpeciesToSinnohDexNo(u16 species) return ret; } -u16 FUN_02069B60(u16 sinnoh_dex) +u16 SinnohDexNoToSpecies(u16 sinnoh_dex) { u16 ret = SPECIES_NONE; if (sinnoh_dex <= SINNOH_DEX_COUNT) @@ -3045,38 +3044,38 @@ u16 FUN_02069B60(u16 sinnoh_dex) return ret; } -void FUN_02069B88(struct Pokemon * src, struct Pokemon * dest) +void CopyPokemonToPokemon(struct Pokemon * src, struct Pokemon * dest) { *dest = *src; } -void FUN_02069BA0(struct Pokemon * src, struct BoxPokemon * dest) +void CopyPokemonToBoxPokemon(struct Pokemon * src, struct BoxPokemon * dest) { *dest = src->box; } -void FUN_02069BB4(struct BoxPokemon * src, struct BoxPokemon * dest) +void CopyBoxPokemonToBoxPokemon(struct BoxPokemon * src, struct BoxPokemon * dest) { *dest = *src; } -s8 FUN_02069BC8(struct Pokemon * pokemon, int flavor) +s8 MonGetFlavorPreference(struct Pokemon * pokemon, int flavor) { - return FUN_02069BD0(&pokemon->box, flavor); + return BoxMonGetFlavorPreference(&pokemon->box, flavor); } -s8 FUN_02069BD0(struct BoxPokemon * boxmon, int flavor) +s8 BoxMonGetFlavorPreference(struct BoxPokemon * boxmon, int flavor) { u32 personality = GetBoxMonData(boxmon, MON_DATA_PERSONALITY, NULL); - return FUN_02069BE4(personality, flavor); + return GetFlavorPreferenceFromPID(personality, flavor); } -s8 FUN_02069BE4(u32 personality, int flavor) +s8 GetFlavorPreferenceFromPID(u32 personality, int flavor) { - return UNK_020F7F16[GetNatureFromPersonality(personality)][flavor]; + return sFlavorPreferencesByNature[GetNatureFromPersonality(personality)][flavor]; } -int FUN_02069BFC(u16 species, u32 forme, u16 * dest) +int Species_LoadLearnsetTable(u16 species, u32 forme, u16 * dest) { int i; u16 * wotbl = AllocFromHeap(0, 22 * sizeof(u16)); @@ -3089,7 +3088,7 @@ int FUN_02069BFC(u16 species, u32 forme, u16 * dest) return i; } -void FUN_02069C4C(struct PlayerParty * party) +void Party_GivePokerusAtRandom(struct PlayerParty * party) { int count = GetPartyCount(party); int idx; @@ -3105,7 +3104,7 @@ void FUN_02069C4C(struct PlayerParty * party) idx = LCRandom() % 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))) + if (!Party_MaskMonsWithPokerus(party, (u8)MaskOfFlagNo(idx))) { do { @@ -3121,7 +3120,7 @@ void FUN_02069C4C(struct PlayerParty * party) } } -u8 FUN_02069CF4(struct PlayerParty * party, u8 mask) +u8 Party_MaskMonsWithPokerus(struct PlayerParty * party, u8 mask) { int i = 0; u32 flag = 1; @@ -3152,7 +3151,7 @@ u8 FUN_02069CF4(struct PlayerParty * party, u8 mask) return ret; } -void FUN_02069D50(struct PlayerParty * party, int r5) +void Party_UpdatePokerus(struct PlayerParty * party, int r5) { int i; u8 pokerus; @@ -3178,7 +3177,7 @@ void FUN_02069D50(struct PlayerParty * party, int r5) } } -void FUN_02069DC8(struct PlayerParty * party) +void Party_SpreadPokerus(struct PlayerParty * party) { int count = GetPartyCount(party); int i; @@ -3215,22 +3214,22 @@ void FUN_02069DC8(struct PlayerParty * party) } } -BOOL FUN_02069E74(struct Pokemon * pokemon) +BOOL Pokemon_HasPokerus(struct Pokemon * pokemon) { - return FUN_02069E7C(&pokemon->box); + return BoxMon_HasPokerus(&pokemon->box); } -BOOL FUN_02069E7C(struct BoxPokemon * boxmon) +BOOL BoxMon_HasPokerus(struct BoxPokemon * boxmon) { return !!(GetBoxMonData(boxmon, MON_DATA_POKERUS, NULL) & 0xF); } -BOOL FUN_02069E94(struct Pokemon * pokemon) +BOOL Pokemon_IsImmuneToPokerus(struct Pokemon * pokemon) { - return FUN_02069E9C(&pokemon->box); + return BoxMon_IsImmuneToPokerus(&pokemon->box); } -BOOL FUN_02069E9C(struct BoxPokemon * boxmon) +BOOL BoxMon_IsImmuneToPokerus(struct BoxPokemon * boxmon) { u8 pokerus = (u8)GetBoxMonData(boxmon, MON_DATA_POKERUS, NULL); if (pokerus & 0xF) @@ -3240,12 +3239,12 @@ BOOL FUN_02069E9C(struct BoxPokemon * boxmon) return FALSE; } -void FUN_02069EC4(struct Pokemon * pokemon) +void Pokemon_UpdateArceusForme(struct Pokemon * pokemon) { - FUN_02069ECC(&pokemon->box); + BoxMon_UpdateArceusForme(&pokemon->box); } -void FUN_02069ECC(struct BoxPokemon * boxmon) +void BoxMon_UpdateArceusForme(struct BoxPokemon * boxmon) { u32 species = GetBoxMonData(boxmon, MON_DATA_SPECIES, NULL); u32 ability = GetBoxMonData(boxmon, MON_DATA_ABILITY, NULL); @@ -3460,7 +3459,7 @@ void FUN_0206A23C(struct Pokemon * r5, u32 personality) struct Pokemon * sp4; sp4 = AllocMonZeroed(0); - FUN_02069B88(r5, sp4); + CopyPokemonToPokemon(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; @@ -3711,7 +3710,7 @@ int FUN_0206AA30(int x) case TRAINER_CLASS_PKMN_TRAINER_POKEKID: return x - TRAINER_CLASS_COMMANDER_JUPITER; default: - if (FUN_0206AE00(x) == 1) + if (TrainerClass_GetGenderOrTrainerCount(x) == 1) return 1; else return 0; @@ -3721,13 +3720,13 @@ int FUN_0206AA30(int x) } } -void FUN_0206AA84(struct Pokemon * pokemon) +void Pokemon_RemoveCapsule(struct Pokemon * pokemon) { u8 sp0 = 0; - u8 sp1[12][2]; - MIi_CpuClearFast(0, sp1, sizeof(sp1)); + CapsuleArray sp1; + MIi_CpuClearFast(0, &sp1, sizeof(sp1)); SetMonData(pokemon, MON_DATA_CAPSULE, &sp0); - SetMonData(pokemon, MON_DATA_SEAL_COORDS, sp1); + SetMonData(pokemon, MON_DATA_SEAL_COORDS, &sp1); } void RestoreBoxMonPP(struct BoxPokemon * boxmon) diff --git a/arm9/src/trainer_data.c b/arm9/src/trainer_data.c new file mode 100644 index 00000000..7c52a78f --- /dev/null +++ b/arm9/src/trainer_data.c @@ -0,0 +1,403 @@ +#include "global.h" +#include "heap.h" +#include "trainer_data.h" +#include "math_util.h" +#include "party.h" +#include "proto.h" +#include "msgdata.h" +#include "constants/trainer_classes.h" + +#pragma thumb on + +extern void * FUN_02024EC0(struct SaveBlock2 *); +extern u16 * FUN_02024EE8(void *); + +// Loads all battle opponents, including multi-battle partner if exists. +void EnemyTrainerSet_Init(struct EnemyTrainerSet * enemies, struct SaveBlock2 * sav2, u32 heap_id) +{ + struct TrainerDataLoaded trdata; + struct MsgData * msgData; + u16 * rivalName; + s32 i; + struct String * str; + + // FIXME: String formatting in files/msgdata/msg/narc_0559.txt is abnormal. + msgData = NewMsgDataFromNarc(1, NARC_MSGDATA_MSG, 559, heap_id); + rivalName = FUN_02024EE8(FUN_02024EC0(sav2)); + for (i = 0; i < 4; i++) + { + if (enemies->trainer_idxs[i] != 0) + { + TrainerData_ReadTrData(enemies->trainer_idxs[i], &trdata.data); + enemies->datas[i] = trdata; + if (trdata.data.trainerClass == TRAINER_CLASS_PKMN_TRAINER_BARRY) + { + CopyU16StringArray(enemies->datas[i].name, rivalName); + } + else + { + str = NewString_ReadMsgData(msgData, enemies->trainer_idxs[i]); + CopyStringToU16Array(str, enemies->datas[i].name, OT_NAME_LENGTH + 1); + String_dtor(str); + } + CreateNPCTrainerParty(enemies, i, heap_id); + } + } + enemies->flags |= trdata.data.doubleBattle; + DestroyMsgData(msgData); +} + +s32 TrainerData_GetAttr(u32 tr_idx, u32 attr_no) +{ + struct TrainerDataLoaded trainer; + s32 ret; + + TrainerData_ReadTrData(tr_idx, &trainer.data); + switch (attr_no) + { + case 0: + ret = trainer.data.trainerType; + break; + case 1: + ret = trainer.data.trainerClass; + break; + case 2: + ret = trainer.data.unk_2; + break; + case 3: + ret = trainer.data.npoke; + break; + case 4: + case 5: + case 6: + case 7: + attr_no -= 4; + ret = trainer.data.items[attr_no]; + break; + case 8: + ret = (s32)trainer.data.unk_C; + break; + case 9: + ret = (s32)trainer.data.doubleBattle; + break; + } + return ret; // UB: uninitialized in event of invalid attr +} + +// Relevant files: +// files/poketool/trmsg/trtbl.narc +// files/poketool/trmsg/trtblofs.narc +// files/msgdata/msg/narc_0558.txt +// trtbl is a single-member NARC whose entries are two shorts each. The first short +// designates the trainer ID and the second the message ID. They are ordered the same +// as the corresponding msgdata file. All messages for a given trainer are found together, +// however the trainers are not in order in this file. trtblofs gives a pointer into trtbl +// for each trainer. trtblofs is also a single-member NARC whose entries are shorts, one +// per NPC trainer. +BOOL TrainerMessageWithIdPairExists(u32 trainer_idx, u32 msg_id, u32 heap_id) +{ + u16 rdbuf[3]; + struct NARC * trTblNarc; + BOOL ret = FALSE; + u32 trTblSize; + + trTblSize = GetNarcMemberSizeByIdPair(NARC_POKETOOL_TRMSG_TRTBL, 0); + ReadFromNarcMemberByIdPair(&rdbuf[0], NARC_POKETOOL_TRMSG_TRTBLOFS, 0, trainer_idx * 2, 2); + trTblNarc = NARC_ctor(NARC_POKETOOL_TRMSG_TRTBL, heap_id); + while (rdbuf[0] != trTblSize) + { + NARC_ReadFromMember(trTblNarc, 0, rdbuf[0], 4, &rdbuf[1]); + if (rdbuf[1] == trainer_idx && rdbuf[2] == msg_id) + { + ret = TRUE; + break; + } + if (rdbuf[1] != trainer_idx) + break; + rdbuf[0] += 4; + } + NARC_dtor(trTblNarc); + return ret; +} + +void GetTrainerMessageByIdPair(u32 trainer_idx, u32 msg_id, struct String * str, u32 heap_id) +{ + u16 rdbuf[3]; + u32 trTblSize; + struct NARC * trTblNarc; + + trTblSize = GetNarcMemberSizeByIdPair(NARC_POKETOOL_TRMSG_TRTBL, 0); + ReadFromNarcMemberByIdPair(&rdbuf[0], NARC_POKETOOL_TRMSG_TRTBLOFS, 0, trainer_idx * 2, 2); + trTblNarc = NARC_ctor(NARC_POKETOOL_TRMSG_TRTBL, heap_id); + while (rdbuf[0] != trTblSize) + { + NARC_ReadFromMember(trTblNarc, 0, rdbuf[0], 4, &rdbuf[1]); + if (rdbuf[1] == trainer_idx && rdbuf[2] == msg_id) + { + ReadMsgData_NewNarc_ExistingString(NARC_MSGDATA_MSG, 558, (u32)(rdbuf[0] / 4), heap_id, str); + break; + } + rdbuf[0] += 4; + } + NARC_dtor(trTblNarc); + if (rdbuf[0] == trTblSize) + StringSetEmpty(str); +} + +void TrainerData_ReadTrData(u32 idx, struct TrainerData * dest) +{ + ReadWholeNarcMemberByIdPair(dest, NARC_POKETOOL_TRAINER_TRDATA, (s32)idx); +} + +void TrainerData_ReadTrPoke(u32 idx, union TrainerMon * dest) +{ + ReadWholeNarcMemberByIdPair(dest, NARC_POKETOOL_TRAINER_TRPOKE, (s32)idx); +} + +const u8 sTrainerClassGenderCountTbl[] = { + /*TRAINER_CLASS_PKMN_TRAINER_M*/ 0, + /*TRAINER_CLASS_PKMN_TRAINER_F*/ 1, + /*TRAINER_CLASS_YOUNGSTER*/ 0, + /*TRAINER_CLASS_LASS*/ 1, + /*TRAINER_CLASS_CAMPER*/ 0, + /*TRAINER_CLASS_PICNICKER*/ 1, + /*TRAINER_CLASS_BUG_CATCHER*/ 0, + /*TRAINER_CLASS_AROMA_LADY*/ 1, + /*TRAINER_CLASS_TWINS*/ 1, + /*TRAINER_CLASS_HIKER*/ 0, + /*TRAINER_CLASS_BATTLE_GIRL*/ 1, + /*TRAINER_CLASS_FISHERMAN*/ 0, + /*TRAINER_CLASS_CYCLIST_M*/ 0, + /*TRAINER_CLASS_CYCLIST_F*/ 1, + /*TRAINER_CLASS_BLACK_BELT*/ 0, + /*TRAINER_CLASS_ARTIST*/ 0, + /*TRAINER_CLASS_PKMN_BREEDER_M*/ 0, + /*TRAINER_CLASS_PKMN_BREEDER_F*/ 1, + /*TRAINER_CLASS_COWGIRL*/ 1, + /*TRAINER_CLASS_JOGGER*/ 0, + /*TRAINER_CLASS_POKEFAN_M*/ 0, + /*TRAINER_CLASS_POKEFAN_F*/ 1, + /*TRAINER_CLASS_POKE_KID*/ 1, + /*TRAINER_CLASS_YOUNG_COUPLE*/ 2, + /*TRAINER_CLASS_ACE_TRAINER_M*/ 0, + /*TRAINER_CLASS_ACE_TRAINER_F*/ 1, + /*TRAINER_CLASS_WAITRESS*/ 1, + /*TRAINER_CLASS_VETERAN*/ 0, + /*TRAINER_CLASS_NINJA_BOY*/ 0, + /*TRAINER_CLASS_DRAGON_TAMER*/ 0, + /*TRAINER_CLASS_BIRD_KEEPER*/ 1, + /*TRAINER_CLASS_DOUBLE_TEAM*/ 2, + /*TRAINER_CLASS_RICH_BOY*/ 0, + /*TRAINER_CLASS_LADY*/ 1, + /*TRAINER_CLASS_GENTLEMAN*/ 0, + /*TRAINER_CLASS_SOCIALITE*/ 1, + /*TRAINER_CLASS_BEAUTY*/ 1, + /*TRAINER_CLASS_COLLECTOR*/ 0, + /*TRAINER_CLASS_POLICEMAN*/ 0, + /*TRAINER_CLASS_PKMN_RANGER_M*/ 0, + /*TRAINER_CLASS_PKMN_RANGER_F*/ 1, + /*TRAINER_CLASS_SCIENTIST*/ 0, + /*TRAINER_CLASS_SWIMMER_M*/ 0, + /*TRAINER_CLASS_SWIMMER_F*/ 1, + /*TRAINER_CLASS_TUBER_M*/ 0, + /*TRAINER_CLASS_TUBER_F*/ 1, + /*TRAINER_CLASS_SAILOR*/ 0, + /*TRAINER_CLASS_SIS_AND_BRO*/ 2, + /*TRAINER_CLASS_RUIN_MANIAC*/ 0, + /*TRAINER_CLASS_PSYCHIC_M*/ 0, + /*TRAINER_CLASS_PSYCHIC_F*/ 1, + /*TRAINER_CLASS_PI*/ 0, + /*TRAINER_CLASS_GUITARIST*/ 0, + /*TRAINER_CLASS_ACE_TRAINER_SNOW_M*/ 0, + /*TRAINER_CLASS_ACE_TRAINER_SNOW_F*/ 1, + /*TRAINER_CLASS_SKIER_M*/ 0, + /*TRAINER_CLASS_SKIER_F*/ 1, + /*TRAINER_CLASS_ROUGHNECK*/ 0, + /*TRAINER_CLASS_CLOWN*/ 0, + /*TRAINER_CLASS_WORKER*/ 0, + /*TRAINER_CLASS_SCHOOL_KID_M*/ 0, + /*TRAINER_CLASS_SCHOOL_KID_F*/ 1, + /*TRAINER_CLASS_LEADER_ROARK*/ 0, + /*TRAINER_CLASS_PKMN_TRAINER_BARRY*/ 0, + /*TRAINER_CLASS_LEADER_BYRON*/ 0, + /*TRAINER_CLASS_ELITE_FOUR_AARON*/ 0, + /*TRAINER_CLASS_ELITE_FOUR_BERTHA*/ 1, + /*TRAINER_CLASS_ELITE_FOUR_FLINT*/ 0, + /*TRAINER_CLASS_ELITE_FOUR_LUCIEN*/ 0, + /*TRAINER_CLASS_CHAMPION*/ 1, + /*TRAINER_CLASS_BELLE__PA*/ 2, + /*TRAINER_CLASS_RANCHER*/ 0, + /*TRAINER_CLASS_COMMANDER_MARS*/ 1, + /*TRAINER_CLASS_GALACTIC*/ 0, + /*TRAINER_CLASS_LEADER_GARDENIA*/ 1, + /*TRAINER_CLASS_LEADER_WAKE*/ 0, + /*TRAINER_CLASS_LEADER_MAYLENE*/ 1, + /*TRAINER_CLASS_LEADER_FANTINA*/ 1, + /*TRAINER_CLASS_LEADER_CANDICE*/ 1, + /*TRAINER_CLASS_LEADER_VOLKNER*/ 0, + /*TRAINER_CLASS_PARASOL_LADY*/ 1, + /*TRAINER_CLASS_WAITER*/ 0, + /*TRAINER_CLASS_INTERVIEWERS*/ 2, + /*TRAINER_CLASS_CAMERAMAN*/ 0, + /*TRAINER_CLASS_REPORTER*/ 1, + /*TRAINER_CLASS_IDOL*/ 1, + /*TRAINER_CLASS_GALACTIC_BOSS*/ 0, + /*TRAINER_CLASS_COMMANDER_JUPITER*/ 1, + /*TRAINER_CLASS_COMMANDER_SATURN*/ 1, + /*TRAINER_CLASS_GALACTIC_F*/ 1, + /*TRAINER_CLASS_PKMN_TRAINER_AROMA_LADY*/ 1, + /*TRAINER_CLASS_PKMN_TRAINER_RICH_BOY*/ 0, + /*TRAINER_CLASS_PKMN_TRAINER_PICNICKER*/ 1, + /*TRAINER_CLASS_PKMN_TRAINER_CAMPER*/ 0, + /*TRAINER_CLASS_PKMN_TRAINER_POKEKID*/ 1, + /*TRAINER_CLASS_PKMN_TRAINER_LUCAS*/ 0, + /*TRAINER_CLASS_PKMN_TRAINER_DAWN*/ 1, + /*TRAINER_CLASS_TOWER_TYCOON*/ 0 +}; + +// Returns 0 for male, 1 for female, 2 for doubles. See above vector. +int TrainerClass_GetGenderOrTrainerCount(int a0) +{ + return sTrainerClassGenderCountTbl[a0]; +} + +void CreateNPCTrainerParty(struct EnemyTrainerSet * enemies, s32 party_id, u32 heap_id) +{ + union TrainerMon * data; + s32 i; + s32 j; + u32 seed_bak; + struct Pokemon * pokemon; + struct TrainerMonSpeciesItemMoves * monSpeciesItemMoves; + struct TrainerMonSpeciesItem * monSpeciesItem; + struct TrainerMonSpeciesMoves * monSpeciesMoves; + struct TrainerMonSpecies * monSpecies; + u32 seed; + u32 personality; + u8 iv; + u32 pid_gender; + + // We abuse the RNG for personality value generation, so back up the overworld + // state + seed_bak = GetLCRNGSeed(); + InitPartyWithMaxSize(enemies->parties[party_id], PARTY_SIZE); + data = (union TrainerMon *)AllocFromHeap(heap_id, sizeof(union TrainerMon) * PARTY_SIZE); + pokemon = AllocMonZeroed(heap_id); + TrainerData_ReadTrPoke(enemies->trainer_idxs[party_id], data); + + // If a Pokemon's gender ratio is 50/50, the generated Pokemon will be the same + // gender as its trainer. Otherwise, it will assume the more abundant gender + // according to its species gender ratio. In double battles, the behavior is + // identical to that of a solitary male opponent. + pid_gender = (u32)((TrainerClass_GetGenderOrTrainerCount(enemies->datas[party_id].data.trainerClass) == 1) ? 0x78 : 0x88); + + // The trainer types can be more efficiently and expandibly treated as a flag + // array, with bit 0 being custom moveset and bit 1 being held item. + // Nintendo didn't do it that way, instead using a switch statement and a lot + // of code duplication. This has been the case since the 2nd generation games. + switch (enemies->datas[party_id].data.trainerType) + { + case TRTYPE_MON: + { + monSpecies = &data->species; + for (i = 0; i < enemies->datas[party_id].data.npoke; i++) + { + // Generate personality by seeding with a value based on the difficulty, + // level, species, and opponent ID. Roll the RNG N times, where N is + // the index of its trainer class. Finally, left shift the 16-bit + // pseudorandom value and add the gender selector. + // This guarantees that NPC trainers' Pokemon are generated in a + // consistent manner between attempts. + seed = monSpecies[i].difficulty + monSpecies[i].level + monSpecies[i].species + enemies->trainer_idxs[party_id]; + SetLCRNGSeed(seed); + for (j = 0; j < enemies->datas[party_id].data.trainerClass; j++) + { + seed = LCRandom(); + } + personality = (seed << 8); + personality += pid_gender; + + // Difficulty is a number between 0 and 250 which directly corresponds + // to the (uniform) IV spread of the generated Pokemon. + iv = (u8)((monSpecies[i].difficulty * 31) / 255); + CreateMon(pokemon, monSpecies[i].species, monSpecies[i].level, iv, 1, (s32)personality, 2, 0); + + // If you were treating the trainer type as a bitfield, you'd put the + // checks for held item and moves here. You'd also treat the trpoke + // data as a flat u16 array rather than an array of fixed-width structs. + AddMonToParty(enemies->parties[party_id], pokemon); + } + break; + } + case TRTYPE_MON_MOVES: + { + monSpeciesMoves = &data->species_moves; + for (i = 0; i < enemies->datas[party_id].data.npoke; i++) + { + seed = monSpeciesMoves[i].difficulty + monSpeciesMoves[i].level + monSpeciesMoves[i].species + enemies->trainer_idxs[party_id]; + SetLCRNGSeed(seed); + for (j = 0; j < enemies->datas[party_id].data.trainerClass; j++) + { + seed = LCRandom(); + } + personality = (seed << 8); + personality += pid_gender; + iv = (u8)((monSpeciesMoves[i].difficulty * 31) / 255); + CreateMon(pokemon, monSpeciesMoves[i].species, monSpeciesMoves[i].level, iv, 1, (s32)personality, 2, 0); + for (j = 0; j < 4; j++) + { + MonSetMoveInSlot(pokemon, monSpeciesMoves[i].moves[j], (u8)j); + } + AddMonToParty(enemies->parties[party_id], pokemon); + } + break; + } + case TRTYPE_MON_ITEM: + { + monSpeciesItem = &data->species_item; + for (i = 0; i < enemies->datas[party_id].data.npoke; i++) + { + seed = monSpeciesItem[i].difficulty + monSpeciesItem[i].level + monSpeciesItem[i].species + enemies->trainer_idxs[party_id]; + SetLCRNGSeed(seed); + for (j = 0; j < enemies->datas[party_id].data.trainerClass; j++) + { + seed = LCRandom(); + } + personality = (seed << 8); + personality += pid_gender; + iv = (u8)((monSpeciesItem[i].difficulty * 31) / 255); + CreateMon(pokemon, monSpeciesItem[i].species, monSpeciesItem[i].level, iv, 1, (s32)personality, 2, 0); + SetMonData(pokemon, MON_DATA_HELD_ITEM, &monSpeciesItem[i].item); + AddMonToParty(enemies->parties[party_id], pokemon); + } + break; + } + case TRTYPE_MON_ITEM_MOVES: + { + monSpeciesItemMoves = &data->species_item_moves; + for (i = 0; i < enemies->datas[party_id].data.npoke; i++) + { + seed = monSpeciesItemMoves[i].difficulty + monSpeciesItemMoves[i].level + monSpeciesItemMoves[i].species + enemies->trainer_idxs[party_id]; + SetLCRNGSeed(seed); + for (j = 0; j < enemies->datas[party_id].data.trainerClass; j++) + { + seed = LCRandom(); + } + personality = (seed << 8); + personality += pid_gender; + iv = (u8)((monSpeciesItemMoves[i].difficulty * 31) / 255); + CreateMon(pokemon, monSpeciesItemMoves[i].species, monSpeciesItemMoves[i].level, iv, 1, (s32)personality, 2, 0); + SetMonData(pokemon, MON_DATA_HELD_ITEM, &monSpeciesItemMoves[i].item); + for (j = 0; j < 4; j++) + { + MonSetMoveInSlot(pokemon, monSpeciesItemMoves[i].moves[j], (u8)j); + } + AddMonToParty(enemies->parties[party_id], pokemon); + } + break; + } + } + FreeToHeap(data); + FreeToHeap(pokemon); + SetLCRNGSeed(seed_bak); +} diff --git a/arm9/src/unk_0206B688.c b/arm9/src/unk_0206B688.c new file mode 100644 index 00000000..465fa842 --- /dev/null +++ b/arm9/src/unk_0206B688.c @@ -0,0 +1,185 @@ +#include "global.h" +#include "pokemon.h" +#include "unk_0206B688.h" + +#pragma thumb on + +u16 BoxMon_GetAlternateForme(struct BoxPokemon * boxmon); +u32 FUN_0206B6D4(u32 species, u32 is_egg, u32 forme); + +u32 FUN_0206B688(struct BoxPokemon * boxmon) +{ + BOOL decry = AcquireBoxMonLock(boxmon); + u32 species = GetBoxMonData(boxmon, MON_DATA_SPECIES, NULL); + u32 is_egg = GetBoxMonData(boxmon, MON_DATA_IS_EGG, NULL); + u32 forme = BoxMon_GetAlternateForme(boxmon); + u32 ret = FUN_0206B6D4(species, is_egg, forme); + ReleaseBoxMonLock(boxmon, decry); + return ret; +} + +u32 FUN_0206B6C8(struct Pokemon * pokemon) +{ + return FUN_0206B688(FUN_020690E4(pokemon)); +} + +u32 FUN_0206B6D4(u32 species, u32 is_egg, u32 forme) +{ + if (is_egg == TRUE) + { + if (species == SPECIES_MANAPHY) + return 502; + else + return 501; + } + if (forme != 0) + { + if (species == SPECIES_DEOXYS) + return 502 + forme; + if (species == SPECIES_UNOWN) + return 506 + forme; + if (species == SPECIES_BURMY) + return 533 + forme; + if (species == SPECIES_WORMADAM) + return 535 + forme; + if (species == SPECIES_SHELLOS) + return 537 + forme; + if (species == SPECIES_GASTRODON) + return 538 + forme; + } + return (species <= SPECIES_ARCEUS ? species : 0) + 7; +} + +u16 BoxMon_GetAlternateForme(struct BoxPokemon * boxmon) +{ + u32 species = GetBoxMonData(boxmon, MON_DATA_SPECIES2, NULL); + switch (species) + { + case SPECIES_UNOWN: + return GetBoxMonUnownLetter(boxmon); + case SPECIES_DEOXYS: + case SPECIES_BURMY: + case SPECIES_WORMADAM: + case SPECIES_SHELLOS: + case SPECIES_GASTRODON: + return (u16) GetBoxMonData(boxmon, MON_DATA_FORME, NULL); + default: + return 0; + } +} + +const u8 UNK_020F8074[] = { + 0, 1, 1, 1, 0, 0, 0, 0, 2, 2, 1, 1, 0, 1, 2, 2, + 0, 0, 0, 2, 1, 0, 0, 2, 2, 2, 0, 2, 2, 2, 2, 2, + 2, 2, 2, 0, 0, 2, 1, 0, 0, 2, 2, 1, 0, 0, 0, 0, + 0, 2, 2, 2, 1, 1, 1, 2, 1, 2, 0, 0, 0, 0, 0, 2, + 2, 2, 0, 2, 0, 1, 1, 1, 2, 2, 1, 1, 1, 0, 0, 0, + 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 1, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 1, 2, 2, 1, + 1, 0, 0, 1, 0, 0, 0, 0, 2, 2, 0, 1, 2, 1, 0, 2, + 2, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 0, 1, + 0, 0, 0, 0, 0, 2, 2, 0, 1, 1, 1, 1, 1, 1, 2, 2, + 2, 2, 2, 2, 2, 0, 0, 1, 0, 2, 2, 0, 0, 0, 1, 2, + 2, 0, 0, 2, 0, 0, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, + 1, 1, 0, 0, 2, 2, 2, 0, 0, 0, 0, 1, 0, 2, 2, 2, + 0, 0, 2, 0, 0, 1, 2, 0, 0, 2, 0, 0, 2, 2, 0, 0, + 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 2, 1, 1, + 1, 1, 1, 0, 2, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 2, 0, 2, 1, 1, 1, + 1, 1, 1, 0, 2, 2, 0, 0, 1, 1, 1, 2, 0, 1, 1, 2, + 2, 1, 1, 1, 1, 0, 2, 2, 2, 1, 2, 0, 0, 2, 2, 2, + 2, 2, 2, 0, 0, 1, 0, 0, 0, 0, 2, 0, 1, 2, 0, 0, + 2, 0, 1, 0, 1, 0, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, + 2, 1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 2, 0, 0, + 1, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 2, 2, 0, 0, 0, + 0, 1, 0, 2, 2, 0, 0, 0, 0, 2, 2, 0, 0, 2, 2, 0, + 1, 0, 0, 1, 1, 1, 1, 0, 0, 2, 2, 0, 0, 0, 0, 2, + 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 2, 2, 2, 2, 2, 0, 1, 0, + 2, 0, 2, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 2, 1, 1, 0, 2, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, + 0, 2, 1, 0, 2, 1, 1, 0, 2, 2, 0, 1, 0, 2, 2, 0, + 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 0, 1, 0, 0, 0, 0, 0, 0 +}; + +u32 FUN_0206B7BC(u32 species, u32 forme, u32 is_egg) +{ + if (is_egg == TRUE) + { + if (species == SPECIES_MANAPHY) + species = 495; + else + species = 494; + } + else if (species > SPECIES_ARCEUS) + species = 0; + else if (forme != 0) + { + if (species == SPECIES_DEOXYS) + species = 495 + forme; + else if (species == SPECIES_UNOWN) + species = 498 + forme; + else if (species == SPECIES_BURMY) + species = 526 + forme; + else if (species == SPECIES_WORMADAM) + species = 528 + forme; + else if (species == SPECIES_SHELLOS) + species = 530 + forme; + else if (species == SPECIES_GASTRODON) + species = 531 + forme; + } + return UNK_020F8074[species]; +} + +u32 FUN_0206B83C(struct BoxPokemon * boxmon) +{ + BOOL decry = AcquireBoxMonLock(boxmon); + u32 forme = BoxMon_GetAlternateForme(boxmon); + u32 species = GetBoxMonData(boxmon, MON_DATA_SPECIES, NULL); + u32 is_egg = GetBoxMonData(boxmon, MON_DATA_IS_EGG, NULL); + ReleaseBoxMonLock(boxmon, decry); + return FUN_0206B7BC(species, forme, is_egg); +} + +u32 FUN_0206B87C(struct Pokemon * pokemon) +{ + return FUN_0206B83C(FUN_020690E4(pokemon)); +} + +u32 FUN_0206B888(void) +{ + return 0; +} + +u32 FUN_0206B88C(void) +{ + return 2; +} + +u32 FUN_0206B890(void) +{ + return 4; +} + +u32 FUN_0206B894(void) +{ + return 6; +} + +u32 FUN_0206B898(void) +{ + return 1; +} + +u32 FUN_0206B89C(void) +{ + return 3; +} + +u32 FUN_0206B8A0(void) +{ + return 5; +} diff --git a/arm9/src/unk_0206BB28.c b/arm9/src/unk_0206BB28.c new file mode 100644 index 00000000..baaecc6a --- /dev/null +++ b/arm9/src/unk_0206BB28.c @@ -0,0 +1,25 @@ +#include "global.h" +#include "save_block_2.h" +#include "pokedex.h" +#include "pokemon.h" +#include "unk_0206BB28.h" + +#pragma thumb on + +BOOL FUN_0206BB28(struct SaveBlock2 * sav2) +{ + return FUN_0206BB34(Sav2_Pokedex_get(sav2)); +} + +BOOL FUN_0206BB34(struct Pokedex * pokedex) +{ + return Pokedex_GetNatDexFlag(pokedex) == TRUE; +} + +u32 FUN_0206BB48(BOOL isNationalDex, u32 species) +{ + if (!isNationalDex) + species = SpeciesToSinnohDexNo((u16)species); + return species; +} + |