• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

Pokéball hacking guide

Skeli

Lord of the Rings
300
Posts
10
Years
Pokéball Hacking Guide


Bag_Pok%C3%A9_Ball_Sprite.png
Introduction
Bag_Pok%C3%A9_Ball_Sprite.png
All credits for the original thread go to danills. It's thanks to him any of this is even possible. The following introduction is from him.
Some months ago, when I was still attempting my first hack, I was wondering whether it was possible to create a custom pokeball. The only thing I found was this post by JPAN. It wasn't complete, and I hadn't seen anyone using it, so I forgot about it.
Now, I am working full-time on Platinum Red&Blue with GoGoJJTech, and had to implement gen IV pokeballs into the hack. I have altered JPAN's asm code a bit, and included documentation on the throwing graphics for everybody to use. Enjoy!


Bag_Great_Ball_Sprite.png
Requirements
Bag_Great_Ball_Sprite.png
  • A hex editor (I use HxD)
  • A way to find free space in your rom; FSF recommended
  • Images for your balls
  • A way to insert those images (I use unLZ-GBA)
  • Gen 3 Tools
  • Basic hex editing/assembly knowledge. I do assume you know how to assemble a routine and place an inverted pointer +1 to it.

Bag_Ultra_Ball_Sprite.png
Step 1: Dealing with the pokemon data limiters
Bag_Ultra_Ball_Sprite.png
WARNING: This step will break any saves in progress!
This is the easiest part. As you can see here, the balls only get four bits of data, and 0 is unused, meaning you can add up to three balls. Since I don't think there are many people who have transferred pokemon from Colosseum or XD to a hack, it's safe to sacrifice the most significant bit used to determine the game of origin, leaving us space for 19 extra balls. If you need more, you will need a different workaround.
You've got to change six bytes:
  • At 080400B6, place 80
  • At 080400B8, place 44
  • At 080400BE, place 0B
  • At 08040855, place FC
  • At 0804085A, place 1F
  • At 0804085E, place 89
  • At 08040862, place 7C
Now apply all changes in this post.

And you're done! Move on to step 2.


