summaryrefslogtreecommitdiff
path: root/Add-a-new-field-move-effect.md
blob: 57c67cb99b2fb37979006ce2e48762fa91b5917e (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
198
199
200
201
202
203
204
205
206
This tutorial is for how to add a new field move effect: a function for a move outside of battle, like Rock Smash, Sweet Scent, all the HM moves, etc. As an example, we'll add a field effect for Earthquake.


## Contents

1. [Define a menu item constant](#1-define-a-menu-item-constant)
2. [Associate the menu item with a move](#2-associate-the-menu-item-with-a-move)
3. [Implement the party menu item](#3-implement-the-party-menu-item)
4. [Implement the field effect](#4-implement-the-field-effect)


## 1. Define a menu item constant

Edit [constants/menu_constants.asm](../blob/master/constants/menu_constants.asm):

```diff
 ; MonMenuOptions indexes (see data/mon_menu.asm)
 ; used by PokemonActionSubmenu (see engine/pokemon/mon_menu.asm)
 	const_def 1
 	; moves
 	const MONMENUITEM_CUT        ; 1
 	...
 	const MONMENUITEM_SWEETSCENT ; 14
+	const MONMENUITEM_EARTHQUAKE
 	; options
 	const MONMENUITEM_STATS      ; 15
 	...
```


## 2. Associate the menu item with a move

Edit [data/mon_menu.asm](../blob/master/data/mon_menu.asm):

```diff
 MonMenuOptions:
 ; category, item, value; actions are in PokemonActionSubmenu (see engine/pokemon/mon_menu.asm)
 ; moves
 	db MONMENU_FIELD_MOVE, MONMENUITEM_CUT,        CUT
 	...
 	db MONMENU_FIELD_MOVE, MONMENUITEM_SWEETSCENT, SWEET_SCENT
+	db MONMENU_FIELD_MOVE, MONMENUITEM_EARTHQUAKE, EARTHQUAKE
 ; options
 	db MONMENU_MENUOPTION, MONMENUITEM_STATS,      MONMENUVALUE_STATS
 	...
```


## 3. Implement the party menu item

Edit [engine/pokemon/mon_menu.asm](../blob/master/engine/pokemon/mon_menu.asm) (or [engine/menus/start_menu.asm](../blob/master/engine/menus/start_menu.asm) in older versions of pokecrystal):

```diff
 PokemonActionSubmenu:
 	...

 .Actions:
 	dbw MONMENUITEM_CUT,        MonMenu_Cut
 	...
 	dbw MONMENUITEM_SWEETSCENT, MonMenu_SweetScent
+	dbw MONMENUITEM_EARTHQUAKE, MonMenu_Earthquake
 	dbw MONMENUITEM_STATS,      OpenPartyStats
 	...

 MonMenu_RockSmash:
 	farcall RockSmashFunction
 	ld a, [wFieldMoveSucceeded]
 	cp $1
 	jr nz, .Fail
 	ld b, $4
 	ld a, $2
 	ret
 
 .Fail:
 	ld a, $3
 	ret

 MonMenu_SweetScent:
 	farcall SweetScentFromMenu
 	ld b, $4
 	ld a, $2
 	ret
+
+MonMenu_Earthquake:
+	farcall EarthquakeFunction
+	ld a, [wFieldMoveSucceeded]
+	and a
+	jr z, .Fail
+	ld b, $4
+	ld a, $2
+	ret
+
+.Fail:
+	ld a, $3
+	ret
```

The returned value of `a` affects what happens after the menu item is chosen:

- **$0:** Stays in the party menu.
- **$1:** Unused, seems buggy.
- **$2:** Exits the Start menu.
- **$3:** Stays in the party menu.

Like many other field move menu items, `MonMenu_Earthquake` returns `$2` or `$3` depending on whether its effect succeeded.

Next and last, we'll define its effect as `EarthquakeFunction`.


## 4. Implement the field effect

Edit [engine/events/overworld.asm](../blob/master/engine/events/overworld.asm):

```diff
+EarthquakeFunction:
+	call FieldMoveJumptableReset
+.loop
+	ld hl, .Jumptable
+	call FieldMoveJumptable
+	jr nc, .loop
+	and $7f
+	ld [wFieldMoveSucceeded], a
+	ret
+
+.Jumptable:
+	dw .TryEarthquake
+	dw .DoEarthquake
+	dw .FailEarthquake_Bike
+	dw .FailEarthquake_Surf
+
+.TryEarthquake:
+	ld a, [wPlayerState]
+	cp PLAYER_BIKE
+	jr z, .fail_bike
+	cp PLAYER_SURF
+	jr z, .fail_surf
+	cp PLAYER_SURF_PIKA
+	jr z, .fail_surf
+	ld a, $1
+	ret
+.fail_bike
+	ld a, $2
+	ret
+.fail_surf
+	ld a, $3
+	ret
+
+.DoEarthquake:
+	ld hl, EarthquakeScript
+	call QueueScript
+	ld a, $81
+	ret
+
+.FailEarthquake_Bike:
+	ld hl, CantEarthquakeOnBikeText
+	call MenuTextboxBackup
+	ld a, $80
+	ret
+
+.FailEarthquake_Surf:
+	ld hl, CantEarthquakeOnWaterText
+	call MenuTextboxBackup
+	ld a, $80
+	ret
+
+EarthquakeScript:
+	reloadmappart
+	special UpdateTimePals
+	callasm GetPartyNick
+	writetext UsedEarthquakeText
+	waitbutton
+	closetext
+	playsound SFX_STRENGTH
+	earthquake 50
+	pause 30
+	jumptext TheGroundShookText
+
+UsedEarthquakeText:
+	text_ram wStringBuffer3
+	text " used"
+	line "EARTHQUAKE!"
+	done
+
+TheGroundShookText:
+	text "The ground shook!"
+	done
+
+CantEarthquakeOnBikeText:
+	text "It's unsafe to"
+	line "ride a bike in"
+	cont "an EARTHQUAKE!"
+	prompt
+
+CantEarthquakeOnWaterText:
+	text "There's no earth"
+	line "to quake here!"
+	prompt
```

This step calls for the most originality. You have to implement whatever your new field move is supposed to do, using assembly code and event scripts. Here I just made Earthquake play a short visual effect, but fail to do so if you're Surfing or on a Bicycle.

That's everything:

![Screenshot](screenshots/field-move-earthquake.png)

Real effects, like Rock Climb or Dive, will be more complicated. Study how the existing effects work and try to imitate their structure.