jep-hack/engine/battle/ai/scoring.asm
Llinos Evans 093bda0253 Strong Arm, Water Sport, and more HMs.
This adds Rock Climb functionality to Strong Arm and Dive functionality to Water Sport, as discussed in the server. HMs have been added, but we need 16bit Items to add Wind Ride, and I haven't finished their functionality.

The Rock Climb tile is a bit terrible, it's not easy to notice. Maybe change so that it works well with yellow or another colour?

This does not build due to issues with effect_commands.asm, but since Zeta is meant to be working on the mapping and Water Sport anyway, it seems to be up his alley.

I ported over much of the underwater assets Rangi was using as they looked very pretty. I imagine it'll be fun to utilise going forward. May as well, right?

I shall now lay down in a dark room.

Review: c21561ea71 (diff-5508f3b794fc68821ba35e94b6a293b2aaaa16c02a1b34fac70d03fd2f74c4b2R113)
2024-12-28 06:26:01 +00:00

3331 lines
54 KiB
NASM

AIScoring: ; used only for BANK(AIScoring)
AI_Basic:
; 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, wEnemyAIMoveScores - 1
ld de, wEnemyMonMoves
ld b, NUM_MOVES + 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, [wBattleMonStatus]
and a
jr nz, .discourage
; Dismiss Safeguard if it's already active.
ld a, [wPlayerScreens]
bit SCREENS_SAFEGUARD, a
jr z, .checkmove
.discourage
call AIDiscourageMove
jr .checkmove
INCLUDE "data/battle/ai/status_only_effects.asm"
AI_Setup:
; 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, wEnemyAIMoveScores - 1
ld de, wEnemyMonMoves
ld b, NUM_MOVES + 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, [wEnemyTurnsTaken]
and a
jr nz, .discourage
jr .encourage
.statdown
ld a, [wPlayerTurnsTaken]
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
AI_Types:
; 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, wEnemyAIMoveScores - 1
ld de, wEnemyMonMoves
ld b, NUM_MOVES + 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
ldh [hBattleTurn], a
callfar BattleCheckTypeMatchup
pop de
pop bc
pop hl
ld a, [wTypeMatchup]
and a
jr z, .immune
cp EFFECTIVE
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, wEnemyMonMoves
ld b, NUM_MOVES + 1
ld c, 0
.checkmove2
dec b
jr z, .movesdone
ld a, [hli]
and a
jr z, .movesdone
call AIGetEnemyMove
ld a, [wEnemyMoveStruct + MOVE_TYPE]
cp d
jr z, .checkmove2
ld a, [wEnemyMoveStruct + MOVE_POWER]
and a
jr nz, .damaging
jr .checkmove2
.damaging
ld c, a
.movesdone
ld a, c
pop bc
pop de
pop hl
and a
jr z, .checkmove
inc [hl]
jr .checkmove
.immune
call AIDiscourageMove
jr .checkmove
AI_Offensive:
; Greatly discourage non-damaging moves.
ld hl, wEnemyAIMoveScores - 1
ld de, wEnemyMonMoves
ld b, NUM_MOVES + 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
AI_Smart:
; Context-specific scoring.
ld hl, wEnemyAIMoveScores
ld de, wEnemyMonMoves
ld b, NUM_MOVES + 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, AI_Smart_EffectHandlers
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
AI_Smart_EffectHandlers:
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
dbw EFFECT_SURF, AI_Smart_Surf
dbw EFFECT_WHIRLPOOL, AI_Smart_Whirlpool
db -1 ; end
AI_Smart_Sleep:
; 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, .encourage
ld b, EFFECT_NIGHTMARE
call AIHasMoveEffect
ret nc
.encourage
call AI_50_50
ret c
dec [hl]
dec [hl]
ret
AI_Smart_LeechHit:
push hl
ld a, 1
ldh [hBattleTurn], a
callfar BattleCheckTypeMatchup
pop hl
; 60% chance to discourage this move if not very effective.
ld a, [wTypeMatchup]
cp EFFECTIVE
jr c, .discourage
; 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
.discourage
call Random
cp 39 percent + 1
ret c
inc [hl]
ret
AI_Smart_LockOn:
ld a, [wPlayerSubStatus5]
bit SUBSTATUS_LOCK_ON, a
jr nz, .player_locked_on
push hl
call AICheckEnemyQuarterHP
jr nc, .discourage
call AICheckEnemyHalfHP
jr c, .skip_speed_check
call AICompareSpeed
jr nc, .discourage
.skip_speed_check
ld a, [wPlayerEvaLevel]
cp BASE_STAT_LEVEL + 3
jr nc, .maybe_encourage
cp BASE_STAT_LEVEL + 1
jr nc, .do_nothing
ld a, [wEnemyAccLevel]
cp BASE_STAT_LEVEL - 2
jr c, .maybe_encourage
cp BASE_STAT_LEVEL
jr c, .do_nothing
ld hl, wEnemyMonMoves
ld c, NUM_MOVES + 1
.checkmove
dec c
jr z, .discourage
ld a, [hli]
and a
jr z, .discourage
call AIGetEnemyMove
ld a, [wEnemyMoveStruct + MOVE_ACC]
cp 71 percent - 1
jr nc, .checkmove
ld a, 1
ldh [hBattleTurn], a
push hl
push bc
farcall BattleCheckTypeMatchup
ld a, [wTypeMatchup]
cp EFFECTIVE
pop bc
pop hl
jr c, .checkmove
.do_nothing
pop hl
ret
.discourage
pop hl
inc [hl]
ret
.maybe_encourage
pop hl
call AI_50_50
ret c
dec [hl]
dec [hl]
ret
.player_locked_on
push hl
ld hl, wEnemyAIMoveScores - 1
ld de, wEnemyMonMoves
ld c, NUM_MOVES + 1
.checkmove2
inc hl
dec c
jr z, .dismiss
ld a, [de]
and a
jr z, .dismiss
inc de
call AIGetEnemyMove
ld a, [wEnemyMoveStruct + MOVE_ACC]
cp 71 percent - 1
jr nc, .checkmove2
dec [hl]
dec [hl]
jr .checkmove2
.dismiss
pop hl
jp AIDiscourageMove
AI_Smart_Selfdestruct:
; Selfdestruct, Explosion
; Unless this is the enemy's last Pokemon...
push hl
farcall FindAliveEnemyMons
pop hl
jr nc, .notlastmon
; ...greatly discourage this move unless this is the player's last Pokemon too.
push hl
call AICheckLastPlayerMon
pop hl
jr nz, .discourage
.notlastmon
; Greatly discourage this move if enemy's HP is above 50%.
call AICheckEnemyHalfHP
jr c, .discourage
; 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 8 percent
ret c
.discourage
inc [hl]
inc [hl]
inc [hl]
ret
AI_Smart_DreamEater:
; 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
AI_Smart_EvasionUp:
; Dismiss this move if enemy's evasion can't raise anymore.
ld a, [wEnemyEvaLevel]
cp MAX_STAT_LEVEL
jp nc, AIDiscourageMove
; If enemy's HP is full...
call AICheckEnemyMaxHP
jr nc, .hp_mismatch_1
; ...greatly encourage this move if player is badly poisoned.
ld a, [wPlayerSubStatus5]
bit SUBSTATUS_TOXIC, a
jr nz, .greatly_encourage
; ...70% chance to greatly encourage this move if player is not badly poisoned.
call Random
cp 70 percent
jr nc, .not_encouraged
.greatly_encourage
dec [hl]
dec [hl]
ret
.hp_mismatch_1
; Greatly discourage this move if enemy's HP is below 25%.
call AICheckEnemyQuarterHP
jr nc, .hp_mismatch_2
; If enemy's HP is above 25% but not full, 4% chance to greatly encourage this move.
call Random
cp 4 percent
jr c, .greatly_encourage
; If enemy's HP is between 25% and 50%,...
call AICheckEnemyHalfHP
jr nc, .hp_mismatch_3
; If enemy's HP is above 50% but not full, 20% chance to greatly encourage this move.
call AI_80_20
jr c, .greatly_encourage
jr .not_encouraged
.hp_mismatch_3
; ...50% chance to greatly discourage this move.
call AI_50_50
jr c, .not_encouraged
.hp_mismatch_2
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.
.not_encouraged
ld a, [wPlayerSubStatus5]
bit SUBSTATUS_TOXIC, a
jr nz, .maybe_greatly_encourage
ld a, [wPlayerSubStatus4]
bit SUBSTATUS_LEECH_SEED, a
jr nz, .maybe_encourage
; Discourage this move if enemy's evasion level is higher than player's accuracy level.
ld a, [wEnemyEvaLevel]
ld b, a
ld a, [wPlayerAccLevel]
cp b
jr c, .discourage
; Greatly encourage this move if the player is in the middle of Fury Cutter or Rollout.
ld a, [wPlayerFuryCutterCount]
and a
jr nz, .greatly_encourage
ld a, [wPlayerSubStatus1]
bit SUBSTATUS_ROLLOUT, a
jr nz, .greatly_encourage
.discourage
inc [hl]
ret
; Player is badly poisoned.
; 70% chance to greatly encourage this move.
; This would counter any previous discouragement.
.maybe_greatly_encourage
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.
.maybe_encourage
call AI_50_50
ret c
dec [hl]
ret
AI_Smart_AlwaysHit:
; 80% chance to greatly encourage this move if either...
; ...enemy's accuracy level has been lowered three or more stages
ld a, [wEnemyAccLevel]
cp BASE_STAT_LEVEL - 2
jr c, .encourage
; ...or player's evasion level has been raised three or more stages.
ld a, [wPlayerEvaLevel]
cp BASE_STAT_LEVEL + 3
ret c
.encourage
call AI_80_20
ret c
dec [hl]
dec [hl]
ret
AI_Smart_MirrorMove:
; If the player did not use any move last turn...
ld a, [wLastPlayerCounterMove]
and a
jr nz, .usedmove
; ...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...
.usedmove
push hl
ld hl, UsefulMoves
call AI_CheckMoveInList
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
AI_Smart_AccuracyDown:
; If player's HP is full...
call AICheckPlayerMaxHP
jr nc, .hp_mismatch_1
; ...and enemy's HP is above 50%...
call AICheckEnemyHalfHP
jr nc, .hp_mismatch_1
; ...greatly encourage this move if player is badly poisoned.
ld a, [wPlayerSubStatus5]
bit SUBSTATUS_TOXIC, a
jr nz, .greatly_encourage
; ...70% chance to greatly encourage this move if player is not badly poisoned.
call Random
cp 70 percent
jr nc, .not_encouraged
.greatly_encourage
dec [hl]
dec [hl]
ret
.hp_mismatch_1
; Greatly discourage this move if player's HP is below 25%.
call AICheckPlayerQuarterHP
jr nc, .hp_mismatch_2
; If player's HP is above 25% but not full, 4% chance to greatly encourage this move.
call Random
cp 4 percent
jr c, .greatly_encourage
; If player's HP is between 25% and 50%,...
call AICheckPlayerHalfHP
jr nc, .hp_mismatch_3
; If player's HP is above 50% but not full, 20% chance to greatly encourage this move.
call AI_80_20
jr c, .greatly_encourage
jr .not_encouraged
; ...50% chance to greatly discourage this move.
.hp_mismatch_3
call AI_50_50
jr c, .not_encouraged
.hp_mismatch_2
inc [hl]
inc [hl]
; We only end up here if the move has not been already encouraged.
.not_encouraged
ld a, [wPlayerSubStatus5]
bit SUBSTATUS_TOXIC, a
jr nz, .maybe_greatly_encourage
ld a, [wPlayerSubStatus4]
bit SUBSTATUS_LEECH_SEED, a
jr nz, .encourage
; Discourage this move if enemy's evasion level is higher than player's accuracy level.
ld a, [wEnemyEvaLevel]
ld b, a
ld a, [wPlayerAccLevel]
cp b
jr c, .discourage
; Greatly encourage this move if the player is in the middle of Fury Cutter or Rollout.
ld a, [wPlayerFuryCutterCount]
and a
jr nz, .greatly_encourage
ld a, [wPlayerSubStatus1]
bit SUBSTATUS_ROLLOUT, a
jr nz, .greatly_encourage
.discourage
inc [hl]
ret
; Player is badly poisoned.
; 70% chance to greatly encourage this move.
; This would counter any previous discouragement.
.maybe_greatly_encourage
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.
.encourage
call AI_50_50
ret c
dec [hl]
ret
AI_Smart_ResetStats:
; 85% chance to encourage this move if any of enemy's stat levels is lower than -2.
push hl
ld hl, wEnemyAtkLevel
ld c, NUM_LEVEL_STATS
.enemystatsloop
dec c
jr z, .enemystatsdone
ld a, [hli]
cp BASE_STAT_LEVEL - 2
jr c, .encourage
jr .enemystatsloop
; 85% chance to encourage this move if any of player's stat levels is higher than +2.
.enemystatsdone
ld hl, wPlayerAtkLevel
ld c, NUM_LEVEL_STATS
.playerstatsloop
dec c
jr z, .discourage
ld a, [hli]
cp BASE_STAT_LEVEL + 3
jr c, .playerstatsloop
.encourage
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.
.discourage
pop hl
inc [hl]
ret
AI_Smart_Bide:
; 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
AI_Smart_ForceSwitch:
; 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 BASE_AI_SWITCH_SCORE
pop hl
ret c
inc [hl]
ret
AI_Smart_Heal:
AI_Smart_MorningSun:
AI_Smart_Synthesis:
AI_Smart_Moonlight:
; 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, .encourage
call AICheckEnemyHalfHP
ret nc
inc [hl]
ret
.encourage
call Random
cp 10 percent
ret c
dec [hl]
dec [hl]
ret
AI_Smart_Toxic:
AI_Smart_LeechSeed:
; Discourage this move if player's HP is below 50%.
call AICheckPlayerHalfHP
ret c
inc [hl]
ret
AI_Smart_LightScreen:
AI_Smart_Reflect:
; 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
AI_Smart_Ohko:
; 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, [wBattleMonLevel]
ld b, a
ld a, [wEnemyMonLevel]
cp b
jp c, AIDiscourageMove
call AICheckPlayerHalfHP
ret c
inc [hl]
ret
AI_Smart_TrapTarget:
; Bind, Wrap, Fire Spin, Clamp
; 50% chance to discourage this move if the player is already trapped.
ld a, [wPlayerWrapCount]
and a
jr nz, .discourage
; 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, [wPlayerSubStatus5]
bit SUBSTATUS_TOXIC, a
jr nz, .encourage
ld a, [wPlayerSubStatus1]
and 1 << SUBSTATUS_IN_LOVE | 1 << SUBSTATUS_ROLLOUT | 1 << SUBSTATUS_IDENTIFIED | 1 << SUBSTATUS_NIGHTMARE
jr nz, .encourage
; Else, 50% chance to greatly encourage this move if it's the player's Pokemon first turn.
ld a, [wPlayerTurnsTaken]
and a
jr z, .encourage
; 50% chance to discourage this move otherwise.
.discourage
call AI_50_50
ret c
inc [hl]
ret
.encourage
call AICheckEnemyQuarterHP
ret nc
call AI_50_50
ret c
dec [hl]
dec [hl]
ret
AI_Smart_RazorWind:
AI_Smart_Unused2B:
ld a, [wEnemySubStatus1]
bit SUBSTATUS_PERISH, a
jr z, .no_perish_count
ld a, [wEnemyPerishCount]
cp 3
jr c, .discourage
.no_perish_count
push hl
ld hl, wPlayerUsedMoves
ld c, NUM_MOVES
.checkmove
ld a, [hli]
and a
jr z, .movesdone
call AIGetEnemyMove
ld a, [wEnemyMoveStruct + MOVE_EFFECT]
cp EFFECT_PROTECT
jr z, .dismiss
dec c
jr nz, .checkmove
.movesdone
pop hl
ld a, [wEnemySubStatus3]
bit SUBSTATUS_CONFUSED, a
jr nz, .maybe_discourage
call AICheckEnemyHalfHP
ret c
.maybe_discourage
call Random
cp 79 percent - 1
ret c
.discourage
inc [hl]
ret
.dismiss
pop hl
ld a, [hl]
add 6
ld [hl], a
ret
AI_Smart_Confuse:
; 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, .skipdiscourage
inc [hl]
.skipdiscourage
; Discourage again if player's HP is below 25%.
call AICheckPlayerQuarterHP
ret c
inc [hl]
ret
AI_Smart_SpDefenseUp2:
; Discourage this move if enemy's HP is lower than 50%.
call AICheckEnemyHalfHP
jr nc, .discourage
; Discourage this move if enemy's special defense level is higher than +3.
ld a, [wEnemySDefLevel]
cp BASE_STAT_LEVEL + 4
jr nc, .discourage
; 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 BASE_STAT_LEVEL + 2
ret nc
ld a, [wBattleMonType1]
cp SPECIAL
jr nc, .encourage
ld a, [wBattleMonType2]
cp SPECIAL
ret c
.encourage
call AI_80_20
ret c
dec [hl]
dec [hl]
ret
.discourage
inc [hl]
ret
AI_Smart_Fly:
; Fly, Dig, Dive, Bounce
; Greatly encourage this move if the player is
; flying or underground, and slower than the enemy.
ld a, [wPlayerSubStatus3]
and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
jr nz, .player_hidden
ld a, [wPlayerSubStatus4]
and 1 << SUBSTATUS_UNDERWATER
ret z
.player_hidden
call AICompareSpeed
ret nc
dec [hl]
dec [hl]
dec [hl]
ret
AI_Smart_SuperFang:
; Discourage this move if player's HP is below 25%.
call AICheckPlayerQuarterHP
ret c
inc [hl]
ret
AI_Smart_Paralyze:
; 50% chance to discourage this move if player's HP is below 25%.
call AICheckPlayerQuarterHP
jr nc, .discourage
; 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
.discourage
call AI_50_50
ret c
inc [hl]
ret
AI_Smart_SpeedDownHit:
; 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]
push hl
call GetMoveIDFromIndex
ld a, h
if HIGH(ICY_WIND)
cp HIGH(ICY_WIND)
else
and a
endc
ld a, l
pop hl
ret nz
cp LOW(ICY_WIND)
ret nz
call AICheckEnemyQuarterHP
ret nc
ld a, [wPlayerTurnsTaken]
and a
ret nz
call AICompareSpeed
ret c
call Random
cp 12 percent
ret c
dec [hl]
dec [hl]
ret
AI_Smart_Substitute:
; Dismiss this move if enemy's HP is below 50%.
call AICheckEnemyHalfHP
ret c
jp AIDiscourageMove
AI_Smart_HyperBeam:
call AICheckEnemyHalfHP
jr c, .discourage
; 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
.discourage
; 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
AI_Smart_Rage:
ld a, [wEnemySubStatus4]
bit SUBSTATUS_RAGE, a
jr z, .notbuilding
; If enemy's Rage is building, 50% chance to encourage this move.
call AI_50_50
jr c, .skipencourage
dec [hl]
; Encourage this move based on Rage's counter.
.skipencourage
ld a, [wEnemyRageCounter]
cp 2
ret c
dec [hl]
ld a, [wEnemyRageCounter]
cp 3
ret c
dec [hl]
ret
.notbuilding
; If enemy's Rage is not building, discourage this move if enemy's HP is below 50%.
call AICheckEnemyHalfHP
jr nc, .discourage
; 20% chance to encourage this move otherwise.
call AI_80_20
ret nc
dec [hl]
ret
.discourage
inc [hl]
ret
AI_Smart_Mimic:
; Discourage this move if the player did not use any move last turn.
ld a, [wLastPlayerCounterMove]
and a
jr z, .dismiss
call AICheckEnemyHalfHP
jr nc, .discourage
push hl
ld a, [wLastPlayerCounterMove]
call AIGetEnemyMove
ld a, 1
ldh [hBattleTurn], a
callfar BattleCheckTypeMatchup
ld a, [wTypeMatchup]
cp EFFECTIVE
pop hl
jr c, .discourage
jr z, .skip_encourage
call AI_50_50
jr c, .skip_encourage
dec [hl]
.skip_encourage
ld a, [wLastPlayerCounterMove]
push hl
ld hl, UsefulMoves
call AI_CheckMoveInList
pop hl
ret nc
call AI_50_50
ret c
dec [hl]
ret
.dismiss
; Dismiss this move if the enemy is faster than the player.
call AICompareSpeed
jp c, AIDiscourageMove
.discourage
inc [hl]
ret
AI_Smart_Counter:
push hl
ld hl, wPlayerUsedMoves
ld c, NUM_MOVES
ld b, 0
.playermoveloop
ld a, [hli]
and a
jr z, .skipmove
call AIGetEnemyMove
ld a, [wEnemyMoveStruct + MOVE_POWER]
and a
jr z, .skipmove
ld a, [wEnemyMoveStruct + MOVE_TYPE]
cp SPECIAL
jr nc, .skipmove
inc b
.skipmove
dec c
jr nz, .playermoveloop
pop hl
ld a, b
and a
jr z, .discourage
cp 3
jr nc, .encourage
ld a, [wLastPlayerCounterMove]
and a
jr z, .done
call AIGetEnemyMove
ld a, [wEnemyMoveStruct + MOVE_POWER]
and a
jr z, .done
ld a, [wEnemyMoveStruct + MOVE_TYPE]
cp SPECIAL
jr nc, .done
.encourage
call Random
cp 39 percent + 1
jr c, .done
dec [hl]
.done
ret
.discourage
inc [hl]
ret
AI_Smart_Encore:
call AICompareSpeed
jr nc, .discourage
ld a, [wLastPlayerMove]
and a
jp z, AIDiscourageMove
call AIGetEnemyMove
ld a, [wEnemyMoveStruct + MOVE_POWER]
and a
jr z, .weakmove
push hl
ld a, [wEnemyMoveStruct + MOVE_TYPE]
ld hl, wEnemyMonType1
predef CheckTypeMatchup
pop hl
ld a, [wTypeMatchup]
cp EFFECTIVE
jr nc, .weakmove
and a
ret nz
jr .encourage
.weakmove
push hl
ld a, [wLastPlayerCounterMove]
ld hl, EncoreMoves
call AI_CheckMoveInList
pop hl
jr nc, .discourage
.encourage
call Random
cp 28 percent - 1
ret c
dec [hl]
dec [hl]
ret
.discourage
inc [hl]
inc [hl]
inc [hl]
ret
INCLUDE "data/battle/ai/encore_moves.asm"
AI_Smart_PainSplit:
; Discourage this move if [enemy's current HP * 2 > player's current HP].
push hl
ld hl, wEnemyMonHP
ld b, [hl]
inc hl
ld c, [hl]
sla c
rl b
ld hl, wBattleMonHP + 1
ld a, [hld]
cp c
ld a, [hl]
sbc b
pop hl
ret nc
inc [hl]
ret
AI_Smart_Snore:
AI_Smart_SleepTalk:
; Greatly encourage this move if enemy is fast asleep.
; Greatly discourage this move otherwise.
ld a, [wEnemyMonStatus]
and SLP_MASK
cp 1
jr z, .discourage
dec [hl]
dec [hl]
dec [hl]
ret
.discourage
inc [hl]
inc [hl]
inc [hl]
ret
AI_Smart_DefrostOpponent:
; Greatly encourage this move if enemy is frozen.
; No move has EFFECT_DEFROST_OPPONENT, so this layer is unused.
ld a, [wEnemyMonStatus]
and 1 << FRZ
ret z
dec [hl]
dec [hl]
dec [hl]
ret
AI_Smart_Spite:
ld a, [wLastPlayerCounterMove]
and a
jr nz, .usedmove
call AICompareSpeed
jp c, AIDiscourageMove
call AI_50_50
ret c
inc [hl]
ret
.usedmove
push hl
ld b, a
ld c, NUM_MOVES
ld hl, wBattleMonMoves
ld de, wBattleMonPP
.moveloop
ld a, [hli]
cp b
jr z, .foundmove
inc de
dec c
jr nz, .moveloop
pop hl
ret
.foundmove
pop hl
ld a, [de]
cp 6
jr c, .encourage
cp 15
jr nc, .discourage
call Random
cp 39 percent + 1
ret nc
.discourage
inc [hl]
ret
.encourage
call Random
cp 39 percent + 1
ret c
dec [hl]
dec [hl]
ret
.dismiss ; unreferenced
jp AIDiscourageMove
AI_Smart_DestinyBond:
AI_Smart_Reversal:
AI_Smart_SkullBash:
; Discourage this move if enemy's HP is above 25%.
call AICheckEnemyQuarterHP
ret nc
inc [hl]
ret
AI_Smart_HealBell:
; 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, [wOTPartyCount]
ld b, a
ld c, 0
ld hl, wOTPartyMon1HP
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, [wEnemyMonStatus]
and a
jr z, .ok
dec [hl]
.ok
and 1 << FRZ | SLP_MASK
ret z
call AI_50_50
ret c
dec [hl]
dec [hl]
ret
.no_status
ld a, [wEnemyMonStatus]
and a
ret nz
jp AIDiscourageMove
AI_Smart_PriorityHit:
call AICompareSpeed
ret c
; Dismiss this move if the player is flying, underwater, or underground.
ld a, [wPlayerSubStatus3]
and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
jp nz, AIDiscourageMove
ld a, [wPlayerSubStatus4]
and 1 << SUBSTATUS_UNDERWATER
jp nz, AIDiscourageMove
; Greatly encourage this move if it will KO the player.
ld a, 1
ldh [hBattleTurn], a
push hl
callfar EnemyAttackDamage
callfar BattleCommand_DamageCalc
callfar BattleCommand_Stab
pop hl
ld a, [wCurDamage + 1]
ld c, a
ld a, [wCurDamage]
ld b, a
ld a, [wBattleMonHP + 1]
cp c
ld a, [wBattleMonHP]
sbc b
ret nc
dec [hl]
dec [hl]
dec [hl]
ret
AI_Smart_Surf:
AI_Smart_Whirlpool:
; Greatly encourage this move if the player is underwater and the enemy is faster.
ld a, [wLastPlayerCounterMove]
cp DIVE
ret nz
ld a, [wPlayerSubStatus4]
bit SUBSTATUS_UNDERWATER, a
jr z, .could_dive
call AICompareSpeed
ret nc
dec [hl]
dec [hl]
ret
.could_dive
; Try to predict if the player will use Dive 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
AI_Smart_Thief:
; Don't use Thief unless it's the only move available.
ld a, [hl]
add $1e
ld [hl], a
ret
AI_Smart_Conversion2:
; BUG: "Smart" AI discourages Conversion2 after the first turn (see docs/bugs_and_glitches.md)
ld a, [wLastPlayerMove]
and a
jr nz, .discourage
push hl
ld l, a
ld a, MOVE_TYPE
call GetMoveAttribute
ld [wPlayerMoveStruct + MOVE_TYPE], a
xor a
ldh [hBattleTurn], a
callfar BattleCheckTypeMatchup
ld a, [wTypeMatchup]
cp EFFECTIVE
pop hl
jr c, .discourage
ret z
call AI_50_50
ret c
dec [hl]
ret
.discourage
call Random
cp 10 percent
ret c
inc [hl]
ret
AI_Smart_Disable:
call AICompareSpeed
jr nc, .discourage
push hl
ld a, [wLastPlayerCounterMove]
ld hl, UsefulMoves
call AI_CheckMoveInList
pop hl
jr nc, .notencourage
call Random
cp 39 percent + 1
ret c
dec [hl]
ret
.notencourage
ld a, [wEnemyMoveStruct + MOVE_POWER]
and a
ret nz
.discourage
call Random
cp 8 percent
ret c
inc [hl]
ret
AI_Smart_MeanLook:
call AICheckEnemyHalfHP
jr nc, .discourage
push hl
call AICheckLastPlayerMon
pop hl
jp z, AIDiscourageMove
; 80% chance to greatly encourage this move if the enemy is badly poisoned.
; BUG: "Smart" AI encourages Mean Look if its own Pokémon is badly poisoned (see docs/bugs_and_glitches.md)
ld a, [wEnemySubStatus5]
bit SUBSTATUS_TOXIC, a
jr nz, .encourage
; 80% chance to greatly encourage this move if the player is either
; in love, identified, stuck in Rollout, or has a Nightmare.
ld a, [wPlayerSubStatus1]
and 1 << SUBSTATUS_IN_LOVE | 1 << SUBSTATUS_ROLLOUT | 1 << SUBSTATUS_IDENTIFIED | 1 << SUBSTATUS_NIGHTMARE
jr nz, .encourage
; Otherwise, discourage this move unless the player only has not very effective moves against the enemy.
push hl
callfar CheckPlayerMoveTypeMatchups
ld a, [wEnemyAISwitchScore]
cp BASE_AI_SWITCH_SCORE + 1 ; not very effective
pop hl
ret nc
.discourage
inc [hl]
ret
.encourage
call AI_80_20
ret c
dec [hl]
dec [hl]
dec [hl]
ret
AICheckLastPlayerMon:
ld a, [wPartyCount]
ld b, a
ld c, 0
ld hl, wPartyMon1HP
ld de, PARTYMON_STRUCT_LENGTH
.loop
ld a, [wCurBattleMon]
cp c
jr z, .skip
ld a, [hli]
or [hl]
ret nz
dec hl
.skip
add hl, de
inc c
dec b
jr nz, .loop
ret
AI_Smart_Nightmare:
; 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
AI_Smart_FlameWheel:
; Use this move if the enemy is frozen.
ld a, [wEnemyMonStatus]
bit FRZ, a
ret z
rept 5
dec [hl]
endr
ret
AI_Smart_Curse:
ld a, [wEnemyMonType1]
cp GHOST
jr z, .ghost_curse
ld a, [wEnemyMonType2]
cp GHOST
jr z, .ghost_curse
call AICheckEnemyHalfHP
jr nc, .encourage
ld a, [wEnemyAtkLevel]
cp BASE_STAT_LEVEL + 4
jr nc, .encourage
cp BASE_STAT_LEVEL + 2
ret nc
ld a, [wBattleMonType1]
cp GHOST
jr z, .greatly_encourage
cp SPECIAL
ret nc
ld a, [wBattleMonType2]
cp SPECIAL
ret nc
call AI_80_20
ret c
dec [hl]
dec [hl]
ret
.approve
inc [hl]
inc [hl]
.greatly_encourage
inc [hl]
.encourage
inc [hl]
ret
.ghost_curse
ld a, [wPlayerSubStatus1]
bit SUBSTATUS_CURSE, a
jp nz, AIDiscourageMove
push hl
farcall FindAliveEnemyMons
pop hl
jr nc, .notlastmon
push hl
call AICheckLastPlayerMon
pop hl
jr nz, .approve
jr .ghost_continue
.notlastmon
push hl
call AICheckLastPlayerMon
pop hl
jr z, .maybe_greatly_encourage
.ghost_continue
call AICheckEnemyQuarterHP
jp nc, .approve
call AICheckEnemyHalfHP
jr nc, .greatly_encourage
call AICheckEnemyMaxHP
ret nc
ld a, [wPlayerTurnsTaken]
and a
ret nz
.maybe_greatly_encourage
call AI_50_50
ret c
dec [hl]
dec [hl]
ret
AI_Smart_Protect:
; Greatly discourage this move if the enemy already used Protect.
ld a, [wEnemyProtectCount]
and a
jr nz, .greatly_discourage
; Discourage this move if the player is locked on.
ld a, [wPlayerSubStatus5]
bit SUBSTATUS_LOCK_ON, a
jr nz, .discourage
; Encourage this move if the player's Fury Cutter is boosted enough.
ld a, [wPlayerFuryCutterCount]
cp 3
jr nc, .encourage
; Encourage this move if the player has charged a two-turn move.
ld a, [wPlayerSubStatus3]
bit SUBSTATUS_CHARGED, a
jr nz, .encourage
; Encourage this move if the player is affected by Toxic, Leech Seed, or Curse.
ld a, [wPlayerSubStatus5]
bit SUBSTATUS_TOXIC, a
jr nz, .encourage
ld a, [wPlayerSubStatus4]
bit SUBSTATUS_LEECH_SEED, a
jr nz, .encourage
ld a, [wPlayerSubStatus1]
bit SUBSTATUS_CURSE, a
jr nz, .encourage
; Discourage this move if the player's Rollout count is not boosted enough.
bit SUBSTATUS_ROLLOUT, a
jr z, .discourage
ld a, [wPlayerRolloutCount]
cp 3
jr c, .discourage
; 80% chance to encourage this move otherwise.
.encourage
call AI_80_20
ret c
dec [hl]
ret
.greatly_discourage
inc [hl]
.discourage
call Random
cp 8 percent
ret c
inc [hl]
inc [hl]
ret
AI_Smart_Foresight:
; 60% chance to encourage this move if the enemy's accuracy is sharply lowered.
ld a, [wEnemyAccLevel]
cp BASE_STAT_LEVEL - 2
jr c, .encourage
; 60% chance to encourage this move if the player's evasion is sharply raised.
ld a, [wPlayerEvaLevel]
cp BASE_STAT_LEVEL + 3
jr nc, .encourage
; 60% chance to encourage this move if the player is a Ghost type.
ld a, [wBattleMonType1]
cp GHOST
jr z, .encourage
ld a, [wBattleMonType2]
cp GHOST
jr z, .encourage
; 92% chance to discourage this move otherwise.
call Random
cp 8 percent
ret c
inc [hl]
ret
.encourage
call Random
cp 39 percent + 1
ret c
dec [hl]
dec [hl]
ret
AI_Smart_PerishSong:
push hl
callfar FindAliveEnemyMons
pop hl
jr c, .no
ld a, [wPlayerSubStatus5]
bit SUBSTATUS_CANT_RUN, a
jr nz, .yes
push hl
callfar CheckPlayerMoveTypeMatchups
ld a, [wEnemyAISwitchScore]
cp BASE_AI_SWITCH_SCORE
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
AI_Smart_Sandstorm:
; Greatly discourage this move if the player is immune to Sandstorm damage.
ld a, [wBattleMonType1]
push hl
ld hl, .SandstormImmuneTypes
ld de, 1
call IsInArray
pop hl
jr c, .greatly_discourage
ld a, [wBattleMonType2]
push hl
ld hl, .SandstormImmuneTypes
ld de, 1
call IsInArray
pop hl
jr c, .greatly_discourage
; Discourage this move if player's HP is below 50%.
call AICheckPlayerHalfHP
jr nc, .discourage
; 50% chance to encourage this move otherwise.
call AI_50_50
ret c
dec [hl]
ret
.greatly_discourage
inc [hl]
.discourage
inc [hl]
ret
.SandstormImmuneTypes:
db ROCK
db GROUND
db STEEL
db -1 ; end
AI_Smart_Endure:
; Greatly discourage this move if the enemy already used Protect.
ld a, [wEnemyProtectCount]
and a
jr nz, .greatly_discourage
; Greatly discourage this move if the enemy's HP is full.
call AICheckEnemyMaxHP
jr c, .greatly_discourage
; Discourage this move if the enemy's HP is at least 25%.
call AICheckEnemyQuarterHP
jr c, .discourage
; If the enemy has Reversal...
ld b, EFFECT_REVERSAL
call AIHasMoveEffect
jr nc, .no_reversal
; ...80% chance to greatly encourage this move.
call AI_80_20
ret c
dec [hl]
dec [hl]
dec [hl]
ret
.no_reversal
; If the enemy is not locked on, do nothing.
ld a, [wEnemySubStatus5]
bit SUBSTATUS_LOCK_ON, a
ret z
; 50% chance to greatly encourage this move.
call AI_50_50
ret c
dec [hl]
dec [hl]
ret
.greatly_discourage
inc [hl]
.discourage
inc [hl]
ret
AI_Smart_FuryCutter:
; Encourage this move based on Fury Cutter's count.
ld a, [wEnemyFuryCutterCount]
and a
jr z, AI_Smart_Rollout
dec [hl]
cp 2
jr c, AI_Smart_Rollout
dec [hl]
dec [hl]
cp 3
jr c, AI_Smart_Rollout
dec [hl]
dec [hl]
dec [hl]
; fallthrough
AI_Smart_Rollout:
; Rollout, Fury Cutter
; 80% chance to discourage this move if the enemy is in love, confused, or paralyzed.
ld a, [wEnemySubStatus1]
bit SUBSTATUS_IN_LOVE, a
jr nz, .maybe_discourage
ld a, [wEnemySubStatus3]
bit SUBSTATUS_CONFUSED, a
jr nz, .maybe_discourage
ld a, [wEnemyMonStatus]
bit PAR, a
jr nz, .maybe_discourage
; 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, .maybe_discourage
ld a, [wEnemyAccLevel]
cp BASE_STAT_LEVEL
jr c, .maybe_discourage
ld a, [wPlayerEvaLevel]
cp BASE_STAT_LEVEL + 1
jr nc, .maybe_discourage
; 80% chance to greatly encourage this move otherwise.
call Random
cp 79 percent - 1
ret nc
dec [hl]
dec [hl]
ret
.maybe_discourage
call AI_80_20
ret c
inc [hl]
ret
AI_Smart_Swagger:
AI_Smart_Attract:
; 80% chance to encourage this move during the first turn of player's Pokemon.
; 80% chance to discourage this move otherwise.
ld a, [wPlayerTurnsTaken]
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
AI_Smart_Safeguard:
; 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
AI_Smart_Magnitude:
AI_Smart_Earthquake:
; Greatly encourage this move if the player is underground and the enemy is faster.
ld a, [wLastPlayerCounterMove]
push hl
call GetMoveIndexFromID
ld a, h
if HIGH(DIG)
cp HIGH(DIG)
else
and a
endc
ld a, l
pop hl
ret nz
cp LOW(DIG)
ret nz
ld a, [wPlayerSubStatus3]
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
AI_Smart_BatonPass:
; 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 BASE_AI_SWITCH_SCORE
pop hl
ret c
inc [hl]
ret
AI_Smart_Pursuit:
; 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, .encourage
call AI_80_20
ret c
inc [hl]
ret
.encourage
call AI_50_50
ret c
dec [hl]
dec [hl]
ret
AI_Smart_RapidSpin:
; 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, .encourage
ld a, [wEnemySubStatus4]
bit SUBSTATUS_LEECH_SEED, a
jr nz, .encourage
ld a, [wEnemyScreens]
bit SCREENS_SPIKES, a
ret z
.encourage
call AI_80_20
ret c
dec [hl]
dec [hl]
ret
AI_Smart_HiddenPower:
push hl
ld a, 1
ldh [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, [wTypeMatchup]
cp EFFECTIVE
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, [wTypeMatchup]
cp EFFECTIVE + 1
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
AI_Smart_RainDance:
; Greatly discourage this move if it would favour the player type-wise.
; Particularly, if the player is a Water-type.
ld a, [wBattleMonType1]
cp WATER
jr z, AIBadWeatherType
cp FIRE
jr z, AIGoodWeatherType
ld a, [wBattleMonType2]
cp WATER
jr z, AIBadWeatherType
cp FIRE
jr z, AIGoodWeatherType
push hl
ld hl, RainDanceMoves
jr AI_Smart_WeatherMove
INCLUDE "data/battle/ai/rain_dance_moves.asm"
AI_Smart_SunnyDay:
; Greatly discourage this move if it would favour the player type-wise.
; Particularly, if the player is a Fire-type.
ld a, [wBattleMonType1]
cp FIRE
jr z, AIBadWeatherType
cp WATER
jr z, AIGoodWeatherType
ld a, [wBattleMonType2]
cp FIRE
jr z, AIBadWeatherType
cp WATER
jr z, AIGoodWeatherType
push hl
ld hl, SunnyDayMoves
; fallthrough
AI_Smart_WeatherMove:
; 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
AIBadWeatherType:
inc [hl]
inc [hl]
inc [hl]
ret
AIGoodWeatherType:
; 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, [wPlayerTurnsTaken]
and a
jr z, .good
; Or it's the first turn of the enemy's Pokemon.
ld a, [wEnemyTurnsTaken]
and a
ret nz
.good
dec [hl]
dec [hl]
ret
INCLUDE "data/battle/ai/sunny_day_moves.asm"
AI_Smart_BellyDrum:
; 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, [wEnemyAtkLevel]
cp BASE_STAT_LEVEL + 3
jr nc, .discourage
call AICheckEnemyMaxHP
ret c
inc [hl]
call AICheckEnemyHalfHP
ret c
.discourage
ld a, [hl]
add 5
ld [hl], a
ret
AI_Smart_PsychUp:
push hl
ld hl, wEnemyAtkLevel
ld b, NUM_LEVEL_STATS
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.
.enemy_loop
ld a, [hli]
sub BASE_STAT_LEVEL
add c
ld c, a
dec b
jr nz, .enemy_loop
; 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, wPlayerAtkLevel
ld b, NUM_LEVEL_STATS
ld d, 100
.player_loop
ld a, [hli]
sub BASE_STAT_LEVEL
add d
ld d, a
dec b
jr nz, .player_loop
; 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, .discourage
; Else, 80% chance to encourage this move unless player's accuracy level is lower than -1...
ld a, [wPlayerAccLevel]
cp BASE_STAT_LEVEL - 1
ret c
; ...or enemy's evasion level is higher than +0.
ld a, [wEnemyEvaLevel]
cp BASE_STAT_LEVEL + 1
ret nc
call AI_80_20
ret c
dec [hl]
ret
.discourage
inc [hl]
inc [hl]
ret
AI_Smart_MirrorCoat:
push hl
ld hl, wPlayerUsedMoves
ld c, NUM_MOVES
ld b, 0
.playermoveloop
ld a, [hli]
and a
jr z, .skipmove
call AIGetEnemyMove
ld a, [wEnemyMoveStruct + MOVE_POWER]
and a
jr z, .skipmove
ld a, [wEnemyMoveStruct + MOVE_TYPE]
cp SPECIAL
jr c, .skipmove
inc b
.skipmove
dec c
jr nz, .playermoveloop
pop hl
ld a, b
and a
jr z, .discourage
cp 3
jr nc, .encourage
ld a, [wLastPlayerCounterMove]
and a
jr z, .done
call AIGetEnemyMove
ld a, [wEnemyMoveStruct + MOVE_POWER]
and a
jr z, .done
ld a, [wEnemyMoveStruct + MOVE_TYPE]
cp SPECIAL
jr c, .done
.encourage
call Random
cp 39 percent + 1
jr c, .done
dec [hl]
.done
ret
.discourage
inc [hl]
ret
AI_Smart_Twister:
AI_Smart_Gust:
; Greatly encourage this move if the player is flying and the enemy is faster.
ld a, [wLastPlayerCounterMove]
push hl
call GetMoveIndexFromID
ld a, h
if HIGH(FLY)
cp HIGH(FLY)
else
and a
endc
ld a, l
pop hl
ret nz
cp LOW(FLY)
ret nz
ld a, [wPlayerSubStatus3]
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
AI_Smart_FutureSight:
; Greatly encourage this move if the player is
; flying, underwater, or underground, and slower than the enemy.
call AICompareSpeed
ret nc
ld a, [wPlayerSubStatus3]
and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
jr nz, .player_hidden
ld a, [wPlayerSubStatus4]
and 1 << SUBSTATUS_UNDERWATER
ret z
.player_hidden
dec [hl]
dec [hl]
ret
AI_Smart_Stomp:
; 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
AI_Smart_Solarbeam:
; 80% chance to encourage this move when it's sunny.
; 90% chance to discourage this move when it's raining.
ld a, [wBattleWeather]
cp WEATHER_SUN
jr z, .encourage
cp WEATHER_RAIN
ret nz
call Random
cp 10 percent
ret c
inc [hl]
inc [hl]
ret
.encourage
call AI_80_20
ret c
dec [hl]
dec [hl]
ret
AI_Smart_Thunder:
; 90% chance to discourage this move when it's sunny.
ld a, [wBattleWeather]
cp WEATHER_SUN
ret nz
call Random
cp 10 percent
ret c
inc [hl]
ret
AICompareSpeed:
; Return carry if enemy is faster than player.
push bc
ld a, [wEnemyMonSpeed + 1]
ld b, a
ld a, [wBattleMonSpeed + 1]
cp b
ld a, [wEnemyMonSpeed]
ld b, a
ld a, [wBattleMonSpeed]
sbc b
pop bc
ret
AICheckPlayerMaxHP:
push hl
push de
push bc
ld de, wBattleMonHP
ld hl, wBattleMonMaxHP
jr AICheckMaxHP
AICheckEnemyMaxHP:
push hl
push de
push bc
ld de, wEnemyMonHP
ld hl, wEnemyMonMaxHP
; fallthrough
AICheckMaxHP:
; Return carry if hp at de matches max hp at hl.
ld a, [de]
inc de
cp [hl]
jr nz, .not_max
inc hl
ld a, [de]
cp [hl]
jr nz, .not_max
pop bc
pop de
pop hl
scf
ret
.not_max
pop bc
pop de
pop hl
and a
ret
AICheckPlayerHalfHP:
push hl
ld hl, wBattleMonHP
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
AICheckEnemyHalfHP:
push hl
push de
push bc
ld hl, wEnemyMonHP
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
AICheckEnemyQuarterHP:
push hl
push de
push bc
ld hl, wEnemyMonHP
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
AICheckPlayerQuarterHP:
push hl
ld hl, wBattleMonHP
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
AIHasMoveEffect:
; Return carry if the enemy has move b.
push hl
ld hl, wEnemyMonMoves
ld c, NUM_MOVES
.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
AIHasMoveInArray:
; Return carry if the enemy has a move in array hl.
push de
push bc
push hl
ld b, NUM_MOVES
ld de, wEnemyMonMoves
.loop
ld a, [de]
inc de
and a
jr z, .next
call GetMoveIndexFromID
ld a, h
ld c, l
pop hl
push hl
push bc
push de
ld b, a
ld de, 2
call IsInWordArray
pop de
pop bc
jr c, .done
.next
dec b
jr nz, .loop
.done
pop hl
pop bc
pop de
ret
INCLUDE "data/battle/ai/useful_moves.asm"
AI_Opportunist:
; 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, .lowhp
; 50% chance to discourage stall moves if enemy's HP is between 25% and 50%.
call AI_50_50
ret c
.lowhp
ld hl, wEnemyAIMoveScores - 1
ld de, wEnemyMonMoves
ld c, NUM_MOVES + 1
.checkmove
inc hl
dec c
jr z, .done
ld a, [de]
inc de
and a
jr z, .done
push hl
push de
push bc
ld hl, StallMoves
call AI_CheckMoveInList
pop bc
pop de
pop hl
jr nc, .checkmove
inc [hl]
jr .checkmove
.done
ret
INCLUDE "data/battle/ai/stall_moves.asm"
AI_Aggressive:
; 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, wEnemyMonMoves
ld bc, 0
ld de, 0
.checkmove
inc b
ld a, b
cp NUM_MOVES + 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, [wCurDamage + 1]
cp e
ld a, [wCurDamage]
sbc d
jr c, .checkmove
ld a, [wCurDamage + 1]
ld e, a
ld a, [wCurDamage]
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
ret z
; Discourage moves that do less damage unless they're reckless too.
ld hl, wEnemyAIMoveScores - 1
ld de, wEnemyMonMoves
ld b, 0
.checkmove2
inc b
ld a, b
cp NUM_MOVES + 1
ret z
; 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
INCLUDE "data/battle/ai/reckless_moves.asm"
AIDamageCalc:
ld a, 1
ldh [hBattleTurn], a
ld a, [wEnemyMoveStruct + MOVE_EFFECT]
ld de, 1
ld hl, ConstantDamageEffects
call IsInArray
jr nc, .notconstant
callfar BattleCommand_ConstantDamage
ret
.notconstant
callfar EnemyAttackDamage
callfar BattleCommand_DamageCalc
callfar BattleCommand_Stab
ret
INCLUDE "data/battle/ai/constant_damage_effects.asm"
AI_Cautious:
; 90% chance to discourage moves with residual effects after the first turn.
ld a, [wEnemyTurnsTaken]
and a
ret z
ld hl, wEnemyAIMoveScores - 1
ld de, wEnemyMonMoves
ld c, NUM_MOVES + 1
.loop
inc hl
dec c
ret z
ld a, [de]
inc de
and a
ret z
push hl
push de
push bc
ld hl, ResidualMoves
call AI_CheckMoveInList
pop bc
pop de
pop hl
jr nc, .loop
call Random
cp 90 percent + 1
ret nc
inc [hl]
jr .loop
INCLUDE "data/battle/ai/residual_moves.asm"
AI_Status:
; Dismiss status moves that don't affect the player.
ld hl, wEnemyAIMoveScores - 1
ld de, wEnemyMonMoves
ld b, NUM_MOVES + 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, [wBattleMonType1]
cp POISON
jr z, .immune
ld a, [wBattleMonType2]
cp POISON
jr z, .immune
.typeimmunity
push hl
push bc
push de
ld a, 1
ldh [hBattleTurn], a
callfar BattleCheckTypeMatchup
pop de
pop bc
pop hl
ld a, [wTypeMatchup]
and a
jr nz, .checkmove
.immune
call AIDiscourageMove
jr .checkmove
AI_Risky:
; Use any move that will KO the target.
; Risky moves will often be an exception (see below).
ld hl, wEnemyAIMoveScores - 1
ld de, wEnemyMonMoves
ld c, NUM_MOVES + 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, RiskyEffects
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, [wCurDamage + 1]
ld e, a
ld a, [wCurDamage]
ld d, a
ld a, [wBattleMonHP + 1]
cp e
ld a, [wBattleMonHP]
sbc d
jr nc, .nextmove
pop hl
rept 5
dec [hl]
endr
push hl
.nextmove
pop hl
pop bc
pop de
jr .checkmove
INCLUDE "data/battle/ai/risky_effects.asm"
AI_None:
ret
AIDiscourageMove:
ld a, [hl]
add 10
ld [hl], a
ret
AIGetEnemyMove:
; Load attributes of move a into ram
push hl
push de
push bc
ld de, wEnemyMoveStruct
call GetMoveData
pop bc
pop de
pop hl
ret
AI_80_20:
call Random
cp 20 percent - 1
ret
AI_50_50:
call Random
cp 50 percent + 1
ret
AI_CheckMoveInList:
push hl
call GetMoveIndexFromID
ld b, h
ld c, l
pop hl
ld de, 2
jp IsInWordArray