summaryrefslogtreecommitdiff
path: root/Rock-Climb.md
blob: f90b46b0e2eb5620ac9fc2e0ced8e4cf05831304 (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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
Gen 4 introduced Rock Climb, a field move that can scale rocky walls, as HM08. Its in-battle effect, to deal damage with a chance of confusion, already exists (for Psybeam); and its field effect is not too complex to implement.

(The code for this feature was adapted from [Pokémon Orange](https://github.com/PiaCarrot/pokeorange/).)


## Contents

1. [Prepare the Rock Climb move](#1-prepare-the-rock-climb-move)
2. [Prepare the HM08 item](#2-prepare-the-hm08-item)
3. [Define a collision type for rocky walls](#3-define-a-collision-type-for-rocky-walls)
4. [Start to prepare the Rock Climb field move effect](#4-start-to-prepare-the-rock-climb-field-move-effect)
5. [Define a utility function to check for rocky walls](#5-define-a-utility-function-to-check-for-rocky-walls)
6. [Define text related to using Rock Climb](#6-define-text-related-to-using-rock-climb)
7. [Finish the Rock Climb field move effect](#7-finish-the-rock-climb-field-move-effect)
8. [Talk to rocky walls to use Rock Climb](#8-talk-to-rocky-walls-to-use-rock-climb)
9. [Add rocky walls to a map](#9-add-rocky-walls-to-a-map)


## 1. Prepare the Rock Climb move

We're going to add a field effect for climbing rocky walls; but first, we have to add the move Rock Climb, following [this tutorial](Add-a-new-move).

Replace `MOVE_OR_ANIM_FC` with `ROCK_CLIMB`; give it a name, description, and battle properties (`ROCK_CLIMB, EFFECT_CONFUSE_HIT, 90, NORMAL, 85, 20, 20`); give it an animation (it can share `BattleAnim_Waterfall`); and add it to Pokémon learnsets (Sandshrew, Geodude, Onix, Rhyhorn, and Gligar learn it as an Egg move).


## 2. Prepare the HM08 item

We also have to add the item HM08, following [this tutorial](Add-a-new-TM-or-HM).

Add an HM for `ROCK_CLIMB`; give it a name and attributes (`0, HELD_NONE, 0, CANT_SELECT | CANT_TOSS, TM_HM, ITEMMENU_PARTY, ITEMMENU_NOUSE`); associate it with the move `ROCK_CLIMB`; make it unforgettable; and add it to Pokémon base learnsets (48 Pokémon are compatible with it, including all three fully-evolved Johto starters).


## 3. Define a collision type for rocky walls

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

```diff
 ; collision data types (see data/tilesets/*_collision.asm)
 ; TileCollisionTable indexes (see data/collision_permissions.asm)
 COLL_FLOOR             EQU $00
 COLL_01                EQU $01 ; garbage
 COLL_03                EQU $03 ; garbage
 COLL_04                EQU $04 ; garbage
+COLL_ROCKY_WALL        EQU $06
 COLL_WALL              EQU $07
 ...
```

And edit [data/collision_permissions.asm](../blob/master/data/collision_permissions.asm):

```diff
 TileCollisionTable::
 ; entries correspond to COLL_* constants
 	NONTALKABLE  LANDTILE ; COLL_FLOOR
 	NONTALKABLE  LANDTILE ; COLL_01
 	NONTALKABLE  LANDTILE ; 02
 	NONTALKABLE  LANDTILE ; COLL_03
 	NONTALKABLE  LANDTILE ; COLL_04
 	NONTALKABLE  LANDTILE ; 05
-	NONTALKABLE  LANDTILE ; 06
+	   TALKABLE  WALLTILE ; COLL_ROCKY_WALL
 	NONTALKABLE  WALLTILE ; COLL_WALL
 	...
```

Rocky walls will prompt to use Rock Climb when talked to, so they need to be `TALKABLE`.


## 4. Start to prepare the Rock Climb field move effect

Now we can start to add the field move effect, following [this tutorial](Add-a-new-field-move-effect).

Define `MONMENUITEM_ROCKCLIMB`; associate it with the move `ROCK_CLIMB`; and implement `MonMenu_RockClimb` for its menu action (in [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) like this:

```diff
+MonMenu_RockClimb:
+	farcall RockClimbFunction
+	ld a, [wFieldMoveSucceeded]
+	cp $1
+	jr nz, .Fail
+	ld b, $4
+	ld a, $2
+	ret
+
+.Fail:
+	ld a, $3
+	ret
```

We still have to implement `RockClimbFunction`; but first, let's define some more components for it.


## 5. Define a utility function to check for rocky walls

Edit [home/map_objects.asm](../blob/master/home/map_objects.asm):

```diff
 CheckHeadbuttTreeTile::
 	cp COLL_HEADBUTT_TREE
 	ret z
 	cp COLL_HEADBUTT_TREE_1D
 	ret
+
+CheckRockyWallTile::
+	cp COLL_ROCKY_WALL
+	ret
```

This isn't strictly necessary—we could just directly use `cp COLL_ROCKY_WALL` instead of `call CheckRockyWallTile`—but it's how the other field moves work. And this approach is easier to extend, if for some reason more than one collision type should act like a rocky wall.


## 6. Define text related to using Rock Climb

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

```diff
+_AskRockClimbText::
+	text "The wall is very"
+	line "rocky…"
+
+	para "Want to use"
+	line "ROCK CLIMB?"
+	done
+
+_UsedRockClimbText::
+	text_ram wStringBuffer2
+	text " used"
+	line "ROCK CLIMB!"
+	prompt
+
+_CantRockClimbText::
+	text "The wall is very"
+	line "rocky…"
+
+	para "Will a #MON's"
+	line "move scale it?"
+	done
```

This could have gone in [common_1.asm](../blob/master/data/text/common_1.asm) or [common_3.asm](../blob/master/data/text/common_3.asm) instead, but [common_2.asm](../blob/master/data/text/common_2.asm) has text related to other HM moves already.

We'll need this text, and the previous `CheckRockyWallTile` routine, when we define `RockClimbFunction` next.


## 7. Finish the Rock Climb field move effect

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

```diff
+RockClimbFunction:
+	call FieldMoveJumptableReset
+.loop
+	ld hl, .jumptable
+	call FieldMoveJumptable
+	jr nc, .loop
+	and $7f
+	ld [wFieldMoveSucceeded], a
+	ret
+
+.jumptable:
+	dw .TryRockClimb
+	dw .DoRockClimb
+	dw .FailRockClimb
+
+.TryRockClimb:
+	ld de, ENGINE_EARTHBADGE
+	farcall CheckBadge
+	jr c, .noearthbadge
+	call TryRockClimbMenu
+	jr c, .failed
+	ld a, $1
+	ret
+
+.noearthbadge
+	ld a, $80
+	ret
+
+.failed
+	ld a, $2
+	ret
+
+.DoRockClimb:
+	ld hl, RockClimbFromMenuScript
+	call QueueScript
+	ld a, $81
+	ret
+
+.FailRockClimb:
+	call FieldMoveFailed
+	ld a, $80
+	ret
+
+TryRockClimbMenu:
+	call GetFacingTileCoord
+	ld c, a
+	push de
+	call CheckRockyWallTile
+	pop de
+	jr nz, .failed
+	xor a
+	ret
+
+.failed
+	scf
+	ret
+
+TryRockClimbOW::
+	ld de, ENGINE_EARTHBADGE
+	call CheckEngineFlag
+	jr c, .cant_climb
+
+	ld d, ROCK_CLIMB
+	call CheckPartyMove
+	jr c, .cant_climb
+
+	ld a, BANK(AskRockClimbScript)
+	ld hl, AskRockClimbScript
+	call CallScript
+	scf
+	ret
+
+.cant_climb
+	ld a, BANK(CantRockClimbScript)
+	ld hl, CantRockClimbScript
+	call CallScript
+	scf
+	ret
+
+AskRockClimbScript:
+	opentext
+	writetext AskRockClimbText
+	yesorno
+	iftrue UsedRockClimbScript
+	closetext
+	end
+
+CantRockClimbScript:
+	jumptext CantRockClimbText
+
+RockClimbFromMenuScript:
+	reloadmappart
+	special UpdateTimePals
+
+UsedRockClimbScript:
+	callasm GetPartyNick
+	writetext UsedRockClimbText
+	closetext
+	waitsfx
+	playsound SFX_STRENGTH
+	readvar VAR_FACING
+	if_equal DOWN, .Down
+.loop_up
+	applymovement PLAYER, .RockClimbUpStep
+	callasm .CheckContinueRockClimb
+	iffalse .loop_up
+	end
+
+.Down:
+	applymovement PLAYER, .RockClimbFixFacing
+.loop_down
+	applymovement PLAYER, .RockClimbDownStep
+	callasm .CheckContinueRockClimb
+	iffalse .loop_down
+	applymovement PLAYER, .RockClimbRemoveFixedFacing
+	end
+
+.CheckContinueRockClimb:
+	xor a
+	ld [wScriptVar], a
+	ld a, [wPlayerStandingTile]
+	call CheckRockyWallTile
+	ret z
+	ld a, $1
+	ld [wScriptVar], a
+	ret
+
+.RockClimbUpStep:
+	step UP
+	step_end
+
+.RockClimbDownStep:
+	step DOWN
+	step_end
+
+.RockClimbFixFacing:
+	turn_head UP
+	fix_facing
+	step_end
+
+.RockClimbRemoveFixedFacing:
+	remove_fixed_facing
+	turn_head DOWN
+	step_end
+
+AskRockClimbText:
+	text_far _AskRockClimbText
+	text_end
+
+UsedRockClimbText:
+	text_far _UsedRockClimbText
+	text_end
+
+CantRockClimbText:
+	text_far _CantRockClimbText
+	text_end
```

You can study how this routine works; it's similar to other field moves. Just like in HG/SS, you need the Earth Badge to use it. (If you don't want that, remove the two checks for `ENGINE_EARTHBADGE`.) When you're facing up or down toward a rocky wall, you can climb it. Just like waterfalls, you'll continue moving until you reach a different type of tile.

Anyway, the requisite move, HM, and field effect are all done, but we still have a few improvements to make.


## 8. Talk to rocky walls to use Rock Climb

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

```diff
 TryTileCollisionEvent::
 	...

 .headbutt
 	ld a, [wFacingTileID]
 	call CheckHeadbuttTreeTile
-	jr nz, .surf
+	jr nz, .rock_climb
 	farcall TryHeadbuttOW
	jr c, .done
	jr .noevent
+
+.rock_climb
+	ld a, [wFacingTileID]
+	call CheckRockyWallTile
+	jr nz, .surf
+	farcall TryRockClimbOW
+	jr .done

 .surf
 	farcall TrySurfOW
 	jr nc, .noevent
 	jr .done

 .noevent
 	xor a
 	ret

 .done
 	call PlayClickSFX
 	ld a, $ff
 	scf
 	ret
```

`TryTileCollisionEvent` checks for various relevant collision types, one after another, so we just add a case for rocky walls.

That's it! Now `COLL_ROCKY_WALL` can be used like any other collision type—try assigning it to a block in [data/tilesets/\*_collision.asm](../tree/master/data/tilesets/).

…Although, there aren't any suitable tiles for rocky walls. So let's make some.


## 9. Add rocky walls to a map

Here are some rocky wall tiles edited from [Pokémon Orange](https://github.com/PiaCarrot/pokeorange/):

![Screenshot](screenshots/rocky-wall-tiles.png)

Let's say you want to copy HG/SS and require Rock Climb for an item ball on Route 45. Since [maps/Route45.blk](../blob/master/maps/Route45.blk) uses the `johto` tileset, here's what that would involve:

1. Add the rocky wall tiles to [gfx/tilesets/johto.png](../blob/master/gfx/tilesets/johto.png)
2. Assign the `BROWN` color to those tiles in [gfx/tilesets/johto_palette_map.asm](../blob/master/gfx/tilesets/johto_palette_map.asm)
3. Design a rocky wall block in [data/tilesets/johto_metatiles.bin](../blob/master/data/tilesets/johto_metatiles.bin)
4. Assign the `ROCKY_WALL` collision type to that block in [data/tilesets/johto_collision.asm](../blob/master/data/tilesets/johto_collision.asm)
5. Redesign [maps/Route45.blk](../blob/master/maps/Route45.blk) to use the rocky wall block

You can use [Polished Map](https://github.com/Rangi42/polished-map) to edit maps and tilesets; refer to the [new map](Add-a-new-map-and-landmark) and [new tileset](Add-a-new-tileset) tutorials for more information.

Now test it out!

![Screenshot](screenshots/rock-climb.png)

By the way, if you're walking on top of cliffs, it's possible to walk down onto a cave entrance. That's because the clifftops all use `COLL_FLOOR`, cave entrances use `COLL_CAVE`, and of course it's possible to walk from the former to the latter, since there's no real concept of "elevation" in Gen 2. The solution is to use `COLL_DOWN_WALL` for clifftops above cave entrances. That way you can walk *onto* the space but not *down* from it. (The top edges of cliffs already use `COLL_UP_WALL` so you can't walk between them and the ground level.)