diff options
Diffstat (limited to 'engine')
46 files changed, 36672 insertions, 185 deletions
diff --git a/engine/anims/anim_commands.asm b/engine/anims/anim_commands.asm new file mode 100644 index 000000000..1977f9112 --- /dev/null +++ b/engine/anims/anim_commands.asm @@ -0,0 +1,1514 @@ +; Battle animation command interpreter. + +PlayBattleAnim: ; cc0d6 + + ld a, [rSVBK] + push af + + ld a, 5 + ld [rSVBK], a + + call _PlayBattleAnim + + pop af + ld [rSVBK], a + ret +; cc0e4 + +_PlayBattleAnim: ; cc0e4 + + ld c, 6 +.wait + call BattleAnimDelayFrame + dec c + jr nz, .wait + + call BattleAnimAssignPals + call BattleAnimRequestPals + call BattleAnimDelayFrame + + ld c, 1 + ld a, [rKEY1] + bit 7, a + jr nz, .asm_cc0ff + ld c, 3 + +.asm_cc0ff + ld hl, hVBlank + ld a, [hl] + push af + + ld [hl], c + call BattleAnimRunScript + + pop af + ld [hVBlank], a + + ld a, $1 + ld [hBGMapMode], a + + call BattleAnimDelayFrame + call BattleAnimDelayFrame + call BattleAnimDelayFrame + call WaitSFX + ret +; cc11c + +BattleAnimRunScript: ; cc11c + + ld a, [FXAnimID + 1] + and a + jr nz, .hi_byte + + farcall CheckBattleScene + jr c, .disabled + + call BattleAnimClearHud + call RunBattleAnimScript + + call BattleAnimAssignPals + call BattleAnimRequestPals + + xor a + ld [hSCX], a + ld [hSCY], a + call BattleAnimDelayFrame + call BattleAnimRestoreHuds + +.disabled + ld a, [wNumHits] + and a + jr z, .done + + ld l, a + ld h, 0 + ld de, ANIM_MISS + add hl, de + ld a, l + ld [FXAnimID], a + ld a, h + ld [FXAnimID + 1], a + +.hi_byte + call WaitSFX + call PlayHitSound + call RunBattleAnimScript + +.done + call BattleAnim_RevertPals + ret +; cc163 + +RunBattleAnimScript: ; cc163 + + call ClearBattleAnims + +.playframe + call RunBattleAnimCommand + call _ExecuteBGEffects + call BattleAnim_UpdateOAM_All + call PushLYOverrides + call BattleAnimRequestPals + +; Speed up Rollout's animation. + ld a, [FXAnimID + 1] + or a + jr nz, .not_rollout + + ld a, [FXAnimID] + cp ROLLOUT + jr nz, .not_rollout + + ld a, $2e + ld b, 5 + ld de, 4 + ld hl, ActiveBGEffects +.find + cp [hl] + jr z, .done + add hl, de + dec b + jr nz, .find + +.not_rollout + call BattleAnimDelayFrame + +.done + ld a, [BattleAnimFlags] + bit 0, a + jr z, .playframe + + call BattleAnim_ClearCGB_OAMFlags + ret +; cc1a1 + +BattleAnimClearHud: ; cc1a1 + + call BattleAnimDelayFrame + call WaitTop + call ClearActorHud + ld a, $1 + ld [hBGMapMode], a + call BattleAnimDelayFrame + call BattleAnimDelayFrame + call BattleAnimDelayFrame + call WaitTop + ret +; cc1bb + +BattleAnimRestoreHuds: ; cc1bb + + call BattleAnimDelayFrame + call WaitTop + + ld a, [rSVBK] + push af + ld a, $1 + ld [rSVBK], a + + ld hl, UpdateBattleHuds + ld a, BANK(UpdatePlayerHUD) + rst FarCall ; Why not "call UpdateBattleHuds"? + + pop af + ld [rSVBK], a + + ld a, $1 + ld [hBGMapMode], a + call BattleAnimDelayFrame + call BattleAnimDelayFrame + call BattleAnimDelayFrame + call WaitTop + ret +; cc1e2 + +BattleAnimRequestPals: ; cc1e2 + + ld a, [hCGB] + and a + ret z + + ld a, [rBGP] + ld b, a + ld a, [wBGP] + cp b + call nz, BattleAnim_SetBGPals + + ld a, [rOBP0] + ld b, a + ld a, [wOBP0] + cp b + call nz, BattleAnim_SetOBPals + ret +; cc1fb + +BattleAnimDelayFrame: ; cc1fb +; Like DelayFrame but wastes battery life. + + ld a, 1 + ld [VBlankOccurred], a +.wait + ld a, [VBlankOccurred] + and a + jr nz, .wait + ret +; cc207 + +ClearActorHud: ; cc207 + + ld a, [hBattleTurn] + and a + jr z, .player + + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + ret + +.player + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + ret +; cc220 + +Functioncc220: ; cc220 +; Appears to be unused. + xor a + ld [hBGMapMode], a + ld a, LOW(VBGMap0 tile $28) + ld [hBGMapAddress], a + ld a, HIGH(VBGMap0 tile $28) + ld [hBGMapAddress + 1], a + call WaitBGMap2 + ld a, $60 + ld [hWY], a + xor a ; LOW(VBGMap0) + ld [hBGMapAddress], a + ld a, HIGH(VBGMap0) + ld [hBGMapAddress + 1], a + call BattleAnimDelayFrame + ret +; cc23d + + +BattleAnim_ClearCGB_OAMFlags: ; cc23d + + ld a, [BattleAnimFlags] + bit 3, a + jr z, .delete + + ld hl, Sprites + 3 + ld c, (SpritesEnd - Sprites) / 4 +.loop + ld a, [hl] + and $f0 + ld [hli], a + inc hl + inc hl + inc hl + dec c + jr nz, .loop + ret + +.delete + ld hl, Sprites + ld c, SpritesEnd - Sprites + xor a +.loop2 + ld [hli], a + dec c + jr nz, .loop2 + ret +; cc25f + +RunBattleAnimCommand: ; cc25f + call .CheckTimer + ret nc + call .RunScript + ret +; cc267 + +.CheckTimer: ; cc267 + ld a, [BattleAnimDuration] + and a + jr z, .done + + dec a + ld [BattleAnimDuration], a + and a + ret + +.done + scf + ret +; cc275 + +.RunScript: ; cc275 +.loop + call GetBattleAnimByte + + cp $ff + jr nz, .not_done_with_anim + +; Return from a subroutine. + ld hl, BattleAnimFlags + bit 1, [hl] + jr nz, .do_anim + + set 0, [hl] + ret + +.not_done_with_anim + cp $d0 + jr nc, .do_anim + + ld [BattleAnimDuration], a + ret + +.do_anim + call .DoCommand + + jr .loop +; cc293 + +.DoCommand: ; cc293 +; Execute battle animation command in [BattleAnimByte]. + ld a, [BattleAnimByte] + sub $d0 + + ld e, a + ld d, 0 + ld hl, BattleAnimCommands + add hl, de + add hl, de + + ld a, [hli] + ld h, [hl] + ld l, a + jp hl +; cc2a4 + + +BattleAnimCommands:: ; cc2a4 (33:42a4) +; entries correspond to macros/move_anim.asm enumeration + dw BattleAnimCmd_Obj + dw BattleAnimCmd_1GFX + dw BattleAnimCmd_2GFX + dw BattleAnimCmd_3GFX + dw BattleAnimCmd_4GFX + dw BattleAnimCmd_5GFX + dw BattleAnimCmd_IncObj + dw BattleAnimCmd_SetObj + dw BattleAnimCmd_IncBGEffect + dw BattleAnimCmd_EnemyFeetObj + dw BattleAnimCmd_PlayerHeadObj + dw BattleAnimCmd_CheckPokeball + dw BattleAnimCmd_Transform + dw BattleAnimCmd_RaiseSub + dw BattleAnimCmd_DropSub + dw BattleAnimCmd_ResetObp0 + dw BattleAnimCmd_Sound + dw BattleAnimCmd_Cry + dw BattleAnimCmd_MinimizeOpp + dw BattleAnimCmd_OAMOn + dw BattleAnimCmd_OAMOff + dw BattleAnimCmd_ClearObjs + dw BattleAnimCmd_BeatUp + dw BattleAnimCmd_E7 + dw BattleAnimCmd_UpdateActorPic + dw BattleAnimCmd_Minimize + dw BattleAnimCmd_EA ; dummy + dw BattleAnimCmd_EB ; dummy + dw BattleAnimCmd_EC ; dummy + dw BattleAnimCmd_ED ; dummy + dw BattleAnimCmd_IfParamAnd + dw BattleAnimCmd_JumpUntil + dw BattleAnimCmd_BGEffect + dw BattleAnimCmd_BGP + dw BattleAnimCmd_OBP0 + dw BattleAnimCmd_OBP1 + dw BattleAnimCmd_ClearSprites + dw BattleAnimCmd_F5 + dw BattleAnimCmd_F6 + dw BattleAnimCmd_F7 + dw BattleAnimCmd_IfParamEqual + dw BattleAnimCmd_SetVar + dw BattleAnimCmd_IncVar + dw BattleAnimCmd_IfVarEqual + dw BattleAnimCmd_Jump + dw BattleAnimCmd_Loop + dw BattleAnimCmd_Call + dw BattleAnimCmd_Ret + + +BattleAnimCmd_EA: +BattleAnimCmd_EB: +BattleAnimCmd_EC: +BattleAnimCmd_ED: ; cc304 (33:4304) + ret + +BattleAnimCmd_Ret: ; cc305 (33:4305) + ld hl, BattleAnimFlags + res 1, [hl] + ld hl, BattleAnimParent + ld e, [hl] + inc hl + ld d, [hl] + ld hl, BattleAnimAddress + ld [hl], e + inc hl + ld [hl], d + ret + +BattleAnimCmd_Call: ; cc317 (33:4317) + call GetBattleAnimByte + ld e, a + call GetBattleAnimByte + ld d, a + push de + ld hl, BattleAnimAddress + ld e, [hl] + inc hl + ld d, [hl] + ld hl, BattleAnimParent + ld [hl], e + inc hl + ld [hl], d + pop de + ld hl, BattleAnimAddress + ld [hl], e + inc hl + ld [hl], d + ld hl, BattleAnimFlags + set 1, [hl] + ret + +BattleAnimCmd_Jump: ; cc339 (33:4339) + call GetBattleAnimByte + ld e, a + call GetBattleAnimByte + ld d, a + ld hl, BattleAnimAddress + ld [hl], e + inc hl + ld [hl], d + ret + +BattleAnimCmd_Loop: ; cc348 (33:4348) + call GetBattleAnimByte + ld hl, BattleAnimFlags + bit 2, [hl] + jr nz, .continue_loop + and a + jr z, .perpetual + dec a + set 2, [hl] + ld [BattleAnimLoops], a +.continue_loop + ld hl, BattleAnimLoops + ld a, [hl] + and a + jr z, .return_from_loop + dec [hl] +.perpetual + call GetBattleAnimByte + ld e, a + call GetBattleAnimByte + ld d, a + ld hl, BattleAnimAddress + ld [hl], e + inc hl + ld [hl], d + ret + +.return_from_loop + ld hl, BattleAnimFlags + res 2, [hl] + ld hl, BattleAnimAddress + ld e, [hl] + inc hl + ld d, [hl] + inc de + inc de + ld [hl], d + dec hl + ld [hl], e + ret + +BattleAnimCmd_JumpUntil: ; cc383 (33:4383) + ld hl, wBattleAnimParam + ld a, [hl] + and a + jr z, .dont_jump + + dec [hl] + call GetBattleAnimByte + ld e, a + call GetBattleAnimByte + ld d, a + ld hl, BattleAnimAddress + ld [hl], e + inc hl + ld [hl], d + ret + +.dont_jump + ld hl, BattleAnimAddress + ld e, [hl] + inc hl + ld d, [hl] + inc de + inc de + ld [hl], d + dec hl + ld [hl], e + ret + +BattleAnimCmd_SetVar: ; cc3a6 (33:43a6) + call GetBattleAnimByte + ld [BattleAnimVar], a + ret + +BattleAnimCmd_IncVar: ; cc3ad (33:43ad) + ld hl, BattleAnimVar + inc [hl] + ret + +BattleAnimCmd_IfVarEqual: ; cc3b2 (33:43b2) + call GetBattleAnimByte + ld hl, BattleAnimVar + cp [hl] + jr z, .jump + + ld hl, BattleAnimAddress + ld e, [hl] + inc hl + ld d, [hl] + inc de + inc de + ld [hl], d + dec hl + ld [hl], e + ret + +.jump + call GetBattleAnimByte + ld e, a + call GetBattleAnimByte + ld d, a + ld hl, BattleAnimAddress + ld [hl], e + inc hl + ld [hl], d + ret + +BattleAnimCmd_IfParamEqual: ; cc3d6 (33:43d6) + call GetBattleAnimByte + ld hl, wBattleAnimParam + cp [hl] + jr z, .jump + + ld hl, BattleAnimAddress + ld e, [hl] + inc hl + ld d, [hl] + inc de + inc de + ld [hl], d + dec hl + ld [hl], e + ret + +.jump + call GetBattleAnimByte + ld e, a + call GetBattleAnimByte + ld d, a + ld hl, BattleAnimAddress + ld [hl], e + inc hl + ld [hl], d + ret + +BattleAnimCmd_IfParamAnd: ; cc3fa (33:43fa) + call GetBattleAnimByte + ld e, a + ld a, [wBattleAnimParam] + and e + jr nz, .jump + + ld hl, BattleAnimAddress + ld e, [hl] + inc hl + ld d, [hl] + inc de + inc de + ld [hl], d + dec hl + ld [hl], e + ret + +.jump + call GetBattleAnimByte + ld e, a + call GetBattleAnimByte + ld d, a + ld hl, BattleAnimAddress + ld [hl], e + inc hl + ld [hl], d + ret + +BattleAnimCmd_Obj: ; cc41f (33:441f) +; index, x, y, param + call GetBattleAnimByte + ld [wBattleAnimTemp0], a + call GetBattleAnimByte + ld [wBattleAnimTemp1], a + call GetBattleAnimByte + ld [wBattleAnimTemp2], a + call GetBattleAnimByte + ld [wBattleAnimTemp3], a + call QueueBattleAnimation + ret + +BattleAnimCmd_BGEffect: ; cc43b (33:443b) + call GetBattleAnimByte + ld [wBattleAnimTemp0], a + call GetBattleAnimByte + ld [wBattleAnimTemp1], a + call GetBattleAnimByte + ld [wBattleAnimTemp2], a + call GetBattleAnimByte + ld [wBattleAnimTemp3], a + call _QueueBGEffect + ret + +BattleAnimCmd_BGP: ; cc457 (33:4457) + call GetBattleAnimByte + ld [wBGP], a + ret + +BattleAnimCmd_OBP0: ; cc45e (33:445e) + call GetBattleAnimByte + ld [wOBP0], a + ret + +BattleAnimCmd_OBP1: ; cc465 (33:4465) + call GetBattleAnimByte + ld [wOBP1], a + ret + +BattleAnimCmd_ResetObp0: ; cc46c (33:446c) + ld a, [hSGB] + and a + ld a, $e0 + jr z, .not_sgb + ld a, $f0 +.not_sgb + ld [wOBP0], a + ret + +BattleAnimCmd_ClearObjs: ; cc479 (33:4479) + ld hl, ActiveAnimObjects + ld a, $a0 +.loop + ld [hl], $0 + inc hl + dec a + jr nz, .loop + ret + +BattleAnimCmd_1GFX: +BattleAnimCmd_2GFX: +BattleAnimCmd_3GFX: +BattleAnimCmd_4GFX: +BattleAnimCmd_5GFX: ; cc485 (33:4485) + ld a, [BattleAnimByte] + and $f + ld c, a + ld hl, wBattleAnimTileDict + xor a + ld [wBattleAnimTemp0], a +.loop + ld a, [wBattleAnimTemp0] + cp (VTiles1 - VTiles0) / $10 - $31 + ret nc + call GetBattleAnimByte + ld [hli], a + ld a, [wBattleAnimTemp0] + ld [hli], a + push bc + push hl + ld l, a + ld h, $0 +rept 4 + add hl, hl +endr + ld de, VTiles0 tile $31 + add hl, de + ld a, [BattleAnimByte] + call LoadBattleAnimObj + ld a, [wBattleAnimTemp0] + add c + ld [wBattleAnimTemp0], a + pop hl + pop bc + dec c + jr nz, .loop + ret + +BattleAnimCmd_IncObj: ; cc4c0 (33:44c0) + call GetBattleAnimByte + ld e, 10 + ld bc, ActiveAnimObjects +.loop + ld hl, BATTLEANIMSTRUCT_INDEX + add hl, bc + ld d, [hl] + ld a, [BattleAnimByte] + cp d + jr z, .found + ld hl, BATTLEANIMSTRUCT_LENGTH + add hl, bc + ld c, l + ld b, h + dec e + jr nz, .loop + ret + +.found + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + inc [hl] + ret + +BattleAnimCmd_IncBGEffect: ; cc4e3 (33:44e3) + call GetBattleAnimByte + ld e, 5 + ld bc, ActiveBGEffects +.loop + ld hl, $0 + add hl, bc + ld d, [hl] + ld a, [BattleAnimByte] + cp d + jr z, .found + ld hl, 4 + add hl, bc + ld c, l + ld b, h + dec e + jr nz, .loop + ret + +.found + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + inc [hl] + ret + +BattleAnimCmd_SetObj: ; cc506 (33:4506) + call GetBattleAnimByte + ld e, 10 + ld bc, ActiveAnimObjects +.loop + ld hl, BATTLEANIMSTRUCT_INDEX + add hl, bc + ld d, [hl] + ld a, [BattleAnimByte] + cp d + jr z, .found + ld hl, BATTLEANIMSTRUCT_LENGTH + add hl, bc + ld c, l + ld b, h + dec e + jr nz, .loop + ret + +.found + call GetBattleAnimByte + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld [hl], a + ret + +BattleAnimCmd_EnemyFeetObj: ; cc52c (33:452c) + + ld hl, wBattleAnimTileDict +.loop + ld a, [hl] + and a + jr z, .okay + inc hl + inc hl + jr .loop + +.okay + ld a, $28 + ld [hli], a + ld a, $42 + ld [hli], a + ld a, $29 + ld [hli], a + ld a, $49 + ld [hl], a + + ld hl, VTiles0 tile $73 + ld de, VTiles2 tile $06 + ld a, $70 + ld [wBattleAnimTemp0], a + ld a, $7 + call .LoadFootprint + ld de, VTiles2 tile $31 + ld a, $60 + ld [wBattleAnimTemp0], a + ld a, $6 + call .LoadFootprint + ret + +.LoadFootprint: ; cc561 (33:4561) + push af + push hl + push de + lb bc, BANK(BattleAnimCmd_EnemyFeetObj), 1 + call Request2bpp + pop de + ld a, [wBattleAnimTemp0] + ld l, a + ld h, 0 + add hl, de + ld e, l + ld d, h + pop hl + ld bc, 1 tiles + add hl, bc + pop af + dec a + jr nz, .LoadFootprint + ret + +BattleAnimCmd_PlayerHeadObj: ; cc57e (33:457e) + + ld hl, wBattleAnimTileDict +.loop + ld a, [hl] + and a + jr z, .okay + inc hl + inc hl + jr .loop + +.okay + ld a, $28 + ld [hli], a + ld a, $35 + ld [hli], a + ld a, $29 + ld [hli], a + ld a, $43 + ld [hl], a + + ld hl, VTiles0 tile $66 + ld de, VTiles2 tile $05 + ld a, $70 + ld [wBattleAnimTemp0], a + ld a, $7 + call .LoadHead + ld de, VTiles2 tile $31 + ld a, $60 + ld [wBattleAnimTemp0], a + ld a, $6 + call .LoadHead + ret + +.LoadHead: ; cc5b3 (33:45b3) + push af + push hl + push de + lb bc, BANK(BattleAnimCmd_EnemyFeetObj), 2 + call Request2bpp + pop de + ld a, [wBattleAnimTemp0] + ld l, a + ld h, 0 + add hl, de + ld e, l + ld d, h + pop hl + ld bc, 2 tiles + add hl, bc + pop af + dec a + jr nz, .LoadHead + ret + +BattleAnimCmd_CheckPokeball: ; cc5d0 (33:45d0) + callfar GetPokeBallWobble + ld a, c + ld [BattleAnimVar], a + ret + +BattleAnimCmd_E7: ; cc5db (33:45db) + ret + +BattleAnimCmd_Transform: ; cc5dc (33:45dc) + ld a, [rSVBK] + push af + ld a, 1 + ld [rSVBK], a + ld a, [CurPartySpecies] ; CurPartySpecies + push af + + ld a, [hBattleTurn] + and a + jr z, .player + + ld a, [TempBattleMonSpecies] ; TempBattleMonSpecies + ld [CurPartySpecies], a ; CurPartySpecies + ld hl, BattleMonDVs ; BattleMonDVs + predef GetUnownLetter + ld de, VTiles0 tile $00 + predef GetMonFrontpic + jr .done + +.player + ld a, [TempEnemyMonSpecies] ; TempEnemyMonSpecies + ld [CurPartySpecies], a ; CurPartySpecies + ld hl, EnemyMonDVs ; EnemyMonDVs + predef GetUnownLetter + ld de, VTiles0 tile $00 + predef GetMonBackpic + +.done + pop af + ld [CurPartySpecies], a ; CurPartySpecies + pop af + ld [rSVBK], a + ret + +BattleAnimCmd_UpdateActorPic: ; cc622 (33:4622) + + ld de, VTiles0 tile $00 + ld a, [hBattleTurn] + and a + jr z, .player + + ld hl, VTiles2 tile $00 + ld b, 0 + ld c, $31 + call Request2bpp + ret + +.player + ld hl, VTiles2 tile $31 + ld b, 0 + ld c, $24 + call Request2bpp + ret + +BattleAnimCmd_RaiseSub: ; cc640 (33:4640) + + ld a, [rSVBK] + push af + ld a, 1 + ld [rSVBK], a + xor a + call GetSRAMBank + +GetSubstitutePic: ; cc64c + + ld hl, sScratch + ld bc, (7 * 7) tiles +.loop + xor a + ld [hli], a + dec bc + ld a, c + or b + jr nz, .loop + + ld a, [hBattleTurn] + and a + jr z, .player + + ld hl, MonsterSpriteGFX + 0 tiles + ld de, sScratch + (2 * 7 + 5) tiles + call .CopyTile + ld hl, MonsterSpriteGFX + 1 tiles + ld de, sScratch + (3 * 7 + 5) tiles + call .CopyTile + ld hl, MonsterSpriteGFX + 2 tiles + ld de, sScratch + (2 * 7 + 6) tiles + call .CopyTile + ld hl, MonsterSpriteGFX + 3 tiles + ld de, sScratch + (3 * 7 + 6) tiles + call .CopyTile + + ld hl, VTiles2 tile $00 + ld de, sScratch + lb bc, BANK(GetSubstitutePic), 7 * 7 + call Request2bpp + jr .done + +.player + ld hl, MonsterSpriteGFX + 4 tiles + ld de, sScratch + (2 * 6 + 4) tiles + call .CopyTile + ld hl, MonsterSpriteGFX + 5 tiles + ld de, sScratch + (3 * 6 + 4) tiles + call .CopyTile + ld hl, MonsterSpriteGFX + 6 tiles + ld de, sScratch + (2 * 6 + 5) tiles + call .CopyTile + ld hl, MonsterSpriteGFX + 7 tiles + ld de, sScratch + (3 * 6 + 5) tiles + call .CopyTile + + ld hl, VTiles2 tile $31 + ld de, sScratch + lb bc, BANK(GetSubstitutePic), 6 * 6 + call Request2bpp + +.done + call CloseSRAM + pop af + ld [rSVBK], a + ret + +.CopyTile: ; cc6c6 (33:46c6) + ld bc, 1 tiles + ld a, BANK(MonsterSpriteGFX) + call FarCopyBytes + ret + +BattleAnimCmd_MinimizeOpp: ; cc6cf (33:46cf) + ld a, [rSVBK] + push af + ld a, $1 + ld [rSVBK], a + xor a + call GetSRAMBank + call GetMinimizePic + call Request2bpp + call CloseSRAM + pop af + ld [rSVBK], a + ret + +GetMinimizePic: ; cc6e7 (33:46e7) + ld hl, sScratch + ld bc, $31 tiles +.loop + xor a + ld [hli], a + dec bc + ld a, c + or b + jr nz, .loop + + ld a, [hBattleTurn] + and a + jr z, .player + + ld de, sScratch + $1a tiles + call CopyMinimizePic + ld hl, VTiles2 tile $00 + ld de, sScratch + lb bc, BANK(GetMinimizePic), $31 + ret + +.player + ld de, sScratch + $160 + call CopyMinimizePic + ld hl, VTiles2 tile $31 + ld de, sScratch + lb bc, BANK(GetMinimizePic), $24 + ret + +CopyMinimizePic: ; cc719 (33:4719) + ld hl, MinimizePic + ld bc, $10 + ld a, BANK(MinimizePic) + call FarCopyBytes + ret +; cc725 (33:4725) + +MinimizePic: ; cc725 +INCBIN "gfx/battle/minimize.2bpp" +; cc735 + +BattleAnimCmd_Minimize: ; cc735 (33:4735) + ld a, [rSVBK] + push af + ld a, $1 + ld [rSVBK], a + xor a + call GetSRAMBank + call GetMinimizePic + ld hl, VTiles0 tile $00 + call Request2bpp + call CloseSRAM + pop af + ld [rSVBK], a + ret + +BattleAnimCmd_DropSub: ; cc750 (33:4750) + ld a, [rSVBK] + push af + ld a, $1 + ld [rSVBK], a + + ld a, [CurPartySpecies] ; CurPartySpecies + push af + ld a, [hBattleTurn] + and a + jr z, .player + + callfar DropEnemySub + jr .done + +.player + callfar DropPlayerSub + +.done + pop af + ld [CurPartySpecies], a ; CurPartySpecies + pop af + ld [rSVBK], a + ret + +BattleAnimCmd_BeatUp: ; cc776 (33:4776) + ld a, [rSVBK] + push af + ld a, $1 + ld [rSVBK], a + ld a, [CurPartySpecies] ; CurPartySpecies + push af + + ld a, [wBattleAnimParam] + ld [CurPartySpecies], a ; CurPartySpecies + + ld a, [hBattleTurn] + and a + jr z, .player + + ld hl, BattleMonDVs + predef GetUnownLetter + ld de, VTiles2 tile $00 + predef GetMonFrontpic + jr .done + +.player + ld hl, EnemyMonDVs + predef GetUnownLetter + ld de, VTiles2 tile $31 + predef GetMonBackpic + +.done + pop af + ld [CurPartySpecies], a ; CurPartySpecies + ld b, SCGB_BATTLE_COLORS + call GetSGBLayout + pop af + ld [rSVBK], a + ret + +BattleAnimCmd_OAMOn: ; cc7bb (33:47bb) + xor a + ld [hOAMUpdate], a + ret + +BattleAnimCmd_OAMOff: ; cc7bf (33:47bf) + ld a, $1 + ld [hOAMUpdate], a + ret + +BattleAnimCmd_ClearSprites: ; cc7c4 (33:47c4) + ld hl, BattleAnimFlags + set 3, [hl] + ret + +BattleAnimCmd_F5: ; cc7ca (33:47ca) + ret + +BattleAnimCmd_F6: ; cc7cb (33:47cb) + ret + +BattleAnimCmd_F7: ; cc7cc (33:47cc) + ret + +BattleAnimCmd_Sound: ; cc7cd (33:47cd) + call GetBattleAnimByte + ld e, a + srl a + srl a + ld [wSFXDuration], a + call .GetCryTrack + and 3 + ld [CryTracks], a ; CryTracks + + ld e, a + ld d, 0 + ld hl, .GetPanning + add hl, de + ld a, [hl] + ld [wStereoPanningMask], a + + call GetBattleAnimByte + ld e, a + ld d, 0 + callfar PlayStereoSFX + + ret +; cc7f8 (33:47f8) + +.GetPanning: ; cc7f8 + db $f0, $0f, $f0, $0f +; cc7fc + +.GetCryTrack: ; cc7fc (33:47fc) + ld a, [hBattleTurn] + and a + jr nz, .enemy + + ld a, e + ret + +.enemy + ld a, e + xor 1 + ret + +BattleAnimCmd_Cry: ; cc807 (33:4807) + call GetBattleAnimByte + and 3 + ld e, a + ld d, 0 + ld hl, .CryData +rept 4 + add hl, de +endr + + ld a, [rSVBK] + push af + ld a, 1 + ld [rSVBK], a + + ld a, [hBattleTurn] + and a + jr nz, .enemy + + ld a, $f0 + ld [CryTracks], a ; CryTracks + ld a, [BattleMonSpecies] ; BattleMonSpecies + jr .done_cry_tracks + +.enemy + ld a, $0f + ld [CryTracks], a ; CryTracks + ld a, [EnemyMonSpecies] ; EnemyMon + +.done_cry_tracks + push hl + call LoadCryHeader + pop hl + jr c, .done + + ld a, [hli] + ld c, a + ld a, [hli] + ld b, a + + push hl + ld hl, CryPitch + ld a, [hli] + ld h, [hl] + ld l, a + add hl, bc + ld a, l + ld [CryPitch], a + ld a, h + ld [CryPitch + 1], a + pop hl + + ld a, [hli] + ld c, a + ld b, [hl] + ld hl, CryLength ; CryLength + ld a, [hli] + ld h, [hl] + ld l, a + add hl, bc + + ld a, l + ld [CryLength], a ; CryLength + ld a, h + ld [CryLength + 1], a + ld a, 1 + ld [wStereoPanningMask], a + + callfar _PlayCryHeader + +.done + pop af + ld [rSVBK], a + ret +; cc871 (33:4871) + +.CryData: ; cc871 +; +pitch, +length + dw $0000, $00c0 + dw $0000, $0040 + dw $0000, $0000 + dw $0000, $0000 +; cc881 + + +PlayHitSound: ; cc881 + ld a, [wNumHits] + cp $1 + jr z, .okay + cp $4 + ret nz + +.okay + ld a, [TypeModifier] + and $7f + ret z + + cp 10 + ld de, SFX_DAMAGE + jr z, .play + + ld de, SFX_SUPER_EFFECTIVE + jr nc, .play + + ld de, SFX_NOT_VERY_EFFECTIVE + +.play + call PlaySFX + ret +; cc8a4 + +BattleAnimAssignPals: ; cc8a4 + ld a, [hCGB] + and a + jr nz, .cgb + ld a, [hSGB] + and a + ld a, %11100000 + jr z, .sgb + ld a, %11110000 + +.sgb + ld [wOBP0], a + ld a, %11100100 + ld [wBGP], a + ld [wOBP1], a + ret + +.cgb + ld a, %11100100 + ld [wBGP], a + ld [wOBP0], a + ld [wOBP1], a + call DmgToCgbBGPals + lb de, %11100100, %11100100 + call DmgToCgbObjPals + ret +; cc8d3 + +ClearBattleAnims: ; cc8d3 +; Clear animation block + ld hl, LYOverrides + ld bc, wBattleAnimEnd - LYOverrides +.loop + ld [hl], $0 + inc hl + dec bc + ld a, c + or b + jr nz, .loop + + ld hl, FXAnimID + ld e, [hl] + inc hl + ld d, [hl] + ld hl, BattleAnimations + add hl, de + add hl, de + call GetBattleAnimPointer + call BattleAnimAssignPals + call BattleAnimDelayFrame + ret +; cc8f6 + +BattleAnim_RevertPals: ; cc8f6 + call WaitTop + ld a, %11100100 + ld [wBGP], a + ld [wOBP0], a + ld [wOBP1], a + call DmgToCgbBGPals + lb de, %11100100, %11100100 + call DmgToCgbObjPals + xor a + ld [hSCX], a + ld [hSCY], a + call BattleAnimDelayFrame + ld a, $1 + ld [hBGMapMode], a + ret +; cc91a + +BattleAnim_SetBGPals: ; cc91a + ld [rBGP], a + ld a, [hCGB] + and a + ret z + ld a, [rSVBK] + push af + ld a, $5 + ld [rSVBK], a + ld hl, BGPals + ld de, UnknBGPals + ld a, [rBGP] + ld b, a + ld c, 7 + call CopyPals + ld hl, OBPals + ld de, UnknOBPals + ld a, [rBGP] + ld b, a + ld c, 2 + call CopyPals + pop af + ld [rSVBK], a + ld a, $1 + ld [hCGBPalUpdate], a + ret +; cc94b + +BattleAnim_SetOBPals: ; cc94b + ld [rOBP0], a + ld a, [hCGB] + and a + ret z + ld a, [rSVBK] + push af + ld a, $5 + ld [rSVBK], a + ld hl, OBPals palette PAL_BATTLE_OB_GRAY + ld de, UnknOBPals palette PAL_BATTLE_OB_GRAY + ld a, [rOBP0] + ld b, a + ld c, 2 + call CopyPals + pop af + ld [rSVBK], a + ld a, $1 + ld [hCGBPalUpdate], a + ret +; cc96e + +BattleAnim_UpdateOAM_All: ; cc96e + ld a, $0 + ld [wBattleAnimOAMPointerLo], a + ld hl, ActiveAnimObjects + ld e, 10 +.loop + ld a, [hl] + and a + jr z, .next + ld c, l + ld b, h + push hl + push de + call DoBattleAnimFrame + call BattleAnimOAMUpdate + pop de + pop hl + jr c, .done + +.next + ld bc, BATTLEANIMSTRUCT_LENGTH + add hl, bc + dec e + jr nz, .loop + ld a, [wBattleAnimOAMPointerLo] + ld l, a + ld h, HIGH(Sprites) +.loop2 + ld a, l + cp LOW(SpritesEnd) + jr nc, .done + xor a + ld [hli], a + jr .loop2 + +.done + ret +; cc9a1 diff --git a/engine/anims/bg_effects.asm b/engine/anims/bg_effects.asm new file mode 100644 index 000000000..ab4a8036b --- /dev/null +++ b/engine/anims/bg_effects.asm @@ -0,0 +1,2958 @@ + const_def + const BGSQUARE_SIX + const BGSQUARE_FOUR + const BGSQUARE_TWO + const BGSQUARE_SEVEN + const BGSQUARE_FIVE + const BGSQUARE_THREE + +; BG effects for use in battle animations. + +ExecuteBGEffects: ; c8000 (32:4000) + ld hl, ActiveBGEffects + ld e, 5 +.loop + ld a, [hl] + and a + jr z, .next + ld c, l + ld b, h + push hl + push de + call DoBattleBGEffectFunction + pop de + pop hl +.next + ld bc, 4 + add hl, bc + dec e + jr nz, .loop + ret + +QueueBGEffect: ; c801a (32:401a) + ld hl, ActiveBGEffects + ld e, 5 +.loop + ld a, [hl] + and a + jr z, .load + ld bc, 4 + add hl, bc + dec e + jr nz, .loop + scf + ret + +.load + ld c, l + ld b, h + ld hl, BG_EFFECT_STRUCT_FUNCTION + add hl, bc + ld a, [wBattleAnimTemp0] + ld [hli], a + ld a, [wBattleAnimTemp1] + ld [hli], a + ld a, [wBattleAnimTemp2] + ld [hli], a + ld a, [wBattleAnimTemp3] + ld [hl], a + ret + +EndBattleBGEffect: ; c8043 (32:4043) + ld hl, BG_EFFECT_STRUCT_FUNCTION + add hl, bc + ld [hl], 0 + ret + +DoBattleBGEffectFunction: ; c804a (32:404a) + ld hl, BG_EFFECT_STRUCT_FUNCTION + add hl, bc + ld e, [hl] + ld d, 0 + ld hl, BattleBGEffects + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + jp hl + +BattleBGEffects: ; c805a (32:405a) +; entries correspond to ANIM_BG_* constants + dw BattleBGEffect_End + dw BattleBGEffect_FlashInverted + dw BattleBGEffect_FlashWhite + dw BattleBGEffect_WhiteHues + dw BattleBGEffect_BlackHues + dw BattleBGEffect_AlternateHues + dw BattleBGEffect_06 + dw BattleBGEffect_07 + dw BattleBGEffect_08 + dw BattleBGEffect_HideMon + dw BattleBGEffect_ShowMon + dw BattleBGEffect_EnterMon + dw BattleBGEffect_ReturnMon + dw BattleBGEffect_Surf + dw BattleBGEffect_Whirlpool + dw BattleBGEffect_Teleport + dw BattleBGEffect_NightShade + dw BattleBGEffect_FeetFollow + dw BattleBGEffect_HeadFollow + dw BattleBGEffect_DoubleTeam + dw BattleBGEffect_AcidArmor + dw BattleBGEffect_RapidFlash + dw BattleBGEffect_16 + dw BattleBGEffect_17 + dw BattleBGEffect_18 + dw BattleBGEffect_19 + dw BattleBGEffect_1a + dw BattleBGEffect_1b + dw BattleBGEffect_1c + dw BattleBGEffect_1d + dw BattleBGEffect_1e + dw BattleBGEffect_1f + dw BattleBGEffect_20 + dw BattleBGEffect_Withdraw + dw BattleBGEffect_BounceDown + dw BattleBGEffect_Dig + dw BattleBGEffect_Tackle + dw BattleBGEffect_25 + dw BattleBGEffect_26 + dw BattleBGEffect_27 + dw BattleBGEffect_28 + dw BattleBGEffect_Psychic + dw BattleBGEffect_2a + dw BattleBGEffect_2b + dw BattleBGEffect_2c + dw BattleBGEffect_2d + dw BattleBGEffect_2e + dw BattleBGEffect_2f + dw BattleBGEffect_30 + dw BattleBGEffect_31 + dw BattleBGEffect_32 + dw BattleBGEffect_VibrateMon + dw BattleBGEffect_WobbleMon + dw BattleBGEffect_35 + + +BattleBGEffect_End: ; c80c6 (32:40c6) + call EndBattleBGEffect + ret + +BatttleBGEffects_GetNamedJumptablePointer: ; c80ca (32:40ca) + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + ld l, [hl] + ld h, 0 + add hl, hl + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + ret + +BattleBGEffects_AnonJumptable: ; c80d7 (32:40d7) + pop de + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + ld l, [hl] + ld h, 0 + add hl, hl + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + jp hl + +BattleBGEffects_IncrementJumptable: ; c80e5 (32:40e5) + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + inc [hl] + ret + +BattleBGEffect_FlashInverted: ; c80eb (32:40eb) + ld de, .inverted + jp BattleBGEffect_FlashContinue + +.inverted + db %11100100 ; 3210 + db %00011011 ; 0123 +; c80f3 + +BattleBGEffect_FlashWhite: ; c80f3 (32:40f3) + ld de, .white + jp BattleBGEffect_FlashContinue + +.white + db %11100100 ; 3210 + db %00000000 ; 0000 +; c80fb + +BattleBGEffect_FlashContinue: ; c80fb (32:40fb) +; current timer, flash duration, number of flashes + ld a, $1 + ld [wBattleAnimTemp0], a + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + ld a, [hl] + and a + jr z, .init + dec [hl] + ret + +.init + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + ld [hl], a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + and a + jr nz, .apply_pal + call EndBattleBGEffect + ret + +.apply_pal + dec a + ld [hl], a + and 1 + ld l, a + ld h, 0 + add hl, de + ld a, [hl] + ld [wBGP], a + ret + +BattleBGEffect_WhiteHues: ; c812d (32:412d) + ld de, .Pals + call BattleBGEffect_GetNthDMGPal + jr c, .quit + ld [wBGP], a + ret + +.quit + call EndBattleBGEffect + ret + +.Pals: + db %11100100 + db %11100000 + db %11010000 + db -1 +; c8141 + +BattleBGEffect_BlackHues: ; c8141 (32:4141) + ld de, .Pals + call BattleBGEffect_GetNthDMGPal + jr c, .quit + ld [wBGP], a + ret + +.quit + call EndBattleBGEffect + ret + +.Pals: + db %11100100 + db %11110100 + db %11111000 + db -1 +; c8155 + +BattleBGEffect_AlternateHues: ; c8155 (32:4155) + ld de, .Pals + call BattleBGEffect_GetNthDMGPal + jr c, .quit + ld [wBGP], a + ld [wOBP1], a + ret + +.quit + call EndBattleBGEffect + ret + +.Pals: + db %11100100 + db %11111000 + db %11111100 + db %11111000 + db %11100100 + db %10010000 + db %01000000 + db %10010000 + db -2 +; c8171 + +BattleBGEffect_06: ; c8171 (32:4171) + call BattleBGEffects_CheckSGB + jr nz, .sgb + ld de, .PalsCGB + jr .okay + +.sgb + ld de, .PalsSGB +.okay + call BattleBGEffect_GetNthDMGPal + ld [wOBP0], a + ret + +.PalsCGB: + db %11100100 + db %10010000 + db -2 + +.PalsSGB: + db %11110000 + db %11000000 + db -2 +; c818b + +BattleBGEffect_07: ; c818b (32:418b) + call BattleBGEffects_CheckSGB + jr nz, .sgb + ld de, .PalsCGB + jr .okay + +.sgb + ld de, .PalsSGB +.okay + call BattleBGEffect_GetNthDMGPal + ld [wOBP0], a + ret + +.PalsCGB: + db %11100100 + db %11011000 + db -2 + +.PalsSGB: + db %11110000 + db %11001100 + db -2 +; c81a5 + +BattleBGEffect_08: ; c81a5 (32:41a5) + ld de, .Pals + call BattleBGEffect_GetNthDMGPal + ld [wBGP], a + ret + +.Pals: + db %00011011 + db %01100011 + db %10000111 + db -2 +; c81b3 + +BattleBGEffect_HideMon: ; c81b3 (32:41b3) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw BattleBGEffects_IncrementJumptable + dw BattleBGEffects_IncrementJumptable + dw BattleBGEffects_IncrementJumptable + dw .four + + +.zero + call BattleBGEffects_IncrementJumptable + push bc + call BGEffect_CheckBattleTurn + jr nz, .player_side + hlcoord 12, 0 + lb bc, 7, 7 + jr .got_pointer + +.player_side + hlcoord 2, 6 + lb bc, 6, 6 +.got_pointer + call ClearBox + pop bc + xor a + ld [hBGMapThird], a + ld a, $1 + ld [hBGMapMode], a + ret + +.four + xor a + ld [hBGMapMode], a + call EndBattleBGEffect + ret + +BattleBGEffect_ShowMon: ; c81ea (32:41ea) + call BGEffect_CheckFlyDigStatus + jr z, .not_flying + call EndBattleBGEffect + ret + +.not_flying + call BGEffect_CheckBattleTurn + jr nz, .player_side + ld de, .EnemyData + jr .got_pointer + +.player_side + ld de, .PlayerData +.got_pointer + ld a, e + ld [wBattleAnimTemp1], a + ld a, d + ld [wBattleAnimTemp2], a + call BattleBGEffect_RunPicResizeScript + ret + +.PlayerData: + db 0, $31, 0 + db -1 +.EnemyData: + db 3, $00, 3 + db -1 +; c8214 + +BattleBGEffect_FeetFollow: ; c8214 (32:4214) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw BattleBGEffects_IncrementJumptable + dw BattleBGEffects_IncrementJumptable + dw BattleBGEffects_IncrementJumptable + dw .five + + +.zero + call BGEffect_CheckFlyDigStatus + jr z, .not_flying_digging + ld hl, wNumActiveBattleAnims + inc [hl] + call EndBattleBGEffect + ret + +.not_flying_digging + call BattleBGEffects_IncrementJumptable + push bc + call BGEffect_CheckBattleTurn + jr nz, .player_turn + ld a, ANIM_OBJ_PLAYERFEETFOLLOW + ld [wBattleAnimTemp0], a + ld a, 16 * 8 + 4 + jr .okay + +.player_turn + ld a, ANIM_OBJ_ENEMYFEETFOLLOW + ld [wBattleAnimTemp0], a + ld a, 6 * 8 +.okay + ld [wBattleAnimTemp1], a + ld a, 8 * 8 + ld [wBattleAnimTemp2], a + xor a + ld [wBattleAnimTemp3], a + call _QueueBattleAnimation + pop bc + ret + +.one + call BattleBGEffects_IncrementJumptable + push bc + call BGEffect_CheckBattleTurn + jr nz, .player_turn_2 + hlcoord 12, 6 + lb bc, 1, 7 + jr .okay2 + +.player_turn_2 + hlcoord 2, 6 + lb bc, 1, 6 +.okay2 + call ClearBox + ld a, $1 + ld [hBGMapMode], a + pop bc + ret + +.five + xor a + ld [hBGMapMode], a + call EndBattleBGEffect + ret + +BattleBGEffect_HeadFollow: ; c8281 (32:4281) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw BattleBGEffects_IncrementJumptable + dw BattleBGEffects_IncrementJumptable + dw BattleBGEffects_IncrementJumptable + dw .five + + +.zero + call BGEffect_CheckFlyDigStatus + jr z, .not_flying_digging + ld hl, wNumActiveBattleAnims + inc [hl] + call EndBattleBGEffect + ret + +.not_flying_digging + call BattleBGEffects_IncrementJumptable + push bc + call BGEffect_CheckBattleTurn + jr nz, .player_turn + ld a, ANIM_OBJ_BA + ld [wBattleAnimTemp0], a + ld a, 16 * 8 + 4 + jr .okay + +.player_turn + ld a, ANIM_OBJ_BB + ld [wBattleAnimTemp0], a + ld a, 6 * 8 +.okay + ld [wBattleAnimTemp1], a + ld a, 8 * 8 + ld [wBattleAnimTemp2], a + xor a + ld [wBattleAnimTemp3], a + call _QueueBattleAnimation + pop bc + ret + +.one + call BattleBGEffects_IncrementJumptable + push bc + call BGEffect_CheckBattleTurn + jr nz, .player_turn_2 + hlcoord 12, 5 + lb bc, 2, 7 + jr .okay2 + +.player_turn_2 + hlcoord 2, 6 + lb bc, 2, 6 +.okay2 + call ClearBox + ld a, $1 + ld [hBGMapMode], a + pop bc + ret + +.five + xor a + ld [hBGMapMode], a + call EndBattleBGEffect + ret + +_QueueBattleAnimation: ; c82ee (32:42ee) + callfar QueueBattleAnimation + ret + +BattleBGEffect_27: ; c82f5 (32:42f5) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw BattleBGEffects_IncrementJumptable + dw BattleBGEffects_IncrementJumptable + dw .four + + +.zero + call BattleBGEffects_IncrementJumptable + call BGEffect_CheckBattleTurn + ld [hl], a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + and a + jr z, .user + ld a, $9 + jr .okay + +.user + ld a, $8 +.okay + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], a + ret + +.one + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + and a + jr z, .user_2 + hlcoord 0, 6 + lb de, 8, 6 +.row1 + push de + push hl +.col1 + inc hl + ld a, [hld] + ld [hli], a + dec d + jr nz, .col1 + pop hl + ld de, SCREEN_WIDTH + add hl, de + pop de + dec e + jr nz, .row1 + jr .okay2 + +.user_2 + hlcoord 19, 0 + lb de, 8, 7 +.row2 + push de + push hl +.col2 + dec hl + ld a, [hli] + ld [hld], a + dec d + jr nz, .col2 + pop hl + ld de, SCREEN_WIDTH + add hl, de + pop de + dec e + jr nz, .row2 +.okay2 + xor a + ld [hBGMapThird], a + ld a, $1 + ld [hBGMapMode], a + call BattleBGEffects_IncrementJumptable + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + dec [hl] + ret + +.four + xor a + ld [hBGMapMode], a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + and a + jr z, .done + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + ld [hl], $1 + ret + +.done + call EndBattleBGEffect + ret + +BattleBGEffect_EnterMon: ; c837b (32:437b) + call BGEffect_CheckBattleTurn + jr nz, .player_turn + ld de, .EnemyData + jr .okay + +.player_turn + ld de, .PlayerData +.okay + ld a, e + ld [wBattleAnimTemp1], a + ld a, d + ld [wBattleAnimTemp2], a + call BattleBGEffect_RunPicResizeScript + ret + +.PlayerData: + db 2, $31, 2 + db 1, $31, 1 + db 0, $31, 0 + db -1 +.EnemyData: + db 5, $00, 5 + db 4, $00, 4 + db 3, $00, 3 + db -1 +; c83a8 + +BattleBGEffect_ReturnMon: ; c83a8 (32:43a8) + call BGEffect_CheckBattleTurn + jr nz, .player_turn + ld de, .EnemyData + jr .okay + +.player_turn + ld de, .PlayerData +.okay + ld a, e + ld [wBattleAnimTemp1], a + ld a, d + ld [wBattleAnimTemp2], a + call BattleBGEffect_RunPicResizeScript + ret + +.PlayerData: + db 0, $31, 0 + db -2, $66, 0 + db 1, $31, 1 + db -2, $44, 1 + db 2, $31, 2 + db -2, $22, 2 + db -3, $00, 0 + db -1 +.EnemyData: + db 3, $00, 3 + db -2, $77, 3 + db 4, $00, 4 + db -2, $55, 4 + db 5, $00, 5 + db -2, $33, 5 + db -3, $00, 0 + db -1 +; c83ed + +BattleBGEffect_RunPicResizeScript: ; c83ed (32:43ed) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw BattleBGEffects_IncrementJumptable + dw BattleBGEffects_IncrementJumptable + dw .restart + dw .end + + +.zero + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld e, [hl] + ld d, $0 + inc [hl] + ld a, [wBattleAnimTemp1] + ld l, a + ld a, [wBattleAnimTemp2] + ld h, a + add hl, de + add hl, de + add hl, de + ld a, [hl] + cp -1 + jr z, .end + cp -2 + jr z, .clear + cp -3 + jr z, .skip + call .PlaceGraphic +.skip + call BattleBGEffects_IncrementJumptable + ld a, $1 + ld [hBGMapMode], a + ret + +.clear + call .ClearBox + jr .zero + +.restart + xor a + ld [hBGMapMode], a + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + ld [hl], $0 + ret + +.end + xor a + ld [hBGMapMode], a + call EndBattleBGEffect + ret + +.ClearBox: +; get dims + push bc + inc hl + ld a, [hli] + ld b, a + and $f + ld c, a + ld a, b + swap a + and $f + ld b, a +; get coords + ld e, [hl] + ld d, 0 + ld hl, .Coords + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + call ClearBox + pop bc + ret + +.PlaceGraphic: +; get dims + push bc + push hl + ld e, [hl] + ld d, 0 + ld hl, .BGSquares + add hl, de + add hl, de + add hl, de + ld a, [hli] + ld b, a + and $f + ld c, a + ld a, b + swap a + and $f + ld b, a +; store pointer + ld e, [hl] + inc hl + ld d, [hl] +; get byte + pop hl + inc hl + ld a, [hli] + ld [wBattleAnimTemp0], a +; get coord + push de + ld e, [hl] + ld d, 0 + ld hl, .Coords + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + pop de +; fill box +.row + push bc + push hl + ld a, [wBattleAnimTemp0] + ld b, a +.col + ld a, [de] + add b + ld [hli], a + inc de + dec c + jr nz, .col + pop hl + ld bc, SCREEN_WIDTH + add hl, bc + pop bc + dec b + jr nz, .row + pop bc + ret + +.Coords: + dwcoord 2, 6 + dwcoord 3, 8 + dwcoord 4, 10 + dwcoord 12, 0 + dwcoord 13, 2 + dwcoord 14, 4 + +.BGSquares: +bgsquare: MACRO + dn \1, \2 + dw \3 +endm + + bgsquare 6, 6, .SixBySix + bgsquare 4, 4, .FourByFour + bgsquare 2, 2, .TwoByTwo + bgsquare 7, 7, .SevenBySeven + bgsquare 5, 5, .FiveByFive + bgsquare 3, 3, .ThreeByThree + +.SixBySix: + db $00, $06, $0c, $12, $18, $1e + db $01, $07, $0d, $13, $19, $1f + db $02, $08, $0e, $14, $1a, $20 + db $03, $09, $0f, $15, $1b, $21 + db $04, $0a, $10, $16, $1c, $22 + db $05, $0b, $11, $17, $1d, $23 + +.FourByFour: + db $00, $0c, $12, $1e + db $02, $0e, $14, $20 + db $03, $0f, $15, $21 + db $05, $11, $17, $23 + +.TwoByTwo: + db $00, $1e + db $05, $23 + +.SevenBySeven: + db $00, $07, $0e, $15, $1c, $23, $2a + db $01, $08, $0f, $16, $1d, $24, $2b + db $02, $09, $10, $17, $1e, $25, $2c + db $03, $0a, $11, $18, $1f, $26, $2d + db $04, $0b, $12, $19, $20, $27, $2e + db $05, $0c, $13, $1a, $21, $28, $2f + db $06, $0d, $14, $1b, $22, $29, $30 + +.FiveByFive: + db $00, $07, $15, $23, $2a + db $01, $08, $16, $24, $2b + db $03, $0a, $18, $26, $2d + db $05, $0c, $1a, $28, $2f + db $06, $0d, $1b, $29, $30 + +.ThreeByThree: + db $00, $15, $2a + db $03, $18, $2d + db $06, $1b, $30 +; c8545 + +BattleBGEffect_Surf: ; c8545 (32:4545) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + lb de, 2, 2 + call InitSurfWaves + +.one + ld a, [hLCDCPointer] + and a + ret z + push bc + call .RotatewSurfWaveBGEffect + pop bc + ret + +.two + call BattleAnim_ResetLCDStatCustom + ret + +.RotatewSurfWaveBGEffect: + ld hl, wSurfWaveBGEffect + ld de, wSurfWaveBGEffect + 1 + ld c, wSurfWaveBGEffectEnd - wSurfWaveBGEffect - 1 + ld a, [hl] + push af +.loop + ld a, [de] + inc de + ld [hli], a + dec c + jr nz, .loop + pop af + ld [hl], a + ld de, LYOverridesBackup + ld hl, wSurfWaveBGEffect + ld bc, $0 +.loop2 + ld a, [hLYOverrideStart] + cp e + jr nc, .load_zero + push hl + add hl, bc + ld a, [hl] + pop hl + jr .okay + +.load_zero + xor a +.okay + ld [de], a + ld a, c + inc a + and $3f + ld c, a + inc de + ld a, e + cp $5f + jr c, .loop2 + ret + +BattleBGEffect_Whirlpool: ; c8599 (32:4599) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCY - $ff00 + ld [hLCDCPointer], a + xor a + ld [hLYOverrideStart], a + ld a, $5e + ld [hLYOverrideEnd], a + lb de, 2, 2 + call Functionc8f2e + ret + +.one + call BattleBGEffect_WavyScreenFX + ret + +.two + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_30: ; c85c2 (32:45c2) + call BattleBGEffects_ClearLYOverrides + ld a, rSCY - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + call EndBattleBGEffect + ret + +BattleBGEffect_31: ; c85ce (32:45ce) + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + ld e, a + add $4 + ld [hl], a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + and $f0 + swap a + xor $ff + add $4 + ld d, a + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + ld a, [hl] + ld [wBattleAnimTemp0], a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + cp $20 + jr nc, .done + inc [hl] + inc [hl] + call Functionc8f9a + ret + +.done + call BattleBGEffects_ClearLYOverrides + call EndBattleBGEffect + ret + +BattleBGEffect_32: ; c8603 (32:4603) + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_Psychic: ; c8607 (32:4607) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + ld [hLCDCPointer], a + xor a + ld [hLYOverrideStart], a + ld a, $5f + ld [hLYOverrideEnd], a + lb de, 6, 5 + call Functionc8f2e + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 + ret + +.one + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + inc [hl] + and $3 + ret nz + call BattleBGEffect_WavyScreenFX + ret + +.two + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_Teleport: ; c863f (32:463f) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + lb de, 6, 5 + call Functionc8f2e + ret + +.one + call BattleBGEffect_WavyScreenFX + ret + +.two + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_NightShade: ; c8662 (32:4662) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCY - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld e, [hl] + ld d, 2 + call Functionc8f2e + ret + +.one + call BattleBGEffect_WavyScreenFX + ret + +.two + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_DoubleTeam: ; c8689 (32:4689) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw .three + dw .four + dw .five + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld [hl], $0 + ret + +.one + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + cp $10 + jr nc, .next + inc [hl] + call .UpdateLYOverrides + ret + +.three + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + cp $ff + jr z, .next + dec [hl] + call .UpdateLYOverrides + ret + +.next + call BattleBGEffects_IncrementJumptable + ret + +.two + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + ld d, $2 + call BattleBGEffects_Sine + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + add [hl] + call .UpdateLYOverrides + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + add $4 + ld [hl], a + +.four + ret + +.UpdateLYOverrides: + ld e, a + xor $ff + inc a + ld d, a + ld h, HIGH(LYOverridesBackup) + ld a, [hLYOverrideStart] + ld l, a + ld a, [hLYOverrideEnd] + sub l + srl a + push af +.loop + ld [hl], e + inc hl + ld [hl], d + inc hl + dec a + jr nz, .loop + pop af + ret nc + ld [hl], e + ret + +.five + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_AcidArmor: ; c8709 (32:4709) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCY - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld e, [hl] + ld d, 2 + call Functionc8f2e + ld h, HIGH(LYOverridesBackup) + ld a, [hLYOverrideEnd] + ld l, a + ld [hl], $0 + dec l + ld [hl], $0 + ret + +.one + ld a, [hLYOverrideEnd] + ld l, a + ld h, HIGH(LYOverridesBackup) + ld e, l + ld d, h + dec de +.loop + ld a, [de] + dec de + ld [hld], a + ld a, [hLYOverrideStart] + cp l + jr nz, .loop + ld [hl], $90 + ld a, [hLYOverrideEnd] + ld l, a + ld a, [hl] + cp $1 + jr c, .okay + cp $90 + jr z, .okay + ld [hl], $0 +.okay + dec l + ld a, [hl] + cp $2 + ret c + cp $90 + ret z + ld [hl], $0 + ret + +.two + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_Withdraw: ; c8761 (32:4761) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCY - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld [hl], $1 + ret + +.one + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + and $3f + ld d, a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + cp d + ret nc + call BGEffect_DisplaceLYOverridesBackup + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + rlca + rlca + and $3 + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + add [hl] + ld [hl], a + ret + +.two + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_Dig: ; c87a7 (32:47a7) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw .three + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCY - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld [hl], $2 + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 + ret + +.one + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + and a + jr z, .next + dec [hl] + ret + +.next + ld [hl], $10 + call BattleBGEffects_IncrementJumptable +.two + ld a, [hLYOverrideStart] + ld l, a + ld a, [hLYOverrideEnd] + sub l + dec a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + cp [hl] + ret c + ld a, [hl] + push af + and $7 + jr nz, .skip + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + dec [hl] +.skip + pop af + call BGEffect_DisplaceLYOverridesBackup + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + inc [hl] + inc [hl] + ret + +.three + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_Tackle: ; c8805 (32:4805) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw Tackle_BGEffect25_2d_one + dw Tackle_BGEffect25_2d_two + dw .three + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 + call BGEffect_CheckBattleTurn + jr nz, .player_side + ld a, 2 + jr .okay + +.player_side + ld a, -2 +.okay + ld [hl], a + ret + +.three + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_25: ; c8837 (32:4837) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw Tackle_BGEffect25_2d_one + dw Tackle_BGEffect25_2d_two + dw .three + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + call BattleBGEffect_SetLCDStatCustoms2 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 + call BGEffect_CheckBattleTurn + jr nz, .player_side + ld a, 2 + jr .okay + +.player_side + ld a, -2 +.okay + ld [hl], a + ret + +.three + call BattleAnim_ResetLCDStatCustom + ret + +Tackle_BGEffect25_2d_one: + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + cp -8 + jr z, .reached_limit + cp 8 + jr nz, .finish +.reached_limit + call BattleBGEffects_IncrementJumptable +.finish + call Functionc88a5 + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + add [hl] + ld [hl], a + ret + +Tackle_BGEffect25_2d_two: + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + and a + jr nz, .asm_c8893 + call BattleBGEffects_IncrementJumptable +.asm_c8893 + call Functionc88a5 + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + xor $ff + inc a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + add [hl] + ld [hl], a + ret + +Functionc88a5: ; c88a5 (32:48a5) + push af + ld a, [FXAnimID + 1] ; FXAnimID + 1 + or a + jr nz, .not_rollout + ld a, [FXAnimID] ; FXAnimID + cp ROLLOUT + jr z, .rollout +.not_rollout + pop af + jp BGEffect_FillLYOverridesBackup + +.rollout + ld a, [hLYOverrideStart] + ld d, a + ld a, [hLYOverrideEnd] + sub d + ld d, a + ld h, HIGH(LYOverridesBackup) + ld a, [hSCY] + or a + jr nz, .skip1 + ld a, [hLYOverrideStart] + or a + jr z, .skip2 + dec a + ld l, a + ld [hl], $0 + jr .skip2 + +.skip1 + ld a, [hLYOverrideEnd] + dec a + ld l, a + ld [hl], $0 +.skip2 + ld a, [hSCY] + ld l, a + ld a, [hLYOverrideStart] + sub l + jr nc, .skip3 + xor a + dec d +.skip3 + ld l, a + pop af +.loop + ld [hli], a + dec d + jr nz, .loop + ret + +BattleBGEffect_2d: ; c88e7 (32:48e7) + call BattleBGEffects_AnonJumptable +.anon_dw + dw BGEffect2d_2f_zero + dw Tackle_BGEffect25_2d_one + dw Tackle_BGEffect25_2d_two + dw .three + + +.three + call BattleAnim_ResetLCDStatCustom + ret + +BGEffect2d_2f_zero: + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 + call BGEffect_CheckBattleTurn + jr nz, .player_turn + ld a, -2 + jr .okay + +.player_turn + ld a, 2 +.okay + ld [hl], a + ret + +BattleBGEffect_2f: ; c8919 (32:4919) + call BattleBGEffects_AnonJumptable +.anon_dw + dw BGEffect2d_2f_zero + dw Tackle_BGEffect25_2d_one + dw .two + dw Tackle_BGEffect25_2d_two + dw .four + +.four + call BattleAnim_ResetLCDStatCustom +.two + ret + +BattleBGEffect_26: ; c892a (32:492a) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 + ret + +.one + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + ld d, $8 + call BattleBGEffects_Sine + call BGEffect_FillLYOverridesBackup + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + add $4 + ld [hl], a + ret + +.two + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_2c: ; c8964 (32:4964) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + xor a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld [hli], a + ld [hl], a + ret + +.one + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + ld d, $6 + call BattleBGEffects_Sine + push af + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + ld d, $2 + call BattleBGEffects_Sine + ld e, a + pop af + add e + call BGEffect_FillLYOverridesBackup + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + add $8 + ld [hl], a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + add $2 + ld [hl], a + ret + +.two + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_28: ; c89b5 (32:49b5) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ret + +.one + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + cp $20 + ret nc + inc [hl] + ld d, a + ld e, 4 + call Functionc8f2e + ret + +.two + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + and a + jr z, .reset + dec [hl] + ld d, a + ld e, 4 + call Functionc8f2e + ret + +.reset + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_BounceDown: ; c89ee (32:49ee) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCY - $ff00 + call BattleBGEffect_SetLCDStatCustoms2 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld [hl], $1 + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $20 + ret + +.one + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + cp $38 + ret nc + push af + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + ld d, $10 + call BattleBGEffects_Cosine + add $10 + ld d, a + pop af + add d + call BGEffect_DisplaceLYOverridesBackup + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + inc [hl] + inc [hl] + ret + +.two + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_2a: ; c8a3a (32:4a3a) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw .three + dw .four + dw .five + +.zero + call BattleBGEffects_IncrementJumptable + ld a, $e4 + call BattleBGEffects_SetLYOverrides + ld a, $47 + call BattleBGEffect_SetLCDStatCustoms1 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld a, [hLYOverrideStart] + ld l, a + ld h, HIGH(LYOverridesBackup) +.loop + ld a, [hLYOverrideEnd] + cp l + jr z, .done + xor a + ld [hli], a + jr .loop + +.done + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 +.one +.four + ret + +.two + call .GetLYOverride + jr nc, .next + call .SetLYOverridesBackup + ret + +.next + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 + ld a, [hLYOverrideStart] + inc a + ld [hLYOverrideStart], a + call BattleBGEffects_IncrementJumptable + ret + +.three + call .GetLYOverride + jr nc, .finish + call .SetLYOverridesBackup + ld a, [hLYOverrideEnd] + dec a + ld l, a + ld [hl], e + ret + +.finish + call BattleBGEffects_IncrementJumptable + ret + +.SetLYOverridesBackup: + ld e, a + ld a, [hLYOverrideStart] + ld l, a + ld a, [hLYOverrideEnd] + sub l + srl a + ld h, HIGH(LYOverridesBackup) +.loop2 + ld [hl], e + inc hl + inc hl + dec a + jr nz, .loop2 + ret + +.five + call BattleBGEffects_ResetVideoHRAM + ret + +.GetLYOverride: + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + inc [hl] + srl a + srl a + srl a + ld e, a + ld d, 0 + ld hl, .data + add hl, de + ld a, [hl] + cp $ff + ret + +.data + db $00, $40, $90, $e4 + db -1 +; c8acc + +BattleBGEffect_2b: ; c8acc (32:4acc) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + + +.zero + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld [hl], $40 + ret + +.one + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + and a + jr z, .done + dec [hl] + srl a + srl a + srl a + and $f + ld d, a + ld e, a + call Functionc8f2e + ret + +.done + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_1c: ; c8b00 (32:4b00) + ld a, [hCGB] + and a + jr nz, .cgb + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero + call BattleBGEffects_IncrementJumptable + ld a, $e4 + call BattleBGEffects_SetLYOverrides + ld a, rBGP - $ff00 + ld [hLCDCPointer], a + xor a + ld [hLYOverrideStart], a + ld a, $60 + ld [hLYOverrideEnd], a + ret + +.one + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + inc [hl] + ld e, a + and $7 + ret nz + ld a, e + and $18 + sla a + swap a + sla a + ld e, a + ld d, $0 + push bc + call BGEffect_CheckBattleTurn + jr nz, .player + ld hl, .CGB_DMGEnemyData + add hl, de + ld a, [hli] + ld [wOBP1], a + ld d, a + ld e, [hl] + lb bc, $2f, $30 + jr .okay + +.player + ld hl, .DMG_PlayerData + add hl, de + ld d, [hl] + inc hl + ld a, [hl] + ld [wOBP1], a + ld e, a + lb bc, $37, $28 +.okay + call .DMG_LYOverrideLoads + pop bc + ret + +.two + call BattleBGEffects_ResetVideoHRAM + ld a, $e4 + ld [wBGP], a + ld [wOBP1], a + ret + +.DMG_LYOverrideLoads: + ld hl, LYOverridesBackup +.loop1 + ld [hl], d + inc hl + dec b + jr nz, .loop1 +.loop2 + ld [hl], e + inc hl + dec c + jr nz, .loop2 + ret + +.cgb + ld de, .Jumptable + call BatttleBGEffects_GetNamedJumptablePointer + jp hl + +.Jumptable: + dw .cgb_zero + dw .cgb_one + dw .cgb_two +.cgb_zero + call BattleBGEffects_IncrementJumptable + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 + ret + +.cgb_one + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + inc [hl] + ld e, a + and $7 + ret nz + ld a, e + and $18 + sla a + swap a + sla a + ld e, a + ld d, 0 + call BGEffect_CheckBattleTurn + jr nz, .player_2 + ld hl, .CGB_DMGEnemyData + add hl, de + ld a, [hli] + push hl + call BGEffects_LoadBGPal1_OBPal0 + pop hl + ld a, [hl] + call BGEffects_LoadBGPal0_OBPal1 + ret + +.player_2 + ld hl, .CGB_DMGEnemyData + add hl, de + ld a, [hli] + push hl + call BGEffects_LoadBGPal0_OBPal1 + pop hl + ld a, [hl] + call BGEffects_LoadBGPal1_OBPal0 + ret + +.cgb_two + ld a, $e4 + call BGEffects_LoadBGPal0_OBPal1 + ld a, $e4 + call BGEffects_LoadBGPal1_OBPal0 + call EndBattleBGEffect + ret + +.CGB_DMGEnemyData: + db $e4, $e4 + db $f8, $90 + db $fc, $40 + db $f8, $90 +.DMG_PlayerData: + db $e4, $e4 + db $90, $f8 + db $40, $fc + db $90, $f8 +; c8be8 + +BattleBGEffect_RapidFlash: ; c8be8 (32:4be8) + ld de, .FlashPals + call BGEffect_RapidCyclePals + ret + +.FlashPals: + db $e4, $6c, $fe +; c8bf2 + +BattleBGEffect_16: ; c8bf2 (32:4bf2) + ld de, .Pals + call BGEffect_RapidCyclePals + ret + +.Pals: + db $e4, $90, $40, $ff +; c8bfd + +BattleBGEffect_17: ; c8bfd (32:4bfd) + ld de, .Pals + call BGEffect_RapidCyclePals + ret + +.Pals: + db $e4, $f8, $fc, $ff +; c8c08 + +BattleBGEffect_18: ; c8c08 (32:4c08) + ld de, .Pals + call BGEffect_RapidCyclePals + ret + +.Pals: + db $e4, $90, $40, $90, $fe +; c8c14 + +BattleBGEffect_19: ; c8c14 (32:4c14) + ld de, .Pals + call BGEffect_RapidCyclePals + ret + +.Pals: + db $e4, $f8, $fc, $f8, $fe +; c8c20 + +BattleBGEffect_1a: ; c8c20 (32:4c20) + ld de, .Pals + call BGEffect_RapidCyclePals + ret + +.Pals: + db $e4, $f8, $fc, $f8, $e4, $90, $40, $90, $fe +; c8c30 + +BattleBGEffect_1b: ; c8c30 (32:4c30) + ld de, .Pals + call BGEffect_RapidCyclePals + ret + +.Pals: + db $e4, $fc, $e4, $00, $fe +; c8c3c + +BattleBGEffect_1d: ; c8c3c (32:4c3c) + ld de, .Pals + call BGEffect_RapidCyclePals + ret + +.Pals: + db $e4, $90, $40, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $40, $90, $e4, $ff +; c8c55 + +BattleBGEffect_1e: ; c8c55 (32:4c55) + ld de, .Pals + call BGEffect_RapidCyclePals + ret + +.Pals: + db $00, $40, $90, $e4, $ff +; c8c61 + +BattleBGEffect_VibrateMon: ; c8c61 (32:4c61) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + + +.zero ; c8c68 (32:4c68) + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + call BattleBGEffect_SetLCDStatCustoms1 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld [hl], $1 + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $20 + ret + +.one ; c8c85 (32:4c85) + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + and a + jr z, .finish + dec [hl] + and $1 + ret nz + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + xor $ff + inc a + ld [hl], a + call BGEffect_FillLYOverridesBackup + ret + +.finish + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_WobbleMon: ; c8ca2 (32:4ca2) + call BattleBGEffects_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + + +.zero ; c8cab (32:4cab) + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_ClearLYOverrides + ld a, rSCX - $ff00 + ld [hLCDCPointer], a + xor a + ld [hLYOverrideStart], a + ld a, $37 + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 + ret + +.one ; c8cc3 (32:4cc3) + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + cp $40 + jr nc, .two + ld d, $6 + call BattleBGEffects_Sine + call BGEffect_FillLYOverridesBackup + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + add $2 + ld [hl], a + ret + +.two ; c8cdd (32:4cdd) + call BattleAnim_ResetLCDStatCustom + ret + +BattleBGEffect_2e: ; c8ce1 (32:4ce1) + call Functionc8d0b + jr c, .xor_a + bit 7, a + jr z, .okay +.xor_a + xor a +.okay + push af + call DelayFrame + pop af + ld [hSCY], a + xor $ff + inc a + ld [AnimObject01_YOffset], a + ret + +BattleBGEffect_1f: ; c8cf9 (32:4cf9) + call Functionc8d0b + jr nc, .skip + xor a +.skip + ld [hSCX], a + ret + +BattleBGEffect_20: ; c8d02 (32:4d02) + call Functionc8d0b + jr nc, .skip + xor a +.skip + ld [hSCY], a + ret + +Functionc8d0b: ; c8d0b (32:4d0b) + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + ld a, [hl] + and a + jr nz, .okay + call EndBattleBGEffect + scf + ret + +.okay + dec [hl] + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + and $f + jr z, .every_16_frames + dec [hl] + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + and a + ret + +.every_16_frames + ld a, [hl] + swap a + or [hl] + ld [hl], a + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + xor $ff + inc a + ld [hl], a + and a + ret + +BattleBGEffect_35: ; c8d3a (32:4d3a) + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + cp $40 + jr nc, .finish + ld d, $6 + call BattleBGEffects_Sine + ld [hSCX], a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + add $2 + ld [hl], a + ret + +.finish + xor a + ld [hSCX], a + ret + +BattleBGEffect_GetNthDMGPal: ; c8d57 (32:4d57) + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + ld a, [hl] + and a + jr z, .zero + dec [hl] + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + call BattleBGEffect_GetNextDMGPal + ret + +.zero + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + ld hl, BG_EFFECT_STRUCT_JT_INDEX + add hl, bc + ld [hl], a + call BattleBGEffect_GetFirstDMGPal + ret + +BGEffect_RapidCyclePals: ; c8d77 (32:4d77) + ld a, [hCGB] + and a + jr nz, .cgb + push de + ld de, .Jumptable_DMG + call BatttleBGEffects_GetNamedJumptablePointer + pop de + jp hl + +.Jumptable_DMG: + dw .zero_dmg + dw .one_dmg + dw .two_dmg + + +.zero_dmg ; c8d8b (32:4d8b) + call BattleBGEffects_IncrementJumptable + ld a, $e4 + call BattleBGEffects_SetLYOverrides + ld a, $47 + call BattleBGEffect_SetLCDStatCustoms1 + ld a, [hLYOverrideEnd] + inc a + ld [hLYOverrideEnd], a + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + ld [hl], $0 + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld [hl], a + ret + +.one_dmg ; c8daa (32:4daa) + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + and $f + jr z, .okay_1_dmg + dec [hl] + ret + +.okay_1_dmg + ld a, [hl] + swap a + or [hl] + ld [hl], a + call BattleBGEffect_GetFirstDMGPal + jr c, .okay_2_dmg + call BGEffect_FillLYOverridesBackup + ret + +.okay_2_dmg + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + dec [hl] + ret + +.two_dmg ; c8dc9 (32:4dc9) + call BattleBGEffects_ResetVideoHRAM + ld a, %11100100 + ld [rBGP], a + call EndBattleBGEffect + ret + +.cgb + push de + ld de, .Jumptable_CGB + call BatttleBGEffects_GetNamedJumptablePointer + pop de + jp hl + +.Jumptable_CGB: ; c8ddd (32:4ddd) + dw .zero_cgb + dw .one_cgb + dw .two_cgb + dw .three_cgb + dw .four_cgb + + +.zero_cgb ; c8de7 (32:4de7) + call BGEffect_CheckBattleTurn + jr nz, .player_turn_cgb + call BattleBGEffects_IncrementJumptable + call BattleBGEffects_IncrementJumptable +.player_turn_cgb + call BattleBGEffects_IncrementJumptable + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + ld [hl], $0 + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld [hl], a + ret + +.one_cgb ; c8e02 (32:4e02) + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + and $f + jr z, .okay_1_cgb + dec [hl] + ret + +.okay_1_cgb + ld a, [hl] + swap a + or [hl] + ld [hl], a + call BattleBGEffect_GetFirstDMGPal + jr c, .okay_2_cgb + call BGEffects_LoadBGPal0_OBPal1 + ret + +.okay_2_cgb + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + dec [hl] + ret + +.two_cgb ; c8e21 (32:4e21) + ld a, $e4 + call BGEffects_LoadBGPal0_OBPal1 + call EndBattleBGEffect + ret + +.three_cgb ; c8e2a (32:4e2a) + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hl] + and $f + jr z, .okay_3_cgb + dec [hl] + ret + +.okay_3_cgb + ld a, [hl] + swap a + or [hl] + ld [hl], a + call BattleBGEffect_GetFirstDMGPal + jr c, .okay_4_cgb + call BGEffects_LoadBGPal1_OBPal0 + ret + +.okay_4_cgb + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + dec [hl] + ret + +.four_cgb ; c8e49 (32:4e49) + ld a, $e4 + call BGEffects_LoadBGPal1_OBPal0 + call EndBattleBGEffect + ret + +BGEffects_LoadBGPal0_OBPal1: ; c8e52 (32:4e52) + ld h, a + ld a, [rSVBK] + push af + ld a, $5 + ld [rSVBK], a + ld a, h + push bc + push af + ld hl, BGPals + ld de, UnknBGPals + ld b, a + ld c, $1 + call CopyPals + ld hl, OBPals + 8 + ld de, UnknOBPals + 8 + pop af + ld b, a + ld c, $1 + call CopyPals + pop bc + pop af + ld [rSVBK], a + ld a, $1 + ld [hCGBPalUpdate], a + ret + +BGEffects_LoadBGPal1_OBPal0: ; c8e7f (32:4e7f) + ld h, a + ld a, [rSVBK] + push af + ld a, $5 + ld [rSVBK], a + ld a, h + push bc + push af + ld hl, BGPals + 8 + ld de, UnknBGPals + 8 + ld b, a + ld c, $1 + call CopyPals + ld hl, OBPals ; OBPals + ld de, UnknOBPals ; wd040 + pop af + ld b, a + ld c, $1 + call CopyPals + pop bc + pop af + ld [rSVBK], a + ld a, $1 + ld [hCGBPalUpdate], a + ret + +BattleBGEffect_GetFirstDMGPal: ; c8eac (32:4eac) + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld a, [hl] + inc [hl] +BattleBGEffect_GetNextDMGPal: ; c8eb2 (32:4eb2) + ld l, a + ld h, $0 + add hl, de + ld a, [hl] + cp -1 + jr z, .quit + cp -2 + jr nz, .repeat + ld a, [de] + ld hl, BG_EFFECT_STRUCT_03 + add hl, bc + ld [hl], $0 +.repeat + and a + ret + +.quit + scf + ret + +BattleBGEffects_ClearLYOverrides: ; c8eca (32:4eca) + xor a +BattleBGEffects_SetLYOverrides: ; c8ecb (32:4ecb) + ld hl, LYOverrides ; wListPointer + ld e, $99 +.loop1 + ld [hli], a + dec e + jr nz, .loop1 + ld hl, LYOverridesBackup + ld e, $91 +.loop2 + ld [hli], a + dec e + jr nz, .loop2 + ret + +BattleBGEffect_SetLCDStatCustoms1: ; c8ede (32:4ede) + ld [hLCDCPointer], a + call BGEffect_CheckBattleTurn + jr nz, .player_turn + lb de, $00, $36 + jr .okay + +.player_turn + lb de, $2f, $5e +.okay + ld a, d + ld [hLYOverrideStart], a + ld a, e + ld [hLYOverrideEnd], a + ret + +BattleBGEffect_SetLCDStatCustoms2: ; c8ef4 (32:4ef4) + ld [hLCDCPointer], a + call BGEffect_CheckBattleTurn + jr nz, .player_turn + lb de, $00, $36 + jr .okay + +.player_turn + lb de, $2d, $5e +.okay + ld a, d + ld [hLYOverrideStart], a + ld a, e + ld [hLYOverrideEnd], a + ret + +BattleAnim_ResetLCDStatCustom: ; c8f0a (32:4f0a) + xor a + ld [hLYOverrideStart], a + ld [hLYOverrideEnd], a + call BattleBGEffects_ClearLYOverrides + xor a + ld [hLCDCPointer], a + call EndBattleBGEffect + ret + +BattleBGEffects_ResetVideoHRAM: ; c8f19 (32:4f19) + xor a + ld [hLCDCPointer], a + ld a, %11100100 + ld [rBGP], a + ld [wBGP], a + ld [wOBP1], a + ld [hLYOverrideStart], a + ld [hLYOverrideEnd], a + call BattleBGEffects_ClearLYOverrides + ret + +Functionc8f2e: ; c8f2e (32:4f2e) + push bc + xor a + ld [wBattleAnimTemp0], a + ld a, e + ld [wBattleAnimTemp1], a + ld a, d + ld [wBattleAnimTemp2], a + ld a, $80 + ld [wBattleAnimTemp3], a + ld bc, LYOverridesBackup +.loop + ld a, [hLYOverrideStart] + cp c + jr nc, .next + ld a, [hLYOverrideEnd] + cp c + jr c, .next + ld a, [wBattleAnimTemp2] + ld d, a + ld a, [wBattleAnimTemp0] + call BattleBGEffects_Sine + ld [bc], a +.next + inc bc + ld a, [wBattleAnimTemp1] + ld hl, wBattleAnimTemp0 + add [hl] + ld [hl], a + ld hl, wBattleAnimTemp3 + dec [hl] + jr nz, .loop + pop bc + ret + +InitSurfWaves: ; c8f69 (32:4f69) + push bc + xor a + ld [wBattleAnimTemp0], a + ld a, e + ld [wBattleAnimTemp1], a + ld a, d + ld [wBattleAnimTemp2], a + ld a, $40 + ld [wBattleAnimTemp3], a + ld bc, wSurfWaveBGEffect +.loop + ld a, [wBattleAnimTemp2] + ld d, a + ld a, [wBattleAnimTemp0] + call BattleBGEffects_Sine + ld [bc], a + inc bc + ld a, [wBattleAnimTemp1] + ld hl, wBattleAnimTemp0 + add [hl] + ld [hl], a + ld hl, wBattleAnimTemp3 + dec [hl] + jr nz, .loop + pop bc + ret + +Functionc8f9a: ; c8f9a (32:4f9a) + push bc + ld [wBattleAnimTemp3], a + ld a, e + ld [wBattleAnimTemp1], a + ld a, d + ld [wBattleAnimTemp2], a + call .GetLYOverrideBackupAddrOffset + ld hl, LYOverridesBackup + add hl, de + ld c, l + ld b, h +.loop + ld a, [wBattleAnimTemp3] + and a + jr z, .done + dec a + ld [wBattleAnimTemp3], a + push af + ld a, [wBattleAnimTemp2] + ld d, a + ld a, [wBattleAnimTemp1] + push hl + call BattleBGEffects_Sine + ld e, a + pop hl + ld a, [hLYOverrideEnd] + cp c + jr c, .skip1 + ld a, e + ld [bc], a + inc bc +.skip1 + ld a, [hLYOverrideStart] + cp l + jr nc, .skip2 + ld [hl], e + dec hl +.skip2 + ld a, [wBattleAnimTemp1] + add $4 + ld [wBattleAnimTemp1], a + pop af + jr .loop + +.done + pop bc + and a + ret + +.GetLYOverrideBackupAddrOffset: + ld a, [hLYOverrideStart] + ld e, a + ld a, [wBattleAnimTemp0] + add e + ld e, a + ld d, $0 + ret + +BattleBGEffect_WavyScreenFX: ; c8fef (32:4fef) + push bc + ld a, [hLYOverrideStart] + ld l, a + inc a + ld e, a + ld h, HIGH(LYOverridesBackup) + ld d, h + ld a, [hLYOverrideEnd] + sub l + and a + jr z, .done + ld c, a + ld a, [hl] + push af +.loop + ld a, [de] + inc de + ld [hli], a + dec c + jr nz, .loop + pop af + ld [hl], a +.done + pop bc + ret + +BGEffect_FillLYOverridesBackup: ; c900b (32:500b) + push af + ld h, HIGH(LYOverridesBackup) + ld a, [hLYOverrideStart] + ld l, a + ld a, [hLYOverrideEnd] + sub l + ld d, a + pop af +.loop + ld [hli], a + dec d + jr nz, .loop + ret + +BGEffect_DisplaceLYOverridesBackup: ; c901b (32:501b) + ; e = a; d = [hLYOverrideEnd] - [hLYOverrideStart] - a + push af + ld e, a + ld a, [hLYOverrideStart] + ld l, a + ld a, [hLYOverrideEnd] + sub l + sub e + ld d, a + ld h, HIGH(LYOverridesBackup) + ld a, [hLYOverrideStart] + ld l, a + ld a, $90 +.loop + ld [hli], a + dec e + jr nz, .loop + pop af + xor $ff +.loop2 + ld [hli], a + dec d + jr nz, .loop2 + ret + +BGEffect_CheckBattleTurn: ; c9038 (32:5038) + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hBattleTurn] + and $1 + xor [hl] + ret + +BGEffect_CheckFlyDigStatus: ; c9042 (32:5042) + ld hl, BG_EFFECT_STRUCT_BATTLE_TURN + add hl, bc + ld a, [hBattleTurn] + and $1 + xor [hl] + jr nz, .player + ld a, [EnemySubStatus3] ; EnemySubStatus3 + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret + +.player + ld a, [PlayerSubStatus3] ; PlayerSubStatus3 + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret + +BattleBGEffects_CheckSGB: ; c9059 (32:5059) + ld a, [hSGB] + and a + ret + +BattleBGEffects_Sine: ; c905d (32:505d) + ld e, a + callfar BattleAnim_Sine_e + ld a, e + ret + +BattleBGEffects_Cosine: ; c9066 (32:5066) + ld e, a + callfar BattleAnim_Cosine_e + ld a, e + ret + +; c906f (32:506f) diff --git a/engine/anims/engine.asm b/engine/anims/engine.asm new file mode 100755 index 000000000..ae3bdde28 --- /dev/null +++ b/engine/anims/engine.asm @@ -0,0 +1,314 @@ +QueueBattleAnimation: ; cc9a1 (33:49a1) + ld hl, ActiveAnimObjects + ld e, 10 +.loop + ld a, [hl] + and a + jr z, .done + ld bc, BATTLEANIMSTRUCT_LENGTH + add hl, bc + dec e + jr nz, .loop + scf + ret + +.done + ld c, l + ld b, h + ld hl, wNumActiveBattleAnims + inc [hl] + call InitBattleAnimation + ret + +DeinitBattleAnimation: ; cc9bd + ld hl, BATTLEANIMSTRUCT_INDEX + add hl, bc + ld [hl], $0 + ret + +; cc9c4 + +InitBattleAnimation: ; cc9c4 (33:49c4) + ld a, [wBattleAnimTemp0] + ld e, a + ld d, 0 + ld hl, BattleAnimObjects +rept 6 + add hl, de +endr + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_INDEX + add hl, bc + ld a, [wNumActiveBattleAnims] + ld [hli], a ; Index + ld a, [de] + inc de + ld [hli], a ; 01 + ld a, [de] + inc de + ld [hli], a ; 02 + ld a, [de] + inc de + ld [hli], a ; Frameset ID + ld a, [de] + inc de + ld [hli], a ; Function + ld a, [de] + inc de + ld [hli], a ; 05 + ld a, [de] + call GetBattleAnimTileOffset + ld [hli], a ; Tile ID + ld a, [wBattleAnimTemp1] + ld [hli], a ; X Coord + ld a, [wBattleAnimTemp2] + ld [hli], a ; Y Coord + xor a + ld [hli], a ; X Offset + ld [hli], a ; Y Offset + ld a, [wBattleAnimTemp3] + ld [hli], a ; 0b + xor a + ld [hli], a ; 0c + dec a + ld [hli], a ; 0d + xor a + ld [hli], a ; 0e + ld [hli], a ; 0f + ld [hl], a ; 10 + ret + +BattleAnimOAMUpdate: ; cca09 + call InitBattleAnimBuffer + call GetBattleAnimFrame + cp -3 + jp z, .done + cp -4 + jp z, .delete + push af + ld hl, wBattleAnimTempOAMFlags + ld a, [wBattleAnimTemp7] + xor [hl] + and $e0 + ld [hl], a + pop af + push bc + call GetBattleAnimOAMPointer + ld a, [wBattleAnimTempTileID] + add [hl] + ld [wBattleAnimTempTileID], a + inc hl + ld a, [hli] + ld c, a + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wBattleAnimOAMPointerLo] + ld e, a + ld d, HIGH(Sprites) +.loop + ld a, [wBattleAnimTempYCoord] + ld b, a + ld a, [wBattleAnimTempYOffset] + add b + ld b, a + push hl + ld a, [hl] + ld hl, wBattleAnimTempOAMFlags + bit 6, [hl] + jr z, .no_yflip + add $8 + xor $ff + inc a + +.no_yflip + pop hl + add b + ld [de], a + inc hl + inc de + ld a, [wBattleAnimTempXCoord] + ld b, a + ld a, [wBattleAnimTempXOffset] + add b + ld b, a + push hl + ld a, [hl] + ld hl, wBattleAnimTempOAMFlags + bit 5, [hl] + jr z, .no_xflip + add $8 + xor $ff + inc a + +.no_xflip + pop hl + add b + ld [de], a + inc hl + inc de + ld a, [wBattleAnimTempTileID] + add $31 + add [hl] + ld [de], a + inc hl + inc de + ld a, [wBattleAnimTempOAMFlags] + ld b, a + ld a, [hl] + xor b + and $e0 + ld b, a + ld a, [hl] + and $10 + or b + ld b, a + ld a, [wBattleAnimTempPalette] + and $f + or b + ld [de], a + inc hl + inc de + ld a, e + ld [wBattleAnimOAMPointerLo], a + cp $a0 + jr nc, .exit_set_carry + dec c + jr nz, .loop + pop bc + jr .done + +.delete + call DeinitBattleAnimation + +.done + and a + ret + +.exit_set_carry + pop bc + scf + ret + +; ccaaa + +InitBattleAnimBuffer: ; ccaaa + ld hl, BATTLEANIMSTRUCT_01 + add hl, bc + ld a, [hl] + and %10000000 + ld [wBattleAnimTempOAMFlags], a + xor a + ld [wBattleAnimTemp7], a + ld hl, BATTLEANIMSTRUCT_PALETTE + add hl, bc + ld a, [hl] + ld [wBattleAnimTempPalette], a + ld hl, BATTLEANIMSTRUCT_02 + add hl, bc + ld a, [hl] + ld [wBattleAnimTemp1], a + ld hl, BATTLEANIMSTRUCT_TILEID + add hl, bc + ld a, [hli] + ld [wBattleAnimTempTileID], a + ld a, [hli] + ld [wBattleAnimTempXCoord], a + ld a, [hli] + ld [wBattleAnimTempYCoord], a + ld a, [hli] + ld [wBattleAnimTempXOffset], a + ld a, [hli] + ld [wBattleAnimTempYOffset], a + ld a, [hBattleTurn] + and a + ret z + ld hl, BATTLEANIMSTRUCT_01 + add hl, bc + ld a, [hl] + ld [wBattleAnimTempOAMFlags], a + bit 0, [hl] + ret z + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hli] + ld d, a + ld a, (-10 * 8) + 4 + sub d + ld [wBattleAnimTempXCoord], a + ld a, [hli] + ld d, a + ld a, [wBattleAnimTemp1] + cp $ff + jr nz, .check_kinesis_softboiled_milkdrink + ld a, 5 * 8 + add d + jr .done + +.check_kinesis_softboiled_milkdrink + sub d + push af + ld a, [FXAnimID + 1] + or a + jr nz, .no_sub + ld a, [FXAnimID] + cp KINESIS + jr z, .kinesis + cp SOFTBOILED + jr z, .softboiled + cp MILK_DRINK + jr nz, .no_sub +.kinesis +.softboiled +.milk_drink + pop af + sub 1 * 8 + jr .done + +.no_sub + pop af +.done + ld [wBattleAnimTempYCoord], a + ld a, [hli] + xor $ff + inc a + ld [wBattleAnimTempXOffset], a + ret + +; ccb31 + +GetBattleAnimTileOffset: ; ccb31 (33:4b31) + push hl + push bc + ld hl, wBattleAnimTileDict + ld b, a + ld c, 10 / 2 +.loop + ld a, [hli] + cp b + jr z, .load + inc hl + dec c + jr nz, .loop + xor a + jr .done + +.load + ld a, [hl] +.done + pop bc + pop hl + ret + +_ExecuteBGEffects: ; ccb48 + callfar ExecuteBGEffects + ret + +; ccb4f + +_QueueBGEffect: ; ccb4f (33:4b4f) + callfar QueueBGEffect + ret + +; ccb56 (33:4b56) diff --git a/engine/anims/functions.asm b/engine/anims/functions.asm new file mode 100755 index 000000000..e5b2b16c4 --- /dev/null +++ b/engine/anims/functions.asm @@ -0,0 +1,4157 @@ +DoBattleAnimFrame: ; ccfbe + ld hl, BATTLEANIMSTRUCT_FUNCTION + add hl, bc + ld e, [hl] + ld d, 0 + ld hl, .Jumptable + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + jp hl +; ccfce + +.Jumptable: +; entries correspond to BATTLEANIMFUNC_* constants + dw BattleAnimFunction_Null ; 00 + dw BattleAnimFunction_01 ; 01 + dw BattleAnimFunction_02 ; 02 + dw BattleAnimFunction_03 ; 03 + dw BattleAnimFunction_04 ; 04 + dw BattleAnimFunction_ThrowFromPlayerToEnemy ; 05 + dw BattleAnimFunction_ThrowFromPlayerToEnemyAndDisappear ; 06 + dw BattleAnimFunction_07 ; 07 + dw BattleAnimFunction_08 ; 08 + dw BattleAnimFunction_09 ; 09 + dw BattleAnimFunction_0A ; 0a + dw BattleAnimFunction_RazorLeaf ; 0b + dw BattleAnimFunction_0C ; 0c + dw BattleAnimFunction_0D ; 0d + dw BattleAnimFunction_0E ; 0e + dw BattleAnimFunction_0F ; 0f + dw BattleAnimFunction_10 ; 10 + dw BattleAnimFunction_11 ; 11 + dw BattleAnimFunction_PokeBall ; 12 + dw BattleAnimFunction_PokeBallBlocked ; 13 + dw BattleAnimFunction_14 ; 14 + dw BattleAnimFunction_15 ; 15 + dw BattleAnimFunction_16 ; 16 + dw BattleAnimFunction_17 ; 17 + dw BattleAnimFunction_18 ; 18 + dw BattleAnimFunction_19 ; 19 + dw BattleAnimFunction_1A ; 1a + dw BattleAnimFunction_1B ; 1b + dw BattleAnimFunction_1C ; 1c + dw BattleAnimFunction_1D ; 1d + dw BattleAnimFunction_1E ; 1e + dw BattleAnimFunction_1F ; 1f + dw BattleAnimFunction_LeechSeed ; 20 + dw BattleAnimFunction_21 ; 21 + dw BattleAnimFunction_22 ; 22 + dw BattleAnimFunction_23 ; 23 + dw BattleAnimFunction_24 ; 24 + dw BattleAnimFunction_25 ; 25 + dw BattleAnimFunction_26 ; 26 + dw BattleAnimFunction_27 ; 27 + dw BattleAnimFunction_28 ; 28 + dw BattleAnimFunction_SpiralDescent ; 29 + dw BattleAnimFunction_PoisonGas ; 2a + dw BattleAnimFunction_Horn ; 2b + dw BattleAnimFunction_2C ; 2c + dw BattleAnimFunction_2D ; 2d + dw BattleAnimFunction_2E ; 2e + dw BattleAnimFunction_2F ; 2f + dw BattleAnimFunction_30 ; 30 + dw BattleAnimFunction_31 ; 31 + dw BattleAnimFunction_32 ; 32 + dw BattleAnimFunction_33 ; 33 + dw BattleAnimFunction_34 ; 34 + dw BattleAnimFunction_35 ; 35 + dw BattleAnimFunction_36 ; 36 + dw BattleAnimFunction_37 ; 37 + dw BattleAnimFunction_38 ; 38 + dw BattleAnimFunction_39 ; 39 + dw BattleAnimFunction_3A ; 3a + dw BattleAnimFunction_3B ; 3b + dw BattleAnimFunction_3C ; 3c + dw BattleAnimFunction_3D ; 3d + dw BattleAnimFunction_3E ; 3e + dw BattleAnimFunction_3F ; 3f + dw BattleAnimFunction_40 ; 40 + dw BattleAnimFunction_41 ; 41 + dw BattleAnimFunction_42 ; 42 + dw BattleAnimFunction_43 ; 43 + dw BattleAnimFunction_44 ; 44 + dw BattleAnimFunction_45 ; 45 + dw BattleAnimFunction_46 ; 46 + dw BattleAnimFunction_47 ; 47 + dw BattleAnimFunction_48 ; 48 + dw BattleAnimFunction_49 ; 49 + dw BattleAnimFunction_4A ; 4a + dw BattleAnimFunction_4B ; 4b + dw BattleAnimFunction_4C ; 4c + dw BattleAnimFunction_4D ; 4d + dw BattleAnimFunction_4E ; 4e + dw BattleAnimFunction_4F ; 4f + +BattleAnimFunction_Null: ; cd06e (33:506e) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one +.one + call DeinitBattleAnimation +.zero + ret + +BattleAnimFunction_ThrowFromPlayerToEnemyAndDisappear: ; cd079 (33:5079) + call BattleAnimFunction_ThrowFromPlayerToEnemy + ret c + call DeinitBattleAnimation + ret + +BattleAnimFunction_ThrowFromPlayerToEnemy: ; cd081 (33:5081) + ; If x coord at $88 or beyond, abort. + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $88 + ret nc + ; Move right 2 pixels + add $2 + ld [hl], a + ; Move down 1 pixel + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + dec [hl] + ; Decrease ??? and hold onto its previous value (argument of the sine function) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + dec [hl] + ; Get ???, which is the amplitude of the sine function + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld d, [hl] + call BattleAnim_Sine + ; Store the result in the Y offset + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ; Carry flag denotes success + scf + ret + +BattleAnimFunction_04: ; cd0a6 (33:50a6) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $88 + jr c, .asm_cd0b3 + call DeinitBattleAnimation + ret + +.asm_cd0b3 + add $2 + ld [hl], a + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + dec [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + inc [hl] + inc [hl] + inc [hl] + inc [hl] + ld d, $10 + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + sra a + sra a + sra a + sra a + ld [hl], a + ret + +BattleAnimFunction_03: ; cd0e3 (33:50e3) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one +.zero + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + bit 7, [hl] + ld a, $0 + jr z, .asm_cd0f9 + ld a, $20 +.asm_cd0f9 + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $7f + ld [hl], a +.one + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld d, [hl] + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + ret + +BattleAnimFunction_01: ; cd12a (33:512a) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one +.one + call DeinitBattleAnimation + ret + +.zero + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $84 + ret nc + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + call Functionce70a + ret + +BattleAnimFunction_02: ; cd146 (33:5146) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $84 + jr nc, .asm_cd158 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + call Functionce70a + ret + +.asm_cd158 + call DeinitBattleAnimation + ret + +BattleAnimFunction_PokeBall: ; cd15c (33:515c) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw .three + dw .four + dw .five + dw .six + dw .seven + dw .eight + dw .nine + dw .ten + dw .eleven +.zero ; init + call GetBallAnimPal + call BattleAnim_IncAnonJumptableIndex + ret + +.one + call BattleAnimFunction_ThrowFromPlayerToEnemy + ret c + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + add [hl] + ld [hl], a + ld a, BATTLEANIMFRAMESET_0B + call ReinitBattleAnimFrameset + call BattleAnim_IncAnonJumptableIndex + ret + +.three + call BattleAnim_IncAnonJumptableIndex + ld a, BATTLEANIMFRAMESET_09 + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $0 + inc hl + ld [hl], $10 +.four + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hli] + ld d, [hl] + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + dec a + ld [hl], a + and $1f + ret nz + ld [hl], a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + sub $4 + ld [hl], a + ret nz + ld a, BATTLEANIMFRAMESET_0C + call ReinitBattleAnimFrameset + call BattleAnim_IncAnonJumptableIndex + ret + +.six + ld a, BATTLEANIMFRAMESET_0D + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + dec [hl] +.two +.five +.nine + ret + +.seven + call GetBallAnimPal + ld a, BATTLEANIMFRAMESET_0A + call ReinitBattleAnimFrameset + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], $20 +.eight +.ten + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hli] + ld d, [hl] + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + dec a + ld [hl], a + and $1f + jr z, .eleven + and $f + ret nz + call BattleAnim_IncAnonJumptableIndex + ret + +.eleven + call DeinitBattleAnimation + ret + +BattleAnimFunction_PokeBallBlocked: ; cd212 (33:5212) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two +.zero + call GetBallAnimPal + call BattleAnim_IncAnonJumptableIndex + ret + +.one + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $70 + jr nc, .next + call BattleAnimFunction_ThrowFromPlayerToEnemy + ret + +.next + call BattleAnim_IncAnonJumptableIndex +.two + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + cp $80 + jr nc, .done + add $4 + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + dec [hl] + dec [hl] + ret + +.done + call DeinitBattleAnimation + ret + +GetBallAnimPal: ; cd249 (33:5249) + ld hl, BallColors + ld a, [rSVBK] + push af + ld a, $1 + ld [rSVBK], a + ld a, [CurItem] ; CurItem + ld e, a + pop af + ld [rSVBK], a +.IsInArray: + ld a, [hli] + cp -1 + jr z, .load + cp e + jr z, .load + inc hl + jr .IsInArray + +.load + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_PALETTE + add hl, bc + ld [hl], a + ret +; cd26c (33:526c) + +INCLUDE "data/anims/ball_colors.asm" + +BattleAnimFunction_10: ; cd284 (33:5284) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw .three + dw .four +.zero + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + swap a + and $f + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld [hl], a + ret + +.one + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $88 + ret nc + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + call Functionce70a + ret + +.two + call DeinitBattleAnimation + ret + +.three + call BattleAnim_IncAnonJumptableIndex + ld a, BATTLEANIMFRAMESET_0F + call ReinitBattleAnimFrameset +.four + ret + +BattleAnimFunction_07: ; cd2be (33:52be) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one +.zero + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $30 + inc hl + ld [hl], $48 +.one + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hli] + ld d, [hl] + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + ld a, [hl] + and $3f + ret nz + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $20 + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + sub [hl] + jr z, .done + jr c, .done + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], a + ret + +.done + call DeinitBattleAnimation + ret + +BattleAnimFunction_08: ; cd306 (33:5306) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw .three +.zero + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $80 + jr nc, .next + call .SetCoords + ret + +.next + call BattleAnim_IncAnonJumptableIndex +.one + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $0 +.two + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + cp $40 + jr nc, .loop_back + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld d, $18 + call BattleAnim_Cosine + sub $18 + sra a + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld d, $18 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + add [hl] + ld [hl], a + ret + +.loop_back + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f0 + jr z, .finish + sub $10 + ld d, a + ld a, [hl] + and $f + or d + ld [hl], a + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + dec [hl] + ret + +.finish + call BattleAnim_IncAnonJumptableIndex +.three + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $b0 + jr c, .retain + call DeinitBattleAnimation + ret + +.retain + call .SetCoords + ret + +.SetCoords: + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + add [hl] + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f + ld e, a + srl e + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc +.loop + dec [hl] + dec e + jr nz, .loop + ret + +BattleAnimFunction_09: ; cd3ae (33:53ae) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two +.zero + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $0 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a +.one + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + and a + jr z, .done_one + dec [hl] + ret + +.done_one + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + swap a + and $f + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld a, [hl] + xor $ff + inc a + ld [hl], a + ret + +.two + call DeinitBattleAnimation + ret + +BattleAnimFunction_0A: ; cd3f2 (33:53f2) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw .three + dw .four + dw .five + dw .six + dw .seven + dw .eight + dw .nine +.zero + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld [hl], a + cp $7 + jr z, .seven + ld a, BATTLEANIMFRAMESET_11 + call ReinitBattleAnimFrameset + ret + +.seven + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $88 + jr nc, .set_up_eight + add $2 + ld [hl], a + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + dec [hl] + ret + +.set_up_eight + call BattleAnim_IncAnonJumptableIndex + ld a, BATTLEANIMFRAMESET_10 + call ReinitBattleAnimFrameset +.eight + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld d, $10 + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + ret + +.nine + call DeinitBattleAnimation + ret + +.one + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + dec [hl] + ret + +.four + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + inc [hl] +.two + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + dec [hl] + ret + +.five + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + inc [hl] +.three + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + inc [hl] +.six + ret + +BattleAnimFunction_RazorLeaf: ; cd478 (33:5478) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw .three + dw .four + dw .five + dw .six + dw .seven + dw .eight +.zero + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $40 +.one + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + cp $30 + jr nc, .sine_cosine + call BattleAnim_IncAnonJumptableIndex + xor a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hli], a + ld [hl], a + ld a, BATTLEANIMFRAMESET_17 + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + bit 6, [hl] + ret z + ld hl, BATTLEANIMSTRUCT_FRAME + add hl, bc + ld [hl], $5 + ret + +.sine_cosine + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $3f + ld d, a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + dec [hl] + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + call Functioncd557 + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld h, [hl] + ld l, a + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld [hl], d + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], e + ret + +.two + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + cp $20 + jr nz, .sine_cosine_2 + call DeinitBattleAnimation + ret + +.sine_cosine_2 + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld d, $10 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + bit 6, [hl] + jr nz, .decrease + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + jr .finish + +.decrease + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + dec [hl] +.finish + ld de, $80 + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld h, [hl] + ld l, a + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], d + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], e + ret + +.three + ld a, BATTLEANIMFRAMESET_16 + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_01 + add hl, bc + res 5, [hl] +.four +.five +.six +.seven + call BattleAnim_IncAnonJumptableIndex + ret + +.eight + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $c0 + ret nc + ld a, $8 + call Functionce70a + ret + +Functioncd557: ; cd557 (33:5557) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + bit 7, a + jr nz, .negative + cp $20 + jr nc, .plus_256 + cp $18 + jr nc, .plus_384 + ld de, $200 + ret + +.plus_384 + ld de, $180 + ret + +.plus_256 + ld de, $100 + ret + +.negative + and $3f + cp $20 + jr nc, .minus_256 + cp $18 + jr nc, .minus_384 + ld de, -$200 + ret + +.minus_384 + ld de, -$180 + ret + +.minus_256 + ld de, -$100 + ret + +BattleAnimFunction_4E: ; cd58a (33:558a) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one +.zero + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $40 + rlca + rlca + add $19 + ld hl, BATTLEANIMSTRUCT_FRAMESET_ID + add hl, bc + ld [hl], a + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $40 +.one + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + cp $30 + jr nc, .sine_cosine + call DeinitBattleAnimation + ret + +.sine_cosine + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $3f + ld d, a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + dec [hl] + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + call Functioncd557 + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld h, [hl] + ld l, a + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld [hl], d + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], e + ret + +BattleAnimFunction_0C: ; cd5e9 (33:55e9) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two +.zero + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $c +.one + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + and a + jr z, .next + dec [hl] + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + call Functionce70a + ret + +.next + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $0 + ld a, BATTLEANIMFRAMESET_22 + call ReinitBattleAnimFrameset +.two + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $98 + jr nc, .okay + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld h, [hl] + ld l, a + ld de, $60 + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], e + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld [hl], d +.okay + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + cp $20 + ret c + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f0 + ld e, a + ld d, $ff + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld h, [hl] + ld l, a + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], e + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld [hl], d + ret + +BattleAnimFunction_0D: ; cd66a (33:566a) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw .three + dw .four +.zero + call BattleAnim_IncAnonJumptableIndex + ld a, rSCY - $ff00 + ld [hLCDCPointer], a + ld a, $58 + ld [hLYOverrideStart], a + ld a, $5e + ld [hLYOverrideEnd], a + ret + +.one + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld e, [hl] + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + cp e + jr nc, .asm_cd69b + call BattleAnim_IncAnonJumptableIndex + xor a + ld [hLYOverrideStart], a + ret + +.asm_cd69b + dec a + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld d, $10 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + add [hl] + sub $10 + ret c + ld [hLYOverrideStart], a + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld a, [hl] + inc a + and $7 + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + inc [hl] +.two + ret + +.three + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + cp $70 + jr c, asm_cd6da + xor a + ld [hLCDCPointer], a + ld [hLYOverrideStart], a + ld [hLYOverrideEnd], a +.four + call DeinitBattleAnimation + ret + +asm_cd6da: ; cd6da (33:56da) + inc a + inc a + ld [hl], a + sub $10 + ret c + ld [hLYOverrideStart], a + ret + +BattleAnimFunction_0E: ; cd6e3 (33:56e3) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncd6ea + dw Functioncd6f7 +Functioncd6ea: ; cd6ea (33:56ea) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, BATTLEANIMFRAMESET_24 + add [hl] ; offset + call ReinitBattleAnimFrameset +Functioncd6f7: ; cd6f7 (33:56f7) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $b8 + jr c, .asm_cd704 + call DeinitBattleAnimation + ret + +.asm_cd704 + ld a, $2 + call Functionce70a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + dec [hl] + ld d, $8 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ret + +BattleAnimFunction_0F: ; cd71a (33:571a) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncd725 + dw Functioncd728 + dw Functioncd763 + dw Functioncd776 +Functioncd725: ; cd725 (33:5725) + call BattleAnim_IncAnonJumptableIndex +Functioncd728: ; cd728 (33:5728) + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + cp $30 + jr c, .asm_cd747 + ld a, $2 + call Functionce70a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + dec [hl] + ld d, $8 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ret + +.asm_cd747 + call BattleAnim_IncAnonJumptableIndex + ld a, BATTLEANIMFRAMESET_28 + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], $0 + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld [hl], $30 + ld hl, BATTLEANIMSTRUCT_01 + add hl, bc + ld a, [hl] + and $1 + ld [hl], a +Functioncd763: ; cd763 (33:5763) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + cp $18 + jr nc, .asm_cd76e + inc [hl] + ret + +.asm_cd76e + call BattleAnim_IncAnonJumptableIndex + ld a, BATTLEANIMFRAMESET_29 + call ReinitBattleAnimFrameset +Functioncd776: ; cd776 (33:5776) + ret + +BattleAnimFunction_11: ; cd777 (33:5777) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + cp $38 + jr c, .asm_cd784 + call DeinitBattleAnimation + ret + +.asm_cd784 + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld l, [hl] + ld h, a + ld de, $80 + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], e + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], d + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld a, [hl] + xor $10 + ld [hl], a + ret + +BattleAnimFunction_14: ; cd7a4 (33:57a4) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncd7ab + dw Functioncd7d2 +Functioncd7ab: ; cd7ab (33:57ab) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f0 + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f + sla a + sla a + sla a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld [hl], $1 +Functioncd7d2: ; cd7d2 (33:57d2) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + and a + jr nz, .asm_cd7de + call DeinitBattleAnimation + ret + +.asm_cd7de + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + inc [hl] + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld d, [hl] + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + xor $1 + ld [hl], a + ret z + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + dec [hl] + ret + +BattleAnimFunction_15: ; cd80c (33:580c) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncd81f + dw Functioncd817 + dw Functioncd81f + dw Functioncd820 +Functioncd817: ; cd817 (33:5817) + call BattleAnim_IncAnonJumptableIndex + ld a, BATTLEANIMFRAMESET_35 + call ReinitBattleAnimFrameset +Functioncd81f: ; cd81f (33:581f) + ret + +Functioncd820: ; cd820 (33:5820) + call DeinitBattleAnimation + ret + +BattleAnimFunction_16: ; cd824 (33:5824) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncd835 + dw Functioncd860 + dw Functioncd88f + dw Functioncd88f + dw Functioncd88f + dw Functioncd88f + dw Functioncd893 +Functioncd835: ; cd835 (33:5835) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_FRAMESET_ID + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + bit 7, [hl] + jr nz, .asm_cd852 + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $10 + jr .asm_cd858 + +.asm_cd852 + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $30 +.asm_cd858 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $7f + ld [hl], a +Functioncd860: ; cd860 (33:5860) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld d, [hl] + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + bit 7, a + jr nz, .load_no_inc + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + inc a + jr .reinit + +.load_no_inc + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] +.reinit + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + ld a, [hl] + and $1f + ret nz +Functioncd88f: ; cd88f (33:588f) + call BattleAnim_IncAnonJumptableIndex + ret + +Functioncd893: ; cd893 (33:5893) + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld [hl], $1 + ret + +BattleAnimFunction_17: ; cd89a (33:589a) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncd8ab + dw Functioncd8cc + dw Functioncd8f5 + dw Functioncd8f5 + dw Functioncd8f5 + dw Functioncd8f5 + dw Functioncd8f9 +Functioncd8ab: ; cd8ab (33:58ab) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + bit 7, [hl] + jr nz, .asm_cd8be + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $10 + jr .asm_cd8c4 + +.asm_cd8be + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $30 +.asm_cd8c4 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $7f + ld [hl], a +Functioncd8cc: ; cd8cc (33:58cc) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld d, [hl] + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + bit 7, a + jr nz, .asm_cd8e6 + ld a, $3d + jr .asm_cd8e8 + +.asm_cd8e6 + ld a, $3c +.asm_cd8e8 + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + inc [hl] + ld a, [hl] + and $1f + ret nz +Functioncd8f5: ; cd8f5 (33:58f5) + call BattleAnim_IncAnonJumptableIndex + ret + +Functioncd8f9: ; cd8f9 (33:58f9) + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld [hl], $1 + ret + +BattleAnimFunction_18: ; cd900 (33:5900) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncd907 + dw Functioncd913 +Functioncd907: ; cd907 (33:5907) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $28 + inc hl + ld [hl], $0 +Functioncd913: ; cd913 (33:5913) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld d, [hl] + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + and a + jr z, .asm_cd950 + ld d, a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld e, [hl] + ld hl, hPushOAM ; $ff80 + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], e + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], d + ret + +.asm_cd950 + call DeinitBattleAnimation + ret + +BattleAnimFunction_19: ; cd954 (33:5954) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncd961 + dw Functioncd96a + dw Functioncd96e + dw Functioncd96a + dw Functioncd97b +Functioncd961: ; cd961 (33:5961) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld [hl], $0 +Functioncd96a: ; cd96a (33:596a) + call Functioncd99a + ret + +Functioncd96e: ; cd96e (33:596e) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $88 + jr c, asm_cd988 + call BattleAnim_IncAnonJumptableIndex + ret + +Functioncd97b: ; cd97b (33:597b) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $b8 + jr c, asm_cd988 + call DeinitBattleAnimation + ret + +asm_cd988: ; cd988 (33:5988) + call Functioncd99a + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + inc [hl] + ld a, [hl] + and $1 + ret nz + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + dec [hl] + ret + +Functioncd99a: ; cd99a (33:599a) + call Functioncd9f4 + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + push af + push de + call BattleAnim_Sine + sra a + sra a + sra a + sra a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + add [hl] + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + sub $8 + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and a + jr z, .asm_cd9d7 + cp $c2 + jr c, .asm_cd9e2 +.asm_cd9d7 + dec a + ld [hl], a + and $7 + ret nz + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + inc [hl] + ret + +.asm_cd9e2 + xor a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hli], a + ld [hl], a + ret + +Functioncd9f4: ; cd9f4 (33:59f4) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld e, [hl] + ld d, 0 + ld hl, Unknown_cda01 + add hl, de + ld d, [hl] + ret + +; cda01 (33:5a01) +Unknown_cda01: ; cda01 + db 8, 6, 5, 4, 5, 6, 8, 12, 16 +; cda0a +BattleAnimFunction_1C: ; cda0a (33:5a0a) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $30 + jr nc, .asm_cda17 + call DeinitBattleAnimation + ret + +.asm_cda17 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f + ld e, a + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + sub e + ld [hl], a + srl e + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc +.asm_cda2c + inc [hl] + dec e + jr nz, .asm_cda2c + ret + +BattleAnimFunction_1F: ; cda31 (33:5a31) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncda4c + dw Functioncda3a + dw Functioncda4c +Functioncda3a: ; cda3a (33:5a3a) + ld hl, BATTLEANIMSTRUCT_FRAMESET_ID + add hl, bc + ld a, [hl] + inc a + call ReinitBattleAnimFrameset + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $8 +Functioncda4c: ; cda4c (33:5a4c) + ret + +BattleAnimFunction_LeechSeed: ; cda4d (33:5a4d) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw .three +.zero: ; cda58 (33:5a58) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], $40 + ret + +.one: ; cda62 (33:5a62) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + cp $20 + jr c, .sprout + call Functioncda8d + ret + +.sprout + ld [hl], $40 + ld a, BATTLEANIMFRAMESET_57 + call ReinitBattleAnimFrameset + call BattleAnim_IncAnonJumptableIndex + ret + +.two: ; cda7a (33:5a7a) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + and a + jr z, .flutter + dec [hl] + ret + +.flutter + call BattleAnim_IncAnonJumptableIndex + ld a, BATTLEANIMFRAMESET_58 + call ReinitBattleAnimFrameset +.three: ; cda8c (33:5a8c) + ret + +Functioncda8d: ; cda8d (33:5a8d) + dec [hl] + ld d, $20 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_02 + add hl, bc + ld a, [hl] + add $2 + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld e, [hl] + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld d, [hl] + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld h, [hl] + ld a, h + and $f + swap a + ld l, a + ld a, h + and $f0 + swap a + ld h, a + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], e + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld [hl], d + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + and $1 + ret nz + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + dec [hl] + ret + +BattleAnimFunction_3F: ; cdad6 (33:5ad6) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncdadf + dw Functioncdae9 + dw Functioncdaf9 +Functioncdadf: ; cdadf (33:5adf) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], $40 + ret + +Functioncdae9: ; cdae9 (33:5ae9) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + cp $20 + jr c, .asm_cdaf6 + call Functioncda8d + ret + +.asm_cdaf6 + call BattleAnim_IncAnonJumptableIndex +Functioncdaf9: ; cdaf9 (33:5af9) + ret + +BattleAnimFunction_1A: ; cdafa (33:5afa) + call BattleAnimFunction_03 + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + add $f + ld [hl], a + ret + +BattleAnimFunction_1B: ; cdb06 (33:5b06) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncdb13 + dw Functioncdb14 + dw Functioncdb28 + dw Functioncdb50 + dw Functioncdb65 +Functioncdb13: ; cdb13 (33:5b13) + ret + +Functioncdb14: ; cdb14 (33:5b14) + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + cp $30 + jr c, .asm_cdb24 + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld [hl], $0 + ret + +.asm_cdb24 + add $4 + ld [hl], a + ret + +Functioncdb28: ; cdb28 (33:5b28) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $98 + ret nc + inc [hl] + inc [hl] + ld hl, BATTLEANIMSTRUCT_01 + add hl, bc + set 0, [hl] + ld hl, BATTLEANIMSTRUCT_02 + add hl, bc + ld [hl], $90 + ld hl, BATTLEANIMSTRUCT_FRAME + add hl, bc + ld [hl], $0 + ld hl, BATTLEANIMSTRUCT_DURATION + add hl, bc + ld [hl], $2 + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + dec [hl] + ret + +Functioncdb50: ; cdb50 (33:5b50) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $2c + ld hl, BATTLEANIMSTRUCT_FRAME + add hl, bc + ld [hl], $0 + ld hl, BATTLEANIMSTRUCT_DURATION + add hl, bc + ld [hl], $80 +Functioncdb65: ; cdb65 (33:5b65) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $98 + ret nc + inc [hl] + inc [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + inc [hl] + ld d, $8 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ret + +BattleAnimFunction_1D: ; cdb80 (33:5b80) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncdb9f + dw Functioncdbb3 + dw Functioncdbcf + dw Functioncdbeb + dw Functioncdc74 + dw Functioncdc1a + dw Functioncdbc1 + dw Functioncdc1e + dw Functioncdc27 + dw Functioncdc39 + dw Functioncdc74 + dw Functioncdc48 + dw Functioncdc57 + dw Functioncdc74 +Functioncdb9f: ; cdb9f (33:5b9f) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $28 + inc hl + ld [hl], $10 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld [hl], a + ret + +Functioncdbb3: ; cdbb3 (33:5bb3) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $40 + jr nc, .asm_cdbbd + inc [hl] +.asm_cdbbd + call Functioncdc75 + ret + +Functioncdbc1: ; cdbc1 (33:5bc1) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $4b + jr nc, .asm_cdbcb + inc [hl] +.asm_cdbcb + call Functioncdc75 + ret + +Functioncdbcf: ; cdbcf (33:5bcf) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $88 + jr nc, .asm_cdbe6 + and $f + jr nz, asm_cdbfa + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], $10 + call BattleAnim_IncAnonJumptableIndex + ret + +.asm_cdbe6 + call BattleAnim_IncAnonJumptableIndex + inc [hl] + ret + +Functioncdbeb: ; cdbeb (33:5beb) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + and a + jr z, .asm_cdbf5 + dec [hl] + ret + +.asm_cdbf5 + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + dec [hl] +asm_cdbfa: ; cdbfa (33:5bfa) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + inc [hl] + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld d, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld e, [hl] + ld hl, hPushOAM ; $ff80 + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld [hl], d + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], e + ret + +Functioncdc1a: ; cdc1a (33:5c1a) + call DeinitBattleAnimation + ret + +Functioncdc1e: ; cdc1e (33:5c1e) + ld a, BATTLEANIMFRAMESET_4E + call ReinitBattleAnimFrameset + call BattleAnim_IncAnonJumptableIndex + ret + +Functioncdc27: ; cdc27 (33:5c27) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + inc [hl] + inc [hl] + ld d, $2 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ret + +Functioncdc39: ; cdc39 (33:5c39) + ld a, BATTLEANIMFRAMESET_50 + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], $4 + call BattleAnim_IncAnonJumptableIndex + ret + +Functioncdc48: ; cdc48 (33:5c48) + ld a, BATTLEANIMFRAMESET_4F + call ReinitBattleAnimFrameset + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $40 + ret + +Functioncdc57: ; cdc57 (33:5c57) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld d, $20 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + cp $30 + jr c, .asm_cdc71 + dec [hl] + ret + +.asm_cdc71 + call BattleAnim_IncAnonJumptableIndex +Functioncdc74: ; cdc74 (33:5c74) + ret + +Functioncdc75: ; cdc75 (33:5c75) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hli] + ld d, [hl] + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + ld a, [hl] + and $3f + ret nz + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $20 + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + sub $8 + ld [hl], a + ret nz + xor a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hli], a + ld [hl], a + call BattleAnim_IncAnonJumptableIndex + ret + +BattleAnimFunction_1E: ; cdca6 (33:5ca6) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + and a + jr z, .asm_cdcb6 + cp $d8 + jr nc, .asm_cdcb6 + call DeinitBattleAnimation + ret + +.asm_cdcb6 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld d, [hl] + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + sub d + ld [hl], a + ret + +BattleAnimFunction_21: ; cdcc3 (33:5cc3) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncdcca + dw Functioncdced +Functioncdcca: ; cdcca (33:5cca) + ld a, [hBattleTurn] + and a + jr z, .asm_cdcd9 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + xor $ff + add $3 + ld [hl], a +.asm_cdcd9 + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $8 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, BATTLEANIMFRAMESET_59 + add [hl] + call ReinitBattleAnimFrameset + ret + +Functioncdced: ; cdced (33:5ced) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + and a + jr z, .asm_cdcfa + dec [hl] + call Functioncdcfe + ret + +.asm_cdcfa + call DeinitBattleAnimation + ret + +Functioncdcfe: ; cdcfe (33:5cfe) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + inc [hl] + inc [hl] + ld d, $10 + call BattleAnim_Sine + ld d, a + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and a + jr z, .asm_cdd20 + dec a + ret z + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], d + ret + +.asm_cdd20 + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, d + xor $ff + inc a + ld [hl], a + ret + +BattleAnimFunction_22: ; cdd2a (33:5d2a) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncdd31 + dw Functioncdd4f +Functioncdd31: ; cdd31 (33:5d31) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $3f + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $80 + rlca + ld [hl], a + add BATTLEANIMFRAMESET_5D + call ReinitBattleAnimFrameset + ret + +Functioncdd4f: ; cdd4f (33:5d4f) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + swap a + ld d, a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + inc [hl] + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $80 + ret nc + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + and $3 + jr nz, .asm_cdd87 + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + dec [hl] +.asm_cdd87 + and $1 + ret nz + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + inc [hl] + ret + +BattleAnimFunction_23: ; cdd90 (33:5d90) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncdd97 + dw Functioncddbc +Functioncdd97: ; cdd97 (33:5d97) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_FRAMESET_ID + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $80 + rlca + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + add [hl] + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $7f + ld [hl], a +Functioncddbc: ; cddbc (33:5dbc) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld d, $10 + push af + push de + call BattleAnim_Sine + sra a + sra a + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + inc [hl] + and $3f + jr z, .asm_cddf0 + and $1f + ret nz + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + inc a + jr .asm_cddf5 + +.asm_cddf0 + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] +.asm_cddf5 + call ReinitBattleAnimFrameset + ret + +BattleAnimFunction_24: ; cddf9 (33:5df9) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncde02 + dw Functioncde20 + dw Functioncde21 +Functioncde02: ; cde02 (33:5e02) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + add BATTLEANIMFRAMESET_63 + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld e, [hl] + ld d, 0 + ld hl, Unknown_cde25 + add hl, de + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a +Functioncde20: ; cde20 (33:5e20) + ret + +Functioncde21: ; cde21 (33:5e21) + call DeinitBattleAnimation + ret + +; cde25 (33:5e25) +Unknown_cde25: ; cde25 + db $ec, $f8, $00 +; cde28 +BattleAnimFunction_25: ; cde28 (33:5e28) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + inc [hl] + inc [hl] + ld d, $4 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld d, [hl] + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld e, [hl] + ld hl, $ffa0 + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], d + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], e + ret + +BattleAnimFunction_26: ; cde54 (33:5e54) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + dec [hl] + dec [hl] + ld d, $10 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + inc [hl] + ret + +BattleAnimFunction_27: ; cde6b (33:5e6b) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncde72 + dw Functioncde88 +Functioncde72: ; cde72 (33:5e72) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and a + jr nz, .asm_cde83 + ld hl, BATTLEANIMSTRUCT_01 + add hl, bc + set 6, [hl] +.asm_cde83 + add BATTLEANIMFRAMESET_6A + call ReinitBattleAnimFrameset +Functioncde88: ; cde88 (33:5e88) + ret + +BattleAnimFunction_28: ; cde89 (33:5e89) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncde90 + dw Functioncdebf +Functioncde90: ; cde90 (33:5e90) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $0 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld e, [hl] + ld a, e + and $70 + swap a + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld a, e + and $80 + jr nz, .asm_cdeb2 + ld a, e + and $f + ld [hl], a + ret + +.asm_cdeb2 + ld a, e + and $f + xor $ff + inc a + ld [hl], a + ld a, BATTLEANIMFRAMESET_6E + call ReinitBattleAnimFrameset + ret + +Functioncdebf: ; cdebf (33:5ebf) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + and a + jr z, .asm_cdec9 + dec [hl] + ret + +.asm_cdec9 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld a, [hl] + xor $ff + inc a + ld [hl], a + ret + +BattleAnimFunction_SpiralDescent: ; cdedd (33:5edd) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld d, $18 + push af + push de + call BattleAnim_Sine + sra a + sra a + sra a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + add [hl] + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + ld a, [hl] + and $7 + ret nz + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + cp $28 + jr nc, .delete + inc [hl] + ret + +.delete + call DeinitBattleAnimation + ret + +BattleAnimFunction_2D: ; cdf1b (33:5f1b) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld d, $18 + push af + push de + call BattleAnim_Sine + sra a + sra a + sra a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + add [hl] + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + ld a, [hl] + and $3 + ret nz + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + cp $28 + jr nc, .asm_cdf55 + inc [hl] + ret + +.asm_cdf55 + call DeinitBattleAnimation + ret + +BattleAnimFunction_PoisonGas: ; cdf59 (33:5f59) + call BattleAnim_AnonJumptable +.anon_dw + dw Functioncdf60 + dw BattleAnimFunction_SpiralDescent +Functioncdf60: ; cdf60 (33:5f60) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $84 + jr nc, .next + inc [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + inc [hl] + ld d, $18 + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + and $1 + ret nz + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + dec [hl] + ret + +.next + call BattleAnim_IncAnonJumptableIndex + ret + +BattleAnimFunction_34: ; cdf8c (33:5f8c) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld d, $18 + push af + push de + call BattleAnim_Sine + sra a + sra a + sra a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + add [hl] + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + inc [hl] + inc [hl] + ld a, [hl] + and $7 + ret nz + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + cp $e8 + jr z, .asm_cdfc7 + dec [hl] + ret + +.asm_cdfc7 + call DeinitBattleAnimation + ret + +BattleAnimFunction_3C: ; cdfcb (33:5fcb) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld d, $18 + push af + push de + call BattleAnim_Sine + sra a + sra a + sra a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + add [hl] + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + inc [hl] + inc [hl] + ld a, [hl] + and $3 + ret nz + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + cp $d0 + jr z, .asm_ce007 + dec [hl] + dec [hl] + ret + +.asm_ce007 + call DeinitBattleAnimation + ret + +BattleAnimFunction_35: ; ce00b (33:600b) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce014 + dw Functionce023 + dw Functionce05f +Functionce014: ; ce014 (33:6014) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $34 + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], $10 +Functionce023: ; ce023 (33:6023) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $6c + jr c, .asm_ce02d + ret + +.asm_ce02d + ld a, $2 + call Functionce70a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld d, [hl] + call BattleAnim_Sine + bit 7, a + jr nz, .asm_ce046 + xor $ff + inc a +.asm_ce046 + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + sub $4 + ld [hl], a + and $1f + cp $20 + ret nz + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + srl [hl] + ret + +Functionce05f: ; ce05f (33:605f) + call DeinitBattleAnimation + ret + +BattleAnimFunction_Horn: ; ce063 (33:6063) + call BattleAnim_AnonJumptable +.anon_dw + dw .zero + dw .one + dw .two + dw Functionce09e +.zero: ; ce06e (33:606e) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], a + ret + +.one: ; ce083 (33:6083) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $58 + ret nc + ld a, $2 + call Functionce70a + ret + +.two: ; ce091 (33:6091) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + cp $20 + jr c, Functionce09e + call DeinitBattleAnimation + ret + +Functionce09e: ; ce09e (33:609e) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + ld d, $8 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + sra a + xor $ff + inc a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + add [hl] + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + add $8 + ld [hl], a + ret + +BattleAnimFunction_2C: ; ce0c5 (33:60c5) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce0ce + dw Functionce0f8 + dw Functionce0dd +Functionce0ce: ; ce0ce (33:60ce) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f0 + swap a + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld [hl], a + ret + +Functionce0dd: ; ce0dd (33:60dd) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld d, $10 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + bit 7, a + jr z, .asm_ce0f0 + ld [hl], a +.asm_ce0f0 + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + sub $4 + ld [hl], a +Functionce0f8: ; ce0f8 (33:60f8) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $84 + jr c, .asm_ce105 + call DeinitBattleAnimation + ret + +.asm_ce105 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + call Functionce70a + ret + +BattleAnimFunction_2E: ; ce10e (33:610e) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce115 + dw Functionce12a +Functionce115: ; ce115 (33:6115) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $28 + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + sub $28 + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], a +Functionce12a: ; ce12a (33:612a) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hli] + ld d, [hl] + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + and [hl] + jr nz, .asm_ce149 + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + dec [hl] +.asm_ce149 + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + inc [hl] + ld a, [hl] + and $3f + ret nz + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $20 + inc hl + srl [hl] + ret + +BattleAnimFunction_2F: ; ce15c (33:615c) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld d, [hl] + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + inc [hl] + ld a, [hl] + and $1 + jr nz, .asm_ce189 + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + dec [hl] +.asm_ce189 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $3 + jr nz, .asm_ce197 + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + inc [hl] +.asm_ce197 + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + cp $5a + jr nc, .asm_ce1aa + ld a, [hl] + and a + jr z, .asm_ce1ac + dec [hl] + ret + +.asm_ce1aa + inc [hl] + ret + +.asm_ce1ac + call DeinitBattleAnimation + ret + +BattleAnimFunction_42: ; ce1b0 (33:61b0) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + inc [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld d, [hl] + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + inc [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + cp $40 + jr nc, .asm_ce1df + inc [hl] + ret + +.asm_ce1df + ld a, [hl] + dec [hl] + and a + ret nz + call DeinitBattleAnimation + ret + +BattleAnimFunction_30: ; ce1e7 (33:61e7) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce1ee + dw Functionce1fb +Functionce1ee: ; ce1ee (33:61ee) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], a +Functionce1fb: ; ce1fb (33:61fb) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld d, $30 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + add [hl] + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + add $8 + ld d, $30 + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + inc [hl] + ret + +BattleAnimFunction_31: ; ce226 (33:6226) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce22d + dw Functionce254 +Functionce22d: ; ce22d (33:622d) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld d, $10 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld d, $10 + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld [hl], $f +Functionce254: ; ce254 (33:6254) + ret + +BattleAnimFunction_32: ; ce255 (33:6255) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce260 + dw Functionce274 + dw Functionce278 + dw Functionce289 +Functionce260: ; ce260 (33:6260) + call BattleAnim_IncAnonJumptableIndex + ld a, [hBattleTurn] + and a + jr nz, .asm_ce26c + ld a, $f0 + jr .asm_ce26e + +.asm_ce26c + ld a, $cc +.asm_ce26e + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], a + ret + +Functionce274: ; ce274 (33:6274) + call Functionce29f + ret + +Functionce278: ; ce278 (33:6278) + call Functionce29f + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $84 + ret nc + ld a, $4 + call Functionce70a + ret + +Functionce289: ; ce289 (33:6289) + call Functionce29f + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $d0 + jr nc, .asm_ce29b + ld a, $4 + call Functionce70a + ret + +.asm_ce29b + call DeinitBattleAnimation + ret + +Functionce29f: ; ce29f (33:629f) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + and $7 + inc [hl] + srl a + ld e, a + ld d, $0 + ld a, [hSGB] + and a + jr nz, .asm_ce2b6 + ld hl, Unknown_ce2c4 + jr .asm_ce2b9 + +.asm_ce2b6 + ld hl, Unknown_ce2c8 +.asm_ce2b9 + add hl, de + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + and [hl] + ld [wOBP0], a + ret + +; ce2c4 (33:62c4) +Unknown_ce2c4: ; ce2c4 + db $ff, $aa, $55, $aa +Unknown_ce2c8: ; ce2c8 + db $ff, $ff, $00, $00 +; ce2cc +BattleAnimFunction_33: ; ce2cc (33:62cc) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld d, $18 + call BattleAnim_Sine + sra a + sra a + sra a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + add [hl] + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + inc [hl] + ld d, $18 + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + dec [hl] + dec [hl] + ret + +BattleAnimFunction_36: ; ce2fd (33:62fd) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce306 + dw Functionce330 + dw Functionce34c +Functionce306: ; ce306 (33:6306) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + cp $e0 + jr nz, .asm_ce319 + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $2 + ret + +.asm_ce319 + ld d, a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld e, [hl] + ld hl, hPushOAM ; $ff80 + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], d + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], e + ret + +Functionce330: ; ce330 (33:6330) + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + and a + jr z, .asm_ce33a + dec [hl] + ret + +.asm_ce33a + ld [hl], $4 + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + xor $ff + inc a + ld [hl], a + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + add [hl] + ld [hl], a + ret + +Functionce34c: ; ce34c (33:634c) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $84 + jr nc, .asm_ce35b + ld a, $4 + call Functionce70a + ret + +.asm_ce35b + call DeinitBattleAnimation + ret + +BattleAnimFunction_37: ; ce35f (33:635f) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce366 + dw Functionce375 +Functionce366: ; ce366 (33:6366) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $7f + add BATTLEANIMFRAMESET_81 + call ReinitBattleAnimFrameset +Functionce375: ; ce375 (33:6375) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + bit 7, [hl] + jr nz, .asm_ce383 + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + inc [hl] + ret + +.asm_ce383 + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + dec [hl] + ret + +BattleAnimFunction_38: ; ce389 (33:6389) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce392 + dw Functionce39c + dw Functionce3ae +Functionce392: ; ce392 (33:6392) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $c + ret + +Functionce39c: ; ce39c (33:639c) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + and a + jr z, .asm_ce3a6 + dec [hl] + ret + +.asm_ce3a6 + call BattleAnim_IncAnonJumptableIndex + ld a, BATTLEANIMFRAMESET_20 + call ReinitBattleAnimFrameset +Functionce3ae: ; ce3ae (33:63ae) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + dec [hl] + ret + +BattleAnimFunction_39: ; ce3b4 (33:63b4) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + inc [hl] + inc [hl] + push af + ld d, $2 + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop af + ld d, $8 + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ret + +BattleAnimFunction_3A: ; ce3d2 (33:63d2) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + cp $20 + jr c, .asm_ce3df + call DeinitBattleAnimation + ret + +.asm_ce3df + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld d, $8 + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + add $2 + ld [hl], a + and $7 + ret nz + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + inc [hl] + ret + +BattleAnimFunction_3B: ; ce3ff (33:63ff) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce406 + dw Functionce412 +Functionce406: ; ce406 (33:6406) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + add [hl] + ld [hl], a + ret + +Functionce412: ; ce412 (33:6412) + call DeinitBattleAnimation + ret + +BattleAnimFunction_3D: ; ce416 (33:6416) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld d, $18 + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + sra a + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + inc [hl] + ret + +BattleAnimFunction_3E: ; ce43a (33:643a) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce443 + dw Functionce465 + dw Functionce490 +Functionce443: ; ce443 (33:6443) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $28 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f + ld hl, BATTLEANIMSTRUCT_FRAMESET_ID + add hl, bc + add [hl] + call ReinitBattleAnimFrameset + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and $f0 + or $8 + ld [hl], a +Functionce465: ; ce465 (33:6465) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + and a + jr z, .asm_ce48b + dec [hl] + add $8 + ld d, a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ret + +.asm_ce48b + ld [hl], $10 + call BattleAnim_IncAnonJumptableIndex +Functionce490: ; ce490 (33:6490) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + dec [hl] + and a + ret nz + call DeinitBattleAnimation + ret + +BattleAnimFunction_40: ; ce49c (33:649c) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce4a3 + dw Functionce4b0 +Functionce4a3: ; ce4a3 (33:64a3) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, BATTLEANIMFRAMESET_24 + add [hl] + call ReinitBattleAnimFrameset +Functionce4b0: ; ce4b0 (33:64b0) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + cp $38 + jr nc, .asm_ce4d8 + inc [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + inc [hl] + ld d, $18 + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + ld a, [hl] + and $1 + ret nz + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + dec [hl] + ret + +.asm_ce4d8 + call DeinitBattleAnimation + ret + +BattleAnimFunction_41: ; ce4dc (33:64dc) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and a + ret z + ld d, a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + inc [hl] + call BattleAnim_Sine + bit 7, a + jr nz, .asm_ce4f4 + xor $ff + inc a +.asm_ce4f4 + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + and $1f + ret nz + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + srl [hl] + ret + +BattleAnimFunction_43: ; ce508 (33:6508) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + cp $10 + jr nc, .asm_ce52e + inc [hl] + inc [hl] + ld d, a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ret + +.asm_ce52e + call DeinitBattleAnimation + ret + +BattleAnimFunction_44: ; ce532 (33:6532) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld e, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld d, [hl] + ld a, e + and $c0 + rlca + rlca + add [hl] + ld [hl], a + ld a, e + and $3f + push af + push de + call BattleAnim_Sine + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ret + +BattleAnimFunction_45: ; ce55b (33:655b) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce564 + dw Functionce56e + dw Functionce577 +Functionce564: ; ce564 (33:6564) + ld d, $18 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + inc [hl] + jr asm_ce58f + +Functionce56e: ; ce56e (33:656e) + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], $18 +Functionce577: ; ce577 (33:6577) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + cp $80 + jr nc, .asm_ce58b + ld d, a + add $8 + ld [hl], a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + jr asm_ce58f + +.asm_ce58b + call DeinitBattleAnimation + ret + +asm_ce58f: ; ce58f (33:658f) + call Functionce6f1 + ret + +BattleAnimFunction_46: ; ce593 (33:6593) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce5b3 + dw Functionce59a +Functionce59a: ; ce59a (33:659a) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld a, [hl] + cp $30 + jr c, .asm_ce5b0 + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + dec [hl] + dec [hl] + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc + inc [hl] + inc [hl] + ret + +.asm_ce5b0 + call DeinitBattleAnimation +Functionce5b3: ; ce5b3 (33:65b3) + ret + +BattleAnimFunction_47: ; ce5b4 (33:65b4) + ld d, $50 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + inc [hl] + inc [hl] + push af + push de + call BattleAnim_Sine + sra a + sra a + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + add [hl] + inc [hl] + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ret + +BattleAnimFunction_48: ; ce5dc (33:65dc) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + cp $d0 + jr z, .disappear + dec [hl] + dec [hl] + dec [hl] + dec [hl] + ret + +.disappear + call DeinitBattleAnimation + ret + +BattleAnimFunction_49: ; ce5ee (33:65ee) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce5f9 + dw Functionce60a + dw Functionce622 + dw Functionce618 +Functionce5f9: ; ce5f9 (33:65f9) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + and a + jr nz, asm_ce61c + call BattleAnim_IncAnonJumptableIndex + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], $ec +Functionce60a: ; ce60a (33:660a) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + cp $4 + jr z, Functionce618 + inc [hl] + inc [hl] + inc [hl] + inc [hl] + ret + +Functionce618: ; ce618 (33:6618) + call DeinitBattleAnimation + ret + +asm_ce61c: ; ce61c (33:661c) + call BattleAnim_IncAnonJumptableIndex + call BattleAnim_IncAnonJumptableIndex +Functionce622: ; ce622 (33:6622) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + cp $d8 + ret z + dec [hl] + dec [hl] + dec [hl] + dec [hl] + ret + +BattleAnimFunction_4A: ; ce62f (33:662f) + call BattleAnim_AnonJumptable +.anon_dw + dw Functionce63a + dw Functionce648 + dw Functionce65c + dw Functionce672 +Functionce63a: ; ce63a (33:663a) + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld [hl], a + call BattleAnim_IncAnonJumptableIndex + ret + +Functionce648: ; ce648 (33:6648) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + add $4 + cp $70 + jr c, .asm_ce654 + xor a +.asm_ce654 + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + inc [hl] + inc [hl] + ret + +Functionce65c: ; ce65c (33:665c) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + add $4 + cp $70 + jr c, .asm_ce668 + xor a +.asm_ce668 + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld a, [hl] + add $8 + ld [hl], a + ret + +Functionce672: ; ce672 (33:6672) + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld a, [hl] + add $4 + cp $70 + jr c, .asm_ce67e + xor a +.asm_ce67e + ld [hl], a + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld a, [hl] + add $4 + ld [hl], a + ret + +BattleAnimFunction_4B: ; ce688 (33:6688) + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld d, [hl] + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld e, [hl] + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + ld l, a + and $f0 + ld h, a + swap a + or h + ld h, a + ld a, l + and $f + swap a + ld l, a + add hl, de + ld e, l + ld d, h + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + ld [hl], d + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld [hl], e + ret + +BattleAnimFunction_4C: ; ce6b3 (33:66b3) + ld d, $18 + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld a, [hl] + inc [hl] + call Functionce6f1 + ret + +BattleAnimFunction_4F: ; ce6bf (33:66bf) + ld d, $18 + ld hl, BATTLEANIMSTRUCT_10 + add hl, bc + ld a, [hl] + inc [hl] + srl a + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + add [hl] + call Functionce6f1 + ret + +BattleAnimFunction_4D: ; ce6d2 (33:66d2) + ld hl, BATTLEANIMSTRUCT_0F + add hl, bc + ld a, [hl] + cp $20 + jr nc, .asm_ce6ed + inc [hl] + ld hl, BATTLEANIMSTRUCT_0B + add hl, bc + ld d, [hl] + call BattleAnim_Sine + xor $ff + inc a + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + ret + +.asm_ce6ed + call DeinitBattleAnimation + ret + +Functionce6f1: ; ce6f1 (33:66f1) + push af + push de + call BattleAnim_Sine + sra a + sra a + ld hl, BATTLEANIMSTRUCT_YOFFSET + add hl, bc + ld [hl], a + pop de + pop af + call BattleAnim_Cosine + ld hl, BATTLEANIMSTRUCT_XOFFSET + add hl, bc + ld [hl], a + ret + +Functionce70a: ; ce70a (33:670a) + and $f + ld e, a + ld hl, BATTLEANIMSTRUCT_XCOORD + add hl, bc + add [hl] + ld [hl], a + srl e + ld hl, BATTLEANIMSTRUCT_YCOORD + add hl, bc +.asm_ce719 + dec [hl] + dec e + jr nz, .asm_ce719 + ret + +BattleAnim_AnonJumptable: ; ce71e (33:671e) + pop de + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + ld l, [hl] + ld h, $0 + add hl, hl + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + jp hl + +BattleAnim_IncAnonJumptableIndex: ; ce72c (33:672c) + ld hl, BATTLEANIMSTRUCT_ANON_JT_INDEX + add hl, bc + inc [hl] + ret + +BattleAnim_Cosine: ; ce732 (33:6732) + add $10 +BattleAnim_Sine: ; ce734 (33:6734) +; a = d sin a + and $3f + cp $20 + jr nc, .negative + call .ApplySineWave + ld a, h + ret + +.negative + and $1f + call .ApplySineWave + ld a, h + xor $ff + inc a + ret + +.ApplySineWave: + ld e, a + ld a, d + ld d, 0 + ld hl, BattleAnimSineWave + add hl, de + add hl, de + ld e, [hl] + inc hl + ld d, [hl] + ld hl, $0 +.multiply + srl a + jr nc, .even + add hl, de +.even + sla e + rl d + and a + jr nz, .multiply + ret + +BattleAnim_Sine_e: ; ce765 (33:6765) + ld a, e + call BattleAnim_Sine + ld e, a + ret + +BattleAnim_Cosine_e: ; ce76b (33:676b) + ld a, e + call BattleAnim_Cosine + ld e, a + ret + +; ce771 (33:6771) +BattleAnim_AbsSinePrecise: ; ce771 + ld a, e + call BattleAnim_Sine + ld e, l + ld d, h + ret + +; ce778 +BattleAnim_AbsCosinePrecise: ; ce778 + ld a, e + call BattleAnim_Cosine + ld e, l + ld d, h + ret + +; ce77f +BattleAnimSineWave: ; ce77f + sine_wave $100 +; ce7bf diff --git a/engine/anims/helpers.asm b/engine/anims/helpers.asm new file mode 100755 index 000000000..a692211d3 --- /dev/null +++ b/engine/anims/helpers.asm @@ -0,0 +1,130 @@ +ReinitBattleAnimFrameset: ; ce7bf (33:67bf) + ld hl, BATTLEANIMSTRUCT_FRAMESET_ID + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_DURATION + add hl, bc + ld [hl], 0 + ld hl, BATTLEANIMSTRUCT_FRAME + add hl, bc + ld [hl], -1 + ret + +GetBattleAnimFrame: ; ce7d1 +.loop + ld hl, BATTLEANIMSTRUCT_DURATION + add hl, bc + ld a, [hl] + and a + jr z, .next_frame + dec [hl] + call .GetPointer + ld a, [hli] + push af + jr .okay + +.next_frame + ld hl, BATTLEANIMSTRUCT_FRAME + add hl, bc + inc [hl] + call .GetPointer + ld a, [hli] + cp -2 + jr z, .restart + cp -1 + jr z, .repeat_last + push af + ld a, [hl] + push hl + and $3f + ld hl, BATTLEANIMSTRUCT_DURATION + add hl, bc + ld [hl], a + pop hl + +.okay + ld a, [hl] + and $c0 + srl a + ld [wBattleAnimTemp7], a + pop af + ret + +.repeat_last + xor a + ld hl, BATTLEANIMSTRUCT_DURATION + add hl, bc + ld [hl], a + ld hl, BATTLEANIMSTRUCT_FRAME + add hl, bc + dec [hl] + dec [hl] + jr .loop + +.restart + xor a + ld hl, BATTLEANIMSTRUCT_DURATION + add hl, bc + ld [hl], a + dec a + ld hl, BATTLEANIMSTRUCT_FRAME + add hl, bc + ld [hl], a + jr .loop + +; ce823 + +.GetPointer: ; ce823 + ld hl, BATTLEANIMSTRUCT_FRAMESET_ID + add hl, bc + ld e, [hl] + ld d, 0 + ld hl, BattleAnimFrameData + add hl, de + add hl, de + ld e, [hl] + inc hl + ld d, [hl] + ld hl, BATTLEANIMSTRUCT_FRAME + add hl, bc + ld l, [hl] + ld h, $0 + add hl, hl + add hl, de + ret + +; ce83c + +GetBattleAnimOAMPointer: ; ce83c + ld l, a + ld h, 0 + ld de, BattleAnimOAMData + add hl, hl + add hl, hl + add hl, de + ret + +; ce846 + +LoadBattleAnimObj: ; ce846 (33:6846) + push hl + ld l, a + ld h, 0 + add hl, hl + add hl, hl + ld de, AnimObjGFX + add hl, de + ld c, [hl] + inc hl + ld b, [hl] + inc hl + ld a, [hli] + ld h, [hl] + ld l, a + pop de + push bc + call DecompressRequest2bpp + pop bc + ret + +; ce85e (33:685e) diff --git a/engine/battle/ai/items.asm b/engine/battle/ai/items.asm new file mode 100644 index 000000000..09595077a --- /dev/null +++ b/engine/battle/ai/items.asm @@ -0,0 +1,882 @@ +AI_SwitchOrTryItem: ; 38000 + and a + + ld a, [wBattleMode] + dec a + ret z + + ld a, [wLinkMode] + and a + ret nz + + farcall CheckEnemyLockedIn + ret nz + + ld a, [PlayerSubStatus5] + bit SUBSTATUS_CANT_RUN, a + jr nz, DontSwitch + + ld a, [wEnemyWrapCount] + and a + jr nz, DontSwitch + + ld hl, TrainerClassAttributes + TRNATTR_AI_ITEM_SWITCH + ld a, [InBattleTowerBattle] ; Load always the first TrainerClass for BattleTower-Trainers + and a + jr nz, .ok + + ld a, [TrainerClass] + dec a + ld bc, NUM_TRAINER_ATTRIBUTES + call AddNTimes +.ok + bit SWITCH_OFTEN_F, [hl] + jp nz, SwitchOften + bit SWITCH_RARELY_F, [hl] + jp nz, SwitchRarely + bit SWITCH_SOMETIMES_F, [hl] + jp nz, SwitchSometimes + ; fallthrough + +DontSwitch: ; 38041 + call AI_TryItem + ret +; 38045 + +SwitchOften: ; 38045 + callfar CheckAbleToSwitch + ld a, [wEnemySwitchMonParam] + and $f0 + jp z, DontSwitch + + cp $10 + jr nz, .not_10 + call Random + cp 1 + 50 percent + jr c, .switch + jp DontSwitch +.not_10 + + cp $20 + jr nz, .not_20 + call Random + cp -1 + 79 percent + jr c, .switch + jp DontSwitch +.not_20 + + ; $30 + call Random + cp 4 percent + jp c, DontSwitch + +.switch + ld a, [wEnemySwitchMonParam] + and $f + inc a + ; In register 'a' is the number (1-6) of the Pkmn to switch to + ld [wEnemySwitchMonIndex], a + jp AI_TrySwitch +; 38083 + +SwitchRarely: ; 38083 + callfar CheckAbleToSwitch + ld a, [wEnemySwitchMonParam] + and $f0 + jp z, DontSwitch + + cp $10 + jr nz, .not_10 + call Random + cp 8 percent + jr c, .switch + jp DontSwitch +.not_10 + + cp $20 + jr nz, .not_20 + call Random + cp 12 percent + jr c, .switch + jp DontSwitch +.not_20 + + ; $30 + call Random + cp -1 + 79 percent + jp c, DontSwitch + +.switch + ld a, [wEnemySwitchMonParam] + and $f + inc a + ld [wEnemySwitchMonIndex], a + jp AI_TrySwitch +; 380c1 + +SwitchSometimes: ; 380c1 + callfar CheckAbleToSwitch + ld a, [wEnemySwitchMonParam] + and $f0 + jp z, DontSwitch + + cp $10 + jr nz, .not_10 + call Random + cp -1 + 20 percent + jr c, .switch + jp DontSwitch +.not_10 + + cp $20 + jr nz, .not_20 + call Random + cp 1 + 50 percent + jr c, .switch + jp DontSwitch +.not_20 + + ; $30 + call Random + cp -1 + 20 percent + jp c, DontSwitch + +.switch + ld a, [wEnemySwitchMonParam] + and $f + inc a + ld [wEnemySwitchMonIndex], a + jp AI_TrySwitch +; 380ff + + +CheckSubstatusCantRun: ; 380ff + ld a, [EnemySubStatus5] + bit SUBSTATUS_CANT_RUN, a + ret +; 38105 + + +AI_TryItem: ; 38105 + ; items are not allowed in the BattleTower + ld a, [InBattleTowerBattle] + and a + ret nz + + ld a, [wEnemyTrainerItem1] + ld b, a + ld a, [wEnemyTrainerItem2] + or b + ret z + + call .IsHighestLevel + ret nc + + ld a, [TrainerClass] + dec a + ld hl, TrainerClassAttributes + TRNATTR_AI_ITEM_SWITCH + ld bc, NUM_TRAINER_ATTRIBUTES + call AddNTimes + ld b, h + ld c, l + ld hl, AI_Items + ld de, wEnemyTrainerItem1 +.loop + ld a, [hl] + and a + inc a + ret z + + ld a, [de] + cp [hl] + jr z, .has_item + inc de + ld a, [de] + cp [hl] + jr z, .has_item + + dec de + inc hl + inc hl + inc hl + jr .loop + +.has_item + inc hl + + push hl + push de + ld de, .callback + push de + ld a, [hli] + ld h, [hl] + ld l, a + jp hl +.callback + pop de + pop hl + + inc hl + inc hl + jr c, .loop + +.used_item + xor a + ld [de], a + inc a + ld [wEnemyGoesFirst], a + + ld hl, EnemySubStatus3 + res SUBSTATUS_BIDE, [hl] + + xor a + ld [EnemyFuryCutterCount], a + ld [EnemyProtectCount], a + ld [wEnemyRageCounter], a + + ld hl, EnemySubStatus4 + res SUBSTATUS_RAGE, [hl] + + xor a + ld [LastEnemyCounterMove], a + + scf + ret + + +.IsHighestLevel: ; 38170 + ld a, [OTPartyCount] + ld d, a + ld e, 0 + ld hl, OTPartyMon1Level + ld bc, PARTYMON_STRUCT_LENGTH +.next + ld a, [hl] + cp e + jr c, .ok + ld e, a +.ok + add hl, bc + dec d + jr nz, .next + + ld a, [CurOTMon] + ld hl, OTPartyMon1Level + call AddNTimes + ld a, [hl] + cp e + jr nc, .yes + +.no + and a + ret + +.yes + scf + ret +; 38196 + + +AI_Items: ; 39196 + dbw FULL_RESTORE, .FullRestore + dbw MAX_POTION, .MaxPotion + dbw HYPER_POTION, .HyperPotion + dbw SUPER_POTION, .SuperPotion + dbw POTION, .Potion + dbw X_ACCURACY, .XAccuracy + dbw FULL_HEAL, .FullHeal + dbw GUARD_SPEC, .GuardSpec + dbw DIRE_HIT, .DireHit + dbw X_ATTACK, .XAttack + dbw X_DEFEND, .XDefend + dbw X_SPEED, .XSpeed + dbw X_SPECIAL, .XSpecial + db $ff +; 381be + +.FullHeal: ; 381be + call .Status + jp c, .DontUse + call EnemyUsedFullHeal + jp .Use +; 381ca + +.Status: ; 381ca (e:41ca) + ld a, [EnemyMonStatus] + and a + jp z, .DontUse + + ld a, [bc] + bit CONTEXT_USE_F, a + jr nz, .StatusCheckContext + ld a, [bc] + bit ALWAYS_USE_F, a + jp nz, .Use + call Random + cp -1 + 20 percent + jp c, .Use + jp .DontUse + +.StatusCheckContext: + ld a, [EnemySubStatus5] + bit SUBSTATUS_TOXIC, a + jr z, .FailToxicCheck + ld a, [EnemyToxicCount] + cp 4 + jr c, .FailToxicCheck + call Random + cp 1 + 50 percent + jp c, .Use +.FailToxicCheck: + ld a, [EnemyMonStatus] + and 1 << FRZ | SLP + jp z, .DontUse + jp .Use +; 38208 + +.FullRestore: ; 38208 + call .HealItem + jp nc, .UseFullRestore + ld a, [bc] + bit CONTEXT_USE_F, a + jp z, .DontUse + call .Status + jp c, .DontUse + +.UseFullRestore: + call EnemyUsedFullRestore + jp .Use +; 38220 + +.MaxPotion: ; 38220 + call .HealItem + jp c, .DontUse + call EnemyUsedMaxPotion + jp .Use + +.HealItem: ; 3822c (e:422c) + ld a, [bc] + bit CONTEXT_USE_F, a + jr nz, .CheckHalfOrQuarterHP + callfar AICheckEnemyHalfHP + jp c, .DontUse + ld a, [bc] + bit UNKNOWN_USE_F, a + jp nz, .CheckQuarterHP + callfar AICheckEnemyQuarterHP + jp nc, .UseHealItem + call Random + cp 1 + 50 percent + jp c, .UseHealItem + jp .DontUse + +.CheckQuarterHP: ; 38254 (e:4254) + callfar AICheckEnemyQuarterHP + jp c, .DontUse + call Random + cp -1 + 20 percent + jp c, .DontUse + jr .UseHealItem + +.CheckHalfOrQuarterHP: ; 38267 (e:4267) + callfar AICheckEnemyHalfHP + jp c, .DontUse + callfar AICheckEnemyQuarterHP + jp nc, .UseHealItem + call Random + cp -1 + 20 percent + jp nc, .DontUse + +.UseHealItem: ; 38281 (e:4281) + jp .Use +; 38284 + +.HyperPotion: ; 38284 + call .HealItem + jp c, .DontUse + ld b, 200 + call EnemyUsedHyperPotion + jp .Use +; 38292 (e:4292) + +.SuperPotion: ; 38292 + call .HealItem + jp c, .DontUse + ld b, 50 + call EnemyUsedSuperPotion + jp .Use +; 382a0 + +.Potion: ; 382a0 + call .HealItem + jp c, .DontUse + ld b, 20 + call EnemyUsedPotion + jp .Use +; 382ae + +.asm_382ae ; This appears to be unused + callfar AICheckEnemyMaxHP + jr c, .dont_use + push bc + ld de, EnemyMonMaxHP + 1 + ld hl, EnemyMonHP + 1 + ld a, [de] + sub [hl] + jr z, .check_40_percent + dec hl + dec de + ld c, a + sbc [hl] + and a + jr nz, .check_40_percent + ld a, c + cp b + jp c, .check_50_percent + callfar AICheckEnemyQuarterHP + jr c, .check_40_percent + +.check_50_percent + pop bc + ld a, [bc] + bit UNKNOWN_USE_F, a + jp z, .Use + call Random + cp 1 + 50 percent + jp c, .Use + +.dont_use + jp .DontUse + +.check_40_percent + pop bc + ld a, [bc] + bit UNKNOWN_USE_F, a + jp z, .DontUse + call Random + cp 1 + 39 percent + jp c, .Use + jp .DontUse +; 382f9 + +.XAccuracy: ; 382f9 + call .XItem + jp c, .DontUse + call EnemyUsedXAccuracy + jp .Use +; 38305 + +.GuardSpec: ; 38305 + call .XItem + jp c, .DontUse + call EnemyUsedGuardSpec + jp .Use +; 38311 + +.DireHit: ; 38311 + call .XItem + jp c, .DontUse + call EnemyUsedDireHit + jp .Use +; 3831d (e:431d) + +.XAttack: ; 3831d + call .XItem + jp c, .DontUse + call EnemyUsedXAttack + jp .Use +; 38329 + +.XDefend: ; 38329 + call .XItem + jp c, .DontUse + call EnemyUsedXDefend + jp .Use +; 38335 + +.XSpeed: ; 38335 + call .XItem + jp c, .DontUse + call EnemyUsedXSpeed + jp .Use +; 38341 + +.XSpecial: ; 38341 + call .XItem + jp c, .DontUse + call EnemyUsedXSpecial + jp .Use +; 3834d + +.XItem: ; 3834d (e:434d) + ld a, [EnemyTurnsTaken] + and a + jr nz, .notfirstturnout + ld a, [bc] + bit ALWAYS_USE_F, a + jp nz, .Use + call Random + cp 1 + 50 percent + jp c, .DontUse + ld a, [bc] + bit CONTEXT_USE_F, a + jp nz, .Use + call Random + cp 1 + 50 percent + jp c, .DontUse + jp .Use +.notfirstturnout + ld a, [bc] + bit ALWAYS_USE_F, a + jp z, .DontUse + call Random + cp -1 + 20 percent + jp nc, .DontUse + jp .Use + +.DontUse: + scf + ret + +.Use: + and a + ret + + +AIUpdateHUD: ; 38387 + call UpdateEnemyMonInParty + farcall UpdateEnemyHUD + ld a, $1 + ld [hBGMapMode], a + ld hl, wEnemyItemState + dec [hl] + scf + ret +; 3839a + +AIUsedItemSound: ; 3839a + push de + ld de, SFX_FULL_HEAL + call PlaySFX + pop de + ret +; 383a3 + + +EnemyUsedFullHeal: ; 383a3 (e:43a3) + call AIUsedItemSound + call AI_HealStatus + ld a, FULL_HEAL + jp PrintText_UsedItemOn_AND_AIUpdateHUD + +EnemyUsedMaxPotion: ; 383ae (e:43ae) + ld a, MAX_POTION + ld [CurEnemyItem], a + jr FullRestoreContinue + +EnemyUsedFullRestore: ; 383b5 (e:43b5) + call AI_HealStatus + ld a, FULL_RESTORE + ld [CurEnemyItem], a + ld hl, EnemySubStatus3 + res SUBSTATUS_CONFUSED, [hl] + xor a + ld [EnemyConfuseCount], a + +FullRestoreContinue: ; 383c6 + ld de, wCurHPAnimOldHP + ld hl, EnemyMonHP + 1 + ld a, [hld] + ld [de], a + inc de + ld a, [hl] + ld [de], a + inc de + ld hl, EnemyMonMaxHP + 1 + ld a, [hld] + ld [de], a + inc de + ld [wCurHPAnimMaxHP], a + ld [EnemyMonHP + 1], a + ld a, [hl] + ld [de], a + ld [wCurHPAnimMaxHP + 1], a + ld [EnemyMonHP], a + jr EnemyPotionFinish +; 383e8 (e:43e8) + +EnemyUsedPotion: ; 383e8 + ld a, POTION + ld b, 20 + jr EnemyPotionContinue + +EnemyUsedSuperPotion: ; 383ee + ld a, SUPER_POTION + ld b, 50 + jr EnemyPotionContinue + +EnemyUsedHyperPotion: ; 383f4 (e:43f4) + ld a, HYPER_POTION + ld b, 200 + +EnemyPotionContinue: ; 383f8 + ld [CurEnemyItem], a + ld hl, EnemyMonHP + 1 + ld a, [hl] + ld [wCurHPAnimOldHP], a + add b + ld [hld], a + ld [wCurHPAnimNewHP], a + ld a, [hl] + ld [wCurHPAnimOldHP + 1], a + ld [wCurHPAnimNewHP + 1], a + jr nc, .ok + inc a + ld [hl], a + ld [wCurHPAnimNewHP + 1], a +.ok + inc hl + ld a, [hld] + ld b, a + ld de, EnemyMonMaxHP + 1 + ld a, [de] + dec de + ld [wCurHPAnimMaxHP], a + sub b + ld a, [hli] + ld b, a + ld a, [de] + ld [wCurHPAnimMaxHP + 1], a + sbc b + jr nc, EnemyPotionFinish + inc de + ld a, [de] + dec de + ld [hld], a + ld [wCurHPAnimNewHP], a + ld a, [de] + ld [hl], a + ld [wCurHPAnimNewHP + 1], a + +EnemyPotionFinish: ; 38436 + call PrintText_UsedItemOn + hlcoord 2, 2 + xor a + ld [wWhichHPBar], a + call AIUsedItemSound + predef AnimateHPBar + jp AIUpdateHUD + + +AI_TrySwitch: ; 3844b +; Determine whether the AI can switch based on how many Pokemon are still alive. +; If it can switch, it will. + ld a, [OTPartyCount] + ld c, a + ld hl, OTPartyMon1HP + ld d, 0 +.SwitchLoop: + ld a, [hli] + ld b, a + ld a, [hld] + or b + jr z, .fainted + inc d +.fainted + push bc + ld bc, PARTYMON_STRUCT_LENGTH + add hl, bc + pop bc + dec c + jr nz, .SwitchLoop + + ld a, d + cp 2 + jp nc, AI_Switch + and a + ret +; 3846c + +AI_Switch: ; 3846c + ld a, $1 + ld [wEnemyIsSwitching], a + ld [wEnemyGoesFirst], a + ld hl, EnemySubStatus4 + res SUBSTATUS_RAGE, [hl] + xor a + ld [hBattleTurn], a + callfar PursuitSwitch + + push af + ld a, [CurOTMon] + ld hl, OTPartyMon1Status + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + ld d, h + ld e, l + ld hl, EnemyMonStatus + ld bc, MON_MAXHP - MON_STATUS + call CopyBytes + pop af + + jr c, .skiptext + ld hl, TextJump_EnemyWithdrew + call PrintText + +.skiptext + ld a, 1 + ld [wBattleHasJustStarted], a + callfar NewEnemyMonStatus + callfar ResetEnemyStatLevels + ld hl, PlayerSubStatus1 + res SUBSTATUS_IN_LOVE, [hl] + farcall EnemySwitch + farcall ResetBattleParticipants + xor a + ld [wBattleHasJustStarted], a + ld a, [wLinkMode] + and a + ret nz + scf + ret +; 384d0 + +TextJump_EnemyWithdrew: ; 384d0 + text_jump Text_EnemyWithdrew + db "@" +; 384d5 + +Function384d5: ; This appears to be unused + call AIUsedItemSound + call AI_HealStatus + ld a, FULL_HEAL_RED ; X_SPEED + jp PrintText_UsedItemOn_AND_AIUpdateHUD +; 384e0 + +AI_HealStatus: ; 384e0 + ld a, [CurOTMon] + ld hl, OTPartyMon1Status + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + xor a + ld [hl], a + ld [EnemyMonStatus], a + ; Bug: this should reset SUBSTATUS_NIGHTMARE too + ; Uncomment the lines below to fix + ; ld hl, EnemySubStatus1 + ; res SUBSTATUS_NIGHTMARE, [hl] + ld hl, EnemySubStatus5 + res SUBSTATUS_TOXIC, [hl] + ret +; 384f7 + +EnemyUsedXAccuracy: ; 384f7 + call AIUsedItemSound + ld hl, EnemySubStatus4 + set SUBSTATUS_X_ACCURACY, [hl] + ld a, X_ACCURACY + jp PrintText_UsedItemOn_AND_AIUpdateHUD +; 38504 + +EnemyUsedGuardSpec: ; 38504 + call AIUsedItemSound + ld hl, EnemySubStatus4 + set SUBSTATUS_MIST, [hl] + ld a, GUARD_SPEC + jp PrintText_UsedItemOn_AND_AIUpdateHUD +; 38511 + +EnemyUsedDireHit: ; 38511 + call AIUsedItemSound + ld hl, EnemySubStatus4 + set SUBSTATUS_FOCUS_ENERGY, [hl] + ld a, DIRE_HIT + jp PrintText_UsedItemOn_AND_AIUpdateHUD +; 3851e + +Function3851e: ; This appears to be unused + ld [hDivisor], a + ld hl, EnemyMonMaxHP + ld a, [hli] + ld [hDividend], a + ld a, [hl] + ld [hDividend + 1], a + ld b, 2 + call Divide + ld a, [hQuotient + 2] + ld c, a + ld a, [hQuotient + 1] + ld b, a + ld hl, EnemyMonHP + 1 + ld a, [hld] + ld e, a + ld a, [hl] + ld d, a + ld a, d + sub b + ret nz + ld a, e + sub c + ret +; 38541 + +EnemyUsedXAttack: ; 38541 + ld b, ATTACK + ld a, X_ATTACK + jr EnemyUsedXItem +; 38547 + +EnemyUsedXDefend: ; 38547 + ld b, DEFENSE + ld a, X_DEFEND + jr EnemyUsedXItem +; 3854d + +EnemyUsedXSpeed: ; 3854d + ld b, SPEED + ld a, X_SPEED + jr EnemyUsedXItem +; 38553 + +EnemyUsedXSpecial: ; 38553 + ld b, SP_ATTACK + ld a, X_SPECIAL + + +; Parameter +; a = ITEM_CONSTANT +; b = BATTLE_CONSTANT (ATTACK, DEFENSE, SPEED, SP_ATTACK, SP_DEFENSE, ACCURACY, EVASION) +EnemyUsedXItem: + ld [CurEnemyItem], a + push bc + call PrintText_UsedItemOn + pop bc + farcall CheckIfStatCanBeRaised + jp AIUpdateHUD +; 38568 + + +; Parameter +; a = ITEM_CONSTANT +PrintText_UsedItemOn_AND_AIUpdateHUD: ; 38568 + ld [CurEnemyItem], a + call PrintText_UsedItemOn + jp AIUpdateHUD +; 38571 + +PrintText_UsedItemOn: ; 38571 + ld a, [CurEnemyItem] + ld [wd265], a + call GetItemName + ld hl, StringBuffer1 + ld de, wMonOrItemNameBuffer + ld bc, ITEM_NAME_LENGTH + call CopyBytes + ld hl, TextJump_EnemyUsedOn + jp PrintText +; 3858c + +TextJump_EnemyUsedOn: ; 3858c + text_jump Text_EnemyUsedOn + db "@" +; 38591 diff --git a/engine/battle/ai/move.asm b/engine/battle/ai/move.asm new file mode 100755 index 000000000..11586c0da --- /dev/null +++ b/engine/battle/ai/move.asm @@ -0,0 +1,221 @@ +AIChooseMove: ; 440ce +; Score each move in EnemyMonMoves starting from Buffer1. Lower is better. +; Pick the move with the lowest score. + +; Wildmons attack at random. + ld a, [wBattleMode] + dec a + ret z + + ld a, [wLinkMode] + and a + ret nz + +; No use picking a move if there's no choice. + farcall CheckEnemyLockedIn + ret nz + + +; The default score is 20. Unusable moves are given a score of 80. + ld a, 20 + ld hl, Buffer1 + ld [hli], a + ld [hli], a + ld [hli], a + ld [hl], a + +; Don't pick disabled moves. + ld a, [EnemyDisabledMove] + and a + jr z, .CheckPP + + ld hl, EnemyMonMoves + ld c, 0 +.CheckDisabledMove: + cp [hl] + jr z, .ScoreDisabledMove + inc c + inc hl + jr .CheckDisabledMove +.ScoreDisabledMove: + ld hl, Buffer1 + ld b, 0 + add hl, bc + ld [hl], 80 + +; Don't pick moves with 0 PP. +.CheckPP: + ld hl, Buffer1 - 1 + ld de, EnemyMonPP + ld b, 0 +.CheckMovePP: + inc b + ld a, b + cp EnemyMonMovesEnd - EnemyMonMoves + 1 + jr z, .ApplyLayers + inc hl + ld a, [de] + inc de + and $3f + jr nz, .CheckMovePP + ld [hl], 80 + jr .CheckMovePP + + +; Apply AI scoring layers depending on the trainer class. +.ApplyLayers: + ld hl, TrainerClassAttributes + TRNATTR_AI_MOVE_WEIGHTS + + ; If we have a battle in BattleTower just load the Attributes of the first TrainerClass (Falkner) + ; so we have always the same AI, regardless of the loaded class of trainer + ld a, [InBattleTowerBattle] + bit 0, a + jr nz, .battle_tower_skip + + ld a, [TrainerClass] + dec a + ld bc, 7 ; Trainer2AI - Trainer1AI + call AddNTimes + +.battle_tower_skip + lb bc, CHECK_FLAG, 0 + push bc + push hl + +.CheckLayer: + pop hl + pop bc + + ld a, c + cp 16 ; up to 16 scoring layers + jr z, .DecrementScores + + push bc + ld d, BANK(TrainerClassAttributes) + predef FlagPredef + ld d, c + pop bc + + inc c + push bc + push hl + + ld a, d + and a + jr z, .CheckLayer + + ld hl, AIScoringPointers + dec c + ld b, 0 + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + ld a, BANK(AIScoring) + call FarCall_hl + + jr .CheckLayer + +; Decrement the scores of all moves one by one until one reaches 0. +.DecrementScores: + ld hl, Buffer1 + ld de, EnemyMonMoves + ld c, EnemyMonMovesEnd - EnemyMonMoves + +.DecrementNextScore: + ; If the enemy has no moves, this will infinite. + ld a, [de] + inc de + and a + jr z, .DecrementScores + + ; We are done whenever a score reaches 0 + dec [hl] + jr z, .PickLowestScoreMoves + + ; If we just decremented the fourth move's score, go back to the first move + inc hl + dec c + jr z, .DecrementScores + + jr .DecrementNextScore + +; In order to avoid bias towards the moves located first in memory, increment the scores +; that were decremented one more time than the rest (in case there was a tie). +; This means that the minimum score will be 1. +.PickLowestScoreMoves: + ld a, c + +.move_loop + inc [hl] + dec hl + inc a + cp NUM_MOVES + 1 + jr nz, .move_loop + + ld hl, Buffer1 + ld de, EnemyMonMoves + ld c, NUM_MOVES + +; Give a score of 0 to a blank move +.loop2 + ld a, [de] + and a + jr nz, .skip_load + ld [hl], a + +; Disregard the move if its score is not 1 +.skip_load + ld a, [hl] + dec a + jr z, .keep + xor a + ld [hli], a + jr .after_toss + +.keep + ld a, [de] + ld [hli], a +.after_toss + inc de + dec c + jr nz, .loop2 + +; Randomly choose one of the moves with a score of 1 +.ChooseMove: + ld hl, Buffer1 + call Random + and 3 + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + and a + jr z, .ChooseMove + + ld [CurEnemyMove], a + ld a, c + ld [CurEnemyMoveNum], a + ret +; 441af + + +AIScoringPointers: ; 441af + dw AI_Basic + dw AI_Setup + dw AI_Types + dw AI_Offensive + dw AI_Smart + dw AI_Opportunist + dw AI_Aggressive + dw AI_Cautious + dw AI_Status + dw AI_Risky + dw AI_None + dw AI_None + dw AI_None + dw AI_None + dw AI_None + dw AI_None +; 441cf diff --git a/engine/battle/ai/redundant.asm b/engine/battle/ai/redundant.asm new file mode 100755 index 000000000..2e8f7c6df --- /dev/null +++ b/engine/battle/ai/redundant.asm @@ -0,0 +1,198 @@ +AI_Redundant: ; 2c41a +; Check if move effect c will fail because it's already been used. +; Return z if the move is a good choice. +; Return nz if the move is a bad choice. + ld a, c + ld de, 3 + ld hl, .Moves + call IsInArray + jp nc, .NotRedundant + inc hl + ld a, [hli] + ld h, [hl] + ld l, a + jp hl + +.Moves: ; 2c42c + dbw EFFECT_DREAM_EATER, .DreamEater + dbw EFFECT_HEAL, .Heal + dbw EFFECT_LIGHT_SCREEN, .LightScreen + dbw EFFECT_MIST, .Mist + dbw EFFECT_FOCUS_ENERGY, .FocusEnergy + dbw EFFECT_CONFUSE, .Confuse + dbw EFFECT_TRANSFORM, .Transform + dbw EFFECT_REFLECT, .Reflect + dbw EFFECT_SUBSTITUTE, .Substitute + dbw EFFECT_LEECH_SEED, .LeechSeed + dbw EFFECT_DISABLE, .Disable + dbw EFFECT_ENCORE, .Encore + dbw EFFECT_SNORE, .Snore + dbw EFFECT_SLEEP_TALK, .SleepTalk + dbw EFFECT_MEAN_LOOK, .MeanLook + dbw EFFECT_NIGHTMARE, .Nightmare + dbw EFFECT_SPIKES, .Spikes + dbw EFFECT_FORESIGHT, .Foresight + dbw EFFECT_PERISH_SONG, .PerishSong + dbw EFFECT_SANDSTORM, .Sandstorm + dbw EFFECT_ATTRACT, .Attract + dbw EFFECT_SAFEGUARD, .Safeguard + dbw EFFECT_RAIN_DANCE, .RainDance + dbw EFFECT_SUNNY_DAY, .SunnyDay + dbw EFFECT_TELEPORT, .Teleport + dbw EFFECT_MORNING_SUN, .MorningSun + dbw EFFECT_SYNTHESIS, .Synthesis + dbw EFFECT_MOONLIGHT, .Moonlight + dbw EFFECT_SWAGGER, .Swagger + dbw EFFECT_FUTURE_SIGHT, .FutureSight + db -1 + +.LightScreen: ; 2c487 + ld a, [EnemyScreens] + bit SCREENS_LIGHT_SCREEN, a + ret + +.Mist: ; 2c48d + ld a, [EnemySubStatus4] + bit SUBSTATUS_MIST, a + ret + +.FocusEnergy: ; 2c493 + ld a, [EnemySubStatus4] + bit SUBSTATUS_FOCUS_ENERGY, a + ret + +.Confuse: ; 2c499 + ld a, [PlayerSubStatus3] + bit SUBSTATUS_CONFUSED, a + ret nz + ld a, [PlayerScreens] + bit SCREENS_SAFEGUARD, a + ret + +.Transform: ; 2c4a5 + ld a, [EnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + ret + +.Reflect: ; 2c4ab + ld a, [EnemyScreens] + bit SCREENS_REFLECT, a + ret + +.Substitute: ; 2c4b1 + ld a, [EnemySubStatus4] + bit SUBSTATUS_SUBSTITUTE, a + ret + +.LeechSeed: ; 2c4b7 + ld a, [PlayerSubStatus4] + bit SUBSTATUS_LEECH_SEED, a + ret + +.Disable: ; 2c4bd + ld a, [PlayerDisableCount] + and a + ret + +.Encore: ; 2c4c2 + ld a, [PlayerSubStatus5] + bit SUBSTATUS_ENCORED, a + ret + +.Snore: +.SleepTalk: ; 2c4c8 + ld a, [EnemyMonStatus] + and SLP + jr z, .Redundant + jr .NotRedundant + +.MeanLook: ; 2c4d1 + ld a, [EnemySubStatus5] + bit SUBSTATUS_CANT_RUN, a + ret + +.Nightmare: ; 2c4d7 + ld a, [BattleMonStatus] + and a + jr z, .Redundant + ld a, [PlayerSubStatus1] + bit SUBSTATUS_NIGHTMARE, a + ret + +.Spikes: ; 2c4e3 + ld a, [PlayerScreens] + bit SCREENS_SPIKES, a + ret + +.Foresight: ; 2c4e9 + ld a, [PlayerSubStatus1] + bit SUBSTATUS_IDENTIFIED, a + ret + +.PerishSong: ; 2c4ef + ld a, [PlayerSubStatus1] + bit SUBSTATUS_PERISH, a + ret + +.Sandstorm: ; 2c4f5 + ld a, [Weather] + cp WEATHER_SANDSTORM + jr z, .Redundant + jr .NotRedundant + +.Attract: ; 2c4fe + farcall CheckOppositeGender + jr c, .Redundant + ld a, [PlayerSubStatus1] + bit SUBSTATUS_IN_LOVE, a + ret + +.Safeguard: ; 2c50c + ld a, [EnemyScreens] + bit SCREENS_SAFEGUARD, a + ret + +.RainDance: ; 2c512 + ld a, [Weather] + cp WEATHER_RAIN + jr z, .Redundant + jr .NotRedundant + +.SunnyDay: ; 2c51b + ld a, [Weather] + cp WEATHER_SUN + jr z, .Redundant + jr .NotRedundant + +.DreamEater: ; 2c524 + ld a, [BattleMonStatus] + and SLP + jr z, .Redundant + jr .NotRedundant + +.Swagger: ; 2c52d + ld a, [PlayerSubStatus3] + bit SUBSTATUS_CONFUSED, a + ret + +.FutureSight: ; 2c533 + ld a, [EnemyScreens] + bit 5, a + ret + +.Heal: +.MorningSun: +.Synthesis: +.Moonlight: ; 2c539 + farcall AICheckEnemyMaxHP + jr nc, .NotRedundant + +.Teleport: +.Redundant: ; 2c541 + ld a, 1 + and a + ret + +.NotRedundant: ; 2c545 + xor a + ret diff --git a/engine/battle/ai/scoring.asm b/engine/battle/ai/scoring.asm new file mode 100644 index 000000000..44194d6f7 --- /dev/null +++ b/engine/battle/ai/scoring.asm @@ -0,0 +1,3598 @@ +AIScoring: ; 38591 + +AI_Basic: ; 38591 +; Don't do anything redundant: +; -Using status-only moves if the player can't be statused +; -Using moves that fail if they've already been used + + ld hl, Buffer1 - 1 + ld de, EnemyMonMoves + ld b, EnemyMonMovesEnd - EnemyMonMoves + 1 +.checkmove + dec b + ret z + + inc hl + ld a, [de] + and a + ret z + + inc de + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + ld c, a + +; Dismiss moves with special effects if they are +; useless or not a good choice right now. +; For example, healing moves, weather moves, Dream Eater... + push hl + push de + push bc + farcall AI_Redundant + pop bc + pop de + pop hl + jr nz, .discourage + +; Dismiss status-only moves if the player can't be statused. + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + push hl + push de + push bc + ld hl, .statusonlyeffects + ld de, 1 + call IsInArray + + pop bc + pop de + pop hl + jr nc, .checkmove + + ld a, [BattleMonStatus] + and a + jr nz, .discourage + +; Dismiss Safeguard if it's already active. + ld a, [PlayerScreens] + bit SCREENS_SAFEGUARD, a + jr z, .checkmove + +.discourage + call AIDiscourageMove + jr .checkmove +; 385db + +.statusonlyeffects + db EFFECT_SLEEP + db EFFECT_TOXIC + db EFFECT_POISON + db EFFECT_PARALYZE + db $ff +; 385e0 + + + +AI_Setup: ; 385e0 +; Use stat-modifying moves on turn 1. + +; 50% chance to greatly encourage stat-up moves during the first turn of enemy's Pokemon. +; 50% chance to greatly encourage stat-down moves during the first turn of player's Pokemon. +; Almost 90% chance to greatly discourage stat-modifying moves otherwise. + + ld hl, Buffer1 - 1 + ld de, EnemyMonMoves + ld b, EnemyMonMovesEnd - EnemyMonMoves + 1 +.checkmove + dec b + ret z + + inc hl + ld a, [de] + and a + ret z + + inc de + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + + cp EFFECT_ATTACK_UP + jr c, .checkmove + cp EFFECT_EVASION_UP + 1 + jr c, .statup + +; cp EFFECT_ATTACK_DOWN - 1 + jr z, .checkmove + cp EFFECT_EVASION_DOWN + 1 + jr c, .statdown + + cp EFFECT_ATTACK_UP_2 + jr c, .checkmove + cp EFFECT_EVASION_UP_2 + 1 + jr c, .statup + +; cp EFFECT_ATTACK_DOWN_2 - 1 + jr z, .checkmove + cp EFFECT_EVASION_DOWN_2 + 1 + jr c, .statdown + + jr .checkmove + +.statup + ld a, [EnemyTurnsTaken] + and a + jr nz, .discourage + + jr .encourage + +.statdown + ld a, [PlayerTurnsTaken] + and a + jr nz, .discourage + +.encourage + call AI_50_50 + jr c, .checkmove + + dec [hl] + dec [hl] + jr .checkmove + +.discourage + call Random + cp 12 percent + jr c, .checkmove + inc [hl] + inc [hl] + jr .checkmove +; 38635 + + + +AI_Types: ; 38635 +; Dismiss any move that the player is immune to. +; Encourage super-effective moves. +; Discourage not very effective moves unless +; all damaging moves are of the same type. + + ld hl, Buffer1 - 1 + ld de, EnemyMonMoves + ld b, EnemyMonMovesEnd - EnemyMonMoves + 1 +.checkmove + dec b + ret z + + inc hl + ld a, [de] + and a + ret z + + inc de + call AIGetEnemyMove + + push hl + push bc + push de + ld a, 1 + ld [hBattleTurn], a + callfar BattleCheckTypeMatchup + pop de + pop bc + pop hl + + ld a, [wd265] + and a + jr z, .immune + cp 10 ; 1.0 + jr z, .checkmove + jr c, .noteffective + +; effective + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .checkmove + dec [hl] + jr .checkmove + +.noteffective +; Discourage this move if there are any moves +; that do damage of a different type. + push hl + push de + push bc + ld a, [wEnemyMoveStruct + MOVE_TYPE] + ld d, a + ld hl, EnemyMonMoves + ld b, EnemyMonMovesEnd - EnemyMonMoves + 1 + ld c, 0 +.checkmove2 + dec b + jr z, .asm_38693 + + ld a, [hli] + and a + jr z, .asm_38693 + + call AIGetEnemyMove + ld a, [wEnemyMoveStruct + MOVE_TYPE] + cp d + jr z, .checkmove2 + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr nz, .asm_38692 + jr .checkmove2 + +.asm_38692 + ld c, a +.asm_38693 + ld a, c + pop bc + pop de + pop hl + and a + jr z, .checkmove + inc [hl] + jr .checkmove + +.immune + call AIDiscourageMove + jr .checkmove +; 386a2 + + + +AI_Offensive: ; 386a2 +; Greatly discourage non-damaging moves. + + ld hl, Buffer1 - 1 + ld de, EnemyMonMoves + ld b, EnemyMonMovesEnd - EnemyMonMoves + 1 +.checkmove + dec b + ret z + + inc hl + ld a, [de] + and a + ret z + + inc de + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr nz, .checkmove + + inc [hl] + inc [hl] + jr .checkmove +; 386be + + + +AI_Smart: ; 386be +; Context-specific scoring. + + ld hl, Buffer1 + ld de, EnemyMonMoves + ld b, EnemyMonMovesEnd - EnemyMonMoves + 1 +.checkmove + dec b + ret z + + ld a, [de] + inc de + and a + ret z + + push de + push bc + push hl + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + ld hl, .table_386f2 + ld de, 3 + call IsInArray + + inc hl + jr nc, .nextmove + + ld a, [hli] + ld e, a + ld d, [hl] + + pop hl + push hl + + ld bc, .nextmove + push bc + + push de + ret + +.nextmove + pop hl + pop bc + pop de + inc hl + jr .checkmove + +.table_386f2 + dbw EFFECT_SLEEP, AI_Smart_Sleep + dbw EFFECT_LEECH_HIT, AI_Smart_LeechHit + dbw EFFECT_SELFDESTRUCT, AI_Smart_Selfdestruct + dbw EFFECT_DREAM_EATER, AI_Smart_DreamEater + dbw EFFECT_MIRROR_MOVE, AI_Smart_MirrorMove + dbw EFFECT_EVASION_UP, AI_Smart_EvasionUp + dbw EFFECT_ALWAYS_HIT, AI_Smart_AlwaysHit + dbw EFFECT_ACCURACY_DOWN, AI_Smart_AccuracyDown + dbw EFFECT_RESET_STATS, AI_Smart_ResetStats + dbw EFFECT_BIDE, AI_Smart_Bide + dbw EFFECT_FORCE_SWITCH, AI_Smart_ForceSwitch + dbw EFFECT_HEAL, AI_Smart_Heal + dbw EFFECT_TOXIC, AI_Smart_Toxic + dbw EFFECT_LIGHT_SCREEN, AI_Smart_LightScreen + dbw EFFECT_OHKO, AI_Smart_Ohko + dbw EFFECT_RAZOR_WIND, AI_Smart_RazorWind + dbw EFFECT_SUPER_FANG, AI_Smart_SuperFang + dbw EFFECT_TRAP_TARGET, AI_Smart_TrapTarget + dbw EFFECT_UNUSED_2B, AI_Smart_Unused2B + dbw EFFECT_CONFUSE, AI_Smart_Confuse + dbw EFFECT_SP_DEF_UP_2, AI_Smart_SpDefenseUp2 + dbw EFFECT_REFLECT, AI_Smart_Reflect + dbw EFFECT_PARALYZE, AI_Smart_Paralyze + dbw EFFECT_SPEED_DOWN_HIT, AI_Smart_SpeedDownHit + dbw EFFECT_SUBSTITUTE, AI_Smart_Substitute + dbw EFFECT_HYPER_BEAM, AI_Smart_HyperBeam + dbw EFFECT_RAGE, AI_Smart_Rage + dbw EFFECT_MIMIC, AI_Smart_Mimic + dbw EFFECT_LEECH_SEED, AI_Smart_LeechSeed + dbw EFFECT_DISABLE, AI_Smart_Disable + dbw EFFECT_COUNTER, AI_Smart_Counter + dbw EFFECT_ENCORE, AI_Smart_Encore + dbw EFFECT_PAIN_SPLIT, AI_Smart_PainSplit + dbw EFFECT_SNORE, AI_Smart_Snore + dbw EFFECT_CONVERSION2, AI_Smart_Conversion2 + dbw EFFECT_LOCK_ON, AI_Smart_LockOn + dbw EFFECT_DEFROST_OPPONENT, AI_Smart_DefrostOpponent + dbw EFFECT_SLEEP_TALK, AI_Smart_SleepTalk + dbw EFFECT_DESTINY_BOND, AI_Smart_DestinyBond + dbw EFFECT_REVERSAL, AI_Smart_Reversal + dbw EFFECT_SPITE, AI_Smart_Spite + dbw EFFECT_HEAL_BELL, AI_Smart_HealBell + dbw EFFECT_PRIORITY_HIT, AI_Smart_PriorityHit + dbw EFFECT_THIEF, AI_Smart_Thief + dbw EFFECT_MEAN_LOOK, AI_Smart_MeanLook + dbw EFFECT_NIGHTMARE, AI_Smart_Nightmare + dbw EFFECT_FLAME_WHEEL, AI_Smart_FlameWheel + dbw EFFECT_CURSE, AI_Smart_Curse + dbw EFFECT_PROTECT, AI_Smart_Protect + dbw EFFECT_FORESIGHT, AI_Smart_Foresight + dbw EFFECT_PERISH_SONG, AI_Smart_PerishSong + dbw EFFECT_SANDSTORM, AI_Smart_Sandstorm + dbw EFFECT_ENDURE, AI_Smart_Endure + dbw EFFECT_ROLLOUT, AI_Smart_Rollout + dbw EFFECT_SWAGGER, AI_Smart_Swagger + dbw EFFECT_FURY_CUTTER, AI_Smart_FuryCutter + dbw EFFECT_ATTRACT, AI_Smart_Attract + dbw EFFECT_SAFEGUARD, AI_Smart_Safeguard + dbw EFFECT_MAGNITUDE, AI_Smart_Magnitude + dbw EFFECT_BATON_PASS, AI_Smart_BatonPass + dbw EFFECT_PURSUIT, AI_Smart_Pursuit + dbw EFFECT_RAPID_SPIN, AI_Smart_RapidSpin + dbw EFFECT_MORNING_SUN, AI_Smart_MorningSun + dbw EFFECT_SYNTHESIS, AI_Smart_Synthesis + dbw EFFECT_MOONLIGHT, AI_Smart_Moonlight + dbw EFFECT_HIDDEN_POWER, AI_Smart_HiddenPower + dbw EFFECT_RAIN_DANCE, AI_Smart_RainDance + dbw EFFECT_SUNNY_DAY, AI_Smart_SunnyDay + dbw EFFECT_BELLY_DRUM, AI_Smart_BellyDrum + dbw EFFECT_PSYCH_UP, AI_Smart_PsychUp + dbw EFFECT_MIRROR_COAT, AI_Smart_MirrorCoat + dbw EFFECT_SKULL_BASH, AI_Smart_SkullBash + dbw EFFECT_TWISTER, AI_Smart_Twister + dbw EFFECT_EARTHQUAKE, AI_Smart_Earthquake + dbw EFFECT_FUTURE_SIGHT, AI_Smart_FutureSight + dbw EFFECT_GUST, AI_Smart_Gust + dbw EFFECT_STOMP, AI_Smart_Stomp + dbw EFFECT_SOLARBEAM, AI_Smart_Solarbeam + dbw EFFECT_THUNDER, AI_Smart_Thunder + dbw EFFECT_FLY, AI_Smart_Fly + db $ff +; 387e3 + + +AI_Smart_Sleep: ; 387e3 +; Greatly encourage sleep inducing moves if the enemy has either Dream Eater or Nightmare. +; 50% chance to greatly encourage sleep inducing moves otherwise. + + ld b, EFFECT_DREAM_EATER + call AIHasMoveEffect + jr c, .asm_387f0 + + ld b, EFFECT_NIGHTMARE + call AIHasMoveEffect + ret nc + +.asm_387f0 + call AI_50_50 + ret c + dec [hl] + dec [hl] + ret +; 387f7 + + +AI_Smart_LeechHit: ; 387f7 + push hl + ld a, 1 + ld [hBattleTurn], a + callfar BattleCheckTypeMatchup + pop hl + +; 60% chance to discourage this move if not very effective. + ld a, [wd265] + cp 10 ; 1.0 + jr c, .asm_38815 + +; Do nothing if effectiveness is neutral. + ret z + +; Do nothing if enemy's HP is full. + call AICheckEnemyMaxHP + ret c + +; 80% chance to encourage this move otherwise. + call AI_80_20 + ret c + + dec [hl] + ret + +.asm_38815 + call Random + cp 39 percent + 1 + ret c + + inc [hl] + ret +; 3881d + + +AI_Smart_LockOn: ; 3881d + ld a, [PlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .asm_38882 + + push hl + call AICheckEnemyQuarterHP + jr nc, .asm_38877 + + call AICheckEnemyHalfHP + jr c, .asm_38834 + + call AICompareSpeed + jr nc, .asm_38877 + +.asm_38834 + ld a, [PlayerEvaLevel] + cp $a + jr nc, .asm_3887a + cp $8 + jr nc, .asm_38875 + + ld a, [EnemyAccLevel] + cp $5 + jr c, .asm_3887a + cp $7 + jr c, .asm_38875 + + ld hl, EnemyMonMoves + ld c, EnemyMonMovesEnd - EnemyMonMoves + 1 +.asm_3884f + dec c + jr z, .asm_38877 + + ld a, [hli] + and a + jr z, .asm_38877 + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_ACC] + cp 180 + jr nc, .asm_3884f + + ld a, $1 + ld [hBattleTurn], a + + push hl + push bc + farcall BattleCheckTypeMatchup + ld a, [wd265] + cp $a + pop bc + pop hl + jr c, .asm_3884f + +.asm_38875 + pop hl + ret + +.asm_38877 + pop hl + inc [hl] + ret + +.asm_3887a + pop hl + call AI_50_50 + ret c + + dec [hl] + dec [hl] + ret + +.asm_38882 + push hl + ld hl, Buffer1 - 1 + ld de, EnemyMonMoves + ld c, EnemyMonMovesEnd - EnemyMonMoves + 1 + +.asm_3888b + inc hl + dec c + jr z, .asm_388a2 + + ld a, [de] + and a + jr z, .asm_388a2 + + inc de + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_ACC] + cp 180 + jr nc, .asm_3888b + + dec [hl] + dec [hl] + jr .asm_3888b + +.asm_388a2 + pop hl + jp AIDiscourageMove +; 388a6 + + +AI_Smart_Selfdestruct: ; 388a6 +; Selfdestruct, Explosion + +; Unless this is the enemy's last Pokemon... + push hl + farcall FindAliveEnemyMons + pop hl + jr nc, .asm_388b7 + +; ...greatly discourage this move unless this is the player's last Pokemon too. + push hl + call AICheckLastPlayerMon + pop hl + jr nz, .asm_388c6 + +.asm_388b7 +; Greatly discourage this move if enemy's HP is above 50%. + call AICheckEnemyHalfHP + jr c, .asm_388c6 + +; Do nothing if enemy's HP is below 25%. + call AICheckEnemyQuarterHP + ret nc + +; If enemy's HP is between 25% and 50%, +; over 90% chance to greatly discourage this move. + call Random + cp 9 percent - 2 + ret c + +.asm_388c6 + inc [hl] + inc [hl] + inc [hl] + ret +; 388ca + + +AI_Smart_DreamEater: ; 388ca +; 90% chance to greatly encourage this move. +; The AI_Basic layer will make sure that +; Dream Eater is only used against sleeping targets. + call Random + cp 10 percent + ret c + dec [hl] + dec [hl] + dec [hl] + ret +; 388d4 + + +AI_Smart_EvasionUp: ; 388d4 + +; Dismiss this move if enemy's evasion can't raise anymore. + ld a, [EnemyEvaLevel] + cp $d + jp nc, AIDiscourageMove + +; If enemy's HP is full... + call AICheckEnemyMaxHP + jr nc, .asm_388f2 + +; ...greatly encourage this move if player is badly poisoned. + ld a, [PlayerSubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_388ef + +; ...70% chance to greatly encourage this move if player is not badly poisoned. + call Random + cp 70 percent + jr nc, .asm_38911 + +.asm_388ef + dec [hl] + dec [hl] + ret + +.asm_388f2 + +; Greatly discourage this move if enemy's HP is below 25%. + call AICheckEnemyQuarterHP + jr nc, .asm_3890f + +; If enemy's HP is above 25% but not full, 4% chance to greatly encourage this move. + call Random + cp 4 percent + jr c, .asm_388ef + +; If enemy's HP is between 25% and 50%,... + call AICheckEnemyHalfHP + jr nc, .asm_3890a + +; If enemy's HP is above 50% but not full, 20% chance to greatly encourage this move. + call AI_80_20 + jr c, .asm_388ef + jr .asm_38911 + +.asm_3890a +; ...50% chance to greatly discourage this move. + call AI_50_50 + jr c, .asm_38911 + +.asm_3890f + inc [hl] + inc [hl] + +; 30% chance to end up here if enemy's HP is full and player is not badly poisoned. +; 77% chance to end up here if enemy's HP is above 50% but not full. +; 96% chance to end up here if enemy's HP is between 25% and 50%. +; 100% chance to end up here if enemy's HP is below 25%. +; In other words, we only end up here if the move has not been encouraged or dismissed. +.asm_38911 + ld a, [PlayerSubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_38938 + + ld a, [PlayerSubStatus4] + bit SUBSTATUS_LEECH_SEED, a + jr nz, .asm_38941 + +; Discourage this move if enemy's evasion level is higher than player's accuracy level. + ld a, [EnemyEvaLevel] + ld b, a + ld a, [PlayerAccLevel] + cp b + jr c, .asm_38936 + +; Greatly encourage this move if the player is in the middle of Fury Cutter or Rollout. + ld a, [PlayerFuryCutterCount] + and a + jr nz, .asm_388ef + + ld a, [PlayerSubStatus1] + bit SUBSTATUS_ROLLOUT, a + jr nz, .asm_388ef + + +.asm_38936 + inc [hl] + ret + +; Player is badly poisoned. +; 70% chance to greatly encourage this move. +; This would counter any previous discouragement. +.asm_38938 + call Random + cp 31 percent + 1 + ret c + dec [hl] + dec [hl] + ret + +; Player is seeded. +; 50% chance to encourage this move. +; This would partly counter any previous discouragement. +.asm_38941 + call AI_50_50 + ret c + + dec [hl] + ret +; 38947 + + +AI_Smart_AlwaysHit: ; 38947 +; 80% chance to greatly encourage this move if either... + +; ...enemy's accuracy level has been lowered three or more stages + ld a, [EnemyAccLevel] + cp $5 + jr c, .asm_38954 + +; ...or player's evasion level has been raised three or more stages. + ld a, [PlayerEvaLevel] + cp $a + ret c + +.asm_38954 + call AI_80_20 + ret c + + dec [hl] + dec [hl] + ret +; 3895b + + +AI_Smart_MirrorMove: ; 3895b + +; If the player did not use any move last turn... + ld a, [LastPlayerCounterMove] + and a + jr nz, .asm_38968 + +; ...do nothing if enemy is slower than player + call AICompareSpeed + ret nc + +; ...or dismiss this move if enemy is faster than player. + jp AIDiscourageMove + +; If the player did use a move last turn... +.asm_38968 + push hl + ld hl, UsefulMoves + ld de, 1 + call IsInArray + pop hl + +; ...do nothing if he didn't use a useful move. + ret nc + +; If he did, 50% chance to encourage this move... + call AI_50_50 + ret c + + dec [hl] + +; ...and 90% chance to encourage this move again if the enemy is faster. + call AICompareSpeed + ret nc + + call Random + cp 10 percent + ret c + + dec [hl] + ret +; 38985 + + +AI_Smart_AccuracyDown: ; 38985 + +; If player's HP is full... + call AICheckPlayerMaxHP + jr nc, .asm_389a0 + +; ...and enemy's HP is above 50%... + call AICheckEnemyHalfHP + jr nc, .asm_389a0 + +; ...greatly encourage this move if player is badly poisoned. + ld a, [PlayerSubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_3899d + +; ...70% chance to greatly encourage this move if player is not badly poisoned. + call Random + cp 70 percent + jr nc, .asm_389bf + +.asm_3899d + dec [hl] + dec [hl] + ret + +.asm_389a0 + +; Greatly discourage this move if player's HP is below 25%. + call AICheckPlayerQuarterHP + jr nc, .asm_389bd + +; If player's HP is above 25% but not full, 4% chance to greatly encourage this move. + call Random + cp 4 percent + jr c, .asm_3899d + +; If player's HP is between 25% and 50%,... + call AICheckPlayerHalfHP + jr nc, .asm_389b8 + +; If player's HP is above 50% but not full, 20% chance to greatly encourage this move. + call AI_80_20 + jr c, .asm_3899d + jr .asm_389bf + +; ...50% chance to greatly discourage this move. +.asm_389b8 + call AI_50_50 + jr c, .asm_389bf + +.asm_389bd + inc [hl] + inc [hl] + +; We only end up here if the move has not been already encouraged. +.asm_389bf + ld a, [PlayerSubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_389e6 + + ld a, [PlayerSubStatus4] + bit SUBSTATUS_LEECH_SEED, a + jr nz, .asm_389ef + +; Discourage this move if enemy's evasion level is higher than player's accuracy level. + ld a, [EnemyEvaLevel] + ld b, a + ld a, [PlayerAccLevel] + cp b + jr c, .asm_389e4 + +; Greatly encourage this move if the player is in the middle of Fury Cutter or Rollout. + ld a, [PlayerFuryCutterCount] + and a + jr nz, .asm_3899d + + ld a, [PlayerSubStatus1] + bit SUBSTATUS_ROLLOUT, a + jr nz, .asm_3899d + +.asm_389e4 + inc [hl] + ret + +; Player is badly poisoned. +; 70% chance to greatly encourage this move. +; This would counter any previous discouragement. +.asm_389e6 + call Random + cp 31 percent + 1 + ret c + dec [hl] + dec [hl] + ret + +; Player is seeded. +; 50% chance to encourage this move. +; This would partly counter any previous discouragement. +.asm_389ef + call AI_50_50 + ret c + + dec [hl] + ret +; 389f5 + + +AI_Smart_ResetStats: ; 389f5 + +; 85% chance to encourage this move if any of enemy's stat levels is lower than -2. + push hl + ld hl, EnemyAtkLevel + ld c, $8 +.asm_389fb + dec c + jr z, .asm_38a05 + ld a, [hli] + cp $5 + jr c, .asm_38a12 + jr .asm_389fb + +; 85% chance to encourage this move if any of player's stat levels is higher than +2. +.asm_38a05 + ld hl, PlayerAtkLevel + ld c, $8 +.asm_38a0a + dec c + jr z, .asm_38a1b + ld a, [hli] + cp $a + jr c, .asm_38a0a + +.asm_38a12 + pop hl + call Random + cp 16 percent + ret c + dec [hl] + ret + +; Discourage this move if neither: +; Any of enemy's stat levels is lower than -2. +; Any of player's stat levels is higher than +2. +.asm_38a1b + pop hl + inc [hl] + ret +; 38a1e + + +AI_Smart_Bide: ; 38a1e +; 90% chance to discourage this move unless enemy's HP is full. + + call AICheckEnemyMaxHP + ret c + call Random + cp 10 percent + ret c + inc [hl] + ret +; 38a2a + + +AI_Smart_ForceSwitch: ; 38a2a +; Whirlwind, Roar. + +; Discourage this move if the player has not shown +; a super-effective move against the enemy. +; Consider player's type(s) if its moves are unknown. + + push hl + callfar CheckPlayerMoveTypeMatchups + ld a, [wEnemyAISwitchScore] + cp 10 ; neutral + pop hl + ret c + inc [hl] + ret +; 38a3a + + +AI_Smart_Heal: +AI_Smart_MorningSun: +AI_Smart_Synthesis: +AI_Smart_Moonlight: ; 38a3a +; 90% chance to greatly encourage this move if enemy's HP is below 25%. +; Discourage this move if enemy's HP is higher than 50%. +; Do nothing otherwise. + + call AICheckEnemyQuarterHP + jr nc, .asm_38a45 + call AICheckEnemyHalfHP + ret nc + inc [hl] + ret + +.asm_38a45 + call Random + cp 10 percent + ret c + dec [hl] + dec [hl] + ret +; 38a4e + + +AI_Smart_Toxic: +AI_Smart_LeechSeed: ; 38a4e +; Discourage this move if player's HP is below 50%. + + call AICheckPlayerHalfHP + ret c + inc [hl] + ret +; 38a54 + + +AI_Smart_LightScreen: +AI_Smart_Reflect: ; 38a54 +; Over 90% chance to discourage this move unless enemy's HP is full. + + call AICheckEnemyMaxHP + ret c + call Random + cp 8 percent + ret c + inc [hl] + ret +; 38a60 + + +AI_Smart_Ohko: ; 38a60 +; Dismiss this move if player's level is higher than enemy's level. +; Else, discourage this move is player's HP is below 50%. + + ld a, [BattleMonLevel] + ld b, a + ld a, [EnemyMonLevel] + cp b + jp c, AIDiscourageMove + call AICheckPlayerHalfHP + ret c + inc [hl] + ret +; 38a71 + + +AI_Smart_TrapTarget: ; 38a71 +; Bind, Wrap, Fire Spin, Clamp + +; 50% chance to discourage this move if the player is already trapped. + ld a, [wPlayerWrapCount] + and a + jr nz, .asm_38a8b + +; 50% chance to greatly encourage this move if player is either +; badly poisoned, in love, identified, stuck in Rollout, or has a Nightmare. + ld a, [PlayerSubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_38a91 + + ld a, [PlayerSubStatus1] + and 1<<SUBSTATUS_IN_LOVE | 1<<SUBSTATUS_ROLLOUT | 1<<SUBSTATUS_IDENTIFIED | 1<<SUBSTATUS_NIGHTMARE + jr nz, .asm_38a91 + +; Else, 50% chance to greatly encourage this move if it's the player's Pokemon first turn. + ld a, [PlayerTurnsTaken] + and a + jr z, .asm_38a91 + +; 50% chance to discourage this move otherwise. +.asm_38a8b + call AI_50_50 + ret c + inc [hl] + ret + +.asm_38a91 + call AICheckEnemyQuarterHP + ret nc + call AI_50_50 + ret c + dec [hl] + dec [hl] + ret +; 38a9c + + +AI_Smart_RazorWind: +AI_Smart_Unused2B: ; 38a9c + ld a, [EnemySubStatus1] + bit SUBSTATUS_PERISH, a + jr z, .asm_38aaa + + ld a, [EnemyPerishCount] + cp 3 + jr c, .asm_38ad3 + +.asm_38aaa + push hl + ld hl, PlayerUsedMoves + ld c, 4 + +.asm_38ab0 + ld a, [hli] + and a + jr z, .asm_38ac1 + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + cp EFFECT_PROTECT + jr z, .asm_38ad5 + dec c + jr nz, .asm_38ab0 + +.asm_38ac1 + pop hl + ld a, [EnemySubStatus3] + bit SUBSTATUS_CONFUSED, a + jr nz, .asm_38acd + + call AICheckEnemyHalfHP + ret c + +.asm_38acd + call Random + cp 79 percent - 1 + ret c + +.asm_38ad3 + inc [hl] + ret + +.asm_38ad5 + pop hl + ld a, [hl] + add 6 + ld [hl], a + ret +; 38adb + + +AI_Smart_Confuse: ; 38adb + +; 90% chance to discourage this move if player's HP is between 25% and 50%. + call AICheckPlayerHalfHP + ret c + call Random + cp 10 percent + jr c, .asm_38ae7 + inc [hl] + +.asm_38ae7 +; Discourage again if player's HP is below 25%. + call AICheckPlayerQuarterHP + ret c + inc [hl] + ret +; 38aed + + +AI_Smart_SpDefenseUp2: ; 38aed + +; Discourage this move if enemy's HP is lower than 50%. + call AICheckEnemyHalfHP + jr nc, .asm_38b10 + +; Discourage this move if enemy's special defense level is higher than +3. + ld a, [EnemySDefLevel] + cp $b + jr nc, .asm_38b10 + +; 80% chance to greatly encourage this move if +; enemy's Special Defense level is lower than +2, and the player is of a special type. + cp $9 + ret nc + + ld a, [BattleMonType1] + cp SPECIAL + jr nc, .asm_38b09 + ld a, [BattleMonType2] + cp SPECIAL + ret c + +.asm_38b09 + call AI_80_20 + ret c + dec [hl] + dec [hl] + ret + +.asm_38b10 + inc [hl] + ret +; 38b12 + + +AI_Smart_Fly: ; 38b12 +; Fly, Dig + +; Greatly encourage this move if the player is +; flying or underground, and slower than the enemy. + + ld a, [PlayerSubStatus3] + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret z + + call AICompareSpeed + ret nc + + dec [hl] + dec [hl] + dec [hl] + ret +; 38b20 + + +AI_Smart_SuperFang: ; 38b20 +; Discourage this move if player's HP is below 25%. + + call AICheckPlayerQuarterHP + ret c + inc [hl] + ret +; 38b26 + + +AI_Smart_Paralyze: ; 38b26 + +; 50% chance to discourage this move if player's HP is below 25%. + call AICheckPlayerQuarterHP + jr nc, .asm_38b3a + +; 80% chance to greatly encourage this move +; if enemy is slower than player and its HP is above 25%. + call AICompareSpeed + ret c + call AICheckEnemyQuarterHP + ret nc + call AI_80_20 + ret c + dec [hl] + dec [hl] + ret + +.asm_38b3a + call AI_50_50 + ret c + inc [hl] + ret +; 38b40 + + +AI_Smart_SpeedDownHit: ; 38b40 +; Icy Wind + +; Almost 90% chance to greatly encourage this move if the following conditions all meet: +; Enemy's HP is higher than 25%. +; It's the first turn of player's Pokemon. +; Player is faster than enemy. + + ld a, [wEnemyMoveStruct + MOVE_ANIM] + cp ICY_WIND + ret nz + call AICheckEnemyQuarterHP + ret nc + ld a, [PlayerTurnsTaken] + and a + ret nz + call AICompareSpeed + ret c + call Random + cp 12 percent + ret c + dec [hl] + dec [hl] + ret +; 38b5c + + +AI_Smart_Substitute: ; 38b5c +; Dismiss this move if enemy's HP is below 50%. + + call AICheckEnemyHalfHP + ret c + jp AIDiscourageMove +; 38b63 + + +AI_Smart_HyperBeam: ; 38b63 + call AICheckEnemyHalfHP + jr c, .asm_38b72 + +; 50% chance to encourage this move if enemy's HP is below 25%. + call AICheckEnemyQuarterHP + ret c + call AI_50_50 + ret c + dec [hl] + ret + +.asm_38b72 +; If enemy's HP is above 50%, discourage this move at random + call Random + cp 16 percent + ret c + inc [hl] + call AI_50_50 + ret c + inc [hl] + ret +; 38b7f + + +AI_Smart_Rage: ; 38b7f + ld a, [EnemySubStatus4] + bit SUBSTATUS_RAGE, a + jr z, .asm_38b9b + +; If enemy's Rage is building, 50% chance to encourage this move. + call AI_50_50 + jr c, .asm_38b8c + + dec [hl] + +; Encourage this move based on Rage's counter. +.asm_38b8c + ld a, [wEnemyRageCounter] + cp $2 + ret c + dec [hl] + ld a, [wEnemyRageCounter] + cp $3 + ret c + dec [hl] + ret + +.asm_38b9b +; If enemy's Rage is not building, discourage this move if enemy's HP is below 50%. + call AICheckEnemyHalfHP + jr nc, .asm_38ba6 + +; 50% chance to encourage this move otherwise. + call AI_80_20 + ret nc + dec [hl] + ret + +.asm_38ba6 + inc [hl] + ret +; 38ba8 + + +AI_Smart_Mimic: ; 38ba8 + ld a, [LastPlayerCounterMove] + and a + jr z, .asm_38be9 + + call AICheckEnemyHalfHP + jr nc, .asm_38bef + + push hl + ld a, [LastPlayerCounterMove] + call AIGetEnemyMove + + ld a, $1 + ld [hBattleTurn], a + callfar BattleCheckTypeMatchup + + ld a, [wd265] + cp $a + pop hl + jr c, .asm_38bef + jr z, .asm_38bd4 + + call AI_50_50 + jr c, .asm_38bd4 + + dec [hl] + +.asm_38bd4 + ld a, [LastPlayerCounterMove] + push hl + ld hl, UsefulMoves + ld de, 1 + call IsInArray + + pop hl + ret nc + call AI_50_50 + ret c + dec [hl] + ret + +.asm_38be9 + call AICompareSpeed + jp c, AIDiscourageMove + +.asm_38bef + inc [hl] + ret +; 38bf1 + + +AI_Smart_Counter: ; 38bf1 + push hl + ld hl, PlayerUsedMoves + ld c, 4 + ld b, 0 + +.asm_38bf9 + ld a, [hli] + and a + jr z, .asm_38c0e + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .asm_38c0e + + ld a, [wEnemyMoveStruct + MOVE_TYPE] + cp SPECIAL + jr nc, .asm_38c0e + + inc b + +.asm_38c0e + dec c + jr nz, .asm_38bf9 + + pop hl + ld a, b + and a + jr z, .asm_38c39 + + cp $3 + jr nc, .asm_38c30 + + ld a, [LastPlayerCounterMove] + and a + jr z, .asm_38c38 + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .asm_38c38 + + ld a, [wEnemyMoveStruct + MOVE_TYPE] + cp SPECIAL + jr nc, .asm_38c38 + + +.asm_38c30 + call Random + cp 39 percent + 1 + jr c, .asm_38c38 + + dec [hl] + +.asm_38c38 + ret + +.asm_38c39 + inc [hl] + ret +; 38c3b + + +AI_Smart_Encore: ; 38c3b + call AICompareSpeed + jr nc, .asm_38c81 + + ld a, [LastPlayerMove] + and a + jp z, AIDiscourageMove + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .asm_38c68 + + push hl + ld a, [wEnemyMoveStruct + MOVE_TYPE] + ld hl, EnemyMonType1 + predef CheckTypeMatchup + + pop hl + ld a, [wd265] + cp $a + jr nc, .asm_38c68 + + and a + ret nz + jr .asm_38c78 + +.asm_38c68 + push hl + ld a, [LastPlayerCounterMove] + ld hl, .EncoreMoves + ld de, 1 + call IsInArray + pop hl + jr nc, .asm_38c81 + +.asm_38c78 + call Random + cp 28 percent - 1 + ret c + dec [hl] + dec [hl] + ret + +.asm_38c81 + inc [hl] + inc [hl] + inc [hl] + ret + +.EncoreMoves: + db SWORDS_DANCE + db WHIRLWIND + db LEER + db ROAR + db DISABLE + db MIST + db LEECH_SEED + db GROWTH + db POISONPOWDER + db STRING_SHOT + db MEDITATE + db AGILITY + db TELEPORT + db SCREECH + db HAZE + db FOCUS_ENERGY + db DREAM_EATER + db POISON_GAS + db SPLASH + db SHARPEN + db CONVERSION + db SUPER_FANG + db SUBSTITUTE + db TRIPLE_KICK + db SPIDER_WEB + db MIND_READER + db FLAME_WHEEL + db AEROBLAST + db COTTON_SPORE + db POWDER_SNOW + db $ff +; 38ca4 + + +AI_Smart_PainSplit: ; 38ca4 +; Discourage this move if [enemy's current HP * 2 > player's current HP]. + + push hl + ld hl, EnemyMonHP + ld b, [hl] + inc hl + ld c, [hl] + sla c + rl b + ld hl, BattleMonHP + 1 + ld a, [hld] + cp c + ld a, [hl] + sbc b + pop hl + ret nc + inc [hl] + ret +; 38cba + + +AI_Smart_Snore: +AI_Smart_SleepTalk: ; 38cba +; Greatly encourage this move if enemy is fast asleep. +; Greatly discourage this move otherwise. + + ld a, [EnemyMonStatus] + and $7 + cp $1 + jr z, .asm_38cc7 + + dec [hl] + dec [hl] + dec [hl] + ret + +.asm_38cc7 + inc [hl] + inc [hl] + inc [hl] + ret +; 38ccb + + +AI_Smart_DefrostOpponent: ; 38ccb +; Greatly encourage this move if enemy is frozen. +; No move has EFFECT_DEFROST_OPPONENT, so this layer is unused. + + ld a, [EnemyMonStatus] + and $20 + ret z + dec [hl] + dec [hl] + dec [hl] + ret +; 38cd5 + + +AI_Smart_Spite: ; 38cd5 + ld a, [LastPlayerCounterMove] + and a + jr nz, .asm_38ce7 + + call AICompareSpeed + jp c, AIDiscourageMove + + call AI_50_50 + ret c + inc [hl] + ret + +.asm_38ce7 + push hl + ld b, a + ld c, 4 + ld hl, BattleMonMoves + ld de, BattleMonPP + +.asm_38cf1 + ld a, [hli] + cp b + jr z, .asm_38cfb + + inc de + dec c + jr nz, .asm_38cf1 + + pop hl + ret + +.asm_38cfb + pop hl + ld a, [de] + cp $6 + jr c, .asm_38d0d + cp $f + jr nc, .asm_38d0b + + call Random + cp 39 percent + 1 + ret nc + +.asm_38d0b + inc [hl] + ret + +.asm_38d0d + call Random + cp 39 percent + 1 + ret c + dec [hl] + dec [hl] + ret +; 38d16 + + +Function_0x38d16; 38d16 + jp AIDiscourageMove +; 38d19 + + +AI_Smart_DestinyBond: +AI_Smart_Reversal: +AI_Smart_SkullBash: ; 38d19 +; Discourage this move if enemy's HP is above 25%. + + call AICheckEnemyQuarterHP + ret nc + inc [hl] + ret +; 38d1f + + +AI_Smart_HealBell: ; 38d1f +; Dismiss this move if none of the opponent's Pokemon is statused. +; Encourage this move if the enemy is statused. +; 50% chance to greatly encourage this move if the enemy is fast asleep or frozen. + + push hl + ld a, [OTPartyCount] + ld b, a + ld c, 0 + ld hl, OTPartyMon1HP + ld de, PARTYMON_STRUCT_LENGTH + +.loop + push hl + ld a, [hli] + or [hl] + jr z, .next + + ; status + dec hl + dec hl + dec hl + ld a, [hl] + or c + ld c, a + +.next + pop hl + add hl, de + dec b + jr nz, .loop + + pop hl + ld a, c + and a + jr z, .no_status + + ld a, [EnemyMonStatus] + and a + jr z, .ok + dec [hl] +.ok + and 1 << FRZ | SLP + ret z + call AI_50_50 + ret c + dec [hl] + dec [hl] + ret + +.no_status + ld a, [EnemyMonStatus] + and a + ret nz + jp AIDiscourageMove + +; 38d5a + + +AI_Smart_PriorityHit: ; 38d5a + call AICompareSpeed + ret c + +; Dismiss this move if the player is flying or underground. + ld a, [PlayerSubStatus3] + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + jp nz, AIDiscourageMove + +; Greatly encourage this move if it will KO the player. + ld a, $1 + ld [hBattleTurn], a + push hl + callfar EnemyAttackDamage + callfar BattleCommand_DamageCalc + callfar BattleCommand_Stab + pop hl + ld a, [CurDamage + 1] + ld c, a + ld a, [CurDamage] + ld b, a + ld a, [BattleMonHP + 1] + cp c + ld a, [BattleMonHP] + sbc b + ret nc + dec [hl] + dec [hl] + dec [hl] + ret +; 38d93 + + +AI_Smart_Thief: ; 38d93 +; Don't use Thief unless it's the only move available. + + ld a, [hl] + add $1e + ld [hl], a + ret +; 38d98 + + +AI_Smart_Conversion2: ; 38d98 + ld a, [LastPlayerMove] + and a + jr nz, .asm_38dc9 + + push hl + dec a + ld hl, Moves + MOVE_TYPE + ld bc, MOVE_LENGTH + call AddNTimes + + ld a, BANK(Moves) + call GetFarByte + ld [wPlayerMoveStruct + MOVE_TYPE], a + + xor a + ld [hBattleTurn], a + + callfar BattleCheckTypeMatchup + + ld a, [wd265] + cp $a + pop hl + jr c, .asm_38dc9 + ret z + + call AI_50_50 + ret c + + dec [hl] + ret + +.asm_38dc9 + call Random + cp 10 percent + ret c + inc [hl] + ret +; 38dd1 + + +AI_Smart_Disable: ; 38dd1 + call AICompareSpeed + jr nc, .asm_38df3 + + push hl + ld a, [LastPlayerCounterMove] + ld hl, UsefulMoves + ld de, 1 + call IsInArray + + pop hl + jr nc, .asm_38dee + + call Random + cp 39 percent + 1 + ret c + dec [hl] + ret + +.asm_38dee + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + ret nz + +.asm_38df3 + call Random + cp 8 percent + ret c + inc [hl] + ret +; 38dfb + + +AI_Smart_MeanLook: ; 38dfb + call AICheckEnemyHalfHP + jr nc, .asm_38e24 + + push hl + call AICheckLastPlayerMon + pop hl + jp z, AIDiscourageMove + +; 80% chance to greatly encourage this move if the enemy is badly poisoned (buggy). +; Should check PlayerSubStatus5 instead. + ld a, [EnemySubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_38e26 + +; 80% chance to greatly encourage this move if the player is either +; in love, identified, stuck in Rollout, or has a Nightmare. + ld a, [PlayerSubStatus1] + and 1<<SUBSTATUS_IN_LOVE | 1<<SUBSTATUS_ROLLOUT | 1<<SUBSTATUS_IDENTIFIED | 1<<SUBSTATUS_NIGHTMARE + jr nz, .asm_38e26 + +; Otherwise, discourage this move unless the player only has not very effective moves against the enemy. + push hl + callfar CheckPlayerMoveTypeMatchups + ld a, [wEnemyAISwitchScore] + cp $b ; not very effective + pop hl + ret nc + +.asm_38e24 + inc [hl] + ret + +.asm_38e26 + call AI_80_20 + ret c + dec [hl] + dec [hl] + dec [hl] + ret +; 38e2e + + +AICheckLastPlayerMon: ; 38e2e + ld a, [PartyCount] + ld b, a + ld c, 0 + ld hl, PartyMon1HP + ld de, PARTYMON_STRUCT_LENGTH + +.loop + ld a, [CurBattleMon] + cp c + jr z, .asm_38e44 + + ld a, [hli] + or [hl] + ret nz + dec hl + +.asm_38e44 + add hl, de + inc c + dec b + jr nz, .loop + + ret +; 38e4a + + +AI_Smart_Nightmare: ; 38e4a +; 50% chance to encourage this move. +; The AI_Basic layer will make sure that +; Dream Eater is only used against sleeping targets. + + call AI_50_50 + ret c + dec [hl] + ret +; 38e50 + + +AI_Smart_FlameWheel: ; 38e50 +; Use this move if the enemy is frozen. + + ld a, [EnemyMonStatus] + bit FRZ, a + ret z +rept 5 + dec [hl] +endr + ret +; 38e5c + + +AI_Smart_Curse: ; 38e5c + ld a, [EnemyMonType1] + cp GHOST + jr z, .ghostcurse + ld a, [EnemyMonType2] + cp GHOST + jr z, .ghostcurse + + call AICheckEnemyHalfHP + jr nc, .asm_38e93 + + ld a, [EnemyAtkLevel] + cp $b + jr nc, .asm_38e93 + cp $9 + ret nc + + ld a, [BattleMonType1] + cp GHOST + jr z, .asm_38e92 + cp SPECIAL + ret nc + ld a, [BattleMonType2] + cp SPECIAL + ret nc + call AI_80_20 + ret c + dec [hl] + dec [hl] + ret + +.asm_38e90 + inc [hl] + inc [hl] +.asm_38e92 + inc [hl] +.asm_38e93 + inc [hl] + ret + +.ghostcurse + ld a, [PlayerSubStatus1] + bit SUBSTATUS_CURSE, a + jp nz, AIDiscourageMove + + push hl + farcall FindAliveEnemyMons + pop hl + jr nc, .asm_38eb0 + + push hl + call AICheckLastPlayerMon + pop hl + jr nz, .asm_38e90 + + jr .asm_38eb7 + + +.asm_38eb0 + push hl + call AICheckLastPlayerMon + pop hl + jr z, .asm_38ecb + + +.asm_38eb7 + call AICheckEnemyQuarterHP + jp nc, .asm_38e90 + + call AICheckEnemyHalfHP + jr nc, .asm_38e92 + + call AICheckEnemyMaxHP + ret nc + + ld a, [PlayerTurnsTaken] + and a + ret nz + +.asm_38ecb + call AI_50_50 + ret c + + dec [hl] + dec [hl] + ret +; 38ed2 + + +AI_Smart_Protect: ; 38ed2 + ld a, [EnemyProtectCount] + and a + jr nz, .asm_38f13 + + ld a, [PlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .asm_38f14 + + ld a, [PlayerFuryCutterCount] + cp 3 + jr nc, .asm_38f0d + + ld a, [PlayerSubStatus3] + bit SUBSTATUS_CHARGED, a + jr nz, .asm_38f0d + + ld a, [PlayerSubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_38f0d + ld a, [PlayerSubStatus4] + bit SUBSTATUS_LEECH_SEED, a + jr nz, .asm_38f0d + ld a, [PlayerSubStatus1] + bit SUBSTATUS_CURSE, a + jr nz, .asm_38f0d + + bit SUBSTATUS_ROLLOUT, a + jr z, .asm_38f14 + + ld a, [PlayerRolloutCount] + cp 3 + jr c, .asm_38f14 + +.asm_38f0d + call AI_80_20 + ret c + dec [hl] + ret + +.asm_38f13 + inc [hl] + +.asm_38f14 + call Random + cp 8 percent + ret c + inc [hl] + inc [hl] + ret +; 38f1d + + +AI_Smart_Foresight: ; 38f1d + ld a, [EnemyAccLevel] + cp $5 + jr c, .asm_38f41 + ld a, [PlayerEvaLevel] + cp $a + jr nc, .asm_38f41 + + ld a, [BattleMonType1] + cp GHOST + jr z, .asm_38f41 + ld a, [BattleMonType2] + cp GHOST + jr z, .asm_38f41 + + call Random + cp 8 percent + ret c + inc [hl] + ret + +.asm_38f41 + call Random + cp 39 percent + 1 + ret c + dec [hl] + dec [hl] + ret +; 38f4a + + +AI_Smart_PerishSong: ; 38f4a + push hl + callfar FindAliveEnemyMons + pop hl + jr c, .no + + ld a, [PlayerSubStatus5] + bit SUBSTATUS_CANT_RUN, a + jr nz, .yes + + push hl + callfar CheckPlayerMoveTypeMatchups + ld a, [wEnemyAISwitchScore] + cp 10 ; 1.0 + pop hl + ret c + + call AI_50_50 + ret c + + inc [hl] + ret + +.yes + call AI_50_50 + ret c + + dec [hl] + ret + +.no + ld a, [hl] + add 5 + ld [hl], a + ret +; 38f7a + + +AI_Smart_Sandstorm: ; 38f7a + +; Greatly discourage this move if the player is immune to Sandstorm damage. + ld a, [BattleMonType1] + push hl + ld hl, .SandstormImmuneTypes + ld de, 1 + call IsInArray + pop hl + jr c, .asm_38fa5 + + ld a, [BattleMonType2] + push hl + ld hl, .SandstormImmuneTypes + ld de, 1 + call IsInArray + pop hl + jr c, .asm_38fa5 + +; Discourage this move if player's HP is below 50%. + call AICheckPlayerHalfHP + jr nc, .asm_38fa6 + +; 50% chance to encourage this move otherwise. + call AI_50_50 + ret c + + dec [hl] + ret + +.asm_38fa5 + inc [hl] + +.asm_38fa6 + inc [hl] + ret + +.SandstormImmuneTypes: + db ROCK + db GROUND + db STEEL + db $ff +; 38fac + + +AI_Smart_Endure: ; 38fac + ld a, [EnemyProtectCount] + and a + jr nz, .asm_38fd8 + + call AICheckEnemyMaxHP + jr c, .asm_38fd8 + + call AICheckEnemyQuarterHP + jr c, .asm_38fd9 + + ld b, EFFECT_REVERSAL + call AIHasMoveEffect + jr nc, .asm_38fcb + + call AI_80_20 + ret c + + dec [hl] + dec [hl] + dec [hl] + ret + +.asm_38fcb + ld a, [EnemySubStatus5] + bit SUBSTATUS_LOCK_ON, a + ret z + + call AI_50_50 + ret c + + dec [hl] + dec [hl] + ret + +.asm_38fd8 + inc [hl] + +.asm_38fd9 + inc [hl] + ret +; 38fdb + + +AI_Smart_FuryCutter: ; 38fdb +; Encourage this move based on Fury Cutter's count. + + ld a, [EnemyFuryCutterCount] + and a + jr z, .end + dec [hl] + + cp 2 + jr c, .end + dec [hl] + dec [hl] + + cp 3 + jr c, .end + dec [hl] + dec [hl] + dec [hl] + +.end + + ; fallthrough +; 38fef + + +AI_Smart_Rollout: ; 38fef +; Rollout, Fury Cutter + +; 80% chance to discourage this move if the enemy is in love, confused, or paralyzed. + ld a, [EnemySubStatus1] + bit SUBSTATUS_IN_LOVE, a + jr nz, .asm_39020 + + ld a, [EnemySubStatus3] + bit SUBSTATUS_CONFUSED, a + jr nz, .asm_39020 + + ld a, [EnemyMonStatus] + bit PAR, a + jr nz, .asm_39020 + +; 80% chance to discourage this move if the enemy's HP is below 25%, +; or if accuracy or evasion modifiers favour the player. + call AICheckEnemyQuarterHP + jr nc, .asm_39020 + + ld a, [EnemyAccLevel] + cp 7 + jr c, .asm_39020 + ld a, [PlayerEvaLevel] + cp 8 + jr nc, .asm_39020 + +; Otherwise, 80% chance to greatly encourage this move. + call Random + cp 79 percent - 1 + ret nc + dec [hl] + dec [hl] + ret + +.asm_39020 + call AI_80_20 + ret c + inc [hl] + ret +; 39026 + + +AI_Smart_Swagger: +AI_Smart_Attract: ; 39026 +; 80% chance to encourage this move during the first turn of player's Pokemon. +; 80% chance to discourage this move otherwise. + + ld a, [PlayerTurnsTaken] + and a + jr z, .first_turn + + call AI_80_20 + ret c + inc [hl] + ret + +.first_turn + call Random + cp 79 percent - 1 + ret nc + dec [hl] + ret +; 3903a + + +AI_Smart_Safeguard: ; 3903a +; 80% chance to discourage this move if player's HP is below 50%. + + call AICheckPlayerHalfHP + ret c + call AI_80_20 + ret c + inc [hl] + ret +; 39044 + + +AI_Smart_Magnitude: +AI_Smart_Earthquake: ; 39044 + +; Greatly encourage this move if the player is underground and the enemy is faster. + ld a, [LastPlayerCounterMove] + cp DIG + ret nz + + ld a, [PlayerSubStatus3] + bit SUBSTATUS_UNDERGROUND, a + jr z, .could_dig + + call AICompareSpeed + ret nc + dec [hl] + dec [hl] + ret + +.could_dig + ; Try to predict if the player will use Dig this turn. + + ; 50% chance to encourage this move if the enemy is slower than the player. + call AICompareSpeed + ret c + + call AI_50_50 + ret c + + dec [hl] + ret +; 39062 + + +AI_Smart_BatonPass: ; 39062 +; Discourage this move if the player hasn't shown super-effective moves against the enemy. +; Consider player's type(s) if its moves are unknown. + + push hl + callfar CheckPlayerMoveTypeMatchups + ld a, [wEnemyAISwitchScore] + cp 10 ; neutral + pop hl + ret c + inc [hl] + ret +; 39072 + + +AI_Smart_Pursuit: ; 39072 +; 50% chance to greatly encourage this move if player's HP is below 25%. +; 80% chance to discourage this move otherwise. + + call AICheckPlayerQuarterHP + jr nc, .asm_3907d + call AI_80_20 + ret c + inc [hl] + ret + +.asm_3907d + call AI_50_50 + ret c + dec [hl] + dec [hl] + ret +; 39084 + + +AI_Smart_RapidSpin: ; 39084 +; 80% chance to greatly encourage this move if the enemy is +; trapped (Bind effect), seeded, or scattered with spikes. + + ld a, [wEnemyWrapCount] + and a + jr nz, .asm_39097 + + ld a, [EnemySubStatus4] + bit SUBSTATUS_LEECH_SEED, a + jr nz, .asm_39097 + + ld a, [EnemyScreens] + bit SCREENS_SPIKES, a + ret z + +.asm_39097 + call AI_80_20 + ret c + + dec [hl] + dec [hl] + ret +; 3909e + + +AI_Smart_HiddenPower: ; 3909e + push hl + ld a, 1 + ld [hBattleTurn], a + +; Calculate Hidden Power's type and base power based on enemy's DVs. + callfar HiddenPowerDamage + callfar BattleCheckTypeMatchup + pop hl + +; Discourage Hidden Power if not very effective. + ld a, [wd265] + cp 10 + jr c, .bad + +; Discourage Hidden Power if its base power is lower than 50. + ld a, d + cp 50 + jr c, .bad + +; Encourage Hidden Power if super-effective. + ld a, [wd265] + cp 11 + jr nc, .good + +; Encourage Hidden Power if its base power is 70. + ld a, d + cp 70 + ret c + +.good + dec [hl] + ret + +.bad + inc [hl] + ret +; 390cb + + +AI_Smart_RainDance: ; 390cb + +; Greatly discourage this move if it would favour the player type-wise. +; Particularly, if the player is a Water-type. + ld a, [BattleMonType1] + cp WATER + jr z, AIBadWeatherType + cp FIRE + jr z, AIGoodWeatherType + + ld a, [BattleMonType2] + cp WATER + jr z, AIBadWeatherType + cp FIRE + jr z, AIGoodWeatherType + + push hl + ld hl, RainDanceMoves + jr AI_Smart_WeatherMove +; 390e7 + +RainDanceMoves: ; 390e7 + db WATER_GUN + db HYDRO_PUMP + db SURF + db BUBBLEBEAM + db THUNDER + db WATERFALL + db CLAMP + db BUBBLE + db CRABHAMMER + db OCTAZOOKA + db WHIRLPOOL + db $ff +; 390f3 + + +AI_Smart_SunnyDay: ; 390f3 + +; Greatly discourage this move if it would favour the player type-wise. +; Particularly, if the player is a Fire-type. + ld a, [BattleMonType1] + cp FIRE + jr z, AIBadWeatherType + cp WATER + jr z, AIGoodWeatherType + + ld a, [BattleMonType2] + cp FIRE + jr z, AIBadWeatherType + cp WATER + jr z, AIGoodWeatherType + + push hl + ld hl, SunnyDayMoves + + ; fallthrough +; 3910d + + +AI_Smart_WeatherMove: ; 3910d +; Rain Dance, Sunny Day + +; Greatly discourage this move if the enemy doesn't have +; one of the useful Rain Dance or Sunny Day moves. + call AIHasMoveInArray + pop hl + jr nc, AIBadWeatherType + +; Greatly discourage this move if player's HP is below 50%. + call AICheckPlayerHalfHP + jr nc, AIBadWeatherType + +; 50% chance to encourage this move otherwise. + call AI_50_50 + ret c + + dec [hl] + ret +; 3911e + +AIBadWeatherType: ; 3911e + inc [hl] + inc [hl] + inc [hl] + ret +; 39122 + +AIGoodWeatherType: ; 39122 +; Rain Dance, Sunny Day + +; Greatly encourage this move if it would disfavour the player type-wise and player's HP is above 50%... + call AICheckPlayerHalfHP + ret nc + +; ...as long as one of the following conditions meet: +; It's the first turn of the player's Pokemon. + ld a, [PlayerTurnsTaken] + and a + jr z, .good + +; Or it's the first turn of the enemy's Pokemon. + ld a, [EnemyTurnsTaken] + and a + ret nz + +.good + dec [hl] + dec [hl] + ret +; 39134 + + +SunnyDayMoves: ; 39134 + db FIRE_PUNCH + db EMBER + db FLAMETHROWER + db FIRE_SPIN + db FIRE_BLAST + db SACRED_FIRE + db MORNING_SUN + db SYNTHESIS + db $ff +; 3913d + + +AI_Smart_BellyDrum: ; 3913d +; Dismiss this move if enemy's attack is higher than +2 or if enemy's HP is below 50%. +; Else, discourage this move if enemy's HP is not full. + + ld a, [EnemyAtkLevel] + cp $a + jr nc, .asm_3914d + + call AICheckEnemyMaxHP + ret c + + inc [hl] + + call AICheckEnemyHalfHP + ret c + +.asm_3914d + ld a, [hl] + add $5 + ld [hl], a + ret +; 39152 + + +AI_Smart_PsychUp: ; 39152 + push hl + ld hl, EnemyAtkLevel + ld b, $8 + ld c, 100 + +; Calculate the sum of all enemy's stat level modifiers. Add 100 first to prevent underflow. +; Put the result in c. c will range between 58 and 142. +.asm_3915a + ld a, [hli] + sub $7 + add c + ld c, a + dec b + jr nz, .asm_3915a + +; Calculate the sum of all player's stat level modifiers. Add 100 first to prevent underflow. +; Put the result in d. d will range between 58 and 142. + ld hl, PlayerAtkLevel + ld b, $8 + ld d, 100 + +.asm_39169 + ld a, [hli] + sub $7 + add d + ld d, a + dec b + jr nz, .asm_39169 + +; Greatly discourage this move if enemy's stat levels are higher than player's (if c>=d). + ld a, c + sub d + pop hl + jr nc, .asm_39188 + +; Else, 80% chance to encourage this move unless player's accuracy level is lower than -1... + ld a, [PlayerAccLevel] + cp $6 + ret c + +; ...or enemy's evasion level is higher than +0. + ld a, [EnemyEvaLevel] + cp $8 + ret nc + + call AI_80_20 + ret c + + dec [hl] + ret + +.asm_39188 + inc [hl] + inc [hl] + ret +; 3918b + + +AI_Smart_MirrorCoat: ; 3918b + push hl + ld hl, PlayerUsedMoves + ld c, $4 + ld b, $0 + +.asm_39193 + ld a, [hli] + and a + jr z, .asm_391a8 + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .asm_391a8 + + ld a, [wEnemyMoveStruct + MOVE_TYPE] + cp SPECIAL + jr c, .asm_391a8 + + inc b + +.asm_391a8 + dec c + jr nz, .asm_39193 + + pop hl + ld a, b + and a + jr z, .asm_391d3 + + cp $3 + jr nc, .asm_391ca + + ld a, [LastPlayerCounterMove] + and a + jr z, .asm_391d2 + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .asm_391d2 + + ld a, [wEnemyMoveStruct + MOVE_TYPE] + cp SPECIAL + jr c, .asm_391d2 + + +.asm_391ca + call Random + cp 100 + jr c, .asm_391d2 + dec [hl] + +.asm_391d2 + ret + +.asm_391d3 + inc [hl] + ret +; 391d5 + + +AI_Smart_Twister: +AI_Smart_Gust: ; 391d5 + +; Greatly encourage this move if the player is flying and the enemy is faster. + ld a, [LastPlayerCounterMove] + cp FLY + ret nz + + ld a, [PlayerSubStatus3] + bit SUBSTATUS_FLYING, a + jr z, .couldFly + + call AICompareSpeed + ret nc + + dec [hl] + dec [hl] + ret + +; Try to predict if the player will use Fly this turn. +.couldFly + +; 50% chance to encourage this move if the enemy is slower than the player. + call AICompareSpeed + ret c + call AI_50_50 + ret c + dec [hl] + ret +; 391f3 + + +AI_Smart_FutureSight: ; 391f3 +; Greatly encourage this move if the player is +; flying or underground, and slower than the enemy. + + call AICompareSpeed + ret nc + + ld a, [PlayerSubStatus3] + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret z + + dec [hl] + dec [hl] + ret +; 39200 + + +AI_Smart_Stomp: ; 39200 +; 80% chance to encourage this move if the player has used Minimize. + + ld a, [wPlayerMinimized] + and a + ret z + + call AI_80_20 + ret c + + dec [hl] + ret +; 3920b + + +AI_Smart_Solarbeam: ; 3920b +; 80% chance to encourage this move when it's sunny. +; 90% chance to discourage this move when it's raining. + + ld a, [Weather] + cp WEATHER_SUN + jr z, .asm_3921e + + cp WEATHER_RAIN + ret nz + + call Random + cp 10 percent + ret c + + inc [hl] + inc [hl] + ret + +.asm_3921e + call AI_80_20 + ret c + + dec [hl] + dec [hl] + ret +; 39225 + + +AI_Smart_Thunder: ; 39225 +; 90% chance to discourage this move when it's sunny. + + ld a, [Weather] + cp WEATHER_SUN + ret nz + + call Random + cp 10 percent + ret c + + inc [hl] + ret +; 39233 + + +AICompareSpeed: ; 39233 +; Return carry if enemy is faster than player. + + push bc + ld a, [EnemyMonSpeed + 1] + ld b, a + ld a, [BattleMonSpeed + 1] + cp b + ld a, [EnemyMonSpeed] + ld b, a + ld a, [BattleMonSpeed] + sbc b + pop bc + ret +; 39246 + + +AICheckPlayerMaxHP: ; 39246 + push hl + push de + push bc + ld de, BattleMonHP + ld hl, BattleMonMaxHP + jr AICheckMaxHP +; 39251 + + +AICheckEnemyMaxHP: ; 39251 + push hl + push de + push bc + ld de, EnemyMonHP + ld hl, EnemyMonMaxHP + ; fallthrough +; 3925a + + +AICheckMaxHP: ; 3925a +; Return carry if hp at de matches max hp at hl. + + ld a, [de] + inc de + cp [hl] + jr nz, .asm_39269 + + inc hl + ld a, [de] + cp [hl] + jr nz, .asm_39269 + + pop bc + pop de + pop hl + scf + ret + +.asm_39269 + pop bc + pop de + pop hl + and a + ret +; 3926e + + +AICheckPlayerHalfHP: ; 3926e + push hl + ld hl, BattleMonHP + ld b, [hl] + inc hl + ld c, [hl] + sla c + rl b + inc hl + inc hl + ld a, [hld] + cp c + ld a, [hl] + sbc b + pop hl + ret +; 39281 + + +AICheckEnemyHalfHP: ; 39281 + push hl + push de + push bc + ld hl, EnemyMonHP + ld b, [hl] + inc hl + ld c, [hl] + sla c + rl b + inc hl + inc hl + ld a, [hld] + cp c + ld a, [hl] + sbc b + pop bc + pop de + pop hl + ret +; 39298 + + +AICheckEnemyQuarterHP: ; 39298 + push hl + push de + push bc + ld hl, EnemyMonHP + ld b, [hl] + inc hl + ld c, [hl] + sla c + rl b + sla c + rl b + inc hl + inc hl + ld a, [hld] + cp c + ld a, [hl] + sbc b + pop bc + pop de + pop hl + ret +; 392b3 + + +AICheckPlayerQuarterHP: ; 392b3 + push hl + ld hl, BattleMonHP + ld b, [hl] + inc hl + ld c, [hl] + sla c + rl b + sla c + rl b + inc hl + inc hl + ld a, [hld] + cp c + ld a, [hl] + sbc b + pop hl + ret +; 392ca + + +AIHasMoveEffect: ; 392ca +; Return carry if the enemy has move b. + + push hl + ld hl, EnemyMonMoves + ld c, EnemyMonMovesEnd - EnemyMonMoves + +.checkmove + ld a, [hli] + and a + jr z, .no + + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + cp b + jr z, .yes + + dec c + jr nz, .checkmove + +.no + pop hl + and a + ret + +.yes + pop hl + scf + ret +; 392e6 + + +AIHasMoveInArray: ; 392e6 +; Return carry if the enemy has a move in array hl. + + push hl + push de + push bc + +.next + ld a, [hli] + cp $ff + jr z, .done + + ld b, a + ld c, EnemyMonMovesEnd - EnemyMonMoves + 1 + ld de, EnemyMonMoves + +.check + dec c + jr z, .next + + ld a, [de] + inc de + cp b + jr nz, .check + + scf + +.done + pop bc + pop de + pop hl + ret +; 39301 + + +UsefulMoves: ; 39301 +; Moves that are usable all-around. + db DOUBLE_EDGE + db SING + db FLAMETHROWER + db HYDRO_PUMP + db SURF + db ICE_BEAM + db BLIZZARD + db HYPER_BEAM + db SLEEP_POWDER + db THUNDERBOLT + db THUNDER + db EARTHQUAKE + db TOXIC + db PSYCHIC_M + db HYPNOSIS + db RECOVER + db FIRE_BLAST + db SOFTBOILED + db SUPER_FANG + db $ff +; 39315 + + +AI_Opportunist: ; 39315 +; Discourage stall moves when the enemy's HP is low. + +; Do nothing if enemy's HP is above 50%. + call AICheckEnemyHalfHP + ret c + +; Discourage stall moves if enemy's HP is below 25%. + call AICheckEnemyQuarterHP + jr nc, .asm_39322 + +; 50% chance to discourage stall moves if enemy's HP is between 25% and 50%. + call AI_50_50 + ret c + +.asm_39322 + ld hl, Buffer1 - 1 + ld de, EnemyMonMoves + ld c, EnemyMonMovesEnd - EnemyMonMoves + 1 +.checkmove + inc hl + dec c + jr z, .asm_39347 + + ld a, [de] + inc de + and a + jr z, .asm_39347 + + push hl + push de + push bc + ld hl, .stallmoves + ld de, 1 + call IsInArray + + pop bc + pop de + pop hl + jr nc, .checkmove + + inc [hl] + jr .checkmove + +.asm_39347 + ret + +.stallmoves + db SWORDS_DANCE + db TAIL_WHIP + db LEER + db GROWL + db DISABLE + db MIST + db COUNTER + db LEECH_SEED + db GROWTH + db STRING_SHOT + db MEDITATE + db AGILITY + db RAGE + db MIMIC + db SCREECH + db HARDEN + db WITHDRAW + db DEFENSE_CURL + db BARRIER + db LIGHT_SCREEN + db HAZE + db REFLECT + db FOCUS_ENERGY + db BIDE + db AMNESIA + db TRANSFORM + db SPLASH + db ACID_ARMOR + db SHARPEN + db CONVERSION + db SUBSTITUTE + db FLAME_WHEEL + db $ff +; 39369 + + + +AI_Aggressive: ; 39369 +; Use whatever does the most damage. + +; Discourage all damaging moves but the one that does the most damage. +; If no damaging move deals damage to the player (immune), +; no move will be discouraged + +; Figure out which attack does the most damage and put it in c. + ld hl, EnemyMonMoves + ld bc, 0 + ld de, 0 +.checkmove + inc b + ld a, b + cp EnemyMonMovesEnd - EnemyMonMoves + 1 + jr z, .gotstrongestmove + + ld a, [hli] + and a + jr z, .gotstrongestmove + + push hl + push de + push bc + call AIGetEnemyMove + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .nodamage + call AIDamageCalc + pop bc + pop de + pop hl + +; Update current move if damage is highest so far + ld a, [CurDamage + 1] + cp e + ld a, [CurDamage] + sbc d + jr c, .checkmove + + ld a, [CurDamage + 1] + ld e, a + ld a, [CurDamage] + ld d, a + ld c, b + jr .checkmove + +.nodamage + pop bc + pop de + pop hl + jr .checkmove + +.gotstrongestmove +; Nothing we can do if no attacks did damage. + ld a, c + and a + jr z, .done + +; Discourage moves that do less damage unless they're reckless too. + ld hl, Buffer1 - 1 + ld de, EnemyMonMoves + ld b, 0 +.checkmove2 + inc b + ld a, b + cp EnemyMonMovesEnd - EnemyMonMoves + 1 + jr z, .done + +; Ignore this move if it is the highest damaging one. + cp c + ld a, [de] + inc de + inc hl + jr z, .checkmove2 + + call AIGetEnemyMove + +; Ignore this move if its power is 0 or 1. +; Moves such as Seismic Toss, Hidden Power, +; Counter and Fissure have a base power of 1. + ld a, [wEnemyMoveStruct + MOVE_POWER] + cp 2 + jr c, .checkmove2 + +; Ignore this move if it is reckless. + push hl + push de + push bc + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + ld hl, .RecklessMoves + ld de, 1 + call IsInArray + pop bc + pop de + pop hl + jr c, .checkmove2 + +; If we made it this far, discourage this move. + inc [hl] + jr .checkmove2 + +.done + ret + +.RecklessMoves: + db EFFECT_SELFDESTRUCT + db EFFECT_RAMPAGE + db EFFECT_MULTI_HIT + db EFFECT_DOUBLE_HIT + db $ff +; 393e7 + + +AIDamageCalc: ; 393e7 + ld a, 1 + ld [hBattleTurn], a + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + ld de, 1 + ld hl, .ConstantDamageEffects + call IsInArray + jr nc, .asm_39400 + callfar BattleCommand_ConstantDamage + ret + +.asm_39400 + callfar EnemyAttackDamage + callfar BattleCommand_DamageCalc + callfar BattleCommand_Stab + ret + +.ConstantDamageEffects: + db EFFECT_SUPER_FANG + db EFFECT_STATIC_DAMAGE + db EFFECT_LEVEL_DAMAGE + db EFFECT_PSYWAVE + db $ff +; 39418 + + +AI_Cautious: ; 39418 +; 90% chance to discourage moves with residual effects after the first turn. + + ld a, [EnemyTurnsTaken] + and a + ret z + + ld hl, Buffer1 - 1 + ld de, EnemyMonMoves + ld c, EnemyMonMovesEnd - EnemyMonMoves + 1 +.asm_39425 + inc hl + dec c + ret z + + ld a, [de] + inc de + and a + ret z + + push hl + push de + push bc + ld hl, .residualmoves + ld de, 1 + call IsInArray + + pop bc + pop de + pop hl + jr nc, .asm_39425 + + call Random + cp 90 percent + 1 + ret nc + + inc [hl] + jr .asm_39425 + +.residualmoves + db MIST + db LEECH_SEED + db POISONPOWDER + db STUN_SPORE + db THUNDER_WAVE + db FOCUS_ENERGY + db BIDE + db POISON_GAS + db TRANSFORM + db CONVERSION + db SUBSTITUTE + db SPIKES + db $ff +; 39453 + + + +AI_Status: ; 39453 +; Dismiss status moves that don't affect the player. + + ld hl, Buffer1 - 1 + ld de, EnemyMonMoves + ld b, EnemyMonMovesEnd - EnemyMonMoves + 1 +.checkmove + dec b + ret z + + inc hl + ld a, [de] + and a + ret z + + inc de + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + cp EFFECT_TOXIC + jr z, .poisonimmunity + cp EFFECT_POISON + jr z, .poisonimmunity + cp EFFECT_SLEEP + jr z, .typeimmunity + cp EFFECT_PARALYZE + jr z, .typeimmunity + + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .checkmove + + jr .typeimmunity + +.poisonimmunity + ld a, [BattleMonType1] + cp POISON + jr z, .immune + ld a, [BattleMonType2] + cp POISON + jr z, .immune + +.typeimmunity + push hl + push bc + push de + ld a, 1 + ld [hBattleTurn], a + callfar BattleCheckTypeMatchup + pop de + pop bc + pop hl + + ld a, [wd265] + and a + jr nz, .checkmove + +.immune + call AIDiscourageMove + jr .checkmove +; 394a9 + + + +AI_Risky: ; 394a9 +; Use any move that will KO the target. +; Risky moves will often be an exception (see below). + + ld hl, Buffer1 - 1 + ld de, EnemyMonMoves + ld c, EnemyMonMovesEnd - EnemyMonMoves + 1 +.checkmove + inc hl + dec c + ret z + + ld a, [de] + inc de + and a + ret z + + push de + push bc + push hl + call AIGetEnemyMove + + ld a, [wEnemyMoveStruct + MOVE_POWER] + and a + jr z, .nextmove + +; Don't use risky moves at max hp. + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + ld de, 1 + ld hl, .RiskyMoves + call IsInArray + jr nc, .checkko + + call AICheckEnemyMaxHP + jr c, .nextmove + +; Else, 80% chance to exclude them. + call Random + cp 79 percent - 1 + jr c, .nextmove + +.checkko + call AIDamageCalc + + ld a, [CurDamage + 1] + ld e, a + ld a, [CurDamage] + ld d, a + ld a, [BattleMonHP + 1] + cp e + ld a, [BattleMonHP] + sbc d + jr nc, .nextmove + + pop hl +rept 5 + dec [hl] +endr + push hl + +.nextmove + pop hl + pop bc + pop de + jr .checkmove + +.RiskyMoves: + db EFFECT_SELFDESTRUCT + db EFFECT_OHKO + db $ff +; 39502 + + + +AI_None: ; 39502 + ret +; 39503 + + +AIDiscourageMove: ; 39503 + ld a, [hl] + add 10 + ld [hl], a + ret +; 39508 + + +AIGetEnemyMove: ; 39508 +; Load attributes of move a into ram + + push hl + push de + push bc + dec a + ld hl, Moves + ld bc, MOVE_LENGTH + call AddNTimes + + ld de, wEnemyMoveStruct + ld a, BANK(Moves) + call FarCopyBytes + + pop bc + pop de + pop hl + ret +; 39521 + + +AI_80_20: ; 39521 + call Random + cp 20 percent - 1 + ret +; 39527 + + +AI_50_50: ; 39527 + call Random + cp 50 percent + 1 + ret +; 3952d diff --git a/engine/battle/ai/switch.asm b/engine/battle/ai/switch.asm new file mode 100755 index 000000000..c2f83fa1f --- /dev/null +++ b/engine/battle/ai/switch.asm @@ -0,0 +1,672 @@ +CheckPlayerMoveTypeMatchups: ; 3484e +; Check how well the moves you've already used +; fare against the enemy's Pokemon. Used to +; score a potential switch. + push hl + push de + push bc + ld a, 10 + ld [wEnemyAISwitchScore], a + ld hl, PlayerUsedMoves + ld a, [hl] + and a + jr z, .unknown_moves + + ld d, NUM_MOVES + ld e, 0 +.loop + ld a, [hli] + and a + jr z, .exit + push hl + dec a + ld hl, Moves + MOVE_POWER + call GetMoveAttr + and a + jr z, .next + + inc hl + call GetMoveByte + ld hl, EnemyMonType + call CheckTypeMatchup + ld a, [wTypeMatchup] + cp 10 + 1 ; 1.0 + 0.1 + jr nc, .super_effective + and a + jr z, .next + cp 10 ; 1.0 + jr nc, .neutral + +.not_very_effective + ld a, e + cp 1 ; 0.1 + jr nc, .next + ld e, 1 + jr .next + +.neutral + ld e, 2 + jr .next + +.super_effective + call .DecreaseScore + pop hl + jr .done + +.next + pop hl + dec d + jr nz, .loop + +.exit + ld a, e + cp 2 + jr z, .done + call .IncreaseScore + ld a, e + and a + jr nz, .done + call .IncreaseScore + jr .done + +.unknown_moves + ld a, [BattleMonType1] + ld b, a + ld hl, EnemyMonType1 + call CheckTypeMatchup + ld a, [wTypeMatchup] + cp 10 + 1 ; 1.0 + 0.1 + jr c, .ok + call .DecreaseScore +.ok + ld a, [BattleMonType2] + cp b + jr z, .ok2 + call CheckTypeMatchup + ld a, [wTypeMatchup] + cp 10 + 1 ; 1.0 + 0.1 + jr c, .ok2 + call .DecreaseScore +.ok2 + +.done + call .CheckEnemyMoveMatchups + pop bc + pop de + pop hl + ret +; 348de + + +.CheckEnemyMoveMatchups: ; 348de + ld de, EnemyMonMoves + ld b, NUM_MOVES + 1 + ld c, 0 + + ld a, [wTypeMatchup] + push af +.loop2 + dec b + jr z, .exit2 + + ld a, [de] + and a + jr z, .exit2 + + inc de + dec a + ld hl, Moves + MOVE_POWER + call GetMoveAttr + and a + jr z, .loop2 + + inc hl + call GetMoveByte + ld hl, BattleMonType1 + call CheckTypeMatchup + + ld a, [wTypeMatchup] + ; immune + and a + jr z, .loop2 + + ; not very effective + inc c + cp 10 + jr c, .loop2 + + ; neutral + inc c + inc c + inc c + inc c + inc c + cp 10 + jr z, .loop2 + + ; super effective + ld c, 100 + jr .loop2 + +.exit2 + pop af + ld [wTypeMatchup], a + + ld a, c + and a + jr z, .doubledown ; double down + cp 5 + jr c, .DecreaseScore ; down + cp 100 + ret c + jr .IncreaseScore ; up + +.doubledown + call .DecreaseScore +.DecreaseScore: ; 34931 + ld a, [wEnemyAISwitchScore] + dec a + ld [wEnemyAISwitchScore], a + ret +; 34939 + +.IncreaseScore: ; 34939 + ld a, [wEnemyAISwitchScore] + inc a + ld [wEnemyAISwitchScore], a + ret +; 34941 + +CheckAbleToSwitch: ; 34941 + xor a + ld [wEnemySwitchMonParam], a + call FindAliveEnemyMons + ret c + + ld a, [EnemySubStatus1] + bit SUBSTATUS_PERISH, a + jr z, .no_perish + + ld a, [EnemyPerishCount] + cp 1 + jr nz, .no_perish + + ; Perish count is 1 + + call FindAliveEnemyMons + call FindEnemyMonsWithAtLeastQuarterMaxHP + call FindEnemyMonsThatResistPlayer + call FindAliveEnemyMonsWithASuperEffectiveMove + + ld a, e + cp 2 + jr nz, .not_2 + + ld a, [wEnemyAISwitchScore] + add $30 ; maximum chance + ld [wEnemySwitchMonParam], a + ret + +.not_2 + call FindAliveEnemyMons + sla c + sla c + ld b, $ff + +.loop1 + inc b + sla c + jr nc, .loop1 + + ld a, b + add $30 ; maximum chance + ld [wEnemySwitchMonParam], a + ret + +.no_perish + call CheckPlayerMoveTypeMatchups + ld a, [wEnemyAISwitchScore] + cp 11 + ret nc + + ld a, [LastPlayerCounterMove] + and a + jr z, .no_last_counter_move + + call FindEnemyMonsImmuneToLastCounterMove + ld a, [wEnemyAISwitchScore] + and a + jr z, .no_last_counter_move + + ld c, a + call FindEnemyMonsWithASuperEffectiveMove + ld a, [wEnemyAISwitchScore] + cp $ff + ret z + + ld b, a + ld a, e + cp 2 + jr z, .not_2_again + + call CheckPlayerMoveTypeMatchups + ld a, [wEnemyAISwitchScore] + cp 10 + ret nc + + ld a, b + add $10 + ld [wEnemySwitchMonParam], a + ret + +.not_2_again + ld c, $10 + call CheckPlayerMoveTypeMatchups + ld a, [wEnemyAISwitchScore] + cp 10 + jr nc, .okay + ld c, $20 + +.okay + ld a, b + add c + ld [wEnemySwitchMonParam], a + ret + +.no_last_counter_move + call CheckPlayerMoveTypeMatchups + ld a, [wEnemyAISwitchScore] + cp 10 + ret nc + + call FindAliveEnemyMons + call FindEnemyMonsWithAtLeastQuarterMaxHP + call FindEnemyMonsThatResistPlayer + call FindAliveEnemyMonsWithASuperEffectiveMove + + ld a, e + cp $2 + ret nz + + ld a, [wEnemyAISwitchScore] + add $10 + ld [wEnemySwitchMonParam], a + ret +; 349f4 + + +FindAliveEnemyMons: ; 349f4 + ld a, [OTPartyCount] + cp 2 + jr c, .only_one + + ld d, a + ld e, 0 + ld b, 1 << (PARTY_LENGTH - 1) + ld c, 0 + ld hl, OTPartyMon1HP + +.loop + ld a, [CurOTMon] + cp e + jr z, .next + + push bc + ld b, [hl] + inc hl + ld a, [hld] + or b + pop bc + jr z, .next + + ld a, c + or b + ld c, a + +.next + srl b + push bc + ld bc, PARTYMON_STRUCT_LENGTH + add hl, bc + pop bc + inc e + dec d + jr nz, .loop + + ld a, c + and a + jr nz, .more_than_one + +.only_one + scf + ret + +.more_than_one + and a + ret +; 34a2a + + +FindEnemyMonsImmuneToLastCounterMove: ; 34a2a + ld hl, OTPartyMon1 + ld a, [OTPartyCount] + ld b, a + ld c, 1 << (PARTY_LENGTH - 1) + ld d, 0 + xor a + ld [wEnemyAISwitchScore], a + +.loop + ld a, [CurOTMon] + cp d + push hl + jr z, .next + + push hl + push bc + + ; If the Pokemon has at least 1 HP... + ld bc, MON_HP + add hl, bc + pop bc + ld a, [hli] + or [hl] + pop hl + jr z, .next + + ld a, [hl] + ld [CurSpecies], a + call GetBaseData + + ; the player's last move is damaging... + ld a, [LastPlayerCounterMove] + dec a + ld hl, Moves + MOVE_POWER + call GetMoveAttr + and a + jr z, .next + + ; and the Pokemon is immune to it... + inc hl + call GetMoveByte + ld hl, BaseType + call CheckTypeMatchup + ld a, [wTypeMatchup] + and a + jr nz, .next + + ; ... encourage that Pokemon. + ld a, [wEnemyAISwitchScore] + or c + ld [wEnemyAISwitchScore], a +.next + pop hl + dec b + ret z + + push bc + ld bc, PARTYMON_STRUCT_LENGTH + add hl, bc + pop bc + + inc d + srl c + jr .loop +; 34a85 + + +FindAliveEnemyMonsWithASuperEffectiveMove: ; 34a85 + push bc + ld a, [OTPartyCount] + ld e, a + ld hl, OTPartyMon1HP + ld b, 1 << (PARTY_LENGTH - 1) + ld c, 0 +.loop + ld a, [hli] + or [hl] + jr z, .next + + ld a, b + or c + ld c, a + +.next + srl b + push bc + ld bc, PartyMon2HP - (PartyMon1HP + 1) + add hl, bc + pop bc + dec e + jr nz, .loop + + ld a, c + pop bc + + and c + ld c, a +FindEnemyMonsWithASuperEffectiveMove: ; 34aa7 + + ld a, -1 + ld [wEnemyAISwitchScore], a + ld hl, OTPartyMon1Moves + ld b, 1 << (PARTY_LENGTH - 1) + ld d, 0 + ld e, 0 +.loop + ld a, b + and c + jr z, .next + + push hl + push bc + ; for move on mon: + ld b, NUM_MOVES + ld c, 0 +.loop3 + ; if move is None: break + ld a, [hli] + and a + push hl + jr z, .break3 + + ; if move has no power: continue + dec a + ld hl, Moves + MOVE_POWER + call GetMoveAttr + and a + jr z, .nope + + ; check type matchups + inc hl + call GetMoveByte + ld hl, BattleMonType1 + call CheckTypeMatchup + + ; if immune or not very effective: continue + ld a, [wTypeMatchup] + cp 10 + jr c, .nope + + ; if neutral: load 1 and continue + ld e, 1 + cp 10 + 1 + jr c, .nope + + ; if super-effective: load 2 and break + ld e, 2 + jr .break3 + +.nope + pop hl + dec b + jr nz, .loop3 + + jr .done + +.break3 + pop hl +.done + ld a, e + pop bc + pop hl + cp 2 + jr z, .done2 ; at least one move is super-effective + cp 1 + jr nz, .next ; no move does more than half damage + + ; encourage this pokemon + ld a, d + or b + ld d, a + jr .next ; such a long jump + +.next + ; next pokemon? + push bc + ld bc, PARTYMON_STRUCT_LENGTH + add hl, bc + pop bc + srl b + jr nc, .loop + + ; if no pokemon has a super-effective move: return + ld a, d + ld b, a + and a + ret z + +.done2 + ; convert the bit flag to an int and return + push bc + sla b + sla b + ld c, $ff +.loop2 + inc c + sla b + jr nc, .loop2 + + ld a, c + ld [wEnemyAISwitchScore], a + pop bc + ret +; 34b20 + + +FindEnemyMonsThatResistPlayer: ; 34b20 + push bc + ld hl, OTPartySpecies + ld b, 1 << (PARTY_LENGTH - 1) + ld c, 0 + +.loop + ld a, [hli] + cp $ff + jr z, .done + + push hl + ld [CurSpecies], a + call GetBaseData + ld a, [LastPlayerCounterMove] + and a + jr z, .skip_move + + dec a + ld hl, Moves + MOVE_POWER + call GetMoveAttr + and a + jr z, .skip_move + + inc hl + call GetMoveByte + jr .check_type + +.skip_move + ld a, [BattleMonType1] + ld hl, BaseType + call CheckTypeMatchup + ld a, [wTypeMatchup] + cp 10 + 1 + jr nc, .dont_choose_mon + ld a, [BattleMonType2] + +.check_type + ld hl, BaseType + call CheckTypeMatchup + ld a, [wTypeMatchup] + cp 10 + 1 + jr nc, .dont_choose_mon + + ld a, b + or c + ld c, a + +.dont_choose_mon + srl b + pop hl + jr .loop + +.done + ld a, c + pop bc + and c + ld c, a + ret +; 34b77 + + +FindEnemyMonsWithAtLeastQuarterMaxHP: ; 34b77 + push bc + ld de, OTPartySpecies + ld b, 1 << (PARTY_LENGTH - 1) + ld c, 0 + ld hl, OTPartyMon1HP + +.loop + ld a, [de] + inc de + cp $ff + jr z, .done + + push hl + push bc + ld b, [hl] + inc hl + ld c, [hl] + inc hl + inc hl +; hl = MaxHP + 1 +; bc = [CurHP] * 4 + srl c + rl b + srl c + rl b +; if bc >= [hl], encourage + ld a, [hld] + cp c + ld a, [hl] + sbc b + pop bc + jr nc, .next + + ld a, b + or c + ld c, a + +.next + srl b + pop hl + push bc + ld bc, PARTYMON_STRUCT_LENGTH + add hl, bc + pop bc + jr .loop + +.done + ld a, c + pop bc + and c + ld c, a + ret +; 34bb1 diff --git a/engine/anim_hp_bar.asm b/engine/battle/anim_hp_bar.asm index 78062b547..78062b547 100755 --- a/engine/anim_hp_bar.asm +++ b/engine/battle/anim_hp_bar.asm diff --git a/engine/battle_transition.asm b/engine/battle/battle_transition.asm index bef74ad29..bef74ad29 100644 --- a/engine/battle_transition.asm +++ b/engine/battle/battle_transition.asm diff --git a/engine/battle/core.asm b/engine/battle/core.asm new file mode 100644 index 000000000..a62b70d72 --- /dev/null +++ b/engine/battle/core.asm @@ -0,0 +1,9511 @@ +; Core components of the battle engine. +BattleCore: +DoBattle: ; 3c000 + xor a + ld [wBattleParticipantsNotFainted], a + ld [wBattleParticipantsIncludingFainted], a + ld [wPlayerAction], a + ld [BattleEnded], a + inc a + ld [wBattleHasJustStarted], a + ld hl, OTPartyMon1HP + ld bc, PARTYMON_STRUCT_LENGTH - 1 + ld d, BATTLEACTION_SWITCH1 - 1 +.loop + inc d + ld a, [hli] + or [hl] + jr nz, .alive + add hl, bc + jr .loop + +.alive + ld a, d + ld [wBattleAction], a + ld a, [wLinkMode] + and a + jr z, .not_linked + + ld a, [hLinkPlayerNumber] + cp $2 + jr z, .player_2 + +.not_linked + ld a, [wBattleMode] + dec a + jr z, .wild + xor a + ld [wEnemySwitchMonIndex], a + call NewEnemyMonStatus + call ResetEnemyStatLevels + call BreakAttraction + call EnemySwitch + +.wild + ld c, 40 + call DelayFrames + +.player_2 + call LoadTileMapToTempTileMap + call CheckPlayerPartyForFitPkmn + ld a, d + and a + jp z, LostBattle + call Call_LoadTempTileMapToTileMap + ld a, [BattleType] + cp BATTLETYPE_DEBUG + jp z, .tutorial_debug + cp BATTLETYPE_TUTORIAL + jp z, .tutorial_debug + xor a + ld [CurPartyMon], a +.loop2 + call CheckIfCurPartyMonIsFitToFight + jr nz, .alive2 + ld hl, CurPartyMon + inc [hl] + jr .loop2 + +.alive2 + ld a, [CurBattleMon] + ld [LastPlayerMon], a + ld a, [CurPartyMon] + ld [CurBattleMon], a + inc a + ld hl, PartySpecies - 1 + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + ld [CurPartySpecies], a + ld [TempBattleMonSpecies], a + hlcoord 1, 5 + ld a, 9 + call SlideBattlePicOut + call LoadTileMapToTempTileMap + call ResetBattleParticipants + call InitBattleMon + call ResetPlayerStatLevels + call SendOutPkmnText + call NewBattleMonStatus + call BreakAttraction + call SendOutPlayerMon + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + call SetPlayerTurn + call SpikesDamage + ld a, [wLinkMode] + and a + jr z, .not_linked_2 + ld a, [hLinkPlayerNumber] + cp $2 + jr nz, .not_linked_2 + xor a + ld [wEnemySwitchMonIndex], a + call NewEnemyMonStatus + call ResetEnemyStatLevels + call BreakAttraction + call EnemySwitch + call SetEnemyTurn + call SpikesDamage + +.not_linked_2 + jp BattleTurn + +.tutorial_debug + jp BattleMenu +; 3c0e5 + +WildFled_EnemyFled_LinkBattleCanceled: ; 3c0e5 + call Call_LoadTempTileMapToTileMap + ld a, [wBattleResult] + and $c0 + add $2 + ld [wBattleResult], a + ld a, [wLinkMode] + and a + ld hl, BattleText_WildFled + jr z, .print_text + + ld a, [wBattleResult] + and $c0 + ld [wBattleResult], a + ld hl, BattleText_EnemyFled + call CheckMobileBattleError + jr nc, .print_text + + ld hl, wcd2a + bit 4, [hl] + jr nz, .skip_text + + ld hl, BattleText_LinkErrorBattleCanceled + +.print_text + call StdBattleTextBox + +.skip_text + call StopDangerSound + call CheckMobileBattleError + jr c, .skip_sfx + + ld de, SFX_RUN + call PlaySFX + +.skip_sfx + call SetPlayerTurn + ld a, 1 + ld [BattleEnded], a + ret +; 3c12f + +BattleTurn: ; 3c12f +.loop + call MobileFn_3c1bf + call CheckContestBattleOver + jp c, .quit + + xor a + ld [wPlayerIsSwitching], a + ld [wEnemyIsSwitching], a + ld [wBattleHasJustStarted], a + ld [wPlayerJustGotFrozen], a + ld [wEnemyJustGotFrozen], a + ld [CurDamage], a + ld [CurDamage + 1], a + + call HandleBerserkGene + call UpdateBattleMonInParty + farcall AIChooseMove + + call IsMobileBattle + jr nz, .not_disconnected + farcall Function100da5 + farcall StartMobileInactivityTimer + farcall Function100dd8 + jp c, .quit +.not_disconnected + + call CheckPlayerLockedIn + jr c, .skip_iteration +.loop1 + call BattleMenu + jr c, .quit + ld a, [BattleEnded] + and a + jr nz, .quit + ld a, [wForcedSwitch] ; roared/whirlwinded/teleported + and a + jr nz, .quit +.skip_iteration + call ParsePlayerAction + jr nz, .loop1 + + call EnemyTriesToFlee + jr c, .quit + + call DetermineMoveOrder + jr c, .false + call Battle_EnemyFirst + jr .proceed +.false + call Battle_PlayerFirst +.proceed + call CheckMobileBattleError + jr c, .quit + + ld a, [wForcedSwitch] + and a + jr nz, .quit + + ld a, [BattleEnded] + and a + jr nz, .quit + + call HandleBetweenTurnEffects + ld a, [BattleEnded] + and a + jr nz, .quit + jp .loop + +.quit + ret +; 3c1bf + +MobileFn_3c1bf: mobile + ld a, $5 + call GetSRAMBank + ld hl, $a89b ; s5_a89b + inc [hl] + jr nz, .finish + dec hl + inc [hl] + jr nz, .finish + dec [hl] + inc hl + dec [hl] + +.finish + call CloseSRAM + ret +; 3c1d6 + +HandleBetweenTurnEffects: ; 3c1d6 + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .CheckEnemyFirst + call CheckFaint_PlayerThenEnemy + ret c + call HandleFutureSight + call CheckFaint_PlayerThenEnemy + ret c + call HandleWeather + call CheckFaint_PlayerThenEnemy + ret c + call HandleWrap + call CheckFaint_PlayerThenEnemy + ret c + call HandlePerishSong + call CheckFaint_PlayerThenEnemy + ret c + jr .NoMoreFaintingConditions + +.CheckEnemyFirst: + call CheckFaint_EnemyThenPlayer + ret c + call HandleFutureSight + call CheckFaint_EnemyThenPlayer + ret c + call HandleWeather + call CheckFaint_EnemyThenPlayer + ret c + call HandleWrap + call CheckFaint_EnemyThenPlayer + ret c + call HandlePerishSong + call CheckFaint_EnemyThenPlayer + ret c + +.NoMoreFaintingConditions: + call HandleLeftovers + call HandleMysteryberry + call HanleDefrost + call HandleSafeguard + call HandleScreens + call HandleStatBoostingHeldItems + call HandleHealingItems + call UpdateBattleMonInParty + call LoadTileMapToTempTileMap + jp HandleEncore +; 3c23c + +CheckFaint_PlayerThenEnemy: ; 3c23c + call HasPlayerFainted + jr nz, .PlayerNotFainted + call HandlePlayerMonFaint + ld a, [BattleEnded] + and a + jr nz, .BattleIsOver + +.PlayerNotFainted: + call HasEnemyFainted + jr nz, .BattleContinues + call HandleEnemyMonFaint + ld a, [BattleEnded] + and a + jr nz, .BattleIsOver + +.BattleContinues: + and a + ret + +.BattleIsOver: + scf + ret +; 3c25c + +CheckFaint_EnemyThenPlayer: ; 3c25c + call HasEnemyFainted + jr nz, .EnemyNotFainted + call HandleEnemyMonFaint + ld a, [BattleEnded] + and a + jr nz, .BattleIsOver + +.EnemyNotFainted: + call HasPlayerFainted + jr nz, .BattleContinues + call HandlePlayerMonFaint + ld a, [BattleEnded] + and a + jr nz, .BattleIsOver + +.BattleContinues: + and a + ret + +.BattleIsOver: + scf + ret +; 3c27c + +HandleBerserkGene: ; 3c27c + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .reverse + + call .player + jr .enemy + +.reverse + call .enemy +; jr .player + +.player + call SetPlayerTurn + ld de, PartyMon1Item + ld a, [CurBattleMon] + ld b, a + jr .go + +.enemy + call SetEnemyTurn + ld de, OTPartyMon1Item + ld a, [CurOTMon] + ld b, a +; jr .go + +.go + push de + push bc + callfar GetUserItem + ld a, [hl] + ld [wd265], a + sub BERSERK_GENE + pop bc + pop de + ret nz + + ld [hl], a + + ld h, d + ld l, e + ld a, b + call GetPartyLocation + xor a + ld [hl], a + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + push af + set SUBSTATUS_CONFUSED, [hl] + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVarAddr + push hl + push af + xor a + ld [hl], a + ld [AttackMissed], a + ld [EffectFailed], a + farcall BattleCommand_AttackUp2 + pop af + pop hl + ld [hl], a + call GetItemName + ld hl, BattleText_UsersStringBuffer1Activated + call StdBattleTextBox + callfar BattleCommand_StatUpMessage + pop af + bit SUBSTATUS_CONFUSED, a + ret nz + xor a + ld [wNumHits], a + ld de, ANIM_CONFUSED + call Call_PlayBattleAnim_OnlyIfVisible + call SwitchTurnCore + ld hl, BecameConfusedText + jp StdBattleTextBox +; 3c300 + +EnemyTriesToFlee: ; 3c300 + ld a, [wLinkMode] + and a + jr z, .not_linked + ld a, [wBattleAction] + cp BATTLEACTION_FORFEIT + jr z, .forfeit + +.not_linked + and a + ret + +.forfeit + call WildFled_EnemyFled_LinkBattleCanceled + scf + ret +; 3c314 + +DetermineMoveOrder: ; 3c314 + ld a, [wLinkMode] + and a + jr z, .use_move + ld a, [wBattleAction] + cp BATTLEACTION_E + jr z, .use_move + cp BATTLEACTION_D + jr z, .use_move + sub BATTLEACTION_SWITCH1 + jr c, .use_move + ld a, [wPlayerAction] + cp $2 + jr nz, .switch + ld a, [hLinkPlayerNumber] + cp $2 + jr z, .player_2 + + call BattleRandom + cp 1 + (50 percent) + jp c, .player_first + jp .enemy_first + +.player_2 + call BattleRandom + cp 1 + (50 percent) + jp c, .enemy_first + jp .player_first + +.switch + callfar AI_Switch + call SetEnemyTurn + call SpikesDamage + jp .enemy_first + +.use_move + ld a, [wPlayerAction] + and a + jp nz, .player_first + call CompareMovePriority + jr z, .equal_priority + jp c, .player_first ; player goes first + jp .enemy_first + +.equal_priority + call SetPlayerTurn + callfar GetUserItem + push bc + callfar GetOpponentItem + pop de + ld a, d + cp HELD_QUICK_CLAW + jr nz, .player_no_quick_claw + ld a, b + cp HELD_QUICK_CLAW + jr z, .both_have_quick_claw + call BattleRandom + cp e + jr nc, .speed_check + jp .player_first + +.player_no_quick_claw + ld a, b + cp HELD_QUICK_CLAW + jr nz, .speed_check + call BattleRandom + cp c + jr nc, .speed_check + jp .enemy_first + +.both_have_quick_claw + ld a, [hLinkPlayerNumber] + cp $2 + jr z, .player_2b + call BattleRandom + cp c + jp c, .enemy_first + call BattleRandom + cp e + jp c, .player_first + jr .speed_check + +.player_2b + call BattleRandom + cp e + jp c, .player_first + call BattleRandom + cp c + jp c, .enemy_first + jr .speed_check + +.speed_check + ld de, BattleMonSpeed + ld hl, EnemyMonSpeed + ld c, 2 + call StringCmp + jr z, .speed_tie + jp nc, .player_first + jp .enemy_first + +.speed_tie + ld a, [hLinkPlayerNumber] + cp $2 + jr z, .player_2c + call BattleRandom + cp 1 + (50 percent) + jp c, .player_first + jp .enemy_first + +.player_2c + call BattleRandom + cp 1 + (50 percent) + jp c, .enemy_first +.player_first + scf + ret +; 3c3f3 + +.enemy_first ; 3c3f3 + and a + ret +; 3c3f5 + +CheckContestBattleOver: ; 3c3f5 + ld a, [BattleType] + cp BATTLETYPE_CONTEST + jr nz, .contest_not_over + ld a, [wParkBallsRemaining] + and a + jr nz, .contest_not_over + ld a, [wBattleResult] + and $c0 + add $2 + ld [wBattleResult], a + scf + ret + +.contest_not_over + and a + ret +; 3c410 + +CheckPlayerLockedIn: ; 3c410 + ld a, [PlayerSubStatus4] + and 1 << SUBSTATUS_RECHARGE + jp nz, .quit + + ld hl, EnemySubStatus3 + res SUBSTATUS_FLINCHED, [hl] + ld hl, PlayerSubStatus3 + res SUBSTATUS_FLINCHED, [hl] + + ld a, [hl] + and 1 << SUBSTATUS_CHARGED | 1 << SUBSTATUS_RAMPAGE + jp nz, .quit + + ld hl, PlayerSubStatus1 + bit SUBSTATUS_ROLLOUT, [hl] + jp nz, .quit + + and a + ret + +.quit + scf + ret +; 3c434 + +ParsePlayerAction: ; 3c434 + call CheckPlayerLockedIn + jp c, .locked_in + ld hl, PlayerSubStatus5 + bit SUBSTATUS_ENCORED, [hl] + jr z, .not_encored + ld a, [LastPlayerMove] + ld [CurPlayerMove], a + jr .encored + +.not_encored + ld a, [wPlayerAction] + cp $2 + jr z, .reset_rage + and a + jr nz, .reset_bide + ld a, [PlayerSubStatus3] + and 1 << SUBSTATUS_BIDE + jr nz, .locked_in + xor a + ld [wMoveSelectionMenuType], a + inc a ; POUND + ld [FXAnimID], a + call MoveSelectionScreen + push af + call Call_LoadTempTileMapToTileMap + call UpdateBattleHuds + ld a, [CurPlayerMove] + cp STRUGGLE + jr z, .struggle + call PlayClickSFX + +.struggle + ld a, $1 + ld [hBGMapMode], a + pop af + ret nz + +.encored + call SetPlayerTurn + callfar UpdateMoveData + xor a + ld [wPlayerCharging], a + ld a, [wPlayerMoveStruct + MOVE_EFFECT] + cp EFFECT_FURY_CUTTER + jr z, .continue_fury_cutter + xor a + ld [PlayerFuryCutterCount], a + +.continue_fury_cutter + ld a, [wPlayerMoveStruct + MOVE_EFFECT] + cp EFFECT_RAGE + jr z, .continue_rage + ld hl, PlayerSubStatus4 + res SUBSTATUS_RAGE, [hl] + xor a + ld [wPlayerRageCounter], a + +.continue_rage + ld a, [wPlayerMoveStruct + MOVE_EFFECT] + cp EFFECT_PROTECT + jr z, .continue_protect + cp EFFECT_ENDURE + jr z, .continue_protect + xor a + ld [PlayerProtectCount], a + jr .continue_protect + +.reset_bide + ld hl, PlayerSubStatus3 + res SUBSTATUS_BIDE, [hl] + +.locked_in + xor a + ld [PlayerFuryCutterCount], a + ld [PlayerProtectCount], a + ld [wPlayerRageCounter], a + ld hl, PlayerSubStatus4 + res SUBSTATUS_RAGE, [hl] + +.continue_protect + call ParseEnemyAction + xor a + ret + +.reset_rage + xor a + ld [PlayerFuryCutterCount], a + ld [PlayerProtectCount], a + ld [wPlayerRageCounter], a + ld hl, PlayerSubStatus4 + res SUBSTATUS_RAGE, [hl] + xor a + ret +; 3c4df + +HandleEncore: ; 3c4df + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .player_1 + call .do_player + jr .do_enemy + +.player_1 + call .do_enemy +.do_player + ld hl, PlayerSubStatus5 + bit SUBSTATUS_ENCORED, [hl] + ret z + ld a, [PlayerEncoreCount] + dec a + ld [PlayerEncoreCount], a + jr z, .end_player_encore + ld hl, BattleMonPP + ld a, [CurMoveNum] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + and $3f + ret nz + +.end_player_encore + ld hl, PlayerSubStatus5 + res SUBSTATUS_ENCORED, [hl] + call SetEnemyTurn + ld hl, BattleText_TargetsEncoreEnded + jp StdBattleTextBox + +.do_enemy + ld hl, EnemySubStatus5 + bit SUBSTATUS_ENCORED, [hl] + ret z + ld a, [EnemyEncoreCount] + dec a + ld [EnemyEncoreCount], a + jr z, .end_enemy_encore + ld hl, EnemyMonPP + ld a, [CurEnemyMoveNum] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + and $3f + ret nz + +.end_enemy_encore + ld hl, EnemySubStatus5 + res SUBSTATUS_ENCORED, [hl] + call SetPlayerTurn + ld hl, BattleText_TargetsEncoreEnded + jp StdBattleTextBox +; 3c543 + +TryEnemyFlee: ; 3c543 + ld a, [wBattleMode] + dec a + jr nz, .Stay + + ld a, [PlayerSubStatus5] + bit SUBSTATUS_CANT_RUN, a + jr nz, .Stay + + ld a, [wEnemyWrapCount] + and a + jr nz, .Stay + + ld a, [EnemyMonStatus] + and 1 << FRZ | SLP + jr nz, .Stay + + ld a, [TempEnemyMonSpecies] + ld de, 1 + ld hl, AlwaysFleeMons + call IsInArray + jr c, .Flee + + call BattleRandom + ld b, a + cp 1 + (50 percent) + jr nc, .Stay + + push bc + ld a, [TempEnemyMonSpecies] + ld de, 1 + ld hl, OftenFleeMons + call IsInArray + pop bc + jr c, .Flee + + ld a, b + cp 1 + (10 percent) + jr nc, .Stay + + ld a, [TempEnemyMonSpecies] + ld de, 1 + ld hl, SometimesFleeMons + call IsInArray + jr c, .Flee + +.Stay: + and a + ret + +.Flee: + scf + ret +; 3c59a + +INCLUDE "data/wild/flee_mons.asm" + +CompareMovePriority: ; 3c5b4 +; Compare the priority of the player and enemy's moves. +; Return carry if the player goes first, or z if they match. + + ld a, [CurPlayerMove] + call GetMovePriority + ld b, a + push bc + ld a, [CurEnemyMove] + call GetMovePriority + pop bc + cp b + ret +; 3c5c5 + +GetMovePriority: ; 3c5c5 +; Return the priority (0-3) of move a. + + ld b, a + + ; Vital Throw goes last. + cp VITAL_THROW + ld a, 0 + ret z + + call GetMoveEffect + ld hl, MoveEffectPriorities +.loop + ld a, [hli] + cp b + jr z, .done + inc hl + cp -1 + jr nz, .loop + + ld a, 1 + ret + +.done + ld a, [hl] + ret +; 3c5df + +MoveEffectPriorities: ; 3c5df + db EFFECT_PROTECT, 3 + db EFFECT_ENDURE, 3 + db EFFECT_PRIORITY_HIT, 2 + db EFFECT_FORCE_SWITCH, 0 + db EFFECT_COUNTER, 0 + db EFFECT_MIRROR_COAT, 0 + db -1 +; 3c5ec + +GetMoveEffect: ; 3c5ec + ld a, b + dec a + ld hl, Moves + MOVE_EFFECT + ld bc, MOVE_LENGTH + call AddNTimes + ld a, BANK(Moves) + call GetFarByte + ld b, a + ret +; 3c5fe + +Battle_EnemyFirst: ; 3c5fe + call LoadTileMapToTempTileMap + call TryEnemyFlee + jp c, WildFled_EnemyFled_LinkBattleCanceled + call SetEnemyTurn + ld a, $1 + ld [wEnemyGoesFirst], a + callfar AI_SwitchOrTryItem + jr c, .switch_item + call EnemyTurn_EndOpponentProtectEndureDestinyBond + call CheckMobileBattleError + ret c + ld a, [wForcedSwitch] + and a + ret nz + call HasPlayerFainted + jp z, HandlePlayerMonFaint + call HasEnemyFainted + jp z, HandleEnemyMonFaint + +.switch_item + call SetEnemyTurn + call ResidualDamage + jp z, HandleEnemyMonFaint + call RefreshBattleHuds + call PlayerTurn_EndOpponentProtectEndureDestinyBond + call CheckMobileBattleError + ret c + ld a, [wForcedSwitch] + and a + ret nz + call HasEnemyFainted + jp z, HandleEnemyMonFaint + call HasPlayerFainted + jp z, HandlePlayerMonFaint + call SetPlayerTurn + call ResidualDamage + jp z, HandlePlayerMonFaint + call RefreshBattleHuds + xor a + ld [wPlayerAction], a + ret +; 3c664 + +Battle_PlayerFirst: ; 3c664 + xor a + ld [wEnemyGoesFirst], a + call SetEnemyTurn + callfar AI_SwitchOrTryItem + push af + call PlayerTurn_EndOpponentProtectEndureDestinyBond + pop bc + ld a, [wForcedSwitch] + and a + ret nz + call CheckMobileBattleError + ret c + call HasEnemyFainted + jp z, HandleEnemyMonFaint + call HasPlayerFainted + jp z, HandlePlayerMonFaint + push bc + call SetPlayerTurn + call ResidualDamage + pop bc + jp z, HandlePlayerMonFaint + push bc + call RefreshBattleHuds + pop af + jr c, .switched_or_used_item + call LoadTileMapToTempTileMap + call TryEnemyFlee + jp c, WildFled_EnemyFled_LinkBattleCanceled + call EnemyTurn_EndOpponentProtectEndureDestinyBond + call CheckMobileBattleError + ret c + ld a, [wForcedSwitch] + and a + ret nz + call HasPlayerFainted + jp z, HandlePlayerMonFaint + call HasEnemyFainted + jp z, HandleEnemyMonFaint + +.switched_or_used_item + call SetEnemyTurn + call ResidualDamage + jp z, HandleEnemyMonFaint + call RefreshBattleHuds + xor a + ld [wPlayerAction], a + ret +; 3c6cf + +PlayerTurn_EndOpponentProtectEndureDestinyBond: ; 3c6cf + call SetPlayerTurn + call EndUserDestinyBond + callfar DoPlayerTurn + jp EndOpponentProtectEndureDestinyBond +; 3c6de + +EnemyTurn_EndOpponentProtectEndureDestinyBond: ; 3c6de + call SetEnemyTurn + call EndUserDestinyBond + callfar DoEnemyTurn + jp EndOpponentProtectEndureDestinyBond +; 3c6ed + +EndOpponentProtectEndureDestinyBond: ; 3c6ed + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVarAddr + res SUBSTATUS_PROTECT, [hl] + res SUBSTATUS_ENDURE, [hl] + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + res SUBSTATUS_DESTINY_BOND, [hl] + ret +; 3c6fe + +EndUserDestinyBond: ; 3c6fe + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVarAddr + res SUBSTATUS_DESTINY_BOND, [hl] + ret +; 3c706 + +HasUserFainted: ; 3c706 + ld a, [hBattleTurn] + and a + jr z, HasPlayerFainted +HasEnemyFainted: ; 3c70b + ld hl, EnemyMonHP + jr CheckIfHPIsZero + +HasPlayerFainted: ; 3c710 + ld hl, BattleMonHP + +CheckIfHPIsZero: ; 3c713 + ld a, [hli] + or [hl] + ret +; 3c716 + +ResidualDamage: ; 3c716 +; Return z if the user fainted before +; or as a result of residual damage. +; For Sandstorm damage, see HandleWeather. + + call HasUserFainted + ret z + + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and 1 << PSN | 1 << BRN + jr z, .did_psn_brn + + ld hl, HurtByPoisonText + ld de, ANIM_PSN + and 1 << BRN + jr z, .got_anim + ld hl, HurtByBurnText + ld de, ANIM_BRN +.got_anim + + push de + call StdBattleTextBox + pop de + + xor a + ld [wNumHits], a + call Call_PlayBattleAnim_OnlyIfVisible + call GetEighthMaxHP + ld de, PlayerToxicCount + ld a, [hBattleTurn] + and a + jr z, .check_toxic + ld de, EnemyToxicCount +.check_toxic + + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVar + bit SUBSTATUS_TOXIC, a + jr z, .did_toxic + call GetSixteenthMaxHP + ld a, [de] + inc a + ld [de], a + ld hl, 0 +.add + add hl, bc + dec a + jr nz, .add + ld b, h + ld c, l +.did_toxic + + call SubtractHPFromUser +.did_psn_brn + + call HasUserFainted + jp z, .fainted + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + bit SUBSTATUS_LEECH_SEED, [hl] + jr z, .not_seeded + + call SwitchTurnCore + xor a + ld [wNumHits], a + ld de, ANIM_SAP + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + call z, Call_PlayBattleAnim_OnlyIfVisible + call SwitchTurnCore + + call GetEighthMaxHP + call SubtractHPFromUser + ld a, $1 + ld [hBGMapMode], a + call RestoreHP + ld hl, LeechSeedSapsText + call StdBattleTextBox +.not_seeded + + call HasUserFainted + jr z, .fainted + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + bit SUBSTATUS_NIGHTMARE, [hl] + jr z, .not_nightmare + xor a + ld [wNumHits], a + ld de, ANIM_IN_NIGHTMARE + call Call_PlayBattleAnim_OnlyIfVisible + call GetQuarterMaxHP + call SubtractHPFromUser + ld hl, HasANightmareText + call StdBattleTextBox +.not_nightmare + + call HasUserFainted + jr z, .fainted + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + bit SUBSTATUS_CURSE, [hl] + jr z, .not_cursed + + xor a + ld [wNumHits], a + ld de, ANIM_IN_NIGHTMARE + call Call_PlayBattleAnim_OnlyIfVisible + call GetQuarterMaxHP + call SubtractHPFromUser + ld hl, HurtByCurseText + call StdBattleTextBox + +.not_cursed + ld hl, BattleMonHP + ld a, [hBattleTurn] + and a + jr z, .check_fainted + ld hl, EnemyMonHP + +.check_fainted + ld a, [hli] + or [hl] + ret nz + +.fainted + call RefreshBattleHuds + ld c, 20 + call DelayFrames + xor a + ret +; 3c801 + +HandlePerishSong: ; 3c801 + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .EnemyFirst + call SetPlayerTurn + call .do_it + call SetEnemyTurn + jp .do_it + +.EnemyFirst: + call SetEnemyTurn + call .do_it + call SetPlayerTurn + +.do_it + ld hl, PlayerPerishCount + ld a, [hBattleTurn] + and a + jr z, .got_count + ld hl, EnemyPerishCount + +.got_count + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVar + bit SUBSTATUS_PERISH, a + ret z + dec [hl] + ld a, [hl] + ld [wd265], a + push af + ld hl, PerishCountText + call StdBattleTextBox + pop af + ret nz + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + res SUBSTATUS_PERISH, [hl] + ld a, [hBattleTurn] + and a + jr nz, .kill_enemy + ld hl, BattleMonHP + xor a + ld [hli], a + ld [hl], a + ld hl, PartyMon1HP + ld a, [CurBattleMon] + call GetPartyLocation + xor a + ld [hli], a + ld [hl], a + ret + +.kill_enemy + ld hl, EnemyMonHP + xor a + ld [hli], a + ld [hl], a + ld a, [wBattleMode] + dec a + ret z + ld hl, OTPartyMon1HP + ld a, [CurOTMon] + call GetPartyLocation + xor a + ld [hli], a + ld [hl], a + ret +; 3c874 + +HandleWrap: ; 3c874 + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .EnemyFirst + call SetPlayerTurn + call .do_it + call SetEnemyTurn + jp .do_it + +.EnemyFirst: + call SetEnemyTurn + call .do_it + call SetPlayerTurn + +.do_it + ld hl, wPlayerWrapCount + ld de, wPlayerTrappingMove + ld a, [hBattleTurn] + and a + jr z, .got_addrs + ld hl, wEnemyWrapCount + ld de, wEnemyTrappingMove + +.got_addrs + ld a, [hl] + and a + ret z + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + ret nz + + ld a, [de] + ld [wd265], a + ld [FXAnimID], a + call GetMoveName + dec [hl] + jr z, .release_from_bounds + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + jr nz, .skip_anim + + call SwitchTurnCore + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + predef PlayBattleAnim + call SwitchTurnCore + +.skip_anim + call GetSixteenthMaxHP + call SubtractHPFromUser + ld hl, BattleText_UsersHurtByStringBuffer1 + jr .print_text + +.release_from_bounds + ld hl, BattleText_UserWasReleasedFromStringBuffer1 + +.print_text + jp StdBattleTextBox +; 3c8e4 + +SwitchTurnCore: ; 3c8e4 + ld a, [hBattleTurn] + xor 1 + ld [hBattleTurn], a + ret +; 3c8eb + +HandleLeftovers: ; 3c8eb + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .DoEnemyFirst + call SetPlayerTurn + call .do_it + call SetEnemyTurn + jp .do_it + +.DoEnemyFirst: + call SetEnemyTurn + call .do_it + call SetPlayerTurn +.do_it + + callfar GetUserItem + ld a, [hl] + ld [wd265], a + call GetItemName + ld a, b + cp HELD_LEFTOVERS + ret nz + + ld hl, BattleMonHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, EnemyMonHP + +.got_hp +; Don't restore if we're already at max HP + ld a, [hli] + ld b, a + ld a, [hli] + ld c, a + ld a, [hli] + cp b + jr nz, .restore + ld a, [hl] + cp c + ret z + +.restore + call GetSixteenthMaxHP + call SwitchTurnCore + call RestoreHP + ld hl, BattleText_TargetRecoveredWithItem + jp StdBattleTextBox +; 3c93c + +HandleMysteryberry: ; 3c93c + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .DoEnemyFirst + call SetPlayerTurn + call .do_it + call SetEnemyTurn + jp .do_it + +.DoEnemyFirst: + call SetEnemyTurn + call .do_it + call SetPlayerTurn + +.do_it + callfar GetUserItem + ld a, b + cp HELD_RESTORE_PP + jr nz, .quit + ld hl, PartyMon1PP + ld a, [CurBattleMon] + call GetPartyLocation + ld d, h + ld e, l + ld hl, PartyMon1Moves + ld a, [CurBattleMon] + call GetPartyLocation + ld a, [hBattleTurn] + and a + jr z, .wild + ld de, wWildMonPP + ld hl, wWildMonMoves + ld a, [wBattleMode] + dec a + jr z, .wild + ld hl, OTPartyMon1PP + ld a, [CurOTMon] + call GetPartyLocation + ld d, h + ld e, l + ld hl, OTPartyMon1Moves + ld a, [CurOTMon] + call GetPartyLocation + +.wild + ld c, $0 +.loop + ld a, [hl] + and a + jr z, .quit + ld a, [de] + and $3f + jr z, .restore + inc hl + inc de + inc c + ld a, c + cp NUM_MOVES + jr nz, .loop + +.quit + ret + +.restore + ; lousy hack + ld a, [hl] + cp SKETCH + ld b, 1 + jr z, .sketch + ld b, 5 +.sketch + ld a, [de] + add b + ld [de], a + push bc + push bc + ld a, [hl] + ld [wd265], a + ld de, BattleMonMoves - 1 + ld hl, BattleMonPP + ld a, [hBattleTurn] + and a + jr z, .player_pp + ld de, EnemyMonMoves - 1 + ld hl, EnemyMonPP +.player_pp + inc de + pop bc + ld b, 0 + add hl, bc + push hl + ld h, d + ld l, e + add hl, bc + pop de + pop bc + + ld a, [wd265] + cp [hl] + jr nz, .skip_checks + ld a, [hBattleTurn] + and a + ld a, [PlayerSubStatus5] + jr z, .check_transform + ld a, [EnemySubStatus5] +.check_transform + bit SUBSTATUS_TRANSFORMED, a + jr nz, .skip_checks + ld a, [de] + add b + ld [de], a +.skip_checks + callfar GetUserItem + ld a, [hl] + ld [wd265], a + xor a + ld [hl], a + call GetPartymonItem + ld a, [hBattleTurn] + and a + jr z, .consume_item + ld a, [wBattleMode] + dec a + jr z, .skip_consumption + call GetOTPartymonItem + +.consume_item + xor a + ld [hl], a + +.skip_consumption + call GetItemName + call SwitchTurnCore + call ItemRecoveryAnim + call SwitchTurnCore + ld hl, BattleText_UserRecoveredPPUsing + jp StdBattleTextBox +; 3ca26 + +HandleFutureSight: ; 3ca26 + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .enemy_first + call SetPlayerTurn + call .do_it + call SetEnemyTurn + jp .do_it + +.enemy_first + call SetEnemyTurn + call .do_it + call SetPlayerTurn + +.do_it + ld hl, wPlayerFutureSightCount + ld a, [hBattleTurn] + and a + jr z, .okay + ld hl, wEnemyFutureSightCount + +.okay + ld a, [hl] + and a + ret z + dec a + ld [hl], a + cp $1 + ret nz + + ld hl, BattleText_TargetWasHitByFutureSight + call StdBattleTextBox + + ld a, BATTLE_VARS_MOVE + call GetBattleVarAddr + push af + ld a, FUTURE_SIGHT + ld [hl], a + + callfar UpdateMoveData + xor a + ld [AttackMissed], a + ld [AlreadyDisobeyed], a + ld a, 10 + ld [TypeModifier], a + callfar DoMove + xor a + ld [CurDamage], a + ld [CurDamage + 1], a + + ld a, BATTLE_VARS_MOVE + call GetBattleVarAddr + pop af + ld [hl], a + + call UpdateBattleMonInParty + jp UpdateEnemyMonInParty +; 3ca8f + +HanleDefrost: ; 3ca8f + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .enemy_first + call .do_player_turn + jr .do_enemy_turn + +.enemy_first + call .do_enemy_turn +.do_player_turn + ld a, [BattleMonStatus] + bit FRZ, a + ret z + + ld a, [wPlayerJustGotFrozen] + and a + ret nz + + call BattleRandom + cp 10 percent + ret nc + xor a + ld [BattleMonStatus], a + ld a, [CurBattleMon] + ld hl, PartyMon1Status + call GetPartyLocation + ld [hl], 0 + call UpdateBattleHuds + call SetEnemyTurn + ld hl, DefrostedOpponentText + jp StdBattleTextBox + +.do_enemy_turn + ld a, [EnemyMonStatus] + bit FRZ, a + ret z + ld a, [wEnemyJustGotFrozen] + and a + ret nz + call BattleRandom + cp 10 percent + ret nc + xor a + ld [EnemyMonStatus], a + + ld a, [wBattleMode] + dec a + jr z, .wild + ld a, [CurOTMon] + ld hl, OTPartyMon1Status + call GetPartyLocation + ld [hl], 0 +.wild + + call UpdateBattleHuds + call SetPlayerTurn + ld hl, DefrostedOpponentText + jp StdBattleTextBox +; 3cafb + +HandleSafeguard: ; 3cafb + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .player1 + call .CheckPlayer + jr .CheckEnemy + +.player1 + call .CheckEnemy +.CheckPlayer: + ld a, [PlayerScreens] + bit SCREENS_SAFEGUARD, a + ret z + ld hl, PlayerSafeguardCount + dec [hl] + ret nz + res SCREENS_SAFEGUARD, a + ld [PlayerScreens], a + xor a + jr .print + +.CheckEnemy: + ld a, [EnemyScreens] + bit SCREENS_SAFEGUARD, a + ret z + ld hl, EnemySafeguardCount + dec [hl] + ret nz + res SCREENS_SAFEGUARD, a + ld [EnemyScreens], a + ld a, $1 + +.print + ld [hBattleTurn], a + ld hl, BattleText_SafeguardFaded + jp StdBattleTextBox + +HandleScreens: ; 3cb36 + ld a, [hLinkPlayerNumber] + cp 1 + jr z, .Both + call .CheckPlayer + jr .CheckEnemy + +.Both: + call .CheckEnemy + +.CheckPlayer: + call SetPlayerTurn + ld de, .Your + call .Copy + ld hl, PlayerScreens + ld de, PlayerLightScreenCount + jr .TickScreens + +.CheckEnemy: + call SetEnemyTurn + ld de, .Enemy + call .Copy + ld hl, EnemyScreens + ld de, EnemyLightScreenCount + +.TickScreens: + bit SCREENS_LIGHT_SCREEN, [hl] + call nz, .LightScreenTick + bit SCREENS_REFLECT, [hl] + call nz, .ReflectTick + ret + +.Copy: + ld hl, StringBuffer1 + jp CopyName2 +; 3cb75 + +.Your: + db "Your@" +.Enemy: + db "Enemy@" +; 3cb80 + +.LightScreenTick: ; 3cb80 + ld a, [de] + dec a + ld [de], a + ret nz + res SCREENS_LIGHT_SCREEN, [hl] + push hl + push de + ld hl, BattleText_PkmnLightScreenFell + call StdBattleTextBox + pop de + pop hl + ret +; 3cb91 + +.ReflectTick: ; 3cb91 + inc de + ld a, [de] + dec a + ld [de], a + ret nz + res SCREENS_REFLECT, [hl] + ld hl, BattleText_PkmnReflectFaded + jp StdBattleTextBox +; 3cb9e + +HandleWeather: ; 3cb9e + ld a, [Weather] + cp WEATHER_NONE + ret z + + ld hl, WeatherCount + dec [hl] + jr z, .ended + + ld hl, .WeatherMessages + call .PrintWeatherMessage + + ld a, [Weather] + cp WEATHER_SANDSTORM + ret nz + + ld a, [hLinkPlayerNumber] + cp 1 + jr z, .enemy_first + +.player_first + call SetPlayerTurn + call .SandstormDamage + call SetEnemyTurn + jr .SandstormDamage + +.enemy_first + call SetEnemyTurn + call .SandstormDamage + call SetPlayerTurn + +.SandstormDamage: + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + bit SUBSTATUS_UNDERGROUND, a + ret nz + + ld hl, BattleMonType1 + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyMonType1 +.ok + ld a, [hli] + cp ROCK + ret z + cp GROUND + ret z + cp STEEL + ret z + + ld a, [hl] + cp ROCK + ret z + cp GROUND + ret z + cp STEEL + ret z + + call SwitchTurnCore + xor a + ld [wNumHits], a + ld de, ANIM_IN_SANDSTORM + call Call_PlayBattleAnim + call SwitchTurnCore + call GetEighthMaxHP + call SubtractHPFromUser + + ld hl, SandstormHitsText + jp StdBattleTextBox + +.ended + ld hl, .WeatherEndedMessages + call .PrintWeatherMessage + xor a + ld [Weather], a + ret + +.PrintWeatherMessage: + ld a, [Weather] + dec a + ld c, a + ld b, 0 + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + jp StdBattleTextBox +; 3cc2d + +.WeatherMessages: + dw BattleText_RainContinuesToFall + dw BattleText_TheSunlightIsStrong + dw BattleText_TheSandstormRages +.WeatherEndedMessages: + dw BattleText_TheRainStopped + dw BattleText_TheSunlightFaded + dw BattleText_TheSandstormSubsided +; 3cc39 + +SubtractHPFromTarget: ; 3cc39 + call SubtractHP + jp UpdateHPBar +; 3cc3f + +SubtractHPFromUser: ; 3cc3f +; Subtract HP from Pkmn + call SubtractHP + jp UpdateHPBarBattleHuds +; 3cc45 + +SubtractHP: ; 3cc45 + ld hl, BattleMonHP + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyMonHP +.ok + inc hl + ld a, [hl] + ld [Buffer3], a + sub c + ld [hld], a + ld [Buffer5], a + ld a, [hl] + ld [Buffer4], a + sbc b + ld [hl], a + ld [Buffer6], a + ret nc + + ld a, [Buffer3] + ld c, a + ld a, [Buffer4] + ld b, a + xor a + ld [hli], a + ld [hl], a + ld [Buffer5], a + ld [Buffer6], a + ret +; 3cc76 + +GetSixteenthMaxHP: ; 3cc76 + call GetQuarterMaxHP + ; quarter result + srl c + srl c + ; round up + ld a, c + and a + jr nz, .ok + inc c +.ok + ret +; 3cc83 + +GetEighthMaxHP: ; 3cc83 +; output: bc + call GetQuarterMaxHP +; assumes nothing can have 1024 or more hp +; halve result + srl c +; round up + ld a, c + and a + jr nz, .end + inc c +.end + ret +; 3cc8e + +GetQuarterMaxHP: ; 3cc8e +; output: bc + call GetMaxHP + +; quarter result + srl b + rr c + srl b + rr c + +; assumes nothing can have 1024 or more hp +; round up + ld a, c + and a + jr nz, .end + inc c +.end + ret +; 3cc9f + +GetHalfMaxHP: ; 3cc9f +; output: bc + call GetMaxHP + +; halve result + srl b + rr c + +; floor = 1 + ld a, c + or b + jr nz, .end + inc c +.end + ret +; 3ccac + +GetMaxHP: ; 3ccac +; output: bc, Buffer1-2 + + ld hl, BattleMonMaxHP + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyMonMaxHP +.ok + ld a, [hli] + ld [Buffer2], a + ld b, a + + ld a, [hl] + ld [Buffer1], a + ld c, a + ret +; 3ccc2 + +GetHalfHP: ; 3ccc2 +; unreferenced + ld hl, BattleMonHP + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyMonHP +.ok + ld a, [hli] + ld b, a + ld a, [hli] + ld c, a + srl b + rr c + ld a, [hli] + ld [Buffer2], a + ld a, [hl] + ld [Buffer1], a + ret +; 3ccde + +CheckUserHasEnoughHP: ; 3ccde + ld hl, BattleMonHP + 1 + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyMonHP + 1 +.ok + ld a, c + sub [hl] + dec hl + ld a, b + sbc [hl] + ret +; 3ccef + +RestoreHP ; 3ccef + ld hl, EnemyMonMaxHP + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, BattleMonMaxHP +.ok + ld a, [hli] + ld [Buffer2], a + ld a, [hld] + ld [Buffer1], a + dec hl + ld a, [hl] + ld [Buffer3], a + add c + ld [hld], a + ld [Buffer5], a + ld a, [hl] + ld [Buffer4], a + adc b + ld [hli], a + ld [Buffer6], a + + ld a, [Buffer1] + ld c, a + ld a, [hld] + sub c + ld a, [Buffer2] + ld b, a + ld a, [hl] + sbc b + jr c, .asm_3cd2d + ld a, b + ld [hli], a + ld [Buffer6], a + ld a, c + ld [hl], a + ld [Buffer5], a +.asm_3cd2d + + call SwitchTurnCore + call UpdateHPBarBattleHuds + jp SwitchTurnCore +; 3cd36 + +UpdateHPBarBattleHuds: ; 3cd36 + call UpdateHPBar + jp UpdateBattleHuds +; 3cd3c + +UpdateHPBar: ; 3cd3c + hlcoord 10, 9 + ld a, [hBattleTurn] + and a + ld a, 1 + jr z, .ok + hlcoord 2, 2 + xor a +.ok + push bc + ld [wWhichHPBar], a + predef AnimateHPBar + pop bc + ret +; 3cd55 + +HandleEnemyMonFaint: ; 3cd55 + call FaintEnemyPokemon + ld hl, BattleMonHP + ld a, [hli] + or [hl] + call z, FaintYourPokemon + xor a + ld [wWhichMonFaintedFirst], a + call UpdateBattleStateAndExperienceAfterEnemyFaint + call CheckPlayerPartyForFitPkmn + ld a, d + and a + jp z, LostBattle + + ld hl, BattleMonHP + ld a, [hli] + or [hl] + call nz, UpdatePlayerHUD + + ld a, $1 + ld [hBGMapMode], a + ld c, 60 + call DelayFrames + + ld a, [wBattleMode] + dec a + jr nz, .trainer + + ld a, 1 + ld [BattleEnded], a + ret + +.trainer + call CheckEnemyTrainerDefeated + jp z, WinTrainerBattle + + ld hl, BattleMonHP + ld a, [hli] + or [hl] + jr nz, .player_mon_not_fainted + + call AskUseNextPokemon + jr nc, .dont_flee + + ld a, 1 + ld [BattleEnded], a + ret + +.dont_flee + call ForcePlayerMonChoice + call CheckMobileBattleError + jp c, WildFled_EnemyFled_LinkBattleCanceled + + ld a, $1 + ld [wPlayerAction], a + call HandleEnemySwitch + jp z, WildFled_EnemyFled_LinkBattleCanceled + jr DoubleSwitch + +.player_mon_not_fainted + ld a, $1 + ld [wPlayerAction], a + call HandleEnemySwitch + jp z, WildFled_EnemyFled_LinkBattleCanceled + xor a + ld [wPlayerAction], a + ret +; 3cdca + +DoubleSwitch: ; 3cdca + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .player_1 + call ClearSprites + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + call PlayerPartyMonEntrance + ld a, $1 + call EnemyPartyMonEntrance + jr .done + +.player_1 + ld a, [CurPartyMon] + push af + ld a, $1 + call EnemyPartyMonEntrance + call ClearSprites + call LoadTileMapToTempTileMap + pop af + ld [CurPartyMon], a + call PlayerPartyMonEntrance + +.done + xor a + ld [wPlayerAction], a + ret +; 3ce01 + +UpdateBattleStateAndExperienceAfterEnemyFaint: ; 3ce01 + call UpdateBattleMonInParty + ld a, [wBattleMode] + dec a + jr z, .wild + ld a, [CurOTMon] + ld hl, OTPartyMon1HP + call GetPartyLocation + xor a + ld [hli], a + ld [hl], a + +.wild + ld hl, PlayerSubStatus3 + res SUBSTATUS_IN_LOOP, [hl] + xor a + ld hl, EnemyDamageTaken + ld [hli], a + ld [hl], a + call NewEnemyMonStatus + call BreakAttraction + ld a, [wBattleMode] + dec a + jr z, .wild2 + jr .trainer + +.wild2 + call StopDangerSound + ld a, $1 + ld [wDanger], a + +.trainer + ld hl, BattleMonHP + ld a, [hli] + or [hl] + jr nz, .player_mon_did_not_faint + ld a, [wWhichMonFaintedFirst] + and a + jr nz, .player_mon_did_not_faint + call PlayerMonFaintHappinessMod + +.player_mon_did_not_faint + call CheckPlayerPartyForFitPkmn + ld a, d + and a + ret z + ld a, [wBattleMode] + dec a + call z, PlayVictoryMusic + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + ld a, [wBattleResult] + and $c0 + ld [wBattleResult], a + call IsAnyMonHoldingExpShare + jr z, .skip_exp + ld hl, EnemyMonBaseStats + ld b, EnemyMonEnd - EnemyMonBaseStats +.loop + srl [hl] + inc hl + dec b + jr nz, .loop + +.skip_exp + ld hl, EnemyMonBaseStats + ld de, wBackupEnemyMonBaseStats + ld bc, EnemyMonEnd - EnemyMonBaseStats + call CopyBytes + xor a + ld [wGivingExperienceToExpShareHolders], a + call GiveExperiencePoints + call IsAnyMonHoldingExpShare + ret z + + ld a, [wBattleParticipantsNotFainted] + push af + ld a, d + ld [wBattleParticipantsNotFainted], a + ld hl, wBackupEnemyMonBaseStats + ld de, EnemyMonBaseStats + ld bc, EnemyMonEnd - EnemyMonBaseStats + call CopyBytes + ld a, $1 + ld [wGivingExperienceToExpShareHolders], a + call GiveExperiencePoints + pop af + ld [wBattleParticipantsNotFainted], a + ret +; 3ceaa + +IsAnyMonHoldingExpShare: ; 3ceaa + ld a, [PartyCount] + ld b, a + ld hl, PartyMon1 + ld c, 1 + ld d, 0 +.loop + push hl + push bc + ld bc, MON_HP + add hl, bc + ld a, [hli] + or [hl] + pop bc + pop hl + jr z, .next + + push hl + push bc + ld bc, MON_ITEM + add hl, bc + pop bc + ld a, [hl] + pop hl + + cp EXP_SHARE + jr nz, .next + ld a, d + or c + ld d, a + +.next + sla c + push de + ld de, PARTYMON_STRUCT_LENGTH + add hl, de + pop de + dec b + jr nz, .loop + + ld a, d + ld e, 0 + ld b, PARTY_LENGTH +.loop2 + srl a + jr nc, .okay + inc e + +.okay + dec b + jr nz, .loop2 + ld a, e + and a + ret +; 3ceec + +StopDangerSound: ; 3ceec + xor a + ld [Danger], a + ret +; 3cef1 + +FaintYourPokemon: ; 3cef1 + call StopDangerSound + call WaitSFX + ld a, $f0 + ld [CryTracks], a + ld a, [BattleMonSpecies] + call PlayStereoCry + call PlayerMonFaintedAnimation + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + ld hl, BattleText_PkmnFainted + jp StdBattleTextBox +; 3cf14 + +FaintEnemyPokemon: ; 3cf14 + call WaitSFX + ld de, SFX_KINESIS + call PlaySFX + call EnemyMonFaintedAnimation + ld de, SFX_FAINT + call PlaySFX + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + ld hl, BattleText_EnemyPkmnFainted + jp StdBattleTextBox +; 3cf35 + +CheckEnemyTrainerDefeated: ; 3cf35 + ld a, [OTPartyCount] + ld b, a + xor a + ld hl, OTPartyMon1HP + ld de, PARTYMON_STRUCT_LENGTH + +.loop + or [hl] + inc hl + or [hl] + dec hl + add hl, de + dec b + jr nz, .loop + + and a + ret +; 3cf4a + +HandleEnemySwitch: ; 3cf4a + ld hl, EnemyHPPal + ld e, HP_BAR_LENGTH_PX + call UpdateHPPal + call WaitBGMap + farcall EnemySwitch_TrainerHud + ld a, [wLinkMode] + and a + jr z, .not_linked + + call LinkBattleSendReceiveAction + ld a, [wBattleAction] + cp BATTLEACTION_FORFEIT + ret z + + call Call_LoadTempTileMapToTileMap + +.not_linked + ld hl, BattleMonHP + ld a, [hli] + or [hl] + ld a, $0 + jr nz, EnemyPartyMonEntrance + inc a + ret +; 3cf78 + +EnemyPartyMonEntrance: ; 3cf78 + push af + xor a + ld [wEnemySwitchMonIndex], a + call NewEnemyMonStatus + call ResetEnemyStatLevels + call BreakAttraction + pop af + and a + jr nz, .set + call EnemySwitch + jr .done_switch + +.set + call EnemySwitch_SetMode +.done_switch + call ResetBattleParticipants + call SetEnemyTurn + call SpikesDamage + xor a + ld [wEnemyMoveStruct + MOVE_ANIM], a + ld [wPlayerAction], a + inc a + ret +; 3cfa4 + +WinTrainerBattle: ; 3cfa4 +; Player won the battle + call StopDangerSound + ld a, $1 + ld [wDanger], a + ld [BattleEnded], a + ld a, [wLinkMode] + and a + ld a, b + call z, PlayVictoryMusic + callfar Battle_GetTrainerName + ld hl, BattleText_EnemyWasDefeated + call StdBattleTextBox + + call IsMobileBattle + jr z, .mobile + ld a, [wLinkMode] + and a + ret nz + + ld a, [InBattleTowerBattle] + bit 0, a + jr nz, .battle_tower + + call BattleWinSlideInEnemyTrainerFrontpic + ld c, 40 + call DelayFrames + ld a, [BattleType] + cp BATTLETYPE_CANLOSE + jr nz, .skip_heal + predef HealParty +.skip_heal + ld a, [wMonStatusFlags] + bit 0, a + jr nz, .skip_win_loss_text + call PrintWinLossText + +.skip_win_loss_text + jp .GiveMoney + +.mobile + call BattleWinSlideInEnemyTrainerFrontpic + ld c, 40 + call DelayFrames + ld c, $4 ; win + farcall Mobile_PrintOpponentBattleMessage + ret + +.battle_tower + call BattleWinSlideInEnemyTrainerFrontpic + ld c, 40 + call DelayFrames + call EmptyBattleTextBox + ld c, $3 + farcall BattleTowerText + call WaitPressAorB_BlinkCursor + ld hl, wPayDayMoney + ld a, [hli] + or [hl] + inc hl + or [hl] + ret nz + call ClearTileMap + call ClearBGPalettes + ret + +.GiveMoney: + ld a, [wAmuletCoin] + and a + call nz, .DoubleReward + call .CheckMaxedOutMomMoney + push af + ld a, $0 + jr nc, .okay + ld a, [wMomSavingMoney] + and $7 + cp $3 + jr nz, .okay + inc a + +.okay + ld b, a + ld c, $4 +.loop + ld a, b + and a + jr z, .loop2 + call .SendMoneyToMom + dec c + dec b + jr .loop + +.loop2 + ld a, c + and a + jr z, .done + call .AddMoneyToWallet + dec c + jr .loop2 + +.done + call .DoubleReward + call .DoubleReward + pop af + jr nc, .KeepItAll + ld a, [wMomSavingMoney] + and $7 + jr z, .KeepItAll + ld hl, .SentToMomTexts + dec a + ld c, a + ld b, 0 + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + jp StdBattleTextBox + +.KeepItAll: + ld hl, GotMoneyForWinningText + jp StdBattleTextBox +; 3d081 + +.SendMoneyToMom: ; 3d081 + push bc + ld hl, wBattleReward + 2 + ld de, wMomsMoney + 2 + call AddBattleMoneyToAccount + pop bc + ret +; 3d08d + +.AddMoneyToWallet: ; 3d08d + push bc + ld hl, wBattleReward + 2 + ld de, Money + 2 + call AddBattleMoneyToAccount + pop bc + ret +; 3d099 + +.DoubleReward: ; 3d099 + ld hl, wBattleReward + 2 + sla [hl] + dec hl + rl [hl] + dec hl + rl [hl] + ret nc + ld a, $ff + ld [hli], a + ld [hli], a + ld [hl], a + ret +; 3d0ab + +.SentToMomTexts: ; 3d0ab + dw SentSomeToMomText + dw SentHalfToMomText + dw SentAllToMomText +; 3d0b1 + +.CheckMaxedOutMomMoney: ; 3d0b1 + ld hl, wMomsMoney + 2 + ld a, [hld] + cp LOW(MAX_MONEY) + ld a, [hld] + sbc HIGH(MAX_MONEY) ; mid + ld a, [hl] + sbc HIGH(MAX_MONEY >> 8) + ret +; 3d0be + +AddBattleMoneyToAccount: ; 3d0be + ld c, $3 + and a + push de + push hl + push bc + ld b, h + ld c, l + farcall TrainerRankings_AddToBattlePayouts + pop bc + pop hl +.loop + ld a, [de] + adc [hl] + ld [de], a + dec de + dec hl + dec c + jr nz, .loop + pop hl + ld a, [hld] + cp LOW(MAX_MONEY) + ld a, [hld] + sbc HIGH(MAX_MONEY) ; mid + ld a, [hl] + sbc HIGH(MAX_MONEY >> 8) + ret c + ld [hl], HIGH(MAX_MONEY >> 8) + inc hl + ld [hl], HIGH(MAX_MONEY) ; mid + inc hl + ld [hl], LOW(MAX_MONEY) + ret +; 3d0ea + +PlayVictoryMusic: ; 3d0ea + push de + ld de, MUSIC_NONE + call PlayMusic + call DelayFrame + ld de, MUSIC_WILD_VICTORY + ld a, [wBattleMode] + dec a + jr nz, .trainer_victory + push de + call IsAnyMonHoldingExpShare + pop de + jr nz, .play_music + ld hl, wPayDayMoney + ld a, [hli] + or [hl] + jr nz, .play_music + ld a, [wBattleParticipantsNotFainted] + and a + jr z, .lost + jr .play_music + +.trainer_victory + ld de, MUSIC_GYM_VICTORY + call IsJohtoGymLeader + jr c, .play_music + ld de, MUSIC_TRAINER_VICTORY + +.play_music + call PlayMusic + +.lost + pop de + ret +; 3d123 + +; These functions check if the current opponent is a gym leader or one of a +; few other special trainers. + +; Note: KantoGymLeaders is a subset of JohtoGymLeaders. If you wish to +; differentiate between the two, call IsKantoGymLeader first. + +; The Lance and Red entries are unused for music checks; those trainers are +; accounted for elsewhere. + +IsKantoGymLeader: ; 0x3d123 + ld hl, KantoGymLeaders + jr IsGymLeaderCommon + +IsJohtoGymLeader: ; 0x3d128 + ld hl, JohtoGymLeaders +IsGymLeaderCommon: + push de + ld a, [OtherTrainerClass] + ld de, $0001 + call IsInArray + pop de + ret +; 0x3d137 + +JohtoGymLeaders: + db FALKNER + db WHITNEY + db BUGSY + db MORTY + db PRYCE + db JASMINE + db CHUCK + db CLAIR + db WILL + db BRUNO + db KAREN + db KOGA +; fallthrough +; these two entries are unused + db CHAMPION + db RED +; fallthrough +KantoGymLeaders: + db BROCK + db MISTY + db LT_SURGE + db ERIKA + db JANINE + db SABRINA + db BLAINE + db BLUE + db -1 + +HandlePlayerMonFaint: ; 3d14e + call FaintYourPokemon + ld hl, EnemyMonHP + ld a, [hli] + or [hl] + call z, FaintEnemyPokemon + ld a, $1 + ld [wWhichMonFaintedFirst], a + call PlayerMonFaintHappinessMod + call CheckPlayerPartyForFitPkmn + ld a, d + and a + jp z, LostBattle + ld hl, EnemyMonHP + ld a, [hli] + or [hl] + jr nz, .notfainted + call UpdateBattleStateAndExperienceAfterEnemyFaint + ld a, [wBattleMode] + dec a + jr nz, .trainer + ld a, $1 + ld [BattleEnded], a + ret + +.trainer + call CheckEnemyTrainerDefeated + jp z, WinTrainerBattle + +.notfainted + call AskUseNextPokemon + jr nc, .switch + ld a, $1 + ld [BattleEnded], a + ret + +.switch + call ForcePlayerMonChoice + call CheckMobileBattleError + jp c, WildFled_EnemyFled_LinkBattleCanceled + ld a, c + and a + ret nz + ld a, $1 + ld [wPlayerAction], a + call HandleEnemySwitch + jp z, WildFled_EnemyFled_LinkBattleCanceled + jp DoubleSwitch +; 3d1aa + +PlayerMonFaintHappinessMod: ; 3d1aa + ld a, [CurBattleMon] + ld c, a + ld hl, wBattleParticipantsNotFainted + ld b, RESET_FLAG + predef FlagPredef + ld hl, EnemySubStatus3 + res SUBSTATUS_IN_LOOP, [hl] + xor a + ld [Danger], a + ld hl, PlayerDamageTaken + ld [hli], a + ld [hl], a + ld [BattleMonStatus], a + call UpdateBattleMonInParty + ld c, HAPPINESS_FAINTED + ; If TheirLevel > (YourLevel + 30), use a different parameter + ld a, [BattleMonLevel] + add 30 + ld b, a + ld a, [EnemyMonLevel] + cp b + jr c, .got_param + ld c, HAPPINESS_BEATENBYSTRONGFOE + +.got_param + ld a, [CurBattleMon] + ld [CurPartyMon], a + callfar ChangeHappiness + ld a, [wBattleResult] + and %11000000 + add $1 + ld [wBattleResult], a + ld a, [wWhichMonFaintedFirst] + and a + ret z + ret ; ?????????? +; 3d1f8 + +AskUseNextPokemon: ; 3d1f8 + call EmptyBattleTextBox + call LoadTileMapToTempTileMap +; We don't need to be here if we're in a Trainer battle, +; as that decision is made for us. + ld a, [wBattleMode] + and a + dec a + ret nz + + ld hl, BattleText_UseNextMon + call StdBattleTextBox +.loop + lb bc, 1, 7 + call PlaceYesNoBox + ld a, [wMenuCursorY] + jr c, .pressed_b + and a + ret + +.pressed_b + ld a, [wMenuCursorY] + cp $1 ; YES + jr z, .loop + ld hl, PartyMon1Speed + ld de, EnemyMonSpeed + jp TryToRunAwayFromBattle +; 3d227 + +ForcePlayerMonChoice: ; 3d227 + call EmptyBattleTextBox + call LoadStandardMenuDataHeader + call SetUpBattlePartyMenu_NoLoop + call ForcePickPartyMonInBattle + ld a, [wLinkMode] + and a + jr z, .skip_link + ld a, $1 + ld [wPlayerAction], a + call LinkBattleSendReceiveAction + +.skip_link + xor a + ld [wPlayerAction], a + call CheckMobileBattleError + jr c, .enemy_fainted_mobile_error + ld hl, EnemyMonHP + ld a, [hli] + or [hl] + jr nz, .send_out_pokemon + +.enemy_fainted_mobile_error + call ClearSprites + call ClearBGPalettes + call _LoadHPBar + call ExitMenu + call LoadTileMapToTempTileMap + call WaitBGMap + call GetMemSGBLayout + call SetPalettes + xor a + ld c, a + ret + +.send_out_pokemon + call ClearSprites + ld a, [CurBattleMon] + ld [LastPlayerMon], a + ld a, [CurPartyMon] + ld [CurBattleMon], a + call AddBattleParticipant + call InitBattleMon + call ResetPlayerStatLevels + call ClearPalettes + call DelayFrame + call _LoadHPBar + call CloseWindow + call GetMemSGBLayout + call SetPalettes + call SendOutPkmnText + call NewBattleMonStatus + call BreakAttraction + call SendOutPlayerMon + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + call SetPlayerTurn + call SpikesDamage + ld a, $1 + and a + ld c, a + ret +; 3d2b3 + +PlayerPartyMonEntrance: ; 3d2b3 + ld a, [CurBattleMon] + ld [LastPlayerMon], a + ld a, [CurPartyMon] + ld [CurBattleMon], a + call AddBattleParticipant + call InitBattleMon + call ResetPlayerStatLevels + call SendOutPkmnText + call NewBattleMonStatus + call BreakAttraction + call SendOutPlayerMon + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + call SetPlayerTurn + jp SpikesDamage +; 3d2e0 + +CheckMobileBattleError: ; 3d2e0 + ld a, [wLinkMode] + cp LINK_MOBILE + jr nz, .not_mobile ; It's not a mobile battle + + ld a, [wcd2b] + and a + jr z, .not_mobile + +; We have a mobile battle and something else happened + scf + ret + +.not_mobile + xor a + ret +; 3d2f1 + +IsMobileBattle: ; 3d2f1 + ld a, [wLinkMode] + cp LINK_MOBILE + ret +; 3d2f7 + +SetUpBattlePartyMenu_NoLoop: ; 3d2f7 + call ClearBGPalettes +SetUpBattlePartyMenu: ; switch to fullscreen menu? + farcall LoadPartyMenuGFX + farcall InitPartyMenuWithCancel + farcall InitPartyMenuBGPal7 + farcall InitPartyMenuGFX + ret +; 3d313 + +JumpToPartyMenuAndPrintText: ; 3d313 + farcall WritePartyMenuTilemap + farcall PrintPartyMenuText + call WaitBGMap + call SetPalettes + call DelayFrame + ret +; 3d329 + +SelectBattleMon: ; 3d329 + call IsMobileBattle + jr z, .mobile + farcall PartyMenuSelect + ret + +.mobile + farcall Mobile_PartyMenuSelect + ret +; 3d33c + +PickPartyMonInBattle: ; 3d33c +.loop + ld a, PARTYMENUACTION_SWITCH ; Which PKMN? + ld [PartyMenuActionText], a + call JumpToPartyMenuAndPrintText + call SelectBattleMon + ret c + call CheckIfCurPartyMonIsFitToFight + jr z, .loop + xor a + ret +; 3d34f + +SwitchMonAlreadyOut: ; 3d34f + ld hl, CurBattleMon + ld a, [CurPartyMon] + cp [hl] + jr nz, .notout + + ld hl, BattleText_PkmnIsAlreadyOut + call StdBattleTextBox + scf + ret + +.notout + xor a + ret +; 3d362 + +ForcePickPartyMonInBattle: ; 3d362 +; Can't back out. + +.pick + call PickPartyMonInBattle + ret nc + call CheckMobileBattleError + ret c + + ld de, SFX_WRONG + call PlaySFX + call WaitSFX + jr .pick +; 3d375 + +PickSwitchMonInBattle: ; 3d375 +.pick + call PickPartyMonInBattle + ret c + call SwitchMonAlreadyOut + jr c, .pick + xor a + ret +; 3d380 + +ForcePickSwitchMonInBattle: ; 3d380 +; Can't back out. + +.pick + call ForcePickPartyMonInBattle + call CheckMobileBattleError + ret c + call SwitchMonAlreadyOut + jr c, .pick + + xor a + ret +; 3d38e + +LostBattle: ; 3d38e + ld a, 1 + ld [BattleEnded], a + + ld a, [InBattleTowerBattle] + bit 0, a + jr nz, .battle_tower + + ld a, [BattleType] + cp BATTLETYPE_CANLOSE + jr nz, .not_canlose + +; Remove the enemy from the screen. + hlcoord 0, 0 + lb bc, 8, 21 + call ClearBox + call BattleWinSlideInEnemyTrainerFrontpic + + ld c, 40 + call DelayFrames + + ld a, [wMonStatusFlags] + bit 0, a + jr nz, .skip_win_loss_text + call PrintWinLossText +.skip_win_loss_text + ret + +.battle_tower +; Remove the enemy from the screen. + hlcoord 0, 0 + lb bc, 8, 21 + call ClearBox + call BattleWinSlideInEnemyTrainerFrontpic + + ld c, 40 + call DelayFrames + + call EmptyBattleTextBox + ld c, 2 + farcall BattleTowerText + call WaitPressAorB_BlinkCursor + call ClearTileMap + call ClearBGPalettes + ret + +.not_canlose + ld a, [wLinkMode] + and a + jr nz, .LostLinkBattle + +; Greyscale + ld b, SCGB_BATTLE_GRAYSCALE + call GetSGBLayout + call SetPalettes + jr .end + +.LostLinkBattle: + call UpdateEnemyMonInParty + call CheckEnemyTrainerDefeated + jr nz, .not_tied + ld hl, TiedAgainstText + ld a, [wBattleResult] + and $c0 + add 2 + ld [wBattleResult], a + jr .text + +.not_tied + ld hl, LostAgainstText + call IsMobileBattle + jr z, .mobile + +.text + call StdBattleTextBox + +.end + scf + ret + +.mobile +; Remove the enemy from the screen. + hlcoord 0, 0 + lb bc, 8, 21 + call ClearBox + call BattleWinSlideInEnemyTrainerFrontpic + + ld c, 40 + call DelayFrames + + ld c, $3 ; lost + farcall Mobile_PrintOpponentBattleMessage + scf + ret +; 3d432 + +EnemyMonFaintedAnimation: ; 3d432 + hlcoord 12, 5 + decoord 12, 6 + jp MonFaintedAnimation +; 3d43b + +PlayerMonFaintedAnimation: ; 3d43b + hlcoord 1, 10 + decoord 1, 11 + jp MonFaintedAnimation +; 3d444 + +MonFaintedAnimation: ; 3d444 + ld a, [wcfbe] + push af + set 6, a + ld [wcfbe], a + ld b, 7 + +.OuterLoop: + push bc + push de + push hl + ld b, 6 + +.InnerLoop: + push bc + push hl + push de + ld bc, 7 + call CopyBytes + pop de + pop hl + ld bc, -SCREEN_WIDTH + add hl, bc + push hl + ld h, d + ld l, e + add hl, bc + ld d, h + ld e, l + pop hl + pop bc + dec b + jr nz, .InnerLoop + + ld bc, 20 + add hl, bc + ld de, .Spaces + call PlaceString + ld c, 2 + call DelayFrames + pop hl + pop de + pop bc + dec b + jr nz, .OuterLoop + + pop af + ld [wcfbe], a + ret +; 3d488 + +.Spaces: + db " @" +; 3d490 + +SlideBattlePicOut: ; 3d490 + ld [hMapObjectIndexBuffer], a + ld c, a +.loop + push bc + push hl + ld b, $7 +.loop2 + push hl + call .DoFrame + pop hl + ld de, SCREEN_WIDTH + add hl, de + dec b + jr nz, .loop2 + ld c, 2 + call DelayFrames + pop hl + pop bc + dec c + jr nz, .loop + ret +; 3d4ae + +.DoFrame: ; 3d4ae + ld a, [hMapObjectIndexBuffer] + ld c, a + cp $8 + jr nz, .back +.forward + ld a, [hli] + ld [hld], a + dec hl + dec c + jr nz, .forward + ret + +.back + ld a, [hld] + ld [hli], a + inc hl + dec c + jr nz, .back + ret +; 3d4c3 + +ForceEnemySwitch: ; 3d4c3 + call ResetEnemyBattleVars + ld a, [wEnemySwitchMonIndex] + dec a + ld b, a + call LoadEnemyPkmnToSwitchTo + call ClearEnemyMonBox + call NewEnemyMonStatus + call ResetEnemyStatLevels + call Function_SetEnemyPkmnAndSendOutAnimation + call BreakAttraction + call ResetBattleParticipants + ret +; 3d4e1 + +EnemySwitch: ; 3d4e1 + call CheckWhetherToAskSwitch + jr nc, EnemySwitch_SetMode + ; Shift Mode + call ResetEnemyBattleVars + call CheckWhetherSwitchmonIsPredetermined + jr c, .skip + call FindPkmnInOTPartyToSwitchIntoBattle +.skip + ; 'b' contains the PartyNr of the Pkmn the AI will switch to + call LoadEnemyPkmnToSwitchTo + call OfferSwitch + push af + call ClearEnemyMonBox + call Function_BattleTextEnemySentOut + call Function_SetEnemyPkmnAndSendOutAnimation + pop af + ret c + ; If we're here, then we're switching too + xor a + ld [wBattleParticipantsNotFainted], a + ld [wBattleParticipantsIncludingFainted], a + ld [wPlayerAction], a + inc a + ld [wEnemyIsSwitching], a + call LoadTileMapToTempTileMap + jp PlayerSwitch +; 3d517 + +EnemySwitch_SetMode: ; 3d517 + call ResetEnemyBattleVars + call CheckWhetherSwitchmonIsPredetermined + jr c, .skip + call FindPkmnInOTPartyToSwitchIntoBattle +.skip + ; 'b' contains the PartyNr of the Pkmn the AI will switch to + call LoadEnemyPkmnToSwitchTo + ld a, 1 + ld [wEnemyIsSwitching], a + call ClearEnemyMonBox + call Function_BattleTextEnemySentOut + jp Function_SetEnemyPkmnAndSendOutAnimation +; 3d533 + +CheckWhetherSwitchmonIsPredetermined: ; 3d533 +; returns carry if: ??? + ld a, [wLinkMode] + and a + jr z, .not_linked + + ld a, [wBattleAction] + sub BATTLEACTION_SWITCH1 + ld b, a + jr .return_carry + +.not_linked + ld a, [wEnemySwitchMonIndex] + and a + jr z, .check_wBattleHasJustStarted + + dec a + ld b, a + jr .return_carry + +.check_wBattleHasJustStarted + ld a, [wBattleHasJustStarted] + and a + ld b, $0 + jr nz, .return_carry + + and a + ret + +.return_carry + scf + ret +; 3d557 + +ResetEnemyBattleVars: ; 3d557 +; and draw empty TextBox + xor a + ld [LastPlayerCounterMove], a + ld [LastEnemyCounterMove], a + ld [LastEnemyMove], a + ld [CurEnemyMove], a + dec a + ld [wEnemyItemState], a + xor a + ld [wPlayerWrapCount], a + hlcoord 18, 0 + ld a, 8 + call SlideBattlePicOut + call EmptyBattleTextBox + jp LoadStandardMenuDataHeader +; 3d57a + +ResetBattleParticipants: ; 3d57a + xor a + ld [wBattleParticipantsNotFainted], a + ld [wBattleParticipantsIncludingFainted], a +AddBattleParticipant: ; 3d581 + ld a, [CurBattleMon] + ld c, a + ld hl, wBattleParticipantsNotFainted + ld b, SET_FLAG + push bc + predef FlagPredef + pop bc + ld hl, wBattleParticipantsIncludingFainted + predef_jump FlagPredef +; 3d599 + +FindPkmnInOTPartyToSwitchIntoBattle: ; 3d599 + ld b, $ff + ld a, $1 + ld [Buffer1], a + ld [Buffer2], a +.loop + ld hl, Buffer1 + sla [hl] + inc hl + sla [hl] + inc b + ld a, [OTPartyCount] + cp b + jp z, ScoreMonTypeMatchups + ld a, [CurOTMon] + cp b + jr z, .discourage + ld hl, OTPartyMon1HP + push bc + ld a, b + call GetPartyLocation + ld a, [hli] + ld c, a + ld a, [hl] + or c + pop bc + jr z, .discourage + call LookUpTheEffectivenessOfEveryMove + call IsThePlayerPkmnTypesEffectiveAgainstOTPkmn + jr .loop + +.discourage + ld hl, Buffer2 + set 0, [hl] + jr .loop +; 3d5d7 + +LookUpTheEffectivenessOfEveryMove: ; 3d5d7 + push bc + ld hl, OTPartyMon1Moves + ld a, b + call GetPartyLocation + pop bc + ld e, NUM_MOVES + 1 +.loop + dec e + jr z, .done + ld a, [hli] + and a + jr z, .done + push hl + push de + push bc + dec a + ld hl, Moves + ld bc, MOVE_LENGTH + call AddNTimes + ld de, wEnemyMoveStruct + ld a, BANK(Moves) + call FarCopyBytes + call SetEnemyTurn + callfar BattleCheckTypeMatchup + pop bc + pop de + pop hl + ld a, [wd265] ; Get The Effectiveness Modifier + cp 10 + 1 ; 1.0 + 0.1 + jr c, .loop + ld hl, Buffer1 + set 0, [hl] + ret +.done + ret +; 3d618 + +IsThePlayerPkmnTypesEffectiveAgainstOTPkmn: ; 3d618 +; Calculates the effectiveness of the types of the PlayerPkmn +; against the OTPkmn + push bc + ld hl, OTPartyCount + ld a, b + inc a + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + dec a + ld hl, BaseData + BASE_TYPES + ld bc, BASE_DATA_SIZE + call AddNTimes + ld de, EnemyMonType + ld bc, BASE_CATCH_RATE - BASE_TYPES + ld a, BANK(BaseData) + call FarCopyBytes + ld a, [BattleMonType1] + ld [wPlayerMoveStruct + MOVE_TYPE], a + call SetPlayerTurn + callfar BattleCheckTypeMatchup + ld a, [wd265] + cp 10 + 1 ; 1.0 + 0.1 + jr nc, .super_effective + ld a, [BattleMonType2] + ld [wPlayerMoveStruct + MOVE_TYPE], a + callfar BattleCheckTypeMatchup + ld a, [wd265] + cp 10 + 1 ; 1.0 + 0.1 + jr nc, .super_effective + pop bc + ret + +.super_effective + pop bc + ld hl, Buffer1 + bit 0, [hl] + jr nz, .reset + inc hl + set 0, [hl] + ret + +.reset + res 0, [hl] + ret +; 3d672 + +ScoreMonTypeMatchups: ; 3d672 +.loop1 + ld hl, Buffer1 + sla [hl] + inc hl + sla [hl] + jr nc, .loop1 + ld a, [OTPartyCount] + ld b, a + ld c, [hl] +.loop2 + sla c + jr nc, .okay + dec b + jr z, .loop5 + jr .loop2 + +.okay + ld a, [Buffer1] + and a + jr z, .okay2 + ld b, $ff + ld c, a +.loop3 + inc b + sla c + jr nc, .loop3 + jr .quit + +.okay2 + ld b, $ff + ld a, [Buffer2] + ld c, a +.loop4 + inc b + sla c + jr c, .loop4 + jr .quit + +.loop5 + ld a, [OTPartyCount] + ld b, a + call BattleRandom + and $7 + cp b + jr nc, .loop5 + ld b, a + ld a, [CurOTMon] + cp b + jr z, .loop5 + ld hl, OTPartyMon1HP + push bc + ld a, b + call GetPartyLocation + pop bc + ld a, [hli] + ld c, a + ld a, [hl] + or c + jr z, .loop5 + +.quit + ret +; 3d6ca + +LoadEnemyPkmnToSwitchTo: ; 3d6ca + ; 'b' contains the PartyNr of the Pkmn the AI will switch to + ld a, b + ld [CurPartyMon], a + ld hl, OTPartyMon1Level + call GetPartyLocation + ld a, [hl] + ld [CurPartyLevel], a + ld a, [CurPartyMon] + inc a + ld hl, OTPartyCount + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + ld [TempEnemyMonSpecies], a + ld [CurPartySpecies], a + call LoadEnemyMon + + ld a, [CurPartySpecies] + cp UNOWN + jr nz, .skip_unown + ld a, [wFirstUnownSeen] + and a + jr nz, .skip_unown + ld hl, EnemyMonDVs + predef GetUnownLetter + ld a, [UnownLetter] + ld [wFirstUnownSeen], a +.skip_unown + + ld hl, EnemyMonHP + ld a, [hli] + ld [wEnemyHPAtTimeOfPlayerSwitch], a + ld a, [hl] + ld [wEnemyHPAtTimeOfPlayerSwitch + 1], a + ret +; 3d714 + +CheckWhetherToAskSwitch: ; 3d714 + ld a, [wBattleHasJustStarted] + dec a + jp z, .return_nc + ld a, [PartyCount] + dec a + jp z, .return_nc + ld a, [wLinkMode] + and a + jp nz, .return_nc + ld a, [Options] + bit BATTLE_SHIFT, a + jr nz, .return_nc + ld a, [CurPartyMon] + push af + ld a, [CurBattleMon] + ld [CurPartyMon], a + farcall CheckCurPartyMonFainted + pop bc + ld a, b + ld [CurPartyMon], a + jr c, .return_nc + scf + ret + +.return_nc + and a + ret +; 3d74b + +OfferSwitch: ; 3d74b + ld a, [CurPartyMon] + push af + callfar Battle_GetTrainerName + ld hl, BattleText_EnemyIsAboutToUseWillPlayerChangePkmn + call StdBattleTextBox + lb bc, 1, 7 + call PlaceYesNoBox + ld a, [wMenuCursorY] + dec a + jr nz, .said_no + call SetUpBattlePartyMenu_NoLoop + call PickSwitchMonInBattle + jr c, .canceled_switch + ld a, [CurBattleMon] + ld [LastPlayerMon], a + ld a, [CurPartyMon] + ld [CurBattleMon], a + call ClearPalettes + call DelayFrame + call _LoadHPBar + pop af + ld [CurPartyMon], a + xor a + ld [CurEnemyMove], a + ld [CurPlayerMove], a + and a + ret + +.canceled_switch + call ClearPalettes + call DelayFrame + call _LoadHPBar + +.said_no + pop af + ld [CurPartyMon], a + scf + ret +; 3d7a0 + +ClearEnemyMonBox: ; 3d7a0 + xor a + ld [hBGMapMode], a + call ExitMenu + call ClearSprites + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + call WaitBGMap + jp FinishBattleAnim +; 3d7b8 + +Function_BattleTextEnemySentOut: ; 3d7b8 + callfar Battle_GetTrainerName + ld hl, BattleText_EnemySentOut + call StdBattleTextBox + jp WaitBGMap +; 3d7c7 + +Function_SetEnemyPkmnAndSendOutAnimation: ; 3d7c7 + ld a, [TempEnemyMonSpecies] + ld [CurPartySpecies], a + ld [CurSpecies], a + call GetBaseData + ld a, OTPARTYMON + ld [MonType], a + predef CopyPkmnToTempMon + call GetEnemyMonFrontpic + + xor a + ld [wNumHits], a + ld [wBattleAnimParam], a + call SetEnemyTurn + ld de, ANIM_SEND_OUT_MON + call Call_PlayBattleAnim + + call BattleCheckEnemyShininess + jr nc, .not_shiny + ld a, 1 ; shiny anim + ld [wBattleAnimParam], a + ld de, ANIM_SEND_OUT_MON + call Call_PlayBattleAnim +.not_shiny + + ld bc, TempMonSpecies + farcall CheckFaintedFrzSlp + jr c, .skip_cry + farcall CheckBattleScene + jr c, .cry_no_anim + hlcoord 12, 0 + ld d, $0 + ld e, ANIM_MON_SLOW + predef AnimateFrontpic + jr .skip_cry + +.cry_no_anim + ld a, $f + ld [CryTracks], a + ld a, [TempEnemyMonSpecies] + call PlayStereoCry + +.skip_cry + call UpdateEnemyHUD + ld a, $1 + ld [hBGMapMode], a + ret +; 3d834 + +NewEnemyMonStatus: ; 3d834 + xor a + ld [LastPlayerCounterMove], a + ld [LastEnemyCounterMove], a + ld [LastEnemyMove], a + ld hl, EnemySubStatus1 +rept 4 + ld [hli], a +endr + ld [hl], a + ld [EnemyDisableCount], a + ld [EnemyFuryCutterCount], a + ld [EnemyProtectCount], a + ld [wEnemyRageCounter], a + ld [EnemyDisabledMove], a + ld [wEnemyMinimized], a + ld [wPlayerWrapCount], a + ld [wEnemyWrapCount], a + ld [EnemyTurnsTaken], a + ld hl, PlayerSubStatus5 + res SUBSTATUS_CANT_RUN, [hl] + ret +; 3d867 + +ResetEnemyStatLevels: ; 3d867 + ld a, BASE_STAT_LEVEL + ld b, NUM_LEVEL_STATS + ld hl, EnemyStatLevels +.loop + ld [hli], a + dec b + jr nz, .loop + ret +; 3d873 + +CheckPlayerPartyForFitPkmn: ; 3d873 +; Has the player any Pkmn in his Party that can fight? + ld a, [PartyCount] + ld e, a + xor a + ld hl, PartyMon1HP + ld bc, PartyMon2 - (PartyMon1 + 1) +.loop + or [hl] + inc hl + or [hl] + add hl, bc + dec e + jr nz, .loop + ld d, a + ret +; 3d887 + +CheckIfCurPartyMonIsFitToFight: ; 3d887 + ld a, [CurPartyMon] + ld hl, PartyMon1HP + call GetPartyLocation + ld a, [hli] + or [hl] + ret nz + + ld a, [wBattleHasJustStarted] + and a + jr nz, .finish_fail + ld hl, PartySpecies + ld a, [CurPartyMon] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + cp EGG + ld hl, BattleText_AnEGGCantBattle + jr z, .print_textbox + + ld hl, BattleText_TheresNoWillToBattle + +.print_textbox + call StdBattleTextBox + +.finish_fail + xor a + ret +; 3d8b3 + +TryToRunAwayFromBattle: ; 3d8b3 +; Run away from battle, with or without item + ld a, [BattleType] + cp BATTLETYPE_DEBUG + jp z, .can_escape + cp BATTLETYPE_CONTEST + jp z, .can_escape + cp BATTLETYPE_TRAP + jp z, .cant_escape + cp BATTLETYPE_CELEBI + jp z, .cant_escape + cp BATTLETYPE_SHINY + jp z, .cant_escape + cp BATTLETYPE_SUICUNE + jp z, .cant_escape + + ld a, [wLinkMode] + and a + jp nz, .can_escape + + ld a, [wBattleMode] + dec a + jp nz, .cant_run_from_trainer + + ld a, [EnemySubStatus5] + bit SUBSTATUS_CANT_RUN, a + jp nz, .cant_escape + + ld a, [wPlayerWrapCount] + and a + jp nz, .cant_escape + + push hl + push de + ld a, [BattleMonItem] + ld [wd265], a + ld b, a + callfar GetItemHeldEffect + ld a, b + cp HELD_ESCAPE + pop de + pop hl + jr nz, .no_flee_item + + call SetPlayerTurn + call GetItemName + ld hl, BattleText_UserFledUsingAStringBuffer1 + call StdBattleTextBox + jp .can_escape + +.no_flee_item + ld a, [wNumFleeAttempts] + inc a + ld [wNumFleeAttempts], a + ld a, [hli] + ld [hStringCmpString2 + 0], a + ld a, [hl] + ld [hStringCmpString2 + 1], a + ld a, [de] + inc de + ld [hStringCmpString1 + 0], a + ld a, [de] + ld [hStringCmpString1 + 1], a + call Call_LoadTempTileMapToTileMap + ld de, hStringCmpString2 + ld hl, hStringCmpString1 + ld c, $2 + call StringCmp + jr nc, .can_escape + + xor a + ld [hMultiplicand], a + ld a, $20 + ld [hMultiplier], a + call Multiply + ld a, [hProduct + 2] + ld [hDividend + 0], a + ld a, [hProduct + 3] + ld [hDividend + 1], a + ld a, [hStringCmpString1 + 0] + ld b, a + ld a, [hStringCmpString1 + 1] + srl b + rr a + srl b + rr a + and a + jr z, .can_escape + ld [hDivisor], a + ld b, 2 + call Divide + ld a, [hQuotient + 1] + and a + jr nz, .can_escape + ld a, [wNumFleeAttempts] + ld c, a +.loop + dec c + jr z, .cant_escape_2 + ld b, 30 + ld a, [hQuotient + 2] + add b + ld [hQuotient + 2], a + jr c, .can_escape + jr .loop + +.cant_escape_2 + call BattleRandom + ld b, a + ld a, [hQuotient + 2] + cp b + jr nc, .can_escape + ld a, $1 + ld [wPlayerAction], a + ld hl, BattleText_CantEscape2 + jr .print_inescapable_text + +.cant_escape + ld hl, BattleText_CantEscape + jr .print_inescapable_text + +.cant_run_from_trainer + ld hl, BattleText_TheresNoEscapeFromTrainerBattle + +.print_inescapable_text + call StdBattleTextBox + ld a, $1 + ld [wFailedToFlee], a + call LoadTileMapToTempTileMap + and a + ret + +.can_escape + ld a, [wLinkMode] + and a + ld a, DRAW + jr z, .fled + call LoadTileMapToTempTileMap + xor a + ld [wPlayerAction], a + ld a, $f + ld [CurMoveNum], a + xor a + ld [CurPlayerMove], a + call LinkBattleSendReceiveAction + call Call_LoadTempTileMapToTileMap + call CheckMobileBattleError + jr c, .mobile + + ; Got away safely + ld a, [wBattleAction] + cp BATTLEACTION_FORFEIT + ld a, DRAW + jr z, .fled + dec a +.fled + ld b, a + ld a, [wBattleResult] + and $c0 + add b + ld [wBattleResult], a + call StopDangerSound + push de + ld de, SFX_RUN + call WaitPlaySFX + pop de + call WaitSFX + ld hl, BattleText_GotAwaySafely + call StdBattleTextBox + call WaitSFX + call LoadTileMapToTempTileMap + scf + ret + +.mobile + call StopDangerSound + ld hl, wcd2a + bit 4, [hl] + jr nz, .skip_link_error + ld hl, BattleText_LinkErrorBattleCanceled + call StdBattleTextBox + +.skip_link_error + call WaitSFX + call LoadTileMapToTempTileMap + scf + ret +; 3da0d + +InitBattleMon: ; 3da0d + ld a, MON_SPECIES + call GetPartyParamLocation + ld de, BattleMonSpecies + ld bc, MON_ID + call CopyBytes + ld bc, MON_DVS - MON_ID + add hl, bc + ld de, BattleMonDVs + ld bc, MON_PKRUS - MON_DVS + call CopyBytes + inc hl + inc hl + inc hl + ld de, BattleMonLevel + ld bc, PARTYMON_STRUCT_LENGTH - MON_LEVEL + call CopyBytes + ld a, [BattleMonSpecies] + ld [TempBattleMonSpecies], a + ld [CurPartySpecies], a + ld [CurSpecies], a + call GetBaseData + ld a, [BaseType1] + ld [BattleMonType1], a + ld a, [BaseType2] + ld [BattleMonType2], a + ld hl, PartyMonNicknames + ld a, [CurBattleMon] + call SkipNames + ld de, BattleMonNick + ld bc, PKMN_NAME_LENGTH + call CopyBytes + ld hl, BattleMonAttack + ld de, PlayerStats + ld bc, PARTYMON_STRUCT_LENGTH - MON_ATK + call CopyBytes + call ApplyStatusEffectOnPlayerStats + call BadgeStatBoosts + ret +; 3da74 + +BattleCheckPlayerShininess: ; 3da74 + call GetPartyMonDVs + jr BattleCheckShininess + +BattleCheckEnemyShininess: ; 3da79 + call GetEnemyMonDVs + +BattleCheckShininess: ; 3da7c + ld b, h + ld c, l + callfar CheckShininess + ret +; 3da85 + +GetPartyMonDVs: ; 3da85 + ld hl, BattleMonDVs + ld a, [PlayerSubStatus5] + bit SUBSTATUS_TRANSFORMED, a + ret z + ld hl, PartyMon1DVs + ld a, [CurBattleMon] + jp GetPartyLocation +; 3da97 + +GetEnemyMonDVs: ; 3da97 + ld hl, EnemyMonDVs + ld a, [EnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + ret z + ld hl, wEnemyBackupDVs + ld a, [wBattleMode] + dec a + ret z + ld hl, OTPartyMon1DVs + ld a, [CurOTMon] + jp GetPartyLocation +; 3dab1 + +ResetPlayerStatLevels: ; 3dab1 + ld a, BASE_STAT_LEVEL + ld b, NUM_LEVEL_STATS + ld hl, PlayerStatLevels +.loop + ld [hli], a + dec b + jr nz, .loop + ret +; 3dabd + +InitEnemyMon: ; 3dabd + ld a, [CurPartyMon] + ld hl, OTPartyMon1Species + call GetPartyLocation + ld de, EnemyMonSpecies + ld bc, MON_ID + call CopyBytes + ld bc, MON_DVS - MON_ID + add hl, bc + ld de, EnemyMonDVs + ld bc, MON_PKRUS - MON_DVS + call CopyBytes + inc hl + inc hl + inc hl + ld de, EnemyMonLevel + ld bc, PARTYMON_STRUCT_LENGTH - MON_LEVEL + call CopyBytes + ld a, [EnemyMonSpecies] + ld [CurSpecies], a + call GetBaseData + ld hl, OTPartyMonNicknames + ld a, [CurPartyMon] + call SkipNames + ld de, EnemyMonNick + ld bc, PKMN_NAME_LENGTH + call CopyBytes + ld hl, EnemyMonAttack + ld de, EnemyStats + ld bc, PARTYMON_STRUCT_LENGTH - MON_ATK + call CopyBytes + call ApplyStatusEffectOnEnemyStats + ld hl, BaseType1 + ld de, EnemyMonType1 + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + ld hl, BaseStats + ld de, EnemyMonBaseStats + ld b, 5 +.loop + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .loop + ld a, [CurPartyMon] + ld [CurOTMon], a + ret +; 3db32 + +SwitchPlayerMon: ; 3db32 + call ClearSprites + ld a, [CurBattleMon] + ld [LastPlayerMon], a + ld a, [CurPartyMon] + ld [CurBattleMon], a + call AddBattleParticipant + call InitBattleMon + call ResetPlayerStatLevels + call NewBattleMonStatus + call BreakAttraction + call SendOutPlayerMon + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + ld hl, EnemyMonHP + ld a, [hli] + or [hl] + ret +; 3db5f + +SendOutPlayerMon: ; 3db5f + ld hl, BattleMonDVs + predef GetUnownLetter + hlcoord 1, 5 + ld b, 7 + ld c, 8 + call ClearBox + call WaitBGMap + xor a + ld [hBGMapMode], a + call GetBattleMonBackpic + xor a + ld [hGraphicStartTile], a + ld [wBattleMenuCursorBuffer], a + ld [CurMoveNum], a + ld [TypeModifier], a + ld [wPlayerMoveStruct + MOVE_ANIM], a + ld [LastPlayerCounterMove], a + ld [LastEnemyCounterMove], a + ld [LastPlayerMove], a + call CheckAmuletCoin + call FinishBattleAnim + xor a + ld [wEnemyWrapCount], a + call SetPlayerTurn + xor a + ld [wNumHits], a + ld [wBattleAnimParam], a + ld de, ANIM_SEND_OUT_MON + call Call_PlayBattleAnim + call BattleCheckPlayerShininess + jr nc, .not_shiny + ld a, 1 + ld [wBattleAnimParam], a + ld de, ANIM_SEND_OUT_MON + call Call_PlayBattleAnim + +.not_shiny + ld a, MON_SPECIES + call GetPartyParamLocation + ld b, h + ld c, l + farcall CheckFaintedFrzSlp + jr c, .statused + ld a, $f0 + ld [CryTracks], a + ld a, [CurPartySpecies] + call PlayStereoCry + +.statused + call UpdatePlayerHUD + ld a, $1 + ld [hBGMapMode], a + ret +; 3dbde + +NewBattleMonStatus: ; 3dbde + xor a + ld [LastPlayerCounterMove], a + ld [LastEnemyCounterMove], a + ld [LastPlayerMove], a + ld hl, PlayerSubStatus1 +rept 4 + ld [hli], a +endr + ld [hl], a + ld hl, PlayerUsedMoves + ld [hli], a + ld [hli], a + ld [hli], a + ld [hl], a + ld [PlayerDisableCount], a + ld [PlayerFuryCutterCount], a + ld [PlayerProtectCount], a + ld [wPlayerRageCounter], a + ld [DisabledMove], a + ld [wPlayerMinimized], a + ld [wEnemyWrapCount], a + ld [wPlayerWrapCount], a + ld [PlayerTurnsTaken], a + ld hl, EnemySubStatus5 + res SUBSTATUS_CANT_RUN, [hl] + ret +; 3dc18 + +BreakAttraction: ; 3dc18 + ld hl, PlayerSubStatus1 + res SUBSTATUS_IN_LOVE, [hl] + ld hl, EnemySubStatus1 + res SUBSTATUS_IN_LOVE, [hl] + ret +; 3dc23 + +SpikesDamage: ; 3dc23 + ld hl, PlayerScreens + ld de, BattleMonType + ld bc, UpdatePlayerHUD + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyScreens + ld de, EnemyMonType + ld bc, UpdateEnemyHUD +.ok + + bit SCREENS_SPIKES, [hl] + ret z + + ; Flying-types aren't affected by Spikes. + ld a, [de] + cp FLYING + ret z + inc de + ld a, [de] + cp FLYING + ret z + + push bc + + ld hl, BattleText_UserHurtBySpikes ; "hurt by SPIKES!" + call StdBattleTextBox + + call GetEighthMaxHP + call SubtractHPFromTarget + + pop hl + call .hl + + jp WaitBGMap + +.hl + jp hl +; 3dc5b + +PursuitSwitch: ; 3dc5b + ld a, BATTLE_VARS_MOVE + call GetBattleVar + ld b, a + call GetMoveEffect + ld a, b + cp EFFECT_PURSUIT + jr nz, .done + + ld a, [CurBattleMon] + push af + + ld hl, DoPlayerTurn + ld a, [hBattleTurn] + and a + jr z, .do_turn + ld hl, DoEnemyTurn + ld a, [LastPlayerMon] + ld [CurBattleMon], a +.do_turn + ld a, BANK(DoPlayerTurn) + rst FarCall + + ld a, BATTLE_VARS_MOVE + call GetBattleVarAddr + ld a, $ff + ld [hl], a + + pop af + ld [CurBattleMon], a + + ld a, [hBattleTurn] + and a + jr z, .check_enemy_fainted + + ld a, [LastPlayerMon] + call UpdateBattleMon + ld hl, BattleMonHP + ld a, [hli] + or [hl] + jr nz, .done + + ld a, $f0 + ld [CryTracks], a + ld a, [BattleMonSpecies] + call PlayStereoCry + ld a, [LastPlayerMon] + ld c, a + ld hl, wBattleParticipantsNotFainted + ld b, RESET_FLAG + predef FlagPredef + call PlayerMonFaintedAnimation + ld hl, BattleText_PkmnFainted + jr .done_fainted + +.check_enemy_fainted + ld hl, EnemyMonHP + ld a, [hli] + or [hl] + jr nz, .done + + ld de, SFX_KINESIS + call PlaySFX + call WaitSFX + ld de, SFX_FAINT + call PlaySFX + call WaitSFX + call EnemyMonFaintedAnimation + ld hl, BattleText_EnemyPkmnFainted + +.done_fainted + call StdBattleTextBox + scf + ret + +.done + and a + ret +; 3dce6 + +RecallPlayerMon: ; 3dce6 + ld a, [hBattleTurn] + push af + xor a + ld [hBattleTurn], a + ld [wNumHits], a + ld de, ANIM_RETURN_MON + call Call_PlayBattleAnim + pop af + ld [hBattleTurn], a + ret +; 3dcf9 + +HandleHealingItems: ; 3dcf9 + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .player_1 + call SetPlayerTurn + call HandleHPHealingItem + call UseHeldStatusHealingItem + call UseConfusionHealingItem + call SetEnemyTurn + call HandleHPHealingItem + call UseHeldStatusHealingItem + jp UseConfusionHealingItem + +.player_1 + call SetEnemyTurn + call HandleHPHealingItem + call UseHeldStatusHealingItem + call UseConfusionHealingItem + call SetPlayerTurn + call HandleHPHealingItem + call UseHeldStatusHealingItem + jp UseConfusionHealingItem +; 3dd2f + +HandleHPHealingItem: ; 3dd2f + callfar GetOpponentItem + ld a, b + cp HELD_BERRY + ret nz + ld de, EnemyMonHP + 1 + ld hl, EnemyMonMaxHP + ld a, [hBattleTurn] + and a + jr z, .go + ld de, BattleMonHP + 1 + ld hl, BattleMonMaxHP + +.go +; If, and only if, Pokemon's HP is less than half max, use the item. +; Store current HP in Buffer 3/4 + push bc + ld a, [de] + ld [Buffer3], a + add a + ld c, a + dec de + ld a, [de] + inc de + ld [Buffer4], a + adc a + ld b, a + ld a, b + cp [hl] + ld a, c + pop bc + jr z, .equal + jr c, .less + ret + +.equal + inc hl + cp [hl] + dec hl + ret nc + +.less + call ItemRecoveryAnim + ; store max HP in Buffer1/2 + ld a, [hli] + ld [Buffer2], a + ld a, [hl] + ld [Buffer1], a + ld a, [de] + add c + ld [Buffer5], a + ld c, a + dec de + ld a, [de] + adc $0 + ld [Buffer6], a + ld b, a + ld a, [hld] + cp c + ld a, [hl] + sbc b + jr nc, .okay + ld a, [hli] + ld [Buffer6], a + ld a, [hl] + ld [Buffer5], a + +.okay + ld a, [Buffer6] + ld [de], a + inc de + ld a, [Buffer5] + ld [de], a + ld a, [hBattleTurn] + ld [wWhichHPBar], a + and a + hlcoord 2, 2 + jr z, .got_hp_bar_coords + hlcoord 10, 9 + +.got_hp_bar_coords + ld [wWhichHPBar], a + predef AnimateHPBar +UseOpponentItem: + call RefreshBattleHuds + callfar GetOpponentItem + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetItemName + callfar ConsumeHeldItem + ld hl, RecoveredUsingText + jp StdBattleTextBox +; 3ddc8 + +ItemRecoveryAnim: ; 3ddc8 + push hl + push de + push bc + call EmptyBattleTextBox + ld a, RECOVER + ld [FXAnimID], a + call SwitchTurnCore + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + predef PlayBattleAnim + call SwitchTurnCore + pop bc + pop de + pop hl + ret +; 3dde9 + +UseHeldStatusHealingItem: ; 3dde9 + callfar GetOpponentItem + ld hl, .Statuses +.loop + ld a, [hli] + cp $ff + ret z + inc hl + cp b + jr nz, .loop + dec hl + ld b, [hl] + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and b + ret z + xor a + ld [hl], a + push bc + call UpdateOpponentInParty + pop bc + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + and [hl] + res SUBSTATUS_TOXIC, [hl] + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVarAddr + and [hl] + res SUBSTATUS_NIGHTMARE, [hl] + ld a, b + cp ALL_STATUS + jr nz, .skip_confuse + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVarAddr + res SUBSTATUS_CONFUSED, [hl] + +.skip_confuse + ld hl, CalcEnemyStats + ld a, [hBattleTurn] + and a + jr z, .got_pointer + ld hl, CalcPlayerStats + +.got_pointer + call SwitchTurnCore + ld a, BANK(CalcEnemyStats) + rst FarCall + call SwitchTurnCore + call ItemRecoveryAnim + call UseOpponentItem + ld a, $1 + and a + ret +; 3de44 + +.Statuses: ; 3de44 + db HELD_HEAL_POISON, 1 << PSN + db HELD_HEAL_FREEZE, 1 << FRZ + db HELD_HEAL_BURN, 1 << BRN + db HELD_HEAL_SLEEP, SLP + db HELD_HEAL_PARALYZE, 1 << PAR + db HELD_HEAL_STATUS, ALL_STATUS + db $ff +; 3de51 + +UseConfusionHealingItem: ; 3de51 + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + bit SUBSTATUS_CONFUSED, a + ret z + callfar GetOpponentItem + ld a, b + cp HELD_HEAL_CONFUSION + jr z, .heal_status + cp HELD_HEAL_STATUS + ret nz + +.heal_status + ld a, [hl] + ld [wd265], a + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVarAddr + res SUBSTATUS_CONFUSED, [hl] + call GetItemName + call ItemRecoveryAnim + ld hl, BattleText_ItemHealedConfusion + call StdBattleTextBox + ld a, [hBattleTurn] + and a + jr nz, .do_partymon + call GetOTPartymonItem + xor a + ld [bc], a + ld a, [wBattleMode] + dec a + ret z + ld [hl], $0 + ret + +.do_partymon + call GetPartymonItem + xor a + ld [bc], a + ld [hl], a + ret +; 3de97 + +HandleStatBoostingHeldItems: ; 3de97 +; The effects handled here are not used in-game. + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .player_1 + call .DoPlayer + jp .DoEnemy + +.player_1 + call .DoEnemy + jp .DoPlayer +; 3dea9 + +.DoPlayer: ; 3dea9 + call GetPartymonItem + ld a, $0 + jp .HandleItem +; 3deb1 + +.DoEnemy: ; 3deb1 + call GetOTPartymonItem + ld a, $1 +.HandleItem: ; 3deb6 + ld [hBattleTurn], a + ld d, h + ld e, l + push de + push bc + ld a, [bc] + ld b, a + callfar GetItemHeldEffect + ld hl, .StatUpItems +.loop + ld a, [hli] + cp $ff + jr z, .finish + inc hl + inc hl + cp b + jr nz, .loop + pop bc + ld a, [bc] + ld [wd265], a + push bc + dec hl + dec hl + ld a, [hli] + ld h, [hl] + ld l, a + ld a, BANK(BattleCommand_AttackUp) + rst FarCall + pop bc + pop de + ld a, [FailedMessage] + and a + ret nz + xor a + ld [bc], a + ld [de], a + call GetItemName + ld hl, BattleText_UsersStringBuffer1Activated + call StdBattleTextBox + callfar BattleCommand_StatUpMessage + ret + +.finish + pop bc + pop de + ret +; 3defc + +.StatUpItems: + dbw HELD_ATTACK_UP, BattleCommand_AttackUp + dbw HELD_DEFENSE_UP, BattleCommand_DefenseUp + dbw HELD_SPEED_UP, BattleCommand_SpeedUp + dbw HELD_SP_ATTACK_UP, BattleCommand_SpecialAttackUp + dbw HELD_SP_DEFENSE_UP, BattleCommand_SpecialDefenseUp + dbw HELD_ACCURACY_UP, BattleCommand_AccuracyUp + dbw HELD_EVASION_UP, BattleCommand_EvasionUp + db $ff +; 3df12 + +GetPartymonItem: ; 3df12 + ld hl, PartyMon1Item + ld a, [CurBattleMon] + call GetPartyLocation + ld bc, BattleMonItem + ret +; 3df1f + +GetOTPartymonItem: ; 3df1f + ld hl, OTPartyMon1Item + ld a, [CurOTMon] + call GetPartyLocation + ld bc, EnemyMonItem + ret +; 3df2c + +UpdateBattleHUDs: ; 3df2c + push hl + push de + push bc + call DrawPlayerHUD + ld hl, PlayerHPPal + call SetHPPal + call CheckDanger + call DrawEnemyHUD + ld hl, EnemyHPPal + call SetHPPal + pop bc + pop de + pop hl + ret +; 3df48 + +UpdatePlayerHUD:: ; 3df48 + push hl + push de + push bc + call DrawPlayerHUD + call UpdatePlayerHPPal + call CheckDanger + pop bc + pop de + pop hl + ret +; 3df58 + +DrawPlayerHUD: ; 3df58 + xor a + ld [hBGMapMode], a + + ; Clear the area + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + + farcall DrawPlayerHUDBorder + + hlcoord 18, 9 + ld [hl], $73 ; vertical bar + call PrintPlayerHUD + + ; HP bar + hlcoord 10, 9 + ld b, 1 + xor a ; PARTYMON + ld [MonType], a + predef DrawPlayerHP + + ; Exp bar + push de + ld a, [CurBattleMon] + ld hl, PartyMon1Exp + 2 + call GetPartyLocation + ld d, h + ld e, l + + hlcoord 10, 11 + ld a, [TempMonLevel] + ld b, a + call FillInExpBar + pop de + ret +; 3df98 + +UpdatePlayerHPPal: ; 3df98 + ld hl, PlayerHPPal + jp UpdateHPPal +; 3df9e + +CheckDanger: ; 3df9e + ld hl, BattleMonHP + ld a, [hli] + or [hl] + jr z, .no_danger + ld a, [wDanger] + and a + jr nz, .done + ld a, [PlayerHPPal] + cp HP_RED + jr z, .danger + +.no_danger + ld hl, Danger + res DANGER_ON_F, [hl] + jr .done + +.danger + ld hl, Danger + set DANGER_ON_F, [hl] + +.done + ret +; 3dfbf + +PrintPlayerHUD: ; 3dfbf + ld de, BattleMonNick + hlcoord 10, 7 + call ret_3e138 + call PlaceString + + push bc + + ld a, [CurBattleMon] + ld hl, PartyMon1DVs + call GetPartyLocation + ld de, TempMonDVs + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + ld hl, BattleMonLevel + ld de, TempMonLevel + ld bc, $0011 + call CopyBytes + ld a, [CurBattleMon] + ld hl, PartyMon1Species + call GetPartyLocation + ld a, [hl] + ld [CurPartySpecies], a + ld [CurSpecies], a + call GetBaseData + + pop hl + dec hl + + ld a, TEMPMON + ld [MonType], a + callfar GetGender + ld a, " " + jr c, .got_gender_char + ld a, "♂" + jr nz, .got_gender_char + ld a, "♀" + +.got_gender_char + hlcoord 17, 8 + ld [hl], a + hlcoord 14, 8 + push af ; back up gender + push hl + ld de, BattleMonStatus + predef PlaceNonFaintStatus + pop hl + pop bc + ret nz + ld a, b + cp " " + jr nz, .copy_level ; male or female + dec hl ; genderless + +.copy_level + ld a, [BattleMonLevel] + ld [TempMonLevel], a + jp PrintLevel +; 3e036 + +UpdateEnemyHUD:: ; 3e036 + push hl + push de + push bc + call DrawEnemyHUD + call UpdateEnemyHPPal + pop bc + pop de + pop hl + ret +; 3e043 + +DrawEnemyHUD: ; 3e043 + xor a + ld [hBGMapMode], a + + hlcoord 1, 0 + lb bc, 4, 11 + call ClearBox + + farcall DrawEnemyHUDBorder + + ld a, [TempEnemyMonSpecies] + ld [CurSpecies], a + ld [CurPartySpecies], a + call GetBaseData + ld de, EnemyMonNick + hlcoord 1, 0 + call ret_3e138 + call PlaceString + ld h, b + ld l, c + dec hl + + ld hl, EnemyMonDVs + ld de, TempMonDVs + ld a, [EnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr z, .ok + ld hl, wEnemyBackupDVs +.ok + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + + ld a, TEMPMON + ld [MonType], a + callfar GetGender + ld a, " " + jr c, .got_gender + ld a, "♂" + jr nz, .got_gender + ld a, "♀" + +.got_gender + hlcoord 9, 1 + ld [hl], a + + hlcoord 6, 1 + push af + push hl + ld de, EnemyMonStatus + predef PlaceNonFaintStatus + pop hl + pop bc + jr nz, .skip_level + ld a, b + cp " " + jr nz, .print_level + dec hl +.print_level + ld a, [EnemyMonLevel] + ld [TempMonLevel], a + call PrintLevel +.skip_level + + ld hl, EnemyMonHP + ld a, [hli] + ld [hMultiplicand + 1], a + ld a, [hld] + ld [hMultiplicand + 2], a + or [hl] + jr nz, .not_fainted + + ld c, a + ld e, a + ld d, HP_BAR_LENGTH + jp .draw_bar + +.not_fainted + xor a + ld [hMultiplicand], a + ld a, HP_BAR_LENGTH_PX + ld [hMultiplier], a + call Multiply + ld hl, EnemyMonMaxHP + ld a, [hli] + ld b, a + ld a, [hl] + ld [hMultiplier], a + ld a, b + and a + jr z, .less_than_256_max + ld a, [hMultiplier] + srl b + rr a + srl b + rr a + ld [hDivisor], a + ld a, [hProduct + 2] + ld b, a + srl b + ld a, [hProduct + 3] + rr a + srl b + rr a + ld [hProduct + 3], a + ld a, b + ld [hProduct + 2], a + +.less_than_256_max + ld a, [hProduct + 2] + ld [hDividend + 0], a + ld a, [hProduct + 3] + ld [hDividend + 1], a + ld a, 2 + ld b, a + call Divide + ld a, [hQuotient + 2] + ld e, a + ld a, HP_BAR_LENGTH + ld d, a + ld c, a + +.draw_bar + xor a + ld [wWhichHPBar], a + hlcoord 2, 2 + ld b, 0 + call DrawBattleHPBar + ret +; 3e127 + +UpdateEnemyHPPal: ; 3e127 + ld hl, EnemyHPPal + call UpdateHPPal + ret +; 3e12e + +UpdateHPPal: ; 3e12e + ld b, [hl] + call SetHPPal + ld a, [hl] + cp b + ret z + jp FinishBattleAnim +; 3e138 + +ret_3e138: ; 3e138 + ret +; 3e139 + +BattleMenu: ; 3e139 + xor a + ld [hBGMapMode], a + call LoadTempTileMapToTileMap + + ld a, [BattleType] + cp BATTLETYPE_DEBUG + jr z, .ok + cp BATTLETYPE_TUTORIAL + jr z, .ok + call EmptyBattleTextBox + call UpdateBattleHuds + call EmptyBattleTextBox + call LoadTileMapToTempTileMap +.ok + +.loop + ld a, [BattleType] + cp BATTLETYPE_CONTEST + jr nz, .not_contest + farcall ContestBattleMenu + jr .next +.not_contest + + ; Auto input: choose "ITEM" + ld a, [InputType] + or a + jr z, .skip_dude_pack_select + farcall _DudeAutoInput_DownA +.skip_dude_pack_select + call LoadBattleMenu2 + ret c + +.next + ld a, $1 + ld [hBGMapMode], a + ld a, [wBattleMenuCursorBuffer] + cp $1 + jp z, BattleMenu_Fight + cp $3 + jp z, BattleMenu_Pack + cp $2 + jp z, BattleMenu_PKMN + cp $4 + jp z, BattleMenu_Run + jr .loop +; 3e192 + +BattleMenu_Fight: ; 3e192 + xor a + ld [wNumFleeAttempts], a + call Call_LoadTempTileMapToTileMap + and a + ret +; 3e19b + +LoadBattleMenu2: ; 3e19b + call IsMobileBattle + jr z, .mobile + + farcall LoadBattleMenu + and a + ret + +.mobile + farcall Function100b12 + ld a, [wcd2b] + and a + ret z + + ld hl, wcd2a + bit 4, [hl] + jr nz, .error + ld hl, BattleText_LinkErrorBattleCanceled + call StdBattleTextBox + ld c, 60 + call DelayFrames +.error + scf + ret +; 3e1c7 + +BattleMenu_Pack: ; 3e1c7 + ld a, [wLinkMode] + and a + jp nz, .ItemsCantBeUsed + + ld a, [InBattleTowerBattle] + and a + jp nz, .ItemsCantBeUsed + + call LoadStandardMenuDataHeader + + ld a, [BattleType] + cp BATTLETYPE_TUTORIAL + jr z, .tutorial + cp BATTLETYPE_CONTEST + jr z, .contest + + farcall BattlePack + ld a, [wPlayerAction] + and a + jr z, .didnt_use_item + jr .got_item + +.tutorial + farcall TutorialPack + ld a, POKE_BALL + ld [CurItem], a + call DoItemEffect + jr .got_item + +.contest + ld a, PARK_BALL + ld [CurItem], a + call DoItemEffect + +.got_item + call .UseItem + ret + +.didnt_use_item + call ClearPalettes + call DelayFrame + call _LoadBattleFontsHPBar + call GetBattleMonBackpic + call GetEnemyMonFrontpic + call ExitMenu + call WaitBGMap + call FinishBattleAnim + call LoadTileMapToTempTileMap + jp BattleMenu +; 3e22b + +.ItemsCantBeUsed: ; 3e22b + ld hl, BattleText_ItemsCantBeUsedHere + call StdBattleTextBox + jp BattleMenu +; 3e234 + +.UseItem: ; 3e234 + ld a, [wWildMon] + and a + jr nz, .run + callfar CheckItemPocket + ld a, [wItemAttributeParamBuffer] + cp BALL + jr z, .ball + call ClearBGPalettes + +.ball + xor a + ld [hBGMapMode], a + call _LoadBattleFontsHPBar + call ClearSprites + ld a, [BattleType] + cp BATTLETYPE_TUTORIAL + jr z, .tutorial2 + call GetBattleMonBackpic + +.tutorial2 + call GetEnemyMonFrontpic + ld a, $1 + ld [wMenuCursorY], a + call ExitMenu + call UpdateBattleHUDs + call WaitBGMap + call LoadTileMapToTempTileMap + call ClearWindowData + call FinishBattleAnim + and a + ret + +.run + xor a + ld [wWildMon], a + ld a, [wBattleResult] + and $c0 + ld [wBattleResult], a + call ClearWindowData + call SetPalettes + scf + ret +; 3e28d + +BattleMenu_PKMN: ; 3e28d + call LoadStandardMenuDataHeader +BattleMenuPKMN_ReturnFromStats: + call ExitMenu + call LoadStandardMenuDataHeader + call ClearBGPalettes +BattleMenuPKMN_Loop: + call SetUpBattlePartyMenu + xor a + ld [PartyMenuActionText], a + call JumpToPartyMenuAndPrintText + call SelectBattleMon + jr c, .Cancel +.loop + farcall FreezeMonIcons + call .GetMenu + jr c, .PressedB + call PlaceHollowCursor + ld a, [wMenuCursorY] + cp $1 ; SWITCH + jp z, TryPlayerSwitch + cp $2 ; STATS + jr z, .Stats + cp $3 ; CANCEL + jr z, .Cancel + jr .loop + +.PressedB: + call CheckMobileBattleError + jr c, .Cancel + jr BattleMenuPKMN_Loop + +.Stats: + call Battle_StatsScreen + call CheckMobileBattleError + jr c, .Cancel + jp BattleMenuPKMN_ReturnFromStats + +.Cancel: + call ClearSprites + call ClearPalettes + call DelayFrame + call _LoadHPBar + call CloseWindow + call LoadTileMapToTempTileMap + call GetMemSGBLayout + call SetPalettes + jp BattleMenu +; 3e2f5 + +.GetMenu: ; 3e2f5 + call IsMobileBattle + jr z, .mobile + farcall BattleMonMenu + ret + +.mobile + farcall MobileBattleMonMenu + ret +; 3e308 + +Battle_StatsScreen: ; 3e308 + call DisableLCD + + ld hl, VTiles2 tile $31 + ld de, VTiles0 + ld bc, $11 tiles + call CopyBytes + + ld hl, VTiles2 + ld de, VTiles0 tile $11 + ld bc, $31 tiles + call CopyBytes + + call EnableLCD + + call ClearSprites + call LowVolume + xor a ; PARTYMON + ld [MonType], a + farcall BattleStatsScreenInit + call MaxVolume + + call DisableLCD + + ld hl, VTiles0 + ld de, VTiles2 tile $31 + ld bc, $11 tiles + call CopyBytes + + ld hl, VTiles0 tile $11 + ld de, VTiles2 + ld bc, $31 tiles + call CopyBytes + + call EnableLCD + ret +; 3e358 + +TryPlayerSwitch: ; 3e358 + ld a, [CurBattleMon] + ld d, a + ld a, [CurPartyMon] + cp d + jr nz, .check_trapped + ld hl, BattleText_PkmnIsAlreadyOut + call StdBattleTextBox + jp BattleMenuPKMN_Loop + +.check_trapped + ld a, [wPlayerWrapCount] + and a + jr nz, .trapped + ld a, [EnemySubStatus5] + bit SUBSTATUS_CANT_RUN, a + jr z, .try_switch + +.trapped + ld hl, BattleText_PkmnCantBeRecalled + call StdBattleTextBox + jp BattleMenuPKMN_Loop + +.try_switch + call CheckIfCurPartyMonIsFitToFight + jp z, BattleMenuPKMN_Loop + ld a, [CurBattleMon] + ld [LastPlayerMon], a + ld a, $2 + ld [wPlayerAction], a + call ClearPalettes + call DelayFrame + call ClearSprites + call _LoadHPBar + call CloseWindow + call GetMemSGBLayout + call SetPalettes + ld a, [CurPartyMon] + ld [CurBattleMon], a +PlayerSwitch: ; 3e3ad + ld a, 1 + ld [wPlayerIsSwitching], a + ld a, [wLinkMode] + and a + jr z, .not_linked + call LoadStandardMenuDataHeader + call LinkBattleSendReceiveAction + call CloseWindow + +.not_linked + call ParseEnemyAction + ld a, [wLinkMode] + and a + jr nz, .linked + +.switch + call BattleMonEntrance + and a + ret + +.linked + ld a, [wBattleAction] + cp BATTLEACTION_E + jp z, .switch + cp BATTLEACTION_D + jp z, .switch + cp BATTLEACTION_SWITCH1 + jp c, .switch + cp BATTLEACTION_FORFEIT + jr nz, .dont_run + call WildFled_EnemyFled_LinkBattleCanceled + ret + +.dont_run + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .player_1 + call BattleMonEntrance + call EnemyMonEntrance + and a + ret + +.player_1 + call EnemyMonEntrance + call BattleMonEntrance + and a + ret +; 3e3ff + +EnemyMonEntrance: ; 3e3ff + callfar AI_Switch + call SetEnemyTurn + jp SpikesDamage +; 3e40b + +BattleMonEntrance: ; 3e40b + call WithdrawPkmnText + + ld c, 50 + call DelayFrames + + ld hl, PlayerSubStatus4 + res SUBSTATUS_RAGE, [hl] + + call SetEnemyTurn + call PursuitSwitch + jr c, .ok + call RecallPlayerMon +.ok + + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + + ld a, [CurBattleMon] + ld [CurPartyMon], a + call AddBattleParticipant + call InitBattleMon + call ResetPlayerStatLevels + call SendOutPkmnText + call NewBattleMonStatus + call BreakAttraction + call SendOutPlayerMon + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + call SetPlayerTurn + call SpikesDamage + ld a, $2 + ld [wMenuCursorY], a + ret +; 3e459 + +PassedBattleMonEntrance: ; 3e459 + ld c, 50 + call DelayFrames + + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + + ld a, [CurPartyMon] + ld [CurBattleMon], a + call AddBattleParticipant + call InitBattleMon + xor a + ld [wd265], a + call ApplyStatLevelMultiplierOnAllStats + call SendOutPlayerMon + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + call SetPlayerTurn + jp SpikesDamage +; 3e489 + +BattleMenu_Run: ; 3e489 + call Call_LoadTempTileMapToTileMap + ld a, $3 + ld [wMenuCursorY], a + ld hl, BattleMonSpeed + ld de, EnemyMonSpeed + call TryToRunAwayFromBattle + ld a, $0 + ld [wFailedToFlee], a + ret c + ld a, [wPlayerAction] + and a + ret nz + jp BattleMenu +; 3e4a8 + +CheckAmuletCoin: ; 3e4a8 + ld a, [BattleMonItem] + ld b, a + callfar GetItemHeldEffect + ld a, b + cp HELD_AMULET_COIN + ret nz + ld a, 1 + ld [wAmuletCoin], a + ret +; 3e4bc + +MoveSelectionScreen: ; 3e4bc + call IsMobileBattle + jr nz, .not_mobile + farcall MobileMoveSelectionScreen + ret + +.not_mobile + ld hl, EnemyMonMoves + ld a, [wMoveSelectionMenuType] + dec a + jr z, .got_menu_type + dec a + jr z, .ether_elixer_menu + call CheckPlayerHasUsableMoves + ret z ; use Struggle + ld hl, BattleMonMoves + jr .got_menu_type + +.ether_elixer_menu + ld a, MON_MOVES + call GetPartyParamLocation + +.got_menu_type + ld de, wListMoves_MoveIndicesBuffer + ld bc, NUM_MOVES + call CopyBytes + xor a + ld [hBGMapMode], a + + hlcoord 4, 17 - NUM_MOVES - 1 + ld b, 4 + ld c, 14 + ld a, [wMoveSelectionMenuType] + cp $2 + jr nz, .got_dims + hlcoord 4, 17 - NUM_MOVES - 1 - 4 + ld b, 4 + ld c, 14 +.got_dims + call TextBox + + hlcoord 6, 17 - NUM_MOVES + ld a, [wMoveSelectionMenuType] + cp $2 + jr nz, .got_start_coord + hlcoord 6, 17 - NUM_MOVES - 4 +.got_start_coord + ld a, SCREEN_WIDTH + ld [Buffer1], a + predef ListMoves + + ld b, 5 + ld a, [wMoveSelectionMenuType] + cp $2 + ld a, 17 - NUM_MOVES + jr nz, .got_default_coord + ld b, 5 + ld a, 17 - NUM_MOVES - 4 + +.got_default_coord + ld [w2DMenuCursorInitY], a + ld a, b + ld [w2DMenuCursorInitX], a + ld a, [wMoveSelectionMenuType] + cp $1 + jr z, .skip_inc + ld a, [CurMoveNum] + inc a + +.skip_inc + ld [wMenuCursorY], a + ld a, $1 + ld [wMenuCursorX], a + ld a, [wNumMoves] + inc a + ld [w2DMenuNumRows], a + ld a, $1 + ld [w2DMenuNumCols], a + ld c, $2c + ld a, [wMoveSelectionMenuType] + dec a + ld b, D_DOWN | D_UP | A_BUTTON + jr z, .okay + dec a + ld b, D_DOWN | D_UP | A_BUTTON | B_BUTTON + jr z, .okay + ld a, [wLinkMode] + and a + jr nz, .okay + ld b, D_DOWN | D_UP | A_BUTTON | B_BUTTON | SELECT + +.okay + ld a, b + ld [wMenuJoypadFilter], a + ld a, c + ld [w2DMenuFlags1], a + xor a + ld [w2DMenuFlags2], a + ld a, $10 + ld [w2DMenuCursorOffsets], a +.menu_loop + ld a, [wMoveSelectionMenuType] + and a + jr z, .battle_player_moves + dec a + jr nz, .interpret_joypad + hlcoord 11, 14 + ld de, .string_3e61c + call PlaceString + jr .interpret_joypad + +.battle_player_moves + call MoveInfoBox + ld a, [wMoveSwapBuffer] + and a + jr z, .interpret_joypad + hlcoord 5, 13 + ld bc, SCREEN_WIDTH + dec a + call AddNTimes + ld [hl], "▷" + +.interpret_joypad + ld a, $1 + ld [hBGMapMode], a + call ScrollingMenuJoypad + bit D_UP_F, a + jp nz, .pressed_up + bit D_DOWN_F, a + jp nz, .pressed_down + bit SELECT_F, a + jp nz, .pressed_select + bit B_BUTTON_F, a + ; A button + push af + + xor a + ld [wMoveSwapBuffer], a + ld a, [wMenuCursorY] + dec a + ld [wMenuCursorY], a + ld b, a + ld a, [wMoveSelectionMenuType] + dec a + jr nz, .not_enemy_moves_process_b + + pop af + ret + +.not_enemy_moves_process_b + dec a + ld a, b + ld [CurMoveNum], a + jr nz, .use_move + + pop af + ret + +.use_move + pop af + ret nz + + ld hl, BattleMonPP + ld a, [wMenuCursorY] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + and $3f + jr z, .no_pp_left + ld a, [PlayerDisableCount] + swap a + and $f + dec a + cp c + jr z, .move_disabled + ld a, [wUnusedPlayerLockedMove] + and a + jr nz, .skip2 + ld a, [wMenuCursorY] + ld hl, BattleMonMoves + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + +.skip2 + ld [CurPlayerMove], a + xor a + ret + +.move_disabled + ld hl, BattleText_TheMoveIsDisabled + jr .place_textbox_start_over + +.no_pp_left + ld hl, BattleText_TheresNoPPLeftForThisMove + +.place_textbox_start_over + call StdBattleTextBox + call Call_LoadTempTileMapToTileMap + jp MoveSelectionScreen +; 3e61c + +.string_3e61c ; 3e61c + db "@" +; 3e61d + +.pressed_up + ld a, [wMenuCursorY] + and a + jp nz, .menu_loop + ld a, [wNumMoves] + inc a + ld [wMenuCursorY], a + jp .menu_loop +; 3e62e + +.pressed_down ; 3e62e + ld a, [wMenuCursorY] + ld b, a + ld a, [wNumMoves] + inc a + inc a + cp b + jp nz, .menu_loop + ld a, $1 + ld [wMenuCursorY], a + jp .menu_loop +; 3e643 + +.pressed_select ; 3e643 + ld a, [wMoveSwapBuffer] + and a + jr z, .start_swap + ld hl, BattleMonMoves + call .swap_bytes + ld hl, BattleMonPP + call .swap_bytes + ld hl, PlayerDisableCount + ld a, [hl] + swap a + and $f + ld b, a + ld a, [wMenuCursorY] + cp b + jr nz, .not_swapping_disabled_move + ld a, [hl] + and $f + ld b, a + ld a, [wMoveSwapBuffer] + swap a + add b + ld [hl], a + jr .swap_moves_in_party_struct + +.not_swapping_disabled_move + ld a, [wMoveSwapBuffer] + cp b + jr nz, .swap_moves_in_party_struct + ld a, [hl] + and $f + ld b, a + ld a, [wMenuCursorY] + swap a + add b + ld [hl], a + +.swap_moves_in_party_struct +; Fixes the COOLTRAINER glitch + ld a, [PlayerSubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr nz, .transformed + ld hl, PartyMon1Moves + ld a, [CurBattleMon] + call GetPartyLocation + push hl + call .swap_bytes + pop hl + ld bc, MON_PP - MON_MOVES + add hl, bc + call .swap_bytes + +.transformed + xor a + ld [wMoveSwapBuffer], a + jp MoveSelectionScreen + +.swap_bytes + push hl + ld a, [wMoveSwapBuffer] + dec a + ld c, a + ld b, 0 + add hl, bc + ld d, h + ld e, l + pop hl + ld a, [wMenuCursorY] + dec a + ld c, a + ld b, 0 + add hl, bc + ld a, [de] + ld b, [hl] + ld [hl], a + ld a, b + ld [de], a + ret + +.start_swap + ld a, [wMenuCursorY] + ld [wMoveSwapBuffer], a + jp MoveSelectionScreen +; 3e6c8 + +MoveInfoBox: ; 3e6c8 + xor a + ld [hBGMapMode], a + + hlcoord 0, 8 + ld b, 3 + ld c, 9 + call TextBox + call MobileTextBorder + + ld a, [PlayerDisableCount] + and a + jr z, .not_disabled + + swap a + and $f + ld b, a + ld a, [wMenuCursorY] + cp b + jr nz, .not_disabled + + hlcoord 1, 10 + ld de, .Disabled + call PlaceString + jr .done + +.not_disabled + ld hl, wMenuCursorY + dec [hl] + call SetPlayerTurn + ld hl, BattleMonMoves + ld a, [wMenuCursorY] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + ld [CurPlayerMove], a + + ld a, [CurBattleMon] + ld [CurPartyMon], a + ld a, WILDMON + ld [MonType], a + callfar GetMaxPPOfMove + + ld hl, wMenuCursorY + ld c, [hl] + inc [hl] + ld b, 0 + ld hl, BattleMonPP + add hl, bc + ld a, [hl] + and $3f + ld [StringBuffer1], a + call .PrintPP + + hlcoord 1, 9 + ld de, .Type + call PlaceString + + hlcoord 7, 11 + ld [hl], "/" + + callfar UpdateMoveData + ld a, [wPlayerMoveStruct + MOVE_ANIM] + ld b, a + hlcoord 2, 10 + predef PrintMoveType + +.done + ret +; 3e74f + +.Disabled: + db "Disabled!@" +.Type: + db "TYPE/@" +; 3e75f + +.PrintPP: ; 3e75f + hlcoord 5, 11 + ld a, [wLinkMode] ; What's the point of this check? + cp LINK_MOBILE + jr c, .ok + hlcoord 5, 11 +.ok + push hl + ld de, StringBuffer1 + lb bc, 1, 2 + call PrintNum + pop hl + inc hl + inc hl + ld [hl], "/" + inc hl + ld de, wNamedObjectIndexBuffer + lb bc, 1, 2 + call PrintNum + ret +; 3e786 + +CheckPlayerHasUsableMoves: ; 3e786 + ld a, STRUGGLE + ld [CurPlayerMove], a + ld a, [PlayerDisableCount] + and a + ld hl, BattleMonPP + jr nz, .disabled + + ld a, [hli] + or [hl] + inc hl + or [hl] + inc hl + or [hl] + and $3f + ret nz + jr .force_struggle + +.disabled + swap a + and $f + ld b, a + ld d, NUM_MOVES + 1 + xor a +.loop + dec d + jr z, .done + ld c, [hl] + inc hl + dec b + jr z, .loop + or c + jr .loop + +.done + ; Bug: this will result in a move with PP Up confusing the game. + ; Replace with "and $3f" to fix. + and a + ret nz + +.force_struggle + ld hl, BattleText_PkmnHasNoMovesLeft + call StdBattleTextBox + ld c, 60 + call DelayFrames + xor a + ret +; 3e7c1 + +ParseEnemyAction: ; 3e7c1 + ld a, [wEnemyIsSwitching] + and a + ret nz + ld a, [wLinkMode] + and a + jr z, .not_linked + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + ld a, [wPlayerAction] + and a + call z, LinkBattleSendReceiveAction + call Call_LoadTempTileMapToTileMap + ld a, [wBattleAction] + cp BATTLEACTION_E + jp z, .struggle + cp BATTLEACTION_D + jp z, .battle_action_d + cp BATTLEACTION_SWITCH1 + jp nc, ResetVarsForSubstatusRage + ld [CurEnemyMoveNum], a + ld c, a + ld a, [EnemySubStatus1] + bit SUBSTATUS_ROLLOUT, a + jp nz, .skip_load + ld a, [EnemySubStatus3] + and 1 << SUBSTATUS_CHARGED | 1 << SUBSTATUS_RAMPAGE | 1 << SUBSTATUS_BIDE + jp nz, .skip_load + + ld hl, EnemySubStatus5 + bit SUBSTATUS_ENCORED, [hl] + ld a, [LastEnemyMove] + jp nz, .finish + ld hl, EnemyMonMoves + ld b, 0 + add hl, bc + ld a, [hl] + jp .finish + +.not_linked + ld hl, EnemySubStatus5 + bit SUBSTATUS_ENCORED, [hl] + jr z, .skip_encore + ld a, [LastEnemyMove] + jp .finish + +.skip_encore + call CheckEnemyLockedIn + jp nz, ResetVarsForSubstatusRage + jr .continue + +.battle_action_d + ld a, $ff + jr .finish + +.continue + ld hl, EnemyMonMoves + ld de, EnemyMonPP + ld b, NUM_MOVES +.loop + ld a, [hl] + and a + jp z, .struggle + ld a, [EnemyDisabledMove] + cp [hl] + jr z, .disabled + ld a, [de] + and $3f + jr nz, .enough_pp + +.disabled + inc hl + inc de + dec b + jr nz, .loop + jr .struggle + +.enough_pp + ld a, [wBattleMode] + dec a + jr nz, .skip_load +; wild +.loop2 + ld hl, EnemyMonMoves + call BattleRandom + and 3 ; TODO factor in NUM_MOVES + ld c, a + ld b, 0 + add hl, bc + ld a, [EnemyDisableCount] + swap a + and $f + dec a + cp c + jr z, .loop2 + ld a, [hl] + and a + jr z, .loop2 + ld hl, EnemyMonPP + add hl, bc + ld b, a + ld a, [hl] + and $3f + jr z, .loop2 + ld a, c + ld [CurEnemyMoveNum], a + ld a, b + +.finish + ld [CurEnemyMove], a + +.skip_load + call SetEnemyTurn + callfar UpdateMoveData + call CheckEnemyLockedIn + jr nz, .raging + xor a + ld [wEnemyCharging], a + +.raging + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + cp EFFECT_FURY_CUTTER + jr z, .fury_cutter + xor a + ld [EnemyFuryCutterCount], a + +.fury_cutter + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + cp EFFECT_RAGE + jr z, .no_rage + ld hl, EnemySubStatus4 + res SUBSTATUS_RAGE, [hl] + xor a + ld [wEnemyRageCounter], a + +.no_rage + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + cp EFFECT_PROTECT + ret z + cp EFFECT_ENDURE + ret z + xor a + ld [EnemyProtectCount], a + ret + +.struggle + ld a, STRUGGLE + jr .finish +; 3e8c1 + +ResetVarsForSubstatusRage: ; 3e8c1 + xor a + ld [EnemyFuryCutterCount], a + ld [EnemyProtectCount], a + ld [wEnemyRageCounter], a + ld hl, EnemySubStatus4 + res SUBSTATUS_RAGE, [hl] + ret +; 3e8d1 + +CheckEnemyLockedIn: ; 3e8d1 + ld a, [EnemySubStatus4] + and 1 << SUBSTATUS_RECHARGE + ret nz + + ld hl, EnemySubStatus3 + ld a, [hl] + and 1 << SUBSTATUS_CHARGED | 1 << SUBSTATUS_RAMPAGE | 1 << SUBSTATUS_BIDE + ret nz + + ld hl, EnemySubStatus1 + bit SUBSTATUS_ROLLOUT, [hl] + ret +; 3e8e4 + +LinkBattleSendReceiveAction: ; 3e8e4 + farcall _LinkBattleSendReceiveAction + ret +; 3e8eb + +LoadEnemyMon: ; 3e8eb +; Initialize enemy monster parameters +; To do this we pull the species from TempEnemyMonSpecies + +; Notes: +; BattleRandom is used to ensure sync between Game Boys + +; Clear the whole EnemyMon struct + xor a + ld hl, EnemyMonSpecies + ld bc, EnemyMonEnd - EnemyMon + call ByteFill + +; We don't need to be here if we're in a link battle + ld a, [wLinkMode] + and a + jp nz, InitEnemyMon + +; and also not in a BattleTower-Battle + ld a, [InBattleTowerBattle] ; ???? + bit 0, a + jp nz, InitEnemyMon + +; Make sure everything knows what species we're working with + ld a, [TempEnemyMonSpecies] + ld [EnemyMonSpecies], a + ld [CurSpecies], a + ld [CurPartySpecies], a + +; Grab the BaseData for this species + call GetBaseData + +; Let's get the item: + +; Is the item predetermined? + ld a, [wBattleMode] + dec a + jr z, .WildItem + +; If we're in a trainer battle, the item is in the party struct + ld a, [CurPartyMon] + ld hl, OTPartyMon1Item + call GetPartyLocation ; bc = PartyMon[CurPartyMon] - PartyMons + ld a, [hl] + jr .UpdateItem + +.WildItem: +; In a wild battle, we pull from the item slots in BaseData + +; Force Item1 +; Used for Ho-Oh, Lugia and Snorlax encounters + ld a, [BattleType] + cp BATTLETYPE_FORCEITEM + ld a, [BaseItems] + jr z, .UpdateItem + +; Failing that, it's all up to chance +; Effective chances: +; 75% None +; 23% Item1 +; 2% Item2 + +; 25% chance of getting an item + call BattleRandom + cp 1 + (75 percent) + ld a, NO_ITEM + jr c, .UpdateItem + +; From there, an 8% chance for Item2 + call BattleRandom + cp 8 percent ; 8% of 25% = 2% Item2 + ld a, [BaseItems] + jr nc, .UpdateItem + ld a, [BaseItems+1] + +.UpdateItem: + ld [EnemyMonItem], a + +; Initialize DVs + +; If we're in a trainer battle, DVs are predetermined + ld a, [wBattleMode] + and a + jr z, .InitDVs + + ld a, [EnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr z, .InitDVs + +; Unknown + ld hl, wEnemyBackupDVs + ld de, EnemyMonDVs + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + jp .Happiness + +.InitDVs: + +; Trainer DVs + +; All trainers have preset DVs, determined by class +; See GetTrainerDVs for more on that + farcall GetTrainerDVs +; These are the DVs we'll use if we're actually in a trainer battle + ld a, [wBattleMode] + dec a + jr nz, .UpdateDVs + +; Wild DVs +; Here's where the fun starts + +; Roaming monsters (Entei, Raikou) work differently +; They have their own structs, which are shorter than normal + ld a, [BattleType] + cp BATTLETYPE_ROAMING + jr nz, .NotRoaming + +; Grab HP + call GetRoamMonHP + ld a, [hl] +; Check if the HP has been initialized + and a +; We'll do something with the result in a minute + push af + +; Grab DVs + call GetRoamMonDVs + inc hl + ld a, [hld] + ld c, a + ld b, [hl] + +; Get back the result of our check + pop af +; If the RoamMon struct has already been initialized, we're done + jr nz, .UpdateDVs + +; If it hasn't, we need to initialize the DVs +; (HP is initialized at the end of the battle) + call GetRoamMonDVs + inc hl + call BattleRandom + ld [hld], a + ld c, a + call BattleRandom + ld [hl], a + ld b, a +; We're done with DVs + jr .UpdateDVs + +.NotRoaming: +; Register a contains BattleType + +; Forced shiny battle type +; Used by Red Gyarados at Lake of Rage + cp BATTLETYPE_SHINY + jr nz, .GenerateDVs + + ld b, ATKDEFDV_SHINY ; $ea + ld c, SPDSPCDV_SHINY ; $aa + jr .UpdateDVs + +.GenerateDVs: +; Generate new random DVs + call BattleRandom + ld b, a + call BattleRandom + ld c, a + +.UpdateDVs: +; Input DVs in register bc + ld hl, EnemyMonDVs + ld a, b + ld [hli], a + ld [hl], c + +; We've still got more to do if we're dealing with a wild monster + ld a, [wBattleMode] + dec a + jr nz, .Happiness + +; Species-specfic: + +; Unown + ld a, [TempEnemyMonSpecies] + cp UNOWN + jr nz, .Magikarp + +; Get letter based on DVs + ld hl, EnemyMonDVs + predef GetUnownLetter +; Can't use any letters that haven't been unlocked +; If combined with forced shiny battletype, causes an infinite loop + call CheckUnownLetter + jr c, .GenerateDVs ; try again + +.Magikarp: +; Skimming this part recommended + + ld a, [TempEnemyMonSpecies] + cp MAGIKARP + jr nz, .Happiness + +; Get Magikarp's length + ld de, EnemyMonDVs + ld bc, PlayerID + callfar CalcMagikarpLength + +; We're clear if the length is < 1536 + ld a, [wMagikarpLength] + cp HIGH(1536) + jr nz, .CheckMagikarpArea + +; 5% chance of skipping both size checks + call Random + cp 5 percent + jr c, .CheckMagikarpArea +; Try again if > 1614 + ld a, [wMagikarpLength + 1] + cp LOW(1614) + 2 + jr nc, .GenerateDVs + +; 20% chance of skipping this check + call Random + cp 20 percent - 1 + jr c, .CheckMagikarpArea +; Try again if > 1598 + ld a, [wMagikarpLength + 1] + cp LOW(1598) + 2 + jr nc, .GenerateDVs + +.CheckMagikarpArea: +; The z checks are supposed to be nz +; Instead, all maps in GROUP_LAKE_OF_RAGE (mahogany area) +; and routes 20 and 44 are treated as Lake of Rage + +; This also means Lake of Rage Magikarp can be smaller than ones +; caught elsewhere rather than the other way around + +; Intended behavior enforces a minimum size at Lake of Rage +; The real behavior prevents size flooring in the Lake of Rage area + ld a, [MapGroup] + cp GROUP_LAKE_OF_RAGE + jr z, .Happiness + ld a, [MapNumber] + cp MAP_LAKE_OF_RAGE + jr z, .Happiness +; 40% chance of not flooring + call Random + cp 40 percent - 2 + jr c, .Happiness +; Floor at length 1024 + ld a, [wMagikarpLength] + cp HIGH(1024) + jr c, .GenerateDVs ; try again + +; Finally done with DVs + +.Happiness: +; Set happiness + ld a, BASE_HAPPINESS + ld [EnemyMonHappiness], a +; Set level + ld a, [CurPartyLevel] + ld [EnemyMonLevel], a +; Fill stats + ld de, EnemyMonMaxHP + ld b, FALSE + ld hl, EnemyMonDVs - (MON_DVS - MON_STAT_EXP + 1) ; LinkBattleRNs + 7 ; ? + predef CalcPkmnStats + +; If we're in a trainer battle, +; get the rest of the parameters from the party struct + ld a, [wBattleMode] + cp TRAINER_BATTLE + jr z, .OpponentParty + +; If we're in a wild battle, check wild-specific stuff + and a + jr z, .TreeMon + + ld a, [EnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jp nz, .Moves + +.TreeMon: +; If we're headbutting trees, some monsters enter battle asleep + call CheckSleepingTreeMon + ld a, TREEMON_SLEEP_TURNS + jr c, .UpdateStatus +; Otherwise, no status + xor a + +.UpdateStatus: + ld hl, EnemyMonStatus + ld [hli], a + +; Unused byte + xor a + ld [hli], a + +; Full HP.. + ld a, [EnemyMonMaxHP] + ld [hli], a + ld a, [EnemyMonMaxHP + 1] + ld [hl], a + +; ..unless it's a RoamMon + ld a, [BattleType] + cp BATTLETYPE_ROAMING + jr nz, .Moves + +; Grab HP + call GetRoamMonHP + ld a, [hl] +; Check if it's been initialized again + and a + jr z, .InitRoamHP +; Update from the struct if it has + ld a, [hl] + ld [EnemyMonHP + 1], a + jr .Moves + +.InitRoamHP: +; HP only uses the lo byte in the RoamMon struct since +; Raikou/Entei/Suicune will have < 256 hp at level 40 + ld a, [EnemyMonHP + 1] + ld [hl], a + jr .Moves + +.OpponentParty: +; Get HP from the party struct + ld hl, (OTPartyMon1HP + 1) + ld a, [CurPartyMon] + call GetPartyLocation + ld a, [hld] + ld [EnemyMonHP + 1], a + ld a, [hld] + ld [EnemyMonHP], a + +; Make sure everything knows which monster the opponent is using + ld a, [CurPartyMon] + ld [CurOTMon], a + +; Get status from the party struct + dec hl + ld a, [hl] ; OTPartyMonStatus + ld [EnemyMonStatus], a + +.Moves: + ld hl, BaseType1 + ld de, EnemyMonType1 + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + +; Get moves + ld de, EnemyMonMoves +; Are we in a trainer battle? + ld a, [wBattleMode] + cp TRAINER_BATTLE + jr nz, .WildMoves +; Then copy moves from the party struct + ld hl, OTPartyMon1Moves + ld a, [CurPartyMon] + call GetPartyLocation + ld bc, NUM_MOVES + call CopyBytes + jr .PP + +.WildMoves: +; Clear EnemyMonMoves + xor a + ld h, d + ld l, e + ld [hli], a + ld [hli], a + ld [hli], a + ld [hl], a +; Make sure the predef knows this isn't a partymon + ld [wEvolutionOldSpecies], a +; Fill moves based on level + predef FillMoves + +.PP: +; Trainer battle? + ld a, [wBattleMode] + cp TRAINER_BATTLE + jr z, .TrainerPP + +; Fill wild PP + ld hl, EnemyMonMoves + ld de, EnemyMonPP + predef FillPP + jr .Finish + +.TrainerPP: +; Copy PP from the party struct + ld hl, OTPartyMon1PP + ld a, [CurPartyMon] + call GetPartyLocation + ld de, EnemyMonPP + ld bc, NUM_MOVES + call CopyBytes + +.Finish: +; Only the first five base stats are copied.. + ld hl, BaseStats + ld de, EnemyMonBaseStats + ld b, BaseSpecialDefense - BaseStats +.loop + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .loop + + ld a, [BaseCatchRate] + ld [de], a + inc de + + ld a, [BaseExp] + ld [de], a + + ld a, [TempEnemyMonSpecies] + ld [wd265], a + + call GetPokemonName + +; Did we catch it? + ld a, [wBattleMode] + and a + ret z + +; Update enemy nick + ld hl, StringBuffer1 + ld de, EnemyMonNick + ld bc, PKMN_NAME_LENGTH + call CopyBytes + +; Saw this mon + ld a, [TempEnemyMonSpecies] + dec a + ld c, a + ld b, SET_FLAG + ld hl, PokedexSeen + predef FlagPredef + + ld hl, EnemyMonStats + ld de, EnemyStats + ld bc, EnemyMonStatsEnd - EnemyMonStats + call CopyBytes + + ret +; 3eb38 + +CheckSleepingTreeMon: ; 3eb38 +; Return carry if species is in the list +; for the current time of day + +; Don't do anything if this isn't a tree encounter + ld a, [BattleType] + cp BATTLETYPE_TREE + jr nz, .NotSleeping + +; Get list for the time of day + ld hl, .Morn + ld a, [TimeOfDay] + cp DAY_F + jr c, .Check + ld hl, .Day + jr z, .Check + ld hl, .Nite + +.Check: + ld a, [TempEnemyMonSpecies] + ld de, 1 ; length of species id + call IsInArray +; If it's a match, the opponent is asleep + ret c + +.NotSleeping: + and a + ret + +.Nite: + db CATERPIE + db METAPOD + db BUTTERFREE + db WEEDLE + db KAKUNA + db BEEDRILL + db SPEAROW + db EKANS + db EXEGGCUTE + db LEDYBA + db AIPOM + db -1 ; end + +.Day: + db VENONAT + db HOOTHOOT + db NOCTOWL + db SPINARAK + db HERACROSS + db -1 ; end + +.Morn: + db VENONAT + db HOOTHOOT + db NOCTOWL + db SPINARAK + db HERACROSS + db -1 ; end +; 3eb75 + +CheckUnownLetter: ; 3eb75 +; Return carry if the Unown letter hasn't been unlocked yet + + ld a, [UnlockedUnowns] + ld c, a + ld de, 0 + +.loop + +; Don't check this set unless it's been unlocked + srl c + jr nc, .next + +; Is our letter in the set? + ld hl, .LetterSets + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + + push de + ld a, [UnownLetter] + ld de, 1 + push bc + call IsInArray + pop bc + pop de + + jr c, .match + +.next +; Make sure we haven't gone past the end of the table + inc e + inc e + ld a, e + cp .Set1 - .LetterSets + jr c, .loop + +; Hasn't been unlocked, or the letter is invalid + scf + ret + +.match +; Valid letter + and a + ret + +.LetterSets: + dw .Set1 + dw .Set2 + dw .Set3 + dw .Set4 + +.Set1: + ; A B C D E F G H I J K + db 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, $ff +.Set2: + ; L M N O P Q R + db 12, 13, 14, 15, 16, 17, 18, $ff +.Set3: + ; S T U V W + db 19, 20, 21, 22, 23, $ff +.Set4: + ; X Y Z + db 24, 25, 26, $ff + +; 3ebc7 + +SwapBattlerLevels: ; 3ebc7 +; unreferenced + push bc + ld a, [BattleMonLevel] + ld b, a + ld a, [EnemyMonLevel] + ld [BattleMonLevel], a + ld a, b + ld [EnemyMonLevel], a + pop bc + ret +; 3ebd8 + +BattleWinSlideInEnemyTrainerFrontpic: ; 3ebd8 + xor a + ld [TempEnemyMonSpecies], a + call FinishBattleAnim + ld a, [OtherTrainerClass] + ld [TrainerClass], a + ld de, VTiles2 + callfar GetTrainerPic + hlcoord 19, 0 + ld c, 0 + +.outer_loop + inc c + ld a, c + cp 7 + ret z + xor a + ld [hBGMapMode], a + ld [hBGMapThird], a + ld d, $0 + push bc + push hl + +.inner_loop + call .CopyColumn + inc hl + ld a, 7 + add d + ld d, a + dec c + jr nz, .inner_loop + + ld a, $1 + ld [hBGMapMode], a + ld c, 4 + call DelayFrames + pop hl + pop bc + dec hl + jr .outer_loop +; 3ec1a + +.CopyColumn: ; 3ec1a + push hl + push de + push bc + ld e, 7 + +.loop + ld [hl], d + ld bc, SCREEN_WIDTH + add hl, bc + inc d + dec e + jr nz, .loop + + pop bc + pop de + pop hl + ret +; 3ec2c + +ApplyStatusEffectOnPlayerStats: ; 3ec2c + ld a, 1 + jr ApplyStatusEffectOnStats +; 3ec30 + +ApplyStatusEffectOnEnemyStats: ; 3ec30 + xor a +; 3ec31 + +ApplyStatusEffectOnStats: ; 3ec31 + ld [hBattleTurn], a + call ApplyPrzEffectOnSpeed + jp ApplyBrnEffectOnAttack +; 3ec39 + +ApplyPrzEffectOnSpeed: ; 3ec39 + ld a, [hBattleTurn] + and a + jr z, .enemy + ld a, [BattleMonStatus] + and 1 << PAR + ret z + ld hl, BattleMonSpeed + 1 + ld a, [hld] + ld b, a + ld a, [hl] + srl a + rr b + srl a + rr b + ld [hli], a + or b + jr nz, .player_ok + ld b, $1 ; min speed + +.player_ok + ld [hl], b + ret + +.enemy + ld a, [EnemyMonStatus] + and 1 << PAR + ret z + ld hl, EnemyMonSpeed + 1 + ld a, [hld] + ld b, a + ld a, [hl] + srl a + rr b + srl a + rr b + ld [hli], a + or b + jr nz, .enemy_ok + ld b, $1 ; min speed + +.enemy_ok + ld [hl], b + ret +; 3ec76 + +ApplyBrnEffectOnAttack: ; 3ec76 + ld a, [hBattleTurn] + and a + jr z, .enemy + ld a, [BattleMonStatus] + and 1 << BRN + ret z + ld hl, BattleMonAttack + 1 + ld a, [hld] + ld b, a + ld a, [hl] + srl a + rr b + ld [hli], a + or b + jr nz, .player_ok + ld b, $1 ; min attack + +.player_ok + ld [hl], b + ret + +.enemy + ld a, [EnemyMonStatus] + and 1 << BRN + ret z + ld hl, EnemyMonAttack + 1 + ld a, [hld] + ld b, a + ld a, [hl] + srl a + rr b + ld [hli], a + or b + jr nz, .enemy_ok + ld b, $1 ; min attack + +.enemy_ok + ld [hl], b + ret +; 3ecab + +ApplyStatLevelMultiplierOnAllStats: ; 3ecab +; Apply StatLevelMultipliers on all 5 Stats + ld c, 0 +.stat_loop + call ApplyStatLevelMultiplier + inc c + ld a, c + cp 5 + jr nz, .stat_loop + ret +; 3ecb7 + +ApplyStatLevelMultiplier: ; 3ecb7 + push bc + push bc + ld a, [wd265] + and a + ld a, c + ld hl, BattleMonAttack + ld de, PlayerStats + ld bc, PlayerAtkLevel + jr z, .got_pointers + ld hl, EnemyMonAttack + ld de, EnemyStats + ld bc, EnemyAtkLevel + +.got_pointers + add c + ld c, a + jr nc, .okay + inc b +.okay + ld a, [bc] + pop bc + ld b, a + push bc + sla c + ld b, 0 + add hl, bc + ld a, c + add e + ld e, a + jr nc, .okay2 + inc d +.okay2 + pop bc + push hl + ld hl, .StatLevelMultipliers + dec b + sla b + ld c, b + ld b, 0 + add hl, bc + xor a + ld [hMultiplicand + 0], a + ld a, [de] + ld [hMultiplicand + 1], a + inc de + ld a, [de] + ld [hMultiplicand + 2], a + ld a, [hli] + ld [hMultiplier], a + call Multiply + ld a, [hl] + ld [hDivisor], a + ld b, $4 + call Divide + pop hl + +; Cap at 999. + ld a, [hQuotient + 2] + sub LOW(MAX_STAT_VALUE) + ld a, [hQuotient + 1] + sbc HIGH(MAX_STAT_VALUE) + jp c, .okay3 + + ld a, HIGH(MAX_STAT_VALUE) + ld [hQuotient + 1], a + ld a, LOW(MAX_STAT_VALUE) + ld [hQuotient + 2], a + +.okay3 + ld a, [hQuotient + 1] + ld [hli], a + ld b, a + ld a, [hQuotient + 2] + ld [hl], a + or b + jr nz, .okay4 + inc [hl] + +.okay4 + pop bc + ret +; 3ed2b + +.StatLevelMultipliers: +; / + db 25, 100 ; 25% + db 28, 100 ; 28% + db 33, 100 ; 33% + db 40, 100 ; 40% + db 50, 100 ; 50% + db 66, 100 ; 66% + + db 1, 1 ; 100% + + db 15, 10 ; 150% + db 2, 1 ; 200% + db 25, 10 ; 250% + db 3, 1 ; 300% + db 35, 10 ; 350% + db 4, 1 ; 400% +; 3ed45 + +BadgeStatBoosts: ; 3ed45 +; Raise BattleMon stats depending on which badges have been obtained. + +; Every other badge boosts a stat, starting from the first. + +; ZephyrBadge: Attack +; PlainBadge: Speed +; MineralBadge: Defense +; GlacierBadge: Special Attack +; RisingBadge: Special Defense + +; The boosted stats are in order, except PlainBadge and MineralBadge's boosts are swapped. + + ld a, [wLinkMode] + and a + ret nz + + ld a, [InBattleTowerBattle] + and a + ret nz + + ld a, [JohtoBadges] + +; Swap badges 3 (PlainBadge) and 5 (MineralBadge). + ld d, a + and (1 << PLAINBADGE) + add a + add a + ld b, a + ld a, d + and (1 << MINERALBADGE) + rrca + rrca + ld c, a + ld a, d + and ((1 << ZEPHYRBADGE) | (1 << HIVEBADGE) | (1 << FOGBADGE) | (1 << STORMBADGE) | (1 << GLACIERBADGE) | (1 << RISINGBADGE)) + or b + or c + ld b, a + + ld hl, BattleMonAttack + ld c, 4 +.CheckBadge: + ld a, b + srl b + call c, BoostStat + inc hl + inc hl +; Check every other badge. + srl b + dec c + jr nz, .CheckBadge +; And the last one (RisingBadge) too. + srl a + call c, BoostStat + ret +; 3ed7c + +BoostStat: ; 3ed7c +; Raise stat at hl by 1/8. + + ld a, [hli] + ld d, a + ld e, [hl] + srl d + rr e + srl d + rr e + srl d + rr e + ld a, [hl] + add e + ld [hld], a + ld a, [hl] + adc d + ld [hli], a + +; Cap at 999. + ld a, [hld] + sub LOW(MAX_STAT_VALUE) + ld a, [hl] + sbc HIGH(MAX_STAT_VALUE) + ret c + ld a, HIGH(MAX_STAT_VALUE) + ld [hli], a + ld a, LOW(MAX_STAT_VALUE) + ld [hld], a + ret +; 3ed9f + +_LoadBattleFontsHPBar: ; 3ed9f + callfar LoadBattleFontsHPBar + ret +; 3eda6 + +_LoadHPBar: ; 3eda6 + callfar LoadHPBar + ret +; 3edad + +LoadHPExpBarGFX: ; unreferenced + ld de, EnemyHPBarBorderGFX + ld hl, VTiles2 tile $6c + lb bc, BANK(EnemyHPBarBorderGFX), 4 + call Get1bpp + ld de, HPExpBarBorderGFX + ld hl, VTiles2 tile $73 + lb bc, BANK(HPExpBarBorderGFX), 6 + call Get1bpp + ld de, ExpBarGFX + ld hl, VTiles2 tile $55 + lb bc, BANK(ExpBarGFX), 8 + jp Get2bpp +; 3edd1 + +EmptyBattleTextBox: ; 3edd1 + ld hl, .empty + jp BattleTextBox +.empty + db "@" +; 3edd8 + +_BattleRandom:: ; 3edd8 +; If the normal RNG is used in a link battle it'll desync. +; To circumvent this a shared PRNG is used instead. + +; But if we're in a non-link battle we're safe to use it + ld a, [wLinkMode] + and a + jp z, Random + +; The PRNG operates in streams of 10 values. + +; Which value are we trying to pull? + push hl + push bc + ld a, [LinkBattleRNCount] + ld c, a + ld b, 0 + ld hl, LinkBattleRNs + add hl, bc + inc a + ld [LinkBattleRNCount], a + +; If we haven't hit the end yet, we're good + cp 10 - 1 ; Exclude last value. See the closing comment + ld a, [hl] + pop bc + pop hl + ret c + +; If we have, we have to generate new pseudorandom data +; Instead of having multiple PRNGs, ten seeds are used + push hl + push bc + push af + +; Reset count to 0 + xor a + ld [LinkBattleRNCount], a + ld hl, LinkBattleRNs + ld b, 10 ; number of seeds + +; Generate next number in the sequence for each seed +; a[n+1] = (a[n] * 5 + 1) % 256 +.loop + ; get last # + ld a, [hl] + + ; a * 5 + 1 + ld c, a + add a + add a + add c + inc a + + ; update # + ld [hli], a + dec b + jr nz, .loop + +; This has the side effect of pulling the last value first, +; then wrapping around. As a result, when we check to see if +; we've reached the end, we check the one before it. + + pop af + pop bc + pop hl + ret +; 3ee0f + +Call_PlayBattleAnim_OnlyIfVisible: ; 3ee0f + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret nz +; 3ee17 + +Call_PlayBattleAnim: ; 3ee17 + ld a, e + ld [FXAnimID], a + ld a, d + ld [FXAnimID + 1], a + call WaitBGMap + predef_jump PlayBattleAnim +; 3ee27 + +FinishBattleAnim: ; 3ee27 + push af + push bc + push de + push hl + ld b, SCGB_BATTLE_COLORS + call GetSGBLayout + call SetPalettes + call DelayFrame + pop hl + pop de + pop bc + pop af + ret +; 3ee3b + +GiveExperiencePoints: ; 3ee3b +; Give experience. +; Don't give experience if linked or in the Battle Tower. + ld a, [wLinkMode] + and a + ret nz + + ld a, [InBattleTowerBattle] + bit 0, a + ret nz + + call .EvenlyDivideExpAmongParticipants + xor a + ld [CurPartyMon], a + ld bc, PartyMon1Species + +.loop + ld hl, MON_HP + add hl, bc + ld a, [hli] + or [hl] + jp z, .skip_stats ; fainted + + push bc + ld hl, wBattleParticipantsNotFainted + ld a, [CurPartyMon] + ld c, a + ld b, CHECK_FLAG + ld d, $0 + predef FlagPredef + ld a, c + and a + pop bc + jp z, .skip_stats + +; give stat exp + ld hl, MON_STAT_EXP + 1 + add hl, bc + ld d, h + ld e, l + ld hl, EnemyMonBaseStats - 1 + push bc + ld c, $5 +.loop1 + inc hl + ld a, [de] + add [hl] + ld [de], a + jr nc, .okay1 + dec de + ld a, [de] + inc a + jr z, .next + ld [de], a + inc de + +.okay1 + push hl + push bc + ld a, MON_PKRUS + call GetPartyParamLocation + ld a, [hl] + and a + pop bc + pop hl + jr z, .skip + ld a, [de] + add [hl] + ld [de], a + jr nc, .skip + dec de + ld a, [de] + inc a + jr z, .next + ld [de], a + inc de + jr .skip + +.next + ld a, $ff + ld [de], a + inc de + ld [de], a + +.skip + inc de + inc de + dec c + jr nz, .loop1 + xor a + ld [hMultiplicand + 0], a + ld [hMultiplicand + 1], a + ld a, [EnemyMonBaseExp] + ld [hMultiplicand + 2], a + ld a, [EnemyMonLevel] + ld [hMultiplier], a + call Multiply + ld a, 7 + ld [hDivisor], a + ld b, 4 + call Divide +; Boost Experience for traded Pokemon + pop bc + ld hl, MON_ID + add hl, bc + ld a, [PlayerID] + cp [hl] + jr nz, .boosted + inc hl + ld a, [PlayerID + 1] + cp [hl] + ld a, $0 + jr z, .no_boost + +.boosted + call BoostExp + ld a, $1 + +.no_boost +; Boost experience for a Trainer Battle + ld [StringBuffer2 + 2], a + ld a, [wBattleMode] + dec a + call nz, BoostExp +; Boost experience for Lucky Egg + push bc + ld a, MON_ITEM + call GetPartyParamLocation + ld a, [hl] + cp LUCKY_EGG + call z, BoostExp + ld a, [hQuotient + 2] + ld [StringBuffer2 + 1], a + ld a, [hQuotient + 1] + ld [StringBuffer2], a + ld a, [CurPartyMon] + ld hl, PartyMonNicknames + call GetNick + ld hl, Text_PkmnGainedExpPoint + call BattleTextBox + ld a, [StringBuffer2 + 1] + ld [hQuotient + 2], a + ld a, [StringBuffer2] + ld [hQuotient + 1], a + pop bc + call AnimateExpBar + push bc + call LoadTileMapToTempTileMap + pop bc + ld hl, MON_STAT_EXP - 1 + add hl, bc + ld d, [hl] + ld a, [hQuotient + 2] + add d + ld [hld], a + ld d, [hl] + ld a, [hQuotient + 1] + adc d + ld [hl], a + jr nc, .skip2 + dec hl + inc [hl] + jr nz, .skip2 + ld a, $ff + ld [hli], a + ld [hli], a + ld [hl], a + +.skip2 + ld a, [CurPartyMon] + ld e, a + ld d, $0 + ld hl, PartySpecies + add hl, de + ld a, [hl] + ld [CurSpecies], a + call GetBaseData + push bc + ld d, MAX_LEVEL + callfar CalcExpAtLevel + pop bc + ld hl, MON_STAT_EXP - 1 + add hl, bc + push bc + ld a, [hQuotient] + ld b, a + ld a, [hQuotient + 1] + ld c, a + ld a, [hQuotient + 2] + ld d, a + ld a, [hld] + sub d + ld a, [hld] + sbc c + ld a, [hl] + sbc b + jr c, .not_max_exp + ld a, b + ld [hli], a + ld a, c + ld [hli], a + ld a, d + ld [hld], a + +.not_max_exp + xor a ; PARTYMON + ld [MonType], a + predef CopyPkmnToTempMon + callfar CalcLevel + pop bc + ld hl, MON_LEVEL + add hl, bc + ld a, [hl] + cp MAX_LEVEL + jp nc, .skip_stats + cp d + jp z, .skip_stats +; <NICKNAME> grew to level ##! + ld [wTempLevel], a + ld a, [CurPartyLevel] + push af + ld a, d + ld [CurPartyLevel], a + ld [hl], a + ld hl, MON_SPECIES + add hl, bc + ld a, [hl] + ld [CurSpecies], a + ld [wd265], a + call GetBaseData + ld hl, MON_MAXHP + 1 + add hl, bc + ld a, [hld] + ld e, a + ld d, [hl] + push de + ld hl, MON_MAXHP + add hl, bc + ld d, h + ld e, l + ld hl, MON_STAT_EXP - 1 + add hl, bc + push bc + ld b, TRUE + predef CalcPkmnStats + pop bc + pop de + ld hl, MON_MAXHP + 1 + add hl, bc + ld a, [hld] + sub e + ld e, a + ld a, [hl] + sbc d + ld d, a + dec hl + ld a, [hl] + add e + ld [hld], a + ld a, [hl] + adc d + ld [hl], a + ld a, [CurBattleMon] + ld d, a + ld a, [CurPartyMon] + cp d + jr nz, .skip_animation + ld de, BattleMonHP + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + ld de, BattleMonMaxHP + push bc + ld bc, PARTYMON_STRUCT_LENGTH - MON_MAXHP + call CopyBytes + pop bc + ld hl, MON_LEVEL + add hl, bc + ld a, [hl] + ld [BattleMonLevel], a + ld a, [PlayerSubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr nz, .transformed + ld hl, MON_ATK + add hl, bc + ld de, PlayerStats + ld bc, PARTYMON_STRUCT_LENGTH - MON_ATK + call CopyBytes + +.transformed + xor a + ld [wd265], a + call ApplyStatLevelMultiplierOnAllStats + callfar ApplyStatusEffectOnPlayerStats + callfar BadgeStatBoosts + callfar UpdatePlayerHUD + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + ld a, $1 + ld [hBGMapMode], a + +.skip_animation + farcall LevelUpHappinessMod + ld a, [CurBattleMon] + ld b, a + ld a, [CurPartyMon] + cp b + jr z, .skip_animation2 + ld de, SFX_HIT_END_OF_EXP_BAR + call PlaySFX + call WaitSFX + ld hl, BattleText_StringBuffer1GrewToLevel + call StdBattleTextBox + call LoadTileMapToTempTileMap + +.skip_animation2 + xor a ; PARTYMON + ld [MonType], a + predef CopyPkmnToTempMon + hlcoord 9, 0 + ld b, $a + ld c, $9 + call TextBox + hlcoord 11, 1 + ld bc, 4 + predef PrintTempMonStats + ld c, $1e + call DelayFrames + call WaitPressAorB_BlinkCursor + call Call_LoadTempTileMapToTileMap + xor a ; PARTYMON + ld [MonType], a + ld a, [CurSpecies] + ld [wd265], a + ld a, [CurPartyLevel] + push af + ld c, a + ld a, [wTempLevel] + ld b, a + +.level_loop + inc b + ld a, b + ld [CurPartyLevel], a + push bc + predef LearnLevelMoves + pop bc + ld a, b + cp c + jr nz, .level_loop + pop af + ld [CurPartyLevel], a + ld hl, EvolvableFlags + ld a, [CurPartyMon] + ld c, a + ld b, SET_FLAG + predef FlagPredef + pop af + ld [CurPartyLevel], a + +.skip_stats + ld a, [PartyCount] + ld b, a + ld a, [CurPartyMon] + inc a + cp b + jr z, .done + ld [CurPartyMon], a + ld a, MON_SPECIES + call GetPartyParamLocation + ld b, h + ld c, l + jp .loop + +.done + jp ResetBattleParticipants +; 3f0d4 + +.EvenlyDivideExpAmongParticipants: +; count number of battle participants + ld a, [wBattleParticipantsNotFainted] + ld b, a + ld c, PARTY_LENGTH + ld d, 0 +.count_loop + xor a + srl b + adc d + ld d, a + dec c + jr nz, .count_loop + cp 2 + ret c + + ld [wd265], a + ld hl, EnemyMonBaseStats + ld c, EnemyMonEnd - EnemyMonBaseStats +.count_loop2 + xor a + ld [hDividend + 0], a + ld a, [hl] + ld [hDividend + 1], a + ld a, [wd265] + ld [hDivisor], a + ld b, 2 + call Divide + ld a, [hQuotient + 2] + ld [hli], a + dec c + jr nz, .count_loop2 + ret +; 3f106 + +BoostExp: ; 3f106 +; Multiply experience by 1.5x + push bc +; load experience value + ld a, [hProduct + 2] + ld b, a + ld a, [hProduct + 3] + ld c, a +; halve it + srl b + rr c +; add it back to the whole exp value + add c + ld [hProduct + 3], a + ld a, [hProduct + 2] + adc b + ld [hProduct + 2], a + pop bc + ret +; 3f11b + +Text_PkmnGainedExpPoint: ; 3f11b + text_jump Text_Gained + start_asm + ld hl, TextJump_StringBuffer2ExpPoints + ld a, [StringBuffer2 + 2] ; IsTradedMon + and a + ret z + + ld hl, TextJump_ABoostedStringBuffer2ExpPoints + ret +; 3f12c + +TextJump_ABoostedStringBuffer2ExpPoints: ; 3f12c + text_jump Text_ABoostedStringBuffer2ExpPoints + db "@" +; 3f131 + +TextJump_StringBuffer2ExpPoints: ; 3f131 + text_jump Text_StringBuffer2ExpPoints + db "@" +; 3f136 + +AnimateExpBar: ; 3f136 + push bc + + ld hl, CurPartyMon + ld a, [CurBattleMon] + cp [hl] + jp nz, .finish + + ld a, [BattleMonLevel] + cp MAX_LEVEL + jp nc, .finish + + ld a, [hProduct + 3] + ld [wd004], a + push af + ld a, [hProduct + 2] + ld [wd003], a + push af + xor a + ld [wd002], a + xor a ; PARTYMON + ld [MonType], a + predef CopyPkmnToTempMon + ld a, [TempMonLevel] + ld b, a + ld e, a + push de + ld de, TempMonExp + 2 + call CalcExpBar + push bc + ld hl, TempMonExp + 2 + ld a, [wd004] + add [hl] + ld [hld], a + ld a, [wd003] + adc [hl] + ld [hld], a + jr nc, .NoOverflow + inc [hl] + jr nz, .NoOverflow + ld a, $ff + ld [hli], a + ld [hli], a + ld [hl], a + +.NoOverflow: + ld d, MAX_LEVEL + callfar CalcExpAtLevel + ld a, [hProduct + 1] + ld b, a + ld a, [hProduct + 2] + ld c, a + ld a, [hProduct + 3] + ld d, a + ld hl, TempMonExp + 2 + ld a, [hld] + sub d + ld a, [hld] + sbc c + ld a, [hl] + sbc b + jr c, .AlreadyAtMaxExp + ld a, b + ld [hli], a + ld a, c + ld [hli], a + ld a, d + ld [hld], a + +.AlreadyAtMaxExp: + callfar CalcLevel + ld a, d + pop bc + pop de + ld d, a + cp e + jr nc, .LoopLevels + ld a, e + ld d, a + +.LoopLevels: + ld a, e + cp MAX_LEVEL + jr nc, .FinishExpBar + cp d + jr z, .FinishExpBar + inc a + ld [TempMonLevel], a + ld [CurPartyLevel], a + ld [BattleMonLevel], a + push de + call .PlayExpBarSound + ld c, $40 + call .LoopBarAnimation + call PrintPlayerHUD + ld hl, BattleMonNick + ld de, StringBuffer1 + ld bc, PKMN_NAME_LENGTH + call CopyBytes + call TerminateExpBarSound + ld de, SFX_HIT_END_OF_EXP_BAR + call PlaySFX + farcall AnimateEndOfExpBar + call WaitSFX + ld hl, BattleText_StringBuffer1GrewToLevel + call StdBattleTextBox + pop de + inc e + ld b, $0 + jr .LoopLevels + +.FinishExpBar: + push bc + ld b, d + ld de, TempMonExp + 2 + call CalcExpBar + ld a, b + pop bc + ld c, a + call .PlayExpBarSound + call .LoopBarAnimation + call TerminateExpBarSound + pop af + ld [hProduct + 2], a + pop af + ld [hProduct + 3], a + +.finish + pop bc + ret + +.PlayExpBarSound: + push bc + call WaitSFX + ld de, SFX_EXP_BAR + call PlaySFX + ld c, 10 + call DelayFrames + pop bc + ret + +.LoopBarAnimation: + ld d, 3 + dec b +.anim_loop + inc b + push bc + push de + hlcoord 17, 11 + call PlaceExpBar + pop de + ld a, $1 + ld [hBGMapMode], a + ld c, d + call DelayFrames + xor a + ld [hBGMapMode], a + pop bc + ld a, c + cp b + jr z, .end_animation + inc b + push bc + push de + hlcoord 17, 11 + call PlaceExpBar + pop de + ld a, $1 + ld [hBGMapMode], a + ld c, d + call DelayFrames + xor a + ld [hBGMapMode], a + dec d + jr nz, .min_number_of_frames + ld d, 1 +.min_number_of_frames + pop bc + ld a, c + cp b + jr nz, .anim_loop +.end_animation + ld a, $1 + ld [hBGMapMode], a + ret + +SendOutPkmnText: ; 3f26d + ld a, [wLinkMode] + and a + jr z, .not_linked + + ld hl, JumpText_GoPkmn ; If we're in a LinkBattle print just "Go <PlayerMon>" + + ld a, [wBattleHasJustStarted] ; unless this (unidentified) variable is set + and a + jr nz, .skip_to_textbox + +.not_linked +; Depending on the HP of the enemy Pkmn, the game prints a different text + ld hl, EnemyMonHP + ld a, [hli] + or [hl] + ld hl, JumpText_GoPkmn + jr z, .skip_to_textbox + + ; compute enemy helth remaining as a percentage + xor a + ld [hMultiplicand + 0], a + ld hl, EnemyMonHP + ld a, [hli] + ld [wEnemyHPAtTimeOfPlayerSwitch], a + ld [hMultiplicand + 1], a + ld a, [hl] + ld [wEnemyHPAtTimeOfPlayerSwitch + 1], a + ld [hMultiplicand + 2], a + ld a, 25 + ld [hMultiplier], a + call Multiply + ld hl, EnemyMonMaxHP + ld a, [hli] + ld b, [hl] + srl a + rr b + srl a + rr b + ld a, b + ld b, 4 + ld [hDivisor], a + call Divide + + ld a, [hQuotient + 2] + ld hl, JumpText_GoPkmn + cp 70 + jr nc, .skip_to_textbox + + ld hl, JumpText_DoItPkmn + cp 40 + jr nc, .skip_to_textbox + + ld hl, JumpText_GoForItPkmn + cp 10 + jr nc, .skip_to_textbox + + ld hl, JumpText_YourFoesWeakGetmPkmn +.skip_to_textbox + jp BattleTextBox +; 3f2d1 + +JumpText_GoPkmn: ; 3f2d1 + text_jump Text_GoPkmn + start_asm + jr Function_TextJump_BattleMonNick01 +; 3f2d6 + +JumpText_DoItPkmn: ; 3f2d8 + text_jump Text_DoItPkmn + start_asm + jr Function_TextJump_BattleMonNick01 +; 3f2dd + +JumpText_GoForItPkmn: ; 3f2df + text_jump Text_GoForItPkmn + start_asm + jr Function_TextJump_BattleMonNick01 +; 3f2e4 + +JumpText_YourFoesWeakGetmPkmn: ; 3f2e6 + text_jump Text_YourFoesWeakGetmPkmn + start_asm +Function_TextJump_BattleMonNick01: ; 3f2eb + ld hl, TextJump_BattleMonNick01 + ret +; 3f2ef + +TextJump_BattleMonNick01: ; 3f2ef + text_jump Text_BattleMonNick01 + db "@" +; 3f2f4 + +WithdrawPkmnText: ; 3f2f4 + ld hl, .WithdrawPkmnText + jp BattleTextBox + +.WithdrawPkmnText: + text_jump Text_BattleMonNickComma + start_asm +; Print text to withdraw Pkmn +; depending on HP the message is different + push de + push bc + ld hl, EnemyMonHP + 1 + ld de, wEnemyHPAtTimeOfPlayerSwitch + 1 + ld b, [hl] + dec hl + ld a, [de] + sub b + ld [hMultiplicand + 2], a + dec de + ld b, [hl] + ld a, [de] + sbc b + ld [hMultiplicand + 1], a + ld a, 25 + ld [hMultiplier], a + call Multiply + ld hl, EnemyMonMaxHP + ld a, [hli] + ld b, [hl] + srl a + rr b + srl a + rr b + ld a, b + ld b, 4 + ld [hDivisor], a + call Divide + pop bc + pop de + ld a, [hQuotient + 2] + ld hl, TextJump_ThatsEnoughComeBack + and a + ret z + + ld hl, TextJump_ComeBack + cp 30 + ret c + + ld hl, TextJump_OKComeBack + cp 70 + ret c + + ld hl, TextJump_GoodComeBack + ret +; 3f348 + +TextJump_ThatsEnoughComeBack: ; 3f348 + text_jump Text_ThatsEnoughComeBack + db "@" +; 3f34d + +TextJump_OKComeBack: ; 3f34d + text_jump Text_OKComeBack + db "@" +; 3f352 + +TextJump_GoodComeBack: ; 3f352 + text_jump Text_GoodComeBack + db "@" +; 3f357 + +UnusedFunction_TextJump_ComeBack: ; 3f357 +; this function doesn't seem to be used + ld hl, TextJump_ComeBack + ret +; 3f35b + +TextJump_ComeBack: ; 3f35b + text_jump Text_ComeBack + db "@" +; 3f360 + +HandleSafariAngerEatingStatus: ; unreferenced + ld hl, wSafariMonEating + ld a, [hl] + and a + jr z, .angry + dec [hl] + ld hl, BattleText_WildPkmnIsEating + jr .finish + +.angry + dec hl ; wSafariMonAngerCount + ld a, [hl] + and a + ret z + dec [hl] + ld hl, BattleText_WildPkmnIsAngry + jr nz, .finish + push hl + ld a, [EnemyMonSpecies] + ld [CurSpecies], a + call GetBaseData + ld a, [BaseCatchRate] + ld [EnemyMonCatchRate], a + pop hl + +.finish + push hl + call Call_LoadTempTileMapToTileMap + pop hl + jp StdBattleTextBox +; 3f390 + +FillInExpBar: ; 3f390 + push hl + call CalcExpBar + pop hl + ld de, 7 + add hl, de + jp PlaceExpBar +; 3f39c + +CalcExpBar: ; 3f39c +; Calculate the percent exp between this level and the next +; Level in b + push de + ld d, b + push de + callfar CalcExpAtLevel + pop de +; exp at current level gets pushed to the stack + ld hl, hMultiplicand + ld a, [hli] + push af + ld a, [hli] + push af + ld a, [hl] + push af +; next level + inc d + callfar CalcExpAtLevel +; back up the next level exp, and subtract the two levels + ld hl, hMultiplicand + 2 + ld a, [hl] + ld [hMathBuffer + 2], a + pop bc + sub b + ld [hld], a + ld a, [hl] + ld [hMathBuffer + 1], a + pop bc + sbc b + ld [hld], a + ld a, [hl] + ld [hMathBuffer], a + pop bc + sbc b + ld [hl], a + pop de + + ld hl, hMultiplicand + 1 + ld a, [hli] + push af + ld a, [hl] + push af + +; get the amount of exp remaining to the next level + ld a, [de] + dec de + ld c, a + ld a, [hMathBuffer + 2] + sub c + ld [hld], a + ld a, [de] + dec de + ld b, a + ld a, [hMathBuffer + 1] + sbc b + ld [hld], a + ld a, [de] + ld c, a + ld a, [hMathBuffer] + sbc c + ld [hld], a + xor a + ld [hl], a +; multiply by 64 + ld a, $40 + ld [hMultiplier], a + call Multiply + pop af + ld c, a + pop af + ld b, a +.loop + ld a, b + and a + jr z, .done + srl b + rr c + ld hl, hProduct + srl [hl] + inc hl + rr [hl] + inc hl + rr [hl] + inc hl + rr [hl] + jr .loop + +.done + ld a, c + ld [hDivisor], a + ld b, 4 + call Divide + ld a, [hQuotient + 2] + ld b, a + ld a, $40 + sub b + ld b, a + ret +; 3f41c + +PlaceExpBar: ; 3f41c + ld c, $8 ; number of tiles +.loop1 + ld a, b + sub $8 + jr c, .next + ld b, a + ld a, $6a ; full bar + ld [hld], a + dec c + jr z, .finish + jr .loop1 + +.next + add $8 + jr z, .loop2 + add $54 ; tile to the left of small exp bar tile + jr .skip + +.loop2 + ld a, $62 ; empty bar + +.skip + ld [hld], a + ld a, $62 ; empty bar + dec c + jr nz, .loop2 + +.finish + ret +; 3f43d + +GetBattleMonBackpic: ; 3f43d + ld a, [PlayerSubStatus4] + bit SUBSTATUS_SUBSTITUTE, a + ld hl, BattleAnimCmd_RaiseSub + jr nz, GetBattleMonBackpic_DoAnim ; substitute + +DropPlayerSub: ; 3f447 + ld a, [wPlayerMinimized] + and a + ld hl, BattleAnimCmd_MinimizeOpp + jr nz, GetBattleMonBackpic_DoAnim + ld a, [CurPartySpecies] + push af + ld a, [BattleMonSpecies] + ld [CurPartySpecies], a + ld hl, BattleMonDVs + predef GetUnownLetter + ld de, VTiles2 tile $31 + predef GetMonBackpic + pop af + ld [CurPartySpecies], a + ret +; 3f46f + +GetBattleMonBackpic_DoAnim: ; 3f46f + ld a, [hBattleTurn] + push af + xor a + ld [hBattleTurn], a + ld a, BANK(BattleAnimCommands) + rst FarCall + pop af + ld [hBattleTurn], a + ret +; 3f47c + +GetEnemyMonFrontpic: ; 3f47c + ld a, [EnemySubStatus4] + bit SUBSTATUS_SUBSTITUTE, a + ld hl, BattleAnimCmd_RaiseSub + jr nz, GetEnemyMonFrontpic_DoAnim + +DropEnemySub: ; 3f486 + ld a, [wEnemyMinimized] + and a + ld hl, BattleAnimCmd_MinimizeOpp + jr nz, GetEnemyMonFrontpic_DoAnim + + ld a, [CurPartySpecies] + push af + ld a, [EnemyMonSpecies] + ld [CurSpecies], a + ld [CurPartySpecies], a + call GetBaseData + ld hl, EnemyMonDVs + predef GetUnownLetter + ld de, VTiles2 + predef GetAnimatedFrontpicPredef + pop af + ld [CurPartySpecies], a + ret +; 3f4b4 + +GetEnemyMonFrontpic_DoAnim: ; 3f4b4 + ld a, [hBattleTurn] + push af + call SetEnemyTurn + ld a, BANK(BattleAnimCommands) + rst FarCall + pop af + ld [hBattleTurn], a + ret +; 3f4c1 + +StartBattle: ; 3f4c1 +; This check prevents you from entering a battle without any Pokemon. +; Those using walk-through-walls to bypass getting a Pokemon experience +; the effects of this check. + ld a, [PartyCount] + and a + ret z + + ld a, [TimeOfDayPal] + push af + call BattleIntro + call DoBattle + call ExitBattle + pop af + ld [TimeOfDayPal], a + scf + ret +; 3f4d9 + +_DoBattle: ; 3f4d9 +; unreferenced + call DoBattle + ret +; 3f4dd + +BattleIntro: ; 3f4dd + farcall TrainerRankings_Battles ; mobile + call LoadTrainerOrWildMonPic + xor a + ld [TempBattleMonSpecies], a + ld [wBattleMenuCursorBuffer], a + xor a + ld [hMapAnims], a + farcall PlayBattleMusic + farcall ShowLinkBattleParticipants + farcall FindFirstAliveMonAndStartBattle + call DisableSpriteUpdates + farcall ClearBattleRAM + call InitEnemy + call BackUpVBGMap2 + ld b, SCGB_BATTLE_GRAYSCALE + call GetSGBLayout + ld hl, rLCDC + res 6, [hl] + call InitBattleDisplay + call BattleStartMessage + ld hl, rLCDC + set 6, [hl] + xor a + ld [hBGMapMode], a + call EmptyBattleTextBox + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + call ClearSprites + ld a, [wBattleMode] + cp WILD_BATTLE + call z, UpdateEnemyHUD + ld a, $1 + ld [hBGMapMode], a + ret +; 3f54e + +LoadTrainerOrWildMonPic: ; 3f54e + ld a, [OtherTrainerClass] + and a + jr nz, .Trainer + ld a, [TempWildMonSpecies] + ld [CurPartySpecies], a + +.Trainer: + ld [TempEnemyMonSpecies], a + ret +; 3f55e + +InitEnemy: ; 3f55e + ld a, [OtherTrainerClass] + and a + jp nz, InitEnemyTrainer ; trainer + jp InitEnemyWildmon ; wild +; 3f568 + +BackUpVBGMap2: ; 3f568 + ld a, [rSVBK] + push af + ld a, $6 ; BANK(wDecompressScratch) + ld [rSVBK], a + ld hl, wDecompressScratch + ld bc, $40 tiles ; VBGMap3 - VBGMap2 + ld a, $2 + call ByteFill + ld a, [rVBK] + push af + ld a, $1 + ld [rVBK], a + ld de, wDecompressScratch + hlbgcoord 0, 0 ; VBGMap2 + lb bc, BANK(BackUpVBGMap2), $40 + call Request2bpp + pop af + ld [rVBK], a + pop af + ld [rSVBK], a + ret +; 3f594 + +InitEnemyTrainer: ; 3f594 + ld [TrainerClass], a + farcall TrainerRankings_TrainerBattles + xor a + ld [TempEnemyMonSpecies], a + callfar GetTrainerAttributes + callfar ReadTrainerParty + + ld a, [TrainerClass] + cp RIVAL1 + jr nz, .ok + xor a + ld [OTPartyMon1Item], a +.ok + + ld de, VTiles2 + callfar GetTrainerPic + xor a + ld [hGraphicStartTile], a + dec a + ld [wEnemyItemState], a + hlcoord 12, 0 + lb bc, 7, 7 + predef PlaceGraphic + ld a, -1 + ld [CurOTMon], a + ld a, TRAINER_BATTLE + ld [wBattleMode], a + + call IsJohtoGymLeader + jr nc, .done + xor a + ld [CurPartyMon], a + ld a, [PartyCount] + ld b, a +.partyloop + push bc + ld a, MON_HP + call GetPartyParamLocation + ld a, [hli] + or [hl] + jr z, .skipfaintedmon + ld c, HAPPINESS_GYMBATTLE + callfar ChangeHappiness +.skipfaintedmon + pop bc + dec b + jr z, .done + ld hl, CurPartyMon + inc [hl] + jr .partyloop +.done + ret +; 3f607 + +InitEnemyWildmon: ; 3f607 + ld a, WILD_BATTLE + ld [wBattleMode], a + farcall TrainerRankings_WildBattles + call LoadEnemyMon + ld hl, EnemyMonMoves + ld de, wWildMonMoves + ld bc, NUM_MOVES + call CopyBytes + ld hl, EnemyMonPP + ld de, wWildMonPP + ld bc, NUM_MOVES + call CopyBytes + ld hl, EnemyMonDVs + predef GetUnownLetter + ld a, [CurPartySpecies] + cp UNOWN + jr nz, .skip_unown + ld a, [wFirstUnownSeen] + and a + jr nz, .skip_unown + ld a, [UnownLetter] + ld [wFirstUnownSeen], a +.skip_unown + ld de, VTiles2 + predef GetAnimatedFrontpicPredef + xor a + ld [TrainerClass], a + ld [hGraphicStartTile], a + hlcoord 12, 0 + lb bc, 7, 7 + predef PlaceGraphic + ret +; 3f662 + +Function3f662: ; 3f662 +; XXX + ld hl, EnemyMonMoves + ld de, wListMoves_MoveIndicesBuffer + ld b, NUM_MOVES +.loop + ld a, [de] + inc de + ld [hli], a + and a + jr z, .clearpp + + push bc + push hl + + push hl + dec a + ld hl, Moves + MOVE_PP + ld bc, MOVE_LENGTH + call AddNTimes + ld a, BANK(Moves) + call GetFarByte + pop hl + + ld bc, EnemyMonPP - (EnemyMonMoves + 1) + add hl, bc + ld [hl], a + + pop hl + pop bc + + dec b + jr nz, .loop + ret + +.clear + xor a + ld [hli], a + +.clearpp + push bc + push hl + ld bc, EnemyMonPP - (EnemyMonMoves + 1) + add hl, bc + xor a + ld [hl], a + pop hl + pop bc + dec b + jr nz, .clear + ret +; 3f69e + +ExitBattle: ; 3f69e + call .HandleEndOfBattle + call CleanUpBattleRAM + ret +; 3f6a5 + +.HandleEndOfBattle: ; 3f6a5 + ld a, [wLinkMode] + and a + jr z, .not_linked + call ShowLinkBattleParticipantsAfterEnd + ld c, 150 + call DelayFrames + call DisplayLinkBattleResult + ret + +.not_linked + ld a, [wBattleResult] + and $f + ret nz + call CheckPayDay + xor a + ld [wForceEvolution], a + predef EvolveAfterBattle + farcall GivePokerusAndConvertBerries + ret +; 3f6d0 + +CleanUpBattleRAM: ; 3f6d0 + call BattleEnd_HandleRoamMons + xor a + ld [Danger], a + ld [wBattleMode], a + ld [BattleType], a + ld [AttackMissed], a + ld [TempWildMonSpecies], a + ld [OtherTrainerClass], a + ld [wFailedToFlee], a + ld [wNumFleeAttempts], a + ld [wForcedSwitch], a + ld [wPartyMenuCursor], a + ld [wKeyItemsPocketCursor], a + ld [wItemsPocketCursor], a + ld [wBattleMenuCursorBuffer], a + ld [CurMoveNum], a + ld [wBallsPocketCursor], a + ld [wLastPocket], a + ld [wMenuScrollPosition], a + ld [wKeyItemsPocketScrollPosition], a + ld [wItemsPocketScrollPosition], a + ld [wBallsPocketScrollPosition], a + ld hl, PlayerSubStatus1 + ld b, EnemyFuryCutterCount - PlayerSubStatus1 +.loop + ld [hli], a + dec b + jr nz, .loop + call WaitSFX + ret +; 3f71d + +CheckPayDay: ; 3f71d + ld hl, wPayDayMoney + ld a, [hli] + or [hl] + inc hl + or [hl] + ret z + ld a, [wAmuletCoin] + and a + jr z, .okay + ld hl, wPayDayMoney + 2 + sla [hl] + dec hl + rl [hl] + dec hl + rl [hl] + jr nc, .okay + ld a, $ff + ld [hli], a + ld [hli], a + ld [hl], a + +.okay + ld hl, wPayDayMoney + 2 + ld de, Money + 2 + call AddBattleMoneyToAccount + ld hl, BattleText_PlayerPickedUpPayDayMoney + call StdBattleTextBox + ld a, [InBattleTowerBattle] + bit 0, a + ret z + call ClearTileMap + call ClearBGPalettes + ret +; 3f759 + +ShowLinkBattleParticipantsAfterEnd: ; 3f759 + farcall TrainerRankings_LinkBattles + farcall BackupMobileEventIndex + ld a, [CurOTMon] + ld hl, OTPartyMon1Status + call GetPartyLocation + ld a, [EnemyMonStatus] + ld [hl], a + call ClearTileMap + farcall _ShowLinkBattleParticipants + ret +; 3f77c + +DisplayLinkBattleResult: ; 3f77c + farcall CheckMobileBattleError + jp c, .Mobile_InvalidBattle + call IsMobileBattle2 + jr nz, .proceed + + ld hl, wcd2a + bit 4, [hl] + jr z, .proceed + + farcall DetermineLinkBattleResult + +.proceed + ld a, [wBattleResult] + and $f + cp $1 + jr c, .victory + jr z, .loss + farcall TrainerRankings_ColosseumDraws + ld de, .Draw + jr .store_result + +.victory + farcall TrainerRankings_ColosseumWins + ld de, .Win + jr .store_result + +.loss + farcall TrainerRankings_ColosseumLosses + ld de, .Lose + jr .store_result + +.store_result + hlcoord 6, 8 + call PlaceString + farcall BackupMobileEventIndex + ld c, 200 + call DelayFrames + + ld a, BANK(sLinkBattleStats) + call GetSRAMBank + + call AddLastMobileBattleToLinkRecord + call ReadAndPrintLinkBattleRecord + + call CloseSRAM + + call IsMobileBattle2 + jr z, .mobile + call WaitPressAorB_BlinkCursor + call ClearTileMap + ret + +.mobile + ld c, 200 + call DelayFrames + call ClearTileMap + ret +; 3f7f7 + +.Win: + db "YOU WIN@" +.Lose: + db "YOU LOSE@" +.Draw: + db " DRAW@" +; 3f80f + +.Mobile_InvalidBattle: ; 3f80f + hlcoord 6, 8 + ld de, .Invalid + call PlaceString + ld c, 200 + call DelayFrames + call ClearTileMap + ret +; 3f821 + +.Invalid: + db "INVALID BATTLE@" +; 3f830 + +IsMobileBattle2: ; 3f830 + ld a, [wLinkMode] + cp LINK_MOBILE + ret +; 3f836 + +DisplayLinkRecord: ; 3f836 + ld a, BANK(sLinkBattleStats) + call GetSRAMBank + + call ReadAndPrintLinkBattleRecord + + call CloseSRAM + hlcoord 0, 0, AttrMap + xor a + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + call ByteFill + call WaitBGMap2 + ld b, SCGB_DIPLOMA + call GetSGBLayout + call SetPalettes + ld c, 8 + call DelayFrames + call WaitPressAorB_BlinkCursor + ret +; 3f85f + +ReadAndPrintLinkBattleRecord: ; 3f85f + call ClearTileMap + call ClearSprites + call .PrintBattleRecord + hlcoord 0, 8 + ld b, 5 + ld de, sLinkBattleRecord + 2 +.loop + push bc + push hl + push de + ld a, [de] + and a + jr z, .PrintFormatString + ld a, [wSavedAtLeastOnce] + and a + jr z, .PrintFormatString + push hl + push hl + ld h, d + ld l, e + ld de, wd002 + ld bc, 10 + call CopyBytes + ld a, "@" + ld [de], a + inc de + ld bc, 6 + call CopyBytes + ld de, wd002 + pop hl + call PlaceString + pop hl + ld de, 26 + add hl, de + push hl + ld de, wd00d + lb bc, 2, 4 + call PrintNum + pop hl + ld de, 5 + add hl, de + push hl + ld de, wd00f + lb bc, 2, 4 + call PrintNum + pop hl + ld de, 5 + add hl, de + ld de, wd011 + lb bc, 2, 4 + call PrintNum + jr .next + +.PrintFormatString: + ld de, .Format + call PlaceString +.next + pop hl + ld bc, 18 + add hl, bc + ld d, h + ld e, l + pop hl + ld bc, 2 * SCREEN_WIDTH + add hl, bc + pop bc + dec b + jr nz, .loop + ret + +.PrintBattleRecord: + hlcoord 1, 0 + ld de, .Record + call PlaceString + + hlcoord 0, 6 + ld de, .Result + call PlaceString + + hlcoord 0, 2 + ld de, .Total + call PlaceString + + hlcoord 6, 4 + ld de, sLinkBattleWins + call .PrintZerosIfNoSaveFileExists + jr c, .quit + + lb bc, 2, 4 + call PrintNum + + hlcoord 11, 4 + ld de, sLinkBattleLosses + call .PrintZerosIfNoSaveFileExists + + lb bc, 2, 4 + call PrintNum + + hlcoord 16, 4 + ld de, sLinkBattleDraws + call .PrintZerosIfNoSaveFileExists + + lb bc, 2, 4 + call PrintNum + +.quit + ret + +.PrintZerosIfNoSaveFileExists: + ld a, [wSavedAtLeastOnce] + and a + ret nz + ld de, .Scores + call PlaceString + scf + ret +; 3f938 + +.Scores: + db " 0 0 0@" +; 3f947 + +.Format: ; 3f947 + db " --- <LNBRK>" + db " - - -@" +.Record: ; 3f964 + db "<PLAYER>'s RECORD@" +.Result: ; 3f96e + db "RESULT WIN LOSE DRAW@" +.Total: ; 3f983 + db "TOTAL WIN LOSE DRAW@" +; 3f998 + +BattleEnd_HandleRoamMons: ; 3f998 + ld a, [BattleType] + cp BATTLETYPE_ROAMING + jr nz, .not_roaming + ld a, [wBattleResult] + and $f + jr z, .caught_or_defeated_roam_mon + call GetRoamMonHP + ld a, [EnemyMonHP + 1] + ld [hl], a + jr .update_roam_mons + +.caught_or_defeated_roam_mon + call GetRoamMonHP + ld [hl], $0 + call GetRoamMonMapGroup + ld [hl], $ff + call GetRoamMonMapNumber + ld [hl], $ff + call GetRoamMonSpecies + ld [hl], $0 + ret + +.not_roaming + call BattleRandom + and $f + ret nz + +.update_roam_mons + callfar UpdateRoamMons + ret +; 3f9d1 + +GetRoamMonMapGroup: ; 3f9d1 + ld a, [TempEnemyMonSpecies] + ld b, a + ld a, [wRoamMon1Species] + cp b + ld hl, wRoamMon1MapGroup + ret z + ld a, [wRoamMon2Species] + cp b + ld hl, wRoamMon2MapGroup + ret z + ld hl, wRoamMon3MapGroup + ret +; 3f9e9 + +GetRoamMonMapNumber: ; 3f9e9 + ld a, [TempEnemyMonSpecies] + ld b, a + ld a, [wRoamMon1Species] + cp b + ld hl, wRoamMon1MapNumber + ret z + ld a, [wRoamMon2Species] + cp b + ld hl, wRoamMon2MapNumber + ret z + ld hl, wRoamMon3MapNumber + ret +; 3fa01 + +GetRoamMonHP: ; 3fa01 +; output: hl = wRoamMonHP + ld a, [TempEnemyMonSpecies] + ld b, a + ld a, [wRoamMon1Species] + cp b + ld hl, wRoamMon1HP + ret z + ld a, [wRoamMon2Species] + cp b + ld hl, wRoamMon2HP + ret z + ld hl, wRoamMon3HP + ret +; 3fa19 + +GetRoamMonDVs: ; 3fa19 +; output: hl = wRoamMonDVs + ld a, [TempEnemyMonSpecies] + ld b, a + ld a, [wRoamMon1Species] + cp b + ld hl, wRoamMon1DVs + ret z + ld a, [wRoamMon2Species] + cp b + ld hl, wRoamMon2DVs + ret z + ld hl, wRoamMon3DVs + ret +; 3fa31 + +GetRoamMonSpecies: ; 3fa31 + ld a, [TempEnemyMonSpecies] + ld hl, wRoamMon1Species + cp [hl] + ret z + ld hl, wRoamMon2Species + cp [hl] + ret z + ld hl, wRoamMon3Species + ret +; 3fa42 + +AddLastMobileBattleToLinkRecord: ; 3fa42 + ld hl, OTPlayerID + ld de, StringBuffer1 + ld bc, 2 + call CopyBytes + ld hl, OTPlayerName + ld bc, NAME_LENGTH - 1 + call CopyBytes + ld hl, sLinkBattleResults + call .StoreResult + ld hl, sLinkBattleRecord + ld d, 5 +.loop + push hl + inc hl + inc hl + ld a, [hl] + dec hl + dec hl + and a + jr z, .copy + push de + ld bc, 12 + ld de, StringBuffer1 + call CompareLong + pop de + pop hl + jr c, .done + ld bc, 18 + add hl, bc + dec d + jr nz, .loop + ld bc, -18 + add hl, bc + push hl + +.copy + ld d, h + ld e, l + ld hl, StringBuffer1 + ld bc, 12 + call CopyBytes + ld b, 6 + xor a +.loop2 + ld [de], a + inc de + dec b + jr nz, .loop2 + pop hl + +.done + call .StoreResult + call .FindOpponentAndAppendRecord + ret +; 3faa0 +.StoreResult: ; 3faa0 + ld a, [wBattleResult] + and $f + cp $1 + ld bc, sLinkBattleWins + 1 - sLinkBattleResults + jr c, .okay + ld bc, sLinkBattleLosses + 1 - sLinkBattleResults + jr z, .okay + ld bc, sLinkBattleDraws + 1 - sLinkBattleResults +.okay + add hl, bc + call .CheckOverflow + ret nc + inc [hl] + ret nz + dec hl + inc [hl] + ret +; 3fabe + +.CheckOverflow: ; 3fabe + dec hl + ld a, [hl] + inc hl + cp HIGH(MAX_LINK_RECORD) + ret c + ld a, [hl] + cp LOW(MAX_LINK_RECORD) + ret +; 3fac8 + +.FindOpponentAndAppendRecord: ; 3fac8 + ld b, 5 + ld hl, sLinkBattleRecord + 17 + ld de, wd002 +.loop3 + push bc + push de + push hl + call .LoadPointer + pop hl + ld a, e + pop de + ld [de], a + inc de + ld a, b + ld [de], a + inc de + ld a, c + ld [de], a + inc de + ld bc, 18 + add hl, bc + pop bc + dec b + jr nz, .loop3 + ld b, $0 + ld c, $1 +.loop4 + ld a, b + add b + add b + ld e, a + ld d, $0 + ld hl, wd002 + add hl, de + push hl + ld a, c + add c + add c + ld e, a + ld d, $0 + ld hl, wd002 + add hl, de + ld d, h + ld e, l + pop hl + push bc + ld c, 3 + call StringCmp + pop bc + jr z, .equal + jr nc, .done2 + +.equal + inc c + ld a, c + cp $5 + jr nz, .loop4 + inc b + ld c, b + inc c + ld a, b + cp $4 + jr nz, .loop4 + ret + +.done2 + push bc + ld a, b + ld bc, 18 + ld hl, sLinkBattleRecord + call AddNTimes + push hl + ld de, wd002 + ld bc, 18 + call CopyBytes + pop hl + pop bc + push hl + ld a, c + ld bc, 18 + ld hl, sLinkBattleRecord + call AddNTimes + pop de + push hl + ld bc, 18 + call CopyBytes + ld hl, wd002 + ld bc, 18 + pop de + call CopyBytes + ret +; 3fb54 + +.LoadPointer: ; 3fb54 + ld e, $0 + ld a, [hld] + ld c, a + ld a, [hld] + ld b, a + ld a, [hld] + add c + ld c, a + ld a, [hld] + adc b + ld b, a + jr nc, .okay2 + inc e + +.okay2 + ld a, [hld] + add c + ld c, a + ld a, [hl] + adc b + ld b, a + ret nc + inc e + ret +; 3fb6c + +InitBattleDisplay: ; 3fb6c + call .InitBackPic + hlcoord 0, 12 + ld b, 4 + ld c, 18 + call TextBox + farcall MobileTextBorder + hlcoord 1, 5 + lb bc, 3, 7 + call ClearBox + call LoadStandardFont + call _LoadBattleFontsHPBar + call .BlankBGMap + xor a + ld [hMapAnims], a + ld [hSCY], a + ld a, $90 + ld [hWY], a + ld [rWY], a + call WaitBGMap + xor a + ld [hBGMapMode], a + farcall BattleIntroSlidingPics + ld a, $1 + ld [hBGMapMode], a + ld a, $31 + ld [hGraphicStartTile], a + hlcoord 2, 6 + lb bc, 6, 6 + predef PlaceGraphic + xor a + ld [hWY], a + ld [rWY], a + call WaitBGMap + call HideSprites + ld b, SCGB_BATTLE_COLORS + call GetSGBLayout + call SetPalettes + ld a, $90 + ld [hWY], a + xor a + ld [hSCX], a + ret +; 3fbd6 + +.BlankBGMap: ; 3fbd6 + ld a, [rSVBK] + push af + ld a, $6 + ld [rSVBK], a + + ld hl, wDecompressScratch + ld bc, wScratchAttrMap - wDecompressScratch + ld a, " " + call ByteFill + + ld de, wDecompressScratch + hlbgcoord 0, 0 + lb bc, BANK(.BlankBGMap), $40 + call Request2bpp + + pop af + ld [rSVBK], a + ret +; 3fbf8 + +.InitBackPic: ; 3fbf8 + call GetTrainerBackpic + call CopyBackpic + ret +; 3fbff + +GetTrainerBackpic: ; 3fbff +; Load the player character's backpic (6x6) into VRAM starting from VTiles2 tile $31. + +; Special exception for Dude. + ld b, BANK(DudeBackpic) + ld hl, DudeBackpic + ld a, [BattleType] + cp BATTLETYPE_TUTORIAL + jr z, .Decompress + +; What gender are we? + ld a, [wPlayerSpriteSetupFlags] + bit 2, a ; transformed to male + jr nz, .Chris + ld a, [PlayerGender] + bit 0, a + jr z, .Chris + +; It's a girl. + farcall GetKrisBackpic + ret + +.Chris: +; It's a boy. + ld b, BANK(ChrisBackpic) + ld hl, ChrisBackpic + +.Decompress: + ld de, VTiles2 tile $31 + ld c, $31 + predef DecompressPredef + ret +; 3fc30 + +CopyBackpic: ; 3fc30 + ld a, [rSVBK] + push af + ld a, $6 + ld [rSVBK], a + ld hl, VTiles0 + ld de, VTiles2 tile $31 + ld a, [hROMBank] + ld b, a + ld c, $31 + call Get2bpp + pop af + ld [rSVBK], a + call .LoadTrainerBackpicAsOAM + ld a, $31 + ld [hGraphicStartTile], a + hlcoord 2, 6 + lb bc, 6, 6 + predef PlaceGraphic + ret +; 3fc5b + +.LoadTrainerBackpicAsOAM: ; 3fc5b + ld hl, Sprites + xor a + ld [hMapObjectIndexBuffer], a + ld b, $6 + ld e, 21 * 8 +.outer_loop + ld c, $3 + ld d, 8 * 8 +.inner_loop + ld [hl], d + inc hl + ld [hl], e + inc hl + ld a, [hMapObjectIndexBuffer] + ld [hli], a + inc a + ld [hMapObjectIndexBuffer], a + ld a, $1 + ld [hli], a + ld a, d + add $8 + ld d, a + dec c + jr nz, .inner_loop + ld a, [hMapObjectIndexBuffer] + add $3 + ld [hMapObjectIndexBuffer], a + ld a, e + add $8 + ld e, a + dec b + jr nz, .outer_loop + ret +; 3fc8b + +BattleStartMessage: ; 3fc8b + ld a, [wBattleMode] + dec a + jr z, .wild + + ld de, SFX_SHINE + call PlaySFX + call WaitSFX + + ld c, 20 + call DelayFrames + + farcall Battle_GetTrainerName + + ld hl, WantsToBattleText + jr .PlaceBattleStartText + +.wild + call BattleCheckEnemyShininess + jr nc, .not_shiny + + xor a + ld [wNumHits], a + ld a, 1 + ld [hBattleTurn], a + ld a, 1 + ld [wBattleAnimParam], a + ld de, ANIM_SEND_OUT_MON + call Call_PlayBattleAnim + +.not_shiny + farcall CheckSleepingTreeMon + jr c, .skip_cry + + farcall CheckBattleScene + jr c, .cry_no_anim + + hlcoord 12, 0 + ld d, $0 + ld e, ANIM_MON_NORMAL + predef AnimateFrontpic + jr .skip_cry ; cry is played during the animation + +.cry_no_anim + ld a, $0f + ld [CryTracks], a + ld a, [TempEnemyMonSpecies] + call PlayStereoCry + +.skip_cry + ld a, [BattleType] + cp BATTLETYPE_FISH + jr nz, .NotFishing + + farcall TrainerRankings_HookedEncounters + + ld hl, HookedPokemonAttackedText + jr .PlaceBattleStartText + +.NotFishing: + ld hl, PokemonFellFromTreeText + cp BATTLETYPE_TREE + jr z, .PlaceBattleStartText + ld hl, WildCelebiAppearedText + cp BATTLETYPE_CELEBI + jr z, .PlaceBattleStartText + ld hl, WildPokemonAppearedText + +.PlaceBattleStartText: + push hl + farcall BattleStart_TrainerHuds + pop hl + call StdBattleTextBox + + call IsMobileBattle2 + ret nz + + ld c, $2 ; start + farcall Mobile_PrintOpponentBattleMessage + + ret +; 3fd26 diff --git a/engine/battle/effect_commands.asm b/engine/battle/effect_commands.asm new file mode 100644 index 000000000..5922afea3 --- /dev/null +++ b/engine/battle/effect_commands.asm @@ -0,0 +1,10066 @@ +DoPlayerTurn: ; 34000 + call SetPlayerTurn + + ld a, [wPlayerAction] + and a + ret nz + + jr DoTurn + +; 3400a + + +DoEnemyTurn: ; 3400a + call SetEnemyTurn + + ld a, [wLinkMode] + and a + jr z, DoTurn + + ld a, [wBattleAction] + cp BATTLEACTION_E + jr z, DoTurn + cp BATTLEACTION_SWITCH1 + ret nc + + ; fallthrough +; 3401d + + +DoTurn: ; 3401d +; Read in and execute the user's move effects for this turn. + + xor a + ld [wTurnEnded], a + + ; Effect command checkturn is called for every move. + call CheckTurn + + ld a, [wTurnEnded] + and a + ret nz + + call UpdateMoveData +; 3402c + + +DoMove: ; 3402c +; Get the user's move effect. + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + ld c, a + ld b, 0 + ld hl, MoveEffectsPointers + add hl, bc + add hl, bc + ld a, BANK(MoveEffectsPointers) + call GetFarHalfword + + ld de, BattleScriptBuffer + +.GetMoveEffect: + ld a, BANK(MoveEffects) + call GetFarByte + inc hl + ld [de], a + inc de + cp $ff + jr nz, .GetMoveEffect + +; Start at the first command. + ld hl, BattleScriptBuffer + ld a, l + ld [BattleScriptBufferAddress], a + ld a, h + ld [BattleScriptBufferAddress + 1], a + +.ReadMoveEffectCommand: + +; ld a, [BattleScriptBufferAddress++] + ld a, [BattleScriptBufferAddress] + ld l, a + ld a, [BattleScriptBufferAddress + 1] + ld h, a + + ld a, [hli] + + push af + ld a, l + ld [BattleScriptBufferAddress], a + ld a, h + ld [BattleScriptBufferAddress + 1], a + pop af + +; endturn_command (-2) is used to terminate branches without ending the read cycle. + cp endturn_command + ret nc + +; The rest of the commands (01-af) are read from BattleCommandPointers. + push bc + dec a + ld c, a + ld b, 0 + ld hl, BattleCommandPointers + add hl, bc + add hl, bc + pop bc + + ld a, BANK(BattleCommandPointers) + call GetFarHalfword + + call .DoMoveEffectCommand + + jr .ReadMoveEffectCommand + +.DoMoveEffectCommand: + jp hl + +; 34084 + + +CheckTurn: +BattleCommand_CheckTurn: ; 34084 +; checkturn + +; Repurposed as hardcoded turn handling. Useless as a command. + +; Move $ff immediately ends the turn. + ld a, BATTLE_VARS_MOVE + call GetBattleVar + inc a + jp z, EndTurn + + xor a + ld [AttackMissed], a + ld [EffectFailed], a + ld [wKickCounter], a + ld [AlreadyDisobeyed], a + ld [AlreadyFailed], a + ld [wSomeoneIsRampaging], a + + ld a, 10 ; 1.0 + ld [TypeModifier], a + + ld a, [hBattleTurn] + and a + jp nz, CheckEnemyTurn + + +CheckPlayerTurn: + + ld hl, PlayerSubStatus4 + bit SUBSTATUS_RECHARGE, [hl] + jr z, .no_recharge + + res SUBSTATUS_RECHARGE, [hl] + ld hl, MustRechargeText + call StdBattleTextBox + call CantMove + jp EndTurn + +.no_recharge + + + ld hl, BattleMonStatus + ld a, [hl] + and SLP + jr z, .not_asleep + + dec a + ld [BattleMonStatus], a + and SLP + jr z, .woke_up + + xor a + ld [wNumHits], a + ld de, ANIM_SLP + call FarPlayBattleAnimation + jr .fast_asleep + +.woke_up + ld hl, WokeUpText + call StdBattleTextBox + call CantMove + call UpdateBattleMonInParty + ld hl, UpdatePlayerHUD + call CallBattleCore + ld a, $1 + ld [hBGMapMode], a + ld hl, PlayerSubStatus1 + res SUBSTATUS_NIGHTMARE, [hl] + jr .not_asleep + +.fast_asleep + ld hl, FastAsleepText + call StdBattleTextBox + + ; Snore and Sleep Talk bypass sleep. + ld a, [CurPlayerMove] + cp SNORE + jr z, .not_asleep + cp SLEEP_TALK + jr z, .not_asleep + + call CantMove + jp EndTurn + +.not_asleep + + + ld hl, BattleMonStatus + bit FRZ, [hl] + jr z, .not_frozen + + ; Flame Wheel and Sacred Fire thaw the user. + ld a, [CurPlayerMove] + cp FLAME_WHEEL + jr z, .not_frozen + cp SACRED_FIRE + jr z, .not_frozen + + ld hl, FrozenSolidText + call StdBattleTextBox + + call CantMove + jp EndTurn + +.not_frozen + + + ld hl, PlayerSubStatus3 + bit SUBSTATUS_FLINCHED, [hl] + jr z, .not_flinched + + res SUBSTATUS_FLINCHED, [hl] + ld hl, FlinchedText + call StdBattleTextBox + + call CantMove + jp EndTurn + +.not_flinched + + + ld hl, PlayerDisableCount + ld a, [hl] + and a + jr z, .not_disabled + + dec a + ld [hl], a + and $f + jr nz, .not_disabled + + ld [hl], a + ld [DisabledMove], a + ld hl, DisabledNoMoreText + call StdBattleTextBox + +.not_disabled + + + ld a, [PlayerSubStatus3] + add a + jr nc, .not_confused + ld hl, PlayerConfuseCount + dec [hl] + jr nz, .confused + + ld hl, PlayerSubStatus3 + res SUBSTATUS_CONFUSED, [hl] + ld hl, ConfusedNoMoreText + call StdBattleTextBox + jr .not_confused + +.confused + ld hl, IsConfusedText + call StdBattleTextBox + xor a + ld [wNumHits], a + ld de, ANIM_CONFUSED + call FarPlayBattleAnimation + + ; 50% chance of hitting itself + call BattleRandom + cp $80 + jr nc, .not_confused + + ; clear confusion-dependent substatus + ld hl, PlayerSubStatus3 + ld a, [hl] + and 1 << SUBSTATUS_CONFUSED + ld [hl], a + + call HitConfusion + call CantMove + jp EndTurn + +.not_confused + + + ld a, [PlayerSubStatus1] + add a ; bit SUBSTATUS_ATTRACT + jr nc, .not_infatuated + + ld hl, InLoveWithText + call StdBattleTextBox + xor a + ld [wNumHits], a + ld de, ANIM_IN_LOVE + call FarPlayBattleAnimation + + ; 50% chance of infatuation + call BattleRandom + cp $80 + jr c, .not_infatuated + + ld hl, InfatuationText + call StdBattleTextBox + call CantMove + jp EndTurn + +.not_infatuated + + + ; We can't disable a move that doesn't exist. + ld a, [DisabledMove] + and a + jr z, .no_disabled_move + + ; Are we using the disabled move? + ld hl, CurPlayerMove + cp [hl] + jr nz, .no_disabled_move + + call MoveDisabled + call CantMove + jp EndTurn + +.no_disabled_move + + + ld hl, BattleMonStatus + bit PAR, [hl] + ret z + + ; 25% chance to be fully paralyzed + call BattleRandom + cp $3f + ret nc + + ld hl, FullyParalyzedText + call StdBattleTextBox + call CantMove + jp EndTurn + +; 341f0 + + +CantMove: ; 341f0 + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + res SUBSTATUS_ROLLOUT, [hl] + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + ld a, [hl] + and $ff ^ (1<<SUBSTATUS_BIDE + 1<<SUBSTATUS_RAMPAGE + 1<<SUBSTATUS_CHARGED) + ld [hl], a + + call ResetFuryCutterCount + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp FLY + jr z, .fly_dig + + cp DIG + ret nz + +.fly_dig + res SUBSTATUS_UNDERGROUND, [hl] + res SUBSTATUS_FLYING, [hl] + jp AppearUserRaiseSub + +; 34216 + + + +OpponentCantMove: ; 34216 + call BattleCommand_SwitchTurn + call CantMove + jp BattleCommand_SwitchTurn + +; 3421f + + + +CheckEnemyTurn: ; 3421f + + ld hl, EnemySubStatus4 + bit SUBSTATUS_RECHARGE, [hl] + jr z, .no_recharge + + res SUBSTATUS_RECHARGE, [hl] + ld hl, MustRechargeText + call StdBattleTextBox + call CantMove + jp EndTurn + +.no_recharge + + + ld hl, EnemyMonStatus + ld a, [hl] + and SLP + jr z, .not_asleep + + dec a + ld [EnemyMonStatus], a + and a + jr z, .woke_up + + ld hl, FastAsleepText + call StdBattleTextBox + xor a + ld [wNumHits], a + ld de, ANIM_SLP + call FarPlayBattleAnimation + jr .fast_asleep + +.woke_up + ld hl, WokeUpText + call StdBattleTextBox + call CantMove + call UpdateEnemyMonInParty + ld hl, UpdateEnemyHUD + call CallBattleCore + ld a, $1 + ld [hBGMapMode], a + ld hl, EnemySubStatus1 + res SUBSTATUS_NIGHTMARE, [hl] + jr .not_asleep + +.fast_asleep + ; Snore and Sleep Talk bypass sleep. + ld a, [CurEnemyMove] + cp SNORE + jr z, .not_asleep + cp SLEEP_TALK + jr z, .not_asleep + call CantMove + jp EndTurn + +.not_asleep + + + ld hl, EnemyMonStatus + bit FRZ, [hl] + jr z, .not_frozen + ld a, [CurEnemyMove] + cp FLAME_WHEEL + jr z, .not_frozen + cp SACRED_FIRE + jr z, .not_frozen + + ld hl, FrozenSolidText + call StdBattleTextBox + call CantMove + jp EndTurn + +.not_frozen + + + ld hl, EnemySubStatus3 + bit SUBSTATUS_FLINCHED, [hl] + jr z, .not_flinched + + res SUBSTATUS_FLINCHED, [hl] + ld hl, FlinchedText + call StdBattleTextBox + + call CantMove + jp EndTurn + +.not_flinched + + + ld hl, EnemyDisableCount + ld a, [hl] + and a + jr z, .not_disabled + + dec a + ld [hl], a + and $f + jr nz, .not_disabled + + ld [hl], a + ld [EnemyDisabledMove], a + + ld hl, DisabledNoMoreText + call StdBattleTextBox + +.not_disabled + + + ld a, [EnemySubStatus3] + add a ; bit SUBSTATUS_CONFUSED + jr nc, .not_confused + + ld hl, EnemyConfuseCount + dec [hl] + jr nz, .confused + + ld hl, EnemySubStatus3 + res SUBSTATUS_CONFUSED, [hl] + ld hl, ConfusedNoMoreText + call StdBattleTextBox + jr .not_confused + + +.confused + ld hl, IsConfusedText + call StdBattleTextBox + + xor a + ld [wNumHits], a + ld de, ANIM_CONFUSED + call FarPlayBattleAnimation + + ; 50% chance of hitting itself + call BattleRandom + cp 1 + 50 percent + jr nc, .not_confused + + ; clear confusion-dependent substatus + ld hl, EnemySubStatus3 + ld a, [hl] + and 1 << SUBSTATUS_CONFUSED + ld [hl], a + + ld hl, HurtItselfText + call StdBattleTextBox + call HitSelfInConfusion + call BattleCommand_DamageCalc + call BattleCommand_LowerSub + xor a + ld [wNumHits], a + + ; Flicker the monster pic unless flying or underground. + ld de, ANIM_HIT_CONFUSION + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + call z, PlayFXAnimID + + ld c, $1 + call EnemyHurtItself + call BattleCommand_RaiseSub + call CantMove + jp EndTurn + +.not_confused + + + ld a, [EnemySubStatus1] + add a ; bit SUBSTATUS_ATTRACT + jr nc, .not_infatuated + + ld hl, InLoveWithText + call StdBattleTextBox + xor a + ld [wNumHits], a + ld de, ANIM_IN_LOVE + call FarPlayBattleAnimation + + ; 50% chance of infatuation + call BattleRandom + cp 1 + 50 percent + jr c, .not_infatuated + + ld hl, InfatuationText + call StdBattleTextBox + call CantMove + jp EndTurn + +.not_infatuated + + + ; We can't disable a move that doesn't exist. + ld a, [EnemyDisabledMove] + and a + jr z, .no_disabled_move + + ; Are we using the disabled move? + ld hl, CurEnemyMove + cp [hl] + jr nz, .no_disabled_move + + call MoveDisabled + + call CantMove + jp EndTurn + +.no_disabled_move + + + ld hl, EnemyMonStatus + bit PAR, [hl] + ret z + + ; 25% chance to be fully paralyzed + call BattleRandom + cp $3f + ret nc + + ld hl, FullyParalyzedText + call StdBattleTextBox + call CantMove + + ; fallthrough +; 34385 + + +EndTurn: ; 34385 + ld a, $1 + ld [wTurnEnded], a + jp ResetDamage + +; 3438d + + +MoveDisabled: ; 3438d + + ; Make sure any charged moves fail + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + res SUBSTATUS_CHARGED, [hl] + + ld a, BATTLE_VARS_MOVE + call GetBattleVar + ld [wNamedObjectIndexBuffer], a + call GetMoveName + + ld hl, DisabledMoveText + jp StdBattleTextBox + +; 343a5 + + +HitConfusion: ; 343a5 + + ld hl, HurtItselfText + call StdBattleTextBox + + xor a + ld [CriticalHit], a + + call HitSelfInConfusion + call BattleCommand_DamageCalc + call BattleCommand_LowerSub + + xor a + ld [wNumHits], a + + ; Flicker the monster pic unless flying or underground. + ld de, ANIM_HIT_CONFUSION + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + call z, PlayFXAnimID + + ld hl, UpdatePlayerHUD + call CallBattleCore + ld a, $1 + ld [hBGMapMode], a + ld c, $1 + call PlayerHurtItself + jp BattleCommand_RaiseSub + +; 343db + + +BattleCommand_CheckObedience: ; 343db +; checkobedience + + ; Enemy can't disobey + ld a, [hBattleTurn] + and a + ret nz + + call CheckUserIsCharging + ret nz + + ; If we've already checked this turn + ld a, [AlreadyDisobeyed] + and a + ret nz + + xor a + ld [AlreadyDisobeyed], a + + ; No obedience in link battles + ; (since no handling exists for enemy) + ld a, [wLinkMode] + and a + ret nz + + ld a, [InBattleTowerBattle] + and a + ret nz + + ; If the monster's id doesn't match the player's, + ; some conditions need to be met. + ld a, MON_ID + call BattlePartyAttr + + ld a, [PlayerID] + cp [hl] + jr nz, .obeylevel + inc hl + ld a, [PlayerID + 1] + cp [hl] + ret z + + +.obeylevel + ; The maximum obedience level is constrained by owned badges: + ld hl, JohtoBadges + + ; risingbadge + bit RISINGBADGE, [hl] + ld a, MAX_LEVEL + 1 + jr nz, .getlevel + + ; stormbadge + bit STORMBADGE, [hl] + ld a, 70 + jr nz, .getlevel + + ; fogbadge + bit FOGBADGE, [hl] + ld a, 50 + jr nz, .getlevel + + ; hivebadge + bit HIVEBADGE, [hl] + ld a, 30 + jr nz, .getlevel + + ; no badges + ld a, 10 + + +.getlevel +; c = obedience level +; d = monster level +; b = c + d + + ld b, a + ld c, a + + ld a, [BattleMonLevel] + ld d, a + + add b + ld b, a + +; No overflow (this should never happen) + jr nc, .checklevel + ld b, $ff + + +.checklevel +; If the monster's level is lower than the obedience level, it will obey. + ld a, c + cp d + ret nc + + +; Random number from 0 to obedience level + monster level +.rand1 + call BattleRandom + swap a + cp b + jr nc, .rand1 + +; The higher above the obedience level the monster is, +; the more likely it is to disobey. + cp c + ret c + +; Sleep-only moves have separate handling, and a higher chance of +; being ignored. Lazy monsters like their sleep. + call IgnoreSleepOnly + ret c + + +; Another random number from 0 to obedience level + monster level +.rand2 + call BattleRandom + cp b + jr nc, .rand2 + +; A second chance. + cp c + jr c, .UseInstead + + +; No hope of using a move now. + +; b = number of levels the monster is above the obedience level + ld a, d + sub c + ld b, a + +; The chance of napping is the difference out of 256. + call BattleRandom + swap a + sub b + jr c, .Nap + +; The chance of not hitting itself is the same. + cp b + jr nc, .DoNothing + + ld hl, WontObeyText + call StdBattleTextBox + call HitConfusion + jp .EndDisobedience + + +.Nap: + call BattleRandom + add a + swap a + and SLP + jr z, .Nap + + ld [BattleMonStatus], a + + ld hl, BeganToNapText + jr .Print + + +.DoNothing: + call BattleRandom + and 3 + + ld hl, LoafingAroundText + and a + jr z, .Print + + ld hl, WontObeyText + dec a + jr z, .Print + + ld hl, TurnedAwayText + dec a + jr z, .Print + + ld hl, IgnoredOrdersText + +.Print: + call StdBattleTextBox + jp .EndDisobedience + + +.UseInstead: + +; Can't use another move if the monster only has one! + ld a, [BattleMonMoves + 1] + and a + jr z, .DoNothing + +; Don't bother trying to handle Disable. + ld a, [DisabledMove] + and a + jr nz, .DoNothing + + + ld hl, BattleMonPP + ld de, BattleMonMoves + ld b, 0 + ld c, NUM_MOVES + +.GetTotalPP: + ld a, [hli] + and $3f ; exclude pp up + add b + ld b, a + + dec c + jr z, .CheckMovePP + +; Stop at undefined moves. + inc de + ld a, [de] + and a + jr nz, .GetTotalPP + + +.CheckMovePP: + ld hl, BattleMonPP + ld a, [CurMoveNum] + ld e, a + ld d, 0 + add hl, de + +; Can't use another move if only one move has PP. + ld a, [hl] + and $3f + cp b + jr z, .DoNothing + + +; Make sure we can actually use the move once we get there. + ld a, 1 + ld [AlreadyDisobeyed], a + + ld a, [w2DMenuNumRows] + ld b, a + +; Save the move we originally picked for afterward. + ld a, [CurMoveNum] + ld c, a + push af + + +.RandomMove: + call BattleRandom + and 3 ; TODO NUM_MOVES + + cp b + jr nc, .RandomMove + +; Not the move we were trying to use. + cp c + jr z, .RandomMove + +; Make sure it has PP. + ld [CurMoveNum], a + ld hl, BattleMonPP + ld e, a + ld d, 0 + add hl, de + ld a, [hl] + and $3f + jr z, .RandomMove + + +; Use it. + ld a, [CurMoveNum] + ld c, a + ld b, 0 + ld hl, BattleMonMoves + add hl, bc + ld a, [hl] + ld [CurPlayerMove], a + + call SetPlayerTurn + call UpdateMoveData + call DoMove + + +; Restore original move choice. + pop af + ld [CurMoveNum], a + + +.EndDisobedience: + xor a + ld [LastPlayerMove], a + ld [LastPlayerCounterMove], a + + ; Break Encore too. + ld hl, PlayerSubStatus5 + res SUBSTATUS_ENCORED, [hl] + xor a + ld [PlayerEncoreCount], a + + jp EndMoveEffect + +; 3451f + + +IgnoreSleepOnly: ; 3451f + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + + cp SNORE + jr z, .CheckSleep + cp SLEEP_TALK + jr z, .CheckSleep + and a + ret + +.CheckSleep: + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + ret z + +; 'ignored orders…sleeping!' + ld hl, IgnoredSleepingText + call StdBattleTextBox + + call EndMoveEffect + + scf + ret + +; 34541 + + +BattleCommand_UsedMoveText: ; 34541 +; usedmovetext + farcall DisplayUsedMoveText + ret + +; 34548 + + +CheckUserIsCharging: ; 34548 + + ld a, [hBattleTurn] + and a + ld a, [wPlayerCharging] ; player + jr z, .end + ld a, [wEnemyCharging] ; enemy +.end + and a + ret + +; 34555 + + +BattleCommand_DoTurn: ; 34555 + call CheckUserIsCharging + ret nz + + ld hl, BattleMonPP + ld de, PlayerSubStatus3 + ld bc, PlayerTurnsTaken + + ld a, [hBattleTurn] + and a + jr z, .proceed + + ld hl, EnemyMonPP + ld de, EnemySubStatus3 + ld bc, EnemyTurnsTaken + +.proceed + +; If we've gotten this far, this counts as a turn. + ld a, [bc] + inc a + ld [bc], a + + ld a, BATTLE_VARS_MOVE + call GetBattleVar + cp STRUGGLE + ret z + + ld a, [de] + and 1 << SUBSTATUS_IN_LOOP | 1 << SUBSTATUS_RAMPAGE | 1 << SUBSTATUS_BIDE + ret nz + + call .consume_pp + ld a, b + and a + jp nz, EndMoveEffect + + ; SubStatus5 + inc de + inc de + + ld a, [de] + bit SUBSTATUS_TRANSFORMED, a + ret nz + + ld a, [hBattleTurn] + and a + + ld hl, PartyMon1PP + ld a, [CurBattleMon] + jr z, .player + +; mimic this part entirely if wildbattle + ld a, [wBattleMode] + dec a + jr z, .wild + + ld hl, OTPartyMon1PP + ld a, [CurOTMon] + +.player + call GetPartyLocation + push hl + call CheckMimicUsed + pop hl + ret c + +.consume_pp + ld a, [hBattleTurn] + and a + ld a, [CurMoveNum] + jr z, .okay + ld a, [CurEnemyMoveNum] + +.okay + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + and $3f + jr z, .out_of_pp + dec [hl] + ld b, 0 + ret + +.wild + ld hl, EnemyMonMoves + ld a, [CurEnemyMoveNum] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + cp MIMIC + jr z, .mimic + ld hl, wWildMonMoves + add hl, bc + ld a, [hl] + cp MIMIC + ret z + +.mimic + ld hl, wWildMonPP + call .consume_pp + ret + +.out_of_pp + call BattleCommand_MoveDelay +; get move effect + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar +; continuous? + ld hl, .continuousmoves + ld de, 1 + call IsInArray + +; 'has no pp left for [move]' + ld hl, HasNoPPLeftText + jr c, .print +; 'but no pp is left for the move' + ld hl, NoPPLeftText +.print + call StdBattleTextBox + ld b, 1 + ret + +; 34602 + +.continuousmoves ; 34602 + db EFFECT_RAZOR_WIND + db EFFECT_SKY_ATTACK + db EFFECT_SKULL_BASH + db EFFECT_SOLARBEAM + db EFFECT_FLY + db EFFECT_ROLLOUT + db EFFECT_BIDE + db EFFECT_RAMPAGE + db $ff +; 3460b + +CheckMimicUsed: ; 3460b + ld a, [hBattleTurn] + and a + ld a, [CurMoveNum] + jr z, .player + ld a, [CurEnemyMoveNum] + +.player + ld c, a + ld a, MON_MOVES + call UserPartyAttr + + ld a, BATTLE_VARS_MOVE + call GetBattleVar + cp MIMIC + jr z, .mimic +; + ld b, 0 + add hl, bc + ld a, [hl] + cp MIMIC + jr nz, .mimic + + scf + ret + +.mimic + and a + ret + +; 34631 + + +BattleCommand_Critical: ; 34631 +; critical + +; Determine whether this attack's hit will be critical. + + xor a + ld [CriticalHit], a + + ld a, BATTLE_VARS_MOVE_POWER + call GetBattleVar + and a + ret z + + ld a, [hBattleTurn] + and a + ld hl, EnemyMonItem + ld a, [EnemyMonSpecies] + jr nz, .Item + ld hl, BattleMonItem + ld a, [BattleMonSpecies] + +.Item: + ld c, 0 + + cp CHANSEY + jr nz, .Farfetchd + ld a, [hl] + cp LUCKY_PUNCH + jr nz, .FocusEnergy + +; +2 critical level + ld c, 2 + jr .Tally + +.Farfetchd: + cp FARFETCH_D + jr nz, .FocusEnergy + ld a, [hl] + cp STICK + jr nz, .FocusEnergy + +; +2 critical level + ld c, 2 + jr .Tally + +.FocusEnergy: + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_FOCUS_ENERGY, a + jr z, .CheckCritical + +; +1 critical level + inc c + +.CheckCritical: + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld de, 1 + ld hl, .Criticals + push bc + call IsInArray + pop bc + jr nc, .ScopeLens + +; +2 critical level + inc c + inc c + +.ScopeLens: + push bc + call GetUserItem + ld a, b + cp HELD_CRITICAL_UP ; Increased critical chance. Only Scope Lens has this. + pop bc + jr nz, .Tally + +; +1 critical level + inc c + +.Tally: + ld hl, .Chances + ld b, 0 + add hl, bc + call BattleRandom + cp [hl] + ret nc + ld a, 1 + ld [CriticalHit], a + ret + +.Criticals: + db KARATE_CHOP, RAZOR_WIND, RAZOR_LEAF, CRABHAMMER, SLASH, AEROBLAST, CROSS_CHOP, $ff +.Chances: + ; 6.25% 12.1% 24.6% 33.2% 49.6% 49.6% 49.6% + db $11, $20, $40, $55, $80, $80, $80 + ; 0 1 2 3 4 5 6 +; 346b2 + + +BattleCommand_TripleKick: ; 346b2 +; triplekick + + ld a, [wKickCounter] + ld b, a + inc b + ld hl, CurDamage + 1 + ld a, [hld] + ld e, a + ld a, [hli] + ld d, a +.next_kick + dec b + ret z + ld a, [hl] + add e + ld [hld], a + ld a, [hl] + adc d + ld [hli], a + +; No overflow. + jr nc, .next_kick + ld a, $ff + ld [hld], a + ld [hl], a + ret + +; 346cd + + +BattleCommand_KickCounter: ; 346cd +; kickcounter + + ld hl, wKickCounter + inc [hl] + ret + +; 346d2 + + +BattleCommand_Stab: ; 346d2 +; STAB = Same Type Attack Bonus + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp STRUGGLE + ret z + + ld hl, BattleMonType1 + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, EnemyMonType1 + ld a, [hli] + ld d, a + ld e, [hl] + + ld a, [hBattleTurn] + and a + jr z, .go ; Who Attacks and who Defends + + ld hl, EnemyMonType1 + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, BattleMonType1 + ld a, [hli] + ld d, a + ld e, [hl] + +.go + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVarAddr + ld [wTypeMatchup], a + + push hl + push de + push bc + farcall DoWeatherModifiers + pop bc + pop de + pop hl + + push de + push bc + farcall DoBadgeTypeBoosts + pop bc + pop de + + ld a, [wTypeMatchup] + cp b + jr z, .stab + cp c + jr z, .stab + + jr .SkipStab + +.stab + ld hl, CurDamage + 1 + ld a, [hld] + ld h, [hl] + ld l, a + + ld b, h + ld c, l + srl b + rr c + add hl, bc + + ld a, h + ld [CurDamage], a + ld a, l + ld [CurDamage + 1], a + + ld hl, TypeModifier + set 7, [hl] + +.SkipStab: + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVar + ld b, a + ld hl, TypeMatchups + +.TypesLoop: + ld a, [hli] + + cp $ff + jr z, .end + + ; foresight + cp $fe + jr nz, .SkipForesightCheck + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVar + bit SUBSTATUS_IDENTIFIED, a + jr nz, .end + + jr .TypesLoop + +.SkipForesightCheck: + cp b + jr nz, .SkipType + ld a, [hl] + cp d + jr z, .GotMatchup + cp e + jr z, .GotMatchup + jr .SkipType + +.GotMatchup: + push hl + push bc + inc hl + ld a, [TypeModifier] + and %10000000 + ld b, a +; If the target is immune to the move, treat it as a miss and calculate the damage as 0 + ld a, [hl] + and a + jr nz, .NotImmune + inc a + ld [AttackMissed], a + xor a +.NotImmune: + ld [hMultiplier], a + add b + ld [TypeModifier], a + + xor a + ld [hMultiplicand + 0], a + + ld hl, CurDamage + ld a, [hli] + ld [hMultiplicand + 1], a + ld a, [hld] + ld [hMultiplicand + 2], a + + call Multiply + + ld a, [hProduct + 1] + ld b, a + ld a, [hProduct + 2] + or b + ld b, a + ld a, [hProduct + 3] + or b + jr z, .ok ; This is a very convoluted way to get back that we've essentially dealt no damage. + +; Take the product and divide it by 10. + ld a, 10 + ld [hDivisor], a + ld b, 4 + call Divide + ld a, [hQuotient + 1] + ld b, a + ld a, [hQuotient + 2] + or b + jr nz, .ok + + ld a, 1 + ld [hMultiplicand + 2], a + +.ok + ld a, [hMultiplicand + 1] + ld [hli], a + ld a, [hMultiplicand + 2] + ld [hl], a + pop bc + pop hl + +.SkipType: + inc hl + inc hl + jr .TypesLoop + +.end + call BattleCheckTypeMatchup + ld a, [wTypeMatchup] + ld b, a + ld a, [TypeModifier] + and %10000000 + or b + ld [TypeModifier], a + ret + +; 347c8 + + +BattleCheckTypeMatchup: ; 347c8 + ld hl, EnemyMonType1 + ld a, [hBattleTurn] + and a + jr z, CheckTypeMatchup + ld hl, BattleMonType1 +CheckTypeMatchup: ; 347d3 +; There is an incorrect assumption about this function made in the AI related code: when +; the AI calls CheckTypeMatchup (not BattleCheckTypeMatchup), it assumes that placing the +; offensive type in a will make this function do the right thing. Since a is overwritten, +; this assumption is incorrect. A simple fix would be to load the move type for the +; current move into a in BattleCheckTypeMatchup, before falling through, which is +; consistent with how the rest of the code assumes this code works like. + push hl + push de + push bc + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVar + ld d, a + ld b, [hl] + inc hl + ld c, [hl] + ld a, 10 ; 1.0 + ld [wTypeMatchup], a + ld hl, TypeMatchups +.TypesLoop: + ld a, [hli] + cp $ff + jr z, .End + cp $fe + jr nz, .Next + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVar + bit SUBSTATUS_IDENTIFIED, a + jr nz, .End + jr .TypesLoop + +.Next: + cp d + jr nz, .Nope + ld a, [hli] + cp b + jr z, .Yup + cp c + jr z, .Yup + jr .Nope2 + +.Nope: + inc hl +.Nope2: + inc hl + jr .TypesLoop + +.Yup: + xor a + ld [hDividend + 0], a + ld [hMultiplicand + 0], a + ld [hMultiplicand + 1], a + ld a, [hli] + ld [hMultiplicand + 2], a + ld a, [wTypeMatchup] + ld [hMultiplier], a + call Multiply + ld a, 10 + ld [hDivisor], a + push bc + ld b, 4 + call Divide + pop bc + ld a, [hQuotient + 2] + ld [wTypeMatchup], a + jr .TypesLoop + +.End: + pop bc + pop de + pop hl + ret + +; 34833 + + +BattleCommand_ResetTypeMatchup: ; 34833 +; Reset the type matchup multiplier to 1.0, if the type matchup is not 0. +; If there is immunity in play, the move automatically misses. + call BattleCheckTypeMatchup + ld a, [wTypeMatchup] + and a + ld a, 10 ; 1.0 + jr nz, .reset + call ResetDamage + xor a + ld [TypeModifier], a + inc a + ld [AttackMissed], a + ret + +.reset + ld [wTypeMatchup], a + ret + +; 3484e + +INCLUDE "engine/battle/ai/switch.asm" + +INCLUDE "data/type_matchups.asm" + +BattleCommand_DamageVariation: ; 34cfd +; damagevariation + +; Modify the damage spread between 85% and 100%. + +; Because of the method of division the probability distribution +; is not consistent. This makes the highest damage multipliers +; rarer than normal. + + +; No point in reducing 1 or 0 damage. + ld hl, CurDamage + ld a, [hli] + and a + jr nz, .go + ld a, [hl] + cp 2 + ret c + +.go +; Start with the maximum damage. + xor a + ld [hMultiplicand + 0], a + dec hl + ld a, [hli] + ld [hMultiplicand + 1], a + ld a, [hl] + ld [hMultiplicand + 2], a + +; Multiply by 85-100%... +.loop + call BattleRandom + rrca + cp $d9 ; 85% + jr c, .loop + + ld [hMultiplier], a + call Multiply + +; ...divide by 100%... + ld a, $ff ; 100% + ld [hDivisor], a + ld b, $4 + call Divide + +; ...to get .85-1.00x damage. + ld a, [hQuotient + 1] + ld hl, CurDamage + ld [hli], a + ld a, [hQuotient + 2] + ld [hl], a + ret + +; 34d32 + + +BattleCommand_CheckHit: ; 34d32 +; checkhit + + call .DreamEater + jp z, .Miss + + call .Protect + jp nz, .Miss + + call .DrainSub + jp z, .Miss + + call .LockOn + ret nz + + call .FlyDigMoves + jp nz, .Miss + + call .ThunderRain + ret z + + call .XAccuracy + ret nz + + ; Perfect-accuracy moves + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_ALWAYS_HIT + ret z + + call .StatModifiers + + ld a, [wPlayerMoveStruct + MOVE_ACC] + ld b, a + ld a, [hBattleTurn] + and a + jr z, .BrightPowder + ld a, [wEnemyMoveStruct + MOVE_ACC] + ld b, a + +.BrightPowder: + push bc + call GetOpponentItem + ld a, b + cp HELD_BRIGHTPOWDER + ld a, c ; % miss + pop bc + jr nz, .skip_brightpowder + + ld c, a + ld a, b + sub c + ld b, a + jr nc, .skip_brightpowder + ld b, 0 + +.skip_brightpowder + ld a, b + cp $ff + jr z, .Hit + + call BattleRandom + cp b + jr nc, .Miss + +.Hit: + ret + + +.Miss: +; Keep the damage value intact if we're using (Hi) Jump Kick. + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_JUMP_KICK + jr z, .Missed + call ResetDamage + +.Missed: + ld a, 1 + ld [AttackMissed], a + ret + + +.DreamEater: +; Return z if we're trying to eat the dream of +; a monster that isn't sleeping. + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_DREAM_EATER + ret nz + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVar + and SLP + ret + + +.Protect: +; Return nz if the opponent is protected. + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVar + bit SUBSTATUS_PROTECT, a + ret z + + ld c, 40 + call DelayFrames + +; 'protecting itself!' + ld hl, ProtectingItselfText + call StdBattleTextBox + + ld c, 40 + call DelayFrames + + ld a, 1 + and a + ret + + +.LockOn: +; Return nz if we are locked-on and aren't trying to use Earthquake, +; Fissure or Magnitude on a monster that is flying. + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + bit SUBSTATUS_LOCK_ON, [hl] + res SUBSTATUS_LOCK_ON, [hl] + ret z + + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + bit SUBSTATUS_FLYING, a + jr z, .LockedOn + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + + cp EARTHQUAKE + ret z + cp FISSURE + ret z + cp MAGNITUDE + ret z + +.LockedOn: + ld a, 1 + and a + ret + + +.DrainSub: +; Return z if using an HP drain move on a substitute. + call CheckSubstituteOpp + jr z, .not_draining_sub + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + + cp EFFECT_LEECH_HIT + ret z + cp EFFECT_DREAM_EATER + ret z + +.not_draining_sub + ld a, 1 + and a + ret + + +.FlyDigMoves: +; Check for moves that can hit underground/flying opponents. +; Return z if the current move can hit the opponent. + + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret z + + bit SUBSTATUS_FLYING, a + jr z, .DigMoves + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + + cp GUST + ret z + cp WHIRLWIND + ret z + cp THUNDER + ret z + cp TWISTER + ret + +.DigMoves: + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + + cp EARTHQUAKE + ret z + cp FISSURE + ret z + cp MAGNITUDE + ret + + +.ThunderRain: +; Return z if the current move always hits in rain, and it is raining. + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_THUNDER + ret nz + + ld a, [Weather] + cp WEATHER_RAIN + ret + + +.XAccuracy: + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_X_ACCURACY, a + ret + + +.StatModifiers: + + ld a, [hBattleTurn] + and a + + ; load the user's accuracy into b and the opponent's evasion into c. + ld hl, wPlayerMoveStruct + MOVE_ACC + ld a, [PlayerAccLevel] + ld b, a + ld a, [EnemyEvaLevel] + ld c, a + + jr z, .got_acc_eva + + ld hl, wEnemyMoveStruct + MOVE_ACC + ld a, [EnemyAccLevel] + ld b, a + ld a, [PlayerEvaLevel] + ld c, a + +.got_acc_eva + cp b + jr c, .skip_foresight_check + + ; if the target's evasion is greater than the user's accuracy, + ; check the target's foresight status + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVar + bit SUBSTATUS_IDENTIFIED, a + ret nz + +.skip_foresight_check + ; subtract evasion from 14 + ld a, 14 + sub c + ld c, a + ; store the base move accuracy for math ops + xor a + ld [hMultiplicand + 0], a + ld [hMultiplicand + 1], a + ld a, [hl] + ld [hMultiplicand + 2], a + push hl + ld d, 2 ; do this twice, once for the user's accuracy and once for the target's evasion + +.accuracy_loop + ; look up the multiplier from the table + push bc + ld hl, .AccProb + dec b + sla b + ld c, b + ld b, 0 + add hl, bc + pop bc + ; multiply by the first byte in that row... + ld a, [hli] + ld [hMultiplier], a + call Multiply + ; ... and divide by the second byte + ld a, [hl] + ld [hDivisor], a + ld b, 4 + call Divide + ; minimum accuracy is $0001 + ld a, [hQuotient + 2] + ld b, a + ld a, [hQuotient + 1] + or b + jr nz, .min_accuracy + ld [hQuotient + 1], a + ld a, 1 + ld [hQuotient + 2], a + +.min_accuracy + ; do the same thing to the target's evasion + ld b, c + dec d + jr nz, .accuracy_loop + + ; if the result is more than 2 bytes, max out at 100% + ld a, [hQuotient + 1] + and a + ld a, [hQuotient + 2] + jr z, .finish_accuracy + ld a, $ff + +.finish_accuracy + pop hl + ld [hl], a + ret + +.AccProb: + db 33, 100 ; 33% -6 + db 36, 100 ; 36% -5 + db 43, 100 ; 43% -4 + db 50, 100 ; 50% -3 + db 60, 100 ; 60% -2 + db 75, 100 ; 75% -1 + db 1, 1 ; 100% 0 + db 133, 100 ; 133% +1 + db 166, 100 ; 166% +2 + db 2, 1 ; 200% +3 + db 233, 100 ; 233% +4 + db 133, 50 ; 266% +5 + db 3, 1 ; 300% +6 + +; 34ecc + + +BattleCommand_EffectChance: ; 34ecc +; effectchance + + xor a + ld [EffectFailed], a + call CheckSubstituteOpp + jr nz, .failed + + push hl + ld hl, wPlayerMoveStruct + MOVE_CHANCE + ld a, [hBattleTurn] + and a + jr z, .got_move_chance + ld hl, wEnemyMoveStruct + MOVE_CHANCE +.got_move_chance + + call BattleRandom + cp [hl] + pop hl + ret c + +.failed + ld a, 1 + ld [EffectFailed], a + and a + ret + +; 34eee + + +BattleCommand_LowerSub: ; 34eee +; lowersub + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + ret z + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + bit SUBSTATUS_CHARGED, a + jr nz, .already_charged + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_RAZOR_WIND + jr z, .charge_turn + cp EFFECT_SKY_ATTACK + jr z, .charge_turn + cp EFFECT_SKULL_BASH + jr z, .charge_turn + cp EFFECT_SOLARBEAM + jr z, .charge_turn + cp EFFECT_FLY + jr z, .charge_turn + +.already_charged + call .Rampage + jr z, .charge_turn + + call CheckUserIsCharging + ret nz + +.charge_turn + call _CheckBattleScene + jr c, .mimic_anims + + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + inc a + ld [wKickCounter], a + ld a, SUBSTITUTE + jp LoadAnim + +.mimic_anims + call BattleCommand_LowerSubNoAnim + jp BattleCommand_MoveDelay + +.Rampage: + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_ROLLOUT + jr z, .rollout_rampage + cp EFFECT_RAMPAGE + jr z, .rollout_rampage + + ld a, 1 + and a + ret + +.rollout_rampage + ld a, [wSomeoneIsRampaging] + and a + ld a, 0 + ld [wSomeoneIsRampaging], a + ret + +; 34f57 + + +BattleCommand_HitTarget: ; 34f57 +; hittarget + call BattleCommand_LowerSub + call BattleCommand_HitTargetNoSub + jp BattleCommand_RaiseSub + +; 34f60 + + +BattleCommand_HitTargetNoSub: ; 34f60 + ld a, [AttackMissed] + and a + jp nz, BattleCommand_MoveDelay + + ld a, [hBattleTurn] + and a + ld de, PlayerRolloutCount + ld a, BATTLEANIM_ENEMY_DAMAGE + jr z, .got_rollout_count + ld de, EnemyRolloutCount + ld a, BATTLEANIM_PLAYER_DAMAGE + +.got_rollout_count + ld [wNumHits], a + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_MULTI_HIT + jr z, .multihit + cp EFFECT_CONVERSION + jr z, .conversion + cp EFFECT_DOUBLE_HIT + jr z, .doublehit + cp EFFECT_POISON_MULTI_HIT + jr z, .twineedle + cp EFFECT_TRIPLE_KICK + jr z, .triplekick + xor a + ld [wKickCounter], a + +.triplekick + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld e, a + ld d, 0 + call PlayFXAnimID + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp FLY + jr z, .fly_dig + cp DIG + ret nz + +.fly_dig +; clear sprite + jp AppearUserLowerSub + +.multihit +.conversion +.doublehit +.twineedle + ld a, [wKickCounter] + and 1 + xor 1 + ld [wKickCounter], a + ld a, [de] + cp $1 + push af + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld e, a + ld d, 0 + pop af + jp z, PlayFXAnimID + xor a + ld [wNumHits], a + jp PlayFXAnimID + +; 34fd1 + + +BattleCommand_StatUpAnim: ; 34fd1 + ld a, [AttackMissed] + and a + jp nz, BattleCommand_MoveDelay + + xor a + jr BattleCommand_StatUpDownAnim + +; 34fdb + + +BattleCommand_StatDownAnim: ; 34fdb + ld a, [AttackMissed] + and a + jp nz, BattleCommand_MoveDelay + + ld a, [hBattleTurn] + and a + ld a, BATTLEANIM_ENEMY_STAT_DOWN + jr z, BattleCommand_StatUpDownAnim + ld a, BATTLEANIM_WOBBLE + + ; fallthrough +; 34feb + + +BattleCommand_StatUpDownAnim: ; 34feb + ld [wNumHits], a + xor a + ld [wKickCounter], a + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld e, a + ld d, 0 + jp PlayFXAnimID + +; 34ffd + + +BattleCommand_SwitchTurn: ; 34ffd +; switchturn + + ld a, [hBattleTurn] + xor 1 + ld [hBattleTurn], a + ret + +; 35004 + + +BattleCommand_RaiseSub: ; 35004 +; raisesub + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + ret z + + call _CheckBattleScene + jp c, BattleCommand_RaiseSubNoAnim + + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + ld a, $2 + ld [wKickCounter], a + ld a, SUBSTITUTE + jp LoadAnim + +; 35023 + + +BattleCommand_FailureText: ; 35023 +; failuretext +; If the move missed or failed, load the appropriate +; text, and end the effects of multi-turn or multi- +; hit moves. + ld a, [AttackMissed] + and a + ret z + + call GetFailureResultText + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVarAddr + + cp FLY + jr z, .fly_dig + cp DIG + jr z, .fly_dig + +; Move effect: + inc hl + ld a, [hl] + + cp EFFECT_MULTI_HIT + jr z, .multihit + cp EFFECT_DOUBLE_HIT + jr z, .multihit + cp EFFECT_POISON_MULTI_HIT + jr z, .multihit + jp EndMoveEffect + +.multihit + call BattleCommand_RaiseSub + jp EndMoveEffect + +.fly_dig + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + res SUBSTATUS_UNDERGROUND, [hl] + res SUBSTATUS_FLYING, [hl] + call AppearUserRaiseSub + jp EndMoveEffect + +; 3505e + + +BattleCommand_CheckFaint: ; 3505e +; checkfaint + + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVar + bit SUBSTATUS_ENDURE, a + jr z, .not_enduring + call BattleCommand_FalseSwipe + ld b, $0 + jr nc, .okay + ld b, $1 + jr .okay + +.not_enduring + call GetOpponentItem + ld a, b + cp HELD_FOCUS_BAND + ld b, $0 + jr nz, .okay + call BattleRandom + cp c + jr nc, .okay + call BattleCommand_FalseSwipe + ld b, $0 + jr nc, .okay + ld b, $2 +.okay + push bc + call .check_sub + ld c, $0 + ld a, [hBattleTurn] + and a + jr nz, .damage_player + call EnemyHurtItself + jr .done_damage + +.damage_player + call PlayerHurtItself + +.done_damage + pop bc + ld a, b + and a + ret z + dec a + jr nz, .not_enduring2 + ld hl, EnduredText + jp StdBattleTextBox + +.not_enduring2 + call GetOpponentItem + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetItemName + + ld hl, HungOnText + jp StdBattleTextBox + +.check_sub + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + ret nz + + ld de, PlayerDamageTaken + 1 + ld a, [hBattleTurn] + and a + jr nz, .damage_taken + ld de, EnemyDamageTaken + 1 + +.damage_taken + ld a, [CurDamage + 1] + ld b, a + ld a, [de] + add b + ld [de], a + dec de + ld a, [CurDamage] + ld b, a + ld a, [de] + adc b + ld [de], a + ret nc + ld a, $ff + ld [de], a + inc de + ld [de], a + ret + +; 350e4 + + +GetFailureResultText: ; 350e4 + ld hl, DoesntAffectText + ld de, DoesntAffectText + ld a, [TypeModifier] + and $7f + jr z, .got_text + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_FUTURE_SIGHT + ld hl, ButItFailedText + ld de, ItFailedText + jr z, .got_text + ld hl, AttackMissedText + ld de, AttackMissed2Text + ld a, [CriticalHit] + cp $ff + jr nz, .got_text + ld hl, UnaffectedText +.got_text + call FailText_CheckOpponentProtect + xor a + ld [CriticalHit], a + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_JUMP_KICK + ret nz + + ld a, [TypeModifier] + and $7f + ret z + + ld hl, CurDamage + ld a, [hli] + ld b, [hl] + rept 3 + srl a + rr b + endr + ld [hl], b + dec hl + ld [hli], a + or b + jr nz, .do_at_least_1_damage + inc a + ld [hl], a +.do_at_least_1_damage + ld hl, CrashedText + call StdBattleTextBox + ld a, $1 + ld [wKickCounter], a + call LoadMoveAnim + ld c, $1 + ld a, [hBattleTurn] + and a + jp nz, EnemyHurtItself + jp PlayerHurtItself + +FailText_CheckOpponentProtect: ; 35157 + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVar + bit SUBSTATUS_PROTECT, a + jr z, .not_protected + ld h, d + ld l, e +.not_protected + jp StdBattleTextBox + +; 35165 + + +BattleCommanda5: ; 35165 + ld a, [AttackMissed] + and a + ret z + + ld a, [TypeModifier] + and $7f + jp z, PrintDoesntAffect + jp PrintButItFailed + +; 35175 + + +BattleCommand_CriticalText: ; 35175 +; criticaltext +; Prints the message for critical hits or one-hit KOs. + +; If there is no message to be printed, wait 20 frames. + ld a, [CriticalHit] + and a + jr z, .wait + + dec a + add a + ld hl, .texts + ld b, 0 + ld c, a + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + call StdBattleTextBox + + xor a + ld [CriticalHit], a + +.wait + ld c, 20 + jp DelayFrames + +.texts + dw CriticalHitText + dw OneHitKOText +; 35197 + + +BattleCommand_StartLoop: ; 35197 +; startloop + + ld hl, PlayerRolloutCount + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyRolloutCount +.ok + xor a + ld [hl], a + ret + +; 351a5 + + +BattleCommand_SuperEffectiveLoopText: ; 351a5 +; supereffectivelooptext + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + bit SUBSTATUS_IN_LOOP, a + ret nz + + ; fallthrough +; 351ad + + +BattleCommand_SuperEffectiveText: ; 351ad +; supereffectivetext + + ld a, [TypeModifier] + and $7f + cp 10 ; 1.0 + ret z + ld hl, SuperEffectiveText + jr nc, .print + ld hl, NotVeryEffectiveText +.print + jp StdBattleTextBox + +; 351c0 + + +BattleCommand_CheckDestinyBond: ; 351c0 +; checkdestinybond + +; Faint the user if it fainted an opponent using Destiny Bond. + + ld hl, EnemyMonHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, BattleMonHP + +.got_hp + ld a, [hli] + or [hl] + ret nz + + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVar + bit SUBSTATUS_DESTINY_BOND, a + jr z, .no_dbond + + ld hl, TookDownWithItText + call StdBattleTextBox + + ld a, [hBattleTurn] + and a + ld hl, EnemyMonMaxHP + 1 + bccoord 2, 2 ; hp bar + ld a, 0 + jr nz, .got_max_hp + ld hl, BattleMonMaxHP + 1 + bccoord 10, 9 ; hp bar + ld a, 1 + +.got_max_hp + ld [wWhichHPBar], a + ld a, [hld] + ld [Buffer1], a + ld a, [hld] + ld [Buffer2], a + ld a, [hl] + ld [Buffer3], a + xor a + ld [hld], a + ld a, [hl] + ld [Buffer4], a + xor a + ld [hl], a + ld [Buffer5], a + ld [Buffer6], a + ld h, b + ld l, c + predef AnimateHPBar + call RefreshBattleHuds + + call BattleCommand_SwitchTurn + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + inc a + ld [wKickCounter], a + ld a, DESTINY_BOND + call LoadAnim + call BattleCommand_SwitchTurn + + jr .finish + +.no_dbond + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_MULTI_HIT + jr z, .multiple_hit_raise_sub + cp EFFECT_DOUBLE_HIT + jr z, .multiple_hit_raise_sub + cp EFFECT_POISON_MULTI_HIT + jr z, .multiple_hit_raise_sub + cp EFFECT_TRIPLE_KICK + jr z, .multiple_hit_raise_sub + cp EFFECT_BEAT_UP + jr nz, .finish + +.multiple_hit_raise_sub + call BattleCommand_RaiseSub + +.finish + jp EndMoveEffect + +; 35250 + + +BattleCommand_BuildOpponentRage: ; 35250 +; buildopponentrage + + jp .start + +.start + ld a, [AttackMissed] + and a + ret nz + + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVar + bit SUBSTATUS_RAGE, a + ret z + + ld de, wEnemyRageCounter + ld a, [hBattleTurn] + and a + jr z, .player + ld de, wPlayerRageCounter +.player + ld a, [de] + inc a + ret z + ld [de], a + + call BattleCommand_SwitchTurn + ld hl, RageBuildingText + call StdBattleTextBox + jp BattleCommand_SwitchTurn + +; 3527b + + +BattleCommand_RageDamage: ; 3527b +; ragedamage + + ld a, [CurDamage] + ld h, a + ld b, a + ld a, [CurDamage + 1] + ld l, a + ld c, a + ld a, [hBattleTurn] + and a + ld a, [wPlayerRageCounter] + jr z, .rage_loop + ld a, [wEnemyRageCounter] +.rage_loop + and a + jr z, .done + dec a + add hl, bc + jr nc, .rage_loop + ld hl, -1 +.done + ld a, h + ld [CurDamage], a + ld a, l + ld [CurDamage + 1], a + ret + +; 352a3 + + +EndMoveEffect: ; 352a3 + ld a, [BattleScriptBufferAddress] + ld l, a + ld a, [BattleScriptBufferAddress + 1] + ld h, a + ld a, $ff + ld [hli], a + ld [hli], a + ld [hl], a + ret + +; 352b1 + + +DittoMetalPowder: ; 352b1 + ld a, MON_SPECIES + call BattlePartyAttr + ld a, [hBattleTurn] + and a + ld a, [hl] + jr nz, .Ditto + ld a, [TempEnemyMonSpecies] + +.Ditto: + cp DITTO + ret nz + + push bc + call GetOpponentItem + ld a, [hl] + cp METAL_POWDER + pop bc + ret nz + + ld a, c + srl a + add c + ld c, a + ret nc + + srl b + ld a, b + and a + jr nz, .done + inc b +.done + scf + rr c + ret + +; 352dc + + +BattleCommand_DamageStats: ; 352dc +; damagestats + + ld a, [hBattleTurn] + and a + jp nz, EnemyAttackDamage + + ; fallthrough +; 352e2 + + +PlayerAttackDamage: ; 352e2 +; Return move power d, player level e, enemy defense c and player attack b. + + call ResetDamage + + ld hl, wPlayerMoveStructPower + ld a, [hli] + and a + ld d, a + ret z + + ld a, [hl] + cp SPECIAL + jr nc, .special + +.physical + ld hl, EnemyMonDefense + ld a, [hli] + ld b, a + ld c, [hl] + + ld a, [EnemyScreens] + bit SCREENS_REFLECT, a + jr z, .physicalcrit + sla c + rl b + +.physicalcrit + ld hl, BattleMonAttack + call GetDamageStatsCritical + jr c, .thickclub + + ld hl, EnemyDefense + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, PlayerAttack + jr .thickclub + +.special + ld hl, EnemyMonSpclDef + ld a, [hli] + ld b, a + ld c, [hl] + + ld a, [EnemyScreens] + bit SCREENS_LIGHT_SCREEN, a + jr z, .specialcrit + sla c + rl b + +.specialcrit + ld hl, BattleMonSpclAtk + call GetDamageStatsCritical + jr c, .lightball + + ld hl, EnemySpDef + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, PlayerSpAtk + +.lightball +; Note: Returns player special attack at hl in hl. + call LightBallBoost + jr .done + +.thickclub +; Note: Returns player attack at hl in hl. + call ThickClubBoost + +.done + call TruncateHL_BC + + ld a, [BattleMonLevel] + ld e, a + call DittoMetalPowder + + ld a, 1 + and a + ret + +; 3534d + + +TruncateHL_BC: ; 3534d +.loop +; Truncate 16-bit values hl and bc to 8-bit values b and c respectively. +; b = hl, c = bc + + ld a, h + or b + jr z, .finish + + srl b + rr c + srl b + rr c + + ld a, c + or b + jr nz, .done_bc + inc c + +.done_bc + srl h + rr l + srl h + rr l + + ld a, l + or h + jr nz, .finish + inc l + +.finish + ld a, [wLinkMode] + cp 3 + jr z, .done +; If we go back to the loop point, +; it's the same as doing this exact +; same check twice. + ld a, h + or b + jr nz, .loop + +.done + ld b, l + ret + +; 35378 + + +GetDamageStatsCritical: ; 35378 +; Return carry if non-critical. + + ld a, [CriticalHit] + and a + scf + ret z + + ; fallthrough +; 3537e + + +GetDamageStats: ; 3537e +; Return the attacker's offensive stat and the defender's defensive +; stat based on whether the attacking type is physical or special. + + push hl + push bc + ld a, [hBattleTurn] + and a + jr nz, .enemy + ld a, [wPlayerMoveStructType] + cp SPECIAL +; special + ld a, [PlayerSAtkLevel] + ld b, a + ld a, [EnemySDefLevel] + jr nc, .end +; physical + ld a, [PlayerAtkLevel] + ld b, a + ld a, [EnemyDefLevel] + jr .end + +.enemy + ld a, [wEnemyMoveStructType] + cp SPECIAL +; special + ld a, [EnemySAtkLevel] + ld b, a + ld a, [PlayerSDefLevel] + jr nc, .end +; physical + ld a, [EnemyAtkLevel] + ld b, a + ld a, [PlayerDefLevel] +.end + cp b + pop bc + pop hl + ret + +; 353b5 + + +ThickClubBoost: ; 353b5 +; Return in hl the stat value at hl. + +; If the attacking monster is Cubone or Marowak and +; it's holding a Thick Club, double it. + push bc + push de + ld b, CUBONE + ld c, MAROWAK + ld d, THICK_CLUB + call SpeciesItemBoost + pop de + pop bc + ret + +; 353c3 + + +LightBallBoost: ; 353c3 +; Return in hl the stat value at hl. + +; If the attacking monster is Pikachu and it's +; holding a Light Ball, double it. + push bc + push de + ld b, PIKACHU + ld c, PIKACHU + ld d, LIGHT_BALL + call SpeciesItemBoost + pop de + pop bc + ret + +; 353d1 + + +SpeciesItemBoost: ; 353d1 +; Return in hl the stat value at hl. + +; If the attacking monster is species b or c and +; it's holding item d, double it. + + ld a, [hli] + ld l, [hl] + ld h, a + + push hl + ld a, MON_SPECIES + call BattlePartyAttr + + ld a, [hBattleTurn] + and a + ld a, [hl] + jr z, .CompareSpecies + ld a, [TempEnemyMonSpecies] +.CompareSpecies: + pop hl + + cp b + jr z, .GetItemHeldEffect + cp c + ret nz + +.GetItemHeldEffect: + push hl + call GetUserItem + ld a, [hl] + pop hl + cp d + ret nz + +; Double the stat + sla l + rl h + ret + +; 353f6 + + +EnemyAttackDamage: ; 353f6 + call ResetDamage + +; No damage dealt with 0 power. + ld hl, wEnemyMoveStructPower + ld a, [hli] ; hl = wEnemyMoveStructType + ld d, a + and a + ret z + + ld a, [hl] + cp SPECIAL + jr nc, .Special + +.physical + ld hl, BattleMonDefense + ld a, [hli] + ld b, a + ld c, [hl] + + ld a, [PlayerScreens] + bit SCREENS_REFLECT, a + jr z, .physicalcrit + sla c + rl b + +.physicalcrit + ld hl, EnemyMonAttack + call GetDamageStatsCritical + jr c, .thickclub + + ld hl, PlayerDefense + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, EnemyAttack + jr .thickclub + +.Special: + ld hl, BattleMonSpclDef + ld a, [hli] + ld b, a + ld c, [hl] + + ld a, [PlayerScreens] + bit SCREENS_LIGHT_SCREEN, a + jr z, .specialcrit + sla c + rl b + +.specialcrit + ld hl, EnemyMonSpclAtk + call GetDamageStatsCritical + jr c, .lightball + ld hl, PlayerSpDef + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, EnemySpAtk + +.lightball + call LightBallBoost + jr .done + +.thickclub + call ThickClubBoost + +.done + call TruncateHL_BC + + ld a, [EnemyMonLevel] + ld e, a + call DittoMetalPowder + + ld a, 1 + and a + ret + +; 35461 + + +BattleCommand_BeatUp: ; 35461 +; beatup + + call ResetDamage + ld a, [hBattleTurn] + and a + jp nz, .enemy_beats_up + ld a, [PlayerSubStatus3] + bit SUBSTATUS_IN_LOOP, a + jr nz, .next_mon + ld c, 20 + call DelayFrames + xor a + ld [PlayerRolloutCount], a + ld [wd002], a + ld [wBeatUpHitAtLeastOnce], a + jr .got_mon + +.next_mon + ld a, [PlayerRolloutCount] + ld b, a + ld a, [PartyCount] + sub b + ld [wd002], a + +.got_mon + ld a, [wd002] + ld hl, PartyMonNicknames + call GetNick + ld a, MON_HP + call GetBeatupMonLocation + ld a, [hli] + or [hl] + jp z, .beatup_fail ; fainted + ld a, [wd002] + ld c, a + ld a, [CurBattleMon] + ; BUG: this can desynchronize link battles + ; Change "cp [hl]" to "cp c" to fix + cp [hl] + ld hl, BattleMonStatus + jr z, .active_mon + ld a, MON_STATUS + call GetBeatupMonLocation +.active_mon + ld a, [hl] + and a + jp nz, .beatup_fail + + ld a, $1 + ld [wBeatUpHitAtLeastOnce], a + ld hl, BeatUpAttackText + call StdBattleTextBox + ld a, [EnemyMonSpecies] + ld [CurSpecies], a + call GetBaseData + ld a, [BaseDefense] + ld c, a + push bc + ld a, MON_SPECIES + call GetBeatupMonLocation + ld a, [hl] + ld [CurSpecies], a + call GetBaseData + ld a, [BaseAttack] + pop bc + ld b, a + push bc + ld a, MON_LEVEL + call GetBeatupMonLocation + ld a, [hl] + ld e, a + pop bc + ld a, [wPlayerMoveStructPower] + ld d, a + ret + +.enemy_beats_up + ld a, [EnemySubStatus3] + bit SUBSTATUS_IN_LOOP, a + jr nz, .not_first_enemy_beatup + + xor a + ld [EnemyRolloutCount], a + ld [wd002], a + ld [wBeatUpHitAtLeastOnce], a + jr .enemy_continue + +.not_first_enemy_beatup + ld a, [EnemyRolloutCount] + ld b, a + ld a, [OTPartyCount] + sub b + ld [wd002], a +.enemy_continue + ld a, [wBattleMode] + dec a + jr z, .wild + + ld a, [wLinkMode] + and a + jr nz, .link_or_tower + + ld a, [InBattleTowerBattle] + and a + jr nz, .link_or_tower + + ld a, [wd002] + ld c, a + ld b, 0 + ld hl, OTPartySpecies + add hl, bc + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + jr .got_enemy_nick + +.link_or_tower + ld a, [wd002] + ld hl, OTPartyMonNicknames + ld bc, NAME_LENGTH + call AddNTimes + ld de, StringBuffer1 + call CopyBytes +.got_enemy_nick + ld a, MON_HP + call GetBeatupMonLocation + ld a, [hli] + or [hl] + jp z, .beatup_fail + ld a, [wd002] + ld b, a + ld a, [CurOTMon] + cp b + ld hl, EnemyMonStatus + jr z, .active_enemy + + ld a, MON_STATUS + call GetBeatupMonLocation +.active_enemy + ld a, [hl] + and a + jr nz, .beatup_fail + + ld a, $1 + ld [wBeatUpHitAtLeastOnce], a + jr .finish_beatup + +.wild + ld a, [EnemyMonSpecies] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, BeatUpAttackText + call StdBattleTextBox + jp EnemyAttackDamage + +.finish_beatup + ld hl, BeatUpAttackText + call StdBattleTextBox + ld a, [BattleMonSpecies] + ld [CurSpecies], a + call GetBaseData + ld a, [BaseDefense] + ld c, a + push bc + ld a, MON_SPECIES + call GetBeatupMonLocation + ld a, [hl] + ld [CurSpecies], a + call GetBaseData + ld a, [BaseAttack] + pop bc + ld b, a + push bc + ld a, MON_LEVEL + call GetBeatupMonLocation + ld a, [hl] + ld e, a + pop bc + ld a, [wEnemyMoveStructPower] + ld d, a + ret + +; 355b0 + + +.beatup_fail ; 355b0 + ld b, buildopponentrage_command + jp SkipToBattleCommand + +; 355b5 + + +BattleCommanda8: ; 355b5 + ld a, [wBeatUpHitAtLeastOnce] + and a + ret nz + + jp PrintButItFailed + +; 355bd + + +GetBeatupMonLocation: ; 355bd + push bc + ld c, a + ld b, 0 + ld a, [hBattleTurn] + and a + ld hl, PartyMon1Species + jr z, .got_species + ld hl, OTPartyMon1Species + +.got_species + ld a, [wd002] + add hl, bc + call GetPartyLocation + pop bc + ret + + +BattleCommand_ClearMissDamage: ; 355d5 +; clearmissdamage + ld a, [AttackMissed] + and a + ret z + + jp ResetDamage + +; 355dd + + +HitSelfInConfusion: ; 355dd + call ResetDamage + ld a, [hBattleTurn] + and a + ld hl, BattleMonDefense + ld de, PlayerScreens + ld a, [BattleMonLevel] + jr z, .got_it + + ld hl, EnemyMonDefense + ld de, EnemyScreens + ld a, [EnemyMonLevel] +.got_it + push af + ld a, [hli] + ld b, a + ld c, [hl] + ld a, [de] + bit SCREENS_REFLECT, a + jr z, .mimic_screen + + sla c + rl b +.mimic_screen + dec hl + dec hl + dec hl + ld a, [hli] + ld l, [hl] + ld h, a + call TruncateHL_BC + ld d, 40 + pop af + ld e, a + ret + +; 35612 + + +BattleCommand_DamageCalc: ; 35612 +; damagecalc + +; Return a damage value for move power d, player level e, enemy defense c and player attack b. + +; Return 1 if successful, else 0. + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + +; Selfdestruct and Explosion halve defense. + cp EFFECT_SELFDESTRUCT + jr nz, .dont_selfdestruct + + srl c + jr nz, .dont_selfdestruct + inc c + +.dont_selfdestruct + +; Variable-hit moves and Conversion can have a power of 0. + cp EFFECT_MULTI_HIT + jr z, .skip_zero_damage_check + + cp EFFECT_CONVERSION + jr z, .skip_zero_damage_check + +; No damage if move power is 0. + ld a, d + and a + ret z + +.skip_zero_damage_check +; Minimum defense value is 1. + ld a, c + and a + jr nz, .not_dividing_by_zero + ld c, 1 +.not_dividing_by_zero + + xor a + ld hl, hDividend + ld [hli], a + ld [hli], a + ld [hl], a + +; Level * 2 + ld a, e + add a + jr nc, .level_not_overflowing + ld [hl], $1 +.level_not_overflowing + inc hl + ld [hli], a + +; / 5 + ld a, 5 + ld [hld], a + push bc + ld b, $4 + call Divide + pop bc + +; + 2 + inc [hl] + inc [hl] + +; * bp + inc hl + ld [hl], d + call Multiply + +; * Attack + ld [hl], b + call Multiply + +; / Defense + ld [hl], c + ld b, $4 + call Divide + +; / 50 + ld [hl], 50 + ld b, $4 + call Divide + +; Item boosts + call GetUserItem + + ld a, b + and a + jr z, .DoneItem + + ld hl, TypeBoostItems + +.NextItem: + ld a, [hli] + cp $ff + jr z, .DoneItem + +; Item effect + cp b + ld a, [hli] + jr nz, .NextItem + +; Type + ld b, a + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVar + cp b + jr nz, .DoneItem + +; * 100 + item effect amount + ld a, c + add 100 + ld [hMultiplier], a + call Multiply + +; / 100 + ld a, 100 + ld [hDivisor], a + ld b, 4 + call Divide +.DoneItem: + +; Critical hits + call .CriticalMultiplier + + +; Update CurDamage (capped at 997). + ld hl, CurDamage + ld b, [hl] + ld a, [hProduct + 3] + add b + ld [hProduct + 3], a + jr nc, .dont_cap_1 + + ld a, [hProduct + 2] + inc a + ld [hProduct + 2], a + and a + jr z, .Cap + +.dont_cap_1 + ld a, [hProduct] + ld b, a + ld a, [hProduct + 1] + or a + jr nz, .Cap + + ld a, [hProduct + 2] + cp HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1) + jr c, .dont_cap_2 + + cp HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1) + 1 + jr nc, .Cap + + ld a, [hProduct + 3] + cp LOW(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1) + jr nc, .Cap + +.dont_cap_2 + inc hl + + ld a, [hProduct + 3] + ld b, [hl] + add b + ld [hld], a + + ld a, [hProduct + 2] + ld b, [hl] + adc b + ld [hl], a + jr c, .Cap + + ld a, [hl] + cp HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1) + jr c, .dont_cap_3 + + cp HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1) + 1 + jr nc, .Cap + + inc hl + ld a, [hld] + cp LOW(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1) + jr c, .dont_cap_3 + +.Cap: + ld a, HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE) + ld [hli], a + ld a, LOW(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE) + ld [hld], a + + +.dont_cap_3 +; Minimum neutral damage is 2 (bringing the cap to 999). + inc hl + ld a, [hl] + add MIN_NEUTRAL_DAMAGE + ld [hld], a + jr nc, .dont_floor + inc [hl] +.dont_floor + + ld a, 1 + and a + ret + + +.CriticalMultiplier: + ld a, [CriticalHit] + and a + ret z + +; x2 + ld a, [hQuotient + 2] + add a + ld [hProduct + 3], a + + ld a, [hQuotient + 1] + rl a + ld [hProduct + 2], a + +; Cap at $ffff. + ret nc + + ld a, $ff + ld [hProduct + 2], a + ld [hProduct + 3], a + + ret + +; 35703 + + +TypeBoostItems: ; 35703 + db HELD_NORMAL_BOOST, NORMAL ; Pink/Polkadot Bow + db HELD_FIGHTING_BOOST, FIGHTING ; Blackbelt + db HELD_FLYING_BOOST, FLYING ; Sharp Beak + db HELD_POISON_BOOST, POISON ; Poison Barb + db HELD_GROUND_BOOST, GROUND ; Soft Sand + db HELD_ROCK_BOOST, ROCK ; Hard Stone + db HELD_BUG_BOOST, BUG ; Silverpowder + db HELD_GHOST_BOOST, GHOST ; Spell Tag + db HELD_FIRE_BOOST, FIRE ; Charcoal + db HELD_WATER_BOOST, WATER ; Mystic Water + db HELD_GRASS_BOOST, GRASS ; Miracle Seed + db HELD_ELECTRIC_BOOST, ELECTRIC ; Magnet + db HELD_PSYCHIC_BOOST, PSYCHIC ; Twistedspoon + db HELD_ICE_BOOST, ICE ; Nevermeltice + db HELD_DRAGON_BOOST, DRAGON ; Dragon Scale + db HELD_DARK_BOOST, DARK ; Blackglasses + db HELD_STEEL_BOOST, STEEL ; Metal Coat + db $ff +; 35726 + + +BattleCommand_ConstantDamage: ; 35726 +; constantdamage + + ld hl, BattleMonLevel + ld a, [hBattleTurn] + and a + jr z, .got_turn + ld hl, EnemyMonLevel + +.got_turn + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_LEVEL_DAMAGE + ld b, [hl] + ld a, 0 + jr z, .got_power + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_PSYWAVE + jr z, .psywave + + cp EFFECT_SUPER_FANG + jr z, .super_fang + + cp EFFECT_REVERSAL + jr z, .reversal + + ld a, BATTLE_VARS_MOVE_POWER + call GetBattleVar + ld b, a + ld a, $0 + jr .got_power + +.psywave + ld a, b + srl a + add b + ld b, a +.psywave_loop + call BattleRandom + and a + jr z, .psywave_loop + cp b + jr nc, .psywave_loop + ld b, a + ld a, $0 + jr .got_power + +.super_fang + ld hl, EnemyMonHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, BattleMonHP +.got_hp + ld a, [hli] + srl a + ld b, a + ld a, [hl] + rr a + push af + ld a, b + pop bc + and a + jr nz, .got_power + or b + ld a, $0 + jr nz, .got_power + ld b, $1 + jr .got_power + +.got_power + ld hl, CurDamage + ld [hli], a + ld [hl], b + ret + +.reversal + ld hl, BattleMonHP + ld a, [hBattleTurn] + and a + jr z, .reversal_got_hp + ld hl, EnemyMonHP +.reversal_got_hp + xor a + ld [hDividend], a + ld [hMultiplicand + 0], a + ld a, [hli] + ld [hMultiplicand + 1], a + ld a, [hli] + ld [hMultiplicand + 2], a + ld a, $30 + ld [hMultiplier], a + call Multiply + ld a, [hli] + ld b, a + ld a, [hl] + ld [hDivisor], a + ld a, b + and a + jr z, .skip_to_divide + + ld a, [hProduct + 4] + srl b + rr a + srl b + rr a + ld [hDivisor], a + ld a, [hProduct + 2] + ld b, a + srl b + ld a, [hProduct + 3] + rr a + srl b + rr a + ld [hDividend + 3], a + ld a, b + ld [hDividend + 2], a + +.skip_to_divide + ld b, $4 + call Divide + ld a, [hQuotient + 2] + ld b, a + ld hl, .FlailPower + +.reversal_loop + ld a, [hli] + cp b + jr nc, .break_loop + inc hl + jr .reversal_loop + +.break_loop + ld a, [hBattleTurn] + and a + ld a, [hl] + jr nz, .notPlayersTurn + + ld hl, wPlayerMoveStructPower + ld [hl], a + push hl + call PlayerAttackDamage + jr .notEnemysTurn + +.notPlayersTurn + ld hl, wEnemyMoveStructPower + ld [hl], a + push hl + call EnemyAttackDamage + +.notEnemysTurn + call BattleCommand_DamageCalc + pop hl + ld [hl], 1 + ret + +.FlailPower: + ; px, bp + db 1, 200 + db 4, 150 + db 9, 100 + db 16, 80 + db 32, 40 + db 48, 20 +; 35813 + + +BattleCommand_Counter: ; 35813 +; counter + + ld a, 1 + ld [AttackMissed], a + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + and a + ret z + + ld b, a + callfar GetMoveEffect + ld a, b + cp EFFECT_COUNTER + ret z + + call BattleCommand_ResetTypeMatchup + ld a, [wTypeMatchup] + and a + ret z + + call CheckOpponentWentFirst + ret z + + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + dec a + ld de, StringBuffer1 + call GetMoveData + + ld a, [StringBuffer1 + MOVE_POWER] + and a + ret z + + ld a, [StringBuffer1 + MOVE_TYPE] + cp SPECIAL + ret nc + + ld hl, CurDamage + ld a, [hli] + or [hl] + ret z + + ld a, [hl] + add a + ld [hld], a + ld a, [hl] + adc a + ld [hl], a + jr nc, .capped + ld a, $ff + ld [hli], a + ld [hl], a +.capped + + xor a + ld [AttackMissed], a + ret + +; 35864 + + +BattleCommand_Encore: ; 35864 +; encore + + ld hl, EnemyMonMoves + ld de, EnemyEncoreCount + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, BattleMonMoves + ld de, PlayerEncoreCount +.ok + ld a, BATTLE_VARS_LAST_MOVE_OPP + call GetBattleVar + and a + jp z, .failed + cp STRUGGLE + jp z, .failed + cp ENCORE + jp z, .failed + cp MIRROR_MOVE + jp z, .failed + ld b, a + +.got_move + ld a, [hli] + cp b + jr nz, .got_move + + ld bc, BattleMonPP - BattleMonMoves - 1 + add hl, bc + ld a, [hl] + and $3f + jp z, .failed + ld a, [AttackMissed] + and a + jp nz, .failed + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + bit SUBSTATUS_ENCORED, [hl] + jp nz, .failed + set SUBSTATUS_ENCORED, [hl] + call BattleRandom + and $3 + inc a + inc a + inc a + ld [de], a + call CheckOpponentWentFirst + jr nz, .finish_move + ld a, [hBattleTurn] + and a + jr z, .force_last_enemy_move + + push hl + ld a, [LastPlayerMove] + ld b, a + ld c, 0 + ld hl, BattleMonMoves +.find_player_move + ld a, [hli] + cp b + jr z, .got_player_move + inc c + ld a, c + cp NUM_MOVES + jr c, .find_player_move + pop hl + res SUBSTATUS_ENCORED, [hl] + xor a + ld [de], a + jr .failed + +.got_player_move + pop hl + ld a, c + ld [CurMoveNum], a + ld a, b + ld [CurPlayerMove], a + dec a + ld de, wPlayerMoveStruct + call GetMoveData + jr .finish_move + +.force_last_enemy_move + push hl + ld a, [LastEnemyMove] + ld b, a + ld c, 0 + ld hl, EnemyMonMoves +.find_enemy_move + ld a, [hli] + cp b + jr z, .got_enemy_move + inc c + ld a, c + cp NUM_MOVES + jr c, .find_enemy_move + pop hl + res SUBSTATUS_ENCORED, [hl] + xor a + ld [de], a + jr .failed + +.got_enemy_move + pop hl + ld a, c + ld [CurEnemyMoveNum], a + ld a, b + ld [CurEnemyMove], a + dec a + ld de, wEnemyMoveStruct + call GetMoveData + +.finish_move + call AnimateCurrentMove + ld hl, GotAnEncoreText + jp StdBattleTextBox + +.failed + jp PrintDidntAffect2 + +; 35926 + + +BattleCommand_PainSplit: ; 35926 +; painsplit + + ld a, [AttackMissed] + and a + jp nz, .ButItFailed + call CheckSubstituteOpp + jp nz, .ButItFailed + call AnimateCurrentMove + ld hl, BattleMonMaxHP + 1 + ld de, EnemyMonMaxHP + 1 + call .PlayerShareHP + ld a, $1 + ld [wWhichHPBar], a + hlcoord 10, 9 + predef AnimateHPBar + ld hl, EnemyMonHP + ld a, [hli] + ld [Buffer4], a + ld a, [hli] + ld [Buffer3], a + ld a, [hli] + ld [Buffer2], a + ld a, [hl] + ld [Buffer1], a + call .EnemyShareHP + xor a + ld [wWhichHPBar], a + call ResetDamage + hlcoord 2, 2 + predef AnimateHPBar + farcall _UpdateBattleHUDs + + ld hl, SharedPainText + jp StdBattleTextBox + +.PlayerShareHP: + ld a, [hld] + ld [Buffer1], a + ld a, [hld] + ld [Buffer2], a + ld a, [hld] + ld b, a + ld [Buffer3], a + ld a, [hl] + ld [Buffer4], a + dec de + dec de + ld a, [de] + dec de + add b + ld [CurDamage + 1], a + ld b, [hl] + ld a, [de] + adc b + srl a + ld [CurDamage], a + ld a, [CurDamage + 1] + rr a + ld [CurDamage + 1], a + inc hl + inc hl + inc hl + inc de + inc de + inc de + +.EnemyShareHP: ; 359ac + ld c, [hl] + dec hl + ld a, [CurDamage + 1] + sub c + ld b, [hl] + dec hl + ld a, [CurDamage] + sbc b + jr nc, .skip + + ld a, [CurDamage] + ld b, a + ld a, [CurDamage + 1] + ld c, a +.skip + ld a, c + ld [hld], a + ld [Buffer5], a + ld a, b + ld [hli], a + ld [Buffer6], a + ret + +; 359cd + +.ButItFailed: + jp PrintDidntAffect2 + +; 359d0 + + +BattleCommand_Snore: ; 359d0 +; snore + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + ret nz + call ResetDamage + ld a, $1 + ld [AttackMissed], a + call FailSnore + jp EndMoveEffect + +; 359e6 + + +BattleCommand_Conversion2: ; 359e6 +; conversion2 + + ld a, [AttackMissed] + and a + jr nz, .failed + ld hl, BattleMonType1 + ld a, [hBattleTurn] + and a + jr z, .got_type + ld hl, EnemyMonType1 +.got_type + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + and a + jr z, .failed + push hl + dec a + ld hl, Moves + MOVE_TYPE + call GetMoveAttr + ld d, a + pop hl + cp CURSE_T + jr z, .failed + call AnimateCurrentMove + call BattleCommand_SwitchTurn + +.loop + call BattleRandom + and $1f + cp UNUSED_TYPES + jr c, .okay + cp UNUSED_TYPES_END + jr c, .loop + cp TYPES_END + jr nc, .loop +.okay + ld [hli], a + ld [hld], a + push hl + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVarAddr + push af + push hl + ld a, d + ld [hl], a + call BattleCheckTypeMatchup + pop hl + pop af + ld [hl], a + pop hl + ld a, [wTypeMatchup] + cp 10 + jr nc, .loop + call BattleCommand_SwitchTurn + + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + predef GetTypeName + ld hl, TransformedTypeText + jp StdBattleTextBox + +.failed + jp FailConversion2 + +; 35a53 + + +BattleCommand_LockOn: ; 35a53 +; lockon + + call CheckSubstituteOpp + jr nz, .fail + + ld a, [AttackMissed] + and a + jr nz, .fail + + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + set SUBSTATUS_LOCK_ON, [hl] + call AnimateCurrentMove + + ld hl, TookAimText + jp StdBattleTextBox + +.fail + call AnimateFailedMove + jp PrintDidntAffect + +; 35a74 + + +BattleCommand_Sketch: ; 35a74 +; sketch + + call ClearLastMove +; Don't sketch during a link battle + ld a, [wLinkMode] + and a + jr z, .not_linked + call AnimateFailedMove + jp PrintNothingHappened + +.not_linked +; If the opponent has a substitute up, fail. + call CheckSubstituteOpp + jp nz, .fail +; If the opponent is transformed, fail. + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + bit SUBSTATUS_TRANSFORMED, [hl] + jp nz, .fail +; Get the user's moveset in its party struct. +; This move replacement shall be permanent. +; Pointer will be in de. + ld a, MON_MOVES + call UserPartyAttr + ld d, h + ld e, l +; Get the battle move structs. + ld hl, BattleMonMoves + ld a, [hBattleTurn] + and a + jr z, .get_last_move + ld hl, EnemyMonMoves +.get_last_move + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + ld [wTypeMatchup], a + ld b, a +; Fail if move is invalid or is Struggle. + and a + jr z, .fail + cp STRUGGLE + jr z, .fail +; Fail if user already knows that move + ld c, NUM_MOVES +.does_user_already_know_move + ld a, [hli] + cp b + jr z, .fail + dec c + jr nz, .does_user_already_know_move +; Find Sketch in the user's moveset. +; Pointer in hl, and index in c. + dec hl + ld c, NUM_MOVES +.find_sketch + dec c + ld a, [hld] + cp SKETCH + jr nz, .find_sketch + inc hl +; The Sketched move is loaded to that slot. + ld a, b + ld [hl], a +; Copy the base PP from that move. + push bc + push hl + dec a + ld hl, Moves + MOVE_PP + call GetMoveAttr + pop hl + ld bc, BattleMonPP - BattleMonMoves + add hl, bc + ld [hl], a + pop bc + + ld a, [hBattleTurn] + and a + jr z, .user_trainer + ld a, [wBattleMode] + dec a + jr nz, .user_trainer +; wildmon + ld a, [hl] + push bc + ld hl, wWildMonPP + ld b, 0 + add hl, bc + ld [hl], a + ld hl, wWildMonMoves + add hl, bc + pop bc + ld [hl], b + jr .done_copy + +.user_trainer + ld a, [hl] + push af + ld l, c + ld h, 0 + add hl, de + ld a, b + ld [hl], a + pop af + ld de, MON_PP - MON_MOVES + add hl, de + ld [hl], a +.done_copy + call GetMoveName + call AnimateCurrentMove + + ld hl, SketchedText + jp StdBattleTextBox + +.fail + call AnimateFailedMove + jp PrintDidntAffect + +; 35b16 + + +BattleCommand_DefrostOpponent: ; 35b16 +; defrostopponent +; Thaw the opponent if frozen, and +; raise the user's Attack one stage. + + call AnimateCurrentMove + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + call Defrost + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVarAddr + ld a, [hl] + push hl + push af + + ld a, EFFECT_ATTACK_UP + ld [hl], a + call BattleCommand_StatUp + + pop af + pop hl + ld [hl], a + ret + +; 35b33 + + +BattleCommand_SleepTalk: ; 35b33 +; sleeptalk + + call ClearLastMove + ld a, [AttackMissed] + and a + jr nz, .fail + ld a, [hBattleTurn] + and a + ld hl, BattleMonMoves + 1 + ld a, [DisabledMove] + ld d, a + jr z, .got_moves + ld hl, EnemyMonMoves + 1 + ld a, [EnemyDisabledMove] + ld d, a +.got_moves + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + jr z, .fail + ld a, [hl] + and a + jr z, .fail + call .safely_check_has_usable_move + jr c, .fail + dec hl +.sample_move + push hl + call BattleRandom + and 3 ; TODO factor in NUM_MOVES + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + pop hl + and a + jr z, .sample_move + ld e, a + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp e + jr z, .sample_move + ld a, e + cp d + jr z, .sample_move + call .check_two_turn_move + jr z, .sample_move + ld a, BATTLE_VARS_MOVE + call GetBattleVarAddr + ld a, e + ld [hl], a + call CheckUserIsCharging + jr nz, .charging + ld a, [wKickCounter] + push af + call BattleCommand_LowerSub + pop af + ld [wKickCounter], a +.charging + call LoadMoveAnim + call UpdateMoveData + jp ResetTurn + +.fail + call AnimateFailedMove + jp TryPrintButItFailed + +.safely_check_has_usable_move + push hl + push de + push bc + call .check_has_usable_move + pop bc + pop de + pop hl + ret + +.check_has_usable_move + ld a, [hBattleTurn] + and a + ld a, [DisabledMove] + jr z, .got_move_2 + + ld a, [EnemyDisabledMove] +.got_move_2 + ld b, a + ld a, BATTLE_VARS_MOVE + call GetBattleVar + ld c, a + dec hl + ld d, NUM_MOVES +.loop2 + ld a, [hl] + and a + jr z, .carry + + cp c + jr z, .nope + cp b + jr z, .nope + + call .check_two_turn_move + jr nz, .no_carry + +.nope + inc hl + dec d + jr nz, .loop2 + +.carry + scf + ret + +.no_carry + and a + ret + +.check_two_turn_move + push hl + push de + push bc + + ld b, a + callfar GetMoveEffect + ld a, b + + pop bc + pop de + pop hl + + cp EFFECT_SKULL_BASH + ret z + cp EFFECT_RAZOR_WIND + ret z + cp EFFECT_SKY_ATTACK + ret z + cp EFFECT_SOLARBEAM + ret z + cp EFFECT_FLY + ret z + cp EFFECT_BIDE + ret + +; 35bff + + +BattleCommand_DestinyBond: ; 35bff +; destinybond + + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVarAddr + set SUBSTATUS_DESTINY_BOND, [hl] + call AnimateCurrentMove + ld hl, DestinyBondEffectText + jp StdBattleTextBox + +; 35c0f + + +BattleCommand_Spite: ; 35c0f +; spite + + ld a, [AttackMissed] + and a + jp nz, .failed + ld bc, PARTYMON_STRUCT_LENGTH ; ???? + ld hl, EnemyMonMoves + ld a, [hBattleTurn] + and a + jr z, .got_moves + ld hl, BattleMonMoves +.got_moves + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + and a + jr z, .failed + cp STRUGGLE + jr z, .failed + ld b, a + ld c, -1 +.loop + inc c + ld a, [hli] + cp b + jr nz, .loop + ld [wTypeMatchup], a + dec hl + ld b, 0 + push bc + ld c, BattleMonPP - BattleMonMoves + add hl, bc + pop bc + ld a, [hl] + and $3f + jr z, .failed + push bc + call GetMoveName + call BattleRandom + and 3 + inc a + inc a + ld b, a + ld a, [hl] + and $3f + cp b + jr nc, .deplete_pp + ld b, a +.deplete_pp + ld a, [hl] + sub b + ld [hl], a + push af + ld a, MON_PP + call OpponentPartyAttr + ld d, b + pop af + pop bc + add hl, bc + ld e, a + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVar + bit SUBSTATUS_TRANSFORMED, a + jr nz, .transformed + ld a, [hBattleTurn] + and a + jr nz, .not_wildmon + ld a, [wBattleMode] + dec a + jr nz, .not_wildmon + ld hl, wWildMonPP + add hl, bc +.not_wildmon + ld [hl], e +.transformed + push de + call AnimateCurrentMove + pop de + ld a, d + ld [wTypeMatchup], a + ld hl, SpiteEffectText + jp StdBattleTextBox + +.failed + jp PrintDidntAffect2 + +; 35c94 + + +BattleCommand_FalseSwipe: ; 35c94 +; falseswipe + + ld hl, EnemyMonHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, BattleMonHP +.got_hp + ld de, CurDamage + ld c, 2 + push hl + push de + call StringCmp + pop de + pop hl + jr c, .done + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + dec a + ld [de], a + inc a + jr nz, .okay + dec de + ld a, [de] + dec a + ld [de], a +.okay + ld a, [CriticalHit] + cp $2 + jr nz, .carry + xor a + ld [CriticalHit], a +.carry + scf + ret + +.done + and a + ret + +; 35cc9 + + +BattleCommand_HealBell: ; 35cc9 +; healbell + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + res SUBSTATUS_NIGHTMARE, [hl] + ld de, PartyMon1Status + ld a, [hBattleTurn] + and a + jr z, .got_status + ld de, OTPartyMon1Status +.got_status + ld a, BATTLE_VARS_STATUS + call GetBattleVarAddr + xor a + ld [hl], a + ld h, d + ld l, e + ld bc, PARTYMON_STRUCT_LENGTH + ld d, PARTY_LENGTH +.loop + ld [hl], a + add hl, bc + dec d + jr nz, .loop + call AnimateCurrentMove + + ld hl, BellChimedText + call StdBattleTextBox + + ld a, [hBattleTurn] + and a + jp z, CalcPlayerStats + jp CalcEnemyStats + +; 35d00 + + +FarPlayBattleAnimation: ; 35d00 +; play animation de + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret nz + + ; fallthrough +; 35d08 + +PlayFXAnimID: ; 35d08 + ld a, e + ld [FXAnimID], a + ld a, d + ld [FXAnimID + 1], a + + ld c, 3 + call DelayFrames + + callfar PlayBattleAnim + + ret + +; 35d1c + + +EnemyHurtItself: ; 35d1c + ld hl, CurDamage + ld a, [hli] + ld b, a + ld a, [hl] + or b + jr z, .did_no_damage + + ld a, c + and a + jr nz, .mimic_sub_check + + ld a, [EnemySubStatus4] + bit SUBSTATUS_SUBSTITUTE, a + jp nz, SelfInflictDamageToSubstitute + +.mimic_sub_check + ld a, [hld] + ld b, a + ld a, [EnemyMonHP + 1] + ld [Buffer3], a + sub b + ld [EnemyMonHP + 1], a + ld a, [hl] + ld b, a + ld a, [EnemyMonHP] + ld [Buffer4], a + sbc b + ld [EnemyMonHP], a + jr nc, .mimic_faint + + ld a, [Buffer4] + ld [hli], a + ld a, [Buffer3] + ld [hl], a + + xor a + ld hl, EnemyMonHP + ld [hli], a + ld [hl], a + +.mimic_faint + ld hl, EnemyMonMaxHP + ld a, [hli] + ld [Buffer2], a + ld a, [hl] + ld [Buffer1], a + ld hl, EnemyMonHP + ld a, [hli] + ld [Buffer6], a + ld a, [hl] + ld [Buffer5], a + hlcoord 2, 2 + xor a + ld [wWhichHPBar], a + predef AnimateHPBar +.did_no_damage + jp RefreshBattleHuds + +; 35d7e + + +PlayerHurtItself: ; 35d7e + ld hl, CurDamage + ld a, [hli] + ld b, a + ld a, [hl] + or b + jr z, .did_no_damage + + ld a, c + and a + jr nz, .mimic_sub_check + + ld a, [PlayerSubStatus4] + bit SUBSTATUS_SUBSTITUTE, a + jp nz, SelfInflictDamageToSubstitute +.mimic_sub_check + ld a, [hld] + ld b, a + ld a, [BattleMonHP + 1] + ld [Buffer3], a + sub b + ld [BattleMonHP + 1], a + ld [Buffer5], a + ld b, [hl] + ld a, [BattleMonHP] + ld [Buffer4], a + sbc b + ld [BattleMonHP], a + ld [Buffer6], a + jr nc, .mimic_faint + + ld a, [Buffer4] + ld [hli], a + ld a, [Buffer3] + ld [hl], a + xor a + + ld hl, BattleMonHP + ld [hli], a + ld [hl], a + ld hl, Buffer5 + ld [hli], a + ld [hl], a + +.mimic_faint + ld hl, BattleMonMaxHP + ld a, [hli] + ld [Buffer2], a + ld a, [hl] + ld [Buffer1], a + hlcoord 10, 9 + ld a, $1 + ld [wWhichHPBar], a + predef AnimateHPBar +.did_no_damage + jp RefreshBattleHuds + +; 35de0 + + +SelfInflictDamageToSubstitute: ; 35de0 + + ld hl, SubTookDamageText + call StdBattleTextBox + + ld de, EnemySubstituteHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld de, PlayerSubstituteHP +.got_hp + + ld hl, CurDamage + ld a, [hli] + and a + jr nz, .broke + + ld a, [de] + sub [hl] + ld [de], a + jr z, .broke + jr nc, .done + +.broke + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVarAddr + res SUBSTATUS_SUBSTITUTE, [hl] + + ld hl, SubFadedText + call StdBattleTextBox + + call BattleCommand_SwitchTurn + call BattleCommand_LowerSubNoAnim + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + call z, AppearUserLowerSub + call BattleCommand_SwitchTurn + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVarAddr + cp EFFECT_MULTI_HIT + jr z, .ok + cp EFFECT_DOUBLE_HIT + jr z, .ok + cp EFFECT_POISON_MULTI_HIT + jr z, .ok + cp EFFECT_TRIPLE_KICK + jr z, .ok + cp EFFECT_BEAT_UP + jr z, .ok + xor a + ld [hl], a +.ok + call RefreshBattleHuds +.done + jp ResetDamage + +; 35e40 + + +UpdateMoveData: ; 35e40 + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVarAddr + ld d, h + ld e, l + + ld a, BATTLE_VARS_MOVE + call GetBattleVar + ld [CurMove], a + ld [wNamedObjectIndexBuffer], a + + dec a + call GetMoveData + call GetMoveName + jp CopyName1 + +; 35e5c + + +BattleCommand_SleepTarget: ; 35e5c +; sleeptarget + + call GetOpponentItem + ld a, b + cp HELD_PREVENT_SLEEP + jr nz, .not_protected_by_item + + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetItemName + ld hl, ProtectedByText + jr .fail + +.not_protected_by_item + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + ld d, h + ld e, l + ld a, [de] + and SLP + ld hl, AlreadyAsleepText + jr nz, .fail + + ld a, [AttackMissed] + and a + jp nz, PrintDidntAffect2 + + ld hl, DidntAffect1Text + call .CheckAIRandomFail + jr c, .fail + + ld a, [de] + and a + jr nz, .fail + + call CheckSubstituteOpp + jr nz, .fail + + call AnimateCurrentMove + ld b, $7 + ld a, [InBattleTowerBattle] + and a + jr z, .random_loop + ld b, $3 + +.random_loop + call BattleRandom + and b + jr z, .random_loop + cp 7 + jr z, .random_loop + inc a + ld [de], a + call UpdateOpponentInParty + call RefreshBattleHuds + + ld hl, FellAsleepText + call StdBattleTextBox + + farcall UseHeldStatusHealingItem + + jp z, OpponentCantMove + ret + +.fail + push hl + call AnimateFailedMove + pop hl + jp StdBattleTextBox + +; 35ece + + +.CheckAIRandomFail: ; 35ece + ; Enemy turn + ld a, [hBattleTurn] + and a + jr z, .dont_fail + + ; Not in link battle + ld a, [wLinkMode] + and a + jr nz, .dont_fail + + ld a, [InBattleTowerBattle] + and a + jr nz, .dont_fail + + ; Not locked-on by the enemy + ld a, [PlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .dont_fail + + call BattleRandom + cp $40 ; 25% + ret c + +.dont_fail + xor a + ret + +; 35eee + + +BattleCommand_PoisonTarget: ; 35eee +; poisontarget + + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + ret nz + ld a, [TypeModifier] + and $7f + ret z + call CheckIfTargetIsPoisonType + ret z + call GetOpponentItem + ld a, b + cp HELD_PREVENT_POISON + ret z + ld a, [EffectFailed] + and a + ret nz + call SafeCheckSafeguard + ret nz + + call PoisonOpponent + ld de, ANIM_PSN + call PlayOpponentBattleAnim + call RefreshBattleHuds + + ld hl, WasPoisonedText + call StdBattleTextBox + + farcall UseHeldStatusHealingItem + ret + +; 35f2c + + +BattleCommand_Poison: ; 35f2c +; poison + + ld hl, DoesntAffectText + ld a, [TypeModifier] + and $7f + jp z, .failed + + call CheckIfTargetIsPoisonType + jp z, .failed + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVar + ld b, a + ld hl, AlreadyPoisonedText + and 1 << PSN + jp nz, .failed + + call GetOpponentItem + ld a, b + cp HELD_PREVENT_POISON + jr nz, .do_poison + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetItemName + ld hl, ProtectedByText + jr .failed + +.do_poison + ld hl, DidntAffect1Text + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVar + and a + jr nz, .failed + + ld a, [hBattleTurn] + and a + jr z, .mimic_random + + ld a, [wLinkMode] + and a + jr nz, .mimic_random + + ld a, [InBattleTowerBattle] + and a + jr nz, .mimic_random + + ld a, [PlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .mimic_random + + call BattleRandom + cp $40 ; 25% chance AI fails + jr c, .failed + +.mimic_random + call CheckSubstituteOpp + jr nz, .failed + ld a, [AttackMissed] + and a + jr nz, .failed + call .check_toxic + jr z, .toxic + + call .apply_poison + ld hl, WasPoisonedText + call StdBattleTextBox + jr .finished + +.toxic + set SUBSTATUS_TOXIC, [hl] + xor a + ld [de], a + call .apply_poison + + ld hl, BadlyPoisonedText + call StdBattleTextBox + +.finished + farcall UseHeldStatusHealingItem + ret + +.failed + push hl + call AnimateFailedMove + pop hl + jp StdBattleTextBox + +; 35fc0 + + +.apply_poison ; 35fc0 + call AnimateCurrentMove + call PoisonOpponent + jp RefreshBattleHuds + +; 35fc9 + + +.check_toxic ; 35fc9 + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + ld a, [hBattleTurn] + and a + ld de, EnemyToxicCount + jr z, .ok + ld de, PlayerToxicCount +.ok + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_TOXIC + ret + +; 35fe1 + + +CheckIfTargetIsPoisonType: ; 35fe1 + ld de, EnemyMonType1 + ld a, [hBattleTurn] + and a + jr z, .ok + ld de, BattleMonType1 +.ok + ld a, [de] + inc de + cp POISON + ret z + ld a, [de] + cp POISON + ret + +; 35ff5 + + +PoisonOpponent: ; 35ff5 + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + set PSN, [hl] + jp UpdateOpponentInParty + +; 35fff + + +BattleCommand_DrainTarget: ; 35fff +; draintarget + call SapHealth + ld hl, SuckedHealthText + jp StdBattleTextBox + +; 36008 + + +BattleCommand_EatDream: ; 36008 +; eatdream + call SapHealth + ld hl, DreamEatenText + jp StdBattleTextBox + +; 36011 + + +SapHealth: ; 36011 + ld hl, CurDamage + ld a, [hli] + srl a + ld [hDividend], a + ld b, a + ld a, [hl] + rr a + ld [hDividend + 1], a + or b + jr nz, .ok1 + ld a, $1 + ld [hDividend + 1], a +.ok1 + ld hl, BattleMonHP + ld de, BattleMonMaxHP + ld a, [hBattleTurn] + and a + jr z, .battlemonhp + ld hl, EnemyMonHP + ld de, EnemyMonMaxHP +.battlemonhp + ld bc, Buffer4 + ld a, [hli] + ld [bc], a + ld a, [hl] + dec bc + ld [bc], a + ld a, [de] + dec bc + ld [bc], a + inc de + ld a, [de] + dec bc + ld [bc], a + ld a, [hDividend + 1] + ld b, [hl] + add b + ld [hld], a + ld [Buffer5], a + ld a, [hDividend] + ld b, [hl] + adc b + ld [hli], a + ld [Buffer6], a + jr c, .okay2 + ld a, [hld] + ld b, a + ld a, [de] + dec de + sub b + ld a, [hli] + ld b, a + ld a, [de] + inc de + sbc b + jr nc, .okay3 +.okay2 + ld a, [de] + ld [hld], a + ld [Buffer5], a + dec de + ld a, [de] + ld [hli], a + ld [Buffer6], a + inc de +.okay3 + ld a, [hBattleTurn] + and a + hlcoord 10, 9 + ld a, $1 + jr z, .hp_bar + hlcoord 2, 2 + xor a +.hp_bar + ld [wWhichHPBar], a + predef AnimateHPBar + call RefreshBattleHuds + jp UpdateBattleMonInParty + +; 3608c + + +BattleCommand_BurnTarget: ; 3608c +; burntarget + + xor a + ld [wNumHits], a + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + jp nz, Defrost + ld a, [TypeModifier] + and $7f + ret z + call CheckMoveTypeMatchesTarget ; Don't burn a Fire-type + ret z + call GetOpponentItem + ld a, b + cp HELD_PREVENT_BURN + ret z + ld a, [EffectFailed] + and a + ret nz + call SafeCheckSafeguard + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + set BRN, [hl] + call UpdateOpponentInParty + ld hl, ApplyBrnEffectOnAttack + call CallBattleCore + ld de, ANIM_BRN + call PlayOpponentBattleAnim + call RefreshBattleHuds + + ld hl, WasBurnedText + call StdBattleTextBox + + farcall UseHeldStatusHealingItem + ret + +; 360dd + + +Defrost: ; 360dd + ld a, [hl] + and 1 << FRZ + ret z + + xor a + ld [hl], a + + ld a, [hBattleTurn] + and a + ld a, [CurOTMon] + ld hl, OTPartyMon1Status + jr z, .ok + ld hl, PartyMon1Status + ld a, [CurBattleMon] +.ok + + call GetPartyLocation + xor a + ld [hl], a + call UpdateOpponentInParty + + ld hl, DefrostedOpponentText + jp StdBattleTextBox + +; 36102 + + +BattleCommand_FreezeTarget: ; 36102 +; freezetarget + + xor a + ld [wNumHits], a + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + ret nz + ld a, [TypeModifier] + and $7f + ret z + ld a, [Weather] + cp WEATHER_SUN + ret z + call CheckMoveTypeMatchesTarget ; Don't freeze an Ice-type + ret z + call GetOpponentItem + ld a, b + cp HELD_PREVENT_FREEZE + ret z + ld a, [EffectFailed] + and a + ret nz + call SafeCheckSafeguard + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + set FRZ, [hl] + call UpdateOpponentInParty + ld de, ANIM_FRZ + call PlayOpponentBattleAnim + call RefreshBattleHuds + + ld hl, WasFrozenText + call StdBattleTextBox + + farcall UseHeldStatusHealingItem + ret nz + + call OpponentCantMove + call EndRechargeOpp + ld hl, wEnemyJustGotFrozen + ld a, [hBattleTurn] + and a + jr z, .finish + ld hl, wPlayerJustGotFrozen +.finish + ld [hl], $1 + ret + +; 36165 + + +BattleCommand_ParalyzeTarget: ; 36165 +; paralyzetarget + + xor a + ld [wNumHits], a + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + ret nz + ld a, [TypeModifier] + and $7f + ret z + call GetOpponentItem + ld a, b + cp HELD_PREVENT_PARALYZE + ret z + ld a, [EffectFailed] + and a + ret nz + call SafeCheckSafeguard + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + set PAR, [hl] + call UpdateOpponentInParty + ld hl, ApplyPrzEffectOnSpeed + call CallBattleCore + ld de, ANIM_PAR + call PlayOpponentBattleAnim + call RefreshBattleHuds + call PrintParalyze + ld hl, UseHeldStatusHealingItem + jp CallBattleCore + +; 361ac + + +BattleCommand_AttackUp: ; 361ac +; attackup + ld b, ATTACK + jr BattleCommand_StatUp + +BattleCommand_DefenseUp: ; 361b0 +; defenseup + ld b, DEFENSE + jr BattleCommand_StatUp + +BattleCommand_SpeedUp: ; 361b4 +; speedup + ld b, SPEED + jr BattleCommand_StatUp + +BattleCommand_SpecialAttackUp: ; 361b8 +; specialattackup + ld b, SP_ATTACK + jr BattleCommand_StatUp + +BattleCommand_SpecialDefenseUp: ; 361bc +; specialdefenseup + ld b, SP_DEFENSE + jr BattleCommand_StatUp + +BattleCommand_AccuracyUp: ; 361c0 +; accuracyup + ld b, ACCURACY + jr BattleCommand_StatUp + +BattleCommand_EvasionUp: ; 361c4 +; evasionup + ld b, EVASION + jr BattleCommand_StatUp + +BattleCommand_AttackUp2: ; 361c8 +; attackup2 + ld b, $10 | ATTACK + jr BattleCommand_StatUp + +BattleCommand_DefenseUp2: ; 361cc +; defenseup2 + ld b, $10 | DEFENSE + jr BattleCommand_StatUp + +BattleCommand_SpeedUp2: ; 361d0 +; speedup2 + ld b, $10 | SPEED + jr BattleCommand_StatUp + +BattleCommand_SpecialAttackUp2: ; 361d4 +; specialattackup2 + ld b, $10 | SP_ATTACK + jr BattleCommand_StatUp + +BattleCommand_SpecialDefenseUp2: ; 361d8 +; specialdefenseup2 + ld b, $10 | SP_DEFENSE + jr BattleCommand_StatUp + +BattleCommand_AccuracyUp2: ; 361dc +; accuracyup2 + ld b, $10 | ACCURACY + jr BattleCommand_StatUp + +BattleCommand_EvasionUp2: ; 361e0 +; evasionup2 + ld b, $10 | EVASION + jr BattleCommand_StatUp + +BattleCommand_StatUp: ; 361e4 +; statup + call CheckIfStatCanBeRaised + ld a, [FailedMessage] + and a + ret nz + jp StatUpAnimation + +; 361ef + + +CheckIfStatCanBeRaised: ; 361ef + ld a, b + ld [LoweredStat], a + ld hl, PlayerStatLevels + ld a, [hBattleTurn] + and a + jr z, .got_stat_levels + ld hl, EnemyStatLevels +.got_stat_levels + ld a, [AttackMissed] + and a + jp nz, .stat_raise_failed + ld a, [EffectFailed] + and a + jp nz, .stat_raise_failed + ld a, [LoweredStat] + and $f + ld c, a + ld b, 0 + add hl, bc + ld b, [hl] + inc b + ld a, $d + cp b + jp c, .cant_raise_stat + ld a, [LoweredStat] + and $f0 + jr z, .got_num_stages + inc b + ld a, $d + cp b + jr nc, .got_num_stages + ld b, a +.got_num_stages + ld [hl], b + push hl + ld a, c + cp $5 + jr nc, .done_calcing_stats + ld hl, BattleMonStats + 1 + ld de, PlayerStats + ld a, [hBattleTurn] + and a + jr z, .got_stats_pointer + ld hl, EnemyMonStats + 1 + ld de, EnemyStats +.got_stats_pointer + push bc + sla c + ld b, 0 + add hl, bc + ld a, c + add e + ld e, a + jr nc, .no_carry + inc d +.no_carry + pop bc + ld a, [hld] + sub LOW(MAX_STAT_VALUE) + jr nz, .not_already_max + ld a, [hl] + sbc HIGH(MAX_STAT_VALUE) + jp z, .stats_already_max +.not_already_max + ld a, [hBattleTurn] + and a + jr z, .calc_player_stats + call CalcEnemyStats + jr .done_calcing_stats + +.calc_player_stats + call CalcPlayerStats +.done_calcing_stats + pop hl + xor a + ld [FailedMessage], a + ret + +; 3626e + + +.stats_already_max ; 3626e + pop hl + dec [hl] + ; fallthrough +; 36270 + + +.cant_raise_stat ; 36270 + ld a, $2 + ld [FailedMessage], a + ld a, $1 + ld [AttackMissed], a + ret + +; 3627b + + +.stat_raise_failed ; 3627b + ld a, $1 + ld [FailedMessage], a + ret + +; 36281 + + +StatUpAnimation: ; 36281 + ld bc, wPlayerMinimized + ld hl, DropPlayerSub + ld a, [hBattleTurn] + and a + jr z, .do_player + ld bc, wEnemyMinimized + ld hl, DropEnemySub +.do_player + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp MINIMIZE + ret nz + + ld a, $1 + ld [bc], a + call _CheckBattleScene + ret nc + + xor a + ld [hBGMapMode], a + call CallBattleCore + call WaitBGMap + jp BattleCommand_MoveDelay + +; 362ad + + +BattleCommand_AttackDown: ; 362ad +; attackdown + ld a, ATTACK + jr BattleCommand_StatDown + +BattleCommand_DefenseDown: ; 362b1 +; defensedown + ld a, DEFENSE + jr BattleCommand_StatDown + +BattleCommand_SpeedDown: ; 362b5 +; speeddown + ld a, SPEED + jr BattleCommand_StatDown + +BattleCommand_SpecialAttackDown: ; 362b9 +; specialattackdown + ld a, SP_ATTACK + jr BattleCommand_StatDown + +BattleCommand_SpecialDefenseDown: ; 362bd +; specialdefensedown + ld a, SP_DEFENSE + jr BattleCommand_StatDown + +BattleCommand_AccuracyDown: ; 362c1 +; accuracydown + ld a, ACCURACY + jr BattleCommand_StatDown + +BattleCommand_EvasionDown: ; 362c5 +; evasiondown + ld a, EVASION + jr BattleCommand_StatDown + +BattleCommand_AttackDown2: ; 362c9 +; attackdown2 + ld a, $10 | ATTACK + jr BattleCommand_StatDown + +BattleCommand_DefenseDown2: ; 362cd +; defensedown2 + ld a, $10 | DEFENSE + jr BattleCommand_StatDown + +BattleCommand_SpeedDown2: ; 362d1 +; speeddown2 + ld a, $10 | SPEED + jr BattleCommand_StatDown + +BattleCommand_SpecialAttackDown2: ; 362d5 +; specialattackdown2 + ld a, $10 | SP_ATTACK + jr BattleCommand_StatDown + +BattleCommand_SpecialDefenseDown2: ; 362d9 +; specialdefensedown2 + ld a, $10 | SP_DEFENSE + jr BattleCommand_StatDown + +BattleCommand_AccuracyDown2: ; 362dd +; accuracydown2 + ld a, $10 | ACCURACY + jr BattleCommand_StatDown + +BattleCommand_EvasionDown2: ; 362e1 +; evasiondown2 + ld a, $10 | EVASION + +BattleCommand_StatDown: ; 362e3 +; statdown + + ld [LoweredStat], a + + call CheckMist + jp nz, .Mist + + ld hl, EnemyStatLevels + ld a, [hBattleTurn] + and a + jr z, .GetStatLevel + ld hl, PlayerStatLevels + +.GetStatLevel: +; Attempt to lower the stat. + ld a, [LoweredStat] + and $f + ld c, a + ld b, 0 + add hl, bc + ld b, [hl] + dec b + jp z, .CantLower + +; Sharply lower the stat if applicable. + ld a, [LoweredStat] + and $f0 + jr z, .ComputerMiss + dec b + jr nz, .ComputerMiss + inc b + +.ComputerMiss: +; Computer opponents have a 1/4 chance of failing. + ld a, [hBattleTurn] + and a + jr z, .DidntMiss + + ld a, [wLinkMode] + and a + jr nz, .DidntMiss + + ld a, [InBattleTowerBattle] + and a + jr nz, .DidntMiss + +; Lock-On still always works. + ld a, [PlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .DidntMiss + +; Attacking moves that also lower accuracy are unaffected. + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_ACCURACY_DOWN_HIT + jr z, .DidntMiss + + call BattleRandom + cp $40 + jr c, .Failed + +.DidntMiss: + call CheckSubstituteOpp + jr nz, .Failed + + ld a, [AttackMissed] + and a + jr nz, .Failed + + ld a, [EffectFailed] + and a + jr nz, .Failed + + call CheckHiddenOpponent + jr nz, .Failed + +; Accuracy/Evasion reduction don't involve stats. + ld [hl], b + ld a, c + cp ACCURACY + jr nc, .Hit + + push hl + ld hl, EnemyMonAttack + 1 + ld de, EnemyStats + ld a, [hBattleTurn] + and a + jr z, .do_enemy + ld hl, BattleMonAttack + 1 + ld de, PlayerStats +.do_enemy + call TryLowerStat + pop hl + jr z, .CouldntLower + +.Hit: + xor a + ld [FailedMessage], a + ret + +.CouldntLower: + inc [hl] +.CantLower: + ld a, 3 + ld [FailedMessage], a + ld a, 1 + ld [AttackMissed], a + ret + +.Failed: + ld a, 1 + ld [FailedMessage], a + ld [AttackMissed], a + ret + +.Mist: + ld a, 2 + ld [FailedMessage], a + ld a, 1 + ld [AttackMissed], a + ret + +; 36391 + + +CheckMist: ; 36391 + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_ATTACK_DOWN + jr c, .dont_check_mist + cp EFFECT_EVASION_DOWN + 1 + jr c, .check_mist + cp EFFECT_ATTACK_DOWN_2 + jr c, .dont_check_mist + cp EFFECT_EVASION_DOWN_2 + 1 + jr c, .check_mist + cp EFFECT_ATTACK_DOWN_HIT + jr c, .dont_check_mist + cp EFFECT_EVASION_DOWN_HIT + 1 + jr c, .check_mist +.dont_check_mist + xor a + ret + +.check_mist + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVar + bit SUBSTATUS_MIST, a + ret + +; 363b8 + + +BattleCommand_StatUpMessage: ; 363b8 + ld a, [FailedMessage] + and a + ret nz + ld a, [LoweredStat] + and $f + ld b, a + inc b + call GetStatName + ld hl, .stat + jp BattleTextBox + +.stat + text_jump UnknownText_0x1c0cc6 + start_asm + ld hl, .up + ld a, [LoweredStat] + and $f0 + ret z + ld hl, .wayup + ret + +.wayup + text_jump UnknownText_0x1c0cd0 + db "@" + +.up + text_jump UnknownText_0x1c0ce0 + db "@" + +; 363e9 + + +BattleCommand_StatDownMessage: ; 363e9 + ld a, [FailedMessage] + and a + ret nz + ld a, [LoweredStat] + and $f + ld b, a + inc b + call GetStatName + ld hl, .stat + jp BattleTextBox + +.stat + text_jump UnknownText_0x1c0ceb + start_asm + ld hl, .fell + ld a, [LoweredStat] + and $f0 + ret z + ld hl, .sharplyfell + ret + +.sharplyfell + text_jump UnknownText_0x1c0cf5 + db "@" +.fell + text_jump UnknownText_0x1c0d06 + db "@" + +; 3641a + + +TryLowerStat: ; 3641a +; Lower stat c from stat struct hl (buffer de). + + push bc + sla c + ld b, 0 + add hl, bc + ; add de, c + ld a, c + add e + ld e, a + jr nc, .no_carry + inc d +.no_carry + pop bc + +; The lowest possible stat is 1. + ld a, [hld] + sub 1 + jr nz, .not_min + ld a, [hl] + and a + ret z + +.not_min + ld a, [hBattleTurn] + and a + jr z, .Player + + call BattleCommand_SwitchTurn + call CalcPlayerStats + call BattleCommand_SwitchTurn + jr .end + +.Player: + call BattleCommand_SwitchTurn + call CalcEnemyStats + call BattleCommand_SwitchTurn +.end + ld a, 1 + and a + ret + +; 3644c + + +BattleCommand_StatUpFailText: ; 3644c +; statupfailtext + ld a, [FailedMessage] + and a + ret z + push af + call BattleCommand_MoveDelay + pop af + dec a + jp z, TryPrintButItFailed + ld a, [LoweredStat] + and $f + ld b, a + inc b + call GetStatName + ld hl, WontRiseAnymoreText + jp StdBattleTextBox + +; 3646a + + +BattleCommand_StatDownFailText: ; 3646a +; statdownfailtext + ld a, [FailedMessage] + and a + ret z + push af + call BattleCommand_MoveDelay + pop af + dec a + jp z, TryPrintButItFailed + dec a + ld hl, ProtectedByMistText + jp z, StdBattleTextBox + ld a, [LoweredStat] + and $f + ld b, a + inc b + call GetStatName + ld hl, WontDropAnymoreText + jp StdBattleTextBox + +; 3648f + + +GetStatName: ; 3648f + ld hl, .names + ld c, "@" +.CheckName: + dec b + jr z, .Copy +.GetName: + ld a, [hli] + cp c + jr z, .CheckName + jr .GetName + +.Copy: + ld de, StringBuffer2 + ld bc, StringBuffer3 - StringBuffer2 + jp CopyBytes + +.names + db "ATTACK@" + db "DEFENSE@" + db "SPEED@" + db "SPCL.ATK@" + db "SPCL.DEF@" + db "ACCURACY@" + db "EVASION@" + db "ABILITY@" +; 364e6 + + +StatLevelMultipliers: ; 364e6 + db 25, 100 ; 0.25x + db 28, 100 ; 0.28x + db 33, 100 ; 0.33x + db 40, 100 ; 0.40x + db 50, 100 ; 0.50x + db 66, 100 ; 0.66x + db 1, 1 ; 1.00x + db 15, 10 ; 1.50x + db 2, 1 ; 2.00x + db 25, 10 ; 2.50x + db 3, 1 ; 3.00x + db 35, 10 ; 3.50x + db 4, 1 ; 4.00x +; 36500 + + +BattleCommand_AllStatsUp: ; 36500 +; allstatsup + +; Attack + call ResetMiss + call BattleCommand_AttackUp + call BattleCommand_StatUpMessage + +; Defense + call ResetMiss + call BattleCommand_DefenseUp + call BattleCommand_StatUpMessage + +; Speed + call ResetMiss + call BattleCommand_SpeedUp + call BattleCommand_StatUpMessage + +; Special Attack + call ResetMiss + call BattleCommand_SpecialAttackUp + call BattleCommand_StatUpMessage + +; Special Defense + call ResetMiss + call BattleCommand_SpecialDefenseUp + jp BattleCommand_StatUpMessage +; 3652d + + +ResetMiss: ; 3652d + xor a + ld [AttackMissed], a + ret + +; 36532 + + +LowerStat: ; 36532 + ld [LoweredStat], a + + ld hl, PlayerStatLevels + ld a, [hBattleTurn] + and a + jr z, .got_target + ld hl, EnemyStatLevels + +.got_target + ld a, [LoweredStat] + and $f + ld c, a + ld b, 0 + add hl, bc + ld b, [hl] + dec b + jr z, .cant_lower_anymore + + ld a, [LoweredStat] + and $f0 + jr z, .got_num_stages + dec b + jr nz, .got_num_stages + inc b + +.got_num_stages + ld [hl], b + ld a, c + cp 5 + jr nc, .accuracy_evasion + + push hl + ld hl, BattleMonStats + 1 + ld de, PlayerStats + ld a, [hBattleTurn] + and a + jr z, .got_target_2 + ld hl, EnemyMonStats + 1 + ld de, EnemyStats + +.got_target_2 + call TryLowerStat + pop hl + jr z, .failed + +.accuracy_evasion + ld a, [hBattleTurn] + and a + jr z, .player + + call CalcEnemyStats + + jr .finish + +.player + call CalcPlayerStats + +.finish + xor a + ld [FailedMessage], a + ret + +.failed + inc [hl] + +.cant_lower_anymore + ld a, 2 + ld [FailedMessage], a + ret + +; 3658f + + +BattleCommand_TriStatusChance: ; 3658f +; tristatuschance + + call BattleCommand_EffectChance + +; 1/3 chance of each status +.loop + call BattleRandom + swap a + and 3 + jr z, .loop +; jump + dec a + ld hl, .ptrs + rst JumpTable + ret + +.ptrs + dw BattleCommand_ParalyzeTarget ; paralyze + dw BattleCommand_FreezeTarget ; freeze + dw BattleCommand_BurnTarget ; burn +; 365a7 + + +BattleCommand_Curl: ; 365a7 +; curl + ld a, BATTLE_VARS_SUBSTATUS2 + call GetBattleVarAddr + set SUBSTATUS_CURLED, [hl] + ret + +; 365af + + +BattleCommand_RaiseSubNoAnim: ; 365af + ld hl, GetBattleMonBackpic + ld a, [hBattleTurn] + and a + jr z, .PlayerTurn + ld hl, GetEnemyMonFrontpic +.PlayerTurn: + xor a + ld [hBGMapMode], a + call CallBattleCore + jp WaitBGMap + +; 365c3 + + +BattleCommand_LowerSubNoAnim: ; 365c3 + ld hl, DropPlayerSub + ld a, [hBattleTurn] + and a + jr z, .PlayerTurn + ld hl, DropEnemySub +.PlayerTurn: + xor a + ld [hBGMapMode], a + call CallBattleCore + jp WaitBGMap + +; 365d7 + + +CalcPlayerStats: ; 365d7 + ld hl, PlayerAtkLevel + ld de, PlayerStats + ld bc, BattleMonAttack + + ld a, 5 + call CalcStats + + ld hl, BadgeStatBoosts + call CallBattleCore + + call BattleCommand_SwitchTurn + + ld hl, ApplyPrzEffectOnSpeed + call CallBattleCore + + ld hl, ApplyBrnEffectOnAttack + call CallBattleCore + + jp BattleCommand_SwitchTurn + +; 365fd + + +CalcEnemyStats: ; 365fd + ld hl, EnemyAtkLevel + ld de, EnemyStats + ld bc, EnemyMonAttack + + ld a, 5 + call CalcStats + + call BattleCommand_SwitchTurn + + ld hl, ApplyPrzEffectOnSpeed + call CallBattleCore + + ld hl, ApplyBrnEffectOnAttack + call CallBattleCore + + jp BattleCommand_SwitchTurn + +; 3661d + + +CalcStats: ; 3661d +.loop + push af + ld a, [hli] + push hl + push bc + + ld c, a + dec c + ld b, 0 + ld hl, StatLevelMultipliers + add hl, bc + add hl, bc + + xor a + ld [hMultiplicand + 0], a + ld a, [de] + ld [hMultiplicand + 1], a + inc de + ld a, [de] + ld [hMultiplicand + 2], a + inc de + + ld a, [hli] + ld [hMultiplier], a + call Multiply + + ld a, [hl] + ld [hDivisor], a + ld b, 4 + call Divide + + ld a, [hQuotient + 1] + ld b, a + ld a, [hQuotient + 2] + or b + jr nz, .check_maxed_out + + ld a, 1 + ld [hQuotient + 2], a + jr .not_maxed_out + +.check_maxed_out + ld a, [hQuotient + 2] + cp LOW(MAX_STAT_VALUE) + ld a, b + sbc HIGH(MAX_STAT_VALUE) + jr c, .not_maxed_out + + ld a, LOW(MAX_STAT_VALUE) + ld [hQuotient + 2], a + ld a, HIGH(MAX_STAT_VALUE) + ld [hQuotient + 1], a + +.not_maxed_out + pop bc + ld a, [hQuotient + 1] + ld [bc], a + inc bc + ld a, [hQuotient + 2] + ld [bc], a + inc bc + pop hl + pop af + dec a + jr nz, .loop + + ret + +; 36671 + + +BattleCommand_StoreEnergy: ; 36671 +; storeenergy + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + bit SUBSTATUS_BIDE, a + ret z + + ld hl, PlayerRolloutCount + ld a, [hBattleTurn] + and a + jr z, .check_still_storing_energy + ld hl, EnemyRolloutCount +.check_still_storing_energy + dec [hl] + jr nz, .still_storing + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + res SUBSTATUS_BIDE, [hl] + + ld hl, UnleashedEnergyText + call StdBattleTextBox + + ld a, BATTLE_VARS_MOVE_POWER + call GetBattleVarAddr + ld a, 1 + ld [hl], a + ld hl, PlayerDamageTaken + 1 + ld de, wPlayerCharging ; player + ld a, [hBattleTurn] + and a + jr z, .player + ld hl, EnemyDamageTaken + 1 + ld de, wEnemyCharging ; enemy +.player + ld a, [hld] + add a + ld b, a + ld [CurDamage + 1], a + ld a, [hl] + rl a + ld [CurDamage], a + jr nc, .not_maxed + ld a, $ff + ld [CurDamage], a + ld [CurDamage + 1], a +.not_maxed + or b + jr nz, .built_up_something + ld a, 1 + ld [AttackMissed], a +.built_up_something + xor a + ld [hli], a + ld [hl], a + ld [de], a + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVarAddr + ld a, BIDE + ld [hl], a + + ld b, unleashenergy_command + jp SkipToBattleCommand + +.still_storing + ld hl, StoringEnergyText + call StdBattleTextBox + jp EndMoveEffect + +; 366e5 + + +BattleCommand_UnleashEnergy: ; 366e5 +; unleashenergy + + ld de, PlayerDamageTaken + ld bc, PlayerRolloutCount + ld a, [hBattleTurn] + and a + jr z, .got_damage + ld de, EnemyDamageTaken + ld bc, EnemyRolloutCount +.got_damage + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + set SUBSTATUS_BIDE, [hl] + xor a + ld [de], a + inc de + ld [de], a + ld [wPlayerMoveStructEffect], a + ld [wEnemyMoveStructEffect], a + call BattleRandom + and 1 + inc a + inc a + ld [bc], a + ld a, 1 + ld [wKickCounter], a + call AnimateCurrentMove + jp EndMoveEffect + +; 3671a + + +BattleCommand_CheckRampage: ; 3671a +; checkrampage + + ld de, PlayerRolloutCount + ld a, [hBattleTurn] + and a + jr z, .player + ld de, EnemyRolloutCount +.player + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + bit SUBSTATUS_RAMPAGE, [hl] + ret z + ld a, [de] + dec a + ld [de], a + jr nz, .continue_rampage + + res SUBSTATUS_RAMPAGE, [hl] + call BattleCommand_SwitchTurn + call SafeCheckSafeguard + push af + call BattleCommand_SwitchTurn + pop af + jr nz, .continue_rampage + + set SUBSTATUS_CONFUSED, [hl] + call BattleRandom + and %00000001 + inc a + inc a + inc de ; ConfuseCount + ld [de], a +.continue_rampage + ld b, rampage_command + jp SkipToBattleCommand + +; 36751 + + +BattleCommand_Rampage: ; 36751 +; rampage + +; No rampage during Sleep Talk. + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + ret nz + + ld de, PlayerRolloutCount + ld a, [hBattleTurn] + and a + jr z, .ok + ld de, EnemyRolloutCount +.ok + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + set SUBSTATUS_RAMPAGE, [hl] +; Rampage for 1 or 2 more turns + call BattleRandom + and %00000001 + inc a + ld [de], a + ld a, 1 + ld [wSomeoneIsRampaging], a + ret + +; 36778 + + +BattleCommand_Teleport: ; 36778 +; teleport + + ld a, [BattleType] + cp BATTLETYPE_SHINY + jr z, .failed + cp BATTLETYPE_TRAP + jr z, .failed + cp BATTLETYPE_CELEBI + jr z, .failed + cp BATTLETYPE_SUICUNE + jr z, .failed + + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVar + bit SUBSTATUS_CANT_RUN, a + jr nz, .failed +; Only need to check these next things if it's your turn + ld a, [hBattleTurn] + and a + jr nz, .enemy_turn +; Can't teleport from a trainer battle + ld a, [wBattleMode] + dec a + jr nz, .failed +; If your level is greater than the opponent's, you run without fail. + ld a, [CurPartyLevel] + ld b, a + ld a, [BattleMonLevel] + cp b + jr nc, .run_away +; Generate a number between 0 and (YourLevel + TheirLevel). + add b + ld c, a + inc c +.loop_player + call BattleRandom + cp c + jr nc, .loop_player +; If that number is greater than 4 times your level, run away. + srl b + srl b + cp b + jr nc, .run_away + +.failed + call AnimateFailedMove + jp PrintButItFailed + +.enemy_turn + ld a, [wBattleMode] + dec a + jr nz, .failed + ld a, [BattleMonLevel] + ld b, a + ld a, [CurPartyLevel] + cp b + jr nc, .run_away + add b + ld c, a + inc c +.loop_enemy + call BattleRandom + cp c + jr nc, .loop_enemy + srl b + srl b + cp b + ; This does the wrong thing. What was + ; probably intended was jr c, .failed + ; The way this is made makes enemy use + ; of Teleport always succeed if able + jr nc, .run_away +.run_away + call UpdateBattleMonInParty + xor a + ld [wNumHits], a + inc a + ld [wForcedSwitch], a + ld [wKickCounter], a + call SetBattleDraw + call BattleCommand_LowerSub + call LoadMoveAnim + ld c, 20 + call DelayFrames + call SetBattleDraw + + ld hl, FledFromBattleText + jp StdBattleTextBox + +; 36804 + + +SetBattleDraw: ; 36804 + ld a, [wBattleResult] + and $c0 + or $2 + ld [wBattleResult], a + ret + +; 3680f + + +BattleCommand_ForceSwitch: ; 3680f +; forceswitch + + ld a, [BattleType] + cp BATTLETYPE_SHINY + jp z, .fail + cp BATTLETYPE_TRAP + jp z, .fail + cp BATTLETYPE_CELEBI + jp z, .fail + cp BATTLETYPE_SUICUNE + jp z, .fail + ld a, [hBattleTurn] + and a + jp nz, .force_player_switch + ld a, [AttackMissed] + and a + jr nz, .missed + ld a, [wBattleMode] + dec a + jr nz, .trainer + ld a, [CurPartyLevel] + ld b, a + ld a, [BattleMonLevel] + cp b + jr nc, .wild_force_flee + add b + ld c, a + inc c +.random_loop_wild + call BattleRandom + cp c + jr nc, .random_loop_wild + srl b + srl b + cp b + jr nc, .wild_force_flee +.missed + jp .fail + +.wild_force_flee + call UpdateBattleMonInParty + xor a + ld [wNumHits], a + inc a + ld [wForcedSwitch], a + call SetBattleDraw + ld a, [wPlayerMoveStructAnimation] + jp .succeed + +.trainer + call FindAliveEnemyMons + jr c, .switch_fail + ld a, [wEnemyGoesFirst] + and a + jr z, .switch_fail + call UpdateEnemyMonInParty + ld a, $1 + ld [wKickCounter], a + call AnimateCurrentMove + ld c, $14 + call DelayFrames + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + ld c, 20 + call DelayFrames + ld a, [OTPartyCount] + ld b, a + ld a, [CurOTMon] + ld c, a +; select a random enemy mon to switch to +.random_loop_trainer + call BattleRandom + and $7 + cp b + jr nc, .random_loop_trainer + cp c + jr z, .random_loop_trainer + push af + push bc + ld hl, OTPartyMon1HP + call GetPartyLocation + ld a, [hli] + or [hl] + pop bc + pop de + jr z, .random_loop_trainer + ld a, d + inc a + ld [wEnemySwitchMonIndex], a + callfar ForceEnemySwitch + + ld hl, DraggedOutText + call StdBattleTextBox + + ld hl, SpikesDamage + jp CallBattleCore + +.switch_fail + jp .fail + +.force_player_switch + ld a, [AttackMissed] + and a + jr nz, .player_miss + + ld a, [wBattleMode] + dec a + jr nz, .vs_trainer + + ld a, [BattleMonLevel] + ld b, a + ld a, [CurPartyLevel] + cp b + jr nc, .wild_succeed_playeristarget + + add b + ld c, a + inc c +.wild_random_loop_playeristarget + call BattleRandom + cp c + jr nc, .wild_random_loop_playeristarget + + srl b + srl b + cp b + jr nc, .wild_succeed_playeristarget + +.player_miss + jr .fail + +.wild_succeed_playeristarget + call UpdateBattleMonInParty + xor a + ld [wNumHits], a + inc a + ld [wForcedSwitch], a + call SetBattleDraw + ld a, [wEnemyMoveStructAnimation] + jr .succeed + +.vs_trainer + call CheckPlayerHasMonToSwitchTo + jr c, .fail + + ld a, [wEnemyGoesFirst] + cp $1 + jr z, .switch_fail + + call UpdateBattleMonInParty + ld a, $1 + ld [wKickCounter], a + call AnimateCurrentMove + ld c, 20 + call DelayFrames + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + ld c, 20 + call DelayFrames + ld a, [PartyCount] + ld b, a + ld a, [CurBattleMon] + ld c, a +.random_loop_trainer_playeristarget + call BattleRandom + and $7 + cp b + jr nc, .random_loop_trainer_playeristarget + + cp c + jr z, .random_loop_trainer_playeristarget + + push af + push bc + ld hl, PartyMon1HP + call GetPartyLocation + ld a, [hli] + or [hl] + pop bc + pop de + jr z, .random_loop_trainer_playeristarget + + ld a, d + ld [CurPartyMon], a + ld hl, SwitchPlayerMon + call CallBattleCore + + ld hl, DraggedOutText + call StdBattleTextBox + + ld hl, SpikesDamage + jp CallBattleCore + +.fail + call BattleCommand_LowerSub + call BattleCommand_MoveDelay + call BattleCommand_RaiseSub + jp PrintButItFailed + +.succeed + push af + call SetBattleDraw + ld a, $1 + ld [wKickCounter], a + call AnimateCurrentMove + ld c, 20 + call DelayFrames + pop af + + ld hl, FledInFearText + cp ROAR + jr z, .do_text + ld hl, BlownAwayText +.do_text + jp StdBattleTextBox + +; 36994 + + +CheckPlayerHasMonToSwitchTo: ; 36994 + ld a, [PartyCount] + ld d, a + ld e, 0 + ld bc, PARTYMON_STRUCT_LENGTH +.loop + ld a, [CurBattleMon] + cp e + jr z, .next + + ld a, e + ld hl, PartyMon1HP + call AddNTimes + ld a, [hli] + or [hl] + jr nz, .not_fainted + +.next + inc e + dec d + jr nz, .loop + + scf + ret + +.not_fainted + and a + ret + +; 369b6 + + +BattleCommand_EndLoop: ; 369b6 +; endloop + +; Loop back to the command before 'critical'. + + ld de, PlayerRolloutCount + ld bc, PlayerDamageTaken + ld a, [hBattleTurn] + and a + jr z, .got_addrs + ld de, EnemyRolloutCount + ld bc, EnemyDamageTaken +.got_addrs + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + bit SUBSTATUS_IN_LOOP, [hl] + jp nz, .in_loop + set SUBSTATUS_IN_LOOP, [hl] + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVarAddr + ld a, [hl] + cp EFFECT_POISON_MULTI_HIT + jr z, .twineedle + cp EFFECT_DOUBLE_HIT + ld a, 1 + jr z, .double_hit + ld a, [hl] + cp EFFECT_BEAT_UP + jr z, .beat_up + cp EFFECT_TRIPLE_KICK + jr nz, .not_triple_kick +.reject_triple_kick_sample + call BattleRandom + and $3 + jr z, .reject_triple_kick_sample + dec a + jr nz, .double_hit + ld a, 1 + ld [bc], a + jr .done_loop + +.beat_up + ld a, [hBattleTurn] + and a + jr nz, .check_ot_beat_up + ld a, [PartyCount] + cp 1 + jp z, .only_one_beatup + dec a + jr .double_hit + +.check_ot_beat_up + ld a, [wBattleMode] + cp WILD_BATTLE + jp z, .only_one_beatup + ld a, [OTPartyCount] + cp 1 + jp z, .only_one_beatup + dec a + jr .double_hit + +.only_one_beatup + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + res SUBSTATUS_IN_LOOP, [hl] + call BattleCommanda8 + jp EndMoveEffect + +.not_triple_kick + call BattleRandom + and $3 + cp 2 + jr c, .got_number_hits + call BattleRandom + and $3 +.got_number_hits + inc a +.double_hit + ld [de], a + inc a + ld [bc], a + jr .loop_back_to_critical + +.twineedle + ld a, 1 + jr .double_hit + +.in_loop + ld a, [de] + dec a + ld [de], a + jr nz, .loop_back_to_critical +.done_loop + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + res SUBSTATUS_IN_LOOP, [hl] + + ld hl, PlayerHitTimesText + ld a, [hBattleTurn] + and a + jr z, .got_hit_n_times_text + ld hl, EnemyHitTimesText +.got_hit_n_times_text + + push bc + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_BEAT_UP + jr z, .beat_up_2 + call StdBattleTextBox +.beat_up_2 + + pop bc + xor a + ld [bc], a + ret + +; Loop back to the command before 'critical'. +.loop_back_to_critical + ld a, [BattleScriptBufferAddress + 1] + ld h, a + ld a, [BattleScriptBufferAddress] + ld l, a +.not_critical + ld a, [hld] + cp critical_command + jr nz, .not_critical + inc hl + ld a, h + ld [BattleScriptBufferAddress + 1], a + ld a, l + ld [BattleScriptBufferAddress], a + ret + +; 36a82 + + +BattleCommand_FakeOut: ; 36a82 + ld a, [AttackMissed] + and a + ret nz + + call CheckSubstituteOpp + jr nz, .fail + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVar + and 1 << FRZ | SLP + jr nz, .fail + + call CheckOpponentWentFirst + jr z, FlinchTarget + +.fail + ld a, 1 + ld [AttackMissed], a + ret + +; 36aa0 + + +BattleCommand_FlinchTarget: ; 36aa0 + call CheckSubstituteOpp + ret nz + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVar + and 1 << FRZ | SLP + ret nz + + call CheckOpponentWentFirst + ret nz + + ld a, [EffectFailed] + and a + ret nz + + ; fallthrough +; 36ab5 + + +FlinchTarget: ; 36ab5 + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVarAddr + set SUBSTATUS_FLINCHED, [hl] + jp EndRechargeOpp + +; 36abf + + +CheckOpponentWentFirst: ; 36abf +; Returns a=0, z if user went first +; Returns a=1, nz if opponent went first + push bc + ld a, [wEnemyGoesFirst] ; 0 if player went first + ld b, a + ld a, [hBattleTurn] ; 0 if it's the player's turn + xor b ; 1 if opponent went first + pop bc + ret + +; 36ac9 + + +BattleCommand_HeldFlinch: ; 36ac9 +; kingsrock + + ld a, [AttackMissed] + and a + ret nz + + call GetUserItem + ld a, b + cp HELD_FLINCH + ret nz + + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVarAddr + ld d, h + ld e, l + call GetUserItem + call BattleRandom + cp c + ret nc + call EndRechargeOpp + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVarAddr + set SUBSTATUS_FLINCHED, [hl] + ret + +; 36af3 + + +BattleCommand_OHKO: ; 36af3 +; ohko + + call ResetDamage + ld a, [TypeModifier] + and $7f + jr z, .no_effect + ld hl, EnemyMonLevel + ld de, BattleMonLevel + ld bc, wPlayerMoveStruct + MOVE_ACC + ld a, [hBattleTurn] + and a + jr z, .got_move_accuracy + push hl + ld h, d + ld l, e + pop de + ld bc, wEnemyMoveStruct + MOVE_ACC +.got_move_accuracy + ld a, [de] + sub [hl] + jr c, .no_effect + add a + ld e, a + ld a, [bc] + add e + jr nc, .finish_ohko + ld a, $ff +.finish_ohko + ld [bc], a + call BattleCommand_CheckHit + ld hl, CurDamage + ld a, $ff + ld [hli], a + ld [hl], a + ld a, $2 + ld [CriticalHit], a + ret + +.no_effect + ld a, $ff + ld [CriticalHit], a + ld a, $1 + ld [AttackMissed], a + ret + +; 36b3a + + +BattleCommand_CheckCharge: ; 36b3a +; checkcharge + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + bit SUBSTATUS_CHARGED, [hl] + ret z + res SUBSTATUS_CHARGED, [hl] + res SUBSTATUS_UNDERGROUND, [hl] + res SUBSTATUS_FLYING, [hl] + ld b, charge_command + jp SkipToBattleCommand + +; 36b4d + + +BattleCommand_Charge: ; 36b4d +; charge + + call BattleCommand_ClearText + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + jr z, .awake + + call BattleCommand_MoveDelay + call BattleCommand_RaiseSub + call PrintButItFailed + jp EndMoveEffect + +.awake + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + set SUBSTATUS_CHARGED, [hl] + + ld hl, IgnoredOrders2Text + ld a, [AlreadyDisobeyed] + and a + call nz, StdBattleTextBox + + call BattleCommand_LowerSub + xor a + ld [wNumHits], a + inc a + ld [wKickCounter], a + call LoadMoveAnim + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp FLY + jr z, .flying + cp DIG + jr z, .flying + call BattleCommand_RaiseSub + jr .not_flying + +.flying + call DisappearUser +.not_flying + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld b, a + cp FLY + jr z, .set_flying + cp DIG + jr nz, .dont_set_digging + set SUBSTATUS_UNDERGROUND, [hl] + jr .dont_set_digging + +.set_flying + set SUBSTATUS_FLYING, [hl] + +.dont_set_digging + call CheckUserIsCharging + jr nz, .mimic + ld a, BATTLE_VARS_LAST_COUNTER_MOVE + call GetBattleVarAddr + ld [hl], b + ld a, BATTLE_VARS_LAST_MOVE + call GetBattleVarAddr + ld [hl], b + +.mimic + call ResetDamage + + ld hl, .UsedText + call BattleTextBox + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_SKULL_BASH + ld b, endturn_command + jp z, SkipToBattleCommand + jp EndMoveEffect + +.UsedText: + text_jump UnknownText_0x1c0d0e ; "[USER]" + start_asm + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp RAZOR_WIND + ld hl, .RazorWind + jr z, .done + + cp SOLARBEAM + ld hl, .Solarbeam + jr z, .done + + cp SKULL_BASH + ld hl, .SkullBash + jr z, .done + + cp SKY_ATTACK + ld hl, .SkyAttack + jr z, .done + + cp FLY + ld hl, .Fly + jr z, .done + + cp DIG + ld hl, .Dig + +.done + ret + +.RazorWind: +; 'made a whirlwind!' + text_jump UnknownText_0x1c0d12 + db "@" + +.Solarbeam: +; 'took in sunlight!' + text_jump UnknownText_0x1c0d26 + db "@" + +.SkullBash: +; 'lowered its head!' + text_jump UnknownText_0x1c0d3a + db "@" + +.SkyAttack: +; 'is glowing!' + text_jump UnknownText_0x1c0d4e + db "@" + +.Fly: +; 'flew up high!' + text_jump UnknownText_0x1c0d5c + db "@" + +.Dig: +; 'dug a hole!' + text_jump UnknownText_0x1c0d6c + db "@" +; 36c2c + + +BattleCommand3c: ; 36c2c +; unused + ret + +; 36c2d + + +BattleCommand_TrapTarget: ; 36c2d +; traptarget + + ld a, [AttackMissed] + and a + ret nz + ld hl, wEnemyWrapCount + ld de, wEnemyTrappingMove + ld a, [hBattleTurn] + and a + jr z, .got_trap + ld hl, wPlayerWrapCount + ld de, wPlayerTrappingMove + +.got_trap + ld a, [hl] + and a + ret nz + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + ret nz + call BattleRandom + and 3 + inc a + inc a + inc a + ld [hl], a + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld [de], a + ld b, a + ld hl, .Traps + +.find_trap_text + ld a, [hli] + cp b + jr z, .found_trap_text + inc hl + inc hl + jr .find_trap_text + +.found_trap_text + ld a, [hli] + ld h, [hl] + ld l, a + jp StdBattleTextBox + +.Traps: + dbw BIND, UsedBindText ; 'used BIND on' + dbw WRAP, WrappedByText ; 'was WRAPPED by' + dbw FIRE_SPIN, FireSpinTrapText ; 'was trapped!' + dbw CLAMP, ClampedByText ; 'was CLAMPED by' + dbw WHIRLPOOL, WhirlpoolTrapText ; 'was trapped!' +; 36c7e + + +BattleCommand_Mist: ; 36c7e +; mist + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + bit SUBSTATUS_MIST, [hl] + jr nz, .already_mist + set SUBSTATUS_MIST, [hl] + call AnimateCurrentMove + ld hl, MistText + jp StdBattleTextBox + +.already_mist + call AnimateFailedMove + jp PrintButItFailed + +; 36c98 + + +BattleCommand_FocusEnergy: ; 36c98 +; focusenergy + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + bit SUBSTATUS_FOCUS_ENERGY, [hl] + jr nz, .already_pumped + set SUBSTATUS_FOCUS_ENERGY, [hl] + call AnimateCurrentMove + ld hl, GettingPumpedText + jp StdBattleTextBox + +.already_pumped + call AnimateFailedMove + jp PrintButItFailed + +; 36cb2 + + +BattleCommand_Recoil: ; 36cb2 +; recoil + + ld hl, BattleMonMaxHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, EnemyMonMaxHP +.got_hp + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld d, a +; get 1/4 damage or 1 HP, whichever is higher + ld a, [CurDamage] + ld b, a + ld a, [CurDamage + 1] + ld c, a + srl b + rr c + srl b + rr c + ld a, b + or c + jr nz, .min_damage + inc c +.min_damage + ld a, [hli] + ld [Buffer2], a + ld a, [hl] + ld [Buffer1], a + dec hl + dec hl + ld a, [hl] + ld [Buffer3], a + sub c + ld [hld], a + ld [Buffer5], a + ld a, [hl] + ld [Buffer4], a + sbc b + ld [hl], a + ld [Buffer6], a + jr nc, .dont_ko + xor a + ld [hli], a + ld [hl], a + ld hl, Buffer5 + ld [hli], a + ld [hl], a +.dont_ko + hlcoord 10, 9 + ld a, [hBattleTurn] + and a + ld a, 1 + jr z, .animate_hp_bar + hlcoord 2, 2 + xor a +.animate_hp_bar + ld [wWhichHPBar], a + predef AnimateHPBar + call RefreshBattleHuds + ld hl, RecoilText + jp StdBattleTextBox + +; 36d1d + + +BattleCommand_ConfuseTarget: ; 36d1d +; confusetarget + + call GetOpponentItem + ld a, b + cp HELD_PREVENT_CONFUSE + ret z + ld a, [EffectFailed] + and a + ret nz + call SafeCheckSafeguard + ret nz + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVarAddr + bit SUBSTATUS_CONFUSED, [hl] + ret nz + jr BattleCommand_FinishConfusingTarget + + +BattleCommand_Confuse: ; 36d3b +; confuse + + call GetOpponentItem + ld a, b + cp HELD_PREVENT_CONFUSE + jr nz, .no_item_protection + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetItemName + call AnimateFailedMove + ld hl, ProtectedByText + jp StdBattleTextBox + +.no_item_protection + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVarAddr + bit SUBSTATUS_CONFUSED, [hl] + jr z, .not_already_confused + call AnimateFailedMove + ld hl, AlreadyConfusedText + jp StdBattleTextBox + +.not_already_confused + call CheckSubstituteOpp + jr nz, BattleCommand_Confuse_CheckSnore_Swagger_ConfuseHit + ld a, [AttackMissed] + and a + jr nz, BattleCommand_Confuse_CheckSnore_Swagger_ConfuseHit +BattleCommand_FinishConfusingTarget: ; 36d70 + ld bc, EnemyConfuseCount + ld a, [hBattleTurn] + and a + jr z, .got_confuse_count + ld bc, PlayerConfuseCount + +.got_confuse_count + set SUBSTATUS_CONFUSED, [hl] + call BattleRandom + and 3 + inc a + inc a + ld [bc], a + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_CONFUSE_HIT + jr z, .got_effect + cp EFFECT_SNORE + jr z, .got_effect + cp EFFECT_SWAGGER + jr z, .got_effect + call AnimateCurrentMove + +.got_effect + ld de, ANIM_CONFUSED + call PlayOpponentBattleAnim + + ld hl, BecameConfusedText + call StdBattleTextBox + + call GetOpponentItem + ld a, b + cp HELD_HEAL_STATUS + jr z, .heal_confusion + cp HELD_HEAL_CONFUSION + ret nz +.heal_confusion + ld hl, UseConfusionHealingItem + jp CallBattleCore + +; 36db6 + +BattleCommand_Confuse_CheckSnore_Swagger_ConfuseHit: ; 36db6 + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_CONFUSE_HIT + ret z + cp EFFECT_SNORE + ret z + cp EFFECT_SWAGGER + ret z + jp PrintDidntAffect2 + +; 36dc7 + + +BattleCommand_Paralyze: ; 36dc7 +; paralyze + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVar + bit PAR, a + jr nz, .paralyzed + ld a, [TypeModifier] + and $7f + jr z, .didnt_affect + call GetOpponentItem + ld a, b + cp HELD_PREVENT_PARALYZE + jr nz, .no_item_protection + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetItemName + call AnimateFailedMove + ld hl, ProtectedByText + jp StdBattleTextBox + +.no_item_protection + ld a, [hBattleTurn] + and a + jr z, .dont_sample_failure + + ld a, [wLinkMode] + and a + jr nz, .dont_sample_failure + + ld a, [InBattleTowerBattle] + and a + jr nz, .dont_sample_failure + + ld a, [PlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .dont_sample_failure + + call BattleRandom + cp 1 + 25 percent + jr c, .failed + +.dont_sample_failure + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + jr nz, .failed + ld a, [AttackMissed] + and a + jr nz, .failed + call CheckSubstituteOpp + jr nz, .failed + ld c, 30 + call DelayFrames + call AnimateCurrentMove + ld a, $1 + ld [hBGMapMode], a + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + set PAR, [hl] + call UpdateOpponentInParty + ld hl, ApplyPrzEffectOnSpeed + call CallBattleCore + call UpdateBattleHuds + call PrintParalyze + ld hl, UseHeldStatusHealingItem + jp CallBattleCore + +.paralyzed + call AnimateFailedMove + ld hl, AlreadyParalyzedText + jp StdBattleTextBox + +.failed + jp PrintDidntAffect2 + +.didnt_affect + call AnimateFailedMove + jp PrintDoesntAffect + +; 36e5b + + +CheckMoveTypeMatchesTarget: ; 36e5b +; Compare move type to opponent type. +; Return z if matching the opponent type, +; unless the move is Normal (Tri Attack). + + push hl + + ld hl, EnemyMonType1 + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, BattleMonType1 +.ok + + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVar + cp NORMAL + jr z, .normal + + cp [hl] + jr z, .return + + inc hl + cp [hl] + +.return + pop hl + ret + +.normal + ld a, 1 + and a + pop hl + ret + +; 36e7c + + +BattleCommand_Substitute: ; 36e7c +; substitute + + call BattleCommand_MoveDelay + ld hl, BattleMonMaxHP + ld de, PlayerSubstituteHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, EnemyMonMaxHP + ld de, EnemySubstituteHP +.got_hp + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + jr nz, .already_has_sub + + ld a, [hli] + ld b, [hl] + srl a + rr b + srl a + rr b + dec hl + dec hl + ld a, b + ld [de], a + ld a, [hld] + sub b + ld e, a + ld a, [hl] + sbc 0 + ld d, a + jr c, .too_weak_to_sub + ld a, d + or e + jr z, .too_weak_to_sub + ld [hl], d + inc hl + ld [hl], e + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + set SUBSTATUS_SUBSTITUTE, [hl] + + ld hl, wPlayerWrapCount + ld de, wPlayerTrappingMove + ld a, [hBattleTurn] + and a + jr z, .player + ld hl, wEnemyWrapCount + ld de, wEnemyTrappingMove +.player + + xor a + ld [hl], a + ld [de], a + call _CheckBattleScene + jr c, .no_anim + + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + ld [wKickCounter], a + ld a, SUBSTITUTE + call LoadAnim + jr .finish + +.no_anim + call BattleCommand_RaiseSubNoAnim +.finish + ld hl, MadeSubstituteText + call StdBattleTextBox + jp RefreshBattleHuds + +.already_has_sub + call CheckUserIsCharging + call nz, BattleCommand_RaiseSub + ld hl, HasSubstituteText + jr .jp_stdbattletextbox + +.too_weak_to_sub + call CheckUserIsCharging + call nz, BattleCommand_RaiseSub + ld hl, TooWeakSubText +.jp_stdbattletextbox + jp StdBattleTextBox + +; 36f0b + +BattleCommand_RechargeNextTurn: ; 36f0b +; rechargenextturn + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + set SUBSTATUS_RECHARGE, [hl] + ret + +; 36f13 + + +EndRechargeOpp: ; 36f13 + push hl + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVarAddr + res SUBSTATUS_RECHARGE, [hl] + pop hl + ret + +; 36f1d + + +BattleCommand_Rage: ; 36f1d +; rage + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + set SUBSTATUS_RAGE, [hl] + ret + +; 36f25 + + +BattleCommand_DoubleFlyingDamage: ; 36f25 +; doubleflyingdamage + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + bit SUBSTATUS_FLYING, a + ret z + jr DoubleDamage + +; 36f2f + + +BattleCommand_DoubleUndergroundDamage: ; 36f2f +; doubleundergrounddamage + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + bit SUBSTATUS_UNDERGROUND, a + ret z + + ; fallthrough +; 36f37 + + +DoubleDamage: ; 36f37 + ld hl, CurDamage + 1 + sla [hl] + dec hl + rl [hl] + jr nc, .quit + + ld a, $ff + ld [hli], a + ld [hl], a +.quit + ret + +; 36f46 + + +BattleCommand_Mimic: ; 36f46 +; mimic + + call ClearLastMove + call BattleCommand_MoveDelay + ld a, [AttackMissed] + and a + jr nz, .fail + ld hl, BattleMonMoves + ld a, [hBattleTurn] + and a + jr z, .player_turn + ld hl, EnemyMonMoves +.player_turn + call CheckHiddenOpponent + jr nz, .fail + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + and a + jr z, .fail + cp STRUGGLE + jr z, .fail + ld b, a + ld c, NUM_MOVES +.check_already_knows_move + ld a, [hli] + cp b + jr z, .fail + dec c + jr nz, .check_already_knows_move + dec hl +.find_mimic + ld a, [hld] + cp MIMIC + jr nz, .find_mimic + inc hl + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + ld [hl], a + ld [wNamedObjectIndexBuffer], a + ld bc, BattleMonPP - BattleMonMoves + add hl, bc + ld [hl], 5 + call GetMoveName + call AnimateCurrentMove + ld hl, LearnedMoveText + jp StdBattleTextBox + +.fail + jp FailMimic + +; 36f9d + + +BattleCommand_LeechSeed: ; 36f9d +; leechseed + ld a, [AttackMissed] + and a + jr nz, .evaded + call CheckSubstituteOpp + jr nz, .evaded + + ld de, EnemyMonType1 + ld a, [hBattleTurn] + and a + jr z, .ok + ld de, BattleMonType1 +.ok + + ld a, [de] + cp GRASS + jr z, .grass + inc de + ld a, [de] + cp GRASS + jr z, .grass + + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVarAddr + bit SUBSTATUS_LEECH_SEED, [hl] + jr nz, .evaded + set SUBSTATUS_LEECH_SEED, [hl] + call AnimateCurrentMove + ld hl, WasSeededText + jp StdBattleTextBox + +.grass + call AnimateFailedMove + jp PrintDoesntAffect + +.evaded + call AnimateFailedMove + ld hl, EvadedText + jp StdBattleTextBox + +; 36fe1 + + +BattleCommand_Splash: ; 36fe1 + call AnimateCurrentMove + farcall TrainerRankings_Splash + jp PrintNothingHappened + +; 36fed + + +BattleCommand_Disable: ; 36fed +; disable + + ld a, [AttackMissed] + and a + jr nz, .failed + + ld de, EnemyDisableCount + ld hl, EnemyMonMoves + ld a, [hBattleTurn] + and a + jr z, .got_moves + ld de, PlayerDisableCount + ld hl, BattleMonMoves +.got_moves + + ld a, [de] + and a + jr nz, .failed + + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + and a + jr z, .failed + cp STRUGGLE + jr z, .failed + + ld b, a + ld c, $ff +.loop + inc c + ld a, [hli] + cp b + jr nz, .loop + + ld a, [hBattleTurn] + and a + ld hl, EnemyMonPP + jr z, .got_pp + ld hl, BattleMonPP +.got_pp + ld b, 0 + add hl, bc + ld a, [hl] + and a + jr z, .failed +.loop2 + call BattleRandom + and 7 + jr z, .loop2 + inc a + inc c + swap c + add c + ld [de], a + call AnimateCurrentMove + ld hl, DisabledMove + ld a, [hBattleTurn] + and a + jr nz, .got_disabled_move_pointer + inc hl +.got_disabled_move_pointer + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + ld [hl], a + ld [wNamedObjectIndexBuffer], a + call GetMoveName + ld hl, WasDisabledText + jp StdBattleTextBox + +.failed + jp FailDisable + +; 3705c + + +BattleCommand_PayDay: ; 3705c +; payday + + xor a + ld hl, StringBuffer1 + ld [hli], a + + ld a, [hBattleTurn] + and a + ld a, [BattleMonLevel] + jr z, .ok + ld a, [EnemyMonLevel] +.ok + + add a + ld hl, wPayDayMoney + 2 + add [hl] + ld [hld], a + jr nc, .done + inc [hl] + dec hl + jr nz, .done + inc [hl] +.done + ld hl, CoinsScatteredText + jp StdBattleTextBox + +; 3707f + + +BattleCommand_Conversion: ; 3707f +; conversion + + ld hl, BattleMonMoves + ld de, BattleMonType1 + ld a, [hBattleTurn] + and a + jr z, .got_moves + ld hl, EnemyMonMoves + ld de, EnemyMonType1 +.got_moves + push de + ld c, 0 + ld de, StringBuffer1 +.loop + push hl + ld b, 0 + add hl, bc + ld a, [hl] + pop hl + and a + jr z, .okay + push hl + push bc + dec a + ld hl, Moves + MOVE_TYPE + call GetMoveAttr + ld [de], a + inc de + pop bc + pop hl + inc c + ld a, c + cp NUM_MOVES + jr c, .loop +.okay + ld a, $ff + ld [de], a + inc de + ld [de], a + inc de + ld [de], a + pop de + ld hl, StringBuffer1 +.loop2 + ld a, [hl] + cp -1 + jr z, .fail + cp CURSE_T + jr z, .next + ld a, [de] + cp [hl] + jr z, .next + inc de + ld a, [de] + dec de + cp [hl] + jr nz, .done +.next + inc hl + jr .loop2 + +.fail + call AnimateFailedMove + jp PrintButItFailed + +.done +.loop3 + call BattleRandom + and 3 ; TODO factor in NUM_MOVES + ld c, a + ld b, 0 + ld hl, StringBuffer1 + add hl, bc + ld a, [hl] + cp -1 + jr z, .loop3 + cp CURSE_T + jr z, .loop3 + ld a, [de] + cp [hl] + jr z, .loop3 + inc de + ld a, [de] + dec de + cp [hl] + jr z, .loop3 + ld a, [hl] + ld [de], a + inc de + ld [de], a + ld [wNamedObjectIndexBuffer], a + farcall GetTypeName + call AnimateCurrentMove + ld hl, TransformedTypeText + jp StdBattleTextBox + +; 3710e + + +BattleCommand_ResetStats: ; 3710e +; resetstats + + ld a, 7 ; neutral + ld hl, PlayerStatLevels + call .Fill + ld hl, EnemyStatLevels + call .Fill + + ld a, [hBattleTurn] + push af + + call SetPlayerTurn + call CalcPlayerStats + call SetEnemyTurn + call CalcEnemyStats + + pop af + ld [hBattleTurn], a + + call AnimateCurrentMove + + ld hl, EliminatedStatsText + jp StdBattleTextBox + +.Fill: + ld b, PlayerStatLevelsEnd - PlayerStatLevels +.next + ld [hli], a + dec b + jr nz, .next + ret + +; 3713e + + +BattleCommand_Heal: ; 3713e +; heal + + ld de, BattleMonHP + ld hl, BattleMonMaxHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld de, EnemyMonHP + ld hl, EnemyMonMaxHP +.got_hp + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld b, a + push hl + push de + push bc + ld c, 2 + call StringCmp + pop bc + pop de + pop hl + jp z, .hp_full + ld a, b + cp REST + jr nz, .not_rest + + push hl + push de + push af + call BattleCommand_MoveDelay + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVarAddr + res SUBSTATUS_TOXIC, [hl] + ld a, BATTLE_VARS_STATUS + call GetBattleVarAddr + ld a, [hl] + and a + ld [hl], REST_SLEEP_TURNS + 1 + ld hl, WentToSleepText + jr z, .no_status_to_heal + ld hl, RestedText +.no_status_to_heal + call StdBattleTextBox + ld a, [hBattleTurn] + and a + jr nz, .calc_enemy_stats + call CalcPlayerStats + jr .got_stats + +.calc_enemy_stats + call CalcEnemyStats +.got_stats + pop af + pop de + pop hl + +.not_rest + jr z, .restore_full_hp + ld hl, GetHalfMaxHP + call CallBattleCore + jr .finish + +.restore_full_hp + ld hl, GetMaxHP + call CallBattleCore +.finish + call AnimateCurrentMove + call BattleCommand_SwitchTurn + ld hl, RestoreHP + call CallBattleCore + call BattleCommand_SwitchTurn + call UpdateUserInParty + call RefreshBattleHuds + ld hl, RegainedHealthText + jp StdBattleTextBox + +.hp_full + call AnimateFailedMove + ld hl, HPIsFullText + jp StdBattleTextBox + +; 371cd + +INCLUDE "engine/battle/effect_commands/transform.asm" + +BattleSideCopy: ; 372c6 +; Copy bc bytes from hl to de if it's the player's turn. +; Copy bc bytes from de to hl if it's the enemy's turn. + ld a, [hBattleTurn] + and a + jr z, .copy + +; Swap hl and de + push hl + ld h, d + ld l, e + pop de +.copy + jp CopyBytes + +; 372d2 + + +BattleEffect_ButItFailed: ; 372d2 + call AnimateFailedMove + jp PrintButItFailed + +; 372d8 + + +ClearLastMove: ; 372d8 + ld a, BATTLE_VARS_LAST_COUNTER_MOVE + call GetBattleVarAddr + xor a + ld [hl], a + + ld a, BATTLE_VARS_LAST_MOVE + call GetBattleVarAddr + xor a + ld [hl], a + ret + +; 372e7 + + +ResetActorDisable: ; 372e7 + ld a, [hBattleTurn] + and a + jr z, .player + + xor a + ld [EnemyDisableCount], a + ld [EnemyDisabledMove], a + ret + +.player + xor a + ld [PlayerDisableCount], a + ld [DisabledMove], a + ret + +; 372fc + + +BattleCommand_Screen: ; 372fc +; screen + + ld hl, PlayerScreens + ld bc, PlayerLightScreenCount + ld a, [hBattleTurn] + and a + jr z, .got_screens_pointer + ld hl, EnemyScreens + ld bc, EnemyLightScreenCount + +.got_screens_pointer + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_LIGHT_SCREEN + jr nz, .Reflect + + bit SCREENS_LIGHT_SCREEN, [hl] + jr nz, .failed + set SCREENS_LIGHT_SCREEN, [hl] + ld a, 5 + ld [bc], a + ld hl, LightScreenEffectText + jr .good + +.Reflect: + bit SCREENS_REFLECT, [hl] + jr nz, .failed + set SCREENS_REFLECT, [hl] + + ; LightScreenCount -> ReflectCount + inc bc + + ld a, 5 + ld [bc], a + ld hl, ReflectEffectText + +.good + call AnimateCurrentMove + jp StdBattleTextBox + +.failed + call AnimateFailedMove + jp PrintButItFailed + +; 3733d + + +PrintDoesntAffect: ; 3733d +; 'it doesn't affect' + ld hl, DoesntAffectText + jp StdBattleTextBox + +; 37343 + + +PrintNothingHappened: ; 37343 +; 'but nothing happened!' + ld hl, NothingHappenedText + jp StdBattleTextBox + +; 37349 + + +TryPrintButItFailed: ; 37349 + ld a, [AlreadyFailed] + and a + ret nz + + ; fallthrough +; 3734e + + +PrintButItFailed: ; 3734e +; 'but it failed!' + ld hl, ButItFailedText + jp StdBattleTextBox + +; 37354 + + +FailSnore: +FailDisable: +FailConversion2: +FailAttract: +FailForesight: +FailSpikes: + call AnimateFailedMove + ; fallthrough +; 37357 + +FailMimic: ; 37357 + ld hl, ButItFailedText ; 'but it failed!' + ld de, ItFailedText ; 'it failed!' + jp FailText_CheckOpponentProtect + +; 37360 + + +PrintDidntAffect: ; 37360 +; 'it didn't affect' + ld hl, DidntAffect1Text + jp StdBattleTextBox + +; 37366 + + +PrintDidntAffect2: ; 37366 + call AnimateFailedMove + ld hl, DidntAffect1Text ; 'it didn't affect' + ld de, DidntAffect2Text ; 'it didn't affect' + jp FailText_CheckOpponentProtect + +; 37372 + + +PrintParalyze: ; 37372 +; 'paralyzed! maybe it can't attack!' + ld hl, ParalyzedText + jp StdBattleTextBox + +; 37378 + + +CheckSubstituteOpp: ; 37378 + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + ret + +; 37380 + + +BattleCommand_Selfdestruct: ; 37380 + farcall TrainerRankings_Selfdestruct + ld a, BATTLEANIM_PLAYER_DAMAGE + ld [wNumHits], a + ld c, 3 + call DelayFrames + ld a, BATTLE_VARS_STATUS + call GetBattleVarAddr + xor a + ld [hli], a + inc hl + ld [hli], a + ld [hl], a + ld a, $1 + ld [wKickCounter], a + call BattleCommand_LowerSub + call LoadMoveAnim + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + res SUBSTATUS_LEECH_SEED, [hl] + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + res SUBSTATUS_DESTINY_BOND, [hl] + call _CheckBattleScene + ret nc + farcall DrawPlayerHUD + farcall DrawEnemyHUD + call WaitBGMap + jp RefreshBattleHuds + +; 373c9 + + +INCLUDE "engine/battle/effect_commands/mirror_move.asm" + +INCLUDE "engine/battle/effect_commands/metronome.asm" + + +CheckUserMove: ; 37462 +; Return z if the user has move a. + ld b, a + ld de, BattleMonMoves + ld a, [hBattleTurn] + and a + jr z, .ok + ld de, EnemyMonMoves +.ok + + ld c, NUM_MOVES +.loop + ld a, [de] + inc de + cp b + ret z + + dec c + jr nz, .loop + + ld a, 1 + and a + ret + +; 3747b + + +ResetTurn: ; 3747b + ld hl, wPlayerCharging + ld a, [hBattleTurn] + and a + jr z, .player + ld hl, wEnemyCharging + +.player + ld [hl], 1 + xor a + ld [AlreadyDisobeyed], a + call DoMove + jp EndMoveEffect + +; 37492 + + +INCLUDE "engine/battle/effect_commands/thief.asm" + + +BattleCommand_ArenaTrap: ; 37517 +; arenatrap + +; Doesn't work on an absent opponent. + + call CheckHiddenOpponent + jr nz, .failed + +; Don't trap if the opponent is already trapped. + + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVarAddr + bit SUBSTATUS_CANT_RUN, [hl] + jr nz, .failed + +; Otherwise trap the opponent. + + set SUBSTATUS_CANT_RUN, [hl] + call AnimateCurrentMove + ld hl, CantEscapeNowText + jp StdBattleTextBox + +.failed + call AnimateFailedMove + jp PrintButItFailed + +; 37536 + + +INCLUDE "engine/battle/effect_commands/nightmare.asm" + + +BattleCommand_Defrost: ; 37563 +; defrost + +; Thaw the user. + + ld a, BATTLE_VARS_STATUS + call GetBattleVarAddr + bit FRZ, [hl] + ret z + res FRZ, [hl] + +; Don't update the enemy's party struct in a wild battle. + + ld a, [hBattleTurn] + and a + jr z, .party + + ld a, [wBattleMode] + dec a + jr z, .done + +.party + ld a, MON_STATUS + call UserPartyAttr + res FRZ, [hl] + +.done + call RefreshBattleHuds + ld hl, WasDefrostedText + jp StdBattleTextBox + +; 37588 + + +INCLUDE "engine/battle/effect_commands/curse.asm" + +INCLUDE "engine/battle/effect_commands/protect.asm" + +INCLUDE "engine/battle/effect_commands/endure.asm" + +INCLUDE "engine/battle/effect_commands/spikes.asm" + +INCLUDE "engine/battle/effect_commands/foresight.asm" + +INCLUDE "engine/battle/effect_commands/perish_song.asm" + +INCLUDE "engine/battle/effect_commands/sandstorm.asm" + +INCLUDE "engine/battle/effect_commands/rollout.asm" + + +BattleCommand5d: ; 37791 +; unused + ret + +; 37792 + + +BattleCommand_FuryCutter: ; 37792 +; furycutter + + ld hl, PlayerFuryCutterCount + ld a, [hBattleTurn] + and a + jr z, .go + ld hl, EnemyFuryCutterCount + +.go + ld a, [AttackMissed] + and a + jp nz, ResetFuryCutterCount + + inc [hl] + +; Damage capped at 5 turns' worth (16x). + ld a, [hl] + ld b, a + cp 6 + jr c, .checkdouble + ld b, 5 + +.checkdouble + dec b + ret z + +; Double the damage + ld hl, CurDamage + 1 + sla [hl] + dec hl + rl [hl] + jr nc, .checkdouble + +; No overflow + ld a, $ff + ld [hli], a + ld [hl], a + ret + +; 377be + + +ResetFuryCutterCount: ; 377be + + push hl + + ld hl, PlayerFuryCutterCount + ld a, [hBattleTurn] + and a + jr z, .reset + ld hl, EnemyFuryCutterCount + +.reset + xor a + ld [hl], a + + pop hl + ret + +; 377ce + + +INCLUDE "engine/battle/effect_commands/attract.asm" + +BattleCommand_HappinessPower: ; 3784b +; happinesspower + push bc + ld hl, BattleMonHappiness + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyMonHappiness +.ok + xor a + ld [hMultiplicand + 0], a + ld [hMultiplicand + 1], a + ld a, [hl] + ld [hMultiplicand + 2], a + ld a, 10 + ld [hMultiplier], a + call Multiply + ld a, 25 + ld [hDivisor], a + ld b, 4 + call Divide + ld a, [hQuotient + 2] + ld d, a + pop bc + ret + +; 37874 + + +INCLUDE "engine/battle/effect_commands/present.asm" + +BattleCommand_FrustrationPower: ; 3790e +; frustrationpower + + push bc + ld hl, BattleMonHappiness + ld a, [hBattleTurn] + and a + jr z, .got_happiness + ld hl, EnemyMonHappiness +.got_happiness + ld a, $ff + sub [hl] + ld [hMultiplicand + 2], a + xor a + ld [hMultiplicand + 0], a + ld [hMultiplicand + 1], a + ld a, 10 + ld [hMultiplier], a + call Multiply + ld a, 25 + ld [hDivisor], a + ld b, 4 + call Divide + ld a, [hQuotient + 2] + ld d, a + pop bc + ret + +; 37939 + + +BattleCommand_Safeguard: ; 37939 +; safeguard + + ld hl, PlayerScreens + ld de, PlayerSafeguardCount + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyScreens + ld de, EnemySafeguardCount +.ok + bit SCREENS_SAFEGUARD, [hl] + jr nz, .failed + set SCREENS_SAFEGUARD, [hl] + ld a, 5 + ld [de], a + call AnimateCurrentMove + ld hl, CoveredByVeilText + jp StdBattleTextBox + +.failed + call AnimateFailedMove + jp PrintButItFailed + +; 37962 + + +SafeCheckSafeguard: ; 37962 + push hl + ld hl, EnemyScreens + ld a, [hBattleTurn] + and a + jr z, .got_turn + ld hl, PlayerScreens + +.got_turn + bit SCREENS_SAFEGUARD, [hl] + pop hl + ret + +; 37972 + + +BattleCommand_CheckSafeguard: ; 37972 +; checksafeguard + ld hl, EnemyScreens + ld a, [hBattleTurn] + and a + jr z, .got_turn + ld hl, PlayerScreens +.got_turn + bit SCREENS_SAFEGUARD, [hl] + ret z + ld a, 1 + ld [AttackMissed], a + call BattleCommand_MoveDelay + ld hl, SafeguardProtectText + call StdBattleTextBox + jp EndMoveEffect + +; 37991 + + +BattleCommand_GetMagnitude: ; 37991 +; getmagnitude + + push bc + call BattleRandom + ld b, a + ld hl, .Magnitudes +.loop + ld a, [hli] + cp b + jr nc, .ok + inc hl + inc hl + jr .loop + +.ok + ld d, [hl] + push de + inc hl + ld a, [hl] + ld [wTypeMatchup], a + call BattleCommand_MoveDelay + ld hl, MagnitudeText + call StdBattleTextBox + pop de + pop bc + ret + +.Magnitudes: + ; /255, BP, magnitude + db 13, 10, 4 + db 38, 30, 5 + db 89, 50, 6 + db 166, 70, 7 + db 217, 90, 8 + db 242, 110, 9 + db 255, 150, 10 +; 379c9 + + +BattleCommand_BatonPass: ; 379c9 +; batonpass + + ld a, [hBattleTurn] + and a + jp nz, .Enemy + + +; Need something to switch to + call CheckAnyOtherAlivePartyMons + jp z, FailedBatonPass + + call UpdateBattleMonInParty + call AnimateCurrentMove + + ld c, 50 + call DelayFrames + +; Transition into switchmon menu + call LoadStandardMenuDataHeader + farcall SetUpBattlePartyMenu_NoLoop + + farcall ForcePickSwitchMonInBattle + +; Return to battle scene + call ClearPalettes + farcall _LoadBattleFontsHPBar + call CloseWindow + call ClearSprites + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + ld b, SCGB_BATTLE_COLORS + call GetSGBLayout + call SetPalettes + call BatonPass_LinkPlayerSwitch + +; Mobile link battles handle entrances differently + farcall CheckMobileBattleError + jp c, EndMoveEffect + + ld hl, PassedBattleMonEntrance + call CallBattleCore + + call ResetBatonPassStatus + ret + + +.Enemy: + +; Wildmons don't have anything to switch to + ld a, [wBattleMode] + dec a ; WILDMON + jp z, FailedBatonPass + + call CheckAnyOtherAliveEnemyMons + jp z, FailedBatonPass + + call UpdateEnemyMonInParty + call AnimateCurrentMove + call BatonPass_LinkEnemySwitch + +; Mobile link battles handle entrances differently + farcall CheckMobileBattleError + jp c, EndMoveEffect + +; Passed enemy PartyMon entrance + xor a + ld [wEnemySwitchMonIndex], a + ld hl, EnemySwitch_SetMode + call CallBattleCore + ld hl, ResetBattleParticipants + call CallBattleCore + ld a, 1 + ld [wTypeMatchup], a + ld hl, ApplyStatLevelMultiplierOnAllStats + call CallBattleCore + + ld hl, SpikesDamage + call CallBattleCore + + jr ResetBatonPassStatus + +; 37a67 + + +BatonPass_LinkPlayerSwitch: ; 37a67 + ld a, [wLinkMode] + and a + ret z + + ld a, 1 + ld [wPlayerAction], a + + call LoadStandardMenuDataHeader + ld hl, LinkBattleSendReceiveAction + call CallBattleCore + call CloseWindow + + xor a + ld [wPlayerAction], a + ret + +; 37a82 + + +BatonPass_LinkEnemySwitch: ; 37a82 + ld a, [wLinkMode] + and a + ret z + + call LoadStandardMenuDataHeader + ld hl, LinkBattleSendReceiveAction + call CallBattleCore + + ld a, [OTPartyCount] + add BATTLEACTION_SWITCH1 + ld b, a + ld a, [wBattleAction] + cp BATTLEACTION_SWITCH1 + jr c, .baton_pass + cp b + jr c, .switch + +.baton_pass + ld a, [CurOTMon] + add BATTLEACTION_SWITCH1 + ld [wBattleAction], a +.switch + jp CloseWindow + +; 37aab + + +FailedBatonPass: ; 37aab + call AnimateFailedMove + jp PrintButItFailed + +; 37ab1 + + +ResetBatonPassStatus: ; 37ab1 +; Reset status changes that aren't passed by Baton Pass. + + ; Nightmare isn't passed. + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + jr nz, .ok + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + res SUBSTATUS_NIGHTMARE, [hl] +.ok + + ; Disable isn't passed. + call ResetActorDisable + + ; Attraction isn't passed. + ld hl, PlayerSubStatus1 + res SUBSTATUS_IN_LOVE, [hl] + ld hl, EnemySubStatus1 + res SUBSTATUS_IN_LOVE, [hl] + ld hl, PlayerSubStatus5 + + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVarAddr + res SUBSTATUS_TRANSFORMED, [hl] + res SUBSTATUS_ENCORED, [hl] + + ; New mon hasn't used a move yet. + ld a, BATTLE_VARS_LAST_MOVE + call GetBattleVarAddr + ld [hl], 0 + + xor a + ld [wPlayerWrapCount], a + ld [wEnemyWrapCount], a + ret + +; 37ae9 + + +CheckAnyOtherAlivePartyMons: ; 37ae9 + ld hl, PartyMon1HP + ld a, [PartyCount] + ld d, a + ld a, [CurBattleMon] + ld e, a + jr CheckAnyOtherAliveMons + +; 37af6 + + +CheckAnyOtherAliveEnemyMons: ; 37af6 + ld hl, OTPartyMon1HP + ld a, [OTPartyCount] + ld d, a + ld a, [CurOTMon] + ld e, a + + ; fallthrough +; 37b01 + +CheckAnyOtherAliveMons: ; 37b01 +; Check for nonzero HP starting from partymon +; HP at hl for d partymons, besides current mon e. + +; Return nz if any are alive. + + xor a + ld b, a + ld c, a +.loop + ld a, c + cp d + jr z, .done + cp e + jr z, .next + + ld a, [hli] + or b + ld b, a + ld a, [hld] + or b + ld b, a + +.next + push bc + ld bc, PARTYMON_STRUCT_LENGTH + add hl, bc + pop bc + inc c + jr .loop + +.done + ld a, b + and a + ret + +; 37b1d + + +BattleCommand_Pursuit: ; 37b1d +; pursuit +; Double damage if the opponent is switching. + + ld hl, wEnemyIsSwitching + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, wPlayerIsSwitching +.ok + ld a, [hl] + and a + ret z + + ld hl, CurDamage + 1 + sla [hl] + dec hl + rl [hl] + ret nc + + ld a, $ff + ld [hli], a + ld [hl], a + ret + +; 37b39 + + +BattleCommand_ClearHazards: ; 37b39 +; clearhazards + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + bit SUBSTATUS_LEECH_SEED, [hl] + jr z, .not_leeched + res SUBSTATUS_LEECH_SEED, [hl] + ld hl, ShedLeechSeedText + call StdBattleTextBox +.not_leeched + + ld hl, PlayerScreens + ld de, wPlayerWrapCount + ld a, [hBattleTurn] + and a + jr z, .got_screens_wrap + ld hl, EnemyScreens + ld de, wEnemyWrapCount +.got_screens_wrap + bit SCREENS_SPIKES, [hl] + jr z, .no_spikes + res SCREENS_SPIKES, [hl] + ld hl, BlewSpikesText + push de + call StdBattleTextBox + pop de +.no_spikes + + ld a, [de] + and a + ret z + xor a + ld [de], a + ld hl, ReleasedByText + jp StdBattleTextBox + +; 37b74 + + +BattleCommand_HealMorn: ; 37b74 +; healmorn + ld b, MORN_F + jr BattleCommand_TimeBasedHealContinue + +; 37b78 + +BattleCommand_HealDay: ; 37b78 +; healday + ld b, DAY_F + jr BattleCommand_TimeBasedHealContinue + +; 37b7c + +BattleCommand_HealNite: ; 37b7c +; healnite + ld b, NITE_F + ; fallthrough +; 37b7e + +BattleCommand_TimeBasedHealContinue: ; 37b7e +; Time- and weather-sensitive heal. + + ld hl, BattleMonMaxHP + ld de, BattleMonHP + ld a, [hBattleTurn] + and a + jr z, .start + ld hl, EnemyMonMaxHP + ld de, EnemyMonHP + +.start +; Index for .Multipliers +; Default restores half max HP. + ld c, 2 + +; Don't bother healing if HP is already full. + push bc + call StringCmp + pop bc + jr z, .Full + +; Don't factor in time of day in link battles. + ld a, [wLinkMode] + and a + jr nz, .Weather + + ld a, [TimeOfDay] + cp b + jr z, .Weather + dec c ; double + +.Weather: + ld a, [Weather] + and a + jr z, .Heal + +; x2 in sun +; /2 in rain/sandstorm + inc c + cp WEATHER_SUN + jr z, .Heal + dec c + dec c + +.Heal: + ld b, 0 + ld hl, .Multipliers + add hl, bc + add hl, bc + + ld a, [hli] + ld h, [hl] + ld l, a + ld a, BANK(GetMaxHP) + rst FarCall + + call AnimateCurrentMove + call BattleCommand_SwitchTurn + + callfar RestoreHP + + call BattleCommand_SwitchTurn + call UpdateUserInParty + +; 'regained health!' + ld hl, RegainedHealthText + jp StdBattleTextBox + +.Full: + call AnimateFailedMove + +; 'hp is full!' + ld hl, HPIsFullText + jp StdBattleTextBox + +.Multipliers: + dw GetEighthMaxHP + dw GetQuarterMaxHP + dw GetHalfMaxHP + dw GetMaxHP +; 37be8 + + +BattleCommand_HiddenPower: ; 37be8 +; hiddenpower + + ld a, [AttackMissed] + and a + ret nz + farcall HiddenPowerDamage + ret + +; 37bf4 + + +BattleCommand_StartRain: ; 37bf4 +; startrain + ld a, WEATHER_RAIN + ld [Weather], a + ld a, 5 + ld [WeatherCount], a + call AnimateCurrentMove + ld hl, DownpourText + jp StdBattleTextBox + +; 37c07 + + +BattleCommand_StartSun: ; 37c07 +; startsun + ld a, WEATHER_SUN + ld [Weather], a + ld a, 5 + ld [WeatherCount], a + call AnimateCurrentMove + ld hl, SunGotBrightText + jp StdBattleTextBox + +; 37c1a + + +BattleCommand_BellyDrum: ; 37c1a +; bellydrum +; This command is buggy because it raises the user's attack +; before checking that it has enough HP to use the move. +; Swap the order of these two blocks to fix. + call BattleCommand_AttackUp2 + ld a, [AttackMissed] + and a + jr nz, .failed + + callfar GetHalfMaxHP + callfar CheckUserHasEnoughHP + jr nc, .failed + + push bc + call AnimateCurrentMove + pop bc + callfar SubtractHPFromUser + call UpdateUserInParty + ld a, 5 + +.max_attack_loop + push af + call BattleCommand_AttackUp2 + pop af + dec a + jr nz, .max_attack_loop + + ld hl, BellyDrumText + jp StdBattleTextBox + +.failed + call AnimateFailedMove + jp PrintButItFailed + +; 37c55 + + +BattleCommand_PsychUp: ; 37c55 +; psychup + + ld hl, EnemyStatLevels + ld de, PlayerStatLevels + ld a, [hBattleTurn] + and a + jr z, .pointers_correct +; It's the enemy's turn, so swap the pointers. + push hl + ld h, d + ld l, e + pop de +.pointers_correct + push hl + ld b, NUM_LEVEL_STATS +; If any of the enemy's stats is modified from its base level, +; the move succeeds. Otherwise, it fails. +.loop + ld a, [hli] + cp BASE_STAT_LEVEL + jr nz, .break + dec b + jr nz, .loop + pop hl + call AnimateFailedMove + jp PrintButItFailed + +.break + pop hl + ld b, NUM_LEVEL_STATS +.loop2 + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .loop2 + ld a, [hBattleTurn] + and a + jr nz, .calc_enemy_stats + call CalcPlayerStats + jr .merge + +.calc_enemy_stats + call CalcEnemyStats +.merge + call AnimateCurrentMove + ld hl, CopiedStatsText + jp StdBattleTextBox + +; 37c95 + + +BattleCommand_MirrorCoat: ; 37c95 +; mirrorcoat + + ld a, 1 + ld [AttackMissed], a + + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + and a + ret z + + ld b, a + callfar GetMoveEffect + ld a, b + cp EFFECT_MIRROR_COAT + ret z + + call BattleCommand_ResetTypeMatchup + ld a, [wTypeMatchup] + and a + ret z + + call CheckOpponentWentFirst + ret z + + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + dec a + ld de, StringBuffer1 + call GetMoveData + + ld a, [StringBuffer1 + 2] + and a + ret z + + ld a, [StringBuffer1 + 3] + cp SPECIAL + ret c + + ld hl, CurDamage + ld a, [hli] + or [hl] + ret z + + ld a, [hl] + add a + ld [hld], a + ld a, [hl] + adc a + ld [hl], a + jr nc, .capped + ld a, $ff + ld [hli], a + ld [hl], a +.capped + + xor a + ld [AttackMissed], a + ret + +; 37ce6 + + +BattleCommand_DoubleMinimizeDamage: ; 37ce6 +; doubleminimizedamage + + ld hl, wEnemyMinimized + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, wPlayerMinimized +.ok + ld a, [hl] + and a + ret z + ld hl, CurDamage + 1 + sla [hl] + dec hl + rl [hl] + ret nc + ld a, $ff + ld [hli], a + ld [hl], a + ret + +; 37d02 + + +BattleCommand_SkipSunCharge: ; 37d02 +; mimicsuncharge + ld a, [Weather] + cp WEATHER_SUN + ret nz + ld b, charge_command + jp SkipToBattleCommand + +; 37d0d + + +BattleCommand_CheckFutureSight: ; 37d0d +; checkfuturesight + + ld hl, wPlayerFutureSightCount + ld de, wPlayerFutureSightDamage + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, wEnemyFutureSightCount + ld de, wEnemyFutureSightDamage +.ok + + ld a, [hl] + and a + ret z + cp 1 + ret nz + + ld [hl], 0 + ld a, [de] + inc de + ld [CurDamage], a + ld a, [de] + ld [CurDamage + 1], a + ld b, futuresight_command + jp SkipToBattleCommand + +; 37d34 + +BattleCommand_FutureSight: ; 37d34 +; futuresight + + call CheckUserIsCharging + jr nz, .AlreadyChargingFutureSight + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld b, a + ld a, BATTLE_VARS_LAST_COUNTER_MOVE + call GetBattleVarAddr + ld [hl], b + ld a, BATTLE_VARS_LAST_MOVE + call GetBattleVarAddr + ld [hl], b +.AlreadyChargingFutureSight: + ld hl, wPlayerFutureSightCount + ld a, [hBattleTurn] + and a + jr z, .GotFutureSightCount + ld hl, wEnemyFutureSightCount +.GotFutureSightCount: + ld a, [hl] + and a + jr nz, .failed + ld a, 4 + ld [hl], a + call BattleCommand_LowerSub + call BattleCommand_MoveDelay + ld hl, ForesawAttackText + call StdBattleTextBox + call BattleCommand_RaiseSub + ld de, wPlayerFutureSightDamage + ld a, [hBattleTurn] + and a + jr z, .StoreDamage + ld de, wEnemyFutureSightDamage +.StoreDamage: + ld hl, CurDamage + ld a, [hl] + ld [de], a + ld [hl], 0 + inc hl + inc de + ld a, [hl] + ld [de], a + ld [hl], 0 + jp EndMoveEffect + +.failed + pop bc + call ResetDamage + call AnimateFailedMove + call PrintButItFailed + jp EndMoveEffect + +; 37d94 + + +BattleCommand_ThunderAccuracy: ; 37d94 +; thunderaccuracy + + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVarAddr + inc hl + ld a, [Weather] + cp WEATHER_RAIN + jr z, .rain + cp WEATHER_SUN + ret nz + ld [hl], 50 percent + 1 + ret + +.rain + ; Redundant with CheckHit guranteeing hit + ld [hl], 100 percent + ret + +; 37daa + + +CheckHiddenOpponent: ; 37daa +; BUG: This routine should account for Lock-On and Mind Reader. + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret + +; 37db2 + + +GetUserItem: ; 37db2 +; Return the effect of the user's item in bc, and its id at hl. + ld hl, BattleMonItem + ld a, [hBattleTurn] + and a + jr z, .go + ld hl, EnemyMonItem +.go + ld b, [hl] + jp GetItemHeldEffect + +; 37dc1 + + +GetOpponentItem: ; 37dc1 +; Return the effect of the opponent's item in bc, and its id at hl. + ld hl, EnemyMonItem + ld a, [hBattleTurn] + and a + jr z, .go + ld hl, BattleMonItem +.go + ld b, [hl] + jp GetItemHeldEffect + +; 37dd0 + + +GetItemHeldEffect: ; 37dd0 +; Return the effect of item b in bc. + ld a, b + and a + ret z + + push hl + ld hl, ItemAttributes + ITEMATTR_EFFECT + dec a + ld c, a + ld b, 0 + ld a, ITEMATTR_STRUCT_LENGTH + call AddNTimes + ld a, BANK(ItemAttributes) + call GetFarHalfword + ld b, l + ld c, h + pop hl + ret + +; 37de9 + + +AnimateCurrentMoveEitherSide: ; 37de9 + push hl + push de + push bc + ld a, [wKickCounter] + push af + call BattleCommand_LowerSub + pop af + ld [wKickCounter], a + call PlayDamageAnim + call BattleCommand_RaiseSub + pop bc + pop de + pop hl + ret + +; 37e01 + + +AnimateCurrentMove: ; 37e01 + push hl + push de + push bc + ld a, [wKickCounter] + push af + call BattleCommand_LowerSub + pop af + ld [wKickCounter], a + call LoadMoveAnim + call BattleCommand_RaiseSub + pop bc + pop de + pop hl + ret + +; 37e19 + + +PlayDamageAnim: ; 37e19 + xor a + ld [FXAnimID + 1], a + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + and a + ret z + + ld [FXAnimID], a + + ld a, [hBattleTurn] + and a + ld a, BATTLEANIM_ENEMY_DAMAGE + jr z, .player + ld a, BATTLEANIM_PLAYER_DAMAGE + +.player + ld [wNumHits], a + + jp PlayUserBattleAnim + +; 37e36 + + +LoadMoveAnim: ; 37e36 + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + and a + ret z + + ; fallthrough +; 37e44 + + +LoadAnim: ; 37e44 + + ld [FXAnimID], a + + ; fallthrough +; 37e47 + + +PlayUserBattleAnim: ; 37e47 + push hl + push de + push bc + callfar PlayBattleAnim + pop bc + pop de + pop hl + ret + +; 37e54 + + +PlayOpponentBattleAnim: ; 37e54 + ld a, e + ld [FXAnimID], a + ld a, d + ld [FXAnimID + 1], a + xor a + ld [wNumHits], a + + push hl + push de + push bc + call BattleCommand_SwitchTurn + + callfar PlayBattleAnim + + call BattleCommand_SwitchTurn + pop bc + pop de + pop hl + ret + +; 37e73 + + +CallBattleCore: ; 37e73 + ld a, BANK(BattleCore) + rst FarCall + ret + +; 37e77 + + +AnimateFailedMove: ; 37e77 + call BattleCommand_LowerSub + call BattleCommand_MoveDelay + jp BattleCommand_RaiseSub + +; 37e80 + + +BattleCommand_MoveDelay: ; 37e80 +; movedelay +; Wait 40 frames. + ld c, 40 + jp DelayFrames + +; 37e85 + + +BattleCommand_ClearText: ; 37e85 +; cleartext + +; Used in multi-hit moves. + ld hl, .text + jp BattleTextBox + +.text + db "@" +; 37e8c + + +SkipToBattleCommand: ; 37e8c +; Skip over commands until reaching command b. + ld a, [BattleScriptBufferAddress + 1] + ld h, a + ld a, [BattleScriptBufferAddress] + ld l, a +.loop + ld a, [hli] + cp b + jr nz, .loop + + ld a, h + ld [BattleScriptBufferAddress + 1], a + ld a, l + ld [BattleScriptBufferAddress], a + ret + +; 37ea1 + + +GetMoveAttr: ; 37ea1 +; Assuming hl = Moves + x, return attribute x of move a. + push bc + ld bc, MOVE_LENGTH + call AddNTimes + call GetMoveByte + pop bc + ret + +; 37ead + + +GetMoveData: ; 37ead +; Copy move struct a to de. + ld hl, Moves + ld bc, MOVE_LENGTH + call AddNTimes + ld a, Bank(Moves) + jp FarCopyBytes + +; 37ebb + + +GetMoveByte: ; 37ebb + ld a, BANK(Moves) + jp GetFarByte + +; 37ec0 + + +DisappearUser: ; 37ec0 + farcall _DisappearUser + ret + +; 37ec7 + + +AppearUserLowerSub: ; 37ec7 + farcall _AppearUserLowerSub + ret + +; 37ece + + +AppearUserRaiseSub: ; 37ece + farcall _AppearUserRaiseSub + ret + +; 37ed5 + + +_CheckBattleScene: ; 37ed5 +; Checks the options. Returns carry if battle animations are disabled. + push hl + push de + push bc + farcall CheckBattleScene + pop bc + pop de + pop hl + ret + +; 37ee2 diff --git a/engine/battle/effect_commands/attract.asm b/engine/battle/effect_commands/attract.asm new file mode 100755 index 000000000..0a6d7c975 --- /dev/null +++ b/engine/battle/effect_commands/attract.asm @@ -0,0 +1,79 @@ +BattleCommand_Attract: ; 377ce +; attract + ld a, [AttackMissed] + and a + jr nz, .failed + call CheckOppositeGender + jr c, .failed + call CheckHiddenOpponent + jr nz, .failed + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVarAddr + bit SUBSTATUS_IN_LOVE, [hl] + jr nz, .failed + + set SUBSTATUS_IN_LOVE, [hl] + call AnimateCurrentMove + +; 'fell in love!' + ld hl, FellInLoveText + jp StdBattleTextBox + +.failed + jp FailAttract +; 377f5 + + +CheckOppositeGender: ; 377f5 + ld a, MON_SPECIES + call BattlePartyAttr + ld a, [hl] + ld [CurPartySpecies], a + + ld a, [CurBattleMon] + ld [CurPartyMon], a + xor a + ld [MonType], a + + farcall GetGender + jr c, .genderless_samegender + + ld b, 1 + jr nz, .got_gender + dec b + +.got_gender + push bc + ld a, [TempEnemyMonSpecies] + ld [CurPartySpecies], a + ld hl, EnemyMonDVs + ld a, [EnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr z, .not_transformed + ld hl, wEnemyBackupDVs +.not_transformed + ld a, [hli] + ld [TempMonDVs], a + ld a, [hl] + ld [TempMonDVs + 1], a + ld a, 3 + ld [MonType], a + farcall GetGender + pop bc + jr c, .genderless_samegender + + ld a, 1 + jr nz, .got_enemy_gender + dec a + +.got_enemy_gender + xor b + jr z, .genderless_samegender + + and a + ret + +.genderless_samegender + scf + ret +; 3784b diff --git a/engine/battle/effect_commands/curse.asm b/engine/battle/effect_commands/curse.asm new file mode 100644 index 000000000..dceb3b8d5 --- /dev/null +++ b/engine/battle/effect_commands/curse.asm @@ -0,0 +1,97 @@ +BattleCommand_Curse: ; 37588 +; curse + + ld de, BattleMonType1 + ld bc, PlayerStatLevels + ld a, [hBattleTurn] + and a + jr z, .go + ld de, EnemyMonType1 + ld bc, EnemyStatLevels + +.go + +; Curse is different for Ghost-types. + + ld a, [de] + cp GHOST + jr z, .ghost + inc de + ld a, [de] + cp GHOST + jr z, .ghost + + +; If no stats can be increased, don't. + +; Attack + ld a, [bc] + cp MAX_STAT_LEVEL + jr c, .raise + +; Defense + inc bc + ld a, [bc] + cp MAX_STAT_LEVEL + jr nc, .cantraise + +.raise + +; Raise Attack and Defense, and lower Speed. + + ld a, $1 + ld [wKickCounter], a + call AnimateCurrentMove + ld a, SPEED + call LowerStat + call BattleCommand_SwitchTurn + call BattleCommand_StatDownMessage + call ResetMiss + call BattleCommand_SwitchTurn + call BattleCommand_AttackUp + call BattleCommand_StatUpMessage + call ResetMiss + call BattleCommand_DefenseUp + jp BattleCommand_StatUpMessage + + +.ghost + +; Cut HP in half and put a curse on the opponent. + + call CheckHiddenOpponent + jr nz, .failed + + call CheckSubstituteOpp + jr nz, .failed + + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVarAddr + bit SUBSTATUS_CURSE, [hl] + jr nz, .failed + + set SUBSTATUS_CURSE, [hl] + call AnimateCurrentMove + ld hl, GetHalfMaxHP + call CallBattleCore + ld hl, SubtractHPFromUser + call CallBattleCore + call UpdateUserInParty + ld hl, PutACurseText + jp StdBattleTextBox + +.failed + call AnimateFailedMove + jp PrintButItFailed + + +.cantraise + +; Can't raise either stat. + + ld b, ABILITY + 1 + call GetStatName + call AnimateFailedMove + ld hl, WontRiseAnymoreText + jp StdBattleTextBox +; 37618 diff --git a/engine/battle/effect_commands/endure.asm b/engine/battle/effect_commands/endure.asm new file mode 100644 index 000000000..ed4329ff5 --- /dev/null +++ b/engine/battle/effect_commands/endure.asm @@ -0,0 +1,17 @@ +BattleCommand_Endure: ; 3766f +; endure + +; Endure shares code with Protect. See protect.asm. + + call ProtectChance + ret c + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + set SUBSTATUS_ENDURE, [hl] + + call AnimateCurrentMove + + ld hl, BracedItselfText + jp StdBattleTextBox +; 37683 diff --git a/engine/battle/effect_commands/foresight.asm b/engine/battle/effect_commands/foresight.asm new file mode 100644 index 000000000..6f4f97cd2 --- /dev/null +++ b/engine/battle/effect_commands/foresight.asm @@ -0,0 +1,23 @@ +BattleCommand_Foresight: ; 376a0 +; foresight + + ld a, [AttackMissed] + and a + jr nz, .failed + + call CheckHiddenOpponent + jr nz, .failed + + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVarAddr + bit SUBSTATUS_IDENTIFIED, [hl] + jr nz, .failed + + set SUBSTATUS_IDENTIFIED, [hl] + call AnimateCurrentMove + ld hl, IdentifiedText + jp StdBattleTextBox + +.failed + jp FailForesight +; 376c2 diff --git a/engine/battle/effect_commands/metronome.asm b/engine/battle/effect_commands/metronome.asm new file mode 100644 index 000000000..1908df84d --- /dev/null +++ b/engine/battle/effect_commands/metronome.asm @@ -0,0 +1,61 @@ +BattleCommand_Metronome: ; 37418 +; metronome + + call ClearLastMove + call CheckUserIsCharging + jr nz, .asm_3742b + + ld a, [wKickCounter] + push af + call BattleCommand_LowerSub + pop af + ld [wKickCounter], a + +.asm_3742b + call LoadMoveAnim + +.GetMove: + call BattleRandom + +; No invalid moves. + cp NUM_ATTACKS + 1 + jr nc, .GetMove + +; None of the moves in MetronomeExcepts. + push af + ld de, 1 + ld hl, MetronomeExcepts + call IsInArray + pop bc + jr c, .GetMove + +; No moves the user already has. + ld a, b + call CheckUserMove + jr z, .GetMove + + + ld a, BATTLE_VARS_MOVE + call GetBattleVarAddr + ld [hl], b + call UpdateMoveData + jp ResetTurn +; 37454 + + +MetronomeExcepts: ; 37454 + db NO_MOVE + db METRONOME + db STRUGGLE + db SKETCH + db MIMIC + db COUNTER + db MIRROR_COAT + db PROTECT + db DETECT + db ENDURE + db DESTINY_BOND + db SLEEP_TALK + db THIEF + db -1 +; 37462 diff --git a/engine/battle/effect_commands/mirror_move.asm b/engine/battle/effect_commands/mirror_move.asm new file mode 100644 index 000000000..c4f208d77 --- /dev/null +++ b/engine/battle/effect_commands/mirror_move.asm @@ -0,0 +1,52 @@ +BattleCommand_MirrorMove: ; 373c9 +; mirrormove + + call ClearLastMove + + ld a, BATTLE_VARS_MOVE + call GetBattleVarAddr + + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + and a + jr z, .failed + + call CheckUserMove + jr nz, .use + +.failed + call AnimateFailedMove + + ld hl, MirrorMoveFailedText + call StdBattleTextBox + jp EndMoveEffect + +.use + ld a, b + ld [hl], a + ld [wd265], a + + push af + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVarAddr + ld d, h + ld e, l + pop af + + dec a + call GetMoveData + call GetMoveName + call CopyName1 + call CheckUserIsCharging + jr nz, .done + + ld a, [wKickCounter] + push af + call BattleCommand_LowerSub + pop af + ld [wKickCounter], a + +.done + call BattleCommand_MoveDelay + jp ResetTurn +; 37418 diff --git a/engine/battle/effect_commands/nightmare.asm b/engine/battle/effect_commands/nightmare.asm new file mode 100644 index 000000000..788e3de41 --- /dev/null +++ b/engine/battle/effect_commands/nightmare.asm @@ -0,0 +1,38 @@ +BattleCommand_Nightmare: ; 37536 +; nightmare + +; Can't hit an absent opponent. + + call CheckHiddenOpponent + jr nz, .failed + +; Can't hit a substitute. + + call CheckSubstituteOpp + jr nz, .failed + +; Only works on a sleeping opponent. + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and SLP + jr z, .failed + +; Bail if the opponent is already having a nightmare. + + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVarAddr + bit SUBSTATUS_NIGHTMARE, [hl] + jr nz, .failed + +; Otherwise give the opponent a nightmare. + + set SUBSTATUS_NIGHTMARE, [hl] + call AnimateCurrentMove + ld hl, StartedNightmareText + jp StdBattleTextBox + +.failed + call AnimateFailedMove + jp PrintButItFailed +; 37563 diff --git a/engine/battle/effect_commands/perish_song.asm b/engine/battle/effect_commands/perish_song.asm new file mode 100644 index 000000000..ac491ef6b --- /dev/null +++ b/engine/battle/effect_commands/perish_song.asm @@ -0,0 +1,40 @@ +BattleCommand_PerishSong: ; 376c2 +; perishsong + + + ld hl, PlayerSubStatus1 + ld de, EnemySubStatus1 + bit SUBSTATUS_PERISH, [hl] + jr z, .ok + + ld a, [de] + bit SUBSTATUS_PERISH, a + jr nz, .failed + +.ok + bit SUBSTATUS_PERISH, [hl] + jr nz, .enemy + + set SUBSTATUS_PERISH, [hl] + ld a, 4 + ld [PlayerPerishCount], a + +.enemy + ld a, [de] + bit SUBSTATUS_PERISH, a + jr nz, .done + + set SUBSTATUS_PERISH, a + ld [de], a + ld a, 4 + ld [EnemyPerishCount], a + +.done + call AnimateCurrentMove + ld hl, StartPerishText + jp StdBattleTextBox + +.failed + call AnimateFailedMove + jp PrintButItFailed +; 376f8 diff --git a/engine/battle/effect_commands/present.asm b/engine/battle/effect_commands/present.asm new file mode 100755 index 000000000..819294f8c --- /dev/null +++ b/engine/battle/effect_commands/present.asm @@ -0,0 +1,93 @@ +BattleCommand_Present: ; 37874 +; present + + ld a, [wLinkMode] + cp LINK_COLOSSEUM + jr z, .colosseum_skippush + push bc + push de +.colosseum_skippush + + call BattleCommand_Stab + + ld a, [wLinkMode] + cp LINK_COLOSSEUM + jr z, .colosseum_skippop + pop de + pop bc +.colosseum_skippop + + ld a, [wTypeMatchup] + and a + jp z, AnimateFailedMove + ld a, [AttackMissed] + and a + jp nz, AnimateFailedMove + + push bc + call BattleRandom + ld b, a + ld hl, .PresentPower + ld c, 0 +.next + ld a, [hli] + cp $ff + jr z, .heal_effect ; 378a4 $11 + cp b + jr nc, .got_power ; 378a7 $4 + inc c + inc hl + jr .next ; 378ab $f4 + +.got_power + ld a, c + ld [wPresentPower], a + call AnimateCurrentMoveEitherSide + ld d, [hl] + pop bc + ret + +.heal_effect + pop bc + ld a, $3 + ld [wPresentPower], a + call AnimateCurrentMove + call BattleCommand_SwitchTurn + ld hl, AICheckPlayerMaxHP + ld a, [hBattleTurn] + and a + jr z, .got_hp_fn_pointer ; 378c9 $3 + ld hl, AICheckEnemyMaxHP +.got_hp_fn_pointer + ld a, BANK(AICheckPlayerMaxHP) + rst FarCall + jr c, .already_fully_healed ; 378d1 $20 + + ld hl, GetQuarterMaxHP + call CallBattleCore + call BattleCommand_SwitchTurn + ld hl, RestoreHP + call CallBattleCore + call BattleCommand_SwitchTurn + ld hl, RegainedHealthText + call StdBattleTextBox + call BattleCommand_SwitchTurn + call UpdateOpponentInParty + jr .do_animation ; 378f1 $11 + +.already_fully_healed + call BattleCommand_SwitchTurn + call _CheckBattleScene + jr nc, .do_animation ; 378f9 $9 + call AnimateFailedMove + ld hl, RefusedGiftText + call StdBattleTextBox +.do_animation + jp EndMoveEffect + +.PresentPower: + db 40 percent, 40 + db 70 percent + 1, 80 + db 80 percent, 120 + db $ff +; 3790e diff --git a/engine/battle/effect_commands/protect.asm b/engine/battle/effect_commands/protect.asm new file mode 100644 index 000000000..568ac00f8 --- /dev/null +++ b/engine/battle/effect_commands/protect.asm @@ -0,0 +1,80 @@ +BattleCommand_Protect: ; 37618 +; protect + call ProtectChance + ret c + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + set SUBSTATUS_PROTECT, [hl] + + call AnimateCurrentMove + + ld hl, ProtectedItselfText + jp StdBattleTextBox +; 3762c + + +ProtectChance: ; 3762c + + ld de, PlayerProtectCount + ld a, [hBattleTurn] + and a + jr z, .asm_37637 + ld de, EnemyProtectCount +.asm_37637 + + call CheckOpponentWentFirst + jr nz, .failed + +; Can't have a substitute. + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + jr nz, .failed + +; Halve the chance of a successful Protect for each consecutive use. + + ld b, $ff + ld a, [de] + ld c, a +.loop + ld a, c + and a + jr z, .done + dec c + + srl b + ld a, b + and a + jr nz, .loop + jr .failed +.done + +.rand + call BattleRandom + and a + jr z, .rand + + dec a + cp b + jr nc, .failed + +; Another consecutive Protect use. + + ld a, [de] + inc a + ld [de], a + + and a + ret + + +.failed + xor a + ld [de], a + call AnimateFailedMove + call PrintButItFailed + scf + ret +; 3766f diff --git a/engine/battle/effect_commands/rollout.asm b/engine/battle/effect_commands/rollout.asm new file mode 100644 index 000000000..4ce9ab3d8 --- /dev/null +++ b/engine/battle/effect_commands/rollout.asm @@ -0,0 +1,99 @@ +MAX_ROLLOUT_COUNT EQU 5 + + +BattleCommand_CheckCurl: ; 37718 +; checkcurl + + ld de, PlayerRolloutCount + ld a, [hBattleTurn] + and a + jr z, .ok + ld de, EnemyRolloutCount +.ok + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVar + bit SUBSTATUS_ROLLOUT, a + jr z, .reset + + ld b, $4 ; doturn + jp SkipToBattleCommand + +.reset + xor a + ld [de], a + ret +; 37734 + + +BattleCommand_RolloutPower: ; 37734 +; rolloutpower + + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + ret nz + + ld hl, PlayerRolloutCount + ld a, [hBattleTurn] + and a + jr z, .got_rollout_count + ld hl, EnemyRolloutCount + +.got_rollout_count + ld a, [hl] + and a + jr nz, .skip_set_rampage + ld a, 1 + ld [wSomeoneIsRampaging], a + +.skip_set_rampage + ld a, [AttackMissed] + and a + jr z, .hit + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + res 6, [hl] + ret + +.hit + inc [hl] + ld a, [hl] + ld b, a + cp MAX_ROLLOUT_COUNT + jr c, .not_done_with_rollout + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + res SUBSTATUS_ROLLOUT, [hl] + jr .done_with_substatus_flag + +.not_done_with_rollout + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + set SUBSTATUS_ROLLOUT, [hl] + +.done_with_substatus_flag + ld a, BATTLE_VARS_SUBSTATUS2 + call GetBattleVar + bit SUBSTATUS_CURLED, a + jr z, .not_curled + inc b +.not_curled +.loop + dec b + jr z, .done_damage + + ld hl, CurDamage + 1 + sla [hl] + dec hl + rl [hl] + jr nc, .loop + + ld a, $ff + ld [hli], a + ld [hl], a + +.done_damage + ret +; 37791 diff --git a/engine/battle/effect_commands/sandstorm.asm b/engine/battle/effect_commands/sandstorm.asm new file mode 100644 index 000000000..27b8e8e2c --- /dev/null +++ b/engine/battle/effect_commands/sandstorm.asm @@ -0,0 +1,19 @@ +BattleCommand_StartSandstorm: ; 376f8 +; startsandstorm + + ld a, [Weather] + cp WEATHER_SANDSTORM + jr z, .failed + + ld a, WEATHER_SANDSTORM + ld [Weather], a + ld a, 5 + ld [WeatherCount], a + call AnimateCurrentMove + ld hl, SandstormBrewedText + jp StdBattleTextBox + +.failed + call AnimateFailedMove + jp PrintButItFailed +; 37718 diff --git a/engine/battle/effect_commands/spikes.asm b/engine/battle/effect_commands/spikes.asm new file mode 100644 index 000000000..3d15e4cfd --- /dev/null +++ b/engine/battle/effect_commands/spikes.asm @@ -0,0 +1,27 @@ +BattleCommand_Spikes: ; 37683 +; spikes + + ld hl, EnemyScreens + ld a, [hBattleTurn] + and a + jr z, .asm_3768e + ld hl, PlayerScreens +.asm_3768e + +; Fails if spikes are already down! + + bit SCREENS_SPIKES, [hl] + jr nz, .failed + +; Nothing else stops it from working. + + set SCREENS_SPIKES, [hl] + + call AnimateCurrentMove + + ld hl, SpikesText + jp StdBattleTextBox + +.failed + jp FailSpikes +; 376a0 diff --git a/engine/battle/effect_commands/thief.asm b/engine/battle/effect_commands/thief.asm new file mode 100644 index 000000000..6d32d68d4 --- /dev/null +++ b/engine/battle/effect_commands/thief.asm @@ -0,0 +1,116 @@ +BattleCommand_Thief: ; 37492 +; thief + + ld a, [hBattleTurn] + and a + jr nz, .enemy + +; The player needs to be able to steal an item. + + call .playeritem + ld a, [hl] + and a + ret nz + +; The enemy needs to have an item to steal. + + call .enemyitem + ld a, [hl] + and a + ret z + +; Can't steal mail. + + ld [wd265], a + ld d, a + farcall ItemIsMail + ret c + + ld a, [EffectFailed] + and a + ret nz + + ld a, [wLinkMode] + and a + jr z, .stealenemyitem + + ld a, [wBattleMode] + dec a + ret z + +.stealenemyitem + call .enemyitem + xor a + ld [hl], a + ld [de], a + + call .playeritem + ld a, [wd265] + ld [hl], a + ld [de], a + jr .stole + + +.enemy + +; The enemy can't already have an item. + + call .enemyitem + ld a, [hl] + and a + ret nz + +; The player must have an item to steal. + + call .playeritem + ld a, [hl] + and a + ret z + +; Can't steal mail! + + ld [wd265], a + ld d, a + farcall ItemIsMail + ret c + + ld a, [EffectFailed] + and a + ret nz + +; If the enemy steals your item, +; it's gone for good if you don't get it back. + + call .playeritem + xor a + ld [hl], a + ld [de], a + + call .enemyitem + ld a, [wd265] + ld [hl], a + ld [de], a + + +.stole + call GetItemName + ld hl, StoleText + jp StdBattleTextBox + + +.playeritem + ld a, 1 + call BattlePartyAttr + ld d, h + ld e, l + ld hl, BattleMonItem + ret + +.enemyitem + ld a, 1 + call OTPartyAttr + ld d, h + ld e, l + ld hl, EnemyMonItem + ret +; 37517 diff --git a/engine/battle/effect_commands/transform.asm b/engine/battle/effect_commands/transform.asm new file mode 100755 index 000000000..65c3f3e60 --- /dev/null +++ b/engine/battle/effect_commands/transform.asm @@ -0,0 +1,141 @@ + +BattleCommand_Transform: ; 371cd +; transform + + call ClearLastMove + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + bit SUBSTATUS_TRANSFORMED, [hl] + jp nz, BattleEffect_ButItFailed + call CheckHiddenOpponent + jp nz, BattleEffect_ButItFailed + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + ld a, $1 + ld [wKickCounter], a + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + bit SUBSTATUS_SUBSTITUTE, [hl] + push af + jr z, .mimic_substitute + call CheckUserIsCharging + jr nz, .mimic_substitute + ld a, SUBSTITUTE + call LoadAnim +.mimic_substitute + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVarAddr + set SUBSTATUS_TRANSFORMED, [hl] + call ResetActorDisable + ld hl, BattleMonSpecies + ld de, EnemyMonSpecies + ld a, [hBattleTurn] + and a + jr nz, .got_mon_species + ld hl, EnemyMonSpecies + ld de, BattleMonSpecies + xor a + ld [CurMoveNum], a +.got_mon_species + push hl + ld a, [hli] + ld [de], a + inc hl + inc de + inc de + ld bc, NUM_MOVES + call CopyBytes + ld a, [hBattleTurn] + and a + jr z, .mimic_enemy_backup + ld a, [de] + ld [wEnemyBackupDVs], a + inc de + ld a, [de] + ld [wEnemyBackupDVs + 1], a + dec de +.mimic_enemy_backup +; copy DVs + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + inc de +; move pointer to stats + ld bc, BattleMonStats - BattleMonPP + add hl, bc + push hl + ld h, d + ld l, e + add hl, bc + ld d, h + ld e, l + pop hl + ld bc, BattleMonStructEnd - BattleMonStats + call CopyBytes +; init the power points + ld bc, BattleMonMoves - BattleMonStructEnd + add hl, bc + push de + ld d, h + ld e, l + pop hl + ld bc, BattleMonPP - BattleMonStructEnd + add hl, bc + ld b, NUM_MOVES +.pp_loop + ld a, [de] + inc de + and a + jr z, .done_move + cp SKETCH + ld a, 1 + jr z, .done_move + ld a, 5 +.done_move + ld [hli], a + dec b + jr nz, .pp_loop + pop hl + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, EnemyStats + ld de, PlayerStats + ld bc, 2 * 5 + call BattleSideCopy + ld hl, EnemyStatLevels + ld de, PlayerStatLevels + ld bc, 8 + call BattleSideCopy + call _CheckBattleScene + jr c, .mimic_anims + ld a, [hBattleTurn] + and a + ld a, [wPlayerMinimized] + jr z, .got_byte + ld a, [wEnemyMinimized] +.got_byte + and a + jr nz, .mimic_anims + call LoadMoveAnim + jr .after_anim + +.mimic_anims + call BattleCommand_MoveDelay + call BattleCommand_RaiseSubNoAnim +.after_anim + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + ld a, $2 + ld [wKickCounter], a + pop af + ld a, SUBSTITUTE + call nz, LoadAnim + ld hl, TransformedText + jp StdBattleTextBox + +; 372c6 diff --git a/engine/battle/hidden_power.asm b/engine/battle/hidden_power.asm new file mode 100644 index 000000000..c75a67ab3 --- /dev/null +++ b/engine/battle/hidden_power.asm @@ -0,0 +1,111 @@ +HiddenPowerDamage: ; fbced +; Override Hidden Power's type and power based on the user's DVs. + + ld hl, BattleMonDVs + ld a, [hBattleTurn] + and a + jr z, .got_dvs + ld hl, EnemyMonDVs +.got_dvs + + +; Power: + +; Take the top bit from each stat + + ; Attack + ld a, [hl] + swap a + and 8 + + ; Defense + ld b, a + ld a, [hli] + and 8 + srl a + or b + + ; Speed + ld b, a + ld a, [hl] + swap a + and 8 + srl a + srl a + or b + + ; Special + ld b, a + ld a, [hl] + and 8 + srl a + srl a + srl a + or b + +; Multiply by 5 + ld b, a + add a + add a + add b + +; Add Special & 3 + ld b, a + ld a, [hld] + and 3 + add b + +; Divide by 2 and add 30 + 1 + srl a + add 30 + inc a + + ld d, a + + +; Type: + + ; Def & 3 + ld a, [hl] + and 3 + ld b, a + + ; + (Atk & 3) << 2 + ld a, [hl] + and 3 << 4 + swap a + add a + add a + or b + +; Skip Normal + inc a + +; Skip Bird + cp BIRD + jr c, .done + inc a + +; Skip unused types + cp UNUSED_TYPES + jr c, .done + add SPECIAL - UNUSED_TYPES + +.done + +; Overwrite the current move type. + push af + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVarAddr + pop af + ld [hl], a + +; Get the rest of the damage formula variables +; based on the new type, but keep base power. + ld a, d + push af + farcall BattleCommand_DamageStats ; damagestats + pop af + ld d, a + ret +; fbd54 diff --git a/engine/battle/link_result.asm b/engine/battle/link_result.asm new file mode 100755 index 000000000..cf6102acc --- /dev/null +++ b/engine/battle/link_result.asm @@ -0,0 +1,162 @@ +DetermineLinkBattleResult: ; 2b930 + farcall UpdateEnemyMonInParty + ld hl, PartyMon1HP + call .CountMonsRemaining + push bc + ld hl, OTPartyMon1HP + call .CountMonsRemaining + ld a, c + pop bc + cp c + jr z, .even_number_of_mons_remaining + jr c, .defeat + jr .victory + +.even_number_of_mons_remaining + call .BothSides_CheckNumberMonsAtFullHealth + jr z, .drawn + ld a, e + cp $1 + jr z, .victory + cp $2 + jr z, .defeat + ld hl, PartyMon1HP + call .CalcPercentHPRemaining + push de + ld hl, OTPartyMon1HP + call .CalcPercentHPRemaining + pop hl + ld a, d + cp h + jr c, .victory + jr z, .compare_lo + jr .defeat + +.compare_lo + ld a, e + cp l + jr z, .drawn + jr nc, .defeat + +.victory + ld a, [wBattleResult] + and $f0 + ld [wBattleResult], a + ret + +.defeat + ld a, [wBattleResult] + and $f0 + add $1 + ld [wBattleResult], a + ret + +.drawn + ld a, [wBattleResult] + and $f0 + add $2 + ld [wBattleResult], a + ret + +.CountMonsRemaining: ; 2b995 + ld c, 0 + ld b, 3 + ld de, PARTYMON_STRUCT_LENGTH - 1 +.loop + ld a, [hli] + or [hl] + jr nz, .not_fainted + inc c + +.not_fainted + add hl, de + dec b + jr nz, .loop + ret + +.CalcPercentHPRemaining: ; 2b9a6 + ld de, 0 + ld c, $3 +.loop2 + ld a, [hli] + or [hl] + jr z, .next + dec hl + xor a + ld [hDividend + 0], a + ld a, [hli] + ld [hDividend + 1], a + ld a, [hli] + ld [hDividend + 2], a + xor a + ld [hDividend + 3], a + ld a, [hli] + ld b, a + ld a, [hld] + srl b + rr a + srl b + rr a + ld [hDivisor], a + ld b, $4 + call Divide + ld a, [hQuotient + 2] + add e + ld e, a + ld a, [hQuotient + 1] + adc d + ld d, a + dec hl + +.next + push de + ld de, $2f + add hl, de + pop de + dec c + jr nz, .loop2 + ret + +.BothSides_CheckNumberMonsAtFullHealth: ; 2b9e1 + ld hl, PartyMon1HP + call .CheckFaintedOrFullHealth + jr nz, .finish ; we have a pokemon that's neither fainted nor at full health + ld hl, OTPartyMon1HP + call .CheckFaintedOrFullHealth + ld e, $1 + ret + +.finish + ld hl, OTPartyMon1HP + call .CheckFaintedOrFullHealth + ld e, $0 + ret nz ; we both have pokemon that are neither fainted nor at full health + ld e, $2 + ld a, $1 + and a + ret + +.CheckFaintedOrFullHealth: ; 2ba01 + ld d, 3 +.loop3 + ld a, [hli] + ld b, a + ld a, [hli] + ld c, a + or b + jr z, .fainted_or_full_health + ld a, [hli] + cp b + ret nz + ld a, [hld] + cp c + ret nz + +.fainted_or_full_health + push de + ld de, PARTYMON_STRUCT_LENGTH - 2 + add hl, de + pop de + dec d + jr nz, .loop3 + ret diff --git a/engine/battle/menu.asm b/engine/battle/menu.asm new file mode 100755 index 000000000..07d3e6081 --- /dev/null +++ b/engine/battle/menu.asm @@ -0,0 +1,118 @@ +LoadBattleMenu: ; 24ef2 + ld hl, BattleMenuDataHeader + call LoadMenuDataHeader + ld a, [wBattleMenuCursorBuffer] + ld [wMenuCursorBuffer], a + call InterpretBattleMenu + ld a, [wMenuCursorBuffer] + ld [wBattleMenuCursorBuffer], a + call ExitMenu + ret +; 24f0b + +SafariBattleMenu: ; 24f0b +; untranslated + ld hl, MenuDataHeader_0x24f4e + call LoadMenuDataHeader + jr Function24f19 +; 24f13 + +ContestBattleMenu: ; 24f13 + ld hl, MenuDataHeader_0x24f89 + call LoadMenuDataHeader +; 24f19 + +Function24f19: ; 24f19 + ld a, [wBattleMenuCursorBuffer] + ld [wMenuCursorBuffer], a + call _2DMenu + ld a, [wMenuCursorBuffer] + ld [wBattleMenuCursorBuffer], a + call ExitMenu + ret +; 24f2c + +BattleMenuDataHeader: ; 24f2c + db $40 ; flags + db 12, 08 ; start coords + db 17, 19 ; end coords + dw MenuData_0x24f34 + db 1 ; default option +; 24f34 + +MenuData_0x24f34: ; 0x24f34 + db $81 ; flags + dn 2, 2 ; rows, columns + db 6 ; spacing + dba Strings24f3d + dbw BANK(MenuData_0x24f34), 0 +; 0x24f3d + +Strings24f3d: ; 0x24f3d + db "FIGHT@" + db "<PKMN>@" + db "PACK@" + db "RUN@" +; 24f4e + +MenuDataHeader_0x24f4e: ; 24f4e + db $40 ; flags + db 12, 00 ; start coords + db 17, 19 ; end coords + dw MenuData_0x24f56 + db 1 ; default option +; 24f56 + +MenuData_0x24f56: ; 24f56 + db $81 ; flags + dn 2, 2 ; rows, columns + db 11 ; spacing + dba Strings24f5f + dba Function24f7c +; 24f5f + +Strings24f5f: ; 24f5f + db "サファりボール× @" ; "SAFARI BALL× @" + db "エサをなげる@" ; "THROW BAIT" + db "いしをなげる@" ; "THROW ROCK" + db "にげる@" ; "RUN" +; 24f7c + +Function24f7c: ; 24f7c + hlcoord 17, 13 + ld de, wSafariBallsRemaining + lb bc, PRINTNUM_LEADINGZEROS | 1, 2 + call PrintNum + ret +; 24f89 + +MenuDataHeader_0x24f89: ; 24f89 + db $40 ; flags + db 12, 02 ; start coords + db 17, 19 ; end coords + dw MenuData_0x24f91 + db 1 ; default option +; 24f91 + +MenuData_0x24f91: ; 24f91 + db $81 ; flags + dn 2, 2 ; rows, columns + db 12 ; spacing + dba Strings24f9a + dba Function24fb2 +; 24f9a + +Strings24f9a: ; 24f9a + db "FIGHT@" + db "<PKMN>", "@" + db "PARKBALL× @" + db "RUN@" +; 24fb2 + +Function24fb2: ; 24fb2 + hlcoord 13, 16 + ld de, wParkBallsRemaining + lb bc, PRINTNUM_LEADINGZEROS | 1, 2 + call PrintNum + ret +; 24fbf diff --git a/engine/battle/misc.asm b/engine/battle/misc.asm new file mode 100644 index 000000000..b05dc8071 --- /dev/null +++ b/engine/battle/misc.asm @@ -0,0 +1,257 @@ +_DisappearUser: ; fbd54 + xor a + ld [hBGMapMode], a + ld a, [hBattleTurn] + and a + jr z, .player + call GetEnemyFrontpicCoords + jr .okay +.player + call GetPlayerBackpicCoords +.okay + call ClearBox + jr FinishAppearDisappearUser + +_AppearUserRaiseSub: ; fbd69 (3e:7d69) + farcall BattleCommand_RaiseSubNoAnim + jr AppearUser + +_AppearUserLowerSub: ; fbd71 (3e:7d71) + farcall BattleCommand_LowerSubNoAnim + +AppearUser: ; fbd77 (3e:7d77) + xor a + ld [hBGMapMode], a + ld a, [hBattleTurn] + and a + jr z, .player + call GetEnemyFrontpicCoords + xor a + jr .okay +.player + call GetPlayerBackpicCoords + ld a, $31 +.okay + ld [hGraphicStartTile], a + predef PlaceGraphic +FinishAppearDisappearUser: ; fbd91 (3e:7d91) + ld a, $1 + ld [hBGMapMode], a + ret + +GetEnemyFrontpicCoords: ; fbd96 (3e:7d96) + hlcoord 12, 0 + lb bc, 7, 7 + ret + +GetPlayerBackpicCoords: ; fbd9d (3e:7d9d) + hlcoord 2, 6 + lb bc, 6, 6 + ret + + +DoWeatherModifiers: ; fbda4 + + ld de, .WeatherTypeModifiers + ld a, [Weather] + ld b, a + ld a, [wd265] ; move type + ld c, a + +.CheckWeatherType: + ld a, [de] + inc de + cp $ff + jr z, .done_weather_types + + cp b + jr nz, .NextWeatherType + + ld a, [de] + cp c + jr z, .ApplyModifier + +.NextWeatherType: + inc de + inc de + jr .CheckWeatherType + + +.done_weather_types + ld de, .WeatherMoveModifiers + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + ld c, a + +.CheckWeatherMove: + ld a, [de] + inc de + cp $ff + jr z, .done + + cp b + jr nz, .NextWeatherMove + + ld a, [de] + cp c + jr z, .ApplyModifier + +.NextWeatherMove: + inc de + inc de + jr .CheckWeatherMove + +.ApplyModifier: + xor a + ld [hMultiplicand + 0], a + ld hl, CurDamage + ld a, [hli] + ld [hMultiplicand + 1], a + ld a, [hl] + ld [hMultiplicand + 2], a + + inc de + ld a, [de] + ld [hMultiplier], a + + call Multiply + + ld a, 10 + ld [hDivisor], a + ld b, $4 + call Divide + + ld a, [hQuotient + 0] + and a + ld bc, -1 + jr nz, .Update + + ld a, [hQuotient + 1] + ld b, a + ld a, [hQuotient + 2] + ld c, a + or b + jr nz, .Update + + ld bc, 1 + +.Update: + ld a, b + ld [CurDamage], a + ld a, c + ld [CurDamage + 1], a + +.done + ret + +.WeatherTypeModifiers: + db WEATHER_RAIN, WATER, 15 + db WEATHER_RAIN, FIRE, 05 + db WEATHER_SUN, FIRE, 15 + db WEATHER_SUN, WATER, 05 + db $ff + +.WeatherMoveModifiers: + db WEATHER_RAIN, EFFECT_SOLARBEAM, 05 + db $ff +; fbe24 + + +DoBadgeTypeBoosts: ; fbe24 + ld a, [wLinkMode] + and a + ret nz + + ld a, [InBattleTowerBattle] + and a + ret nz + + ld a, [hBattleTurn] + and a + ret nz + + push de + push bc + + ld hl, .BadgeTypes + + ld a, [KantoBadges] + ld b, a + ld a, [JohtoBadges] + ld c, a + +.CheckBadge: + ld a, [hl] + cp $ff + jr z, .done + + srl b + rr c + jr nc, .NextBadge + + ld a, [wd265] ; move type + cp [hl] + jr z, .ApplyBoost + +.NextBadge: + inc hl + jr .CheckBadge + +.ApplyBoost: + ld a, [CurDamage] + ld h, a + ld d, a + ld a, [CurDamage + 1] + ld l, a + ld e, a + + srl d + rr e + srl d + rr e + srl d + rr e + + ld a, e + or d + jr nz, .done_min + ld e, 1 + +.done_min + add hl, de + jr nc, .Update + + ld hl, $ffff + +.Update: + ld a, h + ld [CurDamage], a + ld a, l + ld [CurDamage + 1], a + +.done + pop bc + pop de + ret + +.BadgeTypes: + db FLYING ; zephyrbadge + db BUG ; hivebadge + db NORMAL ; plainbadge + db GHOST ; fogbadge + db STEEL ; mineralbadge + db FIGHTING ; stormbadge + db ICE ; glacierbadge + db DRAGON ; risingbadge + + db ROCK ; boulderbadge + db WATER ; cascadebadge + db ELECTRIC ; thunderbadge + db GRASS ; rainbowbadge + db POISON ; soulbadge + db PSYCHIC ; marshbadge + db FIRE ; volcanobadge + db GROUND ; earthbadge + db $ff +; fbe91 diff --git a/engine/read_trainer_attributes.asm b/engine/battle/read_trainer_attributes.asm index dfb8d3682..dfb8d3682 100644 --- a/engine/read_trainer_attributes.asm +++ b/engine/battle/read_trainer_attributes.asm diff --git a/engine/read_trainer_party.asm b/engine/battle/read_trainer_party.asm index 9b7727a84..9b7727a84 100755 --- a/engine/read_trainer_party.asm +++ b/engine/battle/read_trainer_party.asm diff --git a/engine/battle/sliding_intro.asm b/engine/battle/sliding_intro.asm new file mode 100755 index 000000000..ed78add8e --- /dev/null +++ b/engine/battle/sliding_intro.asm @@ -0,0 +1,104 @@ +BattleIntroSlidingPics: ; 4e980 + ld a, [rSVBK] + push af + ld a, $5 + ld [rSVBK], a + call .subfunction1 + ld a, rSCX - $ff00 + ld [hLCDCPointer], a + call .subfunction2 + xor a + ld [hLCDCPointer], a + pop af + ld [rSVBK], a + ret +; 4e998 + +.subfunction1 ; 4e998 + call .subfunction4 + ld a, $90 + ld [hSCX], a + ld a, %11100100 + call DmgToCgbBGPals + lb de, %11100100, %11100100 + call DmgToCgbObjPals + ret +; 4e9ab + +.subfunction2 ; 4e9ab + ld d, $90 + ld e, $72 + ld a, $48 + inc a +.loop1 + push af +.loop2 + ld a, [rLY] + cp $60 + jr c, .loop2 + ld a, d + ld [hSCX], a + call .subfunction5 + inc e + inc e + dec d + dec d + pop af + push af + cp $1 + jr z, .skip1 + push de + call .subfunction3 + pop de + +.skip1 + call DelayFrame + pop af + dec a + jr nz, .loop1 + ret +; 4e9d6 + +.subfunction3 ; 4e9d6 + ld hl, Sprites + 1 ; x pixel + ld c, $12 ; 18 + ld de, $4 +.loop3 + dec [hl] + dec [hl] + add hl, de + dec c + jr nz, .loop3 + ret +; 4e9e5 + +.subfunction4 ; 4e9e5 + ld hl, LYOverrides + ld a, $90 + ld bc, SCREEN_HEIGHT_PX + call ByteFill + ret +; 4e9f1 + +.subfunction5 ; 4e9f1 + ld hl, LYOverrides + ld a, d + ld c, $3e ; 62 +.loop4 + ld [hli], a + dec c + jr nz, .loop4 + ld a, e + ld c, $22 ; 34 +.loop5 + ld [hli], a + dec c + jr nz, .loop5 + xor a + ld c, $30 ; 48 +.loop6 + ld [hli], a + dec c + jr nz, .loop6 + ret +; 4ea0a diff --git a/engine/start_battle.asm b/engine/battle/start_battle.asm index 8d510b72e..8d510b72e 100644 --- a/engine/start_battle.asm +++ b/engine/battle/start_battle.asm diff --git a/engine/battle/trainer_huds.asm b/engine/battle/trainer_huds.asm new file mode 100755 index 000000000..9efe08414 --- /dev/null +++ b/engine/battle/trainer_huds.asm @@ -0,0 +1,269 @@ +BattleStart_TrainerHuds: ; 2c000 + ld a, $e4 + ld [rOBP0], a + call LoadBallIconGFX + call ShowPlayerMonsRemaining + ld a, [wBattleMode] + dec a + ret z + jp ShowOTTrainerMonsRemaining +; 2c012 + +EnemySwitch_TrainerHud: ; 2c012 + ld a, $e4 + ld [rOBP0], a + call LoadBallIconGFX + jp ShowOTTrainerMonsRemaining +; 2c01c + +ShowPlayerMonsRemaining: ; 2c01c + call DrawPlayerPartyIconHUDBorder + ld hl, PartyMon1HP + ld de, PartyCount + call StageBallTilesData + ; ldpixel wPlaceBallsX, 12, 12 + ld a, 12 * 8 + ld hl, wPlaceBallsX + ld [hli], a + ld [hl], a + ld a, 8 + ld [wPlaceBallsDirection], a + ld hl, Sprites + jp LoadTrainerHudOAM +; 2c03a + +ShowOTTrainerMonsRemaining: ; 2c03a + call DrawEnemyHUDBorder + ld hl, OTPartyMon1HP + ld de, OTPartyCount + call StageBallTilesData + ; ldpixel wPlaceBallsX, 9, 4 + ld hl, wPlaceBallsX + ld a, 9 * 8 + ld [hli], a + ld [hl], 4 * 8 + ld a, -8 + ld [wPlaceBallsDirection], a + ld hl, Sprites + PARTY_LENGTH * 4 + jp LoadTrainerHudOAM +; 2c059 + +StageBallTilesData: ; 2c059 + ld a, [de] + push af + ld de, Buffer1 + ld c, PARTY_LENGTH + ld a, $34 ; empty slot +.loop1 + ld [de], a + inc de + dec c + jr nz, .loop1 + pop af + ld de, Buffer1 +.loop2 + push af + call .GetHUDTile + inc de + pop af + dec a + jr nz, .loop2 + ret +; 2c075 + +.GetHUDTile: ; 2c075 + ld a, [hli] + and a + jr nz, .got_hp + ld a, [hl] + and a + ld b, $33 ; fainted + jr z, .fainted + +.got_hp + dec hl + dec hl + dec hl + ld a, [hl] + and a + ld b, $32 ; statused + jr nz, .load + dec b ; normal + jr .load + +.fainted + dec hl + dec hl + dec hl + +.load + ld a, b + ld [de], a + ld bc, PARTYMON_STRUCT_LENGTH + MON_HP - MON_STATUS + add hl, bc + ret +; 2c095 + +DrawPlayerHUDBorder: ; 2c095 + ld hl, .tiles + ld de, wTrainerHUDTiles + ld bc, 4 + call CopyBytes + hlcoord 18, 10 + ld de, -1 ; start on right + jr PlaceHUDBorderTiles + +.tiles + db $73 ; right side + db $77 ; bottom right + db $6f ; bottom left + db $76 ; bottom side +; 2c0ad + +DrawPlayerPartyIconHUDBorder: ; 2c0ad + ld hl, .tiles + ld de, wTrainerHUDTiles + ld bc, 4 + call CopyBytes + hlcoord 18, 10 + ld de, -1 ; start on right + jr PlaceHUDBorderTiles + +.tiles + db $73 ; right side + db $5c ; bottom right + db $6f ; bottom left + db $76 ; bottom side +; 2c0c5 + +DrawEnemyHUDBorder: ; 2c0c5 + ld hl, .tiles + ld de, wTrainerHUDTiles + ld bc, 4 + call CopyBytes + hlcoord 1, 2 + ld de, 1 ; start on left + call PlaceHUDBorderTiles + ld a, [wBattleMode] + dec a + ret nz + ld a, [TempEnemyMonSpecies] + dec a + call CheckCaughtMon + ret z + hlcoord 1, 1 + ld [hl], $5d + ret + +.tiles + db $6d ; left side + db $74 ; bottom left + db $78 ; bottom right + db $76 ; bottom side +; 2c0f1 + +PlaceHUDBorderTiles: ; 2c0f1 + ld a, [wTrainerHUDTiles] + ld [hl], a + ld bc, SCREEN_WIDTH + add hl, bc + ld a, [StartFlypoint] + ld [hl], a + ld b, $8 +.loop + add hl, de + ld a, [MovementBuffer] + ld [hl], a + dec b + jr nz, .loop + add hl, de + ld a, [EndFlypoint] + ld [hl], a + ret +; 2c10d + +LinkBattle_TrainerHuds: ; 2c10d + call LoadBallIconGFX + ld hl, PartyMon1HP + ld de, PartyCount + call StageBallTilesData + ld hl, wPlaceBallsX + ld a, 10 * 8 + ld [hli], a + ld [hl], 8 * 8 + ld a, $8 + ld [wPlaceBallsDirection], a + ld hl, Sprites + call LoadTrainerHudOAM + + ld hl, OTPartyMon1HP + ld de, OTPartyCount + call StageBallTilesData + ld hl, wPlaceBallsX + ld a, 10 * 8 + ld [hli], a + ld [hl], 13 * 8 + ld hl, Sprites + PARTY_LENGTH * 4 + jp LoadTrainerHudOAM +; 2c143 + +LoadTrainerHudOAM: ; 2c143 + ld de, Buffer1 + ld c, PARTY_LENGTH +.loop + ld a, [wPlaceBallsY] + ld [hli], a + ld a, [wPlaceBallsX] + ld [hli], a + ld a, [de] + ld [hli], a + ld a, $3 + ld [hli], a + ld a, [wPlaceBallsX] + ld b, a + ld a, [wPlaceBallsDirection] + add b + ld [wPlaceBallsX], a + inc de + dec c + jr nz, .loop + ret +; 2c165 + +LoadBallIconGFX: ; 2c165 + ld de, .gfx + ld hl, VTiles0 tile $31 + lb bc, BANK(LoadBallIconGFX), 4 + call Get2bpp_2 + ret +; 2c172 + +.gfx ; 2c172 +INCBIN "gfx/battle/balls.2bpp" +; 2c1b2 + +_ShowLinkBattleParticipants: ; 2c1b2 + call ClearBGPalettes + call LoadFontsExtra + hlcoord 2, 3 + ld b, 9 + ld c, 14 + call TextBox + hlcoord 4, 5 + ld de, PlayerName + call PlaceString + hlcoord 4, 10 + ld de, OTPlayerName + call PlaceString + hlcoord 9, 8 + ld a, "<BOLD_V>" + ld [hli], a + ld [hl], "<BOLD_S>" + farcall LinkBattle_TrainerHuds ; no need to farcall + ld b, SCGB_DIPLOMA + call GetSGBLayout + call SetPalettes + ld a, $e4 + ld [rOBP0], a + ret +; 2c1ef diff --git a/engine/trainer_scripts.asm b/engine/battle/trainer_scripts.asm index 212cd7f28..212cd7f28 100644 --- a/engine/trainer_scripts.asm +++ b/engine/battle/trainer_scripts.asm diff --git a/engine/battle/used_move_text.asm b/engine/battle/used_move_text.asm new file mode 100755 index 000000000..ce9e51359 --- /dev/null +++ b/engine/battle/used_move_text.asm @@ -0,0 +1,338 @@ +DisplayUsedMoveText: ; 105db0 +; battle command 03 + ld hl, UsedMoveText + call BattleTextBox + jp WaitBGMap +; 105db9 + +UsedMoveText: ; 105db9 +; this is a stream of text and asm from 105db9 to 105ef6 + text_jump _ActorNameText + start_asm + ld a, [hBattleTurn] + and a + jr nz, .start + + ld a, [wPlayerMoveStruct + MOVE_ANIM] + call UpdateUsedMoves + +.start + ld a, BATTLE_VARS_LAST_MOVE + call GetBattleVarAddr + ld d, h + ld e, l + + ld a, BATTLE_VARS_LAST_COUNTER_MOVE + call GetBattleVarAddr + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld [wd265], a + + push hl + farcall CheckUserIsCharging + pop hl + jr nz, .grammar + + ; update last move + ld a, [wd265] + ld [hl], a + ld [de], a + +.grammar + call GetMoveGrammar +; wd265 now contains MoveGrammar + +; everything except 'instead' made redundant in localization + + ; check obedience + ld a, [AlreadyDisobeyed] + and a + ld hl, UsedMove2Text + ret nz + + ; check move grammar + ld a, [wd265] + cp $3 + ld hl, UsedMove2Text + ret c + ld hl, UsedMove1Text + ret +; 105e04 + +UsedMove1Text: ; 105e04 + text_jump _UsedMove1Text + start_asm + jr UsedMoveText_CheckObedience +; 105e0b + +UsedMove2Text: ; 105e0b + text_jump _UsedMove2Text + start_asm +UsedMoveText_CheckObedience: ; 105e10 +; check obedience + ld a, [AlreadyDisobeyed] + and a + jr z, .GetMoveNameText +; print "instead," + ld hl, .UsedInsteadText + ret +; 105e1a + +.UsedInsteadText: + text_jump _UsedInsteadText + start_asm +.GetMoveNameText: + ld hl, MoveNameText + ret +; 105e23 + +MoveNameText: ; 105e23 + text_jump _MoveNameText + start_asm +; get start address + ld hl, .endusedmovetexts + +; get move id + ld a, [wd265] + +; 2-byte pointer + add a + +; seek + push bc + ld b, $0 + ld c, a + add hl, bc + pop bc + +; get pointer to usedmovetext ender + ld a, [hli] + ld h, [hl] + ld l, a + ret +; 105e39 + +.endusedmovetexts ; 105e39 + dw EndUsedMove1Text + dw EndUsedMove2Text + dw EndUsedMove3Text + dw EndUsedMove4Text + dw EndUsedMove5Text +; 105e43 + +EndUsedMove1Text: ; 105e43 + text_jump _EndUsedMove1Text + db "@" +; 105e48 +EndUsedMove2Text: ; 105e48 + text_jump _EndUsedMove2Text + db "@" +; 105e4d +EndUsedMove3Text: ; 105e4d + text_jump _EndUsedMove3Text + db "@" +; 105e52 +EndUsedMove4Text: ; 105e52 + text_jump _EndUsedMove4Text + db "@" +; 105e57 +EndUsedMove5Text: ; 105e57 + text_jump _EndUsedMove5Text + db "@" +; 105e5c + + +GetMoveGrammar: ; 105e5c +; store move grammar type in wd265 + + push bc +; c = move id + ld a, [wd265] + ld c, a + ld b, $0 + +; read grammar table + ld hl, MoveGrammar +.loop + ld a, [hli] +; end of table? + cp $ff + jr z, .end +; match? + cp c + jr z, .end +; advance grammar type at $00 + and a + jr nz, .loop +; next grammar type + inc b + jr .loop + +.end +; wd265 now contains move grammar + ld a, b + ld [wd265], a + +; we're done + pop bc + ret +; 105e7a + +MoveGrammar: ; 105e7a +; made redundant in localization +; each move is given an identifier for what usedmovetext to use (0-4): + +; 0 + db SWORDS_DANCE + db GROWTH + db STRENGTH + db HARDEN + db MINIMIZE + db SMOKESCREEN + db WITHDRAW + db DEFENSE_CURL + db EGG_BOMB + db SMOG + db BONE_CLUB + db FLASH + db SPLASH + db ACID_ARMOR + db BONEMERANG + db REST + db SHARPEN + db SUBSTITUTE + db MIND_READER + db SNORE + db PROTECT + db SPIKES + db ENDURE + db ROLLOUT + db SWAGGER + db SLEEP_TALK + db HIDDEN_POWER + db PSYCH_UP + db EXTREMESPEED + db 0 ; end set + +; 1 + db RECOVER + db TELEPORT + db BIDE + db SELFDESTRUCT + db AMNESIA + db FLAIL + db 0 ; end set + +; 2 + db MEDITATE + db AGILITY + db MIMIC + db DOUBLE_TEAM + db BARRAGE + db TRANSFORM + db STRUGGLE + db SCARY_FACE + db 0 ; end set + +; 3 + db POUND + db SCRATCH + db VICEGRIP + db WING_ATTACK + db FLY + db BIND + db SLAM + db HORN_ATTACK + db WRAP + db THRASH + db TAIL_WHIP + db LEER + db BITE + db GROWL + db ROAR + db SING + db PECK + db ABSORB + db STRING_SHOT + db EARTHQUAKE + db FISSURE + db DIG + db TOXIC + db SCREECH + db METRONOME + db LICK + db CLAMP + db CONSTRICT + db POISON_GAS + db BUBBLE + db SLASH + db SPIDER_WEB + db NIGHTMARE + db CURSE + db FORESIGHT + db CHARM + db ATTRACT + db ROCK_SMASH + db 0 ; end set + +; all other moves = 4 + db $ff ; end +; 105ed0 + + +UpdateUsedMoves: ; 105ed0 +; append move a to PlayerUsedMoves unless it has already been used + + push bc +; start of list + ld hl, PlayerUsedMoves +; get move id + ld b, a +; next count + ld c, NUM_MOVES + +.loop +; get move from the list + ld a, [hli] +; not used yet? + and a + jr z, .add +; already used? + cp b + jr z, .quit +; next byte + dec c + jr nz, .loop + +; if the list is full and the move hasn't already been used +; shift the list back one byte, deleting the first move used +; this can occur with struggle or a new learned move + ld hl, PlayerUsedMoves + 1 +; 1 = 2 + ld a, [hld] + ld [hli], a +; 2 = 3 + inc hl + ld a, [hld] + ld [hli], a +; 3 = 4 + inc hl + ld a, [hld] + ld [hl], a +; 4 = new move + ld a, b + ld [PlayerUsedMoves + 3], a + jr .quit + +.add +; go back to the byte we just inced from + dec hl +; add the new move + ld [hl], b + +.quit +; list updated + pop bc + ret +; 105ef6 diff --git a/engine/map_setup.asm b/engine/map_setup.asm index 20faecb5d..472532739 100644 --- a/engine/map_setup.asm +++ b/engine/map_setup.asm @@ -1,4 +1,3 @@ - RunMapSetupScript:: ; 15363 ld a, [hMapEntryMethod] and $f @@ -15,183 +14,7 @@ RunMapSetupScript:: ; 15363 ret ; 15377 -MapSetupScripts: ; 15377 - dw MapSetupScript_Warp - dw MapSetupScript_Continue - dw MapSetupScript_ReloadMap - dw MapSetupScript_Teleport - dw MapSetupScript_Door - dw MapSetupScript_Fall - dw MapSetupScript_Connection - dw MapSetupScript_LinkReturn - dw MapSetupScript_Train - dw MapSetupScript_Submenu - dw MapSetupScript_BadWarp - dw MapSetupScript_Fly -; 1538f - -MapSetupScript_Teleport: ; 1538f - db map_prolong_sprites -MapSetupScript_Fly: ; 15390 - db map_fade_out_palettes - db map_keep_roam -MapSetupScript_Warp: ; 15392 - db map_lcd_off - db map_sound_off - db map_load_spawn - db map_attributes - db map_change_callback - db map_spawn_coord - db map_player_coord - db map_anchor_screen - db map_load_blocks - db map_buffer_screen - db map_load_graphics - db map_time_of_day - db map_load_objects - db map_lcd_on - db map_palettes - db map_face_down - db map_sprites - db map_bike_music - db map_max_volume - db map_fade_in_palettes - db map_animations_on - db map_wildmons - db map_end - -MapSetupScript_BadWarp: ; 153a9 - db map_load_spawn - db map_attributes - db map_change_callback - db map_spawn_coord - db map_player_coord - db map_anchor_screen - db map_load_blocks - db map_buffer_screen - db map_lcd_off - db map_load_graphics - db map_time_of_day - db map_fade_out_music - db map_lcd_on - db map_load_objects - db map_palettes - db map_face_down - db map_sprites - db map_fade_music - db map_fade_in_palettes - db map_animations_on - db map_wildmons - db map_end - -MapSetupScript_Connection: ; 153bf - db map_animations_off - db map_load_connection - db map_attributes - db map_change_callback - db map_player_coord - db map_load_blocks - db map_load_tileset - db map_save_screen - db map_load_objects - db map_fade_music - db map_palettes - db map_stop_script - db map_keep_palettes - db map_wildmons - db map_update_roam - db map_animations_on - db map_end - -MapSetupScript_Fall: ; 153d0 - db map_prolong_sprites -MapSetupScript_Door: ; 153d1 - db map_fade_out_palettes -MapSetupScript_Train: ; 153d2 - db map_load_warp - db map_attributes - db map_warp_face - db map_change_callback - db map_player_coord - db map_load_blocks - db map_buffer_screen - db map_lcd_off - db map_load_graphics - db map_time_of_day - db map_fade_out_music - db map_lcd_on - db map_load_objects - db map_palettes - db map_sprites - db map_fade_music - db map_fade_in_palettes - db map_animations_on - db map_wildmons - db map_update_roam - db map_end - -MapSetupScript_ReloadMap: ; 153e7 - db map_fade - db map_clear_bg_palettes - db map_lcd_off - db map_sound_off - db map_load_blocks - db map_connection_blocks - db map_load_graphics - db map_time_of_day - db map_lcd_on - db map_palettes - db map_sprites - db map_music_force - db map_fade_in_palettes - db map_animations_on - db map_wildmons - db map_end - -MapSetupScript_LinkReturn: ; 153f7 - db map_fade - db map_lcd_off - db map_sound_off - db map_change_callback - db map_load_blocks - db map_buffer_screen - db map_load_graphics - db map_time_of_day - db map_lcd_on - db map_palettes - db map_sprites - db map_bike_music - db map_fade_in_palettes - db map_animations_on - db map_wildmons - db map_text_scroll_off - db map_end - -MapSetupScript_Continue: ; 15408 - db map_lcd_off - db map_sound_off - db map_attributes_2 - db map_anchor_screen - db map_start_callback - db map_load_blocks - db map_connection_blocks - db map_buffer_screen - db map_load_graphics - db map_time_of_day - db map_lcd_on - db map_palettes - db map_sprites - db map_bike_music - db map_fade_in_palettes - db map_animations_on - db map_wildmons - db map_end - -MapSetupScript_Submenu: ; 1541a - db map_load_blocks - db map_connection_blocks - db map_end - +INCLUDE "data/maps/map_setup_scripts.asm" ReadMapSetupScript: ; 1541d .loop @@ -238,6 +61,7 @@ ReadMapSetupScript: ; 1541d ; 15440 MapSetupCommands: ; 15440 +; entries correspond to command indexes in constants/map_setup_constants.asm dba EnableLCD ; 00 dba DisableLCD ; 01 dba MapSetup_Sound_Off ; 02 diff --git a/engine/mystery_gift_2.asm b/engine/mystery_gift_2.asm index dc0baf39c..1d180f714 100755 --- a/engine/mystery_gift_2.asm +++ b/engine/mystery_gift_2.asm @@ -147,6 +147,6 @@ MysteryGiftFallbackItem: ; 2c722 (b:4722) ; 2c725 (b:4725) -INCLUDE "data/mystery_gift/items.asm" +INCLUDE "data/mystery_gift_items.asm" -INCLUDE "data/mystery_gift/decos.asm" +INCLUDE "data/mystery_gift_decos.asm" diff --git a/engine/pokegear.asm b/engine/pokegear.asm index 96959205b..a3e43cebf 100755 --- a/engine/pokegear.asm +++ b/engine/pokegear.asm @@ -2338,7 +2338,7 @@ HasVisitedSpawn: ; 91c50 ; 91c5e -INCLUDE "data/flypoints.asm" +INCLUDE "data/maps/flypoints.asm" ret_91c8f: ; 91c8f ret diff --git a/engine/sprites.asm b/engine/sprites.asm index 755ee0835..cc579a914 100755 --- a/engine/sprites.asm +++ b/engine/sprites.asm @@ -551,13 +551,13 @@ BrokenGetStdGraphics: ; 8d1ac ; 8d1c4 -INCLUDE "data/sprite_anim_seqs.asm" +INCLUDE "data/sprites/sequences.asm" INCLUDE "engine/sprite_anims.asm" -INCLUDE "data/sprite_anim_frames.asm" +INCLUDE "data/sprites/framesets.asm" -INCLUDE "data/sprite_anim_oam.asm" +INCLUDE "data/sprites/oam.asm" BrokenStdGFXPointers: ; Broken 2bpp pointers diff --git a/engine/tmhm.asm b/engine/tmhm.asm index 78d3b1707..6a9c76f00 100755 --- a/engine/tmhm.asm +++ b/engine/tmhm.asm @@ -46,4 +46,4 @@ GetTMHMMove: ; 1166a ; 1167a -INCLUDE "data/tmhm_moves.asm" +INCLUDE "data/moves/tmhm_moves.asm" diff --git a/engine/types.asm b/engine/types.asm new file mode 100644 index 000000000..375bfe434 --- /dev/null +++ b/engine/types.asm @@ -0,0 +1,101 @@ +PrintMonTypes: ; 5090d +; Print one or both types of [CurSpecies] +; on the stats screen at hl. + + push hl + call GetBaseData + pop hl + + push hl + ld a, [BaseType1] + call .Print + + ; Single-typed monsters really + ; have two of the same type. + ld a, [BaseType1] + ld b, a + ld a, [BaseType2] + cp b + pop hl + jr z, .hide_type_2 + + ld bc, SCREEN_WIDTH + add hl, bc + +.Print: + ld b, a + jr PrintType + +.hide_type_2 + ; Erase any type name that was here before. + ; Seems to be pointless in localized versions. + ld a, " " + ld bc, SCREEN_WIDTH - 3 + add hl, bc + ld [hl], a + inc bc + add hl, bc + ld bc, 5 + jp ByteFill +; 5093a + + +PrintMoveType: ; 5093a +; Print the type of move b at hl. + + push hl + ld a, b + dec a + ld bc, MOVE_LENGTH + ld hl, Moves + call AddNTimes + ld de, StringBuffer1 + ld a, BANK(Moves) + call FarCopyBytes + ld a, [StringBuffer1 + MOVE_TYPE] + pop hl + + ld b, a + + +PrintType: ; 50953 +; Print type b at hl. + + ld a, b + + push hl + add a + ld hl, TypeNames + ld e, a + ld d, 0 + add hl, de + ld a, [hli] + ld e, a + ld d, [hl] + pop hl + + jp PlaceString +; 50964 + + +GetTypeName: ; 50964 +; Copy the name of type [wd265] to StringBuffer1. + + ld a, [wd265] + ld hl, TypeNames + ld e, a + ld d, 0 + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + ld de, StringBuffer1 + ld bc, 13 + jp CopyBytes +; 5097b + + +INCLUDE "data/type_names.asm" + +; 50a28 |