pokeemerald/src/start_menu.c
Eduardo Quezada 0d5b00aaf2 Merge remote-tracking branch 'pret/master' into RHH/pr/upcoming/pret_20230829
# Conflicts:
#	README.md
#	data/battle_ai_scripts.s
#	data/battle_scripts_1.s
#	data/maps/BattleFrontier_Lounge7/scripts.inc
#	include/battle_anim.h
#	include/battle_message.h
#	include/constants/items.h
#	src/battle_ai_script_commands.c
#	src/battle_ai_switch_items.c
#	src/battle_anim_throw.c
#	src/battle_anim_utility_funcs.c
#	src/battle_controller_link_opponent.c
#	src/battle_controller_link_partner.c
#	src/battle_controller_opponent.c
#	src/battle_controller_player.c
#	src/battle_controller_player_partner.c
#	src/battle_controller_recorded_opponent.c
#	src/battle_controller_recorded_player.c
#	src/battle_controller_wally.c
#	src/battle_gfx_sfx_util.c
#	src/battle_message.c
#	src/battle_script_commands.c
#	src/battle_util.c
#	src/data/party_menu.h
#	src/data/pokemon/tmhm_learnsets.h
#	src/daycare.c
#	src/field_specials.c
#	src/hall_of_fame.c
#	src/party_menu.c
#	src/pokemon.c
#	src/tv.c
2023-08-31 14:28:01 -04:00

1488 lines
38 KiB
C

