diff options
Diffstat (limited to 'engine/overworld')
22 files changed, 981 insertions, 627 deletions
diff --git a/engine/overworld/advance_player_sprite.asm b/engine/overworld/advance_player_sprite.asm new file mode 100644 index 00000000..4ebdac84 --- /dev/null +++ b/engine/overworld/advance_player_sprite.asm @@ -0,0 +1,244 @@ +_AdvancePlayerSprite:: + ld a, [wSpritePlayerStateData1YStepVector] + ld b, a + ld a, [wSpritePlayerStateData1XStepVector] + ld c, a + ld hl, wWalkCounter ; walking animation counter + dec [hl] + jr nz, .afterUpdateMapCoords +; if it's the end of the animation, update the player's map coordinates + ld hl, wPikachuOverworldStateFlags + res 5, [hl] + ld a, [wYCoord] + add b + ld [wYCoord], a + ld a, [wXCoord] + add c + ld [wXCoord], a +.afterUpdateMapCoords + ld a, [wWalkCounter] ; walking animation counter + cp $07 + jp nz, .scrollBackgroundAndSprites +; if this is the first iteration of the animation + ld a, c + cp $01 + jr nz, .checkIfMovingWest +; moving east + ld a, [wMapViewVRAMPointer] + ld e, a + and $e0 + ld d, a + ld a, e + add $02 + and $1f + or d + ld [wMapViewVRAMPointer], a + jr .adjustXCoordWithinBlock +.checkIfMovingWest + cp $ff + jr nz, .checkIfMovingSouth +; moving west + ld a, [wMapViewVRAMPointer] + ld e, a + and $e0 + ld d, a + ld a, e + sub $02 + and $1f + or d + ld [wMapViewVRAMPointer], a + jr .adjustXCoordWithinBlock +.checkIfMovingSouth + ld a, b + cp $01 + jr nz, .checkIfMovingNorth +; moving south + ld a, [wMapViewVRAMPointer] + add $40 + ld [wMapViewVRAMPointer], a + jr nc, .adjustXCoordWithinBlock + ld a, [wMapViewVRAMPointer + 1] + inc a + and $03 + or $98 + ld [wMapViewVRAMPointer + 1], a + jr .adjustXCoordWithinBlock +.checkIfMovingNorth + cp $ff + jr nz, .adjustXCoordWithinBlock +; moving north + ld a, [wMapViewVRAMPointer] + sub $40 + ld [wMapViewVRAMPointer], a + jr nc, .adjustXCoordWithinBlock + ld a, [wMapViewVRAMPointer + 1] + dec a + and $03 + or $98 + ld [wMapViewVRAMPointer + 1], a +.adjustXCoordWithinBlock + ld a, c + and a + jr z, .pointlessJump ; mistake? +.pointlessJump + ld hl, wXBlockCoord + ld a, [hl] + add c + ld [hl], a + cp $02 + jr nz, .checkForMoveToWestBlock +; moved into the tile block to the east + xor a + ld [hl], a + ld hl, wXOffsetSinceLastSpecialWarp + inc [hl] + ld de, wCurrentTileBlockMapViewPointer + call MoveTileBlockMapPointerEast + jr .updateMapView +.checkForMoveToWestBlock + cp $ff + jr nz, .adjustYCoordWithinBlock +; moved into the tile block to the west + ld a, $01 + ld [hl], a + ld hl, wXOffsetSinceLastSpecialWarp + dec [hl] + ld de, wCurrentTileBlockMapViewPointer + call MoveTileBlockMapPointerWest + jr .updateMapView +.adjustYCoordWithinBlock + ld hl, wYBlockCoord + ld a, [hl] + add b + ld [hl], a + cp $02 + jr nz, .checkForMoveToNorthBlock +; moved into the tile block to the south + xor a + ld [hl], a + ld hl, wYOffsetSinceLastSpecialWarp + inc [hl] + ld de, wCurrentTileBlockMapViewPointer + ld a, [wCurMapWidth] + call MoveTileBlockMapPointerSouth + jr .updateMapView +.checkForMoveToNorthBlock + cp $ff + jr nz, .updateMapView +; moved into the tile block to the north + ld a, $01 + ld [hl], a + ld hl, wYOffsetSinceLastSpecialWarp + dec [hl] + ld de, wCurrentTileBlockMapViewPointer + ld a, [wCurMapWidth] + call MoveTileBlockMapPointerNorth +.updateMapView + call LoadCurrentMapView + ld a, [wSpritePlayerStateData1YStepVector] + cp $01 + jr nz, .checkIfMovingNorth2 +; if moving south + call ScheduleSouthRowRedraw + jr .scrollBackgroundAndSprites +.checkIfMovingNorth2 + cp $ff + jr nz, .checkIfMovingEast2 +; if moving north + call ScheduleNorthRowRedraw + jr .scrollBackgroundAndSprites +.checkIfMovingEast2 + ld a, [wSpritePlayerStateData1XStepVector] + cp $01 + jr nz, .checkIfMovingWest2 +; if moving east + call ScheduleEastColumnRedraw + jr .scrollBackgroundAndSprites +.checkIfMovingWest2 + cp $ff + jr nz, .scrollBackgroundAndSprites +; if moving west + call ScheduleWestColumnRedraw +.scrollBackgroundAndSprites + ld a, [wSpritePlayerStateData1YStepVector] + add a + ld b, a + ld a, [wSpritePlayerStateData1XStepVector] + add a + ld c, a +; shift all the sprites in the direction opposite of the player's motion +; so that the player appears to move relative to them + ld hl, wSprite01StateData1YPixels + ld e, 15 +.spriteShiftLoop + ld a, [hl] + sub b + ld [hli], a + inc l + ld a, [hl] + sub c + ld [hl], a + ld a, $0e + add l + ld l, a + dec e + jr nz, .spriteShiftLoop +.done + ldh a, [hSCY] + add b + ldh [hSCY], a ; update background scroll Y + ldh a, [hSCX] + add c + ldh [hSCX], a ; update background scroll X + ret + +; the following four functions are used to move the pointer to the upper left +; corner of the tile block map in the direction of motion + +MoveTileBlockMapPointerEast:: + ld a, [de] + add $01 + ld [de], a + ret nc + inc de + ld a, [de] + inc a + ld [de], a + ret + +MoveTileBlockMapPointerWest:: + ld a, [de] + sub $01 + ld [de], a + ret nc + inc de + ld a, [de] + dec a + ld [de], a + ret + +MoveTileBlockMapPointerSouth:: + add MAP_BORDER * 2 + ld b, a + ld a, [de] + add b + ld [de], a + ret nc + inc de + ld a, [de] + inc a + ld [de], a + ret + +MoveTileBlockMapPointerNorth:: + add MAP_BORDER * 2 + ld b, a + ld a, [de] + sub b + ld [de], a + ret nc + inc de + ld a, [de] + dec a + ld [de], a + ret diff --git a/engine/overworld/auto_movement.asm b/engine/overworld/auto_movement.asm index 9c078f08..a68da55f 100755 --- a/engine/overworld/auto_movement.asm +++ b/engine/overworld/auto_movement.asm @@ -37,8 +37,8 @@ _EndNPCMovementScript:: res 1, [hl] xor a ld [wNPCMovementScriptSpriteOffset], a - ld [wNPCMovementScriptPointerTableNum], a ld [wNPCMovementScriptFunctionNum], a + ld [wNPCMovementScriptPointerTableNum], a ld [wWastedByteCD3A], a ld [wSimulatedJoypadStatesIndex], a ld [wSimulatedJoypadStatesEnd], a @@ -79,6 +79,10 @@ PalletMovementScript_OakMoveLeft: ld a, $3 ld [wNPCMovementScriptFunctionNum], a .done + ld a, BANK(Music_MuseumGuy) + ld c, a + ld a, MUSIC_MUSEUM_GUY + call PlayMusic ld hl, wFlags_D733 set 1, [hl] ld a, $fc @@ -127,8 +131,9 @@ PalletMovementScript_WalkToLab: ld [wNPCMovementScriptFunctionNum], a ret + RLEList_ProfOakWalkToLab: - db NPC_MOVEMENT_DOWN, 5 + db NPC_MOVEMENT_DOWN, 6 ; differs from red db NPC_MOVEMENT_LEFT, 1 db NPC_MOVEMENT_DOWN, 5 db NPC_MOVEMENT_RIGHT, 3 @@ -141,7 +146,7 @@ RLEList_PlayerWalkToLab: db D_RIGHT, 3 db D_DOWN, 5 db D_LEFT, 1 - db D_DOWN, 6 + db D_DOWN, 7 ; differs from red db -1 ; end PalletMovementScript_Done: @@ -163,11 +168,9 @@ PewterMuseumGuyMovementScriptPointerTable:: PewterMovementScript_WalkToMuseum: ld a, BANK(Music_MuseumGuy) - ld [wAudioROMBank], a - ld [wAudioSavedROMBank], a + ld c, a ld a, MUSIC_MUSEUM_GUY - ld [wNewSoundID], a - call PlaySound + call PlayMusic ld a, [wSpriteIndex] swap a ld [wNPCMovementScriptSpriteOffset], a @@ -179,7 +182,7 @@ PewterMovementScript_WalkToMuseum: ld [wSimulatedJoypadStatesIndex], a xor a ld [wWhichPewterGuy], a - predef PewterGuys + call PewterGuys ld hl, wNPCMovementDirections2 ld de, RLEList_PewterMuseumGuy call DecodeRLEList @@ -219,11 +222,9 @@ PewterGymGuyMovementScriptPointerTable:: PewterMovementScript_WalkToGym: ld a, BANK(Music_MuseumGuy) - ld [wAudioROMBank], a - ld [wAudioSavedROMBank], a + ld c, a ld a, MUSIC_MUSEUM_GUY - ld [wNewSoundID], a - call PlaySound + call PlayMusic ld a, [wSpriteIndex] swap a ld [wNPCMovementScriptSpriteOffset], a @@ -236,7 +237,7 @@ PewterMovementScript_WalkToGym: ld [wSimulatedJoypadStatesIndex], a ld a, 1 ld [wWhichPewterGuy], a - predef PewterGuys + call PewterGuys ld hl, wNPCMovementDirections2 ld de, RLEList_PewterGymGuy call DecodeRLEList @@ -266,27 +267,4 @@ RLEList_PewterGymGuy: db NPC_MOVEMENT_RIGHT, 3 db -1 ; end -FreezeEnemyTrainerSprite:: - ld a, [wCurMap] - cp POKEMON_TOWER_7F - ret z ; the Rockets on Pokemon Tower 7F leave after battling, so don't freeze them - ld hl, RivalIDs - ld a, [wEngagedTrainerClass] - ld b, a -.loop - ld a, [hli] - 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] - ldh [hSpriteIndex], a - jp SetSpriteMovementBytesToFF - -RivalIDs: - db OPP_RIVAL1 - db OPP_RIVAL2 - db OPP_RIVAL3 - db -1 ; end +INCLUDE "engine/events/pewter_guys.asm" diff --git a/engine/overworld/cut.asm b/engine/overworld/cut.asm index 6a92ccc0..e36b8d88 100755 --- a/engine/overworld/cut.asm +++ b/engine/overworld/cut.asm @@ -76,6 +76,7 @@ InitCutAnimOAM: ld [wWhichAnimationOffsets], a ld a, %11100100 ldh [rOBP1], a + call UpdateGBCPal_OBP1 ld a, [wCutTile] cp $52 jr z, .grass @@ -123,8 +124,8 @@ WriteCutOrBoulderDustAnimationOAMBlock: jp WriteOAMBlock CutOrBoulderDustAnimationTilesAndAttributes: - dbsprite 2, -1, 0, 4, $fd, OAM_OBP1 - dbsprite 2, -1, 0, 6, $ff, OAM_OBP1 + dbsprite 2, -1, 4, 4, $fd, OAM_OBP1 | %100 + dbsprite 2, -1, 4, 6, $ff, OAM_OBP1 | %100 GetCutOrBoulderDustAnimationOffsets: ld hl, wSpritePlayerStateData1YPixels diff --git a/engine/overworld/cut2.asm b/engine/overworld/cut2.asm index 3d4a5905..1f691eef 100755 --- a/engine/overworld/cut2.asm +++ b/engine/overworld/cut2.asm @@ -18,6 +18,7 @@ AnimCut: ldh a, [rOBP1] xor $64 ldh [rOBP1], a + call UpdateGBCPal_OBP1 call DelayFrame pop bc dec c @@ -68,6 +69,7 @@ AnimCutGrass_UpdateOAMEntries: ldh a, [rOBP1] xor $64 ldh [rOBP1], a + call UpdateGBCPal_OBP1 call DelayFrame pop bc dec c diff --git a/engine/overworld/dungeon_warps.asm b/engine/overworld/dungeon_warps.asm new file mode 100644 index 00000000..7641c688 --- /dev/null +++ b/engine/overworld/dungeon_warps.asm @@ -0,0 +1,15 @@ +IsPlayerOnDungeonWarp:: + xor a + ld [wWhichDungeonWarp], a + ld a, [wd72d] + bit 4, a + ret nz + call ArePlayerCoordsInArray + ret nc + ld a, [wCoordIndex] + ld [wWhichDungeonWarp], a + ld hl, wd72d + set 4, [hl] + ld hl, wd732 + set 4, [hl] + ret diff --git a/engine/overworld/dust_smoke.asm b/engine/overworld/dust_smoke.asm index a20a0591..773def96 100755 --- a/engine/overworld/dust_smoke.asm +++ b/engine/overworld/dust_smoke.asm @@ -7,6 +7,7 @@ AnimateBoulderDust: ld [wUpdateSpritesEnabled], a ld a, %11100100 ldh [rOBP1], a + call UpdateGBCPal_OBP1 call LoadSmokeTileFourTimes farcall WriteCutOrBoulderDustAnimationOAMBlock ld c, 8 ; number of steps in animation @@ -21,6 +22,7 @@ AnimateBoulderDust: ldh a, [rOBP1] xor %01100100 ldh [rOBP1], a + call UpdateGBCPal_OBP1 call Delay3 pop bc dec c diff --git a/engine/overworld/elevator.asm b/engine/overworld/elevator.asm index fa404602..b873ffad 100755 --- a/engine/overworld/elevator.asm +++ b/engine/overworld/elevator.asm @@ -4,8 +4,7 @@ ShakeElevator:: ld de, SCREEN_HEIGHT * $20 call ShakeElevatorRedrawRow call Delay3 - ld a, SFX_STOP_ALL_MUSIC - call PlaySound + call StopAllMusic ldh a, [hSCY] ld d, a ld e, $1 @@ -27,8 +26,7 @@ ShakeElevator:: jr nz, .shakeLoop ld a, d ldh [hSCY], a - ld a, SFX_STOP_ALL_MUSIC - call PlaySound + call StopAllMusic ld c, BANK(SFX_Safari_Zone_PA) ld a, SFX_SAFARI_ZONE_PA call PlayMusic diff --git a/engine/overworld/emotion_bubbles.asm b/engine/overworld/emotion_bubbles.asm index 5a41c226..3ad714e9 100755 --- a/engine/overworld/emotion_bubbles.asm +++ b/engine/overworld/emotion_bubbles.asm @@ -1,13 +1,16 @@ EmotionBubble: ld a, [wWhichEmotionBubble] + and $f + swap a ld c, a ld b, 0 - ld hl, EmotionBubblesPointerTable + ld hl, EmotionBubbles + add hl, bc ; each emotion bubble is 16 bytes, so calculate the offset directly instead of with a pointer table add hl, bc add hl, bc - ld e, [hl] - inc hl - ld d, [hl] + add hl, bc + ld e, l + ld d, h ld hl, vChars1 tile $78 lb bc, BANK(EmotionBubbles), 4 call CopyVideoData @@ -59,13 +62,9 @@ EmotionBubble: pop af ld [wUpdateSpritesEnabled], a call DelayFrame - jp UpdateSprites + call UpdateSprites + ret -EmotionBubblesPointerTable: -; entries correspond to *_BUBBLE constants - dw ShockEmote - dw QuestionEmote - dw HappyEmote EmotionBubblesOAM: dbsprite 0, -1, 0, 0, $f9, 0 @@ -75,3 +74,8 @@ EmotionBubbles: ShockEmote: INCBIN "gfx/emotes/shock.2bpp" QuestionEmote: INCBIN "gfx/emotes/question.2bpp" HappyEmote: INCBIN "gfx/emotes/happy.2bpp" +SkullEmote: INCBIN "gfx/emotes/skull.2bpp" +HeartEmote: INCBIN "gfx/emotes/heart.2bpp" +BoltEmote: INCBIN "gfx/emotes/bolt.2bpp" +ZzzEmote: INCBIN "gfx/emotes/zzz.2bpp" +FishEmote: INCBIN "gfx/emotes/fish.2bpp" diff --git a/engine/overworld/healing_machine.asm b/engine/overworld/healing_machine.asm index 40ca6f65..e5fba7e1 100755 --- a/engine/overworld/healing_machine.asm +++ b/engine/overworld/healing_machine.asm @@ -12,14 +12,13 @@ AnimateHealingMachine: push af ld a, $e0 ldh [rOBP1], a + call UpdateGBCPal_OBP1 ld hl, wOAMBuffer + $84 ld de, PokeCenterOAMData call CopyHealingMachineOAM ld a, 4 ld [wAudioFadeOutControl], a - ld a, SFX_STOP_ALL_MUSIC - ld [wNewSoundID], a - call PlaySound + call StopAllMusic .waitLoop ld a, [wAudioFadeOutControl] and a ; is fade-out finished? @@ -35,12 +34,10 @@ AnimateHealingMachine: dec b jr nz, .partyLoop ld a, [wAudioROMBank] - cp BANK(Audio3_UpdateMusic) + cp BANK(AudioEngine3) ld [wAudioSavedROMBank], a jr nz, .next - ld a, SFX_STOP_ALL_MUSIC - ld [wNewSoundID], a - call PlaySound + call StopAllMusic ld a, BANK(Music_PkmnHealed) ld [wAudioROMBank], a .next @@ -57,6 +54,7 @@ AnimateHealingMachine: call DelayFrames pop af ldh [rOBP1], a + call UpdateGBCPal_OBP1 pop hl pop af ld [hl], a @@ -67,14 +65,14 @@ PokeCenterFlashingMonitorAndHealBall: PokeCenterOAMData: ; heal machine monitor - dbsprite 6, 4, 4, 4, $7c, OAM_OBP1 + dbsprite 6, 4, 4, 4, $7c, OAM_OBP1 | %100 ; 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 + dbsprite 6, 5, 0, 3, $7d, OAM_OBP1 | %100 + dbsprite 7, 5, 0, 3, $7d, OAM_OBP1 | OAM_HFLIP | %100 + dbsprite 6, 6, 0, 0, $7d, OAM_OBP1 | %100 + dbsprite 7, 6, 0, 0, $7d, OAM_OBP1 | OAM_HFLIP | %100 + dbsprite 6, 6, 0, 5, $7d, OAM_OBP1 | %100 + dbsprite 7, 6, 0, 5, $7d, OAM_OBP1 | OAM_HFLIP | %100 ; d = value to xor with palette FlashSprite8Times: @@ -83,6 +81,7 @@ FlashSprite8Times: ldh a, [rOBP1] xor d ldh [rOBP1], a + call UpdateGBCPal_OBP1 ld c, 10 call DelayFrames dec b diff --git a/engine/overworld/hidden_objects.asm b/engine/overworld/hidden_objects.asm index 855328e7..84108986 100755 --- a/engine/overworld/hidden_objects.asm +++ b/engine/overworld/hidden_objects.asm @@ -1,19 +1,3 @@ -IsPlayerOnDungeonWarp:: - xor a - ld [wWhichDungeonWarp], a - ld a, [wd72d] - bit 4, a - ret nz - call ArePlayerCoordsInArray - ret nc - ld a, [wCoordIndex] - ld [wWhichDungeonWarp], a - ld hl, wd72d - set 4, [hl] - ld hl, wd732 - set 4, [hl] - ret - ; if a hidden object was found, stores $00 in [hDidntFindAnyHiddenObject], else stores $ff CheckForHiddenObject:: ld hl, hItemAlreadyFound @@ -22,22 +6,12 @@ CheckForHiddenObject:: ld [hli], a ; [hSavedMapTextPtr] ld [hli], a ; [hSavedMapTextPtr + 1] ld [hl], a ; [hDidntFindAnyHiddenObject] - ld de, $0 ld hl, HiddenObjectMaps -.hiddenMapLoop - ld a, [hli] - ld b, a - cp $ff - jr z, .noMatch + ld de, 3 ld a, [wCurMap] - cp b - jr z, .foundMatchingMap - inc de - inc de - jr .hiddenMapLoop -.foundMatchingMap - ld hl, HiddenObjectPointers - add hl, de + call IsInArray + jr nc, .noMatch + inc hl ld a, [hli] ld h, [hl] ld l, a diff --git a/engine/overworld/ledges.asm b/engine/overworld/ledges.asm index f01ae5ef..9925c528 100755 --- a/engine/overworld/ledges.asm +++ b/engine/overworld/ledges.asm @@ -61,10 +61,13 @@ LoadHoppingShadowOAM: ld de, LedgeHoppingShadow lb bc, BANK(LedgeHoppingShadow), (LedgeHoppingShadowEnd - LedgeHoppingShadow) / $8 call CopyVideoDataDouble - ld a, $9 - lb bc, $54, $48 ; b, c = y, x coordinates of shadow - ld de, LedgeHoppingShadowOAM - call WriteOAMBlock + ld hl, LedgeHoppingShadowOAM + ld de, wOAMBuffer + 36 * 4 + ld bc, LedgeHoppingShadowOAMEnd - LedgeHoppingShadowOAM + call CopyData + ld a, $a0 + ld [wOAMBuffer + 38 * 4], a + ld [wOAMBuffer + 39 * 4], a ret LedgeHoppingShadow: @@ -72,5 +75,6 @@ LedgeHoppingShadow: LedgeHoppingShadowEnd: LedgeHoppingShadowOAM: - dbsprite 2, -1, 0, 7, $ff, OAM_HFLIP - dbsprite 8, -1, 0, 7, $ff, OAM_HFLIP | OAM_VFLIP + dbsprite 9, 11, 0, 0, $ff, 0 + dbsprite 10, 11, 0, 0, $ff, OAM_HFLIP +LedgeHoppingShadowOAMEnd: diff --git a/engine/overworld/map_sprites.asm b/engine/overworld/map_sprites.asm index fa3a37dc..e31c0bd2 100755 --- a/engine/overworld/map_sprites.asm +++ b/engine/overworld/map_sprites.asm @@ -4,251 +4,17 @@ ; This is also called after displaying text because loading ; text tile patterns overwrites half of the sprite tile pattern data. ; Note on notation: -; 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:: +; $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:: 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, wSpritePlayerStateData1PictureID - ld de, wSpritePlayerStateData2PictureID -; Loop to copy picture IDs from [x#SPRITESTATEDATA1_PICTUREID] -; to [x#SPRITESTATEDATA2_PICTUREID] for LoadMapSpriteTilePatterns. -.copyPictureIDLoop - ld a, [hl] ; a = [x#SPRITESTATEDATA1_PICTUREID] - ld [de], a ; [x#SPRITESTATEDATA2_PICTUREID] = a - ld a, $10 - add e - ld e, a - ld a, $10 - add l - ld l, a - jr nz, .copyPictureIDLoop - -; This is used for both inside and outside maps, since it is called by -; InitOutsideMapSprites. -; Loads tile pattern data for sprites into VRAM. -LoadMapSpriteTilePatterns: - ld a, [wNumSprites] - and a ; are there any sprites? - jr nz, .spritesExist - ret -.spritesExist - ld c, a ; c = [wNumSprites] - ld b, $10 ; number of sprite slots - ld hl, wSpritePlayerStateData2PictureID - xor a - 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, wSprite01StateData2ImageBaseOffset -.loadTilePatternLoop - 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. -.checkIfAlreadyLoadedLoop - ld a, e - and $f0 - ld b, a ; b = offset of the wSpriteStateData2 sprite slot being checked against - ld a, l - and $f0 ; a = offset of current wSpriteStateData2 sprite slot - cp b ; done checking all previous sprite slots? - jr z, .notAlreadyLoaded - ld a, [de] ; picture ID of the wSpriteStateData2 sprite slot being checked against - cp [hl] ; do the picture ID's match? - jp z, .alreadyLoaded - ld a, e - add $10 - ld e, a - jr .checkIfAlreadyLoadedLoop -.notAlreadyLoaded - 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 -.findNextVRAMSlotLoop - ld a, e - add $10 - ld e, a - ld a, l - cp e ; reached current slot? - jr z, .foundNextVRAMSlot - 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 - jr c, .findNextVRAMSlotLoop ; if the slot being checked is less than the current max -; if the slot being checked is greater than or equal to the current max - ld b, a ; store new max VRAM slot - jr .findNextVRAMSlotLoop -.foundNextVRAMSlot - 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] ; [x#SPRITESTATEDATA2_IMAGEBASEOFFSET] - ld b, a ; b = current sprite picture ID - cp FIRST_STILL_SPRITE ; is it a 4-tile sprite? - jr c, .notFourTileSprite - pop af - ldh a, [hFourTileSpriteCount] - add 11 - jr .storeVRAMSlot -.notFourTileSprite - pop af -.storeVRAMSlot - 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 - add a - push bc - push hl - ld hl, SpriteSheetPointerTable - jr nc, .noCarry - inc h -.noCarry - add l - ld l, a - jr nc, .noCarry2 - inc h -.noCarry2 - push hl - call ReadSpriteSheetData - push af - push de - push bc - ld hl, vNPCSprites ; VRAM base address - 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 -; hl = vSprites + [hVRAMSlot] * 12 tiles -.calculateVRAMAddrLoop - add hl, bc - dec d - jr nz, .calculateVRAMAddrLoop - jr .loadStillTilePattern -.fourTileSpriteVRAMAddr - 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 tile $78 ; address for first 4-tile sprite - inc a - ldh [hFourTileSpriteCount], a -.loadStillTilePattern - pop bc - pop de - pop af - push hl - push hl - ld h, d - ld l, e - pop de - ld b, a - ld a, [wFontLoaded] - bit 0, a ; reloading upper half of tile patterns after displaying text? - jr nz, .skipFirstLoad ; if so, skip loading data into the lower half - ld a, b - ld b, 0 - call FarCopyData2 ; load tile pattern data for sprite when standing still -.skipFirstLoad - pop de - pop hl - ldh a, [hVRAMSlot] - cp 11 ; is it a 4-tile sprite? - jr nc, .skipSecondLoad ; if so, there is no second block - push de - call ReadSpriteSheetData - push af - ld a, $c0 - add e - ld e, a - jr nc, .noCarry3 - inc d -.noCarry3 - ld a, [wFontLoaded] - bit 0, a ; reloading upper half of tile patterns after displaying text? - jr nz, .loadWhileLCDOn - pop af - pop hl - set 3, h ; add $800 to hl - push hl - ld h, d - ld l, e - pop de - call FarCopyData2 ; load tile pattern data for sprite when walking - jr .skipSecondLoad -; When reloading the upper half of tile patterns after displaying text, the LCD -; will be on, so CopyVideoData (which writes to VRAM only during V-blank) must -; be used instead of FarCopyData2. -.loadWhileLCDOn - pop af - pop hl - set 3, h ; add $800 to hl - ld b, a - swap c - call CopyVideoData ; load tile pattern data for sprite when walking -.skipSecondLoad - pop hl - pop bc - jr .nextSpriteSlot -.alreadyLoaded ; if the current picture ID has already had its tile patterns loaded - inc de - 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, wSpritePlayerStateData2PictureID - ld b, $10 -; the pictures IDs stored at [x#SPRITESTATEDATA2_PICTUREID] are no longer needed, -; so zero them -.zeroStoredPictureIDLoop - xor a - ld [hl], a ; [x#SPRITESTATEDATA2_PICTUREID] - ld a, $10 - add l - ld l, a - dec b - jr nz, .zeroStoredPictureIDLoop - ret - -; reads data from SpriteSheetPointerTable -; INPUT: -; hl = address of sprite sheet entry -; OUTPUT: -; de = pointer to sprite sheet -; bc = length in bytes -; a = ROM bank -ReadSpriteSheetData: - ld a, [hli] - ld e, a - ld a, [hli] - ld d, a - ld a, [hli] - ld c, a - xor a - ld b, a - ld a, [hli] + call LoadSpriteSetFromMapHeader + call LoadMapSpriteTilePatterns + call Func_14150 ret ; Loads sprite set for outside maps (cities and routes) and sets VRAM slots. @@ -257,15 +23,8 @@ InitOutsideMapSprites: ld a, [wCurMap] cp FIRST_INDOOR_MAP ; is the map a city or a route? ret nc ; if not, return - ld hl, MapSpriteSets - add l - ld l, a - jr nc, .noCarry - inc h -.noCarry - ld a, [hl] ; a = spriteSetID - cp $f0 ; does the map have 2 sprite sets? - call nc, GetSplitMapSpriteSetID ; if so, choose the appropriate one + call GetSplitMapSpriteSetID +; if so, choose the appropriate one ld b, a ; b = spriteSetID ld a, [wFontLoaded] bit 0, a ; reloading upper half of tile patterns after displaying text? @@ -277,120 +36,285 @@ InitOutsideMapSprites: ld a, b ld [wSpriteSetID], a dec a - ld b, a - sla a ld c, a - sla a - sla a - add c - add b ; a = (spriteSetID - 1) * 11 - ld de, SpriteSets -; add a to de to get offset of sprite set - add e - ld e, a - jr nc, .noCarry2 - inc d -.noCarry2 - ld hl, wSpritePlayerStateData2PictureID - ld a, SPRITE_RED - ld [hl], a - ld bc, wSpriteSet -; Load the sprite set into RAM. -; 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 ; [x#SPRITESTATEDATA2_PICTUREID] - ld [bc], a - inc de - inc bc - ld a, l - cp $bd ; reached 11th sprite slot? - jr nz, .loadSpriteSetLoop - ld b, 4 ; 4 remaining sprite slots -.zeroRemainingSlotsLoop ; loop to zero the picture ID's of the remaining sprite slots - ld a, $10 - add l - ld l, a - xor a - ld [hl], a ; [x#SPRITESTATEDATA2_PICTUREID] - dec b - jr nz, .zeroRemainingSlotsLoop - ld a, [wNumSprites] - push af ; save number of sprites - ld a, 11 ; 11 sprites in sprite set - ld [wNumSprites], a + ld b, 0 + ld a, (wSpriteSetID - wSpriteSet) + ld hl, SpriteSets + call AddNTimes ; get sprite set offset + ld de, wSpriteSet + ld bc, (wSpriteSetID - wSpriteSet) + call CopyData ; copy it to wSpriteSet call LoadMapSpriteTilePatterns - pop af - ld [wNumSprites], a ; restore number of sprites - 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 ; [x#SPRITESTATEDATA2_IMAGEBASEOFFSET] - ld a, $10 - add l - ld l, a - dec b - jr nz, .zeroVRAMSlotsLoop .skipLoadingSpriteSet - ld hl, wSprite01StateData1 + call Func_14150 + scf + ret + +LoadSpriteSetFromMapHeader: ; 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 ; for a sprite slot, the picture ID for the sprite is looked up within the -; sprite set. The index of the picture ID within the sprite set plus one -; (since the Red sprite always has the first VRAM tile pattern slot) is the -; VRAM tile pattern slot. +; sprite set. The index of the picture ID within the sprite set plus two +; (since the Red sprite always has the first VRAM tile pattern slot and the +; Pikachu sprite reserves the second slot) is the VRAM tile pattern slot. + ld hl, wSpriteSet + ld bc, (wSpriteSetID - wSpriteSet) + xor a + call FillMemory + ld a, SPRITE_PIKACHU ; load Pikachu separately + ld [wSpriteSet], a + ld hl, wSprite01StateData1 + ld a, 14 .storeVRAMSlotsLoop - ld c, 0 + push af 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 + jr z, .continue ; if the sprite slot is not used + ld c, a + call CheckForFourTileSprite ; is this a four tile sprite? + jr nc, .isFourTileSprite +; loop through the space reserved for four tile picture IDs + ld de, wSpriteSet + 9 + ld b, 2 + call CheckIfPictureIDAlreadyLoaded + jr .continue + +.isFourTileSprite +; loop through the space reserved for regular picture IDs ld de, wSpriteSet -; Loop to find the index of the sprite's picture ID within the sprite set. -.getPictureIndexLoop - inc c + ld b, 9 + call CheckIfPictureIDAlreadyLoaded +.continue + ld de, wSprite02StateData1 - wSprite01StateData1 + add hl, de + pop af + dec a + jr nz, .storeVRAMSlotsLoop + ret + +CheckIfPictureIDAlreadyLoaded: +; 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. +.loop ld a, [de] + and a ; is sprite set slot not taken up yet? + jr z, .spriteSlotNotTaken ; if so, load it as it signifies we've reached + ; the end of data for the last sprite set + + cp c ; is the tile pattern already loaded? + ret z ; don't redundantly load + dec b ; have we reached the end of the sprite set? + jr z, .spriteNotAlreadyLoaded ; if so, we're done here inc de - cp b ; does the picture ID match? - jr nz, .getPictureIndexLoop - inc c -.skipGettingPictureIndex - push hl - inc h - ld a, $0e - add l - ld l, a - ld a, c ; a = VRAM slot (zero if sprite slot is not used) - ld [hl], a ; [x#SPRITESTATEDATA2_IMAGEBASEOFFSET] - pop hl - ld a, $10 - add l + jr .loop + +.spriteSlotNotTaken + ld a, c + ld [de], a + ret +.spriteNotAlreadyLoaded + scf + ret + +CheckForFourTileSprite: +; Checks for a sprite added in yellow +; Returns no carry if the sprite is Pikachu, as its sprite is handled separately +; Else, returns carry if the sprite uses 4 tiles + cp SPRITE_PIKACHU ; is this the Pikachu Sprite? + ret z ; return if yes + + cp FIRST_STILL_SPRITE ; is this a four tile sprite? + jr nc, .notYellowSprite ; set carry if yes +; regular sprite + and a + ret + +.notYellowSprite + scf + ret + +LoadMapSpriteTilePatterns: + ld a, 0 +.loop + ldh [hVRAMSlot], a + cp 9 + jr nc, .fourTileSprite + call LoadStillTilePattern + call LoadWalkingTilePattern + jr .continue + +.fourTileSprite + call LoadStillTilePattern +.continue + ldh a, [hVRAMSlot] + inc a + cp 11 + jr nz, .loop + ret + +ReloadWalkingTilePatterns: + xor a +.loop + ldh [hVRAMSlot], a + cp 9 + jr nc, .fourTileSprite + call LoadWalkingTilePattern +.fourTileSprite + ldh a, [hVRAMSlot] + inc a + cp 11 + jr nz, .loop + ret + +LoadStillTilePattern: + ld a, [wFontLoaded] + bit 0, a ; reloading upper half of tile patterns after displaying text? + ret nz ; if so, skip loading data into the lower half + call ReadSpriteSheetData + ret nc + call GetSpriteVRAMAddress + call CopyVideoDataAlternate ; new yellow function + ret + +LoadWalkingTilePattern: + call ReadSpriteSheetData + ret nc + ld hl, $c0 + add hl, de + ld d, h + ld e, l + call GetSpriteVRAMAddress + set 3, h ; add $800 to hl + call CopyVideoDataAlternate + ret + +GetSpriteVRAMAddress: + push bc + ldh a, [hVRAMSlot] + ld c, a + ld b, 0 + ld hl, SpriteVRAMAddresses + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] ld l, a + pop bc + ret + +SpriteVRAMAddresses: +; Equivalent to multiplying $C0 (number of bytes in 12 tiles) times the VRAM +; slot and adding the result to $8000 (the VRAM base address). + dw vChars0 + $0c0 + dw vChars0 + $180 + dw vChars0 + $240 + dw vChars0 + $300 + dw vChars0 + $3c0 + dw vChars0 + $480 + dw vChars0 + $540 + dw vChars0 + $600 + dw vChars0 + $6c0 + dw vChars0 + $780 ; 4-tile sprites + dw vChars0 + $7c0 ; 4-tile sprites + +ReadSpriteSheetData: + ldh a, [hVRAMSlot] + ld e, a + ld d, 0 + ld hl, wSpriteSet + add hl, de + ld a, [hl] and a - jr nz, .storeVRAMSlotsLoop + ret z + + dec a + ld l, a + ld h, 0 + add hl, hl + add hl, hl + ld de, SpriteSheetPointerTable + add hl, de + ld e, [hl] + inc hl + ld d, [hl] + inc hl + ld c, [hl] + swap c ; get the number of tiles, not the raw byte length + ; this is because of the use of CopyVideoDataAlternate + inc hl + ld b, [hl] + inc hl scf ret +Func_14150: + ld a, $1 + ld [wSpritePlayerStateData2ImageBaseOffset], a ; vram slot for player + ld a, $2 + ld [wSpritePikachuStateData2ImageBaseOffset], a ; vram slot for Pikachu + ld a, $e + ld hl, wSprite01StateData1 +.loop + ldh [hVRAMSlot], a ; store current sprite set slot as a counter + ld a, [hl] ; [x#SPRITESTATEDATA1_PICTUREID] + and a ; is the sprite unused? + jr z, .spriteUnused + call Func_14179 + push hl + ld de, (wSpritePlayerStateData2ImageBaseOffset) - (wSpriteStateData1) ; $10e + add hl, de ; [x#SPRITESTATEDATA2_IMAGEBASEOFFSET] + ld [hl], a ; write offset + pop hl +.spriteUnused + ld de, wSprite02StateData1 - wSprite01StateData1 + add hl, de + ldh a, [hVRAMSlot] + dec a + jr nz, .loop + ret + +Func_14179: + push de + push bc + ld c, a ; c = picture ID + ld b, 11 + ld de, wSpriteSet +.findSpriteImageBaseOffsetLoop + ld a, [de] ; a = sprite set picture ID + cp c ; have we found a match? + jr z, .foundSpritePictureID ; if so, get the sprite image base offset and return + inc de + dec b ; have we looped through all entries in wSpriteSet? + jr nz, .findSpriteImageBaseOffsetLoop ; continue looping if not + ld a, $1 ; assume slot one if this ever happens + jr .done +.foundSpritePictureID + ld a, 13 + sub b ; get sprite image base offset +.done + pop bc + pop de + ret + +GetSplitMapSpriteSetID: + ld e, a + ld d, 0 + ld hl, MapSpriteSets + add hl, de + ld a, [hl] ; a = spriteSetID + cp a, $f0 ; does the map have 2 sprite sets? + ret c ; Chooses the correct sprite set ID depending on the player's position within ; the map for maps with two sprite sets. -GetSplitMapSpriteSetID: cp $f8 jr z, .route20 ld hl, SplitMapSpriteSets and $0f dec a - sla a - sla a + add a + add a add l ld l, a jr nc, .noCarry diff --git a/engine/overworld/missable_objects.asm b/engine/overworld/missable_objects.asm index 31fdc257..358a9b9f 100644 --- a/engine/overworld/missable_objects.asm +++ b/engine/overworld/missable_objects.asm @@ -17,18 +17,15 @@ MarkTownVisitedAndLoadMissableObjects:: ld h, [hl] ; fall through -LoadMissableObjects: +; LoadMissableObjects: +; seems to not exist in yellow (predef replaced with something near TryPushingBoulder) ld l, a push hl - ld de, MissableObjects ; calculate difference between out pointer and the base pointer ld a, l - sub e - jr nc, .asm_f13c - dec h -.asm_f13c + sub MissableObjects & $ff ; calculate difference between out pointer and the base pointer ld l, a ld a, h - sub d + sbc MissableObjects / $100 ld h, a ld a, h ldh [hDividend], a diff --git a/engine/overworld/movement.asm b/engine/overworld/movement.asm index 2fb8c384..dadf2194 100644 --- a/engine/overworld/movement.asm +++ b/engine/overworld/movement.asm @@ -22,7 +22,13 @@ UpdatePlayerSprite: ld [wSpritePlayerStateData1ImageIndex], a ret .lowerLeftTileIsMapTile + ld a, [wUpdateSpritesEnabled] + push af + ld a, $ff + ld [wUpdateSpritesEnabled], a call DetectCollisionBetweenSprites + pop af + ld [wUpdateSpritesEnabled], a ld h, HIGH(wSpriteStateData1) ld a, [wWalkCounter] and a @@ -48,42 +54,24 @@ UpdatePlayerSprite: jr z, .notMoving ld a, SPRITE_FACING_RIGHT jr .next +.next + ld [wSpritePlayerStateData1FacingDirection], a ; facing direction + ld a, [wFontLoaded] + bit 0, a + jr z, .moving .notMoving ; zero the animation counters xor a ld [wSpritePlayerStateData1IntraAnimFrameCounter], a ld [wSpritePlayerStateData1AnimFrameCounter], a - jr .calcImageIndex -.next - ld [wSpritePlayerStateData1FacingDirection], a - ld a, [wFontLoaded] - bit 0, a - jr nz, .notMoving + call Func_4e32 + jr .skipSpriteAnim .moving ld a, [wd736] bit 7, a ; is the player sprite spinning due to a spin tile? jr nz, .skipSpriteAnim - ldh a, [hCurrentSpriteOffset] - add $7 - ld l, a - ld a, [hl] - inc a - ld [hl], a - cp 4 - jr nz, .calcImageIndex - xor a - ld [hl], a - inc hl - ld a, [hl] - inc a - and $3 - ld [hl], a -.calcImageIndex - ld a, [wSpritePlayerStateData1AnimFrameCounter] - ld b, a - ld a, [wSpritePlayerStateData1FacingDirection] - add b - ld [wSpritePlayerStateData1ImageIndex], a + call Func_5274 + call Func_4e32 .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 @@ -100,15 +88,12 @@ UpdatePlayerSprite: ld [wSpritePlayerStateData2GrassPriority], a ret -UnusedReadSpriteDataFunction: - push bc - push af - ldh a, [hCurrentSpriteOffset] - ld c, a - pop af - add c - ld l, a - pop bc +Func_4e32: + ld a, [wSpritePlayerStateData1AnimFrameCounter] + ld b, a + ld a, [wSpritePlayerStateData1FacingDirection] + add b + ld [wSpritePlayerStateData1ImageIndex], a ret UpdateNPCSprite: @@ -146,6 +131,8 @@ UpdateNPCSprite: jp z, UpdateSpriteMovementDelay ; [x#SPRITESTATEDATA1_MOVEMENTSTATUS] == 2 cp $3 jp z, UpdateSpriteInWalkingAnimation ; [x#SPRITESTATEDATA1_MOVEMENTSTATUS] == 3 + cp $4 + jp z, Func_5357 ld a, [wWalkCounter] and a ret nz ; don't do anything yet if player is currently moving (redundant, already tested in CheckSpriteAvailability) @@ -156,9 +143,9 @@ UpdateNPCSprite: ld l, a ld a, [hl] ; x#SPRITESTATEDATA2_MOVEMENTBYTE1 inc a - jr z, .randomMovement ; value STAY + jp z, .randomMovement ; value STAY inc a - jr z, .randomMovement ; value WALK + jp z, .randomMovement ; value WALK ; scripted movement dec a ld [hl], a ; increment movement byte 1 (movement data index) @@ -183,12 +170,18 @@ UpdateNPCSprite: ret .next cp WALK - jr nz, .determineDirection + jr nz, .asm_4ecb ; 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] (?) - jr .determineDirection +.asm_4ecb + push af + call Func_5288 + pop bc + ld a, b + jr nc, .determineDirection + ret .randomMovement call GetTileSpriteStandsOn call Random @@ -263,34 +256,14 @@ ChangeFacingDirection: ; set carry on failure, clears carry on success TryWalking: push hl - ld h, HIGH(wSpriteStateData1) - ldh a, [hCurrentSpriteOffset] - add $9 - ld l, a - ld [hl], c ; x#SPRITESTATEDATA1_FACINGDIRECTION - ldh a, [hCurrentSpriteOffset] - add $3 - ld l, a - ld [hl], d ; x#SPRITESTATEDATA1_YSTEPVECTOR - inc l - inc l - ld [hl], e ; x#SPRITESTATEDATA1_XSTEPVECTOR + call Func_5337 pop hl push de - ld c, [hl] ; read tile to walk onto + ld c, [hl] call CanWalkOntoTile pop de ret c ; cannot walk there (reinitialization of delay values already done) - ld h, HIGH(wSpriteStateData2) - ldh a, [hCurrentSpriteOffset] - add $4 - ld l, a - ld a, [hl] ; x#SPRITESTATEDATA2_MAPY - add d - ld [hli], a ; update Y position - ld a, [hl] ; x#SPRITESTATEDATA2_MAPX - add e - ld [hl], a ; update X position + call Func_5349 ldh a, [hCurrentSpriteOffset] ld l, a ld [hl], $10 ; [x#SPRITESTATEDATA2_WALKANIMATIONCOUNTER] = 16 @@ -301,22 +274,7 @@ TryWalking: ; update the walking animation parameters for a sprite that is currently walking UpdateSpriteInWalkingAnimation: - ldh a, [hCurrentSpriteOffset] - add $7 - ld l, a - ld a, [hl] ; x#SPRITESTATEDATA1_INTRAANIMFRAMECOUNTER - inc a - ld [hl], a ; [x#SPRITESTATEDATA1_INTRAANIMFRAMECOUNTER]++ - cp $4 - jr nz, .noNextAnimationFrame - xor a - ld [hl], a ; [x#SPRITESTATEDATA1_INTRAANIMFRAMECOUNTER] = 0 - inc l - 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 + call Func_5274 ldh a, [hCurrentSpriteOffset] add $3 ld l, a @@ -448,6 +406,7 @@ InitializeSpriteStatus: ld a, $8 ld [hli], a ; [x#SPRITESTATEDATA2_YDISPLACEMENT] = 8 ld [hl], a ; [x#SPRITESTATEDATA2_XDISPLACEMENT] = 8 + call InitializeSpriteScreenPosition ; could have done fallthrough here ret ; calculates the sprite's screen position from its map position and the player position @@ -460,7 +419,7 @@ InitializeSpriteScreenPosition: ld b, a ld a, [hl] ; x#SPRITESTATEDATA2_MAPY sub b ; relative to player position - swap a ; * 16 + call Func_5033 sub $4 ; - 4 dec h ld [hli], a ; [x#SPRITESTATEDATA1_YPIXELS] @@ -469,11 +428,23 @@ InitializeSpriteScreenPosition: ld b, a ld a, [hli] ; x#SPRITESTATEDATA2_MAPX sub b ; relative to player position - swap a ; * 16 + call Func_5033 dec h ld [hl], a ; [x#SPRITESTATEDATA1_XPIXELS] ret +Func_5033: + jr nc, .asm_503c + cpl + inc a + swap a + cpl + inc a + ret +.asm_503c + swap a + ret + ; tests if sprite is off screen or otherwise unable to do anything CheckSpriteAvailability: predef IsObjectHidden @@ -593,16 +564,8 @@ CanWalkOntoTile: and a ret .notScripted - ld a, [wTilesetCollisionPtr] - ld l, a - ld a, [wTilesetCollisionPtr+1] - ld h, a -.tilePassableLoop - ld a, [hli] - cp $ff - jr z, .impassable - cp c - jr nz, .tilePassableLoop + call _IsTilePassable + jr c, .impassable ld h, HIGH(wSpriteStateData2) ldh a, [hCurrentSpriteOffset] add $6 @@ -626,7 +589,13 @@ CanWalkOntoTile: jr nc, .impassable ; don't walk off screen push de push bc + ld a, [wUpdateSpritesEnabled] + push af + ld a, $ff + ld [wUpdateSpritesEnabled], a call DetectCollisionBetweenSprites + pop af + ld [wUpdateSpritesEnabled], a pop bc pop de ld h, HIGH(wSpriteStateData1) @@ -649,8 +618,9 @@ CanWalkOntoTile: ; 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) + ; this was fixed in Yellow cp $5 - jr c, .impassable ; if [x#SPRITESTATEDATA2_YDISPLACEMENT]+d < 5, don't go + ;jr c, .impassable ; if [x#SPRITESTATEDATA2_YDISPLACEMENT]+d < 5, don't go jr .checkHorizontal .upwards sub $1 @@ -704,7 +674,7 @@ GetTileSpriteStandsOn: ld l, a 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 + and $f8 ; in case object is currently moving (XXX why changed to $f8?) srl a ; screen Y tile * 4 ld c, a ld b, $0 @@ -870,20 +840,235 @@ AnimScriptedNPCMovement: ret AdvanceScriptedNPCAnimFrameCounter: + call Func_5274 + ld h, HIGH(wSpriteStateData1) ldh a, [hCurrentSpriteOffset] - add $7 + add $8 ld l, a ld a, [hl] ; intra-animation frame counter + and $3 + ldh [hSpriteAnimFrameCounter], a + ret + +Func_5274: + ldh a, [hCurrentSpriteOffset] + add $7 + ld l, a + ld h, HIGH(wSpriteStateData1) + ld a, [hl] ; x#SPRITESTATEDATA1_INTRAANIMFRAMECOUNTER inc a - ld [hl], a - cp 4 + and $3 + ld [hl], a ; [x#SPRITESTATEDATA1_INTRAANIMFRAMECOUNTER]++ ret nz - xor a - ld [hl], a ; reset intra-animation frame counter inc l - ld a, [hl] ; animation frame counter + 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) + ret + +Func_5288: +; nice lookup table +; a is supposedly [wNPCMovementDirections + $fe] + cp $5 + jr z, .asm_52af + cp $4 + jr z, .asm_52aa + cp $6 + jr z, .asm_52b4 + cp $7 + jr z, .asm_52b9 + cp $11 + jr z, .asm_52c3 + cp $12 + jr z, .asm_52be + cp $13 + jr z, .asm_52c8 + cp $14 + jr z, .asm_52cd + xor a + ret +; set 1? +.asm_52aa + call Func_531f + jr .asm_52e6 +.asm_52af + call Func_5325 + jr .asm_52e6 +.asm_52b4 + call Func_5331 + jr .asm_52e6 +.asm_52b9 + call Func_532b + jr .asm_52e6 +; set 2? +.asm_52be + call Func_531f + jr .asm_52fa +.asm_52c3 + call Func_5325 + jr .asm_52fa +.asm_52c8 + call Func_5331 + jr .asm_52fa +.asm_52cd + call Func_532b + jr .asm_52fa +; set 3? (unused) +.asm_52d2 + call Func_531f + jr .asm_530b +.asm_52d7 + call Func_5325 + jr .asm_530b +.asm_52dc + call Func_5331 + jr .asm_530b +.asm_52e1 + call Func_532b + jr .asm_530b + +.asm_52e6 + call Func_5337 + call Func_5349 + ldh a, [hCurrentSpriteOffset] + ld l, a + ld [hl], $8 + dec h + inc l + ld [hl], $4 + call UpdateSpriteImage + scf + ret + +.asm_52fa + call Func_5337 + ldh a, [hCurrentSpriteOffset] + ld l, a + ld [hl], $8 + dec h + inc l + ld [hl], $3 + call UpdateSpriteImage + scf + ret + +.asm_530b + call Func_5337 + call Func_5349 + ldh a, [hCurrentSpriteOffset] + ld l, a + ld [hl], $8 + dec h + inc l + ld [hl], $3 + call UpdateSpriteImage + scf + ret + +Func_531f: + lb de, 1, 0 + ld c, SPRITE_FACING_DOWN + ret + +Func_5325: + lb de, -1, 0 + ld c, SPRITE_FACING_UP + ret + +Func_532b: + lb de, 0, 1 + ld c, SPRITE_FACING_RIGHT + ret + +Func_5331: + lb de, 0, -1 + ld c, SPRITE_FACING_LEFT + ret + +Func_5337: + ldh a, [hCurrentSpriteOffset] + add $9 + ld l, a + ld h, HIGH(wSpriteStateData1) + ld [hl], c ; x#SPRITESTATEDATA1_FACINGDIRECTION + ldh a, [hCurrentSpriteOffset] + add $3 + ld l, a + ld [hl], d ; x#SPRITESTATEDATA1_YSTEPVECTOR + inc l + inc l + ld [hl], e ; x#SPRITESTATEDATA1_XSTEPVECTOR + ret + +Func_5349: + ld h, HIGH(wSpriteStateData2) + ldh a, [hCurrentSpriteOffset] + add $4 + ld l, a + ld a, [hl] ; x#SPRITESTATEDATA2_MAPY + add d + ld [hli], a ; update Y position + ld a, [hl] ; x#SPRITESTATEDATA2_MAPX + add e + ld [hl], a ; update X position + ret + +Func_5357: + call Func_5274 + ldh a, [hCurrentSpriteOffset] + add $3 + ld l, a + ld h, HIGH(wSpriteStateData1) + ld a, [hli] + add a + ld b, a + ld a, [hl] + add b + ld [hli], a + ld a, [hli] + add a + ld b, a + ld a, [hl] + add b + ld [hl], a + ldh a, [hCurrentSpriteOffset] + ld l, a + ld h, HIGH(wSpriteStateData2) + dec [hl] + ret nz + ld a, $6 + add l + ld l, a + ld a, [hl] + cp $fe + jr nc, .asm_5386 + ldh a, [hCurrentSpriteOffset] + inc a + ld l, a + ld h, HIGH(wSpriteStateData1) + ld [hl], $1 + ret +.asm_5386 + call Random + ldh a, [hCurrentSpriteOffset] + add $8 + ld l, a + ld h, HIGH(wSpriteStateData2) + ldh a, [hRandomAdd] + and $7f + ld [hl], a + dec h + ldh a, [hCurrentSpriteOffset] + inc a + ld l, a + ld [hl], $2 + inc l + inc l + xor a + ld b, [hl] + ld [hli], a + inc l + ld c, [hl] ld [hl], a - ldh [hSpriteAnimFrameCounter], a ret diff --git a/engine/overworld/npc_movement_2.asm b/engine/overworld/npc_movement_2.asm new file mode 100755 index 00000000..2ced9da6 --- /dev/null +++ b/engine/overworld/npc_movement_2.asm @@ -0,0 +1,24 @@ +FreezeEnemyTrainerSprite:: + ld a, [wCurMap] + cp POKEMON_TOWER_7F + ret z ; the Rockets on Pokemon Tower 7F leave after battling, so don't freeze them + ld hl, RivalIDs + ld a, [wEngagedTrainerClass] + ld b, a +.loop + ld a, [hli] + 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] + ldh [hSpriteIndex], a + jp SetSpriteMovementBytesToFF + +RivalIDs: + db OPP_RIVAL1 + db OPP_RIVAL2 + db OPP_RIVAL3 + db -1 ; end diff --git a/engine/overworld/pathfinding.asm b/engine/overworld/pathfinding.asm index 1925dbbc..a824d337 100644 --- a/engine/overworld/pathfinding.asm +++ b/engine/overworld/pathfinding.asm @@ -14,22 +14,22 @@ FindPathToPlayer: call CalcDifference ld d, a and a - jr nz, .asm_f8da + jr nz, .asm_f76a ldh a, [hFindPathFlags] set 0, a ; current end of path matches the player's Y coordinate ldh [hFindPathFlags], a -.asm_f8da +.asm_f76a ldh a, [hFindPathXProgress] ld b, a ldh a, [hNPCPlayerXDistance] ; X distance in steps call CalcDifference ld e, a and a - jr nz, .asm_f8ec + jr nz, .asm_f77c ldh a, [hFindPathFlags] set 1, a ; current end of path matches the player's X coordinate ldh [hFindPathFlags], a -.asm_f8ec +.asm_f77c ldh a, [hFindPathFlags] cp $3 ; has the end of the path reached the player's position? jr z, .done diff --git a/engine/overworld/player_animations.asm b/engine/overworld/player_animations.asm index c458a013..5056c0b2 100755 --- a/engine/overworld/player_animations.asm +++ b/engine/overworld/player_animations.asm @@ -13,8 +13,8 @@ EnterMapAnim:: call PlaySound ld hl, wd732 bit 4, [hl] ; used dungeon warp? - res 4, [hl] pop hl + ;res 4, [hl] jr nz, .dungeonWarpAnimation call PlayerSpinWhileMovingDown ld a, SFX_TELEPORT_ENTER_2 @@ -34,21 +34,22 @@ EnterMapAnim:: ld [hl], $ff ; wPlayerSpinInPlaceAnimSoundID ld hl, wFacingDirectionList call PlayerSpinInPlace + ld a, $1 + ld [wPikachuSpawnState], a .restoreDefaultMusic call PlayDefaultMusic .done + call Func_151d jp RestoreFacingDirectionAndYScreenPos .dungeonWarpAnimation ld c, 50 call DelayFrames call PlayerSpinWhileMovingDown + ld a, $0 + ld [wPikachuSpawnState], a jr .done .flyAnimation pop hl - ld de, BirdSprite - ld hl, vNPCSprites - lb bc, BANK(BirdSprite), $0c - call CopyVideoData call LoadBirdSpriteGraphics ld a, SFX_FLY call PlaySound @@ -61,6 +62,8 @@ EnterMapAnim:: ld de, FlyAnimationEnterScreenCoords call DoFlyAnimation call LoadPlayerSpriteGraphics + ld a, $1 + ld [wPikachuSpawnState], a jr .restoreDefaultMusic FlyAnimationEnterScreenCoords: @@ -90,7 +93,9 @@ PlayerSpinWhileMovingDown: ld [hl], a ; wPlayerSpinWhileMovingUpOrDownAnimFrameDelay jp PlayerSpinWhileMovingUpOrDown + _LeaveMapAnim:: + call Func_1510 call InitFacingDirectionList call IsPlayerStandingOnWarpPadOrHole ld a, b @@ -249,12 +254,14 @@ DoFlyAnimation: LoadBirdSpriteGraphics: ld de, BirdSprite + ld b, BANK(BirdSprite) + ld c, $c ld hl, vNPCSprites - lb bc, BANK(BirdSprite), 12 call CopyVideoData ld de, BirdSprite tile 12 ; moving animation sprite + ld b, BANK(BirdSprite) + ld c, 12 ld hl, vNPCSprites2 - lb bc, BANK(BirdSprite), 12 jp CopyVideoData InitFacingDirectionList: @@ -380,9 +387,10 @@ FishingAnim: call DelayFrames ld hl, wd736 set 6, [hl] ; reserve the last 4 OAM entries + ld hl, vNPCSprites ld de, RedSprite - ld hl, vNPCSprites tile $00 - lb bc, BANK(RedSprite), 12 + ld b, BANK(RedSprite) + ld c, 12 call CopyVideoData ld a, $4 ld hl, RedFishingTiles diff --git a/engine/overworld/player_state.asm b/engine/overworld/player_state.asm index 70326754..c966c128 100644 --- a/engine/overworld/player_state.asm +++ b/engine/overworld/player_state.asm @@ -70,7 +70,8 @@ CheckForceBikeOrSurf:: ld a, $1 ld [wWalkBikeSurfState], a ld [wWalkBikeSurfStateCopy], a - jp ForceBikeOrSurf + call ForceBikeOrSurf + ret .incorrectMap inc hl .incorrectY @@ -80,7 +81,8 @@ CheckForceBikeOrSurf:: ld a, $2 ld [wWalkBikeSurfState], a ld [wWalkBikeSurfStateCopy], a - jp ForceBikeOrSurf + call ForceBikeOrSurf + ret INCLUDE "data/maps/force_bike_surf.asm" @@ -101,10 +103,10 @@ IsPlayerFacingEdgeOfMap:: ld b, a ld a, [wXCoord] ld c, a - ld de, .asm_c41e + ld de, .returnaddress push de jp hl -.asm_c41e +.returnaddress pop bc pop de pop hl @@ -224,8 +226,7 @@ PrintSafariZoneSteps:: cp CERULEAN_CAVE_2F ret nc hlcoord 0, 0 - ld b, 3 - ld c, 7 + lb bc, 3, 7 call TextBoxBorder hlcoord 1, 1 ld de, wSafariSteps @@ -239,11 +240,11 @@ PrintSafariZoneSteps:: call PlaceString ld a, [wNumSafariBalls] cp 10 - jr nc, .asm_c56d + jr nc, .numSafariBallsTwoDigits hlcoord 5, 3 ld a, " " ld [hl], a -.asm_c56d +.numSafariBallsTwoDigits hlcoord 6, 3 ld de, wNumSafariBalls lb bc, 1, 2 @@ -345,16 +346,8 @@ GetTileTwoStepsInFrontOfPlayer: CheckForCollisionWhenPushingBoulder: call GetTileTwoStepsInFrontOfPlayer - ld hl, wTilesetCollisionPtr - ld a, [hli] - ld h, [hl] - ld l, a -.loop - ld a, [hli] - cp $ff - jr z, .done ; if the tile two steps ahead is not passable - cp c - jr nz, .loop + call IsTilePassable + jr c, .done ld hl, TilePairCollisionsLand call CheckForTilePairCollisions2 ld a, $ff diff --git a/engine/overworld/push_boulder.asm b/engine/overworld/push_boulder.asm index a8e532d3..09911ca3 100644 --- a/engine/overworld/push_boulder.asm +++ b/engine/overworld/push_boulder.asm @@ -2,6 +2,8 @@ TryPushingBoulder:: ld a, [wd728] bit 0, a ; using Strength? ret z +Func_f0a7: +; where LoadMissableObjects predef points to now ld a, [wFlags_0xcd60] bit 1, a ; has boulder dust animation from previous push played yet? ret nz diff --git a/engine/overworld/sprite_collisions.asm b/engine/overworld/sprite_collisions.asm index dc57d5b9..db81977b 100644 --- a/engine/overworld/sprite_collisions.asm +++ b/engine/overworld/sprite_collisions.asm @@ -1,5 +1,5 @@ _UpdateSprites:: - ld h, $c1 + ld h, wSpriteStateData1 / $100 inc h ld a, SPRITESTATEDATA2_IMAGEBASEOFFSET .spriteLoop @@ -24,9 +24,12 @@ _UpdateSprites:: jr nz, .spriteLoop ret .updateCurrentSprite - cp $1 - jp nz, UpdateNonPlayerSprite - jp UpdatePlayerSprite + ldh a, [hCurrentSpriteOffset] + and a + jp z, UpdatePlayerSprite + cp $f0 ; pikachu + jp z, SpawnPikachu + ld a, [hl] UpdateNonPlayerSprite: dec a @@ -52,11 +55,10 @@ UpdateNonPlayerSprite: ; 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 + ; nop ld h, HIGH(wSpriteStateData1) ldh a, [hCurrentSpriteOffset] - add LOW(wSpriteStateData1) ld l, a ld a, [hl] ; a = [i#SPRITESTATEDATA1_PICTUREID] (0 if slot is unused) @@ -271,6 +273,17 @@ DetectCollisionBetweenSprites: jr nc, .next ; go to next sprite if distance is still positive after both adjustments .collision + ld a, l + and $f0 ; collision with pikachu? + jr nz, .asm_4cd9 + xor a + ld [wd434], a + ldh a, [hFF8F] + cp $f + jr nz, .asm_4cd9 + call Func_4d0a + jr .asm_4cef +.asm_4cd9 ldh a, [hFF91] ; a = 7 or 9 depending on sprite i's delta X ld b, a ldh a, [hFF90] ; a = 7 or 9 depending on sprite i's delta Y @@ -296,6 +309,7 @@ DetectCollisionBetweenSprites: ; to indicate which sprite the collision occurred with inc l inc l +.asm_4cef ldh a, [hFF8F] ; a = loop counter ld de, SpriteCollisionBitTable add a @@ -324,6 +338,26 @@ DetectCollisionBetweenSprites: ; c = 0 if delta X/Y is 0 ; c = 7 if delta X/Y is 1 ; c = 9 if delta X/Y is -1 +Func_4d0a: + ldh a, [hFF91] + ld b, a + ldh a, [hFF90] + inc l + cp b + jr c, .asm_4d17 + ld b, %1100 + jr .asm_4d19 +.asm_4d17 + ld b, %11 +.asm_4d19 + ld a, c + and b + ld [wd434], a + ld a, c + inc l + inc l + ret + SetSpriteCollisionValues: and a ld b, 0 diff --git a/engine/overworld/tilesets.asm b/engine/overworld/tilesets.asm index f40cbbc2..686fa50c 100644 --- a/engine/overworld/tilesets.asm +++ b/engine/overworld/tilesets.asm @@ -5,23 +5,14 @@ LoadTilesetHeader: ld a, [wCurMapTileset] add a add a - ld b, a - add a - add b ; a = tileset * 12 - jr nc, .noCarry - inc d -.noCarry ld e, a ld hl, Tilesets add hl, de + add hl, de + add hl, de ld de, wTilesetBank - ld c, $b -.copyTilesetHeaderLoop - ld a, [hli] - ld [de], a - inc de - dec c - jr nz, .copyTilesetHeaderLoop + ld bc, $b + call CopyData ld a, [hl] ldh [hTilesetType], a xor a @@ -35,13 +26,13 @@ LoadTilesetHeader: call IsInArray pop de pop hl - jr c, .asm_c797 + jr c, .notDungeonTileset ld a, [wCurMapTileset] ld b, a ldh a, [hPreviousTileset] cp b jr z, .done -.asm_c797 +.notDungeonTileset ld a, [wDestinationWarpID] cp $ff jr z, .done diff --git a/engine/overworld/turn_sprite.asm b/engine/overworld/turn_sprite.asm deleted file mode 100755 index 7b34a03a..00000000 --- a/engine/overworld/turn_sprite.asm +++ /dev/null @@ -1,25 +0,0 @@ -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 |