This commit is contained in:
dannye 2021-03-23 00:53:43 -05:00
commit e8dd755e18
3702 changed files with 163333 additions and 159040 deletions

View file

@ -1,4 +1,4 @@
PlayerStepOutFromDoor:
PlayerStepOutFromDoor::
ld hl, wd730
res 1, [hl]
call IsPlayerStandingOnDoorTile
@ -12,7 +12,7 @@ PlayerStepOutFromDoor:
ld a, D_DOWN
ld [wSimulatedJoypadStatesEnd], a
xor a
ld [wSpriteStateData1 + 2], a
ld [wSpritePlayerStateData1ImageIndex], a
call StartSimulatingJoypadStates
ret
.notStandingOnDoor
@ -27,7 +27,7 @@ PlayerStepOutFromDoor:
res 7, [hl]
ret
_EndNPCMovementScript:
_EndNPCMovementScript::
ld hl, wd730
res 7, [hl]
ld hl, wd72e
@ -44,7 +44,7 @@ _EndNPCMovementScript:
ld [wSimulatedJoypadStatesEnd], a
ret
PalletMovementScriptPointerTable:
PalletMovementScriptPointerTable::
dw PalletMovementScript_OakMoveLeft
dw PalletMovementScript_PlayerMoveLeft
dw PalletMovementScript_WaitAndWalkToLab
@ -66,7 +66,7 @@ PalletMovementScript_OakMoveLeft:
call FillMemory
ld [hl], $ff
ld a, [wSpriteIndex]
ld [H_SPRITEINDEX], a
ldh [hSpriteIndex], a
ld de, wNPCMovementDirections2
call MoveSprite
ld a, $1
@ -91,7 +91,7 @@ PalletMovementScript_PlayerMoveLeft:
ret nz ; return if Oak is still moving
ld a, [wNumStepsToTake]
ld [wSimulatedJoypadStatesIndex], a
ld [hNPCMovementDirections2Index], a
ldh [hNPCMovementDirections2Index], a
predef ConvertNPCMovementDirectionsToJoypadMasks
call StartSimulatingJoypadStates
ld a, $2
@ -110,7 +110,7 @@ PalletMovementScript_WalkToLab:
swap a
ld [wNPCMovementScriptSpriteOffset], a
xor a
ld [wSpriteStateData2 + $06], a
ld [wSpritePlayerStateData2MovementByte1], a
ld hl, wSimulatedJoypadStatesEnd
ld de, RLEList_PlayerWalkToLab
call DecodeRLEList
@ -128,21 +128,21 @@ PalletMovementScript_WalkToLab:
ret
RLEList_ProfOakWalkToLab:
db NPC_MOVEMENT_DOWN, $05
db NPC_MOVEMENT_LEFT, $01
db NPC_MOVEMENT_DOWN, $05
db NPC_MOVEMENT_RIGHT, $03
db NPC_MOVEMENT_UP, $01
db $E0, $01 ; stand still
db $FF
db NPC_MOVEMENT_DOWN, 5
db NPC_MOVEMENT_LEFT, 1
db NPC_MOVEMENT_DOWN, 5
db NPC_MOVEMENT_RIGHT, 3
db NPC_MOVEMENT_UP, 1
db NPC_CHANGE_FACING, 1
db -1 ; end
RLEList_PlayerWalkToLab:
db D_UP, $02
db D_RIGHT, $03
db D_DOWN, $05
db D_LEFT, $01
db D_DOWN, $06
db $FF
db D_UP, 2
db D_RIGHT, 3
db D_DOWN, 5
db D_LEFT, 1
db D_DOWN, 6
db -1 ; end
PalletMovementScript_Done:
ld a, [wSimulatedJoypadStatesIndex]
@ -157,7 +157,7 @@ PalletMovementScript_Done:
res 7, [hl]
jp EndNPCMovementScript
PewterMuseumGuyMovementScriptPointerTable:
PewterMuseumGuyMovementScriptPointerTable::
dw PewterMovementScript_WalkToMuseum
dw PewterMovementScript_Done
@ -190,18 +190,18 @@ PewterMovementScript_WalkToMuseum:
ret
RLEList_PewterMuseumPlayer:
db 0, $01
db D_UP, $03
db D_LEFT, $0D
db D_UP, $06
db $FF
db NO_INPUT, 1
db D_UP, 3
db D_LEFT, 13
db D_UP, 6
db -1 ; end
RLEList_PewterMuseumGuy:
db NPC_MOVEMENT_UP, $06
db NPC_MOVEMENT_LEFT, $0D
db NPC_MOVEMENT_UP, $03
db NPC_MOVEMENT_LEFT, $01
db $FF
db NPC_MOVEMENT_UP, 6
db NPC_MOVEMENT_LEFT, 13
db NPC_MOVEMENT_UP, 3
db NPC_MOVEMENT_LEFT, 1
db -1 ; end
PewterMovementScript_Done:
ld a, [wSimulatedJoypadStatesIndex]
@ -213,7 +213,7 @@ PewterMovementScript_Done:
res 7, [hl]
jp EndNPCMovementScript
PewterGymGuyMovementScriptPointerTable:
PewterGymGuyMovementScriptPointerTable::
dw PewterMovementScript_WalkToGym
dw PewterMovementScript_Done
@ -228,7 +228,7 @@ PewterMovementScript_WalkToGym:
swap a
ld [wNPCMovementScriptSpriteOffset], a
xor a
ld [wSpriteStateData2 + $06], a
ld [wSpritePlayerStateData2MovementByte1], a
ld hl, wSimulatedJoypadStatesEnd
ld de, RLEList_PewterGymPlayer
call DecodeRLEList
@ -249,24 +249,24 @@ PewterMovementScript_WalkToGym:
ret
RLEList_PewterGymPlayer:
db 0, $01
db D_RIGHT, $02
db D_DOWN, $05
db D_LEFT, $0B
db D_UP, $05
db D_LEFT, $0F
db $FF
db NO_INPUT, 1
db D_RIGHT, 2
db D_DOWN, 5
db D_LEFT, 11
db D_UP, 5
db D_LEFT, 15
db -1 ; end
RLEList_PewterGymGuy:
db NPC_MOVEMENT_DOWN, $02
db NPC_MOVEMENT_LEFT, $0F
db NPC_MOVEMENT_UP, $05
db NPC_MOVEMENT_LEFT, $0B
db NPC_MOVEMENT_DOWN, $05
db NPC_MOVEMENT_RIGHT, $03
db $FF
db NPC_MOVEMENT_DOWN, 2
db NPC_MOVEMENT_LEFT, 15
db NPC_MOVEMENT_UP, 5
db NPC_MOVEMENT_LEFT, 11
db NPC_MOVEMENT_DOWN, 5
db NPC_MOVEMENT_RIGHT, 3
db -1 ; end
FreezeEnemyTrainerSprite:
FreezeEnemyTrainerSprite::
ld a, [wCurMap]
cp POKEMON_TOWER_7F
ret z ; the Rockets on Pokemon Tower 7F leave after battling, so don't freeze them
@ -275,18 +275,18 @@ FreezeEnemyTrainerSprite:
ld b, a
.loop
ld a, [hli]
cp $ff
cp -1
jr z, .notRival
cp b
ret z ; the rival leaves after battling, so don't freeze him
jr .loop
.notRival
ld a, [wSpriteIndex]
ld [H_SPRITEINDEX], a
ldh [hSpriteIndex], a
jp SetSpriteMovementBytesToFF
RivalIDs:
db OPP_SONY1
db OPP_SONY2
db OPP_SONY3
db $ff
db OPP_RIVAL1
db OPP_RIVAL2
db OPP_RIVAL3
db -1 ; end

View file

@ -1,151 +0,0 @@
CableClubNPC:
ld hl, CableClubNPCWelcomeText
call PrintText
CheckEvent EVENT_GOT_POKEDEX
jp nz, .receivedPokedex
; if the player hasn't received the pokedex
ld c, 60
call DelayFrames
ld hl, CableClubNPCMakingPreparationsText
call PrintText
jp .didNotConnect
.receivedPokedex
ld a, $1
ld [wMenuJoypadPollCount], a
ld a, 90
ld [wLinkTimeoutCounter], a
.establishConnectionLoop
ld a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
jr z, .establishedConnection
cp USING_EXTERNAL_CLOCK
jr z, .establishedConnection
ld a, CONNECTION_NOT_ESTABLISHED
ld [hSerialConnectionStatus], a
ld a, ESTABLISH_CONNECTION_WITH_EXTERNAL_CLOCK
ld [rSB], a
xor a
ld [hSerialReceiveData], a
ld a, START_TRANSFER_EXTERNAL_CLOCK
ld [rSC], a
ld a, [wLinkTimeoutCounter]
dec a
ld [wLinkTimeoutCounter], a
jr z, .failedToEstablishConnection
ld a, ESTABLISH_CONNECTION_WITH_INTERNAL_CLOCK
ld [rSB], a
ld a, START_TRANSFER_INTERNAL_CLOCK
ld [rSC], a
call DelayFrame
jr .establishConnectionLoop
.establishedConnection
call Serial_SendZeroByte
call DelayFrame
call Serial_SendZeroByte
ld c, 50
call DelayFrames
ld hl, CableClubNPCPleaseApplyHereHaveToSaveText
call PrintText
xor a
ld [wMenuJoypadPollCount], a
call YesNoChoice
ld a, $1
ld [wMenuJoypadPollCount], a
ld a, [wCurrentMenuItem]
and a
jr nz, .choseNo
callab SaveSAVtoSRAM
call WaitForSoundToFinish
ld a, SFX_SAVE
call PlaySoundWaitForCurrent
ld hl, CableClubNPCPleaseWaitText
call PrintText
ld hl, wUnknownSerialCounter
ld a, $3
ld [hli], a
xor a
ld [hl], a
ld [hSerialReceivedNewData], a
ld [wSerialExchangeNybbleSendData], a
call Serial_SyncAndExchangeNybble
ld hl, wUnknownSerialCounter
ld a, [hli]
inc a
jr nz, .connected
ld a, [hl]
inc a
jr nz, .connected
ld b, 10
.syncLoop
call DelayFrame
call Serial_SendZeroByte
dec b
jr nz, .syncLoop
call CloseLinkConnection
ld hl, CableClubNPCLinkClosedBecauseOfInactivityText
call PrintText
jr .didNotConnect
.failedToEstablishConnection
ld hl, CableClubNPCAreaReservedFor2FriendsLinkedByCableText
call PrintText
jr .didNotConnect
.choseNo
call CloseLinkConnection
ld hl, CableClubNPCPleaseComeAgainText
call PrintText
.didNotConnect
xor a
ld hl, wUnknownSerialCounter
ld [hli], a
ld [hl], a
ld hl, wd72e
res 6, [hl]
xor a
ld [wMenuJoypadPollCount], a
ret
.connected
xor a
ld [hld], a
ld [hl], a
jpab LinkMenu
CableClubNPCAreaReservedFor2FriendsLinkedByCableText:
TX_FAR _CableClubNPCAreaReservedFor2FriendsLinkedByCableText
db "@"
CableClubNPCWelcomeText:
TX_FAR _CableClubNPCWelcomeText
db "@"
CableClubNPCPleaseApplyHereHaveToSaveText:
TX_FAR _CableClubNPCPleaseApplyHereHaveToSaveText
db "@"
CableClubNPCPleaseWaitText:
TX_FAR _CableClubNPCPleaseWaitText
TX_DELAY
db "@"
CableClubNPCLinkClosedBecauseOfInactivityText:
TX_FAR _CableClubNPCLinkClosedBecauseOfInactivityText
db "@"
CableClubNPCPleaseComeAgainText:
TX_FAR _CableClubNPCPleaseComeAgainText
db "@"
CableClubNPCMakingPreparationsText:
TX_FAR _CableClubNPCMakingPreparationsText
db "@"
CloseLinkConnection:
call Delay3
ld a, CONNECTION_NOT_ESTABLISHED
ld [hSerialConnectionStatus], a
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

View file

@ -1,112 +0,0 @@
PrintCardKeyText:
ld hl, SilphCoMapList
ld a, [wCurMap]
ld b, a
.silphCoMapListLoop
ld a, [hli]
cp $ff
ret z
cp b
jr nz, .silphCoMapListLoop
predef GetTileAndCoordsInFrontOfPlayer
ld a, [wTileInFrontOfPlayer]
cp $18
jr z, .cardKeyDoorInFrontOfPlayer
cp $24
jr z, .cardKeyDoorInFrontOfPlayer
ld b, a
ld a, [wCurMap]
cp SILPH_CO_11F
ret nz
ld a, b
cp $5e
ret nz
.cardKeyDoorInFrontOfPlayer
ld b, CARD_KEY
call IsItemInBag
jr z, .noCardKey
call GetCoordsInFrontOfPlayer
push de
tx_pre_id CardKeySuccessText
ld [hSpriteIndexOrTextID], a
call PrintPredefTextID
pop de
srl d
ld a, d
ld b, a
ld [wCardKeyDoorY], a
srl e
ld a, e
ld c, a
ld [wCardKeyDoorX], a
ld a, [wCurMap]
cp SILPH_CO_11F
jr nz, .notSilphCo11F
ld a, $3
jr .replaceCardKeyDoorTileBlock
.notSilphCo11F
ld a, $e
.replaceCardKeyDoorTileBlock
ld [wNewTileBlockID], a
predef ReplaceTileBlock
ld hl, wCurrentMapScriptFlags
set 5, [hl]
ld a, SFX_GO_INSIDE
jp PlaySound
.noCardKey
tx_pre_id CardKeyFailText
ld [hSpriteIndexOrTextID], a
jp PrintPredefTextID
SilphCoMapList:
db SILPH_CO_2F
db SILPH_CO_3F
db SILPH_CO_4F
db SILPH_CO_5F
db SILPH_CO_6F
db SILPH_CO_7F
db SILPH_CO_8F
db SILPH_CO_9F
db SILPH_CO_10F
db SILPH_CO_11F
db $FF
CardKeySuccessText:
TX_FAR _CardKeySuccessText1
TX_SFX_ITEM_1
TX_FAR _CardKeySuccessText2
db "@"
CardKeyFailText:
TX_FAR _CardKeyFailText
db "@"
; d = Y
; e = X
GetCoordsInFrontOfPlayer:
ld a, [wYCoord]
ld d, a
ld a, [wXCoord]
ld e, a
ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
and a
jr nz, .notFacingDown
; facing down
inc d
ret
.notFacingDown
cp SPRITE_FACING_UP
jr nz, .notFacingUp
; facing up
dec d
ret
.notFacingUp
cp SPRITE_FACING_LEFT
jr nz, .notFacingLeft
; facing left
dec e
ret
.notFacingLeft
; facing right
inc e
ret

View file

@ -1,123 +0,0 @@
GiveFossilToCinnabarLab:
ld hl, wd730
set 6, [hl]
xor a
ld [wCurrentMenuItem], a
ld a, A_BUTTON | B_BUTTON
ld [wMenuWatchedKeys], a
ld a, [wFilteredBagItemsCount]
dec a
ld [wMaxMenuItem], a
ld a, 2
ld [wTopMenuItemY], a
ld a, 1
ld [wTopMenuItemX], a
ld a, [wFilteredBagItemsCount]
dec a
ld bc, 2
ld hl, 3
call AddNTimes
dec l
ld b, l
ld c, $d
coord hl, 0, 0
call TextBoxBorder
call UpdateSprites
call PrintFossilsInBag
ld hl, wd730
res 6, [hl]
call HandleMenuInput
bit 1, a ; pressed B?
jr nz, .cancelledGivingFossil
ld hl, wFilteredBagItems
ld a, [wCurrentMenuItem]
ld d, 0
ld e, a
add hl, de
ld a, [hl]
ld [$ffdb], a
cp DOME_FOSSIL
jr z, .choseDomeFossil
cp HELIX_FOSSIL
jr z, .choseHelixFossil
ld b, AERODACTYL
jr .fossilSelected
.choseHelixFossil
ld b, OMANYTE
jr .fossilSelected
.choseDomeFossil
ld b, KABUTO
.fossilSelected
ld [wFossilItem], a
ld a, b
ld [wFossilMon], a
call LoadFossilItemAndMonName
ld hl, LabFossil_610ae
call PrintText
call YesNoChoice
ld a, [wCurrentMenuItem]
and a
jr nz, .cancelledGivingFossil
ld hl, LabFossil_610b3
call PrintText
ld a, [wFossilItem]
ld [hItemToRemoveID], a
callba RemoveItemByID
ld hl, LabFossil_610b8
call PrintText
SetEvents EVENT_GAVE_FOSSIL_TO_LAB, EVENT_LAB_STILL_REVIVING_FOSSIL
ret
.cancelledGivingFossil
ld hl, LabFossil_610bd
call PrintText
ret
LabFossil_610ae:
TX_FAR _Lab4Text_610ae
db "@"
LabFossil_610b3:
TX_FAR _Lab4Text_610b3
db "@"
LabFossil_610b8:
TX_FAR _Lab4Text_610b8
db "@"
LabFossil_610bd:
TX_FAR _Lab4Text_610bd
db "@"
PrintFossilsInBag:
; Prints each fossil in the player's bag on a separate line in the menu.
ld hl, wFilteredBagItems
xor a
ld [hItemCounter], a
.loop
ld a, [hli]
cp $ff
ret z
push hl
ld [wd11e], a
call GetItemName
coord hl, 2, 2
ld a, [hItemCounter]
ld bc, SCREEN_WIDTH * 2
call AddNTimes
ld de, wcd6d
call PlaceString
ld hl, hItemCounter
inc [hl]
pop hl
jr .loop
; loads the names of the fossil item and the resulting mon
LoadFossilItemAndMonName:
ld a, [wFossilMon]
ld [wd11e], a
call GetMonName
call CopyStringToCF4B
ld a, [wFossilItem]
ld [wd11e], a
call GetItemName
ret

View file

@ -1,14 +1,14 @@
ClearVariablesOnEnterMap:
ld a, SCREEN_HEIGHT_PIXELS
ld [hWY], a
ld [rWY], a
ClearVariablesOnEnterMap::
ld a, SCREEN_HEIGHT_PX
ldh [hWY], a
ldh [rWY], a
xor a
ld [H_AUTOBGTRANSFERENABLED], a
ldh [hAutoBGTransferEnabled], a
ld [wStepCounter], a
ld [wLoneAttackNo], a
ld [hJoyPressed], a
ld [hJoyReleased], a
ld [hJoyHeld], a
ldh [hJoyPressed], a
ldh [hJoyReleased], a
ldh [hJoyHeld], a
ld [wActionResultOrTookBattleTurn], a
ld [wUnusedD5A3], a
ld hl, wCardKeyDoorY

66
engine/overworld/cut.asm Executable file → Normal file
View file

@ -22,8 +22,8 @@ UsedCut:
jp PrintText
.NothingToCutText
TX_FAR _NothingToCutText
db "@"
text_far _NothingToCutText
text_end
.canCut
ld [wCutTile], a
@ -37,15 +37,15 @@ UsedCut:
call GBPalWhiteOutWithDelay3
call ClearSprites
call RestoreScreenTilesAndReloadTilePatterns
ld a, SCREEN_HEIGHT_PIXELS
ld [hWY], a
ld a, SCREEN_HEIGHT_PX
ldh [hWY], a
call Delay3
call LoadGBPal
call LoadCurrentMapView
call SaveScreenTilesToBuffer2
call Delay3
xor a
ld [hWY], a
ldh [hWY], a
ld hl, UsedCutText
call PrintText
call LoadScreenTilesFromBuffer2
@ -57,46 +57,46 @@ UsedCut:
ld de, CutTreeBlockSwaps
call ReplaceTreeTileBlock
call RedrawMapView
callba AnimCut
farcall AnimCut
ld a, $1
ld [wUpdateSpritesEnabled], a
ld a, SFX_CUT
call PlaySound
ld a, $90
ld [hWY], a
ldh [hWY], a
call UpdateSprites
jp RedrawMapView
UsedCutText:
TX_FAR _UsedCutText
db "@"
text_far _UsedCutText
text_end
InitCutAnimOAM:
xor a
ld [wWhichAnimationOffsets], a
ld a, %11100100
ld [rOBP1], a
ldh [rOBP1], a
ld a, [wCutTile]
cp $52
jr z, .grass
; tree
ld de, Overworld_GFX + $2d0 ; cuttable tree sprite top row
ld hl, vChars1 + $7c0
lb bc, BANK(Overworld_GFX), $02
ld de, Overworld_GFX tile $2d ; cuttable tree sprite top row
ld hl, vChars1 tile $7c
lb bc, BANK(Overworld_GFX), 2
call CopyVideoData
ld de, Overworld_GFX + $3d0 ; cuttable tree sprite bottom row
ld hl, vChars1 + $7e0
lb bc, BANK(Overworld_GFX), $02
ld de, Overworld_GFX tile $3d ; cuttable tree sprite bottom row
ld hl, vChars1 tile $7e
lb bc, BANK(Overworld_GFX), 2
call CopyVideoData
jr WriteCutOrBoulderDustAnimationOAMBlock
.grass
ld hl, vChars1 + $7c0
ld hl, vChars1 tile $7c
call LoadCutGrassAnimationTilePattern
ld hl, vChars1 + $7d0
ld hl, vChars1 tile $7d
call LoadCutGrassAnimationTilePattern
ld hl, vChars1 + $7e0
ld hl, vChars1 tile $7e
call LoadCutGrassAnimationTilePattern
ld hl, vChars1 + $7f0
ld hl, vChars1 tile $7f
call LoadCutGrassAnimationTilePattern
call WriteCutOrBoulderDustAnimationOAMBlock
ld hl, wOAMBuffer + $93
@ -112,8 +112,8 @@ InitCutAnimOAM:
ret
LoadCutGrassAnimationTilePattern:
ld de, AnimationTileset2 + $60 ; tile depicting a leaf
lb bc, BANK(AnimationTileset2), $01
ld de, AnimationTileset2 tile 6 ; tile depicting a leaf
lb bc, BANK(AnimationTileset2), 1
jp CopyVideoData
WriteCutOrBoulderDustAnimationOAMBlock:
@ -123,11 +123,11 @@ WriteCutOrBoulderDustAnimationOAMBlock:
jp WriteOAMBlock
CutOrBoulderDustAnimationTilesAndAttributes:
db $FC,$10,$FD,$10
db $FE,$10,$FF,$10
dbsprite 2, -1, 0, 4, $fd, OAM_OBP1
dbsprite 2, -1, 0, 6, $ff, OAM_OBP1
GetCutOrBoulderDustAnimationOffsets:
ld hl, wSpriteStateData1 + 4
ld hl, wSpritePlayerStateData1YPixels
ld a, [hli] ; player's sprite screen Y position
ld b, a
inc hl
@ -187,7 +187,7 @@ ReplaceTreeTileBlock:
ld h, [hl]
ld l, a
add hl, bc
ld a, [wSpriteStateData1 + 9] ; player sprite's facing direction
ld a, [wSpritePlayerStateData1FacingDirection]
and a
jr z, .down
cp SPRITE_FACING_UP
@ -248,16 +248,4 @@ ReplaceTreeTileBlock:
ld [hl], a
ret
CutTreeBlockSwaps:
; first byte = tileset block containing the cut tree
; second byte = corresponding tileset block after the cut animation happens
db $32, $6D
db $33, $6C
db $34, $6F
db $35, $4C
db $60, $6E
db $0B, $0A
db $3C, $35
db $3F, $35
db $3D, $36
db $FF ; list terminator
INCLUDE "data/tilesets/cut_tree_blocks.asm"