Bag_Safari_Ball_Sprite.png
Step 2: Inserting the catch rate routine
Bag_Safari_Ball_Sprite.png
JPAN has written a neat routine that replaces the regular check for pokeballs (see the link posted above). However, it requires you to perform a cmp for every ball index, and that's not very efficient and forces you to modify the routine every time you add a ball. Thus, I have modified it, so that it checks what pocket the selected item is in. Now, you only have to give the item the right pocket value and it becomes a ball. The routine:
Spoiler:
Now, in the code you see "somevar". There you must place an address (or use this one I saw in JPAN's original routine) that will keep track of the current pokeball index. Other than in the routine, there are a few places you need to place a pointer to it:
  • 0802D500
  • 0802D544
  • 0802D6A0
  • 0802D71C
  • 0802D7B8
  • 080EF4B4
  • 080EF4DC
  • 080EF674
  • 080EF9AC
  • 080F0368
You probably don't know what the pokeball index is. Well, it's an unused value in the item structure, which can be changed with Gen3Tools pretty easily. If you take a look at any pre-existing Poke Ball in Gen3Tools, you'll see its ball index next to "Type". The Premier Ball has the highest index of 12, so any new balls can be counted up from there (eg. Dusk Ball is 13, Quick Ball is 14, etc.)
(more information here)
Now you've done all that, it's time to assemble the routine. Insert in anywhere, and place a pointer to it at 08016494. Then at 08016460, type 00 00 00 00 0B 4A 97 46. Done! Move on to the next step to make your ball actually do something.


Bag_Master_Ball_Sprite.png
Step 3: Making the balls do something
Bag_Master_Ball_Sprite.png
The balls with a pokeball index (previously index number) higher than 5 each have their own catch rate calculation subroutine. We need to extend that. To do this, first change the byte at 0x802D52C to FF. Then, look at the table at 0x802D54C. It has a pointer to a routine for every pokeball starting from 6. At 0x802D548 you can see a pointer to the table; repoint it somewhere else (the table is 0x1C bytes long). Now, to give a ball a certain catch rate, you must write a routine to load it into r4, and exit to 0x802D7A2. Then place a pointer to that routine in the table.
Some example routines:
Bag_Quick_Ball_Sprite.png
Quick ball:
Spoiler:
Bag_Dusk_Ball_Sprite.png
Dusk ball:
Spoiler:
Bag_Park_Ball_Sprite.png
Park ball; this one uses a modified safari ball routine, and will get another piece of code later:
Spoiler:
Bag_Heal_Ball_Sprite.png
Bag_Cherish_Ball_Sprite.png
Heal ball/Cherish ball (the heal ball will get another piece of code later)
These are special. They load the catch rate from the "Extra value" of the item (labeled as "Extra" in Gen3Tools). In the case of these balls it's 10, but you can easily change it without altering the code:
Spoiler:
Bag_Moon_Ball_Sprite.png
Moon Ball:
Spoiler:
Bag_Sport_Ball_Sprite.png
Sport Ball:
Spoiler:
Bag_Dream_Ball_Sprite.png
Dream Ball:
This is a hook from the Master Ball routine. This code DOES NOT go at the end of the catch routine table. Where a routine in the table would have gone for the Dream Ball, place 00 00 00 00. Despite it not having its own routine, the Dream Ball still receives a unique index like every other ball.
Spoiler:
Bag_Beast_Ball_Sprite.png
Beast Ball:
Spoiler:
Here comes the part JPAN didn't document: animations. And be prepared, it's a long part.


Step four: Expanding the Throwing Graphics - Part 1
Bag_Level_Ball_Sprite.png
The conversion table
Bag_Level_Ball_Sprite.png
Now, if you've ever looked at the pokeballs in an item viewer and at the throwing graphics of them in an image viewer, you might have noticed they're in a different order. So, there is a routine somewhere that converts the index to the throwing graphics table (or tgt in short because I'm lazy) entry. That routine is located at 080EF52C. Due to the way it's written, there's enough space to replace it by a new routine and a table. First the routine:
Spoiler:
Assemble this routine and insert it at 080ef52C. Now, the conversion from index to tgt entry will be done through throwtablepositionstable. By this, we freed up more than enough space at the specified offset, so I recommend you to put the table there. Now for the table, it will look like this:
Code:
(unused zeroth entry) FF 04 03 01 00 02 05 06 07 08 09 0A 0B (insert ongoing numbers for each of your balls here)
It is the easiest if you insert the throwing graphics in the same order as your pokeballs, so just count up. For the five gen 4 balls, it would be
Code:
FF 04 03 01 00 02 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10
But be careful: while the pokeball index was one-indexed, the tgt is zero-indexed, which means that in the entry for ball x you will have to type x-1.
After inserting this, remove a limiter by typing 00 00 at 080EF972 and at 080F02D6, and continue to the next step.


Step four: Expanding the Throwing Graphics - Part 2
Bag_Lure_Ball_Sprite.png
The image and palette tables
Bag_Lure_Ball_IV_Sprite.png
Prepare your ball images. Example with gen 4 balls:
DzLLV9G.png

Made by Bela. Isn't he awesome? :D
Anyways, you must repoint and extend two tables in this step. First, the one for the images, located at 0826056C. 12 entries, each eight bytes: one word and two halfwords. Repoint it somewhere. Then, append your own balls as follows:
Code:
word		pointer to image
halfword	decompressed size (180)
halfword	tag of ball(I'm not sure which tags are free exactly, but I started with tag 0xFF00 for the first entry and counted up for the following balls/particles and it worked fine.)
The second table is a lot like this one: it's for the palettes. Located at 082605CC, again 12*8 bytes long. Repoint somewhere, and extend this way:
Code:
word		pointer to palette
halfword	tag of ball
halfword	filler (0000)
We just started repointing, and we still have a long way to go.


Step four: Expanding the Throwing Graphics - Part 3
Bag_Moon_Ball_Sprite.png
Repointing generic tables
Bag_Moon_Ball_Sprite.png
Here comes a list of the tables:
Spoiler:
After you have done this, you can finally assign particles and animations to your balls.


Step four: Expanding the Throwing Graphics - Part 4
Bag_Friend_Ball_Sprite.png
The particle and animation tables
Bag_Friend_Ball_Sprite.png
As for now, I will only document the tables and their meanings, and how to assign existing animations/particles to new balls. Another part on custom animations may follow later.
The first table you need to repoint and extend is located at 0840C068. For every ball it tells which particle to use. 0=sticks, 1=stars, 2=bubbles, 3=hearts, 4=big green crosses, 5=small green crosses (last two strongly affected by the second table).
The second table is located at 0840C074. Each entry is a pointer to a routine+1 that describes how the particles should act. I can't really describe the effects, so just look at them.
And that's it! Congratulations, you've succesfully expanded the pokeballs! The next parts will describe how to apply some special effects.


Step Five: Expanding the Throwing Graphics - Part 5
Bag_Luxury_Ball_Sprite.png
Ball Opening Colour Table
Bag_Luxury_Ball_Sprite.png
There is one last table at 0x40C1C4:
Code:
DF 7A F0 7A D7 53 FF 3F 97 72 F5 67 2C 7B 7E 2B 1F 43 DD 7B 3F 2A 3F 29
Each half-word (2 bytes) in this table corresponds to the palette the Pokemon is faded when it comes out of that certain Poke Ball. For instance, the first entry, 0x7ADF (DF 7A reversed) is the pink colour a Pokemon fades from when it leaves a Poke Ball. To repoint this table, copy 0x18 bytes to another location, replace the pointers to C4 C1 40 08, and add new colours on to the end of your table in the same order as your Poke Balls. APE's colour picker can be used to calculate the hex codes of new colours in reversed format, ready to be added to the table.


Step Six: Additional effects part 1
Bag_Love_Ball_Sprite.png
Healing pokemon after capture
Bag_Love_Ball_Sprite.png
This effect was written by danills for the Heal Ball:
Spoiler:
In this code you must change the values at the ball index and somevar. Then assemble it and insert it anywhere. To activate it, place 00 4B 9F 46 XX XX XX XX at 08040B08, where XXXXXXXX is an inverted pointer to this routine.


Step Six: Additional effects part 2
Bag_Heavy_Ball_Sprite.png
Retaining pokeballs
Bag_Heavy_Ball_Sprite.png
This effect was written by me for the Park Ball, and will work if the caught poke already has a pokeball, like with the Pal Park:
Spoiler:
In this code you must only change the the ball index. Then assemble it and insert it anywhere. To activate it, place 40 4B 9F 46 12 F0 EB FD 13 F0 49 FA at 0802D6EE, and 70 BD XX XX XX XX at 0802D7EE where XXXXXXXX is an inverted pointer to this routine.


Step Six: Additional effects part 3
Bag_Fast_Ball_Sprite.png
The givepokemon hack
Bag_Fast_Ball_Sprite.png
One of the gen 4 balls is the Cherish Ball, which has no effects other than being the standard ball for event pokes. To copy this effect, I wrote a piece of code to change the givepokemon command. Know how it has three unused parameters? Well, the last one, a byte, is now the pokeball the received pokemon will be in. If it's 0, it will be in a regular pokeball.
Anyways, the hack:
Code:
Type A1 68 0A 79 00 2A 00 D1 04 22 05 31 at 0806c014. Activate the hack by typing 29 98 at 0803DC52.
Congratulations! You are finished! If you write more ball effects, I'm sure everybody will gladly take a look at them!


Bag_Sport_Ball_Sprite.png
To-do list
Bag_Sport_Ball_Sprite.png
  • Implement custom particles
  • Discover how to write custom animations
  • Come up with a solution for the Heavy Ball
  • Think of a way to create a ball that catches trainer's pokemon
  • Finish the givepokemon hack to include the moveset

Bag_Premier_Ball_Sprite.png
Credits
Bag_Premier_Ball_Sprite.png
  • JPAN, for the original research and his tutorial that actually got me into asm
  • knizz, for his disassembly (if you haven't heard about it yet, it's a must-have for any asm hacker: link) and infinite amount of help, with finding tables, answering all my dumb questions, and even answering most of my advanced questions
  • Danills for the original code
  • GoGo, for pushing me to finish this
  • Bela, for drawing the balls
  • Jambo51, for the idea of the givepokemon hack
  • Mat (bond697), for trying to help danills fix a major issue with this. Although the reason for the crash turned out to be something else, He appreciated his help and he learned something
  • Kearnseyboy6, for code
  • Ghoulslash, for code
 
Last edited:
3,830
Posts
14
Years
  • Age 27
  • OH
  • Seen Feb 26, 2024
This is great!
You do a wonderful job of explaining such a complex task! :)

EDIT:

To use the givepokemon hack on LeafGreen 1.0, just do everything you would for FireRed 1.0.
The offsets and ASM are unchanged. :)
 

daniilS

busy trying to do stuff not done yet
409
Posts
10
Years
  • Age 24
  • Seen Jan 29, 2024
Thanks for all the positive feedback guys!
I assume for gen v mechanics, we simply make it #40 for 5x the chance?

Awesome tut btw
Yeah, and now I look at it I don't remember why it isn't a simple mov.
 

kearnseyboy6

Aussie's Toughest Mudder
300
Posts
15
Years
  • Seen Jun 22, 2019
Hey,

Can you please guide me if this level ball works?

Spoiler:


I sourced it from http://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9_Ball#Level_Ball

This is my very first branching asm, would like some feedback please :) ?

