diff options
author | entrpntr <entrpntr@gmail.com> | 2020-04-19 10:45:35 -0400 |
---|---|---|
committer | entrpntr <entrpntr@gmail.com> | 2020-04-19 10:48:54 -0400 |
commit | e10598eb204358343491c92348b9220185e3b33d (patch) | |
tree | d9df3c7c21997600449695ad4d55b24ed13eb3bb /engine/battle/effect_commands.asm | |
parent | 6ebd8441e249bba020036b5be5ccbe020b12e32b (diff) |
Start adding engine/battle/effect_commands.asm.
Diffstat (limited to 'engine/battle/effect_commands.asm')
-rw-r--r-- | engine/battle/effect_commands.asm | 1221 |
1 files changed, 1221 insertions, 0 deletions
diff --git a/engine/battle/effect_commands.asm b/engine/battle/effect_commands.asm new file mode 100644 index 00000000..023730ac --- /dev/null +++ b/engine/battle/effect_commands.asm @@ -0,0 +1,1221 @@ +DoPlayerTurn: +; Read in and execute the player's move effects for this turn. + call SetPlayerTurn + + ld a, [wBattlePlayerAction] + and a ; BATTLEPLAYERACTION_USEMOVE? + ret nz + + xor a + ld [wTurnEnded], a + + ; Effect command checkturn is called for every move. + call CheckTurn + + ld a, [wTurnEnded] + and a + ret nz + + call UpdateMoveData + jr DoMove + +DoEnemyTurn: +; Read in and execute the enemy's move effects for this turn. + call SetEnemyTurn + + ld a, [wLinkMode] + and a + jr z, .do_it + + ld a, [wBattleAction] + cp BATTLEACTION_STRUGGLE + jr z, .do_it + cp BATTLEACTION_SWITCH1 + ret nc + +.do_it + xor a + ld [wTurnEnded], a + + ; Effect command checkturn is called for every move. + call CheckTurn + + ld a, [wTurnEnded] + and a + ret nz + + call UpdateMoveData + + ; fallthrough + +DoMove: +; 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, wBattleScriptBuffer + +.GetMoveEffect: + ld a, BANK(MoveEffects) + call GetFarByte + inc hl + ld [de], a + inc de + cp endmove_command + jr nz, .GetMoveEffect + +; Start at the first command. + ld hl, wBattleScriptBuffer + ld a, l + ld [wBattleScriptBufferAddress], a + ld a, h + ld [wBattleScriptBufferAddress + 1], a + +.ReadMoveEffectCommand: +; ld a, [wBattleScriptBufferAddress++] + ld a, [wBattleScriptBufferAddress] + ld l, a + ld a, [wBattleScriptBufferAddress + 1] + ld h, a + + ld a, [hli] + + push af + ld a, l + ld [wBattleScriptBufferAddress], a + ld a, h + ld [wBattleScriptBufferAddress + 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 + +CheckTurn: +BattleCommand_CheckTurn: +; 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 [wAttackMissed], a + ld [wEffectFailed], a + ld [wKickCounter], a + ld [wAlreadyDisobeyed], a + ld [wAlreadyFailed], a + ld [wSomeoneIsRampaging], a + + ld a, EFFECTIVE + ld [wTypeModifier], a + + ldh a, [hBattleTurn] + and a + jp nz, CheckEnemyTurn + +CheckPlayerTurn: + ld hl, wPlayerSubStatus4 + 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, wBattleMonStatus + ld a, [hl] + and SLP + jr z, .not_asleep + + dec a + ld [wBattleMonStatus], 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 + ldh [hBGMapMode], a + ld hl, wPlayerSubStatus1 + res SUBSTATUS_NIGHTMARE, [hl] + jr .not_asleep + +.fast_asleep + ld hl, FastAsleepText + call StdBattleTextbox + + ; Snore and Sleep Talk bypass sleep. + ld a, [wCurPlayerMove] + cp SNORE + jr z, .not_asleep + cp SLEEP_TALK + jr z, .not_asleep + + call CantMove + jp EndTurn + +.not_asleep + + ld hl, wBattleMonStatus + bit FRZ, [hl] + jr z, .not_frozen + + ; Flame Wheel and Sacred Fire thaw the user. + ld a, [wCurPlayerMove] + 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, wPlayerSubStatus3 + 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, wPlayerDisableCount + ld a, [hl] + and a + jr z, .not_disabled + + dec a + ld [hl], a + and $f + jr nz, .not_disabled + + ld [hl], a + ld [wDisabledMove], a + ld hl, DisabledNoMoreText + call StdBattleTextbox + +.not_disabled + + ld a, [wPlayerSubStatus3] + add a + jr nc, .not_confused + ld hl, wPlayerConfuseCount + dec [hl] + jr nz, .confused + + ld hl, wPlayerSubStatus3 + 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 50 percent + 1 + jr nc, .not_confused + + ; clear confusion-dependent substatus + ld hl, wPlayerSubStatus3 + ld a, [hl] + and 1 << SUBSTATUS_CONFUSED + ld [hl], a + + call HitConfusion + call CantMove + jp EndTurn + +.not_confused + + ld a, [wPlayerSubStatus1] + 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 50 percent + 1 + 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, [wDisabledMove] + and a + jr z, .no_disabled_move + + ; Are we using the disabled move? + ld hl, wCurPlayerMove + cp [hl] + jr nz, .no_disabled_move + + call MoveDisabled + call CantMove + jp EndTurn + +.no_disabled_move + + ld hl, wBattleMonStatus + bit PAR, [hl] + ret z + + ; 25% chance to be fully paralyzed + call BattleRandom + cp 25 percent + ret nc + + ld hl, FullyParalyzedText + call StdBattleTextbox + call CantMove + jp EndTurn + +CantMove: + 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 + +OpponentCantMove: + call BattleCommand_SwitchTurn + call CantMove + jp BattleCommand_SwitchTurn + +CheckEnemyTurn: + ld hl, wEnemySubStatus4 + 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, wEnemyMonStatus + ld a, [hl] + and SLP + jr z, .not_asleep + + dec a + ld [wEnemyMonStatus], 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 + ldh [hBGMapMode], a + ld hl, wEnemySubStatus1 + res SUBSTATUS_NIGHTMARE, [hl] + jr .not_asleep + +.fast_asleep + ; Snore and Sleep Talk bypass sleep. + ld a, [wCurEnemyMove] + cp SNORE + jr z, .not_asleep + cp SLEEP_TALK + jr z, .not_asleep + call CantMove + jp EndTurn + +.not_asleep + + ld hl, wEnemyMonStatus + bit FRZ, [hl] + jr z, .not_frozen + + ; Flame Wheel and Sacred Fire thaw the user. + ld a, [wCurEnemyMove] + 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, wEnemySubStatus3 + 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, wEnemyDisableCount + ld a, [hl] + and a + jr z, .not_disabled + + dec a + ld [hl], a + and $f + jr nz, .not_disabled + + ld [hl], a + ld [wEnemyDisabledMove], a + + ld hl, DisabledNoMoreText + call StdBattleTextbox + +.not_disabled + + ld a, [wEnemySubStatus3] + add a ; bit SUBSTATUS_CONFUSED + jr nc, .not_confused + + ld hl, wEnemyConfuseCount + dec [hl] + jr nz, .confused + + ld hl, wEnemySubStatus3 + 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 50 percent + 1 + jr nc, .not_confused + + ; clear confusion-dependent substatus + ld hl, wEnemySubStatus3 + 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, TRUE + call DoEnemyDamage + call BattleCommand_RaiseSub + call CantMove + jp EndTurn + +.not_confused + + ld a, [wEnemySubStatus1] + 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 50 percent + 1 + 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, [wEnemyDisabledMove] + and a + jr z, .no_disabled_move + + ; Are we using the disabled move? + ld hl, wCurEnemyMove + cp [hl] + jr nz, .no_disabled_move + + call MoveDisabled + + call CantMove + jp EndTurn + +.no_disabled_move + + ld hl, wEnemyMonStatus + bit PAR, [hl] + ret z + + ; 25% chance to be fully paralyzed + call BattleRandom + cp 25 percent + ret nc + + ld hl, FullyParalyzedText + call StdBattleTextbox + call CantMove + + ; fallthrough + +EndTurn: + ld a, $1 + ld [wTurnEnded], a + jp ResetDamage + +MoveDisabled: + ; 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 + +HitConfusion: + ld hl, HurtItselfText + call StdBattleTextbox + + xor a + ld [wCriticalHit], 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 + ldh [hBGMapMode], a + ld c, TRUE + call DoPlayerDamage + jp BattleCommand_RaiseSub + +BattleCommand_CheckObedience: +; checkobedience + + ; Enemy can't disobey + ldh a, [hBattleTurn] + and a + ret nz + + call CheckUserIsCharging + ret nz + + ; If we've already checked this turn + ld a, [wAlreadyDisobeyed] + and a + ret nz + + xor a + ld [wAlreadyDisobeyed], a + + ; No obedience in link battles + ; (since no handling exists for enemy) + ld a, [wLinkMode] + 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, [wPlayerID] + cp [hl] + jr nz, .obeylevel + inc hl + ld a, [wPlayerID + 1] + cp [hl] + ret z + +.obeylevel + ; The maximum obedience level is constrained by owned badges: + ld hl, wJohtoBadges + + ; 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, [wBattleMonLevel] + 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 [wBattleMonStatus], a + + ld hl, BeganToNapText + jr .Print + +.DoNothing: + ; 4 random choices + call BattleRandom + and %11 + + ld hl, LoafingAroundText + and a ; 0 + jr z, .Print + + ld hl, WontObeyText + dec a ; 1 + jr z, .Print + + ld hl, TurnedAwayText + dec a ; 2 + 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, [wBattleMonMoves + 1] + and a + jr z, .DoNothing + +; Don't bother trying to handle Disable. + ld a, [wDisabledMove] + and a + jr nz, .DoNothing + + ld hl, wBattleMonPP + ld de, wBattleMonMoves + ld b, 0 + ld c, NUM_MOVES + +.GetTotalPP: + ld a, [hli] + and PP_MASK + 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, wBattleMonPP + ld a, [wCurMoveNum] + ld e, a + ld d, 0 + add hl, de + +; Can't use another move if only one move has PP. + ld a, [hl] + and PP_MASK + cp b + jr z, .DoNothing + +; Make sure we can actually use the move once we get there. + ld a, 1 + ld [wAlreadyDisobeyed], a + + ld a, [w2DMenuNumRows] + ld b, a + +; Save the move we originally picked for afterward. + ld a, [wCurMoveNum] + ld c, a + push af + +.RandomMove: + call BattleRandom + maskbits 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 [wCurMoveNum], a + ld hl, wBattleMonPP + ld e, a + ld d, 0 + add hl, de + ld a, [hl] + and PP_MASK + jr z, .RandomMove + +; Use it. + ld a, [wCurMoveNum] + ld c, a + ld b, 0 + ld hl, wBattleMonMoves + add hl, bc + ld a, [hl] + ld [wCurPlayerMove], a + + call SetPlayerTurn + call UpdateMoveData + call DoMove + +; Restore original move choice. + pop af + ld [wCurMoveNum], a + +.EndDisobedience: + xor a + ld [wLastPlayerMove], a + ld [wLastPlayerCounterMove], a + + ; Break Encore too. + ld hl, wPlayerSubStatus5 + res SUBSTATUS_ENCORED, [hl] + xor a + ld [wPlayerEncoreCount], a + + jp EndMoveEffect + +IgnoreSleepOnly: + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + + ; Snore and Sleep Talk bypass sleep. + 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 + +INCLUDE "engine/battle/used_move_text.asm" + +BattleCommand_DoTurn: + call CheckUserIsCharging + ret nz + + ld hl, wBattleMonPP + ld de, wPlayerSubStatus3 + ld bc, wPlayerTurnsTaken + + ldh a, [hBattleTurn] + and a + jr z, .proceed + + ld hl, wEnemyMonPP + ld de, wEnemySubStatus3 + ld bc, wEnemyTurnsTaken + +.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 + + ldh a, [hBattleTurn] + and a + + ld hl, wPartyMon1PP + ld a, [wCurBattleMon] + jr z, .player + +; mimic this part entirely if wildbattle + ld a, [wBattleMode] + dec a + jr z, .wild + + ld hl, wOTPartyMon1PP + ld a, [wCurOTMon] + +.player + call GetPartyLocation + push hl + call CheckMimicUsed + pop hl + ret c + +.consume_pp + ldh a, [hBattleTurn] + and a + ld a, [wCurMoveNum] + jr z, .okay + ld a, [wCurEnemyMoveNum] + +.okay + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + and PP_MASK + jr z, .out_of_pp + dec [hl] + ld b, 0 + ret + +.wild + ld hl, wEnemyMonMoves + ld a, [wCurEnemyMoveNum] + 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 +; 'has no pp left for [move]' + ld hl, HasNoPPLeftText +; get move effect + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar +; continuous? + cp EFFECT_RAZOR_WIND + jr z, .print + + cp EFFECT_SKY_ATTACK + jr z, .print + + cp EFFECT_SKULL_BASH + jr z, .print + + cp EFFECT_SOLARBEAM + jr z, .print + + cp EFFECT_FLY + jr z, .print + + cp EFFECT_ROLLOUT + jr z, .print + + cp EFFECT_BIDE + jr z, .print + + cp EFFECT_RAMPAGE + jr z, .print + +; 'but no pp is left for the move' + ld hl, NoPPLeftText +.print + call StdBattleTextbox + ld b, 1 + ret + +CheckMimicUsed: + ldh a, [hBattleTurn] + and a + ld a, [wCurMoveNum] + jr z, .player + ld a, [wCurEnemyMoveNum] + +.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 + +BattleCommand_Critical: +; critical + +; Determine whether this attack's hit will be critical. + + xor a + ld [wCriticalHit], a + + ld a, BATTLE_VARS_MOVE_POWER + call GetBattleVar + and a + ret z + + ldh a, [hBattleTurn] + and a + ld hl, wEnemyMonItem + ld a, [wEnemyMonSpecies] + jr nz, .Item + ld hl, wBattleMonItem + ld a, [wBattleMonSpecies] + +.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, CriticalHitMoves + 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, CriticalHitChances + ld b, 0 + add hl, bc + call BattleRandom + cp [hl] + ret nc + ld a, 1 + ld [wCriticalHit], a + ret + +INCLUDE "data/moves/critical_hit_moves.asm" + +INCLUDE "data/battle/critical_hit_chances.asm" + +INCLUDE "engine/battle/move_effects/triple_kick.asm" |