diff options
-rw-r--r-- | engine/battle/core.asm | 69 | ||||
-rw-r--r-- | home/random.asm | 69 | ||||
-rw-r--r-- | shim.sym | 1 | ||||
-rw-r--r-- | wram.asm | 7 |
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 @@ -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 @@ -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] |