aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAsh Ketchum <no-reply@sl0p.foo>2026-07-15 14:44:55 +0200
committerAsh Ketchum <no-reply@sl0p.foo>2026-07-15 14:44:55 +0200
commit2749e462a29ec323fee27dfc674f99d044f04706 (patch)
tree292fe3819210dec49819403e57d9cf80e67e16c5
parentSL0P.md: document EXPLORE arrows + A-to-warp (diff)
downloadpokeyellow-2749e462a29ec323fee27dfc674f99d044f04706.tar.gz
pokeyellow-2749e462a29ec323fee27dfc674f99d044f04706.tar.xz
pokeyellow-2749e462a29ec323fee27dfc674f99d044f04706.zip
EXPLORE: smooth hardware-scroll animation for in-map page moves
-rw-r--r--engine/slop_menu.asm267
1 files changed, 248 insertions, 19 deletions
diff --git a/engine/slop_menu.asm b/engine/slop_menu.asm
index 2e1adaaa..acad203c 100644
--- a/engine/slop_menu.asm
+++ b/engine/slop_menu.asm
@@ -225,6 +225,10 @@ WarpMapTable:
; ===========================================================================
DEF SLOP_PAGE_X EQU 10 ; coords moved per horizontal page (~one screen)
DEF SLOP_PAGE_Y EQU 8 ; coords moved per vertical page
+; smooth-scroll animation speed. SLOP_SCROLL_PX must divide 16 (one coord-step
+; is 16 px). Bigger = faster/steppier, smaller = slower/smoother.
+DEF SLOP_SCROLL_PX EQU 8
+DEF SLOP_SCROLL_FRAMES EQU 16 / SLOP_SCROLL_PX
SlopExplore:
; save origin (map, coords, block coords, view pointer) to restore on exit
@@ -247,13 +251,8 @@ SlopExplore:
push af
call LoadMapData ; reload current map + tileset (menu clobbered VRAM)
.renderView
- xor a
- ld [wYBlockCoord], a ; block-aligned camera centred on wYCoord/wXCoord
- ld [wXBlockCoord], a
- call SlopSetViewPtr
- call LoadCurrentMapView
- ld b, HIGH(vBGMap0)
- call CopyScreenTileBufferToVRAM
+ call SlopExploreRenderBG ; fresh render to vBGMap0, hardware scroll reset
+.renderArrows
call LoadFontTilePatterns ; arrow glyphs ($ed/$ee) into VRAM for the OBJ layer
; draw a direction-arrow sprite for each direction the camera can currently move:
; either there's more map that way, or the map has a connection that way.
@@ -349,7 +348,7 @@ SlopExplore:
jr z, .ckDown
ld a, [wYCoord]
sub SLOP_PAGE_Y
- jp nc, .setY
+ jp nc, .moveUp
ld hl, wNorthConnectedMap
ld de, wNorthConnectedMapYAlignment
ld a, 0 ; clamp target = top
@@ -363,8 +362,8 @@ SlopExplore:
ld a, [wYCoord]
add SLOP_PAGE_Y
cp b
- jp c, .setY
- jp z, .setY
+ jp c, .moveDown
+ jp z, .moveDown
ld hl, wSouthConnectedMap
ld de, wSouthConnectedMapYAlignment
ld a, b ; clamp target = max Y
@@ -374,7 +373,7 @@ SlopExplore:
jr z, .ckRight
ld a, [wXCoord]
sub SLOP_PAGE_X
- jp nc, .setX
+ jp nc, .moveLeft
ld hl, wWestConnectedMap
ld de, wWestConnectedMapYAlignment
ld a, 0
@@ -388,18 +387,30 @@ SlopExplore:
ld a, [wXCoord]
add SLOP_PAGE_X
cp b
- jp c, .setX
- jp z, .setX
+ jp c, .moveRight
+ jp z, .moveRight
ld hl, wEastConnectedMap
ld de, wEastConnectedMapYAlignment
ld a, b
jp .crossH
-.setY
- ld [wYCoord], a
- jp .renderView
-.setX
- ld [wXCoord], a
- jp .renderView
+; in-map page moves: smooth-scroll one screen, then just redraw the arrows
+; (the scroll already left the destination view on screen in rotated VRAM).
+.moveUp
+ ld c, SLOP_PAGE_Y
+ call SlopScrollUp
+ jp .renderArrows
+.moveDown
+ ld c, SLOP_PAGE_Y
+ call SlopScrollDown
+ jp .renderArrows
+.moveLeft
+ ld c, SLOP_PAGE_X
+ call SlopScrollLeft
+ jp .renderArrows
+.moveRight
+ ld c, SLOP_PAGE_X
+ call SlopScrollRight
+ jp .renderArrows
; vertical cross (up/down): hl -> connected-map byte, de -> its YAlignment,
; a = Y to clamp to when there is no connection.
.crossV
@@ -566,6 +577,224 @@ SlopSetViewPtr:
ld [wCurrentTileBlockMapViewPointer + 1], a
ret
+; render the current view freshly to vBGMap0 and reset the hardware scroll so
+; the camera is block-aligned at SCX/SCY = 0. Used on entry, map-cross and
+; clamp (i.e. everywhere except the animated in-map page moves).
+SlopExploreRenderBG:
+ xor a
+ ld [wYBlockCoord], a ; block-aligned camera centred on wYCoord/wXCoord
+ ld [wXBlockCoord], a
+ ldh [hAutoBGTransferEnabled], a ; use RedrawRowOrColumn path, not AutoBgMapTransfer
+ ld [wMapViewVRAMPointer], a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ ld a, HIGH(vBGMap0)
+ ld [wMapViewVRAMPointer + 1], a
+ call SlopSetViewPtr
+ call LoadCurrentMapView
+ ld b, HIGH(vBGMap0)
+ jp CopyScreenTileBufferToVRAM
+
+; ---------------------------------------------------------------------------
+; Smooth EXPLORE scrolling. Each routine pans the camera `c` coords in one
+; direction, 16 px per coord-step, reusing the walking engine's rotating-VRAM
+; machinery: advance wMapViewVRAMPointer, re-render wTileMap for the new
+; position, inject the freshly exposed 2-tile edge with a Schedule*Redraw
+; (applied by RedrawRowOrColumn in VBlank), and ramp hSCX/hSCY SLOP_SCROLL_PX
+; px per frame. After an even coord count it ends block-aligned exactly where
+; SlopExploreRenderBG would have placed the view, so wTileMap / the block
+; pointer / arrow logic / warp scan are all consistent afterwards.
+; ---------------------------------------------------------------------------
+SlopScrollRight:
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+.loop
+ push bc
+ ld a, [wXCoord]
+ inc a
+ ld [wXCoord], a
+ ld a, [wMapViewVRAMPointer] ; VRAM col +2 (wrap within the 32-tile row)
+ ld e, a
+ and $e0
+ ld d, a
+ ld a, e
+ add 2
+ and $1f
+ or d
+ ld [wMapViewVRAMPointer], a
+ ld hl, wXBlockCoord
+ inc [hl]
+ ld a, [hl]
+ cp 2
+ jr nz, .go
+ ld [hl], 0 ; crossed a block east -> advance block pointer
+ ld hl, wCurrentTileBlockMapViewPointer
+ inc [hl]
+ jr nz, .go
+ inc hl
+ inc [hl]
+.go
+ call LoadCurrentMapView
+ call ScheduleEastColumnRedraw
+ ld c, SLOP_SCROLL_FRAMES
+.frames
+ ldh a, [hSCX]
+ add SLOP_SCROLL_PX
+ ldh [hSCX], a
+ call DelayFrame
+ dec c
+ jr nz, .frames
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
+
+SlopScrollLeft:
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+.loop
+ push bc
+ ld a, [wXCoord]
+ dec a
+ ld [wXCoord], a
+ ld a, [wMapViewVRAMPointer] ; VRAM col -2
+ ld e, a
+ and $e0
+ ld d, a
+ ld a, e
+ sub 2
+ and $1f
+ or d
+ ld [wMapViewVRAMPointer], a
+ ld hl, wXBlockCoord
+ dec [hl]
+ ld a, [hl]
+ inc a
+ jr nz, .go ; was 0 -> now $ff: crossed a block west
+ ld [hl], 1
+ ld hl, wCurrentTileBlockMapViewPointer
+ ld a, [hl]
+ sub 1
+ ld [hl], a
+ jr nc, .go
+ inc hl
+ dec [hl]
+.go
+ call LoadCurrentMapView
+ call ScheduleWestColumnRedraw
+ ld c, SLOP_SCROLL_FRAMES
+.frames
+ ldh a, [hSCX]
+ sub SLOP_SCROLL_PX
+ ldh [hSCX], a
+ call DelayFrame
+ dec c
+ jr nz, .frames
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
+
+SlopScrollDown:
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+.loop
+ push bc
+ ld a, [wYCoord]
+ inc a
+ ld [wYCoord], a
+ ld a, [wMapViewVRAMPointer] ; VRAM row +1 (=+$40), wrap high byte into vBGMap0
+ add $40
+ ld [wMapViewVRAMPointer], a
+ jr nc, .vramDone
+ ld a, [wMapViewVRAMPointer + 1]
+ inc a
+ and $03
+ or $98
+ ld [wMapViewVRAMPointer + 1], a
+.vramDone
+ ld hl, wYBlockCoord
+ inc [hl]
+ ld a, [hl]
+ cp 2
+ jr nz, .go
+ ld [hl], 0 ; crossed a block south -> advance block pointer
+ ld a, [wCurMapWidth]
+ add MAP_BORDER * 2
+ ld b, a
+ ld hl, wCurrentTileBlockMapViewPointer
+ ld a, [hl]
+ add b
+ ld [hl], a
+ jr nc, .go
+ inc hl
+ inc [hl]
+.go
+ call LoadCurrentMapView
+ call ScheduleSouthRowRedraw
+ ld c, SLOP_SCROLL_FRAMES
+.frames
+ ldh a, [hSCY]
+ add SLOP_SCROLL_PX
+ ldh [hSCY], a
+ call DelayFrame
+ dec c
+ jr nz, .frames
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
+
+SlopScrollUp:
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+.loop
+ push bc
+ ld a, [wYCoord]
+ dec a
+ ld [wYCoord], a
+ ld a, [wMapViewVRAMPointer] ; VRAM row -1 (=-$40)
+ sub $40
+ ld [wMapViewVRAMPointer], a
+ jr nc, .vramDone
+ ld a, [wMapViewVRAMPointer + 1]
+ dec a
+ and $03
+ or $98
+ ld [wMapViewVRAMPointer + 1], a
+.vramDone
+ ld hl, wYBlockCoord
+ dec [hl]
+ ld a, [hl]
+ inc a
+ jr nz, .go ; was 0 -> now $ff: crossed a block north
+ ld [hl], 1
+ ld a, [wCurMapWidth]
+ add MAP_BORDER * 2
+ ld b, a
+ ld hl, wCurrentTileBlockMapViewPointer
+ ld a, [hl]
+ sub b
+ ld [hl], a
+ jr nc, .go
+ inc hl
+ dec [hl]
+.go
+ call LoadCurrentMapView
+ call ScheduleNorthRowRedraw
+ ld c, SLOP_SCROLL_FRAMES
+.frames
+ ldh a, [hSCY]
+ sub SLOP_SCROLL_PX
+ ldh [hSCY], a
+ call DelayFrame
+ dec c
+ jr nz, .frames
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
+
; (dy, dx) coord offsets scanned outward from the centre for a walkable tile
SlopWarpOffsets:
db 0, 0