Skip to content
ElectroDeoxys edited this page May 8, 2024 · 3 revisions

This tutorial is for how to add a new card, allowing for up to 254 cards in the game. Card IDs in this game are 8-bit, which means they can range in value between 0 and 255 inclusive. However, the IDs $00 and $FF are reserved for special list handling, so effectively only 254 card IDs are considered valid. As an example, we'll add this Chikorita card.

Contents

  1. Define a card constant
  2. Define the card data
  3. Add card graphics
  4. Add text
  5. Adjust layout.link

1. Define a card constant

Edit src/constants/card_constants.asm:

        const TANGELA_LV12                ; $2d
        const SCYTHER                     ; $2e
        const PINSIR                      ; $2f
+       const CHIKORITA
        const CHARMANDER                  ; $30
        const CHARMELEON                  ; $31
        const CHARIZARD                   ; $32

Here we respected the logical order of the cards, inserting it as the last Grass Pokémon card. This order will matter for the edits in the rest of the files. At this point, if you try to run make, then you will get some errors warning you that some tables are the wrong length. Indeed, with the addition of a new card constant, we need to update some data entries. So let's get to it!

Note: You might notice that there will be a gap between ; $2f and ; $30 in the list of constants. These are merely comments to document which constant refers to which hex value. Since a new constant is introduced right after $2f, then CHIKORITA will become the new $30 and all other subsequent entries will be shifted up by 1. At this point it's probably a good idea to either update these values or just delete these comments, so as to not introduce any confusion in the constant values.

2. Define the card data

Edit src/data/card.asm:

 CardPointers::
	table_width 2, CardPointers
	dw NULL
	dw GrassEnergyCard
        ...
        dw TangelaLv12Card
        dw ScytherCard
        dw PinsirCard
+       dw ChikoritaCard
        dw CharmanderCard
        dw CharmeleonCard
        dw CharizardCard

After adding this pointer, we need to fill in the data that we want to assign to the card. Edit the file again some lines down, after the data corresponding to Pinsir:

        tx PinsirDescription ; description
        db 0

+ChikoritaCard:
+       db TYPE_PKMN_GRASS ; type
+       gfx ChikoritaCardGfx ; gfx
+       tx ChikoritaName ; name
+       db CIRCLE ; rarity
+       db COLOSSEUM | NONE ; sets
+       db CHIKORITA
+       db 50 ; hp
+       db BASIC ; stage
+       dw NONE ; pre-evo name
+
+       ; attack 1
+       energy COLORLESS, 1 ; energies
+       tx TackleName ; name
+       dw NONE ; description
+       dw NONE ; description (cont)
+       db 10 ; damage
+       db DAMAGE_NORMAL ; category
+       dw NONE ; effect commands
+       db NONE ; flags 1
+       db NONE ; flags 2
+       db NONE ; flags 3
+       db 0
+       db ATK_ANIM_HIT ; animation
+
+       ; attack 2
+       energy GRASS, 1 ; energies
+       tx DeflectorName ; name
+       tx DeflectorDescription ; description
+       tx DeflectorDescriptionCont ; description (cont)
+       db 0 ; damage
+       db RESIDUAL ; category
+       dw ElectabuzzLightScreenEffectCommands ; effect commands
+       db NONE ; flags 1
+       db NULLIFY_OR_WEAKEN_ATTACK ; flags 2
+       db NONE ; flags 3
+       db 0
+       db ATK_ANIM_BARRIER ; animation
+
+       db 1 ; retreat cost
+       db WR_FIRE ; weakness
+       db NONE ; resistance
+       tx LeafName ; category
+       db 152 ; Pokedex number
+       db 0
+       db 12 ; level
+       db 2, 11 ; length
+       dw 14 * 10 ; weight
+       tx ChikoritaDescription ; description
+       db 0
+
 CharmanderCard:
        db TYPE_PKMN_FIRE ; type
        gfx CharmanderCardGfx ; gfx

Here's the meaning of each field in order:

  • type of card, either Grass, Fire, Water, Trainer, etc.
  • card picture graphics.
  • text ID of card name.
  • rarity, either Circle, Diamond, Star or Promo.
  • card set, which booster pack will it belong to, and also optionally an indication for the Jungle, Fossil, GB or Promo icon.
  • card constant that this card corresponds to.
  • amount of HP.
  • what Pokémon stage it is, either Basic, 1 Stage or 2 Stage.
  • text ID of pre-evolution card name, if any.
  • attack 1 and attack 2:
    • energy cost.
    • name text ID.
    • description text ID (page 1).
    • description text ID (page 2).
    • damage.
    • category, which will be tied to how damage is calculated.
    • flags, which are associated to how the AI scores each attack.
    • animation index, which will play when the attack is used.
  • retreat cost
  • weakness, will be a WR_* constant
  • resistance, will be a WR_* constant
  • flavor related information
    • category text ID, (i.e. "Leaf" in "Leaf Pokémon")
    • Pokédex number
    • level
    • length, in feet and inches
    • weight in lbs, which is multiplied by 10 so that the decimal can be shown
    • text ID of Pokédex description