8
engine/overworld/cut2.asm Executable file → Normal file
View file

@ -15,9 +15,9 @@ AnimCut:
ld [wCoordAdjustmentAmount], a
ld c, 2
call AdjustOAMBlockXPos2
ld a, [rOBP1]
ldh a, [rOBP1]
xor $64
ld [rOBP1], a
ldh [rOBP1], a
call DelayFrame
pop bc
dec c
@ -65,9 +65,9 @@ AnimCutGrass_UpdateOAMEntries:
ld [wCoordAdjustmentAmount], a
ld c, 1
call AdjustOAMBlockXPos2
ld a, [rOBP1]
ldh a, [rOBP1]
xor $64
ld [rOBP1], a
ldh [rOBP1], a
call DelayFrame
pop bc
dec c

51
engine/overworld/doors.asm Executable file → Normal file
View file

@ -11,7 +11,7 @@ IsPlayerStandingOnDoorTile:
ld a, [hli]
ld h, [hl]
ld l, a
aCoord 8, 9 ; a = lower left background tile under player's sprite
lda_coord 8, 9 ; a = lower left background tile under player's sprite
ld b, a
.loop
ld a, [hli]
@ -25,51 +25,4 @@ IsPlayerStandingOnDoorTile:
and a
ret
DoorTileIDPointers:
dbw OVERWORLD, OverworldDoorTileIDs
dbw FOREST, ForestDoorTileIDs
dbw MART, MartDoorTileIDs
dbw HOUSE, HouseDoorTileIDs
dbw FOREST_GATE, TilesetMuseumDoorTileIDs
dbw MUSEUM, TilesetMuseumDoorTileIDs
dbw GATE, TilesetMuseumDoorTileIDs
dbw SHIP, ShipDoorTileIDs
dbw LOBBY, LobbyDoorTileIDs
dbw MANSION, MansionDoorTileIDs
dbw LAB, LabDoorTileIDs
dbw FACILITY, FacilityDoorTileIDs
dbw PLATEAU, PlateauDoorTileIDs
db $ff
OverworldDoorTileIDs:
db $1B,$58,$00
ForestDoorTileIDs:
db $3a,$00
MartDoorTileIDs:
db $5e,$00
HouseDoorTileIDs:
db $54,$00
TilesetMuseumDoorTileIDs:
db $3b,$00
ShipDoorTileIDs:
db $1e,$00
LobbyDoorTileIDs:
db $1c,$38,$1a,$00
MansionDoorTileIDs:
db $1a,$1c,$53,$00
LabDoorTileIDs:
db $34,$00
FacilityDoorTileIDs:
db $43,$58,$1b,$00
PlateauDoorTileIDs:
db $3b,$1b,$00
INCLUDE "data/tilesets/door_tile_ids.asm"

View file

@ -6,9 +6,9 @@ AnimateBoulderDust:
ld a, $ff
ld [wUpdateSpritesEnabled], a
ld a, %11100100
ld [rOBP1], a
ldh [rOBP1], a
call LoadSmokeTileFourTimes
callba WriteCutOrBoulderDustAnimationOAMBlock
farcall WriteCutOrBoulderDustAnimationOAMBlock
ld c, 8 ; number of steps in animation
.loop
push bc
@ -18,9 +18,9 @@ AnimateBoulderDust:
ld c, 4
jp hl
.returnAddress
ld a, [rOBP1]
ldh a, [rOBP1]
xor %01100100
ld [rOBP1], a
ldh [rOBP1], a
call Delay3
pop bc
dec c
@ -30,7 +30,7 @@ AnimateBoulderDust:
jp LoadPlayerSpriteGraphics
GetMoveBoulderDustFunctionPointer:
ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
ld a, [wSpritePlayerStateData1FacingDirection]
ld hl, MoveBoulderDustFunctionPointerTable
ld c, a
ld b, $0
@ -68,15 +68,15 @@ MoveBoulderDustFunctionPointerTable:
db $FF,$01
dw AdjustOAMBlockXPos
LoadSmokeTileFourTimes:
ld hl, vChars1 + $7c0
ld c, $4
LoadSmokeTileFourTimes::
ld hl, vChars1 tile $7c
ld c, 4
.loop
push bc
push hl
call LoadSmokeTile
pop hl
ld bc, $10
ld bc, 1 tiles
add hl, bc
pop bc
dec c
@ -89,5 +89,5 @@ LoadSmokeTile:
jp CopyVideoData
SSAnneSmokePuffTile:
INCBIN "gfx/ss_anne_smoke_puff.2bpp"
INCBIN "gfx/overworld/smoke.2bpp"
SSAnneSmokePuffTileEnd:

16
engine/overworld/elevator.asm Executable file → Normal file
View file

@ -1,12 +1,12 @@
ShakeElevator:
ShakeElevator::
ld de, -$20
call ShakeElevatorRedrawRow
ld de, SCREEN_HEIGHT * $20
call ShakeElevatorRedrawRow
call Delay3
ld a, $ff
ld a, SFX_STOP_ALL_MUSIC
call PlaySound
ld a, [hSCY]
ldh a, [hSCY]
ld d, a
ld e, $1
ld b, 100
@ -15,7 +15,7 @@ ShakeElevator:
xor $fe
ld e, a
add d
ld [hSCY], a
ldh [hSCY], a
push bc
ld c, 0 ; BANK(SFX_Collision_1)
ld a, SFX_COLLISION
@ -26,14 +26,14 @@ ShakeElevator:
dec b
jr nz, .shakeLoop
ld a, d
ld [hSCY], a
ld a, $ff
ldh [hSCY], a
ld a, SFX_STOP_ALL_MUSIC
call PlaySound
ld c, 0 ; BANK(SFX_Safari_Zone_PA)
ld a, SFX_SAFARI_ZONE_PA
call PlaySound
.musicLoop
ld a, [wChannelSoundIDs + Ch4]
ld a, [wChannelSoundIDs + Ch5]
cp SFX_SAFARI_ZONE_PA
jr z, .musicLoop
call UpdateSprites
@ -56,7 +56,7 @@ ShakeElevatorRedrawRow:
add hl, de
ld a, h
and $3
or vBGMap0 / $100
or HIGH(vBGMap0)
ld d, a
ld a, l
pop hl

21
engine/overworld/emotion_bubbles.asm Executable file → Normal file
View file

@ -8,8 +8,8 @@ EmotionBubble:
ld e, [hl]
inc hl
ld d, [hl]
ld hl, vChars1 + $780
lb bc, BANK(EmotionBubbles), $04
ld hl, vChars1 tile $78
lb bc, BANK(EmotionBubbles), 4
call CopyVideoData
ld a, [wUpdateSpritesEnabled]
push af
@ -38,7 +38,7 @@ EmotionBubble:
jr nz, .loop
; get the screen coordinates of the sprite the bubble is to be displayed above
ld hl, wSpriteStateData1 + 4
ld hl, wSpritePlayerStateData1YPixels
ld a, [wEmotionBubbleSpriteIndex]
swap a
ld c, a
@ -62,13 +62,16 @@ EmotionBubble:
jp UpdateSprites
EmotionBubblesPointerTable:
dw EmotionBubbles
dw EmotionBubbles + $40
dw EmotionBubbles + $80
; entries correspond to *_BUBBLE constants
dw ShockEmote
dw QuestionEmote
dw HappyEmote
EmotionBubblesOAM:
db $F8,$00,$F9,$00
db $FA,$00,$FB,$00
dbsprite 0, -1, 0, 0, $f9, 0
dbsprite 0, -1, 0, 2, $fb, 0
EmotionBubbles:
INCBIN "gfx/emotion_bubbles.2bpp"
ShockEmote: INCBIN "gfx/emotes/shock.2bpp"
QuestionEmote: INCBIN "gfx/emotes/question.2bpp"
HappyEmote: INCBIN "gfx/emotes/happy.2bpp"

View file

@ -7,16 +7,16 @@ PrintStrengthTxt:
jp PrintText
UsedStrengthText:
TX_FAR _UsedStrengthText
TX_ASM
text_far _UsedStrengthText
text_asm
ld a, [wcf91]
call PlayCry
call Delay3
jp TextScriptEnd
CanMoveBouldersText:
TX_FAR _CanMoveBouldersText
db "@"
text_far _CanMoveBouldersText
text_end
IsSurfingAllowed:
; Returns whether surfing is allowed in bit 1 of wd728.
@ -46,12 +46,13 @@ IsSurfingAllowed:
jp PrintText
CoordsData_cdf7:
db $0B,$07,$FF
dbmapcoord 7, 11
db -1 ; end
CurrentTooFastText:
TX_FAR _CurrentTooFastText
db "@"
text_far _CurrentTooFastText
text_end
CyclingIsFunText:
TX_FAR _CyclingIsFunText
db "@"
text_far _CyclingIsFunText
text_end

51
engine/overworld/healing_machine.asm Executable file → Normal file
View file

@ -3,25 +3,25 @@ AnimateHealingMachine:
call PlayMusic
ld de, PokeCenterFlashingMonitorAndHealBall
ld hl, vChars0 + $7c0
lb bc, BANK(PokeCenterFlashingMonitorAndHealBall), $03 ; loads one too many tiles
ld hl, vChars0 tile $7c
lb bc, BANK(PokeCenterFlashingMonitorAndHealBall), 3 ; should be 2
call CopyVideoData
ld hl, wUpdateSpritesEnabled
ld a, [hl]
push af
ld [hl], $ff
push hl
ld a, [rOBP1]
ldh a, [rOBP1]
push af
ld a, $e0
ld [rOBP1], a
ldh [rOBP1], a
ld hl, wOAMBuffer + $84
ld de, PokeCenterOAMData
call CopyHealingMachineOAM
; ld a, 4
; ld [wAudioFadeOutControl], a
; ld a, $ff
; ld a, SFX_STOP_ALL_MUSIC
; ld [wNewSoundID], a
; call PlaySound
;.waitLoop
@ -40,10 +40,10 @@ AnimateHealingMachine:
dec b
jr nz, .partyLoop
ld a, [wAudioROMBank]
cp $1f ; 0 ; BANK(Audio3_UpdateMusic) XXXXX
cp $1f ; BANK("Audio Engine 3")
ld [wAudioSavedROMBank], a
jr nz, .next
ld a, $ff
ld a, SFX_STOP_ALL_MUSIC
ld [wNewSoundID], a
call PlaySound
ld a, 0 ; BANK(Music_PkmnHealed)
@ -62,33 +62,33 @@ AnimateHealingMachine:
ld c, 32
call DelayFrames
pop af
ld [rOBP1], a
ldh [rOBP1], a
pop hl
pop af
ld [hl], a
jp UpdateSprites
PokeCenterFlashingMonitorAndHealBall:
INCBIN "gfx/pokecenter_ball.2bpp"
INCBIN "gfx/overworld/heal_machine.2bpp"
PokeCenterOAMData:
db $24,$34,$7C,$10 ; heal machine monitor
db $2B,$30,$7D,$10 ; pokeballs 1-6
db $2B,$38,$7D,$30
db $30,$30,$7D,$10
db $30,$38,$7D,$30
db $35,$30,$7D,$10
db $35,$38,$7D,$30
; heal machine monitor
dbsprite 6, 4, 4, 4, $7c, OAM_OBP1
; poke balls 1-6
dbsprite 6, 5, 0, 3, $7d, OAM_OBP1
dbsprite 7, 5, 0, 3, $7d, OAM_OBP1 | OAM_HFLIP
dbsprite 6, 6, 0, 0, $7d, OAM_OBP1
dbsprite 7, 6, 0, 0, $7d, OAM_OBP1 | OAM_HFLIP
dbsprite 6, 6, 0, 5, $7d, OAM_OBP1
dbsprite 7, 6, 0, 5, $7d, OAM_OBP1 | OAM_HFLIP
; d = value to xor with palette
FlashSprite8Times:
ld b, 8
.loop
ld a, [rOBP1]
ldh a, [rOBP1]
xor d
ld [rOBP1], a
ldh [rOBP1], a
ld c, 10
call DelayFrames
dec b
@ -97,16 +97,9 @@ FlashSprite8Times:
CopyHealingMachineOAM:
; copy one OAM entry and advance the pointers
REPT 4
ld a, [de]
inc de
ld [hli], a
ld a, [de]
inc de
ld [hli], a
ld a, [de]
inc de
ld [hli], a
ld a, [de]
inc de
ld [hli], a
ENDR
ret

View file

@ -1,161 +0,0 @@
HiddenItems:
ld hl, HiddenItemCoords
call FindHiddenItemOrCoinsIndex
ld [wHiddenItemOrCoinsIndex], a
ld hl, wObtainedHiddenItemsFlags
ld a, [wHiddenItemOrCoinsIndex]
ld c, a
ld b, FLAG_TEST
predef FlagActionPredef
ld a, c
and a
ret nz
call EnableAutoTextBoxDrawing
ld a, 1
ld [wDoNotWaitForButtonPressAfterDisplayingText], a
ld a, [wHiddenObjectFunctionArgument] ; item ID
ld [wd11e], a
call GetItemName
tx_pre_jump FoundHiddenItemText
INCLUDE "data/hidden_item_coords.asm"
FoundHiddenItemText:
TX_FAR _FoundHiddenItemText
TX_ASM
ld a, [wHiddenObjectFunctionArgument] ; item ID
ld b, a
ld c, 1
call GiveItem
jr nc, .bagFull
ld hl, wObtainedHiddenItemsFlags
ld a, [wHiddenItemOrCoinsIndex]
ld c, a
ld b, FLAG_SET
predef FlagActionPredef
ld a, SFX_GET_ITEM_2
call PlaySoundWaitForCurrent
call WaitForSoundToFinish
jp TextScriptEnd
.bagFull
call WaitForTextScrollButtonPress ; wait for button press
xor a
ld [wDoNotWaitForButtonPressAfterDisplayingText], a
ld hl, HiddenItemBagFullText
call PrintText
jp TextScriptEnd
HiddenItemBagFullText:
TX_FAR _HiddenItemBagFullText
db "@"
HiddenCoins:
ld b, COIN_CASE
predef GetQuantityOfItemInBag
ld a, b
and a
ret z
ld hl, HiddenCoinCoords
call FindHiddenItemOrCoinsIndex
ld [wHiddenItemOrCoinsIndex], a
ld hl, wObtainedHiddenCoinsFlags
ld a, [wHiddenItemOrCoinsIndex]
ld c, a
ld b, FLAG_TEST
predef FlagActionPredef
ld a, c
and a
ret nz
xor a
ld [hUnusedCoinsByte], a
ld [hCoins], a
ld [hCoins + 1], a
ld a, [wHiddenObjectFunctionArgument]
sub COIN
cp 10
jr z, .bcd10
cp 20
jr z, .bcd20
cp 40
jr z, .bcd20 ; should be bcd40
jr .bcd100
.bcd10
ld a, $10
ld [hCoins + 1], a
jr .bcdDone
.bcd20
ld a, $20
ld [hCoins + 1], a
jr .bcdDone
.bcd40 ; due to a typo, this is never used
ld a, $40
ld [hCoins + 1], a
jr .bcdDone
.bcd100
ld a, $1
ld [hCoins], a
.bcdDone
ld de, wPlayerCoins + 1
ld hl, hCoins + 1
ld c, $2
predef AddBCDPredef
ld hl, wObtainedHiddenCoinsFlags
ld a, [wHiddenItemOrCoinsIndex]
ld c, a
ld b, FLAG_SET
predef FlagActionPredef
call EnableAutoTextBoxDrawing
ld a, [wPlayerCoins]
cp $99
jr nz, .roomInCoinCase
ld a, [wPlayerCoins + 1]
cp $99
jr nz, .roomInCoinCase
tx_pre_id DroppedHiddenCoinsText
jr .done
.roomInCoinCase
tx_pre_id FoundHiddenCoinsText
.done
jp PrintPredefTextID
INCLUDE "data/hidden_coins.asm"
FoundHiddenCoinsText:
TX_FAR _FoundHiddenCoinsText
TX_SFX_ITEM_2
db "@"
DroppedHiddenCoinsText:
TX_FAR _FoundHiddenCoins2Text
TX_SFX_ITEM_2
TX_FAR _DroppedHiddenCoinsText
db "@"
FindHiddenItemOrCoinsIndex:
ld a, [wHiddenObjectY]
ld d, a
ld a, [wHiddenObjectX]
ld e, a
ld a, [wCurMap]
ld b, a
ld c, -1
.loop
inc c
ld a, [hli]
cp $ff ; end of the list?
ret z ; if so, we're done here
cp b
jr nz, .next1
ld a, [hli]
cp d
jr nz, .next2
ld a, [hli]
cp e
jr nz, .loop
ld a, c
ret
.next1
inc hl
.next2
inc hl
jr .loop

26
engine/overworld/hidden_objects.asm Executable file → Normal file
View file

@ -1,4 +1,4 @@
IsPlayerOnDungeonWarp:
IsPlayerOnDungeonWarp::
xor a
ld [wWhichDungeonWarp], a
ld a, [wd72d]
@ -14,14 +14,14 @@ IsPlayerOnDungeonWarp:
set 4, [hl]
ret
; if a hidden object was found, stores $00 in [$ffee], else stores $ff
CheckForHiddenObject:
ld hl, $ffeb
; if a hidden object was found, stores $00 in [hDidntFindAnyHiddenObject], else stores $ff
CheckForHiddenObject::
ld hl, hItemAlreadyFound
xor a
ld [hli], a
ld [hli], a
ld [hli], a
ld [hl], a
ld [hli], a ; [hItemAlreadyFound]
ld [hli], a ; [hSavedMapTextPtr]
ld [hli], a ; [hSavedMapTextPtr + 1]
ld [hl], a ; [hDidntFindAnyHiddenObject]
ld de, $0
ld hl, HiddenObjectMaps
.hiddenMapLoop
@ -58,7 +58,7 @@ CheckForHiddenObject:
ld [wHiddenObjectX], a
ld c, a
call CheckIfCoordsInFrontOfPlayerMatch
ld a, [hCoordsInFrontOfPlayerMatch]
ldh a, [hCoordsInFrontOfPlayerMatch]
and a
jr z, .foundMatchingObject
inc hl
@ -81,13 +81,13 @@ CheckForHiddenObject:
ret
.noMatch
ld a, $ff
ld [$ffee], a
ldh [hDidntFindAnyHiddenObject], a
ret
; checks if the coordinates in front of the player's sprite match Y in b and X in c
; [hCoordsInFrontOfPlayerMatch] = $00 if they match, $ff if they don't match
CheckIfCoordsInFrontOfPlayerMatch:
ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
ld a, [wSpritePlayerStateData1FacingDirection]
cp SPRITE_FACING_UP
jr z, .facingUp
cp SPRITE_FACING_LEFT
@ -127,7 +127,7 @@ CheckIfCoordsInFrontOfPlayerMatch:
.didNotMatch
ld a, $ff
.done
ld [hCoordsInFrontOfPlayerMatch], a
ldh [hCoordsInFrontOfPlayerMatch], a
ret
INCLUDE "data/hidden_objects.asm"
INCLUDE "data/events/hidden_objects.asm"

View file

@ -1,54 +0,0 @@
PickUpItem:
call EnableAutoTextBoxDrawing
ld a, [hSpriteIndexOrTextID]
ld b, a
ld hl, wMissableObjectList
.missableObjectsListLoop
ld a, [hli]
cp $ff
ret z
cp b
jr z, .isMissable
inc hl
jr .missableObjectsListLoop
.isMissable
ld a, [hl]
ld [$ffdb], a
ld hl, wMapSpriteExtraData
ld a, [hSpriteIndexOrTextID]
dec a
add a
ld d, 0
ld e, a
add hl, de
ld a, [hl]
ld b, a ; item
ld c, 1 ; quantity
call GiveItem
jr nc, .BagFull
ld a, [$ffdb]
ld [wMissableObjectIndex], a
predef HideObject
ld a, 1
ld [wDoNotWaitForButtonPressAfterDisplayingText], a
ld hl, FoundItemText
jr .print
.BagFull
ld hl, NoMoreRoomForItemText
.print
call PrintText
ret
FoundItemText:
TX_FAR _FoundItemText
TX_SFX_ITEM_1
db "@"
NoMoreRoomForItemText:
TX_FAR _NoMoreRoomForItemText
db "@"

28
engine/overworld/ledges.asm Executable file → Normal file
View file

@ -1,4 +1,4 @@
HandleLedges:
HandleLedges::
ld a, [wd736]
bit 6, a ; already jumping down ledge
ret nz
@ -6,9 +6,9 @@ HandleLedges:
and a ; OVERWORLD
ret nz
predef GetTileAndCoordsInFrontOfPlayer
ld a, [wSpriteStateData1 + 9]
ld a, [wSpritePlayerStateData1FacingDirection]
ld b, a
aCoord 8, 9
lda_coord 8, 9
ld c, a
ld a, [wTileInFrontOfPlayer]
ld d, a
@ -36,7 +36,7 @@ HandleLedges:
inc hl
jr .loop
.foundMatch
ld a, [hJoyHeld]
ldh a, [hJoyHeld]
and e
ret z
ld a, $ff
@ -54,20 +54,10 @@ HandleLedges:
call PlaySound
ret
; (player direction) (tile player standing on) (ledge tile) (input required)
LedgeTiles:
db SPRITE_FACING_DOWN, $2C,$37,D_DOWN
db SPRITE_FACING_DOWN, $39,$36,D_DOWN
db SPRITE_FACING_DOWN, $39,$37,D_DOWN
db SPRITE_FACING_LEFT, $2C,$27,D_LEFT
db SPRITE_FACING_LEFT, $39,$27,D_LEFT
db SPRITE_FACING_RIGHT,$2C,$0D,D_RIGHT
db SPRITE_FACING_RIGHT,$2C,$1D,D_RIGHT
db SPRITE_FACING_RIGHT,$39,$0D,D_RIGHT
db $FF
INCLUDE "data/tilesets/ledge_tiles.asm"
LoadHoppingShadowOAM:
ld hl, vChars1 + $7f0
ld hl, vChars1 tile $7f
ld de, LedgeHoppingShadow
lb bc, BANK(LedgeHoppingShadow), (LedgeHoppingShadowEnd - LedgeHoppingShadow) / $8
call CopyVideoDataDouble
@ -78,9 +68,9 @@ LoadHoppingShadowOAM:
ret
LedgeHoppingShadow:
INCBIN "gfx/ledge_hopping_shadow.1bpp"
INCBIN "gfx/overworld/shadow.1bpp"
LedgeHoppingShadowEnd:
LedgeHoppingShadowOAM:
db $FF,$10,$FF,$20
db $FF,$40,$FF,$60
dbsprite 2, -1, 0, 7, $ff, OAM_HFLIP
dbsprite 8, -1, 0, 7, $ff, OAM_HFLIP | OAM_VFLIP

