diff options
-rw-r--r-- | Add-a-new-move-effect.md | 201 | ||||
-rw-r--r-- | Tutorials.md | 1 | ||||
-rw-r--r-- | screenshots/effect-hex.png | bin | 0 -> 3797 bytes |
3 files changed, 202 insertions, 0 deletions
diff --git a/Add-a-new-move-effect.md b/Add-a-new-move-effect.md new file mode 100644 index 0000000..5b813e7 --- /dev/null +++ b/Add-a-new-move-effect.md @@ -0,0 +1,201 @@ +This tutorial is for how to add a new move effect. As an example, we'll add Hex. + + +## Contents + +1. [Prepare the move itself](#1-prepare-the-move-itself) +2. [Define an effect constant](#2-define-an-effect-constant) +3. [Update the effect pointer table](#3-update-the-effect-pointer-table) +4. [Write the effect script](#4-write-the-effect-script) +5. [Define any new battle commands](#5-define-any-new-battle-commands) +6. [Teach the AI to use the effect well](#6-teach-the-ai-to-use-the-effect-well) + + +## 1. Prepare the move itself + +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-a-new-move). + +Replace `MOVE_OR_ANIM_FC` with `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). + + +## 2. Define an effect constant + +`EFFECT_HEX` has not been defined yet, so we'll do that next. Edit [constants/move_effect_constants.asm](../blob/master/constants/move_effect_constants.asm): + +```diff + ; MoveEffectsPointers indexes (see data/moves/effects_pointers.asm) + const_def + const EFFECT_NORMAL_HIT + ... + const EFFECT_DEFENSE_CURL ++ const EFFECT_HEX +``` + +If you want to be save space, there are six `UNUSED` effects you can replace, instead of adding `EFFECT_HEX` to the end of the list. + + +## 3. Update the effect pointer table + +Edit [data/moves/effects_pointers.asm](../blob/master/data/moves/effects_pointers.asm): + +```diff + MoveEffectsPointers: ; 271f4 + ; entries correspond to EFFECT_* constants + dw NormalHit + ... + dw DefenseCurl ++ dw Hex +``` + + +## 4. Write the effect script + +Edit [data/moves/effects.asm](../blob/master/data/moves/effects.asm): + +```diff ++Hex: ++ checkobedience ++ usedmovetext ++ doturn ++ critical ++ damagestats ++ damagecalc ++ stab ++ damagevariation ++ hex ++ checkhit ++ moveanim ++ failuretext ++ applydamage ++ criticaltext ++ supereffectivetext ++ checkdestinybond ++ buildopponentrage ++ kingsrock ++ endmove +``` + +Move effects are written in their own scripting language; see [docs/move_effect_commands.md](../blob/master/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.) + + +## 5. Define any new battle 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](../blob/master/macros/scripts/battle_commands.asm): + +```diff + ; BattleCommandPointers indexes (see data/battle/effect_command_pointers.asm) + enum_start 1 + command checkturn ; 01 + ... + command curl ; af ++ command hex ; b0 +``` + +You 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](../blob/master/data/battle/effect_command_pointers.asm): + +```diff + BattleCommandPointers: ; 3fd28 + ; entries correspond to macros/scripts/battle_commands.asm + dw BattleCommand_CheckTurn ; 34084 + ... + dw BattleCommand_Curl ; 365a7 ++ dw BattleCommand_Hex + ; 3fe86 +``` + +Create **engine/battle/move_effects/hex.asm**: + +```diff ++BattleCommand_Hex: ++; 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 damage ++ jp DoubleDamage +``` + +And edit [engine/battle/effect_commands.asm](../blob/master/engine/battle/effect_commands.asm): + +```diff + INCLUDE "engine/battle/move_effects/rage.asm" ++ ++INCLUDE "engine/battle/move_effects/hex.asm" + + BattleCommand_DoubleFlyingDamage: ; 36f25 + ; 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. + + +## 6. Teach the AI to use the effect well + +This step is optional, but if you feel capable of writing new code, it's nice to have the enemy AI use new moves in appropriate situations. + +First, look at the tables of moves and effects in [data/battle/ai](../tree/master/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](../blob/master/engine/battle/ai/scoring.asm): + +```diff + AI_Smart: ; 386be + ; Context-specific scoring. + + ... + + .table_386f2 + dbw EFFECT_SLEEP, AI_Smart_Sleep + ... + dbw EFFECT_FLY, AI_Smart_Fly ++ dbw EFFECT_HEX, AI_Smart_Hex + db -1 ; end + ; 387e3 + + ... + + AI_Smart_DefrostOpponent: ; 38ccb + ; 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 + ; 38cd5 ++ ++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] ++ ret +``` + +Pretty 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! + + diff --git a/Tutorials.md b/Tutorials.md index 010eecd..306de17 100644 --- a/Tutorials.md +++ b/Tutorials.md @@ -14,6 +14,7 @@ Tutorials may use diff syntax to show edits: - [Trainer class](Add-a-new-trainer-class) - [Type (Fairy)](Add-a-new-Fairy-type) - [Move (up to 254)](Add-a-new-move) +- [Move effect](Add-a-new-move-effect) - [Item (up to 254)](Add-different-kinds-of-new-items) - [TM (up to 120)](Add-a-new-TM) - [Music song](Add-a-new-music-song) diff --git a/screenshots/effect-hex.png b/screenshots/effect-hex.png Binary files differnew file mode 100644 index 0000000..8635109 --- /dev/null +++ b/screenshots/effect-hex.png |