It basically checks your level against theirs, if its lower x1
If its higher it branches and halves your level, then checks again. if lower x2 (less than double but higher than wild)
If its higher again it will half, then check again. If lower x4 (more than double but less than quadruple)
If its higher it branches and moves x8. How does that sound?
 

daniilS

busy trying to do stuff not done yet
409
Posts
10
Years
  • Age 24
  • Seen Jan 29, 2024
Hey,

Can you please guide me if this level ball works?

Spoiler:


I sourced it from http://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9_Ball#Level_Ball

This is my very first branching asm, would like some feedback please :) ?

It basically checks your level against theirs, if its lower x1
If its higher it branches and halves your level, then checks again. if lower x2 (less than double but higher than wild)
If its higher again it will half, then check again. If lower x4 (more than double but less than quadruple)
If its higher it branches and moves x8. How does that sound?

Looks nice! However, this may cause some issues. For example, if your pokémon is level 17 (10001b) and the wild pokémon is level 2 (10b), right-shifting 17 three times will give 2 (10b), and that isn't higher than the wildpokelevel. So I would left-shift the wildpokelevel instead.
Also you forgot to add 84 to yourpokelevel, and I don't really get why you're using bne instead of simple b, and the last bne has no real use too, but good job apart from that!
 

kearnseyboy6

