mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-11-18 12:37:38 +01:00
297 lines
7.9 KiB
C
297 lines
7.9 KiB
C
#include "global.h"
|
|
#include "gba/flash_internal.h"
|
|
#include "load_save.h"
|
|
#include "main.h"
|
|
#include "pokemon.h"
|
|
#include "random.h"
|
|
#include "malloc.h"
|
|
#include "item.h"
|
|
|
|
extern void* gUnknown_0203CF5C;
|
|
|
|
extern bool16 IdentifyFlash(void);
|
|
extern void SetDecorationInventoriesPointers(void);
|
|
extern void ApplyNewEncryptionKeyToGameStats(u32 key);
|
|
extern void ApplyNewEncryptionKeyToBerryPowder(u32 key);
|
|
extern void sub_8084FAC(int unused);
|
|
|
|
#define SAVEBLOCK_MOVE_RANGE 128
|
|
|
|
struct LoadedSaveData
|
|
{
|
|
/*0x0000*/ struct ItemSlot items[BAG_ITEMS_COUNT];
|
|
/*0x0078*/ struct ItemSlot keyItems[BAG_KEYITEMS_COUNT];
|
|
/*0x00F0*/ struct ItemSlot pokeBalls[BAG_POKEBALLS_COUNT];
|
|
/*0x0130*/ struct ItemSlot TMsHMs[BAG_TMHM_COUNT];
|
|
/*0x0230*/ struct ItemSlot berries[BAG_BERRIES_COUNT];
|
|
/*0x02E8*/ struct MailStruct mail[MAIL_COUNT];
|
|
};
|
|
|
|
// EWRAM DATA
|
|
EWRAM_DATA struct SaveBlock2 gSaveblock2 = {0};
|
|
EWRAM_DATA u8 gSaveblock2_DMA[SAVEBLOCK_MOVE_RANGE] = {0};
|
|
|
|
EWRAM_DATA struct SaveBlock1 gSaveblock1 = {0};
|
|
EWRAM_DATA u8 gSaveblock1_DMA[SAVEBLOCK_MOVE_RANGE] = {0};
|
|
|
|
EWRAM_DATA struct PokemonStorage gPokemonStorage = {0};
|
|
EWRAM_DATA u8 gSaveblock3_DMA[SAVEBLOCK_MOVE_RANGE] = {0};
|
|
|
|
EWRAM_DATA struct LoadedSaveData gLoadedSaveData = {0};
|
|
EWRAM_DATA u32 gLastEncryptionKey = 0;
|
|
|
|
// IWRAM common
|
|
IWRAM_DATA bool32 gFlashMemoryPresent;
|
|
IWRAM_DATA struct SaveBlock1 *gSaveBlock1Ptr;
|
|
IWRAM_DATA struct SaveBlock2 *gSaveBlock2Ptr;
|
|
IWRAM_DATA struct PokemonStorage *gPokemonStoragePtr;
|
|
|
|
// code
|
|
void CheckForFlashMemory(void)
|
|
{
|
|
if (!IdentifyFlash())
|
|
{
|
|
gFlashMemoryPresent = TRUE;
|
|
InitFlashTimer();
|
|
}
|
|
else
|
|
{
|
|
gFlashMemoryPresent = FALSE;
|
|
}
|
|
}
|
|
|
|
void ClearSav2(void)
|
|
{
|
|
CpuFill16(0, &gSaveblock2, sizeof(struct SaveBlock2) + sizeof(gSaveblock2_DMA));
|
|
}
|
|
|
|
void ClearSav1(void)
|
|
{
|
|
CpuFill16(0, &gSaveblock1, sizeof(struct SaveBlock1) + sizeof(gSaveblock1_DMA));
|
|
}
|
|
|
|
void SetSaveBlocksPointers(u16 offset)
|
|
{
|
|
struct SaveBlock1** sav1_LocalVar = &gSaveBlock1Ptr;
|
|
|
|
offset = (offset + Random()) & (SAVEBLOCK_MOVE_RANGE - 4);
|
|
|
|
gSaveBlock2Ptr = (void*)(&gSaveblock2) + offset;
|
|
*sav1_LocalVar = (void*)(&gSaveblock1) + offset;
|
|
gPokemonStoragePtr = (void*)(&gPokemonStorage) + offset;
|
|
|
|
SetBagItemsPointers();
|
|
SetDecorationInventoriesPointers();
|
|
}
|
|
|
|
void MoveSaveBlocks_ResetHeap(void)
|
|
{
|
|
void *vblankCB, *hblankCB;
|
|
u32 encryptionKey;
|
|
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;
|
|
gUnknown_0203CF5C = 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
|
|
// argument is a sum of the individual trainerId bytes
|
|
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;
|
|
|
|
// create a new encryption key
|
|
encryptionKey = (Random() << 0x10) + (Random());
|
|
ApplyNewEncryptionKeyToAllEncryptedData(encryptionKey);
|
|
gSaveBlock2Ptr->encryptionKey = encryptionKey;
|
|
}
|
|
|
|
u32 GetSecretBase2Field_9(void)
|
|
{
|
|
return gSaveBlock2Ptr->specialSaveWarp & 1;
|
|
}
|
|
|
|
void ClearSecretBase2Field_9(void)
|
|
{
|
|
gSaveBlock2Ptr->specialSaveWarp &= ~1;
|
|
}
|
|
|
|
void sub_8076D48(void)
|
|
{
|
|
gSaveBlock2Ptr->specialSaveWarp |= 1;
|
|
}
|
|
|
|
void sub_8076D5C(void)
|
|
{
|
|
sub_8084FAC(0);
|
|
gSaveBlock2Ptr->specialSaveWarp |= 1;
|
|
}
|
|
|
|
void sav2_gender2_inplace_and_xFE(void)
|
|
{
|
|
gSaveBlock2Ptr->specialSaveWarp &= ~1;
|
|
}
|
|
|
|
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 SaveMapObjects(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAP_OBJECTS_COUNT; i++)
|
|
gSaveBlock1Ptr->mapObjects[i] = gMapObjects[i];
|
|
}
|
|
|
|
void LoadMapObjects(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAP_OBJECTS_COUNT; i++)
|
|
gMapObjects[i] = gSaveBlock1Ptr->mapObjects[i];
|
|
}
|
|
|
|
void SaveSerializedGame(void)
|
|
{
|
|
SavePlayerParty();
|
|
SaveMapObjects();
|
|
}
|
|
|
|
void LoadSerializedGame(void)
|
|
{
|
|
LoadPlayerParty();
|
|
LoadMapObjects();
|
|
}
|
|
|
|
void LoadPlayerBag(void)
|
|
{
|
|
int i;
|
|
|
|
// load player items.
|
|
for (i = 0; i < BAG_ITEMS_COUNT; i++)
|
|
gLoadedSaveData.items[i] = gSaveBlock1Ptr->bagPocket_Items[i];
|
|
|
|
// load player key items.
|
|
for (i = 0; i < BAG_KEYITEMS_COUNT; i++)
|
|
gLoadedSaveData.keyItems[i] = gSaveBlock1Ptr->bagPocket_KeyItems[i];
|
|
|
|
// load player pokeballs.
|
|
for (i = 0; i < BAG_POKEBALLS_COUNT; i++)
|
|
gLoadedSaveData.pokeBalls[i] = gSaveBlock1Ptr->bagPocket_PokeBalls[i];
|
|
|
|
// load player TMs and HMs.
|
|
for (i = 0; i < BAG_TMHM_COUNT; i++)
|
|
gLoadedSaveData.TMsHMs[i] = gSaveBlock1Ptr->bagPocket_TMHM[i];
|
|
|
|
// load player berries.
|
|
for (i = 0; i < BAG_BERRIES_COUNT; i++)
|
|
gLoadedSaveData.berries[i] = gSaveBlock1Ptr->bagPocket_Berries[i];
|
|
|
|
// load mail.
|
|
for (i = 0; i < MAIL_COUNT; i++)
|
|
gLoadedSaveData.mail[i] = gSaveBlock1Ptr->mail[i];
|
|
|
|
gLastEncryptionKey = gSaveBlock2Ptr->encryptionKey;
|
|
}
|
|
|
|
void SavePlayerBag(void)
|
|
{
|
|
int i;
|
|
u32 encryptionKeyBackup;
|
|
|
|
// save player items.
|
|
for (i = 0; i < BAG_ITEMS_COUNT; i++)
|
|
gSaveBlock1Ptr->bagPocket_Items[i] = gLoadedSaveData.items[i];
|
|
|
|
// save player key items.
|
|
for (i = 0; i < BAG_KEYITEMS_COUNT; i++)
|
|
gSaveBlock1Ptr->bagPocket_KeyItems[i] = gLoadedSaveData.keyItems[i];
|
|
|
|
// save player pokeballs.
|
|
for (i = 0; i < BAG_POKEBALLS_COUNT; i++)
|
|
gSaveBlock1Ptr->bagPocket_PokeBalls[i] = gLoadedSaveData.pokeBalls[i];
|
|
|
|
// save player TMs and HMs.
|
|
for (i = 0; i < BAG_TMHM_COUNT; i++)
|
|
gSaveBlock1Ptr->bagPocket_TMHM[i] = gLoadedSaveData.TMsHMs[i];
|
|
|
|
// save player berries.
|
|
for (i = 0; i < BAG_BERRIES_COUNT; i++)
|
|
gSaveBlock1Ptr->bagPocket_Berries[i] = gLoadedSaveData.berries[i];
|
|
|
|
// save mail.
|
|
for (i = 0; i < MAIL_COUNT; i++)
|
|
gSaveBlock1Ptr->mail[i] = gLoadedSaveData.mail[i];
|
|
|
|
encryptionKeyBackup = gSaveBlock2Ptr->encryptionKey;
|
|
gSaveBlock2Ptr->encryptionKey = gLastEncryptionKey;
|
|
ApplyNewEncryptionKeyToBagItems(encryptionKeyBackup);
|
|
gSaveBlock2Ptr->encryptionKey = encryptionKeyBackup; // updated twice?
|
|
}
|
|
|
|
void ApplyNewEncryptionKeyToHword(u16 *hWord, u32 newKey)
|
|
{
|
|
*hWord ^= gSaveBlock2Ptr->encryptionKey;
|
|
*hWord ^= newKey;
|
|
}
|
|
|
|
void ApplyNewEncryptionKeyToWord(u32 *word, u32 newKey)
|
|
{
|
|
*word ^= gSaveBlock2Ptr->encryptionKey;
|
|
*word ^= newKey;
|
|
}
|
|
|
|
void ApplyNewEncryptionKeyToAllEncryptedData(u32 encryptionKey)
|
|
{
|
|
ApplyNewEncryptionKeyToGameStats(encryptionKey);
|
|
ApplyNewEncryptionKeyToBagItems_(encryptionKey);
|
|
ApplyNewEncryptionKeyToBerryPowder(encryptionKey);
|
|
ApplyNewEncryptionKeyToWord(&gSaveBlock1Ptr->money, encryptionKey);
|
|
ApplyNewEncryptionKeyToHword(&gSaveBlock1Ptr->coins, encryptionKey);
|
|
}
|