summaryrefslogtreecommitdiff
path: root/Add-a-new-Pack-pocket.md
blob: 316732a58b17c95c0df8ed5aa48d24b2cd0a9ef0 (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
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
This tutorial is for how to add a new Pack pocket. As an example, we'll add a Berry Pocket.


## Contents

1. [Define pocket-related constants](#1-define-pocket-related-constants)
2. [Give the pocket a name](#2-give-the-pocket-a-name)
3. [Update the item types](#3-update-the-item-types)
4. [Update the Pack graphics](#4-update-the-pack-graphics)
5. [Add space in WRAM for the new pocket](#5-add-space-in-wram-for-the-new-pocket)
6. [Initialize the new WRAM](#6-initialize-the-new-wram)
7. [Update `HasNoItems` and `CheckRegisteredItem` to check the new pocket](#7-update-hasnoitems-and-checkregistereditem-to-check-the-new-pocket)
8. [Update standard inventory routines](#8-update-standard-inventory-routines)
9. [Update the Pack engine](#9-update-the-pack-engine)
10. [Update the Crystal-only Pack engine](#10-update-the-crystal-only-pack-engine)
11. [Update Kurt's Apricorn script](#11-update-kurts-apricorn-script)
12. [Fix build errors](#12-fix-build-errors)


## 1. Define pocket-related constants

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

```diff
 ; item types
 	const_def 1
 	const ITEM     ; 1
 	const KEY_ITEM ; 2
 	const BALL     ; 3
 	const TM_HM    ; 4
+	const BERRIES  ; 5

 ...

 ; pack pockets
 	const_def
 	const ITEM_POCKET     ; 0
 	const BALL_POCKET     ; 1
 	const KEY_ITEM_POCKET ; 2
 	const TM_HM_POCKET    ; 3
+	const BERRY_POCKET    ; 4
 NUM_POCKETS EQU const_value

 MAX_ITEMS     EQU 20
 MAX_BALLS     EQU 12
 MAX_KEY_ITEMS EQU 25
 MAX_PC_ITEMS  EQU 50
+MAX_BERRIES   EQU 17
```

Notice that the "item types" constants are in a different order than the "pack pockets" constants. So don't mix them up. Also we name the item type "`BERRIES`" because "`BERRY`" is an item, so don't mix those up either.

The `MAX_*` constants are the storage capacities of their respective pockets. We defined `MAX_BERRIES` as 17 because there are 17 items that will go in the Berry pocket, as we'll see later; that way you can conveniently carry one stack of each Berry. (Likewise, `MAX_BALLS` is 12, and 12 items belong in the Ball pocket.)


## 2. Give the pocket a name

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

```diff
 ItemPocketNames:
 ; entries correspond to item type constants
 	dw .Item
 	dw .Key
 	dw .Ball
 	dw .TM
+	dw .Berry

 .Item: db "ITEM POCKET@"
 .Key:  db "KEY POCKET@"
 .Ball: db "BALL POCKET@"
 .TM:   db "TM POCKET@"
+.Berry: db "BERRY POCKET@"
```

The phrase "`the BERRY POCKET.`" has to fit on one line for the message "*PLAYER* put the *ITEM* in the *POCKET*." So a pocket name can be up to 13 characters long, plus a "@" at the end.


## 3. Update the item types

Edit [data/items/attributes.asm](../blob/master/data/items/attributes.asm), changing the relevant items' types from `ITEM` to `BERRIES`:

- `BERRY`
- `GOLD_BERRY`
- `PSNCUREBERRY`
- `PRZCUREBERRY`
- `BURNT_BERRY`
- `ICE_BERRY`
- `BITTER_BERRY`
- `MINT_BERRY`
- `MIRACLEBERRY`
- `MYSTERYBERRY`
- `RED_APRICORN`
- `BLU_APRICORN`
- `YLW_APRICORN`
- `GRN_APRICORN`
- `WHT_APRICORN`
- `BLK_APRICORN`
- `PNK_APRICORN`

Note that all of these items have the `CANT_SELECT` property. The only items without it are `BICYCLE`, `ITEMFINDER`, `OLD_ROD`, `GOOD_ROD`, and `SUPER_ROD`, which are all Key Items. I haven't tried creating a non–Key Item that can be registered to the Select button, but suspect that it would cause glitches.


## 4. Update the Pack graphics

Edit [gfx/pack/pack.png](../blob/master/gfx/pack/pack.png):

![gfx/pack/pack.png](screenshots/gfx-pack-pack.png)

Edit [gfx/pack/pack_f.png](../blob/master/gfx/pack/pack_f.png):

![gfx/pack/pack_f.png](screenshots/gfx-pack-pack_f.png)

And edit [gfx/pack/pack_menu.png](../blob/master/gfx/pack/pack_menu.png):

![gfx/pack/pack_menu.png](screenshots/gfx-pack-pack_menu.png)

The pack.png and pack_f.png graphics are in this order, from top to bottom: Key Items, Items, TM/HM, Balls. We've split the Ball pocket in half and turned the right half into a Berry pocket, with its graphic appended to the bottom of the image. (Note that this doesn't match the order of either set of constants. We'll see later that the offsets of each pocket's individual picture are hard-coded in a table, not calculated directly from a constant.)

The pack_menu.png graphic is a set of 80 tiles in no particular order, except for the 20 sequential tiles that form the "`◀▶ POCKET ▼▲ ITEMS`" header. We've added the new "Berries" subtitle sequentially, but that's just to be neat; we'll see later that the individual tiles of the subtitles are all hard-coded, so you can fit them into any of the unused tiles in the original:

![gfx/pack/pack_menu.png](screenshots/unused-pack_menu-tiles.png)


## 5. Add space in WRAM for the new pocket

Edit [wram.asm](../blob/master/wram.asm):

```diff
 wPCItemsCursor::        db
 wPartyMenuCursor::      db
 wItemsPocketCursor::    db
 wKeyItemsPocketCursor:: db
 wBallsPocketCursor::    db
 wTMHMPocketCursor::     db
+wBerryPocketCursor::    db

 wPCItemsScrollPosition::        db
 wPartyMenuScrollPosition::      db ; unused
 wItemsPocketScrollPosition::    db
 wKeyItemsPocketScrollPosition:: db
 wBallsPocketScrollPosition::    db
 wTMHMPocketScrollPosition::     db
+wBerryPocketScrollPosition::    db

 ...

+wDudeNumBerries::
 wDudeNumKeyItems:: db ; d292
 wDudeKeyItems:: ds 18
 wDudeKeyItemsEnd:: db

 ...

 wCmdQueue:: ds CMDQUEUE_CAPACITY * CMDQUEUE_ENTRY_SIZE

-	ds 40

 ...

 wNumBalls:: db ; d8d7
 wBalls:: ds MAX_BALLS * 2 + 1 ; d8d8
 wBallsEnd::

+wNumBerries:: db
+wBerries:: ds MAX_BERRIES * 2 + 1
+wBerriesEnd::
```

Every pocket has a <code>w<i>Name</i>PocketCursor</code> and a <code>w<i>Name</i>PocketScrollPosition</code> byte for scrolling through it, a <code>wNum<i>Names</i></code> byte that stores how many items are in it, and a <code>w<i>Names</i></code>–<code>w<i>Names</i>End</code> array for storing its items. `wTMsHMs` and `wKeyItems` are special, but normal item-storage pockets like `wItems` and `wBalls` have two bytes per possible item (one for the ID, one for the quantity) plus a byte for the end-of-list marker.

`wDudeNumBerries` just shares space with `wDudeNumKeyItems` because the catch tutorial dude only shows his Item and Ball pockets. It's probably possible to remove the data and code for his Key Item pocket entirely, but that's beyond the scope of this tutorial, and not necessary unless you really need some extra space.

Speaking of extra space: we used a total of 37 more WRAM bytes for the Berry pocket's data. Its WRAM bank has barely any free space left, so in general you'll need to remove as many bytes as you add. There was an unused `ds 40` that conveniently saved 40 bytes. If you want larger pockets and need to free up more space, shortly below the pockets is an unused `ds 13`, then `ds 49` after the <code>w<i>MapName</i>SceneID</code> bytes, then `ds 100` after the <code>w<i>Trainer</i>FightCount</code> bytes, and a `ds 23` after `wPhoneList`. Any of those can be reduced to make more room for Pack pockets (or for more map scene IDs, or extending `wEventFlags` if you raise `NUM_EVENTS`, or so on).


## 6. Initialize the new WRAM

Edit [engine/menus/intro_menu.asm](../blob/master/engine/menus/intro_menu.asm):

```diff
 	ld hl, wNumItems
 	call .InitList

 	ld hl, wNumKeyItems
 	call .InitList

 	ld hl, wNumBalls
 	call .InitList
+
+	ld hl, wNumBerries
+	call .InitList

 	ld hl, wNumPCItems
 	call .InitList
```

As the `.InitList` comment explains, this "loads 0 in the count and −1 in the first item slot."


## 7. Update `HasNoItems` and `CheckRegisteredItem` to check the new pocket

Edit [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):

```diff
 HasNoItems:
 	ld a, [wNumItems]
 	and a
 	ret nz
 	ld a, [wNumKeyItems]
 	and a
 	ret nz
 	ld a, [wNumBalls]
 	and a
 	ret nz
+	ld a, [wNumBerries]
+	and a
+	ret nz
 	ld hl, wTMsHMs
 	ld b, NUM_TMS + NUM_HMS
 .loop
 	ld a, [hli]
 	and a
 	jr nz, .done
 	dec b
 	jr nz, .loop
 	scf
 	ret
 .done
 	and a
 	ret
```

Now edit [engine/overworld/select_menu.asm](../blob/master/engine/overworld/select_menu.asm):

```diff
 .Pockets:
 ; entries correspond to *_POCKET constants
 	dw .CheckItem
 	dw .CheckBall
 	dw .CheckKeyItem
 	dw .CheckTMHM
+	dw .CheckBerry

 ...

 .CheckBall:
 	ld hl, wNumBalls
+.StandardCheck:
 	call .CheckRegisteredNo
 	jr nc, .NoRegisteredItem
 	inc hl
 	ld e, a
 	ld d, 0
 	add hl, de
 	add hl, de
 	call .IsSameItem
 	jr c, .NoRegisteredItem
 	ret
+
+.CheckBerry:
+	ld hl, wNumBerries
+	jr .StandardCheck
```

There's no such thing as a Ball or Berry that can be registered, so I haven't actually tested this code; if there's a bug with the built-in handling of registered Balls, it will also apply to Berries. You're better off leaving Key Items as the only type that can be registered.


## 8. Update standard inventory routines

Edit [engine/items/items.asm](../blob/master/engine/items/items.asm). Four routines here need updating, so let's take them one by one.

Edit `_ReceiveItem`:

```diff
 _ReceiveItem::
 	...

 .Pockets:
 ; entries correspond to item types
 	dw .Item
 	dw .KeyItem
 	dw .Ball
 	dw .TMHM
+	dw .Berry

 ...

 .Ball:
 	ld hl, wNumBalls
 	jp PutItemInPocket
+
+.Berry:
+	ld hl, wNumBerries
+	jp PutItemInPocket
```

Edit `_TossItem`:

```diff
 _TossItem::
 	...

 .Pockets:
 ; entries correspond to item types
 	dw .Item
 	dw .KeyItem
 	dw .Ball
 	dw .TMHM
+	dw .Berry

 .Ball:
 	ld hl, wNumBalls
 	jp RemoveItemFromPocket
+
+.Berry:
+	ld hl, wNumBerries
+	jp RemoveItemFromPocket
```

Edit `_CheckItem`:

```diff
 _CheckItem::
 	...

 .Pockets:
 ; entries correspond to item types
 	dw .Item
 	dw .KeyItem
 	dw .Ball
 	dw .TMHM
+	dw .Berry

 .Ball:
 	ld hl, wNumBalls
 	jp CheckTheItem
+
+.Berry:
+	ld hl, wNumBerries
+	jp CheckTheItem
```

And edit `GetPocketCapacity`:

```diff
 GetPocketCapacity:
 	ld c, MAX_ITEMS
 	ld a, e
 	cp LOW(wNumItems)
 	jr nz, .not_bag
 	ld a, d
 	cp HIGH(wNumItems)
 	ret z

 .not_bag
 	ld c, MAX_PC_ITEMS
 	ld a, e
 	cp LOW(wNumPCItems)
 	jr nz, .not_pc
 	ld a, d
 	cp HIGH(wNumPCItems)
 	ret z

 .not_pc
+	ld c, MAX_BERRIES
+	ld a, e
+	cp LOW(wBerries)
+	jr nz, .not_berries
+	ld a, d
+	cp HIGH(wNumBerries)
+	ret z
+
+.not_berries
 	ld c, MAX_BALLS
 	ret
```

In most of these cases we just based the Berry pocket case on the Ball pocket case. The TM/HM and Key Item pockets are special, and the Item pocket is sometimes treated as a "default" case with different handling. But the Ball pocket is non-default and just stores regular items, so it's safe to copy.


## 9. Update the Pack engine

We've saved editing the longest file for last: [engine/items/pack.asm](../blob/master/engine/items/pack.asm). Let's go over it piece by piece. (Don't worry, a lot of it is just copy+pasting chunks of code with the word "Berry" substituted for "Ball" or "Item".)

```diff
 ; Pack.Jumptable and BattlePack.Jumptable indexes
 	const_def
 	const PACKSTATE_INITGFX            ;  0
 	const PACKSTATE_INITITEMSPOCKET    ;  1
 	const PACKSTATE_ITEMSPOCKETMENU    ;  2
 	const PACKSTATE_INITBALLSPOCKET    ;  3
 	const PACKSTATE_BALLSPOCKETMENU    ;  4
 	const PACKSTATE_INITKEYITEMSPOCKET ;  5
 	const PACKSTATE_KEYITEMSPOCKETMENU ;  6
 	const PACKSTATE_INITTMHMPOCKET     ;  7
 	const PACKSTATE_TMHMPOCKETMENU     ;  8
+	const PACKSTATE_INITBERRYPOCKET
+	const PACKSTATE_BERRYPOCKETMENU
 	const PACKSTATE_QUITNOSCRIPT       ;  9
 	const PACKSTATE_QUITRUNSCRIPT      ; 10
```

These are jumptable indexes. Jumptables are a common design pattern you'll see for interfaces with a lot of different states and transitions between states, like the Pokédex and Pokégear. In general, there's a table of pointers corresponding to these index constants, and each pointer is to a different subroutine. Control jumps to whichever pointer corresponds to the value in `wJumptableIndex`, which usually starts at 0. Each subroutine can change `wJumptableIndex`, often by incrementing it to automatically reach the next state in the table, or by setting particular values depending on which buttons are pressed.

Notice the pattern to this table: for each pocket, there's a `PACKSTATE_INIT*POCKET` state followed by a `PACKSTATE_*POCKETMENU` state. They happen to be in the same order as the `*_POCKET` constants, although that isn't actually significant; all that matters is that the default pocket be the first one (since the `PACKSTATE_INITGFX` state increments `wJumptableIndex` and advances to the next state, which should thus be the default pocket's `INIT` state).

```diff
 Pack:
 	...

 .Jumptable:
 ; entries correspond to PACKSTATE_* constants
 	dw .InitGFX            ;  0
 	dw .InitItemsPocket    ;  1
 	dw .ItemsPocketMenu    ;  2
 	dw .InitBallsPocket    ;  3
 	dw .BallsPocketMenu    ;  4
 	dw .InitKeyItemsPocket ;  5
 	dw .KeyItemsPocketMenu ;  6
 	dw .InitTMHMPocket     ;  7
 	dw .TMHMPocketMenu     ;  8
+	dw .InitBerryPocket
+	dw .BerryPocketMenu
 	dw Pack_QuitNoScript   ;  9
 	dw Pack_QuitRunScript  ; 10
```

Here's the first jumptable corresponding to those constants. It's the "core" jumptable for when you enter the Pack via the Start Menu.

```diff
 .KeyItemsPocketMenu:
 	...
-	ld b, PACKSTATE_INITBALLSPOCKET ; left
+	ld b, PACKSTATE_INITBERRYPOCKET ; left
 	ld c, PACKSTATE_INITTMHMPOCKET ; right
 	call Pack_InterpretJoypad
 	ret c
 	call .ItemBallsKey_LoadSubmenu
 	ret

 ...

 .InitBallsPocket:
 	ld a, BALL_POCKET
 	ld [wCurPocket], a
 	call ClearPocketList
 	call DrawPocketName
 	call WaitBGMap_DrawPackGFX
 	call Pack_JumptableNext
 	ret

 .BallsPocketMenu:
 	ld hl, BallsPocketMenuHeader
 	call CopyMenuHeader
 	ld a, [wBallsPocketCursor]
 	ld [wMenuCursorPosition], a
 	ld a, [wBallsPocketScrollPosition]
 	ld [wMenuScrollPosition], a
 	call ScrollingMenu
 	ld a, [wMenuScrollPosition]
 	ld [wBallsPocketScrollPosition], a
 	ld a, [wMenuCursorY]
 	ld [wBallsPocketCursor], a
 	ld b, PACKSTATE_INITITEMSPOCKET ; left
-	ld c, PACKSTATE_INITKEYITEMSPOCKET ; right
+	ld c, PACKSTATE_INITBERRYPOCKET ; right
 	call Pack_InterpretJoypad
 	ret c
 	call .ItemBallsKey_LoadSubmenu
 	ret
+
+.InitBerryPocket:
+	ld a, BERRY_POCKET
+	ld [wCurPocket], a
+	call ClearPocketList
+	call DrawPocketName
+	call WaitBGMap_DrawPackGFX
+	call Pack_JumptableNext
+	ret
+
+.BerryPocketMenu:
+	ld hl, BerryPocketMenuHeader
+	call CopyMenuHeader
+	ld a, [wBerryPocketCursor]
+	ld [wMenuCursorPosition], a
+	ld a, [wBerryPocketScrollPosition]
+	ld [wMenuScrollPosition], a
+	call ScrollingMenu
+	ld a, [wMenuScrollPosition]
+	ld [wBerryPocketScrollPosition], a
+	ld a, [wMenuCursorY]
+	ld [wBerryPocketCursor], a
+	ld b, PACKSTATE_INITBALLSPOCKET ; left
+	ld c, PACKSTATE_INITKEYITEMSPOCKET ; right
+	call Pack_InterpretJoypad
+	ret c
+	call .ItemBallsKey_LoadSubmenu
+	ret
```

We're doing two things here.

One, we insert the Berry pocket in-between the Ball and Key Item pockets. Originally you can scroll left and right through the pockets in order: Items ↔ Balls ↔ Key Items ↔ TM/HM ↔ Items again. This is done by explicitly hard-coding each pocket's left and right ones. So the Berry pocket just had to be coded in.

Two, we actually write the subroutines that we just added pointers to in the jumptable. Really they're just copy+pasted from the Ball pocket's subroutines, but with "Berry" substituted for "Ball". (As we discussed earlier, the Ball pocket is safe to use as a base, since it stores regular items and isn't a default like the Items pocket.)

```diff
 BattlePack:
 	...

 .Jumptable:
 ; entries correspond to PACKSTATE_* constants
 	dw .InitGFX            ;  0
 	dw .InitItemsPocket    ;  1
 	dw .ItemsPocketMenu    ;  2
 	dw .InitBallsPocket    ;  3
 	dw .BallsPocketMenu    ;  4
 	dw .InitKeyItemsPocket ;  5
 	dw .KeyItemsPocketMenu ;  6
 	dw .InitTMHMPocket     ;  7
 	dw .TMHMPocketMenu     ;  8
+	dw .InitBerryPocket
+	dw .BerryPocketMenu
 	dw Pack_QuitNoScript   ;  9
 	dw Pack_QuitRunScript  ; 10
```

This is another jumptable, but for using the Pack during battle. Again, we add pointers for the Berry pocket, and will next have to define them.

```diff
 .KeyItemsPocketMenu:
 	...
-	ld b, PACKSTATE_INITBALLSPOCKET ; left
+	ld b, PACKSTATE_INITBERRYPOCKET ; left
 	ld c, PACKSTATE_INITTMHMPOCKET ; right
 	call Pack_InterpretJoypad
 	ret c
 	call ItemSubmenu
 	ret

 ...

 .InitBallsPocket:
 	ld a, BALL_POCKET
 	ld [wCurPocket], a
 	call ClearPocketList
 	call DrawPocketName
 	call WaitBGMap_DrawPackGFX
 	call Pack_JumptableNext
 	ret

 .BallsPocketMenu:
 	ld hl, BallsPocketMenuHeader
 	call CopyMenuHeader
 	ld a, [wBallsPocketCursor]
 	ld [wMenuCursorPosition], a
 	ld a, [wBallsPocketScrollPosition]
 	ld [wMenuScrollPosition], a
 	call ScrollingMenu
 	ld a, [wMenuScrollPosition]
 	ld [wBallsPocketScrollPosition], a
 	ld a, [wMenuCursorY]
 	ld [wBallsPocketCursor], a
 	ld b, PACKSTATE_INITITEMSPOCKET ; left
-	ld c, PACKSTATE_INITKEYITEMSPOCKET ; right
+	ld c, PACKSTATE_INITBERRYPOCKET ; right
 	call Pack_InterpretJoypad
 	ret c
 	call ItemSubmenu
 	ret
+
+.InitBerryPocket:
+	ld a, BERRY_POCKET
+	ld [wCurPocket], a
+	call ClearPocketList
+	call DrawPocketName
+	call WaitBGMap_DrawPackGFX
+	call Pack_JumptableNext
+	ret
+
+.BerryPocketMenu:
+	ld hl, BerryPocketMenuHeader
+	call CopyMenuHeader
+	ld a, [wBerryPocketCursor]
+	ld [wMenuCursorPosition], a
+	ld a, [wBerryPocketScrollPosition]
+	ld [wMenuScrollPosition], a
+	call ScrollingMenu
+	ld a, [wMenuScrollPosition]
+	ld [wBerryPocketScrollPosition], a
+	ld a, [wMenuCursorY]
+	ld [wBerryPocketCursor], a
+	ld b, PACKSTATE_INITBALLSPOCKET ; left
+	ld c, PACKSTATE_INITKEYITEMSPOCKET ; right
+	call Pack_InterpretJoypad
+	ret c
+	call ItemSubmenu
+	ret
```

Just like before, we insert the Berry pocket between the Ball and Key Item pockets, and base the Berry pocket's subroutines on the pre-existing Ball pocket ones.

```diff
 DepositSellPack:
 	...

 .Jumptable:
 ; entries correspond to *_POCKET constants
 	dw .ItemsPocket
 	dw .BallsPocket
 	dw .KeyItemsPocket
 	dw .TMHMPocket
+	dw .BerryPocket

 ...

 .BallsPocket:
 	ld a, BALL_POCKET
 	call InitPocket
 	ld hl, PC_Mart_BallsPocketMenuHeader
 	call CopyMenuHeader
 	ld a, [wBallsPocketCursor]
 	ld [wMenuCursorPosition], a
 	ld a, [wBallsPocketScrollPosition]
 	ld [wMenuScrollPosition], a
 	call ScrollingMenu
 	ld a, [wMenuScrollPosition]
 	ld [wBallsPocketScrollPosition], a
 	ld a, [wMenuCursorY]
 	ld [wBallsPocketCursor], a
 	ret
+
+.BerryPocket:
+	ld a, BERRY_POCKET
+	call InitPocket
+	ld hl, PC_Mart_BerryPocketMenuHeader
+	call CopyMenuHeader
+	ld a, [wBerryPocketCursor]
+	ld [wMenuCursorPosition], a
+	ld a, [wBerryPocketScrollPosition]
+	ld [wMenuScrollPosition], a
+	call ScrollingMenu
+	ld a, [wMenuScrollPosition]
+	ld [wBerryPocketScrollPosition], a
+	ld a, [wMenuCursorY]
+	ld [wBerryPocketCursor], a
+	ret
```

Here's a jumptable for when the Pack is opened to deposit or sell an item; it has entries for each individual pocket, less complicated than the previous jumptables with their intermediate `INIT` states. As usual, we just look at how the other pockets work and do what they do but with the word "Berry" in the right places.

```diff
 .d_left
 	ld a, [wJumptableIndex]
 	dec a
-	maskbits NUM_POCKETS
+	cp -1
+	jr nz, .left_ok
+	ld a, NUM_POCKETS - 1
+.left_ok
 	ld [wJumptableIndex], a
 	push de
 	ld de, SFX_SWITCH_POCKETS
 	call PlaySFX
 	pop de
 	scf
 	ret

 .d_right
 	ld a, [wJumptableIndex]
 	inc a
-	maskbits NUM_POCKETS
+	cp NUM_POCKETS
+	jr nz, .right_ok
+	xor a
+.right_ok
 	ld [wJumptableIndex], a
 	push de
 	ld de, SFX_SWITCH_POCKETS
 	call PlaySFX
 	pop de
 	scf
 	ret
```

This is somewhat tricky to notice. Here the code is decrementing or incrementing `wJumptableIndex` (that is, subtracting or adding 1) when you press Left or Right. But doing that can go beyond the valid range, since it might decrement the minimum or increment the maximum. When there were only four pockets, they neatly took up two bits, so a bitmask could be used to efficiently clamp them within the valid range. But five pockets requires more explicit checks so that the minimum and maximum values (0 and `NUM_POCKETS` − 1) wrap around.

```diff
 TutorialPack:
 	...

 .dw
 ; entries correspond to *_POCKET constants
 	dw .Items
 	dw .Balls
 	dw .KeyItems
 	dw .TMHM
+	dw .Berries

 ...

 .Balls:
 	ld a, BALL_POCKET
 	ld hl, .BallsMenuHeader
 	jr .DisplayPocket

 .BallsMenuHeader:
 	db MENU_BACKUP_TILES ; flags
 	menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
 	dw .BallsMenuData
 	db 1 ; default option

 .BallsMenuData:
 	db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP | STATICMENU_CURSOR ; flags
 	db 5, 8 ; rows, columns
 	db 2 ; horizontal spacing
 	dbw 0, wDudeNumBalls
 	dba PlaceMenuItemName
 	dba PlaceMenuItemQuantity
 	dba UpdateItemDescription
+
+.Berries:
+	ld a, BERRY_POCKET
+	ld hl, .BerriesMenuHeader
+	jr .DisplayPocket
+
+.BerriesMenuHeader:
+	db MENU_BACKUP_TILES ; flags
+	menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+	dw .BerriesMenuData
+	db 1 ; default option
+
+.BerriesMenuData:
+	db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP | STATICMENU_CURSOR ; flags
+	db 5, 8 ; rows, columns
+	db 2 ; horizontal spacing
+	dbw 0, wDudeNumBerries
+	dba PlaceMenuItemName
+	dba PlaceMenuItemQuantity
+	dba UpdateItemDescription
```

Another jumptable, this time used by the catch tutorial dude. Once again, we just add an entry to the jumptable for the Berry pocket and base its code and data on whatever the Ball pocket does.

```diff
 PackGFXPointers:
 	dw PackGFX + (15 tiles) * 1 ; ITEM_POCKET
 	dw PackGFX + (15 tiles) * 3 ; BALL_POCKET
 	dw PackGFX + (15 tiles) * 0 ; KEY_ITEM_POCKET
 	dw PackGFX + (15 tiles) * 2 ; TM_HM_POCKET
+	dw PackGFX + (15 tiles) * 4 ; BERRY_POCKET
```

This is a table of pointers to the individual highlighted pocket pictures in pack.png and pack_f.png. Remember how they were out of order compared to the constants? That's why this table is necessary. For example, the first (#0) picture was of the Key Item pocket, and `KEY_ITEM_POCKET` is 2, so the third (#2) entry here points to the first picture. Anyway, all we have to do is add a pointer for the Berry pocket again.

```diff
 .tilemap
 ; ITEM_POCKET
 	db $00, $04, $04, $04, $01 ; top border
 	db $06, $07, $08, $09, $0a ; Items
 	db $02, $05, $05, $05, $03 ; bottom border
 ; BALL_POCKET
 	db $00, $04, $04, $04, $01 ; top border
 	db $15, $16, $17, $18, $19 ; Balls
 	db $02, $05, $05, $05, $03 ; bottom border
 ; KEY_ITEM_POCKET
 	db $00, $04, $04, $04, $01 ; top border
 	db $0b, $0c, $0d, $0e, $0f ; Key Items
 	db $02, $05, $05, $05, $03 ; bottom border
 ; TM_HM_POCKET
 	db $00, $04, $04, $04, $01 ; top border
 	db $10, $11, $12, $13, $14 ; TM/HM
 	db $02, $05, $05, $05, $03 ; bottom border
+; BERRY_POCKET
+	db $00, $04, $04, $04, $01 ; top border
+	db $1a, $1b, $1c, $1d, $1e ; Berries
+	db $02, $05, $05, $05, $03 ; bottom border
```

These are tilemaps for the pocket name labels in pack_menu.png. Each one is three rows of five tiles each, with tile indexes starting at 0. Take a look at pack_menu.png and notice how the hexadecimal indexes here correspond to tiles that form sensible pictures.

```diff
 BallsPocketMenuHeader:
 	db MENU_BACKUP_TILES ; flags
 	menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
 	dw .MenuData
 	db 1 ; default option

 .MenuData:
 	db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP | STATICMENU_CURSOR ; flags
 	db 5, 8 ; rows, columns
 	db SCROLLINGMENU_ITEMS_QUANTITY ; item format
 	dbw 0, wNumBalls
 	dba PlaceMenuItemName
 	dba PlaceMenuItemQuantity
 	dba UpdateItemDescription

 PC_Mart_BallsPocketMenuHeader:
 	db MENU_BACKUP_TILES ; flags
 	menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
 	dw .MenuData
 	db 1 ; default option

 .MenuData:
 	db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP ; flags
 	db 5, 8 ; rows, columns
 	db SCROLLINGMENU_ITEMS_QUANTITY ; item format
 	dbw 0, wNumBalls
 	dba PlaceMenuItemName
 	dba PlaceMenuItemQuantity
 	dba UpdateItemDescription
+
+BerryPocketMenuHeader:
+	db MENU_BACKUP_TILES ; flags
+	menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+	dw .MenuData
+	db 1 ; default option
+
+.MenuData:
+	db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP | STATICMENU_CURSOR ; flags
+	db 5, 8 ; rows, columns
+	db SCROLLINGMENU_ITEMS_QUANTITY ; item format
+	dbw 0, wNumBerries
+	dba PlaceMenuItemName
+	dba PlaceMenuItemQuantity
+	dba UpdateItemDescription
+
+PC_Mart_BerryPocketMenuHeader:
+	db MENU_BACKUP_TILES ; flags
+	menu_coords 7, 1, SCREEN_WIDTH - 1, TEXTBOX_Y - 1
+	dw .MenuData
+	db 1 ; default option
+
+.MenuData:
+	db STATICMENU_ENABLE_SELECT | STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP ; flags
+	db 5, 8 ; rows, columns
+	db SCROLLINGMENU_ITEMS_QUANTITY ; item format
+	dbw 0, wNumBerries
+	dba PlaceMenuItemName
+	dba PlaceMenuItemQuantity
+	dba UpdateItemDescription
```

We saw `BallsPocketMenuHeader` used in the subroutines for the Start Menu Pack and the battle Pack, and `PC_Mart_BallsPocketMenuHeader` in the subroutine for the Pack when depositing or selling. Here they're finally being defined. And since we created the corresponding names `BerryPocketMenuHeader` and `PC_Mart_BerryPocketMenuHeader`, they need defining too; as usual, we can just copy whatever the Ball pocket does and substitute "Berry" for "Ball".


## 10. Update the Crystal-only Pack engine

Edit [engine/items/pack_kris.asm](../blob/master/engine/items/pack_kris.asm):

```diff
 PackFGFXPointers:
 	dw PackFGFX + (15 tiles) * 1 ; ITEM_POCKET
 	dw PackFGFX + (15 tiles) * 3 ; BALL_POCKET
 	dw PackFGFX + (15 tiles) * 0 ; KEY_ITEM_POCKET
 	dw PackFGFX + (15 tiles) * 2 ; TM_HM_POCKET
+	dw PackFGFX + (15 tiles) * 4 ; BERRY_POCKET
```

This is just like `PackGFXPointers`, but for the Crystal-only girl's Pack.


## 11. Update Kurt's Apricorn script

If you did not change the Apricorns' pocket, then skip this step.

Kurt's script to turn Apricorns into Balls assumes they're still in the Item pocket. Fixing this is thankfully quick and easy. Edit [engine/events/kurt.asm](../blob/master/engine/events/kurt.asm). There are *five* places in the code where we need to do this:

```diff
-	ld hl, wNumItems
+	ld hl, wNumBerries
```

1. `Kurt_GetQuantityOfApricorn`
2. `Kurt_GiveUpSelectedQuantityOfSelectedApricorn`
3. `Kurt_GetAddressOfApricornQuantity`
4. `Kurt_GetRidOfItem`
5. `Kurt_GetRidOfItem.okay`

Just use your text editor to find all five occurrences of "`wNumItems`" in the file, and make that one-line change to all of them.


## 12. Fix build errors

We're almost finished, but if you run `make` now, it gives an error:

```
error: engine/items/pack.asm(1243) : Value must be 8-bit
```

Line 1243 of [engine/items/pack.asm](../blob/master/engine/items/pack.asm) is `jr .DisplayPocket`.

So, `jr` and `jp` both jump to the given label. But `jp` encodes the full two-byte address of the label, while `jr` saves a byte by encoding a one-byte distance to jump. That means it can only reach −128 to 127 bytes away from its own location. Some of the code we added must have made `.DisplayPocket` more than 128 bytes away from this `jr` instruction. Anyway, the solution is simple: change it to `jp`.

```diff
 TutorialPack:
 	...

 .Items:
 	xor a ; ITEM_POCKET
 	ld hl, .ItemsMenuHeader
-	jr .DisplayPocket
+	jp .DisplayPocket
```

(If you're adding more pockets, you might have more errors like this.)

We're finally done!

![Screenshot](screenshots/berry-pocket.png)

There are many other pockets you could add. Gen 4 had Medicine, Mail, and Battle pockets; there could also be a separate pocket for held items, or for a new type of item entirely.