StarsMmd Posted June 27, 2015 Share Posted June 27, 2015 (edited) I have a lot of information on 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--Code Part 1 of my tutorials: -hacking-tutorial-part-1-File-decompression-recompression'>http://projectpokemon.org/forums/showthread.php?46250-Stars-Pokemon-colosseum-and--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 Same as other games I believe. -Code/blob/master/Enums/Reference/XGExpRate.swift'>https://github.com/PekanMmd/Pokemon--Code/blob/master/Enums/Reference/XGExpRate.swift Evolution Methods: Same as other games with 0x10 being used for the exclusive eevee evolutions with the sun and moon shards -Code/blob/master/Enums/Reference/XGEvolutionMethods.swift'>https://github.com/PekanMmd/Pokemon--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 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: -Code/blob/master/Enums/Reference/XGSpecialStringCharacters.swift'>https://github.com/PekanMmd/Pokemon--Code/blob/master/Enums/Reference/XGSpecialStringCharacters.swift 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 come at the end. -Code/blob/master/JSON/Items.json'>https://github.com/PekanMmd/Pokemon--Code/blob/master/JSON/Items.json Trainer Models: -Code/blob/master/Enums/Reference/XGTrainerModels.swift'>https://github.com/PekanMmd/Pokemon--Code/blob/master/Enums/Reference/XGTrainerModels.swift Trainer Classes: -Code/blob/master/Enums/Reference/XGTrainerClasses.swift'>https://github.com/PekanMmd/Pokemon--Code/blob/master/Enums/Reference/XGTrainerClasses.swift 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--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--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--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 November 17, 2015 by StarsMmd Link to comment Share on other sites More sharing options...
Tiddlywinks Posted November 17, 2015 Share Posted November 17, 2015 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). Link to comment Share on other sites More sharing options...
StarsMmd Posted November 17, 2015 Author Share Posted November 17, 2015 Well, either I glossed over this thread before or I never noticed it. =PThe 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 ?? Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now