diff options
Diffstat (limited to 'engine/overworld')
28 files changed, 1305 insertions, 694 deletions
diff --git a/engine/overworld/advance_player_sprite.asm b/engine/overworld/advance_player_sprite.asm new file mode 100644 index 00000000..6b4a0cbb --- /dev/null +++ b/engine/overworld/advance_player_sprite.asm @@ -0,0 +1,241 @@ +_AdvancePlayerSprite:: + ld a,[wSpriteStateData1 + 3] ; delta Y + ld b,a + ld a,[wSpriteStateData1 + 5] ; delta X + ld c,a + ld hl,wWalkCounter ; walking animation counter + dec [hl] + jr nz,.afterUpdateMapCoords +; if it's the end of the animation, update the player's map coordinates + 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 a,$07 + jp nz,.scrollBackgroundAndSprites +; if this is the first iteration of the animation + ld a,c + cp a,$01 + jr nz,.checkIfMovingWest +; moving east + 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 a,$ff + jr nz,.checkIfMovingSouth +; moving west + ld a,[wMapViewVRAMPointer] + ld e,a + and a,$e0 + ld d,a + ld a,e + sub $02 + and $1f + or d + ld [wMapViewVRAMPointer],a + jr .adjustXCoordWithinBlock +.checkIfMovingSouth + ld a,b + cp a,$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 a,$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 a,$ff + jr nz,.adjustYCoordWithinBlock +; moved into the tile block to the west + ld a,$1 + 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 $2 + 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 a,$ff + jr nz,.updateMapView +; moved into the tile block to the north + ld a,$1 + ld [hl],a + ld hl,wYOffsetSinceLastSpecialWarp + dec [hl] + ld de,wCurrentTileBlockMapViewPointer + ld a,[wCurMapWidth] + call MoveTileBlockMapPointerNorth +.updateMapView + call LoadCurrentMapView + ld a,[wSpriteStateData1 + 3] ; delta Y + cp $1 + 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,[wSpriteStateData1 + 5] ; delta X + cp $1 + jr nz,.checkIfMovingWest2 +; if moving east + call ScheduleEastColumnRedraw + jr .scrollBackgroundAndSprites +.checkIfMovingWest2 + cp $ff + jr nz,.scrollBackgroundAndSprites +; if moving west + call ScheduleWestColumnRedraw +.scrollBackgroundAndSprites + ld a,[wSpriteStateData1 + 3] ; delta Y + add a + ld b,a + ld a,[wSpriteStateData1 + 5] ; delta X + 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,wSpriteStateData1 + $14 + 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 + ld a,[hSCY] + add b + ld [hSCY],a ; update background scroll Y + ld a,[hSCX] + add c + ld [hSCX],a ; update background scroll X + ret + +MoveTileBlockMapPointerEast:: + ld a,[de] + add $1 + ld [de],a + ret nc + inc de + ld a,[de] + inc a + ld [de],a + ret + +MoveTileBlockMapPointerWest:: + ld a,[de] + sub $1 + ld [de],a + ret nc + inc de + ld a,[de] + dec a + ld [de],a + ret + +MoveTileBlockMapPointerSouth:: + add $6 + 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 $6 + 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/cable_club_npc.asm b/engine/overworld/cable_club_npc.asm index 08067412..12ce64a4 100755 --- a/engine/overworld/cable_club_npc.asm +++ b/engine/overworld/cable_club_npc.asm @@ -1,9 +1,12 @@ CableClubNPC: ld hl, CableClubNPCWelcomeText call PrintText + call CheckPikachuFollowingPlayer + jr nz, .asm_7048 CheckEvent EVENT_GOT_POKEDEX jp nz, .receivedPokedex ; if the player hasn't received the pokedex +.asm_7048 ld c, 60 call DelayFrames ld hl, CableClubNPCMakingPreparationsText @@ -107,7 +110,61 @@ CableClubNPC: xor a ld [hld], a ld [hl], a - jpab LinkMenu + ld a, [wLetterPrintingDelayFlags] + push af + callab LinkMenu + pop af + ld [wLetterPrintingDelayFlags], a + ret + +; seems to be similar of Serial_SyncAndExchangeNybble +Serial_SyncAndExchangeNybbleDouble: + ld a, $ff + ld [wSerialExchangeNybbleReceiveData], a +.loop + call Serial_ExchangeNybble + call DelayFrame + push hl + ld hl, wUnknownSerialCounter + 1 + dec [hl] + jr nz, .next + dec hl + dec [hl] + jr nz, .next + pop hl + jr .setUnknownSerialCounterToFFFF +.next + pop hl + ld a, [wSerialExchangeNybbleReceiveData] + inc a + jr z, .loop + call DelayFrame + ld a, $ff + ld [wSerialExchangeNybbleReceiveData], a + call Serial_ExchangeNybble + ld a, [wSerialExchangeNybbleReceiveData] + inc a + jr z, .loop + ld b, 10 +.syncLoop1 + call DelayFrame + call Serial_ExchangeNybble + dec b + jr nz, .syncLoop1 + ld b, 10 +.syncLoop2 + call DelayFrame + call Serial_SendZeroByte + dec b + jr nz, .syncLoop2 + ld a, [wSerialExchangeNybbleReceiveData] + ld [wSerialSyncAndExchangeNybbleReceiveData], a + ret +.setUnknownSerialCounterToFFFF + ld a, $ff + ld [wUnknownSerialCounter], a + ld [wUnknownSerialCounter + 1], a + ret CableClubNPCAreaReservedFor2FriendsLinkedByCableText: TX_FAR _CableClubNPCAreaReservedFor2FriendsLinkedByCableText diff --git a/engine/overworld/card_key.asm b/engine/overworld/card_key.asm index 35495c82..a4452b4a 100755 --- a/engine/overworld/card_key.asm +++ b/engine/overworld/card_key.asm @@ -8,7 +8,8 @@ PrintCardKeyText: ret z cp b jr nz, .silphCoMapListLoop - predef GetTileAndCoordsInFrontOfPlayer +; does not check for tile in front of player. This might be buggy + ;predef GetTileAndCoordsInFrontOfPlayer ld a, [wTileInFrontOfPlayer] cp $18 jr z, .cardKeyDoorInFrontOfPlayer @@ -25,12 +26,12 @@ PrintCardKeyText: ld b, CARD_KEY call IsItemInBag jr z, .noCardKey - call GetCoordsInFrontOfPlayer - push de + xor a + ld [wPlayerMovingDirection], a tx_pre_id CardKeySuccessText ld [hSpriteIndexOrTextID], a call PrintPredefTextID - pop de + call GetCoordsInFrontOfPlayer srl d ld a, d ld b, a @@ -88,7 +89,7 @@ GetCoordsInFrontOfPlayer: ld d, a ld a, [wXCoord] ld e, a - ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction + ld a, [wSpritePlayerStateData1FacingDirection] ; player's sprite facing direction and a jr nz, .notFacingDown ; facing down diff --git a/engine/overworld/cut.asm b/engine/overworld/cut.asm index f6ae6468..bc7d092d 100755 --- a/engine/overworld/cut.asm +++ b/engine/overworld/cut.asm @@ -76,6 +76,7 @@ InitCutAnimOAM: ld [wWhichAnimationOffsets], a ld a, %11100100 ld [rOBP1], a + call UpdateGBCPal_OBP1 ld a, [wCutTile] cp $52 jr z, .grass @@ -123,8 +124,8 @@ WriteCutOrBoulderDustAnimationOAMBlock: jp WriteOAMBlock CutOrBoulderDustAnimationTilesAndAttributes: - db $FC,$10,$FD,$10 - db $FE,$10,$FF,$10 + db $FC,$14,$FD,$14 + db $FE,$14,$FF,$14 GetCutOrBoulderDustAnimationOffsets: ld hl, wSpriteStateData1 + 4 @@ -187,7 +188,7 @@ ReplaceTreeTileBlock: ld h, [hl] ld l, a add hl, bc - ld a, [wSpriteStateData1 + 9] ; player sprite's facing direction + ld a, [wSpritePlayerStateData1FacingDirection] ; player sprite's facing direction and a jr z, .down cp SPRITE_FACING_UP diff --git a/engine/overworld/cut2.asm b/engine/overworld/cut2.asm index f16fed66..37490f95 100755 --- a/engine/overworld/cut2.asm +++ b/engine/overworld/cut2.asm @@ -18,6 +18,7 @@ AnimCut: ld a, [rOBP1] xor $64 ld [rOBP1], a + call UpdateGBCPal_OBP1 call DelayFrame pop bc dec c @@ -68,6 +69,7 @@ AnimCutGrass_UpdateOAMEntries: ld a, [rOBP1] xor $64 ld [rOBP1], a + call UpdateGBCPal_OBP1 call DelayFrame pop bc dec c diff --git a/engine/overworld/doors.asm b/engine/overworld/doors.asm index c39e096d..8bde8600 100755 --- a/engine/overworld/doors.asm +++ b/engine/overworld/doors.asm @@ -39,6 +39,7 @@ DoorTileIDPointers: dbw LAB, LabDoorTileIDs dbw FACILITY, FacilityDoorTileIDs dbw PLATEAU, PlateauDoorTileIDs + dbw INTERIOR, InteriorDoorTileIDs db $ff OverworldDoorTileIDs: @@ -73,3 +74,6 @@ FacilityDoorTileIDs: PlateauDoorTileIDs: db $3b,$1b,$00 + +InteriorDoorTileIDs: + db $04,$15,$00 diff --git a/engine/overworld/dungeon_warps.asm b/engine/overworld/dungeon_warps.asm new file mode 100644 index 00000000..f47dfb01 --- /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/elevator.asm b/engine/overworld/elevator.asm index d68e4f81..47ec78f9 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, $ff - call PlaySound + call StopAllMusic ld a, [hSCY] ld d, a ld e, $1 @@ -27,8 +26,7 @@ ShakeElevator: jr nz, .shakeLoop ld a, d ld [hSCY], a - ld a, $ff - 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 ac4276bd..3b02fd55 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 + $780 lb bc, BANK(EmotionBubbles), $04 call CopyVideoData @@ -59,12 +62,9 @@ EmotionBubble: pop af ld [wUpdateSpritesEnabled], a call DelayFrame - jp UpdateSprites + call UpdateSprites + ret -EmotionBubblesPointerTable: - dw EmotionBubbles - dw EmotionBubbles + $40 - dw EmotionBubbles + $80 EmotionBubblesOAM: db $F8,$00,$F9,$00 diff --git a/engine/overworld/field_move_messages.asm b/engine/overworld/field_move_messages.asm index b1506742..1d111917 100644 --- a/engine/overworld/field_move_messages.asm +++ b/engine/overworld/field_move_messages.asm @@ -32,7 +32,7 @@ IsSurfingAllowed: ret nz CheckBothEventsSet EVENT_SEAFOAM4_BOULDER1_DOWN_HOLE, EVENT_SEAFOAM4_BOULDER2_DOWN_HOLE ret z - ld hl, CoordsData_cdf7 + ld hl, CoordsData_f5b64 call ArePlayerCoordsInArray ret nc ld hl, wd728 @@ -45,7 +45,7 @@ IsSurfingAllowed: ld hl, CyclingIsFunText jp PrintText -CoordsData_cdf7: +CoordsData_f5b64: db $0B,$07,$FF CurrentTooFastText: diff --git a/engine/overworld/healing_machine.asm b/engine/overworld/healing_machine.asm index 38a44cfb..e5ba004e 100755 --- a/engine/overworld/healing_machine.asm +++ b/engine/overworld/healing_machine.asm @@ -12,14 +12,13 @@ AnimateHealingMachine: push af ld a, $e0 ld [rOBP1], a + call UpdateGBCPal_OBP1 ld hl, wOAMBuffer + $84 ld de, PokeCenterOAMData call CopyHealingMachineOAM ld a, 4 ld [wAudioFadeOutControl], a - ld a, $ff - 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, $ff - 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 ld [rOBP1], a + call UpdateGBCPal_OBP1 pop hl pop af ld [hl], a @@ -66,13 +64,13 @@ PokeCenterFlashingMonitorAndHealBall: INCBIN "gfx/pokecenter_ball.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 + db $24,$34,$7C,$14 ; heal machine monitor + db $2B,$30,$7D,$14 ; pokeballs 1-6 + db $2B,$38,$7D,$34 + db $30,$30,$7D,$14 + db $30,$38,$7D,$34 + db $35,$30,$7D,$14 + db $35,$38,$7D,$34 ; d = value to xor with palette FlashSprite8Times: @@ -81,6 +79,7 @@ FlashSprite8Times: ld a, [rOBP1] xor d ld [rOBP1], a + call UpdateGBCPal_OBP1 ld c, 10 call DelayFrames dec b diff --git a/engine/overworld/hidden_items.asm b/engine/overworld/hidden_items.asm index 32783f83..b64411c7 100755 --- a/engine/overworld/hidden_items.asm +++ b/engine/overworld/hidden_items.asm @@ -9,7 +9,7 @@ HiddenItems: predef FlagActionPredef ld a, c and a - ret nz + jr nz, .itemAlreadyFound call EnableAutoTextBoxDrawing ld a, 1 ld [wDoNotWaitForButtonPressAfterDisplayingText], a @@ -18,6 +18,11 @@ HiddenItems: call GetItemName tx_pre_jump FoundHiddenItemText +.itemAlreadyFound + ld a, $ff + ld [hItemAlreadyFound], a + ret + INCLUDE "data/hidden_item_coords.asm" FoundHiddenItemText: @@ -54,7 +59,7 @@ HiddenCoins: predef GetQuantityOfItemInBag ld a, b and a - ret z + jr z, .doNotPickUpCoins ld hl, HiddenCoinCoords call FindHiddenItemOrCoinsIndex ld [wHiddenItemOrCoinsIndex], a @@ -65,7 +70,7 @@ HiddenCoins: predef FlagActionPredef ld a, c and a - ret nz + jr nz, .doNotPickUpCoins xor a ld [hUnusedCoinsByte], a ld [hCoins], a @@ -79,6 +84,12 @@ HiddenCoins: cp 40 jr z, .bcd20 ; should be bcd40 jr .bcd100 + +.doNotPickUpCoins + ld a, $ff + ld [hItemAlreadyFound], a + ret + .bcd10 ld a, $10 ld [hCoins + 1], a diff --git a/engine/overworld/hidden_objects.asm b/engine/overworld/hidden_objects.asm index dcdf8537..66815b60 100755 --- a/engine/overworld/hidden_objects.asm +++ b/engine/overworld/hidden_objects.asm @@ -1,43 +1,17 @@ -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 [$ffee], else stores $ff +; if a hidden object was found, stores $00 in [hDidntFindAnyHiddenObject], else stores $ff CheckForHiddenObject: - ld hl, $ffeb + ld hl, hItemAlreadyFound xor a ld [hli], a ld [hli], a ld [hli], a ld [hl], a - 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 @@ -81,13 +55,13 @@ CheckForHiddenObject: ret .noMatch ld a, $ff - ld [$ffee], a + ld [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] ; player's sprite facing direction cp SPRITE_FACING_UP jr z, .facingUp cp SPRITE_FACING_LEFT diff --git a/engine/overworld/ledges.asm b/engine/overworld/ledges.asm index 342540b2..a44ddf8b 100755 --- a/engine/overworld/ledges.asm +++ b/engine/overworld/ledges.asm @@ -6,7 +6,7 @@ HandleLedges: and a ; OVERWORLD ret nz predef GetTileAndCoordsInFrontOfPlayer - ld a, [wSpriteStateData1 + 9] + ld a, [wSpritePlayerStateData1FacingDirection] ld b, a aCoord 8, 9 ld c, a @@ -71,10 +71,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: @@ -82,5 +85,6 @@ LedgeHoppingShadow: LedgeHoppingShadowEnd: LedgeHoppingShadowOAM: - db $FF,$10,$FF,$20 - db $FF,$40,$FF,$60 + db $58,$48,$FF,$00 + db $58,$50,$FF,$20 +LedgeHoppingShadowOAMEnd: diff --git a/engine/overworld/map_sprite_functions1.asm b/engine/overworld/map_sprite_functions1.asm index d1a411fa..2ad923fb 100644 --- a/engine/overworld/map_sprite_functions1.asm +++ b/engine/overworld/map_sprite_functions1.asm @@ -1,7 +1,7 @@ _UpdateSprites: - ld h, $c1 + ld h, wSpriteStateData1 / $100 inc h - ld a, $e ; wSpriteStateData2 + $0e + ld a, $e ; (wSpriteStateData2 + $0e) & $ff .spriteLoop ld l, a sub $e @@ -24,9 +24,12 @@ _UpdateSprites: jr nz, .spriteLoop ret .updateCurrentSprite - cp $1 - jp nz, UpdateNonPlayerSprite - jp UpdatePlayerSprite + ld a, [H_CURRENTSPRITEOFFSET] + and a + jp z, UpdatePlayerSprite + cp $f0 ; pikachu + jp z, SpawnPikachu + ld a, [hl] UpdateNonPlayerSprite: dec a @@ -51,11 +54,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, wSpriteStateData1 / $100 ld a, [H_CURRENTSPRITEOFFSET] - add wSpriteStateData1 % $100 ld l, a ld a, [hl] ; a = [$c1i0] (picture) (0 if slot is unused) @@ -270,6 +272,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 + ld a, [$ff8f] + cp $f + jr nz, .asm_4cd9 + call Func_4d0a + jr .asm_4cef +.asm_4cd9 ld a, [$ff91] ; 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 @@ -294,6 +307,7 @@ DetectCollisionBetweenSprites: ; set bit in [$c1ie] or [$c1if] to indicate which sprite the collision occurred with inc l inc l +.asm_4cef ld a, [$ff8f] ; a = loop counter ld de, SpriteCollisionBitTable add a @@ -322,6 +336,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: + ld a, [$ff91] + ld b, a + ld a, [$ff90] + 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/map_sprites.asm b/engine/overworld/map_sprites.asm index 8a6057a0..3e2c3912 100755 --- a/engine/overworld/map_sprites.asm +++ b/engine/overworld/map_sprites.asm @@ -8,261 +8,23 @@ ; 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: +_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. -.copyPictureIDLoop - ld a, [hl] ; $C1X0 (picture ID) - ld [de], a ; $C2XD - 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, wSpriteStateData2 + $0d - 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 - ld a, l - add $10 - ld l, a - dec b - jr nz, .copyPictureIDLoop - ld hl, wSpriteStateData2 + $1e -.loadTilePatternLoop - ld de, wSpriteStateData2 + $1d -; 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, wSpriteStateData2 + $0e - 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] ; $C2YE (VRAM slot) - 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] ; $C2XE (sprite picture ID) - ld b, a ; b = current sprite picture ID - cp SPRITE_BALL ; is it a 4-tile sprite? - jr c, .notFourTileSprite - pop af - ld 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 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, $c0 ; number of bytes per VRAM slot - ld 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). -.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] - and a - jr nz, .loadStillTilePattern -; if it's the first 4-tile sprite - ld hl, vSprites + $780 ; address for first 4-tile sprite - inc a - ld [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 - ld 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 = VRAM slot for the current picture ID (from $C2YE) - ld [hl], a ; store VRAM slot in current wSpriteStateData2 sprite slot (at $C2XE) -.nextSpriteSlot - ld a, l - add $10 - ld l, a - dec c - jp nz, .loadTilePatternLoop - ld hl, wSpriteStateData2 + $0d - ld b, $10 -; the pictures ID's stored at $C2XD are no longer needed, so zero them -.zeroStoredPictureIDLoop - xor a - ld [hl], a ; $C2XD - 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. ; 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 a, REDS_HOUSE_1F ; is the map a city or a route (map ID less than $25)? 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? @@ -274,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, wSpriteStateData2 + $0d - 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 -; 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 [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 ; $C2XD (sprite picture ID) - 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, wSpriteStateData2 + $1e - 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 a, $10 - add l - ld l, a - dec b - jr nz, .zeroVRAMSlotsLoop .skipLoadingSpriteSet - ld hl, wSpriteStateData1 + $10 + 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] ; $C1X0 (picture ID) (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 ; $C2XE (VRAM slot) - 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 SPRITE_BALL ; 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 + ld [hVRAMSlot], a + cp 9 + jr nc, .fourTileSprite + call LoadStillTilePattern + call LoadWalkingTilePattern + jr .continue + +.fourTileSprite + call LoadStillTilePattern +.continue + ld a, [hVRAMSlot] + inc a + cp 11 + jr nz, .loop + ret + +ReloadWalkingTilePatterns: + xor a +.loop + ld [hVRAMSlot], a + cp 9 + jr nc, .fourTileSprite + call LoadWalkingTilePattern +.fourTileSprite + ld 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 + ld 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: + ld 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 + ld [hVRAMSlot], a ; store current sprite set slot as a counter + ld a, [hl] ; $c1x0 (picture ID) + and a ; is the sprite unused? + jr z, .spriteUnused + call Func_14179 + push hl + ld de, (wSpritePlayerStateData2ImageBaseOffset) - (wSpriteStateData1) ; $10e + add hl, de ; get $c2xe (sprite image base offset) + ld [hl], a ; write offset + pop hl +.spriteUnused + ld de, wSprite02StateData1 - wSprite01StateData1 + add hl, de + ld 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 8587c0f7..dd601451 100644 --- a/engine/overworld/missable_objects.asm +++ b/engine/overworld/missable_objects.asm @@ -17,33 +17,30 @@ 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, MapHS00 ; calculate difference between out pointer and the base pointer ld a, l - sub e - jr nc, .asm_f13c - dec h -.asm_f13c + sub MapHS00 & $ff ; calculate difference between out pointer and the base pointer ld l, a ld a, h - sub d + sbc MapHS00 / $100 ld h, a ld a, h ld [H_DIVIDEND], a ld a, l - ld [H_DIVIDEND+1], a + ld [H_DIVIDEND + 1], a xor a - ld [H_DIVIDEND+2], a - ld [H_DIVIDEND+3], a + ld [H_DIVIDEND + 2], a + ld [H_DIVIDEND + 3], a ld a, $3 ld [H_DIVISOR], 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] + ld a, [H_DIVIDEND + 3] ld c, a ; store global offset in c ld de, wMissableObjectList pop hl diff --git a/engine/overworld/movement.asm b/engine/overworld/movement.asm index f272f497..f2334479 100644 --- a/engine/overworld/movement.asm +++ b/engine/overworld/movement.asm @@ -22,7 +22,13 @@ UpdatePlayerSprite: ld [wSpriteStateData1 + 2], a ret .lowerLeftTileIsMapTile + ld a, [wUpdateSpritesEnabled] + push af + ld a, $ff + ld [wUpdateSpritesEnabled], a call DetectCollisionBetweenSprites + pop af + ld [wUpdateSpritesEnabled], a ld h, wSpriteStateData1 / $100 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 [wSpriteStateData1 + 7], a ld [wSpriteStateData1 + 8], a - jr .calcImageIndex -.next - ld [wSpriteStateData1 + 9], a ; facing direction - 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 - ld a, [H_CURRENTSPRITEOFFSET] - 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, [wSpriteStateData1 + 8] - ld b, a - ld a, [wSpriteStateData1 + 9] - add b - ld [wSpriteStateData1 + 2], 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 @@ -97,18 +85,15 @@ UpdatePlayerSprite: jr nz, .next2 ld a, $80 .next2 - ld [wSpriteStateData2 + 7], a + ld [wSpriteStateData2 + $07], a ret -UnusedReadSpriteDataFunction: - push bc - push af - ld a, [H_CURRENTSPRITEOFFSET] - ld c, a - pop af - add c - ld l, a - pop bc +Func_4e32: + ld a, [wSpriteStateData1 + 8] + ld b, a + ld a, [wSpritePlayerStateData1FacingDirection] + add b + ld [wSpriteStateData1 + 2], a ret UpdateNPCSprite: @@ -121,7 +106,7 @@ UpdateNPCSprite: ld l, a ld a, [hl] ; read movement byte 2 ld [wCurSpriteMovement2], a - ld h, $c1 + ld h, wSpriteStateData1 / $100 ld a, [H_CURRENTSPRITEOFFSET] ld l, a inc l @@ -130,7 +115,7 @@ UpdateNPCSprite: jp z, InitializeSpriteStatus call CheckSpriteAvailability ret c ; if sprite is invisible, on tile >=MAP_TILESET_SIZE, in grass or player is currently walking - ld h, $c1 + ld h, wSpriteStateData1 / $100 ld a, [H_CURRENTSPRITEOFFSET] ld l, a inc l @@ -146,19 +131,21 @@ UpdateNPCSprite: jp z, UpdateSpriteMovementDelay ; c1x1 == 2 cp $3 jp z, UpdateSpriteInWalkingAnimation ; c1x1 == 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) call InitializeSpriteScreenPosition - ld h, $c2 + ld h, wSpriteStateData2 / $100 ld a, [H_CURRENTSPRITEOFFSET] add $6 ld l, a ld a, [hl] ; c2x6: movement byte 1 inc a - jr z, .randomMovement ; value $FF + jp z, .randomMovement ; value $FF inc a - jr z, .randomMovement ; value $FE + jp z, .randomMovement ; value $FE ; 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 $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,59 +256,25 @@ ChangeFacingDirection: ; set carry on failure, clears carry on success TryWalking: push hl - ld h, $c1 - ld a, [H_CURRENTSPRITEOFFSET] - add $9 - ld l, a - ld [hl], c ; c1x9 (update facing direction) - ld a, [H_CURRENTSPRITEOFFSET] - add $3 - ld l, a - ld [hl], d ; c1x3 (update Y movement delta) - inc l - inc l - ld [hl], e ; c1x5 (update X movement delta) + 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, $c2 + ret c + call Func_5349 ld a, [H_CURRENTSPRITEOFFSET] - add $4 ld l, a - ld a, [hl] ; c2x4: Y position - add d - ld [hli], a ; update Y position - ld a, [hl] ; c2x5: X position - add e - ld [hl], a ; update X position - ld a, [H_CURRENTSPRITEOFFSET] - ld l, a - ld [hl], $10 ; c2x0=16: walk animation counter + ld [hl], $10 ; c1x9 (update facing direction) dec h inc l - ld [hl], $3 ; c1x1: set movement status to walking + ld [hl], $3 jp UpdateSpriteImage ; update the walking animation parameters for a sprite that is currently walking UpdateSpriteInWalkingAnimation: - ld a, [H_CURRENTSPRITEOFFSET] - add $7 - ld l, a - ld a, [hl] ; c1x7 (counter until next walk animation frame) - inc a - ld [hl], a ; c1x7 += 1 - cp $4 - jr nz, .noNextAnimationFrame - xor a - ld [hl], a ; c1x7 = 0 - inc l - ld a, [hl] ; c1x8 (walk animation frame) - inc a - and $3 - ld [hl], a ; advance to next animation frame every 4 ticks (16 ticks total for one step) + call Func_5274 .noNextAnimationFrame ld a, [H_CURRENTSPRITEOFFSET] add $3 @@ -446,6 +405,7 @@ InitializeSpriteStatus: ld a, $8 ld [hli], a ; $c2x2: set Y displacement to 8 ld [hl], a ; $c2x3: set X displacement to 8 + call InitializeSpriteScreenPosition ; could have done fallthrough here ret ; calculates the sprite's screen position form its map position and the player position @@ -458,7 +418,7 @@ InitializeSpriteScreenPosition: ld b, a ld a, [hl] ; c2x4 (Y position + 4) sub b ; relative to player position - swap a ; * 16 + call Func_5033 sub $4 ; - 4 dec h ld [hli], a ; c1x4 (screen Y position) @@ -467,11 +427,23 @@ InitializeSpriteScreenPosition: ld b, a ld a, [hli] ; c2x6 (X position + 4) sub b ; relative to player position - swap a ; * 16 + call Func_5033 dec h ld [hl], a ; c1x6 (screen X position) 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 @@ -591,17 +563,9 @@ 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 - ld h, $c2 + call _IsTilePassable + jr c, .impassable + ld h, wSpriteStateData2 / $100 ld a, [H_CURRENTSPRITEOFFSET] add $6 ld l, a @@ -624,7 +588,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, wSpriteStateData1 / $100 @@ -643,7 +613,7 @@ CanWalkOntoTile: jr nz, .upwards add d cp $5 - jr c, .impassable ; if c2x2+d < 5, don't go ;bug: this tests probably were supposed to prevent sprites + ;jr c, .impassable (bugfix) ; 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 @@ -665,7 +635,7 @@ CanWalkOntoTile: and a ; clear carry (marking success) ret .impassable - ld h, $c1 + ld h, wSpriteStateData1 / $100 ld a, [H_CURRENTSPRITEOFFSET] inc a ld l, a @@ -697,7 +667,7 @@ GetTileSpriteStandsOn: ld l, a ld a, [hli] ; c1x4: screen Y position 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 @@ -863,20 +833,235 @@ AnimScriptedNPCMovement: ret AdvanceScriptedNPCAnimFrameCounter: + call Func_5274 + ld h, wSpriteStateData1 / $100 ld a, [H_CURRENTSPRITEOFFSET] - add $7 + add $8 ld l, a ld a, [hl] ; intra-animation frame counter + and $3 + ld [hSpriteAnimFrameCounter], a + ret + +Func_5274: + ld a, [H_CURRENTSPRITEOFFSET] + add $7 + ld l, a + ld h, wSpriteStateData1 / $100 + ld a, [hl] ; c1x7 (counter until next walk animation frame) inc a + and $3 + ld [hl], a ; c1x7 += 1 + ret nz ; c1x7 = 0 + inc l + ld a, [hl] ; c1x8 (walk animation frame) + 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 + ld a, [H_CURRENTSPRITEOFFSET] + ld l, a + ld [hl], $8 + dec h + inc l + ld [hl], $4 + call UpdateSpriteImage + scf + ret + +.asm_52fa + call Func_5337 + ld a, [H_CURRENTSPRITEOFFSET] + 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 + ld a, [H_CURRENTSPRITEOFFSET] + 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: + ld a, [H_CURRENTSPRITEOFFSET] + add $9 + ld l, a + ld h, wSpriteStateData1 / $100 + ld [hl], c ; c1x9 (update facing direction) + ld a, [H_CURRENTSPRITEOFFSET] + add $3 + ld l, a + ld [hl], d ; c1x3 (update Y movement delta) + inc l + inc l + ld [hl], e ; c1x5 (update X movement delta) + ret + +Func_5349: + ld h, wSpriteStateData2 / $100 + ld a, [H_CURRENTSPRITEOFFSET] + add $4 + ld l, a + ld a, [hl] ; c2x4: Y position + add d + ld [hli], a ; update Y position + ld a, [hl] ; c2x5: X position + add e + ld [hl], a ; update X position + ret + +Func_5357: + call Func_5274 + ld a, [H_CURRENTSPRITEOFFSET] + add $3 + ld l, a + ld h, wSpriteStateData1 / $100 + 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 - cp 4 + ld a, [H_CURRENTSPRITEOFFSET] + ld l, a + ld h, wSpriteStateData2 / $100 + dec [hl] ret nz + ld a, $6 + add l + ld l, a + ld a, [hl] + cp $fe + jr nc, .asm_5386 + ld a, [H_CURRENTSPRITEOFFSET] + inc a + ld l, a + ld h, wSpriteStateData1 / $100 + ld [hl], $1 + ret +.asm_5386 + call Random + ld a, [H_CURRENTSPRITEOFFSET] + add $8 + ld l, a + ld h, wSpriteStateData2 / $100 + ld a, [hRandomAdd] + and $7f + ld [hl], a + dec h + ld a, [H_CURRENTSPRITEOFFSET] + inc a + ld l, a + ld [hl], $2 + inc l + inc l xor a - ld [hl], a ; reset intra-animation frame counter + ld b, [hl] + ld [hli], a inc l - ld a, [hl] ; animation frame counter - inc a - and $3 + ld c, [hl] ld [hl], a - ld [hSpriteAnimFrameCounter], a ret diff --git a/engine/overworld/npc_movement.asm b/engine/overworld/npc_movement.asm index 968615f0..670cb121 100755 --- a/engine/overworld/npc_movement.asm +++ b/engine/overworld/npc_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, $05 + db NPC_MOVEMENT_DOWN, $06 ; differs from red db NPC_MOVEMENT_LEFT, $01 db NPC_MOVEMENT_DOWN, $05 db NPC_MOVEMENT_RIGHT, $03 @@ -141,7 +146,7 @@ RLEList_PlayerWalkToLab: db D_RIGHT, $03 db D_DOWN, $05 db D_LEFT, $01 - db D_DOWN, $06 + db D_DOWN, $07 ; differs from red db $FF 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, $03 db $FF -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 $ff - 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 - jp SetSpriteMovementBytesToFF - -RivalIDs: - db OPP_SONY1 - db OPP_SONY2 - db OPP_SONY3 - db $ff +INCLUDE "engine/overworld/pewter_guys.asm" diff --git a/engine/overworld/npc_movement_2.asm b/engine/overworld/npc_movement_2.asm new file mode 100755 index 00000000..93d1afce --- /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 $ff + 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 + jp SetSpriteMovementBytesToFF + +RivalIDs: + db OPP_SONY1 + db OPP_SONY2 + db OPP_SONY3 + db $ff diff --git a/engine/overworld/oam.asm b/engine/overworld/oam.asm index 2c2a3dff..5a831327 100644 --- a/engine/overworld/oam.asm +++ b/engine/overworld/oam.asm @@ -1,6 +1,8 @@ PrepareOAMData: ; Determine OAM data for currently visible ; sprites and write it to wOAMBuffer. +; Yellow code has been changed to use registers more efficiently +; as well as tweaking the code to show gbc palettes ld a, [wUpdateSpritesEnabled] dec a @@ -18,9 +20,9 @@ PrepareOAMData: .spriteLoop ld [hSpriteOffset2], a - ld d, wSpriteStateData1 / $100 - ld a, [hSpriteOffset2] ld e, a + ld d, wSpriteStateData1 / $100 + ld a, [de] ; c1x0 and a jp z, .nextSprite @@ -40,16 +42,22 @@ PrepareOAMData: jr c, .usefacing ; unchanging - and $f - add $10 ; skip to the second half of the table which doesn't account for facing direction + ld a, $0 jr .next .usefacing and $f .next +; read the entry from the table + ld c, a + ld b, 0 + ld hl, SpriteFacingAndAnimationTable + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] ld l, a - ; get sprite priority push de inc d @@ -61,65 +69,46 @@ PrepareOAMData: 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] + add [hl] + cp $a0 + jr z, .hidden + jr nc, .asm_4a41 +.hidden + call Func_4a7b + ld [wd5cd], a + ld a, [hOAMBufferOffset] + ld e, a ld d, wOAMBuffer / $100 .tileLoop + ld a, [hli] + ld c, a +.loop 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 + inc e 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 + ld [de], a + inc hl 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 a, [wd5cd] + add [hl] + cp $80 + jr c, .asm_4a1c 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 a, [$fffc] + add b +.asm_4a1c ld [de], a ; tile id inc hl inc e @@ -129,15 +118,19 @@ PrepareOAMData: ld a, [hSpritePriority] or [hl] .skipPriority - inc hl + and $f0 + bit 4, a ; OBP0 or OBP1 + jr z, .spriteusesOBP0 + or %100 ; palettes 4-7 are OBP1 +.spriteusesOBP0 ld [de], a + inc hl inc e - bit 0, a ; OAMFLAG_ENDOFDATA - jr z, .tileLoop + dec c + jr nz, .loop ld a, e ld [hOAMBufferOffset], a - .nextSprite ld a, [hSpriteOffset2] add $10 @@ -145,26 +138,31 @@ PrepareOAMData: jp nz, .spriteLoop ; Clear unused OAM. - ld a, [hOAMBufferOffset] - ld l, a - ld h, wOAMBuffer / $100 - ld de, $4 - ld b, $a0 +.asm_4a41 ld a, [wd736] bit 6, a ; jumping down ledge or fishing animation? - ld a, $a0 + ld c, $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 + ld c, $90 .clear - cp l - ret z + ld a, [hOAMBufferOffset] + cp c + ret nc + ld l, a + ld h, wOAMBuffer / $100 + ld a, c + ld de, $4 ; entry size + ld b, $a0 +.clearLoop ld [hl], b add hl, de - jr .clear + cp l + jr nz, .clearLoop + ret GetSpriteScreenXY: inc e @@ -187,3 +185,48 @@ GetSpriteScreenXY: and $f0 ld [de], a ; c1xb (x) ret + +Func_4a7b: + push bc + 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 ; $7c + jr .done + +.notFourTileSprite + ; a *= 12 + add a + add a + ld c, a + add a + add c +.done + pop bc + ret + +INCLUDE "engine/oam_dma.asm" + +_IsTilePassable:: + ld hl,wTilesetCollisionPtr ; pointer to list of passable tiles + ld a,[hli] + ld h,[hl] + ld l,a ; hl now points to passable tiles +.loop + ld a,[hli] + cp a,$ff + jr z,.tileNotPassable + cp c + jr nz,.loop + xor a + ret +.tileNotPassable + scf + ret + +INCLUDE "data/collision.asm" ; probably diff --git a/engine/overworld/player_animations.asm b/engine/overworld/player_animations.asm index a17e67bd..d4ecec53 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), $0c call CopyVideoData ld de, BirdSprite + $c0 ; moving animation sprite + ld b, BANK(BirdSprite) + ld c, $0c ld hl, vNPCSprites2 - lb bc, BANK(BirdSprite), $0c jp CopyVideoData InitFacingDirectionList: @@ -386,9 +393,10 @@ FishingAnim: call DelayFrames ld hl, wd736 set 6, [hl] ; reserve the last 4 OAM entries - ld de, RedSprite ld hl, vNPCSprites - lb bc, BANK(RedSprite), $c + ld de, RedSprite + ld b, BANK(RedSprite) + ld c, $c call CopyVideoData ld a, $4 ld hl, RedFishingTiles diff --git a/engine/overworld/player_state.asm b/engine/overworld/player_state.asm index 73c55da2..8cbacc61 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/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 @@ -240,8 +242,7 @@ PrintSafariZoneSteps: cp CERULEAN_CAVE_2F ret nc coord hl, 0, 0 - ld b, 3 - ld c, 7 + lb bc, 3, 7 call TextBoxBorder coord hl, 1, 1 ld de, wSafariSteps @@ -255,11 +256,11 @@ PrintSafariZoneSteps: call PlaceString ld a, [wNumSafariBalls] cp 10 - jr nc, .asm_c56d + jr nc, .numSafariBallsTwoDigits coord hl, 5, 3 ld a, " " ld [hl], a -.asm_c56d +.numSafariBallsTwoDigits coord hl, 6, 3 ld de, wNumSafariBalls lb bc, 1, 2 @@ -361,16 +362,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/poison.asm b/engine/overworld/poison.asm index 5d8eb9fd..03fb8a65 100644 --- a/engine/overworld/poison.asm +++ b/engine/overworld/poison.asm @@ -2,13 +2,20 @@ ApplyOutOfBattlePoisonDamage: ld a, [wd730] add a jp c, .noBlackOut ; no black out if joypad states are being simulated + ld a, [wd492] + bit 7, a + jp nz, .noBlackOut + ld a, [wd72e] + bit 6, a + jp nz, .noBlackOut ld a, [wPartyCount] and a jp z, .noBlackOut call IncrementDayCareMonExp + call Func_c4c7 ld a, [wStepCounter] and $3 ; is the counter a multiple of 4? - jp nz, .noBlackOut ; only apply poison damage every fourth step + jp nz, .skipPoisonEffectAndSound ; only apply poison damage every fourth step ld [wWhichPokemon], a ld hl, wPartyMon1Status ld de, wPartySpecies @@ -54,6 +61,12 @@ ApplyOutOfBattlePoisonDamage: ld a, TEXT_MON_FAINTED ld [hSpriteIndexOrTextID], a call DisplayTextID + callab IsThisPartymonStarterPikachu_Party + jr nc, .curMonNotPlayerPikachu + ld e, $3 + callab PlayPikachuSoundClip + calladb_ModifyPikachuHappiness PIKAHAPPY_PSNFNT +.curMonNotPlayerPikachu pop de pop hl .nextMon @@ -110,3 +123,29 @@ ApplyOutOfBattlePoisonDamage: .done ld [wOutOfBattleBlackout], a ret + +Func_c4c7: + ld a, [wStepCounter] + and a + jr nz, .asm_c4de + call Random + and $1 + jr z, .asm_c4de + calladb_ModifyPikachuHappiness $6 +.asm_c4de + ld hl, wPikachuMood + ld a, [hl] + cp $80 + jr z, .asm_c4ef + jr c, .asm_c4ea + dec a + dec a +.asm_c4ea + inc a + ld [hl], a + cp $80 + ret nz +.asm_c4ef + xor a + ld [wd49c], a + ret diff --git a/engine/overworld/pokecenter.asm b/engine/overworld/pokecenter.asm index f26bedf8..cf0159f9 100755 --- a/engine/overworld/pokecenter.asm +++ b/engine/overworld/pokecenter.asm @@ -1,4 +1,13 @@ DisplayPokemonCenterDialogue_: + ld a, [wCurMap] + cp PEWTER_POKECENTER + jr nz, .regularCenter + call CheckPikachuFollowingPlayer + jr z, .regularCenter + ld hl, LooksContentText ; if pikachu is sleeping, don't heal + call PrintText + ret +.regularCenter call SaveScreenTilesToBuffer1 ; save screen ld hl, PokemonCenterWelcomeText call PrintText @@ -11,18 +20,36 @@ DisplayPokemonCenterDialogue_: call PrintText .skipShallWeHealYourPokemon call YesNoChoicePokeCenter ; yes/no menu + call UpdateSprites ld a, [wCurrentMenuItem] and a - jr nz, .declinedHealing ; if the player chose No + jp nz, .declinedHealing ; if the player chose No call SetLastBlackoutMap - call LoadScreenTilesFromBuffer1 ; restore screen + callab IsStarterPikachuInOurParty + jr nc, .notHealingPlayerPikachu + call CheckPikachuFollowingPlayer + jr nz, .notHealingPlayerPikachu + call LoadCurrentMapView + call Delay3 + call UpdateSprites + callab PikachuWalksToNurseJoy ; todo +.notHealingPlayerPikachu ld hl, NeedYourPokemonText call PrintText - ld a, $18 - ld [wSpriteStateData1 + $12], a ; make the nurse turn to face the machine - call Delay3 - predef HealParty + ld c, 64 + call DelayFrames + call CheckPikachuFollowingPlayer + jr nz, .playerPikachuNotOnScreen + call DisablePikachuOverworldSpriteDrawing + callab IsStarterPikachuInOurParty + call c, Func_6eaa +.playerPikachuNotOnScreen + lb bc, 1, 8 + call Func_6ebb + ld c, 30 + call DelayFrames callba AnimateHealingMachine ; do the healing machine animation + predef HealParty xor a ld [wAudioFadeOutControl], a ld a, [wAudioSavedROMBank] @@ -31,19 +58,69 @@ DisplayPokemonCenterDialogue_: ld [wLastMusicSoundID], a ld [wNewSoundID], a call PlaySound + call CheckPikachuFollowingPlayer + jr nz, .doNotReturnPikachu + callab IsStarterPikachuInOurParty + call c, Func_6eaa + ld a, $5 + ld [wPikachuSpawnState], a + call EnablePikachuOverworldSpriteDrawing +.doNotReturnPikachu + lb bc, 1, 0 + call Func_6ebb ld hl, PokemonFightingFitText call PrintText - ld a, $14 - ld [wSpriteStateData1 + $12], a ; make the nurse bow - ld c, a + callab IsStarterPikachuInOurParty + jr nc, .notInParty + lb bc, 15, 0 + call Func_6ebb +.notInParty + call LoadCurrentMapView + call Delay3 + call UpdateSprites + callab ReloadWalkingTilePatterns + ld a, $1 + ld [H_SPRITEINDEX], a + ld a, $1 + ld [hSpriteImageIndex], a + call SpriteFunc_34a1 + ld c, 40 call DelayFrames + call UpdateSprites + call LoadFontTilePatterns jr .done .declinedHealing call LoadScreenTilesFromBuffer1 ; restore screen .done ld hl, PokemonCenterFarewellText call PrintText - jp UpdateSprites + call UpdateSprites + ret + +Func_6eaa: + ld a, $1 + ld [H_SPRITEINDEX], a + ld a, $4 + ld [hSpriteImageIndex], a + call SpriteFunc_34a1 + ld c, 64 + call DelayFrames + ret + +Func_6ebb: + ld a, b + ld [H_SPRITEINDEX], a + ld a, c + ld [hSpriteImageIndex], a + push bc + call SetSpriteFacingDirectionAndDelay + pop bc + ld a, b + ld [H_SPRITEINDEX], a + ld a, c + ld [hSpriteImageIndex], a + call SpriteFunc_34a1 + ret PokemonCenterWelcomeText: TX_FAR _PokemonCenterWelcomeText @@ -66,3 +143,7 @@ PokemonCenterFarewellText: TX_DELAY TX_FAR _PokemonCenterFarewellText db "@" + +LooksContentText: + TX_FAR _LooksContentText + db "@" diff --git a/engine/overworld/push_boulder.asm b/engine/overworld/push_boulder.asm index c91605a8..8a385345 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 @@ -36,7 +38,7 @@ TryPushingBoulder: jp nz, ResetBoulderPushFlags ld a, [hJoyHeld] ld b, a - ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction + ld a, [wSpritePlayerStateData1FacingDirection] ; player's sprite facing direction cp SPRITE_FACING_UP jr z, .pushBoulderUp cp SPRITE_FACING_LEFT diff --git a/engine/overworld/ssanne.asm b/engine/overworld/ssanne.asm index ea4747ce..cf3b1284 100755 --- a/engine/overworld/ssanne.asm +++ b/engine/overworld/ssanne.asm @@ -7,6 +7,7 @@ AnimateBoulderDust: ld [wUpdateSpritesEnabled], a ld a, %11100100 ld [rOBP1], a + call UpdateGBCPal_OBP1 call LoadSmokeTileFourTimes callba WriteCutOrBoulderDustAnimationOAMBlock ld c, 8 ; number of steps in animation @@ -21,6 +22,7 @@ AnimateBoulderDust: ld a, [rOBP1] xor %01100100 ld [rOBP1], a + call UpdateGBCPal_OBP1 call Delay3 pop bc dec c @@ -30,7 +32,7 @@ AnimateBoulderDust: jp LoadPlayerSpriteGraphics GetMoveBoulderDustFunctionPointer: - ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction + ld a, [wSpritePlayerStateData1FacingDirection] ; player's sprite facing direction ld hl, MoveBoulderDustFunctionPointerTable ld c, a ld b, $0 diff --git a/engine/overworld/tileset_header.asm b/engine/overworld/tileset_header.asm index 6e33974f..05061651 100644 --- a/engine/overworld/tileset_header.asm +++ b/engine/overworld/tileset_header.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] ld [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 ld a, [hPreviousTileset] cp b jr z, .done -.asm_c797 +.notDungeonTileset ld a, [wDestinationWarpID] cp $ff jr z, .done |