SaveMenu: call LoadStandardMenuHeader lb de, 4, 0 farcall DisplayNormalContinueData call SpeechTextbox call UpdateSprites farcall SaveMenu_CopyTilemapAtOnce ld hl, WouldYouLikeToSaveTheGameText call SaveTheGame_yesorno jr nz, .refused call AskOverwriteSaveFile jr c, .refused call PauseGameLogic call SavingDontTurnOffThePower call ResumeGameLogic call ExitMenu and a ret .refused call ExitMenu call ReloadPalettes farcall SaveMenu_CopyTilemapAtOnce scf ret SaveAfterLinkTrade: call PauseGameLogic farcall StageRTCTimeForSave farcall BackupMysteryGift call SavePokemonData call SaveChecksum call SaveBackupPokemonData call SaveBackupChecksum farcall BackupPartyMonMail farcall SaveRTC call ResumeGameLogic ret ChangeBoxSaveGame: push de ld hl, ChangeBoxSaveText call MenuTextbox call YesNoBox call ExitMenu jr c, .refused call AskOverwriteSaveFile jr c, .refused call PauseGameLogic call SaveBox pop de ld a, e ld [wCurBox], a call LoadBox call SavingDontTurnOffThePower call ResumeGameLogic and a ret .refused pop de ret Link_SaveGame: call AskOverwriteSaveFile jr c, .refused call PauseGameLogic call SavingDontTurnOffThePower call ResumeGameLogic and a .refused ret MoveMonWOMail_SaveGame: call PauseGameLogic push de call SaveBox pop de ld a, e ld [wCurBox], a call LoadBox call ResumeGameLogic ret MoveMonWOMail_InsertMon_SaveGame: call PauseGameLogic push de call SaveBox pop de ld a, e ld [wCurBox], a ld a, TRUE ld [wSaveFileExists], a farcall StageRTCTimeForSave farcall BackupMysteryGift call ValidateSave call SaveOptions call SavePlayerData call SavePokemonData call SaveChecksum call ValidateBackupSave call SaveBackupOptions call SaveBackupPlayerData call SaveBackupPokemonData call SaveBackupChecksum farcall BackupPartyMonMail farcall SaveRTC call LoadBox call ResumeGameLogic ld de, SFX_SAVE call PlaySFX ld c, 24 call DelayFrames ret StartMoveMonWOMail_SaveGame: ld hl, MoveMonWOMailSaveText call MenuTextbox call YesNoBox call ExitMenu jr c, .refused call AskOverwriteSaveFile jr c, .refused call PauseGameLogic call SavingDontTurnOffThePower call ResumeGameLogic and a ret .refused scf ret PauseGameLogic: ld a, TRUE ld [wGameLogicPaused], a ret ResumeGameLogic: xor a ; FALSE ld [wGameLogicPaused], a ret AddHallOfFameEntry: ld a, BANK(sHallOfFame) call OpenSRAM ld hl, sHallOfFame + HOF_LENGTH * (NUM_HOF_TEAMS - 1) - 1 ld de, sHallOfFame + HOF_LENGTH * NUM_HOF_TEAMS - 1 ld bc, HOF_LENGTH * (NUM_HOF_TEAMS - 1) .loop ld a, [hld] ld [de], a dec de dec bc ld a, c or b jr nz, .loop ld hl, wHallOfFamePokemonList ld de, sHallOfFame ld bc, wHallOfFamePokemonListEnd - wHallOfFamePokemonList + 1 call CopyBytes call CloseSRAM ret SaveGameData: call _SaveGameData ret AskOverwriteSaveFile: ld a, [wSaveFileExists] and a jr z, .erase call CompareLoadedAndSavedPlayerID jr z, .yoursavefile ld hl, AnotherSaveFileText call SaveTheGame_yesorno jr nz, .refused jr .erase .yoursavefile ld hl, AlreadyASaveFileText call SaveTheGame_yesorno jr nz, .refused jr .ok .erase call ErasePreviousSave .ok and a ret .refused scf ret SaveTheGame_yesorno: ld b, BANK(WouldYouLikeToSaveTheGameText) call MapTextbox call LoadMenuTextbox lb bc, 0, 7 call PlaceYesNoBox ld a, [wMenuCursorY] dec a call CloseWindow push af call ReloadPalettes pop af and a ret CompareLoadedAndSavedPlayerID: ld a, BANK(sPlayerData) call OpenSRAM ld hl, sPlayerData + (wPlayerID - wPlayerData) ld a, [hli] ld c, [hl] ld b, a call CloseSRAM ld a, [wPlayerID] cp b ret nz ld a, [wPlayerID + 1] cp c ret SavingDontTurnOffThePower: ; Prevent joypad interrupts xor a ldh [hJoypadReleased], a ldh [hJoypadPressed], a ldh [hJoypadSum], a ldh [hJoypadDown], a ; Save the text speed setting to the stack ld a, [wOptions] push af ; Set the text speed to medium ld a, TEXT_DELAY_MED ld [wOptions], a ; SAVING... DON'T TURN OFF THE POWER. ld hl, SavingDontTurnOffThePowerText call PrintText ; Restore the text speed setting pop af ld [wOptions], a ; Wait for 16 frames ld c, 16 call DelayFrames call _SaveGameData ; wait 32 frames ld c, 32 call DelayFrames ; copy the original text speed setting to the stack ld a, [wOptions] push af ; set text speed to medium ld a, TEXT_DELAY_MED ld [wOptions], a ; saved the game! ld hl, SavedTheGameText call PrintText ; restore the original text speed setting pop af ld [wOptions], a ld de, SFX_SAVE call WaitPlaySFX call WaitSFX ; wait 30 frames ld c, 30 call DelayFrames ret _SaveGameData: ld a, TRUE ld [wSaveFileExists], a farcall StageRTCTimeForSave farcall BackupMysteryGift call ValidateSave call SaveOptions call SavePlayerData call SavePokemonData call SaveBox call SaveChecksum call ValidateBackupSave call SaveBackupOptions call SaveBackupPlayerData call SaveBackupPokemonData call SaveBackupChecksum call UpdateStackTop farcall BackupPartyMonMail farcall SaveRTC ret UpdateStackTop: ; sStackTop appears to be unused. ; It could have been used to debug stack overflow during saving. call FindStackTop ld a, BANK(sStackTop) call OpenSRAM ld a, [sStackTop + 0] ld e, a ld a, [sStackTop + 1] ld d, a or e jr z, .update ld a, e sub l ld a, d sbc h jr c, .done .update ld a, l ld [sStackTop + 0], a ld a, h ld [sStackTop + 1], a .done call CloseSRAM ret FindStackTop: ; Find the furthest point that sp has traversed to. ; This is distinct from the current value of sp. ld hl, wStackBottom .loop ld a, [hl] or a ret nz inc hl jr .loop ErasePreviousSave: call EraseBoxes call EraseHallOfFame call EraseLinkBattleStats call EraseMysteryGift ld a, BANK(sStackTop) call OpenSRAM xor a ld [sStackTop + 0], a ld [sStackTop + 1], a call CloseSRAM ld a, $1 ld [wSavedAtLeastOnce], a ret EraseLinkBattleStats: ld a, BANK(sLinkBattleStats) call OpenSRAM ld hl, sLinkBattleStats ld bc, sLinkBattleStatsEnd - sLinkBattleStats xor a call ByteFill jp CloseSRAM EraseMysteryGift: ld a, BANK(sBackupMysteryGiftItem) call OpenSRAM ld hl, sBackupMysteryGiftItem ld bc, sBackupMysteryGiftItemEnd - sBackupMysteryGiftItem xor a call ByteFill jp CloseSRAM EraseHallOfFame: ld a, BANK(sHallOfFame) call OpenSRAM ld hl, sHallOfFame ld bc, sHallOfFameEnd - sHallOfFame xor a call ByteFill jp CloseSRAM ValidateSave: ld a, BANK(sCheckValue1) ; aka BANK(sCheckValue2) call OpenSRAM ld a, SAVE_CHECK_VALUE_1 ld [sCheckValue1], a ld a, SAVE_CHECK_VALUE_2 ld [sCheckValue2], a jp CloseSRAM SaveOptions: ld a, BANK(sOptions) call OpenSRAM ld hl, wOptions ld de, sOptions ld bc, wOptionsEnd - wOptions call CopyBytes ld a, [wOptions] and ~(1 << NO_TEXT_SCROLL) ld [sOptions], a jp CloseSRAM SavePlayerData: ld a, BANK(sPlayerData) call OpenSRAM ld hl, wPlayerData ld de, sPlayerData ld bc, wPlayerDataEnd - wPlayerData call CopyBytes ld hl, wCurMapData ld de, sCurMapData ld bc, wCurMapDataEnd - wCurMapData call CopyBytes jp CloseSRAM SavePokemonData: ld a, BANK(sPokemonData) call OpenSRAM ld hl, wPokemonData ld de, sPokemonData ld bc, wPokemonDataEnd - wPokemonData call CopyBytes call CloseSRAM ret SaveBox: call GetBoxAddress call SaveBoxAddress ret SaveChecksum: ld hl, sGameData ld bc, sGameDataEnd - sGameData ld a, BANK(sGameData) call OpenSRAM call Checksum ld a, e ld [sChecksum + 0], a ld a, d ld [sChecksum + 1], a call CloseSRAM ret ValidateBackupSave: ld a, BANK(sBackupCheckValue1) ; aka BANK(sBackupCheckValue2) call OpenSRAM ld a, SAVE_CHECK_VALUE_1 ld [sBackupCheckValue1], a ld a, SAVE_CHECK_VALUE_2 ld [sBackupCheckValue2], a call CloseSRAM ret SaveBackupOptions: ld a, BANK(sBackupOptions) call OpenSRAM ld hl, wOptions ld de, sBackupOptions ld bc, wOptionsEnd - wOptions call CopyBytes call CloseSRAM ret SaveBackupPlayerData: ld a, BANK(sBackupPlayerData3) call OpenSRAM ld hl, wPlayerData3 ld de, sBackupPlayerData3 ld bc, wPlayerData3End - wPlayerData3 call CopyBytes ld a, BANK(sBackupPlayerData1) call OpenSRAM ld hl, wPlayerData1 ld de, sBackupPlayerData1 ld bc, wPlayerData1End - wPlayerData1 call CopyBytes ld a, BANK(sBackupPlayerData2) call OpenSRAM ld hl, wPlayerData2 ld de, sBackupPlayerData2 ld bc, wPlayerData2End - wPlayerData2 call CopyBytes ld a, BANK(sBackupCurMapData) call OpenSRAM ld hl, wCurMapData ld de, sBackupCurMapData ld bc, wCurMapDataEnd - wCurMapData call CopyBytes call CloseSRAM ret SaveBackupPokemonData: ld a, BANK(sBackupPokemonData) call OpenSRAM ld hl, wPokemonData ld de, sBackupPokemonData ld bc, wPokemonDataEnd - wPokemonData call CopyBytes call CloseSRAM ret SaveBackupChecksum: ld a, BANK(sBackupPlayerData3) call OpenSRAM ld hl, sBackupPlayerData3 ld bc, wPlayerData3End - wPlayerData3 call Checksum push de ld hl, sBackupPokemonData ld bc, wPokemonDataEnd - wPokemonData call Checksum pop hl add hl, de ld a, BANK(sBackupPlayerData1) call OpenSRAM push hl ld hl, sBackupPlayerData1 ld bc, wPlayerData1End - wPlayerData1 call Checksum pop hl add hl, de ld a, BANK(sBackupPlayerData2) call OpenSRAM push hl ld hl, sBackupPlayerData2 ld bc, wPlayerData2End - wPlayerData2 call Checksum pop hl add hl, de ld a, BANK(sBackupCurMapData) call OpenSRAM push hl ld hl, sBackupCurMapData ld bc, wCurMapDataEnd - wCurMapData call Checksum pop hl add hl, de ld a, l ld [sBackupChecksum + 0], a ld a, h ld [sBackupChecksum + 1], a call CloseSRAM ret TryLoadSaveFile: call VerifyChecksum jr nz, .backup call LoadPlayerData call LoadPokemonData call LoadBox farcall RestorePartyMonMail farcall RestoreMysteryGift call ValidateBackupSave call SaveBackupOptions call SaveBackupPlayerData call SaveBackupPokemonData call SaveBackupChecksum and a ret .backup call VerifyBackupChecksum jr nz, .corrupt call LoadBackupPlayerData call LoadBackupPokemonData call LoadBox farcall RestorePartyMonMail farcall RestoreMysteryGift call ValidateSave call SaveOptions call SavePlayerData call SavePokemonData call SaveChecksum and a ret .corrupt ld a, [wOptions] push af set NO_TEXT_SCROLL, a ld [wOptions], a ld hl, SaveFileCorruptedText call PrintText pop af ld [wOptions], a scf ret TryLoadSaveData: xor a ; FALSE ld [wSaveFileExists], a call CheckPrimarySaveFile ld a, [wSaveFileExists] and a jr z, .backup ld a, BANK(sPlayerData) call OpenSRAM ld hl, sPlayerData + wStartDay - wPlayerData ld de, wStartDay ld bc, 14 call CopyBytes call CloseSRAM ret .backup call CheckBackupSaveFile ld a, [wSaveFileExists] and a jr z, .corrupt ld a, BANK(sBackupPlayerData1) call OpenSRAM ld hl, sBackupPlayerData1 + wStartDay - wPlayerData ld de, wStartDay ld bc, 14 call CopyBytes call CloseSRAM ret .corrupt ld hl, DefaultOptions ld de, wOptions ld bc, wOptionsEnd - wOptions call CopyBytes call ClearClock ret INCLUDE "data/default_options.asm" CheckPrimarySaveFile: ld a, BANK(sCheckValue1) ; aka BANK(sCheckValue2) call OpenSRAM ld a, [sCheckValue1] cp SAVE_CHECK_VALUE_1 jr nz, .nope ld a, [sCheckValue2] cp SAVE_CHECK_VALUE_2 jr nz, .nope ld hl, sOptions ld de, wOptions ld bc, wOptionsEnd - wOptions call CopyBytes call CloseSRAM call CheckTextDelay ld a, TRUE ld [wSaveFileExists], a .nope call CloseSRAM ret CheckBackupSaveFile: ld a, BANK(sBackupCheckValue1) ; aka BANK(sBackupCheckValue2) call OpenSRAM ld a, [sBackupCheckValue1] cp SAVE_CHECK_VALUE_1 jr nz, .nope ld a, [sBackupCheckValue2] cp SAVE_CHECK_VALUE_2 jr nz, .nope ld hl, sBackupOptions ld de, wOptions ld bc, wOptionsEnd - wOptions call CopyBytes call CheckTextDelay ld a, $2 ld [wSaveFileExists], a .nope call CloseSRAM ret CheckTextDelay: ; Fix options if text delay is invalid ld hl, wTextboxFlags res NO_TEXT_DELAY_F, [hl] ld a, [wOptions] and TEXT_DELAY_MASK cp TEXT_DELAY_FAST ret z cp TEXT_DELAY_MED ret z cp TEXT_DELAY_SLOW ret z ld a, [wOptions] and ~TEXT_DELAY_MASK or (1 << FAST_TEXT_DELAY_F) | (1 << NO_TEXT_DELAY_F) ld [wOptions], a ret LoadPlayerData: ld a, BANK(sPlayerData) call OpenSRAM ld hl, sPlayerData ld de, wPlayerData ld bc, wPlayerDataEnd - wPlayerData call CopyBytes ld hl, sCurMapData ld de, wCurMapData ld bc, wCurMapDataEnd - wCurMapData call CopyBytes call CloseSRAM ret LoadPokemonData: ld a, BANK(sPokemonData) call OpenSRAM ld hl, sPokemonData ld de, wPokemonData ld bc, wPokemonDataEnd - wPokemonData call CopyBytes call CloseSRAM ret LoadBox: call GetBoxAddress call LoadBoxAddress ret VerifyChecksum: ld hl, sGameData ld bc, sGameDataEnd - sGameData ld a, BANK(sGameData) call OpenSRAM call Checksum ld a, [sChecksum + 0] cp e jr nz, .fail ld a, [sChecksum + 1] cp d .fail push af call CloseSRAM pop af ret LoadBackupPlayerData: ld a, BANK(sBackupPlayerData3) call OpenSRAM ld hl, sBackupPlayerData3 ld de, wPlayerData3 ld bc, wPlayerData3End - wPlayerData3 call CopyBytes ld a, BANK(sBackupPlayerData1) call OpenSRAM ld hl, sBackupPlayerData1 ld de, wPlayerData1 ld bc, wPlayerData1End - wPlayerData1 call CopyBytes ld a, BANK(sBackupPlayerData2) call OpenSRAM ld hl, sBackupPlayerData2 ld de, wPlayerData2 ld bc, wPlayerData2End - wPlayerData2 call CopyBytes ld a, BANK(sBackupCurMapData) call OpenSRAM ld hl, sBackupCurMapData ld de, wCurMapData ld bc, wCurMapDataEnd - wCurMapData call CopyBytes call CloseSRAM ret LoadBackupPokemonData: ld a, BANK(sBackupPokemonData) call OpenSRAM ld hl, sBackupPokemonData ld de, wPokemonData ld bc, wPokemonDataEnd - wPokemonData call CopyBytes call CloseSRAM ret VerifyBackupChecksum: ld a, BANK(sBackupPokemonData) call OpenSRAM ld hl, sBackupPokemonData ld bc, wPokemonDataEnd - wPokemonData call Checksum push de ld hl, sBackupPlayerData3 ld bc, wPlayerData3End - wPlayerData3 call Checksum pop hl add hl, de ld a, BANK(sBackupPlayerData1) call OpenSRAM push hl ld hl, sBackupPlayerData1 ld bc, wPlayerData1End - wPlayerData1 call Checksum pop hl add hl, de ld a, BANK(sBackupPlayerData2) call OpenSRAM push hl ld hl, sBackupPlayerData2 ld bc, wPlayerData2End - wPlayerData2 call Checksum pop hl add hl, de ld a, BANK(sBackupCurMapData) call OpenSRAM push hl ld hl, sBackupCurMapData ld bc, wCurMapDataEnd - wCurMapData call Checksum pop hl add hl, de ld d, h ld e, l ld a, [sBackupChecksum + 0] cp e jr nz, .fail ld a, [sBackupChecksum + 1] cp d .fail push af call CloseSRAM pop af ret GetBoxAddress: ld a, [wCurBox] cp NUM_BOXES jr c, .ok xor a ld [wCurBox], a .ok ld e, a ld d, 0 ld hl, BoxAddresses rept 5 add hl, de endr ld a, [hli] push af ld a, [hli] ld e, a ld a, [hli] ld d, a ld a, [hli] ld h, [hl] ld l, a pop af ret SaveBoxAddress: ; Save box via wBoxPartialData. ; We do this in three steps because the size of wBoxPartialData is less than ; the size of sBox. push hl ; Load the first part of the active box. push af push de ld a, BANK(sBox) call OpenSRAM ld hl, sBox ld de, wBoxPartialData ld bc, (wBoxPartialDataEnd - wBoxPartialData) call CopyBytes call CloseSRAM pop de pop af ; Save it to the target box. push af push de call OpenSRAM ld hl, wBoxPartialData ld bc, (wBoxPartialDataEnd - wBoxPartialData) call CopyBytes call CloseSRAM ; Load the second part of the active box. ld a, BANK(sBox) call OpenSRAM ld hl, sBox + (wBoxPartialDataEnd - wBoxPartialData) ld de, wBoxPartialData ld bc, (wBoxPartialDataEnd - wBoxPartialData) call CopyBytes call CloseSRAM pop de pop af ld hl, (wBoxPartialDataEnd - wBoxPartialData) add hl, de ld e, l ld d, h ; Save it to the next part of the target box. push af push de call OpenSRAM ld hl, wBoxPartialData ld bc, (wBoxPartialDataEnd - wBoxPartialData) call CopyBytes call CloseSRAM ; Load the third and final part of the active box. ld a, BANK(sBox) call OpenSRAM ld hl, sBox + (wBoxPartialDataEnd - wBoxPartialData) * 2 ld de, wBoxPartialData ld bc, sBoxEnd - (sBox + (wBoxPartialDataEnd - wBoxPartialData) * 2) ; $8e call CopyBytes call CloseSRAM pop de pop af ld hl, (wBoxPartialDataEnd - wBoxPartialData) add hl, de ld e, l ld d, h ; Save it to the final part of the target box. call OpenSRAM ld hl, wBoxPartialData ld bc, sBoxEnd - (sBox + (wBoxPartialDataEnd - wBoxPartialData) * 2) ; $8e call CopyBytes call CloseSRAM pop hl ret LoadBoxAddress: ; Load box via wBoxPartialData. ; We do this in three steps because the size of wBoxPartialData is less than ; the size of sBox. push hl ld l, e ld h, d ; Load part 1 push af push hl call OpenSRAM ld de, wBoxPartialData ld bc, (wBoxPartialDataEnd - wBoxPartialData) call CopyBytes call CloseSRAM ld a, BANK(sBox) call OpenSRAM ld hl, wBoxPartialData ld de, sBox ld bc, (wBoxPartialDataEnd - wBoxPartialData) call CopyBytes call CloseSRAM pop hl pop af ld de, (wBoxPartialDataEnd - wBoxPartialData) add hl, de ; Load part 2 push af push hl call OpenSRAM ld de, wBoxPartialData ld bc, (wBoxPartialDataEnd - wBoxPartialData) call CopyBytes call CloseSRAM ld a, BANK(sBox) call OpenSRAM ld hl, wBoxPartialData ld de, sBox + (wBoxPartialDataEnd - wBoxPartialData) ld bc, (wBoxPartialDataEnd - wBoxPartialData) call CopyBytes call CloseSRAM pop hl pop af ; Load part 3 ld de, (wBoxPartialDataEnd - wBoxPartialData) add hl, de call OpenSRAM ld de, wBoxPartialData ld bc, sBoxEnd - (sBox + (wBoxPartialDataEnd - wBoxPartialData) * 2) ; $8e call CopyBytes call CloseSRAM ld a, BANK(sBox) call OpenSRAM ld hl, wBoxPartialData ld de, sBox + (wBoxPartialDataEnd - wBoxPartialData) * 2 ld bc, sBoxEnd - (sBox + (wBoxPartialDataEnd - wBoxPartialData) * 2) ; $8e call CopyBytes call CloseSRAM pop hl ret EraseBoxes: ld hl, BoxAddresses ld c, NUM_BOXES .next push bc ld a, [hli] call OpenSRAM ld a, [hli] ld e, a ld a, [hli] ld d, a xor a ld [de], a inc de ld a, -1 ld [de], a inc de ld bc, sBoxEnd - (sBox + 2) .clear xor a ld [de], a inc de dec bc ld a, b or c jr nz, .clear ld a, [hli] ld e, a ld a, [hli] ld d, a ld a, -1 ld [de], a inc de xor a ld [de], a call CloseSRAM pop bc dec c jr nz, .next ret box_address: MACRO assert BANK(\1) == BANK(\2) db BANK(\1) dw \1, \2 ENDM BoxAddresses: table_width 5, BoxAddresses box_address sBox1, sBox1End box_address sBox2, sBox2End box_address sBox3, sBox3End box_address sBox4, sBox4End box_address sBox5, sBox5End box_address sBox6, sBox6End box_address sBox7, sBox7End box_address sBox8, sBox8End box_address sBox9, sBox9End box_address sBox10, sBox10End box_address sBox11, sBox11End box_address sBox12, sBox12End box_address sBox13, sBox13End box_address sBox14, sBox14End assert_table_length NUM_BOXES Checksum: ld de, 0 .loop ld a, [hli] add e ld e, a ld a, 0 adc d ld d, a dec bc ld a, b or c jr nz, .loop ret WouldYouLikeToSaveTheGameText: text_far _WouldYouLikeToSaveTheGameText text_end SavingDontTurnOffThePowerText: text_far _SavingDontTurnOffThePowerText text_end SavedTheGameText: text_far _SavedTheGameText text_end AlreadyASaveFileText: text_far _AlreadyASaveFileText text_end AnotherSaveFileText: text_far _AnotherSaveFileText text_end SaveFileCorruptedText: text_far _SaveFileCorruptedText text_end ChangeBoxSaveText: text_far _ChangeBoxSaveText text_end MoveMonWOMailSaveText: text_far _MoveMonWOMailSaveText text_end