diff options
author | entrpntr <entrpntr@gmail.com> | 2020-04-19 15:25:51 -0400 |
---|---|---|
committer | entrpntr <entrpntr@gmail.com> | 2020-04-19 15:25:51 -0400 |
commit | 7b63a9c032a130a08fc554b9b6790fe47d170530 (patch) | |
tree | c5a5169c8c3946154cf846f0c61d87516bb0c87d | |
parent | e953302d3f81f080fd5d8423000496ce2fad36d3 (diff) |
Finish disassembling effect commands.
56 files changed, 5718 insertions, 141 deletions
diff --git a/constants/battle_constants.asm b/constants/battle_constants.asm index 4fc3020b..796697db 100644 --- a/constants/battle_constants.asm +++ b/constants/battle_constants.asm @@ -90,8 +90,6 @@ const_value SET 1 const BATTLETYPE_TREE const BATTLETYPE_TRAP const BATTLETYPE_FORCEITEM - const BATTLETYPE_CELEBI - const BATTLETYPE_SUICUNE ; battle variables const_def @@ -248,3 +246,6 @@ SUBSTATUS_CURLED EQU 0 const WIN const LOSE const DRAW + +BATTLERESULT_BOX_FULL EQU 7 +BATTLERESULT_BITMASK EQU (1 << BATTLERESULT_BOX_FULL) diff --git a/data/battle/stat_multipliers.asm b/data/battle/stat_multipliers.asm new file mode 100644 index 00000000..bbb1cadd --- /dev/null +++ b/data/battle/stat_multipliers.asm @@ -0,0 +1,20 @@ +; Multiplier ratios for all stats from modifier -6 to +6 +; (except accuracy, see data/battle/accuracy_multipliers.asm). + +; This table is identical to data/battle/stat_multipliers_2.asm. +; This one is used by CalcBattleStats. + +StatLevelMultipliers: + db 25, 100 ; -6 = 25% + db 28, 100 ; -5 = 28% + db 33, 100 ; -4 = 33% + db 40, 100 ; -3 = 40% + db 50, 100 ; -2 = 50% + db 66, 100 ; -1 = 66% + db 1, 1 ; 0 = 100% + db 15, 10 ; +1 = 150% + db 2, 1 ; +2 = 200% + db 25, 10 ; +3 = 250% + db 3, 1 ; +4 = 300% + db 35, 10 ; +5 = 350% + db 4, 1 ; +6 = 400% diff --git a/data/battle/stat_names.asm b/data/battle/stat_names.asm new file mode 100644 index 00000000..a144a225 --- /dev/null +++ b/data/battle/stat_names.asm @@ -0,0 +1,10 @@ +StatNames: +; entries correspond to stat ids + db "ATTACK@" + db "DEFENSE@" + db "SPEED@" + db "SPCL.ATK@" + db "SPCL.DEF@" + db "ACCURACY@" + db "EVASION@" + db "ABILITY@" ; used for BattleCommand_Curse diff --git a/data/moves/magnitude_power.asm b/data/moves/magnitude_power.asm new file mode 100644 index 00000000..7359bdb1 --- /dev/null +++ b/data/moves/magnitude_power.asm @@ -0,0 +1,9 @@ +MagnitudePower: + ; chance, power, 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 diff --git a/data/moves/metronome_exception_moves.asm b/data/moves/metronome_exception_moves.asm new file mode 100644 index 00000000..a5aa4413 --- /dev/null +++ b/data/moves/metronome_exception_moves.asm @@ -0,0 +1,17 @@ +; Metronome cannot turn into these moves. + +MetronomeExcepts: + db NO_MOVE + db METRONOME + db STRUGGLE + db SKETCH + db MIMIC + db COUNTER + db MIRROR_COAT + db PROTECT + db DETECT + db ENDURE + db DESTINY_BOND + db SLEEP_TALK + db THIEF + db -1 diff --git a/data/moves/present_power.asm b/data/moves/present_power.asm new file mode 100644 index 00000000..885e9c69 --- /dev/null +++ b/data/moves/present_power.asm @@ -0,0 +1,6 @@ +PresentPower: + ; chance, power + db 40 percent, 40 ; 40% + db 70 percent + 1, 80 ; 30% + db 80 percent, 120 ; 10% + db -1 ; 20% chance to heal instead diff --git a/data/text/battle.asm b/data/text/battle.asm index a222cac5..cccc9421 100755 --- a/data/text/battle.asm +++ b/data/text/battle.asm @@ -442,7 +442,7 @@ UsedBindText: cont "<TARGET>!" prompt -WhirlpoolTrapText: +WasTrappedText: text "<TARGET>" line "was trapped!" prompt @@ -806,7 +806,7 @@ SubFadedText: line "SUBSTITUTE faded!" prompt -LearnedMoveText: +MimicLearnedMoveText: text "<USER>" line "learned" cont "@" @@ -1072,7 +1072,7 @@ BeatUpAttackText: line "attack!" done -CanReceiveGiftText: +CantReceiveGiftText: text "<TARGET> can't" line "receive the gift!" prompt diff --git a/data/text/common_2.asm b/data/text/common_2.asm index 355c88bb..d82fdccd 100644 --- a/data/text/common_2.asm +++ b/data/text/common_2.asm @@ -372,65 +372,65 @@ _EndUsedMove5Text:: text "!" done -UnknownText_0x1c0cc6:: +Text_BattleEffectActivate:: text "<USER>'s" line "@" text_ram wStringBuffer2 db "@@" -UnknownText_0x1c0cd0:: +_BattleStatWentWayUpText:: text_pause text "<SCROLL>went way up!" prompt -UnknownText_0x1c0ce0:: +_BattleStatWentUpText:: text " went up!" prompt -UnknownText_0x1c0ceb:: +Text_BattleFoeEffectActivate:: text "<TARGET>'s" line "@" text_ram wStringBuffer2 db "@@" -UnknownText_0x1c0cf5:: +_BattleStatSharplyFellText:: text_pause text "<SCROLL>sharply fell!" prompt -UnknownText_0x1c0d06:: +_BattleStatFellText:: text " fell!" prompt -UnknownText_0x1c0d0e:: +Text_BattleUser:: text "<USER>@@" -UnknownText_0x1c0d12:: +_BattleMadeWhirlwindText:: text_start line "made a whirlwind!" prompt -UnknownText_0x1c0d26:: +_BattleTookSunlightText:: text_start line "took in sunlight!" prompt -UnknownText_0x1c0d3a:: +_BattleLoweredHeadText:: text_start line "lowered its head!" prompt -UnknownText_0x1c0d4e:: +_BattleGlowingText:: text_start line "is glowing!" prompt -UnknownText_0x1c0d5c:: +_BattleFlewText:: text_start line "flew up high!" prompt -UnknownText_0x1c0d6c:: +_BattleDugText:: text_start line "dug a hole!" prompt diff --git a/engine/battle/effect_commands.asm b/engine/battle/effect_commands.asm index 7734c66f..815cc17d 100644 --- a/engine/battle/effect_commands.asm +++ b/engine/battle/effect_commands.asm @@ -3571,3 +3571,3295 @@ DoSubstituteDamage: call RefreshBattleHuds .done jp ResetDamage + +UpdateMoveData: + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVarAddr + ld d, h + ld e, l + + ld a, BATTLE_VARS_MOVE + call GetBattleVar + ld [wCurSpecies], a + ld [wNamedObjectIndexBuffer], a + + dec a + call GetMoveData + call GetMoveName + jp CopyName1 + +BattleCommand_SleepTarget: +; 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, [wAttackMissed] + 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 + +.random_loop + call BattleRandom + and 7 + 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 + ret nz + + call OpponentCantMove + ret + +.fail + call AnimateFailedMove + jp StdBattleTextbox + +.CheckAIRandomFail: + ; Enemy turn + ldh a, [hBattleTurn] + and a + jr z, .dont_fail + + ; Not in link battle + ld a, [wLinkMode] + and a + jr nz, .dont_fail + + ; Not locked-on by the enemy + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .dont_fail + + call BattleRandom + cp 25 percent + 1 ; 25% chance AI fails + ret c + +.dont_fail + xor a + ret + +BattleCommand_PoisonTarget: +; poisontarget + + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + ret nz + ld a, [wTypeModifier] + and $7f + ret z + call CheckIfTargetIsPoisonType + ret z + call GetOpponentItem + ld a, b + cp HELD_PREVENT_POISON + ret z + ld a, [wEffectFailed] + 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 + +BattleCommand_Poison: +; poison + + ld hl, DoesntAffectText + ld a, [wTypeModifier] + 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 + + ldh a, [hBattleTurn] + and a + jr z, .dont_sample_failure + + ld a, [wLinkMode] + and a + jr nz, .dont_sample_failure + + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .dont_sample_failure + + call BattleRandom + cp 25 percent + 1 ; 25% chance AI fails + jr c, .failed + +.dont_sample_failure + call CheckSubstituteOpp + jr nz, .failed + ld a, [wAttackMissed] + 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 + call AnimateFailedMove + jp StdBattleTextbox + +.apply_poison + call AnimateCurrentMove + call PoisonOpponent + jp RefreshBattleHuds + +.check_toxic + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + ldh a, [hBattleTurn] + and a + ld de, wEnemyToxicCount + jr z, .ok + ld de, wPlayerToxicCount +.ok + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_TOXIC + ret + +CheckIfTargetIsPoisonType: + ld de, wEnemyMonType1 + ldh a, [hBattleTurn] + and a + jr z, .ok + ld de, wBattleMonType1 +.ok + ld a, [de] + inc de + cp POISON + ret z + ld a, [de] + cp POISON + ret + +PoisonOpponent: + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + set PSN, [hl] + jp UpdateOpponentInParty + +BattleCommand_DrainTarget: +; draintarget + call SapHealth + ld hl, SuckedHealthText + jp StdBattleTextbox + +BattleCommand_EatDream: +; eatdream + call SapHealth + ld hl, DreamEatenText + jp StdBattleTextbox + +SapHealth: + ; Divide damage by 2, store it in hDividend + ld hl, wCurDamage + ld a, [hli] + srl a + ldh [hDividend], a + ld b, a + ld a, [hl] + rr a + ldh [hDividend + 1], a + or b + jr nz, .at_least_one + ld a, 1 + ldh [hDividend + 1], a +.at_least_one + + ld hl, wBattleMonHP + ld de, wBattleMonMaxHP + ldh a, [hBattleTurn] + and a + jr z, .battlemonhp + ld hl, wEnemyMonHP + ld de, wEnemyMonMaxHP +.battlemonhp + + ; Store current HP in little endian wBuffer3/4 + ld bc, wBuffer4 + ld a, [hli] + ld [bc], a + ld a, [hl] + dec bc + ld [bc], a + + ; Store max HP in little endian wBuffer1/2 + ld a, [de] + dec bc + ld [bc], a + inc de + ld a, [de] + dec bc + ld [bc], a + + ; Add hDividend to current HP and copy it to little endian wBuffer5/6 + ldh a, [hDividend + 1] + ld b, [hl] + add b + ld [hld], a + ld [wBuffer5], a + ldh a, [hDividend] + ld b, [hl] + adc b + ld [hli], a + ld [wBuffer6], a + jr c, .max_hp + + ; Substract current HP from max HP (to see if we have more than max HP) + 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, .finish + +.max_hp + ; Load max HP into current HP and copy it to little endian wBuffer5/6 + ld a, [de] + ld [hld], a + ld [wBuffer5], a + dec de + ld a, [de] + ld [hli], a + ld [wBuffer6], a + inc de + +.finish + ldh 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 + +BattleCommand_BurnTarget: +; 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, [wTypeModifier] + 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, [wEffectFailed] + 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 + +Defrost: + ld a, [hl] + and 1 << FRZ + ret z + + xor a + ld [hl], a + + ldh a, [hBattleTurn] + and a + ld a, [wCurOTMon] + ld hl, wOTPartyMon1Status + jr z, .ok + ld hl, wPartyMon1Status + ld a, [wCurBattleMon] +.ok + + call GetPartyLocation + xor a + ld [hl], a + call UpdateOpponentInParty + + ld hl, DefrostedOpponentText + jp StdBattleTextbox + +BattleCommand_FreezeTarget: +; freezetarget + + xor a + ld [wNumHits], a + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + ret nz + ld a, [wTypeModifier] + and $7f + ret z + ld a, [wBattleWeather] + 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, [wEffectFailed] + 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 + ldh a, [hBattleTurn] + and a + jr z, .finish + ld hl, wPlayerJustGotFrozen +.finish + ld [hl], $1 + ret + +BattleCommand_ParalyzeTarget: +; paralyzetarget + + xor a + ld [wNumHits], a + call CheckSubstituteOpp + ret nz + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + ret nz + ld a, [wTypeModifier] + and $7f + ret z + call GetOpponentItem + ld a, b + cp HELD_PREVENT_PARALYZE + ret z + ld a, [wEffectFailed] + 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 + +BattleCommand_AttackUp: +; attackup + ld b, ATTACK + jr BattleCommand_StatUp + +BattleCommand_DefenseUp: +; defenseup + ld b, DEFENSE + jr BattleCommand_StatUp + +BattleCommand_SpeedUp: +; speedup + ld b, SPEED + jr BattleCommand_StatUp + +BattleCommand_SpecialAttackUp: +; specialattackup + ld b, SP_ATTACK + jr BattleCommand_StatUp + +BattleCommand_SpecialDefenseUp: +; specialdefenseup + ld b, SP_DEFENSE + jr BattleCommand_StatUp + +BattleCommand_AccuracyUp: +; accuracyup + ld b, ACCURACY + jr BattleCommand_StatUp + +BattleCommand_EvasionUp: +; evasionup + ld b, EVASION + jr BattleCommand_StatUp + +BattleCommand_AttackUp2: +; attackup2 + ld b, $10 | ATTACK + jr BattleCommand_StatUp + +BattleCommand_DefenseUp2: +; defenseup2 + ld b, $10 | DEFENSE + jr BattleCommand_StatUp + +BattleCommand_SpeedUp2: +; speedup2 + ld b, $10 | SPEED + jr BattleCommand_StatUp + +BattleCommand_SpecialAttackUp2: +; specialattackup2 + ld b, $10 | SP_ATTACK + jr BattleCommand_StatUp + +BattleCommand_SpecialDefenseUp2: +; specialdefenseup2 + ld b, $10 | SP_DEFENSE + jr BattleCommand_StatUp + +BattleCommand_AccuracyUp2: +; accuracyup2 + ld b, $10 | ACCURACY + jr BattleCommand_StatUp + +BattleCommand_EvasionUp2: +; evasionup2 + ld b, $10 | EVASION + jr BattleCommand_StatUp + +BattleCommand_StatUp: +; statup + call RaiseStat + ld a, [wFailedMessage] + and a + ret nz + jp MinimizeDropSub + +RaiseStat: + ld a, b + ld [wLoweredStat], a + ld hl, wPlayerStatLevels + ldh a, [hBattleTurn] + and a + jr z, .got_stat_levels + ld hl, wEnemyStatLevels +.got_stat_levels + ld a, [wAttackMissed] + and a + jp nz, .stat_raise_failed + ld a, [wEffectFailed] + and a + jp nz, .stat_raise_failed + ld a, [wLoweredStat] + 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, [wLoweredStat] + 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, wBattleMonStats + 1 + ld de, wPlayerStats + ldh a, [hBattleTurn] + and a + jr z, .got_stats_pointer + ld hl, wEnemyMonStats + 1 + ld de, wEnemyStats +.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 + ldh 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 [wFailedMessage], a + ret + +.stats_already_max + pop hl + dec [hl] + ; fallthrough + +.cant_raise_stat + ld a, $2 + ld [wFailedMessage], a + ld a, $1 + ld [wAttackMissed], a + ret + +.stat_raise_failed + ld a, $1 + ld [wFailedMessage], a + ret + +MinimizeDropSub: +; Lower the substitute if we're minimizing + + ld bc, wPlayerMinimized + ld hl, DropPlayerSub + ldh 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 + ; check battle scene + ld a, [wOptions] + add a + ret nc + + xor a + ldh [hBGMapMode], a + call CallBattleCore + call WaitBGMap + jp BattleCommand_MoveDelay + +BattleCommand_AttackDown: +; attackdown + ld a, ATTACK + jr BattleCommand_StatDown + +BattleCommand_DefenseDown: +; defensedown + ld a, DEFENSE + jr BattleCommand_StatDown + +BattleCommand_SpeedDown: +; speeddown + ld a, SPEED + jr BattleCommand_StatDown + +BattleCommand_SpecialAttackDown: +; specialattackdown + ld a, SP_ATTACK + jr BattleCommand_StatDown + +BattleCommand_SpecialDefenseDown: +; specialdefensedown + ld a, SP_DEFENSE + jr BattleCommand_StatDown + +BattleCommand_AccuracyDown: +; accuracydown + ld a, ACCURACY + jr BattleCommand_StatDown + +BattleCommand_EvasionDown: +; evasiondown + ld a, EVASION + jr BattleCommand_StatDown + +BattleCommand_AttackDown2: +; attackdown2 + ld a, $10 | ATTACK + jr BattleCommand_StatDown + +BattleCommand_DefenseDown2: +; defensedown2 + ld a, $10 | DEFENSE + jr BattleCommand_StatDown + +BattleCommand_SpeedDown2: +; speeddown2 + ld a, $10 | SPEED + jr BattleCommand_StatDown + +BattleCommand_SpecialAttackDown2: +; specialattackdown2 + ld a, $10 | SP_ATTACK + jr BattleCommand_StatDown + +BattleCommand_SpecialDefenseDown2: +; specialdefensedown2 + ld a, $10 | SP_DEFENSE + jr BattleCommand_StatDown + +BattleCommand_AccuracyDown2: +; accuracydown2 + ld a, $10 | ACCURACY + jr BattleCommand_StatDown + +BattleCommand_EvasionDown2: +; evasiondown2 + ld a, $10 | EVASION + +BattleCommand_StatDown: +; statdown + + ld [wLoweredStat], a + + call CheckMist + jp nz, .Mist + + ld hl, wEnemyStatLevels + ldh a, [hBattleTurn] + and a + jr z, .GetStatLevel + ld hl, wPlayerStatLevels + +.GetStatLevel: +; Attempt to lower the stat. + ld a, [wLoweredStat] + 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, [wLoweredStat] + and $f0 + jr z, .ComputerMiss + dec b + jr nz, .ComputerMiss + inc b + +.ComputerMiss: +; Computer opponents have a 25% chance of failing. + ldh a, [hBattleTurn] + and a + jr z, .DidntMiss + + ld a, [wLinkMode] + and a + jr nz, .DidntMiss + +; Lock-On still always works. + ld a, [wPlayerSubStatus5] + 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 25 percent + 1 ; 25% chance AI fails + jr c, .Failed + +.DidntMiss: + call CheckSubstituteOpp + jr nz, .Failed + + ld a, [wAttackMissed] + and a + jr nz, .Failed + + ld a, [wEffectFailed] + 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, wEnemyMonAttack + 1 + ld de, wEnemyStats + ldh a, [hBattleTurn] + and a + jr z, .do_enemy + ld hl, wBattleMonAttack + 1 + ld de, wPlayerStats +.do_enemy + call TryLowerStat + pop hl + jr z, .CouldntLower + +.Hit: + xor a + ld [wFailedMessage], a + ret + +.CouldntLower: + inc [hl] +.CantLower: + ld a, 3 + ld [wFailedMessage], a + ld a, 1 + ld [wAttackMissed], a + ret + +.Failed: + ld a, 1 + ld [wFailedMessage], a + ld [wAttackMissed], a + ret + +.Mist: + ld a, 2 + ld [wFailedMessage], a + ld a, 1 + ld [wAttackMissed], a + ret + +CheckMist: + 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 + +BattleCommand_StatUpMessage: + ld a, [wFailedMessage] + and a + ret nz + ld a, [wLoweredStat] + and $f + ld b, a + inc b + call GetStatName + ld hl, .stat + jp PrintText + +.stat + text_far Text_BattleEffectActivate + text_asm + ld hl, .BattleStatWentUpText + ld a, [wLoweredStat] + and $f0 + ret z + ld hl, .BattleStatWentWayUpText + ret + +.BattleStatWentWayUpText: + text_far _BattleStatWentWayUpText + text_end + +.BattleStatWentUpText: + text_far _BattleStatWentUpText + text_end + +BattleCommand_StatDownMessage: + ld a, [wFailedMessage] + and a + ret nz + ld a, [wLoweredStat] + and $f + ld b, a + inc b + call GetStatName + ld hl, .stat + jp PrintText + +.stat + text_far Text_BattleFoeEffectActivate + text_asm + ld hl, .BattleStatFellText + ld a, [wLoweredStat] + and $f0 + ret z + ld hl, .BattleStatSharplyFellText + ret + +.BattleStatSharplyFellText: + text_far _BattleStatSharplyFellText + text_end + +.BattleStatFellText: + text_far _BattleStatFellText + text_end + +TryLowerStat: +; 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 + ldh 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 + +BattleCommand_StatUpFailText: +; statupfailtext + ld a, [wFailedMessage] + and a + ret z + push af + call BattleCommand_MoveDelay + pop af + dec a + jp z, TryPrintButItFailed + ld a, [wLoweredStat] + and $f + ld b, a + inc b + call GetStatName + ld hl, WontRiseAnymoreText + jp StdBattleTextbox + +BattleCommand_StatDownFailText: +; statdownfailtext + ld a, [wFailedMessage] + 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, [wLoweredStat] + and $f + ld b, a + inc b + call GetStatName + ld hl, WontDropAnymoreText + jp StdBattleTextbox + +GetStatName: + ld hl, StatNames + ld c, "@" +.CheckName: + dec b + jr z, .Copy +.GetName: + ld a, [hli] + cp c + jr z, .CheckName + jr .GetName + +.Copy: + ld de, wStringBuffer2 + ld bc, 10 + jp CopyBytes + +INCLUDE "data/battle/stat_names.asm" + +INCLUDE "data/battle/stat_multipliers.asm" + +BattleCommand_AllStatsUp: +; 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 + +ResetMiss: + xor a + ld [wAttackMissed], a + ret + +LowerStat: + ld [wLoweredStat], a + + ld hl, wPlayerStatLevels + ldh a, [hBattleTurn] + and a + jr z, .got_target + ld hl, wEnemyStatLevels + +.got_target + ld a, [wLoweredStat] + and $f + ld c, a + ld b, 0 + add hl, bc + ld b, [hl] + dec b + jr z, .cant_lower_anymore + + ld a, [wLoweredStat] + 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, wBattleMonStats + 1 + ld de, wPlayerStats + ldh a, [hBattleTurn] + and a + jr z, .got_target_2 + ld hl, wEnemyMonStats + 1 + ld de, wEnemyStats + +.got_target_2 + call TryLowerStat + pop hl + jr z, .failed + +.accuracy_evasion + ldh a, [hBattleTurn] + and a + jr z, .player + + call CalcEnemyStats + + jr .finish + +.player + call CalcPlayerStats + +.finish + xor a + ld [wFailedMessage], a + ret + +.failed + inc [hl] + +.cant_lower_anymore + ld a, 2 + ld [wFailedMessage], a + ret + +BattleCommand_TriStatusChance: +; tristatuschance + + call BattleCommand_EffectChance + +.loop + ; 1/3 chance of each status + call BattleRandom + swap a + and %11 + jr z, .loop + dec a + ld hl, .ptrs + rst JumpTable + ret + +.ptrs + dw BattleCommand_ParalyzeTarget ; paralyze + dw BattleCommand_FreezeTarget ; freeze + dw BattleCommand_BurnTarget ; burn + +BattleCommand_Curl: +; curl + ld a, BATTLE_VARS_SUBSTATUS2 + call GetBattleVarAddr + set SUBSTATUS_CURLED, [hl] + ret + +BattleCommand_RaiseSubNoAnim: + ld hl, GetBattleMonBackpic + ldh a, [hBattleTurn] + and a + jr z, .PlayerTurn + ld hl, GetEnemyMonFrontpic +.PlayerTurn: + xor a + ldh [hBGMapMode], a + call CallBattleCore + jp WaitBGMap + +BattleCommand_LowerSubNoAnim: + ld hl, DropPlayerSub + ldh a, [hBattleTurn] + and a + jr z, .PlayerTurn + ld hl, DropEnemySub +.PlayerTurn: + xor a + ldh [hBGMapMode], a + call CallBattleCore + jp WaitBGMap + +CalcPlayerStats: + ld hl, wPlayerAtkLevel + ld de, wPlayerStats + ld bc, wBattleMonAttack + + ld a, 5 + call CalcBattleStats + + ld hl, BadgeStatBoosts + call CallBattleCore + + call BattleCommand_SwitchTurn + + ld hl, ApplyPrzEffectOnSpeed + call CallBattleCore + + ld hl, ApplyBrnEffectOnAttack + call CallBattleCore + + jp BattleCommand_SwitchTurn + +CalcEnemyStats: + ld hl, wEnemyAtkLevel + ld de, wEnemyStats + ld bc, wEnemyMonAttack + + ld a, 5 + call CalcBattleStats + + call BattleCommand_SwitchTurn + + ld hl, ApplyPrzEffectOnSpeed + call CallBattleCore + + ld hl, ApplyBrnEffectOnAttack + call CallBattleCore + + jp BattleCommand_SwitchTurn + +CalcBattleStats: +.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 + ldh [hMultiplicand + 0], a + ld a, [de] + ldh [hMultiplicand + 1], a + inc de + ld a, [de] + ldh [hMultiplicand + 2], a + inc de + + ld a, [hli] + ldh [hMultiplier], a + call Multiply + + ld a, [hl] + ldh [hDivisor], a + ld b, 4 + call Divide + + ldh a, [hQuotient + 2] + ld b, a + ldh a, [hQuotient + 3] + or b + jr nz, .check_maxed_out + + ld a, 1 + ldh [hQuotient + 3], a + jr .not_maxed_out + +.check_maxed_out + ldh a, [hQuotient + 3] + cp LOW(MAX_STAT_VALUE) + ld a, b + sbc HIGH(MAX_STAT_VALUE) + jr c, .not_maxed_out + + ld a, LOW(MAX_STAT_VALUE) + ldh [hQuotient + 3], a + ld a, HIGH(MAX_STAT_VALUE) + ldh [hQuotient + 2], a + +.not_maxed_out + pop bc + ldh a, [hQuotient + 2] + ld [bc], a + inc bc + ldh a, [hQuotient + 3] + ld [bc], a + inc bc + pop hl + pop af + dec a + jr nz, .loop + + ret + +INCLUDE "engine/battle/move_effects/bide.asm" + +BattleCommand_CheckRampage: +; checkrampage + + ld de, wPlayerRolloutCount + ldh a, [hBattleTurn] + and a + jr z, .player + ld de, wEnemyRolloutCount +.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 + +BattleCommand_Rampage: +; rampage + +; No rampage during Sleep Talk. + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + ret nz + + ld de, wPlayerRolloutCount + ldh a, [hBattleTurn] + and a + jr z, .ok + ld de, wEnemyRolloutCount +.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 + +INCLUDE "engine/battle/move_effects/teleport.asm" + +BattleCommand_ForceSwitch: +; forceswitch + + ld a, [wBattleType] + cp BATTLETYPE_SHINY + jp z, .fail + cp BATTLETYPE_TRAP + jp z, .fail + ldh a, [hBattleTurn] + and a + jp nz, .force_player_switch + ld a, [wAttackMissed] + and a + jr nz, .missed + ld a, [wBattleMode] + dec a + jr nz, .trainer + ld a, [wCurPartyLevel] + ld b, a + ld a, [wBattleMonLevel] + 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 + ; set battle draw + inc a + ld [wBattleResult], a + 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, [wOTPartyCount] + ld b, a + ld a, [wCurOTMon] + 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, wOTPartyMon1HP + 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, [wAttackMissed] + and a + jr nz, .player_miss + + ld a, [wBattleMode] + dec a + jr nz, .vs_trainer + + ld a, [wBattleMonLevel] + ld b, a + ld a, [wCurPartyLevel] + 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 + jp .fail + +.wild_succeed_playeristarget + call UpdateBattleMonInParty + xor a + ld [wNumHits], a + inc a + ld [wForcedSwitch], a + ; set battle draw + inc a + ld [wBattleResult], a + ld a, [wEnemyMoveStructAnimation] + jr .succeed + +.vs_trainer + call CheckPlayerHasMonToSwitchTo + jr c, .switch_fail2 + + 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, [wPartyCount] + ld b, a + ld a, [wCurBattleMon] + 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, wPartyMon1HP + call GetPartyLocation + ld a, [hli] + or [hl] + pop bc + pop de + jr z, .random_loop_trainer_playeristarget + + ld a, d + ld [wCurPartyMon], a + ld hl, SwitchPlayerMon + call CallBattleCore + + ld hl, DraggedOutText + call StdBattleTextbox + + ld hl, SpikesDamage + jp CallBattleCore + +.switch_fail2 + jr .fail + +.succeed + push af + ld a, DRAW + ld [wBattleResult], a + 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 + +.fail + call BattleCommand_LowerSub + call BattleCommand_MoveDelay + call BattleCommand_RaiseSub + jp PrintButItFailed + +CheckPlayerHasMonToSwitchTo: + ld a, [wPartyCount] + ld d, a + ld e, 0 + ld bc, PARTYMON_STRUCT_LENGTH +.loop + ld a, [wCurBattleMon] + cp e + jr z, .next + + ld a, e + ld hl, wPartyMon1HP + 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 + +BattleCommand_EndLoop: +; endloop + +; Loop back to 'critical'. + + ld de, wPlayerRolloutCount + ld bc, wPlayerDamageTaken + ldh a, [hBattleTurn] + and a + jr z, .got_addrs + ld de, wEnemyRolloutCount + ld bc, wEnemyDamageTaken +.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 + ldh a, [hBattleTurn] + and a + jr nz, .check_ot_beat_up + ld a, [wPartyCount] + 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, [wOTPartyCount] + 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 BattleCommand_BeatUpFailText + 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 + ldh 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_critical + ld a, [wBattleScriptBufferAddress + 1] + ld h, a + ld a, [wBattleScriptBufferAddress] + ld l, a +.not_critical + ld a, [hld] + cp critical_command + jr nz, .not_critical + inc hl + ld a, h + ld [wBattleScriptBufferAddress + 1], a + ld a, l + ld [wBattleScriptBufferAddress], a + ret + +BattleCommand_FakeOut: + ld a, [wAttackMissed] + 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 [wAttackMissed], a + ret + +BattleCommand_FlinchTarget: + call CheckSubstituteOpp + ret nz + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVar + and 1 << FRZ | SLP + ret nz + + call CheckOpponentWentFirst + ret nz + + ld a, [wEffectFailed] + and a + ret nz + + ; fallthrough + +FlinchTarget: + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVarAddr + set SUBSTATUS_FLINCHED, [hl] + jp EndRechargeOpp + +CheckOpponentWentFirst: +; 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 + ldh a, [hBattleTurn] ; 0 if it's the player's turn + xor b ; 1 if opponent went first + pop bc + ret + +BattleCommand_HeldFlinch: +; kingsrock + + ld a, [wAttackMissed] + 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 + +BattleCommand_OHKO: +; ohko + + call ResetDamage + ld a, [wTypeModifier] + and $7f + jr z, .no_effect + ld hl, wEnemyMonLevel + ld de, wBattleMonLevel + ld bc, wPlayerMoveStruct + MOVE_ACC + ldh 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, wCurDamage + ld a, $ff + ld [hli], a + ld [hl], a + ld a, $2 + ld [wCriticalHit], a + ret + +.no_effect + ld a, $ff + ld [wCriticalHit], a + ld a, $1 + ld [wAttackMissed], a + ret + +BattleCommand_CheckCharge: +; 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 + +BattleCommand_Charge: +; 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, [wAlreadyDisobeyed] + 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 PrintText + + ld a, BATTLE_VARS_MOVE_EFFECT + call GetBattleVar + cp EFFECT_SKULL_BASH + ld b, endturn_command + jp z, SkipToBattleCommand + jp EndMoveEffect + +.UsedText: + text_far Text_BattleUser ; "<USER>" + text_asm + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + cp RAZOR_WIND + ld hl, .BattleMadeWhirlwindText + jr z, .done + + cp SOLARBEAM + ld hl, .BattleTookSunlightText + jr z, .done + + cp SKULL_BASH + ld hl, .BattleLoweredHeadText + jr z, .done + + cp SKY_ATTACK + ld hl, .BattleGlowingText + jr z, .done + + cp FLY + ld hl, .BattleFlewText + jr z, .done + + cp DIG + ld hl, .BattleDugText + +.done + ret + +.BattleMadeWhirlwindText: + text_far _BattleMadeWhirlwindText + text_end + +.BattleTookSunlightText: + text_far _BattleTookSunlightText + text_end + +.BattleLoweredHeadText: + text_far _BattleLoweredHeadText + text_end + +.BattleGlowingText: + text_far _BattleGlowingText + text_end + +.BattleFlewText: + text_far _BattleFlewText + text_end + +.BattleDugText: + text_far _BattleDugText + text_end + +BattleCommand3c: +; unused + ret + +BattleCommand_TrapTarget: +; traptarget + + ld a, [wAttackMissed] + and a + ret nz + ld hl, wEnemyWrapCount + ld de, wEnemyTrappingMove + ldh 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 + ; trapped for 2-5 turns + and %11 + 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, WasTrappedText ; 'was trapped!' + dbw CLAMP, ClampedByText ; 'was CLAMPED by' + dbw WHIRLPOOL, WasTrappedText ; 'was trapped!' + +INCLUDE "engine/battle/move_effects/mist.asm" + +INCLUDE "engine/battle/move_effects/focus_energy.asm" + +BattleCommand_Recoil: +; recoil + + ld hl, wBattleMonMaxHP + ldh a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, wEnemyMonMaxHP +.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, [wCurDamage] + ld b, a + ld a, [wCurDamage + 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 [wBuffer2], a + ld a, [hl] + ld [wBuffer1], a + dec hl + dec hl + ld a, [hl] + ld [wBuffer3], a + sub c + ld [hld], a + ld [wBuffer5], a + ld a, [hl] + ld [wBuffer4], a + sbc b + ld [hl], a + ld [wBuffer6], a + jr nc, .dont_ko + xor a + ld [hli], a + ld [hl], a + ld hl, wBuffer5 + ld [hli], a + ld [hl], a +.dont_ko + hlcoord 10, 9 + ldh 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 + +BattleCommand_ConfuseTarget: +; confusetarget + + call GetOpponentItem + ld a, b + cp HELD_PREVENT_CONFUSE + ret z + ld a, [wEffectFailed] + 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: +; 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, [wAttackMissed] + and a + jr nz, BattleCommand_Confuse_CheckSnore_Swagger_ConfuseHit +BattleCommand_FinishConfusingTarget: + ld bc, wEnemyConfuseCount + ldh a, [hBattleTurn] + and a + jr z, .got_confuse_count + ld bc, wPlayerConfuseCount + +.got_confuse_count + set SUBSTATUS_CONFUSED, [hl] + ; confused for 2-5 turns + call BattleRandom + and %11 + 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 + +BattleCommand_Confuse_CheckSnore_Swagger_ConfuseHit: + 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 + +BattleCommand_Paralyze: +; paralyze + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVar + bit PAR, a + jr nz, .paralyzed + ld a, [wTypeModifier] + 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 + ldh a, [hBattleTurn] + and a + jr z, .dont_sample_failure + + ld a, [wLinkMode] + and a + jr nz, .dont_sample_failure + + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_LOCK_ON, a + jr nz, .dont_sample_failure + + call BattleRandom + cp 25 percent + 1 ; 25% chance AI fails + jr c, .failed + +.dont_sample_failure + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and a + jr nz, .failed + ld a, [wAttackMissed] + and a + jr nz, .failed + call CheckSubstituteOpp + jr nz, .failed + ld c, 30 + call DelayFrames + call AnimateCurrentMove + ld a, $1 + ldh [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 + +CheckMoveTypeMatchesTarget: +; Compare move type to opponent type. +; Return z if matching the opponent type, +; unless the move is Normal (Tri Attack). + + push hl + + ld hl, wEnemyMonType1 + ldh a, [hBattleTurn] + and a + jr z, .ok + ld hl, wBattleMonType1 +.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 + +INCLUDE "engine/battle/move_effects/substitute.asm" + +BattleCommand_RechargeNextTurn: +; rechargenextturn + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + set SUBSTATUS_RECHARGE, [hl] + ret + +EndRechargeOpp: + push hl + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVarAddr + res SUBSTATUS_RECHARGE, [hl] + pop hl + ret + +INCLUDE "engine/battle/move_effects/rage.asm" + +BattleCommand_DoubleFlyingDamage: +; doubleflyingdamage + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + bit SUBSTATUS_FLYING, a + ret z + jr DoubleDamage + +BattleCommand_DoubleUndergroundDamage: +; doubleundergrounddamage + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + bit SUBSTATUS_UNDERGROUND, a + ret z + + ; fallthrough + +DoubleDamage: + ld hl, wCurDamage + 1 + sla [hl] + dec hl + rl [hl] + jr nc, .quit + + ld a, $ff + ld [hli], a + ld [hl], a +.quit + ret + +INCLUDE "engine/battle/move_effects/mimic.asm" + +INCLUDE "engine/battle/move_effects/leech_seed.asm" + +INCLUDE "engine/battle/move_effects/splash.asm" + +INCLUDE "engine/battle/move_effects/disable.asm" + +INCLUDE "engine/battle/move_effects/pay_day.asm" + +INCLUDE "engine/battle/move_effects/conversion.asm" + +BattleCommand_ResetStats: +; resetstats + + ld a, 7 ; neutral + ld hl, wPlayerStatLevels + call .Fill + ld hl, wEnemyStatLevels + call .Fill + + ldh a, [hBattleTurn] + push af + + call SetPlayerTurn + call CalcPlayerStats + call SetEnemyTurn + call CalcEnemyStats + + pop af + ldh [hBattleTurn], a + + call AnimateCurrentMove + + ld hl, EliminatedStatsText + jp StdBattleTextbox + +.Fill: + ld b, wPlayerStatLevelsEnd - wPlayerStatLevels +.next + ld [hli], a + dec b + jr nz, .next + ret + +BattleCommand_Heal: +; heal + + ld de, wBattleMonHP + ld hl, wBattleMonMaxHP + ldh a, [hBattleTurn] + and a + jr z, .got_hp + ld de, wEnemyMonHP + ld hl, wEnemyMonMaxHP +.got_hp + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + ld b, a + push hl + push de + push bc + ld c, 2 + call CompareBytes + 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 + ldh 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 + +INCLUDE "engine/battle/move_effects/transform.asm" + +BattleEffect_ButItFailed: + call AnimateFailedMove + jp PrintButItFailed + +ClearLastMove: + 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 + +ResetActorDisable: + ldh a, [hBattleTurn] + and a + jr z, .player + + xor a + ld [wEnemyDisableCount], a + ld [wEnemyDisabledMove], a + ret + +.player + xor a + ld [wPlayerDisableCount], a + ld [wDisabledMove], a + ret + +BattleCommand_Screen: +; screen + + ld hl, wPlayerScreens + ld bc, wPlayerLightScreenCount + ldh a, [hBattleTurn] + and a + jr z, .got_screens_pointer + ld hl, wEnemyScreens + ld bc, wEnemyLightScreenCount + +.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 + +PrintDoesntAffect: +; 'it doesn't affect' + ld hl, DoesntAffectText + jp StdBattleTextbox + +PrintNothingHappened: +; 'but nothing happened!' + ld hl, NothingHappenedText + jp StdBattleTextbox + +TryPrintButItFailed: + ld a, [wAlreadyFailed] + and a + ret nz + + ; fallthrough + +PrintButItFailed: +; 'but it failed!' + ld hl, ButItFailedText + jp StdBattleTextbox + +FailMove: + call AnimateFailedMove + ; fallthrough + +FailMimic: + ld hl, ButItFailedText ; 'but it failed!' + ld de, ItFailedText ; 'it failed!' + jp FailText_CheckOpponentProtect + +PrintDidntAffect: +; 'it didn't affect' + ld hl, DidntAffect1Text + jp StdBattleTextbox + +PrintDidntAffect2: + call AnimateFailedMove + ld hl, DidntAffect1Text ; 'it didn't affect' + ld de, DidntAffect2Text ; 'it didn't affect' + jp FailText_CheckOpponentProtect + +PrintParalyze: +; 'paralyzed! maybe it can't attack!' + ld hl, ParalyzedText + jp StdBattleTextbox + +CheckSubstituteOpp: + ld a, BATTLE_VARS_SUBSTATUS4_OPP + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + ret + +INCLUDE "engine/battle/move_effects/selfdestruct.asm" + +INCLUDE "engine/battle/move_effects/mirror_move.asm" + +INCLUDE "engine/battle/move_effects/metronome.asm" + +CheckUserMove: +; Return z if the user has move a. + ld b, a + ld de, wBattleMonMoves + ldh a, [hBattleTurn] + and a + jr z, .ok + ld de, wEnemyMonMoves +.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 + +ResetTurn: + ld hl, wPlayerCharging + ldh a, [hBattleTurn] + and a + jr z, .player + ld hl, wEnemyCharging + +.player + ld [hl], 1 + xor a + ld [wAlreadyDisobeyed], a + call DoMove + jp EndMoveEffect + +INCLUDE "engine/battle/move_effects/thief.asm" + +BattleCommand_ArenaTrap: +; 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 + +INCLUDE "engine/battle/move_effects/nightmare.asm" + +BattleCommand_Defrost: +; 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. + + ldh 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 + +INCLUDE "engine/battle/move_effects/curse.asm" + +INCLUDE "engine/battle/move_effects/protect.asm" + +INCLUDE "engine/battle/move_effects/endure.asm" + +INCLUDE "engine/battle/move_effects/spikes.asm" + +INCLUDE "engine/battle/move_effects/foresight.asm" + +INCLUDE "engine/battle/move_effects/perish_song.asm" + +INCLUDE "engine/battle/move_effects/sandstorm.asm" + +INCLUDE "engine/battle/move_effects/rollout.asm" + +BattleCommand5d: +; unused + ret + +INCLUDE "engine/battle/move_effects/fury_cutter.asm" + +INCLUDE "engine/battle/move_effects/attract.asm" + +INCLUDE "engine/battle/move_effects/return.asm" + +INCLUDE "engine/battle/move_effects/present.asm" + +INCLUDE "engine/battle/move_effects/frustration.asm" + +INCLUDE "engine/battle/move_effects/safeguard.asm" + +SafeCheckSafeguard: + push hl + ld hl, wEnemyScreens + ldh a, [hBattleTurn] + and a + jr z, .got_turn + ld hl, wPlayerScreens + +.got_turn + bit SCREENS_SAFEGUARD, [hl] + pop hl + ret + +BattleCommand_CheckSafeguard: +; checksafeguard + ld hl, wEnemyScreens + ldh a, [hBattleTurn] + and a + jr z, .got_turn + ld hl, wPlayerScreens +.got_turn + bit SCREENS_SAFEGUARD, [hl] + ret z + ld a, 1 + ld [wAttackMissed], a + call BattleCommand_MoveDelay + ld hl, SafeguardProtectText + call StdBattleTextbox + jp EndMoveEffect + +INCLUDE "engine/battle/move_effects/magnitude.asm" + +INCLUDE "engine/battle/move_effects/baton_pass.asm" + +INCLUDE "engine/battle/move_effects/pursuit.asm" + +INCLUDE "engine/battle/move_effects/rapid_spin.asm" + +BattleCommand_HealMorn: +; healmorn + ld b, MORN_F + jr BattleCommand_TimeBasedHealContinue + +BattleCommand_HealDay: +; healday + ld b, DAY_F + jr BattleCommand_TimeBasedHealContinue + +BattleCommand_HealNite: +; healnite + ld b, NITE_F + ; fallthrough + +BattleCommand_TimeBasedHealContinue: +; Time- and weather-sensitive heal. + + ld hl, wBattleMonMaxHP + ld de, wBattleMonHP + ldh a, [hBattleTurn] + and a + jr z, .start + ld hl, wEnemyMonMaxHP + ld de, wEnemyMonHP + +.start +; Index for .Multipliers +; Default restores half max HP. + ld c, 2 + +; Don't bother healing if HP is already full. + push bc + call CompareBytes + 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, [wTimeOfDay] + cp b + jr z, .Weather + dec c ; double + +.Weather: + ld a, [wBattleWeather] + 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 + +INCLUDE "engine/battle/move_effects/hidden_power.asm" + +INCLUDE "engine/battle/move_effects/rain_dance.asm" + +INCLUDE "engine/battle/move_effects/sunny_day.asm" + +INCLUDE "engine/battle/move_effects/belly_drum.asm" + +INCLUDE "engine/battle/move_effects/psych_up.asm" + +INCLUDE "engine/battle/move_effects/mirror_coat.asm" + +BattleCommand_DoubleMinimizeDamage: +; doubleminimizedamage + + ld hl, wEnemyMinimized + ldh a, [hBattleTurn] + and a + jr z, .ok + ld hl, wPlayerMinimized +.ok + ld a, [hl] + and a + ret z + ld hl, wCurDamage + 1 + sla [hl] + dec hl + rl [hl] + ret nc + ld a, $ff + ld [hli], a + ld [hl], a + ret + +BattleCommand_SkipSunCharge: +; mimicsuncharge + ld a, [wBattleWeather] + cp WEATHER_SUN + ret nz + ld b, charge_command + jp SkipToBattleCommand + +INCLUDE "engine/battle/move_effects/future_sight.asm" + +INCLUDE "engine/battle/move_effects/thunder.asm" + +CheckHiddenOpponent: +; BUG: This routine is completely redundant and introduces a bug, since BattleCommand_CheckHit does these checks properly. + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret + +GetUserItem: +; Return the effect of the user's item in bc, and its id at hl. + ld hl, wBattleMonItem + ldh a, [hBattleTurn] + and a + jr z, .go + ld hl, wEnemyMonItem +.go + ld b, [hl] + jp GetItemHeldEffect + +GetOpponentItem: +; Return the effect of the opponent's item in bc, and its id at hl. + ld hl, wEnemyMonItem + ldh a, [hBattleTurn] + and a + jr z, .go + ld hl, wBattleMonItem +.go + ld b, [hl] + jp GetItemHeldEffect + +GetItemHeldEffect: +; 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 + +AnimateCurrentMoveEitherSide: + 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 + +AnimateCurrentMove: + 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 + +PlayDamageAnim: + xor a + ld [wFXAnimID + 1], a + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + and a + ret z + + ld [wFXAnimID], a + + ldh a, [hBattleTurn] + and a + ld a, BATTLEANIM_ENEMY_DAMAGE + jr z, .player + ld a, BATTLEANIM_PLAYER_DAMAGE + +.player + ld [wNumHits], a + + jp PlayUserBattleAnim + +LoadMoveAnim: + xor a + ld [wNumHits], a + ld [wFXAnimID + 1], a + + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVar + and a + ret z + + ; fallthrough + +LoadAnim: + ld [wFXAnimID], a + + ; fallthrough + +PlayUserBattleAnim: + push hl + push de + push bc + callfar PlayBattleAnim + pop bc + pop de + pop hl + ret + +PlayOpponentBattleAnim: + ld a, e + ld [wFXAnimID], a + ld a, d + ld [wFXAnimID + 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 + +CallBattleCore: + ld a, BANK("Battle Core") + rst FarCall + ret + +AnimateFailedMove: + call BattleCommand_LowerSub + call BattleCommand_MoveDelay + jp BattleCommand_RaiseSub + +BattleCommand_MoveDelay: +; movedelay +; Wait 40 frames. + ld c, 40 + jp DelayFrames + +BattleCommand_ClearText: +; cleartext + +; Used in multi-hit moves. + ld hl, .text + jp PrintText + +.text: + text_end + +SkipToBattleCommand: +; Skip over commands until reaching command b. + ld a, [wBattleScriptBufferAddress + 1] + ld h, a + ld a, [wBattleScriptBufferAddress] + ld l, a +.loop + ld a, [hli] + cp b + jr nz, .loop + + ld a, h + ld [wBattleScriptBufferAddress + 1], a + ld a, l + ld [wBattleScriptBufferAddress], a + ret + +GetMoveAttr: +; Assuming hl = Moves + x, return attribute x of move a. + push bc + ld bc, MOVE_LENGTH + call AddNTimes + call GetMoveByte + pop bc + ret + +GetMoveData: +; Copy move struct a to de. + ld hl, Moves + ld bc, MOVE_LENGTH + call AddNTimes + ld a, BANK(Moves) + jp FarCopyBytes + +GetMoveByte: + ld a, BANK(Moves) + jp GetFarByte + +DisappearUser: + farcall _DisappearUser + ret + +AppearUserLowerSub: + farcall _AppearUserLowerSub + ret + +AppearUserRaiseSub: + farcall _AppearUserRaiseSub + ret diff --git a/engine/battle/move_effects/attract.asm b/engine/battle/move_effects/attract.asm new file mode 100644 index 00000000..5eb82d65 --- /dev/null +++ b/engine/battle/move_effects/attract.asm @@ -0,0 +1,76 @@ +BattleCommand_Attract: +; attract + ld a, [wAttackMissed] + and a + jr nz, .failed + call CheckOppositeGender + jr c, .failed + call CheckHiddenOpponent + jr nz, .failed + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVarAddr + bit SUBSTATUS_IN_LOVE, [hl] + jr nz, .failed + + set SUBSTATUS_IN_LOVE, [hl] + call AnimateCurrentMove + +; 'fell in love!' + ld hl, FellInLoveText + jp StdBattleTextbox + +.failed + jp FailMove + +CheckOppositeGender: + ld a, MON_SPECIES + call BattlePartyAttr + ld a, [hl] + ld [wCurPartySpecies], a + + ld a, [wCurBattleMon] + ld [wCurPartyMon], a + xor a + ld [wMonType], a + + farcall GetGender + jr c, .genderless_samegender + + ld b, 1 + jr nz, .got_gender + dec b + +.got_gender + push bc + ld a, [wTempEnemyMonSpecies] + ld [wCurPartySpecies], a + ld hl, wEnemyMonDVs + ld a, [wEnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr z, .not_transformed + ld hl, wEnemyBackupDVs +.not_transformed + ld a, [hli] + ld [wTempMonDVs], a + ld a, [hl] + ld [wTempMonDVs + 1], a + ld a, 3 + ld [wMonType], a + farcall GetGender + pop bc + jr c, .genderless_samegender + + ld a, 1 + jr nz, .got_enemy_gender + dec a + +.got_enemy_gender + xor b + jr z, .genderless_samegender + + and a + ret + +.genderless_samegender + scf + ret diff --git a/engine/battle/move_effects/baton_pass.asm b/engine/battle/move_effects/baton_pass.asm new file mode 100644 index 00000000..bf9e3235 --- /dev/null +++ b/engine/battle/move_effects/baton_pass.asm @@ -0,0 +1,194 @@ +BattleCommand_BatonPass: +; batonpass + + ldh 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 LoadStandardMenuHeader + 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 + + 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 + +; Passed enemy PartyMon entrance + xor a + ld [wEnemySwitchMonIndex], a + ld hl, EnemySwitch_SetMode + call CallBattleCore + ld hl, ResetBattleParticipants + call CallBattleCore + ld a, TRUE + ld [wApplyStatLevelMultipliersToEnemy], a + ld hl, ApplyStatLevelMultiplierOnAllStats + call CallBattleCore + + ld hl, SpikesDamage + call CallBattleCore + + jr ResetBatonPassStatus + +BatonPass_LinkPlayerSwitch: + ld a, [wLinkMode] + and a + ret z + + ld a, BATTLEPLAYERACTION_USEITEM + ld [wBattlePlayerAction], a + + call LoadStandardMenuHeader + ld hl, LinkBattleSendReceiveAction + call CallBattleCore + call CloseWindow + + xor a ; BATTLEPLAYERACTION_USEMOVE + ld [wBattlePlayerAction], a + ret + +BatonPass_LinkEnemySwitch: + ld a, [wLinkMode] + and a + ret z + + call LoadStandardMenuHeader + ld hl, LinkBattleSendReceiveAction + call CallBattleCore + jp CloseWindow + +FailedBatonPass: + call AnimateFailedMove + jp PrintButItFailed + +ResetBatonPassStatus: +; 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, wPlayerSubStatus1 + res SUBSTATUS_IN_LOVE, [hl] + ld hl, wEnemySubStatus1 + res SUBSTATUS_IN_LOVE, [hl] + ld hl, wPlayerSubStatus5 + + 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 + +CheckAnyOtherAlivePartyMons: + ld hl, wPartyMon1HP + ld a, [wPartyCount] + ld d, a + ld a, [wCurBattleMon] + ld e, a + jr CheckAnyOtherAliveMons + +CheckAnyOtherAliveEnemyMons: + ld hl, wOTPartyMon1HP + ld a, [wOTPartyCount] + ld d, a + ld a, [wCurOTMon] + ld e, a + + ; fallthrough + +CheckAnyOtherAliveMons: +; 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 diff --git a/engine/battle/move_effects/belly_drum.asm b/engine/battle/move_effects/belly_drum.asm new file mode 100644 index 00000000..5b1361f2 --- /dev/null +++ b/engine/battle/move_effects/belly_drum.asm @@ -0,0 +1,30 @@ +BattleCommand_BellyDrum: +; 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, [wAttackMissed] + and a + jr nz, .failed + + callfar GetHalfMaxHP + callfar CheckUserHasEnoughHP + jr nc, .failed + + push bc + call AnimateCurrentMove + pop bc + callfar SubtractHPFromUser + call UpdateUserInParty + +rept 5 + call BattleCommand_AttackUp2 +endr + + ld hl, BellyDrumText + jp StdBattleTextbox + +.failed + call AnimateFailedMove + jp PrintButItFailed diff --git a/engine/battle/move_effects/bide.asm b/engine/battle/move_effects/bide.asm new file mode 100644 index 00000000..74f7c9cf --- /dev/null +++ b/engine/battle/move_effects/bide.asm @@ -0,0 +1,100 @@ +BattleCommand_StoreEnergy: +; storeenergy + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + bit SUBSTATUS_BIDE, a + ret z + + ld hl, wPlayerRolloutCount + ldh a, [hBattleTurn] + and a + jr z, .check_still_storing_energy + ld hl, wEnemyRolloutCount +.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, wPlayerDamageTaken + 1 + ld de, wPlayerCharging ; player + ldh a, [hBattleTurn] + and a + jr z, .player + ld hl, wEnemyDamageTaken + 1 + ld de, wEnemyCharging ; enemy +.player + ld a, [hld] + add a + ld b, a + ld [wCurDamage + 1], a + ld a, [hl] + rl a + ld [wCurDamage], a + jr nc, .not_maxed + ld a, $ff + ld [wCurDamage], a + ld [wCurDamage + 1], a +.not_maxed + or b + jr nz, .built_up_something + ld a, 1 + ld [wAttackMissed], 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 + +BattleCommand_UnleashEnergy: +; unleashenergy + + ld de, wPlayerDamageTaken + ld bc, wPlayerRolloutCount + ldh a, [hBattleTurn] + and a + jr z, .got_damage + ld de, wEnemyDamageTaken + ld bc, wEnemyRolloutCount +.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 diff --git a/engine/battle/move_effects/conversion.asm b/engine/battle/move_effects/conversion.asm new file mode 100644 index 00000000..b6081a6b --- /dev/null +++ b/engine/battle/move_effects/conversion.asm @@ -0,0 +1,96 @@ +BattleCommand_Conversion: +; conversion + + ld hl, wBattleMonMoves + ld de, wBattleMonType1 + ldh a, [hBattleTurn] + and a + jr z, .got_moves + ld hl, wEnemyMonMoves + ld de, wEnemyMonType1 +.got_moves + push de + ld c, 0 + ld de, wStringBuffer1 +.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, wStringBuffer1 +.loop2 + ld a, [hl] + cp -1 + jr z, .fail + cp CURSE_TYPE + 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 + maskbits NUM_MOVES + ld c, a + ld b, 0 + ld hl, wStringBuffer1 + add hl, bc + ld a, [hl] + cp -1 + jr z, .loop3 + cp CURSE_TYPE + 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 diff --git a/engine/battle/move_effects/curse.asm b/engine/battle/move_effects/curse.asm new file mode 100644 index 00000000..3507c668 --- /dev/null +++ b/engine/battle/move_effects/curse.asm @@ -0,0 +1,93 @@ +BattleCommand_Curse: +; curse + + ld de, wBattleMonType1 + ld bc, wPlayerStatLevels + ldh a, [hBattleTurn] + and a + jr z, .go + ld de, wEnemyMonType1 + ld bc, wEnemyStatLevels + +.go + +; Curse is different for Ghost-types. + + ld a, [de] + cp GHOST + jr z, .ghost + inc de + ld a, [de] + cp GHOST + jr z, .ghost + +; If no stats can be increased, don't. + +; Attack + ld a, [bc] + cp MAX_STAT_LEVEL + jr c, .raise + +; Defense + inc bc + ld a, [bc] + cp MAX_STAT_LEVEL + jr nc, .cantraise + +.raise + +; Raise Attack and Defense, and lower Speed. + + ld a, $1 + ld [wKickCounter], a + call AnimateCurrentMove + ld a, SPEED + call LowerStat + call BattleCommand_SwitchTurn + call BattleCommand_StatDownMessage + call ResetMiss + call BattleCommand_SwitchTurn + call BattleCommand_AttackUp + call BattleCommand_StatUpMessage + call ResetMiss + call BattleCommand_DefenseUp + jp BattleCommand_StatUpMessage + +.ghost + +; Cut HP in half and put a curse on the opponent. + + call CheckHiddenOpponent + jr nz, .failed + + call CheckSubstituteOpp + jr nz, .failed + + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVarAddr + bit SUBSTATUS_CURSE, [hl] + jr nz, .failed + + set SUBSTATUS_CURSE, [hl] + call AnimateCurrentMove + ld hl, GetHalfMaxHP + call CallBattleCore + ld hl, SubtractHPFromUser + call CallBattleCore + call UpdateUserInParty + ld hl, PutACurseText + jp StdBattleTextbox + +.failed + call AnimateFailedMove + jp PrintButItFailed + +.cantraise + +; Can't raise either stat. + + ld b, ABILITY + 1 + call GetStatName + call AnimateFailedMove + ld hl, WontRiseAnymoreText + jp StdBattleTextbox diff --git a/engine/battle/move_effects/disable.asm b/engine/battle/move_effects/disable.asm new file mode 100644 index 00000000..de6dbc60 --- /dev/null +++ b/engine/battle/move_effects/disable.asm @@ -0,0 +1,72 @@ +BattleCommand_Disable: +; disable + + ld a, [wAttackMissed] + and a + jr nz, .failed + + ld de, wEnemyDisableCount + ld hl, wEnemyMonMoves + ldh a, [hBattleTurn] + and a + jr z, .got_moves + ld de, wPlayerDisableCount + ld hl, wBattleMonMoves +.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 + + ldh a, [hBattleTurn] + and a + ld hl, wEnemyMonPP + jr z, .got_pp + ld hl, wBattleMonPP +.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, wDisabledMove + ldh 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 FailMove diff --git a/engine/battle/move_effects/endure.asm b/engine/battle/move_effects/endure.asm new file mode 100644 index 00000000..00ccb130 --- /dev/null +++ b/engine/battle/move_effects/endure.asm @@ -0,0 +1,16 @@ +BattleCommand_Endure: +; endure + +; Endure shares code with Protect. See protect.asm. + + call ProtectChance + ret c + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + set SUBSTATUS_ENDURE, [hl] + + call AnimateCurrentMove + + ld hl, BracedItselfText + jp StdBattleTextbox diff --git a/engine/battle/move_effects/focus_energy.asm b/engine/battle/move_effects/focus_energy.asm new file mode 100644 index 00000000..c4eb1f33 --- /dev/null +++ b/engine/battle/move_effects/focus_energy.asm @@ -0,0 +1,15 @@ +BattleCommand_FocusEnergy: +; 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 diff --git a/engine/battle/move_effects/foresight.asm b/engine/battle/move_effects/foresight.asm new file mode 100644 index 00000000..ff25b04e --- /dev/null +++ b/engine/battle/move_effects/foresight.asm @@ -0,0 +1,22 @@ +BattleCommand_Foresight: +; foresight + + ld a, [wAttackMissed] + and a + jr nz, .failed + + call CheckHiddenOpponent + jr nz, .failed + + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVarAddr + bit SUBSTATUS_IDENTIFIED, [hl] + jr nz, .failed + + set SUBSTATUS_IDENTIFIED, [hl] + call AnimateCurrentMove + ld hl, IdentifiedText + jp StdBattleTextbox + +.failed + jp FailMove diff --git a/engine/battle/move_effects/frustration.asm b/engine/battle/move_effects/frustration.asm new file mode 100644 index 00000000..b07942c7 --- /dev/null +++ b/engine/battle/move_effects/frustration.asm @@ -0,0 +1,27 @@ +BattleCommand_FrustrationPower: +; frustrationpower + + push bc + ld hl, wBattleMonHappiness + ldh a, [hBattleTurn] + and a + jr z, .got_happiness + ld hl, wEnemyMonHappiness +.got_happiness + ld a, $ff + sub [hl] + ldh [hMultiplicand + 2], a + xor a + ldh [hMultiplicand + 0], a + ldh [hMultiplicand + 1], a + ld a, 10 + ldh [hMultiplier], a + call Multiply + ld a, 25 + ldh [hDivisor], a + ld b, 4 + call Divide + ldh a, [hQuotient + 3] + ld d, a + pop bc + ret diff --git a/engine/battle/move_effects/fury_cutter.asm b/engine/battle/move_effects/fury_cutter.asm new file mode 100644 index 00000000..a1284849 --- /dev/null +++ b/engine/battle/move_effects/fury_cutter.asm @@ -0,0 +1,55 @@ +BattleCommand_FuryCutter: +; furycutter + + ld hl, wPlayerFuryCutterCount + ldh a, [hBattleTurn] + and a + jr z, .go + ld hl, wEnemyFuryCutterCount + +.go + ld a, [wAttackMissed] + 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, wCurDamage + 1 + sla [hl] + dec hl + rl [hl] + jr nc, .checkdouble + +; No overflow + ld a, $ff + ld [hli], a + ld [hl], a + ret + +ResetFuryCutterCount: + push hl + + ld hl, wPlayerFuryCutterCount + ldh a, [hBattleTurn] + and a + jr z, .reset + ld hl, wEnemyFuryCutterCount + +.reset + xor a + ld [hl], a + + pop hl + ret diff --git a/engine/battle/move_effects/future_sight.asm b/engine/battle/move_effects/future_sight.asm new file mode 100644 index 00000000..129a9e08 --- /dev/null +++ b/engine/battle/move_effects/future_sight.asm @@ -0,0 +1,81 @@ +BattleCommand_CheckFutureSight: +; checkfuturesight + + ld hl, wPlayerFutureSightCount + ld de, wPlayerFutureSightDamage + ldh 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 [wCurDamage], a + ld a, [de] + ld [wCurDamage + 1], a + ld b, futuresight_command + jp SkipToBattleCommand + +BattleCommand_FutureSight: +; 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 + ldh 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 + ldh a, [hBattleTurn] + and a + jr z, .StoreDamage + ld de, wEnemyFutureSightDamage +.StoreDamage: + ld hl, wCurDamage + 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 diff --git a/engine/battle/move_effects/hidden_power.asm b/engine/battle/move_effects/hidden_power.asm new file mode 100644 index 00000000..3b40a6c3 --- /dev/null +++ b/engine/battle/move_effects/hidden_power.asm @@ -0,0 +1,8 @@ +BattleCommand_HiddenPower: +; hiddenpower + + ld a, [wAttackMissed] + and a + ret nz + farcall HiddenPowerDamage + ret diff --git a/engine/battle/move_effects/leech_seed.asm b/engine/battle/move_effects/leech_seed.asm new file mode 100644 index 00000000..bb17ee00 --- /dev/null +++ b/engine/battle/move_effects/leech_seed.asm @@ -0,0 +1,40 @@ +BattleCommand_LeechSeed: +; leechseed + ld a, [wAttackMissed] + and a + jr nz, .evaded + call CheckSubstituteOpp + jr nz, .evaded + + ld de, wEnemyMonType1 + ldh a, [hBattleTurn] + and a + jr z, .ok + ld de, wBattleMonType1 +.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 diff --git a/engine/battle/move_effects/magnitude.asm b/engine/battle/move_effects/magnitude.asm new file mode 100644 index 00000000..f8961b66 --- /dev/null +++ b/engine/battle/move_effects/magnitude.asm @@ -0,0 +1,29 @@ +BattleCommand_GetMagnitude: +; getmagnitude + + push bc + call BattleRandom + ld b, a + ld hl, MagnitudePower +.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 [wDeciramBuffer], a + call BattleCommand_MoveDelay + ld hl, MagnitudeText + call StdBattleTextbox + pop de + pop bc + ret + +INCLUDE "data/moves/magnitude_power.asm" diff --git a/engine/battle/move_effects/metronome.asm b/engine/battle/move_effects/metronome.asm new file mode 100644 index 00000000..25197d7c --- /dev/null +++ b/engine/battle/move_effects/metronome.asm @@ -0,0 +1,43 @@ +BattleCommand_Metronome: +; metronome + + call ClearLastMove + call CheckUserIsCharging + jr nz, .asm_3742b + + ld a, [wKickCounter] + push af + call BattleCommand_LowerSub + pop af + ld [wKickCounter], a + +.asm_3742b + call LoadMoveAnim + +.GetMove: + call BattleRandom + +; No invalid moves. + cp NUM_ATTACKS + 1 + jr nc, .GetMove + +; None of the moves in MetronomeExcepts. + push af + ld de, 1 + ld hl, MetronomeExcepts + call IsInArray + pop bc + jr c, .GetMove + +; No moves the user already has. + ld a, b + call CheckUserMove + jr z, .GetMove + + ld a, BATTLE_VARS_MOVE + call GetBattleVarAddr + ld [hl], b + call UpdateMoveData + jp ResetTurn + +INCLUDE "data/moves/metronome_exception_moves.asm" diff --git a/engine/battle/move_effects/mimic.asm b/engine/battle/move_effects/mimic.asm new file mode 100644 index 00000000..71eb72c6 --- /dev/null +++ b/engine/battle/move_effects/mimic.asm @@ -0,0 +1,50 @@ +BattleCommand_Mimic: +; mimic + + call ClearLastMove + call BattleCommand_MoveDelay + ld a, [wAttackMissed] + and a + jr nz, .fail + ld hl, wBattleMonMoves + ldh a, [hBattleTurn] + and a + jr z, .player_turn + ld hl, wEnemyMonMoves +.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, wBattleMonPP - wBattleMonMoves + add hl, bc + ld [hl], 5 + call GetMoveName + call AnimateCurrentMove + ld hl, MimicLearnedMoveText + jp StdBattleTextbox + +.fail + jp FailMimic diff --git a/engine/battle/move_effects/mirror_coat.asm b/engine/battle/move_effects/mirror_coat.asm new file mode 100644 index 00000000..96afa317 --- /dev/null +++ b/engine/battle/move_effects/mirror_coat.asm @@ -0,0 +1,60 @@ +BattleCommand_MirrorCoat: +; mirrorcoat + + ld a, 1 + ld [wAttackMissed], 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, wStringBuffer1 + call GetMoveData + + ld a, [wStringBuffer1 + MOVE_POWER] + and a + ret z + + ld a, [wStringBuffer1 + MOVE_TYPE] + cp SPECIAL + ret c + + ; BUG: Move should fail with all non-damaging battle actions + ld hl, wCurDamage + 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 [wAttackMissed], a + ret diff --git a/engine/battle/move_effects/mirror_move.asm b/engine/battle/move_effects/mirror_move.asm new file mode 100644 index 00000000..98e8aacc --- /dev/null +++ b/engine/battle/move_effects/mirror_move.asm @@ -0,0 +1,51 @@ +BattleCommand_MirrorMove: +; mirrormove + + call ClearLastMove + + ld a, BATTLE_VARS_MOVE + call GetBattleVarAddr + + ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP + call GetBattleVar + and a + jr z, .failed + + call CheckUserMove + jr nz, .use + +.failed + call AnimateFailedMove + + ld hl, MirrorMoveFailedText + call StdBattleTextbox + jp EndMoveEffect + +.use + ld a, b + ld [hl], a + ld [wNamedObjectIndexBuffer], a + + push af + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVarAddr + ld d, h + ld e, l + pop af + + dec a + call GetMoveData + call GetMoveName + call CopyName1 + call CheckUserIsCharging + jr nz, .done + + ld a, [wKickCounter] + push af + call BattleCommand_LowerSub + pop af + ld [wKickCounter], a + +.done + call BattleCommand_MoveDelay + jp ResetTurn diff --git a/engine/battle/move_effects/mist.asm b/engine/battle/move_effects/mist.asm new file mode 100644 index 00000000..26fafdd2 --- /dev/null +++ b/engine/battle/move_effects/mist.asm @@ -0,0 +1,15 @@ +BattleCommand_Mist: +; 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 diff --git a/engine/battle/move_effects/nightmare.asm b/engine/battle/move_effects/nightmare.asm new file mode 100644 index 00000000..9354b15b --- /dev/null +++ b/engine/battle/move_effects/nightmare.asm @@ -0,0 +1,37 @@ +BattleCommand_Nightmare: +; nightmare + +; Can't hit an absent opponent. + + call CheckHiddenOpponent + jr nz, .failed + +; Can't hit a substitute. + + call CheckSubstituteOpp + jr nz, .failed + +; Only works on a sleeping opponent. + + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and SLP + jr z, .failed + +; Bail if the opponent is already having a nightmare. + + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVarAddr + bit SUBSTATUS_NIGHTMARE, [hl] + jr nz, .failed + +; Otherwise give the opponent a nightmare. + + set SUBSTATUS_NIGHTMARE, [hl] + call AnimateCurrentMove + ld hl, StartedNightmareText + jp StdBattleTextbox + +.failed + call AnimateFailedMove + jp PrintButItFailed diff --git a/engine/battle/move_effects/pay_day.asm b/engine/battle/move_effects/pay_day.asm new file mode 100644 index 00000000..5f857aea --- /dev/null +++ b/engine/battle/move_effects/pay_day.asm @@ -0,0 +1,26 @@ +BattleCommand_PayDay: +; payday + + xor a + ld hl, wStringBuffer1 + ld [hli], a + + ldh a, [hBattleTurn] + and a + ld a, [wBattleMonLevel] + jr z, .ok + ld a, [wEnemyMonLevel] +.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 diff --git a/engine/battle/move_effects/perish_song.asm b/engine/battle/move_effects/perish_song.asm new file mode 100644 index 00000000..1758b65a --- /dev/null +++ b/engine/battle/move_effects/perish_song.asm @@ -0,0 +1,38 @@ +BattleCommand_PerishSong: +; perishsong + + ld hl, wPlayerSubStatus1 + ld de, wEnemySubStatus1 + bit SUBSTATUS_PERISH, [hl] + jr z, .ok + + ld a, [de] + bit SUBSTATUS_PERISH, a + jr nz, .failed + +.ok + bit SUBSTATUS_PERISH, [hl] + jr nz, .enemy + + set SUBSTATUS_PERISH, [hl] + ld a, 4 + ld [wPlayerPerishCount], a + +.enemy + ld a, [de] + bit SUBSTATUS_PERISH, a + jr nz, .done + + set SUBSTATUS_PERISH, a + ld [de], a + ld a, 4 + ld [wEnemyPerishCount], a + +.done + call AnimateCurrentMove + ld hl, StartPerishText + jp StdBattleTextbox + +.failed + call AnimateFailedMove + jp PrintButItFailed diff --git a/engine/battle/move_effects/present.asm b/engine/battle/move_effects/present.asm new file mode 100644 index 00000000..360a4172 --- /dev/null +++ b/engine/battle/move_effects/present.asm @@ -0,0 +1,75 @@ +BattleCommand_Present: +; present + + call BattleCommand_Stab + ld a, [wTypeMatchup] + and a + jp z, AnimateFailedMove + ld a, [wAttackMissed] + and a + jp nz, AnimateFailedMove + + push bc + call BattleRandom + ld b, a + ld hl, PresentPower + ld c, 0 +.next + ld a, [hli] + cp -1 + jr z, .heal_effect + cp b + jr nc, .got_power + inc c + inc hl + jr .next + +.got_power + ld a, c + ld [wPresentPower], a + call AnimateCurrentMoveEitherSide + ld d, [hl] + pop bc + ret + +.heal_effect + pop bc + ld a, 3 + ld [wPresentPower], a + call AnimateCurrentMove + call BattleCommand_SwitchTurn + ld hl, AICheckPlayerMaxHP + ldh a, [hBattleTurn] + and a + jr z, .got_hp_fn_pointer + ld hl, AICheckEnemyMaxHP +.got_hp_fn_pointer + ld a, BANK(AICheckPlayerMaxHP) ; aka BANK(AICheckEnemyMaxHP) + rst FarCall + jr c, .already_fully_healed + + ld hl, GetQuarterMaxHP + call CallBattleCore + call BattleCommand_SwitchTurn + ld hl, RestoreHP + call CallBattleCore + call BattleCommand_SwitchTurn + ld hl, RegainedHealthText + call StdBattleTextbox + call BattleCommand_SwitchTurn + call UpdateOpponentInParty + jr .do_animation + +.already_fully_healed + call BattleCommand_SwitchTurn + ; check battle scene + ld a, [wOptions] + add a + jr nc, .do_animation + call AnimateFailedMove + ld hl, CantReceiveGiftText + call StdBattleTextbox +.do_animation + jp EndMoveEffect + +INCLUDE "data/moves/present_power.asm" diff --git a/engine/battle/move_effects/protect.asm b/engine/battle/move_effects/protect.asm new file mode 100644 index 00000000..e66bce44 --- /dev/null +++ b/engine/battle/move_effects/protect.asm @@ -0,0 +1,75 @@ +BattleCommand_Protect: +; protect + call ProtectChance + ret c + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + set SUBSTATUS_PROTECT, [hl] + + call AnimateCurrentMove + + ld hl, ProtectedItselfText + jp StdBattleTextbox + +ProtectChance: + ld de, wPlayerProtectCount + ldh a, [hBattleTurn] + and a + jr z, .asm_37637 + ld de, wEnemyProtectCount +.asm_37637 + + call CheckOpponentWentFirst + jr nz, .failed + +; Can't have a substitute. + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + jr nz, .failed + +; Halve the chance of a successful Protect for each consecutive use. + + ld b, $ff + ld a, [de] + ld c, a +.loop + ld a, c + and a + jr z, .done + dec c + + srl b + ld a, b + and a + jr nz, .loop + jr .failed +.done + +.rand + call BattleRandom + and a + jr z, .rand + + dec a + cp b + jr nc, .failed + +; Another consecutive Protect use. + + ld a, [de] + inc a + ld [de], a + + and a + ret + +.failed + xor a + ld [de], a + call AnimateFailedMove + call PrintButItFailed + scf + ret diff --git a/engine/battle/move_effects/psych_up.asm b/engine/battle/move_effects/psych_up.asm new file mode 100644 index 00000000..3473b9db --- /dev/null +++ b/engine/battle/move_effects/psych_up.asm @@ -0,0 +1,47 @@ +BattleCommand_PsychUp: +; psychup + + ld hl, wEnemyStatLevels + ld de, wPlayerStatLevels + ldh a, [hBattleTurn] + and a + jr z, .pointers_correct +; It's the enemy's turn, so swap the pointers. + ld hl, wPlayerStatLevels + ld de, wEnemyStatLevels +.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 + ldh 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 diff --git a/engine/battle/move_effects/pursuit.asm b/engine/battle/move_effects/pursuit.asm new file mode 100644 index 00000000..f8979fb9 --- /dev/null +++ b/engine/battle/move_effects/pursuit.asm @@ -0,0 +1,24 @@ +BattleCommand_Pursuit: +; pursuit +; Double damage if the opponent is switching. + + ld hl, wEnemyIsSwitching + ldh a, [hBattleTurn] + and a + jr z, .ok + ld hl, wPlayerIsSwitching +.ok + ld a, [hl] + and a + ret z + + ld hl, wCurDamage + 1 + sla [hl] + dec hl + rl [hl] + ret nc + + ld a, $ff + ld [hli], a + ld [hl], a + ret diff --git a/engine/battle/move_effects/rage.asm b/engine/battle/move_effects/rage.asm new file mode 100644 index 00000000..df206a6b --- /dev/null +++ b/engine/battle/move_effects/rage.asm @@ -0,0 +1,6 @@ +BattleCommand_Rage: +; rage + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + set SUBSTATUS_RAGE, [hl] + ret diff --git a/engine/battle/move_effects/rain_dance.asm b/engine/battle/move_effects/rain_dance.asm new file mode 100644 index 00000000..c22fb9fd --- /dev/null +++ b/engine/battle/move_effects/rain_dance.asm @@ -0,0 +1,9 @@ +BattleCommand_StartRain: +; startrain + ld a, WEATHER_RAIN + ld [wBattleWeather], a + ld a, 5 + ld [wWeatherCount], a + call AnimateCurrentMove + ld hl, DownpourText + jp StdBattleTextbox diff --git a/engine/battle/move_effects/rapid_spin.asm b/engine/battle/move_effects/rapid_spin.asm new file mode 100644 index 00000000..eb396a35 --- /dev/null +++ b/engine/battle/move_effects/rapid_spin.asm @@ -0,0 +1,36 @@ +BattleCommand_ClearHazards: +; 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, wPlayerScreens + ld de, wPlayerWrapCount + ldh a, [hBattleTurn] + and a + jr z, .got_screens_wrap + ld hl, wEnemyScreens + 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 diff --git a/engine/battle/move_effects/return.asm b/engine/battle/move_effects/return.asm new file mode 100644 index 00000000..7c7c5fcb --- /dev/null +++ b/engine/battle/move_effects/return.asm @@ -0,0 +1,25 @@ +BattleCommand_HappinessPower: +; happinesspower + push bc + ld hl, wBattleMonHappiness + ldh a, [hBattleTurn] + and a + jr z, .ok + ld hl, wEnemyMonHappiness +.ok + xor a + ldh [hMultiplicand + 0], a + ldh [hMultiplicand + 1], a + ld a, [hl] + ldh [hMultiplicand + 2], a + ld a, 10 + ldh [hMultiplier], a + call Multiply + ld a, 25 + ldh [hDivisor], a + ld b, 4 + call Divide + ldh a, [hQuotient + 3] + ld d, a + pop bc + ret diff --git a/engine/battle/move_effects/rollout.asm b/engine/battle/move_effects/rollout.asm new file mode 100644 index 00000000..e2f810e6 --- /dev/null +++ b/engine/battle/move_effects/rollout.asm @@ -0,0 +1,95 @@ +MAX_ROLLOUT_COUNT EQU 5 + +BattleCommand_CheckCurl: +; checkcurl + + ld de, wPlayerRolloutCount + ldh a, [hBattleTurn] + and a + jr z, .ok + ld de, wEnemyRolloutCount +.ok + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVar + bit SUBSTATUS_ROLLOUT, a + jr z, .reset + + ld b, $4 ; doturn + jp SkipToBattleCommand + +.reset + xor a + ld [de], a + ret + +BattleCommand_RolloutPower: +; rolloutpower + + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and SLP + ret nz + + ld hl, wPlayerRolloutCount + ldh a, [hBattleTurn] + and a + jr z, .got_rollout_count + ld hl, wEnemyRolloutCount + +.got_rollout_count + ld a, [hl] + and a + jr nz, .skip_set_rampage + ld a, 1 + ld [wSomeoneIsRampaging], a + +.skip_set_rampage + ld a, [wAttackMissed] + and a + jr z, .hit + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + res 6, [hl] + ret + +.hit + inc [hl] + ld a, [hl] + ld b, a + cp MAX_ROLLOUT_COUNT + jr c, .not_done_with_rollout + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + res SUBSTATUS_ROLLOUT, [hl] + jr .done_with_substatus_flag + +.not_done_with_rollout + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + set SUBSTATUS_ROLLOUT, [hl] + +.done_with_substatus_flag + ld a, BATTLE_VARS_SUBSTATUS2 + call GetBattleVar + bit SUBSTATUS_CURLED, a + jr z, .not_curled + inc b +.not_curled +.loop + dec b + jr z, .done_damage + + ld hl, wCurDamage + 1 + sla [hl] + dec hl + rl [hl] + jr nc, .loop + + ld a, $ff + ld [hli], a + ld [hl], a + +.done_damage + ret diff --git a/engine/battle/move_effects/safeguard.asm b/engine/battle/move_effects/safeguard.asm new file mode 100644 index 00000000..e64e8092 --- /dev/null +++ b/engine/battle/move_effects/safeguard.asm @@ -0,0 +1,23 @@ +BattleCommand_Safeguard: +; safeguard + + ld hl, wPlayerScreens + ld de, wPlayerSafeguardCount + ldh a, [hBattleTurn] + and a + jr z, .ok + ld hl, wEnemyScreens + ld de, wEnemySafeguardCount +.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 diff --git a/engine/battle/move_effects/sandstorm.asm b/engine/battle/move_effects/sandstorm.asm new file mode 100644 index 00000000..c88529fb --- /dev/null +++ b/engine/battle/move_effects/sandstorm.asm @@ -0,0 +1,18 @@ +BattleCommand_StartSandstorm: +; startsandstorm + + ld a, [wBattleWeather] + cp WEATHER_SANDSTORM + jr z, .failed + + ld a, WEATHER_SANDSTORM + ld [wBattleWeather], a + ld a, 5 + ld [wWeatherCount], a + call AnimateCurrentMove + ld hl, SandstormBrewedText + jp StdBattleTextbox + +.failed + call AnimateFailedMove + jp PrintButItFailed diff --git a/engine/battle/move_effects/selfdestruct.asm b/engine/battle/move_effects/selfdestruct.asm new file mode 100644 index 00000000..b4967b03 --- /dev/null +++ b/engine/battle/move_effects/selfdestruct.asm @@ -0,0 +1,30 @@ +BattleCommand_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] + ; check battle scene + ld a, [wOptions] + add a + ret nc + farcall DrawPlayerHUD + farcall DrawEnemyHUD + call WaitBGMap + jp RefreshBattleHuds diff --git a/engine/battle/move_effects/spikes.asm b/engine/battle/move_effects/spikes.asm new file mode 100644 index 00000000..96163a68 --- /dev/null +++ b/engine/battle/move_effects/spikes.asm @@ -0,0 +1,26 @@ +BattleCommand_Spikes: +; spikes + + ld hl, wEnemyScreens + ldh a, [hBattleTurn] + and a + jr z, .asm_3768e + ld hl, wPlayerScreens +.asm_3768e + +; Fails if spikes are already down! + + bit SCREENS_SPIKES, [hl] + jr nz, .failed + +; Nothing else stops it from working. + + set SCREENS_SPIKES, [hl] + + call AnimateCurrentMove + + ld hl, SpikesText + jp StdBattleTextbox + +.failed + jp FailMove diff --git a/engine/battle/move_effects/splash.asm b/engine/battle/move_effects/splash.asm new file mode 100644 index 00000000..1be307f8 --- /dev/null +++ b/engine/battle/move_effects/splash.asm @@ -0,0 +1,3 @@ +BattleCommand_Splash: + call AnimateCurrentMove + jp PrintNothingHappened diff --git a/engine/battle/move_effects/substitute.asm b/engine/battle/move_effects/substitute.asm new file mode 100644 index 00000000..c5ab8741 --- /dev/null +++ b/engine/battle/move_effects/substitute.asm @@ -0,0 +1,90 @@ +BattleCommand_Substitute: +; substitute + + call BattleCommand_MoveDelay + ld hl, wBattleMonMaxHP + ld de, wPlayerSubstituteHP + ldh a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, wEnemyMonMaxHP + ld de, wEnemySubstituteHP +.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 + ldh a, [hBattleTurn] + and a + jr z, .player + ld hl, wEnemyWrapCount + ld de, wEnemyTrappingMove +.player + + xor a + ld [hl], a + ld [de], a + ; check battle scene + ld a, [wOptions] + add a + jr c, .no_anim + + xor a + ld [wNumHits], a + ld [wFXAnimID + 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 diff --git a/engine/battle/move_effects/sunny_day.asm b/engine/battle/move_effects/sunny_day.asm new file mode 100644 index 00000000..0edc38e4 --- /dev/null +++ b/engine/battle/move_effects/sunny_day.asm @@ -0,0 +1,9 @@ +BattleCommand_StartSun: +; startsun + ld a, WEATHER_SUN + ld [wBattleWeather], a + ld a, 5 + ld [wWeatherCount], a + call AnimateCurrentMove + ld hl, SunGotBrightText + jp StdBattleTextbox diff --git a/engine/battle/move_effects/teleport.asm b/engine/battle/move_effects/teleport.asm new file mode 100644 index 00000000..7d866ccf --- /dev/null +++ b/engine/battle/move_effects/teleport.asm @@ -0,0 +1,87 @@ +BattleCommand_Teleport: +; teleport + + ld a, [wBattleType] + cp BATTLETYPE_SHINY + jr z, .failed + cp BATTLETYPE_TRAP + 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 + ldh 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, [wCurPartyLevel] + ld b, a + ld a, [wBattleMonLevel] + 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, [wBattleMonLevel] + ld b, a + ld a, [wCurPartyLevel] + 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 should be jr c, .failed + ; As written, it 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 + ; set battle draw + inc a + ld [wBattleResult], a + ld a, 1 + ld [wKickCounter], a + call BattleCommand_LowerSub + call LoadMoveAnim + ld c, 20 + call DelayFrames + ld a, DRAW + ld [wBattleResult], a + + ld hl, FledFromBattleText + jp StdBattleTextbox diff --git a/engine/battle/move_effects/thief.asm b/engine/battle/move_effects/thief.asm new file mode 100644 index 00000000..e588c5ff --- /dev/null +++ b/engine/battle/move_effects/thief.asm @@ -0,0 +1,112 @@ +BattleCommand_Thief: +; thief + + ldh a, [hBattleTurn] + and a + jr nz, .enemy + +; The player needs to be able to steal an item. + + call .playeritem + ld a, [hl] + and a + ret nz + +; The enemy needs to have an item to steal. + + call .enemyitem + ld a, [hl] + and a + ret z + +; Can't steal mail. + + ld [wNamedObjectIndexBuffer], a + ld d, a + farcall ItemIsMail + ret c + + ld a, [wEffectFailed] + and a + ret nz + + ld a, [wLinkMode] + and a + jr z, .stealenemyitem + + ld a, [wBattleMode] + dec a + ret z + +.stealenemyitem + call .enemyitem + xor a + ld [hl], a + ld [de], a + + call .playeritem + ld a, [wNamedObjectIndexBuffer] + ld [hl], a + ld [de], a + jr .stole + +.enemy + +; The enemy can't already have an item. + + call .enemyitem + ld a, [hl] + and a + ret nz + +; The player must have an item to steal. + + call .playeritem + ld a, [hl] + and a + ret z + +; Can't steal mail! + + ld [wNamedObjectIndexBuffer], a + ld d, a + farcall ItemIsMail + ret c + + ld a, [wEffectFailed] + and a + ret nz + +; If the enemy steals your item, +; it's gone for good if you don't get it back. + + call .playeritem + xor a + ld [hl], a + ld [de], a + + call .enemyitem + ld a, [wNamedObjectIndexBuffer] + ld [hl], a + ld [de], a + +.stole + call GetItemName + ld hl, StoleText + jp StdBattleTextbox + +.playeritem + ld a, 1 + call BattlePartyAttr + ld d, h + ld e, l + ld hl, wBattleMonItem + ret + +.enemyitem + ld a, 1 + call OTPartyAttr + ld d, h + ld e, l + ld hl, wEnemyMonItem + ret diff --git a/engine/battle/move_effects/thunder.asm b/engine/battle/move_effects/thunder.asm new file mode 100644 index 00000000..b2a64378 --- /dev/null +++ b/engine/battle/move_effects/thunder.asm @@ -0,0 +1,18 @@ +BattleCommand_ThunderAccuracy: +; thunderaccuracy + + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVarAddr + inc hl + ld a, [wBattleWeather] + 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 diff --git a/engine/battle/move_effects/transform.asm b/engine/battle/move_effects/transform.asm new file mode 100644 index 00000000..0247d8bb --- /dev/null +++ b/engine/battle/move_effects/transform.asm @@ -0,0 +1,155 @@ +BattleCommand_Transform: +; transform + + call ClearLastMove + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + bit SUBSTATUS_TRANSFORMED, [hl] + jp nz, BattleEffect_ButItFailed + call CheckHiddenOpponent + jp nz, BattleEffect_ButItFailed + xor a + ld [wNumHits], a + ld [wFXAnimID + 1], a + ld a, $1 + ld [wKickCounter], a + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + bit SUBSTATUS_SUBSTITUTE, [hl] + push af + jr z, .mimic_substitute + call CheckUserIsCharging + jr nz, .mimic_substitute + ld a, SUBSTITUTE + call LoadAnim +.mimic_substitute + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVarAddr + set SUBSTATUS_TRANSFORMED, [hl] + call ResetActorDisable + ld hl, wBattleMonSpecies + ld de, wEnemyMonSpecies + ldh a, [hBattleTurn] + and a + jr nz, .got_mon_species + ld hl, wEnemyMonSpecies + ld de, wBattleMonSpecies + xor a + ld [wCurMoveNum], a +.got_mon_species + push hl + ld a, [hli] + ld [de], a + inc hl + inc de + inc de + ld bc, NUM_MOVES + call CopyBytes + ldh a, [hBattleTurn] + and a + jr z, .mimic_enemy_backup + ld a, [de] + ld [wEnemyBackupDVs], a + inc de + ld a, [de] + ld [wEnemyBackupDVs + 1], a + dec de +.mimic_enemy_backup +; copy DVs + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + inc de +; move pointer to stats + ld bc, wBattleMonStats - wBattleMonPP + add hl, bc + push hl + ld h, d + ld l, e + add hl, bc + ld d, h + ld e, l + pop hl + ld bc, wBattleMonStructEnd - wBattleMonStats + call CopyBytes +; init the power points + ld bc, wBattleMonMoves - wBattleMonStructEnd + add hl, bc + push de + ld d, h + ld e, l + pop hl + ld bc, wBattleMonPP - wBattleMonStructEnd + add hl, bc + ld b, NUM_MOVES +.pp_loop + ld a, [de] + inc de + and a + jr z, .done_move + cp SKETCH + ld a, 1 + jr z, .done_move + ld a, 5 +.done_move + ld [hli], a + dec b + jr nz, .pp_loop + pop hl + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetPokemonName + ld hl, wEnemyStats + ld de, wPlayerStats + ld bc, 2 * 5 + call BattleSideCopy + ld hl, wEnemyStatLevels + ld de, wPlayerStatLevels + ld bc, 8 + call BattleSideCopy + ; check battle scene + ld a, [wOptions] + add a + jr c, .mimic_anims + ldh a, [hBattleTurn] + and a + ld a, [wPlayerMinimized] + jr z, .got_byte + ld a, [wEnemyMinimized] +.got_byte + and a + jr nz, .mimic_anims + call LoadMoveAnim + jr .after_anim + +.mimic_anims + call BattleCommand_MoveDelay + call BattleCommand_RaiseSubNoAnim +.after_anim + xor a + ld [wNumHits], a + ld [wFXAnimID + 1], a + ld a, $2 + ld [wKickCounter], a + pop af + ld a, SUBSTITUTE + call nz, LoadAnim + ld hl, TransformedText + jp StdBattleTextbox + +BattleSideCopy: +; 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. + ldh a, [hBattleTurn] + and a + jr z, .copy + +; Swap hl and de + push hl + ld h, d + ld l, e + pop de +.copy + jp CopyBytes diff --git a/engine/items/item_effects.asm b/engine/items/item_effects.asm index 46713dfe..bf35d84e 100755 --- a/engine/items/item_effects.asm +++ b/engine/items/item_effects.asm @@ -443,7 +443,7 @@ UltraBall: ; e926 .not_ditto set SUBSTATUS_TRANSFORMED, [hl] - ld hl, wcbd0 + ld hl, wEnemyBackupDVs ld a, [wEnemyMonDVs] ld [hli], a ld a, [wEnemyMonMovesEnd + 1] @@ -1975,7 +1975,7 @@ PokeDoll: ; f4e5 (3:74e5) dec a jr nz, .asm_f4f6 inc a - ld [wd11c], a + ld [wForcedSwitch], a inc a ld [wBattleResult], a jp Functionf7d0 @@ -280,85 +280,6 @@ SECTION "Effect Commands", ROMX INCLUDE "engine/battle/effect_commands.asm" -UpdateMoveData: - dr $35f7c, $36201 - -Defrost: - dr $36201, $36308 -BattleCommand_StatUp: - dr $36308, $36313 -RaiseStat: - dr $36313, $364d7 -BattleCommand_StatUpMessage: - dr $364d7, $3656b -BattleCommand_StatUpFailText: - dr $3656b, $366ce -BattleCommand_RaiseSubNoAnim: - dr $366ce, $366e2 -BattleCommand_LowerSubNoAnim: - dr $366e2, $366f6 -CalcPlayerStats: - dr $366f6, $3671c -CalcEnemyStats: - dr $3671c, $36bcd -CheckOpponentWentFirst: - dr $36bcd, $373dc - -ClearLastMove: - dr $373dc, $37441 -PrintDoesntAffect: - dr $37441, $37447 -PrintNothingHappened: - dr $37447, $3744d -TryPrintButItFailed: - dr $3744d, $37452 -PrintButItFailed: - dr $37452, $37458 -FailMove: - dr $37458, $37464 -PrintDidntAffect: - dr $37464, $3746a -PrintDidntAffect2: - dr $3746a, $3747c -CheckSubstituteOpp: - dr $3747c, $3757a -ResetTurn: - dr $3757a, $378bd -ResetFuryCutterCount: - dr $378bd, $378f4 -CheckOppositeGender: - dr $378f4, $37e7d -GetUserItem: - dr $37e7d, $37e8c -GetOpponentItem: - dr $37e8c, $37e9b -GetItemHeldEffect: - dr $37e9b, $37ecc -AnimateCurrentMove: - dr $37ecc, $37f01 -LoadMoveAnim: - dr $37f01, $37f0f -LoadAnim: - dr $37f0f, $37f3e -CallBattleCore: - dr $37f3e, $37f42 -AnimateFailedMove: - dr $37f42, $37f4b -BattleCommand_MoveDelay: - dr $37f4b, $37f57 -SkipToBattleCommand: - dr $37f57, $37f6c -GetMoveAttr: - dr $37f6c, $37f78 -GetMoveData: - dr $37f78, $37f86 -GetMoveByte: - dr $37f86, $37f92 -AppearUserLowerSub: - dr $37f92, $37f99 -AppearUserRaiseSub: - dr $37f99, $37fa0 - SECTION "Enemy Trainers", ROMX @@ -373,10 +294,32 @@ SECTION "Battle Core", ROMX FleeMons:: dr $3c551, $3c5a4 GetMoveEffect: - dr $3c5a4, $3d39f - + dr $3c5a4, $3cbe7 +SubtractHPFromUser: + dr $3cbe7, $3cc2b +GetEighthMaxHP: + dr $3cc2b, $3cc36 +GetQuarterMaxHP: + dr $3cc36, $3cc47 +GetHalfMaxHP: + dr $3cc47, $3cc54 +GetMaxHP: + dr $3cc54, $3cc86 +CheckUserHasEnoughHP: + dr $3cc86, $3cc97 +RestoreHP: + dr $3cc97, $3d224 + +SetUpBattlePartyMenu_NoLoop: + dr $3d224, $3d28f +ForcePickSwitchMonInBattle: + dr $3d28f, $3d381 +ForceEnemySwitch: + dr $3d381, $3d39f EnemySwitch: - dr $3d39f, $3d438 + dr $3d39f, $3d3d5 +EnemySwitch_SetMode: + dr $3d3d5, $3d438 ResetBattleParticipants: dr $3d438, $3d6cb NewEnemyMonStatus: @@ -388,27 +331,57 @@ CheckPlayerPartyForFitMon:: Function3d8f5: dr $3d8f5, $3d907 Function3d907: - dr $3d907, $3dabc + dr $3d907, $3d9a2 +SwitchPlayerMon: + dr $3d9a2, $3da84 +SpikesDamage: + dr $3da84, $3dabc PursuitSwitch: - dr $3dabc, $3dda9 + dr $3dabc, $3dc4a +UseHeldStatusHealingItem: + dr $3dc4a, $3dcb2 +UseConfusionHealingItem: + dr $3dcb2, $3dda9 UpdatePlayerHUD:: - dr $3dda9, $3de97 + dr $3dda9, $3ddb9 +DrawPlayerHUD: + dr $3ddb9, $3de97 UpdateEnemyHUD:: - dr $3de97, $3e6e8 + dr $3de97, $3dea4 +DrawEnemyHUD: + dr $3dea4, $3e290 +PassedBattleMonEntrance: + dr $3e290, $3e6e8 CheckEnemyLockedIn:: - dr $3e6e8, $3e74b + dr $3e6e8, $3e6fb +LinkBattleSendReceiveAction: + dr $3e6fb, $3e74b LoadEnemyMon: - dr $3e74b, $3ec11 + dr $3e74b, $3ea77 +ApplyPrzEffectOnSpeed: + dr $3ea77, $3eab4 +ApplyBrnEffectOnAttack: + dr $3eab4, $3eae9 +ApplyStatLevelMultiplierOnAllStats: + dr $3eae9, $3eb83 +BadgeStatBoosts: + dr $3eb83, $3ebd8 +_LoadBattleFontsHPBar: + dr $3ebd8, $3ec11 _BattleRandom:: dr $3ec11, $3f196 FillInExpBar:: dr $3f196, $3f243 GetBattleMonBackpic:: - dr $3f243, $3f282 + dr $3f243, $3f24d +DropPlayerSub: + dr $3f24d, $3f282 GetEnemyMonFrontpic:: - dr $3f282, $3f2c7 + dr $3f282, $3f28c +DropEnemySub: + dr $3f28c, $3f2c7 StartBattle:: dr $3f2c7, $3f55d Function3f55d: @@ -843,7 +816,13 @@ CheckMagikarpLength: MagikarpHouseSign: dr $fbdd6, $fbdf1 HiddenPowerDamage: - dr $fbdf1, $fbeaa + dr $fbdf1, $fbe5a +_DisappearUser: + dr $fbe5a, $fbe6f +_AppearUserRaiseSub: + dr $fbe6f, $fbe77 +_AppearUserLowerSub: + dr $fbe77, $fbeaa DoWeatherModifiers: dr $fbeaa, $fbf2b DoBadgeTypeBoosts: @@ -1692,12 +1692,12 @@ wEnemySubStatus4:: ds 1 ; cb4e wEnemySubStatus5:: ds 1 ; cb4f wPlayerRolloutCount:: db ; cb50 wPlayerConfuseCount:: db ; cb51 -wcb52:: ds 1 ; cb52 +wPlayerToxicCount:: db ; cb52 wPlayerDisableCount:: db ; cb53 wPlayerEncoreCount:: db ; cb54 -wcb55:: ds 1 ; cb55 +wPlayerPerishCount:: db ; cb55 wPlayerFuryCutterCount:: db ; cb56 -wcb57:: ds 1 ; cb57 +wPlayerProtectCount:: db ; cb57 wEnemyRolloutCount:: db ; cb58 wEnemyConfuseCount:: db ; cb59 wEnemyToxicCount:: db ; cb5a @@ -1716,9 +1716,10 @@ wBattleReward:: wcb64:: ds 1 ; cb64 wcb65:: ds 1 ; cb65 wcb66:: ds 1 ; cb66 -wKickCounter:: ; cb67 wBattleAnimParam:: - db +wKickCounter:: +wPresentPower:: + db ; cb67 wBattleScriptBuffer:: db ; cb68 wcb69:: ds 1 ; cb69 wcb6a:: ds 1 ; cb6a @@ -1780,6 +1781,8 @@ wEnemySpAtk:: dw wEnemySpDef:: dw ds 1 +wPlayerStatLevels:: ; cbaa +; 07 neutral wPlayerAtkLevel:: db ; cbaa wPlayerDefLevel:: db ; cbab wPlayerSpdLevel:: db ; cbac @@ -1788,6 +1791,10 @@ wPlayerSDefLevel:: db ; cbae wPlayerAccLevel:: db ; cbaf wPlayerEvaLevel:: db ; cbb0 ds 1 +wPlayerStatLevelsEnd:: + +wEnemyStatLevels:: ; cbb2 +; 07 neutral wEnemyAtkLevel:: db ; cbb2 wEnemyDefLevel:: db ; cbb3 wEnemySpdLevel:: db ; cbb4 @@ -1796,6 +1803,8 @@ wEnemySDefLevel:: db ; cbb6 wEnemyAccLevel:: db ; cbb7 wEnemyEvaLevel:: db ; cbb8 ds 1 +wEnemyStatLevelsEnd:: + wEnemyTurnsTaken:: db ; cbba wPlayerTurnsTaken:: db ; cbbb wcbbc:: ds 1 ; cbbc @@ -1817,8 +1826,7 @@ wPayDayMoney:: ds 3 ; cbca wcbcd:: ds 1 ; cbcd wcbce:: ds 1 ; cbce wcbcf:: ds 1 ; cbcf -wcbd0:: ds 1 ; cbd0 -wcbd1:: ds 1 ; cbd1 +wEnemyBackupDVs:: dw wAlreadyDisobeyed:: db ; cbd2 wDisabledMove:: db ; cbd3 wEnemyDisabledMove:: db ; cbd4 @@ -1828,29 +1836,29 @@ wcbd5:: ds 1 ; cbd5 wLastPlayerCounterMove:: db ; cbd6 wLastEnemyCounterMove:: db ; cbd7 -wcbd8:: ds 1 ; cbd8 +wEnemyMinimized:: db ; cbd8 wAlreadyFailed:: db ; cbd9 wcbda:: ds 1 ; cbda wcbdb:: ds 1 ; cbdb wPlayerMinimized:: db ; cbdc wPlayerScreens:: db ; cbdd wEnemyScreens:: db ; cbde -wcbdf:: ds 1 ; cbdf -wcbe0:: ds 1 ; cbe0 +wPlayerSafeguardCount:: db ; cbdf +wPlayerLightScreenCount:: db ; cbe0 wcbe1:: ds 1 ; cbe1 wcbe2:: ds 1 ; cbe2 -wcbe3:: ds 1 ; cbe3 -wcbe4:: ds 1 ; cbe4 +wEnemySafeguardCount:: db ; cbe3 +wEnemyLightScreenCount:: db ; cbe4 wcbe5:: ds 1 ; cbe5 wcbe6:: ds 1 ; cbe6 wcbe7:: ds 1 ; cbe7 wBattleWeather:: db ; cbe8 -wcbe9:: ds 1 ; cbe9 -wcbea:: ds 1 ; cbea +wWeatherCount:: db ; cbe9 +wLoweredStat:: db ; cbea wEffectFailed:: db ; cbeb -wcbec:: ds 1 ; cbec +wFailedMessage:: db ; cbec wEnemyGoesFirst:: db ; cbed -wcbee:: ds 1 ; cbee +wPlayerIsSwitching:: db ; cbee wEnemyIsSwitching:: db ; cbef wPlayerUsedMoves:: ; cbf0 ; add a move that has been used once by the player @@ -1864,8 +1872,8 @@ wcbf7:: ds 1 ; cbf7 wcbf8:: ds 1 ; cbf8 wLastPlayerMove:: ds 1 ; cbf9 wLastEnemyMove:: ds 1 ; cbfa -wcbfb:: ds 1 ; cbfb -wcbfc:: ds 1 ; cbfc +wPlayerFutureSightCount:: db ; cbfb +wEnemyFutureSightCount:: db ; cbfc wcbfd:: ds 1 ; cbfd wcbfe:: ds 1 ; cbfe wcbff:: ds 1 ; cbff @@ -1874,15 +1882,13 @@ wcc01:: ds 1 ; cc01 wcc02:: ds 1 ; cc02 wcc03:: ds 1 ; cc03 wcc04:: ds 1 ; cc04 -wcc05:: ds 1 ; cc05 -wcc06:: ds 1 ; cc06 -wcc07:: ds 1 ; cc07 -wcc08:: ds 1 ; cc08 +wPlayerFutureSightDamage:: dw ; cc05 +wEnemyFutureSightDamage:: dw ; cc07 wPlayerRageCounter:: db ; cc09 wEnemyRageCounter:: db ; cc0a wBeatUpHitAtLeastOnce:: db ; cc0b -wcc0c:: ds 1 ; cc0c -wcc0d:: ds 1 ; cc0d +wPlayerTrappingMove:: db ; cc0c +wEnemyTrappingMove:: db ; cc0d wPlayerWrapCount:: db ; cc0e wEnemyWrapCount:: db ; cc0f wPlayerCharging:: db ; cc10 @@ -1895,8 +1901,8 @@ wWildMonPP:: ds NUM_MOVES ; cc17 wcc1b:: ds 1 ; cc1b wSomeoneIsRampaging:: db ; cc1c -wcc1d:: ds 1 ; cc1d -wcc1e:: ds 1 ; cc1e +wPlayerJustGotFrozen:: db ; cc1d +wEnemyJustGotFrozen:: db ; cc1e wcc1f:: ds 1 ; cc1f ENDU ; cc20 @@ -2847,12 +2853,12 @@ wOtherTrainerClass:: ; d118 ; 0 if opponent is a wild Pokémon, not a trainer db -wBattleType:: ds 1 ; d119 +wBattleType:: db ; d119 wd11a:: ds 1 ; d11a wOtherTrainerID:: db ; d11b -wd11c:: ds 1 ; d11c -wTrainerClass:: ds 1 ; d11d -wUnownLetter:: ds 1 ; d11e +wForcedSwitch:: db ; d11c +wTrainerClass:: db ; d11d +wUnownLetter:: db ; d11e wd11f:: ds 1 ; d11f wBaseDexNo:: ; d120 |