- if heavy_modifier:
- # Only used by Heavy Ball. Changes the target's capture rate outright
- capture_rate += heavy_modifier
- if capture_rate <= 1:
- capture_rate = 1
-
- # This should really be integer math, right? But the formula uses FOURTH
- # ROOTS in a moment, so it can't possibly be. It probably doesn't matter
- # either way, so whatever; use regular ol' division. ball_bonus and
- # status_bonus can be 1.5, anyway.
- base_chance = ((3 * max_hp - 2 * current_hp) * capture_rate * ball_bonus) \
- / (3 * max_hp) \
- * status_bonus
-
- shake_index = (base_chance / 255) ** 0.25 * (2**16 - 1)
+ # HG/SS Pokéballs modify capture rate rather than the ball bonus
+ capture_rate = capture_rate * capture_bonus // 10 + capture_modifier
+ if capture_rate < 1:
+ capture_rate = 1
+ elif capture_rate > 255:
+ capture_rate = 255
+
+ # A slight math note:
+ # The actual formula uses (3 * max_hp - 2 * curr_hp) / (3 * max_hp)
+ # This uses (1 - 2/3 * curr_hp/max_hp)
+ # Integer division is taken into account by flooring immediately
+ # afterwards, so there should be no appreciable rounding error.
+ base_chance = int(
+ capture_rate * ball_bonus // 10 * (1 - 2/3 * percent_hp)
+ )
+ base_chance = base_chance * status_bonus // 10
+
+ # Shake index involves integer sqrt. Lovely.
+ isqrt = lambda x: int(x ** 0.5)
+ if not base_chance:
+ # This is very silly. Due to what must be an oversight, it's possible
+ # for the above formula to end with a zero chance to catch, which is
+ # then thrown blindly into the below denominator. Luckily, the games'
+ # division function is a no-op with a denominator of zero.. which
+ # means a base_chance of 0 is effectively a base chance of 1.
+ base_chance = 1
+ shake_index = 1048560 // isqrt(isqrt(16711680 // base_chance))