DQ1,2(SFC)乱数生成について

最終更新:2011/09/17

SFC版DQ1,2で乱数を用いる場面では、すべて一種類の乱数によってカバーされている。
この乱数は乱数テーブル等は使用しておらず、常に計算によって生成している

乱数が初期化されるタイミングは、電源投入(もしくはリセット)時と、
DQ2のみは冒険の書選択後の冒険開始時にももう一度リセットされる。
また、例外はかなりあるものの、基本的にはフレーム単位で生成され続けている。
(乱数が動かず、経過フレームのみが回っている場合もある。
 また、1フレーム間に複数乱数が回る場合もある。)

乱数計算で使用するメモリーは、$7E0067・$7E00E0・$7E00E2(全て16bit)である。
$67:経過フレーム(1フレームごとにそれぞれ1増加)
 ※下位1バイト($67)は範囲[0〜0xFF]、上位バイト($68)は範囲[0〜0x04]で、
 それぞれ別にカウントが行われている。(例:042eの次は002fになる。)
$E0:乱数の下位2バイト(計算にのみ用いる)
$E2:乱数の上位2バイト(いわゆる乱数。下位1バイトのみ、もしくは2バイト用いることもある)
(0x〜は16進数)

★簡潔に言うと、直前の乱数値($E3〜$E0の8桁)を乱数xとすると
乱数x’=乱数x×3+0x3549+$67 となり、線形合同法の亜種である。

実際に乱数として用いられるのは$E2部分で、1バイトもしくは2バイト分使用される。
8桁の乱数を33221100とすると、22または3322である。

繰り上がりの例外

05A550(0BA550)からが乱数生成ルーチンであるが、繰り上がり処理に一部例外が生じる。

05A550 REP #$20 ; Aを16bitモードに
05A552 LDA $E2 ; "A" = $E2
05A554 PHA
05A555 LDA $E0 ; "A" = $E0
05A557 ASL $E0 ; $E0×2
05A559 ROL $E2 ; $E2×2(キャリーフラグを含む)
05A55B CLC ; キャリーフラグを0に
05A55C ADC $E0 ; "A" += $E0
05A55E STA $E0 ; $E0 = "A"
05A560 PLA
05A561 ADC $E2 ; "A" += $E2
05A563 STA $E2 ; $E2 = "A"
05A565 LDA $E0 ; "A" = $E0
05A567 CLC
05A568 ADC #$3549; "A" += #$3549
05A56B ADC $67 ; "A" += $67
05A56D STA $E0 ; $E0 = "A"
05A56F LDA $E2 ; "A" = $E2
05A571 ADC #$0000  ; "A" += 0
05A574 STA $E2 ; $E2 = "A"
05A576 SEP #$20 ; Aを8bitモードに
05A578 LDA #$00 ; "A" = 0
05A57A XBA
05A57B LDA $E2 ; "A" = $E2
05A57D RTL

(乱数x’=乱数x×3+0x3549+$67)

これを見ると分かるかもしれないが、+0x3549の繰り上がり処理のみ特殊である。
×3した後の$E0部分(16bit)に加算するのだが、
加算後が16bit以上になった際は直接繰上りせず、
$67を足すときに一緒に、最下位bitに+1される。

05A565 LDA $E0 ; "A" = $E0
05A567 CLC ; キャリーフラグを0に
05A568 ADC #$3549; "A" += #$3549
05A56B ADC $67 ; "A" += $67

まず、この言語の仕様として、

というものがあるが、
0x3549加算後にいわゆる繰り上がり処理がないため、
ADC $67でキャリーフラグが消化され、+1されてしまうのである。

文責:Kri (http://com.nicovideo.jp/community/co381358)