#include "global.h"
#include "battle_pike.h"
#include "battle_pyramid.h"
#include "battle_pyramid_bag.h"
#include "bg.h"
#include "debug.h"
#include "event_data.h"
#include "event_object_movement.h"
#include "event_object_lock.h"
#include "event_scripts.h"
#include "fieldmap.h"
#include "field_effect.h"
#include "field_player_avatar.h"
#include "field_specials.h"
#include "field_weather.h"
#include "field_screen_effect.h"
#include "frontier_pass.h"
#include "frontier_util.h"
#include "gpu_regs.h"
#include "international_string_util.h"
#include "item_menu.h"
#include "link.h"
#include "load_save.h"
#include "main.h"
#include "menu.h"
#include "new_game.h"
#include "option_menu.h"
#include "overworld.h"
#include "palette.h"
#include "party_menu.h"
#include "pokedex.h"
#include "pokenav.h"
#include "safari_zone.h"
#include "save.h"
#include "scanline_effect.h"
#include "script.h"
#include "sound.h"
#include "start_menu.h"
#include "strings.h"
#include "string_util.h"
#include "task.h"
#include "text.h"
#include "text_window.h"
#include "trainer_card.h"
#include "window.h"
#include "union_room.h"
#include "constants/battle_frontier.h"
#include "constants/rgb.h"
#include "constants/songs.h"
// Menu actions
enum
{
MENU_ACTION_POKEDEX,
MENU_ACTION_POKEMON,
MENU_ACTION_BAG,
MENU_ACTION_POKENAV,
MENU_ACTION_PLAYER,
MENU_ACTION_SAVE,
MENU_ACTION_OPTION,
MENU_ACTION_EXIT,
MENU_ACTION_RETIRE_SAFARI,
MENU_ACTION_PLAYER_LINK,
MENU_ACTION_REST_FRONTIER,
MENU_ACTION_RETIRE_FRONTIER,
MENU_ACTION_PYRAMID_BAG,
MENU_ACTION_DEBUG,
};
// Save status
enum
{
SAVE_IN_PROGRESS,
SAVE_SUCCESS,
SAVE_CANCELED,
SAVE_ERROR
};
// IWRAM common
bool8 (*gMenuCallback)(void);
// EWRAM
EWRAM_DATA static u8 sSafariBallsWindowId = 0;
EWRAM_DATA static u8 sBattlePyramidFloorWindowId = 0;
EWRAM_DATA static u8 sStartMenuCursorPos = 0;
EWRAM_DATA static u8 sNumStartMenuActions = 0;
EWRAM_DATA static u8 sCurrentStartMenuActions[9] = {0};
EWRAM_DATA static u8 sInitStartMenuData[2] = {0};
EWRAM_DATA static u8 (*sSaveDialogCallback)(void) = NULL;
EWRAM_DATA static u8 sSaveDialogTimer = 0;
EWRAM_DATA static bool8 sSavingComplete = FALSE;
EWRAM_DATA static u8 sSaveInfoWindowId = 0;
// Menu action callbacks
static bool8 StartMenuPokedexCallback(void);
static bool8 StartMenuPokemonCallback(void);
static bool8 StartMenuBagCallback(void);
static bool8 StartMenuPokeNavCallback(void);
static bool8 StartMenuPlayerNameCallback(void);
static bool8 StartMenuSaveCallback(void);
static bool8 StartMenuOptionCallback(void);
static bool8 StartMenuExitCallback(void);
static bool8 StartMenuSafariZoneRetireCallback(void);
static bool8 StartMenuLinkModePlayerNameCallback(void);
static bool8 StartMenuBattlePyramidRetireCallback(void);
static bool8 StartMenuBattlePyramidBagCallback(void);
static bool8 StartMenuDebugCallback(void);
// Menu callbacks
static bool8 SaveStartCallback(void);
static bool8 SaveCallback(void);
static bool8 BattlePyramidRetireStartCallback(void);
static bool8 BattlePyramidRetireReturnCallback(void);
static bool8 BattlePyramidRetireCallback(void);
static bool8 HandleStartMenuInput(void);
// Save dialog callbacks
static u8 SaveConfirmSaveCallback(void);
static u8 SaveYesNoCallback(void);
static u8 SaveConfirmInputCallback(void);
static u8 SaveFileExistsCallback(void);
static u8 SaveConfirmOverwriteDefaultNoCallback(void);
static u8 SaveConfirmOverwriteCallback(void);
static u8 SaveOverwriteInputCallback(void);
static u8 SaveSavingMessageCallback(void);
static u8 SaveDoSaveCallback(void);
static u8 SaveSuccessCallback(void);
static u8 SaveReturnSuccessCallback(void);
static u8 SaveErrorCallback(void);
static u8 SaveReturnErrorCallback(void);
static u8 BattlePyramidConfirmRetireCallback(void);
static u8 BattlePyramidRetireYesNoCallback(void);
static u8 BattlePyramidRetireInputCallback(void);
// Task callbacks
static void StartMenuTask(u8 taskId);
static void SaveGameTask(u8 taskId);
static void Task_SaveAfterLinkBattle(u8 taskId);
static void Task_WaitForBattleTowerLinkSave(u8 taskId);
static bool8 FieldCB_ReturnToFieldStartMenu(void);
static const struct WindowTemplate sWindowTemplate_SafariBalls = {
.bg = 0,
.tilemapLeft = 1,
.tilemapTop = 1,
.width = 9,
.height = 4,
.paletteNum = 15,
.baseBlock = 0x8
};
static const u8 *const sPyramidFloorNames[FRONTIER_STAGES_PER_CHALLENGE + 1] =
{
gText_Floor1,
gText_Floor2,
gText_Floor3,
gText_Floor4,
gText_Floor5,
gText_Floor6,
gText_Floor7,
gText_Peak
};
static const struct WindowTemplate sWindowTemplate_PyramidFloor = {
.bg = 0,
.tilemapLeft = 1,
.tilemapTop = 1,
.width = 10,
.height = 4,
.paletteNum = 15,
.baseBlock = 0x8
};
static const struct WindowTemplate sWindowTemplate_PyramidPeak = {
.bg = 0,
.tilemapLeft = 1,
.tilemapTop = 1,
.width = 12,
.height = 4,
.paletteNum = 15,
.baseBlock = 0x8
};
static const u8 gText_MenuDebug[] = _("DEBUG");
static const struct MenuAction sStartMenuItems[] =
{
[MENU_ACTION_POKEDEX] = {gText_MenuPokedex, {.u8_void = StartMenuPokedexCallback}},
[MENU_ACTION_POKEMON] = {gText_MenuPokemon, {.u8_void = StartMenuPokemonCallback}},
[MENU_ACTION_BAG] = {gText_MenuBag, {.u8_void = StartMenuBagCallback}},
[MENU_ACTION_POKENAV] = {gText_MenuPokenav, {.u8_void = StartMenuPokeNavCallback}},
[MENU_ACTION_PLAYER] = {gText_MenuPlayer, {.u8_void = StartMenuPlayerNameCallback}},
[MENU_ACTION_SAVE] = {gText_MenuSave, {.u8_void = StartMenuSaveCallback}},
[MENU_ACTION_OPTION] = {gText_MenuOption, {.u8_void = StartMenuOptionCallback}},
[MENU_ACTION_EXIT] = {gText_MenuExit, {.u8_void = StartMenuExitCallback}},
[MENU_ACTION_RETIRE_SAFARI] = {gText_MenuRetire, {.u8_void = StartMenuSafariZoneRetireCallback}},
[MENU_ACTION_PLAYER_LINK] = {gText_MenuPlayer, {.u8_void = StartMenuLinkModePlayerNameCallback}},
[MENU_ACTION_REST_FRONTIER] = {gText_MenuRest, {.u8_void = StartMenuSaveCallback}},
[MENU_ACTION_RETIRE_FRONTIER] = {gText_MenuRetire, {.u8_void = StartMenuBattlePyramidRetireCallback}},
[MENU_ACTION_PYRAMID_BAG] = {gText_MenuBag, {.u8_void = StartMenuBattlePyramidBagCallback}},
[MENU_ACTION_DEBUG] = {gText_MenuDebug, {.u8_void = StartMenuDebugCallback}},
};
static const struct BgTemplate sBgTemplates_LinkBattleSave[] =
{
{
.bg = 0,
.charBaseIndex = 2,
.mapBaseIndex = 31,
.screenSize = 0,
.paletteMode = 0,
.priority = 0,
.baseTile = 0
}
};
static const struct WindowTemplate sWindowTemplates_LinkBattleSave[] =
{
{
.bg = 0,
.tilemapLeft = 2,
.tilemapTop = 15,
.width = 26,
.height = 4,
.paletteNum = 15,
.baseBlock = 0x194
},
DUMMY_WIN_TEMPLATE
};
static const struct WindowTemplate sSaveInfoWindowTemplate = {
.bg = 0,
.tilemapLeft = 1,
.tilemapTop = 1,
.width = 14,
.height = 10,
.paletteNum = 15,
.baseBlock = 8
};
// Local functions
static void BuildStartMenuActions(void);
static void AddStartMenuAction(u8 action);
static void BuildNormalStartMenu(void);
static void BuildDebugStartMenu(void);
static void BuildSafariZoneStartMenu(void);
static void BuildLinkModeStartMenu(void);
static void BuildUnionRoomStartMenu(void);
static void BuildBattlePikeStartMenu(void);
static void BuildBattlePyramidStartMenu(void);
static void BuildMultiPartnerRoomStartMenu(void);
static void ShowSafariBallsWindow(void);
static void ShowPyramidFloorWindow(void);
static void RemoveExtraStartMenuWindows(void);
static bool32 PrintStartMenuActions(s8 *pIndex, u32 count);
static bool32 InitStartMenuStep(void);
static void InitStartMenu(void);
static void CreateStartMenuTask(TaskFunc followupFunc);
static void InitSave(void);
static u8 RunSaveCallback(void);
static void ShowSaveMessage(const u8 *message, u8 (*saveCallback)(void));
static void HideSaveMessageWindow(void);
static void HideSaveInfoWindow(void);
static void SaveStartTimer(void);
static bool8 SaveSuccesTimer(void);
static bool8 SaveErrorTimer(void);
static void InitBattlePyramidRetire(void);
static void VBlankCB_LinkBattleSave(void);
static bool32 InitSaveWindowAfterLinkBattle(u8 *par1);
static void CB2_SaveAfterLinkBattle(void);
static void ShowSaveInfoWindow(void);
static void RemoveSaveInfoWindow(void);
static void HideStartMenuWindow(void);
static void HideStartMenuDebug(void);
void SetDexPokemonPokenavFlags(void) // unused
{
FlagSet(FLAG_SYS_POKEDEX_GET);
FlagSet(FLAG_SYS_POKEMON_GET);
FlagSet(FLAG_SYS_POKENAV_GET);
}
static void BuildStartMenuActions(void)
{
sNumStartMenuActions = 0;
if (IsOverworldLinkActive() == TRUE)
{
BuildLinkModeStartMenu();
}
else if (InUnionRoom() == TRUE)
{
BuildUnionRoomStartMenu();
}
else if (GetSafariZoneFlag() == TRUE)
{
BuildSafariZoneStartMenu();
}
else if (InBattlePike())
{
BuildBattlePikeStartMenu();
}
else if (InBattlePyramid())
{
BuildBattlePyramidStartMenu();
}
else if (InMultiPartnerRoom())
{
BuildMultiPartnerRoomStartMenu();
}
else
{
#if DEBUG_OVERWORLD_MENU == TRUE && DEBUG_OVERWORLD_IN_MENU == TRUE
BuildDebugStartMenu();
#else
BuildNormalStartMenu();
#endif
}
}
static void AddStartMenuAction(u8 action)
{
AppendToList(sCurrentStartMenuActions, &sNumStartMenuActions, action);
}
static void BuildNormalStartMenu(void)
{
if (FlagGet(FLAG_SYS_POKEDEX_GET) == TRUE)
{
AddStartMenuAction(MENU_ACTION_POKEDEX);
}
if (FlagGet(FLAG_SYS_POKEMON_GET) == TRUE)
{
AddStartMenuAction(MENU_ACTION_POKEMON);
}
AddStartMenuAction(MENU_ACTION_BAG);
if (FlagGet(FLAG_SYS_POKENAV_GET) == TRUE)
{
AddStartMenuAction(MENU_ACTION_POKENAV);
}
AddStartMenuAction(MENU_ACTION_PLAYER);
AddStartMenuAction(MENU_ACTION_SAVE);
AddStartMenuAction(MENU_ACTION_OPTION);
AddStartMenuAction(MENU_ACTION_EXIT);
}
static void BuildDebugStartMenu(void)
{
AddStartMenuAction(MENU_ACTION_DEBUG);
if (FlagGet(FLAG_SYS_POKEDEX_GET) == TRUE)
AddStartMenuAction(MENU_ACTION_POKEDEX);
if (FlagGet(FLAG_SYS_POKEMON_GET) == TRUE)
AddStartMenuAction(MENU_ACTION_POKEMON);
AddStartMenuAction(MENU_ACTION_BAG);
if (FlagGet(FLAG_SYS_POKENAV_GET) == TRUE)
AddStartMenuAction(MENU_ACTION_POKENAV);
AddStartMenuAction(MENU_ACTION_PLAYER);
AddStartMenuAction(MENU_ACTION_SAVE);
AddStartMenuAction(MENU_ACTION_OPTION);
}
static void BuildSafariZoneStartMenu(void)
{
AddStartMenuAction(MENU_ACTION_RETIRE_SAFARI);
AddStartMenuAction(MENU_ACTION_POKEDEX);
AddStartMenuAction(MENU_ACTION_POKEMON);
AddStartMenuAction(MENU_ACTION_BAG);
AddStartMenuAction(MENU_ACTION_PLAYER);
AddStartMenuAction(MENU_ACTION_OPTION);
AddStartMenuAction(MENU_ACTION_EXIT);
}
static void BuildLinkModeStartMenu(void)
{
AddStartMenuAction(MENU_ACTION_POKEMON);
AddStartMenuAction(MENU_ACTION_BAG);
if (FlagGet(FLAG_SYS_POKENAV_GET) == TRUE)
{
AddStartMenuAction(MENU_ACTION_POKENAV);
}
AddStartMenuAction(MENU_ACTION_PLAYER_LINK);
AddStartMenuAction(MENU_ACTION_OPTION);
AddStartMenuAction(MENU_ACTION_EXIT);
}
static void BuildUnionRoomStartMenu(void)
{
AddStartMenuAction(MENU_ACTION_POKEMON);
AddStartMenuAction(MENU_ACTION_BAG);
if (FlagGet(FLAG_SYS_POKENAV_GET) == TRUE)
{
AddStartMenuAction(MENU_ACTION_POKENAV);
}
AddStartMenuAction(MENU_ACTION_PLAYER);
AddStartMenuAction(MENU_ACTION_OPTION);
AddStartMenuAction(MENU_ACTION_EXIT);
}
static void BuildBattlePikeStartMenu(void)
{
AddStartMenuAction(MENU_ACTION_POKEDEX);
AddStartMenuAction(MENU_ACTION_POKEMON);
AddStartMenuAction(MENU_ACTION_PLAYER);
AddStartMenuAction(MENU_ACTION_OPTION);
AddStartMenuAction(MENU_ACTION_EXIT);
}
static void BuildBattlePyramidStartMenu(void)
{
AddStartMenuAction(MENU_ACTION_POKEMON);
AddStartMenuAction(MENU_ACTION_PYRAMID_BAG);
AddStartMenuAction(MENU_ACTION_PLAYER);
AddStartMenuAction(MENU_ACTION_REST_FRONTIER);
AddStartMenuAction(MENU_ACTION_RETIRE_FRONTIER);
AddStartMenuAction(MENU_ACTION_OPTION);
AddStartMenuAction(MENU_ACTION_EXIT);
}
static void BuildMultiPartnerRoomStartMenu(void)
{
AddStartMenuAction(MENU_ACTION_POKEMON);
AddStartMenuAction(MENU_ACTION_PLAYER);
AddStartMenuAction(MENU_ACTION_OPTION);
AddStartMenuAction(MENU_ACTION_EXIT);
}
static void ShowSafariBallsWindow(void)
{
sSafariBallsWindowId = AddWindow(&sWindowTemplate_SafariBalls);
PutWindowTilemap(sSafariBallsWindowId);
DrawStdWindowFrame(sSafariBallsWindowId, FALSE);
ConvertIntToDecimalStringN(gStringVar1, gNumSafariBalls, STR_CONV_MODE_RIGHT_ALIGN, 2);
StringExpandPlaceholders(gStringVar4, gText_SafariBallStock);
AddTextPrinterParameterized(sSafariBallsWindowId, FONT_NORMAL, gStringVar4, 0, 1, TEXT_SKIP_DRAW, NULL);
CopyWindowToVram(sSafariBallsWindowId, COPYWIN_GFX);
}
static void ShowPyramidFloorWindow(void)
{
if (gSaveBlock2Ptr->frontier.curChallengeBattleNum == FRONTIER_STAGES_PER_CHALLENGE)
sBattlePyramidFloorWindowId = AddWindow(&sWindowTemplate_PyramidPeak);
else
sBattlePyramidFloorWindowId = AddWindow(&sWindowTemplate_PyramidFloor);
PutWindowTilemap(sBattlePyramidFloorWindowId);
DrawStdWindowFrame(sBattlePyramidFloorWindowId, FALSE);
StringCopy(gStringVar1, sPyramidFloorNames[gSaveBlock2Ptr->frontier.curChallengeBattleNum]);
StringExpandPlaceholders(gStringVar4, gText_BattlePyramidFloor);
AddTextPrinterParameterized(sBattlePyramidFloorWindowId, FONT_NORMAL, gStringVar4, 0, 1, TEXT_SKIP_DRAW, NULL);
CopyWindowToVram(sBattlePyramidFloorWindowId, COPYWIN_GFX);
}
static void RemoveExtraStartMenuWindows(void)
{
if (GetSafariZoneFlag())
{
ClearStdWindowAndFrameToTransparent(sSafariBallsWindowId, FALSE);
CopyWindowToVram(sSafariBallsWindowId, COPYWIN_GFX);
RemoveWindow(sSafariBallsWindowId);
}
if (InBattlePyramid())
{
ClearStdWindowAndFrameToTransparent(sBattlePyramidFloorWindowId, FALSE);
RemoveWindow(sBattlePyramidFloorWindowId);
}
}
static bool32 PrintStartMenuActions(s8 *pIndex, u32 count)
{
s8 index = *pIndex;
do
{
if (sStartMenuItems[sCurrentStartMenuActions[index]].func.u8_void == StartMenuPlayerNameCallback)
{
PrintPlayerNameOnWindow(GetStartMenuWindowId(), sStartMenuItems[sCurrentStartMenuActions[index]].text, 8, (index << 4) + 9);
}
else
{
StringExpandPlaceholders(gStringVar4, sStartMenuItems[sCurrentStartMenuActions[index]].text);
AddTextPrinterParameterized(GetStartMenuWindowId(), FONT_NORMAL, gStringVar4, 8, (index << 4) + 9, TEXT_SKIP_DRAW, NULL);
}
index++;
if (index >= sNumStartMenuActions)
{
*pIndex = index;
return TRUE;
}
count--;
}
while (count != 0);
*pIndex = index;
return FALSE;
}
static bool32 InitStartMenuStep(void)
{
s8 state = sInitStartMenuData[0];
switch (state)
{
case 0:
sInitStartMenuData[0]++;
break;
case 1:
BuildStartMenuActions();
sInitStartMenuData[0]++;
break;
case 2:
LoadMessageBoxAndBorderGfx();
DrawStdWindowFrame(AddStartMenuWindow(sNumStartMenuActions), FALSE);
sInitStartMenuData[1] = 0;
sInitStartMenuData[0]++;
break;
case 3:
if (GetSafariZoneFlag())
ShowSafariBallsWindow();
if (InBattlePyramid())
ShowPyramidFloorWindow();
sInitStartMenuData[0]++;
break;
case 4:
if (PrintStartMenuActions(&sInitStartMenuData[1], 2))
sInitStartMenuData[0]++;
break;
case 5:
sStartMenuCursorPos = InitMenuNormal(GetStartMenuWindowId(), FONT_NORMAL, 0, 9, 16, sNumStartMenuActions, sStartMenuCursorPos);
CopyWindowToVram(GetStartMenuWindowId(), COPYWIN_MAP);
return TRUE;
}
return FALSE;
}
static void InitStartMenu(void)
{
sInitStartMenuData[0] = 0;
sInitStartMenuData[1] = 0;
while (!InitStartMenuStep())
;
}
static void StartMenuTask(u8 taskId)
{
if (InitStartMenuStep() == TRUE)
SwitchTaskToFollowupFunc(taskId);
}
static void CreateStartMenuTask(TaskFunc followupFunc)
{
u8 taskId;
sInitStartMenuData[0] = 0;
sInitStartMenuData[1] = 0;
taskId = CreateTask(StartMenuTask, 0x50);
SetTaskFuncWithFollowupFunc(taskId, StartMenuTask, followupFunc);
}
static bool8 FieldCB_ReturnToFieldStartMenu(void)
{
if (InitStartMenuStep() == FALSE)
{
return FALSE;
}
ReturnToFieldOpenStartMenu();
return TRUE;
}
void ShowReturnToFieldStartMenu(void)
{
sInitStartMenuData[0] = 0;
sInitStartMenuData[1] = 0;
gFieldCallback2 = FieldCB_ReturnToFieldStartMenu;
}
void Task_ShowStartMenu(u8 taskId)
{
struct Task *task = &gTasks[taskId];
switch(task->data[0])
{
case 0:
if (InUnionRoom() == TRUE)
SetUsingUnionRoomStartMenu();
gMenuCallback = HandleStartMenuInput;
task->data[0]++;
break;
case 1:
if (gMenuCallback() == TRUE)
DestroyTask(taskId);
break;
}
}
void ShowStartMenu(void)
{
if (!IsOverworldLinkActive())
{
FreezeObjectEvents();
PlayerFreeze();
StopPlayerAvatar();
}
CreateStartMenuTask(Task_ShowStartMenu);
LockPlayerFieldControls();
}
static bool8 HandleStartMenuInput(void)
{
if (JOY_NEW(DPAD_UP))
{
PlaySE(SE_SELECT);
sStartMenuCursorPos = Menu_MoveCursor(-1);
}
if (JOY_NEW(DPAD_DOWN))
{
PlaySE(SE_SELECT);
sStartMenuCursorPos = Menu_MoveCursor(1);
}
if (JOY_NEW(A_BUTTON))
{
PlaySE(SE_SELECT);
if (sStartMenuItems[sCurrentStartMenuActions[sStartMenuCursorPos]].func.u8_void == StartMenuPokedexCallback)
{
if (GetNationalPokedexCount(FLAG_GET_SEEN) == 0)
return FALSE;
}
gMenuCallback = sStartMenuItems[sCurrentStartMenuActions[sStartMenuCursorPos]].func.u8_void;
if (gMenuCallback != StartMenuSaveCallback
&& gMenuCallback != StartMenuExitCallback
&& gMenuCallback != StartMenuDebugCallback
&& gMenuCallback != StartMenuSafariZoneRetireCallback
&& gMenuCallback != StartMenuBattlePyramidRetireCallback)
{
FadeScreen(FADE_TO_BLACK, 0);
}
return FALSE;
}
if (JOY_NEW(START_BUTTON | B_BUTTON))
{
RemoveExtraStartMenuWindows();
HideStartMenu();
return TRUE;
}
return FALSE;
}
static bool8 StartMenuPokedexCallback(void)
{
if (!gPaletteFade.active)
{
IncrementGameStat(GAME_STAT_CHECKED_POKEDEX);
PlayRainStoppingSoundEffect();
RemoveExtraStartMenuWindows();
CleanupOverworldWindowsAndTilemaps();
SetMainCallback2(CB2_OpenPokedex);
return TRUE;
}
return FALSE;
}
static bool8 StartMenuPokemonCallback(void)
{
if (!gPaletteFade.active)
{
PlayRainStoppingSoundEffect();
RemoveExtraStartMenuWindows();
CleanupOverworldWindowsAndTilemaps();
SetMainCallback2(CB2_PartyMenuFromStartMenu); // Display party menu
return TRUE;
}
return FALSE;
}
static bool8 StartMenuBagCallback(void)
{
if (!gPaletteFade.active)
{
PlayRainStoppingSoundEffect();
RemoveExtraStartMenuWindows();
CleanupOverworldWindowsAndTilemaps();
SetMainCallback2(CB2_BagMenuFromStartMenu); // Display bag menu
return TRUE;
}
return FALSE;
}
static bool8 StartMenuPokeNavCallback(void)
{
if (!gPaletteFade.active)
{
PlayRainStoppingSoundEffect();
RemoveExtraStartMenuWindows();
CleanupOverworldWindowsAndTilemaps();
SetMainCallback2(CB2_InitPokeNav); // Display PokeNav
return TRUE;
}
return FALSE;
}
static bool8 StartMenuPlayerNameCallback(void)
{
if (!gPaletteFade.active)
{
PlayRainStoppingSoundEffect();
RemoveExtraStartMenuWindows();
CleanupOverworldWindowsAndTilemaps();
if (IsOverworldLinkActive() || InUnionRoom())
ShowPlayerTrainerCard(CB2_ReturnToFieldWithOpenMenu); // Display trainer card
else if (FlagGet(FLAG_SYS_FRONTIER_PASS))
ShowFrontierPass(CB2_ReturnToFieldWithOpenMenu); // Display frontier pass
else
ShowPlayerTrainerCard(CB2_ReturnToFieldWithOpenMenu); // Display trainer card
return TRUE;
}
return FALSE;
}
static bool8 StartMenuSaveCallback(void)
{
if (InBattlePyramid())
RemoveExtraStartMenuWindows();
gMenuCallback = SaveStartCallback; // Display save menu
return FALSE;
}
static bool8 StartMenuOptionCallback(void)
{
if (!gPaletteFade.active)
{
PlayRainStoppingSoundEffect();
RemoveExtraStartMenuWindows();
CleanupOverworldWindowsAndTilemaps();
SetMainCallback2(CB2_InitOptionMenu); // Display option menu
gMain.savedCallback = CB2_ReturnToFieldWithOpenMenu;
return TRUE;
}
return FALSE;
}
static bool8 StartMenuExitCallback(void)
{
RemoveExtraStartMenuWindows();
HideStartMenu(); // Hide start menu
return TRUE;
}
static bool8 StartMenuDebugCallback(void)
{
RemoveExtraStartMenuWindows();
HideStartMenuDebug(); // Hide start menu without enabling movement
#if DEBUG_OVERWORLD_MENU == TRUE
FreezeObjectEvents();
Debug_ShowMainMenu();
#endif
return TRUE;
}
static bool8 StartMenuSafariZoneRetireCallback(void)
{
RemoveExtraStartMenuWindows();
HideStartMenu();
SafariZoneRetirePrompt();
return TRUE;
}
static void HideStartMenuDebug(void)
{
PlaySE(SE_SELECT);
ClearStdWindowAndFrame(GetStartMenuWindowId(), TRUE);
RemoveStartMenuWindow();
}
static bool8 StartMenuLinkModePlayerNameCallback(void)
{
if (!gPaletteFade.active)
{
PlayRainStoppingSoundEffect();
CleanupOverworldWindowsAndTilemaps();
ShowTrainerCardInLink(gLocalLinkPlayerId, CB2_ReturnToFieldWithOpenMenu);
return TRUE;
}
return FALSE;
}
static bool8 StartMenuBattlePyramidRetireCallback(void)
{
gMenuCallback = BattlePyramidRetireStartCallback; // Confirm retire
return FALSE;
}
// Functionally unused
void ShowBattlePyramidStartMenu(void)
{
ClearDialogWindowAndFrameToTransparent(0, FALSE);
ScriptUnfreezeObjectEvents();
CreateStartMenuTask(Task_ShowStartMenu);
LockPlayerFieldControls();
}
static bool8 StartMenuBattlePyramidBagCallback(void)
{
if (!gPaletteFade.active)
{
PlayRainStoppingSoundEffect();
RemoveExtraStartMenuWindows();
CleanupOverworldWindowsAndTilemaps();
SetMainCallback2(CB2_PyramidBagMenuFromStartMenu);
return TRUE;
}
return FALSE;
}
static bool8 SaveStartCallback(void)
{
InitSave();
gMenuCallback = SaveCallback;
return FALSE;
}
static bool8 SaveCallback(void)
{
switch (RunSaveCallback())
{
case SAVE_IN_PROGRESS:
return FALSE;
case SAVE_CANCELED: // Back to start menu
ClearDialogWindowAndFrameToTransparent(0, FALSE);
InitStartMenu();
gMenuCallback = HandleStartMenuInput;
return FALSE;
case SAVE_SUCCESS:
case SAVE_ERROR: // Close start menu
ClearDialogWindowAndFrameToTransparent(0, TRUE);
ScriptUnfreezeObjectEvents();
UnlockPlayerFieldControls();
SoftResetInBattlePyramid();
return TRUE;
}
return FALSE;
}
static bool8 BattlePyramidRetireStartCallback(void)
{
InitBattlePyramidRetire();
gMenuCallback = BattlePyramidRetireCallback;
return FALSE;
}
static bool8 BattlePyramidRetireReturnCallback(void)
{
InitStartMenu();
gMenuCallback = HandleStartMenuInput;
return FALSE;
}
static bool8 BattlePyramidRetireCallback(void)
{
switch (RunSaveCallback())
{
case SAVE_SUCCESS: // No (Stay in battle pyramid)
RemoveExtraStartMenuWindows();
gMenuCallback = BattlePyramidRetireReturnCallback;
return FALSE;
case SAVE_IN_PROGRESS:
return FALSE;
case SAVE_CANCELED: // Yes (Retire from battle pyramid)
ClearDialogWindowAndFrameToTransparent(0, TRUE);
ScriptUnfreezeObjectEvents();
UnlockPlayerFieldControls();
ScriptContext_SetupScript(BattlePyramid_Retire);
return TRUE;
}
return FALSE;
}
static void InitSave(void)
{
SaveMapView();
sSaveDialogCallback = SaveConfirmSaveCallback;
sSavingComplete = FALSE;
}
static u8 RunSaveCallback(void)
{
// True if text is still printing
if (RunTextPrintersAndIsPrinter0Active() == TRUE)
{
return SAVE_IN_PROGRESS;
}
sSavingComplete = FALSE;
return sSaveDialogCallback();
}
void SaveGame(void)
{
InitSave();
CreateTask(SaveGameTask, 0x50);
}
static void ShowSaveMessage(const u8 *message, u8 (*saveCallback)(void))
{
StringExpandPlaceholders(gStringVar4, message);
LoadMessageBoxAndFrameGfx(0, TRUE);
AddTextPrinterForMessage_2(TRUE);
sSavingComplete = TRUE;
sSaveDialogCallback = saveCallback;
}
static void SaveGameTask(u8 taskId)
{
u8 status = RunSaveCallback();
switch (status)
{
case SAVE_CANCELED:
case SAVE_ERROR:
gSpecialVar_Result = 0;
break;
case SAVE_SUCCESS:
gSpecialVar_Result = status;
break;
case SAVE_IN_PROGRESS:
return;
}
DestroyTask(taskId);
ScriptContext_Enable();
}
static void HideSaveMessageWindow(void)
{
ClearDialogWindowAndFrame(0, TRUE);
}
static void HideSaveInfoWindow(void)
{
RemoveSaveInfoWindow();
}
static void SaveStartTimer(void)
{
sSaveDialogTimer = 60;
}
static bool8 SaveSuccesTimer(void)
{
sSaveDialogTimer--;
if (JOY_HELD(A_BUTTON))
{
PlaySE(SE_SELECT);
return TRUE;
}
if (sSaveDialogTimer == 0)
{
return TRUE;
}
return FALSE;
}
static bool8 SaveErrorTimer(void)
{
if (sSaveDialogTimer != 0)
{
sSaveDialogTimer--;
}
else if (JOY_HELD(A_BUTTON))
{
return TRUE;
}
return FALSE;
}
static u8 SaveConfirmSaveCallback(void)
{
ClearStdWindowAndFrame(GetStartMenuWindowId(), FALSE);
RemoveStartMenuWindow();
ShowSaveInfoWindow();
if (InBattlePyramid())
{
ShowSaveMessage(gText_BattlePyramidConfirmRest, SaveYesNoCallback);
}
else
{
ShowSaveMessage(gText_ConfirmSave, SaveYesNoCallback);
}
return SAVE_IN_PROGRESS;
}
static u8 SaveYesNoCallback(void)
{
DisplayYesNoMenuDefaultYes(); // Show Yes/No menu
sSaveDialogCallback = SaveConfirmInputCallback;
return SAVE_IN_PROGRESS;
}
static u8 SaveConfirmInputCallback(void)
{
switch (Menu_ProcessInputNoWrapClearOnChoose())
{
case 0: // Yes
switch (gSaveFileStatus)
{
case SAVE_STATUS_EMPTY:
case SAVE_STATUS_CORRUPT:
if (gDifferentSaveFile == FALSE)
{
sSaveDialogCallback = SaveFileExistsCallback;
return SAVE_IN_PROGRESS;
}
sSaveDialogCallback = SaveSavingMessageCallback;
return SAVE_IN_PROGRESS;
default:
sSaveDialogCallback = SaveFileExistsCallback;
return SAVE_IN_PROGRESS;
}
case MENU_B_PRESSED:
case 1: // No
HideSaveInfoWindow();
HideSaveMessageWindow();
return SAVE_CANCELED;
}
return SAVE_IN_PROGRESS;
}
// A different save file exists
static u8 SaveFileExistsCallback(void)
{
if (gDifferentSaveFile == TRUE)
{
ShowSaveMessage(gText_DifferentSaveFile, SaveConfirmOverwriteDefaultNoCallback);
}
else
{
ShowSaveMessage(gText_AlreadySavedFile, SaveConfirmOverwriteCallback);
}
return SAVE_IN_PROGRESS;
}
static u8 SaveConfirmOverwriteDefaultNoCallback(void)
{
DisplayYesNoMenuWithDefault(1); // Show Yes/No menu (No selected as default)
sSaveDialogCallback = SaveOverwriteInputCallback;
return SAVE_IN_PROGRESS;
}
static u8 SaveConfirmOverwriteCallback(void)
{
DisplayYesNoMenuDefaultYes(); // Show Yes/No menu
sSaveDialogCallback = SaveOverwriteInputCallback;
return SAVE_IN_PROGRESS;
}
static u8 SaveOverwriteInputCallback(void)
{
switch (Menu_ProcessInputNoWrapClearOnChoose())
{
case 0: // Yes
sSaveDialogCallback = SaveSavingMessageCallback;
return SAVE_IN_PROGRESS;
case MENU_B_PRESSED:
case 1: // No
HideSaveInfoWindow();
HideSaveMessageWindow();
return SAVE_CANCELED;
}
return SAVE_IN_PROGRESS;
}
static u8 SaveSavingMessageCallback(void)
{
ShowSaveMessage(gText_SavingDontTurnOff, SaveDoSaveCallback);
return SAVE_IN_PROGRESS;
}
static u8 SaveDoSaveCallback(void)
{
u8 saveStatus;
IncrementGameStat(GAME_STAT_SAVED_GAME);
PausePyramidChallenge();
if (gDifferentSaveFile == TRUE)
{
saveStatus = TrySavingData(SAVE_OVERWRITE_DIFFERENT_FILE);
gDifferentSaveFile = FALSE;
}
else
{
saveStatus = TrySavingData(SAVE_NORMAL);
}
if (saveStatus == SAVE_STATUS_OK)
ShowSaveMessage(gText_PlayerSavedGame, SaveSuccessCallback);
else
ShowSaveMessage(gText_SaveError, SaveErrorCallback);
SaveStartTimer();
return SAVE_IN_PROGRESS;
}
static u8 SaveSuccessCallback(void)
{
if (!IsTextPrinterActive(0))
{
PlaySE(SE_SAVE);
sSaveDialogCallback = SaveReturnSuccessCallback;
}
return SAVE_IN_PROGRESS;
}
static u8 SaveReturnSuccessCallback(void)
{
if (!IsSEPlaying() && SaveSuccesTimer())
{
HideSaveInfoWindow();
return SAVE_SUCCESS;
}
else
{
return SAVE_IN_PROGRESS;
}
}
static u8 SaveErrorCallback(void)
{
if (!IsTextPrinterActive(0))
{
PlaySE(SE_BOO);
sSaveDialogCallback = SaveReturnErrorCallback;
}
return SAVE_IN_PROGRESS;
}
static u8 SaveReturnErrorCallback(void)
{
if (!SaveErrorTimer())
{
return SAVE_IN_PROGRESS;
}
else
{
HideSaveInfoWindow();
return SAVE_ERROR;
}
}
static void InitBattlePyramidRetire(void)
{
sSaveDialogCallback = BattlePyramidConfirmRetireCallback;
sSavingComplete = FALSE;
}
static u8 BattlePyramidConfirmRetireCallback(void)
{
ClearStdWindowAndFrame(GetStartMenuWindowId(), FALSE);
RemoveStartMenuWindow();
ShowSaveMessage(gText_BattlePyramidConfirmRetire, BattlePyramidRetireYesNoCallback);
return SAVE_IN_PROGRESS;
}
static u8 BattlePyramidRetireYesNoCallback(void)
{
DisplayYesNoMenuWithDefault(1); // Show Yes/No menu (No selected as default)
sSaveDialogCallback = BattlePyramidRetireInputCallback;
return SAVE_IN_PROGRESS;
}
static u8 BattlePyramidRetireInputCallback(void)
{
switch (Menu_ProcessInputNoWrapClearOnChoose())
{
case 0: // Yes
return SAVE_CANCELED;
case MENU_B_PRESSED:
case 1: // No
HideSaveMessageWindow();
return SAVE_SUCCESS;
}
return SAVE_IN_PROGRESS;
}
static void VBlankCB_LinkBattleSave(void)
{
TransferPlttBuffer();
}
static bool32 InitSaveWindowAfterLinkBattle(u8 *state)
{
switch (*state)
{
case 0:
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0);
SetVBlankCallback(NULL);
ScanlineEffect_Stop();
DmaClear16(3, PLTT, PLTT_SIZE);
DmaFillLarge16(3, 0, (void *)VRAM, VRAM_SIZE, 0x1000);
break;
case 1:
ResetSpriteData();
ResetTasks();
ResetPaletteFade();
ScanlineEffect_Clear();
break;
case 2:
ResetBgsAndClearDma3BusyFlags(0);
InitBgsFromTemplates(0, sBgTemplates_LinkBattleSave, ARRAY_COUNT(sBgTemplates_LinkBattleSave));
InitWindows(sWindowTemplates_LinkBattleSave);
LoadUserWindowBorderGfx_(0, 8, BG_PLTT_ID(14));
Menu_LoadStdPalAt(BG_PLTT_ID(15));
break;
case 3:
ShowBg(0);
BlendPalettes(PALETTES_ALL, 16, RGB_BLACK);
SetVBlankCallback(VBlankCB_LinkBattleSave);
EnableInterrupts(1);
break;
case 4:
return TRUE;
}
(*state)++;
return FALSE;
}
void CB2_SetUpSaveAfterLinkBattle(void)
{
if (InitSaveWindowAfterLinkBattle(&gMain.state))
{
CreateTask(Task_SaveAfterLinkBattle, 0x50);
SetMainCallback2(CB2_SaveAfterLinkBattle);
}
}
static void CB2_SaveAfterLinkBattle(void)
{
RunTasks();
UpdatePaletteFade();
}
static void Task_SaveAfterLinkBattle(u8 taskId)
{
s16 *state = gTasks[taskId].data;
if (!gPaletteFade.active)
{
switch (*state)
{
case 0:
FillWindowPixelBuffer(0, PIXEL_FILL(1));
AddTextPrinterParameterized2(0,
FONT_NORMAL,
gText_SavingDontTurnOffPower,
TEXT_SKIP_DRAW,
NULL,
TEXT_COLOR_DARK_GRAY,
TEXT_COLOR_WHITE,
TEXT_COLOR_LIGHT_GRAY);
DrawTextBorderOuter(0, 8, 14);
PutWindowTilemap(0);
CopyWindowToVram(0, COPYWIN_FULL);
BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK);
if (gWirelessCommType != 0 && InUnionRoom())
{
if (Link_AnyPartnersPlayingFRLG_JP())
{
*state = 1;
}
else
{
*state = 5;
}
}
else
{
gSoftResetDisabled = TRUE;
*state = 1;
}
break;
case 1:
SetContinueGameWarpStatusToDynamicWarp();
WriteSaveBlock2();
*state = 2;
break;
case 2:
if (WriteSaveBlock1Sector())
{
ClearContinueGameWarpStatus2();
*state = 3;
gSoftResetDisabled = FALSE;
}
break;
case 3:
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK);
*state = 4;
break;
case 4:
FreeAllWindowBuffers();
SetMainCallback2(gMain.savedCallback);
DestroyTask(taskId);
break;
case 5:
CreateTask(Task_LinkFullSave, 5);
*state = 6;
break;
case 6:
if (!FuncIsActiveTask(Task_LinkFullSave))
{
*state = 3;
}
break;
}
}
}
static void ShowSaveInfoWindow(void)
{
struct WindowTemplate saveInfoWindow = sSaveInfoWindowTemplate;
u8 gender;
u8 color;
u32 xOffset;
u32 yOffset;
if (!FlagGet(FLAG_SYS_POKEDEX_GET))
{
saveInfoWindow.height -= 2;
}
sSaveInfoWindowId = AddWindow(&saveInfoWindow);
DrawStdWindowFrame(sSaveInfoWindowId, FALSE);
gender = gSaveBlock2Ptr->playerGender;
color = TEXT_COLOR_RED; // Red when female, blue when male.
if (gender == MALE)
{
color = TEXT_COLOR_BLUE;
}
// Print region name
yOffset = 1;
BufferSaveMenuText(SAVE_MENU_LOCATION, gStringVar4, TEXT_COLOR_GREEN);
AddTextPrinterParameterized(sSaveInfoWindowId, FONT_NORMAL, gStringVar4, 0, yOffset, TEXT_SKIP_DRAW, NULL);
// Print player name
yOffset += 16;
AddTextPrinterParameterized(sSaveInfoWindowId, FONT_NORMAL, gText_SavingPlayer, 0, yOffset, TEXT_SKIP_DRAW, NULL);
BufferSaveMenuText(SAVE_MENU_NAME, gStringVar4, color);
xOffset = GetStringRightAlignXOffset(FONT_NORMAL, gStringVar4, 0x70);
PrintPlayerNameOnWindow(sSaveInfoWindowId, gStringVar4, xOffset, yOffset);
// Print badge count
yOffset += 16;
AddTextPrinterParameterized(sSaveInfoWindowId, FONT_NORMAL, gText_SavingBadges, 0, yOffset, TEXT_SKIP_DRAW, NULL);
BufferSaveMenuText(SAVE_MENU_BADGES, gStringVar4, color);
xOffset = GetStringRightAlignXOffset(FONT_NORMAL, gStringVar4, 0x70);
AddTextPrinterParameterized(sSaveInfoWindowId, FONT_NORMAL, gStringVar4, xOffset, yOffset, TEXT_SKIP_DRAW, NULL);
if (FlagGet(FLAG_SYS_POKEDEX_GET) == TRUE)
{
// Print pokedex count
yOffset += 16;
AddTextPrinterParameterized(sSaveInfoWindowId, FONT_NORMAL, gText_SavingPokedex, 0, yOffset, TEXT_SKIP_DRAW, NULL);
BufferSaveMenuText(SAVE_MENU_CAUGHT, gStringVar4, color);
xOffset = GetStringRightAlignXOffset(FONT_NORMAL, gStringVar4, 0x70);
AddTextPrinterParameterized(sSaveInfoWindowId, FONT_NORMAL, gStringVar4, xOffset, yOffset, TEXT_SKIP_DRAW, NULL);
}
// Print play time
yOffset += 16;
AddTextPrinterParameterized(sSaveInfoWindowId, FONT_NORMAL, gText_SavingTime, 0, yOffset, TEXT_SKIP_DRAW, NULL);
BufferSaveMenuText(SAVE_MENU_PLAY_TIME, gStringVar4, color);
xOffset = GetStringRightAlignXOffset(FONT_NORMAL, gStringVar4, 0x70);
AddTextPrinterParameterized(sSaveInfoWindowId, FONT_NORMAL, gStringVar4, xOffset, yOffset, TEXT_SKIP_DRAW, NULL);
CopyWindowToVram(sSaveInfoWindowId, COPYWIN_GFX);
}
static void RemoveSaveInfoWindow(void)
{
ClearStdWindowAndFrame(sSaveInfoWindowId, FALSE);
RemoveWindow(sSaveInfoWindowId);
}
static void Task_WaitForBattleTowerLinkSave(u8 taskId)
{
if (!FuncIsActiveTask(Task_LinkFullSave))
{
DestroyTask(taskId);
ScriptContext_Enable();
}
}
#define tInBattleTower data[2]
void SaveForBattleTowerLink(void)
{
u8 taskId = CreateTask(Task_LinkFullSave, 5);
gTasks[taskId].tInBattleTower = TRUE;
gTasks[CreateTask(Task_WaitForBattleTowerLinkSave, 6)].data[1] = taskId;
}
#undef tInBattleTower
static void HideStartMenuWindow(void)
{
ClearStdWindowAndFrame(GetStartMenuWindowId(), TRUE);
RemoveStartMenuWindow();
ScriptUnfreezeObjectEvents();
UnlockPlayerFieldControls();
}
void HideStartMenu(void)
{
PlaySE(SE_SELECT);
HideStartMenuWindow();
}
void AppendToList(u8 *list, u8 *pos, u8 newEntry)
{
list[*pos] = newEntry;
(*pos)++;
}