Skip to content

Add a New Booster Pack

Sha0den edited this page Jan 17, 2025 · 7 revisions

This tutorial will explain how to add a new booster pack to the game. This guide will refer to the new booster pack as Genesis, but you can use whatever name you like. Some versions of poketcg will have different function labels. While this guide will focus on the current disassembly, labels from other repositories will occasionally be noted (primarily poketcg_v2).

Contents

  1. Defining All of the New Constants
  2. Creating the Necessary Graphics Files
  3. Editing the Remaining Data Files
  4. Updating the Card Album
  5. Awarding the Booster Pack to the Player

1. Defining All of the New Constants

Before we begin modifying any of the data or engine files, we should establish all of the constants that will be used throughout this tutorial. A lot of important information is organized into a series of numerical IDs, and these IDs are given labels to help us make sense of this information when we encounter them throughout the disassembly.

Let's start with the obvious constants. Begin by opening src/constants/booster_constants.asm, and add a constant for the new booster pack after the one for Laboratory:

 	const_def
 	const BOOSTER_COLOSSEUM  ; $00
 	const BOOSTER_EVOLUTION  ; $01
 	const BOOSTER_MYSTERY    ; $02
 	const BOOSTER_LABORATORY ; $03
+	const BOOSTER_GENESIS	 ; $04

 	const_def
 	const BOOSTER_COLOSSEUM_NEUTRAL           ; $00
 	const BOOSTER_COLOSSEUM_GRASS             ; $01
 	...

In the following section of the same file, you will see a list with each of the variants for every booster pack. For the purposes of this tutorial, we'll just add a single "Neutral" variant for the new booster pack at the end of the list, but you can create however many you feel is appropriate. Most of the other booster packs have a different version for each of the Pokémon types/Card Clubs.

 	...
 	const BOOSTER_ENERGY_WATER_FIGHTING       ; $1a
 	const BOOSTER_ENERGY_GRASS_PSYCHIC        ; $1b
 	const BOOSTER_ENERGY_RANDOM               ; $1c
+	const BOOSTER_GENESIS_NEUTRAL             ; $1d

 DEF NUM_BOOSTERS EQU const_value
 DEF NO_BOOSTER EQU $ff

Next, go to src/constants/card_data_constants.asm, and update the set 1 constants by adding entries for the new booster pack. Make sure you put the new booster pack between CARD_SET_LABORATORY and CARD_SET_PROMOTIONAL, rather than at the end of each of the lists.

 ; card set constants (set 1)
 	const_def
 	const CARD_SET_COLOSSEUM   ; $0
 	const CARD_SET_EVOLUTION   ; $1
 	const CARD_SET_MYSTERY     ; $2
 	const CARD_SET_LABORATORY  ; $3
+	const CARD_SET_GENESIS	   ; $4
 	const CARD_SET_PROMOTIONAL ; $5
 	const CARD_SET_ENERGY      ; $6
 DEF NUM_CARD_SETS EQU const_value – 1

 ; CARD_DATA_SET constants (set 1)
 	DEF COLOSSEUM   EQU CARD_SET_COLOSSEUM   << 4
 	DEF EVOLUTION   EQU CARD_SET_EVOLUTION   << 4
 	DEF MYSTERY     EQU CARD_SET_MYSTERY     << 4
 	DEF LABORATORY  EQU CARD_SET_LABORATORY  << 4
+	DEF GENESIS     EQU CARD_SET_GENESIS     << 4
 	DEF PROMOTIONAL EQU CARD_SET_PROMOTIONAL << 4
 	DEF ENERGY      EQU CARD_SET_ENERGY      << 4

The next constant will need to be added to src/constants/menu_constants.asm. We'll be defining the total number of cards that the new card set will contain. For this example, let's assume that it will contain only 10 cards, which is essentially the minimum amount since that's how many cards a booster pack contains. The absolute maximum number of cards that a card set can contain is defined in wram as 60 cards, but you should be able to use as many as 80 cards without running into any problems. (Note that in poketcg_v2, these constants were deleted, and the information was moved to CardAlbum.CardSetTotals in src/engine/menus/card_album.asm, as it was never referenced outside of that file/function.)

 	DEF NUM_CARDS_COLOSSEUM   EQU 56
 	DEF NUM_CARDS_EVOLUTION   EQU 50
 	DEF NUM_CARDS_MYSTERY     EQU 51
 	DEF NUM_CARDS_LABORATORY  EQU 51
