shithub: pokered

Download patch

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