diff --git a/include/overlay021/ov21_021D5600.h b/include/overlay021/ov21_021D5600.h deleted file mode 100644 index ce6d8162b1..0000000000 --- a/include/overlay021/ov21_021D5600.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef POKEPLATINUM_OV21_021D5600_H -#define POKEPLATINUM_OV21_021D5600_H - -#include "strbuf.h" - -void ov21_021D5600(Strbuf *param0); -int ov21_021D5608(int param0); -Strbuf *ov21_021D561C(int param0, int param1, int param2); -Strbuf *ov21_021D566C(int param0, int param1, int param2); -Strbuf *ov21_021D56BC(int param0, int param1, int param2, int param3); - -#endif // POKEPLATINUM_OV21_021D5600_H diff --git a/include/overlay021/pokedex_text.h b/include/overlay021/pokedex_text.h new file mode 100644 index 0000000000..5341d1f771 --- /dev/null +++ b/include/overlay021/pokedex_text.h @@ -0,0 +1,12 @@ +#ifndef POKEPLATINUM_POKEDEX_TEXT_H +#define POKEPLATINUM_POKEDEX_TEXT_H + +#include "strbuf.h" + +void PokedexText_Free(Strbuf *strbuf); +int PokedexText_ForeignLanguage(int languageIndex); +Strbuf *PokedexText_NameNumber(int species, int language, int heapID); +Strbuf *PokedexText_Category(int species, int language, int heapID); +Strbuf *PokedexText_DexEntry(int species, int language, int entryOffset, int heapID); + +#endif // POKEPLATINUM_POKEDEX_TEXT_H diff --git a/include/pokedex_language.h b/include/pokedex_language.h new file mode 100644 index 0000000000..aac8e1ed4b --- /dev/null +++ b/include/pokedex_language.h @@ -0,0 +1,9 @@ +#ifndef POKEPLATINUM_POKEDEX_LANGUAGE_H +#define POKEPLATINUM_POKEDEX_LANGUAGE_H + +#define NUM_LANGUAGES 6 + +int PokedexLanguage_LanguageToIndex(int language); +int PokedexLanguage_IndexToLanguage(int languageIndex); + +#endif // POKEPLATINUM_POKEDEX_LANGUAGE_H diff --git a/include/unk_020986CC.h b/include/unk_020986CC.h deleted file mode 100644 index 83754ec113..0000000000 --- a/include/unk_020986CC.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef POKEPLATINUM_UNK_020986CC_H -#define POKEPLATINUM_UNK_020986CC_H - -int sub_020986CC(int param0); -int sub_020986E8(int param0); - -#endif // POKEPLATINUM_UNK_020986CC_H diff --git a/platinum.us/main.lsf b/platinum.us/main.lsf index 7df1d10797..540ad25de6 100644 --- a/platinum.us/main.lsf +++ b/platinum.us/main.lsf @@ -339,7 +339,7 @@ Static main Object main.nef.p/src_unk_02097B18.c.o Object main.nef.p/src_unk_02098218.c.o Object main.nef.p/src_unk_020985E4.c.o - Object main.nef.p/src_unk_020986CC.c.o + Object main.nef.p/src_pokedex_language.c.o Object main.nef.p/src_pokedex_heightweight.c.o Object main.nef.p/src_pokedex_data_index.c.o Object main.nef.p/src_unk_020F6824.c.o @@ -792,7 +792,7 @@ Overlay overlay21 Object main.nef.p/src_overlay021_ov21_021D4C0C.c.o Object main.nef.p/src_overlay021_ov21_021D4EE4.c.o Object main.nef.p/src_overlay021_pokedex_field_map.c.o - Object main.nef.p/src_overlay021_ov21_021D5600.c.o + Object main.nef.p/src_overlay021_pokedex_text.c.o Object main.nef.p/src_overlay021_pokedex_enc_data.c.o Object main.nef.p/src_overlay021_ov21_021D5AEC.c.o Object main.nef.p/src_overlay021_ov21_021D76B0.c.o diff --git a/src/meson.build b/src/meson.build index 785fefdc3e..4dc69f15fb 100644 --- a/src/meson.build +++ b/src/meson.build @@ -323,7 +323,7 @@ pokeplatinum_c = files( 'unk_02097B18.c', 'unk_02098218.c', 'unk_020985E4.c', - 'unk_020986CC.c', + 'pokedex_language.c', 'pokedex_heightweight.c', 'pokedex_data_index.c', 'unk_020989DC.c', @@ -603,7 +603,7 @@ pokeplatinum_c = files( 'overlay021/ov21_021D4C0C.c', 'overlay021/ov21_021D4EE4.c', 'overlay021/pokedex_field_map.c', - 'overlay021/ov21_021D5600.c', + 'overlay021/pokedex_text.c', 'overlay021/pokedex_enc_data.c', 'overlay021/ov21_021D5AEC.c', 'overlay021/ov21_021D76B0.c', diff --git a/src/overlay021/ov21_021D0D80.c b/src/overlay021/ov21_021D0D80.c index a638a00a09..15af6b2624 100644 --- a/src/overlay021/ov21_021D0D80.c +++ b/src/overlay021/ov21_021D0D80.c @@ -14,7 +14,6 @@ #include "overlay021/ov21_021D423C.h" #include "overlay021/ov21_021D4340.h" #include "overlay021/ov21_021D4C0C.h" -#include "overlay021/ov21_021D5600.h" #include "overlay021/ov21_021D5AEC.h" #include "overlay021/ov21_021D76B0.h" #include "overlay021/ov21_021D85B0.h" @@ -33,6 +32,7 @@ #include "overlay021/ov21_021E737C.h" #include "overlay021/ov21_021E8484.h" #include "overlay021/pokedex_sort.h" +#include "overlay021/pokedex_text.h" #include "overlay021/species_caught_status.h" #include "overlay021/struct_ov21_021D0D80.h" #include "overlay021/struct_ov21_021D13FC.h" @@ -664,13 +664,13 @@ void ov21_021D1650(Window *param0, int param1, int param2, int param3) v0 = ov21_021D1CE0(100, param3); } - v1 = ov21_021D561C(param2, GAME_LANGUAGE, param3); + v1 = PokedexText_NameNumber(param2, GAME_LANGUAGE, param3); Text_AddPrinterWithParamsAndColor(param0, FONT_SUBSCREEN, v0, 22, 0, TEXT_SPEED_NO_TRANSFER, TEXT_COLOR(3, 2, 1), NULL); Text_AddPrinterWithParamsAndColor(param0, FONT_SUBSCREEN, v1, 49, 0, TEXT_SPEED_NO_TRANSFER, TEXT_COLOR(3, 2, 1), NULL); Strbuf_Free(v0); - ov21_021D5600(v1); + PokedexText_Free(v1); } Window *ov21_021D16D8(UnkStruct_ov21_021D13FC *param0, const UnkStruct_ov21_021D3320 *param1, int param2, int param3) diff --git a/src/overlay021/ov21_021D5600.c b/src/overlay021/ov21_021D5600.c deleted file mode 100644 index 2774da071e..0000000000 --- a/src/overlay021/ov21_021D5600.c +++ /dev/null @@ -1,168 +0,0 @@ -#include "overlay021/ov21_021D5600.h" - -#include -#include - -#include "constants/narc.h" -#include "constants/species.h" - -#include "error_handling.h" -#include "inlines.h" -#include "message.h" -#include "message_util.h" -#include "strbuf.h" -#include "unk_020986CC.h" - -static const u8 Unk_ov21_021E9CC4[6] = { - 0x1, - 0x2, - 0x3, - 0x4, - 0x5, - 0x0 -}; - -static inline int inline_ov21_021D5764(int param0); -static inline BOOL inline_ov21_021D5764_1(int param0, int param1); -static Strbuf *LoadMessage(int param0, int param1, int param2); -static void ov21_021D5764(int param0, int param1, int *param2, int *param3, int *param4); - -void ov21_021D5600(Strbuf *param0) -{ - Strbuf_Free(param0); -} - -int ov21_021D5608(int param0) -{ - return sub_020986E8(Unk_ov21_021E9CC4[param0 + 1]); -} - -Strbuf *ov21_021D561C(int param0, int param1, int param2) -{ - int v0; - int v1; - int v2; - int v3; - - ov21_021D5764(param0, param1, &v0, &v1, &v2); - - if (v2 == 6) { - return MessageUtil_SpeciesName(param0, param2); - } else { - const int Unk_ov21_021E9CCC[] = { - 0x2CD, - 0x2C8, - 0x2C9, - 0x2CA, - 0x2CB, - 0x2CC - }; - v3 = Unk_ov21_021E9CCC[v2]; - v2 = v0; - } - - return LoadMessage(v3, v2, param2); -} - -Strbuf *ov21_021D566C(int param0, int param1, int param2) -{ - int v0; - int v1; - int v2; - int v3; - - ov21_021D5764(param0, param1, &v0, &v1, &v2); - - if (v2 == 6) { - v2 = param0; - v3 = 711; - } else { - const int Unk_ov21_021E9CE4[] = { - 0x2D3, - 0x2CE, - 0x2CF, - 0x2D0, - 0x2D1, - 0x2D2 - }; - v3 = Unk_ov21_021E9CE4[v2]; - v2 = v0; - } - - return LoadMessage(v3, v2, param2); -} - -Strbuf *ov21_021D56BC(int param0, int param1, int param2, int param3) -{ - int v0; - int v1; - int v2; - int v3; - - ov21_021D5764(param0, param1, &v0, &v1, &v2); - - if (v2 == 6) { - GF_ASSERT(param2 < 1); - v2 = param0 * 1 + param2; - v3 = 706; - } else { - const int Unk_ov21_021E9CFC[] = { - 0x2C1, - 0x2BC, - 0x2BD, - 0x2BE, - 0x2BF, - 0x2C0 - }; - GF_ASSERT(param2 < 1); - v3 = Unk_ov21_021E9CFC[v2]; - v2 = v0 * 1 + param2; - } - - return LoadMessage(v3, v2, param3); -} - -static inline BOOL inline_ov21_021D5764_1(int param0, int param1) -{ - if ((param0 > NATIONAL_DEX_COUNT) && (param1 != 6)) { - return 0; - } - - return 1; -} - -static Strbuf *LoadMessage(int bankID, int entryID, int heapID) -{ - MessageLoader *messageLoader = MessageLoader_Init(1, NARC_INDEX_MSGDATA__PL_MSG, bankID, heapID); - - if (messageLoader) { - Strbuf *strbuf = Strbuf_Init(256, heapID); - - if (strbuf) { - MessageLoader_GetStrbuf(messageLoader, entryID, strbuf); - } - - MessageLoader_Free(messageLoader); - return strbuf; - } - - return NULL; -} - -static void ov21_021D5764(int param0, int param1, int *param2, int *param3, int *param4) -{ - *param3 = sub_020986CC(param1); - - GF_ASSERT(*param3 < 6); - - *param2 = param0; - *param4 = inline_ov21_021D5764(*param3); - - GF_ASSERT(inline_ov21_021D5764_1(*param2, *param4)); -} - -static inline int inline_ov21_021D5764(int param0) -{ - GF_ASSERT(param0 < 6); - return (param0 == 1) ? 6 : param0; -} diff --git a/src/overlay021/ov21_021DE668.c b/src/overlay021/ov21_021DE668.c index cde9243932..432b0a48a4 100644 --- a/src/overlay021/ov21_021DE668.c +++ b/src/overlay021/ov21_021DE668.c @@ -9,9 +9,9 @@ #include "overlay021/ov21_021D1F90.h" #include "overlay021/ov21_021D1FA4.h" #include "overlay021/ov21_021D4C0C.h" -#include "overlay021/ov21_021D5600.h" #include "overlay021/ov21_021E29DC.h" #include "overlay021/pokedex_sort.h" +#include "overlay021/pokedex_text.h" #include "overlay021/struct_ov21_021D0F60_decl.h" #include "overlay021/struct_ov21_021D13FC.h" #include "overlay021/struct_ov21_021D2648.h" @@ -469,12 +469,12 @@ static void ov21_021DEC80(Window *param0, int param1, int param2, u32 param3) static void ov21_021DECD4(Window *param0, int param1, int param2, int param3, u32 param4) { - Strbuf *v0 = ov21_021D56BC(param2, GAME_LANGUAGE, param3, param1); + Strbuf *v0 = PokedexText_DexEntry(param2, GAME_LANGUAGE, param3, param1); u32 v1 = Font_CalcMaxLineWidth(FONT_SYSTEM, v0, 0); u32 v2 = (v1 < 240) ? 128 - v1 / 2 : 8; Text_AddPrinterWithParamsAndColor(param0, FONT_SYSTEM, v0, v2, 136, TEXT_SPEED_INSTANT, param4, NULL); - ov21_021D5600(v0); + PokedexText_Free(v0); } static void ov21_021DED24(UnkStruct_ov21_021DF374 *param0, UnkStruct_ov21_021DE760 *param1, const UnkStruct_ov21_021DE6D4 *param2, int param3) @@ -785,7 +785,7 @@ Window *ov21_021DF30C(UnkStruct_ov21_021D4C0C *param0, int param1, int param2) Strbuf *v1; v0 = ov21_021D4D6C(param0, 18, 2); - v1 = ov21_021D566C(param1, GAME_LANGUAGE, param2); + v1 = PokedexText_Category(param1, GAME_LANGUAGE, param2); { u32 v2 = Font_CalcStrbufWidth(FONT_SUBSCREEN, v1, 0); @@ -794,7 +794,7 @@ Window *ov21_021DF30C(UnkStruct_ov21_021D4C0C *param0, int param1, int param2) ov21_021D4E80(param0, v0, v1, v3, 0); } - ov21_021D5600(v1); + PokedexText_Free(v1); return v0; } diff --git a/src/overlay021/ov21_021E0C68.c b/src/overlay021/ov21_021E0C68.c index e07788233e..37b5d85f68 100644 --- a/src/overlay021/ov21_021E0C68.c +++ b/src/overlay021/ov21_021E0C68.c @@ -8,9 +8,9 @@ #include "overlay021/ov21_021D0D80.h" #include "overlay021/ov21_021D1FA4.h" #include "overlay021/ov21_021D4C0C.h" -#include "overlay021/ov21_021D5600.h" #include "overlay021/ov21_021E29DC.h" #include "overlay021/pokedex_sort.h" +#include "overlay021/pokedex_text.h" #include "overlay021/struct_ov21_021D0F60_decl.h" #include "overlay021/struct_ov21_021D13FC.h" #include "overlay021/struct_ov21_021D2648.h" @@ -445,12 +445,12 @@ static void ov21_021E10D0(UnkStruct_ov21_021E0D7C *param0, const UnkStruct_ov21_ static void ov21_021E1188(UnkStruct_ov21_021E0D7C *param0, int param1, int param2, int param3, int param4) { - Strbuf *v0 = ov21_021D56BC(param2, param3, param4, param1); + Strbuf *v0 = PokedexText_DexEntry(param2, param3, param4, param1); u32 v1 = Font_CalcMaxLineWidth(FONT_SYSTEM, v0, 0); u32 v2 = (v1 < 240) ? 128 - v1 / 2 : 8; Text_AddPrinterWithParamsAndColor(¶m0->unk_00->unk_04, FONT_SYSTEM, v0, v2, 136, TEXT_SPEED_INSTANT, TEXT_COLOR(2, 1, 0), NULL); - ov21_021D5600(v0); + PokedexText_Free(v0); } static void ov21_021E11DC(UnkStruct_ov21_021E0D7C *param0, const UnkStruct_ov21_021E0D68 *param1, int param2) @@ -567,7 +567,7 @@ static Window *ov21_021E1460(UnkStruct_ov21_021E0D7C *param0, int param1, int pa Strbuf *v1; v0 = ov21_021D4D6C(param0->unk_00->unk_14C, 18, 2); - v1 = ov21_021D566C(param1, GAME_LANGUAGE, param2); + v1 = PokedexText_Category(param1, GAME_LANGUAGE, param2); { u32 v2 = Font_CalcStrbufWidth(FONT_SUBSCREEN, v1, 0); @@ -575,7 +575,7 @@ static Window *ov21_021E1460(UnkStruct_ov21_021E0D7C *param0, int param1, int pa ov21_021D4E80(param0->unk_00->unk_14C, v0, v1, v3, 0); } - ov21_021D5600(v1); + PokedexText_Free(v1); return v0; } @@ -818,19 +818,19 @@ static int ov21_021E185C(int param0) static void ov21_021E18A0(UnkStruct_ov21_021E0D7C *param0, int param1, int param2, int param3) { - Strbuf *v0 = ov21_021D561C(param2, param3, param1); + Strbuf *v0 = PokedexText_NameNumber(param2, param3, param1); Text_AddPrinterWithParamsAndColor(¶m0->unk_00->unk_04, FONT_SYSTEM, v0, 120, 96, TEXT_SPEED_INSTANT, TEXT_COLOR(2, 1, 0), NULL); - ov21_021D5600(v0); + PokedexText_Free(v0); } static void ov21_021E18DC(UnkStruct_ov21_021E0D7C *param0, int param1, int param2, int param3) { - Strbuf *v0 = ov21_021D566C(param2, param3, param1); + Strbuf *v0 = PokedexText_Category(param2, param3, param1); u32 v1; v1 = 240 - Font_CalcStrbufWidth(FONT_SYSTEM, v0, 0); Text_AddPrinterWithParamsAndColor(¶m0->unk_00->unk_04, FONT_SYSTEM, v0, v1, 112, TEXT_SPEED_INSTANT, TEXT_COLOR(2, 1, 0), NULL); - ov21_021D5600(v0); + PokedexText_Free(v0); } diff --git a/src/overlay021/ov21_021E1924.c b/src/overlay021/ov21_021E1924.c index 5b2cea0af7..403a22bda2 100644 --- a/src/overlay021/ov21_021E1924.c +++ b/src/overlay021/ov21_021E1924.c @@ -9,11 +9,11 @@ #include "overlay021/ov21_021D1FA4.h" #include "overlay021/ov21_021D4340.h" #include "overlay021/ov21_021D4C0C.h" -#include "overlay021/ov21_021D5600.h" #include "overlay021/ov21_021DE668.h" #include "overlay021/ov21_021E0C68.h" #include "overlay021/ov21_021E29DC.h" #include "overlay021/pokedex_sort.h" +#include "overlay021/pokedex_text.h" #include "overlay021/struct_ov21_021D0F60_decl.h" #include "overlay021/struct_ov21_021D13FC.h" #include "overlay021/struct_ov21_021D3320.h" @@ -1019,7 +1019,7 @@ static void ov21_021E27C0(UnkStruct_ov21_021E1E74 *param0, UnkStruct_ov21_021E1A v1 = 72; ov21_021E0CDC(param1->unk_10, 2); - v2 = ov21_021D5608(param3 - 1); + v2 = PokedexText_ForeignLanguage(param3 - 1); ov21_021E0CF8(param1->unk_10, v2); break; default: @@ -1127,7 +1127,7 @@ static void ov21_021E2968(UnkStruct_ov21_021E1E74 *param0, UnkStruct_ov21_021E1A param0->unk_38 = 0; for (v1 = 0; v1 < (6 - 1); v1++) { - v2 = ov21_021D5608(v1); + v2 = PokedexText_ForeignLanguage(v1); v0 = ov21_021D392C(param1->unk_04, v2); if (v0) { diff --git a/src/overlay021/pokedex_text.c b/src/overlay021/pokedex_text.c new file mode 100644 index 0000000000..26ac94a1a3 --- /dev/null +++ b/src/overlay021/pokedex_text.c @@ -0,0 +1,179 @@ +#include "overlay021/pokedex_text.h" + +#include +#include + +#include "constants/narc.h" +#include "constants/species.h" + +#include "text/pl_msg.naix" + +#include "error_handling.h" +#include "inlines.h" +#include "message.h" +#include "message_util.h" +#include "pokedex_language.h" +#include "strbuf.h" + +enum LangIndex { + LI_JAPANESE, + LI_ENGLISH, + LI_FRENCH, + LI_GERMAN, + LI_ITALIAN, + LI_SPANISH +}; + +static const u8 messageBankLanguageOrder[NUM_LANGUAGES] = { + LI_ENGLISH, + LI_FRENCH, + LI_GERMAN, + LI_ITALIAN, + LI_SPANISH, + LI_JAPANESE +}; + +static inline int LanguageIndex_Guarded(int languageIndex); +static inline BOOL ValidLanguage(int species, int languageIndex); +static Strbuf *LoadMessage(int bankID, int entryID, int heapID); +static void GetLanguageIndex(int species, int language, int *dexNum, int *languageIndexUnguarded, int *languageIndex); + +void PokedexText_Free(Strbuf *strbuf) +{ + Strbuf_Free(strbuf); +} + +int PokedexText_ForeignLanguage(int languageIndex) +{ + return PokedexLanguage_IndexToLanguage(messageBankLanguageOrder[languageIndex + 1]); +} + +Strbuf *PokedexText_NameNumber(int species, int language, int heapID) +{ + int dexNum; + int languageIndex_unguarded; + int index; + int bankID; + + GetLanguageIndex(species, language, &dexNum, &languageIndex_unguarded, &index); + + if (index == NUM_LANGUAGES) { + return MessageUtil_SpeciesName(species, heapID); + } else { + const int nameNumberBanks[] = { + message_bank_unk_0717, + message_bank_species_name_number_1, + message_bank_unk_0713, + message_bank_unk_0714, + message_bank_species_name_number_2, + message_bank_species_name_number_3 + }; + bankID = nameNumberBanks[index]; + index = dexNum; + } + + return LoadMessage(bankID, index, heapID); +} + +Strbuf *PokedexText_Category(int species, int language, int heapID) +{ + int dexNum; + int languageIndex_unguarded; + int index; + int bankID; + + GetLanguageIndex(species, language, &dexNum, &languageIndex_unguarded, &index); + + if (index == NUM_LANGUAGES) { + index = species; + bankID = message_bank_unk_0711; + } else { + const int categoryBanks[] = { + message_bank_unk_0723, + message_bank_species_category, + message_bank_unk_0719, + message_bank_unk_0720, + message_bank_unk_0721, + message_bank_unk_0722 + }; + bankID = categoryBanks[index]; + index = dexNum; + } + + return LoadMessage(bankID, index, heapID); +} + +Strbuf *PokedexText_DexEntry(int species, int language, int entryOffset, int heapID) +{ + int dexNum; + int languageIndex_unguarded; + int index; + int bankID; + + GetLanguageIndex(species, language, &dexNum, &languageIndex_unguarded, &index); + + if (index == NUM_LANGUAGES) { + GF_ASSERT(entryOffset < 1); + index = species + entryOffset; + bankID = message_bank_species_dex_entry; + } else { + const int dexEntryBanks[] = { + message_bank_unk_0705, + message_bank_unk_0700, + message_bank_unk_0701, + message_bank_unk_0702, + message_bank_unk_0703, + message_bank_unk_0704 + }; + GF_ASSERT(entryOffset < 1); + bankID = dexEntryBanks[index]; + index = dexNum + entryOffset; + } + + return LoadMessage(bankID, index, heapID); +} + +static inline BOOL ValidLanguage(int species, int languageIndex) +{ + if ((species > NATIONAL_DEX_COUNT) && (languageIndex != NUM_LANGUAGES)) { + return FALSE; + } + + return TRUE; +} + +static Strbuf *LoadMessage(int bankID, int entryID, int heapID) +{ + MessageLoader *messageLoader = MessageLoader_Init(MESSAGE_LOADER_NARC_HANDLE, NARC_INDEX_MSGDATA__PL_MSG, bankID, heapID); + + if (messageLoader) { + Strbuf *strbuf = Strbuf_Init(256, heapID); + + if (strbuf) { + MessageLoader_GetStrbuf(messageLoader, entryID, strbuf); + } + + MessageLoader_Free(messageLoader); + return strbuf; + } + + return NULL; +} + +static void GetLanguageIndex(int species, int language, int *dexNum, int *languageIndexUnguarded, int *languageIndex) +{ + *languageIndexUnguarded = PokedexLanguage_LanguageToIndex(language); + + GF_ASSERT(*languageIndexUnguarded < NUM_LANGUAGES); + + *dexNum = species; + *languageIndex = LanguageIndex_Guarded(*languageIndexUnguarded); + + GF_ASSERT(ValidLanguage(*dexNum, *languageIndex)); +} + +static inline int LanguageIndex_Guarded(int languageIndex) +{ + GF_ASSERT(languageIndex < NUM_LANGUAGES); + return (languageIndex == LI_ENGLISH) ? NUM_LANGUAGES : languageIndex; +} diff --git a/src/pokedex_data.c b/src/pokedex_data.c new file mode 100644 index 0000000000..6f189bfc3d --- /dev/null +++ b/src/pokedex_data.c @@ -0,0 +1,1240 @@ +#include "pokedex_data.h" + +#include +#include + +#include "constants/species.h" + +#include "heap.h" +#include "inlines.h" +#include "pokedex_language.h" +#include "pokemon.h" +#include "savedata.h" + +#define DEX_SIZE_U32 ((int)((NATIONAL_DEX_COUNT - 1) / 32) + 1) // default 16 +#define MAGIC_NUMBER 3203386110 +#define NUM_MYTHICALS_NATIONAL 11 +#define NATIONAL_DEX_GOAL (NATIONAL_DEX_COUNT - NUM_MYTHICALS_NATIONAL) +#define UNOWN_COUNT 28 +#define DEOXYS_COUNT 4 +#define ROTOM_COUNT 6 +#define TERMINAL_4BITS 0x7 +#define TERMINAL_BYTE 0xf +#define TERMINAL_U8 0xff +#define TERMINAL_U32 0xffffffff + +typedef struct PokedexData { + u32 magic; + u32 caughtPokemon[DEX_SIZE_U32]; + u32 seenPokemon[DEX_SIZE_U32]; + u32 recordedGenders[2][DEX_SIZE_U32]; + u32 spindaForms; + u8 shellosForms; + u8 gastrodonForms; + u8 burmyForms; + u8 wormadamForms; + u8 unownForms[UNOWN_COUNT]; + u8 recordedLanguages[MAX_SPECIES + 1]; + u8 canDetectForms; + u8 canDetectLanguages; + u8 pokedexObtained; + u8 nationalDexObtained; + u32 rotomForms; + u8 shayminForms; + u8 giratinaForms; +} PokedexData; + +int PokedexData_SaveSize(void) +{ + return sizeof(PokedexData); +} + +PokedexData *PokedexData_Alloc(u32 heapID) +{ + PokedexData *pokedexData = Heap_AllocFromHeap(heapID, sizeof(PokedexData)); + PokedexData_Init(pokedexData); + + return pokedexData; +} + +void PokedexData_Copy(const PokedexData *src, PokedexData *dest) +{ + MI_CpuCopy8(src, dest, sizeof(PokedexData)); +} + +static inline void CheckPokedexIntegrity(const PokedexData *pokedexData) +{ + GF_ASSERT(pokedexData->magic == MAGIC_NUMBER); +} + +static BOOL SpeciesInvalid(u16 species) +{ + if (species == SPECIES_NONE || species > NATIONAL_DEX_COUNT) { + GF_ASSERT(FALSE); + return TRUE; + } else { + return FALSE; + } +} + +static inline BOOL ReadBit_2Forms(const u8 *array, u16 bitIndex) +{ + bitIndex--; + return 0 != (array[bitIndex >> 0x3] & (1 << (bitIndex & 0x7))); +} + +static inline void ActivateBit_2Forms(u8 *array, u16 bitIndex) +{ + bitIndex--; + array[bitIndex >> 0x3] |= 1 << (bitIndex & 0x7); +} + +static inline void SetBit_2Forms(u8 *array, u8 value, u16 bitIndex) +{ + GF_ASSERT(value < 2); + + bitIndex--; + + array[bitIndex >> 0x3] &= ~(1 << (bitIndex & 0x7)); + array[bitIndex >> 0x3] |= value << (bitIndex & 0x7); +} + +static inline u32 ReadBit_3Forms(const u8 *array, u16 bitIndex) +{ + return (array[bitIndex >> 2] >> ((bitIndex & 0x3) * 2)) & 0x3; +} + +static inline void SetBit_3Forms(u8 *array, u8 value, u16 bitIndex) +{ + GF_ASSERT(value < 4); + + array[bitIndex >> 2] &= ~(0x3 << ((bitIndex & 0x3) * 2)); + array[bitIndex >> 2] |= value << ((bitIndex & 0x3) * 2); +} + +static inline void Write_SeenSpecies(PokedexData *pokedexData, u16 species) +{ + ActivateBit_2Forms((u8 *)pokedexData->seenPokemon, species); +} + +static inline void Write_CaughtSpecies(PokedexData *pokedexData, u16 species) +{ + ActivateBit_2Forms((u8 *)pokedexData->caughtPokemon, species); +} + +static void SetBit_Gender(PokedexData *pokedexData, u8 gender, u8 isSeen, u16 bitIndex) +{ + if (isSeen == FALSE) { + SetBit_2Forms((u8 *)pokedexData->recordedGenders[1], gender, bitIndex); + } + + SetBit_2Forms((u8 *)pokedexData->recordedGenders[isSeen], gender, bitIndex); +} + +static void UpdateGender(PokedexData *pokedexData, u8 gender, u8 isSeen, u16 bitIndex) +{ + GF_ASSERT(gender <= 2); + + if (gender == GENDER_NONE) { + gender = GENDER_MALE; + } + + SetBit_Gender(pokedexData, gender, isSeen, bitIndex); +} + +static inline BOOL SpeciesSeen(const PokedexData *pokedexData, u16 species) +{ + return ReadBit_2Forms((const u8 *)pokedexData->seenPokemon, species); +} + +static inline BOOL SpeciesCaught(const PokedexData *pokedexData, u16 species) +{ + return ReadBit_2Forms((const u8 *)pokedexData->caughtPokemon, species); +} + +static inline u8 GetGender(const PokedexData *pokedexData, u16 species, u8 bitIndex) +{ + return ReadBit_2Forms((const u8 *)pokedexData->recordedGenders[bitIndex], species); +} + +static inline void SetForm_Spinda(PokedexData *pokedexData, u16 species, u32 personality) +{ + if (species == SPECIES_SPINDA) { + pokedexData->spindaForms = personality; + } +} + +static int NumFormsSeen_Unown(const PokedexData *pokedexData) +{ + int formIndex; + + for (formIndex = 0; formIndex < UNOWN_COUNT; formIndex++) { + if (pokedexData->unownForms[formIndex] == TERMINAL_U8) { + break; + } + } + + return formIndex; +} + +static BOOL UnownFormSeen(const PokedexData *pokedexData, u8 form) +{ + for (int formIndex = 0; formIndex < UNOWN_COUNT; formIndex++) { + if (pokedexData->unownForms[formIndex] == form) { + return TRUE; + } + } + + return FALSE; +} + +static void SetUnownForm(PokedexData *pokedexData, int form) +{ + if (UnownFormSeen(pokedexData, form)) { + return; + } + + int numUnownSeen = NumFormsSeen_Unown(pokedexData); + + if (numUnownSeen < UNOWN_COUNT) { + pokedexData->unownForms[numUnownSeen] = form; + } +} + +static int NumFormsSeen_TwoForms(const PokedexData *pokedexData, u32 species) +{ + GF_ASSERT((species == SPECIES_SHELLOS) || (species == SPECIES_GASTRODON) || (species == SPECIES_SHAYMIN) || (species == SPECIES_GIRATINA)); + + if (PokedexData_HasSeenSpecies(pokedexData, species) == FALSE) { + return 0; + } + + const u8 *formArray; + switch (species) { + case SPECIES_SHELLOS: + formArray = &pokedexData->shellosForms; + break; + case SPECIES_GASTRODON: + formArray = &pokedexData->gastrodonForms; + break; + case SPECIES_SHAYMIN: + formArray = &pokedexData->shayminForms; + break; + case SPECIES_GIRATINA: + formArray = &pokedexData->giratinaForms; + break; + } + + u32 form_1 = ReadBit_2Forms(formArray, 1); + u32 form_2 = ReadBit_2Forms(formArray, 2); + + if (form_1 == form_2) { + return 1; + } + + return 2; +} + +static BOOL FormSeen_TwoForms(const PokedexData *pokedexData, u32 species, u8 form) +{ + GF_ASSERT((species == SPECIES_SHELLOS) || (species == SPECIES_GASTRODON) || (species == SPECIES_SHAYMIN) || (species == SPECIES_GIRATINA)); + + if (PokedexData_HasSeenSpecies(pokedexData, species) == FALSE) { + return FALSE; + } + + const u8 *formArray; + switch (species) { + case SPECIES_SHELLOS: + formArray = &pokedexData->shellosForms; + break; + case SPECIES_GASTRODON: + formArray = &pokedexData->gastrodonForms; + break; + case SPECIES_SHAYMIN: + formArray = &pokedexData->shayminForms; + break; + case SPECIES_GIRATINA: + formArray = &pokedexData->giratinaForms; + break; + } + + u32 numFormsSeen = NumFormsSeen_TwoForms(pokedexData, species); + + for (u32 formIndex = 0; formIndex < numFormsSeen; formIndex++) { + u32 currentForm = ReadBit_2Forms(formArray, formIndex + 1); + + if (currentForm == form) { + return TRUE; + } + } + + return FALSE; +} + +static void UpdateForms_TwoForms(PokedexData *pokedexData, u32 species, int form) +{ + GF_ASSERT((species == SPECIES_SHELLOS) || (species == SPECIES_GASTRODON) || (species == SPECIES_SHAYMIN) || (species == SPECIES_GIRATINA)); + + if (FormSeen_TwoForms(pokedexData, species, form)) { + return; + } + + u8 *formArray; + switch (species) { + case SPECIES_SHELLOS: + formArray = &pokedexData->shellosForms; + break; + case SPECIES_GASTRODON: + formArray = &pokedexData->gastrodonForms; + break; + case SPECIES_SHAYMIN: + formArray = &pokedexData->shayminForms; + break; + case SPECIES_GIRATINA: + formArray = &pokedexData->giratinaForms; + break; + } + + int numFormsSeen = NumFormsSeen_TwoForms(pokedexData, species); + + if (numFormsSeen < 2) { + SetBit_2Forms(formArray, form, numFormsSeen + 1); + + if (numFormsSeen == 0) { + SetBit_2Forms(formArray, form, numFormsSeen + 2); + } + } +} + +static int NumFormsSeen_ThreeForms(const PokedexData *pokedexData, u32 species) +{ + GF_ASSERT((species == SPECIES_BURMY) || (species == SPECIES_WORMADAM)); + + if (PokedexData_HasSeenSpecies(pokedexData, species) == FALSE) { + return 0; + } + + const u8 *formArray; + if (species == SPECIES_BURMY) { + formArray = &pokedexData->burmyForms; + } else { + formArray = &pokedexData->wormadamForms; + } + + int formIndex; + for (formIndex = 0; formIndex < 3; formIndex++) { + u32 currentForm = ReadBit_3Forms(formArray, formIndex); + + if (currentForm == 3) { + break; + } + } + + return formIndex; +} + +static BOOL FormSeen_ThreeForms(const PokedexData *pokedexData, u32 species, u8 form) +{ + GF_ASSERT((species == SPECIES_BURMY) || (species == SPECIES_WORMADAM)); + + if (PokedexData_HasSeenSpecies(pokedexData, species) == FALSE) { + return FALSE; + } + + const u8 *formArray; + if (species == SPECIES_BURMY) { + formArray = &pokedexData->burmyForms; + } else { + formArray = &pokedexData->wormadamForms; + } + + for (int formIndex = 0; formIndex < 3; formIndex++) { + u32 currentForm = ReadBit_3Forms(formArray, formIndex); + + if (currentForm == form) { + return TRUE; + } + } + + return FALSE; +} + +static void UpdateForms_ThreeForms(PokedexData *pokedexData, u32 species, int form) +{ + GF_ASSERT((species == SPECIES_BURMY) || (species == SPECIES_WORMADAM)); + + if (FormSeen_ThreeForms(pokedexData, species, form)) { + return; + } + + u8 *formArray; + if (species == SPECIES_BURMY) { + formArray = &pokedexData->burmyForms; + } else { + formArray = &pokedexData->wormadamForms; + } + + int numFormsSeen = NumFormsSeen_ThreeForms(pokedexData, species); + + if (numFormsSeen < 3) { + SetBit_3Forms(formArray, form, numFormsSeen); + } +} + +static void WriteBit_Deoxys(u32 *array, u8 value, u8 bitIndex) +{ + u32 bitOffset = (24 + (bitIndex * 4)); + u32 emptyBits = ~(0xf << bitOffset); + + array[DEX_SIZE_U32 - 1] &= emptyBits; + array[DEX_SIZE_U32 - 1] |= (value << bitOffset); +} + +static void UpdateFormArray_Deoxys(PokedexData *pokedexData, u8 form, u8 bitIndex) +{ + // Deoxys forms are currently stored in spare bits in these arrays + // This will want to be changed when modding to avoid overlapping references + + GF_ASSERT(bitIndex < DEOXYS_COUNT); + GF_ASSERT(form <= TERMINAL_BYTE); + + if (bitIndex < 2) { + WriteBit_Deoxys(pokedexData->caughtPokemon, form, bitIndex); + } else { + WriteBit_Deoxys(pokedexData->seenPokemon, form, bitIndex - 2); + } +} + +static inline u32 ReadBit_Deoxys(const u32 *array, u8 bitIndex) +{ + u32 bitOffset = (24 + (bitIndex * 4)); + u32 form = (array[DEX_SIZE_U32 - 1] >> bitOffset) & 0xf; + + return form; +} + +static u32 GetForm_Deoxys(const PokedexData *pokedexData, u8 formIndex) +{ + // Deoxys forms are currently stored in spare bits in these arrays + // This will want to be changed when modding to avoid overlapping references + + u32 form; + if (formIndex < 2) { + form = ReadBit_Deoxys(pokedexData->caughtPokemon, formIndex); + } else { + form = ReadBit_Deoxys(pokedexData->seenPokemon, formIndex - 2); + } + + return form; +} + +static u32 NumFormsSeen_Deoxys(const PokedexData *pokedexData) +{ + int formIndex; + + for (formIndex = 0; formIndex < DEOXYS_COUNT; formIndex++) { + if (GetForm_Deoxys(pokedexData, formIndex) == TERMINAL_BYTE) { + break; + } + } + + return formIndex; +} + +static BOOL FormSeen_Deoxys(const PokedexData *pokedexData, u32 form) +{ + for (int formIndex = 0; formIndex < DEOXYS_COUNT; formIndex++) { + if (GetForm_Deoxys(pokedexData, formIndex) == form) { + return TRUE; + } + } + + return FALSE; +} + +static void UpdateForms_Deoxys(PokedexData *pokedexData, u16 species, Pokemon *pokemon) +{ + u8 form = Pokemon_GetValue(pokemon, MON_DATA_FORM, NULL); + + if (species == SPECIES_DEOXYS) { + if (FormSeen_Deoxys(pokedexData, form) == FALSE) { + u32 newIndex = NumFormsSeen_Deoxys(pokedexData); + UpdateFormArray_Deoxys(pokedexData, form, newIndex); + } + } +} + +static void InitDeoxys(PokedexData *pokedexData) +{ + for (int formIndex = 0; formIndex < DEOXYS_COUNT; formIndex++) { + UpdateFormArray_Deoxys(pokedexData, TERMINAL_BYTE, formIndex); + } +} + +static inline u32 ReadBit_Rotom(u32 formArray, u32 formIndex) +{ + return (formArray >> (formIndex * 3)) & 0x7; +} + +static inline void SetBit_Rotom(u32 *formArray, u32 formIndex, u32 form) +{ + GF_ASSERT(form < TERMINAL_4BITS); + + (*formArray) &= ~(0x7 << (formIndex * 3)); + (*formArray) |= (form << (formIndex * 3)); +} + +static int NumFormsSeen_Rotom(const PokedexData *pokedexData, u32 species) +{ + GF_ASSERT(species == SPECIES_ROTOM); + + if (PokedexData_HasSeenSpecies(pokedexData, species) == FALSE) { + return 0; + } + + u32 form; + int formIndex; + int numFormsSeen = 0; + + for (formIndex = 0; formIndex < ROTOM_COUNT; formIndex++) { + form = ReadBit_Rotom(pokedexData->rotomForms, formIndex); + + if (form != TERMINAL_4BITS) { + numFormsSeen++; + } else { + break; + } + } + + return numFormsSeen; +} + +static BOOL FormSeen_Rotom(const PokedexData *pokedexData, u32 species, u8 form) +{ + GF_ASSERT(species == SPECIES_ROTOM); + + if (PokedexData_HasSeenSpecies(pokedexData, species) == FALSE) { + return FALSE; + } + + int formIndex; + u32 numFormsSeen = NumFormsSeen_Rotom(pokedexData, species); + + for (formIndex = 0; formIndex < numFormsSeen; formIndex++) { + u32 rotomForm = ReadBit_Rotom(pokedexData->rotomForms, formIndex); + + if (rotomForm == form) { + return TRUE; + } + } + + return FALSE; +} + +static void UpdateForms_Rotom(PokedexData *pokedexData, u32 species, int form) +{ + int numFormsSeen; + + GF_ASSERT(species == SPECIES_ROTOM); + + if (FormSeen_Rotom(pokedexData, species, form)) { + return; + } + + numFormsSeen = NumFormsSeen_Rotom(pokedexData, species); + + if (numFormsSeen < ROTOM_COUNT) { + SetBit_Rotom(&pokedexData->rotomForms, numFormsSeen, form); + } +} + +static void UpdateForm(PokedexData *pokedexData, u16 species, Pokemon *pokemon) +{ + int form; + + switch (species) { + case SPECIES_UNOWN: + form = Pokemon_GetForm(pokemon); + SetUnownForm(pokedexData, form); + break; + case SPECIES_BURMY: + form = Pokemon_GetValue(pokemon, MON_DATA_FORM, NULL); + UpdateForms_ThreeForms(pokedexData, species, form); + break; + case SPECIES_WORMADAM: + form = Pokemon_GetValue(pokemon, MON_DATA_FORM, NULL); + UpdateForms_ThreeForms(pokedexData, species, form); + break; + case SPECIES_SHELLOS: + form = Pokemon_GetValue(pokemon, MON_DATA_FORM, NULL); + UpdateForms_TwoForms(pokedexData, species, form); + break; + case SPECIES_GASTRODON: + form = Pokemon_GetValue(pokemon, MON_DATA_FORM, NULL); + UpdateForms_TwoForms(pokedexData, species, form); + break; + case SPECIES_DEOXYS: + UpdateForms_Deoxys(pokedexData, species, pokemon); + break; + case SPECIES_SHAYMIN: + form = Pokemon_GetValue(pokemon, MON_DATA_FORM, NULL); + UpdateForms_TwoForms(pokedexData, species, form); + break; + case SPECIES_GIRATINA: + form = Pokemon_GetValue(pokemon, MON_DATA_FORM, NULL); + UpdateForms_TwoForms(pokedexData, species, form); + break; + case SPECIES_ROTOM: + form = Pokemon_GetValue(pokemon, MON_DATA_FORM, NULL); + UpdateForms_Rotom(pokedexData, species, form); + break; + default: + break; + } +} + +static void UpdateLanguage(PokedexData *pokedexData, u16 species, u32 language) +{ + int bitIndex = species; + int languageIndex = PokedexLanguage_LanguageToIndex(language); + + if (languageIndex == NUM_LANGUAGES) { + return; + } + + pokedexData->recordedLanguages[bitIndex] |= 1 << languageIndex; +} + +static u32 GetDisplayGender(const PokedexData *pokedexData, u16 species, int displaySecondary) +{ + u32 defaultGender, secondaryGender; + u32 displayGender; + + if (PokemonPersonalData_GetSpeciesValue(species, MON_DATA_PERSONAL_GENDER) == GENDER_RATIO_NO_GENDER) { + if (displaySecondary == FALSE) { + return GENDER_NONE; + } else { + return -1; + } + } + + defaultGender = GetGender(pokedexData, species, 0); + + if (displaySecondary == TRUE) { + secondaryGender = GetGender(pokedexData, species, 1); + + if (secondaryGender == defaultGender) { + displayGender = -1; + } else { + displayGender = secondaryGender; + } + } else { + displayGender = defaultGender; + } + + return displayGender; +} + +static inline int GetForm_Unown(const PokedexData *pokedexData, int formIndex) +{ + return pokedexData->unownForms[formIndex]; +} + +static int GetForm_TwoForms(const PokedexData *pokedexData, u32 species, int formIndex) +{ + const u8 *formArray; + + GF_ASSERT((species == SPECIES_SHELLOS) || (species == SPECIES_GASTRODON) || (species == SPECIES_SHAYMIN) || (species == SPECIES_GIRATINA)); + GF_ASSERT(formIndex < 2); + + switch (species) { + case SPECIES_SHELLOS: + formArray = &pokedexData->shellosForms; + break; + case SPECIES_GASTRODON: + formArray = &pokedexData->gastrodonForms; + break; + case SPECIES_SHAYMIN: + formArray = &pokedexData->shayminForms; + break; + case SPECIES_GIRATINA: + formArray = &pokedexData->giratinaForms; + break; + } + + return ReadBit_2Forms(formArray, formIndex + 1); +} + +static int GetForm_Rotom(const PokedexData *pokedexData, u32 species, int formIndex) +{ + GF_ASSERT(species == SPECIES_ROTOM); + GF_ASSERT(formIndex < ROTOM_COUNT); + + return ReadBit_Rotom(pokedexData->rotomForms, formIndex); +} + +static int GetForm_3Forms(const PokedexData *pokedexData, u32 species, int formIndex) +{ + const u8 *formArray; + + GF_ASSERT((species == SPECIES_BURMY) || (species == SPECIES_WORMADAM)); + GF_ASSERT(formIndex < 3); + + if (species == SPECIES_BURMY) { + formArray = &pokedexData->burmyForms; + } else { + formArray = &pokedexData->wormadamForms; + } + + return ReadBit_3Forms(formArray, formIndex); +} + +static BOOL CountsForDexCompletion_National(u16 species) +{ + int i; + BOOL included; + static const u16 mythicals[NUM_MYTHICALS_NATIONAL] = { + SPECIES_MEW, + SPECIES_LUGIA, + SPECIES_HO_OH, + SPECIES_CELEBI, + SPECIES_JIRACHI, + SPECIES_DEOXYS, + SPECIES_PHIONE, + SPECIES_MANAPHY, + SPECIES_DARKRAI, + SPECIES_SHAYMIN, + SPECIES_ARCEUS + }; + + included = TRUE; + + for (i = 0; i < NUM_MYTHICALS_NATIONAL; i++) { + if (mythicals[i] == species) { + included = FALSE; + } + } + + return included; +} + +static BOOL CountsForDexCompletion_Local(u16 species) +{ + return TRUE; +} + +void PokedexData_Init(PokedexData *pokedexData) +{ + memset(pokedexData, 0, sizeof(PokedexData)); + + pokedexData->magic = MAGIC_NUMBER; + pokedexData->nationalDexObtained = FALSE; + + memset(pokedexData->unownForms, TERMINAL_U8, sizeof(u8) * UNOWN_COUNT); + + pokedexData->shellosForms = TERMINAL_U8; + pokedexData->gastrodonForms = TERMINAL_U8; + pokedexData->burmyForms = TERMINAL_U8; + pokedexData->wormadamForms = TERMINAL_U8; + pokedexData->rotomForms = TERMINAL_U32; + pokedexData->shayminForms = TERMINAL_U8; + pokedexData->giratinaForms = TERMINAL_U8; + + InitDeoxys(pokedexData); +} + +u16 PokedexData_CountCaught_National(const PokedexData *pokedexData) +{ + CheckPokedexIntegrity(pokedexData); + + int species; + int caughtCount = 0; + for (species = 1; species <= NATIONAL_DEX_COUNT; species++) { + if (PokedexData_HasCaughtSpecies(pokedexData, species) == TRUE) { + caughtCount++; + } + } + + return caughtCount; +} + +u16 PokedexData_CountSeen_National(const PokedexData *pokedex) +{ + CheckPokedexIntegrity(pokedex); + + int species; + int seenCount = 0; + for (species = 1; species <= NATIONAL_DEX_COUNT; species++) { + if (PokedexData_HasSeenSpecies(pokedex, species) == TRUE) { + seenCount++; + } + } + + return seenCount; +} + +u16 PokedexData_CountSeen(const PokedexData *pokedex) +{ + if (PokedexData_IsNationalDexObtained(pokedex)) { + return PokedexData_CountSeen_National(pokedex); + } + + return PokedexData_CountSeen_Local(pokedex); +} + +u16 PokedexData_CountCaught_Local(const PokedexData *pokedexData) +{ + CheckPokedexIntegrity(pokedexData); + + int species; + int caughtCount = 0; + for (species = 1; species <= NATIONAL_DEX_COUNT; species++) { + if (PokedexData_HasCaughtSpecies(pokedexData, species) == TRUE) { + if (Pokemon_SinnohDexNumber(species) != 0) { + caughtCount++; + } + } + } + + return caughtCount; +} + +u16 PokedexData_CountSeen_Local(const PokedexData *pokedex) +{ + CheckPokedexIntegrity(pokedex); + + int species; + int seenCount = 0; + for (species = 1; species <= NATIONAL_DEX_COUNT; species++) { + if (PokedexData_HasSeenSpecies(pokedex, species) == TRUE && Pokemon_SinnohDexNumber(species) != 0) { + seenCount++; + } + } + + return seenCount; +} + +BOOL PokedexData_NationalDexCompleted(const PokedexData *pokedexData) +{ + u16 numCaught = PokedexData_NumCaught_National(pokedexData); + + if (numCaught >= NATIONAL_DEX_GOAL) { + return TRUE; + } + + return FALSE; +} + +BOOL PokedexData_LocalDexCompleted(const PokedexData *pokedexData) +{ + u16 numCaught = PokedexData_NumCaught_Local(pokedexData); + + if (numCaught >= LOCAL_DEX_COUNT) { + return TRUE; + } + + return FALSE; +} + +u16 PokedexData_NumCaught_National(const PokedexData *pokedexData) +{ + int species; + u16 numCaught = 0; + + for (species = 1; species <= NATIONAL_DEX_COUNT; species++) { + if (PokedexData_HasCaughtSpecies(pokedexData, species) == TRUE) { + if (CountsForDexCompletion_National(species) == TRUE) { + numCaught++; + } + } + } + + return numCaught; +} + +u16 PokedexData_NumCaught_Local(const PokedexData *pokedexData) +{ + int species; + u16 numCaught = 0; + + for (species = 1; species <= NATIONAL_DEX_COUNT; species++) { + if (PokedexData_HasSeenSpecies(pokedexData, species) == TRUE) { + u32 localDexNum = Pokemon_SinnohDexNumber(species); + + if (localDexNum != 0) { + if (CountsForDexCompletion_Local(species) == TRUE) { + numCaught++; + } + } + } + } + + return numCaught; +} + +BOOL PokedexData_HasCaughtSpecies(const PokedexData *pokedex, u16 species) +{ + CheckPokedexIntegrity(pokedex); + + if (SpeciesInvalid(species)) { + return FALSE; + } + + if (SpeciesCaught(pokedex, species) && SpeciesSeen(pokedex, species)) { + return TRUE; + } else { + return FALSE; + } +} + +BOOL PokedexData_HasSeenSpecies(const PokedexData *pokedex, u16 species) +{ + CheckPokedexIntegrity(pokedex); + + if (SpeciesInvalid(species)) { + return FALSE; + } + + return SpeciesSeen(pokedex, species); +} + +u32 PokedexData_GetForm_Spinda(const PokedexData *pokedexData, u8 formIndex) +{ + CheckPokedexIntegrity(pokedexData); + + u32 form; + switch (formIndex) { + case 0: + form = pokedexData->spindaForms; + break; + default: + GF_ASSERT(FALSE); + break; + } + + return form; +} + +u32 PokedexData_DisplayedGender(const PokedexData *pokedexData, u16 species, int displaySecondary) +{ + CheckPokedexIntegrity(pokedexData); + + if (SpeciesInvalid(species)) { + return -1; + } + + if (!SpeciesSeen(pokedexData, species)) { + return -1; + } + + return GetDisplayGender(pokedexData, species, displaySecondary); +} + +u32 PokedexData_GetForm_Unown(const PokedexData *pokedexData, int formIndex) +{ + CheckPokedexIntegrity(pokedexData); + + if (NumFormsSeen_Unown(pokedexData) <= formIndex) { + return -1; + } + + return GetForm_Unown(pokedexData, formIndex); +} + +u32 PokedexData_NumFormsSeen_Unown(const PokedexData *pokedexData) +{ + CheckPokedexIntegrity(pokedexData); + return NumFormsSeen_Unown(pokedexData); +} + +u32 PokedexData_GetForm_Shellos(const PokedexData *pokedexData, int formIndex) +{ + CheckPokedexIntegrity(pokedexData); + + if (NumFormsSeen_TwoForms(pokedexData, SPECIES_SHELLOS) <= formIndex) { + return -1; + } + + return GetForm_TwoForms(pokedexData, SPECIES_SHELLOS, formIndex); +} + +u32 PokedexData_NumFormsSeen_Shellos(const PokedexData *pokedexData) +{ + CheckPokedexIntegrity(pokedexData); + return NumFormsSeen_TwoForms(pokedexData, SPECIES_SHELLOS); +} + +u32 PokedexData_GetForm_Gastrodon(const PokedexData *pokedexData, int formIndex) +{ + CheckPokedexIntegrity(pokedexData); + + if (NumFormsSeen_TwoForms(pokedexData, SPECIES_GASTRODON) <= formIndex) { + return -1; + } + + return GetForm_TwoForms(pokedexData, SPECIES_GASTRODON, formIndex); +} + +u32 PokedexData_NumFormsSeen_Gastrodon(const PokedexData *pokedexData) +{ + CheckPokedexIntegrity(pokedexData); + return NumFormsSeen_TwoForms(pokedexData, SPECIES_GASTRODON); +} + +u32 PokedexData_GetForm_Burmy(const PokedexData *pokedexData, int formIndex) +{ + CheckPokedexIntegrity(pokedexData); + + if (NumFormsSeen_ThreeForms(pokedexData, SPECIES_BURMY) <= formIndex) { + return -1; + } + + return GetForm_3Forms(pokedexData, SPECIES_BURMY, formIndex); +} + +u32 PokedexData_NumFormsSeen_Burmy(const PokedexData *pokedexData) +{ + CheckPokedexIntegrity(pokedexData); + return NumFormsSeen_ThreeForms(pokedexData, SPECIES_BURMY); +} + +u32 PokedexData_GetForm_Wormadam(const PokedexData *pokedexData, int formIndex) +{ + CheckPokedexIntegrity(pokedexData); + + if (NumFormsSeen_ThreeForms(pokedexData, SPECIES_WORMADAM) <= formIndex) { + return -1; + } + + return GetForm_3Forms(pokedexData, SPECIES_WORMADAM, formIndex); +} + +u32 PokedexData_NumFormsSeen_Wormadam(const PokedexData *pokedexData) +{ + CheckPokedexIntegrity(pokedexData); + return NumFormsSeen_ThreeForms(pokedexData, SPECIES_WORMADAM); +} + +u32 PokedexData_GetForm_Deoxys(const PokedexData *pokedexData, int formIndex) +{ + CheckPokedexIntegrity(pokedexData); + return GetForm_Deoxys(pokedexData, formIndex); +} + +u32 PokedexData_NumFormsSeen_Deoxys(const PokedexData *pokedexData) +{ + CheckPokedexIntegrity(pokedexData); + return NumFormsSeen_Deoxys(pokedexData); +} + +void PokedexData_CaptureEntry(PokedexData *pokedexData, Pokemon *pokemon) +{ + u16 species = Pokemon_GetValue(pokemon, MON_DATA_SPECIES, NULL); + u32 personality = Pokemon_GetValue(pokemon, MON_DATA_PERSONALITY, NULL); + u32 gender = Pokemon_GetGender(pokemon); + + CheckPokedexIntegrity(pokedexData); + + if (SpeciesInvalid(species)) { + return; + } + + if (!SpeciesSeen(pokedexData, species)) { + SetForm_Spinda(pokedexData, species, personality); + UpdateGender(pokedexData, gender, FALSE, species); + } else { + u32 defaultGender = GetGender(pokedexData, species, 0); + + if (defaultGender != gender) { + UpdateGender(pokedexData, gender, TRUE, species); + } + } + + UpdateForm(pokedexData, species, pokemon); + Write_SeenSpecies(pokedexData, species); +} + +void PokedexData_TradeEntry(PokedexData *pokedexData, Pokemon *pokemon) +{ + u16 species = Pokemon_GetValue(pokemon, MON_DATA_SPECIES, NULL); + u32 language = Pokemon_GetValue(pokemon, MON_DATA_LANGUAGE, NULL); + u32 personality = Pokemon_GetValue(pokemon, MON_DATA_PERSONALITY, NULL); + u32 gender = Pokemon_GetGender(pokemon); + + CheckPokedexIntegrity(pokedexData); + + if (SpeciesInvalid(species)) { + return; + } + + if (!SpeciesSeen(pokedexData, species)) { + SetForm_Spinda(pokedexData, species, personality); + UpdateGender(pokedexData, gender, FALSE, species); + } else { + u32 displayedGender = GetGender(pokedexData, species, 0); + + if (displayedGender != gender) { + UpdateGender(pokedexData, gender, TRUE, species); + } + } + + UpdateForm(pokedexData, species, pokemon); + UpdateLanguage(pokedexData, species, language); + + Write_CaughtSpecies(pokedexData, species); + Write_SeenSpecies(pokedexData, species); +} + +void PokedexData_ObtainNationalDex(PokedexData *pokedexData) +{ + CheckPokedexIntegrity(pokedexData); + pokedexData->nationalDexObtained = TRUE; +} + +BOOL PokedexData_IsNationalDexObtained(const PokedexData *pokedex) +{ + CheckPokedexIntegrity(pokedex); + return pokedex->nationalDexObtained; +} + +BOOL PokedexData_CanDetectForms(const PokedexData *pokedexData) +{ + CheckPokedexIntegrity(pokedexData); + return pokedexData->canDetectForms; +} + +void PokedexData_TurnOnFormDetection(PokedexData *pokedexData) +{ + CheckPokedexIntegrity(pokedexData); + pokedexData->canDetectForms = TRUE; +} + +BOOL PokedexData_IsLanguageObtained(const PokedexData *pokedexData, u16 species, u32 languageIndex) +{ + int bitIndex; + + GF_ASSERT(languageIndex < 8); + + CheckPokedexIntegrity(pokedexData); + + bitIndex = species; + languageIndex = PokedexLanguage_LanguageToIndex(languageIndex); + + return pokedexData->recordedLanguages[bitIndex] & (1 << languageIndex); +} + +void PokedexData_TurnOnLanguageDetection(PokedexData *pokedexData) +{ + pokedexData->canDetectLanguages = TRUE; +} + +BOOL PokedexData_CanDetectLanguages(const PokedexData *pokedexData) +{ + return pokedexData->canDetectLanguages; +} + +BOOL PokedexData_IsObtained(const PokedexData *pokedex) +{ + CheckPokedexIntegrity(pokedex); + return pokedex->pokedexObtained; +} + +void PokedexData_ObtainPokedex(PokedexData *pokedex) +{ + CheckPokedexIntegrity(pokedex); + pokedex->pokedexObtained = TRUE; +} + +PokedexData *SaveData_PokedexData(SaveData *saveData) +{ + PokedexData *pokedex = SaveData_SaveTable(saveData, SAVE_TABLE_ENTRY_POKEDEX); + return pokedex; +} + +u32 PokedexData_GetDisplayForm(const PokedexData *pokedexData, int species, int formIndex) +{ + CheckPokedexIntegrity(pokedexData); + + switch (species) { + case SPECIES_UNOWN: + if (formIndex < PokedexData_NumFormsSeen_Unown(pokedexData)) { + return PokedexData_GetForm_Unown(pokedexData, formIndex); + } + break; + case SPECIES_SHELLOS: + if (formIndex < PokedexData_NumFormsSeen_Shellos(pokedexData)) { + return PokedexData_GetForm_Shellos(pokedexData, formIndex); + } + break; + case SPECIES_GASTRODON: + if (formIndex < PokedexData_NumFormsSeen_Gastrodon(pokedexData)) { + return PokedexData_GetForm_Gastrodon(pokedexData, formIndex); + } + break; + case SPECIES_BURMY: + if (formIndex < PokedexData_NumFormsSeen_Burmy(pokedexData)) { + return PokedexData_GetForm_Burmy(pokedexData, formIndex); + } + break; + case SPECIES_WORMADAM: + if (formIndex < PokedexData_NumFormsSeen_Wormadam(pokedexData)) { + return PokedexData_GetForm_Wormadam(pokedexData, formIndex); + } + break; + case SPECIES_DEOXYS: + if (formIndex < PokedexData_NumFormsSeen_Deoxys(pokedexData)) { + return PokedexData_GetForm_Deoxys(pokedexData, formIndex); + } + break; + case SPECIES_SHAYMIN: + if (formIndex < NumFormsSeen_TwoForms(pokedexData, SPECIES_SHAYMIN)) { + return GetForm_TwoForms(pokedexData, SPECIES_SHAYMIN, formIndex); + } + break; + case SPECIES_GIRATINA: + if (formIndex < NumFormsSeen_TwoForms(pokedexData, SPECIES_GIRATINA)) { + return GetForm_TwoForms(pokedexData, SPECIES_GIRATINA, formIndex); + } + break; + case SPECIES_ROTOM: + if (formIndex < NumFormsSeen_Rotom(pokedexData, SPECIES_ROTOM)) { + return GetForm_Rotom(pokedexData, SPECIES_ROTOM, formIndex); + } + break; + default: + break; + } + + return 0; +} + +u32 PokedexData_NumFormsSeen(const PokedexData *pokedex, int species) +{ + CheckPokedexIntegrity(pokedex); + + switch (species) { + case SPECIES_UNOWN: + return PokedexData_NumFormsSeen_Unown(pokedex); + case SPECIES_SHELLOS: + return PokedexData_NumFormsSeen_Shellos(pokedex); + case SPECIES_GASTRODON: + return PokedexData_NumFormsSeen_Gastrodon(pokedex); + case SPECIES_BURMY: + return PokedexData_NumFormsSeen_Burmy(pokedex); + case SPECIES_WORMADAM: + return PokedexData_NumFormsSeen_Wormadam(pokedex); + case SPECIES_DEOXYS: + return PokedexData_NumFormsSeen_Deoxys(pokedex); + case SPECIES_SHAYMIN: + return NumFormsSeen_TwoForms(pokedex, SPECIES_SHAYMIN); + case SPECIES_GIRATINA: + return NumFormsSeen_TwoForms(pokedex, SPECIES_GIRATINA); + case SPECIES_ROTOM: + return NumFormsSeen_Rotom(pokedex, SPECIES_ROTOM); + default: + break; + } + + return 1; +} diff --git a/src/pokedex_language.c b/src/pokedex_language.c new file mode 100644 index 0000000000..1e7d313733 --- /dev/null +++ b/src/pokedex_language.c @@ -0,0 +1,34 @@ +#include "pokedex_language.h" + +#include +#include + +#include "global/pm_version.h" + +static const u8 languageArray[NUM_LANGUAGES] = { + JAPANESE, + ENGLISH, + FRENCH, + GERMAN, + ITALIAN, + SPANISH +}; + +int PokedexLanguage_LanguageToIndex(int language) +{ + int languageIndex; + + for (languageIndex = 0; languageIndex < NUM_LANGUAGES; languageIndex++) { + if (language == languageArray[languageIndex]) { + break; + } + } + + return languageIndex; +} + +int PokedexLanguage_IndexToLanguage(int languageIndex) +{ + GF_ASSERT(languageIndex < NUM_LANGUAGES); + return languageArray[languageIndex]; +} diff --git a/src/unk_0202631C.c b/src/unk_0202631C.c index 699193005f..d39c533cff 100644 --- a/src/unk_0202631C.c +++ b/src/unk_0202631C.c @@ -7,9 +7,9 @@ #include "heap.h" #include "inlines.h" +#include "pokedex_language.h" #include "pokemon.h" #include "savedata.h" -#include "unk_020986CC.h" // These u32[16] arrays store pokedex seen/caught info as bit flags // Therefore 32 * 16 = 512 pokedex slots. These need to be bumped up if it's pushed past this number @@ -622,7 +622,7 @@ static void sub_02026B88(PokedexData *param0, u16 param1, u32 param2) int v1; v0 = param1; - v1 = sub_020986CC(param2); + v1 = PokedexLanguage_LanguageToIndex(param2); if (v1 == 6) { return; @@ -1162,7 +1162,7 @@ BOOL sub_020274D0(const PokedexData *param0, u16 species, u32 param2) CheckPokedexIntegrity(param0); speciesInt = species; - param2 = sub_020986CC(param2); + param2 = PokedexLanguage_LanguageToIndex(param2); return param0->recordedLanguages[speciesInt] & (1 << param2); } diff --git a/src/unk_020986CC.c b/src/unk_020986CC.c deleted file mode 100644 index e3c84a1ac4..0000000000 --- a/src/unk_020986CC.c +++ /dev/null @@ -1,32 +0,0 @@ -#include "unk_020986CC.h" - -#include -#include - -static const u8 Unk_020F681C[6] = { - 0x1, - 0x2, - 0x3, - 0x5, - 0x4, - 0x7 -}; - -int sub_020986CC(int param0) -{ - int v0; - - for (v0 = 0; v0 < 6; v0++) { - if (param0 == Unk_020F681C[v0]) { - break; - } - } - - return v0; -} - -int sub_020986E8(int param0) -{ - GF_ASSERT(param0 < 6); - return Unk_020F681C[param0]; -}