PDA

View Full Version : [Tutorial] HackMew's Knowledge


HackMew
December 1st, 2007, 02:21 AM
HackMew's Knowledge
A comprehensive guide to everything I know regarding Advance hacking

All right, this is the place I'm going to post all my documents and tutorials. Before saying anything else, I'd like to tell you this thread shouldn't be used for nothing but readers' feedback, criticisms or suggestions. Therefore, for any questions, feel free to ask in the Simple Questions (http://pokecommunity.com/showthread.php?t=79614) thread instead. If it wasn't answered yet, of course.
Anyway, this thread is still a work in progress so remember to check often for updates ;)

Documents - Table of Contents

[alink id="palette"]GBA Palette Format: What is and how is stored a color palette?[/alink id]

Tutorials - Table of Contents

[alink id="APE1"]Palette Editing with APE: Part 1 - Searching and Replacing an uncompressed palette[/alink id]
[alink id="ASM1"]Having fun with ASM: Lesson 1[/alink id]
Shinies Unleashed: Lesson 2
[alink id="recovery"]ROM Recovery: Restoring a screwed up ROM to its full glory[/alink id]

Quick Research - Table of Contents

Taking Pokémon away
Running Shoes inside buildings
I'm Fixin' It: The Pomeg Glitch
Getting the min/max level of your Pokémon party
I'm Fixin' It: The Pokédex Glitch
I'm Fixin' It: The Roaming Legendaries IV Glitch
I'm Fixin' It: Emerald's Broken PRNG


