summaryrefslogtreecommitdiff
path: root/Fix-the-1-in-255-miss-bug.md
blob: 409e7836d50577a99f4d544913521a2c223d8202 (plain)
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!