summaryrefslogtreecommitdiff
path: root/Adding-items-that-act-like-HMs.md
blob: a92d86368253fa583b54f351d5bae806b82675e0 (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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
This tutorial will cover how to add items that act like HM Field moves, using CUT as an example.

## Contents

1. [Adding the item](#1-adding-the-item)
2. [Fixing the success message](#2-fixing-the-success-message)
3. [Fixing Oak's message](#3-fixing-oaks-message)
4. [Including other HMs](#4-including-other-hms)

## 1. Adding the item

Follow the guide on [adding new items](#Add-a-new-item) to create the item that will act like an HM. I changed ITEM_19 into CHAINSAW with the following:

[constants/item_constants.asm](../blob/master/constants/item_constants.asm):
```Diff
	const WATER_STONE  ; 18
-	const ITEM_19      ; 19
+	const CHAINSAW     ; 19
	const HP_UP        ; 1a
```

[data/items/names.asm](../blob/master/data/items/names.asm):
```Diff
	db "WATER STONE@"
-	db "TERU-SAMA@"
+	db "CHAINSAW@"
	db "HP UP@"
```

[data/items/descriptions.asm](../blob/master/data/items/descriptions.asm):

```diff
 	dw WaterStoneDesc
-	dw TeruSama2Desc
+	dw ChainsawDesc
	dw HPUpDesc

 	...

-TeruSama2Desc:
-	db   "?@"
+ChainsawDesc:
+	db   "Cuts down pesky"
+	next "plants.@"
```

[data/items/attributes.asm](../blob/master/data/items/attributes.asm):
```Diff
-; ITEM_19
-	item_attribute $9999, HELD_NONE, 0, NO_LIMITS, ITEM, ITEMMENU_NOUSE, ITEMMENU_NOUSE
+; CHAINSAW
+	item_attribute 0, HELD_NONE, 0, CANT_TOSS, KEY_ITEM, ITEMMENU_CLOSE, ITEMMENU_NOUSE
```

[data/items/catch_rate_items.asm](../blob/master/data/items/catch_rate_items.asm):
```Diff
TimeCapsule_CatchRateItems:
-	db ITEM_19, LEFTOVERS
```

***

In this example, Chainsaw will act like the HM Cut, so we'll use `CutFunction` in [engine/events/overworld.asm](../blob/master/engine/events/overworld.asm). A list of HM Functions is at the end of this tutorial. Since these functions are in a different bank from the item effect functions, we just need to write a small function that can farcall our HM Function. [ engine/items/item_effects.asm](../blob/master/engine/items/item_effects.asm ):

```Diff
	dw EvoStoneEffect      ; WATER_STONE
-	dw NoEffect            ; ITEM_19
+	dw ChainsawEffect      ; CHAINSAW

	...

+ChainsawEffect:
+	farcall CutFunction
+	ret
```

## 2. Fixing the success message
The above works, but it has a few flaws. Firstly, a message will pop up saying a Pokémon used the relevant HM Effect. There are several ways to change this, but the easiest is to edit the text that's displayed when your HM's effect script is run. The HM Effect scripts will be listed at the end.

First, skip loading the Pokémon's name. At best this finds the first Pokémon that has cut, at worse it fails and the text is incorrect. [engine/events/overworld.asm](../blob/master/engine/events/overworld.asm):

```Diff
Script_Cut:
-	callasm GetPartyNickname
	writetext UseCutText
```

Then, we can change the text to be a bit more neutral. `UseCutText` points to `_UseCutText` in [data/text/common_2.asm](../blob/master/data/text/common_2.asm):

```Diff
_UseCutText::
-	text_ram wStringBuffer2
-	text " used"
-	line "CUT!"
+	text "You cut some"
+	line "plants!"
	prompt
```

## 3. Fixing Oak's message

As it stands, if you use your item and it fails, you'll be told the HM's error message AND be yelled at by Oak. To avoid this, we can introduce a new temporary var that can be used to skip Oak's message for HM-like-items.

First off, we need to create a new label in wram. There's a nice chunk of free space in wram bank 0 right after `wDaysSince`. [wram.asm](../blob/master/wram.asm):


```Diff
wDaysSince:: db

+wUsingHMItem:: db

SECTION "WRAM 1", WRAMX
```

Next, we'll change our item effect so that it sets `wUsingHMItem` to 1, signifying that it's okay to skip Oak's Message. [engine/items/item_effects.asm](../blob/master/engine/items/item_effects.asm)

```Diff
ChainsawEffect:
+	ld a, 1
+	ld [wUsingHMItem], a
	farcall CutFunction
	ret
```

Finally, we'll skip Oak's message if `wUsingHMItem` is set. Oak's message is handled in [engine/items/pack.asm](../blob/master/engine/items/pack.asm):

```Diff
	ld a, [wItemEffectSucceeded]
	and a
-	jr z, .Oak
+
+	; grab and reset wUsingHMItem without changing flag
+	ld hl, wUsingHMItem
+	ld a, [hl]
+	ld [hl], 0
+
+	jr z, .tryOak
	ld a, PACKSTATE_QUITRUNSCRIPT
	ld [wJumptableIndex], a
	ret

+.tryOak
+	or a
+	jr z, .Oak
+	ret

TossMenu:
	ld hl, Text_ThrowAwayHowMany
```

The above loads `wUsingHMItem`'s value and resets it to 0 so Oak's message won't be skipped for normal items. If Oak's message would normally plays, it will do one quick check of `wUsingHMItem`'s old value, and go right to returning if it wasn't zero.

## 4. Including other HMs

Including the other HM effects is as simple as repeating the above with different effect functions and new items. Our code to handle Oak's message based on `wUsingHMItem` doesn't need to be changed to allow other HMs, however every HM must include code to it to 1 (or any other nonzero value).

The following are lists of HM Functions as of time of writing. These may not all work as well as Cut, and may change naming conventions over time.

### HM Function List

All of these are in [engine/events/overworld.asm](../blob/master/engine/events/overworld.asm).
* `CutFunction`
* `FlyFunction`
* `SurfFunction`
* `StrengthFunction`
* `OWFlash`
* `WhirlpoolFunction`
* `WaterfallFunction`

Additionally, functions like `TeleportFunction` can be used as well.

### HM Effect Scripts

All of these are in [engine/events/overworld.asm](../blob/master/engine/events/overworld.asm).

* `Script_Cut`
* Fly does not show a message
* `UsedSurfScript`
* `Script_UsedStrength`
* Flash does not show the Pokémon's name
* `Script_UsedWhirlpool`
* `Script_UsedWaterfall`

### Using the item as default on the overworld

Even with the item added and it being functional, the game will still check for a pokemon in the party to use the HM move when attempting to interact with a cuttable tree on the overworld. This is a simple fix.

If we look in [engine/events/overworld.asm](../blob/master/engine/events/overworld.asm) at the bottom, we'll see `TryCutOW`. This function is called when the player interacts with a cuttable tree, normally it checks the party first for a pokemon with cut, then for the appropriate badge, so we'll change it.

```Diff
CutFunction:
...

.CheckAble:
-	ld de, ENGINE_HIVEBADGE
-	call CheckBadge
-	jr c, .nohivebadge
	call CheckMapForSomethingToCut
	jr c, .nothingtocut
	ld a, $1
	ret

-.nohivebadge
-	ld a, $80
-	ret

```

and

```Diff
TryCutOW::
-	ld d, CUT
-	call CheckPartyMove
-	jr c, .cant_cut

-	ld de, ENGINE_HIVEBADGE
-	call CheckEngineFlag
+	ld a, CHAINSAW
+	ld [wCurItem], a
+	ld hl, wNumItems
+	call CheckItem
+	jr nc, .cant_cut
```

This removes the checks for an eligible pokemon and badge, and just checks for the item in the bag.