SaveMenu: call LoadStandardMenuHeader farcall DisplaySaveInfoOnSave call SpeechTextbox2bpp call UpdateSprites farcall 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 farcall CopyTilemapAtOnce scf ret AutoSaveGameInOverworld: call PauseGameLogic ; Prevent joypad interrupts xor a ldh [hJoypadReleased], a ldh [hJoypadPressed], a ldh [hJoypadSum], a ldh [hJoypadDown], a ; Signal that we're saving inside a level ld a, TRUE ld [wSaveFileInOverworld], a call SaveGameData call ResumeGameLogic ret AutoSaveGameOutsideOverworld: call PauseGameLogic ; Prevent joypad interrupts xor a ldh [hJoypadReleased], a ldh [hJoypadPressed], a ldh [hJoypadSum], a ldh [hJoypadDown], a ; Signal that we're not saving inside a level xor a ; FALSE ld [wSaveFileInOverworld], a call SaveGameData call ResumeGameLogic ret SaveAfterLinkTrade: call PauseGameLogic call SavePokemonData call SaveChecksum call SaveBackupPokemonData call SaveBackupChecksum farcall BackupPartyMonMail 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 SavingDontTurnOffThePower call SaveBox pop de ld a, e ld [wCurBox], a call LoadBox call SavedTheGame 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 call ValidateSave call SaveOptions call SavePlayerData call SavePokemonData call SaveChecksum call ValidateBackupSave call SaveBackupOptions call SaveBackupPlayerData call SaveBackupPokemonData call SaveBackupChecksum farcall BackupPartyMonMail 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 ; This vc_hook causes the Virtual Console to set [sMobileEventIndex] and [sMobileEventIndexBackup] ; to MOBILE_EVENT_OBJECT_GS_BALL, which enables you to get the GS Ball, take it to Kurt, and ; encounter Celebi. It assumes that sMobileEventIndex and sMobileEventIndexBackup are at their ; original addresses. vc_hook Enable_GS_Ball_mobile_event vc_assert BANK(sMobileEventIndex) == $1 && sMobileEventIndex == $be3c, \ "sMobileEventIndex is no longer located at 01:be3c." vc_assert BANK(sMobileEventIndexBackup) == $1 && sMobileEventIndexBackup == $be44, \ "sMobileEventIndexBackup is no longer located at 01:be44." vc_assert MOBILE_EVENT_OBJECT_GS_BALL == $0b, \ "MOBILE_EVENT_OBJECT_GS_BALL is no longer equal to $0b." 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 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: call SavingDontTurnOffThePower SavedTheGame: ld a, TRUE ld [wSaveFileInOverworld], a 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 PrintText1bpp ; 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 call ValidateSave call SaveOptions call SavePlayerData call SavePokemonData call SaveDisabledSpacesBackupsData call SaveMapObjectsBackupsData call SaveBox call SaveChecksum call ValidateBackupSave call SaveBackupOptions call SaveBackupPlayerData call SaveBackupPokemonData call SaveBackupChecksum call UpdateStackTop farcall BackupPartyMonMail 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 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 PrintText1bpp ; Restore the text speed setting pop af ld [wOptions], a ; Wait for 16 frames ld c, 16 call DelayFrames ret ErasePreviousSave: call EraseBoxes call EraseHallOfFame call EraseLinkBattleStats 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 EraseHallOfFame: ld a, BANK(sHallOfFame) call OpenSRAM ld hl, sHallOfFame ld bc, sHallOfFameEnd - sHallOfFame xor a call ByteFill jp CloseSRAM HallOfFame_InitSaveIfNeeded: ld a, [wSavedAtLeastOnce] and a ret nz call ErasePreviousSave ret 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 SaveDisabledSpacesBackupsData: ldh a, [rSVBK] push af ld a, BANK(wDisabledSpacesBackups) ldh [rSVBK], a ld a, BANK(sDisabledSpacesBackups) call OpenSRAM ld hl, wDisabledSpacesBackups ld de, sDisabledSpacesBackups ld bc, wDisabledSpacesBackupsEnd - wDisabledSpacesBackups call CopyBytes call CloseSRAM pop af ldh [rSVBK], a ret SaveMapObjectsBackupsData: ldh a, [rSVBK] push af ld a, BANK(wMapObjectsBackups) ldh [rSVBK], a ld a, BANK(sMapObjectsBackups) call OpenSRAM ld hl, wMapObjectsBackups ld de, sMapObjectsBackups ld bc, wMapObjectsBackupsEnd - wMapObjectsBackups call CopyBytes call CloseSRAM pop af ldh [rSVBK], a 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(sBackupPlayerData) call OpenSRAM ld hl, wPlayerData ld de, sBackupPlayerData ld bc, wPlayerDataEnd - wPlayerData call CopyBytes 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 hl, sBackupGameData ld bc, sBackupGameDataEnd - sBackupGameData ld a, BANK(sBackupGameData) call OpenSRAM call Checksum ld a, e ld [sBackupChecksum + 0], a ld a, d ld [sBackupChecksum + 1], a call CloseSRAM ret TryLoadSaveFile: call VerifyChecksum jr nz, .backup call LoadPlayerData call LoadPokemonData call LoadDisabledSpacesBackupsData call LoadMapObjectsBackupsData call LoadBox farcall RestorePartyMonMail call ValidateBackupSave call SaveBackupOptions call SaveBackupPlayerData call SaveBackupPokemonData call SaveBackupChecksum and a ret .backup call VerifyBackupChecksum jr nz, .corrupt call LoadBackupPlayerData call LoadBackupPokemonData call LoadDisabledSpacesBackupsData call LoadMapObjectsBackupsData call LoadBox farcall RestorePartyMonMail 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 PrintText1bpp 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, 8 call CopyBytes ld hl, sPlayerData + wStatusFlags - wPlayerData ld de, wStatusFlags ld a, [hl] ld [de], a call CloseSRAM ret .backup call CheckBackupSaveFile ld a, [wSaveFileExists] and a jr z, .corrupt ld a, BANK(sBackupPlayerData) call OpenSRAM ld hl, sBackupPlayerData + wStartDay - wPlayerData ld de, wStartDay ld bc, 8 call CopyBytes ld hl, sBackupPlayerData + wStatusFlags - wPlayerData ld de, wStatusFlags ld a, [hl] ld [de], a call CloseSRAM ret .corrupt ld hl, DefaultOptions ld de, wOptions ld bc, wOptionsEnd - wOptions call CopyBytes 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 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 ld a, $2 ld [wSaveFileExists], a .nope call CloseSRAM 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 LoadDisabledSpacesBackupsData: ldh a, [rSVBK] push af ld a, BANK(wDisabledSpacesBackups) ldh [rSVBK], a ld a, BANK(sDisabledSpacesBackups) call OpenSRAM ld hl, sDisabledSpacesBackups ld de, wDisabledSpacesBackups ld bc, wDisabledSpacesBackupsEnd - wDisabledSpacesBackups call CopyBytes call CloseSRAM pop af ldh [rSVBK], a ret LoadMapObjectsBackupsData: ldh a, [rSVBK] push af ld a, BANK(wMapObjectsBackups) ldh [rSVBK], a ld a, BANK(sMapObjectsBackups) call OpenSRAM ld hl, sMapObjectsBackups ld de, wMapObjectsBackups ld bc, wMapObjectsBackupsEnd - wMapObjectsBackups call CopyBytes call CloseSRAM pop af ldh [rSVBK], a 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(sBackupPlayerData) call OpenSRAM ld hl, sBackupPlayerData ld de, wPlayerData ld bc, wPlayerDataEnd - wPlayerData call CopyBytes 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 hl, sBackupGameData ld bc, sBackupGameDataEnd - sBackupGameData ld a, BANK(sBackupGameData) call OpenSRAM call Checksum 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 BoxAddresses: table_width 5, BoxAddresses for n, 1, NUM_BOXES + 1 db BANK(sBox{d:n}) ; aka BANK(sBox{d:n}End) dw sBox{d:n}, sBox{d:n}End endr 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