diff options
Diffstat (limited to 'engine')
| -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) | 