+	DEF NUM_CARDS_GENESIS     EQU 10
 	DEF NUM_CARDS_PROMOTIONAL EQU 20

Another constant will need to be added to src/constants/scene_constants.asm as well. This is for the small cutscene that plays after the player receives a booster pack.

 	...
 	const SCENE_COPYRIGHT                     ; $19
 	const SCENE_JAPANESE_TITLE_SCREEN_2_COPY  ; $1a
 	const SCENE_COLOR_PALETTE                 ; $1b
+	const SCENE_GENESIS_BOOSTER		  ; $1c

 DEF NUM_SCENES EQU const_value

The final constants are related to the graphics that will be added in the following step. That includes 2 more tilemaps (DMG and CGB) in src/constants/tilemap_constants.asm...

 	...
 	const TILEMAP_COPYRIGHT                        ; $66
 	const TILEMAP_COPYRIGHT_CGB                    ; $67
 	const TILEMAP_NINTENDO                         ; $68
 	const TILEMAP_COMPANIES                        ; $69
+	const TILEMAP_GENESIS                          ; $6a
+	const TILEMAP_GENESIS_CGB                      ; $6b

 DEF NUM_TILEMAPS EQU const_value

...and 2 more tilesets in src/constants/tileset_constants.asm.

 	...
 	const TILESET_JESSICA                     ; $54
 	const TILESET_STEPHANIE                   ; $55
 	const TILESET_AARON                       ; $56
+	const TILESET_GENESIS_1                   ; $57
+	const TILESET_GENESIS_2                   ; $58

 DEF NUM_TILESETS EQU const_value


2. Creating the Necessary Graphics Files

To start things off, go to src/gfx/booster_packs. Create a copy of the laboratory1.png file, and name it genesis1.png. Then, create a copy of laboratory2.png, and name it genesis2.png. Since this is merely a tutorial, we won't be going further than that, but if you wish to design your own graphic, feel free to edit the files in your preferred image editing program (e.g. Asesprite, GIMP, Paint.NET, etc.). RGBDS won't be able to use these .png files, but when it comes time to build the game, rgbgfx will use them to generate .2bpp files, which can then be stored within the rom file.


The next file will be added to src/data/maps/tiles/dimensions. This time, create a copy of laboratory.dimensions, and name it genesis.dimensions. Technically, all of the booster pack images have the same dimensions, so there's no need to edit this file.


Moving on, go to src/data/maps/tiles/cgb, and create a copy of laboratory.bin with the name genesis.bin. Feel free to edit it and the .bin file from the next instruction using Tilemap Studio. Just like with the .2bpp files from the first instruction, both genesis.bgmap and genesis.bgmap.lz will be generated upon compiling the rom. You can also ignore any *.match files; they ensure that the repository's data is identical to what exists in the original game, which is irrelevant since we're modifying the original game.


If your game still supports the original Game Boy (DMG), then you'll also need to create a copy of laboratory.bin in src/data/maps/tiles/gb, again renaming it genesis.bin.


And if your game still supports the Super Game Boy, then you'll need to create one last binary file with the relevant palette information in src/data/sgb_data, so copy laboratory_booster_pals.bin and name the new file genesis_booster_pals.bin. You can edit this file as well, but I don't know of any specific program that will make the process easier.

Now, we'll need to add a few lines to src/engine/sgb.asm so that the corresponding .lz file will be included when we build the rom.

 SGBData_LaboratoryBooster:
 	dw $20 ; length
 	INCBIN "data/sgb_data/laboratory_booster_pals.bin.lz"

+SGBData_GenesisBooster:
+	dw $20 ; length
+	INCBIN "data/sgb_data/genesis_booster_pals.bin.lz"
+
 SGBData_PlayerPortraitPals:

Let's do the same with the rest of the files that we just added to the repository. Open src/gfx.asm and add the following to any SECTION that has the requisite space. If none exist, you'll need to add a new SECTION (e.g. Gfx 13) and then assign it to a rom bank in src/layout.link.

