-
Notifications
You must be signed in to change notification settings - Fork 892
Add a new move effect
This tutorial is for how to add a new move effect. As an example, we'll add Hex.
- Prepare the move itself
- Define an effect constant
- Update the effect pointer table
- Write the effect script
- Define any new battle commands
- Teach the AI to use the effect well
Hex is an attack from Gen 5 that doubles in power if the target has a status condition. No effect like that existed in Gen 2, so we're going to add one; but first, we have to add the move Hex, following this tutorial.
Add the constant HEX; give it a name, description, and battle properties (HEX, EFFECT_HEX, 65, GHOST, 100, 10, 0); give it an animation (it can share BattleAnim_Spite); and add it to Pokémon learnsets (Vulpix, Tentacool/Tentacruel, Gastly/Haunter/Gengar, and Misdreavus by level-up; Vulpix and Dunsparce by breeding).
EFFECT_HEX has not been defined yet, so we'll do that next. Edit constants/move_effect_constants.asm:
; MoveEffectsPointers indexes (see data/moves/effects_pointers.asm)
const_def
const EFFECT_NORMAL_HIT
...
const EFFECT_DEFENSE_CURL
+ const EFFECT_HEXIf you want to save space, there are six UNUSED effects you can replace, instead of adding EFFECT_HEX to the end of the list.
Edit data/moves/effects_pointers.asm:
MoveEffectsPointers:
; entries correspond to EFFECT_* constants
dw NormalHit
...
dw DefenseCurl
+ dw HexEdit data/moves/effects.asm:
+Hex:
+ checkobedience
+ usedmovetext
+ doturn
+ critical
+ damagestats
+ damagecalc
+ stab
+ damagevariation
+ hex
+ checkhit
+ moveanim
+ failuretext
+ applydamage
+ criticaltext
+ supereffectivetext
+ checkfaint
+ buildopponentrage
+ kingsrock
+ endmoveMove effects are written in their own scripting language; see docs/move_effect_commands.md for a list of the usable commands.
If you're writing a custom effect, it's helpful to start with an existing one and modify it as needed. Here I took the NormalHit effect and added a hex command to double the damage if the target has a status condition. (No such command exists yet, so we'll have to add that next, but many new effects can be written just with the predefined commands.)
The Hex move effect script needs a new hex battle command, so let's define that next. It's similar to the process of adding every other new thing: define hex as a constant, give it an entry in a pointer table, and define the thing it's pointing to.
Edit macros/scripts/battle_commands.asm:
; BattleCommandPointers indexes (see data/battle/effect_command_pointers.asm)
const_def 1
command checkturn ; 01
...
command curl ; af
+ command hex ; b0You can replace effect0x3c or effect0x5d before adding to the end of the list, if you're like me and don't want to leave unused code lying around. ;)
Anyway, edit data/battle/effect_command_pointers.asm:
BattleCommandPointers:
; entries correspond to macros/scripts/battle_commands.asm
dw BattleCommand_CheckTurn
...
dw BattleCommand_Curl
+ dw BattleCommand_HexCreate engine/battle/move_effects/hex.asm:
+BattleCommand_Hex:
+; Get the opponent's status condition
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVar
+; Return if it's 0 (no condition)
+ and a
+ ret z
+; It's not 0, so double the damage
+ jp DoubleDamageAnd edit engine/battle/effect_commands.asm:
INCLUDE "engine/battle/move_effects/rage.asm"
+
+INCLUDE "engine/battle/move_effects/hex.asm"
BattleCommand_DoubleFlyingDamage:
; doubleflyingdamage
ld a, BATTLE_VARS_SUBSTATUS3_OPP
call GetBattleVar
bit SUBSTATUS_FLYING, a
ret z
jr DoubleDamage(We could have just written the BattleCommand_Hex code right in engine/battle/effect_commands.asm, but it's more organized to follow pokecrystal's convention of putting individual moves' unique commands in their own files.)
Notice how similar BattleCommand_Hex is to BattleCommand_DoubleFlyingDamage right below it. Whether you're writing data tables, scripts, or assembly code, you don't have to start from scratch; you can find something close to what you want and modify it.
Now that we successfully added Hex, it'd nice to have the enemy AI use the new move in appropriate situations.
First, look at the tables of moves and effects in data/battle/ai. They all have comments at the top explaining what they're for, like "AI_CAUTIOUS discourages these moves after the first turn." Consider whether your new move effect should be added to any of these tables. There's nowhere we need to add HEX or EFFECT_HEX, though.
Next, we'll teach AI_SMART to take advantage of EFFECT_HEX when the player has a status condition. Edit engine/battle/ai/scoring.asm:
AI_Smart:
; Context-specific scoring.
...
AI_Smart_EffectHandlers:
dbw EFFECT_SLEEP, AI_Smart_Sleep
...
dbw EFFECT_FLY, AI_Smart_Fly
+ dbw EFFECT_HEX, AI_Smart_Hex
db -1 ; end
...
AI_Smart_DefrostOpponent:
; Greatly encourage this move if enemy is frozen.
; No move has EFFECT_DEFROST_OPPONENT, so this layer is unused.
ld a, [wEnemyMonStatus]
and 1 << FRZ
ret z
dec [hl]
dec [hl]
dec [hl]
ret
+
+AI_Smart_Hex:
+; Greatly encourage this move if the player has a status condition.
+
+ ld a, [wBattleMonStatus]
+ and a
+ ret z
+ dec [hl]
+ dec [hl]
+ dec [hl]
+ retPretty self-explanatory. Find the right table, add an entry for EFFECT_HEX, and base the new AI routine on a pre-existing one.
That's all!
