2015-11-28 12:13:40 -08:00
|
|
|
AIChooseMove: ; 440ce
|
|
|
|
; Score each move in EnemyMonMoves starting from Buffer1. Lower is better.
|
|
|
|
; Pick the move with the lowest score.
|
|
|
|
|
|
|
|
; Wildmons attack at random.
|
|
|
|
ld a, [wBattleMode]
|
|
|
|
dec a
|
|
|
|
ret z
|
|
|
|
|
|
|
|
ld a, [wLinkMode]
|
|
|
|
and a
|
|
|
|
ret nz
|
|
|
|
|
|
|
|
; No use picking a move if there's no choice.
|
2017-12-24 09:47:30 -08:00
|
|
|
farcall CheckEnemyLockedIn
|
2015-11-28 12:13:40 -08:00
|
|
|
ret nz
|
|
|
|
|
|
|
|
|
|
|
|
; The default score is 20. Unusable moves are given a score of 80.
|
|
|
|
ld a, 20
|
|
|
|
ld hl, Buffer1
|
|
|
|
ld [hli], a
|
2016-05-10 09:31:49 -07:00
|
|
|
ld [hli], a
|
|
|
|
ld [hli], a
|
2015-11-28 12:13:40 -08:00
|
|
|
ld [hl], a
|
|
|
|
|
|
|
|
; Don't pick disabled moves.
|
|
|
|
ld a, [EnemyDisabledMove]
|
|
|
|
and a
|
|
|
|
jr z, .CheckPP
|
|
|
|
|
|
|
|
ld hl, EnemyMonMoves
|
|
|
|
ld c, 0
|
2016-04-10 11:42:14 -07:00
|
|
|
.CheckDisabledMove:
|
2015-11-28 12:13:40 -08:00
|
|
|
cp [hl]
|
|
|
|
jr z, .ScoreDisabledMove
|
|
|
|
inc c
|
|
|
|
inc hl
|
|
|
|
jr .CheckDisabledMove
|
2016-04-10 11:42:14 -07:00
|
|
|
.ScoreDisabledMove:
|
2015-11-28 12:13:40 -08:00
|
|
|
ld hl, Buffer1
|
|
|
|
ld b, 0
|
|
|
|
add hl, bc
|
|
|
|
ld [hl], 80
|
|
|
|
|
|
|
|
; Don't pick moves with 0 PP.
|
2016-04-10 11:42:14 -07:00
|
|
|
.CheckPP:
|
2015-11-28 12:13:40 -08:00
|
|
|
ld hl, Buffer1 - 1
|
|
|
|
ld de, EnemyMonPP
|
|
|
|
ld b, 0
|
2016-04-10 11:42:14 -07:00
|
|
|
.CheckMovePP:
|
2015-11-28 12:13:40 -08:00
|
|
|
inc b
|
|
|
|
ld a, b
|
|
|
|
cp EnemyMonMovesEnd - EnemyMonMoves + 1
|
|
|
|
jr z, .ApplyLayers
|
|
|
|
inc hl
|
|
|
|
ld a, [de]
|
|
|
|
inc de
|
|
|
|
and $3f
|
|
|
|
jr nz, .CheckMovePP
|
|
|
|
ld [hl], 80
|
|
|
|
jr .CheckMovePP
|
|
|
|
|
|
|
|
|
|
|
|
; Apply AI scoring layers depending on the trainer class.
|
2016-04-10 11:42:14 -07:00
|
|
|
.ApplyLayers:
|
2015-11-28 12:13:40 -08:00
|
|
|
ld hl, TrainerClassAttributes + TRNATTR_AI_MOVE_WEIGHTS
|
|
|
|
|
|
|
|
; If we have a battle in BattleTower just load the Attributes of the first TrainerClass (Falkner)
|
|
|
|
; so we have always the same AI, regardless of the loaded class of trainer
|
|
|
|
ld a, [InBattleTowerBattle]
|
|
|
|
bit 0, a
|
|
|
|
jr nz, .battle_tower_skip
|
|
|
|
|
|
|
|
ld a, [TrainerClass]
|
|
|
|
dec a
|
|
|
|
ld bc, 7 ; Trainer2AI - Trainer1AI
|
|
|
|
call AddNTimes
|
|
|
|
|
|
|
|
.battle_tower_skip
|
|
|
|
lb bc, CHECK_FLAG, 0
|
|
|
|
push bc
|
|
|
|
push hl
|
|
|
|
|
2016-04-10 11:42:14 -07:00
|
|
|
.CheckLayer:
|
2015-11-28 12:13:40 -08:00
|
|
|
pop hl
|
|
|
|
pop bc
|
|
|
|
|
|
|
|
ld a, c
|
|
|
|
cp 16 ; up to 16 scoring layers
|
|
|
|
jr z, .DecrementScores
|
|
|
|
|
|
|
|
push bc
|
|
|
|
ld d, BANK(TrainerClassAttributes)
|
|
|
|
predef FlagPredef
|
|
|
|
ld d, c
|
|
|
|
pop bc
|
|
|
|
|
|
|
|
inc c
|
|
|
|
push bc
|
|
|
|
push hl
|
|
|
|
|
|
|
|
ld a, d
|
|
|
|
and a
|
|
|
|
jr z, .CheckLayer
|
|
|
|
|
|
|
|
ld hl, AIScoringPointers
|
|
|
|
dec c
|
|
|
|
ld b, 0
|
|
|
|
add hl, bc
|
2016-05-04 08:46:23 -07:00
|
|
|
add hl, bc
|
2015-11-28 12:13:40 -08:00
|
|
|
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.
|
2016-04-10 11:42:14 -07:00
|
|
|
.DecrementScores:
|
2015-11-28 12:13:40 -08:00
|
|
|
ld hl, Buffer1
|
|
|
|
ld de, EnemyMonMoves
|
|
|
|
ld c, EnemyMonMovesEnd - EnemyMonMoves
|
|
|
|
|
2016-04-10 11:42:14 -07:00
|
|
|
.DecrementNextScore:
|
2015-11-28 12:13:40 -08:00
|
|
|
; 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.
|
2016-04-10 11:42:14 -07:00
|
|
|
.PickLowestScoreMoves:
|
2015-11-28 12:13:40 -08:00
|
|
|
ld a, c
|
|
|
|
|
|
|
|
.move_loop
|
|
|
|
inc [hl]
|
|
|
|
dec hl
|
|
|
|
inc a
|
|
|
|
cp NUM_MOVES + 1
|
|
|
|
jr nz, .move_loop
|
|
|
|
|
|
|
|
ld hl, Buffer1
|
|
|
|
ld de, EnemyMonMoves
|
|
|
|
ld c, NUM_MOVES
|
|
|
|
|
2016-04-10 11:42:14 -07:00
|
|
|
; Give a score of 0 to a blank move
|
2015-11-28 12:13:40 -08:00
|
|
|
.loop2
|
|
|
|
ld a, [de]
|
|
|
|
and a
|
|
|
|
jr nz, .skip_load
|
|
|
|
ld [hl], a
|
|
|
|
|
2016-04-10 11:42:14 -07:00
|
|
|
; Disregard the move if its score is not 1
|
2015-11-28 12:13:40 -08:00
|
|
|
.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
|
|
|
|
|
2016-04-10 11:42:14 -07:00
|
|
|
; Randomly choose one of the moves with a score of 1
|
|
|
|
.ChooseMove:
|
2015-11-28 12:13:40 -08:00
|
|
|
ld hl, Buffer1
|
|
|
|
call Random
|
|
|
|
and 3
|
|
|
|
ld c, a
|
|
|
|
ld b, 0
|
|
|
|
add hl, bc
|
|
|
|
ld a, [hl]
|
|
|
|
and a
|
|
|
|
jr z, .ChooseMove
|
|
|
|
|
|
|
|
ld [CurEnemyMove], a
|
|
|
|
ld a, c
|
|
|
|
ld [CurEnemyMoveNum], a
|
|
|
|
ret
|
|
|
|
; 441af
|
|
|
|
|
|
|
|
|
|
|
|
AIScoringPointers: ; 441af
|
|
|
|
dw AI_Basic
|
|
|
|
dw AI_Setup
|
|
|
|
dw AI_Types
|
|
|
|
dw AI_Offensive
|
|
|
|
dw AI_Smart
|
|
|
|
dw AI_Opportunist
|
|
|
|
dw AI_Aggressive
|
|
|
|
dw AI_Cautious
|
|
|
|
dw AI_Status
|
|
|
|
dw AI_Risky
|
|
|
|
dw AI_None
|
|
|
|
dw AI_None
|
|
|
|
dw AI_None
|
|
|
|
dw AI_None
|
|
|
|
dw AI_None
|
|
|
|
dw AI_None
|
|
|
|
; 441cf
|