105
engine/overworld/map_sprites.asm Executable file → Normal file
View file

@ -4,20 +4,21 @@
; This is also called after displaying text because loading
; text tile patterns overwrites half of the sprite tile pattern data.
; Note on notation:
; $C1X* and $C2X* are used to denote wSpriteStateData1-wSpriteStateData1 + $ff and wSpriteStateData2 + $00-wSpriteStateData2 + $ff sprite slot
; fields, respectively, within loops. The X is the loop index.
; If there is an inner loop, Y is the inner loop index, i.e. $C1Y* and $C2Y*
; denote fields of the sprite slots iterated over in the inner loop.
InitMapSprites:
; x#SPRITESTATEDATA1_* and x#SPRITESTATEDATA2_* are used to denote wSpriteStateData1 and
; wSpriteStateData2 sprite slot, respectively, within loops. The X is the loop index.
; If there is an inner loop, Y is the inner loop index, i.e. y#SPRITESTATEDATA1_* and
; y#SPRITESTATEDATA2_* denote fields of the sprite slots iterated over in the inner loop.
InitMapSprites::
call InitOutsideMapSprites
ret c ; return if the map is an outside map (already handled by above call)
; if the map is an inside map (i.e. mapID >= $25)
ld hl, wSpriteStateData1
ld de, wSpriteStateData2 + $0d
; Loop to copy picture ID's from $C1X0 to $C2XD for LoadMapSpriteTilePatterns.
ld hl, wSpritePlayerStateData1PictureID
ld de, wSpritePlayerStateData2PictureID
; Loop to copy picture IDs from [x#SPRITESTATEDATA1_PICTUREID]
; to [x#SPRITESTATEDATA2_PICTUREID] for LoadMapSpriteTilePatterns.
.copyPictureIDLoop
ld a, [hl] ; $C1X0 (picture ID)
ld [de], a ; $C2XD
ld a, [hl] ; a = [x#SPRITESTATEDATA1_PICTUREID]
ld [de], a ; [x#SPRITESTATEDATA2_PICTUREID] = a
ld a, $10
add e
ld e, a
@ -37,20 +38,22 @@ LoadMapSpriteTilePatterns:
.spritesExist
ld c, a ; c = [wNumSprites]
ld b, $10 ; number of sprite slots
ld hl, wSpriteStateData2 + $0d
ld hl, wSpritePlayerStateData2PictureID
xor a
ld [hFourTileSpriteCount], a
.copyPictureIDLoop ; loop to copy picture ID from $C2XD to $C2XE
ld a, [hli] ; $C2XD (sprite picture ID)
ld [hld], a ; $C2XE
ldh [hFourTileSpriteCount], a
; Loop to copy picture IDs from [x#SPRITESTATEDATA2_PICTUREID]
; to [x#SPRITESTATEDATA2_IMAGEBASEOFFSET].
.copyPictureIDLoop
ld a, [hli] ; a = [x#SPRITESTATEDATA2_PICTUREID]
ld [hld], a ; [x#SPRITESTATEDATA2_IMAGEBASEOFFSET] = a
ld a, l
add $10
ld l, a
dec b
jr nz, .copyPictureIDLoop
ld hl, wSpriteStateData2 + $1e
ld hl, wSprite01StateData2ImageBaseOffset
.loadTilePatternLoop
ld de, wSpriteStateData2 + $1d
ld de, wSprite01StateData2PictureID
; Check if the current picture ID has already had its tile patterns loaded.
; This done by looping through the previous sprite slots and seeing if any of
; their picture ID's match that of the current sprite slot.
@ -70,7 +73,7 @@ LoadMapSpriteTilePatterns:
ld e, a
jr .checkIfAlreadyLoadedLoop
.notAlreadyLoaded
ld de, wSpriteStateData2 + $0e
ld de, wSpritePlayerStateData2ImageBaseOffset
ld b, $01
; loop to find the highest tile pattern VRAM slot (among the first 10 slots) used by a previous sprite slot
; this is done in order to find the first free VRAM slot available
@ -81,7 +84,7 @@ LoadMapSpriteTilePatterns:
ld a, l
cp e ; reached current slot?
jr z, .foundNextVRAMSlot
ld a, [de] ; $C2YE (VRAM slot)
ld a, [de] ; y#SPRITESTATEDATA2_IMAGEBASEOFFSET
cp 11 ; is it one of the first 10 slots?
jr nc, .findNextVRAMSlotLoop
cp b ; compare the slot being checked to the current max
@ -93,19 +96,19 @@ LoadMapSpriteTilePatterns:
inc b ; increment previous max value to get next VRAM tile pattern slot
ld a, b ; a = next VRAM tile pattern slot
push af
ld a, [hl] ; $C2XE (sprite picture ID)
ld a, [hl] ; [x#SPRITESTATEDATA2_IMAGEBASEOFFSET]
ld b, a ; b = current sprite picture ID
cp SPRITE_BALL ; is it a 4-tile sprite?
cp FIRST_STILL_SPRITE ; is it a 4-tile sprite?
jr c, .notFourTileSprite
pop af
ld a, [hFourTileSpriteCount]
ldh a, [hFourTileSpriteCount]
add 11
jr .storeVRAMSlot
.notFourTileSprite
pop af
.storeVRAMSlot
ld [hl], a ; store VRAM slot at $C2XE
ld [hVRAMSlot], a ; used to determine if it's 4-tile sprite later
ld [hl], a ; store VRAM slot at [x#SPRITESTATEDATA2_IMAGEBASEOFFSET]
ldh [hVRAMSlot], a ; used to determine if it's 4-tile sprite later
ld a, b ; a = current sprite picture ID
dec a
add a
@ -127,28 +130,27 @@ LoadMapSpriteTilePatterns:
push de
push bc
ld hl, vNPCSprites ; VRAM base address
ld bc, $c0 ; number of bytes per VRAM slot
ld a, [hVRAMSlot]
ld bc, 12 tiles ; number of bytes per VRAM slot
ldh a, [hVRAMSlot]
cp 11 ; is it a 4-tile sprite?
jr nc, .fourTileSpriteVRAMAddr
ld d, a
dec d
; Equivalent to multiplying $C0 (number of bytes in 12 tiles) times the VRAM
; slot and adding the result to $8000 (the VRAM base address).
; hl = vSprites + [hVRAMSlot] * 12 tiles
.calculateVRAMAddrLoop
add hl, bc
dec d
jr nz, .calculateVRAMAddrLoop
jr .loadStillTilePattern
.fourTileSpriteVRAMAddr
ld hl, vSprites + $7c0 ; address for second 4-tile sprite
ld a, [hFourTileSpriteCount]
ld hl, vSprites tile $7c ; address for second 4-tile sprite
ldh a, [hFourTileSpriteCount]
and a
jr nz, .loadStillTilePattern
; if it's the first 4-tile sprite
ld hl, vSprites + $780 ; address for first 4-tile sprite
ld hl, vSprites tile $78 ; address for first 4-tile sprite
inc a
ld [hFourTileSpriteCount], a
ldh [hFourTileSpriteCount], a
.loadStillTilePattern
pop bc
pop de
@ -168,7 +170,7 @@ LoadMapSpriteTilePatterns:
.skipFirstLoad
pop de
pop hl
ld a, [hVRAMSlot]
ldh a, [hVRAMSlot]
cp 11 ; is it a 4-tile sprite?
jr nc, .skipSecondLoad ; if so, there is no second block
push de
@ -208,20 +210,21 @@ LoadMapSpriteTilePatterns:
jr .nextSpriteSlot
.alreadyLoaded ; if the current picture ID has already had its tile patterns loaded
inc de
ld a, [de] ; a = VRAM slot for the current picture ID (from $C2YE)
ld [hl], a ; store VRAM slot in current wSpriteStateData2 sprite slot (at $C2XE)
ld a, [de] ; a = [y#SPRITESTATEDATA2_IMAGEBASEOFFSET]
ld [hl], a ; [x#SPRITESTATEDATA2_IMAGEBASEOFFSET] = a
.nextSpriteSlot
ld a, l
add $10
ld l, a
dec c
jp nz, .loadTilePatternLoop
ld hl, wSpriteStateData2 + $0d
ld hl, wSpritePlayerStateData2PictureID
ld b, $10
; the pictures ID's stored at $C2XD are no longer needed, so zero them
; the pictures IDs stored at [x#SPRITESTATEDATA2_PICTUREID] are no longer needed,
; so zero them
.zeroStoredPictureIDLoop
xor a
ld [hl], a ; $C2XD
ld [hl], a ; [x#SPRITESTATEDATA2_PICTUREID]
ld a, $10
add l
ld l, a
@ -252,7 +255,7 @@ ReadSpriteSheetData:
; sets carry if the map is a city or route, unsets carry if not
InitOutsideMapSprites:
ld a, [wCurMap]
cp REDS_HOUSE_1F ; is the map a city or a route (map ID less than $25)?
cp FIRST_INDOOR_MAP ; is the map a city or a route?
ret nc ; if not, return
ld hl, MapSpriteSets
add l
@ -288,20 +291,20 @@ InitOutsideMapSprites:
jr nc, .noCarry2
inc d
.noCarry2
ld hl, wSpriteStateData2 + $0d
ld hl, wSpritePlayerStateData2PictureID
ld a, SPRITE_RED
ld [hl], a
ld bc, wSpriteSet
; Load the sprite set into RAM.
; This loop also fills $C2XD (sprite picture ID) where X is from $0 to $A
; with picture ID's. This is done so that LoadMapSpriteTilePatterns will
; This loop also fills [x#SPRITESTATEDATA2_PICTUREID] where X is from $0 to $A
; with picture IDs. This is done so that LoadMapSpriteTilePatterns will
; load tile patterns for all sprite pictures in the sprite set.
.loadSpriteSetLoop
ld a, $10
add l
ld l, a
ld a, [de] ; sprite picture ID from sprite set
ld [hl], a ; $C2XD (sprite picture ID)
ld [hl], a ; [x#SPRITESTATEDATA2_PICTUREID]
ld [bc], a
inc de
inc bc
@ -314,7 +317,7 @@ InitOutsideMapSprites:
add l
ld l, a
xor a
ld [hl], a ; $C2XD (sprite picture ID)
ld [hl], a ; [x#SPRITESTATEDATA2_PICTUREID]
dec b
jr nz, .zeroRemainingSlotsLoop
ld a, [wNumSprites]
@ -324,21 +327,21 @@ InitOutsideMapSprites:
call LoadMapSpriteTilePatterns
pop af
ld [wNumSprites], a ; restore number of sprites
ld hl, wSpriteStateData2 + $1e
ld hl, wSprite01StateData2ImageBaseOffset
ld b, $0f
; The VRAM tile pattern slots that LoadMapSpriteTilePatterns set are in the
; order of the map's sprite set, not the order of the actual sprites loaded
; for the current map. So, they are not needed and are zeroed by this loop.
.zeroVRAMSlotsLoop
xor a
ld [hl], a ; $C2XE (VRAM slot)
ld [hl], a ; [x#SPRITESTATEDATA2_IMAGEBASEOFFSET]
ld a, $10
add l
ld l, a
dec b
jr nz, .zeroVRAMSlotsLoop
.skipLoadingSpriteSet
ld hl, wSpriteStateData1 + $10
ld hl, wSprite01StateData1
; This loop stores the correct VRAM tile pattern slots according the sprite
; data from the map's header. Since the VRAM tile pattern slots are filled in
; the order of the sprite set, in order to find the VRAM tile pattern slot
@ -348,7 +351,7 @@ InitOutsideMapSprites:
; VRAM tile pattern slot.
.storeVRAMSlotsLoop
ld c, 0
ld a, [hl] ; $C1X0 (picture ID) (zero if sprite slot is not used)
ld a, [hl] ; [x#SPRITESTATEDATA1_PICTUREID] (zero if sprite slot is not used)
and a ; is the sprite slot used?
jr z, .skipGettingPictureIndex ; if the sprite slot is not used
ld b, a ; b = picture ID
@ -368,7 +371,7 @@ InitOutsideMapSprites:
add l
ld l, a
ld a, c ; a = VRAM slot (zero if sprite slot is not used)
ld [hl], a ; $C2XE (VRAM slot)
ld [hl], a ; [x#SPRITESTATEDATA2_IMAGEBASEOFFSET]
pop hl
ld a, $10
add l
@ -437,4 +440,6 @@ GetSplitMapSpriteSetID:
ld a, $01
ret
INCLUDE "data/sprite_sets.asm"
INCLUDE "data/maps/sprite_sets.asm"
INCLUDE "data/sprites/sprites.asm"

View file

@ -1,6 +1,6 @@
MarkTownVisitedAndLoadMissableObjects:
MarkTownVisitedAndLoadMissableObjects::
ld a, [wCurMap]
cp ROUTE_1
cp FIRST_ROUTE_MAP
jr nc, .notInTown
ld c, a
ld b, FLAG_SET
@ -20,7 +20,7 @@ MarkTownVisitedAndLoadMissableObjects:
LoadMissableObjects:
ld l, a
push hl
ld de, MapHS00 ; calculate difference between out pointer and the base pointer
ld de, MissableObjects ; calculate difference between out pointer and the base pointer
ld a, l
sub e
jr nc, .asm_f13c
@ -31,25 +31,25 @@ LoadMissableObjects:
sub d
ld h, a
ld a, h
ld [H_DIVIDEND], a
ldh [hDividend], a
ld a, l
ld [H_DIVIDEND+1], a
ldh [hDividend+1], a
xor a
ld [H_DIVIDEND+2], a
ld [H_DIVIDEND+3], a
ldh [hDividend+2], a
ldh [hDividend+3], a
ld a, $3
ld [H_DIVISOR], a
ldh [hDivisor], a
ld b, $2
call Divide ; divide difference by 3, resulting in the global offset (number of missable items before ours)
ld a, [wCurMap]
ld b, a
ld a, [H_DIVIDEND+3]
ldh a, [hDividend+3]
ld c, a ; store global offset in c
ld de, wMissableObjectList
pop hl
.writeMissableObjectsListLoop
ld a, [hli]
cp $ff
cp -1
jr z, .done ; end of list
cp b
jr nz, .done ; not for current map anymore
@ -63,7 +63,7 @@ LoadMissableObjects:
inc de
jr .writeMissableObjectsListLoop
.done
ld a, $ff
ld a, -1
ld [de], a ; write sentinel
ret
@ -72,17 +72,17 @@ InitializeMissableObjectsFlags:
ld bc, wMissableObjectFlagsEnd - wMissableObjectFlags
xor a
call FillMemory ; clear missable objects flags
ld hl, MapHS00
ld hl, MissableObjects
xor a
ld [wMissableObjectCounter], a
.missableObjectsLoop
ld a, [hli]
cp $ff ; end of list
cp -1 ; end of list
ret z
push hl
inc hl
ld a, [hl]
cp Hide
cp HIDE
jr nz, .skip
ld hl, wMissableObjectFlags
ld a, [wMissableObjectCounter]
@ -99,13 +99,13 @@ InitializeMissableObjectsFlags:
; tests if current sprite is a missable object that is hidden/has been removed
IsObjectHidden:
ld a, [H_CURRENTSPRITEOFFSET]
ldh a, [hCurrentSpriteOffset]
swap a
ld b, a
ld hl, wMissableObjectList
.loop
ld a, [hli]
cp $ff
cp -1
jr z, .notHidden ; not missable -> not hidden
cp b
ld a, [hli]
@ -120,7 +120,7 @@ IsObjectHidden:
.notHidden
xor a
.hidden
ld [$ffe5], a
ldh [hIsHiddenMissableObject], a
ret
; adds missable object (items, leg. pokemon, etc.) to the map

View file

@ -1,27 +1,29 @@
MAP_TILESET_SIZE EQU $60
UpdatePlayerSprite:
ld a, [wSpriteStateData2]
ld a, [wSpritePlayerStateData2WalkAnimationCounter]
and a
jr z, .checkIfTextBoxInFrontOfSprite
cp $ff
jr z, .disableSprite
dec a
ld [wSpriteStateData2], a
ld [wSpritePlayerStateData2WalkAnimationCounter], a
jr .disableSprite
; check if a text box is in front of the sprite by checking if the lower left
; background tile the sprite is standing on is greater than $5F, which is
; the maximum number for map tiles
.checkIfTextBoxInFrontOfSprite
aCoord 8, 9
ld [hTilePlayerStandingOn], a
cp $60
lda_coord 8, 9
ldh [hTilePlayerStandingOn], a
cp MAP_TILESET_SIZE
jr c, .lowerLeftTileIsMapTile
.disableSprite
ld a, $ff
ld [wSpriteStateData1 + 2], a
ld [wSpritePlayerStateData1ImageIndex], a
ret
.lowerLeftTileIsMapTile
call DetectCollisionBetweenSprites
ld h, wSpriteStateData1 / $100
ld h, HIGH(wSpriteStateData1)
ld a, [wWalkCounter]
and a
jr nz, .moving
@ -49,11 +51,11 @@ UpdatePlayerSprite:
.notMoving
; zero the animation counters
xor a
ld [wSpriteStateData1 + 7], a
ld [wSpriteStateData1 + 8], a
ld [wSpritePlayerStateData1IntraAnimFrameCounter], a
ld [wSpritePlayerStateData1AnimFrameCounter], a
jr .calcImageIndex
.next
ld [wSpriteStateData1 + 9], a ; facing direction
ld [wSpritePlayerStateData1FacingDirection], a
ld a, [wFontLoaded]
bit 0, a
jr nz, .notMoving
@ -61,7 +63,7 @@ UpdatePlayerSprite:
ld a, [wd736]
bit 7, a ; is the player sprite spinning due to a spin tile?
jr nz, .skipSpriteAnim
ld a, [H_CURRENTSPRITEOFFSET]
ldh a, [hCurrentSpriteOffset]
add $7
ld l, a
ld a, [hl]
@ -77,31 +79,31 @@ UpdatePlayerSprite:
and $3
ld [hl], a
.calcImageIndex
ld a, [wSpriteStateData1 + 8]
ld a, [wSpritePlayerStateData1AnimFrameCounter]
ld b, a
ld a, [wSpriteStateData1 + 9]
ld a, [wSpritePlayerStateData1FacingDirection]
add b
ld [wSpriteStateData1 + 2], a
ld [wSpritePlayerStateData1ImageIndex], a
.skipSpriteAnim
; If the player is standing on a grass tile, make the player's sprite have
; lower priority than the background so that it's partially obscured by the
; grass. Only the lower half of the sprite is permitted to have the priority
; bit set by later logic.
ld a, [hTilePlayerStandingOn]
ldh a, [hTilePlayerStandingOn]
ld c, a
ld a, [wGrassTile]
cp c
ld a, $0
ld a, 0
jr nz, .next2
ld a, $80
ld a, OAM_BEHIND_BG
.next2
ld [wSpriteStateData2 + 7], a
ld [wSpritePlayerStateData2GrassPriority], a
ret
UnusedReadSpriteDataFunction:
push bc
push af
ld a, [H_CURRENTSPRITEOFFSET]
ldh a, [hCurrentSpriteOffset]
ld c, a
pop af
add c
@ -110,7 +112,7 @@ UnusedReadSpriteDataFunction:
ret
UpdateNPCSprite:
ld a, [H_CURRENTSPRITEOFFSET]
ldh a, [hCurrentSpriteOffset]
swap a
dec a
add a
@ -122,20 +124,20 @@ UpdateNPCSprite:
.nc
ld a, [hl] ; read movement byte 2
ld [wCurSpriteMovement2], a
ld h, $c1
ld a, [H_CURRENTSPRITEOFFSET]
ld h, HIGH(wSpriteStateData1)
ldh a, [hCurrentSpriteOffset]
ld l, a
inc l
ld a, [hl] ; c1x1
ld a, [hl] ; x#SPRITESTATEDATA1_MOVEMENTSTATUS
and a
jp z, InitializeSpriteStatus
call CheckSpriteAvailability
ret c ; if sprite is invisible, on tile >=$60, in grass or player is currently walking
ld h, $c1
ld a, [H_CURRENTSPRITEOFFSET]
ret c ; if sprite is invisible, on tile >=MAP_TILESET_SIZE, in grass or player is currently walking
ld h, HIGH(wSpriteStateData1)
ldh a, [hCurrentSpriteOffset]
ld l, a
inc l
ld a, [hl] ; c1x1
ld a, [hl] ; x#SPRITESTATEDATA1_MOVEMENTSTATUS
bit 7, a ; is the face player flag set?
jp nz, MakeNPCFacePlayer
ld b, a
@ -144,22 +146,22 @@ UpdateNPCSprite:
jp nz, notYetMoving
ld a, b
cp $2
jp z, UpdateSpriteMovementDelay ; c1x1 == 2
jp z, UpdateSpriteMovementDelay ; [x#SPRITESTATEDATA1_MOVEMENTSTATUS] == 2
cp $3
jp z, UpdateSpriteInWalkingAnimation ; c1x1 == 3
jp z, UpdateSpriteInWalkingAnimation ; [x#SPRITESTATEDATA1_MOVEMENTSTATUS] == 3
ld a, [wWalkCounter]
and a
ret nz ; don't do anything yet if player is currently moving (redundant, already tested in CheckSpriteAvailability)
call InitializeSpriteScreenPosition
ld h, $c2
ld a, [H_CURRENTSPRITEOFFSET]
ld h, HIGH(wSpriteStateData2)
ldh a, [hCurrentSpriteOffset]
add $6
ld l, a
ld a, [hl] ; c2x6: movement byte 1
ld a, [hl] ; x#SPRITESTATEDATA2_MOVEMENTBYTE1
inc a
jr z, .randomMovement ; value $FF
jr z, .randomMovement ; value STAY
inc a
jr z, .randomMovement ; value $FE
jr z, .randomMovement ; value WALK
; scripted movement
dec a
ld [hl], a ; increment movement byte 1 (movement data index)
@ -170,7 +172,7 @@ UpdateNPCSprite:
pop hl
ld de, wNPCMovementDirections
call LoadDEPlusA ; a = [wNPCMovementDirections + movement byte 1]
cp $e0
cp NPC_CHANGE_FACING
jp z, ChangeFacingDirection
cp STAY
jr nz, .next
@ -185,7 +187,7 @@ UpdateNPCSprite:
.next
cp WALK
jr nz, .determineDirection
; current NPC movement data is $fe. this seems buggy
; current NPC movement data is WALK ($fe). this seems buggy
ld [hl], $1 ; set movement byte 1 to $1
ld de, wNPCMovementDirections
call LoadDEPlusA ; a = [wNPCMovementDirections + $fe] (?)
@ -196,20 +198,20 @@ UpdateNPCSprite:
.determineDirection
ld b, a
ld a, [wCurSpriteMovement2]
cp $d0
jr z, .moveDown ; movement byte 2 = $d0 forces down
cp $d1
jr z, .moveUp ; movement byte 2 = $d1 forces up
cp $d2
jr z, .moveLeft ; movement byte 2 = $d2 forces left
cp $d3
jr z, .moveRight ; movement byte 2 = $d3 forces right
cp DOWN
jr z, .moveDown
cp UP
jr z, .moveUp
cp LEFT
jr z, .moveLeft
cp RIGHT
jr z, .moveRight
ld a, b
cp $40 ; a < $40: down (or left)
cp NPC_MOVEMENT_UP ; NPC_MOVEMENT_DOWN <= a < NPC_MOVEMENT_UP: down (or left)
jr nc, .notDown
ld a, [wCurSpriteMovement2]
cp $2
jr z, .moveLeft ; movement byte 2 = $2 only allows left or right
cp LEFT_RIGHT
jr z, .moveLeft
.moveDown
ld de, 2*SCREEN_WIDTH
add hl, de ; move tile pointer two rows down
@ -217,11 +219,11 @@ UpdateNPCSprite:
lb bc, 4, SPRITE_FACING_DOWN
jr TryWalking
.notDown
cp $80 ; $40 <= a < $80: up (or right)
cp NPC_MOVEMENT_LEFT ; NPC_MOVEMENT_UP <= a < NPC_MOVEMENT_LEFT: up (or right)
jr nc, .notUp
ld a, [wCurSpriteMovement2]
cp $2
jr z, .moveRight ; movement byte 2 = $2 only allows left or right
cp LEFT_RIGHT
jr z, .moveRight
.moveUp
ld de, -2*SCREEN_WIDTH
add hl, de ; move tile pointer two rows up
@ -229,21 +231,21 @@ UpdateNPCSprite:
lb bc, 8, SPRITE_FACING_UP
jr TryWalking
.notUp
cp $c0 ; $80 <= a < $c0: left (or up)
cp NPC_MOVEMENT_RIGHT ; NPC_MOVEMENT_LEFT <= a < NPC_MOVEMENT_RIGHT: left (or up)
jr nc, .notLeft
ld a, [wCurSpriteMovement2]
cp $1
jr z, .moveUp ; movement byte 2 = $1 only allows up or down
cp UP_DOWN
jr z, .moveUp
.moveLeft
dec hl
dec hl ; move tile pointer two columns left
lb de, 0, -1
lb bc, 2, SPRITE_FACING_LEFT
jr TryWalking
.notLeft ; $c0 <= a: right (or down)
.notLeft ; NPC_MOVEMENT_RIGHT <= a: right (or down)
ld a, [wCurSpriteMovement2]
cp $1
jr z, .moveDown ; movement byte 2 = $1 only allows up or down
cp UP_DOWN
jr z, .moveDown
.moveRight
inc hl
inc hl ; move tile pointer two columns right
@ -264,143 +266,145 @@ ChangeFacingDirection:
; set carry on failure, clears carry on success
TryWalking:
push hl
ld h, $c1
ld a, [H_CURRENTSPRITEOFFSET]
ld h, HIGH(wSpriteStateData1)
ldh a, [hCurrentSpriteOffset]
add $9
ld l, a
ld [hl], c ; c1x9 (update facing direction)
ld a, [H_CURRENTSPRITEOFFSET]
ld [hl], c ; x#SPRITESTATEDATA1_FACINGDIRECTION
ldh a, [hCurrentSpriteOffset]
add $3
ld l, a
ld [hl], d ; c1x3 (update Y movement delta)
ld [hl], d ; x#SPRITESTATEDATA1_YSTEPVECTOR
inc l
inc l
ld [hl], e ; c1x5 (update X movement delta)
ld [hl], e ; x#SPRITESTATEDATA1_XSTEPVECTOR
pop hl
push de
ld c, [hl] ; read tile to walk onto
call CanWalkOntoTile
pop de
ret c ; cannot walk there (reinitialization of delay values already done)
ld h, $c2
ld a, [H_CURRENTSPRITEOFFSET]
ld h, HIGH(wSpriteStateData2)
ldh a, [hCurrentSpriteOffset]
add $4
ld l, a
ld a, [hl] ; c2x4: Y position
ld a, [hl] ; x#SPRITESTATEDATA2_MAPY
add d
ld [hli], a ; update Y position
ld a, [hl] ; c2x5: X position
ld a, [hl] ; x#SPRITESTATEDATA2_MAPX
add e
ld [hl], a ; update X position
ld a, [H_CURRENTSPRITEOFFSET]
ldh a, [hCurrentSpriteOffset]
ld l, a
ld [hl], $10 ; c2x0=16: walk animation counter
ld [hl], $10 ; [x#SPRITESTATEDATA2_WALKANIMATIONCOUNTER] = 16
dec h
inc l
ld [hl], $3 ; c1x1: set movement status to walking
ld [hl], $3 ; x#SPRITESTATEDATA1_MOVEMENTSTATUS
jp UpdateSpriteImage
; update the walking animation parameters for a sprite that is currently walking
UpdateSpriteInWalkingAnimation:
ld a, [H_CURRENTSPRITEOFFSET]
ldh a, [hCurrentSpriteOffset]
add $7
ld l, a
ld a, [hl] ; c1x7 (counter until next walk animation frame)
ld a, [hl] ; x#SPRITESTATEDATA1_INTRAANIMFRAMECOUNTER
inc a
ld [hl], a ; c1x7 += 1
ld [hl], a ; [x#SPRITESTATEDATA1_INTRAANIMFRAMECOUNTER]++
cp $4
jr nz, .noNextAnimationFrame
xor a
ld [hl], a ; c1x7 = 0
ld [hl], a ; [x#SPRITESTATEDATA1_INTRAANIMFRAMECOUNTER] = 0
inc l
ld a, [hl] ; c1x8 (walk animation frame)
ld a, [hl] ; x#SPRITESTATEDATA1_ANIMFRAMECOUNTER
inc a
and $3
ld [hl], a ; advance to next animation frame every 4 ticks (16 ticks total for one step)
.noNextAnimationFrame
ld a, [H_CURRENTSPRITEOFFSET]
ldh a, [hCurrentSpriteOffset]
add $3
ld l, a
ld a, [hli] ; c1x3 (movement Y delta)
ld a, [hli] ; x#SPRITESTATEDATA1_YSTEPVECTOR
ld b, a
ld a, [hl] ; c1x4 (screen Y position)
ld a, [hl] ; x#SPRITESTATEDATA1_YPIXELS
add b
ld [hli], a ; update screen Y position
ld a, [hli] ; c1x5 (movement X delta)
ld [hli], a ; update [x#SPRITESTATEDATA1_YPIXELS]
ld a, [hli] ; x#SPRITESTATEDATA1_XSTEPVECTOR
ld b, a
ld a, [hl] ; c1x6 (screen X position)
ld a, [hl] ; x#SPRITESTATEDATA1_XPIXELS
add b
ld [hl], a ; update screen X position
ld a, [H_CURRENTSPRITEOFFSET]
ld [hl], a ; update [x#SPRITESTATEDATA1_XPIXELS]
ldh a, [hCurrentSpriteOffset]
ld l, a
inc h
ld a, [hl] ; c2x0 (walk animation counter)
ld a, [hl] ; x#SPRITESTATEDATA2_WALKANIMATIONCOUNTER
dec a
ld [hl], a ; update walk animation counter
ret nz
ld a, $6 ; walking finished, update state
add l
ld l, a
ld a, [hl] ; c2x6 (movement byte 1)
cp $fe
jr nc, .initNextMovementCounter ; values $fe and $ff
ld a, [H_CURRENTSPRITEOFFSET]
ld a, [hl] ; x#SPRITESTATEDATA2_MOVEMENTBYTE1
cp WALK
jr nc, .initNextMovementCounter ; values WALK or STAY
ldh a, [hCurrentSpriteOffset]
inc a
ld l, a
dec h
ld [hl], $1 ; c1x1 = 1 (movement status ready)
ld [hl], $1 ; [x#SPRITESTATEDATA1_MOVEMENTSTATUS] = 1 (movement status ready)
ret
.initNextMovementCounter
call Random
ld a, [H_CURRENTSPRITEOFFSET]
ldh a, [hCurrentSpriteOffset]
add $8
ld l, a
ld a, [hRandomAdd]
ldh a, [hRandomAdd]
and $7f
ld [hl], a ; c2x8: set next movement delay to a random value in [0,$7f]
dec h ; note that value 0 actually makes the delay $100 (bug?)
ld a, [H_CURRENTSPRITEOFFSET]
ld [hl], a ; x#SPRITESTATEDATA2_MOVEMENTDELAY:
; set next movement delay to a random value in [0,$7f]
; note that value 0 actually makes the delay $100 (bug?)
dec h ; HIGH(wSpriteStateData1)
ldh a, [hCurrentSpriteOffset]
inc a
ld l, a
ld [hl], $2 ; c1x1 = 2 (movement status)
ld [hl], $2 ; [x#SPRITESTATEDATA1_MOVEMENTSTATUS] = 2 (movement status)
inc l
inc l
xor a
ld b, [hl] ; c1x3 (movement Y delta)
ld [hli], a ; reset movement Y delta
ld b, [hl] ; x#SPRITESTATEDATA1_YSTEPVECTOR
ld [hli], a ; [x#SPRITESTATEDATA1_YSTEPVECTOR] = 0
inc l
ld c, [hl] ; c1x5 (movement X delta)
ld [hl], a ; reset movement X delta
ld c, [hl] ; x#SPRITESTATEDATA1_XSTEPVECTOR
ld [hl], a ; [x#SPRITESTATEDATA1_XSTEPVECTOR] = 0
ret
; update delay value (c2x8) for sprites in the delayed state (c1x1)
; update [x#SPRITESTATEDATA2_MOVEMENTDELAY] for sprites in the delayed state (x#SPRITESTATEDATA1_MOVEMENTSTATUS)
UpdateSpriteMovementDelay:
ld h, $c2
ld a, [H_CURRENTSPRITEOFFSET]
ld h, HIGH(wSpriteStateData2)
ldh a, [hCurrentSpriteOffset]
add $6
ld l, a
ld a, [hl] ; c2x6: movement byte 1
ld a, [hl] ; x#SPRITESTATEDATA2_MOVEMENTBYTE1
inc l
inc l
cp $fe
jr nc, .tickMoveCounter ; values $fe or $ff
cp WALK
jr nc, .tickMoveCounter ; values WALK or STAY
ld [hl], $0
jr .moving
.tickMoveCounter
dec [hl] ; c2x8: frame counter until next movement
dec [hl] ; x#SPRITESTATEDATA2_MOVEMENTDELAY
jr nz, notYetMoving
.moving
dec h
ld a, [H_CURRENTSPRITEOFFSET]
ldh a, [hCurrentSpriteOffset]
inc a
ld l, a
ld [hl], $1 ; c1x1 = 1 (mark as ready to move)
ld [hl], $1 ; [x#SPRITESTATEDATA1_MOVEMENTSTATUS] = 1 (mark as ready to move)
notYetMoving:
ld h, wSpriteStateData1 / $100
ld a, [H_CURRENTSPRITEOFFSET]
add $8
ld h, HIGH(wSpriteStateData1)
ldh a, [hCurrentSpriteOffset]
add SPRITESTATEDATA1_ANIMFRAMECOUNTER
ld l, a
ld [hl], $0 ; c1x8 = 0 (walk animation frame)
ld [hl], $0 ; [x#SPRITESTATEDATA1_ANIMFRAMECOUNTER] = 0 (walk animation frame)
jp UpdateSpriteImage
MakeNPCFacePlayer:
@ -430,108 +434,108 @@ MakeNPCFacePlayer:
.notFacingRight
ld c, SPRITE_FACING_LEFT
.facingDirectionDetermined
ld a, [H_CURRENTSPRITEOFFSET]
ldh a, [hCurrentSpriteOffset]
add $9
ld l, a
ld [hl], c ; c1x9: set facing direction
ld [hl], c ; [x#SPRITESTATEDATA1_FACINGDIRECTION]: set facing direction
jr notYetMoving
InitializeSpriteStatus:
ld [hl], $1 ; $c1x1: set movement status to ready
ld [hl], $1 ; [x#SPRITESTATEDATA1_MOVEMENTSTATUS] = ready
inc l
ld [hl], $ff ; $c1x2: set sprite image to $ff (invisible/off screen)
inc h
ld a, [H_CURRENTSPRITEOFFSET]
ld [hl], $ff ; [x#SPRITESTATEDATA1_IMAGEINDEX] = invisible/off screen
inc h ; HIGH(wSpriteStateData2)
ldh a, [hCurrentSpriteOffset]
add $2
ld l, a
ld a, $8
ld [hli], a ; $c2x2: set Y displacement to 8
ld [hl], a ; $c2x3: set X displacement to 8
ld [hli], a ; [x#SPRITESTATEDATA2_YDISPLACEMENT] = 8
ld [hl], a ; [x#SPRITESTATEDATA2_XDISPLACEMENT] = 8
ret
; calculates the sprite's screen position form its map position and the player position
; calculates the sprite's screen position from its map position and the player position
InitializeSpriteScreenPosition:
ld h, wSpriteStateData2 / $100
ld a, [H_CURRENTSPRITEOFFSET]
add $4
ld h, HIGH(wSpriteStateData2)
ldh a, [hCurrentSpriteOffset]
add SPRITESTATEDATA2_MAPY
ld l, a
ld a, [wYCoord]
ld b, a
ld a, [hl] ; c2x4 (Y position + 4)
ld a, [hl] ; x#SPRITESTATEDATA2_MAPY
sub b ; relative to player position
swap a ; * 16
sub $4 ; - 4
dec h
ld [hli], a ; c1x4 (screen Y position)
ld [hli], a ; [x#SPRITESTATEDATA1_YPIXELS]
inc h
ld a, [wXCoord]
ld b, a
ld a, [hli] ; c2x6 (X position + 4)
ld a, [hli] ; x#SPRITESTATEDATA2_MAPX
sub b ; relative to player position
swap a ; * 16
dec h
ld [hl], a ; c1x6 (screen X position)
ld [hl], a ; [x#SPRITESTATEDATA1_XPIXELS]
ret
; tests if sprite is off screen or otherwise unable to do anything
CheckSpriteAvailability:
predef IsObjectHidden
ld a, [$ffe5]
ldh a, [hIsHiddenMissableObject]
and a
jp nz, .spriteInvisible
ld h, wSpriteStateData2 / $100
ld a, [H_CURRENTSPRITEOFFSET]
add $6
ld h, HIGH(wSpriteStateData2)
ldh a, [hCurrentSpriteOffset]
add SPRITESTATEDATA2_MOVEMENTBYTE1
ld l, a
ld a, [hl] ; c2x6: movement byte 1
cp $fe
jr c, .skipXVisibilityTest ; movement byte 1 < $fe (i.e. the sprite's movement is scripted)
ld a, [H_CURRENTSPRITEOFFSET]
add $4
ld a, [hl] ; x#SPRITESTATEDATA2_MOVEMENTBYTE1
cp WALK
jr c, .skipXVisibilityTest ; movement byte 1 < WALK (i.e. the sprite's movement is scripted)
ldh a, [hCurrentSpriteOffset]
add SPRITESTATEDATA2_MAPY
ld l, a
ld b, [hl] ; c2x4: Y pos (+4)
ld b, [hl] ; x#SPRITESTATEDATA2_MAPY
ld a, [wYCoord]
cp b
jr z, .skipYVisibilityTest
jr nc, .spriteInvisible ; above screen region
add $8 ; screen is 9 tiles high
add SCREEN_HEIGHT / 2 - 1
cp b
jr c, .spriteInvisible ; below screen region
.skipYVisibilityTest
inc l
ld b, [hl] ; c2x5: X pos (+4)
ld b, [hl] ; x#SPRITESTATEDATA2_MAPX
ld a, [wXCoord]
cp b
jr z, .skipXVisibilityTest
jr nc, .spriteInvisible ; left of screen region
add $9 ; screen is 10 tiles wide
add SCREEN_WIDTH / 2 - 1
cp b
jr c, .spriteInvisible ; right of screen region
.skipXVisibilityTest
; make the sprite invisible if a text box is in front of it
; $5F is the maximum number for map tiles
call GetTileSpriteStandsOn
ld d, $60
ld d, MAP_TILESET_SIZE
ld a, [hli]
cp d
jr nc, .spriteInvisible ; standing on tile with ID >=$60 (bottom left tile)
jr nc, .spriteInvisible ; standing on tile with ID >=MAP_TILESET_SIZE (bottom left tile)
ld a, [hld]
cp d
jr nc, .spriteInvisible ; standing on tile with ID >=$60 (bottom right tile)
ld bc, -20
jr nc, .spriteInvisible ; standing on tile with ID >=MAP_TILESET_SIZE (bottom right tile)
ld bc, -SCREEN_WIDTH
add hl, bc ; go back one row of tiles
ld a, [hli]
cp d
jr nc, .spriteInvisible ; standing on tile with ID >=$60 (top left tile)
jr nc, .spriteInvisible ; standing on tile with ID >=MAP_TILESET_SIZE (top left tile)
ld a, [hl]
cp d
jr c, .spriteVisible ; standing on tile with ID >=$60 (top right tile)
jr c, .spriteVisible ; standing on tile with ID >=MAP_TILESET_SIZE (top right tile)
.spriteInvisible
ld h, wSpriteStateData1 / $100
ld a, [H_CURRENTSPRITEOFFSET]
add $2
ld h, HIGH(wSpriteStateData1)
ldh a, [hCurrentSpriteOffset]
add SPRITESTATEDATA1_IMAGEINDEX
ld l, a
ld [hl], $ff ; c1x2
ld [hl], $ff ; x#SPRITESTATEDATA1_IMAGEINDEX
scf
jr .done
.spriteVisible
@ -541,37 +545,37 @@ CheckSpriteAvailability:
jr nz, .done ; if player is currently walking, we're done
call UpdateSpriteImage
inc h
ld a, [H_CURRENTSPRITEOFFSET]
ldh a, [hCurrentSpriteOffset]
add $7
ld l, a
ld a, [wGrassTile]
cp c
ld a, $0
ld a, 0
jr nz, .notInGrass
ld a, $80
ld a, OAM_BEHIND_BG
.notInGrass
ld [hl], a ; c2x7
ld [hl], a ; x#SPRITESTATEDATA2_GRASSPRIORITY
and a
.done
ret
UpdateSpriteImage:
ld h, $c1
ld a, [H_CURRENTSPRITEOFFSET]
ld h, HIGH(wSpriteStateData1)
ldh a, [hCurrentSpriteOffset]
add $8
ld l, a
ld a, [hli] ; c1x8: walk animation frame
ld a, [hli] ; x#SPRITESTATEDATA1_ANIMFRAMECOUNTER
ld b, a
ld a, [hl] ; c1x9: facing direction
ld a, [hl] ; x#SPRITESTATEDATA1_FACINGDIRECTION
add b
ld b, a
ld a, [$ff93] ; current sprite offset
ldh a, [hTilePlayerStandingOn]
add b
ld b, a
ld a, [H_CURRENTSPRITEOFFSET]
ldh a, [hCurrentSpriteOffset]
add $2
ld l, a
ld [hl], b ; c1x2: sprite to display
ld [hl], b ; x#SPRITESTATEDATA1_IMAGEINDEX
ret
; tests if sprite can walk the specified direction
@ -581,13 +585,13 @@ UpdateSpriteImage:
; e: X movement delta (-1, 0 or 1)
; set carry on failure, clears carry on success
CanWalkOntoTile:
ld h, wSpriteStateData2 / $100
ld a, [H_CURRENTSPRITEOFFSET]
add $6
ld h, HIGH(wSpriteStateData2)
ldh a, [hCurrentSpriteOffset]
add SPRITESTATEDATA2_MOVEMENTBYTE1
ld l, a
ld a, [hl] ; c2x6 (movement byte 1)
cp $fe
jr nc, .notScripted ; values $fe and $ff
ld a, [hl] ; x#SPRITESTATEDATA2_MOVEMENTBYTE1
cp WALK
jr nc, .notScripted ; values WALK or STAY
; always allow walking if the movement is scripted
and a
ret
@ -602,24 +606,24 @@ CanWalkOntoTile:
jr z, .impassable
cp c
jr nz, .tilePassableLoop
ld h, $c2
ld a, [H_CURRENTSPRITEOFFSET]
ld h, HIGH(wSpriteStateData2)
ldh a, [hCurrentSpriteOffset]
add $6
ld l, a
ld a, [hl] ; $c2x6 (movement byte 1)
ld a, [hl] ; x#SPRITESTATEDATA2_MOVEMENTBYTE1
inc a
jr z, .impassable ; if $ff, no movement allowed (however, changing direction is)
ld h, wSpriteStateData1 / $100
ld a, [H_CURRENTSPRITEOFFSET]
add $4
ld h, HIGH(wSpriteStateData1)
ldh a, [hCurrentSpriteOffset]
add SPRITESTATEDATA1_YPIXELS
ld l, a
ld a, [hli] ; c1x4 (screen Y pos)
ld a, [hli] ; x#SPRITESTATEDATA1_YPIXELS
add $4 ; align to blocks (Y pos is always 4 pixels off)
add d ; add Y delta
cp $80 ; if value is >$80, the destination is off screen (either $81 or $FF underflow)
jr nc, .impassable ; don't walk off screen
inc l
ld a, [hl] ; c1x6 (screen X pos)
ld a, [hl] ; x#SPRITESTATEDATA1_XPIXELS
add e ; add X delta
cp $90 ; if value is >$90, the destination is off screen (either $91 or $FF underflow)
jr nc, .impassable ; don't walk off screen
@ -628,30 +632,35 @@ CanWalkOntoTile:
call DetectCollisionBetweenSprites
pop bc
pop de
ld h, wSpriteStateData1 / $100
ld a, [H_CURRENTSPRITEOFFSET]
ld h, HIGH(wSpriteStateData1)
ldh a, [hCurrentSpriteOffset]
add $c
ld l, a
ld a, [hl] ; c1xc (directions in which sprite collision would occur)
ld a, [hl] ; x#SPRITESTATEDATA1_COLLISIONDATA (directions in which sprite collision would occur)
and b ; check against chosen direction (1,2,4 or 8)
jr nz, .impassable ; collision between sprites, don't go there
ld h, wSpriteStateData2 / $100
ld a, [H_CURRENTSPRITEOFFSET]
add $2
ld h, HIGH(wSpriteStateData2)
ldh a, [hCurrentSpriteOffset]
add SPRITESTATEDATA2_YDISPLACEMENT
ld l, a
ld a, [hli] ; c2x2 (sprite Y displacement, initialized at $8, keep track of where a sprite did go)
ld a, [hli] ; x#SPRITESTATEDATA2_YDISPLACEMENT (initialized at $8, keep track of where a sprite did go)
bit 7, d ; check if going upwards (d=$ff)
jr nz, .upwards
add d
; bug: these tests against $5 probably were supposed to prevent
; sprites from walking out too far, but this line makes sprites get
; stuck whenever they walked upwards 5 steps
; on the other hand, the amount a sprite can walk out to the
; right of bottom is not limited (until the counter overflows)
cp $5
jr c, .impassable ; if c2x2+d < 5, don't go ;bug: this tests probably were supposed to prevent sprites
jr .checkHorizontal ; from walking out too far, but this line makes sprites get stuck
.upwards ; whenever they walked upwards 5 steps
sub $1 ; on the other hand, the amount a sprite can walk out to the
jr c, .impassable ; if d2x2 == 0, don't go ; right of bottom is not limited (until the counter overflows)
jr c, .impassable ; if [x#SPRITESTATEDATA2_YDISPLACEMENT]+d < 5, don't go
jr .checkHorizontal
.upwards
sub $1
jr c, .impassable ; if [x#SPRITESTATEDATA2_YDISPLACEMENT] == 0, don't go
.checkHorizontal
ld d, a
ld a, [hl] ; c2x3 (sprite X displacement, initialized at $8, keep track of where a sprite did go)
ld a, [hl] ; x#SPRITESTATEDATA2_XDISPLACEMENT (initialized at $8, keep track of where a sprite did go)
bit 7, e ; check if going left (e=$ff)
jr nz, .left
add e
@ -659,32 +668,32 @@ CanWalkOntoTile:
jr .passable
.left
sub $1
jr c, .impassable ; if d2x3 == 0, don't go
jr c, .impassable ; if [x#SPRITESTATEDATA2_XDISPLACEMENT] == 0, don't go
.passable
ld [hld], a ; update c2x3
ld [hl], d ; update c2x2
ld [hld], a ; update x#SPRITESTATEDATA2_XDISPLACEMENT
ld [hl], d ; update x#SPRITESTATEDATA2_YDISPLACEMENT
and a ; clear carry (marking success)
ret
.impassable
ld h, $c1
ld a, [H_CURRENTSPRITEOFFSET]
ld h, HIGH(wSpriteStateData1)
ldh a, [hCurrentSpriteOffset]
inc a
ld l, a
ld [hl], $2 ; c1x1 = 2 (set movement status to delayed)
ld [hl], $2 ; [x#SPRITESTATEDATA1_MOVEMENTSTATUS] = 2 (delayed)
inc l
inc l
xor a
ld [hli], a ; c1x3 = 0 (clear Y movement delta)
ld [hli], a ; [x#SPRITESTATEDATA1_YSTEPVECTOR] = 0
inc l
ld [hl], a ; c1x5 = 0 (clear X movement delta)
ld [hl], a ; [x#SPRITESTATEDATA1_XSTEPVECTOR] = 0
inc h
ld a, [H_CURRENTSPRITEOFFSET]
ldh a, [hCurrentSpriteOffset]
add $8
ld l, a
call Random
ld a, [hRandomAdd]
ldh a, [hRandomAdd]
and $7f
ld [hl], a ; c2x8: set next movement delay to a random value in [0,$7f] (again with delay $100 if value is 0)
ld [hl], a ; x#SPRITESTATEDATA2_MOVEMENTDELAY: set to a random value in [0,$7f] (again with delay $100 if value is 0)
scf ; set carry (marking failure to walk)
ret
@ -692,25 +701,25 @@ CanWalkOntoTile:
; this is always the lower left tile of the 2x2 tile blocks all sprites are snapped to
; hl: output pointer
GetTileSpriteStandsOn:
ld h, wSpriteStateData1 / $100
ld a, [H_CURRENTSPRITEOFFSET]
add $4
ld h, HIGH(wSpriteStateData1)
ldh a, [hCurrentSpriteOffset]
add SPRITESTATEDATA1_YPIXELS
ld l, a
ld a, [hli] ; c1x4: screen Y position
ld a, [hli] ; x#SPRITESTATEDATA1_YPIXELS
add $4 ; align to 2*2 tile blocks (Y position is always off 4 pixels to the top)
and $f0 ; in case object is currently moving
srl a ; screen Y tile * 4
ld c, a
ld b, $0
inc l
ld a, [hl] ; c1x6: screen Y position
ld a, [hl] ; x#SPRITESTATEDATA1_XPIXELS
srl a
srl a
srl a ; screen X tile
add SCREEN_WIDTH ; screen X tile + 20
ld d, $0
ld e, a
coord hl, 0, 0
hlcoord 0, 0
add hl, bc
add hl, bc
add hl, bc
@ -785,7 +794,7 @@ DoScriptedNPCMovement:
ld a, [hl]
add b
ld [hl], a
ld a, [H_CURRENTSPRITEOFFSET]
ldh a, [hCurrentSpriteOffset]
add $9
ld l, a
ld a, c
@ -808,17 +817,17 @@ InitScriptedNPCMovement:
jp AnimScriptedNPCMovement
GetSpriteScreenYPointer:
ld a, $4
ld a, SPRITESTATEDATA1_YPIXELS
ld b, a
jr GetSpriteScreenXYPointerCommon
GetSpriteScreenXPointer:
ld a, $6
ld a, SPRITESTATEDATA1_XPIXELS
ld b, a
GetSpriteScreenXYPointerCommon:
ld hl, wSpriteStateData1
ld a, [H_CURRENTSPRITEOFFSET]
ldh a, [hCurrentSpriteOffset]
add l
add b
ld l, a
@ -826,16 +835,16 @@ GetSpriteScreenXYPointerCommon:
AnimScriptedNPCMovement:
ld hl, wSpriteStateData2
ld a, [H_CURRENTSPRITEOFFSET]
add $e
ldh a, [hCurrentSpriteOffset]
add SPRITESTATEDATA2_IMAGEBASEOFFSET
ld l, a
ld a, [hl] ; VRAM slot
dec a
swap a
ld b, a
ld hl, wSpriteStateData1
ld a, [H_CURRENTSPRITEOFFSET]
add $9
ldh a, [hCurrentSpriteOffset]
add SPRITESTATEDATA1_FACINGDIRECTION
ld l, a
ld a, [hl] ; facing direction
cp SPRITE_FACING_DOWN
@ -850,21 +859,21 @@ AnimScriptedNPCMovement:
.anim
add b
ld b, a
ld [hSpriteVRAMSlotAndFacing], a
ldh [hSpriteVRAMSlotAndFacing], a
call AdvanceScriptedNPCAnimFrameCounter
ld hl, wSpriteStateData1
ld a, [H_CURRENTSPRITEOFFSET]
add $2
ldh a, [hCurrentSpriteOffset]
add SPRITESTATEDATA1_IMAGEINDEX
ld l, a
ld a, [hSpriteVRAMSlotAndFacing]
ldh a, [hSpriteVRAMSlotAndFacing]
ld b, a
ld a, [hSpriteAnimFrameCounter]
ldh a, [hSpriteAnimFrameCounter]
add b
ld [hl], a
ret
AdvanceScriptedNPCAnimFrameCounter:
ld a, [H_CURRENTSPRITEOFFSET]
ldh a, [hCurrentSpriteOffset]
add $7
ld l, a
ld a, [hl] ; intra-animation frame counter
@ -879,5 +888,5 @@ AdvanceScriptedNPCAnimFrameCounter:
inc a
and $3
ld [hl], a
ld [hSpriteAnimFrameCounter], a
ldh [hSpriteAnimFrameCounter], a
ret

View file

@ -1,71 +0,0 @@
OaksAideScript:
ld hl, OaksAideHiText
call PrintText
call YesNoChoice
ld a, [wCurrentMenuItem]
and a
jr nz, .choseNo
ld hl, wPokedexOwned
ld b, wPokedexOwnedEnd - wPokedexOwned
call CountSetBits
ld a, [wNumSetBits]
ld [hOaksAideNumMonsOwned], a
ld b, a
ld a, [hOaksAideRequirement]
cp b
jr z, .giveItem
jr nc, .notEnoughOwnedMons
.giveItem
ld hl, OaksAideHereYouGoText
call PrintText
ld a, [hOaksAideRewardItem]
ld b, a
ld c, 1
call GiveItem
jr nc, .bagFull
ld hl, OaksAideGotItemText
call PrintText
ld a, $1
jr .done
.bagFull
ld hl, OaksAideNoRoomText
call PrintText
xor a
jr .done
.notEnoughOwnedMons
ld hl, OaksAideUhOhText
call PrintText
ld a, $80
jr .done
.choseNo
ld hl, OaksAideComeBackText
call PrintText
ld a, $ff
.done
ld [hOaksAideResult], a
ret
OaksAideHiText:
TX_FAR _OaksAideHiText
db "@"
OaksAideUhOhText:
TX_FAR _OaksAideUhOhText
db "@"
OaksAideComeBackText:
TX_FAR _OaksAideComeBackText
db "@"
OaksAideHereYouGoText:
TX_FAR _OaksAideHereYouGoText
db "@"
OaksAideGotItemText:
TX_FAR _OaksAideGotItemText
TX_SFX_ITEM_1
db "@"
OaksAideNoRoomText:
TX_FAR _OaksAideNoRoomText
db "@"

View file

@ -1,189 +0,0 @@
PrepareOAMData:
; Determine OAM data for currently visible
; sprites and write it to wOAMBuffer.
ld a, [wUpdateSpritesEnabled]
dec a
jr z, .updateEnabled
cp -1
ret nz
ld [wUpdateSpritesEnabled], a
jp HideSprites
.updateEnabled
xor a
ld [hOAMBufferOffset], a
.spriteLoop
ld [hSpriteOffset2], a
ld d, wSpriteStateData1 / $100
ld a, [hSpriteOffset2]
ld e, a
ld a, [de] ; c1x0
and a
jp z, .nextSprite
inc e
inc e
ld a, [de] ; c1x2 (facing/anim)
ld [wd5cd], a
cp $ff ; off-screen (don't draw)
jr nz, .visible
call GetSpriteScreenXY
jr .nextSprite
.visible
cp $a0 ; is the sprite unchanging like an item ball or boulder?
jr c, .usefacing
; unchanging
and $f
add $10 ; skip to the second half of the table which doesn't account for facing direction
jr .next
.usefacing
and $f
.next
ld l, a
; get sprite priority
push de
inc d
ld a, e
add $5
ld e, a
ld a, [de] ; c2x7
and $80
ld [hSpritePriority], a ; temp store sprite priority
pop de
; read the entry from the table
ld h, 0
ld bc, SpriteFacingAndAnimationTable
add hl, hl
add hl, hl
add hl, bc
ld a, [hli]
ld c, a
ld a, [hli]
ld b, a
ld a, [hli]
ld h, [hl]
ld l, a
call GetSpriteScreenXY
ld a, [hOAMBufferOffset]
ld e, a
ld d, wOAMBuffer / $100
.tileLoop
ld a, [hSpriteScreenY] ; temp for sprite Y position
add $10 ; Y=16 is top of screen (Y=0 is invisible)
add [hl] ; add Y offset from table
ld [de], a ; write new sprite OAM Y position
inc hl
ld a, [hSpriteScreenX] ; temp for sprite X position
add $8 ; X=8 is left of screen (X=0 is invisible)
add [hl] ; add X offset from table
inc e
ld [de], a ; write new sprite OAM X position
inc e
ld a, [bc] ; read pattern number offset (accommodates orientation (offset 0,4 or 8) and animation (offset 0 or $80))
inc bc
push bc
ld b, a
ld a, [wd5cd] ; temp copy of c1x2
swap a ; high nybble determines sprite used (0 is always player sprite, next are some npcs)
and $f
; Sprites $a and $b have one face (and therefore 4 tiles instead of 12).
; As a result, sprite $b's tile offset is less than normal.
cp $b
jr nz, .notFourTileSprite
ld a, $a * 12 + 4
jr .next2
.notFourTileSprite
; a *= 12
sla a
sla a
ld c, a
sla a
add c
.next2
add b ; add the tile offset from the table (based on frame and facing direction)
pop bc
ld [de], a ; tile id
inc hl
inc e
ld a, [hl]
bit 1, a ; is the tile allowed to set the sprite priority bit?
jr z, .skipPriority
ld a, [hSpritePriority]
or [hl]
.skipPriority
inc hl
ld [de], a
inc e
bit 0, a ; OAMFLAG_ENDOFDATA
jr z, .tileLoop
ld a, e
ld [hOAMBufferOffset], a
.nextSprite
ld a, [hSpriteOffset2]
add $10
cp $100 % $100
jp nz, .spriteLoop
; Clear unused OAM.
ld a, [hOAMBufferOffset]
ld l, a
ld h, wOAMBuffer / $100
ld de, $4
ld b, $a0
ld a, [wd736]
bit 6, a ; jumping down ledge or fishing animation?
ld a, $a0
jr z, .clear
; Don't clear the last 4 entries because they are used for the shadow in the
; jumping down ledge animation and the rod in the fishing animation.
ld a, $90
.clear
cp l
ret z
ld [hl], b
add hl, de
jr .clear
GetSpriteScreenXY:
inc e
inc e
ld a, [de] ; c1x4
ld [hSpriteScreenY], a
inc e
inc e
ld a, [de] ; c1x6
ld [hSpriteScreenX], a
ld a, 4
add e
ld e, a
ld a, [hSpriteScreenY]
add 4
and $f0
ld [de], a ; c1xa (y)
inc e
ld a, [hSpriteScreenX]
and $f0
ld [de], a ; c1xb (x)
ret

View file

@ -0,0 +1,201 @@
FindPathToPlayer:
xor a
ld hl, hFindPathNumSteps
ld [hli], a ; hFindPathNumSteps
ld [hli], a ; hFindPathFlags
ld [hli], a ; hFindPathYProgress
ld [hl], a ; hFindPathXProgress
ld hl, wNPCMovementDirections2
ld de, $0
.loop
ldh a, [hFindPathYProgress]
ld b, a
ldh a, [hNPCPlayerYDistance] ; Y distance in steps
call CalcDifference
ld d, a
and a
jr nz, .asm_f8da
ldh a, [hFindPathFlags]
set 0, a ; current end of path matches the player's Y coordinate
ldh [hFindPathFlags], a
.asm_f8da
ldh a, [hFindPathXProgress]
ld b, a
ldh a, [hNPCPlayerXDistance] ; X distance in steps
call CalcDifference
ld e, a
and a
jr nz, .asm_f8ec
ldh a, [hFindPathFlags]
set 1, a ; current end of path matches the player's X coordinate
ldh [hFindPathFlags], a
.asm_f8ec
ldh a, [hFindPathFlags]
cp $3 ; has the end of the path reached the player's position?
jr z, .done
; Compare whether the X distance between the player and the current of the path
; is greater or if the Y distance is. Then, try to reduce whichever is greater.
ld a, e
cp d
jr c, .yDistanceGreater
; x distance is greater
ldh a, [hNPCPlayerRelativePosFlags]
bit 1, a
jr nz, .playerIsLeftOfNPC
ld d, NPC_MOVEMENT_RIGHT
jr .next1
.playerIsLeftOfNPC
ld d, NPC_MOVEMENT_LEFT
.next1
ldh a, [hFindPathXProgress]
add 1
ldh [hFindPathXProgress], a
jr .storeDirection
.yDistanceGreater
ldh a, [hNPCPlayerRelativePosFlags]
bit 0, a
jr nz, .playerIsAboveNPC
ld d, NPC_MOVEMENT_DOWN
jr .next2
.playerIsAboveNPC
ld d, NPC_MOVEMENT_UP
.next2
ldh a, [hFindPathYProgress]
add 1
ldh [hFindPathYProgress], a
.storeDirection
ld a, d
ld [hli], a
ldh a, [hFindPathNumSteps]
inc a
ldh [hFindPathNumSteps], a
jp .loop
.done
ld [hl], $ff
ret
CalcPositionOfPlayerRelativeToNPC:
xor a
ldh [hNPCPlayerRelativePosFlags], a
ld a, [wSpritePlayerStateData1YPixels]
ld d, a
ld a, [wSpritePlayerStateData1XPixels]
ld e, a
ld hl, wSpriteStateData1
ldh a, [hNPCSpriteOffset]
add l
add SPRITESTATEDATA1_YPIXELS
ld l, a
jr nc, .noCarry
inc h
.noCarry
ld a, d
ld b, a
ld a, [hli] ; NPC sprite screen Y position in pixels
call CalcDifference
jr nc, .NPCSouthOfOrAlignedWithPlayer
.NPCNorthOfPlayer
push hl
ld hl, hNPCPlayerRelativePosFlags
bit 0, [hl]
set 0, [hl]
pop hl
jr .divideYDistance
.NPCSouthOfOrAlignedWithPlayer
push hl
ld hl, hNPCPlayerRelativePosFlags
bit 0, [hl]
res 0, [hl]
pop hl
.divideYDistance
push hl
ld hl, hDividend2
ld [hli], a
ld a, 16
ld [hli], a
call DivideBytes ; divide Y absolute distance by 16
ld a, [hl] ; quotient
ldh [hNPCPlayerYDistance], a
pop hl
inc hl
ld b, e
ld a, [hl] ; NPC sprite screen X position in pixels
call CalcDifference
jr nc, .NPCEastOfOrAlignedWithPlayer
.NPCWestOfPlayer
push hl
ld hl, hNPCPlayerRelativePosFlags
bit 1, [hl]
set 1, [hl]
pop hl
jr .divideXDistance
.NPCEastOfOrAlignedWithPlayer
push hl
ld hl, hNPCPlayerRelativePosFlags
bit 1, [hl]
res 1, [hl]
pop hl
.divideXDistance
ldh [hDividend2], a
ld a, 16
ldh [hDivisor2], a
call DivideBytes ; divide X absolute distance by 16
ldh a, [hQuotient2]
ldh [hNPCPlayerXDistance], a
ldh a, [hNPCPlayerRelativePosPerspective]
and a
ret z
ldh a, [hNPCPlayerRelativePosFlags]
cpl
and $3
ldh [hNPCPlayerRelativePosFlags], a
ret
ConvertNPCMovementDirectionsToJoypadMasks:
ldh a, [hNPCMovementDirections2Index]
ld [wNPCMovementDirections2Index], a
dec a
ld de, wSimulatedJoypadStatesEnd
ld hl, wNPCMovementDirections2
add l
ld l, a
jr nc, .loop
inc h
.loop
ld a, [hld]
call ConvertNPCMovementDirectionToJoypadMask
ld [de], a
inc de
ldh a, [hNPCMovementDirections2Index]
dec a
ldh [hNPCMovementDirections2Index], a
jr nz, .loop
ret
ConvertNPCMovementDirectionToJoypadMask:
push hl
ld b, a
ld hl, NPCMovementDirectionsToJoypadMasksTable
.loop
ld a, [hli]
cp $ff
jr z, .done
cp b
jr z, .loadJoypadMask
inc hl
jr .loop
.loadJoypadMask
ld a, [hl]
.done
pop hl
ret
NPCMovementDirectionsToJoypadMasksTable:
db NPC_MOVEMENT_UP, D_UP
db NPC_MOVEMENT_DOWN, D_DOWN
db NPC_MOVEMENT_LEFT, D_LEFT
db NPC_MOVEMENT_RIGHT, D_RIGHT
db $ff
; unreferenced
ret

View file

@ -1,102 +0,0 @@
PewterGuys:
ld hl, wSimulatedJoypadStatesEnd
ld a, [wSimulatedJoypadStatesIndex]
dec a ; this decrement causes it to overwrite the last byte before $FF in the list
ld [wSimulatedJoypadStatesIndex], a
ld d, 0
ld e, a
add hl, de
ld d, h
ld e, l
ld hl, PointerTable_37ce6
ld a, [wWhichPewterGuy]
add a
ld b, 0
ld c, a
add hl, bc
ld a, [hli]
ld h, [hl]
ld l, a
ld a, [wYCoord]
ld b, a
ld a, [wXCoord]
ld c, a
.findMatchingCoordsLoop
ld a, [hli]
cp b
jr nz, .nextEntry1
ld a, [hli]
cp c
jr nz, .nextEntry2
ld a, [hli]
ld h, [hl]
ld l, a
.copyMovementDataLoop
ld a, [hli]
cp $ff
ret z
ld [de], a
inc de
ld a, [wSimulatedJoypadStatesIndex]
inc a
ld [wSimulatedJoypadStatesIndex], a
jr .copyMovementDataLoop
.nextEntry1
inc hl
.nextEntry2
inc hl
inc hl
jr .findMatchingCoordsLoop
PointerTable_37ce6:
dw PewterMuseumGuyCoords
dw PewterGymGuyCoords
; these are the four coordinates of the spaces below, above, to the left and
; to the right of the museum guy, and pointers to different movements for
; the player to make to get positioned before the main movement.
PewterMuseumGuyCoords:
db 18, 27
dw .down
db 16, 27
dw .up
db 17, 26
dw .left
db 17, 28
dw .right
.down
db D_UP, D_UP, $ff
.up
db D_RIGHT, D_LEFT, $ff
.left
db D_UP, D_RIGHT, $ff
.right
db D_UP, D_LEFT, $ff
; these are the five coordinates which trigger the gym guy and pointers to
; different movements for the player to make to get positioned before the
; main movement
; $00 is a pause
PewterGymGuyCoords:
db 16, 34
dw .one
db 17, 35
dw .two
db 18, 37
dw .three
db 19, 37
dw .four
db 17, 36
dw .five
.one
db D_LEFT, D_DOWN, D_DOWN, D_RIGHT, $ff
.two
db D_LEFT, D_DOWN, D_RIGHT, D_LEFT, $ff
.three
db D_LEFT, D_LEFT, D_LEFT, $00, $00, $00, $00, $00, $00, $00, $00, $ff
.four
db D_LEFT, D_LEFT, D_UP, D_LEFT, $ff
.five
db D_LEFT, D_DOWN, D_LEFT, $00, $00, $00, $00, $00, $00, $00, $00, $ff

122
engine/overworld/player_animations.asm Executable file → Normal file
View file

@ -1,7 +1,7 @@
EnterMapAnim:
EnterMapAnim::
call InitFacingDirectionList
ld a, $ec
ld [wSpriteStateData1 + 4], a ; player's sprite Y screen position
ld [wSpritePlayerStateData1YPixels], a
call Delay3
push hl
call GBFadeInFromWhite
@ -90,7 +90,7 @@ PlayerSpinWhileMovingDown:
ld [hl], a ; wPlayerSpinWhileMovingUpOrDownAnimFrameDelay
jp PlayerSpinWhileMovingUpOrDown
_LeaveMapAnim:
_LeaveMapAnim::
call InitFacingDirectionList
call IsPlayerStandingOnWarpPadOrHole
ld a, b
@ -227,19 +227,19 @@ DoFlyAnimation:
ld a, [wFlyAnimBirdSpriteImageIndex]
xor $1 ; make the bird flap its wings
ld [wFlyAnimBirdSpriteImageIndex], a
ld [wSpriteStateData1 + 2], a
ld [wSpritePlayerStateData1ImageIndex], a
call Delay3
ld a, [wFlyAnimUsingCoordList]
cp $ff
jr z, .skipCopyingCoords ; if the bird is flapping its wings in place
ld hl, wSpriteStateData1 + 4
ld hl, wSpritePlayerStateData1YPixels
ld a, [de]
inc de
ld [hli], a
ld [hli], a ; y
inc hl
ld a, [de]
inc de
ld [hl], a
ld [hl], a ; x
.skipCopyingCoords
ld a, [wFlyAnimCounter]
dec a
@ -250,23 +250,23 @@ DoFlyAnimation:
LoadBirdSpriteGraphics:
ld de, BirdSprite
ld hl, vNPCSprites
lb bc, BANK(BirdSprite), $0c
lb bc, BANK(BirdSprite), 12
call CopyVideoData
ld de, BirdSprite + $c0 ; moving animation sprite
ld de, BirdSprite tile 12 ; moving animation sprite
ld hl, vNPCSprites2
lb bc, BANK(BirdSprite), $0c
lb bc, BANK(BirdSprite), 12
jp CopyVideoData
InitFacingDirectionList:
ld a, [wSpriteStateData1 + 2] ; player's sprite facing direction (image index is locked to standing images)
ld a, [wSpritePlayerStateData1ImageIndex] ; (image index is locked to standing images)
ld [wSavedPlayerFacingDirection], a
ld a, [wSpriteStateData1 + 4] ; player's sprite Y screen position
ld a, [wSpritePlayerStateData1YPixels]
ld [wSavedPlayerScreenY], a
ld hl, PlayerSpinningFacingOrder
ld de, wFacingDirectionList
ld bc, 4
call CopyData
ld a, [wSpriteStateData1 + 2] ; player's sprite facing direction (image index is locked to standing images)
ld a, [wSpritePlayerStateData1ImageIndex] ; (image index is locked to standing images)
ld hl, wFacingDirectionList
; find the place in the list that matches the current facing direction
.loop
@ -284,7 +284,7 @@ PlayerSpinningFacingOrder:
SpinPlayerSprite:
; copy the current value from the list into the sprite data and rotate the list
ld a, [hl]
ld [wSpriteStateData1 + 2], a ; player's sprite facing direction (image index is locked to standing images)
ld [wSpritePlayerStateData1ImageIndex], a ; (image index is locked to standing images)
push hl
ld hl, wFacingDirectionList
ld de, wFacingDirectionList - 1
@ -320,9 +320,9 @@ PlayerSpinWhileMovingUpOrDown:
call SpinPlayerSprite
ld a, [wPlayerSpinWhileMovingUpOrDownAnimDeltaY]
ld c, a
ld a, [wSpriteStateData1 + 4] ; player's sprite Y screen position
ld a, [wSpritePlayerStateData1YPixels]
add c
ld [wSpriteStateData1 + 4], a
ld [wSpritePlayerStateData1YPixels], a
ld c, a
ld a, [wPlayerSpinWhileMovingUpOrDownAnimMaxY]
cp c
@ -334,9 +334,9 @@ PlayerSpinWhileMovingUpOrDown:
RestoreFacingDirectionAndYScreenPos:
ld a, [wSavedPlayerScreenY]
ld [wSpriteStateData1 + 4], a
ld [wSpritePlayerStateData1YPixels], a
ld a, [wSavedPlayerFacingDirection]
ld [wSpriteStateData1 + 2], a
ld [wSpritePlayerStateData1ImageIndex], a ; (image index is locked to standing images)
ret
; if SGB, 2 frames, else 3 frames
@ -347,9 +347,9 @@ GetPlayerTeleportAnimFrameDelay:
inc a
ret
IsPlayerStandingOnWarpPadOrHole:
IsPlayerStandingOnWarpPadOrHole::
ld b, 0
ld hl, .warpPadAndHoleData
ld hl, WarpPadAndHoleData
ld a, [wCurMapTileset]
ld c, a
.loop
@ -358,7 +358,7 @@ IsPlayerStandingOnWarpPadOrHole:
jr z, .done
cp c
jr nz, .nextEntry
aCoord 8, 9
lda_coord 8, 9
cp [hl]
jr z, .foundMatch
.nextEntry
@ -373,13 +373,7 @@ IsPlayerStandingOnWarpPadOrHole:
ld [wStandingOnWarpPadOrHole], a
ret
; format: db tileset id, tile id, value to be put in [wStandingOnWarpPadOrHole]
.warpPadAndHoleData:
db FACILITY, $20, 1 ; warp pad
db FACILITY, $11, 2 ; hole
db CAVERN, $22, 2 ; hole
db INTERIOR, $55, 1 ; warp pad
db $FF
INCLUDE "data/tilesets/warp_pad_hole_tile_ids.asm"
FishingAnim:
ld c, 10
@ -387,13 +381,13 @@ FishingAnim:
ld hl, wd736
set 6, [hl] ; reserve the last 4 OAM entries
ld de, RedSprite
ld hl, vNPCSprites
lb bc, BANK(RedSprite), $c
ld hl, vNPCSprites tile $00
lb bc, BANK(RedSprite), 12
call CopyVideoData
ld a, $4
ld hl, RedFishingTiles
call LoadAnimSpriteGfx
ld a, [wSpriteStateData1 + 2]
ld a, [wSpritePlayerStateData1ImageIndex]
ld c, a
ld b, $0
ld hl, FishingRodOAM
@ -416,7 +410,7 @@ FishingAnim:
; shake the player's sprite vertically
ld b, 10
.loop
ld hl, wSpriteStateData1 + 4 ; player's sprite Y screen position
ld hl, wSpritePlayerStateData1YPixels
call .ShakePlayerSprite
ld hl, wOAMBuffer + $9c
call .ShakePlayerSprite
@ -426,7 +420,7 @@ FishingAnim:
; If the player is facing up, hide the fishing rod so it doesn't overlap with
; the exclamation bubble that will be shown next.
ld a, [wSpriteStateData1 + 2] ; player's sprite facing direction
ld a, [wSpritePlayerStateData1ImageIndex] ; (image index is locked to standing images)
cp SPRITE_FACING_UP
jr nz, .skipHidingFishingRod
ld a, $a0
@ -440,7 +434,7 @@ FishingAnim:
predef EmotionBubble
; If the player is facing up, unhide the fishing rod.
ld a, [wSpriteStateData1 + 2] ; player's sprite facing direction
ld a, [wSpritePlayerStateData1ImageIndex] ; (image index is locked to standing images)
cp SPRITE_FACING_UP
jr nz, .skipUnhidingFishingRod
ld a, $44
@ -463,46 +457,38 @@ FishingAnim:
ret
NoNibbleText:
TX_FAR _NoNibbleText
db "@"
text_far _NoNibbleText
text_end
NothingHereText:
TX_FAR _NothingHereText
db "@"
text_far _NothingHereText
text_end
ItsABiteText:
TX_FAR _ItsABiteText
db "@"
text_far _ItsABiteText
text_end
FishingRodOAM:
; specifies how the fishing rod should be drawn on the screen
; first byte = screen y coordinate
; second byte = screen x coordinate
; third byte = tile number
; fourth byte = sprite properties
db $5B, $4C, $FD, $00 ; player facing down
db $44, $4C, $FD, $00 ; player facing up
db $50, $40, $FE, $00 ; player facing left
db $50, $58, $FE, $20 ; player facing right ($20 means "horizontally flip the tile")
dbsprite 9, 11, 4, 3, $fd, 0 ; down
dbsprite 9, 8, 4, 4, $fd, 0 ; up
dbsprite 8, 10, 0, 0, $fe, 0 ; left
dbsprite 11, 10, 0, 0, $fe, OAM_HFLIP ; right
fishing_gfx: MACRO
dw \1
db \2
db BANK(\1)
dw vNPCSprites tile \3
ENDM
RedFishingTiles:
dw RedFishingTilesFront
db 2, BANK(RedFishingTilesFront)
dw vNPCSprites + $20
fishing_gfx RedFishingTilesFront, 2, $02
fishing_gfx RedFishingTilesBack, 2, $06
fishing_gfx RedFishingTilesSide, 2, $0a
fishing_gfx RedFishingRodTiles, 3, $fd
dw RedFishingTilesBack
db 2, BANK(RedFishingTilesBack)
dw vNPCSprites + $60
dw RedFishingTilesSide
db 2, BANK(RedFishingTilesSide)
dw vNPCSprites + $a0
dw RedFishingRodTiles
db 3, BANK(RedFishingRodTiles)
dw vNPCSprites2 + $7d0
_HandleMidJump:
_HandleMidJump::
ld a, [wPlayerJumpingYScreenCoordsIndex]
ld c, a
inc a
@ -513,7 +499,7 @@ _HandleMidJump:
ld hl, PlayerJumpingYScreenCoords
add hl, bc
ld a, [hl]
ld [wSpriteStateData1 + 4], a ; player's sprite y coordinate
ld [wSpritePlayerStateData1YPixels], a
ret
.finishedJump
ld a, [wWalkCounter]
@ -522,9 +508,9 @@ _HandleMidJump:
call UpdateSprites
call Delay3
xor a
ld [hJoyHeld], a
ld [hJoyPressed], a
ld [hJoyReleased], a
ldh [hJoyHeld], a
ldh [hJoyPressed], a
ldh [hJoyReleased], a
ld [wPlayerJumpingYScreenCoordsIndex], a
ld hl, wd736
res 6, [hl] ; not jumping down a ledge any more

View file

@ -1,5 +1,5 @@
; only used for setting bit 2 of wd736 upon entering a new map
IsPlayerStandingOnWarp:
IsPlayerStandingOnWarp::
ld a, [wNumberOfWarps]
and a
ret z
@ -17,7 +17,7 @@ IsPlayerStandingOnWarp:
ld a, [hli] ; target warp
ld [wDestinationWarpID], a
ld a, [hl] ; target map
ld [hWarpDestinationMap], a
ldh [hWarpDestinationMap], a
ld hl, wd736
set 2, [hl] ; standing on warp flag
ret
@ -31,7 +31,7 @@ IsPlayerStandingOnWarp:
jr nz, .loop
ret
CheckForceBikeOrSurf:
CheckForceBikeOrSurf::
ld hl, wd732
bit 5, [hl]
ret nz
@ -82,13 +82,13 @@ CheckForceBikeOrSurf:
ld [wWalkBikeSurfStateCopy], a
jp ForceBikeOrSurf
INCLUDE "data/force_bike_surf.asm"
INCLUDE "data/maps/force_bike_surf.asm"
IsPlayerFacingEdgeOfMap:
IsPlayerFacingEdgeOfMap::
push hl
push de
push bc
ld a, [wSpriteStateData1 + 9] ; player sprite's facing direction
ld a, [wSpritePlayerStateData1FacingDirection]
srl a
ld c, a
ld b, $0
@ -150,19 +150,19 @@ IsPlayerFacingEdgeOfMap:
scf
ret
IsWarpTileInFrontOfPlayer:
IsWarpTileInFrontOfPlayer::
push hl
push de
push bc
call _GetTileAndCoordsInFrontOfPlayer
ld a, [wCurMap]
cp SS_ANNE_BOW
jr z, .ssAnne5
ld a, [wSpriteStateData1 + 9] ; player sprite's facing direction
jr z, IsSSAnneBowWarpTileInFrontOfPlayer
ld a, [wSpritePlayerStateData1FacingDirection]
srl a
ld c, a
ld b, 0
ld hl, .warpTileListPointers
ld hl, WarpTileListPointers
add hl, bc
ld a, [hli]
ld h, [hl]
@ -176,39 +176,23 @@ IsWarpTileInFrontOfPlayer:
pop hl
ret
.warpTileListPointers:
dw .facingDownWarpTiles
dw .facingUpWarpTiles
dw .facingLeftWarpTiles
dw .facingRightWarpTiles
INCLUDE "data/tilesets/warp_carpet_tile_ids.asm"
.facingDownWarpTiles
db $01,$12,$17,$3D,$04,$18,$33,$FF
.facingUpWarpTiles
db $01,$5C,$FF
.facingLeftWarpTiles
db $1A,$4B,$FF
.facingRightWarpTiles
db $0F,$4E,$FF
.ssAnne5
IsSSAnneBowWarpTileInFrontOfPlayer:
ld a, [wTileInFrontOfPlayer]
cp $15
jr nz, .notSSAnne5Warp
scf
jr .done
jr IsWarpTileInFrontOfPlayer.done
.notSSAnne5Warp
and a
jr .done
jr IsWarpTileInFrontOfPlayer.done
IsPlayerStandingOnDoorTileOrWarpTile:
IsPlayerStandingOnDoorTileOrWarpTile::
push hl
push de
push bc
callba IsPlayerStandingOnDoorTile
farcall IsPlayerStandingOnDoorTile
jr c, .done
ld a, [wCurMapTileset]
add a
@ -220,7 +204,7 @@ IsPlayerStandingOnDoorTileOrWarpTile:
ld h, [hl]
ld l, a
ld de, $1
aCoord 8, 9
lda_coord 8, 9
call IsInArray
jr nc, .done
ld hl, wd736
@ -231,36 +215,36 @@ IsPlayerStandingOnDoorTileOrWarpTile:
pop hl
ret
INCLUDE "data/warp_tile_ids.asm"
INCLUDE "data/tilesets/warp_tile_ids.asm"
PrintSafariZoneSteps:
PrintSafariZoneSteps::
ld a, [wCurMap]
cp SAFARI_ZONE_EAST
ret c
cp CERULEAN_CAVE_2F
ret nc
coord hl, 0, 0
hlcoord 0, 0
ld b, 3
ld c, 7
call TextBoxBorder
coord hl, 1, 1
hlcoord 1, 1
ld de, wSafariSteps
lb bc, 2, 3
call PrintNumber
coord hl, 4, 1
hlcoord 4, 1
ld de, SafariSteps
call PlaceString
coord hl, 1, 3
hlcoord 1, 3
ld de, SafariBallText
call PlaceString
ld a, [wNumSafariBalls]
cp 10
jr nc, .asm_c56d
coord hl, 5, 3
hlcoord 5, 3
ld a, " "
ld [hl], a
.asm_c56d
coord hl, 6, 3
hlcoord 6, 3
ld de, wNumSafariBalls
lb bc, 1, 2
jp PrintNumber
@ -279,32 +263,32 @@ _GetTileAndCoordsInFrontOfPlayer:
ld d, a
ld a, [wXCoord]
ld e, a
ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
ld a, [wSpritePlayerStateData1FacingDirection]
and a ; cp SPRITE_FACING_DOWN
jr nz, .notFacingDown
; facing down
aCoord 8, 11
lda_coord 8, 11
inc d
jr .storeTile
.notFacingDown
cp SPRITE_FACING_UP
jr nz, .notFacingUp
; facing up
aCoord 8, 7
lda_coord 8, 7
dec d
jr .storeTile
.notFacingUp
cp SPRITE_FACING_LEFT
jr nz, .notFacingLeft
; facing left
aCoord 6, 9
lda_coord 6, 9
dec e
jr .storeTile
.notFacingLeft
cp SPRITE_FACING_RIGHT
jr nz, .storeTile
; facing right
aCoord 10, 9
lda_coord 10, 9
inc e
.storeTile
ld c, a
@ -313,45 +297,45 @@ _GetTileAndCoordsInFrontOfPlayer:
GetTileTwoStepsInFrontOfPlayer:
xor a
ld [$ffdb], a
ldh [hPlayerFacing], a
ld hl, wYCoord
ld a, [hli]
ld d, a
ld e, [hl]
ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
ld a, [wSpritePlayerStateData1FacingDirection]
and a ; cp SPRITE_FACING_DOWN
jr nz, .notFacingDown
; facing down
ld hl, $ffdb
ld hl, hPlayerFacing
set 0, [hl]
aCoord 8, 13
lda_coord 8, 13
inc d
jr .storeTile
.notFacingDown
cp SPRITE_FACING_UP
jr nz, .notFacingUp
; facing up
ld hl, $ffdb
ld hl, hPlayerFacing
set 1, [hl]
aCoord 8, 5
lda_coord 8, 5
dec d
jr .storeTile
.notFacingUp
cp SPRITE_FACING_LEFT
jr nz, .notFacingLeft
; facing left
ld hl, $ffdb
ld hl, hPlayerFacing
set 2, [hl]
aCoord 4, 9
lda_coord 4, 9
dec e
jr .storeTile
.notFacingLeft
cp SPRITE_FACING_RIGHT
jr nz, .storeTile
; facing right
ld hl, $ffdb
ld hl, hPlayerFacing
set 3, [hl]
aCoord 12, 9
lda_coord 12, 9
inc e
.storeTile
ld c, a
@ -391,36 +375,36 @@ CheckForBoulderCollisionWithSprites:
swap a
ld d, 0
ld e, a
ld hl, wSpriteStateData2 + $14
ld hl, wSprite01StateData2MapY
add hl, de
ld a, [hli] ; map Y position
ld [$ffdc], a
ldh [hPlayerYCoord], a
ld a, [hl] ; map X position
ld [$ffdd], a
ldh [hPlayerXCoord], a
ld a, [wNumSprites]
ld c, a
ld de, $f
ld hl, wSpriteStateData2 + $14
ld a, [$ffdb]
ld hl, wSprite01StateData2MapY
ldh a, [hPlayerFacing]
and $3 ; facing up or down?
jr z, .pushingHorizontallyLoop
.pushingVerticallyLoop
inc hl
ld a, [$ffdd]
ldh a, [hPlayerXCoord]
cp [hl]
jr nz, .nextSprite1 ; if X coordinates don't match
dec hl
ld a, [hli]
ld b, a
ld a, [$ffdb]
ldh a, [hPlayerFacing]
rrca
jr c, .pushingDown
; pushing up
ld a, [$ffdc]
ldh a, [hPlayerYCoord]
dec a
jr .compareYCoords
.pushingDown
ld a, [$ffdc]
ldh a, [hPlayerYCoord]
inc a
.compareYCoords
cp b
@ -433,19 +417,19 @@ CheckForBoulderCollisionWithSprites:
.pushingHorizontallyLoop
ld a, [hli]
ld b, a
ld a, [$ffdc]
ldh a, [hPlayerYCoord]
cp b
jr nz, .nextSprite2
ld b, [hl]
ld a, [$ffdb]
ldh a, [hPlayerFacing]
bit 2, a
jr nz, .pushingLeft
; pushing right
ld a, [$ffdd]
ldh a, [hPlayerXCoord]
inc a
jr .compareXCoords
.pushingLeft
ld a, [$ffdd]
ldh a, [hPlayerXCoord]
dec a
.compareXCoords
cp b

View file

@ -1,112 +0,0 @@
ApplyOutOfBattlePoisonDamage:
ld a, [wd730]
add a
jp c, .noBlackOut ; no black out if joypad states are being simulated
ld a, [wPartyCount]
and a
jp z, .noBlackOut
call IncrementDayCareMonExp
ld a, [wStepCounter]
and $3 ; is the counter a multiple of 4?
jp nz, .noBlackOut ; only apply poison damage every fourth step
ld [wWhichPokemon], a
ld hl, wPartyMon1Status
ld de, wPartySpecies
.applyDamageLoop
ld a, [hl]
and (1 << PSN)
jr z, .nextMon2 ; not poisoned
dec hl
dec hl
ld a, [hld]
ld b, a
ld a, [hli]
or b
jr z, .nextMon ; already fainted
; subtract 1 from HP
ld a, [hl]
dec a
ld [hld], a
inc a
jr nz, .noBorrow
; borrow 1 from upper byte of HP
dec [hl]
inc hl
jr .nextMon
.noBorrow
ld a, [hli]
or [hl]
jr nz, .nextMon ; didn't faint from damage
; the mon fainted from the damage
push hl
inc hl
inc hl
ld [hl], a
ld a, [de]
ld [wd11e], a
push de
ld a, [wWhichPokemon]
ld hl, wPartyMonNicks
call GetPartyMonName
xor a
ld [wJoyIgnore], a
call EnableAutoTextBoxDrawing
ld a, TEXT_MON_FAINTED
ld [hSpriteIndexOrTextID], a
call DisplayTextID
pop de
pop hl
.nextMon
inc hl
inc hl
.nextMon2
inc de
ld a, [de]
inc a
jr z, .applyDamageLoopDone
ld bc, wPartyMon2 - wPartyMon1
add hl, bc
push hl
ld hl, wWhichPokemon
inc [hl]
pop hl
jr .applyDamageLoop
.applyDamageLoopDone
ld hl, wPartyMon1Status
ld a, [wPartyCount]
ld d, a
ld e, 0
.countPoisonedLoop
ld a, [hl]
and (1 << PSN)
or e
ld e, a
ld bc, wPartyMon2 - wPartyMon1
add hl, bc
dec d
jr nz, .countPoisonedLoop
ld a, e
and a ; are any party members poisoned?
jr z, .skipPoisonEffectAndSound
ld b, $2
predef ChangeBGPalColor0_4Frames ; change BG white to dark grey for 4 frames
ld a, SFX_POISONED
call PlaySound
.skipPoisonEffectAndSound
predef AnyPartyAlive
ld a, d
and a
jr nz, .noBlackOut
call EnableAutoTextBoxDrawing
ld a, TEXT_BLACKED_OUT
ld [hSpriteIndexOrTextID], a
call DisplayTextID
ld hl, wd72e
set 5, [hl]
ld a, $ff
jr .done
.noBlackOut
xor a
.done
ld [wOutOfBattleBlackout], a
ret

View file

@ -1,68 +0,0 @@
DisplayPokemonCenterDialogue_:
call SaveScreenTilesToBuffer1 ; save screen
ld hl, PokemonCenterWelcomeText
call PrintText
ld hl, wd72e
bit 2, [hl]
set 1, [hl]
set 2, [hl]
jr nz, .skipShallWeHealYourPokemon
ld hl, ShallWeHealYourPokemonText
call PrintText
.skipShallWeHealYourPokemon
call YesNoChoicePokeCenter ; yes/no menu
ld a, [wCurrentMenuItem]
and a
jr nz, .declinedHealing ; if the player chose No
call SetLastBlackoutMap
call LoadScreenTilesFromBuffer1 ; restore screen
ld hl, NeedYourPokemonText
call PrintText
ld a, $18
ld [wSpriteStateData1 + $12], a ; make the nurse turn to face the machine
call Delay3
predef HealParty
callba AnimateHealingMachine ; do the healing machine animation
xor a
ld [wAudioFadeOutControl], a
ld a, [wAudioSavedROMBank]
ld [wAudioROMBank], a
ld a, [wMapMusicSoundID]
ld [wLastMusicSoundID], a
ld [wNewSoundID], a
call PlayMusic
ld hl, PokemonFightingFitText
call PrintText
ld a, $14
ld [wSpriteStateData1 + $12], a ; make the nurse bow
ld c, a
call DelayFrames
jr .done
.declinedHealing
call LoadScreenTilesFromBuffer1 ; restore screen
.done
ld hl, PokemonCenterFarewellText
call PrintText
jp UpdateSprites
PokemonCenterWelcomeText:
TX_FAR _PokemonCenterWelcomeText
db "@"
ShallWeHealYourPokemonText:
TX_DELAY
TX_FAR _ShallWeHealYourPokemonText
db "@"
NeedYourPokemonText:
TX_FAR _NeedYourPokemonText
db "@"
PokemonFightingFitText:
TX_FAR _PokemonFightingFitText
db "@"
PokemonCenterFarewellText:
TX_DELAY
TX_FAR _PokemonCenterFarewellText
db "@"

View file

@ -1,272 +0,0 @@
DisplayPokemartDialogue_:
ld a, [wListScrollOffset]
ld [wSavedListScrollOffset], a
call UpdateSprites
xor a
ld [wBoughtOrSoldItemInMart], a
.loop
xor a
ld [wListScrollOffset], a
ld [wCurrentMenuItem], a
ld [wPlayerMonNumber], a
inc a
ld [wPrintItemPrices], a
ld a, MONEY_BOX
ld [wTextBoxID], a
call DisplayTextBoxID
ld a, BUY_SELL_QUIT_MENU
ld [wTextBoxID], a
call DisplayTextBoxID
; This code is useless. It copies the address of the pokemart's inventory to hl,
; but the address is never used.
ld hl, wItemListPointer
ld a, [hli]
ld l, [hl]
ld h, a
ld a, [wMenuExitMethod]
cp CANCELLED_MENU
jp z, .done
ld a, [wChosenMenuItem]
and a ; buying?
jp z, .buyMenu
dec a ; selling?
jp z, .sellMenu
dec a ; quitting?
jp z, .done
.sellMenu
; the same variables are set again below, so this code has no effect
xor a
ld [wPrintItemPrices], a
ld a, INIT_BAG_ITEM_LIST
ld [wInitListType], a
callab InitList
ld a, [wNumBagItems]
and a
jp z, .bagEmpty
ld hl, PokemonSellingGreetingText
call PrintText
call SaveScreenTilesToBuffer1 ; save screen
.sellMenuLoop
call LoadScreenTilesFromBuffer1 ; restore saved screen
ld a, MONEY_BOX
ld [wTextBoxID], a
call DisplayTextBoxID ; draw money text box
ld hl, wNumBagItems
ld a, l
ld [wListPointer], a
ld a, h
ld [wListPointer + 1], a
xor a
ld [wPrintItemPrices], a
ld [wCurrentMenuItem], a
ld a, ITEMLISTMENU
ld [wListMenuID], a
call DisplayListMenuID
jp c, .returnToMainPokemartMenu ; if the player closed the menu
.confirmItemSale ; if the player is trying to sell a specific item
call IsKeyItem
ld a, [wIsKeyItem]
and a
jr nz, .unsellableItem
ld a, [wcf91]
call IsItemHM
jr c, .unsellableItem
ld a, PRICEDITEMLISTMENU
ld [wListMenuID], a
ld [hHalveItemPrices], a ; halve prices when selling
call DisplayChooseQuantityMenu
inc a
jr z, .sellMenuLoop ; if the player closed the choose quantity menu with the B button
ld hl, PokemartTellSellPriceText
lb bc, 14, 1 ; location that PrintText always prints to, this is useless
call PrintText
coord hl, 14, 7
lb bc, 8, 15
ld a, TWO_OPTION_MENU
ld [wTextBoxID], a
call DisplayTextBoxID ; yes/no menu
ld a, [wMenuExitMethod]
cp CHOSE_SECOND_ITEM
jr z, .sellMenuLoop ; if the player chose No or pressed the B button
; The following code is supposed to check if the player chose No, but the above
; check already catches it.
ld a, [wChosenMenuItem]
dec a
jr z, .sellMenuLoop
.sellItem
ld a, [wBoughtOrSoldItemInMart]
and a
jr nz, .skipSettingFlag1
inc a
ld [wBoughtOrSoldItemInMart], a
.skipSettingFlag1
call AddAmountSoldToMoney
ld hl, wNumBagItems
call RemoveItemFromInventory
jp .sellMenuLoop
.unsellableItem
ld hl, PokemartUnsellableItemText
call PrintText
jp .returnToMainPokemartMenu
.bagEmpty
ld hl, PokemartItemBagEmptyText
call PrintText
call SaveScreenTilesToBuffer1
jp .returnToMainPokemartMenu
.buyMenu
; the same variables are set again below, so this code has no effect
ld a, 1
ld [wPrintItemPrices], a
ld a, INIT_OTHER_ITEM_LIST
ld [wInitListType], a
callab InitList
ld hl, PokemartBuyingGreetingText
call PrintText
call SaveScreenTilesToBuffer1
.buyMenuLoop
call LoadScreenTilesFromBuffer1
ld a, MONEY_BOX
ld [wTextBoxID], a
call DisplayTextBoxID
ld hl, wItemList
ld a, l
ld [wListPointer], a
ld a, h
ld [wListPointer + 1], a
xor a
ld [wCurrentMenuItem], a
inc a
ld [wPrintItemPrices], a
inc a ; a = 2 (PRICEDITEMLISTMENU)
ld [wListMenuID], a
call DisplayListMenuID
jr c, .returnToMainPokemartMenu ; if the player closed the menu
ld a, 99
ld [wMaxItemQuantity], a
xor a
ld [hHalveItemPrices], a ; don't halve item prices when buying
call DisplayChooseQuantityMenu
inc a
jr z, .buyMenuLoop ; if the player closed the choose quantity menu with the B button
ld a, [wcf91] ; item ID
ld [wd11e], a ; store item ID for GetItemName
call GetItemName
call CopyStringToCF4B ; copy name to wcf4b
ld hl, PokemartTellBuyPriceText
call PrintText
coord hl, 14, 7
lb bc, 8, 15
ld a, TWO_OPTION_MENU
ld [wTextBoxID], a
call DisplayTextBoxID ; yes/no menu
ld a, [wMenuExitMethod]
cp CHOSE_SECOND_ITEM
jp z, .buyMenuLoop ; if the player chose No or pressed the B button
; The following code is supposed to check if the player chose No, but the above
; check already catches it.
ld a, [wChosenMenuItem]
dec a
jr z, .buyMenuLoop
.buyItem
call .isThereEnoughMoney
jr c, .notEnoughMoney
ld hl, wNumBagItems
call AddItemToInventory
jr nc, .bagFull
call SubtractAmountPaidFromMoney
ld a, [wBoughtOrSoldItemInMart]
and a
jr nz, .skipSettingFlag2
ld a, 1
ld [wBoughtOrSoldItemInMart], a
.skipSettingFlag2
ld a, SFX_PURCHASE
call PlaySoundWaitForCurrent
call WaitForSoundToFinish
ld hl, PokemartBoughtItemText
call PrintText
jp .buyMenuLoop
.returnToMainPokemartMenu
call LoadScreenTilesFromBuffer1
ld a, MONEY_BOX
ld [wTextBoxID], a
call DisplayTextBoxID
ld hl, PokemartAnythingElseText
call PrintText
jp .loop
.isThereEnoughMoney
ld de, wPlayerMoney
ld hl, hMoney
ld c, 3 ; length of money in bytes
jp StringCmp
.notEnoughMoney
ld hl, PokemartNotEnoughMoneyText
call PrintText
jr .returnToMainPokemartMenu
.bagFull
ld hl, PokemartItemBagFullText
call PrintText
jr .returnToMainPokemartMenu
.done
ld hl, PokemartThankYouText
call PrintText
ld a, 1
ld [wUpdateSpritesEnabled], a
call UpdateSprites
ld a, [wSavedListScrollOffset]
ld [wListScrollOffset], a
ret
PokemartBuyingGreetingText:
TX_FAR _PokemartBuyingGreetingText
db "@"
PokemartTellBuyPriceText:
TX_FAR _PokemartTellBuyPriceText
db "@"
PokemartBoughtItemText:
TX_FAR _PokemartBoughtItemText
db "@"
PokemartNotEnoughMoneyText:
TX_FAR _PokemartNotEnoughMoneyText
db "@"
PokemartItemBagFullText:
TX_FAR _PokemartItemBagFullText
db "@"
PokemonSellingGreetingText:
TX_FAR _PokemonSellingGreetingText
db "@"
PokemartTellSellPriceText:
TX_FAR _PokemartTellSellPriceText
db "@"
PokemartItemBagEmptyText:
TX_FAR _PokemartItemBagEmptyText
db "@"
PokemartUnsellableItemText:
TX_FAR _PokemartUnsellableItemText
db "@"
PokemartThankYouText:
TX_FAR _PokemartThankYouText
db "@"
PokemartAnythingElseText:
TX_FAR _PokemartAnythingElseText
db "@"

View file

@ -1,4 +1,4 @@
TryPushingBoulder:
TryPushingBoulder::
ld a, [wd728]
bit 0, a ; using Strength?
ret z
@ -6,15 +6,15 @@ TryPushingBoulder:
bit 1, a ; has boulder dust animation from previous push played yet?
ret nz
xor a
ld [hSpriteIndexOrTextID], a
ldh [hSpriteIndexOrTextID], a
call IsSpriteInFrontOfPlayer
ld a, [hSpriteIndexOrTextID]
ldh a, [hSpriteIndexOrTextID]
ld [wBoulderSpriteIndex], a
and a
jp z, ResetBoulderPushFlags
ld hl, wSpriteStateData1 + 1
ld hl, wSpritePlayerStateData1MovementStatus
ld d, $0
ld a, [hSpriteIndexOrTextID]
ldh a, [hSpriteIndexOrTextID]
swap a
ld e, a
add hl, de
@ -27,16 +27,16 @@ TryPushingBoulder:
bit 6, [hl]
set 6, [hl] ; indicate that the player has tried pushing
ret z ; the player must try pushing twice before the boulder will move
ld a, [hJoyHeld]
ldh a, [hJoyHeld]
and D_RIGHT | D_LEFT | D_UP | D_DOWN
ret z
predef CheckForCollisionWhenPushingBoulder
ld a, [wTileInFrontOfBoulderAndBoulderCollisionResult]
and a ; was there a collision?
jp nz, ResetBoulderPushFlags
ld a, [hJoyHeld]
ldh a, [hJoyHeld]
ld b, a
ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
ld a, [wSpritePlayerStateData1FacingDirection]
cp SPRITE_FACING_UP
jr z, .pushBoulderUp
cp SPRITE_FACING_LEFT
@ -71,28 +71,32 @@ TryPushingBoulder:
ret
PushBoulderUpMovementData:
db NPC_MOVEMENT_UP,$FF
db NPC_MOVEMENT_UP
db -1 ; end
PushBoulderDownMovementData:
db NPC_MOVEMENT_DOWN,$FF
db NPC_MOVEMENT_DOWN
db -1 ; end
PushBoulderLeftMovementData:
db NPC_MOVEMENT_LEFT,$FF
db NPC_MOVEMENT_LEFT
db -1 ; end
PushBoulderRightMovementData:
db NPC_MOVEMENT_RIGHT,$FF
db NPC_MOVEMENT_RIGHT
db -1 ; end
DoBoulderDustAnimation:
DoBoulderDustAnimation::
ld a, [wd730]
bit 0, a
ret nz
callab AnimateBoulderDust
callfar AnimateBoulderDust
call DiscardButtonPresses
ld [wJoyIgnore], a
call ResetBoulderPushFlags
set 7, [hl]
ld a, [wBoulderSpriteIndex]
ld [H_SPRITEINDEX], a
ldh [hSpriteIndex], a
call GetSpriteMovementByte2Pointer
ld [hl], $10
ld a, SFX_CUT

View file

@ -1,16 +0,0 @@
RemoveGuardDrink:
ld hl, GuardDrinksList
.drinkLoop
ld a, [hli]
ld [$ffdb], a
and a
ret z
push hl
ld b, a
call IsItemInBag
pop hl
jr z, .drinkLoop
jpba RemoveItemByID
GuardDrinksList:
db FRESH_WATER, SODA_POP, LEMONADE, $00

View file

@ -1,29 +0,0 @@
SetLastBlackoutMap:
; Set the map to return to when
; blacking out or using Teleport or Dig.
; Safari rest houses don't count.
push hl
ld hl, SafariZoneRestHouses
ld a, [wCurMap]
ld b, a
.loop
ld a, [hli]
cp -1
jr z, .notresthouse
cp b
jr nz, .loop
jr .done
.notresthouse
ld a, [wLastMap]
ld [wLastBlackoutMap], a
.done
pop hl
ret
SafariZoneRestHouses:
db SAFARI_ZONE_WEST_REST_HOUSE
db SAFARI_ZONE_EAST_REST_HOUSE
db SAFARI_ZONE_NORTH_REST_HOUSE
db -1

View file

@ -0,0 +1,149 @@
SpecialWarpIn::
call LoadSpecialWarpData
predef LoadTilesetHeader
ld hl, wd732
bit 2, [hl] ; dungeon warp or fly warp?
res 2, [hl]
jr z, .next
; if dungeon warp or fly warp
ld a, [wDestinationMap]
jr .next2
.next
bit 1, [hl]
jr z, .next3
call DebugStart
.next3
ld a, 0
.next2
ld b, a
ld a, [wd72d]
and a
jr nz, .next4
ld a, b
.next4
ld hl, wd732
bit 4, [hl] ; dungeon warp?
ret nz
; if not dungeon warp
ld [wLastMap], a
ret
; gets the map ID, tile block map view pointer, tileset, and coordinates
LoadSpecialWarpData:
ld a, [wd72d]
cp TRADE_CENTER
jr nz, .notTradeCenter
ld hl, TradeCenterSpec1
ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK ; which gameboy is clocking determines who is on the left and who is on the right
jr z, .copyWarpData
ld hl, TradeCenterSpec2
jr .copyWarpData
.notTradeCenter
cp COLOSSEUM
jr nz, .notColosseum
ld hl, ColosseumSpec1
ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
jr z, .copyWarpData
ld hl, ColosseumSpec2
jr .copyWarpData
.notColosseum
ld a, [wd732]
bit 1, a
jr nz, .notFirstMap
bit 2, a
jr nz, .notFirstMap
ld hl, FirstMapSpec
.copyWarpData
ld de, wCurMap
ld c, $7
.copyWarpDataLoop
ld a, [hli]
ld [de], a
inc de
dec c
jr nz, .copyWarpDataLoop
ld a, [hli]
ld [wCurMapTileset], a
xor a
jr .done
.notFirstMap
ld a, [wLastMap] ; this value is overwritten before it's ever read
ld hl, wd732
bit 4, [hl] ; used dungeon warp (jumped down hole/waterfall)?
jr nz, .usedDunegonWarp
bit 6, [hl] ; return to last pokemon center (or player's house)?
res 6, [hl]
jr z, .otherDestination
; return to last pokemon center or player's house
ld a, [wLastBlackoutMap]
jr .usedFlyWarp
.usedDunegonWarp
ld hl, wd72d
res 4, [hl]
ld a, [wDungeonWarpDestinationMap]
ld b, a
ld [wCurMap], a
ld a, [wWhichDungeonWarp]
ld c, a
ld hl, DungeonWarpList
ld de, 0
ld a, 6
ld [wDungeonWarpDataEntrySize], a
.dungeonWarpListLoop
ld a, [hli]
cp b
jr z, .matchedDungeonWarpDestinationMap
inc hl
jr .nextDungeonWarp
.matchedDungeonWarpDestinationMap
ld a, [hli]
cp c
jr z, .matchedDungeonWarpID
.nextDungeonWarp
ld a, [wDungeonWarpDataEntrySize]
add e
ld e, a
jr .dungeonWarpListLoop
.matchedDungeonWarpID
ld hl, DungeonWarpData
add hl, de
jr .copyWarpData2
.otherDestination
ld a, [wDestinationMap]
.usedFlyWarp
ld b, a
ld [wCurMap], a
ld hl, FlyWarpDataPtr
.flyWarpDataPtrLoop
ld a, [hli]
inc hl
cp b
jr z, .foundFlyWarpMatch
inc hl
inc hl
jr .flyWarpDataPtrLoop
.foundFlyWarpMatch
ld a, [hli]
ld h, [hl]
ld l, a
.copyWarpData2
ld de, wCurrentTileBlockMapViewPointer
ld c, $6
.copyWarpDataLoop2
ld a, [hli]
ld [de], a
inc de
dec c
jr nz, .copyWarpDataLoop2
xor a ; OVERWORLD
ld [wCurMapTileset], a
.done
ld [wYOffsetSinceLastSpecialWarp], a
ld [wXOffsetSinceLastSpecialWarp], a
ld a, $ff ; the player's coordinates have already been updated using a special warp, so don't use any of the normal warps
ld [wDestinationWarpID], a
ret
INCLUDE "data/maps/special_warps.asm"

View file

@ -0,0 +1,65 @@
LoadSpinnerArrowTiles::
ld a, [wSpritePlayerStateData1ImageIndex]
srl a
srl a
ld hl, SpinnerPlayerFacingDirections
ld c, a
ld b, $0
add hl, bc
ld a, [hl]
ld [wSpritePlayerStateData1ImageIndex], a
ld a, [wCurMapTileset]
cp FACILITY
ld hl, FacilitySpinnerArrows
jr z, .asm_44ff6
ld hl, GymSpinnerArrows
.asm_44ff6
ld a, [wSimulatedJoypadStatesIndex]
bit 0, a
jr nz, .asm_45001
ld de, $18
add hl, de
.asm_45001
ld a, $4
ld bc, $0
.asm_45006
push af
push hl
push bc
add hl, bc
ld a, [hli]
ld e, a
ld a, [hli]
ld d, a
ld a, [hli]
ld c, a
ld a, [hli]
ld b, a
ld a, [hli]
ld h, [hl]
ld l, a
call CopyVideoData
pop bc
ld a, $6
add c
ld c, a
pop hl
pop af
dec a
jr nz, .asm_45006
ret
INCLUDE "data/tilesets/spinner_tiles.asm"
SpinnerPlayerFacingDirections:
; This isn't the order of the facing directions. Rather, it's a list of
; the facing directions that come next. For example, when the player is
; facing down (00), the next facing direction is left (08).
db $08 ; down -> left
db $0C ; up -> right
db $04 ; left -> up
db $00 ; right -> down
; these tiles are the animation for the tiles that push the player in dungeons like Rocket HQ
SpinnerArrowAnimTiles:
INCBIN "gfx/overworld/spinners.2bpp"

View file

@ -1,15 +1,15 @@
_UpdateSprites:
_UpdateSprites::
ld h, $c1
inc h
ld a, $e ; wSpriteStateData2 + $0e
ld a, SPRITESTATEDATA2_IMAGEBASEOFFSET
.spriteLoop
ld l, a
sub $e
sub SPRITESTATEDATA2_IMAGEBASEOFFSET
ld c, a
ld [H_CURRENTSPRITEOFFSET], a
ldh [hCurrentSpriteOffset], a
ld a, [hl]
and a
jr z, .skipSprite ; tests $c2Xe
jr z, .skipSprite ; tests SPRITESTATEDATA2_IMAGEBASEOFFSET
push hl
push de
push bc
@ -20,7 +20,7 @@ _UpdateSprites:
.skipSprite
ld a, l
add $10 ; move to next sprite
cp $e ; test for overflow (back at $0e)
cp SPRITESTATEDATA2_IMAGEBASEOFFSET ; test for overflow (back at beginning)
jr nz, .spriteLoop
ret
.updateCurrentSprite
@ -31,34 +31,35 @@ _UpdateSprites:
UpdateNonPlayerSprite:
dec a
swap a
ld [$ff93], a ; $10 * sprite#
ldh [hTilePlayerStandingOn], a ; $10 * sprite#
ld a, [wNPCMovementScriptSpriteOffset] ; some sprite offset?
ld b, a
ld a, [H_CURRENTSPRITEOFFSET]
ldh a, [hCurrentSpriteOffset]
cp b
jr nz, .unequal
jp DoScriptedNPCMovement
.unequal
jp UpdateNPCSprite
; This detects if the current sprite (whose offset is at H_CURRENTSPRITEOFFSET)
; This detects if the current sprite (whose offset is at hCurrentSpriteOffset)
; is going to collide with another sprite by looping over the other sprites.
; The current sprite's offset will be labelled with i (e.g. $c1i0).
; The loop sprite's offset will labelled with j (e.g. $c1j0).
; The current sprite's offset will be labelled with i (e.g. i#SPRITESTATEDATA1_PICTUREID).
; The loop sprite's offset will labelled with j (e.g. j#SPRITESTATEDATA1_PICTUREID).
;
; Note that the Y coordinate of the sprite (in [$c1k4]) is one of the following
; 9 values when the sprite is aligned with the grid: $fc, $0c, $1c, $2c, ..., $7c.
; Note that the Y coordinate of the sprite (in [k#SPRITESTATEDATA1_YPIXELS])
; is one of the following 9 values when the sprite is aligned with the grid:
; $fc, $0c, $1c, $2c, ..., $7c.
; The reason that 4 is added below to the coordinate is to make it align with a
; multiple of $10 to make comparisons easier.
DetectCollisionBetweenSprites:
nop
ld h, wSpriteStateData1 / $100
ld a, [H_CURRENTSPRITEOFFSET]
add wSpriteStateData1 % $100
ld h, HIGH(wSpriteStateData1)
ldh a, [hCurrentSpriteOffset]
add LOW(wSpriteStateData1)
ld l, a
ld a, [hl] ; a = [$c1i0] (picture) (0 if slot is unused)
ld a, [hl] ; a = [i#SPRITESTATEDATA1_PICTUREID] (0 if slot is unused)
and a ; is this sprite slot slot used?
ret z ; return if not used
@ -66,10 +67,10 @@ DetectCollisionBetweenSprites:
add 3
ld l, a
ld a, [hli] ; a = [$c1i3] (delta Y) (-1, 0, or 1)
ld a, [hli] ; a = [i#SPRITESTATEDATA1_YSTEPVECTOR] (-1, 0, or 1)
call SetSpriteCollisionValues
ld a, [hli] ; a = [$C1i4] (Y screen coordinate)
ld a, [hli] ; a = [i#SPRITESTATEDATA1_YPIXELS]
add 4 ; align with multiple of $10
; The effect of the following 3 lines is to
@ -79,11 +80,11 @@ DetectCollisionBetweenSprites:
and $f0
or c
ld [$ff90], a ; store Y coordinate adjusted for direction of movement
ldh [hFF90], a ; store Y coordinate adjusted for direction of movement
ld a, [hli] ; a = [$c1i5] (delta X) (-1, 0, or 1)
ld a, [hli] ; a = [i#SPRITESTATEDATA1_XSTEPVECTOR] (-1, 0, or 1)
call SetSpriteCollisionValues
ld a, [hl] ; a = [$C1i6] (X screen coordinate)
ld a, [hl] ; a = [i#SPRITESTATEDATA1_XPIXELS]
; The effect of the following 3 lines is to
; add 7 to a if moving east or
@ -92,52 +93,52 @@ DetectCollisionBetweenSprites:
and $f0
or c
ld [$ff91], a ; store X coordinate adjusted for direction of movement
ldh [hFF91], a ; store X coordinate adjusted for direction of movement
ld a, l
add 7
ld l, a
xor a
ld [hld], a ; zero [$c1id] XXX what's [$c1id] for?
ld [hld], a ; zero [$c1ic] (directions in which collisions occurred)
ld [hld], a ; zero [i#SPRITESTATEDATA1_0D] XXX what's this for?
ld [hld], a ; zero [i#SPRITESTATEDATA1_COLLISIONDATA]
ld a, [$ff91]
ld [hld], a ; [$c1ib] = adjusted X coordinate
ld a, [$ff90]
ld [hl], a ; [$c1ia] = adjusted Y coordinate
ldh a, [hFF91]
ld [hld], a ; [i#SPRITESTATEDATA1_XADJUSTED]
ldh a, [hFF90]
ld [hl], a ; [i#SPRITESTATEDATA1_YADJUSTED]
xor a ; zero the loop counter
.loop
ld [$ff8f], a ; store loop counter
ldh [hFF8F], a ; store loop counter
swap a
ld e, a
ld a, [H_CURRENTSPRITEOFFSET]
ldh a, [hCurrentSpriteOffset]
cp e ; does the loop sprite match the current sprite?
jp z, .next ; go to the next sprite if they match
ld d, h
ld a, [de] ; a = [$c1j0] (picture) (0 if slot is unused)
ld a, [de] ; a = [j#SPRITESTATEDATA1_PICTUREID] (0 if slot is unused)
and a ; is this sprite slot slot used?
jp z, .next ; go the next sprite if not used
inc e
inc e
ld a, [de] ; a = [$c1j2] ($ff means the sprite is offscreen)
ld a, [de] ; a = [j#SPRITESTATEDATA1_IMAGEINDEX] ($ff means the sprite is offscreen)
inc a
jp z, .next ; go the next sprite if offscreen
ld a, [H_CURRENTSPRITEOFFSET]
ldh a, [hCurrentSpriteOffset]
add 10
ld l, a
inc e
ld a, [de] ; a = [$c1j3] (delta Y)
ld a, [de] ; a = [j#SPRITESTATEDATA1_YSTEPVECTOR]
call SetSpriteCollisionValues
inc e
ld a, [de] ; a = [$C1j4] (Y screen coordinate)
ld a, [de] ; a = [j#SPRITESTATEDATA1_YPIXELS]
add 4 ; align with multiple of $10
; The effect of the following 3 lines is to
@ -147,18 +148,18 @@ DetectCollisionBetweenSprites:
and $f0
or c
sub [hl] ; subtract the adjusted Y coordinate of sprite i ([$c1ia]) from that of sprite j
sub [hl] ; subtract [i#SPRITESTATEDATA1_YADJUSTED] from [j#SPRITESTATEDATA1_YADJUSTED]
; calculate the absolute value of the difference to get the distance
jr nc, .noCarry1
cpl
inc a
.noCarry1
ld [$ff90], a ; store the distance between the two sprites' adjusted Y values
ldh [hFF90], a ; store the distance between the two sprites' adjusted Y values
; Use the carry flag set by the above subtraction to determine which sprite's
; Y coordinate is larger. This information is used later to set [$c1ic],
; which stores which direction the collision occurred in.
; Y coordinate is larger. This information is used later to set
; [i#SPRITESTATEDATA1_COLLISIONDATA].
; The following 5 lines set the lowest 2 bits of c, which are later shifted left by 2.
; If sprite i's Y is larger, set lowest 2 bits of c to 10.
; If sprite j's Y is larger or both are equal, set lowest 2 bits of c to 01.
@ -170,30 +171,30 @@ DetectCollisionBetweenSprites:
; If sprite i's delta Y is 0, then b = 7, else b = 9.
ld b, 7
ld a, [hl] ; a = [$c1ia] (adjusted Y coordinate)
ld a, [hl] ; a = [i#SPRITESTATEDATA1_YADJUSTED]
and $f
jr z, .next1
ld b, 9
.next1
ld a, [$ff90] ; a = distance between adjusted Y coordinates
ldh a, [hFF90] ; a = distance between adjusted Y coordinates
sub b
ld [$ff92], a ; store distance adjusted using sprite i's direction
ldh [hFF92], a ; store distance adjusted using sprite i's direction
ld a, b
ld [$ff90], a ; store 7 or 9 depending on sprite i's delta Y
ldh [hFF90], a ; store 7 or 9 depending on sprite i's delta Y
jr c, .checkXDistance
; If sprite j's delta Y is 0, then b = 7, else b = 9.
ld b, 7
dec e
ld a, [de] ; a = [$c1j3] (delta Y)
ld a, [de] ; a = [j#SPRITESTATEDATA1_YSTEPVECTOR]
inc e
and a
jr z, .next2
ld b, 9
.next2
ld a, [$ff92] ; a = distance adjusted using sprite i's direction
ldh a, [hFF92] ; a = distance adjusted using sprite i's direction
sub b ; adjust distance using sprite j's direction
jr z, .checkXDistance
jr nc, .next ; go to next sprite if distance is still positive after both adjustments
@ -201,13 +202,13 @@ DetectCollisionBetweenSprites:
.checkXDistance
inc e
inc l
ld a, [de] ; a = [$c1j5] (delta X)
ld a, [de] ; a = [j#SPRITESTATEDATA1_XSTEPVECTOR]
push bc
call SetSpriteCollisionValues
inc e
ld a, [de] ; a = [$c1j6] (X screen coordinate)
ld a, [de] ; a = [j#SPRITESTATEDATA1_XPIXELS]
; The effect of the following 3 lines is to
; add 7 to a if moving east or
@ -218,18 +219,18 @@ DetectCollisionBetweenSprites:
pop bc
sub [hl] ; subtract the adjusted X coordinate of sprite i ([$c1ib]) from that of sprite j
sub [hl] ; subtract [i#SPRITESTATEDATA1_XADJUSTED] from [j#SPRITESTATEDATA1_XADJUSTED]
; calculate the absolute value of the difference to get the distance
jr nc, .noCarry2
cpl
inc a
.noCarry2
ld [$ff91], a ; store the distance between the two sprites' adjusted X values
ldh [hFF91], a ; store the distance between the two sprites' adjusted X values
; Use the carry flag set by the above subtraction to determine which sprite's
; X coordinate is larger. This information is used later to set [$c1ic],
; which stores which direction the collision occurred in.
; X coordinate is larger. This information is used later to set
; [i#SPRITESTATEDATA1_COLLISIONDATA].
; The following 5 lines set the lowest 2 bits of c.
; If sprite i's X is larger, set lowest 2 bits of c to 10.
; If sprite j's X is larger or both are equal, set lowest 2 bits of c to 01.
@ -241,38 +242,38 @@ DetectCollisionBetweenSprites:
; If sprite i's delta X is 0, then b = 7, else b = 9.
ld b, 7
ld a, [hl] ; a = [$c1ib] (adjusted X coordinate)
ld a, [hl] ; a = [i#SPRITESTATEDATA1_XADJUSTED]
and $f
jr z, .next3
ld b, 9
.next3
ld a, [$ff91] ; a = distance between adjusted X coordinates
ldh a, [hFF91] ; a = distance between adjusted X coordinates
sub b
ld [$ff92], a ; store distance adjusted using sprite i's direction
ldh [hFF92], a ; store distance adjusted using sprite i's direction
ld a, b
ld [$ff91], a ; store 7 or 9 depending on sprite i's delta X
ldh [hFF91], a ; store 7 or 9 depending on sprite i's delta X
jr c, .collision
; If sprite j's delta X is 0, then b = 7, else b = 9.
ld b, 7
dec e
ld a, [de] ; a = [$c1j5] (delta X)
ld a, [de] ; a = [j#SPRITESTATEDATA1_XSTEPVECTOR]
inc e
and a
jr z, .next4
ld b, 9
.next4
ld a, [$ff92] ; a = distance adjusted using sprite i's direction
ldh a, [hFF92] ; a = distance adjusted using sprite i's direction
sub b ; adjust distance using sprite j's direction
jr z, .collision
jr nc, .next ; go to next sprite if distance is still positive after both adjustments
.collision
ld a, [$ff91] ; a = 7 or 9 depending on sprite i's delta X
ldh a, [hFF91] ; a = 7 or 9 depending on sprite i's delta X
ld b, a
ld a, [$ff90] ; a = 7 or 9 depending on sprite i's delta Y
ldh a, [hFF90] ; a = 7 or 9 depending on sprite i's delta Y
inc l
; If delta X isn't 0 and delta Y is 0, then b = %0011, else b = %1100.
@ -287,14 +288,15 @@ DetectCollisionBetweenSprites:
.next6
ld a, c ; c has 2 bits set (one of bits 0-1 is set for the X axis and one of bits 2-3 for the Y axis)
and b ; we select either the bit in bits 0-1 or bits 2-3 based on the calculation immediately above
or [hl] ; or with existing collision direction bits in [$c1ic]
or [hl] ; or with existing collision direction bits in [i#SPRITESTATEDATA1_COLLISIONDATA]
ld [hl], a ; store new value
ld a, c ; useless code because a is overwritten before being used again
; set bit in [$c1ie] or [$c1if] to indicate which sprite the collision occurred with
; set bit in [i#SPRITESTATEDATA1_0E] or [i#SPRITESTATEDATA1_0F]
; to indicate which sprite the collision occurred with
inc l
inc l
ld a, [$ff8f] ; a = loop counter
ldh a, [hFF8F] ; a = loop counter
ld de, SpriteCollisionBitTable
add a
add e
@ -311,7 +313,7 @@ DetectCollisionBetweenSprites:
ld [hl], a
.next
ld a, [$ff8f] ; a = loop counter
ldh a, [hFF8F] ; a = loop counter
inc a
cp $10
jp nz, .loop

View file

@ -23,9 +23,9 @@ LoadTilesetHeader:
dec c
jr nz, .copyTilesetHeaderLoop
ld a, [hl]
ld [hTilesetType], a
ldh [hTileAnimations], a
xor a
ld [$ffd8], a
ldh [hMovingBGTilesCounter1], a
pop hl
ld a, [wCurMapTileset]
push hl
@ -38,7 +38,7 @@ LoadTilesetHeader:
jr c, .asm_c797
ld a, [wCurMapTileset]
ld b, a
ld a, [hPreviousTileset]
ldh a, [hPreviousTileset]
cp b
jr z, .done
.asm_c797
@ -55,6 +55,6 @@ LoadTilesetHeader:
.done
ret
INCLUDE "data/dungeon_tilesets.asm"
INCLUDE "data/tilesets/dungeon_tilesets.asm"
INCLUDE "data/tileset_headers.asm"
INCLUDE "data/tilesets/tileset_headers.asm"

View file

@ -1,80 +1,80 @@
_GetSpritePosition1:
_GetSpritePosition1::
ld hl, wSpriteStateData1
ld de, $4
ld de, SPRITESTATEDATA1_YPIXELS
ld a, [wSpriteIndex]
ld [H_SPRITEINDEX], a
ldh [hSpriteIndex], a
call GetSpriteDataPointer
ld a, [hli] ; c1x4 (screen Y pos)
ld [$ffeb], a
ld a, [hli] ; x#SPRITESTATEDATA1_YPIXELS
ldh [hSpriteScreenYCoord], a
inc hl
ld a, [hl] ; c1x6 (screen X pos)
ld [$ffec], a
ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6)
ld a, [hl] ; x#SPRITESTATEDATA1_XPIXELS
ldh [hSpriteScreenXCoord], a
ld de, wSpritePlayerStateData2MapY - wSpritePlayerStateData1XPixels
add hl, de
ld a, [hli] ; c2x4 (map Y pos)
ld [$ffed], a
ld a, [hl] ; c2x5 (map X pos)
ld [$ffee], a
ld a, [hli] ; x#SPRITESTATEDATA2_MAPY
ldh [hSpriteMapYCoord], a
ld a, [hl] ; x#SPRITESTATEDATA2_MAPX
ldh [hSpriteMapXCoord], a
ret
_GetSpritePosition2:
_GetSpritePosition2::
ld hl, wSpriteStateData1
ld de, $4
ld de, SPRITESTATEDATA1_YPIXELS
ld a, [wSpriteIndex]
ld [H_SPRITEINDEX], a
ldh [hSpriteIndex], a
call GetSpriteDataPointer
ld a, [hli] ; c1x4 (screen Y pos)
ld a, [hli] ; x#SPRITESTATEDATA1_YPIXELS
ld [wSavedSpriteScreenY], a
inc hl
ld a, [hl] ; c1x6 (screen X pos)
ld a, [hl] ; x#SPRITESTATEDATA1_XPIXELS
ld [wSavedSpriteScreenX], a
ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6)
ld de, wSpritePlayerStateData2MapY - wSpritePlayerStateData1XPixels
add hl, de
ld a, [hli] ; c2x4 (map Y pos)
ld a, [hli] ; x#SPRITESTATEDATA2_MAPY
ld [wSavedSpriteMapY], a
ld a, [hl] ; c2x5 (map X pos)
ld a, [hl] ; x#SPRITESTATEDATA2_MAPX
ld [wSavedSpriteMapX], a
ret
_SetSpritePosition1:
_SetSpritePosition1::
ld hl, wSpriteStateData1
ld de, $4
ld de, SPRITESTATEDATA1_YPIXELS
ld a, [wSpriteIndex]
ld [H_SPRITEINDEX], a
ldh [hSpriteIndex], a
call GetSpriteDataPointer
ld a, [$ffeb] ; c1x4 (screen Y pos)
ldh a, [hSpriteScreenYCoord] ; x#SPRITESTATEDATA1_YPIXELS
ld [hli], a
inc hl
ld a, [$ffec] ; c1x6 (screen X pos)
ldh a, [hSpriteScreenXCoord] ; x#SPRITESTATEDATA1_XPIXELS
ld [hl], a
ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6)
ld de, wSpritePlayerStateData2MapY - wSpritePlayerStateData1XPixels
add hl, de
ld a, [$ffed] ; c2x4 (map Y pos)
ldh a, [hSpriteMapYCoord] ; x#SPRITESTATEDATA2_MAPY
ld [hli], a
ld a, [$ffee] ; c2x5 (map X pos)
ldh a, [hSpriteMapXCoord] ; x#SPRITESTATEDATA2_MAPX
ld [hl], a
ret
_SetSpritePosition2:
_SetSpritePosition2::
ld hl, wSpriteStateData1
ld de, 4
ld de, SPRITESTATEDATA1_YPIXELS
ld a, [wSpriteIndex]
ld [H_SPRITEINDEX], a
ldh [hSpriteIndex], a
call GetSpriteDataPointer
ld a, [wSavedSpriteScreenY]
ld [hli], a ; c1x4 (screen Y pos)
ld [hli], a ; x#SPRITESTATEDATA1_YPIXELS
inc hl
ld a, [wSavedSpriteScreenX]
ld [hl], a ; c1x6 (screen X pos)
ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6)
ld [hl], a ; x#SPRITESTATEDATA1_XPIXELS
ld de, wSpritePlayerStateData2MapY - wSpritePlayerStateData1XPixels
add hl, de
ld a, [wSavedSpriteMapY]
ld [hli], a ; c2x4 (map Y pos)
ld [hli], a ; x#SPRITESTATEDATA2_MAPY
ld a, [wSavedSpriteMapX]
ld [hl], a ; c2x5 (map X pos)
ld [hl], a ; x#SPRITESTATEDATA2_MAPX
ret
TrainerWalkUpToPlayer:
TrainerWalkUpToPlayer::
ld a, [wSpriteIndex]
swap a
ld [wTrainerSpriteOffset], a
@ -144,7 +144,7 @@ TrainerWalkUpToPlayer:
call FillMemory ; write the necessary steps to reach player
ld [hl], $ff ; write end of list sentinel
ld a, [wSpriteIndex]
ld [H_SPRITEINDEX], a
ldh [hSpriteIndex], a
jp MoveSprite_
; input: de = offset within sprite entry
@ -152,7 +152,7 @@ TrainerWalkUpToPlayer:
GetSpriteDataPointer:
push de
add hl, de
ld a, [H_SPRITEINDEX]
ldh a, [hSpriteIndex]
swap a
ld d, $0
ld e, a
@ -165,23 +165,23 @@ TrainerEngage:
push hl
push de
ld a, [wTrainerSpriteOffset]
add $2
add SPRITESTATEDATA1_IMAGEINDEX
ld d, $0
ld e, a
ld hl, wSpriteStateData1
add hl, de
ld a, [hl] ; c1x2: sprite image index
ld a, [hl] ; x#SPRITESTATEDATA1_IMAGEINDEX
sub $ff
jr nz, .spriteOnScreen ; test if sprite is on screen
jp .noEngage
.spriteOnScreen
ld a, [wTrainerSpriteOffset]
add $9
add SPRITESTATEDATA1_FACINGDIRECTION
ld d, $0
ld e, a
ld hl, wSpriteStateData1
add hl, de
ld a, [hl] ; c1x9: facing direction
ld a, [hl] ; x#SPRITESTATEDATA1_FACINGDIRECTION
ld [wTrainerFacingDirection], a
call ReadTrainerScreenPosition
ld a, [wTrainerScreenY] ; sprite screen Y pos
@ -234,20 +234,20 @@ TrainerEngage:
; reads trainer's Y position to wTrainerScreenY and X position to wTrainerScreenX
ReadTrainerScreenPosition:
ld a, [wTrainerSpriteOffset]
add $4
add SPRITESTATEDATA1_YPIXELS
ld d, $0
ld e, a
ld hl, wSpriteStateData1
add hl, de
ld a, [hl] ; c1x4 (sprite Y pos)
ld a, [hl] ; x#SPRITESTATEDATA1_YPIXELS
ld [wTrainerScreenY], a
ld a, [wTrainerSpriteOffset]
add $6
add SPRITESTATEDATA1_XPIXELS
ld d, $0
ld e, a
ld hl, wSpriteStateData1
add hl, de
ld a, [hl] ; c1x6 (sprite X pos)
ld a, [hl] ; x#SPRITESTATEDATA1_XPIXELS
ld [wTrainerScreenX], a
ret
@ -295,24 +295,24 @@ CheckPlayerIsInFrontOfSprite:
cp POWER_PLANT
jp z, .engage ; bypass this for power plant to get voltorb fake items to work
ld a, [wTrainerSpriteOffset]
add $4
add SPRITESTATEDATA1_YPIXELS
ld d, $0
ld e, a
ld hl, wSpriteStateData1
add hl, de
ld a, [hl] ; c1x4 (sprite screen Y pos)
ld a, [hl] ; x#SPRITESTATEDATA1_YPIXELS
cp $fc
jr nz, .notOnTopmostTile ; special case if sprite is on topmost tile (Y = $fc (-4)), make it come down a block
ld a, $c
.notOnTopmostTile
ld [wTrainerScreenY], a
ld a, [wTrainerSpriteOffset]
add $6
add SPRITESTATEDATA1_XPIXELS
ld d, $0
ld e, a
ld hl, wSpriteStateData1
add hl, de
ld a, [hl] ; c1x6 (sprite screen X pos)
ld a, [hl] ; x#SPRITESTATEDATA1_XPIXELS
ld [wTrainerScreenX], a
ld a, [wTrainerFacingDirection] ; facing direction
cp SPRITE_FACING_DOWN

View file

@ -0,0 +1,25 @@
UpdateSpriteFacingOffsetAndDelayMovement::
ld h, HIGH(wSpriteStateData2)
ldh a, [hCurrentSpriteOffset]
add $8
ld l, a
ld a, $7f ; maximum movement delay
ld [hl], a ; x#SPRITESTATEDATA2_MOVEMENTDELAY
dec h ; HIGH(wSpriteStateData1)
ldh a, [hCurrentSpriteOffset]
add $9
ld l, a
ld a, [hld] ; x#SPRITESTATEDATA1_FACINGDIRECTION
ld b, a
xor a
ld [hld], a
ld [hl], a ; x#SPRITESTATEDATA1_ANIMFRAMECOUNTER
ldh a, [hCurrentSpriteOffset]
add SPRITESTATEDATA1_IMAGEINDEX
ld l, a
ld a, [hl] ; x#SPRITESTATEDATA1_IMAGEINDEX
or b ; or in the facing direction
ld [hld], a
ld a, $2 ; delayed movement status
ld [hl], a ; x#SPRITESTATEDATA1_MOVEMENTSTATUS
ret

View file

@ -50,20 +50,20 @@ RedrawMapView:
ld a, [wIsInBattle]
inc a
ret z
ld a, [H_AUTOBGTRANSFERENABLED]
ldh a, [hAutoBGTransferEnabled]
push af
ld a, [hTilesetType]
ldh a, [hTileAnimations]
push af
xor a
ld [H_AUTOBGTRANSFERENABLED], a
ld [hTilesetType], a ; no flower/water BG tile animations
ldh [hAutoBGTransferEnabled], a
ldh [hTileAnimations], a
call LoadCurrentMapView
call RunDefaultPaletteCommand
ld hl, wMapViewVRAMPointer
ld a, [hli]
ld h, [hl]
ld l, a
ld de, -2 * 32
ld de, -2 * BG_MAP_WIDTH
add hl, de
ld a, h
and $3
@ -73,23 +73,23 @@ RedrawMapView:
ld a, h
ld [wBuffer + 1], a ; this copy of the address is not used
ld a, 2
ld [$ffbe], a
ld c, 9 ; number of rows of 2x2 tiles (this covers the whole screen)
ldh [hRedrawMapViewRowOffset], a
ld c, SCREEN_HEIGHT / 2 ; number of rows of 2x2 tiles (this covers the whole screen)
.redrawRowLoop
push bc
push hl
push hl
ld hl, wTileMap - 2 * SCREEN_WIDTH
ld de, SCREEN_WIDTH
ld a, [$ffbe]
ldh a, [hRedrawMapViewRowOffset]
.calcWRAMAddrLoop
add hl, de
dec a
jr nz, .calcWRAMAddrLoop
call CopyToRedrawRowOrColumnSrcTiles
pop hl
ld de, $20
ld a, [$ffbe]
ld de, BG_MAP_WIDTH
ldh a, [hRedrawMapViewRowOffset]
ld c, a
.calcVRAMAddrLoop
add hl, de
@ -98,13 +98,13 @@ RedrawMapView:
or $98
dec c
jr nz, .calcVRAMAddrLoop
ld [hRedrawRowOrColumnDest + 1], a
ldh [hRedrawRowOrColumnDest + 1], a
ld a, l
ld [hRedrawRowOrColumnDest], a
ldh [hRedrawRowOrColumnDest], a
ld a, REDRAW_ROW
ld [hRedrawRowOrColumnMode], a
ldh [hRedrawRowOrColumnMode], a
call DelayFrame
ld hl, $ffbe
ld hl, hRedrawMapViewRowOffset
inc [hl]
inc [hl]
pop hl
@ -112,9 +112,9 @@ RedrawMapView:
dec c
jr nz, .redrawRowLoop
pop af
ld [hTilesetType], a
ldh [hTileAnimations], a
pop af
ld [H_AUTOBGTRANSFERENABLED], a
ldh [hAutoBGTransferEnabled], a
ret
CompareHLWithBC:

View file

@ -1,4 +1,4 @@
LoadWildData:
LoadWildData::
ld hl, WildDataPointers
ld a, [wCurMap]
@ -16,10 +16,10 @@ LoadWildData:
jr z, .NoGrassData ; if no grass data, skip to surfing data
push hl
ld de, wGrassMons ; otherwise, load grass data
ld bc, $0014
ld bc, $14
call CopyData
pop hl
ld bc, $0014
ld bc, $14
add hl, bc
.NoGrassData
ld a, [hli]
@ -27,7 +27,7 @@ LoadWildData:
and a
ret z ; if no water data, we're done
ld de, wWaterMons ; otherwise, load surfing data
ld bc, $0014
ld bc, $14
jp CopyData
INCLUDE "data/wild_mons.asm"
INCLUDE "data/wild/grass_water.asm"