PHO - Pokémon Hackers Online
Go Back   PHO - Pokémon Hackers Online > ROM Hacking > Guides & Documentation

Guides & Documentation Learn how to make your own Pokémon game through the process of ROM Hacking, or help out the community by sharing your information.

Thread Tools Display Modes
Old 28th June 2015, 07:21 PM   #1
Join Date: May 2015
Posts: 14
Default Pokemon XD Hacking Info Dump

This is a copy of my thread on project pokemon which is where you'll find the rest of my stuff.

I have a lot of information on XD which I'll be adding to this post. I've been writing an app to streamline the hacking process and I've pretty much completed the logic and just need to complete the UI now. As a result there is a lot of code that is quite useful as a reference. It's all in the swift programming language which I doubt many people here use but it should be simple enough to figure out what it all does.

Here's a link to the repository :

Part 1 of my tutorials:

I'll be updating this post with more details.


Types, TMs, HMs, natures and abilities are the same as any other gen III main series game.

Bag Slots

None = 0x0
Pokeballs = 0x1
Items = 0x2
Berries = 0x3
TMs = 0x4
KeyItems = 0x5
Colognes = 0x6
BattleCDs = 0x7

Super effectiveness

Ineffective = 0x43
NotVeryEffective = 0x42
Neutral = 0x3F
SuperEffective = 0x41

EXP Rates

Evolution Methods:

Same as other games with 0x10 being used for the XD exclusive eevee evolutions with the sun and moon shards


Male = 0x0
Female = 0x1
Genderless = 0x2


Shadow Lab = "D1"
Mt. Battle = "D2"
S.S. Libra = "D3"
Realgam Tower = "D4"
CipherKey Lair = "D5"
Citadark Isle = "D6"
Orre Colosseum = "D7"
Phenac City = "M1"
Pyrite Town = "M2"
Agate Village = "M3"
Pokemon HQ = "M5"
Gateon Port = "M6"
Outskirt Stand = "S1"
Snagem Hideout = "S2"
Kaminkos House = "S3"

Move Targets:

Selected Target = 0x00
Depends On Move = 0x01
All Pokemon = 0x02 (I think this is an XD exclusive as Shadow Half is the only move that uses it.)
Random = 0x03
Both Foes = 0x04
User = 0x05
Both Foes and Ally = 0x06
Opponent Field = 0x07

Special String Characters:

Font Colours:

