summaryrefslogtreecommitdiff
path: root/Add-a-new-overworld-sprite.md
blob: e3e209e32d7c86074de17ce46edc35746364fe4a (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
This tutorial is for how to add a new overworld sprite. As an example, we'll add three different kinds of sprites.


## Contents

1. [Know which kind of sprite you need](#1-know-which-kind-of-sprite-you-need)
2. [Define a sprite constant](#2-define-a-sprite-constant)
3. [Update files depending on the kind of sprite](#3-update-files-depending-on-the-kind-of-sprite)
   - [Regular sprite: define graphics and properties](#regular-sprite-define-graphics-and-properties)
   - [Pokémon sprite: define corresponding Pokémon](#pokémon-sprite-define-corresponding-pokémon)
   - [Variable sprite: initialize appearance](#variable-sprite-initialize-appearance)


## 1. Know which kind of sprite you need

There are three kinds of overworld sprites:

- **Regular sprites** have their own individual graphics.
- **Pokémon sprites** reuse the menu icons for party Pokémon.
- **Variable sprites** do not have any graphics, but can appear as any other sprite. (The sprite they appear as can be changed, hence "variable".)


## 2. Define a sprite constant

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

```diff
 ; sprite ids
 ; OverworldSprites indexes (see data/sprites/sprites.asm)
 	const_def
 	const SPRITE_NONE ; 00
 	...
 	const SPRITE_STANDING_YOUNGSTER ; 66
+	const SPRITE_GIOVANNI

 ; SpriteMons indexes (see data/sprites/sprite_mons.asm)
 	const_def $80
 SPRITE_POKEMON EQU const_value
 	const SPRITE_UNOWN ; 80
 	...
 	const SPRITE_HO_OH ; a2
+	const SPRITE_EGG

 ; special GetMonSprite values (see engine/overworld/overworld.asm)
 	const_def $e0
 	const SPRITE_DAY_CARE_MON_1 ; e0
 	const SPRITE_DAY_CARE_MON_2 ; e1

 ; wVariableSprites indexes (see wram.asm)
 	const_def $f0
 SPRITE_VARS EQU const_value
 	const SPRITE_CONSOLE ; f0
 	...
 	const SPRITE_JANINE_IMPERSONATOR ; fc
+	const SPRITE_LOOKER
```

We've defined three new sprites: `SPRITE_GIOVANNI` is regular, `SPRITE_EGG` is a Pokémon, and `SPRITE_LOOKER` is variable. (The intention is that [Looker](https://bulbapedia.bulbagarden.net/wiki/Looker), the International Police officer, can appear in disguise.)

The Pokémon sprites all come after defining `SPRITE_POKEMON`, and the variable sprites after `SPRITE_VARS`. Notice how their exact starting values are set by `const_def`; the particular values don't matter, so for example, if you need space for more Pokémon sprites you can lower the `SPRITE_POKEMON` starting value (thus eating into slots which could otherwise have been used for regular sprites).


## 3. Update files depending on the kind of sprite

Each kind of sprite uses data in different files.


### Regular sprite: define graphics and properties

First, create **gfx/sprites/giovanni.png**:

![gfx/sprites/giovanni.png](screenshots/gfx-sprites-giovanni.png)

Then edit [gfx/sprites.asm](../blob/master/gfx/sprites.asm):

```diff
+SECTION "Sprites 3", ROMX
+
+GiovanniSpriteGFX:: INCBIN "gfx/sprites/giovanni.2bpp"
```

It doesn't matter where new sprite graphics go, so you can add them in the existing sections or create new ones. New sections will automatically be placed wherever they'll fit when you run `make`, so you don't have to deal with bank overflow errors.

Finally, edit [data/sprites/sprites.asm](../blob/master/data/sprites/sprites.asm):

```diff
 OverworldSprites:
 ; entries correspond to SPRITE_* constants
 	overworld_sprite ChrisSpriteGFX, 12, WALKING_SPRITE, PAL_OW_RED
 	...
 	overworld_sprite StandingYoungsterSpriteGFX, 12, STANDING_SPRITE, PAL_OW_BLUE
+	overworld_sprite GiovanniSpriteGFX, 12, WALKING_SPRITE, PAL_OW_BROWN
```

The `overworld_sprite` macro takes four arguments:

- **pointer:** The label of the sprite graphics.
- **length:** How many tiles the sprite uses, not counting alternate walking frames. A single frame is 16x16 pixels and 2x2 = 4 tiles; a standing or walking sprite has three basic frames, so 12 tiles total.
- **type:** Either `WALKING_SPRITE`, `STANDING_SPRITE`, or `STILL_SPRITE`.
- **palette:** The default color palette for overworld events that don't assign a particular one.

Note that `BigSnorlaxSpriteGFX`, `BigLaprasSpriteGFX`, and `BigOnixSpriteGFX` do not have the usual three-frame structure (facing down, up, and to the side), but they still use the `STANDING_SPRITE` type. This is because the type just affects how many tiles get loaded when the sprite is used. NPC events in map scripts that use these sprites will also use the movement functions `SPRITEMOVEDATA_BIGDOLL`, `SPRITEMOVEDATA_BIGDOLLSYM` (for the symmetrical Snorlax or Lapras), or `SPRITEMOVEDATA_BIGDOLLASYM` (for the asymmetrical Onix). Different movement functions can make display the sprites' tiles in different ways than the usual 2-by-2 NPC structure. (Designing your own nonstandard sprites is beyond the scope of this tutorial.)


### Pokémon sprite: define corresponding Pokémon

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

```diff
 SpriteMons:
 ; entries correspond to SPRITE_* constants past SPRITE_POKEMON
 	db UNOWN
 	...
 	db HO_OH
+	db EGG
```

This means that `SPRITE_EGG` will use the same menu icon as `EGG`, just like `SPRITE_UNOWN` uses the icon for `UNOWN`, etc.

There's one problem: `EGG` doesn't actually *have* a defined menu icon, since the party menu code treats Eggs as a special case. So edit [data/pokemon/menu_icons.asm](../blob/master/data/pokemon/menu_icons.asm):

```diff
 MonMenuIcons:
 	db ICON_BULBASAUR   ; BULBASAUR
 	...
 	db ICON_HUMANSHAPE  ; CELEBI
+	db ICON_MONSTER     ; MON_FC
+	db ICON_EGG         ; EGG
+	db ICON_MONSTER     ; MON_FE
```

Now `EGG` (and the two unused Pokémon slots) has its menu icon defined in the usual way, so `SPRITE_EGG` will appear correctly.


### Variable sprite: initialize appearance

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

```diff
 InitializeEventsScript:
 	...
 	variablesprite SPRITE_WEIRD_TREE, SPRITE_SUDOWOODO
 	...
 	variablesprite SPRITE_JANINE_IMPERSONATOR, SPRITE_LASS
+	variablesprite SPRITE_LOOKER, SPRITE_ROCKET
```

`InitializeEventsScript` is called once at the very start of the game. It sets a lot of events, since they're all unset by default, and initializes how variable sprites will look.

The variable sprites' appearances are stored in `wVariableSprites` in [wram.asm](../blob/master/wram.asm). We don't need to edit that, since it's automatically sized to fit all the variable sprites.

Note that if you change the `const_def` before `SPRITE_VARS` to fit more (or fewer) variable sprites, the size of `wVariableSprites` will change, and it might get too big to fit in its bank. Then you'll have to find unused space in wram.asm to delete (like the `ds 40` a few lines above `wVariableSprites`).

When event scripts use variable sprites, they use the `variablesprite` command to assign a new appearance, followed by `special LoadUsedSpritesGFX` if a sprites needs to visibly change its appearance. For example, in [maps/FuchsiaPokecenter1F.asm](../blob/master/maps/FuchsiaPokecenter1F.asm):

```
	variablesprite SPRITE_JANINE_IMPERSONATOR, SPRITE_JANINE
	special LoadUsedSpritesGFX
	...
	variablesprite SPRITE_JANINE_IMPERSONATOR, SPRITE_LASS
	special LoadUsedSpritesGFX
```

Anyway, that's all we need to do. Now the new `SPRITE_*` constants can be used just like any others.

![Screenshot](screenshots/overworld-sprites.png)