mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-11-17 20:17:38 +01:00
427 lines
12 KiB
C
Executable File
427 lines
12 KiB
C
Executable File
#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, s8 speed, u8 *str);
|
|
|
|
extern void (*gGameContinueCallback)(void);
|
|
|
|
extern u32 gDamagedSaveSectors;
|
|
|
|
extern const u8 gBirchHelpGfx[];
|
|
extern const u8 gBirchBagTilemap[];
|
|
extern const u8 gBirchGrassTilemap[];
|
|
extern const u16 gBirchBagGrassPal[];
|
|
extern const u16 gUnknown_0850FEFC[];
|
|
extern const u16 gUnknown_0860F074[];
|
|
extern const u32 gUnknown_0850E87C[];
|
|
extern struct SaveSection gSaveDataBuffer;
|
|
|
|
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[];
|
|
|
|
// gSaveFailedClockInfo enum
|
|
enum
|
|
{
|
|
CLOCK_RUNNING,
|
|
DEBUG_TIMER
|
|
};
|
|
|
|
// gSaveFailedWindowIds enum
|
|
enum
|
|
{
|
|
TEXT_WIN_ID,
|
|
CLOCK_WIN_ID
|
|
};
|
|
|
|
EWRAM_DATA u16 gSaveFailedType = {0};
|
|
EWRAM_DATA u16 gSaveFailedClockInfo[2] = {0};
|
|
EWRAM_DATA u8 gSaveFailedUnused1[12] = {0};
|
|
EWRAM_DATA u8 gSaveFailedWindowIds[2] = {0};
|
|
EWRAM_DATA u8 gSaveFailedUnused2[4] = {0};
|
|
|
|
static const struct OamData sClockOamData =
|
|
{
|
|
160, // Y
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
0
|
|
};
|
|
|
|
static const struct BgTemplate gUnknown_085EFD88[3] =
|
|
{
|
|
{
|
|
.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,
|
|
},
|
|
};
|
|
|
|
static const struct WindowTemplate gUnknown_085EFD94[] =
|
|
{
|
|
{
|
|
.priority = 255,
|
|
.tilemapLeft = 0,
|
|
.tilemapTop = 0,
|
|
.width = 0,
|
|
.height = 0,
|
|
.paletteNum = 0,
|
|
.baseBlock = 0,
|
|
}
|
|
};
|
|
|
|
static const struct WindowTemplate gUnknown_085EFD9C[] =
|
|
{
|
|
{
|
|
.priority = 0,
|
|
.tilemapLeft = 1,
|
|
.tilemapTop = 13,
|
|
.width = 28,
|
|
.height = 6,
|
|
.paletteNum = 15,
|
|
.baseBlock = 1,
|
|
}
|
|
};
|
|
|
|
static const struct WindowTemplate gUnknown_085EFDA4[] =
|
|
{
|
|
{
|
|
.priority = 0,
|
|
.tilemapLeft = 14,
|
|
.tilemapTop = 9,
|
|
.width = 2,
|
|
.height = 2,
|
|
.paletteNum = 15,
|
|
.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 },
|
|
};
|
|
|
|
static const u8 gSaveFailedClockPal[] = INCBIN_U8("graphics/misc/clock_small.gbapal");
|
|
static const u8 gSaveFailedClockGfx[] = INCBIN_U8("graphics/misc/clock_small.4bpp.lz");
|
|
|
|
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);
|
|
|
|
// although this is a general text printer, it's only used in this file.
|
|
static void SaveFailedScreenTextPrint(u8 *text, u8 var1, u8 var2)
|
|
{
|
|
struct TextColor color;
|
|
|
|
color.fgColor = 0;
|
|
color.bgColor = 15;
|
|
color.shadowColor = 3;
|
|
AddTextPrinterParametrized2(gSaveFailedWindowIds[TEXT_WIN_ID], 1, var1 * 8, var2 * 8 + 1, 0, 0, &color, 0, text);
|
|
}
|
|
|
|
void DoSaveFailedScreen(u8 saveType)
|
|
{
|
|
SetMainCallback2(CB2_SaveFailedScreen);
|
|
gSaveFailedType = saveType;
|
|
gSaveFailedClockInfo[CLOCK_RUNNING] = FALSE;
|
|
gSaveFailedClockInfo[DEBUG_TIMER] = 0;
|
|
gSaveFailedWindowIds[TEXT_WIN_ID] = 0;
|
|
gSaveFailedWindowIds[CLOCK_WIN_ID] = 0;
|
|
}
|
|
|
|
static void VBlankCB(void)
|
|
{
|
|
LoadOam();
|
|
ProcessSpriteCopyRequests();
|
|
TransferPlttBuffer();
|
|
}
|
|
|
|
static void CB2_SaveFailedScreen(void)
|
|
{
|
|
switch (gMain.state)
|
|
{
|
|
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);
|
|
LZ77UnCompVram(gBirchHelpGfx, (void *)VRAM);
|
|
LZ77UnCompVram(gBirchBagTilemap, (void *)(VRAM + 0x7000));
|
|
LZ77UnCompVram(gBirchGrassTilemap, (void *)(VRAM + 0x7800));
|
|
LZ77UnCompVram(gSaveFailedClockGfx, (void *)(VRAM + 0x10020));
|
|
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?
|
|
gSaveFailedWindowIds[TEXT_WIN_ID] = AddWindowWithoutTileMap(gUnknown_085EFD9C);
|
|
SetWindowAttribute(gSaveFailedWindowIds[TEXT_WIN_ID], 7, (u32)&gDecompressionBuffer[0x2800]);
|
|
gSaveFailedWindowIds[CLOCK_WIN_ID] = AddWindowWithoutTileMap(gUnknown_085EFDA4);
|
|
SetWindowAttribute(gSaveFailedWindowIds[CLOCK_WIN_ID], 7, (u32)&gDecompressionBuffer[0x3D00]);
|
|
DeactivateAllTextPrinters();
|
|
ResetSpriteData();
|
|
ResetTasks();
|
|
ResetPaletteFade();
|
|
LoadPalette(gBirchBagGrassPal, 0, 0x40);
|
|
LoadPalette(gSaveFailedClockPal, 0x100, 0x20);
|
|
LoadPalette(gUnknown_0850FEFC, 0xE0, 0x20);
|
|
LoadPalette(gUnknown_0860F074, 0xF0, 0x20);
|
|
SetWindowBorderStyle(gSaveFailedWindowIds[TEXT_WIN_ID], FALSE, 0x214, 0xE);
|
|
SetWindowBorderStyle(gSaveFailedWindowIds[CLOCK_WIN_ID], FALSE, 0x214, 0xE);
|
|
FillWindowPixelBuffer(gSaveFailedWindowIds[CLOCK_WIN_ID], 0x11); // backwards?
|
|
FillWindowPixelBuffer(gSaveFailedWindowIds[TEXT_WIN_ID], 0x11);
|
|
CopyWindowToVram(gSaveFailedWindowIds[CLOCK_WIN_ID], 2); // again?
|
|
CopyWindowToVram(gSaveFailedWindowIds[TEXT_WIN_ID], 1);
|
|
SaveFailedScreenTextPrint(gText_SaveFailedCheckingBackup, 1, 0);
|
|
BeginNormalPaletteFade(0xFFFFFFFF, 0, 16, 0, 0);
|
|
EnableInterrupts(1);
|
|
SetVBlankCallback(VBlankCB);
|
|
SetGpuReg(0, 0x1040);
|
|
ShowBg(0);
|
|
ShowBg(2);
|
|
ShowBg(3);
|
|
gMain.state++;
|
|
break;
|
|
case 1:
|
|
if (!UpdatePaletteFade())
|
|
{
|
|
SetMainCallback2(CB2_WipeSave);
|
|
SetVBlankCallback(VBlankCB_UpdateClockGraphics);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void CB2_WipeSave(void)
|
|
{
|
|
u8 wipeTries = 0;
|
|
|
|
gSaveFailedClockInfo[CLOCK_RUNNING] = TRUE;
|
|
|
|
while (gDamagedSaveSectors != 0 && wipeTries < 3)
|
|
{
|
|
if (WipeSectors(gDamagedSaveSectors) != FALSE)
|
|
{
|
|
FillWindowPixelBuffer(gSaveFailedWindowIds[TEXT_WIN_ID], 0x11);
|
|
SaveFailedScreenTextPrint(gText_BackupMemoryDamaged, 1, 0);
|
|
SetMainCallback2(CB2_GameplayCannotBeContinued);
|
|
return;
|
|
}
|
|
|
|
FillWindowPixelBuffer(gSaveFailedWindowIds[TEXT_WIN_ID], 0x11);
|
|
SaveFailedScreenTextPrint(gText_CheckCompleted, 1, 0);
|
|
HandleSavingData(gSaveFailedType);
|
|
|
|
if (gDamagedSaveSectors != 0)
|
|
{
|
|
FillWindowPixelBuffer(gSaveFailedWindowIds[TEXT_WIN_ID], 0x11);
|
|
SaveFailedScreenTextPrint(gText_SaveFailedCheckingBackup, 1, 0);
|
|
}
|
|
|
|
wipeTries++;
|
|
}
|
|
|
|
if (wipeTries == 3)
|
|
{
|
|
FillWindowPixelBuffer(gSaveFailedWindowIds[TEXT_WIN_ID], 0x11);
|
|
SaveFailedScreenTextPrint(gText_BackupMemoryDamaged, 1, 0);
|
|
}
|
|
else
|
|
{
|
|
FillWindowPixelBuffer(gSaveFailedWindowIds[TEXT_WIN_ID], 0x11);
|
|
|
|
if (gGameContinueCallback == NULL)
|
|
SaveFailedScreenTextPrint(gText_SaveCompleteGameCannotContinue, 1, 0);
|
|
else
|
|
SaveFailedScreenTextPrint(gText_SaveCompletePressA, 1, 0);
|
|
}
|
|
|
|
SetMainCallback2(CB2_FadeAndReturnToTitleScreen);
|
|
}
|
|
|
|
static void CB2_GameplayCannotBeContinued(void)
|
|
{
|
|
gSaveFailedClockInfo[CLOCK_RUNNING] = FALSE;
|
|
|
|
if (gMain.newKeys & A_BUTTON)
|
|
{
|
|
FillWindowPixelBuffer(gSaveFailedWindowIds[TEXT_WIN_ID], 0x11);
|
|
SaveFailedScreenTextPrint(gText_GamePlayCannotBeContinued, 1, 0);
|
|
SetVBlankCallback(VBlankCB);
|
|
SetMainCallback2(CB2_FadeAndReturnToTitleScreen);
|
|
}
|
|
}
|
|
|
|
static void CB2_FadeAndReturnToTitleScreen(void)
|
|
{
|
|
gSaveFailedClockInfo[CLOCK_RUNNING] = FALSE;
|
|
|
|
if (gMain.newKeys & A_BUTTON)
|
|
{
|
|
BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, 0);
|
|
SetVBlankCallback(VBlankCB);
|
|
SetMainCallback2(CB2_ReturnToTitleScreen);
|
|
}
|
|
}
|
|
|
|
static void CB2_ReturnToTitleScreen(void)
|
|
{
|
|
if (!UpdatePaletteFade())
|
|
{
|
|
if (gGameContinueCallback == NULL) // no callback exists, so do a soft reset.
|
|
{
|
|
DoSoftReset();
|
|
}
|
|
else
|
|
{
|
|
SetMainCallback2((MainCallback)gGameContinueCallback);
|
|
gGameContinueCallback = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void VBlankCB_UpdateClockGraphics(void)
|
|
{
|
|
unsigned int n = (gMain.vblankCounter2 >> 3) & 7;
|
|
|
|
gMain.oamBuffer[0] = sClockOamData;
|
|
gMain.oamBuffer[0].x = 112;
|
|
gMain.oamBuffer[0].y = (CLOCK_WIN_TOP + 1) * 8;;
|
|
|
|
if (gSaveFailedClockInfo[CLOCK_RUNNING] != FALSE)
|
|
{
|
|
gMain.oamBuffer[0].tileNum = sClockFrames[n][0];
|
|
gMain.oamBuffer[0].matrixNum = (sClockFrames[n][2] << 4) | (sClockFrames[n][1] << 3);
|
|
}
|
|
else
|
|
{
|
|
gMain.oamBuffer[0].tileNum = 1;
|
|
}
|
|
|
|
CpuFastCopy(gMain.oamBuffer, (void *)OAM, 4);
|
|
|
|
if (gSaveFailedClockInfo[DEBUG_TIMER])
|
|
gSaveFailedClockInfo[DEBUG_TIMER]--;
|
|
}
|
|
|
|
static bool8 VerifySectorWipe(u16 sector)
|
|
{
|
|
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;
|
|
}
|
|
|
|
static bool8 WipeSector(u16 sector)
|
|
{
|
|
u16 i, j;
|
|
bool8 failed = TRUE;
|
|
|
|
for (i = 0; failed && i < 130; i++)
|
|
{
|
|
for (j = 0; j < 0x1000; j++)
|
|
ProgramFlashByte(sector, j, 0);
|
|
|
|
failed = VerifySectorWipe(sector);
|
|
}
|
|
|
|
return failed;
|
|
}
|
|
|
|
static bool8 WipeSectors(u32 sectorBits)
|
|
{
|
|
u16 i;
|
|
|
|
for (i = 0; i < 0x20; i++)
|
|
if ((sectorBits & (1 << i)) && !WipeSector(i))
|
|
sectorBits &= ~(1 << i);
|
|
|
|
if (sectorBits == 0)
|
|
return FALSE;
|
|
else
|
|
return TRUE;
|
|
}
|