ref: 1a3e59155f53d6ace5e0daee6d3f71f849367bd0
parent: 5f2a62871addefc7e6b845a9bb601caa26e0d237
author: Mr Wint <MrWint42@gmail.com>
date: Sun Mar 3 23:37:11 EST 2013
in-battle enemy move selection routines
--- a/main.asm
+++ b/main.asm
@@ -36556,8 +36556,266 @@
db $25, $44, $20; Weepinbell
db $25, $66, $CC; Victreebel
-INCBIN "baserom.gbc",$39680,$39884 - $39680
+INCBIN "baserom.gbc",$39680,$39719 - $39680
+; creates a set of moves that may be used and returns its address in hl
+; unused slots are filled with 0, all used slots may be chosen with equal probability
+AIEnemyTrainerChooseMoves: ; 5719 0x39719
+ ld a, $a
+ ld hl, $cee9 ; init temporary move selection array. Only the moves with the lowest numbers are chosen in the end
+ ld [hli], a ; move 1
+ ld [hli], a ; move 2
+ ld [hli], a ; move 3
+ ld [hl], a ; move 4
+ ld a, [W_ENEMYDISABLEDMOVE] ; forbid disabled move (if any)
+ swap a
+ and $f
+ jr z, .noMoveDisabled
+ ld hl, $cee9
+ dec a
+ ld c, a
+ ld b, $0
+ add hl, bc ; advance pointer to forbidden move
+ ld [hl], $50 ; forbid (highly discourage) disabled move
+.noMoveDisabled
+ ld hl, TrainerClassMoveChoiceModifications ; 589B
+ ld a, [W_TRAINERCLASS]
+ ld b, a
+.loopTrainerClasses
+ dec b
+ jr z, .readTrainerClassData
+.loopTrainerClassData
+ ld a, [hli]
+ and a
+ jr nz, .loopTrainerClassData
+ jr .loopTrainerClasses
+.readTrainerClassData
+ ld a, [hl]
+ and a
+ jp z, .useOriginalMoveSet
+ push hl
+.nextMoveChoiceModification
+ pop hl
+ ld a, [hli]
+ and a
+ jr z, .loopFindMinimumEntries
+ push hl
+ ld hl, AIMoveChoiceModificationFunctionPointers ; $57a3
+ dec a
+ add a
+ ld c, a
+ ld b, $0
+ add hl, bc ; skip to pointer
+ ld a, [hli] ; read pointer into hl
+ ld h, [hl]
+ ld l, a
+ ld de, .nextMoveChoiceModification ; set return address
+ push de
+ jp [hl] ; execute modification function
+.loopFindMinimumEntries ; all entries will be decremented sequentially until one of them is zero
+ ld hl, $cee9 ; temp move selection array
+ ld de, $cfed ; enemy moves
+ ld c, $4
+.loopDecrementEntries
+ ld a, [de]
+ inc de
+ and a
+ jr z, .loopFindMinimumEntries
+ dec [hl]
+ jr z, .minimumEntriesFound
+ inc hl
+ dec c
+ jr z, .loopFindMinimumEntries
+ jr .loopDecrementEntries
+.minimumEntriesFound
+ ld a, c
+.loopUndoPartialIteration ; undo last (partial) loop iteration
+ inc [hl]
+ dec hl
+ inc a
+ cp $5
+ jr nz, .loopUndoPartialIteration
+ ld hl, $cee9 ; temp move selection array
+ ld de, $cfed ; enemy moves
+ ld c, $4
+.filterMinimalEntries ; all minimal entries now have value 1. All other slots will be disabled (move set to 0)
+ ld a, [de]
+ and a
+ jr nz, .moveExisting ; 0x3978a $1
+ ld [hl], a
+.moveExisting
+ ld a, [hl]
+ dec a
+ jr z, .slotWithMinimalValue
+ xor a
+ ld [hli], a ; disable move slot
+ jr .next
+.slotWithMinimalValue
+ ld a, [de]
+ ld [hli], a ; enable move slot
+.next
+ inc de
+ dec c
+ jr nz, .filterMinimalEntries
+ ld hl, $cee9 ; use created temporary array as move set
+ ret
+.useOriginalMoveSet
+ ld hl, $cfed ; use original move set
+ ret
+
+AIMoveChoiceModificationFunctionPointers: ; 57a3
+dw AIMoveChoiceModification1
+dw AIMoveChoiceModification2
+dw AIMoveChoiceModification3
+dw AIMoveChoiceModification4 ; unused, does nothing
+
+; discourages moves that cause no damage but only a status ailment if player's mon already has one
+AIMoveChoiceModification1: ; 57ab
+ ld a, [W_PLAYERMONSTATUS]
+ and a
+ ret z ; return if no status ailment on player's mon
+ ld hl, $cee8 ; temp move selection array (-1 byte offest)
+ ld de, $cfed ; enemy moves
+ ld b, $5
+.nextMove
+ dec b
+ ret z ; processed all 4 moves
+ inc hl
+ ld a, [de]
+ and a
+ ret z ; no more moves in move set
+ inc de
+ call ReadMove
+ ld a, [W_ENEMYMOVEPOWER]
+ and a
+ jr nz, .nextMove
+ ld a, [W_ENEMYMOVEEFFECT]
+ push hl
+ push de
+ push bc
+ ld hl, StatusAilmentMoveEffects
+ ld de, $0001
+ call IsInArray
+ pop bc
+ pop de
+ pop hl
+ jr nc, .nextMove
+ ld a, [hl]
+ add $5 ; discourage move
+ ld [hl], a
+ jr .nextMove
+
+StatusAilmentMoveEffects ; 57e2
+db $01 ; some sleep effect?
+db SLEEP_EFFECT
+db POISON_EFFECT
+db PARALYZE_EFFECT
+db $FF
+
+; slightly encourage moves with specific effects
+AIMoveChoiceModification2: ; 57e7
+ ld a, [$ccd5]
+ cp $1
+ ret nz
+ ld hl, $cee8 ; temp move selection array (-1 byte offest)
+ ld de, $cfed ; enemy moves
+ ld b, $5
+.nextMove
+ dec b
+ ret z ; processed all 4 moves
+ inc hl
+ ld a, [de]
+ and a
+ ret z ; no more moves in move set
+ inc de
+ call ReadMove
+ ld a, [W_ENEMYMOVEEFFECT]
+ cp ATTACK_UP1_EFFECT
+ jr c, .nextMove
+ cp BIDE_EFFECT
+ jr c, .preferMove
+ cp ATTACK_UP2_EFFECT
+ jr c, .nextMove
+ cp POISON_EFFECT
+ jr c, .preferMove
+ jr .nextMove
+.preferMove
+ dec [hl] ; slighly encourage this move
+ jr .nextMove
+
+; encourages moves that are effective against the player's mon
+AIMoveChoiceModification3: ; 5817
+ ld hl, $cee8 ; temp move selection array (-1 byte offest)
+ ld de, $cfed ; enemy moves
+ ld b, $5
+.nextMove
+ dec b
+ ret z ; processed all 4 moves
+ inc hl
+ ld a, [de]
+ and a
+ ret z ; no more moves in move set
+ inc de
+ call ReadMove
+ push hl
+ push bc
+ push de
+ ld hl, AIGetTypeEffectiveness
+ ld b, BANK(AIGetTypeEffectiveness)
+ call Bankswitch
+ pop de
+ pop bc
+ pop hl
+ ld a, [$d11e]
+ cp $10
+ jr z, .nextMove
+ jr c, .notEffectiveMove
+ dec [hl] ; slighly encourage this move
+ jr .nextMove
+.notEffectiveMove ; discourages non-effective moves if better moves are available
+ push hl
+ push de
+ push bc
+ ld a, [W_ENEMYMOVETYPE]
+ ld d, a
+ ld hl, $cfed ; enemy moves
+ ld b, $5
+ ld c, $0
+.loopMoves
+ dec b
+ jr z, .done
+ ld a, [hli]
+ and a
+ jr z, .done
+ call ReadMove
+ ld a, [W_ENEMYMOVEEFFECT]
+ cp SUPER_FANG_EFFECT
+ jr z, .betterMoveFound ; Super Fang is considered to be a better move
+ cp SPECIAL_DAMAGE_EFFECT
+ jr z, .betterMoveFound ; any special damage moves are considered to be better moves
+ cp FLY_EFFECT
+ jr z, .betterMoveFound ; Fly is considered to be a better move
+ ld a, [W_ENEMYMOVETYPE]
+ cp d
+ jr z, .loopMoves
+ ld a, [W_ENEMYMOVEPOWER]
+ and a
+ jr nz, .betterMoveFound ; damaging moves of a different type are considered to be better moves
+ jr .loopMoves
+.betterMoveFound
+ ld c, a
+.done
+ ld a, c
+ pop bc
+ pop de
+ pop hl
+ and a
+ jr z, .nextMove
+ inc [hl] ; slighly discourage this move
+ jr .nextMove
+AIMoveChoiceModification4: ; 5883
+ ret
+
ReadMove: ; 5884
push hl
push de
@@ -36573,9 +36831,61 @@
pop hl
ret
+; move choice modifiaction methods that are applied for each trainer class
+; 0 is sentinel value
+TrainerClassMoveChoiceModifications: ; 589B
+db 0 ; YOUNGSTER
+db 1,0 ; BUG CATCHER
+db 1,0 ; LASS
+db 1,3,0 ; SAILOR
+db 1,0 ; JR__TRAINER_M
+db 1,0 ; JR__TRAINER_F
+db 1,2,3,0; POKEMANIAC
+db 1,2,0 ; SUPER_NERD
+db 1,0 ; HIKER
+db 1,0 ; BIKER
+db 1,3,0 ; BURGLAR
+db 1,0 ; ENGINEER
+db 1,2,0 ; JUGGLER_X
+db 1,3,0 ; FISHER
+db 1,3,0 ; SWIMMER
+db 0 ; CUE_BALL
+db 1,0 ; GAMBLER
+db 1,3,0 ; BEAUTY
+db 1,2,0 ; PSYCHIC_TR
+db 1,3,0 ; ROCKER
+db 1,0 ; JUGGLER
+db 1,0 ; TAMER
+db 1,0 ; BIRD_KEEPER
+db 1,0 ; BLACKBELT
+db 1,0 ; SONY1
+db 1,3,0 ; PROF_OAK
+db 1,2,0 ; CHIEF
+db 1,2,0 ; SCIENTIST
+db 1,3,0 ; GIOVANNI
+db 1,0 ; ROCKET
+db 1,3,0 ; COOLTRAINER_M
+db 1,3,0 ; COOLTRAINER_F
+db 1,0 ; BRUNO
+db 1,0 ; BROCK
+db 1,3,0 ; MISTY
+db 1,3,0 ; LT__SURGE
+db 1,3,0 ; ERIKA
+db 1,3,0 ; KOGA
+db 1,3,0 ; BLAINE
+db 1,3,0 ; SABRINA
+db 1,2,0 ; GENTLEMAN
+db 1,3,0 ; SONY2
+db 1,3,0 ; SONY3
+db 1,2,3,0; LORELEI
+db 1,0 ; CHANNELER
+db 1,0 ; AGATHA
+db 1,3,0 ; LANCE
+
+
; trainer data: from 5C53 to 652E
-INCBIN "baserom.gbc",$3989B,$39914 - $3989B
+; INCBIN "baserom.gbc",$3989e,$39914 - $3989e
; trainer pic pointers and base money.
dw YoungsterPic
@@ -40808,8 +41118,100 @@
db $50
; 0x3d430 + 5 bytes
-INCBIN "baserom.gbc",$3d435,$274
+INCBIN "baserom.gbc",$3d435,$3d564 - $3d435
+SelectEnemyMove: ; 5564 0x3d564
+ ld a, [W_ISLINKBATTLE]
+ sub $4
+ jr nz, .noLinkBattle
+ call $3719
+ call $5605
+ call $3725
+ ld a, [$cc3e]
+ cp $e
+ jp z, $5601
+ cp $d
+ jr z, .unableToMove
+ cp $4
+ ret nc
+ ld [$cce2], a
+ ld c, a
+ ld hl, $cfed
+ ld b, $0
+ add hl, bc
+ ld a, [hl]
+ jr .done
+.noLinkBattle
+ ld a, [W_ENEMYBATTSTATUS2]
+ and $60 ; need to recharge or using rage
+ ret nz
+ ld hl, W_ENEMYBATTSTATUS1
+ ld a, [hl]
+ and $12 ; using multi-turn move or bide
+ ret nz
+ ld a, [W_ENEMYMONSTATUS]
+ and SLP | FRZ ; sleeping or frozen
+ ret nz
+ ld a, [W_ENEMYBATTSTATUS1]
+ and $21 ; using fly/dig or thrash/petal dance
+ ret nz
+ ld a, [W_PLAYERBATTSTATUS1]
+ bit 5, a ; caught in player's multi-turn move (e.g. wrap)
+ jr z, .notCaughtInWrap
+.unableToMove
+ ld a, $ff
+ jr .done
+.notCaughtInWrap
+ ld hl, $cfee ; 2nd enemy move
+ ld a, [hld]
+ and a
+ jr nz, .atLeastTwoMovesAvailable
+ ld a, [W_ENEMYDISABLEDMOVE]
+ and a
+ ld a, STRUGGLE ; struggle if the only move is disabled
+ jr nz, .done
+.atLeastTwoMovesAvailable
+ ld a, [W_ISINBATTLE]
+ dec a
+ jr z, .chooseRandomMove ; wild encounter
+ ld hl, AIEnemyTrainerChooseMoves
+ ld b, BANK(AIEnemyTrainerChooseMoves)
+ call Bankswitch
+.chooseRandomMove
+ push hl
+ call GenRandomInBattle ; get random
+ ld b, $1
+ cp $3f ; select move 1 in [0,3e] (63/256 chance)
+ jr c, .moveChosen
+ inc hl
+ inc b
+ cp $7f ; select move 1 in [3f,7e] (64/256 chance)
+ jr c, .moveChosen
+ inc hl
+ inc b
+ cp $be ; select move 1 in [7f,bd] (63/256 chance)
+ jr c, .moveChosen
+ inc hl
+ inc b ; select move 4 in [be,ff] (66/256 chance)
+.moveChosen
+ ld a, b
+ dec a
+ ld [W_ENEMYMOVELISTINDEX], a
+ ld a, [W_ENEMYDISABLEDMOVE]
+ swap a
+ and $f
+ cp b
+ ld a, [hl]
+ pop hl
+ jr z, .chooseRandomMove ; move disabled, try again
+ and a
+ jr z, .chooseRandomMove ; move non-existant, try again
+.done
+ ld [W_ENEMYSELECTEDMOVE], a
+ ret
+
+INCBIN "baserom.gbc",$3d601,$3d6a9 - $3d601
+
; in-battle stuff
ld hl,W_PLAYERBATTSTATUS1
res 4,[hl]
@@ -41114,7 +41516,7 @@
ld [$CC5B],a
ld a,CONF_ANIM - 1
call $6F07
- call $6E9B
+ call GenRandomInBattle
cp a,$80
jr c,.next3
ld hl,W_PLAYERBATTSTATUS1
@@ -41137,7 +41539,7 @@
ld hl,W_PLAYERMONSTATUS
bit 6,[hl]
jr z,.next7 ; 5975
- call $6E9B ; random number?
+ call GenRandomInBattle ; random number
cp a,$3F
jr nc,.next7
ld hl,FullyParalyzedText
@@ -41225,7 +41627,7 @@
ld hl,W_PLAYERBATTSTATUS1
res 1,[hl]
set 7,[hl]
- call $6E9B ; random number?
+ call GenRandomInBattle ; random number
and a,3
inc a
inc a
@@ -41607,7 +42009,7 @@
jr nc, .SkipHighCritical
ld b, $ff
.SkipHighCritical
- call $6e9b ; probably generates a random value, in "a"
+ call GenRandomInBattle ; generates a random value, in "a"
rlc a
rlc a
rlc a
@@ -41738,7 +42140,7 @@
ld b,a ; b = level * 1.5
; loop until a random number in the range [1, b) is found
.loop
- call $6e9b ; random number
+ call GenRandomInBattle ; random number
and a
jr z,.loop
cp b
@@ -41859,7 +42261,7 @@
; this differs from the range when the player attacks, which is [1, b)
; it's possible for the enemy to do 0 damage with Psywave, but the player always does at least 1 damage
.loop
- call $6e9b ; random number
+ call GenRandomInBattle ; random number
cp b
jr nc,.loop
ld b,a
@@ -42094,7 +42496,7 @@
ld hl,W_ENEMYSELECTEDMOVE
; loop to pick a random number in the range [1, $a5) to be the move used by Metronome
.pickMoveLoop
- call $6e9b ; random number
+ call GenRandomInBattle ; random number
and a
jr z,.pickMoveLoop
cp a,$a5 ; max normal move number + 1 (this is Struggle's move number)
@@ -42477,7 +42879,7 @@
.doAccuracyCheck
; if the random number generated is greater than or equal to the scaled accuracy, the move misses
; note that this means that even the highest accuracy is still just a 255/256 chance, not 100%
- call $6e9b ; random number
+ call GenRandomInBattle ; random number
cp b
jr nc,.moveMissed
ret
@@ -42576,8 +42978,53 @@
db $50
; 0x3e887 + 5 bytes
-INCBIN "baserom.gbc",$3e88c,$67b
+INCBIN "baserom.gbc",$3e88c,$3ee9b - $3e88c
+; generates a random number unless in link battle
+; stores random number in A
+GenRandomInBattle: ; 6e9b
+ ld a, [W_ISLINKBATTLE]
+ cp $4
+ jp nz, GenRandom
+ push hl
+ push bc
+ ld a, [$ccde]
+ ld c, a
+ ld b, $0
+ ld hl, $d148
+ add hl, bc
+ inc a
+ ld [$ccde], a
+ cp $9
+ ld a, [hl]
+ pop bc
+ pop hl
+ ret c
+ push hl
+ push bc
+ push af
+ xor a
+ ld [$ccde], a
+ ld hl, $d148
+ ld b, $9
+.asm_3eec5
+ ld a, [hl]
+ ld c, a
+ add a
+ add a
+ add c
+ inc a
+ ld [hli], a
+ dec b
+ jr nz, .asm_3eec5 ; 0x3eecd $f6
+ pop af
+ pop bc
+ pop hl
+ ret
+; 0x3eed3
+
+INCBIN "baserom.gbc",$3eed3,$3ef07 - $3eed3
+
PlayMoveAnimation: ; 6F07
ld [$D07C],a
call Delay3
@@ -42657,7 +43104,7 @@
sub a, $1e ;subtract $1E to map to equivalent 10% chance effects
.next1
push af ;push effect...
- call $6e9b ;get random 8bit value for probability test
+ call GenRandomInBattle ;get random 8bit value for probability test
cp b ;success?
pop bc ;...pop effect into C
ret nc ;do nothing if random value is >= 1A or 4D [no status applied]
@@ -42709,7 +43156,7 @@
sub a, $1e
.next1
push af
- call $6e9b
+ call GenRandomInBattle
cp b
pop bc
ret nc