summaryrefslogtreecommitdiff
path: root/engine/battle/effect_commands.asm
diff options
context:
space:
mode:
authorentrpntr <entrpntr@gmail.com>2020-04-19 12:31:56 -0400
committerentrpntr <entrpntr@gmail.com>2020-04-19 12:31:56 -0400
commite953302d3f81f080fd5d8423000496ce2fad36d3 (patch)
treebb66787122ec1029524153c96c3f34b66780e5c7 /engine/battle/effect_commands.asm
parente10598eb204358343491c92348b9220185e3b33d (diff)
Continue with effect commands (about 50% complete).
Diffstat (limited to 'engine/battle/effect_commands.asm')
-rw-r--r--engine/battle/effect_commands.asm2352
1 files changed, 2352 insertions, 0 deletions
diff --git a/engine/battle/effect_commands.asm b/engine/battle/effect_commands.asm
index 023730ac..7734c66f 100644
--- a/engine/battle/effect_commands.asm
+++ b/engine/battle/effect_commands.asm
@@ -1219,3 +1219,2355 @@ INCLUDE "data/moves/critical_hit_moves.asm"
INCLUDE "data/battle/critical_hit_chances.asm"
INCLUDE "engine/battle/move_effects/triple_kick.asm"
+
+BattleCommand_Stab:
+; STAB = Same Type Attack Bonus
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ cp STRUGGLE
+ ret z
+
+ ld hl, wBattleMonType1
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld hl, wEnemyMonType1
+ ld a, [hli]
+ ld d, a
+ ld e, [hl]
+
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .go ; Who Attacks and who Defends
+
+ ld hl, wEnemyMonType1
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld hl, wBattleMonType1
+ ld a, [hli]
+ ld d, a
+ ld e, [hl]
+
+.go
+ ld a, BATTLE_VARS_MOVE_TYPE
+ call GetBattleVarAddr
+ ld [wCurType], a
+
+ push hl
+ push de
+ push bc
+ farcall DoWeatherModifiers
+ pop bc
+ pop de
+ pop hl
+
+ push de
+ push bc
+ farcall DoBadgeTypeBoosts
+ pop bc
+ pop de
+
+ ld a, [wCurType]
+ cp b
+ jr z, .stab
+ cp c
+ jr z, .stab
+
+ jr .SkipStab
+
+.stab
+ ld hl, wCurDamage + 1
+ ld a, [hld]
+ ld h, [hl]
+ ld l, a
+
+ ld b, h
+ ld c, l
+ srl b
+ rr c
+ add hl, bc
+
+ ld a, h
+ ld [wCurDamage], a
+ ld a, l
+ ld [wCurDamage + 1], a
+
+ ld hl, wTypeModifier
+ set 7, [hl]
+
+.SkipStab:
+ ld a, BATTLE_VARS_MOVE_TYPE
+ call GetBattleVar
+ ld b, a
+ ld hl, TypeMatchups
+
+.TypesLoop:
+ ld a, [hli]
+
+ cp -1
+ jr z, .end
+
+ ; foresight
+ cp -2
+ jr nz, .SkipForesightCheck
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVar
+ bit SUBSTATUS_IDENTIFIED, a
+ jr nz, .end
+
+ jr .TypesLoop
+
+.SkipForesightCheck:
+ cp b
+ jr nz, .SkipType
+ ld a, [hl]
+ cp d
+ jr z, .GotMatchup
+ cp e
+ jr z, .GotMatchup
+ jr .SkipType
+
+.GotMatchup:
+ push hl
+ push bc
+ inc hl
+ ld a, [wTypeModifier]
+ and %10000000
+ ld b, a
+; If the target is immune to the move, treat it as a miss and calculate the damage as 0
+ ld a, [hl]
+ and a
+ jr nz, .NotImmune
+ inc a
+ ld [wAttackMissed], a
+ xor a
+.NotImmune:
+ ldh [hMultiplier], a
+ add b
+ ld [wTypeModifier], a
+
+ xor a
+ ldh [hMultiplicand + 0], a
+
+ ld hl, wCurDamage
+ ld a, [hli]
+ ldh [hMultiplicand + 1], a
+ ld a, [hld]
+ ldh [hMultiplicand + 2], a
+
+ call Multiply
+
+ ldh a, [hProduct + 1]
+ ld b, a
+ ldh a, [hProduct + 2]
+ or b
+ ld b, a
+ ldh a, [hProduct + 3]
+ or b
+ jr z, .ok ; This is a very convoluted way to get back that we've essentially dealt no damage.
+
+; Take the product and divide it by 10.
+ ld a, 10
+ ldh [hDivisor], a
+ ld b, 4
+ call Divide
+ ldh a, [hQuotient + 2]
+ ld b, a
+ ldh a, [hQuotient + 3]
+ or b
+ jr nz, .ok
+
+ ld a, 1
+ ldh [hMultiplicand + 2], a
+
+.ok
+ ldh a, [hMultiplicand + 1]
+ ld [hli], a
+ ldh a, [hMultiplicand + 2]
+ ld [hl], a
+ pop bc
+ pop hl
+
+.SkipType:
+ inc hl
+ inc hl
+ jr .TypesLoop
+
+.end
+ call BattleCheckTypeMatchup
+ ld a, [wTypeMatchup]
+ ld b, a
+ ld a, [wTypeModifier]
+ and %10000000
+ or b
+ ld [wTypeModifier], a
+ ret
+
+BattleCheckTypeMatchup:
+ ld hl, wEnemyMonType1
+ ldh a, [hBattleTurn]
+ and a
+ jr z, CheckTypeMatchup
+ ld hl, wBattleMonType1
+CheckTypeMatchup:
+; There is an incorrect assumption about this function made in the AI related code: when
+; the AI calls CheckTypeMatchup (not BattleCheckTypeMatchup), it assumes that placing the
+; offensive type in a will make this function do the right thing. Since a is overwritten,
+; this assumption is incorrect. A simple fix would be to load the move type for the
+; current move into a in BattleCheckTypeMatchup, before falling through, which is
+; consistent with how the rest of the code assumes this code works like.
+ push hl
+ push de
+ push bc
+ ld a, BATTLE_VARS_MOVE_TYPE
+ call GetBattleVar
+ ld d, a
+ ld b, [hl]
+ inc hl
+ ld c, [hl]
+ ld a, 10 ; 1.0
+ ld [wTypeMatchup], a
+ ld hl, TypeMatchups
+.TypesLoop:
+ ld a, [hli]
+ cp -1
+ jr z, .End
+ cp -2
+ jr nz, .Next
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVar
+ bit SUBSTATUS_IDENTIFIED, a
+ jr nz, .End
+ jr .TypesLoop
+
+.Next:
+ cp d
+ jr nz, .Nope
+ ld a, [hli]
+ cp b
+ jr z, .Yup
+ cp c
+ jr z, .Yup
+ jr .Nope2
+
+.Nope:
+ inc hl
+.Nope2:
+ inc hl
+ jr .TypesLoop
+
+.Yup:
+ xor a
+ ldh [hDividend + 0], a
+ ldh [hMultiplicand + 0], a
+ ldh [hMultiplicand + 1], a
+ ld a, [hli]
+ ldh [hMultiplicand + 2], a
+ ld a, [wTypeMatchup]
+ ldh [hMultiplier], a
+ call Multiply
+ ld a, 10
+ ldh [hDivisor], a
+ push bc
+ ld b, 4
+ call Divide
+ pop bc
+ ldh a, [hQuotient + 3]
+ ld [wTypeMatchup], a
+ jr .TypesLoop
+
+.End:
+ pop bc
+ pop de
+ pop hl
+ ret
+
+BattleCommand_ResetTypeMatchup:
+; Reset the type matchup multiplier to 1.0, if the type matchup is not 0.
+; If there is immunity in play, the move automatically misses.
+ call BattleCheckTypeMatchup
+ ld a, [wTypeMatchup]
+ and a
+ ld a, 10 ; 1.0
+ jr nz, .reset
+ call ResetDamage
+ xor a
+ ld [wTypeModifier], a
+ inc a
+ ld [wAttackMissed], a
+ ret
+
+.reset
+ ld [wTypeMatchup], a
+ ret
+
+INCLUDE "engine/battle/ai/switch.asm"
+
+INCLUDE "data/types/type_matchups.asm"
+
+BattleCommand_DamageVariation:
+; damagevariation
+
+; Modify the damage spread between 85% and 100%.
+
+; Because of the method of division the probability distribution
+; is not consistent. This makes the highest damage multipliers
+; rarer than normal.
+
+; No point in reducing 1 or 0 damage.
+ ld hl, wCurDamage
+ ld a, [hli]
+ and a
+ jr nz, .go
+ ld a, [hl]
+ cp 2
+ ret c
+
+.go
+; Start with the maximum damage.
+ xor a
+ ldh [hMultiplicand + 0], a
+ dec hl
+ ld a, [hli]
+ ldh [hMultiplicand + 1], a
+ ld a, [hl]
+ ldh [hMultiplicand + 2], a
+
+; Multiply by 85-100%...
+.loop
+ call BattleRandom
+ rrca
+ cp 85 percent + 1
+ jr c, .loop
+
+ ldh [hMultiplier], a
+ call Multiply
+
+; ...divide by 100%...
+ ld a, $ff ; 100%
+ ldh [hDivisor], a
+ ld b, $4
+ call Divide
+
+; ...to get .85-1.00x damage.
+ ldh a, [hQuotient + 2]
+ ld hl, wCurDamage
+ ld [hli], a
+ ldh a, [hQuotient + 3]
+ ld [hl], a
+ ret
+
+BattleCommand_CheckHit:
+; checkhit
+
+ call .DreamEater
+ jp z, .Miss
+
+ call .Protect
+ jp nz, .Miss
+
+ call .DrainSub
+ jp z, .Miss
+
+ call .LockOn
+ ret nz
+
+ call .FlyDigMoves
+ jp nz, .Miss
+
+ call .ThunderRain
+ ret z
+
+ call .XAccuracy
+ ret nz
+
+ ; Perfect-accuracy moves
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_ALWAYS_HIT
+ ret z
+
+ call .StatModifiers
+
+ ld a, [wPlayerMoveStruct + MOVE_ACC]
+ ld b, a
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .BrightPowder
+ ld a, [wEnemyMoveStruct + MOVE_ACC]
+ ld b, a
+
+.BrightPowder:
+ push bc
+ call GetOpponentItem
+ ld a, b
+ cp HELD_BRIGHTPOWDER
+ ld a, c ; % miss
+ pop bc
+ jr nz, .skip_brightpowder
+
+ ld c, a
+ ld a, b
+ sub c
+ ld b, a
+ jr nc, .skip_brightpowder
+ ld b, 0
+
+.skip_brightpowder
+ ld a, b
+ cp -1
+ jr z, .Hit
+
+ call BattleRandom
+ cp b
+ jr nc, .Miss
+
+.Hit:
+ ret
+
+.Miss:
+; Keep the damage value intact if we're using (Hi) Jump Kick.
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_JUMP_KICK
+ jr z, .Missed
+ call ResetDamage
+
+.Missed:
+ ld a, 1
+ ld [wAttackMissed], a
+ ret
+
+.DreamEater:
+; Return z if we're trying to eat the dream of
+; a monster that isn't sleeping.
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_DREAM_EATER
+ ret nz
+
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVar
+ and SLP
+ ret
+
+.Protect:
+; Return nz if the opponent is protected.
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVar
+ bit SUBSTATUS_PROTECT, a
+ ret z
+
+ ld c, 40
+ call DelayFrames
+
+; 'protecting itself!'
+ ld hl, ProtectingItselfText
+ call StdBattleTextbox
+
+ ld c, 40
+ call DelayFrames
+
+ ld a, 1
+ and a
+ ret
+
+.LockOn:
+; Return nz if we are locked-on and aren't trying to use Earthquake,
+; Fissure or Magnitude on a monster that is flying.
+ ld a, BATTLE_VARS_SUBSTATUS5_OPP
+ call GetBattleVarAddr
+ bit SUBSTATUS_LOCK_ON, [hl]
+ res SUBSTATUS_LOCK_ON, [hl]
+ ret z
+
+ ld a, BATTLE_VARS_SUBSTATUS3_OPP
+ call GetBattleVar
+ bit SUBSTATUS_FLYING, a
+ jr z, .LockedOn
+
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+
+ cp EARTHQUAKE
+ ret z
+ cp FISSURE
+ ret z
+ cp MAGNITUDE
+ ret z
+
+.LockedOn:
+ ld a, 1
+ and a
+ ret
+
+.DrainSub:
+; Return z if using an HP drain move on a substitute.
+ call CheckSubstituteOpp
+ jr z, .not_draining_sub
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+
+ cp EFFECT_LEECH_HIT
+ ret z
+ cp EFFECT_DREAM_EATER
+ ret z
+
+.not_draining_sub
+ ld a, 1
+ and a
+ ret
+
+.FlyDigMoves:
+; Check for moves that can hit underground/flying opponents.
+; Return z if the current move can hit the opponent.
+
+ ld a, BATTLE_VARS_SUBSTATUS3_OPP
+ call GetBattleVar
+ and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ ret z
+
+ bit SUBSTATUS_FLYING, a
+ jr z, .DigMoves
+
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+
+ cp GUST
+ ret z
+ cp WHIRLWIND
+ ret z
+ cp THUNDER
+ ret z
+ cp TWISTER
+ ret
+
+.DigMoves:
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+
+ cp EARTHQUAKE
+ ret z
+ cp FISSURE
+ ret z
+ cp MAGNITUDE
+ ret
+
+.ThunderRain:
+; Return z if the current move always hits in rain, and it is raining.
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_THUNDER
+ ret nz
+
+ ld a, [wBattleWeather]
+ cp WEATHER_RAIN
+ ret
+
+.XAccuracy:
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVar
+ bit SUBSTATUS_X_ACCURACY, a
+ ret
+
+.StatModifiers:
+ ldh a, [hBattleTurn]
+ and a
+
+ ; load the user's accuracy into b and the opponent's evasion into c.
+ ld hl, wPlayerMoveStruct + MOVE_ACC
+ ld a, [wPlayerAccLevel]
+ ld b, a
+ ld a, [wEnemyEvaLevel]
+ ld c, a
+
+ jr z, .got_acc_eva
+
+ ld hl, wEnemyMoveStruct + MOVE_ACC
+ ld a, [wEnemyAccLevel]
+ ld b, a
+ ld a, [wPlayerEvaLevel]
+ ld c, a
+
+.got_acc_eva
+ cp b
+ jr c, .skip_foresight_check
+
+ ; if the target's evasion is greater than the user's accuracy,
+ ; check the target's foresight status
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVar
+ bit SUBSTATUS_IDENTIFIED, a
+ ret nz
+
+.skip_foresight_check
+ ; subtract evasion from 14
+ ld a, MAX_STAT_LEVEL + 1
+ sub c
+ ld c, a
+ ; store the base move accuracy for math ops
+ xor a
+ ldh [hMultiplicand + 0], a
+ ldh [hMultiplicand + 1], a
+ ld a, [hl]
+ ldh [hMultiplicand + 2], a
+ push hl
+ ld d, 2 ; do this twice, once for the user's accuracy and once for the target's evasion
+
+.accuracy_loop
+ ; look up the multiplier from the table
+ push bc
+ ld hl, AccuracyLevelMultipliers
+ dec b
+ sla b
+ ld c, b
+ ld b, 0
+ add hl, bc
+ pop bc
+ ; multiply by the first byte in that row...
+ ld a, [hli]
+ ldh [hMultiplier], a
+ call Multiply
+ ; ... and divide by the second byte
+ ld a, [hl]
+ ldh [hDivisor], a
+ ld b, 4
+ call Divide
+ ; minimum accuracy is $0001
+ ldh a, [hQuotient + 3]
+ ld b, a
+ ldh a, [hQuotient + 2]
+ or b
+ jr nz, .min_accuracy
+ ldh [hQuotient + 2], a
+ ld a, 1
+ ldh [hQuotient + 3], a
+
+.min_accuracy
+ ; do the same thing to the target's evasion
+ ld b, c
+ dec d
+ jr nz, .accuracy_loop
+
+ ; if the result is more than 2 bytes, max out at 100%
+ ldh a, [hQuotient + 2]
+ and a
+ ldh a, [hQuotient + 3]
+ jr z, .finish_accuracy
+ ld a, $ff
+
+.finish_accuracy
+ pop hl
+ ld [hl], a
+ ret
+
+INCLUDE "data/battle/accuracy_multipliers.asm"
+
+BattleCommand_EffectChance:
+; effectchance
+
+ xor a
+ ld [wEffectFailed], a
+ call CheckSubstituteOpp
+ jr nz, .failed
+
+ push hl
+ ld hl, wPlayerMoveStruct + MOVE_CHANCE
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_move_chance
+ ld hl, wEnemyMoveStruct + MOVE_CHANCE
+.got_move_chance
+
+ ; BUG: 1/256 chance to fail even for a 100% effect chance,
+ ; since carry is not set if BattleRandom == [hl] == 255
+ call BattleRandom
+ cp [hl]
+ pop hl
+ ret c
+
+.failed
+ ld a, 1
+ ld [wEffectFailed], a
+ and a
+ ret
+
+BattleCommand_LowerSub:
+; lowersub
+
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVar
+ bit SUBSTATUS_SUBSTITUTE, a
+ ret z
+
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVar
+ bit SUBSTATUS_CHARGED, a
+ jr nz, .already_charged
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_RAZOR_WIND
+ jr z, .charge_turn
+ cp EFFECT_SKY_ATTACK
+ jr z, .charge_turn
+ cp EFFECT_SKULL_BASH
+ jr z, .charge_turn
+ cp EFFECT_SOLARBEAM
+ jr z, .charge_turn
+ cp EFFECT_FLY
+ jr z, .charge_turn
+
+.already_charged
+ call .Rampage
+ jr z, .charge_turn
+
+ call CheckUserIsCharging
+ ret nz
+
+.charge_turn
+ ; check battle scene
+ ld a, [wOptions]
+ add a
+ jr c, .mimic_anims
+
+ xor a
+ ld [wNumHits], a
+ ld [wFXAnimID + 1], a
+ inc a
+ ld [wKickCounter], a
+ ld a, SUBSTITUTE
+ jp LoadAnim
+
+.mimic_anims
+ call BattleCommand_LowerSubNoAnim
+ jp BattleCommand_MoveDelay
+
+.Rampage:
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_ROLLOUT
+ jr z, .rollout_rampage
+ cp EFFECT_RAMPAGE
+ jr z, .rollout_rampage
+
+ ld a, 1
+ and a
+ ret
+
+.rollout_rampage
+ ld a, [wSomeoneIsRampaging]
+ and a
+ ld a, 0
+ ld [wSomeoneIsRampaging], a
+ ret
+
+BattleCommand_MoveAnim:
+; moveanim
+ call BattleCommand_LowerSub
+ call BattleCommand_MoveAnimNoSub
+ jp BattleCommand_RaiseSub
+
+BattleCommand_MoveAnimNoSub:
+ ld a, [wAttackMissed]
+ and a
+ jp nz, BattleCommand_MoveDelay
+
+ ldh a, [hBattleTurn]
+ and a
+ ld de, wPlayerRolloutCount
+ ld a, BATTLEANIM_ENEMY_DAMAGE
+ jr z, .got_rollout_count
+ ld de, wEnemyRolloutCount
+ ld a, BATTLEANIM_PLAYER_DAMAGE
+
+.got_rollout_count
+ ld [wNumHits], a
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_MULTI_HIT
+ jr z, .alternate_anim
+ cp EFFECT_CONVERSION
+ jr z, .alternate_anim
+ cp EFFECT_DOUBLE_HIT
+ jr z, .alternate_anim
+ cp EFFECT_POISON_MULTI_HIT
+ jr z, .alternate_anim
+ cp EFFECT_TRIPLE_KICK
+ jr z, .triplekick
+ xor a
+ ld [wKickCounter], a
+
+.triplekick
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ ld e, a
+ ld d, 0
+ call PlayFXAnimID
+
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ cp FLY
+ jr z, .clear_sprite
+ cp DIG
+ ret nz
+.clear_sprite
+ jp AppearUserLowerSub
+
+.alternate_anim
+ ld a, [wKickCounter]
+ and 1
+ xor 1
+ ld [wKickCounter], a
+ ld a, [de]
+ cp 1
+ push af
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ ld e, a
+ ld d, 0
+ pop af
+ jp z, PlayFXAnimID
+ xor a
+ ld [wNumHits], a
+ jp PlayFXAnimID
+
+BattleCommand_StatUpAnim:
+ ld a, [wAttackMissed]
+ and a
+ jp nz, BattleCommand_MoveDelay
+
+ xor a
+ jr BattleCommand_StatUpDownAnim
+
+BattleCommand_StatDownAnim:
+ ld a, [wAttackMissed]
+ and a
+ jp nz, BattleCommand_MoveDelay
+
+ ldh a, [hBattleTurn]
+ and a
+ ld a, BATTLEANIM_ENEMY_STAT_DOWN
+ jr z, BattleCommand_StatUpDownAnim
+ ld a, BATTLEANIM_WOBBLE
+
+ ; fallthrough
+
+BattleCommand_StatUpDownAnim:
+ ld [wNumHits], a
+ xor a
+ ld [wKickCounter], a
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ ld e, a
+ ld d, 0
+ jp PlayFXAnimID
+
+BattleCommand_SwitchTurn:
+; switchturn
+
+ ldh a, [hBattleTurn]
+ xor 1
+ ldh [hBattleTurn], a
+ ret
+
+BattleCommand_RaiseSub:
+; raisesub
+
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVar
+ bit SUBSTATUS_SUBSTITUTE, a
+ ret z
+
+ ; check battle scene
+ ld a, [wOptions]
+ add a
+ jp c, BattleCommand_RaiseSubNoAnim
+
+ xor a
+ ld [wNumHits], a
+ ld [wFXAnimID + 1], a
+ ld a, $2
+ ld [wKickCounter], a
+ ld a, SUBSTITUTE
+ jp LoadAnim
+
+BattleCommand_FailureText:
+; failuretext
+; If the move missed or failed, load the appropriate
+; text, and end the effects of multi-turn or multi-
+; hit moves.
+ ld a, [wAttackMissed]
+ and a
+ ret z
+
+ call GetFailureResultText
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVarAddr
+
+ cp FLY
+ jr z, .fly_dig
+ cp DIG
+ jr z, .fly_dig
+
+; Move effect:
+ inc hl
+ ld a, [hl]
+
+ cp EFFECT_MULTI_HIT
+ jr z, .multihit
+ cp EFFECT_DOUBLE_HIT
+ jr z, .multihit
+ cp EFFECT_POISON_MULTI_HIT
+ jr z, .multihit
+ jp EndMoveEffect
+
+.multihit
+ call BattleCommand_RaiseSub
+ jp EndMoveEffect
+
+.fly_dig
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVarAddr
+ res SUBSTATUS_UNDERGROUND, [hl]
+ res SUBSTATUS_FLYING, [hl]
+ call AppearUserRaiseSub
+ jp EndMoveEffect
+
+BattleCommand_ApplyDamage:
+; applydamage
+
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVar
+ bit SUBSTATUS_ENDURE, a
+ jr z, .focus_band
+
+ call BattleCommand_FalseSwipe
+ ld b, 0
+ jr nc, .damage
+ ld b, 1
+ jr .damage
+
+.focus_band
+ call GetOpponentItem
+ ld a, b
+ cp HELD_FOCUS_BAND
+ ld b, 0
+ jr nz, .damage
+
+ call BattleRandom
+ cp c
+ jr nc, .damage
+ call BattleCommand_FalseSwipe
+ ld b, 0
+ jr nc, .damage
+ ld b, 2
+
+.damage
+ push bc
+ call .update_damage_taken
+ ld c, FALSE
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .damage_player
+ call DoEnemyDamage
+ jr .done_damage
+
+.damage_player
+ call DoPlayerDamage
+
+.done_damage
+ pop bc
+ ld a, b
+ and a
+ ret z
+
+ dec a
+ jr nz, .focus_band_text
+ ld hl, EnduredText
+ jp StdBattleTextbox
+
+.focus_band_text
+ call GetOpponentItem
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ call GetItemName
+ ld hl, HungOnText
+ jp StdBattleTextbox
+
+.update_damage_taken
+ ld a, BATTLE_VARS_SUBSTATUS4_OPP
+ call GetBattleVar
+ bit SUBSTATUS_SUBSTITUTE, a
+ ret nz
+
+ ld de, wPlayerDamageTaken + 1
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .got_damage_taken
+ ld de, wEnemyDamageTaken + 1
+
+.got_damage_taken
+ ld a, [wCurDamage + 1]
+ ld b, a
+ ld a, [de]
+ add b
+ ld [de], a
+ dec de
+ ld a, [wCurDamage]
+ ld b, a
+ ld a, [de]
+ adc b
+ ld [de], a
+ ret nc
+ ld a, $ff
+ ld [de], a
+ inc de
+ ld [de], a
+ ret
+
+GetFailureResultText:
+ ld hl, DoesntAffectText
+ ld de, DoesntAffectText
+ ld a, [wTypeModifier]
+ and $7f
+ jr z, .got_text
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_FUTURE_SIGHT
+ ld hl, ButItFailedText
+ ld de, ItFailedText
+ jr z, .got_text
+ ld hl, AttackMissedText
+ ld de, AttackMissed2Text
+ ld a, [wCriticalHit]
+ cp -1
+ jr nz, .got_text
+ ld hl, UnaffectedText
+.got_text
+ call FailText_CheckOpponentProtect
+ xor a
+ ld [wCriticalHit], a
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_JUMP_KICK
+ ret nz
+
+ ld a, [wTypeModifier]
+ and $7f
+ ret z
+
+ ld hl, wCurDamage
+ ld a, [hli]
+ ld b, [hl]
+rept 3
+ srl a
+ rr b
+endr
+ ld [hl], b
+ dec hl
+ ld [hli], a
+ or b
+ jr nz, .do_at_least_1_damage
+ inc a
+ ld [hl], a
+.do_at_least_1_damage
+ ld hl, CrashedText
+ call StdBattleTextbox
+ ld a, $1
+ ld [wKickCounter], a
+ call LoadMoveAnim
+ ld c, TRUE
+ ldh a, [hBattleTurn]
+ and a
+ jp nz, DoEnemyDamage
+ jp DoPlayerDamage
+
+FailText_CheckOpponentProtect:
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVar
+ bit SUBSTATUS_PROTECT, a
+ jr z, .not_protected
+ ld h, d
+ ld l, e
+.not_protected
+ jp StdBattleTextbox
+
+BattleCommand_BideFailText:
+ ld a, [wAttackMissed]
+ and a
+ ret z
+
+ ld a, [wTypeModifier]
+ and $7f
+ jp z, PrintDoesntAffect
+ jp PrintButItFailed
+
+BattleCommand_CriticalText:
+; criticaltext
+; Prints the message for critical hits or one-hit KOs.
+
+; If there is no message to be printed, wait 20 frames.
+ ld a, [wCriticalHit]
+ and a
+ jr z, .wait
+
+ dec a
+ add a
+ ld hl, .texts
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call StdBattleTextbox
+
+ xor a
+ ld [wCriticalHit], a
+
+.wait
+ ld c, 20
+ jp DelayFrames
+
+.texts
+ dw CriticalHitText
+ dw OneHitKOText
+
+BattleCommand_StartLoop:
+; startloop
+
+ ld hl, wPlayerRolloutCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld hl, wEnemyRolloutCount
+.ok
+ xor a
+ ld [hl], a
+ ret
+
+BattleCommand_SuperEffectiveLoopText:
+; supereffectivelooptext
+
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVarAddr
+ bit SUBSTATUS_IN_LOOP, a
+ ret nz
+
+ ; fallthrough
+
+BattleCommand_SuperEffectiveText:
+; supereffectivetext
+
+ ld a, [wTypeModifier]
+ and $7f
+ cp 10 ; 1.0
+ ret z
+ ld hl, SuperEffectiveText
+ jr nc, .print
+ ld hl, NotVeryEffectiveText
+.print
+ jp StdBattleTextbox
+
+BattleCommand_CheckFaint:
+; checkfaint
+
+; Faint the opponent if its HP reached zero
+; and faint the user along with it if it used Destiny Bond.
+; Ends the move effect if the opponent faints.
+
+ ld hl, wEnemyMonHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_hp
+ ld hl, wBattleMonHP
+
+.got_hp
+ ld a, [hli]
+ or [hl]
+ ret nz
+
+ ld a, BATTLE_VARS_SUBSTATUS5_OPP
+ call GetBattleVar
+ bit SUBSTATUS_DESTINY_BOND, a
+ jr z, .no_dbond
+
+ ld hl, TookDownWithItText
+ call StdBattleTextbox
+
+ ldh a, [hBattleTurn]
+ and a
+ ld hl, wEnemyMonMaxHP + 1
+ bccoord 2, 2 ; hp bar
+ ld a, 0
+ jr nz, .got_max_hp
+ ld hl, wBattleMonMaxHP + 1
+ bccoord 10, 9 ; hp bar
+ ld a, 1
+
+.got_max_hp
+ ld [wWhichHPBar], a
+ ld a, [hld]
+ ld [wBuffer1], a
+ ld a, [hld]
+ ld [wBuffer2], a
+ ld a, [hl]
+ ld [wBuffer3], a
+ xor a
+ ld [hld], a
+ ld a, [hl]
+ ld [wBuffer4], a
+ xor a
+ ld [hl], a
+ ld [wBuffer5], a
+ ld [wBuffer6], a
+ ld h, b
+ ld l, c
+ predef AnimateHPBar
+ call RefreshBattleHuds
+
+ call BattleCommand_SwitchTurn
+ xor a
+ ld [wNumHits], a
+ ld [wFXAnimID + 1], a
+ inc a
+ ld [wKickCounter], a
+ ld a, DESTINY_BOND
+ call LoadAnim
+ call BattleCommand_SwitchTurn
+
+ jr .finish
+
+.no_dbond
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_MULTI_HIT
+ jr z, .multiple_hit_raise_sub
+ cp EFFECT_DOUBLE_HIT
+ jr z, .multiple_hit_raise_sub
+ cp EFFECT_POISON_MULTI_HIT
+ jr z, .multiple_hit_raise_sub
+ cp EFFECT_TRIPLE_KICK
+ jr z, .multiple_hit_raise_sub
+ cp EFFECT_BEAT_UP
+ jr nz, .finish
+
+.multiple_hit_raise_sub
+ call BattleCommand_RaiseSub
+
+.finish
+ jp EndMoveEffect
+
+BattleCommand_BuildOpponentRage:
+; buildopponentrage
+
+ jp .start
+
+.start
+ ld a, [wAttackMissed]
+ and a
+ ret nz
+
+ ld a, BATTLE_VARS_SUBSTATUS4_OPP
+ call GetBattleVar
+ bit SUBSTATUS_RAGE, a
+ ret z
+
+ ld de, wEnemyRageCounter
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .player
+ ld de, wPlayerRageCounter
+.player
+ ld a, [de]
+ inc a
+ ret z
+ ld [de], a
+
+ call BattleCommand_SwitchTurn
+ ld hl, RageBuildingText
+ call StdBattleTextbox
+ jp BattleCommand_SwitchTurn
+
+BattleCommand_RageDamage:
+; ragedamage
+
+ ld a, [wCurDamage]
+ ld h, a
+ ld b, a
+ ld a, [wCurDamage + 1]
+ ld l, a
+ ld c, a
+ ldh a, [hBattleTurn]
+ and a
+ ld a, [wPlayerRageCounter]
+ jr z, .rage_loop
+ ld a, [wEnemyRageCounter]
+.rage_loop
+ and a
+ jr z, .done
+ dec a
+ add hl, bc
+ jr nc, .rage_loop
+ ld hl, $ffff
+.done
+ ld a, h
+ ld [wCurDamage], a
+ ld a, l
+ ld [wCurDamage + 1], a
+ ret
+
+EndMoveEffect:
+ ld a, [wBattleScriptBufferAddress]
+ ld l, a
+ ld a, [wBattleScriptBufferAddress + 1]
+ ld h, a
+ ld a, $ff
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ret
+
+DittoMetalPowder:
+ ld a, MON_SPECIES
+ call BattlePartyAttr
+ ldh a, [hBattleTurn]
+ and a
+ ld a, [hl]
+ jr nz, .Ditto
+ ld a, [wTempEnemyMonSpecies]
+
+.Ditto:
+ cp DITTO
+ ret nz
+
+ push bc
+ call GetOpponentItem
+ ld a, [hl]
+ cp METAL_POWDER
+ pop bc
+ ret nz
+
+ ld a, c
+ srl a
+ add c
+ ld c, a
+ ret nc
+
+ srl b
+ ld a, b
+ and a
+ jr nz, .done
+ inc b
+.done
+ scf
+ rr c
+ ret
+
+BattleCommand_DamageStats:
+; damagestats
+
+ ldh a, [hBattleTurn]
+ and a
+ jp nz, EnemyAttackDamage
+
+ ; fallthrough
+
+PlayerAttackDamage:
+; Return move power d, player level e, enemy defense c and player attack b.
+
+ call ResetDamage
+
+ ld hl, wPlayerMoveStructPower
+ ld a, [hli]
+ and a
+ ld d, a
+ ret z
+
+ ld a, [hl]
+ cp SPECIAL
+ jr nc, .special
+
+.physical
+ ld hl, wEnemyMonDefense
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+
+ ld a, [wEnemyScreens]
+ bit SCREENS_REFLECT, a
+ jr z, .physicalcrit
+ sla c
+ rl b
+
+.physicalcrit
+ ld hl, wBattleMonAttack
+ call CheckDamageStatsCritical
+ jr c, .thickclub
+
+ ld hl, wEnemyDefense
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld hl, wPlayerAttack
+ jr .thickclub
+
+.special
+ ld hl, wEnemyMonSpclDef
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+
+ ld a, [wEnemyScreens]
+ bit SCREENS_LIGHT_SCREEN, a
+ jr z, .specialcrit
+ sla c
+ rl b
+
+.specialcrit
+ ld hl, wBattleMonSpclAtk
+ call CheckDamageStatsCritical
+ jr c, .lightball
+
+ ld hl, wEnemySpDef
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld hl, wPlayerSpAtk
+
+.lightball
+; Note: Returns player special attack at hl in hl.
+ call LightBallBoost
+ jr .done
+
+.thickclub
+; Note: Returns player attack at hl in hl.
+ call ThickClubBoost
+
+.done
+ call TruncateHL_BC
+
+ ld a, [wBattleMonLevel]
+ ld e, a
+ call DittoMetalPowder
+
+ ld a, 1
+ and a
+ ret
+
+TruncateHL_BC:
+.loop
+; Truncate 16-bit values hl and bc to 8-bit values b and c respectively.
+; b = hl, c = bc
+
+ ld a, h
+ or b
+ jr z, .done
+
+ srl b
+ rr c
+ srl b
+ rr c
+
+ ld a, c
+ or b
+ jr nz, .done_bc
+ inc c
+
+.done_bc
+ srl h
+ rr l
+ srl h
+ rr l
+
+ ld a, l
+ or h
+ jr nz, .done
+ inc l
+
+.done
+ ld b, l
+ ret
+
+CheckDamageStatsCritical:
+; Return carry if boosted stats should be used in damage calculations.
+; Unboosted stats should be used if the attack is a critical hit,
+; and the stage of the opponent's defense is higher than the user's attack.
+
+ ld a, [wCriticalHit]
+ and a
+ scf
+ ret z
+
+ push hl
+ push bc
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .enemy
+ ld a, [wPlayerMoveStructType]
+ cp SPECIAL
+; special
+ ld a, [wPlayerSAtkLevel]
+ ld b, a
+ ld a, [wEnemySDefLevel]
+ jr nc, .end
+; physical
+ ld a, [wPlayerAtkLevel]
+ ld b, a
+ ld a, [wEnemyDefLevel]
+ jr .end
+
+.enemy
+ ld a, [wEnemyMoveStructType]
+ cp SPECIAL
+; special
+ ld a, [wEnemySAtkLevel]
+ ld b, a
+ ld a, [wPlayerSDefLevel]
+ jr nc, .end
+; physical
+ ld a, [wEnemyAtkLevel]
+ ld b, a
+ ld a, [wPlayerDefLevel]
+.end
+ cp b
+ pop bc
+ pop hl
+ ret
+
+ThickClubBoost:
+; Return in hl the stat value at hl.
+
+; If the attacking monster is Cubone or Marowak and
+; it's holding a Thick Club, double it.
+ push bc
+ push de
+ ld b, CUBONE
+ ld c, MAROWAK
+ ld d, THICK_CLUB
+ call SpeciesItemBoost
+ pop de
+ pop bc
+ ret
+
+LightBallBoost:
+; Return in hl the stat value at hl.
+
+; If the attacking monster is Pikachu and it's
+; holding a Light Ball, double it.
+ push bc
+ push de
+ ld b, PIKACHU
+ ld c, PIKACHU
+ ld d, LIGHT_BALL
+ call SpeciesItemBoost
+ pop de
+ pop bc
+ ret
+
+SpeciesItemBoost:
+; Return in hl the stat value at hl.
+
+; If the attacking monster is species b or c and
+; it's holding item d, double it.
+
+ ld a, [hli]
+ ld l, [hl]
+ ld h, a
+
+ push hl
+ ld a, MON_SPECIES
+ call BattlePartyAttr
+
+ ldh a, [hBattleTurn]
+ and a
+ ld a, [hl]
+ jr z, .CompareSpecies
+ ld a, [wTempEnemyMonSpecies]
+.CompareSpecies:
+ pop hl
+
+ cp b
+ jr z, .GetItemHeldEffect
+ cp c
+ ret nz
+
+.GetItemHeldEffect:
+ push hl
+ call GetUserItem
+ ld a, [hl]
+ pop hl
+ cp d
+ ret nz
+
+; Double the stat
+ sla l
+ rl h
+ ret
+
+EnemyAttackDamage:
+ call ResetDamage
+
+; No damage dealt with 0 power.
+ ld hl, wEnemyMoveStructPower
+ ld a, [hli] ; hl = wEnemyMoveStructType
+ ld d, a
+ and a
+ ret z
+
+ ld a, [hl]
+ cp SPECIAL
+ jr nc, .Special
+
+.physical
+ ld hl, wBattleMonDefense
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+
+ ld a, [wPlayerScreens]
+ bit SCREENS_REFLECT, a
+ jr z, .physicalcrit
+ sla c
+ rl b
+
+.physicalcrit
+ ld hl, wEnemyMonAttack
+ call CheckDamageStatsCritical
+ jr c, .thickclub
+
+ ld hl, wPlayerDefense
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld hl, wEnemyAttack
+ jr .thickclub
+
+.Special:
+ ld hl, wBattleMonSpclDef
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+
+ ld a, [wPlayerScreens]
+ bit SCREENS_LIGHT_SCREEN, a
+ jr z, .specialcrit
+ sla c
+ rl b
+
+.specialcrit
+ ld hl, wEnemyMonSpclAtk
+ call CheckDamageStatsCritical
+ jr c, .lightball
+ ld hl, wPlayerSpDef
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld hl, wEnemySpAtk
+
+.lightball
+ call LightBallBoost
+ jr .done
+
+.thickclub
+ call ThickClubBoost
+
+.done
+ call TruncateHL_BC
+
+ ld a, [wEnemyMonLevel]
+ ld e, a
+ call DittoMetalPowder
+
+ ld a, 1
+ and a
+ ret
+
+INCLUDE "engine/battle/move_effects/beat_up.asm"
+
+BattleCommand_ClearMissDamage:
+; clearmissdamage
+ ld a, [wAttackMissed]
+ and a
+ ret z
+
+ jp ResetDamage
+
+HitSelfInConfusion:
+ call ResetDamage
+ ldh a, [hBattleTurn]
+ and a
+ ld hl, wBattleMonDefense
+ ld de, wPlayerScreens
+ ld a, [wBattleMonLevel]
+ jr z, .got_it
+
+ ld hl, wEnemyMonDefense
+ ld de, wEnemyScreens
+ ld a, [wEnemyMonLevel]
+.got_it
+ push af
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld a, [de]
+ bit SCREENS_REFLECT, a
+ jr z, .mimic_screen
+
+ sla c
+ rl b
+.mimic_screen
+ dec hl
+ dec hl
+ dec hl
+ ld a, [hli]
+ ld l, [hl]
+ ld h, a
+ call TruncateHL_BC
+ ld d, 40
+ pop af
+ ld e, a
+ ret
+
+BattleCommand_DamageCalc:
+; damagecalc
+
+; Return a damage value for move power d, player level e, enemy defense c and player attack b.
+
+; Return 1 if successful, else 0.
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+
+; Selfdestruct and Explosion halve defense.
+ cp EFFECT_SELFDESTRUCT
+ jr nz, .dont_selfdestruct
+
+ srl c
+ jr nz, .dont_selfdestruct
+ inc c
+
+.dont_selfdestruct
+
+; Variable-hit moves and Conversion can have a power of 0.
+ cp EFFECT_MULTI_HIT
+ jr z, .skip_zero_damage_check
+
+ cp EFFECT_CONVERSION
+ jr z, .skip_zero_damage_check
+
+; No damage if move power is 0.
+ ld a, d
+ and a
+ ret z
+
+.skip_zero_damage_check
+; Minimum defense value is 1.
+ ld a, c
+ and a
+ jr nz, .not_dividing_by_zero
+ ld c, 1
+.not_dividing_by_zero
+
+ xor a
+ ld hl, hDividend
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+
+; Level * 2
+ ld a, e
+ add a
+ jr nc, .level_not_overflowing
+ ld [hl], 1
+.level_not_overflowing
+ inc hl
+ ld [hli], a
+
+; / 5
+ ld a, 5
+ ld [hld], a
+ push bc
+ ld b, 4
+ call Divide
+ pop bc
+
+; + 2
+ inc [hl]
+ inc [hl]
+
+; * bp
+ inc hl
+ ld [hl], d
+ call Multiply
+
+; * Attack
+ ld [hl], b
+ call Multiply
+
+; / Defense
+ ld [hl], c
+ ld b, 4
+ call Divide
+
+; / 50
+ ld [hl], 50
+ ld b, $4
+ call Divide
+
+; Item boosts
+ call GetUserItem
+
+ ld a, b
+ and a
+ jr z, .DoneItem
+
+ ld hl, TypeBoostItems
+
+.NextItem:
+ ld a, [hli]
+ cp -1
+ jr z, .DoneItem
+
+; Item effect
+ cp b
+ ld a, [hli]
+ jr nz, .NextItem
+
+; Type
+ ld b, a
+ ld a, BATTLE_VARS_MOVE_TYPE
+ call GetBattleVar
+ cp b
+ jr nz, .DoneItem
+
+; * 100 + item effect amount
+ ld a, c
+ add 100
+ ldh [hMultiplier], a
+ call Multiply
+
+; / 100
+ ld a, 100
+ ldh [hDivisor], a
+ ld b, 4
+ call Divide
+
+.DoneItem:
+; Critical hits
+ call .CriticalMultiplier
+
+; Update wCurDamage (capped at 997).
+ ld hl, wCurDamage
+ ld b, [hl]
+ ldh a, [hProduct + 3]
+ add b
+ ldh [hProduct + 3], a
+ jr nc, .dont_cap_1
+
+ ldh a, [hProduct + 2]
+ inc a
+ ldh [hProduct + 2], a
+ and a
+ jr z, .Cap
+
+.dont_cap_1
+ ldh a, [hProduct]
+ ld b, a
+ ldh a, [hProduct + 1]
+ or a
+ jr nz, .Cap
+
+ ldh a, [hProduct + 2]
+ cp HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1)
+ jr c, .dont_cap_2
+
+ cp HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1) + 1
+ jr nc, .Cap
+
+ ldh a, [hProduct + 3]
+ cp LOW(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1)
+ jr nc, .Cap
+
+.dont_cap_2
+ inc hl
+
+ ldh a, [hProduct + 3]
+ ld b, [hl]
+ add b
+ ld [hld], a
+
+ ldh a, [hProduct + 2]
+ ld b, [hl]
+ adc b
+ ld [hl], a
+ jr c, .Cap
+
+ ld a, [hl]
+ cp HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1)
+ jr c, .dont_cap_3
+
+ cp HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1) + 1
+ jr nc, .Cap
+
+ inc hl
+ ld a, [hld]
+ cp LOW(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1)
+ jr c, .dont_cap_3
+
+.Cap:
+ ld a, HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE)
+ ld [hli], a
+ ld a, LOW(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE)
+ ld [hld], a
+
+.dont_cap_3
+; Minimum neutral damage is 2 (bringing the cap to 999).
+ inc hl
+ ld a, [hl]
+ add MIN_NEUTRAL_DAMAGE
+ ld [hld], a
+ jr nc, .dont_floor
+ inc [hl]
+.dont_floor
+
+ ld a, 1
+ and a
+ ret
+
+.CriticalMultiplier:
+ ld a, [wCriticalHit]
+ and a
+ ret z
+
+; x2
+ ldh a, [hQuotient + 3]
+ sla a
+ ldh [hProduct + 3], a
+
+ ldh a, [hQuotient + 2]
+ rl a
+ ldh [hProduct + 2], a
+
+; Cap at $ffff.
+ ret nc
+
+ ld a, $ff
+ ldh [hProduct + 2], a
+ ldh [hProduct + 3], a
+
+ ret
+
+INCLUDE "data/types/type_boost_items.asm"
+
+BattleCommand_ConstantDamage:
+; constantdamage
+
+ ld hl, wBattleMonLevel
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_turn
+ ld hl, wEnemyMonLevel
+
+.got_turn
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_LEVEL_DAMAGE
+ ld b, [hl]
+ ld a, 0
+ jr z, .got_power
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_PSYWAVE
+ jr z, .psywave
+
+ cp EFFECT_SUPER_FANG
+ jr z, .super_fang
+
+ cp EFFECT_REVERSAL
+ jr z, .reversal
+
+ ld a, BATTLE_VARS_MOVE_POWER
+ call GetBattleVar
+ ld b, a
+ ld a, $0
+ jr .got_power
+
+.psywave
+ ld a, b
+ srl a
+ add b
+ ld b, a
+.psywave_loop
+ call BattleRandom
+ and a
+ jr z, .psywave_loop
+ cp b
+ jr nc, .psywave_loop
+ ld b, a
+ ld a, 0
+ jr .got_power
+
+.super_fang
+ ld hl, wEnemyMonHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_hp
+ ld hl, wBattleMonHP
+.got_hp
+ ld a, [hli]
+ srl a
+ ld b, a
+ ld a, [hl]
+ rr a
+ push af
+ ld a, b
+ pop bc
+ and a
+ jr nz, .got_power
+ or b
+ ld a, 0
+ jr nz, .got_power
+ ld b, 1
+ jr .got_power
+
+.got_power
+ ld hl, wCurDamage
+ ld [hli], a
+ ld [hl], b
+ ret
+
+.reversal
+ ld hl, wBattleMonHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .reversal_got_hp
+ ld hl, wEnemyMonHP
+.reversal_got_hp
+ xor a
+ ldh [hDividend], a
+ ldh [hMultiplicand + 0], a
+ ld a, [hli]
+ ldh [hMultiplicand + 1], a
+ ld a, [hli]
+ ldh [hMultiplicand + 2], a
+ ld a, 48
+ ldh [hMultiplier], a
+ call Multiply
+ ld a, [hli]
+ ld b, a
+ ld a, [hl]
+ ldh [hDivisor], a
+ ld a, b
+ and a
+ jr z, .skip_to_divide
+
+ ldh a, [hProduct + 4]
+ srl b
+ rr a
+ srl b
+ rr a
+ ldh [hDivisor], a
+ ldh a, [hProduct + 2]
+ ld b, a
+ srl b
+ ldh a, [hProduct + 3]
+ rr a
+ srl b
+ rr a
+ ldh [hDividend + 3], a
+ ld a, b
+ ldh [hDividend + 2], a
+
+.skip_to_divide
+ ld b, 4
+ call Divide
+ ldh a, [hQuotient + 3]
+ ld b, a
+ ld hl, FlailReversalPower
+
+.reversal_loop
+ ld a, [hli]
+ cp b
+ jr nc, .break_loop
+ inc hl
+ jr .reversal_loop
+
+.break_loop
+ ldh a, [hBattleTurn]
+ and a
+ ld a, [hl]
+ jr nz, .notPlayersTurn
+
+ ld hl, wPlayerMoveStructPower
+ ld [hl], a
+ push hl
+ call PlayerAttackDamage
+ jr .notEnemysTurn
+
+.notPlayersTurn
+ ld hl, wEnemyMoveStructPower
+ ld [hl], a
+ push hl
+ call EnemyAttackDamage
+
+.notEnemysTurn
+ call BattleCommand_DamageCalc
+ pop hl
+ ld [hl], 1
+ ret
+
+INCLUDE "data/moves/flail_reversal_power.asm"
+
+INCLUDE "engine/battle/move_effects/counter.asm"
+
+INCLUDE "engine/battle/move_effects/encore.asm"
+
+INCLUDE "engine/battle/move_effects/pain_split.asm"
+
+INCLUDE "engine/battle/move_effects/snore.asm"
+
+INCLUDE "engine/battle/move_effects/conversion2.asm"
+
+INCLUDE "engine/battle/move_effects/lock_on.asm"
+
+INCLUDE "engine/battle/move_effects/sketch.asm"
+
+BattleCommand_DefrostOpponent:
+; defrostopponent
+; Thaw the opponent if frozen, and
+; raise the user's Attack one stage.
+
+ call AnimateCurrentMove
+
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVarAddr
+ call Defrost
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVarAddr
+ ld a, [hl]
+ push hl
+ push af
+
+ ld a, EFFECT_ATTACK_UP
+ ld [hl], a
+ call BattleCommand_StatUp
+
+ pop af
+ pop hl
+ ld [hl], a
+ ret
+
+INCLUDE "engine/battle/move_effects/sleep_talk.asm"
+
+INCLUDE "engine/battle/move_effects/destiny_bond.asm"
+
+INCLUDE "engine/battle/move_effects/spite.asm"
+
+INCLUDE "engine/battle/move_effects/false_swipe.asm"
+
+INCLUDE "engine/battle/move_effects/heal_bell.asm"
+
+FarPlayBattleAnimation:
+; play animation de
+
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVar
+ and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ ret nz
+
+ ; fallthrough
+
+PlayFXAnimID:
+ ld a, e
+ ld [wFXAnimID], a
+ ld a, d
+ ld [wFXAnimID + 1], a
+
+ ld c, 3
+ call DelayFrames
+ callfar PlayBattleAnim
+ ret
+
+DoEnemyDamage:
+ ld hl, wCurDamage
+ ld a, [hli]
+ ld b, a
+ ld a, [hl]
+ or b
+ jr z, .did_no_damage
+
+ ld a, c
+ and a
+ jr nz, .ignore_substitute
+ ld a, [wEnemySubStatus4]
+ bit SUBSTATUS_SUBSTITUTE, a
+ jp nz, DoSubstituteDamage
+
+.ignore_substitute
+ ; Substract wCurDamage from wEnemyMonHP.
+ ; store original HP in little endian wBuffer3/4
+ ld a, [hld]
+ ld b, a
+ ld a, [wEnemyMonHP + 1]
+ ld [wBuffer3], a
+ sub b
+ ld [wEnemyMonHP + 1], a
+ ld a, [hl]
+ ld b, a
+ ld a, [wEnemyMonHP]
+ ld [wBuffer4], a
+ sbc b
+ ld [wEnemyMonHP], a
+ jr nc, .no_underflow
+
+ ld a, [wBuffer4]
+ ld [hli], a
+ ld a, [wBuffer3]
+ ld [hl], a
+ xor a
+ ld hl, wEnemyMonHP
+ ld [hli], a
+ ld [hl], a
+
+.no_underflow
+ ld hl, wEnemyMonMaxHP
+ ld a, [hli]
+ ld [wBuffer2], a
+ ld a, [hl]
+ ld [wBuffer1], a
+ ld hl, wEnemyMonHP
+ ld a, [hli]
+ ld [wBuffer6], a
+ ld a, [hl]
+ ld [wBuffer5], a
+
+ hlcoord 2, 2
+ xor a
+ ld [wWhichHPBar], a
+ predef AnimateHPBar
+.did_no_damage
+ jp RefreshBattleHuds
+
+DoPlayerDamage:
+ ld hl, wCurDamage
+ ld a, [hli]
+ ld b, a
+ ld a, [hl]
+ or b
+ jr z, .did_no_damage
+
+ ld a, c
+ and a
+ jr nz, .ignore_substitute
+ ld a, [wPlayerSubStatus4]
+ bit SUBSTATUS_SUBSTITUTE, a
+ jp nz, DoSubstituteDamage
+
+.ignore_substitute
+ ; Substract wCurDamage from wBattleMonHP.
+ ; store original HP in little endian wBuffer3/4
+ ; store new HP in little endian wBuffer5/6
+ ld a, [hld]
+ ld b, a
+ ld a, [wBattleMonHP + 1]
+ ld [wBuffer3], a
+ sub b
+ ld [wBattleMonHP + 1], a
+ ld [wBuffer5], a
+ ld b, [hl]
+ ld a, [wBattleMonHP]
+ ld [wBuffer4], a
+ sbc b
+ ld [wBattleMonHP], a
+ ld [wBuffer6], a
+ jr nc, .no_underflow
+
+ ld a, [wBuffer4]
+ ld [hli], a
+ ld a, [wBuffer3]
+ ld [hl], a
+ xor a
+ ld hl, wBattleMonHP
+ ld [hli], a
+ ld [hl], a
+ ld hl, wBuffer5
+ ld [hli], a
+ ld [hl], a
+
+.no_underflow
+ ld hl, wBattleMonMaxHP
+ ld a, [hli]
+ ld [wBuffer2], a
+ ld a, [hl]
+ ld [wBuffer1], a
+
+ hlcoord 10, 9
+ ld a, 1
+ ld [wWhichHPBar], a
+ predef AnimateHPBar
+.did_no_damage
+ jp RefreshBattleHuds
+
+DoSubstituteDamage:
+ ld hl, SubTookDamageText
+ call StdBattleTextbox
+
+ ld de, wEnemySubstituteHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_hp
+ ld de, wPlayerSubstituteHP
+.got_hp
+
+ ld hl, wCurDamage
+ ld a, [hli]
+ and a
+ jr nz, .broke
+
+ ld a, [de]
+ sub [hl]
+ ld [de], a
+ jr z, .broke
+ jr nc, .done
+
+.broke
+ ld a, BATTLE_VARS_SUBSTATUS4_OPP
+ call GetBattleVarAddr
+ res SUBSTATUS_SUBSTITUTE, [hl]
+
+ ld hl, SubFadedText
+ call StdBattleTextbox
+
+ call BattleCommand_SwitchTurn
+ call BattleCommand_LowerSubNoAnim
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVar
+ and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ call z, AppearUserLowerSub
+ call BattleCommand_SwitchTurn
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVarAddr
+ cp EFFECT_MULTI_HIT
+ jr z, .ok
+ cp EFFECT_DOUBLE_HIT
+ jr z, .ok
+ cp EFFECT_POISON_MULTI_HIT
+ jr z, .ok
+ cp EFFECT_TRIPLE_KICK
+ jr z, .ok
+ cp EFFECT_BEAT_UP
+ jr z, .ok
+ xor a
+ ld [hl], a
+.ok
+ call RefreshBattleHuds
+.done
+ jp ResetDamage