summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarcus Huderle <huderlem@gmail.com>2016-09-10 11:00:02 -0700
committerMarcus Huderle <huderlem@gmail.com>2016-09-10 11:00:02 -0700
commit3cb79cf078e82206796e1b834393ab771593de72 (patch)
tree3e27550ab45ce782db8f2e182819015ba3aef733 /src
parentf5d9daeca38728f67db92a175c37e5a3bc18cee3 (diff)
parent19bffecc4deb401aa51add3b95163b72686f40ee (diff)
Merge 'master' with 'origin/master'
Diffstat (limited to 'src')
-rw-r--r--src/link.c8
-rw-r--r--src/m4a_tables.c2
-rw-r--r--src/main.c8
-rw-r--r--src/main_menu.c1662
-rw-r--r--src/menu.c1003
-rw-r--r--src/pokemon_1.c680
-rw-r--r--src/pokemon_2.c539
-rw-r--r--src/text.c2
-rw-r--r--src/text_window.c196
9 files changed, 4093 insertions, 7 deletions
diff --git a/src/link.c b/src/link.c
index a5d848b83..13fcf8c05 100644
--- a/src/link.c
+++ b/src/link.c
@@ -27,7 +27,7 @@ struct LinkTestBGInfo
u32 dummy_C;
};
-extern void sub_8071C4C(const struct WindowConfig *);
+extern void InitMenuWindow(const struct WindowConfig *);
extern void sub_80516C4(u8, u16);
extern u8 unk_2000000[];
@@ -237,7 +237,7 @@ static void LinkTestScreen(void)
ResetTasks();
SetVBlankCallback(VBlankCB_LinkTest);
SetUpWindowConfig(&gWindowConfig_81E6CE4);
- sub_8071C4C(&gWindowConfig_81E6CE4);
+ InitMenuWindow(&gWindowConfig_81E6CE4);
ResetBlockSend();
gLinkType = 0x1111;
OpenLink();
@@ -1224,8 +1224,8 @@ void CB2_LinkError(void)
ResetTasks();
SetVBlankCallback(VBlankCB_LinkTest);
SetUpWindowConfig(&gWindowConfig_81E7198);
- sub_8071C4C(&gWindowConfig_81E7198);
- sub_8071EF4();
+ InitMenuWindow(&gWindowConfig_81E7198);
+ MenuZeroFillScreen();
REG_BLDALPHA = 0;
REG_BG0VOFS = 0;
REG_BG0HOFS = 0;
diff --git a/src/m4a_tables.c b/src/m4a_tables.c
index 39344a590..f557fb073 100644
--- a/src/m4a_tables.c
+++ b/src/m4a_tables.c
@@ -260,7 +260,7 @@ const struct PokemonCrySong gPokemonCrySongTemplate =
0, // block count
255, // priority
0, // reverb
- (struct ToneData *)&gUnknown_0842FC88,
+ (struct ToneData *)&voicegroup_842FC88,
NULL,
NULL,
0,
diff --git a/src/main.c b/src/main.c
index 751a2c7f8..937978c38 100644
--- a/src/main.c
+++ b/src/main.c
@@ -18,7 +18,13 @@ void SerialIntr(void);
void IntrDummy(void);
void Timer3Intr(void);
-const u8 gGameVersion = 2; // Ruby
+#ifdef SAPPHIRE
+#define GAME_VERSION VERSION_SAPPHIRE
+#else
+#define GAME_VERSION VERSION_RUBY
+#endif
+
+const u8 gGameVersion = GAME_VERSION;
const u8 gGameLanguage = 2; // English
diff --git a/src/main_menu.c b/src/main_menu.c
new file mode 100644
index 000000000..692267c64
--- /dev/null
+++ b/src/main_menu.c
@@ -0,0 +1,1662 @@
+#include "global.h"
+#include "text.h"
+#include "sprite.h"
+#include "task.h"
+#include "main.h"
+#include "rtc.h"
+#include "songs.h"
+#include "palette.h"
+#include "string_util.h"
+#include "species.h"
+#include "pokemon.h"
+
+extern u8 MenuUpdateWindowText(void);
+extern void MenuPrint(u8 *, u8, u8);
+extern void CB2_ContinueSavedGame(void);
+extern void CB2_InitMysteryEventMenu(void);
+extern void CB2_InitOptionMenu(void);
+extern void CB2_InitTitleScreen(void);
+extern void FormatPlayTime(u8 *str, u16 hours, u16 minutes, bool16 colon);
+extern u8 *sub_8072C74(u8 *, u8 *, u8, u8);
+extern u16 GetPokedexSeenCount(void);
+extern u8 *sub_8072C14(u8 *, s32, u8, u8);
+extern u8 sub_80729D8(u8 *, u8, u16, u8);
+extern u8 GetBadgeCount(void);
+extern void Task_Birch1(u8);
+void MenuPrintMessage(const u8 *string, u8 a, u8 b);
+u8 MenuUpdateWindowText_OverrideLineLength(u8 a);
+void sub_8072DEC(void);
+u8 sub_8075374(void);
+void MenuSetText(u32);
+void cry_related(u16, u8);
+void audio_play(u8 a);
+void MenuZeroFillWindowRect(u8 a, u8 b, u8 c, u8 d);
+u8 GetMenuCursorPos(void);
+void DoNamingScreen(u8 r0, struct SaveBlock2 *r1, u16 r2, u16 r3, u8 s0, MainCallback s4);
+void DisplayYesNoMenu(u8 r0, u8 r1, u32 r2);
+s8 ProcessMenuInputNoWrap_(void);
+void c2_load_new_map_2(void);
+void LZ77UnCompVram(const void *src, void *dest);
+void InitMenuWindow(const struct WindowConfig *);
+void CB2_MainMenu(void);
+void VBlankCB_MainMenu(void);
+void DecompressPicFromTable_2(const struct SpriteSheet *, u8, u8, void *, void *, u32);
+void LoadCompressedObjectPalette(const struct SpritePalette *);
+u8 AddNewGameBirchObject(u8, u8, u8);
+u8 sub_80859BC(u8, u16, u16, u8, void *);
+void MenuDrawTextWindow(u8 a, u8 b, u8 c, u8 d);
+
+extern struct PaletteFadeControl gPaletteFade;
+extern u8 gSaveFileDeletedMessage[];
+extern u8 gSaveFileCorruptMessage[];
+extern u8 gBoardNotInstalledMessage[];
+extern u8 gBatteryDryMessage[];
+extern u16 gSaveFileStatus;
+extern u8 gMainMenuString_Continue[];
+extern u8 gMainMenuString_NewGame[];
+extern u8 gMainMenuString_MysteryEvents[];
+extern u8 gMainMenuString_Option[];
+extern u8 gMainMenuString_Player[];
+extern u8 gMainMenuString_Time[];
+extern u8 gMainMenuString_Pokedex[];
+extern u8 gMainMenuString_Badges[];
+
+void CB2_MainMenu(void);
+void VBlankCB_MainMenu(void);
+void CB2_InitMainMenu(void);
+static void sub_80096FC(void);
+static u32 InitMainMenu(bool8 a1);
+static void Task_CheckSave(u8 taskId);
+static void Task_WaitForSaveErrorAck(u8 taskId);
+static void Task_CheckRtc(u8 taskId);
+static void Task_WaitForRtcErrorAck(u8 taskId);
+static void Task_DrawMainMenu(u8 taskId);
+static void Task_HighlightCurrentMenuItem(u8 taskId);
+static bool8 MainMenuProcessKeyInput(u8 taskId);
+static void Task_MainMenuProcessKeyInput(u8 taskId);
+static void MainMenuPressedA(u8 taskId);
+static void MainMenuPressedB(u8 taskId);
+static void HighlightCurrentMenuItem(u8, u8);
+static void PrintMainMenuItem(u8 *text, u8, u8);
+static void PrintSaveFileInfo(void);
+static void PrintPlayerName(void);
+static void PrintPlayTime(void);
+static void PrintPokedexCount(void);
+static void PrintBadgeCount(void);
+
+extern u16 gMainMenuPalette[];
+
+void CB2_MainMenu(void)
+{
+ RunTasks();
+ AnimateSprites();
+ BuildOamBuffer();
+ UpdatePaletteFade();
+}
+
+void VBlankCB_MainMenu(void)
+{
+ LoadOam();
+ ProcessSpriteCopyRequests();
+ TransferPlttBuffer();
+}
+
+void CB2_InitMainMenu(void)
+{
+ InitMainMenu(FALSE);
+}
+
+static void sub_80096FC(void)
+{
+ InitMainMenu(TRUE);
+}
+
+u32 InitMainMenu(u8 a1)
+{
+ u16 savedIme;
+ u8 taskId;
+
+ SetVBlankCallback(NULL);
+
+ REG_DISPCNT = 0;
+ REG_BG2CNT = 0;
+ REG_BG1CNT = 0;
+ REG_BG0CNT = 0;
+ REG_BG2HOFS = 0;
+ REG_BG2VOFS = 0;
+ REG_BG1HOFS = 0;
+ REG_BG1VOFS = 0;
+ REG_BG0HOFS = 0;
+ REG_BG0VOFS = 0;
+
+ DmaFill16(3, 0, (void *)VRAM, VRAM_SIZE);
+ DmaFill32(3, 0, (void *)OAM, OAM_SIZE);
+ DmaFill16(3, 0, (void *)(PLTT + 2), PLTT_SIZE - 2);
+
+ ResetPaletteFade();
+ LoadPalette(gMainMenuPalette, 0, 32);
+ remove_some_task();
+ ResetTasks();
+ ResetSpriteData();
+ FreeAllSpritePalettes();
+ SetUpWindowConfig(&gWindowConfig_81E6C3C);
+ InitMenuWindow(&gWindowConfig_81E6CE4);
+
+ if (a1)
+ BeginNormalPaletteFade(-1, 0, 0x10, 0, 0x0000); // fade to black
+ else
+ BeginNormalPaletteFade(-1, 0, 0x10, 0, 0xFFFF); // fade to white
+
+ REG_WIN0H = 0;
+ REG_WIN0V = 0;
+ REG_WININ = 0;
+ REG_WINOUT = 0;
+ REG_BLDCNT = 0;
+ REG_BLDALPHA = 0;
+ REG_BLDY = 0;
+
+ savedIme = REG_IME;
+ REG_IME = 0;
+ REG_IE |= INTR_FLAG_VBLANK;
+ REG_IME = savedIme;
+
+ SetVBlankCallback(VBlankCB_MainMenu);
+ SetMainCallback2(CB2_MainMenu);
+
+ REG_DISPCNT = DISPCNT_OBJ_1D_MAP
+ | DISPCNT_BG0_ON
+ | DISPCNT_OBJ_ON
+ | DISPCNT_WIN0_ON;
+
+ taskId = CreateTask(Task_CheckSave, 0);
+ gTasks[taskId].data[1] = 0;
+
+ return 0;
+}
+
+void Task_CheckSave(u8 taskId)
+{
+ if (gPaletteFade.active)
+ return;
+
+ REG_WIN0H = 0;
+ REG_WIN0V = 0;
+ REG_WININ = 0x1111;
+ REG_WINOUT = 49;
+ REG_BLDCNT = 241;
+ REG_BLDALPHA = 0;
+ REG_BLDY = 7;
+
+ switch (gSaveFileStatus)
+ {
+ case 1:
+ if (sub_806918C() == TRUE)
+ gTasks[taskId].data[0] = 2;
+ else
+ gTasks[taskId].data[0] = 1;
+
+ gTasks[taskId].func = Task_CheckRtc;
+ break;
+ case 2:
+ MenuDrawTextWindow(2, 14, 27, 19);
+ MenuPrintMessage(gSaveFileDeletedMessage, 3, 15);
+ REG_WIN0H = WIN_RANGE(17, 223);
+ REG_WIN0V = WIN_RANGE(113, 159);
+ gTasks[taskId].data[0] = 0;
+ gTasks[taskId].func = Task_WaitForSaveErrorAck;
+ break;
+ case 255:
+ MenuDrawTextWindow(2, 14, 27, 19);
+ MenuPrintMessage(gSaveFileCorruptMessage, 3, 15);
+ REG_WIN0H = WIN_RANGE(17, 223);
+ REG_WIN0V = WIN_RANGE(113, 159);
+ gTasks[taskId].data[0] = 1;
+ gTasks[taskId].func = Task_WaitForSaveErrorAck;
+
+ if (sub_806918C() == TRUE)
+ gTasks[taskId].data[0] = 2;
+ else
+ gTasks[taskId].data[0] = 1;
+ break;
+ case 0:
+ default:
+ gTasks[taskId].data[0] = 0;
+ gTasks[taskId].func = Task_CheckRtc;
+ break;
+ case 4:
+ MenuDrawTextWindow(2, 14, 27, 19);
+ MenuPrintMessage(gBoardNotInstalledMessage, 3, 15);
+ REG_WIN0H = WIN_RANGE(17, 223);
+ REG_WIN0V = WIN_RANGE(113, 159);
+ gTasks[taskId].data[0] = 0;
+ gTasks[taskId].func = Task_WaitForSaveErrorAck;
+ return;
+ }
+}
+
+void Task_WaitForSaveErrorAck(u8 taskId)
+{
+ if (MenuUpdateWindowText())
+ {
+ if (gMain.newKeys & A_BUTTON)
+ {
+ MenuZeroFillWindowRect(2, 14, 27, 19);
+ gTasks[taskId].func = Task_CheckRtc;
+ }
+ }
+}
+
+void Task_CheckRtc(u8 taskId)
+{
+ if (!gPaletteFade.active)
+ {
+ REG_WIN0H = 0;
+ REG_WIN0V = 0;
+ REG_WININ = 0x1111;
+ REG_WINOUT = 49;
+ REG_BLDCNT = 241;
+ REG_BLDALPHA = 0;
+ REG_BLDY = 7;
+
+ if (!(RtcGetErrorStatus() & RTC_ERR_FLAG_MASK))
+ {
+ gTasks[taskId].func = Task_DrawMainMenu;
+ }
+ else
+ {
+ MenuDrawTextWindow(2, 14, 27, 19);
+ MenuPrintMessage(gBatteryDryMessage, 3, 15);
+ REG_WIN0H = WIN_RANGE(17, 223);
+ REG_WIN0V = WIN_RANGE(113, 159);
+ gTasks[taskId].func = Task_WaitForRtcErrorAck;
+ }
+ }
+}
+
+void Task_WaitForRtcErrorAck(u8 taskId)
+{
+ if (MenuUpdateWindowText())
+ {
+ if ( gMain.newKeys & 1 )
+ {
+ MenuZeroFillWindowRect(2, 14, 27, 19);
+ gTasks[taskId].func = Task_DrawMainMenu;
+ }
+ }
+}
+
+void Task_DrawMainMenu(u8 taskId)
+{
+ u16 palette;
+
+ if (!gPaletteFade.active)
+ {
+ REG_WIN0H = 0;
+ REG_WIN0V = 0;
+ REG_WININ = 0x1111;
+ REG_WINOUT = 49;
+ REG_BLDCNT = 241;
+ REG_BLDALPHA = 0;
+ REG_BLDY = 7;
+
+ palette = RGB(0, 0, 0);
+ LoadPalette(&palette, 254, 2);
+
+ if (gSaveBlock2.playerGender == MALE)
+ {
+ palette = RGB(4, 16, 31);
+ LoadPalette(&palette, 241, 2);
+ }
+ else
+ {
+ palette = RGB(31, 3, 21);
+ LoadPalette(&palette, 241, 2);
+ }
+
+ switch (gTasks[taskId].data[0])
+ {
+ case 0:
+ default:
+ MenuDrawTextWindow(1, 0, 28, 3);
+ PrintMainMenuItem(gMainMenuString_NewGame, 2, 1);
+ MenuDrawTextWindow(1, 4, 28, 7);
+ PrintMainMenuItem(gMainMenuString_Option, 2, 5);
+ break;
+ case 1:
+ MenuDrawTextWindow(1, 0, 28, 7);
+ PrintMainMenuItem(gMainMenuString_Continue, 2, 1);
+ MenuDrawTextWindow(1, 8, 28, 11);
+ PrintMainMenuItem(gMainMenuString_NewGame, 2, 9);
+ MenuDrawTextWindow(1, 12, 28, 15);
+ PrintMainMenuItem(gMainMenuString_Option, 2, 13);
+ PrintSaveFileInfo();
+ break;
+ case 2:
+ MenuDrawTextWindow(1, 0, 28, 7);
+ PrintMainMenuItem(gMainMenuString_Continue, 2, 1);
+ MenuDrawTextWindow(1, 8, 28, 11);
+ PrintMainMenuItem(gMainMenuString_NewGame, 2, 9);
+ MenuDrawTextWindow(1, 12, 28, 15);
+ PrintMainMenuItem(gMainMenuString_MysteryEvents, 2, 13);
+ MenuDrawTextWindow(1, 16, 28, 19);
+ PrintMainMenuItem(gMainMenuString_Option, 2, 0x11);
+ PrintSaveFileInfo();
+ break;
+ }
+
+ gTasks[taskId].func = Task_HighlightCurrentMenuItem;
+ }
+}
+
+void Task_HighlightCurrentMenuItem(u8 taskId)
+{
+ HighlightCurrentMenuItem(gTasks[taskId].data[0], gTasks[taskId].data[1]);
+ gTasks[taskId].func = Task_MainMenuProcessKeyInput;
+}
+
+bool8 MainMenuProcessKeyInput(u8 taskId)
+{
+ if (gMain.newKeys & A_BUTTON)
+ {
+ audio_play(SE_SELECT);
+ BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 0x10, 0x0000);
+ gTasks[taskId].func = MainMenuPressedA;
+ }
+ else if (gMain.newKeys & B_BUTTON)
+ {
+ audio_play(SE_SELECT);
+ BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 0x10, 0xFFFF);
+ REG_WIN0H = WIN_RANGE(0, 240);
+ REG_WIN0V = WIN_RANGE(0, 160);
+ gTasks[taskId].func = MainMenuPressedB;
+ }
+ else
+ {
+ s32 menuItemCount;
+
+ switch (gTasks[taskId].data[0])
+ {
+ case 0:
+ default:
+ menuItemCount = 2;
+ break;
+ case 1:
+ menuItemCount = 3;
+ break;
+ case 2:
+ menuItemCount = 4;
+ break;
+ }
+
+ if (gMain.newKeys & DPAD_UP)
+ {
+ if (gTasks[taskId].data[1] > 0)
+ {
+ gTasks[taskId].data[1]--;
+ return TRUE;
+ }
+ }
+ if (gMain.newKeys & DPAD_DOWN)
+ {
+ if (gTasks[taskId].data[1] < menuItemCount - 1)
+ {
+ gTasks[taskId].data[1]++;
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+void Task_MainMenuProcessKeyInput(u8 taskId)
+{
+ bool8 currentMenuItemChanged = MainMenuProcessKeyInput(taskId);
+ if (currentMenuItemChanged)
+ gTasks[taskId].func = Task_HighlightCurrentMenuItem;
+}
+
+void MainMenuPressedA(u8 taskId)
+{
+ enum
+ {
+ NEW_GAME,
+ CONTINUE,
+ OPTION,
+ MYSTERY_EVENTS,
+ } action;
+
+ if (gPaletteFade.active)
+ return;
+
+ switch (gTasks[taskId].data[0])
+ {
+ case 0:
+ default:
+ switch (gTasks[taskId].data[1])
+ {
+ case 0:
+ default:
+ action = NEW_GAME;
+ break;
+ case 1:
+ action = OPTION;
+ break;
+ }
+ break;
+ case 1:
+ switch (gTasks[taskId].data[1])
+ {
+ case 0:
+ default:
+ action = CONTINUE;
+ break;
+ case 1:
+ action = NEW_GAME;
+ break;
+ case 2:
+ action = OPTION;
+ break;
+ }
+ break;
+ case 2:
+ switch (gTasks[taskId].data[1])
+ {
+ case 0:
+ default:
+ action = CONTINUE;
+ break;
+ case 1:
+ action = NEW_GAME;
+ break;
+ case 2:
+ action = MYSTERY_EVENTS;
+ break;
+ case 3:
+ action = OPTION;
+ break;
+ }
+ break;
+ }
+
+ switch ((int)action)
+ {
+ case NEW_GAME:
+ default:
+ gPlttBufferUnfaded[0] = 0;
+ gPlttBufferFaded[0] = 0;
+ gTasks[taskId].func = Task_Birch1;
+ break;
+ case CONTINUE:
+ gPlttBufferUnfaded[0] = 0;
+ gPlttBufferFaded[0] = 0;
+ SetMainCallback2(CB2_ContinueSavedGame);
+ DestroyTask(taskId);
+ break;
+ case OPTION:
+ gMain.field_8 = (u32)sub_80096FC;
+ SetMainCallback2(CB2_InitOptionMenu);
+ DestroyTask(taskId);
+ break;
+ case MYSTERY_EVENTS:
+ SetMainCallback2(CB2_InitMysteryEventMenu);
+ DestroyTask(taskId);
+ break;
+ }
+}
+
+void MainMenuPressedB(u8 taskId)
+{
+ if (!gPaletteFade.active)
+ {
+ SetMainCallback2(CB2_InitTitleScreen);
+ DestroyTask(taskId);
+ }
+}
+
+void HighlightCurrentMenuItem(u8 layout, u8 menuItem)
+{
+ REG_WIN0H = WIN_RANGE(9, 231);
+
+ switch (layout)
+ {
+ case 0:
+ default:
+ switch (menuItem)
+ {
+ case 0:
+ default:
+ REG_WIN0V = WIN_RANGE(1, 31);
+ break;
+ case 1:
+ REG_WIN0V = WIN_RANGE(33, 63);
+ break;
+ }
+ break;
+ case 1:
+ switch (menuItem)
+ {
+ case 0:
+ default:
+ REG_WIN0V = WIN_RANGE(1, 63);
+ break;
+ case 1:
+ REG_WIN0V = WIN_RANGE(65, 95);
+ break;
+ case 2:
+ REG_WIN0V = WIN_RANGE(97, 127);
+ break;
+ }
+ break;
+ case 2:
+ switch (menuItem)
+ {
+ case 0:
+ default:
+ REG_WIN0V = WIN_RANGE(1, 63);
+ break;
+ case 1:
+ REG_WIN0V = WIN_RANGE(65, 95);
+ break;
+ case 2:
+ REG_WIN0V = WIN_RANGE(97, 127);
+ break;
+ case 3:
+ REG_WIN0V = WIN_RANGE(129, 159);
+ break;
+ }
+ break;
+ }
+}
+
+void PrintMainMenuItem(u8 *text, u8 left, u8 top)
+{
+ u8 i;
+ u8 buffer[32];
+
+ buffer[0] = 0xFC;
+ buffer[1] = 1;
+ buffer[2] = 14;
+
+ for (i = 0; i < 26; i++)
+ buffer[3 + i] = text[i];
+
+ buffer[29] = EOS;
+
+ MenuPrint(buffer, left, top);
+}
+
+void PrintSaveFileInfo(void)
+{
+ PrintPlayerName();
+ PrintPokedexCount();
+ PrintPlayTime();
+ PrintBadgeCount();
+}
+
+void PrintPlayerName(void)
+{
+ MenuPrint(gMainMenuString_Player, 2, 3);
+ MenuPrint(gSaveBlock2.playerName, 9, 3);
+}
+
+void PrintPlayTime(void)
+{
+ u8 playTime[16];
+ u8 alignedPlayTime[32];
+
+ MenuPrint(gMainMenuString_Time, 16, 3);
+ FormatPlayTime(playTime, gSaveBlock2.playTimeHours, gSaveBlock2.playTimeMinutes, 1);
+ sub_8072C74(alignedPlayTime, playTime, 48, 1);
+ MenuPrint(alignedPlayTime, 22, 3);
+}
+
+void PrintPokedexCount(void)
+{
+ u8 buffer[16];
+
+ MenuPrint(gMainMenuString_Pokedex, 2, 5);
+ sub_8072C14(buffer, GetPokedexSeenCount(), 18, 0);
+ MenuPrint(buffer, 9, 5);
+}
+
+void PrintBadgeCount(void)
+{
+ u8 buffer[16];
+
+ MenuPrint(gMainMenuString_Badges, 16, 5);
+ ConvertIntToDecimalString(buffer, GetBadgeCount());
+ sub_80729D8(buffer, 205, 40, 1);
+}
+
+//Text Strings
+extern const u8 gUnknown_081C6D78[]; //Hi! Sorry to keep you waiting!...
+extern const u8 gUnknown_081C6DF8[];
+extern const u8 gUnknown_081C6E1A[];
+extern const u8 gUnknown_081C6FCB[];
+extern const u8 gUnknown_081C6FD8[];
+extern const u8 gUnknown_081C6FFA[];
+extern u8 gUnknown_081C7017[];
+extern u8 gUnknown_081C7025[];
+extern u8 gUnknown_081C7074[];
+
+struct MonCoords
+{
+ u8 x, y;
+};
+
+extern const struct MonCoords gMonFrontPicCoords[];
+extern const struct SpriteSheet gMonFrontPicTable[];
+extern const struct SpritePalette gMonPaletteTable[];
+extern struct SpriteTemplate gUnknown_02024E8C;
+extern void * const gUnknown_081FAF4C[];
+extern u16 gUnknown_081E795C[];
+extern u8 * const gUnknown_081E79B0[][2];
+extern u8 * const gUnknown_081E79C0[][2];
+extern u8 * const gUnknown_081E79E8[][2];
+
+extern const u8 gUnknown_081E764C[];
+extern const u8 gUnknown_081E768C[];
+extern const u8 gUnknown_081E7834[];
+extern const u8 gUnknown_081E796C[];
+extern const u8 gUnknown_0840DFF7[];
+
+extern u8 gSpriteAffineAnimTable_81E79AC[];
+
+extern struct Sprite gSprites[];
+extern u8 gStringVar4[];
+
+extern u8 unk_2000000[];
+
+void task_new_game_prof_birch_speech_2(u8 taskId);
+void task_new_game_prof_birch_speech_3(u8 taskId);
+void task_new_game_prof_birch_speech_4(u8 taskId);
+void task_new_game_prof_birch_speech_5(u8 taskId);
+void task_new_game_prof_birch_speech_6(u8 taskId);
+void task_new_game_prof_birch_speech_7(u8 taskId);
+void task_new_game_prof_birch_speech_8(u8 taskId);
+void task_new_game_prof_birch_speech_9(u8 taskId);
+void task_new_game_prof_birch_speech_10(u8 taskId);
+void task_new_game_prof_birch_speech_11(u8 taskId);
+void task_new_game_prof_birch_speech_12(u8 taskId);
+void task_new_game_prof_birch_speech_13(u8 taskId);
+void task_new_game_prof_birch_speech_14(u8 taskId);
+void task_new_game_prof_birch_speech_15(u8 taskId);
+void task_new_game_prof_birch_speech_16(u8 taskId);
+void task_new_game_prof_birch_speech_17(u8 taskId);
+void task_new_game_prof_birch_speech_18(u8 taskId);
+void sub_800A974(u8 taskId);
+void Task_800A9B4(u8 taskId);
+void sub_800A9EC(u8 taskId);
+void sub_800AAAC(u8 taskId);
+void task_new_game_prof_birch_speech_part2_1(u8 taskId);
+void sub_800AB38(u8 taskId);
+void task_new_game_prof_birch_speech_part2_4(u8 taskId);
+void sub_800AC20(u8 taskId);
+void task_new_game_prof_birch_speech_part2_6(u8 taskId);
+void task_new_game_prof_birch_speech_part2_7(u8 taskId);
+void task_new_game_prof_birch_speech_part2_8(u8 taskId);
+void task_new_game_prof_birch_speech_part2_9(u8 taskId);
+void task_new_game_prof_birch_speech_part2_10(u8 taskId);
+void sub_800AFC0(u8 taskId);
+void sub_800B034(u8 taskId);
+void new_game_prof_birch_speech_part2_start();
+void nullsub_34(struct Sprite *sprite);
+void sub_800B240(struct Sprite *sprite);
+u8 CreateAzurillSprite(u8, u8);
+void AddBirchSpeechObjects(u8);
+void sub_800B3EC(u8);
+void sub_800B458(u8, u8);
+void sub_800B4C8(u8);
+void sub_800B534(u8 taskId, u8 a);
+void sub_800B5A8(u8);
+void sub_800B614(u8, u8);
+void sub_800B654(u8);
+void sub_800B6C0(u8 taskId, u8 a);
+void CreateGenderMenu(u8 left, u8 top);
+s8 GenderMenuProcessInput(void);
+void CreateNameMenu(u8 a, u8 b);
+s8 NameMenuProcessInput(void);
+void set_default_player_name(u8 a);
+
+void Task_Birch1(u8 taskId)
+{
+ SetUpWindowConfig(&gWindowConfig_81E6C3C);
+ InitMenuWindow(&gWindowConfig_81E6CE4);
+ REG_WIN0H = 0;
+ REG_WIN0V = 0;
+ REG_WININ = 0;
+ REG_WINOUT = 0;
+ REG_BLDCNT = 0;
+ REG_BLDALPHA = 0;
+ REG_BLDY = 0;
+ LZ77UnCompVram(gUnknown_081E768C, (void *)BG_VRAM);
+ LZ77UnCompVram(gUnknown_081E7834, (void *)(BG_VRAM + 0x3800));
+ LoadPalette(gUnknown_081E764C, 0, 0x40);
+ LoadPalette(gUnknown_081E796C, 1, 0x10);
+ remove_some_task();
+ ResetSpriteData();
+ FreeAllSpritePalettes();
+ AddBirchSpeechObjects(taskId);
+ BeginNormalPaletteFade(-1, 0, 0x10, 0, 0);
+ REG_BG1CNT = 0x00000703;
+ REG_DISPCNT = DISPCNT_BG0_ON | DISPCNT_BG1_ON | DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP;
+ gTasks[taskId].data[4] = 0;
+ gTasks[taskId].func = task_new_game_prof_birch_speech_2;
+ gTasks[taskId].data[2] = 0xFF;
+ gTasks[taskId].data[3] = 0xFF;
+ gTasks[taskId].data[7] = 0xD8;
+
+ sub_8075474(BGM_DOORO_X4);
+}
+
+void task_new_game_prof_birch_speech_2(u8 taskId)
+{
+ struct Task *tasks = gTasks;
+ struct Task *task = &tasks[taskId];
+
+ if (task->data[7] != 0)
+ {
+ task->data[7]--;
+ }
+ else
+ {
+ u8 spriteId = task->data[8];
+ struct Sprite *sprites = gSprites;
+ struct Sprite *sprite = &sprites[spriteId];
+ sprite->pos1.x = 0x88;
+ sprite->pos1.y = 0x3C;
+ sprite->invisible = 0;
+ sprite->oam.objMode = 1;
+ sub_800B534(taskId, 0xA);
+ sub_800B6C0(taskId, 0x14);
+ task->data[7] = 0x50;
+ task->func = task_new_game_prof_birch_speech_3;
+ }
+}
+
+void task_new_game_prof_birch_speech_3(u8 taskId)
+{
+ struct Task *tasks = gTasks;
+ struct Task *task = &tasks[taskId];
+
+ if (task->data[5] != 0)
+ {
+ struct Sprite *sprites = gSprites;
+ struct Sprite *sprite = &sprites[task->data[8]];
+
+ sprite->oam.objMode = 0;
+ if (task->data[7])
+ {
+ task->data[7]--;
+ }
+ else
+ {
+ MenuDrawTextWindow(0x2, 0xD, 0x1B, 0x12);
+ MenuPrintMessage(gUnknown_081C6D78, 3, 14);
+ task->func = task_new_game_prof_birch_speech_4;
+ }
+ }
+}
+
+void task_new_game_prof_birch_speech_4(u8 taskId)
+{
+ if (!gPaletteFade.active && MenuUpdateWindowText_OverrideLineLength(24))
+ {
+ gTasks[taskId].func = task_new_game_prof_birch_speech_5;
+ MenuPrintMessage(gUnknown_081C6DF8, 3, 14);
+ }
+}
+
+void task_new_game_prof_birch_speech_5(u8 taskId)
+{
+ if (MenuUpdateWindowText_OverrideLineLength(24))
+ gTasks[taskId].func = task_new_game_prof_birch_speech_6;
+}
+
+void task_new_game_prof_birch_speech_6(u8 taskId)
+{
+ struct Task *tasks = gTasks;
+ struct Task *task = &tasks[taskId];
+ u8 data = task->data[9];
+ struct Sprite *sprites = gSprites;
+ struct Sprite *sprite = &sprites[data];
+
+ sprite->pos1.x = 0x68;
+ sprite->pos1.y = 0x48;
+ sprite->invisible = 0;
+ sprite->data0 = 0;
+ CreatePokeballSprite(data, sprite->oam.paletteNum, 0x70, 0x3A, 0, 0, 0x20, 0x0000FFFF);
+ task->func = task_new_game_prof_birch_speech_7;
+ task->data[7] = 0;
+}
+
+void task_new_game_prof_birch_speech_7(u8 taskId)
+{
+ struct Task *tasks;
+ struct Task *task;
+
+ if (sub_8075374())
+ {
+ struct Task *tasks = gTasks;
+ struct Task *task = &tasks[taskId];
+
+ if (task->data[7] > 0x5F)
+ {
+ MenuSetText((u32)&gUnknown_0840DFF7);
+ task->func = task_new_game_prof_birch_speech_8;
+ }
+ }
+
+ tasks = gTasks;
+ task = &tasks[taskId];
+
+ if (task->data[7] < 0x4000)
+ {
+ task->data[7]++;
+ if (task->data[7] == 0x20)
+ {
+ cry_related(SPECIES_AZURILL, 0);
+ }
+ }
+}
+
+void task_new_game_prof_birch_speech_8(u8 taskId)
+{
+ if (MenuUpdateWindowText_OverrideLineLength(24))
+ {
+ MenuPrintMessage(gUnknown_081C6E1A, 3, 14);
+ gTasks[taskId].func = task_new_game_prof_birch_speech_9;
+ }
+}
+
+void task_new_game_prof_birch_speech_9(u8 taskId)
+{
+ if (MenuUpdateWindowText_OverrideLineLength(24))
+ {
+ MenuDrawTextWindow(0x2, 0xD, 0x1B, 0x12);
+ MenuPrintMessage(gUnknown_081C6FCB, 3, 14);
+ gTasks[taskId].func = task_new_game_prof_birch_speech_10;
+ }
+}
+
+void task_new_game_prof_birch_speech_10(u8 taskId)
+{
+ if (MenuUpdateWindowText_OverrideLineLength(24))
+ {
+ struct Sprite *sprites = gSprites;
+ struct Task *tasks = gTasks;
+ struct Task *task = &tasks[taskId];
+ struct Sprite *sprite = &sprites[task->data[8]];
+ struct Sprite *sprite2;
+
+ sprite->oam.objMode = 1;
+ sprite2 = &sprites[task->data[9]];
+ sprite2->oam.objMode = 1;
+ sub_800B458(taskId, 0x2);
+ sub_800B614(taskId, 0x1);
+ task->data[7] = 0x40;
+ task->func = task_new_game_prof_birch_speech_11;
+ }
+}
+
+void task_new_game_prof_birch_speech_11(u8 taskId)
+{
+ struct Task *tasks = gTasks;
+ struct Task *task = &tasks[taskId];
+
+ if (task->data[4] != -0x3C)
+ {
+ task->data[4] -= 2;
+ REG_BG1HOFS = task->data[4];
+ }
+ else
+ {
+ task->data[4] = 0x0000ffc4;
+ task->func = task_new_game_prof_birch_speech_12;
+ }
+}
+
+void task_new_game_prof_birch_speech_12(u8 taskId)
+{
+ if (gTasks[taskId].data[5])
+ {
+ gSprites[gTasks[taskId].data[8]].invisible = 1;
+ gSprites[gTasks[taskId].data[9]].invisible = 1;
+
+ if (gTasks[taskId].data[7])
+ {
+ gTasks[taskId].data[7]--;
+ }
+ else
+ {
+ u8 data10 = gTasks[taskId].data[10];
+
+ gSprites[data10].pos1.x = 0xB4;
+ gSprites[data10].pos1.y = 0x3C;
+ gSprites[data10].invisible = 0;
+ gSprites[data10].oam.objMode = 1;
+ gTasks[taskId].data[2] = data10;
+ gTasks[taskId].data[6] = 0;
+ sub_800B534(taskId, 2);
+ sub_800B6C0(taskId, 1);
+ gTasks[taskId].func = task_new_game_prof_birch_speech_13;
+ }
+ }
+}
+
+void task_new_game_prof_birch_speech_13(u8 taskId)
+{
+ struct Task *tasks = gTasks;
+ struct Task *task = &tasks[taskId];
+
+ if (task->data[5])
+ {
+ struct Sprite *sprites = gSprites;
+ struct Sprite *sprite = &sprites[task->data[2]];
+
+ sprite->oam.objMode = 0;
+ task->func = task_new_game_prof_birch_speech_14;
+ }
+}
+
+void task_new_game_prof_birch_speech_14(u8 taskId)
+{
+ MenuDrawTextWindow(2, 0xD, 0x1B, 0x12);
+ MenuPrintMessage(gUnknown_081C6FD8, 3, 14);
+ gTasks[taskId].func = task_new_game_prof_birch_speech_15;
+}
+
+void task_new_game_prof_birch_speech_15(u8 taskId)
+{
+ if (MenuUpdateWindowText_OverrideLineLength(24))
+ {
+ CreateGenderMenu(2, 4);
+ gTasks[taskId].func = task_new_game_prof_birch_speech_16;
+ }
+}
+
+void task_new_game_prof_birch_speech_16(u8 taskId)
+{
+ u8 cursorPos;
+
+ switch (GenderMenuProcessInput())
+ {
+ case MALE:
+ sub_8072DEC();
+ audio_play(SE_SELECT);
+ gSaveBlock2.playerGender = MALE;
+ MenuZeroFillWindowRect(2, 4, 8, 9);
+ gTasks[taskId].func = sub_800A974;
+ break;
+ case FEMALE:
+ sub_8072DEC();
+ audio_play(SE_SELECT);
+ gSaveBlock2.playerGender = FEMALE;
+ MenuZeroFillWindowRect(2, 4, 8, 9);
+ gTasks[taskId].func = sub_800A974;
+ break;
+ }
+
+ cursorPos = GetMenuCursorPos();
+
+ if (cursorPos != gTasks[taskId].data[6])
+ {
+ gTasks[taskId].data[6] = cursorPos;
+ gSprites[gTasks[taskId].data[2]].oam.objMode = 1;
+ sub_800B458(taskId, 0);
+ gTasks[taskId].func = task_new_game_prof_birch_speech_17;
+ }
+}
+
+void task_new_game_prof_birch_speech_17(u8 taskId)
+{
+ u8 spriteId = gTasks[taskId].data[2];
+
+ if (gTasks[taskId].data[5] == 0)
+ {
+ gSprites[spriteId].pos1.x += 4;
+ }
+ else
+ {
+ gSprites[spriteId].invisible = 1;
+ if (gTasks[taskId].data[6])
+ {
+ spriteId = gTasks[taskId].data[11];
+ }
+ else
+ {
+ spriteId = gTasks[taskId].data[10];
+ }
+
+ gSprites[spriteId].pos1.x = 0xF0;
+ gSprites[spriteId].pos1.y = 0x3C;
+ gSprites[spriteId].invisible = 0;
+ gTasks[taskId].data[2] = spriteId;
+ gSprites[spriteId].oam.objMode = 1;
+ sub_800B534(taskId, 0);
+ gTasks[taskId].func = task_new_game_prof_birch_speech_18;
+ }
+}
+
+void task_new_game_prof_birch_speech_18(u8 taskId)
+{
+ u8 spriteId = gTasks[taskId].data[2];
+
+ if (gSprites[spriteId].pos1.x > 0xB4)
+ {
+ gSprites[spriteId].pos1.x -= 4;
+ }
+ else
+ {
+ gSprites[spriteId].pos1.x = 0xB4;
+ if (gTasks[taskId].data[5])
+ {
+ gSprites[spriteId].oam.objMode = 0;
+ gTasks[taskId].func = task_new_game_prof_birch_speech_16;
+ }
+ }
+}
+
+void sub_800A974(u8 taskId)
+{
+ MenuDrawTextWindow(2, 13, 27, 18);
+ MenuPrintMessage(gUnknown_081C6FFA, 3, 14);
+ gTasks[taskId].func = Task_800A9B4;
+}
+
+void Task_800A9B4(u8 taskId)
+{
+ if (MenuUpdateWindowText_OverrideLineLength(24))
+ {
+ CreateNameMenu(2, 1);
+ gTasks[taskId].func = sub_800A9EC;
+ }
+}
+
+void sub_800A9EC(u8 taskId)
+{
+ s8 n = NameMenuProcessInput();
+
+ switch (n)
+ {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ sub_8072DEC();
+ audio_play(SE_SELECT);
+ MenuZeroFillWindowRect(2, 1, 22, 12);
+ set_default_player_name(n);
+ gTasks[taskId].func = task_new_game_prof_birch_speech_part2_1;
+ break;
+ case 0:
+ audio_play(SE_SELECT);
+ BeginNormalPaletteFade(-1, 0, 0, 16, 0);
+ gTasks[taskId].func = sub_800AAAC;
+ break;
+ case -1:
+ sub_8072DEC();
+ audio_play(SE_SELECT);
+ MenuZeroFillWindowRect(2, 1, 22, 12);
+ gTasks[taskId].func = task_new_game_prof_birch_speech_14;
+ break;
+ }
+}
+
+void sub_800AAAC(u8 taskId)
+{
+ if (!gPaletteFade.active)
+ {
+ set_default_player_name(1);
+ DoNamingScreen(0, &gSaveBlock2, gSaveBlock2.playerGender, 0, 0, new_game_prof_birch_speech_part2_start);
+ }
+}
+
+void task_new_game_prof_birch_speech_part2_1(u8 taskId)
+{
+ MenuDrawTextWindow(2, 13, 27, 18);
+ StringExpandPlaceholders(gStringVar4, gUnknown_081C7017);
+ MenuPrintMessage(gStringVar4, 3, 14);
+ gTasks[taskId].func = sub_800AB38;
+}
+
+void sub_800AB38(u8 taskId)
+{
+ if (MenuUpdateWindowText_OverrideLineLength(24))
+ {
+ DisplayYesNoMenu(2, 1, 1);
+ gTasks[taskId].func = task_new_game_prof_birch_speech_part2_4;
+ }
+}
+
+void task_new_game_prof_birch_speech_part2_4(u8 taskId)
+{
+ switch (ProcessMenuInputNoWrap_())
+ {
+ case 0:
+ audio_play(SE_SELECT);
+ MenuZeroFillWindowRect(2, 1, 8, 7);
+ gSprites[gTasks[taskId].data[2]].oam.objMode = ST_OAM_OBJ_BLEND;
+ sub_800B458(taskId, 2);
+ sub_800B614(taskId, 1);
+ gTasks[taskId].func = sub_800AC20;
+ break;
+ case -1:
+ case 1:
+ audio_play(SE_SELECT);
+ MenuZeroFillWindowRect(2, 1, 8, 7);
+ gTasks[taskId].func = task_new_game_prof_birch_speech_14;
+ break;
+ }
+}
+
+void sub_800AC20(u8 taskId)
+{
+ if (gTasks[taskId].data[4])
+ {
+ gTasks[taskId].data[4] += 2;
+ REG_BG1HOFS = gTasks[taskId].data[4];
+ }
+ else
+ {
+ gTasks[taskId].func = task_new_game_prof_birch_speech_part2_6;
+ }
+}
+
+void task_new_game_prof_birch_speech_part2_6(u8 taskId)
+{
+ if (gTasks[taskId].data[5])
+ {
+ s16 spriteId;
+
+ spriteId = gTasks[taskId].data[10];
+ gSprites[spriteId].invisible = 1;
+
+ spriteId = gTasks[taskId].data[11];
+ gSprites[spriteId].invisible = 1;
+
+ spriteId = (u8)gTasks[taskId].data[8];
+ gSprites[spriteId].pos1.x = 0x88;
+ gSprites[spriteId].pos1.y = 0x40;
+ gSprites[spriteId].invisible = 0;
+ gSprites[spriteId].oam.objMode = 1;
+
+ spriteId = (u8)gTasks[taskId].data[9];
+ gSprites[spriteId].pos1.x = 0x68;
+ gSprites[spriteId].pos1.y = 0x48;
+ gSprites[spriteId].invisible = 0;
+ gSprites[spriteId].oam.objMode = 1;
+
+ sub_800B534(taskId, 2);
+ sub_800B6C0(taskId, 1);
+ MenuDrawTextWindow(2, 13, 27, 18);
+ StringExpandPlaceholders(gStringVar4, gUnknown_081C7025);
+ MenuPrintMessage(gStringVar4, 3, 14);
+ gTasks[taskId].func = task_new_game_prof_birch_speech_part2_7;
+ }
+}
+
+void task_new_game_prof_birch_speech_part2_7(u8 taskId)
+{
+ if (gTasks[taskId].data[5])
+ {
+ s16 spriteId;
+
+ spriteId = gTasks[taskId].data[8];
+ gSprites[spriteId].oam.objMode = 0;
+
+ spriteId = gTasks[taskId].data[9];
+ gSprites[spriteId].oam.objMode = 0;
+
+ if (MenuUpdateWindowText_OverrideLineLength(24))
+ {
+ spriteId = gTasks[taskId].data[8];
+ gSprites[spriteId].oam.objMode = 1;
+
+ spriteId = gTasks[taskId].data[9];
+ gSprites[spriteId].oam.objMode = 1;
+
+ sub_800B458(taskId, 2);
+ sub_800B614(taskId, 1);
+ gTasks[taskId].data[7] = 0x40;
+ gTasks[taskId].func = task_new_game_prof_birch_speech_part2_8;
+ }
+ }
+}
+
+void task_new_game_prof_birch_speech_part2_8(u8 taskId)
+{
+ if (gTasks[taskId].data[5])
+ {
+ s16 spriteId;
+
+ spriteId = gTasks[taskId].data[8];
+ gSprites[spriteId].invisible = 1;
+
+ spriteId = gTasks[taskId].data[9];
+ gSprites[spriteId].invisible = 1;
+
+ if (gTasks[taskId].data[7])
+ {
+ gTasks[taskId].data[7]--;
+ }
+ else
+ {
+ u8 spriteId;
+
+ if (gSaveBlock2.playerGender)
+ spriteId = (u8)gTasks[taskId].data[11];
+ else
+ spriteId = (u8)gTasks[taskId].data[10];
+
+ gSprites[spriteId].pos1.x = 0x78;
+ gSprites[spriteId].pos1.y = 0x3C;
+ gSprites[spriteId].invisible = 0;
+ gSprites[spriteId].oam.objMode = 1;
+ gTasks[taskId].data[2] = spriteId;
+
+ sub_800B534(taskId, 2);
+ sub_800B6C0(taskId, 1);
+ MenuDrawTextWindow(2, 13, 27, 18);
+ MenuPrintMessage(gUnknown_081C7074, 3, 14);
+ gTasks[taskId].func = task_new_game_prof_birch_speech_part2_9;
+ }
+ }
+}
+
+void task_new_game_prof_birch_speech_part2_9(u8 taskId)
+{
+ if (gTasks[taskId].data[5])
+ {
+ s16 spriteId;
+
+ spriteId = gTasks[taskId].data[2];
+ gSprites[spriteId].oam.objMode = 0;
+
+ if (MenuUpdateWindowText_OverrideLineLength(24))
+ {
+ u8 spriteId;
+
+ spriteId = gTasks[taskId].data[2];
+ gSprites[spriteId].oam.affineMode = 1;
+ gSprites[spriteId].affineAnims = (union AffineAnimCmd **)gSpriteAffineAnimTable_81E79AC;
+ InitSpriteAffineAnim(&gSprites[spriteId]);
+ StartSpriteAffineAnim(&gSprites[spriteId], 0);
+ gSprites[spriteId].callback = sub_800B240;
+ BeginNormalPaletteFade(0x0000ffff, 0, 0, 0x10, 0);
+ play_sound_effect(4);
+ gTasks[taskId].func = task_new_game_prof_birch_speech_part2_10;
+ }
+ }
+}
+
+void task_new_game_prof_birch_speech_part2_10(u8 taskId)
+{
+ u8 spriteId = gTasks[taskId].data[2];
+
+ if (gSprites[spriteId].affineAnimEnded)
+ gTasks[taskId].func = sub_800AFC0;
+}
+
+void sub_800AFC0(u8 taskId)
+{
+ if (!gPaletteFade.active)
+ {
+ u8 spriteId = gTasks[taskId].data[2];
+ gSprites[spriteId].callback = nullsub_34;
+ REG_DISPCNT = 4160;
+ BeginNormalPaletteFade(0xFFFF0000, 0, 0, 0x10, 0xFFFF);
+ gTasks[taskId].func = sub_800B034;
+ }
+}
+
+void sub_800B034(u8 taskId)
+{
+ if (!gPaletteFade.active)
+ {
+ SetMainCallback2(c2_load_new_map_2);
+ DestroyTask(taskId);
+ }
+}
+
+// CB2
+void new_game_prof_birch_speech_part2_start()
+{
+ u8 taskId;
+ u8 spriteId;
+ u16 savedIme;
+
+ SetVBlankCallback(NULL);
+
+ REG_DISPCNT = 0;
+ REG_BG2CNT = 0;
+ REG_BG1CNT = 0;
+ REG_BG0CNT = 0;
+ REG_BG2HOFS = 0;
+ REG_BG2VOFS = 0;
+ REG_BG1HOFS = 0;
+ REG_BG1VOFS = 0;
+ REG_BG0HOFS = 0;
+ REG_BG0VOFS = 0;
+
+ DmaFill16(3, 0, (void *)VRAM, VRAM_SIZE);
+ DmaFill32(3, 0, (void *)OAM, OAM_SIZE);
+ DmaFill16(3, 0, (void *)PLTT, PLTT_SIZE);
+
+ ResetPaletteFade();
+
+ LZ77UnCompVram(gUnknown_081E768C, (void *)BG_VRAM);
+ LZ77UnCompVram(gUnknown_081E7834, (void *)(BG_VRAM + 0x3800));
+
+ LoadPalette(gUnknown_081E764C, 0, 0x40);
+
+ ResetTasks();
+
+ taskId = CreateTask(task_new_game_prof_birch_speech_part2_1, 0);
+
+ gTasks[taskId].data[4] = -60;
+
+ remove_some_task();
+ ResetSpriteData();
+ FreeAllSpritePalettes();
+ AddBirchSpeechObjects(taskId);
+
+ SetUpWindowConfig(&gWindowConfig_81E6C3C);
+ InitMenuWindow(&gWindowConfig_81E6CE4);
+
+ if (gSaveBlock2.playerGender != MALE)
+ {
+ gTasks[taskId].data[6] = FEMALE;
+ spriteId = gTasks[taskId].data[11];
+ }
+ else
+ {
+ gTasks[taskId].data[6] = MALE;
+ spriteId = gTasks[taskId].data[10];
+ }
+
+ gSprites[spriteId].pos1.x = 180;
+ gSprites[spriteId].pos1.y = 60;
+ gSprites[spriteId].invisible = 0;
+
+ gTasks[taskId].data[2] = spriteId;
+
+ REG_BG1HOFS = -60;
+
+ BeginNormalPaletteFade(0xFFFFFFFFu, 0, 0x10, 0, 0);
+
+ REG_WIN0H = 0;
+ REG_WIN0V = 0;
+ REG_WININ = 0;
+ REG_WINOUT = 0;
+ REG_BLDCNT = 0;
+ REG_BLDALPHA = 0;
+ REG_BLDY = 0;
+
+ savedIme = REG_IME;
+ REG_IME = 0;
+ REG_IE |= INTR_FLAG_VBLANK;
+ REG_IME = savedIme;
+
+ SetVBlankCallback(VBlankCB_MainMenu);
+ SetMainCallback2(CB2_MainMenu);
+ REG_BG1CNT = 1795;
+ REG_DISPCNT = 4928;
+}
+
+void nullsub_34(struct Sprite *sprite)
+{
+}
+
+void sub_800B240(struct Sprite *sprite)
+{
+ u32 y = (sprite->pos1.y << 16) + sprite->data0 + 0xC000;
+ sprite->pos1.y = y >> 16;
+ sprite->data0 = y;
+}
+
+u8 CreateAzurillSprite(u8 a1, u8 a2)
+{
+ DecompressPicFromTable_2(
+ &gMonFrontPicTable[SPECIES_AZURILL],
+ gMonFrontPicCoords[SPECIES_AZURILL].x,
+ gMonFrontPicCoords[SPECIES_AZURILL].y,
+ gUnknown_081FAF4C[0],
+ gUnknown_081FAF4C[1],
+ SPECIES_AZURILL);
+ LoadCompressedObjectPalette(&gMonPaletteTable[SPECIES_AZURILL]);
+ GetMonSpriteTemplate_803C56C(SPECIES_AZURILL, 1);
+ return CreateSprite(&gUnknown_02024E8C, a1, a2, 0);
+}
+
+void AddBirchSpeechObjects(u8 taskId)
+{
+ u8 spriteId;
+
+ spriteId = AddNewGameBirchObject(136, 60, 1);
+ gSprites[spriteId].callback = nullsub_34;
+ gSprites[spriteId].oam.priority = 0;
+ gSprites[spriteId].invisible = 1;
+ gTasks[taskId].data[8] = spriteId;
+
+ spriteId = CreateAzurillSprite(0x68, 0x48);
+ gSprites[spriteId].callback = nullsub_34;
+ gSprites[spriteId].oam.priority = 0;
+ gSprites[spriteId].invisible = 1;
+ gTasks[taskId].data[9] = spriteId;
+
+ spriteId = sub_80859BC(0, 120, 60, 0, unk_2000000);
+ gSprites[spriteId].callback = nullsub_34;
+ gSprites[spriteId].invisible = 1;
+ gSprites[spriteId].oam.priority = 0;
+ gTasks[taskId].data[10] = spriteId;
+
+ spriteId = sub_80859BC(1, 120, 60, 0, unk_2000000 + 0x800);
+ gSprites[spriteId].callback = nullsub_34;
+ gSprites[spriteId].invisible = 1;
+ gSprites[spriteId].oam.priority = 0;
+ gTasks[taskId].data[11] = spriteId;
+}
+
+void sub_800B3EC(u8 taskId)
+{
+ if (gTasks[taskId].data[1] == 0)
+ {
+ gTasks[gTasks[taskId].data[0]].data[5] = 1;
+ DestroyTask(taskId);
+ }
+ else
+ {
+ if (gTasks[taskId].data[4])
+ {
+ gTasks[taskId].data[4]--;
+ }
+ else
+ {
+ gTasks[taskId].data[4] = gTasks[taskId].data[3];
+ gTasks[taskId].data[1]--;
+ gTasks[taskId].data[2]++;
+ REG_BLDALPHA = gTasks[taskId].data[1] + (gTasks[taskId].data[2] * 256);
+ }
+ }
+}
+
+void sub_800B458(u8 taskId, u8 a2)
+{
+ u8 newTaskId;
+
+ REG_BLDCNT = 592;
+ REG_BLDALPHA = 16;
+ REG_BLDY = 0;
+ gTasks[taskId].data[5] = 0;
+ newTaskId = CreateTask(sub_800B3EC, 0);
+
+ gTasks[newTaskId].data[0] = taskId;
+ gTasks[newTaskId].data[1] = 16;
+ gTasks[newTaskId].data[2] = 0;
+ gTasks[newTaskId].data[3] = a2;
+ gTasks[newTaskId].data[4] = a2;
+}
+
+void sub_800B4C8(u8 taskId)
+{
+ if (gTasks[taskId].data[1] == 16)
+ {
+ gTasks[gTasks[taskId].data[0]].data[5] = 1;
+ DestroyTask(taskId);
+ }
+ else if (gTasks[taskId].data[4])
+ {
+ gTasks[taskId].data[4]--;
+ }
+ else
+ {
+ gTasks[taskId].data[4] = gTasks[taskId].data[3];
+ gTasks[taskId].data[1]++;
+ gTasks[taskId].data[2]--;
+ REG_BLDALPHA = gTasks[taskId].data[1] + (gTasks[taskId].data[2] * 256);
+ }
+}
+
+void sub_800B534(u8 taskId, u8 a2)
+{
+ u8 newTaskId;
+
+ REG_BLDCNT = 592;
+ REG_BLDALPHA = 4096;
+ REG_BLDY = 0;
+ gTasks[taskId].data[5] = 0;
+ newTaskId = CreateTask(sub_800B4C8, 0);
+
+ gTasks[newTaskId].data[0] = taskId;
+ gTasks[newTaskId].data[1] = 0;
+ gTasks[newTaskId].data[2] = 16;
+ gTasks[newTaskId].data[3] = a2;
+ gTasks[newTaskId].data[4] = a2;
+}
+
+void sub_800B5A8(u8 taskId)
+{
+ if (gTasks[taskId].data[2])
+ {
+ gTasks[taskId].data[2]--;
+ }
+ else
+ {
+ if (gTasks[taskId].data[1] == 8)
+ {
+ DestroyTask(taskId);
+ }
+ else if (gTasks[taskId].data[4])
+ {
+ gTasks[taskId].data[4]--;
+ }
+ else
+ {
+ gTasks[taskId].data[4] = gTasks[taskId].data[3];
+ gTasks[taskId].data[1]++;
+ LoadPalette(&gUnknown_081E795C[gTasks[taskId].data[1]], 1, 0x10);
+ }
+ }
+}
+
+void sub_800B614(u8 a1, u8 a2)
+{
+ u8 newTaskId = CreateTask(sub_800B5A8, 0);
+ gTasks[newTaskId].data[0] = a1;
+ gTasks[newTaskId].data[1] = 0;
+ gTasks[newTaskId].data[2] = 8;
+ gTasks[newTaskId].data[3] = a2;
+ gTasks[newTaskId].data[4] = a2;
+}
+
+void sub_800B654(u8 taskId)
+{
+ if (gTasks[taskId].data[2])
+ {
+ gTasks[taskId].data[2]--;
+ }
+ else
+ {
+ if (gTasks[taskId].data[1] == 0)
+ {
+ DestroyTask(taskId);
+ }
+ else
+ {
+ if (gTasks[taskId].data[4])
+ {
+ gTasks[taskId].data[4]--;
+ }
+ else
+ {
+ gTasks[taskId].data[4] = gTasks[taskId].data[3];
+ gTasks[taskId].data[1]--;
+ LoadPalette(&gUnknown_081E795C[gTasks[taskId].data[1]], 1, 0x10);
+ }
+ }
+ }
+}
+
+void sub_800B6C0(u8 a1, u8 a2)
+{
+ u8 newTaskId = CreateTask(sub_800B654, 0);
+ gTasks[newTaskId].data[0] = a1;
+ gTasks[newTaskId].data[1] = 8;
+ gTasks[newTaskId].data[2] = 8;
+ gTasks[newTaskId].data[3] = a2;
+ gTasks[newTaskId].data[4] = a2;
+}
+
+void CreateGenderMenu(u8 left, u8 top)
+{
+ u8 menuLeft, menuTop;
+ MenuDrawTextWindow(left, top, left + 6, top + 5);
+ menuLeft = left + 1;
+ menuTop = top + 1;
+ PrintMenuItems(menuLeft, menuTop, 2, gUnknown_081E79B0);
+ InitMenu(0, menuLeft, menuTop, 2, 0, 5);
+}
+
+s8 GenderMenuProcessInput(void)
+{
+ return ProcessMenuInputNoWrap();
+}
+
+void CreateNameMenu(u8 left, u8 top)
+{
+ MenuDrawTextWindow(left, top, left + 10, top + 11);
+
+ if (gSaveBlock2.playerGender == MALE)
+ {
+ PrintMenuItems((u8)(left + 1), (u8)(top + 1), 5, gUnknown_081E79C0);
+ }
+ else
+ {
+ PrintMenuItems((u8)(left + 1), (u8)(top + 1), 5, gUnknown_081E79E8);
+ }
+
+ InitMenu(0, (u8)(left + 1), (u8)(top + 1), 5, 0, 9);
+}
+
+s8 NameMenuProcessInput(void)
+{
+ return ProcessMenuInput();
+}
+
+void set_default_player_name(u8 index)
+{
+ u8 i;
+ u8 *name;
+
+ if (gSaveBlock2.playerGender == MALE)
+ name = gUnknown_081E79C0[index][0];
+ else
+ name = gUnknown_081E79E8[index][0];
+
+ for (i = 0; i < 7; i++)
+ gSaveBlock2.playerName[i] = name[i];
+
+ gSaveBlock2.playerName[i] = EOS;
+}
diff --git a/src/menu.c b/src/menu.c
new file mode 100644
index 000000000..b101165f2
--- /dev/null
+++ b/src/menu.c
@@ -0,0 +1,1003 @@
+#include "global.h"
+#include "main.h"
+#include "text.h"
+#include "songs.h"
+#include "text_window.h"
+
+struct Menu
+{
+ u8 left;
+ u8 top;
+ s8 cursorPos;
+ s8 minCursorPos;
+ s8 maxCursorPos;
+ u8 width;
+ u8 height;
+ u8 menu_field_7;
+ u8 columnXCoords[8];
+};
+
+void InitMenuWindow(struct WindowConfig *);
+void MultistepInitMenuWindowBegin(struct WindowConfig *);
+void MultistepInitMenuWindowInternal(struct WindowConfig *, u16);
+bool32 MultistepInitMenuWindowContinue(void);
+void InitMenuWindowInternal(struct WindowConfig *, u16);
+void unref_sub_8071DA4(struct WindowConfig *, u16);
+void MenuLoadTextWindowGraphics_OverrideFrameType(u8);
+void MenuLoadTextWindowGraphics(void);
+void BasicInitMenuWindow(struct WindowConfig *);
+void MenuPrint(u8 *, u8, u8);
+void MenuZeroFillWindowRect(u8, u8, u8, u8);
+void MenuFillWindowRectWithBlankTile(u8, u8, u8, u8);
+void MenuZeroFillScreen(void);
+void MenuDrawTextWindow(u8, u8, u8, u8);
+void sub_8071F40(u8 *);
+void sub_8071F60(u8, u8, u8, u8);
+u16 unref_sub_8071F98(u8, u8);
+void unref_sub_8071FBC(u16, u8, u8, u8, u8);
+void MenuDisplayMessageBox(void);
+void MenuPrintMessage(u8 *, u8, u8);
+void sub_8072044(u8 *);
+void MenuSetText(u8 *);
+u8 MenuUpdateWindowText(void);
+u8 unref_sub_8072098(void);
+void sub_80720B0(void);
+u8 MoveMenuCursor(s8);
+u8 MoveMenuCursorNoWrap(s8);
+u8 GetMenuCursorPos(void);
+s8 ProcessMenuInput(void);
+s8 ProcessMenuInputNoWrap(void);
+u8 MoveMenuCursor3(s8);
+u8 MoveMenuCursor4(s8);
+bool8 sub_80723D4(void);
+u8 sub_8072484(u8, u8, u8, u8, u8, u8, u32);
+u8 sub_80724F4(u8, u8, u8, u8*[][2], u8);
+void sub_8072620(u8, u8, u8, u8*[][2], u8);
+void sub_807274C(u8, u8, u8, u8, u8*[][2], u8, u32);
+s8 sub_80727CC(void);
+u8 sub_807288C(u8);
+void PrintMenuItems(u8, u8, u8, u8*[][2]);
+void PrintMenuItemsReordered(u8, u8, u8, u8*[][2], u8*);
+void InitYesNoMenu(u8, u8, u8);
+void DisplayYesNoMenu(u8, u8, u32);
+s8 ProcessMenuInputNoWrap_(void);
+u8 sub_80729D8(u8 *, u8, u16, u8);
+u8 sub_8072A18(u8 *, u8, u16, u8, u32);
+u8 unref_sub_8072A5C(u8 *, u8 *, u8, u16, u8, u32);
+int sub_8072AB0(u8 *, u8, u16, u8, u8, u32);
+void sub_8072B4C(u8 *, u8, u8);
+void sub_8072B80(u8 *, u8, u8, u8 *);
+void sub_8072BD8(u8 *, u8, u8, u16);
+u8 *sub_8072C14(u8 *, s32, u8, u8);
+u8 *sub_8072C44(u8 *, s32, u8, u8);
+u8 *sub_8072C74(u8 *, u8 *, u8, u8);
+u8 sub_8072CA4(u8 *s);
+u8 sub_8072CBC(void);
+void sub_8072CD4(u8 *, u8 *, u8 *);
+u32 MenuUpdateWindowText_OverrideLineLength(u8);
+struct Window * unref_sub_8072D0C(void);
+void sub_8072D18(u8, u8);
+u8 InitMenu(u8, u8, u8, u8, u8, u8);
+void RedrawMenuCursor(u8, u8);
+void unref_sub_8072DC0(void);
+void sub_8072DCC(u8);
+void sub_8072DDC(u8);
+void sub_8072DEC(void);
+
+extern void sub_814A5C0(u8, u16, u8, u16, u8);
+extern void sub_814A880(u8, u8);
+extern void sub_814A904(void);
+extern void sub_814A958(u8);
+extern void sub_814A7FC(void);
+
+static struct Menu gMenu;
+
+extern struct Window gMenuWindow;
+extern struct Window *gMenuWindowPtr;
+extern u8 gMenuMultistepInitState;
+extern u16 gMenuTextTileOffset;
+extern u16 gMenuTextWindowTileOffset;
+extern u16 gMenuTextWindowContentTileOffset;
+extern u16 gMenuMessageBoxContentTileOffset;
+
+extern const u8 *gUnknown_08376D74[][2];
+
+void InitMenuWindow(struct WindowConfig *winConfig)
+{
+ InitMenuWindowInternal(winConfig, 1);
+}
+
+void MultistepInitMenuWindowBegin(struct WindowConfig *winConfig)
+{
+ MultistepInitMenuWindowInternal(winConfig, 1);
+}
+
+void MultistepInitMenuWindowInternal(struct WindowConfig *winConfig, u16 tileOffset)
+{
+ gMenuMultistepInitState = 0;
+ gMenuTextTileOffset = tileOffset;
+ gMenuWindowPtr = &gMenuWindow;
+ InitWindowFromConfig(&gMenuWindow, winConfig);
+}
+
+bool32 MultistepInitMenuWindowContinue(void)
+{
+ switch (gMenuMultistepInitState)
+ {
+ case 0:
+ gMenuMultistepInitState++;
+ return 0;
+ case 1:
+ gMenuTextWindowTileOffset = MultistepInitWindowTileData(gMenuWindowPtr, gMenuTextTileOffset);
+ goto next;
+ case 2:
+ if (!MultistepLoadFont())
+ goto fail;
+ goto next;
+ case 3:
+ gMenuTextWindowContentTileOffset = SetTextWindowBaseTileNum(gMenuTextWindowTileOffset);
+ next:
+ gMenuMultistepInitState++;
+ return 0;
+ case 4:
+ LoadTextWindowGraphics(gMenuWindowPtr);
+ gMenuMessageBoxContentTileOffset = SetMessageBoxBaseTileNum(gMenuTextWindowContentTileOffset);
+ return 1;
+ default:
+ fail:
+ return 0;
+ }
+}
+
+void InitMenuWindowInternal(struct WindowConfig *winConfig, u16 tileOffset)
+{
+ gMenuWindowPtr = &gMenuWindow;
+ InitWindowFromConfig(&gMenuWindow, winConfig);
+ gMenuTextTileOffset = tileOffset;
+ gMenuTextWindowTileOffset = InitWindowTileData(gMenuWindowPtr, gMenuTextTileOffset);
+ gMenuTextWindowContentTileOffset = SetTextWindowBaseTileNum(gMenuTextWindowTileOffset);
+ LoadTextWindowGraphics(gMenuWindowPtr);
+ gMenuMessageBoxContentTileOffset = SetMessageBoxBaseTileNum(gMenuTextWindowContentTileOffset);
+}
+
+void unref_sub_8071DA4(struct WindowConfig *winConfig, u16 tileOffset)
+{
+ gMenuWindowPtr = &gMenuWindow;
+ InitWindowFromConfig(&gMenuWindow, winConfig);
+ gMenuTextWindowTileOffset = tileOffset;
+ gMenuTextWindowContentTileOffset = SetTextWindowBaseTileNum(gMenuTextWindowTileOffset);
+ LoadTextWindowGraphics(gMenuWindowPtr);
+ gMenuTextTileOffset = SetMessageBoxBaseTileNum(gMenuTextWindowContentTileOffset);
+ gMenuMessageBoxContentTileOffset = InitWindowTileData(gMenuWindowPtr, gMenuTextTileOffset);
+}
+
+void MenuLoadTextWindowGraphics_OverrideFrameType(u8 frameType)
+{
+ LoadTextWindowGraphics_OverrideFrameType(gMenuWindowPtr, frameType);
+}
+
+void MenuLoadTextWindowGraphics(void)
+{
+ LoadTextWindowGraphics(gMenuWindowPtr);
+}
+
+void BasicInitMenuWindow(struct WindowConfig *winConfig)
+{
+ InitWindowFromConfig(gMenuWindowPtr, winConfig);
+ gMenuWindowPtr->tileDataStartOffset = gMenuTextTileOffset;
+}
+
+void MenuPrint(u8 *str, u8 left, u8 top)
+{
+ sub_8003460(gMenuWindowPtr, str, gMenuTextTileOffset, left, top);
+}
+
+void MenuZeroFillWindowRect(u8 a1, u8 a2, u8 a3, u8 a4)
+{
+ ZeroFillWindowRect(gMenuWindowPtr, a1, a2, a3, a4);
+}
+
+void MenuFillWindowRectWithBlankTile(u8 left, u8 top, u8 right, u8 bottom)
+{
+ FillWindowRectWithBlankTile(gMenuWindowPtr, left, top, right, bottom);
+}
+
+void MenuZeroFillScreen(void)
+{
+ MenuZeroFillWindowRect(0, 0, 29, 19);
+}
+
+void MenuDrawTextWindow(u8 left, u8 top, u8 right, u8 bottom)
+{
+ DrawTextWindow(gMenuWindowPtr, left, top, right, bottom);
+}
+
+void sub_8071F40(u8 *str)
+{
+ MenuDrawTextWindow(2, 14, 28, 19);
+ MenuPrint(str, 3, 15);
+}
+
+void sub_8071F60(u8 a1, u8 a2, u8 a3, u8 a4)
+{
+ sub_8003490(gMenuWindowPtr, a1, gMenuTextTileOffset, a2, a3);
+}
+
+u16 unref_sub_8071F98(u8 x, u8 y)
+{
+ return GetWindowTilemapEntry(gMenuWindowPtr, x, y);
+}
+
+void unref_sub_8071FBC(u16 a1, u8 a2, u8 a3, u8 a4, u8 a5)
+{
+ DrawWindowRect(gMenuWindowPtr, a1, a2, a3, a4, a5);
+}
+
+void MenuDisplayMessageBox(void)
+{
+ DisplayMessageBox(gMenuWindowPtr);
+}
+
+void MenuPrintMessage(u8 *str, u8 left, u8 top)
+{
+ sub_8002EB0(gMenuWindowPtr, str, gMenuTextTileOffset, left, top);
+}
+
+void sub_8072044(u8 *str)
+{
+ sub_8002EB0(gMenuWindowPtr, str, gMenuTextTileOffset, 2, 15);
+}
+
+void MenuSetText(u8 *str)
+{
+ sub_8002E90(gMenuWindowPtr, str);
+}
+
+u8 MenuUpdateWindowText(void)
+{
+ return sub_80035AC(gMenuWindowPtr);
+}
+
+u8 unref_sub_8072098(void)
+{
+ return sub_8003418(gMenuWindowPtr);
+}
+
+void sub_80720B0(void)
+{
+ ClearWindowTextLines(gMenuWindowPtr);
+}
+
+u8 MoveMenuCursor(s8 delta)
+{
+ s32 newPos = gMenu.cursorPos + delta;
+
+ if (newPos < gMenu.minCursorPos)
+ gMenu.cursorPos = gMenu.maxCursorPos;
+ else if (newPos > gMenu.maxCursorPos)
+ gMenu.cursorPos = gMenu.minCursorPos;
+ else
+ gMenu.cursorPos += delta;
+
+ RedrawMenuCursor(gMenu.left, 2 * gMenu.cursorPos + gMenu.top);
+ return gMenu.cursorPos;
+}
+
+u8 MoveMenuCursorNoWrap(s8 delta)
+{
+ s32 newPos = gMenu.cursorPos + delta;
+
+ if (newPos < gMenu.minCursorPos)
+ gMenu.cursorPos = gMenu.minCursorPos;
+ else if (newPos > gMenu.maxCursorPos)
+ gMenu.cursorPos = gMenu.maxCursorPos;
+ else
+ gMenu.cursorPos += delta;
+
+ RedrawMenuCursor(gMenu.left, 2 * gMenu.cursorPos + gMenu.top);
+ return gMenu.cursorPos;
+}
+
+u8 GetMenuCursorPos(void)
+{
+ return gMenu.cursorPos;
+}
+
+s8 ProcessMenuInput(void)
+{
+ if (gMain.newKeys & A_BUTTON)
+ {
+ audio_play(SE_SELECT);
+ if (gMenu.menu_field_7)
+ sub_8072DEC();
+ return gMenu.cursorPos;
+ }
+
+ if (gMain.newKeys & B_BUTTON)
+ {
+ if (gMenu.menu_field_7)
+ sub_8072DEC();
+ return -1;
+ }
+
+ if (gMain.newKeys & DPAD_UP)
+ {
+ audio_play(SE_SELECT);
+ MoveMenuCursor(-1);
+ return -2;
+ }
+ else if (gMain.newKeys & DPAD_DOWN)
+ {
+ audio_play(SE_SELECT);
+ MoveMenuCursor(1);
+ return -2;
+ }
+
+ return -2;
+}
+
+s8 ProcessMenuInputNoWrap(void)
+{
+ u8 cursorPos = gMenu.cursorPos;
+
+ if (gMain.newKeys & A_BUTTON)
+ {
+ audio_play(SE_SELECT);
+ if (gMenu.menu_field_7)
+ sub_8072DEC();
+ return gMenu.cursorPos;
+ }
+
+ if (gMain.newKeys & B_BUTTON)
+ {
+ if (gMenu.menu_field_7)
+ sub_8072DEC();
+ return -1;
+ }
+
+ if (gMain.newKeys & DPAD_UP)
+ {
+ if (cursorPos != MoveMenuCursorNoWrap(-1))
+ audio_play(SE_SELECT);
+ return -2;
+ }
+ else if (gMain.newKeys & DPAD_DOWN)
+ {
+ if (cursorPos != MoveMenuCursorNoWrap(1))
+ audio_play(SE_SELECT);
+ return -2;
+ }
+
+ MoveMenuCursorNoWrap(0);
+ return -2;
+}
+
+u8 MoveMenuCursor3(s8 delta)
+{
+ u8 menuHeight = (gMenu.maxCursorPos + 1) >> 1;
+ s32 newPos = gMenu.cursorPos + delta;
+
+ if (newPos < gMenu.minCursorPos)
+ gMenu.cursorPos = gMenu.maxCursorPos;
+ else if (newPos > gMenu.maxCursorPos)
+ gMenu.cursorPos = gMenu.minCursorPos;
+ else
+ gMenu.cursorPos += delta;
+
+ RedrawMenuCursor(
+ 6 * (gMenu.cursorPos / menuHeight) + gMenu.left,
+ 2 * (gMenu.cursorPos % menuHeight) + gMenu.top);
+
+ return gMenu.cursorPos;
+}
+
+u8 MoveMenuCursor4(s8 delta)
+{
+ if (gMenu.cursorPos + delta <= gMenu.maxCursorPos)
+ {
+ if (sub_80723D4() == TRUE)
+ return gMenu.cursorPos;
+ }
+ else
+ {
+ return gMenu.cursorPos;
+ }
+
+ gMenu.cursorPos += delta;
+
+ if ((gMenu.maxCursorPos + 1) / gMenu.width == 0)
+ RedrawMenuCursor(
+ gMenu.left + gMenu.columnXCoords[gMenu.cursorPos % gMenu.width],
+ 2 * ((gMenu.cursorPos / gMenu.width) % gMenu.height) + gMenu.top);
+ else
+ RedrawMenuCursor(
+ gMenu.left + gMenu.columnXCoords[gMenu.cursorPos % gMenu.width],
+ 2 * (gMenu.cursorPos / gMenu.width) + gMenu.top);
+
+ return gMenu.cursorPos;
+}
+
+bool8 sub_80723D4(void)
+{
+ if ((gMain.newKeys & DPAD_UP) && gMenu.cursorPos < gMenu.width)
+ return TRUE;
+
+ if ((gMain.newKeys & DPAD_DOWN) && gMenu.cursorPos >= (gMenu.maxCursorPos + 1) - gMenu.width)
+ return TRUE;
+
+ if ((gMain.newKeys & DPAD_LEFT)
+ && ((gMenu.cursorPos - (gMenu.cursorPos % gMenu.width)) % gMenu.width == 1 // always false
+ || gMenu.cursorPos == 0
+ || gMenu.cursorPos % gMenu.width == 0))
+ return TRUE;
+
+ if ((gMain.newKeys & DPAD_RIGHT) && gMenu.cursorPos % gMenu.width == gMenu.width - 1)
+ return TRUE;
+
+ return FALSE;
+}
+
+u8 sub_8072484(u8 a1, u8 a2, u8 menuItemCount, u8 a4, u8 width, u8 a6, u32 a7)
+{
+ u8 v7;
+
+ gMenu.width = width;
+ gMenu.height = menuItemCount / width;
+ InitMenu(0, a1, a2, menuItemCount, a4, a6);
+ v7 = 0;
+ if (a7)
+ v7 = -1;
+ gMenu.menu_field_7 = v7;
+ return a4;
+}
+
+#ifdef NONMATCHING
+u8 sub_80724F4(u8 left, u8 top, u8 menuItemCount, u8 *menuItems[][2], u8 columnCount)
+{
+ u8 i;
+ u8 maxWidth;
+ s32 height;
+
+ for (i = 0; i < 7; i++)
+ gMenu.columnXCoords[i] = 0;
+
+ maxWidth = 0;
+ for (i = 0; i < menuItemCount; i++)
+ {
+ u8 width = (sub_8072CA4(menuItems[i][0]) + 7) / 8;
+
+ if (width > maxWidth)
+ maxWidth = width;
+ }
+
+ for (i = 1; i <= columnCount; i++)
+ gMenu.columnXCoords[i] = maxWidth;
+
+ for (i = 1; i <= columnCount; i++)
+ gMenu.columnXCoords[i] += 1 + gMenu.columnXCoords[i - 1];
+
+ gMenu.columnXCoords[columnCount]--;
+
+ if (!((menuItemCount / 2) < columnCount || (menuItemCount % 2 != 0))
+ || columnCount == 1
+ || columnCount == menuItemCount)
+ {
+ height = 2 * (menuItemCount / columnCount) + 1;
+ }
+ else
+ {
+ height = 2 * ((menuItemCount / columnCount) + 1) + 1;
+ }
+
+ {
+ u8 right;
+ u8 bottom;
+ u32 totalWidth;
+ register s32 val asm("r1");
+
+ val = (s8)top + height;
+ bottom = val;
+
+ totalWidth = (gMenu.columnXCoords[columnCount] + 1);
+ right = left + totalWidth;
+
+ MenuDrawTextWindow(left, top, right, bottom);
+ }
+
+ return maxWidth;
+}
+#else
+__attribute__((naked))
+u8 sub_80724F4(u8 left, u8 top, u8 menuItemCount, u8 *menuItems[][2], u8 columnCount)
+{
+ asm("push {r4-r7,lr}\n\
+ mov r7, r10\n\
+ mov r6, r9\n\
+ mov r5, r8\n\
+ push {r5-r7}\n\
+ sub sp, #0xC\n\
+ mov r8, r3\n\
+ ldr r3, [sp, #0x2C]\n\
+ lsl r0, #24\n\
+ lsr r0, #24\n\
+ str r0, [sp]\n\
+ lsl r1, #24\n\
+ lsr r1, #24\n\
+ str r1, [sp, #0x4]\n\
+ lsl r2, #24\n\
+ lsr r6, r2, #24\n\
+ lsl r3, #24\n\
+ lsr r5, r3, #24\n\
+ movs r4, #0\n\
+ ldr r0, _080725D4\n\
+ mov r9, r0\n\
+ mov r1, r9\n\
+ add r1, #0x8\n\
+ movs r2, #0\n\
+_08072524:\n\
+ add r0, r4, r1\n\
+ strb r2, [r0]\n\
+ add r0, r4, #0x1\n\
+ lsl r0, #24\n\
+ lsr r4, r0, #24\n\
+ cmp r4, #0x6\n\
+ bls _08072524\n\
+ movs r7, #0\n\
+ movs r4, #0\n\
+ lsr r2, r6, #1\n\
+ mov r10, r2\n\
+ ldr r0, [sp, #0x4]\n\
+ lsl r0, #24\n\
+ str r0, [sp, #0x8]\n\
+ cmp r7, r6\n\
+ bcs _08072566\n\
+_08072544:\n\
+ lsl r0, r4, #3\n\
+ add r0, r8\n\
+ ldr r0, [r0]\n\
+ bl sub_8072CA4\n\
+ lsl r0, #24\n\
+ lsr r0, #24\n\
+ add r1, r0, #0x7\n\
+ lsr r0, r1, #3\n\
+ cmp r0, r7\n\
+ bls _0807255C\n\
+ add r7, r0, #0\n\
+_0807255C:\n\
+ add r0, r4, #0x1\n\
+ lsl r0, #24\n\
+ lsr r4, r0, #24\n\
+ cmp r4, r6\n\
+ bcc _08072544\n\
+_08072566:\n\
+ movs r4, #0x1\n\
+ ldr r2, _080725D4\n\
+ mov r9, r2\n\
+ cmp r4, r5\n\
+ bhi _08072582\n\
+ mov r1, r9\n\
+ add r1, #0x8\n\
+_08072574:\n\
+ add r0, r4, r1\n\
+ strb r7, [r0]\n\
+ add r0, r4, #0x1\n\
+ lsl r0, #24\n\
+ lsr r4, r0, #24\n\
+ cmp r4, r5\n\
+ bls _08072574\n\
+_08072582:\n\
+ movs r4, #0x1\n\
+ cmp r4, r5\n\
+ bhi _080725A4\n\
+ ldr r3, _080725D8\n\
+_0807258A:\n\
+ add r2, r4, r3\n\
+ ldrb r1, [r2]\n\
+ sub r0, r4, #0x1\n\
+ add r0, r3\n\
+ add r1, #0x1\n\
+ ldrb r0, [r0]\n\
+ add r1, r0\n\
+ strb r1, [r2]\n\
+ add r0, r4, #0x1\n\
+ lsl r0, #24\n\
+ lsr r4, r0, #24\n\
+ cmp r4, r5\n\
+ bls _0807258A\n\
+_080725A4:\n\
+ mov r1, r9\n\
+ add r1, #0x8\n\
+ add r1, r5, r1\n\
+ ldrb r0, [r1]\n\
+ sub r0, #0x1\n\
+ strb r0, [r1]\n\
+ cmp r10, r5\n\
+ bcc _080725BC\n\
+ movs r0, #0x1\n\
+ and r0, r6\n\
+ cmp r0, #0\n\
+ beq _080725C4\n\
+_080725BC:\n\
+ cmp r5, #0x1\n\
+ beq _080725C4\n\
+ cmp r5, r6\n\
+ bne _080725DC\n\
+_080725C4:\n\
+ add r0, r6, #0\n\
+ add r1, r5, #0\n\
+ bl __udivsi3\n\
+ lsl r0, #24\n\
+ lsr r0, #23\n\
+ add r0, #0x1\n\
+ b _080725EA\n\
+ .align 2, 0\n\
+_080725D4: .4byte 0x030006b0\n\
+_080725D8: .4byte 0x030006b8\n\
+_080725DC:\n\
+ add r0, r6, #0\n\
+ add r1, r5, #0\n\
+ bl __udivsi3\n\
+ lsl r0, #24\n\
+ lsr r0, #23\n\
+ add r0, #0x3\n\
+_080725EA:\n\
+ ldr r2, [sp, #0x8]\n\
+ asr r1, r2, #24\n\
+ add r1, r0\n\
+ lsl r1, #24\n\
+ lsr r3, r1, #24\n\
+ mov r0, r9\n\
+ add r0, #0x8\n\
+ add r0, r5, r0\n\
+ ldrb r2, [r0]\n\
+ add r2, #0x1\n\
+ ldr r0, [sp]\n\
+ add r2, r0, r2\n\
+ lsl r2, #24\n\
+ lsr r2, #24\n\
+ ldr r1, [sp, #0x4]\n\
+ bl MenuDrawTextWindow\n\
+ add r0, r7, #0\n\
+ add sp, #0xC\n\
+ pop {r3-r5}\n\
+ mov r8, r3\n\
+ mov r9, r4\n\
+ mov r10, r5\n\
+ pop {r4-r7}\n\
+ pop {r1}\n\
+ bx r1\n");
+}
+#endif // NONMATCHING
+
+void sub_8072620(u8 left, u8 top, u8 menuItemCount, u8 *menuItems[][2], u8 columnCount)
+{
+ u8 i;
+ u8 maxWidth;
+
+ for (i = 0; i < 7; i++)
+ gMenu.columnXCoords[i] = 0;
+
+ maxWidth = 0;
+ for (i = 0; i < menuItemCount; i++)
+ {
+ u8 width = (sub_8072CA4(menuItems[i][0]) + 7) / 8;
+
+ if (width > maxWidth)
+ maxWidth = width;
+ }
+
+ for (i = 1; i <= columnCount; i++)
+ gMenu.columnXCoords[i] = maxWidth;
+
+ for (i = 1; i <= columnCount; i++)
+ gMenu.columnXCoords[i] += 1 + gMenu.columnXCoords[i - 1];
+
+ gMenu.columnXCoords[columnCount]--;
+
+ for (i = 0; i < columnCount; i++)
+ {
+ u8 row = 0;
+ u8 j;
+ for (j = 0; i + j < menuItemCount; j += columnCount, row++)
+ MenuPrint(menuItems[i + j][0], left + gMenu.columnXCoords[i % columnCount], top + 2 * row);
+ }
+}
+
+void sub_807274C(u8 left, u8 top, u8 menuItemCount, u8 a4, u8 *menuItems[][2], u8 columnCount, u32 a7)
+{
+ u8 maxWidth = sub_80724F4(left, top, menuItemCount, menuItems, columnCount);
+
+ sub_8072484(left + 1, top + 1, menuItemCount, a4, columnCount, maxWidth, a7);
+ sub_8072620(left + 1, top + 1, menuItemCount, menuItems, columnCount);
+}
+
+s8 sub_80727CC(void)
+{
+ if (gMain.newKeys & A_BUTTON)
+ {
+ if (gMenu.menu_field_7)
+ sub_8072DEC();
+ audio_play(SE_SELECT);
+ return GetMenuCursorPos();
+ }
+
+ if (gMain.newKeys & B_BUTTON)
+ {
+ if (gMenu.menu_field_7)
+ sub_8072DEC();
+ return -1;
+ }
+
+ if (gMain.newKeys & DPAD_UP)
+ {
+ audio_play(SE_SELECT);
+ MoveMenuCursor4(-gMenu.width);
+ return -2;
+ }
+ else if (gMain.newKeys & DPAD_DOWN)
+ {
+ audio_play(SE_SELECT);
+ MoveMenuCursor4(gMenu.width);
+ return -2;
+ }
+ else if (gMain.newKeys & DPAD_LEFT)
+ {
+ audio_play(SE_SELECT);
+ MoveMenuCursor4(-1);
+ return -2;
+ }
+ else if (gMain.newKeys & DPAD_RIGHT)
+ {
+ audio_play(SE_SELECT);
+ MoveMenuCursor4(1);
+ return -2;
+ }
+
+ return -2;
+}
+
+u8 sub_807288C(u8 column)
+{
+ return gMenu.columnXCoords[column];
+}
+
+void PrintMenuItems(u8 left, u8 top, u8 menuItemCount, u8 *menuItems[][2])
+{
+ u8 i;
+
+ for (i = 0; i < menuItemCount; i++)
+ MenuPrint(menuItems[i][0], left, top + 2 * i);
+}
+
+void PrintMenuItemsReordered(u8 left, u8 top, u8 menuItemCount, u8 *menuItems[][2], u8 *order)
+{
+ u8 i;
+
+ for (i = 0; i < menuItemCount; i++)
+ MenuPrint(menuItems[order[i]][0], left, top + 2 * i);
+}
+
+void InitYesNoMenu(u8 left, u8 top, u8 a3)
+{
+ PrintMenuItems(left + 1, top + 1, 2, (void *)gUnknown_08376D74);
+ InitMenu(0, left + 1, top + 1, 2, 0, a3);
+}
+
+void DisplayYesNoMenu(u8 left, u8 top, u32 a3)
+{
+ MenuDrawTextWindow(left, top, left + 6, top + 5);
+ InitYesNoMenu(left, top, 5);
+ gMenu.menu_field_7 = a3 ? -1 : 0;
+}
+
+s8 ProcessMenuInputNoWrap_(void)
+{
+ return ProcessMenuInputNoWrap();
+}
+
+u8 sub_80729D8(u8 *text, u8 left, u16 top, u8 a4)
+{
+ return sub_8004D04(gMenuWindowPtr, text, gMenuTextTileOffset, left, top, a4);
+}
+
+u8 sub_8072A18(u8 *text, u8 left, u16 top, u8 width, u32 a5)
+{
+ return sub_8004FD0(gMenuWindowPtr, 0, text, gMenuTextTileOffset, left, top, width, a5);
+}
+
+u8 unref_sub_8072A5C(u8 *dest, u8 *src, u8 left, u16 top, u8 width, u32 a6)
+{
+ return sub_8004FD0(gMenuWindowPtr, dest, src, gMenuTextTileOffset, left, top, width, a6);
+}
+
+__attribute__((naked))
+int sub_8072AB0(u8 *str, u8 left, u16 top, u8 width, u8 height, u32 a6)
+{
+ asm("push {r4-r7,lr}\n\
+ mov r7, r9\n\
+ mov r6, r8\n\
+ push {r6,r7}\n\
+ sub sp, #0x10\n\
+ mov r9, r0\n\
+ add r4, r1, #0\n\
+ add r5, r2, #0\n\
+ ldr r0, [sp, #0x2C]\n\
+ ldr r2, [sp, #0x30]\n\
+ lsl r4, #24\n\
+ lsr r1, r4, #24\n\
+ mov r12, r1\n\
+ lsl r5, #16\n\
+ lsr r7, r5, #16\n\
+ lsl r3, #24\n\
+ lsr r6, r3, #24\n\
+ lsl r0, #24\n\
+ lsr r0, #24\n\
+ mov r8, r0\n\
+ ldr r0, _08072B44\n\
+ ldr r0, [r0]\n\
+ ldr r1, _08072B48\n\
+ ldrh r3, [r1]\n\
+ mov r1, r12\n\
+ str r1, [sp]\n\
+ str r7, [sp, #0x4]\n\
+ str r6, [sp, #0x8]\n\
+ str r2, [sp, #0xC]\n\
+ movs r1, #0\n\
+ mov r2, r9\n\
+ bl sub_8004FD0\n\
+ add r1, r0, #0\n\
+ lsl r1, #24\n\
+ lsr r2, r1, #24\n\
+ lsr r4, #27\n\
+ mov r12, r4\n\
+ lsr r7, r5, #19\n\
+ add r1, r6, #0x7\n\
+ lsr r6, r1, #3\n\
+ mov r1, r8\n\
+ add r1, #0x7\n\
+ asr r1, #3\n\
+ lsl r1, #24\n\
+ lsr r1, #24\n\
+ mov r8, r1\n\
+ cmp r2, r8\n\
+ bcs _08072B34\n\
+ lsl r1, r2, #1\n\
+ add r1, r7, r1\n\
+ lsl r1, #24\n\
+ lsr r1, #24\n\
+ mov r0, r12\n\
+ add r2, r0, r6\n\
+ sub r2, #0x1\n\
+ lsl r2, #24\n\
+ lsr r2, #24\n\
+ mov r0, r8\n\
+ add r3, r0, r7\n\
+ sub r3, #0x1\n\
+ lsl r3, #24\n\
+ lsr r3, #24\n\
+ mov r0, r12\n\
+ bl MenuFillWindowRectWithBlankTile\n\
+_08072B34:\n\
+ add sp, #0x10\n\
+ pop {r3,r4}\n\
+ mov r8, r3\n\
+ mov r9, r4\n\
+ pop {r4-r7}\n\
+ pop {r1}\n\
+ bx r1\n\
+ .align 2, 0\n\
+_08072B44: .4byte 0x0202e9c8\n\
+_08072B48: .4byte 0x0202e9ce\n");
+}
+
+void sub_8072B4C(u8 *str, u8 left, u8 top)
+{
+ sub_8004D38(gMenuWindowPtr, str, gMenuTextTileOffset, left, top);
+}
+
+void sub_8072B80(u8 *a1, u8 a2, u8 a3, u8 *a4)
+{
+ u8 buffer[64];
+ u8 width = GetStringWidth(gMenuWindowPtr, a4);
+ AlignString(gMenuWindowPtr, buffer, a1, width, 1);
+ sub_8003460(gMenuWindowPtr, buffer, gMenuTextTileOffset, a2, a3);
+}
+
+void sub_8072BD8(u8 *a1, u8 a2, u8 a3, u16 a4)
+{
+ sub_8004DB0(gMenuWindowPtr, a1, gMenuTextTileOffset, a2, a3, a4);
+}
+
+u8 *sub_8072C14(u8 *a1, s32 a2, u8 a3, u8 a4)
+{
+ return AlignInt1(gMenuWindowPtr, a1, a2, a3, a4);
+}
+
+u8 *sub_8072C44(u8 *a1, s32 a2, u8 a3, u8 a4)
+{
+ return AlignInt2(gMenuWindowPtr, a1, a2, a3, a4);
+}
+
+u8 *sub_8072C74(u8 *a1, u8 *a2, u8 a3, u8 a4)
+{
+ return AlignString(gMenuWindowPtr, a1, a2, a3, a4);
+}
+
+u8 sub_8072CA4(u8 *str)
+{
+ return GetStringWidth(gMenuWindowPtr, str);
+}
+
+u8 sub_8072CBC()
+{
+ return sub_8004E24(gMenuWindowPtr);
+}
+
+void sub_8072CD4(u8 *a1, u8 *a2, u8 *a3)
+{
+ sub_8004E28(gMenuWindowPtr, a1, a2, a3);
+}
+
+u32 MenuUpdateWindowText_OverrideLineLength(u8 lineLength)
+{
+ return sub_80037C8(gMenuWindowPtr, lineLength);
+}
+
+struct Window *unref_sub_8072D0C(void)
+{
+ return gMenuWindowPtr;
+}
+
+void sub_8072D18(u8 a1, u8 a2)
+{
+ sub_814A5C0(a1, 0xFFFF, 12, 11679, 8 * a2);
+}
+
+u8 InitMenu(u8 a1, u8 left, u8 top, u8 numChoices, u8 cursorPos, u8 a6)
+{
+ s32 pos;
+
+ if (a6)
+ sub_8072D18(a1, a6);
+
+ gMenu.left = left - 1;
+ gMenu.top = top;
+ gMenu.minCursorPos = 0;
+ gMenu.maxCursorPos = numChoices - 1;
+ gMenu.menu_field_7 = 0;
+
+ pos = cursorPos;
+
+ if (pos < 0 || pos > gMenu.maxCursorPos)
+ pos = 0;
+
+ gMenu.cursorPos = pos;
+ MoveMenuCursor(0);
+
+ return pos;
+}
+
+void RedrawMenuCursor(u8 a1, u8 a2)
+{
+ sub_814A880((a1 + 1) * 8, 8 * a2);
+}
+
+void unref_sub_8072DC0()
+{
+ sub_814A904();
+}
+
+void sub_8072DCC(u8 a1)
+{
+ sub_814A958(a1);
+}
+
+void sub_8072DDC(u8 a1)
+{
+ sub_8072DCC(8 * a1);
+}
+
+void sub_8072DEC(void)
+{
+ sub_814A7FC();
+}
diff --git a/src/pokemon_1.c b/src/pokemon_1.c
new file mode 100644
index 000000000..566db2e68
--- /dev/null
+++ b/src/pokemon_1.c
@@ -0,0 +1,680 @@
+#include "global.h"
+#include "text.h"
+#include "string_util.h"
+#include "pokemon.h"
+#include "species.h"
+#include "main.h"
+#include "sprite.h"
+
+extern u8 sav1_map_get_name();
+
+extern struct Pokemon gPlayerParty[6]; // 0x3004360
+extern struct Pokemon gEnemyParty[6]; // 0x30045C0
+
+extern u8 unk_2000000[];
+extern u16 word_2024E82;
+extern u8 byte_2024E88;
+
+extern u32 gExperienceTables[8][101];
+extern struct BaseStats gBaseStats[];
+extern struct BattleMove gBattleMoves[];
+extern const u16 *gLevelUpLearnsets[];
+
+void ZeroBoxMonData(struct BoxPokemon *boxMon)
+{
+ u8 *raw = (u8 *)boxMon;
+ u32 i;
+ for (i = 0; i < sizeof(struct BoxPokemon); i++)
+ raw[i] = 0;
+}
+
+void ZeroMonData(struct Pokemon *mon)
+{
+ u32 arg;
+ ZeroBoxMonData(&mon->box);
+ arg = 0;
+ SetMonData(mon, MON_DATA_STATUS, (u8 *)&arg);
+ SetMonData(mon, MON_DATA_LEVEL, (u8 *)&arg);
+ SetMonData(mon, MON_DATA_HP, (u8 *)&arg);
+ SetMonData(mon, MON_DATA_MAX_HP, (u8 *)&arg);
+ SetMonData(mon, MON_DATA_ATK, (u8 *)&arg);
+ SetMonData(mon, MON_DATA_DEF, (u8 *)&arg);
+ SetMonData(mon, MON_DATA_SPD, (u8 *)&arg);
+ SetMonData(mon, MON_DATA_SPATK, (u8 *)&arg);
+ SetMonData(mon, MON_DATA_SPDEF, (u8 *)&arg);
+ arg = 255;
+ SetMonData(mon, MON_DATA_64, (u8 *)&arg);
+}
+
+void ZeroPlayerPartyMons(void)
+{
+ s32 i;
+ for (i = 0; i < 6; i++)
+ ZeroMonData(&gPlayerParty[i]);
+}
+
+void ZeroEnemyPartyMons(void)
+{
+ s32 i;
+ for (i = 0; i < 6; i++)
+ ZeroMonData(&gEnemyParty[i]);
+}
+
+void CreateMon(struct Pokemon *mon, u16 species, u8 level, u8 fixedIV, u8 hasFixedPersonality, u32 fixedPersonality, u8 otIdType, u32 fixedOtId)
+{
+ u32 arg;
+ ZeroMonData(mon);
+ CreateBoxMon(&mon->box, species, level, fixedIV, hasFixedPersonality, fixedPersonality, otIdType, fixedOtId);
+ SetMonData(mon, MON_DATA_LEVEL, &level);
+ arg = 255;
+ SetMonData(mon, MON_DATA_64, (u8 *)&arg);
+ CalculateMonStats(mon);
+}
+
+void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV, u8 hasFixedPersonality, u32 fixedPersonality, u8 otIdType, u32 fixedOtId)
+{
+ u8 speciesName[10];
+ u32 personality;
+ u32 value;
+ u16 checksum;
+
+ ZeroBoxMonData(boxMon);
+
+ if (hasFixedPersonality)
+ {
+ personality = fixedPersonality;
+ }
+ else
+ {
+ u32 r = Random();
+ personality = (u16)r | (Random() << 16);
+ }
+
+ SetBoxMonData(boxMon, MON_DATA_PERSONALITY, (u8 *)&personality);
+
+ if (otIdType == 2)
+ {
+ u32 shinyValue;
+ do
+ {
+ u32 r = Random();
+ value = (u16)r | (Random() << 16);
+ asm(""); // needed to match for some reason
+ shinyValue = ((value & 0xFFFF0000) >> 16) ^ (value & 0x0000FFFF) ^ ((personality & 0xFFFF0000) >> 16) ^ (personality & 0x0000FFFF);
+ } while (shinyValue < 8);
+ }
+ else if (otIdType == 1)
+ {
+ value = fixedOtId;
+ }
+ else
+ {
+ value = gSaveBlock2.playerTrainerId[0]
+ | (gSaveBlock2.playerTrainerId[1] << 8)
+ | (gSaveBlock2.playerTrainerId[2] << 16)
+ | (gSaveBlock2.playerTrainerId[3] << 24);
+ }
+
+ SetBoxMonData(boxMon, MON_DATA_OT_ID, (u8 *)&value);
+
+ checksum = CalculateBoxMonChecksum(boxMon);
+ SetBoxMonData(boxMon, MON_DATA_CHECKSUM, (u8 *)&checksum);
+ EncryptBoxMon(boxMon);
+ GetSpeciesName(speciesName, species);
+ SetBoxMonData(boxMon, MON_DATA_NICKNAME, speciesName);
+ SetBoxMonData(boxMon, MON_DATA_LANGUAGE, &gGameLanguage);
+ SetBoxMonData(boxMon, MON_DATA_OT_NAME, gSaveBlock2.playerName);
+ SetBoxMonData(boxMon, MON_DATA_SPECIES, (u8 *)&species);
+ SetBoxMonData(boxMon, MON_DATA_EXP, (u8 *)&gExperienceTables[gBaseStats[species].growthRate][level]);
+ SetBoxMonData(boxMon, MON_DATA_FRIENDSHIP, &gBaseStats[species].friendship);
+ value = sav1_map_get_name();
+ SetBoxMonData(boxMon, MON_DATA_MET_LOCATION, (u8 *)&value);
+ SetBoxMonData(boxMon, MON_DATA_MET_LEVEL, &level);
+ SetBoxMonData(boxMon, MON_DATA_MET_GAME, &gGameVersion);
+ value = 4;
+ SetBoxMonData(boxMon, MON_DATA_POKEBALL, (u8 *)&value);
+ SetBoxMonData(boxMon, MON_DATA_OT_GENDER, &gSaveBlock2.playerGender);
+
+ if (fixedIV < 32)
+ {
+ SetBoxMonData(boxMon, MON_DATA_HP_IV, &fixedIV);
+ SetBoxMonData(boxMon, MON_DATA_ATK_IV, &fixedIV);
+ SetBoxMonData(boxMon, MON_DATA_DEF_IV, &fixedIV);
+ SetBoxMonData(boxMon, MON_DATA_SPD_IV, &fixedIV);
+ SetBoxMonData(boxMon, MON_DATA_SPATK_IV, &fixedIV);
+ SetBoxMonData(boxMon, MON_DATA_SPDEF_IV, &fixedIV);
+ }
+ else
+ {
+ u32 iv;
+ value = (u16)Random();
+
+ iv = value & 0x1F;
+ SetBoxMonData(boxMon, MON_DATA_HP_IV, (u8 *)&iv);
+ iv = (value & 0x3E0) >> 5;
+ SetBoxMonData(boxMon, MON_DATA_ATK_IV, (u8 *)&iv);
+ iv = (value &0x7C00) >> 10;
+ SetBoxMonData(boxMon, MON_DATA_DEF_IV, (u8 *)&iv);
+
+ value = (u16)Random();
+
+ iv = value & 0x1F;
+ SetBoxMonData(boxMon, MON_DATA_SPD_IV, (u8 *)&iv);
+ iv = (value & 0x3E0) >> 5;
+ SetBoxMonData(boxMon, MON_DATA_SPATK_IV, (u8 *)&iv);
+ iv = (value &0x7C00) >> 10;
+ SetBoxMonData(boxMon, MON_DATA_SPDEF_IV, (u8 *)&iv);
+ }
+
+ if (gBaseStats[species].ability2)
+ {
+ value = personality & 1;
+ SetBoxMonData(boxMon, MON_DATA_ALT_ABILITY, (u8 *)&value);
+ }
+
+ GiveBoxMonInitialMoveset(boxMon);
+}
+
+void CreateMonWithNature(struct Pokemon *mon, u16 species, u8 level, u8 fixedIV, u8 nature)
+{
+ u32 personality;
+
+ do
+ {
+ u32 r = Random();
+ personality = (u16)r | (Random() << 16);
+ }
+ while (nature != GetNatureFromPersonality(personality));
+
+ CreateMon(mon, species, level, fixedIV, 1, personality, 0, 0);
+}
+
+void CreateMonWithGenderNatureLetter(struct Pokemon *mon, u16 species, u8 level, u8 fixedIV, u8 gender, u8 nature, u8 unownLetter)
+{
+ u32 personality;
+
+ if ((u8)(unownLetter - 1) < 28)
+ {
+ u16 actualLetter;
+
+ do
+ {
+ u32 r = Random();
+ personality = (u16)r | (Random() << 16);
+ actualLetter = ((((personality & 0x3000000) >> 18) | ((personality & 0x30000) >> 12) | ((personality & 0x300) >> 6) | personality & 0x3) % 28);
+ }
+ while (nature != GetNatureFromPersonality(personality)
+ || gender != GetGenderFromSpeciesAndPersonality(species, personality)
+ || actualLetter != unownLetter - 1);
+ }
+ else
+ {
+ do
+ {
+ u32 r = Random();
+ personality = (u16)r | (Random() << 16);
+ }
+ while (nature != GetNatureFromPersonality(personality)
+ || gender != GetGenderFromSpeciesAndPersonality(species, personality));
+ }
+
+ CreateMon(mon, species, level, fixedIV, 1, personality, 0, 0);
+}
+
+// This is only used to create Wally's Ralts.
+void CreateMaleMon(struct Pokemon *mon, u16 species, u8 level)
+{
+ u32 personality;
+ u32 otId;
+
+ do
+ {
+ u32 r1, r2;
+ r1 = Random();
+ otId = (u16)r1 | (Random() << 16);
+ r2 = Random();
+ personality = (u16)r2 | (Random() << 16);
+ }
+ while (GetGenderFromSpeciesAndPersonality(species, personality) != MON_MALE);
+ CreateMon(mon, species, level, 32, 1, personality, 1, otId);
+}
+
+void CreateMonWithIVsPersonality(struct Pokemon *mon, u16 species, u8 level, u32 ivs, u32 personality)
+{
+ CreateMon(mon, species, level, 0, 1, personality, 0, 0);
+ SetMonData(mon, MON_DATA_IVS, (u8 *)&ivs);
+ CalculateMonStats(mon);
+}
+
+void CreateMonWithIVsOTID(struct Pokemon *mon, u16 species, u8 level, u8 *ivs, u32 otId)
+{
+ CreateMon(mon, species, level, 0, 0, 0, 1, otId);
+ SetMonData(mon, MON_DATA_HP_IV, &ivs[0]);
+ SetMonData(mon, MON_DATA_ATK_IV, &ivs[1]);
+ SetMonData(mon, MON_DATA_DEF_IV, &ivs[2]);
+ SetMonData(mon, MON_DATA_SPD_IV, &ivs[3]);
+ SetMonData(mon, MON_DATA_SPATK_IV, &ivs[4]);
+ SetMonData(mon, MON_DATA_SPDEF_IV, &ivs[5]);
+ CalculateMonStats(mon);
+}
+
+void CreateMonWithEVSpread(struct Pokemon *mon, u16 species, u8 level, u8 fixedIV, u8 evSpread)
+{
+ register s32 i asm("r5");
+ register u32 temp asm("r4");
+ s32 statCount = 0;
+ u16 evAmount;
+ register u32 mask1 asm("r1");
+ u8 mask2;
+
+ CreateMon(mon, species, level, fixedIV, 0, 0, 0, 0);
+
+ temp = evSpread;
+ mask1 = 1;
+ i = 5;
+ do
+ {
+ if (temp & mask1)
+ statCount++;
+ temp >>= 1;
+ i--;
+ } while (i >= 0);
+
+
+ evAmount = 510 / statCount;
+ mask2 = 1;
+ i = 0;
+ do
+ {
+ if (evSpread & mask2)
+ SetMonData(mon, MON_DATA_HP_EV + i, (u8 *)&evAmount);
+ mask2 <<= 1;
+ i++;
+ } while (i < 6);
+
+ CalculateMonStats(mon);
+}
+
+void sub_803ADE8(struct Pokemon *mon, struct UnknownPokemonStruct *src)
+{
+ s32 i;
+ u8 nickname[11];
+ u8 language;
+ u8 value;
+
+ CreateMon(mon, src->species, src->level, 0, 1, src->personality, 1, src->otId);
+
+ for (i = 0; i < 4; i++)
+ SetMonMoveSlot(mon, src->moves[i], i);
+
+ SetMonData(mon, MON_DATA_PP_BONUSES, (u8 *)&src->ppBonuses);
+ SetMonData(mon, MON_DATA_HELD_ITEM, (u8 *)&src->heldItem);
+
+ StringCopy(nickname, src->nickname);
+
+ if (nickname[0] == 0xFC && nickname[1] == 0x15)
+ language = 1;
+ else
+ language = 2;
+
+ SetMonData(mon, MON_DATA_LANGUAGE, &language);
+ SkipExtCtrlCodes(nickname);
+ SetMonData(mon, MON_DATA_NICKNAME, nickname);
+ SetMonData(mon, MON_DATA_FRIENDSHIP, (u8 *)&src->friendship);
+ SetMonData(mon, MON_DATA_HP_EV, (u8 *)&src->hpEV);
+ SetMonData(mon, MON_DATA_ATK_EV, (u8 *)&src->attackEV);
+ SetMonData(mon, MON_DATA_DEF_EV, (u8 *)&src->defenseEV);
+ SetMonData(mon, MON_DATA_SPD_EV, (u8 *)&src->speedEV);
+ SetMonData(mon, MON_DATA_SPATK_EV, (u8 *)&src->spAttackEV);
+ SetMonData(mon, MON_DATA_SPDEF_EV, (u8 *)&src->spDefenseEV);
+ value = src->altAbility;
+ SetMonData(mon, MON_DATA_ALT_ABILITY, &value);
+ value = src->hpIV;
+ SetMonData(mon, MON_DATA_HP_IV, &value);
+ value = src->attackIV;
+ SetMonData(mon, MON_DATA_ATK_IV, &value);
+ value = src->defenseIV;
+ SetMonData(mon, MON_DATA_DEF_IV, &value);
+ value = src->speedIV;
+ SetMonData(mon, MON_DATA_SPD_IV, &value);
+ value = src->spAttackIV;
+ SetMonData(mon, MON_DATA_SPATK_IV, &value);
+ value = src->spDefenseIV;
+ SetMonData(mon, MON_DATA_SPDEF_IV, &value);
+ CalculateMonStats(mon);
+}
+
+void sub_803AF78(struct Pokemon *mon, struct UnknownPokemonStruct *dest)
+{
+ s32 i;
+ u16 heldItem;
+
+ dest->species = GetMonData(mon, MON_DATA_SPECIES, NULL);
+ heldItem = GetMonData(mon, MON_DATA_HELD_ITEM, NULL);
+
+ if (heldItem == 175)
+ heldItem = 0;
+
+ dest->heldItem = heldItem;
+
+ for (i = 0; i < 4; i++)
+ dest->moves[i] = GetMonData(mon, MON_DATA_MOVE1 + i, NULL);
+
+ dest->level = GetMonData(mon, MON_DATA_LEVEL, NULL);
+ dest->ppBonuses = GetMonData(mon, MON_DATA_PP_BONUSES, NULL);
+ dest->otId = GetMonData(mon, MON_DATA_OT_ID, NULL);
+ dest->hpEV = GetMonData(mon, MON_DATA_HP_EV, NULL);
+ dest->attackEV = GetMonData(mon, MON_DATA_ATK_EV, NULL);
+ dest->defenseEV = GetMonData(mon, MON_DATA_DEF_EV, NULL);
+ dest->speedEV = GetMonData(mon, MON_DATA_SPD_EV, NULL);
+ dest->spAttackEV = GetMonData(mon, MON_DATA_SPATK_EV, NULL);
+ dest->spDefenseEV = GetMonData(mon, MON_DATA_SPDEF_EV, NULL);
+ dest->friendship = GetMonData(mon, MON_DATA_FRIENDSHIP, NULL);
+ dest->hpIV = GetMonData(mon, MON_DATA_HP_IV, NULL);
+ dest->attackIV = GetMonData(mon, MON_DATA_ATK_IV, NULL);
+ dest->defenseIV = GetMonData(mon, MON_DATA_DEF_IV, NULL);
+ dest->speedIV = GetMonData(mon, MON_DATA_SPD_IV, NULL);
+ dest->spAttackIV = GetMonData(mon, MON_DATA_SPATK_IV, NULL);
+ dest->spDefenseIV = GetMonData(mon, MON_DATA_SPDEF_IV, NULL);
+ dest->altAbility = GetMonData(mon, MON_DATA_ALT_ABILITY, NULL);
+ dest->personality = GetMonData(mon, MON_DATA_PERSONALITY, NULL);
+ GetMonData(mon, MON_DATA_NICKNAME, dest->nickname);
+}
+
+u16 CalculateBoxMonChecksum(struct BoxPokemon *boxMon)
+{
+ u16 checksum = 0;
+ union PokemonSubstruct *substruct0 = GetSubstruct(boxMon, boxMon->personality, 0);
+ union PokemonSubstruct *substruct1 = GetSubstruct(boxMon, boxMon->personality, 1);
+ union PokemonSubstruct *substruct2 = GetSubstruct(boxMon, boxMon->personality, 2);
+ union PokemonSubstruct *substruct3 = GetSubstruct(boxMon, boxMon->personality, 3);
+ s32 i;
+
+ for (i = 0; i < 6; i++)
+ checksum += substruct0->raw[i];
+
+ for (i = 0; i < 6; i++)
+ checksum += substruct1->raw[i];
+
+ for (i = 0; i < 6; i++)
+ checksum += substruct2->raw[i];
+
+ for (i = 0; i < 6; i++)
+ checksum += substruct3->raw[i];
+
+ return checksum;
+}
+
+#define CALC_STAT(base, iv, ev, statIndex, field) \
+{ \
+ u8 baseStat = gBaseStats[species].base; \
+ s32 n = (((2 * baseStat + iv + ev / 4) * level) / 100) + 5; \
+ u8 nature = GetNature(mon); \
+ n = nature_stat_mod(nature, n, statIndex); \
+ SetMonData(mon, field, (u8 *)&n); \
+}
+
+void CalculateMonStats(struct Pokemon *mon)
+{
+ s32 oldMaxHP = GetMonData(mon, MON_DATA_MAX_HP, NULL);
+ s32 currentHP = GetMonData(mon, MON_DATA_HP, NULL);
+ s32 hpIV = GetMonData(mon, MON_DATA_HP_IV, NULL);
+ s32 hpEV = GetMonData(mon, MON_DATA_HP_EV, NULL);
+ s32 attackIV = GetMonData(mon, MON_DATA_ATK_IV, NULL);
+ s32 attackEV = GetMonData(mon, MON_DATA_ATK_EV, NULL);
+ s32 defenseIV = GetMonData(mon, MON_DATA_DEF_IV, NULL);
+ s32 defenseEV = GetMonData(mon, MON_DATA_DEF_EV, NULL);
+ s32 speedIV = GetMonData(mon, MON_DATA_SPD_IV, NULL);
+ s32 speedEV = GetMonData(mon, MON_DATA_SPD_EV, NULL);
+ s32 spAttackIV = GetMonData(mon, MON_DATA_SPATK_IV, NULL);
+ s32 spAttackEV = GetMonData(mon, MON_DATA_SPATK_EV, NULL);
+ s32 spDefenseIV = GetMonData(mon, MON_DATA_SPDEF_IV, NULL);
+ s32 spDefenseEV = GetMonData(mon, MON_DATA_SPDEF_EV, NULL);
+ u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL);
+ s32 level = GetLevelFromMonExp(mon);
+ s32 newMaxHP;
+ u8 nature;
+
+ SetMonData(mon, MON_DATA_LEVEL, (u8 *)&level);
+
+ if (species == SPECIES_SHEDINJA)
+ {
+ newMaxHP = 1;
+ }
+ else
+ {
+ s32 n = 2 * gBaseStats[species].baseHP + hpIV;
+ newMaxHP = (((n + hpEV / 4) * level) / 100) + level + 10;
+ }
+
+ unk_2000000[0x160FA] = newMaxHP - oldMaxHP;
+ if (unk_2000000[0x160FA] == 0)
+ unk_2000000[0x160FA] = 1;
+
+ SetMonData(mon, MON_DATA_MAX_HP, (u8 *)&newMaxHP);
+
+ CALC_STAT(baseAttack, attackIV, attackEV, 1, MON_DATA_ATK)
+ CALC_STAT(baseDefense, defenseIV, defenseEV, 2, MON_DATA_DEF)
+ CALC_STAT(baseSpeed, speedIV, speedEV, 3, MON_DATA_SPD)
+ CALC_STAT(baseSpAttack, spAttackIV, spAttackEV, 4, MON_DATA_SPATK)
+ CALC_STAT(baseSpDefense, spDefenseIV, spDefenseEV, 5, MON_DATA_SPDEF)
+
+ if (species == SPECIES_SHEDINJA)
+ {
+ if (currentHP != 0 || oldMaxHP == 0)
+ {
+ currentHP = 1;
+ goto set_hp;
+ }
+ }
+ else
+ {
+ if (currentHP != 0 || oldMaxHP == 0)
+ {
+ if (currentHP != 0)
+ currentHP += newMaxHP - oldMaxHP;
+ else if (oldMaxHP == 0)
+ currentHP = newMaxHP;
+ set_hp:
+ SetMonData(mon, MON_DATA_HP, (u8 *)&currentHP);
+ }
+ }
+}
+
+void sub_803B4B4(struct Pokemon *src, struct Pokemon *dest)
+{
+ u32 value = 0;
+ memcpy(&dest->box, &src->box, sizeof(struct BoxPokemon));
+ SetMonData(dest, MON_DATA_STATUS, (u8 *)&value);
+ SetMonData(dest, MON_DATA_HP, (u8 *)&value);
+ SetMonData(dest, MON_DATA_MAX_HP, (u8 *)&value);
+ value = 255;
+ SetMonData(dest, MON_DATA_64, (u8 *)&value);
+ CalculateMonStats(dest);
+}
+
+u8 GetLevelFromMonExp(struct Pokemon *mon)
+{
+ u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL);
+ u32 exp = GetMonData(mon, MON_DATA_EXP, NULL);
+ s32 level = 1;
+
+ while (level <= 100 && gExperienceTables[gBaseStats[species].growthRate][level] <= exp)
+ level++;
+
+ return level - 1;
+}
+
+u8 GetLevelFromBoxMonExp(struct BoxPokemon *boxMon)
+{
+ u16 species = GetBoxMonData(boxMon, MON_DATA_SPECIES, NULL);
+ u32 exp = GetBoxMonData(boxMon, MON_DATA_EXP, NULL);
+ s32 level = 1;
+
+ while (level <= 100 && gExperienceTables[gBaseStats[species].growthRate][level] <= exp)
+ level++;
+
+ return level - 1;
+}
+
+u16 GiveMoveToMon(struct Pokemon *mon, u16 move)
+{
+ return GiveMoveToBoxMon(&mon->box, move);
+}
+
+u16 GiveMoveToBoxMon(struct BoxPokemon *boxMon, u16 move)
+{
+ s32 i;
+ for (i = 0; i < 4; i++)
+ {
+ u16 existingMove = GetBoxMonData(boxMon, MON_DATA_MOVE1 + i, NULL);
+ if (!existingMove)
+ {
+ SetBoxMonData(boxMon, MON_DATA_MOVE1 + i, (u8 *)&move);
+ SetBoxMonData(boxMon, MON_DATA_PP1 + i, &gBattleMoves[move].pp);
+ return move;
+ }
+ if (existingMove == move)
+ return -2;
+ }
+ return -1;
+}
+
+u16 GiveMoveToBattleMon(struct BattlePokemon *mon, u16 move)
+{
+ s32 i;
+
+ for (i = 0; i < 4; i++)
+ {
+ if (!mon->moves[i])
+ {
+ mon->moves[i] = move;
+ mon->pp[i] = gBattleMoves[move].pp;
+ return move;
+ }
+ }
+
+ return -1;
+}
+
+void SetMonMoveSlot(struct Pokemon *mon, u16 move, u8 slot)
+{
+ SetMonData(mon, MON_DATA_MOVE1 + slot, (u8 *)&move);
+ SetMonData(mon, MON_DATA_PP1 + slot, &gBattleMoves[move].pp);
+}
+
+void SetBattleMonMoveSlot(struct BattlePokemon *mon, u16 move, u8 slot)
+{
+ mon->moves[slot] = move;
+ mon->pp[slot] = gBattleMoves[move].pp;
+}
+
+void GiveMonInitialMoveset(struct Pokemon *mon)
+{
+ GiveBoxMonInitialMoveset(&mon->box);
+}
+
+void GiveBoxMonInitialMoveset(struct BoxPokemon *boxMon)
+{
+ u16 species = GetBoxMonData(boxMon, MON_DATA_SPECIES, NULL);
+ s32 level = GetLevelFromBoxMonExp(boxMon);
+ s32 i;
+
+ for (i = 0; gLevelUpLearnsets[species][i] != (u16)-1; i++)
+ {
+ u16 moveLevel;
+ u16 move;
+
+ moveLevel = (gLevelUpLearnsets[species][i] & 0xFE00);
+
+ if (moveLevel > (level << 9))
+ break;
+
+ move = (gLevelUpLearnsets[species][i] & 0x1FF);
+
+ if (GiveMoveToBoxMon(boxMon, move) == (u16)-1)
+ DeleteFirstMoveAndGiveMoveToBoxMon(boxMon, move);
+ }
+}
+
+u16 sub_803B7C8(struct Pokemon *mon, u8 a2)
+{
+ u32 retVal = 0;
+ u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL);
+ u8 level = GetMonData(mon, MON_DATA_LEVEL, NULL);
+
+ if (a2)
+ {
+ byte_2024E88 = retVal;
+
+ while ((gLevelUpLearnsets[species][byte_2024E88] & 0xFE00) != (level << 9))
+ {
+ byte_2024E88++;
+ if (gLevelUpLearnsets[species][byte_2024E88] == (u16)-1)
+ return 0;
+ }
+ }
+
+ if ((gLevelUpLearnsets[species][byte_2024E88] & 0xFE00) == (level << 9))
+ {
+ word_2024E82 = (gLevelUpLearnsets[species][byte_2024E88] & 0x1FF);
+ byte_2024E88++;
+ retVal = GiveMoveToMon(mon, word_2024E82);
+ }
+
+ return retVal;
+}
+
+void DeleteFirstMoveAndGiveMoveToMon(struct Pokemon *mon, u16 move)
+{
+ s32 i;
+ u16 moves[4];
+ u8 pp[4];
+ u8 ppBonuses;
+
+ for (i = 0; i < 3; i++)
+ {
+ moves[i] = GetMonData(mon, MON_DATA_MOVE2 + i, NULL);
+ pp[i]= GetMonData(mon, MON_DATA_PP2 + i, NULL);
+ }
+
+ ppBonuses = GetMonData(mon, MON_DATA_PP_BONUSES, NULL);
+ ppBonuses >>= 2;
+ moves[3] = move;
+ pp[3] = gBattleMoves[move].pp;
+
+ for (i = 0; i < 4; i++)
+ {
+ SetMonData(mon, MON_DATA_MOVE1 + i, (u8 *)&moves[i]);
+ SetMonData(mon, MON_DATA_PP1 + i, &pp[i]);
+ }
+
+ SetMonData(mon, MON_DATA_PP_BONUSES, &ppBonuses);
+}
+
+void DeleteFirstMoveAndGiveMoveToBoxMon(struct BoxPokemon *boxMon, u16 move)
+{
+ s32 i;
+ u16 moves[4];
+ u8 pp[4];
+ u8 ppBonuses;
+
+ for (i = 0; i < 3; i++)
+ {
+ moves[i] = GetBoxMonData(boxMon, MON_DATA_MOVE2 + i, NULL);
+ pp[i]= GetBoxMonData(boxMon, MON_DATA_PP2 + i, NULL);
+ }
+
+ ppBonuses = GetBoxMonData(boxMon, MON_DATA_PP_BONUSES, NULL);
+ ppBonuses >>= 2;
+ moves[3] = move;
+ pp[3] = gBattleMoves[move].pp;
+
+ for (i = 0; i < 4; i++)
+ {
+ SetBoxMonData(boxMon, MON_DATA_MOVE1 + i, (u8 *)&moves[i]);
+ SetBoxMonData(boxMon, MON_DATA_PP1 + i, &pp[i]);
+ }
+
+ SetBoxMonData(boxMon, MON_DATA_PP_BONUSES, &ppBonuses);
+}
diff --git a/src/pokemon_2.c b/src/pokemon_2.c
new file mode 100644
index 000000000..647808d14
--- /dev/null
+++ b/src/pokemon_2.c
@@ -0,0 +1,539 @@
+#include "global.h"
+#include "text.h"
+#include "string_util.h"
+#include "pokemon.h"
+#include "species.h"
+#include "main.h"
+#include "sprite.h"
+
+extern struct SpriteTemplate gUnknown_02024E8C;
+
+extern u8 gBadEggNickname[];
+extern u8 gEggNickname[];
+extern u32 gBitTable[];
+extern struct BaseStats gBaseStats[];
+extern struct SpriteTemplate gSpriteTemplate_8208288[];
+extern union AmimCmd *gSpriteAnimTable_81E7C64[];
+extern union AnimCmd **gUnknown_081EC2A4[];
+extern union AnimCmd **gUnknown_081ECACC[];
+
+u8 GetMonGender(struct Pokemon *mon)
+{
+ return GetBoxMonGender(&mon->box);
+}
+
+u8 GetBoxMonGender(struct BoxPokemon *boxMon)
+{
+ u16 species = GetBoxMonData(boxMon, MON_DATA_SPECIES, NULL);
+ u32 personality = GetBoxMonData(boxMon, MON_DATA_PERSONALITY, NULL);
+
+ switch (gBaseStats[species].genderRatio)
+ {
+ case MON_MALE:
+ case MON_FEMALE:
+ case MON_GENDERLESS:
+ return gBaseStats[species].genderRatio;
+ }
+
+ if (gBaseStats[species].genderRatio > (personality & 0xFF))
+ return MON_FEMALE;
+ else
+ return MON_MALE;
+}
+
+u8 GetGenderFromSpeciesAndPersonality(u16 species, u32 personality)
+{
+ switch (gBaseStats[species].genderRatio)
+ {
+ case MON_MALE:
+ case MON_FEMALE:
+ case MON_GENDERLESS:
+ return gBaseStats[species].genderRatio;
+ }
+
+ if (gBaseStats[species].genderRatio > (personality & 0xFF))
+ return MON_FEMALE;
+ else
+ return MON_MALE;
+}
+
+void GetMonSpriteTemplate_803C56C(u16 species, u8 a2)
+{
+ gUnknown_02024E8C = gSpriteTemplate_8208288[a2];
+ gUnknown_02024E8C.paletteTag = species;
+ gUnknown_02024E8C.anims = (union AnimCmd **)gSpriteAnimTable_81E7C64;
+}
+
+void GetMonSpriteTemplate_803C5A0(u16 species, u8 a2)
+{
+ gUnknown_02024E8C = gSpriteTemplate_8208288[a2];
+ gUnknown_02024E8C.paletteTag = species;
+ if (a2 == 0 || a2 == 2)
+ gUnknown_02024E8C.anims = gUnknown_081ECACC[species];
+ else
+ gUnknown_02024E8C.anims = gUnknown_081EC2A4[species];
+}
+
+void EncryptBoxMon(struct BoxPokemon *boxMon)
+{
+ u32 i;
+ for (i = 0; i < 12; i++)
+ {
+ boxMon->secure.raw[i] ^= boxMon->personality;
+ boxMon->secure.raw[i] ^= boxMon->otId;
+ }
+}
+
+void DecryptBoxMon(struct BoxPokemon *boxMon)
+{
+ u32 i;
+ for (i = 0; i < 12; i++)
+ {
+ boxMon->secure.raw[i] ^= boxMon->otId;
+ boxMon->secure.raw[i] ^= boxMon->personality;
+ }
+}
+
+#define SUBSTRUCT_CASE(n, v1, v2, v3, v4) \
+case n: \
+ switch (substructType) \
+ { \
+ case 0: \
+ substruct = &substructs ## n [v1]; \
+ break; \
+ case 1: \
+ substruct = &substructs ## n [v2]; \
+ break; \
+ case 2: \
+ substruct = &substructs ## n [v3]; \
+ break; \
+ case 3: \
+ substruct = &substructs ## n [v4]; \
+ break; \
+ } \
+ break;
+
+union PokemonSubstruct *GetSubstruct(struct BoxPokemon *boxMon, u32 personality, u8 substructType)
+{
+ union PokemonSubstruct *substruct = NULL;
+
+ union PokemonSubstruct *substructs0 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs1 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs2 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs3 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs4 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs5 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs6 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs7 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs8 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs9 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs10 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs11 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs12 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs13 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs14 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs15 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs16 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs17 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs18 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs19 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs20 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs21 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs22 = boxMon->secure.substructs;
+ union PokemonSubstruct *substructs23 = boxMon->secure.substructs;
+
+ switch (personality % 24)
+ {
+ SUBSTRUCT_CASE( 0,0,1,2,3)
+ SUBSTRUCT_CASE( 1,0,1,3,2)
+ SUBSTRUCT_CASE( 2,0,2,1,3)
+ SUBSTRUCT_CASE( 3,0,3,1,2)
+ SUBSTRUCT_CASE( 4,0,2,3,1)
+ SUBSTRUCT_CASE( 5,0,3,2,1)
+ SUBSTRUCT_CASE( 6,1,0,2,3)
+ SUBSTRUCT_CASE( 7,1,0,3,2)
+ SUBSTRUCT_CASE( 8,2,0,1,3)
+ SUBSTRUCT_CASE( 9,3,0,1,2)
+ SUBSTRUCT_CASE(10,2,0,3,1)
+ SUBSTRUCT_CASE(11,3,0,2,1)
+ SUBSTRUCT_CASE(12,1,2,0,3)
+ SUBSTRUCT_CASE(13,1,3,0,2)
+ SUBSTRUCT_CASE(14,2,1,0,3)
+ SUBSTRUCT_CASE(15,3,1,0,2)
+ SUBSTRUCT_CASE(16,2,3,0,1)
+ SUBSTRUCT_CASE(17,3,2,0,1)
+ SUBSTRUCT_CASE(18,1,2,3,0)
+ SUBSTRUCT_CASE(19,1,3,2,0)
+ SUBSTRUCT_CASE(20,2,1,3,0)
+ SUBSTRUCT_CASE(21,3,1,2,0)
+ SUBSTRUCT_CASE(22,2,3,1,0)
+ SUBSTRUCT_CASE(23,3,2,1,0)
+ }
+
+ return substruct;
+}
+
+u32 GetMonData(struct Pokemon *mon, s32 field, u8 *data)
+{
+ switch (field)
+ {
+ case MON_DATA_STATUS:
+ return mon->status;
+ case MON_DATA_LEVEL:
+ return mon->level;
+ case MON_DATA_HP:
+ return mon->hp;
+ case MON_DATA_MAX_HP:
+ return mon->maxHP;
+ case MON_DATA_ATK:
+ return mon->attack;
+ case MON_DATA_DEF:
+ return mon->defense;
+ case MON_DATA_SPD:
+ return mon->speed;
+ case MON_DATA_SPATK:
+ return mon->spAttack;
+ case MON_DATA_SPDEF:
+ return mon->spDefense;
+ case MON_DATA_64:
+ return mon->pokerus;
+ default:
+ return GetBoxMonData(&mon->box, field, data);
+ }
+}
+
+u32 GetBoxMonData(struct BoxPokemon *boxMon, s32 field, u8 *data)
+{
+ u32 retVal = 0;
+ struct PokemonSubstruct0 *substruct0 = NULL;
+ struct PokemonSubstruct1 *substruct1 = NULL;
+ struct PokemonSubstruct2 *substruct2 = NULL;
+ struct PokemonSubstruct3 *substruct3 = NULL;
+
+ if (field > MON_DATA_10)
+ {
+ substruct0 = &(GetSubstruct(boxMon, boxMon->personality, 0)->type0);
+ substruct1 = &(GetSubstruct(boxMon, boxMon->personality, 1)->type1);
+ substruct2 = &(GetSubstruct(boxMon, boxMon->personality, 2)->type2);
+ substruct3 = &(GetSubstruct(boxMon, boxMon->personality, 3)->type3);
+
+ DecryptBoxMon(boxMon);
+
+ if (CalculateBoxMonChecksum(boxMon) != boxMon->checksum)
+ {
+ boxMon->isBadEgg = 1;
+ boxMon->sanity3 = 1;
+ substruct3->isEgg = 1;
+ }
+ }
+
+ switch (field)
+ {
+ case MON_DATA_PERSONALITY:
+ retVal = boxMon->personality;
+ break;
+ case MON_DATA_OT_ID:
+ retVal = boxMon->otId;
+ break;
+ case MON_DATA_NICKNAME:
+ {
+ if (boxMon->isBadEgg)
+ {
+ StringCopy(data, gBadEggNickname);
+ retVal = StringLength(data);
+ }
+ else if (boxMon->sanity3)
+ {
+ StringCopy(data, gEggNickname);
+ retVal = StringLength(data);
+ }
+ else
+ {
+ retVal = 0;
+
+ while (retVal < 10 && boxMon->nickname[retVal] != EOS)
+ {
+ data[retVal] = boxMon->nickname[retVal];
+ retVal++;
+ }
+
+ data[retVal] = EOS;
+ ConvertInternationalString(data, boxMon->language);
+ retVal = StringLength(data);
+ }
+ break;
+ }
+ case MON_DATA_LANGUAGE:
+ retVal = boxMon->language;
+ break;
+ case MON_DATA_SANITY_BIT1:
+ retVal = boxMon->isBadEgg;
+ break;
+ case MON_DATA_SANITY_BIT2:
+ retVal = boxMon->sanity2;
+ break;
+ case MON_DATA_SANITY_BIT3:
+ retVal = boxMon->sanity3;
+ break;
+ case MON_DATA_OT_NAME:
+ {
+ retVal = 0;
+
+ while (retVal < 7 && boxMon->otName[retVal] != EOS)
+ {
+ data[retVal] = boxMon->otName[retVal];
+ retVal++;
+ }
+
+ data[retVal] = EOS;
+ break;
+ }
+ case MON_DATA_MARKINGS:
+ retVal = boxMon->markings;
+ break;
+ case MON_DATA_CHECKSUM:
+ retVal = boxMon->checksum;
+ break;
+ case MON_DATA_10:
+ retVal = boxMon->unknown;
+ break;
+ case MON_DATA_SPECIES:
+ retVal = boxMon->isBadEgg ? 412 : substruct0->species;
+ break;
+ case MON_DATA_HELD_ITEM:
+ retVal = substruct0->heldItem;
+ break;
+ case MON_DATA_EXP:
+ retVal = substruct0->experience;
+ break;
+ case MON_DATA_PP_BONUSES:
+ retVal = substruct0->ppBonuses;
+ break;
+ case MON_DATA_FRIENDSHIP:
+ retVal = substruct0->friendship;
+ break;
+ case MON_DATA_MOVE1:
+ case MON_DATA_MOVE2:
+ case MON_DATA_MOVE3:
+ case MON_DATA_MOVE4:
+ retVal = substruct1->moves[field - MON_DATA_MOVE1];
+ break;
+ case MON_DATA_PP1:
+ case MON_DATA_PP2:
+ case MON_DATA_PP3:
+ case MON_DATA_PP4:
+ retVal = substruct1->pp[field - MON_DATA_PP1];
+ break;
+ case MON_DATA_HP_EV:
+ retVal = substruct2->hpEV;
+ break;
+ case MON_DATA_ATK_EV:
+ retVal = substruct2->attackEV;
+ break;
+ case MON_DATA_DEF_EV:
+ retVal = substruct2->defenseEV;
+ break;
+ case MON_DATA_SPD_EV:
+ retVal = substruct2->speedEV;
+ break;
+ case MON_DATA_SPATK_EV:
+ retVal = substruct2->spAttackEV;
+ break;
+ case MON_DATA_SPDEF_EV:
+ retVal = substruct2->spDefenseEV;
+ break;
+ case MON_DATA_COOL:
+ retVal = substruct2->cool;
+ break;
+ case MON_DATA_BEAUTY:
+ retVal = substruct2->beauty;
+ break;
+ case MON_DATA_CUTE:
+ retVal = substruct2->cute;
+ break;
+ case MON_DATA_SMART:
+ retVal = substruct2->smart;
+ break;
+ case MON_DATA_TOUGH:
+ retVal = substruct2->tough;
+ break;
+ case MON_DATA_SHEEN:
+ retVal = substruct2->sheen;
+ break;
+ case MON_DATA_POKERUS:
+ retVal = substruct3->pokerus;
+ break;
+ case MON_DATA_MET_LOCATION:
+ retVal = substruct3->metLocation;
+ break;
+ case MON_DATA_MET_LEVEL:
+ retVal = substruct3->metLevel;
+ break;
+ case MON_DATA_MET_GAME:
+ retVal = substruct3->metGame;
+ break;
+ case MON_DATA_POKEBALL:
+ retVal = substruct3->pokeball;
+ break;
+ case MON_DATA_OT_GENDER:
+ retVal = substruct3->otGender;
+ break;
+ case MON_DATA_HP_IV:
+ retVal = substruct3->hpIV;
+ break;
+ case MON_DATA_ATK_IV:
+ retVal = substruct3->attackIV;
+ break;
+ case MON_DATA_DEF_IV:
+ retVal = substruct3->defenseIV;
+ break;
+ case MON_DATA_SPD_IV:
+ retVal = substruct3->speedIV;
+ break;
+ case MON_DATA_SPATK_IV:
+ retVal = substruct3->spAttackIV;
+ break;
+ case MON_DATA_SPDEF_IV:
+ retVal = substruct3->spDefenseIV;
+ break;
+ case MON_DATA_IS_EGG:
+ retVal = substruct3->isEgg;
+ break;
+ case MON_DATA_ALT_ABILITY:
+ retVal = substruct3->altAbility;
+ break;
+ case MON_DATA_COOL_RIBBON:
+ retVal = substruct3->coolRibbon;
+ break;
+ case MON_DATA_BEAUTY_RIBBON:
+ retVal = substruct3->beautyRibbon;
+ break;
+ case MON_DATA_CUTE_RIBBON:
+ retVal = substruct3->cuteRibbon;
+ break;
+ case MON_DATA_SMART_RIBBON:
+ retVal = substruct3->smartRibbon;
+ break;
+ case MON_DATA_TOUGH_RIBBON:
+ retVal = substruct3->toughRibbon;
+ break;
+ case MON_DATA_CHAMPION_RIBBON:
+ retVal = substruct3->championRibbon;
+ break;
+ case MON_DATA_WINNING_RIBBON:
+ retVal = substruct3->winningRibbon;
+ break;
+ case MON_DATA_VICTORY_RIBBON:
+ retVal = substruct3->victoryRibbon;
+ break;
+ case MON_DATA_ARTIST_RIBBON:
+ retVal = substruct3->artistRibbon;
+ break;
+ case MON_DATA_EFFORT_RIBBON:
+ retVal = substruct3->effortRibbon;
+ break;
+ case MON_DATA_GIFT_RIBBON_1:
+ retVal = substruct3->giftRibbon1;
+ break;
+ case MON_DATA_GIFT_RIBBON_2:
+ retVal = substruct3->giftRibbon2;
+ break;
+ case MON_DATA_GIFT_RIBBON_3:
+ retVal = substruct3->giftRibbon3;
+ break;
+ case MON_DATA_GIFT_RIBBON_4:
+ retVal = substruct3->giftRibbon4;
+ break;
+ case MON_DATA_GIFT_RIBBON_5:
+ retVal = substruct3->giftRibbon5;
+ break;
+ case MON_DATA_GIFT_RIBBON_6:
+ retVal = substruct3->giftRibbon6;
+ break;
+ case MON_DATA_GIFT_RIBBON_7:
+ retVal = substruct3->giftRibbon7;
+ break;
+ case MON_DATA_FATEFUL_ENCOUNTER:
+ retVal = substruct3->fatefulEncounter;
+ break;
+ case MON_DATA_SPECIES2:
+ retVal = substruct0->species;
+ if (substruct0->species && (substruct3->isEgg || boxMon->isBadEgg))
+ retVal = 412;
+ break;
+ case MON_DATA_IVS:
+ retVal = substruct3->hpIV | (substruct3->attackIV << 5) | (substruct3->defenseIV << 10) | (substruct3->speedIV << 15) | (substruct3->spAttackIV << 20) | (substruct3->spDefenseIV << 25);
+ break;
+ case MON_DATA_KNOWN_MOVES:
+ if (substruct0->species && !substruct3->isEgg)
+ {
+ u16 *moves = (u16 *)data;
+ s32 i = 0;
+
+ while (moves[i] != 355)
+ {
+ u16 move = moves[i];
+ if (substruct1->moves[0] == move
+ || substruct1->moves[1] == move
+ || substruct1->moves[2] == move
+ || substruct1->moves[3] == move)
+ retVal |= gBitTable[i];
+ i++;
+ }
+ }
+ break;
+ case MON_DATA_RIBBON_COUNT:
+ retVal = 0;
+ if (substruct0->species && !substruct3->isEgg)
+ {
+ retVal += substruct3->coolRibbon;
+ retVal += substruct3->beautyRibbon;
+ retVal += substruct3->cuteRibbon;
+ retVal += substruct3->smartRibbon;
+ retVal += substruct3->toughRibbon;
+ retVal += substruct3->championRibbon;
+ retVal += substruct3->winningRibbon;
+ retVal += substruct3->victoryRibbon;
+ retVal += substruct3->artistRibbon;
+ retVal += substruct3->effortRibbon;
+ retVal += substruct3->giftRibbon1;
+ retVal += substruct3->giftRibbon2;
+ retVal += substruct3->giftRibbon3;
+ retVal += substruct3->giftRibbon4;
+ retVal += substruct3->giftRibbon5;
+ retVal += substruct3->giftRibbon6;
+ retVal += substruct3->giftRibbon7;
+ }
+ break;
+ case MON_DATA_RIBBONS:
+ retVal = 0;
+ if (substruct0->species && !substruct3->isEgg)
+ {
+ retVal = substruct3->championRibbon
+ | (substruct3->coolRibbon << 1)
+ | (substruct3->beautyRibbon << 4)
+ | (substruct3->cuteRibbon << 7)
+ | (substruct3->smartRibbon << 10)
+ | (substruct3->toughRibbon << 13)
+ | (substruct3->winningRibbon << 16)
+ | (substruct3->victoryRibbon << 17)
+ | (substruct3->artistRibbon << 18)
+ | (substruct3->effortRibbon << 19)
+ | (substruct3->giftRibbon1 << 20)
+ | (substruct3->giftRibbon2 << 21)
+ | (substruct3->giftRibbon3 << 22)
+ | (substruct3->giftRibbon4 << 23)
+ | (substruct3->giftRibbon5 << 24)
+ | (substruct3->giftRibbon6 << 25)
+ | (substruct3->giftRibbon7 << 26);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (field > MON_DATA_10)
+ EncryptBoxMon(boxMon);
+
+ return retVal;
+}
diff --git a/src/text.c b/src/text.c
index 372d3e7e2..64a302fed 100644
--- a/src/text.c
+++ b/src/text.c
@@ -2523,7 +2523,7 @@ u8 sub_80037A0(struct Window *win)
return retVal;
}
-u8 sub_80037C8(struct Window *win, u8 lineLength)
+u32 sub_80037C8(struct Window *win, u8 lineLength)
{
u8 retVal;
diff --git a/src/text_window.c b/src/text_window.c
new file mode 100644
index 000000000..ab14fe1fb
--- /dev/null
+++ b/src/text_window.c
@@ -0,0 +1,196 @@
+#include "global.h"
+#include "main.h"
+#include "text.h"
+#include "text_window.h"
+
+u16 SetTextWindowBaseTileNum(u16);
+void LoadTextWindowGraphics(struct Window *);
+void LoadTextWindowGraphics_OverridePalSlot(struct Window *, u8);
+void LoadTextWindowGraphics_OverrideFrameType(struct Window *, u8);
+void DrawTextWindow(struct Window *win, u8 left, u8 top, u8 right, u8 bottom);
+const struct FrameGraphics *GetTextWindowFrameGraphics(u8 frameType);
+static void LoadTextWindowTiles(u8, void *);
+static void LoadTextWindowPalette(u8, u8);
+static void DrawTextWindowInternal(u16 *dest, u16 baseTileNum, u8 left, u8 top, u8 right, u8 bottom);
+u16 SetMessageBoxBaseTileNum(u16);
+void unref_sub_80651DC(struct Window *, u8 *);
+void DisplayMessageBox(struct Window *);
+static u16 GetMessageBoxTilemapEntry(u16 tilemapEntry, u8 x, u8 y, u8 width, u8 height);
+static void DrawMessageBox(struct Window *win, u8 left, u8 top, u8 width, u8 height);
+void DrawStandardMessageBox(struct Window *win);
+void LoadMessageBoxTiles(struct Window *win);
+void sub_806536C(struct Window *win);
+
+static u16 sTextWindowBaseTileNum;
+static u16 sMessageBoxBaseTileNum;
+
+struct FrameGraphics
+{
+ u8 *tiles;
+ u16 *palette;
+};
+
+extern const struct FrameGraphics gUnknown_083761F0[20];
+
+extern const u16 gMessageBoxTilemap[5][7];
+extern const u8 gMessageBox_Gfx[];
+
+u16 SetTextWindowBaseTileNum(u16 baseTileNum)
+{
+ sTextWindowBaseTileNum = baseTileNum;
+ return baseTileNum + 9;
+}
+
+void LoadTextWindowGraphics(struct Window *win)
+{
+ u8 *tileData = win->config->tileData + TILE_SIZE_4BPP * sTextWindowBaseTileNum;
+ LoadTextWindowTiles(gSaveBlock2.optionsWindowFrameType, tileData);
+ LoadTextWindowPalette(gSaveBlock2.optionsWindowFrameType, 0xE);
+}
+
+void LoadTextWindowGraphics_OverridePalSlot(struct Window *win, u8 palSlot)
+{
+ u8 *tileData = win->config->tileData + TILE_SIZE_4BPP * sTextWindowBaseTileNum;
+ LoadTextWindowTiles(gSaveBlock2.optionsWindowFrameType, tileData);
+ LoadTextWindowPalette(gSaveBlock2.optionsWindowFrameType, palSlot);
+}
+
+void LoadTextWindowGraphics_OverrideFrameType(struct Window *win, u8 frameType)
+{
+ u8 *tileData = win->config->tileData + TILE_SIZE_4BPP * sTextWindowBaseTileNum;
+ LoadTextWindowTiles(frameType, tileData);
+ LoadTextWindowPalette(frameType, 0xE);
+}
+
+void DrawTextWindow(struct Window *win, u8 left, u8 top, u8 right, u8 bottom)
+{
+ DrawTextWindowInternal(win->config->tilemap, sTextWindowBaseTileNum, left, top, right, bottom);
+}
+
+const struct FrameGraphics *GetTextWindowFrameGraphics(u8 frameType)
+{
+ if (frameType > 19)
+ return &gUnknown_083761F0[0];
+ else
+ return &gUnknown_083761F0[frameType];
+}
+
+static void LoadTextWindowTiles(u8 frameType, void *dest)
+{
+ const struct FrameGraphics *frameGraphics = GetTextWindowFrameGraphics(frameType);
+ CpuFastCopy(frameGraphics->tiles, dest, 9 * TILE_SIZE_4BPP);
+}
+
+static void LoadTextWindowPalette(u8 frameType, u8 palSlot)
+{
+ const struct FrameGraphics *frameGraphics = GetTextWindowFrameGraphics(frameType);
+ LoadPalette(frameGraphics->palette, 16 * palSlot, 0x20);
+}
+
+static void DrawTextWindowInternal(u16 *dest, u16 baseTileNum, u8 left, u8 top, u8 right, u8 bottom)
+{
+ u8 x, y;
+ u8 startX, endX;
+ u8 startY, endY;
+
+ startX = (left < right) ? left : right;
+ endX = (right > left) ? right : left;
+
+ startY = (top < bottom) ? top : bottom;
+ endY = (bottom > top) ? bottom : top;
+
+ dest[32 * startY + startX] = baseTileNum | 0xE000;
+
+ for (x = startX + 1; x < endX; x++)
+ dest[32 * startY + x] = (baseTileNum + 1) | 0xE000;
+
+ dest[32 * startY + endX] = (baseTileNum + 2) | 0xE000;
+
+ for (y = startY + 1; y < endY; y++)
+ {
+ dest[32 * y + startX] = (baseTileNum + 3) | 0xE000;
+
+ for (x = startX + 1; x < endX; x++)
+ dest[32 * y + x] = (baseTileNum + 4) | 0xE000;
+
+ dest[32 * y + endX] = (baseTileNum + 5) | 0xE000;
+ }
+
+ dest[32 * endY + startX] = (baseTileNum + 6) | 0xE000;
+
+ for (x = startX + 1; x < endX; x++)
+ dest[32 * endY + x] = (baseTileNum + 7) | 0xE000;
+
+ dest[32 * endY + endX] = (baseTileNum + 8) | 0xE000;
+}
+
+u16 SetMessageBoxBaseTileNum(u16 baseTileNum)
+{
+ sMessageBoxBaseTileNum = baseTileNum;
+ return baseTileNum + 14;
+}
+
+void unref_sub_80651DC(struct Window *win, u8 *text)
+{
+ sub_8002EB0(win, text, sMessageBoxBaseTileNum + 14, 2, 15);
+}
+
+void DisplayMessageBox(struct Window *win)
+{
+ LoadMessageBoxTiles(win);
+ DrawStandardMessageBox(win);
+}
+
+static u16 GetMessageBoxTilemapEntry(u16 baseTilemapEntry, u8 x, u8 y, u8 width, u8 height)
+{
+ u16 tilemapEntry = 9;
+
+ if (y >= height)
+ y = y - height + 3;
+ else if (y > 1)
+ y = 2;
+
+ if (x >= width + 2)
+ x = x - (width + 2) + 4;
+ else if (x > 2)
+ x = 3;
+
+ if (x <= 6 && y <= 4)
+ tilemapEntry = gMessageBoxTilemap[y][x];
+
+ tilemapEntry += baseTilemapEntry;
+
+ return tilemapEntry;
+}
+
+static void DrawMessageBox(struct Window *win, u8 left, u8 top, u8 width, u8 height)
+{
+ u8 i, j;
+ u16 tilemapEntry = (win->paletteNum << 12) | sMessageBoxBaseTileNum;
+ u16 *tilemap = win->config->tilemap;
+
+ for (i = 0; i < height + 2; i++)
+ for (j = 0; j < width + 6; j++)
+ tilemap[(left + j) + 32 * (top + i)] = (win->paletteNum << 12) | GetMessageBoxTilemapEntry(tilemapEntry, j, i, width, height);
+}
+
+void DrawStandardMessageBox(struct Window *win)
+{
+ DrawMessageBox(win, 0, 14, 26, 4);
+}
+
+void LoadMessageBoxTiles(struct Window *win)
+{
+ u8 *tileData = win->config->tileData;
+ CpuFastCopy(gMessageBox_Gfx, tileData + 32 * sMessageBoxBaseTileNum, 14 * TILE_SIZE_4BPP);
+}
+
+void sub_806536C(struct Window *win)
+{
+ u8 i;
+ u16 *tilemap = win->config->tilemap + 0x1C0;
+ u16 tilemapEntry = win->paletteNum << 12;
+
+ for (i = 0; i < 0xC0; i++)
+ tilemap[i] = tilemapEntry;
+}