summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engine/battle/core.asm69
-rw-r--r--home/random.asm69
-rw-r--r--shim.sym1
-rw-r--r--wram.asm7
4 files changed, 145 insertions, 1 deletions
diff --git a/engine/battle/core.asm b/engine/battle/core.asm
new file mode 100644
index 0000000..c79fb22
--- /dev/null
+++ b/engine/battle/core.asm
@@ -0,0 +1,69 @@
+include "constants.asm"
+
+SECTION "Battle Random", ROMX [$63DA], BANK [$0F]
+_BattleRandom: ; 3e3da (f:63da)
+; If the normal RNG is used in a link battle it'll desync.
+; To circumvent this a shared PRNG is used instead.
+
+; But if we're in a non-link battle we're safe to use it
+ ld a, [wLinkMode]
+ and a
+ jp z, Random
+
+; The PRNG operates in streams of 10 values.
+
+; Which value are we trying to pull?
+ push hl
+ push bc
+ ld a, [wLinkBattleRNCount]
+ ld c, a
+ ld b, $0
+ ld hl, wLinkBattleRNs
+ add hl, bc
+ inc a
+ ld [wLinkBattleRNCount], a
+
+; If we haven't hit the end yet, we're good
+ cp 9 ; number of seeds, including the last one. see comment in pokecrystal
+ ld a, [hl]
+ pop bc
+ pop hl
+ ret c
+
+; If we have, we have to generate new pseudorandom data
+; Instead of having multiple PRNGs, ten seeds are used
+ push hl
+ push bc
+ push af
+
+; Reset count to 0
+ xor a
+ ld [wLinkBattleRNCount], a
+ ld hl, wLinkBattleRNs
+ ld b, 9 ; number of seeds; in release, this was increased to 10
+
+; Generate next number in the sequence for each seed
+; a[n+1] = (a[n] * 5 + 1) % 256
+.loop
+ ; get last #
+ ld a, [hl]
+
+ ; a * 5 + 1
+ ld c, a
+ add a
+ add a
+ add c
+ inc a
+
+ ; update #
+ ld [hli], a
+ dec b
+ jr nz, .loop
+
+; This has the side effect of pulling the last value first,
+; then wrapping around. As a result
+
+ pop af
+ pop bc
+ pop hl
+ ret
diff --git a/home/random.asm b/home/random.asm
new file mode 100644
index 0000000..5ca7c78
--- /dev/null
+++ b/home/random.asm
@@ -0,0 +1,69 @@
+include "constants.asm"
+
+if DEBUG
+SECTION "Random Number Generation", ROM0 [$3270]
+else
+SECTION "Random Number Generation", ROM0 [$3234]
+endc
+
+Random::
+; A simple hardware-based random number generator (RNG).
+
+; Two random numbers are generated by adding and subtracting
+; the divider to the respective values every time it's called.
+
+; The divider is a register that increments at a rate of 16384Hz.
+; For comparison, the Game Boy operates at a clock speed of 4.2MHz.
+
+; This implementation also takes the current scanline as read from rLY
+; and adds it nybble-swapped to the value of the divider. The unswapped
+; value of rLY is also added to the value that's subtracted.
+
+; Additionally, an equivalent function is executed in VBlank.
+
+; This leaves a with the value in hRandomSub.
+
+ push bc
+
+ ldh a, [rLY]
+ ld c, a
+ swap a
+ ld b, a
+ ldh a, [rDIV]
+ adc b
+ ld b, a
+ ldh a, [hRandomAdd]
+ adc b
+ ldh [hRandomAdd], a
+
+ ldh a, [rLY]
+ swap a
+ ld b, a
+ ldh a, [rDIV]
+ adc b
+ adc c
+ ld b, a
+ ldh a, [hRandomSub]
+ sbc b
+ ldh [hRandomSub], a
+
+ pop bc
+ ret
+
+BattleRandom::
+; _BattleRandom lives in another bank.
+
+; It handles all RNG calls in the battle engine, allowing
+; link battles to remain in sync using a shared PRNG.
+ ldh a, [hROMBank]
+ push af
+ ld a, BANK(_BattleRandom)
+ call Bankswitch
+
+ call _BattleRandom
+
+ ld [wPredefHL + 1], a
+ pop af
+ call Bankswitch
+ ld a, [wPredefHL + 1]
+ ret
diff --git a/shim.sym b/shim.sym
index bdca7c3..ac185f2 100644
--- a/shim.sym
+++ b/shim.sym
@@ -22,7 +22,6 @@
00:23dc LoadWildMons
00:23e5 FadeIn ; This is not OverworldFadeIn, but I don't know what it is
00:2C05 StartMenuCheck
-00:3270 Random
00:3621 WaitBGMap
00:362B SetPalettes
00:3634 ClearPalettes
diff --git a/wram.asm b/wram.asm
index a6ed29e..8042d4d 100644
--- a/wram.asm
+++ b/wram.asm
@@ -182,6 +182,9 @@ wEnemySubStatus3:: db ; ca42
ds $14
wTrainerClass:: ; ca57
db
+; ca58
+ ds $6b
+wLinkBattleRNCount:: db ; cac3
ENDU
@@ -370,6 +373,10 @@ wLinkMode:: db ; cdbd
wTargetMapUnk:: db ; cdbe ; TODO: Probably warp ID, check
wTargetMapGroup:: db ; cdbf
wTargetMapId:: db ; cdc0
+; cdc1
+ ds $c
+wLinkBattleRNs:: ds 10 ; cdcd
+; cddd
SECTION "CE00", WRAM0[$CE00]