sovereignx/src/save_failed_screen.c

333 lines
10 KiB
C
Raw Normal View History

2017-10-06 23:33:35 +01:00
#include "global.h"
#include "text.h"
#include "main.h"
#include "palette.h"
#include "gpu_regs.h"
#include "bg.h"
#include "task.h"
#include "window.h"
#include "menu.h"
#include "save.h"
#include "gba/flash_internal.h"
#define MSG_WIN_TOP 12
#define CLOCK_WIN_TOP (MSG_WIN_TOP - 4)
extern void AddTextPrinterParametrized2(u8 windowId, u8 fontId, u8 x, u8 y, u8 letterSpacing, u8 lineSpacing, struct TextColor *color, u8 speed, u8 *str);
extern void (*gGameContinueCallback)(void);
extern u32 gDamagedSaveSectors;
2017-10-07 00:48:18 +01:00
extern u16 gSaveFailedType;
extern const u8 gBirchHelpGfx[];
extern const u8 gBirchBagTilemap[];
extern const u8 gBirchGrassTilemap[];
extern const u8 gSaveFailedClockGfx[];
2017-10-06 23:33:35 +01:00
2017-10-07 00:48:18 +01:00
extern const struct OamData gClockOamData; // sClockOamData
extern const u8 gClockFrames[8][3]; // sClockFrames
2017-10-06 23:33:35 +01:00
extern const struct BgTemplate gUnknown_085EFD88[];
extern const struct WindowTemplate gUnknown_085EFD94[];
extern struct WindowTemplate gUnknown_085EFD9C;
extern struct WindowTemplate gUnknown_085EFDA4;
extern struct SaveSection gSaveDataBuffer;
extern const u32 gUnknown_0850E87C[];
2017-10-07 00:48:18 +01:00
extern const u16 gBirchBagGrassPal[];
extern const u16 gSaveFailedClockPal[];
2017-10-06 23:33:35 +01:00
extern const u16 gUnknown_0850FEFC[];
extern const u16 gUnknown_0860F074[];
extern u8 gText_SaveFailedCheckingBackup[];
extern u8 gText_BackupMemoryDamaged[];
extern u8 gText_CheckCompleted[];
extern u8 gText_SaveCompleteGameCannotContinue[];
extern u8 gText_SaveCompletePressA[];
extern u8 gText_GamePlayCannotBeContinued[];
extern u8 gDecompressionBuffer[];
2017-10-07 00:48:18 +01:00
struct ClockInfo
2017-10-06 23:33:35 +01:00
{
2017-10-07 00:48:18 +01:00
bool16 clockRunning;
u16 debugTimer; // appears to be unused; it's only set to 0 and never used within the game. perhaps it was a volatile-like timer expected to be modified by an external tool?
2017-10-06 23:33:35 +01:00
};
2017-10-07 00:48:18 +01:00
extern struct ClockInfo gSaveFailedClockInfo;
2017-10-06 23:33:35 +01:00
2017-10-07 00:48:18 +01:00
struct WindowIds
2017-10-06 23:33:35 +01:00
{
2017-10-07 00:48:18 +01:00
u8 textWindowId;
u8 clockWindowId;
2017-10-06 23:33:35 +01:00
};
2017-10-07 00:48:18 +01:00
extern struct WindowIds gSaveFailedWindowIds;
2017-10-06 23:33:35 +01:00
2017-10-07 00:48:18 +01: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-06 23:33:35 +01:00
2017-10-07 00:48:18 +01:00
// although this is a general text printer, it's only used in this file.
static void SaveFailedScreenTextPrint(u8 *text, u8 var1, u8 var2)
2017-10-06 23:33:35 +01:00
{
struct TextColor color;
color.fgColor = 0;
color.bgColor = 15;
color.shadowColor = 3;
2017-10-07 00:48:18 +01:00
AddTextPrinterParametrized2(gSaveFailedWindowIds.textWindowId, 1, var1 * 8, var2 * 8 + 1, 0, 0, &color, 0, text);
2017-10-06 23:33:35 +01:00
}
void DoSaveFailedScreen(u8 saveType)
{
2017-10-07 00:48:18 +01:00
SetMainCallback2(CB2_SaveFailedScreen);
gSaveFailedType = saveType;
gSaveFailedClockInfo.clockRunning = FALSE;
gSaveFailedClockInfo.debugTimer = 0;
gSaveFailedWindowIds.textWindowId = 0;
gSaveFailedWindowIds.clockWindowId = 0;
2017-10-06 23:33:35 +01:00
}
2017-10-07 00:48:18 +01:00
static void VBlankCB(void)
2017-10-06 23:33:35 +01:00
{
LoadOam();
ProcessSpriteCopyRequests();
TransferPlttBuffer();
}
2017-10-07 00:48:18 +01:00
static void CB2_SaveFailedScreen(void)
2017-10-06 23:33:35 +01:00
{
2017-10-07 00:48:18 +01:00
switch (gMain.state)
2017-10-06 23:33:35 +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);
// how come this doesnt use the Dma manager?
DmaFill16(3, 0, VRAM, VRAM_SIZE);
DmaFill32(3, 0, OAM, OAM_SIZE);
DmaFill16(3, 0, PLTT, PLTT_SIZE);
2017-10-07 00:48:18 +01:00
LZ77UnCompVram(gBirchHelpGfx, (void *)VRAM);
LZ77UnCompVram(gBirchBagTilemap, (void *)(VRAM + 0x7000));
LZ77UnCompVram(gBirchGrassTilemap, (void *)(VRAM + 0x7800));
LZ77UnCompVram(gSaveFailedClockGfx, (void *)(VRAM + 0x10020));
2017-10-06 23:33:35 +01:00
ResetBgsAndClearDma3BusyFlags(0);
InitBgsFromTemplates(0, gUnknown_085EFD88, 3);
SetBgTilemapBuffer(0, (void *)&gDecompressionBuffer[0x2000]);
CpuFill32(0, &gDecompressionBuffer[0x2000], 0x800);
LoadBgTiles(0, gUnknown_0850E87C, 0x120, 0x214);
InitWindows(gUnknown_085EFD94);
// AddWindowWithoutTileMap returns a u16/integer, but the info is clobbered into a u8 here resulting in lost info. Bug?
2017-10-07 00:48:18 +01:00
gSaveFailedWindowIds.textWindowId = AddWindowWithoutTileMap(&gUnknown_085EFD9C);
SetWindowAttribute(gSaveFailedWindowIds.textWindowId, 7, (u32)&gDecompressionBuffer[0x2800]);
gSaveFailedWindowIds.clockWindowId = AddWindowWithoutTileMap(&gUnknown_085EFDA4);
SetWindowAttribute(gSaveFailedWindowIds.clockWindowId, 7, (u32)&gDecompressionBuffer[0x3D00]);
2017-10-06 23:33:35 +01:00
DeactivateAllTextPrinters();
ResetSpriteData();
ResetTasks();
ResetPaletteFade();
2017-10-07 00:48:18 +01:00
LoadPalette(gBirchBagGrassPal, 0, 0x40);
LoadPalette(gSaveFailedClockPal, 0x100, 0x20);
2017-10-06 23:33:35 +01:00
LoadPalette(gUnknown_0850FEFC, 0xE0, 0x20);
LoadPalette(gUnknown_0860F074, 0xF0, 0x20);
2017-10-07 00:48:18 +01:00
SetWindowBorderStyle(gSaveFailedWindowIds.textWindowId, FALSE, 0x214, 0xE);
SetWindowBorderStyle(gSaveFailedWindowIds.clockWindowId, FALSE, 0x214, 0xE);
FillWindowPixelBuffer(gSaveFailedWindowIds.clockWindowId, 0x11); // backwards?
FillWindowPixelBuffer(gSaveFailedWindowIds.textWindowId, 0x11);
CopyWindowToVram(gSaveFailedWindowIds.clockWindowId, 2); // again?
CopyWindowToVram(gSaveFailedWindowIds.textWindowId, 1);
SaveFailedScreenTextPrint(gText_SaveFailedCheckingBackup, 1, 0);
2017-10-06 23:33:35 +01:00
BeginNormalPaletteFade(0xFFFFFFFF, 0, 16, 0, 0);
EnableInterrupts(1);
2017-10-07 00:48:18 +01:00
SetVBlankCallback(VBlankCB);
2017-10-06 23:33:35 +01:00
SetGpuReg(0, 0x1040);
ShowBg(0);
ShowBg(2);
ShowBg(3);
gMain.state++;
break;
case 1:
2017-10-07 00:48:18 +01:00
if (!UpdatePaletteFade())
2017-10-06 23:33:35 +01:00
{
2017-10-07 00:48:18 +01:00
SetMainCallback2(CB2_WipeSave);
SetVBlankCallback(VBlankCB_UpdateClockGraphics);
2017-10-06 23:33:35 +01:00
}
break;
}
}
2017-10-07 00:48:18 +01:00
static void CB2_WipeSave(void)
2017-10-06 23:33:35 +01:00
{
u8 wipeTries = 0;
2017-10-07 00:48:18 +01:00
gSaveFailedClockInfo.clockRunning = TRUE;
2017-10-06 23:33:35 +01:00
while (gDamagedSaveSectors != 0 && wipeTries < 3)
{
2017-10-07 00:48:18 +01:00
if (WipeSectors(gDamagedSaveSectors) != FALSE)
2017-10-06 23:33:35 +01:00
{
2017-10-07 00:48:18 +01:00
FillWindowPixelBuffer(gSaveFailedWindowIds.textWindowId, 0x11);
SaveFailedScreenTextPrint(gText_BackupMemoryDamaged, 1, 0);
SetMainCallback2(CB2_GameplayCannotBeContinued);
2017-10-06 23:33:35 +01:00
return;
}
2017-10-07 00:48:18 +01:00
FillWindowPixelBuffer(gSaveFailedWindowIds.textWindowId, 0x11);
SaveFailedScreenTextPrint(gText_CheckCompleted, 1, 0);
HandleSavingData(gSaveFailedType);
2017-10-06 23:33:35 +01:00
2017-10-07 00:48:18 +01:00
if (gDamagedSaveSectors != 0)
2017-10-06 23:33:35 +01:00
{
2017-10-07 00:48:18 +01:00
FillWindowPixelBuffer(gSaveFailedWindowIds.textWindowId, 0x11);
SaveFailedScreenTextPrint(gText_SaveFailedCheckingBackup, 1, 0);
2017-10-06 23:33:35 +01:00
}
wipeTries++;
}
2017-10-07 00:48:18 +01:00
if (wipeTries == 3)
2017-10-06 23:33:35 +01:00
{
2017-10-07 00:48:18 +01:00
FillWindowPixelBuffer(gSaveFailedWindowIds.textWindowId, 0x11);
SaveFailedScreenTextPrint(gText_BackupMemoryDamaged, 1, 0);
2017-10-06 23:33:35 +01:00
}
else
{
2017-10-07 00:48:18 +01:00
FillWindowPixelBuffer(gSaveFailedWindowIds.textWindowId, 0x11);
2017-10-06 23:33:35 +01:00
2017-10-07 00:48:18 +01:00
if (gGameContinueCallback == NULL)
SaveFailedScreenTextPrint(gText_SaveCompleteGameCannotContinue, 1, 0);
2017-10-06 23:33:35 +01:00
else
2017-10-07 00:48:18 +01:00
SaveFailedScreenTextPrint(gText_SaveCompletePressA, 1, 0);
2017-10-06 23:33:35 +01:00
}
2017-10-07 00:48:18 +01:00
SetMainCallback2(CB2_FadeAndReturnToTitleScreen);
2017-10-06 23:33:35 +01:00
}
2017-10-07 00:48:18 +01:00
static void CB2_GameplayCannotBeContinued(void)
2017-10-06 23:33:35 +01:00
{
2017-10-07 00:48:18 +01:00
gSaveFailedClockInfo.clockRunning = FALSE;
2017-10-06 23:33:35 +01:00
2017-10-07 00:48:18 +01:00
if (gMain.newKeys & A_BUTTON)
2017-10-06 23:33:35 +01:00
{
2017-10-07 00:48:18 +01:00
FillWindowPixelBuffer(gSaveFailedWindowIds.textWindowId, 0x11);
SaveFailedScreenTextPrint(gText_GamePlayCannotBeContinued, 1, 0);
SetVBlankCallback(VBlankCB);
SetMainCallback2(CB2_FadeAndReturnToTitleScreen);
2017-10-06 23:33:35 +01:00
}
}
2017-10-07 00:48:18 +01:00
static void CB2_FadeAndReturnToTitleScreen(void)
2017-10-06 23:33:35 +01:00
{
2017-10-07 00:48:18 +01:00
gSaveFailedClockInfo.clockRunning = FALSE;
2017-10-06 23:33:35 +01:00
2017-10-07 00:48:18 +01:00
if (gMain.newKeys & A_BUTTON)
2017-10-06 23:33:35 +01:00
{
BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, 0);
2017-10-07 00:48:18 +01:00
SetVBlankCallback(VBlankCB);
SetMainCallback2(CB2_ReturnToTitleScreen);
2017-10-06 23:33:35 +01:00
}
}
2017-10-07 00:48:18 +01:00
void CB2_ReturnToTitleScreen(void)
2017-10-06 23:33:35 +01:00
{
2017-10-07 00:48:18 +01:00
if (!UpdatePaletteFade())
2017-10-06 23:33:35 +01:00
{
2017-10-07 00:48:18 +01:00
if (gGameContinueCallback == NULL) // no callback exists, so do a soft reset.
2017-10-06 23:33:35 +01:00
{
DoSoftReset();
}
else
{
SetMainCallback2((MainCallback)gGameContinueCallback);
gGameContinueCallback = NULL;
}
}
}
2017-10-07 00:48:18 +01:00
static void VBlankCB_UpdateClockGraphics(void)
2017-10-06 23:33:35 +01:00
{
unsigned int n = (gMain.vblankCounter2 >> 3) & 7;
2017-10-07 00:48:18 +01:00
gMain.oamBuffer[0] = gClockOamData;
2017-10-06 23:33:35 +01:00
gMain.oamBuffer[0].x = 112;
gMain.oamBuffer[0].y = (CLOCK_WIN_TOP + 1) * 8;;
2017-10-07 00:48:18 +01:00
if (gSaveFailedClockInfo.clockRunning != FALSE)
2017-10-06 23:33:35 +01:00
{
2017-10-07 00:48:18 +01:00
gMain.oamBuffer[0].tileNum = gClockFrames[n][0];
gMain.oamBuffer[0].matrixNum = (gClockFrames[n][2] << 4) | (gClockFrames[n][1] << 3);
2017-10-06 23:33:35 +01:00
}
else
{
gMain.oamBuffer[0].tileNum = 1;
}
CpuFastCopy(gMain.oamBuffer, (void *)OAM, 4);
2017-10-07 00:48:18 +01:00
if (gSaveFailedClockInfo.debugTimer)
gSaveFailedClockInfo.debugTimer--;
2017-10-06 23:33:35 +01:00
}
2017-10-07 00:48:18 +01:00
static bool8 VerifySectorWipe(u16 sector)
2017-10-06 23:33:35 +01:00
{
u32 *ptr = (u32 *)&gSaveDataBuffer;
u16 i;
ReadFlash(sector, 0, (u8 *)ptr, 4096);
for (i = 0; i < 0x400; i++, ptr++)
if (*ptr)
return TRUE;
return FALSE;
}
2017-10-07 00:48:18 +01:00
static bool8 WipeSector(u16 sector)
2017-10-06 23:33:35 +01:00
{
u16 i, j;
bool8 failed = TRUE;
for (i = 0; failed && i < 130; i++)
{
for (j = 0; j < 0x1000; j++)
ProgramFlashByte(sector, j, 0);
2017-10-07 00:48:18 +01:00
failed = VerifySectorWipe(sector);
2017-10-06 23:33:35 +01:00
}
return failed;
}
2017-10-07 00:48:18 +01:00
static bool8 WipeSectors(u32 sectorBits)
2017-10-06 23:33:35 +01:00
{
u16 i;
for (i = 0; i < 0x20; i++)
2017-10-07 00:48:18 +01:00
if ((sectorBits & (1 << i)) && !WipeSector(i))
2017-10-06 23:33:35 +01:00
sectorBits &= ~(1 << i);
if (sectorBits == 0)
return FALSE;
else
return TRUE;
}