[A ID]palette[/A ID][DOC] GBA Palette Format
What is and how is stored a color palette? v1.0
From Wikipedia (http://en.wikipedia.org/wiki/Palette_%28computing%29)
A palette, in computer graphics, is a designated subset of the total range of colors supported by a particular image. Each color in the palette is assigned an index, and for each pixel one of these indices is stored to determine the color of the pixel.Palettes into RAM
Palettes are divided into two types: background and object ones. Background palettes are stored in the range of addresses 05000000-050001FF. As you can see they use a total of 0x200 bytes which is in decimal 512. Therefore this range of memory can have up to 256 colors.
Object palettes are really close to the background ones except their address which is 05000200-050003FF.
Each background and object palette into RAM may be either split into 16 palettes with 16 colors each, or may be used as a single palette with 256 colors.

Color Definitions
GBA supports up to 32768 colors (0x8000). Each color occupies two bytes. Since the the cubic root of 32768 is 32, each color level (Red, Green and Blue) has 32 possible variations, from 0 to 31. Colors go from 0x0000 to 0x7FFF, where the first represent the black color and the latter the white one.

Transparent Colors
Color 0 of all background and object palettes is treated as transparent. Since palettes can have either 16 or 256 colors, only 15 and 255 colors respectively are actually visible.

Backdrop Color
Color 0 of the background palette 0 is used as backdrop color. That means this color is displayed if an area of the screen is not covered by any non-transparent background or object dots.

Palettes into ROM
Palettes are stored into the ROM following the Little Endian ordering. This means the first and the second byte of each colors are swapped. For example, the white color (0x7FFF) would be found as FF7F. Palettes are usually stored uncompressed but you could find them compressed as well.

Here's the structure of a 16 color palette, uncompressed:
[Color2 Byte2 Color2 Byte1] ... [Color15 Byte2 Color15 Byte1]

Example:
[00 00] [F7 47] [50 33] [47 1A] [67 09] [8E 31] [E8 18] [1F 7C] [71 5F] [1F 3B] [1D 36] [D8 20] [94 63] [2E 53] [C8 46] [83 36]

As I said palette can also be compressed, LZ77 compressed in particular. The main difference is that LZ77 compressed palette have an appropriate header before the actual "color part". This "color part" doesn't follow a strict structure since it depends on the LZ77 compression.

I will provide a common LZ77 compressed 16 color palette:
[LZ77 Header - 5 bytes] [Color0 Byte2 Color0 Byte1] [Color1 Byte2 Color1 Byte1] ... [Color15 Byte2 Color15 Byte1]

Example:
[10 20 00 00 00] [39 57] [FF 7F] [0C 5E] [48 45] [00] [05 31] [A3 28] [BF 53] [3C 37] [00] [76 2A] [91 11] [7F 03] [7F 02] [00] [9F 01] [1D 00] [31 46] [42 08]


[COLOR=gray]This document is Copyright © 2007 by HackMew.
Parts of this document were freely inspired by the GBATEK specifications (http://www.work.de/nocash/gbatek.htm).
You are not allowed to copy, modify or distribute it without permission.


[A ID]APE1[/A ID][TUT] Palette Editing with APE
Part 1 - Searching and Replacing an uncompressed palette v1.0
Requirements: VisualBoyAdvance v1.7.2 or later, latest APE, some ROMs to edit.

For this tutorial we're going to use a FireRed US v1.0 ROM. Anyway, keep in mind the tutorial is fully compatible with any other Advance ROMs.
Let's say we want to replace the color of the trees in order to make them snowy.
First of all, open APE and load your favourite ROM. Run VBA and load the same ROM. Load a savegame or start a new game, as you like. Once you're in some areas outside the first city (or hany other city/route which has some trees), open the Palette Viewer (Tools -> Palette viewer).

[css-div="width: 818px; padding: 10px 10px 10px 10px; border: dotted 1px dimgray; background-color: #FFFFFF;"]http://www.geekimages.com/pics/20070814/APE1_1.png

Figure 1. Opening the Palette Viewer.[/css-div]

Once there, save the background palette by pressing the Save BG button. You can save the palette either using the Paintshop format or the Adobe Color Table one. Avoid using the Microsoft Palette format (selected by default) since it wouldn't be loaded by APE.

[css-div="width:569px; padding: 10px 10px 10px 10px; border: dotted 1px dimgray; background-color: #FFFFFF;"]http://www.geekimages.com/pics/20070814/APE1_2.png

Figure 2. Saving the background palette.[/css-div]

Close VBA and return to APE, choose the Search Palette option and import the palette you've just saved into the Actual Palette. (Edit -> Actual Palette -> Import - or just click the image button on the right side)

[css-div="width:540px; padding: 10px 10px 10px 10px; border: dotted 1px dimgray; background-color: #FFFFFF;"]http://www.geekimages.com/pics/20070814/APE1_3.png

Figure 3. Importing the palette into APE.[/css-div]

Now click the Search button. If everything went fine, APE will find the palette and it will display its offset and the colors as well.

[css-div="width:540px; padding: 10px 10px 10px 10px; border: dotted 1px dimgray; background-color: #FFFFFF;"]http://www.geekimages.com/pics/20070814/APE1_4.png

Figure 4. Searching the palette with APE.[/css-div]

Copy the Actual Palette to the Changed one (Edit -> Actual Palette -> Copy- or simply using the image buttons). As you can notice the Replace button has just been enabled.

[css-div="width:540px; padding: 10px 10px 10px 10px; border: dotted 1px dimgray; background-color: #FFFFFF;"]http://www.geekimages.com/pics/20070814/APE1_5.png

Figure 5. Copying the Actual Palette to the Changed one.[/css-div]

Well, let's edit the palette now! The color we will use are the following:

[css-div="width:540px; padding: 10px 10px 10px 10px; border: dotted 1px dimgray; background-color: #FFFFFF;"]http://www.geekimages.com/pics/20070814/APE1_6.png

Figure 6. Replacing the old colors.[/css-div]

Edit the palette showed in the the Changed Palette in order to get the appropriate colors. When you're done, just press the Replace button. Open VBA again and try the ROM you've just edited to see the changes.
But...

[css-div="width:240px; padding: 10px 10px 10px 10px; border: dotted 1px dimgray; background-color: #FFFFFF;"]http://www.geekimages.com/pics/20070814/APE1_7.png

Figure 7. What the heck?[/css-div]

the colors are still the same! What the heck happened? There are, in fact, multiple outdoor palettes inside the ROM. Until now we've just edited one of them. All you have to do is to replace the rest of them.
How? Simply search the old palette and while keeping the same Changed Palette hit the Replace button, until you can't find the old palette any more. Close the ROM from VBA and open it again to see the changes.

[css-div="width:240px; padding: 10px 10px 10px 10px; border: dotted 1px dimgray; background-color: #FFFFFF;"]http://www.geekimages.com/pics/20070814/APE1_8.png

Figure 8. The final result.[/css-div]

Have fun replacing palettes!


This tutorial is Copyright © 2007 by HackMew.
You are not allowed to copy, modify or distribute it without permission.


[A ID]ASM1[/A ID][TUT] Having fun with ASM
Lesson 1 - The very basics v1.2
Requirements: VisualBoyAdvance v1.7.2 or later, VBA-SDL-H (special debugging version), ASM assembler, hex editor, some ROMs.

Introduction
How many times have you ever heard the word "ASM"? No matter how many, what's behind that mysterious acronym?

ASM stands for assembly (http://en.wikipedia.org/wiki/Assembly_language), which is a low-level programming language (http://en.wikipedia.org/wiki/Low-level_language). Generally speaking, programming languages can be splitted into 4 main categories. At the lowest level we have machine code (http://en.wikipedia.org/wiki/Machine_code): raw (binary) numbers that the CPU (http://en.wikipedia.org/wiki/Cpu) decodes into instructions (http://en.wikipedia.org/wiki/Instruction_%28computer_science%29) to execute. On the higher level we have assembly. Each assembly instruction corresponds to one machine code instruction. In fact there's a 1:1 relationship between machine code and assembly. Human beings aren't made to program in machine code, where all you have is a long series of binary numbers. That's why assembly programming was created: to let programmers interact with the CPU at the lowest level yet using an easily understandable code. One step up are compiled languages like C, which use structured language element to be more like English, but need to be compiled to machine code in order to be able to run. Finally, there are scripted languages like VB or Java which are run through interpreters designed to run the right kinds of machine code to get the desired effects.

When dealing with ASM, we're basically programming. Therefore we need to know how a processor actually works and write code it can understand. Being a programmer already will sure help here because the main concepts are the same.

ARM and THUMB
We talked about ASM in general, but from now on we will refer to the GBA. The GBA itself has a custom processor created by Nintendo, called ARM7TDMI. The CPU has 2 instruction sets (http://en.wikipedia.org/wiki/Instruction_set): ARM and THUMB.
For our purposes we're going to use THUMB 99.9% of the times. THUMB takes less space into ROM (half the size compared to ARM) and it's executed a lot faster when located in the ROM. There are some cons, indeed. Nothing we should care about now, though.

Getting started
Like I wrote in the Requisites, an ASM assembler (http://en.wikipedia.org/wiki/Assembly_language#Assembler) is required. A link will be provided later.
Since most assembler, if not all of them, are command line-based you'll need to use a command prompt. If you have no idea what a command prompt is, you better stop here for now and get more info about it (http://www.google.com/search?hl=en&q=command+prompt) before continuing.

Once you're familiar with the command prompt, you can download the 50365 file which contains the assembler we're going to use. Extract all the 3 files inside a folder (for example on the Desktop) and open a command prompt window. Something similar will appear:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]Microsoft Windows [Version 6.1.7600]
Copyright (c) 2009 Microsoft Corporation. All right reserved.

C:\Users\YourName>[/css-div]
Now navigate to the directory where the file were extracted earlier:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]Microsoft Windows [Version 6.1.7600]
Copyright (c) 2009 Microsoft Corporation. All right reserved.

C:\Users\YourName>cd Desktop
C:\Users\YourName\Desktop>[/css-div]
Now that you're in the right folder, you're ready to assemble your first (THUMB) ASM routine. What exactly? Good question.
Since this is the first lesson I prepared for you a simple routine. Here's the file: 45005. It includes 3 different versions, depending on the game you're hacking.
Download it and put the right .asm file in the same directory where the assembler is. Then rename it to lesson1.asm. To assemble it do the following:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]Microsoft Windows [Version 6.1.7600]
Copyright (c) 2009 Microsoft Corporation. All right reserved.

C:\Users\YourName>cd Desktop
C:\Users\YourName\Desktop>thumb lesson1.asm lesson1.bin
Assembled successfully.

[/css-div]
If everything went fine, you'll get the "Assembled successfully" message as shown above. In case you didn't specify the "lesson1.bin", the resulting file would be the same name as the .asm source, except with a .bin extension.
Now open the lesson1.bin file through a hex editor, copy its content and paste it into a free space area inside your ROM, paying attention to overwrite the existings free space, and not to simple insert new bytes. In the latter case, in fact, everything would be shifted down, and the ROM size increased. Definitely not what we wnat. Also, Make sure the offset ends with either 0, 4, 8 or C. For example, 0x800000 is a good offset while 0x91003D is not. That is needed in order for the game to execute the routine properly. Write down the offset (or just memorize it, if you feel doing so) because you'll need it soon.

Testing it out
The ASM routine was correctly inserted into the ROM. Now it's time to test it. Prepare a script like this, where YourOffset must be replaced with the offset you wrote down before + 1. Example: 0x871034 + 1 = 0x871035. Why? That's needed by ROM so that it will correctly run our routine using the THUMB instruction set. If you don't add 1, the routine will be treated as ARM, hence it won't work.
I'll assume you're using XSE, so if you're using a different script editor you'll have to pay attention about the proper syntax needed. The script itself is pretty simple and since this is not a scripting tutorial I'm not going to explain it any further.

#dynamic 0x800000

#org @start
callasm YourOffset
buffernumber 0x0 LASTRESULT
msgbox @secret 0x2
end

#org @secret
= Sshh! I'll tell you a secret[.]\nYour Secret ID is !Compile the script and assign it to a person. Then load the emulator and talk to the person.
If you did everything correctly you'll get something like this:

[css-div="width: 240px; padding: 10px 10px 10px 10px; border: dotted 1px dimgray; background-color: #FFFFFF;"]http://s5.tinypic.com/2hs5ax4.jpg

Our script in action.[/css-div]


How does it work
So far we merely inserted a routine and we called it from a script. We have no idea what happens behind the scenes, yet.
Except one thing: the routine is used to retrieve the Secret ID. Well, not truly secret any more, eh?
The Secret ID is stored into the RAM along with other info about the player. The structure is the following:

[Name (8 bytes)] [Gender (1 byte)] [??? (1 byte)] [Trainer ID (2 bytes)] [Secret ID (2 bytes)]
[Hours of play (2 bytes)] [Minutes (1 byte)] [Seconds (1 byte)] [Frames (http://en.wikipedia.org/wiki/Frame_rate#Frame_rates_in_video_games) (1 byte)]
[??? (1 byte)] [Options (2 bytes)]
Let's see the .asm file in detail now. Remember it's a plain text file so Notepad will be able to read it just fine. Since the 3 routines are mostly the same I'll explain the FireRed version first, then the differences between the different versions.

On the very first line we can see:

.textThis is a directive that will tell the assembler to assemble the following lines in the .text code section of the temporary object file which is created.

.align 2This is a directive that will byte align the following code by 2 bytes. Since it's a THUMB routine it must be 2.

.thumbThis is a directive to inform the assembler the following lines will use the THUMB instruction set.

.thumb_funcThis directive will state the fact we're using THUMB. Both .thumb and .thumb_func are needed.

.global lesson1Optional.

main:This is a label called "main". It's a good behaviour to call the main one that way.

push {r0-r1, lr}Here the true THUMB code starts. This instruction will push registers from r0 to r1, along with the Link Register into the stack. "What the heck are registers? Stack??"

Registers are special memory areas which are 32 bits wide hence they can hold numbers up to 4 bytes. They can be accessed by simply calling their name. There's a total of 16 registers, from r0 to r15. A bit more in detail:
- r0-r12: These 13 registers are the so called General Purpose Registers, which means they can be used for whatever reason you may have. However in THUMB mode r0 - r7 (Low Registers), can always be used whereas r8 - r12 (High Registers) can be used only by some instructions.

- r13: While in ARM mode the user can choose to use r13 or another register as a Stack Pointer, in THUMB mode this register is always used as Stack Pointer.

- r14: This is used as Link Register. When calling to a sub-routine by a branch with a Link instruction, the return address is stored in this register. Storing the return address is a lot faster then pushing it into memory, however there's only one LR register for each mode so the user must manually push its content before issuing "nested" subroutines.

- r15: This is used as Program Counter, when reading from r15 it will return a value of PC+n because of read-ahead (pipelining) while "n" depends on the instruction and on the CPU state (THUMB or ARM).

- Stack: besides registers, there's another special memory area called "Stack". It's used to store the value of registers into it so that you can safely modify them. When you store something into the stack, that's called "pushing". When you're done, you will do the opposite. That is, "popping". When you pop a register, its value will be restored to its previous state.

A frequently used metaphor is the idea of a stack of plates in a spring loaded cafeteria stack. In such a stack, only the top plate is visible and accessible to the user, all other plates remain hidden. As new plates are added, each new plate becomes the top of the stack, hiding each plate below, pushing the stack of plates down. As the top plate is removed from the stack, they can be used, the plates pop back up, and the second plate becomes the top of the stack. Two important principles are illustrated by this metaphor: the Last In First Out principle is one; the second is that the contents of the stack are hidden. Only the top plate is visible, so to see what is on the third plate, the first and second plates will have to be removed.To sum it up, when we use push {r0-r1, lr}, we're storing - or better, pushing - registers from r0 to r1 and the Link Register into the stack. So, following the above metaphor, r0, r1 and lr would become the top plate.

ldr r0, .PLAYER_DATAThis THUMB instruction will load the value of our custom symbol called .PLAYER_DATA into the register r0.

ldr r0, [r0]This THUMB instruction will load into r0 the value pointed by the actual value of r0. Yes, you've guessed right: .PLAYER_DATA is a memory address which holds a pointer to the player data. First we loaded the address into r0, then we loaded into the same register the value located at the address stored in the register itself.

ldr r1, .VARThis THUMB instruction will load into r1 the value of the symbol .VAR, which is the memory address of the variable 0x800D, LASTRESULT.

ldrh r0, [r0, #0xC]Right now in r0 we have the memory address of the player data. If you start counting from the first byte of the name till the Secret ID, you'll end up with 12 (0xC) bytes. So this THUMB instruction will load an half-word stored at the address r0 + 0xC. Not surprisingly, that's exactly where the Secred ID is stored. Why half-word? And, more important: what are half-words? Except for "byte" which is always 8 bits, there isn't a strict convention about its multiples. When talking about ASM, anyway, we define word a 32 bits value. Therefore an half-word (as the name suggests) is 16 bits. And the Secret ID takes 2 bytes, or 16 bits indeed.

strh r0, [r1]This THUMB instruction will store the value held by r0 (which is our Secret ID) at the address pointed by r1, which is LASTRESULT. Note that we're using the "h" suffix once again. In fact we're storing an half-word since variables are 16 bits wide (from 0x0 to 0xFFFF).

pop {r0-r1, pc}This THUMB instruction will revert the effect of our previous push. Remember that when you push a variable and you change its value, you should always pop it back.

.align 2 Assembler directive. Nothing new actually. Just don't forget it.

.PLAYER_DATA:This is a label used to define the .PLAYER_DATA symbol used by the routine.

.word 0x0300500CAssigns the word (32 bits) 0x300500C to .PLAYER_DATA.

.VAR:This is a label used to define the .VAR symbol used by the routine.

.word 0x020270B6 + (0x800D * 2)Assigns the word (32 bits) 0x020270B6 + (0x800D * 2) = 0x020370D0 to .VAR. If you're wondering about the "weird" format, I made that to make it easier changing the variable used. Note however this would work only for temporary variables, 0x800D onwards. For the previous temporary variables, just increase the main address by 2 (in the example above, you would change it to .word 0x020270B8 + (0x8000 * 2), if you were to use variable 0x8000).

For the sake of precision, I'll explain you how memory is used by the GBA.
- System ROM/BIOS: starts at 0x0000000 with a length of 16KBs, this section contains BIOS memory which is strictly read-only.
- External Working RAM/EWRAM: starts at 0x2000000 and has a length of 256 KB. Since it contains a 16-bit databus, THUMB is best used here.
It allows 8, 16 and 32 bits read/write.
- Internal Working RAM/IWRAM: begins at 0x3000000 and has a length of 32 KB with a 32-bit databus thus making it fast for ARM code.
It allows 8, 16 and 32 bit read/write.
- Register Memory/IO: begins at 0x4000000 going up to 1 KB. This is where you control graphics, sound, timing, keypressing etc.
Besides the name, it has absolutely nothing to do with the actual registers: r0-r15.
- Palette Memory: starts at 0x5000000 going up to 1 KB. This area contains 2 palettes: backgrounds and sprites, respectively.
- Video Memory/VRAM: starts at 0x6000000, graphic data (tilesets, sprites, tilemaps) are stored here. Sprites are usually stored starting from 0x6010000.
- Object Attribute Memory/OAM: begins at 0x7000000 with a length of 1 KB. This is where you control sprites such as storing width, height, or location to sprite graphic data.
- ROM: begins at 0x8000000 going to a maximum of 32 MB, usually. THUMB is the best choice over here.
If you compare the FireRed and Emerald routine you'll see they're pretty much the same, except the .PLAYER_DATA and .VAR values. Since FireRed and Emerald are different games, that's predictable if not obvious. Except for the different value the Ruby one seems to be missing something though. In particular the ldr r0, [r0] line. What's the reason?

Normal RAM hacking, relies heavily on the fact - whether you realize it or not - that the data you are searching for is static (stays in the same place), at least for the duration of the search. To fight hackers, some data in FR/LG and Emerald is stored in dynamic locations - i.e. it is moving constantly, for example whenever you open a menu or you leave a map. The method is called DMA (http://en.wikipedia.org/wiki/Dynamic_memory_allocation), or Dynamic Memory Allocation. This scheme is actually weak though: somewhere in the RAM, there must be a value that tells the game where the data in question is currently stored: a pointer. Ruby has no such protections therefore we can load the memory address directly into the register. When dealing with FR/LG and/or Emerald instead, we must first load the address that contains the pointer to the actual data, and then load the pointer itself.

Let's debug
The routine we used was (relatively) simple, but as soon as the routines grow and get more and more complicated, you can't just rely on simply using a callasm to see if they work or not. Especially in the latter case. That's when a debugger comes in handy. So if you didn't download it yet, this is the right moment to do it: 51237.
The VBA-SDL-H is a command line program, so you'll need to use a command prompt:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]Microsoft Windows [Version 6.1.7600]
Copyright (c) 2009 Microsoft Corporation. All right reserved.

C:\Users\YourName>cd Desktop
C:\Users\YourName\Desktop>VBA-SDL-H.exe "ROM Name.gba"
[/css-div]
Once you start it, the ROM will be loaded. Nothing special so far. To access the debugging features, press F11 at any time while the game is running. This stops the execution of the ROM. In the console window you will now see the debugger> prompt. This is where you type in commands.

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]R00=00000000 R04=00000000 R08=00000000 R12=00000040
R01=00000004 R05=030030e4 R09=00000000 R13=03007e24
R02=030030f0 R06=030030e4 R10=00000000 R14=080004ab
R03=00000001 R07=030030f0 R11=00000000 R15=080008ac
CPSR=6000003f (.ZC...T Mode: 1f)
080008b2 d0fa beq $080008aa
> 080008aa 8b91 ldrh r1, [r2, #0x1c]
080008ac 1c18 add r0, r3, #0x0
debugger>[/css-div]
The first 4 lines show us the current content of the 16 registers. Then we have the CPSR (which can be safely ignored for now) and other 3 lines. In the example above, 080008b2 d0fa beq $080008aa is the last executed instruction. 080008aa 8b91 ldrh r1, [r2, #0x1c] is the instruction it's going to be executed. 080008ac 1c18 add r0, r3, #0x0 is the instruction following the current one, if executed.

To return to the game, you use the command c. To quit, you can press Esc whilst the game is running, or use the q command from the console.
Since we want to debug our THUMB routine, we will need to set a breakpoint. To set a THUMB breakpoint you use the bt command. The syntax is bt [address]. For example, if our routine was located at 0x900000 into the ROM, we would use bt 08900000. Once the breakpoint is set, press c to return to the game and talk to the person who got the script assigned. The game will stop and you'll get a similar screen:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]Breakpoint 0 reached
R00=08820001 R04=03000eb0 R08=00000000 R12=0202063c
R01=08069f9b R05=030030e4 R09=00000000 R13=03007dfc
R02=08800012 R06=030030e4 R10=00000000 R14=08069f9f
R03=03000eb0 R07=030030f0 R11=00000000 R15=08820002
CPSR=0000003f (......T Mode: 1f)
081e3ba8 4700 bx r0
> 08820000 b503 push {r0,r1,lr}
08820002 4803 ldr r0, [$08820010] (=$0300500c)
debugger>[/css-div]
As you can see it stopped right at the beginning of the routine. Now you can use the n command to execute the next instruction, watching carefully how registers change.
Before pressing n, it's always better to make assumptions about the possible content of the registers after each instruction. This way you'll be able to compare the results you're getting with your expected results, and therefore to see if the routine is working properly or not.

Downloads
- 50365
- 45005

References
- Wikipedia (http://en.wikipedia.orh)
- Whirlwind Tour of ARM Assembly (http://www.coranac.com/tonc/text/asm.htm)
- Official ARM7DTMI Technical Manual (http://www.arm.com/pdfs/DDI0210B_7TDMI_R4.pdf)
- GBATek (http://nocash.emubase.de/gbatek.htm)
- THUMB Quick Reference (http://re-eject.gbadev.org/files/ThumbRefV2-beta.pdf)
- Assembler Quick Reference (http://re-eject.gbadev.org/files/GasARMRef.pdf)
- Assembler Manual (http://tigcc.ticalc.org/doc/gnuasm.html)

Challenge time
Are you up for an ASM challenge? Then edit the routine so that it can store both Trainer ID and Secret ID into two different variables of your choice.
Note: you can only use r0 and r1 like in the original routine. Solution will be available on next lesson.


[COLOR=gray]This tutorial is Copyright © 2009 by HackMew.
You are [B]not allowed to copy, modify or distribute it without permission.


[A ID]recovery[/A ID][TUT] ROM Recovery
Restoring a screwed up ROM to its full glory v1.0
Requirements: A-Ptch (or LIPS, or any other good patcher), some ROMs.

The technique I'm going to explain works 100%. Anyway, before going into details, I have to warn you about the fact it will work if, and only if, you know exactly what was the dramatic change you did that screwed up anything. Of course, a backup is usually the best solution but things can go wrong and so you may forget backing up or even worse, lose some backups along the way. Long story short: the last change is crucial for this to be useful.

Screwed up ROMs anyone?
To recover a ROM we first need something to recover obviously. For this tutorial I will be ruining a ROM intentionally. I'll use a clean FireRed US v1.0 ROM. Let's open it using unLZ...

[css-div="width: 597px; padding: 10px 10px 10px 10px; border: dotted 1px dimgray; background-color: #FFFFFF;"]http://i41.tinypic.com/2nvfrjt.jpg

Figure 1. Hmm...[/css-div]
I stopped at Charmander's sprite, as you can see. Since it's a LZ77 compressed picture, screwing it up is fairly easy: overwriting it with a bigger one. The first picture it comes into my mind is Charmeleon, which should be bigger. Right?

[css-div="width: 597px; padding: 10px 10px 10px 10px; border: dotted 1px dimgray; background-color: #FFFFFF;"]http://i42.tinypic.com/15rjvpg.jpg

Figure 2. Is it big enough?[/css-div]
And unLZ confirms that, indeed. Now, since this is a tutorial we need to ruin the ROM. Therefore I'll uncheck the "Auto abort" option, something you should never do.

[css-div="width: 597px; padding: 10px 10px 10px 10px; border: dotted 1px dimgray; background-color: #FFFFFF;"]http://i39.tinypic.com/2mg5pat.jpg

Figure 3. Soon to be ruined.[/css-div]
What happens after clicking OK? The answer is easily predictable:

[css-div="width: 597px; padding: 10px 10px 10px 10px; border: dotted 1px dimgray; background-color: #FFFFFF;"]http://i41.tinypic.com/34s4a2t.jpg

Figure 4. Screwed up![/css-div]
It's recovery time!
So we got a screwed up ROM... Let's fix it.
1. Take your screwed up ROM and a clean one. Just for extreme safety, do a backup of the ruined ROM.
2. Now repeat the last change you did on the clean ROM you took.
In my case I would re-insert Charmeleon over Charmander on the clean ROM, with "Auto abort" off. In your case this action will depend on what you did earlier.
3. Then open A-Ptch or whatever patcher you fancy. As the original, unmodified ROM take the modified clean ROM. As the new modified ROM take the screwed up ROM.
4. Create the patch.
5. Now take another clean ROM and apply the patch you just created to it.If you did everything correctly, the ROM will be fully recovered now.


This tutorial is Copyright © 2009 by HackMew.
You are not allowed to copy, modify or distribute it without permission.

cooley
December 2nd, 2007, 05:03 PM
Yep, that is exactly how I do it. Hopefully, there are no more Palette Questions in the Simple questions Thread.

spenceroone3
December 2nd, 2007, 08:52 PM
Good tutorial.

There are, in fact, multiple outdoor palettes inside the ROM. Until now we've just edited one of them. All you have to do is to replace the rest of them.

That's what mucked me up in another tut! Thanks for clearing that up.

/Circa
December 2nd, 2007, 11:05 PM
If this doesn't explain palette editting, nothing will :l.
I'll see if I can get a full list of palettes for everyone.

Theres also the hex editting way, which I think is more effective and safer, but it is troublesome..
Good job HackMew.

Binary
December 3rd, 2007, 07:55 AM
Wow a new way of pallete editing, that cleared alot of things up.
*Keeps this tut in mind*
Thanks alot it was simpler than hex-editing.

~Celebi

I can haz haxburgrz?
December 4th, 2007, 05:27 AM
YAY A SIMPLE WAY!!! soz i'm shouting a lot today.... GO HACKMEW!!! tyvm for the tut

axlefoley
December 4th, 2007, 07:04 PM
how do can you calculate what the 4 digit hex number is for a colour? I am trying to edit the palettes of some overworlds and I would like to know how to get the number

D-Trogh
December 5th, 2007, 04:17 AM
how do can you calculate what the 4 digit hex number is for a colour? I am trying to edit the palettes of some overworlds and I would like to know how to get the numberErr... APE's Color Picker maybe? - -'
Or Color 2 HEX.. ?

axlefoley
December 5th, 2007, 11:53 AM
thanks a lot helps if i open my eyes lol. Does it matter what order I put the new colours into palette?

Sagiri
January 22nd, 2008, 02:42 PM
How? Simply search the old palette and while keeping the same Changed Palette hit the Replace button, until you can't find the old palette any more.

That is confusing. How do you search the old palette? What do you press?

While waiting for help... I think I'll sprite...

cooley
January 22nd, 2008, 06:18 PM
The original Palette ( the one you wanted to change ). After you search for it, Click Replace, don't do anything els except for Testing it in-game. If no results are shown, then you click "Search" again, Click Replace and keep on repeating until the palette is replaced.

Simple ;)

Sagiri
January 23rd, 2008, 01:25 PM
Well, thank you.
Actually, I found out what to do earlier, but I hadn't been allowed on the compy.

Hellsing
January 26th, 2008, 08:24 PM
When I import the actual palette, then copy it to the changed palette the replace button isn't enabled. Why?

lostprophetsown
January 27th, 2008, 02:52 AM
once again hackmew you help everyone in the community with your superb skilled guides very nice help so i could make snowy trees!

Νιτραμ
February 1st, 2008, 01:06 AM
Regarding the multiple palettes change, there's no need for doing so.

Just search for the palette around offset starting with 0xE and I am pretty sure it's the last one over there and it's significantly apart from the bunch of other, same palettes (which are gathered from 0x26... to 0x28... and when this one is at 0xE... it's a big difference). Maybe it will make your edits faster.

Cheers!

Hardy Har Har
April 17th, 2008, 07:35 PM
how to determine the equivalences? example, violet is 0D4D.

i tried the tutorial on the title screen and the result is:
http://i252.photobucket.com/albums/hh26/jaqthemouse/titlescreen.jpg

Blazichu
April 18th, 2008, 03:00 AM
psyduck007, stop reviving month old threads... HackMew if you want this reopened PM Christos or myself.

*Locks*

Thrace
February 9th, 2009, 02:22 PM
HackMew has requested this thread be reopened.

Opened

HackMew
February 13th, 2009, 10:46 PM
For those interested I've just posted an ASM tutorial. Enjoy it :)

Surf
February 13th, 2009, 10:58 PM
That was a great ASM tutorial Hackmew.
I might try a pallete change soon ;)

ZodiacDaGreat
February 14th, 2009, 12:27 AM
I'm glad to see its posted. Great job Andrea ^^. These tutorials rival Thethethethe and mine XD I'm up for that challenge ^^

Ninja Caterpie
February 14th, 2009, 01:09 AM
Ooh, nice an ASM tutorial thing.

I still don't understand what the commands and thingos do, but i'll wrap my head around it soon enough. =P

0m3GA ARS3NAL
February 14th, 2009, 02:17 AM
YES! Finally, an ASM tutorial that gets down to the very basics, complete with definitions of everything I need to know! Better than any of the tutorials I have read so far! I especially like it because it explains things line by line, you don't see that often, people could learn from you! You deserve some +Rep, so here you go!

liuyanghejerry
February 14th, 2009, 03:33 AM
Originally HackMew is an ASM hacker,too! I just found that the period of ASM is coming!

BTW, for starters like me, a lot of ARM commands are really needed to be explain.

hi sir tomato my password is syvniti
February 17th, 2009, 06:48 AM
Wow, This is propperly the tutorial I like most here at pc, You did an awesome job.

I'm really Excited about the next tutorial. I spended nearly about an hours but it was all the time worth. Now I realeized that ASM isn't a big green garlic junior'ish monster living under my bed...


Is that ok?
http://img23.imageshack.us/img23/2232/text1cj5.png

SPOILER - Do not open this if you plan on reading the tutorial or are currently doing it. Please don't.
First I wanted to just copy the intire 4 byte long word with both the id and the secret one, But the compiler wouldn't let me do that since the offset had to be a multiplication of &h4, I couldn't do that (But if there is a solution where I could do some thing like that please tell me.)
So then I decided to both parts seperatly, But since the ID was stored in the last two bytes of a word and I didn't know how to only get the last part of the word, I copyed the intiere word to to variables (&h800A and &h800B) Which emptys the 800A with zeros.
To get the secret ID I allmost did excatly like you did, except I changed the offset a bit.
The thing I spended most time on was finding the location of the vars, I just thought they were in order (like 800B, 800C, 800D) and not storred in that random way.
Here's my code.
.text
.align 2
.thumb
.thumb_func
.global lesson1

main:
push {r0-r1, lr}
ldr r0, .PLAYER_DATA
ldr r0, [r0]
ldr r1, .VAR
ldr r0, [r0, #0x8]
str r0, [r1]
ldr r0, .PLAYER_DATA
ldr r0, [r0]
ldrh r0, [r0, #0xC]
strh r0, [r1, #0x4]
pop {r0-r1, pc}

.align 2
.PLAYER_DATA:
.word 0x0300500C
.VAR:
.word 0x020370CC
Is it aproved? (I mean, I filled the 0x800A with zeros.:nervous:)
If I was aloud to use other registers I would propperly just have saved the data location offset, and save a bit space / time there.

Edit: I just tryed fixing my routine, and first I just used the var 800A instead of 800D for the secret ID since I had to use to vars for the normal one at first anyway...
Next I tryed using the third register instead of emptying the first one and reload the first offet again.

push {r0-r1-r2, lr}
ldr r0, .Var1
ldr r0, [r0]
ldr r1, .Var2
ldr r2, [r0, #0x8]
str r2, [r1]
ldrh r0, [r0, #0xC]
strh r0, [r1]
pop {r0-r1-r2, pc}

Was it a good idea to use the register 2?

SPOILER - Do not open this if you plan on reading the tutorial or are currently doing it. Please don't.

Last I would like too tell I'm really really happy for this tutorial, and you're doing a great job. It's really well written and I'm looking forward to part two!
EDIT INSIDE THE SPOILER!

HackMew
February 21st, 2009, 03:17 AM
Thank you all, I really appreciate your feedback. While you wait for the next lesson, do you have any suggestions perhaps?

hi sir tomato my password is syvniti
February 21st, 2009, 05:50 AM
Thank you all, I really appreciate your feedback. While you wait for the next lesson, do you have any suggestions perhaps?

Actually I don't have any suggestions, but I would be very glad if the next guide was as well exsplained as this one.
Else more task and homework.

Edit: And less waiting time! (Now take your time, I'll just wait with eating, showering and drinking for the next guide...
I'll edit my other post now...

Disturbed
February 27th, 2009, 12:49 PM
All of your tutorials seem quite extensive. If I ever take the time to read it, I'll bet they'll help me.
Now, to comment on your most recent tutorial. First off, it seems detailed, and even gives an example of how you can crash a ROM! It's really great, Andrea. I look forward to more extensive tutorials by you.

cooley
March 1st, 2009, 04:39 PM
Hey I just wanted to complement you for your ASM Tutorial. I'm no longer scared of ASM anymore XD Its very nice the way you share valuable info with all of us, but in spite of how easily-comprehendable you make it, some people just can't learn on a basic level :P ( I am not talking about me btw )

Good luck with the next lesson, I can't wait to learn something new ^_^ Oh and I'll talk to you when I do think of a suggestion ;)
-cooley

hi sir tomato my password is syvniti
March 2nd, 2009, 04:35 AM
Hey I just wanted to complement you for your ASM Tutorial. I'm no longer scared of ASM anymore XD Its very nice the way you share valuable info with all of us, but in spite of how easily-comprehendable you make it, some people just can't learn on a basic level :P ( I am not talking about me btw )

SO DAMN WRONG...

If most of the people on these forums just took the time too sit down, and maybe learned some basic other stuff before, most would propperly be able to follow these tutorials but...

cooley
March 2nd, 2009, 07:15 AM
SO DAMN WRONG...

If most of the people on these forums just took the time too sit down, and maybe learned some basic other stuff before, most would propperly be able to follow these tutorials but...
Maybe, but MOST people are not willing to do that. I think this is a bit off-topic though, VM if you like ^_^

Surf
March 11th, 2009, 10:14 PM
Zomg, I actually understood half of the ASM tutorial.
I managed to compile a timer that foofatron showed me :D
Thanks for the tut Hackmew, I really enjoyed it!

0m3GA ARS3NAL
March 14th, 2009, 12:38 AM
Hmm.... I hope a 2nd tutorial is released sooner or later... (Sooner than later, heheh) I have really wanted to learn this stuff, and I understand THIS MUCH OF IT. *makes fingers into a small pinch*
I still wanna know more!

Pokepal17
March 17th, 2009, 12:14 PM
Well I've been reading the ASM tutorial and I'm beginning to understand it. Maybe for the next ASM tutorial you could show how to make a temporary effect in-game become permanent e.g. make the player overworld not change back after changing it with writebytetooffset.

master_script_maker
June 10th, 2009, 07:41 AM
great tutorial, but i have one question. Why do you change the values of player_data and var at the end of the script?

Full Metal
June 19th, 2009, 10:32 AM
Hey hackmew I tried to add the trainer id into the asm as well....
it is A instead of C right?
I did something wrong though the script freezes before the guy even faces player
which is weird cuz i called the asm after faceplayer, then called buffernumber 0x1 LASTRESULT (for the secret id) and buffernumber 0x2 (for the trainerid)
the music keeps playing so i think it's my problems with asm.
well anwyays here's my attempt for FireRed.

.text
.align 2
.thumb
.thumb_func
.global lesson1

main:
push {r0-r1, lr}
ldr r0, .PLAYER_DATA
ldr r0, [r0]
ldr r1, .VAR
ldrh r0, [r0, #0xC]
strh r0, [r1]
pop {pc}
push {lr}
ldr r0, .PLAYER_DATA
ldr r0, [r0]
ldr r1, .VAR2
ldrh r0, [r0, #0xA]
strh r0, [r1]
pop {r0-r1, pc}

.align 3
.PLAYER_DATA:
.word 0x02024EA4
.VAR:
.word 0x0201E8C2 + (0x800D * 2)
.VAR2:
.word 0x0201E8C2 + (0x8001 * 2)

i haven't tried debugging it just yet....

-DarK-
July 7th, 2009, 07:50 AM
Something goes wrong for me... Everything is fine up to the point where I paste the content from that lesson1.bin into my FR rom. When I try to play the ROM, it freezes as soon as I play A or let the gamefreak logo thing pass by. When I try loading it in A-Map, A-Map crashes... What went wrong then? I used the right offset (0x820000), it had plenty of free space, and yet nothing worked and my ROM got screwed up... And yes, I did assemble the fr lesson, I double checked it.

HackMew
July 7th, 2009, 08:15 AM
great tutorial, but i have one question. Why do you change the values of player_data and var at the end of the script?


It's not a script.
I don't change anything, I just assign a values for both. Pretty different.
You should read the tutorial again, I guess.

Hey hackmew I tried to add the trainer id into the asm as well....
it is A instead of C right?
I did something wrong though the script freezes before the guy even faces player
which is weird cuz i called the asm after faceplayer, then called buffernumber 0x1 LASTRESULT (for the secret id) and buffernumber 0x2 (for the trainerid)
the music keeps playing so i think it's my problems with asm.
well anwyays here's my attempt for FireRed.

.text
.align 2
.thumb
.thumb_func
.global lesson1

main:
push {r0-r1, lr}
ldr r0, .PLAYER_DATA
ldr r0, [r0]
ldr r1, .VAR
ldrh r0, [r0, #0xC]
strh r0, [r1]
pop {pc}
push {lr}
ldr r0, .PLAYER_DATA
ldr r0, [r0]
ldr r1, .VAR2
ldrh r0, [r0, #0xA]
strh r0, [r1]
pop {r0-r1, pc}

.align 3
.PLAYER_DATA:
.word 0x02024EA4
.VAR:
.word 0x0201E8C2 + (0x800D * 2)
.VAR2:
.word 0x0201E8C2 + (0x8001 * 2)

i haven't tried debugging it just yet....

Yes, it's 0xA instead of 0xC as it's 2 bytes before. Aside from that, your whole ASM routine is screwed up. Please read the guide again, as I never used .align 3 anywhere, for example. Your push/pop usage is also wrong.


Something goes wrong for me... Everything is fine up to the point where I paste the content from that lesson1.bin into my FR rom. When I try to play the ROM, it freezes as soon as I play A or let the gamefreak logo thing pass by. When I try loading it in A-Map, A-Map crashes... What went wrong then? I used the right offset (0x820000), it had plenty of free space, and yet nothing worked and my ROM got screwed up... And yes, I did assemble the fr lesson, I double checked it.

That's just because you screwed up your ROM. Remember you can't simple insert the new routine pasting it somewhere. That way, you increase the ROM size and screw up all the data after because the pointer will be mostly broken. So, when pasting, make sure to overwrite the right amount of space.

-DarK-
July 7th, 2009, 09:15 AM
That's just because you screwed up your ROM. Remember you can't simple insert the new routine pasting it somewhere. That way, you increase the ROM size and screw up all the data after because the pointer will be mostly broken. So, when pasting, make sure to overwrite the right amount of space.

Ah thank you, it worked. I thought bytes were overwrited already when you just pasted it.

EDIT: Ok, I tried something out, but it didn't work:

.text
.align 2
.thumb
.thumb_func
.global test1

main:
push {r0-r1, lr}
ldr r0, .WILD_NEW
ldr r0, [r0]
ldr r1, .WILD_DATA
ldrh r0, [r0, #0x8]
strh r0, [r1]
pop {r0-r1, pc}

.align 2
.WILD_NEW:
.word 0x00810000
.WILD_DATA:
.word 0x003C8F00



I tried using this to change wild data for Route 1. The first rattata in the list was supposed to be changed to an arbok, but it didn't work, so it seems. I kept encountering the usual pidgey's and rattata's (tried around 20 - 30 encouters, didn't find it).

Here's my script (a simple lvl script):

#dynamic 0x800000

#org @start
checkflag 0x201
if b_true goto @stop
callasm 0x810009
setflag 0x201
end

#org @stop
end

I'm new to ASM, and I'm not sure what I missed out, so can someone help?

PlatniumPiano
July 8th, 2009, 08:22 AM
Hackmew, I have a problem.
I extraced the .asm rountines into a folder named "thumb" on my desktop, which contains the assembler. The first time I tried to assemble, the routine opened in Visual C++ I have installed on my computer. But, whenever I try and run the command prompt as
C:\Documents and Settings\Name\Desktop>thumb lesson1.asm lesson1.bin
I get the message
'thumb' is not recognized as an internal or external command, operable
program or batch file.
I have little experience with command prompts, so did I mis-type something? Or is it another problem I am having?

HackMew
July 8th, 2009, 08:40 AM
Ah thank you, it worked. I thought bytes were overwrited already when you just pasted it.

EDIT: Ok, I tried something out, but it didn't work:

.text
.align 2
.thumb
.thumb_func
.global test1

main:
push {r0-r1, lr}
ldr r0, .WILD_NEW
ldr r0, [r0]
ldr r1, .WILD_DATA
ldrh r0, [r0, #0x8]
strh r0, [r1]
pop {r0-r1, pc}

.align 2
.WILD_NEW:
.word 0x00810000
.WILD_DATA:
.word 0x003C8F00



I tried using this to change wild data for Route 1. The first rattata in the list was supposed to be changed to an arbok, but it didn't work, so it seems. I kept encountering the usual pidgey's and rattata's (tried around 20 - 30 encouters, didn't find it).

Here's my script (a simple lvl script):

#dynamic 0x800000

#org @start
checkflag 0x201
if b_true goto @stop
callasm 0x810009
setflag 0x201
end

#org @stop
end

I'm new to ASM, and I'm not sure what I missed out, so can someone help?

Like I told you already, you can't edit the ROM as it's Read-Only Memory. Even if the ASM routine was correct, it would never work.


Hackmew, I have a problem.
I extraced the .asm rountines into a folder named "thumb" on my desktop, which contains the assembler. The first time I tried to assemble, the routine opened in Visual C++ I have installed on my computer. But, whenever I try and run the command prompt as
C:\Documents and Settings\Name\Desktop>thumb lesson1.asm lesson1.bin
I get the message
'thumb' is not recognized as an internal or external command, operable
program or batch file.
I have little experience with command prompts, so did I mis-type something? Or is it another problem I am having?

Well... The problem is your using the wrong folder. Type "cd thumb" without quotes and try again. If you extracted everything from the zipped archive into your thumb folder, it will work.

PlatniumPiano
July 8th, 2009, 08:43 AM
Well... The problem is your using the wrong folder. Type "cd thumb" without quotes and try again. If you extracted everything from the zipped archive into your thumb folder, it will work.
Now what happens is that the command prompt opens the routine in Visual C++ again :/

HackMew
July 8th, 2009, 08:47 AM
Now what happens is that the command prompt opens the routine in Visual C++ again :/

Uhm... okay, please see my PM.

-DarK-
July 8th, 2009, 09:59 AM
Like I told you already, you can't edit the ROM as it's Read-Only Memory. Even if the ASM routine was correct, it would never work.

I must've partially misunderstood a part of the tutorial then. But to which offset in the RAM can/must I move the data to be able to change it then?

EDIT: I experimented some more, but it still doesn't work... Here's my ASM routine:

.text
.align 2
.thumb
.thumb_func
.global test1

main:
push {r0-r2, lr}
ldr r0, .WILD_DATA
ldr r0, [r0]
ldr r1, .RAM
ldr r1, [r0, #0x8]
ldr r2, =0x00210000
mov r2, #0x3
add r2, #0x1
mov r2, #0x6
add r2, #0x2
mov r2, #0x18
add r2, #0x3
mov r2, #0x00
str r2, [r1]
pop {r0-r2, pc}


.align 2
.WILD_DATA:
.word 0x003C8F00
.RAM:
.word 0x00200000



The offset used for the ASM routine is still 810008 (and the script is also still the same, but without the check-/setflag now, just "callasm 0x810009" and "end"). I really don't know how to get through this... Can somebody help me?

hi sir tomato my password is syvniti
July 21st, 2009, 04:51 AM
I must've partially misunderstood a part of the tutorial then. But to which offset in the RAM can/must I move the data to be able to change it then?

EDIT: I experimented some more, but it still doesn't work... Here's my ASM routine:

.text
.align 2
.thumb
.thumb_func
.global test1

main:
push {r0-r2, lr}
ldr r0, .WILD_DATA
ldr r0, [r0]
ldr r1, .RAM
ldr r1, [r0, #0x8]
ldr r2, =0x00210000
mov r2, #0x3
add r2, #0x1
mov r2, #0x6
add r2, #0x2
mov r2, #0x18
add r2, #0x3
mov r2, #0x00
str r2, [r1]
pop {r0-r2, pc}


.align 2
.WILD_DATA:
.word 0x003C8F00
.RAM:
.word 0x00200000



The offset used for the ASM routine is still 810008 (and the script is also still the same, but without the check-/setflag now, just "callasm 0x810009" and "end"). I really don't know how to get through this... Can somebody help me?
I'm not sure I understand you.. But... Why do you need this:
ldr r2, =0x00210000
mov r2, #0x3
add r2, #0x1
mov r2, #0x6
add r2, #0x2
mov r2, #0x18
add r2, #0x3

It's seems you're just emptying the third(2) register in the end, with:
mov r2, #0x00
If you'd exsplaing me what you want to do, I might be able to help you.

-DarK-
July 21st, 2009, 05:19 AM
I'm not sure I understand you.. But... Why do you need this:
ldr r2, =0x00210000
mov r2, #0x3
add r2, #0x1
mov r2, #0x6
add r2, #0x2
mov r2, #0x18
add r2, #0x3

It's seems you're just emptying the third(2) register in the end, with:
mov r2, #0x00
If you'd exsplaing me what you want to do, I might be able to help you.

Well, I tried various ways to temporarely change wild pokemon encounters on a certain map (route 1 in my case, just for testing purposes), but nothing seems to work. No matter what I try, I simply can't seem to get it right.

HackMew
July 21st, 2009, 05:25 AM
Well, I tried various ways to temporarely change wild pokemon encounters on a certain map (route 1 in my case, just for testing purposes), but nothing seems to work. No matter what I try, I simply can't seem to get it right.

Just like I told you, you can't change the wild data as it's stored in the ROM. Even if you save the wild data to the RAM, the game will still keep reading the data from the ROM. You would need to find the routine that loads the wild data from the ROM and hack it so it loads it from the RAM instead.
Also, please remember this is not an ASM help thread okay?

-DarK-
July 21st, 2009, 05:51 AM
You would need to find the routine that loads the wild data from the ROM and hack it so it loads it from the RAM instead.

Which I can't do with my current ASM knowledge. I don't even know how and where to start for that. Oh well, pretty pointless to continue then.

hi sir tomato my password is syvniti
July 21st, 2009, 06:24 AM
Which I can't do with my current ASM knowledge. I don't even know how and where to start for that. Oh well, pretty pointless to continue then.Or maybe you should try to read this tutorial...

-DarK-
July 21st, 2009, 06:36 AM
Or maybe you should try to read this tutorial...

I've read it 10x over already, I don't see how it can help me with what I'm trying, as it's something diffirent.

HackMew
October 10th, 2009, 04:10 PM
[A ID]ASM2[/A ID][TUT] Shinies Unleashed
Lesson 2 - Gettin' better v1.0
Requirements: VisualBoyAdvance v1.7.2 or later, VBA-SDL-H (special debugging version), ASM assembler, hex editor, some ROMs.



[css-div="border-style:solid;border-width:2px;padding: 5px 5px 5px 5px; border-color:#D4A12F;background-color:#FEFC75;color:#D4A12F;font-variant:small-caps;"]Important Note!
Before you start reading, it would be better if you update your tools, in particular the ASM assembler. Also, I made a VBA-SDL-H custom archive to include a newer SDL.dll file for those who might be experiencing problems. If that's the case, rename the original SDL.dll file to something like SDL_old.dll and rename the SDL_new.dll to SDL.dll. Both are available in the first lesson (http://www.pokecommunity.com/showthread.php?t=117917#ASM1).[/css-div]

Personality Value
A Pokémon's Personality, sometimes also called Pokémon ID, is a 32-bit value between 0x0 and 0xFFFFFFFF inclusive (0 - 4,294,967,295), which is generated by the games' Pseudo-Random Number Generator (PRNG (http://en.wikipedia.org/wiki/Pseudorandom_number_generator)) when the Pokémon is first encountered. It is set as soon as the Pokémon appears in the wild, or when is received from an NPC (http://en.wikipedia.org/wiki/Non-player_character), or when a Pokémon's egg is received. The Personality value controls many things, including gender, nature, abilities, Unown's letter, and others (http://bulbapedia.bulbagarden.net/wiki/Personality_value).

Individual Values
Individual values, also known as determinant values (both often shortened, respectively, to IVs and DVs), are the Pokémon analogue to genes (http://en.wikipedia.org/wiki/Genes). They are instrumental in determining the differing stats of Pokémon, most specifically of the same species. There are six IVs, one for each of the basic stats: HP, Attack, Defense, Speed, Special Attack and Special Defense. IVs are ranging from 0-31 (or binary 00000-11111). The IV data for each Pokémon is stored as a packed bit field (http://en.wikipedia.org/wiki/Bit_field), taking up 32 bits, including one bit to set if the Pokémon is an egg and another one to determine which of two abilities a Pokémon has (if it has potential to have more than one). The Ability bit is the Most Significant Bit (MSB (http://en.wikipedia.org/wiki/Most_significant_bit)).

Ability / IsEgg / Sp. Def / Sp. Atk / Speed / Defense / Attack / HP
1 1 11111 11111 11111 11111 11111 11111

Shininess
Whether a Pokémon is shiny or not depends on the values of the Trainer ID number, secret ID number, and Personality value. There is an 8 in 65536 chance of a Pokémon being shiny, which simplifies to 1/8192.
Let's call the Personality PID, the Trainer ID TID and the Secret ID SID. We also halve the PID into two 16-bit halves, called PID1 and PID2.

A = TID XOR SID
B = PID1 XOR PID2
C = A XOR B

If C is between 0 and 7 inclusive, then the Pokémon is shiny. As an example, let's take a trainer whose Trainer ID is 32561 and whose Secret ID is 17523.

TID = 32561 = 0x7F31
SID = 17523 = 0x4473

This trainer encounters a Pokémon whose Personality value is 632689202.

PID = 632689202 = 0x25B61232
PID1 = 0x25B6
PID2 = 0x1232

A = TID XOR SID = 0x73F1 XOR 0x4473 = 0x3782
B = PID1 XOR PID2 = 0x25B6 XOR 0x1232 = 0x3784

C = A XOR B = 0x3782 XOR 0x3784 = 0x2

Since 0x2 is less than 0x8, the Pokémon is shiny.

The Pokémon Pseudo-Random Number Generator
A PRNG is an attempt at creating random numbers. There are various methods that can be used to generate pseudo-random numbers. For the sake of simplicity we will refer to them as random even if they are not truly random but are governed by a mathematical formula. The games use one of the simplest types of random number generators, which is the class of Linear Congruential Generators (LCG (http://en.wikipedia.org/wiki/Linear_congruential_generator)).The formula is the following:

Xn+1 = [(a * Xn) + c] mod m

where a is what we call multiplier, c is the increment and m is the modulus. While it is very simple to implement, it produces good random numbers when given particular values for a, c and m. By "good random numbers" we mean that if the numbers were to be listed next to each other, we wouldn't be able to predict what the next random number would be in the list unless we apply the formula. Speaking about the Pokémon games, a, c and m are respectively: 0x41C64E6D (1,103,515,245), 0x6073 (24691) and 2^32 (4,294,967,296). The PRNG works as follows: when the game loads, the program assigns a number to a 32-bit variable which we call seed. Seeds are also occasionally derived from user input, as it is highly improbable to do the exact same thing more than once, making it appear “random”. Whenever the PRNG is called, the current seed is put through the formula and the result then becomes the seed for any subsequent uses of the random generator. Therefore the nature of the generator is a recursive algorithm (http://en.wikipedia.org/wiki/Recursion_(computer_science)). Knowing that the modulo of powers of 2 (http://en.wikipedia.org/wiki/Modulo_operation) can alternatively be expressed as a bitwise AND (http://en.wikipedia.org/wiki/Bitwise_operation) operation:

x mod 2^n = x AND (2^n - 1)

we can replace the coefficients in the general formula above to match the values used by the games:

Result = [(0x41C64E6D * Seed) + 0x6073] AND 0xFFFFFFFF

Note that the result itself is not the random number: only the upper 16 bits are. This means the PRNG can produce numbers between 0x0 and 0xFFFF inclusive (0 – 65535).
For instance, given the seed 0x82341825, what is the random number that the PRNG outputs?
First we multiply the seed by multiplier, getting 0x2174164F61278DC1. Then we add the increment and we get 0x2174164F6127EE34. ANDing it with 0xFFFFFFFF we get the final result, which is 0x6127EE34. The random number produced is thus the first 16 bits of this new seed, 0x6127. Repeatedly invoking the PRNG produces the following list of random numbers:
0x6127, 0xF8CC, 0xED12, 0xA5FE, 0x61BB, ...
It can be proven that the seed variable will become the same as it was at the beginning only after the PRNG is invoked 4,294,967,296 times. In all those PRNG executions, the seed would have become equal to every number between 0x0 and 0xFFFFFFFF (or between 0 and 4,294,967,295) exactly once. This essentially means that the random number sequence won't repeat itself till after that amount of invocations.
A reverse function for the PRNG might also be useful. That is, given the current seed retrieving the previous one. For a given Xn+1, Xn = [(a^-1) * (Xn+1 – c)] mod m. Due to the fact we are working with integer numbers and the formula includes a modulo, in order to get a^-1 (or 1/a, which is the same) we can't simple calculate the inverse number as we would usually do. For example, if x = 2.0, x^-1 = 2.0^-1 = 1/2.0 = 0.5. Instead, we need to find the modular multiplicate inverse (http://en.wikipedia.org/wiki/Modular_multiplicative_inverse), if it exists. In our case, it does and it's 0xEEB9EB65 (4,005,161,829). Replacing the coefficients with their values, we get the inverse formula:

Result = [0xEEB9EB65 * (Seed – 0x6073)] AND 0xFFFFFFFF

Given the seed 0x6127EE34, we need to fist subtract it by 0x6073 getting 0x61278DC1. Then we multiply it by 0xEEB9EB65 and we get 0x5A9954B482341825. After ANDing, the final result is 0x82341825. Does this number ring a bell? Yeah, it is the seed used above.

Let's extract now the PRNG routine from a FR US v1.0 ROM (which is located at 0x44EC8) and comment it line by line:

08044ec8 4a04 ldr r2, [$08044edc] (=$03005000)
Load into r2 the address 0x03005000, which is where the current seed is stored.

08044eca 6811 ldr r1, [r2, #0x0]
Load into r1 the 32-bit seed located at the address stored in r2 + 0x0.

08044ecc 4804 ldr r0, [$08044ee0] (=$41c64e6d)
Load into R0 the multiplier.

08044ece 4348 mul r0, r1
Multiply the multiplier by the current seed and store the result in R0.

08044ed0 4904 ldr r1, [$08044ee4] (=$00006073)
Load into r1 the increment.

08044ed2 1840 add r0, r0, r1
Increment the value in R0 by the value in r1, store the result in R0.

08044ed4 6010 str r0, [r2, #0x0]
Store the new seed at the address stored in R2 + 0x0.

08044ed6 0c00 lsr r0, r0, #0x10
Logical right shift (http://en.wikipedia.org/wiki/Logical_shift) R0 by 0x10 (16) bits to get only the upper 16-bit value from the new seed.

08044ed8 4770 bx lr
Return wherever the routine was called.

The routine is quite simple, as you can see. You might argue there's no ANDing in the routine and, indeed there's no explicit AND operation. As you should remember, though, the registers can hold up to 32-bit values. When the value overflows it is truncated to the lower 32 bits. This means there's no need to use the AND operator.

PID/IVs Relationship
If you read carefully till now, you should have noticed that something doesn't seem right. The PID is randomly generated, and it's a 32-bit value. Yet the PRNG generate only 16-bit numbers. How come? The answer is simple. The game creates a PID from two PRNG calls. Since each PRNG call results in a 16-bit number, appending these two 16-bit numbers together makes a 32-bit number, which becomes the PID of the Pokémon: the second random number becomes the first 16 bits of the PID, and the first random number becomes the second 16 bits.
For example, suppose the two random numbers generated were 0x6127 and 0xF8CC as above. Then the PID of the Pokémon would be 0xF8CC6127 (4,174,143,783).
The six IVs of the Pokémon are also created from just two PRNG calls. Since each IV consists of 5 bits (because the binary number 11111 is equal to 31 in decimal), the first random number would contain 3 of these IVs (5 + 5 + 5 = 15), with one extra bit, while the second random number would contain the other 3. The IVs would be extracted from the two random numbers as follows:

First Random Number:
x | xxxxx | xxxxx | xxxxx
-|Defense IV| Attack IV | HP IV

Second Random Number:
x | xxxxx | xxxxx | xxxxx
-|Sp. Def IV | Sp. Atk IV | Speed IV

There are basically 11 different ways of how the PRNG is invoked to produce a Pokémon:

1. A-B-C-D
Four PRNG calls are made, two to generate the PID and two to generate the IVs. It can be illustrated as [PID] [PID] [IVs] [IVs].

2. A-B-C-E
Five PRNG calls are made. The first two are used to generate the PID and the last two are used to generate the IVs. The fourth PRNG call is not used for anything. It can be illustrated as [PID] [PID] [IVs] [xxx] [IVs].

3. A-B-C-F
It can be illustrated as [PID] [PID] [IVs] [xxx] [xxx] [IVs].

4. A-B-D-E
It can be illustrated as [PID] [PID] [IVs] [xxx] [IVs].

5. A-B-D-F
It can be illustrated as [PID] [PID] [xxx] [IVs] [xxx] [IVs].

6. A-B-E-F
It can be illustrated as [PID] [PID] [xxx] [xxx] [IVs] [IVs].

7. A-C-D-E
It can be illustrated as [PID] [xxx] [PID] [IVs] [IVs].

8. A-C-D-F
It can be illustrated as [PID] [xxx] [PID] [IVs] [xxx] [IVs].

9. A-D-E-F
It can be illustrated as [PID] [xxx] [xxx] [PID] [IVs] [IVs].

10. B-A-C-D (Restricted)
Restricted refers to the fact the seed used to generate the PID/IVs can only be a value between 0x0 and 0xFFFF. It can be illustrated as [PID] [PID] [IVs] [IVs].

11. B-A-C-D (Unrestricted)
It can be illustrated as [PID] [PID] [IVs] [IVs].


Methods 2-9 are used to produce wild Pokémon. All the Pokémon we can catch or that are given in the games are created using Method 1. Examples of non-wild Pokémon are: legendary Pokémon, starters, Eevee in FR/LG, Castform and Beldum in R/S/E. Method 1 is also used for some wild Pokémon. The criterion for choosing whether method to use in the creation of wild Pokémon seems to be arbitrary, although it might be related to the terrain where they are situated. Methods 10-11 are only used for GBA event Pokémon such as the WISHMKR Jirachi and others.

Introducing the Shiny Hack v3
While the second version by Mastermind_X solved the issues in the first one, some things weren't fixed. First of all, it wasn't designed to work with trainer's Pokémon, meaning we couldn't choose which Pokémon should have been shiny or not. The only thing we could get was having the first one, and only the first one, shiny. Also, take a look at the shininess explanation above. See C = A XOR B? Well, in version 2 (and version 1 as well) C is always zero. Considering “normal” shinies should have it ranging from 0 to 7, it's not that good, is it? Think about this scenario too: let's say we want to give the player two shinies. Using version 2 the shiny flag is disabled automatically, so we would need to enable it, give the Pokémon, enable it again and give the second Pokémon. A bit annoying. Last but not the least, the hacked shinies were easily recognized as being hacked due to the IVs not matching. Version 3 is my effort at fixing all the issues above. This new version introduces an 8-bit shiny counter rather than a flag. While a flag can be either on or off (0/1), the shiny counter can be anything between 0x1 and 0xFF (1 - 255). Each time the routine is called, the counter is decreased by 1. When the counter reaches 0x0, the Shiny Hack is disabled. The shiny counter can be easily accessed in game. All we have to do is to set the variable 0x8003.

setvar 0x8003 0x2

In the example above, the shiny counter would be set to 0x2. This means we could give two consequent Pokémon and both would be shiny. After the second Pokémon is given, the shiny counter would reach 0x0, so the Shiny Hack would be disabled. For wild Pokémon, it's better not to set the counter anything higher than 0x1 anyway. What about trainers? The main concept is similar. The difference is that we need two setvar commands. The first one will be used as the counter, and the second will be used to tell which Pokémon needs to be shiny. Let's say we're about to battle a trainer who has 5 Pokémon. We want the second and the third Pokémon to be shiny, for example. So we would first set variable 0x8003 like this:

setvar 0x8003 0xYY0X

where X stands for the Pokémon amount the trainer has. In our example, X is 5 therefore:

setvar 0x8003 0xYY05

Then we need to choose the shiny Pokémon. Starting from the very first Pokémon till the last one, we write 1 if the Pokémon needs to be shiny or 0 otherwise:

01100

In case you didn't realize, that's just a custom binary bit field. After converting it to hex we get 0xC. So:

setvar 0x8003 0xC05

That's it. Time to see how the Shiny Hack v3 works more in-depth.

How does it work
Now, I might just say "I does this and that, bla bla… the end". But it wouldn't be half as funny as what we're actually going to do. So… we need to hack the Pokémon data, fine. Of course we need to know where it is stored, first. Taking a look at the Pokémon data structure (http://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_data_structure_in_the_GBA), we can see the first 4 bytes are the Personality, immediately followed by the 4-byte Trainer IDs. Since the Personality changes all the times, the Trainer IDs can be a good choice for searching the data. Start the VBA-SDL-H and load a FireRed ROM. To make things easier, start a new game, pick your starter and retrieve your Secret ID. If you don't remember how to retrieve the Secret ID, than re-read the first lesson. At this point, go into the grass and keep walking till a wild Pokémon appears. Then press F11 to stop the game. To search a hex string, the syntax is the following:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]fh <start> [<max-result>] <hex-string>[/css-div]
The start parameter is used to determine which address to start looking for the hex string. The max result parameter will determine the max amount of results to display. As for the hex string, it must be made up by one or more hex values. In our case, the start parameter can be simply 0 and the max result one can be 50, just in case. To get the hex string, first convert into hex both Trainer ID and Secret ID. For example, if they were 51267 and 14964 respectively, they would be 0xC843 and 0x3A74. Now swap the first and the second byte. We get 0x43C8 and 0x743A. Now, putting both swapped IDs together we get 0x43C8743A. Anyway, the hex string doesn't need the 0x prefix, so it would just be 43C8743A. Type fh 0 50 43C8743A and press Enter:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]Search result (0): 020151c0
Search result (1): 020228cc
Search result (2): 0202341c
Search result (3): 0202361c
Search result (4): 02023c38
Search result (5): 02023c90
Search result (6): 02024030
Search result (7): 02024288
Search result (8): 020245a2
Search completed.
9 results found.[/css-div]
Only one of them is the right one, though. To find it out, we need to check each result to see if it could be a valid one. Right after the Trainer IDs there's the Pokémon nickname, in fact. Let's check the first one, by typing mb 020151c0 and pressing Enter afterwards:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> mb 020151c0
020151c0 43 c8 74 3a bd c2 bb cc c7 bb c8 be bf cc 02 02 C.t:............
020151d0 bb bb bb bb bb bb bb 00 31 07 00 00 19 4c 93 f2 ........1....L..
020151e0 13 4c be f2 30 64 be f2 13 4c bf f2 13 4c be f2 .L..0d...L...L..
020151f0 13 4c be f2 17 4c be f2 de 4c be f2 13 00 be f2 .L...L...L......
02015200 13 14 bb d0 f7 a4 a2 dd 13 4c be f2 00 00 00 00 .........L......
02015210 06 ff 14 00 14 00 0b 00 0b 00 0e 00 0e 00 0a 00 ................
02015220 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................[/css-div]
The first 4 bytes are the Trainer IDs: 43 C8 74 3A. The next 10 bytes are the nickname: BD C2 BB CC C7 BB C8 BE BF CC, which translate into CHARMANDER. Definitely not the wild Pokémon, a Pidgey in my case. Let's go ahead with the next result:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> mb 020228cc
020228cc 43 c8 74 3a 00 00 00 00 00 00 00 00 00 00 00 00 C.t:............
020228dc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
020228ec 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
020228fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202290c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202291c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202292c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................[/css-div]
Considering the hypothetical nickname is all filled by 0x00, it can't be a valid result, so we check the next one:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> mb 0202341c
0202341c 43 c8 74 3a 00 00 00 00 00 00 00 00 00 00 00 00 C.t:............
0202342c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202343c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202344c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202345c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202346c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202347c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................[/css-div]
Nothing much to say, it's the same as the previous one. Another one skipped, and another one to check:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> mb 0202361c
0202361c 43 c8 74 3a 00 00 00 00 00 00 00 00 00 00 00 00 C.t:............
0202362c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202363c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202364c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202365c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202366c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202367c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................[/css-div]
Once again, a zero-filled one. Next one:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> mb 02023c38
02023c38 43 c8 74 3a 10 00 07 00 07 00 08 00 07 00 07 00 C.t:............
02023c48 21 00 00 00 00 00 00 00 62 3a 61 3a 06 06 06 06 !.......b:a:....
02023c58 06 06 06 06 33 00 02 04 23 00 00 00 0f 00 03 46 ....3...#......F
02023c68 0f 00 00 00 ca c3 be c1 bf d3 ff be bf cc ff 00 ................
02023c78 bb bb bb bb bb bb bb ff 39 00 00 00 45 f2 c2 55 ........9...E..U
02023c88 00 00 00 00 00 00 00 00 43 c8 74 3a 00 00 00 00 ........C.t:....
02023c98 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................[/css-div]
Somehow interesting. It might be valid… but wait. Even if it's not all 0x00, the nickname is not valid anyway because there are some 0x00, which means the nickname would have some spaces in it. Clearly not a valid result. Well, let's see another one:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> mb 02023c90
02023c90 43 c8 74 3a 00 00 00 00 00 00 00 00 00 00 00 00 C.t:............
02023ca0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
02023cb0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
02023cc0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
02023cd0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
02023ce0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
02023cf0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................[/css-div]
Again, an invalid result. Are we out of luck or something? Hmm, my extra senses are tingling… the next result must be the good one:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> mb 02024030
02024030 43 c8 74 3a ca c3 be c1 bf d3 ff 03 fe 1f 02 02 C.t:............
02024040 bb bb bb bb bb bb bb 00 53 42 00 00 16 3a b6 6f ........SB...:.o
02024050 3f 3a b6 6f 06 7c b6 6f 06 5f b5 4d 64 00 d7 55 ?:.o.|.o._.Md..U
02024060 06 3a b6 6f 06 3a b6 6f 06 3a b6 6f 06 3a b6 6f .:.o.:.o.:.o.:.o
02024070 27 3a b6 6f 06 3a b6 6f 25 3a b6 6f 00 00 00 00 ':.o.:.o%:.o....
02024080 03 ff 0f 00 0f 00 07 00 07 00 08 00 07 00 07 00 ................
02024090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................[/css-div]
Note there's a FF in the nickname, so it stops there. The nickname is then CA C3 BE C1 BF D3, or PIDGEY. Gotcha! That seems to be the right result. But just in case, let's check the last ones too:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> mb 02024288
02024288 43 c8 74 3a bd c2 bb cc c7 bb c8 be bf cc 02 02 C.t:............
02024298 bb bb bb bb bb bb bb 00 31 07 00 00 19 4c 93 f2 ........1....L..
020242a8 13 4c be f2 30 64 be f2 13 4c bf f2 13 4c be f2 .L..0d...L...L..
020242b8 13 4c be f2 17 4c be f2 de 4c be f2 13 00 be f2 .L...L...L......
020242c8 13 14 bb d0 f7 a4 a2 dd 13 4c be f2 00 00 00 00 .........L......
020242d8 06 ff 14 00 14 00 0b 00 0b 00 0e 00 0e 00 0a 00 ................
020242e8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................[/css-div]
This might have been valid, if the nickname wasn't CHARMANDER. One more to go:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> mb 020245a2
020245a2 43 c8 74 3a 00 00 0c 09 28 00 01 00 00 00 00 00 C.t:....(.......
020245b2 da 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 ................
020245c2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
020245d2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
020245e2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
020245f2 00 00 48 80 00 00 00 00 00 00 00 00 00 00 00 00 ..H.............
02024602 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................[/css-div]
Is there anything to say? Not really, it's not valid. That confirms the address 0x02024030 is what we were looking for. Yay! However, it might be DMA-protected, meaning it could change each time. Type c and press Enter to continue the normal gameplay. Run away from the wild Pokémon, or just kill it. Now enter/exit a building. If the address was protected, that would be one thing that triggers the change. Press F11 and put a breakpoint (http://en.wikipedia.org/wiki/Breakpoint) on write at 0x02024030, for 4 bytes. This is the syntax:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]bpw {address} {size}[/css-div]
In our case, we would type bpw 02024030 4. Yeah, no hex prefix at all:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> bpw 02024030 4
Added break on write at 02024030 for 4 bytes[/css-div]
Type c and continue the game. Whenever the game will write anything in the range 0x02024030 - 0x02024034, the debugger will break. If the address changed all the time, it wouldn't break at all, because the game would write to different addresses all the times. So walk into the grass and see what happens. The game will break:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]Breakpoint (on write) address 02024030 old:43 new:00
R00=02024030 R04=0202402c R08=00000001 R12=00000001
R01=00000004 R05=02024220 R09=00000000 R13=03007d64
R02=0202402c R06=00000003 R10=00000000 R14=0803d99f
R03=00000000 R07=083c8e90 R11=00000000 R15=0803d98a
CPSR=0000003f (......T Mode: 1f)
0803d986 7003 strb r3, [r0, #0x0]
> 0803d988 3101 add r1, #0x1
0803d98a 294f cmp r1, #0x4f[/css-div]
This means the address is not protected, good news. Analyzing further the breakpoint data, we can see the first byte, 0x43, got overwritten by 0x00. After continuing, the game will break again:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]Breakpoint (on write) address 02024031 old:c8 new:00
R00=02024031 R04=0202402c R08=00000001 R12=00000001
R01=00000005 R05=02024220 R09=00000000 R13=03007d64
R02=0202402c R06=00000003 R10=00000000 R14=0803d99f
R03=00000000 R07=083c8e90 R11=00000000 R15=0803d98a
CPSR=0000003f (......T Mode: 1f)
0803d986 7003 strb r3, [r0, #0x0]
> 0803d988 3101 add r1, #0x1
0803d98a 294f cmp r1, #0x4f[/css-div]
In this case, the second byte got overwritten. In case you haven't guessed that, we're inside an erasing loop, used to clean the Pokémon data before a wild battle.

So, type c and continue till the bytes are replaced by the actual Trainer IDs, like in the example below:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]Breakpoint (on write) address 02024030 old:00000000 new:3a74c843
R00=3a000000 R04=03007cf8 R08=00000000 R12=00000008
R01=3a74c843 R05=00000000 R09=00000000 R13=03007cc0
R02=03007cf8 R06=00000000 R10=00000001 R14=0803db9d
R03=0202402c R07=0202402c R11=00000000 R15=080406dc
CPSR=0000003f (......T Mode: 1f)
080406d8 6079 str r1, [r7, #0x4]
> 080406da e1fe b $08040ada
080406dc 2200 mov r2, #0x0[/css-div]
Here we got inside the routine that wrote into memory the Trainer ID and Secret ID for the Pokémon. Type bpwc to clear the breakpoint. It's time to look into the routine further now. Being the current address 0x080406DA, we can try looking what's upwards by using the dt (disassemble THUMB) command. As a first estimation, let's go back by 0x20 bytes:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> dt 080406ba
080406ba 78e0 ldrb r0, [r4, #0x3]
080406bc 0600 lsl r0, r0, #0x18
080406be 1809 add r1, r1, r0
080406c0 6039 str r1, [r7, #0x0]
080406c2 e20a b $08040ada
080406c4 7821 ldrb r1, [r4, #0x0]
080406c6 7860 ldrb r0, [r4, #0x1]
080406c8 0200 lsl r0, r0, #0x08
080406ca 1809 add r1, r1, r0
080406cc 78a0 ldrb r0, [r4, #0x2]
080406ce 0400 lsl r0, r0, #0x10
080406d0 1809 add r1, r1, r0
080406d2 78e0 ldrb r0, [r4, #0x3]
080406d4 0600 lsl r0, r0, #0x18
080406d6 1809 add r1, r1, r0
080406d8 6079 str r1, [r7, #0x4]
080406da e1fe b $08040ada
080406dc 2200 mov r2, #0x0
080406de 1c3b add r3, r7, #0x0
080406e0 3308 add r3, #0x8[/css-div]
Starting from 0x080406DA and going back we can see many ldrb, lsl and add instructions. At some point, though, there's a branch, located at the address 0x080406C2. Since the branch will jump elsewhere, we can take for granted the routine part writing the Trainer IDs into RAM starts the instruction immediately after, 0x080406C4. Now we need to see where's the end. After those ldrb, lsl and add instructions, there's a str r1, [r7, #0x4], which is the instruction that triggered the breakpoint on write. Shortly after there's a branch. So the code we're interested in it's between 0x080406C4 and 0x080406DA. Even though we know all those instructions will end up writing the Trainer IDs somewhere, it would be interesting to know how it actually happens. We then start putting a THUMB breakpoint on the beginning address, using the bt command like shown below:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> bt 080406c4
Added THUMB breakpoint at 080406c4[/css-div]
Now continue the game and walk into the grass again. When a wild Pokémon is about to appear, the debugger will break:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]Breakpoint 0 reached
R00=080406c4 R04=03007cf8 R08=00000000 R12=00000008
R01=08040568 R05=00000000 R09=00000000 R13=03007cc0
R02=03007cf8 R06=00000000 R10=00000001 R14=0803db9d
R03=0202402c R07=0202402c R11=00000000 R15=080406c6
CPSR=0000003f (......T Mode: 1f)
08040560 4687 mov pc, r0
> 080406c4 7821 ldrb r1, [r4, #0x0]
080406c6 7860 ldrb r0, [r4, #0x1][/css-div]
The instruction at 0x080406C4 is what will be executed next. Type n to execute it:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> n
Continuing after breakpoint
R00=080406c4 R04=03007cf8 R08=00000000 R12=00000008
R01=00000043 R05=00000000 R09=00000000 R13=03007cc0
R02=03007cf8 R06=00000000 R10=00000001 R14=0803db9d
R03=0202402c R07=0202402c R11=00000000 R15=080406c8
CPSR=0000003f (......T Mode: 1f)
080406c4 7821 ldrb r1, [r4, #0x0]
> 080406c6 7860 ldrb r0, [r4, #0x1]
080406c8 0200 lsl r0, r0, #0x08[/css-div]
As you can see, a byte was loaded into R01, from the address stored in R04. That's the first byte of the Trainer IDs. Keep pressing n to execute the next instructions till the branch, watching carefully what happens each time. If you pay enough attention you will see the Trainer IDs are loaded byte by byte and put into R01, and finally stored in the memory location pointed by R07 + 4: 0x0202402C + 0x4 = 0x02024030. The following is the complete code:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]080406c4 7821 ldrb r1, [r4, #0x0]
080406c6 7860 ldrb r0, [r4, #0x1]
080406c8 0200 lsl r0, r0, #0x08
080406ca 1809 add r1, r1, r0
080406cc 78a0 ldrb r0, [r4, #0x2]
080406ce 0400 lsl r0, r0, #0x10
080406d0 1809 add r1, r1, r0
080406d2 78e0 ldrb r0, [r4, #0x3]
080406d4 0600 lsl r0, r0, #0x18
080406d6 1809 add r1, r1, r0
080406d8 6079 str r1, [r7, #0x4]
080406da e1fe b $08040ada[/css-div]
Considering we need to expand it to call our custom shiny handler, we need to replace some of the bytes and make it so the new instructions lead to the hacked routine, making the Pokémon shiny as needed. To call the shiny routine, we basically need 3 things: the address of the routine stored into some register, a bl instruction (branch with link) and a bx one (branch and exchange). It works like this: first of all we need to put the routine address into a register. Which register exactly depends on the other 2 instructions. While I said it in the first lesson already, it's good to remember that the address, pointing to a THUMB routine, must be odd or the game would treat it as an ARM routine instead, and guess what… it wouldn't work at all. The branch with link instruction is used to call a sub-routine and return to where it was called afterwards. The “link” in the name refers to the Link Register which is where the return address is stored. The bl instruction cannot use a direct address. Instead, it can point up to 4 MB forward or backward the address it is used in. This is a problem for us, and indeed we need to use the branch and exchange instruction. All the bx instruction need is a register containing the desired address. When a bx is executed, the address stored into the register is saved into the Program Counter (PC) and the game continue executing the instructions from there. The bx instruction is actually more powerful. Like its name suggests, it can exchange between ARM and THUMB mode. For our purposes, though, we don't need any exchanges and the address in the register will be a odd one. So, the routine address is loaded into a register, then the bl instruction is executed, with the branch pointing to the branch and exchange instruction. This way the routine is executed, and once it's finished, the instruction immediately after the branch with link will be executed. For this to work, the bx must not be near the branch with link. Most of the times, we don't really need to put a bx instruction ourselves, because there are many available already. So start disassembling the routine till you find a bx. It might take some time before you actually find one, depending on the routine's length. Sooner or later, you'll get one. The first we can get is located at 0x08040AFA:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]08040afa 4700 bx r0[/css-div]
As you can see, the register R0 is used. That means our routine address needs to be loaded into R0 if we want to use that branch.

The new code would therefore look something like this:

ldr r0, (=$routine address)
bl $bx address
add r1, r1, r0
ldrb r0, [r4, #0x2]
lsl r0, r0, #0x10
add r1, r1, r0
ldrb r0, [r4, #0x3]
lsl r0, r0, #0x18
add r1, r1, r0
str r1, [r7, #0x4]
b $08040ada

The previous instructions would be overwritten by the ldr and bl. Unlike all other THUMB instructions, bl is the only one that requires 4 bytes. The ldr instruction takes 2 bytes, but in this case it requires 4 additional bytes for the address. However, if you we just overwrite the old instructions, we would break the routine as some instructions would not be executed any more, obviously. Therefore we must take into account the overwritten instructions and execute them manually in the routine we call. We're lucky anyway. We don't need to execute the overwritten instructions at all, with a bit of optimizing. What about it? Well, as you know, the Trainer IDs are loaded one byte at a time. What if we were able to load them 2 bytes at a time, instead? We would save some space, and the extra space gained could be used to put our extra instructions needed to call the shiny routine. Sounds cool, eh? Don't forget we can't always be so lucky. Sometimes, even by optimizing, you don't gain enough space, and sometimes you can't optimize at all. And there's another important thing to note. I said we could load the Trainer IDs 2 byte at once, hence optimizing the old code. We need to be sure, however, that the optimized code works exactly as the old one. This time, everything's okay, as the Trainer IDs are always stored at half-word (16 bit) aligned address. Why is that bit of info important? The very reason is that the ldrh (load half-word) instruction needs to have a half-word aligned address to load the data properly. If for some reasons, the Trainer IDs were badly aligned, we couldn't use ldrh and therefore the optimizing would be gone. Let's analyze the first instructions:

ldrb r1, [r4, #0x0]
ldrb r0, [r4, #0x1]
lsl r0, r0, #0x08
add r1, r1, r0

The very first byte of the Trainer IDs is loaded into R1 from R4, with the first ldrb instruction. The instruction immediately after will load the second byte into R0. Then the value in R0 is shifted by 1 byte (8 bits) and finally both values are put together into R1.

Here's a brief info of what happens:

R1 = 000000T1
R0 = 000000T2
R0 = 0000T200
R1 = 0000T2T1

All those 4 instructions takes a total of 8 bytes. However, we can replace all those with a single ldrh instruction, getting the same result:

ldrh r1, [r4, #0x0]

which means

R1 = 0000T2T1

Not bad. Going from 8 bytes to 2 bytes, we've got 6 free bytes. More optimizing:

ldrb r0, [r4, #0x2]
lsl r0, r0, #0x10
add r1, r1, r0
ldrb r0, [r4, #0x3]
lsl r0, r0, #0x18
add r1, r1, r0

The first ldrb instruction will load into R0 the third byte of the Trainer IDs. The value into R0 is then shifted by 0x10 bits, and added to the current value stored into R1. Then the last byte of the Trainer IDs is loaded into R0, shifted by 0x18 bits this time and added to the R1 value:

R0 = 000000T3
R0 = 00T30000
R1 = 00T3T2T1
R0 = 000000T4
R0 = T4000000
R1 = T4T3T2T1

The instructions above takes 12 bytes but we only need 6 to do the same, thus saving 6 further bytes:

ldrh r0, [r4, #0x2]
lsl r0, r0, #0x10
add r1, r1, r0

so

R0 = 0000T4T3
R0 = T4T30000
R1 = T4T3T2T1

We've got a total of 12 free bytes, which is the exact number of bytes (did I say "lucky"?) we will need. Let's see the new, patched routine:

080406c4 8821 ldrh r1, [r4, #0x0]
080406c6 8860 ldrh r0, [r4, #0x2]
080406c8 0400 lsl r0, r0, #0x10
080406ca 1809 add r1, r1, r0
080406cc 4801 ldr r0, [$080406d4] (=$XXXXXXXX)
080406ce f000 bl $08040afa
080406d2 e001 b $080406d8
080406d4 XXXX
080406d6 XXXX
080406d8 6079 str r1, [r7, #0x4]
080406da e1fe b $08040ada

That means the existing bytes at the offset 0x406C4 need to be replaced with the following ones:

21 88 60 88 00 04 09 18 01 48 00 F0 14 FA 01 E0 XX XX XX XX 79 60 FE E1

where XX XX XX XX represents the shiny routine pointer. For now, don't ask how did I get those values: just take them for granted. If you looked carefully you probably noticed there's an unconditional branch after the branch with link. That's used to skip the routine address stored after, as it's not meant to be treated as some kind of instructions. Now that we can call our custom routine, we need the actual routine. Before showing you the code, I'd like to explain the basic concepts it relies on. As soon as the routine is executed, there's a first safety check to ensure the shiny hack routine is not executed when it shouldn't. Then the shiny counter is checked. If the value is equal to zero, then the routine ends because there's nothing to do. If the value is higher than zero, then it's subtracted by 1 and updated. Now there are two possibilities: the Pokémon that needs to be shiny might or might not be a trainer's one. In the latter case, the Trainer IDs are replaced by the Pokémon ID, hence making the Pokémon shiny. I chose to do this way in order to let the trainers' Pokémon keep the same nature, gender, etc. they would have if they were not shiny. If the Pokémon comes from the wild, of was give us from a NPC, things are different.

First we get a random number between 0 and 7. Then we get another 16-bit random number and we double it to a full word. The resulting word is XORed with the previous random number, and then XORed again with the Trainer IDs:

N1 = 0000000X, X = 0-7
N2 = 0000YYZZ
N3 = YYZZYYZZ
N3 = N3 XOR N1
N3 = N3 XOR Trainer IDs

This way we get a Pokémon ID that would make the Pokémon shiny. However, considering the PID would be usually determined in a whole different way, we must check if the Pokémon ID we got is a valid one. Valid means the Pokémon ID must meet an important requirement: the value has to be like it was generated by the game's PRNG. If the generated Pokémon ID is not valid, then a new one is generated till we get a proper one. There's a tight relationship between the Pokémon ID and the IVs, and since we're manually hacking the Pokémon ID after being generated we must handle the situation accordingly. While checking the PID validity, if we get a good value we also get the seed that, if put through the PRNG formula, would generate the 16 high bits of our PID. In order to generate matching IVs, the current seed must be replaced (remember each time a random number is generated, a new seed is generated too) with the seed we got from the validity check. This way, once the game needs to generate the IVs, it will outputs the right values as it would normally do.

[css-div="width: 240px; padding: 10px; border: dotted 1px dimgray; background-color: #FFF"]http://i37.tinypic.com/23jlwki.png

Yay! It works.[/css-div]
.text
.align 2
.thumb
.thumb_func
.global shiny_hackv3

main:
lsr r0, r4, #0x18
cmp r0, #0x3
bne return
ldr r0, .SHINY_COUNTER
ldrb r0, [r0]
cmp r0, #0x0
bne shiny_hack

return:
bx lr

shiny_hack:
push {r2-r5, lr}
sub r3, r0, #0x1
ldr r0, .SHINY_COUNTER
strb r3, [r0]
ldrb r4, [r0, #0x1]
cmp r4, #0x0
bne is_trainer
add r4, r1, #0x0

no_trainer:
ldr r2, .RANDOM
bl branch_r2
mov r3, #0x7
and r0, r3
add r3, r0, #0x0
ldr r2, .RANDOM
bl branch_r2
lsl r5, r0, #0x10
orr r5, r0
eor r5, r3
eor r5, r4
push {r4-r6}
lsr r1, r5, #0x10
lsl r0, r5, #0x10
mvn r3, r3
lsr r3, r3, #0x10
ldr r4, .RND_MULTIPLIER
ldr r5, .RND_INCREMENT

rnd_loop:
add r6, r0, #0x0
mul r6, r4
add r6, r5
lsr r2, r6, #0x10
cmp r2, r1
beq rnd_end
add r0, #0x1
sub r3, #0x1
cmp r3, #0x0
bne rnd_loop
b not_found

rnd_end:
ldr r2, .RND_ADDRESS
str r6, [r2]
pop {r1, r5-r6}
str r5, [r7]

shiny_ret:
pop {r2-r5, pc}

not_found:
pop {r4-r6}
b no_trainer

is_trainer:
mov r5, #0x1
lsl r5, r3
and r4, r5
cmp r4, #0x0
beq trainer_ret
ldr r1, [r7]

trainer_ret:
b shiny_ret

branch_r2:
bx r2

.align 2
.RND_MULTIPLIER:
.word 0x41C64E6D
.RND_INCREMENT:
.word 0x00006073
.RND_ADDRESS:
.word 0x03005000
.SHINY_COUNTER:
.word 0x020270B8 + (0x8003 * 2)
.RANDOM:
.word 0x08044EC8|1

References
- Pokémon IVs (http://bulbapedia.bulbagarden.net/wiki/IV)
- The Process of PID and IV Creation of Non-Bred Pokemon (http://www.smogon.com/ingame/rng/pid_iv_creation)
- Guide PID-IV (http://projectpokemon.org/editingresearch/guidepidiv.php)
- Personality Value (http://bulbapedia.bulbagarden.net/wiki/Personality_value)

Challenge time
Are you up for an ASM challenge? Then find a way to convert the instruction "lsl r1, r2, #0x3" into hex.

Here's the solution to the previous challenge. It's the FireRed version, and only the actual code. Even if it's the FireRed version, however, the solution is the similar for any game:
[code]main:
push {r0-r1, lr}
ldr r0, .PLAYER_DATA
ldr r0, [r0]
ldr r1, .VAR
ldrh r0, [r0, #0xA]
strh r0, [r1]
ldr r0, .PLAYER_DATA
ldr r0, [r0]
ldrh r0, [r0, #0xC]
strh r0, [r1, #0x2]
pop {r0-r1, pc}[code]

This tutorial is Copyright © 2009 by HackMew.
You are not allowed to copy, modify or distribute it without permission.

Pokepal17
October 10th, 2009, 04:25 PM
[A ID]ASM2[/A ID][TUT] Shinies Unleashed
Lesson 2 - Gettin' better v1.0
Requirements: VisualBoyAdvance v1.7.2 or later, VBA-SDL-H (special debugging version), ASM assembler, hex editor, some ROMs.



[css-div="border-style:solid;border-width:2px;padding: 5px 5px 5px 5px; border-color:#D4A12F;background-color:#FEFC75;color:#D4A12F;font-variant:small-caps;"]Important Note!
Before you start reading, it would be better if you update your tools, in particular the ASM assembler. Also, I made a VBA-SDL-H custom archive to include a newer SDL.dll file for those who might be experiencing problems. If that's the case, rename the original SDL.dll file to something like SDL_old.dll and rename the SDL_new.dll to SDL.dll. Both are available in the first lesson (http://www.pokecommunity.com/showthread.php?t=117917#ASM1).[/css-div]

Personality Value
A Pokémon's Personality, sometimes also called Pokémon ID, is a 32-bit value between 0x0 and 0xFFFFFFFF inclusive (0 - 4,294,967,295), which is generated by the games' Pseudo-Random Number Generator (PRNG (http://en.wikipedia.org/wiki/Pseudorandom_number_generator)) when the Pokémon is first encountered. It is set as soon as the Pokémon appears in the wild, or when is received from an NPC (http://en.wikipedia.org/wiki/Non-player_character), or when a Pokémon's egg is received. The Personality value controls many things, including gender, nature, abilities, Unown's letter, and others (http://bulbapedia.bulbagarden.net/wiki/Personality_value).

Individual Values
Individual values, also known as determinant values (both often shortened, respectively, to IVs and DVs), are the Pokémon analogue to genes (http://en.wikipedia.org/wiki/Genes). They are instrumental in determining the differing stats of Pokémon, most specifically of the same species. There are six IVs, one for each of the basic stats: HP, Attack, Defense, Speed, Special Attack and Special Defense. IVs are ranging from 0-31 (or binary 00000-11111). The IV data for each Pokémon is stored as a packed bit field (http://en.wikipedia.org/wiki/Bit_field), taking up 32 bits, including one bit each to set if the Pokémon is an egg or is nicknamed, respectively. The IsEgg bit is the Most Significant Bit (MSB (http://en.wikipedia.org/wiki/Most_significant_bit)).

IsEgg / IsNicknamed / Sp. Def / Sp. Atk / Speed / Defense / Attack / HP
1 1 11111 11111 11111 11111 11111 11111

Shininess
Whether a Pokémon is shiny or not depends on the values of the Trainer ID number, secret ID number, and Personality value. There is an 8 in 65536 chance of a Pokémon being shiny, which simplifies to 1/8192.
Let's call the Personality PID, the Trainer ID TID and the Secret ID SID. We also halve the PID into two 16-bit halves, called PID1 and PID2.

A = TID XOR SID
B = PID1 XOR PID2
C = A XOR B

If C is between 0 and 7 inclusive, then the Pokémon is shiny. As an example, let's take a trainer whose Trainer ID is 32561 and whose Secret ID is 17523.

TID = 32561 = 0x7F31
SID = 17523 = 0x4473

This trainer encounters a Pokémon whose Personality value is 632689202.

PID = 632689202 = 0x25B61232
PID1 = 0x25B6
PID2 = 0x1232

A = TID XOR SID = 0x73F1 XOR 0x4473 = 0x3782
B = PID1 XOR PID2 = 0x25B6 XOR 0x1232 = 0x3784

C = A XOR B = 0x3782 XOR 0x3784 = 0x2

Since 0x2 is less than 0x8, the Pokémon is shiny.

The Pokémon Pseudo-Random Number Generator
A PRNG is an attempt at creating random numbers. There are various methods that can be used to generate pseudo-random numbers. For the sake of simplicity we will refer to them as random even if they are not truly random but are governed by a mathematical formula. The games use one of the simplest types of random number generators, which is the class of Linear Congruential Generators (LCG (http://en.wikipedia.org/wiki/Linear_congruential_generator)).The formula is the following:

Xn+1 = [(a * Xn) + c] mod m

where a is what we call multiplier, c is the increment and m is the modulus. While it is very simple to implement, it produces good random numbers when given particular values for a, c and m. By "good random numbers" we mean that if the numbers were to be listed next to each other, we wouldn't be able to predict what the next random number would be in the list unless we apply the formula. Speaking about the Pokémon games, a, c and m are respectively: 0x41C64E6D (1,103,515,245), 0x6073 (24691) and 2^32 (4,294,967,296). The PRNG works as follows: when the game loads, the program assigns a number to a 32-bit variable which we call seed. Seeds are also occasionally derived from user input, as it is highly improbable to do the exact same thing more than once, making it appear “random”. Whenever the PRNG is called, the current seed is put through the formula and the result then becomes the seed for any subsequent uses of the random generator. Therefore the nature of the generator is a recursive algorithm (http://en.wikipedia.org/wiki/Recursion_(computer_science)). Knowing that the modulo of powers of 2 (http://en.wikipedia.org/wiki/Modulo_operation) can alternatively be expressed as a bitwise AND (http://en.wikipedia.org/wiki/Bitwise_operation) operation:

x mod 2^n = x AND (2^n - 1)

we can replace the coefficients in the general formula above to match the values used by the games:

Result = [(0x41C64E6D * Seed) + 0x6073] AND 0xFFFFFFFF

Note that the result itself is not the random number: only the upper 16 bits are. This means the PRNG can produce numbers between 0x0 and 0xFFFF inclusive (0 – 65535).
For instance, given the seed 0x82341825, what is the random number that the PRNG outputs?
First we multiply the seed by multiplier, getting 0x2174164F61278DC1. Then we add the increment and we get 0x2174164F6127EE34. ANDing it with 0xFFFFFFFF we get the final result, which is 0x6127EE34. The random number produced is thus the first 16 bits of this new seed, 0x6127. Repeatedly invoking the PRNG produces the following list of random numbers:
0x6127, 0xF8CC, 0xED12, 0xA5FE, 0x61BB, ...
It can be proven that the seed variable will become the same as it was at the beginning only after the PRNG is invoked 4,294,967,296 times. In all those PRNG executions, the seed would have become equal to every number between 0x0 and 0xFFFFFFFF (or between 0 and 4,294,967,295) exactly once. This essentially means that the random number sequence won't repeat itself till after that amount of invocations.
A reverse function for the PRNG might also be useful. That is, given the current seed retrieving the previous one. For a given Xn+1, Xn = [(a^-1) * (Xn+1 – c)] mod m. Due to the fact we are working with integer numbers and the formula includes a modulo, in order to get a^-1 (or 1/a, which is the same) we can't simple calculate the inverse number as we would usually do. For example, if x = 2.0, x^-1 = 2.0^-1 = 1/2.0 = 0.5. Instead, we need to find the modular multiplicate inverse (http://en.wikipedia.org/wiki/Modular_multiplicative_inverse), if it exists. In our case, it does and it's 0xEEB9EB65 (4,005,161,829). Replacing the coefficients with their values, we get the inverse formula:

Result = [0xEEB9EB65 * (Seed – 0x6073)] AND 0xFFFFFFFF

Given the seed 0x6127EE34, we need to fist subtract it by 0x6073 getting 0x61278DC1. Then we multiply it by 0xEEB9EB65 and we get 0x5A9954B482341825. After ANDing, the final result is 0x82341825. Does this number ring a bell? Yeah, it is the seed used above.

Let's extract now the PRNG routine from a FR US v1.0 ROM (which is located at 0x44EC8) and comment it line by line:

08044ec8 4a04 ldr r2, [$08044edc] (=$03005000)
Load into r2 the address 0x03005000, which is where the current seed is stored.

08044eca 6811 ldr r1, [r2, #0x0]
Load into r1 the 32-bit seed located at the address stored in r2 + 0x0.

08044ecc 4804 ldr r0, [$08044ee0] (=$41c64e6d)
Load into R0 the multiplier.

08044ece 4348 mul r0, r1
Multiply the multiplier by the current seed and store the result in R0.

08044ed0 4904 ldr r1, [$08044ee4] (=$00006073)
Load into r1 the increment.

08044ed2 1840 add r0, r0, r1
Increment the value in R0 by the value in r1, store the result in R0.

08044ed4 6010 str r0, [r2, #0x0]
Store the new seed at the address stored in R2 + 0x0.

08044ed6 0c00 lsr r0, r0, #0x10
Logical right shift (http://en.wikipedia.org/wiki/Logical_shift) R0 by 0x10 (16) bits to get only the upper 16-bit value from the new seed.

08044ed8 4770 bx lr
Return wherever the routine was called.

The routine is quite simple, as you can see. You might argue there's no ANDing in the routine and, indeed there's no explicit AND operation. As you should remember, though, the registers can hold up to 32-bit values. When the value overflows it is truncated to the lower 32 bits. This means there's no need to use the AND operator.

PID/IVs Relationship
If you read carefully till now, you should have noticed that something doesn't seem right. The PID is randomly generated, and it's a 32-bit value. Yet the PRNG generate only 16-bit numbers. How come? The answer is simple. The game creates a PID from two PRNG calls. Since each PRNG call results in a 16-bit number, appending these two 16-bit numbers together makes a 32-bit number, which becomes the PID of the Pokémon: the second random number becomes the first 16 bits of the PID, and the first random number becomes the second 16 bits.
For example, suppose the two random numbers generated were 0x6127 and 0xF8CC as above. Then the PID of the Pokémon would be 0xF8CC6127 (4,174,143,783).
The six IVs of the Pokémon are also created from just two PRNG calls. Since each IV consists of 5 bits (because the binary number 11111 is equal to 31 in decimal), the first random number would contain 3 of these IVs (5 + 5 + 5 = 15), with one extra bit, while the second random number would contain the other 3. The IVs would be extracted from the two random numbers as follows:

First Random Number:
x | xxxxx | xxxxx | xxxxx
-|Defense IV| Attack IV | HP IV

Second Random Number:
x | xxxxx | xxxxx | xxxxx
-|Sp. Def IV | Sp. Atk IV | Speed IV

There are basically six different ways of how the PRNG is invoked to produce a Pokémon:
Method 1
Four PRNG calls are made, two to generate the PID and two to generate the IVs. It can be illustrated as [PID] [PID] [IVs] [IVs].

Method 2
Five PRNG calls are made. The first two are used to generate the PID and the last two are used to generate the IVs. The third PRNG call is not used for anything. It can be illustrated as [PID] [PID] [xxx] [IVs] [IVs].

Method 3
Five PRNG calls are made. The first and third are used to generate the PID and the last two are used to generate the IVs. The second PRNG call is not used for anything. It can be illustrated as [PID] [xxx] [PID] [IVs] [IVs].

Method 4
Five PRNG calls are made. The first and second are used to generate the PID and the third and fifth are used to generate the IVs. The fourth PRNG call is not used for anything. It can be illustrated as [PID] [PID] [IVs] [xxx] [IVs].

Method 5
Six PRNG calls are made. The first and second are used to generate the PID and the fourth and sixth are used to generate the IVs. The third and fifth PRNG calls are not used for anything. It can be illustrated as [PID] [PID] [xxx] [IVs] [xxx] [IVs].

Method 6
Six PRNG calls are made. The first and second are used to generate the PID and the fifth and sixth are used to generate the IVs. The third and fourth PRNG calls are not used for anything. It can be illustrated as [PID] [PID] [xxx] [xxx] [IVs] [IVs].

Methods 2-6 are used to produce wild Pokémon. All the Pokémon we can catch or that are given in the games are created using Method 1. Examples of non-wild Pokémon are: legendary Pokémon, starters, Eevee in FR/LG, Castform and Beldum in R/S/E. Method 1 is also used for some wild Pokémon. The criterion for choosing whether method to use in the creation of wild Pokémon seems to be arbitrary, although it might be related to the terrain where they are situated.

Introducing the Shiny Hack v3
While the second version by Mastermind_X solved the issues in the first one, some things weren't fixed. First of all, it wasn't designed to work with trainer's Pokémon, meaning we couldn't choose which Pokémon should have been shiny or not. The only thing we could get was having the first one, and only the first one, shiny. Also, take a look at the shininess explanation above. See C = A XOR B? Well, in version 2 (and version 1 as well) C is always zero. Considering “normal” shinies should have it ranging from 0 to 7, it's not that good, is it? Think about this scenario too: let's say we want to give the player two shinies. Using version 2 the shiny flag is disabled automatically, so we would need to enable it, give the Pokémon, enable it again and give the second Pokémon. A bit annoying. Last but not the least, the hacked shinies were easily recognized as being hacked due to the IVs not matching. Version 3 is my effort at fixing all the issues above. This new version introduces an 8-bit shiny counter rather than a flag. While a flag can be either on or off (0/1), the shiny counter can be anything between 0x1 and 0xFF (1 - 255). Each time the routine is called, the counter is decreased by 1. When the counter reaches 0x0, the Shiny Hack is disabled. The shiny counter can be easily accessed in game. All we have to do is to set the variable 0x8003.

setvar 0x8003 0x2

In the example above, the shiny counter would be set to 0x2. This means we could give two consequent Pokémon and both would be shiny. After the second Pokémon is given, the shiny counter would reach 0x0, so the Shiny Hack would be disabled. For wild Pokémon, it's better not to set the counter anything higher than 0x1 anyway. What about trainers? The main concept is similar. The difference is that we need two setvar commands. The first one will be used as the counter, and the second will be used to tell which Pokémon needs to be shiny. Let's say we're about to battle a trainer who has 5 Pokémon. We want the second and the third Pokémon to be shiny, for example. So we would first set variable 0x8003 like this:

setvar 0x8003 0xYY0X

where X stands for the Pokémon amount the trainer has. In our example, X is 5 therefore:

setvar 0x8003 0xYY05

Then we need to choose the shiny Pokémon. Starting from the very first Pokémon till the last one, we write 1 if the Pokémon needs to be shiny or 0 otherwise:

01100

In case you didn't realize, that's just a custom binary bit field. After converting it to hex we get 0xC. So:

setvar 0x8003 0xC05

That's it. Time to see how the Shiny Hack v3 works more in-depth.

How does it work
Now, I might just say "I does this and that, bla bla… the end". But it wouldn't be half as funny as what we're actually going to do. So… we need to hack the Pokémon data, fine. Of course we need to know where it is stored, first. Taking a look at the Pokémon data structure (http://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_data_structure_in_the_GBA), we can see the first 4 bytes are the Personality, immediately followed by the 4-byte Trainer IDs. Since the Personality changes all the times, the Trainer IDs can be a good choice for searching the data. Start the VBA-SDL-H and load a FireRed ROM. To make things easier, start a new game, pick your starter and retrieve your Secret ID. If you don't remember how to retrieve the Secret ID, than re-read the first lesson. At this point, go into the grass and keep walking till a wild Pokémon appears. Then press F11 to stop the game. To search a hex string, the syntax is the following:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]fh <start> [<max-result>] <hex-string>[/css-div]
The start parameter is used to determine which address to start looking for the hex string. The max result parameter will determine the max amount of results to display. As for the hex string, it must be made up by one or more hex values. In our case, the start parameter can be simply 0 and the max result one can be 50, just in case. To get the hex string, first convert into hex both Trainer ID and Secret ID. For example, if they were 51267 and 14964 respectively, they would be 0xC843 and 0x3A74. Now swap the first and the second byte. We get 0x43C8 and 0x743A. Now, putting both swapped IDs together we get 0x43C8743A. Anyway, the hex string doesn't need the 0x prefix, so it would just be 43C8743A. Type fh 0 50 43C8743A and press Enter:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]Search result (0): 020151c0
Search result (1): 020228cc
Search result (2): 0202341c
Search result (3): 0202361c
Search result (4): 02023c38
Search result (5): 02023c90
Search result (6): 02024030
Search result (7): 02024288
Search result (8): 020245a2
Search completed.
9 results found.[/css-div]
Only one of them is the right one, though. To find it out, we need to check each result to see if it could be a valid one. Right after the Trainer IDs there's the Pokémon nickname, in fact. Let's check the first one, by typing mb 020151c0 and pressing Enter afterwards:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> mb 020151c0
020151c0 43 c8 74 3a bd c2 bb cc c7 bb c8 be bf cc 02 02 C.t:............
020151d0 bb bb bb bb bb bb bb 00 31 07 00 00 19 4c 93 f2 ........1....L..
020151e0 13 4c be f2 30 64 be f2 13 4c bf f2 13 4c be f2 .L..0d...L...L..
020151f0 13 4c be f2 17 4c be f2 de 4c be f2 13 00 be f2 .L...L...L......
02015200 13 14 bb d0 f7 a4 a2 dd 13 4c be f2 00 00 00 00 .........L......
02015210 06 ff 14 00 14 00 0b 00 0b 00 0e 00 0e 00 0a 00 ................
02015220 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................[/css-div]
The first 4 bytes are the Trainer IDs: 43 C8 74 3A. The next 10 bytes are the nickname: BD C2 BB CC C7 BB C8 BE BF CC, which translate into CHARMANDER. Definitely not the wild Pokémon, a Pidgey in my case. Let's go ahead with the next result:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> mb 020228cc
020228cc 43 c8 74 3a 00 00 00 00 00 00 00 00 00 00 00 00 C.t:............
020228dc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
020228ec 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
020228fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202290c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202291c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202292c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................[/css-div]
Considering the hypothetical nickname is all filled by 0x00, it can't be a valid result, so we check the next one:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> mb 0202341c
0202341c 43 c8 74 3a 00 00 00 00 00 00 00 00 00 00 00 00 C.t:............
0202342c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202343c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202344c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202345c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202346c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202347c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................[/css-div]
Nothing much to say, it's the same as the previous one. Another one skipped, and another one to check:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> mb 0202361c
0202361c 43 c8 74 3a 00 00 00 00 00 00 00 00 00 00 00 00 C.t:............
0202362c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202363c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202364c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202365c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202366c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0202367c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................[/css-div]
Once again, a zero-filled one. Next one:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> mb 02023c38
02023c38 43 c8 74 3a 10 00 07 00 07 00 08 00 07 00 07 00 C.t:............
02023c48 21 00 00 00 00 00 00 00 62 3a 61 3a 06 06 06 06 !.......b:a:....
02023c58 06 06 06 06 33 00 02 04 23 00 00 00 0f 00 03 46 ....3...#......F
02023c68 0f 00 00 00 ca c3 be c1 bf d3 ff be bf cc ff 00 ................
02023c78 bb bb bb bb bb bb bb ff 39 00 00 00 45 f2 c2 55 ........9...E..U
02023c88 00 00 00 00 00 00 00 00 43 c8 74 3a 00 00 00 00 ........C.t:....
02023c98 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................[/css-div]
Somehow interesting. It might be valid… but wait. Even if it's not all 0x00, the nickname is not valid anyway because there are some 0x00, which means the nickname would have some spaces in it. Clearly not a valid result. Well, let's see another one:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> mb 02023c90
02023c90 43 c8 74 3a 00 00 00 00 00 00 00 00 00 00 00 00 C.t:............
02023ca0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
02023cb0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
02023cc0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
02023cd0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
02023ce0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
02023cf0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................[/css-div]
Again, an invalid result. Are we out of luck or something? Hmm, my extra senses are tingling… the next result must be the good one:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> mb 02024030
02024030 43 c8 74 3a ca c3 be c1 bf d3 ff 03 fe 1f 02 02 C.t:............
02024040 bb bb bb bb bb bb bb 00 53 42 00 00 16 3a b6 6f ........SB...:.o
02024050 3f 3a b6 6f 06 7c b6 6f 06 5f b5 4d 64 00 d7 55 ?:.o.|.o._.Md..U
02024060 06 3a b6 6f 06 3a b6 6f 06 3a b6 6f 06 3a b6 6f .:.o.:.o.:.o.:.o
02024070 27 3a b6 6f 06 3a b6 6f 25 3a b6 6f 00 00 00 00 ':.o.:.o%:.o....
02024080 03 ff 0f 00 0f 00 07 00 07 00 08 00 07 00 07 00 ................
02024090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................[/css-div]
Note there's a FF in the nickname, so it stops there. The nickname is then CA C3 BE C1 BF D3, or PIDGEY. Gotcha! That seems to be the right result. But just in case, let's check the last ones too:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> mb 02024288
02024288 43 c8 74 3a bd c2 bb cc c7 bb c8 be bf cc 02 02 C.t:............
02024298 bb bb bb bb bb bb bb 00 31 07 00 00 19 4c 93 f2 ........1....L..
020242a8 13 4c be f2 30 64 be f2 13 4c bf f2 13 4c be f2 .L..0d...L...L..
020242b8 13 4c be f2 17 4c be f2 de 4c be f2 13 00 be f2 .L...L...L......
020242c8 13 14 bb d0 f7 a4 a2 dd 13 4c be f2 00 00 00 00 .........L......
020242d8 06 ff 14 00 14 00 0b 00 0b 00 0e 00 0e 00 0a 00 ................
020242e8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................[/css-div]
This might have been valid, if the nickname wasn't CHARMANDER. One more to go:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> mb 020245a2
020245a2 43 c8 74 3a 00 00 0c 09 28 00 01 00 00 00 00 00 C.t:....(.......
020245b2 da 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 ................
020245c2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
020245d2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
020245e2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
020245f2 00 00 48 80 00 00 00 00 00 00 00 00 00 00 00 00 ..H.............
02024602 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................[/css-div]
Is there anything to say? Not really, it's not valid. That confirms the address 0x02024030 is what we were looking for. Yay! However, it might be DMA-protected, meaning it could change each time. Type c and press Enter to continue the normal gameplay. Run away from the wild Pokémon, or just kill it. Now enter/exit a building. If the address was protected, that would be one thing that triggers the change. Press F11 and put a breakpoint (http://en.wikipedia.org/wiki/Breakpoint) on write at 0x02024030, for 4 bytes. This is the syntax:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]bpw {address} {size}[/css-div]
In our case, we would type bpw 02024030 4. Yeah, no hex prefix at all:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> bpw 02024030 4
Added break on write at 02024030 for 4 bytes[/css-div]
Type c and continue the game. Whenever the game will write anything in the range 0x02024030 - 0x02024034, the debugger will break. If the address changed all the time, it wouldn't break at all, because the game would write to different addresses all the times. So walk into the grass and see what happens. The game will break:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]Breakpoint (on write) address 02024030 old:43 new:00
R00=02024030 R04=0202402c R08=00000001 R12=00000001
R01=00000004 R05=02024220 R09=00000000 R13=03007d64
R02=0202402c R06=00000003 R10=00000000 R14=0803d99f
R03=00000000 R07=083c8e90 R11=00000000 R15=0803d98a
CPSR=0000003f (......T Mode: 1f)
0803d986 7003 strb r3, [r0, #0x0]
> 0803d988 3101 add r1, #0x1
0803d98a 294f cmp r1, #0x4f[/css-div]
This means the address is not protected, good news. Analyzing further the breakpoint data, we can see the first byte, 0x43, got overwritten by 0x00. After continuing, the game will break again:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]Breakpoint (on write) address 02024031 old:c8 new:00
R00=02024031 R04=0202402c R08=00000001 R12=00000001
R01=00000005 R05=02024220 R09=00000000 R13=03007d64
R02=0202402c R06=00000003 R10=00000000 R14=0803d99f
R03=00000000 R07=083c8e90 R11=00000000 R15=0803d98a
CPSR=0000003f (......T Mode: 1f)
0803d986 7003 strb r3, [r0, #0x0]
> 0803d988 3101 add r1, #0x1
0803d98a 294f cmp r1, #0x4f[/css-div]
In this case, the second byte got overwritten. In case you haven't guessed that, we're inside an erasing loop, used to clean the Pokémon data before a wild battle.

So, type c and continue till the bytes are replaced by the actual Trainer IDs, like in the example below:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]Breakpoint (on write) address 02024030 old:00000000 new:3a74c843
R00=3a000000 R04=03007cf8 R08=00000000 R12=00000008
R01=3a74c843 R05=00000000 R09=00000000 R13=03007cc0
R02=03007cf8 R06=00000000 R10=00000001 R14=0803db9d
R03=0202402c R07=0202402c R11=00000000 R15=080406dc
CPSR=0000003f (......T Mode: 1f)
080406d8 6079 str r1, [r7, #0x4]
> 080406da e1fe b $08040ada
080406dc 2200 mov r2, #0x0[/css-div]
Here we got inside the routine that wrote into memory the Trainer ID and Secret ID for the Pokémon. Type bpwc to clear the breakpoint. It's time to look into the routine further now. Being the current address 0x080406DA, we can try looking what's upwards by using the dt (disassemble THUMB) command. As a first estimation, let's go back by 0x20 bytes:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> dt 080406ba
080406ba 78e0 ldrb r0, [r4, #0x3]
080406bc 0600 lsl r0, r0, #0x18
080406be 1809 add r1, r1, r0
080406c0 6039 str r1, [r7, #0x0]
080406c2 e20a b $08040ada
080406c4 7821 ldrb r1, [r4, #0x0]
080406c6 7860 ldrb r0, [r4, #0x1]
080406c8 0200 lsl r0, r0, #0x08
080406ca 1809 add r1, r1, r0
080406cc 78a0 ldrb r0, [r4, #0x2]
080406ce 0400 lsl r0, r0, #0x10
080406d0 1809 add r1, r1, r0
080406d2 78e0 ldrb r0, [r4, #0x3]
080406d4 0600 lsl r0, r0, #0x18
080406d6 1809 add r1, r1, r0
080406d8 6079 str r1, [r7, #0x4]
080406da e1fe b $08040ada
080406dc 2200 mov r2, #0x0
080406de 1c3b add r3, r7, #0x0
080406e0 3308 add r3, #0x8[/css-div]
Starting from 0x080406DA and going back we can see many ldrb, lsl and add instructions. At some point, though, there's a branch, located at the address 0x080406C2. Since the branch will jump elsewhere, we can take for granted the routine part writing the Trainer IDs into RAM starts the instruction immediately after, 0x080406C4. Now we need to see where's the end. After those ldrb, lsl and add instructions, there's a str r1, [r7, #0x4], which is the instruction that triggered the breakpoint on write. Shortly after there's a branch. So the code we're interested in it's between 0x080406C4 and 0x080406DA. Even though we know all those instructions will end up writing the Trainer IDs somewhere, it would be interesting to know how it actually happens. We then start putting a THUMB breakpoint on the beginning address, using the bt command like shown below:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> bt 080406c4
Added THUMB breakpoint at 080406c4[/css-div]
Now continue the game and walk into the grass again. When a wild Pokémon is about to appear, the debugger will break:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]Breakpoint 0 reached
R00=080406c4 R04=03007cf8 R08=00000000 R12=00000008
R01=08040568 R05=00000000 R09=00000000 R13=03007cc0
R02=03007cf8 R06=00000000 R10=00000001 R14=0803db9d
R03=0202402c R07=0202402c R11=00000000 R15=080406c6
CPSR=0000003f (......T Mode: 1f)
08040560 4687 mov pc, r0
> 080406c4 7821 ldrb r1, [r4, #0x0]
080406c6 7860 ldrb r0, [r4, #0x1][/css-div]
The instruction at 0x080406C4 is what will be executed next. Type n to execute it:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]debugger> n
Continuing after breakpoint
R00=080406c4 R04=03007cf8 R08=00000000 R12=00000008
R01=00000043 R05=00000000 R09=00000000 R13=03007cc0
R02=03007cf8 R06=00000000 R10=00000001 R14=0803db9d
R03=0202402c R07=0202402c R11=00000000 R15=080406c8
CPSR=0000003f (......T Mode: 1f)
080406c4 7821 ldrb r1, [r4, #0x0]
> 080406c6 7860 ldrb r0, [r4, #0x1]
080406c8 0200 lsl r0, r0, #0x08[/css-div]
As you can see, a byte was loaded into R01, from the address stored in R04. That's the first byte of the Trainer IDs. Keep pressing n to execute the next instructions till the branch, watching carefully what happens each time. If you pay enough attention you will see the Trainer IDs are loaded byte by byte and put into R01, and finally stored in the memory location pointed by R07 + 4: 0x0202402C + 0x4 = 0x02024030. The following is the complete code:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]080406c4 7821 ldrb r1, [r4, #0x0]
080406c6 7860 ldrb r0, [r4, #0x1]
080406c8 0200 lsl r0, r0, #0x08
080406ca 1809 add r1, r1, r0
080406cc 78a0 ldrb r0, [r4, #0x2]
080406ce 0400 lsl r0, r0, #0x10
080406d0 1809 add r1, r1, r0
080406d2 78e0 ldrb r0, [r4, #0x3]
080406d4 0600 lsl r0, r0, #0x18
080406d6 1809 add r1, r1, r0
080406d8 6079 str r1, [r7, #0x4]
080406da e1fe b $08040ada[/css-div]
Considering we need to expand it to call our custom shiny handler, we need to replace some of the bytes and make it so the new instructions lead to the hacked routine, making the Pokémon shiny as needed. To call the shiny routine, we basically need 3 things: the address of the routine stored into some register, a bl instruction (branch with link) and a bx one (branch and exchange). It works like this: first of all we need to put the routine address into a register. Which register exactly depends on the other 2 instructions. While I said it in the first lesson already, it's good to remember that the address, pointing to a THUMB routine, must be odd or the game would treat it as an ARM routine instead, and guess what… it wouldn't work at all. The branch with link instruction is used to call a sub-routine and return to where it was called afterwards. The “link” in the name refers to the Link Register which is where the return address is stored. The bl instruction cannot use a direct address. Instead, it can point up to 16 MB forward or backward the address it is used in. This is a problem for us, and indeed we need to use the branch and exchange instruction. All the bx instruction need is a register containing the desired address. When a bx is executed, the address stored into the register is saved into the Program Counter (PC) and the game continue executing the instructions from there. The bx instruction is actually more powerful. Like its name suggests, it can exchange between ARM and THUMB mode. For our purposes, though, we don't need any exchanges and the address in the register will be a odd one. So, the routine address is loaded into a register, then the bl instruction is executed, with the branch pointing to the branch and exchange instruction. This way the routine is executed, and once it's finished, the instruction immediately after the branch with link will be executed. For this to work, the bx must not be near the branch with link. Most of the times, we don't really need to put a bx instruction ourselves, because there are many available already. So start disassembling the routine till you find a bx. It might take some time before you actually find one, depending on the routine's length. Sooner or later, you'll get one. The first we can get is located at 0x08040AFA:

[css-div="background-color: #000000; color: #C0C0C0; font-family: Lucida Console; width: 600px; padding: 10px 10px 10px 10px"]08040afa 4700 bx r0[/css-div]
As you can see, the register R0 is used. That means our routine address needs to be loaded into R0 if we want to use that branch.

The new code would therefore look something like this:

ldr r0, (=$routine address)
bl $bx address
add r1, r1, r0
ldrb r0, [r4, #0x2]
lsl r0, r0, #0x10
add r1, r1, r0
ldrb r0, [r4, #0x3]
lsl r0, r0, #0x18
add r1, r1, r0
str r1, [r7, #0x4]
b $08040ada

The previous instructions would be overwritten by the ldr and bl. Unlike all other THUMB instructions, bl is the only one that requires 4 bytes. The ldr instruction takes 2 bytes, but in this case it requires 4 additional bytes for the address. However, if you we just overwrite the old instructions, we would break the routine as some instructions would not be executed any more, obviously. Therefore we must take into account the overwritten instructions and execute them manually in the routine we call. We're lucky anyway. We don't need to execute the overwritten instructions at all, with a bit of optimizing. What about it? Well, as you know, the Trainer IDs are loaded one byte at a time. What if we were able to load them 2 bytes at a time, instead? We would save some space, and the extra space gained could be used to put our extra instructions needed to call the shiny routine. Sounds cool, eh? Don't forget we can't always be so lucky. Sometimes, even by optimizing, you don't gain enough space, and sometimes you can't optimize at all. And there's another important thing to note. I said we could load the Trainer IDs 2 byte at once, hence optimizing the old code. We need to be sure, however, that the optimized code works exactly as the old one. This time, everything's okay, as the Trainer IDs are always stored at half-word (16 bit) aligned address. Why is that bit of info important? The very reason is that the ldrh (load half-word) instruction needs to have a half-word aligned address to load the data properly. If for some reasons, the Trainer IDs were badly aligned, we couldn't use ldrh and therefore the optimizing would be gone. Let's analyze the first instructions:

ldrb r1, [r4, #0x0]
ldrb r0, [r4, #0x1]
lsl r0, r0, #0x08
add r1, r1, r0

The very first byte of the Trainer IDs is loaded into R1 from R4, with the first ldrb instruction. The instruction immediately after will load the second byte into R0. Then the value in R0 is shifted by 1 byte (8 bits) and finally both values are put together into R1.

Here's a brief info of what happens:

R1 = 000000T1
R0 = 000000T2
R0 = 0000T200
R1 = 0000T2T1

All those 4 instructions takes a total of 8 bytes. However, we can replace all those with a single ldrh instruction, getting the same result:

ldrh r1, [r4, #0x0]

which means

R1 = 0000T2T1

Not bad. Going from 8 bytes to 2 bytes, we've got 6 free bytes. More optimizing:

ldrb r0, [r4, #0x2]
lsl r0, r0, #0x10
add r1, r1, r0
ldrb r0, [r4, #0x3]
lsl r0, r0, #0x18
add r1, r1, r0

The first ldrb instruction will load into R0 the third byte of the Trainer IDs. The value into R0 is then shifted by 0x10 bits, and added to the current value stored into R1. Then the last byte of the Trainer IDs is loaded into R0, shifted by 0x18 bits this time and added to the R1 value:

R0 = 000000T3
R0 = 00T30000
R1 = 00T3T2T1
R0 = 000000T4
R0 = T4000000
R1 = T4T3T2T1

The instructions above takes 12 bytes but we only need 6 to do the same, thus saving 6 further bytes:

ldrh r0, [r4, #0x2]
lsl r0, r0, #0x10
add r1, r1, r0

so

R0 = 0000T4T3
R0 = T4T30000
R1 = T4T3T2T1

We've got a total of 12 free bytes, which is the exact number of bytes (did I say "lucky"?) we will need. Let's see the new, patched routine:

080406c4 8821 ldrh r1, [r4, #0x0]
080406c6 8860 ldrh r0, [r4, #0x2]
080406c8 0400 lsl r0, r0, #0x10
080406ca 1809 add r1, r1, r0
080406cc 4801 ldr r0, [$080406d4] (=$XXXXXXXX)
080406ce f000 bl $08040afa
080406d2 e001 b $080406d8
080406d4 XXXX
080406d6 XXXX
080406d8 6079 str r1, [r7, #0x4]
080406da e1fe b $08040ada

That means the existing bytes at the offset 0x406C4 need to be replaced with the following ones:

21 88 60 88 00 04 09 18 01 48 00 F0 14 FA 01 E0 XX XX XX XX 79 60 FE E1

where XX XX XX XX represents the shiny routine pointer. For now, don't ask how did I get those values: just take them for granted. If you looked carefully you probably noticed there's an unconditional branch after the branch with link. That's used to skip the routine address stored after, as it's not meant to be treated as some kind of instructions. Now that we can call our custom routine, we need the actual routine. Before showing you the code, I'd like to explain the basic concepts it relies on. As soon as the routine is executed, there's a first safety check to ensure the shiny hack routine is not executed when it shouldn't. Then the shiny counter is checked. If the value is equal to zero, then the routine ends because there's nothing to do. If the value is higher than zero, then it's subtracted by 1 and updated. Now there are two possibilities: the Pokémon that needs to be shiny might or might not be a trainer's one. In the latter case, the Trainer IDs are replaced by the Pokémon ID, hence making the Pokémon shiny. I chose to do this way in order to let the trainers' Pokémon keep the same nature, gender, etc. they would have if they were not shiny. If the Pokémon comes from the wild, of was give us from a NPC, things are different.

First we get a random number between 0 and 7. Then we get another 16-bit random number and we double it to a full word. The resulting word is XORed with the previous random number, and then XORed again with the Trainer IDs:

N1 = 0000000X, X = 0-7
N2 = 0000YYZZ
N3 = YYZZYYZZ
N3 = N3 XOR N1
N3 = N3 XOR Trainer IDs

This way we get a Pokémon ID that would make the Pokémon shiny. However, considering the PID would be usually determined in a whole different way, we must check if the Pokémon ID we got is a valid one. Valid means the Pokémon ID must meet an important requirement: the value has to be like it was generated by the game's PRNG. If the generated Pokémon ID is not valid, then a new one is generated till we get a proper one. There's a tight relationship between the Pokémon ID and the IVs, and since we're manually hacking the Pokémon ID after being generated we must handle the situation accordingly. While checking the PID validity, if we get a good value we also get the seed that, if put through the PRNG formula, would generate the 16 high bits of our PID. In order to generate matching IVs, the current seed must be replaced (remember each time a random number is generated, a new seed is generated too) with the seed we got from the validity check. This way, once the game needs to generate the IVs, it will outputs the right values as it would normally do.

[css-div="width: 240px; padding: 10px 10px 10px 10px; border: dotted 1px dimgray; background-color: #FFFFFF;"]http://i37.tinypic.com/23jlwki.png

Yay! It works.[/css-div]
.text
.align 2
.thumb
.thumb_func
.global shiny_hackv3

main:
lsr r0, r4, #0x18
cmp r0, #0x3
bne return
ldr r0, .SHINY_COUNTER
ldrb r0, [r0]
cmp r0, #0x0
bne shiny_hack

return:
bx lr

shiny_hack:
push {r2-r5, lr}
sub r3, r0, #0x1
ldr r0, .SHINY_COUNTER
strb r3, [r0]
ldrb r4, [r0, #0x1]
cmp r4, #0x0
bne is_trainer
add r4, r1, #0x0

no_trainer:
ldr r2, .RANDOM
bl branch_r2
mov r3, #0x7
and r0, r3
add r3, r0, #0x0
ldr r2, .RANDOM
bl branch_r2
lsl r5, r0, #0x10
orr r5, r0
eor r5, r3
eor r5, r4
push {r4-r6}
lsr r1, r5, #0x10
lsl r0, r5, #0x10
mvn r3, r3
lsr r3, r3, #0x10
ldr r4, .RND_MULTIPLIER
ldr r5, .RND_INCREMENT

rnd_loop:
add r6, r0, #0x0
mul r6, r4
add r6, r5
lsr r2, r6, #0x10
cmp r2, r1
beq rnd_end
add r0, #0x1
sub r3, #0x1
cmp r3, #0x0
bne rnd_loop
b not_found

rnd_end:
ldr r2, .RND_ADDRESS
str r6, [r2]
pop {r1, r5-r6}
str r5, [r7]

shiny_ret:
pop {r2-r5, pc}

not_found:
pop {r4-r6}
b no_trainer

is_trainer:
mov r5, #0x1
lsl r5, r3
and r4, r5
cmp r4, #0x0
beq trainer_ret
ldr r1, [r7]

trainer_ret:
b shiny_ret

branch_r2:
bx r2

.align 2
.RND_MULTIPLIER:
.word 0x41C64E6D
.RND_INCREMENT:
.word 0x00006073
.RND_ADDRESS:
.word 0x03005000
.SHINY_COUNTER:
.word 0x020270B8 + (0x8003 * 2)
.RANDOM:
.word 0x08044EC8|1

References
- Pokémon IVs (http://bulbapedia.bulbagarden.net/wiki/IV)
- The Process of PID and IV Creation of Non-Bred Pokemon (http://www.smogon.com/dp/articles/pid_iv_creation)
- Guide PID-IV (http://projectpokemon.org/editingresearch/guidepidiv.php)
- Personality Value (http://bulbapedia.bulbagarden.net/wiki/Personality_value)

Challenge time
Are you up for an ASM challenge? Then find a way to conver the instruction "lsl r1, r2, #0x3" into hex.

Here's the solution to the previous challenge. It's the FireRed version, and only the actual code. Even if it's the FireRed version, however, the solution is the similar for any game:
[code]main:
push {r0-r1, lr}
ldr r0, .PLAYER_DATA
ldr r0, [r0]
ldr r1, .VAR
ldrh r0, [r0, #0xA]
strh r0, [r1]
ldr r0, .PLAYER_DATA
ldr r0, [r0]
ldrh r0, [r0, #0xC]
strh r0, [r1, #0x2]
pop {r0-r1, pc}[code]

This tutorial is Copyright © 2009 by HackMew.
You are not allowed to copy, modify or distribute it without permission.

Wow. This is awesome. This should fill us all with ASM knowledge. Thanks so much. :D

cooley
October 10th, 2009, 08:00 PM
So I'd have to agree with you Pokepal. HackMew is the only main reason why I will always hack GBA. He's very helpful to everyone :D

colcolstyles
October 17th, 2009, 04:35 PM
Just look at that thing!
I'm going to have to try and tackle this at another time when I can go through it slowly and thoroughly. I'll bet you put a hell of a lot of effort into that. Excellent work!

HackMew
October 25th, 2009, 08:13 AM
Thank you all for the nice comments. It's good to see at least some people do appreciate my efforts. BTW, thethethethe reported me a little error I made in the tut, basically the branch with link range being limited to 4 MB rather than 16 MB as I originally wrote. It was no way critical for the scope of the ASM lesson, but it was an error nonetheless.

lilJburroughs
February 5th, 2010, 04:57 PM
I read most of the tutorial... and my head is spinning.

I didn't follow through and insert the (script? non-script?) "code" into the rom, as I was just trying to understand how the code works, so I could learn how to apply it to what I need to use it for, but I can't seem to really grasp any of that. Which is disappointing, as I caught on to scripting very quickly.

It's a very thorough tutuorial, and it teaches you how to use ASM, but it seems like it only teaches a very specific application of it. Maybe I'm missing something?

Darkerm
February 12th, 2010, 09:48 AM
Like Dimond and Pearl Eevee can evolbe in Ice and Grass by level up in a place of route. I want to ask you that if it is possible to evolbe Eevee into any type By thalkin to any person who will evolbe Eevee into any 7 type I want.

HackMew
February 12th, 2010, 10:11 AM
I read most of the tutorial... and my head is spinning.

I didn't follow through and insert the (script? non-script?) "code" into the rom, as I was just trying to understand how the code works, so I could learn how to apply it to what I need to use it for, but I can't seem to really grasp any of that. Which is disappointing, as I caught on to scripting very quickly.

It's a very thorough tutuorial, and it teaches you how to use ASM, but it seems like it only teaches a very specific application of it. Maybe I'm missing something?

It does teach a very specific application, but that's just a working example. You should focus on the ASM routine itself, and see how the things are done. Re-read the tut if needed. And don't forget to use the debugger.


Like Dimond and Pearl Eevee can evolbe in Ice and Grass by level up in a place of route. I want to ask you that if it is possible to evolbe Eevee into any type By thalkin to any person who will evolbe Eevee into any 7 type I want.

Yes, you could. But you should be quite ASM skilled to do something similar. Also, this whole thread is about the Advance generation, and there are only 5 Eevee evolutions.

altariaking
February 16th, 2010, 11:48 AM
good tutorial, but where do i download vba-sdl-h

colcolstyles
February 16th, 2010, 07:02 PM
Let's debug
The routine we used was (relatively) simple, but as soon as the routines grow and get more and more complicated, you can't just rely on simply using a callasm to see if they work or not. Especially in the latter case. That's when a debugger comes in handy. So if you didn't download it yet, this is the right moment to do it: VBA-SDL-H.zip (http://www.pokecommunity.com/attachment.php?attachmentid=51237&d=1259264753).

There it is.

HackMew, can I suggest that you post the links to some of the more important resources for your tutorials (e.g., VBA-SDL-H, the assembler, and the "lesson1" .asm files) somewhere more easily accessible than in the midst of the tutorial? It's annoying to have to look through the entire document just to find one particular link and I'm sure that doing so will reduce the amount of posts asking where things are.

HackMew
February 25th, 2010, 08:57 AM
There it is.

HackMew, can I suggest that you post the links to some of the more important resources for your tutorials (e.g., VBA-SDL-H, the assembler, and the "lesson1" .asm files) somewhere more easily accessible than in the midst of the tutorial? It's annoying to have to look through the entire document just to find one particular link and I'm sure that doing so will reduce the amount of posts asking where things are.

Will sure do. Thanks for your suggestion.

Umbreonic Aura
March 3rd, 2010, 09:22 AM
Hackmew I worship you O.o
You are the best hacker ever!
Your A-ptch is better than LIPS from personal experience.

Zeffy
April 2nd, 2010, 05:05 AM
Ok, I follow everything on the tutorial but whenever I try to locate my Desktop like this:


C>Documents and Settings\Name\Desktop

It says:


'DOCUMENTS' is not recognized as an internal or external command, operable program or batch file.

I don't get it. HELP!

xGGxToiZ
April 2nd, 2010, 05:19 AM
It's recovery time!
So we got a screwed up ROM... Let's fix it.1. Take your screwed up ROM and a clean one. Just for exteme safety, do a backup of the ruined ROM.
2. Now repeat the last change you did on the clean ROM you took.
In my case I would re-insert Charmeleon over Charmander on the clean ROM, with "Auto abort" off. In your case this action will depend on what you did earlier.
3. Then open A-Ptch or whatever patcher you fancy. As the original, unmodified ROM take the modified clean ROM. As the new modified ROM take the screwed up ROM.
4. Create the patch.
5. Now take another clean ROM and apply the patch you just created to it.If you did everything correctly, the ROM will be fully recovered now.


OMFG! That was amazing . .

My ROM was screwed because of music editing then I saw this thread and followed it and what do you know, it really FIXED it! (This prevented me from doing additional 5 hours of repairing xD)

" I thought that was it."

Thanks a lot!
You're really the best . . (and no, no flattery)

Full Metal
April 2nd, 2010, 05:58 AM
Ok, I follow everything on the tutorial but whenever I try to locate my Desktop like this:


C>Documents and Settings\Name\Desktop

It says:


'DOCUMENTS' is not recognized as an internal or external command, operable program or batch file.

I don't get it. HELP!
try using quotes *character count*

Zeffy
April 2nd, 2010, 06:25 PM
try using quotes *character count*
Umm, could you give an example I don't quite get it.

ShinyBill
April 3rd, 2010, 04:34 PM
OMFG! That was amazing . .

My ROM was screwed because of music editing then I saw this thread and followed it and what do you know, it really FIXED it! (This prevented me from doing additional 5 hours of repairing xD)

" I thought that was it."

Thanks a lot!
You're really the best . . (and no, no flattery)



Can you help me? I didn't managed to do it. I wanted to delete 2 maps from the same bank so I did a way I found in a tut. On Map Header I put -2. Then I inserted a blank map and those 2 were gone. But then every map with bank 3 didn't open. It said 'Access violation at address 004CCB2A in module 'AdvanceMap.exe'. Read of address 22222222'. I followed the instructions for rescuing but it did not work! It said the file was invalid to patch! Please, help me.

altariaking
April 5th, 2010, 08:37 AM
i'm having trouble at the very beggining with the command prompt...
after i type everything in it says-
C>CUsers\marc\Desktop>
but it still won't work...

Zeffy
April 8th, 2010, 02:41 AM
i'm having trouble at the very beggining with the command prompt...
after i type everything in it says-
C>CUsers\marc\Desktop>
but it still won't work...
I've had that problem too. Maybe you're using the wrong command prompt.

What OS are you using?

If XP go to Start Menu, then select Run and type in cmd. If you typed in command prompt, it won't work.

If Vista, go to Start Menu, then type cmd.

If other OS, then I don't know.

I have a problem now, everytime I insert an ASM file, it screws up my ROM. I'm sure I'm using a clean ROM, I've tried different ROMs now but it still screws up.

Full Metal
April 8th, 2010, 04:27 AM
Umm, could you give an example I don't quite get it.

command prompt works like thish (in a laymans' nutshell)
programfilename program-argument <mawr program arguments>
If your current directory is
"C:\"
and you enter "job.exe"
cmd concatenates the two onto eachother, and you get "C:\job.exe", which is then executed
now if you typed
"job.exe C:\program files"
that would not work because the argument gets split into...
"C:\program" and "files"
to solve this, put it in quotes

Shiny Quagsire
April 8th, 2010, 05:36 AM
also, if your using xp, you would go: cd "C:\Documents and Settings\NAME HERE\Desktop\ASM". the cd stands for change directory.

altariaking
April 8th, 2010, 07:12 AM
thanks zeffy, works now. my SID is 0. i think i made a mistake somewhere...

Zeffy
April 9th, 2010, 01:30 AM
command prompt works like thish (in a laymans' nutshell)
programfilename program-argument <mawr program arguments>
If your current directory is
"C:\"
and you enter "job.exe"
cmd concatenates the two onto eachother, and you get "C:\job.exe", which is then executed
now if you typed
"job.exe C:\program files"
that would not work because the argument gets split into...
"C:\program" and "files"
to solve this, put it in quotes
I already solved that problem, thanks anyways. But, your post is full of smileys. :/

third93
April 11th, 2010, 01:36 AM
ehm hackmew i can translate your tutorial in italian???

altariaking
April 11th, 2010, 02:13 AM
hackmew is italian...
if he needs it translated he should be able to do itself...

third93
April 11th, 2010, 04:08 AM
yes,but i don't see this tutorial in italian and i ask him^^

Full Metal
April 11th, 2010, 09:33 AM
I already solved that problem, thanks anyways. But, your post is full of smileys. :/

sorry 'bout that, C:\ is equal to C: \ only without smileys (i forgot to disable them)

JoshuRAWRR
May 12th, 2010, 11:20 AM
hey, i just started pokehacking...and im very low on scripts :'(
but hackmew this helped alot

ERROR
May 26th, 2010, 07:24 AM
i have question about compiling
i understand how it was done and all but how was it compiled into the rom? i dont see where that happened :(

and also concerning palettes if i was making a titlescreen would it be possible to repoint the palettes to a different offset wouldnt that make it easier for using images that used 32 palettes or more?

Penguins
June 26th, 2010, 11:15 AM
Cool you are the best Hack Mew I love using your tools they are just so convenient. Good job. Just keep on hacking.

Samike360
July 2nd, 2010, 09:09 PM
I have a problem...I've been doing the ASM tutorial but whenever I start the debugger and the Rom, it always gives me an error and shuts out of the rom with an error report. It says "VBA-over.ini not found" on the command prompt.

X-Buster
July 2nd, 2010, 09:21 PM
I have a problem...I've been doing the ASM tutorial but whenever I start the debugger and the Rom, it always gives me an error and shuts out of the rom with an error report. It says "VBA-over.ini not found" on the command prompt.
if you have the ordinary VBA, copy it's .ini file and paste the same directory as the debugger.

Samike360
July 2nd, 2010, 09:25 PM
if you have the ordinary VBA, copy it's .ini file and paste the same directory as the debugger.

Hmm...how would I do that excatly? And what's the ordinary VBA?

X-Buster
July 10th, 2010, 03:59 PM
Hmm...how would I do that excatly? And what's the ordinary VBA?
here's a default ini file for the debugger, just save it the same directory as your debugger.

FlameShocker
July 28th, 2010, 09:03 AM
I was wondering, is the
.VAR:
.word 0x020270B6 + (0x800D * 2)in the ASM code in lesson 1 for the buffer part of the script? I don't know since I'm still new to assembly and scripting. The main reason I'm asking is because I'd like to know how I can modify the .word portion. Additionally, what is the
+ (0x800D * 2)for?

Edit: One thing I forgot to mention: I'm hacking Fire Red.

I found out that 0x800D is the buffer (yay, scripting tutorials), but what's the times 2 thing for?

Also, what does address 0x020270B6 do (in Fire Red)?

colcolstyles
July 28th, 2010, 10:53 AM
I was wondering, is the
.VAR:
.word 0x020270B6 + (0x800D * 2)in the ASM code in lesson 1 for the buffer part of the script? I don't know since I'm still new to assembly and scripting. The main reason I'm asking is because I'd like to know how I can modify the .word portion. Additionally, what is the
+ (0x800D * 2)for?

Edit: One thing I forgot to mention: I'm hacking Fire Red.

I found out that 0x800D is the buffer (yay, scripting tutorials), but what's the times 2 thing for?

Also, what does address 0x020270B6 do (in Fire Red)?

That is the address of the variable '0x800D' (more commonly known as 'LASTRESULT') in the WRAM. The reason that "+ (0x800D * 2)" is appended to the main '0x020270B6' part is that if you multiply 0x800D by 2 and then add it to the main part, you get '0x020370D0' which is the actual address of '0x800D'. HackMew formatted it that way for convenience. If you wanted to use variable '0x8004' instead, all you have to do is change '0x800D' to '0x8004'. Otherwise, you'd have to calculate what address '0x8004' is at and that's just no fun.

FlameShocker
July 28th, 2010, 04:55 PM
Okay, thanks. That cleared things up for me.

professional
July 30th, 2010, 12:31 AM
the only tut that I understand
P.S you make ASM look easy

IntrOutro
July 30th, 2010, 10:23 PM
Hi, how exactly the extended script looks like regarding to the Trainer ID + Secret ID in the 1st ASM Lesson? I just manage to get the Trainer ID to show up but not the Secret ID.

I'll just recopy the script part from the 1st Lesson so anyone of you don't have to look back:
#dynamic 0x800000

#org @start
callasm YourOffset
buffernumber 0x0 LASTRESULT
msgbox @secret 0x2
end

#org @secret
= Sshh! I'll tell you a secret[.]\nYour Secret ID is [buffer1]!

and the ASM that I'm based on (Emerald):
.text
.align 2
.thumb
.thumb_func
.global lesson1

main:
push {r0-r1, lr}
ldr r0, .PLAYER_DATA
ldr r0, [r0]
ldr r1, .VAR
ldrh r0, [r0, #0xA]
strh r0, [r1]
ldr r0, .PLAYER_DATA
ldr r0, [r0]
ldrh r0, [r0, #0xC]
strh r0, [r1, #0x2]
pop {r0-r1, pc}


.align 2
.PLAYER_DATA:
.word 0x03005D90
.VAR:
.word 0x020275D6 + (0x800D * 2)

And, do you set the [buffer1] twice in the strings area or split it to something like [buffer1] and [buffer2]?

I really like to know how it's done because the extended script isn't covered in any of the tutorials (only the crucial asm part was covered in the end of 2nd ASM Lesson).

colcolstyles
July 31st, 2010, 11:10 AM
Hi, how exactly the extended script looks like regarding to the Trainer ID + Secret ID in the 1st ASM Lesson? I just manage to get the Trainer ID to show up but not the Secret ID.

I'll just recopy the script part from the 1st Lesson so anyone of you don't have to look back:
#dynamic 0x800000

#org @start
callasm YourOffset
buffernumber 0x0 LASTRESULT
msgbox @secret 0x2
end

#org @secret
= Sshh! I'll tell you a secret[.]\nYour Secret ID is [buffer1]!

and the ASM that I'm based on (Emerald):
.text
.align 2
.thumb
.thumb_func
.global lesson1

main:
push {r0-r1, lr}
ldr r0, .PLAYER_DATA
ldr r0, [r0]
ldr r1, .VAR
ldrh r0, [r0, #0xA]
strh r0, [r1]
ldr r0, .PLAYER_DATA
ldr r0, [r0]
ldrh r0, [r0, #0xC]
strh r0, [r1, #0x2]
pop {r0-r1, pc}


.align 2
.PLAYER_DATA:
.word 0x03005D90
.VAR:
.word 0x020275D6 + (0x800D * 2)

And, do you set the [buffer1] twice in the strings area or split it to something like [buffer1] and [buffer2]?

I really like to know how it's done because the extended script isn't covered in any of the tutorials (only the crucial asm part was covered in the end of 2nd ASM Lesson).

The ASM looks fine as far as I can tell. Here's how I would do the script:
#dynamic 0x800000

#org @start
callasm YourOffset
buffernumber 0x0 0x800D
buffernumber 0x1 0x800E
msgbox @secret 0x2
end

#org @secret
= Sshh! I'll tell you a secret[.]\nYour Secret ID is [buffer1]! Also, your Trainer ID is [buffer2].

So, yes, you would use 'buffer2'. Just remember that you have to buffer the second number and use '0x01' as the first parameter. It's a little counterintuitive because the number stored in 'buffer 0x0' is accessed via 'buffer1' and the number stored in 'buffer 0x1' is accessed via 'buffer2' but you'll get the hang of it. Also note that since you stored the second number at 'r0 + #0x02', the number would be contained in the variable after LASTRESULT (0x800D), i.e., 0x800E.

IntrOutro
July 31st, 2010, 12:26 PM
Thank you!

Once, I thought I had to make some comparative function. The closest thing I did was:


#dynamic 0x800000

#org @start
callasm YourOffset
buffernumber 0x0 LASTRESULT
buffernumber 0x1 LASTRESULT
msgbox @secret 0x2
end

#org @secret
= [buffer1] and [buffer2].


All this while, I thought that the LASTRESULT (0x800D) was the only carrier for an output/result, lol. I should be more careful in reading any scripts/tutorials after this.

So, yes, you would use 'buffer2'. Just remember that you have to buffer the second number and use '0x01' as the first parameter. It's a little counterintuitive because the number stored in 'buffer 0x0' is accessed via 'buffer1' and the number stored in 'buffer 0x1' is accessed via 'buffer2' but you'll get the hang of it. Also note that since you stored the second number at 'r0 + #0x02', the number would be contained in the variable after LASTRESULT (0x800D), i.e., 0x800E.

Thank you again for the reminder, the actual 2nd call is at 0x800F.

ger345
August 1st, 2010, 01:34 PM
Wow, you know alot about hacking pokemon games!

EdensElite
June 25th, 2011, 01:26 PM
This has cleared a few things up for me thanks ^.^, But just a question, do you actually need ASM to script, or can I just never go near ASM and just use XSE to compile scripts without it?

Shiny Quagsire
June 25th, 2011, 05:19 PM
This has cleared a few things up for me thanks ^.^, But just a question, do you actually need ASM to script, or can I just never go near ASM and just use XSE to compile scripts without it?

ASM and scripting are two different things. ASM is actual coding that the game uses to manage data. Scripting is string of commands used for events. While scripting can call ASM, ASM isn't needed to script.

Forestpelt
July 5th, 2011, 05:08 PM
Hello, is there a way to change the names of the main Pokemon natures? For example instead of GENTLE, I could rename it SILLY, while keeping the same effects that GENTLE would in the game. I'm using Emerald version, by the way. Thanks!

Team Fail
July 5th, 2011, 05:13 PM
Hello, is there a way to change the names of the main Pokemon natures? For example instead of GENTLE, I could rename it SILLY, while keeping the same effects that GENTLE would in the game. I'm using Emerald version, by the way. Thanks!

You can use a Hex Editor with a GBA .tbl file, or you can use A-Text (I cannot remember if there is a better alternative.)

Forestpelt
July 6th, 2011, 10:34 AM
Thanks, I only have one more question. I can get my scripts to work, but only if I start a completely new file! How do I fix this? I want to be able to load my old file and see the changes I made. Oh and when I load my save-states, I can't go through any doors.

Cherrysa23
August 2nd, 2011, 07:31 PM
please, I really can't see what I'm doing wrong

when I open the rom, it's just a white screen, the rom doesn't start...

that fine, I was missing the vba-over.ini file

so if soemone else has the error, that solve the problems

jvpski3
August 11th, 2011, 09:07 AM
Just wondering.... Can you do a tutorial on other than BRPEE???

mihir
August 16th, 2011, 05:45 AM
I might look like an idiot, but.... I need an advancemap tutorial.Its simple,but I'm simpler.And the tools are really good!

erusanma
October 31st, 2011, 11:48 PM
I have a question about your debbuger,because the command prompt dysplays this message:

..............
Unknown file type pokemon.

Also,when trying to open a fire red rom,only a white image is displayed in the emulator.

But apart from all this all your tools are exellent,specially xse because I really like scripting in an easy way(not like pokescript or scripted).

Sorry for any mistake I commit but English is not my native language.

NintendoBoyDX
April 7th, 2012, 06:42 PM
This is way more complicated than it needs to be... 080440F4 is the shiny decision routine. Go to 0804411E and replace it with 00 20. This is the spot that it checks whether the value is greater or less than 7. Replacing that will make the value always 00 right before the check, and that means all pokemon will be shiny. Much easier to replace 2 bytes.

just throwin that out there

YouListeningROMs
April 10th, 2012, 05:56 PM
With ASM, how would you do modulo?

NintendoBoyDX
April 10th, 2012, 10:39 PM
With ASM, how would you do modulo?
There are a couple of ways in fr. There is software interrupt 0x6, which is a bios function call that does division and modulo. There is routine 081E4018 developed by gamefreak, that does division and modulo as well.

R0 = dividend
R1 = divisor

returning
R0 = quotient
R1 = modulo answer

081E4684 is another routine made by gamefreak that does modulo only.

A few other math routines:
081E460C: another division routine
081E3B9C: square root, calls swi 0x8

I've stumbled across a few others that I dont remember..

YouListeningROMs
April 11th, 2012, 03:57 AM
There are a couple of ways in fr. There is software interrupt 0x6, which is a bios function call that does division and modulo. There is routine 081E4018 developed by gamefreak, that does division and modulo as well.

R0 = dividend
R1 = divisor

returning
R0 = quotient
R1 = modulo answer

081E4684 is another routine made by gamefreak that does modulo only.

A few other math routines:
081E460C: another division routine
081E3B9C: square root, calls swi 0x8

I've stumbled across a few others that I dont remember..

Thank you for your assistance.

truekidmoney
November 13th, 2012, 08:07 AM
Hey guys i have a question how do i get the results lesson1.bin this:
03 B5 03 48 00 68 03 49 80 89 08 80 03 BD C0 46
0C 50 00 03 D0 70 03 02
into my rom?

hashtag
November 13th, 2012, 08:13 AM
Use a Hex Editor and insert the bytes into free space ending with a 0, 4, 8 or C.

CallarinCreator
November 30th, 2012, 07:55 AM
kan u post something on xse? it aint wantin to work for me. it will work. but it shuts down after like a second.

Deokishisu
November 30th, 2012, 09:27 AM
kan u post something on xse? it aint wantin to work for me. it will work. but it shuts down after like a second.

O poor English, struck down in its prime.

Anyway, this is because of the auto update feature. Since Hackmew's site is down, it tries to update, fails, and closes. To fix it, go into your .ini file and change it so that the AutoUpdateCheck equals zero.

So that line should look like this:
AutoUpdateCheck=0

GoGoJJTech
January 30th, 2013, 04:52 PM
These are extremely helpful ( and long ) well great job hackmew

Chaos Rush
February 3rd, 2013, 12:37 AM
I decided to take a crack at HackMew's ASM challenge, and I succeeded!
http://i50.tinypic.com/efews8.png http://i45.tinypic.com/16ld1g2.png

This is what I modified the routine to:
.text
.align 2
.thumb
.thumb_func
.global lesson1

main:
push {r0-r1, lr}
ldr r0, .PLAYER_DATA
ldr r0, [r0]
ldr r1, .VAR
ldrh r0, [r0, #0xC]
strh r0, [r1]
ldr r0, .PLAYER_DATA
ldr r0, [r0]
ldr r1, .NEXT
ldrh r0, [r0, #0xA]
strh r0, [r1]
pop {r0-r1, pc}


.align 2
.PLAYER_DATA:
.word 0x0300500C
.VAR:
.word 0x020270B6 + (0x800D * 2)
.NEXT:
.word 0x020270B8 + (0x8000 * 2)

And the XSE script:
#dynamic 0x800000
#org @main
callasm YourASMoffset
buffernumber 0x0 LASTRESULT
buffernumber 0x1 0x8000
msgbox @msg MSG_FACE
end


#org @msg
= Your Trainer ID is [buffer2].\nYour Secret ID is [buffer1].

Going to do my best to get ASM down...

FBI agent
February 3rd, 2013, 06:46 AM
I decided to take a crack at HackMew's ASM challenge, and I succeeded!
http://i50.tinypic.com/efews8.png http://i45.tinypic.com/16ld1g2.png

This is what I modified the routine to:
.text
.align 2
.thumb
.thumb_func
.global lesson1

main:
push {r0-r1, lr}
ldr r0, .PLAYER_DATA
ldr r0, [r0]
ldr r1, .VAR
ldrh r0, [r0, #0xC]
strh r0, [r1]
ldr r0, .PLAYER_DATA
ldr r0, [r0]
ldr r1, .NEXT
ldrh r0, [r0, #0xA]
strh r0, [r1]
pop {r0-r1, pc}


.align 2
.PLAYER_DATA:
.word 0x0300500C
.VAR:
.word 0x020270B6 + (0x800D * 2)
.NEXT:
.word 0x020270B8 + (0x8000 * 2)

And the XSE script:
#dynamic 0x800000
#org @main
callasm YourASMoffset
buffernumber 0x0 LASTRESULT
buffernumber 0x1 0x8000
msgbox @msg MSG_FACE
end


#org @msg
= Your Trainer ID is [buffer2].\nYour Secret ID is [buffer1].

Going to do my best to get ASM down...

Spoiler tags, pls!
Also, you don't need to load player data twice.
It should till work without doing this the second time:
ldr r0, .PLAYER_DATA
ldr r0, [r0]

EDIT: I lied, the way you did it, you did need to load it twice (or subtract :D).

karatekid552
February 9th, 2013, 08:22 PM
Almost all of the reference links for the ASM tutorial are broken. I have found a few of them, would it be alright for me to post them here? Or should I pm them to DrFuji/giradalkia to add to the end of the tut?

Edit: only two are broken.... Wow, I remember that being a lot more last time....

Edit2: I guess since no one has objected it is fine for me to post the links here:


Assembly Wikipedia: (So easy to find it really wasn't broken, but whatever) http://en.wikipedia.org/wiki/Assembly_language

ARM7DTMI Technical Manuel: http://infocenter.arm.com/help/topic/com.arm.doc.ddi0210c/DDI0210B.pdf

Tonic: Whirlwind Tour of ARM Assembly: http://www.coranac.com/tonc/text/asm.htm

Hope these help anyone who wants to learn ASM.

Kurapika
May 17th, 2013, 10:12 AM
Since I see people asking questions here, I have a problem using ldr with cmp. I am making a code that compares two words, one located in the RAM and the other located in the ROM. so what I do: ldr r1, .word1 ldr r1, [r1] ldr r2, .word2 ldr r2, [r2] cmp r1, r2 beq YayTheyEqualz ... The problem is, the jump never occurs even when the words are equal... So I tried this: ldr r1, .word1 ldrh r1, [r1] ldr r2, .word2 ldrh r2, [r2] cmp r1, r2 beq SecondHalf ... SecondHalf: ldr r1, .word1 ldr r1, [r1, #0x2] ldr r2, .word2 ldrh r2, [r2, #0x2] cmp r1, r2 beq YayTheyEqualz ... And this 2nd code works correctly but takes more space and it is more complicated. So, I'm wondering if ldr and/or cmr commands have some particular behaviour that makes the first code not working??? Or am I just doing something wrong?

karatekid552
May 17th, 2013, 03:30 PM
Since I see people asking questions here, I have a problem using ldr with cmp. I am making a code that compares two words, one located in the RAM and the other located in the ROM. so what I do: ldr r1, .word1 ldr r1, [r1] ldr r2, .word2 ldr r2, [r2] cmp r1, r2 beq YayTheyEqualz ... The problem is, the jump never occurs even when the words are equal... So I tried this: ldr r1, .word1 ldrh r1, [r1] ldr r2, .word2 ldrh r2, [r2] cmp r1, r2 beq SecondHalf ... SecondHalf: ldr r1, .word1 ldr r1, [r1, #0x2] ldr r2, .word2 ldrh r2, [r2, #0x2] cmp r1, r2 beq YayTheyEqualz ... And this 2nd code works correctly but takes more space and it is more complicated. So, I'm wondering if ldr and/or cmr commands have some particular behaviour that makes the first code not working??? Or am I just doing something wrong?

Would you mind giving us all of the ASM in the regular format? It is really tough the read this way.

Kurapika
May 17th, 2013, 04:31 PM
code 1: http://pastebin.com/raw.php?i=yJicZbCv code 2: http://pastebin.com/raw.php?i=XaKjiPPY The first one doesn't jump to TheyAreEqualz even when it should, the second code works perfectly for me. (Sorry, for some reason, line skips are removed from my posts ;_; I think it's just my ****** Internet -.-')

karatekid552
May 17th, 2013, 06:00 PM
code 1: http://pastebin.com/raw.php?i=yJicZbCv code 2: http://pastebin.com/raw.php?i=XaKjiPPY The first one doesn't jump to TheyAreEqualz even when it should, the second code works perfectly for me. (Sorry, for some reason, line skips are removed from my posts ;_; I think it's just my ****** Internet -.-')

From looking at your code, both routines are loading different things. Parts are loading words and others are loading half-words and neither lines up with the other routine. That is probably where your problem lies. A word is 4 bytes and a half-word is 2 bytes. Take that as you wish.

Kurapika
October 4th, 2013, 08:38 AM
.word 0x020270B6 + (0x800D * 2)
Assigns the word (32 bits) 0x020270B6 + (0x800D * 2) = 0x020370D0 to .VAR. If you're wondering about the "weird" format, I made that to make it easier changing the variable used. Note however this would work only for temporary variables, 0x800D onwards. For the previous temporary variables, just increase the main address by 2 (in the example above, you would change it to .word 0x020270B8 + (0x8000 * 2), if you were to use variable 0x8000).
But does this way work for any other variables other than the 0x8000 family?

karatekid552
October 4th, 2013, 09:22 AM
.word 0x020270B6 + (0x800D * 2)
Assigns the word (32 bits) 0x020270B6 + (0x800D * 2) = 0x020370D0 to .VAR. If you're wondering about the "weird" format, I made that to make it easier changing the variable used. Note however this would work only for temporary variables, 0x800D onwards. For the previous temporary variables, just increase the main address by 2 (in the example above, you would change it to .word 0x020270B8 + (0x8000 * 2), if you were to use variable 0x8000).
But does this way work for any other variables other than the 0x8000 family?

The others are DMA protected. Check my battle bg changer to see how to check vars of others. There is an in-game decrypter function.

Kurapika
October 4th, 2013, 09:57 AM
Oh damn! :(
I'll check your tutorial, thank you bro!