summaryrefslogtreecommitdiff
path: root/Add-weather-icons-when-selecting-a-move.md
blob: 0dcd71bf626831e848bf0e43aed476bbe1309c4e (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
Since Gen 5, the current weather gets displayed during battles on the bottom screen. This tutorial will explain how to do so in Gen 2, more specifically, during move selection. It works by creating a sprite for the weather icon, so you'll also learn how to work with sprite graphics on the Game Boy Color.

## Add the code to display the sprites

Edit [engine/battle/core.asm](../blob/master/engine/battle/core.asm)
```diff
 BattleTurn:
 ...
 .skip_iteration
	call ParsePlayerAction
+	push af
+	call ClearSprites
+	pop af
	jr nz, .loop1
```
```diff
 MoveSelectionScreen:
 ...
 .battle_player_moves
	call MoveInfoBox
+	call GetWeatherImage
	ld a, [wMoveSwapBuffer]
 ...
 .place_textbox_start_over
+	push hl
+	call ClearSprites
+	pop hl
	call StdBattleTextbox
```
There's not much to explain here. These changes are just to clear the sprite when we dont need it and to add the call function to the code below.

Add this function to [engine/battle/core.asm](../blob/master/engine/battle/core.asm)
```
GetWeatherImage:
	ld a, [wBattleWeather]
	and a
	ret z
	cp WEATHER_RAIN
	ld de, RainWeatherImage
	lb bc, PAL_BATTLE_OB_BLUE, 4
	jr z, .done
	cp WEATHER_SUN
	ld de, SunWeatherImage
	ld b, PAL_BATTLE_OB_YELLOW
	jr z, .done
	cp WEATHER_SANDSTORM
	ld de, SandstormWeatherImage
	ld b, PAL_BATTLE_OB_BROWN
	jr z, .done
	ret
	
.done
	push bc
	ld b, BANK(WeatherImages) ; c = 4
	ld hl, vTiles0
	call Request2bpp
	pop bc
	ld hl, wVirtualOAMSprite00
	ld de, .WeatherImageOAMData
.loop
	ld a, [de]
	inc de
	ld [hli], a
	ld a, [de]
	inc de
	ld [hli], a
	dec c
	ld a, c
	ld [hli], a
	ld a, b
	ld [hli], a
	jr nz, .loop
	ret

.WeatherImageOAMData
; positions are backwards since
; we load them in reverse order
	db $88, $1c ; y/x - bottom right
	db $88, $14 ; y/x - bottom left
	db $80, $1c ; y/x - top right
	db $80, $14 ; y/x - top left
```
Request2bpp is an important function. It grabs the image from ROM and places it where you want, usually VRAM. The description of it is kind of weird, but basically `b` is the bank that the image resides, `de` is the address that the image resides, `hl` is where you want to copy it to, and `c` is how many tiles to copy.
If you're wanting to make an image a sprite, `wVirtualOAM` is where you want to go. You don't want to write directly to OAM because that would require specific timings that wouldn't be available all of the time. So, you must load the OAM data into `wVirtualOAM`. Every so often, many times per second actually, the game loads whatever is in `wVirtualOAM` into the actual OAM, when those timings I mentioned are available.
OAM data works like this, each sprite is an 8x8 tile just like the background or map tiles, but they can be put anywhere on the screen. Each sprite uses 4 bytes in this order, Y position, X position, Tile number, Attributes. Look [here](http://gbdev.gg8.se/wiki/articles/Video_Display#VRAM_Sprite_Attribute_Table_.28OAM.29) for a better description of the OAM structure.

## Add the graphics

Add these graphics to gfx/battle/weather

![rain.png](screenshots/rain_icon.png
![sun.png](screenshots/sun_icon.png
![sandstorm.png](screenshots/sandstorm_icon.png

Creat a new file called weather_images.asm in gfx/
```WeatherImages::

RainWeatherImage:
INCBIN "gfx/battle/weather/rain.2bpp"

SunWeatherImage:
INCBIN "gfx/battle/weather/sun.2bpp"

SandstormWeatherImage:
INCBIN "gfx/battle/weather/sand.2bpp"
```

Add this section to [main.asm](../blob/master/main.asm)
```
SECTION "Battle Weather Images", ROMX

INCLUDE "gfx/weather_images.asm"
```

RGBDS will add this section to any free space in a bank unless you add `"Battle WeatherImages"` to [pokecrystal.link](../blob/master/pokecrystal.link).

## Optimize the code

Now, if you plan on not adding any new weather effects or weather icons, optimization is straightforward. Otherwise, there's some tricks you can use to keep the code optimized.

A quick and easy optimzation is to replace the `cp WEATHER_X` in GetWeatherImage to `dec a` like so.
```diff
 GetWeatherImage:
	ld a, [wBattleWeather]
	and a
	ret z
-	cp WEATHER_RAIN
+	dec a
	ld de, RainWeatherImage
	lb bc, PAL_BATTLE_OB_BLUE, 4
	jr z, .done
-	cp WEATHER_SUN
+	dec a
	ld de, SunWeatherImage
	ld b, PAL_BATTLE_OB_YELLOW
	jr z, .done
-	cp WEATHER_SANDSTORM
+	dec a
	ld de, SandstormWeatherImage
	ld b, PAL_BATTLE_OB_BROWN
	jr z, .done
	ret
```

You can do that because WEATHER_RAIN = 0 + 1, WEATHER_SUN = WEATHER_RAIN + 1, and WEATHER_SANDSTORM = WEATHER_SUN + 1.

That format can be continued to be used if whatever new weather effects equal one more than the last.

## Addendum

Here is a pre-made graphic for Hail made by Bronzeswagger if you decide to add Hail to your hack.

![hail.png](screenshots/hail_icon.png)