pokered/home/overworld.asm

2403 lines
54 KiB
NASM
Raw Normal View History

HandleMidJump::
; Handle the player jumping down
; a ledge in the overworld.
2015-07-19 18:56:13 +00:00
jpba _HandleMidJump
EnterMap::
; Load a new map.
ld a, $ff
ld [wJoyIgnore], a
call LoadMapData
2014-09-14 18:29:18 +00:00
callba ClearVariablesAfterLoadingMapData
ld hl, wd72c
2014-09-13 07:50:56 +00:00
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
2014-09-14 18:29:18 +00:00
call z, ResetUsingStrengthOutOfBattleBit
call nz, MapEntryAfterBattle
ld hl, wd732
ld a, [hl]
2014-09-13 07:50:56 +00:00
and 1 << 4 | 1 << 3 ; fly warp or dungeon warp
jr z, .didNotEnterUsingFlyWarpOrDungeonWarp
res 3, [hl]
2014-09-14 18:29:18 +00:00
callba EnterMapAnim
call UpdateSprites
2014-09-13 07:50:56 +00:00
.didNotEnterUsingFlyWarpOrDungeonWarp
callba CheckForceBikeOrSurf ; handle currents in SF islands and forced bike riding in cycling road
ld hl, wd72d
res 5, [hl]
call UpdateSprites
ld hl, wd126
set 5, [hl]
set 6, [hl]
xor a
ld [wJoyIgnore], a
OverworldLoop::
call DelayFrame
OverworldLoopLessDelay::
call DelayFrame
call LoadGBPal
ld a,[wd736]
bit 6,a ; jumping down a ledge?
call nz, HandleMidJump
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
2014-09-14 18:29:18 +00:00
ld a,[wSafariZoneGameOver]
and a
jp nz,WarpFound2
ld hl,wd72d
bit 3,[hl]
res 3,[hl]
jp nz,WarpFound2
ld a,[wd732]
2014-09-13 07:50:56 +00:00
and a,1 << 4 | 1 << 3 ; fly warp or dungeon warp
jp nz,HandleFlyWarpOrDungeonWarp
2015-08-31 02:38:41 +00:00
ld a,[wCurOpponent]
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
2014-09-14 18:29:18 +00:00
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
2014-09-14 18:29:18 +00:00
call IsPlayerCharacterBeingControlledByGame
jr nz,.checkForOpponent
2014-09-14 18:29:18 +00:00
call CheckForHiddenObjectOrBookshelfOrCardKeyDoor
ld a,[$ffeb]
and a
2014-09-14 18:29:18 +00:00
jp z,OverworldLoop ; jump if a hidden object or bookshelf was found, but not if a card key door was found
call IsSpriteOrSignInFrontOfPlayer
ld a,[hSpriteIndexOrTextID]
and a
jp z,OverworldLoop
.displayDialogue
2014-09-13 07:50:56 +00:00
predef GetTileAndCoordsInFrontOfPlayer
call UpdateSprites
ld a,[wFlags_0xcd60]
bit 2,a
jr nz,.checkForOpponent
bit 0,a
jr nz,.checkForOpponent
aCoord 8, 9
2015-07-15 06:16:06 +00:00
ld [wTilePlayerStandingOn],a ; unused?
call DisplayTextID ; display either the start menu or the NPC/sign text
2015-07-26 02:26:54 +00:00
ld a,[wEnteringCableClub]
and a
jr z,.checkForOpponent
dec a
2015-07-26 02:26:54 +00:00
ld a,0
ld [wEnteringCableClub],a
jr z,.changeMap
2015-07-26 02:26:54 +00:00
; XXX can this code be reached?
predef LoadSAV
2015-08-31 02:38:41 +00:00
ld a,[wCurMap]
2014-09-13 07:50:56 +00:00
ld [wDestinationMap],a
call SpecialWarpIn
2015-08-31 02:38:41 +00:00
ld a,[wCurMap]
call SwitchToMapRomBank ; switch to the ROM bank of the current map
2015-08-31 02:38:41 +00:00
ld hl,wCurMapTileset
set 7,[hl]
.changeMap
jp EnterMap
.checkForOpponent
2015-08-31 02:38:41 +00:00
ld a,[wCurOpponent]
and a
jp nz,.newBattle
jp OverworldLoop
.noDirectionButtonsPressed
ld hl,wFlags_0xcd60
res 2,[hl]
2014-09-13 07:50:56 +00:00
call UpdateSprites
2015-07-25 03:27:59 +00:00
ld a,1
ld [wCheckFor180DegreeTurn],a
2015-07-20 00:52:26 +00:00
ld a,[wPlayerMovingDirection] ; the direction that was pressed last time
and a
jp z,OverworldLoop
; if a direction was pressed last time
2015-07-20 00:52:26 +00:00
ld [wPlayerLastStopDirection],a ; save the last direction
xor a
2015-07-20 00:52:26 +00:00
ld [wPlayerMovingDirection],a ; zero the direction
jp OverworldLoop
.checkIfDownButtonIsPressed
ld a,[hJoyHeld] ; current joypad state
bit 7,a ; down button
jr z,.checkIfUpButtonIsPressed
2015-07-20 00:52:26 +00:00
ld a,1
ld [wSpriteStateData1 + 3],a ; delta Y
ld a,PLAYER_DIR_DOWN
jr .handleDirectionButtonPress
.checkIfUpButtonIsPressed
bit 6,a ; up button
jr z,.checkIfLeftButtonIsPressed
2015-07-20 00:52:26 +00:00
ld a,-1
ld [wSpriteStateData1 + 3],a ; delta Y
ld a,PLAYER_DIR_UP
jr .handleDirectionButtonPress
.checkIfLeftButtonIsPressed
bit 5,a ; left button
jr z,.checkIfRightButtonIsPressed
2015-07-20 00:52:26 +00:00
ld a,-1
ld [wSpriteStateData1 + 5],a ; delta X
ld a,PLAYER_DIR_LEFT
jr .handleDirectionButtonPress
.checkIfRightButtonIsPressed
bit 4,a ; right button
jr z,.noDirectionButtonsPressed
2015-07-20 00:52:26 +00:00
ld a,1 ; PLAYER_DIR_RIGHT
ld [wSpriteStateData1 + 5],a ; delta X
.handleDirectionButtonPress
2015-07-20 00:52:26 +00:00
ld [wPlayerDirection],a ; new direction
ld a,[wd730]
bit 7,a ; are we simulating button presses?
jr nz,.noDirectionChange ; ignore direction changes if we are
2015-07-25 03:27:59 +00:00
ld a,[wCheckFor180DegreeTurn]
and a
jr z,.noDirectionChange
2015-07-20 00:52:26 +00:00
ld a,[wPlayerDirection] ; new direction
ld b,a
2015-07-20 00:52:26 +00:00
ld a,[wPlayerLastStopDirection] ; old direction
cp b
jr z,.noDirectionChange
2015-07-25 03:27:59 +00:00
; Check whether the player did a 180-degree turn.
; It appears that this code was supposed to show the player rotate by having
; the player's sprite face an intermediate direction before facing the opposite
; direction (instead of doing an instantaneous about-face), but the intermediate
; direction is only set for a short period of time. It is unlikely for it to
; ever be visible because DelayFrame is called at the start of OverworldLoop and
; normally not enough cycles would be executed between then and the time the
; direction is set for V-blank to occur while the direction is still set.
swap a ; put old direction in upper half
or b ; put new direction in lower half
2015-07-20 00:52:26 +00:00
cp a,(PLAYER_DIR_DOWN << 4) | PLAYER_DIR_UP ; change dir from down to up
jr nz,.notDownToUp
2015-07-20 00:52:26 +00:00
ld a,PLAYER_DIR_LEFT
ld [wPlayerMovingDirection],a
2015-07-25 03:27:59 +00:00
jr .holdIntermediateDirectionLoop
.notDownToUp
2015-07-20 00:52:26 +00:00
cp a,(PLAYER_DIR_UP << 4) | PLAYER_DIR_DOWN ; change dir from up to down
jr nz,.notUpToDown
2015-07-20 00:52:26 +00:00
ld a,PLAYER_DIR_RIGHT
ld [wPlayerMovingDirection],a
2015-07-25 03:27:59 +00:00
jr .holdIntermediateDirectionLoop
.notUpToDown
2015-07-20 00:52:26 +00:00
cp a,(PLAYER_DIR_RIGHT << 4) | PLAYER_DIR_LEFT ; change dir from right to left
jr nz,.notRightToLeft
2015-07-20 00:52:26 +00:00
ld a,PLAYER_DIR_DOWN
ld [wPlayerMovingDirection],a
2015-07-25 03:27:59 +00:00
jr .holdIntermediateDirectionLoop
.notRightToLeft
2015-07-20 00:52:26 +00:00
cp a,(PLAYER_DIR_LEFT << 4) | PLAYER_DIR_RIGHT ; change dir from left to right
2015-07-25 03:27:59 +00:00
jr nz,.holdIntermediateDirectionLoop
2015-07-20 00:52:26 +00:00
ld a,PLAYER_DIR_UP
ld [wPlayerMovingDirection],a
2015-07-25 03:27:59 +00:00
.holdIntermediateDirectionLoop
ld hl,wFlags_0xcd60
set 2,[hl]
2015-07-25 03:27:59 +00:00
ld hl,wCheckFor180DegreeTurn
dec [hl]
2015-07-25 03:27:59 +00:00
jr nz,.holdIntermediateDirectionLoop
2015-07-20 00:52:26 +00:00
ld a,[wPlayerDirection]
ld [wPlayerMovingDirection],a
call NewBattle
jp c,.battleOccurred
jp OverworldLoop
.noDirectionChange
2015-07-20 00:52:26 +00:00
ld a,[wPlayerDirection] ; current direction
ld [wPlayerMovingDirection],a ; save direction
2014-09-13 07:50:56 +00:00
call UpdateSprites
ld a,[wWalkBikeSurfState]
cp a,$02 ; surfing
jr z,.surfing
; not surfing
call CollisionCheckOnLand
jr nc,.noCollision
2014-09-13 07:50:56 +00:00
; collision occurred
push hl
ld hl,wd736
2014-09-13 07:50:56 +00:00
bit 2,[hl] ; standing on warp flag
pop hl
jp z,OverworldLoop
2014-09-13 07:50:56 +00:00
; 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
jr .moveAhead2
.moveAhead
ld a,[wd736]
bit 7,a
jr z,.noSpinning
callba LoadSpinnerArrowTiles ; spin while moving
.noSpinning
call UpdateSprites
.moveAhead2
ld hl,wFlags_0xcd60
res 2,[hl]
2014-09-13 07:50:56 +00:00
ld a,[wWalkBikeSurfState]
dec a ; riding a bike?
jr nz,.normalPlayerSpriteAdvancement
ld a,[wd736]
bit 6,a ; jumping a ledge?
jr nz,.normalPlayerSpriteAdvancement
call BikeSpeedup ; if riding a bike and not jumping a ledge
.normalPlayerSpriteAdvancement
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
ld a,[wd730]
bit 7,a
jr nz,.doneStepCounting ; if button presses are being simulated, don't count steps
; step counting
2014-09-13 07:50:56 +00:00
ld hl,wStepCounter
dec [hl]
ld a,[wd72c]
bit 0,a
jr z,.doneStepCounting
2014-09-13 07:50:56 +00:00
ld hl,wNumberOfNoRandomBattleStepsLeft
dec [hl]
jr nz,.doneStepCounting
ld hl,wd72c
2014-09-13 07:50:56 +00:00
res 0,[hl] ; indicate that the player has stepped thrice since the last battle
.doneStepCounting
2015-07-21 01:32:02 +00:00
CheckEvent EVENT_IN_SAFARI_ZONE
jr z,.notSafariZone
callba SafariZoneCheckSteps
2014-09-14 18:29:18 +00:00
ld a,[wSafariZoneGameOver]
and a
jp nz,WarpFound2
.notSafariZone
2015-08-31 02:38:41 +00:00
ld a,[wIsInBattle]
and a
jp nz,CheckWarpsNoCollision
2014-09-13 07:50:56 +00:00
predef ApplyOutOfBattlePoisonDamage ; also increment daycare mon exp
2015-07-13 06:00:48 +00:00
ld a,[wOutOfBattleBlackout]
and a
jp nz,HandleBlackOut ; if all pokemon fainted
.newBattle
call NewBattle
ld hl,wd736
2014-09-13 07:50:56 +00:00
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]
2015-08-31 02:38:41 +00:00
ld hl,wFlags_D733
res 3,[hl]
ld hl,wd126
set 5,[hl]
set 6,[hl]
xor a
2014-09-13 07:50:56 +00:00
ld [hJoyHeld],a
2015-08-31 02:38:41 +00:00
ld a,[wCurMap]
cp a,CINNABAR_GYM
jr nz,.notCinnabarGym
2015-07-21 01:32:02 +00:00
SetEvent EVENT_2A7
.notCinnabarGym
ld hl,wd72e
set 5,[hl]
2015-08-31 02:38:41 +00:00
ld a,[wCurMap]
cp a,OAKS_LAB
2014-09-13 07:50:56 +00:00
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,10
call DelayFrames
jp EnterMap
.allPokemonFainted
ld a,$ff
2015-08-31 02:38:41 +00:00
ld [wIsInBattle],a
call RunMapScript
jp HandleBlackOut
; 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:: ; 0683 (0:0683)
ld a,[wd72d]
bit 4,a
jr nz,.noBattle
2014-09-14 18:29:18 +00:00
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
2015-07-19 18:56:13 +00:00
jpba InitBattle
.noBattle
and a
ret
; function to make bikes twice as fast as walking
BikeSpeedup:: ; 06a0 (0:06a0)
ld a,[wNPCMovementScriptPointerTableNum]
and a
ret nz
2015-08-31 02:38:41 +00:00
ld a,[wCurMap]
cp a,ROUTE_17 ; Cycling Road
jr nz,.goFaster
2014-09-13 07:50:56 +00:00
ld a,[hJoyHeld]
and a,D_UP | D_LEFT | D_RIGHT
ret nz
.goFaster
jp AdvancePlayerSprite
; check if the player has stepped onto a warp after having not collided
CheckWarpsNoCollision:: ; 06b4 (0:06b4)
2014-09-13 07:50:56 +00:00
ld a,[wNumberOfWarps]
and a
jp z,CheckMapConnections
2014-09-13 07:50:56 +00:00
ld a,[wNumberOfWarps]
ld b,0
ld c,a
2015-08-31 02:38:41 +00:00
ld a,[wYCoord]
ld d,a
2015-08-31 02:38:41 +00:00
ld a,[wXCoord]
ld e,a
2014-09-13 07:50:56 +00:00
ld hl,wWarpEntries
CheckWarpsNoCollisionLoop:: ; 06cc (0:06cc)
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
2014-09-13 07:50:56 +00:00
set 2,[hl] ; standing on warp flag
callba IsPlayerStandingOnDoorTileOrWarpTile
pop bc
pop hl
2014-09-13 07:50:56 +00:00
jr c,WarpFound1 ; jump if standing on door or warp
push hl
push bc
2014-09-13 07:50:56 +00:00
call ExtraWarpCheck
pop bc
pop hl
jr nc,CheckWarpsNoCollisionRetry2
; if the extra check passed
2015-08-31 02:38:41 +00:00
ld a,[wFlags_D733]
bit 2,a
jr nz,WarpFound1
push de
push bc
call Joypad
pop bc
pop de
2014-09-13 07:50:56 +00:00
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
; check if the player has stepped onto a warp after having collided
CheckWarpsCollision:: ; 0706 (0:0706)
2014-09-13 07:50:56 +00:00
ld a,[wNumberOfWarps]
ld c,a
2014-09-13 07:50:56 +00:00
ld hl,wWarpEntries
.loop
ld a,[hli] ; Y coordinate of warp
ld b,a
2015-08-31 02:38:41 +00:00
ld a,[wYCoord]
cp b
jr nz,.retry1
ld a,[hli] ; X coordinate of warp
ld b,a
2015-08-31 02:38:41 +00:00
ld a,[wXCoord]
cp b
jr nz,.retry2
ld a,[hli]
2014-09-13 07:50:56 +00:00
ld [wDestinationWarpID],a
ld a,[hl]
2015-07-18 15:17:29 +00:00
ld [hWarpDestinationMap],a
jr WarpFound2
.retry1
inc hl
.retry2
inc hl
inc hl
dec c
jr nz,.loop
jp OverworldLoop
CheckWarpsNoCollisionRetry1:: ; 072f (0:072f)
inc hl
CheckWarpsNoCollisionRetry2:: ; 0730 (0:0730)
inc hl
inc hl
jp ContinueCheckWarpsNoCollisionLoop
WarpFound1:: ; 0735 (0:0735)
ld a,[hli]
2014-09-13 07:50:56 +00:00
ld [wDestinationWarpID],a
ld a,[hli]
2015-07-18 15:17:29 +00:00
ld [hWarpDestinationMap],a
WarpFound2:: ; 073c (0:073c)
2014-09-13 07:50:56 +00:00
ld a,[wNumberOfWarps]
sub c
2015-07-26 02:26:54 +00:00
ld [wWarpedFromWhichWarp],a ; save ID of used warp
2015-08-31 02:38:41 +00:00
ld a,[wCurMap]
2015-07-26 02:26:54 +00:00
ld [wWarpedFromWhichMap],a
call CheckIfInOutsideMap
jr nz,.indoorMaps
; this is for handling "outside" maps that can't have the 0xFF destination map
2015-08-31 02:38:41 +00:00
ld a,[wCurMap]
ld [wLastMap],a
2015-08-31 02:38:41 +00:00
ld a,[wCurMapWidth]
2015-07-26 02:26:54 +00:00
ld [wUnusedD366],a ; not read
2015-07-18 15:17:29 +00:00
ld a,[hWarpDestinationMap]
2015-08-31 02:38:41 +00:00
ld [wCurMap],a
cp a,ROCK_TUNNEL_1
jr nz,.notRockTunnel
ld a,$06
2014-09-13 07:50:56 +00:00
ld [wMapPalOffset],a
call GBFadeOutToBlack
.notRockTunnel
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
2015-07-18 15:17:29 +00:00
ld a,[hWarpDestinationMap] ; destination map
cp a,$ff
jr z,.goBackOutside
; if not going back to the previous map
2015-08-31 02:38:41 +00:00
ld [wCurMap],a
2014-09-13 07:50:56 +00:00
callba IsPlayerStandingOnWarpPadOrHole
2015-07-25 03:27:59 +00:00
ld a,[wStandingOnWarpPadOrHole]
2014-09-13 07:50:56 +00:00
dec a ; is the player on a warp pad?
jr nz,.notWarpPad
; if the player is on a warp pad
ld hl,wd732
set 3,[hl]
call LeaveMapAnim
jr .skipMapChangeSound
2014-09-13 07:50:56 +00:00
.notWarpPad
call PlayMapChangeSound
.skipMapChangeSound
ld hl,wd736
res 0,[hl]
res 1,[hl]
jr .done
.goBackOutside
ld a,[wLastMap]
2015-08-31 02:38:41 +00:00
ld [wCurMap],a
call PlayMapChangeSound
xor a
2014-09-13 07:50:56 +00:00
ld [wMapPalOffset],a
.done
ld hl,wd736
set 0,[hl] ; have the player's sprite step out from the door (if there is one)
2014-09-14 18:29:18 +00:00
call IgnoreInputForHalfSecond
jp EnterMap
ContinueCheckWarpsNoCollisionLoop:: ; 07b5 (0:07b5)
inc b ; increment warp number
dec c ; decrement number of warps
jp nz,CheckWarpsNoCollisionLoop
; if no matching warp was found
CheckMapConnections:: ; 07ba (0:07ba)
.checkWestMap
2015-08-31 02:38:41 +00:00
ld a,[wXCoord]
cp a,$ff
jr nz,.checkEastMap
2015-08-31 02:38:41 +00:00
ld a,[wMapConn3Ptr]
ld [wCurMap],a
2015-07-18 15:17:29 +00:00
ld a,[wWestConnectedMapXAlignment] ; new X coordinate upon entering west map
2015-08-31 02:38:41 +00:00
ld [wXCoord],a
ld a,[wYCoord]
ld c,a
2015-07-18 15:17:29 +00:00
ld a,[wWestConnectedMapYAlignment] ; Y adjustment upon entering west map
add c
ld c,a
2015-08-31 02:38:41 +00:00
ld [wYCoord],a
2015-07-18 15:17:29 +00:00
ld a,[wWestConnectedMapViewPointer] ; pointer to upper left corner of map without adjustment for Y position
ld l,a
2015-07-18 15:17:29 +00:00
ld a,[wWestConnectedMapViewPointer + 1]
ld h,a
srl c
jr z,.savePointer1
.pointerAdjustmentLoop1
2015-07-18 15:17:29 +00:00
ld a,[wWestConnectedMapWidth] ; width of connected map
add a,MAP_BORDER * 2
ld e,a
ld d,0
ld b,0
add hl,de
dec c
jr nz,.pointerAdjustmentLoop1
.savePointer1
ld a,l
2014-09-13 07:50:56 +00:00
ld [wCurrentTileBlockMapViewPointer],a ; pointer to upper left corner of current tile block map section
ld a,h
2014-09-13 07:50:56 +00:00
ld [wCurrentTileBlockMapViewPointer + 1],a
jp .loadNewMap
.checkEastMap
ld b,a
2015-07-20 00:52:26 +00:00
ld a,[wCurrentMapWidth2] ; map width
cp b
jr nz,.checkNorthMap
2015-08-31 02:38:41 +00:00
ld a,[wMapConn4Ptr]
ld [wCurMap],a
2015-07-18 15:17:29 +00:00
ld a,[wEastConnectedMapXAlignment] ; new X coordinate upon entering east map
2015-08-31 02:38:41 +00:00
ld [wXCoord],a
ld a,[wYCoord]
ld c,a
2015-07-18 15:17:29 +00:00
ld a,[wEastConnectedMapYAlignment] ; Y adjustment upon entering east map
add c
ld c,a
2015-08-31 02:38:41 +00:00
ld [wYCoord],a
2015-07-18 15:17:29 +00:00
ld a,[wEastConnectedMapViewPointer] ; pointer to upper left corner of map without adjustment for Y position
ld l,a
2015-07-18 15:17:29 +00:00
ld a,[wEastConnectedMapViewPointer + 1]
ld h,a
srl c
jr z,.savePointer2
.pointerAdjustmentLoop2
2015-07-18 15:17:29 +00:00
ld a,[wEastConnectedMapWidth]
add a,MAP_BORDER * 2
ld e,a
ld d,0
ld b,0
add hl,de
dec c
jr nz,.pointerAdjustmentLoop2
.savePointer2
ld a,l
2014-09-13 07:50:56 +00:00
ld [wCurrentTileBlockMapViewPointer],a ; pointer to upper left corner of current tile block map section
ld a,h
2014-09-13 07:50:56 +00:00
ld [wCurrentTileBlockMapViewPointer + 1],a
jp .loadNewMap
.checkNorthMap
2015-08-31 02:38:41 +00:00
ld a,[wYCoord]
cp a,$ff
jr nz,.checkSouthMap
2015-08-31 02:38:41 +00:00
ld a,[wMapConn1Ptr]
ld [wCurMap],a
2015-07-18 15:17:29 +00:00
ld a,[wNorthConnectedMapYAlignment] ; new Y coordinate upon entering north map
2015-08-31 02:38:41 +00:00
ld [wYCoord],a
ld a,[wXCoord]
ld c,a
2015-07-18 15:17:29 +00:00
ld a,[wNorthConnectedMapXAlignment] ; X adjustment upon entering north map
add c
ld c,a
2015-08-31 02:38:41 +00:00
ld [wXCoord],a
2015-07-18 15:17:29 +00:00
ld a,[wNorthConnectedMapViewPointer] ; pointer to upper left corner of map without adjustment for X position
ld l,a
2015-07-18 15:17:29 +00:00
ld a,[wNorthConnectedMapViewPointer + 1]
ld h,a
2015-07-18 15:17:29 +00:00
ld b,0
srl c
add hl,bc
ld a,l
2014-09-13 07:50:56 +00:00
ld [wCurrentTileBlockMapViewPointer],a ; pointer to upper left corner of current tile block map section
ld a,h
2014-09-13 07:50:56 +00:00
ld [wCurrentTileBlockMapViewPointer + 1],a
jp .loadNewMap
.checkSouthMap
ld b,a
2015-07-20 00:52:26 +00:00
ld a,[wCurrentMapHeight2]
cp b
jr nz,.didNotEnterConnectedMap
2015-08-31 02:38:41 +00:00
ld a,[wMapConn2Ptr]
ld [wCurMap],a
2015-07-18 15:17:29 +00:00
ld a,[wSouthConnectedMapYAlignment] ; new Y coordinate upon entering south map
2015-08-31 02:38:41 +00:00
ld [wYCoord],a
ld a,[wXCoord]
ld c,a
2015-07-18 15:17:29 +00:00
ld a,[wSouthConnectedMapXAlignment] ; X adjustment upon entering south map
add c
ld c,a
2015-08-31 02:38:41 +00:00
ld [wXCoord],a
2015-07-18 15:17:29 +00:00
ld a,[wSouthConnectedMapViewPointer] ; pointer to upper left corner of map without adjustment for X position
ld l,a
2015-07-18 15:17:29 +00:00
ld a,[wSouthConnectedMapViewPointer + 1]
ld h,a
2015-07-18 15:17:29 +00:00
ld b,0
srl c
add hl,bc
ld a,l
2014-09-13 07:50:56 +00:00
ld [wCurrentTileBlockMapViewPointer],a ; pointer to upper left corner of current tile block map section
ld a,h
2014-09-13 07:50:56 +00:00
ld [wCurrentTileBlockMapViewPointer + 1],a
.loadNewMap ; load the connected map that was entered
call LoadMapHeader
2015-08-09 05:32:44 +00:00
call PlayDefaultMusicFadeOutCurrent
2015-08-12 09:16:56 +00:00
ld b, SET_PAL_OVERWORLD
call RunPaletteCommand
; Since the sprite set shouldn't change, this will just update VRAM slots at
; $C2XE without loading any tile patterns.
callba InitMapSprites
call LoadTileBlockMap
jp OverworldLoopLessDelay
.didNotEnterConnectedMap
jp OverworldLoop
; function to play a sound when changing maps
PlayMapChangeSound:: ; 08c9 (0:08c9)
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
2015-07-19 08:46:12 +00:00
ld a,SFX_GO_INSIDE
jr .playSound
.didNotGoThroughDoor
2015-07-19 08:46:12 +00:00
ld a,SFX_GO_OUTSIDE
.playSound
call PlaySound
2014-09-13 07:50:56 +00:00
ld a,[wMapPalOffset]
and a
ret nz
2014-09-13 07:50:56 +00:00
jp GBFadeOutToBlack
CheckIfInOutsideMap:: ; 08e1 (0:08e1)
; If the player is in an outside map (a town or route), set the z flag
2015-08-31 02:38:41 +00:00
ld a, [wCurMapTileset]
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:: ; 08e9 (0:08e9)
2015-08-31 02:38:41 +00:00
ld a, [wCurMap]
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
2015-08-31 02:38:41 +00:00
ld a, [wCurMapTileset]
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
2014-09-13 07:50:56 +00:00
ld hl, IsPlayerFacingEdgeOfMap
jr .doBankswitch
.useFunction2
2014-09-13 07:50:56 +00:00
ld hl, IsWarpTileInFrontOfPlayer
.doBankswitch
2014-09-13 07:50:56 +00:00
ld b, BANK(IsWarpTileInFrontOfPlayer)
jp Bankswitch
MapEntryAfterBattle:: ; 091f (0:091f)
2014-09-13 07:50:56 +00:00
callba IsPlayerStandingOnWarp ; for enabling warp testing after collisions
ld a,[wMapPalOffset]
and a
2014-09-13 07:50:56 +00:00
jp z,GBFadeInFromWhite
jp LoadGBPal
HandleBlackOut::
; For when all the player's pokemon faint.
; Does not print the "blacked out" message.
2014-09-13 07:50:56 +00:00
call GBFadeOutToBlack
ld a, $08
call StopMusic
ld hl, wd72e
res 5, [hl]
2014-09-13 07:50:56 +00:00
ld a, Bank(ResetStatusAndHalveMoneyOnBlackout) ; also Bank(SpecialWarpIn) and Bank(SpecialEnterMap)
ld [H_LOADEDROMBANK], a
2014-09-14 18:29:18 +00:00
ld [MBC1RomBank], a
2014-09-13 07:50:56 +00:00
call ResetStatusAndHalveMoneyOnBlackout
call SpecialWarpIn
2015-08-09 05:32:44 +00:00
call PlayDefaultMusicFadeOutCurrent
2014-09-13 07:50:56 +00:00
jp SpecialEnterMap
StopMusic::
2015-08-09 05:32:44 +00:00
ld [wAudioFadeOutControl], a
ld a, $ff
2015-08-09 05:32:44 +00:00
ld [wNewSoundID], a
call PlaySound
.wait
2015-08-09 05:32:44 +00:00
ld a, [wAudioFadeOutControl]
and a
jr nz, .wait
jp StopAllSounds
2014-09-13 07:50:56 +00:00
HandleFlyWarpOrDungeonWarp::
call UpdateSprites
call Delay3
xor a
2014-08-09 05:39:13 +00:00
ld [wBattleResult], a
2014-09-13 07:50:56 +00:00
ld [wWalkBikeSurfState], a
2015-08-31 02:38:41 +00:00
ld [wIsInBattle], a
2014-09-13 07:50:56 +00:00
ld [wMapPalOffset], a
ld hl, wd732
2014-09-13 07:50:56 +00:00
set 2, [hl] ; fly warp or dungeon warp
res 5, [hl] ; forced to ride bike
call LeaveMapAnim
2014-09-13 07:50:56 +00:00
ld a, Bank(SpecialWarpIn)
ld [H_LOADEDROMBANK], a
ld [MBC1RomBank], a
2014-09-13 07:50:56 +00:00
call SpecialWarpIn
jp SpecialEnterMap
LeaveMapAnim::
2015-07-19 18:56:13 +00:00
jpba _LeaveMapAnim
LoadPlayerSpriteGraphics::
; Load sprite graphics based on whether the player is standing, biking, or surfing.
; 0: standing
; 1: biking
; 2: surfing
2014-09-13 07:50:56 +00:00
ld a, [wWalkBikeSurfState]
dec a
jr z, .ridingBike
2014-09-14 18:29:18 +00:00
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
2014-09-13 07:50:56 +00:00
ld [wWalkBikeSurfState], a
ld [wWalkBikeSurfStateCopy], a
jp LoadWalkingPlayerSpriteGraphics
.determineGraphics
2014-09-13 07:50:56 +00:00
ld a, [wWalkBikeSurfState]
and a
jp z, LoadWalkingPlayerSpriteGraphics
dec a
jp z, LoadBikePlayerSpriteGraphics
dec a
jp z, LoadSurfingPlayerSpriteGraphics
jp LoadWalkingPlayerSpriteGraphics
IsBikeRidingAllowed::
; The bike can be used on Route 23 and Indigo Plateau,
; or maps with tilesets in BikeRidingTilesets.
; Return carry if biking is allowed.
2015-08-31 02:38:41 +00:00
ld a, [wCurMap]
cp ROUTE_23
jr z, .allowed
cp INDIGO_PLATEAU
jr z, .allowed
2015-08-31 02:38:41 +00:00
ld a, [wCurMapTileset]
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:: ; 09e8 (0:09e8)
2015-08-31 02:38:41 +00:00
ld a,[wTileSetGFXPtr]
ld l,a
2015-08-31 02:38:41 +00:00
ld a,[wTileSetGFXPtr + 1]
ld h,a
ld de,vTileset
ld bc,$600
2015-08-31 02:38:41 +00:00
ld a,[wTileSetBank]
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:: ; 09fc (0:09fc)
; fill C6E8-CBFB with the background tile
ld hl,wOverworldMap
2015-07-20 00:52:26 +00:00
ld a,[wMapBackgroundTile]
ld d,a
ld bc,$0514
.backgroundTileLoop
ld a,d
ld [hli],a
dec bc
ld a,c
or b
jr nz,.backgroundTileLoop
; 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
2015-08-31 02:38:41 +00:00
ld a,[wCurMapWidth]
2015-07-18 15:17:29 +00:00
ld [hMapWidth],a
add a,MAP_BORDER * 2 ; east and west
2015-07-18 15:17:29 +00:00
ld [hMapStride],a ; map width + border
ld b,0
ld c,a
; make space for north border (next 3 lines)
add hl,bc
add hl,bc
add hl,bc
ld c,MAP_BORDER
add hl,bc ; this puts us past the (west) border
2015-08-31 02:38:41 +00:00
ld a,[wMapDataPtr] ; tile map pointer
ld e,a
2015-08-31 02:38:41 +00:00
ld a,[wMapDataPtr + 1]
ld d,a ; de = tile map pointer
2015-08-31 02:38:41 +00:00
ld a,[wCurMapHeight]
ld b,a
.rowLoop ; copy one row each iteration
push hl
2015-07-18 15:17:29 +00:00
ld a,[hMapWidth] ; 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
2015-07-18 15:17:29 +00:00
ld a,[hMapStride] ; map width + border
add l
ld l,a
jr nc,.noCarry
inc h
.noCarry
dec b
jr nz,.rowLoop
.northConnection
2015-08-31 02:38:41 +00:00
ld a,[wMapConn1Ptr]
cp a,$ff
jr z,.southConnection
call SwitchToMapRomBank
2015-07-18 15:17:29 +00:00
ld a,[wNorthConnectionStripSrc]
ld l,a
2015-07-18 15:17:29 +00:00
ld a,[wNorthConnectionStripSrc + 1]
ld h,a
2015-07-18 15:17:29 +00:00
ld a,[wNorthConnectionStripDest]
ld e,a
2015-07-18 15:17:29 +00:00
ld a,[wNorthConnectionStripDest + 1]
ld d,a
2015-07-18 15:17:29 +00:00
ld a,[wNorthConnectionStripWidth]
ld [hNorthSouthConnectionStripWidth],a
ld a,[wNorthConnectedMapWidth]
ld [hNorthSouthConnectedMapWidth],a
call LoadNorthSouthConnectionsTileMap
.southConnection
2015-08-31 02:38:41 +00:00
ld a,[wMapConn2Ptr]
cp a,$ff
jr z,.westConnection
call SwitchToMapRomBank
2015-07-18 15:17:29 +00:00
ld a,[wSouthConnectionStripSrc]
ld l,a
2015-07-18 15:17:29 +00:00
ld a,[wSouthConnectionStripSrc + 1]
ld h,a
2015-07-18 15:17:29 +00:00
ld a,[wSouthConnectionStripDest]
ld e,a
2015-07-18 15:17:29 +00:00
ld a,[wSouthConnectionStripDest + 1]
ld d,a
2015-07-18 15:17:29 +00:00
ld a,[wSouthConnectionStripWidth]
ld [hNorthSouthConnectionStripWidth],a
ld a,[wSouthConnectedMapWidth]
ld [hNorthSouthConnectedMapWidth],a
call LoadNorthSouthConnectionsTileMap
.westConnection
2015-08-31 02:38:41 +00:00
ld a,[wMapConn3Ptr]
cp a,$ff
jr z,.eastConnection
call SwitchToMapRomBank
2015-07-18 15:17:29 +00:00
ld a,[wWestConnectionStripSrc]
ld l,a
2015-07-18 15:17:29 +00:00
ld a,[wWestConnectionStripSrc + 1]
ld h,a
2015-07-18 15:17:29 +00:00
ld a,[wWestConnectionStripDest]
ld e,a
2015-07-18 15:17:29 +00:00
ld a,[wWestConnectionStripDest + 1]
ld d,a
2015-07-18 15:17:29 +00:00
ld a,[wWestConnectionStripHeight]
ld b,a
2015-07-18 15:17:29 +00:00
ld a,[wWestConnectedMapWidth]
ld [hEastWestConnectedMapWidth],a
call LoadEastWestConnectionsTileMap
.eastConnection
2015-08-31 02:38:41 +00:00
ld a,[wMapConn4Ptr]
cp a,$ff
jr z,.done
call SwitchToMapRomBank
2015-07-18 15:17:29 +00:00
ld a,[wEastConnectionStripSrc]
ld l,a
2015-07-18 15:17:29 +00:00
ld a,[wEastConnectionStripSrc + 1]
ld h,a
2015-07-18 15:17:29 +00:00
ld a,[wEastConnectionStripDest]
ld e,a
2015-07-18 15:17:29 +00:00
ld a,[wEastConnectionStripDest + 1]
ld d,a
2015-07-18 15:17:29 +00:00
ld a,[wEastConnectionStripHeight]
ld b,a
2015-07-18 15:17:29 +00:00
ld a,[wEastConnectedMapWidth]
ld [hEastWestConnectedMapWidth],a
call LoadEastWestConnectionsTileMap
.done
ret
LoadNorthSouthConnectionsTileMap:: ; 0ade (0:0ade)
ld c,MAP_BORDER
.loop
push de
push hl
2015-07-18 15:17:29 +00:00
ld a,[hNorthSouthConnectionStripWidth]
ld b,a
.innerLoop
ld a,[hli]
ld [de],a
inc de
dec b
jr nz,.innerLoop
pop hl
pop de
2015-07-18 15:17:29 +00:00
ld a,[hNorthSouthConnectedMapWidth]
add l
ld l,a
jr nc,.noCarry1
inc h
.noCarry1
2015-08-31 02:38:41 +00:00
ld a,[wCurMapWidth]
add a,MAP_BORDER * 2
add e
ld e,a
jr nc,.noCarry2
inc d
.noCarry2
dec c
jr nz,.loop
ret
LoadEastWestConnectionsTileMap:: ; 0b02 (0:0b02)
push hl
push de
ld c,MAP_BORDER
.innerLoop
ld a,[hli]
ld [de],a
inc de
dec c
jr nz,.innerLoop
pop de
pop hl
2015-07-18 15:17:29 +00:00
ld a,[hEastWestConnectedMapWidth]
add l
ld l,a
jr nc,.noCarry1
inc h
.noCarry1
2015-08-31 02:38:41 +00:00
ld a,[wCurMapWidth]
add a,MAP_BORDER * 2
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
2014-09-14 18:29:18 +00:00
; if so, it is stored in [hSpriteIndexOrTextID]
; if not, [hSpriteIndexOrTextID] is set to 0
IsSpriteOrSignInFrontOfPlayer:: ; 0b23 (0:0b23)
xor a
2014-09-14 18:29:18 +00:00
ld [hSpriteIndexOrTextID],a
2015-07-20 00:52:26 +00:00
ld a,[wNumSigns]
and a
jr z,.extendRangeOverCounter
; if there are signs
2014-09-13 07:50:56 +00:00
predef GetTileAndCoordsInFrontOfPlayer ; get the coordinates in front of the player in de
2015-07-20 00:52:26 +00:00
ld hl,wSignCoords
ld a,[wNumSigns]
ld b,a
2015-07-20 00:52:26 +00:00
ld c,0
.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
2015-07-20 00:52:26 +00:00
ld hl,wSignTextIDs
ld b,0
dec c
add hl,bc
ld a,[hl]
2014-09-14 18:29:18 +00:00
ld [hSpriteIndexOrTextID],a ; store sign text ID
pop bc
pop hl
ret
.retry
dec b
jr nz,.signLoop
; 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
.extendRangeOverCounter
2014-09-13 07:50:56 +00:00
predef GetTileAndCoordsInFrontOfPlayer ; get the tile in front of the player in c
2015-08-31 02:38:41 +00:00
ld hl,wTileSetTalkingOverTiles ; list of tiles that extend talking range (counter tiles)
2015-07-20 00:52:26 +00:00
ld b,3
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
; part of the above function, but sometimes its called on its own, when signs are irrelevant
2014-09-14 18:29:18 +00:00
; the caller must zero [hSpriteIndexOrTextID]
IsSpriteInFrontOfPlayer:: ; 0b6b (0:0b6b)
ld d,$10 ; talking range in pixels (normal range)
IsSpriteInFrontOfPlayer2:: ; 0b6d (0:0b6d)
2015-07-20 00:52:26 +00:00
lb bc, $3c, $40 ; Y and X position of player sprite
ld a,[wSpriteStateData1 + 9] ; direction the player is facing
.checkIfPlayerFacingUp
cp SPRITE_FACING_UP
jr nz,.checkIfPlayerFacingDown
; facing up
ld a,b
sub d
ld b,a
2015-07-20 00:52:26 +00:00
ld a,PLAYER_DIR_UP
jr .doneCheckingDirection
.checkIfPlayerFacingDown
cp SPRITE_FACING_DOWN
jr nz,.checkIfPlayerFacingRight
; facing down
ld a,b
add d
ld b,a
2015-07-20 00:52:26 +00:00
ld a,PLAYER_DIR_DOWN
jr .doneCheckingDirection
.checkIfPlayerFacingRight
cp SPRITE_FACING_RIGHT
jr nz,.playerFacingLeft
; facing right
ld a,c
add d
ld c,a
2015-07-20 00:52:26 +00:00
ld a,PLAYER_DIR_RIGHT
jr .doneCheckingDirection
.playerFacingLeft
; facing left
ld a,c
sub d
ld c,a
2015-07-20 00:52:26 +00:00
ld a,PLAYER_DIR_LEFT
.doneCheckingDirection
2015-07-20 00:52:26 +00:00
ld [wPlayerDirection],a
2015-08-31 02:38:41 +00:00
ld a,[wNumSprites] ; number of sprites
and a
ret z
; if there are sprites
ld hl,wSpriteStateData1 + $10
ld d,a
ld e,$01
.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
ret
.foundSpriteInFrontOfPlayer
pop hl
ld a,l
and a,$f0
inc a
2015-08-30 00:15:05 +00:00
ld l,a ; hl = $c1x1
set 7,[hl] ; set flag to make the sprite face the player
ld a,e
2014-09-14 18:29:18 +00:00
ld [hSpriteIndexOrTextID],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:: ; 0bd1 (0:0bd1)
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
2015-07-20 00:52:26 +00:00
ld a,[wPlayerDirection] ; 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,.collision
xor a
2014-09-14 18:29:18 +00:00
ld [hSpriteIndexOrTextID],a
call IsSpriteInFrontOfPlayer ; check for sprite collisions again? when does the above check fail to detect a sprite collision?
2014-09-14 18:29:18 +00:00
ld a,[hSpriteIndexOrTextID]
and a ; was there a sprite collision?
jr nz,.collision
; if no sprite collision
ld hl,TilePairCollisionsLand
call CheckForJumpingAndTilePairCollisions
jr c,.collision
call CheckTilePassable
jr nc,.noCollision
.collision
2015-08-09 05:32:44 +00:00
ld a,[wChannelSoundIDs + CH4]
2015-07-19 08:46:12 +00:00
cp a,SFX_COLLISION ; check if collision sound is already playing
jr z,.setCarry
2015-07-19 08:46:12 +00:00
ld a,SFX_COLLISION
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:: ; 0c10 (0:0c10)
2014-09-13 07:50:56 +00:00
predef GetTileAndCoordsInFrontOfPlayer ; get tile in front of player
ld a,[wTileInFrontOfPlayer] ; tile in front of player
ld c,a
2015-08-31 02:38:41 +00:00
ld hl,wTileSetCollisionPtr ; pointer to list of passable tiles
ld a,[hli]
ld h,[hl]
ld l,a ; hl now points to passable tiles
.loop
ld a,[hli]
cp a,$ff
jr z,.tileNotPassable
cp c
ret z
jr .loop
.tileNotPassable
scf
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:: ; 0c2a (0:0c2a)
push hl
2014-09-13 07:50:56 +00:00
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
2014-09-13 07:50:56 +00:00
CheckForTilePairCollisions2:: ; 0c44 (0:0c44)
aCoord 8, 9 ; tile the player is on
2015-07-15 06:16:06 +00:00
ld [wTilePlayerStandingOn],a
CheckForTilePairCollisions:: ; 0c4a (0:0c4a)
2014-09-13 07:50:56 +00:00
ld a,[wTileInFrontOfPlayer]
ld c,a
.tilePairCollisionLoop
2015-08-31 02:38:41 +00:00
ld a,[wCurMapTileset] ; 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
2015-07-15 06:16:06 +00:00
ld a,[wTilePlayerStandingOn] ; 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:: ; 0c7e (0:0c7e)
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:: ; 0ca0 (0:0ca0)
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:: ; 0caa (0:0caa)
ld a,[H_LOADEDROMBANK]
push af
2015-08-31 02:38:41 +00:00
ld a,[wTileSetBank] ; tile data ROM bank
ld [H_LOADEDROMBANK],a
ld [MBC1RomBank],a ; switch to ROM bank that contains tile data
2014-09-13 07:50:56 +00:00
ld a,[wCurrentTileBlockMapViewPointer] ; address of upper left corner of current map view
ld e,a
2014-09-13 07:50:56 +00:00
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
2015-08-31 02:38:41 +00:00
ld a,[wCurMapWidth]
add a,MAP_BORDER * 2
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
2015-08-31 02:38:41 +00:00
ld a,[wYBlockCoord]
and a
jr z,.adjustForXCoordWithinTileBlock
ld bc,$0030
add hl,bc
.adjustForXCoordWithinTileBlock
2015-08-31 02:38:41 +00:00
ld a,[wXBlockCoord]
and a
jr z,.copyToVisibleAreaBuffer
ld bc,$0002
add hl,bc
.copyToVisibleAreaBuffer
coord de, 0, 0 ; base address for the tiles that are directly transferred to VRAM during V-blank
ld b, SCREEN_HEIGHT
.rowLoop2
ld c, SCREEN_WIDTH
.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
ld [H_LOADEDROMBANK],a
ld [MBC1RomBank],a ; restore previous ROM bank
ret
AdvancePlayerSprite:: ; 0d27 (0:0d27)
ld a,[wSpriteStateData1 + 3] ; delta Y
ld b,a
ld a,[wSpriteStateData1 + 5] ; delta X
ld c,a
ld hl,wWalkCounter ; walking animation counter
dec [hl]
jr nz,.afterUpdateMapCoords
; if it's the end of the animation, update the player's map coordinates
2015-08-31 02:38:41 +00:00
ld a,[wYCoord]
add b
2015-08-31 02:38:41 +00:00
ld [wYCoord],a
ld a,[wXCoord]
add c
2015-08-31 02:38:41 +00:00
ld [wXCoord],a
.afterUpdateMapCoords
ld a,[wWalkCounter] ; walking animation counter
cp a,$07
jp nz,.scrollBackgroundAndSprites
; if this is the first iteration of the animation
ld a,c
cp a,$01
jr nz,.checkIfMovingWest
; moving east
2014-09-14 18:29:18 +00:00
ld a,[wMapViewVRAMPointer]
ld e,a
and a,$e0
ld d,a
ld a,e
add a,$02
and a,$1f
or d
2014-09-14 18:29:18 +00:00
ld [wMapViewVRAMPointer],a
jr .adjustXCoordWithinBlock
.checkIfMovingWest
cp a,$ff
jr nz,.checkIfMovingSouth
; moving west
2014-09-14 18:29:18 +00:00
ld a,[wMapViewVRAMPointer]
ld e,a
and a,$e0
ld d,a
ld a,e
sub a,$02
and a,$1f
or d
2014-09-14 18:29:18 +00:00
ld [wMapViewVRAMPointer],a
jr .adjustXCoordWithinBlock
.checkIfMovingSouth
ld a,b
cp a,$01
jr nz,.checkIfMovingNorth
; moving south
2014-09-14 18:29:18 +00:00
ld a,[wMapViewVRAMPointer]
add a,$40
2014-09-14 18:29:18 +00:00
ld [wMapViewVRAMPointer],a
jr nc,.adjustXCoordWithinBlock
2014-09-14 18:29:18 +00:00
ld a,[wMapViewVRAMPointer + 1]
inc a
and a,$03
or a,$98
2014-09-14 18:29:18 +00:00
ld [wMapViewVRAMPointer + 1],a
jr .adjustXCoordWithinBlock
.checkIfMovingNorth
cp a,$ff
jr nz,.adjustXCoordWithinBlock
; moving north
2014-09-14 18:29:18 +00:00
ld a,[wMapViewVRAMPointer]
sub a,$40
2014-09-14 18:29:18 +00:00
ld [wMapViewVRAMPointer],a
jr nc,.adjustXCoordWithinBlock
2014-09-14 18:29:18 +00:00
ld a,[wMapViewVRAMPointer + 1]
dec a
and a,$03
or a,$98
2014-09-14 18:29:18 +00:00
ld [wMapViewVRAMPointer + 1],a
.adjustXCoordWithinBlock
ld a,c
and a
jr z,.pointlessJump ; mistake?
.pointlessJump
2015-08-31 02:38:41 +00:00
ld hl,wXBlockCoord
ld a,[hl]
add c
ld [hl],a
cp a,$02
jr nz,.checkForMoveToWestBlock
; moved into the tile block to the east
xor a
ld [hl],a
2014-09-13 07:50:56 +00:00
ld hl,wXOffsetSinceLastSpecialWarp
inc [hl]
2014-09-13 07:50:56 +00:00
ld de,wCurrentTileBlockMapViewPointer
call MoveTileBlockMapPointerEast
jr .updateMapView
.checkForMoveToWestBlock
cp a,$ff
jr nz,.adjustYCoordWithinBlock
; moved into the tile block to the west
ld a,$01
ld [hl],a
2014-09-13 07:50:56 +00:00
ld hl,wXOffsetSinceLastSpecialWarp
dec [hl]
2014-09-13 07:50:56 +00:00
ld de,wCurrentTileBlockMapViewPointer
call MoveTileBlockMapPointerWest
jr .updateMapView
.adjustYCoordWithinBlock
2015-08-31 02:38:41 +00:00
ld hl,wYBlockCoord
ld a,[hl]
add b
ld [hl],a
cp a,$02
jr nz,.checkForMoveToNorthBlock
; moved into the tile block to the south
xor a
ld [hl],a
2014-09-13 07:50:56 +00:00
ld hl,wYOffsetSinceLastSpecialWarp
inc [hl]
2014-09-13 07:50:56 +00:00
ld de,wCurrentTileBlockMapViewPointer
2015-08-31 02:38:41 +00:00
ld a,[wCurMapWidth]
call MoveTileBlockMapPointerSouth
jr .updateMapView
.checkForMoveToNorthBlock
cp a,$ff
jr nz,.updateMapView
; moved into the tile block to the north
ld a,$01
ld [hl],a
2014-09-13 07:50:56 +00:00
ld hl,wYOffsetSinceLastSpecialWarp
dec [hl]
2014-09-13 07:50:56 +00:00
ld de,wCurrentTileBlockMapViewPointer
2015-08-31 02:38:41 +00:00
ld a,[wCurMapWidth]
call MoveTileBlockMapPointerNorth
.updateMapView
call LoadCurrentMapView
ld a,[wSpriteStateData1 + 3] ; delta Y
cp a,$01
jr nz,.checkIfMovingNorth2
; if moving south
call ScheduleSouthRowRedraw
jr .scrollBackgroundAndSprites
.checkIfMovingNorth2
cp a,$ff
jr nz,.checkIfMovingEast2
; if moving north
call ScheduleNorthRowRedraw
jr .scrollBackgroundAndSprites
.checkIfMovingEast2
ld a,[wSpriteStateData1 + 5] ; delta X
cp a,$01
jr nz,.checkIfMovingWest2
; if moving east
call ScheduleEastColumnRedraw
jr .scrollBackgroundAndSprites
.checkIfMovingWest2
cp a,$ff
jr nz,.scrollBackgroundAndSprites
; if moving west
call ScheduleWestColumnRedraw
.scrollBackgroundAndSprites
ld a,[wSpriteStateData1 + 3] ; delta Y
ld b,a
ld a,[wSpriteStateData1 + 5] ; delta X
ld c,a
sla b
sla c
2015-02-07 10:43:08 +00:00
ld a,[hSCY]
add b
2015-02-07 10:43:08 +00:00
ld [hSCY],a ; update background scroll Y
ld a,[hSCX]
add c
2015-02-07 10:43:08 +00:00
ld [hSCX],a ; update background scroll X
; shift all the sprites in the direction opposite of the player's motion
; so that the player appears to move relative to them
ld hl,wSpriteStateData1 + $14
2015-08-31 02:38:41 +00:00
ld a,[wNumSprites] ; number of sprites
and a ; are there any sprites?
jr z,.done
ld e,a
.spriteShiftLoop
ld a,[hl]
sub b
ld [hli],a
inc l
ld a,[hl]
sub c
ld [hl],a
ld a,$0e
add l
ld l,a
dec e
jr nz,.spriteShiftLoop
.done
ret
; the following four functions are used to move the pointer to the upper left
; corner of the tile block map in the direction of motion
MoveTileBlockMapPointerEast:: ; 0e65 (0:0e65)
ld a,[de]
add a,$01
ld [de],a
ret nc
inc de
ld a,[de]
inc a
ld [de],a
ret
MoveTileBlockMapPointerWest:: ; 0e6f (0:0e6f)
ld a,[de]
sub a,$01
ld [de],a
ret nc
inc de
ld a,[de]
dec a
ld [de],a
ret
MoveTileBlockMapPointerSouth:: ; 0e79 (0:0e79)
add a,MAP_BORDER * 2
ld b,a
ld a,[de]
add b
ld [de],a
ret nc
inc de
ld a,[de]
inc a
ld [de],a
ret
MoveTileBlockMapPointerNorth:: ; 0e85 (0:0e85)
add a,MAP_BORDER * 2
ld b,a
ld a,[de]
sub b
ld [de],a
ret nc
inc de
ld a,[de]
dec a
ld [de],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:: ; 0e91 (0:0e91)
2015-07-18 20:52:03 +00:00
coord hl, 0, 0
call CopyToRedrawRowOrColumnSrcTiles
2014-09-14 18:29:18 +00:00
ld a,[wMapViewVRAMPointer]
ld [hRedrawRowOrColumnDest],a
2014-09-14 18:29:18 +00:00
ld a,[wMapViewVRAMPointer + 1]
ld [hRedrawRowOrColumnDest + 1],a
ld a,REDRAW_ROW
ld [hRedrawRowOrColumnMode],a
ret
CopyToRedrawRowOrColumnSrcTiles:: ; 0ea6 (0:0ea6)
ld de,wRedrawRowOrColumnSrcTiles
2015-07-19 05:34:11 +00:00
ld c,2 * SCREEN_WIDTH
.loop
ld a,[hli]
ld [de],a
inc de
dec c
jr nz,.loop
ret
ScheduleSouthRowRedraw:: ; 0eb2 (0:0eb2)
2015-07-18 20:52:03 +00:00
coord hl, 0, 16
call CopyToRedrawRowOrColumnSrcTiles
2014-09-14 18:29:18 +00:00
ld a,[wMapViewVRAMPointer]
ld l,a
2014-09-14 18:29:18 +00:00
ld a,[wMapViewVRAMPointer + 1]
ld h,a
ld bc,$0200
add hl,bc
ld a,h
and a,$03
or a,$98
ld [hRedrawRowOrColumnDest + 1],a
ld a,l
ld [hRedrawRowOrColumnDest],a
ld a,REDRAW_ROW
ld [hRedrawRowOrColumnMode],a
ret
ScheduleEastColumnRedraw:: ; 0ed3 (0:0ed3)
2015-07-18 20:52:03 +00:00
coord hl, 18, 0
call ScheduleColumnRedrawHelper
2014-09-14 18:29:18 +00:00
ld a,[wMapViewVRAMPointer]
ld c,a
and a,$e0
ld b,a
ld a,c
add a,18
and a,$1f
or b
ld [hRedrawRowOrColumnDest],a
2014-09-14 18:29:18 +00:00
ld a,[wMapViewVRAMPointer + 1]
ld [hRedrawRowOrColumnDest + 1],a
ld a,REDRAW_COL
ld [hRedrawRowOrColumnMode],a
ret
ScheduleColumnRedrawHelper:: ; 0ef2 (0:0ef2)
ld de,wRedrawRowOrColumnSrcTiles
2015-07-14 07:16:19 +00:00
ld c,SCREEN_HEIGHT
.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:: ; 0f08 (0:0f08)
2015-07-18 20:52:03 +00:00
coord hl, 0, 0
call ScheduleColumnRedrawHelper
2014-09-14 18:29:18 +00:00
ld a,[wMapViewVRAMPointer]
ld [hRedrawRowOrColumnDest],a
2014-09-14 18:29:18 +00:00
ld a,[wMapViewVRAMPointer + 1]
ld [hRedrawRowOrColumnDest + 1],a
ld a,REDRAW_COL
ld [hRedrawRowOrColumnMode],a
ret
; function to write the tiles that make up a tile block to memory
; Input: c = tile block ID, hl = destination address
DrawTileBlock:: ; 0f1d (0:0f1d)
push hl
2015-08-31 02:38:41 +00:00
ld a,[wTileSetBlocksPtr] ; pointer to tiles
ld l,a
2015-08-31 02:38:41 +00:00
ld a,[wTileSetBlocksPtr + 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:: ; 0f4d (0:0f4d)
xor a
ld [wSpriteStateData1 + 3],a
ld [wSpriteStateData1 + 5],a
call RunMapScript
call Joypad
2015-08-31 02:38:41 +00:00
ld a,[wFlags_D733]
bit 3,a ; check if a trainer wants a challenge
jr nz,.notForcedDownwards
2015-08-31 02:38:41 +00:00
ld a,[wCurMap]
cp a,ROUTE_17 ; Cycling Road
jr nz,.notForcedDownwards
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
.notForcedDownwards
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
ld hl,wSimulatedJoypadStatesIndex
dec [hl]
ld a,[hl]
cp a,$ff
jr z,.doneSimulating ; if the end of the simulated button presses has been reached
ld hl,wSimulatedJoypadStatesEnd
add l
ld l,a
jr nc,.noCarry
inc h
.noCarry
ld a,[hl]
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
; 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:: ; 0fb7 (0:0fb7)
ld a,[wd730]
bit 7,a
jp nz,.noCollision ; return and clear carry if button presses are being simulated
2015-07-20 00:52:26 +00:00
ld a,[wPlayerDirection] ; 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
2014-09-13 07:50:56 +00:00
predef GetTileAndCoordsInFrontOfPlayer ; get tile in front of player (puts it in c and [wTileInFrontOfPlayer])
ld a,[wTileInFrontOfPlayer] ; tile in front of player
cp a,$14 ; water tile
jr z,.noCollision ; keep surfing if it's a water tile
cp a,$32 ; either the left tile of the S.S. Anne boarding platform or the tile on eastern coastlines (depending on the current tileset)
jr z,.checkIfVermilionDockTileset
cp a,$48 ; tile on right on coast lines in Safari Zone
jr z,.noCollision ; keep surfing
; check if the [land] tile in front of the player is passable
.checkIfNextTileIsPassable
2015-08-31 02:38:41 +00:00
ld hl,wTileSetCollisionPtr ; pointer to list of passable tiles
ld a,[hli]
ld h,[hl]
ld l,a
.loop
ld a,[hli]
cp a,$ff
jr z,.collision
cp c
jr z,.stopSurfing ; stop surfing if the tile is passable
jr .loop
.collision
2015-08-09 05:32:44 +00:00
ld a,[wChannelSoundIDs + CH4]
2015-07-19 08:46:12 +00:00
cp a,SFX_COLLISION ; check if collision sound is already playing
jr z,.setCarry
2015-07-19 08:46:12 +00:00
ld a,SFX_COLLISION
call PlaySound ; play collision sound (if it's not already playing)
.setCarry
scf
jr .done
.noCollision
and a
.done
ret
.stopSurfing
xor a
2014-09-13 07:50:56 +00:00
ld [wWalkBikeSurfState],a
call LoadPlayerSpriteGraphics
call PlayDefaultMusic
jr .noCollision
.checkIfVermilionDockTileset
2015-08-31 02:38:41 +00:00
ld a, [wCurMapTileset] ; 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
; function to run the current map's script
RunMapScript:: ; 101b (0:101b)
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
2015-08-31 02:38:41 +00:00
ld a,[wCurMap] ; current map number
call SwitchToMapRomBank ; change to the ROM bank the map's data is in
2015-08-31 02:38:41 +00:00
ld hl,wMapScriptPtr
ld a,[hli]
ld h,[hl]
ld l,a
ld de,.return
push de
jp [hl] ; jump to script
.return
ret
LoadWalkingPlayerSpriteGraphics:: ; 104d (0:104d)
ld de,RedSprite
ld hl,vNPCSprites
jr LoadPlayerSpriteGraphicsCommon
LoadSurfingPlayerSpriteGraphics:: ; 1055 (0:1055)
ld de,SeelSprite
ld hl,vNPCSprites
jr LoadPlayerSpriteGraphicsCommon
LoadBikePlayerSpriteGraphics:: ; 105d (0:105d)
ld de,RedCyclingSprite
ld hl,vNPCSprites
LoadPlayerSpriteGraphicsCommon:: ; 1063 (0:1063)
push de
push hl
2015-08-05 21:20:29 +00:00
lb bc, BANK(RedSprite), $0c
call CopyVideoData
pop hl
pop de
ld a,$c0
add e
ld e,a
jr nc,.noCarry
inc d
.noCarry
set 3,h
2015-08-05 21:20:29 +00:00
lb bc, BANK(RedSprite), $0c
jp CopyVideoData
; function to load data from the map header
LoadMapHeader:: ; 107c (0:107c)
2014-09-14 18:29:18 +00:00
callba MarkTownVisitedAndLoadMissableObjects
2015-08-31 02:38:41 +00:00
ld a,[wCurMapTileset]
2015-07-25 03:27:59 +00:00
ld [wUnusedD119],a
2015-08-31 02:38:41 +00:00
ld a,[wCurMap]
call SwitchToMapRomBank
2015-08-31 02:38:41 +00:00
ld a,[wCurMapTileset]
ld b,a
res 7,a
2015-08-31 02:38:41 +00:00
ld [wCurMapTileset],a
2015-07-18 15:17:29 +00:00
ld [hPreviousTileset],a
bit 7,b
ret nz
ld hl,MapHeaderPointers
2015-08-31 02:38:41 +00:00
ld a,[wCurMap]
sla a
jr nc,.noCarry1
inc h
.noCarry1
add l
ld l,a
jr nc,.noCarry2
inc h
.noCarry2
ld a,[hli]
ld h,[hl]
ld l,a ; hl = base of map header
; copy the first 10 bytes (the fixed area) of the map data to D367-D370
2015-08-31 02:38:41 +00:00
ld de,wCurMapTileset
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
2015-08-31 02:38:41 +00:00
ld [wMapConn1Ptr],a
ld [wMapConn2Ptr],a
ld [wMapConn3Ptr],a
ld [wMapConn4Ptr],a
; copy connection data (if any) to WRAM
2015-08-31 02:38:41 +00:00
ld a,[wMapConnections]
ld b,a
.checkNorth
bit 3,b
jr z,.checkSouth
2015-08-31 02:38:41 +00:00
ld de,wMapConn1Ptr
call CopyMapConnectionHeader
.checkSouth
bit 2,b
jr z,.checkWest
2015-08-31 02:38:41 +00:00
ld de,wMapConn2Ptr
call CopyMapConnectionHeader
.checkWest
bit 1,b
jr z,.checkEast
2015-08-31 02:38:41 +00:00
ld de,wMapConn3Ptr
call CopyMapConnectionHeader
.checkEast
bit 0,b
jr z,.getObjectDataPointer
2015-08-31 02:38:41 +00:00
ld de,wMapConn4Ptr
call CopyMapConnectionHeader
.getObjectDataPointer
ld a,[hli]
2015-07-20 00:52:26 +00:00
ld [wObjectDataPointerTemp],a
ld a,[hli]
2015-07-20 00:52:26 +00:00
ld [wObjectDataPointerTemp + 1],a
push hl
2015-07-20 00:52:26 +00:00
ld a,[wObjectDataPointerTemp]
ld l,a
2015-07-20 00:52:26 +00:00
ld a,[wObjectDataPointerTemp + 1]
ld h,a ; hl = base of object data
2015-07-20 00:52:26 +00:00
ld de,wMapBackgroundTile
ld a,[hli]
2015-07-20 00:52:26 +00:00
ld [de],a
.loadWarpData
2014-09-13 07:50:56 +00:00
ld a,[hli]
ld [wNumberOfWarps],a
and a
jr z,.loadSignData
ld c,a
2014-09-13 07:50:56 +00:00
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
2015-07-20 00:52:26 +00:00
ld [wNumSigns],a
and a ; are there any signs?
jr z,.loadSpriteData ; if not, skip this
ld c,a
2015-07-20 00:52:26 +00:00
ld de,wSignTextIDs
ld a,d
2015-07-20 00:52:26 +00:00
ld [hSignCoordPointer],a
ld a,e
2015-07-20 00:52:26 +00:00
ld [hSignCoordPointer + 1],a
ld de,wSignCoords
.signLoop
ld a,[hli]
ld [de],a
inc de
ld a,[hli]
ld [de],a
inc de
push de
2015-07-20 00:52:26 +00:00
ld a,[hSignCoordPointer]
ld d,a
2015-07-20 00:52:26 +00:00
ld a,[hSignCoordPointer + 1]
ld e,a
ld a,[hli]
ld [de],a
inc de
ld a,d
2015-07-20 00:52:26 +00:00
ld [hSignCoordPointer],a
ld a,e
2015-07-20 00:52:26 +00:00
ld [hSignCoordPointer + 1],a
pop de
dec c
jr nz,.signLoop
.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
ld a,[hli]
2015-08-31 02:38:41 +00:00
ld [wNumSprites],a ; save the number of sprites
push hl
; zero C110-C1FF and C210-C2FF
ld hl,wSpriteStateData1 + $10
ld de,wSpriteStateData2 + $10
xor a
ld b,$f0
.zeroSpriteDataLoop
ld [hli],a
ld [de],a
inc e
dec b
jr nz,.zeroSpriteDataLoop
; initialize all C100-C1FF sprite entries to disabled (other than player's)
ld hl,wSpriteStateData1 + $12
ld de,$0010
ld c,$0f
.disableSpriteEntriesLoop
ld [hl],$ff
add hl,de
dec c
jr nz,.disableSpriteEntriesLoop
pop hl
ld de,wSpriteStateData1 + $10
2015-08-31 02:38:41 +00:00
ld a,[wNumSprites] ; number of sprites
and a ; are there any sprites?
jp z,.finishUp ; if there are no sprites, skip the rest
ld b,a
ld c,$00
.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]
2015-07-18 15:17:29 +00:00
ld [hLoadSpriteTemp1],a ; save movement byte 2
ld a,[hli]
2015-07-18 15:17:29 +00:00
ld [hLoadSpriteTemp2],a ; save text ID and flags byte
push bc
push hl
ld b,$00
2015-08-31 02:38:41 +00:00
ld hl,wMapSpriteData
add hl,bc
2015-07-18 15:17:29 +00:00
ld a,[hLoadSpriteTemp1]
ld [hli],a ; store movement byte 2 in byte 0 of sprite entry
2015-07-18 15:17:29 +00:00
ld a,[hLoadSpriteTemp2]
ld [hl],a ; this appears pointless, since the value is overwritten immediately after
2015-07-18 15:17:29 +00:00
ld a,[hLoadSpriteTemp2]
ld [hLoadSpriteTemp1],a
and a,$3f
ld [hl],a ; store text ID in byte 1 of sprite entry
pop hl
2015-07-18 15:17:29 +00:00
ld a,[hLoadSpriteTemp1]
bit 6,a
jr nz,.trainerSprite
bit 7,a
jr nz,.itemBallSprite
jr .regularSprite
.trainerSprite
ld a,[hli]
2015-07-18 15:17:29 +00:00
ld [hLoadSpriteTemp1],a ; save trainer class
ld a,[hli]
2015-07-18 15:17:29 +00:00
ld [hLoadSpriteTemp2],a ; save trainer number (within class)
push hl
2015-08-31 02:38:41 +00:00
ld hl,wMapSpriteExtraData
add hl,bc
2015-07-18 15:17:29 +00:00
ld a,[hLoadSpriteTemp1]
ld [hli],a ; store trainer class in byte 0 of the entry
2015-07-18 15:17:29 +00:00
ld a,[hLoadSpriteTemp2]
ld [hl],a ; store trainer number in byte 1 of the entry
pop hl
jr .nextSprite
.itemBallSprite
ld a,[hli]
2015-07-18 15:17:29 +00:00
ld [hLoadSpriteTemp1],a ; save item number
push hl
2015-08-31 02:38:41 +00:00
ld hl,wMapSpriteExtraData
add hl,bc
2015-07-18 15:17:29 +00:00
ld a,[hLoadSpriteTemp1]
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
jr .nextSprite
.regularSprite
push hl
2015-08-31 02:38:41 +00:00
ld hl,wMapSpriteExtraData
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
.nextSprite
pop bc
dec d
ld a,$0a
add e
ld e,a
inc c
inc c
dec b
jp nz,.loadSpriteLoop
.finishUp
2014-09-13 07:50:56 +00:00
predef LoadTilesetHeader
callab LoadWildData
pop hl ; restore hl from before going to the warp/sign/sprite data (this value was saved for seemingly no purpose)
2015-08-31 02:38:41 +00:00
ld a,[wCurMapHeight] ; map height in 4x4 tile blocks
add a ; double it
2015-07-20 00:52:26 +00:00
ld [wCurrentMapHeight2],a ; store map height in 2x2 tile blocks
2015-08-31 02:38:41 +00:00
ld a,[wCurMapWidth] ; map width in 4x4 tile blocks
add a ; double it
2015-07-20 00:52:26 +00:00
ld [wCurrentMapWidth2],a ; map width in 2x2 tile blocks
2015-08-31 02:38:41 +00:00
ld a,[wCurMap]
ld c,a
ld b,$00
ld a,[H_LOADEDROMBANK]
push af
ld a, BANK(MapSongBanks)
ld [H_LOADEDROMBANK],a
ld [MBC1RomBank],a
ld hl, MapSongBanks
add hl,bc
add hl,bc
ld a,[hli]
2015-08-09 05:32:44 +00:00
ld [wMapMusicSoundID],a ; music 1
ld a,[hl]
2015-08-09 05:32:44 +00:00
ld [wMapMusicROMBank],a ; music 2
pop af
ld [H_LOADEDROMBANK],a
ld [MBC1RomBank],a
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
; function to load map data
LoadMapData:: ; 1241 (0:1241)
ld a,[H_LOADEDROMBANK]
push af
call DisableLCD
ld a,$98
2014-09-14 18:29:18 +00:00
ld [wMapViewVRAMPointer + 1],a
xor a
2014-09-14 18:29:18 +00:00
ld [wMapViewVRAMPointer],a
2015-02-07 10:43:08 +00:00
ld [hSCY],a
ld [hSCX],a
ld [wWalkCounter],a
2015-07-25 03:27:59 +00:00
ld [wUnusedD119],a
2014-09-13 07:50:56 +00:00
ld [wWalkBikeSurfStateCopy],a
2015-08-31 02:38:41 +00:00
ld [wSpriteSetID],a
call LoadTextBoxTilePatterns
call LoadMapHeader
callba InitMapSprites ; load tile pattern data for sprites
call LoadTileBlockMap
call LoadTilesetTilePatternData
call LoadCurrentMapView
; copy current map view to VRAM
2015-07-18 20:52:03 +00:00
coord hl, 0, 0
ld de,vBGMap0
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
add e
ld e,a
jr nc,.noCarry
inc d
.noCarry
dec b
jr nz,.vramCopyLoop
ld a,$01
2014-09-13 07:50:56 +00:00
ld [wUpdateSpritesEnabled],a
call EnableLCD
2015-08-12 09:16:56 +00:00
ld b, SET_PAL_OVERWORLD
call RunPaletteCommand
call LoadPlayerSpriteGraphics
ld a,[wd732]
2014-09-13 07:50:56 +00:00
and a,1 << 4 | 1 << 3 ; fly warp or dungeon warp
jr nz,.restoreRomBank
2015-08-31 02:38:41 +00:00
ld a,[wFlags_D733]
bit 1,a
jr nz,.restoreRomBank
2015-08-09 05:32:44 +00:00
call UpdateMusic6Times
call PlayDefaultMusicFadeOutCurrent
.restoreRomBank
pop af
ld [H_LOADEDROMBANK],a
ld [MBC1RomBank],a
ret
; function to switch to the ROM bank that a map is stored in
; Input: a = map number
SwitchToMapRomBank:: ; 12bc (0:12bc)
push hl
push bc
ld c,a
ld b,$00
ld a,Bank(MapHeaderBanks)
call BankswitchHome ; switch to ROM bank 3
ld hl,MapHeaderBanks
add hl,bc
ld a,[hl]
ld [$ffe8],a ; save map ROM bank
call BankswitchBack
ld a,[$ffe8]
ld [H_LOADEDROMBANK],a
ld [MBC1RomBank],a ; switch to map ROM bank
pop bc
pop hl
ret
2014-09-14 18:29:18 +00:00
IgnoreInputForHalfSecond: ; 12da (0:12da)
ld a, 30
ld [wIgnoreInputCounter], a
ld hl, wd730
ld a, [hl]
or $26
2014-09-14 18:29:18 +00:00
ld [hl], a ; set ignore input bit
ret
2014-09-14 18:29:18 +00:00
ResetUsingStrengthOutOfBattleBit: ; 12e7 (0:12e7)
ld hl, wd728
res 0, [hl]
ret
ForceBikeOrSurf:: ; 12ed (0:12ed)
ld b, BANK(RedSprite)
ld hl, LoadPlayerSpriteGraphics
call Bankswitch
jp PlayDefaultMusic ; update map/player state?