2017-09-03 14:13:01 +02:00
# include "global.h"
2019-03-02 09:18:08 +01:00
# include "agb_flash.h"
2017-09-03 14:13:01 +02:00
# include "gba/flash_internal.h"
2019-03-02 09:18:08 +01:00
# include "fieldmap.h"
2017-09-03 14:13:01 +02:00
# include "save.h"
2017-09-29 10:06:36 +02:00
# include "task.h"
2018-02-15 23:54:34 +01:00
# include "decompress.h"
2018-04-29 14:21:59 +02:00
# include "load_save.h"
# include "overworld.h"
2018-12-20 22:53:08 +01:00
# include "pokemon_storage_system.h"
2018-11-18 19:37:18 +01:00
# include "main.h"
2019-01-13 13:15:23 +01:00
# include "trainer_hill.h"
2019-03-02 09:18:08 +01:00
# include "link.h"
2018-11-18 19:37:18 +01:00
# include "constants/game_stat.h"
Undo PokeCodec's PRs
This commit undoes most of PokeCodec's PRs after the debate in chat. Some
harmless or completely superseded PRs have been left alone, as there is not
much benefit in attempting to undo them.
Reverts #1104, #1108, #1115, #1118, #1119, #1124, #1126, #1127, #1132, #1136,
#1137, #1139, #1140, #1144, #1148, #1149, #1150, #1153, #1155, #1177, #1179,
#1180, #1181, #1182 and #1183.
2020-09-13 09:22:50 +02:00
static u16 CalculateChecksum ( void * data , u16 size ) ;
2020-01-12 21:27:37 +01:00
static bool8 DoReadFlashWholeSection ( u8 sector , struct SaveSection * section ) ;
2018-11-18 19:37:18 +01:00
static u8 GetSaveValidStatus ( const struct SaveSectionLocation * location ) ;
static u8 sub_8152E10 ( u16 a1 , const struct SaveSectionLocation * location ) ;
static u8 ClearSaveData_2 ( u16 a1 , const struct SaveSectionLocation * location ) ;
static u8 TryWriteSector ( u8 sector , u8 * data ) ;
static u8 HandleWriteSector ( u16 a1 , const struct SaveSectionLocation * location ) ;
2017-09-03 14:13:01 +02:00
2018-01-31 21:26:57 +01:00
// Divide save blocks into individual chunks to be written to flash sectors
/*
* Sector Layout :
2018-04-29 14:21:59 +02:00
*
2018-01-31 21:26:57 +01:00
* Sectors 0 - 13 : Save Slot 1
* Sectors 14 - 27 : Save Slot 2
* Sectors 28 - 29 : Hall of Fame
2018-11-18 19:37:18 +01:00
* Sector 30 : Trainer Hill
2018-01-31 23:12:46 +01:00
* Sector 31 : Recorded Battle
2018-04-29 14:21:59 +02:00
*
2018-01-31 21:26:57 +01:00
* There are two save slots for saving the player ' s game data . We alternate between
* them each time the game is saved , so that if the current save slot is corrupt ,
* we can load the previous one . We also rotate the sectors in each save slot
* so that the same data is not always being written to the same sector . This
* might be done to reduce wear on the flash memory , but I ' m not sure , since all
* 14 sectors get written anyway .
*/
// (u8 *)structure was removed from the first statement of the macro in Emerald.
// This is because malloc is used to allocate addresses so storing the raw
2018-04-29 14:21:59 +02:00
// addresses should not be done in the offsets information.
2021-10-13 19:19:15 +02:00
# define SAVEBLOCK_CHUNK(structure, chunkNum) \
{ \
chunkNum * SECTOR_DATA_SIZE , \
sizeof ( structure ) > = chunkNum * SECTOR_DATA_SIZE ? \
min ( sizeof ( structure ) - chunkNum * SECTOR_DATA_SIZE , SECTOR_DATA_SIZE ) : 0 \
}
2018-01-31 21:26:57 +01:00
2020-01-12 21:27:37 +01:00
static const struct SaveSectionOffsets sSaveSectionOffsets [ ] =
2018-01-31 21:26:57 +01:00
{
SAVEBLOCK_CHUNK ( gSaveblock2 , 0 ) ,
SAVEBLOCK_CHUNK ( gSaveblock1 , 0 ) ,
SAVEBLOCK_CHUNK ( gSaveblock1 , 1 ) ,
SAVEBLOCK_CHUNK ( gSaveblock1 , 2 ) ,
SAVEBLOCK_CHUNK ( gSaveblock1 , 3 ) ,
SAVEBLOCK_CHUNK ( gPokemonStorage , 0 ) ,
SAVEBLOCK_CHUNK ( gPokemonStorage , 1 ) ,
SAVEBLOCK_CHUNK ( gPokemonStorage , 2 ) ,
SAVEBLOCK_CHUNK ( gPokemonStorage , 3 ) ,
SAVEBLOCK_CHUNK ( gPokemonStorage , 4 ) ,
SAVEBLOCK_CHUNK ( gPokemonStorage , 5 ) ,
SAVEBLOCK_CHUNK ( gPokemonStorage , 6 ) ,
SAVEBLOCK_CHUNK ( gPokemonStorage , 7 ) ,
SAVEBLOCK_CHUNK ( gPokemonStorage , 8 ) ,
} ;
2017-09-03 15:39:33 +02:00
// iwram common
u16 gLastWrittenSector ;
u32 gLastSaveCounter ;
u16 gLastKnownGoodSector ;
u32 gDamagedSaveSectors ;
u32 gSaveCounter ;
struct SaveSection * gFastSaveSection ;
u16 gUnknown_03006208 ;
u16 gSaveUnusedVar ;
2017-09-03 22:50:17 +02:00
u16 gSaveFileStatus ;
2017-09-03 15:39:33 +02:00
void ( * gGameContinueCallback ) ( void ) ;
2020-01-12 21:27:37 +01:00
struct SaveSectionLocation gRamSaveSectionLocations [ SECTOR_SAVE_SLOT_LENGTH ] ;
2018-09-10 01:01:39 +02:00
u16 gSaveUnusedVar2 ;
2020-01-12 21:27:37 +01:00
u16 gSaveAttemptStatus ;
2017-09-03 15:39:33 +02:00
EWRAM_DATA struct SaveSection gSaveDataBuffer = { 0 } ;
2018-11-19 01:03:14 +01:00
EWRAM_DATA static u8 sUnusedVar = 0 ;
2017-09-03 14:13:01 +02:00
void ClearSaveData ( void )
{
u16 i ;
for ( i = 0 ; i < NUM_SECTORS_PER_SLOT ; i + + )
{
EraseFlashSector ( i ) ;
EraseFlashSector ( i + NUM_SECTORS_PER_SLOT ) ; // clear slot 2.
}
}
2018-02-15 23:54:34 +01:00
void Save_ResetSaveCounters ( void )
2017-09-03 14:13:01 +02:00
{
gSaveCounter = 0 ;
gLastWrittenSector = 0 ;
gDamagedSaveSectors = 0 ;
}
2018-11-18 19:37:18 +01:00
static bool32 SetDamagedSectorBits ( u8 op , u8 bit )
2017-09-03 14:13:01 +02:00
{
bool32 retVal = FALSE ;
switch ( op )
{
case ENABLE :
gDamagedSaveSectors | = ( 1 < < bit ) ;
break ;
case DISABLE :
gDamagedSaveSectors & = ~ ( 1 < < bit ) ;
break ;
case CHECK : // unused
if ( gDamagedSaveSectors & ( 1 < < bit ) )
retVal = TRUE ;
break ;
}
return retVal ;
}
2021-08-16 00:26:09 +02:00
static u8 SaveWriteToFlash ( u16 sectorId , const struct SaveSectionLocation * location )
2017-09-03 14:13:01 +02:00
{
2020-01-12 21:27:37 +01:00
u32 status ;
2017-09-03 14:13:01 +02:00
u16 i ;
2017-09-03 15:39:33 +02:00
gFastSaveSection = & gSaveDataBuffer ;
2017-09-03 14:13:01 +02:00
2021-08-16 00:26:09 +02:00
if ( sectorId ! = 0xFFFF ) // for link
2017-09-03 14:13:01 +02:00
{
2021-08-16 00:26:09 +02:00
status = HandleWriteSector ( sectorId , location ) ;
2017-09-03 14:13:01 +02:00
}
else
{
gLastKnownGoodSector = gLastWrittenSector ; // backup the current written sector before attempting to write.
gLastSaveCounter = gSaveCounter ;
gLastWrittenSector + + ;
2018-11-18 19:37:18 +01:00
gLastWrittenSector = gLastWrittenSector % SECTOR_SAVE_SLOT_LENGTH ; // array count save sector locations
2017-09-03 14:13:01 +02:00
gSaveCounter + + ;
2020-01-12 21:27:37 +01:00
status = SAVE_STATUS_OK ;
2017-09-03 14:13:01 +02:00
2018-11-18 19:37:18 +01:00
for ( i = 0 ; i < SECTOR_SAVE_SLOT_LENGTH ; i + + )
2017-09-03 14:13:01 +02:00
HandleWriteSector ( i , location ) ;
if ( gDamagedSaveSectors ! = 0 ) // skip the damaged sector.
{
2020-01-12 21:27:37 +01:00
status = SAVE_STATUS_ERROR ;
2017-09-03 14:13:01 +02:00
gLastWrittenSector = gLastKnownGoodSector ;
gSaveCounter = gLastSaveCounter ;
}
}
2020-01-12 21:27:37 +01:00
return status ;
2017-09-03 14:13:01 +02:00
}
2020-01-12 21:27:37 +01:00
static u8 HandleWriteSector ( u16 sectorId , const struct SaveSectionLocation * location )
2017-09-03 14:13:01 +02:00
{
u16 i ;
u16 sector ;
u8 * data ;
u16 size ;
2020-01-12 21:27:37 +01:00
sector = sectorId + gLastWrittenSector ;
2018-11-18 19:37:18 +01:00
sector % = SECTOR_SAVE_SLOT_LENGTH ;
2021-08-16 00:26:09 +02:00
sector + = SECTOR_SAVE_SLOT_LENGTH * ( gSaveCounter % NUM_SAVE_SLOTS ) ;
2017-09-03 14:13:01 +02:00
2020-01-12 21:27:37 +01:00
data = location [ sectorId ] . data ;
size = location [ sectorId ] . size ;
2017-09-03 14:13:01 +02:00
// clear save section.
for ( i = 0 ; i < sizeof ( struct SaveSection ) ; i + + )
( ( char * ) gFastSaveSection ) [ i ] = 0 ;
2020-01-12 21:27:37 +01:00
gFastSaveSection - > id = sectorId ;
2017-09-03 14:13:01 +02:00
gFastSaveSection - > security = UNKNOWN_CHECK_VALUE ;
gFastSaveSection - > counter = gSaveCounter ;
for ( i = 0 ; i < size ; i + + )
gFastSaveSection - > data [ i ] = data [ i ] ;
gFastSaveSection - > checksum = CalculateChecksum ( data , size ) ;
return TryWriteSector ( sector , gFastSaveSection - > data ) ;
}
2018-11-18 19:37:18 +01:00
static u8 HandleWriteSectorNBytes ( u8 sector , u8 * data , u16 size )
2017-09-03 14:13:01 +02:00
{
u16 i ;
2017-09-03 15:39:33 +02:00
struct SaveSection * section = & gSaveDataBuffer ;
2017-09-03 14:13:01 +02:00
for ( i = 0 ; i < sizeof ( struct SaveSection ) ; i + + )
( ( char * ) section ) [ i ] = 0 ;
section - > security = UNKNOWN_CHECK_VALUE ;
for ( i = 0 ; i < size ; i + + )
section - > data [ i ] = data [ i ] ;
section - > id = CalculateChecksum ( data , size ) ; // though this appears to be incorrect, it might be some sector checksum instead of a whole save checksum and only appears to be relevent to HOF data, if used.
return TryWriteSector ( sector , section - > data ) ;
}
2018-11-18 19:37:18 +01:00
static u8 TryWriteSector ( u8 sector , u8 * data )
2017-09-03 14:13:01 +02:00
{
if ( ProgramFlashSectorAndVerify ( sector , data ) ! = 0 ) // is damaged?
{
SetDamagedSectorBits ( ENABLE , sector ) ; // set damaged sector bits.
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_ERROR ;
2017-09-03 14:13:01 +02:00
}
else
{
SetDamagedSectorBits ( DISABLE , sector ) ; // unset damaged sector bits. it's safe now.
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_OK ;
2017-09-03 14:13:01 +02:00
}
}
2018-11-18 19:37:18 +01:00
static u32 RestoreSaveBackupVarsAndIncrement ( const struct SaveSectionLocation * location ) // location is unused
2017-09-03 14:13:01 +02:00
{
2017-09-03 15:39:33 +02:00
gFastSaveSection = & gSaveDataBuffer ;
2017-09-03 14:13:01 +02:00
gLastKnownGoodSector = gLastWrittenSector ;
gLastSaveCounter = gSaveCounter ;
gLastWrittenSector + + ;
2018-11-18 19:37:18 +01:00
gLastWrittenSector % = SECTOR_SAVE_SLOT_LENGTH ;
2017-09-03 14:13:01 +02:00
gSaveCounter + + ;
gUnknown_03006208 = 0 ;
gDamagedSaveSectors = 0 ;
return 0 ;
}
2018-11-18 19:37:18 +01:00
static u32 RestoreSaveBackupVars ( const struct SaveSectionLocation * location ) // only ever called once, and gSaveBlock2 is passed to this function. location is unused
2017-09-03 14:13:01 +02:00
{
2017-09-03 15:39:33 +02:00
gFastSaveSection = & gSaveDataBuffer ;
2017-09-03 14:13:01 +02:00
gLastKnownGoodSector = gLastWrittenSector ;
gLastSaveCounter = gSaveCounter ;
gUnknown_03006208 = 0 ;
gDamagedSaveSectors = 0 ;
return 0 ;
}
2020-01-12 21:27:37 +01:00
static u8 sub_81529D4 ( u16 sectorId , const struct SaveSectionLocation * location )
2017-09-03 14:13:01 +02:00
{
2020-01-12 21:27:37 +01:00
u8 status ;
2017-09-03 14:13:01 +02:00
2020-01-12 21:27:37 +01:00
if ( gUnknown_03006208 < sectorId - 1 )
2017-09-03 14:13:01 +02:00
{
2020-01-12 21:27:37 +01:00
status = SAVE_STATUS_OK ;
2017-09-03 14:13:01 +02:00
HandleWriteSector ( gUnknown_03006208 , location ) ;
gUnknown_03006208 + + ;
if ( gDamagedSaveSectors )
{
2020-01-12 21:27:37 +01:00
status = SAVE_STATUS_ERROR ;
2017-09-03 14:13:01 +02:00
gLastWrittenSector = gLastKnownGoodSector ;
gSaveCounter = gLastSaveCounter ;
}
}
else
{
2020-01-12 21:27:37 +01:00
status = SAVE_STATUS_ERROR ;
2017-09-03 14:13:01 +02:00
}
2020-01-12 21:27:37 +01:00
return status ;
2017-09-03 14:13:01 +02:00
}
2020-01-12 21:27:37 +01:00
static u8 sub_8152A34 ( u16 sectorId , const struct SaveSectionLocation * location )
2017-09-03 14:13:01 +02:00
{
2020-01-12 21:27:37 +01:00
u8 status = SAVE_STATUS_OK ;
2017-09-03 14:13:01 +02:00
2020-01-12 21:27:37 +01:00
ClearSaveData_2 ( sectorId - 1 , location ) ;
2017-09-03 14:13:01 +02:00
if ( gDamagedSaveSectors )
{
2020-01-12 21:27:37 +01:00
status = SAVE_STATUS_ERROR ;
2017-09-03 14:13:01 +02:00
gLastWrittenSector = gLastKnownGoodSector ;
gSaveCounter = gLastSaveCounter ;
}
2020-01-12 21:27:37 +01:00
return status ;
2017-09-03 14:13:01 +02:00
}
2020-01-12 21:27:37 +01:00
static u8 ClearSaveData_2 ( u16 sectorId , const struct SaveSectionLocation * location )
2017-09-03 14:13:01 +02:00
{
u16 i ;
u16 sector ;
u8 * data ;
u16 size ;
u8 status ;
2020-01-12 21:27:37 +01:00
sector = sectorId + gLastWrittenSector ;
2018-11-18 19:37:18 +01:00
sector % = SECTOR_SAVE_SLOT_LENGTH ;
2021-08-16 00:26:09 +02:00
sector + = SECTOR_SAVE_SLOT_LENGTH * ( gSaveCounter % NUM_SAVE_SLOTS ) ;
2017-09-03 14:13:01 +02:00
2020-01-12 21:27:37 +01:00
data = location [ sectorId ] . data ;
size = location [ sectorId ] . size ;
2017-09-03 14:13:01 +02:00
// clear temp save section.
for ( i = 0 ; i < sizeof ( struct SaveSection ) ; i + + )
( ( char * ) gFastSaveSection ) [ i ] = 0 ;
2020-01-12 21:27:37 +01:00
gFastSaveSection - > id = sectorId ;
2017-09-03 14:13:01 +02:00
gFastSaveSection - > security = UNKNOWN_CHECK_VALUE ;
gFastSaveSection - > counter = gSaveCounter ;
// set temp section's data.
for ( i = 0 ; i < size ; i + + )
gFastSaveSection - > data [ i ] = data [ i ] ;
// calculate checksum.
gFastSaveSection - > checksum = CalculateChecksum ( data , size ) ;
EraseFlashSector ( sector ) ;
2020-01-12 21:27:37 +01:00
status = SAVE_STATUS_OK ;
2017-09-03 14:13:01 +02:00
for ( i = 0 ; i < sizeof ( struct UnkSaveSection ) ; i + + )
{
if ( ProgramFlashByte ( sector , i , ( ( u8 * ) gFastSaveSection ) [ i ] ) )
{
2020-01-12 21:27:37 +01:00
status = SAVE_STATUS_ERROR ;
2017-09-03 14:13:01 +02:00
break ;
}
}
2020-01-12 21:27:37 +01:00
if ( status = = SAVE_STATUS_ERROR )
2017-09-03 14:13:01 +02:00
{
SetDamagedSectorBits ( ENABLE , sector ) ;
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_ERROR ;
2017-09-03 14:13:01 +02:00
}
else
{
2020-01-12 21:27:37 +01:00
status = SAVE_STATUS_OK ;
2017-09-03 14:13:01 +02:00
for ( i = 0 ; i < 7 ; i + + )
{
if ( ProgramFlashByte ( sector , 0xFF9 + i , ( ( u8 * ) gFastSaveSection ) [ 0xFF9 + i ] ) )
{
2020-01-12 21:27:37 +01:00
status = SAVE_STATUS_ERROR ;
2017-09-03 14:13:01 +02:00
break ;
}
}
2020-01-12 21:27:37 +01:00
if ( status = = SAVE_STATUS_ERROR )
2017-09-03 14:13:01 +02:00
{
SetDamagedSectorBits ( ENABLE , sector ) ;
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_ERROR ;
2017-09-03 14:13:01 +02:00
}
else
{
SetDamagedSectorBits ( DISABLE , sector ) ;
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_OK ;
2017-09-03 14:13:01 +02:00
}
}
}
2020-01-12 21:27:37 +01:00
static u8 sav12_xor_get ( u16 sectorId , const struct SaveSectionLocation * location )
2017-09-03 14:13:01 +02:00
{
u16 sector ;
2020-01-12 21:27:37 +01:00
sector = sectorId + gLastWrittenSector ; // no sub 1?
2018-11-18 19:37:18 +01:00
sector % = SECTOR_SAVE_SLOT_LENGTH ;
2021-08-16 00:26:09 +02:00
sector + = SECTOR_SAVE_SLOT_LENGTH * ( gSaveCounter % NUM_SAVE_SLOTS ) ;
2017-09-03 14:13:01 +02:00
if ( ProgramFlashByte ( sector , sizeof ( struct UnkSaveSection ) , 0x25 ) )
{
// sector is damaged, so enable the bit in gDamagedSaveSectors and restore the last written sector and save counter.
SetDamagedSectorBits ( ENABLE , sector ) ;
gLastWrittenSector = gLastKnownGoodSector ;
gSaveCounter = gLastSaveCounter ;
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_ERROR ;
2017-09-03 14:13:01 +02:00
}
else
{
SetDamagedSectorBits ( DISABLE , sector ) ;
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_OK ;
2017-09-03 14:13:01 +02:00
}
}
2020-01-12 21:27:37 +01:00
static u8 sub_8152CAC ( u16 sectorId , const struct SaveSectionLocation * location )
2017-09-03 14:13:01 +02:00
{
u16 sector ;
2020-01-12 21:27:37 +01:00
sector = sectorId + gLastWrittenSector - 1 ;
2018-11-18 19:37:18 +01:00
sector % = SECTOR_SAVE_SLOT_LENGTH ;
2021-08-16 00:26:09 +02:00
sector + = SECTOR_SAVE_SLOT_LENGTH * ( gSaveCounter % NUM_SAVE_SLOTS ) ;
2017-09-03 14:13:01 +02:00
if ( ProgramFlashByte ( sector , sizeof ( struct UnkSaveSection ) , ( ( u8 * ) gFastSaveSection ) [ sizeof ( struct UnkSaveSection ) ] ) )
{
// sector is damaged, so enable the bit in gDamagedSaveSectors and restore the last written sector and save counter.
SetDamagedSectorBits ( ENABLE , sector ) ;
gLastWrittenSector = gLastKnownGoodSector ;
gSaveCounter = gLastSaveCounter ;
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_ERROR ;
2017-09-03 14:13:01 +02:00
}
else
{
SetDamagedSectorBits ( DISABLE , sector ) ;
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_OK ;
2017-09-03 14:13:01 +02:00
}
}
2020-01-12 21:27:37 +01:00
static u8 sub_8152D44 ( u16 sectorId , const struct SaveSectionLocation * location )
2017-09-03 14:13:01 +02:00
{
u16 sector ;
2020-01-12 21:27:37 +01:00
sector = sectorId + gLastWrittenSector - 1 ; // no sub 1?
2018-11-18 19:37:18 +01:00
sector % = SECTOR_SAVE_SLOT_LENGTH ;
2021-08-16 00:26:09 +02:00
sector + = SECTOR_SAVE_SLOT_LENGTH * ( gSaveCounter % NUM_SAVE_SLOTS ) ;
2017-09-03 14:13:01 +02:00
if ( ProgramFlashByte ( sector , sizeof ( struct UnkSaveSection ) , 0x25 ) )
{
// sector is damaged, so enable the bit in gDamagedSaveSectors and restore the last written sector and save counter.
SetDamagedSectorBits ( ENABLE , sector ) ;
gLastWrittenSector = gLastKnownGoodSector ;
gSaveCounter = gLastSaveCounter ;
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_ERROR ;
2017-09-03 14:13:01 +02:00
}
else
{
SetDamagedSectorBits ( DISABLE , sector ) ;
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_OK ;
2017-09-03 14:13:01 +02:00
}
}
2018-11-18 19:37:18 +01:00
static u8 sub_8152DD0 ( u16 a1 , const struct SaveSectionLocation * location )
2017-09-03 14:13:01 +02:00
{
2020-01-12 21:27:37 +01:00
u8 status ;
2017-09-03 15:39:33 +02:00
gFastSaveSection = & gSaveDataBuffer ;
2017-09-03 14:13:01 +02:00
if ( a1 ! = 0xFFFF )
{
2020-01-12 21:27:37 +01:00
status = SAVE_STATUS_ERROR ;
2017-09-03 14:13:01 +02:00
}
else
{
2020-01-12 21:27:37 +01:00
status = GetSaveValidStatus ( location ) ;
2017-09-03 14:13:01 +02:00
sub_8152E10 ( 0xFFFF , location ) ;
}
2020-01-12 21:27:37 +01:00
return status ;
2017-09-03 14:13:01 +02:00
}
2018-11-18 19:37:18 +01:00
static u8 sub_8152E10 ( u16 a1 , const struct SaveSectionLocation * location )
2017-09-03 14:13:01 +02:00
{
u16 i ;
u16 checksum ;
2021-08-16 00:26:09 +02:00
u16 slotOffset = SECTOR_SAVE_SLOT_LENGTH * ( gSaveCounter % NUM_SAVE_SLOTS ) ;
2017-09-03 14:13:01 +02:00
u16 id ;
2018-11-18 19:37:18 +01:00
for ( i = 0 ; i < SECTOR_SAVE_SLOT_LENGTH ; i + + )
2017-09-03 14:13:01 +02:00
{
2021-08-16 00:26:09 +02:00
DoReadFlashWholeSection ( i + slotOffset , gFastSaveSection ) ;
2017-09-03 14:13:01 +02:00
id = gFastSaveSection - > id ;
if ( id = = 0 )
gLastWrittenSector = i ;
checksum = CalculateChecksum ( gFastSaveSection - > data , location [ id ] . size ) ;
if ( gFastSaveSection - > security = = UNKNOWN_CHECK_VALUE
& & gFastSaveSection - > checksum = = checksum )
{
u16 j ;
for ( j = 0 ; j < location [ id ] . size ; j + + )
( ( u8 * ) location [ id ] . data ) [ j ] = gFastSaveSection - > data [ j ] ;
}
}
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_OK ;
2017-09-03 14:13:01 +02:00
}
2018-11-18 19:37:18 +01:00
static u8 GetSaveValidStatus ( const struct SaveSectionLocation * location )
2017-09-03 14:13:01 +02:00
{
u16 i ;
u16 checksum ;
u32 saveSlot1Counter = 0 ;
u32 saveSlot2Counter = 0 ;
u32 slotCheckField = 0 ;
bool8 securityPassed = FALSE ;
u8 saveSlot1Status ;
u8 saveSlot2Status ;
// check save slot 1.
2018-11-18 19:37:18 +01:00
for ( i = 0 ; i < SECTOR_SAVE_SLOT_LENGTH ; i + + )
2017-09-03 14:13:01 +02:00
{
DoReadFlashWholeSection ( i , gFastSaveSection ) ;
if ( gFastSaveSection - > security = = UNKNOWN_CHECK_VALUE )
{
securityPassed = TRUE ;
checksum = CalculateChecksum ( gFastSaveSection - > data , location [ gFastSaveSection - > id ] . size ) ;
if ( gFastSaveSection - > checksum = = checksum )
{
saveSlot1Counter = gFastSaveSection - > counter ;
slotCheckField | = 1 < < gFastSaveSection - > id ;
}
}
}
if ( securityPassed )
{
if ( slotCheckField = = 0x3FFF )
2020-01-12 21:27:37 +01:00
saveSlot1Status = SAVE_STATUS_OK ;
2017-09-03 14:13:01 +02:00
else
2020-01-12 21:27:37 +01:00
saveSlot1Status = SAVE_STATUS_ERROR ;
2017-09-03 14:13:01 +02:00
}
else
{
2020-01-12 21:27:37 +01:00
saveSlot1Status = SAVE_STATUS_EMPTY ;
2017-09-03 14:13:01 +02:00
}
slotCheckField = 0 ;
securityPassed = FALSE ;
// check save slot 2.
2018-11-18 19:37:18 +01:00
for ( i = 0 ; i < SECTOR_SAVE_SLOT_LENGTH ; i + + )
2017-09-03 14:13:01 +02:00
{
2018-11-18 19:37:18 +01:00
DoReadFlashWholeSection ( i + SECTOR_SAVE_SLOT_LENGTH , gFastSaveSection ) ;
2017-09-03 14:13:01 +02:00
if ( gFastSaveSection - > security = = UNKNOWN_CHECK_VALUE )
{
securityPassed = TRUE ;
checksum = CalculateChecksum ( gFastSaveSection - > data , location [ gFastSaveSection - > id ] . size ) ;
if ( gFastSaveSection - > checksum = = checksum )
{
saveSlot2Counter = gFastSaveSection - > counter ;
slotCheckField | = 1 < < gFastSaveSection - > id ;
}
}
}
if ( securityPassed )
{
if ( slotCheckField = = 0x3FFF )
2020-01-12 21:27:37 +01:00
saveSlot2Status = SAVE_STATUS_OK ;
2017-09-03 14:13:01 +02:00
else
2020-01-12 21:27:37 +01:00
saveSlot2Status = SAVE_STATUS_ERROR ;
2017-09-03 14:13:01 +02:00
}
else
{
2020-01-12 21:27:37 +01:00
saveSlot2Status = SAVE_STATUS_EMPTY ;
2017-09-03 14:13:01 +02:00
}
2020-01-12 21:27:37 +01:00
if ( saveSlot1Status = = SAVE_STATUS_OK & & saveSlot2Status = = SAVE_STATUS_OK )
2017-09-03 14:13:01 +02:00
{
if ( ( saveSlot1Counter = = - 1 & & saveSlot2Counter = = 0 ) | | ( saveSlot1Counter = = 0 & & saveSlot2Counter = = - 1 ) )
{
if ( ( unsigned ) ( saveSlot1Counter + 1 ) < ( unsigned ) ( saveSlot2Counter + 1 ) )
gSaveCounter = saveSlot2Counter ;
else
gSaveCounter = saveSlot1Counter ;
}
else
{
if ( saveSlot1Counter < saveSlot2Counter )
gSaveCounter = saveSlot2Counter ;
else
gSaveCounter = saveSlot1Counter ;
}
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_OK ;
2017-09-03 14:13:01 +02:00
}
2020-01-12 21:27:37 +01:00
if ( saveSlot1Status = = SAVE_STATUS_OK )
2017-09-03 14:13:01 +02:00
{
gSaveCounter = saveSlot1Counter ;
2020-01-12 21:27:37 +01:00
if ( saveSlot2Status = = SAVE_STATUS_ERROR )
return SAVE_STATUS_ERROR ;
return SAVE_STATUS_OK ;
2017-09-03 14:13:01 +02:00
}
2020-01-12 21:27:37 +01:00
if ( saveSlot2Status = = SAVE_STATUS_OK )
2017-09-03 14:13:01 +02:00
{
gSaveCounter = saveSlot2Counter ;
2020-01-12 21:27:37 +01:00
if ( saveSlot1Status = = SAVE_STATUS_ERROR )
return SAVE_STATUS_ERROR ;
return SAVE_STATUS_OK ;
2017-09-03 14:13:01 +02:00
}
2020-01-12 21:27:37 +01:00
if ( saveSlot1Status = = SAVE_STATUS_EMPTY & & saveSlot2Status = = SAVE_STATUS_EMPTY )
2017-09-03 14:13:01 +02:00
{
gSaveCounter = 0 ;
gLastWrittenSector = 0 ;
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_EMPTY ;
2017-09-03 14:13:01 +02:00
}
gSaveCounter = 0 ;
gLastWrittenSector = 0 ;
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_CORRUPT ;
2017-09-03 14:13:01 +02:00
}
2020-01-12 21:27:37 +01:00
static u8 sub_81530DC ( u8 sectorId , u8 * data , u16 size )
2017-09-03 14:13:01 +02:00
{
u16 i ;
2017-09-03 15:39:33 +02:00
struct SaveSection * section = & gSaveDataBuffer ;
2020-01-12 21:27:37 +01:00
DoReadFlashWholeSection ( sectorId , section ) ;
2017-09-03 14:13:01 +02:00
if ( section - > security = = UNKNOWN_CHECK_VALUE )
{
u16 checksum = CalculateChecksum ( section - > data , size ) ;
if ( section - > id = = checksum )
{
for ( i = 0 ; i < size ; i + + )
data [ i ] = section - > data [ i ] ;
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_OK ;
2017-09-03 14:13:01 +02:00
}
else
{
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_CORRUPT ;
2017-09-03 14:13:01 +02:00
}
}
else
{
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_EMPTY ;
2017-09-03 14:13:01 +02:00
}
}
2020-01-12 21:27:37 +01:00
// Return value always ignored
static bool8 DoReadFlashWholeSection ( u8 sector , struct SaveSection * section )
2017-09-03 14:13:01 +02:00
{
ReadFlash ( sector , 0 , section - > data , sizeof ( struct SaveSection ) ) ;
2020-01-12 21:27:37 +01:00
return TRUE ;
2017-09-03 14:13:01 +02:00
}
Undo PokeCodec's PRs
This commit undoes most of PokeCodec's PRs after the debate in chat. Some
harmless or completely superseded PRs have been left alone, as there is not
much benefit in attempting to undo them.
Reverts #1104, #1108, #1115, #1118, #1119, #1124, #1126, #1127, #1132, #1136,
#1137, #1139, #1140, #1144, #1148, #1149, #1150, #1153, #1155, #1177, #1179,
#1180, #1181, #1182 and #1183.
2020-09-13 09:22:50 +02:00
static u16 CalculateChecksum ( void * data , u16 size )
2017-09-03 14:13:01 +02:00
{
u16 i ;
u32 checksum = 0 ;
for ( i = 0 ; i < ( size / 4 ) ; i + + )
2019-06-26 14:13:38 +02:00
{
checksum + = * ( ( u32 * ) data ) ;
data + = sizeof ( u32 ) ;
}
2017-09-03 14:13:01 +02:00
return ( ( checksum > > 16 ) + checksum ) ;
}
2018-11-18 19:37:18 +01:00
static void UpdateSaveAddresses ( void )
2017-09-03 14:13:01 +02:00
{
2017-09-03 15:39:33 +02:00
int i = 0 ;
2017-09-03 14:13:01 +02:00
2020-01-12 21:27:37 +01:00
gRamSaveSectionLocations [ i ] . data = ( void * ) ( gSaveBlock2Ptr ) + sSaveSectionOffsets [ i ] . toAdd ;
gRamSaveSectionLocations [ i ] . size = sSaveSectionOffsets [ i ] . size ;
2017-09-29 10:06:36 +02:00
2020-01-12 21:27:37 +01:00
for ( i = SECTOR_ID_SAVEBLOCK1_START ; i < = SECTOR_ID_SAVEBLOCK1_END ; i + + )
2017-09-03 14:13:01 +02:00
{
2020-01-12 21:27:37 +01:00
gRamSaveSectionLocations [ i ] . data = ( void * ) ( gSaveBlock1Ptr ) + sSaveSectionOffsets [ i ] . toAdd ;
gRamSaveSectionLocations [ i ] . size = sSaveSectionOffsets [ i ] . size ;
2017-09-03 14:13:01 +02:00
}
2020-10-24 04:12:09 +02:00
for ( ; i < = SECTOR_ID_PKMN_STORAGE_END ; i + + ) //setting i to SECTOR_ID_PKMN_STORAGE_START does not match
2017-09-03 14:13:01 +02:00
{
2020-01-12 21:27:37 +01:00
gRamSaveSectionLocations [ i ] . data = ( void * ) ( gPokemonStoragePtr ) + sSaveSectionOffsets [ i ] . toAdd ;
gRamSaveSectionLocations [ i ] . size = sSaveSectionOffsets [ i ] . size ;
2017-09-03 14:13:01 +02:00
}
}
u8 HandleSavingData ( u8 saveType )
{
u8 i ;
2019-03-01 07:49:11 +01:00
u32 * backupVar = gTrainerHillVBlankCounter ;
2017-09-03 14:13:01 +02:00
u8 * tempAddr ;
2019-03-01 07:49:11 +01:00
gTrainerHillVBlankCounter = NULL ;
2017-09-03 14:13:01 +02:00
UpdateSaveAddresses ( ) ;
switch ( saveType )
{
2018-02-15 23:54:34 +01:00
case SAVE_HALL_OF_FAME_ERASE_BEFORE : // deletes HOF before overwriting HOF completely. unused
2018-11-18 19:37:18 +01:00
for ( i = SECTOR_ID_HOF_1 ; i < SECTORS_COUNT ; i + + )
2017-09-03 14:13:01 +02:00
EraseFlashSector ( i ) ;
2018-02-15 23:54:34 +01:00
case SAVE_HALL_OF_FAME : // hall of fame.
2017-09-03 14:13:01 +02:00
if ( GetGameStat ( GAME_STAT_ENTERED_HOF ) < 999 )
IncrementGameStat ( GAME_STAT_ENTERED_HOF ) ;
SaveSerializedGame ( ) ;
2020-01-12 21:27:37 +01:00
SaveWriteToFlash ( 0xFFFF , gRamSaveSectionLocations ) ;
2018-02-15 23:54:34 +01:00
tempAddr = gDecompressionBuffer ;
2020-01-12 21:27:37 +01:00
HandleWriteSectorNBytes ( SECTOR_ID_HOF_1 , tempAddr , SECTOR_DATA_SIZE ) ;
HandleWriteSectorNBytes ( SECTOR_ID_HOF_2 , tempAddr + SECTOR_DATA_SIZE , SECTOR_DATA_SIZE ) ;
2017-09-03 14:13:01 +02:00
break ;
2018-02-15 23:54:34 +01:00
case SAVE_NORMAL : // normal save. also called by overwriting your own save.
2017-09-03 14:13:01 +02:00
default :
SaveSerializedGame ( ) ;
2020-01-12 21:27:37 +01:00
SaveWriteToFlash ( 0xFFFF , gRamSaveSectionLocations ) ;
2017-09-03 14:13:01 +02:00
break ;
2019-11-24 22:58:40 +01:00
case SAVE_LINK : // Link and Battle Frontier
case SAVE_LINK2 : // Unused
2017-09-03 14:13:01 +02:00
SaveSerializedGame ( ) ;
2020-01-12 21:27:37 +01:00
for ( i = SECTOR_ID_SAVEBLOCK2 ; i < = SECTOR_ID_SAVEBLOCK1_END ; i + + )
2017-09-03 14:13:01 +02:00
ClearSaveData_2 ( i , gRamSaveSectionLocations ) ;
2020-01-12 21:27:37 +01:00
for ( i = SECTOR_ID_SAVEBLOCK2 ; i < = SECTOR_ID_SAVEBLOCK1_END ; i + + )
2017-09-03 14:13:01 +02:00
sav12_xor_get ( i , gRamSaveSectionLocations ) ;
break ;
2018-11-18 19:37:18 +01:00
// Support for Ereader was removed in Emerald.
2017-09-03 14:13:01 +02:00
/*
case EREADER_SAVE : // used in mossdeep "game corner" before/after battling old man e-reader trainer
SaveSerializedGame ( ) ;
2020-01-12 21:27:37 +01:00
SaveWriteToFlash ( 0 , gRamSaveSectionLocations ) ;
2017-09-03 14:13:01 +02:00
break ;
*/
2018-02-15 23:54:34 +01:00
case SAVE_OVERWRITE_DIFFERENT_FILE :
2018-11-18 19:37:18 +01:00
for ( i = SECTOR_ID_HOF_1 ; i < SECTORS_COUNT ; i + + )
2017-09-03 14:13:01 +02:00
EraseFlashSector ( i ) ; // erase HOF.
SaveSerializedGame ( ) ;
2020-01-12 21:27:37 +01:00
SaveWriteToFlash ( 0xFFFF , gRamSaveSectionLocations ) ;
2017-09-03 14:13:01 +02:00
break ;
}
2019-03-01 07:49:11 +01:00
gTrainerHillVBlankCounter = backupVar ;
2017-09-03 14:13:01 +02:00
return 0 ;
}
2018-11-18 19:37:18 +01:00
u8 TrySavingData ( u8 saveType )
2017-09-03 14:13:01 +02:00
{
2018-10-30 21:45:26 +01:00
if ( gFlashMemoryPresent ! = TRUE )
2017-09-03 14:13:01 +02:00
{
2020-01-12 21:27:37 +01:00
gSaveAttemptStatus = SAVE_STATUS_ERROR ;
return SAVE_STATUS_ERROR ;
2017-09-03 14:13:01 +02:00
}
2018-10-30 21:45:26 +01:00
HandleSavingData ( saveType ) ;
if ( ! gDamagedSaveSectors )
{
2020-01-12 21:27:37 +01:00
gSaveAttemptStatus = SAVE_STATUS_OK ;
return SAVE_STATUS_OK ;
2018-10-30 21:45:26 +01:00
}
else
{
DoSaveFailedScreen ( saveType ) ;
2020-01-12 21:27:37 +01:00
gSaveAttemptStatus = SAVE_STATUS_ERROR ;
return SAVE_STATUS_ERROR ;
2018-10-30 21:45:26 +01:00
}
2017-09-03 14:13:01 +02:00
}
2020-01-12 21:27:37 +01:00
bool8 sub_8153380 ( void ) // trade.c
2017-09-03 14:13:01 +02:00
{
if ( gFlashMemoryPresent ! = TRUE )
2018-10-30 21:45:26 +01:00
return TRUE ;
2017-09-03 14:13:01 +02:00
UpdateSaveAddresses ( ) ;
SaveSerializedGame ( ) ;
RestoreSaveBackupVarsAndIncrement ( gRamSaveSectionLocations ) ;
2018-10-30 21:45:26 +01:00
return FALSE ;
2017-09-03 14:13:01 +02:00
}
2020-01-12 21:27:37 +01:00
bool8 sub_81533AC ( void ) // trade.c
2017-09-03 14:13:01 +02:00
{
2020-01-12 21:27:37 +01:00
u8 status = sub_81529D4 ( SECTOR_SAVE_SLOT_LENGTH , gRamSaveSectionLocations ) ;
2017-09-03 14:13:01 +02:00
if ( gDamagedSaveSectors )
2020-01-12 21:27:37 +01:00
DoSaveFailedScreen ( SAVE_NORMAL ) ;
if ( status = = SAVE_STATUS_ERROR )
2018-10-30 21:45:26 +01:00
return TRUE ;
2017-09-03 14:13:01 +02:00
else
2018-10-30 21:45:26 +01:00
return FALSE ;
2017-09-03 14:13:01 +02:00
}
2020-01-12 21:27:37 +01:00
bool8 sub_81533E0 ( void ) // trade.c
2017-09-03 14:13:01 +02:00
{
2018-11-18 19:37:18 +01:00
sub_8152A34 ( SECTOR_SAVE_SLOT_LENGTH , gRamSaveSectionLocations ) ;
2017-09-03 14:13:01 +02:00
if ( gDamagedSaveSectors )
2020-01-12 21:27:37 +01:00
DoSaveFailedScreen ( SAVE_NORMAL ) ;
return FALSE ;
2017-09-03 14:13:01 +02:00
}
2020-01-12 21:27:37 +01:00
bool8 sub_8153408 ( void ) // trade.c
2017-09-03 14:13:01 +02:00
{
2018-11-18 19:37:18 +01:00
sub_8152CAC ( SECTOR_SAVE_SLOT_LENGTH , gRamSaveSectionLocations ) ;
2017-09-03 14:13:01 +02:00
if ( gDamagedSaveSectors )
2020-01-12 21:27:37 +01:00
DoSaveFailedScreen ( SAVE_NORMAL ) ;
return FALSE ;
2017-09-03 14:13:01 +02:00
}
2019-02-11 02:42:50 +01:00
u8 FullSaveGame ( void )
2017-09-03 14:13:01 +02:00
{
if ( gFlashMemoryPresent ! = TRUE )
2020-01-12 21:27:37 +01:00
return TRUE ;
2017-09-03 14:13:01 +02:00
UpdateSaveAddresses ( ) ;
SaveSerializedGame ( ) ;
RestoreSaveBackupVars ( gRamSaveSectionLocations ) ;
sub_8152A34 ( gUnknown_03006208 + 1 , gRamSaveSectionLocations ) ;
2020-01-12 21:27:37 +01:00
return FALSE ;
2017-09-03 14:13:01 +02:00
}
2019-02-11 02:42:50 +01:00
bool8 CheckSaveFile ( void )
2017-09-03 14:13:01 +02:00
{
u8 retVal = FALSE ;
2020-01-12 21:27:37 +01:00
u16 sectorId = + + gUnknown_03006208 ;
if ( sectorId < = SECTOR_ID_SAVEBLOCK1_END )
2017-09-03 14:13:01 +02:00
{
sub_8152A34 ( gUnknown_03006208 + 1 , gRamSaveSectionLocations ) ;
2020-01-12 21:27:37 +01:00
sub_8152D44 ( sectorId , gRamSaveSectionLocations ) ;
2017-09-03 14:13:01 +02:00
}
else
{
2020-01-12 21:27:37 +01:00
sub_8152D44 ( sectorId , gRamSaveSectionLocations ) ;
2017-09-03 14:13:01 +02:00
retVal = TRUE ;
}
if ( gDamagedSaveSectors )
2020-01-12 21:27:37 +01:00
DoSaveFailedScreen ( SAVE_LINK ) ;
2017-09-03 14:13:01 +02:00
return retVal ;
}
2020-01-12 21:27:37 +01:00
u8 Save_LoadGameData ( u8 saveType )
2017-09-03 14:13:01 +02:00
{
2020-01-12 21:27:37 +01:00
u8 status ;
2017-09-03 14:13:01 +02:00
if ( gFlashMemoryPresent ! = TRUE )
{
2020-01-12 21:27:37 +01:00
gSaveFileStatus = SAVE_STATUS_NO_FLASH ;
return SAVE_STATUS_ERROR ;
2017-09-03 14:13:01 +02:00
}
UpdateSaveAddresses ( ) ;
2020-01-12 21:27:37 +01:00
switch ( saveType )
2017-09-03 14:13:01 +02:00
{
2020-01-12 21:27:37 +01:00
case SAVE_NORMAL :
2017-09-03 14:13:01 +02:00
default :
2020-01-12 21:27:37 +01:00
status = sub_8152DD0 ( 0xFFFF , gRamSaveSectionLocations ) ;
2017-09-03 14:13:01 +02:00
LoadSerializedGame ( ) ;
2020-01-12 21:27:37 +01:00
gSaveFileStatus = status ;
2017-09-03 14:13:01 +02:00
gGameContinueCallback = 0 ;
break ;
2020-01-12 21:27:37 +01:00
case SAVE_HALL_OF_FAME :
status = sub_81530DC ( SECTOR_ID_HOF_1 , gDecompressionBuffer , SECTOR_DATA_SIZE ) ;
if ( status = = SAVE_STATUS_OK )
status = sub_81530DC ( SECTOR_ID_HOF_2 , gDecompressionBuffer + SECTOR_DATA_SIZE , SECTOR_DATA_SIZE ) ;
2017-09-03 14:13:01 +02:00
break ;
}
2020-01-12 21:27:37 +01:00
return status ;
2017-09-03 14:13:01 +02:00
}
2017-09-03 15:39:33 +02:00
2021-08-16 00:26:09 +02:00
u16 GetSaveBlocksPointersBaseOffset ( void )
2017-09-03 15:39:33 +02:00
{
2021-08-16 00:26:09 +02:00
u16 i , slotOffset ;
2017-09-03 15:39:33 +02:00
struct SaveSection * savSection ;
savSection = gFastSaveSection = & gSaveDataBuffer ;
2018-04-29 14:21:59 +02:00
if ( gFlashMemoryPresent ! = TRUE )
2021-08-16 00:26:09 +02:00
return 0 ;
2017-09-03 15:39:33 +02:00
UpdateSaveAddresses ( ) ;
GetSaveValidStatus ( gRamSaveSectionLocations ) ;
2021-08-16 00:26:09 +02:00
slotOffset = SECTOR_SAVE_SLOT_LENGTH * ( gSaveCounter % NUM_SAVE_SLOTS ) ;
2018-11-18 19:37:18 +01:00
for ( i = 0 ; i < SECTOR_SAVE_SLOT_LENGTH ; i + + )
2017-09-03 15:39:33 +02:00
{
2021-08-16 00:26:09 +02:00
DoReadFlashWholeSection ( i + slotOffset , gFastSaveSection ) ;
// Base offset for SaveBlock2 is calculated using the trainer id
if ( gFastSaveSection - > id = = SECTOR_ID_SAVEBLOCK2 )
return savSection - > data [ offsetof ( struct SaveBlock2 , playerTrainerId [ 0 ] ) ] +
savSection - > data [ offsetof ( struct SaveBlock2 , playerTrainerId [ 1 ] ) ] +
savSection - > data [ offsetof ( struct SaveBlock2 , playerTrainerId [ 2 ] ) ] +
savSection - > data [ offsetof ( struct SaveBlock2 , playerTrainerId [ 3 ] ) ] ;
2017-09-03 15:39:33 +02:00
}
2021-08-16 00:26:09 +02:00
return 0 ;
2017-09-03 15:39:33 +02:00
}
2019-04-04 17:55:18 +02:00
u32 TryReadSpecialSaveSection ( u8 sector , u8 * dst )
2017-09-03 15:39:33 +02:00
{
s32 i ;
s32 size ;
u8 * savData ;
2018-11-18 19:37:18 +01:00
if ( sector ! = SECTOR_ID_TRAINER_HILL & & sector ! = SECTOR_ID_RECORDED_BATTLE )
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_ERROR ;
2017-10-07 05:30:35 +02:00
ReadFlash ( sector , 0 , ( u8 * ) & gSaveDataBuffer , sizeof ( struct SaveSection ) ) ;
2019-04-04 17:55:18 +02:00
if ( * ( u32 * ) ( & gSaveDataBuffer . data [ 0 ] ) ! = SPECIAL_SECTION_SENTINEL )
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_ERROR ;
2017-09-03 15:39:33 +02:00
// copies whole save section except u32 counter
i = 0 ;
size = 0xFFB ;
savData = & gSaveDataBuffer . data [ 4 ] ;
for ( ; i < = size ; i + + )
dst [ i ] = savData [ i ] ;
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_OK ;
2017-09-03 15:39:33 +02:00
}
2019-04-04 17:55:18 +02:00
u32 TryWriteSpecialSaveSection ( u8 sector , u8 * src )
2017-09-03 15:39:33 +02:00
{
s32 i ;
s32 size ;
u8 * savData ;
void * savDataBuffer ;
2019-04-04 17:55:18 +02:00
if ( sector ! = SECTOR_ID_TRAINER_HILL & & sector ! = SECTOR_ID_RECORDED_BATTLE )
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_ERROR ;
2017-11-13 18:07:23 +01:00
2017-09-03 15:39:33 +02:00
savDataBuffer = & gSaveDataBuffer ;
2019-04-04 17:55:18 +02:00
* ( u32 * ) ( savDataBuffer ) = SPECIAL_SECTION_SENTINEL ;
2017-09-03 15:39:33 +02:00
// copies whole save section except u32 counter
i = 0 ;
size = 0xFFB ;
savData = & gSaveDataBuffer . data [ 4 ] ;
for ( ; i < = size ; i + + )
savData [ i ] = src [ i ] ;
if ( ProgramFlashSectorAndVerify ( sector , savDataBuffer ) ! = 0 )
2020-01-12 21:27:37 +01:00
return SAVE_STATUS_ERROR ;
return SAVE_STATUS_OK ;
2017-09-03 15:39:33 +02:00
}
2017-09-29 10:06:36 +02:00
2020-06-04 00:00:53 +02:00
# define tState data[0]
# define tTimer data[1]
# define tPartialSave data[2]
void Task_LinkSave ( u8 taskId )
2017-09-29 10:06:36 +02:00
{
2020-06-04 00:00:53 +02:00
s16 * data = gTasks [ taskId ] . data ;
2017-09-29 10:06:36 +02:00
2020-06-04 00:00:53 +02:00
switch ( tState )
2017-09-29 10:06:36 +02:00
{
case 0 :
gSoftResetDisabled = TRUE ;
2020-06-04 00:00:53 +02:00
tState = 1 ;
2017-09-29 10:06:36 +02:00
break ;
case 1 :
2020-08-13 09:09:47 +02:00
SetLinkStandbyCallback ( ) ;
2020-06-04 00:00:53 +02:00
tState = 2 ;
2017-09-29 10:06:36 +02:00
break ;
case 2 :
2018-12-31 09:22:21 +01:00
if ( IsLinkTaskFinished ( ) )
2017-09-29 10:06:36 +02:00
{
2020-06-04 00:00:53 +02:00
if ( ! tPartialSave )
2021-04-06 22:05:43 +02:00
SaveMapView ( ) ;
2020-06-04 00:00:53 +02:00
tState = 3 ;
2017-09-29 10:06:36 +02:00
}
break ;
case 3 :
2020-06-04 00:00:53 +02:00
if ( ! tPartialSave )
2018-12-27 23:30:47 +01:00
SetContinueGameWarpStatusToDynamicWarp ( ) ;
2017-09-29 10:06:36 +02:00
sub_8153380 ( ) ;
2020-06-04 00:00:53 +02:00
tState = 4 ;
2017-09-29 10:06:36 +02:00
break ;
case 4 :
2020-06-04 00:00:53 +02:00
if ( + + tTimer = = 5 )
2017-09-29 10:06:36 +02:00
{
2020-06-04 00:00:53 +02:00
tTimer = 0 ;
tState = 5 ;
2017-09-29 10:06:36 +02:00
}
break ;
case 5 :
if ( sub_81533AC ( ) )
2020-06-04 00:00:53 +02:00
tState = 6 ;
2017-09-29 10:06:36 +02:00
else
2020-06-04 00:00:53 +02:00
tState = 4 ;
2017-09-29 10:06:36 +02:00
break ;
case 6 :
sub_81533E0 ( ) ;
2020-06-04 00:00:53 +02:00
tState = 7 ;
2017-09-29 10:06:36 +02:00
break ;
case 7 :
2020-06-04 00:00:53 +02:00
if ( ! tPartialSave )
2018-12-27 23:30:47 +01:00
ClearContinueGameWarpStatus2 ( ) ;
2020-08-13 09:09:47 +02:00
SetLinkStandbyCallback ( ) ;
2020-06-04 00:00:53 +02:00
tState = 8 ;
2017-09-29 10:06:36 +02:00
break ;
case 8 :
2018-12-31 09:22:21 +01:00
if ( IsLinkTaskFinished ( ) )
2017-09-29 10:06:36 +02:00
{
sub_8153408 ( ) ;
2020-06-04 00:00:53 +02:00
tState = 9 ;
2017-09-29 10:06:36 +02:00
}
break ;
case 9 :
2020-08-13 09:09:47 +02:00
SetLinkStandbyCallback ( ) ;
2020-06-04 00:00:53 +02:00
tState = 10 ;
2017-09-29 10:06:36 +02:00
break ;
case 10 :
2018-12-31 09:22:21 +01:00
if ( IsLinkTaskFinished ( ) )
2020-06-04 00:00:53 +02:00
tState + + ;
2017-09-29 10:06:36 +02:00
break ;
case 11 :
2020-06-04 00:00:53 +02:00
if ( + + tTimer > 5 )
2017-09-29 10:06:36 +02:00
{
gSoftResetDisabled = FALSE ;
DestroyTask ( taskId ) ;
}
break ;
}
}
2020-06-04 00:00:53 +02:00
# undef tState
# undef tTimer
# undef tPartialSave