Aussie's Toughest Mudder
300
Posts
15
Years
  • Seen Jun 22, 2019
Cool so I'm definitely improving my asm skills.

I made a test code for heavy ball, I haven't applied your tut yet so I haven't tested it but it looks reasonable. The main problem with the heavy ball is this hack let's you set a value in r4 and then C*R4, so R4 is basically the ball bonus. Heavy ball doesn't multiply... it adds eg (C+40). So without modifying the routine we could be stuck.

But I think what if we could always have (C+40) = (C*R4)? We simply have algebra to deal with. So our R4 will always mathematically be:

(C+40)/C right? I think so.

Luckily Knizz has found a division routine that's lets me code this to one decimal place. Any way here it is:

Spoiler:


So this is still my 2nd asm script so I'm 100% sure there are inefficiencies and it's probably wrong, but maybe this could help with the heavy ball solution?
 

GoGoJJTech

(☞゚ヮ゚)☞ http://GoGoJJTech.com ☜(゚ヮ゚☜)
2,475
Posts
11
Years
The givepokemonhack works, but if I start a battle against a trainer, the game freezes, when the opponent throws the ball.

That means you either inserted incorrectly or corrupted something.

EDIT: daniilS explained what could happen to cause the bug.
 
Last edited:

daniilS

busy trying to do stuff not done yet
409
Posts
10
Years
  • Age 24
  • Seen Jan 29, 2024
Is there any way you could also give the routine for a Master Ball & a regular Pokeball??

Do you mean a routine with fixed catch rate? There is one at heal/cherish ball. Or did I misunderstand?
 

Turtl3Skulll

Blue Turtl3
76
Posts
10
Years
Do you mean a routine with fixed catch rate? There is one at heal/cherish ball. Or did I misunderstand?

I didn't realize the cherish ball had s standard fixed catch rate, I assume to make another master ball I'd just have to check bulbapedia for the catch rate info on it, or is it different to make one w/ 100% catch rate??
 

daniilS

busy trying to do stuff not done yet
409
Posts
10
Years
  • Age 24
  • Seen Jan 29, 2024
The masterball is a special case because it skips catch rate calculation completely, but entering 255 as a value should give you no problems unless a poke has a catch rate below 3.
 

Turtl3Skulll

Blue Turtl3
76
Posts
10
Years
Alrighty thanks daniilS! I'll use test it out later today.
I wish I'd known how to work this tutorial when it had come out, I think this is flipping awesome, thanks for answer me too:D
 

daniilS

busy trying to do stuff not done yet
409
Posts
10
Years
  • Age 24
  • Seen Jan 29, 2024
I've updated the offset of somevar. If anybody is actually using this, please change it, as the first offset may be unsafe to use in some hacks.
 

kearnseyboy6

Aussie's Toughest Mudder
300
Posts
15
Years
  • Seen Jun 22, 2019
For some reason, my extended balls don't have particles assigned in game even when I assign them. I changed all balls to sticks, and it works until I get to new balls.

Any clue?
 

daniilS

busy trying to do stuff not done yet
409
Posts
10
Years
  • Age 24
  • Seen Jan 29, 2024
For some reason, my extended balls don't have particles assigned in game even when I assign them. I changed all balls to sticks, and it works until I get to new balls.

Any clue?

I'd double check step four part three. If that's done correctly, then I can't tell what's wrong without having a look at your rom.
 
Back
Top