From 2fe782b11a039b52fd236da28fb2f1ae10cae7db Mon Sep 17 00:00:00 2001 From: xCrystal Date: Wed, 1 Apr 2015 16:51:04 +0200 Subject: Rename battle files and split move effects Part 4 e.asm, e_2. asm, and 14.asm --- engine/battle/14.asm | 94 -- engine/battle/draw_hud_pokeball_gfx.asm | 191 +++ engine/battle/e.asm | 1569 -------------------- engine/battle/e_2.asm | 301 ---- engine/battle/init_battle_variables.asm | 40 + engine/battle/moveEffects/heal_effect.asm | 116 ++ engine/battle/moveEffects/paralyze_effect.asm | 53 + .../moveEffects/reflect_light_screen_effect.asm | 45 + engine/battle/moveEffects/transform_effect.asm | 138 ++ engine/battle/scroll_draw_trainer_pic.asm | 50 + engine/battle/trainer_party_ai_misc.asm | 1263 ++++++++++++++++ engine/battle/unused_stats_functions.asm | 62 + 12 files changed, 1958 insertions(+), 1964 deletions(-) delete mode 100755 engine/battle/14.asm create mode 100644 engine/battle/draw_hud_pokeball_gfx.asm delete mode 100755 engine/battle/e.asm delete mode 100755 engine/battle/e_2.asm create mode 100644 engine/battle/init_battle_variables.asm create mode 100644 engine/battle/moveEffects/heal_effect.asm create mode 100644 engine/battle/moveEffects/paralyze_effect.asm create mode 100644 engine/battle/moveEffects/reflect_light_screen_effect.asm create mode 100644 engine/battle/moveEffects/transform_effect.asm create mode 100644 engine/battle/scroll_draw_trainer_pic.asm create mode 100644 engine/battle/trainer_party_ai_misc.asm create mode 100644 engine/battle/unused_stats_functions.asm (limited to 'engine') diff --git a/engine/battle/14.asm b/engine/battle/14.asm deleted file mode 100755 index 1b2d7462..00000000 --- a/engine/battle/14.asm +++ /dev/null @@ -1,94 +0,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 diff --git a/engine/battle/draw_hud_pokeball_gfx.asm b/engine/battle/draw_hud_pokeball_gfx.asm new file mode 100644 index 00000000..fce3701c --- /dev/null +++ b/engine/battle/draw_hud_pokeball_gfx.asm @@ -0,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" diff --git a/engine/battle/e.asm b/engine/battle/e.asm deleted file mode 100755 index 1144abe8..00000000 --- a/engine/battle/e.asm +++ /dev/null @@ -1,1569 +0,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" diff --git a/engine/battle/e_2.asm b/engine/battle/e_2.asm deleted file mode 100755 index 9400282d..00000000 --- a/engine/battle/e_2.asm +++ /dev/null @@ -1,301 +0,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 diff --git a/engine/battle/init_battle_variables.asm b/engine/battle/init_battle_variables.asm new file mode 100644 index 00000000..457cc4e1 --- /dev/null +++ b/engine/battle/init_battle_variables.asm @@ -0,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 diff --git a/engine/battle/moveEffects/heal_effect.asm b/engine/battle/moveEffects/heal_effect.asm new file mode 100644 index 00000000..22d482e7 --- /dev/null +++ b/engine/battle/moveEffects/heal_effect.asm @@ -0,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 "@" diff --git a/engine/battle/moveEffects/paralyze_effect.asm b/engine/battle/moveEffects/paralyze_effect.asm new file mode 100644 index 00000000..69acbb01 --- /dev/null +++ b/engine/battle/moveEffects/paralyze_effect.asm @@ -0,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 diff --git a/engine/battle/moveEffects/reflect_light_screen_effect.asm b/engine/battle/moveEffects/reflect_light_screen_effect.asm new file mode 100644 index 00000000..39a2c154 --- /dev/null +++ b/engine/battle/moveEffects/reflect_light_screen_effect.asm @@ -0,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 diff --git a/engine/battle/moveEffects/transform_effect.asm b/engine/battle/moveEffects/transform_effect.asm new file mode 100644 index 00000000..6e25712a --- /dev/null +++ b/engine/battle/moveEffects/transform_effect.asm @@ -0,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 "@" diff --git a/engine/battle/scroll_draw_trainer_pic.asm b/engine/battle/scroll_draw_trainer_pic.asm new file mode 100644 index 00000000..18df86e0 --- /dev/null +++ b/engine/battle/scroll_draw_trainer_pic.asm @@ -0,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 diff --git a/engine/battle/trainer_party_ai_misc.asm b/engine/battle/trainer_party_ai_misc.asm new file mode 100644 index 00000000..8cbb9329 --- /dev/null +++ b/engine/battle/trainer_party_ai_misc.asm @@ -0,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 "@" diff --git a/engine/battle/unused_stats_functions.asm b/engine/battle/unused_stats_functions.asm new file mode 100644 index 00000000..23ddbc20 --- /dev/null +++ b/engine/battle/unused_stats_functions.asm @@ -0,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 -- cgit v1.2.3