mirror of
https://github.com/thornAvery/jep-hack.git
synced 2026-02-06 16:15:24 +13:00
First Commit
Upload literally everything from the pokecrystal16 expand-move-ID branch
This commit is contained in:
commit
2f8a41f833
4618 changed files with 480386 additions and 0 deletions
845
engine/battle/ai/items.asm
Normal file
845
engine/battle/ai/items.asm
Normal file
|
|
@ -0,0 +1,845 @@
|
|||
AI_SwitchOrTryItem:
|
||||
and a
|
||||
|
||||
ld a, [wBattleMode]
|
||||
dec a
|
||||
ret z
|
||||
|
||||
ld a, [wLinkMode]
|
||||
and a
|
||||
ret nz
|
||||
|
||||
farcall CheckEnemyLockedIn
|
||||
ret nz
|
||||
|
||||
ld a, [wPlayerSubStatus5]
|
||||
bit SUBSTATUS_CANT_RUN, a
|
||||
jr nz, DontSwitch
|
||||
|
||||
ld a, [wEnemyWrapCount]
|
||||
and a
|
||||
jr nz, DontSwitch
|
||||
|
||||
; always load the first trainer class in wTrainerClass for Battle Tower trainers
|
||||
ld hl, TrainerClassAttributes + TRNATTR_AI_ITEM_SWITCH
|
||||
ld a, [wInBattleTowerBattle]
|
||||
and a
|
||||
jr nz, .ok
|
||||
|
||||
ld a, [wTrainerClass]
|
||||
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:
|
||||
call AI_TryItem
|
||||
ret
|
||||
|
||||
SwitchOften:
|
||||
callfar CheckAbleToSwitch
|
||||
ld a, [wEnemySwitchMonParam]
|
||||
and $f0
|
||||
jp z, DontSwitch
|
||||
|
||||
cp $10
|
||||
jr nz, .not_10
|
||||
call Random
|
||||
cp 50 percent + 1
|
||||
jr c, .switch
|
||||
jp DontSwitch
|
||||
.not_10
|
||||
|
||||
cp $20
|
||||
jr nz, .not_20
|
||||
call Random
|
||||
cp 79 percent - 1
|
||||
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 mon to switch to
|
||||
ld [wEnemySwitchMonIndex], a
|
||||
jp AI_TrySwitch
|
||||
|
||||
SwitchRarely:
|
||||
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 79 percent - 1
|
||||
jp c, DontSwitch
|
||||
|
||||
.switch
|
||||
ld a, [wEnemySwitchMonParam]
|
||||
and $f
|
||||
inc a
|
||||
ld [wEnemySwitchMonIndex], a
|
||||
jp AI_TrySwitch
|
||||
|
||||
SwitchSometimes:
|
||||
callfar CheckAbleToSwitch
|
||||
ld a, [wEnemySwitchMonParam]
|
||||
and $f0
|
||||
jp z, DontSwitch
|
||||
|
||||
cp $10
|
||||
jr nz, .not_10
|
||||
call Random
|
||||
cp 20 percent - 1
|
||||
jr c, .switch
|
||||
jp DontSwitch
|
||||
.not_10
|
||||
|
||||
cp $20
|
||||
jr nz, .not_20
|
||||
call Random
|
||||
cp 50 percent + 1
|
||||
jr c, .switch
|
||||
jp DontSwitch
|
||||
.not_20
|
||||
|
||||
; $30
|
||||
call Random
|
||||
cp 20 percent - 1
|
||||
jp c, DontSwitch
|
||||
|
||||
.switch
|
||||
ld a, [wEnemySwitchMonParam]
|
||||
and $f
|
||||
inc a
|
||||
ld [wEnemySwitchMonIndex], a
|
||||
jp AI_TrySwitch
|
||||
|
||||
CheckSubstatusCantRun: ; unreferenced
|
||||
ld a, [wEnemySubStatus5]
|
||||
bit SUBSTATUS_CANT_RUN, a
|
||||
ret
|
||||
|
||||
AI_TryItem:
|
||||
; items are not allowed in the Battle Tower
|
||||
ld a, [wInBattleTowerBattle]
|
||||
and a
|
||||
ret nz
|
||||
|
||||
ld a, [wEnemyTrainerItem1]
|
||||
ld b, a
|
||||
ld a, [wEnemyTrainerItem2]
|
||||
or b
|
||||
ret z
|
||||
|
||||
call .IsHighestLevel
|
||||
ret nc
|
||||
|
||||
ld a, [wTrainerClass]
|
||||
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, wEnemySubStatus3
|
||||
res SUBSTATUS_BIDE, [hl]
|
||||
|
||||
xor a
|
||||
ld [wEnemyFuryCutterCount], a
|
||||
ld [wEnemyProtectCount], a
|
||||
ld [wEnemyRageCounter], a
|
||||
|
||||
ld hl, wEnemySubStatus4
|
||||
res SUBSTATUS_RAGE, [hl]
|
||||
|
||||
xor a
|
||||
ld [wLastEnemyCounterMove], a
|
||||
|
||||
scf
|
||||
ret
|
||||
|
||||
.IsHighestLevel:
|
||||
ld a, [wOTPartyCount]
|
||||
ld d, a
|
||||
ld e, 0
|
||||
ld hl, wOTPartyMon1Level
|
||||
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, [wCurOTMon]
|
||||
ld hl, wOTPartyMon1Level
|
||||
call AddNTimes
|
||||
ld a, [hl]
|
||||
cp e
|
||||
jr nc, .yes
|
||||
|
||||
.no ; unreferenced
|
||||
and a
|
||||
ret
|
||||
|
||||
.yes
|
||||
scf
|
||||
ret
|
||||
|
||||
AI_Items:
|
||||
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 -1 ; end
|
||||
|
||||
.FullHeal:
|
||||
call .Status
|
||||
jp c, .DontUse
|
||||
call EnemyUsedFullHeal
|
||||
jp .Use
|
||||
|
||||
.Status:
|
||||
ld a, [wEnemyMonStatus]
|
||||
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 20 percent - 1
|
||||
jp c, .Use
|
||||
jp .DontUse
|
||||
|
||||
.StatusCheckContext:
|
||||
ld a, [wEnemySubStatus5]
|
||||
bit SUBSTATUS_TOXIC, a
|
||||
jr z, .FailToxicCheck
|
||||
ld a, [wEnemyToxicCount]
|
||||
cp 4
|
||||
jr c, .FailToxicCheck
|
||||
call Random
|
||||
cp 50 percent + 1
|
||||
jp c, .Use
|
||||
.FailToxicCheck:
|
||||
ld a, [wEnemyMonStatus]
|
||||
and 1 << FRZ | SLP_MASK
|
||||
jp z, .DontUse
|
||||
jp .Use
|
||||
|
||||
.FullRestore:
|
||||
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
|
||||
|
||||
.MaxPotion:
|
||||
call .HealItem
|
||||
jp c, .DontUse
|
||||
call EnemyUsedMaxPotion
|
||||
jp .Use
|
||||
|
||||
.HealItem:
|
||||
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 50 percent + 1
|
||||
jp c, .UseHealItem
|
||||
jp .DontUse
|
||||
|
||||
.CheckQuarterHP:
|
||||
callfar AICheckEnemyQuarterHP
|
||||
jp c, .DontUse
|
||||
call Random
|
||||
cp 20 percent - 1
|
||||
jp c, .DontUse
|
||||
jr .UseHealItem
|
||||
|
||||
.CheckHalfOrQuarterHP:
|
||||
callfar AICheckEnemyHalfHP
|
||||
jp c, .DontUse
|
||||
callfar AICheckEnemyQuarterHP
|
||||
jp nc, .UseHealItem
|
||||
call Random
|
||||
cp 20 percent - 1
|
||||
jp nc, .DontUse
|
||||
|
||||
.UseHealItem:
|
||||
jp .Use
|
||||
|
||||
.HyperPotion:
|
||||
call .HealItem
|
||||
jp c, .DontUse
|
||||
ld b, 200
|
||||
call EnemyUsedHyperPotion
|
||||
jp .Use
|
||||
|
||||
.SuperPotion:
|
||||
call .HealItem
|
||||
jp c, .DontUse
|
||||
ld b, 50
|
||||
call EnemyUsedSuperPotion
|
||||
jp .Use
|
||||
|
||||
.Potion:
|
||||
call .HealItem
|
||||
jp c, .DontUse
|
||||
ld b, 20
|
||||
call EnemyUsedPotion
|
||||
jp .Use
|
||||
|
||||
; Everything up to "End unused" is unused
|
||||
|
||||
.UnusedHealItem: ; unreferenced
|
||||
; This has similar conditions to .HealItem
|
||||
callfar AICheckEnemyMaxHP
|
||||
jr c, .dont_use
|
||||
push bc
|
||||
ld de, wEnemyMonMaxHP + 1
|
||||
ld hl, wEnemyMonHP + 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 50 percent + 1
|
||||
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 39 percent + 1
|
||||
jp c, .Use
|
||||
jp .DontUse
|
||||
|
||||
; End unused
|
||||
|
||||
.XAccuracy:
|
||||
call .XItem
|
||||
jp c, .DontUse
|
||||
call EnemyUsedXAccuracy
|
||||
jp .Use
|
||||
|
||||
.GuardSpec:
|
||||
call .XItem
|
||||
jp c, .DontUse
|
||||
call EnemyUsedGuardSpec
|
||||
jp .Use
|
||||
|
||||
.DireHit:
|
||||
call .XItem
|
||||
jp c, .DontUse
|
||||
call EnemyUsedDireHit
|
||||
jp .Use
|
||||
|
||||
.XAttack:
|
||||
call .XItem
|
||||
jp c, .DontUse
|
||||
call EnemyUsedXAttack
|
||||
jp .Use
|
||||
|
||||
.XDefend:
|
||||
call .XItem
|
||||
jp c, .DontUse
|
||||
call EnemyUsedXDefend
|
||||
jp .Use
|
||||
|
||||
.XSpeed:
|
||||
call .XItem
|
||||
jp c, .DontUse
|
||||
call EnemyUsedXSpeed
|
||||
jp .Use
|
||||
|
||||
.XSpecial:
|
||||
call .XItem
|
||||
jp c, .DontUse
|
||||
call EnemyUsedXSpecial
|
||||
jp .Use
|
||||
|
||||
.XItem:
|
||||
ld a, [wEnemyTurnsTaken]
|
||||
and a
|
||||
jr nz, .notfirstturnout
|
||||
ld a, [bc]
|
||||
bit ALWAYS_USE_F, a
|
||||
jp nz, .Use
|
||||
call Random
|
||||
cp 50 percent + 1
|
||||
jp c, .DontUse
|
||||
ld a, [bc]
|
||||
bit CONTEXT_USE_F, a
|
||||
jp nz, .Use
|
||||
call Random
|
||||
cp 50 percent + 1
|
||||
jp c, .DontUse
|
||||
jp .Use
|
||||
.notfirstturnout
|
||||
ld a, [bc]
|
||||
bit ALWAYS_USE_F, a
|
||||
jp z, .DontUse
|
||||
call Random
|
||||
cp 20 percent - 1
|
||||
jp nc, .DontUse
|
||||
jp .Use
|
||||
|
||||
.DontUse:
|
||||
scf
|
||||
ret
|
||||
|
||||
.Use:
|
||||
and a
|
||||
ret
|
||||
|
||||
AIUpdateHUD:
|
||||
call UpdateEnemyMonInParty
|
||||
farcall UpdateEnemyHUD
|
||||
ld a, $1
|
||||
ldh [hBGMapMode], a
|
||||
ld hl, wEnemyItemState
|
||||
dec [hl]
|
||||
scf
|
||||
ret
|
||||
|
||||
AIUsedItemSound:
|
||||
push de
|
||||
ld de, SFX_FULL_HEAL
|
||||
call PlaySFX
|
||||
pop de
|
||||
ret
|
||||
|
||||
EnemyUsedFullHeal:
|
||||
call AIUsedItemSound
|
||||
call AI_HealStatus
|
||||
ld a, FULL_HEAL
|
||||
jp PrintText_UsedItemOn_AND_AIUpdateHUD
|
||||
|
||||
EnemyUsedMaxPotion:
|
||||
ld a, MAX_POTION
|
||||
ld [wCurEnemyItem], a
|
||||
jr FullRestoreContinue
|
||||
|
||||
EnemyUsedFullRestore:
|
||||
; BUG: AI use of Full Heal does not cure confusion status (see docs/bugs_and_glitches.md)
|
||||
call AI_HealStatus
|
||||
ld a, FULL_RESTORE
|
||||
ld [wCurEnemyItem], a
|
||||
ld hl, wEnemySubStatus3
|
||||
res SUBSTATUS_CONFUSED, [hl]
|
||||
xor a
|
||||
ld [wEnemyConfuseCount], a
|
||||
; fallthrough
|
||||
|
||||
FullRestoreContinue:
|
||||
ld de, wCurHPAnimOldHP
|
||||
ld hl, wEnemyMonHP + 1
|
||||
ld a, [hld]
|
||||
ld [de], a
|
||||
inc de
|
||||
ld a, [hl]
|
||||
ld [de], a
|
||||
inc de
|
||||
ld hl, wEnemyMonMaxHP + 1
|
||||
ld a, [hld]
|
||||
ld [de], a
|
||||
inc de
|
||||
ld [wCurHPAnimMaxHP], a
|
||||
ld [wEnemyMonHP + 1], a
|
||||
ld a, [hl]
|
||||
ld [de], a
|
||||
ld [wCurHPAnimMaxHP + 1], a
|
||||
ld [wEnemyMonHP], a
|
||||
jr EnemyPotionFinish
|
||||
|
||||
EnemyUsedPotion:
|
||||
ld a, POTION
|
||||
ld b, 20
|
||||
jr EnemyPotionContinue
|
||||
|
||||
EnemyUsedSuperPotion:
|
||||
ld a, SUPER_POTION
|
||||
ld b, 50
|
||||
jr EnemyPotionContinue
|
||||
|
||||
EnemyUsedHyperPotion:
|
||||
ld a, HYPER_POTION
|
||||
ld b, 200
|
||||
|
||||
EnemyPotionContinue:
|
||||
ld [wCurEnemyItem], a
|
||||
ld hl, wEnemyMonHP + 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, wEnemyMonMaxHP + 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:
|
||||
call PrintText_UsedItemOn
|
||||
hlcoord 2, 2
|
||||
xor a
|
||||
ld [wWhichHPBar], a
|
||||
call AIUsedItemSound
|
||||
predef AnimateHPBar
|
||||
jp AIUpdateHUD
|
||||
|
||||
AI_TrySwitch:
|
||||
; Determine whether the AI can switch based on how many Pokemon are still alive.
|
||||
; If it can switch, it will.
|
||||
ld a, [wOTPartyCount]
|
||||
ld c, a
|
||||
ld hl, wOTPartyMon1HP
|
||||
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
|
||||
|
||||
AI_Switch:
|
||||
ld a, $1
|
||||
ld [wEnemyIsSwitching], a
|
||||
ld [wEnemyGoesFirst], a
|
||||
ld hl, wEnemySubStatus4
|
||||
res SUBSTATUS_RAGE, [hl]
|
||||
xor a
|
||||
ldh [hBattleTurn], a
|
||||
callfar PursuitSwitch
|
||||
|
||||
push af
|
||||
ld a, [wCurOTMon]
|
||||
ld hl, wOTPartyMon1Status
|
||||
ld bc, PARTYMON_STRUCT_LENGTH
|
||||
call AddNTimes
|
||||
ld d, h
|
||||
ld e, l
|
||||
ld hl, wEnemyMonStatus
|
||||
ld bc, MON_MAXHP - MON_STATUS
|
||||
call CopyBytes
|
||||
pop af
|
||||
|
||||
jr c, .skiptext
|
||||
ld hl, EnemyWithdrewText
|
||||
call PrintText
|
||||
|
||||
.skiptext
|
||||
ld a, 1
|
||||
ld [wBattleHasJustStarted], a
|
||||
callfar NewEnemyMonStatus
|
||||
callfar ResetEnemyStatLevels
|
||||
ld hl, wPlayerSubStatus1
|
||||
res SUBSTATUS_IN_LOVE, [hl]
|
||||
farcall EnemySwitch
|
||||
farcall ResetBattleParticipants
|
||||
xor a
|
||||
ld [wBattleHasJustStarted], a
|
||||
ld a, [wLinkMode]
|
||||
and a
|
||||
ret nz
|
||||
scf
|
||||
ret
|
||||
|
||||
EnemyWithdrewText:
|
||||
text_far _EnemyWithdrewText
|
||||
text_end
|
||||
|
||||
EnemyUsedFullHealRed: ; unreferenced
|
||||
call AIUsedItemSound
|
||||
call AI_HealStatus
|
||||
ld a, FULL_HEAL_RED ; X_SPEED
|
||||
jp PrintText_UsedItemOn_AND_AIUpdateHUD
|
||||
|
||||
AI_HealStatus:
|
||||
; BUG: AI use of Full Heal or Full Restore does not cure Nightmare status (see docs/bugs_and_glitches.md)
|
||||
ld a, [wCurOTMon]
|
||||
ld hl, wOTPartyMon1Status
|
||||
ld bc, PARTYMON_STRUCT_LENGTH
|
||||
call AddNTimes
|
||||
xor a
|
||||
ld [hl], a
|
||||
ld [wEnemyMonStatus], a
|
||||
ld hl, wEnemySubStatus5
|
||||
res SUBSTATUS_TOXIC, [hl]
|
||||
ret
|
||||
|
||||
EnemyUsedXAccuracy:
|
||||
call AIUsedItemSound
|
||||
ld hl, wEnemySubStatus4
|
||||
set SUBSTATUS_X_ACCURACY, [hl]
|
||||
ld a, X_ACCURACY
|
||||
jp PrintText_UsedItemOn_AND_AIUpdateHUD
|
||||
|
||||
EnemyUsedGuardSpec:
|
||||
call AIUsedItemSound
|
||||
ld hl, wEnemySubStatus4
|
||||
set SUBSTATUS_MIST, [hl]
|
||||
ld a, GUARD_SPEC
|
||||
jp PrintText_UsedItemOn_AND_AIUpdateHUD
|
||||
|
||||
EnemyUsedDireHit:
|
||||
call AIUsedItemSound
|
||||
ld hl, wEnemySubStatus4
|
||||
set SUBSTATUS_FOCUS_ENERGY, [hl]
|
||||
ld a, DIRE_HIT
|
||||
jp PrintText_UsedItemOn_AND_AIUpdateHUD
|
||||
|
||||
AICheckEnemyFractionMaxHP: ; unreferenced
|
||||
; Input: a = divisor
|
||||
; Work: bc = [wEnemyMonMaxHP] / a
|
||||
; Work: de = [wEnemyMonHP]
|
||||
; Output:
|
||||
; - c, nz if [wEnemyMonHP] > [wEnemyMonMaxHP] / a
|
||||
; - nc, z if [wEnemyMonHP] = [wEnemyMonMaxHP] / a
|
||||
; - nc, nz if [wEnemyMonHP] < [wEnemyMonMaxHP] / a
|
||||
ldh [hDivisor], a
|
||||
ld hl, wEnemyMonMaxHP
|
||||
ld a, [hli]
|
||||
ldh [hDividend], a
|
||||
ld a, [hl]
|
||||
ldh [hDividend + 1], a
|
||||
ld b, 2
|
||||
call Divide
|
||||
ldh a, [hQuotient + 3]
|
||||
ld c, a
|
||||
ldh a, [hQuotient + 2]
|
||||
ld b, a
|
||||
ld hl, wEnemyMonHP + 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
|
||||
|
||||
EnemyUsedXAttack:
|
||||
ld b, ATTACK
|
||||
ld a, X_ATTACK
|
||||
jr EnemyUsedXItem
|
||||
|
||||
EnemyUsedXDefend:
|
||||
ld b, DEFENSE
|
||||
ld a, X_DEFEND
|
||||
jr EnemyUsedXItem
|
||||
|
||||
EnemyUsedXSpeed:
|
||||
ld b, SPEED
|
||||
ld a, X_SPEED
|
||||
jr EnemyUsedXItem
|
||||
|
||||
EnemyUsedXSpecial:
|
||||
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 [wCurEnemyItem], a
|
||||
push bc
|
||||
call PrintText_UsedItemOn
|
||||
pop bc
|
||||
farcall RaiseStat
|
||||
jp AIUpdateHUD
|
||||
|
||||
; Parameter
|
||||
; a = ITEM_CONSTANT
|
||||
PrintText_UsedItemOn_AND_AIUpdateHUD:
|
||||
ld [wCurEnemyItem], a
|
||||
call PrintText_UsedItemOn
|
||||
jp AIUpdateHUD
|
||||
|
||||
PrintText_UsedItemOn:
|
||||
ld a, [wCurEnemyItem]
|
||||
ld [wNamedObjectIndex], a
|
||||
call GetItemName
|
||||
ld hl, wStringBuffer1
|
||||
ld de, wMonOrItemNameBuffer
|
||||
ld bc, ITEM_NAME_LENGTH
|
||||
call CopyBytes
|
||||
ld hl, EnemyUsedOnText
|
||||
jp PrintText
|
||||
|
||||
EnemyUsedOnText:
|
||||
text_far _EnemyUsedOnText
|
||||
text_end
|
||||
217
engine/battle/ai/move.asm
Normal file
217
engine/battle/ai/move.asm
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
AIChooseMove:
|
||||
; Score each move of wEnemyMonMoves in wEnemyAIMoveScores. 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, wEnemyAIMoveScores
|
||||
ld [hli], a
|
||||
ld [hli], a
|
||||
ld [hli], a
|
||||
ld [hl], a
|
||||
|
||||
; Don't pick disabled moves.
|
||||
ld a, [wEnemyDisabledMove]
|
||||
and a
|
||||
jr z, .CheckPP
|
||||
|
||||
ld hl, wEnemyMonMoves
|
||||
ld c, 0
|
||||
.CheckDisabledMove:
|
||||
cp [hl]
|
||||
jr z, .ScoreDisabledMove
|
||||
inc c
|
||||
inc hl
|
||||
jr .CheckDisabledMove
|
||||
.ScoreDisabledMove:
|
||||
ld hl, wEnemyAIMoveScores
|
||||
ld b, 0
|
||||
add hl, bc
|
||||
ld [hl], 80
|
||||
|
||||
; Don't pick moves with 0 PP.
|
||||
.CheckPP:
|
||||
ld hl, wEnemyAIMoveScores - 1
|
||||
ld de, wEnemyMonPP
|
||||
ld b, 0
|
||||
.CheckMovePP:
|
||||
inc b
|
||||
ld a, b
|
||||
cp NUM_MOVES + 1
|
||||
jr z, .ApplyLayers
|
||||
inc hl
|
||||
ld a, [de]
|
||||
inc de
|
||||
and PP_MASK
|
||||
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 trainer class in wTrainerClass (Falkner)
|
||||
; so we have always the same AI, regardless of the loaded class of trainer
|
||||
ld a, [wInBattleTowerBattle]
|
||||
bit 0, a
|
||||
jr nz, .battle_tower_skip
|
||||
|
||||
ld a, [wTrainerClass]
|
||||
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 SmallFarFlagAction
|
||||
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, wEnemyAIMoveScores
|
||||
ld de, wEnemyMonMoves
|
||||
ld c, NUM_MOVES
|
||||
|
||||
.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, wEnemyAIMoveScores
|
||||
ld de, wEnemyMonMoves
|
||||
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, wEnemyAIMoveScores
|
||||
call Random
|
||||
maskbits NUM_MOVES
|
||||
ld c, a
|
||||
ld b, 0
|
||||
add hl, bc
|
||||
ld a, [hl]
|
||||
and a
|
||||
jr z, .ChooseMove
|
||||
|
||||
ld [wCurEnemyMove], a
|
||||
ld a, c
|
||||
ld [wCurEnemyMoveNum], a
|
||||
ret
|
||||
|
||||
AIScoringPointers:
|
||||
; entries correspond to AI_* constants
|
||||
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
|
||||
199
engine/battle/ai/redundant.asm
Normal file
199
engine/battle/ai/redundant.asm
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
AI_Redundant:
|
||||
; 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:
|
||||
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:
|
||||
ld a, [wEnemyScreens]
|
||||
bit SCREENS_LIGHT_SCREEN, a
|
||||
ret
|
||||
|
||||
.Mist:
|
||||
ld a, [wEnemySubStatus4]
|
||||
bit SUBSTATUS_MIST, a
|
||||
ret
|
||||
|
||||
.FocusEnergy:
|
||||
ld a, [wEnemySubStatus4]
|
||||
bit SUBSTATUS_FOCUS_ENERGY, a
|
||||
ret
|
||||
|
||||
.Confuse:
|
||||
ld a, [wPlayerSubStatus3]
|
||||
bit SUBSTATUS_CONFUSED, a
|
||||
ret nz
|
||||
ld a, [wPlayerScreens]
|
||||
bit SCREENS_SAFEGUARD, a
|
||||
ret
|
||||
|
||||
.Transform:
|
||||
ld a, [wEnemySubStatus5]
|
||||
bit SUBSTATUS_TRANSFORMED, a
|
||||
ret
|
||||
|
||||
.Reflect:
|
||||
ld a, [wEnemyScreens]
|
||||
bit SCREENS_REFLECT, a
|
||||
ret
|
||||
|
||||
.Substitute:
|
||||
ld a, [wEnemySubStatus4]
|
||||
bit SUBSTATUS_SUBSTITUTE, a
|
||||
ret
|
||||
|
||||
.LeechSeed:
|
||||
ld a, [wPlayerSubStatus4]
|
||||
bit SUBSTATUS_LEECH_SEED, a
|
||||
ret
|
||||
|
||||
.Disable:
|
||||
ld a, [wPlayerDisableCount]
|
||||
and a
|
||||
ret
|
||||
|
||||
.Encore:
|
||||
ld a, [wPlayerSubStatus5]
|
||||
bit SUBSTATUS_ENCORED, a
|
||||
ret
|
||||
|
||||
.Snore:
|
||||
.SleepTalk:
|
||||
ld a, [wEnemyMonStatus]
|
||||
and SLP_MASK
|
||||
jr z, .Redundant
|
||||
jr .NotRedundant
|
||||
|
||||
.MeanLook:
|
||||
ld a, [wEnemySubStatus5]
|
||||
bit SUBSTATUS_CANT_RUN, a
|
||||
ret
|
||||
|
||||
.Nightmare:
|
||||
ld a, [wBattleMonStatus]
|
||||
and a
|
||||
jr z, .Redundant
|
||||
ld a, [wPlayerSubStatus1]
|
||||
bit SUBSTATUS_NIGHTMARE, a
|
||||
ret
|
||||
|
||||
.Spikes:
|
||||
ld a, [wPlayerScreens]
|
||||
bit SCREENS_SPIKES, a
|
||||
ret
|
||||
|
||||
.Foresight:
|
||||
ld a, [wPlayerSubStatus1]
|
||||
bit SUBSTATUS_IDENTIFIED, a
|
||||
ret
|
||||
|
||||
.PerishSong:
|
||||
ld a, [wPlayerSubStatus1]
|
||||
bit SUBSTATUS_PERISH, a
|
||||
ret
|
||||
|
||||
.Sandstorm:
|
||||
ld a, [wBattleWeather]
|
||||
cp WEATHER_SANDSTORM
|
||||
jr z, .Redundant
|
||||
jr .NotRedundant
|
||||
|
||||
.Attract:
|
||||
farcall CheckOppositeGender
|
||||
jr c, .Redundant
|
||||
ld a, [wPlayerSubStatus1]
|
||||
bit SUBSTATUS_IN_LOVE, a
|
||||
ret
|
||||
|
||||
.Safeguard:
|
||||
ld a, [wEnemyScreens]
|
||||
bit SCREENS_SAFEGUARD, a
|
||||
ret
|
||||
|
||||
.RainDance:
|
||||
ld a, [wBattleWeather]
|
||||
cp WEATHER_RAIN
|
||||
jr z, .Redundant
|
||||
jr .NotRedundant
|
||||
|
||||
.SunnyDay:
|
||||
ld a, [wBattleWeather]
|
||||
cp WEATHER_SUN
|
||||
jr z, .Redundant
|
||||
jr .NotRedundant
|
||||
|
||||
.DreamEater:
|
||||
ld a, [wBattleMonStatus]
|
||||
and SLP_MASK
|
||||
jr z, .Redundant
|
||||
jr .NotRedundant
|
||||
|
||||
.Swagger:
|
||||
ld a, [wPlayerSubStatus3]
|
||||
bit SUBSTATUS_CONFUSED, a
|
||||
ret
|
||||
|
||||
.FutureSight:
|
||||
; BUG: AI does not discourage Future Sight when it's already been used (see docs/bugs_and_glitches.md)
|
||||
ld a, [wEnemyScreens]
|
||||
bit 5, a
|
||||
ret
|
||||
|
||||
.Heal:
|
||||
.MorningSun:
|
||||
.Synthesis:
|
||||
.Moonlight:
|
||||
farcall AICheckEnemyMaxHP
|
||||
jr nc, .NotRedundant
|
||||
|
||||
.Teleport:
|
||||
.Redundant:
|
||||
ld a, 1
|
||||
and a
|
||||
ret
|
||||
|
||||
.NotRedundant:
|
||||
xor a
|
||||
ret
|
||||
3293
engine/battle/ai/scoring.asm
Normal file
3293
engine/battle/ai/scoring.asm
Normal file
File diff suppressed because it is too large
Load diff
650
engine/battle/ai/switch.asm
Normal file
650
engine/battle/ai/switch.asm
Normal file
|
|
@ -0,0 +1,650 @@
|
|||
CheckPlayerMoveTypeMatchups:
|
||||
; 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, BASE_AI_SWITCH_SCORE
|
||||
ld [wEnemyAISwitchScore], a
|
||||
ld hl, wPlayerUsedMoves
|
||||
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
|
||||
call GetMoveTypeIfDamaging
|
||||
jr z, .next
|
||||
|
||||
ld hl, wEnemyMonType
|
||||
call CheckTypeMatchup
|
||||
ld a, [wTypeMatchup]
|
||||
cp EFFECTIVE + 1 ; 1.0 + 0.1
|
||||
jr nc, .super_effective
|
||||
and a
|
||||
jr z, .next
|
||||
cp EFFECTIVE ; 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, [wBattleMonType1]
|
||||
ld b, a
|
||||
ld hl, wEnemyMonType1
|
||||
call CheckTypeMatchup
|
||||
ld a, [wTypeMatchup]
|
||||
cp EFFECTIVE + 1 ; 1.0 + 0.1
|
||||
jr c, .ok
|
||||
call .DecreaseScore
|
||||
.ok
|
||||
ld a, [wBattleMonType2]
|
||||
cp b
|
||||
jr z, .ok2
|
||||
call CheckTypeMatchup
|
||||
ld a, [wTypeMatchup]
|
||||
cp EFFECTIVE + 1 ; 1.0 + 0.1
|
||||
jr c, .ok2
|
||||
call .DecreaseScore
|
||||
.ok2
|
||||
|
||||
.done
|
||||
call .CheckEnemyMoveMatchups
|
||||
pop bc
|
||||
pop de
|
||||
pop hl
|
||||
ret
|
||||
|
||||
.CheckEnemyMoveMatchups:
|
||||
ld de, wEnemyMonMoves
|
||||
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
|
||||
call GetMoveTypeIfDamaging
|
||||
jr z, .loop2
|
||||
|
||||
ld hl, wBattleMonType1
|
||||
call CheckTypeMatchup
|
||||
|
||||
ld a, [wTypeMatchup]
|
||||
; immune
|
||||
and a
|
||||
jr z, .loop2
|
||||
|
||||
; not very effective
|
||||
inc c
|
||||
cp EFFECTIVE
|
||||
jr c, .loop2
|
||||
|
||||
; neutral
|
||||
inc c
|
||||
inc c
|
||||
inc c
|
||||
inc c
|
||||
inc c
|
||||
cp EFFECTIVE
|
||||
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:
|
||||
ld a, [wEnemyAISwitchScore]
|
||||
dec a
|
||||
ld [wEnemyAISwitchScore], a
|
||||
ret
|
||||
|
||||
.IncreaseScore:
|
||||
ld a, [wEnemyAISwitchScore]
|
||||
inc a
|
||||
ld [wEnemyAISwitchScore], a
|
||||
ret
|
||||
|
||||
CheckAbleToSwitch:
|
||||
xor a
|
||||
ld [wEnemySwitchMonParam], a
|
||||
call FindAliveEnemyMons
|
||||
ret c
|
||||
|
||||
ld a, [wEnemySubStatus1]
|
||||
bit SUBSTATUS_PERISH, a
|
||||
jr z, .no_perish
|
||||
|
||||
ld a, [wEnemyPerishCount]
|
||||
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, [wLastPlayerCounterMove]
|
||||
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
|
||||
|
||||
FindAliveEnemyMons:
|
||||
ld a, [wOTPartyCount]
|
||||
cp 2
|
||||
jr c, .only_one
|
||||
|
||||
ld d, a
|
||||
ld e, 0
|
||||
ld b, 1 << (PARTY_LENGTH - 1)
|
||||
ld c, 0
|
||||
ld hl, wOTPartyMon1HP
|
||||
|
||||
.loop
|
||||
ld a, [wCurOTMon]
|
||||
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
|
||||
|
||||
FindEnemyMonsImmuneToLastCounterMove:
|
||||
ld hl, wOTPartyMon1
|
||||
ld a, [wOTPartyCount]
|
||||
ld b, a
|
||||
ld c, 1 << (PARTY_LENGTH - 1)
|
||||
ld d, 0
|
||||
xor a
|
||||
ld [wEnemyAISwitchScore], a
|
||||
|
||||
.loop
|
||||
ld a, [wCurOTMon]
|
||||
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 [wCurSpecies], a
|
||||
call GetBaseData
|
||||
|
||||
; the player's last move is damaging...
|
||||
ld a, [wLastPlayerCounterMove]
|
||||
call GetMoveTypeIfDamaging
|
||||
jr z, .next
|
||||
|
||||
; and the Pokemon is immune to it...
|
||||
ld hl, wBaseType
|
||||
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
|
||||
|
||||
FindAliveEnemyMonsWithASuperEffectiveMove:
|
||||
push bc
|
||||
ld a, [wOTPartyCount]
|
||||
ld e, a
|
||||
ld hl, wOTPartyMon1HP
|
||||
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, wPartyMon2HP - (wPartyMon1HP + 1)
|
||||
add hl, bc
|
||||
pop bc
|
||||
dec e
|
||||
jr nz, .loop
|
||||
|
||||
ld a, c
|
||||
pop bc
|
||||
|
||||
and c
|
||||
ld c, a
|
||||
; fallthrough
|
||||
|
||||
FindEnemyMonsWithASuperEffectiveMove:
|
||||
ld a, -1
|
||||
ld [wEnemyAISwitchScore], a
|
||||
ld hl, wOTPartyMon1Moves
|
||||
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
|
||||
call GetMoveTypeIfDamaging
|
||||
jr z, .nope
|
||||
|
||||
; check type matchups
|
||||
ld hl, wBattleMonType1
|
||||
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 EFFECTIVE + 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
|
||||
|
||||
FindEnemyMonsThatResistPlayer:
|
||||
push bc
|
||||
ld hl, wOTPartySpecies
|
||||
ld b, 1 << (PARTY_LENGTH - 1)
|
||||
ld c, 0
|
||||
|
||||
.loop
|
||||
ld a, [hli]
|
||||
cp $ff
|
||||
jr z, .done
|
||||
|
||||
push hl
|
||||
ld [wCurSpecies], a
|
||||
call GetBaseData
|
||||
ld a, [wLastPlayerCounterMove]
|
||||
and a
|
||||
jr z, .skip_move
|
||||
|
||||
call GetMoveTypeIfDamaging
|
||||
jr nz, .check_type
|
||||
|
||||
.skip_move
|
||||
ld a, [wBattleMonType1]
|
||||
ld hl, wBaseType
|
||||
call CheckTypeMatchup
|
||||
ld a, [wTypeMatchup]
|
||||
cp 10 + 1
|
||||
jr nc, .dont_choose_mon
|
||||
ld a, [wBattleMonType2]
|
||||
|
||||
.check_type
|
||||
ld hl, wBaseType
|
||||
call CheckTypeMatchup
|
||||
ld a, [wTypeMatchup]
|
||||
cp EFFECTIVE + 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
|
||||
|
||||
FindEnemyMonsWithAtLeastQuarterMaxHP:
|
||||
push bc
|
||||
ld de, wOTPartySpecies
|
||||
ld b, 1 << (PARTY_LENGTH - 1)
|
||||
ld c, 0
|
||||
ld hl, wOTPartyMon1HP
|
||||
|
||||
.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
|
||||
|
||||
GetMoveTypeIfDamaging:
|
||||
; returns the type of move a in a, and sets the zero flag depending on whether the move causes damage
|
||||
; clobbers hl
|
||||
push bc
|
||||
call GetMoveAddress
|
||||
ld b, a
|
||||
rept MOVE_POWER - 1
|
||||
inc hl
|
||||
endr
|
||||
call GetFarByte
|
||||
ld c, a
|
||||
ld a, b
|
||||
inc hl
|
||||
call GetFarByte
|
||||
inc c
|
||||
dec c
|
||||
pop bc
|
||||
ret
|
||||
Loading…
Add table
Add a link
Reference in a new issue