ref: ce9940a2eb89caa9f53507a6d6071f8eaf85ee48
parent: 10211cc461b35140c815e18e95f7070eb0dcc586
author: xCrystal <rgr.crystal@gmail.com>
date: Wed Apr 1 13:27:51 EDT 2015
Further split bank e stuff
--- /dev/null
+++ b/engine/battle/bank_e_misc.asm
@@ -1,0 +1,122 @@
+; formats a string at wMovesString that lists the moves at wMoves
+FormatMovesString: ; 39b87 (e:5b87)
+ ld hl, wMoves
+ ld de, wMovesString
+ ld b, $0
+.printMoveNameLoop
+ ld a, [hli]
+ and a ; end of move list?
+ jr z, .printDashLoop ; print dashes when no moves are left
+ push hl
+ ld [wd0b5], a
+ ld a, BANK(MoveNames)
+ ld [wPredefBank], a
+ ld a, MOVE_NAME
+ ld [wNameListType], a
+ call GetName
+ ld hl, wcd6d
+.copyNameLoop
+ ld a, [hli]
+ cp $50
+ jr z, .doneCopyingName
+ ld [de], a
+ inc de
+ jr .copyNameLoop
+.doneCopyingName
+ ld a, b
+ ld [wcd6c], a
+ inc b
+ ld a, $4e ; line break
+ ld [de], a
+ inc de
+ pop hl
+ ld a, b
+ cp NUM_MOVES
+ jr z, .done
+ jr .printMoveNameLoop
+.printDashLoop
+ ld a, "-"
+ ld [de], a
+ inc de
+ inc b
+ ld a, b
+ cp NUM_MOVES
+ jr z, .done
+ ld a, $4e ; line break
+ ld [de], a
+ inc de
+ jr .printDashLoop
+.done
+ ld a, "@"
+ ld [de], a
+ ret
+
+; XXX this is called in a few places, but it doesn't appear to do anything useful
+Func_39bd5: ; 39bd5 (e:5bd5)
+ ld a, [wd11b]
+ cp $1
+ jr nz, .asm_39be6
+ ld hl, wEnemyPartyCount
+ ld de, wEnemyMonOT
+ ld a, ENEMYOT_NAME
+ jr .asm_39c18
+.asm_39be6
+ cp $4
+ jr nz, .calcAttackStat4
+ ld hl, wPartyCount
+ ld de, wPartyMonOT
+ ld a, PLAYEROT_NAME
+ jr .asm_39c18
+.calcAttackStat4
+ cp $5
+ jr nz, .asm_39c02
+ ld hl, wStringBuffer2 + 11
+ ld de, MonsterNames
+ ld a, MONSTER_NAME
+ jr .asm_39c18
+.asm_39c02
+ cp $2
+ jr nz, .asm_39c10
+ ld hl, wNumBagItems
+ ld de, ItemNames
+ ld a, ITEM_NAME
+ jr .asm_39c18
+.asm_39c10
+ ld hl, wStringBuffer2 + 11
+ ld de, ItemNames
+ ld a, ITEM_NAME
+.asm_39c18
+ ld [wNameListType], a
+ ld a, l
+ ld [wList], a
+ ld a, h
+ ld [wList + 1], a
+ ld a, e
+ ld [wcf8d], a
+ ld a, d
+ ld [wcf8e], a
+ ld bc, ItemPrices
+ ld a, c
+ ld [wItemPrices], a
+ ld a, b
+ ld [wItemPrices + 1], a
+ ret
+
+; get species of mon e in list [wcc49] for LoadMonData
+GetMonSpecies: ; 39c37 (e:5c37)
+ ld hl, wPartySpecies
+ ld a, [wcc49]
+ and a
+ jr z, .getSpecies
+ dec a
+ jr z, .enemyParty
+ ld hl, wBoxSpecies
+ jr .getSpecies
+.enemyParty
+ ld hl, wEnemyPartyMons
+.getSpecies
+ ld d, 0
+ add hl, de
+ ld a, [hl]
+ ld [wcf91], a
+ ret
\ No newline at end of file
--- /dev/null
+++ b/engine/battle/read_trainer_party.asm
@@ -1,0 +1,164 @@
+ReadTrainer: ; 39c53 (e:5c53)
+
+; don't change any moves in a link battle
+ ld a,[wLinkState]
+ and a
+ ret nz
+
+; set [wEnemyPartyCount] to 0, [wEnemyPartyMons] to FF
+; XXX first is total enemy pokemon?
+; XXX second is species of first pokemon?
+ ld hl,wEnemyPartyCount
+ xor a
+ ld [hli],a
+ dec a
+ ld [hl],a
+
+; get the pointer to trainer data for this class
+ ld a,[W_CUROPPONENT]
+ sub $C9 ; convert value from pokemon to trainer
+ add a,a
+ ld hl,TrainerDataPointers
+ ld c,a
+ ld b,0
+ add hl,bc ; hl points to trainer class
+ ld a,[hli]
+ ld h,[hl]
+ ld l,a
+ ld a,[W_TRAINERNO]
+ ld b,a
+; At this point b contains the trainer number,
+; and hl points to the trainer class.
+; Our next task is to iterate through the trainers,
+; decrementing b each time, until we get to the right one.
+.outer
+ dec b
+ jr z,.IterateTrainer
+.inner
+ ld a,[hli]
+ and a
+ jr nz,.inner
+ jr .outer
+
+; if the first byte of trainer data is FF,
+; - each pokemon has a specific level
+; (as opposed to the whole team being of the same level)
+; - if [W_LONEATTACKNO] != 0, one pokemon on the team has a special move
+; else the first byte is the level of every pokemon on the team
+.IterateTrainer
+ ld a,[hli]
+ cp $FF ; is the trainer special?
+ jr z,.SpecialTrainer ; if so, check for special moves
+ ld [W_CURENEMYLVL],a
+.LoopTrainerData
+ ld a,[hli]
+ and a ; have we reached the end of the trainer data?
+ jr z,.FinishUp
+ ld [wcf91],a ; write species somewhere (XXX why?)
+ ld a,1
+ ld [wcc49],a
+ push hl
+ call AddPartyMon
+ pop hl
+ jr .LoopTrainerData
+.SpecialTrainer
+; if this code is being run:
+; - each pokemon has a specific level
+; (as opposed to the whole team being of the same level)
+; - if [W_LONEATTACKNO] != 0, one pokemon on the team has a special move
+ ld a,[hli]
+ and a ; have we reached the end of the trainer data?
+ jr z,.AddLoneMove
+ ld [W_CURENEMYLVL],a
+ ld a,[hli]
+ ld [wcf91],a
+ ld a,1
+ ld [wcc49],a
+ push hl
+ call AddPartyMon
+ pop hl
+ jr .SpecialTrainer
+.AddLoneMove
+; does the trainer have a single monster with a different move
+ ld a,[W_LONEATTACKNO] ; Brock is 01, Misty is 02, Erika is 04, etc
+ and a
+ jr z,.AddTeamMove
+ dec a
+ add a,a
+ ld c,a
+ ld b,0
+ ld hl,LoneMoves
+ add hl,bc
+ ld a,[hli]
+ ld d,[hl]
+ ld hl,wEnemyMon1Moves + 2
+ ld bc,wEnemyMon2 - wEnemyMon1
+ call AddNTimes
+ ld [hl],d
+ jr .FinishUp
+.AddTeamMove
+; check if our trainer's team has special moves
+
+; get trainer class number
+ ld a,[W_CUROPPONENT]
+ sub $C8
+ ld b,a
+ ld hl,TeamMoves
+
+; iterate through entries in TeamMoves, checking each for our trainer class
+.IterateTeamMoves
+ ld a,[hli]
+ cp b
+ jr z,.GiveTeamMoves ; is there a match?
+ inc hl ; if not, go to the next entry
+ inc a
+ jr nz,.IterateTeamMoves
+
+; no matches found. is this trainer champion rival?
+ ld a,b
+ cp SONY3
+ jr z,.ChampionRival
+ jr .FinishUp ; nope
+.GiveTeamMoves
+ ld a,[hl]
+ ld [wEnemyMon5Moves + 2],a
+ jr .FinishUp
+.ChampionRival ; give moves to his team
+
+; pidgeot
+ ld a,SKY_ATTACK
+ ld [wEnemyMon1Moves + 2],a
+
+; starter
+ ld a,[W_RIVALSTARTER]
+ cp STARTER3
+ ld b,MEGA_DRAIN
+ jr z,.GiveStarterMove
+ cp STARTER1
+ ld b,FIRE_BLAST
+ jr z,.GiveStarterMove
+ ld b,BLIZZARD ; must be squirtle
+.GiveStarterMove
+ ld a,b
+ ld [wEnemyMon6Moves + 2],a
+.FinishUp ; XXX this needs documenting
+ xor a ; clear D079-D07B
+ ld de,wd079
+ ld [de],a
+ inc de
+ ld [de],a
+ inc de
+ ld [de],a
+ ld a,[W_CURENEMYLVL]
+ ld b,a
+.LastLoop
+ ld hl,wd047
+ ld c,2
+ push bc
+ predef AddBCDPredef
+ pop bc
+ inc de
+ inc de
+ dec b
+ jr nz,.LastLoop
+ ret
\ No newline at end of file
--- /dev/null
+++ b/engine/battle/trainer_ai.asm
@@ -1,0 +1,837 @@
+; 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: ; 39719 (e:5719)
+ ld a, $a
+ ld hl, wHPBarMaxHP ; 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, wHPBarMaxHP
+ 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, wHPBarMaxHP ; temp move selection array
+ ld de, wEnemyMonMoves ; 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, wHPBarMaxHP ; temp move selection array
+ ld de, wEnemyMonMoves ; 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, wHPBarMaxHP ; use created temporary array as move set
+ ret
+.useOriginalMoveSet
+ ld hl, wEnemyMonMoves ; use original move set
+ ret
+
+AIMoveChoiceModificationFunctionPointers: ; 397a3 (e: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: ; 397ab (e:57ab)
+ ld a, [wBattleMonStatus]
+ and a
+ ret z ; return if no status ailment on player's mon
+ ld hl, wBuffer - 1 ; temp move selection array (-1 byte offest)
+ ld de, wEnemyMonMoves ; enemy moves
+ ld b, NUM_MOVES + 1
+.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 ; heavily discourage move
+ ld [hl], a
+ jr .nextMove
+
+StatusAilmentMoveEffects ; 57e2
+ db $01 ; unused sleep effect
+ db SLEEP_EFFECT
+ db POISON_EFFECT
+ db PARALYZE_EFFECT
+ db $FF
+
+; slightly encourage moves with specific effects.
+; in particular, stat-modifying moves and other move effects
+; that fall in-bewteen
+AIMoveChoiceModification2: ; 397e7 (e:57e7)
+ ld a, [wAILayer2Encouragement]
+ cp $1
+ ret nz
+ ld hl, wBuffer - 1 ; temp move selection array (-1 byte offset)
+ ld de, wEnemyMonMoves ; enemy moves
+ ld b, NUM_MOVES + 1
+.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] ; sligthly encourage this move
+ jr .nextMove
+
+; encourages moves that are effective against the player's mon (even if non-damaging).
+; discourage damaging moves that are ineffective or not very effective against the player's mon,
+; unless there's no damaging move that deals at least neutral damage
+AIMoveChoiceModification3: ; 39817 (e:5817)
+ ld hl, wBuffer - 1 ; temp move selection array (-1 byte offset)
+ ld de, wEnemyMonMoves ; 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
+ callab AIGetTypeEffectiveness
+ pop de
+ pop bc
+ pop hl
+ ld a, [wd11e]
+ cp $10
+ jr z, .nextMove
+ jr c, .notEffectiveMove
+ dec [hl] ; sligthly 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, wEnemyMonMoves ; enemy moves
+ ld b, NUM_MOVES + 1
+ 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] ; sligthly discourage this move
+ jr .nextMove
+AIMoveChoiceModification4: ; 39883 (e:5883)
+ ret
+
+ReadMove: ; 39884 (e:5884)
+ push hl
+ push de
+ push bc
+ dec a
+ ld hl,Moves
+ ld bc,6
+ call AddNTimes
+ ld de,W_ENEMYMOVENUM
+ call CopyData
+ pop bc
+ pop de
+ pop hl
+ ret
+
+; move choice modification methods that are applied for each trainer class
+; 0 is sentinel value
+TrainerClassMoveChoiceModifications: ; 3989b (e: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
+
+INCLUDE "engine/battle/trainer_pic_money_pointers.asm"
+
+INCLUDE "text/trainer_names.asm"
+
+INCLUDE "engine/battle/bank_e_misc.asm"
+
+INCLUDE "engine/battle/read_trainer_party.asm"
+
+INCLUDE "data/trainer_moves.asm"
+
+INCLUDE "data/trainer_parties.asm"
+
+TrainerAI: ; 3a52e (e:652e)
+;XXX called at 34964, 3c342, 3c398
+ and a
+ ld a,[W_ISINBATTLE]
+ dec a
+ ret z ; if not a trainer, we're done here
+ ld a,[wLinkState]
+ cp LINK_STATE_BATTLING
+ ret z
+ ld a,[W_TRAINERCLASS] ; what trainer class is this?
+ dec a
+ ld c,a
+ ld b,0
+ ld hl,TrainerAIPointers
+ add hl,bc
+ add hl,bc
+ add hl,bc
+ ld a,[wAICount]
+ and a
+ ret z ; if no AI uses left, we're done here
+ inc hl
+ inc a
+ jr nz,.getpointer
+ dec hl
+ ld a,[hli]
+ ld [wAICount],a
+.getpointer
+ ld a,[hli]
+ ld h,[hl]
+ ld l,a
+ call Random
+ jp [hl]
+
+TrainerAIPointers: ; 3a55c (e:655c)
+; one entry per trainer class
+; first byte, number of times (per Pokémon) it can occur
+; next two bytes, pointer to AI subroutine for trainer class
+ dbw 3,GenericAI
+ dbw 3,GenericAI
+ dbw 3,GenericAI
+ dbw 3,GenericAI
+ dbw 3,GenericAI
+ dbw 3,GenericAI
+ dbw 3,GenericAI
+ dbw 3,GenericAI
+ dbw 3,GenericAI
+ dbw 3,GenericAI
+ dbw 3,GenericAI
+ dbw 3,GenericAI
+ dbw 3,JugglerAI ; juggler_x
+ dbw 3,GenericAI
+ dbw 3,GenericAI
+ dbw 3,GenericAI
+ dbw 3,GenericAI
+ dbw 3,GenericAI
+ dbw 3,GenericAI
+ dbw 3,GenericAI
+ dbw 3,JugglerAI ; juggler
+ dbw 3,GenericAI
+ dbw 3,GenericAI
+ dbw 2,BlackbeltAI ; blackbelt
+ dbw 3,GenericAI
+ dbw 3,GenericAI
+ dbw 1,GenericAI ; chief
+ dbw 3,GenericAI
+ dbw 1,GiovanniAI ; giovanni
+ dbw 3,GenericAI
+ dbw 2,CooltrainerMAI ; cooltrainerm
+ dbw 1,CooltrainerFAI ; cooltrainerf
+ dbw 2,BrunoAI ; bruno
+ dbw 5,BrockAI ; brock
+ dbw 1,MistyAI ; misty
+ dbw 1,LtSurgeAI ; surge
+ dbw 1,ErikaAI ; erika
+ dbw 2,KogaAI ; koga
+ dbw 2,BlaineAI ; blaine
+ dbw 1,SabrinaAI ; sabrina
+ dbw 3,GenericAI
+ dbw 1,Sony2AI ; sony2
+ dbw 1,Sony3AI ; sony3
+ dbw 2,LoreleiAI ; lorelei
+ dbw 3,GenericAI
+ dbw 2,AgathaAI ; agatha
+ dbw 1,LanceAI ; lance
+
+JugglerAI: ; 3a5e9 (e:65e9)
+ cp $40
+ ret nc
+ jp AISwitchIfEnoughMons
+
+BlackbeltAI: ; 3a5ef (e:65ef)
+ cp $20
+ ret nc
+ jp AIUseXAttack
+
+GiovanniAI: ; 3a5f5 (e:65f5)
+ cp $40
+ ret nc
+ jp AIUseGuardSpec
+
+CooltrainerMAI: ; 3a5fb (e:65fb)
+ cp $40
+ ret nc
+ jp AIUseXAttack
+
+CooltrainerFAI: ; 3a601 (e:6601)
+ cp $40
+ ld a,$A
+ call AICheckIfHPBelowFraction
+ jp c,AIUseHyperPotion
+ ld a,5
+ call AICheckIfHPBelowFraction
+ ret nc
+ jp AISwitchIfEnoughMons
+
+BrockAI: ; 3a614 (e:6614)
+; if his active monster has a status condition, use a full heal
+ ld a,[wEnemyMonStatus]
+ and a
+ ret z
+ jp AIUseFullHeal
+
+MistyAI: ; 3a61c (e:661c)
+ cp $40
+ ret nc
+ jp AIUseXDefend
+
+LtSurgeAI: ; 3a622 (e:6622)
+ cp $40
+ ret nc
+ jp AIUseXSpeed
+
+ErikaAI: ; 3a628 (e:6628)
+ cp $80
+ ret nc
+ ld a,$A
+ call AICheckIfHPBelowFraction
+ ret nc
+ jp AIUseSuperPotion
+
+KogaAI: ; 3a634 (e:6634)
+ cp $40
+ ret nc
+ jp AIUseXAttack
+
+BlaineAI: ; 3a63a (e:663a)
+ cp $40
+ ret nc
+ jp AIUseSuperPotion
+
+SabrinaAI: ; 3a640 (e:6640)
+ cp $40
+ ret nc
+ ld a,$A
+ call AICheckIfHPBelowFraction
+ ret nc
+ jp AIUseHyperPotion
+
+Sony2AI: ; 3a64c (e:664c)
+ cp $20
+ ret nc
+ ld a,5
+ call AICheckIfHPBelowFraction
+ ret nc
+ jp AIUsePotion
+
+Sony3AI: ; 3a658 (e:6658)
+ cp $20
+ ret nc
+ ld a,5
+ call AICheckIfHPBelowFraction
+ ret nc
+ jp AIUseFullRestore
+
+LoreleiAI: ; 3a664 (e:6664)
+ cp $80
+ ret nc
+ ld a,5
+ call AICheckIfHPBelowFraction
+ ret nc
+ jp AIUseSuperPotion
+
+BrunoAI: ; 3a670 (e:6670)
+ cp $40
+ ret nc
+ jp AIUseXDefend
+
+AgathaAI: ; 3a676 (e:6676)
+ cp $14
+ jp c,AISwitchIfEnoughMons
+ cp $80
+ ret nc
+ ld a,4
+ call AICheckIfHPBelowFraction
+ ret nc
+ jp AIUseSuperPotion
+
+LanceAI: ; 3a687 (e:6687)
+ cp $80
+ ret nc
+ ld a,5
+ call AICheckIfHPBelowFraction
+ ret nc
+ jp AIUseHyperPotion
+
+GenericAI: ; 3a693 (e:6693)
+ and a ; clear carry
+ ret
+
+; end of individual trainer AI routines
+
+DecrementAICount: ; 3a695 (e:6695)
+ ld hl,wAICount
+ dec [hl]
+ scf
+ ret
+
+Func_3a69b: ; 3a69b (e:669b)
+ ld a,(SFX_08_3e - SFX_Headers_08) / 3
+ jp PlaySoundWaitForCurrent
+
+AIUseFullRestore: ; 3a6a0 (e:66a0)
+ call AICureStatus
+ ld a,FULL_RESTORE
+ ld [wcf05],a
+ ld de,wHPBarOldHP
+ 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 [wHPBarMaxHP],a
+ ld [wEnemyMonHP + 1],a
+ ld a,[hl]
+ ld [de],a
+ ld [wHPBarMaxHP+1],a
+ ld [wEnemyMonHP],a
+ jr AIPrintItemUseAndUpdateHPBar
+
+AIUsePotion: ; 3a6ca (e:66ca)
+; enemy trainer heals his monster with a potion
+ ld a,POTION
+ ld b,20
+ jr AIRecoverHP
+
+AIUseSuperPotion: ; 3a6d0 (e:66d0)
+; enemy trainer heals his monster with a super potion
+ ld a,SUPER_POTION
+ ld b,50
+ jr AIRecoverHP
+
+AIUseHyperPotion: ; 3a6d6 (e:66d6)
+; enemy trainer heals his monster with a hyper potion
+ ld a,HYPER_POTION
+ ld b,200
+ ; fallthrough
+
+AIRecoverHP: ; 3a6da (e:66da)
+; heal b HP and print "trainer used $(a) on pokemon!"
+ ld [wcf05],a
+ ld hl,wEnemyMonHP + 1
+ ld a,[hl]
+ ld [wHPBarOldHP],a
+ add b
+ ld [hld],a
+ ld [wHPBarNewHP],a
+ ld a,[hl]
+ ld [wHPBarOldHP+1],a
+ ld [wHPBarNewHP+1],a
+ jr nc,.next
+ inc a
+ ld [hl],a
+ ld [wHPBarNewHP+1],a
+.next
+ inc hl
+ ld a,[hld]
+ ld b,a
+ ld de,wEnemyMonMaxHP + 1
+ ld a,[de]
+ dec de
+ ld [wHPBarMaxHP],a
+ sub b
+ ld a,[hli]
+ ld b,a
+ ld a,[de]
+ ld [wHPBarMaxHP+1],a
+ sbc b
+ jr nc,AIPrintItemUseAndUpdateHPBar
+ inc de
+ ld a,[de]
+ dec de
+ ld [hld],a
+ ld [wHPBarNewHP],a
+ ld a,[de]
+ ld [hl],a
+ ld [wHPBarNewHP+1],a
+ ; fallthrough
+
+AIPrintItemUseAndUpdateHPBar: ; 3a718 (e:6718)
+ call AIPrintItemUse_
+ hlCoord 2, 2
+ xor a
+ ld [wHPBarType],a
+ predef UpdateHPBar2
+ jp DecrementAICount
+
+AISwitchIfEnoughMons: ; 3a72a (e:672a)
+; enemy trainer switches if there are 3 or more unfainted mons in party
+ ld a,[wEnemyPartyCount]
+ ld c,a
+ ld hl,wEnemyMon1HP
+
+ ld d,0 ; keep count of unfainted monsters
+
+ ; count how many monsters haven't fainted yet
+.loop
+ ld a,[hli]
+ ld b,a
+ ld a,[hld]
+ or b
+ jr z,.Fainted ; has monster fainted?
+ inc d
+.Fainted
+ push bc
+ ld bc,$2C
+ add hl,bc
+ pop bc
+ dec c
+ jr nz,.loop
+
+ ld a,d ; how many available monsters are there?
+ cp 2 ; don't bother if only 1 or 2
+ jp nc,SwitchEnemyMon
+ and a
+ ret
+
+SwitchEnemyMon: ; 3a74b (e:674b)
+
+; prepare to withdraw the active monster: copy hp, number, and status to roster
+
+ ld a,[wEnemyMonPartyPos]
+ ld hl,wEnemyMon1HP
+ ld bc,wEnemyMon2 - wEnemyMon1
+ call AddNTimes
+ ld d,h
+ ld e,l
+ ld hl,wEnemyMonHP
+ ld bc,4
+ call CopyData
+
+ ld hl, AIBattleWithdrawText
+ call PrintText
+
+ ld a,1
+ ld [wd11d],a
+ callab EnemySendOut
+ xor a
+ ld [wd11d],a
+
+ ld a,[wLinkState]
+ cp LINK_STATE_BATTLING
+ ret z
+ scf
+ ret
+
+AIBattleWithdrawText: ; 3a781 (e:6781)
+ TX_FAR _AIBattleWithdrawText
+ db "@"
+
+AIUseFullHeal: ; 3a786 (e:6786)
+ call Func_3a69b
+ call AICureStatus
+ ld a,FULL_HEAL
+ jp AIPrintItemUse
+
+AICureStatus: ; 3a791 (e:6791)
+; cures the status of enemy's active pokemon
+ ld a,[wEnemyMonPartyPos]
+ ld hl,wEnemyMon1Status
+ ld bc,wEnemyMon2 - wEnemyMon1
+ call AddNTimes
+ xor a
+ ld [hl],a ; clear status in enemy team roster
+ ld [wEnemyMonStatus],a ; clear status of active enemy
+ ld hl,W_ENEMYBATTSTATUS3
+ res 0,[hl]
+ ret
+
+AIUseXAccuracy: ; 0x3a7a8 unused
+ call Func_3a69b
+ ld hl,W_ENEMYBATTSTATUS2
+ set 0,[hl]
+ ld a,X_ACCURACY
+ jp AIPrintItemUse
+
+AIUseGuardSpec: ; 3a7b5 (e:67b5)
+ call Func_3a69b
+ ld hl,W_ENEMYBATTSTATUS2
+ set 1,[hl]
+ ld a,GUARD_SPEC_
+ jp AIPrintItemUse
+
+AIUseDireHit: ; 0x3a7c2 unused
+ call Func_3a69b
+ ld hl,W_ENEMYBATTSTATUS2
+ set 2,[hl]
+ ld a,DIRE_HIT
+ jp AIPrintItemUse
+
+AICheckIfHPBelowFraction: ; 3a7cf (e:67cf)
+; return carry if enemy trainer's current HP is below 1 / a of the maximum
+ ld [H_DIVISOR],a
+ ld hl,wEnemyMonMaxHP
+ ld a,[hli]
+ ld [H_DIVIDEND],a
+ ld a,[hl]
+ ld [H_DIVIDEND + 1],a
+ ld b,2
+ call Divide
+ ld a,[H_QUOTIENT + 3]
+ ld c,a
+ ld a,[H_QUOTIENT + 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
+
+AIUseXAttack: ; 3a7f2 (e:67f2)
+ ld b,$A
+ ld a,X_ATTACK
+ jr AIIncreaseStat
+
+AIUseXDefend: ; 3a7f8 (e:67f8)
+ ld b,$B
+ ld a,X_DEFEND
+ jr AIIncreaseStat
+
+AIUseXSpeed: ; 3a7fe (e:67fe)
+ ld b,$C
+ ld a,X_SPEED
+ jr AIIncreaseStat
+
+AIUseXSpecial: ; 3a804 (e:6804)
+ ld b,$D
+ ld a,X_SPECIAL
+ ; fallthrough
+
+AIIncreaseStat: ; 3a808 (e:6808)
+ ld [wcf05],a
+ push bc
+ call AIPrintItemUse_
+ pop bc
+ ld hl,W_ENEMYMOVEEFFECT
+ ld a,[hld]
+ push af
+ ld a,[hl]
+ push af
+ push hl
+ ld a,$AF
+ ld [hli],a
+ ld [hl],b
+ callab StatModifierUpEffect
+ pop hl
+ pop af
+ ld [hli],a
+ pop af
+ ld [hl],a
+ jp DecrementAICount
+
+AIPrintItemUse: ; 3a82c (e:682c)
+ ld [wcf05],a
+ call AIPrintItemUse_
+ jp DecrementAICount
+
+AIPrintItemUse_: ; 3a835 (e:6835)
+; print "x used [wcf05] on z!"
+ ld a,[wcf05]
+ ld [wd11e],a
+ call GetItemName
+ ld hl, AIBattleUseItemText
+ jp PrintText
+
+AIBattleUseItemText: ; 3a844 (e:6844)
+ TX_FAR _AIBattleUseItemText
+ db "@"
--- a/engine/battle/trainer_party_ai_misc.asm
+++ /dev/null
@@ -1,1263 +1,0 @@
-; 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: ; 39719 (e:5719)
- ld a, $a
- ld hl, wHPBarMaxHP ; 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, wHPBarMaxHP
- 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, wHPBarMaxHP ; temp move selection array
- ld de, wEnemyMonMoves ; 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, wHPBarMaxHP ; temp move selection array
- ld de, wEnemyMonMoves ; 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, wHPBarMaxHP ; use created temporary array as move set
- ret
-.useOriginalMoveSet
- ld hl, wEnemyMonMoves ; use original move set
- ret
-
-AIMoveChoiceModificationFunctionPointers: ; 397a3 (e: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: ; 397ab (e:57ab)
- ld a, [wBattleMonStatus]
- and a
- ret z ; return if no status ailment on player's mon
- ld hl, wBuffer - 1 ; temp move selection array (-1 byte offest)
- ld de, wEnemyMonMoves ; enemy moves
- ld b, NUM_MOVES + 1
-.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 ; heavily discourage move
- ld [hl], a
- jr .nextMove
-
-StatusAilmentMoveEffects ; 57e2
- db $01 ; unused sleep effect
- db SLEEP_EFFECT
- db POISON_EFFECT
- db PARALYZE_EFFECT
- db $FF
-
-; slightly encourage moves with specific effects.
-; in particular, stat-modifying moves and other move effects
-; that fall in-bewteen
-AIMoveChoiceModification2: ; 397e7 (e:57e7)
- ld a, [wAILayer2Encouragement]
- cp $1
- ret nz
- ld hl, wBuffer - 1 ; temp move selection array (-1 byte offset)
- ld de, wEnemyMonMoves ; enemy moves
- ld b, NUM_MOVES + 1
-.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] ; sligthly encourage this move
- jr .nextMove
-
-; encourages moves that are effective against the player's mon (even if non-damaging).
-; discourage damaging moves that are ineffective or not very effective against the player's mon,
-; unless there's no damaging move that deals at least neutral damage
-AIMoveChoiceModification3: ; 39817 (e:5817)
- ld hl, wBuffer - 1 ; temp move selection array (-1 byte offset)
- ld de, wEnemyMonMoves ; 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
- callab AIGetTypeEffectiveness
- pop de
- pop bc
- pop hl
- ld a, [wd11e]
- cp $10
- jr z, .nextMove
- jr c, .notEffectiveMove
- dec [hl] ; sligthly 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, wEnemyMonMoves ; enemy moves
- ld b, NUM_MOVES + 1
- 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] ; sligthly discourage this move
- jr .nextMove
-AIMoveChoiceModification4: ; 39883 (e:5883)
- ret
-
-ReadMove: ; 39884 (e:5884)
- push hl
- push de
- push bc
- dec a
- ld hl,Moves
- ld bc,6
- call AddNTimes
- ld de,W_ENEMYMOVENUM
- call CopyData
- pop bc
- pop de
- pop hl
- ret
-
-; move choice modification methods that are applied for each trainer class
-; 0 is sentinel value
-TrainerClassMoveChoiceModifications: ; 3989b (e: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
-
-TrainerPicAndMoneyPointers: ; 39914 (e:5914)
-; trainer pic pointers and base money.
-; money received after battle = base money × level of highest-level enemy mon
- dw YoungsterPic
- money 1500
-
- dw BugCatcherPic
- money 1000
-
- dw LassPic
- money 1500
-
- dw SailorPic
- money 3000
-
- dw JrTrainerMPic
- money 2000
-
- dw JrTrainerFPic
- money 2000
-
- dw PokemaniacPic
- money 5000
-
- dw SuperNerdPic
- money 2500
-
- dw HikerPic
- money 3500
-
- dw BikerPic
- money 2000
-
- dw BurglarPic
- money 9000
-
- dw EngineerPic
- money 5000
-
- dw JugglerPic
- money 3500
-
- dw FisherPic
- money 3500
-
- dw SwimmerPic
- money 500
-
- dw CueBallPic
- money 2500
-
- dw GamblerPic
- money 7000
-
- dw BeautyPic
- money 7000
-
- dw PsychicPic
- money 1000
-
- dw RockerPic
- money 2500
-
- dw JugglerPic
- money 3500
-
- dw TamerPic
- money 4000
-
- dw BirdKeeperPic
- money 2500
-
- dw BlackbeltPic
- money 2500
-
- dw Rival1Pic
- money 3500
-
- dw ProfOakPic
- money 9900
-
- dw ChiefPic
- money 3000
-
- dw ScientistPic
- money 5000
-
- dw GiovanniPic
- money 9900
-
- dw RocketPic
- money 3000
-
- dw CooltrainerMPic
- money 3500
-
- dw CooltrainerFPic
- money 3500
-
- dw BrunoPic
- money 9900
-
- dw BrockPic
- money 9900
-
- dw MistyPic
- money 9900
-
- dw LtSurgePic
- money 9900
-
- dw ErikaPic
- money 9900
-
- dw KogaPic
- money 9900
-
- dw BlainePic
- money 9900
-
- dw SabrinaPic
- money 9900
-
- dw GentlemanPic
- money 7000
-
- dw Rival2Pic
- money 6500
-
- dw Rival3Pic
- money 9900
-
- dw LoreleiPic
- money 9900
-
- dw ChannelerPic
- money 3000
-
- dw AgathaPic
- money 9900
-
- dw LancePic
- money 9900
-
-INCLUDE "text/trainer_names.asm"
-
-; formats a string at wMovesString that lists the moves at wMoves
-FormatMovesString: ; 39b87 (e:5b87)
- ld hl, wMoves
- ld de, wMovesString
- ld b, $0
-.printMoveNameLoop
- ld a, [hli]
- and a ; end of move list?
- jr z, .printDashLoop ; print dashes when no moves are left
- push hl
- ld [wd0b5], a
- ld a, BANK(MoveNames)
- ld [wPredefBank], a
- ld a, MOVE_NAME
- ld [wNameListType], a
- call GetName
- ld hl, wcd6d
-.copyNameLoop
- ld a, [hli]
- cp $50
- jr z, .doneCopyingName
- ld [de], a
- inc de
- jr .copyNameLoop
-.doneCopyingName
- ld a, b
- ld [wcd6c], a
- inc b
- ld a, $4e ; line break
- ld [de], a
- inc de
- pop hl
- ld a, b
- cp NUM_MOVES
- jr z, .done
- jr .printMoveNameLoop
-.printDashLoop
- ld a, "-"
- ld [de], a
- inc de
- inc b
- ld a, b
- cp NUM_MOVES
- jr z, .done
- ld a, $4e ; line break
- ld [de], a
- inc de
- jr .printDashLoop
-.done
- ld a, "@"
- ld [de], a
- ret
-
-; XXX this is called in a few places, but it doesn't appear to do anything useful
-Func_39bd5: ; 39bd5 (e:5bd5)
- ld a, [wd11b]
- cp $1
- jr nz, .asm_39be6
- ld hl, wEnemyPartyCount
- ld de, wEnemyMonOT
- ld a, ENEMYOT_NAME
- jr .asm_39c18
-.asm_39be6
- cp $4
- jr nz, .calcAttackStat4
- ld hl, wPartyCount
- ld de, wPartyMonOT
- ld a, PLAYEROT_NAME
- jr .asm_39c18
-.calcAttackStat4
- cp $5
- jr nz, .asm_39c02
- ld hl, wStringBuffer2 + 11
- ld de, MonsterNames
- ld a, MONSTER_NAME
- jr .asm_39c18
-.asm_39c02
- cp $2
- jr nz, .asm_39c10
- ld hl, wNumBagItems
- ld de, ItemNames
- ld a, ITEM_NAME
- jr .asm_39c18
-.asm_39c10
- ld hl, wStringBuffer2 + 11
- ld de, ItemNames
- ld a, ITEM_NAME
-.asm_39c18
- ld [wNameListType], a
- ld a, l
- ld [wList], a
- ld a, h
- ld [wList + 1], a
- ld a, e
- ld [wcf8d], a
- ld a, d
- ld [wcf8e], a
- ld bc, ItemPrices
- ld a, c
- ld [wItemPrices], a
- ld a, b
- ld [wItemPrices + 1], a
- ret
-
-; get species of mon e in list [wcc49] for LoadMonData
-GetMonSpecies: ; 39c37 (e:5c37)
- ld hl, wPartySpecies
- ld a, [wcc49]
- and a
- jr z, .getSpecies
- dec a
- jr z, .enemyParty
- ld hl, wBoxSpecies
- jr .getSpecies
-.enemyParty
- ld hl, wEnemyPartyMons
-.getSpecies
- ld d, 0
- add hl, de
- ld a, [hl]
- ld [wcf91], a
- ret
-
-ReadTrainer: ; 39c53 (e:5c53)
-
-; don't change any moves in a link battle
- ld a,[wLinkState]
- and a
- ret nz
-
-; set [wEnemyPartyCount] to 0, [wEnemyPartyMons] to FF
-; XXX first is total enemy pokemon?
-; XXX second is species of first pokemon?
- ld hl,wEnemyPartyCount
- xor a
- ld [hli],a
- dec a
- ld [hl],a
-
-; get the pointer to trainer data for this class
- ld a,[W_CUROPPONENT]
- sub $C9 ; convert value from pokemon to trainer
- add a,a
- ld hl,TrainerDataPointers
- ld c,a
- ld b,0
- add hl,bc ; hl points to trainer class
- ld a,[hli]
- ld h,[hl]
- ld l,a
- ld a,[W_TRAINERNO]
- ld b,a
-; At this point b contains the trainer number,
-; and hl points to the trainer class.
-; Our next task is to iterate through the trainers,
-; decrementing b each time, until we get to the right one.
-.outer
- dec b
- jr z,.IterateTrainer
-.inner
- ld a,[hli]
- and a
- jr nz,.inner
- jr .outer
-
-; if the first byte of trainer data is FF,
-; - each pokemon has a specific level
-; (as opposed to the whole team being of the same level)
-; - if [W_LONEATTACKNO] != 0, one pokemon on the team has a special move
-; else the first byte is the level of every pokemon on the team
-.IterateTrainer
- ld a,[hli]
- cp $FF ; is the trainer special?
- jr z,.SpecialTrainer ; if so, check for special moves
- ld [W_CURENEMYLVL],a
-.LoopTrainerData
- ld a,[hli]
- and a ; have we reached the end of the trainer data?
- jr z,.FinishUp
- ld [wcf91],a ; write species somewhere (XXX why?)
- ld a,1
- ld [wcc49],a
- push hl
- call AddPartyMon
- pop hl
- jr .LoopTrainerData
-.SpecialTrainer
-; if this code is being run:
-; - each pokemon has a specific level
-; (as opposed to the whole team being of the same level)
-; - if [W_LONEATTACKNO] != 0, one pokemon on the team has a special move
- ld a,[hli]
- and a ; have we reached the end of the trainer data?
- jr z,.AddLoneMove
- ld [W_CURENEMYLVL],a
- ld a,[hli]
- ld [wcf91],a
- ld a,1
- ld [wcc49],a
- push hl
- call AddPartyMon
- pop hl
- jr .SpecialTrainer
-.AddLoneMove
-; does the trainer have a single monster with a different move
- ld a,[W_LONEATTACKNO] ; Brock is 01, Misty is 02, Erika is 04, etc
- and a
- jr z,.AddTeamMove
- dec a
- add a,a
- ld c,a
- ld b,0
- ld hl,LoneMoves
- add hl,bc
- ld a,[hli]
- ld d,[hl]
- ld hl,wEnemyMon1Moves + 2
- ld bc,wEnemyMon2 - wEnemyMon1
- call AddNTimes
- ld [hl],d
- jr .FinishUp
-.AddTeamMove
-; check if our trainer's team has special moves
-
-; get trainer class number
- ld a,[W_CUROPPONENT]
- sub $C8
- ld b,a
- ld hl,TeamMoves
-
-; iterate through entries in TeamMoves, checking each for our trainer class
-.IterateTeamMoves
- ld a,[hli]
- cp b
- jr z,.GiveTeamMoves ; is there a match?
- inc hl ; if not, go to the next entry
- inc a
- jr nz,.IterateTeamMoves
-
- ; no matches found. is this trainer champion rival?
- ld a,b
- cp SONY3
- jr z,.ChampionRival
- jr .FinishUp ; nope
-.GiveTeamMoves
- ld a,[hl]
- ld [wEnemyMon5Moves + 2],a
- jr .FinishUp
-.ChampionRival ; give moves to his team
-
-; pidgeot
- ld a,SKY_ATTACK
- ld [wEnemyMon1Moves + 2],a
-
-; starter
- ld a,[W_RIVALSTARTER]
- cp STARTER3
- ld b,MEGA_DRAIN
- jr z,.GiveStarterMove
- cp STARTER1
- ld b,FIRE_BLAST
- jr z,.GiveStarterMove
- ld b,BLIZZARD ; must be squirtle
-.GiveStarterMove
- ld a,b
- ld [wEnemyMon6Moves + 2],a
-.FinishUp ; XXX this needs documenting
- xor a ; clear D079-D07B
- ld de,wd079
- ld [de],a
- inc de
- ld [de],a
- inc de
- ld [de],a
- ld a,[W_CURENEMYLVL]
- ld b,a
-.LastLoop
- ld hl,wd047
- ld c,2
- push bc
- predef AddBCDPredef
- pop bc
- inc de
- inc de
- dec b
- jr nz,.LastLoop
- ret
-
-INCLUDE "data/trainer_moves.asm"
-
-INCLUDE "data/trainer_parties.asm"
-
-TrainerAI: ; 3a52e (e:652e)
-;XXX called at 34964, 3c342, 3c398
- and a
- ld a,[W_ISINBATTLE]
- dec a
- ret z ; if not a trainer, we're done here
- ld a,[wLinkState]
- cp LINK_STATE_BATTLING
- ret z
- ld a,[W_TRAINERCLASS] ; what trainer class is this?
- dec a
- ld c,a
- ld b,0
- ld hl,TrainerAIPointers
- add hl,bc
- add hl,bc
- add hl,bc
- ld a,[wAICount]
- and a
- ret z ; if no AI uses left, we're done here
- inc hl
- inc a
- jr nz,.getpointer
- dec hl
- ld a,[hli]
- ld [wAICount],a
-.getpointer
- ld a,[hli]
- ld h,[hl]
- ld l,a
- call Random
- jp [hl]
-
-TrainerAIPointers: ; 3a55c (e:655c)
-; one entry per trainer class
-; first byte, number of times (per Pokémon) it can occur
-; next two bytes, pointer to AI subroutine for trainer class
- dbw 3,GenericAI
- dbw 3,GenericAI
- dbw 3,GenericAI
- dbw 3,GenericAI
- dbw 3,GenericAI
- dbw 3,GenericAI
- dbw 3,GenericAI
- dbw 3,GenericAI
- dbw 3,GenericAI
- dbw 3,GenericAI
- dbw 3,GenericAI
- dbw 3,GenericAI
- dbw 3,JugglerAI ; juggler_x
- dbw 3,GenericAI
- dbw 3,GenericAI
- dbw 3,GenericAI
- dbw 3,GenericAI
- dbw 3,GenericAI
- dbw 3,GenericAI
- dbw 3,GenericAI
- dbw 3,JugglerAI ; juggler
- dbw 3,GenericAI
- dbw 3,GenericAI
- dbw 2,BlackbeltAI ; blackbelt
- dbw 3,GenericAI
- dbw 3,GenericAI
- dbw 1,GenericAI ; chief
- dbw 3,GenericAI
- dbw 1,GiovanniAI ; giovanni
- dbw 3,GenericAI
- dbw 2,CooltrainerMAI ; cooltrainerm
- dbw 1,CooltrainerFAI ; cooltrainerf
- dbw 2,BrunoAI ; bruno
- dbw 5,BrockAI ; brock
- dbw 1,MistyAI ; misty
- dbw 1,LtSurgeAI ; surge
- dbw 1,ErikaAI ; erika
- dbw 2,KogaAI ; koga
- dbw 2,BlaineAI ; blaine
- dbw 1,SabrinaAI ; sabrina
- dbw 3,GenericAI
- dbw 1,Sony2AI ; sony2
- dbw 1,Sony3AI ; sony3
- dbw 2,LoreleiAI ; lorelei
- dbw 3,GenericAI
- dbw 2,AgathaAI ; agatha
- dbw 1,LanceAI ; lance
-
-JugglerAI: ; 3a5e9 (e:65e9)
- cp $40
- ret nc
- jp AISwitchIfEnoughMons
-
-BlackbeltAI: ; 3a5ef (e:65ef)
- cp $20
- ret nc
- jp AIUseXAttack
-
-GiovanniAI: ; 3a5f5 (e:65f5)
- cp $40
- ret nc
- jp AIUseGuardSpec
-
-CooltrainerMAI: ; 3a5fb (e:65fb)
- cp $40
- ret nc
- jp AIUseXAttack
-
-CooltrainerFAI: ; 3a601 (e:6601)
- cp $40
- ld a,$A
- call AICheckIfHPBelowFraction
- jp c,AIUseHyperPotion
- ld a,5
- call AICheckIfHPBelowFraction
- ret nc
- jp AISwitchIfEnoughMons
-
-BrockAI: ; 3a614 (e:6614)
-; if his active monster has a status condition, use a full heal
- ld a,[wEnemyMonStatus]
- and a
- ret z
- jp AIUseFullHeal
-
-MistyAI: ; 3a61c (e:661c)
- cp $40
- ret nc
- jp AIUseXDefend
-
-LtSurgeAI: ; 3a622 (e:6622)
- cp $40
- ret nc
- jp AIUseXSpeed
-
-ErikaAI: ; 3a628 (e:6628)
- cp $80
- ret nc
- ld a,$A
- call AICheckIfHPBelowFraction
- ret nc
- jp AIUseSuperPotion
-
-KogaAI: ; 3a634 (e:6634)
- cp $40
- ret nc
- jp AIUseXAttack
-
-BlaineAI: ; 3a63a (e:663a)
- cp $40
- ret nc
- jp AIUseSuperPotion
-
-SabrinaAI: ; 3a640 (e:6640)
- cp $40
- ret nc
- ld a,$A
- call AICheckIfHPBelowFraction
- ret nc
- jp AIUseHyperPotion
-
-Sony2AI: ; 3a64c (e:664c)
- cp $20
- ret nc
- ld a,5
- call AICheckIfHPBelowFraction
- ret nc
- jp AIUsePotion
-
-Sony3AI: ; 3a658 (e:6658)
- cp $20
- ret nc
- ld a,5
- call AICheckIfHPBelowFraction
- ret nc
- jp AIUseFullRestore
-
-LoreleiAI: ; 3a664 (e:6664)
- cp $80
- ret nc
- ld a,5
- call AICheckIfHPBelowFraction
- ret nc
- jp AIUseSuperPotion
-
-BrunoAI: ; 3a670 (e:6670)
- cp $40
- ret nc
- jp AIUseXDefend
-
-AgathaAI: ; 3a676 (e:6676)
- cp $14
- jp c,AISwitchIfEnoughMons
- cp $80
- ret nc
- ld a,4
- call AICheckIfHPBelowFraction
- ret nc
- jp AIUseSuperPotion
-
-LanceAI: ; 3a687 (e:6687)
- cp $80
- ret nc
- ld a,5
- call AICheckIfHPBelowFraction
- ret nc
- jp AIUseHyperPotion
-
-GenericAI: ; 3a693 (e:6693)
- and a ; clear carry
- ret
-
-; end of individual trainer AI routines
-
-DecrementAICount: ; 3a695 (e:6695)
- ld hl,wAICount
- dec [hl]
- scf
- ret
-
-Func_3a69b: ; 3a69b (e:669b)
- ld a,(SFX_08_3e - SFX_Headers_08) / 3
- jp PlaySoundWaitForCurrent
-
-AIUseFullRestore: ; 3a6a0 (e:66a0)
- call AICureStatus
- ld a,FULL_RESTORE
- ld [wcf05],a
- ld de,wHPBarOldHP
- 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 [wHPBarMaxHP],a
- ld [wEnemyMonHP + 1],a
- ld a,[hl]
- ld [de],a
- ld [wHPBarMaxHP+1],a
- ld [wEnemyMonHP],a
- jr AIPrintItemUseAndUpdateHPBar
-
-AIUsePotion: ; 3a6ca (e:66ca)
-; enemy trainer heals his monster with a potion
- ld a,POTION
- ld b,20
- jr AIRecoverHP
-
-AIUseSuperPotion: ; 3a6d0 (e:66d0)
-; enemy trainer heals his monster with a super potion
- ld a,SUPER_POTION
- ld b,50
- jr AIRecoverHP
-
-AIUseHyperPotion: ; 3a6d6 (e:66d6)
-; enemy trainer heals his monster with a hyper potion
- ld a,HYPER_POTION
- ld b,200
- ; fallthrough
-
-AIRecoverHP: ; 3a6da (e:66da)
-; heal b HP and print "trainer used $(a) on pokemon!"
- ld [wcf05],a
- ld hl,wEnemyMonHP + 1
- ld a,[hl]
- ld [wHPBarOldHP],a
- add b
- ld [hld],a
- ld [wHPBarNewHP],a
- ld a,[hl]
- ld [wHPBarOldHP+1],a
- ld [wHPBarNewHP+1],a
- jr nc,.next
- inc a
- ld [hl],a
- ld [wHPBarNewHP+1],a
-.next
- inc hl
- ld a,[hld]
- ld b,a
- ld de,wEnemyMonMaxHP + 1
- ld a,[de]
- dec de
- ld [wHPBarMaxHP],a
- sub b
- ld a,[hli]
- ld b,a
- ld a,[de]
- ld [wHPBarMaxHP+1],a
- sbc b
- jr nc,AIPrintItemUseAndUpdateHPBar
- inc de
- ld a,[de]
- dec de
- ld [hld],a
- ld [wHPBarNewHP],a
- ld a,[de]
- ld [hl],a
- ld [wHPBarNewHP+1],a
- ; fallthrough
-
-AIPrintItemUseAndUpdateHPBar: ; 3a718 (e:6718)
- call AIPrintItemUse_
- hlCoord 2, 2
- xor a
- ld [wHPBarType],a
- predef UpdateHPBar2
- jp DecrementAICount
-
-AISwitchIfEnoughMons: ; 3a72a (e:672a)
-; enemy trainer switches if there are 3 or more unfainted mons in party
- ld a,[wEnemyPartyCount]
- ld c,a
- ld hl,wEnemyMon1HP
-
- ld d,0 ; keep count of unfainted monsters
-
- ; count how many monsters haven't fainted yet
-.loop
- ld a,[hli]
- ld b,a
- ld a,[hld]
- or b
- jr z,.Fainted ; has monster fainted?
- inc d
-.Fainted
- push bc
- ld bc,$2C
- add hl,bc
- pop bc
- dec c
- jr nz,.loop
-
- ld a,d ; how many available monsters are there?
- cp 2 ; don't bother if only 1 or 2
- jp nc,SwitchEnemyMon
- and a
- ret
-
-SwitchEnemyMon: ; 3a74b (e:674b)
-
-; prepare to withdraw the active monster: copy hp, number, and status to roster
-
- ld a,[wEnemyMonPartyPos]
- ld hl,wEnemyMon1HP
- ld bc,wEnemyMon2 - wEnemyMon1
- call AddNTimes
- ld d,h
- ld e,l
- ld hl,wEnemyMonHP
- ld bc,4
- call CopyData
-
- ld hl, AIBattleWithdrawText
- call PrintText
-
- ld a,1
- ld [wd11d],a
- callab EnemySendOut
- xor a
- ld [wd11d],a
-
- ld a,[wLinkState]
- cp LINK_STATE_BATTLING
- ret z
- scf
- ret
-
-AIBattleWithdrawText: ; 3a781 (e:6781)
- TX_FAR _AIBattleWithdrawText
- db "@"
-
-AIUseFullHeal: ; 3a786 (e:6786)
- call Func_3a69b
- call AICureStatus
- ld a,FULL_HEAL
- jp AIPrintItemUse
-
-AICureStatus: ; 3a791 (e:6791)
-; cures the status of enemy's active pokemon
- ld a,[wEnemyMonPartyPos]
- ld hl,wEnemyMon1Status
- ld bc,wEnemyMon2 - wEnemyMon1
- call AddNTimes
- xor a
- ld [hl],a ; clear status in enemy team roster
- ld [wEnemyMonStatus],a ; clear status of active enemy
- ld hl,W_ENEMYBATTSTATUS3
- res 0,[hl]
- ret
-
-AIUseXAccuracy: ; 0x3a7a8 unused
- call Func_3a69b
- ld hl,W_ENEMYBATTSTATUS2
- set 0,[hl]
- ld a,X_ACCURACY
- jp AIPrintItemUse
-
-AIUseGuardSpec: ; 3a7b5 (e:67b5)
- call Func_3a69b
- ld hl,W_ENEMYBATTSTATUS2
- set 1,[hl]
- ld a,GUARD_SPEC_
- jp AIPrintItemUse
-
-AIUseDireHit: ; 0x3a7c2 unused
- call Func_3a69b
- ld hl,W_ENEMYBATTSTATUS2
- set 2,[hl]
- ld a,DIRE_HIT
- jp AIPrintItemUse
-
-AICheckIfHPBelowFraction: ; 3a7cf (e:67cf)
-; return carry if enemy trainer's current HP is below 1 / a of the maximum
- ld [H_DIVISOR],a
- ld hl,wEnemyMonMaxHP
- ld a,[hli]
- ld [H_DIVIDEND],a
- ld a,[hl]
- ld [H_DIVIDEND + 1],a
- ld b,2
- call Divide
- ld a,[H_QUOTIENT + 3]
- ld c,a
- ld a,[H_QUOTIENT + 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
-
-AIUseXAttack: ; 3a7f2 (e:67f2)
- ld b,$A
- ld a,X_ATTACK
- jr AIIncreaseStat
-
-AIUseXDefend: ; 3a7f8 (e:67f8)
- ld b,$B
- ld a,X_DEFEND
- jr AIIncreaseStat
-
-AIUseXSpeed: ; 3a7fe (e:67fe)
- ld b,$C
- ld a,X_SPEED
- jr AIIncreaseStat
-
-AIUseXSpecial: ; 3a804 (e:6804)
- ld b,$D
- ld a,X_SPECIAL
- ; fallthrough
-
-AIIncreaseStat: ; 3a808 (e:6808)
- ld [wcf05],a
- push bc
- call AIPrintItemUse_
- pop bc
- ld hl,W_ENEMYMOVEEFFECT
- ld a,[hld]
- push af
- ld a,[hl]
- push af
- push hl
- ld a,$AF
- ld [hli],a
- ld [hl],b
- callab StatModifierUpEffect
- pop hl
- pop af
- ld [hli],a
- pop af
- ld [hl],a
- jp DecrementAICount
-
-AIPrintItemUse: ; 3a82c (e:682c)
- ld [wcf05],a
- call AIPrintItemUse_
- jp DecrementAICount
-
-AIPrintItemUse_: ; 3a835 (e:6835)
-; print "x used [wcf05] on z!"
- ld a,[wcf05]
- ld [wd11e],a
- call GetItemName
- ld hl, AIBattleUseItemText
- jp PrintText
-
-AIBattleUseItemText: ; 3a844 (e:6844)
- TX_FAR _AIBattleUseItemText
- db "@"
--- /dev/null
+++ b/engine/battle/trainer_pic_money_pointers.asm
@@ -1,0 +1,143 @@
+TrainerPicAndMoneyPointers: ; 39914 (e:5914)
+; trainer pic pointers and base money.
+; money received after battle = base money × level of highest-level enemy mon
+ dw YoungsterPic
+ money 1500
+
+ dw BugCatcherPic
+ money 1000
+
+ dw LassPic
+ money 1500
+
+ dw SailorPic
+ money 3000
+
+ dw JrTrainerMPic
+ money 2000
+
+ dw JrTrainerFPic
+ money 2000
+
+ dw PokemaniacPic
+ money 5000
+
+ dw SuperNerdPic
+ money 2500
+
+ dw HikerPic
+ money 3500
+
+ dw BikerPic
+ money 2000
+
+ dw BurglarPic
+ money 9000
+
+ dw EngineerPic
+ money 5000
+
+ dw JugglerPic
+ money 3500
+
+ dw FisherPic
+ money 3500
+
+ dw SwimmerPic
+ money 500
+
+ dw CueBallPic
+ money 2500
+
+ dw GamblerPic
+ money 7000
+
+ dw BeautyPic
+ money 7000
+
+ dw PsychicPic
+ money 1000
+
+ dw RockerPic
+ money 2500
+
+ dw JugglerPic
+ money 3500
+
+ dw TamerPic
+ money 4000
+
+ dw BirdKeeperPic
+ money 2500
+
+ dw BlackbeltPic
+ money 2500
+
+ dw Rival1Pic
+ money 3500
+
+ dw ProfOakPic
+ money 9900
+
+ dw ChiefPic
+ money 3000
+
+ dw ScientistPic
+ money 5000
+
+ dw GiovanniPic
+ money 9900
+
+ dw RocketPic
+ money 3000
+
+ dw CooltrainerMPic
+ money 3500
+
+ dw CooltrainerFPic
+ money 3500
+
+ dw BrunoPic
+ money 9900
+
+ dw BrockPic
+ money 9900
+
+ dw MistyPic
+ money 9900
+
+ dw LtSurgePic
+ money 9900
+
+ dw ErikaPic
+ money 9900
+
+ dw KogaPic
+ money 9900
+
+ dw BlainePic
+ money 9900
+
+ dw SabrinaPic
+ money 9900
+
+ dw GentlemanPic
+ money 7000
+
+ dw Rival2Pic
+ money 6500
+
+ dw Rival3Pic
+ money 9900
+
+ dw LoreleiPic
+ money 9900
+
+ dw ChannelerPic
+ money 3000
+
+ dw AgathaPic
+ money 9900
+
+ dw LancePic
+ money 9900
\ No newline at end of file
--- a/main.asm
+++ b/main.asm
@@ -5465,7 +5465,7 @@
INCLUDE "data/cries.asm"
INCLUDE "engine/battle/unused_stats_functions.asm"
INCLUDE "engine/battle/scroll_draw_trainer_pic.asm"
-INCLUDE "engine/battle/trainer_party_ai_misc.asm"
+INCLUDE "engine/battle/trainer_ai.asm"
INCLUDE "engine/battle/draw_hud_pokeball_gfx.asm"
TradingAnimationGraphics: