mirror of
https://github.com/pret/pokefirered.git
synced 2026-05-10 14:01:52 -05:00
254 lines
6.6 KiB
C
254 lines
6.6 KiB
C
#include "global.h"
|
|
|
|
#include "gba/flash_internal.h"
|
|
|
|
#include "malloc.h"
|
|
|
|
#include "agb_flash.h"
|
|
#include "berry_powder.h"
|
|
#include "fake_rtc.h"
|
|
#include "item.h"
|
|
#include "load_save.h"
|
|
#include "overworld.h"
|
|
#include "pokemon.h"
|
|
#include "pokemon_storage_system.h"
|
|
#include "quest_log.h"
|
|
#include "random.h"
|
|
#include "save_location.h"
|
|
#include "trainer_tower.h"
|
|
#include "constants/event_objects.h"
|
|
|
|
struct LoadedSaveData
|
|
{
|
|
/*0x0000*/ struct Bag bag;
|
|
/*0x02E8*/ struct Mail mail[MAIL_COUNT];
|
|
};
|
|
|
|
// EWRAM DATA
|
|
EWRAM_DATA struct SaveBlock3 gSaveblock3 = {};
|
|
EWRAM_DATA struct SaveBlock2ASLR gSaveblock2 = {0};
|
|
EWRAM_DATA struct SaveBlock1ASLR gSaveblock1 = {0};
|
|
EWRAM_DATA struct PokemonStorageASLR gPokemonStorage = {0};
|
|
|
|
EWRAM_DATA struct LoadedSaveData gLoadedSaveData = {0};
|
|
|
|
// IWRAM common
|
|
COMMON_DATA bool32 gFlashMemoryPresent = 0;
|
|
COMMON_DATA struct SaveBlock1 *gSaveBlock1Ptr = NULL;
|
|
COMMON_DATA struct SaveBlock2 *gSaveBlock2Ptr = NULL;
|
|
IWRAM_INIT struct SaveBlock3 *gSaveBlock3Ptr = &gSaveblock3;
|
|
COMMON_DATA struct PokemonStorage *gPokemonStoragePtr = NULL;
|
|
|
|
void CheckForFlashMemory(void)
|
|
{
|
|
if (!IdentifyFlash())
|
|
{
|
|
gFlashMemoryPresent = TRUE;
|
|
InitFlashTimer();
|
|
}
|
|
else
|
|
{
|
|
gFlashMemoryPresent = FALSE;
|
|
}
|
|
}
|
|
|
|
void ClearSav3(void)
|
|
{
|
|
CpuFill16(0, &gSaveblock3, sizeof(struct SaveBlock3));
|
|
FakeRtc_Reset();
|
|
}
|
|
|
|
void ClearSav2(void)
|
|
{
|
|
CpuFill16(0, &gSaveblock2, sizeof(struct SaveBlock2ASLR));
|
|
}
|
|
|
|
void ClearSav1(void)
|
|
{
|
|
CpuFill16(0, &gSaveblock1, sizeof(struct SaveBlock1ASLR));
|
|
}
|
|
|
|
void SetSaveBlocksPointers(u16 offset)
|
|
{
|
|
struct SaveBlock1** sav1_LocalVar = &gSaveBlock1Ptr;
|
|
void *oldSave = (void *)gSaveBlock1Ptr;
|
|
|
|
offset = (offset + Random()) & (SAVEBLOCK_MOVE_RANGE - 4);
|
|
|
|
gSaveBlock2Ptr = (void *)(&gSaveblock2) + offset;
|
|
*sav1_LocalVar = (void *)(&gSaveblock1) + offset;
|
|
gPokemonStoragePtr = (void *)(&gPokemonStorage) + offset;
|
|
|
|
SetBagItemsPointers();
|
|
QL_AddASLROffset(oldSave);
|
|
}
|
|
|
|
void MoveSaveBlocks_ResetHeap(void)
|
|
{
|
|
void *vblankCB, *hblankCB;
|
|
struct SaveBlock2 *saveBlock2Copy;
|
|
struct SaveBlock1 *saveBlock1Copy;
|
|
struct PokemonStorage *pokemonStorageCopy;
|
|
|
|
// save interrupt functions and turn them off
|
|
vblankCB = gMain.vblankCallback;
|
|
hblankCB = gMain.hblankCallback;
|
|
gMain.vblankCallback = NULL;
|
|
gMain.hblankCallback = NULL;
|
|
gTrainerTowerVBlankCounter = NULL;
|
|
|
|
saveBlock2Copy = (struct SaveBlock2 *)(gHeap);
|
|
saveBlock1Copy = (struct SaveBlock1 *)(gHeap + sizeof(struct SaveBlock2));
|
|
pokemonStorageCopy = (struct PokemonStorage *)(gHeap + sizeof(struct SaveBlock2) + sizeof(struct SaveBlock1));
|
|
|
|
// backup the saves.
|
|
*saveBlock2Copy = *gSaveBlock2Ptr;
|
|
*saveBlock1Copy = *gSaveBlock1Ptr;
|
|
*pokemonStorageCopy = *gPokemonStoragePtr;
|
|
|
|
// change saveblocks' pointers
|
|
SetSaveBlocksPointers(
|
|
saveBlock2Copy->playerTrainerId[0] +
|
|
saveBlock2Copy->playerTrainerId[1] +
|
|
saveBlock2Copy->playerTrainerId[2] +
|
|
saveBlock2Copy->playerTrainerId[3]);
|
|
|
|
// restore saveblock data since the pointers changed
|
|
*gSaveBlock2Ptr = *saveBlock2Copy;
|
|
*gSaveBlock1Ptr = *saveBlock1Copy;
|
|
*gPokemonStoragePtr = *pokemonStorageCopy;
|
|
|
|
// heap was destroyed in the copying process, so reset it
|
|
InitHeap(gHeap, HEAP_SIZE);
|
|
|
|
// restore interrupt functions
|
|
gMain.hblankCallback = hblankCB;
|
|
gMain.vblankCallback = vblankCB;
|
|
}
|
|
|
|
u32 UseContinueGameWarp(void)
|
|
{
|
|
return gSaveBlock2Ptr->specialSaveWarpFlags & CONTINUE_GAME_WARP;
|
|
}
|
|
|
|
void ClearContinueGameWarpStatus(void)
|
|
{
|
|
gSaveBlock2Ptr->specialSaveWarpFlags &= ~CONTINUE_GAME_WARP;
|
|
}
|
|
|
|
void SetContinueGameWarpStatus(void)
|
|
{
|
|
gSaveBlock2Ptr->specialSaveWarpFlags |= CONTINUE_GAME_WARP;
|
|
}
|
|
|
|
void SetContinueGameWarpStatusToDynamicWarp(void)
|
|
{
|
|
SetContinueGameWarpToDynamicWarp(0);
|
|
gSaveBlock2Ptr->specialSaveWarpFlags |= CONTINUE_GAME_WARP;
|
|
}
|
|
|
|
void ClearContinueGameWarpStatus2(void)
|
|
{
|
|
gSaveBlock2Ptr->specialSaveWarpFlags &= ~CONTINUE_GAME_WARP;
|
|
}
|
|
|
|
void SavePlayerParty(void)
|
|
{
|
|
int i;
|
|
|
|
gSaveBlock1Ptr->playerPartyCount = gPlayerPartyCount;
|
|
|
|
for (i = 0; i < PARTY_SIZE; i++)
|
|
gSaveBlock1Ptr->playerParty[i] = gPlayerParty[i];
|
|
}
|
|
|
|
void LoadPlayerParty(void)
|
|
{
|
|
int i;
|
|
|
|
gPlayerPartyCount = gSaveBlock1Ptr->playerPartyCount;
|
|
|
|
for (i = 0; i < PARTY_SIZE; i++)
|
|
gPlayerParty[i] = gSaveBlock1Ptr->playerParty[i];
|
|
}
|
|
|
|
void SaveObjectEvents(void)
|
|
{
|
|
int i;
|
|
u16 graphicsId;
|
|
|
|
for (i = 0; i < OBJECT_EVENTS_COUNT; i++)
|
|
{
|
|
gSaveBlock1Ptr->objectEvents[i] = gObjectEvents[i];
|
|
// Swap graphicsId bytes when saving and loading
|
|
// This keeps compatibility with vanilla,
|
|
// since the lower graphicsIds will be in the same place as vanilla
|
|
graphicsId = gObjectEvents[i].graphicsId;
|
|
gSaveBlock1Ptr->objectEvents[i].graphicsId = (graphicsId >> 8) | (graphicsId << 8);
|
|
gSaveBlock1Ptr->objectEvents[i].spriteId = 127; // magic number
|
|
// To avoid crash on vanilla, save follower as inactive
|
|
if (gObjectEvents[i].localId == OBJ_EVENT_ID_FOLLOWER)
|
|
gSaveBlock1Ptr->objectEvents[i].active = FALSE;
|
|
}
|
|
}
|
|
|
|
void LoadObjectEvents(void)
|
|
{
|
|
int i;
|
|
u16 graphicsId;
|
|
|
|
for (i = 0; i < OBJECT_EVENTS_COUNT; i++)
|
|
{
|
|
gObjectEvents[i] = gSaveBlock1Ptr->objectEvents[i];
|
|
// Swap graphicsId bytes when saving and loading
|
|
// This keeps compatibility with vanilla,
|
|
// since the lower graphicsIds will be in the same place as vanilla
|
|
graphicsId = gObjectEvents[i].graphicsId;
|
|
gObjectEvents[i].graphicsId = (graphicsId >> 8) | (graphicsId << 8);
|
|
if (gObjectEvents[i].spriteId != 127)
|
|
gObjectEvents[i].graphicsId &= 0xFF;
|
|
gObjectEvents[i].spriteId = 0;
|
|
// Try to restore saved inactive follower
|
|
if (gObjectEvents[i].localId == OBJ_EVENT_ID_FOLLOWER &&
|
|
!gObjectEvents[i].active &&
|
|
gObjectEvents[i].graphicsId & OBJ_EVENT_MON)
|
|
gObjectEvents[i].active = TRUE;
|
|
}
|
|
}
|
|
|
|
void CopyPartyAndObjectsToSave(void)
|
|
{
|
|
SavePlayerParty();
|
|
SaveObjectEvents();
|
|
}
|
|
|
|
void CopyPartyAndObjectsFromSave(void)
|
|
{
|
|
LoadPlayerParty();
|
|
LoadObjectEvents();
|
|
}
|
|
|
|
void LoadPlayerBag(void)
|
|
{
|
|
int i;
|
|
|
|
// load player bag.
|
|
memcpy(&gLoadedSaveData.bag, &gSaveBlock1Ptr->bag, sizeof(struct Bag));
|
|
|
|
// load mail.
|
|
for (i = 0; i < MAIL_COUNT; i++)
|
|
gLoadedSaveData.mail[i] = gSaveBlock1Ptr->mail[i];
|
|
}
|
|
|
|
void SavePlayerBag(void)
|
|
{
|
|
int i;
|
|
|
|
// save player bag.
|
|
memcpy(&gSaveBlock1Ptr->bag, &gLoadedSaveData.bag, sizeof(struct Bag));
|
|
|
|
// save mail.
|
|
for (i = 0; i < MAIL_COUNT; i++)
|
|
gSaveBlock1Ptr->mail[i] = gLoadedSaveData.mail[i];
|
|
}
|