A couple of things of note here. Firstly, there's a lot of stuff that is not defined yet, namely ChikoritaCardGfx, and ChikoritaName, DeflectorName, DeflectorDescription, DeflectorDescriptionCont, LeafName and ChikoritaDescription. Secondly, we are reusing the attack effect already implemented for Electabuzz's Light Screen, ElectabuzzLightScreenEffectCommands, which has an identical effect to Deflector. That will save us the trouble of implementing the attack ourselves. When in doubt, the data of a similar card (e.g. Bulbasaur) can be copied and then you can modify what is needed. Additionally, it's important to keep in mind that this is specific to Pokémon cards. Energy cards and Trainer cards will have decidedly different formats. You can check the documentation in the disassembly to learn of how they are structured.

3. Add card graphics

For the card picture, you'll need a 64x48 PNG file with only 4 colors. As for this example, we'll use the following picture:

chikorita

Save it as chikorita.png inside src/gfx/cards. Then edit src/gfx.asm and insert the picture right after the Recycle card graphics:

 RecycleCardGfx::
        INCBIN "gfx/cards/recycle.2bpp"
        INCBIN "gfx/cards/recycle.pal"
+
+ChikoritaCardGfx::
+       INCBIN "gfx/cards/chikorita.2bpp"
+       INCBIN "gfx/cards/chikorita.pal"

For this case we will put the picture at the end of the card graphics so as to not move them around the banks. By using INCBIN, we are signalling that a .2bpp and .pal file need to be generated from the Chikorita PNG file, which will happen when you run make.

4. Add text

We'll need to include in the ROM all the text needed for displaying the card information. Before we can add new text, we need to make some space in the bank that holds the text offsets by deleting some unused text. Edit src/text/text_offsets.asm:

 TextOffsets::
        ...
        textpointer WeaknessText                                       ; 0x0008
        textpointer ResistanceText                                     ; 0x0009
        textpointer PKMNPWRText                                        ; 0x000a
-       textpointer UnusedText000b                                     ; 0x000b
        textpointer LengthText                                         ; 0x000c
        textpointer WeightText                                         ; 0x000d
        textpointer PokemonText                                        ; 0x000e
        ...
        textpointer TrainerCardText                                    ; 0x001f
        textpointer EnergyCardText                                     ; 0x0020
        textpointer DeckPrinterText                                    ; 0x0021
-       textpointer UnusedText0022                                     ; 0x0022
        textpointer NoPokemonOnTheBenchText                            ; 0x0023
        textpointer UnableDueToSleepText                               ; 0x0024
        textpointer UnableDueToParalysisText                           ; 0x0025

Then delete the text corresponding to these entries in src/text/text1.asm:

 PKMNPWRText:
        text "PKMN PWR"
        done

-UnusedText000b: ; Unused (Pokemon Card)
-       textfw "ポケモンカード"
-       done
-
 LengthText:
        text "Length"
        done
        ...
 DeckPrinterText:
        text "Deck"
        done

-UnusedText0022: ; Unused
-       text "Attack"
-       done
-
 NoPokemonOnTheBenchText:
        text "No Pokémon on the Bench."
        done

Now we can go ahead and add the text that we need. Edit src/text/text_offsets.asm again, to add the entries for the new text:

 TextOffsets::
        ...
        textpointer GamblerDescription                                 ; 0x0bab
        textpointer RecycleName                                        ; 0x0bac
        textpointer RecycleDescription                                 ; 0x0bad
+       textpointer ChikoritaName
+       textpointer ChikoritaDescription
+       textpointer LeafName
+       textpointer DeflectorName
+       textpointer DeflectorDescription
+       textpointer DeflectorDescriptionCont

Finally, we are going to add the new text at the end of src/text/text13.asm:

 RecycleDescription:
        line "in your discard pile on top of your"
        line "deck."
        done
+
+ChikoritaName:
+       text "Chikorita"
+       done
+
+ChikoritaDescription:
+       text "A sweet aroma gently wafts from the"
+       line "leaf on its head. It is docile and"
+       line "loves to soak up the sun's rays."
+       done
+
+LeafName:
+       text "Leaf"
+       done
+
+DeflectorName:
+       text "Deflector"
+       done
+
+DeflectorDescription:
+       text "Whenever an attack does damage to"
+       line "Chikorita (after applying Weakness"
+       line "and Resistance) during your"
+       line "opponent's next turn, that attack"
+       line "only does half the damage to"
+       line "Chikorita (rounded down to the"
+       line "nearest 10)."
+       done
+
+DeflectorDescriptionCont:
+       text "(Any other effects of attacks still"
+       line "happen.)"
+       done

5. Adjust layout.link

There's just one more pesky detail that needs to be addressed. The data we added for the Chikorita card makes the bank holding all the card data overflow. To be able to assemble the ROM, we will need to move some data around. Luckily, we can just move the "Cards" section to another empty bank and it will be solved. But we can do a little trick by editing src/layout.link:

 ROMX $0b
        "Effect Functions"
 ROMX $0c
        "Decks"
-       "Cards"
 ROMX $0d
        "Text 1"
 ROMX $0e

Here we can see that the "Cards" section was hardcoded to be in ROM $0c. By removing the section inside layout.link, we are creating a floating section. This means the assembler will place it in the first spot in ROM where there is space for it. If you prefer to have it hardcoded, you can alternatively move it to an empty bank (say ROM $0a).

And that is it, you just created your first card!

chikorita1