#include "global.h" #include "gba/flash_internal.h" #include "load_save.h" #include "main.h" #include "pokemon.h" #include "random.h" extern void* gUnknown_0203CF5C; extern bool16 IdentifyFlash(void); extern void SetBagItemsPointers(void); extern void SetDecorationInventoriesPointers(void); extern void ApplyNewEncryptionKeyToGameStats(u32 key); extern void ApplyNewEncryptionKeyToBagItems(u32 newKey); extern void ApplyNewEncryptionKeyToBagItems_(u32 key); extern void ApplyNewEncryptionKeyToBerryPowder(u32 key); extern void sub_8084FAC(int unused); // this is probably wrong or misleading due to it being used in ResetHeap... extern void InitHeap(void *pointer, u32 size); #define SAVEBLOCK_MOVE_RANGE 128 struct LoadedSaveData { /*0x0000*/ struct ItemSlot items[30]; /*0x0078*/ struct ItemSlot keyItems[30]; /*0x00F0*/ struct ItemSlot pokeBalls[16]; /*0x0130*/ struct ItemSlot TMsHMs[64]; /*0x0230*/ struct ItemSlot berries[46]; /*0x02E8*/ struct MailStruct mail[MAIL_COUNT]; }; 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}; void ApplyNewEncryptionKeyToAllEncryptedData(u32 encryptionKey); 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(); } extern u8 gHeap[]; 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; } u8 sav2_x1_query_bit1(void) { return gSaveBlock2Ptr->specialSaveWarp & 1; } void sav2_x9_clear_bit1(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 copy_player_party_to_sav1(void) // SavePlayerParty { int i; gSaveBlock1Ptr->playerPartyCount = gPlayerPartyCount; for (i = 0; i < 6; i++) gSaveBlock1Ptr->playerParty[i] = gPlayerParty[i]; } void copy_player_party_from_sav1(void) // LoadPlayerParty { int i; gPlayerPartyCount = gSaveBlock1Ptr->playerPartyCount; for (i = 0; i < 6; i++) gPlayerParty[i] = gSaveBlock1Ptr->playerParty[i]; } void save_serialize_npcs(void) // SaveMapObjects { int i; for (i = 0; i < 16; i++) gSaveBlock1Ptr->mapObjects[i] = gMapObjects[i]; } void save_deserialize_npcs(void) // LoadMapObjects { int i; for (i = 0; i < 16; i++) gMapObjects[i] = gSaveBlock1Ptr->mapObjects[i]; } void SaveSerializedGame(void) { copy_player_party_to_sav1(); save_serialize_npcs(); } void LoadSerializedGame(void) { copy_player_party_from_sav1(); save_deserialize_npcs(); } void copy_bags_and_unk_data_from_save_blocks(void) { int i; // load player items. for (i = 0; i < 30; i++) gLoadedSaveData.items[i] = gSaveBlock1Ptr->bagPocket_Items[i]; // load player key items. for (i = 0; i < 30; i++) gLoadedSaveData.keyItems[i] = gSaveBlock1Ptr->bagPocket_KeyItems[i]; // load player pokeballs. for (i = 0; i < 16; i++) gLoadedSaveData.pokeBalls[i] = gSaveBlock1Ptr->bagPocket_PokeBalls[i]; // load player TMs and HMs. for (i = 0; i < 64; i++) gLoadedSaveData.TMsHMs[i] = gSaveBlock1Ptr->bagPocket_TMHM[i]; // load player berries. for (i = 0; i < 46; i++) gLoadedSaveData.berries[i] = gSaveBlock1Ptr->bagPocket_Berries[i]; // load mail. for (i = 0; i < 16; i++) gLoadedSaveData.mail[i] = gSaveBlock1Ptr->mail[i]; gLastEncryptionKey = gSaveBlock2Ptr->encryptionKey; } void copy_bags_and_unk_data_to_save_blocks(void) { int i; u32 encryptionKeyBackup; // save player items. for (i = 0; i < 30; i++) gSaveBlock1Ptr->bagPocket_Items[i] = gLoadedSaveData.items[i]; // save player key items. for (i = 0; i < 30; i++) gSaveBlock1Ptr->bagPocket_KeyItems[i] = gLoadedSaveData.keyItems[i]; // save player pokeballs. for (i = 0; i < 16; i++) gSaveBlock1Ptr->bagPocket_PokeBalls[i] = gLoadedSaveData.pokeBalls[i]; // save player TMs and HMs. for (i = 0; i < 64; i++) gSaveBlock1Ptr->bagPocket_TMHM[i] = gLoadedSaveData.TMsHMs[i]; // save player berries. for (i = 0; i < 46; i++) gSaveBlock1Ptr->bagPocket_Berries[i] = gLoadedSaveData.berries[i]; // save mail. for (i = 0; i < 16; 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); }