Genesis1Gfx::
	dw 96
	INCBIN "gfx/booster_packs/genesis1.2bpp"

Genesis2Gfx::
	dw 86
	INCBIN "gfx/booster_packs/genesis2.2bpp"

GenesisTilemap::
	INCBIN "data/maps/tiles/dimensions/genesis.dimensions"
	dw NULL
	db FALSE ; cgb mode
	INCBIN "data/maps/tiles/gb/genesis.bin.lz"

GenesisCGBTilemap::
	INCBIN "data/maps/tiles/dimensions/genesis.dimensions"
	dw NULL
	db TRUE ; cgb mode
	INCBIN "data/maps/tiles/cgb/genesis.bgmap.lz"

The final task will be to add this new information to the tilemap and tileset tables. First, add another 2 entries to Tilemaps in src/engine/gfx/tilemaps.asm.

 Tilemaps:
	...
 	tilemap CopyrightCGBTilemap,               TILESET_COPYRIGHT                   ; TILEMAP_COPYRIGHT_CGB
 	tilemap NintendoTilemap,                   TILESET_NINTENDO                    ; TILEMAP_NINTENDO
 	tilemap CompaniesTilemap,                  TILESET_COMPANIES                   ; TILEMAP_COMPANIES
+	tilemap GenesisTilemap,                    TILESET_GENESIS_1                   ; TILEMAP_GENESIS
+	tilemap GenesisCGBTilemap,                 TILESET_GENESIS_2                   ; TILEMAP_GENESIS_CGB
 	assert_table_length NUM_TILEMAPS

And then, add the corresponding entries to Tilesets in src/engine/gfx/tilesets.asm

 Tilesets:
	...
 	tileset JessicaGfx,                     36 ; TILESET_JESSICA
 	tileset StephanieGfx,                   36 ; TILESET_STEPHANIE
 	tileset AaronGfx,                       36 ; TILESET_AARON
+	tileset Genesis1Gfx,                    96 ; TILESET_GENESIS_1
+	tileset Genesis2Gfx,                    86 ; TILESET_GENESIS_2
 	assert_table_length NUM_TILESETS


3: Editing the Remaining Data Files

Unsurprisingly, the main booster pack data can be found at src/data/booster_packs.asm. First, we need to define the rarity distribution, located at the top of the file. As always, you can adjust these ratios however you wish, but for this tutorial, we'll simply copy the distribution used for Laboratory, namely 0 Energy cards, 6 Common cards, 3 Uncommon cards and 1 Rare card.

BoosterSetRarityAmountsTable:
;	db energies, commons, uncommons, rares
; commons + uncommons + rares needs to be equal to 10 minus the number of energy cards
; defined in the pack's data below; otherwise, the number of cards in the pack won't be 10.
 	db 1, 5, 3, 1 ; COLOSSEUM
 	db 1, 5, 3, 1 ; EVOLUTION
 	db 0, 6, 3, 1 ; MYSTERY
 	db 0, 6, 3, 1 ; LABORATORY
+	db 0, 6, 3, 1 ; GENESIS

The rest of the file is comprised of specialized variants for each of the booster packs, each with its own card type ratios. If you recall, we only decided to add the one "Neutral" variant for this tutorial, but remember to define any other variants that were assigned constants during Step 1. You can insert the new booster variant(s) anywhere in src/data/booster_packs.asm, but we'll just place this one at the end of the file.

 BoosterPack_RandomEnergies::
 	...
 	db  0 ; Colorless Type Chance
 	db  0 ; Trainer Card Chance
 	db  0 ; Energy Card Chance

+BoosterPack_GenesisNeutral::
+	booster_set GENESIS ; booster pack set
+	dw NULL ; energy or energy generation function
+
+; Card Type Chances
+	db 20 ; Grass Type Chance
+	db 20 ; Fire Type Chance
+	db 20 ; Water Type Chance
+	db 20 ; Lightning Type Chance
+	db 20 ; Fighting Type Chance
+	db 20 ; Psychic Type Chance
+	db 20 ; Colorless Type Chance
+	db 20 ; Trainer Card Chance
+	db  0 ; Energy Card Chance
+

