aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAsh Ketchum <no-reply@sl0p.foo>2026-07-15 12:15:50 +0200
committerAsh Ketchum <no-reply@sl0p.foo>2026-07-15 12:15:50 +0200
commit259c6b8ec4524dcd4a75da065106107f2165b202 (patch)
treef7aaba15cd3a45c5620dab7f338522ff4480fa2b
parenttools: render_overworld.py - build seamless Kanto map from source (diff)
downloadpokeyellow-259c6b8ec4524dcd4a75da065106107f2165b202.tar.gz
pokeyellow-259c6b8ec4524dcd4a75da065106107f2165b202.tar.xz
pokeyellow-259c6b8ec4524dcd4a75da065106107f2165b202.zip
explore: pivot to noclip free-roam camera
Ground-truth from render_overworld.py showed Kanto is ONE seamless world joined along shared edges with per-connection offsets -- so a map-by-map browser is the wrong model. Replaced it with noclip free-roam that leans on the engine's own player-walk + connection-crossing machinery (which already handles seams/offsets correctly): - wSlopNoclip flag (reused the dead wUnusedObtainedBadges byte at D356, 0 r/w, not unioned, in the saved region -> safe). - CollisionCheckOnLand: 5-byte hook at the top -> when noclip is set, return no-collision. Freed the room in ROM0 by deleting the unreferenced Func_0db5 (dead farcall LoadToggleableObjectData) in LoadMapHeader. - EXPLORE menu entry now just toggles wSlopNoclip and closes the menu, dropping you into the overworld to glide through walls/NPCs/ledges and walk across map connections exactly as the world data defines them. Verified: Pallet -> (walk north through the fences) -> seam-cross into Route 1 at y=35 -> continue north; toggle off restores collision (player blocked).
-rw-r--r--engine/movie/oak_speech/init_player_data.asm2
-rw-r--r--engine/slop_menu.asm152
-rw-r--r--home/overworld.asm9
-rw-r--r--ram/wram.asm2
4 files changed, 17 insertions, 148 deletions
diff --git a/engine/movie/oak_speech/init_player_data.asm b/engine/movie/oak_speech/init_player_data.asm
index 90fb8f0e..589f4b5f 100644
--- a/engine/movie/oak_speech/init_player_data.asm
+++ b/engine/movie/oak_speech/init_player_data.asm
@@ -39,7 +39,7 @@ DEF START_MONEY EQU $3000
ld hl, wObtainedBadges
ld [hli], a
- ASSERT wObtainedBadges + 1 == wUnusedObtainedBadges
+ ASSERT wObtainedBadges + 1 == wSlopNoclip
ld [hl], a
ld hl, wPlayerCoins
diff --git a/engine/slop_menu.asm b/engine/slop_menu.asm
index fcac7d10..e3b07fe6 100644
--- a/engine/slop_menu.asm
+++ b/engine/slop_menu.asm
@@ -221,149 +221,17 @@ WarpMapTable:
; (via wCurMapConnections + the connection headers). B restores the original
; map and returns to the SL0P menu. No warping yet - read-only browse.
; ===========================================================================
+; ===========================================================================
+; EXPLORE: toggle noclip free-roam. With noclip on, CollisionCheckOnLand is
+; bypassed, so you glide through walls / NPCs / ledges and cross map connection
+; seams exactly as the world data defines them. Closes the menu so you drop
+; straight back into the overworld to roam. Pick it again to turn it off.
+; ===========================================================================
SlopExplore:
-; save origin map + coords on the stack
- ld a, [wYCoord]
- ld b, a
- ld a, [wXCoord]
- ld c, a
- push bc ; origin Y,X
- ld a, [wCurrentTileBlockMapViewPointer]
- ld b, a
- ld a, [wCurrentTileBlockMapViewPointer + 1]
- ld c, a
- push bc ; origin view pointer
- ld a, [wCurMap]
- push af ; origin map
-.render
-; LoadMapData loads the map header + block map into wOverworldMap, but it renders
-; using a STALE wCurrentTileBlockMapViewPointer -- the game only ever sets that
-; from warp / connection / walk data, never from wXCoord/wYCoord. So load the
-; map, then compute a centered view pointer ourselves and redraw the view.
- call LoadMapData
-; stride = wCurMapWidth + MAP_BORDER*2 ; bufRow = height/2 + 1 ; bufCol = width/2
-; wCurrentTileBlockMapViewPointer = wOverworldMap + bufRow*stride + bufCol
- ld a, [wCurMapWidth]
- add MAP_BORDER * 2
- ld c, a
- ld b, 0 ; bc = row stride (blocks)
- ld hl, 0
- ld a, [wCurMapHeight]
- srl a
- inc a ; bufRow (>= 1)
-.viewRowLoop
- add hl, bc
- dec a
- jr nz, .viewRowLoop
- ld a, [wCurMapWidth]
- srl a ; bufCol = width/2
- add l
- ld l, a
- jr nc, .viewNoCarry
- inc h
-.viewNoCarry
- ld bc, wOverworldMap
- add hl, bc
- ld a, l
- ld [wCurrentTileBlockMapViewPointer], a
- ld a, h
- ld [wCurrentTileBlockMapViewPointer + 1], a
- xor a
- ld [wYBlockCoord], a
- ld [wXBlockCoord], a
- call LoadCurrentMapView ; redraw wTileMap centered on the map
- ldh a, [rLCDC] ; hide ALL sprites (player + actors) via LCDC
- res B_LCDC_OBJS, a
- ldh [rLCDC], a
- ld a, $90
- ldh [hWY], a ; window off-screen -> the BG map is visible
-; overlay direction markers at the screen edges for the legit connections
- call LoadFontTilePatterns
- ld a, [wCurMapConnections]
- ld e, a
- bit NORTH_F, e
- jr z, .noN
- hlcoord 9, 0
- ld [hl], $8D
-.noN
- bit SOUTH_F, e
- jr z, .noS
- hlcoord 9, 15
- ld [hl], $92
-.noS
- bit WEST_F, e
- jr z, .noW
- hlcoord 0, 8
- ld [hl], $96
-.noW
- bit EAST_F, e
- jr z, .noE
- hlcoord 18, 8
- ld [hl], $84
-.noE
- ld b, HIGH(vBGMap0)
- call CopyScreenTileBufferToVRAM ; push map + markers to VRAM
-.input
- call DelayFrame
- call JoypadLowSensitivity
- ldh a, [hJoyPressed]
- ld d, a
- bit B_PAD_B, d
- jr nz, .exit
- bit B_PAD_UP, d
- jr z, .chkDown
- ld a, [wCurMapConnections]
- bit NORTH_F, a
- jp z, .input
- ld a, [wNorthConnectedMap]
- ld [wCurMap], a
- jp .render
-.chkDown
- bit B_PAD_DOWN, d
- jr z, .chkLeft
- ld a, [wCurMapConnections]
- bit SOUTH_F, a
- jp z, .input
- ld a, [wSouthConnectedMap]
- ld [wCurMap], a
- jp .render
-.chkLeft
- bit B_PAD_LEFT, d
- jr z, .chkRight
- ld a, [wCurMapConnections]
- bit WEST_F, a
- jp z, .input
- ld a, [wWestConnectedMap]
- ld [wCurMap], a
- jp .render
-.chkRight
- bit B_PAD_RIGHT, d
- jp z, .input
- ld a, [wCurMapConnections]
- bit EAST_F, a
- jp z, .input
- ld a, [wEastConnectedMap]
- ld [wCurMap], a
- jp .render
-.exit
- pop af
- ld [wCurMap], a ; restore origin map
- pop bc ; restore origin view pointer
- ld a, b
- ld [wCurrentTileBlockMapViewPointer], a
- ld a, c
- ld [wCurrentTileBlockMapViewPointer + 1], a
- pop bc ; restore origin Y,X
- ld a, b
- ld [wYCoord], a
- and $1
- ld [wYBlockCoord], a
- ld a, c
- ld [wXCoord], a
- and $1
- ld [wXBlockCoord], a
- call LoadMapData ; reload origin, rendered from the restored pointer
- and a ; carry clear -> back to SL0P menu
+ ld a, [wSlopNoclip]
+ xor $01
+ ld [wSlopNoclip], a
+ scf ; carry set -> close menu, back to overworld
ret
; ===========================================================================
diff --git a/home/overworld.asm b/home/overworld.asm
index a41a7ba8..95b94646 100644
--- a/home/overworld.asm
+++ b/home/overworld.asm
@@ -1218,6 +1218,9 @@ SignLoop::
; function to check if the player will jump down a ledge and check if the tile ahead is passable (when not surfing)
; sets the carry flag if there is a collision, and unsets it if there isn't a collision
CollisionCheckOnLand::
+ ld a, [wSlopNoclip] ; SL0P noclip: walk through everything (carry clear)
+ and a
+ ret nz
ld a, [wMovementFlags]
bit BIT_LEDGE_OR_FISHING, a
jr nz, .noCollision
@@ -1797,10 +1800,8 @@ LoadPlayerSpriteGraphicsCommon::
; function to load data from the map header
LoadMapHeader::
farcall MarkTownVisitedAndLoadToggleableObjects
- jr asm_0dbd
-
-Func_0db5:: ; unreferenced
- farcall LoadToggleableObjectData
+; SL0P: removed unreferenced Func_0db5 (farcall LoadToggleableObjectData) to make
+; room in ROM0 for the noclip hook in CollisionCheckOnLand.
asm_0dbd:
ld a, [wCurMapTileset]
ld [wUnusedCurMapTilesetCopy], a
diff --git a/ram/wram.asm b/ram/wram.asm
index 62ef1c44..e0488e62 100644
--- a/ram/wram.asm
+++ b/ram/wram.asm
@@ -1943,7 +1943,7 @@ wOptions:: db
wObtainedBadges:: flag_array NUM_BADGES
-wUnusedObtainedBadges:: db
+wSlopNoclip:: db ; SL0P: nonzero = noclip free-roam (walk through walls)
wLetterPrintingDelayFlags:: db