diff options
Diffstat (limited to 'engine/battle/effect_commands.asm')
-rw-r--r-- | engine/battle/effect_commands.asm | 10066 |
1 files changed, 10066 insertions, 0 deletions
diff --git a/engine/battle/effect_commands.asm b/engine/battle/effect_commands.asm new file mode 100644 index 000000000..5922afea3 --- /dev/null +++ b/engine/battle/effect_commands.asm @@ -0,0 +1,10066 @@ +DoPlayerTurn: ; 34000 + call SetPlayerTurn + + ld a, [wPlayerAction] + and a + ret nz + + jr DoTurn + +; 3400a + + +DoEnemyTurn: ; 3400a + call SetEnemyTurn + + ld a, [wLinkMode] + and a + jr z, DoTurn + + ld a, [wBattleAction] + cp BATTLEACTION_E + jr z, DoTurn + cp BATTLEACTION_SWITCH1 + ret nc + + ; fallthrough +; 3401d + + +DoTurn: ; 3401d +; Read in and execute the user's move effects for this turn. + + xor a + ld [wTurnEnded], a + + ; Effect command checkturn is called for every move. + call CheckTurn + + ld a, [wTurnEnded] + and a + ret nz + + call UpdateMoveData +; 3402c + + +DoMove: ; 3402c +; Get the user's move effect. + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + ld c, a + ld b, 0 + ld hl, MoveEffectsPointers + add hl, bc + add hl, bc + ld a, BANK(MoveEffectsPointers) + call GetFarHalfword + + ld de, BattleScriptBuffer + +.GetMoveEffect: + ld a, BANK(MoveEffects) + call GetFarByte + inc hl + ld [de], a + inc de + cp $ff + jr nz, .GetMoveEffect + +; Start at the first command. + ld hl, BattleScriptBuffer + ld a, l + ld [BattleScriptBufferAddress], a + ld a, h + ld [BattleScriptBufferAddress + 1], a + +.ReadMoveEffectCommand: + +; ld a, [BattleScriptBufferAddress++] + ld a, [BattleScriptBufferAddress] + ld l, a + ld a, [BattleScriptBufferAddress + 1] + ld h, a + + ld a, [hli] + + push af + ld a, l + ld [BattleScriptBufferAddress], a + ld a, h + ld [BattleScriptBufferAddress + 1], a + pop af + +; endturn_command (-2) is used to terminate branches without ending the read cycle. + cp endturn_command + ret nc + +; The rest of the commands (01-af) are read from BattleCommandPointers. + push bc + dec a + ld c, a + ld b, 0 + ld hl, BattleCommandPointers + add hl, bc + add hl, bc + pop bc + + ld a, BANK(BattleCommandPointers) + call GetFarHalfword + + call .DoMoveEffectCommand + + jr .ReadMoveEffectCommand + +.DoMoveEffectCommand: + jp hl + +; 34084 + + +CheckTurn: +BattleCommand_CheckTurn: ; 34084 +; checkturn + +; Repurposed as hardcoded turn handling. Useless as a command. + +; Move $ff immediately ends the turn. + ld a, BATTLE_VARS_MOVE + call GetBattleVar + inc a + jp z, EndTurn + + xor a + ld [AttackMissed], a + ld [EffectFailed], a + ld [wKickCounter], a + ld [AlreadyDisobeyed], a + ld [AlreadyFailed], a + ld [wSomeoneIsRampaging], a + + ld a, 10 ; 1.0 + ld [TypeModifier], a + + ld a, [hBattleTurn] + and a + jp nz, CheckEnemyTurn + + +CheckPlayerTurn: + + ld hl, PlayerSubStatus4 + bit SUBSTATUS_RECHARGE, [hl] + jr z, .no_recharge + + res SUBSTATUS_RECHARGE, [hl] + ld hl, MustRechargeText + call StdBattleTextBox + call CantMove + jp EndTurn + +.no_recharge + + + ld hl, BattleMonStatus + ld a, [hl] + and SLP + jr z, .not_asleep + + dec a + ld [BattleMonStatus], a + and SLP + jr z, .woke_up + + xor a + ld [wNumHits], a + ld de, ANIM_SLP + call FarPlayBattleAnimation + jr .fast_asleep + +.woke_up + ld hl, WokeUpText + call StdBattleTextBox + call CantMove + call UpdateBattleMonInParty + ld hl, UpdatePlayerHUD + call CallBattleCore + ld a, $1 + ld [hBGMapMode], a + ld hl, PlayerSubStatus1 + res SUBSTATUS_NIGHTMARE, [hl] + jr .not_asleep + +.fast_asleep + ld hl, FastAsleepText + call StdBattleTextBox + + ; Snore and Sleep Talk bypass sleep. + ld a, [CurPlayerMove] + cp SNORE + jr z, .not_asleep + cp SLEEP_TALK + jr z, .not_asleep + + call CantMove + jp EndTurn + +.not_asleep + + + ld hl, BattleMonStatus + bit FRZ, [hl] + jr z, .not_frozen + + ; Flame Wheel and Sacred Fire thaw the user. + ld a, [CurPlayerMove] + cp FLAME_WHEEL + jr z, .not_frozen + cp SACRED_FIRE + jr z, .not_frozen + + ld hl, FrozenSolidText + call StdBattleTextBox + + call CantMove + jp EndTurn + +.not_frozen + + + ld hl, PlayerSubStatus3 + bit SUBSTATUS_FLINCHED, [hl] + jr z, .not_flinched + + res SUBSTATUS_FLINCHED, [hl] + ld hl, FlinchedText + call StdBattleTextBox + + call CantMove + jp EndTurn + +.not_flinched + + + ld hl, PlayerDisableCount + ld a, [hl] + and a + jr z, .not_disabled + + dec a + ld [hl], a + and $f + jr nz, .not_disabled + + ld [hl], a + ld [DisabledMove], a + ld hl, DisabledNoMoreText + call StdBattleTextBox + +.not_disabled + + + ld a, [PlayerSubStatus3] + add a + jr nc, .not_confused + ld hl, PlayerConfuseCount + dec [hl] + jr nz, .confused + + ld hl, PlayerSubStatus3 + res SUBSTATUS_CONFUSED, [hl] + ld hl, ConfusedNoMoreText + call StdBattleTextBox + jr .not_confused + +.confused + ld hl, IsConfusedText + call StdBattleTextBox + xor a + ld [wNumHits], a + ld de, ANIM_CONFUSED + call FarPlayBattleAnimation + + ; 50% chance of hitting itself + call BattleRandom + cp $80 + jr nc, .not_confused + + ; clear confusion-dependent substatus + ld hl, PlayerSubStatus3 + ld a, [hl] + and 1 << SUBSTATUS_CONFUSED + ld [hl], a + + call HitConfusion + call CantMove + jp EndTurn + +.not_confused + + + ld a, [PlayerSubStatus1] + add a ; bit SUBSTATUS_ATTRACT + jr nc, .not_infatuated + + ld hl, InLoveWithText + call StdBattleTextBox + xor a + ld [wNumHits], a + ld de, ANIM_IN_LOVE + call FarPlayBattleAnimation + + ; 50% chance of infatuation + call BattleRandom + cp $80 + jr c, .not_infatuated + + ld hl, InfatuationText + call StdBattleTextBox + call CantMove + jp EndTurn + +.not_infatuated + + + ; We can't disable a move that doesn't exist. + ld a, [DisabledMove] + and a + jr z, .no_disabled_move + + ; Are we using the disabled move? + ld hl, CurPlayerMove + cp [hl] + jr nz, .no_disabled_move + + call MoveDisabled + call CantMove + jp EndTurn + +.no_disabled_move + + + ld hl, BattleMonStatus + bit PAR, [hl] + ret z + + ; 25% chance to be fully paralyzed + call BattleRandom + cp $3f + ret nc + + ld hl, FullyParalyzedText + call StdBattleTextBox + call CantMove + jp EndTurn + +; 341f0 + + +CantMove: ; 341f0 + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + res SUBSTATUS_ROLLOUT, [hl] + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + ld a, [hl] + and $ff ^ (1<<SUBSTATUS_BIDE + 1<<SUBSTATUS_RAMPAGE + 1<<SUBSTATUS_CHARGED) + ld [hl], a + + call ResetFuryCutterCount + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp FLY + jr z, .fly_dig + + cp DIG + ret nz + +.fly_dig + res SUBSTATUS_UNDERGROUND, [hl] + res SUBSTATUS_FLYING, [hl] + jp AppearUserRaiseSub + +; 34216 + + + +OpponentCantMove: ; 34216 + call BattleCommand_SwitchTurn + call CantMove + jp BattleCommand_SwitchTurn + +; 3421f + + + +CheckEnemyTurn: ; 3421f + + ld hl, EnemySubStatus4 + bit SUBSTATUS_RECHARGE, [hl] + jr z, .no_recharge + + res SUBSTATUS_RECHARGE, [hl] + ld hl, MustRechargeText + call StdBattleTextBox + call CantMove + jp EndTurn + +.no_recharge + + + ld hl, EnemyMonStatus + ld a, [hl] + and SLP + jr z, .not_asleep + + dec a + ld [EnemyMonStatus], a + and a + jr z, .woke_up + + ld hl, FastAsleepText + call StdBattleTextBox + xor a + ld [wNumHits], a + ld de, ANIM_SLP + call FarPlayBattleAnimation + jr .fast_asleep + +.woke_up + ld hl, WokeUpText + call StdBattleTextBox + call CantMove + call UpdateEnemyMonInParty + ld hl, UpdateEnemyHUD + call CallBattleCore + ld a, $1 + ld [hBGMapMode], a + ld hl, EnemySubStatus1 + res SUBSTATUS_NIGHTMARE, [hl] + jr .not_asleep + +.fast_asleep + ; Snore and Sleep Talk bypass sleep. + ld a, [CurEnemyMove] + cp SNORE + jr z, .not_asleep + cp SLEEP_TALK + jr z, .not_asleep + call CantMove + jp EndTurn + +.not_asleep + + + ld hl, EnemyMonStatus + bit FRZ, [hl] + jr z, .not_frozen + ld a, [CurEnemyMove] + cp FLAME_WHEEL + jr z, .not_frozen + cp SACRED_FIRE + jr z, .not_frozen + + ld hl, FrozenSolidText + call StdBattleTextBox + call CantMove + jp EndTurn + +.not_frozen + + + ld hl, EnemySubStatus3 + bit SUBSTATUS_FLINCHED, [hl] + jr z, .not_flinched + + res SUBSTATUS_FLINCHED, [hl] + ld hl, FlinchedText + call StdBattleTextBox + + call CantMove + jp EndTurn + +.not_flinched + + + ld hl, EnemyDisableCount + ld a, [hl] + and a + jr z, .not_disabled + + dec a + ld [hl], a + and $f + jr nz, .not_disabled + + ld [hl], a + ld [EnemyDisabledMove], a + + ld hl, DisabledNoMoreText + call StdBattleTextBox + +.not_disabled + + + ld a, [EnemySubStatus3] + add a ; bit SUBSTATUS_CONFUSED + jr nc, .not_confused + + ld hl, EnemyConfuseCount + dec [hl] + jr nz, .confused + + ld hl, EnemySubStatus3 + res SUBSTATUS_CONFUSED, [hl] + ld hl, ConfusedNoMoreText + call StdBattleTextBox + jr .not_confused + + +.confused + ld hl, IsConfusedText + call StdBattleTextBox + + xor a + ld [wNumHits], a + ld de, ANIM_CONFUSED + call FarPlayBattleAnimation + + ; 50% chance of hitting itself + call BattleRandom + cp 1 + 50 percent + jr nc, .not_confused + + ; clear confusion-dependent substatus + ld hl, EnemySubStatus3 + ld a, [hl] + and 1 << SUBSTATUS_CONFUSED + ld [hl], a + + ld hl, HurtItselfText + call StdBattleTextBox + call HitSelfInConfusion + call BattleCommand_DamageCalc + call BattleCommand_LowerSub + xor a + ld [wNumHits], a + + ; Flicker the monster pic unless flying or underground. + ld de, ANIM_HIT_CONFUSION + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + call z, PlayFXAnimID + + ld c, $1 + call EnemyHurtItself + call BattleCommand_RaiseSub + call CantMove + jp EndTurn + +.not_confused + + + ld a, [EnemySubStatus1] + add a ; bit SUBSTATUS_ATTRACT + jr nc, .not_infatuated + + ld hl, InLoveWithText + call StdBattleTextBox + xor a + ld [wNumHits], a + ld de, ANIM_IN_LOVE + call FarPlayBattleAnimation + + ; 50% chance of infatuation + call BattleRandom + cp 1 + 50 percent + jr c, .not_infatuated + + ld hl, InfatuationText + call StdBattleTextBox + call CantMove + jp EndTurn + +.not_infatuated + + + ; We can't disable a move that doesn't exist. + ld a, [EnemyDisabledMove] + and a + jr z, .no_disabled_move + + ; Are we using the disabled move? + ld hl, CurEnemyMove + cp [hl] + jr nz, .no_disabled_move + + call MoveDisabled + + call CantMove + jp EndTurn + +.no_disabled_move + + + ld hl, EnemyMonStatus + bit PAR, [hl] + ret z + + ; 25% chance to be fully paralyzed + call BattleRandom + cp $3f + ret nc + + ld hl, FullyParalyzedText + call StdBattleTextBox + call CantMove + + ; fallthrough +; 34385 + + +EndTurn: ; 34385 + ld a, $1 + ld [wTurnEnded], a + jp ResetDamage + +; 3438d + + +MoveDisabled: ; 3438d + + ; Make sure any charged moves fail + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + res SUBSTATUS_CHARGED, [hl] + + ld a, BATTLE_VARS_MOVE + call GetBattleVar + ld [wNamedObjectIndexBuffer], a + call GetMoveName + + ld hl, DisabledMoveText + jp StdBattleTextBox + +; 343a5 + + +HitConfusion: ; 343a5 + + ld hl, HurtItselfText + call StdBattleTextBox + + xor a + ld [CriticalHit], a + + call HitSelfInConfusion + call BattleCommand_DamageCalc + call BattleCommand_LowerSub + + xor a + ld [wNumHits], a + + ; Flicker the monster pic unless flying or underground. + ld de, ANIM_HIT_CONFUSION + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + call z, PlayFXAnimID + + ld hl, UpdatePlayerHUD + call CallBattleCore + ld a, $1 + ld [hBGMapMode], a + ld c, $1 + call PlayerHurtItself + jp BattleCommand_RaiseSub + +; 343db + + +BattleCommand_CheckObedience: ; 343db +; checkobedience + + ; Enemy can't disobey + ld a, [hBattleTurn] + and a + ret nz + + call CheckUserIsCharging + ret nz + + ; If we've already checked this turn + ld a, [AlreadyDisobeyed] + and a + ret nz + + xor a + ld [AlreadyDisobeyed], a + + ; No obedience in link battles + ; (since no handling exists for enemy) + ld a, [wLinkMode] + and a + ret nz + + ld a, [InBattleTowerBattle] + and a + ret nz + + ; If the monster's id doesn't match the player's, + ; some conditions need to be met. + ld a, MON_ID + call BattlePartyAttr + + ld a, [PlayerID] + cp [hl] + jr nz, .obeylevel + inc hl + ld a, [PlayerID + 1] + cp [hl] + ret z + + +.obeylevel + ; The maximum obedience level is constrained by owned badges: + ld hl, JohtoBadges + + ; risingbadge + bit RISINGBADGE, [hl] + ld a, MAX_LEVEL + 1 + jr nz, .getlevel + + ; stormbadge + bit STORMBADGE, [hl] + ld a, 70 + jr nz, .getlevel + + ; fogbadge + bit FOGBADGE, [hl] + ld a, 50 + jr nz, .getlevel + + ; hivebadge + bit HIVEBADGE, [hl] + ld a, 30 + jr nz, .getlevel + + ; no badges + ld a, 10 + + +.getlevel +; c = obedience level +; d = monster level +; b = c + d + + ld b, a + ld c, a + + ld a, [BattleMonLevel] + ld d, a + + add b + ld b, a + +; No overflow (this should never happen) + jr nc, .checklevel + ld b, $ff + + +.checklevel +; If the monster's level is lower than the obedience level, it will obey. + ld a, c + cp d + ret nc + + +; Random number from 0 to obedience level + monster level +.rand1 + call BattleRandom + swap a + cp b + jr nc, .rand1 + +; The higher above the obedience level the monster is, +; the more likely it is to disobey. + cp c + ret c + +; Sleep-only moves have separate handling, and a higher chance of +; being ignored. Lazy monsters like their sleep. + call IgnoreSleepOnly + ret c + + +; Another random number from 0 to obedience level + monster level +.rand2 + call BattleRandom + cp b + jr nc, .rand2 + +; A second chance. + cp c + jr c, .UseInstead + + +; No hope of using a move now. + +; b = number of levels the monster is above the obedience level + ld a, d + sub c + ld b, a + +; The chance of napping is the difference out of 256. + call BattleRandom + swap a + sub b + jr c, .Nap + +; The chance of not hitting itself is the same. + cp b + jr nc, .DoNothing + + ld hl, WontObeyText + call StdBattleTextBox + call HitConfusion + jp .EndDisobedience + + +.Nap: + call BattleRandom + add a + swap a + and SLP + jr z, .Nap + + ld [BattleMonStatus], a + + ld hl, BeganToNapText + jr .Print + + +.DoNothing: + call BattleRandom + and 3 + + ld hl, LoafingAroundText + and a + jr z, .Print + + ld hl, WontObeyText + dec a + jr z, .Print + + ld hl, TurnedAwayText + dec a + jr z, .Print + + ld hl, IgnoredOrdersText + +.Print: + call StdBattleTextBox + jp .EndDisobedience + + +.UseInstead: + +; Can't use another move if the monster only has one! + ld a, [BattleMonMoves + 1] + and a + jr z, .DoNothing + +; Don't bother trying to handle Disable. + ld a, [DisabledMove] + and a + jr nz, .DoNothing + + + ld hl, BattleMonPP + ld de, BattleMonMoves + ld b, 0 + ld c, NUM_MOVES + +.GetTotalPP: + ld a, [hli] + and $3f ; exclude pp up + add b + ld b, a + + dec c + jr z, .CheckMovePP + +; Stop at undefined moves. + inc de + ld a, [de] + and a + jr nz, .GetTotalPP + + +.CheckMovePP: + ld hl, BattleMonPP + ld a, [CurMoveNum] + ld e, a + ld d, 0 + add hl, de + +; Can't use another move if only one move has PP. + ld a, [hl] + and $3f + cp b + jr z, .DoNothing + + +; Make sure we can actually use the move once we get there. + ld a, 1 + ld [AlreadyDisobeyed], a + + ld a, [w2DMenuNumRows] + ld b, a + +; Save the move we originally picked for afterward. + ld a, [CurMoveNum] + ld c, a + push af + + +.RandomMove: + call BattleRandom + and 3 ; TODO NUM_MOVES + + cp b + jr nc, .RandomMove + +; Not the move we were trying to use. + cp c + jr z, .RandomMove + +; Make sure it has PP. + ld [CurMoveNum], a + ld hl, BattleMonPP + ld e, a + ld d, 0 + add hl, de + ld a, [hl] + and $3f + jr z, .RandomMove + + +; Use it. + ld a, [CurMoveNum] + ld c, a + ld b, 0 + ld hl, BattleMonMoves + add hl, bc + ld a, [hl] + ld [CurPlayerMove], a + + call SetPlayerTurn + call UpdateMoveData + call DoMove + + +; Restore original move choice. + pop af + ld [CurMoveNum], a + + +.EndDisobedience: + xor a + ld [LastPlayerMove], a + ld [LastPlayerCounterMove], a + + ; Break Encore too. + ld hl, PlayerSubStatus5 + res SUBSTATUS_ENCORED, [hl] + xor a + ld [PlayerEncoreCount], a + + jp EndMoveEffect + +; 3451f + + +IgnoreSleepOnly: ; 3451f + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + + cp SNORE + jr z, .CheckSleep + cp SLEEP_TALK + jr z, .CheckSleep + and a + ret + +.CheckSleep: + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + ret z + +; 'ignored orders…sleeping!' + ld hl, IgnoredSleepingText + call StdBattleTextBox + + call EndMoveEffect + + scf + ret + +; 34541 + + +BattleCommand_UsedMoveText: ; 34541 +; usedmovetext + farcall DisplayUsedMoveText + ret + +; 34548 + + +CheckUserIsCharging: ; 34548 + + ld a, [hBattleTurn] + and a + ld a, [wPlayerCharging] ; player + jr z, .end + ld a, [wEnemyCharging] ; enemy +.end + and a + ret + +; 34555 + + +BattleCommand_DoTurn: ; 34555 + call CheckUserIsCharging + ret nz + + ld hl, BattleMonPP + ld de, PlayerSubStatus3 + ld bc, PlayerTurnsTaken + + ld a, [hBattleTurn] + and a + jr z, .proceed + + ld hl, EnemyMonPP + ld de, EnemySubStatus3 + ld bc, EnemyTurnsTaken + +.proceed + +; If we've gotten this far, this counts as a turn. + ld a, [bc] + inc a + ld [bc], a + + ld a, BATTLE_VARS_MOVE + call GetBattleVar + cp STRUGGLE + ret z + + ld a, [de] + and 1 << SUBSTATUS_IN_LOOP | 1 << SUBSTATUS_RAMPAGE | 1 << SUBSTATUS_BIDE + ret nz + + call .consume_pp + ld a, b + and a + jp nz, EndMoveEffect + + ; SubStatus5 + inc de + inc de + + ld a, [de] + bit SUBSTATUS_TRANSFORMED, a + ret nz + + ld a, [hBattleTurn] + and a + + ld hl, PartyMon1PP + ld a, [CurBattleMon] + jr z, .player + +; mimic this part entirely if wildbattle + ld a, [wBattleMode] + dec a + jr z, .wild + + ld hl, OTPartyMon1PP + ld a, [CurOTMon] + +.player + call GetPartyLocation + push hl + call CheckMimicUsed + pop hl + ret c + +.consume_pp + ld a, [hBattleTurn] + and a + ld a, [CurMoveNum] + jr z, .okay + ld a, [CurEnemyMoveNum] + +.okay + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + and $3f + jr z, .out_of_pp + dec [hl] + ld b, 0 + ret + +.wild + ld hl, EnemyMonMoves + ld a, [CurEnemyMoveNum] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + cp MIMIC + jr z, .mimic + ld hl, wWildMonMoves + add hl, bc + ld a, [hl] + cp MIMIC + ret z + +.mimic + ld hl, wWildMonPP + call .consume_pp + ret + +.out_of_pp + call BattleCommand_MoveDelay +; get move effect + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar +; continuous? + ld hl, .continuousmoves + ld de, 1 + call IsInArray + +; 'has no pp left for [move]' + ld hl, HasNoPPLeftText + jr c, .print +; 'but no pp is left for the move' + ld hl, NoPPLeftText +.print + call StdBattleTextBox + ld b, 1 + ret + +; 34602 + +.continuousmoves ; 34602 + db EFFECT_RAZOR_WIND + db EFFECT_SKY_ATTACK + db EFFECT_SKULL_BASH + db EFFECT_SOLARBEAM + db EFFECT_FLY + db EFFECT_ROLLOUT + db EFFECT_BIDE + db EFFECT_RAMPAGE + db $ff +; 3460b + +CheckMimicUsed: ; 3460b + ld a, [hBattleTurn] + and a + ld a, [CurMoveNum] + jr z, .player + ld a, [CurEnemyMoveNum] + +.player + ld c, a + ld a, MON_MOVES + call UserPartyAttr + + ld a, BATTLE_VARS_MOVE + call GetBattleVar + cp MIMIC + jr z, .mimic +; + ld b, 0 + add hl, bc + ld a, [hl] + cp MIMIC + jr nz, .mimic + + scf + ret + +.mimic + and a + ret + +; 34631 + + +BattleCommand_Critical: ; 34631 +; critical + +; Determine whether this attack's hit will be critical. + + xor a + ld [CriticalHit], a + + ld a, BATTLE_VARS_MOVE_POWER + call GetBattleVar + and a + ret z + + ld a, [hBattleTurn] + and a + ld hl, EnemyMonItem + ld a, [EnemyMonSpecies] + jr nz, .Item + ld hl, BattleMonItem + ld a, [BattleMonSpecies] + +.Item: + ld c, 0 + + cp CHANSEY + jr nz, .Farfetchd + ld a, [hl] + cp LUCKY_PUNCH + jr nz, .FocusEnergy + +; +2 critical level + ld c, 2 + jr .Tally + +.Farfetchd: + cp FARFETCH_D + jr nz, .FocusEnergy + ld a, [hl] + cp STICK + jr nz, .FocusEnergy + +; +2 critical level + ld c, 2 + jr .Tally + +.FocusEnergy: + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_FOCUS_ENERGY, a + jr z, .CheckCritical + +; +1 critical level + inc c + +.CheckCritical: + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld de, 1 + ld hl, .Criticals + push bc + call IsInArray + pop bc + jr nc, .ScopeLens + +; +2 critical level + inc c + inc c + +.ScopeLens: + push bc + call GetUserItem + ld a, b + cp HELD_CRITICAL_UP ; Increased critical chance. Only Scope Lens has this. + pop bc + jr nz, .Tally + +; +1 critical level + inc c + +.Tally: + ld hl, .Chances + ld b, 0 + add hl, bc + call BattleRandom + cp [hl] + ret nc + ld a, 1 + ld [CriticalHit], a + ret + +.Criticals: + db KARATE_CHOP, RAZOR_WIND, RAZOR_LEAF, CRABHAMMER, SLASH, AEROBLAST, CROSS_CHOP, $ff +.Chances: + ; 6.25% 12.1% 24.6% 33.2% 49.6% 49.6% 49.6% + db $11, $20, $40, $55, $80, $80, $80 + ; 0 1 2 3 4 5 6 +; 346b2 + + +BattleCommand_TripleKick: ; 346b2 +; triplekick + + ld a, [wKickCounter] + ld b, a + inc b + ld hl, CurDamage + 1 + ld a, [hld] + ld e, a + ld a, [hli] + ld d, a +.next_kick + dec b + ret z + ld a, [hl] + add e + ld [hld], a + ld a, [hl] + adc d + ld [hli], a + +; No overflow. + jr nc, .next_kick + ld a, $ff + ld [hld], a + ld [hl], a + ret + +; 346cd + + +BattleCommand_KickCounter: ; 346cd +; kickcounter + + ld hl, wKickCounter + inc [hl] + ret + +; 346d2 + + +BattleCommand_Stab: ; 346d2 +; STAB = Same Type Attack Bonus + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp STRUGGLE + ret z + + ld hl, BattleMonType1 + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, EnemyMonType1 + ld a, [hli] + ld d, a + ld e, [hl] + + ld a, [hBattleTurn] + and a + jr z, .go ; Who Attacks and who Defends + + ld hl, EnemyMonType1 + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, BattleMonType1 + ld a, [hli] + ld d, a + ld e, [hl] + +.go + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVarAddr + ld [wTypeMatchup], 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, [wTypeMatchup] + cp b + jr z, .stab + cp c + jr z, .stab + + jr .SkipStab + +.stab + ld hl, CurDamage + 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 [CurDamage], a + ld a, l + ld [CurDamage + 1], a + + ld hl, TypeModifier + set 7, [hl] + +.SkipStab: + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVar + ld b, a + ld hl, TypeMatchups + +.TypesLoop: + ld a, [hli] + + cp $ff + jr z, .end + + ; foresight + cp $fe + 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, [TypeModifier] + 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 [AttackMissed], a + xor a +.NotImmune: + ld [hMultiplier], a + add b + ld [TypeModifier], a + + xor a + ld [hMultiplicand + 0], a + + ld hl, CurDamage + ld a, [hli] + ld [hMultiplicand + 1], a + ld a, [hld] + ld [hMultiplicand + 2], a + + call Multiply + + ld a, [hProduct + 1] + ld b, a + ld a, [hProduct + 2] + or b + ld b, a + ld 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 + ld [hDivisor], a + ld b, 4 + call Divide + ld a, [hQuotient + 1] + ld b, a + ld a, [hQuotient + 2] + or b + jr nz, .ok + + ld a, 1 + ld [hMultiplicand + 2], a + +.ok + ld a, [hMultiplicand + 1] + ld [hli], a + ld 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, [TypeModifier] + and %10000000 + or b + ld [TypeModifier], a + ret + +; 347c8 + + +BattleCheckTypeMatchup: ; 347c8 + ld hl, EnemyMonType1 + ld a, [hBattleTurn] + and a + jr z, CheckTypeMatchup + ld hl, BattleMonType1 +CheckTypeMatchup: ; 347d3 +; 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 $ff + jr z, .End + cp $fe + 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 + ld [hDividend + 0], a + ld [hMultiplicand + 0], a + ld [hMultiplicand + 1], a + ld a, [hli] + ld [hMultiplicand + 2], a + ld a, [wTypeMatchup] + ld [hMultiplier], a + call Multiply + ld a, 10 + ld [hDivisor], a + push bc + ld b, 4 + call Divide + pop bc + ld a, [hQuotient + 2] + ld [wTypeMatchup], a + jr .TypesLoop + +.End: + pop bc + pop de + pop hl + ret + +; 34833 + + +BattleCommand_ResetTypeMatchup: ; 34833 +; 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 [TypeModifier], a + inc a + ld [AttackMissed], a + ret + +.reset + ld [wTypeMatchup], a + ret + +; 3484e + +INCLUDE "engine/battle/ai/switch.asm" + +INCLUDE "data/type_matchups.asm" + +BattleCommand_DamageVariation: ; 34cfd +; 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, CurDamage + ld a, [hli] + and a + jr nz, .go + ld a, [hl] + cp 2 + ret c + +.go +; Start with the maximum damage. + xor a + ld [hMultiplicand + 0], a + dec hl + ld a, [hli] + ld [hMultiplicand + 1], a + ld a, [hl] + ld [hMultiplicand + 2], a + +; Multiply by 85-100%... +.loop + call BattleRandom + rrca + cp $d9 ; 85% + jr c, .loop + + ld [hMultiplier], a + call Multiply + +; ...divide by 100%... + ld a, $ff ; 100% + ld [hDivisor], a + ld b, $4 + call Divide + +; ...to get .85-1.00x damage. + ld a, [hQuotient + 1] + ld hl, CurDamage + ld [hli], a + ld a, [hQuotient + 2] + ld [hl], a + ret + +; 34d32 + + +BattleCommand_CheckHit: ; 34d32 +; 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 + ld 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 $ff + 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 [AttackMissed], 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, [Weather] + cp WEATHER_RAIN + ret + + +.XAccuracy: + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_X_ACCURACY, a + ret + + +.StatModifiers: + + ld 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, [PlayerAccLevel] + ld b, a + ld a, [EnemyEvaLevel] + ld c, a + + jr z, .got_acc_eva + + ld hl, wEnemyMoveStruct + MOVE_ACC + ld a, [EnemyAccLevel] + ld b, a + ld a, [PlayerEvaLevel] + 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, 14 + sub c + ld c, a + ; store the base move accuracy for math ops + xor a + ld [hMultiplicand + 0], a + ld [hMultiplicand + 1], a + ld a, [hl] + ld [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, .AccProb + 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] + ld [hMultiplier], a + call Multiply + ; ... and divide by the second byte + ld a, [hl] + ld [hDivisor], a + ld b, 4 + call Divide + ; minimum accuracy is $0001 + ld a, [hQuotient + 2] + ld b, a + ld a, [hQuotient + 1] + or b + jr nz, .min_accuracy + ld [hQuotient + 1], a + ld a, 1 + ld [hQuotient + 2], 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% + ld a, [hQuotient + 1] + and a + ld a, [hQuotient + 2] + jr z, .finish_accuracy + ld a, $ff + +.finish_accuracy + pop hl + ld [hl], a + ret + +.AccProb: + db 33, 100 ; 33% -6 + db 36, 100 ; 36% -5 + db 43, 100 ; 43% -4 + db 50, 100 ; 50% -3 + db 60, 100 ; 60% -2 + db 75, 100 ; 75% -1 + db 1, 1 ; 100% 0 + db 133, 100 ; 133% +1 + db 166, 100 ; 166% +2 + db 2, 1 ; 200% +3 + db 233, 100 ; 233% +4 + db 133, 50 ; 266% +5 + db 3, 1 ; 300% +6 + +; 34ecc + + +BattleCommand_EffectChance: ; 34ecc +; effectchance + + xor a + ld [EffectFailed], a + call CheckSubstituteOpp + jr nz, .failed + + push hl + ld hl, wPlayerMoveStruct + MOVE_CHANCE + ld a, [hBattleTurn] + and a + jr z, .got_move_chance + ld hl, wEnemyMoveStruct + MOVE_CHANCE +.got_move_chance + + call BattleRandom + cp [hl] + pop hl + ret c + +.failed + ld a, 1 + ld [EffectFailed], a + and a + ret + +; 34eee + + +BattleCommand_LowerSub: ; 34eee +; 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 + call _CheckBattleScene + jr c, .mimic_anims + + xor a + ld [wNumHits], a + ld [FXAnimID + 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 + +; 34f57 + + +BattleCommand_HitTarget: ; 34f57 +; hittarget + call BattleCommand_LowerSub + call BattleCommand_HitTargetNoSub + jp BattleCommand_RaiseSub + +; 34f60 + + +BattleCommand_HitTargetNoSub: ; 34f60 + ld a, [AttackMissed] + and a + jp nz, BattleCommand_MoveDelay + + ld a, [hBattleTurn] + and a + ld de, PlayerRolloutCount + ld a, BATTLEANIM_ENEMY_DAMAGE + jr z, .got_rollout_count + ld de, EnemyRolloutCount + 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, .multihit + cp EFFECT_CONVERSION + jr z, .conversion + cp EFFECT_DOUBLE_HIT + jr z, .doublehit + cp EFFECT_POISON_MULTI_HIT + jr z, .twineedle + 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, .fly_dig + cp DIG + ret nz + +.fly_dig +; clear sprite + jp AppearUserLowerSub + +.multihit +.conversion +.doublehit +.twineedle + 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 + +; 34fd1 + + +BattleCommand_StatUpAnim: ; 34fd1 + ld a, [AttackMissed] + and a + jp nz, BattleCommand_MoveDelay + + xor a + jr BattleCommand_StatUpDownAnim + +; 34fdb + + +BattleCommand_StatDownAnim: ; 34fdb + ld a, [AttackMissed] + and a + jp nz, BattleCommand_MoveDelay + + ld a, [hBattleTurn] + and a + ld a, BATTLEANIM_ENEMY_STAT_DOWN + jr z, BattleCommand_StatUpDownAnim + ld a, BATTLEANIM_WOBBLE + + ; fallthrough +; 34feb + + +BattleCommand_StatUpDownAnim: ; 34feb + ld [wNumHits], a + xor a + ld [wKickCounter], a + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld e, a + ld d, 0 + jp PlayFXAnimID + +; 34ffd + + +BattleCommand_SwitchTurn: ; 34ffd +; switchturn + + ld a, [hBattleTurn] + xor 1 + ld [hBattleTurn], a + ret + +; 35004 + + +BattleCommand_RaiseSub: ; 35004 +; raisesub + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + ret z + + call _CheckBattleScene + jp c, BattleCommand_RaiseSubNoAnim + + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + ld a, $2 + ld [wKickCounter], a + ld a, SUBSTITUTE + jp LoadAnim + +; 35023 + + +BattleCommand_FailureText: ; 35023 +; failuretext +; If the move missed or failed, load the appropriate +; text, and end the effects of multi-turn or multi- +; hit moves. + ld a, [AttackMissed] + 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 + +; 3505e + + +BattleCommand_CheckFaint: ; 3505e +; checkfaint + + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVar + bit SUBSTATUS_ENDURE, a + jr z, .not_enduring + call BattleCommand_FalseSwipe + ld b, $0 + jr nc, .okay + ld b, $1 + jr .okay + +.not_enduring + call GetOpponentItem + ld a, b + cp HELD_FOCUS_BAND + ld b, $0 + jr nz, .okay + call BattleRandom + cp c + jr nc, .okay + call BattleCommand_FalseSwipe + ld b, $0 + jr nc, .okay + ld b, $2 +.okay + push bc + call .check_sub + ld c, $0 + ld a, [hBattleTurn] + and a + jr nz, .damage_player + call EnemyHurtItself + jr .done_damage + +.damage_player + call PlayerHurtItself + +.done_damage + pop bc + ld a, b + and a + ret z + dec a + jr nz, .not_enduring2 + ld hl, EnduredText + jp StdBattleTextBox + +.not_enduring2 + call GetOpponentItem + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetItemName + + ld hl, HungOnText + jp StdBattleTextBox + +.check_sub + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + ret nz + + ld de, PlayerDamageTaken + 1 + ld a, [hBattleTurn] + and a + jr nz, .damage_taken + ld de, EnemyDamageTaken + 1 + +.damage_taken + ld a, [CurDamage + 1] + ld b, a + ld a, [de] + add b + ld [de], a + dec de + ld a, [CurDamage] + 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 + +; 350e4 + + +GetFailureResultText: ; 350e4 + ld hl, DoesntAffectText + ld de, DoesntAffectText + ld a, [TypeModifier] + 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, [CriticalHit] + cp $ff + jr nz, .got_text + ld hl, UnaffectedText +.got_text + call FailText_CheckOpponentProtect + xor a + ld [CriticalHit], a + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_JUMP_KICK + ret nz + + ld a, [TypeModifier] + and $7f + ret z + + ld hl, CurDamage + 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, $1 + ld a, [hBattleTurn] + and a + jp nz, EnemyHurtItself + jp PlayerHurtItself + +FailText_CheckOpponentProtect: ; 35157 + 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 + +; 35165 + + +BattleCommanda5: ; 35165 + ld a, [AttackMissed] + and a + ret z + + ld a, [TypeModifier] + and $7f + jp z, PrintDoesntAffect + jp PrintButItFailed + +; 35175 + + +BattleCommand_CriticalText: ; 35175 +; criticaltext +; Prints the message for critical hits or one-hit KOs. + +; If there is no message to be printed, wait 20 frames. + ld a, [CriticalHit] + 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 [CriticalHit], a + +.wait + ld c, 20 + jp DelayFrames + +.texts + dw CriticalHitText + dw OneHitKOText +; 35197 + + +BattleCommand_StartLoop: ; 35197 +; startloop + + ld hl, PlayerRolloutCount + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyRolloutCount +.ok + xor a + ld [hl], a + ret + +; 351a5 + + +BattleCommand_SuperEffectiveLoopText: ; 351a5 +; supereffectivelooptext + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + bit SUBSTATUS_IN_LOOP, a + ret nz + + ; fallthrough +; 351ad + + +BattleCommand_SuperEffectiveText: ; 351ad +; supereffectivetext + + ld a, [TypeModifier] + and $7f + cp 10 ; 1.0 + ret z + ld hl, SuperEffectiveText + jr nc, .print + ld hl, NotVeryEffectiveText +.print + jp StdBattleTextBox + +; 351c0 + + +BattleCommand_CheckDestinyBond: ; 351c0 +; checkdestinybond + +; Faint the user if it fainted an opponent using Destiny Bond. + + ld hl, EnemyMonHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, BattleMonHP + +.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 + + ld a, [hBattleTurn] + and a + ld hl, EnemyMonMaxHP + 1 + bccoord 2, 2 ; hp bar + ld a, 0 + jr nz, .got_max_hp + ld hl, BattleMonMaxHP + 1 + bccoord 10, 9 ; hp bar + ld a, 1 + +.got_max_hp + ld [wWhichHPBar], a + ld a, [hld] + ld [Buffer1], a + ld a, [hld] + ld [Buffer2], a + ld a, [hl] + ld [Buffer3], a + xor a + ld [hld], a + ld a, [hl] + ld [Buffer4], a + xor a + ld [hl], a + ld [Buffer5], a + ld [Buffer6], a + ld h, b + ld l, c + predef AnimateHPBar + call RefreshBattleHuds + + call BattleCommand_SwitchTurn + xor a + ld [wNumHits], a + ld [FXAnimID + 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 + +; 35250 + + +BattleCommand_BuildOpponentRage: ; 35250 +; buildopponentrage + + jp .start + +.start + ld a, [AttackMissed] + and a + ret nz + + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVar + bit SUBSTATUS_RAGE, a + ret z + + ld de, wEnemyRageCounter + ld 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 + +; 3527b + + +BattleCommand_RageDamage: ; 3527b +; ragedamage + + ld a, [CurDamage] + ld h, a + ld b, a + ld a, [CurDamage + 1] + ld l, a + ld c, a + ld 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, -1 +.done + ld a, h + ld [CurDamage], a + ld a, l + ld [CurDamage + 1], a + ret + +; 352a3 + + +EndMoveEffect: ; 352a3 + ld a, [BattleScriptBufferAddress] + ld l, a + ld a, [BattleScriptBufferAddress + 1] + ld h, a + ld a, $ff + ld [hli], a + ld [hli], a + ld [hl], a + ret + +; 352b1 + + +DittoMetalPowder: ; 352b1 + ld a, MON_SPECIES + call BattlePartyAttr + ld a, [hBattleTurn] + and a + ld a, [hl] + jr nz, .Ditto + ld a, [TempEnemyMonSpecies] + +.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 + +; 352dc + + +BattleCommand_DamageStats: ; 352dc +; damagestats + + ld a, [hBattleTurn] + and a + jp nz, EnemyAttackDamage + + ; fallthrough +; 352e2 + + +PlayerAttackDamage: ; 352e2 +; 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, EnemyMonDefense + ld a, [hli] + ld b, a + ld c, [hl] + + ld a, [EnemyScreens] + bit SCREENS_REFLECT, a + jr z, .physicalcrit + sla c + rl b + +.physicalcrit + ld hl, BattleMonAttack + call GetDamageStatsCritical + jr c, .thickclub + + ld hl, EnemyDefense + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, PlayerAttack + jr .thickclub + +.special + ld hl, EnemyMonSpclDef + ld a, [hli] + ld b, a + ld c, [hl] + + ld a, [EnemyScreens] + bit SCREENS_LIGHT_SCREEN, a + jr z, .specialcrit + sla c + rl b + +.specialcrit + ld hl, BattleMonSpclAtk + call GetDamageStatsCritical + jr c, .lightball + + ld hl, EnemySpDef + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, PlayerSpAtk + +.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, [BattleMonLevel] + ld e, a + call DittoMetalPowder + + ld a, 1 + and a + ret + +; 3534d + + +TruncateHL_BC: ; 3534d +.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, .finish + + 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, .finish + inc l + +.finish + ld a, [wLinkMode] + cp 3 + jr z, .done +; If we go back to the loop point, +; it's the same as doing this exact +; same check twice. + ld a, h + or b + jr nz, .loop + +.done + ld b, l + ret + +; 35378 + + +GetDamageStatsCritical: ; 35378 +; Return carry if non-critical. + + ld a, [CriticalHit] + and a + scf + ret z + + ; fallthrough +; 3537e + + +GetDamageStats: ; 3537e +; Return the attacker's offensive stat and the defender's defensive +; stat based on whether the attacking type is physical or special. + + push hl + push bc + ld a, [hBattleTurn] + and a + jr nz, .enemy + ld a, [wPlayerMoveStructType] + cp SPECIAL +; special + ld a, [PlayerSAtkLevel] + ld b, a + ld a, [EnemySDefLevel] + jr nc, .end +; physical + ld a, [PlayerAtkLevel] + ld b, a + ld a, [EnemyDefLevel] + jr .end + +.enemy + ld a, [wEnemyMoveStructType] + cp SPECIAL +; special + ld a, [EnemySAtkLevel] + ld b, a + ld a, [PlayerSDefLevel] + jr nc, .end +; physical + ld a, [EnemyAtkLevel] + ld b, a + ld a, [PlayerDefLevel] +.end + cp b + pop bc + pop hl + ret + +; 353b5 + + +ThickClubBoost: ; 353b5 +; 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 + +; 353c3 + + +LightBallBoost: ; 353c3 +; 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 + +; 353d1 + + +SpeciesItemBoost: ; 353d1 +; 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 + + ld a, [hBattleTurn] + and a + ld a, [hl] + jr z, .CompareSpecies + ld a, [TempEnemyMonSpecies] +.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 + +; 353f6 + + +EnemyAttackDamage: ; 353f6 + 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, BattleMonDefense + ld a, [hli] + ld b, a + ld c, [hl] + + ld a, [PlayerScreens] + bit SCREENS_REFLECT, a + jr z, .physicalcrit + sla c + rl b + +.physicalcrit + ld hl, EnemyMonAttack + call GetDamageStatsCritical + jr c, .thickclub + + ld hl, PlayerDefense + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, EnemyAttack + jr .thickclub + +.Special: + ld hl, BattleMonSpclDef + ld a, [hli] + ld b, a + ld c, [hl] + + ld a, [PlayerScreens] + bit SCREENS_LIGHT_SCREEN, a + jr z, .specialcrit + sla c + rl b + +.specialcrit + ld hl, EnemyMonSpclAtk + call GetDamageStatsCritical + jr c, .lightball + ld hl, PlayerSpDef + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, EnemySpAtk + +.lightball + call LightBallBoost + jr .done + +.thickclub + call ThickClubBoost + +.done + call TruncateHL_BC + + ld a, [EnemyMonLevel] + ld e, a + call DittoMetalPowder + + ld a, 1 + and a + ret + +; 35461 + + +BattleCommand_BeatUp: ; 35461 +; beatup + + call ResetDamage + ld a, [hBattleTurn] + and a + jp nz, .enemy_beats_up + ld a, [PlayerSubStatus3] + bit SUBSTATUS_IN_LOOP, a + jr nz, .next_mon + ld c, 20 + call DelayFrames + xor a + ld [PlayerRolloutCount], a + ld [wd002], a + ld [wBeatUpHitAtLeastOnce], a + jr .got_mon + +.next_mon + ld a, [PlayerRolloutCount] + ld b, a + ld a, [PartyCount] + sub b + ld [wd002], a + +.got_mon + ld a, [wd002] + ld hl, PartyMonNicknames + call GetNick + ld a, MON_HP + call GetBeatupMonLocation + ld a, [hli] + or [hl] + jp z, .beatup_fail ; fainted + ld a, [wd002] + ld c, a + ld a, [CurBattleMon] + ; BUG: this can desynchronize link battles + ; Change "cp [hl]" to "cp c" to fix + cp [hl] + ld hl, BattleMonStatus + jr z, .active_mon + ld a, MON_STATUS + call GetBeatupMonLocation +.active_mon + ld a, [hl] + and a + jp nz, .beatup_fail + + ld a, $1 + ld [wBeatUpHitAtLeastOnce], a + ld hl, BeatUpAttackText + call StdBattleTextBox + ld a, [EnemyMonSpecies] + ld [CurSpecies], a + call GetBaseData + ld a, [BaseDefense] + ld c, a + push bc + ld a, MON_SPECIES + call GetBeatupMonLocation + ld a, [hl] + ld [CurSpecies], a + call GetBaseData + ld a, [BaseAttack] + pop bc + ld b, a + push bc + ld a, MON_LEVEL + call GetBeatupMonLocation + ld a, [hl] + ld e, a + pop bc + ld a, [wPlayerMoveStructPower] + ld d, a + ret + +.enemy_beats_up + ld a, [EnemySubStatus3] + bit SUBSTATUS_IN_LOOP, a + jr nz, .not_first_enemy_beatup + + xor a + ld [EnemyRolloutCount], a + ld [wd002], a + ld [wBeatUpHitAtLeastOnce], a + jr .enemy_continue + +.not_first_enemy_beatup + ld a, [EnemyRolloutCount] + ld b, a + ld a, [OTPartyCount] + sub b + ld [wd002], a +.enemy_continue + ld a, [wBattleMode] + dec a + jr z, .wild + + ld a, [wLinkMode] + and a + jr nz, .link_or_tower + + ld a, [InBattleTowerBattle] + and a + jr nz, .link_or_tower + + ld a, [wd002] + ld c, a + ld b, 0 + ld hl, OTPartySpecies + add hl, bc + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + jr .got_enemy_nick + +.link_or_tower + ld a, [wd002] + ld hl, OTPartyMonNicknames + ld bc, NAME_LENGTH + call AddNTimes + ld de, StringBuffer1 + call CopyBytes +.got_enemy_nick + ld a, MON_HP + call GetBeatupMonLocation + ld a, [hli] + or [hl] + jp z, .beatup_fail + ld a, [wd002] + ld b, a + ld a, [CurOTMon] + cp b + ld hl, EnemyMonStatus + jr z, .active_enemy + + ld a, MON_STATUS + call GetBeatupMonLocation +.active_enemy + ld a, [hl] + and a + jr nz, .beatup_fail + + ld a, $1 + ld [wBeatUpHitAtLeastOnce], a + jr .finish_beatup + +.wild + ld a, [EnemyMonSpecies] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, BeatUpAttackText + call StdBattleTextBox + jp EnemyAttackDamage + +.finish_beatup + ld hl, BeatUpAttackText + call StdBattleTextBox + ld a, [BattleMonSpecies] + ld [CurSpecies], a + call GetBaseData + ld a, [BaseDefense] + ld c, a + push bc + ld a, MON_SPECIES + call GetBeatupMonLocation + ld a, [hl] + ld [CurSpecies], a + call GetBaseData + ld a, [BaseAttack] + pop bc + ld b, a + push bc + ld a, MON_LEVEL + call GetBeatupMonLocation + ld a, [hl] + ld e, a + pop bc + ld a, [wEnemyMoveStructPower] + ld d, a + ret + +; 355b0 + + +.beatup_fail ; 355b0 + ld b, buildopponentrage_command + jp SkipToBattleCommand + +; 355b5 + + +BattleCommanda8: ; 355b5 + ld a, [wBeatUpHitAtLeastOnce] + and a + ret nz + + jp PrintButItFailed + +; 355bd + + +GetBeatupMonLocation: ; 355bd + push bc + ld c, a + ld b, 0 + ld a, [hBattleTurn] + and a + ld hl, PartyMon1Species + jr z, .got_species + ld hl, OTPartyMon1Species + +.got_species + ld a, [wd002] + add hl, bc + call GetPartyLocation + pop bc + ret + + +BattleCommand_ClearMissDamage: ; 355d5 +; clearmissdamage + ld a, [AttackMissed] + and a + ret z + + jp ResetDamage + +; 355dd + + +HitSelfInConfusion: ; 355dd + call ResetDamage + ld a, [hBattleTurn] + and a + ld hl, BattleMonDefense + ld de, PlayerScreens + ld a, [BattleMonLevel] + jr z, .got_it + + ld hl, EnemyMonDefense + ld de, EnemyScreens + ld a, [EnemyMonLevel] +.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 + +; 35612 + + +BattleCommand_DamageCalc: ; 35612 +; 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 $ff + 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 + ld [hMultiplier], a + call Multiply + +; / 100 + ld a, 100 + ld [hDivisor], a + ld b, 4 + call Divide +.DoneItem: + +; Critical hits + call .CriticalMultiplier + + +; Update CurDamage (capped at 997). + ld hl, CurDamage + ld b, [hl] + ld a, [hProduct + 3] + add b + ld [hProduct + 3], a + jr nc, .dont_cap_1 + + ld a, [hProduct + 2] + inc a + ld [hProduct + 2], a + and a + jr z, .Cap + +.dont_cap_1 + ld a, [hProduct] + ld b, a + ld a, [hProduct + 1] + or a + jr nz, .Cap + + ld 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 + + ld a, [hProduct + 3] + cp LOW(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1) + jr nc, .Cap + +.dont_cap_2 + inc hl + + ld a, [hProduct + 3] + ld b, [hl] + add b + ld [hld], a + + ld 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, [CriticalHit] + and a + ret z + +; x2 + ld a, [hQuotient + 2] + add a + ld [hProduct + 3], a + + ld a, [hQuotient + 1] + rl a + ld [hProduct + 2], a + +; Cap at $ffff. + ret nc + + ld a, $ff + ld [hProduct + 2], a + ld [hProduct + 3], a + + ret + +; 35703 + + +TypeBoostItems: ; 35703 + db HELD_NORMAL_BOOST, NORMAL ; Pink/Polkadot Bow + db HELD_FIGHTING_BOOST, FIGHTING ; Blackbelt + db HELD_FLYING_BOOST, FLYING ; Sharp Beak + db HELD_POISON_BOOST, POISON ; Poison Barb + db HELD_GROUND_BOOST, GROUND ; Soft Sand + db HELD_ROCK_BOOST, ROCK ; Hard Stone + db HELD_BUG_BOOST, BUG ; Silverpowder + db HELD_GHOST_BOOST, GHOST ; Spell Tag + db HELD_FIRE_BOOST, FIRE ; Charcoal + db HELD_WATER_BOOST, WATER ; Mystic Water + db HELD_GRASS_BOOST, GRASS ; Miracle Seed + db HELD_ELECTRIC_BOOST, ELECTRIC ; Magnet + db HELD_PSYCHIC_BOOST, PSYCHIC ; Twistedspoon + db HELD_ICE_BOOST, ICE ; Nevermeltice + db HELD_DRAGON_BOOST, DRAGON ; Dragon Scale + db HELD_DARK_BOOST, DARK ; Blackglasses + db HELD_STEEL_BOOST, STEEL ; Metal Coat + db $ff +; 35726 + + +BattleCommand_ConstantDamage: ; 35726 +; constantdamage + + ld hl, BattleMonLevel + ld a, [hBattleTurn] + and a + jr z, .got_turn + ld hl, EnemyMonLevel + +.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, EnemyMonHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, BattleMonHP +.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, CurDamage + ld [hli], a + ld [hl], b + ret + +.reversal + ld hl, BattleMonHP + ld a, [hBattleTurn] + and a + jr z, .reversal_got_hp + ld hl, EnemyMonHP +.reversal_got_hp + xor a + ld [hDividend], a + ld [hMultiplicand + 0], a + ld a, [hli] + ld [hMultiplicand + 1], a + ld a, [hli] + ld [hMultiplicand + 2], a + ld a, $30 + ld [hMultiplier], a + call Multiply + ld a, [hli] + ld b, a + ld a, [hl] + ld [hDivisor], a + ld a, b + and a + jr z, .skip_to_divide + + ld a, [hProduct + 4] + srl b + rr a + srl b + rr a + ld [hDivisor], a + ld a, [hProduct + 2] + ld b, a + srl b + ld a, [hProduct + 3] + rr a + srl b + rr a + ld [hDividend + 3], a + ld a, b + ld [hDividend + 2], a + +.skip_to_divide + ld b, $4 + call Divide + ld a, [hQuotient + 2] + ld b, a + ld hl, .FlailPower + +.reversal_loop + ld a, [hli] + cp b + jr nc, .break_loop + inc hl + jr .reversal_loop + +.break_loop + ld 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 + +.FlailPower: + ; px, bp + db 1, 200 + db 4, 150 + db 9, 100 + db 16, 80 + db 32, 40 + db 48, 20 +; 35813 + + +BattleCommand_Counter: ; 35813 +; counter + + ld a, 1 + ld [AttackMissed], a + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + and a + ret z + + ld b, a + callfar GetMoveEffect + ld a, b + cp EFFECT_COUNTER + ret z + + call BattleCommand_ResetTypeMatchup + ld a, [wTypeMatchup] + and a + ret z + + call CheckOpponentWentFirst + ret z + + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + dec a + ld de, StringBuffer1 + call GetMoveData + + ld a, [StringBuffer1 + MOVE_POWER] + and a + ret z + + ld a, [StringBuffer1 + MOVE_TYPE] + cp SPECIAL + ret nc + + ld hl, CurDamage + ld a, [hli] + or [hl] + ret z + + ld a, [hl] + add a + ld [hld], a + ld a, [hl] + adc a + ld [hl], a + jr nc, .capped + ld a, $ff + ld [hli], a + ld [hl], a +.capped + + xor a + ld [AttackMissed], a + ret + +; 35864 + + +BattleCommand_Encore: ; 35864 +; encore + + ld hl, EnemyMonMoves + ld de, EnemyEncoreCount + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, BattleMonMoves + ld de, PlayerEncoreCount +.ok + ld a, BATTLE_VARS_LAST_MOVE_OPP + call GetBattleVar + and a + jp z, .failed + cp STRUGGLE + jp z, .failed + cp ENCORE + jp z, .failed + cp MIRROR_MOVE + jp z, .failed + ld b, a + +.got_move + ld a, [hli] + cp b + jr nz, .got_move + + ld bc, BattleMonPP - BattleMonMoves - 1 + add hl, bc + ld a, [hl] + and $3f + jp z, .failed + ld a, [AttackMissed] + and a + jp nz, .failed + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + bit SUBSTATUS_ENCORED, [hl] + jp nz, .failed + set SUBSTATUS_ENCORED, [hl] + call BattleRandom + and $3 + inc a + inc a + inc a + ld [de], a + call CheckOpponentWentFirst + jr nz, .finish_move + ld a, [hBattleTurn] + and a + jr z, .force_last_enemy_move + + push hl + ld a, [LastPlayerMove] + ld b, a + ld c, 0 + ld hl, BattleMonMoves +.find_player_move + ld a, [hli] + cp b + jr z, .got_player_move + inc c + ld a, c + cp NUM_MOVES + jr c, .find_player_move + pop hl + res SUBSTATUS_ENCORED, [hl] + xor a + ld [de], a + jr .failed + +.got_player_move + pop hl + ld a, c + ld [CurMoveNum], a + ld a, b + ld [CurPlayerMove], a + dec a + ld de, wPlayerMoveStruct + call GetMoveData + jr .finish_move + +.force_last_enemy_move + push hl + ld a, [LastEnemyMove] + ld b, a + ld c, 0 + ld hl, EnemyMonMoves +.find_enemy_move + ld a, [hli] + cp b + jr z, .got_enemy_move + inc c + ld a, c + cp NUM_MOVES + jr c, .find_enemy_move + pop hl + res SUBSTATUS_ENCORED, [hl] + xor a + ld [de], a + jr .failed + +.got_enemy_move + pop hl + ld a, c + ld [CurEnemyMoveNum], a + ld a, b + ld [CurEnemyMove], a + dec a + ld de, wEnemyMoveStruct + call GetMoveData + +.finish_move + call AnimateCurrentMove + ld hl, GotAnEncoreText + jp StdBattleTextBox + +.failed + jp PrintDidntAffect2 + +; 35926 + + +BattleCommand_PainSplit: ; 35926 +; painsplit + + ld a, [AttackMissed] + and a + jp nz, .ButItFailed + call CheckSubstituteOpp + jp nz, .ButItFailed + call AnimateCurrentMove + ld hl, BattleMonMaxHP + 1 + ld de, EnemyMonMaxHP + 1 + call .PlayerShareHP + ld a, $1 + ld [wWhichHPBar], a + hlcoord 10, 9 + predef AnimateHPBar + ld hl, EnemyMonHP + ld a, [hli] + ld [Buffer4], a + ld a, [hli] + ld [Buffer3], a + ld a, [hli] + ld [Buffer2], a + ld a, [hl] + ld [Buffer1], a + call .EnemyShareHP + xor a + ld [wWhichHPBar], a + call ResetDamage + hlcoord 2, 2 + predef AnimateHPBar + farcall _UpdateBattleHUDs + + ld hl, SharedPainText + jp StdBattleTextBox + +.PlayerShareHP: + ld a, [hld] + ld [Buffer1], a + ld a, [hld] + ld [Buffer2], a + ld a, [hld] + ld b, a + ld [Buffer3], a + ld a, [hl] + ld [Buffer4], a + dec de + dec de + ld a, [de] + dec de + add b + ld [CurDamage + 1], a + ld b, [hl] + ld a, [de] + adc b + srl a + ld [CurDamage], a + ld a, [CurDamage + 1] + rr a + ld [CurDamage + 1], a + inc hl + inc hl + inc hl + inc de + inc de + inc de + +.EnemyShareHP: ; 359ac + ld c, [hl] + dec hl + ld a, [CurDamage + 1] + sub c + ld b, [hl] + dec hl + ld a, [CurDamage] + sbc b + jr nc, .skip + + ld a, [CurDamage] + ld b, a + ld a, [CurDamage + 1] + ld c, a +.skip + ld a, c + ld [hld], a + ld [Buffer5], a + ld a, b + ld [hli], a + ld [Buffer6], a + ret + +; 359cd + +.ButItFailed: + jp PrintDidntAffect2 + +; 359d0 + + +BattleCommand_Snore: ; 359d0 +; snore + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + ret nz + call ResetDamage + ld a, $1 + ld [AttackMissed], a + call FailSnore + jp EndMoveEffect + +; 359e6 + + +BattleCommand_Conversion2: ; 359e6 +; conversion2 + + ld a, [AttackMissed] + and a + jr nz, .failed + ld hl, BattleMonType1 + ld a, [hBattleTurn] + and a + jr z, .got_type + ld hl, EnemyMonType1 +.got_type + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + and a + jr z, .failed + push hl + dec a + ld hl, Moves + MOVE_TYPE + call GetMoveAttr + ld d, a + pop hl + cp CURSE_T + jr z, .failed + call AnimateCurrentMove + call BattleCommand_SwitchTurn + +.loop + call BattleRandom + and $1f + cp UNUSED_TYPES + jr c, .okay + cp UNUSED_TYPES_END + jr c, .loop + cp TYPES_END + jr nc, .loop +.okay + ld [hli], a + ld [hld], a + push hl + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVarAddr + push af + push hl + ld a, d + ld [hl], a + call BattleCheckTypeMatchup + pop hl + pop af + ld [hl], a + pop hl + ld a, [wTypeMatchup] + cp 10 + jr nc, .loop + call BattleCommand_SwitchTurn + + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + predef GetTypeName + ld hl, TransformedTypeText + jp StdBattleTextBox + +.failed + jp FailConversion2 + +; 35a53 + + +BattleCommand_LockOn: ; 35a53 +; lockon + + call CheckSubstituteOpp + jr nz, .fail + + ld a, [AttackMissed] + and a + jr nz, .fail + + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + set SUBSTATUS_LOCK_ON, [hl] + call AnimateCurrentMove + + ld hl, TookAimText + jp StdBattleTextBox + +.fail + call AnimateFailedMove + jp PrintDidntAffect + +; 35a74 + + +BattleCommand_Sketch: ; 35a74 +; sketch + + call ClearLastMove +; Don't sketch during a link battle + ld a, [wLinkMode] + and a + jr z, .not_linked + call AnimateFailedMove + jp PrintNothingHappened + +.not_linked +; If the opponent has a substitute up, fail. + call CheckSubstituteOpp + jp nz, .fail +; If the opponent is transformed, fail. + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + bit SUBSTATUS_TRANSFORMED, [hl] + jp nz, .fail +; Get the user's moveset in its party struct. +; This move replacement shall be permanent. +; Pointer will be in de. + ld a, MON_MOVES + call UserPartyAttr + ld d, h + ld e, l +; Get the battle move structs. + ld hl, BattleMonMoves + ld a, [hBattleTurn] + and a + jr z, .get_last_move + ld hl, EnemyMonMoves +.get_last_move + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + ld [wTypeMatchup], a + ld b, a +; Fail if move is invalid or is Struggle. + and a + jr z, .fail + cp STRUGGLE + jr z, .fail +; Fail if user already knows that move + ld c, NUM_MOVES +.does_user_already_know_move + ld a, [hli] + cp b + jr z, .fail + dec c + jr nz, .does_user_already_know_move +; Find Sketch in the user's moveset. +; Pointer in hl, and index in c. + dec hl + ld c, NUM_MOVES +.find_sketch + dec c + ld a, [hld] + cp SKETCH + jr nz, .find_sketch + inc hl +; The Sketched move is loaded to that slot. + ld a, b + ld [hl], a +; Copy the base PP from that move. + push bc + push hl + dec a + ld hl, Moves + MOVE_PP + call GetMoveAttr + pop hl + ld bc, BattleMonPP - BattleMonMoves + add hl, bc + ld [hl], a + pop bc + + ld a, [hBattleTurn] + and a + jr z, .user_trainer + ld a, [wBattleMode] + dec a + jr nz, .user_trainer +; wildmon + ld a, [hl] + push bc + ld hl, wWildMonPP + ld b, 0 + add hl, bc + ld [hl], a + ld hl, wWildMonMoves + add hl, bc + pop bc + ld [hl], b + jr .done_copy + +.user_trainer + ld a, [hl] + push af + ld l, c + ld h, 0 + add hl, de + ld a, b + ld [hl], a + pop af + ld de, MON_PP - MON_MOVES + add hl, de + ld [hl], a +.done_copy + call GetMoveName + call AnimateCurrentMove + + ld hl, SketchedText + jp StdBattleTextBox + +.fail + call AnimateFailedMove + jp PrintDidntAffect + +; 35b16 + + +BattleCommand_DefrostOpponent: ; 35b16 +; 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 + +; 35b33 + + +BattleCommand_SleepTalk: ; 35b33 +; sleeptalk + + call ClearLastMove + ld a, [AttackMissed] + and a + jr nz, .fail + ld a, [hBattleTurn] + and a + ld hl, BattleMonMoves + 1 + ld a, [DisabledMove] + ld d, a + jr z, .got_moves + ld hl, EnemyMonMoves + 1 + ld a, [EnemyDisabledMove] + ld d, a +.got_moves + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + jr z, .fail + ld a, [hl] + and a + jr z, .fail + call .safely_check_has_usable_move + jr c, .fail + dec hl +.sample_move + push hl + call BattleRandom + and 3 ; TODO factor in NUM_MOVES + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + pop hl + and a + jr z, .sample_move + ld e, a + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp e + jr z, .sample_move + ld a, e + cp d + jr z, .sample_move + call .check_two_turn_move + jr z, .sample_move + ld a, BATTLE_VARS_MOVE + call GetBattleVarAddr + ld a, e + ld [hl], a + call CheckUserIsCharging + jr nz, .charging + ld a, [wKickCounter] + push af + call BattleCommand_LowerSub + pop af + ld [wKickCounter], a +.charging + call LoadMoveAnim + call UpdateMoveData + jp ResetTurn + +.fail + call AnimateFailedMove + jp TryPrintButItFailed + +.safely_check_has_usable_move + push hl + push de + push bc + call .check_has_usable_move + pop bc + pop de + pop hl + ret + +.check_has_usable_move + ld a, [hBattleTurn] + and a + ld a, [DisabledMove] + jr z, .got_move_2 + + ld a, [EnemyDisabledMove] +.got_move_2 + ld b, a + ld a, BATTLE_VARS_MOVE + call GetBattleVar + ld c, a + dec hl + ld d, NUM_MOVES +.loop2 + ld a, [hl] + and a + jr z, .carry + + cp c + jr z, .nope + cp b + jr z, .nope + + call .check_two_turn_move + jr nz, .no_carry + +.nope + inc hl + dec d + jr nz, .loop2 + +.carry + scf + ret + +.no_carry + and a + ret + +.check_two_turn_move + push hl + push de + push bc + + ld b, a + callfar GetMoveEffect + ld a, b + + pop bc + pop de + pop hl + + cp EFFECT_SKULL_BASH + ret z + cp EFFECT_RAZOR_WIND + ret z + cp EFFECT_SKY_ATTACK + ret z + cp EFFECT_SOLARBEAM + ret z + cp EFFECT_FLY + ret z + cp EFFECT_BIDE + ret + +; 35bff + + +BattleCommand_DestinyBond: ; 35bff +; destinybond + + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVarAddr + set SUBSTATUS_DESTINY_BOND, [hl] + call AnimateCurrentMove + ld hl, DestinyBondEffectText + jp StdBattleTextBox + +; 35c0f + + +BattleCommand_Spite: ; 35c0f +; spite + + ld a, [AttackMissed] + and a + jp nz, .failed + ld bc, PARTYMON_STRUCT_LENGTH ; ???? + ld hl, EnemyMonMoves + ld a, [hBattleTurn] + and a + jr z, .got_moves + ld hl, BattleMonMoves +.got_moves + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + and a + jr z, .failed + cp STRUGGLE + jr z, .failed + ld b, a + ld c, -1 +.loop + inc c + ld a, [hli] + cp b + jr nz, .loop + ld [wTypeMatchup], a + dec hl + ld b, 0 + push bc + ld c, BattleMonPP - BattleMonMoves + add hl, bc + pop bc + ld a, [hl] + and $3f + jr z, .failed + push bc + call GetMoveName + call BattleRandom + and 3 + inc a + inc a + ld b, a + ld a, [hl] + and $3f + cp b + jr nc, .deplete_pp + ld b, a +.deplete_pp + ld a, [hl] + sub b + ld [hl], a + push af + ld a, MON_PP + call OpponentPartyAttr + ld d, b + pop af + pop bc + add hl, bc + ld e, a + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVar + bit SUBSTATUS_TRANSFORMED, a + jr nz, .transformed + ld a, [hBattleTurn] + and a + jr nz, .not_wildmon + ld a, [wBattleMode] + dec a + jr nz, .not_wildmon + ld hl, wWildMonPP + add hl, bc +.not_wildmon + ld [hl], e +.transformed + push de + call AnimateCurrentMove + pop de + ld a, d + ld [wTypeMatchup], a + ld hl, SpiteEffectText + jp StdBattleTextBox + +.failed + jp PrintDidntAffect2 + +; 35c94 + + +BattleCommand_FalseSwipe: ; 35c94 +; falseswipe + + ld hl, EnemyMonHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, BattleMonHP +.got_hp + ld de, CurDamage + ld c, 2 + push hl + push de + call StringCmp + pop de + pop hl + jr c, .done + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + dec a + ld [de], a + inc a + jr nz, .okay + dec de + ld a, [de] + dec a + ld [de], a +.okay + ld a, [CriticalHit] + cp $2 + jr nz, .carry + xor a + ld [CriticalHit], a +.carry + scf + ret + +.done + and a + ret + +; 35cc9 + + +BattleCommand_HealBell: ; 35cc9 +; healbell + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + res SUBSTATUS_NIGHTMARE, [hl] + ld de, PartyMon1Status + ld a, [hBattleTurn] + and a + jr z, .got_status + ld de, OTPartyMon1Status +.got_status + ld a, BATTLE_VARS_STATUS + call GetBattleVarAddr + xor a + ld [hl], a + ld h, d + ld l, e + ld bc, PARTYMON_STRUCT_LENGTH + ld d, PARTY_LENGTH +.loop + ld [hl], a + add hl, bc + dec d + jr nz, .loop + call AnimateCurrentMove + + ld hl, BellChimedText + call StdBattleTextBox + + ld a, [hBattleTurn] + and a + jp z, CalcPlayerStats + jp CalcEnemyStats + +; 35d00 + + +FarPlayBattleAnimation: ; 35d00 +; play animation de + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret nz + + ; fallthrough +; 35d08 + +PlayFXAnimID: ; 35d08 + ld a, e + ld [FXAnimID], a + ld a, d + ld [FXAnimID + 1], a + + ld c, 3 + call DelayFrames + + callfar PlayBattleAnim + + ret + +; 35d1c + + +EnemyHurtItself: ; 35d1c + ld hl, CurDamage + ld a, [hli] + ld b, a + ld a, [hl] + or b + jr z, .did_no_damage + + ld a, c + and a + jr nz, .mimic_sub_check + + ld a, [EnemySubStatus4] + bit SUBSTATUS_SUBSTITUTE, a + jp nz, SelfInflictDamageToSubstitute + +.mimic_sub_check + ld a, [hld] + ld b, a + ld a, [EnemyMonHP + 1] + ld [Buffer3], a + sub b + ld [EnemyMonHP + 1], a + ld a, [hl] + ld b, a + ld a, [EnemyMonHP] + ld [Buffer4], a + sbc b + ld [EnemyMonHP], a + jr nc, .mimic_faint + + ld a, [Buffer4] + ld [hli], a + ld a, [Buffer3] + ld [hl], a + + xor a + ld hl, EnemyMonHP + ld [hli], a + ld [hl], a + +.mimic_faint + ld hl, EnemyMonMaxHP + ld a, [hli] + ld [Buffer2], a + ld a, [hl] + ld [Buffer1], a + ld hl, EnemyMonHP + ld a, [hli] + ld [Buffer6], a + ld a, [hl] + ld [Buffer5], a + hlcoord 2, 2 + xor a + ld [wWhichHPBar], a + predef AnimateHPBar +.did_no_damage + jp RefreshBattleHuds + +; 35d7e + + +PlayerHurtItself: ; 35d7e + ld hl, CurDamage + ld a, [hli] + ld b, a + ld a, [hl] + or b + jr z, .did_no_damage + + ld a, c + and a + jr nz, .mimic_sub_check + + ld a, [PlayerSubStatus4] + bit SUBSTATUS_SUBSTITUTE, a + jp nz, SelfInflictDamageToSubstitute +.mimic_sub_check + ld a, [hld] + ld b, a + ld a, [BattleMonHP + 1] + ld [Buffer3], a + sub b + ld [BattleMonHP + 1], a + ld [Buffer5], a + ld b, [hl] + ld a, [BattleMonHP] + ld [Buffer4], a + sbc b + ld [BattleMonHP], a + ld [Buffer6], a + jr nc, .mimic_faint + + ld a, [Buffer4] + ld [hli], a + ld a, [Buffer3] + ld [hl], a + xor a + + ld hl, BattleMonHP + ld [hli], a + ld [hl], a + ld hl, Buffer5 + ld [hli], a + ld [hl], a + +.mimic_faint + ld hl, BattleMonMaxHP + ld a, [hli] + ld [Buffer2], a + ld a, [hl] + ld [Buffer1], a + hlcoord 10, 9 + ld a, $1 + ld [wWhichHPBar], a + predef AnimateHPBar +.did_no_damage + jp RefreshBattleHuds + +; 35de0 + + +SelfInflictDamageToSubstitute: ; 35de0 + + ld hl, SubTookDamageText + call StdBattleTextBox + + ld de, EnemySubstituteHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld de, PlayerSubstituteHP +.got_hp + + ld hl, CurDamage + 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 + +; 35e40 + + +UpdateMoveData: ; 35e40 + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVarAddr + ld d, h + ld e, l + + ld a, BATTLE_VARS_MOVE + call GetBattleVar + ld [CurMove], a + ld [wNamedObjectIndexBuffer], a + + dec a + call GetMoveData + call GetMoveName + jp CopyName1 + +; 35e5c + + +BattleCommand_SleepTarget: ; 35e5c +; sleeptarget + + call GetOpponentItem + ld a, b + cp HELD_PREVENT_SLEEP + jr nz, .not_protected_by_item + + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetItemName + ld hl, ProtectedByText + jr .fail + +.not_protected_by_item + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + ld d, h + ld e, l + ld a, [de] + and SLP + ld hl, AlreadyAsleepText + jr nz, .fail + + ld a, [AttackMissed] + and a + jp nz, PrintDidntAffect2 + + ld hl, DidntAffect1Text + call .CheckAIRandomFail + jr c, .fail + + ld a, [de] + and a + jr nz, .fail + + call CheckSubstituteOpp + jr nz, .fail + + call AnimateCurrentMove + ld b, $7 + ld a, [InBattleTowerBattle] + and a + jr z, .random_loop + ld b, $3 + +.random_loop + call BattleRandom + and b + jr z, .random_loop + cp 7 + jr z, .random_loop + inc a + ld [de], a + call UpdateOpponentInParty + call RefreshBattleHuds + + ld hl, FellAsleepText + call StdBattleTextBox + + farcall UseHeldStatusHealingItem + + jp z, OpponentCantMove + ret + +.fail + push hl + call AnimateFailedMove + pop hl + jp StdBattleTextBox + +; 35ece + + +.CheckAIRandomFail: ; 35ece + ; Enemy turn + ld a, [hBattleTurn] + and a + jr z, .dont_fail + + ; Not in link battle + ld a, [wLinkMode] + and a + jr nz, .dont_fail + + ld a, [InBattleTowerBattle] + and a + jr nz, .dont_fail + + ; Not locked-on by the enemy + ld a, [PlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .dont_fail + + call BattleRandom + cp $40 ; 25% + ret c + +.dont_fail + xor a + ret + +; 35eee + + +BattleCommand_PoisonTarget: ; 35eee +; poisontarget + + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + ret nz + ld a, [TypeModifier] + and $7f + ret z + call CheckIfTargetIsPoisonType + ret z + call GetOpponentItem + ld a, b + cp HELD_PREVENT_POISON + ret z + ld a, [EffectFailed] + and a + ret nz + call SafeCheckSafeguard + ret nz + + call PoisonOpponent + ld de, ANIM_PSN + call PlayOpponentBattleAnim + call RefreshBattleHuds + + ld hl, WasPoisonedText + call StdBattleTextBox + + farcall UseHeldStatusHealingItem + ret + +; 35f2c + + +BattleCommand_Poison: ; 35f2c +; poison + + ld hl, DoesntAffectText + ld a, [TypeModifier] + and $7f + jp z, .failed + + call CheckIfTargetIsPoisonType + jp z, .failed + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVar + ld b, a + ld hl, AlreadyPoisonedText + and 1 << PSN + jp nz, .failed + + call GetOpponentItem + ld a, b + cp HELD_PREVENT_POISON + jr nz, .do_poison + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetItemName + ld hl, ProtectedByText + jr .failed + +.do_poison + ld hl, DidntAffect1Text + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVar + and a + jr nz, .failed + + ld a, [hBattleTurn] + and a + jr z, .mimic_random + + ld a, [wLinkMode] + and a + jr nz, .mimic_random + + ld a, [InBattleTowerBattle] + and a + jr nz, .mimic_random + + ld a, [PlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .mimic_random + + call BattleRandom + cp $40 ; 25% chance AI fails + jr c, .failed + +.mimic_random + call CheckSubstituteOpp + jr nz, .failed + ld a, [AttackMissed] + and a + jr nz, .failed + call .check_toxic + jr z, .toxic + + call .apply_poison + ld hl, WasPoisonedText + call StdBattleTextBox + jr .finished + +.toxic + set SUBSTATUS_TOXIC, [hl] + xor a + ld [de], a + call .apply_poison + + ld hl, BadlyPoisonedText + call StdBattleTextBox + +.finished + farcall UseHeldStatusHealingItem + ret + +.failed + push hl + call AnimateFailedMove + pop hl + jp StdBattleTextBox + +; 35fc0 + + +.apply_poison ; 35fc0 + call AnimateCurrentMove + call PoisonOpponent + jp RefreshBattleHuds + +; 35fc9 + + +.check_toxic ; 35fc9 + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + ld a, [hBattleTurn] + and a + ld de, EnemyToxicCount + jr z, .ok + ld de, PlayerToxicCount +.ok + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_TOXIC + ret + +; 35fe1 + + +CheckIfTargetIsPoisonType: ; 35fe1 + ld de, EnemyMonType1 + ld a, [hBattleTurn] + and a + jr z, .ok + ld de, BattleMonType1 +.ok + ld a, [de] + inc de + cp POISON + ret z + ld a, [de] + cp POISON + ret + +; 35ff5 + + +PoisonOpponent: ; 35ff5 + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + set PSN, [hl] + jp UpdateOpponentInParty + +; 35fff + + +BattleCommand_DrainTarget: ; 35fff +; draintarget + call SapHealth + ld hl, SuckedHealthText + jp StdBattleTextBox + +; 36008 + + +BattleCommand_EatDream: ; 36008 +; eatdream + call SapHealth + ld hl, DreamEatenText + jp StdBattleTextBox + +; 36011 + + +SapHealth: ; 36011 + ld hl, CurDamage + ld a, [hli] + srl a + ld [hDividend], a + ld b, a + ld a, [hl] + rr a + ld [hDividend + 1], a + or b + jr nz, .ok1 + ld a, $1 + ld [hDividend + 1], a +.ok1 + ld hl, BattleMonHP + ld de, BattleMonMaxHP + ld a, [hBattleTurn] + and a + jr z, .battlemonhp + ld hl, EnemyMonHP + ld de, EnemyMonMaxHP +.battlemonhp + ld bc, Buffer4 + ld a, [hli] + ld [bc], a + ld a, [hl] + dec bc + ld [bc], a + ld a, [de] + dec bc + ld [bc], a + inc de + ld a, [de] + dec bc + ld [bc], a + ld a, [hDividend + 1] + ld b, [hl] + add b + ld [hld], a + ld [Buffer5], a + ld a, [hDividend] + ld b, [hl] + adc b + ld [hli], a + ld [Buffer6], a + jr c, .okay2 + ld a, [hld] + ld b, a + ld a, [de] + dec de + sub b + ld a, [hli] + ld b, a + ld a, [de] + inc de + sbc b + jr nc, .okay3 +.okay2 + ld a, [de] + ld [hld], a + ld [Buffer5], a + dec de + ld a, [de] + ld [hli], a + ld [Buffer6], a + inc de +.okay3 + ld a, [hBattleTurn] + and a + hlcoord 10, 9 + ld a, $1 + jr z, .hp_bar + hlcoord 2, 2 + xor a +.hp_bar + ld [wWhichHPBar], a + predef AnimateHPBar + call RefreshBattleHuds + jp UpdateBattleMonInParty + +; 3608c + + +BattleCommand_BurnTarget: ; 3608c +; burntarget + + xor a + ld [wNumHits], a + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + jp nz, Defrost + ld a, [TypeModifier] + and $7f + ret z + call CheckMoveTypeMatchesTarget ; Don't burn a Fire-type + ret z + call GetOpponentItem + ld a, b + cp HELD_PREVENT_BURN + ret z + ld a, [EffectFailed] + and a + ret nz + call SafeCheckSafeguard + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + set BRN, [hl] + call UpdateOpponentInParty + ld hl, ApplyBrnEffectOnAttack + call CallBattleCore + ld de, ANIM_BRN + call PlayOpponentBattleAnim + call RefreshBattleHuds + + ld hl, WasBurnedText + call StdBattleTextBox + + farcall UseHeldStatusHealingItem + ret + +; 360dd + + +Defrost: ; 360dd + ld a, [hl] + and 1 << FRZ + ret z + + xor a + ld [hl], a + + ld a, [hBattleTurn] + and a + ld a, [CurOTMon] + ld hl, OTPartyMon1Status + jr z, .ok + ld hl, PartyMon1Status + ld a, [CurBattleMon] +.ok + + call GetPartyLocation + xor a + ld [hl], a + call UpdateOpponentInParty + + ld hl, DefrostedOpponentText + jp StdBattleTextBox + +; 36102 + + +BattleCommand_FreezeTarget: ; 36102 +; freezetarget + + xor a + ld [wNumHits], a + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + ret nz + ld a, [TypeModifier] + and $7f + ret z + ld a, [Weather] + cp WEATHER_SUN + ret z + call CheckMoveTypeMatchesTarget ; Don't freeze an Ice-type + ret z + call GetOpponentItem + ld a, b + cp HELD_PREVENT_FREEZE + ret z + ld a, [EffectFailed] + and a + ret nz + call SafeCheckSafeguard + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + set FRZ, [hl] + call UpdateOpponentInParty + ld de, ANIM_FRZ + call PlayOpponentBattleAnim + call RefreshBattleHuds + + ld hl, WasFrozenText + call StdBattleTextBox + + farcall UseHeldStatusHealingItem + ret nz + + call OpponentCantMove + call EndRechargeOpp + ld hl, wEnemyJustGotFrozen + ld a, [hBattleTurn] + and a + jr z, .finish + ld hl, wPlayerJustGotFrozen +.finish + ld [hl], $1 + ret + +; 36165 + + +BattleCommand_ParalyzeTarget: ; 36165 +; paralyzetarget + + xor a + ld [wNumHits], a + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + ret nz + ld a, [TypeModifier] + and $7f + ret z + call GetOpponentItem + ld a, b + cp HELD_PREVENT_PARALYZE + ret z + ld a, [EffectFailed] + and a + ret nz + call SafeCheckSafeguard + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + set PAR, [hl] + call UpdateOpponentInParty + ld hl, ApplyPrzEffectOnSpeed + call CallBattleCore + ld de, ANIM_PAR + call PlayOpponentBattleAnim + call RefreshBattleHuds + call PrintParalyze + ld hl, UseHeldStatusHealingItem + jp CallBattleCore + +; 361ac + + +BattleCommand_AttackUp: ; 361ac +; attackup + ld b, ATTACK + jr BattleCommand_StatUp + +BattleCommand_DefenseUp: ; 361b0 +; defenseup + ld b, DEFENSE + jr BattleCommand_StatUp + +BattleCommand_SpeedUp: ; 361b4 +; speedup + ld b, SPEED + jr BattleCommand_StatUp + +BattleCommand_SpecialAttackUp: ; 361b8 +; specialattackup + ld b, SP_ATTACK + jr BattleCommand_StatUp + +BattleCommand_SpecialDefenseUp: ; 361bc +; specialdefenseup + ld b, SP_DEFENSE + jr BattleCommand_StatUp + +BattleCommand_AccuracyUp: ; 361c0 +; accuracyup + ld b, ACCURACY + jr BattleCommand_StatUp + +BattleCommand_EvasionUp: ; 361c4 +; evasionup + ld b, EVASION + jr BattleCommand_StatUp + +BattleCommand_AttackUp2: ; 361c8 +; attackup2 + ld b, $10 | ATTACK + jr BattleCommand_StatUp + +BattleCommand_DefenseUp2: ; 361cc +; defenseup2 + ld b, $10 | DEFENSE + jr BattleCommand_StatUp + +BattleCommand_SpeedUp2: ; 361d0 +; speedup2 + ld b, $10 | SPEED + jr BattleCommand_StatUp + +BattleCommand_SpecialAttackUp2: ; 361d4 +; specialattackup2 + ld b, $10 | SP_ATTACK + jr BattleCommand_StatUp + +BattleCommand_SpecialDefenseUp2: ; 361d8 +; specialdefenseup2 + ld b, $10 | SP_DEFENSE + jr BattleCommand_StatUp + +BattleCommand_AccuracyUp2: ; 361dc +; accuracyup2 + ld b, $10 | ACCURACY + jr BattleCommand_StatUp + +BattleCommand_EvasionUp2: ; 361e0 +; evasionup2 + ld b, $10 | EVASION + jr BattleCommand_StatUp + +BattleCommand_StatUp: ; 361e4 +; statup + call CheckIfStatCanBeRaised + ld a, [FailedMessage] + and a + ret nz + jp StatUpAnimation + +; 361ef + + +CheckIfStatCanBeRaised: ; 361ef + ld a, b + ld [LoweredStat], a + ld hl, PlayerStatLevels + ld a, [hBattleTurn] + and a + jr z, .got_stat_levels + ld hl, EnemyStatLevels +.got_stat_levels + ld a, [AttackMissed] + and a + jp nz, .stat_raise_failed + ld a, [EffectFailed] + and a + jp nz, .stat_raise_failed + ld a, [LoweredStat] + and $f + ld c, a + ld b, 0 + add hl, bc + ld b, [hl] + inc b + ld a, $d + cp b + jp c, .cant_raise_stat + ld a, [LoweredStat] + and $f0 + jr z, .got_num_stages + inc b + ld a, $d + cp b + jr nc, .got_num_stages + ld b, a +.got_num_stages + ld [hl], b + push hl + ld a, c + cp $5 + jr nc, .done_calcing_stats + ld hl, BattleMonStats + 1 + ld de, PlayerStats + ld a, [hBattleTurn] + and a + jr z, .got_stats_pointer + ld hl, EnemyMonStats + 1 + ld de, EnemyStats +.got_stats_pointer + push bc + sla c + ld b, 0 + add hl, bc + ld a, c + add e + ld e, a + jr nc, .no_carry + inc d +.no_carry + pop bc + ld a, [hld] + sub LOW(MAX_STAT_VALUE) + jr nz, .not_already_max + ld a, [hl] + sbc HIGH(MAX_STAT_VALUE) + jp z, .stats_already_max +.not_already_max + ld a, [hBattleTurn] + and a + jr z, .calc_player_stats + call CalcEnemyStats + jr .done_calcing_stats + +.calc_player_stats + call CalcPlayerStats +.done_calcing_stats + pop hl + xor a + ld [FailedMessage], a + ret + +; 3626e + + +.stats_already_max ; 3626e + pop hl + dec [hl] + ; fallthrough +; 36270 + + +.cant_raise_stat ; 36270 + ld a, $2 + ld [FailedMessage], a + ld a, $1 + ld [AttackMissed], a + ret + +; 3627b + + +.stat_raise_failed ; 3627b + ld a, $1 + ld [FailedMessage], a + ret + +; 36281 + + +StatUpAnimation: ; 36281 + ld bc, wPlayerMinimized + ld hl, DropPlayerSub + ld a, [hBattleTurn] + and a + jr z, .do_player + ld bc, wEnemyMinimized + ld hl, DropEnemySub +.do_player + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp MINIMIZE + ret nz + + ld a, $1 + ld [bc], a + call _CheckBattleScene + ret nc + + xor a + ld [hBGMapMode], a + call CallBattleCore + call WaitBGMap + jp BattleCommand_MoveDelay + +; 362ad + + +BattleCommand_AttackDown: ; 362ad +; attackdown + ld a, ATTACK + jr BattleCommand_StatDown + +BattleCommand_DefenseDown: ; 362b1 +; defensedown + ld a, DEFENSE + jr BattleCommand_StatDown + +BattleCommand_SpeedDown: ; 362b5 +; speeddown + ld a, SPEED + jr BattleCommand_StatDown + +BattleCommand_SpecialAttackDown: ; 362b9 +; specialattackdown + ld a, SP_ATTACK + jr BattleCommand_StatDown + +BattleCommand_SpecialDefenseDown: ; 362bd +; specialdefensedown + ld a, SP_DEFENSE + jr BattleCommand_StatDown + +BattleCommand_AccuracyDown: ; 362c1 +; accuracydown + ld a, ACCURACY + jr BattleCommand_StatDown + +BattleCommand_EvasionDown: ; 362c5 +; evasiondown + ld a, EVASION + jr BattleCommand_StatDown + +BattleCommand_AttackDown2: ; 362c9 +; attackdown2 + ld a, $10 | ATTACK + jr BattleCommand_StatDown + +BattleCommand_DefenseDown2: ; 362cd +; defensedown2 + ld a, $10 | DEFENSE + jr BattleCommand_StatDown + +BattleCommand_SpeedDown2: ; 362d1 +; speeddown2 + ld a, $10 | SPEED + jr BattleCommand_StatDown + +BattleCommand_SpecialAttackDown2: ; 362d5 +; specialattackdown2 + ld a, $10 | SP_ATTACK + jr BattleCommand_StatDown + +BattleCommand_SpecialDefenseDown2: ; 362d9 +; specialdefensedown2 + ld a, $10 | SP_DEFENSE + jr BattleCommand_StatDown + +BattleCommand_AccuracyDown2: ; 362dd +; accuracydown2 + ld a, $10 | ACCURACY + jr BattleCommand_StatDown + +BattleCommand_EvasionDown2: ; 362e1 +; evasiondown2 + ld a, $10 | EVASION + +BattleCommand_StatDown: ; 362e3 +; statdown + + ld [LoweredStat], a + + call CheckMist + jp nz, .Mist + + ld hl, EnemyStatLevels + ld a, [hBattleTurn] + and a + jr z, .GetStatLevel + ld hl, PlayerStatLevels + +.GetStatLevel: +; Attempt to lower the stat. + ld a, [LoweredStat] + and $f + ld c, a + ld b, 0 + add hl, bc + ld b, [hl] + dec b + jp z, .CantLower + +; Sharply lower the stat if applicable. + ld a, [LoweredStat] + and $f0 + jr z, .ComputerMiss + dec b + jr nz, .ComputerMiss + inc b + +.ComputerMiss: +; Computer opponents have a 1/4 chance of failing. + ld a, [hBattleTurn] + and a + jr z, .DidntMiss + + ld a, [wLinkMode] + and a + jr nz, .DidntMiss + + ld a, [InBattleTowerBattle] + and a + jr nz, .DidntMiss + +; Lock-On still always works. + ld a, [PlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .DidntMiss + +; Attacking moves that also lower accuracy are unaffected. + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_ACCURACY_DOWN_HIT + jr z, .DidntMiss + + call BattleRandom + cp $40 + jr c, .Failed + +.DidntMiss: + call CheckSubstituteOpp + jr nz, .Failed + + ld a, [AttackMissed] + and a + jr nz, .Failed + + ld a, [EffectFailed] + and a + jr nz, .Failed + + call CheckHiddenOpponent + jr nz, .Failed + +; Accuracy/Evasion reduction don't involve stats. + ld [hl], b + ld a, c + cp ACCURACY + jr nc, .Hit + + push hl + ld hl, EnemyMonAttack + 1 + ld de, EnemyStats + ld a, [hBattleTurn] + and a + jr z, .do_enemy + ld hl, BattleMonAttack + 1 + ld de, PlayerStats +.do_enemy + call TryLowerStat + pop hl + jr z, .CouldntLower + +.Hit: + xor a + ld [FailedMessage], a + ret + +.CouldntLower: + inc [hl] +.CantLower: + ld a, 3 + ld [FailedMessage], a + ld a, 1 + ld [AttackMissed], a + ret + +.Failed: + ld a, 1 + ld [FailedMessage], a + ld [AttackMissed], a + ret + +.Mist: + ld a, 2 + ld [FailedMessage], a + ld a, 1 + ld [AttackMissed], a + ret + +; 36391 + + +CheckMist: ; 36391 + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_ATTACK_DOWN + jr c, .dont_check_mist + cp EFFECT_EVASION_DOWN + 1 + jr c, .check_mist + cp EFFECT_ATTACK_DOWN_2 + jr c, .dont_check_mist + cp EFFECT_EVASION_DOWN_2 + 1 + jr c, .check_mist + cp EFFECT_ATTACK_DOWN_HIT + jr c, .dont_check_mist + cp EFFECT_EVASION_DOWN_HIT + 1 + jr c, .check_mist +.dont_check_mist + xor a + ret + +.check_mist + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVar + bit SUBSTATUS_MIST, a + ret + +; 363b8 + + +BattleCommand_StatUpMessage: ; 363b8 + ld a, [FailedMessage] + and a + ret nz + ld a, [LoweredStat] + and $f + ld b, a + inc b + call GetStatName + ld hl, .stat + jp BattleTextBox + +.stat + text_jump UnknownText_0x1c0cc6 + start_asm + ld hl, .up + ld a, [LoweredStat] + and $f0 + ret z + ld hl, .wayup + ret + +.wayup + text_jump UnknownText_0x1c0cd0 + db "@" + +.up + text_jump UnknownText_0x1c0ce0 + db "@" + +; 363e9 + + +BattleCommand_StatDownMessage: ; 363e9 + ld a, [FailedMessage] + and a + ret nz + ld a, [LoweredStat] + and $f + ld b, a + inc b + call GetStatName + ld hl, .stat + jp BattleTextBox + +.stat + text_jump UnknownText_0x1c0ceb + start_asm + ld hl, .fell + ld a, [LoweredStat] + and $f0 + ret z + ld hl, .sharplyfell + ret + +.sharplyfell + text_jump UnknownText_0x1c0cf5 + db "@" +.fell + text_jump UnknownText_0x1c0d06 + db "@" + +; 3641a + + +TryLowerStat: ; 3641a +; Lower stat c from stat struct hl (buffer de). + + push bc + sla c + ld b, 0 + add hl, bc + ; add de, c + ld a, c + add e + ld e, a + jr nc, .no_carry + inc d +.no_carry + pop bc + +; The lowest possible stat is 1. + ld a, [hld] + sub 1 + jr nz, .not_min + ld a, [hl] + and a + ret z + +.not_min + ld a, [hBattleTurn] + and a + jr z, .Player + + call BattleCommand_SwitchTurn + call CalcPlayerStats + call BattleCommand_SwitchTurn + jr .end + +.Player: + call BattleCommand_SwitchTurn + call CalcEnemyStats + call BattleCommand_SwitchTurn +.end + ld a, 1 + and a + ret + +; 3644c + + +BattleCommand_StatUpFailText: ; 3644c +; statupfailtext + ld a, [FailedMessage] + and a + ret z + push af + call BattleCommand_MoveDelay + pop af + dec a + jp z, TryPrintButItFailed + ld a, [LoweredStat] + and $f + ld b, a + inc b + call GetStatName + ld hl, WontRiseAnymoreText + jp StdBattleTextBox + +; 3646a + + +BattleCommand_StatDownFailText: ; 3646a +; statdownfailtext + ld a, [FailedMessage] + and a + ret z + push af + call BattleCommand_MoveDelay + pop af + dec a + jp z, TryPrintButItFailed + dec a + ld hl, ProtectedByMistText + jp z, StdBattleTextBox + ld a, [LoweredStat] + and $f + ld b, a + inc b + call GetStatName + ld hl, WontDropAnymoreText + jp StdBattleTextBox + +; 3648f + + +GetStatName: ; 3648f + ld hl, .names + ld c, "@" +.CheckName: + dec b + jr z, .Copy +.GetName: + ld a, [hli] + cp c + jr z, .CheckName + jr .GetName + +.Copy: + ld de, StringBuffer2 + ld bc, StringBuffer3 - StringBuffer2 + jp CopyBytes + +.names + db "ATTACK@" + db "DEFENSE@" + db "SPEED@" + db "SPCL.ATK@" + db "SPCL.DEF@" + db "ACCURACY@" + db "EVASION@" + db "ABILITY@" +; 364e6 + + +StatLevelMultipliers: ; 364e6 + db 25, 100 ; 0.25x + db 28, 100 ; 0.28x + db 33, 100 ; 0.33x + db 40, 100 ; 0.40x + db 50, 100 ; 0.50x + db 66, 100 ; 0.66x + db 1, 1 ; 1.00x + db 15, 10 ; 1.50x + db 2, 1 ; 2.00x + db 25, 10 ; 2.50x + db 3, 1 ; 3.00x + db 35, 10 ; 3.50x + db 4, 1 ; 4.00x +; 36500 + + +BattleCommand_AllStatsUp: ; 36500 +; allstatsup + +; Attack + call ResetMiss + call BattleCommand_AttackUp + call BattleCommand_StatUpMessage + +; Defense + call ResetMiss + call BattleCommand_DefenseUp + call BattleCommand_StatUpMessage + +; Speed + call ResetMiss + call BattleCommand_SpeedUp + call BattleCommand_StatUpMessage + +; Special Attack + call ResetMiss + call BattleCommand_SpecialAttackUp + call BattleCommand_StatUpMessage + +; Special Defense + call ResetMiss + call BattleCommand_SpecialDefenseUp + jp BattleCommand_StatUpMessage +; 3652d + + +ResetMiss: ; 3652d + xor a + ld [AttackMissed], a + ret + +; 36532 + + +LowerStat: ; 36532 + ld [LoweredStat], a + + ld hl, PlayerStatLevels + ld a, [hBattleTurn] + and a + jr z, .got_target + ld hl, EnemyStatLevels + +.got_target + ld a, [LoweredStat] + and $f + ld c, a + ld b, 0 + add hl, bc + ld b, [hl] + dec b + jr z, .cant_lower_anymore + + ld a, [LoweredStat] + and $f0 + jr z, .got_num_stages + dec b + jr nz, .got_num_stages + inc b + +.got_num_stages + ld [hl], b + ld a, c + cp 5 + jr nc, .accuracy_evasion + + push hl + ld hl, BattleMonStats + 1 + ld de, PlayerStats + ld a, [hBattleTurn] + and a + jr z, .got_target_2 + ld hl, EnemyMonStats + 1 + ld de, EnemyStats + +.got_target_2 + call TryLowerStat + pop hl + jr z, .failed + +.accuracy_evasion + ld a, [hBattleTurn] + and a + jr z, .player + + call CalcEnemyStats + + jr .finish + +.player + call CalcPlayerStats + +.finish + xor a + ld [FailedMessage], a + ret + +.failed + inc [hl] + +.cant_lower_anymore + ld a, 2 + ld [FailedMessage], a + ret + +; 3658f + + +BattleCommand_TriStatusChance: ; 3658f +; tristatuschance + + call BattleCommand_EffectChance + +; 1/3 chance of each status +.loop + call BattleRandom + swap a + and 3 + jr z, .loop +; jump + dec a + ld hl, .ptrs + rst JumpTable + ret + +.ptrs + dw BattleCommand_ParalyzeTarget ; paralyze + dw BattleCommand_FreezeTarget ; freeze + dw BattleCommand_BurnTarget ; burn +; 365a7 + + +BattleCommand_Curl: ; 365a7 +; curl + ld a, BATTLE_VARS_SUBSTATUS2 + call GetBattleVarAddr + set SUBSTATUS_CURLED, [hl] + ret + +; 365af + + +BattleCommand_RaiseSubNoAnim: ; 365af + ld hl, GetBattleMonBackpic + ld a, [hBattleTurn] + and a + jr z, .PlayerTurn + ld hl, GetEnemyMonFrontpic +.PlayerTurn: + xor a + ld [hBGMapMode], a + call CallBattleCore + jp WaitBGMap + +; 365c3 + + +BattleCommand_LowerSubNoAnim: ; 365c3 + ld hl, DropPlayerSub + ld a, [hBattleTurn] + and a + jr z, .PlayerTurn + ld hl, DropEnemySub +.PlayerTurn: + xor a + ld [hBGMapMode], a + call CallBattleCore + jp WaitBGMap + +; 365d7 + + +CalcPlayerStats: ; 365d7 + ld hl, PlayerAtkLevel + ld de, PlayerStats + ld bc, BattleMonAttack + + ld a, 5 + call CalcStats + + ld hl, BadgeStatBoosts + call CallBattleCore + + call BattleCommand_SwitchTurn + + ld hl, ApplyPrzEffectOnSpeed + call CallBattleCore + + ld hl, ApplyBrnEffectOnAttack + call CallBattleCore + + jp BattleCommand_SwitchTurn + +; 365fd + + +CalcEnemyStats: ; 365fd + ld hl, EnemyAtkLevel + ld de, EnemyStats + ld bc, EnemyMonAttack + + ld a, 5 + call CalcStats + + call BattleCommand_SwitchTurn + + ld hl, ApplyPrzEffectOnSpeed + call CallBattleCore + + ld hl, ApplyBrnEffectOnAttack + call CallBattleCore + + jp BattleCommand_SwitchTurn + +; 3661d + + +CalcStats: ; 3661d +.loop + push af + ld a, [hli] + push hl + push bc + + ld c, a + dec c + ld b, 0 + ld hl, StatLevelMultipliers + add hl, bc + add hl, bc + + xor a + ld [hMultiplicand + 0], a + ld a, [de] + ld [hMultiplicand + 1], a + inc de + ld a, [de] + ld [hMultiplicand + 2], a + inc de + + ld a, [hli] + ld [hMultiplier], a + call Multiply + + ld a, [hl] + ld [hDivisor], a + ld b, 4 + call Divide + + ld a, [hQuotient + 1] + ld b, a + ld a, [hQuotient + 2] + or b + jr nz, .check_maxed_out + + ld a, 1 + ld [hQuotient + 2], a + jr .not_maxed_out + +.check_maxed_out + ld a, [hQuotient + 2] + cp LOW(MAX_STAT_VALUE) + ld a, b + sbc HIGH(MAX_STAT_VALUE) + jr c, .not_maxed_out + + ld a, LOW(MAX_STAT_VALUE) + ld [hQuotient + 2], a + ld a, HIGH(MAX_STAT_VALUE) + ld [hQuotient + 1], a + +.not_maxed_out + pop bc + ld a, [hQuotient + 1] + ld [bc], a + inc bc + ld a, [hQuotient + 2] + ld [bc], a + inc bc + pop hl + pop af + dec a + jr nz, .loop + + ret + +; 36671 + + +BattleCommand_StoreEnergy: ; 36671 +; storeenergy + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + bit SUBSTATUS_BIDE, a + ret z + + ld hl, PlayerRolloutCount + ld a, [hBattleTurn] + and a + jr z, .check_still_storing_energy + ld hl, EnemyRolloutCount +.check_still_storing_energy + dec [hl] + jr nz, .still_storing + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + res SUBSTATUS_BIDE, [hl] + + ld hl, UnleashedEnergyText + call StdBattleTextBox + + ld a, BATTLE_VARS_MOVE_POWER + call GetBattleVarAddr + ld a, 1 + ld [hl], a + ld hl, PlayerDamageTaken + 1 + ld de, wPlayerCharging ; player + ld a, [hBattleTurn] + and a + jr z, .player + ld hl, EnemyDamageTaken + 1 + ld de, wEnemyCharging ; enemy +.player + ld a, [hld] + add a + ld b, a + ld [CurDamage + 1], a + ld a, [hl] + rl a + ld [CurDamage], a + jr nc, .not_maxed + ld a, $ff + ld [CurDamage], a + ld [CurDamage + 1], a +.not_maxed + or b + jr nz, .built_up_something + ld a, 1 + ld [AttackMissed], a +.built_up_something + xor a + ld [hli], a + ld [hl], a + ld [de], a + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVarAddr + ld a, BIDE + ld [hl], a + + ld b, unleashenergy_command + jp SkipToBattleCommand + +.still_storing + ld hl, StoringEnergyText + call StdBattleTextBox + jp EndMoveEffect + +; 366e5 + + +BattleCommand_UnleashEnergy: ; 366e5 +; unleashenergy + + ld de, PlayerDamageTaken + ld bc, PlayerRolloutCount + ld a, [hBattleTurn] + and a + jr z, .got_damage + ld de, EnemyDamageTaken + ld bc, EnemyRolloutCount +.got_damage + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + set SUBSTATUS_BIDE, [hl] + xor a + ld [de], a + inc de + ld [de], a + ld [wPlayerMoveStructEffect], a + ld [wEnemyMoveStructEffect], a + call BattleRandom + and 1 + inc a + inc a + ld [bc], a + ld a, 1 + ld [wKickCounter], a + call AnimateCurrentMove + jp EndMoveEffect + +; 3671a + + +BattleCommand_CheckRampage: ; 3671a +; checkrampage + + ld de, PlayerRolloutCount + ld a, [hBattleTurn] + and a + jr z, .player + ld de, EnemyRolloutCount +.player + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + bit SUBSTATUS_RAMPAGE, [hl] + ret z + ld a, [de] + dec a + ld [de], a + jr nz, .continue_rampage + + res SUBSTATUS_RAMPAGE, [hl] + call BattleCommand_SwitchTurn + call SafeCheckSafeguard + push af + call BattleCommand_SwitchTurn + pop af + jr nz, .continue_rampage + + set SUBSTATUS_CONFUSED, [hl] + call BattleRandom + and %00000001 + inc a + inc a + inc de ; ConfuseCount + ld [de], a +.continue_rampage + ld b, rampage_command + jp SkipToBattleCommand + +; 36751 + + +BattleCommand_Rampage: ; 36751 +; rampage + +; No rampage during Sleep Talk. + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + ret nz + + ld de, PlayerRolloutCount + ld a, [hBattleTurn] + and a + jr z, .ok + ld de, EnemyRolloutCount +.ok + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + set SUBSTATUS_RAMPAGE, [hl] +; Rampage for 1 or 2 more turns + call BattleRandom + and %00000001 + inc a + ld [de], a + ld a, 1 + ld [wSomeoneIsRampaging], a + ret + +; 36778 + + +BattleCommand_Teleport: ; 36778 +; teleport + + ld a, [BattleType] + cp BATTLETYPE_SHINY + jr z, .failed + cp BATTLETYPE_TRAP + jr z, .failed + cp BATTLETYPE_CELEBI + jr z, .failed + cp BATTLETYPE_SUICUNE + jr z, .failed + + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVar + bit SUBSTATUS_CANT_RUN, a + jr nz, .failed +; Only need to check these next things if it's your turn + ld a, [hBattleTurn] + and a + jr nz, .enemy_turn +; Can't teleport from a trainer battle + ld a, [wBattleMode] + dec a + jr nz, .failed +; If your level is greater than the opponent's, you run without fail. + ld a, [CurPartyLevel] + ld b, a + ld a, [BattleMonLevel] + cp b + jr nc, .run_away +; Generate a number between 0 and (YourLevel + TheirLevel). + add b + ld c, a + inc c +.loop_player + call BattleRandom + cp c + jr nc, .loop_player +; If that number is greater than 4 times your level, run away. + srl b + srl b + cp b + jr nc, .run_away + +.failed + call AnimateFailedMove + jp PrintButItFailed + +.enemy_turn + ld a, [wBattleMode] + dec a + jr nz, .failed + ld a, [BattleMonLevel] + ld b, a + ld a, [CurPartyLevel] + cp b + jr nc, .run_away + add b + ld c, a + inc c +.loop_enemy + call BattleRandom + cp c + jr nc, .loop_enemy + srl b + srl b + cp b + ; This does the wrong thing. What was + ; probably intended was jr c, .failed + ; The way this is made makes enemy use + ; of Teleport always succeed if able + jr nc, .run_away +.run_away + call UpdateBattleMonInParty + xor a + ld [wNumHits], a + inc a + ld [wForcedSwitch], a + ld [wKickCounter], a + call SetBattleDraw + call BattleCommand_LowerSub + call LoadMoveAnim + ld c, 20 + call DelayFrames + call SetBattleDraw + + ld hl, FledFromBattleText + jp StdBattleTextBox + +; 36804 + + +SetBattleDraw: ; 36804 + ld a, [wBattleResult] + and $c0 + or $2 + ld [wBattleResult], a + ret + +; 3680f + + +BattleCommand_ForceSwitch: ; 3680f +; forceswitch + + ld a, [BattleType] + cp BATTLETYPE_SHINY + jp z, .fail + cp BATTLETYPE_TRAP + jp z, .fail + cp BATTLETYPE_CELEBI + jp z, .fail + cp BATTLETYPE_SUICUNE + jp z, .fail + ld a, [hBattleTurn] + and a + jp nz, .force_player_switch + ld a, [AttackMissed] + and a + jr nz, .missed + ld a, [wBattleMode] + dec a + jr nz, .trainer + ld a, [CurPartyLevel] + ld b, a + ld a, [BattleMonLevel] + cp b + jr nc, .wild_force_flee + add b + ld c, a + inc c +.random_loop_wild + call BattleRandom + cp c + jr nc, .random_loop_wild + srl b + srl b + cp b + jr nc, .wild_force_flee +.missed + jp .fail + +.wild_force_flee + call UpdateBattleMonInParty + xor a + ld [wNumHits], a + inc a + ld [wForcedSwitch], a + call SetBattleDraw + ld a, [wPlayerMoveStructAnimation] + jp .succeed + +.trainer + call FindAliveEnemyMons + jr c, .switch_fail + ld a, [wEnemyGoesFirst] + and a + jr z, .switch_fail + call UpdateEnemyMonInParty + ld a, $1 + ld [wKickCounter], a + call AnimateCurrentMove + ld c, $14 + call DelayFrames + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + ld c, 20 + call DelayFrames + ld a, [OTPartyCount] + ld b, a + ld a, [CurOTMon] + ld c, a +; select a random enemy mon to switch to +.random_loop_trainer + call BattleRandom + and $7 + cp b + jr nc, .random_loop_trainer + cp c + jr z, .random_loop_trainer + push af + push bc + ld hl, OTPartyMon1HP + call GetPartyLocation + ld a, [hli] + or [hl] + pop bc + pop de + jr z, .random_loop_trainer + ld a, d + inc a + ld [wEnemySwitchMonIndex], a + callfar ForceEnemySwitch + + ld hl, DraggedOutText + call StdBattleTextBox + + ld hl, SpikesDamage + jp CallBattleCore + +.switch_fail + jp .fail + +.force_player_switch + ld a, [AttackMissed] + and a + jr nz, .player_miss + + ld a, [wBattleMode] + dec a + jr nz, .vs_trainer + + ld a, [BattleMonLevel] + ld b, a + ld a, [CurPartyLevel] + cp b + jr nc, .wild_succeed_playeristarget + + add b + ld c, a + inc c +.wild_random_loop_playeristarget + call BattleRandom + cp c + jr nc, .wild_random_loop_playeristarget + + srl b + srl b + cp b + jr nc, .wild_succeed_playeristarget + +.player_miss + jr .fail + +.wild_succeed_playeristarget + call UpdateBattleMonInParty + xor a + ld [wNumHits], a + inc a + ld [wForcedSwitch], a + call SetBattleDraw + ld a, [wEnemyMoveStructAnimation] + jr .succeed + +.vs_trainer + call CheckPlayerHasMonToSwitchTo + jr c, .fail + + ld a, [wEnemyGoesFirst] + cp $1 + jr z, .switch_fail + + call UpdateBattleMonInParty + ld a, $1 + ld [wKickCounter], a + call AnimateCurrentMove + ld c, 20 + call DelayFrames + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + ld c, 20 + call DelayFrames + ld a, [PartyCount] + ld b, a + ld a, [CurBattleMon] + ld c, a +.random_loop_trainer_playeristarget + call BattleRandom + and $7 + cp b + jr nc, .random_loop_trainer_playeristarget + + cp c + jr z, .random_loop_trainer_playeristarget + + push af + push bc + ld hl, PartyMon1HP + call GetPartyLocation + ld a, [hli] + or [hl] + pop bc + pop de + jr z, .random_loop_trainer_playeristarget + + ld a, d + ld [CurPartyMon], a + ld hl, SwitchPlayerMon + call CallBattleCore + + ld hl, DraggedOutText + call StdBattleTextBox + + ld hl, SpikesDamage + jp CallBattleCore + +.fail + call BattleCommand_LowerSub + call BattleCommand_MoveDelay + call BattleCommand_RaiseSub + jp PrintButItFailed + +.succeed + push af + call SetBattleDraw + ld a, $1 + ld [wKickCounter], a + call AnimateCurrentMove + ld c, 20 + call DelayFrames + pop af + + ld hl, FledInFearText + cp ROAR + jr z, .do_text + ld hl, BlownAwayText +.do_text + jp StdBattleTextBox + +; 36994 + + +CheckPlayerHasMonToSwitchTo: ; 36994 + ld a, [PartyCount] + ld d, a + ld e, 0 + ld bc, PARTYMON_STRUCT_LENGTH +.loop + ld a, [CurBattleMon] + cp e + jr z, .next + + ld a, e + ld hl, PartyMon1HP + call AddNTimes + ld a, [hli] + or [hl] + jr nz, .not_fainted + +.next + inc e + dec d + jr nz, .loop + + scf + ret + +.not_fainted + and a + ret + +; 369b6 + + +BattleCommand_EndLoop: ; 369b6 +; endloop + +; Loop back to the command before 'critical'. + + ld de, PlayerRolloutCount + ld bc, PlayerDamageTaken + ld a, [hBattleTurn] + and a + jr z, .got_addrs + ld de, EnemyRolloutCount + ld bc, EnemyDamageTaken +.got_addrs + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + bit SUBSTATUS_IN_LOOP, [hl] + jp nz, .in_loop + set SUBSTATUS_IN_LOOP, [hl] + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVarAddr + ld a, [hl] + cp EFFECT_POISON_MULTI_HIT + jr z, .twineedle + cp EFFECT_DOUBLE_HIT + ld a, 1 + jr z, .double_hit + ld a, [hl] + cp EFFECT_BEAT_UP + jr z, .beat_up + cp EFFECT_TRIPLE_KICK + jr nz, .not_triple_kick +.reject_triple_kick_sample + call BattleRandom + and $3 + jr z, .reject_triple_kick_sample + dec a + jr nz, .double_hit + ld a, 1 + ld [bc], a + jr .done_loop + +.beat_up + ld a, [hBattleTurn] + and a + jr nz, .check_ot_beat_up + ld a, [PartyCount] + cp 1 + jp z, .only_one_beatup + dec a + jr .double_hit + +.check_ot_beat_up + ld a, [wBattleMode] + cp WILD_BATTLE + jp z, .only_one_beatup + ld a, [OTPartyCount] + cp 1 + jp z, .only_one_beatup + dec a + jr .double_hit + +.only_one_beatup + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + res SUBSTATUS_IN_LOOP, [hl] + call BattleCommanda8 + jp EndMoveEffect + +.not_triple_kick + call BattleRandom + and $3 + cp 2 + jr c, .got_number_hits + call BattleRandom + and $3 +.got_number_hits + inc a +.double_hit + ld [de], a + inc a + ld [bc], a + jr .loop_back_to_critical + +.twineedle + ld a, 1 + jr .double_hit + +.in_loop + ld a, [de] + dec a + ld [de], a + jr nz, .loop_back_to_critical +.done_loop + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + res SUBSTATUS_IN_LOOP, [hl] + + ld hl, PlayerHitTimesText + ld a, [hBattleTurn] + and a + jr z, .got_hit_n_times_text + ld hl, EnemyHitTimesText +.got_hit_n_times_text + + push bc + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_BEAT_UP + jr z, .beat_up_2 + call StdBattleTextBox +.beat_up_2 + + pop bc + xor a + ld [bc], a + ret + +; Loop back to the command before 'critical'. +.loop_back_to_critical + ld a, [BattleScriptBufferAddress + 1] + ld h, a + ld a, [BattleScriptBufferAddress] + ld l, a +.not_critical + ld a, [hld] + cp critical_command + jr nz, .not_critical + inc hl + ld a, h + ld [BattleScriptBufferAddress + 1], a + ld a, l + ld [BattleScriptBufferAddress], a + ret + +; 36a82 + + +BattleCommand_FakeOut: ; 36a82 + ld a, [AttackMissed] + and a + ret nz + + call CheckSubstituteOpp + jr nz, .fail + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVar + and 1 << FRZ | SLP + jr nz, .fail + + call CheckOpponentWentFirst + jr z, FlinchTarget + +.fail + ld a, 1 + ld [AttackMissed], a + ret + +; 36aa0 + + +BattleCommand_FlinchTarget: ; 36aa0 + call CheckSubstituteOpp + ret nz + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVar + and 1 << FRZ | SLP + ret nz + + call CheckOpponentWentFirst + ret nz + + ld a, [EffectFailed] + and a + ret nz + + ; fallthrough +; 36ab5 + + +FlinchTarget: ; 36ab5 + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVarAddr + set SUBSTATUS_FLINCHED, [hl] + jp EndRechargeOpp + +; 36abf + + +CheckOpponentWentFirst: ; 36abf +; Returns a=0, z if user went first +; Returns a=1, nz if opponent went first + push bc + ld a, [wEnemyGoesFirst] ; 0 if player went first + ld b, a + ld a, [hBattleTurn] ; 0 if it's the player's turn + xor b ; 1 if opponent went first + pop bc + ret + +; 36ac9 + + +BattleCommand_HeldFlinch: ; 36ac9 +; kingsrock + + ld a, [AttackMissed] + and a + ret nz + + call GetUserItem + ld a, b + cp HELD_FLINCH + ret nz + + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVarAddr + ld d, h + ld e, l + call GetUserItem + call BattleRandom + cp c + ret nc + call EndRechargeOpp + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVarAddr + set SUBSTATUS_FLINCHED, [hl] + ret + +; 36af3 + + +BattleCommand_OHKO: ; 36af3 +; ohko + + call ResetDamage + ld a, [TypeModifier] + and $7f + jr z, .no_effect + ld hl, EnemyMonLevel + ld de, BattleMonLevel + ld bc, wPlayerMoveStruct + MOVE_ACC + ld a, [hBattleTurn] + and a + jr z, .got_move_accuracy + push hl + ld h, d + ld l, e + pop de + ld bc, wEnemyMoveStruct + MOVE_ACC +.got_move_accuracy + ld a, [de] + sub [hl] + jr c, .no_effect + add a + ld e, a + ld a, [bc] + add e + jr nc, .finish_ohko + ld a, $ff +.finish_ohko + ld [bc], a + call BattleCommand_CheckHit + ld hl, CurDamage + ld a, $ff + ld [hli], a + ld [hl], a + ld a, $2 + ld [CriticalHit], a + ret + +.no_effect + ld a, $ff + ld [CriticalHit], a + ld a, $1 + ld [AttackMissed], a + ret + +; 36b3a + + +BattleCommand_CheckCharge: ; 36b3a +; checkcharge + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + bit SUBSTATUS_CHARGED, [hl] + ret z + res SUBSTATUS_CHARGED, [hl] + res SUBSTATUS_UNDERGROUND, [hl] + res SUBSTATUS_FLYING, [hl] + ld b, charge_command + jp SkipToBattleCommand + +; 36b4d + + +BattleCommand_Charge: ; 36b4d +; charge + + call BattleCommand_ClearText + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + jr z, .awake + + call BattleCommand_MoveDelay + call BattleCommand_RaiseSub + call PrintButItFailed + jp EndMoveEffect + +.awake + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + set SUBSTATUS_CHARGED, [hl] + + ld hl, IgnoredOrders2Text + ld a, [AlreadyDisobeyed] + and a + call nz, StdBattleTextBox + + call BattleCommand_LowerSub + xor a + ld [wNumHits], a + inc a + ld [wKickCounter], a + call LoadMoveAnim + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp FLY + jr z, .flying + cp DIG + jr z, .flying + call BattleCommand_RaiseSub + jr .not_flying + +.flying + call DisappearUser +.not_flying + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld b, a + cp FLY + jr z, .set_flying + cp DIG + jr nz, .dont_set_digging + set SUBSTATUS_UNDERGROUND, [hl] + jr .dont_set_digging + +.set_flying + set SUBSTATUS_FLYING, [hl] + +.dont_set_digging + call CheckUserIsCharging + jr nz, .mimic + ld a, BATTLE_VARS_LAST_COUNTER_MOVE + call GetBattleVarAddr + ld [hl], b + ld a, BATTLE_VARS_LAST_MOVE + call GetBattleVarAddr + ld [hl], b + +.mimic + call ResetDamage + + ld hl, .UsedText + call BattleTextBox + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_SKULL_BASH + ld b, endturn_command + jp z, SkipToBattleCommand + jp EndMoveEffect + +.UsedText: + text_jump UnknownText_0x1c0d0e ; "[USER]" + start_asm + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp RAZOR_WIND + ld hl, .RazorWind + jr z, .done + + cp SOLARBEAM + ld hl, .Solarbeam + jr z, .done + + cp SKULL_BASH + ld hl, .SkullBash + jr z, .done + + cp SKY_ATTACK + ld hl, .SkyAttack + jr z, .done + + cp FLY + ld hl, .Fly + jr z, .done + + cp DIG + ld hl, .Dig + +.done + ret + +.RazorWind: +; 'made a whirlwind!' + text_jump UnknownText_0x1c0d12 + db "@" + +.Solarbeam: +; 'took in sunlight!' + text_jump UnknownText_0x1c0d26 + db "@" + +.SkullBash: +; 'lowered its head!' + text_jump UnknownText_0x1c0d3a + db "@" + +.SkyAttack: +; 'is glowing!' + text_jump UnknownText_0x1c0d4e + db "@" + +.Fly: +; 'flew up high!' + text_jump UnknownText_0x1c0d5c + db "@" + +.Dig: +; 'dug a hole!' + text_jump UnknownText_0x1c0d6c + db "@" +; 36c2c + + +BattleCommand3c: ; 36c2c +; unused + ret + +; 36c2d + + +BattleCommand_TrapTarget: ; 36c2d +; traptarget + + ld a, [AttackMissed] + and a + ret nz + ld hl, wEnemyWrapCount + ld de, wEnemyTrappingMove + ld a, [hBattleTurn] + and a + jr z, .got_trap + ld hl, wPlayerWrapCount + ld de, wPlayerTrappingMove + +.got_trap + ld a, [hl] + and a + ret nz + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + ret nz + call BattleRandom + and 3 + inc a + inc a + inc a + ld [hl], a + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld [de], a + ld b, a + ld hl, .Traps + +.find_trap_text + ld a, [hli] + cp b + jr z, .found_trap_text + inc hl + inc hl + jr .find_trap_text + +.found_trap_text + ld a, [hli] + ld h, [hl] + ld l, a + jp StdBattleTextBox + +.Traps: + dbw BIND, UsedBindText ; 'used BIND on' + dbw WRAP, WrappedByText ; 'was WRAPPED by' + dbw FIRE_SPIN, FireSpinTrapText ; 'was trapped!' + dbw CLAMP, ClampedByText ; 'was CLAMPED by' + dbw WHIRLPOOL, WhirlpoolTrapText ; 'was trapped!' +; 36c7e + + +BattleCommand_Mist: ; 36c7e +; mist + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + bit SUBSTATUS_MIST, [hl] + jr nz, .already_mist + set SUBSTATUS_MIST, [hl] + call AnimateCurrentMove + ld hl, MistText + jp StdBattleTextBox + +.already_mist + call AnimateFailedMove + jp PrintButItFailed + +; 36c98 + + +BattleCommand_FocusEnergy: ; 36c98 +; focusenergy + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + bit SUBSTATUS_FOCUS_ENERGY, [hl] + jr nz, .already_pumped + set SUBSTATUS_FOCUS_ENERGY, [hl] + call AnimateCurrentMove + ld hl, GettingPumpedText + jp StdBattleTextBox + +.already_pumped + call AnimateFailedMove + jp PrintButItFailed + +; 36cb2 + + +BattleCommand_Recoil: ; 36cb2 +; recoil + + ld hl, BattleMonMaxHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, EnemyMonMaxHP +.got_hp + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld d, a +; get 1/4 damage or 1 HP, whichever is higher + ld a, [CurDamage] + ld b, a + ld a, [CurDamage + 1] + ld c, a + srl b + rr c + srl b + rr c + ld a, b + or c + jr nz, .min_damage + inc c +.min_damage + ld a, [hli] + ld [Buffer2], a + ld a, [hl] + ld [Buffer1], a + dec hl + dec hl + ld a, [hl] + ld [Buffer3], a + sub c + ld [hld], a + ld [Buffer5], a + ld a, [hl] + ld [Buffer4], a + sbc b + ld [hl], a + ld [Buffer6], a + jr nc, .dont_ko + xor a + ld [hli], a + ld [hl], a + ld hl, Buffer5 + ld [hli], a + ld [hl], a +.dont_ko + hlcoord 10, 9 + ld a, [hBattleTurn] + and a + ld a, 1 + jr z, .animate_hp_bar + hlcoord 2, 2 + xor a +.animate_hp_bar + ld [wWhichHPBar], a + predef AnimateHPBar + call RefreshBattleHuds + ld hl, RecoilText + jp StdBattleTextBox + +; 36d1d + + +BattleCommand_ConfuseTarget: ; 36d1d +; confusetarget + + call GetOpponentItem + ld a, b + cp HELD_PREVENT_CONFUSE + ret z + ld a, [EffectFailed] + and a + ret nz + call SafeCheckSafeguard + ret nz + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVarAddr + bit SUBSTATUS_CONFUSED, [hl] + ret nz + jr BattleCommand_FinishConfusingTarget + + +BattleCommand_Confuse: ; 36d3b +; confuse + + call GetOpponentItem + ld a, b + cp HELD_PREVENT_CONFUSE + jr nz, .no_item_protection + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetItemName + call AnimateFailedMove + ld hl, ProtectedByText + jp StdBattleTextBox + +.no_item_protection + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVarAddr + bit SUBSTATUS_CONFUSED, [hl] + jr z, .not_already_confused + call AnimateFailedMove + ld hl, AlreadyConfusedText + jp StdBattleTextBox + +.not_already_confused + call CheckSubstituteOpp + jr nz, BattleCommand_Confuse_CheckSnore_Swagger_ConfuseHit + ld a, [AttackMissed] + and a + jr nz, BattleCommand_Confuse_CheckSnore_Swagger_ConfuseHit +BattleCommand_FinishConfusingTarget: ; 36d70 + ld bc, EnemyConfuseCount + ld a, [hBattleTurn] + and a + jr z, .got_confuse_count + ld bc, PlayerConfuseCount + +.got_confuse_count + set SUBSTATUS_CONFUSED, [hl] + call BattleRandom + and 3 + inc a + inc a + ld [bc], a + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_CONFUSE_HIT + jr z, .got_effect + cp EFFECT_SNORE + jr z, .got_effect + cp EFFECT_SWAGGER + jr z, .got_effect + call AnimateCurrentMove + +.got_effect + ld de, ANIM_CONFUSED + call PlayOpponentBattleAnim + + ld hl, BecameConfusedText + call StdBattleTextBox + + call GetOpponentItem + ld a, b + cp HELD_HEAL_STATUS + jr z, .heal_confusion + cp HELD_HEAL_CONFUSION + ret nz +.heal_confusion + ld hl, UseConfusionHealingItem + jp CallBattleCore + +; 36db6 + +BattleCommand_Confuse_CheckSnore_Swagger_ConfuseHit: ; 36db6 + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_CONFUSE_HIT + ret z + cp EFFECT_SNORE + ret z + cp EFFECT_SWAGGER + ret z + jp PrintDidntAffect2 + +; 36dc7 + + +BattleCommand_Paralyze: ; 36dc7 +; paralyze + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVar + bit PAR, a + jr nz, .paralyzed + ld a, [TypeModifier] + and $7f + jr z, .didnt_affect + call GetOpponentItem + ld a, b + cp HELD_PREVENT_PARALYZE + jr nz, .no_item_protection + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetItemName + call AnimateFailedMove + ld hl, ProtectedByText + jp StdBattleTextBox + +.no_item_protection + ld a, [hBattleTurn] + and a + jr z, .dont_sample_failure + + ld a, [wLinkMode] + and a + jr nz, .dont_sample_failure + + ld a, [InBattleTowerBattle] + and a + jr nz, .dont_sample_failure + + ld a, [PlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .dont_sample_failure + + call BattleRandom + cp 1 + 25 percent + jr c, .failed + +.dont_sample_failure + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + jr nz, .failed + ld a, [AttackMissed] + and a + jr nz, .failed + call CheckSubstituteOpp + jr nz, .failed + ld c, 30 + call DelayFrames + call AnimateCurrentMove + ld a, $1 + ld [hBGMapMode], a + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + set PAR, [hl] + call UpdateOpponentInParty + ld hl, ApplyPrzEffectOnSpeed + call CallBattleCore + call UpdateBattleHuds + call PrintParalyze + ld hl, UseHeldStatusHealingItem + jp CallBattleCore + +.paralyzed + call AnimateFailedMove + ld hl, AlreadyParalyzedText + jp StdBattleTextBox + +.failed + jp PrintDidntAffect2 + +.didnt_affect + call AnimateFailedMove + jp PrintDoesntAffect + +; 36e5b + + +CheckMoveTypeMatchesTarget: ; 36e5b +; Compare move type to opponent type. +; Return z if matching the opponent type, +; unless the move is Normal (Tri Attack). + + push hl + + ld hl, EnemyMonType1 + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, BattleMonType1 +.ok + + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVar + cp NORMAL + jr z, .normal + + cp [hl] + jr z, .return + + inc hl + cp [hl] + +.return + pop hl + ret + +.normal + ld a, 1 + and a + pop hl + ret + +; 36e7c + + +BattleCommand_Substitute: ; 36e7c +; substitute + + call BattleCommand_MoveDelay + ld hl, BattleMonMaxHP + ld de, PlayerSubstituteHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, EnemyMonMaxHP + ld de, EnemySubstituteHP +.got_hp + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + jr nz, .already_has_sub + + ld a, [hli] + ld b, [hl] + srl a + rr b + srl a + rr b + dec hl + dec hl + ld a, b + ld [de], a + ld a, [hld] + sub b + ld e, a + ld a, [hl] + sbc 0 + ld d, a + jr c, .too_weak_to_sub + ld a, d + or e + jr z, .too_weak_to_sub + ld [hl], d + inc hl + ld [hl], e + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + set SUBSTATUS_SUBSTITUTE, [hl] + + ld hl, wPlayerWrapCount + ld de, wPlayerTrappingMove + ld a, [hBattleTurn] + and a + jr z, .player + ld hl, wEnemyWrapCount + ld de, wEnemyTrappingMove +.player + + xor a + ld [hl], a + ld [de], a + call _CheckBattleScene + jr c, .no_anim + + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + ld [wKickCounter], a + ld a, SUBSTITUTE + call LoadAnim + jr .finish + +.no_anim + call BattleCommand_RaiseSubNoAnim +.finish + ld hl, MadeSubstituteText + call StdBattleTextBox + jp RefreshBattleHuds + +.already_has_sub + call CheckUserIsCharging + call nz, BattleCommand_RaiseSub + ld hl, HasSubstituteText + jr .jp_stdbattletextbox + +.too_weak_to_sub + call CheckUserIsCharging + call nz, BattleCommand_RaiseSub + ld hl, TooWeakSubText +.jp_stdbattletextbox + jp StdBattleTextBox + +; 36f0b + +BattleCommand_RechargeNextTurn: ; 36f0b +; rechargenextturn + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + set SUBSTATUS_RECHARGE, [hl] + ret + +; 36f13 + + +EndRechargeOpp: ; 36f13 + push hl + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVarAddr + res SUBSTATUS_RECHARGE, [hl] + pop hl + ret + +; 36f1d + + +BattleCommand_Rage: ; 36f1d +; rage + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + set SUBSTATUS_RAGE, [hl] + ret + +; 36f25 + + +BattleCommand_DoubleFlyingDamage: ; 36f25 +; doubleflyingdamage + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + bit SUBSTATUS_FLYING, a + ret z + jr DoubleDamage + +; 36f2f + + +BattleCommand_DoubleUndergroundDamage: ; 36f2f +; doubleundergrounddamage + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + bit SUBSTATUS_UNDERGROUND, a + ret z + + ; fallthrough +; 36f37 + + +DoubleDamage: ; 36f37 + ld hl, CurDamage + 1 + sla [hl] + dec hl + rl [hl] + jr nc, .quit + + ld a, $ff + ld [hli], a + ld [hl], a +.quit + ret + +; 36f46 + + +BattleCommand_Mimic: ; 36f46 +; mimic + + call ClearLastMove + call BattleCommand_MoveDelay + ld a, [AttackMissed] + and a + jr nz, .fail + ld hl, BattleMonMoves + ld a, [hBattleTurn] + and a + jr z, .player_turn + ld hl, EnemyMonMoves +.player_turn + call CheckHiddenOpponent + jr nz, .fail + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + and a + jr z, .fail + cp STRUGGLE + jr z, .fail + ld b, a + ld c, NUM_MOVES +.check_already_knows_move + ld a, [hli] + cp b + jr z, .fail + dec c + jr nz, .check_already_knows_move + dec hl +.find_mimic + ld a, [hld] + cp MIMIC + jr nz, .find_mimic + inc hl + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + ld [hl], a + ld [wNamedObjectIndexBuffer], a + ld bc, BattleMonPP - BattleMonMoves + add hl, bc + ld [hl], 5 + call GetMoveName + call AnimateCurrentMove + ld hl, LearnedMoveText + jp StdBattleTextBox + +.fail + jp FailMimic + +; 36f9d + + +BattleCommand_LeechSeed: ; 36f9d +; leechseed + ld a, [AttackMissed] + and a + jr nz, .evaded + call CheckSubstituteOpp + jr nz, .evaded + + ld de, EnemyMonType1 + ld a, [hBattleTurn] + and a + jr z, .ok + ld de, BattleMonType1 +.ok + + ld a, [de] + cp GRASS + jr z, .grass + inc de + ld a, [de] + cp GRASS + jr z, .grass + + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVarAddr + bit SUBSTATUS_LEECH_SEED, [hl] + jr nz, .evaded + set SUBSTATUS_LEECH_SEED, [hl] + call AnimateCurrentMove + ld hl, WasSeededText + jp StdBattleTextBox + +.grass + call AnimateFailedMove + jp PrintDoesntAffect + +.evaded + call AnimateFailedMove + ld hl, EvadedText + jp StdBattleTextBox + +; 36fe1 + + +BattleCommand_Splash: ; 36fe1 + call AnimateCurrentMove + farcall TrainerRankings_Splash + jp PrintNothingHappened + +; 36fed + + +BattleCommand_Disable: ; 36fed +; disable + + ld a, [AttackMissed] + and a + jr nz, .failed + + ld de, EnemyDisableCount + ld hl, EnemyMonMoves + ld a, [hBattleTurn] + and a + jr z, .got_moves + ld de, PlayerDisableCount + ld hl, BattleMonMoves +.got_moves + + ld a, [de] + and a + jr nz, .failed + + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + and a + jr z, .failed + cp STRUGGLE + jr z, .failed + + ld b, a + ld c, $ff +.loop + inc c + ld a, [hli] + cp b + jr nz, .loop + + ld a, [hBattleTurn] + and a + ld hl, EnemyMonPP + jr z, .got_pp + ld hl, BattleMonPP +.got_pp + ld b, 0 + add hl, bc + ld a, [hl] + and a + jr z, .failed +.loop2 + call BattleRandom + and 7 + jr z, .loop2 + inc a + inc c + swap c + add c + ld [de], a + call AnimateCurrentMove + ld hl, DisabledMove + ld a, [hBattleTurn] + and a + jr nz, .got_disabled_move_pointer + inc hl +.got_disabled_move_pointer + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + ld [hl], a + ld [wNamedObjectIndexBuffer], a + call GetMoveName + ld hl, WasDisabledText + jp StdBattleTextBox + +.failed + jp FailDisable + +; 3705c + + +BattleCommand_PayDay: ; 3705c +; payday + + xor a + ld hl, StringBuffer1 + ld [hli], a + + ld a, [hBattleTurn] + and a + ld a, [BattleMonLevel] + jr z, .ok + ld a, [EnemyMonLevel] +.ok + + add a + ld hl, wPayDayMoney + 2 + add [hl] + ld [hld], a + jr nc, .done + inc [hl] + dec hl + jr nz, .done + inc [hl] +.done + ld hl, CoinsScatteredText + jp StdBattleTextBox + +; 3707f + + +BattleCommand_Conversion: ; 3707f +; conversion + + ld hl, BattleMonMoves + ld de, BattleMonType1 + ld a, [hBattleTurn] + and a + jr z, .got_moves + ld hl, EnemyMonMoves + ld de, EnemyMonType1 +.got_moves + push de + ld c, 0 + ld de, StringBuffer1 +.loop + push hl + ld b, 0 + add hl, bc + ld a, [hl] + pop hl + and a + jr z, .okay + push hl + push bc + dec a + ld hl, Moves + MOVE_TYPE + call GetMoveAttr + ld [de], a + inc de + pop bc + pop hl + inc c + ld a, c + cp NUM_MOVES + jr c, .loop +.okay + ld a, $ff + ld [de], a + inc de + ld [de], a + inc de + ld [de], a + pop de + ld hl, StringBuffer1 +.loop2 + ld a, [hl] + cp -1 + jr z, .fail + cp CURSE_T + jr z, .next + ld a, [de] + cp [hl] + jr z, .next + inc de + ld a, [de] + dec de + cp [hl] + jr nz, .done +.next + inc hl + jr .loop2 + +.fail + call AnimateFailedMove + jp PrintButItFailed + +.done +.loop3 + call BattleRandom + and 3 ; TODO factor in NUM_MOVES + ld c, a + ld b, 0 + ld hl, StringBuffer1 + add hl, bc + ld a, [hl] + cp -1 + jr z, .loop3 + cp CURSE_T + jr z, .loop3 + ld a, [de] + cp [hl] + jr z, .loop3 + inc de + ld a, [de] + dec de + cp [hl] + jr z, .loop3 + ld a, [hl] + ld [de], a + inc de + ld [de], a + ld [wNamedObjectIndexBuffer], a + farcall GetTypeName + call AnimateCurrentMove + ld hl, TransformedTypeText + jp StdBattleTextBox + +; 3710e + + +BattleCommand_ResetStats: ; 3710e +; resetstats + + ld a, 7 ; neutral + ld hl, PlayerStatLevels + call .Fill + ld hl, EnemyStatLevels + call .Fill + + ld a, [hBattleTurn] + push af + + call SetPlayerTurn + call CalcPlayerStats + call SetEnemyTurn + call CalcEnemyStats + + pop af + ld [hBattleTurn], a + + call AnimateCurrentMove + + ld hl, EliminatedStatsText + jp StdBattleTextBox + +.Fill: + ld b, PlayerStatLevelsEnd - PlayerStatLevels +.next + ld [hli], a + dec b + jr nz, .next + ret + +; 3713e + + +BattleCommand_Heal: ; 3713e +; heal + + ld de, BattleMonHP + ld hl, BattleMonMaxHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld de, EnemyMonHP + ld hl, EnemyMonMaxHP +.got_hp + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld b, a + push hl + push de + push bc + ld c, 2 + call StringCmp + pop bc + pop de + pop hl + jp z, .hp_full + ld a, b + cp REST + jr nz, .not_rest + + push hl + push de + push af + call BattleCommand_MoveDelay + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVarAddr + res SUBSTATUS_TOXIC, [hl] + ld a, BATTLE_VARS_STATUS + call GetBattleVarAddr + ld a, [hl] + and a + ld [hl], REST_SLEEP_TURNS + 1 + ld hl, WentToSleepText + jr z, .no_status_to_heal + ld hl, RestedText +.no_status_to_heal + call StdBattleTextBox + ld a, [hBattleTurn] + and a + jr nz, .calc_enemy_stats + call CalcPlayerStats + jr .got_stats + +.calc_enemy_stats + call CalcEnemyStats +.got_stats + pop af + pop de + pop hl + +.not_rest + jr z, .restore_full_hp + ld hl, GetHalfMaxHP + call CallBattleCore + jr .finish + +.restore_full_hp + ld hl, GetMaxHP + call CallBattleCore +.finish + call AnimateCurrentMove + call BattleCommand_SwitchTurn + ld hl, RestoreHP + call CallBattleCore + call BattleCommand_SwitchTurn + call UpdateUserInParty + call RefreshBattleHuds + ld hl, RegainedHealthText + jp StdBattleTextBox + +.hp_full + call AnimateFailedMove + ld hl, HPIsFullText + jp StdBattleTextBox + +; 371cd + +INCLUDE "engine/battle/effect_commands/transform.asm" + +BattleSideCopy: ; 372c6 +; Copy bc bytes from hl to de if it's the player's turn. +; Copy bc bytes from de to hl if it's the enemy's turn. + ld a, [hBattleTurn] + and a + jr z, .copy + +; Swap hl and de + push hl + ld h, d + ld l, e + pop de +.copy + jp CopyBytes + +; 372d2 + + +BattleEffect_ButItFailed: ; 372d2 + call AnimateFailedMove + jp PrintButItFailed + +; 372d8 + + +ClearLastMove: ; 372d8 + ld a, BATTLE_VARS_LAST_COUNTER_MOVE + call GetBattleVarAddr + xor a + ld [hl], a + + ld a, BATTLE_VARS_LAST_MOVE + call GetBattleVarAddr + xor a + ld [hl], a + ret + +; 372e7 + + +ResetActorDisable: ; 372e7 + ld a, [hBattleTurn] + and a + jr z, .player + + xor a + ld [EnemyDisableCount], a + ld [EnemyDisabledMove], a + ret + +.player + xor a + ld [PlayerDisableCount], a + ld [DisabledMove], a + ret + +; 372fc + + +BattleCommand_Screen: ; 372fc +; screen + + ld hl, PlayerScreens + ld bc, PlayerLightScreenCount + ld a, [hBattleTurn] + and a + jr z, .got_screens_pointer + ld hl, EnemyScreens + ld bc, EnemyLightScreenCount + +.got_screens_pointer + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_LIGHT_SCREEN + jr nz, .Reflect + + bit SCREENS_LIGHT_SCREEN, [hl] + jr nz, .failed + set SCREENS_LIGHT_SCREEN, [hl] + ld a, 5 + ld [bc], a + ld hl, LightScreenEffectText + jr .good + +.Reflect: + bit SCREENS_REFLECT, [hl] + jr nz, .failed + set SCREENS_REFLECT, [hl] + + ; LightScreenCount -> ReflectCount + inc bc + + ld a, 5 + ld [bc], a + ld hl, ReflectEffectText + +.good + call AnimateCurrentMove + jp StdBattleTextBox + +.failed + call AnimateFailedMove + jp PrintButItFailed + +; 3733d + + +PrintDoesntAffect: ; 3733d +; 'it doesn't affect' + ld hl, DoesntAffectText + jp StdBattleTextBox + +; 37343 + + +PrintNothingHappened: ; 37343 +; 'but nothing happened!' + ld hl, NothingHappenedText + jp StdBattleTextBox + +; 37349 + + +TryPrintButItFailed: ; 37349 + ld a, [AlreadyFailed] + and a + ret nz + + ; fallthrough +; 3734e + + +PrintButItFailed: ; 3734e +; 'but it failed!' + ld hl, ButItFailedText + jp StdBattleTextBox + +; 37354 + + +FailSnore: +FailDisable: +FailConversion2: +FailAttract: +FailForesight: +FailSpikes: + call AnimateFailedMove + ; fallthrough +; 37357 + +FailMimic: ; 37357 + ld hl, ButItFailedText ; 'but it failed!' + ld de, ItFailedText ; 'it failed!' + jp FailText_CheckOpponentProtect + +; 37360 + + +PrintDidntAffect: ; 37360 +; 'it didn't affect' + ld hl, DidntAffect1Text + jp StdBattleTextBox + +; 37366 + + +PrintDidntAffect2: ; 37366 + call AnimateFailedMove + ld hl, DidntAffect1Text ; 'it didn't affect' + ld de, DidntAffect2Text ; 'it didn't affect' + jp FailText_CheckOpponentProtect + +; 37372 + + +PrintParalyze: ; 37372 +; 'paralyzed! maybe it can't attack!' + ld hl, ParalyzedText + jp StdBattleTextBox + +; 37378 + + +CheckSubstituteOpp: ; 37378 + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + ret + +; 37380 + + +BattleCommand_Selfdestruct: ; 37380 + farcall TrainerRankings_Selfdestruct + ld a, BATTLEANIM_PLAYER_DAMAGE + ld [wNumHits], a + ld c, 3 + call DelayFrames + ld a, BATTLE_VARS_STATUS + call GetBattleVarAddr + xor a + ld [hli], a + inc hl + ld [hli], a + ld [hl], a + ld a, $1 + ld [wKickCounter], a + call BattleCommand_LowerSub + call LoadMoveAnim + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + res SUBSTATUS_LEECH_SEED, [hl] + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + res SUBSTATUS_DESTINY_BOND, [hl] + call _CheckBattleScene + ret nc + farcall DrawPlayerHUD + farcall DrawEnemyHUD + call WaitBGMap + jp RefreshBattleHuds + +; 373c9 + + +INCLUDE "engine/battle/effect_commands/mirror_move.asm" + +INCLUDE "engine/battle/effect_commands/metronome.asm" + + +CheckUserMove: ; 37462 +; Return z if the user has move a. + ld b, a + ld de, BattleMonMoves + ld a, [hBattleTurn] + and a + jr z, .ok + ld de, EnemyMonMoves +.ok + + ld c, NUM_MOVES +.loop + ld a, [de] + inc de + cp b + ret z + + dec c + jr nz, .loop + + ld a, 1 + and a + ret + +; 3747b + + +ResetTurn: ; 3747b + ld hl, wPlayerCharging + ld a, [hBattleTurn] + and a + jr z, .player + ld hl, wEnemyCharging + +.player + ld [hl], 1 + xor a + ld [AlreadyDisobeyed], a + call DoMove + jp EndMoveEffect + +; 37492 + + +INCLUDE "engine/battle/effect_commands/thief.asm" + + +BattleCommand_ArenaTrap: ; 37517 +; arenatrap + +; Doesn't work on an absent opponent. + + call CheckHiddenOpponent + jr nz, .failed + +; Don't trap if the opponent is already trapped. + + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVarAddr + bit SUBSTATUS_CANT_RUN, [hl] + jr nz, .failed + +; Otherwise trap the opponent. + + set SUBSTATUS_CANT_RUN, [hl] + call AnimateCurrentMove + ld hl, CantEscapeNowText + jp StdBattleTextBox + +.failed + call AnimateFailedMove + jp PrintButItFailed + +; 37536 + + +INCLUDE "engine/battle/effect_commands/nightmare.asm" + + +BattleCommand_Defrost: ; 37563 +; defrost + +; Thaw the user. + + ld a, BATTLE_VARS_STATUS + call GetBattleVarAddr + bit FRZ, [hl] + ret z + res FRZ, [hl] + +; Don't update the enemy's party struct in a wild battle. + + ld a, [hBattleTurn] + and a + jr z, .party + + ld a, [wBattleMode] + dec a + jr z, .done + +.party + ld a, MON_STATUS + call UserPartyAttr + res FRZ, [hl] + +.done + call RefreshBattleHuds + ld hl, WasDefrostedText + jp StdBattleTextBox + +; 37588 + + +INCLUDE "engine/battle/effect_commands/curse.asm" + +INCLUDE "engine/battle/effect_commands/protect.asm" + +INCLUDE "engine/battle/effect_commands/endure.asm" + +INCLUDE "engine/battle/effect_commands/spikes.asm" + +INCLUDE "engine/battle/effect_commands/foresight.asm" + +INCLUDE "engine/battle/effect_commands/perish_song.asm" + +INCLUDE "engine/battle/effect_commands/sandstorm.asm" + +INCLUDE "engine/battle/effect_commands/rollout.asm" + + +BattleCommand5d: ; 37791 +; unused + ret + +; 37792 + + +BattleCommand_FuryCutter: ; 37792 +; furycutter + + ld hl, PlayerFuryCutterCount + ld a, [hBattleTurn] + and a + jr z, .go + ld hl, EnemyFuryCutterCount + +.go + ld a, [AttackMissed] + and a + jp nz, ResetFuryCutterCount + + inc [hl] + +; Damage capped at 5 turns' worth (16x). + ld a, [hl] + ld b, a + cp 6 + jr c, .checkdouble + ld b, 5 + +.checkdouble + dec b + ret z + +; Double the damage + ld hl, CurDamage + 1 + sla [hl] + dec hl + rl [hl] + jr nc, .checkdouble + +; No overflow + ld a, $ff + ld [hli], a + ld [hl], a + ret + +; 377be + + +ResetFuryCutterCount: ; 377be + + push hl + + ld hl, PlayerFuryCutterCount + ld a, [hBattleTurn] + and a + jr z, .reset + ld hl, EnemyFuryCutterCount + +.reset + xor a + ld [hl], a + + pop hl + ret + +; 377ce + + +INCLUDE "engine/battle/effect_commands/attract.asm" + +BattleCommand_HappinessPower: ; 3784b +; happinesspower + push bc + ld hl, BattleMonHappiness + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyMonHappiness +.ok + xor a + ld [hMultiplicand + 0], a + ld [hMultiplicand + 1], a + ld a, [hl] + ld [hMultiplicand + 2], a + ld a, 10 + ld [hMultiplier], a + call Multiply + ld a, 25 + ld [hDivisor], a + ld b, 4 + call Divide + ld a, [hQuotient + 2] + ld d, a + pop bc + ret + +; 37874 + + +INCLUDE "engine/battle/effect_commands/present.asm" + +BattleCommand_FrustrationPower: ; 3790e +; frustrationpower + + push bc + ld hl, BattleMonHappiness + ld a, [hBattleTurn] + and a + jr z, .got_happiness + ld hl, EnemyMonHappiness +.got_happiness + ld a, $ff + sub [hl] + ld [hMultiplicand + 2], a + xor a + ld [hMultiplicand + 0], a + ld [hMultiplicand + 1], a + ld a, 10 + ld [hMultiplier], a + call Multiply + ld a, 25 + ld [hDivisor], a + ld b, 4 + call Divide + ld a, [hQuotient + 2] + ld d, a + pop bc + ret + +; 37939 + + +BattleCommand_Safeguard: ; 37939 +; safeguard + + ld hl, PlayerScreens + ld de, PlayerSafeguardCount + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyScreens + ld de, EnemySafeguardCount +.ok + bit SCREENS_SAFEGUARD, [hl] + jr nz, .failed + set SCREENS_SAFEGUARD, [hl] + ld a, 5 + ld [de], a + call AnimateCurrentMove + ld hl, CoveredByVeilText + jp StdBattleTextBox + +.failed + call AnimateFailedMove + jp PrintButItFailed + +; 37962 + + +SafeCheckSafeguard: ; 37962 + push hl + ld hl, EnemyScreens + ld a, [hBattleTurn] + and a + jr z, .got_turn + ld hl, PlayerScreens + +.got_turn + bit SCREENS_SAFEGUARD, [hl] + pop hl + ret + +; 37972 + + +BattleCommand_CheckSafeguard: ; 37972 +; checksafeguard + ld hl, EnemyScreens + ld a, [hBattleTurn] + and a + jr z, .got_turn + ld hl, PlayerScreens +.got_turn + bit SCREENS_SAFEGUARD, [hl] + ret z + ld a, 1 + ld [AttackMissed], a + call BattleCommand_MoveDelay + ld hl, SafeguardProtectText + call StdBattleTextBox + jp EndMoveEffect + +; 37991 + + +BattleCommand_GetMagnitude: ; 37991 +; getmagnitude + + push bc + call BattleRandom + ld b, a + ld hl, .Magnitudes +.loop + ld a, [hli] + cp b + jr nc, .ok + inc hl + inc hl + jr .loop + +.ok + ld d, [hl] + push de + inc hl + ld a, [hl] + ld [wTypeMatchup], a + call BattleCommand_MoveDelay + ld hl, MagnitudeText + call StdBattleTextBox + pop de + pop bc + ret + +.Magnitudes: + ; /255, BP, magnitude + db 13, 10, 4 + db 38, 30, 5 + db 89, 50, 6 + db 166, 70, 7 + db 217, 90, 8 + db 242, 110, 9 + db 255, 150, 10 +; 379c9 + + +BattleCommand_BatonPass: ; 379c9 +; batonpass + + ld a, [hBattleTurn] + and a + jp nz, .Enemy + + +; Need something to switch to + call CheckAnyOtherAlivePartyMons + jp z, FailedBatonPass + + call UpdateBattleMonInParty + call AnimateCurrentMove + + ld c, 50 + call DelayFrames + +; Transition into switchmon menu + call LoadStandardMenuDataHeader + farcall SetUpBattlePartyMenu_NoLoop + + farcall ForcePickSwitchMonInBattle + +; Return to battle scene + call ClearPalettes + farcall _LoadBattleFontsHPBar + call CloseWindow + call ClearSprites + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + ld b, SCGB_BATTLE_COLORS + call GetSGBLayout + call SetPalettes + call BatonPass_LinkPlayerSwitch + +; Mobile link battles handle entrances differently + farcall CheckMobileBattleError + jp c, EndMoveEffect + + ld hl, PassedBattleMonEntrance + call CallBattleCore + + call ResetBatonPassStatus + ret + + +.Enemy: + +; Wildmons don't have anything to switch to + ld a, [wBattleMode] + dec a ; WILDMON + jp z, FailedBatonPass + + call CheckAnyOtherAliveEnemyMons + jp z, FailedBatonPass + + call UpdateEnemyMonInParty + call AnimateCurrentMove + call BatonPass_LinkEnemySwitch + +; Mobile link battles handle entrances differently + farcall CheckMobileBattleError + jp c, EndMoveEffect + +; Passed enemy PartyMon entrance + xor a + ld [wEnemySwitchMonIndex], a + ld hl, EnemySwitch_SetMode + call CallBattleCore + ld hl, ResetBattleParticipants + call CallBattleCore + ld a, 1 + ld [wTypeMatchup], a + ld hl, ApplyStatLevelMultiplierOnAllStats + call CallBattleCore + + ld hl, SpikesDamage + call CallBattleCore + + jr ResetBatonPassStatus + +; 37a67 + + +BatonPass_LinkPlayerSwitch: ; 37a67 + ld a, [wLinkMode] + and a + ret z + + ld a, 1 + ld [wPlayerAction], a + + call LoadStandardMenuDataHeader + ld hl, LinkBattleSendReceiveAction + call CallBattleCore + call CloseWindow + + xor a + ld [wPlayerAction], a + ret + +; 37a82 + + +BatonPass_LinkEnemySwitch: ; 37a82 + ld a, [wLinkMode] + and a + ret z + + call LoadStandardMenuDataHeader + ld hl, LinkBattleSendReceiveAction + call CallBattleCore + + ld a, [OTPartyCount] + add BATTLEACTION_SWITCH1 + ld b, a + ld a, [wBattleAction] + cp BATTLEACTION_SWITCH1 + jr c, .baton_pass + cp b + jr c, .switch + +.baton_pass + ld a, [CurOTMon] + add BATTLEACTION_SWITCH1 + ld [wBattleAction], a +.switch + jp CloseWindow + +; 37aab + + +FailedBatonPass: ; 37aab + call AnimateFailedMove + jp PrintButItFailed + +; 37ab1 + + +ResetBatonPassStatus: ; 37ab1 +; Reset status changes that aren't passed by Baton Pass. + + ; Nightmare isn't passed. + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + jr nz, .ok + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + res SUBSTATUS_NIGHTMARE, [hl] +.ok + + ; Disable isn't passed. + call ResetActorDisable + + ; Attraction isn't passed. + ld hl, PlayerSubStatus1 + res SUBSTATUS_IN_LOVE, [hl] + ld hl, EnemySubStatus1 + res SUBSTATUS_IN_LOVE, [hl] + ld hl, PlayerSubStatus5 + + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVarAddr + res SUBSTATUS_TRANSFORMED, [hl] + res SUBSTATUS_ENCORED, [hl] + + ; New mon hasn't used a move yet. + ld a, BATTLE_VARS_LAST_MOVE + call GetBattleVarAddr + ld [hl], 0 + + xor a + ld [wPlayerWrapCount], a + ld [wEnemyWrapCount], a + ret + +; 37ae9 + + +CheckAnyOtherAlivePartyMons: ; 37ae9 + ld hl, PartyMon1HP + ld a, [PartyCount] + ld d, a + ld a, [CurBattleMon] + ld e, a + jr CheckAnyOtherAliveMons + +; 37af6 + + +CheckAnyOtherAliveEnemyMons: ; 37af6 + ld hl, OTPartyMon1HP + ld a, [OTPartyCount] + ld d, a + ld a, [CurOTMon] + ld e, a + + ; fallthrough +; 37b01 + +CheckAnyOtherAliveMons: ; 37b01 +; Check for nonzero HP starting from partymon +; HP at hl for d partymons, besides current mon e. + +; Return nz if any are alive. + + xor a + ld b, a + ld c, a +.loop + ld a, c + cp d + jr z, .done + cp e + jr z, .next + + ld a, [hli] + or b + ld b, a + ld a, [hld] + or b + ld b, a + +.next + push bc + ld bc, PARTYMON_STRUCT_LENGTH + add hl, bc + pop bc + inc c + jr .loop + +.done + ld a, b + and a + ret + +; 37b1d + + +BattleCommand_Pursuit: ; 37b1d +; pursuit +; Double damage if the opponent is switching. + + ld hl, wEnemyIsSwitching + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, wPlayerIsSwitching +.ok + ld a, [hl] + and a + ret z + + ld hl, CurDamage + 1 + sla [hl] + dec hl + rl [hl] + ret nc + + ld a, $ff + ld [hli], a + ld [hl], a + ret + +; 37b39 + + +BattleCommand_ClearHazards: ; 37b39 +; clearhazards + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + bit SUBSTATUS_LEECH_SEED, [hl] + jr z, .not_leeched + res SUBSTATUS_LEECH_SEED, [hl] + ld hl, ShedLeechSeedText + call StdBattleTextBox +.not_leeched + + ld hl, PlayerScreens + ld de, wPlayerWrapCount + ld a, [hBattleTurn] + and a + jr z, .got_screens_wrap + ld hl, EnemyScreens + ld de, wEnemyWrapCount +.got_screens_wrap + bit SCREENS_SPIKES, [hl] + jr z, .no_spikes + res SCREENS_SPIKES, [hl] + ld hl, BlewSpikesText + push de + call StdBattleTextBox + pop de +.no_spikes + + ld a, [de] + and a + ret z + xor a + ld [de], a + ld hl, ReleasedByText + jp StdBattleTextBox + +; 37b74 + + +BattleCommand_HealMorn: ; 37b74 +; healmorn + ld b, MORN_F + jr BattleCommand_TimeBasedHealContinue + +; 37b78 + +BattleCommand_HealDay: ; 37b78 +; healday + ld b, DAY_F + jr BattleCommand_TimeBasedHealContinue + +; 37b7c + +BattleCommand_HealNite: ; 37b7c +; healnite + ld b, NITE_F + ; fallthrough +; 37b7e + +BattleCommand_TimeBasedHealContinue: ; 37b7e +; Time- and weather-sensitive heal. + + ld hl, BattleMonMaxHP + ld de, BattleMonHP + ld a, [hBattleTurn] + and a + jr z, .start + ld hl, EnemyMonMaxHP + ld de, EnemyMonHP + +.start +; Index for .Multipliers +; Default restores half max HP. + ld c, 2 + +; Don't bother healing if HP is already full. + push bc + call StringCmp + pop bc + jr z, .Full + +; Don't factor in time of day in link battles. + ld a, [wLinkMode] + and a + jr nz, .Weather + + ld a, [TimeOfDay] + cp b + jr z, .Weather + dec c ; double + +.Weather: + ld a, [Weather] + and a + jr z, .Heal + +; x2 in sun +; /2 in rain/sandstorm + inc c + cp WEATHER_SUN + jr z, .Heal + dec c + dec c + +.Heal: + ld b, 0 + ld hl, .Multipliers + add hl, bc + add hl, bc + + ld a, [hli] + ld h, [hl] + ld l, a + ld a, BANK(GetMaxHP) + rst FarCall + + call AnimateCurrentMove + call BattleCommand_SwitchTurn + + callfar RestoreHP + + call BattleCommand_SwitchTurn + call UpdateUserInParty + +; 'regained health!' + ld hl, RegainedHealthText + jp StdBattleTextBox + +.Full: + call AnimateFailedMove + +; 'hp is full!' + ld hl, HPIsFullText + jp StdBattleTextBox + +.Multipliers: + dw GetEighthMaxHP + dw GetQuarterMaxHP + dw GetHalfMaxHP + dw GetMaxHP +; 37be8 + + +BattleCommand_HiddenPower: ; 37be8 +; hiddenpower + + ld a, [AttackMissed] + and a + ret nz + farcall HiddenPowerDamage + ret + +; 37bf4 + + +BattleCommand_StartRain: ; 37bf4 +; startrain + ld a, WEATHER_RAIN + ld [Weather], a + ld a, 5 + ld [WeatherCount], a + call AnimateCurrentMove + ld hl, DownpourText + jp StdBattleTextBox + +; 37c07 + + +BattleCommand_StartSun: ; 37c07 +; startsun + ld a, WEATHER_SUN + ld [Weather], a + ld a, 5 + ld [WeatherCount], a + call AnimateCurrentMove + ld hl, SunGotBrightText + jp StdBattleTextBox + +; 37c1a + + +BattleCommand_BellyDrum: ; 37c1a +; bellydrum +; This command is buggy because it raises the user's attack +; before checking that it has enough HP to use the move. +; Swap the order of these two blocks to fix. + call BattleCommand_AttackUp2 + ld a, [AttackMissed] + and a + jr nz, .failed + + callfar GetHalfMaxHP + callfar CheckUserHasEnoughHP + jr nc, .failed + + push bc + call AnimateCurrentMove + pop bc + callfar SubtractHPFromUser + call UpdateUserInParty + ld a, 5 + +.max_attack_loop + push af + call BattleCommand_AttackUp2 + pop af + dec a + jr nz, .max_attack_loop + + ld hl, BellyDrumText + jp StdBattleTextBox + +.failed + call AnimateFailedMove + jp PrintButItFailed + +; 37c55 + + +BattleCommand_PsychUp: ; 37c55 +; psychup + + ld hl, EnemyStatLevels + ld de, PlayerStatLevels + ld a, [hBattleTurn] + and a + jr z, .pointers_correct +; It's the enemy's turn, so swap the pointers. + push hl + ld h, d + ld l, e + pop de +.pointers_correct + push hl + ld b, NUM_LEVEL_STATS +; If any of the enemy's stats is modified from its base level, +; the move succeeds. Otherwise, it fails. +.loop + ld a, [hli] + cp BASE_STAT_LEVEL + jr nz, .break + dec b + jr nz, .loop + pop hl + call AnimateFailedMove + jp PrintButItFailed + +.break + pop hl + ld b, NUM_LEVEL_STATS +.loop2 + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .loop2 + ld a, [hBattleTurn] + and a + jr nz, .calc_enemy_stats + call CalcPlayerStats + jr .merge + +.calc_enemy_stats + call CalcEnemyStats +.merge + call AnimateCurrentMove + ld hl, CopiedStatsText + jp StdBattleTextBox + +; 37c95 + + +BattleCommand_MirrorCoat: ; 37c95 +; mirrorcoat + + ld a, 1 + ld [AttackMissed], a + + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + and a + ret z + + ld b, a + callfar GetMoveEffect + ld a, b + cp EFFECT_MIRROR_COAT + ret z + + call BattleCommand_ResetTypeMatchup + ld a, [wTypeMatchup] + and a + ret z + + call CheckOpponentWentFirst + ret z + + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + dec a + ld de, StringBuffer1 + call GetMoveData + + ld a, [StringBuffer1 + 2] + and a + ret z + + ld a, [StringBuffer1 + 3] + cp SPECIAL + ret c + + ld hl, CurDamage + ld a, [hli] + or [hl] + ret z + + ld a, [hl] + add a + ld [hld], a + ld a, [hl] + adc a + ld [hl], a + jr nc, .capped + ld a, $ff + ld [hli], a + ld [hl], a +.capped + + xor a + ld [AttackMissed], a + ret + +; 37ce6 + + +BattleCommand_DoubleMinimizeDamage: ; 37ce6 +; doubleminimizedamage + + ld hl, wEnemyMinimized + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, wPlayerMinimized +.ok + ld a, [hl] + and a + ret z + ld hl, CurDamage + 1 + sla [hl] + dec hl + rl [hl] + ret nc + ld a, $ff + ld [hli], a + ld [hl], a + ret + +; 37d02 + + +BattleCommand_SkipSunCharge: ; 37d02 +; mimicsuncharge + ld a, [Weather] + cp WEATHER_SUN + ret nz + ld b, charge_command + jp SkipToBattleCommand + +; 37d0d + + +BattleCommand_CheckFutureSight: ; 37d0d +; checkfuturesight + + ld hl, wPlayerFutureSightCount + ld de, wPlayerFutureSightDamage + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, wEnemyFutureSightCount + ld de, wEnemyFutureSightDamage +.ok + + ld a, [hl] + and a + ret z + cp 1 + ret nz + + ld [hl], 0 + ld a, [de] + inc de + ld [CurDamage], a + ld a, [de] + ld [CurDamage + 1], a + ld b, futuresight_command + jp SkipToBattleCommand + +; 37d34 + +BattleCommand_FutureSight: ; 37d34 +; futuresight + + call CheckUserIsCharging + jr nz, .AlreadyChargingFutureSight + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld b, a + ld a, BATTLE_VARS_LAST_COUNTER_MOVE + call GetBattleVarAddr + ld [hl], b + ld a, BATTLE_VARS_LAST_MOVE + call GetBattleVarAddr + ld [hl], b +.AlreadyChargingFutureSight: + ld hl, wPlayerFutureSightCount + ld a, [hBattleTurn] + and a + jr z, .GotFutureSightCount + ld hl, wEnemyFutureSightCount +.GotFutureSightCount: + ld a, [hl] + and a + jr nz, .failed + ld a, 4 + ld [hl], a + call BattleCommand_LowerSub + call BattleCommand_MoveDelay + ld hl, ForesawAttackText + call StdBattleTextBox + call BattleCommand_RaiseSub + ld de, wPlayerFutureSightDamage + ld a, [hBattleTurn] + and a + jr z, .StoreDamage + ld de, wEnemyFutureSightDamage +.StoreDamage: + ld hl, CurDamage + ld a, [hl] + ld [de], a + ld [hl], 0 + inc hl + inc de + ld a, [hl] + ld [de], a + ld [hl], 0 + jp EndMoveEffect + +.failed + pop bc + call ResetDamage + call AnimateFailedMove + call PrintButItFailed + jp EndMoveEffect + +; 37d94 + + +BattleCommand_ThunderAccuracy: ; 37d94 +; thunderaccuracy + + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVarAddr + inc hl + ld a, [Weather] + cp WEATHER_RAIN + jr z, .rain + cp WEATHER_SUN + ret nz + ld [hl], 50 percent + 1 + ret + +.rain + ; Redundant with CheckHit guranteeing hit + ld [hl], 100 percent + ret + +; 37daa + + +CheckHiddenOpponent: ; 37daa +; BUG: This routine should account for Lock-On and Mind Reader. + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret + +; 37db2 + + +GetUserItem: ; 37db2 +; Return the effect of the user's item in bc, and its id at hl. + ld hl, BattleMonItem + ld a, [hBattleTurn] + and a + jr z, .go + ld hl, EnemyMonItem +.go + ld b, [hl] + jp GetItemHeldEffect + +; 37dc1 + + +GetOpponentItem: ; 37dc1 +; Return the effect of the opponent's item in bc, and its id at hl. + ld hl, EnemyMonItem + ld a, [hBattleTurn] + and a + jr z, .go + ld hl, BattleMonItem +.go + ld b, [hl] + jp GetItemHeldEffect + +; 37dd0 + + +GetItemHeldEffect: ; 37dd0 +; Return the effect of item b in bc. + ld a, b + and a + ret z + + push hl + ld hl, ItemAttributes + ITEMATTR_EFFECT + dec a + ld c, a + ld b, 0 + ld a, ITEMATTR_STRUCT_LENGTH + call AddNTimes + ld a, BANK(ItemAttributes) + call GetFarHalfword + ld b, l + ld c, h + pop hl + ret + +; 37de9 + + +AnimateCurrentMoveEitherSide: ; 37de9 + push hl + push de + push bc + ld a, [wKickCounter] + push af + call BattleCommand_LowerSub + pop af + ld [wKickCounter], a + call PlayDamageAnim + call BattleCommand_RaiseSub + pop bc + pop de + pop hl + ret + +; 37e01 + + +AnimateCurrentMove: ; 37e01 + push hl + push de + push bc + ld a, [wKickCounter] + push af + call BattleCommand_LowerSub + pop af + ld [wKickCounter], a + call LoadMoveAnim + call BattleCommand_RaiseSub + pop bc + pop de + pop hl + ret + +; 37e19 + + +PlayDamageAnim: ; 37e19 + xor a + ld [FXAnimID + 1], a + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + and a + ret z + + ld [FXAnimID], a + + ld a, [hBattleTurn] + and a + ld a, BATTLEANIM_ENEMY_DAMAGE + jr z, .player + ld a, BATTLEANIM_PLAYER_DAMAGE + +.player + ld [wNumHits], a + + jp PlayUserBattleAnim + +; 37e36 + + +LoadMoveAnim: ; 37e36 + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + and a + ret z + + ; fallthrough +; 37e44 + + +LoadAnim: ; 37e44 + + ld [FXAnimID], a + + ; fallthrough +; 37e47 + + +PlayUserBattleAnim: ; 37e47 + push hl + push de + push bc + callfar PlayBattleAnim + pop bc + pop de + pop hl + ret + +; 37e54 + + +PlayOpponentBattleAnim: ; 37e54 + ld a, e + ld [FXAnimID], a + ld a, d + ld [FXAnimID + 1], a + xor a + ld [wNumHits], a + + push hl + push de + push bc + call BattleCommand_SwitchTurn + + callfar PlayBattleAnim + + call BattleCommand_SwitchTurn + pop bc + pop de + pop hl + ret + +; 37e73 + + +CallBattleCore: ; 37e73 + ld a, BANK(BattleCore) + rst FarCall + ret + +; 37e77 + + +AnimateFailedMove: ; 37e77 + call BattleCommand_LowerSub + call BattleCommand_MoveDelay + jp BattleCommand_RaiseSub + +; 37e80 + + +BattleCommand_MoveDelay: ; 37e80 +; movedelay +; Wait 40 frames. + ld c, 40 + jp DelayFrames + +; 37e85 + + +BattleCommand_ClearText: ; 37e85 +; cleartext + +; Used in multi-hit moves. + ld hl, .text + jp BattleTextBox + +.text + db "@" +; 37e8c + + +SkipToBattleCommand: ; 37e8c +; Skip over commands until reaching command b. + ld a, [BattleScriptBufferAddress + 1] + ld h, a + ld a, [BattleScriptBufferAddress] + ld l, a +.loop + ld a, [hli] + cp b + jr nz, .loop + + ld a, h + ld [BattleScriptBufferAddress + 1], a + ld a, l + ld [BattleScriptBufferAddress], a + ret + +; 37ea1 + + +GetMoveAttr: ; 37ea1 +; Assuming hl = Moves + x, return attribute x of move a. + push bc + ld bc, MOVE_LENGTH + call AddNTimes + call GetMoveByte + pop bc + ret + +; 37ead + + +GetMoveData: ; 37ead +; Copy move struct a to de. + ld hl, Moves + ld bc, MOVE_LENGTH + call AddNTimes + ld a, Bank(Moves) + jp FarCopyBytes + +; 37ebb + + +GetMoveByte: ; 37ebb + ld a, BANK(Moves) + jp GetFarByte + +; 37ec0 + + +DisappearUser: ; 37ec0 + farcall _DisappearUser + ret + +; 37ec7 + + +AppearUserLowerSub: ; 37ec7 + farcall _AppearUserLowerSub + ret + +; 37ece + + +AppearUserRaiseSub: ; 37ece + farcall _AppearUserRaiseSub + ret + +; 37ed5 + + +_CheckBattleScene: ; 37ed5 +; Checks the options. Returns carry if battle animations are disabled. + push hl + push de + push bc + farcall CheckBattleScene + pop bc + pop de + pop hl + ret + +; 37ee2 |