mirror of
https://github.com/thornAvery/kep-hack.git
synced 2025-09-16 18:30:50 +12:00
AI Improvements
This fixes some of the issues with the current AI system to make them better. In short: - Most Trainers should correctly recognise when a move is not very effective, and not use it. If they have a supereffective move and a regular-effective move, they will slightly prioritise the supereffective one, but not always use it like in regular RBY. This prevents the Lorelei softlock, for example. - Trainers won't attempt to set status effects on Pokemon that already have one, won't try recovering at full health, and won't attempt to set up multiple Reflects or Light Screen - Certain high-level trainers will recognise when a Pokemon does not have a status, and will try to inflict one if so. This makes Agatha's, Erika's and Koga's team types much more effective. - Youngsters and Cue Balls no longer pick moves randomly and will actually give it some thought - Brock and the Engineers now recognize type effectiveness, Students do not given how early they're encountered. - General improvements to move choices for all Gym Leaders, E4 and Shinjuku Jacky. We're almost done.
This commit is contained in:
parent
a486ec7657
commit
e6763371e4
|
@ -260,7 +260,7 @@ and more!
|
|||
|
||||
Known Bugs
|
||||
====
|
||||
- The new AI (possibly bugged?) behaves quite oddly, such as using Recover at full HP, spamming status-inflicting moves like Lovely Kiss, neglecting supereffective moves, setting up multiple Reflects, etc.
|
||||
- Currently testing...
|
||||
|
||||
Evolution Methods for new Pokemon
|
||||
====
|
||||
|
|
|
@ -50,7 +50,7 @@ PredefPointers::
|
|||
add_predef UpdateHPBar
|
||||
add_predef HPBarLength
|
||||
add_predef Diploma_TextBoxBorder
|
||||
; add_predef DoubleOrHalveSelectedStats
|
||||
add_predef DoubleOrHalveSelectedStats
|
||||
add_predef ShowPokedexMenu
|
||||
add_predef EvolutionAfterBattle
|
||||
add_predef SaveSAVtoSRAM0
|
||||
|
|
|
@ -9,7 +9,7 @@ ENDM
|
|||
; move choice modification methods that are applied for each trainer class
|
||||
TrainerClassMoveChoiceModifications:
|
||||
list_start TrainerClassMoveChoiceModifications
|
||||
move_choices ; YOUNGSTER
|
||||
move_choices 1 ; YOUNGSTER
|
||||
move_choices 1 ; BUG CATCHER
|
||||
move_choices 1 ; LASS
|
||||
move_choices 1, 3 ; SAILOR
|
||||
|
@ -20,10 +20,10 @@ TrainerClassMoveChoiceModifications:
|
|||
move_choices 1 ; HIKER
|
||||
move_choices 1 ; BIKER
|
||||
move_choices 1, 3 ; BURGLAR
|
||||
move_choices 1 ; ENGINEER
|
||||
move_choices 1, 3 ; ENGINEER
|
||||
move_choices 1, 3 ; FISHER
|
||||
move_choices 1, 3 ; SWIMMER
|
||||
move_choices ; CUE_BALL
|
||||
move_choices 1 ; CUE_BALL
|
||||
move_choices 1 ; GAMBLER
|
||||
move_choices 1, 3 ; BEAUTY
|
||||
move_choices 1, 2 ; PSYCHIC_TR
|
||||
|
@ -33,32 +33,32 @@ TrainerClassMoveChoiceModifications:
|
|||
move_choices 1 ; BIRD_KEEPER
|
||||
move_choices 1 ; BLACKBELT
|
||||
move_choices 1 ; RIVAL1
|
||||
move_choices 1, 3 ; PROF_OAK
|
||||
move_choices 1, 2 ; CHIEF
|
||||
move_choices 1, 2 ; SCIENTIST
|
||||
move_choices 1, 3 ; GIOVANNI
|
||||
move_choices 1, 2, 3, 4 ; PROF_OAK
|
||||
move_choices 1, 2, 3, 4 ; CHIEF
|
||||
move_choices 1, 2, 4 ; SCIENTIST
|
||||
move_choices 1, 2, 3 ; GIOVANNI
|
||||
move_choices 1 ; ROCKET
|
||||
move_choices 1, 3 ; COOLTRAINER_M
|
||||
move_choices 1, 3 ; COOLTRAINER_F
|
||||
move_choices 1 ; BRUNO
|
||||
move_choices 1 ; BROCK
|
||||
move_choices 1, 3 ; MISTY
|
||||
move_choices 1, 3 ; LT_SURGE
|
||||
move_choices 1, 3 ; ERIKA
|
||||
move_choices 1, 3 ; KOGA
|
||||
move_choices 1, 3 ; BLAINE
|
||||
move_choices 1, 3 ; SABRINA
|
||||
move_choices 1, 3, 4 ; COOLTRAINER_M
|
||||
move_choices 1, 3, 4 ; COOLTRAINER_F
|
||||
move_choices 1, 2, 3 ; BRUNO
|
||||
move_choices 1, 3 ; BROCK
|
||||
move_choices 1, 3, 4 ; MISTY
|
||||
move_choices 1, 2, 3 ; LT_SURGE
|
||||
move_choices 1, 3, 4 ; ERIKA
|
||||
move_choices 1, 3, 4 ; KOGA
|
||||
move_choices 1, 2, 3 ; BLAINE
|
||||
move_choices 1, 3, 4 ; SABRINA
|
||||
move_choices 1, 2 ; GENTLEMAN
|
||||
move_choices 1, 3 ; RIVAL2
|
||||
move_choices 1, 3 ; RIVAL3
|
||||
move_choices 1, 2, 3 ; LORELEI
|
||||
move_choices 1, 2, 3, 4 ; RIVAL3
|
||||
move_choices 1, 2, 3, 4 ; LORELEI
|
||||
move_choices 1 ; CHANNELER
|
||||
move_choices 1 ; AGATHA
|
||||
move_choices 1, 3 ; LANCE
|
||||
move_choices 1, 3, ; YUJIROU, was UNUSED_JUGGLER
|
||||
move_choices 1, 3, ; STUDENT
|
||||
move_choices 1, 2, 3, 4 ; AGATHA
|
||||
move_choices 1, 2, 3, 4 ; LANCE
|
||||
move_choices 1, 3, ; YUJIROU
|
||||
move_choices 1 ; STUDENT
|
||||
move_choices 1, 3, ; FIREFIGHTER
|
||||
move_choices 1, 3, ; KOICHI
|
||||
move_choices 1, 3, ; JACK
|
||||
move_choices 1, 2, 3 ; KOICHI
|
||||
move_choices 1, 2, 3, 4 ; JACK
|
||||
move_choices 1, 3, ; JESSIE_JAMES
|
||||
assert_list_length NUM_TRAINERS
|
||||
|
|
|
@ -7,6 +7,18 @@ AIEnemyTrainerChooseMoves:
|
|||
ld [hli], a ; move 2
|
||||
ld [hli], a ; move 3
|
||||
ld [hl], a ; move 4
|
||||
|
||||
;;;;;;;;;; shinpokerednote: ADDED: make a backup buffer
|
||||
push hl
|
||||
ld a, $ff
|
||||
inc hl
|
||||
ld [hli], a ;backup 1
|
||||
ld [hli], a ;backup 2
|
||||
ld [hli], a ;backup 3
|
||||
ld [hl], a ;backup 4
|
||||
pop hl
|
||||
;;;;;;;;;;
|
||||
|
||||
ld a, [wEnemyDisabledMove] ; forbid disabled move (if any)
|
||||
swap a
|
||||
and $f
|
||||
|
@ -52,6 +64,11 @@ AIEnemyTrainerChooseMoves:
|
|||
ld de, .nextMoveChoiceModification ; set return address
|
||||
push de
|
||||
jp hl ; execute modification function
|
||||
.loopFindMinimumEntries_backupfirst ;shinpokerednote: ADDED: make a backup of the scores
|
||||
ld hl, wBuffer ; temp move selection array
|
||||
ld de, wBuffer + NUM_MOVES ;backup buffer
|
||||
ld bc, NUM_MOVES
|
||||
rst _CopyData
|
||||
.loopFindMinimumEntries ; all entries will be decremented sequentially until one of them is zero
|
||||
ld hl, wBuffer ; temp move selection array
|
||||
ld de, wEnemyMonMoves ; enemy moves
|
||||
|
@ -466,10 +483,8 @@ AIMoveChoiceModification3:
|
|||
jr c, .notEffectiveMove
|
||||
;ld a, [wEnemyMoveEffect]
|
||||
; check for reasons not to use a super effective move here
|
||||
|
||||
dec [hl] ; slightly encourage this super effective move
|
||||
.checkSpecificEffects ; we'll further encourage certain moves
|
||||
call EncouragePriorityIfSlow
|
||||
call EncourageDrainingMoveIfLowHealth
|
||||
jr .nextMove
|
||||
.notEffectiveMove ; discourages non-effective moves if better moves are available
|
||||
|
@ -479,7 +494,7 @@ AIMoveChoiceModification3:
|
|||
ld a, [wEnemyMoveType]
|
||||
ld d, a
|
||||
ld hl, wEnemyMonMoves ; enemy moves
|
||||
ld b, NUM_MOVES + 1
|
||||
ld bc, NUM_MOVES + 1
|
||||
ld c, $0
|
||||
.loopMoves
|
||||
dec b
|
||||
|
@ -543,18 +558,6 @@ CompareSpeed:
|
|||
ret
|
||||
;;;;;;;;;;
|
||||
|
||||
; PureRGBnote: ADDED: encourages priority moves if the enemy's pokemon is slower than the player's and the move is neutral or super effective.
|
||||
; BUT this effect is only applied after you have the soulbadge to prevent priority moves from being spammed early game.
|
||||
; Applies to trainers that use AI subroutine 3
|
||||
EncouragePriorityIfSlow:
|
||||
ld a, [wObtainedBadges]
|
||||
bit BIT_SOULBADGE, a
|
||||
ret z
|
||||
call CompareSpeed
|
||||
ret nc
|
||||
dec [hl] ; encourage the move if it's a priority move and the pokemon is slower
|
||||
ret
|
||||
|
||||
; PureRGBnote: ADDED: if the opponent has less than 1/2 health they will prefer healing moves if they use AI subroutine 3
|
||||
EncourageDrainingMoveIfLowHealth:
|
||||
ld a, [wEnemyMoveEffect]
|
||||
|
@ -576,11 +579,11 @@ AIMoveChoiceModification4:
|
|||
ld b, NUM_MOVES + 1
|
||||
.nextMove
|
||||
dec b
|
||||
jr z, .done ; processed all 4 moves
|
||||
ret z ; processed all 4 moves
|
||||
inc hl
|
||||
ld a, [de]
|
||||
and a
|
||||
jr z, .done ; no more moves in move set
|
||||
ret z ; no more moves in move set
|
||||
inc de
|
||||
call ReadMove
|
||||
ld a, [wEnemyMoveEffect]
|
||||
|
@ -626,8 +629,7 @@ AIMoveChoiceModification4:
|
|||
jr z, .nextMove ; if the AI thinks the player IS NOT asleep before they switch, we shouldn't encourage based on the new mon's status
|
||||
ld a, [wBattleMonStatus]
|
||||
and SLP_MASK
|
||||
jr nz, .preferMoveEvenMore ; heavier favor for dream eater if the opponent is asleep
|
||||
jr .nextMove
|
||||
jr z, .nextMove
|
||||
.preferMoveEvenMore
|
||||
dec [hl]
|
||||
jr .preferMove
|
||||
|
@ -676,9 +678,6 @@ TrainerAI:
|
|||
ld a, [wIsInBattle]
|
||||
dec a
|
||||
ret z ; if not a trainer, we're done here
|
||||
ld a, [wCurMap]
|
||||
cp BATTLE_TENT
|
||||
ret z ; if we are in battle tent, we are done
|
||||
ld a, [wLinkState]
|
||||
cp LINK_STATE_BATTLING
|
||||
ret z ; if in a link battle, we're done as well
|
||||
|
@ -732,12 +731,9 @@ BlackbeltAI:
|
|||
jp AIUseXAttack
|
||||
|
||||
GiovanniAI:
|
||||
cp 20 percent + 1
|
||||
cp 25 percent + 1
|
||||
ret nc
|
||||
ld a, [wEnemyBattleStatus2]
|
||||
bit GETTING_PUMPED, a
|
||||
ret nz
|
||||
jp AIUseDireHit
|
||||
jp AIUseXAttack ; Used to use a Guard Spec. This will make the item use have a proper impact - healing doesn't feel right for a trainer fixated on strength.
|
||||
|
||||
CooltrainerMAI:
|
||||
cp 20 percent + 1
|
||||
|
@ -765,41 +761,46 @@ BrockAI:
|
|||
jp AIUseFullHeal
|
||||
|
||||
MistyAI:
|
||||
cp 20 percent + 1
|
||||
cp 25 percent + 1
|
||||
ret nc
|
||||
jp AIUseXDefend
|
||||
ld a, 10
|
||||
call AICheckIfHPBelowFraction
|
||||
ret nc
|
||||
jp AIUseSuperPotion ; Replicates Starmie using Recover. Unlike other trainers that heal, Misty will do this 26% of the time instead of 51%.
|
||||
|
||||
LtSurgeAI:
|
||||
cp 10 percent + 1
|
||||
cp 20 percent + 1
|
||||
ret nc
|
||||
jp AIUseXSpeed
|
||||
jp AIUseXSpecial
|
||||
|
||||
ErikaAI:
|
||||
cp 50 percent + 1
|
||||
ret nc
|
||||
ld a, 5
|
||||
ld a, 10
|
||||
call AICheckIfHPBelowFraction
|
||||
ret nc
|
||||
jp AIUseSuperPotion
|
||||
|
||||
KogaAI:
|
||||
cp 10 percent + 1
|
||||
cp 50 percent + 1
|
||||
ret nc
|
||||
jp AIUseXAttack
|
||||
ld a, 10
|
||||
call AICheckIfHPBelowFraction
|
||||
ret nc
|
||||
jp AIUseSuperPotion ; Koga is weird - I don't think anything fits. X Attack is certainly not the move though...
|
||||
|
||||
BlaineAI: ;blaine needs to check HP. this was an oversight
|
||||
cp 40 percent + 1
|
||||
jr nc, .blainereturn
|
||||
ld a, 2
|
||||
call AICheckIfHPBelowFraction
|
||||
jp c, AIUseSuperPotion
|
||||
.blainereturn
|
||||
ret
|
||||
BlaineAI:
|
||||
cp 25 percent + 1
|
||||
ret nc
|
||||
ld a, 10
|
||||
call AICheckIfHPBelowFraction
|
||||
ret nc ; this fixes the super potion thing - PvK
|
||||
jp AIUseHyperPotion ; Instead of a Super Potion though, let's give him this. More impactful for the sixth gym while staying true to the meme that everyone knows Gen 1 Blaine for.
|
||||
|
||||
SabrinaAI:
|
||||
cp 25 percent + 1
|
||||
ret nc
|
||||
ld a, 5
|
||||
ld a, 10
|
||||
call AICheckIfHPBelowFraction
|
||||
ret nc
|
||||
jp AIUseHyperPotion
|
||||
|
@ -810,7 +811,7 @@ Rival2AI:
|
|||
ld a, 5
|
||||
call AICheckIfHPBelowFraction
|
||||
ret nc
|
||||
jp AIUseHyperPotion
|
||||
jp AIUseSuperPotion
|
||||
|
||||
Rival3AI:
|
||||
cp 40 percent - 1
|
||||
|
@ -821,43 +822,51 @@ Rival3AI:
|
|||
jp AIUseFullRestore
|
||||
|
||||
LoreleiAI:
|
||||
cp 50 percent + 1
|
||||
cp 15 percent + 1
|
||||
ret nc
|
||||
jp AIUseXSpecial
|
||||
cp 40 percent + 1
|
||||
ret nc
|
||||
ld a, 5
|
||||
call AICheckIfHPBelowFraction
|
||||
ret nc
|
||||
jp AIUseHyperPotion
|
||||
jp AIUseFullRestore
|
||||
|
||||
BrunoAI:
|
||||
;cp 10 percent + 1
|
||||
;ret nc
|
||||
;jp AIUseXDefend
|
||||
cp 30 percent + 1
|
||||
jr nc, .brunoreturn
|
||||
cp 15 percent + 1
|
||||
ret nc
|
||||
jp AIUseXAttack
|
||||
cp 40 percent + 1
|
||||
ret nc
|
||||
ld a, 5
|
||||
call AICheckIfHPBelowFraction
|
||||
jp c, AIUseHyperPotion
|
||||
.brunoreturn
|
||||
ret
|
||||
ret nc
|
||||
jp AIUseFullRestore
|
||||
|
||||
AgathaAI:
|
||||
cp 8 percent
|
||||
jp c, AISwitchIfEnoughMons
|
||||
cp 50 percent + 1
|
||||
cp 15 percent + 1
|
||||
ret nc
|
||||
ld a, 4
|
||||
call AICheckIfHPBelowFraction
|
||||
ret nc
|
||||
jp AIUseHyperPotion
|
||||
|
||||
LanceAI:
|
||||
cp 50 percent + 1
|
||||
jp AIUseXAccuracy ; hahahahahahahaha
|
||||
cp 40 percent + 1
|
||||
ret nc
|
||||
ld a, 5
|
||||
call AICheckIfHPBelowFraction
|
||||
ret nc
|
||||
jp AIUseFullRestore
|
||||
|
||||
LanceAI:
|
||||
cp 15 percent + 1
|
||||
ret nc
|
||||
jp AIUseXSpecial
|
||||
cp 50 percent + 1
|
||||
ret nc
|
||||
ld a, 10
|
||||
call AICheckIfHPBelowFraction
|
||||
ret nc
|
||||
jp AIUseFullRestore
|
||||
|
||||
GenericAI:
|
||||
and a ; clear carry
|
||||
ret
|
||||
|
@ -1087,12 +1096,12 @@ AICureStatus: ;shinpokerednote: CHANGED: modified to be more robust and also und
|
|||
res BADLY_POISONED, [hl] ;clear toxic bit
|
||||
ret
|
||||
|
||||
;AIUseXAccuracy: ; unused
|
||||
; call AIPlayRestoringSFX
|
||||
; ld hl, wEnemyBattleStatus2
|
||||
; set 0, [hl]
|
||||
; ld a, X_ACCURACY
|
||||
; jp AIPrintItemUse
|
||||
AIUseXAccuracy:
|
||||
call AIPlayRestoringSFX
|
||||
ld hl, wEnemyBattleStatus2
|
||||
set 0, [hl]
|
||||
ld a, X_ACCURACY
|
||||
jp AIPrintItemUse
|
||||
|
||||
;AIUseGuardSpec: ; PureRGBnote: CHANGED: now unused
|
||||
; call AIPlayRestoringSFX
|
||||
|
|
|
@ -1,4 +1,54 @@
|
|||
; Used by the pureRGB AI
|
||||
;shinpokerednote: ADDED: doubles the given stat
|
||||
DoubleSelectedStats:
|
||||
ldh a, [hWhoseTurn]
|
||||
and a
|
||||
ld a, [wPlayerStatsToDouble]
|
||||
ld hl, wBattleMonAttack
|
||||
jr z, .notEnemyTurn
|
||||
ld a, [wEnemyStatsToDouble]
|
||||
ld hl, wEnemyMonAttack
|
||||
.notEnemyTurn
|
||||
ld c, 4
|
||||
ld b, a
|
||||
.loop
|
||||
srl b
|
||||
call c, .doubleStat
|
||||
inc hl
|
||||
inc hl
|
||||
dec c
|
||||
ret z
|
||||
jr .loop
|
||||
.doubleStat
|
||||
push bc
|
||||
ld a, [hli]
|
||||
ld b, a
|
||||
ld c, [hl] ; bc holds value of stat to double
|
||||
;double the stat
|
||||
sla c
|
||||
rl b
|
||||
;cap stat at 999
|
||||
;b register contains high byte & c register contains low byte
|
||||
ld a, c ;let's work on low byte first. Note that decimal 999 is $03E7 in hex.
|
||||
sub 999 % $100 ;a = a - ($03E7 % $100). Gives a = a - $E7. A byte % $100 always gives the lesser nibble.
|
||||
;Note that if a < $E7 then the carry bit 'c' in the flag register gets set due to overflowing with a negative result.
|
||||
ld a, b ;now let's work on the high byte
|
||||
sbc 999 / $100 ;a = a - ($03E7 / $100 + c_flag). Gives a = a - ($03 + c_flag). A byte / $100 always gives the greater nibble.
|
||||
;Note again that if a < $03 then the carry bit remains set.
|
||||
;If the bit is already set from the lesser nibble, then its addition here can still make it remain set if a is low enough.
|
||||
jr c, .donecapping ;jump to next marker if the c_flag is set. This only remains set if BC < the cap of $03E7.
|
||||
;else let's continue and set the 999 cap
|
||||
ld a, 999 / $100 ; else load $03 into a
|
||||
ld b, a ;and store it as the high byte
|
||||
ld a, 999 % $100 ; else load $E7 into a
|
||||
ld c, a ;and store it as the low byte
|
||||
;now registers b & c together contain $03E7 for a capped stat value of 999
|
||||
.donecapping
|
||||
ld a, c
|
||||
ld [hld], a
|
||||
ld [hl], b
|
||||
pop bc
|
||||
ret
|
||||
|
||||
;shinpokerednote: ADDED: doubles attack if burned or quadruples speed if paralyzed.
|
||||
;It's meant to be run right before healing paralysis or burn so as to
|
||||
;undo the stat changes.
|
||||
|
@ -31,35 +81,6 @@ UndoBurnParStats:
|
|||
ld [de], a ;reset the stat change bits
|
||||
ret
|
||||
|
||||
; Reused for pureRGB AI
|
||||
DoubleSelectedStats:
|
||||
ldh a, [hWhoseTurn]
|
||||
and a
|
||||
ld a, [wPlayerStatsToDouble]
|
||||
ld hl, wBattleMonAttack + 1
|
||||
jr z, .notEnemyTurn
|
||||
ld a, [wEnemyStatsToDouble]
|
||||
ld hl, wEnemyMonAttack + 1
|
||||
.notEnemyTurn
|
||||
ld c, 4
|
||||
ld b, a
|
||||
.loop
|
||||
srl b
|
||||
call c, .doubleStat
|
||||
inc hl
|
||||
inc hl
|
||||
dec c
|
||||
ret z
|
||||
jr .loop
|
||||
.doubleStat
|
||||
ld a, [hl]
|
||||
add a
|
||||
ld [hld], a
|
||||
ld a, [hl]
|
||||
rl a
|
||||
ld [hli], a
|
||||
ret
|
||||
|
||||
; does nothing since no stats are ever selected (barring glitches)
|
||||
;HalveSelectedStats:
|
||||
; ldh a, [hWhoseTurn]
|
||||
|
|
4
main.asm
4
main.asm
|
@ -186,6 +186,8 @@ SECTION "Battle Engine 7", ROMX
|
|||
|
||||
INCLUDE "data/moves/moves.asm"
|
||||
INCLUDE "data/pokemon/cries.asm"
|
||||
INCLUDE "engine/battle/scroll_draw_trainer_pic.asm"
|
||||
INCLUDE "engine/battle/trainer_ai.asm"
|
||||
INCLUDE "engine/battle/unused_stats_functions.asm"
|
||||
INCLUDE "engine/battle/move_effects/heal.asm"
|
||||
INCLUDE "engine/battle/move_effects/transform.asm"
|
||||
|
@ -249,8 +251,6 @@ INCLUDE "engine/events/hidden_objects/indigo_plateau_hq.asm"
|
|||
|
||||
SECTION "Battle Engine 9", ROMX
|
||||
|
||||
INCLUDE "engine/battle/scroll_draw_trainer_pic.asm"
|
||||
INCLUDE "engine/battle/trainer_ai.asm"
|
||||
INCLUDE "engine/battle/draw_hud_pokeball_gfx.asm"
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue