ref: 01095f77943b9a7fd0432a6ad2e5c18f2d3e66ae
parent: 21f306d6532843172b133ab407ccd1da7a37c6bb
parent: d3bf8bca5e7e6e2ccf98241bee950d9cccf2994e
author: Daniel Harding <corrnondacqb@yahoo.com>
date: Thu Jan 22 16:28:43 EST 2015
Merge pull request #67 from xCrystal/master Lots of commentary in engine/battle/core.asm
--- a/engine/battle/core.asm
+++ b/engine/battle/core.asm
@@ -1,7 +1,7 @@
BattleCore:
; These are move effects (second value from the Moves table in bank $E).
-EffectsArray1: ; 3c000 (f:4000)
+ResidualEffects1: ; 3c000 (f:4000)
db CONVERSION_EFFECT
db HAZE_EFFECT
db SWITCH_AND_TELEPORT_EFFECT
@@ -19,14 +19,14 @@
db LEECH_SEED_EFFECT
db SPLASH_EFFECT
db -1
-EffectsArray2: ; 3c011 (f:4011)
+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
-EffectsArray3: ; 3c014 (f:4014)
-; non-damaging, stat‐affecting or status‐causing moves?
+ResidualEffects2: ; 3c014 (f:4014)
+; stat-affecting moves, sleep-inflicting moves, and Bide
; e.g., Meditate, Bide, Hypnosis
db $01
db ATTACK_UP1_EFFECT
@@ -56,7 +56,7 @@
db ACCURACY_DOWN2_EFFECT
db EVASION_DOWN2_EFFECT
db -1
-EffectsArray4: ; 3c030 (f:4030)
+AlwaysHappenSideEffects: ; 3c030 (f:4030)
; Attacks that aren't finished after they faint the opponent.
db DRAIN_HP_EFFECT
db EXPLODE_EFFECT
@@ -69,7 +69,10 @@
db TWINEEDLE_EFFECT
db RAGE_EFFECT
db -1
-EffectsArray5: ; 3c03b (f:403b)
+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
@@ -85,8 +88,8 @@
db JUMP_KICK_EFFECT
db RECOIL_EFFECT
; fallthrough to Next EffectsArray
-EffectsArray5B: ; 3c049 (f:4049)
-; moves that prevent the player from switching moves?
+SpecialEffectsCont: ; 3c049 (f:4049)
+; damaging moves whose effect is executed prior to damage calculation
db THRASH_PETAL_DANCE_EFFECT
db TRAPPING_EFFECT
db -1
@@ -405,7 +408,7 @@
ld a, [W_ENEMYBATTSTATUS1]
bit 5, 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 select a move
+; 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
@@ -449,7 +452,7 @@
ld b, 0
add hl, bc
ld a, [hl]
- cp METRONOME
+ cp METRONOME ; a MIRROR MOVE check is missing, might lead to a desync in link battles when combined with multi-turn moves
jr nz, .asm_3c2dd
ld [wPlayerSelectedMove], a
.asm_3c2dd
@@ -485,7 +488,7 @@
jr z, .speedEqual
jr nc, .playerMovesFirst ; if player is faster
jr .enemyMovesFirst ; if enemy is faster
-.speedEqual
+.speedEqual ; 50/50 chance for both players
ld a, [$ffaa]
cp $2
jr z, .invertOutcome
@@ -509,7 +512,7 @@
ret nz ; if so, return
ld a, b
and a
- jp z, HandlePlayerMonFainted
+ jp z, HandlePlayerMonFainted
.AIActionUsedEnemyFirst
call HandlePoisonBurnLeechSeed
jp z, HandleEnemyMonFainted
@@ -702,6 +705,7 @@
ret
; adds bc to enemy HP
+; bc isn't updated if HP substracted was capped to prevent overkill
HandlePoisonBurnLeechSeed_IncreaseEnemyHP: ; 3c4a3 (f:44a3)
push hl
ld hl, wEnemyMonMaxHP
@@ -833,7 +837,7 @@
res 2, [hl]
xor a
ld [W_NUMHITS], a
- ld hl, wd065 ; enemy statuses
+ ld hl, wd065 ; clear enemy statuses
ld [hli], a
ld [hli], a
ld [hli], a
@@ -1358,7 +1362,7 @@
; don't change wPartyGainExpFlags or wPartyFoughtCurrentEnemyFlags
EnemySendOutFirstMon: ; 3c92a (f:492a)
xor a
- ld hl,wd065
+ ld hl,wd065 ; clear enemy statuses
ld [hli],a
ld [hli],a
ld [hli],a
@@ -3105,10 +3109,10 @@
ExecutePlayerMove: ; 3d65e (f:565e)
xor a
- ld [H_WHOSETURN], a
+ ld [H_WHOSETURN], a ; set player's turn
ld a, [wPlayerSelectedMove]
inc a
- jp z, Func_3d80a
+ jp z, ExecutePlayerMoveDone ; for selected move = FF, skip most of player's turn
xor a
ld [W_MOVEMISSED], a
ld [wcced], a
@@ -3117,9 +3121,9 @@
ld [wd05b], a
ld a, [wcd6a]
and a
- jp nz, Func_3d80a
+ jp nz, ExecutePlayerMoveDone
call PrintGhostText
- jp z, Func_3d80a
+ jp z, ExecutePlayerMoveDone
call CheckPlayerStatusConditions
jr nz, .asm_3d68a
jp [hl]
@@ -3126,10 +3130,10 @@
.asm_3d68a
call GetCurrentMove
ld hl, W_PLAYERBATTSTATUS1
- bit 4, [hl]
- jr nz, asm_3d6a9
+ bit 4, [hl] ; charging up for attack
+ jr nz, PlayerCanExecuteChargingMove
call CheckForDisobedience
- jp z, Func_3d80a
+ jp z, ExecutePlayerMoveDone
Func_3d69a: ; 3d69a (f:569a)
ld a, [W_PLAYERMOVEEFFECT]
@@ -3137,14 +3141,16 @@
jp z, JumpMoveEffect
cp FLY_EFFECT
jp z, JumpMoveEffect
- jr asm_3d6b0
+ jr PlayerCanExecuteMove
; in-battle stuff
-asm_3d6a9: ; 3d6a9 (f:56a9)
+PlayerCanExecuteChargingMove: ; 3d6a9 (f:56a9)
ld hl,W_PLAYERBATTSTATUS1
- res 4,[hl]
+ res 4,[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 6,[hl]
-asm_3d6b0: ; 3d6b0 (f:56b0)
+PlayerCanExecuteMove: ; 3d6b0 (f:56b0)
call PrintMonName1Text
ld hl,DecrementPP
ld de,wPlayerSelectedMove ; pointer to the move just used
@@ -3151,30 +3157,32 @@
ld b,BANK(DecrementPP)
call Bankswitch
ld a,[W_PLAYERMOVEEFFECT] ; effect of the move just used
- ld hl,EffectsArray1
+ ld hl,ResidualEffects1
ld de,1
call IsInArray
- jp c,JumpMoveEffect
+ jp c,JumpMoveEffect ; ResidualEffects1 moves skip damage calculation and accuracy tests
+ ; unless executed as part of their exclusive effect functions
ld a,[W_PLAYERMOVEEFFECT]
- ld hl,EffectsArray5B
+ ld hl,SpecialEffectsCont
ld de,1
call IsInArray
- call c,JumpMoveEffect
-asm_3d6dc: ; 3d6dc (f:56dc)
+ call c,JumpMoveEffect ; execute the effects of SpecialEffectsCont moves (e.g. Wrap, Thrash) but don't skip anything
+CalcMoveDamage: ; 3d6dc (f:56dc)
ld a,[W_PLAYERMOVEEFFECT]
- ld hl,EffectsArray2
+ ld hl,SetDamageEffects
ld de,1
- call IsInArray
- jp c,.asm_3d702
+ call IsInArray
+ jp c,.moveHitTest ; SetDamageEffects moves (e.g. Seismic Toss and Super Fang) skip damage calculation
call CriticalHitTest
call HandleCounterMove
jr z,asm_3d705
call GetDamageVarsForPlayerAttack
call CalculateDamage
- jp z,asm_3d74b
+ jp z,asm_3d74b ; 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
-.asm_3d702
+.moveHitTest
call MoveHitTest
asm_3d705
ld a,[W_MOVEMISSED]
@@ -3181,9 +3189,9 @@
and a
jr z,asm_3d714
ld a,[W_PLAYERMOVEEFFECT]
- sub a,7
- jr z,asm_3d71e
- jr asm_3d74b
+ sub a,7 ; Explosion effect
+ jr z,asm_3d71e ; don't play any animation if the move missed, unless it was EXPLODE_EFFECT
+ jr asm_3d74b
asm_3d714
ld a,[W_PLAYERMOVEEFFECT]
and a
@@ -3190,7 +3198,7 @@
ld a,4
jr z,asm_3d71e
ld a,5
-asm_3d71e
+asm_3d71e
push af
ld a,[W_PLAYERBATTSTATUS2]
bit 4,a
@@ -3201,7 +3209,7 @@
ld [wcc5b],a
ld a,[W_PLAYERMOVENUM]
call PlayMoveAnimation
- call Func_3eed3
+ call HandleExplodingAnimation
call DrawPlayerHUDAndHPBar
ld a,[W_PLAYERBATTSTATUS2]
bit 4,a
@@ -3208,96 +3216,99 @@
ld hl,Func_79771
ld b,BANK(Func_79771)
call nz,Bankswitch
- jr asm_3d766
+ jr MirrorMoveCheck
asm_3d74b
ld c,$1E
call DelayFrames
ld a,[W_PLAYERMOVEEFFECT]
cp a,FLY_EFFECT
- jr z,.next5
+ jr z,.playAnim
cp a,CHARGE_EFFECT
- jr z,.next5
- jr asm_3d766
-.next5
+ jr z,.playAnim
+ jr MirrorMoveCheck
+.playAnim
xor a
ld [wcc5b],a
ld a,STATUS_AFFECTED_ANIM
call PlayMoveAnimation
-asm_3d766
+MirrorMoveCheck
ld a,[W_PLAYERMOVEEFFECT]
cp a,MIRROR_MOVE_EFFECT
- jr nz,.next6
+ jr nz,.metronomeCheck
call MirrorMoveCopyMove
- jp z,Func_3d80a
+ jp z,ExecutePlayerMoveDone
xor a
ld [wcced],a
- jp Func_3d69a
-.next6
+ jp Func_3d69a ; if Mirror Move was successful go back to damage calculation for copied move
+.metronomeCheck
cp a,METRONOME_EFFECT
- jr nz,.next7
+ jr nz,.next
call MetronomePickMove
- jp Func_3d69a
-.next7
+ jp Func_3d69a ; Go back to damage calculation for the move picked by Metronome
+.next
ld a,[W_PLAYERMOVEEFFECT]
- ld hl,EffectsArray3
+ ld hl,ResidualEffects2
ld de,1
call IsInArray
- jp c,JumpMoveEffect
+ jp c,JumpMoveEffect ; done here after executing effects of ResidualEffects2
ld a,[W_MOVEMISSED]
and a
- jr z,.next8
+ jr z,.moveDidNotMiss
call PrintMoveFailureText
ld a,[W_PLAYERMOVEEFFECT]
- cp a,EXPLODE_EFFECT
- jr z,.next9
- jp Func_3d80a
-.next8
+ 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 [wccf4],a
-.next9
+.notDone
ld a,[W_PLAYERMOVEEFFECT]
- ld hl,EffectsArray4
+ ld hl,AlwaysHappenSideEffects
ld de,1
call IsInArray
- call c,JumpMoveEffect
+ call c,JumpMoveEffect ; not done after executing effects of AlwaysHappenSideEffects
ld hl,wEnemyMonHP
ld a,[hli]
ld b,[hl]
or b
- ret z
+ ret z ; don't do anything else if the enemy fainted
call HandleBuildingRage
ld hl,W_PLAYERBATTSTATUS1
bit 2,[hl]
- jr z,.next10
+ jr z,.executeOtherEffects
ld a,[wPlayerNumAttacksLeft]
dec a
ld [wPlayerNumAttacksLeft],a
- jp nz,asm_3d714
-
+ jp nz,asm_3d714 ; 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 2,[hl]
ld hl,MultiHitText
call PrintText
xor a
- ld [W_NUMHITS],a ; reset
-.next10
+ ld [W_NUMHITS],a
+.executeOtherEffects
ld a,[W_PLAYERMOVEEFFECT]
and a
- jp z,Func_3d80a
- ld hl,EffectsArray5
+ jp z,ExecutePlayerMoveDone
+ ld hl,SpecialEffects
ld de,1
call IsInArray
- call nc,JumpMoveEffect
- jp Func_3d80a
+ call nc,JumpMoveEffect ; move effects not included in SpecialEffects, which are the effects not covered yet.
+ ; the only exception is Rage, whose effect will be executed for a second time (although it's irrelevant)
+ ; includes some side effects and all non-volatile status effects but sleep.
+ ; responsible for executing Twineedle's second effect (poison)
+ jp ExecutePlayerMoveDone
MultiHitText: ; 3d805 (f:5805)
TX_FAR _MultiHitText
db "@"
-Func_3d80a: ; 3d80a (f:580a)
+ExecutePlayerMoveDone: ; 3d80a (f:580a)
xor a
ld [wcd6a],a
ld b,1
@@ -3375,8 +3386,8 @@
.sleepDone
xor a
ld [wccf1],a
- ld hl,Func_3d80a
- jp .CannotUseMove
+ ld hl,ExecutePlayerMoveDone ; player can't move this turn
+ jp .returnToHL
.FrozenCheck
bit FRZ,[hl] ; frozen?
@@ -3385,37 +3396,37 @@
call PrintText
xor a
ld [wccf1],a
- ld hl,Func_3d80a
- jp .CannotUseMove
+ ld hl,ExecutePlayerMoveDone ; player can't move this turn
+ jp .returnToHL
.HeldInPlaceCheck
ld a,[W_ENEMYBATTSTATUS1]
- bit 5,a
+ bit 5,a ; is enemy using a mult-turn move like wrap?
jp z,.FlinchedCheck
ld hl,CantMoveText
call PrintText
- ld hl,Func_3d80a
- jp .CannotUseMove
+ ld hl,ExecutePlayerMoveDone ; player can't move this turn
+ jp .returnToHL
.FlinchedCheck
ld hl,W_PLAYERBATTSTATUS1
bit 3,[hl]
jp z,.HyperBeamCheck
- res 3,[hl]
+ res 3,[hl] ; reset player's flinch status
ld hl,FlinchedText
call PrintText
- ld hl,Func_3d80a
- jp .CannotUseMove
+ ld hl,ExecutePlayerMoveDone ; player can't move this turn
+ jp .returnToHL
.HyperBeamCheck
ld hl,W_PLAYERBATTSTATUS2
bit 5,[hl]
jr z,.AnyMoveDisabledCheck
- res 5,[hl]
+ res 5,[hl] ; reset player's recharge status
ld hl,MustRechargeText
call PrintText
- ld hl,Func_3d80a
- jp .CannotUseMove
+ ld hl,ExecutePlayerMoveDone ; player can't move this turn
+ jp .returnToHL
.AnyMoveDisabledCheck
ld hl,W_PLAYERDISABLEDMOVE
@@ -3424,7 +3435,7 @@
jr z,.ConfusedCheck
dec a
ld [hl],a
- and a,$F
+ and a,$F ; did Disable counter hit 0?
jr nz,.ConfusedCheck
ld [hl],a
ld [wccee],a
@@ -3433,13 +3444,13 @@
.ConfusedCheck
ld a,[W_PLAYERBATTSTATUS1]
- add a
+ add a ; is player confused?
jr nc,.TriedToUseDisabledMoveCheck
ld hl,wd06b
dec [hl]
jr nz,.IsConfused
ld hl,W_PLAYERBATTSTATUS1
- res 7,[hl]
+ res 7,[hl] ; if confused counter hit 0, reset confusion status
ld hl,ConfusedNoMoreText
call PrintText
jr .TriedToUseDisabledMoveCheck
@@ -3451,13 +3462,13 @@
ld a,CONF_ANIM - 1
call PlayMoveAnimation
call BattleRandom
- cp a,$80
+ cp a,$80 ; 50% chance to hurt itself
jr c,.TriedToUseDisabledMoveCheck
ld hl,W_PLAYERBATTSTATUS1
ld a,[hl]
- and a,$80 ; confused
+ and a,$80 ; if mon hurts itself, clear every other status from W_PLAYERBATTSTATUS1
ld [hl],a
- call PrintHurtItselfText
+ call HandleSelfConfusionDamage
jr .MonHurtItselfOrFullyParalysed
.TriedToUseDisabledMoveCheck
@@ -3468,8 +3479,8 @@
cp [hl]
jr nz,.ParalysisCheck
call PrintMoveIsDisabledText
- ld hl,Func_3d80a
- jp .CannotUseMove
+ ld hl,ExecutePlayerMoveDone ; if a disabled move was somehow selected, player can't move this turn
+ jp .returnToHL
.ParalysisCheck
ld hl,wBattleMonStatus
@@ -3476,7 +3487,7 @@
bit PAR,[hl]
jr z,.BideCheck
call BattleRandom
- cp a,$3F
+ cp a,$3F ; 25% to be fully paralyzed
jr nc,.BideCheck
ld hl,FullyParalyzedText
call PrintText
@@ -3484,7 +3495,7 @@
.MonHurtItselfOrFullyParalysed
ld hl,W_PLAYERBATTSTATUS1
ld a,[hl]
- and a,$CC ; clear bide, thrashing, charging up, and multi-turn moves such as warp
+ and a, %11001100 ; clear bide, thrashing, charging up, and multi-turn moves such as warp (redundant, already cleared)
ld [hl],a
ld a,[W_PLAYERMOVEEFFECT]
cp a,FLY_EFFECT
@@ -3499,8 +3510,8 @@
ld a,STATUS_AFFECTED_ANIM
call PlayMoveAnimation
.NotFlyOrChargeEffect
- ld hl,Func_3d80a
- jp .CannotUseMove
+ ld hl,ExecutePlayerMoveDone
+ jp .returnToHL ; if using a two-turn move, we need to recharge the first turn
.BideCheck
ld hl,W_PLAYERBATTSTATUS1
@@ -3514,16 +3525,16 @@
ld c,[hl]
ld hl,wd075
ld a,[hl]
- add c
+ add c ; acumulate damage taken
ld [hld],a
ld a,[hl]
adc b
ld [hl],a
ld hl,wPlayerNumAttacksLeft
- dec [hl]
+ dec [hl] ; did Bide counter hit 0?
jr z,.UnleashEnergy
- ld hl,Func_3d80a
- jp .CannotUseMove
+ ld hl,ExecutePlayerMoveDone
+ jp .returnToHL ; unless mon unleashes energy, can't move this turn
.UnleashEnergy
ld hl,W_PLAYERBATTSTATUS1
res 0,[hl] ; not using bide any more
@@ -3537,7 +3548,7 @@
ld b,a
ld [wd0d8],a
ld a,[hl]
- rl a
+ rl a ; double the damage
ld [W_DAMAGE],a
or b
jr nz,.next
@@ -3549,8 +3560,8 @@
ld [hl],a
ld a,BIDE
ld [W_PLAYERMOVENUM],a
- ld hl,asm_3d705
- jp .CannotUseMove
+ ld hl,asm_3d705 ; skip damage calculation, DecrementPP and MoveHitTest
+ jp .returnToHL
.ThrashingAboutCheck
bit 1,[hl] ; is mon using thrash or petal dance?
@@ -3560,20 +3571,20 @@
ld hl,ThrashingAboutText
call PrintText
ld hl,wPlayerNumAttacksLeft
- dec [hl]
- ld hl,asm_3d6dc
- jp nz,.CannotUseMove
+ dec [hl] ; did Trashing About counter hit 0?
+ ld hl,CalcMoveDamage ; skip DecrementPP
+ jp nz,.returnToHL
push hl
ld hl,W_PLAYERBATTSTATUS1
- res 1,[hl]
- set 7,[hl]
+ res 1,[hl] ; no longer trashing about
+ set 7,[hl] ; confused
call BattleRandom
and a,3
inc a
- inc a
+ inc a ; confused for 2-5 turns
ld [wd06b],a
- pop hl
- jp .CannotUseMove
+ pop hl ; skip DecrementPP
+ jp .returnToHL
.MultiturnMoveCheck
bit 5,[hl] ; is mon using multi-turn move?
@@ -3581,16 +3592,16 @@
ld hl,AttackContinuesText
call PrintText
ld a,[wPlayerNumAttacksLeft]
- dec a
+ dec a ; did multi-turn move end?
ld [wPlayerNumAttacksLeft],a
- ld hl,asm_3d714
- jp nz,.CannotUseMove
- jp .CannotUseMove
+ ld hl,asm_3d714 ; if it didn't, skip damage calculation (deal damage equal to last hit), DecrementPP and MoveHitTest
+ jp nz,.returnToHL
+ jp .returnToHL
.RageCheck
ld a, [W_PLAYERBATTSTATUS2]
bit 6, a ; is mon using rage?
- jp z, .CanUseMove
+ jp z, .CanUseMove ; if we made it this far, mon can move normally this turn
ld a, RAGE
ld [wd11e], a
call GetMoveName
@@ -3597,10 +3608,10 @@
call CopyStringToCF4B
xor a
ld [W_PLAYERMOVEEFFECT], a
- ld hl, asm_3d6b0
- jp .CannotUseMove
+ ld hl, PlayerCanExecuteMove
+ jp .returnToHL
-.CannotUseMove
+.returnToHL
xor a
ret
@@ -3691,7 +3702,7 @@
TX_FAR _MoveIsDisabledText
db "@"
-PrintHurtItselfText: ; 3daad (f:5aad)
+HandleSelfConfusionDamage: ; 3daad (f:5aad)
ld hl, HurtItselfText
call PrintText
ld hl, wEnemyMonDefense
@@ -3709,13 +3720,13 @@
push af
xor a
ld [hli], a
- ld [wCriticalHitOrOHKO], a
- ld a, $28
+ ld [wCriticalHitOrOHKO], a ; self-inflicted confusion damage can't be a Critical Hit
+ ld a, $28 ; 40 base power
ld [hli], a
xor a
ld [hl], a
call GetDamageVarsForPlayerAttack
- call CalculateDamage
+ call CalculateDamage ; ignores AdjustDamageForMoveType (type-less damage), RandomizeDamage, and MoveHitTest (always hits)
pop af
pop hl
ld [hl], a
@@ -3893,8 +3904,9 @@
cp JUMP_KICK_EFFECT
ret nz
- ; if you get here, the mon used hi jump kick and missed
- ld hl, W_DAMAGE
+ ; if you get here, the mon used jump kick or hi jump kick and missed
+ ld hl, W_DAMAGE ; 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
@@ -3907,10 +3919,10 @@
dec hl
ld [hli], a
or b
- jr nz, .asm_3dc2a
+ jr nz, .applyRecoil
inc a
ld [hl], a
-.asm_3dc2a
+.applyRecoil
ld hl, KeptGoingAndCrashedText
call PrintText
ld b, $4
@@ -3917,9 +3929,9 @@
predef Func_48125
ld a, [H_WHOSETURN]
and a
- jr nz, .asm_3dc3f
+ jr nz, .enemyTurn
jp ApplyDamageToPlayerPokemon
-.asm_3dc3f
+.enemyTurn
jp ApplyDamageToEnemyPokemon
AttackMissedText: ; 3dc42 (f:5c42)
@@ -4053,7 +4065,7 @@
jr nc, .monDoesNothing
ld hl, WontObeyText
call PrintText
- call PrintHurtItselfText
+ call HandleSelfConfusionDamage
jp .cannotUseMove
.monNaps
call BattleRandom
@@ -4200,7 +4212,7 @@
jr z, .physicalAttackCritCheck
; if the enemy has used Reflect, double the enemy's defense
sla c
- rl b
+ rl b
.physicalAttackCritCheck
ld hl, wBattleMonAttack
ld a, [wCriticalHitOrOHKO]
@@ -4231,6 +4243,8 @@
; 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]
@@ -4258,12 +4272,13 @@
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)
+; bc /= 4 (scale enemy's defensive stat)
srl b
rr c
srl b
rr c
- ; hl /= 4 (scale player's offensive stat)
+; 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
@@ -4340,6 +4355,8 @@
; 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]
@@ -4372,6 +4389,7 @@
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
@@ -4402,7 +4420,7 @@
push bc
ld a, [W_ISLINKBATTLE]
cp $4
- jr nz, .asm_3df40
+ jr nz, .notLinkBattle
ld hl, wEnemyMon1Stats
dec c
sla c
@@ -4418,7 +4436,7 @@
pop bc
pop de
ret
-.asm_3df40
+.notLinkBattle
ld a, [wEnemyMonLevel]
ld [W_CURENEMYLVL], a
ld a, [wEnemyMonSpecies]
@@ -4579,6 +4597,7 @@
jr c, .asm_3e00a
.asm_3e004
+; cap at 997
ld a, 997 / $100
ld [hli], a
ld a, 997 % $100
@@ -4585,6 +4604,7 @@
ld [hld], a
.asm_3e00a
+; add 2
inc hl
ld a, [hl]
add 2
@@ -4591,8 +4611,9 @@
ld [hld], a
jr nc, .done
inc [hl]
+
.done
-
+; minimum damage is 1
ld a, 1
and a
ret
@@ -4653,7 +4674,7 @@
.focusEnergyUsed
srl b
.noFocusEnergyUsed
- ld hl, HighCriticalMoves ; table of high critical hit moves
+ 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?
@@ -4671,7 +4692,7 @@
jr nc, .SkipHighCritical
ld b, $ff
.SkipHighCritical
- call BattleRandom ; generates a random value, in "a"
+ call BattleRandom ; generates a random value, in "a"
rlc a
rlc a
rlc a
@@ -4678,7 +4699,7 @@
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
+ ld [wCriticalHitOrOHKO], a ; set critical hit flag
ret
; high critical hit moves
@@ -4692,6 +4713,12 @@
; function to determine if Counter hits and if so, how much damage it does
HandleCounterMove: ; 3e093 (f:6093)
+; 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
@@ -4710,11 +4737,11 @@
ld [W_MOVEMISSED],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 ; if the target also used Counter, miss
+ ret z ; miss if the opponent's last selected move is Counter.
ld a,[de]
and a
- ret z ; if the move the target used has 0 power, miss
-; check if the move the target used was Normal or Fighting type
+ 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
@@ -4728,8 +4755,10 @@
ld hl,W_DAMAGE
ld a,[hli]
or [hl]
- ret z ; Counter misses if the target did no damage to the Counter user
-; double the damage that the target did to the Counter user
+ ret z ; If we made it here, Counter still misses if the last move used in battle did no damage to its target.
+ ; W_DAMAGE 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
@@ -4758,7 +4787,7 @@
jr z,.specialDamage
ld a,[W_PLAYERMOVEPOWER]
and a
- jp z,ApplyAttackToEnemyPokemonDone
+ jp z,ApplyAttackToEnemyPokemonDone ; no attack to apply if base power is 0
jr ApplyDamageToEnemyPokemon
.superFangEffect
; set the damage to half the target's HP
@@ -4781,16 +4810,16 @@
.specialDamage
ld hl,wBattleMonLevel
ld a,[hl]
- ld b,a
+ ld b,a ; Seismic Toss deals damage equal to the user's level
ld a,[W_PLAYERMOVENUM]
- cp a,SEISMIC_TOSS
+ cp a,SEISMIC_TOSS
jr z,.storeDamage
cp a,NIGHT_SHADE
jr z,.storeDamage
- ld b,SONICBOOM_DAMAGE
+ ld b,SONICBOOM_DAMAGE ; 20
cp a,SONICBOOM
jr z,.storeDamage
- ld b,DRAGON_RAGE_DAMAGE
+ ld b,DRAGON_RAGE_DAMAGE ; 40
cp a,DRAGON_RAGE
jr z,.storeDamage
; Psywave
@@ -4807,7 +4836,7 @@
cp b
jr nc,.loop
ld b,a
-.storeDamage
+.storeDamage ; store damage value at b
ld hl,W_DAMAGE
xor a
ld [hli],a
@@ -4839,7 +4868,7 @@
sbc b
ld [wEnemyMonHP],a
jr nc,.animateHpBar
-; if more damage was done than the current HP, zero the HP and set the damage
+; if more damage was done than the current HP, zero the HP and set the damage (W_DAMAGE)
; equal to how much HP the pokemon had before the attack
ld a,[wHPBarOldHP+1]
ld [hli],a
@@ -4959,7 +4988,7 @@
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
+; if more damage was done than the current HP, zero the HP and set the damage (W_DAMAGE)
; equal to how much HP the pokemon had before the attack
ld a,[wHPBarOldHP+1]
ld [hli],a
@@ -4986,6 +5015,11 @@
jp DrawHUDsAndHPBars
AttackSubstitute: ; 3e25e (f:625e)
+; 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
@@ -5008,6 +5042,7 @@
ld [de],a
ret nc
.substituteBroke
+; If the target's Substitute breaks, W_DAMAGE isn't updated with the amount of HP the Substitute had before being attacked.
ld h,b
ld l,c
res 4,[hl] ; unset the substitute bit
@@ -5089,6 +5124,11 @@
; copy last move for Mirror Move
; sets zero flag on failure and unsets zero flag on success
MirrorMoveCopyMove: ; 3e2fd (f:62fd)
+; Mirror Move makes use of ccf1 and ccf2 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
@@ -5102,12 +5142,11 @@
ld hl,wEnemySelectedMove
.next
ld [hl],a
- cp a,MIRROR_MOVE ; did the target pokemon also use Mirror Move?
+ cp a,MIRROR_MOVE ; did the target Pokemon last use Mirror Move, and miss?
jr z,.mirrorMoveFailed
and a ; null move?
jr nz,ReloadMoveData
.mirrorMoveFailed
-; Mirror Move fails on itself and null moves
ld hl,MirrorMoveFailedText
call PrintText
xor a
@@ -5187,9 +5226,9 @@
ld a,[H_WHOSETURN]
and a
ld a,[wPlayerMonNumber] ; value for player turn
- jr z,.next2
+ jr z,.updatePP
ld a,[wEnemyMonPartyPos] ; value for enemy turn
-.next2
+.updatePP
ld bc,wEnemyMon2 - wEnemyMon1
call AddNTimes
inc [hl] ; increment PP in the party memory location
@@ -5296,6 +5335,7 @@
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 [W_MOVEMISSED],a
.skipTypeImmunity
@@ -5546,7 +5586,7 @@
jr nz, .DamageGreaterThanOne
ld a, [hl]
cp 2
- ret c
+ ret c ; return if damage is equal to 0 or 1
.DamageGreaterThanOne
xor a
ld [H_MULTIPLICAND], a
@@ -5632,12 +5672,12 @@
ld [wcced], a
call PrintMonName1Text
ld a, [W_ENEMYMOVEEFFECT]
- ld hl, EffectsArray1
+ ld hl, ResidualEffects1
ld de, $1
call IsInArray
jp c, JumpMoveEffect
ld a, [W_ENEMYMOVEEFFECT]
- ld hl, EffectsArray5B
+ ld hl, SpecialEffectsCont
ld de, $1
call IsInArray
call c, JumpMoveEffect
@@ -5644,7 +5684,7 @@
asm_3e750: ; 3e750 (f:6750)
call SwapPlayerAndEnemyLevels
ld a, [W_ENEMYMOVEEFFECT]
- ld hl, EffectsArray2
+ ld hl, SetDamageEffects
ld de, $1
call IsInArray
jp c, Func_3e77f
@@ -5693,7 +5733,7 @@
ld [wcc5b], a
ld a, [W_ENEMYMOVENUM]
call PlayMoveAnimation
- call Func_3eed3
+ call HandleExplodingAnimation
call DrawEnemyHUDAndHPBar
ld a, [W_ENEMYBATTSTATUS2]
bit 4, a ; does mon have a substitute?
@@ -5731,7 +5771,7 @@
jp Func_3e6fc
.notMetronomeEffect
ld a, [W_ENEMYMOVEEFFECT]
- ld hl, EffectsArray3
+ ld hl, ResidualEffects2
ld de, $1
call IsInArray
jp c, JumpMoveEffect
@@ -5751,7 +5791,7 @@
ld [wccf4], a
.asm_3e83e
ld a, [W_ENEMYMOVEEFFECT]
- ld hl, EffectsArray4
+ ld hl, AlwaysHappenSideEffects
ld de, $1
call IsInArray
call c, JumpMoveEffect
@@ -5778,7 +5818,7 @@
ld a, [W_ENEMYMOVEEFFECT]
and a
jr z, Func_3e88c
- ld hl, EffectsArray5
+ ld hl, SpecialEffects
ld de, $1
call IsInArray
call nc, JumpMoveEffect
@@ -6704,14 +6744,14 @@
ret
-Func_3eed3: ; 3eed3 (f:6ed3)
+HandleExplodingAnimation: ; 3eed3 (f:6ed3)
ld a, [H_WHOSETURN]
and a
- ld hl, wEnemyMonType1 ; wcfea (aliases: wEnemyMonType)
+ ld hl, wEnemyMonType1 ; wcfea
ld de, W_ENEMYBATTSTATUS1
ld a, [W_PLAYERMOVENUM]
jr z, .asm_3eeea
- ld hl, wBattleMonType1 ; wd019 (aliases: wBattleMonType)
+ ld hl, wBattleMonType1 ; wd019
ld de, W_ENEMYBATTSTATUS1
ld a, [W_ENEMYMOVENUM]
.asm_3eeea
@@ -6732,7 +6772,7 @@
ld a, [W_MOVEMISSED]
and a
ret nz
- ld a, MEGA_PUNCH
+ ld a, 5
ld [wcc5b], a
PlayMoveAnimation: ; 3ef07 (f:6f07)
@@ -7136,41 +7176,43 @@
ld bc, W_ENEMYBATTSTATUS2
ld a, [H_WHOSETURN]
and a
- jp z, .asm_3f20e
+ jp z, .sleepEffect
ld de, wBattleMonStatus
ld bc, W_PLAYERBATTSTATUS2
-.asm_3f20e
+.sleepEffect
ld a, [bc]
- bit 5, a ; does the mon need to recharge? (hyper beam)
- res 5, a ; mon no longer needs to recharge
+ bit 5, a ; does the target need to recharge? (hyper beam)
+ res 5, a ; target no longer needs to recharge
ld [bc], a
- jr nz, .asm_3f231
+ jr nz, .setSleepCounter ; if the target had to recharge, all hit tests will be skipped
+ ; including the event where the target already has another status
ld a, [de]
ld b, a
and $7
- jr z, .asm_3f222
+ jr z, .notAlreadySleeping ; can't affect a mon that is already asleep
ld hl, AlreadyAsleepText
jp PrintText
-.asm_3f222
+.notAlreadySleeping
ld a, b
and a
- jr nz, .asm_3f242
+ jr nz, .didntAffect ; can't affect a mon that is already statused
push de
- call MoveHitTest
+ call MoveHitTest ; apply accuracy tests
pop de
ld a, [W_MOVEMISSED]
and a
- jr nz, .asm_3f242
-.asm_3f231
+ jr nz, .didntAffect
+.setSleepCounter
+; set target's sleep counter to a random number between 1 and 7
call BattleRandom
- and $7
- jr z, .asm_3f231
+ and $7
+ jr z, .setSleepCounter
ld [de], a
call Func_3fb89
ld hl, FellAsleepText
jp PrintText
-.asm_3f242
+.didntAffect
jp PrintDidntAffectText
FellAsleepText: ; 3f245 (f:7245)
@@ -7186,45 +7228,45 @@
ld de, W_PLAYERMOVEEFFECT
ld a, [H_WHOSETURN]
and a
- jr z, .asm_3f260
+ jr z, .poisonEffect
ld hl, wBattleMonStatus
ld de, W_ENEMYMOVEEFFECT
-.asm_3f260
+.poisonEffect
call CheckTargetSubstitute
- jr nz, .asm_3f2d3
+ jr nz, .noEffect ; can't posion a substitute target
ld a, [hli]
ld b, a
and a
- jr nz, .asm_3f2d3
+ jr nz, .noEffect ; miss if target is already statused
ld a, [hli]
- cp $3
- jr z, .asm_3f2d3
+ cp POISON ; can't posion a poison-type target
+ jr z, .noEffect
ld a, [hld]
- cp $3
- jr z, .asm_3f2d3
+ cp POISON ; can't posion a poison-type target
+ jr z, .noEffect
ld a, [de]
cp POISON_SIDE_EFFECT1
ld b, $34 ; ~20% chance of poisoning
- jr z, .asm_3f290
+ jr z, .sideEffectTest
cp POISON_SIDE_EFFECT2
ld b, $67 ; ~40% chance of poisoning
- jr z, .asm_3f290
+ jr z, .sideEffectTest
push hl
push de
- call MoveHitTest
+ call MoveHitTest ; apply accuracy tests
pop de
pop hl
ld a, [W_MOVEMISSED]
and a
- jr nz, .asm_3f2d7
- jr .asm_3f295
-.asm_3f290
- call BattleRandom
- cp b
+ jr nz, .didntAffect
+ jr .inflictPoison
+.sideEffectTest
+ call BattleRandom
+ cp b ; was side effect successful?
ret nc
-.asm_3f295
+.inflictPoison
dec hl
- set 3, [hl]
+ set 3, [hl] ; mon is now poisoned
push de
dec de
ld a, [H_WHOSETURN]
@@ -7233,19 +7275,19 @@
ld hl, W_PLAYERBATTSTATUS3
ld a, [de]
ld de, W_PLAYERTOXICCOUNTER
- jr nz, .asm_3f2b0
+ jr nz, .ok
ld b, ANIM_A9
ld hl, W_ENEMYBATTSTATUS3
ld de, W_ENEMYTOXICCOUNTER
-.asm_3f2b0
+.ok
cp TOXIC
- jr nz, .asm_3f2bd
- set 0, [hl]
+ jr nz, .normalPoison ; done if move is not Toxic
+ set 0, [hl] ; else set Toxic battstatus
xor a
ld [de], a
ld hl, BadlyPoisonedText
jr .asm_3f2c0
-.asm_3f2bd
+.normalPoison
ld hl, PoisonedText
.asm_3f2c0
pop de
@@ -7258,11 +7300,11 @@
.asm_3f2cd
call Func_3fb89
jp PrintText
-.asm_3f2d3
+.noEffect
ld a, [de]
cp POISON_EFFECT
ret nz
-.asm_3f2d7
+.didntAffect
ld c, $32
call DelayFrames
jp PrintDidntAffectText
@@ -7285,10 +7327,10 @@
ld de, W_PLAYERBATTSTATUS2
ld a, [H_WHOSETURN]
and a
- jr z, .asm_3f302
+ jr z, .faintUser
ld hl, wEnemyMonHP
ld de, W_ENEMYBATTSTATUS2
-.asm_3f302
+.faintUser
xor a
ld [hli], a ; set the mon's HP to 0
ld [hli], a
@@ -7302,65 +7344,64 @@
FreezeBurnParalyzeEffect: ; 3f30c (f:730c)
xor a
ld [wcc5b], 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, [$fff3] ;whose turn?
+ 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, [$fff3]
and a
jp nz, opponentAttacker
ld a, [wEnemyMonStatus]
and a
- jp nz, CheckDefrost
- ;opponent has no existing status
+ jp nz, CheckDefrost ; can't inflict status if opponent is already statused
ld a, [W_PLAYERMOVETYPE]
ld b, a
ld a, [wEnemyMonType1]
- cp b
- ret z ;return if they match [can't freeze an ice type etc.]
+ cp b ; do target type 1 and move type match?
+ ret z ; return if they match (an ice move can't freeze an ice-type, body slam can't paralyze a normal-type, etc.)
ld a, [wEnemyMonType2]
- cp b
- ret z ;return..
+ cp b ; do target type 2 and move type match?
+ ret z ; return if they match
ld a, [W_PLAYERMOVEEFFECT]
- cp a, 7 ;10% status effects are 04, 05, 06 so 07 will set carry for those
- ld b, $1a ;[1A-1]/100 or [26-1]/256 = 9.8%~ chance
- jr c, .next1 ;branch ahead if this is a 10% chance effect..
- ld b, $4d ;..or use [4D-1]/100 or [76-1]/256 = 29.7%~ chance
- sub a, $1e ;subtract $1E to map to equivalent 10% chance effects
+ 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..
+ ld b, $4d ; else use 0x4D/0x100 or 77/256 = 30.1%~ chance
+ sub a, $1e ; subtract $1E to map to equivalent 10% chance effects
.next1
- push af ;push effect...
- call BattleRandom ;get random 8bit value for probability test
- cp b ;success?
- pop bc ;...pop effect into C
- ret nc ;do nothing if random value is >= 1A or 4D [no status applied]
- ;the test passed
- ld a, b ;what type of effect is this?
+ push af
+ call BattleRandom ; get random 8bit value for probability test
+ cp b
+ pop bc
+ 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
cp a, FREEZE_SIDE_EFFECT
jr z, .freeze
+; .paralyze
ld a, 1 << PAR
ld [wEnemyMonStatus], a
- call QuarterSpeedDueToParalysis ;quarter speed of affected monster
+ call QuarterSpeedDueToParalysis ; quarter speed of affected mon
ld a, ANIM_A9
- call Func_3fbb9 ;animation
- jp PrintMayNotAttackText ;print paralysis text
+ call PlayBattleAnimatiom
+ jp PrintMayNotAttackText ; print paralysis text
.burn
ld a, 1 << BRN
ld [wEnemyMonStatus], a
- call HalveAttackDueToBurn
+ call HalveAttackDueToBurn ; halve attack of affected mon
ld a, ANIM_A9
- call Func_3fbb9 ;animation
+ call PlayBattleAnimatiom
ld hl, BurnedText
jp PrintText
.freeze
- call Func_3f9cf ;resets bit 5 of the D063/D068 flags
+ call ClearHyperBeam ; resets hyper beam (recharge) condition from both players
ld a, 1 << FRZ
ld [wEnemyMonStatus], a
ld a, ANIM_A9
- call Func_3fbb9 ;animation
+ call PlayBattleAnimatiom
ld hl, FrozenText
jp PrintText
opponentAttacker: ; 3f382 (f:7382)
- ld a, [wBattleMonStatus] ;this appears to the same as above with addresses swapped for opponent
+ ld a, [wBattleMonStatus] ; mostly same as above with addresses swapped for opponent
and a
jp nz, CheckDefrost
ld a, [W_ENEMYMOVETYPE]
@@ -7399,6 +7440,7 @@
ld hl, BurnedText
jp PrintText
.freeze
+; hyper beam bits aren't reseted for opponent's side
ld a, 1 << FRZ
ld [wBattleMonStatus], a
ld hl, FrozenText
@@ -7413,28 +7455,27 @@
db "@"
CheckDefrost: ; 3f3e2 (f:73e2)
- and a, 1 << FRZ ;are they frozen?
- ret z ;return if so
- ;not frozen
- ld a, [$fff3] ;whose turn?
+; 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
+ ld a, [$fff3]
and a
jr nz, .opponent
;player [attacker]
ld a, [W_PLAYERMOVETYPE]
sub a, FIRE
- ret nz ;return if it isn't fire
- ;type is fire
- ld [wEnemyMonStatus], a ;set opponent status to 00 ["defrost" a frozen monster]
+ ret nz ; return if type of move used isn't fire
+ ld [wEnemyMonStatus], a ; set opponent status to 00 ["defrost" a frozen monster]
ld hl, wEnemyMon1Status
ld a, [wEnemyMonPartyPos]
ld bc, wEnemyMon2 - wEnemyMon1
call AddNTimes
xor a
- ld [hl], a ;clear status in roster
+ ld [hl], a ; clear status in roster
ld hl, FireDefrostedText
jr .common
.opponent
- ld a, [W_ENEMYMOVETYPE] ;same as above with addresses swapped
+ ld a, [W_ENEMYMOVETYPE] ; same as above with addresses swapped
sub a, FIRE
ret nz
ld [wBattleMonStatus], a
@@ -7457,64 +7498,65 @@
ld de, W_PLAYERMOVEEFFECT
ld a, [H_WHOSETURN]
and a
- jr z, .asm_3f439
+ jr z, .statModifierUpEffect
ld hl, wEnemyMonStatMods
ld de, W_ENEMYMOVEEFFECT
-.asm_3f439
+.statModifierUpEffect
ld a, [de]
- sub $a
+ sub ATTACK_UP1_EFFECT
cp $8
- jr c, .asm_3f442
- sub $28
-.asm_3f442
+ jr c, .incrementStatMod
+ sub ATTACK_UP2_EFFECT - ATTACK_UP1_EFFECT ; map +2 effects to equivalent +1 effect
+.incrementStatMod
ld c, a
ld b, $0
add hl, bc
ld b, [hl]
- inc b
+ inc b ; increment corresponding stat mod
ld a, $d
- cp b
+ cp b ; can't raise stat past +6 ($d or 13)
jp c, Func_3f522
ld a, [de]
- cp $12
- jr c, .asm_3f45a
- inc b
+ cp ATTACK_UP1_EFFECT + $8 ; is it a +2 effect?
+ jr c, .ok
+ inc b ; if so, increment stat mod again
ld a, $d
- cp b
- jr nc, .asm_3f45a
+ cp b ; unless it's already +6
+ jr nc, .ok
ld b, a
-.asm_3f45a
+.ok
ld [hl], b
ld a, c
cp $4
- jr nc, asm_3f4ca
+ jr nc, UpdateStatDone ; jump if mod affected is evasion/accuracy
push hl
ld hl, wBattleMonAttack + 1
ld de, wcd12
ld a, [H_WHOSETURN]
and a
- jr z, .asm_3f472
+ jr z, .pointToStats
ld hl, wEnemyMonAttack + 1
ld de, wEnemyMonUnmodifiedAttack
-.asm_3f472
+.pointToStats
push bc
sla c
ld b, $0
- add hl, bc
+ add hl, bc ; hl = modified stat
ld a, c
add e
ld e, a
- jr nc, .asm_3f47e
- inc d
-.asm_3f47e
+ jr nc, .checkIf999
+ inc d ; de = unmodified (original) stat
+.checkIf999
pop bc
ld a, [hld]
- sub $e7
- jr nz, .asm_3f48a
+ sub $e7 ; check if stat is already 999
+ jr nz, .recalculateStat
ld a, [hl]
sbc $3
jp z, Func_3f520
-.asm_3f48a
+.recalculateStat ; recalculate affected stat
+ ; paralysis and burn penalties, as well as badge boosts are ignored
push hl
push bc
ld hl, StatModifierRatios
@@ -7539,23 +7581,24 @@
ld b, $4
call Divide
pop hl
+; cap at 999
ld a, [$ff98]
sub $e7
ld a, [$ff97]
sbc $3
- jp c, Func_3f4c3
+ jp c, UpdateStat
ld a, 999 / $100
ld [$ff97], a
ld a, 999 % $100
ld [$ff98], a
-Func_3f4c3: ; 3f4c3 (f:74c3)
+UpdateStat: ; 3f4c3 (f:74c3)
ld a, [$ff97]
ld [hli], a
ld a, [$ff98]
ld [hl], a
pop hl
-asm_3f4ca: ; 3f4ca (f:74ca)
+UpdateStatDone: ; 3f4ca (f:74ca)
ld b, c
inc b
call Func_3f688
@@ -7572,19 +7615,19 @@
ld a, [de]
cp MINIMIZE
jr nz, .asm_3f4f9
- bit 4, [hl]
+ bit 4, [hl] ; substitute
push af
push bc
ld hl, Func_79747
ld b, BANK(Func_79747)
push de
- call nz, Bankswitch
+ call nz, Bankswitch ; play Minimize animation unless there's Substitute involved
pop de
.asm_3f4f9
call Func_3fba8
ld a, [de]
cp MINIMIZE
- jr nz, .asm_3f50e
+ jr nz, .applyBadgeBoostsAndStatusPenalties
pop bc
ld a, $1
ld [bc], a
@@ -7592,15 +7635,18 @@
ld b, BANK(Func_79771)
pop af
call nz, Bankswitch
-.asm_3f50e
+.applyBadgeBoostsAndStatusPenalties
ld a, [H_WHOSETURN]
and a
- call z, ApplyBadgeStatBoosts
+ call z, ApplyBadgeStatBoosts ; whenever the player uses a stat-up move, badge boosts get reapplied again to every stat,
+ ; even to those not affected by the stat-up move (will be boosted further)
ld hl, MonsStatsRoseText
call PrintText
- call QuarterSpeedDueToParalysis
- jp HalveAttackDueToBurn
+; these shouldn't be here
+ 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
+
Func_3f520: ; 3f520 (f:7520)
pop hl
dec [hl]
@@ -7638,67 +7684,67 @@
ld bc, W_ENEMYBATTSTATUS1
ld a, [H_WHOSETURN]
and a
- jr z, .asm_3f572
+ jr z, .statModifierDownEffect
ld hl, wPlayerMonStatMods
ld de, W_ENEMYMOVEEFFECT
ld bc, W_PLAYERBATTSTATUS1
ld a, [W_ISLINKBATTLE]
cp $4
- jr z, .asm_3f572
+ jr z, .statModifierDownEffect
call BattleRandom
- cp $40
- jp c, Func_3f65a
-.asm_3f572
- call CheckTargetSubstitute
- jp nz, Func_3f65a
+ cp $40 ; 1/4 chance to miss by wildmon
+ jp c, MoveMissed
+.statModifierDownEffect
+ call CheckTargetSubstitute ; can't hit through substitute
+ jp nz, MoveMissed
ld a, [de]
cp ATTACK_DOWN_SIDE_EFFECT
- jr c, .asm_3f58a
+ jr c, .nonSideEffect
call BattleRandom
- cp SPLASH_EFFECT
- jp nc, Func_3f650
+ cp $55 ; 85/256 chance for side effects
+ jp nc, CantLowerAnymore
ld a, [de]
- sub ATTACK_DOWN_SIDE_EFFECT
- jr .asm_3f5a9
-.asm_3f58a
+ sub ATTACK_DOWN_SIDE_EFFECT ; map each stat to 0-3
+ jr .decrementStatMod
+.nonSideEffect ; non-side effects only
push hl
push de
push bc
- call MoveHitTest
+ call MoveHitTest ; apply accuracy tests
pop bc
pop de
pop hl
ld a, [W_MOVEMISSED]
and a
- jp nz, Func_3f65a
+ jp nz, MoveMissed
ld a, [bc]
- bit 6, a
- jp nz, Func_3f65a
+ bit 6, a ; fly/dig
+ jp nz, MoveMissed
ld a, [de]
- sub $12
+ sub ATTACK_DOWN1_EFFECT
cp $8
- jr c, .asm_3f5a9
- sub $28
-.asm_3f5a9
+ jr c, .decrementStatMod
+ sub ATTACK_DOWN2_EFFECT - ATTACK_DOWN1_EFFECT ; map +2 effects to corresponding +1 effect
+.decrementStatMod
ld c, a
ld b, $0
add hl, bc
ld b, [hl]
- dec b
- jp z, Func_3f650
+ dec b ; dec corresponding stat mod
+ jp z, CantLowerAnymore ; if stat mod is 1 (-6), can't lower anymore
ld a, [de]
cp $24
- jr c, .asm_3f5bf
+ jr c, .ok
cp $44
- jr nc, .asm_3f5bf
- dec b
- jr nz, .asm_3f5bf
- inc b
-.asm_3f5bf
- ld [hl], b
+ jr nc, .ok
+ dec b ; stat down 2 effects only (dec mod again)
+ jr nz, .ok
+ inc b ; increment mod to 1 (-6) if it would become 0 (-7)
+.ok
+ ld [hl], b ; save modified mod
ld a, c
- cp $4
- jr nc, asm_3f62c
+ cp $4
+ jr nc, UpdateStat2Done ; jump for evasion/accuracy
push hl
push de
ld hl, wEnemyMonAttack + 1
@@ -7705,28 +7751,30 @@
ld de, wEnemyMonUnmodifiedAttack
ld a, [H_WHOSETURN]
and a
- jr z, .asm_3f5d8
+ jr z, .pointToStat
ld hl, wBattleMonAttack + 1
ld de, wcd12
-.asm_3f5d8
+.pointToStat
push bc
sla c
ld b, $0
- add hl, bc
+ add hl, bc ; hl = modified stat
ld a, c
add e
ld e, a
jr nc, .asm_3f5e4
- inc d
+ inc d ; de = unmodified stat
.asm_3f5e4
pop bc
ld a, [hld]
- sub $1
- jr nz, .asm_3f5ef
+ sub $1 ; can't lower stat below 1 (-6)
+ jr nz, .recalculateStat
ld a, [hl]
and a
jp z, Func_3f64d
-.asm_3f5ef
+.recalculateStat
+; recalculate affected stat
+; paralysis and burn penalties, as well as badge boosts are ignored
push hl
push bc
ld hl, StatModifierRatios
@@ -7755,12 +7803,12 @@
ld b, a
ld a, [$ff97]
or b
- jp nz, Func_3f624
+ jp nz, UpdateStat2
ld [$ff97], a
ld a, $1
ld [$ff98], a
-Func_3f624: ; 3f624 (f:7624)
+UpdateStat2: ; 3f624 (f:7624)
ld a, [$ff97]
ld [hli], a
ld a, [$ff98]
@@ -7767,7 +7815,7 @@
ld [hl], a
pop de
pop hl
-asm_3f62c: ; 3f62c (f:762c)
+UpdateStat2Done: ; 3f62c (f:762c)
ld b, c
inc b
push de
@@ -7775,14 +7823,19 @@
pop de
ld a, [de]
cp $44
- jr nc, .asm_3f63b
+ jr nc, .ApplyBadgeBoostsAndStatusPenalties
call Func_3fb89
-.asm_3f63b
+.ApplyBadgeBoostsAndStatusPenalties
ld a, [H_WHOSETURN]
and a
- call nz, ApplyBadgeStatBoosts
+ call nz, ApplyBadgeStatBoosts ; whenever the player uses a stat-down move, badge boosts get reapplied again to every stat,
+ ; even to those not affected by the stat-up move (will be boosted further)
ld hl, MonsStatsFellText
call PrintText
+
+; These where probably added given that a stat-down move affecting speed or attack will override
+; the stat penalties from paralysis and burn respectively.
+; But they are always called regardless of the stat affected by the stat-down move.
call QuarterSpeedDueToParalysis
jp HalveAttackDueToBurn
@@ -7791,7 +7844,7 @@
pop hl
inc [hl]
-Func_3f650: ; 3f650 (f:7650)
+CantLowerAnymore: ; 3f650 (f:7650)
ld a, [de]
cp ATTACK_DOWN_SIDE_EFFECT
ret nc
@@ -7798,7 +7851,7 @@
ld hl, NothingHappenedText
jp PrintText
-Func_3f65a: ; 3f65a (f:765a)
+MoveMissed: ; 3f65a (f:765a)
ld a, [de]
cp $44
ret nc
@@ -7875,11 +7928,11 @@
ld bc, wPlayerNumAttacksLeft
ld a, [H_WHOSETURN]
and a
- jr z, .asm_3f6fc
+ jr z, .bideEffect
ld hl, W_ENEMYBATTSTATUS1
ld de, wcd05
ld bc, wEnemyNumAttacksLeft
-.asm_3f6fc
+.bideEffect
set 0, [hl] ; mon is now using bide
xor a
ld [de], a
@@ -7891,7 +7944,7 @@
and $1
inc a
inc a
- ld [bc], a
+ ld [bc], a ; set Bide counter to 2 or 3 at random
ld a, [H_WHOSETURN]
add XSTATITEM_ANIM
jp Func_3fb96
@@ -7901,16 +7954,16 @@
ld de, wPlayerNumAttacksLeft
ld a, [H_WHOSETURN]
and a
- jr z, .asm_3f728
+ jr z, .thrashPetalDanceEffect
ld hl, W_ENEMYBATTSTATUS1
ld de, wEnemyNumAttacksLeft
-.asm_3f728
+.thrashPetalDanceEffect
set 1, [hl] ; mon is now using thrash/petal dance
call BattleRandom
- and $1
+ and $1
inc a
inc a
- ld [de], a
+ ld [de], a ; set thrash/petal dance counter to 2 or 3 at random
ld a, [H_WHOSETURN]
add ANIM_B0
jp Func_3fb96
@@ -8004,7 +8057,7 @@
jp Func_3fb4e
.asm_3f7e4
push af
- call Func_3fbb9
+ call PlayBattleAnimatiom
ld c, $14
call DelayFrames
pop af
@@ -8036,11 +8089,11 @@
ld bc, W_NUMHITS
ld a, [H_WHOSETURN]
and a
- jr z, .asm_3f828
+ jr z, .twoToFiveAttacksEffect
ld hl, W_ENEMYBATTSTATUS1
ld de, wEnemyNumAttacksLeft
ld bc, wcd05
-.asm_3f828
+.twoToFiveAttacksEffect
bit 2, [hl] ; is mon attacking multiple times?
ret nz
set 2, [hl] ; mon is now attacking multiple times
@@ -8047,32 +8100,33 @@
ld hl, W_PLAYERMOVEEFFECT
ld a, [H_WHOSETURN]
and a
- jr z, .asm_3f838
+ jr z, .setNumberOfHits
ld hl, W_ENEMYMOVEEFFECT
-.asm_3f838
+.setNumberOfHits
ld a, [hl]
cp TWINEEDLE_EFFECT
- jr z, .asm_3f856
+ jr z, .twineedle
cp ATTACK_TWICE_EFFECT
- ld a, $2
- jr z, .asm_3f853
+ ld a, $2 ; number of hits it's always 2 for ATTACK_TWICE_EFFECT
+ jr z, .saveNumberOfHits
+; for TWO_TO_FIVE_ATTACKS_EFFECT 3/8 chance for 2 and 3 hits, and 1/8 chance for 4 and 5 hits
call BattleRandom
- and $3
- cp $2
- jr c, .asm_3f851
+ and $3
+ cp $2
+ jr c, .asm_3f851
call BattleRandom
and $3
-.asm_3f851
+.asm_3f851
inc a
inc a
-.asm_3f853
+.saveNumberOfHits
ld [de], a
ld [bc], a
ret
-.asm_3f856
- ld a, $2
- ld [hl], a
- jr .asm_3f853
+.twineedle
+ ld a, POISON_SIDE_EFFECT1
+ ld [hl], a ; set Twineedle's effect to poison effect
+ jr .saveNumberOfHits
FlichSideEffect: ; 3f85b (f:785b)
call CheckTargetSubstitute
@@ -8095,7 +8149,7 @@
cp b
ret nc
set 3, [hl] ; set mon's status to flinching
- call Func_3f9cf
+ call ClearHyperBeam
ret
OneHitKOEffect: ; 3f884 (f:7884)
@@ -8131,7 +8185,7 @@
xor a
ld [wcc5b], a
ld a, b
- call Func_3fbb9
+ call PlayBattleAnimatiom
ld a, [de]
ld [wWhichTrade], a
ld hl, ChargeMoveEffectText
@@ -8196,7 +8250,7 @@
.asm_3f928
bit 5, [hl]
ret nz
- call Func_3f9cf
+ call ClearHyperBeam
set 5, [hl]
call BattleRandom
and $3
@@ -8295,7 +8349,7 @@
set 5, [hl] ; mon now needs to recharge
ret
-Func_3f9cf: ; 3f9cf (f:79cf)
+ClearHyperBeam: ; 3f9cf (f:79cf)
push hl
ld hl, W_ENEMYBATTSTATUS2
ld a, [H_WHOSETURN]
@@ -8606,7 +8660,7 @@
and a
ret z
-Func_3fbb9: ; 3fbb9 (f:7bb9)
+PlayBattleAnimatiom: ; 3fbb9 (f:7bb9)
ld [W_ANIMATIONID], a
Func_3fbbc: ; 3fbbc (f:7bbc)