#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); }