summaryrefslogtreecommitdiff
path: root/home
diff options
context:
space:
mode:
Diffstat (limited to 'home')
-rw-r--r--home/audio.asm372
-rw-r--r--home/init.asm272
-rw-r--r--home/overworld.asm4584
-rw-r--r--home/serial.asm622
4 files changed, 2925 insertions, 2925 deletions
diff --git a/home/audio.asm b/home/audio.asm
index e062c8da..abdfec54 100644
--- a/home/audio.asm
+++ b/home/audio.asm
@@ -1,186 +1,186 @@
-PlayDefaultMusic:: ; 2307 (0:2307)
- call WaitForSoundToFinish
- xor a
- ld c, a
- ld d, a
- ld [wcfca], a
- jr asm_2324
-
-Func_2312:: ; 2312 (0:2312)
- ld c, $a
- ld d, $0
- ld a, [wd72e]
- bit 5, a
- jr z, asm_2324
- xor a
- ld [wcfca], a
- ld c, $8
- ld d, c
-asm_2324:: ; 2324 (0:2324)
- ld a, [wWalkBikeSurfState]
- and a
- jr z, .asm_2343
- cp $2
- jr z, .asm_2332
- ld a, MUSIC_BIKE_RIDING
- jr .asm_2334
-.asm_2332
- ld a, MUSIC_SURFING
-.asm_2334
- ld b, a
- ld a, d
- and a
- ld a, BANK(Music_BikeRiding)
- jr nz, .asm_233e
- ld [wc0ef], a
-.asm_233e
- ld [wc0f0], a
- jr .asm_234c
-.asm_2343
- ld a, [wd35b]
- ld b, a
- call Func_2385
- jr c, .asm_2351
-.asm_234c
- ld a, [wcfca]
- cp b
- ret z
-.asm_2351
- ld a, c
- ld [wMusicHeaderPointer], a
- ld a, b
- ld [wcfca], a
- ld [wc0ee], a
- jp PlaySound
-
-Func_235f:: ; 235f (0:235f)
- ld a, [wc0ef]
- ld b, a
- cp BANK(Music2_UpdateMusic)
- jr nz, .checkForBank08
-.bank02
- ld hl, Music2_UpdateMusic
- jr .asm_2378
-.checkForBank08
- cp BANK(Music8_UpdateMusic)
- jr nz, .bank1F
-.bank08
- ld hl, Music8_UpdateMusic
- jr .asm_2378
-.bank1F
- ld hl, Music1f_UpdateMusic
-.asm_2378
- ld c, $6
-.asm_237a
- push bc
- push hl
- call Bankswitch
- pop hl
- pop bc
- dec c
- jr nz, .asm_237a
- ret
-
-Func_2385:: ; 2385 (0:2385)
- ld a, [wd35c]
- ld e, a
- ld a, [wc0ef]
- cp e
- jr nz, .asm_2394
- ld [wc0f0], a
- and a
- ret
-.asm_2394
- ld a, c
- and a
- ld a, e
- jr nz, .asm_239c
- ld [wc0ef], a
-.asm_239c
- ld [wc0f0], a
- scf
- ret
-
-PlayMusic:: ; 23a1 (0:23a1)
- ld b, a
- ld [wc0ee], a
- xor a
- ld [wMusicHeaderPointer], a
- ld a, c
- ld [wc0ef], a
- ld [wc0f0], a
- ld a, b
-
-StopAllMusic:: ; 2233 (0:2233)
- ld a,$FF
- ld [wc0ee],a
-; plays music specified by a. If value is $ff, music is stopped
-PlaySound:: ; 23b1 (0:23b1)
- push hl
- push de
- push bc
- ld b, a
- ld a, [wc0ee]
- and a
- jr z, .asm_23c8
- xor a
- ld [wc02a], a
- ld [wc02b], a
- ld [wc02c], a
- ld [wc02d], a
-.asm_23c8
- ld a, [wMusicHeaderPointer]
- and a
- jr z, .asm_23e3
- ld a, [wc0ee]
- and a
- jr z, .asm_2425
- xor a
- ld [wc0ee], a
- ld a, [wcfca]
- cp $ff
- jr nz, .asm_2414
- xor a
- ld [wMusicHeaderPointer], a
-.asm_23e3
- xor a
- ld [wc0ee], a
- ld a, [H_LOADEDROMBANK]
- ld [$ffb9], a
- ld a, [wc0ef]
- ld [H_LOADEDROMBANK], a
- ld [$2000], a
- cp BANK(Func_9876)
- jr nz, .checkForBank08
-.bank02
- ld a, b
- call Func_9876
- jr .asm_240b
-.checkForBank08
- cp BANK(Func_22035)
- jr nz, .bank1F
-.bank08
- ld a, b
- call Func_22035
- jr .asm_240b
-.bank1F
- ld a, b
- call Func_7d8ea
-.asm_240b
- ld a, [$ffb9]
- ld [H_LOADEDROMBANK], a
- ld [$2000], a
- jr .asm_2425
-.asm_2414
- ld a, b
- ld [wcfca], a
- ld a, [wMusicHeaderPointer]
- ld [wcfc8], a
- ld [wcfc9], a
- ld a, b
- ld [wMusicHeaderPointer], a
-.asm_2425
- pop bc
- pop de
- pop hl
- ret
+PlayDefaultMusic:: ; 2307 (0:2307)
+ call WaitForSoundToFinish
+ xor a
+ ld c, a
+ ld d, a
+ ld [wcfca], a
+ jr asm_2324
+
+Func_2312:: ; 2312 (0:2312)
+ ld c, $a
+ ld d, $0
+ ld a, [wd72e]
+ bit 5, a
+ jr z, asm_2324
+ xor a
+ ld [wcfca], a
+ ld c, $8
+ ld d, c
+asm_2324:: ; 2324 (0:2324)
+ ld a, [wWalkBikeSurfState]
+ and a
+ jr z, .asm_2343
+ cp $2
+ jr z, .asm_2332
+ ld a, MUSIC_BIKE_RIDING
+ jr .asm_2334
+.asm_2332
+ ld a, MUSIC_SURFING
+.asm_2334
+ ld b, a
+ ld a, d
+ and a
+ ld a, BANK(Music_BikeRiding)
+ jr nz, .asm_233e
+ ld [wc0ef], a
+.asm_233e
+ ld [wc0f0], a
+ jr .asm_234c
+.asm_2343
+ ld a, [wd35b]
+ ld b, a
+ call Func_2385
+ jr c, .asm_2351
+.asm_234c
+ ld a, [wcfca]
+ cp b
+ ret z
+.asm_2351
+ ld a, c
+ ld [wMusicHeaderPointer], a
+ ld a, b
+ ld [wcfca], a
+ ld [wc0ee], a
+ jp PlaySound
+
+Func_235f:: ; 235f (0:235f)
+ ld a, [wc0ef]
+ ld b, a
+ cp BANK(Music2_UpdateMusic)
+ jr nz, .checkForBank08
+.bank02
+ ld hl, Music2_UpdateMusic
+ jr .asm_2378
+.checkForBank08
+ cp BANK(Music8_UpdateMusic)
+ jr nz, .bank1F
+.bank08
+ ld hl, Music8_UpdateMusic
+ jr .asm_2378
+.bank1F
+ ld hl, Music1f_UpdateMusic
+.asm_2378
+ ld c, $6
+.asm_237a
+ push bc
+ push hl
+ call Bankswitch
+ pop hl
+ pop bc
+ dec c
+ jr nz, .asm_237a
+ ret
+
+Func_2385:: ; 2385 (0:2385)
+ ld a, [wd35c]
+ ld e, a
+ ld a, [wc0ef]
+ cp e
+ jr nz, .asm_2394
+ ld [wc0f0], a
+ and a
+ ret
+.asm_2394
+ ld a, c
+ and a
+ ld a, e
+ jr nz, .asm_239c
+ ld [wc0ef], a
+.asm_239c
+ ld [wc0f0], a
+ scf
+ ret
+
+PlayMusic:: ; 23a1 (0:23a1)
+ ld b, a
+ ld [wc0ee], a
+ xor a
+ ld [wMusicHeaderPointer], a
+ ld a, c
+ ld [wc0ef], a
+ ld [wc0f0], a
+ ld a, b
+
+StopAllMusic:: ; 2233 (0:2233)
+ ld a,$FF
+ ld [wc0ee],a
+; plays music specified by a. If value is $ff, music is stopped
+PlaySound:: ; 23b1 (0:23b1)
+ push hl
+ push de
+ push bc
+ ld b, a
+ ld a, [wc0ee]
+ and a
+ jr z, .asm_23c8
+ xor a
+ ld [wc02a], a
+ ld [wc02b], a
+ ld [wc02c], a
+ ld [wc02d], a
+.asm_23c8
+ ld a, [wMusicHeaderPointer]
+ and a
+ jr z, .asm_23e3
+ ld a, [wc0ee]
+ and a
+ jr z, .asm_2425
+ xor a
+ ld [wc0ee], a
+ ld a, [wcfca]
+ cp $ff
+ jr nz, .asm_2414
+ xor a
+ ld [wMusicHeaderPointer], a
+.asm_23e3
+ xor a
+ ld [wc0ee], a
+ ld a, [H_LOADEDROMBANK]
+ ld [$ffb9], a
+ ld a, [wc0ef]
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ cp BANK(Func_9876)
+ jr nz, .checkForBank08
+.bank02
+ ld a, b
+ call Func_9876
+ jr .asm_240b
+.checkForBank08
+ cp BANK(Func_22035)
+ jr nz, .bank1F
+.bank08
+ ld a, b
+ call Func_22035
+ jr .asm_240b
+.bank1F
+ ld a, b
+ call Func_7d8ea
+.asm_240b
+ ld a, [$ffb9]
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ jr .asm_2425
+.asm_2414
+ ld a, b
+ ld [wcfca], a
+ ld a, [wMusicHeaderPointer]
+ ld [wcfc8], a
+ ld [wcfc9], a
+ ld a, b
+ ld [wMusicHeaderPointer], a
+.asm_2425
+ pop bc
+ pop de
+ pop hl
+ ret
diff --git a/home/init.asm b/home/init.asm
index 701a4bb8..202bd110 100644
--- a/home/init.asm
+++ b/home/init.asm
@@ -1,136 +1,136 @@
-SoftReset::
- call StopAllSounds
- call GBPalWhiteOut
- ld c, $20
- call DelayFrames
- ; fallthrough
-
-Init::
-; Program init.
-
-rLCDC_DEFAULT EQU %11100011
-; * LCD enabled
-; * Window tile map at $9C00
-; * Window display enabled
-; * BG and window tile data at $8800
-; * BG tile map at $9800
-; * 8x8 OBJ size
-; * OBJ display enabled
-; * BG display enabled
-
- di
-
- xor a
- ld [rIF], a
- ld [rIE], a
- ld [$ff43], a
- ld [$ff42], a
- ld [rSB], a
- ld [rSC], a
- ld [$ff4b], a
- ld [$ff4a], a
- ld [$ff06], a
- ld [$ff07], a
- ld [$ff47], a
- ld [$ff48], a
- ld [$ff49], a
-
- ld a, rLCDC_ENABLE_MASK
- ld [rLCDC], a
- call DisableLCD
-
- ld sp, wStack
-
- ld hl, $c000 ; start of WRAM
- ld bc, $2000 ; size of WRAM
-.loop
- ld [hl], 0
- inc hl
- dec bc
- ld a, b
- or c
- jr nz, .loop
-
- call ClearVram
-
- ld hl, $ff80
- ld bc, $ffff - $ff80
- call FillMemory
-
- call ClearSprites
-
- ld a, Bank(WriteDMACodeToHRAM)
- ld [H_LOADEDROMBANK], a
- ld [MBC1RomBank], a
- call WriteDMACodeToHRAM
-
- xor a
- ld [hTilesetType], a
- ld [$ff41], a
- ld [hSCX], a
- ld [hSCY], a
- ld [$ff0f], a
- ld a, 1 << VBLANK + 1 << TIMER + 1 << SERIAL
- ld [rIE], a
-
- ld a, 144 ; move the window off-screen
- ld [hWY], a
- ld [rWY], a
- ld a, 7
- ld [rWX], a
-
- ld a, CONNECTION_NOT_ESTABLISHED
- ld [hSerialConnectionStatus], a
-
- ld h, vBGMap0 / $100
- call ClearBgMap
- ld h, vBGMap1 / $100
- call ClearBgMap
-
- ld a, rLCDC_DEFAULT
- ld [rLCDC], a
- ld a, 16
- ld [hSoftReset], a
- call StopAllSounds
-
- ei
-
- predef LoadSGB
-
- ld a, BANK(SFX_1f_67)
- ld [wc0ef], a
- ld [wc0f0], a
- ld a, $9c
- ld [$ffbd], a
- xor a
- ld [$ffbc], a
- dec a
- ld [wUpdateSpritesEnabled], a
-
- predef PlayIntro
-
- call DisableLCD
- call ClearVram
- call GBPalNormal
- call ClearSprites
- ld a, rLCDC_DEFAULT
- ld [rLCDC], a
-
- jp SetDefaultNamesBeforeTitlescreen
-
-ClearVram:
- ld hl, $8000
- ld bc, $2000
- xor a
- jp FillMemory
-
-
-StopAllSounds::
- ld a, BANK(Music2_UpdateMusic)
- ld [wc0ef], a
- ld [wc0f0], a
- xor a
- ld [wMusicHeaderPointer], a
- ld [wc0ee], a
- ld [wcfca], a
- jp StopAllMusic
+SoftReset::
+ call StopAllSounds
+ call GBPalWhiteOut
+ ld c, $20
+ call DelayFrames
+ ; fallthrough
+
+Init::
+; Program init.
+
+rLCDC_DEFAULT EQU %11100011
+; * LCD enabled
+; * Window tile map at $9C00
+; * Window display enabled
+; * BG and window tile data at $8800
+; * BG tile map at $9800
+; * 8x8 OBJ size
+; * OBJ display enabled
+; * BG display enabled
+
+ di
+
+ xor a
+ ld [rIF], a
+ ld [rIE], a
+ ld [$ff43], a
+ ld [$ff42], a
+ ld [rSB], a
+ ld [rSC], a
+ ld [$ff4b], a
+ ld [$ff4a], a
+ ld [$ff06], a
+ ld [$ff07], a
+ ld [$ff47], a
+ ld [$ff48], a
+ ld [$ff49], a
+
+ ld a, rLCDC_ENABLE_MASK
+ ld [rLCDC], a
+ call DisableLCD
+
+ ld sp, wStack
+
+ ld hl, $c000 ; start of WRAM
+ ld bc, $2000 ; size of WRAM
+.loop
+ ld [hl], 0
+ inc hl
+ dec bc
+ ld a, b
+ or c
+ jr nz, .loop
+
+ call ClearVram
+
+ ld hl, $ff80
+ ld bc, $ffff - $ff80
+ call FillMemory
+
+ call ClearSprites
+
+ ld a, Bank(WriteDMACodeToHRAM)
+ ld [H_LOADEDROMBANK], a
+ ld [MBC1RomBank], a
+ call WriteDMACodeToHRAM
+
+ xor a
+ ld [hTilesetType], a
+ ld [$ff41], a
+ ld [hSCX], a
+ ld [hSCY], a
+ ld [$ff0f], a
+ ld a, 1 << VBLANK + 1 << TIMER + 1 << SERIAL
+ ld [rIE], a
+
+ ld a, 144 ; move the window off-screen
+ ld [hWY], a
+ ld [rWY], a
+ ld a, 7
+ ld [rWX], a
+
+ ld a, CONNECTION_NOT_ESTABLISHED
+ ld [hSerialConnectionStatus], a
+
+ ld h, vBGMap0 / $100
+ call ClearBgMap
+ ld h, vBGMap1 / $100
+ call ClearBgMap
+
+ ld a, rLCDC_DEFAULT
+ ld [rLCDC], a
+ ld a, 16
+ ld [hSoftReset], a
+ call StopAllSounds
+
+ ei
+
+ predef LoadSGB
+
+ ld a, BANK(SFX_1f_67)
+ ld [wc0ef], a
+ ld [wc0f0], a
+ ld a, $9c
+ ld [$ffbd], a
+ xor a
+ ld [$ffbc], a
+ dec a
+ ld [wUpdateSpritesEnabled], a
+
+ predef PlayIntro
+
+ call DisableLCD
+ call ClearVram
+ call GBPalNormal
+ call ClearSprites
+ ld a, rLCDC_DEFAULT
+ ld [rLCDC], a
+
+ jp SetDefaultNamesBeforeTitlescreen
+
+ClearVram:
+ ld hl, $8000
+ ld bc, $2000
+ xor a
+ jp FillMemory
+
+
+StopAllSounds::
+ ld a, BANK(Music2_UpdateMusic)
+ ld [wc0ef], a
+ ld [wc0f0], a
+ xor a
+ ld [wMusicHeaderPointer], a
+ ld [wc0ee], a
+ ld [wcfca], a
+ jp StopAllMusic
diff --git a/home/overworld.asm b/home/overworld.asm
index 508e243a..b3008903 100644
--- a/home/overworld.asm
+++ b/home/overworld.asm
@@ -1,2293 +1,2293 @@
-EnterMap:: ; 01d7 (0:01d7)
-; Load a new map.
- ld a, $ff
- ld [wJoyIgnore], a
- call LoadMapData
- callba ClearVariablesAfterLoadingMapData
- ld hl, wd72c
- bit 0, [hl] ; has the player already made 3 steps since the last battle?
- jr z, .skipGivingThreeStepsOfNoRandomBattles
- ld a, 3 ; minimum number of steps between battles
- ld [wNumberOfNoRandomBattleStepsLeft], a
-.skipGivingThreeStepsOfNoRandomBattles
- ld hl, wd72e
- bit 5, [hl] ; did a battle happen immediately before this?
- res 5, [hl] ; unset the "battle just happened" flag
- call z, ResetUsingStrengthOutOfBattleBit
- call nz, MapEntryAfterBattle
- ld hl, wd732
- ld a, [hl]
- and 1 << 4 | 1 << 3 ; fly warp or dungeon warp
- jr z, .didNotEnterUsingFlyWarpOrDungeonWarp
- callba EnterMapAnim
- call UpdateSprites
- ld hl, wd732
- res 3, [hl]
- ld hl, wd72e
- res 4, [hl]
- call Func_342a
-.didNotEnterUsingFlyWarpOrDungeonWarp
- callba CheckForceBikeOrSurf ; handle currents in SF islands and forced bike riding in cycling road
- ld hl, wd732
- bit 4, [hl]
- res 4, [hl]
- ld hl, wd72d
- res 5, [hl]
- call UpdateSprites
- ld hl, wd126
- set 5, [hl]
- set 6, [hl]
- xor a
- ld [wJoyIgnore], a
-
-OverworldLoop:: ; 0242 (0:0242)
- call DelayFrame
-OverworldLoopLessDelay:: ; 0245 (0:0245)
- call DelayFrame
- call Func_342a
- call LoadGBPal
- ld a,[wWalkCounter]
- and a
- jp nz,.moveAhead ; if the player sprite has not yet completed the walking animation
- call JoypadOverworld ; get joypad state (which is possibly simulated)
- callba SafariZoneCheck
- ld a,[wSafariZoneGameOver]
- and a
- jp nz,WarpFound2
- ld hl,wd72d
- bit 3,[hl]
- res 3,[hl]
- jp nz,WarpFound2
- ld a,[wd732]
- and a,1 << 4 | 1 << 3 ; fly warp or dungeon warp
- jp nz,HandleFlyWarpOrDungeonWarp
- ld a,[W_CUROPPONENT]
- and a
- jp nz,.newBattle
- ld a,[wd730]
- bit 7,a ; are we simulating button presses?
- jr z,.notSimulating
- ld a,[hJoyHeld]
- jr .checkIfStartIsPressed
-.notSimulating
- ld a,[hJoyPressed]
-.checkIfStartIsPressed
- bit 3,a ; start button
- jr z,.startButtonNotPressed
-; if START is pressed
- xor a
- ld [hSpriteIndexOrTextID],a ; start menu text ID
- jp .displayDialogue
-.startButtonNotPressed
- bit 0,a ; A button
- jp z,.checkIfDownButtonIsPressed
-; if A is pressed
- ld a,[wd730]
- bit 2,a
- jp nz,.noDirectionButtonsPressed
- call IsPlayerCharacterBeingControlledByGame
- jr nz,.checkForOpponent
- call CheckForHiddenObjectOrBookshelfOrCardKeyDoor
- ld a,[$ffeb]
- and a
- jp z,OverworldLoop ; jump if a hidden object or bookshelf was found, but not if a card key door was found
- xor a
- ld [wd436],a ; new yellow address
- call IsSpriteOrSignInFrontOfPlayer
- call Func_0ffe
- ld a,[hSpriteIndexOrTextID]
- and a
- jp z,OverworldLoop
-.displayDialogue
- predef GetTileAndCoordsInFrontOfPlayer
- call UpdateSprites
- ld a,[wFlags_0xcd60]
- bit 2,a
- jr nz,.checkForOpponent
- bit 0,a
- jr nz,.checkForOpponent
- aCoord 8, 9
- ld [wcf0e],a
- call DisplayTextID ; display either the start menu or the NPC/sign text
- ld a,[wcc47]
- and a
- jr z,.checkForOpponent
- xor a
- ld [wcc47],a
- jp EnterMap
-; predef LoadSAV
-; ld a,[W_CURMAP]
-; ld [wDestinationMap],a
-; call SpecialWarpIn
-; ld a,[W_CURMAP]
-; call SwitchToMapRomBank ; switch to the ROM bank of the current map
-; ld hl,W_CURMAPTILESET
-; set 7,[hl]
-.checkForOpponent
- ld a,[W_CUROPPONENT]
- and a
- jp nz,.newBattle
- jp OverworldLoop
-.noDirectionButtonsPressed
- call UpdateSprites ; 231c
- ld hl,wFlags_0xcd60
- res 2,[hl]
- xor a
- ld [wd435], a
- ld a, $1
- ld a,$01
- ld [wcc4b],a
- ld a,[wd528] ; the direction that was pressed last time
- and a
- jr z, .overworldloop
-; if a direction was pressed last time
- ld [wd529],a ; save the last direction
- xor a
- ld [wd528],a ; zero the direction
-.overworldloop
- jp OverworldLoop
-.checkIfDownButtonIsPressed
- ld a,[hJoyHeld] ; current joypad state
- bit 7,a ; down button
- jr z,.checkIfUpButtonIsPressed
- ld a,$01
- ld [wSpriteStateData1 + 3],a
- ld a,$04
- jr .handleDirectionButtonPress
-.checkIfUpButtonIsPressed
- bit 6,a ; up button
- jr z,.checkIfLeftButtonIsPressed
- ld a,$ff
- ld [wSpriteStateData1 + 3],a
- ld a,$08
- jr .handleDirectionButtonPress
-.checkIfLeftButtonIsPressed
- bit 5,a ; left button
- jr z,.checkIfRightButtonIsPressed
- ld a,$ff
- ld [wSpriteStateData1 + 5],a
- ld a,$02
- jr .handleDirectionButtonPress
-.checkIfRightButtonIsPressed
- bit 4,a ; right button
- jr z,.noDirectionButtonsPressed
- ld a,$01
- ld [wSpriteStateData1 + 5],a
-.handleDirectionButtonPress
- ld [wd52a],a ; new direction
- ld a,[wd730]
- bit 7,a ; are we simulating button presses?
- jr nz,.noDirectionChange ; ignore direction changes if we are
- ld a,[wcc4b]
- and a
- jr z,.noDirectionChange
- ld a,[wd52a] ; new direction
- ld b,a
- ld a,[wd529] ; old direction
- cp b
- jr z,.noDirectionChange
- ld a,$8
- ld [wd434],a
-; unlike in red/blue, yellow does not have the 180 degrees odd code
- ld hl,wFlags_0xcd60
- set 2,[hl]
- xor a
- ld [wcc4b],a
- ld a,[wd52a]
- ld [wd528],a
- call NewBattle
- jp c,.battleOccurred
- jp OverworldLoop
-.noDirectionChange
- ld a,[wd52a] ; current direction
- ld [wd528],a ; save direction
- call UpdateSprites
- ld a,[wWalkBikeSurfState]
- cp a,$02 ; surfing
- jr z,.surfing
-; not surfing
- call CollisionCheckOnLand
- jr nc,.noCollision
-; collision occurred
- push hl
- ld hl,wd736
- bit 2,[hl] ; standing on warp flag
- pop hl
- jp z,OverworldLoop
-; collision occurred while standing on a warp
- push hl
- call ExtraWarpCheck ; sets carry if there is a potential to warp
- pop hl
- jp c,CheckWarpsCollision
- jp OverworldLoop
-.surfing
- call CollisionCheckOnWater
- jp c,OverworldLoop
-.noCollision
- ld a,$08
- ld [wWalkCounter],a
- callab Func_fcc08
- jr .moveAhead2
-.moveAhead
- call IsSpinning
- call UpdateSprites ; move sprites
-.moveAhead2
- ld hl,wFlags_0xcd60
- res 2,[hl]
- xor a
- ld [wd435],a
- call DoBikeSpeedup
- call AdvancePlayerSprite
- ld a,[wWalkCounter]
- and a
- jp nz,CheckMapConnections ; it seems like this check will never succeed (the other place where CheckMapConnections is run works)
-; walking animation finished
- call StepCountCheck
- ld a,[wd790]
- bit 7,a ; in the safari zone?
- jr z,.notSafariZone
- callba SafariZoneCheckSteps
- ld a,[wSafariZoneGameOver]
- and a
- jp nz,WarpFound2
-.notSafariZone
- ld a,[W_ISINBATTLE]
- and a
- jp nz,CheckWarpsNoCollision
- predef ApplyOutOfBattlePoisonDamage ; also increment daycare mon exp
- ld a,[wd12d]
- and a
- jp nz,HandleBlackOut ; if all pokemon fainted
-.newBattle
- call NewBattle
- ld hl,wd736
- res 2,[hl] ; standing on warp flag
- jp nc,CheckWarpsNoCollision ; check for warps if there was no battle
-.battleOccurred
- ld hl,wd72d
- res 6,[hl]
- ld hl,W_FLAGS_D733
- res 3,[hl]
- ld hl,wd126
- set 5,[hl]
- set 6,[hl]
- xor a
- ld [hJoyHeld],a
- ld a,[W_CURMAP]
- cp a,CINNABAR_GYM
- jr nz,.notCinnabarGym
- ld hl,wd79b
- set 7,[hl]
-.notCinnabarGym
- ld hl,wd72e
- set 5,[hl]
- ld a,[W_CURMAP]
- cp a,OAKS_LAB
- jp z,.noFaintCheck ; no blacking out if the player lost to the rival in Oak's lab
- callab AnyPartyAlive
- ld a,d
- and a
- jr z,.allPokemonFainted
-.noFaintCheck
- ld c,$0a
- call DelayFrames
- jp EnterMap
-;.allPokemonFainted
-; ld a,$ff
-; ld [W_ISINBATTLE],a
-; call RunMapScript
-; jp HandleBlackOut
-
-StepCountCheck:: ; 0457 (0:0457)
- ld a,[wd730]
- bit 7,a
- jr nz,.doneStepCounting ; if button presses are being simulated, don't count steps
-; step counting
- ld hl,wStepCounter
- dec [hl]
- ld a,[wd72c]
- bit 0,a
- jr z,.doneStepCounting
- ld hl,wNumberOfNoRandomBattleStepsLeft
- dec [hl]
- jr nz,.doneStepCounting
- ld hl,wd72c
- res 0,[hl] ; indicate that the player has stepped thrice since the last battle
-.doneStepCounting
- ret
-
-; function to determine if there will be a battle and execute it (either a trainer battle or wild battle)
-; sets carry if a battle occurred and unsets carry if not
-NewBattle:: ; 0480 (0:0480)
- ld a,[wd72d]
- bit 4,a
- jr nz,.noBattle
- call IsPlayerCharacterBeingControlledByGame
- jr nz,.noBattle ; no battle if the player character is under the game's control
- ld a,[wd72e]
- bit 4,a
- jr nz,.noBattle
- ld b, BANK(InitBattle)
- ld hl, InitBattle ; 3d:5ff2
- jp Bankswitch
-.noBattle
- and a
- ret
-
-DoBikeSpeedup:: ; 049d (0:049d)
- ld a,[wWalkBikeSurfState]
- dec a ; riding a bike?
- ret nz
- ld a,[wd736]
- bit 6,a
- ret nz
- ld a,[wNPCMovementScriptPointerTableNum]
- and a
- ret nz
- ld a,[W_CURMAP]
- cp ROUTE_17 ; cycling road
- jr nz,.goFaster
- ld a,[hJoyHeld]
- and a,D_UP | D_LEFT | D_RIGHT
- ret nz
-.goFaster
- call AdvancePlayerSprite
- ret
-
-; check if the player has stepped onto a warp after having not collided
-CheckWarpsNoCollision:: ; 04bd (0:04bd)
- ld a,[wNumberOfWarps]
- and a
- jp z,CheckMapConnections
- ld b,0
- ld a,[wNumberOfWarps]
- ld c,a
- ld a,[W_YCOORD]
- ld d,a
- ld a,[W_XCOORD]
- ld e,a
- ld hl,wWarpEntries
-CheckWarpsNoCollisionLoop:: ; 04d5 (0:04d5)
- ld a,[hli] ; check if the warp's Y position matches
- cp d
- jr nz,CheckWarpsNoCollisionRetry1
- ld a,[hli] ; check if the warp's X position matches
- cp e
- jr nz,CheckWarpsNoCollisionRetry2
-; if a match was found
- push hl
- push bc
- ld hl,wd736
- set 2,[hl] ; standing on warp flag
- callba IsPlayerStandingOnDoorTileOrWarpTile
- pop bc
- pop hl
- jr c,WarpFound1 ; jump if standing on door or warp
- push hl
- push bc
- call ExtraWarpCheck
- pop bc
- pop hl
- jr nc,CheckWarpsNoCollisionRetry2
-; if the extra check passed
- ld a,[W_FLAGS_D733]
- bit 2,a
- jr nz,WarpFound1
- push de
- push bc
- call Joypad
- pop bc
- pop de
- ld a,[hJoyHeld]
- and a,D_DOWN | D_UP | D_LEFT | D_RIGHT
- jr z,CheckWarpsNoCollisionRetry2 ; if directional buttons aren't being pressed, do not pass through the warp
- jr WarpFound1
-
-CheckWarpsNoCollisionRetry1:: ; 050f (0:050f)
- inc hl
-CheckWarpsNoCollisionRetry2:: ; 0510 (0:0510)
- inc hl
- inc hl
-ContinueCheckWarpsNoCollisionLoop:: ; 0512 (0:0512)
- inc b ; increment warp number
- dec c ; decrement number of warps
- jp nz,CheckWarpsNoCollisionLoop
- jp CheckMapConnections
-
-; check if the player has stepped onto a warp after having collided
-CheckWarpsCollision:: ; 051a (0:051a)
- ld a,[wNumberOfWarps]
- ld c,a
- ld hl,wWarpEntries
-.loop
- ld a,[hli] ; Y coordinate of warp
- ld b,a
- ld a,[W_YCOORD]
- cp b
- jr nz,.retry1
- ld a,[hli] ; X coordinate of warp
- ld b,a
- ld a,[W_XCOORD]
- cp b
- jr nz,.retry2
- ld a,[hli]
- ld [wDestinationWarpID],a
- ld a,[hl]
- ld [$ff8b],a ; save target map
- jr WarpFound2
-.retry1
- inc hl
-.retry2
- inc hl
- inc hl
- dec c
- jr nz,.loop
- jp OverworldLoop
-
-WarpFound1:: ; 0543 (0:0543)
- ld a,[hli]
- ld [wDestinationWarpID],a
- ld a,[hli]
- ld [$ff8b],a ; save target map
-
-WarpFound2:: ; 054a (0:054a)
- ld a,[wNumberOfWarps]
- sub c
- ld [wd73b],a ; save ID of used warp
- ld a,[W_CURMAP]
- ld [wd73c],a
- call CheckIfInOutsideMap
- jr nz,.indoorMaps
-; this is for handling "outside" maps that can't have the 0xFF destination map
- ld a,[W_CURMAP]
- ld [wLastMap],a
- ld a,[W_CURMAPWIDTH]
- ld [wd366],a
- ld a,[$ff8b] ; destination map number
- ld [W_CURMAP],a ; change current map to destination map
- cp a,ROCK_TUNNEL_1
- jr nz,.notRockTunnel
- ld a,$06
- ld [wMapPalOffset],a
- call GBFadeOutToBlack
-.notRockTunnel
- callab Func_fc5fa ; 3f:45fa
- call PlayMapChangeSound
- jr .done
-; for maps that can have the 0xFF destination map, which means to return to the outside map; not all these maps are necessarily indoors, though
-.indoorMaps
- ld a,[$ff8b] ; destination map
- cp a,$ff
- jr z,.goBackOutside
-; if not going back to the previous map
- ld [W_CURMAP],a ; current map number
- callba IsPlayerStandingOnWarpPadOrHole
- ld a,[wcd5b]
- dec a ; is the player on a warp pad?
- jr nz,.notWarpPad
-; if the player is on a warp pad
- call LeaveMapAnim
- ld hl,wd732
- set 3,[hl]
- jr .skipMapChangeSound
-.notWarpPad
- call PlayMapChangeSound
-.skipMapChangeSound
- ld hl,wd736
- res 0,[hl]
- res 1,[hl]
- callab Func_fc65b ; 3f:465b
- jr .done
-.goBackOutside
- callab Func_fc69a ; 3f:469a
- ld a,[wLastMap]
- ld [W_CURMAP],a
- call PlayMapChangeSound
- xor a
- ld [wMapPalOffset],a
-.done
- ld hl,wd736
- set 0,[hl] ; have the player's sprite step out from the door (if there is one)
- call IgnoreInputForHalfSecond
- jp EnterMap
-
-; if no matching warp was found
-CheckMapConnections:: ; 05db (0:05db)
-.checkWestMap
- ld a,[W_XCOORD]
- cp a,$ff
- jr nz,.checkEastMap
- ld a,[W_MAPCONN3PTR]
- ld [W_CURMAP],a
- ld a,[wd38f] ; new X coordinate upon entering west map
- ld [W_XCOORD],a
- ld a,[W_YCOORD]
- ld c,a
- ld a,[wd38e] ; Y adjustment upon entering west map
- add c
- ld c,a
- ld [W_YCOORD],a
- ld a,[wd390] ; pointer to upper left corner of map without adjustment for Y position
- ld l,a
- ld a,[wd391]
- ld h,a
- srl c
- jr z,.savePointer1
-.pointerAdjustmentLoop1
- ld a,[wd38d] ; width of connected map
- add a,$06
- ld e,a
- ld d,$00
- ld b,$00
- add hl,de
- dec c
- jr nz,.pointerAdjustmentLoop1
-.savePointer1
- ld a,l
- ld [wCurrentTileBlockMapViewPointer],a ; pointer to upper left corner of current tile block map section
- ld a,h
- ld [wCurrentTileBlockMapViewPointer + 1],a
- jp .loadNewMap
-.checkEastMap
- ld b,a
- ld a,[wd525] ; map width
- cp b
- jr nz,.checkNorthMap
- ld a,[W_MAPCONN4PTR]
- ld [W_CURMAP],a
- ld a,[wd39a] ; new X coordinate upon entering east map
- ld [W_XCOORD],a
- ld a,[W_YCOORD]
- ld c,a
- ld a,[wd399] ; Y adjustment upon entering east map
- add c
- ld c,a
- ld [W_YCOORD],a
- ld a,[wd39b] ; pointer to upper left corner of map without adjustment for Y position
- ld l,a
- ld a,[wd39c]
- ld h,a
- srl c
- jr z,.savePointer2
-.pointerAdjustmentLoop2
- ld a,[wd398]
- add a,$06
- ld e,a
- ld d,$00
- ld b,$00
- add hl,de
- dec c
- jr nz,.pointerAdjustmentLoop2
-.savePointer2
- ld a,l
- ld [wCurrentTileBlockMapViewPointer],a ; pointer to upper left corner of current tile block map section
- ld a,h
- ld [wCurrentTileBlockMapViewPointer + 1],a
- jp .loadNewMap
-.checkNorthMap
- ld a,[W_YCOORD]
- cp a,$ff
- jr nz,.checkSouthMap
- ld a,[W_MAPCONN1PTR]
- ld [W_CURMAP],a
- ld a,[wd378] ; new Y coordinate upon entering north map
- ld [W_YCOORD],a
- ld a,[W_XCOORD]
- ld c,a
- ld a,[wd379] ; X adjustment upon entering north map
- add c
- ld c,a
- ld [W_XCOORD],a
- ld a,[wd37a] ; pointer to upper left corner of map without adjustment for X position
- ld l,a
- ld a,[wd37b]
- ld h,a
- ld b,$00
- srl c
- add hl,bc
- ld a,l
- ld [wCurrentTileBlockMapViewPointer],a ; pointer to upper left corner of current tile block map section
- ld a,h
- ld [wCurrentTileBlockMapViewPointer + 1],a
- jp .loadNewMap
-.checkSouthMap
- ld b,a
- ld a,[wd524]
- cp b
- jr nz,.didNotEnterConnectedMap
- ld a,[W_MAPCONN2PTR]
- ld [W_CURMAP],a
- ld a,[wd383] ; new Y coordinate upon entering south map
- ld [W_YCOORD],a
- ld a,[W_XCOORD]
- ld c,a
- ld a,[wd384] ; X adjustment upon entering south map
- add c
- ld c,a
- ld [W_XCOORD],a
- ld a,[wd385] ; pointer to upper left corner of map without adjustment for X position
- ld l,a
- ld a,[wd386]
- ld h,a
- ld b,$00
- srl c
- add hl,bc
- ld a,l
- ld [wCurrentTileBlockMapViewPointer],a ; pointer to upper left corner of current tile block map section
- ld a,h
- ld [wCurrentTileBlockMapViewPointer + 1],a
-.loadNewMap ; 06ce (0:06ce)
-; load the connected map that was entered
- ld hl,[wd430]
- set 4,[hl]
- ld a,$2
- ld [wd431],a
- call LoadMapHeader ; 0dab (0:0dab)
- call Func_2312 ; music
- ld b,$09
- call GoPAL_SET
-; Since the sprite set shouldn't change, this will just update VRAM slots at
-; $C2XE without loading any tile patterns.
- call InitMapSprites
- call LoadTileBlockMap
- jp OverworldLoopLessDelay
-.didNotEnterConnectedMap
- jp OverworldLoop
-
-; function to play a sound when changing maps
-PlayMapChangeSound:: ; 06ef (0:06ef)
- ld a,[W_CURMAPTILESET]
- cp FACILITY
- jr z,.didNotGoThroughDoor
- cp CEMETERY
- jr z,.didNotGoThroughDoor
- cp UNDERGROUND
- jr nz,.didNotGoThroughDoor
- aCoord 8, 8 ; upper left tile of the 4x4 square the player's sprite is standing on
- cp a,$0b ; door tile in tileset 0
- jr nz,.didNotGoThroughDoor
- ld a,(SFX_02_57 - SFX_Headers_02) / 3
- jr .playSound
-.didNotGoThroughDoor
- ld a,(SFX_02_5c - SFX_Headers_02) / 3
-.playSound
- call PlaySound
- ld a,[wMapPalOffset]
- and a
- ret nz
- jp GBFadeOutToBlack
-
-CheckIfInOutsideMap:: ; 0712 (0:0712)
-; If the player is in an outside map (a town or route), set the z flag
- ld a, [W_CURMAPTILESET]
- and a ; most towns/routes have tileset 0 (OVERWORLD)
- ret z
- cp PLATEAU ; Route 23 / Indigo Plateau
- ret
-
-; this function is an extra check that sometimes has to pass in order to warp, beyond just standing on a warp
-; the "sometimes" qualification is necessary because of CheckWarpsNoCollision's behavior
-; depending on the map, either "function 1" or "function 2" is used for the check
-; "function 1" passes when the player is at the edge of the map and is facing towards the outside of the map
-; "function 2" passes when the the tile in front of the player is among a certain set
-; sets carry if the check passes, otherwise clears carry
-ExtraWarpCheck:: ; 071a (0:071a)
- ld a, [W_CURMAP]
- cp SS_ANNE_3
- jr z, .useFunction1
- cp ROCKET_HIDEOUT_1
- jr z, .useFunction2
- cp ROCKET_HIDEOUT_2
- jr z, .useFunction2
- cp ROCKET_HIDEOUT_4
- jr z, .useFunction2
- cp ROCK_TUNNEL_1
- jr z, .useFunction2
- ld a, [W_CURMAPTILESET]
- and a ; outside tileset (OVERWORLD)
- jr z, .useFunction2
- cp SHIP ; S.S. Anne tileset
- jr z, .useFunction2
- cp SHIP_PORT ; Vermilion Port tileset
- jr z, .useFunction2
- cp PLATEAU ; Indigo Plateau tileset
- jr z, .useFunction2
-.useFunction1
- ld hl, IsPlayerFacingEdgeOfMap
- jr .doBankswitch
-.useFunction2
- ld hl, IsWarpTileInFrontOfPlayer
-.doBankswitch
- ld b, BANK(IsWarpTileInFrontOfPlayer)
- jp Bankswitch
-
-MapEntryAfterBattle:: ; 0750 (0:0750)
- callba IsPlayerStandingOnWarp ; for enabling warp testing after collisions
- ld a,[wMapPalOffset]
- and a
- jp z,GBFadeInFromWhite
- jp LoadGBPal
-
-HandleBlackOut:: ; 0762 (0:0762)
-; For when all the player's pokemon faint.
-; Does not print the "blacked out" message.
-
- call GBFadeOutToBlack
- ld a, $08
- call StopMusic
- ld hl, wd72e
- res 5, [hl]
- switchbank SpecialWarpIn ; also Bank(SpecialEnterMap)
- callab ResetStatusAndHalveMoneyOnBlackout ; 3c:4274
- call SpecialWarpIn
- call Func_2312
- jp SpecialEnterMap
-
-StopMusic:: ; 0788 (0:0788)
- ld [wMusicHeaderPointer], a
- call StopAllMusic
-.wait
- ld a, [wMusicHeaderPointer]
- and a
- jr nz, .wait
- jp StopAllSounds
-
-HandleFlyWarpOrDungeonWarp:: ; 0794 (0:0794)
- call UpdateSprites
- call Delay3
- xor a
- ld [wBattleResult], a
- ld [wWalkBikeSurfState], a
- ld [W_ISINBATTLE], a
- ld [wMapPalOffset], a
- ld hl, wd732
- set 2, [hl] ; fly warp or dungeon warp
- res 5, [hl] ; forced to ride bike
- call LeaveMapAnim
- call LoadPlayerSpriteGraphics
- callsb SpecialWarpIn
- jp SpecialEnterMap
-
-LeaveMapAnim:: ; 07bc (0:07bc)
- ld b, BANK(_LeaveMapAnim)
- ld hl, _LeaveMapAnim
- jp Bankswitch
-
-Func_07c4:: ; 07c4 (0:07c4)
- ld a, [wWalkBikeSurfState]
- and a
- ret z
- xor a
- ld [wWalkBikeSurfState],a
- ld hl,wd732
- bit 4,[hl]
- ret z
- call PlayDefaultMusic
- ret
-
-LoadPlayerSpriteGraphics:: ; 07d7 (0:07d7)
-; Load sprite graphics based on whether the player is standing, biking, or surfing.
-
- ; 0: standing
- ; 1: biking
- ; 2: surfing
-
- ld a, [wWalkBikeSurfState]
- dec a
- jr z, .ridingBike
-
- ld a, [hTilesetType]
- and a
- jr nz, .determineGraphics
- jr .startWalking
-
-.ridingBike
- ; If the bike can't be used,
- ; start walking instead.
- call IsBikeRidingAllowed
- jr c, .determineGraphics
-
-.startWalking
- xor a
- ld [wWalkBikeSurfState], a
- ld [wWalkBikeSurfStateCopy], a
- jp LoadWalkingPlayerSpriteGraphics
-
-.determineGraphics
- ld a, [wWalkBikeSurfState]
- and a
- jp z, LoadWalkingPlayerSpriteGraphics
- dec a
- jp z, LoadBikePlayerSpriteGraphics
- dec a
- jp z, LoadSurfingPlayerSpriteGraphics
- jp LoadWalkingPlayerSpriteGraphics
-
-IsBikeRidingAllowed:: ; 0805 (0:0805)
-; The bike can be used on Route 23 and Indigo Plateau,
-; or maps with tilesets in BikeRidingTilesets.
-; Return carry if biking is allowed.
-
- ld a, [W_CURMAP]
- cp ROUTE_23
- jr z, .allowed
- cp INDIGO_PLATEAU
- jr z, .allowed
-
- ld a, [W_CURMAPTILESET]
- ld b, a
- ld hl, BikeRidingTilesets
-.loop
- ld a, [hli]
- cp b
- jr z, .allowed
- inc a
- jr nz, .loop
- and a
- ret
-
-.allowed
- scf
- ret
-
-INCLUDE "data/bike_riding_tilesets.asm"
-
-; load the tile pattern data of the current tileset into VRAM
-LoadTilesetTilePatternData:: ; 0828 (0:0828)
- ld a,[W_TILESETGFXPTR]
- ld l,a
- ld a,[W_TILESETGFXPTR + 1]
- ld h,a
- ld de,vTileset
- ld bc,$600
- ld a,[W_TILESETBANK]
- jp FarCopyData2
-
-; this loads the current maps complete tile map (which references blocks, not individual tiles) to C6E8
-; it can also load partial tile maps of connected maps into a border of length 3 around the current map
-LoadTileBlockMap:: ; 083c (0:083c)
-; fill C6E8-CBFB with the background tile
- ld hl,wOverworldMap
- ld bc,$0514
- ld a,[wd3ad] ; background tile number
- call FillMemory
-; load tile map of current map (made of tile block IDs)
-; a 3-byte border at the edges of the map is kept so that there is space for map connections
- ld hl,wOverworldMap
- ld a,[W_CURMAPWIDTH]
- ld [$ff8c],a
- add a,$06 ; border (east and west)
- ld [$ff8b],a ; map width + border
- ld b,$00
- ld c,a
-; make space for north border (next 3 lines)
- add hl,bc
- add hl,bc
- add hl,bc
- ld c,$03
- add hl,bc ; this puts us past the (west) border
- ld a,[W_MAPDATAPTR] ; tile map pointer
- ld e,a
- ld a,[W_MAPDATAPTR + 1]
- ld d,a ; de = tile map pointer
- ld a,[W_CURMAPHEIGHT]
- ld b,a
-.rowLoop ; copy one row each iteration
- push hl
- ld a,[$ff8c] ; map width (without border)
- ld c,a
-.rowInnerLoop
- ld a,[de]
- inc de
- ld [hli],a
- dec c
- jr nz,.rowInnerLoop
-; add the map width plus the border to the base address of the current row to get the next row's address
- pop hl
- ld a,[$ff8b] ; map width + border
- add l
- ld l,a
- jr nc,.noCarry
- inc h
-.noCarry
- dec b
- jr nz,.rowLoop
-.northConnection
- ld a,[W_MAPCONN1PTR]
- cp a,$ff
- jr z,.southConnection
- call SwitchToMapRomBank
- ld a,[wd372]
- ld l,a
- ld a,[wd373]
- ld h,a
- ld a,[wd374]
- ld e,a
- ld a,[wd375]
- ld d,a
- ld a,[wd376]
- ld [$ff8b],a
- ld a,[wd377]
- ld [$ff8c],a
- call LoadNorthSouthConnectionsTileMap
-.southConnection
- ld a,[W_MAPCONN2PTR]
- cp a,$ff
- jr z,.westConnection
- call SwitchToMapRomBank
- ld a,[wd37d]
- ld l,a
- ld a,[wd37e]
- ld h,a
- ld a,[wd37f]
- ld e,a
- ld a,[wd380]
- ld d,a
- ld a,[wd381]
- ld [$ff8b],a
- ld a,[wd382]
- ld [$ff8c],a
- call LoadNorthSouthConnectionsTileMap
-.westConnection
- ld a,[W_MAPCONN3PTR]
- cp a,$ff
- jr z,.eastConnection
- call SwitchToMapRomBank
- ld a,[wd388]
- ld l,a
- ld a,[wd389]
- ld h,a
- ld a,[wd38a]
- ld e,a
- ld a,[wd38b]
- ld d,a
- ld a,[wd38c]
- ld b,a
- ld a,[wd38d]
- ld [$ff8b],a
- call LoadEastWestConnectionsTileMap
-.eastConnection
- ld a,[W_MAPCONN4PTR]
- cp a,$ff
- jr z,.done
- call SwitchToMapRomBank
- ld a,[wd393]
- ld l,a
- ld a,[wd394]
- ld h,a
- ld a,[wd395]
- ld e,a
- ld a,[wd396]
- ld d,a
- ld a,[wd397]
- ld b,a
- ld a,[wd398]
- ld [$ff8b],a
- call LoadEastWestConnectionsTileMap
-.done
- ret
-
-LoadNorthSouthConnectionsTileMap:: ; 0919 (0:0919)
- ld c,$03
-.loop
- push de
- push hl
- ld a,[$ff8b] ; width of connection
- ld b,a
-.innerLoop
- ld a,[hli]
- ld [de],a
- inc de
- dec b
- jr nz,.innerLoop
- pop hl
- pop de
- ld a,[$ff8c] ; width of connected map
- add l
- ld l,a
- jr nc,.noCarry1
- inc h
-.noCarry1
- ld a,[W_CURMAPWIDTH]
- add a,$06
- add e
- ld e,a
- jr nc,.noCarry2
- inc d
-.noCarry2
- dec c
- jr nz,.loop
- ret
-
-LoadEastWestConnectionsTileMap:: ; 093d (0:093d)
- push hl
- push de
- ld c,$03
-.innerLoop
- ld a,[hli]
- ld [de],a
- inc de
- dec c
- jr nz,.innerLoop
- pop de
- pop hl
- ld a,[$ff8b] ; width of connected map
- add l
- ld l,a
- jr nc,.noCarry1
- inc h
-.noCarry1
- ld a,[W_CURMAPWIDTH]
- add a,$06
- add e
- ld e,a
- jr nc,.noCarry2
- inc d
-.noCarry2
- dec b
- jr nz,LoadEastWestConnectionsTileMap
- ret
-
-; function to check if there is a sign or sprite in front of the player
-; if so, carry is set. otherwise, carry is cleared
-IsSpriteOrSignInFrontOfPlayer:: ; 095e (0:095e)
- xor a
- ld [hSpriteIndexOrTextID],a
- ld a,[wd4b0] ; number of signs in the map
- and a
- jr z,.extendRangeOverCounter
-; if there are signs
- predef GetTileAndCoordsInFrontOfPlayer ; get the coordinates in front of the player in de
- call SignLoop
- ret c
-.extendRangeOverCounter
-; check if the player is front of a counter in a pokemon center, pokemart, etc. and if so, extend the range at which he can talk to the NPC
- predef GetTileAndCoordsInFrontOfPlayer ; get the tile in front of the player in c
- ld hl,W_TILESETTALKINGOVERTILES ; list of tiles that extend talking range (counter tiles)
- ld b,$03
- ld d,$20 ; talking range in pixels (long range)
-.counterTilesLoop
- ld a,[hli]
- cp c
- jr z,IsSpriteInFrontOfPlayer2 ; jumps if the tile in front of the player is a counter tile
- dec b
- jr nz,.counterTilesLoop
-
-; sets carry flag if a sprite is in front of the player, resets if not
-IsSpriteInFrontOfPlayer:: ; 0983 (0:0983)
- ld d,$10 ; talking range in pixels (normal range)
-IsSpriteInFrontOfPlayer2:: ; 0985 (0:0985)
- ld bc,$3c40 ; Y and X position of player sprite
- ld a,[wSpriteStateData1 + 9] ; direction the player is facing
-.checkIfPlayerFacingUp
- cp a,$04
- jr nz,.checkIfPlayerFacingDown
-; facing up
- ld a,b
- sub d
- ld b,a
- ld a,$08
- jr .doneCheckingDirection
-.checkIfPlayerFacingDown
- cp a,$00
- jr nz,.checkIfPlayerFacingRight
-; facing down
- ld a,b
- add d
- ld b,a
- ld a,$04
- jr .doneCheckingDirection
-.checkIfPlayerFacingRight
- cp a,$0c
- jr nz,.playerFacingLeft
-; facing right
- ld a,c
- add d
- ld c,a
- ld a,$01
- jr .doneCheckingDirection
-.playerFacingLeft
-; facing left
- ld a,c
- sub d
- ld c,a
- ld a,$02
-.doneCheckingDirection
- ld [wd52a],a
- ld hl,wSpriteStateData1 + $10
-; yellow does not have the "if sprites are existant" check
- ld e,$01
- ld d,$f
-.spriteLoop
- push hl
- ld a,[hli] ; image (0 if no sprite)
- and a
- jr z,.nextSprite
- inc l
- ld a,[hli] ; sprite visibility
- inc a
- jr z,.nextSprite
- inc l
- ld a,[hli] ; Y location
- cp b
- jr nz,.nextSprite
- inc l
- ld a,[hl] ; X location
- cp c
- jr z,.foundSpriteInFrontOfPlayer
-.nextSprite
- pop hl
- ld a,l
- add a,$10
- ld l,a
- inc e
- dec d
- jr nz,.spriteLoop
- xor a
- ret
-.foundSpriteInFrontOfPlayer
- pop hl
- ld a,l
- and a,$f0
- inc a
- ld l,a
- set 7,[hl]
- ld a,e
- ld [hSpriteIndexOrTextID],a
- ld a,[hSpriteIndexOrTextID] ; possible useless read because a already has the value of the read address
- cp a,$f
- jr nz,.dontwritetowd436
- ld a,$FF
- ld [wd436],a
-.dontwritetowd436
- scf
- ret
-
-SignLoop:: ; 09f2 (0:09f2)
-; search if a player is facing a sign
- ld hl,wd4b1 ; start of sign coordinates
- ld a,[wd4b0] ; number of signs in the map
- ld b,a
- ld c,$00
-.signLoop
- inc c
- ld a,[hli] ; sign Y
- cp d
- jr z,.yCoordMatched
- inc hl
- jr .retry
-.yCoordMatched
- ld a,[hli] ; sign X
- cp e
- jr nz,.retry
-.xCoordMatched
-; found sign
- push hl
- push bc
- ld hl,wd4d1 ; start of sign text ID's
- ld b,$00
- dec c
- add hl,bc
- ld a,[hl]
- ld [hSpriteIndexOrTextID],a ; store sign text ID
- pop bc
- pop hl
- scf
- ret
-.retry
- dec b
- jr nz,.signLoop
- xor a
- ret
-
-; 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:: ; 0a1c (0:0a1c)
- ld a,[wd736]
- bit 6,a ; is the player jumping?
- jr nz,.noCollision
-; if not jumping a ledge
- ld a,[wSimulatedJoypadStatesIndex]
- and a
- jr nz,.noCollision ; no collisions when the player's movements are being controlled by the game
- ld a,[wd52a] ; the direction that the player is trying to go in
- ld d,a
- ld a,[wSpriteStateData1 + 12] ; the player sprite's collision data (bit field) (set in the sprite movement code)
- and d ; check if a sprite is in the direction the player is trying to go
- nop ; ??? why is this in the code
- jr nz,.collision
- xor a
- ld [hSpriteIndexOrTextID],a
- call IsSpriteInFrontOfPlayer ; check for sprite collisions again? when does the above check fail to detect a sprite collision?
- jr nc,.asm_0a5c
- res 7,[hl]
- ld a,[hSpriteIndexOrTextID]
- and a ; was there a sprite collision?
- jr z,.asm_0a5c
-; if no sprite collision
- cp $f
- jr nz,.collision
- call CheckForJumpingAndTilePairCollisions
- jr nz,.collision
- ld a,[hJoyHeld]
- and $2
- jr nz,.asm_0a5c
- ld hl,wd435
- ld a,[hl]
- and a
- jr z,.asm_0a5c
- dec [hl]
- jr nz,.collision
-.asm_0a5c
- ld hl,TilePairCollisionsLand
- call CheckForJumpingAndTilePairCollisions
- jr c,.collision
- call CheckTilePassable
- jr nc,.noCollision
-.collision
- ld a,[wc02a]
- cp a,(SFX_02_5b - SFX_Headers_02) / 3 ; check if collision sound is already playing
- jr z,.setCarry
- ld a,(SFX_02_5b - SFX_Headers_02) / 3
- call PlaySound ; play collision sound (if it's not already playing)
-.setCarry
- scf
- ret
-.noCollision
- and a
- ret
-
-; function that checks if the tile in front of the player is passable
-; clears carry if it is, sets carry if not
-CheckTilePassable:: ; 0a79 (0:0a79)
- predef GetTileAndCoordsInFrontOfPlayer ; get tile in front of player
- ld a,[wTileInFrontOfPlayer] ; tile in front of player
- ld c,a
- call IsTilePassable
- ret
-
-; check if the player is going to jump down a small ledge
-; and check for collisions that only occur between certain pairs of tiles
-; Input: hl - address of directional collision data
-; sets carry if there is a collision and unsets carry if not
-CheckForJumpingAndTilePairCollisions:: ; 0a86 (0:0a86)
- push hl
- predef GetTileAndCoordsInFrontOfPlayer ; get the tile in front of the player
- push de
- push bc
- callba HandleLedges ; check if the player is trying to jump a ledge
- pop bc
- pop de
- pop hl
- and a
- ld a,[wd736]
- bit 6,a ; is the player jumping?
- ret nz
-; if not jumping
-
-CheckForTilePairCollisions2:: ; 0aa0 (0:0aa0)
- aCoord 8, 9 ; tile the player is on
- ld [wcf0e],a
-
-CheckForTilePairCollisions:: ; 0aa6 (0:0aa6)
- ld a,[wTileInFrontOfPlayer]
- ld c,a
-.tilePairCollisionLoop
- ld a,[W_CURMAPTILESET] ; tileset number
- ld b,a
- ld a,[hli]
- cp a,$ff
- jr z,.noMatch
- cp b
- jr z,.tilesetMatches
- inc hl
-.retry
- inc hl
- jr .tilePairCollisionLoop
-.tilesetMatches
- ld a,[wcf0e] ; tile the player is on
- ld b,a
- ld a,[hl]
- cp b
- jr z,.currentTileMatchesFirstInPair
- inc hl
- ld a,[hl]
- cp b
- jr z,.currentTileMatchesSecondInPair
- jr .retry
-.currentTileMatchesFirstInPair
- inc hl
- ld a,[hl]
- cp c
- jr z,.foundMatch
- jr .tilePairCollisionLoop
-.currentTileMatchesSecondInPair
- dec hl
- ld a,[hli]
- cp c
- inc hl
- jr nz,.tilePairCollisionLoop
-.foundMatch
- scf
- ret
-.noMatch
- and a
- ret
-
-; FORMAT: tileset number, tile 1, tile 2
-; terminated by 0xFF
-; these entries indicate that the player may not cross between tile 1 and tile 2
-; it's mainly used to simulate differences in elevation
-
-TilePairCollisionsLand:: ; 0ada (0:0ada)
- db CAVERN, $20, $05
- db CAVERN, $41, $05
- db FOREST, $30, $2E
- db CAVERN, $2A, $05
- db CAVERN, $05, $21
- db FOREST, $52, $2E
- db FOREST, $55, $2E
- db FOREST, $56, $2E
- db FOREST, $20, $2E
- db FOREST, $5E, $2E
- db FOREST, $5F, $2E
- db $FF
-
-TilePairCollisionsWater:: ; 0afc (0:0afc)
- db FOREST, $14, $2E
- db FOREST, $48, $2E
- db CAVERN, $14, $05
- db $FF
-
-; this builds a tile map from the tile block map based on the current X/Y coordinates of the player's character
-LoadCurrentMapView:: ; 0b06 (0:0b06)
- ld a,[H_LOADEDROMBANK]
- push af
- ld a,[W_TILESETBANK] ; tile data ROM bank
- call BankswitchCommon ; switch to ROM bank that contains tile data
- ld a,[wCurrentTileBlockMapViewPointer] ; address of upper left corner of current map view
- ld e,a
- ld a,[wCurrentTileBlockMapViewPointer + 1]
- ld d,a
- ld hl,wTileMapBackup
- ld b,$05
-.rowLoop ; each loop iteration fills in one row of tile blocks
- push hl
- push de
- ld c,$06
-.rowInnerLoop ; loop to draw each tile block of the current row
- push bc
- push de
- push hl
- ld a,[de]
- ld c,a ; tile block number
- call DrawTileBlock
- pop hl
- pop de
- pop bc
- inc hl
- inc hl
- inc hl
- inc hl
- inc de
- dec c
- jr nz,.rowInnerLoop
-; update tile block map pointer to next row's address
- pop de
- ld a,[W_CURMAPWIDTH]
- add a,$06
- add e
- ld e,a
- jr nc,.noCarry
- inc d
-.noCarry
-; update tile map pointer to next row's address
- pop hl
- ld a,$60
- add l
- ld l,a
- jr nc,.noCarry2
- inc h
-.noCarry2
- dec b
- jr nz,.rowLoop
- ld hl,wTileMapBackup
- ld bc,$0000
-.adjustForYCoordWithinTileBlock
- ld a,[W_YBLOCKCOORD]
- and a
- jr z,.adjustForXCoordWithinTileBlock
- ld bc,$0030
- add hl,bc
-.adjustForXCoordWithinTileBlock
- ld a,[W_XBLOCKCOORD]
- and a
- jr z,.copyToVisibleAreaBuffer
- ld bc,$0002
- add hl,bc
-.copyToVisibleAreaBuffer
- ld de,wTileMap ; base address for the tiles that are directly transfered to VRAM during V-blank
- ld b,$12
-.rowLoop2
- ld c,$14
-.rowInnerLoop2
- ld a,[hli]
- ld [de],a
- inc de
- dec c
- jr nz,.rowInnerLoop2
- ld a,$04
- add l
- ld l,a
- jr nc,.noCarry3
- inc h
-.noCarry3
- dec b
- jr nz,.rowLoop2
- pop af
- call BankswitchCommon ; restore previous ROM bank
- ret
-
-AdvancePlayerSprite:: ; 0b7f (0:0b7f)
- ld a,[wUpdateSpritesEnabled]
- push af
- ld a,$FF
- ld [wUpdateSpritesEnabled],a
- ld hl, _AdvancePlayerSprite ; 3c:410c
- ld b, BANK(_AdvancePlayerSprite)
- call Bankswitch
- pop af
- ld [wUpdateSpritesEnabled],a
- ret
-
-; the following 6 functions are used to tell the V-blank handler to redraw
-; the portion of the map that was newly exposed due to the player's movement
-
-ScheduleNorthRowRedraw:: ; 0b95 (0:0b95)
- hlCoord 0, 0
- call CopyToScreenEdgeTiles
- ld a,[wMapViewVRAMPointer]
- ld [H_SCREENEDGEREDRAWADDR],a
- ld a,[wMapViewVRAMPointer + 1]
- ld [H_SCREENEDGEREDRAWADDR + 1],a
- ld a,REDRAWROW
- ld [H_SCREENEDGEREDRAW],a
- ret
-
-CopyToScreenEdgeTiles:: ; 0baa (0:0baa)
- ld de,wScreenEdgeTiles
- ld c,2 * 20
-.loop
- ld a,[hli]
- ld [de],a
- inc de
- dec c
- jr nz,.loop
- ret
-
-ScheduleSouthRowRedraw:: ; 0bb6 (0:0bb6)
- hlCoord 0, 16
- call CopyToScreenEdgeTiles
- ld a,[wMapViewVRAMPointer]
- ld l,a
- ld a,[wMapViewVRAMPointer + 1]
- ld h,a
- ld bc,$0200
- add hl,bc
- ld a,h
- and a,$03
- or a,$98
- ld [H_SCREENEDGEREDRAWADDR + 1],a
- ld a,l
- ld [H_SCREENEDGEREDRAWADDR],a
- ld a,REDRAWROW
- ld [H_SCREENEDGEREDRAW],a
- ret
-
-ScheduleEastColumnRedraw:: ; 0bd6 (0:0bd7)
- hlCoord 18, 0
- call ScheduleColumnRedrawHelper
- ld a,[wMapViewVRAMPointer]
- ld c,a
- and a,$e0
- ld b,a
- ld a,c
- add a,18
- and a,$1f
- or b
- ld [H_SCREENEDGEREDRAWADDR],a
- ld a,[wMapViewVRAMPointer + 1]
- ld [H_SCREENEDGEREDRAWADDR + 1],a
- ld a,REDRAWCOL
- ld [H_SCREENEDGEREDRAW],a
- ret
-
-ScheduleColumnRedrawHelper:: ; 0bf6 (0:0bf6)
- ld de,wScreenEdgeTiles
- ld c,$12
-.loop
- ld a,[hli]
- ld [de],a
- inc de
- ld a,[hl]
- ld [de],a
- inc de
- ld a,19
- add l
- ld l,a
- jr nc,.noCarry
- inc h
-.noCarry
- dec c
- jr nz,.loop
- ret
-
-ScheduleWestColumnRedraw:: ; 0c0c (0:0c0c)
- hlCoord 0, 0
- call ScheduleColumnRedrawHelper
- ld a,[wMapViewVRAMPointer]
- ld [H_SCREENEDGEREDRAWADDR],a
- ld a,[wMapViewVRAMPointer + 1]
- ld [H_SCREENEDGEREDRAWADDR + 1],a
- ld a,REDRAWCOL
- ld [H_SCREENEDGEREDRAW],a
- ret
-
-; function to write the tiles that make up a tile block to memory
-; Input: c = tile block ID, hl = destination address
-DrawTileBlock:: ; 0c21 (0:0c21)
- push hl
- ld a,[W_TILESETBLOCKSPTR] ; pointer to tiles
- ld l,a
- ld a,[W_TILESETBLOCKSPTR + 1]
- ld h,a
- ld a,c
- swap a
- ld b,a
- and a,$f0
- ld c,a
- ld a,b
- and a,$0f
- ld b,a ; bc = tile block ID * 0x10
- add hl,bc
- ld d,h
- ld e,l ; de = address of the tile block's tiles
- pop hl
- ld c,$04 ; 4 loop iterations
-.loop ; each loop iteration, write 4 tile numbers
- push bc
- ld a,[de]
- ld [hli],a
- inc de
- ld a,[de]
- ld [hli],a
- inc de
- ld a,[de]
- ld [hli],a
- inc de
- ld a,[de]
- ld [hl],a
- inc de
- ld bc,$0015
- add hl,bc
- pop bc
- dec c
- jr nz,.loop
- ret
-
-; function to update joypad state and simulate button presses
-JoypadOverworld:: ; 0c51 (0:0c51)
- xor a
- ld [wSpriteStateData1 + 3],a
- ld [wSpriteStateData1 + 5],a
- call RunMapScript
- call Joypad
- call ForceBikeDown
- call AreInputsSimulated
- ret
-
-ForceBikeDown:: ; 0c65 (0:0c65)
- ld a,[W_FLAGS_D733]
- bit 3,a ; check if a trainer wants a challenge
- ret nz
- ld a,[W_CURMAP]
- cp a,ROUTE_17 ; Cycling Road
- ret nz
- ld a,[hJoyHeld]
- and a,D_DOWN | D_UP | D_LEFT | D_RIGHT | B_BUTTON | A_BUTTON
- jr nz,.notForcedDownwards
- ld a,D_DOWN
- ld [hJoyHeld],a ; on the cycling road, if there isn't a trainer and the player isn't pressing buttons, simulate a down press
- ret
-
-AreInputsSimulated:: ; 0c7b (0:0c7b)
- ld a,[wd730]
- bit 7,a
- ret z
-; if simulating button presses
- ld a,[hJoyHeld]
- ld b,a
- ld a,[wOverrideSimulatedJoypadStatesMask] ; bit mask for button presses that override simulated ones
- and b
- ret nz ; return if the simulated button presses are overridden
- call GetSimulatedInput
- jr nc,.doneSimulating
- ld [hJoyHeld],a ; store simulated button press in joypad state
- and a
- ret nz
- ld [hJoyPressed],a
- ld [hJoyReleased],a
- ret
-
-; if done simulating button presses
-.doneSimulating
- xor a
- ld [wWastedByteCD3A],a
- ld [wSimulatedJoypadStatesIndex],a
- ld [wSimulatedJoypadStatesEnd],a
- ld [wJoyIgnore],a
- ld [hJoyHeld],a
- ld hl,wd736
- ld a,[hl]
- and a,$f8
- ld [hl],a
- ld hl,wd730
- res 7,[hl]
- ret
-
-GetSimulatedInput:: ; 0cb3 (0:0cb3)
- ld hl,wSimulatedJoypadStatesIndex
- dec [hl]
- ld a,[hl]
- cp a,$ff
- jr z,.endofsimulatedinputs ; if the end of the simulated button presses has been reached
- push de
- ld e,a
- ld d,$0
- ld hl,wSimulatedJoypadStatesEnd
- add hl,de
- ld a,[hl]
- pop de
- scf
- ret
-.endofsimulatedinputs
- and a
- ret
-
-
-; function to check the tile ahead to determine if the character should get on land or keep surfing
-; sets carry if there is a collision and clears carry otherwise
-; It seems that this function has a bug in it, but due to luck, it doesn't
-; show up. After detecting a sprite collision, it jumps to the code that
-; checks if the next tile is passable instead of just directly jumping to the
-; "collision detected" code. However, it doesn't store the next tile in c,
-; so the old value of c is used. 2429 is always called before this function,
-; and 2429 always sets c to 0xF0. There is no 0xF0 background tile, so it
-; is considered impassable and it is detected as a collision.
-CollisionCheckOnWater:: ; 0cca (0:0cca)
- ld a,[wd730]
- bit 7,a
- jp nz,.noCollision ; return and clear carry if button presses are being simulated
- ld a,[wd52a] ; the direction that the player is trying to go in
- ld d,a
- ld a,[wSpriteStateData1 + 12] ; the player sprite's collision data (bit field) (set in the sprite movement code)
- and d ; check if a sprite is in the direction the player is trying to go
- jr nz,.checkIfNextTileIsPassable ; bug?
- ld hl,TilePairCollisionsWater
- call CheckForJumpingAndTilePairCollisions
- jr c,.collision
- predef GetTileAndCoordsInFrontOfPlayer ; get tile in front of player (puts it in c and [wTileInFrontOfPlayer])
- callab IsNextTileShoreOrWater ; 3:6808
- jr c,.noCollsion
- ld a,[wTileInFrontOfPlayer] ; tile in front of player
- ld c,a
- call IsTilePassable
- jr nc,.stopSurfing
-.collision
- ld a,[wc02a]
- cp a,(SFX_02_5b - SFX_Headers_02) / 3 ; check if collision sound is already playing
- jr z,.setCarry
- ld a,(SFX_02_5b - SFX_Headers_02) / 3
- call PlaySound ; play collision sound (if it's not already playing)
-.setCarry
- scf
- jr .done
-.checkIfVermilionDockTileset
- ld a, [W_CURMAPTILESET] ; tileset
- cp SHIP_PORT ; Vermilion Dock tileset
- jr nz, .noCollision ; keep surfing if it's not the boarding platform tile
- jr .stopSurfing ; if it is the boarding platform tile, stop surfing
-.stopSurfing ; based game freak
- ld a,$3
- ld [wd431],a
- ld hl,wd430
- set 5,[hl]
- xor a
- ld [wWalkBikeSurfState],a
- call LoadPlayerSpriteGraphics
- call PlayDefaultMusic
- jr .noCollision
-.noCollision ; ...and they do the same mistake twice
- and a
-.done
- ret
-
-; function to run the current map's script
-RunMapScript:: ; 0d2c (0:0d2c)
- push hl
- push de
- push bc
- callba TryPushingBoulder
- ld a,[wFlags_0xcd60]
- bit 1,a ; play boulder dust animation
- jr z,.afterBoulderEffect
- callba DoBoulderDustAnimation
-.afterBoulderEffect
- pop bc
- pop de
- pop hl
- call RunNPCMovementScript
- ld a,[W_CURMAP] ; current map number
- call SwitchToMapRomBank ; change to the ROM bank the map's data is in
- ld hl,W_MAPSCRIPTPTR
- ld a,[hli]
- ld h,[hl]
- ld l,a
- ld de,.return
- push de
- jp [hl] ; jump to script
-.return
- ret
-
-Func_0d5e:: ; 0d5e (0:0d5e)
-; new sprite copy stuff
- xor a
- ld [wd473],a
- ld b,BANK(RedSprite)
- ld de,RedSprite ; $4180
- jr LoadPlayerSpriteGraphicsCommon
-
-Func_0d69:: ; 0d69 (0:0d69)
- ld a,[wd473]
- and a
- jr z,.asm_0d75
- dec a
- jr z,.asm_0d83
- dec a
- jr z,.asm_0d7c
-.asm_0d75
- ld a,[wd472]
- bit 6,a
- jr z,LoadSurfingPlayerSpriteGraphics
-.asm_0d7c
- ld b,BANK(Pointer_fedef)
- ld de,Pointer_fedef ; 3f:6def
- jr LoadPlayerSpriteGraphicsCommon
-
-LoadSurfingPlayerSpriteGraphics:: ; 0d83 (0:0d83)
- ld b,BANK(RedSprite) ; not sure, but probably same bank (5)
- ld de,SeelSprite
- jr LoadPlayerSpriteGraphicsCommon
-
-LoadBikePlayerSpriteGraphics:: ; 0d8a (0:0d8a)
- ld de,RedCyclingSprite
-LoadPlayerSpriteGraphicsCommon:: ; 0d8f (0:0d8f)
- ld hl,vNPCSprites
- push de
- push hl
- ld c, $c
- call CopyVideoData
- pop hl
- pop de
- ld a,$c0
- add e
- ld e,a
- jr nc,.noCarry
- inc d
-.noCarry
- set 3,h
- ld c,$c
- jp CopyVideoData
-
-; function to load data from the map header
-LoadMapHeader:: ; 0dab (0:0dab)
- callba MarkTownVisitedAndLoadMissableObjects
- jr .asm_0dbd
- callba Func_f0a55 ; 3c:4a55
-.asm_0dbd
- ld a,[W_CURMAPTILESET]
- ld [wd119],a
- ld a,[W_CURMAP]
- call SwitchToMapRomBank
- ld a,[W_CURMAPTILESET]
- ld b,a
- res 7,a
- ld [W_CURMAPTILESET],a
- ld [$ff8b],a
- bit 7,b
- ret nz
- call GetMapHeaderPointer
-; copy the first 10 bytes (the fixed area) of the map data to D367-D370
- ld de,W_CURMAPTILESET
- ld c,$0a
-.copyFixedHeaderLoop
- ld a,[hli]
- ld [de],a
- inc de
- dec c
- jr nz,.copyFixedHeaderLoop
-; initialize all the connected maps to disabled at first, before loading the actual values
- ld a,$ff
- ld [W_MAPCONN1PTR],a
- ld [W_MAPCONN2PTR],a
- ld [W_MAPCONN3PTR],a
- ld [W_MAPCONN4PTR],a
-; copy connection data (if any) to WRAM
- ld a,[W_MAPCONNECTIONS]
- ld b,a
-.checkNorth
- bit 3,b
- jr z,.checkSouth
- ld de,W_MAPCONN1PTR
- call CopyMapConnectionHeader
-.checkSouth
- bit 2,b
- jr z,.checkWest
- ld de,W_MAPCONN2PTR
- call CopyMapConnectionHeader
-.checkWest
- bit 1,b
- jr z,.checkEast
- ld de,W_MAPCONN3PTR
- call CopyMapConnectionHeader
-.checkEast
- bit 0,b
- jr z,.getObjectDataPointer
- ld de,W_MAPCONN4PTR
- call CopyMapConnectionHeader
-.getObjectDataPointer
- ld a,[hli]
- ld [wd3a9],a
- ld a,[hli]
- ld [wd3aa],a
- push hl
- ld a,[wd3a9]
- ld l,a
- ld a,[wd3aa]
- ld h,a ; hl = base of object data
- ld de,wd3ad ; background tile ID
- ld a,[hli]
- ld [de],a ; save background tile ID
-.loadWarpData
- ld a,[hli]
- ld [wNumberOfWarps],a
- and a
- jr z,.loadSignData
- ld c,a
- ld de,wWarpEntries
-.warpLoop ; one warp per loop iteration
- ld b,$04
-.warpInnerLoop
- ld a,[hli]
- ld [de],a
- inc de
- dec b
- jr nz,.warpInnerLoop
- dec c
- jr nz,.warpLoop
-.loadSignData
- ld a,[hli] ; number of signs
- ld [wd4b0],a ; save the number of signs
- and a ; are there any signs?
- jr z,.loadSpriteData ; if not, skip this
- call CopySignData ; 0eb3 (0:0eb3)
-.loadSpriteData
- ld a,[wd72e]
- bit 5,a ; did a battle happen immediately before this?
- jp nz,.finishUp ; if so, skip this because battles don't destroy this data
- call InitSprites
-.finishUp
- predef LoadTilesetHeader
- ld a,[wd72e]
- bit 5,a ; did a battle happen immediately before this?
- jr nz,.asm_0e73
- callab Func_fc4fa ; 3f:44fa
- callab LoadWildData
- pop hl ; restore hl from before going to the warp/sign/sprite data (this value was saved for seemingly no purpose)
- ld a,[W_CURMAPHEIGHT] ; map height in 4x4 tile blocks
- add a ; double it
- ld [wd524],a ; store map height in 2x2 tile blocks
- ld a,[W_CURMAPWIDTH] ; map width in 4x4 tile blocks
- add a ; double it
- ld [wd525],a ; map width in 2x2 tile blocks
- ld a,[W_CURMAP]
- ld c,a
- ld b,$00
- ld a,[H_LOADEDROMBANK]
- push af
- switchbank MapSongBanks
- ld hl, MapSongBanks ; 3f:4000
- add hl,bc
- add hl,bc
- ld a,[hli]
- ld [wd35b],a ; music 1
- ld a,[hl]
- ld [wd35c],a ; music 2
- pop af
- call BankswitchCommon
- ret
-
-; function to copy map connection data from ROM to WRAM
-; Input: hl = source, de = destination
-CopyMapConnectionHeader:: ; 1238 (0:1238)
- ld c,$0b
-.loop
- ld a,[hli]
- ld [de],a
- inc de
- dec c
- jr nz,.loop
- ret
-
-CopySignData:: ; 0eb3 (0:0eb3)
- ld de,wd4b1 ; start of sign coords
- ld bc,wd4d1 ; start of sign text ids
- ld a,[wd4b0] ; number of signs
-.signcopyloop
- push af
- ld a,[hli]
- ld [de],a ; copy y coord
- inc de
- ld a,[hli]
- ld [de],a ; copy x coord
- inc de
- ld a,[hli]
- ld [bc],a ; copy sign text id
- inc bc
- pop af
- dec a
- jr nz,.signcopyloop
- ret
-
-; function to load map data
-LoadMapData:: ; 1241 (0:1241)
- ld a,[H_LOADEDROMBANK]
- push af
- call DisableLCD
- call ResetMapVariables
- call LoadTextBoxTilePatterns
- call LoadMapHeader
- call InitMapSprites ; load tile pattern data for sprites
- call LoadScreenRelatedData
- call CopyMapViewToVRAM
- ld a,$01
- ld [wUpdateSpritesEnabled],a
- call EnableLCD
- ld b,$09
- call GoPAL_SET
- call LoadPlayerSpriteGraphics
- ld a,[wd732]
- and a,1 << 4 | 1 << 3 ; fly warp or dungeon warp
- jr nz,.restoreRomBank
- ld a,[W_FLAGS_D733]
- bit 1,a
- jr nz,.restoreRomBank
- call Func_235f ; music related
- call Func_2312 ; music related
-.restoreRomBank
- pop af
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- ret
-
-LoadScreenRelatedData:: ; 0f0c (0:0f0c)
- call LoadTileBlockMap
- call LoadTilesetTilePatternData
- call LoadCurrentMapView
- ret
-
-Func_0f16:: ; 0f16 (0:0f16)
- ld a,[H_LOADEDROMBANK]
- push af
- call DisableLCD
- call ResetMapVariables
- ld a,[W_CURMAP]
- call SwitchToMapRomBank
- call LoadScreenRelatedData
- call CopyMapViewToVRAM
- ld de,vBGMap1
- call CopyMapViewToVRAM2
- call EnableLCD
- call ReloadMapSpriteTilePatterns
- pop af
- call BankswitchCommon
- jr .asm_0f4d
-Func_0f3d:: ; 0f3d (0:0f3d)
- ld a,[H_LOADEDROMBANK]
- push af
- ld a,[W_CURMAP]
- call SwitchToMapRomBank
- call LoadTileBlockMap
- pop af
- call BankswitchCommon
-.asm_0f4d
- ld hl, Func_f02da
- ld b,BANK(Func_f02da) ; 3c:42da
- jp Bankswitch
- ret ; useless?
-
-ResetMapVariables:: ; 0f56 (0:0f56)
- ld a,$98
- ld [wMapViewVRAMPointer + 1],a
- xor a
- ld [wMapViewVRAMPointer],a
- ld [hSCY],a
- ld [hSCX],a
- ld [wWalkCounter],a
- ld [wd119],a
- ld [W_SPRITESETID],a
- ld [wWalkBikeSurfStateCopy],a
- ret
-
-CopyMapViewToVRAM:: ; 0f70 (0:0f70)
-; copy current map view to VRAM
- ld de,vBGMap0
-CopyMapViewToVRAM2: ; 0f73 (0:0f73)
- ld hl,wTileMap
- ld b,18
-.vramCopyLoop
- ld c,20
-.vramCopyInnerLoop
- ld a,[hli]
- ld [de],a
- inc e
- dec c
- jr nz,.vramCopyInnerLoop
- ld a,32 - 20 ; total vram map width in tiles - screen width in tiles
- add e
- ld e,a
- jr nc,.noCarry
- inc d
-.noCarry
- dec b
- jr nz,.vramCopyLoop
- ret
-
-; function to switch to the ROM bank that a map is stored in
-; Input: a = map number
-SwitchToMapRomBank:: ; 0f8b (0:0f8b)
- push hl
- push bc
- ld c,a
- ld b,$00
- ld a,BANK(MapHeaderBanks)
- call BankswitchHome ; switch to ROM bank 3F
- ld hl,MapHeaderBanks
- add hl,bc
- ld a,[hl]
- ld [$ffe8],a ; save map ROM bank
- call BankswitchCommon
- pop bc
- pop hl
- ret
-
-GetMapHeaderPointer:: ; 0fa7 (0:0fa7)
- ld a,[H_LOADEDROMBANK]
- push af
- switchbank MapHeaderPointers ; 3f:41f2
- push de
- ld a,[W_CURMAP]
- ld e,a
- ld d,$0
- ld hl,MapHeaderPointers
- add hl,de
- add hl,de
- ld a,[hli]
- ld h,[hl]
- ld l,a
- pop de
- pop af
- jp BankswitchCommon
-
-IgnoreInputForHalfSecond: ; 0fc3 (0:0fc3)
- ld a, 30
- ld [wIgnoreInputCounter], a
- ld hl, wd730
- ld a, [hl]
- or $26
- ld [hl], a ; set ignore input bit
- ret
-
-ResetUsingStrengthOutOfBattleBit: ; 0fd0 (0:0fd0)
- ld hl, wd728
- res 0, [hl]
- ret
-
-ForceBikeOrSurf:: ; 0fd6 (0:0fd6)
- ld b, BANK(RedSprite)
- ld hl, LoadPlayerSpriteGraphics
- call Bankswitch
- jp PlayDefaultMusic ; update map/player state?
-
-; Handle the player jumping down
-; a ledge in the overworld.
-HandleMidJump:: ; 0fe1 (0:0fe1)
- ld a,[wd736]
- bit 7,a ; jumping down a ledge?
- ret z
- ld b, BANK(_HandleMidJump)
- ld hl, _HandleMidJump
- jp Bankswitch
-
-IsSpinning:: ; 0ff0 (0:0ff0)
- ld a,[wd736]
- bit 7,a
- ret z ; no spinning
- ld b, BANK(LoadSpinnerArrowTiles); spin while moving
- ld hl,LoadSpinnerArrowTiles ; 11:5077
- jp Bankswitch
-
-Func_0ffe:: ; 0ffe (0:0ffe)
- ld hl, Func_fcf0c ; 3f:4f0c
- ld b, BANK(Func_fcf0c)
- jp Bankswitch
-
-InitSprites:: ; 1006 (0:1006)
- ld a,[hli]
- ld [W_NUMSPRITES],a ; save the number of sprites
- push hl
- push hl
- push de
- push bc
- call ZeroSpriteStateData
- call DisableRegularSprites
- ld hl,W_MAPSPRITEDATA
- ld bc,$20
- xor a
- call FillMemory
- pop bc
- pop de
- pop hl
- ld a,[W_NUMSPRITES]
- and a ; are sprites existant?
- ret z ; don't copy sprite data if not
- ld b,a
- ld c,$0
- ld de,wSpriteStateData1 + $10
-; copy sprite stuff?
-.loadSpriteLoop
- ld a,[hli]
- ld [de],a ; store picture ID at C1X0
- inc d
- ld a,$04
- add e
- ld e,a
- ld a,[hli]
- ld [de],a ; store Y position at C2X4
- inc e
- ld a,[hli]
- ld [de],a ; store X position at C2X5
- inc e
- ld a,[hli]
- ld [de],a ; store movement byte 1 at C2X6
- ld a,[hli]
- ld [$ff8d],a ; save movement byte 2
- ld a,[hli]
- ld [$ff8e],a ; save text ID and flags byte
- push bc
- call LoadSprite
- pop bc
- dec d
- ld a,e
- add a,$a
- ld e,a
- inc c
- inc c
- dec b
- jr nz,.loadSpriteLoop
- ret
-
-ZeroSpriteStateData:: ; 1050 (0:1050)
-; zero C110-C1EF and C210-C2EF
-; C1F0-C1FF and C2F0-C2FF is probably used for Pikachu
- ld hl,wSpriteStateData1 + $10
- ld de,wSpriteStateData2 + $10
- xor a
- ld b,$e0
-.loop
- ld [hli],a
- ld [de],a
- inc e
- dec b
- jr nz,.loop
- ret
-
-DisableRegularSprites:: ; 1060 (0:1060)
-; initialize all C100-C1FF sprite entries to disabled (other than player's and pikachu)
- ld hl,wSpriteStateData1 + $12
- ld de,$10
- ld c,$e
-.loop
- ld [hl],$ff
- add hl,de
- dec c
- jr nz,.loop
- ret
-
-LoadSprite:: ; 106f (0:106f)
- push hl
- ld b,$0
- ld hl,W_MAPSPRITEDATA
- add hl,bc
- ld a,[$ff8d]
- ld [hli],a ; store movement byte 2 in byte 0 of sprite entry
- ld a,[$ff8e]
- ld [hl],a ; this appears pointless, since the value is overwritten immediately after
- ld a,[$ff8e]
- ld [$ff8d],a
- and a,$3f
- ld [hl],a ; store text ID in byte 1 of sprite entry
- pop hl
- ld a,[$ff8d]
- bit 6,a
- jr nz,.trainerSprite
- bit 7,a
- jr nz,.itemBallSprite
-; for regular sprites
- push hl
- ld hl,W_MAPSPRITEEXTRADATA
- add hl,bc
-; zero both bytes, since regular sprites don't use this extra space
- xor a
- ld [hli],a
- ld [hl],a
- pop hl
- ret
-
-.trainerSprite
- ld a,[hli]
- ld [$ff8d],a ; save trainer class
- ld a,[hli]
- ld [$ff8e],a ; save trainer number (within class)
- push hl
- ld hl,W_MAPSPRITEEXTRADATA
- add hl,bc
- ld a,[$ff8d]
- ld [hli],a ; store trainer class in byte 0 of the entry
- ld a,[$ff8e]
- ld [hl],a ; store trainer number in byte 1 of the entry
- pop hl
- ret
-
-.itemBallSprite
- ld a,[hli]
- ld [$ff8d],a ; save item number
- push hl
- ld hl,W_MAPSPRITEEXTRADATA
- add hl,bc
- ld a,[$ff8d]
- ld [hli],a ; store item number in byte 0 of the entry
- xor a
- ld [hl],a ; zero byte 1, since it is not used
- pop hl
+EnterMap:: ; 01d7 (0:01d7)
+; Load a new map.
+ ld a, $ff
+ ld [wJoyIgnore], a
+ call LoadMapData
+ callba ClearVariablesAfterLoadingMapData
+ ld hl, wd72c
+ bit 0, [hl] ; has the player already made 3 steps since the last battle?
+ jr z, .skipGivingThreeStepsOfNoRandomBattles
+ ld a, 3 ; minimum number of steps between battles
+ ld [wNumberOfNoRandomBattleStepsLeft], a
+.skipGivingThreeStepsOfNoRandomBattles
+ ld hl, wd72e
+ bit 5, [hl] ; did a battle happen immediately before this?
+ res 5, [hl] ; unset the "battle just happened" flag
+ call z, ResetUsingStrengthOutOfBattleBit
+ call nz, MapEntryAfterBattle
+ ld hl, wd732
+ ld a, [hl]
+ and 1 << 4 | 1 << 3 ; fly warp or dungeon warp
+ jr z, .didNotEnterUsingFlyWarpOrDungeonWarp
+ callba EnterMapAnim
+ call UpdateSprites
+ ld hl, wd732
+ res 3, [hl]
+ ld hl, wd72e
+ res 4, [hl]
+ call Func_342a
+.didNotEnterUsingFlyWarpOrDungeonWarp
+ callba CheckForceBikeOrSurf ; handle currents in SF islands and forced bike riding in cycling road
+ ld hl, wd732
+ bit 4, [hl]
+ res 4, [hl]
+ ld hl, wd72d
+ res 5, [hl]
+ call UpdateSprites
+ ld hl, wd126
+ set 5, [hl]
+ set 6, [hl]
+ xor a
+ ld [wJoyIgnore], a
+
+OverworldLoop:: ; 0242 (0:0242)
+ call DelayFrame
+OverworldLoopLessDelay:: ; 0245 (0:0245)
+ call DelayFrame
+ call Func_342a
+ call LoadGBPal
+ ld a,[wWalkCounter]
+ and a
+ jp nz,.moveAhead ; if the player sprite has not yet completed the walking animation
+ call JoypadOverworld ; get joypad state (which is possibly simulated)
+ callba SafariZoneCheck
+ ld a,[wSafariZoneGameOver]
+ and a
+ jp nz,WarpFound2
+ ld hl,wd72d
+ bit 3,[hl]
+ res 3,[hl]
+ jp nz,WarpFound2
+ ld a,[wd732]
+ and a,1 << 4 | 1 << 3 ; fly warp or dungeon warp
+ jp nz,HandleFlyWarpOrDungeonWarp
+ ld a,[W_CUROPPONENT]
+ and a
+ jp nz,.newBattle
+ ld a,[wd730]
+ bit 7,a ; are we simulating button presses?
+ jr z,.notSimulating
+ ld a,[hJoyHeld]
+ jr .checkIfStartIsPressed
+.notSimulating
+ ld a,[hJoyPressed]
+.checkIfStartIsPressed
+ bit 3,a ; start button
+ jr z,.startButtonNotPressed
+; if START is pressed
+ xor a
+ ld [hSpriteIndexOrTextID],a ; start menu text ID
+ jp .displayDialogue
+.startButtonNotPressed
+ bit 0,a ; A button
+ jp z,.checkIfDownButtonIsPressed
+; if A is pressed
+ ld a,[wd730]
+ bit 2,a
+ jp nz,.noDirectionButtonsPressed
+ call IsPlayerCharacterBeingControlledByGame
+ jr nz,.checkForOpponent
+ call CheckForHiddenObjectOrBookshelfOrCardKeyDoor
+ ld a,[$ffeb]
+ and a
+ jp z,OverworldLoop ; jump if a hidden object or bookshelf was found, but not if a card key door was found
+ xor a
+ ld [wd436],a ; new yellow address
+ call IsSpriteOrSignInFrontOfPlayer
+ call Func_0ffe
+ ld a,[hSpriteIndexOrTextID]
+ and a
+ jp z,OverworldLoop
+.displayDialogue
+ predef GetTileAndCoordsInFrontOfPlayer
+ call UpdateSprites
+ ld a,[wFlags_0xcd60]
+ bit 2,a
+ jr nz,.checkForOpponent
+ bit 0,a
+ jr nz,.checkForOpponent
+ aCoord 8, 9
+ ld [wcf0e],a
+ call DisplayTextID ; display either the start menu or the NPC/sign text
+ ld a,[wcc47]
+ and a
+ jr z,.checkForOpponent
+ xor a
+ ld [wcc47],a
+ jp EnterMap
+; predef LoadSAV
+; ld a,[W_CURMAP]
+; ld [wDestinationMap],a
+; call SpecialWarpIn
+; ld a,[W_CURMAP]
+; call SwitchToMapRomBank ; switch to the ROM bank of the current map
+; ld hl,W_CURMAPTILESET
+; set 7,[hl]
+.checkForOpponent
+ ld a,[W_CUROPPONENT]
+ and a
+ jp nz,.newBattle
+ jp OverworldLoop
+.noDirectionButtonsPressed
+ call UpdateSprites ; 231c
+ ld hl,wFlags_0xcd60
+ res 2,[hl]
+ xor a
+ ld [wd435], a
+ ld a, $1
+ ld a,$01
+ ld [wcc4b],a
+ ld a,[wd528] ; the direction that was pressed last time
+ and a
+ jr z, .overworldloop
+; if a direction was pressed last time
+ ld [wd529],a ; save the last direction
+ xor a
+ ld [wd528],a ; zero the direction
+.overworldloop
+ jp OverworldLoop
+.checkIfDownButtonIsPressed
+ ld a,[hJoyHeld] ; current joypad state
+ bit 7,a ; down button
+ jr z,.checkIfUpButtonIsPressed
+ ld a,$01
+ ld [wSpriteStateData1 + 3],a
+ ld a,$04
+ jr .handleDirectionButtonPress
+.checkIfUpButtonIsPressed
+ bit 6,a ; up button
+ jr z,.checkIfLeftButtonIsPressed
+ ld a,$ff
+ ld [wSpriteStateData1 + 3],a
+ ld a,$08
+ jr .handleDirectionButtonPress
+.checkIfLeftButtonIsPressed
+ bit 5,a ; left button
+ jr z,.checkIfRightButtonIsPressed
+ ld a,$ff
+ ld [wSpriteStateData1 + 5],a
+ ld a,$02
+ jr .handleDirectionButtonPress
+.checkIfRightButtonIsPressed
+ bit 4,a ; right button
+ jr z,.noDirectionButtonsPressed
+ ld a,$01
+ ld [wSpriteStateData1 + 5],a
+.handleDirectionButtonPress
+ ld [wd52a],a ; new direction
+ ld a,[wd730]
+ bit 7,a ; are we simulating button presses?
+ jr nz,.noDirectionChange ; ignore direction changes if we are
+ ld a,[wcc4b]
+ and a
+ jr z,.noDirectionChange
+ ld a,[wd52a] ; new direction
+ ld b,a
+ ld a,[wd529] ; old direction
+ cp b
+ jr z,.noDirectionChange
+ ld a,$8
+ ld [wd434],a
+; unlike in red/blue, yellow does not have the 180 degrees odd code
+ ld hl,wFlags_0xcd60
+ set 2,[hl]
+ xor a
+ ld [wcc4b],a
+ ld a,[wd52a]
+ ld [wd528],a
+ call NewBattle
+ jp c,.battleOccurred
+ jp OverworldLoop
+.noDirectionChange
+ ld a,[wd52a] ; current direction
+ ld [wd528],a ; save direction
+ call UpdateSprites
+ ld a,[wWalkBikeSurfState]
+ cp a,$02 ; surfing
+ jr z,.surfing
+; not surfing
+ call CollisionCheckOnLand
+ jr nc,.noCollision
+; collision occurred
+ push hl
+ ld hl,wd736
+ bit 2,[hl] ; standing on warp flag
+ pop hl
+ jp z,OverworldLoop
+; collision occurred while standing on a warp
+ push hl
+ call ExtraWarpCheck ; sets carry if there is a potential to warp
+ pop hl
+ jp c,CheckWarpsCollision
+ jp OverworldLoop
+.surfing
+ call CollisionCheckOnWater
+ jp c,OverworldLoop
+.noCollision
+ ld a,$08
+ ld [wWalkCounter],a
+ callab Func_fcc08
+ jr .moveAhead2
+.moveAhead
+ call IsSpinning
+ call UpdateSprites ; move sprites
+.moveAhead2
+ ld hl,wFlags_0xcd60
+ res 2,[hl]
+ xor a
+ ld [wd435],a
+ call DoBikeSpeedup
+ call AdvancePlayerSprite
+ ld a,[wWalkCounter]
+ and a
+ jp nz,CheckMapConnections ; it seems like this check will never succeed (the other place where CheckMapConnections is run works)
+; walking animation finished
+ call StepCountCheck
+ ld a,[wd790]
+ bit 7,a ; in the safari zone?
+ jr z,.notSafariZone
+ callba SafariZoneCheckSteps
+ ld a,[wSafariZoneGameOver]
+ and a
+ jp nz,WarpFound2
+.notSafariZone
+ ld a,[W_ISINBATTLE]
+ and a
+ jp nz,CheckWarpsNoCollision
+ predef ApplyOutOfBattlePoisonDamage ; also increment daycare mon exp
+ ld a,[wd12d]
+ and a
+ jp nz,HandleBlackOut ; if all pokemon fainted
+.newBattle
+ call NewBattle
+ ld hl,wd736
+ res 2,[hl] ; standing on warp flag
+ jp nc,CheckWarpsNoCollision ; check for warps if there was no battle
+.battleOccurred
+ ld hl,wd72d
+ res 6,[hl]
+ ld hl,W_FLAGS_D733
+ res 3,[hl]
+ ld hl,wd126
+ set 5,[hl]
+ set 6,[hl]
+ xor a
+ ld [hJoyHeld],a
+ ld a,[W_CURMAP]
+ cp a,CINNABAR_GYM
+ jr nz,.notCinnabarGym
+ ld hl,wd79b
+ set 7,[hl]
+.notCinnabarGym
+ ld hl,wd72e
+ set 5,[hl]
+ ld a,[W_CURMAP]
+ cp a,OAKS_LAB
+ jp z,.noFaintCheck ; no blacking out if the player lost to the rival in Oak's lab
+ callab AnyPartyAlive
+ ld a,d
+ and a
+ jr z,.allPokemonFainted
+.noFaintCheck
+ ld c,$0a
+ call DelayFrames
+ jp EnterMap
+;.allPokemonFainted
+; ld a,$ff
+; ld [W_ISINBATTLE],a
+; call RunMapScript
+; jp HandleBlackOut
+
+StepCountCheck:: ; 0457 (0:0457)
+ ld a,[wd730]
+ bit 7,a
+ jr nz,.doneStepCounting ; if button presses are being simulated, don't count steps
+; step counting
+ ld hl,wStepCounter
+ dec [hl]
+ ld a,[wd72c]
+ bit 0,a
+ jr z,.doneStepCounting
+ ld hl,wNumberOfNoRandomBattleStepsLeft
+ dec [hl]
+ jr nz,.doneStepCounting
+ ld hl,wd72c
+ res 0,[hl] ; indicate that the player has stepped thrice since the last battle
+.doneStepCounting
+ ret
+
+; function to determine if there will be a battle and execute it (either a trainer battle or wild battle)
+; sets carry if a battle occurred and unsets carry if not
+NewBattle:: ; 0480 (0:0480)
+ ld a,[wd72d]
+ bit 4,a
+ jr nz,.noBattle
+ call IsPlayerCharacterBeingControlledByGame
+ jr nz,.noBattle ; no battle if the player character is under the game's control
+ ld a,[wd72e]
+ bit 4,a
+ jr nz,.noBattle
+ ld b, BANK(InitBattle)
+ ld hl, InitBattle ; 3d:5ff2
+ jp Bankswitch
+.noBattle
+ and a
+ ret
+
+DoBikeSpeedup:: ; 049d (0:049d)
+ ld a,[wWalkBikeSurfState]
+ dec a ; riding a bike?
+ ret nz
+ ld a,[wd736]
+ bit 6,a
+ ret nz
+ ld a,[wNPCMovementScriptPointerTableNum]
+ and a
+ ret nz
+ ld a,[W_CURMAP]
+ cp ROUTE_17 ; cycling road
+ jr nz,.goFaster
+ ld a,[hJoyHeld]
+ and a,D_UP | D_LEFT | D_RIGHT
+ ret nz
+.goFaster
+ call AdvancePlayerSprite
+ ret
+
+; check if the player has stepped onto a warp after having not collided
+CheckWarpsNoCollision:: ; 04bd (0:04bd)
+ ld a,[wNumberOfWarps]
+ and a
+ jp z,CheckMapConnections
+ ld b,0
+ ld a,[wNumberOfWarps]
+ ld c,a
+ ld a,[W_YCOORD]
+ ld d,a
+ ld a,[W_XCOORD]
+ ld e,a
+ ld hl,wWarpEntries
+CheckWarpsNoCollisionLoop:: ; 04d5 (0:04d5)
+ ld a,[hli] ; check if the warp's Y position matches
+ cp d
+ jr nz,CheckWarpsNoCollisionRetry1
+ ld a,[hli] ; check if the warp's X position matches
+ cp e
+ jr nz,CheckWarpsNoCollisionRetry2
+; if a match was found
+ push hl
+ push bc
+ ld hl,wd736
+ set 2,[hl] ; standing on warp flag
+ callba IsPlayerStandingOnDoorTileOrWarpTile
+ pop bc
+ pop hl
+ jr c,WarpFound1 ; jump if standing on door or warp
+ push hl
+ push bc
+ call ExtraWarpCheck
+ pop bc
+ pop hl
+ jr nc,CheckWarpsNoCollisionRetry2
+; if the extra check passed
+ ld a,[W_FLAGS_D733]
+ bit 2,a
+ jr nz,WarpFound1
+ push de
+ push bc
+ call Joypad
+ pop bc
+ pop de
+ ld a,[hJoyHeld]
+ and a,D_DOWN | D_UP | D_LEFT | D_RIGHT
+ jr z,CheckWarpsNoCollisionRetry2 ; if directional buttons aren't being pressed, do not pass through the warp
+ jr WarpFound1
+
+CheckWarpsNoCollisionRetry1:: ; 050f (0:050f)
+ inc hl
+CheckWarpsNoCollisionRetry2:: ; 0510 (0:0510)
+ inc hl
+ inc hl
+ContinueCheckWarpsNoCollisionLoop:: ; 0512 (0:0512)
+ inc b ; increment warp number
+ dec c ; decrement number of warps
+ jp nz,CheckWarpsNoCollisionLoop
+ jp CheckMapConnections
+
+; check if the player has stepped onto a warp after having collided
+CheckWarpsCollision:: ; 051a (0:051a)
+ ld a,[wNumberOfWarps]
+ ld c,a
+ ld hl,wWarpEntries
+.loop
+ ld a,[hli] ; Y coordinate of warp
+ ld b,a
+ ld a,[W_YCOORD]
+ cp b
+ jr nz,.retry1
+ ld a,[hli] ; X coordinate of warp
+ ld b,a
+ ld a,[W_XCOORD]
+ cp b
+ jr nz,.retry2
+ ld a,[hli]
+ ld [wDestinationWarpID],a
+ ld a,[hl]
+ ld [$ff8b],a ; save target map
+ jr WarpFound2
+.retry1
+ inc hl
+.retry2
+ inc hl
+ inc hl
+ dec c
+ jr nz,.loop
+ jp OverworldLoop
+
+WarpFound1:: ; 0543 (0:0543)
+ ld a,[hli]
+ ld [wDestinationWarpID],a
+ ld a,[hli]
+ ld [$ff8b],a ; save target map
+
+WarpFound2:: ; 054a (0:054a)
+ ld a,[wNumberOfWarps]
+ sub c
+ ld [wd73b],a ; save ID of used warp
+ ld a,[W_CURMAP]
+ ld [wd73c],a
+ call CheckIfInOutsideMap
+ jr nz,.indoorMaps
+; this is for handling "outside" maps that can't have the 0xFF destination map
+ ld a,[W_CURMAP]
+ ld [wLastMap],a
+ ld a,[W_CURMAPWIDTH]
+ ld [wd366],a
+ ld a,[$ff8b] ; destination map number
+ ld [W_CURMAP],a ; change current map to destination map
+ cp a,ROCK_TUNNEL_1
+ jr nz,.notRockTunnel
+ ld a,$06
+ ld [wMapPalOffset],a
+ call GBFadeOutToBlack
+.notRockTunnel
+ callab Func_fc5fa ; 3f:45fa
+ call PlayMapChangeSound
+ jr .done
+; for maps that can have the 0xFF destination map, which means to return to the outside map; not all these maps are necessarily indoors, though
+.indoorMaps
+ ld a,[$ff8b] ; destination map
+ cp a,$ff
+ jr z,.goBackOutside
+; if not going back to the previous map
+ ld [W_CURMAP],a ; current map number
+ callba IsPlayerStandingOnWarpPadOrHole
+ ld a,[wcd5b]
+ dec a ; is the player on a warp pad?
+ jr nz,.notWarpPad
+; if the player is on a warp pad
+ call LeaveMapAnim
+ ld hl,wd732
+ set 3,[hl]
+ jr .skipMapChangeSound
+.notWarpPad
+ call PlayMapChangeSound
+.skipMapChangeSound
+ ld hl,wd736
+ res 0,[hl]
+ res 1,[hl]
+ callab Func_fc65b ; 3f:465b
+ jr .done
+.goBackOutside
+ callab Func_fc69a ; 3f:469a
+ ld a,[wLastMap]
+ ld [W_CURMAP],a
+ call PlayMapChangeSound
+ xor a
+ ld [wMapPalOffset],a
+.done
+ ld hl,wd736
+ set 0,[hl] ; have the player's sprite step out from the door (if there is one)
+ call IgnoreInputForHalfSecond
+ jp EnterMap
+
+; if no matching warp was found
+CheckMapConnections:: ; 05db (0:05db)
+.checkWestMap
+ ld a,[W_XCOORD]
+ cp a,$ff
+ jr nz,.checkEastMap
+ ld a,[W_MAPCONN3PTR]
+ ld [W_CURMAP],a
+ ld a,[wd38f] ; new X coordinate upon entering west map
+ ld [W_XCOORD],a
+ ld a,[W_YCOORD]
+ ld c,a
+ ld a,[wd38e] ; Y adjustment upon entering west map
+ add c
+ ld c,a
+ ld [W_YCOORD],a
+ ld a,[wd390] ; pointer to upper left corner of map without adjustment for Y position
+ ld l,a
+ ld a,[wd391]
+ ld h,a
+ srl c
+ jr z,.savePointer1
+.pointerAdjustmentLoop1
+ ld a,[wd38d] ; width of connected map
+ add a,$06
+ ld e,a
+ ld d,$00
+ ld b,$00
+ add hl,de
+ dec c
+ jr nz,.pointerAdjustmentLoop1
+.savePointer1
+ ld a,l
+ ld [wCurrentTileBlockMapViewPointer],a ; pointer to upper left corner of current tile block map section
+ ld a,h
+ ld [wCurrentTileBlockMapViewPointer + 1],a
+ jp .loadNewMap
+.checkEastMap
+ ld b,a
+ ld a,[wd525] ; map width
+ cp b
+ jr nz,.checkNorthMap
+ ld a,[W_MAPCONN4PTR]
+ ld [W_CURMAP],a
+ ld a,[wd39a] ; new X coordinate upon entering east map
+ ld [W_XCOORD],a
+ ld a,[W_YCOORD]
+ ld c,a
+ ld a,[wd399] ; Y adjustment upon entering east map
+ add c
+ ld c,a
+ ld [W_YCOORD],a
+ ld a,[wd39b] ; pointer to upper left corner of map without adjustment for Y position
+ ld l,a
+ ld a,[wd39c]
+ ld h,a
+ srl c
+ jr z,.savePointer2
+.pointerAdjustmentLoop2
+ ld a,[wd398]
+ add a,$06
+ ld e,a
+ ld d,$00
+ ld b,$00
+ add hl,de
+ dec c
+ jr nz,.pointerAdjustmentLoop2
+.savePointer2
+ ld a,l
+ ld [wCurrentTileBlockMapViewPointer],a ; pointer to upper left corner of current tile block map section
+ ld a,h
+ ld [wCurrentTileBlockMapViewPointer + 1],a
+ jp .loadNewMap
+.checkNorthMap
+ ld a,[W_YCOORD]
+ cp a,$ff
+ jr nz,.checkSouthMap
+ ld a,[W_MAPCONN1PTR]
+ ld [W_CURMAP],a
+ ld a,[wd378] ; new Y coordinate upon entering north map
+ ld [W_YCOORD],a
+ ld a,[W_XCOORD]
+ ld c,a
+ ld a,[wd379] ; X adjustment upon entering north map
+ add c
+ ld c,a
+ ld [W_XCOORD],a
+ ld a,[wd37a] ; pointer to upper left corner of map without adjustment for X position
+ ld l,a
+ ld a,[wd37b]
+ ld h,a
+ ld b,$00
+ srl c
+ add hl,bc
+ ld a,l
+ ld [wCurrentTileBlockMapViewPointer],a ; pointer to upper left corner of current tile block map section
+ ld a,h
+ ld [wCurrentTileBlockMapViewPointer + 1],a
+ jp .loadNewMap
+.checkSouthMap
+ ld b,a
+ ld a,[wd524]
+ cp b
+ jr nz,.didNotEnterConnectedMap
+ ld a,[W_MAPCONN2PTR]
+ ld [W_CURMAP],a
+ ld a,[wd383] ; new Y coordinate upon entering south map
+ ld [W_YCOORD],a
+ ld a,[W_XCOORD]
+ ld c,a
+ ld a,[wd384] ; X adjustment upon entering south map
+ add c
+ ld c,a
+ ld [W_XCOORD],a
+ ld a,[wd385] ; pointer to upper left corner of map without adjustment for X position
+ ld l,a
+ ld a,[wd386]
+ ld h,a
+ ld b,$00
+ srl c
+ add hl,bc
+ ld a,l
+ ld [wCurrentTileBlockMapViewPointer],a ; pointer to upper left corner of current tile block map section
+ ld a,h
+ ld [wCurrentTileBlockMapViewPointer + 1],a
+.loadNewMap ; 06ce (0:06ce)
+; load the connected map that was entered
+ ld hl,[wd430]
+ set 4,[hl]
+ ld a,$2
+ ld [wd431],a
+ call LoadMapHeader ; 0dab (0:0dab)
+ call Func_2312 ; music
+ ld b,$09
+ call GoPAL_SET
+; Since the sprite set shouldn't change, this will just update VRAM slots at
+; $C2XE without loading any tile patterns.
+ call InitMapSprites
+ call LoadTileBlockMap
+ jp OverworldLoopLessDelay
+.didNotEnterConnectedMap
+ jp OverworldLoop
+
+; function to play a sound when changing maps
+PlayMapChangeSound:: ; 06ef (0:06ef)
+ ld a,[W_CURMAPTILESET]
+ cp FACILITY
+ jr z,.didNotGoThroughDoor
+ cp CEMETERY
+ jr z,.didNotGoThroughDoor
+ cp UNDERGROUND
+ jr nz,.didNotGoThroughDoor
+ aCoord 8, 8 ; upper left tile of the 4x4 square the player's sprite is standing on
+ cp a,$0b ; door tile in tileset 0
+ jr nz,.didNotGoThroughDoor
+ ld a,(SFX_02_57 - SFX_Headers_02) / 3
+ jr .playSound
+.didNotGoThroughDoor
+ ld a,(SFX_02_5c - SFX_Headers_02) / 3
+.playSound
+ call PlaySound
+ ld a,[wMapPalOffset]
+ and a
+ ret nz
+ jp GBFadeOutToBlack
+
+CheckIfInOutsideMap:: ; 0712 (0:0712)
+; If the player is in an outside map (a town or route), set the z flag
+ ld a, [W_CURMAPTILESET]
+ and a ; most towns/routes have tileset 0 (OVERWORLD)
+ ret z
+ cp PLATEAU ; Route 23 / Indigo Plateau
+ ret
+
+; this function is an extra check that sometimes has to pass in order to warp, beyond just standing on a warp
+; the "sometimes" qualification is necessary because of CheckWarpsNoCollision's behavior
+; depending on the map, either "function 1" or "function 2" is used for the check
+; "function 1" passes when the player is at the edge of the map and is facing towards the outside of the map
+; "function 2" passes when the the tile in front of the player is among a certain set
+; sets carry if the check passes, otherwise clears carry
+ExtraWarpCheck:: ; 071a (0:071a)
+ ld a, [W_CURMAP]
+ cp SS_ANNE_3
+ jr z, .useFunction1
+ cp ROCKET_HIDEOUT_1
+ jr z, .useFunction2
+ cp ROCKET_HIDEOUT_2
+ jr z, .useFunction2
+ cp ROCKET_HIDEOUT_4
+ jr z, .useFunction2
+ cp ROCK_TUNNEL_1
+ jr z, .useFunction2
+ ld a, [W_CURMAPTILESET]
+ and a ; outside tileset (OVERWORLD)
+ jr z, .useFunction2
+ cp SHIP ; S.S. Anne tileset
+ jr z, .useFunction2
+ cp SHIP_PORT ; Vermilion Port tileset
+ jr z, .useFunction2
+ cp PLATEAU ; Indigo Plateau tileset
+ jr z, .useFunction2
+.useFunction1
+ ld hl, IsPlayerFacingEdgeOfMap
+ jr .doBankswitch
+.useFunction2
+ ld hl, IsWarpTileInFrontOfPlayer
+.doBankswitch
+ ld b, BANK(IsWarpTileInFrontOfPlayer)
+ jp Bankswitch
+
+MapEntryAfterBattle:: ; 0750 (0:0750)
+ callba IsPlayerStandingOnWarp ; for enabling warp testing after collisions
+ ld a,[wMapPalOffset]
+ and a
+ jp z,GBFadeInFromWhite
+ jp LoadGBPal
+
+HandleBlackOut:: ; 0762 (0:0762)
+; For when all the player's pokemon faint.
+; Does not print the "blacked out" message.
+
+ call GBFadeOutToBlack
+ ld a, $08
+ call StopMusic
+ ld hl, wd72e
+ res 5, [hl]
+ switchbank SpecialWarpIn ; also Bank(SpecialEnterMap)
+ callab ResetStatusAndHalveMoneyOnBlackout ; 3c:4274
+ call SpecialWarpIn
+ call Func_2312
+ jp SpecialEnterMap
+
+StopMusic:: ; 0788 (0:0788)
+ ld [wMusicHeaderPointer], a
+ call StopAllMusic
+.wait
+ ld a, [wMusicHeaderPointer]
+ and a
+ jr nz, .wait
+ jp StopAllSounds
+
+HandleFlyWarpOrDungeonWarp:: ; 0794 (0:0794)
+ call UpdateSprites
+ call Delay3
+ xor a
+ ld [wBattleResult], a
+ ld [wWalkBikeSurfState], a
+ ld [W_ISINBATTLE], a
+ ld [wMapPalOffset], a
+ ld hl, wd732
+ set 2, [hl] ; fly warp or dungeon warp
+ res 5, [hl] ; forced to ride bike
+ call LeaveMapAnim
+ call LoadPlayerSpriteGraphics
+ callsb SpecialWarpIn
+ jp SpecialEnterMap
+
+LeaveMapAnim:: ; 07bc (0:07bc)
+ ld b, BANK(_LeaveMapAnim)
+ ld hl, _LeaveMapAnim
+ jp Bankswitch
+
+Func_07c4:: ; 07c4 (0:07c4)
+ ld a, [wWalkBikeSurfState]
+ and a
+ ret z
+ xor a
+ ld [wWalkBikeSurfState],a
+ ld hl,wd732
+ bit 4,[hl]
+ ret z
+ call PlayDefaultMusic
+ ret
+
+LoadPlayerSpriteGraphics:: ; 07d7 (0:07d7)
+; Load sprite graphics based on whether the player is standing, biking, or surfing.
+
+ ; 0: standing
+ ; 1: biking
+ ; 2: surfing
+
+ ld a, [wWalkBikeSurfState]
+ dec a
+ jr z, .ridingBike
+
+ ld a, [hTilesetType]
+ and a
+ jr nz, .determineGraphics
+ jr .startWalking
+
+.ridingBike
+ ; If the bike can't be used,
+ ; start walking instead.
+ call IsBikeRidingAllowed
+ jr c, .determineGraphics
+
+.startWalking
+ xor a
+ ld [wWalkBikeSurfState], a
+ ld [wWalkBikeSurfStateCopy], a
+ jp LoadWalkingPlayerSpriteGraphics
+
+.determineGraphics
+ ld a, [wWalkBikeSurfState]
+ and a
+ jp z, LoadWalkingPlayerSpriteGraphics
+ dec a
+ jp z, LoadBikePlayerSpriteGraphics
+ dec a
+ jp z, LoadSurfingPlayerSpriteGraphics
+ jp LoadWalkingPlayerSpriteGraphics
+
+IsBikeRidingAllowed:: ; 0805 (0:0805)
+; The bike can be used on Route 23 and Indigo Plateau,
+; or maps with tilesets in BikeRidingTilesets.
+; Return carry if biking is allowed.
+
+ ld a, [W_CURMAP]
+ cp ROUTE_23
+ jr z, .allowed
+ cp INDIGO_PLATEAU
+ jr z, .allowed
+
+ ld a, [W_CURMAPTILESET]
+ ld b, a
+ ld hl, BikeRidingTilesets
+.loop
+ ld a, [hli]
+ cp b
+ jr z, .allowed
+ inc a
+ jr nz, .loop
+ and a
+ ret
+
+.allowed
+ scf
+ ret
+
+INCLUDE "data/bike_riding_tilesets.asm"
+
+; load the tile pattern data of the current tileset into VRAM
+LoadTilesetTilePatternData:: ; 0828 (0:0828)
+ ld a,[W_TILESETGFXPTR]
+ ld l,a
+ ld a,[W_TILESETGFXPTR + 1]
+ ld h,a
+ ld de,vTileset
+ ld bc,$600
+ ld a,[W_TILESETBANK]
+ jp FarCopyData2
+
+; this loads the current maps complete tile map (which references blocks, not individual tiles) to C6E8
+; it can also load partial tile maps of connected maps into a border of length 3 around the current map
+LoadTileBlockMap:: ; 083c (0:083c)
+; fill C6E8-CBFB with the background tile
+ ld hl,wOverworldMap
+ ld bc,$0514
+ ld a,[wd3ad] ; background tile number
+ call FillMemory
+; load tile map of current map (made of tile block IDs)
+; a 3-byte border at the edges of the map is kept so that there is space for map connections
+ ld hl,wOverworldMap
+ ld a,[W_CURMAPWIDTH]
+ ld [$ff8c],a
+ add a,$06 ; border (east and west)
+ ld [$ff8b],a ; map width + border
+ ld b,$00
+ ld c,a
+; make space for north border (next 3 lines)
+ add hl,bc
+ add hl,bc
+ add hl,bc
+ ld c,$03
+ add hl,bc ; this puts us past the (west) border
+ ld a,[W_MAPDATAPTR] ; tile map pointer
+ ld e,a
+ ld a,[W_MAPDATAPTR + 1]
+ ld d,a ; de = tile map pointer
+ ld a,[W_CURMAPHEIGHT]
+ ld b,a
+.rowLoop ; copy one row each iteration
+ push hl
+ ld a,[$ff8c] ; map width (without border)
+ ld c,a
+.rowInnerLoop
+ ld a,[de]
+ inc de
+ ld [hli],a
+ dec c
+ jr nz,.rowInnerLoop
+; add the map width plus the border to the base address of the current row to get the next row's address
+ pop hl
+ ld a,[$ff8b] ; map width + border
+ add l
+ ld l,a
+ jr nc,.noCarry
+ inc h
+.noCarry
+ dec b
+ jr nz,.rowLoop
+.northConnection
+ ld a,[W_MAPCONN1PTR]
+ cp a,$ff
+ jr z,.southConnection
+ call SwitchToMapRomBank
+ ld a,[wd372]
+ ld l,a
+ ld a,[wd373]
+ ld h,a
+ ld a,[wd374]
+ ld e,a
+ ld a,[wd375]
+ ld d,a
+ ld a,[wd376]
+ ld [$ff8b],a
+ ld a,[wd377]
+ ld [$ff8c],a
+ call LoadNorthSouthConnectionsTileMap
+.southConnection
+ ld a,[W_MAPCONN2PTR]
+ cp a,$ff
+ jr z,.westConnection
+ call SwitchToMapRomBank
+ ld a,[wd37d]
+ ld l,a
+ ld a,[wd37e]
+ ld h,a
+ ld a,[wd37f]
+ ld e,a
+ ld a,[wd380]
+ ld d,a
+ ld a,[wd381]
+ ld [$ff8b],a
+ ld a,[wd382]
+ ld [$ff8c],a
+ call LoadNorthSouthConnectionsTileMap
+.westConnection
+ ld a,[W_MAPCONN3PTR]
+ cp a,$ff
+ jr z,.eastConnection
+ call SwitchToMapRomBank
+ ld a,[wd388]
+ ld l,a
+ ld a,[wd389]
+ ld h,a
+ ld a,[wd38a]
+ ld e,a
+ ld a,[wd38b]
+ ld d,a
+ ld a,[wd38c]
+ ld b,a
+ ld a,[wd38d]
+ ld [$ff8b],a
+ call LoadEastWestConnectionsTileMap
+.eastConnection
+ ld a,[W_MAPCONN4PTR]
+ cp a,$ff
+ jr z,.done
+ call SwitchToMapRomBank
+ ld a,[wd393]
+ ld l,a
+ ld a,[wd394]
+ ld h,a
+ ld a,[wd395]
+ ld e,a
+ ld a,[wd396]
+ ld d,a
+ ld a,[wd397]
+ ld b,a
+ ld a,[wd398]
+ ld [$ff8b],a
+ call LoadEastWestConnectionsTileMap
+.done
+ ret
+
+LoadNorthSouthConnectionsTileMap:: ; 0919 (0:0919)
+ ld c,$03
+.loop
+ push de
+ push hl
+ ld a,[$ff8b] ; width of connection
+ ld b,a
+.innerLoop
+ ld a,[hli]
+ ld [de],a
+ inc de
+ dec b
+ jr nz,.innerLoop
+ pop hl
+ pop de
+ ld a,[$ff8c] ; width of connected map
+ add l
+ ld l,a
+ jr nc,.noCarry1
+ inc h
+.noCarry1
+ ld a,[W_CURMAPWIDTH]
+ add a,$06
+ add e
+ ld e,a
+ jr nc,.noCarry2
+ inc d
+.noCarry2
+ dec c
+ jr nz,.loop
+ ret
+
+LoadEastWestConnectionsTileMap:: ; 093d (0:093d)
+ push hl
+ push de
+ ld c,$03
+.innerLoop
+ ld a,[hli]
+ ld [de],a
+ inc de
+ dec c
+ jr nz,.innerLoop
+ pop de
+ pop hl
+ ld a,[$ff8b] ; width of connected map
+ add l
+ ld l,a
+ jr nc,.noCarry1
+ inc h
+.noCarry1
+ ld a,[W_CURMAPWIDTH]
+ add a,$06
+ add e
+ ld e,a
+ jr nc,.noCarry2
+ inc d
+.noCarry2
+ dec b
+ jr nz,LoadEastWestConnectionsTileMap
+ ret
+
+; function to check if there is a sign or sprite in front of the player
+; if so, carry is set. otherwise, carry is cleared
+IsSpriteOrSignInFrontOfPlayer:: ; 095e (0:095e)
+ xor a
+ ld [hSpriteIndexOrTextID],a
+ ld a,[wd4b0] ; number of signs in the map
+ and a
+ jr z,.extendRangeOverCounter
+; if there are signs
+ predef GetTileAndCoordsInFrontOfPlayer ; get the coordinates in front of the player in de
+ call SignLoop
+ ret c
+.extendRangeOverCounter
+; check if the player is front of a counter in a pokemon center, pokemart, etc. and if so, extend the range at which he can talk to the NPC
+ predef GetTileAndCoordsInFrontOfPlayer ; get the tile in front of the player in c
+ ld hl,W_TILESETTALKINGOVERTILES ; list of tiles that extend talking range (counter tiles)
+ ld b,$03
+ ld d,$20 ; talking range in pixels (long range)
+.counterTilesLoop
+ ld a,[hli]
+ cp c
+ jr z,IsSpriteInFrontOfPlayer2 ; jumps if the tile in front of the player is a counter tile
+ dec b
+ jr nz,.counterTilesLoop
+
+; sets carry flag if a sprite is in front of the player, resets if not
+IsSpriteInFrontOfPlayer:: ; 0983 (0:0983)
+ ld d,$10 ; talking range in pixels (normal range)
+IsSpriteInFrontOfPlayer2:: ; 0985 (0:0985)
+ ld bc,$3c40 ; Y and X position of player sprite
+ ld a,[wSpriteStateData1 + 9] ; direction the player is facing
+.checkIfPlayerFacingUp
+ cp a,$04
+ jr nz,.checkIfPlayerFacingDown
+; facing up
+ ld a,b
+ sub d
+ ld b,a
+ ld a,$08
+ jr .doneCheckingDirection
+.checkIfPlayerFacingDown
+ cp a,$00
+ jr nz,.checkIfPlayerFacingRight
+; facing down
+ ld a,b
+ add d
+ ld b,a
+ ld a,$04
+ jr .doneCheckingDirection
+.checkIfPlayerFacingRight
+ cp a,$0c
+ jr nz,.playerFacingLeft
+; facing right
+ ld a,c
+ add d
+ ld c,a
+ ld a,$01
+ jr .doneCheckingDirection
+.playerFacingLeft
+; facing left
+ ld a,c
+ sub d
+ ld c,a
+ ld a,$02
+.doneCheckingDirection
+ ld [wd52a],a
+ ld hl,wSpriteStateData1 + $10
+; yellow does not have the "if sprites are existant" check
+ ld e,$01
+ ld d,$f
+.spriteLoop
+ push hl
+ ld a,[hli] ; image (0 if no sprite)
+ and a
+ jr z,.nextSprite
+ inc l
+ ld a,[hli] ; sprite visibility
+ inc a
+ jr z,.nextSprite
+ inc l
+ ld a,[hli] ; Y location
+ cp b
+ jr nz,.nextSprite
+ inc l
+ ld a,[hl] ; X location
+ cp c
+ jr z,.foundSpriteInFrontOfPlayer
+.nextSprite
+ pop hl
+ ld a,l
+ add a,$10
+ ld l,a
+ inc e
+ dec d
+ jr nz,.spriteLoop
+ xor a
+ ret
+.foundSpriteInFrontOfPlayer
+ pop hl
+ ld a,l
+ and a,$f0
+ inc a
+ ld l,a
+ set 7,[hl]
+ ld a,e
+ ld [hSpriteIndexOrTextID],a
+ ld a,[hSpriteIndexOrTextID] ; possible useless read because a already has the value of the read address
+ cp a,$f
+ jr nz,.dontwritetowd436
+ ld a,$FF
+ ld [wd436],a
+.dontwritetowd436
+ scf
+ ret
+
+SignLoop:: ; 09f2 (0:09f2)
+; search if a player is facing a sign
+ ld hl,wd4b1 ; start of sign coordinates
+ ld a,[wd4b0] ; number of signs in the map
+ ld b,a
+ ld c,$00
+.signLoop
+ inc c
+ ld a,[hli] ; sign Y
+ cp d
+ jr z,.yCoordMatched
+ inc hl
+ jr .retry
+.yCoordMatched
+ ld a,[hli] ; sign X
+ cp e
+ jr nz,.retry
+.xCoordMatched
+; found sign
+ push hl
+ push bc
+ ld hl,wd4d1 ; start of sign text ID's
+ ld b,$00
+ dec c
+ add hl,bc
+ ld a,[hl]
+ ld [hSpriteIndexOrTextID],a ; store sign text ID
+ pop bc
+ pop hl
+ scf
+ ret
+.retry
+ dec b
+ jr nz,.signLoop
+ xor a
+ ret
+
+; 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:: ; 0a1c (0:0a1c)
+ ld a,[wd736]
+ bit 6,a ; is the player jumping?
+ jr nz,.noCollision
+; if not jumping a ledge
+ ld a,[wSimulatedJoypadStatesIndex]
+ and a
+ jr nz,.noCollision ; no collisions when the player's movements are being controlled by the game
+ ld a,[wd52a] ; the direction that the player is trying to go in
+ ld d,a
+ ld a,[wSpriteStateData1 + 12] ; the player sprite's collision data (bit field) (set in the sprite movement code)
+ and d ; check if a sprite is in the direction the player is trying to go
+ nop ; ??? why is this in the code
+ jr nz,.collision
+ xor a
+ ld [hSpriteIndexOrTextID],a
+ call IsSpriteInFrontOfPlayer ; check for sprite collisions again? when does the above check fail to detect a sprite collision?
+ jr nc,.asm_0a5c
+ res 7,[hl]
+ ld a,[hSpriteIndexOrTextID]
+ and a ; was there a sprite collision?
+ jr z,.asm_0a5c
+; if no sprite collision
+ cp $f
+ jr nz,.collision
+ call CheckForJumpingAndTilePairCollisions
+ jr nz,.collision
+ ld a,[hJoyHeld]
+ and $2
+ jr nz,.asm_0a5c
+ ld hl,wd435
+ ld a,[hl]
+ and a
+ jr z,.asm_0a5c
+ dec [hl]
+ jr nz,.collision
+.asm_0a5c
+ ld hl,TilePairCollisionsLand
+ call CheckForJumpingAndTilePairCollisions
+ jr c,.collision
+ call CheckTilePassable
+ jr nc,.noCollision
+.collision
+ ld a,[wc02a]
+ cp a,(SFX_02_5b - SFX_Headers_02) / 3 ; check if collision sound is already playing
+ jr z,.setCarry
+ ld a,(SFX_02_5b - SFX_Headers_02) / 3
+ call PlaySound ; play collision sound (if it's not already playing)
+.setCarry
+ scf
+ ret
+.noCollision
+ and a
+ ret
+
+; function that checks if the tile in front of the player is passable
+; clears carry if it is, sets carry if not
+CheckTilePassable:: ; 0a79 (0:0a79)
+ predef GetTileAndCoordsInFrontOfPlayer ; get tile in front of player
+ ld a,[wTileInFrontOfPlayer] ; tile in front of player
+ ld c,a
+ call IsTilePassable
+ ret
+
+; check if the player is going to jump down a small ledge
+; and check for collisions that only occur between certain pairs of tiles
+; Input: hl - address of directional collision data
+; sets carry if there is a collision and unsets carry if not
+CheckForJumpingAndTilePairCollisions:: ; 0a86 (0:0a86)
+ push hl
+ predef GetTileAndCoordsInFrontOfPlayer ; get the tile in front of the player
+ push de
+ push bc
+ callba HandleLedges ; check if the player is trying to jump a ledge
+ pop bc
+ pop de
+ pop hl
+ and a
+ ld a,[wd736]
+ bit 6,a ; is the player jumping?
+ ret nz
+; if not jumping
+
+CheckForTilePairCollisions2:: ; 0aa0 (0:0aa0)
+ aCoord 8, 9 ; tile the player is on
+ ld [wcf0e],a
+
+CheckForTilePairCollisions:: ; 0aa6 (0:0aa6)
+ ld a,[wTileInFrontOfPlayer]
+ ld c,a
+.tilePairCollisionLoop
+ ld a,[W_CURMAPTILESET] ; tileset number
+ ld b,a
+ ld a,[hli]
+ cp a,$ff
+ jr z,.noMatch
+ cp b
+ jr z,.tilesetMatches
+ inc hl
+.retry
+ inc hl
+ jr .tilePairCollisionLoop
+.tilesetMatches
+ ld a,[wcf0e] ; tile the player is on
+ ld b,a
+ ld a,[hl]
+ cp b
+ jr z,.currentTileMatchesFirstInPair
+ inc hl
+ ld a,[hl]
+ cp b
+ jr z,.currentTileMatchesSecondInPair
+ jr .retry
+.currentTileMatchesFirstInPair
+ inc hl
+ ld a,[hl]
+ cp c
+ jr z,.foundMatch
+ jr .tilePairCollisionLoop
+.currentTileMatchesSecondInPair
+ dec hl
+ ld a,[hli]
+ cp c
+ inc hl
+ jr nz,.tilePairCollisionLoop
+.foundMatch
+ scf
+ ret
+.noMatch
+ and a
+ ret
+
+; FORMAT: tileset number, tile 1, tile 2
+; terminated by 0xFF
+; these entries indicate that the player may not cross between tile 1 and tile 2
+; it's mainly used to simulate differences in elevation
+
+TilePairCollisionsLand:: ; 0ada (0:0ada)
+ db CAVERN, $20, $05
+ db CAVERN, $41, $05
+ db FOREST, $30, $2E
+ db CAVERN, $2A, $05
+ db CAVERN, $05, $21
+ db FOREST, $52, $2E
+ db FOREST, $55, $2E
+ db FOREST, $56, $2E
+ db FOREST, $20, $2E
+ db FOREST, $5E, $2E
+ db FOREST, $5F, $2E
+ db $FF
+
+TilePairCollisionsWater:: ; 0afc (0:0afc)
+ db FOREST, $14, $2E
+ db FOREST, $48, $2E
+ db CAVERN, $14, $05
+ db $FF
+
+; this builds a tile map from the tile block map based on the current X/Y coordinates of the player's character
+LoadCurrentMapView:: ; 0b06 (0:0b06)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,[W_TILESETBANK] ; tile data ROM bank
+ call BankswitchCommon ; switch to ROM bank that contains tile data
+ ld a,[wCurrentTileBlockMapViewPointer] ; address of upper left corner of current map view
+ ld e,a
+ ld a,[wCurrentTileBlockMapViewPointer + 1]
+ ld d,a
+ ld hl,wTileMapBackup
+ ld b,$05
+.rowLoop ; each loop iteration fills in one row of tile blocks
+ push hl
+ push de
+ ld c,$06
+.rowInnerLoop ; loop to draw each tile block of the current row
+ push bc
+ push de
+ push hl
+ ld a,[de]
+ ld c,a ; tile block number
+ call DrawTileBlock
+ pop hl
+ pop de
+ pop bc
+ inc hl
+ inc hl
+ inc hl
+ inc hl
+ inc de
+ dec c
+ jr nz,.rowInnerLoop
+; update tile block map pointer to next row's address
+ pop de
+ ld a,[W_CURMAPWIDTH]
+ add a,$06
+ add e
+ ld e,a
+ jr nc,.noCarry
+ inc d
+.noCarry
+; update tile map pointer to next row's address
+ pop hl
+ ld a,$60
+ add l
+ ld l,a
+ jr nc,.noCarry2
+ inc h
+.noCarry2
+ dec b
+ jr nz,.rowLoop
+ ld hl,wTileMapBackup
+ ld bc,$0000
+.adjustForYCoordWithinTileBlock
+ ld a,[W_YBLOCKCOORD]
+ and a
+ jr z,.adjustForXCoordWithinTileBlock
+ ld bc,$0030
+ add hl,bc
+.adjustForXCoordWithinTileBlock
+ ld a,[W_XBLOCKCOORD]
+ and a
+ jr z,.copyToVisibleAreaBuffer
+ ld bc,$0002
+ add hl,bc
+.copyToVisibleAreaBuffer
+ ld de,wTileMap ; base address for the tiles that are directly transfered to VRAM during V-blank
+ ld b,$12
+.rowLoop2
+ ld c,$14
+.rowInnerLoop2
+ ld a,[hli]
+ ld [de],a
+ inc de
+ dec c
+ jr nz,.rowInnerLoop2
+ ld a,$04
+ add l
+ ld l,a
+ jr nc,.noCarry3
+ inc h
+.noCarry3
+ dec b
+ jr nz,.rowLoop2
+ pop af
+ call BankswitchCommon ; restore previous ROM bank
+ ret
+
+AdvancePlayerSprite:: ; 0b7f (0:0b7f)
+ ld a,[wUpdateSpritesEnabled]
+ push af
+ ld a,$FF
+ ld [wUpdateSpritesEnabled],a
+ ld hl, _AdvancePlayerSprite ; 3c:410c
+ ld b, BANK(_AdvancePlayerSprite)
+ call Bankswitch
+ pop af
+ ld [wUpdateSpritesEnabled],a
+ ret
+
+; the following 6 functions are used to tell the V-blank handler to redraw
+; the portion of the map that was newly exposed due to the player's movement
+
+ScheduleNorthRowRedraw:: ; 0b95 (0:0b95)
+ hlCoord 0, 0
+ call CopyToScreenEdgeTiles
+ ld a,[wMapViewVRAMPointer]
+ ld [H_SCREENEDGEREDRAWADDR],a
+ ld a,[wMapViewVRAMPointer + 1]
+ ld [H_SCREENEDGEREDRAWADDR + 1],a
+ ld a,REDRAWROW
+ ld [H_SCREENEDGEREDRAW],a
+ ret
+
+CopyToScreenEdgeTiles:: ; 0baa (0:0baa)
+ ld de,wScreenEdgeTiles
+ ld c,2 * 20
+.loop
+ ld a,[hli]
+ ld [de],a
+ inc de
+ dec c
+ jr nz,.loop
+ ret
+
+ScheduleSouthRowRedraw:: ; 0bb6 (0:0bb6)
+ hlCoord 0, 16
+ call CopyToScreenEdgeTiles
+ ld a,[wMapViewVRAMPointer]
+ ld l,a
+ ld a,[wMapViewVRAMPointer + 1]
+ ld h,a
+ ld bc,$0200
+ add hl,bc
+ ld a,h
+ and a,$03
+ or a,$98
+ ld [H_SCREENEDGEREDRAWADDR + 1],a
+ ld a,l
+ ld [H_SCREENEDGEREDRAWADDR],a
+ ld a,REDRAWROW
+ ld [H_SCREENEDGEREDRAW],a
+ ret
+
+ScheduleEastColumnRedraw:: ; 0bd6 (0:0bd7)
+ hlCoord 18, 0
+ call ScheduleColumnRedrawHelper
+ ld a,[wMapViewVRAMPointer]
+ ld c,a
+ and a,$e0
+ ld b,a
+ ld a,c
+ add a,18
+ and a,$1f
+ or b
+ ld [H_SCREENEDGEREDRAWADDR],a
+ ld a,[wMapViewVRAMPointer + 1]
+ ld [H_SCREENEDGEREDRAWADDR + 1],a
+ ld a,REDRAWCOL
+ ld [H_SCREENEDGEREDRAW],a
+ ret
+
+ScheduleColumnRedrawHelper:: ; 0bf6 (0:0bf6)
+ ld de,wScreenEdgeTiles
+ ld c,$12
+.loop
+ ld a,[hli]
+ ld [de],a
+ inc de
+ ld a,[hl]
+ ld [de],a
+ inc de
+ ld a,19
+ add l
+ ld l,a
+ jr nc,.noCarry
+ inc h
+.noCarry
+ dec c
+ jr nz,.loop
+ ret
+
+ScheduleWestColumnRedraw:: ; 0c0c (0:0c0c)
+ hlCoord 0, 0
+ call ScheduleColumnRedrawHelper
+ ld a,[wMapViewVRAMPointer]
+ ld [H_SCREENEDGEREDRAWADDR],a
+ ld a,[wMapViewVRAMPointer + 1]
+ ld [H_SCREENEDGEREDRAWADDR + 1],a
+ ld a,REDRAWCOL
+ ld [H_SCREENEDGEREDRAW],a
+ ret
+
+; function to write the tiles that make up a tile block to memory
+; Input: c = tile block ID, hl = destination address
+DrawTileBlock:: ; 0c21 (0:0c21)
+ push hl
+ ld a,[W_TILESETBLOCKSPTR] ; pointer to tiles
+ ld l,a
+ ld a,[W_TILESETBLOCKSPTR + 1]
+ ld h,a
+ ld a,c
+ swap a
+ ld b,a
+ and a,$f0
+ ld c,a
+ ld a,b
+ and a,$0f
+ ld b,a ; bc = tile block ID * 0x10
+ add hl,bc
+ ld d,h
+ ld e,l ; de = address of the tile block's tiles
+ pop hl
+ ld c,$04 ; 4 loop iterations
+.loop ; each loop iteration, write 4 tile numbers
+ push bc
+ ld a,[de]
+ ld [hli],a
+ inc de
+ ld a,[de]
+ ld [hli],a
+ inc de
+ ld a,[de]
+ ld [hli],a
+ inc de
+ ld a,[de]
+ ld [hl],a
+ inc de
+ ld bc,$0015
+ add hl,bc
+ pop bc
+ dec c
+ jr nz,.loop
+ ret
+
+; function to update joypad state and simulate button presses
+JoypadOverworld:: ; 0c51 (0:0c51)
+ xor a
+ ld [wSpriteStateData1 + 3],a
+ ld [wSpriteStateData1 + 5],a
+ call RunMapScript
+ call Joypad
+ call ForceBikeDown
+ call AreInputsSimulated
+ ret
+
+ForceBikeDown:: ; 0c65 (0:0c65)
+ ld a,[W_FLAGS_D733]
+ bit 3,a ; check if a trainer wants a challenge
+ ret nz
+ ld a,[W_CURMAP]
+ cp a,ROUTE_17 ; Cycling Road
+ ret nz
+ ld a,[hJoyHeld]
+ and a,D_DOWN | D_UP | D_LEFT | D_RIGHT | B_BUTTON | A_BUTTON
+ jr nz,.notForcedDownwards
+ ld a,D_DOWN
+ ld [hJoyHeld],a ; on the cycling road, if there isn't a trainer and the player isn't pressing buttons, simulate a down press
+ ret
+
+AreInputsSimulated:: ; 0c7b (0:0c7b)
+ ld a,[wd730]
+ bit 7,a
+ ret z
+; if simulating button presses
+ ld a,[hJoyHeld]
+ ld b,a
+ ld a,[wOverrideSimulatedJoypadStatesMask] ; bit mask for button presses that override simulated ones
+ and b
+ ret nz ; return if the simulated button presses are overridden
+ call GetSimulatedInput
+ jr nc,.doneSimulating
+ ld [hJoyHeld],a ; store simulated button press in joypad state
+ and a
+ ret nz
+ ld [hJoyPressed],a
+ ld [hJoyReleased],a
+ ret
+
+; if done simulating button presses
+.doneSimulating
+ xor a
+ ld [wWastedByteCD3A],a
+ ld [wSimulatedJoypadStatesIndex],a
+ ld [wSimulatedJoypadStatesEnd],a
+ ld [wJoyIgnore],a
+ ld [hJoyHeld],a
+ ld hl,wd736
+ ld a,[hl]
+ and a,$f8
+ ld [hl],a
+ ld hl,wd730
+ res 7,[hl]
+ ret
+
+GetSimulatedInput:: ; 0cb3 (0:0cb3)
+ ld hl,wSimulatedJoypadStatesIndex
+ dec [hl]
+ ld a,[hl]
+ cp a,$ff
+ jr z,.endofsimulatedinputs ; if the end of the simulated button presses has been reached
+ push de
+ ld e,a
+ ld d,$0
+ ld hl,wSimulatedJoypadStatesEnd
+ add hl,de
+ ld a,[hl]
+ pop de
+ scf
+ ret
+.endofsimulatedinputs
+ and a
+ ret
+
+
+; function to check the tile ahead to determine if the character should get on land or keep surfing
+; sets carry if there is a collision and clears carry otherwise
+; It seems that this function has a bug in it, but due to luck, it doesn't
+; show up. After detecting a sprite collision, it jumps to the code that
+; checks if the next tile is passable instead of just directly jumping to the
+; "collision detected" code. However, it doesn't store the next tile in c,
+; so the old value of c is used. 2429 is always called before this function,
+; and 2429 always sets c to 0xF0. There is no 0xF0 background tile, so it
+; is considered impassable and it is detected as a collision.
+CollisionCheckOnWater:: ; 0cca (0:0cca)
+ ld a,[wd730]
+ bit 7,a
+ jp nz,.noCollision ; return and clear carry if button presses are being simulated
+ ld a,[wd52a] ; the direction that the player is trying to go in
+ ld d,a
+ ld a,[wSpriteStateData1 + 12] ; the player sprite's collision data (bit field) (set in the sprite movement code)
+ and d ; check if a sprite is in the direction the player is trying to go
+ jr nz,.checkIfNextTileIsPassable ; bug?
+ ld hl,TilePairCollisionsWater
+ call CheckForJumpingAndTilePairCollisions
+ jr c,.collision
+ predef GetTileAndCoordsInFrontOfPlayer ; get tile in front of player (puts it in c and [wTileInFrontOfPlayer])
+ callab IsNextTileShoreOrWater ; 3:6808
+ jr c,.noCollsion
+ ld a,[wTileInFrontOfPlayer] ; tile in front of player
+ ld c,a
+ call IsTilePassable
+ jr nc,.stopSurfing
+.collision
+ ld a,[wc02a]
+ cp a,(SFX_02_5b - SFX_Headers_02) / 3 ; check if collision sound is already playing
+ jr z,.setCarry
+ ld a,(SFX_02_5b - SFX_Headers_02) / 3
+ call PlaySound ; play collision sound (if it's not already playing)
+.setCarry
+ scf
+ jr .done
+.checkIfVermilionDockTileset
+ ld a, [W_CURMAPTILESET] ; tileset
+ cp SHIP_PORT ; Vermilion Dock tileset
+ jr nz, .noCollision ; keep surfing if it's not the boarding platform tile
+ jr .stopSurfing ; if it is the boarding platform tile, stop surfing
+.stopSurfing ; based game freak
+ ld a,$3
+ ld [wd431],a
+ ld hl,wd430
+ set 5,[hl]
+ xor a
+ ld [wWalkBikeSurfState],a
+ call LoadPlayerSpriteGraphics
+ call PlayDefaultMusic
+ jr .noCollision
+.noCollision ; ...and they do the same mistake twice
+ and a
+.done
+ ret
+
+; function to run the current map's script
+RunMapScript:: ; 0d2c (0:0d2c)
+ push hl
+ push de
+ push bc
+ callba TryPushingBoulder
+ ld a,[wFlags_0xcd60]
+ bit 1,a ; play boulder dust animation
+ jr z,.afterBoulderEffect
+ callba DoBoulderDustAnimation
+.afterBoulderEffect
+ pop bc
+ pop de
+ pop hl
+ call RunNPCMovementScript
+ ld a,[W_CURMAP] ; current map number
+ call SwitchToMapRomBank ; change to the ROM bank the map's data is in
+ ld hl,W_MAPSCRIPTPTR
+ ld a,[hli]
+ ld h,[hl]
+ ld l,a
+ ld de,.return
+ push de
+ jp [hl] ; jump to script
+.return
+ ret
+
+Func_0d5e:: ; 0d5e (0:0d5e)
+; new sprite copy stuff
+ xor a
+ ld [wd473],a
+ ld b,BANK(RedSprite)
+ ld de,RedSprite ; $4180
+ jr LoadPlayerSpriteGraphicsCommon
+
+Func_0d69:: ; 0d69 (0:0d69)
+ ld a,[wd473]
+ and a
+ jr z,.asm_0d75
+ dec a
+ jr z,.asm_0d83
+ dec a
+ jr z,.asm_0d7c
+.asm_0d75
+ ld a,[wd472]
+ bit 6,a
+ jr z,LoadSurfingPlayerSpriteGraphics
+.asm_0d7c
+ ld b,BANK(Pointer_fedef)
+ ld de,Pointer_fedef ; 3f:6def
+ jr LoadPlayerSpriteGraphicsCommon
+
+LoadSurfingPlayerSpriteGraphics:: ; 0d83 (0:0d83)
+ ld b,BANK(RedSprite) ; not sure, but probably same bank (5)
+ ld de,SeelSprite
+ jr LoadPlayerSpriteGraphicsCommon
+
+LoadBikePlayerSpriteGraphics:: ; 0d8a (0:0d8a)
+ ld de,RedCyclingSprite
+LoadPlayerSpriteGraphicsCommon:: ; 0d8f (0:0d8f)
+ ld hl,vNPCSprites
+ push de
+ push hl
+ ld c, $c
+ call CopyVideoData
+ pop hl
+ pop de
+ ld a,$c0
+ add e
+ ld e,a
+ jr nc,.noCarry
+ inc d
+.noCarry
+ set 3,h
+ ld c,$c
+ jp CopyVideoData
+
+; function to load data from the map header
+LoadMapHeader:: ; 0dab (0:0dab)
+ callba MarkTownVisitedAndLoadMissableObjects
+ jr .asm_0dbd
+ callba Func_f0a55 ; 3c:4a55
+.asm_0dbd
+ ld a,[W_CURMAPTILESET]
+ ld [wd119],a
+ ld a,[W_CURMAP]
+ call SwitchToMapRomBank
+ ld a,[W_CURMAPTILESET]
+ ld b,a
+ res 7,a
+ ld [W_CURMAPTILESET],a
+ ld [$ff8b],a
+ bit 7,b
+ ret nz
+ call GetMapHeaderPointer
+; copy the first 10 bytes (the fixed area) of the map data to D367-D370
+ ld de,W_CURMAPTILESET
+ ld c,$0a
+.copyFixedHeaderLoop
+ ld a,[hli]
+ ld [de],a
+ inc de
+ dec c
+ jr nz,.copyFixedHeaderLoop
+; initialize all the connected maps to disabled at first, before loading the actual values
+ ld a,$ff
+ ld [W_MAPCONN1PTR],a
+ ld [W_MAPCONN2PTR],a
+ ld [W_MAPCONN3PTR],a
+ ld [W_MAPCONN4PTR],a
+; copy connection data (if any) to WRAM
+ ld a,[W_MAPCONNECTIONS]
+ ld b,a
+.checkNorth
+ bit 3,b
+ jr z,.checkSouth
+ ld de,W_MAPCONN1PTR
+ call CopyMapConnectionHeader
+.checkSouth
+ bit 2,b
+ jr z,.checkWest
+ ld de,W_MAPCONN2PTR
+ call CopyMapConnectionHeader
+.checkWest
+ bit 1,b
+ jr z,.checkEast
+ ld de,W_MAPCONN3PTR
+ call CopyMapConnectionHeader
+.checkEast
+ bit 0,b
+ jr z,.getObjectDataPointer
+ ld de,W_MAPCONN4PTR
+ call CopyMapConnectionHeader
+.getObjectDataPointer
+ ld a,[hli]
+ ld [wd3a9],a
+ ld a,[hli]
+ ld [wd3aa],a
+ push hl
+ ld a,[wd3a9]
+ ld l,a
+ ld a,[wd3aa]
+ ld h,a ; hl = base of object data
+ ld de,wd3ad ; background tile ID
+ ld a,[hli]
+ ld [de],a ; save background tile ID
+.loadWarpData
+ ld a,[hli]
+ ld [wNumberOfWarps],a
+ and a
+ jr z,.loadSignData
+ ld c,a
+ ld de,wWarpEntries
+.warpLoop ; one warp per loop iteration
+ ld b,$04
+.warpInnerLoop
+ ld a,[hli]
+ ld [de],a
+ inc de
+ dec b
+ jr nz,.warpInnerLoop
+ dec c
+ jr nz,.warpLoop
+.loadSignData
+ ld a,[hli] ; number of signs
+ ld [wd4b0],a ; save the number of signs
+ and a ; are there any signs?
+ jr z,.loadSpriteData ; if not, skip this
+ call CopySignData ; 0eb3 (0:0eb3)
+.loadSpriteData
+ ld a,[wd72e]
+ bit 5,a ; did a battle happen immediately before this?
+ jp nz,.finishUp ; if so, skip this because battles don't destroy this data
+ call InitSprites
+.finishUp
+ predef LoadTilesetHeader
+ ld a,[wd72e]
+ bit 5,a ; did a battle happen immediately before this?
+ jr nz,.asm_0e73
+ callab Func_fc4fa ; 3f:44fa
+ callab LoadWildData
+ pop hl ; restore hl from before going to the warp/sign/sprite data (this value was saved for seemingly no purpose)
+ ld a,[W_CURMAPHEIGHT] ; map height in 4x4 tile blocks
+ add a ; double it
+ ld [wd524],a ; store map height in 2x2 tile blocks
+ ld a,[W_CURMAPWIDTH] ; map width in 4x4 tile blocks
+ add a ; double it
+ ld [wd525],a ; map width in 2x2 tile blocks
+ ld a,[W_CURMAP]
+ ld c,a
+ ld b,$00
+ ld a,[H_LOADEDROMBANK]
+ push af
+ switchbank MapSongBanks
+ ld hl, MapSongBanks ; 3f:4000
+ add hl,bc
+ add hl,bc
+ ld a,[hli]
+ ld [wd35b],a ; music 1
+ ld a,[hl]
+ ld [wd35c],a ; music 2
+ pop af
+ call BankswitchCommon
+ ret
+
+; function to copy map connection data from ROM to WRAM
+; Input: hl = source, de = destination
+CopyMapConnectionHeader:: ; 1238 (0:1238)
+ ld c,$0b
+.loop
+ ld a,[hli]
+ ld [de],a
+ inc de
+ dec c
+ jr nz,.loop
+ ret
+
+CopySignData:: ; 0eb3 (0:0eb3)
+ ld de,wd4b1 ; start of sign coords
+ ld bc,wd4d1 ; start of sign text ids
+ ld a,[wd4b0] ; number of signs
+.signcopyloop
+ push af
+ ld a,[hli]
+ ld [de],a ; copy y coord
+ inc de
+ ld a,[hli]
+ ld [de],a ; copy x coord
+ inc de
+ ld a,[hli]
+ ld [bc],a ; copy sign text id
+ inc bc
+ pop af
+ dec a
+ jr nz,.signcopyloop
+ ret
+
+; function to load map data
+LoadMapData:: ; 1241 (0:1241)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ call DisableLCD
+ call ResetMapVariables
+ call LoadTextBoxTilePatterns
+ call LoadMapHeader
+ call InitMapSprites ; load tile pattern data for sprites
+ call LoadScreenRelatedData
+ call CopyMapViewToVRAM
+ ld a,$01
+ ld [wUpdateSpritesEnabled],a
+ call EnableLCD
+ ld b,$09
+ call GoPAL_SET
+ call LoadPlayerSpriteGraphics
+ ld a,[wd732]
+ and a,1 << 4 | 1 << 3 ; fly warp or dungeon warp
+ jr nz,.restoreRomBank
+ ld a,[W_FLAGS_D733]
+ bit 1,a
+ jr nz,.restoreRomBank
+ call Func_235f ; music related
+ call Func_2312 ; music related
+.restoreRomBank
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+
+LoadScreenRelatedData:: ; 0f0c (0:0f0c)
+ call LoadTileBlockMap
+ call LoadTilesetTilePatternData
+ call LoadCurrentMapView
+ ret
+
+Func_0f16:: ; 0f16 (0:0f16)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ call DisableLCD
+ call ResetMapVariables
+ ld a,[W_CURMAP]
+ call SwitchToMapRomBank
+ call LoadScreenRelatedData
+ call CopyMapViewToVRAM
+ ld de,vBGMap1
+ call CopyMapViewToVRAM2
+ call EnableLCD
+ call ReloadMapSpriteTilePatterns
+ pop af
+ call BankswitchCommon
+ jr .asm_0f4d
+Func_0f3d:: ; 0f3d (0:0f3d)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,[W_CURMAP]
+ call SwitchToMapRomBank
+ call LoadTileBlockMap
+ pop af
+ call BankswitchCommon
+.asm_0f4d
+ ld hl, Func_f02da
+ ld b,BANK(Func_f02da) ; 3c:42da
+ jp Bankswitch
+ ret ; useless?
+
+ResetMapVariables:: ; 0f56 (0:0f56)
+ ld a,$98
+ ld [wMapViewVRAMPointer + 1],a
+ xor a
+ ld [wMapViewVRAMPointer],a
+ ld [hSCY],a
+ ld [hSCX],a
+ ld [wWalkCounter],a
+ ld [wd119],a
+ ld [W_SPRITESETID],a
+ ld [wWalkBikeSurfStateCopy],a
+ ret
+
+CopyMapViewToVRAM:: ; 0f70 (0:0f70)
+; copy current map view to VRAM
+ ld de,vBGMap0
+CopyMapViewToVRAM2: ; 0f73 (0:0f73)
+ ld hl,wTileMap
+ ld b,18
+.vramCopyLoop
+ ld c,20
+.vramCopyInnerLoop
+ ld a,[hli]
+ ld [de],a
+ inc e
+ dec c
+ jr nz,.vramCopyInnerLoop
+ ld a,32 - 20 ; total vram map width in tiles - screen width in tiles
+ add e
+ ld e,a
+ jr nc,.noCarry
+ inc d
+.noCarry
+ dec b
+ jr nz,.vramCopyLoop
+ ret
+
+; function to switch to the ROM bank that a map is stored in
+; Input: a = map number
+SwitchToMapRomBank:: ; 0f8b (0:0f8b)
+ push hl
+ push bc
+ ld c,a
+ ld b,$00
+ ld a,BANK(MapHeaderBanks)
+ call BankswitchHome ; switch to ROM bank 3F
+ ld hl,MapHeaderBanks
+ add hl,bc
+ ld a,[hl]
+ ld [$ffe8],a ; save map ROM bank
+ call BankswitchCommon
+ pop bc
+ pop hl
+ ret
+
+GetMapHeaderPointer:: ; 0fa7 (0:0fa7)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ switchbank MapHeaderPointers ; 3f:41f2
+ push de
+ ld a,[W_CURMAP]
+ ld e,a
+ ld d,$0
+ ld hl,MapHeaderPointers
+ add hl,de
+ add hl,de
+ ld a,[hli]
+ ld h,[hl]
+ ld l,a
+ pop de
+ pop af
+ jp BankswitchCommon
+
+IgnoreInputForHalfSecond: ; 0fc3 (0:0fc3)
+ ld a, 30
+ ld [wIgnoreInputCounter], a
+ ld hl, wd730
+ ld a, [hl]
+ or $26
+ ld [hl], a ; set ignore input bit
+ ret
+
+ResetUsingStrengthOutOfBattleBit: ; 0fd0 (0:0fd0)
+ ld hl, wd728
+ res 0, [hl]
+ ret
+
+ForceBikeOrSurf:: ; 0fd6 (0:0fd6)
+ ld b, BANK(RedSprite)
+ ld hl, LoadPlayerSpriteGraphics
+ call Bankswitch
+ jp PlayDefaultMusic ; update map/player state?
+
+; Handle the player jumping down
+; a ledge in the overworld.
+HandleMidJump:: ; 0fe1 (0:0fe1)
+ ld a,[wd736]
+ bit 7,a ; jumping down a ledge?
+ ret z
+ ld b, BANK(_HandleMidJump)
+ ld hl, _HandleMidJump
+ jp Bankswitch
+
+IsSpinning:: ; 0ff0 (0:0ff0)
+ ld a,[wd736]
+ bit 7,a
+ ret z ; no spinning
+ ld b, BANK(LoadSpinnerArrowTiles); spin while moving
+ ld hl,LoadSpinnerArrowTiles ; 11:5077
+ jp Bankswitch
+
+Func_0ffe:: ; 0ffe (0:0ffe)
+ ld hl, Func_fcf0c ; 3f:4f0c
+ ld b, BANK(Func_fcf0c)
+ jp Bankswitch
+
+InitSprites:: ; 1006 (0:1006)
+ ld a,[hli]
+ ld [W_NUMSPRITES],a ; save the number of sprites
+ push hl
+ push hl
+ push de
+ push bc
+ call ZeroSpriteStateData
+ call DisableRegularSprites
+ ld hl,W_MAPSPRITEDATA
+ ld bc,$20
+ xor a
+ call FillMemory
+ pop bc
+ pop de
+ pop hl
+ ld a,[W_NUMSPRITES]
+ and a ; are sprites existant?
+ ret z ; don't copy sprite data if not
+ ld b,a
+ ld c,$0
+ ld de,wSpriteStateData1 + $10
+; copy sprite stuff?
+.loadSpriteLoop
+ ld a,[hli]
+ ld [de],a ; store picture ID at C1X0
+ inc d
+ ld a,$04
+ add e
+ ld e,a
+ ld a,[hli]
+ ld [de],a ; store Y position at C2X4
+ inc e
+ ld a,[hli]
+ ld [de],a ; store X position at C2X5
+ inc e
+ ld a,[hli]
+ ld [de],a ; store movement byte 1 at C2X6
+ ld a,[hli]
+ ld [$ff8d],a ; save movement byte 2
+ ld a,[hli]
+ ld [$ff8e],a ; save text ID and flags byte
+ push bc
+ call LoadSprite
+ pop bc
+ dec d
+ ld a,e
+ add a,$a
+ ld e,a
+ inc c
+ inc c
+ dec b
+ jr nz,.loadSpriteLoop
+ ret
+
+ZeroSpriteStateData:: ; 1050 (0:1050)
+; zero C110-C1EF and C210-C2EF
+; C1F0-C1FF and C2F0-C2FF is probably used for Pikachu
+ ld hl,wSpriteStateData1 + $10
+ ld de,wSpriteStateData2 + $10
+ xor a
+ ld b,$e0
+.loop
+ ld [hli],a
+ ld [de],a
+ inc e
+ dec b
+ jr nz,.loop
+ ret
+
+DisableRegularSprites:: ; 1060 (0:1060)
+; initialize all C100-C1FF sprite entries to disabled (other than player's and pikachu)
+ ld hl,wSpriteStateData1 + $12
+ ld de,$10
+ ld c,$e
+.loop
+ ld [hl],$ff
+ add hl,de
+ dec c
+ jr nz,.loop
+ ret
+
+LoadSprite:: ; 106f (0:106f)
+ push hl
+ ld b,$0
+ ld hl,W_MAPSPRITEDATA
+ add hl,bc
+ ld a,[$ff8d]
+ ld [hli],a ; store movement byte 2 in byte 0 of sprite entry
+ ld a,[$ff8e]
+ ld [hl],a ; this appears pointless, since the value is overwritten immediately after
+ ld a,[$ff8e]
+ ld [$ff8d],a
+ and a,$3f
+ ld [hl],a ; store text ID in byte 1 of sprite entry
+ pop hl
+ ld a,[$ff8d]
+ bit 6,a
+ jr nz,.trainerSprite
+ bit 7,a
+ jr nz,.itemBallSprite
+; for regular sprites
+ push hl
+ ld hl,W_MAPSPRITEEXTRADATA
+ add hl,bc
+; zero both bytes, since regular sprites don't use this extra space
+ xor a
+ ld [hli],a
+ ld [hl],a
+ pop hl
+ ret
+
+.trainerSprite
+ ld a,[hli]
+ ld [$ff8d],a ; save trainer class
+ ld a,[hli]
+ ld [$ff8e],a ; save trainer number (within class)
+ push hl
+ ld hl,W_MAPSPRITEEXTRADATA
+ add hl,bc
+ ld a,[$ff8d]
+ ld [hli],a ; store trainer class in byte 0 of the entry
+ ld a,[$ff8e]
+ ld [hl],a ; store trainer number in byte 1 of the entry
+ pop hl
+ ret
+
+.itemBallSprite
+ ld a,[hli]
+ ld [$ff8d],a ; save item number
+ push hl
+ ld hl,W_MAPSPRITEEXTRADATA
+ add hl,bc
+ ld a,[$ff8d]
+ ld [hli],a ; store item number in byte 0 of the entry
+ xor a
+ ld [hl],a ; zero byte 1, since it is not used
+ pop hl
ret ; end of home/overworld.asm = 10b9 (0:10b9) \ No newline at end of file
diff --git a/home/serial.asm b/home/serial.asm
index 86d74040..a199de57 100644
--- a/home/serial.asm
+++ b/home/serial.asm
@@ -1,312 +1,312 @@
-Serial:: ; 2125 (0:2125)
- push af
- push bc
- push de
- push hl
- ld a, [hSerialConnectionStatus]
- inc a
- jr z, .connectionNotYetEstablished
- ld a, [rSB]
- ld [hSerialReceiveData], a
- ld a, [hSerialSendData]
- ld [rSB], a
- ld a, [hSerialConnectionStatus]
- cp USING_INTERNAL_CLOCK
- jr z, .done
-; using external clock
- ld a, START_TRANSFER_EXTERNAL_CLOCK
- ld [rSC], a
- jr .done
-.connectionNotYetEstablished
- ld a, [rSB]
- ld [hSerialReceiveData], a
- ld [hSerialConnectionStatus], a
- cp USING_INTERNAL_CLOCK
- jr z, .usingInternalClock
-; using external clock
- xor a
- ld [rSB], a
- ld a, $3
- ld [rDIV], a
-.waitLoop
- ld a, [rDIV]
- bit 7, a
- jr nz, .waitLoop
- ld a, START_TRANSFER_EXTERNAL_CLOCK
- ld [rSC], a
- jr .done
-.usingInternalClock
- xor a
- ld [rSB], a
-.done
- ld a, $1
- ld [hSerialReceivedNewData], a
- ld a, SERIAL_NO_DATA_BYTE
- ld [hSerialSendData], a
- pop hl
- pop de
- pop bc
- pop af
- reti
-
-; hl = send data
-; de = receive data
-; bc = length of data
-Serial_ExchangeBytes:: ; 216f (0:216f)
- ld a, 1
- ld [hSerialIgnoringInitialData], a
-.loop
- ld a, [hl]
- ld [hSerialSendData], a
- call Serial_ExchangeByte
- push bc
- ld b, a
- inc hl
- ld a, 48
-.waitLoop
- dec a
- jr nz, .waitLoop
- ld a, [hSerialIgnoringInitialData]
- and a
- ld a, b
- pop bc
- jr z, .storeReceivedByte
- dec hl
- cp SERIAL_PREAMBLE_BYTE
- jr nz, .loop
- xor a
- ld [hSerialIgnoringInitialData], a
- jr .loop
-.storeReceivedByte
- ld [de], a
- inc de
- dec bc
- ld a, b
- or c
- jr nz, .loop
- ret
-
-Serial_ExchangeByte:: ; 219a (0:219a)
- xor a
- ld [hSerialReceivedNewData], a
- ld a, [hSerialConnectionStatus]
- cp USING_INTERNAL_CLOCK
- jr nz, .asm_21a7
- ld a, START_TRANSFER_INTERNAL_CLOCK
- ld [rSC], a
-.asm_21a7
- ld a, [hSerialReceivedNewData]
- and a
- jr nz, .asm_21f1
- ld a, [hSerialConnectionStatus]
- cp USING_EXTERNAL_CLOCK
- jr nz, .asm_21cc
- call IsUnknownCounterZero
- jr z, .asm_21cc
- call WaitLoop_15Iterations
- push hl
- ld hl, wUnknownSerialCounter + 1
- inc [hl]
- jr nz, .asm_21c3
- dec hl
- inc [hl]
-.asm_21c3
- pop hl
- call IsUnknownCounterZero
- jr nz, .asm_21a7
- jp SetUnknownCounterToFFFF
-.asm_21cc
- ld a, [rIE]
- and (1 << SERIAL) | (1 << TIMER) | (1 << LCD_STAT) | (1 << VBLANK)
- cp (1 << SERIAL)
- jr nz, .asm_21a7
- ld a, [wUnknownSerialCounter2]
- dec a
- ld [wUnknownSerialCounter2], a
- jr nz, .asm_21a7
- ld a, [wUnknownSerialCounter2 + 1]
- dec a
- ld [wUnknownSerialCounter2 + 1], a
- jr nz, .asm_21a7
- ld a, [hSerialConnectionStatus]
- cp USING_EXTERNAL_CLOCK
- jr z, .asm_21f1
- ld a, 255
-.waitLoop
- dec a
- jr nz, .waitLoop
-.asm_21f1
- xor a
- ld [hSerialReceivedNewData], a
- ld a, [rIE]
- and (1 << SERIAL) | (1 << TIMER) | (1 << LCD_STAT) | (1 << VBLANK)
- sub (1 << SERIAL)
- jr nz, .asm_2204
- ld [wUnknownSerialCounter2], a
- ld a, $50
- ld [wUnknownSerialCounter2 + 1], a
-.asm_2204
- ld a, [hSerialReceiveData]
- cp SERIAL_NO_DATA_BYTE
- ret nz
- call IsUnknownCounterZero
- jr z, .asm_221f
- push hl
- ld hl, wUnknownSerialCounter + 1
- ld a, [hl]
- dec a
- ld [hld], a
- inc a
- jr nz, .asm_2219
- dec [hl]
-.asm_2219
- pop hl
- call IsUnknownCounterZero
- jr z, SetUnknownCounterToFFFF
-.asm_221f
- ld a, [rIE]
- and (1 << SERIAL) | (1 << TIMER) | (1 << LCD_STAT) | (1 << VBLANK)
- cp (1 << SERIAL)
- ld a, SERIAL_NO_DATA_BYTE
- ret z
- ld a, [hl]
- ld [hSerialSendData], a
- call DelayFrame
- jp Serial_ExchangeByte
-
-WaitLoop_15Iterations:: ; 2231 (0:2231)
- ld a, 15
-.waitLoop
- dec a
- jr nz, .waitLoop
- ret
-
-IsUnknownCounterZero:: ; 2237 (0:2237)
- push hl
- ld hl, wUnknownSerialCounter
- ld a, [hli]
- or [hl]
- pop hl
- ret
-
-; a is always 0 when this is called
-SetUnknownCounterToFFFF:: ; 223f (0:223f)
- dec a
- ld [wUnknownSerialCounter], a
- ld [wUnknownSerialCounter + 1], a
- ret
-
-; This is used to exchange the button press and selected menu item on the link menu.
-; The data is sent thrice and read twice to increase reliability.
-Serial_ExchangeLinkMenuSelection:: ; 2247 (0:2247)
- ld hl, wLinkMenuSelectionSendBuffer
- ld de, wLinkMenuSelectionReceiveBuffer
- ld c, 2 ; number of bytes to save
- ld a, 1
- ld [hSerialIgnoringInitialData], a
-.loop
- call DelayFrame
- ld a, [hl]
- ld [hSerialSendData], a
- call Serial_ExchangeByte
- ld b, a
- inc hl
- ld a, [hSerialIgnoringInitialData]
- and a
- ld a, 0
- ld [hSerialIgnoringInitialData], a
- jr nz, .loop
- ld a, b
- ld [de], a
- inc de
- dec c
- jr nz, .loop
- ret
-
-Serial_PrintWaitingTextAndSyncAndExchangeNybble:: ; 226e (0:226e)
- call SaveScreenTilesToBuffer1
- callab PrintWaitingText
- call Serial_SyncAndExchangeNybble
- jp LoadScreenTilesFromBuffer1
-
-Serial_SyncAndExchangeNybble:: ; 227f (0:227f)
- ld a, $ff
- ld [wSerialExchangeNybbleReceiveData], a
-.loop1
- call Serial_ExchangeNybble
- call DelayFrame
- call IsUnknownCounterZero
- jr z, .next1
- push hl
- ld hl, wUnknownSerialCounter + 1
- dec [hl]
- jr nz, .next2
- dec hl
- dec [hl]
- jr nz, .next2
- pop hl
- xor a
- jp SetUnknownCounterToFFFF
-.next2
- pop hl
-.next1
- ld a, [wSerialExchangeNybbleReceiveData]
- inc a
- jr z, .loop1
- ld b, 10
-.loop2
- call DelayFrame
- call Serial_ExchangeNybble
- dec b
- jr nz, .loop2
- ld b, 10
-.loop3
- call DelayFrame
- call Serial_SendZeroByte
- dec b
- jr nz, .loop3
- ld a, [wSerialExchangeNybbleReceiveData]
- ld [wSerialSyncAndExchangeNybbleReceiveData], a
- ret
-
-Serial_ExchangeNybble:: ; 22c3 (0:22c3)
- call .doExchange
- ld a, [wSerialExchangeNybbleSendData]
- add $60
- ld [hSerialSendData], a
- ld a, [hSerialConnectionStatus]
- cp USING_INTERNAL_CLOCK
- jr nz, .doExchange
- ld a, START_TRANSFER_INTERNAL_CLOCK
- ld [rSC], a
-.doExchange
- ld a, [hSerialReceiveData]
- ld [wSerialExchangeNybbleTempReceiveData], a
- and $f0
- cp $60
- ret nz
- xor a
- ld [hSerialReceiveData], a
- ld a, [wSerialExchangeNybbleTempReceiveData]
- and $f
- ld [wSerialExchangeNybbleReceiveData], a
- ret
-
-Serial_SendZeroByte:: ; 22ed (0:22ed)
- xor a
- ld [hSerialSendData], a
- ld a, [hSerialConnectionStatus]
- cp USING_INTERNAL_CLOCK
- ret nz
- ld a, START_TRANSFER_INTERNAL_CLOCK
- ld [rSC], a
- ret
-
-Serial_TryEstablishingExternallyClockedConnection:: ; 22fa (0:22fa)
- ld a, ESTABLISH_CONNECTION_WITH_EXTERNAL_CLOCK
- ld [rSB], a
- xor a
- ld [hSerialReceiveData], a
- ld a, START_TRANSFER_EXTERNAL_CLOCK
- ld [rSC], a
+Serial:: ; 2125 (0:2125)
+ push af
+ push bc
+ push de
+ push hl
+ ld a, [hSerialConnectionStatus]
+ inc a
+ jr z, .connectionNotYetEstablished
+ ld a, [rSB]
+ ld [hSerialReceiveData], a
+ ld a, [hSerialSendData]
+ ld [rSB], a
+ ld a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr z, .done
+; using external clock
+ ld a, START_TRANSFER_EXTERNAL_CLOCK
+ ld [rSC], a
+ jr .done
+.connectionNotYetEstablished
+ ld a, [rSB]
+ ld [hSerialReceiveData], a
+ ld [hSerialConnectionStatus], a
+ cp USING_INTERNAL_CLOCK
+ jr z, .usingInternalClock
+; using external clock
+ xor a
+ ld [rSB], a
+ ld a, $3
+ ld [rDIV], a
+.waitLoop
+ ld a, [rDIV]
+ bit 7, a
+ jr nz, .waitLoop
+ ld a, START_TRANSFER_EXTERNAL_CLOCK
+ ld [rSC], a
+ jr .done
+.usingInternalClock
+ xor a
+ ld [rSB], a
+.done
+ ld a, $1
+ ld [hSerialReceivedNewData], a
+ ld a, SERIAL_NO_DATA_BYTE
+ ld [hSerialSendData], a
+ pop hl
+ pop de
+ pop bc
+ pop af
+ reti
+
+; hl = send data
+; de = receive data
+; bc = length of data
+Serial_ExchangeBytes:: ; 216f (0:216f)
+ ld a, 1
+ ld [hSerialIgnoringInitialData], a
+.loop
+ ld a, [hl]
+ ld [hSerialSendData], a
+ call Serial_ExchangeByte
+ push bc
+ ld b, a
+ inc hl
+ ld a, 48
+.waitLoop
+ dec a
+ jr nz, .waitLoop
+ ld a, [hSerialIgnoringInitialData]
+ and a
+ ld a, b
+ pop bc
+ jr z, .storeReceivedByte
+ dec hl
+ cp SERIAL_PREAMBLE_BYTE
+ jr nz, .loop
+ xor a
+ ld [hSerialIgnoringInitialData], a
+ jr .loop
+.storeReceivedByte
+ ld [de], a
+ inc de
+ dec bc
+ ld a, b
+ or c
+ jr nz, .loop
+ ret
+
+Serial_ExchangeByte:: ; 219a (0:219a)
+ xor a
+ ld [hSerialReceivedNewData], a
+ ld a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr nz, .asm_21a7
+ ld a, START_TRANSFER_INTERNAL_CLOCK
+ ld [rSC], a
+.asm_21a7
+ ld a, [hSerialReceivedNewData]
+ and a
+ jr nz, .asm_21f1
+ ld a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ jr nz, .asm_21cc
+ call IsUnknownCounterZero
+ jr z, .asm_21cc
+ call WaitLoop_15Iterations
+ push hl
+ ld hl, wUnknownSerialCounter + 1
+ inc [hl]
+ jr nz, .asm_21c3
+ dec hl
+ inc [hl]
+.asm_21c3
+ pop hl
+ call IsUnknownCounterZero
+ jr nz, .asm_21a7
+ jp SetUnknownCounterToFFFF
+.asm_21cc
+ ld a, [rIE]
+ and (1 << SERIAL) | (1 << TIMER) | (1 << LCD_STAT) | (1 << VBLANK)
+ cp (1 << SERIAL)
+ jr nz, .asm_21a7
+ ld a, [wUnknownSerialCounter2]
+ dec a
+ ld [wUnknownSerialCounter2], a
+ jr nz, .asm_21a7
+ ld a, [wUnknownSerialCounter2 + 1]
+ dec a
+ ld [wUnknownSerialCounter2 + 1], a
+ jr nz, .asm_21a7
+ ld a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ jr z, .asm_21f1
+ ld a, 255
+.waitLoop
+ dec a
+ jr nz, .waitLoop
+.asm_21f1
+ xor a
+ ld [hSerialReceivedNewData], a
+ ld a, [rIE]
+ and (1 << SERIAL) | (1 << TIMER) | (1 << LCD_STAT) | (1 << VBLANK)
+ sub (1 << SERIAL)
+ jr nz, .asm_2204
+ ld [wUnknownSerialCounter2], a
+ ld a, $50
+ ld [wUnknownSerialCounter2 + 1], a
+.asm_2204
+ ld a, [hSerialReceiveData]
+ cp SERIAL_NO_DATA_BYTE
+ ret nz
+ call IsUnknownCounterZero
+ jr z, .asm_221f
+ push hl
+ ld hl, wUnknownSerialCounter + 1
+ ld a, [hl]
+ dec a
+ ld [hld], a
+ inc a
+ jr nz, .asm_2219
+ dec [hl]
+.asm_2219
+ pop hl
+ call IsUnknownCounterZero
+ jr z, SetUnknownCounterToFFFF
+.asm_221f
+ ld a, [rIE]
+ and (1 << SERIAL) | (1 << TIMER) | (1 << LCD_STAT) | (1 << VBLANK)
+ cp (1 << SERIAL)
+ ld a, SERIAL_NO_DATA_BYTE
+ ret z
+ ld a, [hl]
+ ld [hSerialSendData], a
+ call DelayFrame
+ jp Serial_ExchangeByte
+
+WaitLoop_15Iterations:: ; 2231 (0:2231)
+ ld a, 15
+.waitLoop
+ dec a
+ jr nz, .waitLoop
+ ret
+
+IsUnknownCounterZero:: ; 2237 (0:2237)
+ push hl
+ ld hl, wUnknownSerialCounter
+ ld a, [hli]
+ or [hl]
+ pop hl
+ ret
+
+; a is always 0 when this is called
+SetUnknownCounterToFFFF:: ; 223f (0:223f)
+ dec a
+ ld [wUnknownSerialCounter], a
+ ld [wUnknownSerialCounter + 1], a
+ ret
+
+; This is used to exchange the button press and selected menu item on the link menu.
+; The data is sent thrice and read twice to increase reliability.
+Serial_ExchangeLinkMenuSelection:: ; 2247 (0:2247)
+ ld hl, wLinkMenuSelectionSendBuffer
+ ld de, wLinkMenuSelectionReceiveBuffer
+ ld c, 2 ; number of bytes to save
+ ld a, 1
+ ld [hSerialIgnoringInitialData], a
+.loop
+ call DelayFrame
+ ld a, [hl]
+ ld [hSerialSendData], a
+ call Serial_ExchangeByte
+ ld b, a
+ inc hl
+ ld a, [hSerialIgnoringInitialData]
+ and a
+ ld a, 0
+ ld [hSerialIgnoringInitialData], a
+ jr nz, .loop
+ ld a, b
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop
+ ret
+
+Serial_PrintWaitingTextAndSyncAndExchangeNybble:: ; 226e (0:226e)
+ call SaveScreenTilesToBuffer1
+ callab PrintWaitingText
+ call Serial_SyncAndExchangeNybble
+ jp LoadScreenTilesFromBuffer1
+
+Serial_SyncAndExchangeNybble:: ; 227f (0:227f)
+ ld a, $ff
+ ld [wSerialExchangeNybbleReceiveData], a
+.loop1
+ call Serial_ExchangeNybble
+ call DelayFrame
+ call IsUnknownCounterZero
+ jr z, .next1
+ push hl
+ ld hl, wUnknownSerialCounter + 1
+ dec [hl]
+ jr nz, .next2
+ dec hl
+ dec [hl]
+ jr nz, .next2
+ pop hl
+ xor a
+ jp SetUnknownCounterToFFFF
+.next2
+ pop hl
+.next1
+ ld a, [wSerialExchangeNybbleReceiveData]
+ inc a
+ jr z, .loop1
+ ld b, 10
+.loop2
+ call DelayFrame
+ call Serial_ExchangeNybble
+ dec b
+ jr nz, .loop2
+ ld b, 10
+.loop3
+ call DelayFrame
+ call Serial_SendZeroByte
+ dec b
+ jr nz, .loop3
+ ld a, [wSerialExchangeNybbleReceiveData]
+ ld [wSerialSyncAndExchangeNybbleReceiveData], a
+ ret
+
+Serial_ExchangeNybble:: ; 22c3 (0:22c3)
+ call .doExchange
+ ld a, [wSerialExchangeNybbleSendData]
+ add $60
+ ld [hSerialSendData], a
+ ld a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr nz, .doExchange
+ ld a, START_TRANSFER_INTERNAL_CLOCK
+ ld [rSC], a
+.doExchange
+ ld a, [hSerialReceiveData]
+ ld [wSerialExchangeNybbleTempReceiveData], a
+ and $f0
+ cp $60
+ ret nz
+ xor a
+ ld [hSerialReceiveData], a
+ ld a, [wSerialExchangeNybbleTempReceiveData]
+ and $f
+ ld [wSerialExchangeNybbleReceiveData], a
+ ret
+
+Serial_SendZeroByte:: ; 22ed (0:22ed)
+ xor a
+ ld [hSerialSendData], a
+ ld a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ ret nz
+ ld a, START_TRANSFER_INTERNAL_CLOCK
+ ld [rSC], a
+ ret
+
+Serial_TryEstablishingExternallyClockedConnection:: ; 22fa (0:22fa)
+ ld a, ESTABLISH_CONNECTION_WITH_EXTERNAL_CLOCK
+ ld [rSB], a
+ xor a
+ ld [hSerialReceiveData], a
+ ld a, START_TRANSFER_EXTERNAL_CLOCK
+ ld [rSC], a
ret \ No newline at end of file