/engine/battle/animations.asm
Assembly | 2453 lines | 2146 code | 161 blank | 146 comment | 0 complexity | bc4c6b8a4abd0b99fd2859a010ddf5b9 MD5 | raw file
- ; Draws a "frame block". Frame blocks are blocks of tiles that are put
- ; together to form frames in battle animations.
- DrawFrameBlock:
- ld l,c
- ld h,b
- ld a,[hli]
- ld [wNumFBTiles],a
- ld a,[wFBDestAddr + 1]
- ld e,a
- ld a,[wFBDestAddr]
- ld d,a
- xor a
- ld [wFBTileCounter],a ; loop counter
- .loop
- ld a,[wFBTileCounter]
- inc a
- ld [wFBTileCounter],a
- ld a,[wSubAnimTransform]
- dec a
- jr z,.flipHorizontalAndVertical ; 1
- dec a
- jp z,.flipHorizontalTranslateDown ; 2
- dec a
- jr z,.flipBaseCoords ; 3
- .noTransformation
- ld a,[wBaseCoordY]
- add [hl]
- ld [de],a ; store Y
- inc hl
- inc de
- ld a,[wBaseCoordX]
- jr .finishCopying
- .flipBaseCoords
- ld a,[wBaseCoordY]
- ld b,a
- ld a,136
- sub b ; flip Y base coordinate
- add [hl] ; Y offset
- ld [de],a ; store Y
- inc hl
- inc de
- ld a,[wBaseCoordX]
- ld b,a
- ld a,168
- sub b ; flip X base coordinate
- .finishCopying ; finish copying values to OAM (when [wSubAnimTransform] not 1 or 2)
- add [hl] ; X offset
- ld [de],a ; store X
- inc hl
- inc de
- ld a,[hli]
- add a,$31 ; base tile ID for battle animations
- ld [de],a ; store tile ID
- inc de
- ld a,[hli]
- ld [de],a ; store flags
- inc de
- jp .nextTile
- .flipHorizontalAndVertical
- ld a,[wBaseCoordY]
- add [hl] ; Y offset
- ld b,a
- ld a,136
- sub b ; flip Y coordinate
- ld [de],a ; store Y
- inc hl
- inc de
- ld a,[wBaseCoordX]
- add [hl] ; X offset
- ld b,a
- ld a,168
- sub b ; flip X coordinate
- ld [de],a ; store X
- inc hl
- inc de
- ld a,[hli]
- add a,$31 ; base tile ID for battle animations
- ld [de],a ; store tile ID
- inc de
- ; toggle horizontal and vertical flip
- ld a,[hli] ; flags
- and a
- ld b,OAM_VFLIP | OAM_HFLIP
- jr z,.storeFlags1
- cp a,OAM_HFLIP
- ld b,OAM_VFLIP
- jr z,.storeFlags1
- cp a,OAM_VFLIP
- ld b,OAM_HFLIP
- jr z,.storeFlags1
- ld b,0
- .storeFlags1
- ld a,b
- ld [de],a
- inc de
- jp .nextTile
- .flipHorizontalTranslateDown
- ld a,[wBaseCoordY]
- add [hl]
- add a,40 ; translate Y coordinate downwards
- ld [de],a ; store Y
- inc hl
- inc de
- ld a,[wBaseCoordX]
- add [hl]
- ld b,a
- ld a,168
- sub b ; flip X coordinate
- ld [de],a ; store X
- inc hl
- inc de
- ld a,[hli]
- add a,$31 ; base tile ID for battle animations
- ld [de],a ; store tile ID
- inc de
- ld a,[hli]
- bit 5,a ; is horizontal flip enabled?
- jr nz,.disableHorizontalFlip
- .enableHorizontalFlip
- set 5,a
- jr .storeFlags2
- .disableHorizontalFlip
- res 5,a
- .storeFlags2
- ld [de],a
- inc de
- .nextTile
- ld a,[wFBTileCounter]
- ld c,a
- ld a,[wNumFBTiles]
- cp c
- jp nz,.loop ; go back up if there are more tiles to draw
- .afterDrawingTiles
- ld a,[wFBMode]
- cp a,2
- jr z,.advanceFrameBlockDestAddr; skip delay and don't clean OAM buffer
- ld a,[wSubAnimFrameDelay]
- ld c,a
- call DelayFrames
- ld a,[wFBMode]
- cp a,3
- jr z,.advanceFrameBlockDestAddr ; skip cleaning OAM buffer
- cp a,4
- jr z,.done ; skip cleaning OAM buffer and don't advance the frame block destination address
- ld a,[wAnimationID]
- cp a,GROWL
- jr z,.resetFrameBlockDestAddr
- call AnimationCleanOAM
- .resetFrameBlockDestAddr
- ld hl,wOAMBuffer ; OAM buffer
- ld a,l
- ld [wFBDestAddr + 1],a
- ld a,h
- ld [wFBDestAddr],a ; set destination address to beginning of OAM buffer
- ret
- .advanceFrameBlockDestAddr
- ld a,e
- ld [wFBDestAddr + 1],a
- ld a,d
- ld [wFBDestAddr],a
- .done
- ret
- PlayAnimation:
- xor a
- ld [$FF8B],a ; it looks like nothing reads this
- ld [wSubAnimTransform],a
- ld a,[wAnimationID] ; get animation number
- dec a
- ld l,a
- ld h,0
- add hl,hl
- ld de,AttackAnimationPointers ; animation command stream pointers
- add hl,de
- ld a,[hli]
- ld h,[hl]
- ld l,a
- .animationLoop
- ld a,[hli]
- cp a,$FF
- jr z,.AnimationOver
- cp a,$C0 ; is this subanimation or a special effect?
- jr c,.playSubanimation
- .doSpecialEffect
- ld c,a
- ld de,SpecialEffectPointers
- .searchSpecialEffectTableLoop
- ld a,[de]
- cp c
- jr z,.foundMatch
- inc de
- inc de
- inc de
- jr .searchSpecialEffectTableLoop
- .foundMatch
- ld a,[hli]
- cp a,$FF ; is there a sound to play?
- jr z,.skipPlayingSound
- ld [wAnimSoundID],a ; store sound
- push hl
- push de
- call GetMoveSound
- call PlaySound
- pop de
- pop hl
- .skipPlayingSound
- push hl
- inc de
- ld a,[de]
- ld l,a
- inc de
- ld a,[de]
- ld h,a
- ld de,.nextAnimationCommand
- push de
- jp [hl] ; jump to special effect function
- .playSubanimation
- ld c,a
- and a,%00111111
- ld [wSubAnimFrameDelay],a
- xor a
- sla c
- rla
- sla c
- rla
- ld [wWhichBattleAnimTileset],a
- ld a,[hli] ; sound
- ld [wAnimSoundID],a ; store sound
- ld a,[hli] ; subanimation ID
- ld c,l
- ld b,h
- ld l,a
- ld h,0
- add hl,hl
- ld de,SubanimationPointers
- add hl,de
- ld a,l
- ld [wSubAnimAddrPtr],a
- ld a,h
- ld [wSubAnimAddrPtr + 1],a
- ld l,c
- ld h,b
- push hl
- ld a,[rOBP0]
- push af
- ld a,[wAnimPalette]
- ld [rOBP0],a
- call LoadAnimationTileset
- call LoadSubanimation
- call PlaySubanimation
- pop af
- ld [rOBP0],a
- .nextAnimationCommand
- pop hl
- jr .animationLoop
- .AnimationOver
- ret
- LoadSubanimation:
- ld a,[wSubAnimAddrPtr + 1]
- ld h,a
- ld a,[wSubAnimAddrPtr]
- ld l,a
- ld a,[hli]
- ld e,a
- ld a,[hl]
- ld d,a ; de = address of subanimation
- ld a,[de]
- ld b,a
- and a,31
- ld [wSubAnimCounter],a ; number of frame blocks
- ld a,b
- and a,%11100000
- cp a,5 << 5 ; is subanimation type 5?
- jr nz,.isNotType5
- .isType5
- call GetSubanimationTransform2
- jr .saveTransformation
- .isNotType5
- call GetSubanimationTransform1
- .saveTransformation
- ; place the upper 3 bits of a into bits 0-2 of a before storing
- srl a
- swap a
- ld [wSubAnimTransform],a
- cp a,4 ; is the animation reversed?
- ld hl,0
- jr nz,.storeSubentryAddr
- ; if the animation is reversed, then place the initial subentry address at the end of the list of subentries
- ld a,[wSubAnimCounter]
- dec a
- ld bc,3
- .loop
- add hl,bc
- dec a
- jr nz,.loop
- .storeSubentryAddr
- inc de
- add hl,de
- ld a,l
- ld [wSubAnimSubEntryAddr],a
- ld a,h
- ld [wSubAnimSubEntryAddr + 1],a
- ret
- ; called if the subanimation type is not 5
- ; sets the transform to 0 (i.e. no transform) if it's the player's turn
- ; sets the transform to the subanimation type if it's the enemy's turn
- GetSubanimationTransform1:
- ld b,a
- ld a,[H_WHOSETURN]
- and a
- ld a,b
- ret nz
- xor a
- ret
- ; called if the subanimation type is 5
- ; sets the transform to 2 (i.e. horizontal and vertical flip) if it's the player's turn
- ; sets the transform to 0 (i.e. no transform) if it's the enemy's turn
- GetSubanimationTransform2:
- ld a,[H_WHOSETURN]
- and a
- ld a,2 << 5
- ret z
- xor a
- ret
- ; loads tile patterns for battle animations
- LoadAnimationTileset:
- ld a,[wWhichBattleAnimTileset]
- add a
- add a
- ld hl,AnimationTilesetPointers
- ld e,a
- ld d,0
- add hl,de
- ld a,[hli]
- ld [wTempTilesetNumTiles],a ; number of tiles
- ld a,[hli]
- ld e,a
- ld a,[hl]
- ld d,a ; de = address of tileset
- ld hl,vSprites + $310
- ld b, BANK(AnimationTileset1) ; ROM bank
- ld a,[wTempTilesetNumTiles]
- ld c,a ; number of tiles
- jp CopyVideoData ; load tileset
- AnimationTilesetPointers:
- db 79 ; number of tiles
- dw AnimationTileset1
- db $FF
- db 79 ; number of tiles
- dw AnimationTileset2
- db $FF
- db 64 ; number of tiles
- dw AnimationTileset1
- db $FF
- AnimationTileset1:
- INCBIN "gfx/attack_anim_1.2bpp"
- AnimationTileset2:
- INCBIN "gfx/attack_anim_2.2bpp"
- SlotMachineTiles2:
- IF DEF(_RED)
- INCBIN "gfx/red/slotmachine2.2bpp"
- ENDC
- IF DEF(_BLUE)
- INCBIN "gfx/blue/slotmachine2.2bpp"
- ENDC
- MoveAnimation:
- push hl
- push de
- push bc
- push af
- call WaitForSoundToFinish
- call SetAnimationPalette
- ld a,[wAnimationID]
- and a
- jr z, .animationFinished
- ; if throwing a Poké Ball, skip the regular animation code
- cp a,TOSS_ANIM
- jr nz, .moveAnimation
- ld de, .animationFinished
- push de
- jp TossBallAnimation
- .moveAnimation
- ; check if battle animations are disabled in the options
- ld a,[wOptions]
- bit 7,a
- jr nz, .animationsDisabled
- call ShareMoveAnimations
- call PlayAnimation
- jr .next4
- .animationsDisabled
- ld c,30
- call DelayFrames
- .next4
- call PlayApplyingAttackAnimation ; shake the screen or flash the pic in and out (to show damage)
- .animationFinished
- call WaitForSoundToFinish
- xor a
- ld [wSubAnimSubEntryAddr],a
- ld [wUnusedD09B],a
- ld [wSubAnimTransform],a
- dec a
- ld [wAnimSoundID],a
- pop af
- pop bc
- pop de
- pop hl
- ret
- ShareMoveAnimations:
- ; some moves just reuse animations from status conditions
- ld a,[H_WHOSETURN]
- and a
- ret z
- ; opponent’s turn
- ld a,[wAnimationID]
- cp a,AMNESIA
- ld b,CONF_ANIM
- jr z, .replaceAnim
- cp a,REST
- ld b,SLP_ANIM
- ret nz
- .replaceAnim
- ld a,b
- ld [wAnimationID],a
- ret
- PlayApplyingAttackAnimation:
- ; Generic animation that shows after the move's individual animation
- ; Different animation depending on whether the move has an additional effect and on whose turn it is
- ld a,[wAnimationType]
- and a
- ret z
- dec a
- add a
- ld c,a
- ld b,0
- ld hl,AnimationTypePointerTable
- add hl,bc
- ld a,[hli]
- ld h,[hl]
- ld l,a
- jp [hl]
- AnimationTypePointerTable:
- dw ShakeScreenVertically ; enemy mon has used a damaging move without a side effect
- dw ShakeScreenHorizontallyHeavy ; enemy mon has used a damaging move with a side effect
- dw ShakeScreenHorizontallySlow ; enemy mon has used a non-damaging move
- dw BlinkEnemyMonSprite ; player mon has used a damaging move without a side effect
- dw ShakeScreenHorizontallyLight ; player mon has used a damaging move with a side effect
- dw ShakeScreenHorizontallySlow2 ; player mon has used a non-damaging move
- ShakeScreenVertically:
- call PlayApplyingAttackSound
- ld b, 8
- jp AnimationShakeScreenVertically
- ShakeScreenHorizontallyHeavy:
- call PlayApplyingAttackSound
- ld b, 8
- jp AnimationShakeScreenHorizontallyFast
- ShakeScreenHorizontallySlow:
- lb bc, 6, 2
- jr AnimationShakeScreenHorizontallySlow
- BlinkEnemyMonSprite:
- call PlayApplyingAttackSound
- jp AnimationBlinkEnemyMon
- ShakeScreenHorizontallyLight:
- call PlayApplyingAttackSound
- ld b, 2
- jp AnimationShakeScreenHorizontallyFast
- ShakeScreenHorizontallySlow2:
- lb bc, 3, 2
- AnimationShakeScreenHorizontallySlow:
- push bc
- push bc
- .loop1
- ld a, [rWX]
- inc a
- ld [rWX], a
- ld c, 2
- call DelayFrames
- dec b
- jr nz, .loop1
- pop bc
- .loop2
- ld a, [rWX]
- dec a
- ld [rWX], a
- ld c, 2
- call DelayFrames
- dec b
- jr nz, .loop2
- pop bc
- dec c
- jr nz, AnimationShakeScreenHorizontallySlow
- ret
- SetAnimationPalette:
- ld a, [wOnSGB]
- and a
- ld a, $e4
- jr z, .notSGB
- ld a, $f0
- ld [wAnimPalette], a
- ld b, $e4
- ld a, [wAnimationID]
- cp TRADE_BALL_DROP_ANIM
- jr c, .next
- cp TRADE_BALL_POOF_ANIM + 1
- jr nc, .next
- ld b, $f0
- .next
- ld a, b
- ld [rOBP0], a
- ld a, $6c
- ld [rOBP1], a
- ret
- .notSGB
- ld a, $e4
- ld [wAnimPalette], a
- ld [rOBP0], a
- ld a, $6c
- ld [rOBP1], a
- ret
- PlaySubanimation:
- ld a,[wAnimSoundID]
- cp a,$FF
- jr z,.skipPlayingSound
- call GetMoveSound
- call PlaySound
- .skipPlayingSound
- ld hl,wOAMBuffer ; base address of OAM buffer
- ld a,l
- ld [wFBDestAddr + 1],a
- ld a,h
- ld [wFBDestAddr],a
- ld a,[wSubAnimSubEntryAddr + 1]
- ld h,a
- ld a,[wSubAnimSubEntryAddr]
- ld l,a
- .loop
- push hl
- ld c,[hl] ; frame block ID
- ld b,0
- ld hl,FrameBlockPointers
- add hl,bc
- add hl,bc
- ld a,[hli]
- ld c,a
- ld a,[hli]
- ld b,a
- pop hl
- inc hl
- push hl
- ld e,[hl] ; base coordinate ID
- ld d,0
- ld hl,FrameBlockBaseCoords ; base coordinate table
- add hl,de
- add hl,de
- ld a,[hli]
- ld [wBaseCoordY],a
- ld a,[hl]
- ld [wBaseCoordX],a
- pop hl
- inc hl
- ld a,[hl] ; frame block mode
- ld [wFBMode],a
- call DrawFrameBlock
- call DoSpecialEffectByAnimationId ; run animation-specific function (if there is one)
- ld a,[wSubAnimCounter]
- dec a
- ld [wSubAnimCounter],a
- ret z
- ld a,[wSubAnimSubEntryAddr + 1]
- ld h,a
- ld a,[wSubAnimSubEntryAddr]
- ld l,a
- ld a,[wSubAnimTransform]
- cp a,4 ; is the animation reversed?
- ld bc,3
- jr nz,.nextSubanimationSubentry
- ld bc,-3
- .nextSubanimationSubentry
- add hl,bc
- ld a,h
- ld [wSubAnimSubEntryAddr + 1],a
- ld a,l
- ld [wSubAnimSubEntryAddr],a
- jp .loop
- AnimationCleanOAM:
- push hl
- push de
- push bc
- push af
- call DelayFrame
- call ClearSprites
- pop af
- pop bc
- pop de
- pop hl
- ret
- ; this runs after each frame block is drawn in a subanimation
- ; it runs a particular special effect based on the animation ID
- DoSpecialEffectByAnimationId:
- push hl
- push de
- push bc
- ld a,[wAnimationID]
- ld hl,AnimationIdSpecialEffects
- ld de,3
- call IsInArray
- jr nc,.done
- inc hl
- ld a,[hli]
- ld h,[hl]
- ld l,a
- ld de,.done
- push de
- jp [hl]
- .done
- pop bc
- pop de
- pop hl
- ret
- ; Format: Animation ID (1 byte), Address (2 bytes)
- AnimationIdSpecialEffects:
- db MEGA_PUNCH
- dw AnimationFlashScreen
- db GUILLOTINE
- dw AnimationFlashScreen
- db MEGA_KICK
- dw AnimationFlashScreen
- db HEADBUTT
- dw AnimationFlashScreen
- db TAIL_WHIP
- dw TailWhipAnimationUnused
- db GROWL
- dw DoGrowlSpecialEffects
- db DISABLE
- dw AnimationFlashScreen
- db BLIZZARD
- dw DoBlizzardSpecialEffects
- db BUBBLEBEAM
- dw AnimationFlashScreen
- db HYPER_BEAM
- dw FlashScreenEveryFourFrameBlocks
- db THUNDERBOLT
- dw FlashScreenEveryEightFrameBlocks
- db REFLECT
- dw AnimationFlashScreen
- db SELFDESTRUCT
- dw DoExplodeSpecialEffects
- db SPORE
- dw AnimationFlashScreen
- db EXPLOSION
- dw DoExplodeSpecialEffects
- db ROCK_SLIDE
- dw DoRockSlideSpecialEffects
- db TRADE_BALL_DROP_ANIM
- dw TradeHidePokemon
- db TRADE_BALL_SHAKE_ANIM
- dw TradeShakePokeball
- db TRADE_BALL_TILT_ANIM
- dw TradeJumpPokeball
- db TOSS_ANIM
- dw DoBallTossSpecialEffects
- db SHAKE_ANIM
- dw DoBallShakeSpecialEffects
- db POOF_ANIM
- dw DoPoofSpecialEffects
- db GREATTOSS_ANIM
- dw DoBallTossSpecialEffects
- db ULTRATOSS_ANIM
- dw DoBallTossSpecialEffects
- db $FF ; terminator
- DoBallTossSpecialEffects:
- ld a,[wcf91]
- cp a,3 ; is it a Master Ball or Ultra Ball?
- jr nc,.skipFlashingEffect
- .flashingEffect ; do a flashing effect if it's Master Ball or Ultra Ball
- ld a,[rOBP0]
- xor a,%00111100 ; complement colors 1 and 2
- ld [rOBP0],a
- .skipFlashingEffect
- ld a,[wSubAnimCounter]
- cp a,11 ; is it the beginning of the subanimation?
- jr nz,.skipPlayingSound
- ; if it is the beginning of the subanimation, play a sound
- ld a,SFX_BALL_TOSS
- call PlaySound
- .skipPlayingSound
- ld a,[wIsInBattle]
- cp a,02 ; is it a trainer battle?
- jr z,.isTrainerBattle
- ld a,[wd11e]
- cp a,$10 ; is the enemy pokemon the Ghost Marowak?
- ret nz
- ; if the enemy pokemon is the Ghost Marowak, make it dodge during the last 3 frames
- ld a,[wSubAnimCounter]
- cp a,3
- jr z,.moveGhostMarowakLeft
- cp a,2
- jr z,.moveGhostMarowakLeft
- cp a,1
- ret nz
- .moveGhostMarowakLeft
- coord hl, 17, 0
- ld de,20
- lb bc, 7, 7
- .loop
- push hl
- push bc
- call AnimCopyRowRight ; move row of tiles left
- pop bc
- pop hl
- add hl,de
- dec b
- jr nz,.loop
- ld a,%00001000
- ld [rNR10],a ; Channel 1 sweep register
- ret
- .isTrainerBattle ; if it's a trainer battle, shorten the animation by one frame
- ld a,[wSubAnimCounter]
- cp a,3
- ret nz
- dec a
- ld [wSubAnimCounter],a
- ret
- DoBallShakeSpecialEffects:
- ld a,[wSubAnimCounter]
- cp a,4 ; is it the beginning of a shake?
- jr nz,.skipPlayingSound
- ; if it is the beginning of a shake, play a sound and wait 2/3 of a second
- ld a,SFX_TINK
- call PlaySound
- ld c,40
- call DelayFrames
- .skipPlayingSound
- ld a,[wSubAnimCounter]
- dec a
- ret nz
- ; if it's the end of the ball shaking subanimation, check if more shakes are left and restart the subanimation
- ld a,[wNumShakes] ; number of shakes
- dec a ; decrement number of shakes
- ld [wNumShakes],a
- ret z
- ; if there are shakes left, restart the subanimation
- ld a,[wSubAnimSubEntryAddr]
- ld l,a
- ld a,[wSubAnimSubEntryAddr + 1]
- ld h,a
- ld de,-(4 * 3) ; 4 subentries and 3 bytes per subentry
- add hl,de
- ld a,l
- ld [wSubAnimSubEntryAddr],a
- ld a,h
- ld [wSubAnimSubEntryAddr + 1],a
- ld a,5 ; number of subentries in the ball shaking subanimation plus one
- ld [wSubAnimCounter],a
- ret
- ; plays a sound after the second frame of the poof animation
- DoPoofSpecialEffects:
- ld a,[wSubAnimCounter]
- cp a,5
- ret nz
- ld a,SFX_BALL_POOF
- jp PlaySound
- DoRockSlideSpecialEffects:
- ld a,[wSubAnimCounter]
- cp a,12
- ret nc
- cp a,8
- jr nc,.shakeScreen
- cp a,1
- jp z,AnimationFlashScreen ; if it's the end of the subanimation, flash the screen
- ret
- ; if the subaninmation counter is between 8 and 11, shake the screen horizontally and vertically
- .shakeScreen
- ld b,1
- predef PredefShakeScreenHorizontally ; shake horizontally
- ld b,1
- predef_jump PredefShakeScreenVertically ; shake vertically
- FlashScreenEveryEightFrameBlocks:
- ld a,[wSubAnimCounter]
- and a,7 ; is the subanimation counter exactly 8?
- call z,AnimationFlashScreen ; if so, flash the screen
- ret
- ; flashes the screen if the subanimation counter is divisible by 4
- FlashScreenEveryFourFrameBlocks:
- ld a,[wSubAnimCounter]
- and a,3
- call z,AnimationFlashScreen
- ret
- ; used for Explosion and Selfdestruct
- DoExplodeSpecialEffects:
- ld a,[wSubAnimCounter]
- cp a,1 ; is it the end of the subanimation?
- jr nz,FlashScreenEveryFourFrameBlocks
- ; if it's the end of the subanimation, make the attacking pokemon disappear
- coord hl, 1, 5
- jp AnimationHideMonPic ; make pokemon disappear
- ; flashes the screen when subanimation counter is 1 modulo 4
- DoBlizzardSpecialEffects:
- ld a,[wSubAnimCounter]
- cp a,13
- jp z,AnimationFlashScreen
- cp a,9
- jp z,AnimationFlashScreen
- cp a,5
- jp z,AnimationFlashScreen
- cp a,1
- jp z,AnimationFlashScreen
- ret
- ; flashes the screen at 3 points in the subanimation
- ; unused
- FlashScreenUnused:
- ld a,[wSubAnimCounter]
- cp a,14
- jp z,AnimationFlashScreen
- cp a,9
- jp z,AnimationFlashScreen
- cp a,2
- jp z,AnimationFlashScreen
- ret
- ; function to make the pokemon disappear at the beginning of the animation
- TradeHidePokemon:
- ld a,[wSubAnimCounter]
- cp a,6
- ret nz
- ld a,2 * SCREEN_WIDTH + 7
- jp ClearMonPicFromTileMap ; make pokemon disappear
- ; function to make a shaking pokeball jump up at the end of the animation
- TradeShakePokeball:
- ld a,[wSubAnimCounter]
- cp a,1
- ret nz
- ; if it's the end of the animation, make the ball jump up
- ld de,BallMoveDistances1
- .loop
- ld hl,wOAMBuffer ; OAM buffer
- ld bc,4
- .innerLoop
- ld a,[de]
- cp a,$ff
- jr z,.done
- add [hl] ; add to Y value of OAM entry
- ld [hl],a
- add hl,bc
- ld a,l
- cp a,4 * 4 ; there are 4 entries, each 4 bytes
- jr nz,.innerLoop
- inc de
- push bc
- call Delay3
- pop bc
- jr .loop
- .done
- call AnimationCleanOAM
- ld a,SFX_TRADE_MACHINE
- jp PlaySound
- BallMoveDistances1:
- db -12,-12,-8
- db $ff ; terminator
- ; function to make the pokeball jump up
- TradeJumpPokeball:
- ld de,BallMoveDistances2
- .loop
- ld hl,wOAMBuffer ; OAM buffer
- ld bc,4
- .innerLoop
- ld a,[de]
- cp a,$ff
- jp z,ClearScreen
- add [hl]
- ld [hl],a
- add hl,bc
- ld a,l
- cp a,4 * 4 ; there are 4 entries, each 4 bytes
- jr nz,.innerLoop
- inc de
- push de
- ld a,[de]
- cp a,12
- jr z,.playSound
- cp a,$ff
- jr nz,.skipPlayingSound
- .playSound ; play sound if next move distance is 12 or this is the last one
- ld a,SFX_BATTLE_18
- call PlaySound
- .skipPlayingSound
- push bc
- ld c,5
- call DelayFrames
- pop bc
- ld a,[hSCX] ; background scroll X
- sub a,8 ; scroll to the left
- ld [hSCX],a
- pop de
- jr .loop
- BallMoveDistances2:
- db 11,12,-12,-7,7,12,-8,8
- db $ff ; terminator
- ; this function copies the current musical note graphic
- ; so that there are two musical notes flying towards the defending pokemon
- DoGrowlSpecialEffects:
- ld hl,wOAMBuffer ; OAM buffer
- ld de,wOAMBuffer + $10
- ld bc,$10
- call CopyData ; copy the musical note graphic
- ld a,[wSubAnimCounter]
- dec a
- call z,AnimationCleanOAM ; clean up at the end of the subanimation
- ret
- ; this is associated with Tail Whip, but Tail Whip doesn't use any subanimations
- TailWhipAnimationUnused:
- ld a,1
- ld [wSubAnimCounter],a
- ld c,20
- jp DelayFrames
- ; Format: Special Effect ID (1 byte), Address (2 bytes)
- SpecialEffectPointers:
- db SE_DARK_SCREEN_FLASH ; $FE
- dw AnimationFlashScreen
- db SE_DARK_SCREEN_PALETTE ; $FD
- dw AnimationDarkScreenPalette
- db SE_RESET_SCREEN_PALETTE ; $FC
- dw AnimationResetScreenPalette
- db SE_SHAKE_SCREEN ; $FB
- dw AnimationShakeScreen
- db SE_WATER_DROPLETS_EVERYWHERE ; $FA
- dw AnimationWaterDropletsEverywhere
- db SE_DARKEN_MON_PALETTE ; $F9
- dw AnimationDarkenMonPalette
- db SE_FLASH_SCREEN_LONG ; $F8
- dw AnimationFlashScreenLong
- db SE_SLIDE_MON_UP ; $F7
- dw AnimationSlideMonUp
- db SE_SLIDE_MON_DOWN ; $F6
- dw AnimationSlideMonDown
- db SE_FLASH_MON_PIC ; $F5
- dw AnimationFlashMonPic
- db SE_SLIDE_MON_OFF ; $F4
- dw AnimationSlideMonOff
- db SE_BLINK_MON ; $F3
- dw AnimationBlinkMon
- db SE_MOVE_MON_HORIZONTALLY ; $F2
- dw AnimationMoveMonHorizontally
- db SE_RESET_MON_POSITION ; $F1
- dw AnimationResetMonPosition
- db SE_LIGHT_SCREEN_PALETTE ; $F0
- dw AnimationLightScreenPalette
- db SE_HIDE_MON_PIC ; $EF
- dw AnimationHideMonPic
- db SE_SQUISH_MON_PIC ; $EE
- dw AnimationSquishMonPic
- db SE_SHOOT_BALLS_UPWARD ; $ED
- dw AnimationShootBallsUpward
- db SE_SHOOT_MANY_BALLS_UPWARD ; $EC
- dw AnimationShootManyBallsUpward
- db SE_BOUNCE_UP_AND_DOWN ; $EB
- dw AnimationBoundUpAndDown
- db SE_MINIMIZE_MON ; $EA
- dw AnimationMinimizeMon
- db SE_SLIDE_MON_DOWN_AND_HIDE ; $E9
- dw AnimationSlideMonDownAndHide
- db SE_TRANSFORM_MON ; $E8
- dw AnimationTransformMon
- db SE_LEAVES_FALLING ; $E7
- dw AnimationLeavesFalling
- db SE_PETALS_FALLING ; $E6
- dw AnimationPetalsFalling
- db SE_SLIDE_MON_HALF_OFF ; $E5
- dw AnimationSlideMonHalfOff
- db SE_SHAKE_ENEMY_HUD ; $E4
- dw AnimationShakeEnemyHUD
- db SE_SHAKE_ENEMY_HUD_2 ; unused--same pointer as SE_SHAKE_ENEMY_HUD ($E4)
- dw AnimationShakeEnemyHUD
- db SE_SPIRAL_BALLS_INWARD ; $E2
- dw AnimationSpiralBallsInward
- db SE_DELAY_ANIMATION_10 ; $E1
- dw AnimationDelay10
- db SE_FLASH_ENEMY_MON_PIC ; unused--same as SE_FLASH_MON_PIC ($F5), but for the enemy mon
- dw AnimationFlashEnemyMonPic
- db SE_HIDE_ENEMY_MON_PIC ; $DF
- dw AnimationHideEnemyMonPic
- db SE_BLINK_ENEMY_MON ; $DE
- dw AnimationBlinkEnemyMon
- db SE_SHOW_MON_PIC ; $DD
- dw AnimationShowMonPic
- db SE_SHOW_ENEMY_MON_PIC ; $DC
- dw AnimationShowEnemyMonPic
- db SE_SLIDE_ENEMY_MON_OFF ; $DB
- dw AnimationSlideEnemyMonOff
- db SE_SHAKE_BACK_AND_FORTH ; $DA
- dw AnimationShakeBackAndForth
- db SE_SUBSTITUTE_MON ; $D9
- dw AnimationSubstitute
- db SE_WAVY_SCREEN ; $D8
- dw AnimationWavyScreen
- db $FF
- AnimationDelay10:
- ld c,10
- jp DelayFrames
- ; calls a function with the turn flipped from player to enemy or vice versa
- ; input - hl - address of function to call
- CallWithTurnFlipped:
- ld a,[H_WHOSETURN]
- push af
- xor a,1
- ld [H_WHOSETURN],a
- ld de,.returnAddress
- push de
- jp [hl]
- .returnAddress
- pop af
- ld [H_WHOSETURN],a
- ret
- ; flashes the screen for an extended period (48 frames)
- AnimationFlashScreenLong:
- ld a,3 ; cycle through the palettes 3 times
- ld [wFlashScreenLongCounter],a
- ld a,[wOnSGB] ; running on SGB?
- and a
- ld hl,FlashScreenLongMonochrome
- jr z,.loop
- ld hl,FlashScreenLongSGB
- .loop
- push hl
- .innerLoop
- ld a,[hli]
- cp a,$01 ; is it the end of the palettes?
- jr z,.endOfPalettes
- ld [rBGP],a
- call FlashScreenLongDelay
- jr .innerLoop
- .endOfPalettes
- ld a,[wFlashScreenLongCounter]
- dec a
- ld [wFlashScreenLongCounter],a
- pop hl
- jr nz,.loop
- ret
- ; BG palettes
- FlashScreenLongMonochrome:
- db %11111001 ; 3, 3, 2, 1
- db %11111110 ; 3, 3, 3, 2
- db %11111111 ; 3, 3, 3, 3
- db %11111110 ; 3, 3, 3, 2
- db %11111001 ; 3, 3, 2, 1
- db %11100100 ; 3, 2, 1, 0
- db %10010000 ; 2, 1, 0, 0
- db %01000000 ; 1, 0, 0, 0
- db %00000000 ; 0, 0, 0, 0
- db %01000000 ; 1, 0, 0, 0
- db %10010000 ; 2, 1, 0, 0
- db %11100100 ; 3, 2, 1, 0
- db $01 ; terminator
- ; BG palettes
- FlashScreenLongSGB:
- db %11111000 ; 3, 3, 2, 0
- db %11111100 ; 3, 3, 3, 0
- db %11111111 ; 3, 3, 3, 3
- db %11111100 ; 3, 3, 3, 0
- db %11111000 ; 3, 3, 2, 0
- db %11100100 ; 3, 2, 1, 0
- db %10010000 ; 2, 1, 0, 0
- db %01000000 ; 1, 0, 0, 0
- db %00000000 ; 0, 0, 0, 0
- db %01000000 ; 1, 0, 0, 0
- db %10010000 ; 2, 1, 0, 0
- db %11100100 ; 3, 2, 1, 0
- db $01 ; terminator
- ; causes a delay of 2 frames for the first cycle
- ; causes a delay of 1 frame for the second and third cycles
- FlashScreenLongDelay:
- ld a,[wFlashScreenLongCounter]
- cp a,4 ; never true since [wFlashScreenLongCounter] starts at 3
- ld c,4
- jr z,.delayFrames
- cp a,3
- ld c,2
- jr z,.delayFrames
- cp a,2 ; nothing is done with this
- ld c,1
- .delayFrames
- jp DelayFrames
- AnimationFlashScreen:
- ld a,[rBGP]
- push af ; save initial palette
- ld a,%00011011 ; 0, 1, 2, 3 (inverted colors)
- ld [rBGP],a
- ld c,2
- call DelayFrames
- xor a ; white out background
- ld [rBGP],a
- ld c,2
- call DelayFrames
- pop af
- ld [rBGP],a ; restore initial palette
- ret
- AnimationDarkScreenPalette:
- ; Changes the screen's palette to a dark palette.
- lb bc, $6f, $6f
- jr SetAnimationBGPalette
- AnimationDarkenMonPalette:
- ; Darkens the mon sprite's palette.
- lb bc, $f9, $f4
- jr SetAnimationBGPalette
- AnimationUnusedPalette1:
- lb bc, $fe, $f8
- jr SetAnimationBGPalette
- AnimationUnusedPalette2:
- lb bc, $ff, $ff
- jr SetAnimationBGPalette
- AnimationResetScreenPalette:
- ; Restores the screen's palette to the normal palette.
- lb bc, $e4, $e4
- jr SetAnimationBGPalette
- AnimationUnusedPalette3:
- lb bc, $00, $00
- jr SetAnimationBGPalette
- AnimationLightScreenPalette:
- ; Changes the screen to use a palette with light colors.
- lb bc, $90, $90
- jr SetAnimationBGPalette
- AnimationUnusedPalette4:
- lb bc, $40, $40
- SetAnimationBGPalette:
- ld a, [wOnSGB]
- and a
- ld a, b
- jr z, .next
- ld a, c
- .next
- ld [rBGP], a
- ret
- ld b, $5
- AnimationShakeScreenVertically:
- predef_jump PredefShakeScreenVertically
- AnimationShakeScreen:
- ; Shakes the screen for a while. Used in Earthquake/Fissure/etc. animations.
- ld b, $8
- AnimationShakeScreenHorizontallyFast:
- predef_jump PredefShakeScreenHorizontally
- AnimationWaterDropletsEverywhere:
- ; Draws water droplets all over the screen and makes them
- ; scroll. It's hard to describe, but it's the main animation
- ; in Surf/Mist/Toxic.
- xor a
- ld [wWhichBattleAnimTileset], a
- call LoadAnimationTileset
- ld d, 32
- ld a, -16
- ld [wBaseCoordX], a
- ld a, $71
- ld [wDropletTile], a
- .loop
- ld a, 16
- ld [wBaseCoordY], a
- ld a, 0
- ld [wUnusedD08A], a
- call _AnimationWaterDroplets
- ld a, 24
- ld [wBaseCoordY], a
- ld a, 32
- ld [wUnusedD08A], a
- call _AnimationWaterDroplets
- dec d
- jr nz, .loop
- ret
- _AnimationWaterDroplets:
- ld hl, wOAMBuffer
- .loop
- ld a, [wBaseCoordY]
- ld [hli], a ; Y
- ld a, [wBaseCoordX]
- add 27
- ld [wBaseCoordX], a
- ld [hli], a ; X
- ld a, [wDropletTile]
- ld [hli], a ; tile
- xor a
- ld [hli], a ; attribute
- ld a, [wBaseCoordX]
- cp 144
- jr c, .loop
- sub 168
- ld [wBaseCoordX], a
- ld a, [wBaseCoordY]
- add 16
- ld [wBaseCoordY], a
- cp 112
- jr c, .loop
- call AnimationCleanOAM
- jp DelayFrame
- AnimationSlideMonUp:
- ; Slides the mon's sprite upwards.
- ld c, 7
- ld a, [H_WHOSETURN]
- and a
- coord hl, 1, 6
- coord de, 1, 5
- ld a, $30
- jr z, .next
- coord hl, 12, 1
- coord de, 12, 0
- ld a, $ff
- .next
- ld [wSlideMonUpBottomRowLeftTile], a
- jp _AnimationSlideMonUp
- AnimationSlideMonDown:
- ; Slides the mon's sprite down out of the screen.
- xor a
- call GetTileIDList
- .loop
- call GetMonSpriteTileMapPointerFromRowCount
- push bc
- push de
- call CopyPicTiles
- call Delay3
- call AnimationHideMonPic
- pop de
- pop bc
- dec b
- jr nz, .loop
- ret
- AnimationSlideMonOff:
- ; Slides the mon's sprite off the screen horizontally.
- ld e, 8
- ld a, 3
- ld [wSlideMonDelay], a
- jp _AnimationSlideMonOff
- AnimationSlideEnemyMonOff:
- ; Slides the enemy mon off the screen horizontally.
- ld hl, AnimationSlideMonOff
- jp CallWithTurnFlipped
- _AnimationSlideMonUp:
- push de
- push hl
- push bc
- ; In each iteration, slide up all rows but the top one (which is overwritten).
- ld b, 6
- .slideLoop
- push bc
- push de
- push hl
- ld bc, 7
- call CopyData
- ; Note that de and hl are popped in the same order they are pushed, swapping
- ; their values. When CopyData is called, hl points to a tile 1 row below
- ; the one de points to. To maintain this relationship, after swapping, we add 2
- ; rows to hl so that it is 1 row below again.
- pop de
- pop hl
- ld bc, SCREEN_WIDTH * 2
- add hl, bc
- pop bc
- dec b
- jr nz, .slideLoop
- ; Fill in the bottom row of the mon pic with the next row's tile IDs.
- ld a, [H_WHOSETURN]
- and a
- coord hl, 1, 11
- jr z, .next
- coord hl, 12, 6
- .next
- ld a, [wSlideMonUpBottomRowLeftTile]
- inc a
- ld [wSlideMonUpBottomRowLeftTile], a
- ld c, 7
- .fillBottomRowLoop
- ld [hli], a
- add 7
- dec c
- jr nz, .fillBottomRowLoop
- ld c, 2
- call DelayFrames
- pop bc
- pop hl
- pop de
- dec c
- jr nz, _AnimationSlideMonUp
- ret
- ShakeEnemyHUD_WritePlayerMonPicOAM:
- ; Writes the OAM entries for a copy of the player mon's pic in OAM.
- ; The top 5 rows are reproduced in OAM, although only 2 are actually needed.
- ld a, $10
- ld [wBaseCoordX], a
- ld a, $30
- ld [wBaseCoordY], a
- ld hl, wOAMBuffer
- ld d, 0
- ld c, 7
- .loop
- ld a, [wBaseCoordY]
- ld e, a
- ld b, 5
- .innerLoop
- call BattleAnimWriteOAMEntry
- inc d
- dec b
- jr nz, .innerLoop
- dec c
- ret z
- inc d
- inc d
- ld a, [wBaseCoordX]
- add 8
- ld [wBaseCoordX], a
- jr .loop
- BattleAnimWriteOAMEntry:
- ; Y coordinate = e (increased by 8 each call, before the write to OAM)
- ; X coordinate = [wBaseCoordX]
- ; tile = d
- ; attributes = 0
- ld a, e
- add 8
- ld e, a
- ld [hli], a
- ld a, [wBaseCoordX]
- ld [hli], a
- ld a, d
- ld [hli], a
- xor a
- ld [hli], a
- ret
- AdjustOAMBlockXPos:
- ld l, e
- ld h, d
- AdjustOAMBlockXPos2:
- ld de, 4
- .loop
- ld a, [wCoordAdjustmentAmount]
- ld b, a
- ld a, [hl]
- add b
- cp 168
- jr c, .skipPuttingEntryOffScreen
- ; put off-screen if X >= 168
- dec hl
- ld a, 160
- ld [hli], a
- .skipPuttingEntryOffScreen
- ld [hl], a
- add hl, de
- dec c
- jr nz, .loop
- ret
- AdjustOAMBlockYPos:
- ld l, e
- ld h, d
- AdjustOAMBlockYPos2:
- ld de, 4
- .loop
- ld a, [wCoordAdjustmentAmount]
- ld b, a
- ld a, [hl]
- add b
- cp 112
- jr c, .skipSettingPreviousEntrysAttribute
- dec hl
- ld a, 160 ; bug, sets previous OAM entry's attribute
- ld [hli], a
- .skipSettingPreviousEntrysAttribute
- ld [hl], a
- add hl, de
- dec c
- jr nz, .loop
- ret
- AnimationBlinkEnemyMon:
- ; Make the enemy mon's sprite blink on and off for a second or two
- ld hl, AnimationBlinkMon
- jp CallWithTurnFlipped
- AnimationBlinkMon:
- ; Make the mon's sprite blink on and off for a second or two.
- push af
- ld c, 6
- .loop
- push bc
- call AnimationHideMonPic
- ld c, 5
- call DelayFrames
- call AnimationShowMonPic
- ld c, 5
- call DelayFrames
- pop bc
- dec c
- jr nz, .loop
- pop af
- ret
- AnimationFlashMonPic:
- ; Flashes the mon's sprite on and off
- ld a, [wBattleMonSpecies]
- ld [wChangeMonPicPlayerTurnSpecies], a
- ld a, [wEnemyMonSpecies]
- ld [wChangeMonPicEnemyTurnSpecies], a
- jp ChangeMonPic
- AnimationFlashEnemyMonPic:
- ; Flashes the enemy mon's sprite on and off
- ld hl, AnimationFlashMonPic
- jp CallWithTurnFlipped
- AnimationShowMonPic:
- xor a
- call GetTileIDList
- call GetMonSpriteTileMapPointerFromRowCount
- call CopyPicTiles
- jp Delay3
- AnimationShowEnemyMonPic:
- ; Shows the emenmy mon's front sprite. Used in animations like Seismic Toss
- ; to make the mon's sprite reappear after disappears offscreen.
- ld hl, AnimationShowMonPic
- jp CallWithTurnFlipped
- AnimationShakeBackAndForth:
- ; Shakes the mon's sprite back and forth rapidly. This is used in Double Team.
- ; The mon's sprite disappears after this animation.
- ld a, [H_WHOSETURN]
- and a
- coord hl, 0, 5
- coord de, 2, 5
- jr z, .next
- coord hl, 11, 0
- coord de, 13, 0
- .next
- xor a
- ld c, $10
- .loop
- push af
- push bc
- push de
- push hl
- push hl
- push de
- push af
- push hl
- push hl
- call GetTileIDList
- pop hl
- call CopyPicTiles
- call Delay3
- pop hl
- lb bc, 7, 9
- call ClearScreenArea
- pop af
- call GetTileIDList
- pop hl
- call CopyPicTiles
- call Delay3
- pop hl
- lb bc, 7, 9
- call ClearScreenArea
- pop hl
- pop de
- pop bc
- pop af
- dec c
- jr nz, .loop
- ret
- AnimationMoveMonHorizontally:
- ; Shifts the mon's sprite horizontally to a fixed location. Used by lots of
- ; animations like Tackle/Body Slam.
- call AnimationHideMonPic
- ld a, [H_WHOSETURN]
- and a
- coord hl, 2, 5
- jr z, .next
- coord hl, 11, 0
- .next
- xor a
- push hl
- call GetTileIDList
- pop hl
- call CopyPicTiles
- ld c, 3
- jp DelayFrames
- AnimationResetMonPosition:
- ; Resets the mon's sprites to be located at the normal coordinates.
- ld a, [H_WHOSETURN]
- and a
- ld a, 5 * SCREEN_WIDTH + 2
- jr z, .next
- ld a, 11
- .next
- call ClearMonPicFromTileMap
- jp AnimationShowMonPic
- AnimationSpiralBallsInward:
- ; Creates an effect that looks like energy balls spiralling into the
- ; player mon's sprite. Used in Focus Energy, for example.
- ld a, [H_WHOSETURN]
- and a
- jr z, .playerTurn
- ld a, -40
- ld [wSpiralBallsBaseY], a
- ld a, 80
- ld [wSpiralBallsBaseX], a
- jr .next
- .playerTurn
- xor a
- ld [wSpiralBallsBaseY], a
- ld [wSpiralBallsBaseX], a
- .next
- ld d, $7a ; ball tile
- ld c, 3 ; number of balls
- xor a
- call InitMultipleObjectsOAM
- ld hl, SpiralBallAnimationCoordinates
- .loop
- push hl
- ld c, 3
- ld de, wOAMBuffer
- .innerLoop
- ld a, [hl]
- cp $ff
- jr z, .done
- ld a, [wSpiralBallsBaseY]
- add [hl]
- ld [de], a ; Y
- inc de
- inc hl
- ld a, [wSpiralBallsBaseX]
- add [hl]
- ld [de], a ; X
- inc hl
- inc de
- inc de
- inc de
- dec c
- jr nz, .innerLoop
- ld c, 5
- call DelayFrames
- pop hl
- inc hl
- inc hl
- jr .loop
- .done
- pop hl
- call AnimationCleanOAM
- jp AnimationFlashScreen
- SpiralBallAnimationCoordinates:
- ; y, x pairs
- ; This is the sequence of screen coordinates that the spiralling
- ; balls are positioned at.
- db $38, $28
- db $40, $18
- db $50, $10
- db $60, $18
- db $68, $28
- db $60, $38
- db $50, $40
- db $40, $38
- db $40, $28
- db $46, $1E
- db $50, $18
- db $5B, $1E
- db $60, $28
- db $5B, $32
- db $50, $38
- db $46, $32
- db $48, $28
- db $50, $20
- db $58, $28
- db $50, $30
- db $50, $28
- db $FF ; list terminator
- AnimationSquishMonPic:
- ; Squishes the mon's sprite horizontally making it
- ; disappear. Used by Teleport/Sky Attack animations.
- ld c, 4
- .loop
- push bc
- ld a, [H_WHOSETURN]
- and a
- jr z, .playerTurn
- coord hl, 16, 0
- coord de, 14, 0
- jr .next
- .playerTurn
- coord hl, 5, 5
- coord de, 3, 5
- .next
- push de
- xor a ; left
- ld [wSquishMonCurrentDirection], a
- call _AnimationSquishMonPic
- pop hl
- ld a, 1 ; right
- ld [wSquishMonCurrentDirection], a
- call _AnimationSquishMonPic
- pop bc
- dec c
- jr nz, .loop
- call AnimationHideMonPic
- ld c, 2
- jp DelayFrame
- _AnimationSquishMonPic:
- ld c, 7
- .loop
- push bc
- push hl
- ld c, 3
- ld a, [wSquishMonCurrentDirection]
- cp 0
- jr nz, .right
- call AnimCopyRowLeft
- dec hl
- jr .next
- .right
- call AnimCopyRowRight
- inc hl
- .next
- ld [hl], " "
- pop hl
- ld de, SCREEN_WIDTH
- add hl, de
- pop bc
- dec c
- jr nz, .loop
- jp Delay3
- AnimationShootBallsUpward:
- ; Shoots one pillar of "energy" balls upwards. Used in Teleport/Sky Attack
- ; animations.
- ld a, [H_WHOSETURN]
- and a
- jr z, .playerTurn
- lb bc, 0, 16 * 8
- jr .next
- .playerTurn
- lb bc, 6 * 8, 5 * 8
- .next
- ld a, b
- ld [wBaseCoordY], a
- ld a, c
- ld [wBaseCoordX], a
- lb bc, 5, 1
- call _AnimationShootBallsUpward
- jp AnimationCleanOAM
- _AnimationShootBallsUpward:
- push bc
- xor a
- ld [wWhichBattleAnimTileset], a
- call LoadAnimationTileset
- pop bc
- ld d, $7a ; ball tile
- ld hl, wOAMBuffer
- push bc
- ld a, [wBaseCoordY]
- ld e, a
- .initOAMLoop
- call BattleAnimWriteOAMEntry
- dec b
- jr nz, .initOAMLoop
- call DelayFrame
- pop bc
- ld a, b
- ld [wNumShootingBalls], a
- .loop
- push bc
- ld hl, wOAMBuffer
- .innerLoop
- ld a, [wBaseCoordY]
- add 8
- ld e, a
- ld a, [hl]
- cp e ; has the ball reached the top?
- jr z, .reachedTop
- add -4 ; ball hasn't reached the top. move it up 4 pixels
- ld [hl], a
- jr .next
- .reachedTop
- ; remove the ball once it has reached the top
- ld [hl], 0 ; put it off-screen
- ld a, [wNumShootingBalls]
- dec a
- ld [wNumShootingBalls], a
- .next
- ld de, 4
- add hl, de ; next OAM entry
- dec b
- jr nz, .innerLoop
- call DelayFrames
- pop bc
- ld a, [wNumShootingBalls]
- and a
- jr nz, .loop
- ret
- AnimationShootManyBallsUpward:
- ; Shoots several pillars of "energy" balls upward.
- ld a, [H_WHOSETURN]
- and a
- ld hl, UpwardBallsAnimXCoordinatesPlayerTurn
- ld a, $50 ; y coordinate for "energy" ball pillar
- jr z, .player
- ld hl, UpwardBallsAnimXCoordinatesEnemyTurn
- ld a, $28 ; y coordinate for "energy" ball pillar
- .player
- ld [wSavedY], a
- .loop
- ld a, [wSavedY]
- ld [wBaseCoordY], a
- ld a, [hli]
- cp $ff
- jp z, AnimationCleanOAM
- ld [wBaseCoordX], a
- lb bc, 4, 1
- push hl
- call _AnimationShootBallsUpward
- pop hl
- jr .loop
- UpwardBallsAnimXCoordinatesPlayerTurn:
- ; List of x coordinates for each pillar of "energy" balls in the
- ; AnimationShootManyBallsUpward animation. It's unused in the game.
- db $10, $40, $28, $18, $38, $30
- db $FF ; list terminator
- UpwardBallsAnimXCoordinatesEnemyTurn:
- ; List of x coordinates for each pillar of "energy" balls in the
- ; AnimationShootManyBallsUpward animation. It's unused in the game.
- db $60, $90, $78, $68, $88, $80
- db $FF ; list terminator
- AnimationMinimizeMon:
- ; Changes the mon's sprite to a mini black sprite. Used by the
- ; Minimize animation.
- ld hl, wTempPic
- push hl
- xor a
- ld bc, 7 * 7 * $10
- call FillMemory
- pop hl
- ld de, $194
- add hl, de
- ld de, MinimizedMonSprite
- ld c, MinimizedMonSpriteEnd - MinimizedMonSprite
- .loop
- ld a, [de]
- ld [hli], a
- ld [hli], a
- inc de
- dec c
- jr nz, .loop
- call CopyTempPicToMonPic
- call Delay3
- jp AnimationShowMonPic
- MinimizedMonSprite:
- INCBIN "gfx/minimized_mon_sprite.1bpp"
- MinimizedMonSpriteEnd:
- AnimationSlideMonDownAndHide:
- ; Slides the mon's sprite down and disappears. Used in Acid Armor.
- ld a, $1
- ld c, $2
- .loop
- push bc
- push af
- call AnimationHideMonPic
- pop af
- push af
- call GetTileIDList
- call GetMonSpriteTileMapPointerFromRowCount
- call CopyPicTiles
- ld c, 8
- call DelayFrames
- pop af
- inc a
- pop bc
- dec c
- jr nz, .loop
- call AnimationHideMonPic
- ld hl, wTempPic
- ld bc, $0310
- xor a
- call FillMemory
- jp CopyTempPicToMonPic
- _AnimationSlideMonOff:
- ; Slides the mon's sprite off the screen horizontally by e tiles and waits
- ; [wSlideMonDelay] V-blanks each time the pic is slid by one tile.
- ld a, [H_WHOSETURN]
- and a
- jr z, .playerTurn
- coord hl, 12, 0
- jr .next
- .playerTurn
- coord hl, 0, 5
- .next
- ld d, 8 ; d's value is unused
- .slideLoop ; iterates once for each time the pic slides by one tile
- push hl
- ld b, 7
- .rowLoop ; iterates once for each row
- ld c, 8
- .tileLoop ; iterates once for each tile in the row
- ld a, [H_WHOSETURN]
- and a
- jr z, .playerTurn2
- call .EnemyNextTile
- jr .next2
- .playerTurn2
- call .PlayerNextTile
- .next2
- ld [hli], a
- dec c
- jr nz, .tileLoop
- push de
- ld de, SCREEN_WIDTH - 8
- add hl, de
- pop de
- dec b
- jr nz, .rowLoop
- ld a, [wSlideMonDelay]
- ld c, a
- call DelayFrames
- pop hl
- dec d
- dec e
- jr nz, .slideLoop
- ret
- ; Since mon pic tile numbers go from top to bottom, left to right in order,
- ; adding the height of the mon pic in tiles to a tile number gives the tile
- ; number of the tile one column to the right (and thus subtracting the height
- ; gives the reverse). If the next tile would be past the edge of the pic, the 2
- ; functions below catch it by checking if the tile number is within the valid
- ; range and if not, replacing it with a blank tile.
- .PlayerNextTile
- ld a, [hl]
- add 7
- ; This is a bug. The lower right corner tile of the mon back pic is blanked
- ; while the mon is sliding off the screen. It should compare with the max tile
- ; plus one instead.
- cp $61
- ret c
- ld a, " "
- ret
- .EnemyNextTile
- ld a, [hl]
- sub 7
- ; This has the same problem as above, but it has no visible effect because
- ; the lower right tile is in the first column to slide off the screen.
- cp $30
- ret c
- ld a, " "
- ret
- AnimationSlideMonHalfOff:
- ; Slides the mon's sprite halfway off the screen. It's used in Softboiled.
- ld e, 4
- ld a, 4
- ld [wSlideMonDelay], a
- call _AnimationSlideMonOff
- jp Delay3
- CopyTempPicToMonPic:
- ld a, [H_WHOSETURN]
- and a
- ld hl, vBackPic ; player turn
- jr z, .next
- ld hl, vFrontPic ; enemy turn
- .next
- ld de, wTempPic
- ld bc, 7 * 7
- jp CopyVideoData
- AnimationWavyScreen:
- ; used in Psywave/Psychic etc.
- ld hl, vBGMap0
- call BattleAnimCopyTileMapToVRAM
- call Delay3
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- ld a, SCREEN_HEIGHT_PIXELS
- ld [hWY], a
- ld d, $80 ; terminator
- ld e, SCREEN_HEIGHT_PIXELS - 1
- ld c, $ff
- ld hl, WavyScreenLineOffsets
- .loop
- push hl
- .innerLoop
- call WavyScreen_SetSCX
- ld a, [rLY]
- cp e ; is it the last visible line in the frame?
- jr nz, .innerLoop ; keep going if not
- pop hl
- inc hl
- ld a, [hl]
- cp d ; have we reached the end?
- jr nz, .next
- ld hl, WavyScreenLineOffsets ; go back to the beginning if so
- .next
- dec c
- jr nz, .loop
- xor a
- ld [hWY], a
- call SaveScreenTilesToBuffer2
- call ClearScreen
- ld a, 1
- ld [H_AUTOBGTRANSFERENABLED], a
- call Delay3
- call LoadScreenTilesFromBuffer2
- ld hl, vBGMap1
- call BattleAnimCopyTileMapToVRAM
- ret
- WavyScreen_SetSCX:
- ld a, [rSTAT]
- and $3 ; is it H-blank?
- jr nz, WavyScreen_SetSCX ; wait until it's H-blank
- ld a, [hl]
- ld [rSCX], a
- inc hl
- ld a, [hl]
- cp d ; have we reached the end?
- ret nz
- ld hl, WavyScreenLineOffsets ; go back to the beginning if so
- ret
- WavyScreenLineOffsets:
- ; Sequence of horizontal line pixel offsets for the wavy screen animation.
- ; This sequence vaguely resembles a sine wave.
- db 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1
- db 0, 0, 0, 0, 0, -1, -1, -1, -2, -2, -2, -2, -2, -1, -1, -1
- db $80 ; terminator
- AnimationSubstitute:
- ; Changes the pokemon's sprite to the mini sprite
- ld hl, wTempPic
- xor a
- ld bc, $0310
- call FillMemory
- ld a, [H_WHOSETURN]
- and a
- jr z, .playerTurn
- ld hl, SlowbroSprite ; facing down sprite
- ld de, wTempPic + $120
- call CopySlowbroSpriteData
- ld hl, SlowbroSprite + $10
- ld de, wTempPic + $120 + $70
- call CopySlowbroSpriteData
- ld hl, SlowbroSprite + $20
- ld de, wTempPic + $120 + $10
- call CopySlowbroSpriteData
- ld hl, SlowbroSprite + $30
- ld de, wTempPic + $120 + $10 + $70
- call CopySlowbroSpriteData
- jr .next
- .playerTurn
- ld hl, SlowbroSprite + $40 ; facing up sprite
- ld de, wTempPic + $120 + $70
- call CopySlowbroSpriteData
- ld hl, SlowbroSprite + $50
- ld de, wTempPic + $120 + $e0
- call CopySlowbroSpriteData
- ld hl, SlowbroSprite + $60
- ld de, wTempPic + $120 + $80
- call CopySlowbroSpriteData
- ld hl, SlowbroSprite + $70
- ld de, wTempPic + $120 + $f0
- call CopySlowbroSpriteData
- .next
- call CopyTempPicToMonPic
- jp AnimationShowMonPic
- CopySlowbroSpriteData:
- ld bc, $0010
- ld a, BANK(SlowbroSprite)
- jp FarCopyData2
- HideSubstituteShowMonAnim:
- ld a, [H_WHOSETURN]
- and a
- ld hl, wPlayerMonMinimized
- ld a, [wPlayerBattleStatus2]
- jr z, .next1
- ld hl, wEnemyMonMinimized
- ld a, [wEnemyBattleStatus2]
- .next1
- push hl
- ; if the substitute broke, slide it down, else slide it offscreen horizontally
- bit HasSubstituteUp, a
- jr nz, .substituteStillUp
- call AnimationSlideMonDown
- jr .next2
- .substituteStillUp
- call AnimationSlideMonOff
- .next2
- pop hl
- ld a, [hl]
- and a
- jp nz, AnimationMinimizeMon
- call AnimationFlashMonPic
- jp AnimationShowMonPic
- ReshowSubstituteAnim:
- call AnimationSlideMonOff
- call AnimationSubstitute
- jp AnimationShowMonPic
- AnimationBoundUpAndDown:
- ; Bounces the mon's sprite up and down several times. It is used
- ; by Splash's animation.
- ld c, 5
- .loop
- push bc
- call AnimationSlideMonDown
- pop bc
- dec c
- jr nz, .loop
- jp AnimationShowMonPic
- AnimationTransformMon:
- ; Redraws this mon's sprite as the back/front sprite of the opposing mon.
- ; Used in Transform.
- ld a, [wEnemyMonSpecies]
- ld [wChangeMonPicPlayerTurnSpecies], a
- ld a, [wBattleMonSpecies]
- ld [wChangeMonPicEnemyTurnSpecies], a
- ChangeMonPic:
- ld a, [H_WHOSETURN]
- and a
- jr z, .playerTurn
- ld a, [wChangeMonPicEnemyTurnSpecies]
- ld [wcf91], a
- ld [wd0b5], a
- xor a
- ld [wSpriteFlipped], a
- call GetMonHeader
- coord hl, 12, 0
- call LoadFrontSpriteByMonIndex
- jr .done
- .playerTurn
- ld a, [wBattleMonSpecies2]
- push af
- ld a, [wChangeMonPicPlayerTurnSpecies]
- ld [wBattleMonSpecies2], a
- ld [wd0b5], a
- call GetMonHeader
- predef LoadMonBackPic
- xor a
- call GetTileIDList
- call GetMonSpriteTileMapPointerFromRowCount
- call CopyPicTiles
- pop af
- ld [wBattleMonSpecies2], a
- .done
- ld b, SET_PAL_BATTLE
- jp RunPaletteCommand
- AnimationHideEnemyMonPic:
- ; Hides the enemy mon's sprite
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- ld hl, AnimationHideMonPic
- call CallWithTurnFlipped
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- jp Delay3
- InitMultipleObjectsOAM:
- ; Writes c OAM entries with tile d.
- ; Sets their Y coordinates to sequential multiples of 8, starting from 0.
- ; Sets their X coordinates to 0.
- ; Loads animation tileset a.
- push bc
- push de
- ld [wWhichBattleAnimTileset], a
- call LoadAnimationTileset
- pop de
- pop bc
- xor a
- ld e, a
- ld [wBaseCoordX], a
- ld hl, wOAMBuffer
- .loop
- call BattleAnimWriteOAMEntry
- dec c
- jr nz, .loop
- ret
- AnimationHideMonPic:
- ; Hides the mon's sprite.
- ld a, [H_WHOSETURN]
- and a
- jr z, .playerTurn
- ld a, 12
- jr ClearMonPicFromTileMap
- .playerTurn
- ld a, 5 * SCREEN_WIDTH + 1
- ClearMonPicFromTileMap:
- push hl
- push de
- push bc
- ld e, a
- ld d, 0
- coord hl, 0, 0
- add hl, de
- lb bc, 7, 7
- call ClearScreenArea
- pop bc
- pop de
- pop hl
- ret
- ; puts the tile map destination address of a mon sprite in hl, given the row count in b
- ; The usual row count is 7, but it may be smaller when sliding a mon sprite in/out,
- ; in order to show only a portion of the mon sprite.
- GetMonSpriteTileMapPointerFromRowCount:
- push de
- ld a, [H_WHOSETURN]
- and a
- jr nz, .enemyTurn
- ld a, 20 * 5 + 1
- jr .next
- .enemyTurn
- ld a, 12
- .next
- coord hl, 0, 0
- ld e, a
- ld d, 0
- add hl, de
- ld a, 7
- sub b
- and a
- jr z, .done
- ld de, 20
- .loop
- add hl, de
- dec a
- jr nz, .loop
- .done
- pop de
- ret
- ; Input:
- ; a = tile ID list index
- ; Output:
- ; de = tile ID list pointer
- ; b = number of rows
- ; c = number of columns
- GetTileIDList:
- ld hl, TileIDListPointerTable
- ld e, a
- ld d, 0
- add hl, de
- add hl, de
- add hl, de
- ld a, [hli]
- ld e, a
- ld a, [hli]
- ld d, a
- ld a, [hli]
- ld b, a
- and $f
- ld c, a
- ld a, b
- swap a
- and $f
- ld b, a
- ret
- AnimCopyRowLeft:
- ; copy a row of c tiles 1 tile left
- ld a, [hld]
- ld [hli], a
- inc hl
- dec c
- jr nz, AnimCopyRowLeft
- ret
- AnimCopyRowRight:
- ; copy a row of c tiles 1 tile right
- ld a, [hli]
- ld [hld], a
- dec hl
- dec c
- jr nz, AnimCopyRowRight
- ret
- ; get the sound of the move id in b
- GetMoveSoundB:
- ld a, b
- call GetMoveSound
- ld b, a
- ret
- GetMoveSound:
- ld hl,MoveSoundTable
- ld e,a
- ld d,0
- add hl,de
- add hl,de
- add hl,de
- ld a,[hli]
- ld b,a
- call IsCryMove
- jr nc,.NotCryMove
- ld a,[H_WHOSETURN]
- and a
- jr nz,.next
- ld a,[wBattleMonSpecies] ; get number of current monster
- jr .Continue
- .next
- ld a,[wEnemyMonSpecies]
- .Continue
- push hl
- call GetCryData
- ld b,a
- pop hl
- ld a,[wFrequencyModifier]
- add [hl]
- ld [wFrequencyModifier],a
- inc hl
- ld a,[wTempoModifier]
- add [hl]
- ld [wTempoModifier],a
- jr .done
- .NotCryMove
- ld a,[hli]
- ld [wFrequencyModifier],a
- ld a,[hli]
- ld [wTempoModifier],a
- .done
- ld a,b
- ret
- IsCryMove:
- ; set carry if the move animation involves playing a monster cry
- ld a,[wAnimationID]
- cp a,GROWL
- jr z,.CryMove
- cp a,ROAR
- jr z,.CryMove
- and a ; clear carry
- ret
- .CryMove
- scf
- ret
- MoveSoundTable:
- ; ID, pitch mod, tempo mod
- db SFX_POUND, $00,$80 ; POUND
- db SFX_BATTLE_0C, $10,$80 ; KARATE_CHOP
- db SFX_DOUBLESLAP, $00,$80 ; DOUBLESLAP
- db SFX_BATTLE_0B, $01,$80 ; COMET_PUNCH
- db SFX_BATTLE_0D, $00,$40 ; MEGA_PUNCH
- db SFX_SILPH_SCOPE, $00,$ff ; PAY_DAY
- db SFX_BATTLE_0D, $10,$60 ; FIRE_PUNCH
- db SFX_BATTLE_0D, $20,$80 ; ICE_PUNCH
- db SFX_BATTLE_0D, $00,$a0 ; THUNDERPUNCH
- db SFX_DAMAGE, $00,$80 ; SCRATCH
- db SFX_BATTLE_0F, $20,$40 ; VICEGRIP
- db SFX_BATTLE_0F, $00,$80 ; GUILLOTINE
- db SFX_BATTLE_0E, $00,$a0 ; RAZOR_WIND
- db SFX_NOT_VERY_EFFECTIVE,$10,$c0 ; SWORDS_DANCE
- db SFX_NOT_VERY_EFFECTIVE,$00,$a0 ; CUT
- db SFX_BATTLE_12, $00,$c0 ; GUST
- db SFX_BATTLE_12, $10,$a0 ; WING_ATTACK
- db SFX_BATTLE_13, $00,$e0 ; WHIRLWIND
- db SFX_NOT_VERY_EFFECTIVE,$20,$c0 ; FLY
- db SFX_BATTLE_14, $00,$80 ; BIND
- db SFX_BATTLE_22, $00,$80 ; SLAM
- db SFX_VINE_WHIP, $01,$80 ; VINE_WHIP
- db SFX_BATTLE_20, $00,$80 ; STOMP
- db SFX_BATTLE_17, $f0,$40 ; DOUBLE_KICK
- db SFX_SUPER_EFFECTIVE, $00,$80 ; MEGA_KICK
- db SFX_BATTLE_17, $00,$80 ; JUMP_KICK
- db SFX_BATTLE_21, $10,$80 ; ROLLING_KICK
- db SFX_BATTLE_1B, $01,$a0 ; SAND_ATTACK
- db SFX_BATTLE_18, $00,$80 ; HEADBUTT
- db SFX_BATTLE_1E, $00,$60 ; HORN_ATTACK
- db SFX_BATTLE_1E, $01,$40 ; FURY_ATTACK
- db SFX_HORN_DRILL, $00,$a0 ; HORN_DRILL
- db SFX_SUPER_EFFECTIVE, $10,$a0 ; TACKLE
- db SFX_BATTLE_20, $00,$c0 ; BODY_SLAM
- db SFX_BATTLE_14, $10,$60 ; WRAP
- db SFX_SUPER_EFFECTIVE, $00,$a0 ; TAKE_DOWN
- db SFX_BATTLE_22, $11,$c0 ; THRASH
- db SFX_SUPER_EFFECTIVE, $20,$c0 ; DOUBLE_EDGE
- db SFX_BATTLE_21, $00,$80 ; TAIL_WHIP
- db SFX_BATTLE_1B, $00,$80 ; POISON_STING
- db SFX_BATTLE_1B, $20,$c0 ; TWINEEDLE
- db SFX_BATTLE_19, $00,$80 ; PIN_MISSILE
- db SFX_BATTLE_31, $ff,$40 ; LEER
- db SFX_BATTLE_1E, $00,$80 ; BITE
- db SFX_BATTLE_0B, $00,$c0 ; GROWL
- db SFX_BATTLE_0B, $00,$40 ; ROAR
- db SFX_BATTLE_35, $00,$80 ; SING
- db SFX_BATTLE_27, $40,$60 ; SUPERSONIC
- db SFX_BATTLE_27, $00,$80 ; SONICBOOM
- db SFX_BATTLE_27, $ff,$40 ; DISABLE
- db SFX_BATTLE_2A, $80,$c0 ; ACID
- db SFX_BATTLE_19, $10,$a0 ; EMBER
- db SFX_BATTLE_19, $21,$e0 ; FLAMETHROWER
- db SFX_BATTLE_29, $00,$80 ; MIST
- db SFX_BATTLE_24, $20,$60 ; WATER_GUN
- db SFX_BATTLE_2A, $00,$80 ; HYDRO_PUMP
- db SFX_BATTLE_2C, $00,$80 ; SURF
- db SFX_BATTLE_28, $40,$80 ; ICE_BEAM
- db SFX_BATTLE_29, $f0,$e0 ; BLIZZARD
- db SFX_PSYBEAM, $00,$80 ; PSYBEAM
- db SFX_BATTLE_2A, $f0,$60 ; BUBBLEBEAM
- db SFX_BATTLE_28, $00,$80 ; AURORA_BEAM
- db SFX_BATTLE_36, $00,$80 ; HYPER_BEAM
- db SFX_PECK,$01, $a0 ; PECK
- db SFX_BATTLE_13, $f0,$20 ; DRILL_PECK
- db SFX_BATTLE_23, $01,$c0 ; SUBMISSION
- db SFX_BATTLE_23, $00,$80 ; LOW_KICK
- db SFX_SUPER_EFFECTIVE, $00,$e0 ; COUNTER
- db SFX_BATTLE_26, $01,$60 ; SEISMIC_TOSS
- db SFX_BATTLE_26, $20,$40 ; STRENGTH
- db SFX_BATTLE_24, $00,$80 ; ABSORB
- db SFX_BATTLE_24, $40,$c0 ; MEGA_DRAIN
- db SFX_BATTLE_1B, $03,$60 ; LEECH_SEED
- db SFX_BATTLE_25, $11,$e0 ; GROWTH
- db SFX_BATTLE_12, $20,$e0 ; RAZOR_LEAF
- db SFX_BATTLE_2E, $00,$80 ; SOLARBEAM
- db SFX_BATTLE_1C, $00,$80 ; POISONPOWDER
- db SFX_BATTLE_1C, $11,$a0 ; STUN_SPORE
- db SFX_BATTLE_1C, $01,$c0 ; SLEEP_POWDER
- db SFX_BATTLE_13, $14,$c0 ; PETAL_DANCE
- db SFX_BATTLE_1B, $02,$a0 ; STRING_SHOT
- db SFX_BATTLE_29, $f0,$80 ; DRAGON_RAGE
- db SFX_BATTLE_29, $20,$c0 ; FIRE_SPIN
- db SFX_BATTLE_2F, $00,$20 ; THUNDERSHOCK
- db SFX_BATTLE_2F, $20,$80 ; THUNDERBOLT
- db SFX_BATTLE_2E, $12,$60 ; THUNDER_WAVE
- db SF