diff options
author | Daniel Harding <corrnondacqb@yahoo.com> | 2015-01-22 21:28:43 -0500 |
---|---|---|
committer | Daniel Harding <corrnondacqb@yahoo.com> | 2015-01-22 21:28:43 -0500 |
commit | 01095f77943b9a7fd0432a6ad2e5c18f2d3e66ae (patch) | |
tree | 6328fe57bdca966019aaafd7fb5322f65bd67d03 | |
parent | 21f306d6532843172b133ab407ccd1da7a37c6bb (diff) | |
parent | d3bf8bca5e7e6e2ccf98241bee950d9cccf2994e (diff) |
Merge pull request #67 from xCrystal/master
Lots of commentary in engine/battle/core.asm
-rwxr-xr-x | engine/battle/core.asm | 774 |
1 files changed, 414 insertions, 360 deletions
diff --git a/engine/battle/core.asm b/engine/battle/core.asm index 43373fdd..cfcfa9db 100755 --- 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 @@ EffectsArray1: ; 3c000 (f:4000) 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 @@ EffectsArray3: ; 3c014 (f:4014) 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 @@ EffectsArray4: ; 3c030 (f:4030) 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 @@ EffectsArray5: ; 3c03b (f:403b) 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 @@ MainInBattleLoop: ; 3c233 (f:4233) 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 @@ MainInBattleLoop: ; 3c233 (f:4233) 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 @@ MainInBattleLoop: ; 3c233 (f:4233) 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 @@ MainInBattleLoop: ; 3c233 (f:4233) 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 @@ HandlePoisonBurnLeechSeed_DecreaseOwnHP: ; 3c43d (f:443d) 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 @@ FaintEnemyPokemon ; 0x3c567 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 @@ EnemySendOut: ; 3c90e (f:490e) ; 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 @@ LinkBattleExchangeData: ; 3d605 (f:5605) 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,19 +3121,19 @@ ExecutePlayerMove: ; 3d65e (f:565e) 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] .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,60 +3141,64 @@ Func_3d69a: ; 3d69a (f:569a) 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 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] 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 ld a,4 jr z,asm_3d71e ld a,5 -asm_3d71e +asm_3d71e push af ld a,[W_PLAYERBATTSTATUS2] bit 4,a @@ -3201,103 +3209,106 @@ asm_3d71e ld [wcc5b],a ld a,[W_PLAYERMOVENUM] call PlayMoveAnimation - call Func_3eed3 + call HandleExplodingAnimation call DrawPlayerHUDAndHPBar ld a,[W_PLAYERBATTSTATUS2] bit 4,a 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 @@ CheckPlayerStatusConditions: ; 3d854 (f:5854) .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 @@ CheckPlayerStatusConditions: ; 3d854 (f:5854) 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 @@ CheckPlayerStatusConditions: ; 3d854 (f:5854) 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 @@ CheckPlayerStatusConditions: ; 3d854 (f:5854) .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 @@ CheckPlayerStatusConditions: ; 3d854 (f:5854) 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,15 +3479,15 @@ CheckPlayerStatusConditions: ; 3d854 (f:5854) 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 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 @@ CheckPlayerStatusConditions: ; 3d854 (f:5854) .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 @@ CheckPlayerStatusConditions: ; 3d854 (f:5854) 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 @@ CheckPlayerStatusConditions: ; 3d854 (f:5854) 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 @@ CheckPlayerStatusConditions: ; 3d854 (f:5854) 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 @@ CheckPlayerStatusConditions: ; 3d854 (f:5854) 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 @@ CheckPlayerStatusConditions: ; 3d854 (f:5854) 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,26 +3592,26 @@ CheckPlayerStatusConditions: ; 3d854 (f:5854) 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 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 @@ MoveIsDisabledText: ; 3daa8 (f:5aa8) TX_FAR _MoveIsDisabledText db "@" -PrintHurtItselfText: ; 3daad (f:5aad) +HandleSelfConfusionDamage: ; 3daad (f:5aad) ld hl, HurtItselfText call PrintText ld hl, wEnemyMonDefense @@ -3709,13 +3720,13 @@ PrintHurtItselfText: ; 3daad (f:5aad) 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 @@ PrintMoveFailureText: ; 3dbe2 (f:5be2) 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,19 +3919,19 @@ PrintMoveFailureText: ; 3dbe2 (f:5be2) 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 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 @@ CheckForDisobedience: ; 3dc88 (f:5c88) jr nc, .monDoesNothing ld hl, WontObeyText call PrintText - call PrintHurtItselfText + call HandleSelfConfusionDamage jp .cannotUseMove .monNaps call BattleRandom @@ -4200,7 +4212,7 @@ GetDamageVarsForPlayerAttack: ; 3ddcf (f:5dcf) 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 @@ GetDamageVarsForPlayerAttack: ; 3ddcf (f:5dcf) ; 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 @@ GetDamageVarsForPlayerAttack: ; 3ddcf (f:5dcf) 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 @@ GetDamageVarsForEnemyAttack: ; 3de75 (f:5e75) ; 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 @@ GetDamageVarsForEnemyAttack: ; 3de75 (f:5e75) 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 @@ GetEnemyMonStat: ; 3df1c (f:5f1c) 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 @@ GetEnemyMonStat: ; 3df1c (f:5f1c) pop bc pop de ret -.asm_3df40 +.notLinkBattle ld a, [wEnemyMonLevel] ld [W_CURENEMYLVL], a ld a, [wEnemyMonSpecies] @@ -4579,20 +4597,23 @@ CalculateDamage: ; 3df65 (f:5f65) jr c, .asm_3e00a .asm_3e004 +; cap at 997 ld a, 997 / $100 ld [hli], a ld a, 997 % $100 ld [hld], a .asm_3e00a +; 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 @@ -4653,7 +4674,7 @@ CriticalHitTest: ; 3e023 (f:6023) .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,14 +4692,14 @@ CriticalHitTest: ; 3e023 (f:6023) 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 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 @@ HighCriticalMoves: ; 3e08e (f:608e) ; 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 @@ HandleCounterMove: ; 3e093 (f:6093) 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 @@ HandleCounterMove: ; 3e093 (f:6093) 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 @@ ApplyAttackToEnemyPokemon: ; 3e0df (f:60df) 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 @@ ApplyAttackToEnemyPokemon: ; 3e0df (f:60df) .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 @@ ApplyAttackToEnemyPokemon: ; 3e0df (f:60df) 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 @@ ApplyDamageToEnemyPokemon: ; 3e142 (f:6142) 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 @@ ApplyDamageToPlayerPokemon: ; 3e200 (f:6200) 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 @@ ApplyAttackToPlayerPokemonDone 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 @@ AttackSubstitute: ; 3e25e (f:625e) 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 @@ BuildingRageText: ; 3e2f8 (f:62f8) ; 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 @@ MirrorMoveCopyMove: ; 3e2fd (f:62fd) 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 @@ IncrementMovePP: ; 3e373 (f:6373) 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 @@ AdjustDamageForMoveType: ; 3e3a5 (f:63a5) 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 @@ RandomizeDamage: ; 3e687 (f:6687) 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,19 +5672,19 @@ asm_3e72b: ; 3e72b (f:672b) 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 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 @@ asm_3e7a4: ; 3e7a4 (f:67a4) 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 @@ asm_3e7ef: ; 3e7ef (f:67ef) 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 @@ asm_3e7ef: ; 3e7ef (f:67ef) 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 @@ asm_3e7ef: ; 3e7ef (f:67ef) 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 @@ BattleRandom: 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 @@ Func_3eed3: ; 3eed3 (f:6ed3) 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 @@ SleepEffect: ; 3f1fc (f:71fc) 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 @@ PoisonEffect: ; 3f24f (f:724f) 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 @@ PoisonEffect: ; 3f24f (f:724f) 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 @@ PoisonEffect: ; 3f24f (f:724f) .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 @@ ExplodeEffect: ; 3f2f1 (f:72f1) 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 @@ ExplodeEffect: ; 3f2f1 (f:72f1) 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 @@ opponentAttacker: ; 3f382 (f:7382) 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 @@ FrozenText: ; 3f3dd (f:73dd) 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 @@ StatModifierUpEffect: ; 3f428 (f:7428) 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 @@ StatModifierUpEffect: ; 3f428 (f:7428) 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 @@ asm_3f4ca: ; 3f4ca (f:74ca) 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,14 +7635,17 @@ asm_3f4ca: ; 3f4ca (f:74ca) 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 @@ -7638,95 +7684,97 @@ StatModifierDownEffect: ; 3f54c (f:754c) 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 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,19 +7803,19 @@ StatModifierDownEffect: ; 3f54c (f:754c) 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] 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 @@ asm_3f62c: ; 3f62c (f:762c) 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,14 +7844,14 @@ Func_3f64d: ; 3f64d (f:764d) pop hl inc [hl] -Func_3f650: ; 3f650 (f:7650) +CantLowerAnymore: ; 3f650 (f:7650) ld a, [de] cp ATTACK_DOWN_SIDE_EFFECT ret nc 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 @@ BideEffect: ; 3f6e5 (f:76e5) 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 @@ BideEffect: ; 3f6e5 (f:76e5) 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 @@ ThrashPetalDanceEffect: ; 3f717 (f:7717) 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 @@ SwitchAndTeleportEffect: ; 3f739 (f:7739) jp Func_3fb4e .asm_3f7e4 push af - call Func_3fbb9 + call PlayBattleAnimatiom ld c, $14 call DelayFrames pop af @@ -8036,43 +8089,44 @@ TwoToFiveAttacksEffect: ; 3f811 (f:7811) 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 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 @@ FlichSideEffect: ; 3f85b (f:785b) 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 @@ ChargeEffect: ; 3f88c (f:788c) 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 @@ TrappingEffect: ; 3f917 (f:7917) .asm_3f928 bit 5, [hl] ret nz - call Func_3f9cf + call ClearHyperBeam set 5, [hl] call BattleRandom and $3 @@ -8295,7 +8349,7 @@ HyperBeamEffect: ; 3f9c1 (f:79c1) 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 @@ Func_3fba8: ; 3fba8 (f:7ba8) and a ret z -Func_3fbb9: ; 3fbb9 (f:7bb9) +PlayBattleAnimatiom: ; 3fbb9 (f:7bb9) ld [W_ANIMATIONID], a Func_3fbbc: ; 3fbbc (f:7bbc) |