When you use the special character that changes the font colour to a predefined colour, these are the colours that the next byte refers to. I tried going above 5 and they all remained black (or maybe white, can't remember)
White = 0x00
Yellow = 0x01
Green = 0x02
Blue = 0x03
Yellow2 = 0x04
Black = 0x05


There are slots for the key items in r/s which are unimplemented. The new items and key items exclusive to XD come at the end.

Trainer Models:

Trainer Classes:


None = 0x0
Sun = 0x1
Rain = 0x2
Sandstorm = 0x3
Hail = 0x4
ShadowSky = 0x5


same as gen 3 games with a couple of additions. Note that gen 3 order is different from later gens.
Bulbasaur = 0x0001
Deoxys = 0x019A
Chimecho = 0x019B
??? = 0x019C
Bonsly = 0x019D
Munchlax = 0x019E (It's literally just munchlax's name which is used as a reference for pokespots. It doesn't have a battle model or any battle data)


Same as other games but with the shadow moves afterwards
Pound = 0x1
Psycho Boost = 0x162
??? = 0x163 (unused)
Shadow Blitz = 0x164
Shadow Rush = 0x165
Shadow Break = 0x166
Shadow End = 0x167
Shadow Wave = 0x168
Shadow Rave = 0x169
Shadow Storm = 0x16A
Shadow Fire = 0x16B
Shadow Bolt = 0x16C
Shadow Chill = 0x16D
Shadow Blast = 0x16E
Shadow Sky = 0x16F
Shadow Hold = 0x170
Shadow Mist = 0x171
Shadow Panic = 0x172
Shadow Down = 0x173
Shadow Shed = 0x174
Shadow Half = 0x175
??? = 0x176 (unusable)

Move Effects:
same as other games but with a few additions.
harshly lowers foes evasion = 0xD6 (shadow mist)
changes weather to shadow sky = 0xD7 (shadow sky)
eliminates moves like reflect. = 0xD8 (shadow shed)
reduces the HP of all pokemon in battle by half. must recharge. = 0xD9 (shadow half)

Move Category:

None = 0x0
Physical = 0x1
Special = 0x2



First TM in Start.dol = 0x40239F (The HMs come straight after)
First Battle Bingo Card in common_rel = 0x1CAF
Mt. Battle Chikorita in Start.dol = 0x1C5974
Mt. Battle Cyndaquil in Start.dol = 0x1C59A0
Mt. Battle Totodile in Start.dol = 0x1C59CC
First PokeSpot pokemon in common_rel = 0x2FAC
Demo Starter Vaporeon in Start.dol = 0x14F614
Demo Starter Jolteon in Start.dol = 0x14F73C
Starter Eevee in Start.dol = 0x1CBC50
Trade Meditite in Start.dol = 0x1C5888
Trade Shuckle in Start.dol = 0x1C58D8
Trade Larvitar in Start.dol = 0x1C5928
Traded Shadow Togepi in Start.dol = 0x1C5760 (I found the elekid you get in the trade but accidentally lost the offset. Will find it again)
First Item in common_rel = 0x1FEE4
First Move in common_rel = 0xA2710
First Nature in common_rel = 0x47728
First Trainer Class in common_rel = 0xEA40
First Tutor Move in common_rel = 0xA7918
First Type in common_rel = 0xA7C30


First Ability Name ID = 0xC1D
First Ability Description ID = 0xCE5
First Trainer Class Name ID = 0x1B59

Entry Numbers:

Number of Abilities = 0x4D
Number of TMs and HMs = 0x3A
Number of Trainer Classes = 0x33 (first is empty entry)
Special Characters with 2 byte values = [0x07,0x09,0x38,0x52,0x53,0x5B,0x5C]
Special Characters with 5 byte values = [0x08]
Number of Bingo Cards = 0x0B
Number of PokeSpot entries = 0x0B
Number of Items = 0x01BC
Number of Moves = 0x0177 (first is an empty entry as well as 0x0163 and 0x0177)
Number of Natures = 0x19
Number of Pokemon = 0x019F (first is an empty slot and so is 0x19C. There are also 25 empty slots between celebi and treeko like in other gen III games)
Number of Tutor Moves = 0x0C
Number of Types = 0x12
Max Number of Evolutions = 0x05
Max Number of Level Up Moves = 0x13

Entry Sizes:

Size of TM entry = 0x08
Size of Bingo Card entry = 0xB6
Size of Battle Bingo Pokemon entry = 0x0A
Size of PokeSpot Pokemon entry = 0x0C
Size of Trainer Pokemon entry = 0x20
Size of Item Entry = 0x28
Size of Move entry = 0x38
Size of Nature entry = 0x28
Size of Pokemon stats entry = 0x124
Size of Trainer entry = 0x38
Size of Trainer Class entry = 0x0C
Size of Tutor Move entry = 0x0C
Size of Type entry = 0x30
Size of Evolution entry = 0x06
Size of Level Up Move entry = 0x04


First Shadow Move Index = 0x0164 (The game's ASM determine's whether a move is a shadow move by compring it's index to 0x164)
First TM Item Data = 0x0121

Texture Editing:

I've uploaded the code I use to replace textures to the git hub repository. It's all in swift because I use it on my ipad app but anyone is free to port it.
Before running the code I use the program TiledGGD to extract the texture as a PNG.
Here's how:

First open the file in a text editor. The first 4 bytes are the width and height of the texture although sometimes one of the sizes may end up being a multiple of this value. I'm not sure how this works yet though so I just use it to get an idea.

The 5th byte is the number of bits per pixel for the image. Some are 8 bit (indexed) and some are 16 or 32 bits (not indexed). There are also a few that are 4 bits per pixel but don't have a palette which is odd for 4bpp images. Treating them as non-indexed doesn't yield a perfect image though so more research is needed for these ones.

The 4 byte value at offset 0x28 is a pointer to the start of the pixel data. This always points to 0x80 in every texture I've encountered so far.

The 4 byte value at offset 0x48 is a pointer to the start of the palette data. If the image isn't indexed this value defaults to 0.

Using this information we can figure out the settings for TiledGGD. The bits per pixel is the 5th byte in the texture. The images are Tiled. The tile sizes are 8x4 for 8bpp images and 4x4 for 16bpp images. Not sure of the tile sizes for other pixel depths and don't know how the game determines the tile size from the data (Maybe it checks if the dimensions are divisble by 8 or not?). The image start offset is the value at 0x28 (always 0x80). The palette start offset is the value at 0x48. If the image isn't indexed then set the image endianness to little. Otherwise set the palette endianness to little instead. The colour order is RGB and the alpha value is at the start. Don't ignore the alpha value.

The width and height from the data isn't always right so I just adjust the size with the arrow keys until the image looks right. It's usually pretty obvious when it's been adjusted properly.

Now that the image is displayed properly, just use the save graphics option on the file menu to save it as PNG image.

Once I have the PNG I run it through the program along with the fdat file it was extracted from.

These are the simplified steps the program goes through.

1. Convert the PNG to a bitmap.
2. Rearrange the pixels into the order they will be in as a tiled image. This requires the original fdat to determine details like the tile width and tile height.
3. Convert the pixels to format used in the texture. If it is indexed then each new colour is added to the palette and then each pixel using that colour is converted to an index.
4. The data is then connverted to bytes and written back to the fdat file.

Data Tables:

I'm feeling a bit lazy so I'm just going to copy the offsets from my code. Hopefully the variable names make sense to others. I'll be explaining some of the quirkier ones.


The table starts at 0x47BA0 in common_rel. Each entry is 8 bytes long. The last 4 bytes are the string ID of the ribbon's description.

Battle Bingo Card:

Each card has 3 mystery panels and 13 regular ones.

let kBingoCardIndexOffset = 0x01
let kBingoCardDifficultyLevelOffset = 0x02
let kBingoCardSubIndexOffset = 0x03
let kBingoCardPokemonLevelOffset = 0x04 // Every Pokemon on the card including the starter is of this level.
let kBingoCardPokemonCountOffset = 0x07 // Always has the same value of 13
let kBingoCardMysteryPanelCountOffset = 0x08 // Always has the same value of 3
let kBingoCardNameIDOffset = 0x0B
let kBingoCardDetailsIDOffset = 0x0F
let kBingoCardFirstCouponsRewardOffset = 0x11 // The 10 levels of coupons you receive for the number of bingos achieved.
let kBingoCardFirstPokemonOffset = 0x25 // The first pokemon specified is your starter for that card
let kBingoCardFirstMysteryPanelOffset = 0xB1
Each panel is 2 bytes. The first byte is the the item under the panel:
0x1 = masterball
0x2 = epx1
0x3 = epx2

The second byte is the position of the panel on the board. I believe the top left corner is panel 0 and the rest follow horizontally the rows from top to bottom.

The pokemon are all specified in the order of their panels.


Battle Bingo Pokemon

let kBattleBingoPokemonPanelTypeOffset = 0x00 // Each pokemon has 2 types in its stats. this value determines whether type 0 or type 1 appears on the back of the panel.
let kBattleBingoPokemonAbilityOffset = 0x01 // Determines which of the pokemon's abilities it has
let kBattleBingoPokemonNatureOffset = 0x02
let kBattleBingoPokemonGenderOffset = 0x03 // The genders of the pokemon appear to be random outside of the battles probably due to a programming error.
let kBattleBingoPokemonSpeciesOffset = 0x04
let kBattleBingoPokemonMoveOffset = 0x06 // Only one move per pokemon


let kBagSlotOffset = 0x00 // Determines the pocket the item goes in in the bag like Key items or berries.
let kItemCantBeHeldOffset = 0x01 If this is set you don't get the option to 'GIVE' the item to a pokemon
let kInBattleUseItemIDOffset = 0x04 Used on items that can be used on your pokemon in battle like potions. Not sure what this value affects if anything.
let kItemPriceOffset = 0x06
let kItemCouponCostOffset = 0x08 // Price in battle coupons.
let kItemBattleHoldItemIDOffset = 0x0B Used on items that can be used on by pokemon in battle like the choice band. Not sure what this value affects if anything.
let kItemNameIDOffset = 0x12
let kItemDescriptionIDOffset = 0x16
let kItemParameterOffset = 0x1B // Used on some items to determine things like the amount of HP restored or the chance of activation.
let kFirstFriendshipEffectOffset = 0x24
There are 3 friendship effects and they are signed UInt8s. When the item is used the pokemon's happiness increases or decreases by this value. There are 3 because the amount the value changes by is dependent on the the current happiness. Bulbapedia has the exact values that determine the change. IIRC, the first one is below 100.


let kBattlePurificationOffset = 0x00
let kWalkingPurificationOffset = 0x01
let kCallPurificationOffset = 0x02
let kDayCarePurificationOffset = 0x03
let kColognePurificationOffset = 0x04
let kAttackModificationOffset = 0x05
let kDefenseModificationOffset = 0x06
let kSpAtkModificationOffset = 0x07
let kSpDefModificationOffset = 0x08
let kSpeedModificationOffset = 0x09
let kNatureNameIDOffset = 0x16

Trainer Classes:

A trainer's prize money is their class' payout x max pokemon level x 2. Although Greevil gives 5300 (300 more than expected) after his shadow lugia battle and then the expected 5000 after his actual battle. I don't think that battle uses a separate trainer class so not sure how the game determines the prize money for that battle. Could just be hard coded.
let kTrainerClassPayoutOffset = 0x00
let kTrainerClassNameIDOffset = 0x06

Tutor Moves

A trainer's prize money is their class' payout x max pokemon level x 2. Although Greevil gives 5300 (300 more than expected) after his shadow lugia battle and then the expected 5000 after his actual battle. I don't think that battle uses a separate trainer class so not sure how the game determines the prize money for that battle. Could just be hard coded.
Move's index = 0x00
Availability flag = 0x07
This value affects whether the move is available or not. They are probably in game flags that are set when you've been to a certain map. I haven't documented the values used yet, nor have I tested different values.


let kCategoryOffset = 0x0
let kTypeNameIDOffset = 0xA
let kFirstEffectivenessOffset = 0xD These are listed in the same order as the types are. This determines if the type specified by the current row is super effective on the type the current byte corresponds to.
let kSizeOfTypeData = 0x30

I have changed the ? type to fairy type but it does require some of the ASM to be tweaked a little bit. It has definitely affected a few things and some minor compromises had to be made. I haven't played through the game fully so I might have messed some stuff up without knowing. As far as I can tell, it's very stable though.


let kEvolutionMethodOffset = 0x0 // 1 byte
let kEvolutionConditionOffset = 0x2 // 2 bytes // Like the item or the level required
let kEvolvedFormOffset = 0x4 // 2 bytes

Level up move:

let kLevelUpMoveLevelOffset = 0x0 // 1 byte
let kLevelUpMoveIndexOffset = 0x2 // 2 bytes

Gift and Trade Pokemon:

I'm feeling a bit lazy so I'm just going to copy the offsets from my code. Hopefully the variable names make sense to others. I'll be explaining some of the quirkier ones.

These are actually part of the game's ASM and so don't come in nice tables. They're easy enough to work with though.
The start offsets in Start.dol are given above and these are the offsets to the useful values.

Where I describe "Shiny Values", use:
0x0000 for never shiny
0x0001 for always shiny
0xFFFF for random

Mt. Battle Prizes

These don't come with a level like the other gift pokemon. They probably all have their level specified by the same line of code but I couldn't be bothered to find it since the only way for me to test it would be to play through the whole game (or hope to find a save file that happened to be at the top of mt.battle). The value of 0x5 is quite a common value so it's a harder value to just assume to be correct.

0x02 Species
0x06 Move1
0x0A Move2
0x0E Move3
0x12 Move4

Also note that there are 3 strings for the text in the multichoice box for choosing the pokemon. If you change their species you may also want to change these strings to the new pokemon names.

Beta Starters:

0x02 species
0x07 level
0x16 Move1
0x26 Move2
0x36 Move3
0x46 Move4
0x5E Shiny Value
0x92 EXP value (the actual exp the pokemon has. make sure it corresponds to it's level but can be more than the exact required value to determine how close it is to the next level.)

Start Eevee:

let kStarterSpeciesOffset = 0x02
let kStarterLevelOffset = 0x0B
let kStarterMove1Offset = 0x12
let kStarterMove2Offset = 0x16
let kStarterMove3Offset = 0x1A
let kStarterMove4Offset = 0x1E
let kStarterExpValueOffset = 0x66

Trade Pokemon:

0x02 Species
0x0B Level
0x26 Move1
0x2A Move2
0x2E Move3
0x32 Move4

I found Elekid but lost the offset. Will find it again.

Traded Shadow Togepi:

0x02 Species
0x0B Level
0x26 Move1
0x2A Move2
0x2E Move3
0x32 Move4

StarsMmd is offline   Reply With Quote
Likes Elsa, Pia Carrot liked this post
Sponsored Links

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

All times are GMT. The time now is 08:34 AM.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2017, vBulletin Solutions, Inc. User Alert System provided by Advanced User Tagging (Lite) - vBulletin Mods & Addons Copyright © 2017 DragonByte Technologies Ltd.
Feedback Buttons provided by Advanced Post Thanks / Like (Lite) - vBulletin Mods & Addons Copyright © 2017 DragonByte Technologies Ltd.
Pokémon characters and images belong to Pokémon USA, Inc. and Nintendo.
Pokémon Hackers Online (PHO) is in no way affiliated with or endorsed by Nintendo LLC, Creatures, GAMEFREAK inc,
The Pokémon Company, Pokémon USA, Inc., The Pokémon Company International, or Wizards of the Coast.
All forum/site content (unless noted otherwise) and site designs are © 2006-2013 Pokémon Hackers Online (PHO).
Green Charizard Christos TreeckoLv100

"Black 2" by ARTPOP. Kyurem artwork by XOUS.

no new posts