summaryrefslogtreecommitdiff
path: root/engine/battle/ai
diff options
context:
space:
mode:
authorRemy Oukaour <remy.oukaour@gmail.com>2017-12-26 17:47:05 -0500
committerRemy Oukaour <remy.oukaour@gmail.com>2017-12-26 17:47:05 -0500
commitb5417fafec7dd37cb4be391f3bd3d4541a2a381e (patch)
treea4e7d08afb2e862186a138e82c8ef4785d82786d /engine/battle/ai
parent2f98c2032fd47ada3484bfc37d590992f286d3d4 (diff)
Split battle/ into data/ and engine/ components
Diffstat (limited to 'engine/battle/ai')
-rw-r--r--engine/battle/ai/items.asm882
-rwxr-xr-xengine/battle/ai/move.asm221
-rwxr-xr-xengine/battle/ai/redundant.asm198
-rw-r--r--engine/battle/ai/scoring.asm3598
-rwxr-xr-xengine/battle/ai/switch.asm672
5 files changed, 5571 insertions, 0 deletions
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