summaryrefslogtreecommitdiff
path: root/Add-Hail-as-a-new-weather-condition.md
blob: 96552c08b03c0f23e849b1cd8557c21bbca8147f (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
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
This tutorial is for how to add Hail as a new weather condition. Though it focuses on a specific weather condition, this can be used as a guideline to add any other crazy and wacky weather you wish.
Since Hail has a lot of similarities to Sandstorm, we can use it as a template in which we base our modifications on.


## Contents

1. [Define some new weather constants](#1-define-some-new-weather-constants)
2. [Add new text related to the weather condition](#2-add-new-text-related-to-the-weather-condition)
3. [Add damage-inflicting effect](#3-add-damage-inflicting-effect)
4. [Add Blizzard accuracy bypass effect](#4-add-blizzard-accuracy-bypass-effect)
5. [Halve Solar Beam's power during Hail](#5-halve-solar-beams-power-during-hail)
6. [Add move that triggers the weather condition](#6-add-move-that-triggers-the-weather-condition)
7. [Teach the AI how to use this weather effectively](#7-teach-the-ai-how-to-use-this-weather-effectively)
8. [Make it look flashy!](#8-make-it-look-flashy)


## 1. Define some new weather constants

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

```diff
; values in wBattleWeather
	const_def
	const WEATHER_NONE
	const WEATHER_RAIN
	const WEATHER_SUN
	const WEATHER_SANDSTORM
+	const WEATHER_HAIL
	const WEATHER_RAIN_END
	const WEATHER_SUN_END
	const WEATHER_SANDSTORM_END
+	const WEATHER_HAIL_END
```


## 2. Add new text related to the weather condition

We need to create some new battle text to go along with the most relevant effects that our weather condition shall have (such as when it is started/ended, etc).

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

```diff
 BattleText_TheSandstormRages:
	text "The sandstorm"
	line "rages."
	prompt
 
+BattleText_HailContinuesToFall:
+	text "Hail continues to"
+	line "fall."
+	prompt
+
 BattleText_TheRainStopped:
	text "The rain stopped."
	prompt

	...

 BattleText_TheSandstormSubsided:
	text "The sandstorm"
	line "subsided."
	prompt
 
+BattleText_TheHailStopped:
+	text "The hail stopped."
+	prompt
+
 BattleText_EnemyMonFainted:
	text "Enemy @"
	text_ram wEnemyMonNick

	...

 BattleText_NoTimeLeftToday: ; unreferenced
	text "There is no time"
	line "left today!"
	done

+ItStartedToHailText:
+	text "It started"
+	line "to hail!"
+	prompt
+
+PeltedByHailText:
+	text "<USER>"
+	line "is pelted by HAIL!"
+	prompt
+
```

## 3. Add damage-inflicting effect

Using Sandstorm as a guideline, we can create the actual effects of this new weather condition. This means inflicting some damage to all Pokémon, possibly excluding Ice-types. For Sandstorm, this is done core.asm.

Edit `HandleWeather` in [engine/battle/core.asm](../blob/master/engine/battle/core.asm):

```diff
 HandleWeather:
	...
	ld hl, wWeatherCount
	dec [hl]
-	jr z, .ended
+	jr nz, .continues

+; ended
+	ld hl, .WeatherEndedMessages
+	call .PrintWeatherMessage
+	xor a
+	ld [wBattleWeather], a
+	ret
+
+.continues
	ld hl, .WeatherMessages
	call .PrintWeatherMessage

	ld a, [wBattleWeather]
	cp WEATHER_SANDSTORM
-	ret nz
+	jr nz, .check_hail
 
	ldh a, [hSerialConnectionStatus]
	cp USING_EXTERNAL_CLOCK
	jr z, .enemy_first

	...

	ld hl, SandstormHitsText
	jp StdBattleTextbox

-.ended
-	ld hl, .WeatherEndedMessages
-	call .PrintWeatherMessage
-	xor a
-	ld [wBattleWeather], a
-	ret
+.check_hail
+	ld a, [wBattleWeather]
+	cp WEATHER_HAIL
+	ret nz
+
+	ldh a, [hSerialConnectionStatus]
+	cp USING_EXTERNAL_CLOCK
+	jr z, .enemy_first_hail
+
+; player first
+	call SetPlayerTurn
+	call .HailDamage
+	call SetEnemyTurn
+	jr .HailDamage
+
+.enemy_first_hail
+	call SetEnemyTurn
+	call .HailDamage
+	call SetPlayerTurn
+
+.HailDamage:
+	ld a, BATTLE_VARS_SUBSTATUS3
+	call GetBattleVar
+	bit SUBSTATUS_UNDERGROUND, a
+	ret nz
+
+	ld hl, wBattleMonType1
+	ldh a, [hBattleTurn]
+	and a
+	jr z, .ok1
+	ld hl, wEnemyMonType1
+.ok1
+	ld a, [hli]
+	cp ICE
+	ret z
+
+	ld a, [hl]
+	cp ICE
+	ret z
+
+	call GetSixteenthMaxHP
+	call SubtractHPFromUser
+
+	ld hl, PeltedByHailText
+	jp StdBattleTextbox

 .PrintWeatherMessage:
	ld a, [wBattleWeather]

	...

 .WeatherMessages:
 ; entries correspond to WEATHER_* constants
	dw BattleText_RainContinuesToFall
	dw BattleText_TheSunlightIsStrong
	dw BattleText_TheSandstormRages
+	dw BattleText_HailContinuesToFall

 .WeatherEndedMessages:
 ; entries correspond to WEATHER_* constants
	dw BattleText_TheRainStopped
	dw BattleText_TheSunlightFaded
	dw BattleText_TheSandstormSubsided
+	dw BattleText_TheHailStopped
 ...
```

Some things to note. The `.ended` branch was moved up so as to avoid an unnecessary `jp` instruction after adding the Hail handling, and moves it closer to where the actual weather count check is made. If the weather effect is otherwise still continuing, then the code jumps to the `.continues` branch to execute the right weather effect.

Most of the code for Hail is copied from the Sandstorm handling, with exception of the text to print and the types that are unaffected. Additionally, the animation is removed because we have yet to add any fancy visuals to the new effects (this will optionally be added later). Lastly, the actual battle text data we added in the previous step are referenced for use here.


## 4. Add Blizzard accuracy bypass effect

Another effect of Hail is making it so that Blizzard does not miss when it is active. We can handle this the same way that the game handles Thunder accuracy under the effects of rain.

First we should associate Blizzard with a new specific move effect, which will be subject to the Hail accuracy handling we will implement. (More detail on this process in [this tutorial](https://github.com/pret/pokecrystal/wiki/Add-a-new-move-effect)).

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

```diff
 ; MoveEffectsPointers indexes (see data/moves/effects_pointers.asm)
	const_def
	...
	const EFFECT_BEAT_UP
	const EFFECT_FLY
	const EFFECT_DEFENSE_CURL
+	const EFFECT_BLIZZARD
 NUM_MOVE_EFECTS EQU const_value
```

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

```diff
 Moves:
 ; entries correspond to constants/move_constants.asm
	...
	move ICE_BEAM,     EFFECT_FREEZE_HIT,         95, ICE,          100, 10,  10
-	move BLIZZARD,     EFFECT_FREEZE_HIT,        120, ICE,           70,  5,  10
+	move BLIZZARD,     EFFECT_BLIZZARD,          120, ICE,           70,  5,  10
	move PSYBEAM,      EFFECT_CONFUSE_HIT,        65, PSYCHIC_TYPE, 100, 20,  10
```

For the effect pointer, we will reuse FreezeHit, since for the purposes of what commands the move will call, it is functionally identical to that effect. We don't need to copy it for a new redundant effect.

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

```diff
 MoveEffectsPointers:
 ; entries correspond to EFFECT_* constants
	...
	dw BeatUp
	dw Fly
	dw DefenseCurl
+	dw FreezeHit ; for Blizzard, purposefully with different EFFECT_* constant
	assert_table_length NUM_MOVE_EFECTS
```

Now we can check for this move effect when performing the accuracy checks, similar to how Thunder works in rain.

Edit `BattleCommand_CheckHit` in [engine/battle/effect_commands.asm](../blob/master/engine/battle/effect_commands.asm):

```diff
 BattleCommand_CheckHit:
	...
	call .ThunderRain
	ret z
 
+	call .BlizzardHail
+	ret z
+
	call .XAccuracy
	ret nz
 
	...

	cp WEATHER_RAIN
	ret
 
+.BlizzardHail:
+; Return z if the current move always hits in hail, and it is hailing.
+	ld a, BATTLE_VARS_MOVE_EFFECT
+	call GetBattleVar
+	cp EFFECT_BLIZZARD
+	ret nz
+
+	ld a, [wBattleWeather]
+	cp WEATHER_HAIL
+	ret
+
 .XAccuracy:
	ld a, BATTLE_VARS_SUBSTATUS4
	call GetBattleVar
	...
```

`BattleCommand_CheckHit` is the routine which checks/decides whether any move (with some exceptions) will connect or not. There are special cases, such as Thunder in rain or having the "Locked-On" substatus. Here we add a subroutine which checks whether it's Blizzard (or more specifically, a move that has the effect EFFECT_BLIZZARD) and it's hailing, in which case it completely bypasses the accuracy check.

## 5. Halve Solar Beam's power during Hail

During hail, Solar Beam's power is reduced by 50%, so we need to implement this. Go to [data/battle/weather_modifiers.asm](../blob/master/data/battle/weather_modifiers.asm):

```diff
 WeatherTypeModifiers:
	db WEATHER_RAIN, WATER, MORE_EFFECTIVE
	db WEATHER_RAIN, FIRE,  NOT_VERY_EFFECTIVE
	db WEATHER_SUN,  FIRE,  MORE_EFFECTIVE
	db WEATHER_SUN,  WATER, NOT_VERY_EFFECTIVE
	db -1 ; end

 WeatherMoveModifiers:
	db WEATHER_RAIN, EFFECT_SOLARBEAM, NOT_VERY_EFFECTIVE
+	db WEATHER_HAIL, EFFECT_SOLARBEAM, NOT_VERY_EFFECTIVE
	db -1 ; end
```

## 6. Add move that triggers the weather condition

We have successfully added a weather condition that we can never trigger. Let's fix that by introducing a new move, Hail. You can follow [this tutorial](https://github.com/pret/pokecrystal/wiki/Add-a-new-move) to learn how to add a new move, with the caveat that it should have a new move effect which we will implement, EFFECT_HAIL. Its battle properties are `HAIL, EFFECT_HAIL, 0, ICE, 100, 10, 0`. Let's define what this effect does.

Modify [constants/move_effect_constants.asm](../blob/master/constants/move_effect_constants.asm) again:

```diff
 ; MoveEffectsPointers indexes (see data/moves/effects_pointers.asm)
	const_def
	...
	const EFFECT_BEAT_UP
	const EFFECT_FLY
	const EFFECT_DEFENSE_CURL
	const EFFECT_BLIZZARD
+	const EFFECT_HAIL
 NUM_MOVE_EFECTS EQU const_value
```

Edit [data/moves/effects_pointers.asm](../blob/master/data/moves/effects_pointers.asm) again:

```diff
MoveEffectsPointers:
; entries correspond to EFFECT_* constants
	...
	dw BeatUp
	dw Fly
	dw DefenseCurl
	dw FreezeHit ; for Blizzard, purposefully with different EFFECT_* constant
+	dw Hail
	assert_table_length NUM_MOVE_EFECTS
```

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

```diff
 MoveEffects: ; used only for BANK(MoveEffects)

 ...

 DefenseCurl:
	checkobedience
	usedmovetext
	doturn
	defenseup
	curl
	lowersub
	statupanim
	raisesub
	statupmessage
	statupfailtext
	endmove

+Hail:
+	checkobedience
+	usedmovetext
+	doturn
+	starthail
+	endmove
+
```

Edit [macros/scripts/battle_commands.asm](../blob/master/macros/scripts/battle_commands.asm):

```diff
 ; BattleCommandPointers indexes (see data/battle/effect_command_pointers.asm)
	...
 	command supereffectivelooptext  ; ad
 	command startloop               ; ae
 	command curl                    ; af
+	command starthail               ; b0
NUM_EFFECT_COMMANDS EQU const_value - 1

	const_def -1, -1
	command endmove                 ; ff
	command endturn                 ; fe
```

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

```diff
 BattleCommandPointers:
 ; entries correspond to macros/scripts/battle_commands.asm
	...
	dw BattleCommand_SuperEffectiveLoopText
	dw BattleCommand_StartLoop
	dw BattleCommand_Curl
+	dw BattleCommand_StartHail
	assert_table_length NUM_EFFECT_COMMANDS
```

Here we introduced a new effect for starting the hail weather condition, and associated it to a battle command routine which will be called when the move is used successfully. Again we can draw inspiration from the Sandstorm related routine, `BattleCommand_StartSandstorm`.

Create [engine/battle/move_effects/hail.asm](../blob/master/engine/battle/move_effects/hail.asm):

```diff
+BattleCommand_StartHail:
+; starthail
+
+	ld a, [wBattleWeather]
+	cp WEATHER_HAIL
+	jr z, .failed
+
+	ld a, WEATHER_HAIL
+	ld [wBattleWeather], a
+	ld a, 5
+	ld [wWeatherCount], a
+	ld hl, ItStartedToHailText
+	jp StdBattleTextbox
+
+.failed
+	call AnimateFailedMove
+	jp PrintButItFailed
+
```

Edit [engine/battle/effect_commands.asm](../blob/master/engine/battle/effect_commands.asm) again:

```diff
 INCLUDE "engine/battle/move_effects/future_sight.asm"

 INCLUDE "engine/battle/move_effects/thunder.asm"

+INCLUDE "engine/battle/move_effects/hail.asm"

 CheckHiddenOpponent:
	...
```

This routine simply loads the weather with the hail constant we defined, and sets its remaining turns to 5; in case hail is already set up, it'll fail. The function also prints text depending on what happens. For all practical purposes, our new weather is now implemented.
If you run this at this stage, the new move is functional and the effects work as intended, but we can still do some extra steps in order to polish it. The rest of the sections should be considered optional.


## 7. Teach the AI how to use this weather effectively

There is already some rudimentary logic on how the AI uses the other weather effects. Let's implement some basic checking to have the AI also use Hail in a (minimally) effective manner.

Modify [engine/battle/ai/redundant.asm](../blob/master/engine/battle/ai/redundant.asm):

```diff
 .Moves:	
	...
	dbw EFFECT_MOONLIGHT,    .Moonlight
	dbw EFFECT_SWAGGER,      .Swagger
	dbw EFFECT_FUTURE_SIGHT, .FutureSight
+	dbw EFFECT_HAIL,         .Hail
	db -1

	...
 
+.Hail:
+	ld a, [wBattleWeather]
+	cp WEATHER_HAIL
+	jr z, .Redundant
+	jr .NotRedundant
+
 .Heal:
 .MorningSun:
 .Synthesis:
 .Moonlight:
	...
```

This file lists some moves that the AI can quickly check for redundancy. Hail has a quick redundancy check in which, if it's hailing, then the move should be dismissed.

Edit [engine/battle/ai/scoring.asm](../blob/master/engine/battle/ai/scoring.asm):

```diff
 AI_Smart_EffectHandlers:
	...
	dbw EFFECT_SOLARBEAM,        AI_Smart_Solarbeam
	dbw EFFECT_THUNDER,          AI_Smart_Thunder
	dbw EFFECT_FLY,              AI_Smart_Fly
+	dbw EFFECT_HAIL,             AI_Smart_Hail
	db -1 ; end

	...
 
 .SandstormImmuneTypes:
	db ROCK
	db GROUND
	db STEEL
	db -1 ; end

+AI_Smart_Hail:
+; Greatly discourage this move if the player is immune to Hail damage.
+	ld a, [wBattleMonType1]
+	cp ICE
+	jr z, .greatly_discourage
+
+	ld a, [wBattleMonType2]
+	cp ICE
+	jr z, .greatly_discourage
+
+; Discourage this move if player's HP is below 50%.
+	call AICheckPlayerHalfHP
+	jr nc, .discourage
+
+; Encourage move if AI has good Hail moves
+	push hl
+	ld hl, .GoodHailMoves
+	call AIHasMoveInArray
+	pop hl
+	jr c, .encourage
+
+; 50% chance to encourage this move otherwise.
+	call AI_50_50
+	ret c
+
+.encourage
+	dec [hl]
+	ret
+
+.greatly_discourage
+	inc [hl]
+.discourage
+	inc [hl]
+	ret
+
+.GoodHailMoves
+	db BLIZZARD
+	db -1 ; end
+
 AI_Smart_Endure:
	ld a, [wEnemyProtectCount]
	and a
```

We base this behavior on the Sunny Day/Rain Dance and Sandstorm AI-related routines. The AI will avoid using the move if the player is immune to Hail or has low HP, and will encourage the move if it has any "Good Hail moves", which right now is only composed of the move Blizzard. This list is fully extensible with other moves.


## 8. Make it look flashy!

The move and weather have no special animations. It's completely possible to reuse some other move animation (such as Powder Snow), but we can quickly whip something up with the resources we already have at our disposal. The Sandstorm animation already works well as a "weather hazard," and there are some sprites representing ice, so let's make use of them.

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

```diff
 ; BattleAnimObjects indexes (see data/battle_anims/objects.asm)
	const_def
	...
	const ANIM_OBJ_PLAYERHEAD_1ROW
	const ANIM_OBJ_ENEMYFEET_2ROW
	const ANIM_OBJ_PLAYERHEAD_2ROW
+	const ANIM_OBJ_HAIL
 NUM_ANIM_OBJS EQU const_value
 
 ; BattleAnimFrameData indexes (see data/battle_anims/framesets.asm)
	const_def
	...
	const BATTLEANIMFRAMESET_B6
	const BATTLEANIMFRAMESET_B7
	const BATTLEANIMFRAMESET_B8
+	const BATTLEANIMFRAMESET_HAIL
 NUM_BATTLEANIMFRAMESETS EQU const_value
 
 ; BattleAnimOAMData indexes (see data/battle_anims/oam.asm)
	const_def
	...
	const BATTLEANIMOAMSET_D5
	const BATTLEANIMOAMSET_D6
	const BATTLEANIMOAMSET_D7
+	const BATTLEANIMOAMSET_HAIL
 NUM_BATTLEANIMOAMSETS EQU const_value
```

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

```diff
 BattleAnimFrameData:
 ; entries correspond to BATTLEANIMFRAMESET_* constants
	...
	dw .Frameset_b6 ; BATTLEANIMFRAMESET_B6
	dw .Frameset_b7 ; BATTLEANIMFRAMESET_B7
	dw .Frameset_b8 ; BATTLEANIMFRAMESET_B8
+	dw .Frameset_Hail ; BATTLEANIMFRAMESET_HAIL
	assert_table_length NUM_BATTLEANIMFRAMESETS
 
	...

.Frameset_b8:
	frame BATTLEANIMOAMSET_D7,  8
	endanim
+
+.Frameset_Hail:
+	frame BATTLEANIMOAMSET_HAIL, 32
+	endanim
```

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

```diff
 BattleAnimOAMData:
 ; entries correspond to BATTLEANIMOAMSET_* constants
	...
	battleanimoam $00,  6, .OAMData_d5 ; BATTLEANIMOAMSET_D5
	battleanimoam $00, 14, .OAMData_d6 ; BATTLEANIMOAMSET_D6
	battleanimoam $00, 12, .OAMData_d7 ; BATTLEANIMOAMSET_D7
+	battleanimoam $00, 13, .OAMData_Hail ; BATTLEANIMOAMSET_HAIL
	assert_table_length NUM_BATTLEANIMOAMSETS
 
	...

	dbsprite   6,  -2, 4, 0, $00, $0
	dbsprite   8,  -4, 4, 0, $00, $0
	dbsprite  10,  -2, 4, 0, $00, $0

+.OAMData_Hail:
+	dbsprite -13,  -2, 4, 0, $04, $0
+	dbsprite -11,  -4, 4, 0, $04, $0
+	dbsprite  -9,  -1, 4, 0, $04, $0
+	dbsprite  -7,  -5, 4, 0, $04, $0
+	dbsprite  -5,  -3, 4, 0, $04, $0
+	dbsprite  -3,  -5, 4, 0, $04, $0
+	dbsprite  -1,  -3, 4, 0, $04, $0
+	dbsprite   0,  -3, 4, 0, $04, $0
+	dbsprite   2,  -5, 4, 0, $04, $0
+	dbsprite   4,   0, 4, 0, $04, $0
+	dbsprite   6,  -2, 4, 0, $04, $0
+	dbsprite   8,  -4, 4, 0, $04, $0
+	dbsprite  10,  -2, 4, 0, $04, $0
+
```

These are simply some frame and OAM data that we'll use to get the proper tile from the tileset we'll load along with the new animation. The structure of the OAMData_Hail in particular is the same as Sandstorm's, but with a different tile stored in VRAM. Now we should create an object that will take the form of this little "hail crystal".

Modify [data/battle_anims/objects.asm](../blob/master/data/battle_anims/objects.asm):

```diff
 ; ANIM_OBJ_ENEMYFEET_2ROW
	battleanimobj ABSOLUTE_X, $00, BATTLEANIMFRAMESET_B7, BATTLEANIMFUNC_NULL, PAL_BATTLE_OB_ENEMY, ANIM_GFX_PLAYERHEAD
 ; ANIM_OBJ_PLAYERHEAD_2ROW
	battleanimobj ABSOLUTE_X, $00, BATTLEANIMFRAMESET_B8, BATTLEANIMFUNC_NULL, PAL_BATTLE_OB_PLAYER, ANIM_GFX_ENEMYFEET
+; ANIM_OBJ_HAIL
+	battleanimobj RELATIVE_X | X_FLIP, $00, BATTLEANIMFRAMESET_HAIL, BATTLEANIMFUNC_RAIN_SANDSTORM, PAL_BATTLE_OB_BLUE, ANIM_GFX_ICE
	assert_table_length NUM_ANIM_OBJS
```

Objects are the data structures that serve as the "particles" in the game's animation engine. So having the object created, we need to use them in some form of animation sequence. We're going to create two different animations, which will use the same sequence. Since the animation constant for a move corresponds to it the move's constant already, we only need to define one extra animation constant for the situation where the hail should play between turns (such as the case with Sandstorm).

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

```diff
 ; battle anims
	...
	const ANIM_WOBBLE            ; 113
	const ANIM_SHAKE             ; 114
	const ANIM_HIT_CONFUSION     ; 115
+	const ANIM_IN_HAIL           ; 116
 NUM_BATTLE_ANIMS EQU const_value - 1
```

Modify [data/moves/animations.asm](../blob/master/data/moves/animations.asm):

```diff
	dw BattleAnim_Whirlpool
	dw BattleAnim_BeatUp
+	dw BattleAnim_Hail
	assert_table_length NUM_ATTACKS + 1
-	dw BattleAnim_252
	dw BattleAnim_253
	dw BattleAnim_254
	dw BattleAnim_SweetScent2

	...

	dw BattleAnim_Wobble
	dw BattleAnim_Shake
	dw BattleAnim_HitConfusion
+	dw BattleAnim_InHail
	assert_table_length NUM_BATTLE_ANIMS + 1

 BattleAnim_0:
-BattleAnim_252:
 BattleAnim_253:
 BattleAnim_254:
 BattleAnim_MirrorMove:
	anim_ret

	...

	anim_obj ANIM_OBJ_HIT_BIG_YFIX, 136, 48, $0
	anim_wait 8
	anim_call BattleAnim_ShowMon_0
	anim_ret

+BattleAnim_Hail:
+BattleAnim_InHail:
+	anim_1gfx ANIM_GFX_ICE
+	anim_bgeffect ANIM_BG_WHITE_HUES, $0, $8, $0
+	anim_obj ANIM_OBJ_HAIL, 88, 0, $0
+	anim_wait 8
+	anim_obj ANIM_OBJ_HAIL, 72, 0, $1
+	anim_wait 8
+	anim_obj ANIM_OBJ_HAIL, 56, 0, $2
+.loop
+	anim_sound 0, 1, SFX_SHINE
+	anim_wait 8
+	anim_loop 8, .loop
+	anim_wait 8
+	anim_ret
+

 BattleAnimSub_Drain:
	anim_obj ANIM_OBJ_DRAIN, 132, 44, $0
	anim_obj ANIM_OBJ_DRAIN, 132, 44, $8
	anim_obj ANIM_OBJ_DRAIN, 132, 44, $10
...
```

The animation is now complete, so now we can call it whenever we need to show some hailing in the battle screen.

Edit `HandleWeather.HailDamage` in [engine/battle/core.asm](../blob/master/engine/battle/core.asm):

```diff
 .HailDamage:
	...

	ld a, [hl]
	cp ICE
	ret z

+	call SwitchTurnCore
+	xor a
+	ld [wNumHits], a
+	ld de, ANIM_IN_HAIL
+	call Call_PlayBattleAnim
+	call SwitchTurnCore
+
	call GetSixteenthMaxHP
	call SubtractHPFromUser

	ld hl, PeltedByHailText
	jp StdBattleTextbox
```

Modify the earlier file we created, `BattleCommand_StartHail` in [engine/battle/move_effects/hail.asm](../blob/master/engine/battle/move_effects/hail.asm):

```diff
 BattleCommand_StartHail:
 ; starthail
	...
	ld a, WEATHER_HAIL
	ld [wBattleWeather], a
	ld a, 5
	ld [wWeatherCount], a
+	call AnimateCurrentMove
	ld hl, ItStartedToHailText
	jp StdBattleTextbox
	...
```

And with that, everything is in place, and now we have a brand new weather type to use in the game! The main point of this tutorial was to show how one can simply use the resources already available to create something new. In a lot of cases, it helps to check similar systems already implemented in the codebase.

![Screenshot](https://i.imgur.com/WIqgj2c.gif)