1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
In Generation I, due to a slight quirk of how the accuracy code works, there's a +1/255 chance of missing any move, meaning that 100% accuracy moves have a chance of 255/256 for hitting, or 99.609375%, and not 100%.
This tutorial shows how Generation II fixes this issue.
(Code backported from Pokémon Crystal.)
## Contents
- [Skip if move accuracy is 100%](#1-skip-if-move-accuracy-is-100%)
- [Explaining the fix](#2-explaining-the-fix)
## 1. Skip if move accuracy is 100%
In [engine/battle/core.asm](https://github.com/pret/pokered/blob/master/engine/battle/core.asm), we can go to the label `.doAccuracyCheck` to see the following:
```
.doAccuracyCheck
; if the random number generated is greater than or equal to the scaled accuracy, the move misses
; note that this means that even the highest accuracy is still just a 255/256 chance, not 100%
call BattleRandom
cp b
jr nc, .moveMissed
ret
```
Here's where we insert the proper code.
```diff
.doAccuracyCheck
; if the random number generated is greater than or equal to the scaled accuracy, the move misses
; note that this means that even the highest accuracy is still just a 255/256 chance, not 100%
+ ; The following snippet is taken from Pokemon Crystal, it fixes the above bug.
+ ld a, b
+ cp $FF ; Is the value $FF?
+ ret z ; If so, we need not calculate, just so we can fix this bug.
call BattleRandom
cp b
jr nc, .moveMissed
ret
```
As you can see, we've added only 3 lines of code. This fixes this bug, Gen II style. Now, let's talk about what exactly this does.
## 2. Explaining the fix
For anyone with GB Z80 experience, feel free to skip this part, but for anyone uninformed, I'll try my best to explain with my limited knowledge.
`ld a, b` loads the contents of register b into register a. This is done because b holds the move accuracy of the Pokémon currently using the move.
`cp $FF` just compares a to $FF, technically by subtracting $FF from a.
`ret z` returns from this subroutine IF the Zero flag is set. Due to how cp works, this will be set if the compared value and a are equal. In other words... return if equal. Therefore, if move accuracy is $FF, therefore 100%, then it doesn't bother calculating if the move will miss: after all, the move's accuracy IS 100%. This occurs after other move accuracy calculations, so those will come into effect as well.
Enjoy!
|