We now need to reference the data that was just created. Open src/engine/booster_packs.asm, and scroll down to BoosterDataJumpTable. Add an entry for the neutral variant that we defined during the previous step. If you created additional variants, then you'll need to add entries for them as well.

 BoosterDataJumptable:
 	...
	dw BoosterPack_EnergyWaterFighting
 	dw BoosterPack_EnergyGrassPsychic
 	dw BoosterPack_RandomEnergies
+	dw BoosterPack_GenesisNeutral 
 	assert_table_length NUM_BOOSTERS

Next, open src/engine/menus/give_booster_pack.asm, and add a similar entry to BoosterTypes, using the same order from BoosterDataJumpTable.

 BoosterTypes:
 	...
 	db BOOSTER_COLOSSEUM  ; BOOSTER_ENERGY_WATER_FIGHTING
 	db BOOSTER_COLOSSEUM  ; BOOSTER_ENERGY_GRASS_PSYCHIC
 	db BOOSTER_COLOSSEUM  ; BOOSTER_ENERGY_RANDOM
+	db BOOSTER_GENESIS    ; BOOSTER_GENESIS_NEUTRAL
 	assert_table_length NUM_BOOSTERS

We should also put another entry at the end of BoosterScenesAndNameTexts in the same file. (If you're using poketcg_v2, you should replace GenesisBoosterText with GenesisName.)

 BoosterScenesAndNameTexts
	...
 	db SCENE_LABORATORY_BOOSTER, SCENE_LABORATORY_BOOSTER
 	tx LaboratoryBoosterText
+
+	db SCENE_GENESIS_BOOSTER, SCENE_GENESIS_BOOSTER 
+	tx GenesisBoosterText

 _PauseMenu_Exit:
 	ret

We'll have to make a quick detour before we resume editing the rest of the data files since GenesisBoosterText doesn't yet exist. All of the game's text is located in src/text. You can either replace an unused text or add it to any of the text files that isn't full. You may want to look at the Add New Text tutorial if you're still unfamiliar with the process. (If you're using poketcg_v2, make sure to again replace all instances of GenesisBoosterText with GenesisName.)

GenesisBoosterText:
	text "Genesis"
	done

More data pertaining to the booster pack scenes can be found in src/data/scenes.asm. First, add an entry to ScenePointers.

ScenePointers:
	...
	dw Scene_Copyright
 	dw Scene_JapaneseTitleScreen2
 	dw Scene_ColorPalette
+	dw Scene_GenesisBooster
 	assert_table_length NUM_SCENES

Then, define that scene at the end of the file. The palettes were simply copied from Scene_LaboratoryBooster; however, if you designed your own booster pack graphic during Step 2, then you can change PALETTE_104 to whatever palette the new graphic uses. If it's a custom palette, you'll first need to define that somewhere and then add an entry to Palettes in src/data/palette_pointers.asm.

 Scene_JapaneseTitleScreen2:
 	dw NULL
 	dw NULL
 	db PALETTE_109, PALETTE_100, $00
 	db TILEMAP_JAPANESE_TITLE_SCREEN_2, TILEMAP_JAPANESE_TITLE_SCREEN_2_CGB, $01, $00
 	db $00

+Scene_GenesisBooster: 
+	dw SGBData_GenesisBooster
+	dw NULL
+	db PALETTE_108, PALETTE_104, $01
+	db TILEMAP_GENESIS, TILEMAP_GENESIS_CGB, $80, $00
+	db SPRITE_BOOSTER_PACK_OAM
+	db PALETTE_117, PALETTE_117, $00
+	db $ff, SPRITE_ANIM_189, $00, $00
+	dw $00
+

Finally, none of the previous information matters if there aren't any cards in the Genesis set. We can assign some of the cards in the game to the new booster pack by editing src/data/cards.asm. The following example will show how to move the Bulbasaur card from the Evolution set to the Genesis set, but you can edit whichever cards you want. Just be sure that the number of cards assigned to your new booster pack matches the set total that was recorded during Step 1, and you should also note that it's a good idea to have at least as many cards in the set as there are in a booster pack. For this tutorial, that means that we need to assign 10 cards to the new Genesis set: 6 Commons, 3 Uncommons and 1 Rare.

 BulbasaurCard:
 	db TYPE_PKMN_GRASS ; type
 	gfx BulbasaurCardGfx ; gfx
 	tx BulbasaurName ; name
 	db CIRCLE ; rarity
