• 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.

Research: Critical Capture

239
Posts
8
Years
  • Age 31
  • Seen Apr 15, 2024
Thanks to Daniils and JPAN and everyone else who has worked on expanding pokeballs, we can expand pokeballs and create custom catch rate functions. However, I have yet to see any work on porting the critical capture to Gen 3 games (at least any public work)

I would like to share some research I have done into the subject. I noticed from koople's dodge rate routine that there is some index that appears to determine the outcome of the throw (see below).

First, some info on how the catch rate and subsequent success is determined:
1. The catch rate is calculated starting at 0802d620 and finally loaded into r6:
Spoiler:


2. There is then a check for safari ball and master ball, and we jump to 0802d6a8 for everything else. Eventually, we end up at 0802d752, which is a loop that gets a random value, and compares to the catch rate in r6.
Spoiler:

The loop incrementally increases r4 to a maximum value of 0x4, which holds the "catch index" as follows:
Code:
r4 = 0x0 --> breakout immediately
r4 = 0x1 --> shake once and breakout
r4 = 0x2 --> shake twice and breaout
r4 = 0x3 --> shake three times and breakout
r4 = 0x4 --> shake three times and catch
r4 = 0x5 --> trainer deflection (handled separately)
r4 = 0x6 --> ghost battle dodge (handled separately)
r4 > 0x6 -> ball rolls [r4] times and breaks out. sort of funny to watch it roll 10 times


An non-ideal critical capture routine could be made with a tentative algorithm such as this:
Code:
1. get ratio of caught pokemon to pokedex size
2. check brackets via [URL="https://bulbapedia.bulbagarden.net/wiki/Catch_rate#Critical_capture"]this guide[/URL]
3. get crit_catch_rate * catch_rate (eg. (0 - 2.5)*r6)
4. get random value via 08044ec8
5. compare critical capture rate to random value
6. if lower, critical capture has occurred. otherwise, perform regular capture checks (ie jump to 0802d752)
7. for critical capture: only perform one "shake check". 
7a. set r4 to 0x2 and jump to 0802d74c, or do logic yourself

This routine would theoretically imitate the logic for critical capture; however, the pokeball would still shake three times before capture instead of just once. I haven't had much luck with figuring out how the number of shakes is tied to the catch index yet. I have to imagine it is related to the ball object template table, as it contains data that appears to be related to "shaking" the pokeball. I would guess that the game loops over some animation related to shaking the pokeball based on the value of the "catch index" above.

(hopefully) more to follow. I hope to having a working code of the proposed algorithm soon.

EDIT: Here is an initial working version of the critical capture algorithm. The shaking animation and throwing sound need to be fixed, still
Spoiler:
 
Last edited:

AkameTheBulbasaur

Akame Marukawa of Iyotono
409
Posts
10
Years
Hey this is pretty cool!

Last summer I was trying to figure out a similar sort of mechanic. I was trying to have a chance of being guaranteed to capture the pokemon based in certain things like level differences or Speed boosts. I forgot how it worked because I never ended up using it.

The part that I had the most trouble with was getting the game to have a separate animation for when these sorts of captures would occur. Well, not really a separate animation as much as having different sound effects, much like how actual critical captures have a different sound effect when the ball is thrown.

I'd been looking at the battle scripts called when Poke Balls are thrown but I found nothing that I could make use of :(. Hopefully we can all figure something out.
 
239
Posts
8
Years
  • Age 31
  • Seen Apr 15, 2024
Hey this is pretty cool!

Last summer I was trying to figure out a similar sort of mechanic. I was trying to have a chance of being guaranteed to capture the pokemon based in certain things like level differences or Speed boosts. I forgot how it worked because I never ended up using it.

The part that I had the most trouble with was getting the game to have a separate animation for when these sorts of captures would occur. Well, not really a separate animation as much as having different sound effects, much like how actual critical captures have a different sound effect when the ball is thrown.

I'd been looking at the battle scripts called when Poke Balls are thrown but I found nothing that I could make use of :(. Hopefully we can all figure something out.

Yeah the animation/sound effects seems to be the trickiest part. The battle scripts appear to only print the relevant strings/add data to pokedex/etc after the animation has run its course.

With that, here is a bit more preliminary research I've done:
Spoiler:


I've also come up with a (fully?) working 'critical capture' routine using the algorithm I originally described. It also allows for a custom string to be displayed when critical capture succeeds:
Spoiler:
 
Last edited:

AkameTheBulbasaur

Akame Marukawa of Iyotono
409
Posts
10
Years
So I've figured out how to add a new animation for critical captures.

There's a table at 0x1C6F18 that has a bunch of pointers to animations. The important one is the third entry, 0x1D64F9, which is the PokeBall throwing animation.

You can repoint this table and add a new entry for your new animation.

I used a small routine to actually reroute the game to play your new animation.

Spoiler:


Essentially the way this works is you put a 1 into 0x020370D6. This is the RAM for the temporary var 8010. This will stay the same throughout the battle, so you can set this to 1 during the catch rate routine and then it will know to play the other animation. I picked 8010 for this because it was a var I thought most people wouldn't need to actually use. This, of course, can be changed for some other piece of RAM, but do so at your own risk.

Now for the animation, I just used the default animation, but changed the "19 36 00" to "19 BB AA" where AABB is the sound you want the game to play.

For good measure, I also made a routine for determining guaranteed capture. It's based on the difference between your Speed and the foe's Speed. In other words, if you have a much higher Speed than the wild Pokemon, there is a chance for a guaranteed capture (regardless of Poke Ball) that approached 50%.

For example, if you and the wild Pokemon have the exact same Speed stat, the chance will be 25%.

Spoiler:
 
Last edited:
239
Posts
8
Years
  • Age 31
  • Seen Apr 15, 2024
Awesome work, Akame! Here's a bit more info on the copied animation at 1d64f9:
Code:
03 91 F4 0E 08 02 00 04 00    -> call task 080ef490
19 36 00 00 				-> play throw pokeball sound (0x36)
03 AD F5 0E 08 02 00 		-> 080ef5ac  -> must somehow related to catching
03 E1 F4 0E 08 02 00 		-> call task 080ef4e0 (check trainer block vs. dodgeball indices)
21 07 FF FF 2D 65 1D 08   -> jump to 1d652d if trainer deflection
21 07 FE FF 55 65 1D 08   -> jump to 1d6555 if dodging animation
05 
03 B9 F4 0E 08 02 00   -> call task 080ef4b8
08

Task 080ef5ac loads the ball object table/ball ID, and has a BL to 08074480. This routine looks like so:
Code:
08074480 b530 push {r4,r5,lr}
08074482 0600 lsl r0, r0, #0x18
08074484 0e05 lsr r5, r0, #0x18
08074486 0609 lsl r1, r1, #0x18
08074488 0e0c lsr r4, r1, #0x18
0807448a 2c04 cmp r4, #0x4
0807448c d838 bhi $08074500	  @table limiter or catch index limiter?
0807448e 00a0 lsl r0, r4, #0x02
08074490 4901 ldr r1, [$08074498] (=$0807449c)
08074492 1840 add r0, r0, r1
08074494 6800 ldr r0, [r0, #0x0]
08074496 4687 mov pc, r0

The table at 7449c: (I think a routine is loaded based on the catch index?)
080744b0
080744d8 -> these first three routines appear to load a byte from some table at 3ae01c, not sure what it does
080744b0
08074500 -> my hunch is that this routine results in actually catching the pokemon
08074500:
Spoiler:


I haven't messed around too much with these routines, but I am fairly confident that 080ef5ac determines the shake animations.
 
Back
Top