pokeemerald/src/save_failed_screen.c

404 lines
11 KiB
C
Raw Normal View History

2017-10-07 00:33:35 +02:00
#include "global.h"
#include "text.h"
#include "main.h"
#include "palette.h"
2018-10-21 09:24:57 +02:00
#include "graphics.h"
2017-10-07 00:33:35 +02:00
#include "gpu_regs.h"
#include "bg.h"
#include "decompress.h"
2017-10-07 00:33:35 +02:00
#include "task.h"
#include "window.h"
#include "menu.h"
#include "save.h"
2018-10-21 09:24:57 +02:00
#include "starter_choose.h"
2017-10-07 00:33:35 +02:00
#include "gba/flash_internal.h"
2018-01-21 13:32:11 +01:00
#include "text_window.h"
2018-11-18 20:09:11 +01:00
#include "constants/rgb.h"
2017-10-07 00:33:35 +02:00
#define MSG_WIN_TOP 12
#define CLOCK_WIN_TOP (MSG_WIN_TOP - 4)
2018-11-18 19:37:18 +01:00
extern const u8 gText_SaveFailedCheckingBackup[];
extern const u8 gText_BackupMemoryDamaged[];
extern const u8 gText_CheckCompleted[];
extern const u8 gText_SaveCompleteGameCannotContinue[];
extern const u8 gText_SaveCompletePressA[];
extern const u8 gText_GamePlayCannotBeContinued[];
2017-10-07 00:33:35 +02:00
2021-02-24 20:53:32 +01:00
// sClockInfo enum
2017-10-07 02:26:53 +02:00
enum
2017-10-07 00:33:35 +02:00
{
2017-10-07 02:26:53 +02:00
CLOCK_RUNNING,
DEBUG_TIMER
2017-10-07 00:33:35 +02:00
};
2021-02-24 20:53:32 +01:00
// sWindowIds enum
2017-10-07 02:26:53 +02:00
enum
2017-10-07 00:33:35 +02:00
{
2017-10-07 02:26:53 +02:00
TEXT_WIN_ID,
CLOCK_WIN_ID
2017-10-07 00:33:35 +02:00
};
2021-02-24 20:53:32 +01:00
static EWRAM_DATA u16 sSaveFailedType = {0};
static EWRAM_DATA u16 sClockInfo[2] = {0};
static EWRAM_DATA u8 sUnused1[12] = {0};
static EWRAM_DATA u8 sWindowIds[2] = {0};
static EWRAM_DATA u8 sUnused2[4] = {0};
2017-10-07 00:33:35 +02:00
2017-10-07 03:59:47 +02:00
static const struct OamData sClockOamData =
{
2021-04-15 08:04:01 +02:00
.y = DISPLAY_HEIGHT,
.affineMode = ST_OAM_AFFINE_OFF,
.objMode = ST_OAM_OBJ_NORMAL,
2022-07-30 03:27:39 +02:00
.mosaic = FALSE,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(16x16),
.x = 0,
.matrixNum = 0,
.size = SPRITE_SIZE(16x16),
.tileNum = 0,
.priority = 0,
.paletteNum = 0,
.affineParam = 0
2017-10-07 03:59:47 +02:00
};
static const struct BgTemplate sBgTemplates[3] =
2017-10-07 03:59:47 +02:00
{
{
.bg = 0,
.charBaseIndex = 2,
.mapBaseIndex = 31,
.screenSize = 0,
.paletteMode = 0,
.priority = 0,
.baseTile = 0,
},
{
.bg = 2,
.charBaseIndex = 0,
.mapBaseIndex = 14,
.screenSize = 0,
.paletteMode = 0,
.priority = 2,
.baseTile = 0,
},
{
.bg = 3,
.charBaseIndex = 0,
.mapBaseIndex = 15,
.screenSize = 0,
.paletteMode = 0,
.priority = 3,
.baseTile = 0,
},
};
2021-02-24 20:53:32 +01:00
static const struct WindowTemplate sDummyWindowTemplate[] = { DUMMY_WIN_TEMPLATE };
2017-10-07 03:59:47 +02:00
2021-02-24 20:53:32 +01:00
static const struct WindowTemplate sWindowTemplate_Text[] =
2017-10-07 03:59:47 +02:00
{
{
2018-10-27 00:53:07 +02:00
.bg = 0,
2017-10-07 03:59:47 +02:00
.tilemapLeft = 1,
.tilemapTop = 13,
.width = 28,
.height = 6,
2022-08-19 17:32:00 +02:00
.paletteNum = 15,
2017-10-07 03:59:47 +02:00
.baseBlock = 1,
}
};
2021-02-24 20:53:32 +01:00
static const struct WindowTemplate sWindowTemplate_Clock[] =
2017-10-07 03:59:47 +02:00
{
{
2018-10-27 00:53:07 +02:00
.bg = 0,
2017-10-07 03:59:47 +02:00
.tilemapLeft = 14,
.tilemapTop = 9,
.width = 2,
.height = 2,
2022-08-19 17:32:00 +02:00
.paletteNum = 15,
2017-10-07 03:59:47 +02:00
.baseBlock = 169,
}
};
static const u8 sClockFrames[8][3] =
{
{ 1, 0, 0 },
{ 5, 0, 0 },
{ 9, 0, 0 },
{ 5, 0, 1 },
{ 1, 0, 1 },
{ 5, 1, 1 },
{ 9, 1, 0 },
{ 5, 1, 0 },
};
2017-12-17 23:45:27 +01:00
static const u8 sSaveFailedClockPal[] = INCBIN_U8("graphics/misc/clock_small.gbapal");
2018-10-21 09:24:57 +02:00
static const u32 sSaveFailedClockGfx[] = INCBIN_U32("graphics/misc/clock_small.4bpp.lz");
2017-10-07 03:59:47 +02:00
2017-10-07 01:48:18 +02:00
static void CB2_SaveFailedScreen(void);
static void CB2_WipeSave(void);
static void CB2_GameplayCannotBeContinued(void);
static void CB2_FadeAndReturnToTitleScreen(void);
static void CB2_ReturnToTitleScreen(void);
static void VBlankCB_UpdateClockGraphics(void);
static bool8 VerifySectorWipe(u16 sector);
static bool8 WipeSectors(u32);
2017-10-07 00:33:35 +02:00
2018-11-18 19:37:18 +01:00
// Although this is a general text printer, it's only used in this file.
2021-02-24 20:53:32 +01:00
static void SaveFailedScreenTextPrint(const u8 *text, u8 x, u8 y)
2017-10-07 00:33:35 +02:00
{
2018-02-07 03:37:54 +01:00
u8 color[3];
2017-10-07 00:33:35 +02:00
2021-02-24 20:53:32 +01:00
color[0] = TEXT_COLOR_TRANSPARENT;
color[1] = TEXT_DYNAMIC_COLOR_6;
2021-04-10 04:39:34 +02:00
color[2] = TEXT_COLOR_LIGHT_GRAY;
2021-10-30 22:47:37 +02:00
AddTextPrinterParameterized4(sWindowIds[TEXT_WIN_ID], FONT_NORMAL, x * 8, y * 8 + 1, 0, 0, color, 0, text);
2017-10-07 00:33:35 +02:00
}
void DoSaveFailedScreen(u8 saveType)
{
2017-10-07 01:48:18 +02:00
SetMainCallback2(CB2_SaveFailedScreen);
2021-02-24 20:53:32 +01:00
sSaveFailedType = saveType;
sClockInfo[CLOCK_RUNNING] = FALSE;
sClockInfo[DEBUG_TIMER] = 0;
sWindowIds[TEXT_WIN_ID] = 0;
sWindowIds[CLOCK_WIN_ID] = 0;
2017-10-07 00:33:35 +02:00
}
2017-10-07 01:48:18 +02:00
static void VBlankCB(void)
2017-10-07 00:33:35 +02:00
{
LoadOam();
ProcessSpriteCopyRequests();
TransferPlttBuffer();
}
2017-10-07 01:48:18 +02:00
static void CB2_SaveFailedScreen(void)
2017-10-07 00:33:35 +02:00
{
2017-10-07 01:48:18 +02:00
switch (gMain.state)
2017-10-07 00:33:35 +02:00
{
2018-11-18 19:37:18 +01:00
case 0:
default:
SetVBlankCallback(NULL);
SetGpuReg(REG_OFFSET_DISPCNT, 0);
SetGpuReg(REG_OFFSET_BG3CNT, 0);
SetGpuReg(REG_OFFSET_BG2CNT, 0);
SetGpuReg(REG_OFFSET_BG1CNT, 0);
SetGpuReg(REG_OFFSET_BG0CNT, 0);
SetGpuReg(REG_OFFSET_BG3HOFS, 0);
SetGpuReg(REG_OFFSET_BG3VOFS, 0);
SetGpuReg(REG_OFFSET_BG2HOFS, 0);
SetGpuReg(REG_OFFSET_BG2VOFS, 0);
SetGpuReg(REG_OFFSET_BG1HOFS, 0);
SetGpuReg(REG_OFFSET_BG1VOFS, 0);
SetGpuReg(REG_OFFSET_BG0HOFS, 0);
SetGpuReg(REG_OFFSET_BG0VOFS, 0);
DmaFill16(3, 0, VRAM, VRAM_SIZE);
DmaFill32(3, 0, OAM, OAM_SIZE);
DmaFill16(3, 0, PLTT, PLTT_SIZE);
LZ77UnCompVram(gBirchBagGrass_Gfx, (void *)VRAM);
LZ77UnCompVram(gBirchBagTilemap, (void *)(BG_SCREEN_ADDR(14)));
LZ77UnCompVram(gBirchGrassTilemap, (void *)(BG_SCREEN_ADDR(15)));
2021-02-24 20:53:32 +01:00
LZ77UnCompVram(sSaveFailedClockGfx, (void *)(OBJ_VRAM0 + 0x20));
2018-11-18 19:37:18 +01:00
ResetBgsAndClearDma3BusyFlags(0);
InitBgsFromTemplates(0, sBgTemplates, ARRAY_COUNT(sBgTemplates));
2018-11-18 19:37:18 +01:00
SetBgTilemapBuffer(0, (void *)&gDecompressionBuffer[0x2000]);
CpuFill32(0, &gDecompressionBuffer[0x2000], 0x800);
LoadBgTiles(0, gTextWindowFrame1_Gfx, 0x120, 0x214);
2021-02-24 20:53:32 +01:00
InitWindows(sDummyWindowTemplate);
sWindowIds[TEXT_WIN_ID] = AddWindowWithoutTileMap(sWindowTemplate_Text);
SetWindowAttribute(sWindowIds[TEXT_WIN_ID], 7, (u32)&gDecompressionBuffer[0x2800]);
sWindowIds[CLOCK_WIN_ID] = AddWindowWithoutTileMap(sWindowTemplate_Clock);
SetWindowAttribute(sWindowIds[CLOCK_WIN_ID], 7, (u32)&gDecompressionBuffer[0x3D00]);
2018-11-18 19:37:18 +01:00
DeactivateAllTextPrinters();
ResetSpriteData();
ResetTasks();
ResetPaletteFade();
LoadPalette(gBirchBagGrass_Pal, BG_PLTT_ID(0), 2 * PLTT_SIZE_4BPP);
2022-08-19 17:32:00 +02:00
LoadPalette(sSaveFailedClockPal, OBJ_PLTT_ID(0), PLTT_SIZE_4BPP);
LoadPalette(gTextWindowFrame1_Pal, BG_PLTT_ID(14), PLTT_SIZE_4BPP);
LoadPalette(gStandardMenuPalette, BG_PLTT_ID(15), PLTT_SIZE_4BPP);
2021-02-24 20:53:32 +01:00
DrawStdFrameWithCustomTileAndPalette(sWindowIds[TEXT_WIN_ID], FALSE, 0x214, 0xE);
DrawStdFrameWithCustomTileAndPalette(sWindowIds[CLOCK_WIN_ID], FALSE, 0x214, 0xE);
FillWindowPixelBuffer(sWindowIds[CLOCK_WIN_ID], PIXEL_FILL(1)); // backwards?
FillWindowPixelBuffer(sWindowIds[TEXT_WIN_ID], PIXEL_FILL(1));
2021-11-03 20:29:18 +01:00
CopyWindowToVram(sWindowIds[CLOCK_WIN_ID], COPYWIN_GFX); // again?
CopyWindowToVram(sWindowIds[TEXT_WIN_ID], COPYWIN_MAP);
2018-11-18 19:37:18 +01:00
SaveFailedScreenTextPrint(gText_SaveFailedCheckingBackup, 1, 0);
2021-02-24 17:01:02 +01:00
BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK);
2018-11-18 19:37:18 +01:00
EnableInterrupts(1);
SetVBlankCallback(VBlankCB);
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP);
ShowBg(0);
ShowBg(2);
ShowBg(3);
gMain.state++;
break;
case 1:
if (!UpdatePaletteFade())
{
SetMainCallback2(CB2_WipeSave);
SetVBlankCallback(VBlankCB_UpdateClockGraphics);
}
break;
2017-10-07 00:33:35 +02:00
}
}
2017-10-07 01:48:18 +02:00
static void CB2_WipeSave(void)
2017-10-07 00:33:35 +02:00
{
u8 wipeTries = 0;
2021-02-24 20:53:32 +01:00
sClockInfo[CLOCK_RUNNING] = TRUE;
2017-10-07 00:33:35 +02:00
while (gDamagedSaveSectors != 0 && wipeTries < 3)
{
2021-02-24 20:53:32 +01:00
if (WipeSectors(gDamagedSaveSectors))
2017-10-07 00:33:35 +02:00
{
2021-02-24 20:53:32 +01:00
FillWindowPixelBuffer(sWindowIds[TEXT_WIN_ID], PIXEL_FILL(1));
2017-10-07 01:48:18 +02:00
SaveFailedScreenTextPrint(gText_BackupMemoryDamaged, 1, 0);
SetMainCallback2(CB2_GameplayCannotBeContinued);
2017-10-07 00:33:35 +02:00
return;
}
2021-02-24 20:53:32 +01:00
FillWindowPixelBuffer(sWindowIds[TEXT_WIN_ID], PIXEL_FILL(1));
2017-10-07 01:48:18 +02:00
SaveFailedScreenTextPrint(gText_CheckCompleted, 1, 0);
2021-02-24 20:53:32 +01:00
HandleSavingData(sSaveFailedType);
2017-10-07 00:33:35 +02:00
2017-10-07 01:48:18 +02:00
if (gDamagedSaveSectors != 0)
2017-10-07 00:33:35 +02:00
{
2021-02-24 20:53:32 +01:00
FillWindowPixelBuffer(sWindowIds[TEXT_WIN_ID], PIXEL_FILL(1));
2017-10-07 01:48:18 +02:00
SaveFailedScreenTextPrint(gText_SaveFailedCheckingBackup, 1, 0);
2017-10-07 00:33:35 +02:00
}
wipeTries++;
}
2017-10-07 01:48:18 +02:00
if (wipeTries == 3)
2017-10-07 00:33:35 +02:00
{
2021-02-24 20:53:32 +01:00
FillWindowPixelBuffer(sWindowIds[TEXT_WIN_ID], PIXEL_FILL(1));
2017-10-07 01:48:18 +02:00
SaveFailedScreenTextPrint(gText_BackupMemoryDamaged, 1, 0);
2017-10-07 00:33:35 +02:00
}
else
{
2021-02-24 20:53:32 +01:00
FillWindowPixelBuffer(sWindowIds[TEXT_WIN_ID], PIXEL_FILL(1));
2017-10-07 00:33:35 +02:00
2017-10-07 01:48:18 +02:00
if (gGameContinueCallback == NULL)
SaveFailedScreenTextPrint(gText_SaveCompleteGameCannotContinue, 1, 0);
2017-10-07 00:33:35 +02:00
else
2017-10-07 01:48:18 +02:00
SaveFailedScreenTextPrint(gText_SaveCompletePressA, 1, 0);
2017-10-07 00:33:35 +02:00
}
2017-10-07 01:48:18 +02:00
SetMainCallback2(CB2_FadeAndReturnToTitleScreen);
2017-10-07 00:33:35 +02:00
}
2017-10-07 01:48:18 +02:00
static void CB2_GameplayCannotBeContinued(void)
2017-10-07 00:33:35 +02:00
{
2021-02-24 20:53:32 +01:00
sClockInfo[CLOCK_RUNNING] = FALSE;
2017-10-07 00:33:35 +02:00
2020-09-05 03:11:55 +02:00
if (JOY_NEW(A_BUTTON))
2017-10-07 00:33:35 +02:00
{
2021-02-24 20:53:32 +01:00
FillWindowPixelBuffer(sWindowIds[TEXT_WIN_ID], PIXEL_FILL(1));
2017-10-07 01:48:18 +02:00
SaveFailedScreenTextPrint(gText_GamePlayCannotBeContinued, 1, 0);
SetVBlankCallback(VBlankCB);
SetMainCallback2(CB2_FadeAndReturnToTitleScreen);
2017-10-07 00:33:35 +02:00
}
}
2017-10-07 01:48:18 +02:00
static void CB2_FadeAndReturnToTitleScreen(void)
2017-10-07 00:33:35 +02:00
{
2021-02-24 20:53:32 +01:00
sClockInfo[CLOCK_RUNNING] = FALSE;
2017-10-07 00:33:35 +02:00
2020-09-05 03:11:55 +02:00
if (JOY_NEW(A_BUTTON))
2017-10-07 00:33:35 +02:00
{
2021-02-24 17:01:02 +01:00
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK);
2017-10-07 01:48:18 +02:00
SetVBlankCallback(VBlankCB);
SetMainCallback2(CB2_ReturnToTitleScreen);
2017-10-07 00:33:35 +02:00
}
}
2017-10-07 02:35:29 +02:00
static void CB2_ReturnToTitleScreen(void)
2017-10-07 00:33:35 +02:00
{
2017-10-07 01:48:18 +02:00
if (!UpdatePaletteFade())
2017-10-07 00:33:35 +02:00
{
2017-10-07 01:48:18 +02:00
if (gGameContinueCallback == NULL) // no callback exists, so do a soft reset.
2017-10-07 00:33:35 +02:00
{
DoSoftReset();
}
else
{
SetMainCallback2((MainCallback)gGameContinueCallback);
gGameContinueCallback = NULL;
}
}
}
2017-10-07 01:48:18 +02:00
static void VBlankCB_UpdateClockGraphics(void)
2017-10-07 00:33:35 +02:00
{
2018-11-18 19:37:18 +01:00
u32 n = (gMain.vblankCounter2 >> 3) & 7;
2017-10-07 00:33:35 +02:00
2017-10-07 03:59:47 +02:00
gMain.oamBuffer[0] = sClockOamData;
2017-10-07 00:33:35 +02:00
gMain.oamBuffer[0].x = 112;
2020-07-28 01:17:34 +02:00
gMain.oamBuffer[0].y = (CLOCK_WIN_TOP + 1) * 8;
2017-10-07 00:33:35 +02:00
2021-02-24 20:53:32 +01:00
if (sClockInfo[CLOCK_RUNNING])
2017-10-07 00:33:35 +02:00
{
2017-10-07 03:59:47 +02:00
gMain.oamBuffer[0].tileNum = sClockFrames[n][0];
gMain.oamBuffer[0].matrixNum = (sClockFrames[n][2] << 4) | (sClockFrames[n][1] << 3);
2017-10-07 00:33:35 +02:00
}
else
{
gMain.oamBuffer[0].tileNum = 1;
}
CpuFastCopy(gMain.oamBuffer, (void *)OAM, 4);
2021-02-24 20:53:32 +01:00
if (sClockInfo[DEBUG_TIMER])
sClockInfo[DEBUG_TIMER]--;
2017-10-07 00:33:35 +02:00
}
2017-10-07 01:48:18 +02:00
static bool8 VerifySectorWipe(u16 sector)
2017-10-07 00:33:35 +02:00
{
u32 *ptr = (u32 *)&gSaveDataBuffer;
u16 i;
2021-02-24 20:53:32 +01:00
ReadFlash(sector, 0, (u8 *)ptr, SECTOR_SIZE);
2017-10-07 00:33:35 +02:00
2021-10-29 04:54:41 +02:00
// 1/4 because ptr is u32
for (i = 0; i < SECTOR_SIZE / 4; i++, ptr++)
2017-10-07 00:33:35 +02:00
if (*ptr)
2021-10-29 04:54:41 +02:00
return TRUE; // Sector has nonzero data, failed
2017-10-07 00:33:35 +02:00
return FALSE;
}
2017-10-07 01:48:18 +02:00
static bool8 WipeSector(u16 sector)
2017-10-07 00:33:35 +02:00
{
u16 i, j;
bool8 failed = TRUE;
2021-10-29 04:54:41 +02:00
// Attempt to wipe sector with an arbitrary attempt limit of 130
2017-10-07 00:33:35 +02:00
for (i = 0; failed && i < 130; i++)
{
2021-02-24 20:53:32 +01:00
for (j = 0; j < SECTOR_SIZE; j++)
2017-10-07 00:33:35 +02:00
ProgramFlashByte(sector, j, 0);
2017-10-07 01:48:18 +02:00
failed = VerifySectorWipe(sector);
2017-10-07 00:33:35 +02:00
}
return failed;
}
2017-10-07 01:48:18 +02:00
static bool8 WipeSectors(u32 sectorBits)
2017-10-07 00:33:35 +02:00
{
u16 i;
2021-02-24 20:53:32 +01:00
for (i = 0; i < SECTORS_COUNT; i++)
2017-10-07 01:48:18 +02:00
if ((sectorBits & (1 << i)) && !WipeSector(i))
2017-10-07 00:33:35 +02:00
sectorBits &= ~(1 << i);
if (sectorBits == 0)
return FALSE;
else
return TRUE;
}