summaryrefslogtreecommitdiff
path: root/Add-a-new-map-and-landmark.md
blob: e321c44763b81072abb8fbf8c12ea8251a2f0b19 (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
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
This tutorial is for how to add a new map and a new landmark. As an example, we'll add two maps: the outdoor and indoor maps of the Global Terminal. The indoor map will have its own landmark.


## Contents

1. [Plan the map's role in the game](#1-plan-the-maps-role-in-the-game)
2. [Design the map with Polished Map](#2-design-the-map-with-polished-map)
3. [Define a map constant](#3-define-a-map-constant)
4. [Define its group data](#4-define-its-group-data)
   - [Roof type](#roof-type)
   - [Roof palette](#roof-palette)
   - [Outdoor sprite set](#outdoor-sprite-set)
5. [Define its properties](#5-define-its-properties)
6. [Define its attributes](#6-define-its-attributes)
7. [Define its SGB roof palettes](#7-define-its-sgb-roof-palettes)
8. [Define any new landmarks](#8-define-any-new-landmarks)
9. [Write its event scripts](#9-write-its-event-scripts)
10. [Include the block and script data](#10-include-the-block-and-script-data)
11. [Common mistakes](#11-common-mistakes)
    - [Cave entrance/exit warp doesn't work](#cave-entranceexit-warp-doesnt-work)


## 1. Plan the map's role in the game

The Global Terminal in HGSS was a tall building west of Goldenrod City, made for interaction with other players via DS Wi-Fi. That's not possible with the GameBoy Color, but a "global terminal" would also make sense as an inter-regional rest stop for travelers and tourists in a port city. Here's a mockup of what it will look like:

[![Screenshot](screenshots/global-terminal-draft.png)](screenshots/global-terminal-draft.png)

Microsoft Paint is fine for making mockups and plans; [paint.net](https://www.getpaint.net/) is also a good choice, with more features like layers and an undo/redo history.


## 2. Design the map with Polished Map

The maps/\*.blk files that define map layouts can't be edited as text, and hex editing them is inconvenient. So we'll use [Polished Map](https://github.com/Rangi42/polished-map), a program for Windows or Linux that can edit map layouts as well as tilesets. (Editing tilesets is beyond the scope of this tutorial.)

To install Polished Map, just follow the instructions in its [INSTALL.md](https://github.com/Rangi42/polished-map/blob/master/INSTALL.md): download install.bat and polishedmap.exe from the latest release; run install.bat with admin privileges; and delete the downloaded files, since a shortcut to the installed copy of Polished Map should now exist on your Desktop. If you need help using it, read the documentation in the Help menu.

Anyway, create a new map, choosing **pokecrystal** as the project directory (or whatever your pokecrystal-based project happens to be named). Make the new map 10 blocks wide and 13 blocks high, using the `johto_modern` tileset and `goldenrod` roofs. Then draw its blocks like this:

[![maps/GlobalTerminalOutside.blk](screenshots/polished-map-global-terminal-outside.png)](screenshots/polished-map-global-terminal-outside.png)

Save that as **maps/GlobalTerminalOutside.blk**.

(Notice that the roof and walls appear cyan. That's because the `ROOF` color depends on which group a map is in, and we haven't defined a group for this map yet. We'll see how roofs work later.)

Next, open **maps/GoldenrodCity.blk**; its 20x18 size and `johto_modern` tileset should be filled in automatically, but you'll need to manually pick the `goldenrod` roof pattern. Edit its west side to neatly connect with the Global Terminal:

[![maps/GoldenrodCity.blk](screenshots/polished-map-goldenrod-city.png)](screenshots/polished-map-goldenrod-city.png)

Be sure to save your changes.

Now create another new map, 9 blocks wide and 6 blocks high, using the `radio_tower` tileset. Then draw its blocks like this:

[![maps/GlobalTerminal1F.blk](screenshots/polished-map-global-terminal-1f.png)](screenshots/polished-map-global-terminal-1f.png)

Save that as **maps/GlobalTerminal1F.blk**.

When you're designing maps, keep their size below this limit:

(*width* + 6) × (*height* + 6) ≤ 1300

The current map's block data gets loaded into WRAM at the address `wOverworldMapBlocks`, which is declared to have 1300 bytes in [wram.asm](../blob/master/wram.asm). This buffer gets padded on all sides with an extra 3 blocks to load the edges of any connected maps.

It so happens that a 30x30 map will neatly fit into this limit, since (30+6)×(30+6)=1296. However, keep in mind that the official maps are usually designed with the width as a multiple of 10 and the height as a multiple of 9. For example, small towns are often 10x9; large cities are 20x18; routes may be 20x9, or 10x18, or 10x45, or so on; National Park is 20x27; et cetera.


## 3. Define a map constant

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

```diff
 ; map group ids
 ; `newgroup` indexes are for:
 ; - MapGroupPointers (see data/maps/maps.asm)
 ; - MapGroupRoofs (see data/maps/roofs.asm)
 ; - OutdoorSprites (see data/maps/outdoor_sprites.asm)
 ; - RoofPals (see gfx/tilesets/roofs.pal)
 ; `map_const` indexes are for the sub-tables of MapGroupPointers (see data/maps/maps.asm)
 ; Each map also has associated data:
 ; - attributes (see data/maps/attributes.asm)
 ; - blocks (see data/maps/blocks.asm)
 ; - scripts and events (see data/maps/scripts.asm)
 	const_def

	newgroup OLIVINE                                              ;  1
 	map_const OLIVINE_POKECENTER_1F,                        5,  4 ;  1
 	...
	endgroup

 	...

	newgroup CHERRYGROVE                                          ; 26
 	map_const ROUTE_30,                                    10, 27 ;  1
 	...
	endgroup

+	newgroup GLOBAL_TERMINAL                                      ; 27
+	map_const GLOBAL_TERMINAL_OUTSIDE,                     10, 13 ;  1
+	map_const GLOBAL_TERMINAL_1F,                           9,  6 ;  2
+	endgroup

-NUM_MAP_GROUPS EQU const_value ; 26
+NUM_MAP_GROUPS EQU const_value ; 27
```

Map constants have two parts: the group ID and the map ID. Groups are significant for outdoor maps because they share a roof palette and an outdoor sprite set (more on those later). For indoor maps, groups don't really matter, but they're usually grouped with their corresponding outdoor maps for the sake of organization.

The line `map_const GLOBAL_TERMINAL_OUTSIDE, 10, 13` defines four constants at once:

- `GROUP_GLOBAL_TERMINAL_OUTSIDE` is 27, since that's the current group ID
- `MAP_GLOBAL_TERMINAL_OUTSIDE` is 1, since that's the current map ID
- `GLOBAL_TERMINAL_OUTSIDE_WIDTH` is 10
- `GLOBAL_TERMINAL_OUTSIDE_HEIGHT` is 13

The width and height are the size of the map we designed earlier. Now if you open maps/GlobalTerminalOutside.blk in Polished Map, the TitleCase filename "GlobalTerminalOutside" will get matched with the UPPER_CASE constant prefix "GLOBAL_TERMINAL_OUTSIDE", and the 10x13 size will be automatically filled in.

Note that there is no constant named just `GLOBAL_TERMINAL_OUTSIDE`! This can confuse people because there *are* constants simply named `GOLDENROD_CITY`, `NEW_BARK_TOWN`, etc. Those are landmark constants, unrelated to map constants. We'll see what those are used for later.


## 4. Define its group data

Every map in a group shares three things: a roof type, roof palette, and outdoor sprite set. We made a new group for the Global Terminal, so we have to define all of those.

If you're adding a map to an existing group, you can skip this step! Just be aware of what those values already are for that group, since they limit your options for designing outdoor maps.


### Roof type

The roof type controls which nine roof tiles get used. This only applies to maps with the `TILESET_JOHTO`, `TILESET_JOHTO_MODERN`, or `TILESET_BATTLE_TOWER_OUTSIDE` tileset, since they have placeholder roof tiles in the right spot. (Those particular tilesets are [hard-coded](Hard-coded-logic#tilesets-that-have-per-mapgroup-roofs) by `LoadTilesetGFX` in [home/map.asm](../blob/master/home/map.asm).)

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

```diff
 MapGroupRoofs:
 ; entries correspond to map groups
 ; values are indexes for Roofs (see below)
 	table_width 1, MapGroupRoofs
 	db -1             ;  0
 	db ROOF_OLIVINE   ;  1 (Olivine)
 	...
 	db ROOF_NEW_BARK  ; 26 (Cherrygrove)
+	db ROOF_GOLDENROD ; 27 (Global Terminal)
	assert_table_length NUM_MAP_GROUPS + 1
```

Roof tiles, like all graphics, are only loaded when you warp to a map. Walking across map connections, like from Route 34 to Goldenrod City, will not reload graphics. So if two maps are connected, even if they're in different groups, their roof types have to match. We're going to connect the Global Terminal to Goldenrod City's west edge later, so it has to use the same roof type.


### Roof palette

The roof palette affects tiles that use the `ROOF` palette. It only applies to "outdoor" maps: those with the `TOWN` or `ROUTE` environment. (We'll go over environments later.)

Edit [gfx/tilesets/roofs.pal](../blob/master/gfx/tilesets/roofs.pal):

```diff
 ; group 0 (unused)
 	RGB 21,21,21, 11,11,11 ; morn/day
 	RGB 21,21,21, 11,11,11 ; nite

 ...

 ; group 26 (Cherrygrove)
 	RGB 31,14,28, 31,05,21 ; morn/day
 	RGB 14,07,17, 13,00,08 ; nite

+; group 27 (Global Terminal)
+	RGB 16,23,28, 03,15,21 ; morn/day
+	RGB 08,11,21, 02,08,16 ; nite
```

Maps get most of their palettes from [gfx/tilesets/bg_tiles.pal](../blob/master/gfx/tilesets/bg_tiles.pal), but outdoor maps load their `ROOF` palettes from roofs.pal. Only the middle two colors are specified; the lightest and darkest, usually off-white and gray/black, are unchanged from their bg_tiles.pal values.

Unlike tiles, palettes *are* reloaded when you cross a map connection, so the Global Terminal can have a unique roof color.

If you're using a desktop graphics program like Paint, it will show red, green, and blue color channel values from 0 to 255. Color channels on the GameBoy Color range from 0 to 31, so just divide the Paint values by 8 to get the right ones.

To derive "nite" colors from "morn/day" colors, you can take 50% of the red and green values and 75% of the blue value.


### Outdoor sprite set

The outdoor sprite set is the set of sprites it's possible to use in outdoor maps. Indoor maps are all independent, so they load graphics for whichever sprites happen to be used on each map; but outdoor maps can be connected to each other, so it's necessary to define a set of usable sprites that covers all the connected maps.

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

```diff
 OutdoorSprites:
 ; entries correspond to map groups
 	table_width 2, OutdoorSprites
 	dw OlivineGroupSprites
 	...
 	dw CherrygroveGroupSprites
+	dw GlobalTerminalSprites
	assert_table_length NUM_MAP_GROUPS

 ...

+GlobalTerminalSprites:
 GoldenrodGroupSprites:
 	db SPRITE_SUICUNE
 	db SPRITE_SILVER_TROPHY
 	db SPRITE_POKE_BALL
 	db SPRITE_POKEDEX
 	db SPRITE_WILL
 	db SPRITE_KAREN
 	db SPRITE_NURSE
 	db SPRITE_OLD_LINK_RECEPTIONIST
 	db SPRITE_BIG_LAPRAS
 	db SPRITE_BIG_ONIX
 	db SPRITE_SUDOWOODO
 	db SPRITE_BIG_SNORLAX
 	db SPRITE_GRAMPS
 	db SPRITE_YOUNGSTER
 	db SPRITE_OFFICER
 	db SPRITE_POKEFAN_M
 	db SPRITE_DAY_CARE_MON_1
 	db SPRITE_COOLTRAINER_F
 	db SPRITE_ROCKET
 	db SPRITE_LASS
 	db SPRITE_DAY_CARE_MON_2
 	db SPRITE_FRUIT_TREE
 	db SPRITE_SLOWPOKE
```

The Global Terminal is going to be connected to the west edge of Goldenrod City, so they'll have to have identical sprite sets; to save space, they can literally use the same data. Note that, for instance, `OlivineGroupSprites` and `CianwoodGroupSprites` are two different sets but have identical contents, since you can Surf from Olivine City to Cianwood City.

In general you can use this template for defining new sprite sets:

```asm
	; 12 non-walking filler sprites
	db SPRITE_SUICUNE
	db SPRITE_SILVER_TROPHY
	db SPRITE_FAMICOM
	db SPRITE_POKEDEX
	db SPRITE_WILL
	db SPRITE_KAREN
	db SPRITE_NURSE
	db SPRITE_OLD_LINK_RECEPTIONIST
	db SPRITE_BIG_LAPRAS
	db SPRITE_BIG_ONIX
	db SPRITE_SUDOWOODO
	db SPRITE_BIG_SNORLAX
	; 9 walking sprites
	db SPRITE_COOLTRAINER_M
	db SPRITE_COOLTRAINER_F
	db SPRITE_BUG_CATCHER
	db SPRITE_TWIN
	db SPRITE_YOUNGSTER
	db SPRITE_LASS
	db SPRITE_TEACHER
	db SPRITE_BUENA
	db SPRITE_SUPER_NERD
	; 2 non-walking sprites
	db SPRITE_POKE_BALL
	db SPRITE_FRUIT_TREE
```

A sprite set has 23 sprites, but only nine of them can have walking frames. (Replace those nine with whichever ones your particular maps need.) Examining the VRAM in [BGB](http://bgb.bircd.org/) reveals why they're like this:

![VRAM](screenshots/192-tiles-vram.png)

VRAM is divided into six areas, each 128 tiles large. The middle-right area is for sprites' walking frames. 3 frames per sprite (up/down/side) × 4 tiles per frame = 12 tiles per sprite. 9 NPC sprites + the player sprite = 10 sprites = 120 walking frame tiles. (The remaining 8 are used for special effects like emotes, ledge-hopping shadows, rustling grass, fishing rods, etc.)

Notice how text characters are in the middle-left area. This is why, if an NPC is using a sprite from the top-left area that doesn't have walking frames, it will glitch and appear as text when it takes a step.

This may seem annoying to edit. You have to keep connected sets in sync, like `OlivineGroupSprites` and `CianwoodGroupSprites`; you have to ignore the filler sprites like `SPRITE_FAMICOM` to see which sprites actually get used; and you can't use more than nine sprites with walking frames in a set, even if only nine of them actually walk in any of the maps, because you can't determine which nine will have their walking frames loaded. I strongly recommend following [this tutorial](Improve-the-outdoor-sprite-system) to change the system and fix all of those issues.


## 5. Define its properties

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

```diff
 MapGroupPointers::
 ; pointers to the first map of each map group
 	table_width 2, MapGroupPointers
 	dw MapGroup_Olivine     ;  1
 	...
 	dw MapGroup_Cherrygrove ; 26
+	dw MapGroup_GlobalTerminal ; 27
	assert_table_length NUM_MAP_GROUPS

 ...

+MapGroup_GlobalTerminal:
+	table_width MAP_LENGTH, MapGroup_GlobalTerminal
+	map GlobalTerminalOutside, TILESET_JOHTO_MODERN, ROUTE, LANDMARK_GOLDENROD_CITY, MUSIC_GOLDENROD_CITY, FALSE, PALETTE_AUTO, FISHGROUP_SHORE
+	map GlobalTerminal1F, TILESET_RADIO_TOWER, INDOOR, GLOBAL_TERMINAL, MUSIC_GOLDENROD_CITY, FALSE, PALETTE_DAY, FISHGROUP_SHORE
+	assert_table_length NUM_GLOBAL_TERMINAL_MAPS
```

The `map` macro defines these different properties:

- **map name:** The name of the map. For consistency the same name should be used in every label or filename related to a map.
- **tileset:** The tileset used by the map. The tileset constants are defined in [constants/tileset_constants.asm](../blob/master/constants/tileset_constants.asm). `GlobalTerminalOutside` has to use `TILESET_JOHTO_MODERN`, the same tileset as `GoldenrodCity`, because they'll be connected.
- **environment:** The map environment. Environments have various effects; a subtle one is that the graphics for rustling tall grass are only loaded outdoors, and the graphics for pushing Strength boulders are only loaded indoors (so don't place any Strength boulders outdoors). Valid environments are defined in [constants/map_data_constants.asm](../blob/master/constants/map_data_constants.asm):
   - `TOWN`: Outdoors. Can use Fly or Teleport.
   - `ROUTE`: Outdoors. Can use Fly or Teleport.
   - `INDOOR`: Indoors. Can't use the Bicycle.
   - `CAVE`: Indoors. Can use Dig or Escape Rope out to the last outdoor map (with [some hard-coded exceptions](Hard-coded-logic#outdoor-maps-within-indoor-maps-dont-confuse-dig-or-escape-rope)).
   - `ENVIRONMENT_5`: Neither outdoors nor indoors. Can't use the Bicycle.
   - `GATE`: Indoors. Won't show pop-up location name signs.
   - `DUNGEON`: Indoors. Can't use the Bicycle. Can use Dig or Escape Rope just like `CAVE`.
- **location:** Which landmark corresponds to the map. This affects where you appear on the Town Map and what the pop-up location name sign will say. Note that the `LANDMARK_GLOBAL_TERMINAL` landmark hasn't been defined yet; we'll do that later.
- **music:** What music plays on the map. Some music constants can have unusual behavior; if a map plays the wrong music, you can [correct this design flaw](../blob/master/docs/design_flaws.md#music-ids-64-and-80-or-above-have-special-behavior).
- **phone service flag:** `TRUE` if Pokégear phone service is disabled, otherwise `FALSE`.
- **time of day:** Controls the color palette. One of `PALETTE_AUTO`, `PALETTE_MORN`, `PALETTE_DAY`, `PALETTE_NITE`, or `PALETTE_DARK`. `PALETTE_AUTO` is based on the actual time of day. `PALETTE_DARK` requires Flash.
- **fishing group:** Controls the group of wild Pokémon available by fishing. Valid fishing groups are defined in [constants/map_data_constants.asm](../blob/master/constants/map_data_constants.asm):


## 6. Define its attributes

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

```diff
-	map_attributes GoldenrodCity, GOLDENROD_CITY, $35, NORTH | SOUTH
+	map_attributes GoldenrodCity, GOLDENROD_CITY, $35, NORTH | SOUTH | WEST
 	connection north, Route35, ROUTE_35, 5
 	connection south, Route34, ROUTE_34, 5
+	connection west, GlobalTerminalOutside, GLOBAL_TERMINAL_OUTSIDE, 2
+
+	map_attributes GlobalTerminalOutside, GLOBAL_TERMINAL_OUTSIDE, $35, EAST
+	connection east, GoldenrodCity, GOLDENROD_CITY, -2

 ...

 	...
 	map_attributes Route31VioletGate, ROUTE_31_VIOLET_GATE, $00, 0
+	map_attributes GlobalTerminal1F, GLOBAL_TERMINAL_1F, $00, 0
```

The `map_attributes` macro takes four arguments: the map name, map ID, border block, and connections. The name and ID just identify the map; they aren't defining anything important.

The **border block** is the block ID that fills the map's surroundings when you get too close to the edge. Usually it's trees for an outdoor map, water for the ocean, clifftop for a cave, solid black for a house, etc.

The **connections** value is a combination of `NORTH`, `SOUTH`, `WEST`, or `EAST`, or 0 if the map has no connections. Only outdoor maps have connections; they're what let you walk straight from one map to another, without needing to warp via a door or staircase. Whatever connections a map has, it's followed by a `connection` macro for each of them, in north-south-west-east order.

The `connection` macro takes four arguments: the direction, map name, map ID, and sideways offset. Again, the direction, map name, and map ID are just for identification. The **sideways offset** is how many blocks to shift the connected map perpendicular to its direction. A north or south connection gets shifted right/east, a west or east connection gets shifted down/south. (So negative offsets will shift left/west or up/north, respectively.)

If the offset isn't clear, try comparing screenshots of other maps with their own offset values, and base your own connections on similarly aligned ones. In this case, `GLOBAL_TERMINAL_OUTSIDE` is two blocks lower than `GOLDENROD_CITY`, so their offsets are −2 and 2 respecitvely.

(Before November 10, 2018, the `connection` macro took six parameters; instead of a single sideways offset, you had to specify a target offset, source offset, and strip length, which were confusing and harder to calculate. The current macro definition has legacy support for the old one, since in all of the official maps, sideways offset = target offset − source offset, with the strip length being completely redundant. I strongly recommend porting the new macro to any old pokecrystal projects.)


## 7. Define its SGB roof palettes

Even though Pokémon Crystal isn't compatible with the Super Game Boy, there's a table defining roof palettes for this mode and if we don't edit it then we'll get assembly errors when building the ROM, so we need to add the corresponding constant and define its colors.

First, let's edit [data/maps/sgb_roof_pal_inds.asm](../blob/master/data/maps/sgb_roof_pal_inds.asm):

```diff
 MapGroupRoofSGBPalInds:
 ; entries correspond to map groups
	table_width 1, MapGroupRoofSGBPalInds
	db PREDEFPAL_ROUTES
	...
	db PREDEFPAL_CHERRYGROVE
+	db PREDEFPAL_GLOBAL_TERMINAL
	assert_table_length NUM_MAP_GROUPS + 1
```

We've put `PREDEFPAL_GLOBAL_TERMINAL` in the list, but the constant hasn't been defined yet. Let's create it in [constants/scgb_constants.asm](../blob/master/constants/scgb_constants.asm):

```diff
 ; PredefPals indexes (see gfx/sgb/predef.pal)
 ; GetPredefPal arguments (see engine/gfx/color.asm)
	const_def
	const PREDEFPAL_ROUTES
	...
	const PREDEFPAL_DUNGEONS
+	const PREDEFPAL_GLOBAL_TERMINAL
	const PREDEFPAL_NITE
	...
```

Now the only thing left is to define the colors associated to it. Since which colors we choose really don't matter (again, the SGB mode can't be accesed) let's take the ones from Goldenrod City and edit [gfx/sgb/predef.pal](../blob/master/gfx/sgb/predef.pal):

```diff
	RGB 31,31,31, 22,25,19, 16,21,30, 00,00,00 ; PREDEFPAL_ROUTES
	...
	RGB 31,31,31, 21,14,09, 15,20,20, 00,00,00 ; PREDEFPAL_DUNGEONS
+	RGB 31,31,31, 29,26,18, 15,20,31, 00,00,00 ; PREDEFPAL_GLOBAL_TERMINAL
	RGB 31,31,31, 12,28,22, 15,20,20, 00,00,00 ; PREDEFPAL_NITE
	...
```


## 8. Define any new landmarks

If you don't need any new landmarks, skip this step.

We assigned the `GlobalTerminal1F` map to the new `GLOBAL_TERMINAL` landmark (like how the Radio Tower gets its own landmark), so let's add that next.

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

```diff
 ; Landmarks indexes (see data/maps/landmarks.asm)
 	const_def
  	const LANDMARK_SPECIAL       ; 00
 ; Johto landmarks
 	...
 	const LANDMARK_RADIO_TOWER       ; 11
+	const LANDMARK_GLOBAL_TERMINAL
 	const LANDMARK_ROUTE_35          ; 12
 	...
```

The Town Map will cycle through landmarks in their constant order.

Now edit [data/maps/landmarks.asm](../blob/master/data/maps/landmarks.asm):

```diff
 Landmarks:
 ; entries correspond to constants/landmark_constants.asm
 	table_width 4, Landmarks
 	landmark  -8, -16, SpecialMapName
 	landmark 140, 100, NewBarkTownName
 	...
 	landmark  50,  92, RadioTowerName
+	landmark  44,  92, GlobalTerminalName
 	landmark  52,  76, Route35Name
 	...
 	landmark 140, 116, FastShipName
	assert_table_length NUM_LANDMARKS

 NewBarkTownName:     db "NEW BARK¯TOWN@"
 ...
 SpecialMapName:      db "SPECIAL@"
+GlobalTerminalName:  db "GLOBAL¯TERMINAL@"
```

The two numbers passed to the `landmark` macro are the X and Y coordinates on the Town Map, in pixels from the top-left corner of the screen.

Note the use of "¯" in some landmark names. That character gets treated as a line break in the Town Map, but as a space in pop-up location name signs.


## 9. Write its event scripts

Create **maps/GlobalTerminalOutside.asm**:

```diff
+	object_const_def
+	const GLOBALTERMINALOUTSIDE_ROCKET
+
+GlobalTerminalOutside_MapScripts:
+	def_scene_scripts
+
+	def_callbacks
+
+GlobalTerminalOutside_MapEvents:
+	db 0, 0 ; filler
+
+	def_warp_events
+	warp_event  8, 13, GLOBAL_TERMINAL_1F, 1
+
+	def_coord_events
+
+	def_bg_events
+
+	def_object_events
+	object_event 24, 16, SPRITE_ROCKET, SPRITEMOVEDATA_STANDING_UP, 0, 0, -1, -1, 0, OBJECTTYPE_SCRIPT, 0, GoldenrodCityRocketScoutScript, EVENT_GOLDENROD_CITY_ROCKET_SCOUT
```

And create **maps/GlobalTerminal1F.asm**:

```diff
+	object_const_def
+
+GlobalTerminal1F_MapScripts:
+	def_scene_scripts
+
+	def_callbacks
+
+GlobalTerminal1F_MapEvents:
+	db 0, 0 ; filler
+
+	def_warp_events
+	warp_event  8, 11, GLOBAL_TERMINAL_OUTSIDE, 1
+	warp_event  9, 11, GLOBAL_TERMINAL_OUTSIDE, 1
+
+	def_coord_events
+
+	def_bg_events
+
+	def_object_events
```

The only events defined so far are warps, so you can use the doors into and out of the Global Terminal building. (Their coordinates can be found with Polished Map's "Event Cursor" tool.)

(There's also one `object_event` in GlobalTerminalOutside.asm: a Team Rocket scout copied from GoldenrodCity.asm with only the coordinates changed. That NPC is close enough to the west edge of Goldenrod that it can be seen while you're standing in the Global Terminal map. But NPCs on connected maps aren't visible, so a copy had to be made.)

Writing event scripts is beyond the scope of this tutorial, but you can refer to [docs/map_event_scripts.md](../blob/master/docs/map_event_scripts.md) and [docs/event_commands.md](../blob/master/docs/event_commands.md) for help, and of course use existing map scripts for reference.

You'll probably want a variety of NPCs in the Global Terminal, some from regions beyond Johto and Kanto, maybe with unique items and Pokémon to trade. It's a tall building, with room for more floors than just the one in this example. Or, of course, design your own map. :P

Note that before August 2020, maps did not have `def_*` macros, so they had to manually declare their quantities of `scene_script`s, `callback`s, `warp_event`s, etc. So instead of `def_warp_events`, you would have `db 1` or `db 2`, depending on how many `warp_event`s the map has. If any of those `db` values were wrong, the map could glitch or crash when you enter it.


## 10. Include the block and script data

We created some new files in maps/, but they aren't `INCLUDE`d in the project yet.

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

```diff
+SECTION "Map Blocks 4", ROMX
+
+GlobalTerminalOutside_Blocks:
+	INCBIN "maps/GlobalTerminalOutside.blk"
+
+GlobalTerminal1F_Blocks:
+	INCBIN "maps/GlobalTerminal1F.blk"
```

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

```diff
 SECTION "Map Scripts 25", ROMX
 
 INCLUDE "maps/SilverCaveOutside.asm"
 INCLUDE "maps/Route10North.asm"
+INCLUDE "maps/GlobalTerminalOutside.asm"
+INCLUDE "maps/GlobalTerminal1F.asm"
```

It doesn't really matter which `SECTION` these files go in. You can make new ones to keep them organized, or just keep filling the existing sections until they run out of space. (If `make` gives you a "Section is too big" or "Unable to place section in bank" error, you've overfilled a bank.)

Anyway, we're done!

![Screenshot](screenshots/global-terminal.png)


## 11. Common mistakes

...Well, hopefully we're done. You may be having issues with some aspects of new maps. Here are some common ones and their fixes.

### Cave entrance/exit warp doesn't work

The glowing yellow cave mouth *looks* like what warps you in and out, but it's not. The actual `warp_event` is placed right above it, on block $24 of the `cave` or `dark_cave` tilesets. This block looks just like block $02, the regular floor block, but it has the `WARP_CARPET_DOWN` collision in the bottom-right corner above where the cave mouth would be.

![Screenshot](screenshots/cave-warp.png)