summaryrefslogtreecommitdiff
path: root/engine/menus/save.asm
diff options
context:
space:
mode:
Diffstat (limited to 'engine/menus/save.asm')
-rw-r--r--engine/menus/save.asm1094
1 files changed, 1094 insertions, 0 deletions
diff --git a/engine/menus/save.asm b/engine/menus/save.asm
new file mode 100644
index 00000000..e3b99905
--- /dev/null
+++ b/engine/menus/save.asm
@@ -0,0 +1,1094 @@
+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 Functiond2a
+ 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 Functiond2a
+ 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
+ ; <PLAYER> 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, wStackTop - $fc
+.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 $ff ^ (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, $e
+ 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, $e
+ 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 Function15011
+ 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 Function15011
+ ld a, $2
+ ld [wSaveFileExists], a
+
+.nope
+ call CloseSRAM
+ ret
+
+Function15011:
+ ld hl, wTextboxFlags
+ res 1, [hl]
+ ld a, [wOptions]
+ and 7
+ cp 1
+ ret z
+
+ cp 3
+ ret z
+
+ cp 5
+ ret z
+
+ ld a, [wOptions]
+ and $f8
+ or 3
+ 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
+
+BoxAddresses:
+; dbww bank, address, address
+ dbww BANK(sBox1), sBox1, sBox1End
+ dbww BANK(sBox2), sBox2, sBox2End
+ dbww BANK(sBox3), sBox3, sBox3End
+ dbww BANK(sBox4), sBox4, sBox4End
+ dbww BANK(sBox5), sBox5, sBox5End
+ dbww BANK(sBox6), sBox6, sBox6End
+ dbww BANK(sBox7), sBox7, sBox7End
+ dbww BANK(sBox8), sBox8, sBox8End
+ dbww BANK(sBox9), sBox9, sBox9End
+ dbww BANK(sBox10), sBox10, sBox10End
+ dbww BANK(sBox11), sBox11, sBox11End
+ dbww BANK(sBox12), sBox12, sBox12End
+ dbww BANK(sBox13), sBox13, sBox13End
+ dbww BANK(sBox14), sBox14, sBox14End
+
+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