-	db EVOLUTION | NONE ; sets
+	db GENESIS | NONE ; sets
 	db BULBASAUR
 	db 40 ; hp
 	db BASIC ; stage
 	dw NONE ; pre-evo name


4. Updating the Card Album

Moving on, it's important that we include the new booster pack in the Card Album, which can be accessed from the PC menu. There's a lot to edit, but fortunately it's all contained inside the one file: src/engine/menus/card_album.asm.

To start things off, go to CreateCardSetListAndInitListCoords, and add another section before the one for Laboratory.

 .GetEntryPrefix
 	push af
 	cp CARD_SET_PROMOTIONAL
-	jr nz, .laboratory
+	jr nz, .genesis
 	lb de, TX_FULLWIDTH3, "FW3_P"
 	jr .got_prefix
+.genesis
+	cp CARD_SET_GENESIS
+	jr nz, .laboratory
+	lb de, TX_FULLWIDTH3, "FW3_E"
+	jr .got_prefix
 .laboratory
 	cp CARD_SET_LABORATORY
 	jr nz, .mystery
 	...

If you're using poketcg_v2 or if you simply copied the commit for preventing header text from being overwritten, then you'll also need to add another entry to BoosterNamesTextIDTable, which is located just below .GetEntryPrefix.


Still in the same file, find the CardAlbum function and scroll down to .BoosterPackMenuParams (.SetSelectionMenuParams in poketcg_v2 and .MenuParameters in Pokémon TCG Neo). We'll be increasing the number of menu items that are displayed as well as the spacing between them. Removing the double spacing is a simple workaround that should suffice for now. A better solution would be to have the items be scrollable, but that requires a bit more work. It will probably be added to the tutorial eventually.

 .BoosterPackMenuParams:
 	db 3, 3 ; cursor x, cursor y
-	db 2 ; y displacement between items
+	db 1 ; y displacement between items
-	db 5 ; number of items
+	db 6 ; number of items
 	db SYM_CURSOR_R ; cursor tile number
 	db SYM_SPACE ; tile behind cursor
 	dw NULL ; function pointer if non-0

