Implement the engine to backup map objects when chaning maps (#32)

This commit is contained in:
xCrystal 2023-12-15 19:10:47 +01:00
parent 2bca51eb09
commit d097191ab1
11 changed files with 249 additions and 14 deletions

View File

@ -151,12 +151,12 @@ $(foreach obj, $(pokecrystal11_vc_obj), $(eval $(call DEP,$(obj),$(obj:11_vc.o=.
endif
pokecrystal_opt = -Cjv -t PM_CRYSTAL -i BYTE -n 0 -k 01 -l 0x33 -m 0x1b -r 3 -p 0
pokecrystal11_opt = -Cjv -t PM_CRYSTAL -i BYTE -n 1 -k 01 -l 0x33 -m 0x1b -r 3 -p 0
pokecrystal_au_opt = -Cjv -t PM_CRYSTAL -i BYTU -n 0 -k 01 -l 0x33 -m 0x1b -r 3 -p 0
pokecrystal_debug_opt = -Cjv -t PM_CRYSTAL -i BYTE -n 0 -k 01 -l 0x33 -m 0x1b -r 3 -p 0
pokecrystal11_debug_opt = -Cjv -t PM_CRYSTAL -i BYTE -n 1 -k 01 -l 0x33 -m 0x1b -r 3 -p 0
pokecrystal11_vc_opt = -Cjv -t PM_CRYSTAL -i BYTE -n 1 -k 01 -l 0x33 -m 0x1b -r 3 -p 0
pokecrystal_opt = -Cjv -t PM_CRYSTAL -i BYTE -n 0 -k 01 -l 0x33 -m 0x1b -r 5 -p 0
pokecrystal11_opt = -Cjv -t PM_CRYSTAL -i BYTE -n 1 -k 01 -l 0x33 -m 0x1b -r 5 -p 0
pokecrystal_au_opt = -Cjv -t PM_CRYSTAL -i BYTU -n 0 -k 01 -l 0x33 -m 0x1b -r 5 -p 0
pokecrystal_debug_opt = -Cjv -t PM_CRYSTAL -i BYTE -n 0 -k 01 -l 0x33 -m 0x1b -r 5 -p 0
pokecrystal11_debug_opt = -Cjv -t PM_CRYSTAL -i BYTE -n 1 -k 01 -l 0x33 -m 0x1b -r 5 -p 0
pokecrystal11_vc_opt = -Cjv -t PM_CRYSTAL -i BYTE -n 1 -k 01 -l 0x33 -m 0x1b -r 5 -p 0
%.gbc: $$(%_obj) layout.link
$(RGBLINK) -n $*.sym -m $*.map -l layout.link -o $@ $(filter %.o,$^)

View File

@ -26,7 +26,7 @@ DEF MBC3RTC EQU $a000
DEF SRAM_DISABLE EQU $00
DEF SRAM_ENABLE EQU $0a
DEF NUM_SRAM_BANKS EQU 4
DEF NUM_SRAM_BANKS EQU 8
DEF RTC_S EQU $08 ; Seconds 0-59 (0-3Bh)
DEF RTC_M EQU $09 ; Minutes 0-59 (0-3Bh)

View File

@ -54,3 +54,4 @@ MapSetupCommands:
add_mapsetup SpawnInCustomFacing ; 2f
add_mapsetup ResetLevelScopedEventFlags ; 30
add_mapsetup AnchorPointAfterWarp ; 31
add_mapsetup BackupMapObjects ; 32

View File

@ -58,6 +58,7 @@ MapSetupScript_Fly:
MapSetupScript_Warp:
mapsetup DisableLCD
mapsetup InitSound
mapsetup BackupMapObjects
mapsetup EnterMapSpawnPoint
mapsetup LoadMapAttributes
mapsetup HandleNewMap
@ -82,6 +83,7 @@ MapSetupScript_Warp:
db -1 ; end
MapSetupScript_BadWarp:
mapsetup BackupMapObjects
mapsetup EnterMapSpawnPoint
mapsetup LoadMapAttributes
mapsetup HandleNewMap
@ -108,6 +110,7 @@ MapSetupScript_BadWarp:
MapSetupScript_Connection:
mapsetup SuspendMapAnims
mapsetup BackupMapObjects
mapsetup EnterMapConnection
mapsetup LoadMapAttributes
mapsetup HandleNewMap
@ -129,6 +132,7 @@ MapSetupScript_Fall:
MapSetupScript_Door:
mapsetup FadeOutPalettesToWhite
MapSetupScript_Train:
mapsetup BackupMapObjects
mapsetup EnterMapWarp
mapsetup LoadMapAttributes
mapsetup GetWarpDestCoords

View File

@ -89,6 +89,7 @@ BoardMenuScript::
end
.EnterViewMapMode:
call BackupMapObjectsOnEnterViewMapMode
ld hl, wVramState
res 2, [hl]
ld a, BOARDEVENT_VIEW_MAP_MODE

View File

@ -269,6 +269,7 @@ PromptPlayerToChooseBranchDirection:
jp PlayClickSFX
.EnterViewMapMode:
call BackupMapObjectsOnEnterViewMapMode
ld a, BOARDEVENT_VIEW_MAP_MODE
ldh [hCurBoardEvent], a
ld a, 100

View File

@ -289,6 +289,7 @@ SaveGameData:
call SaveOptions
call SavePlayerData
call SavePokemonData
call SaveMapObjectsBackupsData
call SaveBox
call SaveChecksum
call ValidateBackupSave
@ -446,6 +447,22 @@ SavePokemonData:
call CloseSRAM
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
@ -526,6 +543,7 @@ TryLoadSaveFile:
jr nz, .backup
call LoadPlayerData
call LoadPokemonData
call LoadMapObjectsBackupsData
call LoadBox
farcall RestorePartyMonMail
call ValidateBackupSave
@ -541,6 +559,7 @@ TryLoadSaveFile:
jr nz, .corrupt
call LoadBackupPlayerData
call LoadBackupPokemonData
call LoadMapObjectsBackupsData
call LoadBox
farcall RestorePartyMonMail
call ValidateSave
@ -677,6 +696,22 @@ LoadPokemonData:
call CloseSRAM
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

View File

@ -135,7 +135,7 @@ CheckTrainerAndTalkerEvents:
bit 5, [hl]
ret
; on enter overworld loop
; on enter overworld loop (MAPSETUP_ENTERLEVEL or MAPSETUP_CONTINUE)
StartMap:
xor a
ldh [hScriptVar], a
@ -147,13 +147,39 @@ StartMap:
farcall InitCallReceiveDelay
call ClearJoypad
; initialize board state
ld a, [hMapEntryMethod]
cp MAPSETUP_ENTERLEVEL
jr nz, .not_starting_level
; initialize board state
xor a
ld [wCurTurn], a
ld [wCurSpace], a
; initialize overworld state
ld hl, wNextWarp
xor a
ld [hli], a ; wNextWarp
ld [hli], a ; wNextMapGroup
ld [hli], a ; wNextMapNumber
ld [hli], a ; wPrevWarp
ld [hli], a ; wPrevMapGroup
ld [hl], a ; wPrevMapNumber
ld a, BANK(wMapObjectsBackups)
ld [rSVBK], a
ld e, NUM_MAP_OBJECTS_BACKUPS
ld hl, wMapObjectsBackups
ld bc, wMap2ObjectsBackup - wMap1ObjectsBackup
.loop
ld a, GROUP_N_A
ld [hl], a
add hl, bc
dec e
jr nz, .loop
ld [hl], $00 ; list terminator
ld a, 1
ld [rSVBK], a
.not_starting_level
ld a, BOARDEVENT_DISPLAY_MENU
ldh [hCurBoardEvent], a

View File

@ -144,6 +144,7 @@ EnterMapConnection:
ld [wOverworldMapAnchor], a
ld a, h
ld [wOverworldMapAnchor + 1], a
.done
scf
ret

View File

@ -358,6 +358,87 @@ CheckIndoorMap::
xor a
ret ; z
BackupMapObjects::
; this setup script is called just before the EnterMap* setup script,
; when wMapGroup and wMapNumber still contain the about-to-leave map.
; there is no need to backup map objects when going through connections during View Map mode,
; as during this mode there is no possible interaction that leads to a map objec changing status.
; BackupMapObjectsOnEnterViewMapMode is called when entering View Map mode.
ldh a, [hCurBoardEvent]
cp BOARDEVENT_VIEW_MAP_MODE
ret z
; fallthrough
BackupMapObjectsOnEnterViewMapMode::
ld hl, wMapGroup
ld a, [hli]
ld d, a ; d = wMapGroup
ld e, [hl] ; e = wMapNumber
ld a, BANK(wMapObjectsBackups)
ld [rSVBK], a
ld hl, wMap1ObjectsBackup
ld bc, wMap2ObjectsBackup - wMap1ObjectsBackup - 2
.find_loop
ld a, [hl]
cp GROUP_N_A
jr z, .found_available_entry
and a ; cp $00 (terminator at wMapObjectsBackupsEnd)
jr z, .done
cp d ; wMap<N>ObjectsBackupMapGroup == wMapGroup?
jr nz, .next
inc hl
ld a, [hl]
cp e ; wMap<N>ObjectsBackupMapNumber == wMapNumber?
jr nz, .next2
inc hl
jr .found_matching_entry
.next
inc hl
.next2
inc hl
add hl, bc
jr .find_loop
.found_available_entry
ld [hl], d ; wMapGroup
inc hl
ld [hl], e ; wMapNumber
inc hl
.found_matching_entry
ld a, 1
ld [rSVBK], a
ld de, wMapObject1
ld a, [wCurMapObjectEventCount] ; how many object events are in the about-to-leave map?
and a
jr z, .done ; return if there's zero object events to be saved
sla a
sla a
sla a
sla a
ld c, a ; c = [wCurMapObjectEventCount] * MAPOBJECT_LENGTH
.copy_loop
ld a, 1
ld [rSVBK], a
ld a, c
and %00001111
ld a, $ff ; StructID (first byte) of each object event must be set to $ff
jr z, .got_value
ld a, [de]
.got_value
inc de
ld b, a
ld a, BANK(wMapObjectsBackups)
ld [rSVBK], a
ld a, b
ld [hli], a
dec c
jr nz, .copy_loop
.done
ld a, 1
ld [rSVBK], a
ret
LoadMapAttributes::
call CopyMapPartialAndAttributes
call SwitchToMapScriptsBank
@ -579,8 +660,6 @@ ReadObjectEvents::
ld [wCurMapObjectEventsPointer], a
ld a, d
ld [wCurMapObjectEventsPointer + 1], a
ld a, [wCurMapObjectEventCount]
call CopyMapObjectEvents
; get NUM_OBJECTS - [wCurMapObjectEventCount] - 1
@ -591,9 +670,13 @@ ReadObjectEvents::
jr z, .skip
jr c, .skip
; could have done "inc hl" instead
ld bc, 1
add hl, bc
push af
ld a, [wCurMapObjectEventCount]
ld bc, MAPOBJECT_LENGTH
call AddNTimes
inc hl
; Fill the remaining MAPOBJECT_SPRITE and MAPOBJECT_Y_COORD with 0 and -1, respectively.
pop af ; a = (NUM_OBJECTS - 1) - [wCurMapObjectEventCount], a > 0
ld bc, MAPOBJECT_LENGTH
.loop
ld [hl], 0
@ -610,9 +693,20 @@ ReadObjectEvents::
ret
CopyMapObjectEvents::
ld a, [wCurMapObjectEventCount]
and a
ret z
push hl
push de
call .FindMapObjectsBackup
pop de
pop hl
ret c
; hl = wMapObject1
; de = [wCurMapObjectEventsPointer]
ld a, [wCurMapObjectEventCount]
ld c, a
.loop
push bc
@ -635,6 +729,77 @@ CopyMapObjectEvents::
jr nz, .loop
ret
.FindMapObjectsBackup:
; this is called from the LoadMapAttributes map setup script.
; at this point wMapGroup and wMapNumber contain the about-to-enter map.
; if map is found in wMapObjectsBackups, copy object data from there and return carry.
; return nc otherwise.
ld hl, wMapGroup
ld a, [hli]
ld d, a ; d = wMapGroup
ld e, [hl] ; e = wMapNumber
ld a, BANK(wMapObjectsBackups)
ld [rSVBK], a
ld hl, wMap1ObjectsBackup
ld bc, wMap2ObjectsBackup - wMap1ObjectsBackup - 2
.find_loop
ld a, [hl]
cp GROUP_N_A
jr z, .no_match
and a ; cp $00 (terminator at wMapObjectsBackupsEnd)
jr z, .no_match
cp d ; wMap<N>ObjectsBackupMapGroup == wMapGroup?
jr nz, .next
inc hl
ld a, [hl]
cp e ; wMap<N>ObjectsBackupMapNumber == wMapNumber?
jr nz, .next2
inc hl
jr .found_matching_entry
.next
inc hl
.next2
inc hl
add hl, bc
jr .find_loop
.found_matching_entry
ld a, 1
ld [rSVBK], a
ld de, wMapObject1
ld a, [wCurMapObjectEventCount]
and a
jr z, .done ; return if there's zero object events to be read
sla a
sla a
sla a
sla a
ld c, a ; c = [wCurMapObjectEventCount] * OBJECT_LENGTH
.copy_loop
ld a, BANK(wMapObjectsBackups)
ld [rSVBK], a
ld a, [hli]
ld b, a
ld a, 1
ld [rSVBK], a
ld a, b
ld [de], a
inc de
dec c
jr nz, .copy_loop
.done
ld a, 1
ld [rSVBK], a
scf
ret
.no_match
ld a, 1
ld [rSVBK], a
xor a
ret
ClearObjectStructs::
ld hl, wObjectStructs
ld bc, OBJECT_LENGTH * NUM_OBJECT_STRUCTS

View File

@ -2693,6 +2693,7 @@ wMapObjectsBackups::
; wMap1ObjectsBackup* - wMap10ObjectsBackup*
; ds (2 + MAPOBJECT_LENGTH * (NUM_OBJECTS - 1)) * NUM_MAP_OBJECTS_BACKUPS
for n, 1, NUM_MAP_OBJECTS_BACKUPS
wMap{d:n}ObjectsBackup::
wMap{d:n}ObjectsBackupMapGroup:: db
wMap{d:n}ObjectsBackupMapNumber:: db
wMap{d:n}ObjectsBackupData::