-
Notifications
You must be signed in to change notification settings - Fork 1k
Check base power before skipping damage calculation
DISCLAIMER: As with any changes to the battle engine, one should always make sure to test and check for bugs; especially if these changes will conflict with preexisting changes that you have already made. Please make a note in this tutorial or let me know on Discord (@Xillicis) if you discover any issues or realize a more efficient implementation.
WHY? The main motivation for this tutorial is to make it easier to implement new moves such as Mud Slap, Fire Lash, Chilling Water, Low Sweep, Mud Shot, etc...
In particular, this applies to any move with a move effect belonging to the list ResidualEffects2
which is found in data/battle/residual_effects_2.asm
.
The ResidualEffects2
include all stat up and stat down moves along with BIDE_EFFECT
and SLEEP_EFFECT
which correspond to the moves BIDE
and SPORE
, respectively.
Currently, the changes outlined in this tutorial will not cover damaging moves that have a 100% chance of causing a status effect on the opponent; e.g. Zap Cannon.
Let's consider an example move: Mud Slap.
The base power is 20 and the move always lowers the targets accuracy (assuming the move didn't miss).
In generation 1, moves that always lower a stat like Sand Attack or Tail Whip will automatically skip the damage calculation.
In particular, any move with the move effect belonging to the list residual_effects_2.asm
will skip the damage calculation.
Therefore, if we try to implement Mud Slap following this tutorial Add a New Move and use the ACCURACY_DOWN1_EFFECT
as the move effect, then the move will never deal damage.
We solve this issue by checking that the base power is not zero.
Open up engine/battle/core.asm and make the following change to the subroutine MirrorMoveCheck:
,
...
.next
ld a, [wPlayerMoveEffect]
ld hl, ResidualEffects2
ld de, 1
call IsInArray
- jp c, JumpMoveEffect ; done here after executing effects of ResidualEffects2
+ jr nc, .notResidual2Effect
+ ld a, [wPlayerMovePower]
+ and a ; check if zero base power
+ jp z, JumpMoveEffect
+.notResidual2Effect
ld a, [wMoveMissed]
and a
jr z, .moveDidNotMiss
call PrintMoveFailureText
ld a, [wPlayerMoveEffect]
cp EXPLODE_EFFECT ; even if Explosion or Selfdestruct missed, its effect still needs to be activated
jr z, .notDone
jp ExecutePlayerMoveDone ; otherwise, we're done if the move missed
.moveDidNotMiss
call ApplyAttackToEnemyPokemon
...
Notice that old code checks if the move effect belongs to the list ResidualEffects2
and if so it jumps to the move effect which effectively leaves the current subroutine hence skipping the ApplyAttackToEnemyPokemon
. (Note: IsInArray
sets the carry flag c
if the value stored in register a
belongs to the array pointed to by hl
.) So instead, we change the code to check if the move effect is in ResidualEffects2
and check if the base power is zero before jumping to the move effect.
This code is only for the players move, so we also need to make a similar change for the enemy's move. Head down a bit farther to the subroutine EnemyCheckIfMirrorMoveEffect:
make the following change,
...
ld hl, ResidualEffects2
ld de, $1
call IsInArray
- jp c, JumpMoveEffect
+ jr nc, .notResidual2EffectEnemy
+ ld a, [wEnemyMovePower]
+ and a ; Check if zero base power
+ jp z, JumpMoveEffect
+.notResidual2EffectEnemy
ld a, [wMoveMissed]
and a
jr z, .moveDidNotMiss
...
Damage will now be applied properly; however, if you try the move out, you'll find that the animation will play twice.
Once for the damage and once for the stat reduction.
There are two corrections that have to be made for this.
The first, is if the move increased the user's stat, e.g. Flame Charge.
The second is if the move lowered the opponent's stat, e.g. Mud Slap.
To correct this, open up engine/battle/effects.asm and modify the subroutine UpdateStat:
with the following changes,
...
call nz, Bankswitch
pop de
.notMinimize
+ ldh a, [hWhoseTurn]
+ and a
+ ld a, [wPlayerMovePower]
+ jr z, .gotUsersPower1
+ ld a, [wEnemyMovePower]
+.gotUsersPower1
+ and a ; Skip animation if damage dealing move
+ jr nz, .skipAnimation
call PlayCurrentMoveAnimation
+.skipAnimation
ld a, [de]
cp MINIMIZE
jr nz, .applyBadgeBoostsAndStatusPenalties
...
Go down a bit further and make the following changes to the subroutine UpdateLoweredStatDone:
,
...
ld a, [de]
cp $44
jr nc, .ApplyBadgeBoostsAndStatusPenalties
+ ldh a, [hWhoseTurn] ; check who is using the move
+ and a
+ ld a, [wPlayerMovePower]
+ jr z, .gotUsersPower2
+ ld a, [wEnemyMovePower]
+.gotUsersPower2
+ and a ; Skip animation if damage dealing move
+ jr nz, .ApplyBadgeBoostsAndStatusPenalties
call PlayCurrentMoveAnimation2
.ApplyBadgeBoostsAndStatusPenalties
...
That's it. Note that these changes should work for any of the stat up or down effects listed in data/battle/residual_effects_2.asm