TheZZAZZGlitch's April Fools Event 2019
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.
 
 
 
 

997 lines
21 KiB

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