summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xengine/battle/core.asm701
-rw-r--r--engine/battle/core_.asm7045
-rwxr-xr-xyellow/main.asm2
3 files changed, 391 insertions, 7357 deletions
diff --git a/engine/battle/core.asm b/engine/battle/core.asm
index 80c38841..028d332d 100755
--- a/engine/battle/core.asm
+++ b/engine/battle/core.asm
@@ -258,6 +258,7 @@ StartBattle: ; 3c127 (f:4127)
ld a, d
and a
jp z, HandlePlayerBlackOut ; jump if no mon is alive
+.specialBattle
call LoadScreenTilesFromBuffer1
ld a, [wBattleType]
and a ; is it a normal battle?
@@ -564,7 +565,7 @@ MainInBattleLoop: ; 3c249 (f:4249)
call DrawHUDsAndHPBars
call CheckNumAttacksLeft
jp MainInBattleLoop
-
+
HandlePoisonBurnLeechSeed: ; 3c3d3 (f:43d3)
ld hl, wBattleMonHP
ld de, wBattleMonStatus
@@ -1115,6 +1116,7 @@ RemoveFaintedPlayerMon: ; 3c75e (f:475e)
ld a, $ff
ld [wLowHealthAlarm], a ;disable low health alarm
call WaitForSoundToFinish
+ xor a
.skipWaitForSound
; a is 0, so this zeroes the enemy's accumulated damage.
ld hl, wEnemyBideAccumulatedDamage
@@ -1139,7 +1141,7 @@ RemoveFaintedPlayerMon: ; 3c75e (f:475e)
and a ; was this called by HandleEnemyMonFainted?
ret z ; if so, return
- ld a, [wPlayerMonIndex]
+ ld a, [wPlayerMonNumber]
ld [wWhichPokemon], a
callab IsThisPartymonStarterPikachu_Party
jr nc, .notPlayerPikachu
@@ -1152,20 +1154,22 @@ RemoveFaintedPlayerMon: ; 3c75e (f:475e)
.printText
ld hl, PlayerMonFaintedText
call PrintText
- ld a, [wPlayerMonIndex]
+ ld a, [wPlayerMonNumber]
ld [wWhichPokemon], a
ld a, [wBattleMonLevel]
ld b, a
ld a, [wEnemyMonLevel]
sub b ; enemylevel - playerlevel
; are we stronger than the opposing pokemon?
- jr c, .carelessTrainer ; if so, punish the player for being careless, as they had a level advantage
+ jr c, .regularFaint ; if so, deduct happiness regularly
+
cp 30 ; is the enemy 30 levels greater than us?
jr nc, .carelessTrainer ; if so, punish the player for being careless, as they shouldn't be fighting a very high leveled trainer with such a level difference
+.regularFaint
callabd_ModifyPikachuHappiness PIKAHAPPY_FAINTED
ret
.carelessTrainer
- calladb_ModifyPikachuHappiness PIKAHAPPY_CARELESSTRAINER
+ callabd_ModifyPikachuHappiness PIKAHAPPY_CARELESSTRAINER
ret
PlayerMonFaintedText: ; 3c7fa (f:47fa)
@@ -1223,7 +1227,7 @@ ChooseNextMon: ; 3c83c (f:483c)
ld a, [wLinkState]
cp LINK_STATE_BATTLING
jr nz, .notLinkBattle
- inc a
+ ld a, $1
ld [wActionResultOrTookBattleTurn], a
call LinkBattleExchangeData
.notLinkBattle
@@ -1889,7 +1893,7 @@ SendOutMon: ; 3ccfb (f:4cfb)
coord hl, 4, 11
predef AnimateSendingOutMon
jr .playRegularCry
-.playerPikachu
+.starterPikachu
xor a
ld [H_WHOSETURN], a
ld a, $1
@@ -2209,7 +2213,7 @@ DisplayBattleMenu: ; 3cf78 (f:4f78)
ld [hl], " "
coord hl, 9, 16
ld [hl], "▶"
- ld c, 14
+ ld c, 20
call DelayFrames
ld [hl], $ec
ld a, $2 ; select the "ITEM" menu
@@ -2302,6 +2306,7 @@ DisplayBattleMenu: ; 3cf78 (f:4f78)
ld a, [wBattleType]
cp HURRY_RUN_AWAY_BATTLE
jr z, .handleUnusedBattle
+ ld a, [wBattleType]
cp SAFARI_BATTLE ; is it a Safari battle?
ld a, [wCurrentMenuItem]
ld [wBattleAndStartSavedMenuItem], a
@@ -2338,11 +2343,11 @@ DisplayBattleMenu: ; 3cf78 (f:4f78)
ld a, [wCurrentMenuItem]
cp $3
jp z, BattleMenu_RunWasSelected
- ld hl, RunAwayText
+ ld hl, .RunAwayText
call PrintText
jp DisplayBattleMenu
-RunAwayText: ; 3d0df (f:50df)
+.RunAwayText ; 3d0df (f:50df)
TX_FAR _RunAwayText
db "@"
@@ -2430,7 +2435,6 @@ UseBagItem: ; 3c162 (f:5162)
call CopyStringToCF4B ; copy name
xor a
ld [wPseudoItemID], a
- ld a, [wBattleType]
call UseItem
call LoadHudTilePatterns
call ClearSprites
@@ -2894,8 +2898,8 @@ Func_3d4f5: ; 3d4f5 (f:54f5)
ld a, $0
jr nz, .asm_3d4fd
ld a, $1
- ld [H_WHOSETURN], a
.asm_3d4fd
+ ld [H_WHOSETURN], a
call LoadScreenTilesFromBuffer1
call Func_3d536
ld a, [wTestBattlePlayerSelectedMove]
@@ -2921,12 +2925,12 @@ asm_3d52d: ; 3d52d (f:552d)
jp MoveSelectionMenu
Func_3d536: ; 3d536 (f:5536)
- coord hl, 10, 9
+ coord hl, 10, 16
lb bc, 2, 10
- call TextBoxBorder
+ call ClearScreenArea
coord hl, 10, 17
ld de, wTestBattlePlayerSelectedMove
- lb bc, LEADING_ZEROS | 1, 3
+ lb bc, LEADING_ZEROES | 1, 3
call PrintNumber
ld a, [wTestBattlePlayerSelectedMove]
and a
@@ -2937,7 +2941,7 @@ Func_3d536: ; 3d536 (f:5536)
call GetMoveName
coord hl, 13, 17
jp PlaceString
-
+
AnyMoveToSelect: ; 3d55f (f:555f)
; return z and Struggle as the selected move if all moves have 0 PP and/or are disabled
ld a, STRUGGLE
@@ -2945,7 +2949,7 @@ AnyMoveToSelect: ; 3d55f (f:555f)
ld a, [wPlayerDisabledMove]
and a
ld hl, wBattleMonPP
- jr nz, .asm_3d40e
+ jr nz, .handleDisabledMove
ld a, [hli]
or [hl]
inc hl
@@ -2954,26 +2958,29 @@ AnyMoveToSelect: ; 3d55f (f:555f)
or [hl]
and $3f
ret nz
- jr .asm_3d423
-.asm_3d40e
+ jr .noMovesLeft
+.handleDisabledMove
swap a
- and $f
+ and $f ; get move disabled
ld b, a
- ld d, $5
+ ld d, NUM_MOVES + 1
xor a
-.asm_3d416
+.handleDisabledMovePPLoop
dec d
- jr z, .asm_3d421
- ld c, [hl]
+ jr z, .allMovesChecked
+ ld c, [hl] ; get move PP
inc hl
- dec b
- jr z, .asm_3d416
+ dec b ; is this the disabled move?
+ jr z, .handleDisabledMovePPLoop ; if so, ignore its PP value
or c
- jr .asm_3d416
-.asm_3d421
- and a
- ret nz
-.asm_3d423
+ jr .handleDisabledMovePPLoop
+.allMovesChecked
+; bugfix: only check PP value and not PP up bits
+; in case all other moves have no PP left and a move has a PP up used on it
+; and a non-PP up move is disabled
+ and $3f ; any PP left?
+ ret nz ; return if a move has PP left
+.noMovesLeft
ld hl, NoMovesLeftText
call PrintText
ld c, 60
@@ -2981,11 +2988,14 @@ AnyMoveToSelect: ; 3d55f (f:555f)
xor a
ret
-NoMovesLeftText: ; 3d430 (f:5430)
+NoMovesLeftText: ; 3d59b (f:559b)
TX_FAR _NoMovesLeftText
db "@"
-SwapMovesInMenu: ; 3d435 (f:5435)
+SwapMovesInMenu: ; 3d5a0 (f:55a0)
+ ld a, [wPlayerBattleStatus3]
+ bit Transformed, a
+ jp nz, MoveSelectionMenu
ld a, [wMenuItemToSwap]
and a
jr z, .noMenuItemSelected
@@ -3061,12 +3071,11 @@ SwapMovesInMenu: ; 3d435 (f:5435)
ld [wMenuItemToSwap], a ; select the current menu item for swapping
jp MoveSelectionMenu
-PrintMenuItem: ; 3d4b6 (f:54b6)
+PrintMenuItem: ; 3d629 (f:5629)
xor a
ld [H_AUTOBGTRANSFERENABLED], a
coord hl, 0, 8
- ld b, $3
- ld c, $9
+ lb bc, 3, 9
call TextBoxBorder
ld a, [wPlayerDisabledMove]
and a
@@ -3132,13 +3141,13 @@ PrintMenuItem: ; 3d4b6 (f:54b6)
ld [H_AUTOBGTRANSFERENABLED], a
jp Delay3
-DisabledText: ; 3d555 (f:5555)
+DisabledText: ; 3d6c7 (f:56c7)
db "Disabled!@"
-TypeText: ; 3d55f (f:555f)
+TypeText: ; 3d6d1 (f:56d1)
db "TYPE@"
-SelectEnemyMove: ; 3d564 (f:5564)
+SelectEnemyMove: ; 3d6d6 (f:56d6)
ld a, [wLinkState]
sub LINK_STATE_BATTLING
jr nz, .noLinkBattle
@@ -3148,7 +3157,7 @@ SelectEnemyMove: ; 3d564 (f:5564)
call LoadScreenTilesFromBuffer1
ld a, [wSerialExchangeNybbleReceiveData]
cp $e
- jp z, .asm_3d601
+ jp z, .linkedOpponentUsedStruggle
cp $d
jr z, .unableToSelectMove
cp $4
@@ -3226,12 +3235,12 @@ SelectEnemyMove: ; 3d564 (f:5564)
.done
ld [wEnemySelectedMove], a
ret
-.asm_3d601
+.linkedOpponentUsedStruggle
ld a, STRUGGLE
jr .done
; this appears to exchange data with the other gameboy during link battles
-LinkBattleExchangeData: ; 3d605 (f:5605)
+LinkBattleExchangeData: ; 3d777 (f:5777)
ld a, $ff
ld [wSerialExchangeNybbleReceiveData], a
ld a, [wPlayerMoveListIndex]
@@ -3279,7 +3288,7 @@ LinkBattleExchangeData: ; 3d605 (f:5605)
jr nz, .syncLoop3
ret
-ExecutePlayerMove: ; 3d65e (f:565e)
+ExecutePlayerMove: ; 3d7d0 (f:57d0)
xor a
ld [H_WHOSETURN], a ; set player's turn
ld a, [wPlayerSelectedMove]
@@ -3307,7 +3316,7 @@ ExecutePlayerMove: ; 3d65e (f:565e)
call CheckForDisobedience
jp z, ExecutePlayerMoveDone
-CheckIfPlayerNeedsToChargeUp: ; 3d69a (f:569a)
+CheckIfPlayerNeedsToChargeUp: ; 3d80c (f:580c)
ld a, [wPlayerMoveEffect]
cp CHARGE_EFFECT
jp z, JumpMoveEffect
@@ -3316,13 +3325,13 @@ CheckIfPlayerNeedsToChargeUp: ; 3d69a (f:569a)
jr PlayerCanExecuteMove
; in-battle stuff
-PlayerCanExecuteChargingMove: ; 3d6a9 (f:56a9)
+PlayerCanExecuteChargingMove: ; 3d81b (f:581b)
ld hl,wPlayerBattleStatus1
res ChargingUp,[hl] ; reset charging up and invulnerability statuses if mon was charging up for an attack
; being fully paralyzed or hurting oneself in confusion removes charging up status
; resulting in the Pokemon being invulnerable for the whole battle
res Invulnerable,[hl]
-PlayerCanExecuteMove: ; 3d6b0 (f:56b0)
+PlayerCanExecuteMove: ; 3d822 (f:5822)
call PrintMonName1Text
ld hl,DecrementPP
ld de,wPlayerSelectedMove ; pointer to the move just used
@@ -3339,7 +3348,7 @@ PlayerCanExecuteMove: ; 3d6b0 (f:56b0)
ld de,1
call IsInArray
call c,JumpMoveEffect ; execute the effects of SpecialEffectsCont moves (e.g. Wrap, Thrash) but don't skip anything
-PlayerCalcMoveDamage: ; 3d6dc (f:56dc)
+PlayerCalcMoveDamage: ; 3d84e (f:584e)
ld a,[wPlayerMoveEffect]
ld hl,SetDamageEffects
ld de,1
@@ -3356,7 +3365,7 @@ PlayerCalcMoveDamage: ; 3d6dc (f:56dc)
call RandomizeDamage
.moveHitTest
call MoveHitTest
-handleIfPlayerMoveMissed
+handleIfPlayerMoveMissed: ; 3d877 (f:5877)
ld a,[wMoveMissed]
and a
jr z,getPlayerAnimationType
@@ -3364,13 +3373,13 @@ handleIfPlayerMoveMissed
sub a,EXPLODE_EFFECT
jr z,playPlayerMoveAnimation ; don't play any animation if the move missed, unless it was EXPLODE_EFFECT
jr playerCheckIfFlyOrChargeEffect
-getPlayerAnimationType
+getPlayerAnimationType: ; 3d87b (f:587b)
ld a,[wPlayerMoveEffect]
and a
ld a,4 ; move has no effect other than dealing damage
jr z,playPlayerMoveAnimation
ld a,5 ; move has effect
-playPlayerMoveAnimation
+playPlayerMoveAnimation ; 3d890 (f:5890)
push af
ld a,[wPlayerBattleStatus2]
bit HasSubstituteUp,a
@@ -3389,7 +3398,7 @@ playPlayerMoveAnimation
ld b,BANK(ReshowSubstituteAnim)
call nz,Bankswitch
jr MirrorMoveCheck
-playerCheckIfFlyOrChargeEffect
+playerCheckIfFlyOrChargeEffect ; 3d8bd (f:58bd)
ld c,30
call DelayFrames
ld a,[wPlayerMoveEffect]
@@ -3403,7 +3412,7 @@ playerCheckIfFlyOrChargeEffect
ld [wAnimationType],a
ld a,STATUS_AFFECTED_ANIM
call PlayMoveAnimation
-MirrorMoveCheck
+MirrorMoveCheck: ; 3d8d8 (f:58d8)
ld a,[wPlayerMoveEffect]
cp a,MIRROR_MOVE_EFFECT
jr nz,.metronomeCheck
@@ -3476,17 +3485,17 @@ MirrorMoveCheck
; Responsible for executing Twineedle's second side effect (poison).
jp ExecutePlayerMoveDone
-MultiHitText: ; 3d805 (f:5805)
+MultiHitText: ; 3d977 (f:5977)
TX_FAR _MultiHitText
db "@"
-ExecutePlayerMoveDone: ; 3d80a (f:580a)
+ExecutePlayerMoveDone: ; 3d97c (f:597c)
xor a
ld [wActionResultOrTookBattleTurn],a
ld b,1
ret
-PrintGhostText: ; 3d811 (f:5811)
+PrintGhostText: ; 3d983 (f:5983)
; print the ghost battle messages
call IsGhostBattle
ret nz
@@ -3506,15 +3515,15 @@ PrintGhostText: ; 3d811 (f:5811)
xor a
ret
-ScaredText: ; 3d830 (f:5830)
+ScaredText: ; 3d9a2 (f:59a2)
TX_FAR _ScaredText
db "@"
-GetOutText: ; 3d835 (f:5835)
+GetOutText: ; 3d9a7 (f:59a7)
TX_FAR _GetOutText
db "@"
-IsGhostBattle: ; 3d83a (f:583a)
+IsGhostBattle: ; 3d9ac (f:59ac)
ld a,[wIsInBattle]
dec a
ret nz
@@ -3533,7 +3542,7 @@ IsGhostBattle: ; 3d83a (f:583a)
; checks for various status conditions affecting the player mon
; stores whether the mon cannot use a move this turn in Z flag
-CheckPlayerStatusConditions: ; 3d854 (f:5854)
+CheckPlayerStatusConditions: ; 3d9c6 (f:59c6)
ld hl,wBattleMonStatus
ld a,[hl]
and a,SLP ; sleep mask
@@ -3794,67 +3803,67 @@ CheckPlayerStatusConditions: ; 3d854 (f:5854)
and a
ret
-FastAsleepText: ; 3da3d (f:5a3d)
+FastAsleepText: ; 3dbaf (f:5baf)
TX_FAR _FastAsleepText
db "@"
-WokeUpText: ; 3da42 (f:5a42)
+WokeUpText: ; 3dbb4 (f:5bb4)
TX_FAR _WokeUpText
db "@"
-IsFrozenText: ; 3da47 (f:5a47)
+IsFrozenText: ; 3dbb9 (f:5bb9)
TX_FAR _IsFrozenText
db "@"
-FullyParalyzedText: ; 3da4c (f:5a4c)
+FullyParalyzedText: ; 3dbbe (f:5bbe)
TX_FAR _FullyParalyzedText
db "@"
-FlinchedText: ; 3da51 (f:5a51)
+FlinchedText: ; 3dbc3 (f:5bc3)
TX_FAR _FlinchedText
db "@"
-MustRechargeText: ; 3da56 (f:5a56)
+MustRechargeText: ; 3dbc8 (f:5bc8)
TX_FAR _MustRechargeText
db "@"
-DisabledNoMoreText: ; 3da5b (f:5a5b)
+DisabledNoMoreText: ; 3dbcd (f:5bcd)
TX_FAR _DisabledNoMoreText
db "@"
-IsConfusedText: ; 3da60 (f:5a60)
+IsConfusedText: ; 3dbd2 (f:5bd2)
TX_FAR _IsConfusedText
db "@"
-HurtItselfText: ; 3da65 (f:5a65)
+HurtItselfText: ; 3dbd7 (f:5bd7)
TX_FAR _HurtItselfText
db "@"
-ConfusedNoMoreText: ; 3da6a (f:5a6a)
+ConfusedNoMoreText: ; 3dbdc (f:5bdc)
TX_FAR _ConfusedNoMoreText
db "@"
-SavingEnergyText: ; 3da6f (f:5a6f)
+SavingEnergyText: ; 3dbe1 (f:5be1)
TX_FAR _SavingEnergyText
db "@"
-UnleashedEnergyText: ; 3da74 (f:5a74)
+UnleashedEnergyText: ; 3dbe6 (f:5be6)
TX_FAR _UnleashedEnergyText
db "@"
-ThrashingAboutText: ; 3da79 (f:5a79)
+ThrashingAboutText: ; 3dbeb (f:5beb)
TX_FAR _ThrashingAboutText
db "@"
-AttackContinuesText: ; 3da7e (f:5a7e)
+AttackContinuesText: ; 3dbf0 (f:5bf0)
TX_FAR _AttackContinuesText
db "@"
-CantMoveText: ; 3da83 (f:5a83)
+CantMoveText: ; 3dbf5 (f:5bf5)
TX_FAR _CantMoveText
db "@"
-PrintMoveIsDisabledText: ; 3da88 (f:5a88)
+PrintMoveIsDisabledText: ; 3dbfa (f:5bfa)
ld hl, wPlayerSelectedMove
ld de, wPlayerBattleStatus1
ld a, [H_WHOSETURN]
@@ -3872,11 +3881,11 @@ PrintMoveIsDisabledText: ; 3da88 (f:5a88)
ld hl, MoveIsDisabledText
jp PrintText
-MoveIsDisabledText: ; 3daa8 (f:5aa8)
+MoveIsDisabledText: ; 3dc1a (f:5c1a)
TX_FAR _MoveIsDisabledText
db "@"
-HandleSelfConfusionDamage: ; 3daad (f:5aad)
+HandleSelfConfusionDamage: ; 3dc1f (f:5c1f)
ld hl, HurtItselfText
call PrintText
ld hl, wEnemyMonDefense
@@ -3920,7 +3929,7 @@ HandleSelfConfusionDamage: ; 3daad (f:5aad)
ld [H_WHOSETURN], a
jp ApplyDamageToPlayerPokemon
-PrintMonName1Text: ; 3daf5 (f:5af5)
+PrintMonName1Text: ; 3dc67 (f:5c67)
ld hl, MonName1Text
jp PrintText
@@ -3929,17 +3938,17 @@ PrintMonName1Text: ; 3daf5 (f:5af5)
; those text strings are identical and both continue at PrintInsteadText
; this likely had to do with Japanese grammar that got translated,
; but the functionality didn't get removed
-MonName1Text: ; 3dafb (f:5afb)
+MonName1Text: ; 3dc6d (f:5c6d)
TX_FAR _MonName1Text
TX_ASM
ld a, [H_WHOSETURN]
and a
ld a, [wPlayerMoveNum]
ld hl, wPlayerUsedMove
- jr z, .asm_3db11
+ jr z, .playerTurn
ld a, [wEnemyMoveNum]
ld hl, wEnemyUsedMove
-.asm_3db11
+.playerTurn
ld [hl], a
ld [wd11e], a
call DetermineExclamationPointTextNum
@@ -3954,33 +3963,33 @@ MonName1Text: ; 3dafb (f:5afb)
ld hl, Used1Text
ret
-Used1Text: ; 3db2d (f:5b2d)
+Used1Text: ; 3dc9f (f:5c9f)
TX_FAR _Used1Text
TX_ASM
jr PrintInsteadText
-Used2Text: ; 3db34 (f:5b34)
+Used2Text: ; 3dca6 (f:5ca6)
TX_FAR _Used2Text
TX_ASM
; fall through
-PrintInsteadText: ; 3db39 (f:5b39)
+PrintInsteadText: ; 3dcab (f:5cab)
ld a, [wMonIsDisobedient]
and a
jr z, PrintMoveName
ld hl, InsteadText
ret
-InsteadText: ; 3db43 (f:5b43)
+InsteadText: ; 3dcb5 (f:5cb5)
TX_FAR _InsteadText
TX_ASM
; fall through
-PrintMoveName: ; 3db48 (f:5b48)
+PrintMoveName: ; 3dcba (f:5cba)
ld hl, _PrintMoveName
ret
-_PrintMoveName: ; 3db4c (f:5b4c)
+_PrintMoveName: ; 3dcbe (f:5cbe)
TX_FAR _CF4BText
TX_ASM
ld hl, ExclamationPointPointerTable
@@ -3996,30 +4005,30 @@ _PrintMoveName: ; 3db4c (f:5b4c)
ld l, a
ret
-ExclamationPointPointerTable: ; 3db62 (f:5b62)
+ExclamationPointPointerTable: ; 3dcd4 (f:5cd4)
dw ExclamationPoint1Text
dw ExclamationPoint2Text
dw ExclamationPoint3Text
dw ExclamationPoint4Text
dw ExclamationPoint5Text
-ExclamationPoint1Text: ; 3db6c (f:5b6c)
+ExclamationPoint1Text: ; 3dcde (f:5cde)
TX_FAR _ExclamationPoint1Text
db "@"
-ExclamationPoint2Text: ; 3db71 (f:5b71)
+ExclamationPoint2Text: ; 3dce3 (f:5ce3)
TX_FAR _ExclamationPoint2Text
db "@"
-ExclamationPoint3Text: ; 3db76 (f:5b76)
+ExclamationPoint3Text: ; 3dce8 (f:5ce8)
TX_FAR _ExclamationPoint3Text
db "@"
-ExclamationPoint4Text: ; 3db7b (f:5b7b)
+ExclamationPoint4Text: ; 3dced (f:5ced)
TX_FAR _ExclamationPoint4Text
db "@"
-ExclamationPoint5Text: ; 3db80 (f:5b80)
+ExclamationPoint5Text: ; 3dcf2 (f:5cf2)
TX_FAR _ExclamationPoint5Text
db "@"
@@ -4030,7 +4039,7 @@ ExclamationPoint5Text: ; 3db80 (f:5b80)
; but all five text strings are identical
; this likely had to do with Japanese grammar that got translated,
; but the functionality didn't get removed
-DetermineExclamationPointTextNum: ; 3db85 (f:5b85)
+DetermineExclamationPointTextNum: ; 3dcf7 (f:5cf7)
push bc
ld a, [wd11e] ; move ID
ld c, a
@@ -4052,12 +4061,14 @@ DetermineExclamationPointTextNum: ; 3db85 (f:5b85)
pop bc
ret
-ExclamationPointMoveSets: ; 3dba3 (f:5ba3)
+ExclamationPointMoveSets: ; 3dd15 (f:5d15)
+; a grammar mistake was fixed (only concerning japanese)
+; BIDE is in category 3, moved from category 2
db SWORDS_DANCE, GROWTH
db $00
- db RECOVER, BIDE, SELFDESTRUCT, AMNESIA
+ db RECOVER, SELFDESTRUCT, AMNESIA
db $00
- db MEDITATE, AGILITY, TELEPORT, MIMIC, DOUBLE_TEAM, BARRAGE
+ db MEDITATE, AGILITY, TELEPORT, MIMIC, DOUBLE_TEAM, BIDE, BARRAGE
db $00
db POUND, SCRATCH, VICEGRIP, WING_ATTACK, FLY, BIND, SLAM, HORN_ATTACK, BODY_SLAM
db WRAP, THRASH, TAIL_WHIP, LEER, BITE, GROWL, ROAR, SING, PECK, COUNTER
@@ -4067,7 +4078,7 @@ ExclamationPointMoveSets: ; 3dba3 (f:5ba3)
db $00
db $FF ; terminator
-PrintMoveFailureText: ; 3dbe2 (f:5be2)
+PrintMoveFailureText: ; 3dd54 (f:5d54)
ld de, wPlayerMoveEffect
ld a, [H_WHOSETURN]
and a
@@ -4124,23 +4135,23 @@ PrintMoveFailureText: ; 3dbe2 (f:5be2)
.enemyTurn
jp ApplyDamageToEnemyPokemon
-AttackMissedText: ; 3dc42 (f:5c42)
+AttackMissedText: ; 3ddb4 (f:5db4)
TX_FAR _AttackMissedText
db "@"
-KeptGoingAndCrashedText: ; 3dc47 (f:5c47)
+KeptGoingAndCrashedText: ; 3ddb9 (f:5db9)
TX_FAR _KeptGoingAndCrashedText
db "@"
-UnaffectedText: ; 3dc4c (f:5c4c)
+UnaffectedText: ; 3ddbe (f:5dbe)
TX_FAR _UnaffectedText
db "@"
-PrintDoesntAffectText: ; 3dc51 (f:5c51)
+PrintDoesntAffectText: ; 3ddc3 (f:5dc3)
ld hl, DoesntAffectMonText
jp PrintText
-
-DoesntAffectMonText: ; 3dc57 (f:5c57)
+
+DoesntAffectMonText: ; 3ddc9 (f:5dc9)
TX_FAR _DoesntAffectMonText
db "@"
@@ -5247,7 +5258,7 @@ AttackSubstitute: ; 3e3d0 (f:63d0)
ld a,[H_WHOSETURN]
xor a,$01
ld [H_WHOSETURN],a
- callab HideSubstituteShowMonAnim ; animate the substitute breaking
+ callab Func_79929 ; animate the substitute breaking
; flip the turn back to the way it was
ld a,[H_WHOSETURN]
xor a,$01
@@ -5543,33 +5554,27 @@ AdjustDamageForMoveType: ; 3e517 (f:6517)
jp .loop
.done
ret
-
-; function to tell how effective the type of an enemy attack is on the player's current pokemon
-; this doesn't take into account the effects that dual types can have
-; (e.g. 4x weakness / resistance, weaknesses and resistances canceling)
-; the result is stored in [wTypeEffectiveness]
-; ($05 is not very effective, $10 is neutral, $14 is super effective)
-; as far is can tell, this is only used once in some AI code to help decide which move to use
+
AIGetTypeEffectiveness: ; 3e5bb (f:65bb)
ld a,[wEnemyMoveType]
- ld d,a ; d = type of enemy move
+ ld d,a ; d = type of enemy move
ld hl,wBattleMonType
- ld b,[hl] ; b = type 1 of player's pokemon
+ ld b,[hl] ; b = type 1 of player's pokemon
inc hl
- ld c,[hl] ; c = type 2 of player's pokemon
+ ld c,[hl] ; c = type 2 of player's pokemon
ld a,$10
- ld [wTypeEffectiveness],a ; initialize to neutral effectiveness
+ ld [wd11e],a ; initialize [wd11e] to neutral effectiveness
ld hl,TypeEffects
.loop
ld a,[hli]
cp a,$ff
ret z
- cp d ; match the type of the move
+ cp d ; match the type of the move
jr nz,.nextTypePair1
ld a,[hli]
- cp b ; match with type 1 of pokemon
+ cp b ; match with type 1 of pokemon
jr z,.done
- cp c ; or match with type 2 of pokemon
+ cp c ; or match with type 2 of pokemon
jr z,.done
jr .nextTypePair2
.nextTypePair1
@@ -5577,9 +5582,21 @@ AIGetTypeEffectiveness: ; 3e5bb (f:65bb)
.nextTypePair2
inc hl
jr .loop
+
.done
+ ld a, [wTrainerClass]
+ cp LORELEI
+ jr nz, .ok
+ ld a, [wEnemyMonSpecies]
+ cp DEWGONG
+ jr nz, .ok
+ call BattleRandom
+ cp $66 ; 40 percent
+ ret c
+.ok
+
ld a,[hl]
- ld [wTypeEffectiveness],a ; store damage multiplier
+ ld [wd11e],a ; store damage multiplier
ret
INCLUDE "data/type_effects.asm"
@@ -6558,10 +6575,13 @@ SwapPlayerAndEnemyLevels: ; 3ee07 (f:6e07)
; (for use when scrolling the player sprite and enemy's silhouettes on screen)
LoadPlayerBackPic: ; 3ee18 (f:6e18)
ld a, [wBattleType]
- dec a ; is it the old man tutorial?
- ld de, RedPicBack
- jr nz, .next
ld de, OldManPic
+ cp OLD_MAN_BATTLE ; is it the old man tutorial?
+ jr z, .next
+ ld de, ProfOakPicBack
+ cp STARTER_PIKACHU_BATTLE ; is it the pikachu battle at the beginning of the game?
+ jr z, .next
+ ld de, RedPicBack
.next
ld a, BANK(RedPicBack)
call UncompressSpriteFromDE
@@ -6586,6 +6606,8 @@ LoadPlayerBackPic: ; 3ee18 (f:6e18)
ld [hli], a ; OAM tile number
inc a ; increment tile number
ld [hOAMTile], a
+ ld a, $2
+ ld [hl], a
inc hl
dec c
jr nz, .innerLoop
@@ -6599,18 +6621,15 @@ LoadPlayerBackPic: ; 3ee18 (f:6e18)
jr nz, .loop
ld de, vBackPic
call InterlaceMergeSpriteBuffers
- ld a, $a
- ld [$0], a
- xor a
- ld [$4000], a
+ ld a, $0
+ call SwitchSRAMBankAndLatchClockData
ld hl, vSprites
ld de, S_SPRITEBUFFER1
ld a, [H_LOADEDROMBANK]
ld b, a
ld c, 7 * 7
call CopyVideoData
- xor a
- ld [$0], a
+ call PrepareRTCDataAndDisableSRAM
ld a, $31
ld [hStartTileID], a
coord hl, 1, 5
@@ -7096,7 +7115,7 @@ MoveEffectPointerTable: ; 3f0c5 (f:70c5)
dw SplashEffect ; SPLASH_EFFECT
dw DisableEffect ; DISABLE_EFFECT
-SleepEffect: ; 3f1fc (f:71fc)
+SleepEffect: ; 3f171 (f:7171)
ld de, wEnemyMonStatus
ld bc, wEnemyBattleStatus2
ld a, [H_WHOSETURN]
@@ -7133,6 +7152,16 @@ SleepEffect: ; 3f1fc (f:71fc)
call BattleRandom
and $7
jr z, .setSleepCounter
+ ld b, a
+ ld a, [wUnknownSerialFlag_d499]
+ and a
+ jr z, .asm_3f1ba ; XXX stadium stuff?
+ ld a, b
+ and $3
+ jr z, .setSleepCounter
+ ld b, a
+.asm_3f1ba
+ ld a, b
ld [de], a
call PlayCurrentMoveAnimation2
ld hl, FellAsleepText
@@ -7140,15 +7169,15 @@ SleepEffect: ; 3f1fc (f:71fc)
.didntAffect
jp PrintDidntAffectText
-FellAsleepText: ; 3f245 (f:7245)
+FellAsleepText: ; 3f1c8 (f:71c8)
TX_FAR _FellAsleepText
db "@"
-AlreadyAsleepText: ; 3f24a (f:724a)
+AlreadyAsleepText: ; 3f1cd (f:71cds)
TX_FAR _AlreadyAsleepText
db "@"
-PoisonEffect: ; 3f24f (f:724f)
+PoisonEffect: ; 3f1d2 (f:71d2)
ld hl, wEnemyMonStatus
ld de, wPlayerMoveEffect
ld a, [H_WHOSETURN]
@@ -7211,18 +7240,18 @@ PoisonEffect: ; 3f24f (f:724f)
xor a
ld [de], a
ld hl, BadlyPoisonedText
- jr .asm_3f2c0
+ jr .continue
.normalPoison
ld hl, PoisonedText
-.asm_3f2c0
+.continue
pop de
ld a, [de]
cp POISON_EFFECT
- jr z, .asm_3f2cd
+ jr z, .regularPoisonEffect
ld a, b
call PlayBattleAnimation2
jp PrintText
-.asm_3f2cd
+.regularPoisonEffect
call PlayCurrentMoveAnimation2
jp PrintText
.noEffect
@@ -7234,18 +7263,18 @@ PoisonEffect: ; 3f24f (f:724f)
call DelayFrames
jp PrintDidntAffectText
-PoisonedText: ; 3f2df (f:72df)
+PoisonedText: ; 3f262 (f:7262)
TX_FAR _PoisonedText
db "@"
-BadlyPoisonedText: ; 3f2e4 (f:72e4)
+BadlyPoisonedText: ; 3f267 (f:7267)
TX_FAR _BadlyPoisonedText
db "@"
-DrainHPEffect: ; 3f2e9 (f:72e9)
+DrainHPEffect: ; 3f26c (f:726c)
jpab DrainHPEffect_
-ExplodeEffect: ; 3f2f1 (f:72f1)
+ExplodeEffect: ; 3f274 (f:7274)
ld hl, wBattleMonHP
ld de, wPlayerBattleStatus2
ld a, [H_WHOSETURN]
@@ -7264,14 +7293,14 @@ ExplodeEffect: ; 3f2f1 (f:72f1)
ld [de], a
ret
-FreezeBurnParalyzeEffect: ; 3f30c (f:730c)
+FreezeBurnParalyzeEffect: ; 3f28f (f:728f)
xor a
ld [wAnimationType], a
call CheckTargetSubstitute ; test bit 4 of d063/d068 flags [target has substitute flag]
ret nz ; return if they have a substitute, can't effect them
ld a, [H_WHOSETURN]
and a
- jp nz, opponentAttacker
+ jp nz, .opponentAttacker
ld a, [wEnemyMonStatus]
and a
jp nz, CheckDefrost ; can't inflict status if opponent is already statused
@@ -7284,6 +7313,16 @@ FreezeBurnParalyzeEffect: ; 3f30c (f:730c)
cp b ; do target type 2 and move type match?
ret z ; return if they match
ld a, [wPlayerMoveEffect]
+ cp UNUSED_EFFECT_23 ; more stadium stuff
+ jr nz, .asm_3f2c7
+ ld a, [wUnknownSerialFlag_d499]
+ and a
+ ld a, FREEZE_SIDE_EFFECT
+ ld b, $4d ; else use 0x4D/0x100 or 77/256 = 30.1%~ chance
+ jr z, .next1
+ ld b, $1a ; 0x1A/0x100 or 26/256 = 10.2%~ chance
+ jr .next1
+.asm_3f2c7
cp a, PARALYZE_SIDE_EFFECT1 + 1 ; 10% status effects are 04, 05, 06 so 07 will set carry for those
ld b, $1a ; 0x1A/0x100 or 26/256 = 10.2%~ chance
jr c, .next1 ; branch ahead if this is a 10% chance effect..
@@ -7297,9 +7336,9 @@ FreezeBurnParalyzeEffect: ; 3f30c (f:730c)
ret nc ; do nothing if random value is >= 1A or 4D [no status applied]
ld a, b ; what type of effect is this?
cp a, BURN_SIDE_EFFECT1
- jr z, .burn
+ jr z, .burn1
cp a, FREEZE_SIDE_EFFECT
- jr z, .freeze
+ jr z, .freeze1
; .paralyze
ld a, 1 << PAR
ld [wEnemyMonStatus], a
@@ -7307,7 +7346,7 @@ FreezeBurnParalyzeEffect: ; 3f30c (f:730c)
ld a, ANIM_A9
call PlayBattleAnimation
jp PrintMayNotAttackText ; print paralysis text
-.burn
+.burn1
ld a, 1 << BRN
ld [wEnemyMonStatus], a
call HalveAttackDueToBurn ; halve attack of affected mon
@@ -7315,7 +7354,7 @@ FreezeBurnParalyzeEffect: ; 3f30c (f:730c)
call PlayBattleAnimation
ld hl, BurnedText
jp PrintText
-.freeze
+.freeze1
call ClearHyperBeam ; resets hyper beam (recharge) condition from target
ld a, 1 << FRZ
ld [wEnemyMonStatus], a
@@ -7323,7 +7362,7 @@ FreezeBurnParalyzeEffect: ; 3f30c (f:730c)
call PlayBattleAnimation
ld hl, FrozenText
jp PrintText
-opponentAttacker: ; 3f382 (f:7382)
+.opponentAttacker ; 3f382 (f:7382)
ld a, [wBattleMonStatus] ; mostly same as above with addresses swapped for opponent
and a
jp nz, CheckDefrost
@@ -7336,12 +7375,22 @@ opponentAttacker: ; 3f382 (f:7382)
cp b
ret z
ld a, [wEnemyMoveEffect]
+ cp UNUSED_EFFECT_23 ; more stadium stuff
+ jr nz, .asm_3f341
+ ld a, [wUnknownSerialFlag_d499]
+ and a
+ ld a, FREEZE_SIDE_EFFECT
+ ld b, $4d ; else use 0x4D/0x100 or 77/256 = 30.1%~ chance
+ jr z, .next2
+ ld b, $1a ; 0x1A/0x100 or 26/256 = 10.2%~ chance
+ jr .next2
+.asm_3f341
cp a, PARALYZE_SIDE_EFFECT1 + 1
ld b, $1a
- jr c, .next1
+ jr c, .next2
ld b, $4d
sub a, $1e
-.next1
+.next2
push af
call BattleRandom
cp b
@@ -7349,35 +7398,41 @@ opponentAttacker: ; 3f382 (f:7382)
ret nc
ld a, b
cp a, BURN_SIDE_EFFECT1
- jr z, .burn
+ jr z, .burn2
cp a, FREEZE_SIDE_EFFECT
- jr z, .freeze
+ jr z, .freeze2
ld a, 1 << PAR
ld [wBattleMonStatus], a
call QuarterSpeedDueToParalysis
+ ld a, ANIM_C7
+ call PlayBattleAnimation2
jp PrintMayNotAttackText
-.burn
+.burn2
ld a, 1 << BRN
ld [wBattleMonStatus], a
call HalveAttackDueToBurn
+ ld a, ANIM_C7
+ call PlayBattleAnimation2
ld hl, BurnedText
jp PrintText
-.freeze
+.freeze2
; hyper beam bits aren't reseted for opponent's side
ld a, 1 << FRZ
ld [wBattleMonStatus], a
+ ld a, ANIM_C7
+ call PlayBattleAnimation2
ld hl, FrozenText
jp PrintText
-BurnedText: ; 3f3d8 (f:73d8)
+BurnedText: ; 3f38e (f:738e)
TX_FAR _BurnedText
db "@"
-FrozenText: ; 3f3dd (f:73dd)
+FrozenText: ; 3f393 (f:7393)
TX_FAR _FrozenText
db "@"
-CheckDefrost: ; 3f3e2 (f:73e2)
+CheckDefrost: ; 3f398 (f:7398)
; any fire-type move that has a chance inflict burn (all but Fire Spin) will defrost a frozen target
and a, 1 << FRZ ; are they frozen?
ret z ; return if so
@@ -7412,11 +7467,11 @@ CheckDefrost: ; 3f3e2 (f:73e2)
.common
jp PrintText
-FireDefrostedText: ; 3f423 (f:7423)
+FireDefrostedText: ; 3f3d9 (f:73d9)
TX_FAR _FireDefrostedText
db "@"
-StatModifierUpEffect: ; 3f428 (f:7428)
+StatModifierUpEffect: ; 3f3de (f:73de)
ld hl, wPlayerMonStatMods
ld de, wPlayerMoveEffect
ld a, [H_WHOSETURN]
@@ -7515,13 +7570,13 @@ StatModifierUpEffect: ; 3f428 (f:7428)
ld a, 999 % $100
ld [H_MULTIPLICAND + 2], a
-UpdateStat: ; 3f4c3 (f:74c3)
+UpdateStat: ; 3f479 (f:7479)
ld a, [H_PRODUCT + 2]
ld [hli], a
ld a, [H_PRODUCT + 3]
ld [hl], a
pop hl
-UpdateStatDone: ; 3f4ca (f:74ca)
+UpdateStatDone: ; 3f480 (f:7480)
ld b, c
inc b
call PrintStatText
@@ -7530,25 +7585,25 @@ UpdateStatDone: ; 3f4ca (f:74ca)
ld bc, wPlayerMonMinimized
ld a, [H_WHOSETURN]
and a
- jr z, .asm_3f4e6
+ jr z, .playerTurn
ld hl, wEnemyBattleStatus2
ld de, wEnemyMoveNum
ld bc, wEnemyMonMinimized
-.asm_3f4e6
+.playerTurn
ld a, [de]
cp MINIMIZE
- jr nz, .asm_3f4f9
+ jr nz, .notMinimize
; if a substitute is up, slide off the substitute and show the mon pic before
; playing the minimize animation
bit HasSubstituteUp, [hl]
push af
push bc
+ push de
ld hl, HideSubstituteShowMonAnim
ld b, BANK(HideSubstituteShowMonAnim)
- push de
call nz, Bankswitch
pop de
-.asm_3f4f9
+.notMinimize
call PlayCurrentMoveAnimation
ld a, [de]
cp MINIMIZE
@@ -7572,38 +7627,38 @@ UpdateStatDone: ; 3f4ca (f:74ca)
call QuarterSpeedDueToParalysis ; apply speed penalty to the player whose turn is not, if it's paralyzed
jp HalveAttackDueToBurn ; apply attack penalty to the player whose turn is not, if it's burned
-RestoreOriginalStatModifier: ; 3f520 (f:7520)
+RestoreOriginalStatModifier: ; 3f4d6 (f:74d6)
pop hl
dec [hl]
-PrintNothingHappenedText: ; 3f522 (f:7522)
+PrintNothingHappenedText: ; 3f4d8 (f:74d8)
ld hl, NothingHappenedText
jp PrintText
-MonsStatsRoseText: ; 3f528 (f:7528)
+MonsStatsRoseText: ; 3f4de (f:74de)
TX_FAR _MonsStatsRoseText
TX_ASM
ld hl, GreatlyRoseText
ld a, [H_WHOSETURN]
and a
ld a, [wPlayerMoveEffect]
- jr z, .asm_3f53b
+ jr z, .playerTurn
ld a, [wEnemyMoveEffect]
-.asm_3f53b
+.playerTurn
cp ATTACK_DOWN1_EFFECT
ret nc
ld hl, RoseText
ret
-GreatlyRoseText: ; 3f542 (f:7542)
+GreatlyRoseText: ; 3f4f8 (f:74f8)
db $0a
TX_FAR _GreatlyRoseText
-
-RoseText: ; 3f547 (f:7547)
+; fallthrough
+RoseText: ; 3f4fd (f:74fd)
TX_FAR _RoseText
db "@"
-StatModifierDownEffect: ; 3f54c (f:754c)
+StatModifierDownEffect: ; 3f502 (f:7502)
ld hl, wEnemyMonStatMods
ld de, wPlayerMoveEffect
ld bc, wEnemyBattleStatus1
@@ -7687,9 +7742,9 @@ StatModifierDownEffect: ; 3f54c (f:754c)
ld a, c
add e
ld e, a
- jr nc, .asm_3f5e4
+ jr nc, .noCarry
inc d ; de = unmodified stat
-.asm_3f5e4
+.noCarry
pop bc
ld a, [hld]
sub $1 ; can't lower stat below 1 (-6)
@@ -7733,14 +7788,14 @@ StatModifierDownEffect: ; 3f54c (f:754c)
ld a, $1
ld [H_MULTIPLICAND + 2], a
-UpdateLoweredStat: ; 3f624 (f:7624)
+UpdateLoweredStat: ; 3f5da (f:75da)
ld a, [H_PRODUCT + 2]
ld [hli], a
ld a, [H_PRODUCT + 3]
ld [hl], a
pop de
pop hl
-UpdateLoweredStatDone: ; 3f62c (f:762c)
+UpdateLoweredStatDone: ; 3f5e2 (f:75e2)
ld b, c
inc b
push de
@@ -7764,66 +7819,67 @@ UpdateLoweredStatDone: ; 3f62c (f:762c)
call QuarterSpeedDueToParalysis
jp HalveAttackDueToBurn
-CantLowerAnymore_Pop: ; 3f64d (f:764d)
+CantLowerAnymore_Pop: ; 3f603 (f:7603)
pop de
pop hl
inc [hl]
-CantLowerAnymore: ; 3f650 (f:7650)
+CantLowerAnymore: ; 3f606 (f:7606)
ld a, [de]
cp ATTACK_DOWN_SIDE_EFFECT
ret nc
ld hl, NothingHappenedText
jp PrintText
-MoveMissed: ; 3f65a (f:765a)
+MoveMissed: ; 3f610 (f:7610)
ld a, [de]
cp $44
ret nc
jp ConditionalPrintButItFailed
-MonsStatsFellText: ; 3f661 (f:7661)
+MonsStatsFellText: ; 3f617 (f:7617)
TX_FAR _MonsStatsFellText
TX_ASM
ld hl, FellText
ld a, [H_WHOSETURN]
and a
ld a, [wPlayerMoveEffect]
- jr z, .asm_3f674
+ jr z, .playerTurn
ld a, [wEnemyMoveEffect]
-.asm_3f674
- cp $1a
+.playerTurn
+; check if the move's effect decreases a stat by 2
+ cp BIDE_EFFECT
ret c
- cp $44
+ cp ATTACK_DOWN_SIDE_EFFECT
ret nc
ld hl, GreatlyFellText
ret
-GreatlyFellText: ; 3f67e (f:767e)
+GreatlyFellText: ; 3f634 (f:7634)
db $0a
TX_FAR _GreatlyFellText
-
-FellText: ; 3f683 (f:7683)
+; fallthrough
+FellText: ; 3f639 (f:7639)
TX_FAR _FellText
db "@"
-PrintStatText: ; 3f688 (f:7688)
+PrintStatText: ; 3f63e (f:763e)
ld hl, StatsTextStrings
ld c, "@"
-.asm_3f68d
+.findStatName_outer
dec b
- jr z, .asm_3f696
-.asm_3f690
+ jr z, .foundStatName
+.findStatName_inner
ld a, [hli]
cp c
- jr z, .asm_3f68d
- jr .asm_3f690
-.asm_3f696
+ jr z, .findStatName_outer
+ jr .findStatName_inner
+.foundStatName
ld de, wcf4b
ld bc, $a
jp CopyData
-StatsTextStrings: ; 3f69f (f:769f)
+StatsTextStrings: ; 3f655 (f:7655)
db "ATTACK@"
db "DEFENSE@"
db "SPEED@"
@@ -7831,7 +7887,7 @@ StatsTextStrings: ; 3f69f (f:769f)
db "ACCURACY@"
db "EVADE@"
-StatModifierRatios: ; 3f6cb (f:76cb)
+StatModifierRatios: ; 3f681 (f:7681)
; first byte is numerator, second byte is denominator
db 25, 100 ; 0.25
db 28, 100 ; 0.28
@@ -7847,7 +7903,7 @@ StatModifierRatios: ; 3f6cb (f:76cb)
db 35, 10 ; 3.50
db 4, 1 ; 4.00
-BideEffect: ; 3f6e5 (f:76e5)
+BideEffect: ; 3f69b (f:769b)
ld hl, wPlayerBattleStatus1
ld de, wPlayerBideAccumulatedDamage
ld bc, wPlayerNumAttacksLeft
@@ -7874,7 +7930,7 @@ BideEffect: ; 3f6e5 (f:76e5)
add XSTATITEM_ANIM
jp PlayBattleAnimation2
-ThrashPetalDanceEffect: ; 3f717 (f:7717)
+ThrashPetalDanceEffect: ; 3f7cd (f:77cd)
ld hl, wPlayerBattleStatus1
ld de, wPlayerNumAttacksLeft
ld a, [H_WHOSETURN]
@@ -7893,44 +7949,45 @@ ThrashPetalDanceEffect: ; 3f717 (f:7717)
add ANIM_B0
jp PlayBattleAnimation2
-SwitchAndTeleportEffect: ; 3f739 (f:7739)
+SwitchAndTeleportEffect: ; 3f6ef (f:76ef)
ld a, [H_WHOSETURN]
and a
- jr nz, .asm_3f791
+ jr nz, .handleEnemy
ld a, [wIsInBattle]
dec a
- jr nz, .asm_3f77e
+ jr nz, .notWildBattle1
ld a, [wCurEnemyLVL]
ld b, a
ld a, [wBattleMonLevel]
- cp b
- jr nc, .asm_3f76e
+ cp b ; is the player's level greater than the enemy's level?
+ jr nc, .playerMoveWasSuccessful ; if so, teleport will always succeed
add b
ld c, a
- inc c
-.asm_3f751
+ inc c ; c = sum of player level and enemy level
+.rejectionSampleLoop1
call BattleRandom
- cp c
- jr nc, .asm_3f751
+ cp c ; get a random number between 0 and c
+ jr nc, .rejectionSampleLoop1
srl b
- srl b
- cp b
- jr nc, .asm_3f76e
+ srl b ; b = enemy level * 4
+; bug: does not account for overflow, so levels above 63 can lead to erroneousness results
+ cp b ; is rand[0, playerLevel + enemyLevel] > enemyLevel?
+ jr nc, .playerMoveWasSuccessful ; if so, allow teleporting
ld c, 50
call DelayFrames
ld a, [wPlayerMoveNum]
cp TELEPORT
jp nz, PrintDidntAffectText
jp PrintButItFailedText_
-.asm_3f76e
+.playerMoveWasSuccessful
call ReadPlayerMonCurHPAndStatus
xor a
ld [wAnimationType], a
inc a
ld [wEscapedFromBattle], a
ld a, [wPlayerMoveNum]
- jr .asm_3f7e4
-.asm_3f77e
+ jr .playAnimAndPrintText
+.notWildBattle1
ld c, 50
call DelayFrames
ld hl, IsUnaffectedText
@@ -7938,41 +7995,41 @@ SwitchAndTeleportEffect: ; 3f739 (f:7739)
cp TELEPORT
jp nz, PrintText
jp PrintButItFailedText_
-.asm_3f791
+.handleEnemy
ld a, [wIsInBattle]
dec a
- jr nz, .asm_3f7d1
+ jr nz, .notWildBattle2
ld a, [wBattleMonLevel]
ld b, a
ld a, [wCurEnemyLVL]
cp b
- jr nc, .asm_3f7c1
+ jr nc, .enemyMoveWasSuccessful
add b
ld c, a
inc c
-.asm_3f7a4
+.rejectionSampleLoop2
call BattleRandom
cp c
- jr nc, .asm_3f7a4
+ jr nc, .rejectionSampleLoop2
srl b
srl b
cp b
- jr nc, .asm_3f7c1
+ jr nc, .enemyMoveWasSuccessful
ld c, 50
call DelayFrames
ld a, [wEnemyMoveNum]
cp TELEPORT
jp nz, PrintDidntAffectText
jp PrintButItFailedText_
-.asm_3f7c1
+.enemyMoveWasSuccessful
call ReadPlayerMonCurHPAndStatus
xor a
ld [wAnimationType], a
inc a
ld [wEscapedFromBattle], a
ld a, [wEnemyMoveNum]
- jr .asm_3f7e4
-.asm_3f7d1
+ jr .playAnimAndPrintText
+.notWildBattle2
ld c, 50
call DelayFrames
ld hl, IsUnaffectedText
@@ -7980,7 +8037,7 @@ SwitchAndTeleportEffect: ; 3f739 (f:7739)
cp TELEPORT
jp nz, PrintText
jp ConditionalPrintButItFailed
-.asm_3f7e4
+.playAnimAndPrintText
push af
call PlayBattleAnimation
ld c, 20
@@ -7988,27 +8045,27 @@ SwitchAndTeleportEffect: ; 3f739 (f:7739)
pop af
ld hl, RanFromBattleText
cp TELEPORT
- jr z, .asm_3f7ff
+ jr z, .printText
ld hl, RanAwayScaredText
cp ROAR
- jr z, .asm_3f7ff
+ jr z, .printText
ld hl, WasBlownAwayText
-.asm_3f7ff
+.printText
jp PrintText
-RanFromBattleText: ; 3f802 (f:7802)
+RanFromBattleText: ; 3f7b8 (f:77b8)
TX_FAR _RanFromBattleText
db "@"
-RanAwayScaredText: ; 3f807 (f:7807)
+RanAwayScaredText: ; 3f7bd (f:77bd)
TX_FAR _RanAwayScaredText
db "@"
-WasBlownAwayText: ; 3f80c (f:780c)
+WasBlownAwayText: ; 3f7c2 (f:77c2)
TX_FAR _WasBlownAwayText
db "@"
-TwoToFiveAttacksEffect: ; 3f811 (f:7811)
+TwoToFiveAttacksEffect: ; 3f7c7 (f:77c7)
ld hl, wPlayerBattleStatus1
ld de, wPlayerNumAttacksLeft
ld bc, wPlayerNumHits
@@ -8038,10 +8095,11 @@ TwoToFiveAttacksEffect: ; 3f811 (f:7811)
call BattleRandom
and $3
cp $2
- jr c, .asm_3f851
+ jr c, .gotNumHits
+; if the number of hits was greater than 2, re-roll again for a lower chance
call BattleRandom
and $3
-.asm_3f851
+.gotNumHits
inc a
inc a
.saveNumberOfHits
@@ -8053,7 +8111,7 @@ TwoToFiveAttacksEffect: ; 3f811 (f:7811)
ld [hl], a ; set Twineedle's effect to poison effect
jr .saveNumberOfHits
-FlinchSideEffect: ; 3f85b (f:785b)
+FlinchSideEffect: ; 3f811 (f:7811)
call CheckTargetSubstitute
ret nz
ld hl, wEnemyBattleStatus1
@@ -8064,6 +8122,9 @@ FlinchSideEffect: ; 3f85b (f:785b)
ld hl, wPlayerBattleStatus1
ld de, wEnemyMoveEffect
.flinchSideEffect
+ ld a, [wLinkState]
+ cp LINK_STATE_BATTLING
+ call z, ClearHyperBeam
ld a, [de]
cp FLINCH_SIDE_EFFECT1
ld b, $1a ; ~10% chance of flinch
@@ -8077,10 +8138,10 @@ FlinchSideEffect: ; 3f85b (f:785b)
call ClearHyperBeam
ret
-OneHitKOEffect: ; 3f884 (f:7884)
+OneHitKOEffect: ; 3f842 (f:7842)
jpab OneHitKOEffect_
-ChargeEffect: ; 3f88c (f:788c)
+ChargeEffect: ; 3f84a (f:784a)
ld hl, wPlayerBattleStatus1
ld de, wPlayerMoveEffect
ld a, [H_WHOSETURN]
@@ -8105,64 +8166,81 @@ ChargeEffect: ; 3f88c (f:788c)
set Invulnerable, [hl] ; mon is now invulnerable to typical attacks (fly/dig)
ld b, ANIM_C0
.notDigOrFly
+ push de
+ push bc
+ inc hl ; battle status 2
+ push hl
+ ld a, [hl]
+ bit HasSubstituteUp, a
+ ld hl, HideSubstituteShowMonAnim
+ ld b, BANK(HideSubstituteShowMonAnim)
+ call nz, Bankswitch
+ pop hl
+ pop bc
xor a
ld [wAnimationType], a
ld a, b
call PlayBattleAnimation
+ ld a, [hl]
+ bit HasSubstituteUp, a
+ ld hl, ReshowSubstituteAnim
+ ld b, BANK(ReshowSubstituteAnim)
+ call nz, Bankswitch
+ pop de
ld a, [de]
ld [wChargeMoveNum], a
ld hl, ChargeMoveEffectText
jp PrintText
-ChargeMoveEffectText: ; 3f8c8 (f:78c8)
+ChargeMoveEffectText: ; 3f8a3 (f:78a3)
TX_FAR _ChargeMoveEffectText
TX_ASM
ld a, [wChargeMoveNum]
cp RAZOR_WIND
ld hl, MadeWhirlwindText
- jr z, .asm_3f8f8
+ jr z, .gotText
cp SOLARBEAM
ld hl, TookInSunlightText
- jr z, .asm_3f8f8
+ jr z, .gotText
cp SKULL_BASH
ld hl, LoweredItsHeadText
- jr z, .asm_3f8f8
+ jr z, .gotText
cp SKY_ATTACK
ld hl, SkyAttackGlowingText
- jr z, .asm_3f8f8
+ jr z, .gotText
cp FLY
ld hl, FlewUpHighText
- jr z, .asm_3f8f8
+ jr z, .gotText
cp DIG
ld hl, DugAHoleText
-.asm_3f8f8
+.gotText
ret
-MadeWhirlwindText: ; 3f8f9 (f:78f9)
+MadeWhirlwindText: ; 3f8d4 (f:78d4)
TX_FAR _MadeWhirlwindText
db "@"
-TookInSunlightText: ; 3f8fe (f:78fe)
+TookInSunlightText: ; 3f8d9 (f:78d9)
TX_FAR _TookInSunlightText
db "@"
-LoweredItsHeadText: ; 3f903 (f:7903)
+LoweredItsHeadText: ; 3f8de (f:78de)
TX_FAR _LoweredItsHeadText
db "@"
-SkyAttackGlowingText: ; 3f908 (f:7908)
+SkyAttackGlowingText: ; 3f8e3 (f:78e3)
TX_FAR _SkyAttackGlowingText
db "@"
-FlewUpHighText: ; 3f90d (f:790d)
+FlewUpHighText: ; 3f8e8 (f:78e8)
TX_FAR _FlewUpHighText
db "@"
-DugAHoleText: ; 3f912 (f:7912)
+DugAHoleText: ; 3f8ed (f:78ed)
TX_FAR _DugAHoleText
db "@"
-TrappingEffect: ; 3f917 (f:7917)
+TrappingEffect: ; 3f8f2 (f:78f2)
ld hl, wPlayerBattleStatus1
ld de, wPlayerNumAttacksLeft
ld a, [H_WHOSETURN]
@@ -8187,22 +8265,22 @@ TrappingEffect: ; 3f917 (f:7917)
ld [de], a
ret
-MistEffect: ; 3f941 (f:7941)
+MistEffect: ; 3f91c (f:791c)
jpab MistEffect_
-FocusEnergyEffect: ; 3f949 (f:7949)
+FocusEnergyEffect: ; 3f924 (f:7924)
jpab FocusEnergyEffect_
-RecoilEffect: ; 3f951 (f:7951)
+RecoilEffect: ; 3f92c (f:792c)
jpab RecoilEffect_
-ConfusionSideEffect: ; 3f959 (f:7959)
+ConfusionSideEffect: ; 3f934 (f:7934)
call BattleRandom
- cp $19
+ cp $19 ; ~10% chance
ret nc
jr ConfusionSideEffectSuccess
-ConfusionEffect: ; 3f961 (f:7961)
+ConfusionEffect: ; 3f93c (f:793c)
call CheckTargetSubstitute
jr nz, ConfusionEffectFailed
call MoveHitTest
@@ -8210,7 +8288,7 @@ ConfusionEffect: ; 3f961 (f:7961)
and a
jr nz, ConfusionEffectFailed
-ConfusionSideEffectSuccess: ; 3f96f (f:796f)
+ConfusionSideEffectSuccess: ; 3f94a (f:794a)
ld a, [H_WHOSETURN]
and a
ld hl, wEnemyBattleStatus1
@@ -8236,24 +8314,24 @@ ConfusionSideEffectSuccess: ; 3f96f (f:796f)
ld hl, BecameConfusedText
jp PrintText
-BecameConfusedText: ; 3f9a1 (f:79a1)
+BecameConfusedText: ; 3f97c (f:797c)
TX_FAR _BecameConfusedText
db "@"
-ConfusionEffectFailed: ; 3f9a6 (f:79a6)
+ConfusionEffectFailed: ; 3f981 (f:7981)
cp CONFUSION_SIDE_EFFECT
ret z
ld c, 50
call DelayFrames
jp ConditionalPrintButItFailed
-ParalyzeEffect: ; 3f9b1 (f:79b1)
+ParalyzeEffect: ; 3f98c (f:798c)
jpab ParalyzeEffect_
-SubstituteEffect: ; 3f9b9 (f:79b9)
+SubstituteEffect: ; 3f994 (f:7994)
jpab SubstituteEffect_
-HyperBeamEffect: ; 3f9c1 (f:79c1)
+HyperBeamEffect: ; 3f99c (f:799c)
ld hl, wPlayerBattleStatus2
ld a, [H_WHOSETURN]
and a
@@ -8263,19 +8341,19 @@ HyperBeamEffect: ; 3f9c1 (f:79c1)
set NeedsToRecharge, [hl] ; mon now needs to recharge
ret
-ClearHyperBeam: ; 3f9cf (f:79cf)
+ClearHyperBeam: ; 3f9aa (f:79aa)
push hl
ld hl, wEnemyBattleStatus2
ld a, [H_WHOSETURN]
and a
- jr z, .asm_3f9db
+ jr z, .playerTurn
ld hl, wPlayerBattleStatus2
-.asm_3f9db
+.playerTurn
res NeedsToRecharge, [hl] ; mon no longer needs to recharge
pop hl
ret
-RageEffect: ; 3f9df (f:79df)
+RageEffect: ; 3f9ba (f:79ba)
ld hl, wPlayerBattleStatus2
ld a, [H_WHOSETURN]
and a
@@ -8285,27 +8363,27 @@ RageEffect: ; 3f9df (f:79df)
set UsingRage, [hl] ; mon is now in "rage" mode
ret
-MimicEffect: ; 3f9ed (f:79ed)
+MimicEffect: ; 3f9c8 (f:79c8)
ld c, 50
call DelayFrames
call MoveHitTest
ld a, [wMoveMissed]
and a
- jr nz, .asm_3fa74
+ jr nz, .mimicMissed
ld a, [H_WHOSETURN]
and a
ld hl, wBattleMonMoves
ld a, [wPlayerBattleStatus1]
- jr nz, .asm_3fa13
+ jr nz, .enemyTurn
ld a, [wLinkState]
cp LINK_STATE_BATTLING
- jr nz, .asm_3fa3a
+ jr nz, .letPlayerChooseMove
ld hl, wEnemyMonMoves
ld a, [wEnemyBattleStatus1]
-.asm_3fa13
+.enemyTurn
bit Invulnerable, a
- jr nz, .asm_3fa74
-.asm_3fa17
+ jr nz, .mimicMissed
+.getRandomMove
push hl
call BattleRandom
and $3
@@ -8315,20 +8393,20 @@ MimicEffect: ; 3f9ed (f:79ed)
ld a, [hl]
pop hl
and a
- jr z, .asm_3fa17
+ jr z, .getRandomMove
ld d, a
ld a, [H_WHOSETURN]
and a
ld hl, wBattleMonMoves
ld a, [wPlayerMoveListIndex]
- jr z, .asm_3fa5f
+ jr z, .playerTurn
ld hl, wEnemyMonMoves
ld a, [wEnemyMoveListIndex]
- jr .asm_3fa5f
-.asm_3fa3a
+ jr .playerTurn
+.letPlayerChooseMove
ld a, [wEnemyBattleStatus1]
bit Invulnerable, a
- jr nz, .asm_3fa74
+ jr nz, .mimicMissed
ld a, [wCurrentMenuItem]
push af
ld a, $1
@@ -8343,7 +8421,7 @@ MimicEffect: ; 3f9ed (f:79ed)
ld d, [hl]
pop af
ld hl, wBattleMonMoves
-.asm_3fa5f
+.playerTurn
ld c, a
ld b, $0
add hl, bc
@@ -8354,21 +8432,21 @@ MimicEffect: ; 3f9ed (f:79ed)
call PlayCurrentMoveAnimation
ld hl, MimicLearnedMoveText
jp PrintText
-.asm_3fa74
+.mimicMissed
jp PrintButItFailedText_
-MimicLearnedMoveText: ; 3fa77 (f:7a77)
+MimicLearnedMoveText: ; 3fa52 (f:7a52)
TX_FAR _MimicLearnedMoveText
db "@"
-LeechSeedEffect: ; 3fa7c (f:7a7c)
+LeechSeedEffect: ; 3fa57 (f:7a57)
jpab LeechSeedEffect_
-SplashEffect: ; 3fa84 (f:7a84)
+SplashEffect: ; 3fa5f (f:7a5f)
call PlayCurrentMoveAnimation
jp PrintNoEffectText
-DisableEffect: ; 3fa8a (f:7a8a)
+DisableEffect: ; 3fa65 (f:7a65)
call MoveHitTest
ld a, [wMoveMissed]
and a
@@ -8451,74 +8529,74 @@ DisableEffect: ; 3fa8a (f:7a8a)
.moveMissed
jp PrintButItFailedText_
-MoveWasDisabledText: ; 3fb09 (f:7b09)
+MoveWasDisabledText: ; 3fae4 (f:7ae4)
TX_FAR _MoveWasDisabledText
db "@"
-PayDayEffect: ; 3fb0e (f:7b0e)
+PayDayEffect: ; 3fae9 (f:7ae9)
jpab PayDayEffect_
-ConversionEffect: ; 3fb16 (f:7b16)
+ConversionEffect: ; 3faf1 (f:7af1)
jpab ConversionEffect_
-HazeEffect: ; 3fb1e (f:7b1e)
+HazeEffect: ; 3faf9 (f:7af9)
jpab HazeEffect_
-HealEffect: ; 3fb26 (f:7b26)
+HealEffect: ; 3fb01 (f:7b01)
jpab HealEffect_
-TransformEffect: ; 3fb2e (f:7b2e)
+TransformEffect: ; 3fb09 (f:7b09)
jpab TransformEffect_
-ReflectLightScreenEffect: ; 3fb36 (f:7b36)
+ReflectLightScreenEffect: ; 3fb11 (f:7b11)
jpab ReflectLightScreenEffect_
-NothingHappenedText: ; 3fb3e (f:7b3e)
+NothingHappenedText: ; 3fb19 (f:7b19)
TX_FAR _NothingHappenedText
db "@"
-PrintNoEffectText: ; 3fb43 (f:7b43)
+PrintNoEffectText: ; 3fb1e (f:7b1e)
ld hl, NoEffectText
jp PrintText
-NoEffectText: ; 3fb49 (f:7b49)
+NoEffectText: ; 3fb24 (f:7b24)
TX_FAR _NoEffectText
db "@"
-ConditionalPrintButItFailed: ; 3fb4e (f:7b4e)
+ConditionalPrintButItFailed: ; 3fb29 (f:7b29)
ld a, [wMoveDidntMiss]
and a
ret nz ; return if the side effect failed, yet the attack was successful
-PrintButItFailedText_: ; 3fb53 (f:7b53)
+PrintButItFailedText_: ; 3fb2e (f:7b2e)
ld hl, ButItFailedText
jp PrintText
-ButItFailedText: ; 3fb59 (f:7b59)
+ButItFailedText: ; 3fb34 (f:7b34)
TX_FAR _ButItFailedText
db "@"
-PrintDidntAffectText: ; 3fb5e (f:7b5e)
+PrintDidntAffectText: ; 3fb39 (f:7b39)
ld hl, DidntAffectText
jp PrintText
-DidntAffectText: ; 3fb64 (f:7b64)
+DidntAffectText: ; 3fb3f (f:7b3f)
TX_FAR _DidntAffectText
db "@"
-IsUnaffectedText: ; 3fb69 (f:7b69)
+IsUnaffectedText: ; 3fb44 (f:7b44)
TX_FAR _IsUnaffectedText
db "@"
-PrintMayNotAttackText: ; 3fb6e (f:7b6e)
+PrintMayNotAttackText: ; 3fb49 (f:7b49)
ld hl, ParalyzedMayNotAttackText
jp PrintText
-ParalyzedMayNotAttackText: ; 3fb74 (f:7b74)
+ParalyzedMayNotAttackText: ; 3fb4f (f:7b4f)
TX_FAR _ParalyzedMayNotAttackText
db "@"
-CheckTargetSubstitute: ; 3fb79 (f:7b79)
+CheckTargetSubstitute: ; 3fb54 (f:7b54)
push hl
ld hl, wEnemyBattleStatus2
ld a, [H_WHOSETURN]
@@ -8530,7 +8608,7 @@ CheckTargetSubstitute: ; 3fb79 (f:7b79)
pop hl
ret
-PlayCurrentMoveAnimation2: ; 3fb89 (f:7b89)
+PlayCurrentMoveAnimation2: ; 3fb64 (f:7b64)
; animation at MOVENUM will be played unless MOVENUM is 0
; plays wAnimationType 3 or 6
ld a, [H_WHOSETURN]
@@ -8542,7 +8620,7 @@ PlayCurrentMoveAnimation2: ; 3fb89 (f:7b89)
and a
ret z
-PlayBattleAnimation2: ; 3fb96 (f:7b96)
+PlayBattleAnimation2: ; 3fb71 (f:7b71)
; play animation ID at a and animation type 6 or 3
ld [wAnimationID], a
ld a, [H_WHOSETURN]
@@ -8554,7 +8632,7 @@ PlayBattleAnimation2: ; 3fb96 (f:7b96)
ld [wAnimationType], a
jp PlayBattleAnimationGotID
-PlayCurrentMoveAnimation: ; 3fba8 (f:7ba8)
+PlayCurrentMoveAnimation: ; 3fb83 (f:7b83)
; animation at MOVENUM will be played unless MOVENUM is 0
; resets wAnimationType
xor a
@@ -8568,17 +8646,18 @@ PlayCurrentMoveAnimation: ; 3fba8 (f:7ba8)
and a
ret z
-PlayBattleAnimation: ; 3fbb9 (f:7bb9)
+PlayBattleAnimation: ; 3fb94 (f:7b94)
; play animation ID at a and predefined animation type
ld [wAnimationID], a
-PlayBattleAnimationGotID: ; 3fbbc (f:7bbc)
+PlayBattleAnimationGotID: ; 3fb97 (f:7b97)
; play animation at wAnimationID
push hl
push de
push bc
predef MoveAnimation
+ callab Func_78e98
pop bc
pop de
pop hl
- ret
+ ret \ No newline at end of file
diff --git a/engine/battle/core_.asm b/engine/battle/core_.asm
deleted file mode 100644
index 8a897a56..00000000
--- a/engine/battle/core_.asm
+++ /dev/null
@@ -1,7045 +0,0 @@
-BattleCore:
-
-; These are move effects (second value from the Moves table in bank $E).
-ResidualEffects1: ; 3c000 (f:4000)
-; most non-side effects
- db CONVERSION_EFFECT
- db HAZE_EFFECT
- db SWITCH_AND_TELEPORT_EFFECT
- db MIST_EFFECT
- db FOCUS_ENERGY_EFFECT
- db CONFUSION_EFFECT
- db HEAL_EFFECT
- db TRANSFORM_EFFECT
- db LIGHT_SCREEN_EFFECT
- db REFLECT_EFFECT
- db POISON_EFFECT
- db PARALYZE_EFFECT
- db SUBSTITUTE_EFFECT
- db MIMIC_EFFECT
- db LEECH_SEED_EFFECT
- db SPLASH_EFFECT
- db -1
-SetDamageEffects: ; 3c011 (f:4011)
-; moves that do damage but not through normal calculations
-; e.g., Super Fang, Psywave
- db SUPER_FANG_EFFECT
- db SPECIAL_DAMAGE_EFFECT
- db -1
-ResidualEffects2: ; 3c014 (f:4014)
-; non-side effects not included in ResidualEffects1
-; stat-affecting moves, sleep-inflicting moves, and Bide
-; e.g., Meditate, Bide, Hypnosis
- db $01
- db ATTACK_UP1_EFFECT
- db DEFENSE_UP1_EFFECT
- db SPEED_UP1_EFFECT
- db SPECIAL_UP1_EFFECT
- db ACCURACY_UP1_EFFECT
- db EVASION_UP1_EFFECT
- db ATTACK_DOWN1_EFFECT
- db DEFENSE_DOWN1_EFFECT
- db SPEED_DOWN1_EFFECT
- db SPECIAL_DOWN1_EFFECT
- db ACCURACY_DOWN1_EFFECT
- db EVASION_DOWN1_EFFECT
- db BIDE_EFFECT
- db SLEEP_EFFECT
- db ATTACK_UP2_EFFECT
- db DEFENSE_UP2_EFFECT
- db SPEED_UP2_EFFECT
- db SPECIAL_UP2_EFFECT
- db ACCURACY_UP2_EFFECT
- db EVASION_UP2_EFFECT
- db ATTACK_DOWN2_EFFECT
- db DEFENSE_DOWN2_EFFECT
- db SPEED_DOWN2_EFFECT
- db SPECIAL_DOWN2_EFFECT
- db ACCURACY_DOWN2_EFFECT
- db EVASION_DOWN2_EFFECT
- db -1
-AlwaysHappenSideEffects: ; 3c030 (f:4030)
-; Attacks that aren't finished after they faint the opponent.
- db DRAIN_HP_EFFECT
- db EXPLODE_EFFECT
- db DREAM_EATER_EFFECT
- db PAY_DAY_EFFECT
- db TWO_TO_FIVE_ATTACKS_EFFECT
- db $1E
- db ATTACK_TWICE_EFFECT
- db RECOIL_EFFECT
- db TWINEEDLE_EFFECT
- db RAGE_EFFECT
- db -1
-SpecialEffects: ; 3c03b (f:403b)
-; Effects from arrays 2, 4, and 5B, minus Twineedle and Rage.
-; Includes all effects that do not need to be called at the end of
-; ExecutePlayerMove (or ExecuteEnemyMove), because they have already been handled
- db DRAIN_HP_EFFECT
- db EXPLODE_EFFECT
- db DREAM_EATER_EFFECT
- db PAY_DAY_EFFECT
- db SWIFT_EFFECT
- db TWO_TO_FIVE_ATTACKS_EFFECT
- db $1E
- db CHARGE_EFFECT
- db SUPER_FANG_EFFECT
- db SPECIAL_DAMAGE_EFFECT
- db FLY_EFFECT
- db ATTACK_TWICE_EFFECT
- db JUMP_KICK_EFFECT
- db RECOIL_EFFECT
- ; fallthrough to Next EffectsArray
-SpecialEffectsCont: ; 3c049 (f:4049)
-; damaging moves whose effect is executed prior to damage calculation
- db THRASH_PETAL_DANCE_EFFECT
- db TRAPPING_EFFECT
- db -1
-
-SlidePlayerAndEnemySilhouettesOnScreen: ; 3c04c (f:404c)
- call LoadPlayerBackPic
- ld a, MESSAGE_BOX ; the usual text box at the bottom of the screen
- ld [wTextBoxID], a
- call DisplayTextBoxID
- coord hl, 1, 5
- lb bc, 3, 7
- call ClearScreenArea
- call DisableLCD
- call LoadFontTilePatterns
- call LoadHudAndHpBarAndStatusTilePatterns
- ld hl, vBGMap0
- ld bc, $400
-.clearBackgroundLoop
- ld a, " "
- ld [hli], a
- dec bc
- ld a, b
- or c
- jr nz, .clearBackgroundLoop
-; copy the work RAM tile map to VRAM
- coord hl, 0, 0
- ld de, vBGMap0
- ld b, 18 ; number of rows
-.copyRowLoop
- ld c, 20 ; number of columns
-.copyColumnLoop
- ld a, [hli]
- ld [de], a
- inc e
- dec c
- jr nz, .copyColumnLoop
- ld a, 12 ; number of off screen tiles to the right of screen in VRAM
- add e ; skip the off screen tiles
- ld e, a
- jr nc, .noCarry
- inc d
-.noCarry
- dec b
- jr nz, .copyRowLoop
- call EnableLCD
- ld a, $90
- ld [hWY], a
- ld [rWY], a
- xor a
- ld [hTilesetType], a
- ld [hSCY], a
- dec a
- ld [wUpdateSpritesEnabled], a
- call Delay3
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- ld b, $70
- ld c, $90
- ld a, c
- ld [hSCX], a
- call DelayFrame
- ld a, %11100100 ; inverted palette for silhouette effect
- ld [rBGP], a
- ld [rOBP0], a
- ld [rOBP1], a
- call UpdateGBCPal_BGP
- call UpdateGBCPal_OBP0
- call UpdateGBCPal_OBP1
-.slideSilhouettesLoop ; slide silhouettes of the player's pic and the enemy's pic onto the screen
- ld h, b
- ld l, $40
- call SetScrollXForSlidingPlayerBodyLeft ; begin background scrolling on line $40
- inc b
- inc b
- ld h, $0
- ld l, $60
- call SetScrollXForSlidingPlayerBodyLeft ; end background scrolling on line $60
- call SlidePlayerHeadLeft
- ld a, c
- ld [hSCX], a
- dec c
- dec c
- jr nz, .slideSilhouettesLoop
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- ld a, $31
- ld [hStartTileID], a
- coord hl, 1, 5
- predef CopyUncompressedPicToTilemap
- xor a
- ld [hWY], a
- ld [rWY], a
- inc a
- ld [H_AUTOBGTRANSFERENABLED], a
- call Delay3
- ld b, SET_PAL_BATTLE
- call RunPaletteCommand
- call HideSprites
- jpab PrintBeginningBattleText
-
-; when a battle is starting, silhouettes of the player's pic and the enemy's pic are slid onto the screen
-; the lower of the player's pic (his body) is part of the background, but his head is a sprite
-; the reason for this is that it shares Y coordinates with the lower part of the enemy pic, so background scrolling wouldn't work for both pics
-; instead, the enemy pic is part of the background and uses the scroll register, while the player's head is a sprite and is slid by changing its X coordinates in a loop
-SlidePlayerHeadLeft: ; 3c108 (f:4108)
- push bc
- ld hl, wOAMBuffer + $01
- ld c, $15 ; number of OAM entries
- ld de, $4 ; size of OAM entry
-.loop
- dec [hl] ; decrement X
- dec [hl] ; decrement X
- add hl, de ; next OAM entry
- dec c
- jr nz, .loop
- pop bc
- ret
-
-SetScrollXForSlidingPlayerBodyLeft: ; 3c119 (f:4119)
- ld a, [rLY]
- cp l
- jr nz, SetScrollXForSlidingPlayerBodyLeft
- ld a, h
- ld [rSCX], a
-.loop
- ld a, [rLY]
- cp h
- jr z, .loop
- ret
-
-StartBattle: ; 3c127 (f:4127)
- xor a
- ld [wPartyGainExpFlags], a
- ld [wPartyFoughtCurrentEnemyFlags], a
- ld [wActionResultOrTookBattleTurn], a
- inc a
- ld [wFirstMonsNotOutYet], a
- ld hl, wEnemyMon1HP
- ld bc, wEnemyMon2 - wEnemyMon1 - 1
- ld d, $3
-.findFirstAliveEnemyMonLoop
- inc d
- ld a, [hli]
- or [hl]
- jr nz, .foundFirstAliveEnemyMon
- add hl, bc
- jr .findFirstAliveEnemyMonLoop
-.foundFirstAliveEnemyMon
- ld a, d
- ld [wSerialExchangeNybbleReceiveData], a
- ld a, [wIsInBattle]
- dec a ; is it a trainer battle?
- call nz, EnemySendOutFirstMon ; if it is a trainer battle, send out enemy mon
- ld c, 40
- call DelayFrames
- call SaveScreenTilesToBuffer1
-.checkAnyPartyAlive
- ld a, [wBattleType]
- cp $3
- jp z, .specialBattle
- cp $4
- jp z, .specialBattle
- call AnyPartyAlive
- ld a, d
- and a
- jp z, HandlePlayerBlackOut ; jump if no mon is alive
-.specialBattle
- call LoadScreenTilesFromBuffer1
- ld a, [wBattleType]
- and a ; is it a normal battle?
- jp z, .playerSendOutFirstMon ; if so, send out player mon
-; safari zone battle
-.displaySafariZoneBattleMenu
- call DisplayBattleMenu
- ret c ; return if the player ran from battle
- ld a, [wActionResultOrTookBattleTurn]
- and a ; was the item used successfully?
- jr z, .displaySafariZoneBattleMenu ; if not, display the menu again; XXX does this ever jump?
- ld a, [wNumSafariBalls]
- and a
- jr nz, .notOutOfSafariBalls
- call LoadScreenTilesFromBuffer1
- ld hl, .outOfSafariBallsText
- jp PrintText
-.notOutOfSafariBalls
- callab PrintSafariZoneBattleText
- ld a, [wEnemyMonSpeed + 1]
- add a
- ld b, a ; init b (which is later compared with random value) to (enemy speed % 256) * 2
- jp c, EnemyRan ; if (enemy speed % 256) > 127, the enemy runs
- ld a, [wSafariBaitFactor]
- and a ; is bait factor 0?
- jr z, .checkEscapeFactor
-; bait factor is not 0
-; divide b by 4 (making the mon less likely to run)
- srl b
- srl b
-.checkEscapeFactor
- ld a, [wSafariEscapeFactor]
- and a ; is escape factor 0?
- jr z, .compareWithRandomValue
-; escape factor is not 0
-; multiply b by 2 (making the mon more likely to run)
- sla b
- jr nc, .compareWithRandomValue
-; cap b at 255
- ld b, $ff
-.compareWithRandomValue
- call Random
- cp b
- jr nc, .checkAnyPartyAlive
- jr EnemyRan ; if b was greater than the random value, the enemy runs
-
-.outOfSafariBallsText
- TX_FAR _OutOfSafariBallsText
- db "@"
-
-.playerSendOutFirstMon
- xor a
- ld [wWhichPokemon], a
-.findFirstAliveMonLoop
- call HasMonFainted
- jr nz, .foundFirstAliveMon
-; fainted, go to the next one
- ld hl, wWhichPokemon
- inc [hl]
- jr .findFirstAliveMonLoop
-.foundFirstAliveMon
- ld a, [wWhichPokemon]
- ld [wPlayerMonNumber], a
- inc a
- ld hl, wPartySpecies - 1
- ld c, a
- ld b, 0
- add hl, bc
- ld a, [hl] ; species
- ld [wcf91], a
- ld [wBattleMonSpecies2], a
- call LoadScreenTilesFromBuffer1
- coord hl, 1, 5
- ld a, $9
- call SlideTrainerPicOffScreen
- call SaveScreenTilesToBuffer1
- ld a, [wWhichPokemon]
- ld c, a
- ld b, FLAG_SET
- push bc
- ld hl, wPartyGainExpFlags
- predef FlagActionPredef
- ld hl, wPartyFoughtCurrentEnemyFlags
- pop bc
- predef FlagActionPredef
- call LoadBattleMonFromParty
- call LoadScreenTilesFromBuffer1
- call SendOutMon
- jr MainInBattleLoop
-
-; wild mon or link battle enemy ran from battle
-EnemyRan: ; 3c202 (f:4218)
- call LoadScreenTilesFromBuffer1
- ld a, [wLinkState]
- cp LINK_STATE_BATTLING
- ld hl, WildRanText
- jr nz, .printText
-; link battle
- xor a
- ld [wBattleResult], a
- ld hl, EnemyRanText
-.printText
- call PrintText
- ld a, SFX_RUN
- call PlaySoundWaitForCurrent
- xor a
- ld [H_WHOSETURN], a
- jpab AnimationSlideEnemyMonOff
-
-WildRanText: ; 3c23f (f:423f)
- TX_FAR _WildRanText
- db "@"
-
-EnemyRanText: ; 3c23f (f:423f)
- TX_FAR _EnemyRanText
- db "@"
-
-MainInBattleLoop: ; 3c249 (f:4249)
- call ReadPlayerMonCurHPAndStatus
- ld hl, wBattleMonHP
- ld a, [hli]
- or [hl] ; is battle mon HP 0?
- jp z, HandlePlayerMonFainted ; if battle mon HP is 0, jump
- ld hl, wEnemyMonHP
- ld a, [hli]
- or [hl] ; is enemy mon HP 0?
- jp z, HandleEnemyMonFainted ; if enemy mon HP is 0, jump
- call SaveScreenTilesToBuffer1
- xor a
- ld [wFirstMonsNotOutYet], a
- ld a, [wPlayerBattleStatus2]
- and (1 << NeedsToRecharge) | (1 << UsingRage) ; check if the player is using Rage or needs to recharge
- jr nz, .selectEnemyMove
-; the player is not using Rage and doesn't need to recharge
- ld hl, wEnemyBattleStatus1
- res Flinched, [hl] ; reset flinch bit
- ld hl, wPlayerBattleStatus1
- res Flinched, [hl] ; reset flinch bit
- ld a, [hl]
- and (1 << ThrashingAbout) | (1 << ChargingUp) ; check if the player is thrashing about or charging for an attack
- jr nz, .selectEnemyMove ; if so, jump
-; the player is neither thrashing about nor charging for an attack
- call DisplayBattleMenu ; show battle menu
- ret c ; return if player ran from battle
- ld a, [wEscapedFromBattle]
- and a
- ret nz ; return if pokedoll was used to escape from battle
- ld a, [wBattleMonStatus]
- and (1 << FRZ) | SLP ; is mon frozen or asleep?
- jr nz, .selectEnemyMove ; if so, jump
- ld a, [wPlayerBattleStatus1]
- and (1 << StoringEnergy) | (1 << UsingTrappingMove) ; check player is using Bide or using a multi-turn attack like wrap
- jr nz, .selectEnemyMove ; if so, jump
- ld a, [wEnemyBattleStatus1]
- bit UsingTrappingMove, a ; check if enemy is using a multi-turn attack like wrap
- jr z, .selectPlayerMove ; if not, jump
-; enemy is using a mult-turn attack like wrap, so player is trapped and cannot execute a move
- ld a, $ff
- ld [wPlayerSelectedMove], a
- jr .selectEnemyMove
-.selectPlayerMove
- ld a, [wActionResultOrTookBattleTurn]
- and a ; has the player already used the turn (e.g. by using an item, trying to run or switching pokemon)
- jr nz, .selectEnemyMove
- ld [wMoveMenuType], a
- inc a
- ld [wAnimationID], a
- xor a
- ld [wMenuItemToSwap], a
- call MoveSelectionMenu
- push af
- call LoadScreenTilesFromBuffer1
- call DrawHUDsAndHPBars
- pop af
- jr nz, MainInBattleLoop ; if the player didn't select a move, jump
-.selectEnemyMove
- call SelectEnemyMove
- ld a, [wLinkState]
- cp LINK_STATE_BATTLING
- jr nz, .noLinkBattle
-; link battle
- ld a, [wSerialExchangeNybbleReceiveData]
- cp $f
- jp z, EnemyRan
- cp $e
- jr z, .noLinkBattle
- cp $d
- jr z, .noLinkBattle
- sub $4
- jr c, .noLinkBattle
-; the link battle enemy has switched mons
- ld a, [wPlayerBattleStatus1]
- bit UsingTrappingMove, a ; check if using multi-turn move like Wrap
- jr z, .specialMoveNotUsed
- ld a, [wPlayerMoveListIndex]
- ld hl, wBattleMonMoves
- ld c, a
- ld b, 0
- add hl, bc
- ld a, [hl]
- cp METRONOME ; a MIRROR MOVE check is missing, might lead to a desync in link battles
- ; when combined with multi-turn moves
- jr nz, .specialMoveNotUsed
- ld [wPlayerSelectedMove], a
-.specialMoveNotUsed
- callab SwitchEnemyMon
-.noLinkBattle
- ld a, [wPlayerSelectedMove]
- cp QUICK_ATTACK
- jr nz, .playerDidNotUseQuickAttack
- ld a, [wEnemySelectedMove]
- cp QUICK_ATTACK
- jr z, .compareSpeed ; if both used Quick Attack
- jp .playerMovesFirst ; if player used Quick Attack and enemy didn't
-.playerDidNotUseQuickAttack
- ld a, [wEnemySelectedMove]
- cp QUICK_ATTACK
- jr z, .enemyMovesFirst ; if enemy used Quick Attack and player didn't
- ld a, [wPlayerSelectedMove]
- cp COUNTER
- jr nz, .playerDidNotUseCounter
- ld a, [wEnemySelectedMove]
- cp COUNTER
- jr z, .compareSpeed ; if both used Counter
- jr .enemyMovesFirst ; if player used Counter and enemy didn't
-.playerDidNotUseCounter
- ld a, [wEnemySelectedMove]
- cp COUNTER
- jr z, .playerMovesFirst ; if enemy used Counter and player didn't
-.compareSpeed
- ld de, wBattleMonSpeed ; player speed value
- ld hl, wEnemyMonSpeed ; enemy speed value
- ld c, $2
- call StringCmp ; compare speed values
- jr z, .speedEqual
- jr nc, .playerMovesFirst ; if player is faster
- jr .enemyMovesFirst ; if enemy is faster
-.speedEqual ; 50/50 chance for both players
- ld a, [$ffaa]
- cp $2
- jr z, .invertOutcome
- call BattleRandom
- cp $80
- jr c, .playerMovesFirst
- jr .enemyMovesFirst
-.invertOutcome
- call BattleRandom
- cp $80
- jr c, .enemyMovesFirst
- jr .playerMovesFirst
-.enemyMovesFirst
- ld a, $1
- ld [H_WHOSETURN], a
- callab TrainerAI
- jr c, .AIActionUsedEnemyFirst
- call ExecuteEnemyMove
- ld a, [wEscapedFromBattle]
- and a ; was Teleport, Road, or Whirlwind used to escape from battle?
- ret nz ; if so, return
- ld a, b
- and a
- jp z, HandlePlayerMonFainted
-.AIActionUsedEnemyFirst
- call HandlePoisonBurnLeechSeed
- jp z, HandleEnemyMonFainted
- call DrawHUDsAndHPBars
- call ExecutePlayerMove
- ld a, [wEscapedFromBattle]
- and a ; was Teleport, Road, or Whirlwind used to escape from battle?
- ret nz ; if so, return
- ld a, b
- and a
- jp z, HandleEnemyMonFainted
- call HandlePoisonBurnLeechSeed
- jp z, HandlePlayerMonFainted
- call DrawHUDsAndHPBars
- call CheckNumAttacksLeft
- jp MainInBattleLoop
-.playerMovesFirst
- call ExecutePlayerMove
- ld a, [wEscapedFromBattle]
- and a ; was Teleport, Road, or Whirlwind used to escape from battle?
- ret nz ; if so, return
- ld a, b
- and a
- jp z, HandleEnemyMonFainted
- call HandlePoisonBurnLeechSeed
- jp z, HandlePlayerMonFainted
- call DrawHUDsAndHPBars
- ld a, $1
- ld [H_WHOSETURN], a
- callab TrainerAI
- jr c, .AIActionUsedPlayerFirst
- call ExecuteEnemyMove
- ld a, [wEscapedFromBattle]
- and a ; was Teleport, Road, or Whirlwind used to escape from battle?
- ret nz ; if so, return
- ld a, b
- and a
- jp z, HandlePlayerMonFainted
-.AIActionUsedPlayerFirst
- call HandlePoisonBurnLeechSeed
- jp z, HandleEnemyMonFainted
- call DrawHUDsAndHPBars
- call CheckNumAttacksLeft
- jp MainInBattleLoop
-
-HandlePoisonBurnLeechSeed: ; 3c3d3 (f:43d3)
- ld hl, wBattleMonHP
- ld de, wBattleMonStatus
- ld a, [H_WHOSETURN]
- and a
- jr z, .playersTurn
- ld hl, wEnemyMonHP
- ld de, wEnemyMonStatus
-.playersTurn
- ld a, [de]
- and (1 << BRN) | (1 << PSN)
- jr z, .notBurnedOrPoisoned
- push hl
- ld hl, HurtByPoisonText
- ld a, [de]
- and 1 << BRN
- jr z, .poisoned
- ld hl, HurtByBurnText
-.poisoned
- call PrintText
- xor a
- ld [wAnimationType], a
- ld a,BURN_PSN_ANIM
- call PlayMoveAnimation ; play burn/poison animation
- pop hl
- call HandlePoisonBurnLeechSeed_DecreaseOwnHP
-.notBurnedOrPoisoned
- ld de, wPlayerBattleStatus2
- ld a, [H_WHOSETURN]
- and a
- jr z, .playersTurn2
- ld de, wEnemyBattleStatus2
-.playersTurn2
- ld a, [de]
- add a
- jr nc, .notLeechSeeded
- push hl
- ld a, [H_WHOSETURN]
- push af
- xor $1
- ld [H_WHOSETURN], a
- xor a
- ld [wAnimationType], a
- ld a,ABSORB
- call PlayMoveAnimation ; play leech seed animation (from opposing mon)
- pop af
- ld [H_WHOSETURN], a
- pop hl
- call HandlePoisonBurnLeechSeed_DecreaseOwnHP
- call HandlePoisonBurnLeechSeed_IncreaseEnemyHP
- push hl
- ld hl, HurtByLeechSeedText
- call PrintText
- pop hl
-.notLeechSeeded
- ld a, [hli]
- or [hl]
- ret nz ; test if fainted
- call DrawHUDsAndHPBars
- ld c, 20
- call DelayFrames
- xor a
- ret
-
-HurtByPoisonText: ; 3c444 (f:4444)
- TX_FAR _HurtByPoisonText
- db "@"
-
-HurtByBurnText: ; 3c449 (f:4449)
- TX_FAR _HurtByBurnText
- db "@"
-
-HurtByLeechSeedText: ; 3c44e (f:444e)
- TX_FAR _HurtByLeechSeedText
- db "@"
-
-; decreases the mon's current HP by 1/16 of the Max HP (multiplied by number of toxic ticks if active)
-; note that the toxic ticks are considered even if the damage is not poison (hence the Leech Seed glitch)
-; hl: HP pointer
-; bc (out): total damage
-HandlePoisonBurnLeechSeed_DecreaseOwnHP: ; 3c43d (f:443d)
- push hl
- push hl
- ld bc, $e ; skip to max HP
- add hl, bc
- ld a, [hli] ; load max HP
- ld [wHPBarMaxHP+1], a
- ld b, a
- ld a, [hl]
- ld [wHPBarMaxHP], a
- ld c, a
- srl b
- rr c
- srl b
- rr c
- srl c
- srl c ; c = max HP/16 (assumption: HP < 1024)
- ld a, c
- and a
- jr nz, .nonZeroDamage
- inc c ; damage is at least 1
-.nonZeroDamage
- ld hl, wPlayerBattleStatus3
- ld de, wPlayerToxicCounter
- ld a, [H_WHOSETURN]
- and a
- jr z, .playersTurn
- ld hl, wEnemyBattleStatus3
- ld de, wEnemyToxicCounter
-.playersTurn
- bit BadlyPoisoned, [hl]
- jr z, .noToxic
- ld a, [de] ; increment toxic counter
- inc a
- ld [de], a
- ld hl, $0000
-.toxicTicksLoop
- add hl, bc
- dec a
- jr nz, .toxicTicksLoop
- ld b, h ; bc = damage * toxic counter
- ld c, l
-.noToxic
- pop hl
- inc hl
- ld a, [hl] ; subtract total damage from current HP
- ld [wHPBarOldHP], a
- sub c
- ld [hld], a
- ld [wHPBarNewHP], a
- ld a, [hl]
- ld [wHPBarOldHP+1], a
- sbc b
- ld [hl], a
- ld [wHPBarNewHP+1], a
- jr nc, .noOverkill
- xor a ; overkill: zero HP
- ld [hli], a
- ld [hl], a
- ld [wHPBarNewHP], a
- ld [wHPBarNewHP+1], a
-.noOverkill
- call UpdateCurMonHPBar
- pop hl
- ret
-
-; adds bc to enemy HP
-; bc isn't updated if HP substracted was capped to prevent overkill
-HandlePoisonBurnLeechSeed_IncreaseEnemyHP: ; 3c4b9 (f:44b9)
- push hl
- ld hl, wEnemyMonMaxHP
- ld a, [H_WHOSETURN]
- and a
- jr z, .playersTurn
- ld hl, wBattleMonMaxHP
-.playersTurn
- ld a, [hli]
- ld [wHPBarMaxHP+1], a
- ld a, [hl]
- ld [wHPBarMaxHP], a
- ld de, wBattleMonHP - wBattleMonMaxHP
- add hl, de ; skip back from max hp to current hp
- ld a, [hl]
- ld [wHPBarOldHP], a ; add bc to current HP
- add c
- ld [hld], a
- ld [wHPBarNewHP], a
- ld a, [hl]
- ld [wHPBarOldHP+1], a
- adc b
- ld [hli], a
- ld [wHPBarNewHP+1], a
- ld a, [wHPBarMaxHP]
- ld c, a
- ld a, [hld]
- sub c
- ld a, [wHPBarMaxHP+1]
- ld b, a
- ld a, [hl]
- sbc b
- jr c, .noOverfullHeal
- ld a, b ; overfull heal, set HP to max HP
- ld [hli], a
- ld [wHPBarNewHP+1], a
- ld a, c
- ld [hl], a
- ld [wHPBarNewHP], a
-.noOverfullHeal
- ld a, [H_WHOSETURN]
- xor $1
- ld [H_WHOSETURN], a
- call UpdateCurMonHPBar
- ld a, [H_WHOSETURN]
- xor $1
- ld [H_WHOSETURN], a
- pop hl
- ret
-
-UpdateCurMonHPBar: ; 3c50c (f:450c)
- coord hl, 10, 9 ; tile pointer to player HP bar
- ld a, [H_WHOSETURN]
- and a
- ld a, $1
- jr z, .playersTurn
- coord hl, 2, 2 ; tile pointer to enemy HP bar
- xor a
-.playersTurn
- push bc
- ld [wHPBarType], a
- predef UpdateHPBar2
- pop bc
- ret
-
-CheckNumAttacksLeft: ; 3c525 (f:4525)
- ld a, [wPlayerNumAttacksLeft]
- and a
- jr nz, .checkEnemy
-; player has 0 attacks left
- ld hl, wPlayerBattleStatus1
- res UsingTrappingMove, [hl] ; player not using multi-turn attack like wrap any more
-.checkEnemy
- ld a, [wEnemyNumAttacksLeft]
- and a
- ret nz
-; enemy has 0 attacks left
- ld hl, wEnemyBattleStatus1
- res UsingTrappingMove, [hl] ; enemy not using multi-turn attack like wrap any more
- ret
-
-HandleEnemyMonFainted: ; 3c53b (f:453b)
- xor a
- ld [wInHandlePlayerMonFainted], a
- call FaintEnemyPokemon
- call AnyPartyAlive
- ld a, d
- and a
- jp z, HandlePlayerBlackOut ; if no party mons are alive, the player blacks out
- ld hl, wBattleMonHP
- ld a, [hli]
- or [hl] ; is battle mon HP zero?
- call nz, DrawPlayerHUDAndHPBar ; if battle mon HP is not zero, draw player HD and HP bar
- ld a, [wIsInBattle]
- dec a
- ret z ; return if it's a wild battle
- call AnyEnemyPokemonAliveCheck
- jp z, TrainerBattleVictory
- ld hl, wBattleMonHP
- ld a, [hli]
- or [hl] ; does battle mon have 0 HP?
- jr nz, .skipReplacingBattleMon ; if not, skip replacing battle mon
- call DoUseNextMonDialogue ; this call is useless in a trainer battle. it shouldn't be here
- ret c
- call ChooseNextMon
-.skipReplacingBattleMon
- ld a, $1
- ld [wActionResultOrTookBattleTurn], a
- call ReplaceFaintedEnemyMon
- jp z, EnemyRan
- xor a
- ld [wActionResultOrTookBattleTurn], a
- jp MainInBattleLoop
-
-FaintEnemyPokemon: ; 3c57d (f:457d)
- call ReadPlayerMonCurHPAndStatus
- ld a, [wIsInBattle]
- dec a
- jr z, .wild
- ld a, [wEnemyMonPartyPos]
- ld hl, wEnemyMon1HP
- ld bc, wEnemyMon2 - wEnemyMon1
- call AddNTimes
- xor a
- ld [hli], a
- ld [hl], a
-.wild
- ld hl, wPlayerBattleStatus1
- res AttackingMultipleTimes, [hl]
-; Bug. This only zeroes the high byte of the player's accumulated damage,
-; setting the accumulated damage to itself mod 256 instead of 0 as was probably
-; intended. That alone is problematic, but this mistake has another more severe
-; effect. This function's counterpart for when the player mon faints,
-; RemoveFaintedPlayerMon, zeroes both the high byte and the low byte. In a link
-; battle, the other player's Game Boy will call that function in response to
-; the enemy mon (the player mon from the other side's perspective) fainting,
-; and the states of the two Game Boys will go out of sync unless the damage
-; was congruent to 0 modulo 256.
- xor a
- ld [wPlayerBideAccumulatedDamage], a
- ld hl, wEnemyStatsToDouble ; clear enemy statuses
- ld [hli], a
- ld [hli], a
- ld [hli], a
- ld [hli], a
- ld [hl], a
- ld [wEnemyDisabledMove], a
- ld [wEnemyDisabledMoveNumber], a
- ld [wEnemyMonMinimized], a
- ld hl, wPlayerUsedMove
- ld [hli], a
- ld [hl], a
- coord hl, 12, 5
- coord de, 12, 6
- call SlideDownFaintedMonPic
- coord hl, 0, 0
- lb bc, 4, 11
- call ClearScreenArea
- ld a, [wIsInBattle]
- dec a
- jr z, .wild_win
- xor a
- ld [wFrequencyModifier], a
- ld [wTempoModifier], a
- ld a, SFX_FAINT_FALL
- call PlaySoundWaitForCurrent
-.sfxwait
- ld a, [wChannelSoundIDs + CH4]
- cp SFX_FAINT_FALL
- jr z, .sfxwait
- ld a, SFX_FAINT_THUD
- call PlaySound
- call WaitForSoundToFinish
- jr .sfxplayed
-.wild_win
- call EndLowHealthAlarm
- ld a, MUSIC_DEFEATED_WILD_MON
- call PlayBattleVictoryMusic
-.sfxplayed
-; bug: win sfx is played for wild battles before checking for player mon HP
-; this can lead to odd scenarios where both player and enemy faint, as the win sfx plays yet the player never won the battle
- ld hl, wBattleMonHP
- ld a, [hli]
- or [hl]
- jr nz, .playermonnotfaint
- ld a, [wInHandlePlayerMonFainted]
- and a ; was this called by HandlePlayerMonFainted?
- jr nz, .playermonnotfaint ; if so, don't call RemoveFaintedPlayerMon twice
- call RemoveFaintedPlayerMon
-.playermonnotfaint
- call AnyPartyAlive
- ld a, d
- and a
- ret z
- ld hl, EnemyMonFaintedText
- call PrintText
- call PrintEmptyString
- call SaveScreenTilesToBuffer1
- xor a
- ld [wBattleResult], a
- ld b, EXP_ALL
- call IsItemInBag
- push af
- jr z, .giveExpToMonsThatFought ; if no exp all, then jump
-
-; the player has exp all
-; first, we halve the values that determine exp gain
-; the enemy mon base stats are added to stat exp, so they are halved
-; the base exp (which determines normal exp) is also halved
- ld hl, wEnemyMonBaseStats
- ld b, $7
-.halveExpDataLoop
- srl [hl]
- inc hl
- dec b
- jr nz, .halveExpDataLoop
-
-; give exp (divided evenly) to the mons that actually fought in battle against the enemy mon that has fainted
-; if exp all is in the bag, this will be only be half of the stat exp and normal exp, due to the above loop
-.giveExpToMonsThatFought
- xor a
- ld [wBoostExpByExpAll], a
- callab GainExperience
- pop af
- ret z ; return if no exp all
-
-; the player has exp all
-; now, set the gain exp flag for every party member
-; half of the total stat exp and normal exp will divided evenly amongst every party member
- ld a, $1
- ld [wBoostExpByExpAll], a
- ld a, [wPartyCount]
- ld b, 0
-.gainExpFlagsLoop
- scf
- rl b
- dec a
- jr nz, .gainExpFlagsLoop
- ld a, b
- ld [wPartyGainExpFlags], a
- jpab GainExperience
-
-EnemyMonFaintedText: ; 3c654 (f:4654)
- TX_FAR _EnemyMonFaintedText
- db "@"
-
-EndLowHealthAlarm: ; 3c659 (f:4659)
-; This function is called when the player has the won the battle. It turns off
-; the low health alarm and prevents it from reactivating until the next battle.
- xor a
- ld [wLowHealthAlarm], a ; turn off low health alarm
- ld [wChannelSoundIDs + CH4], a
- inc a
- ld [wLowHealthAlarmDisabled], a ; prevent it from reactivating
- ret
-
-AnyEnemyPokemonAliveCheck: ; 3c665 (f:4665)
- ld a, [wEnemyPartyCount]
- ld b, a
- xor a
- ld hl, wEnemyMon1HP
- ld de, wEnemyMon2 - wEnemyMon1
-.nextPokemon
- or [hl]
- inc hl
- or [hl]
- dec hl
- add hl, de
- dec b
- jr nz, .nextPokemon
- and a
- ret
-
-; stores whether enemy ran in Z flag
-ReplaceFaintedEnemyMon: ; 3c67a (f:467a)
- ld hl, wEnemyHPBarColor
- ld e, $30
- call GetBattleHealthBarColor
- setpal SHADE_BLACK, SHADE_DARK, SHADE_LIGHT, SHADE_WHITE
- ld [rOBP0], a
- ld [rOBP1], a
- call UpdateGBCPal_OBP0
- call UpdateGBCPal_OBP1
- callab DrawEnemyPokeballs
- ld a, [wLinkState]
- cp LINK_STATE_BATTLING
- jr nz, .notLinkBattle
-; link battle
- call LinkBattleExchangeData
- ld a, [wSerialExchangeNybbleReceiveData]
- cp $f
- ret z
- call LoadScreenTilesFromBuffer1
-.notLinkBattle
- call EnemySendOut
- xor a
- ld [wEnemyMoveNum], a
- ld [wActionResultOrTookBattleTurn], a
- ld [wAILayer2Encouragement], a
- inc a ; reset Z flag
- ret
-
-TrainerBattleVictory: ; 3c6b8 (f:46b8)
- call EndLowHealthAlarm
- ld b, MUSIC_DEFEATED_GYM_LEADER
- ld a, [wGymLeaderNo]
- and a
- jr nz, .gymleader
- ld b, MUSIC_DEFEATED_TRAINER
-.gymleader
- ld a, [wTrainerClass]
- cp SONY3 ; final battle against rival
- jr nz, .notrival
- ld b, MUSIC_DEFEATED_GYM_LEADER
- ld hl, wFlags_D733
- set 1, [hl]
-.notrival
- ld a, [wLinkState]
- cp LINK_STATE_BATTLING
- ld a, b
- call nz, PlayBattleVictoryMusic
- ld hl, TrainerDefeatedText
- call PrintText
- ld a, [wLinkState]
- cp LINK_STATE_BATTLING
- ret z
- call ScrollTrainerPicAfterBattle
- ld c, 40
- call DelayFrames
- call PrintEndBattleText
-; win money
- ld hl, MoneyForWinningText
- call PrintText
- ld de, wPlayerMoney + 2
- ld hl, wAmountMoneyWon + 2
- ld c, $3
- predef_jump AddBCDPredef
-
-MoneyForWinningText: ; 3c706 (f:4706)
- TX_FAR _MoneyForWinningText
- db "@"
-
-TrainerDefeatedText: ; 3c70b (f:470b)
- TX_FAR _TrainerDefeatedText
- db "@"
-
-PlayBattleVictoryMusic: ; 3c710 (f:4710)
- push af
- call StopAllMusic
- ld c, BANK(Music_DefeatedTrainer)
- pop af
- call PlayMusic
- jp Delay3
-
-HandlePlayerMonFainted: ; 3c71d (f:471d)
- ld a, 1
- ld [wInHandlePlayerMonFainted], a
- call RemoveFaintedPlayerMon
- call AnyPartyAlive ; test if any more mons are alive
- ld a, d
- and a
- jp z, HandlePlayerBlackOut
- ld hl, wEnemyMonHP
- ld a, [hli]
- or [hl] ; is enemy mon's HP 0?
- jr nz, .doUseNextMonDialogue ; if not, jump
-; the enemy mon has 0 HP
- call FaintEnemyPokemon
- ld a, [wIsInBattle]
- dec a
- ret z ; if wild encounter, battle is over
- call AnyEnemyPokemonAliveCheck
- jp z, TrainerBattleVictory
-.doUseNextMonDialogue
- call DoUseNextMonDialogue
- ret c ; return if the player ran from battle
- call ChooseNextMon
- jp nz, MainInBattleLoop ; if the enemy mon has more than 0 HP, go back to battle loop
-; the enemy mon has 0 HP
- ld a, $1
- ld [wActionResultOrTookBattleTurn], a
- call ReplaceFaintedEnemyMon
- jp z, EnemyRan ; if enemy ran from battle rather than sending out another mon, jump
- xor a
- ld [wActionResultOrTookBattleTurn], a
- jp MainInBattleLoop
-
-; resets flags, slides mon's pic down, plays cry, and prints fainted message
-RemoveFaintedPlayerMon: ; 3c75e (f:475e)
- ld a, [wPlayerMonNumber]
- ld c, a
- ld hl, wPartyGainExpFlags
- ld b, FLAG_RESET
- predef FlagActionPredef ; clear gain exp flag for fainted mon
- ld hl, wEnemyBattleStatus1
- res 2, [hl] ; reset "attacking multiple times" flag
- ld a, [wLowHealthAlarm]
- bit 7, a ; skip sound flag (red bar (?))
- jr z, .skipWaitForSound
- ld a, $ff
- ld [wLowHealthAlarm], a ;disable low health alarm
- call WaitForSoundToFinish
- xor a
-.skipWaitForSound
-; a is 0, so this zeroes the enemy's accumulated damage.
- ld hl, wEnemyBideAccumulatedDamage
- ld [hli], a
- ld [hl], a
- ld [wBattleMonStatus], a
- call ReadPlayerMonCurHPAndStatus
- coord hl, 9, 7
- lb bc, 5, 11
- call ClearScreenArea
- coord hl, 1, 10
- coord de, 1, 11
- call SlideDownFaintedMonPic
- ld a, $1
- ld [wBattleResult], a
-
-; When the player mon and enemy mon faint at the same time and the fact that the
-; enemy mon has fainted is detected first (e.g. when the player mon knocks out
-; the enemy mon using a move with recoil and faints due to the recoil), don't
-; play the player mon's cry or show the "[player mon] fainted!" message.
- ld a, [wInHandlePlayerMonFainted]
- and a ; was this called by HandleEnemyMonFainted?
- ret z ; if so, return
-
- ld a, [wPlayerMonNumber]
- ld [wWhichPokemon], a
- callab IsThisPartymonStarterPikachu_Party
- jr nc, .notPlayerPikachu
- ld e, $3
- callab PlayPikachuSoundClip
- jr .printText
-.notPlayerPikachu
- ld a, [wBattleMonSpecies]
- call PlayCry
-.printText
- ld hl, PlayerMonFaintedText
- call PrintText
- ld a, [wPlayerMonNumber]
- ld [wWhichPokemon], a
- ld a, [wBattleMonLevel]
- ld b, a
- ld a, [wEnemyMonLevel]
- sub b ; enemylevel - playerlevel
- ; are we stronger than the opposing pokemon?
- jr c, .regularFaint ; if so, deduct happiness regularly
-
- cp 30 ; is the enemy 30 levels greater than us?
- jr nc, .carelessTrainer ; if so, punish the player for being careless, as they shouldn't be fighting a very high leveled trainer with such a level difference
-.regularFaint
- callabd_ModifyPikachuHappiness PIKAHAPPY_FAINTED
- ret
-.carelessTrainer
- callabd_ModifyPikachuHappiness PIKAHAPPY_CARELESSTRAINER
- ret
-
-PlayerMonFaintedText: ; 3c7fa (f:47fa)
- TX_FAR _PlayerMonFaintedText
- db "@"
-
-; asks if you want to use next mon
-; stores whether you ran in C flag
-DoUseNextMonDialogue: ; 3c7ff (f:47ff)
- call PrintEmptyString
- call SaveScreenTilesToBuffer1
- ld a, [wIsInBattle]
- and a
- dec a
- ret nz ; return if it's a trainer battle
- ld hl, UseNextMonText
- call PrintText
-.displayYesNoBox
- coord hl, 13, 9
- lb bc, 10, 14
- ld a, TWO_OPTION_MENU
- ld [wTextBoxID], a
- call DisplayTextBoxID
- ld a, [wMenuExitMethod]
- cp CHOSE_SECOND_ITEM ; did the player choose NO?
- jr z, .tryRunning ; if the player chose NO, try running
- and a ; reset carry
- ret
-.tryRunning
- ld a, [wCurrentMenuItem]
- and a
- jr z, .displayYesNoBox ; xxx when does this happen?
- ld hl, wPartyMon1Speed
- ld de, wEnemyMonSpeed
- jp TryRunningFromBattle
-
-UseNextMonText: ; 3c837 (f:4837)
- TX_FAR _UseNextMonText
- db "@"
-
-; choose next player mon to send out
-; stores whether enemy mon has no HP left in Z flag
-ChooseNextMon: ; 3c83c (f:483c)
- ld a, BATTLE_PARTY_MENU
- ld [wPartyMenuTypeOrMessageID], a
- call DisplayPartyMenu
-.checkIfMonChosen
- jr nc, .monChosen
-.goBackToPartyMenu
- call GoBackToPartyMenu
- jr .checkIfMonChosen
-.monChosen
- call HasMonFainted
- jr z, .goBackToPartyMenu ; if mon fainted, you have to choose another
- ld a, [wLinkState]
- cp LINK_STATE_BATTLING
- jr nz, .notLinkBattle
- ld a, $1
- ld [wActionResultOrTookBattleTurn], a
- call LinkBattleExchangeData
-.notLinkBattle
- xor a
- ld [wActionResultOrTookBattleTurn], a
- call ClearSprites
- ld a, [wWhichPokemon]
- ld [wPlayerMonNumber], a
- ld c, a
- ld hl, wPartyGainExpFlags
- ld b, FLAG_SET
- push bc
- predef FlagActionPredef
- pop bc
- ld hl, wPartyFoughtCurrentEnemyFlags
- predef FlagActionPredef
- call LoadBattleMonFromParty
- call GBPalWhiteOut
- call LoadHudTilePatterns
- call LoadScreenTilesFromBuffer1
- call RunDefaultPaletteCommand
- call GBPalNormal
- call SendOutMon
- ld hl, wEnemyMonHP
- ld a, [hli]
- or [hl]
- ret
-
-; called when player is out of usable mons.
-; prints approriate lose message, sets carry flag if player blacked out (special case for initial rival fight)
-HandlePlayerBlackOut: ; 3c89c (f:489c)
- ld a, [wLinkState]
- cp LINK_STATE_BATTLING
- jr z, .notSony1Battle
- ld a, [wCurOpponent]
- cp OPP_SONY1
- jr nz, .notSony1Battle
- coord hl, 0, 0 ; sony 1 battle
- lb bc, 8, 21
- call ClearScreenArea
- call ScrollTrainerPicAfterBattle
- ld c, 40
- call DelayFrames
- ld hl, Sony1WinText
- call PrintText
- ld a, [wCurMap]
- cp OAKS_LAB
- ret z ; starter battle in oak's lab: don't black out
-.notSony1Battle
- ld b, SET_PAL_BATTLE_BLACK
- call RunPaletteCommand
- ld hl, PlayerBlackedOutText2
- ld a, [wLinkState]
- cp LINK_STATE_BATTLING
- jr nz, .noLinkBattle
- ld hl, LinkBattleLostText
-.noLinkBattle
- call PrintText
- ld a, [wd732]
- res 5, a
- ld [wd732], a
- call ClearScreen
- scf
- ret
-
-Sony1WinText: ; 3c8e9 (f:48e9)
- TX_FAR _Sony1WinText
- db "@"
-
-PlayerBlackedOutText2: ; 3c8ee (f:48ee)
- TX_FAR _PlayerBlackedOutText2
- db "@"
-
-LinkBattleLostText: ; 3c8f3 (f:48f3)
- TX_FAR _LinkBattleLostText
- db "@"
-
-; slides pic of fainted mon downwards until it disappears
-; bug: when this is called, [H_AUTOBGTRANSFERENABLED] is non-zero, so there is screen tearing
-SlideDownFaintedMonPic: ; 3c8f8 (f:48f8)
- ld a, [wd730]
- push af
- set 6, a
- ld [wd730], a
- ld b, 7 ; number of times to slide
-.slideStepLoop ; each iteration, the mon is slid down one row
- push bc
- push de
- push hl
- ld b, 6 ; number of rows
-.rowLoop
- push bc
- push hl
- push de
- ld bc, $7
- call CopyData
- pop de
- pop hl
- ld bc, -SCREEN_WIDTH
- add hl, bc
- push hl
- ld h, d
- ld l, e
- add hl, bc
- ld d, h
- ld e, l
- pop hl
- pop bc
- dec b
- jr nz, .rowLoop
- ld bc, SCREEN_WIDTH
- add hl, bc
- ld de, SevenSpacesText
- call PlaceString
- ld c, 2
- call DelayFrames
- pop hl
- pop de
- pop bc
- dec b
- jr nz, .slideStepLoop
- pop af
- ld [wd730], a
- ret
-
-SevenSpacesText: ; 3c93c (f:493c)
- db " @"
-
-; slides the player or enemy trainer off screen
-; a is the number of tiles to slide it horizontally (always 9 for the player trainer or 8 for the enemy trainer)
-; if a is 8, the slide is to the right, else it is to the left
-; bug: when this is called, [H_AUTOBGTRANSFERENABLED] is non-zero, so there is screen tearing
-SlideTrainerPicOffScreen: ; 3c944 (f:4944)
- ld [hSlideAmount], a
- ld c, a
-.slideStepLoop ; each iteration, the trainer pic is slid one tile left/right
- push bc
- push hl
- ld b, 7 ; number of rows
-.rowLoop
- push hl
- ld a, [hSlideAmount]
- ld c, a
-.columnLoop
- ld a, [hSlideAmount]
- cp 8
- jr z, .slideRight
-.slideLeft ; slide player sprite off screen
- ld a, [hld]
- ld [hli], a
- inc hl
- jr .nextColumn
-.slideRight ; slide enemy trainer sprite off screen
- ld a, [hli]
- ld [hld], a
- dec hl
-.nextColumn
- dec c
- jr nz, .columnLoop
- pop hl
- ld de, 20
- add hl, de
- dec b
- jr nz, .rowLoop
- ld c, 2
- call DelayFrames
- pop hl
- pop bc
- dec c
- jr nz, .slideStepLoop
- ret
-
-; send out a trainer's mon
-EnemySendOut: ; 3c973 (f:4973)
- ld hl,wPartyGainExpFlags
- xor a
- ld [hl],a
- ld a,[wPlayerMonNumber]
- ld c,a
- ld b,FLAG_SET
- push bc
- predef FlagActionPredef
- ld hl,wPartyFoughtCurrentEnemyFlags
- xor a
- ld [hl],a
- pop bc
- predef FlagActionPredef
-
-; don't change wPartyGainExpFlags or wPartyFoughtCurrentEnemyFlags
-EnemySendOutFirstMon: ; 3c98f (f:498f)
- xor a
- ld hl,wEnemyStatsToDouble ; clear enemy statuses
- ld [hli],a
- ld [hli],a
- ld [hli],a
- ld [hli],a
- ld [hl],a
- ld [wEnemyDisabledMove],a
- ld [wEnemyDisabledMoveNumber],a
- ld [wEnemyMonMinimized],a
- ld hl,wPlayerUsedMove
- ld [hli],a
- ld [hl],a
- dec a
- ld [wAICount],a
- ld hl,wPlayerBattleStatus1
- res 5,[hl]
- coord hl, 18, 0
- ld a,8
- call SlideTrainerPicOffScreen
- call PrintEmptyString
- call SaveScreenTilesToBuffer1
- ld a,[wLinkState]
- cp LINK_STATE_BATTLING
- jr nz,.next
- ld a,[wSerialExchangeNybbleReceiveData]
- sub 4
- ld [wWhichPokemon],a
- jr .next3
-.next
- ld b,$FF
-.next2
- inc b
- ld a,[wEnemyMonPartyPos]
- cp b
- jr z,.next2
- ld hl,wEnemyMon1
- ld a,b
- ld [wWhichPokemon],a
- push bc
- ld bc,wEnemyMon2 - wEnemyMon1
- call AddNTimes
- pop bc
- inc hl
- ld a,[hli]
- ld c,a
- ld a,[hl]
- or c
- jr z,.next2
-.next3
- ld a,[wWhichPokemon]
- ld hl,wEnemyMon1Level
- ld bc,wEnemyMon2 - wEnemyMon1
- call AddNTimes
- ld a,[hl]
- ld [wCurEnemyLVL],a
- ld a,[wWhichPokemon]
- inc a
- ld hl,wEnemyPartyCount
- ld c,a
- ld b,0
- add hl,bc
- ld a,[hl]
- ld [wEnemyMonSpecies2],a
- ld [wcf91],a
- call LoadEnemyMonData
- ld hl,wEnemyMonHP
- ld a,[hli]
- ld [wLastSwitchInEnemyMonHP],a
- ld a,[hl]
- ld [wLastSwitchInEnemyMonHP + 1],a
- ld a,1
- ld [wCurrentMenuItem],a
- ld a,[wFirstMonsNotOutYet]
- dec a
- jr z,.next4
- ld a,[wPartyCount]
- dec a
- jr z,.next4
- ld a,[wLinkState]
- cp LINK_STATE_BATTLING
- jr z,.next4
- ld a,[wOptions]
- bit 6,a
- jr nz,.next4
- ld hl, TrainerAboutToUseText
- call PrintText
- coord hl, 0, 7
- lb bc, 8, 1
- ld a,TWO_OPTION_MENU
- ld [wTextBoxID],a
- call DisplayTextBoxID
- ld a,[wCurrentMenuItem]
- and a
- jr nz,.next4
- ld a,BATTLE_PARTY_MENU
- ld [wPartyMenuTypeOrMessageID],a
- call DisplayPartyMenu
-.next9
- ld a,1
- ld [wCurrentMenuItem],a
- jr c,.next7
- ld hl,wPlayerMonNumber
- ld a,[wWhichPokemon]
- cp [hl]
- jr nz,.next6
- ld hl,AlreadyOutText
- call PrintText
-.next8
- call GoBackToPartyMenu
- jr .next9
-.next6
- call HasMonFainted
- jr z,.next8
- xor a
- ld [wCurrentMenuItem],a
-.next7
- call GBPalWhiteOut
- call LoadHudTilePatterns
- call LoadScreenTilesFromBuffer1
-.next4
- call ClearSprites
- coord hl, 0, 0
- lb bc, 4, 11
- call ClearScreenArea
- ld b, SET_PAL_BATTLE
- call RunPaletteCommand
- call GBPalNormal
- ld hl,TrainerSentOutText
- call PrintText
- ld a,[wEnemyMonSpecies2]
- ld [wcf91],a
- ld [wd0b5],a
- call GetMonHeader
- ld de,vFrontPic
- call LoadMonFrontSprite
- ld a,-$31
- ld [hStartTileID],a
- coord hl, 15, 6
- predef AnimateSendingOutMon
- ld a,[wEnemyMonSpecies2]
- call PlayCry
- call DrawEnemyHUDAndHPBar
- ld a,[wCurrentMenuItem]
- and a
- ret nz
- xor a
- ld [wPartyGainExpFlags],a
- ld [wPartyFoughtCurrentEnemyFlags],a
- call SaveScreenTilesToBuffer1
- jp SwitchPlayerMon
-
-TrainerAboutToUseText: ; 3cade (f:4ade)
- TX_FAR _TrainerAboutToUseText
- db "@"
-
-TrainerSentOutText: ; 3cae3 (f:4ae3)
- TX_FAR _TrainerSentOutText
- db "@"
-
-; tests if the player has any pokemon that are not fainted
-; sets d = 0 if all fainted, d != 0 if some mons are still alive
-AnyPartyAlive: ; 3cae8 (f:4ae8)
- ld a, [wPartyCount]
- ld e, a
- xor a
- ld hl, wPartyMon1HP
- ld bc, wPartyMon2 - wPartyMon1 - 1
-.partyMonsLoop
- or [hl]
- inc hl
- or [hl]
- add hl, bc
- dec e
- jr nz, .partyMonsLoop
- ld d, a
- ret
-
-; tests if player mon has fainted
-; stores whether mon has fainted in Z flag
-HasMonFainted: ; 3cafc (f:4afc)
- ld a, [wWhichPokemon]
- ld hl, wPartyMon1HP
- ld bc, wPartyMon2 - wPartyMon1
- call AddNTimes
- ld a, [hli]
- or [hl]
- ret nz
- ld a, [wFirstMonsNotOutYet]
- and a
- jr nz, .done
- ld hl, NoWillText
- call PrintText
-.done
- xor a
- ret
-
-NoWillText: ; 3cb19 (f:4b19)
- TX_FAR _NoWillText
- db "@"
-
-; try to run from battle (hl = player speed, de = enemy speed)
-; stores whether the attempt was successful in carry flag
-TryRunningFromBattle: ; 3cb1e (f:4b1e)
- call IsGhostBattle
- jp z, .canEscape ; jump if it's a ghost battle
- ld a, [wBattleType]
- cp $2
- jp z, .canEscape ; jump if it's a safari battle
- cp $3
- jp z, .canEscape ; hurry, get away?
- ld a, [wLinkState]
- cp LINK_STATE_BATTLING
- jp z, .canEscape
- ld a, [wIsInBattle]
- dec a
- jr nz, .trainerBattle ; jump if it's a trainer battle
- ld a, [wNumRunAttempts]
- inc a
- ld [wNumRunAttempts], a
- ld a, [hli]
- ld [H_MULTIPLICAND + 1], a
- ld a, [hl]
- ld [H_MULTIPLICAND + 2], a
- ld a, [de]
- ld [hEnemySpeed], a
- inc de
- ld a, [de]
- ld [hEnemySpeed + 1], a
- call LoadScreenTilesFromBuffer1
- ld de, H_MULTIPLICAND + 1
- ld hl, hEnemySpeed
- ld c, 2
- call StringCmp
- jr nc, .canEscape ; jump if player speed greater than enemy speed
- xor a
- ld [H_MULTIPLICAND], a
- ld a, 32
- ld [H_MULTIPLIER], a
- call Multiply ; multiply player speed by 32
- ld a, [H_PRODUCT + 2]
- ld [H_DIVIDEND], a
- ld a, [H_PRODUCT + 3]
- ld [H_DIVIDEND + 1], a
- ld a, [hEnemySpeed]
- ld b, a
- ld a, [hEnemySpeed + 1]
-; divide enemy speed by 4
- srl b
- rr a
- srl b
- rr a
- and a
- jr z, .canEscape ; jump if enemy speed divided by 4, mod 256 is 0
- ld [H_DIVISOR], a ; ((enemy speed / 4) % 256)
- ld b, $2
- call Divide ; divide (player speed * 32) by ((enemy speed / 4) % 256)
- ld a, [H_QUOTIENT + 2]
- and a ; is the quotient greater than 256?
- jr nz, .canEscape ; if so, the player can escape
- ld a, [wNumRunAttempts]
- ld c, a
-; add 30 to the quotient for each run attempt
-.loop
- dec c
- jr z, .compareWithRandomValue
- ld b, 30
- ld a, [H_QUOTIENT + 3]
- add b
- ld [H_QUOTIENT + 3], a
- jr c, .canEscape
- jr .loop
-.compareWithRandomValue
- call BattleRandom
- ld b, a
- ld a, [H_QUOTIENT + 3]
- cp b
- jr nc, .canEscape ; if the random value was less than or equal to the quotient
- ; plus 30 times the number of attempts, the player can escape
-; can't escape
- ld a, $1
- ld [wActionResultOrTookBattleTurn], a ; you lose your turn when you can't escape
- ld hl, CantEscapeText
- jr .printCantEscapeOrNoRunningText
-.trainerBattle
- ld hl, NoRunningText
-.printCantEscapeOrNoRunningText
- call PrintText
- ld a, 1
- ld [wForcePlayerToChooseMon], a
- call SaveScreenTilesToBuffer1
- and a ; reset carry
- ret
-.canEscape
- ld a, [wLinkState]
- cp LINK_STATE_BATTLING
- ld a, $2
- jr nz, .playSound
-; link battle
- call SaveScreenTilesToBuffer1
- xor a
- ld [wActionResultOrTookBattleTurn], a
- ld a, $f
- ld [wPlayerMoveListIndex], a
- call LinkBattleExchangeData
- call LoadScreenTilesFromBuffer1
- ld a, [wSerialExchangeNybbleReceiveData]
- cp $f
- ld a, $2
- jr z, .playSound
- dec a
-.playSound
- ld [wBattleResult], a
- ld a, SFX_RUN
- call PlaySoundWaitForCurrent
- ld hl, GotAwayText
- call PrintText
- call WaitForSoundToFinish
- call SaveScreenTilesToBuffer1
- scf ; set carry
- ret
-
-CantEscapeText: ; 3cc01 (f:4c01)
- TX_FAR _CantEscapeText
- db "@"
-
-NoRunningText: ; 3cc06 (f:4c06)
- TX_FAR _NoRunningText
- db "@"
-
-GotAwayText: ; 3cc0b (f:4c0b)
- TX_FAR _GotAwayText
- db "@"
-
-; copies from party data to battle mon data when sending out a new player mon
-LoadBattleMonFromParty: ; 3cc10 (f:4c10)
- ld a, [wWhichPokemon]
- ld bc, wPartyMon2 - wPartyMon1
- ld hl, wPartyMon1Species
- call AddNTimes
- ld de, wBattleMonSpecies
- ld bc, wBattleMonDVs - wBattleMonSpecies
- call CopyData
- ld bc, wPartyMon1DVs - wPartyMon1OTID
- add hl, bc
- ld de, wBattleMonDVs
- ld bc, NUM_DVS
- call CopyData
- ld de, wBattleMonPP
- ld bc, NUM_MOVES
- call CopyData
- ld de, wBattleMonLevel
- ld bc, $b
- call CopyData
- ld a, [wBattleMonSpecies2]
- ld [wd0b5], a
- call GetMonHeader
- ld hl, wPartyMonNicks
- ld a, [wPlayerMonNumber]
- call SkipFixedLengthTextEntries
- ld de, wBattleMonNick
- ld bc, NAME_LENGTH
- call CopyData
- ld hl, wBattleMonLevel
- ld de, wPlayerMonUnmodifiedLevel ; block of memory used for unmodified stats
- ld bc, 1 + NUM_STATS * 2
- call CopyData
- call ApplyBurnAndParalysisPenaltiesToPlayer
- call ApplyBadgeStatBoosts
- ld a, $7 ; default stat modifier
- ld b, NUM_STAT_MODS
- ld hl, wPlayerMonAttackMod
-.statModLoop
- ld [hli], a
- dec b
- jr nz, .statModLoop
- ret
-
-; copies from enemy party data to current enemy mon data when sending out a new enemy mon
-LoadEnemyMonFromParty: ; 3cc7d (f:4c7d)
- ld a, [wWhichPokemon]
- ld bc, wEnemyMon2 - wEnemyMon1
- ld hl, wEnemyMons
- call AddNTimes
- ld de, wEnemyMonSpecies
- ld bc, wEnemyMonDVs - wEnemyMonSpecies
- call CopyData
- ld bc, wEnemyMon1DVs - wEnemyMon1OTID
- add hl, bc
- ld de, wEnemyMonDVs
- ld bc, NUM_DVS
- call CopyData
- ld de, wEnemyMonPP
- ld bc, NUM_MOVES
- call CopyData
- ld de, wEnemyMonLevel
- ld bc, $b
- call CopyData
- ld a, [wEnemyMonSpecies]
- ld [wd0b5], a
- call GetMonHeader
- ld hl, wEnemyMonNicks
- ld a, [wWhichPokemon]
- call SkipFixedLengthTextEntries
- ld de, wEnemyMonNick
- ld bc, NAME_LENGTH
- call CopyData
- ld hl, wEnemyMonLevel
- ld de, wEnemyMonUnmodifiedLevel ; block of memory used for unmodified stats
- ld bc, 1 + NUM_STATS * 2
- call CopyData
- call ApplyBurnAndParalysisPenaltiesToEnemy
- ld hl, wMonHBaseStats
- ld de, wEnemyMonBaseStats
- ld b, NUM_STATS
-.copyBaseStatsLoop
- ld a, [hli]
- ld [de], a
- inc de
- dec b
- jr nz, .copyBaseStatsLoop
- ld a, $7 ; default stat modifier
- ld b, NUM_STAT_MODS
- ld hl, wEnemyMonStatMods
-.statModLoop
- ld [hli], a
- dec b
- jr nz, .statModLoop
- ld a, [wWhichPokemon]
- ld [wEnemyMonPartyPos], a
- ret
-
-SendOutMon: ; 3ccfb (f:4cfb)
- callab PrintSendOutMonMessage
- ld hl, wEnemyMonHP
- ld a, [hli]
- or [hl] ; is enemy mon HP zero?
- jp z, .skipDrawingEnemyHUDAndHPBar; if HP is zero, skip drawing the HUD and HP bar
- call DrawEnemyHUDAndHPBar
-.skipDrawingEnemyHUDAndHPBar
- call DrawPlayerHUDAndHPBar
- predef LoadMonBackPic
- xor a
- ld [hStartTileID], a
- ld hl, wBattleAndStartSavedMenuItem
- ld [hli], a
- ld [hl], a
- ld [wBoostExpByExpAll], a
- ld [wDamageMultipliers], a
- ld [wPlayerMoveNum], a
- ld hl, wPlayerUsedMove
- ld [hli], a
- ld [hl], a
- ld hl, wPlayerStatsToDouble
- ld [hli], a
- ld [hli], a
- ld [hli], a
- ld [hli], a
- ld [hl], a
- ld [wPlayerDisabledMove], a
- ld [wPlayerDisabledMoveNumber], a
- ld [wPlayerMonMinimized], a
- ld b, SET_PAL_BATTLE
- call RunPaletteCommand
- ld hl, wEnemyBattleStatus1
- res UsingTrappingMove, [hl]
- callab IsThisPartymonStarterPikachu
- jr c, .starterPikachu
- ld a, $1
- ld [H_WHOSETURN], a
- ld a, POOF_ANIM
- call PlayMoveAnimation
- coord hl, 4, 11
- predef AnimateSendingOutMon
- jr .playRegularCry
-.starterPikachu
- xor a
- ld [H_WHOSETURN], a
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- callab Func_f429f
- callab Func_fd0d0
- ld e, $24
- jr c, .asm_3cd81
- ld e, $a
-.asm_3cd81
- callab PlayPikachuSoundClip
- jr .done
-.playRegularCry
- ld a, [wcf91]
- call PlayCry
-.done
- call PrintEmptyString
- jp SaveScreenTilesToBuffer1
-
-; show 2 stages of the player mon getting smaller before disappearing
-AnimateRetreatingPlayerMon: ; 3cd97 (f:4d97)
- ld a, [wWhichPokemon]
- push af
- ld a, [wPlayerMonNumber]
- ld [wWhichPokemon], a
- callab IsThisPartymonStarterPikachu
- pop bc
- ld a, b
- ld [wWhichPokemon], a
- jr c, .starterPikachu
- coord hl, 1, 5
- lb bc, 7, 7
- call ClearScreenArea
- coord hl, 3, 7
- lb bc, 5, 5
- xor a
- ld [wDownscaledMonSize], a
- ld [hBaseTileID], a
- predef CopyDownscaledMonTiles
- ld c, 4
- call DelayFrames
- call .clearScreenArea
- coord hl, 4, 9
- lb bc, 3, 3
- ld a, 1
- ld [wDownscaledMonSize], a
- xor a
- ld [hBaseTileID], a
- predef CopyDownscaledMonTiles
- call Delay3
- call .clearScreenArea
- ld a, $4c
- Coorda 5, 11
- jr .clearScreenArea
-.starterPikachu
- xor a
- ld [H_WHOSETURN], a
- callab AnimationSlideMonOff
- ret
-.clearScreenArea
- coord hl, 1, 5
- lb bc, 7, 7
- call ClearScreenArea ; jp
- ret
-
-; reads player's current mon's HP into wBattleMonHP
-ReadPlayerMonCurHPAndStatus: ; 3ce08 (f:4e08)
- ld a, [wPlayerMonNumber]
- ld hl, wPartyMon1HP
- ld bc, wPartyMon2 - wPartyMon1
- call AddNTimes
- ld d, h
- ld e, l
- ld hl, wBattleMonHP
- ld bc, $4 ; 2 bytes HP, 1 byte unknown (unused?), 1 byte status
- jp CopyData
-
-DrawHUDsAndHPBars: ; 3ce1f (f:4e1f)
- call DrawPlayerHUDAndHPBar
- jp DrawEnemyHUDAndHPBar
-
-DrawPlayerHUDAndHPBar: ; 3ce25 (f:4e25)
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- coord hl, 9, 7
- lb bc, 5, 11
- call ClearScreenArea
- callab PlacePlayerHUDTiles
- coord hl, 18, 9
- ld [hl], $73
- ld de, wBattleMonNick
- coord hl, 10, 7
- call CenterMonName
- call PlaceString
- ld hl, wBattleMonSpecies
- ld de, wLoadedMon
- ld bc, $c
- call CopyData
- ld hl, wBattleMonLevel
- ld de, wLoadedMonLevel
- ld bc, $b
- call CopyData
- coord hl, 14, 8
- push hl
- inc hl
- ld de, wLoadedMonStatus
- call PrintStatusConditionNotFainted
- pop hl
- jr nz, .doNotPrintLevel
- call PrintLevel
-.doNotPrintLevel
- ld a, [wLoadedMonSpecies]
- ld [wcf91], a
- coord hl, 10, 9
- predef DrawHP
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- ld hl, wPlayerHPBarColor
- call GetBattleHealthBarColor
- ld hl, wBattleMonHP
- ld a, [hli]
- or [hl]
- jr z, .fainted
- ld a, [wLowHealthAlarmDisabled]
- and a ; has the alarm been disabled because the player has already won?
- ret nz ; if so, return
- ld a, [wPlayerHPBarColor]
- cp HP_BAR_RED
- jr z, .setLowHealthAlarm
-.fainted
- ld hl, wLowHealthAlarm
- bit 7, [hl] ;low health alarm enabled?
- ld [hl], $0
- ret z
- xor a
- ld [wChannelSoundIDs + CH4], a
- ret
-.setLowHealthAlarm
- ld hl, wLowHealthAlarm
- set 7, [hl] ;enable low health alarm
- ret
-
-DrawEnemyHUDAndHPBar: ; 3ceb1 (f:4eb1)
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- coord hl, 0, 0
- lb bc, 4, 12
- call ClearScreenArea
- callab PlaceEnemyHUDTiles
- ld de, wEnemyMonNick
- coord hl, 1, 0
- call CenterMonName
- call PlaceString
- coord hl, 4, 1
- push hl
- inc hl
- ld de, wEnemyMonStatus
- call PrintStatusConditionNotFainted
- pop hl
- jr nz, .skipPrintLevel ; if the mon has a status condition, skip printing the level
- ld a, [wEnemyMonLevel]
- ld [wLoadedMonLevel], a
- call PrintLevel
-.skipPrintLevel
- ld hl, wEnemyMonHP
- ld a, [hli]
- ld [H_MULTIPLICAND + 1], a
- ld a, [hld]
- ld [H_MULTIPLICAND + 2], a
- or [hl] ; is current HP zero?
- jr nz, .hpNonzero
-; current HP is 0
-; set variables for DrawHPBar
- ld c, a
- ld e, a
- ld d, $6
- jp .drawHPBar
-.hpNonzero
- xor a
- ld [H_MULTIPLICAND], a
- ld a, 48
- ld [H_MULTIPLIER], a
- call Multiply ; multiply current HP by 48
- ld hl, wEnemyMonMaxHP
- ld a, [hli]
- ld b, a
- ld a, [hl]
- ld [H_DIVISOR], a
- ld a, b
- and a ; is max HP > 255?
- jr z, .doDivide
-; if max HP > 255, scale both (current HP * 48) and max HP by dividing by 4 so that max HP fits in one byte
-; (it needs to be one byte so it can be used as the divisor for the Divide function)
- ld a, [H_DIVISOR]
- srl b
- rr a
- srl b
- rr a
- ld [H_DIVISOR], a
- ld a, [H_PRODUCT + 2]
- ld b, a
- srl b
- ld a, [H_PRODUCT + 3]
- rr a
- srl b
- rr a
- ld [H_PRODUCT + 3], a
- ld a, b
- ld [H_PRODUCT + 2], a
-.doDivide
- ld a, [H_PRODUCT + 2]
- ld [H_DIVIDEND], a
- ld a, [H_PRODUCT + 3]
- ld [H_DIVIDEND + 1], a
- ld a, $2
- ld b, a
- call Divide ; divide (current HP * 48) by max HP
- ld a, [H_QUOTIENT + 3]
-; set variables for DrawHPBar
- ld e, a
- ld a, $6
- ld d, a
- ld c, a
-.drawHPBar
- xor a
- ld [wHPBarType], a
- coord hl, 2, 2
- call DrawHPBar
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- ld hl, wEnemyHPBarColor
-
-GetBattleHealthBarColor: ; 3cf55 (f:4f55)
- ld b, [hl]
- call GetHealthBarColor
- ld a, [hl]
- cp b
- ret z
- ld b, SET_PAL_BATTLE
- jp RunPaletteCommand
-
-; center's mon's name on the battle screen
-; if the name is 1 or 2 letters long, it is printed 2 spaces more to the right than usual
-; (i.e. for names longer than 4 letters)
-; if the name is 3 or 4 letters long, it is printed 1 space more to the right than usual
-; (i.e. for names longer than 4 letters)
-CenterMonName: ; 3cf61 (f:4f61)
- push de
- inc hl
- inc hl
- ld b, $2
-.loop
- inc de
- ld a, [de]
- cp "@"
- jr z, .done
- inc de
- ld a, [de]
- cp "@"
- jr z, .done
- dec hl
- dec b
- jr nz, .loop
-.done
- pop de
- ret
-
-DisplayBattleMenu: ; 3cf78 (f:4f78)
- call LoadScreenTilesFromBuffer1 ; restore saved screen
- ld a, [wBattleType]
- and a
- jr nz, .nonstandardbattle
- call DrawHUDsAndHPBars
- call PrintEmptyString
- call SaveScreenTilesToBuffer1
-.nonstandardbattle
- ld a, [wBattleType]
- cp $2 ; safari
- ld a, BATTLE_MENU_TEMPLATE
- jr nz, .menuselected
- ld a, SAFARI_BATTLE_MENU_TEMPLATE
-.menuselected
- ld [wTextBoxID], a
- call DisplayTextBoxID
- ld a, [wBattleType]
- cp $1
- jr z, .doSimulatedMenuInput ; simulate menu input if it's the old man or prof. oak pikachu battle
- cp $4
- jr z, .doSimulatedMenuInput
- jp .handleBattleMenuInput
-; the following happens for the old man tutorial and prof. oak pikachu battle
-.doSimulatedMenuInput
- ld hl, wPlayerName
- ld de, wGrassRate
- ld bc, NAME_LENGTH
- call CopyData ; temporarily save the player name in unused space,
- ; which is supposed to get overwritten when entering a
- ; map with wild Pokémon.
- ; In Red/Blue, due to an oversight, the data
- ; may not get overwritten (cinnabar) and the infamous
- ; Missingno. glitch can show up. However,
- ; this has been fixed in yellow
- ld hl, .oldManName
- ld a, [wBattleType]
- dec a
- jr z, .useOldManName
- ld hl, .profOakName
-.useOldManName
- ld de, wPlayerName
- ld bc, NAME_LENGTH
- call CopyData
-; the following simulates the keystrokes by drawing menus on screen
- coord hl, 9, 14
- ld [hl], "▶"
- ld c, 20
- call DelayFrames
- ld [hl], " "
- coord hl, 9, 16
- ld [hl], "▶"
- ld c, 20
- call DelayFrames
- ld [hl], $ec
- ld a, $2 ; select the "ITEM" menu
- jp .upperLeftMenuItemWasNotSelected
-.oldManName
- db "OLD MAN@"
-.profOakName
- db "PROF.OAK@"
-.handleBattleMenuInput
- ld a, [wBattleAndStartSavedMenuItem]
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- sub 2 ; check if the cursor is in the left column
- jr c, .leftColumn
-; cursor is in the right column
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- jr .rightColumn
-.leftColumn ; put cursor in left column of menu
- ld a, [wBattleType]
- cp $2
- ld a, " "
- jr z, .safariLeftColumn
-; put cursor in left column for normal battle menu (i.e. when it's not a Safari battle)
- Coorda 15, 14 ; clear upper cursor position in right column
- Coorda 15, 16 ; clear lower cursor position in right column
- ld b, $9 ; top menu item X
- jr .leftColumn_WaitForInput
-.safariLeftColumn
- Coorda 13, 14
- Coorda 13, 16
- coord hl, 7, 14
- ld de, wNumSafariBalls
- lb bc, 1, 2
- call PrintNumber
- ld b, $1 ; top menu item X
-.leftColumn_WaitForInput
- ld hl, wTopMenuItemY
- ld a, $e
- ld [hli], a ; wTopMenuItemY
- ld a, b
- ld [hli], a ; wTopMenuItemX
- inc hl
- inc hl
- ld a, $1
- ld [hli], a ; wMaxMenuItem
- ld [hl], D_RIGHT | A_BUTTON ; wMenuWatchedKeys
- call HandleMenuInput
- bit 4, a ; check if right was pressed
- jr nz, .rightColumn
- jr .AButtonPressed ; the A button was pressed
-.rightColumn ; put cursor in right column of menu
- ld a, [wBattleType]
- cp $2
- ld a, " "
- jr z, .safariRightColumn
-; put cursor in right column for normal battle menu (i.e. when it's not a Safari battle)
- Coorda 9, 14 ; clear upper cursor position in left column
- Coorda 9, 16 ; clear lower cursor position in left column
- ld b, $f ; top menu item X
- jr .rightColumn_WaitForInput
-.safariRightColumn
- Coorda 1, 14 ; clear upper cursor position in left column
- Coorda 1, 16 ; clear lower cursor position in left column
- coord hl, 7, 14
- ld de, wNumSafariBalls
- lb bc, 1, 2
- call PrintNumber
- ld b, $d ; top menu item X
-.rightColumn_WaitForInput
- ld hl, wTopMenuItemY
- ld a, $e
- ld [hli], a ; wTopMenuItemY
- ld a, b
- ld [hli], a ; wTopMenuItemX
- inc hl
- inc hl
- ld a, $1
- ld [hli], a ; wMaxMenuItem
- ld a, D_LEFT | A_BUTTON
- ld [hli], a ; wMenuWatchedKeys
- call HandleMenuInput
- bit 5, a ; check if left was pressed
- jr nz, .leftColumn ; if left was pressed, jump
- ld a, [wCurrentMenuItem]
- add $2 ; if we're in the right column, the actual id is +2
- ld [wCurrentMenuItem], a
-.AButtonPressed
- call PlaceUnfilledArrowMenuCursor
- ld a, [wBattleType]
- cp HURRY_RUN_AWAY_BATTLE
- jr z, .handleUnusedBattle
- ld a, [wBattleType]
- cp SAFARI_BATTLE ; is it a Safari battle?
- ld a, [wCurrentMenuItem]
- ld [wBattleAndStartSavedMenuItem], a
- jr z, .handleMenuSelection
-; not Safari battle
-; swap the IDs of the item menu and party menu (this is probably because they swapped the positions
-; of these menu items in first generation English versions)
- cp $1 ; was the item menu selected?
- jr nz, .notItemMenu
-; item menu was selected
- inc a ; increment a to 2
- jr .handleMenuSelection
-.notItemMenu
- cp $2 ; was the party menu selected?
- jr nz, .handleMenuSelection
-; party menu selected
- dec a ; decrement a to 1
-.handleMenuSelection
- and a
- jr nz, .upperLeftMenuItemWasNotSelected
-; the upper left menu item was selected
- ld a, [wBattleType]
- cp $2
- jr z, .throwSafariBallWasSelected
-; the "FIGHT" menu was selected
- xor a
- ld [wNumRunAttempts], a
- jp LoadScreenTilesFromBuffer1 ; restore saved screen and return
-.throwSafariBallWasSelected
- ld a, SAFARI_BALL
- ld [wcf91], a
- jp UseBagItem
-.handleUnusedBattle
- ld a, [wCurrentMenuItem]
- cp $3
- jp z, BattleMenu_RunWasSelected
- ld hl, .RunAwayText
- call PrintText
- jp DisplayBattleMenu
-
-.RunAwayText ; 3d0df (f:50df)
- TX_FAR _RunAwayText
- db "@"
-
-.upperLeftMenuItemWasNotSelected ; a menu item other than the upper left item was selected
- cp $2
- jp nz, PartyMenuOrRockOrRun
-
-; either the bag (normal battle) or bait (safari battle) was selected
- ld a, [wLinkState]
- cp LINK_STATE_BATTLING
- jr nz, .notLinkBattle
-
-; can't use items in link battles
- ld hl, ItemsCantBeUsedHereText
- call PrintText
- jp DisplayBattleMenu
-
-.notLinkBattle
- call SaveScreenTilesToBuffer2
- ld a, [wBattleType]
- cp $2 ; is it a safari battle?
- jr nz, BagWasSelected
-
-; bait was selected
- ld a, SAFARI_BAIT
- ld [wcf91], a
- jr UseBagItem
-
-BagWasSelected: ; 3d10a (f:510a)
- call LoadScreenTilesFromBuffer1
- ld a, [wBattleType]
- and a ; is it a normal battle?
- jr nz, .next
-
-; normal battle
- call DrawHUDsAndHPBars
-.next
- ld a, [wBattleType]
- cp OLD_MAN_BATTLE ; is it the old man tutorial?
- jr z, .simulatedInputBattle
- cp STARTER_PIKACHU_BATTLE ; is it the prof oak battle with pikachu?
- jr z, .simulatedInputBattle
- jr DisplayPlayerBag
-.simulatedInputBattle
- ld hl, SimulatedInputBattleItemList
- ld a, l
- ld [wListPointer], a
- ld a, h
- ld [wListPointer + 1], a
- jr DisplayBagMenu
-
-SimulatedInputBattleItemList: ; 3c130 (f:5130)
- db 1 ; # of items
- db POKE_BALL, 1
- db $ff
-
-DisplayPlayerBag: ; 3c134 (f:5134)
- ; get the pointer to player's bag when in a normal battle
- ld hl, wNumBagItems
- ld a, l
- ld [wListPointer], a
- ld a, h
- ld [wListPointer + 1], a
-
-DisplayBagMenu: ; 3c13f (f:513f)
- xor a
- ld [wPrintItemPrices], a
- ld a, ITEMLISTMENU
- ld [wListMenuID], a
- ld a, [wBagSavedMenuItem]
- ld [wCurrentMenuItem], a
- call DisplayListMenuID
- ld a, [wCurrentMenuItem]
- ld [wBagSavedMenuItem], a
- ld a, $0
- ld [wMenuWatchMovingOutOfBounds], a
- ld [wMenuItemToSwap], a
- jp c, DisplayBattleMenu ; go back to battle menu if an item was not selected
-
-UseBagItem: ; 3c162 (f:5162)
- ; either use an item from the bag or use a safari zone item
- ld a, [wcf91]
- ld [wd11e], a
- call GetItemName
- call CopyStringToCF4B ; copy name
- xor a
- ld [wPseudoItemID], a
- call UseItem
- call LoadHudTilePatterns
- call ClearSprites
- xor a
- ld [wCurrentMenuItem], a
- ld a, [wBattleType]
- cp SAFARI_BATTLE ; is it a safari battle?
- jr z, .checkIfMonCaptured
-
- ld a, [wActionResultOrTookBattleTurn]
- and a ; was the item used successfully?
- jp z, BagWasSelected ; if not, go back to the bag menu
-
- ld a, [wPlayerBattleStatus1]
- bit UsingTrappingMove, a ; is the player using a multi-turn move like wrap?
- jr z, .checkIfMonCaptured
- ld hl, wPlayerNumAttacksLeft
- dec [hl]
- jr nz, .checkIfMonCaptured
- ld hl, wPlayerBattleStatus1
- res UsingTrappingMove, [hl] ; not using multi-turn move any more
-
-.checkIfMonCaptured
- ld a, [wCapturedMonSpecies]
- and a ; was the enemy mon captured with a ball?
- jr nz, .returnAfterCapturingMon
-
- ld a, [wBattleType]
- cp SAFARI_BATTLE ; is it a safari battle?
- jr z, .returnAfterUsingItem_NoCapture
-; not a safari battle
- call LoadScreenTilesFromBuffer1
- call DrawHUDsAndHPBars
- call Delay3
-.returnAfterUsingItem_NoCapture
-
- call GBPalNormal
- and a ; reset carry
- ret
-
-.returnAfterCapturingMon
- call GBPalNormal
- xor a
- ld [wCapturedMonSpecies], a
- ld a, $2
- ld [wBattleResult], a
- scf ; set carry
- ret
-
-ItemsCantBeUsedHereText: ; 3d1c8 (f:51c8)
- TX_FAR _ItemsCantBeUsedHereText
- db "@"
-
-PartyMenuOrRockOrRun: ; 3d1cd (f:51cd)
- dec a ; was Run selected?
- jp nz, BattleMenu_RunWasSelected
-; party menu or rock was selected
- call SaveScreenTilesToBuffer2
- ld a, [wBattleType]
- cp $2 ; is it a safari battle?
- jr nz, .partyMenuWasSelected
-; safari battle
- ld a, SAFARI_ROCK
- ld [wcf91], a
- jp UseBagItem
-.partyMenuWasSelected
- call LoadScreenTilesFromBuffer1
- xor a ; NORMAL_PARTY_MENU
- ld [wPartyMenuTypeOrMessageID], a
- ld [wMenuItemToSwap], a
- call DisplayPartyMenu
-.checkIfPartyMonWasSelected
- jp nc, .partyMonWasSelected ; if a party mon was selected, jump, else we quit the party menu
-.quitPartyMenu
- call ClearSprites
- call GBPalWhiteOut
- call LoadHudTilePatterns
- call LoadScreenTilesFromBuffer2
- call RunDefaultPaletteCommand
- call GBPalNormal
- jp DisplayBattleMenu
-.partyMonDeselected
- coord hl, 11, 11
- ld bc, 6 * SCREEN_WIDTH + 9
- ld a, " "
- call FillMemory
- xor a ; NORMAL_PARTY_MENU
- ld [wPartyMenuTypeOrMessageID], a
- call GoBackToPartyMenu
- jr .checkIfPartyMonWasSelected
-.partyMonWasSelected
- ld a, SWITCH_STATS_CANCEL_MENU_TEMPLATE
- ld [wTextBoxID], a
- call DisplayTextBoxID
- ld hl, wTopMenuItemY
- ld a, $c
- ld [hli], a ; wTopMenuItemY
- ld [hli], a ; wTopMenuItemX
- xor a
- ld [hli], a ; wCurrentMenuItem
- inc hl
- ld a, $2
- ld [hli], a ; wMaxMenuItem
- ld a, B_BUTTON | A_BUTTON
- ld [hli], a ; wMenuWatchedKeys
- xor a
- ld [hl], a ; wLastMenuItem
- call HandleMenuInput
- bit 1, a ; was A pressed?
- jr nz, .partyMonDeselected ; if B was pressed, jump
-; A was pressed
- call PlaceUnfilledArrowMenuCursor
- ld a, [wCurrentMenuItem]
- cp $2 ; was Cancel selected?
- jr z, .quitPartyMenu ; if so, quit the party menu entirely
- and a ; was Switch selected?
- jr z, .switchMon ; if so, jump
-; Stats was selected
- xor a ; PLAYER_PARTY_DATA
- ld [wMonDataLocation], a
- ld hl, wPartyMon1
- call ClearSprites
-; display the two status screens
- predef StatusScreen
- predef StatusScreen2
-; now we need to reload the enemy mon pic
- ld a, $1
- ld [H_WHOSETURN], a
- ld a, [wEnemyBattleStatus2]
- bit HasSubstituteUp, a ; does the enemy mon have a substitute?
- ld hl, AnimationSubstitute
- jr nz, .doEnemyMonAnimation
-; enemy mon doesn't have substitute
- ld a, [wEnemyMonMinimized]
- and a ; has the enemy mon used Minimise?
- ld hl, AnimationMinimizeMon
- jr nz, .doEnemyMonAnimation
-; enemy mon is not minimised
- ld a, [wEnemyMonSpecies]
- ld [wcf91], a
- ld [wd0b5], a
- call GetMonHeader
- ld de, vFrontPic
- call LoadMonFrontSprite
- jr .enemyMonPicReloaded
-.doEnemyMonAnimation
- ld b, BANK(AnimationSubstitute) ; BANK(AnimationMinimizeMon)
- call Bankswitch
-.enemyMonPicReloaded ; enemy mon pic has been reloaded, so return to the party menu
- jp .partyMenuWasSelected
-.switchMon
- ld a, [wPlayerMonNumber]
- ld d, a
- ld a, [wWhichPokemon]
- cp d ; check if the mon to switch to is already out
- jr nz, .notAlreadyOut
-; mon is already out
- ld hl, AlreadyOutText
- call PrintText
- jp .partyMonDeselected
-.notAlreadyOut
- call HasMonFainted
- jp z, .partyMonDeselected ; can't switch to fainted mon
- ld a, $1
- ld [wActionResultOrTookBattleTurn], a
- call GBPalWhiteOut
- call ClearSprites
- call LoadHudTilePatterns
- call LoadScreenTilesFromBuffer1
- call RunDefaultPaletteCommand
- call GBPalNormal
-; fall through to SwitchPlayerMon
-
-SwitchPlayerMon: ; 3d2c1 (f:52c1)
- callab RetreatMon
- ld c, 50
- call DelayFrames
- call AnimateRetreatingPlayerMon
- ld a, [wWhichPokemon]
- ld [wPlayerMonNumber], a
- ld c, a
- ld b, FLAG_SET
- push bc
- ld hl, wPartyGainExpFlags
- predef FlagActionPredef
- pop bc
- ld hl, wPartyFoughtCurrentEnemyFlags
- predef FlagActionPredef
- call LoadBattleMonFromParty
- call SendOutMon
- call SaveScreenTilesToBuffer1
- ld a, $2
- ld [wCurrentMenuItem], a
- and a
- ret
-
-AlreadyOutText: ; 3d2fc (f:52fc)
- TX_FAR _AlreadyOutText
- db "@"
-
-BattleMenu_RunWasSelected: ; 3d301 (f:5301)
- call LoadScreenTilesFromBuffer1
- ld a, $3
- ld [wCurrentMenuItem], a
- ld hl, wBattleMonSpeed
- ld de, wEnemyMonSpeed
- call TryRunningFromBattle
- ld a, 0
- ld [wForcePlayerToChooseMon], a
- ret c
- ld a, [wActionResultOrTookBattleTurn]
- and a
- ret nz ; return if the player couldn't escape
- jp DisplayBattleMenu
-
-MoveSelectionMenu: ; 3d320 (f:5320)
- ld a, [wMoveMenuType]
- dec a
- jr z, .mimicmenu
- dec a
- jr z, .relearnmenu
- jr .regularmenu
-
-.loadmoves
- ld de, wMoves
- ld bc, NUM_MOVES
- call CopyData
- callab FormatMovesString
- ret
-
-.writemoves
- ld de, wMovesString
- ld a, [hFlags_0xFFFA]
- set 2, a
- ld [hFlags_0xFFFA], a
- call PlaceString
- ld a, [hFlags_0xFFFA]
- res 2, a
- ld [hFlags_0xFFFA], a
- ret
-
-.regularmenu
- call AnyMoveToSelect
- ret z
- ld hl, wBattleMonMoves
- call .loadmoves
- coord hl, 4, 12
- lb bc, 4, 14
- di ; out of pure coincidence, it is possible for vblank to occur between the di and ei
- ; so it is necessary to put the di ei block to not cause tearing
- call TextBoxBorder
- coord hl, 4, 12
- ld [hl], $7a
- coord hl, 10, 12
- ld [hl], $7e
- ei
- coord hl, 6, 13
- call .writemoves
- ld b, $5
- ld a, $c
- jr .menuset
-.mimicmenu
- ld hl, wEnemyMonMoves
- call .loadmoves
- coord hl, 0, 7
- lb bc, 4, 14
- call TextBoxBorder
- coord hl, 2, 8
- call .writemoves
- ld b, $1
- ld a, $7
- jr .menuset
-.relearnmenu
- ld a, [wWhichPokemon]
- ld hl, wPartyMon1Moves
- ld bc, wPartyMon2 - wPartyMon1
- call AddNTimes
- call .loadmoves
- coord hl, 4, 7
- lb bc, 4, 14
- call TextBoxBorder
- coord hl, 6, 8
- call .writemoves
- ld b, $5
- ld a, $7
-.menuset
- ld hl, wTopMenuItemY
- ld [hli], a ; wTopMenuItemY
- ld a, b
- ld [hli], a ; wTopMenuItemX
- ld a, [wMoveMenuType]
- cp $1
- jr z, .selectedmoveknown
- ld a, [wPlayerMoveListIndex]
- inc a
-.selectedmoveknown
- ld [hli], a ; wCurrentMenuItem
- inc hl ; wTileBehindCursor untouched
- ld a, [wNumMovesMinusOne]
- inc a
- inc a
- ld [hli], a ; wMaxMenuItem
- ld a, [wMoveMenuType]
- dec a
- ld b, D_UP | D_DOWN | A_BUTTON
- jr z, .matchedkeyspicked
- dec a
- ld b, D_UP | D_DOWN | A_BUTTON | B_BUTTON
- jr z, .matchedkeyspicked
- ld a, [wLinkState]
- cp LINK_STATE_BATTLING
- jr z, .matchedkeyspicked
- ld a, [wFlags_D733]
- bit BIT_TEST_BATTLE, a
- ld b, D_UP | D_DOWN | A_BUTTON | B_BUTTON | SELECT
- jr z, .matchedkeyspicked
- ld b, $ff
-.matchedkeyspicked
- ld a, b
- ld [hli], a ; wMenuWatchedKeys
- ld a, [wMoveMenuType]
- cp $1
- jr z, .movelistindex1
- ld a, [wPlayerMoveListIndex]
- inc a
-.movelistindex1
- ld [hl], a
-; fallthrough
-
-SelectMenuItem: ; 3d3fe (f:53fe)
- ld a, [wMoveMenuType]
- and a
- jr z, .battleselect
- dec a
- jr nz, .select
- coord hl, 1, 14
- ld de, WhichTechniqueString
- call PlaceString
- jr .select
-.battleselect
- ld a, [wFlags_D733]
- bit BIT_TEST_BATTLE, a
- jr nz, .select
- call PrintMenuItem
- ld a, [wMenuItemToSwap]
- and a
- jr z, .select
- coord hl, 5, 13
- dec a
- ld bc, SCREEN_WIDTH
- call AddNTimes
- ld [hl], $ec
-.select
- ld hl, hFlags_0xFFFA
- set 1, [hl]
- call HandleMenuInput
- ld hl, hFlags_0xFFFA
- res 1, [hl]
- bit 6, a
- jp nz, SelectMenuItem_CursorUp ; up
- bit 7, a
- jp nz, SelectMenuItem_CursorDown ; down
- bit 2, a
- jp nz, SwapMovesInMenu ; select
- bit 1, a ; B, but was it reset above?
- push af
- xor a
- ld [wMenuItemToSwap], a
- ld a, [wCurrentMenuItem]
- dec a
- ld [wCurrentMenuItem], a
- ld b, a
- ld a, [wMoveMenuType]
- dec a ; if not mimic
- jr nz, .notB
- pop af
- ret
-.notB
- dec a
- ld a, b
- ld [wPlayerMoveListIndex], a
- jr nz, .moveselected
- pop af
- ret
-.moveselected
- pop af
- ret nz
- ld hl, wBattleMonPP
- ld a, [wCurrentMenuItem]
- ld c, a
- ld b, $0
- add hl, bc
- ld a, [hl]
- and $3f
- jr z, .noPP
- ld a, [wPlayerDisabledMove]
- swap a
- and $f
- dec a
- cp c
- jr z, .disabled
- ld a, [wPlayerBattleStatus3]
- bit 3, a ; transformed
- jr nz, .dummy ; game freak derp
-.dummy
- ld a, [wCurrentMenuItem]
- ld hl, wBattleMonMoves
- ld c, a
- ld b, $0
- add hl, bc
- ld a, [hl]
- ld [wPlayerSelectedMove], a
- xor a
- ret
-.disabled
- ld hl, MoveDisabledText
- jr .print
-.noPP
- ld hl, MoveNoPPText
-.print
- call PrintText
- call LoadScreenTilesFromBuffer1
- jp MoveSelectionMenu
-
-MoveNoPPText: ; 3d4ae (f:54ae)
- TX_FAR _MoveNoPPText
- db "@"
-
-MoveDisabledText: ; 3d4b3 (f:54b3)
- TX_FAR _MoveDisabledText
- db "@"
-
-WhichTechniqueString: ; 3d4b8 (f:54b8)
- db "WHICH TECHNIQUE?@"
-
-SelectMenuItem_CursorUp: ; 3d4c9 (f:54c9)
- ld a, [wCurrentMenuItem]
- and a
- jp nz, SelectMenuItem
- call EraseMenuCursor
- ld a, [wNumMovesMinusOne]
- inc a
- ld [wCurrentMenuItem], a
- jp SelectMenuItem
-
-SelectMenuItem_CursorDown: ; 3d4dd (f:54dd)
- ld a, [wCurrentMenuItem]
- ld b, a
- ld a, [wNumMovesMinusOne]
- inc a
- inc a
- cp b
- jp nz, SelectMenuItem
- call EraseMenuCursor
- ld a, $1
- ld [wCurrentMenuItem], a
- jp SelectMenuItem
-
-Func_3d4f5: ; 3d4f5 (f:54f5)
- bit 3, a
- ld a, $0
- jr nz, .asm_3d4fd
- ld a, $1
-.asm_3d4fd
- ld [H_WHOSETURN], a
- call LoadScreenTilesFromBuffer1
- call Func_3d536
- ld a, [wTestBattlePlayerSelectedMove]
- and a
- jp z, MoveSelectionMenu
- ld [wAnimationID], a
- xor a
- ld [wAnimationType], a
- predef MoveAnimation
- callab Func_78e98
- jp MoveSelectionMenu
-
-Func_3d523: ; 3d523 (f:5523)
- ld a, [wTestBattlePlayerSelectedMove]
- dec a
- jr asm_3d52d
-Func_3d529: ; 3d529 (f:5529)
- ld a, [wTestBattlePlayerSelectedMove]
- inc a
-asm_3d52d: ; 3d52d (f:552d)
- ld [wTestBattlePlayerSelectedMove], a
- call Func_3d536
- jp MoveSelectionMenu
-
-Func_3d536: ; 3d536 (f:5536)
- coord hl, 10, 16
- lb bc, 2, 10
- call ClearScreenArea
- coord hl, 10, 17
- ld de, wTestBattlePlayerSelectedMove
- lb bc, LEADING_ZEROES | 1, 3
- call PrintNumber
- ld a, [wTestBattlePlayerSelectedMove]
- and a
- ret z
- cp STRUGGLE
- ret nc
- ld [wd11e], a
- call GetMoveName
- coord hl, 13, 17
- jp PlaceString
-
-AnyMoveToSelect: ; 3d55f (f:555f)
-; return z and Struggle as the selected move if all moves have 0 PP and/or are disabled
- ld a, STRUGGLE
- ld [wPlayerSelectedMove], a
- ld a, [wPlayerDisabledMove]
- and a
- ld hl, wBattleMonPP
- jr nz, .handleDisabledMove
- ld a, [hli]
- or [hl]
- inc hl
- or [hl]
- inc hl
- or [hl]
- and $3f
- ret nz
- jr .noMovesLeft
-.handleDisabledMove
- swap a
- and $f ; get move disabled
- ld b, a
- ld d, NUM_MOVES + 1
- xor a
-.handleDisabledMovePPLoop
- dec d
- jr z, .allMovesChecked
- ld c, [hl] ; get move PP
- inc hl
- dec b ; is this the disabled move?
- jr z, .handleDisabledMovePPLoop ; if so, ignore its PP value
- or c
- jr .handleDisabledMovePPLoop
-.allMovesChecked
-; bugfix: only check PP value and not PP up bits
-; in case all other moves have no PP left and a move has a PP up used on it
-; and a non-PP up move is disabled
- and $3f ; any PP left?
- ret nz ; return if a move has PP left
-.noMovesLeft
- ld hl, NoMovesLeftText
- call PrintText
- ld c, 60
- call DelayFrames
- xor a
- ret
-
-NoMovesLeftText: ; 3d59b (f:559b)
- TX_FAR _NoMovesLeftText
- db "@"
-
-SwapMovesInMenu: ; 3d5a0 (f:55a0)
- ld a, [wPlayerBattleStatus3]
- bit Transformed, a
- jp nz, MoveSelectionMenu
- ld a, [wMenuItemToSwap]
- and a
- jr z, .noMenuItemSelected
- ld hl, wBattleMonMoves
- call .swapBytes ; swap moves
- ld hl, wBattleMonPP
- call .swapBytes ; swap move PP
-; update the index of the disabled move if necessary
- ld hl, wPlayerDisabledMove
- ld a, [hl]
- swap a
- and $f
- ld b, a
- ld a, [wCurrentMenuItem]
- cp b
- jr nz, .next
- ld a, [hl]
- and $f
- ld b, a
- ld a, [wMenuItemToSwap]
- swap a
- add b
- ld [hl], a
- jr .swapMovesInPartyMon
-.next
- ld a, [wMenuItemToSwap]
- cp b
- jr nz, .swapMovesInPartyMon
- ld a, [hl]
- and $f
- ld b, a
- ld a, [wCurrentMenuItem]
- swap a
- add b
- ld [hl], a
-.swapMovesInPartyMon
- ld hl, wPartyMon1Moves
- ld a, [wPlayerMonNumber]
- ld bc, wPartyMon2 - wPartyMon1
- call AddNTimes
- push hl
- call .swapBytes ; swap moves
- pop hl
- ld bc, wPartyMon1PP - wPartyMon1Moves
- add hl, bc
- call .swapBytes ; swap move PP
- xor a
- ld [wMenuItemToSwap], a ; deselect the item
- jp MoveSelectionMenu
-.swapBytes
- push hl
- ld a, [wMenuItemToSwap]
- dec a
- ld c, a
- ld b, 0
- add hl, bc
- ld d, h
- ld e, l
- pop hl
- ld a, [wCurrentMenuItem]
- dec a
- ld c, a
- ld b, 0
- add hl, bc
- ld a, [de]
- ld b, [hl]
- ld [hl], a
- ld a, b
- ld [de], a
- ret
-.noMenuItemSelected
- ld a, [wCurrentMenuItem]
- ld [wMenuItemToSwap], a ; select the current menu item for swapping
- jp MoveSelectionMenu
-
-PrintMenuItem: ; 3d629 (f:5629)
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- coord hl, 0, 8
- lb bc, 3, 9
- call TextBoxBorder
- ld a, [wPlayerDisabledMove]
- and a
- jr z, .notDisabled
- swap a
- and $f
- ld b, a
- ld a, [wCurrentMenuItem]
- cp b
- jr nz, .notDisabled
- coord hl, 1, 10
- ld de, DisabledText
- call PlaceString
- jr .moveDisabled
-.notDisabled
- ld hl, wCurrentMenuItem
- dec [hl]
- xor a
- ld [H_WHOSETURN], a
- ld hl, wBattleMonMoves
- ld a, [wCurrentMenuItem]
- ld c, a
- ld b, $0 ; which item in the menu is the cursor pointing to? (0-3)
- add hl, bc ; point to the item (move) in memory
- ld a, [hl]
- ld [wPlayerSelectedMove], a ; update wPlayerSelectedMove even if the move
- ; isn't actually selected (just pointed to by the cursor)
- ld a, [wPlayerMonNumber]
- ld [wWhichPokemon], a
- ld a, BATTLE_MON_DATA
- ld [wMonDataLocation], a
- callab GetMaxPP
- ld hl, wCurrentMenuItem
- ld c, [hl]
- inc [hl]
- ld b, $0
- ld hl, wBattleMonPP
- add hl, bc
- ld a, [hl]
- and $3f
- ld [wcd6d], a
-; print TYPE/<type> and <curPP>/<maxPP>
- coord hl, 1, 9
- ld de, TypeText
- call PlaceString
- coord hl, 7, 11
- ld [hl], "/"
- coord hl, 5, 9
- ld [hl], "/"
- coord hl, 5, 11
- ld de, wcd6d
- lb bc, 1, 2
- call PrintNumber
- coord hl, 8, 11
- ld de, wMaxPP
- lb bc, 1, 2
- call PrintNumber
- call GetCurrentMove
- coord hl, 2, 10
- predef PrintMoveType
-.moveDisabled
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- jp Delay3
-
-DisabledText: ; 3d6c7 (f:56c7)
- db "Disabled!@"
-
-TypeText: ; 3d6d1 (f:56d1)
- db "TYPE@"
-
-SelectEnemyMove: ; 3d6d6 (f:56d6)
- ld a, [wLinkState]
- sub LINK_STATE_BATTLING
- jr nz, .noLinkBattle
-; link battle
- call SaveScreenTilesToBuffer1
- call LinkBattleExchangeData
- call LoadScreenTilesFromBuffer1
- ld a, [wSerialExchangeNybbleReceiveData]
- cp $e
- jp z, .linkedOpponentUsedStruggle
- cp $d
- jr z, .unableToSelectMove
- cp $4
- ret nc
- ld [wEnemyMoveListIndex], a
- ld c, a
- ld hl, wEnemyMonMoves
- ld b, $0
- add hl, bc
- ld a, [hl]
- jr .done
-.noLinkBattle
- ld a, [wEnemyBattleStatus2]
- and (1 << NeedsToRecharge) | (1 << UsingRage) ; need to recharge or using rage
- ret nz
- ld hl, wEnemyBattleStatus1
- ld a, [hl]
- and (1 << ChargingUp) | (1 << ThrashingAbout) ; using a charging move or thrash/petal dance
- ret nz
- ld a, [wEnemyMonStatus]
- and SLP | 1 << FRZ ; sleeping or frozen
- ret nz
- ld a, [wEnemyBattleStatus1]
- and (1 << UsingTrappingMove) | (1 << StoringEnergy) ; using a trapping move like wrap or bide
- ret nz
- ld a, [wPlayerBattleStatus1]
- bit UsingTrappingMove, a ; caught in player's trapping move (e.g. wrap)
- jr z, .canSelectMove
-.unableToSelectMove
- ld a, $ff
- jr .done
-.canSelectMove
- ld hl, wEnemyMonMoves+1 ; 2nd enemy move
- ld a, [hld]
- and a
- jr nz, .atLeastTwoMovesAvailable
- ld a, [wEnemyDisabledMove]
- and a
- ld a, STRUGGLE ; struggle if the only move is disabled
- jr nz, .done
-.atLeastTwoMovesAvailable
- ld a, [wIsInBattle]
- dec a
- jr z, .chooseRandomMove ; wild encounter
- callab AIEnemyTrainerChooseMoves
-.chooseRandomMove
- push hl
- call BattleRandom
- ld b, $1
- cp $3f ; select move 1, [0,3e] (63/256 chance)
- jr c, .moveChosen
- inc hl
- inc b
- cp $7f ; select move 2, [3f,7e] (64/256 chance)
- jr c, .moveChosen
- inc hl
- inc b
- cp $be ; select move 3, [7f,bd] (63/256 chance)
- jr c, .moveChosen
- inc hl
- inc b ; select move 4, [be,ff] (66/256 chance)
-.moveChosen
- ld a, b
- dec a
- ld [wEnemyMoveListIndex], a
- ld a, [wEnemyDisabledMove]
- swap a
- and $f
- cp b
- ld a, [hl]
- pop hl
- jr z, .chooseRandomMove ; move disabled, try again
- and a
- jr z, .chooseRandomMove ; move non-existant, try again
-.done
- ld [wEnemySelectedMove], a
- ret
-.linkedOpponentUsedStruggle
- ld a, STRUGGLE
- jr .done
-
-; this appears to exchange data with the other gameboy during link battles
-LinkBattleExchangeData: ; 3d777 (f:5777)
- ld a, $ff
- ld [wSerialExchangeNybbleReceiveData], a
- ld a, [wPlayerMoveListIndex]
- cp $f ; is the player running from battle?
- jr z, .doExchange
- ld a, [wActionResultOrTookBattleTurn]
- and a ; is the player switching in another mon?
- jr nz, .switching
-; the player used a move
- ld a, [wPlayerSelectedMove]
- cp STRUGGLE
- ld b, $e
- jr z, .next
- dec b
- inc a
- jr z, .next
- ld a, [wPlayerMoveListIndex]
- jr .doExchange
-.switching
- ld a, [wWhichPokemon]
- add 4
- ld b, a
-.next
- ld a, b
-.doExchange
- ld [wSerialExchangeNybbleSendData], a
- callab PrintWaitingText
-.syncLoop1
- call Serial_ExchangeNybble
- call DelayFrame
- ld a, [wSerialExchangeNybbleReceiveData]
- inc a
- jr z, .syncLoop1
- ld b, 10
-.syncLoop2
- call DelayFrame
- call Serial_ExchangeNybble
- dec b
- jr nz, .syncLoop2
- ld b, 10
-.syncLoop3
- call DelayFrame
- call Serial_SendZeroByte
- dec b
- jr nz, .syncLoop3
- ret
-
-ExecutePlayerMove: ; 3d7d0 (f:57d0)
- xor a
- ld [H_WHOSETURN], a ; set player's turn
- ld a, [wPlayerSelectedMove]
- inc a
- jp z, ExecutePlayerMoveDone ; for selected move = FF, skip most of player's turn
- xor a
- ld [wMoveMissed], a
- ld [wMonIsDisobedient], a
- ld [wMoveDidntMiss], a
- ld a, $a
- ld [wDamageMultipliers], a
- ld a, [wActionResultOrTookBattleTurn]
- and a ; has the player already used the turn (e.g. by using an item, trying to run or switching pokemon)
- jp nz, ExecutePlayerMoveDone
- call PrintGhostText
- jp z, ExecutePlayerMoveDone
- call CheckPlayerStatusConditions
- jr nz, .playerHasNoSpecialCondition
- jp [hl]
-.playerHasNoSpecialCondition
- call GetCurrentMove
- ld hl, wPlayerBattleStatus1
- bit ChargingUp, [hl] ; charging up for attack
- jr nz, PlayerCanExecuteChargingMove
- call CheckForDisobedience
- jp z, ExecutePlayerMoveDone
-
-CheckIfPlayerNeedsToChargeUp: ; 3d80c (f:580c)
- ld a, [wPlayerMoveEffect]
- cp CHARGE_EFFECT
- jp z, JumpMoveEffect
- cp FLY_EFFECT
- jp z, JumpMoveEffect
- jr PlayerCanExecuteMove
-
-; in-battle stuff
-PlayerCanExecuteChargingMove: ; 3d81b (f:581b)
- ld hl,wPlayerBattleStatus1
- res ChargingUp,[hl] ; reset charging up and invulnerability statuses if mon was charging up for an attack
- ; being fully paralyzed or hurting oneself in confusion removes charging up status
- ; resulting in the Pokemon being invulnerable for the whole battle
- res Invulnerable,[hl]
-PlayerCanExecuteMove: ; 3d822 (f:5822)
- call PrintMonName1Text
- ld hl,DecrementPP
- ld de,wPlayerSelectedMove ; pointer to the move just used
- ld b,BANK(DecrementPP)
- call Bankswitch
- ld a,[wPlayerMoveEffect] ; effect of the move just used
- ld hl,ResidualEffects1
- ld de,1
- call IsInArray
- jp c,JumpMoveEffect ; ResidualEffects1 moves skip damage calculation and accuracy tests
- ; unless executed as part of their exclusive effect functions
- ld a,[wPlayerMoveEffect]
- ld hl,SpecialEffectsCont
- ld de,1
- call IsInArray
- call c,JumpMoveEffect ; execute the effects of SpecialEffectsCont moves (e.g. Wrap, Thrash) but don't skip anything
-PlayerCalcMoveDamage: ; 3d84e (f:584e)
- ld a,[wPlayerMoveEffect]
- ld hl,SetDamageEffects
- ld de,1
- call IsInArray
- jp c,.moveHitTest ; SetDamageEffects moves (e.g. Seismic Toss and Super Fang) skip damage calculation
- call CriticalHitTest
- call HandleCounterMove
- jr z,handleIfPlayerMoveMissed
- call GetDamageVarsForPlayerAttack
- call CalculateDamage
- jp z,playerCheckIfFlyOrChargeEffect ; for moves with 0 BP, skip any further damage calculation and, for now, skip MoveHitTest
- ; for these moves, accuracy tests will only occur if they are called as part of the effect itself
- call AdjustDamageForMoveType
- call RandomizeDamage
-.moveHitTest
- call MoveHitTest
-handleIfPlayerMoveMissed: ; 3d877 (f:5877)
- ld a,[wMoveMissed]
- and a
- jr z,getPlayerAnimationType
- ld a,[wPlayerMoveEffect]
- sub a,EXPLODE_EFFECT
- jr z,playPlayerMoveAnimation ; don't play any animation if the move missed, unless it was EXPLODE_EFFECT
- jr playerCheckIfFlyOrChargeEffect
-getPlayerAnimationType: ; 3d87b (f:587b)
- ld a,[wPlayerMoveEffect]
- and a
- ld a,4 ; move has no effect other than dealing damage
- jr z,playPlayerMoveAnimation
- ld a,5 ; move has effect
-playPlayerMoveAnimation ; 3d890 (f:5890)
- push af
- ld a,[wPlayerBattleStatus2]
- bit HasSubstituteUp,a
- ld hl,HideSubstituteShowMonAnim
- ld b,BANK(HideSubstituteShowMonAnim)
- call nz,Bankswitch
- pop af
- ld [wAnimationType],a
- ld a,[wPlayerMoveNum]
- call PlayMoveAnimation
- call HandleExplodingAnimation
- call DrawPlayerHUDAndHPBar
- ld a,[wPlayerBattleStatus2]
- bit HasSubstituteUp,a
- ld hl,ReshowSubstituteAnim
- ld b,BANK(ReshowSubstituteAnim)
- call nz,Bankswitch
- jr MirrorMoveCheck
-playerCheckIfFlyOrChargeEffect ; 3d8bd (f:58bd)
- ld c,30
- call DelayFrames
- ld a,[wPlayerMoveEffect]
- cp a,FLY_EFFECT
- jr z,.playAnim
- cp a,CHARGE_EFFECT
- jr z,.playAnim
- jr MirrorMoveCheck
-.playAnim
- xor a
- ld [wAnimationType],a
- ld a,STATUS_AFFECTED_ANIM
- call PlayMoveAnimation
-MirrorMoveCheck: ; 3d8d8 (f:58d8)
- ld a,[wPlayerMoveEffect]
- cp a,MIRROR_MOVE_EFFECT
- jr nz,.metronomeCheck
- call MirrorMoveCopyMove
- jp z,ExecutePlayerMoveDone
- xor a
- ld [wMonIsDisobedient],a
- jp CheckIfPlayerNeedsToChargeUp ; if Mirror Move was successful go back to damage calculation for copied move
-.metronomeCheck
- cp a,METRONOME_EFFECT
- jr nz,.next
- call MetronomePickMove
- jp CheckIfPlayerNeedsToChargeUp ; Go back to damage calculation for the move picked by Metronome
-.next
- ld a,[wPlayerMoveEffect]
- ld hl,ResidualEffects2
- ld de,1
- call IsInArray
- jp c,JumpMoveEffect ; done here after executing effects of ResidualEffects2
- ld a,[wMoveMissed]
- and a
- jr z,.moveDidNotMiss
- call PrintMoveFailureText
- ld a,[wPlayerMoveEffect]
- cp a,EXPLODE_EFFECT ; even if Explosion or Selfdestruct missed, its effect still needs to be activated
- jr z,.notDone
- jp ExecutePlayerMoveDone ; otherwise, we're done if the move missed
-.moveDidNotMiss
- call ApplyAttackToEnemyPokemon
- call PrintCriticalOHKOText
- callab DisplayEffectiveness
- ld a,1
- ld [wMoveDidntMiss],a
-.notDone
- ld a,[wPlayerMoveEffect]
- ld hl,AlwaysHappenSideEffects
- ld de,1
- call IsInArray
- call c,JumpMoveEffect ; not done after executing effects of AlwaysHappenSideEffects
- ld hl,wEnemyMonHP
- ld a,[hli]
- ld b,[hl]
- or b
- ret z ; don't do anything else if the enemy fainted
- call HandleBuildingRage
-
- ld hl,wPlayerBattleStatus1
- bit AttackingMultipleTimes,[hl]
- jr z,.executeOtherEffects
- ld a,[wPlayerNumAttacksLeft]
- dec a
- ld [wPlayerNumAttacksLeft],a
- jp nz,getPlayerAnimationType ; for multi-hit moves, apply attack until PlayerNumAttacksLeft hits 0 or the enemy faints.
- ; damage calculation and accuracy tests only happen for the first hit
- res AttackingMultipleTimes,[hl] ; clear attacking multiple times status when all attacks are over
- ld hl,MultiHitText
- call PrintText
- xor a
- ld [wPlayerNumHits],a
-.executeOtherEffects
- ld a,[wPlayerMoveEffect]
- and a
- jp z,ExecutePlayerMoveDone
- ld hl,SpecialEffects
- ld de,1
- call IsInArray
- call nc,JumpMoveEffect ; move effects not included in SpecialEffects or in either of the ResidualEffect arrays,
- ; which are the effects not covered yet. Rage effect will be executed for a second time (though it's irrelevant).
- ; Includes side effects that only need to be called if the target didn't faint.
- ; Responsible for executing Twineedle's second side effect (poison).
- jp ExecutePlayerMoveDone
-
-MultiHitText: ; 3d977 (f:5977)
- TX_FAR _MultiHitText
- db "@"
-
-ExecutePlayerMoveDone: ; 3d97c (f:597c)
- xor a
- ld [wActionResultOrTookBattleTurn],a
- ld b,1
- ret
-
-PrintGhostText: ; 3d983 (f:5983)
-; print the ghost battle messages
- call IsGhostBattle
- ret nz
- ld a,[H_WHOSETURN]
- and a
- jr nz,.Ghost
- ld a,[wBattleMonStatus] ; player’s turn
- and a,SLP | (1 << FRZ)
- ret nz
- ld hl,ScaredText
- call PrintText
- xor a
- ret
-.Ghost ; ghost’s turn
- ld hl,GetOutText
- call PrintText
- xor a
- ret
-
-ScaredText: ; 3d9a2 (f:59a2)
- TX_FAR _ScaredText
- db "@"
-
-GetOutText: ; 3d9a7 (f:59a7)
- TX_FAR _GetOutText
- db "@"
-
-IsGhostBattle: ; 3d9ac (f:59ac)
- ld a,[wIsInBattle]
- dec a
- ret nz
- ld a,[wCurMap]
- cp a,POKEMONTOWER_1
- jr c,.next
- cp a,LAVENDER_HOUSE_1
- jr nc,.next
- ld b,SILPH_SCOPE
- call IsItemInBag
- ret z
-.next
- ld a,1
- and a
- ret
-
-; checks for various status conditions affecting the player mon
-; stores whether the mon cannot use a move this turn in Z flag
-CheckPlayerStatusConditions: ; 3d9c6 (f:59c6)
- ld hl,wBattleMonStatus
- ld a,[hl]
- and a,SLP ; sleep mask
- jr z,.FrozenCheck
-; sleeping
- dec a
- ld [wBattleMonStatus],a ; decrement number of turns left
- and a
- jr z,.WakeUp ; if the number of turns hit 0, wake up
-; fast asleep
- xor a
- ld [wAnimationType],a
- ld a,SLP_ANIM - 1
- call PlayMoveAnimation
- ld hl,FastAsleepText
- call PrintText
- jr .sleepDone
-.WakeUp
- ld hl,WokeUpText
- call PrintText
-.sleepDone
- xor a
- ld [wPlayerUsedMove],a
- ld hl,ExecutePlayerMoveDone ; player can't move this turn
- jp .returnToHL
-
-.FrozenCheck
- bit FRZ,[hl] ; frozen?
- jr z,.HeldInPlaceCheck
- ld hl,IsFrozenText
- call PrintText
- xor a
- ld [wPlayerUsedMove],a
- ld hl,ExecutePlayerMoveDone ; player can't move this turn
- jp .returnToHL
-
-.HeldInPlaceCheck
- ld a,[wEnemyBattleStatus1]
- bit UsingTrappingMove,a ; is enemy using a mult-turn move like wrap?
- jp z,.FlinchedCheck
- ld hl,CantMoveText
- call PrintText
- ld hl,ExecutePlayerMoveDone ; player can't move this turn
- jp .returnToHL
-
-.FlinchedCheck
- ld hl,wPlayerBattleStatus1
- bit Flinched,[hl]
- jp z,.HyperBeamCheck
- res Flinched,[hl] ; reset player's flinch status
- ld hl,FlinchedText
- call PrintText
- ld hl,ExecutePlayerMoveDone ; player can't move this turn
- jp .returnToHL
-
-.HyperBeamCheck
- ld hl,wPlayerBattleStatus2
- bit NeedsToRecharge,[hl]
- jr z,.AnyMoveDisabledCheck
- res NeedsToRecharge,[hl] ; reset player's recharge status
- ld hl,MustRechargeText
- call PrintText
- ld hl,ExecutePlayerMoveDone ; player can't move this turn
- jp .returnToHL
-
-.AnyMoveDisabledCheck
- ld hl,wPlayerDisabledMove
- ld a,[hl]
- and a
- jr z,.ConfusedCheck
- dec a
- ld [hl],a
- and $f ; did Disable counter hit 0?
- jr nz,.ConfusedCheck
- ld [hl],a
- ld [wPlayerDisabledMoveNumber],a
- ld hl,DisabledNoMoreText
- call PrintText
-
-.ConfusedCheck
- ld a,[wPlayerBattleStatus1]
- add a ; is player confused?
- jr nc,.TriedToUseDisabledMoveCheck
- ld hl,W_PLAYERCONFUSEDCOUNTER
- dec [hl]
- jr nz,.IsConfused
- ld hl,wPlayerBattleStatus1
- res Confused,[hl] ; if confused counter hit 0, reset confusion status
- ld hl,ConfusedNoMoreText
- call PrintText
- jr .TriedToUseDisabledMoveCheck
-.IsConfused
- ld hl,IsConfusedText
- call PrintText
- xor a
- ld [wAnimationType],a
- ld a,CONF_ANIM - 1
- call PlayMoveAnimation
- call BattleRandom
- cp a,$80 ; 50% chance to hurt itself
- jr c,.TriedToUseDisabledMoveCheck
- ld hl,wPlayerBattleStatus1
- ld a,[hl]
- and a, 1 << Confused ; if mon hurts itself, clear every other status from wPlayerBattleStatus1
- ld [hl],a
- call HandleSelfConfusionDamage
- jr .MonHurtItselfOrFullyParalysed
-
-.TriedToUseDisabledMoveCheck
-; prevents a disabled move that was selected before being disabled from being used
- ld a,[wPlayerDisabledMoveNumber]
- and a
- jr z,.ParalysisCheck
- ld hl,wPlayerSelectedMove
- cp [hl]
- jr nz,.ParalysisCheck
- call PrintMoveIsDisabledText
- ld hl,ExecutePlayerMoveDone ; if a disabled move was somehow selected, player can't move this turn
- jp .returnToHL
-
-.ParalysisCheck
- ld hl,wBattleMonStatus
- bit PAR,[hl]
- jr z,.BideCheck
- call BattleRandom
- cp a,$3F ; 25% to be fully paralyzed
- jr nc,.BideCheck
- ld hl,FullyParalyzedText
- call PrintText
-
-.MonHurtItselfOrFullyParalysed
- ld hl,wPlayerBattleStatus1
- ld a,[hl]
- ; clear bide, thrashing, charging up, and trapping moves such as warp (already cleared for confusion damage)
- and $ff ^ ((1 << StoringEnergy) | (1 << ThrashingAbout) | (1 << ChargingUp) | (1 << UsingTrappingMove))
- ld [hl],a
- ld a,[wPlayerMoveEffect]
- cp a,FLY_EFFECT
- jr z,.FlyOrChargeEffect
- cp a,CHARGE_EFFECT
- jr z,.FlyOrChargeEffect
- jr .NotFlyOrChargeEffect
-
-.FlyOrChargeEffect
- xor a
- ld [wAnimationType],a
- ld a,STATUS_AFFECTED_ANIM
- call PlayMoveAnimation
-.NotFlyOrChargeEffect
- ld hl,ExecutePlayerMoveDone
- jp .returnToHL ; if using a two-turn move, we need to recharge the first turn
-
-.BideCheck
- ld hl,wPlayerBattleStatus1
- bit StoringEnergy,[hl] ; is mon using bide?
- jr z,.ThrashingAboutCheck
- xor a
- ld [wPlayerMoveNum],a
- ld hl,wDamage
- ld a,[hli]
- ld b,a
- ld c,[hl]
- ld hl,wPlayerBideAccumulatedDamage + 1
- ld a,[hl]
- add c ; acumulate damage taken
- ld [hld],a
- ld a,[hl]
- adc b
- ld [hl],a
- ld hl,wPlayerNumAttacksLeft
- dec [hl] ; did Bide counter hit 0?
- jr z,.UnleashEnergy
- ld hl,ExecutePlayerMoveDone
- jp .returnToHL ; unless mon unleashes energy, can't move this turn
-.UnleashEnergy
- ld hl,wPlayerBattleStatus1
- res StoringEnergy,[hl] ; not using bide any more
- ld hl,UnleashedEnergyText
- call PrintText
- ld a,1
- ld [wPlayerMovePower],a
- ld hl,wPlayerBideAccumulatedDamage + 1
- ld a,[hld]
- add a
- ld b,a
- ld [wDamage + 1],a
- ld a,[hl]
- rl a ; double the damage
- ld [wDamage],a
- or b
- jr nz,.next
- ld a,1
- ld [wMoveMissed],a
-.next
- xor a
- ld [hli],a
- ld [hl],a
- ld a,BIDE
- ld [wPlayerMoveNum],a
- ld hl,handleIfPlayerMoveMissed ; skip damage calculation, DecrementPP and MoveHitTest
- jp .returnToHL
-
-.ThrashingAboutCheck
- bit ThrashingAbout,[hl] ; is mon using thrash or petal dance?
- jr z,.MultiturnMoveCheck
- ld a,THRASH
- ld [wPlayerMoveNum],a
- ld hl,ThrashingAboutText
- call PrintText
- ld hl,wPlayerNumAttacksLeft
- dec [hl] ; did Thrashing About counter hit 0?
- ld hl,PlayerCalcMoveDamage ; skip DecrementPP
- jp nz,.returnToHL
- push hl
- ld hl,wPlayerBattleStatus1
- res ThrashingAbout,[hl] ; no longer thrashing about
- set Confused,[hl] ; confused
- call BattleRandom
- and a,3
- inc a
- inc a ; confused for 2-5 turns
- ld [W_PLAYERCONFUSEDCOUNTER],a
- pop hl ; skip DecrementPP
- jp .returnToHL
-
-.MultiturnMoveCheck
- bit UsingTrappingMove,[hl] ; is mon using multi-turn move?
- jp z,.RageCheck
- ld hl,AttackContinuesText
- call PrintText
- ld a,[wPlayerNumAttacksLeft]
- dec a ; did multi-turn move end?
- ld [wPlayerNumAttacksLeft],a
- ld hl,getPlayerAnimationType ; if it didn't, skip damage calculation (deal damage equal to last hit),
- ; DecrementPP and MoveHitTest
- jp nz,.returnToHL
- jp .returnToHL
-
-.RageCheck
- ld a, [wPlayerBattleStatus2]
- bit UsingRage, a ; is mon using rage?
- jp z, .checkPlayerStatusConditionsDone ; if we made it this far, mon can move normally this turn
- ld a, RAGE
- ld [wd11e], a
- call GetMoveName
- call CopyStringToCF4B
- xor a
- ld [wPlayerMoveEffect], a
- ld hl, PlayerCanExecuteMove
- jp .returnToHL
-
-.returnToHL
- xor a
- ret
-
-.checkPlayerStatusConditionsDone
- ld a, $1
- and a
- ret
-
-FastAsleepText: ; 3dbaf (f:5baf)
- TX_FAR _FastAsleepText
- db "@"
-
-WokeUpText: ; 3dbb4 (f:5bb4)
- TX_FAR _WokeUpText
- db "@"
-
-IsFrozenText: ; 3dbb9 (f:5bb9)
- TX_FAR _IsFrozenText
- db "@"
-
-FullyParalyzedText: ; 3dbbe (f:5bbe)
- TX_FAR _FullyParalyzedText
- db "@"
-
-FlinchedText: ; 3dbc3 (f:5bc3)
- TX_FAR _FlinchedText
- db "@"
-
-MustRechargeText: ; 3dbc8 (f:5bc8)
- TX_FAR _MustRechargeText
- db "@"
-
-DisabledNoMoreText: ; 3dbcd (f:5bcd)
- TX_FAR _DisabledNoMoreText
- db "@"
-
-IsConfusedText: ; 3dbd2 (f:5bd2)
- TX_FAR _IsConfusedText
- db "@"
-
-HurtItselfText: ; 3dbd7 (f:5bd7)
- TX_FAR _HurtItselfText
- db "@"
-
-ConfusedNoMoreText: ; 3dbdc (f:5bdc)
- TX_FAR _ConfusedNoMoreText
- db "@"
-
-SavingEnergyText: ; 3dbe1 (f:5be1)
- TX_FAR _SavingEnergyText
- db "@"
-
-UnleashedEnergyText: ; 3dbe6 (f:5be6)
- TX_FAR _UnleashedEnergyText
- db "@"
-
-ThrashingAboutText: ; 3dbeb (f:5beb)
- TX_FAR _ThrashingAboutText
- db "@"
-
-AttackContinuesText: ; 3dbf0 (f:5bf0)
- TX_FAR _AttackContinuesText
- db "@"
-
-CantMoveText: ; 3dbf5 (f:5bf5)
- TX_FAR _CantMoveText
- db "@"
-
-PrintMoveIsDisabledText: ; 3dbfa (f:5bfa)
- ld hl, wPlayerSelectedMove
- ld de, wPlayerBattleStatus1
- ld a, [H_WHOSETURN]
- and a
- jr z, .removeChargingUp
- inc hl
- ld de, wEnemyBattleStatus1
-.removeChargingUp
- ld a, [de]
- res ChargingUp, a ; end the pokemon's
- ld [de], a
- ld a, [hl]
- ld [wd11e], a
- call GetMoveName
- ld hl, MoveIsDisabledText
- jp PrintText
-
-MoveIsDisabledText: ; 3dc1a (f:5c1a)
- TX_FAR _MoveIsDisabledText
- db "@"
-
-HandleSelfConfusionDamage: ; 3dc1f (f:5c1f)
- ld hl, HurtItselfText
- call PrintText
- ld hl, wEnemyMonDefense
- ld a, [hli]
- push af
- ld a, [hld]
- push af
- ld a, [wBattleMonDefense]
- ld [hli], a
- ld a, [wBattleMonDefense + 1]
- ld [hl], a
- ld hl, wPlayerMoveEffect
- push hl
- ld a, [hl]
- push af
- xor a
- ld [hli], a
- ld [wCriticalHitOrOHKO], a ; self-inflicted confusion damage can't be a Critical Hit
- ld a, 40 ; 40 base power
- ld [hli], a
- xor a
- ld [hl], a
- call GetDamageVarsForPlayerAttack
- call CalculateDamage ; ignores AdjustDamageForMoveType (type-less damage), RandomizeDamage,
- ; and MoveHitTest (always hits)
- pop af
- pop hl
- ld [hl], a
- ld hl, wEnemyMonDefense + 1
- pop af
- ld [hld], a
- pop af
- ld [hl], a
- xor a
- ld [wAnimationType], a
- inc a
- ld [H_WHOSETURN], a
- call PlayMoveAnimation
- call DrawPlayerHUDAndHPBar
- xor a
- ld [H_WHOSETURN], a
- jp ApplyDamageToPlayerPokemon
-
-PrintMonName1Text: ; 3dc67 (f:5c67)
- ld hl, MonName1Text
- jp PrintText
-
-; this function wastes time calling DetermineExclamationPointTextNum
-; and choosing between Used1Text and Used2Text, even though
-; those text strings are identical and both continue at PrintInsteadText
-; this likely had to do with Japanese grammar that got translated,
-; but the functionality didn't get removed
-MonName1Text: ; 3dc6d (f:5c6d)
- TX_FAR _MonName1Text
- TX_ASM
- ld a, [H_WHOSETURN]
- and a
- ld a, [wPlayerMoveNum]
- ld hl, wPlayerUsedMove
- jr z, .playerTurn
- ld a, [wEnemyMoveNum]
- ld hl, wEnemyUsedMove
-.playerTurn
- ld [hl], a
- ld [wd11e], a
- call DetermineExclamationPointTextNum
- ld a, [wMonIsDisobedient]
- and a
- ld hl, Used2Text
- ret nz
- ld a, [wd11e]
- cp 3
- ld hl, Used2Text
- ret c
- ld hl, Used1Text
- ret
-
-Used1Text: ; 3dc9f (f:5c9f)
- TX_FAR _Used1Text
- TX_ASM
- jr PrintInsteadText
-
-Used2Text: ; 3dca6 (f:5ca6)
- TX_FAR _Used2Text
- TX_ASM
- ; fall through
-
-PrintInsteadText: ; 3dcab (f:5cab)
- ld a, [wMonIsDisobedient]
- and a
- jr z, PrintMoveName
- ld hl, InsteadText
- ret
-
-InsteadText: ; 3dcb5 (f:5cb5)
- TX_FAR _InsteadText
- TX_ASM
- ; fall through
-
-PrintMoveName: ; 3dcba (f:5cba)
- ld hl, _PrintMoveName
- ret
-
-_PrintMoveName: ; 3dcbe (f:5cbe)
- TX_FAR _CF4BText
- TX_ASM
- ld hl, ExclamationPointPointerTable
- ld a, [wd11e] ; exclamation point num
- add a
- push bc
- ld b, $0
- ld c, a
- add hl, bc
- pop bc
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ret
-
-ExclamationPointPointerTable: ; 3dcd4 (f:5cd4)
- dw ExclamationPoint1Text
- dw ExclamationPoint2Text
- dw ExclamationPoint3Text
- dw ExclamationPoint4Text
- dw ExclamationPoint5Text
-
-ExclamationPoint1Text: ; 3dcde (f:5cde)
- TX_FAR _ExclamationPoint1Text
- db "@"
-
-ExclamationPoint2Text: ; 3dce3 (f:5ce3)
- TX_FAR _ExclamationPoint2Text
- db "@"
-
-ExclamationPoint3Text: ; 3dce8 (f:5ce8)
- TX_FAR _ExclamationPoint3Text
- db "@"
-
-ExclamationPoint4Text: ; 3dced (f:5ced)
- TX_FAR _ExclamationPoint4Text
- db "@"
-
-ExclamationPoint5Text: ; 3dcf2 (f:5cf2)
- TX_FAR _ExclamationPoint5Text
- db "@"
-
-; this function does nothing useful
-; if the move being used is in set [1-4] from ExclamationPointMoveSets,
-; use ExclamationPoint[1-4]Text
-; otherwise, use ExclamationPoint5Text
-; but all five text strings are identical
-; this likely had to do with Japanese grammar that got translated,
-; but the functionality didn't get removed
-DetermineExclamationPointTextNum: ; 3dcf7 (f:5cf7)
- push bc
- ld a, [wd11e] ; move ID
- ld c, a
- ld b, $0
- ld hl, ExclamationPointMoveSets
-.loop
- ld a, [hli]
- cp $ff
- jr z, .done
- cp c
- jr z, .done
- and a
- jr nz, .loop
- inc b
- jr .loop
-.done
- ld a, b
- ld [wd11e], a ; exclamation point num
- pop bc
- ret
-
-ExclamationPointMoveSets: ; 3dd15 (f:5d15)
-; a grammar mistake was fixed (only concerning japanese)
-; BIDE is in category 3, moved from category 2
- db SWORDS_DANCE, GROWTH
- db $00
- db RECOVER, SELFDESTRUCT, AMNESIA
- db $00
- db MEDITATE, AGILITY, TELEPORT, MIMIC, DOUBLE_TEAM, BIDE, BARRAGE
- db $00
- db POUND, SCRATCH, VICEGRIP, WING_ATTACK, FLY, BIND, SLAM, HORN_ATTACK, BODY_SLAM
- db WRAP, THRASH, TAIL_WHIP, LEER, BITE, GROWL, ROAR, SING, PECK, COUNTER
- db STRENGTH, ABSORB, STRING_SHOT, EARTHQUAKE, FISSURE, DIG, TOXIC, SCREECH, HARDEN
- db MINIMIZE, WITHDRAW, DEFENSE_CURL, METRONOME, LICK, CLAMP, CONSTRICT, POISON_GAS
- db LEECH_LIFE, BUBBLE, FLASH, SPLASH, ACID_ARMOR, FURY_SWIPES, REST, SHARPEN, SLASH, SUBSTITUTE
- db $00
- db $FF ; terminator
-
-PrintMoveFailureText: ; 3dd54 (f:5d54)
- ld de, wPlayerMoveEffect
- ld a, [H_WHOSETURN]
- and a
- jr z, .playersTurn
- ld de, wEnemyMoveEffect
-.playersTurn
- ld hl, DoesntAffectMonText
- ld a, [wDamageMultipliers]
- and $7f
- jr z, .gotTextToPrint
- ld hl, AttackMissedText
- ld a, [wCriticalHitOrOHKO]
- cp $ff
- jr nz, .gotTextToPrint
- ld hl, UnaffectedText
-.gotTextToPrint
- push de
- call PrintText
- xor a
- ld [wCriticalHitOrOHKO], a
- pop de
- ld a, [de]
- cp JUMP_KICK_EFFECT
- ret nz
-
- ; if you get here, the mon used jump kick or hi jump kick and missed
- ld hl, wDamage ; since the move missed, W_DAMAGE will always contain 0 at this point.
- ; Thus, recoil damage will always be equal to 1
- ; even if it was intended to be potential damage/8.
- ld a, [hli]
- ld b, [hl]
- srl a
- rr b
- srl a
- rr b
- srl a
- rr b
- ld [hl], b
- dec hl
- ld [hli], a
- or b
- jr nz, .applyRecoil
- inc a
- ld [hl], a
-.applyRecoil
- ld hl, KeptGoingAndCrashedText
- call PrintText
- ld b, $4
- predef PredefShakeScreenHorizontally
- ld a, [H_WHOSETURN]
- and a
- jr nz, .enemyTurn
- jp ApplyDamageToPlayerPokemon
-.enemyTurn
- jp ApplyDamageToEnemyPokemon
-
-AttackMissedText: ; 3ddb4 (f:5db4)
- TX_FAR _AttackMissedText
- db "@"
-
-KeptGoingAndCrashedText: ; 3ddb9 (f:5db9)
- TX_FAR _KeptGoingAndCrashedText
- db "@"
-
-UnaffectedText: ; 3ddbe (f:5dbe)
- TX_FAR _UnaffectedText
- db "@"
-
-PrintDoesntAffectText: ; 3ddc3 (f:5dc3)
- ld hl, DoesntAffectMonText
- jp PrintText
-
-DoesntAffectMonText: ; 3ddc9 (f:5dc9)
- TX_FAR _DoesntAffectMonText
- db "@"
-
-; if there was a critical hit or an OHKO was successful, print the corresponding text
-PrintCriticalOHKOText: ; 3ddce (f:5dce)
- ld a, [wCriticalHitOrOHKO]
- and a
- jr z, .done ; do nothing if there was no critical hit or successful OHKO
- dec a
- add a
- ld hl, CriticalOHKOTextPointers
- ld b, $0
- ld c, a
- add hl, bc
- ld a, [hli]
- ld h, [hl]
- ld l, a
- call PrintText
- xor a
- ld [wCriticalHitOrOHKO], a
-.done
- ld c, 20
- jp DelayFrames
-
-CriticalOHKOTextPointers: ; 3ddec (f:5dec)
- dw CriticalHitText
- dw OHKOText
-
-CriticalHitText: ; 3ddf0 (f:5df0)
- TX_FAR _CriticalHitText
- db "@"
-
-OHKOText: ; 3ddf5 (f:5df5)
- TX_FAR _OHKOText
- db "@"
-
-; checks if a traded mon will disobey due to lack of badges
-; stores whether the mon will use a move in Z flag
-CheckForDisobedience: ; 3ddfa (f:5dfa)
- xor a
- ld [wMonIsDisobedient], a
- ld a, [wLinkState]
- cp LINK_STATE_BATTLING
- jr nz, .checkIfMonIsTraded
- ld a, $1
- and a
- ret
-; compare the mon's original trainer ID with the player's ID to see if it was traded
-.checkIfMonIsTraded
- ld hl, wPartyMon1OTID
- ld bc, wPartyMon2 - wPartyMon1
- ld a, [wPlayerMonNumber]
- call AddNTimes
- ld a, [wPlayerID]
- cp [hl]
- jr nz, .monIsTraded
- inc hl
- ld a, [wPlayerID + 1]
- cp [hl]
- jp z, .canUseMove
-; it was traded
-.monIsTraded
-; what level might disobey?
- ld hl, wObtainedBadges
- bit 7, [hl]
- ld a, 101
- jr nz, .next
- bit 5, [hl]
- ld a, 70
- jr nz, .next
- bit 3, [hl]
- ld a, 50
- jr nz, .next
- bit 1, [hl]
- ld a, 30
- jr nz, .next
- ld a, 10
-.next
- ld b, a
- ld c, a
- ld a, [wBattleMonLevel]
- ld d, a
- add b
- ld b, a
- jr nc, .noCarry
- ld b, $ff ; cap b at $ff
-.noCarry
- ld a, c
- cp d
- jp nc, .canUseMove
-.loop1
- call BattleRandom
- swap a
- cp b
- jr nc, .loop1
- cp c
- jp c, .canUseMove
-.loop2
- call BattleRandom
- cp b
- jr nc, .loop2
- cp c
- jr c, .useRandomMove
- ld a, d
- sub c
- ld b, a
- call BattleRandom
- swap a
- sub b
- jr c, .monNaps
- cp b
- jr nc, .monDoesNothing
- ld hl, WontObeyText
- call PrintText
- call HandleSelfConfusionDamage
- jp .cannotUseMove
-.monNaps
- call BattleRandom
- add a
- swap a
- and SLP ; sleep mask
- jr z, .monNaps ; keep trying until we get at least 1 turn of sleep
- ld [wBattleMonStatus], a
- ld hl, BeganToNapText
- jr .printText
-.monDoesNothing
- call BattleRandom
- and $3
- ld hl, LoafingAroundText
- and a
- jr z, .printText
- ld hl, WontObeyText
- dec a
- jr z, .printText
- ld hl, TurnedAwayText
- dec a
- jr z, .printText
- ld hl, IgnoredOrdersText
-.printText
- call PrintText
- jr .cannotUseMove
-.useRandomMove
- ld a, [wBattleMonMoves + 1]
- and a ; is the second move slot empty?
- jr z, .monDoesNothing ; mon will not use move if it only knows one move
- ld a, [wPlayerDisabledMoveNumber]
- and a
- jr nz, .monDoesNothing
- ld a, [wPlayerSelectedMove]
- cp STRUGGLE
- jr z, .monDoesNothing ; mon will not use move if struggling
-; check if only one move has remaining PP
- ld hl, wBattleMonPP
- push hl
- ld a, [hli]
- and $3f
- ld b, a
- ld a, [hli]
- and $3f
- add b
- ld b, a
- ld a, [hli]
- and $3f
- add b
- ld b, a
- ld a, [hl]
- and $3f
- add b
- pop hl
- push af
- ld a, [wCurrentMenuItem]
- ld c, a
- ld b, $0
- add hl, bc
- ld a, [hl]
- and $3f
- ld b, a
- pop af
- cp b
- jr z, .monDoesNothing ; mon will not use move if only one move has remaining PP
- ld a, $1
- ld [wMonIsDisobedient], a
- ld a, [wMaxMenuItem]
- ld b, a
- ld a, [wCurrentMenuItem]
- ld c, a
-.chooseMove
- call BattleRandom
- and $3
- cp b
- jr nc, .chooseMove ; if the random number is greater than the move count, choose another
- cp c
- jr z, .chooseMove ; if the random number matches the move the player selected, choose another
- ld [wCurrentMenuItem], a
- ld hl, wBattleMonPP
- ld e, a
- ld d, $0
- add hl, de
- ld a, [hl]
- and a ; does the move have any PP left?
- jr z, .chooseMove ; if the move has no PP left, choose another
- ld a, [wCurrentMenuItem]
- ld c, a
- ld b, $0
- ld hl, wBattleMonMoves
- add hl, bc
- ld a, [hl]
- ld [wPlayerSelectedMove], a
- call GetCurrentMove
-.canUseMove
- ld a, $1
- and a; clear Z flag
- ret
-.cannotUseMove
- xor a ; set Z flag
- ret
-
-LoafingAroundText: ; 3df28 (f:5f28)
- TX_FAR _LoafingAroundText
- db "@"
-
-BeganToNapText: ; 3df2d (f:5f2d)
- TX_FAR _BeganToNapText
- db "@"
-
-WontObeyText: ; 3df32 (f:5f32)
- TX_FAR _WontObeyText
- db "@"
-
-TurnedAwayText: ; 3df37 (f:5f37)
- TX_FAR _TurnedAwayText
- db "@"
-
-IgnoredOrdersText: ; 3df3c (f:5f3c)
- TX_FAR _IgnoredOrdersText
- db "@"
-
-; sets b, c, d, and e for the CalculateDamage routine in the case of an attack by the player mon
-GetDamageVarsForPlayerAttack: ; 3df41 (f:5f41)
- xor a
- ld hl, wDamage ; damage to eventually inflict, initialise to zero
- ldi [hl], a
- ld [hl], a
- ld hl, wPlayerMovePower
- ld a, [hli]
- and a
- ld d, a ; d = move power
- ret z ; return if move power is zero
- ld a, [hl] ; a = [wPlayerMoveType]
- cp FIRE ; types >= FIRE are all special
- jr nc, .specialAttack
-.physicalAttack
- ld hl, wEnemyMonDefense
- ld a, [hli]
- ld b, a
- ld c, [hl] ; bc = enemy defense
- ld a, [wEnemyBattleStatus3]
- bit HasReflectUp, a ; check for Reflect
- jr z, .physicalAttackCritCheck
-; if the enemy has used Reflect, double the enemy's defense
- sla c
- rl b
-.physicalAttackCritCheck
- ld hl, wBattleMonAttack
- ld a, [wCriticalHitOrOHKO]
- and a ; check for critical hit
- jr z, .scaleStats
-; in the case of a critical hit, reset the player's attack and the enemy's defense to their base values
- ld c, 3 ; defense stat
- call GetEnemyMonStat
- ld a, [H_PRODUCT + 2]
- ld b, a
- ld a, [H_PRODUCT + 3]
- ld c, a
- push bc
- ld hl, wPartyMon1Attack
- ld a, [wPlayerMonNumber]
- ld bc, wPartyMon2 - wPartyMon1
- call AddNTimes
- pop bc
- jr .scaleStats
-.specialAttack
- ld hl, wEnemyMonSpecial
- ld a, [hli]
- ld b, a
- ld c, [hl] ; bc = enemy special
- ld a, [wEnemyBattleStatus3]
- bit HasLightScreenUp, a ; check for Light Screen
- jr z, .specialAttackCritCheck
-; if the enemy has used Light Screen, double the enemy's special
- sla c
- rl b
-; reflect and light screen boosts do not cap the stat at 999, so weird things will happen during stats scaling if
-; a Pokemon with 512 or more Defense has ued Reflect, or if a Pokemon with 512 or more Special has used Light Screen
-.specialAttackCritCheck
- ld hl, wBattleMonSpecial
- ld a, [wCriticalHitOrOHKO]
- and a ; check for critical hit
- jr z, .scaleStats
-; in the case of a critical hit, reset the player's and enemy's specials to their base values
- ld c, 5 ; special stat
- call GetEnemyMonStat
- ld a, [H_PRODUCT + 2]
- ld b, a
- ld a, [H_PRODUCT + 3]
- ld c, a
- push bc
- ld hl, wPartyMon1Special
- ld a, [wPlayerMonNumber]
- ld bc, wPartyMon2 - wPartyMon1
- call AddNTimes
- pop bc
-; if either the offensive or defensive stat is too large to store in a byte, scale both stats by dividing them by 4
-; this allows values with up to 10 bits (values up to 1023) to be handled
-; anything larger will wrap around
-.scaleStats
- ld a, [hli]
- ld l, [hl]
- ld h, a ; hl = player's offensive stat
- or b ; is either high byte nonzero?
- jr z, .next ; if not, we don't need to scale
-; bc /= 4 (scale enemy's defensive stat)
- srl b
- rr c
- srl b
- rr c
-; defensive stat can actually end up as 0, leading to a division by 0 freeze during damage calculation
-; hl /= 4 (scale player's offensive stat)
- srl h
- rr l
- srl h
- rr l
- ld a, l
- or h ; is the player's offensive stat 0?
- jr nz, .next
- inc l ; if the player's offensive stat is 0, bump it up to 1
-.next
- ld b, l ; b = player's offensive stat (possibly scaled)
- ; (c already contains enemy's defensive stat (possibly scaled))
- ld a, [wBattleMonLevel]
- ld e, a ; e = level
- ld a, [wCriticalHitOrOHKO]
- and a ; check for critical hit
- jr z, .done
- sla e ; double level if it was a critical hit
-.done
- ld a, 1
- and a
- ret
-
-; sets b, c, d, and e for the CalculateDamage routine in the case of an attack by the enemy mon
-GetDamageVarsForEnemyAttack: ; 3dfe7 (f:5fe7)
- ld hl, wDamage ; damage to eventually inflict, initialise to zero
- xor a
- ld [hli], a
- ld [hl], a
- ld hl, wEnemyMovePower
- ld a, [hli]
- ld d, a ; d = move power
- and a
- ret z ; return if move power is zero
- ld a, [hl] ; a = [wEnemyMoveType]
- cp FIRE ; types >= FIRE are all special
- jr nc, .specialAttack
-.physicalAttack
- ld hl, wBattleMonDefense
- ld a, [hli]
- ld b, a
- ld c, [hl] ; bc = player defense
- ld a, [wPlayerBattleStatus3]
- bit HasReflectUp, a ; check for Reflect
- jr z, .physicalAttackCritCheck
-; if the player has used Reflect, double the player's defense
- sla c
- rl b
-.physicalAttackCritCheck
- ld hl, wEnemyMonAttack
- ld a, [wCriticalHitOrOHKO]
- and a ; check for critical hit
- jr z, .scaleStats
-; in the case of a critical hit, reset the player's defense and the enemy's attack to their base values
- ld hl, wPartyMon1Defense
- ld a, [wPlayerMonNumber]
- ld bc, wPartyMon2 - wPartyMon1
- call AddNTimes
- ld a, [hli]
- ld b, a
- ld c, [hl]
- push bc
- ld c, 2 ; attack stat
- call GetEnemyMonStat
- ld hl, H_PRODUCT + 2
- pop bc
- jr .scaleStats
-.specialAttack
- ld hl, wBattleMonSpecial
- ld a, [hli]
- ld b, a
- ld c, [hl]
- ld a, [wPlayerBattleStatus3]
- bit HasLightScreenUp, a ; check for Light Screen
- jr z, .specialAttackCritCheck
-; if the player has used Light Screen, double the player's special
- sla c
- rl b
-; reflect and light screen boosts do not cap the stat at 999, so weird things will happen during stats scaling if
-; a Pokemon with 512 or more Defense has ued Reflect, or if a Pokemon with 512 or more Special has used Light Screen
-.specialAttackCritCheck
- ld hl, wEnemyMonSpecial
- ld a, [wCriticalHitOrOHKO]
- and a ; check for critical hit
- jr z, .scaleStats
-; in the case of a critical hit, reset the player's and enemy's specials to their base values
- ld hl, wPartyMon1Special
- ld a, [wPlayerMonNumber]
- ld bc, wPartyMon2 - wPartyMon1
- call AddNTimes
- ld a, [hli]
- ld b, a
- ld c, [hl]
- push bc
- ld c, 5 ; special stat
- call GetEnemyMonStat
- ld hl, H_PRODUCT + 2
- pop bc
-; if either the offensive or defensive stat is too large to store in a byte, scale both stats by dividing them by 4
-; this allows values with up to 10 bits (values up to 1023) to be handled
-; anything larger will wrap around
-.scaleStats
- ld a, [hli]
- ld l, [hl]
- ld h, a ; hl = enemy's offensive stat
- or b ; is either high byte nonzero?
- jr z, .next ; if not, we don't need to scale
-; bc /= 4 (scale player's defensive stat)
- srl b
- rr c
- srl b
- rr c
-; defensive stat can actually end up as 0, leading to a division by 0 freeze during damage calculation
-; hl /= 4 (scale enemy's offensive stat)
- srl h
- rr l
- srl h
- rr l
- ld a, l
- or h ; is the enemy's offensive stat 0?
- jr nz, .next
- inc l ; if the enemy's offensive stat is 0, bump it up to 1
-.next
- ld b, l ; b = enemy's offensive stat (possibly scaled)
- ; (c already contains player's defensive stat (possibly scaled))
- ld a, [wEnemyMonLevel]
- ld e, a
- ld a, [wCriticalHitOrOHKO]
- and a ; check for critical hit
- jr z, .done
- sla e ; double level if it was a critical hit
-.done
- ld a, $1
- and a
- and a
- ret
-
-; get stat c of enemy mon
-; c: stat to get (HP=1,Attack=2,Defense=3,Speed=4,Special=5)
-GetEnemyMonStat: ; 3e08e (f:608e)
- push de
- push bc
- ld a, [wLinkState]
- cp LINK_STATE_BATTLING
- jr nz, .notLinkBattle
- ld hl, wEnemyMon1Stats
- dec c
- sla c
- ld b, $0
- add hl, bc
- ld a, [wEnemyMonPartyPos]
- ld bc, wEnemyMon2 - wEnemyMon1
- call AddNTimes
- ld a, [hli]
- ld [H_MULTIPLICAND + 1], a
- ld a, [hl]
- ld [H_MULTIPLICAND + 2], a
- pop bc
- pop de
- ret
-.notLinkBattle
- ld a, [wEnemyMonLevel]
- ld [wCurEnemyLVL], a
- ld a, [wEnemyMonSpecies]
- ld [wd0b5], a
- call GetMonHeader
- ld hl, wEnemyMonDVs
- ld de, wLoadedMonSpeedExp
- ld a, [hli]
- ld [de], a
- inc de
- ld a, [hl]
- ld [de], a
- pop bc
- ld b, $0
- ld hl, wLoadedMonSpeedExp - $b ; this base address makes CalcStat look in [wLoadedMonSpeedExp] for DVs
- call CalcStat
- pop de
- ret
-
-CalculateDamage: ; 3d0d7 (f:60d7)
-; input:
-; b: attack
-; c: opponent defense
-; d: base power
-; e: level
-
- ld a, [H_WHOSETURN] ; whose turn?
- and a
- ld a, [wPlayerMoveEffect]
- jr z, .effect
- ld a, [wEnemyMoveEffect]
-.effect
-
-; EXPLODE_EFFECT halves defense.
- cp a, EXPLODE_EFFECT
- jr nz, .ok
- srl c
- jr nz, .ok
- inc c ; ...with a minimum value of 1 (used as a divisor later on)
-.ok
-
-; Multi-hit attacks may or may not have 0 bp.
- cp a, TWO_TO_FIVE_ATTACKS_EFFECT
- jr z, .skipbp
- cp a, $1e
- jr z, .skipbp
-
-; Calculate OHKO damage based on remaining HP.
- cp a, OHKO_EFFECT
- jp z, JumpToOHKOMoveEffect
-
-; Don't calculate damage for moves that don't do any.
- ld a, d ; base power
- and a
- ret z
-.skipbp
-
- xor a
- ld hl, H_DIVIDEND
- ldi [hl], a
- ldi [hl], a
- ld [hl], a
-
-; Multiply level by 2
- ld a, e ; level
- add a
- jr nc, .nc
- push af
- ld a, 1
- ld [hl], a
- pop af
-.nc
- inc hl
- ldi [hl], a
-
-; Divide by 5
- ld a, 5
- ldd [hl], a
- push bc
- ld b, 4
- call Divide
- pop bc
-
-; Add 2
- inc [hl]
- inc [hl]
-
- inc hl ; multiplier
-
-; Multiply by attack base power
- ld [hl], d
- call Multiply
-
-; Multiply by attack stat
- ld [hl], b
- call Multiply
-
-; Divide by defender's defense stat
- ld [hl], c
- ld b, 4
- call Divide
-
-; Divide by 50
- ld [hl], 50
- ld b, 4
- call Divide
-
- ld hl, wDamage
- ld b, [hl]
- ld a, [H_QUOTIENT + 3]
- add b
- ld [H_QUOTIENT + 3], a
- jr nc, .asm_3e142
-
- ld a, [H_QUOTIENT + 2]
- inc a
- ld [H_QUOTIENT + 2], a
- and a
- jr z, .asm_3e176
-
-.asm_3e142
- ld a, [H_QUOTIENT]
- ld b, a
- ld a, [H_QUOTIENT + 1]
- or a
- jr nz, .asm_3e176
-
- ld a, [H_QUOTIENT + 2]
- cp 998 / $100
- jr c, .asm_3e15a
- cp 998 / $100 + 1
- jr nc, .asm_3e176
- ld a, [H_QUOTIENT + 3]
- cp 998 % $100
- jr nc, .asm_3e176
-
-.asm_3e15a
- inc hl
- ld a, [H_QUOTIENT + 3]
- ld b, [hl]
- add b
- ld [hld], a
-
- ld a, [H_QUOTIENT + 2]
- ld b, [hl]
- adc b
- ld [hl], a
- jr c, .asm_3e176
-
- ld a, [hl]
- cp 998 / $100
- jr c, .asm_3e17c
- cp 998 / $100 + 1
- jr nc, .asm_3e176
- inc hl
- ld a, [hld]
- cp 998 % $100
- jr c, .asm_3e17c
-
-.asm_3e176
-; cap at 997
- ld a, 997 / $100
- ld [hli], a
- ld a, 997 % $100
- ld [hld], a
-
-.asm_3e17c
-; add 2
- inc hl
- ld a, [hl]
- add 2
- ld [hld], a
- jr nc, .done
- inc [hl]
-
-.done
-; minimum damage is 1
- ld a, 1
- and a
- ret
-
-JumpToOHKOMoveEffect: ; 3e188 (f:6188)
- call JumpMoveEffect
- ld a, [wMoveMissed]
- dec a
- ret
-
-
-UnusedHighCriticalMoves: ; 3e190 (f:6190)
- db KARATE_CHOP
- db RAZOR_LEAF
- db CRABHAMMER
- db SLASH
- db $FF
-; 3e023
-
-; determines if attack is a critical hit
-; azure heights claims "the fastest pokémon (who are, not coincidentally,
-; among the most popular) tend to CH about 20 to 25% of the time."
-CriticalHitTest: ; 3e195 (f:6195)
- xor a
- ld [wCriticalHitOrOHKO], a
- ld a, [H_WHOSETURN]
- and a
- ld a, [wEnemyMonSpecies]
- jr nz, .handleEnemy
- ld a, [wBattleMonSpecies]
-.handleEnemy
- ld [wd0b5], a
- call GetMonHeader
- ld a, [wMonHBaseSpeed]
- ld b, a
- srl b ; (effective (base speed/2))
- ld a, [H_WHOSETURN]
- and a
- ld hl, wPlayerMovePower
- ld de, wPlayerBattleStatus2
- jr z, .calcCriticalHitProbability
- ld hl, wEnemyMovePower
- ld de, wEnemyBattleStatus2
-.calcCriticalHitProbability
- ld a, [hld] ; read base power from RAM
- and a
- ret z ; do nothing if zero
- dec hl
- ld c, [hl] ; read move id
- ld a, [de]
- bit GettingPumped, a ; test for focus energy
- jr nz, .focusEnergyUsed ; bug: using focus energy causes a shift to the right instead of left,
- ; resulting in 1/4 the usual crit chance
- sla b ; (effective (base speed/2)*2)
- jr nc, .noFocusEnergyUsed
- ld b, $ff ; cap at 255/256
- jr .noFocusEnergyUsed
-.focusEnergyUsed
- srl b
-.noFocusEnergyUsed
- ld hl, HighCriticalMoves ; table of high critical hit moves
-.Loop
- ld a, [hli] ; read move from move table
- cp c ; does it match the move about to be used?
- jr z, .HighCritical ; if so, the move about to be used is a high critical hit ratio move
- inc a ; move on to the next move, FF terminates loop
- jr nz, .Loop ; check the next move in HighCriticalMoves
- srl b ; /2 for regular move (effective (base speed / 2))
- jr .SkipHighCritical ; continue as a normal move
-.HighCritical
- sla b ; *2 for high critical hit moves
- jr nc, .noCarry
- ld b, $ff ; cap at 255/256
-.noCarry
- sla b ; *4 for high critical move (effective (base speed/2)*8))
- jr nc, .SkipHighCritical
- ld b, $ff
-.SkipHighCritical
- call BattleRandom ; generates a random value, in "a"
- rlc a
- rlc a
- rlc a
- cp b ; check a against calculated crit rate
- ret nc ; no critical hit if no borrow
- ld a, $1
- ld [wCriticalHitOrOHKO], a ; set critical hit flag
- ret
-
-; high critical hit moves
-HighCriticalMoves: ; 3e200 (f:6200)
- db KARATE_CHOP
- db RAZOR_LEAF
- db CRABHAMMER
- db SLASH
- db $FF
-
-
-; function to determine if Counter hits and if so, how much damage it does
-HandleCounterMove: ; 3e205 (f:6205)
-; The variables checked by Counter are updated whenever the cursor points to a new move in the battle selection menu.
-; This is irrelevant for the opponent's side outside of link battles, since the move selection is controlled by the AI.
-; However, in the scenario where the player switches out and the opponent uses Counter,
-; the outcome may be affected by the player's actions in the move selection menu prior to switching the Pokemon.
-; This might also lead to desync glitches in link battles.
-
- ld a,[H_WHOSETURN] ; whose turn
- and a
-; player's turn
- ld hl,wEnemySelectedMove
- ld de,wEnemyMovePower
- ld a,[wPlayerSelectedMove]
- jr z,.next
-; enemy's turn
- ld hl,wPlayerSelectedMove
- ld de,wPlayerMovePower
- ld a,[wEnemySelectedMove]
-.next
- cp a,COUNTER
- ret nz ; return if not using Counter
- ld a,$01
- ld [wMoveMissed],a ; initialize the move missed variable to true (it is set to false below if the move hits)
- ld a,[hl]
- cp a,COUNTER
- ret z ; miss if the opponent's last selected move is Counter.
- ld a,[de]
- and a
- ret z ; miss if the opponent's last selected move's Base Power is 0.
-; check if the move the target last selected was Normal or Fighting type
- inc de
- ld a,[de]
- and a ; normal type
- jr z,.counterableType
- cp a,FIGHTING
- jr z,.counterableType
-; if the move wasn't Normal or Fighting type, miss
- xor a
- ret
-.counterableType
- ld hl,wDamage
- ld a,[hli]
- or [hl]
- ret z ; If we made it here, Counter still misses if the last move used in battle did no damage to its target.
- ; wDamage is shared by both players, so Counter may strike back damage dealt by the Counter user itself
- ; if the conditions meet, even though 99% of the times damage will come from the target.
-; if it did damage, double it
- ld a,[hl]
- add a
- ldd [hl],a
- ld a,[hl]
- adc a
- ld [hl],a
- jr nc,.noCarry
-; damage is capped at 0xFFFF
- ld a,$ff
- ld [hli],a
- ld [hl],a
-.noCarry
- xor a
- ld [wMoveMissed],a
- call MoveHitTest ; do the normal move hit test in addition to Counter's special rules
- xor a
- ret
-
-ApplyAttackToEnemyPokemon: ; 3e251 (f:6251)
- ld a,[wPlayerMoveEffect]
- cp a,OHKO_EFFECT
- jr z,ApplyDamageToEnemyPokemon
- cp a,SUPER_FANG_EFFECT
- jr z,.superFangEffect
- cp a,SPECIAL_DAMAGE_EFFECT
- jr z,.specialDamage
- ld a,[wPlayerMovePower]
- and a
- jp z,ApplyAttackToEnemyPokemonDone ; no attack to apply if base power is 0
- jr ApplyDamageToEnemyPokemon
-.superFangEffect
-; set the damage to half the target's HP
- ld hl,wEnemyMonHP
- ld de,wDamage
- ld a,[hli]
- srl a
- ld [de],a
- inc de
- ld b,a
- ld a,[hl]
- rr a
- ld [de],a
- or b
- jr nz,ApplyDamageToEnemyPokemon
-; make sure Super Fang's damage is always at least 1
- ld a,$01
- ld [de],a
- jr ApplyDamageToEnemyPokemon
-.specialDamage
- ld hl,wBattleMonLevel
- ld a,[hl]
- ld b,a ; Seismic Toss deals damage equal to the user's level
- ld a,[wPlayerMoveNum]
- cp a,SEISMIC_TOSS
- jr z,.storeDamage
- cp a,NIGHT_SHADE
- jr z,.storeDamage
- ld b,SONICBOOM_DAMAGE ; 20
- cp a,SONICBOOM
- jr z,.storeDamage
- ld b,DRAGON_RAGE_DAMAGE ; 40
- cp a,DRAGON_RAGE
- jr z,.storeDamage
-; Psywave
- ld a,[hl]
- ld b,a
- srl a
- add b
- ld b,a ; b = level * 1.5
-; loop until a random number in the range [1, b) is found
-.loop
- call BattleRandom
- and a
- jr z,.loop
- cp b
- jr nc,.loop
- ld b,a
-.storeDamage ; store damage value at b
- ld hl,wDamage
- xor a
- ld [hli],a
- ld a,b
- ld [hl],a
-
-ApplyDamageToEnemyPokemon: ; 3e2b4 (f:62b4)
- ld hl,wDamage
- ld a,[hli]
- ld b,a
- ld a,[hl]
- or b
- jr z,ApplyAttackToEnemyPokemonDone ; we're done if damage is 0
- ld a,[wEnemyBattleStatus2]
- bit HasSubstituteUp,a ; does the enemy have a substitute?
- jp nz,AttackSubstitute
-; subtract the damage from the pokemon's current HP
-; also, save the current HP at wHPBarOldHP
- ld a,[hld]
- ld b,a
- ld a,[wEnemyMonHP + 1]
- ld [wHPBarOldHP],a
- sub b
- ld [wEnemyMonHP + 1],a
- ld a,[hl]
- ld b,a
- ld a,[wEnemyMonHP]
- ld [wHPBarOldHP+1],a
- sbc b
- ld [wEnemyMonHP],a
- jr nc,.animateHpBar
-; if more damage was done than the current HP, zero the HP and set the damage (wDamage)
-; equal to how much HP the pokemon had before the attack
- ld a,[wHPBarOldHP+1]
- ld [hli],a
- ld a,[wHPBarOldHP]
- ld [hl],a
- xor a
- ld hl,wEnemyMonHP
- ld [hli],a
- ld [hl],a
-.animateHpBar
- ld hl,wEnemyMonMaxHP
- ld a,[hli]
- ld [wHPBarMaxHP+1],a
- ld a,[hl]
- ld [wHPBarMaxHP],a
- ld hl,wEnemyMonHP
- ld a,[hli]
- ld [wHPBarNewHP+1],a
- ld a,[hl]
- ld [wHPBarNewHP],a
- coord hl, 2, 2
- xor a
- ld [wHPBarType],a
- predef UpdateHPBar2 ; animate the HP bar shortening
-ApplyAttackToEnemyPokemonDone: ; 3e30f (f:630f)
- jp DrawHUDsAndHPBars
-
-ApplyAttackToPlayerPokemon: ; 3e312 (f:6312)
- ld a,[wEnemyMoveEffect]
- cp a,OHKO_EFFECT
- jr z,ApplyDamageToPlayerPokemon
- cp a,SUPER_FANG_EFFECT
- jr z,.superFangEffect
- cp a,SPECIAL_DAMAGE_EFFECT
- jr z,.specialDamage
- ld a,[wEnemyMovePower]
- and a
- jp z,ApplyAttackToPlayerPokemonDone
- jr ApplyDamageToPlayerPokemon
-.superFangEffect
-; set the damage to half the target's HP
- ld hl,wBattleMonHP
- ld de,wDamage
- ld a,[hli]
- srl a
- ld [de],a
- inc de
- ld b,a
- ld a,[hl]
- rr a
- ld [de],a
- or b
- jr nz,ApplyDamageToPlayerPokemon
-; make sure Super Fang's damage is always at least 1
- ld a,$01
- ld [de],a
- jr ApplyDamageToPlayerPokemon
-.specialDamage
- ld hl,wEnemyMonLevel
- ld a,[hl]
- ld b,a
- ld a,[wEnemyMoveNum]
- cp a,SEISMIC_TOSS
- jr z,.storeDamage
- cp a,NIGHT_SHADE
- jr z,.storeDamage
- ld b,SONICBOOM_DAMAGE
- cp a,SONICBOOM
- jr z,.storeDamage
- ld b,DRAGON_RAGE_DAMAGE
- cp a,DRAGON_RAGE
- jr z,.storeDamage
-; Psywave
- ld a,[hl]
- ld b,a
- srl a
- add b
- ld b,a ; b = attacker's level * 1.5
-; loop until a random number in the range [0, b) is found
-; this differs from the range when the player attacks, which is [1, b)
-; it's possible for the enemy to do 0 damage with Psywave, but the player always does at least 1 damage
-.loop
- call BattleRandom
- cp b
- jr nc,.loop
- ld b,a
-.storeDamage
- ld hl,wDamage
- xor a
- ld [hli],a
- ld a,b
- ld [hl],a
-
-ApplyDamageToPlayerPokemon: ; 3e372 (f:6372)
- ld hl,wDamage
- ld a,[hli]
- ld b,a
- ld a,[hl]
- or b
- jr z,ApplyAttackToPlayerPokemonDone ; we're done if damage is 0
- ld a,[wPlayerBattleStatus2]
- bit HasSubstituteUp,a ; does the player have a substitute?
- jp nz,AttackSubstitute
-; subtract the damage from the pokemon's current HP
-; also, save the current HP at wHPBarOldHP and the new HP at wHPBarNewHP
- ld a,[hld]
- ld b,a
- ld a,[wBattleMonHP + 1]
- ld [wHPBarOldHP],a
- sub b
- ld [wBattleMonHP + 1],a
- ld [wHPBarNewHP],a
- ld b,[hl]
- ld a,[wBattleMonHP]
- ld [wHPBarOldHP+1],a
- sbc b
- ld [wBattleMonHP],a
- ld [wHPBarNewHP+1],a
- jr nc,.animateHpBar
-; if more damage was done than the current HP, zero the HP and set the damage (wDamage)
-; equal to how much HP the pokemon had before the attack
- ld a,[wHPBarOldHP+1]
- ld [hli],a
- ld a,[wHPBarOldHP]
- ld [hl],a
- xor a
- ld hl,wBattleMonHP
- ld [hli],a
- ld [hl],a
- ld hl,wHPBarNewHP
- ld [hli],a
- ld [hl],a
-.animateHpBar
- ld hl,wBattleMonMaxHP
- ld a,[hli]
- ld [wHPBarMaxHP+1],a
- ld a,[hl]
- ld [wHPBarMaxHP],a
- coord hl, 10, 9
- ld a,$01
- ld [wHPBarType],a
- predef UpdateHPBar2 ; animate the HP bar shortening
-ApplyAttackToPlayerPokemonDone: ; 3e3cd (f:63cd)
- jp DrawHUDsAndHPBars
-
-AttackSubstitute: ; 3e3d0 (f:63d0)
-; Unlike the two ApplyAttackToPokemon functions, Attack Substitute is shared by player and enemy.
-; Self-confusion damage as well as Hi-Jump Kick and Jump Kick recoil cause a momentary turn swap before being applied.
-; If the user has a Substitute up and would take damage because of that,
-; damage will be applied to the other player's Substitute.
-; Normal recoil such as from Double-Edge isn't affected by this glitch,
-; because this function is never called in that case.
-
- ld hl,SubstituteTookDamageText
- call PrintText
-; values for player turn
- ld de,wEnemySubstituteHP
- ld bc,wEnemyBattleStatus2
- ld a,[H_WHOSETURN]
- and a
- jr z,.applyDamageToSubstitute
-; values for enemy turn
- ld de,wPlayerSubstituteHP
- ld bc,wPlayerBattleStatus2
-.applyDamageToSubstitute
- ld hl,wDamage
- ld a,[hli]
- and a
- jr nz,.substituteBroke ; damage > 0xFF always breaks substitutes
-; subtract damage from HP of substitute
- ld a,[de]
- sub [hl]
- ld [de],a
- ret nc
-.substituteBroke
-; If the target's Substitute breaks, wDamage isn't updated with the amount of HP
-; the Substitute had before being attacked.
- ld h,b
- ld l,c
- res HasSubstituteUp,[hl] ; unset the substitute bit
- ld hl,SubstituteBrokeText
- call PrintText
-; flip whose turn it is for the next function call
- ld a,[H_WHOSETURN]
- xor a,$01
- ld [H_WHOSETURN],a
- callab Func_79929 ; animate the substitute breaking
-; flip the turn back to the way it was
- ld a,[H_WHOSETURN]
- xor a,$01
- ld [H_WHOSETURN],a
- ld hl,wPlayerMoveEffect ; value for player's turn
- and a
- jr z,.nullifyEffect
- ld hl,wEnemyMoveEffect ; value for enemy's turn
-.nullifyEffect
- xor a
- ld [hl],a ; zero the effect of the attacker's move
- jp DrawHUDsAndHPBars
-
-SubstituteTookDamageText: ; 3e41e (f:641e)
- TX_FAR _SubstituteTookDamageText
- db "@"
-
-SubstituteBrokeText: ; 3e423 (f:6423)
- TX_FAR _SubstituteBrokeText
- db "@"
-
-; this function raises the attack modifier of a pokemon using Rage when that pokemon is attacked
-HandleBuildingRage: ; 3e428 (f:6428)
-; values for the player turn
- ld hl,wEnemyBattleStatus2
- ld de,wEnemyMonStatMods
- ld bc,wEnemyMoveNum
- ld a,[H_WHOSETURN]
- and a
- jr z,.next
-; values for the enemy turn
- ld hl,wPlayerBattleStatus2
- ld de,wPlayerMonStatMods
- ld bc,wPlayerMoveNum
-.next
- bit UsingRage,[hl] ; is the pokemon being attacked under the effect of Rage?
- ret z ; return if not
- ld a,[de]
- cp a,$0d ; maximum stat modifier value
- ret z ; return if attack modifier is already maxed
- ld a,[H_WHOSETURN]
- xor a,$01 ; flip turn for the stat modifier raising function
- ld [H_WHOSETURN],a
-; temporarily change the target pokemon's move to $00 and the effect to the one
-; that causes the attack modifier to go up one stage
- ld h,b
- ld l,c
- ld [hl],$00 ; null move number
- inc hl
- ld [hl],ATTACK_UP1_EFFECT
- push hl
- ld hl,BuildingRageText
- call PrintText
- call StatModifierUpEffect ; stat modifier raising function
- pop hl
- xor a
- ldd [hl],a ; null move effect
- ld a,RAGE
- ld [hl],a ; restore the target pokemon's move number to Rage
- ld a,[H_WHOSETURN]
- xor a,$01 ; flip turn back to the way it was
- ld [H_WHOSETURN],a
- ret
-
-BuildingRageText: ; 3e46a (f:646a)
- TX_FAR _BuildingRageText
- db "@"
-
-; copy last move for Mirror Move
-; sets zero flag on failure and unsets zero flag on success
-MirrorMoveCopyMove: ; 3e46f (f:646f)
-; Mirror Move makes use of ccf1 (wPlayerUsedMove) and ccf2 (wEnemyUsedMove) addresses,
-; which are mainly used to print the "[Pokemon] used [Move]" text.
-; Both are set to 0 whenever a new Pokemon is sent out
-; ccf1 is also set to 0 whenever the player is fast asleep or frozen solid.
-; ccf2 is also set to 0 whenever the enemy is fast asleep or frozen solid.
-
- ld a,[H_WHOSETURN]
- and a
-; values for player turn
- ld a,[wEnemyUsedMove]
- ld hl,wPlayerSelectedMove
- ld de,wPlayerMoveNum
- jr z,.next
-; values for enemy turn
- ld a,[wPlayerUsedMove]
- ld de,wEnemyMoveNum
- ld hl,wEnemySelectedMove
-.next
- ld [hl],a
- cp a,MIRROR_MOVE ; did the target Pokemon last use Mirror Move, and miss?
- jr z,.mirrorMoveFailed
- and a ; has the target selected any move yet?
- jr nz,ReloadMoveData
-.mirrorMoveFailed
- ld hl,MirrorMoveFailedText
- call PrintText
- xor a
- ret
-
-MirrorMoveFailedText: ; 3e496 (f:6496)
- TX_FAR _MirrorMoveFailedText
- db "@"
-
-; function used to reload move data for moves like Mirror Move and Metronome
-ReloadMoveData: ; 3e49b (f:649b)
- ld [wd11e],a
- dec a
- ld hl,Moves
- ld bc,MoveEnd - Moves
- call AddNTimes
- ld a,BANK(Moves)
- call FarCopyData ; copy the move's stats
- call IncrementMovePP
-; the follow two function calls are used to reload the move name
- call GetMoveName
- call CopyStringToCF4B
- ld a,$01
- and a
- ret
-
-; function that picks a random move for metronome
-MetronomePickMove: ; 3e4ba (f:64ba)
- xor a
- ld [wAnimationType],a
- ld a,METRONOME
- call PlayMoveAnimation ; play Metronome's animation
-; values for player turn
- ld de,wPlayerMoveNum
- ld hl,wPlayerSelectedMove
- ld a,[H_WHOSETURN]
- and a
- jr z,.pickMoveLoop
-; values for enemy turn
- ld de,wEnemyMoveNum
- ld hl,wEnemySelectedMove
-; loop to pick a random number in the range [1, $a5) to be the move used by Metronome
-.pickMoveLoop
- call BattleRandom
- and a
- jr z,.pickMoveLoop
- cp a,NUM_ATTACKS + 1 ; max normal move number + 1 (this is Struggle's move number)
- jr nc,.pickMoveLoop
- cp a,METRONOME
- jr z,.pickMoveLoop
- ld [hl],a
- jr ReloadMoveData
-
-; this function increments the current move's PP
-; it's used to prevent moves that run another move within the same turn
-; (like Mirror Move and Metronome) from losing 2 PP
-IncrementMovePP: ; 3e4e5 (f:64e5)
- ld a,[H_WHOSETURN]
- and a
-; values for player turn
- ld hl,wBattleMonPP
- ld de,wPartyMon1PP
- ld a,[wPlayerMoveListIndex]
- jr z,.next
-; values for enemy turn
- ld hl,wEnemyMonPP
- ld de,wEnemyMon1PP
- ld a,[wEnemyMoveListIndex]
-.next
- ld b,$00
- ld c,a
- add hl,bc
- inc [hl] ; increment PP in the currently battling pokemon memory location
- ld h,d
- ld l,e
- add hl,bc
- ld a,[H_WHOSETURN]
- and a
- ld a,[wPlayerMonNumber] ; value for player turn
- jr z,.updatePP
- ld a,[wEnemyMonPartyPos] ; value for enemy turn
-.updatePP
- ld bc,wEnemyMon2 - wEnemyMon1
- call AddNTimes
- inc [hl] ; increment PP in the party memory location
- ret
-
-; function to adjust the base damage of an attack to account for type effectiveness
-AdjustDamageForMoveType: ; 3e517 (f:6517)
-; values for player turn
- ld hl,wBattleMonType
- ld a,[hli]
- ld b,a ; b = type 1 of attacker
- ld c,[hl] ; c = type 2 of attacker
- ld hl,wEnemyMonType
- ld a,[hli]
- ld d,a ; d = type 1 of defender
- ld e,[hl] ; e = type 2 of defender
- ld a,[wPlayerMoveType]
- ld [wMoveType],a
- ld a,[H_WHOSETURN]
- and a
- jr z,.next
-; values for enemy turn
- ld hl,wEnemyMonType
- ld a,[hli]
- ld b,a ; b = type 1 of attacker
- ld c,[hl] ; c = type 2 of attacker
- ld hl,wBattleMonType
- ld a,[hli]
- ld d,a ; d = type 1 of defender
- ld e,[hl] ; e = type 2 of defender
- ld a,[wEnemyMoveType]
- ld [wMoveType],a
-.next
- ld a,[wMoveType]
- cp b ; does the move type match type 1 of the attacker?
- jr z,.sameTypeAttackBonus
- cp c ; does the move type match type 2 of the attacker?
- jr z,.sameTypeAttackBonus
- jr .skipSameTypeAttackBonus
-.sameTypeAttackBonus
-; if the move type matches one of the attacker's types
- ld hl,wDamage + 1
- ld a,[hld]
- ld h,[hl]
- ld l,a ; hl = damage
- ld b,h
- ld c,l ; bc = damage
- srl b
- rr c ; bc = floor(0.5 * damage)
- add hl,bc ; hl = floor(1.5 * damage)
-; store damage
- ld a,h
- ld [wDamage],a
- ld a,l
- ld [wDamage + 1],a
- ld hl,wDamageMultipliers
- set 7,[hl]
-.skipSameTypeAttackBonus
- ld a,[wMoveType]
- ld b,a
- ld hl,TypeEffects
-.loop
- ld a,[hli] ; a = "attacking type" of the current type pair
- cp a,$ff
- jr z,.done
- cp b ; does move type match "attacking type"?
- jr nz,.nextTypePair
- ld a,[hl] ; a = "defending type" of the current type pair
- cp d ; does type 1 of defender match "defending type"?
- jr z,.matchingPairFound
- cp e ; does type 2 of defender match "defending type"?
- jr z,.matchingPairFound
- jr .nextTypePair
-.matchingPairFound
-; if the move type matches the "attacking type" and one of the defender's types matches the "defending type"
- push hl
- push bc
- inc hl
- ld a,[wDamageMultipliers]
- and a,$80
- ld b,a
- ld a,[hl] ; a = damage multiplier
- ld [H_MULTIPLIER],a
- add b
- ld [wDamageMultipliers],a
- xor a
- ld [H_MULTIPLICAND],a
- ld hl,wDamage
- ld a,[hli]
- ld [H_MULTIPLICAND + 1],a
- ld a,[hld]
- ld [H_MULTIPLICAND + 2],a
- call Multiply
- ld a,10
- ld [H_DIVISOR],a
- ld b,$04
- call Divide
- ld a,[H_QUOTIENT + 2]
- ld [hli],a
- ld b,a
- ld a,[H_QUOTIENT + 3]
- ld [hl],a
- or b ; is damage 0?
- jr nz,.skipTypeImmunity
-.typeImmunity
-; if damage is 0, make the move miss
-; this only occurs if a move that would do 2 or 3 damage is 0.25x effective against the target
- inc a
- ld [wMoveMissed],a
-.skipTypeImmunity
- pop bc
- pop hl
-.nextTypePair
- inc hl
- inc hl
- jp .loop
-.done
- ret
-
-AIGetTypeEffectiveness: ; 3e5bb (f:65bb)
- ld a,[wEnemyMoveType]
- ld d,a ; d = type of enemy move
- ld hl,wBattleMonType
- ld b,[hl] ; b = type 1 of player's pokemon
- inc hl
- ld c,[hl] ; c = type 2 of player's pokemon
- ld a,$10
- ld [wd11e],a ; initialize [wd11e] to neutral effectiveness
- ld hl,TypeEffects
-.loop
- ld a,[hli]
- cp a,$ff
- ret z
- cp d ; match the type of the move
- jr nz,.nextTypePair1
- ld a,[hli]
- cp b ; match with type 1 of pokemon
- jr z,.done
- cp c ; or match with type 2 of pokemon
- jr z,.done
- jr .nextTypePair2
-.nextTypePair1
- inc hl
-.nextTypePair2
- inc hl
- jr .loop
-
-.done
- ld a, [wTrainerClass]
- cp LORELEI
- jr nz, .ok
- ld a, [wEnemyMonSpecies]
- cp DEWGONG
- jr nz, .ok
- call BattleRandom
- cp $66 ; 40 percent
- ret c
-.ok
-
- ld a,[hl]
- ld [wd11e],a ; store damage multiplier
- ret
-
-INCLUDE "data/type_effects.asm"
-
-; some tests that need to pass for a move to hit
-MoveHitTest: ; 3e6f1 (f:66f1)
-; player's turn
- ld hl,wEnemyBattleStatus1
- ld de,wPlayerMoveEffect
- ld bc,wEnemyMonStatus
- ld a,[H_WHOSETURN]
- and a
- jr z,.dreamEaterCheck
-; enemy's turn
- ld hl,wPlayerBattleStatus1
- ld de,wEnemyMoveEffect
- ld bc,wBattleMonStatus
-.dreamEaterCheck
- ld a,[de]
- cp a,DREAM_EATER_EFFECT
- jr nz,.swiftCheck
- ld a,[bc]
- and a,SLP ; is the target pokemon sleeping?
- jp z,.moveMissed
-.swiftCheck
- ld a,[de]
- cp a,SWIFT_EFFECT
- ret z ; Swift never misses (interestingly, Azure Heights lists this is a myth, but it appears to be true)
- call CheckTargetSubstitute ; substitute check (note that this overwrites a)
- jr z,.checkForDigOrFlyStatus
-; this code is buggy. it's supposed to prevent HP draining moves from working on substitutes.
-; since $7b79 overwrites a with either $00 or $01, it never works.
- cp a,DRAIN_HP_EFFECT
- jp z,.moveMissed
- cp a,DREAM_EATER_EFFECT
- jp z,.moveMissed
-.checkForDigOrFlyStatus
- bit Invulnerable,[hl]
- jp nz,.moveMissed
- ld a,[H_WHOSETURN]
- and a
- jr nz,.enemyTurn
-.playerTurn
-; this checks if the move effect is disallowed by mist
- ld a,[wPlayerMoveEffect]
- cp a,ATTACK_DOWN1_EFFECT
- jr c,.skipEnemyMistCheck
- cp a,HAZE_EFFECT + 1
- jr c,.enemyMistCheck
- cp a,ATTACK_DOWN2_EFFECT
- jr c,.skipEnemyMistCheck
- cp a,REFLECT_EFFECT + 1
- jr c,.enemyMistCheck
- jr .skipEnemyMistCheck
-.enemyMistCheck
-; if move effect is from $12 to $19 inclusive or $3a to $41 inclusive
-; i.e. the following moves
-; GROWL, TAIL WHIP, LEER, STRING SHOT, SAND-ATTACK, SMOKESCREEN, KINESIS,
-; FLASH, CONVERSION*, HAZE*, SCREECH, LIGHT SCREEN*, REFLECT*
-; the moves that are marked with an asterisk are not affected since this
-; function is not called when those moves are used
- ld a,[wEnemyBattleStatus2]
- bit ProtectedByMist,a ; is mon protected by mist?
- jp nz,.moveMissed
-.skipEnemyMistCheck
- ld a,[wPlayerBattleStatus2]
- bit UsingXAccuracy,a ; is the player using X Accuracy?
- ret nz ; if so, always hit regardless of accuracy/evasion
- jr .calcHitChance
-.enemyTurn
- ld a,[wEnemyMoveEffect]
- cp a,ATTACK_DOWN1_EFFECT
- jr c,.skipPlayerMistCheck
- cp a,HAZE_EFFECT + 1
- jr c,.playerMistCheck
- cp a,ATTACK_DOWN2_EFFECT
- jr c,.skipPlayerMistCheck
- cp a,REFLECT_EFFECT + 1
- jr c,.playerMistCheck
- jr .skipPlayerMistCheck
-.playerMistCheck
-; similar to enemy mist check
- ld a,[wPlayerBattleStatus2]
- bit ProtectedByMist,a ; is mon protected by mist?
- jp nz,.moveMissed
-.skipPlayerMistCheck
- ld a,[wEnemyBattleStatus2]
- bit UsingXAccuracy,a ; is the enemy using X Accuracy?
- ret nz ; if so, always hit regardless of accuracy/evasion
-.calcHitChance
- call CalcHitChance ; scale the move accuracy according to attacker's accuracy and target's evasion
- ld a,[wPlayerMoveAccuracy]
- ld b,a
- ld a,[H_WHOSETURN]
- and a
- jr z,.doAccuracyCheck
- ld a,[wEnemyMoveAccuracy]
- ld b,a
-.doAccuracyCheck
-; if the random number generated is greater than or equal to the scaled accuracy, the move misses
-; note that this means that even the highest accuracy is still just a 255/256 chance, not 100%
- call BattleRandom
- cp b
- jr nc,.moveMissed
- ret
-.moveMissed
- xor a
- ld hl,wDamage ; zero the damage
- ld [hli],a
- ld [hl],a
- inc a
- ld [wMoveMissed],a
- ld a,[H_WHOSETURN]
- and a
- jr z,.playerTurn2
-.enemyTurn2
- ld hl,wEnemyBattleStatus1
- res UsingTrappingMove,[hl] ; end multi-turn attack e.g. wrap
- ret
-.playerTurn2
- ld hl,wPlayerBattleStatus1
- res UsingTrappingMove,[hl] ; end multi-turn attack e.g. wrap
- ret
-
-; values for player turn
-CalcHitChance: ; 3e7aa (f:67aa)
- ld hl,wPlayerMoveAccuracy
- ld a,[H_WHOSETURN]
- and a
- ld a,[wPlayerMonAccuracyMod]
- ld b,a
- ld a,[wEnemyMonEvasionMod]
- ld c,a
- jr z,.next
-; values for enemy turn
- ld hl,wEnemyMoveAccuracy
- ld a,[wEnemyMonAccuracyMod]
- ld b,a
- ld a,[wPlayerMonEvasionMod]
- ld c,a
-.next
- ld a,$0e
- sub c
- ld c,a ; c = 14 - EVASIONMOD (this "reflects" the value over 7, so that an increase in the target's evasion
- ; decreases the hit chance instead of increasing the hit chance)
-; zero the high bytes of the multiplicand
- xor a
- ld [H_MULTIPLICAND],a
- ld [H_MULTIPLICAND + 1],a
- ld a,[hl]
- ld [H_MULTIPLICAND + 2],a ; set multiplicand to move accuracy
- push hl
- ld d,$02 ; loop has two iterations
-; loop to do the calculations, the first iteration multiplies by the accuracy ratio and
-; the second iteration multiplies by the evasion ratio
-.loop
- push bc
- ld hl, StatModifierRatios ; stat modifier ratios
- dec b
- sla b
- ld c,b
- ld b,$00
- add hl,bc ; hl = address of stat modifier ratio
- pop bc
- ld a,[hli]
- ld [H_MULTIPLIER],a ; set multiplier to the numerator of the ratio
- call Multiply
- ld a,[hl]
- ld [H_DIVISOR],a ; set divisor to the the denominator of the ratio
- ; (the dividend is the product of the previous multiplication)
- ld b,$04 ; number of bytes in the dividend
- call Divide
- ld a,[H_QUOTIENT + 3]
- ld b,a
- ld a,[H_QUOTIENT + 2]
- or b
- jp nz,.nextCalculation
-; make sure the result is always at least one
- ld [H_QUOTIENT + 2],a
- ld a,$01
- ld [H_QUOTIENT + 3],a
-.nextCalculation
- ld b,c
- dec d
- jr nz,.loop
- ld a,[H_QUOTIENT + 2]
- and a ; is the calculated hit chance over 0xFF?
- ld a,[H_QUOTIENT + 3]
- jr z,.storeAccuracy
-; if calculated hit chance over 0xFF
- ld a,$ff ; set the hit chance to 0xFF
-.storeAccuracy
- pop hl
- ld [hl],a ; store the hit chance in the move accuracy variable
- ret
-
-; multiplies damage by a random percentage from ~85% to 100%
-RandomizeDamage: ; 3e80d (f:680d)
- ld hl, wDamage
- ld a, [hli]
- and a
- jr nz, .DamageGreaterThanOne
- ld a, [hl]
- cp 2
- ret c ; return if damage is equal to 0 or 1
-.DamageGreaterThanOne
- xor a
- ld [H_MULTIPLICAND], a
- dec hl
- ld a, [hli]
- ld [H_MULTIPLICAND + 1], a
- ld a, [hl]
- ld [H_MULTIPLICAND + 2], a
-; loop until a random number greater than or equal to 217 is generated
-.loop
- call BattleRandom
- rrca
- cp 217
- jr c, .loop
- ld [H_MULTIPLIER], a
- call Multiply ; multiply damage by the random number, which is in the range [217, 255]
- ld a, 255
- ld [H_DIVISOR], a
- ld b, $4
- call Divide ; divide the result by 255
-; store the modified damage
- ld a, [H_QUOTIENT + 2]
- ld hl, wDamage
- ld [hli], a
- ld a, [H_QUOTIENT + 3]
- ld [hl], a
- ret
-
-; for more detailed commentary, see equivalent function for player side (ExecutePlayerMove)
-ExecuteEnemyMove: ; 3e842 (f:6842)
- ld a, [wEnemySelectedMove]
- inc a
- jp z, ExecuteEnemyMoveDone
- call PrintGhostText
- jp z, ExecuteEnemyMoveDone
- ld a, [wLinkState]
- cp LINK_STATE_BATTLING
- jr nz, .executeEnemyMove
- ld b, $1
- ld a, [wSerialExchangeNybbleReceiveData]
- cp $e
- jr z, .executeEnemyMove
- cp $4
- ret nc
-.executeEnemyMove
- ld hl, wAILayer2Encouragement
- inc [hl]
- xor a
- ld [wMoveMissed], a
- ld [wMoveDidntMiss], a
- ld a, $a
- ld [wDamageMultipliers], a
- call CheckEnemyStatusConditions
- jr nz, .enemyHasNoSpecialConditions
- jp [hl]
-.enemyHasNoSpecialConditions
- ld hl, wEnemyBattleStatus1
- bit ChargingUp, [hl] ; is the enemy charging up for attack?
- jr nz, EnemyCanExecuteChargingMove ; if so, jump
- call GetCurrentMove
-
-CheckIfEnemyNeedsToChargeUp: ; 3e882 (f:6882)
- ld a, [wEnemyMoveEffect]
- cp CHARGE_EFFECT
- jp z, JumpMoveEffect
- cp FLY_EFFECT
- jp z, JumpMoveEffect
- jr EnemyCanExecuteMove
-EnemyCanExecuteChargingMove: ; 3e891 (f:6891)
- ld hl, wEnemyBattleStatus1
- res ChargingUp, [hl] ; no longer charging up for attack
- res Invulnerable, [hl] ; no longer invulnerable to typical attacks
- ld a, [wEnemyMoveNum]
- ld [wd0b5], a
- ld a, BANK(MoveNames)
- ld [wPredefBank], a
- ld a, MOVE_NAME
- ld [wNameListType], a
- call GetName
- ld de, wcd6d
- call CopyStringToCF4B
-EnemyCanExecuteMove: ; 3e8b1 (f:68b1)
- xor a
- ld [wMonIsDisobedient], a
- call PrintMonName1Text
- ld a, [wEnemyMoveEffect]
- ld hl, ResidualEffects1
- ld de, $1
- call IsInArray
- jp c, JumpMoveEffect
- ld a, [wEnemyMoveEffect]
- ld hl, SpecialEffectsCont
- ld de, $1
- call IsInArray
- call c, JumpMoveEffect
-EnemyCalcMoveDamage: ; 3e8d6 (f:68d6)
- call SwapPlayerAndEnemyLevels
- ld a, [wEnemyMoveEffect]
- ld hl, SetDamageEffects
- ld de, $1
- call IsInArray
- jp c, EnemyMoveHitTest
- call CriticalHitTest
- call HandleCounterMove
- jr z, handleIfEnemyMoveMissed
- call SwapPlayerAndEnemyLevels
- call GetDamageVarsForEnemyAttack
- call SwapPlayerAndEnemyLevels
- call CalculateDamage
- jp z, EnemyCheckIfFlyOrChargeEffect
- call AdjustDamageForMoveType
- call RandomizeDamage
-
-EnemyMoveHitTest: ; 3e905 (f:6905)
- call MoveHitTest
-handleIfEnemyMoveMissed: ; 3e908 (f:6908)
- ld a, [wMoveMissed]
- and a
- jr z, .moveDidNotMiss
- ld a, [wEnemyMoveEffect]
- cp EXPLODE_EFFECT
- jr z, handleExplosionMiss
- jr EnemyCheckIfFlyOrChargeEffect
-.moveDidNotMiss
- call SwapPlayerAndEnemyLevels
-
-GetEnemyAnimationType: ; 3e91a (f:691a)
- ld a, [wEnemyMoveEffect]
- and a
- ld a, $1
- jr z, playEnemyMoveAnimation
- ld a, $2
- jr playEnemyMoveAnimation
-handleExplosionMiss: ; 3e926 (f:6926)
- call SwapPlayerAndEnemyLevels
- xor a
-playEnemyMoveAnimation: ; 3e92a (f:692a)
- push af
- ld a, [wEnemyBattleStatus2]
- bit HasSubstituteUp, a ; does mon have a substitute?
- ld hl, HideSubstituteShowMonAnim
- ld b, BANK(HideSubstituteShowMonAnim)
- call nz, Bankswitch
- pop af
- ld [wAnimationType], a
- ld a, [wEnemyMoveNum]
- call PlayMoveAnimation
- call HandleExplodingAnimation
- call DrawEnemyHUDAndHPBar
- ld a, [wEnemyBattleStatus2]
- bit HasSubstituteUp, a ; does mon have a substitute?
- ld hl, ReshowSubstituteAnim
- ld b, BANK(ReshowSubstituteAnim)
- call nz, Bankswitch ; slide the substitute's sprite out
- jr EnemyCheckIfMirrorMoveEffect
-
-EnemyCheckIfFlyOrChargeEffect: ; 3e957 (f:6957)
- call SwapPlayerAndEnemyLevels
- ld c, 30
- call DelayFrames
- ld a, [wEnemyMoveEffect]
- cp FLY_EFFECT
- jr z, .playAnim
- cp CHARGE_EFFECT
- jr z, .playAnim
- jr EnemyCheckIfMirrorMoveEffect
-.playAnim
- xor a
- ld [wAnimationType], a
- ld a,STATUS_AFFECTED_ANIM
- call PlayMoveAnimation
-EnemyCheckIfMirrorMoveEffect: ; 3e975 (f:6975)
- ld a, [wEnemyMoveEffect]
- cp MIRROR_MOVE_EFFECT
- jr nz, .notMirrorMoveEffect
- call MirrorMoveCopyMove
- jp z, ExecuteEnemyMoveDone
- jp CheckIfEnemyNeedsToChargeUp
-.notMirrorMoveEffect
- cp METRONOME_EFFECT
- jr nz, .notMetronomeEffect
- call MetronomePickMove
- jp CheckIfEnemyNeedsToChargeUp
-.notMetronomeEffect
- ld a, [wEnemyMoveEffect]
- ld hl, ResidualEffects2
- ld de, $1
- call IsInArray
- jp c, JumpMoveEffect
- ld a, [wMoveMissed]
- and a
- jr z, .moveDidNotMiss
- call PrintMoveFailureText
- ld a, [wEnemyMoveEffect]
- cp EXPLODE_EFFECT
- jr z, .handleExplosionMiss
- jp ExecuteEnemyMoveDone
-.moveDidNotMiss
- call ApplyAttackToPlayerPokemon
- call PrintCriticalOHKOText
- callab DisplayEffectiveness
- ld a, 1
- ld [wMoveDidntMiss], a
-.handleExplosionMiss
- ld a, [wEnemyMoveEffect]
- ld hl, AlwaysHappenSideEffects
- ld de, $1
- call IsInArray
- call c, JumpMoveEffect
- ld hl, wBattleMonHP
- ld a, [hli]
- ld b, [hl]
- or b
- ret z
- call HandleBuildingRage
- ld hl, wEnemyBattleStatus1
- bit AttackingMultipleTimes, [hl] ; is mon hitting multiple times? (example: double kick)
- jr z, .notMultiHitMove
- push hl
- ld hl, wEnemyNumAttacksLeft
- dec [hl]
- pop hl
- jp nz, GetEnemyAnimationType
- res AttackingMultipleTimes, [hl] ; mon is no longer hitting multiple times
- ld hl, HitXTimesText
- call PrintText
- xor a
- ld [wEnemyNumHits], a
-.notMultiHitMove
- ld a, [wEnemyMoveEffect]
- and a
- jr z, ExecuteEnemyMoveDone
- ld hl, SpecialEffects
- ld de, $1
- call IsInArray
- call nc, JumpMoveEffect
- jr ExecuteEnemyMoveDone
-
-HitXTimesText: ; 3ea0d (f:6a0d)
- TX_FAR _HitXTimesText
- db "@"
-
-ExecuteEnemyMoveDone: ; 3ea12 (f:6a12)
- ld b, $1
- ret
-
-; checks for various status conditions affecting the enemy mon
-; stores whether the mon cannot use a move this turn in Z flag
-CheckEnemyStatusConditions: ; 3ea15 (f:6a15)
- ld hl, wEnemyMonStatus
- ld a, [hl]
- and SLP ; sleep mask
- jr z, .checkIfFrozen
- dec a ; decrement number of turns left
- ld [wEnemyMonStatus], a
- and a
- jr z, .wokeUp ; if the number of turns hit 0, wake up
- ld hl, FastAsleepText
- call PrintText
- xor a
- ld [wAnimationType], a
- ld a,SLP_ANIM
- call PlayMoveAnimation
- jr .sleepDone
-.wokeUp
- ld hl, WokeUpText
- call PrintText
-.sleepDone
- xor a
- ld [wEnemyUsedMove], a
- ld hl, ExecuteEnemyMoveDone ; enemy can't move this turn
- jp .enemyReturnToHL
-.checkIfFrozen
- bit FRZ, [hl]
- jr z, .checkIfTrapped
- ld hl, IsFrozenText
- call PrintText
- xor a
- ld [wEnemyUsedMove], a
- ld hl, ExecuteEnemyMoveDone ; enemy can't move this turn
- jp .enemyReturnToHL
-.checkIfTrapped
- ld a, [wPlayerBattleStatus1]
- bit UsingTrappingMove, a ; is the player using a multi-turn attack like warp
- jp z, .checkIfFlinched
- ld hl, CantMoveText
- call PrintText
- ld hl, ExecuteEnemyMoveDone ; enemy can't move this turn
- jp .enemyReturnToHL
-.checkIfFlinched
- ld hl, wEnemyBattleStatus1
- bit Flinched, [hl] ; check if enemy mon flinched
- jp z, .checkIfMustRecharge
- res Flinched, [hl]
- ld hl, FlinchedText
- call PrintText
- ld hl, ExecuteEnemyMoveDone ; enemy can't move this turn
- jp .enemyReturnToHL
-.checkIfMustRecharge
- ld hl, wEnemyBattleStatus2
- bit NeedsToRecharge, [hl] ; check if enemy mon has to recharge after using a move
- jr z, .checkIfAnyMoveDisabled
- res NeedsToRecharge, [hl]
- ld hl, MustRechargeText
- call PrintText
- ld hl, ExecuteEnemyMoveDone ; enemy can't move this turn
- jp .enemyReturnToHL
-.checkIfAnyMoveDisabled
- ld hl, wEnemyDisabledMove
- ld a, [hl]
- and a
- jr z, .checkIfConfused
- dec a ; decrement disable counter
- ld [hl], a
- and $f ; did disable counter hit 0?
- jr nz, .checkIfConfused
- ld [hl], a
- ld [wEnemyDisabledMoveNumber], a
- ld hl, DisabledNoMoreText
- call PrintText
-.checkIfConfused
- ld a, [wEnemyBattleStatus1]
- add a ; check if enemy mon is confused
- jp nc, .checkIfTriedToUseDisabledMove
- ld hl, W_ENEMYCONFUSEDCOUNTER
- dec [hl]
- jr nz, .isConfused
- ld hl, wEnemyBattleStatus1
- res Confused, [hl] ; if confused counter hit 0, reset confusion status
- ld hl, ConfusedNoMoreText
- call PrintText
- jp .checkIfTriedToUseDisabledMove
-.isConfused
- ld hl, IsConfusedText
- call PrintText
- xor a
- ld [wAnimationType], a
- ld a,CONF_ANIM
- call PlayMoveAnimation
- call BattleRandom
- cp $80
- jr c, .checkIfTriedToUseDisabledMove
- ld hl, wEnemyBattleStatus1
- ld a, [hl]
- and 1 << Confused ; if mon hurts itself, clear every other status from wEnemyBattleStatus1
- ld [hl], a
- ld hl, HurtItselfText
- call PrintText
- ld hl, wBattleMonDefense
- ld a, [hli]
- push af
- ld a, [hld]
- push af
- ld a, [wEnemyMonDefense]
- ld [hli], a
- ld a, [wEnemyMonDefense + 1]
- ld [hl], a
- ld hl, wEnemyMoveEffect
- push hl
- ld a, [hl]
- push af
- xor a
- ld [hli], a
- ld [wCriticalHitOrOHKO], a
- ld a, 40
- ld [hli], a
- xor a
- ld [hl], a
- call GetDamageVarsForEnemyAttack
- call CalculateDamage
- pop af
- pop hl
- ld [hl], a
- ld hl, wBattleMonDefense + 1
- pop af
- ld [hld], a
- pop af
- ld [hl], a
- xor a
- ld [wAnimationType], a
- ld [H_WHOSETURN], a
- ld a, POUND
- call PlayMoveAnimation
- ld a, $1
- ld [H_WHOSETURN], a
- call ApplyDamageToEnemyPokemon
- jr .monHurtItselfOrFullyParalysed
-.checkIfTriedToUseDisabledMove
-; prevents a disabled move that was selected before being disabled from being used
- ld a, [wEnemyDisabledMoveNumber]
- and a
- jr z, .checkIfParalysed
- ld hl, wEnemySelectedMove
- cp [hl]
- jr nz, .checkIfParalysed
- call PrintMoveIsDisabledText
- ld hl, ExecuteEnemyMoveDone ; if a disabled move was somehow selected, player can't move this turn
- jp .enemyReturnToHL
-.checkIfParalysed
- ld hl, wEnemyMonStatus
- bit PAR, [hl]
- jr z, .checkIfUsingBide
- call BattleRandom
- cp $3f ; 25% to be fully paralysed
- jr nc, .checkIfUsingBide
- ld hl, FullyParalyzedText
- call PrintText
-.monHurtItselfOrFullyParalysed
- ld hl, wEnemyBattleStatus1
- ld a, [hl]
- ; clear bide, thrashing about, charging up, and multi-turn moves such as warp
- and $ff ^ ((1 << StoringEnergy) | (1 << ThrashingAbout) | (1 << ChargingUp) | (1 << UsingTrappingMove))
- ld [hl], a
- ld a, [wEnemyMoveEffect]
- cp FLY_EFFECT
- jr z, .flyOrChargeEffect
- cp CHARGE_EFFECT
- jr z, .flyOrChargeEffect
- jr .notFlyOrChargeEffect
-.flyOrChargeEffect
- xor a
- ld [wAnimationType], a
- ld a, STATUS_AFFECTED_ANIM
- call PlayMoveAnimation
-.notFlyOrChargeEffect
- ld hl, ExecuteEnemyMoveDone
- jp .enemyReturnToHL ; if using a two-turn move, enemy needs to recharge the first turn
-.checkIfUsingBide
- ld hl, wEnemyBattleStatus1
- bit StoringEnergy, [hl] ; is mon using bide?
- jr z, .checkIfThrashingAbout
- xor a
- ld [wEnemyMoveNum], a
- ld hl, wDamage
- ld a, [hli]
- ld b, a
- ld c, [hl]
- ld hl, wEnemyBideAccumulatedDamage + 1
- ld a, [hl]
- add c ; accumulate damage taken
- ld [hld], a
- ld a, [hl]
- adc b
- ld [hl], a
- ld hl, wEnemyNumAttacksLeft
- dec [hl] ; did Bide counter hit 0?
- jr z, .unleashEnergy
- ld hl, ExecuteEnemyMoveDone
- jp .enemyReturnToHL ; unless mon unleashes energy, can't move this turn
-.unleashEnergy
- ld hl, wEnemyBattleStatus1
- res StoringEnergy, [hl] ; not using bide any more
- ld hl, UnleashedEnergyText
- call PrintText
- ld a, $1
- ld [wEnemyMovePower], a
- ld hl, wEnemyBideAccumulatedDamage + 1
- ld a, [hld]
- add a
- ld b, a
- ld [wDamage + 1], a
- ld a, [hl]
- rl a ; double the damage
- ld [wDamage], a
- or b
- jr nz, .next
- ld a, $1
- ld [wMoveMissed], a
-.next
- xor a
- ld [hli], a
- ld [hl], a
- ld a, BIDE
- ld [wEnemyMoveNum], a
- call SwapPlayerAndEnemyLevels
- ld hl, handleIfEnemyMoveMissed ; skip damage calculation, DecrementPP and MoveHitTest
- jp .enemyReturnToHL
-.checkIfThrashingAbout
- bit ThrashingAbout, [hl] ; is mon using thrash or petal dance?
- jr z, .checkIfUsingMultiturnMove
- ld a, THRASH
- ld [wEnemyMoveNum], a
- ld hl, ThrashingAboutText
- call PrintText
- ld hl, wEnemyNumAttacksLeft
- dec [hl] ; did Thrashing About counter hit 0?
- ld hl, EnemyCalcMoveDamage ; skip DecrementPP
- jp nz, .enemyReturnToHL
- push hl
- ld hl, wEnemyBattleStatus1
- res ThrashingAbout, [hl] ; mon is no longer using thrash or petal dance
- set Confused, [hl] ; mon is now confused
- call BattleRandom
- and $3
- inc a
- inc a ; confused for 2-5 turns
- ld [W_ENEMYCONFUSEDCOUNTER], a
- pop hl ; skip DecrementPP
- jp .enemyReturnToHL
-.checkIfUsingMultiturnMove
- bit UsingTrappingMove, [hl] ; is mon using multi-turn move?
- jp z, .checkIfUsingRage
- ld hl, AttackContinuesText
- call PrintText
- ld hl, wEnemyNumAttacksLeft
- dec [hl] ; did multi-turn move end?
- ld hl, GetEnemyAnimationType ; if it didn't, skip damage calculation (deal damage equal to last hit),
- ; DecrementPP and MoveHitTest
- jp nz, .enemyReturnToHL
- jp .enemyReturnToHL
-.checkIfUsingRage
- ld a, [wEnemyBattleStatus2]
- bit UsingRage, a ; is mon using rage?
- jp z, .checkEnemyStatusConditionsDone ; if we made it this far, mon can move normally this turn
- ld a, RAGE
- ld [wd11e], a
- call GetMoveName
- call CopyStringToCF4B
- xor a
- ld [wEnemyMoveEffect], a
- ld hl, EnemyCanExecuteMove
- jp .enemyReturnToHL
-.enemyReturnToHL
- xor a ; set Z flag
- ret
-.checkEnemyStatusConditionsDone
- ld a, $1
- and a ; clear Z flag
- ret
-
-GetCurrentMove: ; 3ec44 (f:6c44)
- ld a, [H_WHOSETURN]
- and a
- jp z, .player
- ld de, wEnemyMoveNum
- ld a, [wEnemySelectedMove]
- jr .selected
-.player
- ld de, wPlayerMoveNum
- ld a, [wFlags_D733]
- bit BIT_TEST_BATTLE, a
- ld a, [wTestBattlePlayerSelectedMove]
- jr nz, .selected
- ld a, [wPlayerSelectedMove]
-.selected
- ld [wd0b5], a
- dec a
- ld hl, Moves
- ld bc, MoveEnd - Moves
- call AddNTimes
- ld a, BANK(Moves)
- call FarCopyData
-
- ld a, BANK(MoveNames)
- ld [wPredefBank], a
- ld a, MOVE_NAME
- ld [wNameListType], a
- call GetName
- ld de, wcd6d
- jp CopyStringToCF4B
-
-LoadEnemyMonData: ; 3ec87 (f:6c87)
- ld a, [wLinkState]
- cp LINK_STATE_BATTLING
- jp z, LoadEnemyMonFromParty
- ld a, [wEnemyMonSpecies2]
- ld [wEnemyMonSpecies], a
- ld [wd0b5], a
- call GetMonHeader
- ld a, [wEnemyBattleStatus3]
- bit Transformed, a ; is enemy mon transformed?
- ld hl, wTransformedEnemyMonOriginalDVs ; original DVs before transforming
- ld a, [hli]
- ld b, [hl]
- jr nz, .storeDVs
- ld a, [wIsInBattle]
- cp $2 ; is it a trainer battle?
-; fixed DVs for trainer mon
- ld a, $98
- ld b, $88
- jr z, .storeDVs
-; random DVs for wild mon
- call BattleRandom
- ld b, a
- call BattleRandom
-.storeDVs
- ld hl, wEnemyMonDVs
- ld [hli], a
- ld [hl], b
- ld de, wEnemyMonLevel
- ld a, [wCurEnemyLVL]
- ld [de], a
- inc de
- ld b, $0
- ld hl, wEnemyMonHP
- push hl
- call CalcStats
- pop hl
- ld a, [wIsInBattle]
- cp $2 ; is it a trainer battle?
- jr z, .copyHPAndStatusFromPartyData
- ld a, [wEnemyBattleStatus3]
- bit Transformed, a ; is enemy mon transformed?
- jr nz, .copyTypes ; if transformed, jump
-; if it's a wild mon and not transformed, init the current HP to max HP and the status to 0
- ld a, [wEnemyMonMaxHP]
- ld [hli], a
- ld a, [wEnemyMonMaxHP+1]
- ld [hli], a
- xor a
- inc hl
- ld [hl], a ; init status to 0
- jr .copyTypes
-; if it's a trainer mon, copy the HP and status from the enemy party data
-.copyHPAndStatusFromPartyData
- ld hl, wEnemyMon1HP
- ld a, [wWhichPokemon]
- ld bc, wEnemyMon2 - wEnemyMon1
- call AddNTimes
- ld a, [hli]
- ld [wEnemyMonHP], a
- ld a, [hli]
- ld [wEnemyMonHP + 1], a
- ld a, [wWhichPokemon]
- ld [wEnemyMonPartyPos], a
- inc hl
- ld a, [hl]
- ld [wEnemyMonStatus], a
- jr .copyTypes
-.copyTypes
- ld hl, wMonHTypes
- ld de, wEnemyMonType
- ld a, [hli] ; copy type 1
- ld [de], a
- inc de
- ld a, [hli] ; copy type 2
- ld [de], a
- inc de
- ld a, [hli] ; copy catch rate
- ld [de], a
- inc de
- ld a, [wIsInBattle]
- cp $2 ; is it a trainer battle?
- jr nz, .copyStandardMoves
-; if it's a trainer battle, copy moves from enemy party data
- ld hl, wEnemyMon1Moves
- ld a, [wWhichPokemon]
- ld bc, wEnemyMon2 - wEnemyMon1
- call AddNTimes
- ld bc, NUM_MOVES
- call CopyData
- jr .loadMovePPs
-.copyStandardMoves
-; for a wild mon, first copy default moves from the mon header
- ld hl, wMonHMoves
- ld a, [hli]
- ld [de], a
- inc de
- ld a, [hli]
- ld [de], a
- inc de
- ld a, [hli]
- ld [de], a
- inc de
- ld a, [hl]
- ld [de], a
- dec de
- dec de
- dec de
- xor a
- ld [wLearningMovesFromDayCare], a
- predef WriteMonMoves ; get moves based on current level
-.loadMovePPs
- ld hl, wEnemyMonMoves
- ld de, wEnemyMonPP - 1
- predef LoadMovePPs
- ld hl, wMonHBaseStats
- ld de, wEnemyMonBaseStats
- ld b, NUM_STATS
-.copyBaseStatsLoop
- ld a, [hli]
- ld [de], a
- inc de
- dec b
- jr nz, .copyBaseStatsLoop
- ld hl, wMonHCatchRate
- ld a, [hli]
- ld [de], a
- inc de
- ld a, [hl] ; base exp
- ld [de], a
- ld a, [wEnemyMonSpecies2]
- ld [wd11e], a
- call GetMonName
- ld hl, wcd6d
- ld de, wEnemyMonNick
- ld bc, NAME_LENGTH
- call CopyData
- ld a, [wEnemyMonSpecies2]
- ld [wd11e], a
- predef IndexToPokedex
- ld a, [wd11e]
- dec a
- ld c, a
- ld b, FLAG_SET
- ld hl, wPokedexSeen
- predef FlagActionPredef ; mark this mon as seen in the pokedex
- ld hl, wEnemyMonLevel
- ld de, wEnemyMonUnmodifiedLevel
- ld bc, 1 + NUM_STATS * 2
- call CopyData
- ld a, $7 ; default stat mod
- ld b, NUM_STAT_MODS ; number of stat mods
- ld hl, wEnemyMonStatMods
-.statModLoop
- ld [hli], a
- dec b
- jr nz, .statModLoop
- ret
-
-; calls BattleTransition to show the battle transition animation and initializes some battle variables
-DoBattleTransitionAndInitBattleVariables: ; 3edb8 (f:6db8)
- ld a, [wLinkState]
- cp LINK_STATE_BATTLING
- jr nz, .next
-; link battle
- xor a
- ld [wMenuJoypadPollCount], a
- callab DisplayLinkBattleVersusTextBox
- ld a, $1
- ld [wUpdateSpritesEnabled], a
- call ClearScreen
-.next
- call DelayFrame
- predef BattleTransition
- callab LoadHudAndHpBarAndStatusTilePatterns
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- ld a, $ff
- ld [wUpdateSpritesEnabled], a
- call ClearSprites
- call ClearScreen
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- ld [hWY], a
- ld [rWY], a
- ld [hTilesetType], a
- ld hl, wPlayerStatsToDouble
- ld [hli], a
- ld [hli], a
- ld [hli], a
- ld [hli], a
- ld [hl], a
- ld [wPlayerDisabledMove], a
- ret
-
-; swaps the level values of the BattleMon and EnemyMon structs
-SwapPlayerAndEnemyLevels: ; 3ee07 (f:6e07)
- push bc
- ld a, [wBattleMonLevel]
- ld b, a
- ld a, [wEnemyMonLevel]
- ld [wBattleMonLevel], a
- ld a, b
- ld [wEnemyMonLevel], a
- pop bc
- ret
-
-; loads either red back pic or old man back pic
-; also writes OAM data and loads tile patterns for the Red or Old Man back sprite's head
-; (for use when scrolling the player sprite and enemy's silhouettes on screen)
-LoadPlayerBackPic: ; 3ee18 (f:6e18)
- ld a, [wBattleType]
- ld de, OldManPic
- cp OLD_MAN_BATTLE ; is it the old man tutorial?
- jr z, .next
- ld de, ProfOakPicBack
- cp STARTER_PIKACHU_BATTLE ; is it the pikachu battle at the beginning of the game?
- jr z, .next
- ld de, RedPicBack
-.next
- ld a, BANK(RedPicBack)
- call UncompressSpriteFromDE
- predef ScaleSpriteByTwo
- ld hl, wOAMBuffer
- xor a
- ld [hOAMTile], a ; initial tile number
- ld b, $7 ; 7 columns
- ld e, $a0 ; X for the left-most column
-.loop ; each loop iteration writes 3 OAM entries in a vertical column
- ld c, $3 ; 3 tiles per column
- ld d, $38 ; Y for the top of each column
-.innerLoop ; each loop iteration writes 1 OAM entry in the column
- ld [hl], d ; OAM Y
- inc hl
- ld [hl], e ; OAM X
- ld a, $8 ; height of tile
- add d ; increase Y by height of tile
- ld d, a
- inc hl
- ld a, [hOAMTile]
- ld [hli], a ; OAM tile number
- inc a ; increment tile number
- ld [hOAMTile], a
- ld a, $2
- ld [hl], a
- inc hl
- dec c
- jr nz, .innerLoop
- ld a, [hOAMTile]
- add $4 ; increase tile number by 4
- ld [hOAMTile], a
- ld a, $8 ; width of tile
- add e ; increase X by width of tile
- ld e, a
- dec b
- jr nz, .loop
- ld de, vBackPic
- call InterlaceMergeSpriteBuffers
- ld a, $0
- call SwitchSRAMBankAndLatchClockData
- ld hl, vSprites
- ld de, S_SPRITEBUFFER1
- ld a, [H_LOADEDROMBANK]
- ld b, a
- ld c, 7 * 7
- call CopyVideoData
- call PrepareRTCDataAndDisableSRAM
- ld a, $31
- ld [hStartTileID], a
- coord hl, 1, 5
- predef_jump CopyUncompressedPicToTilemap
-
-; does nothing since no stats are ever selected (barring glitches)
-DoubleOrHalveSelectedStats: ; 3ee8e (f:6e8e)
- callab DoubleSelectedStats
- jpab HalveSelectedStats
-
-ScrollTrainerPicAfterBattle: ; 3ee9e (f:6e9e)
- jpab _ScrollTrainerPicAfterBattle
-
-ApplyBurnAndParalysisPenaltiesToPlayer: ; 3eea6 (f:6ea6)
- ld a, $1
- jr ApplyBurnAndParalysisPenalties
-
-ApplyBurnAndParalysisPenaltiesToEnemy: ; 3eeaa (f:6eaa)
- xor a
-
-ApplyBurnAndParalysisPenalties: ; 3eeab (f:6eab)
- ld [H_WHOSETURN], a
- call QuarterSpeedDueToParalysis
- jp HalveAttackDueToBurn
-
-QuarterSpeedDueToParalysis: ; 3eeb3 (f:6eb3)
- ld a, [H_WHOSETURN]
- and a
- jr z, .playerTurn
-.enemyTurn ; quarter the player's speed
- ld a, [wBattleMonStatus]
- and 1 << PAR
- ret z ; return if player not paralysed
- ld hl, wBattleMonSpeed + 1
- ld a, [hld]
- ld b, a
- ld a, [hl]
- srl a
- rr b
- srl a
- rr b
- ld [hli], a
- or b
- jr nz, .storePlayerSpeed
- ld b, 1 ; give the player a minimum of at least one speed point
-.storePlayerSpeed
- ld [hl], b
- ret
-.playerTurn ; quarter the enemy's speed
- ld a, [wEnemyMonStatus]
- and 1 << PAR
- ret z ; return if enemy not paralysed
- ld hl, wEnemyMonSpeed + 1
- ld a, [hld]
- ld b, a
- ld a, [hl]
- srl a
- rr b
- srl a
- rr b
- ld [hli], a
- or b
- jr nz, .storeEnemySpeed
- ld b, 1 ; give the enemy a minimum of at least one speed point
-.storeEnemySpeed
- ld [hl], b
- ret
-
-HalveAttackDueToBurn: ; 3eeef (f:6eef)
- ld a, [H_WHOSETURN]
- and a
- jr z, .playerTurn
-.enemyTurn ; halve the player's attack
- ld a, [wBattleMonStatus]
- and 1 << BRN
- ret z ; return if player not burnt
- ld hl, wBattleMonAttack + 1
- ld a, [hld]
- ld b, a
- ld a, [hl]
- srl a
- rr b
- ld [hli], a
- or b
- jr nz, .storePlayerAttack
- ld b, 1 ; give the player a minimum of at least one attack point
-.storePlayerAttack
- ld [hl], b
- ret
-.playerTurn ; halve the enemy's attack
- ld a, [wEnemyMonStatus]
- and 1 << BRN
- ret z ; return if enemy not burnt
- ld hl, wEnemyMonAttack + 1
- ld a, [hld]
- ld b, a
- ld a, [hl]
- srl a
- rr b
- ld [hli], a
- or b
- jr nz, .storeEnemyAttack
- ld b, 1 ; give the enemy a minimum of at least one attack point
-.storeEnemyAttack
- ld [hl], b
- ret
-
-CalculateModifiedStats: ; 3ef25 (f:6f25)
- ld c, 0
-.loop
- call CalculateModifiedStat
- inc c
- ld a, c
- cp NUM_STATS - 1
- jr nz, .loop
- ret
-
-; calculate modified stat for stat c (0 = attack, 1 = defense, 2 = speed, 3 = special)
-CalculateModifiedStat: ; 3ef31 (f:6f31)
- push bc
- push bc
- ld a, [wCalculateWhoseStats]
- and a
- ld a, c
- ld hl, wBattleMonAttack
- ld de, wPlayerMonUnmodifiedAttack
- ld bc, wPlayerMonStatMods
- jr z, .next
- ld hl, wEnemyMonAttack
- ld de, wEnemyMonUnmodifiedAttack
- ld bc, wEnemyMonStatMods
-.next
- add c
- ld c, a
- jr nc, .noCarry1
- inc b
-.noCarry1
- ld a, [bc]
- pop bc
- ld b, a
- push bc
- sla c
- ld b, 0
- add hl, bc
- ld a, c
- add e
- ld e, a
- jr nc, .noCarry2
- inc d
-.noCarry2
- pop bc
- push hl
- ld hl, StatModifierRatios
- dec b
- sla b
- ld c, b
- ld b, 0
- add hl, bc
- xor a
- ld [H_MULTIPLICAND], a
- ld a, [de]
- ld [H_MULTIPLICAND + 1], a
- inc de
- ld a, [de]
- ld [H_MULTIPLICAND + 2], a
- ld a, [hli]
- ld [H_MULTIPLIER], a
- call Multiply
- ld a, [hl]
- ld [H_DIVISOR], a
- ld b, $4
- call Divide
- pop hl
- ld a, [H_DIVIDEND + 3]
- sub 999 % $100
- ld a, [H_DIVIDEND + 2]
- sbc 999 / $100
- jp c, .storeNewStatValue
-; cap the stat at 999
- ld a, 999 / $100
- ld [H_DIVIDEND + 2], a
- ld a, 999 % $100
- ld [H_DIVIDEND + 3], a
-.storeNewStatValue
- ld a, [H_DIVIDEND + 2]
- ld [hli], a
- ld b, a
- ld a, [H_DIVIDEND + 3]
- ld [hl], a
- or b
- jr nz, .done
- inc [hl] ; if the stat is 0, bump it up to 1
-.done
- pop bc
- ret
-
-ApplyBadgeStatBoosts: ; 3efa5 (f:6fa5)
- ld a, [wLinkState]
- cp LINK_STATE_BATTLING
- ret z ; return if link battle
- ld a, [wObtainedBadges]
- ld b, a
- ld hl, wBattleMonAttack
- ld c, $4
-; the boost is applied for badges whose bit position is even
-; the order of boosts matches the order they are laid out in RAM
-; Boulder (bit 0) - attack
-; Thunder (bit 2) - defense
-; Soul (bit 4) - speed
-; Volcano (bit 6) - special
-.loop
- srl b
- call c, .applyBoostToStat
- inc hl
- inc hl
- srl b
- dec c
- jr nz, .loop
- ret
-
-; multiply stat at hl by 1.125
-; cap stat at 999
-.applyBoostToStat
- ld a, [hli]
- ld d, a
- ld e, [hl]
- srl d
- rr e
- srl d
- rr e
- srl d
- rr e
- ld a, [hl]
- add e
- ld [hld], a
- ld a, [hl]
- adc d
- ld [hli], a
- ld a, [hld]
- sub 999 % $100
- ld a, [hl]
- sbc 999 / $100
- ret c
- ld a, 999 / $100
- ld [hli], a
- ld a, 999 % $100
- ld [hld], a
- ret
-
-LoadHudAndHpBarAndStatusTilePatterns: ; 3efe4 (f:6fe4)
- call LoadHpBarAndStatusTilePatterns
-
-LoadHudTilePatterns: ; 3efe7 (f:6fe7)
- ld a, [rLCDC]
- add a ; is LCD disabled?
- jr c, .lcdEnabled
-.lcdDisabled
- ld hl, BattleHudTiles1
- ld de, vChars2 + $6d0
- ld bc, BattleHudTiles1End - BattleHudTiles1
- ld a, BANK(BattleHudTiles1)
- call FarCopyDataDouble
- ld hl, BattleHudTiles2
- ld de, vChars2 + $730
- ld bc, BattleHudTiles3End - BattleHudTiles2
- ld a, BANK(BattleHudTiles2)
- jp FarCopyDataDouble
-.lcdEnabled
- ld de, BattleHudTiles1
- ld hl, vChars2 + $6d0
- lb bc, BANK(BattleHudTiles1), (BattleHudTiles1End - BattleHudTiles1) / $8
- call CopyVideoDataDouble
- ld de, BattleHudTiles2
- ld hl, vChars2 + $730
- lb bc, BANK(BattleHudTiles2), (BattleHudTiles3End - BattleHudTiles2) / $8
- jp CopyVideoDataDouble
-
-PrintEmptyString: ; 3f020 (f:7020)
- ld hl, .emptyString
- jp PrintText
-.emptyString
- db "@"
-
-
-BattleRandom: ; 3f027 (f:7027)
-; Link battles use a shared PRNG.
-
- ld a, [wLinkState]
- cp LINK_STATE_BATTLING
- jp nz, Random
-
- push hl
- push bc
- ld a, [wLinkBattleRandomNumberListIndex]
- ld c, a
- ld b, 0
- ld hl, wLinkBattleRandomNumberList
- add hl, bc
- inc a
- ld [wLinkBattleRandomNumberListIndex], a
- cp 9
- ld a, [hl]
- pop bc
- pop hl
- ret c
-
-; if we picked the last seed, we need to recalculate the nine seeds
- push hl
- push bc
- push af
-
-; point to seed 0 so we pick the first number the next time
- xor a
- ld [wLinkBattleRandomNumberListIndex], a
-
- ld hl, wLinkBattleRandomNumberList
- ld b, 9
-.loop
- ld a, [hl]
- ld c, a
-; multiply by 5
- add a
- add a
- add c
-; add 1
- inc a
- ld [hli], a
- dec b
- jr nz, .loop
-
- pop af
- pop bc
- pop hl
- ret
-
-
-HandleExplodingAnimation: ; 3f05f (f:705f)
- ld a, [H_WHOSETURN]
- and a
- ld hl, wEnemyMonType1
- ld de, wEnemyBattleStatus1
- ld a, [wPlayerMoveNum]
- jr z, .player
- ld hl, wBattleMonType1
- ld de, wEnemyBattleStatus1
- ld a, [wEnemyMoveNum]
-.player
- cp SELFDESTRUCT
- jr z, .isExplodingMove
- cp EXPLOSION
- ret nz
-.isExplodingMove
- ld a, [de]
- bit Invulnerable, a ; fly/dig
- ret nz
- ld a, [hli]
- cp GHOST
- ret z
- ld a, [hl]
- cp GHOST
- ret z
- ld a, [wMoveMissed]
- and a
- ret nz
- ld a, 5
- ld [wAnimationType], a
-
-PlayMoveAnimation: ; 3f093 (f:7093)
- ld [wAnimationID],a
- call Delay3
- predef MoveAnimation
- callab Func_78e98
- ret
-
-JumpMoveEffect: ; 3f0a7 (f:70a7)
- call _JumpMoveEffect
- ld b, $1
- ret
-
-_JumpMoveEffect: ; 3f0ad (f:70ad)
- ld a, [H_WHOSETURN]
- and a
- ld a, [wPlayerMoveEffect]
- jr z, .next1
- ld a, [wEnemyMoveEffect]
-.next1
- dec a ; subtract 1, there is no special effect for 00
- add a ; x2, 16bit pointers
- ld hl, MoveEffectPointerTable
- ld b, 0
- ld c, a
- add hl, bc
- ld a, [hli]
- ld h, [hl]
- ld l, a
- jp [hl] ; jump to special effect handler
-
-MoveEffectPointerTable: ; 3f0c5 (f:70c5)
- dr $3f0c5,$3f3de
-StatModifierUpEffect: ; 3f3de (f:73de)
- dr $3f3de,$3f681
-StatModifierRatios: ; 3f681 (f:7681)
- dr $3f681,$3fb2e
-PrintButItFailedText_: ; 3fb2e (f:7b2e)
- dr $3fb2e,$3fb39
-PrintDidntAffectText: ; 3fb39 (f:7b39)
- dr $3fb39,$3fb49
-PrintMayNotAttackText: ; 3fb49 (f:7b49)
- dr $3fb49,$3fb54
-CheckTargetSubstitute: ; 3fb54 (f:7b54)
- dr $3fb54,$3fb83
-PlayCurrentMoveAnimation: ; 3fb83 (f:7b83)
- dr $3fb83,$3ff00 \ No newline at end of file
diff --git a/yellow/main.asm b/yellow/main.asm
index 96e1a2ac..b528f3bb 100755
--- a/yellow/main.asm
+++ b/yellow/main.asm
@@ -4027,7 +4027,7 @@ INCLUDE "engine/evos_moves.asm"
SECTION "bank0F",ROMX,BANK[$0F]
-INCLUDE "engine/battle/core_.asm"
+INCLUDE "engine/battle/core.asm"
SECTION "bank10",ROMX,BANK[$10]