Jump to content

Recommended Posts

Posted (edited)

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 : -Code'>https://github.com/PekanMmd/Pokemon-xD-Code

Part 1 of my tutorials: -hacking-tutorial-part-1-File-decompression-recompression'>http://projectpokemon.org/forums/showthread.php?46250-Stars-Pokemon-colosseum-and-xD-hacking-tutorial-part-1-File-decompression-recompression

I'll be updating this post with more details.

Enumerations:

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

-Code/blob/master/Enums/Reference/XGEvolutionMethods.swift'>https://github.com/PekanMmd/Pokemon-xD-Code/blob/master/Enums/Reference/XGEvolutionMethods.swift

Genders:

Male = 0x0

Female = 0x1

Genderless = 0x2

Maps

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

Orange = 0x04

Black = 0x05

Items:

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.

-Code/blob/master/JSON/Items.json'>https://github.com/PekanMmd/Pokemon-xD-Code/blob/master/JSON/Items.json

Trainer Models:

Trainer Classes:

Weather:

None = 0x0

Sun = 0x1

Rain = 0x2

Sandstorm = 0x3

Hail = 0x4

ShadowSky = 0x5

Pokemon:

same as gen 3 games with a couple of additions. Note that gen 3 order is different from later gens.

-Code/blob/master/JSON/Original%20Pokemon.json'>https://github.com/PekanMmd/Pokemon-xD-Code/blob/master/JSON/Original%20Pokemon.json

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)

Moves:

Same as other games but with the shadow moves afterwards

-Code/blob/master/JSON/Original%20Moves.json'>https://github.com/PekanMmd/Pokemon-xD-Code/blob/master/JSON/Original%20Moves.json

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:

-Code/blob/master/JSON/Move%20Effects.json'>https://github.com/PekanMmd/Pokemon-xD-Code/blob/master/JSON/Move%20Effects.json

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

Constants:

Pointers:

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

Strings:

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 = 0xB8

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

Indexes:

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.

Ribbons:

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

Items

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.

Natures:

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.

Types

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.

Evolution:

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

Edited by StarsMmd
  • 4 months later...
Posted

Well, either I glossed over this thread before or I never noticed it. =P

First Battle Bingo Card in common_rel = 0x1CAF

[...]

Size of Bingo Card entry = 0xB6

The Bingo Cards actually start at 0x1CB0 (so your offsets are skewed by +1), and their length is 0xB8 (the last two bytes are just padding).

Posted
Well, either I glossed over this thread before or I never noticed it. =P

The Bingo Cards actually start at 0x1CB0 (so your offsets are skewed by +1), and their length is 0xB8 (the last two bytes are just padding).

Was wondering how I didn't notice, but I've got it down as 0xB8 in my source code so I guess it was a typo. It's great to have you double checking ??

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...