ref: 509ee98219bae35c3edae81ed36f3c40ab9dbd5b
dir: /engine/save.asm/
LoadSAV: ;(if carry -> write ;"the file data is destroyed") call ClearScreen call LoadFontTilePatterns call LoadTextBoxTilePatterns call LoadSAV0 jr c, .badsum call LoadSAV1 jr c, .badsum call LoadSAV2 jr c, .badsum ld a, $2 ; good checksum jr .goodsum .badsum ld hl, wd730 push hl set 6, [hl] ld hl, FileDataDestroyedText call PrintText ld c, 100 call DelayFrames pop hl res 6, [hl] ld a, $1 ; bad checksum .goodsum ld [wSaveFileStatus], a ret FileDataDestroyedText: TX_FAR _FileDataDestroyedText db "@" LoadSAV0: ld a, SRAM_ENABLE ld [MBC1SRamEnable], a ld a, $1 ld [MBC1SRamBankingMode], a ld [MBC1SRamBank], a ld hl, sPlayerName ; hero name located in SRAM ld bc, sMainDataCheckSum - sPlayerName ; but here checks the full SAV call SAVCheckSum ld c, a ld a, [sMainDataCheckSum] ; SAV's checksum cp c jp z, .checkSumsMatched ; If the computed checksum didn't match the saved on, try again. ld hl, sPlayerName ld bc, sMainDataCheckSum - sPlayerName call SAVCheckSum ld c, a ld a, [sMainDataCheckSum] ; SAV's checksum cp c jp nz, SAVBadCheckSum .checkSumsMatched ld hl, sPlayerName ld de, wPlayerName ld bc, NAME_LENGTH call CopyData ld hl, sMainData ld de, wMainDataStart ld bc, wMainDataEnd - wMainDataStart call CopyData ld hl, wCurMapTileset set 7, [hl] ld hl, sSpriteData ld de, wSpriteDataStart ld bc, wSpriteDataEnd - wSpriteDataStart call CopyData ld a, [sTilesetType] ld [hTilesetType], a ld hl, sCurBoxData ld de, wBoxDataStart ld bc, wBoxDataEnd - wBoxDataStart call CopyData and a jp SAVGoodChecksum LoadSAV1: ld a, SRAM_ENABLE ld [MBC1SRamEnable], a ld a, $1 ld [MBC1SRamBankingMode], a ld [MBC1SRamBank], a ld hl, sPlayerName ; hero name located in SRAM ld bc, sMainDataCheckSum - sPlayerName ; but here checks the full SAV call SAVCheckSum ld c, a ld a, [sMainDataCheckSum] ; SAV's checksum cp c jr nz, SAVBadCheckSum ld hl, sCurBoxData ld de, wBoxDataStart ld bc, wBoxDataEnd - wBoxDataStart call CopyData and a jp SAVGoodChecksum LoadSAV2: ld a, SRAM_ENABLE ld [MBC1SRamEnable], a ld a, $1 ld [MBC1SRamBankingMode], a ld [MBC1SRamBank], a ld hl, sPlayerName ; hero name located in SRAM ld bc, sMainDataCheckSum - sPlayerName ; but here checks the full SAV call SAVCheckSum ld c, a ld a, [sMainDataCheckSum] ; SAV's checksum cp c jp nz, SAVBadCheckSum ld hl, sPartyData ld de, wPartyDataStart ld bc, wPartyDataEnd - wPartyDataStart call CopyData ld hl, sMainData ld de, wPokedexOwned ld bc, wPokedexSeenEnd - wPokedexOwned call CopyData and a jp SAVGoodChecksum SAVBadCheckSum: scf SAVGoodChecksum: ld a, $0 ld [MBC1SRamBankingMode], a ld [MBC1SRamEnable], a ret LoadSAVIgnoreBadCheckSum: ; unused function that loads save data and ignores bad checksums call LoadSAV0 call LoadSAV1 jp LoadSAV2 SaveSAV: callba PrintSaveScreenText ld hl, WouldYouLikeToSaveText call SaveSAVConfirm and a ;|0 = Yes|1 = No| ret nz ld a, [wSaveFileStatus] dec a jr z, .save call SAVCheckRandomID jr z, .save ld hl, OlderFileWillBeErasedText call SaveSAVConfirm and a ret nz .save call SaveSAVtoSRAM coord hl, 1, 13 lb bc, 4, 18 call ClearScreenArea coord hl, 1, 14 ld de, NowSavingString call PlaceString ld c, 120 call DelayFrames ld hl, GameSavedText call PrintText ld a, SFX_SAVE call PlaySoundWaitForCurrent call WaitForSoundToFinish ld c, 30 jp DelayFrames NowSavingString: db "Now saving...@" SaveSAVConfirm: call PrintText coord hl, 0, 7 lb bc, 8, 1 ld a, TWO_OPTION_MENU ld [wTextBoxID], a call DisplayTextBoxID ; yes/no menu ld a, [wCurrentMenuItem] ret WouldYouLikeToSaveText: TX_FAR _WouldYouLikeToSaveText db "@" GameSavedText: TX_FAR _GameSavedText db "@" OlderFileWillBeErasedText: TX_FAR _OlderFileWillBeErasedText db "@" SaveSAVtoSRAM0: ld a, SRAM_ENABLE ld [MBC1SRamEnable], a ld a, $1 ld [MBC1SRamBankingMode], a ld [MBC1SRamBank], a ld hl, wPlayerName ld de, sPlayerName ld bc, NAME_LENGTH call CopyData ld hl, wMainDataStart ld de, sMainData ld bc, wMainDataEnd - wMainDataStart call CopyData ld hl, wSpriteDataStart ld de, sSpriteData ld bc, wSpriteDataEnd - wSpriteDataStart call CopyData ld hl, wBoxDataStart ld de, sCurBoxData ld bc, wBoxDataEnd - wBoxDataStart call CopyData ld a, [hTilesetType] ld [sTilesetType], a ld hl, sPlayerName ld bc, sMainDataCheckSum - sPlayerName call SAVCheckSum ld [sMainDataCheckSum], a xor a ld [MBC1SRamBankingMode], a ld [MBC1SRamEnable], a ret SaveSAVtoSRAM1: ; stored pokémon ld a, SRAM_ENABLE ld [MBC1SRamEnable], a ld a, $1 ld [MBC1SRamBankingMode], a ld [MBC1SRamBank], a ld hl, wBoxDataStart ld de, sCurBoxData ld bc, wBoxDataEnd - wBoxDataStart call CopyData ld hl, sPlayerName ld bc, sMainDataCheckSum - sPlayerName call SAVCheckSum ld [sMainDataCheckSum], a xor a ld [MBC1SRamBankingMode], a ld [MBC1SRamEnable], a ret SaveSAVtoSRAM2: ld a, SRAM_ENABLE ld [MBC1SRamEnable], a ld a, $1 ld [MBC1SRamBankingMode], a ld [MBC1SRamBank], a ld hl, wPartyDataStart ld de, sPartyData ld bc, wPartyDataEnd - wPartyDataStart call CopyData ld hl, wPokedexOwned ; pokédex only ld de, sMainData ld bc, wPokedexSeenEnd - wPokedexOwned call CopyData ld hl, sPlayerName ld bc, sMainDataCheckSum - sPlayerName call SAVCheckSum ld [sMainDataCheckSum], a xor a ld [MBC1SRamBankingMode], a ld [MBC1SRamEnable], a ret SaveSAVtoSRAM: ld a, $2 ld [wSaveFileStatus], a call SaveSAVtoSRAM0 call SaveSAVtoSRAM1 jp SaveSAVtoSRAM2 SAVCheckSum: ;Check Sum (result[1 byte] is complemented) ld d, 0 .loop ld a, [hli] add d ld d, a dec bc ld a, b or c jr nz, .loop ld a, d cpl ret CalcIndividualBoxCheckSums: ld hl, sBox1 ; sBox7 ld de, sBank2IndividualBoxChecksums ; sBank3IndividualBoxChecksums ld b, NUM_BOXES / 2 .loop push bc push de ld bc, wBoxDataEnd - wBoxDataStart call SAVCheckSum pop de ld [de], a inc de pop bc dec b jr nz, .loop ret GetBoxSRAMLocation: ; in: a = box num ; out: b = box SRAM bank, hl = pointer to start of box ld hl, BoxSRAMPointerTable ld a, [wCurrentBoxNum] and $7f cp NUM_BOXES / 2 ld b, 2 jr c, .next inc b sub NUM_BOXES / 2 .next ld e, a ld d, 0 add hl, de add hl, de ld a, [hli] ld h, [hl] ld l, a ret BoxSRAMPointerTable: dw sBox1 ; sBox7 dw sBox2 ; sBox8 dw sBox3 ; sBox9 dw sBox4 ; sBox10 dw sBox5 ; sBox11 dw sBox6 ; sBox12 ChangeBox:: ld hl, WhenYouChangeBoxText call PrintText call YesNoChoice ld a, [wCurrentMenuItem] and a ret nz ; return if No was chosen ld hl, wCurrentBoxNum bit 7, [hl] ; is it the first time player is changing the box? call z, EmptyAllSRAMBoxes ; if so, empty all boxes in SRAM call DisplayChangeBoxMenu call UpdateSprites ld hl, hFlags_0xFFF6 set 1, [hl] call HandleMenuInput ld hl, hFlags_0xFFF6 res 1, [hl] bit 1, a ; pressed b ret nz call GetBoxSRAMLocation ld e, l ld d, h ld hl, wBoxDataStart call CopyBoxToOrFromSRAM ; copy old box from WRAM to SRAM ld a, [wCurrentMenuItem] set 7, a ld [wCurrentBoxNum], a call GetBoxSRAMLocation ld de, wBoxDataStart call CopyBoxToOrFromSRAM ; copy new box from SRAM to WRAM ld hl, wMapTextPtr ld de, wChangeBoxSavedMapTextPointer ld a, [hli] ld [de], a inc de ld a, [hl] ld [de], a call RestoreMapTextPointer call SaveSAVtoSRAM ld hl, wChangeBoxSavedMapTextPointer call SetMapTextPointer ld a, SFX_SAVE call PlaySoundWaitForCurrent call WaitForSoundToFinish ret WhenYouChangeBoxText: TX_FAR _WhenYouChangeBoxText db "@" CopyBoxToOrFromSRAM: ; copy an entire box from hl to de with b as the SRAM bank push hl ld a, SRAM_ENABLE ld [MBC1SRamEnable], a ld a, $1 ld [MBC1SRamBankingMode], a ld a, b ld [MBC1SRamBank], a ld bc, wBoxDataEnd - wBoxDataStart call CopyData pop hl ; mark the memory that the box was copied from as am empty box xor a ld [hli], a dec a ld [hl], a ld hl, sBox1 ; sBox7 ld bc, sBank2AllBoxesChecksum - sBox1 call SAVCheckSum ld [sBank2AllBoxesChecksum], a ; sBank3AllBoxesChecksum call CalcIndividualBoxCheckSums xor a ld [MBC1SRamBankingMode], a ld [MBC1SRamEnable], a ret DisplayChangeBoxMenu: xor a ld [H_AUTOBGTRANSFERENABLED], a ld a, A_BUTTON | B_BUTTON ld [wMenuWatchedKeys], a ld a, 11 ld [wMaxMenuItem], a ld a, 1 ld [wTopMenuItemY], a ld a, 12 ld [wTopMenuItemX], a xor a ld [wMenuWatchMovingOutOfBounds], a ld a, [wCurrentBoxNum] and $7f ld [wCurrentMenuItem], a ld [wLastMenuItem], a coord hl, 0, 0 ld b, 2 ld c, 9 call TextBoxBorder ld hl, ChooseABoxText call PrintText coord hl, 11, 0 ld b, 12 ld c, 7 call TextBoxBorder ld hl, hFlags_0xFFF6 set 2, [hl] ld de, BoxNames coord hl, 13, 1 call PlaceString ld hl, hFlags_0xFFF6 res 2, [hl] ld a, [wCurrentBoxNum] and $7f cp 9 jr c, .singleDigitBoxNum sub 9 coord hl, 8, 2 ld [hl], "1" add "0" jr .next .singleDigitBoxNum add "1" .next Coorda 9, 2 coord hl, 1, 2 ld de, BoxNoText call PlaceString call GetMonCountsForAllBoxes coord hl, 18, 1 ld de, wBoxMonCounts ld bc, SCREEN_WIDTH ld a, $c .loop push af ld a, [de] and a ; is the box empty? jr z, .skipPlacingPokeball ld [hl], $78 ; place pokeball tile next to box name if box not empty .skipPlacingPokeball add hl, bc inc de pop af dec a jr nz, .loop ld a, 1 ld [H_AUTOBGTRANSFERENABLED], a ret ChooseABoxText: TX_FAR _ChooseABoxText db "@" BoxNames: db "BOX 1" next "BOX 2" next "BOX 3" next "BOX 4" next "BOX 5" next "BOX 6" next "BOX 7" next "BOX 8" next "BOX 9" next "BOX10" next "BOX11" next "BOX12@" BoxNoText: db "BOX No.@" EmptyAllSRAMBoxes: ; marks all boxes in SRAM as empty (initialisation for the first time the ; player changes the box) ld a, SRAM_ENABLE ld [MBC1SRamEnable], a ld a, $1 ld [MBC1SRamBankingMode], a ld a, 2 ld [MBC1SRamBank], a call EmptySRAMBoxesInBank ld a, 3 ld [MBC1SRamBank], a call EmptySRAMBoxesInBank xor a ld [MBC1SRamBankingMode], a ld [MBC1SRamEnable], a ret EmptySRAMBoxesInBank: ; marks every box in the current SRAM bank as empty ld hl, sBox1 ; sBox7 call EmptySRAMBox ld hl, sBox2 ; sBox8 call EmptySRAMBox ld hl, sBox3 ; sBox9 call EmptySRAMBox ld hl, sBox4 ; sBox10 call EmptySRAMBox ld hl, sBox5 ; sBox11 call EmptySRAMBox ld hl, sBox6 ; sBox12 call EmptySRAMBox ld hl, sBox1 ; sBox7 ld bc, sBank2AllBoxesChecksum - sBox1 call SAVCheckSum ld [sBank2AllBoxesChecksum], a ; sBank3AllBoxesChecksum call CalcIndividualBoxCheckSums ret EmptySRAMBox: xor a ld [hli], a dec a ld [hl], a ret GetMonCountsForAllBoxes: ld hl, wBoxMonCounts push hl ld a, SRAM_ENABLE ld [MBC1SRamEnable], a ld a, $1 ld [MBC1SRamBankingMode], a ld a, $2 ld [MBC1SRamBank], a call GetMonCountsForBoxesInBank ld a, $3 ld [MBC1SRamBank], a call GetMonCountsForBoxesInBank xor a ld [MBC1SRamBankingMode], a ld [MBC1SRamEnable], a pop hl ; copy the count for the current box from WRAM ld a, [wCurrentBoxNum] and $7f ld c, a ld b, 0 add hl, bc ld a, [wNumInBox] ld [hl], a ret GetMonCountsForBoxesInBank: ld a, [sBox1] ; sBox7 ld [hli], a ld a, [sBox2] ; sBox8 ld [hli], a ld a, [sBox3] ; sBox9 ld [hli], a ld a, [sBox4] ; sBox10 ld [hli], a ld a, [sBox5] ; sBox11 ld [hli], a ld a, [sBox6] ; sBox12 ld [hli], a ret SAVCheckRandomID: ;checks if Sav file is the same by checking player's name 1st letter ($a598) ; and the two random numbers generated at game beginning ;(which are stored at wPlayerID)s ld a, $0a ld [MBC1SRamEnable], a ld a, $01 ld [MBC1SRamBankingMode], a ld [MBC1SRamBank], a ld a, [sPlayerName] and a jr z, .next ld hl, sPlayerName ld bc, sMainDataCheckSum - sPlayerName call SAVCheckSum ld c, a ld a, [sMainDataCheckSum] cp c jr nz, .next ld hl, sMainData + (wPlayerID - wMainDataStart) ; player ID ld a, [hli] ld h, [hl] ld l, a ld a, [wPlayerID] cp l jr nz, .next ld a, [wPlayerID + 1] cp h .next ld a, $00 ld [MBC1SRamBankingMode], a ld [MBC1SRamEnable], a ret SaveHallOfFameTeams: ld a, [wNumHoFTeams] dec a cp HOF_TEAM_CAPACITY jr nc, .shiftHOFTeams ld hl, sHallOfFame ld bc, HOF_TEAM call AddNTimes ld e, l ld d, h ld hl, wHallOfFame ld bc, HOF_TEAM jr HallOfFame_Copy .shiftHOFTeams ; if the space designated for HOF teams is full, then shift all HOF teams to the next slot, making space for the new HOF team ; this deletes the last HOF team though ld hl, sHallOfFame + HOF_TEAM ld de, sHallOfFame ld bc, HOF_TEAM * (HOF_TEAM_CAPACITY - 1) call HallOfFame_Copy ld hl, wHallOfFame ld de, sHallOfFame + HOF_TEAM * (HOF_TEAM_CAPACITY - 1) ld bc, HOF_TEAM jr HallOfFame_Copy LoadHallOfFameTeams: ld hl, sHallOfFame ld bc, HOF_TEAM ld a, [wHoFTeamIndex] call AddNTimes ld de, wHallOfFame ld bc, HOF_TEAM ; fallthrough HallOfFame_Copy: ld a, SRAM_ENABLE ld [MBC1SRamEnable], a ld a, $1 ld [MBC1SRamBankingMode], a xor a ld [MBC1SRamBank], a call CopyData xor a ld [MBC1SRamBankingMode], a ld [MBC1SRamEnable], a ret ClearSAV: ld a, SRAM_ENABLE ld [MBC1SRamEnable], a ld a, $1 ld [MBC1SRamBankingMode], a xor a call PadSRAM_FF ld a, $1 call PadSRAM_FF ld a, $2 call PadSRAM_FF ld a, $3 call PadSRAM_FF xor a ld [MBC1SRamBankingMode], a ld [MBC1SRamEnable], a ret PadSRAM_FF: ld [MBC1SRamBank], a ld hl, $a000 ld bc, $2000 ld a, $ff jp FillMemory