Scroll down even further to .PrintCardCount to set up the card album header for the new booster. (This edit isn't necessary in poketcg_v2.

.PrintCardCount
 	...
 ; print the total number of cards that are in the Card Set
 	ld a, [wSelectedCardSet]
 	cp CARD_SET_PROMOTIONAL
-	jr nz, .check_laboratory
+	jr nz, .check_genesis 
 ; promotional
-	ldtx hl, Item5PromotionalCardText
+	ldtx hl, Item6PromotionalCardText
 	ld e, NUM_CARDS_PROMOTIONAL - 2 ; minus the phantom cards
 	ld a, [wOwnedPhantomCardFlags]
 	bit VENUSAUR_OWNED_PHANTOM_F, a
 	jr z, .check_owns_mew
 	inc e
.check_owns_mew
 	bit MEW_OWNED_PHANTOM_F, a
 	jr z, .has_card_set_count
 	inc e
 	jr .has_card_set_count
+.check_genesis
+	cp CARD_SET_GENESIS
+	jr nz, .check_laboratory
+	ldtx hl, Item5GenesisText
+	ld e, NUM_CARDS_GENESIS
+	jr .has_card_set_count
 .check_laboratory
 	cp CARD_SET_LABORATORY
 	jr nz, .check_mystery
 	...

When the player doesn't have any promotional cards, the game replaces that menu option with a series of dashes. Since the coordinates of the menu items were changed, we need to update the printing coordinates for EmptyPromotionalCardText. This is handled in the same function under .draw_box (.skip_clear_screen in Pokémon TCG Neo), near the end of the file. (This edit also isn't necessary in poketcg_v2; although, there are a couple of other changes that will need to be made. You should add another entry under .CardSetTotals between the ones for CARD_SET_LABORATORY and CARD_SET_PROMOTIONAL (assuming you didn't already do so during Step 1). You should also add another entry under .SetNames for GenesisName, this time between LaboratoryName and PromotionalName.

 	...
; still has no promotional, print empty Card Set name
 	ld a, TRUE
 	ld [wUnavailableAlbumCardSets + CARD_SET_PROMOTIONAL], a
-	ld e, 11
+	ld e, 8
 	ld d, 5
	call InitTextPrinting
	ldtx hl, EmptyPromotionalCardText
	call ProcessTextFromID
 	...

The last thing to edit in src/engine/menus/card_album.asm is the list of menu data located at the end of the file, still within the CardAlbum function. More specifically, the print coordinates for each of the booster pack names needs to be updated now that the menu items are single-spaced; there's also one more entry since we added another booster pack. (Note that the coordinates are different in poketcg_v2 and will need to be adjusted.)

 .BoosterPacksMenuData
 	textitem 7,  1, BoosterPackTitleText
 	textitem 5,  3, Item1ColosseumText
-	textitem 5,  5, Item2EvolutionText
-	textitem 5,  7, Item3MysteryText
-	textitem 5,  9, Item4LaboratoryText
-	textitem 5, 11, Item5PromotionalCardText
+	textitem 5,  4, Item2EvolutionText
+	textitem 5,  5, Item3MysteryText
+	textitem 5,  6, Item4LaboratoryText
+	textitem 5,  7, Item5GenesisText
+	textitem 5,  8, Item6PromotionalCardText
 	db $ff

Before we move on to the next step, we'll need to edit some of the game's text data to comply with our recent changes. First, we'll open src/text/text2.asm, and update Item5PromotionalCardText.

-Item5PromotionalCardText:
-	text " 5. Promotional Cards"
+Item6PromotionalCardText:
+	text " 6. Promotional Cards"
	done

You'll also need to open src/text/text_offsets.asm and rename the label for its pointer.

-	textpointer Item5PromotionalCardText
+	textpointer Item6PromotionalCardText

Plus, we referenced another text that doesn't yet exist. Again, you can either replace an unused text or add it to any of the text files that isn't full, and you can reference the Add New Text tutorial if you're still unfamiliar with the process.

Item5GenesisText:
	text "5. Genesis"
	done

If you're using poketcg_v2, then you'll have to define GenesisText from BoosterNamesTextIDTable too. It's identical to GenesisBoosterText/GenesisName, except that its contents are printed using fullwidth text (8x8 pixel characters) instead of halfwidth text (4x8 pixel characters).

GenesisText:
	textfw "Genesis"
	done


5. Awarding the Booster Pack to the Player

The new booster pack is now in the game, but there isn't yet a way for the player to obtain it. In the original game, the primary way to acquire cards is to defeat NPC duelists, as each duelist can reward up to 3 booster packs upon defeat.

For now, let's simply change Water Club Member Sara's 2nd pack to the neutral variant of the new Genesis booster. Open src/scripts/water_club.asm, scroll down to Script_BeatSara, and edit the following line.

 Script_BeatSara:
 	start_script
 	max_out_event_value EVENT_BEAT_SARA
 	print_npc_text SaraPlayerWon1Text
-	give_booster_packs BOOSTER_COLOSSEUM_WATER, BOOSTER_COLOSSEUM_WATER, NO_BOOSTER
+	give_booster_packs BOOSTER_COLOSSEUM_WATER, BOOSTER_GENESIS_NEUTRAL, NO_BOOSTER
 	print_npc_text SaraPlayerWon2Text
 	quit_script_fully

You'll end up using the same constants regardless of how the booster pack is rewarded. For example, you could also switch the booster pack that Dr. Mason gives you alongside his initial e-mail by making the following change to PCMailBoosterPacks in src/engine/menus/mail.asm.

 PCMailBoosterPacks:
 	table_width 2, PCMailBoosterPacks
 	db $00, $00 ; unused
-	db BOOSTER_COLOSSEUM_NEUTRAL, $00                       ; mail 1
+	db BOOSTER_GENESIS_NEUTRAL, $00                         ; mail 1
 	db BOOSTER_LABORATORY_PSYCHIC, $00                      ; mail 2
 	db BOOSTER_EVOLUTION_GRASS, $00                         ; mail 3