You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
998 lines
21 KiB
998 lines
21 KiB
6 years ago
|
Text_WouldYouLikeToSaveTheGame EQU $5283
|
||
|
Text_SavingDontTurnOffThePower EQU $5288
|
||
|
SaveTheGame_yesorno EQU $4BAF
|
||
|
SaveMenu.refused EQU $4A4A
|
||
|
Text_WaitBGMap EQU $13B6
|
||
|
SpeechTextBox EQU $103E
|
||
|
FarCall EQU $08
|
||
|
FadeOutPalettes EQU $23:$4084
|
||
|
LoadMapPalettes EQU $41:$47EB
|
||
|
ClearScreen EQU $0FDB
|
||
|
UpdateSprites EQU $1AD2
|
||
|
GetSGBLayout EQU $3340
|
||
|
SetPalettes EQU $32F9
|
||
|
DelayFrame EQU $045A
|
||
|
DelayFrames EQU $0468
|
||
|
PrintText EQU $1057
|
||
|
Request1bpp EQU $0F1E
|
||
|
DoubleSpeed EQU $2FEF
|
||
|
hTransferVirtualOAM EQU $FFEC
|
||
|
rSTAT EQU $FF41
|
||
|
CopyBytes EQU $3026
|
||
|
|
||
|
s02_9A12: db ; s02_9A12
|
||
|
|
||
|
SaveGame: ; s02_AD44
|
||
|
push af
|
||
|
push bc
|
||
|
push de
|
||
|
push hl
|
||
|
ei
|
||
|
call Text_WaitBGMap
|
||
|
|
||
|
ld a,[wSavingAllowed]
|
||
|
and a
|
||
|
jr z,.cantsave
|
||
|
|
||
|
; Ask the player to save or some dumb shit idfk
|
||
|
ld hl,$B1E8
|
||
|
ld a,$02
|
||
|
ld [w01_DF34],a
|
||
|
call $A2A3
|
||
|
ld bc,$0204
|
||
|
ld hl,$A41A
|
||
|
ld de,Start
|
||
|
call $AB1F ; Get player input?
|
||
|
and a
|
||
|
jr z,.declined
|
||
|
|
||
|
; Confirmed save
|
||
|
ld a,[wPartyCount]
|
||
|
cp a,$04
|
||
|
jr c,.actuallysave
|
||
|
|
||
|
; Too many party members yadda yadda
|
||
|
ld hl,$B323
|
||
|
ld a,$02
|
||
|
ld [w01_DF34],a
|
||
|
call $A2A3
|
||
|
ld bc,$0204
|
||
|
ld hl,$A41A
|
||
|
ld de,Start
|
||
|
call $AB1F
|
||
|
and a
|
||
|
jr z,$ADA7
|
||
|
|
||
|
.actuallysave ; s02_AD8F
|
||
|
ld a,BANK(FadeOutPalettes)
|
||
|
ld hl,FadeOutPalettes
|
||
|
rst FarCall
|
||
|
ld a,BANK(LoadMapPalettes)
|
||
|
ld hl,LoadMapPalettes
|
||
|
rst FarCall
|
||
|
jp SavingTheGame
|
||
|
|
||
|
.cantsave ; s02_A9DC
|
||
|
ld hl,$B1A6
|
||
|
ld a,$02
|
||
|
ld [$DF34],a
|
||
|
call $A2A3
|
||
|
|
||
|
.declined ; s02_ADA7
|
||
|
pop hl
|
||
|
pop de
|
||
|
pop bc
|
||
|
pop af
|
||
|
jp $0460
|
||
|
|
||
|
sSaveSource: dw ; s02_ADAE
|
||
|
sSaveBlockChecksum: db ; s02_ADB0
|
||
|
s02_ADB1: dl ; s02_ADB1
|
||
|
sBufferCarry: ; s02_ADB5
|
||
|
sROPScriptBackup: dw ; s02_ADB6
|
||
|
s02_ADB8: db ; s02_ADB8
|
||
|
s02_ADB9: db ; s02_ADB9
|
||
|
|
||
|
ROPGadget_ldi_a_hl: ; s02_ADBA
|
||
|
ld a, [hl+]
|
||
|
ret
|
||
|
|
||
|
ROPGadget_ldd_a_hl: ; s02_ADBC
|
||
|
ld a, [hl-]
|
||
|
ret
|
||
|
|
||
|
ROPGadget_ld_hl_c: ; s02_ADBE
|
||
|
ld [hl], c
|
||
|
ret
|
||
|
|
||
|
ROPGadget_ld_b_hl: ; s02_ADC0
|
||
|
ld b, [hl]
|
||
|
ret
|
||
|
|
||
|
ROPGadget_add_b: ; s02_ADC2
|
||
|
add b
|
||
|
ret
|
||
|
|
||
|
ROPGadget_srl_a: ; s02_ADC4
|
||
|
srl a
|
||
|
ret
|
||
|
|
||
|
ROPGadget_xor_hl: ; s02_ADC7
|
||
|
xor [hl]
|
||
|
ret
|
||
|
|
||
|
ROPGadget_call_z: ; s02_ADC9
|
||
|
ret z
|
||
|
pop hl
|
||
|
ret
|
||
|
|
||
|
ROPGadget_variable: ; s02_ADCC
|
||
|
add [hl]
|
||
|
ret
|
||
|
|
||
|
SavingTheGame: ; s02_ADCE
|
||
|
; Cleanup shit because well fuck nobody cares
|
||
|
call ClearScreen
|
||
|
call UpdateSprites
|
||
|
call UninstallVBlankHook ; Only interesting line in this entire blob of fuzz
|
||
|
ld b,$08
|
||
|
call GetSGBLayout
|
||
|
call SetPalettes
|
||
|
ld hl,wMusicFadeID
|
||
|
ld [hl],$00
|
||
|
dec hl
|
||
|
dec hl
|
||
|
ld [hl],$08
|
||
|
ld c,$32
|
||
|
call DelayFrames
|
||
|
ld a,$03
|
||
|
ld [wOptions],a
|
||
|
ld a,$05
|
||
|
rst $10
|
||
|
ld hl,Text_SavingDontTurnOffThePower
|
||
|
call PrintText
|
||
|
ld de,$B400
|
||
|
ld hl,$8C00 ; This graphic is probably a picture of a cucumber
|
||
|
ld bc,$0104
|
||
|
call Request1bpp
|
||
|
call DelayFrame
|
||
|
|
||
|
; Now THAT's more like it
|
||
|
ld de,ROPScript_SaveMain
|
||
|
di
|
||
|
call DoubleSpeed
|
||
|
call UpdateSaveSpinner
|
||
|
ld sp,SaveROPMain
|
||
|
ret
|
||
|
|
||
|
ROP_SaveMain: ; s02_AE18
|
||
|
ld a, [de]
|
||
|
inc de
|
||
|
add a
|
||
|
|
||
|
ld bc, 0
|
||
|
ld c, a
|
||
|
ld hl, .jmptable
|
||
|
add hl, bc
|
||
|
ldw hl, [hl]
|
||
|
.jmptable ; s02_AE2C
|
||
|
jp hl
|
||
|
dw ROP_SetAddr ; $01
|
||
|
dw ROP_InitChecksum ; $02
|
||
|
dw ROP_FetchByte ; $03
|
||
|
dw ROP_end ; $04
|
||
|
dw ROP_ApplyCrypto ; $05
|
||
|
dw ROP_RotateBuffer ; $06
|
||
|
dw ROP_InitCrypto ; $07
|
||
|
dw ROP_AddChecksum ; $08
|
||
|
dw ROP_XorChecksum ; $09
|
||
|
dw $0000 ; $0A
|
||
|
dw ROP_WriteChecksumByte ; $0B
|
||
|
dw ROP_rept ; $0C
|
||
|
dw ROP_StoreByte ; $0D
|
||
|
dw ROP_LoadByte ; $0E
|
||
|
|
||
|
ROP_end: ; s02_AE4A
|
||
|
ld bc, $0100
|
||
|
ld de, $CB00
|
||
|
ld hl, $AE58
|
||
|
ld af, $FF00
|
||
|
call CopyBytes
|
||
|
; Here's the destination of the copied code,
|
||
|
; it does some shit to copy the buffer back to the SRAM.
|
||
|
; I don't really care what it does.
|
||
|
|
||
|
UpdateSaveSpinner: ; s02_AEDB
|
||
|
ld hl,s02_9A12
|
||
|
ld b,$C0
|
||
|
ld a,[s02_ADB9]
|
||
|
inc a
|
||
|
and a,%11
|
||
|
ld [s02_ADB9],a
|
||
|
add b
|
||
|
ld b,a
|
||
|
|
||
|
; Wait for HBlank
|
||
|
.loop ; s02_AEEB
|
||
|
ldh a,[rSTAT]
|
||
|
and a,%11
|
||
|
jr nz,.loop
|
||
|
|
||
|
ld [hl],b
|
||
|
ret
|
||
|
|
||
|
ROP_SetAddr: ; s02_AEF3
|
||
|
; sSaveSource = param
|
||
|
|
||
|
ld hl, sSaveSource
|
||
|
ld a, [de]
|
||
|
ld [hl+], a
|
||
|
inc de
|
||
|
ld a, [de]
|
||
|
ld [hl+], a
|
||
|
inc de
|
||
|
ld hl, ROP_SaveMain
|
||
|
jp hl
|
||
|
|
||
|
ROP_InitChecksum: ; s02_AF09
|
||
|
; sSaveBlockChecksum = param
|
||
|
|
||
|
ld hl, sSaveBlockChecksum
|
||
|
ld a, [de]
|
||
|
inc de
|
||
|
ld [hl+], a
|
||
|
ld hl, ROP_SaveMain
|
||
|
jp hl
|
||
|
|
||
|
ROP_FetchByte: ; s02_AF19
|
||
|
; w00_C800 = *(sSaveSource++)
|
||
|
|
||
|
; Fetch byte from pointer stored at sSaveSource
|
||
|
ld hl, sSaveSource
|
||
|
ldw hl, [hl]
|
||
|
ld a, [hl+]
|
||
|
|
||
|
; Save incremented pointer back into sSaveSource
|
||
|
ld b, h
|
||
|
ld c, l
|
||
|
ld hl, sSaveSource
|
||
|
ld [hl], c
|
||
|
inc hl
|
||
|
ld [hl], b
|
||
|
|
||
|
; Save byte into w00_C800
|
||
|
ld hl, w00_C800
|
||
|
ld [hl+], a
|
||
|
|
||
|
ld hl, ROP_SaveMain
|
||
|
jp hl
|
||
|
|
||
|
ROP_ApplyCrypto: ; s02_AF3B
|
||
|
; w00_C800 ^= func(s02_ADB1)
|
||
|
|
||
|
; s02_ADB2 ^= (s02_ADB1 + 1) ^ s02_ADB4
|
||
|
ld hl, s02_ADB1
|
||
|
inc [hl]
|
||
|
ld b, [hl] ; s02_ADB1
|
||
|
ld a, [hl+]
|
||
|
ld a, [hl+]
|
||
|
ld a, [hl+]
|
||
|
ld a, [hl-] ; s02_ADB4
|
||
|
xor b
|
||
|
ld b, a
|
||
|
ld a, [hl-]
|
||
|
ld a, [hl-] ; s02_ADB2
|
||
|
inc hl
|
||
|
xor b
|
||
|
ld [hl+], a ; s02_ADB2
|
||
|
|
||
|
; s02_ADB3 += s02_ADB2
|
||
|
ld b, a
|
||
|
ld a, [hl-] ; s02_ADB3
|
||
|
inc hl
|
||
|
add b
|
||
|
ld [hl+], a ; s02_ADB3
|
||
|
|
||
|
; s02_ADB4 = s02_ADB2 ^ (s02_ADB4 + (s02_ADB3 / 2))
|
||
|
srl a
|
||
|
ld b, a
|
||
|
ld a, [hl-] ; s02_ADB4
|
||
|
add b
|
||
|
ld b, a
|
||
|
ld a, [hl-]
|
||
|
ld a, [hl+] ; s02_ADB2
|
||
|
xor b
|
||
|
inc hl
|
||
|
ld [hl+], a ; s02_ADB4
|
||
|
|
||
|
; w00_C800 ^= s02_ADB4
|
||
|
ld hl, w00_C800
|
||
|
xor [hl]
|
||
|
ld [hl+], a
|
||
|
|
||
|
ld hl, ROP_SaveMain
|
||
|
jp hl
|
||
|
|
||
|
ROP_RotateBuffer: ; s02_AF85
|
||
|
; s02_ADB8 = ((s02_ADB8 + 1) | $C0) ^ $C0
|
||
|
; s02_ADB8 = (s02_ADB8 + 1) & 0x3F
|
||
|
ld hl, s02_ADB8
|
||
|
ld a, [hl-]
|
||
|
inc a
|
||
|
ld hl, $07FC
|
||
|
or [hl]
|
||
|
ld bc, $C000
|
||
|
xor b
|
||
|
ld hl, s02_ADB8
|
||
|
ld [hl+], a
|
||
|
|
||
|
; Called every 64 times this function is ran
|
||
|
and a
|
||
|
call z, UpdateSaveSpinner
|
||
|
|
||
|
; Save ROPScript pointer
|
||
|
ld hl, sROPScriptBackup
|
||
|
ld a, e
|
||
|
ld [hl+], a
|
||
|
ld [hl], d
|
||
|
|
||
|
; Rotate the entire buffer, using sBufferCarry as carry
|
||
|
ld hl, w00_C800
|
||
|
ld a, [hl+]
|
||
|
ld hl, sBufferCarry
|
||
|
ld [hl+], a
|
||
|
ld bc, $01B0
|
||
|
ld de, w00_C800
|
||
|
ld hl, w00_C800 + 1
|
||
|
ld af, $FF00
|
||
|
call CopyBytes ; bc bytes from hl to de
|
||
|
ld hl, sBufferCarry
|
||
|
ld a, [hl+]
|
||
|
ld hl, w00_C9AF
|
||
|
ld [hl+], a
|
||
|
|
||
|
; Restore ROPScript pointer
|
||
|
ld hl, sROPScriptBackup
|
||
|
ld a, [hl+]
|
||
|
ld d, [hl]
|
||
|
ld e, a
|
||
|
|
||
|
ld hl, ROP_SaveMain
|
||
|
jp hl
|
||
|
|
||
|
ROP_InitCrypto: ; s02_AFE3
|
||
|
; s02_ADB1 = param
|
||
|
|
||
|
ld hl, s02_ADB1
|
||
|
ld a, [de]
|
||
|
ld [hl+], a
|
||
|
inc de
|
||
|
ld a, [de]
|
||
|
ld [hl+], a
|
||
|
inc de
|
||
|
ld a, [de]
|
||
|
ld [hl+], a
|
||
|
inc de
|
||
|
ld a, [de]
|
||
|
ld [hl+], a
|
||
|
inc de
|
||
|
ld hl, ROP_SaveMain
|
||
|
jp hl
|
||
|
|
||
|
ROP_AddChecksum: ; s02_B005
|
||
|
; sSaveBlockChecksum += w00_C800
|
||
|
|
||
|
ld hl, ROPGadget_variable
|
||
|
ld af, $8600 ; add [hl]
|
||
|
ld [hl+], a
|
||
|
ld hl, ROP_s02_B01B
|
||
|
jp hl
|
||
|
|
||
|
ROP_XorChecksum: ; s02_B013
|
||
|
; sSaveBlockChecksum ^= w00_C800
|
||
|
|
||
|
ld hl, ROPGadget_variable
|
||
|
ld af, $AE00 ; xor [hl]
|
||
|
ld [hl+], a
|
||
|
|
||
|
; fallthrough
|
||
|
|
||
|
ROP_s02_B01B: ; s02_B01B
|
||
|
ld hl, sSaveBlockChecksum
|
||
|
ld a, [hl+]
|
||
|
ld hl, w00_C800
|
||
|
add [hl]/xor [hl] ; Modified by caller
|
||
|
ld hl, sSaveBlockChecksum
|
||
|
ld [hl+], a
|
||
|
ld hl, ROP_SaveMain
|
||
|
jp hl
|
||
|
|
||
|
ROP_WriteChecksumByte: ; s02_B033
|
||
|
; w00_C800 = sSaveBlockChecksum
|
||
|
|
||
|
ld hl, sSaveBlockChecksum
|
||
|
ld a, [hl+]
|
||
|
ld hl, w00_C800
|
||
|
ld [hl+], a
|
||
|
ld hl, ROP_SaveMain
|
||
|
jp hl
|
||
|
|
||
|
ROP_StoreByte: ; s02_B045
|
||
|
; *(sSaveSource++) = sSaveBlockChecksum
|
||
|
|
||
|
; *sSaveSource = sSaveBlockChecksum
|
||
|
ld hl, sSaveBlockChecksum
|
||
|
ld b, [hl]
|
||
|
ld hl, sSaveSource
|
||
|
ldw hl, [hl]
|
||
|
ld [hl], b
|
||
|
inc hl
|
||
|
|
||
|
; sSaveSource = sSaveSource + 1
|
||
|
ld b, h
|
||
|
ld c, l
|
||
|
ld hl, sSaveSource
|
||
|
ld [hl], c
|
||
|
inc hl
|
||
|
ld [hl], b
|
||
|
|
||
|
ld hl, ROP_SaveMain
|
||
|
jp hl
|
||
|
|
||
|
ROP_LoadByte: ; s02_B069
|
||
|
; sSaveBlockChecksum = *sSaveSource
|
||
|
|
||
|
ld hl, sSaveSource
|
||
|
ldw hl, [hl]
|
||
|
ld a, [hl+]
|
||
|
ld hl, sSaveBlockChecksum
|
||
|
ld [hl+], a
|
||
|
|
||
|
ld hl, ROP_SaveMain
|
||
|
jp hl
|
||
|
|
||
|
ROP_rept: ; s02_B07D
|
||
|
; do {} while(param[2]--);
|
||
|
|
||
|
; Fetch jump pointer to bc
|
||
|
ld a, [de]
|
||
|
ld c, a
|
||
|
inc de
|
||
|
ld a, [de]
|
||
|
ld b, a
|
||
|
inc de
|
||
|
|
||
|
; If param == 0, return
|
||
|
ld a, [de]
|
||
|
inc de
|
||
|
ld hl, ROP_SaveMain
|
||
|
and a
|
||
|
call z, (jp hl)
|
||
|
|
||
|
; Decrement parameter, if 0, return
|
||
|
dec a
|
||
|
dec de
|
||
|
ld [de], a
|
||
|
inc de
|
||
|
ld hl, ROP_SaveMain
|
||
|
call z, (jp hl)
|
||
|
|
||
|
; Jump to the script at bc
|
||
|
ld d, b
|
||
|
ld a, c
|
||
|
ld e, a
|
||
|
ld hl, ROP_SaveMain
|
||
|
jp hl
|
||
|
|
||
|
ROPScript_SaveMain: ; s02_B0B3
|
||
|
; ==========================================================================
|
||
|
; Start compiling data into save blob, and applying first crypto layer.
|
||
|
; Each "section" of the save blob has its own, fixed crypto seed and checksum.
|
||
|
; ==========================================================================
|
||
|
|
||
|
; sSaveSource = $FCDF
|
||
|
dbw $01, $FCDF ; ROP_SetAddr
|
||
|
|
||
|
; sSaveBlockChecksum = $7F
|
||
|
dbb $02, $7F ; ROP_InitChecksum
|
||
|
|
||
|
; s02_ADB1 = $8C10E62F
|
||
|
dbl $07, $8C10E62F ; ROP_InitCrypto
|
||
|
|
||
|
.s02_B0BD
|
||
|
; rept ($48) {
|
||
|
; w00_C800 = *(sSaveSource++)
|
||
|
db $03 ; ROP_FetchByte
|
||
|
|
||
|
; w00_C800 ^= func(s02_ADB1)
|
||
|
db $05 ; ROP_ApplyCrypto
|
||
|
|
||
|
; sSaveBlockChecksum += w00_C800
|
||
|
db $08 ; ROP_AddChecksum
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
|
||
|
; w00_C800 = *(sSaveSource++)
|
||
|
db $03 ; ROP_FetchByte
|
||
|
|
||
|
; sSaveBlockChecksum ^= w00_C800
|
||
|
db $09 ; ROP_XorChecksum
|
||
|
|
||
|
; w00_C800 ^= func(s02_ADB1)
|
||
|
db $05 ; ROP_ApplyCrypto
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
; }
|
||
|
dbwb $0C, .s02_B0BD, $48 ; ROP_rept
|
||
|
|
||
|
; w00_C800 = sSaveBlockChecksum
|
||
|
db $0B ; ROP_WriteChecksumByte
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
|
||
|
; sSaveSource = $FA7A
|
||
|
dbw $01, $FA7A ; ROP_SetAddr
|
||
|
|
||
|
; sSaveBlockChecksum = $C2
|
||
|
dbb $02, $C2 ; ROP_InitChecksum
|
||
|
|
||
|
; s02_ADB1 = $6AF528C2
|
||
|
dbl $07, $6AF528C2 ; ROP_InitCrypto
|
||
|
|
||
|
.s02_B0D5
|
||
|
; rept ($14) {
|
||
|
; w00_C800 = *(sSaveSource++)
|
||
|
db $03 ; ROP_FetchByte
|
||
|
|
||
|
; w00_C800 ^= func(s02_ADB1)
|
||
|
db $05 ; ROP_ApplyCrypto
|
||
|
|
||
|
; sSaveBlockChecksum ^= w00_C800
|
||
|
db $09 ; ROP_XorChecksum
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
; }
|
||
|
dbwb $0C, .s02_B0D5, $14 ; ROP_rept
|
||
|
|
||
|
; w00_C800 = sSaveBlockChecksum
|
||
|
db $0B ; ROP_WriteChecksumByte
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
|
||
|
; sSaveSource = $F84E
|
||
|
dbw $01, $F84E ; ROP_SetAddr
|
||
|
|
||
|
.s02_B0E2
|
||
|
; rept ($03) {
|
||
|
; w00_C800 = *(sSaveSource++)
|
||
|
db $03 ; ROP_FetchByte
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
; }
|
||
|
dbwb $0C, .s02_B0E2, $03 ; ROP_rept
|
||
|
|
||
|
; sSaveSource = $F859
|
||
|
dbw $01, $F859 ; ROP_SetAddr
|
||
|
|
||
|
; sSaveBlockChecksum = $06
|
||
|
dbb $02, $06 ; ROP_InitChecksum
|
||
|
|
||
|
; s02_ADB1 = $EF7305A6
|
||
|
dbl $07, $EF7305A6 ; ROP_InitCrypto
|
||
|
|
||
|
.s02_B0F2
|
||
|
; rept ($4C) {
|
||
|
; w00_C800 = *(sSaveSource++)
|
||
|
db $03 ; ROP_FetchByte
|
||
|
|
||
|
; w00_C800 ^= func(s02_ADB1)
|
||
|
db $05 ; ROP_ApplyCrypto
|
||
|
|
||
|
; sSaveBlockChecksum ^= w00_C800
|
||
|
db $09 ; ROP_XorChecksum
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
|
||
|
; w00_C800 = *(sSaveSource++)
|
||
|
db $03 ; ROP_FetchByte
|
||
|
|
||
|
; w00_C800 ^= func(s02_ADB1)
|
||
|
db $05 ; ROP_ApplyCrypto
|
||
|
|
||
|
; sSaveBlockChecksum += w00_C800
|
||
|
db $08 ; ROP_AddChecksum
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
; }
|
||
|
dbwb $0C, .s02_B0F2, $4C ; ROP_rept
|
||
|
|
||
|
; w00_C800 = sSaveBlockChecksum
|
||
|
db $0B ; ROP_WriteChecksumByte
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
|
||
|
; sSaveSource = $DE41
|
||
|
dbw $01, $DE41 ; ROP_SetAddr
|
||
|
|
||
|
; s02_ADB1 = $2A7FEC38
|
||
|
dbl $07, $2A7FEC38 ; ROP_InitCrypto
|
||
|
|
||
|
; sSaveBlockChecksum = $3C
|
||
|
dbb $02, $3C ; ROP_InitChecksum
|
||
|
|
||
|
.s02_B10A
|
||
|
; rept ($21) {
|
||
|
; w00_C800 = *(sSaveSource++)
|
||
|
db $03 ; ROP_FetchByte
|
||
|
|
||
|
; sSaveBlockChecksum += w00_C800
|
||
|
db $08 ; ROP_AddChecksum
|
||
|
|
||
|
; w00_C800 ^= func(s02_ADB1)
|
||
|
db $05 ; ROP_ApplyCrypto
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
; }
|
||
|
dbwb $0C, .s02_B10A, $21 ; ROP_rept
|
||
|
|
||
|
; w00_C800 = sSaveBlockChecksum
|
||
|
db $0B ; ROP_WriteChecksumByte
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
|
||
|
; sSaveSource = $DE99
|
||
|
dbw $01, $DE99 ; ROP_SetAddr
|
||
|
|
||
|
; sSaveBlockChecksum = $E2
|
||
|
dbb $02, $E2 ; ROP_InitChecksum
|
||
|
|
||
|
; s02_ADB1 = $4BFC1115
|
||
|
dbl $07, $4BFC1115 ; ROP_InitCrypto
|
||
|
|
||
|
.s02_B11E
|
||
|
; rept ($40) {
|
||
|
; w00_C800 = *(sSaveSource++)
|
||
|
db $03 ; ROP_FetchByte
|
||
|
|
||
|
; w00_C800 ^= func(s02_ADB1)
|
||
|
db $05 ; ROP_ApplyCrypto
|
||
|
|
||
|
; sSaveBlockChecksum += w00_C800
|
||
|
db $08 ; ROP_AddChecksum
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
; }
|
||
|
dbwb $0C, .s02_B11E, $40 ; ROP_rept
|
||
|
|
||
|
; w00_C800 = sSaveBlockChecksum
|
||
|
db $0B ; ROP_WriteChecksumByte
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
|
||
|
; s02_ADB1 = $A23F387C
|
||
|
dbl $07, $A23F387C ; ROP_InitCrypto
|
||
|
|
||
|
; sSaveBlockChecksum = $16
|
||
|
dbb $02, $16 ; ROP_InitChecksum
|
||
|
|
||
|
; sSaveSource = $A003
|
||
|
dbw $01, $A003 ; ROP_SetAddr
|
||
|
|
||
|
.s02_B132
|
||
|
; rept ($04) {
|
||
|
; w00_C800 = *(sSaveSource++)
|
||
|
db $03 ; ROP_FetchByte
|
||
|
|
||
|
; w00_C800 ^= func(s02_ADB1)
|
||
|
db $05 ; ROP_ApplyCrypto
|
||
|
|
||
|
; sSaveBlockChecksum ^= w00_C800
|
||
|
db $09 ; ROP_XorChecksum
|
||
|
|
||
|
; sSaveBlockChecksum += w00_C800
|
||
|
db $08 ; ROP_AddChecksum
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
; }
|
||
|
dbwb $0C, .s02_B132, $04 ; ROP_rept
|
||
|
|
||
|
; w00_C800 = sSaveBlockChecksum
|
||
|
db $0B ; ROP_WriteChecksumByte
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
|
||
|
; ==========================================================================
|
||
|
; End compiling data into save blob.
|
||
|
; ==========================================================================
|
||
|
|
||
|
|
||
|
; ==========================================================================
|
||
|
; Apply second layer of crypto onto the save file as a whole.
|
||
|
; The seed for this crypto is based on random bytes,
|
||
|
; which are stored in the final blob as well.
|
||
|
; ==========================================================================
|
||
|
|
||
|
; sSaveBlockChecksum = $00
|
||
|
dbb $02, $00 ; ROP_InitChecksum
|
||
|
|
||
|
; sSaveSource = $FFE1
|
||
|
dbw $01, $FFE1 ; ROP_SetAddr
|
||
|
|
||
|
; w00_C800 = *(sSaveSource++)
|
||
|
db $03 ; ROP_FetchByte
|
||
|
|
||
|
; sSaveBlockChecksum += w00_C800
|
||
|
db $08 ; ROP_AddChecksum
|
||
|
|
||
|
; sSaveSource = $B16B
|
||
|
dbw $01, $B16B ; ROP_SetAddr
|
||
|
|
||
|
; *(sSaveSource++) = sSaveBlockChecksum
|
||
|
db $0D ; ROP_StoreByte
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
|
||
|
; sSaveSource = $FFE2
|
||
|
dbw $01, $FFE2 ; ROP_SetAddr
|
||
|
|
||
|
; w00_C800 = *(sSaveSource++)
|
||
|
db $03 ; ROP_FetchByte
|
||
|
|
||
|
; sSaveBlockChecksum ^= w00_C800
|
||
|
db $09 ; ROP_XorChecksum
|
||
|
|
||
|
; w00_C800 = sSaveBlockChecksum
|
||
|
db $0B ; ROP_WriteChecksumByte
|
||
|
|
||
|
; sSaveSource = $B16C
|
||
|
dbw $01, $B16C ; ROP_SetAddr
|
||
|
|
||
|
; *(sSaveSource++) = sSaveBlockChecksum
|
||
|
db $0D ; ROP_StoreByte
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
|
||
|
; sSaveSource = $FF04
|
||
|
dbw $01, $FF04 ; ROP_SetAddr
|
||
|
|
||
|
; w00_C800 = *(sSaveSource++)
|
||
|
db $03 ; ROP_FetchByte
|
||
|
|
||
|
; sSaveBlockChecksum += w00_C800
|
||
|
db $08 ; ROP_AddChecksum
|
||
|
|
||
|
; w00_C800 = sSaveBlockChecksum
|
||
|
db $0B ; ROP_WriteChecksumByte
|
||
|
|
||
|
; sSaveSource = $B16D
|
||
|
dbw $01, $B16D ; ROP_SetAddr
|
||
|
|
||
|
; *(sSaveSource++) = sSaveBlockChecksum
|
||
|
db $0D ; ROP_StoreByte
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
|
||
|
; sSaveSource = $FF05
|
||
|
dbw $01, $FF05 ; ROP_SetAddr
|
||
|
|
||
|
; w00_C800 = *(sSaveSource++)
|
||
|
db $03 ; ROP_FetchByte
|
||
|
|
||
|
; sSaveBlockChecksum ^= w00_C800
|
||
|
db $09 ; ROP_XorChecksum
|
||
|
|
||
|
; w00_C800 = sSaveBlockChecksum
|
||
|
db $0B ; ROP_WriteChecksumByte
|
||
|
|
||
|
; sSaveSource = $B16E
|
||
|
dbw $01, $B16E ; ROP_SetAddr
|
||
|
|
||
|
; *(sSaveSource++) = sSaveBlockChecksum
|
||
|
db $0D ; ROP_StoreByte
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
|
||
|
; NOTE: The parameter of this command is modified by the commands above.
|
||
|
; s02_ADB1 = $EFBEADDE
|
||
|
dbl $07, $EFBEADDE ; ROP_InitCrypto
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
|
||
|
; sSaveBlockChecksum = $55
|
||
|
dbb $02, $55 ; ROP_InitChecksum
|
||
|
|
||
|
; sSaveSource = $F350
|
||
|
dbw $01, $F350 ; ROP_SetAddr
|
||
|
|
||
|
; *(sSaveSource++) = sSaveBlockChecksum
|
||
|
db $0D ; ROP_StoreByte
|
||
|
|
||
|
; *(sSaveSource++) = sSaveBlockChecksum
|
||
|
db $0D ; ROP_StoreByte
|
||
|
|
||
|
.s02_B178
|
||
|
; rept ($1AB) {
|
||
|
; sSaveSource = $F350
|
||
|
dbw $01, $F350 ; ROP_SetAddr
|
||
|
|
||
|
; sSaveBlockChecksum = *sSaveSource
|
||
|
db $0E ; ROP_LoadByte
|
||
|
|
||
|
; sSaveBlockChecksum += w00_C800
|
||
|
db $08 ; ROP_AddChecksum
|
||
|
|
||
|
; *(sSaveSource++) = sSaveBlockChecksum
|
||
|
db $0D ; ROP_StoreByte
|
||
|
|
||
|
; sSaveBlockChecksum = *sSaveSource
|
||
|
db $0E ; ROP_LoadByte
|
||
|
|
||
|
; sSaveBlockChecksum ^= w00_C800
|
||
|
db $09 ; ROP_XorChecksum
|
||
|
|
||
|
; *(sSaveSource++) = sSaveBlockChecksum
|
||
|
db $0D ; ROP_StoreByte
|
||
|
|
||
|
; w00_C800 ^= func(s02_ADB1)
|
||
|
db $05 ; ROP_ApplyCrypto
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
; }
|
||
|
dbwb $0C, .s02_B178, $D5 ; ROP_rept
|
||
|
dbwb $0C, .s02_B178, $D6 ; ROP_rept
|
||
|
|
||
|
; sSaveBlockChecksum = $CC
|
||
|
dbb $02, $CC ; ROP_InitChecksum
|
||
|
|
||
|
; sSaveSource = $ADB1
|
||
|
dbw $01, $ADB1 ; ROP_SetAddr
|
||
|
|
||
|
; sSaveBlockChecksum ^= w00_C800
|
||
|
db $09 ; ROP_XorChecksum
|
||
|
|
||
|
; *(sSaveSource++) = sSaveBlockChecksum
|
||
|
db $0D ; ROP_StoreByte
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
|
||
|
; sSaveBlockChecksum ^= w00_C800
|
||
|
db $09 ; ROP_XorChecksum
|
||
|
|
||
|
; *(sSaveSource++) = sSaveBlockChecksum
|
||
|
db $0D ; ROP_StoreByte
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
|
||
|
; sSaveBlockChecksum ^= w00_C800
|
||
|
db $09 ; ROP_XorChecksum
|
||
|
|
||
|
; *(sSaveSource++) = sSaveBlockChecksum
|
||
|
db $0D ; ROP_StoreByte
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
|
||
|
; sSaveBlockChecksum ^= w00_C800
|
||
|
db $09 ; ROP_XorChecksum
|
||
|
|
||
|
; *(sSaveSource++) = sSaveBlockChecksum
|
||
|
db $0D ; ROP_StoreByte
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
|
||
|
; sSaveSource = $F350
|
||
|
dbw $01, $F350 ; ROP_SetAddr
|
||
|
|
||
|
; w00_C800 = *(sSaveSource++)
|
||
|
db $03 ; ROP_FetchByte
|
||
|
|
||
|
; w00_C800 ^= func(s02_ADB1)
|
||
|
db $05 ; ROP_ApplyCrypto
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
|
||
|
; w00_C800 = *(sSaveSource++)
|
||
|
db $03 ; ROP_FetchByte
|
||
|
|
||
|
; w00_C800 ^= func(s02_ADB1)
|
||
|
db $05 ; ROP_ApplyCrypto
|
||
|
|
||
|
; rotatebuffer(w00_C800)
|
||
|
db $06 ; ROP_RotateBuffer
|
||
|
|
||
|
|
||
|
; Copy save blob from the buffer to final location in SRAM, and end.
|
||
|
db $04 ; ROP_end
|
||
|
|
||
|
|
||
|
; Temporary save location for the DelayFrame return pointer
|
||
|
sVBlankReturnPointer: dw ; s02_B4E6
|
||
|
|
||
|
VBlankHook_Save: ; s02_B673
|
||
|
; Saving hook code
|
||
|
|
||
|
; Check if the "P" tile is on the screen (part of "PLAYER")
|
||
|
ld a,[$C4CD] ; wTileMap + ???
|
||
|
cp a,"P" ; $8F
|
||
|
ret nz
|
||
|
|
||
|
; Check that we're trying to make a textbox for saving the game
|
||
|
ld hl,[sp+$12]
|
||
|
ldi a,[hl]
|
||
|
cp a,LOW(Text_WouldYouLikeToSaveTheGame)
|
||
|
ret nz
|
||
|
ldd a,[hl]
|
||
|
cp a,HIGH(Text_WouldYouLikeToSaveTheGame)
|
||
|
ret nz
|
||
|
|
||
|
; Change that text pointer to an empty text box (only include the TX_END command)
|
||
|
ld [hl],LOW($0134)
|
||
|
inc hl
|
||
|
ld [hl],HIGH($0134)
|
||
|
|
||
|
; Change the MapTextbox return address to skip to the end of SaveTheGame_yesorno
|
||
|
ld hl,sp+$16
|
||
|
ld [hl],LOW(SaveTheGame_yesorno + 27) ; $4BCA
|
||
|
|
||
|
; Change the SaveTheGame_yesorno return address to skip to SaveMenu.refused
|
||
|
inc hl
|
||
|
inc hl
|
||
|
ld [hl],LOW(SaveMenu.refused)
|
||
|
inc hl
|
||
|
ld [hl],HIGH(SaveMenu.refused)
|
||
|
|
||
|
; Overwrite return pointer for the vblank hook
|
||
|
ld hl,SaveGame
|
||
|
ld a,l
|
||
|
ld [sVBlankReturnPointer],a
|
||
|
ld a,h
|
||
|
ld [sVBlankReturnPointer + 1],a
|
||
|
ld a,BANK(SaveGame)
|
||
|
ld [wVBlankReturnBank],a ; Overwrite return bank?
|
||
|
ret
|
||
|
|
||
|
UninstallVBlankHook: ; s02_B711
|
||
|
ld hl, hTransferVirtualOAM
|
||
|
ld [hl], $3E ; ld a, n8
|
||
|
inc hl
|
||
|
ld [hl], $C4
|
||
|
ret
|
||
|
|
||
|
w00_C800: ds $1b0 ; w00_C800
|
||
|
w00_C9AF: ; w00_C9AF
|
||
|
|
||
|
wOptions: db ; w01_CFCC
|
||
|
wPartyCount: db ; w01_DCD7
|
||
|
|
||
|
w01_DF34: db
|
||
|
wVBlankReturnBank: db ; w01_DF35
|
||
|
wSavingAllowed: db ; w01_DF3A
|