summaryrefslogtreecommitdiff
path: root/Add-a-new-move-effect.md
blob: f7499a7977af98f3f92d9ebb0facdf030e79c67d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
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).

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).


## 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 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:
 ; 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
+	checkfaint
+	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)
 	const_def 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:
 ; entries correspond to macros/scripts/battle_commands.asm
 	dw BattleCommand_CheckTurn
 	...
 	dw BattleCommand_Curl
+	dw BattleCommand_Hex
```

Create **engine/battle/move_effects/hex.asm**:

```diff
+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 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:
 ; 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

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](../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:
 ; 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]
+	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!

![Screenshot](screenshots/effect-hex.png)