ref: 2fe782b11a039b52fd236da28fb2f1ae10cae7db
parent: 77d0e5ff84cc61ae625da19f184094241eddd4dc
author: xCrystal <rgr.crystal@gmail.com>
date: Wed Apr 1 12:51:04 EDT 2015
Rename battle files and split move effects Part 4 e.asm, e_2. asm, and 14.asm
--- a/engine/battle/14.asm
+++ /dev/null
@@ -1,94 +1,0 @@
-InitBattleVariables: ; 525af (14:65af)
- ld a, [hTilesetType]
- ld [wd0d4], a
- xor a
- ld [wcd6a], a
- ld [wBattleResult], a
- ld hl, wcc2b
- ld [hli], a
- ld [hli], a
- ld [hli], a
- ld [hl], a
- ld [wListScrollOffset], a
- ld [wCriticalHitOrOHKO], a
- ld [wBattleMonSpecies], a
- ld [wPartyGainExpFlags], a
- ld [wPlayerMonNumber], a
- ld [wEscapedFromBattle], a
- ld [wMapPalOffset], a
- ld hl, wcf1d
- ld [hli], a
- ld [hl], a
- ld hl, wccd3
- ld b, $3c
-.loop
- ld [hli], a
- dec b
- jr nz, .loop
- inc a
- ld [wccd9], a
- ld a, [W_CURMAP]
- cp SAFARI_ZONE_EAST
- jr c, .notSafariBattle
- cp SAFARI_ZONE_REST_HOUSE_1
- jr nc, .notSafariBattle
- ld a, $2 ; safari battle
- ld [W_BATTLETYPE], a
-.notSafariBattle
- ld hl, PlayBattleMusic
- ld b, BANK(PlayBattleMusic)
- jp Bankswitch
-
-ParalyzeEffect_: ; 52601 (14:6601)
- ld hl, wEnemyMonStatus
- ld de, W_PLAYERMOVETYPE
- ld a, [H_WHOSETURN]
- and a
- jp z, .next
- ld hl, wBattleMonStatus
- ld de, W_ENEMYMOVETYPE
-.next
- ld a, [hl]
- and a ; does the target already have a status ailment?
- jr nz, .didntAffect
-; check if the target is immune due to types
- ld a, [de]
- cp ELECTRIC
- jr nz, .hitTest
- ld b, h
- ld c, l
- inc bc
- ld a, [bc]
- cp GROUND
- jr z, .doesntAffect
- inc bc
- ld a, [bc]
- cp GROUND
- jr z, .doesntAffect
-.hitTest
- push hl
- callab MoveHitTest
- pop hl
- ld a, [W_MOVEMISSED]
- and a
- jr nz, .didntAffect
- set PAR, [hl]
- callab QuarterSpeedDueToParalysis
- ld c, 30
- call DelayFrames
- callab PlayCurrentMoveAnimation
- ld hl, PrintMayNotAttackText
- ld b, BANK(PrintMayNotAttackText)
- jp Bankswitch
-.didntAffect
- ld c, 50
- call DelayFrames
- ld hl, PrintDidntAffectText
- ld b, BANK(PrintDidntAffectText)
- jp Bankswitch
-.doesntAffect
- ld c, 50
- call DelayFrames
- ld hl, PrintDoesntAffectText
- ld b, BANK(PrintDoesntAffectText)
- jp Bankswitch
--- /dev/null
+++ b/engine/battle/draw_hud_pokeball_gfx.asm
@@ -1,0 +1,191 @@
+DrawAllPokeballs: ; 3a849 (e:6849)
+ call LoadPartyPokeballGfx
+ call SetupOwnPartyPokeballs
+ ld a, [W_ISINBATTLE] ; W_ISINBATTLE
+ dec a
+ ret z ; return if wild pokémon
+ jp SetupEnemyPartyPokeballs
+
+DrawEnemyPokeballs: ; 0x3a857
+ call LoadPartyPokeballGfx
+ jp SetupEnemyPartyPokeballs
+
+LoadPartyPokeballGfx: ; 3a85d (e:685d)
+ ld de, PokeballTileGraphics ; $697e
+ ld hl, vSprites + $310
+ ld bc, (BANK(PokeballTileGraphics) << 8) + $04
+ jp CopyVideoData
+
+SetupOwnPartyPokeballs: ; 3a869 (e:6869)
+ call PlacePlayerHUDTiles
+ ld hl, wPartyMon1
+ ld de, wPartyCount ; wPartyCount
+ call SetupPokeballs
+ ld a, $60
+ ld hl, W_BASECOORDX ; wd081
+ ld [hli], a
+ ld [hl], a
+ ld a, $8
+ ld [wTrainerEngageDistance], a
+ ld hl, wOAMBuffer
+ jp WritePokeballOAMData
+
+SetupEnemyPartyPokeballs: ; 3a887 (e:6887)
+ call PlaceEnemyHUDTiles
+ ld hl, wEnemyMons
+ ld de, wEnemyPartyCount ; wEnemyPartyCount
+ call SetupPokeballs
+ ld hl, W_BASECOORDX ; wd081
+ ld a, $48
+ ld [hli], a
+ ld [hl], $20
+ ld a, $f8
+ ld [wTrainerEngageDistance], a
+ ld hl, wOAMBuffer + PARTY_LENGTH * 4
+ jp WritePokeballOAMData
+
+SetupPokeballs: ; 0x3a8a6
+ ld a, [de]
+ push af
+ ld de, wBuffer
+ ld c, PARTY_LENGTH
+ ld a, $34 ; empty pokeball
+.emptyloop
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .emptyloop
+ pop af
+ ld de, wBuffer
+.monloop
+ push af
+ call PickPokeball
+ inc de
+ pop af
+ dec a
+ jr nz, .monloop
+ ret
+
+PickPokeball: ; 3a8c2 (e:68c2)
+ inc hl
+ ld a, [hli]
+ and a
+ jr nz, .alive
+ ld a, [hl]
+ and a
+ ld b, $33 ; crossed ball (fainted)
+ jr z, .done_fainted
+.alive
+ inc hl
+ inc hl
+ ld a, [hl] ; status
+ and a
+ ld b, $32 ; black ball (status)
+ jr nz, .done
+ dec b ; regular ball
+ jr .done
+.done_fainted
+ inc hl
+ inc hl
+.done
+ ld a, b
+ ld [de], a
+ ld bc, $0028 ; rest of mon struct
+ add hl, bc
+ ret
+
+WritePokeballOAMData: ; 3a8e1 (e:68e1)
+ ld de, wBuffer
+ ld c, PARTY_LENGTH
+.loop
+ ld a, [W_BASECOORDY] ; wd082
+ ld [hli], a
+ ld a, [W_BASECOORDX] ; wd081
+ ld [hli], a
+ ld a, [de]
+ ld [hli], a
+ xor a
+ ld [hli], a
+ ld a, [W_BASECOORDX] ; wd081
+ ld b, a
+ ld a, [wTrainerEngageDistance]
+ add b
+ ld [W_BASECOORDX], a ; wd081
+ inc de
+ dec c
+ jr nz, .loop
+ ret
+
+PlacePlayerHUDTiles: ; 3a902 (e:6902)
+ ld hl, PlayerBattleHUDGraphicsTiles ; $6916
+ ld de, wTrainerFacingDirection
+ ld bc, $3
+ call CopyData
+ hlCoord 18, 10
+ ld de, rIE ; $ffff
+ jr PlaceHUDTiles
+
+PlayerBattleHUDGraphicsTiles: ; 3a916 (e:6916)
+; The tile numbers for specific parts of the battle display for the player's pokemon
+ db $73 ; unused ($73 is hardcoded into the routine that uses these bytes)
+ db $77 ; lower-right corner tile of the HUD
+ db $6F ; lower-left triangle tile of the HUD
+
+PlaceEnemyHUDTiles: ; 3a919 (e:6919)
+ ld hl, EnemyBattleHUDGraphicsTiles ; $692d
+ ld de, wTrainerFacingDirection
+ ld bc, $3
+ call CopyData
+ hlCoord 1, 2
+ ld de, $1
+ jr PlaceHUDTiles
+
+EnemyBattleHUDGraphicsTiles: ; 3a92d (e:692d)
+; The tile numbers for specific parts of the battle display for the enemy
+ db $73 ; unused ($73 is hardcoded in the routine that uses these bytes)
+ db $74 ; lower-left corner tile of the HUD
+ db $78 ; lower-right triangle tile of the HUD
+
+PlaceHUDTiles: ; 3a930 (e:6930)
+ ld [hl], $73
+ ld bc, $14
+ add hl, bc
+ ld a, [wTrainerScreenY]
+ ld [hl], a
+ ld a, $8
+.asm_3a93c
+ add hl, de
+ ld [hl], $76
+ dec a
+ jr nz, .asm_3a93c
+ add hl, de
+ ld a, [wTrainerScreenX]
+ ld [hl], a
+ ret
+
+SetupPlayerAndEnemyPokeballs: ; 3a948 (e:6948)
+ call LoadPartyPokeballGfx
+ ld hl, wPartyMon1Species ; wPartyMon1Species (aliases: wPartyMon1)
+ ld de, wPartyCount ; wPartyCount
+ call SetupPokeballs
+ ld hl, W_BASECOORDX ; wd081
+ ld a, $50
+ ld [hli], a
+ ld [hl], $40
+ ld a, $8
+ ld [wTrainerEngageDistance], a
+ ld hl, wOAMBuffer
+ call WritePokeballOAMData
+ ld hl, wEnemyMons ; wEnemyMon1Species
+ ld de, wEnemyPartyCount ; wEnemyPartyCount
+ call SetupPokeballs
+ ld hl, W_BASECOORDX ; wd081
+ ld a, $50
+ ld [hli], a
+ ld [hl], $68
+ ld hl, wOAMBuffer + $18
+ jp WritePokeballOAMData
+
+; four tiles: pokeball, black pokeball (status ailment), crossed out pokeball (faited) and pokeball slot (no mon)
+PokeballTileGraphics:: ; 3a97e (e:697e)
+ INCBIN "gfx/pokeball.2bpp"
--- a/engine/battle/e.asm
+++ /dev/null
@@ -1,1569 +1,0 @@
-; does nothing since no stats are ever selected (barring glitches)
-DoubleSelectedStats: ; 39680 (e:5680)
- ld a, [H_WHOSETURN]
- 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: ; 396a7 (e:56a7)
- ld a, [H_WHOSETURN]
- and a
- ld a, [wPlayerStatsToHalve]
- ld hl, wBattleMonAttack
- jr z, .notEnemyTurn
- ld a, [wEnemyStatsToHalve]
- ld hl, wEnemyMonAttack
-.notEnemyTurn
- ld c, 4
- ld b, a
-.loop
- srl b
- call c, .halveStat
- inc hl
- inc hl
- dec c
- ret z
- jr .loop
-
-.halveStat
- ld a, [hl]
- srl a
- ld [hli], a
- rr [hl]
- or [hl]
- jr nz, .nonzeroStat
- ld [hl], 1
-.nonzeroStat
- dec hl
- ret
-
-_ScrollTrainerPicAfterBattle: ; 396d3 (e:56d3)
-; Load the enemy trainer's pic and scrolls it into
-; the screen from the right.
- xor a
- ld [wEnemyMonSpecies2], a
- ld b, $1
- call GoPAL_SET
- callab _LoadTrainerPic
- hlCoord 19, 0
- ld c, $0
-.scrollLoop
- inc c
- ld a, c
- cp 7
- ret z
- ld d, $0
- push bc
- push hl
-.drawTrainerPicLoop
- call DrawTrainerPicColumn
- inc hl
- ld a, 7
- add d
- ld d, a
- dec c
- jr nz, .drawTrainerPicLoop
- ld c, 4
- call DelayFrames
- pop hl
- pop bc
- dec hl
- jr .scrollLoop
-
-; write one 7-tile column of the trainer pic to the tilemap
-DrawTrainerPicColumn: ; 39707 (e:5707)
- push hl
- push de
- push bc
- ld e, 7
-.loop
- ld [hl], d
- ld bc, SCREEN_WIDTH
- add hl, bc
- inc d
- dec e
- jr nz, .loop
- pop bc
- pop de
- pop hl
- ret
-
-; 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 "@"
-
-DrawAllPokeballs: ; 3a849 (e:6849)
- call LoadPartyPokeballGfx
- call SetupOwnPartyPokeballs
- ld a, [W_ISINBATTLE] ; W_ISINBATTLE
- dec a
- ret z ; return if wild pokémon
- jp SetupEnemyPartyPokeballs
-
-DrawEnemyPokeballs: ; 0x3a857
- call LoadPartyPokeballGfx
- jp SetupEnemyPartyPokeballs
-
-LoadPartyPokeballGfx: ; 3a85d (e:685d)
- ld de, PokeballTileGraphics ; $697e
- ld hl, vSprites + $310
- ld bc, (BANK(PokeballTileGraphics) << 8) + $04
- jp CopyVideoData
-
-SetupOwnPartyPokeballs: ; 3a869 (e:6869)
- call PlacePlayerHUDTiles
- ld hl, wPartyMon1
- ld de, wPartyCount ; wPartyCount
- call SetupPokeballs
- ld a, $60
- ld hl, W_BASECOORDX ; wd081
- ld [hli], a
- ld [hl], a
- ld a, $8
- ld [wTrainerEngageDistance], a
- ld hl, wOAMBuffer
- jp WritePokeballOAMData
-
-SetupEnemyPartyPokeballs: ; 3a887 (e:6887)
- call PlaceEnemyHUDTiles
- ld hl, wEnemyMons
- ld de, wEnemyPartyCount ; wEnemyPartyCount
- call SetupPokeballs
- ld hl, W_BASECOORDX ; wd081
- ld a, $48
- ld [hli], a
- ld [hl], $20
- ld a, $f8
- ld [wTrainerEngageDistance], a
- ld hl, wOAMBuffer + PARTY_LENGTH * 4
- jp WritePokeballOAMData
-
-SetupPokeballs: ; 0x3a8a6
- ld a, [de]
- push af
- ld de, wBuffer
- ld c, PARTY_LENGTH
- ld a, $34 ; empty pokeball
-.emptyloop
- ld [de], a
- inc de
- dec c
- jr nz, .emptyloop
- pop af
- ld de, wBuffer
-.monloop
- push af
- call PickPokeball
- inc de
- pop af
- dec a
- jr nz, .monloop
- ret
-
-PickPokeball: ; 3a8c2 (e:68c2)
- inc hl
- ld a, [hli]
- and a
- jr nz, .alive
- ld a, [hl]
- and a
- ld b, $33 ; crossed ball (fainted)
- jr z, .done_fainted
-.alive
- inc hl
- inc hl
- ld a, [hl] ; status
- and a
- ld b, $32 ; black ball (status)
- jr nz, .done
- dec b ; regular ball
- jr .done
-.done_fainted
- inc hl
- inc hl
-.done
- ld a, b
- ld [de], a
- ld bc, $0028 ; rest of mon struct
- add hl, bc
- ret
-
-WritePokeballOAMData: ; 3a8e1 (e:68e1)
- ld de, wBuffer
- ld c, PARTY_LENGTH
-.loop
- ld a, [W_BASECOORDY] ; wd082
- ld [hli], a
- ld a, [W_BASECOORDX] ; wd081
- ld [hli], a
- ld a, [de]
- ld [hli], a
- xor a
- ld [hli], a
- ld a, [W_BASECOORDX] ; wd081
- ld b, a
- ld a, [wTrainerEngageDistance]
- add b
- ld [W_BASECOORDX], a ; wd081
- inc de
- dec c
- jr nz, .loop
- ret
-
-PlacePlayerHUDTiles: ; 3a902 (e:6902)
- ld hl, PlayerBattleHUDGraphicsTiles ; $6916
- ld de, wTrainerFacingDirection
- ld bc, $3
- call CopyData
- hlCoord 18, 10
- ld de, rIE ; $ffff
- jr PlaceHUDTiles
-
-PlayerBattleHUDGraphicsTiles: ; 3a916 (e:6916)
-; The tile numbers for specific parts of the battle display for the player's pokemon
- db $73 ; unused ($73 is hardcoded into the routine that uses these bytes)
- db $77 ; lower-right corner tile of the HUD
- db $6F ; lower-left triangle tile of the HUD
-
-PlaceEnemyHUDTiles: ; 3a919 (e:6919)
- ld hl, EnemyBattleHUDGraphicsTiles ; $692d
- ld de, wTrainerFacingDirection
- ld bc, $3
- call CopyData
- hlCoord 1, 2
- ld de, $1
- jr PlaceHUDTiles
-
-EnemyBattleHUDGraphicsTiles: ; 3a92d (e:692d)
-; The tile numbers for specific parts of the battle display for the enemy
- db $73 ; unused ($73 is hardcoded in the routine that uses these bytes)
- db $74 ; lower-left corner tile of the HUD
- db $78 ; lower-right triangle tile of the HUD
-
-PlaceHUDTiles: ; 3a930 (e:6930)
- ld [hl], $73
- ld bc, $14
- add hl, bc
- ld a, [wTrainerScreenY]
- ld [hl], a
- ld a, $8
-.asm_3a93c
- add hl, de
- ld [hl], $76
- dec a
- jr nz, .asm_3a93c
- add hl, de
- ld a, [wTrainerScreenX]
- ld [hl], a
- ret
-
-SetupPlayerAndEnemyPokeballs: ; 3a948 (e:6948)
- call LoadPartyPokeballGfx
- ld hl, wPartyMon1Species ; wPartyMon1Species (aliases: wPartyMon1)
- ld de, wPartyCount ; wPartyCount
- call SetupPokeballs
- ld hl, W_BASECOORDX ; wd081
- ld a, $50
- ld [hli], a
- ld [hl], $40
- ld a, $8
- ld [wTrainerEngageDistance], a
- ld hl, wOAMBuffer
- call WritePokeballOAMData
- ld hl, wEnemyMons ; wEnemyMon1Species
- ld de, wEnemyPartyCount ; wEnemyPartyCount
- call SetupPokeballs
- ld hl, W_BASECOORDX ; wd081
- ld a, $50
- ld [hli], a
- ld [hl], $68
- ld hl, wOAMBuffer + $18
- jp WritePokeballOAMData
-
-; four tiles: pokeball, black pokeball (status ailment), crossed out pokeball (faited) and pokeball slot (no mon)
-PokeballTileGraphics:: ; 3a97e (e:697e)
- INCBIN "gfx/pokeball.2bpp"
--- a/engine/battle/e_2.asm
+++ /dev/null
@@ -1,301 +1,0 @@
-HealEffect_: ; 3b9ec (e:79ec)
- ld a, [H_WHOSETURN]
- and a
- ld de, wBattleMonHP
- ld hl, wBattleMonMaxHP
- ld a, [W_PLAYERMOVENUM]
- jr z, .asm_3ba03
- ld de, wEnemyMonHP
- ld hl, wEnemyMonMaxHP
- ld a, [W_ENEMYMOVENUM]
-.asm_3ba03
- ld b, a
- ld a, [de]
- cp [hl]
- inc de
- inc hl
- ld a, [de]
- sbc [hl]
- jp z, .failed
- ld a, b
- cp REST
- jr nz, .asm_3ba37
- push hl
- push de
- push af
- ld c, 50
- call DelayFrames
- ld hl, wBattleMonStatus
- ld a, [H_WHOSETURN]
- and a
- jr z, .asm_3ba25
- ld hl, wEnemyMonStatus
-.asm_3ba25
- ld a, [hl]
- and a
- ld [hl], 2 ; Number of turns from Rest
- ld hl, StartedSleepingEffect
- jr z, .asm_3ba31
- ld hl, FellAsleepBecameHealthyText
-.asm_3ba31
- call PrintText
- pop af
- pop de
- pop hl
-.asm_3ba37
- ld a, [hld]
- ld [wHPBarMaxHP], a
- ld c, a
- ld a, [hl]
- ld [wHPBarMaxHP+1], a
- ld b, a
- jr z, .asm_3ba47
- srl b
- rr c
-.asm_3ba47
- ld a, [de]
- ld [wHPBarOldHP], a
- add c
- ld [de], a
- ld [wHPBarNewHP], a
- dec de
- ld a, [de]
- ld [wHPBarOldHP+1], a
- adc b
- ld [de], a
- ld [wHPBarNewHP+1], a
- inc hl
- inc de
- ld a, [de]
- dec de
- sub [hl]
- dec hl
- ld a, [de]
- sbc [hl]
- jr c, .asm_3ba6f
- ld a, [hli]
- ld [de], a
- ld [wHPBarNewHP+1], a
- inc de
- ld a, [hl]
- ld [de], a
- ld [wHPBarNewHP], a
-.asm_3ba6f
- ld hl, PlayCurrentMoveAnimation
- call BankswitchEtoF
- ld a, [H_WHOSETURN]
- and a
- hlCoord 10, 9
- ld a, $1
- jr z, .asm_3ba83
- hlCoord 2, 2
- xor a
-.asm_3ba83
- ld [wHPBarType], a
- predef UpdateHPBar2
- ld hl, DrawHUDsAndHPBars
- call BankswitchEtoF
- ld hl, RegainedHealthText
- jp PrintText
-.failed
- ld c, 50
- call DelayFrames
- ld hl, PrintButItFailedText_
- jp BankswitchEtoF
-
-StartedSleepingEffect: ; 3baa2 (e:7aa2)
- TX_FAR _StartedSleepingEffect
- db "@"
-
-FellAsleepBecameHealthyText: ; 3baa7 (e:7aa7)
- TX_FAR _FellAsleepBecameHealthyText
- db "@"
-
-RegainedHealthText: ; 3baac (e:7aac)
- TX_FAR _RegainedHealthText
- db "@"
-
-TransformEffect_: ; 3bab1 (e:7ab1)
- ld hl, wBattleMonSpecies
- ld de, wEnemyMonSpecies
- ld bc, W_ENEMYBATTSTATUS3
- ld a, [W_ENEMYBATTSTATUS1]
- ld a, [H_WHOSETURN]
- and a
- jr nz, .asm_3bad1
- ld hl, wEnemyMonSpecies
- ld de, wBattleMonSpecies
- ld bc, W_PLAYERBATTSTATUS3
- ld [wPlayerMoveListIndex], a
- ld a, [W_PLAYERBATTSTATUS1]
-.asm_3bad1
- bit Invulnerable, a ; is mon invulnerable to typical attacks? (fly/dig)
- jp nz, .failed
- push hl
- push de
- push bc
- ld hl, W_PLAYERBATTSTATUS2
- ld a, [H_WHOSETURN]
- and a
- jr z, .asm_3bae4
- ld hl, W_ENEMYBATTSTATUS2
-.asm_3bae4
- bit HasSubstituteUp, [hl]
- push af
- ld hl, Func_79747
- ld b, BANK(Func_79747)
- call nz, Bankswitch
- ld a, [W_OPTIONS]
- add a
- ld hl, PlayCurrentMoveAnimation
- ld b, BANK(PlayCurrentMoveAnimation)
- jr nc, .asm_3baff
- ld hl, AnimationTransformMon
- ld b, BANK(AnimationTransformMon)
-.asm_3baff
- call Bankswitch
- ld hl, Func_79771
- ld b, BANK(Func_79771)
- pop af
- call nz, Bankswitch
- pop bc
- ld a, [bc]
- set Transformed, a
- ld [bc], a
- pop de
- pop hl
- push hl
- ld a, [hl]
- ld [de], a
- ld bc, $5
- add hl, bc
- inc de
- inc de
- inc de
- inc de
- inc de
- inc bc
- inc bc
- call CopyData
- ld a, [H_WHOSETURN]
- and a
- jr z, .asm_3bb32
- ld a, [de]
- ld [wcceb], a
- inc de
- ld a, [de]
- ld [wccec], a
- dec de
-.asm_3bb32
- ld a, [hli]
- ld [de], a
- inc de
- ld a, [hli]
- ld [de], a
- inc de
- inc hl
- inc hl
- inc hl
- inc de
- inc de
- inc de
- ld bc, $8
- call CopyData
- ld bc, $ffef
- add hl, bc
- ld b, $4
-.asm_3bb4a
- ld a, [hli]
- and a
- jr z, .asm_3bb57
- ld a, $5
- ld [de], a
- inc de
- dec b
- jr nz, .asm_3bb4a
- jr .asm_3bb5d
-.asm_3bb57
- xor a
- ld [de], a
- inc de
- dec b
- jr nz, .asm_3bb57
-.asm_3bb5d
- pop hl
- ld a, [hl]
- ld [wd11e], a
- call GetMonName
- ld hl, wEnemyMonUnmodifiedAttack
- ld de, wPlayerMonUnmodifiedAttack
- call .copyBasedOnTurn
- ld hl, wEnemyMonStatMods
- ld de, wPlayerMonStatMods
- call .copyBasedOnTurn
- ld hl, TransformedText
- jp PrintText
-
-.copyBasedOnTurn
- ld a, [H_WHOSETURN]
- and a
- jr z, .asm_3bb86
- push hl
- ld h, d
- ld l, e
- pop de
-.asm_3bb86
- ld bc, $8
- jp CopyData
-
-.failed
- ld hl, PrintButItFailedText_
- jp BankswitchEtoF
-
-TransformedText: ; 3bb92 (e:7b92)
- TX_FAR _TransformedText
- db "@"
-
-ReflectLightScreenEffect_: ; 3bb97 (e:7b97)
- ld hl, W_PLAYERBATTSTATUS3
- ld de, W_PLAYERMOVEEFFECT
- ld a, [H_WHOSETURN]
- and a
- jr z, .asm_3bba8
- ld hl, W_ENEMYBATTSTATUS3
- ld de, W_ENEMYMOVEEFFECT
-.asm_3bba8
- ld a, [de]
- cp LIGHT_SCREEN_EFFECT
- jr nz, .reflect
- bit HasLightScreenUp, [hl] ; is mon already protected by light screen?
- jr nz, .moveFailed
- set HasLightScreenUp, [hl] ; mon is now protected by light screen
- ld hl, LightScreenProtectedText
- jr .asm_3bbc1
-.reflect
- bit HasReflectUp, [hl] ; is mon already protected by reflect?
- jr nz, .moveFailed
- set HasReflectUp, [hl] ; mon is now protected by reflect
- ld hl, ReflectGainedArmorText
-.asm_3bbc1
- push hl
- ld hl, PlayCurrentMoveAnimation
- call BankswitchEtoF
- pop hl
- jp PrintText
-.moveFailed
- ld c, $32
- call DelayFrames
- ld hl, PrintButItFailedText_
- jp BankswitchEtoF
-
-LightScreenProtectedText: ; 3bbd7 (e:7bd7)
- TX_FAR _LightScreenProtectedText
- db "@"
-
-ReflectGainedArmorText: ; 3bbdc (e:7bdc)
- TX_FAR _ReflectGainedArmorText
- db "@"
-
-BankswitchEtoF: ; 3bbe1 (e:7be1)
- ld b, BANK(BattleCore)
- jp Bankswitch
--- /dev/null
+++ b/engine/battle/init_battle_variables.asm
@@ -1,0 +1,40 @@
+InitBattleVariables: ; 525af (14:65af)
+ ld a, [hTilesetType]
+ ld [wd0d4], a
+ xor a
+ ld [wcd6a], a
+ ld [wBattleResult], a
+ ld hl, wcc2b
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ld [wListScrollOffset], a
+ ld [wCriticalHitOrOHKO], a
+ ld [wBattleMonSpecies], a
+ ld [wPartyGainExpFlags], a
+ ld [wPlayerMonNumber], a
+ ld [wEscapedFromBattle], a
+ ld [wMapPalOffset], a
+ ld hl, wcf1d
+ ld [hli], a
+ ld [hl], a
+ ld hl, wccd3
+ ld b, $3c
+.loop
+ ld [hli], a
+ dec b
+ jr nz, .loop
+ inc a
+ ld [wccd9], a
+ ld a, [W_CURMAP]
+ cp SAFARI_ZONE_EAST
+ jr c, .notSafariBattle
+ cp SAFARI_ZONE_REST_HOUSE_1
+ jr nc, .notSafariBattle
+ ld a, $2 ; safari battle
+ ld [W_BATTLETYPE], a
+.notSafariBattle
+ ld hl, PlayBattleMusic
+ ld b, BANK(PlayBattleMusic)
+ jp Bankswitch
--- /dev/null
+++ b/engine/battle/moveEffects/heal_effect.asm
@@ -1,0 +1,116 @@
+HealEffect_: ; 3b9ec (e:79ec)
+ ld a, [H_WHOSETURN]
+ and a
+ ld de, wBattleMonHP
+ ld hl, wBattleMonMaxHP
+ ld a, [W_PLAYERMOVENUM]
+ jr z, .asm_3ba03
+ ld de, wEnemyMonHP
+ ld hl, wEnemyMonMaxHP
+ ld a, [W_ENEMYMOVENUM]
+.asm_3ba03
+ ld b, a
+ ld a, [de]
+ cp [hl]
+ inc de
+ inc hl
+ ld a, [de]
+ sbc [hl]
+ jp z, .failed
+ ld a, b
+ cp REST
+ jr nz, .asm_3ba37
+ push hl
+ push de
+ push af
+ ld c, 50
+ call DelayFrames
+ ld hl, wBattleMonStatus
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .asm_3ba25
+ ld hl, wEnemyMonStatus
+.asm_3ba25
+ ld a, [hl]
+ and a
+ ld [hl], 2 ; Number of turns from Rest
+ ld hl, StartedSleepingEffect
+ jr z, .asm_3ba31
+ ld hl, FellAsleepBecameHealthyText
+.asm_3ba31
+ call PrintText
+ pop af
+ pop de
+ pop hl
+.asm_3ba37
+ ld a, [hld]
+ ld [wHPBarMaxHP], a
+ ld c, a
+ ld a, [hl]
+ ld [wHPBarMaxHP+1], a
+ ld b, a
+ jr z, .asm_3ba47
+ srl b
+ rr c
+.asm_3ba47
+ ld a, [de]
+ ld [wHPBarOldHP], a
+ add c
+ ld [de], a
+ ld [wHPBarNewHP], a
+ dec de
+ ld a, [de]
+ ld [wHPBarOldHP+1], a
+ adc b
+ ld [de], a
+ ld [wHPBarNewHP+1], a
+ inc hl
+ inc de
+ ld a, [de]
+ dec de
+ sub [hl]
+ dec hl
+ ld a, [de]
+ sbc [hl]
+ jr c, .asm_3ba6f
+ ld a, [hli]
+ ld [de], a
+ ld [wHPBarNewHP+1], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+ ld [wHPBarNewHP], a
+.asm_3ba6f
+ ld hl, PlayCurrentMoveAnimation
+ call BankswitchEtoF
+ ld a, [H_WHOSETURN]
+ and a
+ hlCoord 10, 9
+ ld a, $1
+ jr z, .asm_3ba83
+ hlCoord 2, 2
+ xor a
+.asm_3ba83
+ ld [wHPBarType], a
+ predef UpdateHPBar2
+ ld hl, DrawHUDsAndHPBars
+ call BankswitchEtoF
+ ld hl, RegainedHealthText
+ jp PrintText
+.failed
+ ld c, 50
+ call DelayFrames
+ ld hl, PrintButItFailedText_
+ jp BankswitchEtoF
+
+StartedSleepingEffect: ; 3baa2 (e:7aa2)
+ TX_FAR _StartedSleepingEffect
+ db "@"
+
+FellAsleepBecameHealthyText: ; 3baa7 (e:7aa7)
+ TX_FAR _FellAsleepBecameHealthyText
+ db "@"
+
+RegainedHealthText: ; 3baac (e:7aac)
+ TX_FAR _RegainedHealthText
+ db "@"
--- /dev/null
+++ b/engine/battle/moveEffects/paralyze_effect.asm
@@ -1,0 +1,53 @@
+ParalyzeEffect_: ; 52601 (14:6601)
+ ld hl, wEnemyMonStatus
+ ld de, W_PLAYERMOVETYPE
+ ld a, [H_WHOSETURN]
+ and a
+ jp z, .next
+ ld hl, wBattleMonStatus
+ ld de, W_ENEMYMOVETYPE
+.next
+ ld a, [hl]
+ and a ; does the target already have a status ailment?
+ jr nz, .didntAffect
+; check if the target is immune due to types
+ ld a, [de]
+ cp ELECTRIC
+ jr nz, .hitTest
+ ld b, h
+ ld c, l
+ inc bc
+ ld a, [bc]
+ cp GROUND
+ jr z, .doesntAffect
+ inc bc
+ ld a, [bc]
+ cp GROUND
+ jr z, .doesntAffect
+.hitTest
+ push hl
+ callab MoveHitTest
+ pop hl
+ ld a, [W_MOVEMISSED]
+ and a
+ jr nz, .didntAffect
+ set PAR, [hl]
+ callab QuarterSpeedDueToParalysis
+ ld c, 30
+ call DelayFrames
+ callab PlayCurrentMoveAnimation
+ ld hl, PrintMayNotAttackText
+ ld b, BANK(PrintMayNotAttackText)
+ jp Bankswitch
+.didntAffect
+ ld c, 50
+ call DelayFrames
+ ld hl, PrintDidntAffectText
+ ld b, BANK(PrintDidntAffectText)
+ jp Bankswitch
+.doesntAffect
+ ld c, 50
+ call DelayFrames
+ ld hl, PrintDoesntAffectText
+ ld b, BANK(PrintDoesntAffectText)
+ jp Bankswitch
--- /dev/null
+++ b/engine/battle/moveEffects/reflect_light_screen_effect.asm
@@ -1,0 +1,45 @@
+ReflectLightScreenEffect_: ; 3bb97 (e:7b97)
+ ld hl, W_PLAYERBATTSTATUS3
+ ld de, W_PLAYERMOVEEFFECT
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .asm_3bba8
+ ld hl, W_ENEMYBATTSTATUS3
+ ld de, W_ENEMYMOVEEFFECT
+.asm_3bba8
+ ld a, [de]
+ cp LIGHT_SCREEN_EFFECT
+ jr nz, .reflect
+ bit HasLightScreenUp, [hl] ; is mon already protected by light screen?
+ jr nz, .moveFailed
+ set HasLightScreenUp, [hl] ; mon is now protected by light screen
+ ld hl, LightScreenProtectedText
+ jr .asm_3bbc1
+.reflect
+ bit HasReflectUp, [hl] ; is mon already protected by reflect?
+ jr nz, .moveFailed
+ set HasReflectUp, [hl] ; mon is now protected by reflect
+ ld hl, ReflectGainedArmorText
+.asm_3bbc1
+ push hl
+ ld hl, PlayCurrentMoveAnimation
+ call BankswitchEtoF
+ pop hl
+ jp PrintText
+.moveFailed
+ ld c, $32
+ call DelayFrames
+ ld hl, PrintButItFailedText_
+ jp BankswitchEtoF
+
+LightScreenProtectedText: ; 3bbd7 (e:7bd7)
+ TX_FAR _LightScreenProtectedText
+ db "@"
+
+ReflectGainedArmorText: ; 3bbdc (e:7bdc)
+ TX_FAR _ReflectGainedArmorText
+ db "@"
+
+BankswitchEtoF: ; 3bbe1 (e:7be1)
+ ld b, BANK(BattleCore)
+ jp Bankswitch
--- /dev/null
+++ b/engine/battle/moveEffects/transform_effect.asm
@@ -1,0 +1,138 @@
+TransformEffect_: ; 3bab1 (e:7ab1)
+ ld hl, wBattleMonSpecies
+ ld de, wEnemyMonSpecies
+ ld bc, W_ENEMYBATTSTATUS3
+ ld a, [W_ENEMYBATTSTATUS1]
+ ld a, [H_WHOSETURN]
+ and a
+ jr nz, .asm_3bad1
+ ld hl, wEnemyMonSpecies
+ ld de, wBattleMonSpecies
+ ld bc, W_PLAYERBATTSTATUS3
+ ld [wPlayerMoveListIndex], a
+ ld a, [W_PLAYERBATTSTATUS1]
+.asm_3bad1
+ bit Invulnerable, a ; is mon invulnerable to typical attacks? (fly/dig)
+ jp nz, .failed
+ push hl
+ push de
+ push bc
+ ld hl, W_PLAYERBATTSTATUS2
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .asm_3bae4
+ ld hl, W_ENEMYBATTSTATUS2
+.asm_3bae4
+ bit HasSubstituteUp, [hl]
+ push af
+ ld hl, Func_79747
+ ld b, BANK(Func_79747)
+ call nz, Bankswitch
+ ld a, [W_OPTIONS]
+ add a
+ ld hl, PlayCurrentMoveAnimation
+ ld b, BANK(PlayCurrentMoveAnimation)
+ jr nc, .asm_3baff
+ ld hl, AnimationTransformMon
+ ld b, BANK(AnimationTransformMon)
+.asm_3baff
+ call Bankswitch
+ ld hl, Func_79771
+ ld b, BANK(Func_79771)
+ pop af
+ call nz, Bankswitch
+ pop bc
+ ld a, [bc]
+ set Transformed, a
+ ld [bc], a
+ pop de
+ pop hl
+ push hl
+ ld a, [hl]
+ ld [de], a
+ ld bc, $5
+ add hl, bc
+ inc de
+ inc de
+ inc de
+ inc de
+ inc de
+ inc bc
+ inc bc
+ call CopyData
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .asm_3bb32
+ ld a, [de]
+ ld [wcceb], a
+ inc de
+ ld a, [de]
+ ld [wccec], a
+ dec de
+.asm_3bb32
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ inc de
+ inc hl
+ inc hl
+ inc hl
+ inc de
+ inc de
+ inc de
+ ld bc, $8
+ call CopyData
+ ld bc, $ffef
+ add hl, bc
+ ld b, $4
+.asm_3bb4a
+ ld a, [hli]
+ and a
+ jr z, .asm_3bb57
+ ld a, $5
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .asm_3bb4a
+ jr .asm_3bb5d
+.asm_3bb57
+ xor a
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .asm_3bb57
+.asm_3bb5d
+ pop hl
+ ld a, [hl]
+ ld [wd11e], a
+ call GetMonName
+ ld hl, wEnemyMonUnmodifiedAttack
+ ld de, wPlayerMonUnmodifiedAttack
+ call .copyBasedOnTurn
+ ld hl, wEnemyMonStatMods
+ ld de, wPlayerMonStatMods
+ call .copyBasedOnTurn
+ ld hl, TransformedText
+ jp PrintText
+
+.copyBasedOnTurn
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .asm_3bb86
+ push hl
+ ld h, d
+ ld l, e
+ pop de
+.asm_3bb86
+ ld bc, $8
+ jp CopyData
+
+.failed
+ ld hl, PrintButItFailedText_
+ jp BankswitchEtoF
+
+TransformedText: ; 3bb92 (e:7b92)
+ TX_FAR _TransformedText
+ db "@"
--- /dev/null
+++ b/engine/battle/scroll_draw_trainer_pic.asm
@@ -1,0 +1,50 @@
+_ScrollTrainerPicAfterBattle: ; 396d3 (e:56d3)
+; Load the enemy trainer's pic and scrolls it into
+; the screen from the right.
+ xor a
+ ld [wEnemyMonSpecies2], a
+ ld b, $1
+ call GoPAL_SET
+ callab _LoadTrainerPic
+ hlCoord 19, 0
+ ld c, $0
+.scrollLoop
+ inc c
+ ld a, c
+ cp 7
+ ret z
+ ld d, $0
+ push bc
+ push hl
+.drawTrainerPicLoop
+ call DrawTrainerPicColumn
+ inc hl
+ ld a, 7
+ add d
+ ld d, a
+ dec c
+ jr nz, .drawTrainerPicLoop
+ ld c, 4
+ call DelayFrames
+ pop hl
+ pop bc
+ dec hl
+ jr .scrollLoop
+
+; write one 7-tile column of the trainer pic to the tilemap
+DrawTrainerPicColumn: ; 39707 (e:5707)
+ push hl
+ push de
+ push bc
+ ld e, 7
+.loop
+ ld [hl], d
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ inc d
+ dec e
+ jr nz, .loop
+ pop bc
+ pop de
+ pop hl
+ ret
--- /dev/null
+++ b/engine/battle/trainer_party_ai_misc.asm
@@ -1,0 +1,1263 @@
+; 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/unused_stats_functions.asm
@@ -1,0 +1,62 @@
+; does nothing since no stats are ever selected (barring glitches)
+DoubleSelectedStats: ; 39680 (e:5680)
+ ld a, [H_WHOSETURN]
+ 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: ; 396a7 (e:56a7)
+ ld a, [H_WHOSETURN]
+ and a
+ ld a, [wPlayerStatsToHalve]
+ ld hl, wBattleMonAttack
+ jr z, .notEnemyTurn
+ ld a, [wEnemyStatsToHalve]
+ ld hl, wEnemyMonAttack
+.notEnemyTurn
+ ld c, 4
+ ld b, a
+.loop
+ srl b
+ call c, .halveStat
+ inc hl
+ inc hl
+ dec c
+ ret z
+ jr .loop
+
+.halveStat
+ ld a, [hl]
+ srl a
+ ld [hli], a
+ rr [hl]
+ or [hl]
+ jr nz, .nonzeroStat
+ ld [hl], 1
+.nonzeroStat
+ dec hl
+ ret
--- a/main.asm
+++ b/main.asm
@@ -5463,7 +5463,10 @@
INCLUDE "data/moves.asm"
BaseStats: INCLUDE "data/base_stats.asm"
INCLUDE "data/cries.asm"
-INCLUDE "engine/battle/e.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/draw_hud_pokeball_gfx.asm"
TradingAnimationGraphics:
INCBIN "gfx/game_boy.norepeat.2bpp"
@@ -5474,7 +5477,9 @@
INCBIN "gfx/trade2.2bpp"
INCLUDE "engine/evos_moves.asm"
-INCLUDE "engine/battle/e_2.asm"
+INCLUDE "engine/battle/moveEffects/heal_effect.asm"
+INCLUDE "engine/battle/moveEffects/transform_effect.asm"
+INCLUDE "engine/battle/moveEffects/reflect_light_screen_effect.asm"
SECTION "bankF",ROMX,BANK[$F]
@@ -5947,7 +5952,8 @@
INCLUDE "data/mapObjects/mansion4.asm"
Mansion4Blocks: INCBIN "maps/mansion4.blk"
-INCLUDE "engine/battle/14.asm"
+INCLUDE "engine/battle/init_battle_variables.asm"
+INCLUDE "engine/battle/moveEffects/paralyze_effect.asm"
INCLUDE "engine/overworld/card_key.asm"