各種ゲームのプログラム解析

目次

はじめに

ゲームの内部で起こっている処理を推測するのはなかなか難しいものです。ユーザーサイドから見れば、ゲームの内部処理はほとんど「ブラックボックス」のようなものです。ユーザーサイドでは「(内部で複雑な処理が行われた末の)最終結果」しかわかりませんし、ゲーム中の様々な要素(各種パラメータなど)がどのように「最終結果」に影響を及ぼしているのかについてもわかりません。解明するためには地道な試行錯誤を要します。

中でも「確率」というのはユーザーサイドからは見積もりするのが難しい要素です。特に「めったに起きないこと」が起きる確率を調べる場合などは、多大なサンプル数が必要となるために調査は困難を極めます。

そこで、「ROMイメージ内のプログラムコードの部分を解析する」というアプローチをもって、「外側」から見ただけではわかりにくいことを「内側」から調査してみました。この文書では、各種ゲームのプログラムコードを解析した結果、判明したことについてまとめてみました。現在のところは、主に各種ゲームの「確率」関連の処理について調べていますが、基本的には知的好奇心の赴くままに調査をしています。

対象とするプラットフォームは、今のところスーパーファミコンのゲームのみです。他のROMベースのゲーム機については、ROMイメージをファイルにダンプできるハードウェアを持っていないからです。まあ、CD-ROMベースのゲーム機については特殊なハードウェアがなくても(CD-ROMの)内容を読めるわけですが……さすがにプレイステーションなどのゲームのプログラムコードを解析するスキルはありません。

なお、解析結果には誤りが存在している可能性が多分にあります。ご注意ください。

解析結果についての解説

ファイナルファンタジーIV

お宝入手時の処理

ファイナルファンタジーIVには、モンスターを倒した際のお宝としてしか入手することのできないアイテムが多数存在します。「プリンプリンセス」の「ピンクのしっぽ」などは有名です。そして、これらのいわゆる「レアアイテム」は入手確率が非常に低く設定されています。

プリンプリンセスからピンクのしっぽを入手できる確率については、よく「1/256の確率である」などと言われていますが、果たして本当なのでしょうか? ここでは、「レアアイテム」が実際にはどの程度の確率で入手できるのかを解析した結果について述べます。

お宝を残すかどうかの判定処理

お宝入手の処理は、大きく分けて「お宝を残すかどうかの判定処理」と「(お宝を残した場合)4種類のアイテムの選択処理」の2つの部分になります。以下、順に説明します。

まずは「お宝を残すかどうかの判定処理」を行います。お宝を残す確率はモンスターによって決まっていて、それぞれ0〜3の4段階に分かれています。

なお、ザコモンスターの場合はたいてい"1"に設定されています。(詳しくはff_analyzerの『モンスターの所持アイテムデータ(IV)(ff4monitem.txt)』をご覧ください)

さて、この「5%」「25%」という確率ですが、ファイナルファンタジーIVでは「百分率」の扱いに若干癖があり、わずかに誤差があります。例えば、「5%の確率でお宝を残すか?」という判定を行う際には、「0〜98の範囲の乱数値を取得して、その値が5未満であるか?」という判定を行います。「0〜99の範囲」とか「0〜100の範囲」ではありません(注1)。よって、「5%の確率」は、実際には「5/99(≒ 5.05%)」であると言えます。

さらに、乱数生成の処理自体に起因する大きな誤差があります。例えば、上記の例でいう「0〜98の範囲の乱数値」を取得する際の処理は、「乱数テーブルから0〜255の範囲の乱数値を取得して、99で除算した余を算出する」という処理になっています。乱数テーブルには0〜255の範囲の乱数が偏りなく並んでいるのですが、このアルゴリズムだと「0〜57」が出る確率が少し高く(それぞれ3/256)、逆に「58〜98」が出る確率が少し低い(それぞれ2/256)のです。そうなると、「0〜98の範囲の乱数値」が「0〜4の範囲」になる確率は、「3/256 × 5 = 15/256(≒ 5.86%)」となります。

というわけで、一般的なザコモンスターがお宝を残す確率は「15/256(≒ 5.86%)」となります。

4種類のアイテムの選択処理

そして、お宝を残したと判定された場合、「4種類のアイテムの選択処理」を行います。こちらは単純で、0〜255の範囲の乱数値を取得して、その値の範囲によってアイテムの種類が決まります。

4種類のアイテムが選択される確率
乱数値 確率 アイテム
0〜127 128/256 アイテム1(「ぬすむ」で入手できるアイテム)
128〜207 80/256 アイテム2
208〜251 44/256 アイテム3
252〜255 4/256 アイテム4(いわゆる「レアアイテム」)

以上のことから、一般的なザコモンスターから「レアアイテム」を入手できる確率は、「15/256 × 4/256 ≒ 0.0916%」となります。だいたい1092体くらい倒してようやく1個入手できるかどうか、といったところでしょうか。

おそらくこの確率はすべてのモンスターにおいて同じです。よって、「プリンプリンセスからピンクのしっぽを入手できる確率」は「0.0916%(約1/1092)」となります。「1/256」よりはるかに低い確率です(注2)。ただ、プリンプリンセスは必ず5体で出現するわけで、「5体倒した際の確率」ということになると、単純に計算して「0.0916% × 5 ≒ 0.458%(≒ 1/218)」となります。これならば「当たらずとも遠からず」といったところでしょうか。

乱数

しかしながら、ここで一つ問題点が浮上します。基本的に、コンピュータで生成する疑似乱数は数の並びが事前にすべて決まっていて、乱数生成の試行は独立ではありません。お宝入手時の処理では「お宝を残すかどうかの判定処理」と「4種類のアイテムの選択処理」とで2回の乱数生成処理が行われるわけですが、もしこの2つの判定が連続して行われるとするならば、「レアアイテム」が出るには乱数テーブル内で以下の条件を満たした数字A・Bが隣接して並んでいなくてはならないことになります(乱数生成処理1回ごとに乱数の現在位置が1つ進むと仮定した場合)。

そして、実際に乱数テーブルを見ると、そのような数字A・Bが隣接している箇所はありません。これでは「レアアイテム」が出ないのではないでしょうか?

ファイナルファンタジーIVの乱数テーブル(10進数版)
7 182 240 31 85 91 55 227 174 79 178 94 153 246 119 203
96 143 67 62 167 76 45 136 199 104 215 209 194 242 193 221
170 147 22 247 38 4 54 161 70 78 86 190 108 110 128 213
181 142 164 158 231 202 206 33 255 15 212 140 230 211 152 71
244 13 21 237 196 228 53 120 186 218 39 97 171 185 195 125
133 252 149 107 48 173 134 0 141 205 126 159 229 239 219 89
235 5 20 201 36 44 160 60 68 105 64 113 100 58 116 124
132 19 148 156 150 172 180 188 3 222 84 220 197 216 12 183
37 11 1 28 35 43 51 59 151 27 98 47 176 224 115 204
2 74 254 155 163 109 25 56 117 189 102 135 63 175 243 251
131 10 18 26 34 83 144 207 122 139 82 90 73 106 114 40
88 138 191 14 6 162 253 250 65 101 210 77 226 92 29 69
30 9 17 179 95 41 121 57 46 42 81 217 93 166 234 49
129 137 16 103 245 169 66 130 112 157 146 87 225 61 241 249
238 8 145 24 32 177 165 187 198 72 80 154 214 127 123 233
118 223 50 111 52 168 208 184 99 200 192 236 75 232 23 248

しかし、そのような心配は無用です。実際の処理では、「お宝を残すかどうかの判定処理」が終わった後、「4種類のアイテムの選択処理」を行う直前に、乱数の現在位置を0〜255個分進めているからです。この「0〜255個分」ですが、ファイナルファンタジーIVのプログラムには「1/60秒ごとに常に1ずつ増加している16ビットのカウンタ」なるものがあり、このカウンタの下位8ビット分を使って乱数の現在位置を「0〜255個分」進めているのです。

さらに、戦闘中は常に「1/60秒ごとに乱数の現在位置を1ずつ増加する処理」も行っています。

これらの処理を行っているため、普通にゲームをプレイしているかぎりでは、「お宝を残すかどうかの判定」と「4種類のアイテムの選択処理」の2つは独立試行であると言えます(注3)。

(注1)

なぜ「0〜99」ではなくて「0〜98」の範囲で判定を行うのでしょうか? これは、通常の百分率が0〜100%の範囲なのに対して、ファイナルファンタジーIVにおける百分率は0〜99%の範囲になっているからです。普通、百分率で判定を行うとすると「0%: 必ず失敗」「100%: 必ず成功」ということになりますが、ファイナルファンタジーIVではこれが「0%: 必ず失敗」「99%: 必ず成功」となっているわけです。

(注2)

ちなみに、『ファイナルファンタジーIV イージータイプ』の場合、プリンプリンセスの「お宝を残す確率」は"2"に設定されているため、「25%」となっています(正確には「75/256(≒ 29.23%)」)。「プリンプリンセスからピンクのしっぽを入手できる確率」は「0.458%(約1/218)」となります。

(注3)

ただし、1回の戦闘で多数のモンスターを倒した場合だと、「独立試行」と言えるかどうかはかなり微妙です。宝箱入手判定は、戦闘終了時に倒したモンスターの分だけ繰り返し行われるので、「1/60秒」の間に何度も判定が行われることになります。その間は「1/60秒ごとに常に1ずつ増加している16ビットのカウンタ」の値は変化しませんし、「1/60秒ごとに乱数の現在位置を1ずつ増加する処理」も行われません。そのため、場合によっては「倒したモンスターの数に比べて、お宝の数が非常に多い(少ない)」とか「4種類のアイテムの内訳が偏っている」といったことが起こるかもしれません。

モンスター遭遇時のモンスターパーティ選択処理

ファイナルファンタジーVIにおいて、通常のモンスター出現の際には最大8種類のモンスターパーティの中から出現するモンスターが決まります。決定方法は単純で、0〜255の範囲の乱数値を取得して、その値の範囲によってモンスターパーティの種類が決まります。なお、アラームを使ってモンスターが出現する場合は、乱数値で255を取得したことにして判定されます(つまり、必ず「モンスターパーティ8」が出現する)。

8種類のモンスターパーティが選択される確率
乱数値 確率 モンスターパーティ
0〜42 43/256 モンスターパーティ1
43〜85 43/256 モンスターパーティ2
86〜128 43/256 モンスターパーティ3
129〜171 43/256 モンスターパーティ4
172〜203 32/256 モンスターパーティ5
204〜235 32/256 モンスターパーティ6
236〜251 16/256 モンスターパーティ7
252〜255 4/256 モンスターパーティ8

モンスターパーティ1〜8の実際の割り振りについては、ff_analyzerの『モンスター遭遇テーブルデータ(IV)(ff4monenc.txt)』をご覧ください。

「ぬすむ」処理

成功確率

「ぬすむ」を実行してアイテムを入手できる確率は、基本的には敵味方のレベルによって決まります(以下、「ぬすむ」を行うキャラクタのレベルを「自分レベル」、「ぬすむ」の対象となるモンスターのレベルを「相手レベル」と呼称します)。

まず、戦闘中のみに使用される「隠しパラメータ」が存在していて、戦闘開始時に初期値として「レベル + 10」の値が設定されています(モンスターの場合)。そして、この隠しパラメータは「ぬすむ」の成功率に影響していて、確率の計算式は「(自分レベル + 50 - 相手の隠しパラメータ) ÷ 99」となります。戦闘中に隠しパラメータが変動することはあまりないので、上記の式は「(自分レベル + 40 - 相手レベル) ÷ 99」と解釈しても問題ないでしょう。また、算出した成功率が0%以下になった場合でも、成功率は最低でも1%(正確には3/256(= 1.17%))はあります。

なお、この隠しパラメータは「うそなき」によって変動します。詳しくは『「うそなき」の効果』をご覧ください。

また、戦闘後に必ずお宝を残すモンスターの場合、「ぬすむ」の判定に成功してもアイテムを盗むことはできません。

モンスターに見つかる

「ぬすむ」の判定に失敗した場合、「モンスターにみつかった」となってダメージを受けることがあります。モンスターに見つかる確率についても上記の隠しパラメータが影響しています。具体的には、「相手の隠しパラメータ ÷ 99」の確率でモンスターに見つかります。この時にダメージを受けることがありますが、ダメージ値の算出方法は不明です(注1)。

(注1)

プログラムを見た限りでは、本来は「自分の最大ヒットポイントの1/16のダメージを受ける」という処理を意図していたようにも見えます。

「うそなき」の効果

ポロムの「うそなき」は、その効果が謎に包まれているコマンドです。攻略本には「敵が動揺して、逃亡することが多くなる」などと書かれていますが、実際には何度「うそなき」をしたところで敵が逃亡することはありません。

さて、上記の『「ぬすむ」処理』にて、盗み処理に関する「隠しパラメータ」が存在することについて説明しましたが、「うそなき」は敵全員の隠しパラメータを下げる効果があります。低下する値は「自分の隠しパラメータ ÷ 2」です。

そして、味方キャラクタの隠しパラメータは、戦闘開始時に初期値として「初登場時のレベル」と同じ値が設定されています。ポロムの場合、初登場レベルは10なので、この値が隠しパラメータの初期値として使用されます。従って、「うそなき」使用時に敵の隠しパラメータは「10 ÷ 2 = 5」ポイント下がることになります。

以上のことから「うそなき」の効果をわかりやすくまとめると、「盗みに成功する確率を5%上げる(& 盗み失敗時にモンスターに見つかる確率を5%下げる)」ということになります。

ただし、「ぬすむ」を使用できるエッジが仲間になるのは冒険の中盤以降であるのに対して、「うそなき」を使用できるポロムは冒険序盤の間しかパーティに加入しません。ですから、「うそなき」に盗み成功率を上げる効果があってもまったく意味がないわけです。おそらく、この隠しパラメータには盗み処理以外にもなんらかの働きがあるのでしょうが、現在のところは不明です。また、「うそなき」以外の要因で隠しパラメータが変動することがあるのかもしれませんが、こちらについても現在のところ不明です。

それにしても、この隠しパラメータは意味不明な存在です。敵モンスターの初期値「レベル + 10」はいいとして、味方キャラクタの初期値が「初登場時のレベル」というのはどういう意図があるのでしょうか。どうもパラメータの意味するところが見えてきません。

ファイナルファンタジーV

モンスター遭遇時のモンスターパーティ選択処理

ファイナルファンタジーVにおいて、通常のモンスター出現の際には最大4種類のモンスターパーティの中から出現するモンスターが決まります。決定方法は単純で、0〜255の範囲の乱数値を取得して、その値の範囲によってモンスターパーティの種類が決まります。

4種類のモンスターパーティが選択される確率
乱数値 確率 モンスターパーティ
0〜89 90/256 モンスターパーティ1
90〜179 90/256 モンスターパーティ2
180〜239 60/256 モンスターパーティ3
240〜255 16/256 モンスターパーティ4

モンスターパーティ1〜4の実際の割り振りについては、ff_analyzerの『モンスター遭遇テーブルデータ(V)(ff5monenc.txt)』をご覧ください。

青魔法「マイティガード」やレアアイテム「りゅうのひげ」を入手できることで有名な「スティングレイ」ですが、このモンスターは非常に出現率が低いことで知られています。実際、スティングレイは最も出現率が低い「モンスターパーティ4」に割り振られています(ff5monenc.txtのNo.110参照)。しかし、最も出現率が低いとはいえ確率は16/256(= 6.25%)はあるわけで、せいぜい30回程度も戦闘を繰り返せばたいてい遭遇できます。スティングレイの場合、その出現範囲が非常に限られている(注1)ことが、「出現しにくい」という印象をより強めているのでしょう。

(注1)

スティングレイが出現する場所は、第3世界の海域のごく一部分です。具体的には、『モンスター遭遇マップデータ(V)(ff5monmap.txt)』内で"110"とある場所です。位置的には、カーウェンの町の東にある湖と、沈んだウォルスの塔周辺の内海部分に相当します。

ファイナルファンタジーVI

モンスター遭遇時のモンスターパーティ選択処理

ファイナルファンタジーVIでは、通常モンスターの出現と固定モンスターの出現とを同じような処理として扱っています。また、獣ヶ原でのモンスター出現では独自のアルゴリズムが使われています。これらについて順に説明します。

通常モンスターの出現

通常モンスター出現の際には最大4種類のモンスターパーティの中から出現するモンスターが決まります。決定方法は単純で、0〜255の範囲の乱数値を取得して、その値の範囲によってモンスターパーティの種類が決まります。見てわかるように、ファイナルファンタジーVのアルゴリズムとほとんど同じです。

4種類のモンスターパーティが選択される確率
乱数値 確率 モンスターパーティ
0〜79 80/256 モンスターパーティ1
80〜159 80/256 モンスターパーティ2
160〜239 80/256 モンスターパーティ3
240〜255 16/256 モンスターパーティ4
固定モンスターの出現

固定モンスター出現の際には最大2種類のモンスターパーティの中から出現するモンスターが決まります。「固定モンスター」なのに「最大2種類」の中から決まるというのも変ですが、たいていの場合は「2種類」の両方に同じモンスターパーティが設定されているために完全に「固定」されています。魔大陸上空の帝国空軍のように、固定モンスター出現なのに出現するモンスターの種類がランダムで変わるようなケースの場合は、「2種類」に別々のモンスターパーティが設定されていて「最大2種類」となっているわけです。

モンスターパーティの決定方法は通常モンスターの出現と同じです。0〜255の範囲の乱数値を取得して、その値の範囲によってモンスターパーティの種類が決まります。

2種類のモンスターパーティが選択される確率
乱数値 確率 モンスターパーティ
0〜191 192/256 モンスターパーティ1
192〜255 64/256 モンスターパーティ2

通常モンスター出現時のモンスターパーティ1〜4、および固定モンスター出現時のモンスターパーティ1・2の実際の割り振りについては、ff_analyzerの『モンスター遭遇テーブルデータ(VI)(ff6monenc.txt)』をご覧ください。

「ぬすむ」処理

「ぬすむ」が成功する確率について調べてみました。「ぶんどる」についてはまだ調べていません。「とうぞくのナイフ」で攻撃した際に発動する「ぶんどる」についても調べていません。

成功確率

「ぬすむ」を実行してアイテムを入手できる確率は、「ぬすむ」を行うキャラクタのレベル(以下、「自分レベル」)と、「ぬすむ」の対象となるモンスターのレベル(以下、「相手レベル」)に影響されます。具体的な確率の計算式は「(自分レベル + 50 - 相手レベル) ÷ 99」となります。

このことから、自分レベルと相手レベルとの差が49以上になると、確率に関係なく「ぬすむ」の判定が成功(あるいは失敗)するということになります。例えば、「自分レベル - 相手レベル ≧ 49」という状態だと必ず成功します(注: 「ぬすむ」の判定が成功したからといって、必ずアイテムを入手できるわけではありません)。逆に、「相手レベル - 自分レベル ≧ 49」という状態だと必ず失敗します。

「とうぞくのうでわ」の効果

さて、ファイナルファンタジーVIには「とうぞくのうでわ」というアイテムが存在します。メニューでの説明には『「ぬすむ」の成功率がアップします』とあります。具体的にはどのような効果があるのでしょうか。

実際の効果を簡単に表現すると「盗める確率が2倍になる」といえます。前述した確率の計算式が「(自分レベル + 50 - 相手レベル)×2 ÷ 99」となります。注意すべき点は、「自分レベル + 50 - 相手レベル」の値が0(あるいはそれ以下)であるならば、確率が2倍になっても0は0なので意味はない、ということです。レベル差が49以上あるために盗めない場合は、「とうぞくのうでわ」を装備したところでやはり盗めないというわけです。

2種類のアイテムの選択処理

「ぬすむ」の判定に成功した後は、アイテムの選択処理が行われます。ファイナルファンタジーVIでは、盗めるアイテムには「低確率アイテム」「高確率アイテム」の2種類があります。判定処理は単純で、0〜255の範囲の乱数値を取得して、乱数値が32未満であれば「低確率アイテム」に、32以上であれば「高確率アイテム」になります。よって、「低確率アイテム」を入手できる確率は「32/256 = 1/8」となります。

実際にモンスターから入手できるアイテムについては、ff_analyzerの『モンスターの所持アイテムデータ(VI)(ff6monitem.txt)』をご覧ください。

なお、上記の『モンスターの所持アイテムデータ(VI)』によると、「低確率アイテムしか持っていないモンスター」や「高確率アイテムしか持っていないモンスター」も多数存在します。これらのモンスターに対して「持っていない方のアイテム」を盗んだ場合、「ぬすむ」に失敗したとみなされます。つまり、「低確率アイテムしか持っていないモンスター」から「高確率アイテム」を盗む場合や、「高確率アイテムしか持っていないモンスター」から「低確率アイテム」を盗む場合は、どちらも「ぬすむ」に失敗することになります。

ラグナロックのアイテム変化処理

成功確率

幻獣「ラグナロック」を使用した際にモンスターをアイテム変化できる確率(難易度)は、各モンスターによって決まっていて、それぞれ0〜7の8段階に分かれています。難易度の値と成功確率の関係は、以下のとおりです。

難易度と成功確率の関係
難易度 確率
0 256/256
1 192/256
2 128/256
3 64/256
4 32/256
5 16/256
6 8/256
7 0

各モンスターの難易度の値については、ff_analyzerの『モンスターのアイテム変化データ(VI)(ff6monragna.txt)』をご覧ください。

4種類のアイテムの選択処理

アイテム変化の判定に成功した後は、アイテムの選択処理が行われます。4種類のアイテムが選択される確率は、基本的にはそれぞれほぼ等確率です。

ドラゴンクエストV

宝箱入手判定時の処理

宝箱の入手確率(難易度)はモンスターごとに決まっていて、それぞれ0〜7の8段階に分かれています。公式ガイドブックではアイテムの落としやすさは★1〜3個で表されていますが、実際にはもっと細かく分かれているわけです。実際の難易度の値については、dq_analyzerの『モンスターの所持アイテムデータ(V)(dq5monitem.txt)』をご覧ください。

難易度の値と入手確率の関係は、以下のとおりです。

難易度と入手確率の関係
難易度 確率
0 1/1
1 1/8
2 1/16
3 1/32
4 1/64
5 1/128
6 1/256
7 1/4096

なお、詳しく調べたわけではありませんが、複数のグループからなるモンスターを倒した場合、宝箱を入手することができないようです。

それにしても、難易度7の「確率1/4096」というのはあまりにも低すぎます。公式ガイドブックでは難易度5〜7の確率をまとめて「★1個」としていますが、同じ★1個でも難易度6と7ではまったく確率が違うので注意しましょう。

会心の一撃が出る確率

味方キャラクタの攻撃で「会心の一撃」が出る確率は、1/32です。基本的に、ドラゴンクエストVでは会心の一撃が出やすいキャラクタなどは存在せず、どのキャラクタでも確率は同じようです。

なお、ノンプレイヤーキャラクタが攻撃する場合、内部ではモンスターの行動処理と同レベルで処理されているようで、上の会心の一撃の確率は当てはまりません。例えば、パパスの場合は6種類の行動のうち2つが「会心/痛恨の一撃(の可能性がある)」となっているので、通常のキャラクタよりもやや高い確率で会心の一撃を出します。

また、鞭やブーメランといった、会心の一撃が出ないように設定されている武器で攻撃した場合は、会心の一撃は出ません。

モンスターが仲間になるかどうかの判定処理

何かと謎の多い「モンスターが仲間になる確率」について調べてみました。実のところ、まだ調査の途中なのでほとんど謎は解明できていないのですが、とりあえず基本的な確率については調査が完了しました。

なお、調査の過程で、仲間モンスターに関するとんでもない裏技が隠されていることがわかりました。

モンスターを仲間にできる状況であるかどうかの判定処理

最初に、「モンスターを仲間にできる状況であるかどうか」の判定を行います。このあたりについてはまだ調査していませんが、主人公のレベルや現在の場所などが関係しているようです。後日調査する予定です。

モンスターが仲間になる確率

さて、「モンスターを仲間にできる状況である」場合、乱数値を取得してその値に基づいて仲間になるかどうかを判定します。仲間になる確率ですが、モンスターごとに設定されている「仲間になりやすさ」と、「(馬車かモンスターじいさんのところにいる)同種のモンスターの数」によって決まります。

まず、「仲間になりやすさ」は文字通りモンスターが仲間になる確率を示しています。公式ガイドブックでは「仲間になりやすさ」を♥1〜3個で表していますが、実際には0〜7の8段階のランクに分かれています。実際に設定されている値については、dq_analyzerの『モンスターのその他のデータ(V)(dq5monmisc.txt)』をご覧ください。

そして、馬車かモンスターじいさんのところに同種のモンスターがすでにいる場合、2匹目・3匹目のモンスターが仲間になる確率は下がります。また、すでに同種のモンスターが3匹いる場合は、4匹目が仲間になることはありません。なお、モンスターじいさんのところで別れたモンスターはカウントされません。

これらの2つの要素をもとにして、最終的な確率は以下のように決まります。

「仲間になりやすさ」と加入確率の関係
ランク 確率(1匹目) 確率(2匹目) 確率(3匹目)
0 0 0 0
1 1/256 1/1024 1/1024
2 1/64 1/128 1/256
3 1/32 1/64 1/128
4 1/16 1/64 1/64
5 1/4 1/64 1/64
6 1/2 1/64 1/64
7 1/2 1/32 1/16

2匹目からは確率が大きく低下していることがわかります。しかし、ランク7のモンスターの場合、2匹目よりも3匹目の方が仲間になりやすいことになっています。このあたりは意図したものなのか不具合なのか、よくわからないところです。

なお、公式ガイドブックには「仲間にできるモンスターは、戦闘の一番最後に倒すと、仲間になりやすい」とありますが、この件についてはまだ未調査です。

モンスターが必ず仲間になる裏技

さて、モンスターが仲間になるかどうかの判定処理には一つとんでもない処理が含まれています。それは、「主人公に特定のアイテムを特定の順番で持たせておくと、確率に関係なくモンスターが必ず仲間になる」というものです。

まずは、主人公に以下のアイテムを持たせてください。

  1. ひのきのぼう
  2. とがったホネ
  3. しあわせのぼうし
  4. こんぼう
  5. のこぎりがたな
  6. みかわしのふく

「ひのきのぼう」を主人公に装備させてはいけません。主人公にはこれら以外のアイテムを持たせてはいけませんし、アイテムの順番も変えてはいけません。

この状態で戦闘をすると、戦闘終了後「モンスターを仲間にできる状況である」状態ならば、確率に関係なくモンスターが必ず仲間になります。ただし、もともとモンスターが仲間にならない状況の場合は効果はありません。例えば、主人公のレベルが低かったり、すでに同種のモンスターが3匹仲間にいる場合などです。

この処理は、おそらくはデバッグやテスト用に用意されたものだと思われます。なお、「モンスターが仲間になる確率」の処理以外でも使われている箇所があるようです。少し調べた限りでは、「会心の一撃が出る確率」の処理で、必ず会心の一撃が出るという現象を確認しました。

予想されたことですが、プレイステーション2でリリースされたリメイク版には、この裏技は残っていませんでした。

ドラゴンクエストVI

宝箱入手判定時の処理

宝箱の入手確率(難易度)はモンスターごとに決まっていて、それぞれ0〜7の8段階に分かれています。公式ガイドブックではアイテムの落としやすさは★1〜3個で表されていますが、実際にはもっと細かく分かれているわけです。実際の難易度の値については、dq_analyzerの『モンスターの所持アイテムデータ(VI)(dq6monitem.txt)』をご覧ください。

難易度の値と入手確率の関係は、以下のとおりです。

難易度と入手確率の関係
難易度 確率
0 1/1
1 1/8
2 1/16
3 1/32
4 1/64
5 1/128
6 1/256
7 1/4096

見ての通り、ドラゴンクエストVの『宝箱入手判定時の処理』とまったく同じです。根拠のない予想ですが、ドラゴンクエストVIIでもまったく同じ確率なのではないかと思っています(上の表のランク1〜7が、公式ガイドブックの入手確率A〜Gに対応する)。

モンスターが仲間になるかどうかの判定処理

何かと謎の多い「モンスターが仲間になる確率」について調べてみました。実のところ、解析しきれなかった部分が多いのでまだまだ謎は解明できていないのですが、それについては今後調査していく予定です。

モンスターを仲間にできる状況であるかどうかの判定処理

最初に、「モンスターを仲間にできる状況であるかどうか」の判定を行います。このあたりについては未調査の部分が多いのですが、とりあえずは以下の条件を満たしている必要があります。

「熟練度の高低の判定」と「場所の判定」については、まだ解析できていません。ただ、「熟練度が高いと、仲間になる確率も高くなる」といったことはなさそうです。「熟練度の高低」は「(倒したモンスターを)仲間にできるか/できないか」だけに影響があるようです。

モンスターが仲間になる確率

さて、「モンスターを仲間にできる状況である」場合、乱数値を取得してその値に基づいて仲間になるかどうかを判定します。仲間になる確率ですが、モンスターごとに設定されている「仲間になりやすさ」と、「(馬車かルイーダの酒場にいる)同種のモンスターの数」によって決まります。

まず、「仲間になりやすさ」は文字通りモンスターが仲間になる確率を示しています。公式ガイドブックでは「仲間になりやすさ」を★1〜3個で表していますが、実際には0〜7の8段階のランクに分かれています。実際に設定されている値については、dq_analyzerの『モンスターのその他のデータ(VI)(dq6monmisc.txt)』をご覧ください。

そして、馬車かルイーダの酒場に同種のモンスターがすでにいる場合、2匹目・3匹目のモンスターが仲間になる確率は下がります。また、すでに同種のモンスターが3匹いる場合は、4匹目が仲間になることはありません。なお、ルイーダの酒場で別れたモンスターはカウントされません。

これらの2つの要素をもとにして、最終的な確率は以下のように決まります。

「仲間になりやすさ」と加入確率の関係
ランク 確率(1匹目) 確率(2匹目) 確率(3匹目)
0 0 0 0
1 1/256 0 0
2 1/256 1/1024 1/1024
3 1/64 1/1024 1/1024
4 1/32 1/256 1/256
5 1/16 1/256 1/256
6 1/4 1/128 1/256
7 1/2 1/32 1/128

2匹目からは確率が大きく低下していることがわかります。また、ランク1のモンスターは2匹目が仲間になりません。「ランプのまおう」が1匹しか仲間にならないのは、これが原因です。

なお、公式ガイドブックには「仲間になるモンスターが2種類以上登場したときは、あとに倒す方が仲間になりやすい」とありますが、この件についてはまだ未調査です。

モンスターが必ず仲間になる?

ドラゴンクエストVには「モンスターが必ず仲間になる裏技」が存在しますが、ドラゴンクエストVIにもそういったものはあるのでしょうか?

実は、モンスターが仲間になるかどうかの判定処理の中には「ある条件を満たすと、(乱数による判定処理をスキップして)必ず仲間になる」という処理が存在しています。しかし、その「ある条件」には「ROM内の特定のアドレスをリードして、特定のビットがONになっている(注1)」という条件が含まれています。そして、その「ROM内の特定のアドレス」には、出荷バージョンでは値"00"が設定されています。ですから、この条件は常に成立することはありません(注2)。おそらくは、デバッグ・テスト用途のために、開発者向けに用意されていたものなのでしょう。

どうにかして、実機でのプレイで「モンスターが必ず仲間になる処理」を有効に活用する方法はないものでしょうか。一応、まったく方法がないわけではありません。かなりの荒技ですが、カートリッジ端子の「接触不良」を利用するという方法があります。接触不良などでカートリッジ端子が接続されていない状態では、信号が強制的にON状態になります。これをうまく利用すれば、「ROM内の特定のアドレスをリード」する際に、読み込むアドレスや読み込む値が本来のものとは異なる値になるかもしれません。その結果、「モンスターが必ず仲間になる条件」を満たせる可能性があります。

しかしながら、このような方法は当然ながら危険です。接触不良を起こすための方法としては、「カートリッジに衝撃を与える」とか「カートリッジの斜め挿し」といった方法がありますが、どちらにせよ非常に危険な方法です。フリーズする程度ならまだしも、セーブデータに悪影響を与える可能性もあります。

実際に何度か試してみたところ(注3)、「成功」したことは一度もなく、たいていの場合にフリーズを引き起こしました。また、フリーズ後に冒険の書が消えることも何度かありました。やはり、この方法を実用化するのは無理なようです。

(注1)

正確な条件は、以下の2つの条件をともに満たす場合です。

(注2)

いわゆる「改造コード」を使えば条件を満たすことができるかもしれません(ROM領域の読み込み結果を改変できればの話ですが)。具体的には以下のようになります。

C1FFFF 80   (ROM領域)
7E3D00 11   ("10"だとモンスターが出現しない)

ただし、$C1FFFE〜$C1FFFFの値が"00"以外の値である場合、オープニングから先に進みません。出荷バージョンでこの処理が有効になることがないように、プロテクトをかけているようです。

(注3)

仲間モンスター判定処理前後のタイミング(「○○をやっつけた!」表示)の前後で、カートリッジを傾けたり、圧力をかけてみたりしました。

ドラゴンクエストI・II

宝箱入手判定時の処理

宝箱の入手確率(難易度)はモンスターごとに決まっていて、それぞれ0〜3の4段階に分かれています。詳しくは、dq_analyzerの『モンスターの所持アイテムデータ(II)(dq2monitem.txt)』をご覧ください。

難易度の値と入手確率の関係は、以下のとおりです。

難易度と入手確率の関係
難易度 確率
0 1/8
1 1/16
2 1/32
3 1/128

ドラゴンクエストIII

宝箱入手判定時の処理

宝箱の入手確率(難易度)はモンスターごとに決まっていて、それぞれ0〜7の8段階に分かれています。公式ガイドブックではアイテムの落としやすさは★1〜3個で表されていますが、実際にはもっと細かく分かれているわけです。実際の難易度の値については、dq_analyzerの『モンスターの所持アイテムデータ(III)(dq3monitem.txt)』をご覧ください。

難易度の値と入手確率の関係は、以下のとおりです。

難易度と入手確率の関係
難易度 確率
0 1/1
1 1/8
2 1/16
3 1/32
4 1/64
5 1/128
6 1/256
7 1/1024

ロマンシング サ・ガ2

技閃き判定時の処理

攻撃時に技を閃く確率について調べました。カウンター技や見切り技については未調査です。

技の派生関係

ロマンシング サ・ガ2において、攻撃時の技の閃きはすべて「ある技を使用した際に、ある技を閃く」というような「派生」の関係のもとにあります。実際の派生関係については、rs_analyzerの『技修得の各種データ(2)(rs2techlearndata.txt)』をご覧ください。

このリストの見方ですが、例えば、「通常攻撃: 剣(No.001)」で攻撃した場合、「なぎ払い(No.015)」「二段斬り(No.017)」「短冊斬り(No.018)」……「カマイタチ(No.036)」「稲妻斬り(No.037)」の全19種類のどれかを閃く可能性があることを示しています。同様に、「なぎ払い(No.015)」で攻撃した場合、「短冊斬り(No.018)」「十文字斬り(No.022)」「つむじ風(No.023)」「真空斬り(No.026)」の4種類のどれかを閃く可能性があるわけです。一般には後者の閃きを「派生」と呼ぶことが多いようですが、内部的には両者は同じ扱いになっています。

閃き条件

さて、実際の閃き処理について説明します。先ほどの「通常攻撃: 剣(No.001)」で攻撃した場合を例に挙げて説明すると、大まかな処理としては「なぎ払い(No.015)」から「稲妻斬り(No.037)」の順に閃くかどうかの判定を一つずつ行い、最後まで閃かなかった場合には剣での通常攻撃を行い、途中で閃いた場合はその閃いた技を使用する(閃き処理はその時点で打ち切り)、という流れになります。

個々の技の閃き処理ですが、いくつかの条件を満たしていないと、乱数による閃き判定を行う前に無条件で「閃き失敗」とみなされます。以下にその条件について説明します。

まず、技を閃こうとするキャラクタが混乱・魅了状態になっている場合は、技を閃かないようです。その他にも、技を閃かなくなる特定の状態が存在するようです。「特定の状態」が具体的に何であるかはわかっていません。

また、当然ですが、技欄に空きがない場合も閃きません。閃こうとする技をすでに修得している場合も閃きません。

そして、キャラクタごとの「閃きタイプ」をもとにして、これから閃こうとする技について、閃くことが可能であるかどうかをチェックします。各キャラクタには閃きタイプ16種類のうちのどれかが設定されています。そして、閃きタイプごとに、すべての技について閃き可能かどうかが設定されています。実際にキャラクタに設定されている「閃きタイプ」については『一般キャラクタのフラグ系データ(2)(rs2chrflag.txt)』『特殊キャラクタのフラグ系データ(2)(rs2chrspflag.txt)』を、閃きタイプごとの閃き可能・不可能については『技修得のフラグ系データ(2)(rs2techlearnflag.txt)』をご覧ください。この判定で、これから閃こうとする技が「閃き不可能」だった場合は閃きません。

それから、閃こうとする技が特定の技である場合は、特殊な条件を満たしていない場合は閃きません。「特定の技」に該当するのは「不動剣(No.028)」「活人剣(No.053)」「エイミング(No.099)」の3つです。「特殊な条件」が具体的に何であるかはわかっていません。

それとは逆に、閃こうとする技が特定の技の場合は、ある条件を満たしていると、乱数による判定を行わずに技を閃きます。具体的には、「でたらめ矢(No.134)」は技を閃こうとするキャラクタが「暗い」状態になっていると、無条件で閃きます。

これらの条件に当てはまらなかった場合、乱数による閃き判定に進みます。

閃き確率

閃き確率の算出には、「攻撃対象の武器レベルの平均値」と「技の閃き難易度」の値が使われます。まず、「攻撃対象の武器レベルの平均値」ですが、攻撃対象がモンスターの場合は5種類の武器レベルがすべて同じ値なので、単に「武器レベル」の値をそのまま使用します。実際の「武器レベル」の値については『モンスターの数値系データ(2)(rs2monparam.txt)』をご覧ください。

「技の閃き難易度」は、先ほどの『技修得の各種データ(2)(rs2techlearndata.txt)』に載っている値で、文字通り難易度が高いほど技を閃きにくくなります。注意すべき点として、同じ技でも「派生元」の技の種類によって難易度が異なることです。例えば、「ツバメ返し(No.046)」を閃こうとする場合、「通常攻撃: 大剣(No.002)」から閃こうとすると難易度は"40"となりますが、「切り落とし(No.045)」からだと難易度は"37"に、「強撃(No.043)」からだと難易度は"34"になります。

さて、実際の閃き確率の算出処理ですが、まずは「攻撃対象の武器レベルの平均値 - 技の閃き難易度」の値を求めます。そして、その値から以下の表をもとにして「閃き判定の乱数の境界値(以下、「境界値」)」を求めます。

閃き判定の乱数の境界値
差分値 乱数の境界値
-6以下 0
-5 1
-4 3
-3 5
-2 8
-1 11
0 50
1 18
2 21
3 24
4 26
5 28
6 29
7以上 30

ここで求めた「境界値」が大きいほど、技の閃きに成功しやすくなります。上の表を見るとわかりますが、「攻撃対象の武器レベルの平均値」と「技の閃き難易度」が一致した場合が、最も技を閃きやすくなるようです。

その後、乱数ルーチンから1〜255の範囲の乱数値を取得して、算出した境界値と比較して閃き判定を行います。具体的には、乱数値が境界値以下であれば、閃きに成功したことになります。よって、閃き成功確率は(およそ)「境界値 / 255」となります。

ところが、ロマンシング サ・ガ2の乱数ルーチンは得られる乱数値に偏りがあり、単純に「境界値 / 255」で計算すると微妙に誤差が生じます。例えば、境界値が"30"の場合だと、1〜255の範囲の乱数値で30以下が出れば閃きに成功することになるので、閃き成功確率は30/255(≒ 11.76%)であるように見えます。しかし、実際には乱数ルーチンが30以下を出す確率は25/255なので、正確な閃き成功確率も25/255(≒ 9.80%)となります。この乱数ルーチンの偏りを考慮した、より正確な閃き成功確率は以下のようになります。

境界値と成功確率の関係
境界値 成功確率
0 0
1 1/255
3 2/255
5 4/255
8 6/255
11 13/255
18 20/255
21 22/255
24 22/255
26 24/255
28 24/255
29 25/255
30 25/255
50 52/255

ここで、「覚えられない技」として有名な技である「トリプルヒット」と「ライフスティール」について見てみます。まず、「トリプルヒット」は『技修得の各種データ(2)(rs2techlearndata.txt)』のリスト中に存在していません。よって、「トリプルヒット」は(棍棒の通常攻撃からも「ダブルヒット」からも)閃くことはありません。

「ライフスティール」の方はリスト中に存在していて、小剣の通常攻撃から閃くことになっています。しかし、「閃き難易度」が"80"という極端に高い値になっています。モンスターの中で最も武器レベルが高いのはアルビオンの"43"ですから、「ライフスティール」を閃くのは事実上不可能であるということになります。

ですが、閃き難易度と武器レベルがとの差が大きすぎることが問題であるならば、「極端に武器レベルが高い味方キャラクタ相手に攻撃する」という方法をとれば可能性があるようにも見えます。すなわち、いわゆる「石化皇帝バグ」などによって武器レベルが50を超えたキャラクタを用意して、そのキャラクタに攻撃することで技の閃きをねらうというわけです。味方を攻撃する場合、前述したように、キャラクタが混乱・魅了状態になっている場合は技を閃くことはありませんが、敵がマリオネットを使ったことで攻撃目標が味方に変更された場合は通常どおり技を閃く判定が行われるようです。この方法ならば「ライフスティール」を閃くことができるのでしょうか?

しかし、この方法でも「ライフスティール」を閃くのは不可能だと思います。なぜなら、武器レベルの平均値を求める処理が8ビットで処理されているからです。平均値を求める処理では、まず5種類の武器レベルを合計して、その合計値を5で割るという処理を行っています。この「5種類の武器レベルの合計値」が8ビットで扱われているため、武器レベルが50を超えたキャラクタの場合、合計値がオーバーフローしてしまいます。結局、「武器レベルの平均値」はベストケースでも最大で51(= 255÷5)にしかならないため、「ライフスティール」を閃くのはやはり不可能でしょう。

戦闘終了後のアイテム入手時の処理

戦闘終了時に入手できるアイテムは、内部では「高確率で入手できるアイテム」「低確率で入手できるアイテム」の2種類が設定されています。詳しくはrs_analyzerの『モンスターの所持アイテムデータ(2)(rs2monitem.txt)』をご覧ください

2種類のアイテムを入手できる確率は、それぞれ約1/32(高確率)・約1/64(低確率)となっています。内部的な処理では、例えば「1/32」の確率計算の場合、「0〜31までの乱数値を取得して、値が0であれば判定成功」といった処理になっています。しかし、ロマンシング サ・ガ2の乱数ルーチンは得られる乱数値に偏りがあるため、この場合は正確に「1/32」の確率とはいえず、わずかに誤差があります。乱数ルーチンの挙動を考慮した上でのより正確な確率は、以下のようになります(注1)。

アイテム入手確率
アイテム 確率
高確率 6/255
低確率 3/255

実際の判定処理の流れですが、まずは高確率のアイテムについて、倒したモンスターの数だけ入手判定を行います。その後、低確率のアイテムについて、やはり倒したモンスターの数だけ入手判定を行います。そして、アイテムの入手判定に成功した時点で判定処理を打ち切って、アイテムを入手することになります。

(注1)

さらに正確な確率を求めるためには、アイテム入手判定を行う順番をも考慮しないといけません。アイテム入手判定には「高確率アイテムが先に判定される」「入手判定に成功した時点で入手判定処理を打ち切る」という2つの性質があるため、低確率アイテムを入手できる確率が低くなっている可能性があります。

ロマンシング サ・ガ3

技閃き判定時の処理

攻撃時に技を閃く確率と見切り技を閃く確率について調べました。カウンター技については未調査です。

技の派生関係

ロマンシング サ・ガ3において、攻撃時の技の閃きはすべて「ある技を使用した際に、ある技を閃く」というような「派生」の関係のもとにあります。実際の派生関係については、rs_analyzerの『技修得の各種データ(3)(rs3techlearndata.txt)』をご覧ください。

このリストの見方ですが、例えば、「剣(No.001)」で攻撃した場合、「なぎ払い(No.016)」「かすみ二段(No.017)」「失礼剣(No.018)」……「スケアーボイス(No.036)」「スターバースト(No.037)」の全19種類のどれかを閃く可能性があることを示しています。同様に、「なぎ払い(No.016)」で攻撃した場合、「十文字斬り(No.019)」「飛水断ち(No.020)」「龍尾返し(No.022)」「剣閃(No.028)」の4種類のどれかを閃く可能性があるわけです。一般には後者の閃きを「派生」と呼ぶことが多いようですが、内部的には両者は同じ扱いになっています。

(このあたりの基本的な原理は、ロマンシング サ・ガ2のものとほとんど変わりありません)

閃き条件

さて、実際の閃き処理について説明します。先ほどの「剣(No.001)」で攻撃した場合を例に挙げて説明すると、大まかな処理としては「なぎ払い(No.016)」から「スターバースト(No.037)」の順に閃くかどうかの判定を一つずつ行い、最後まで閃かなかった場合には剣での通常攻撃を行い、途中で閃いた場合はその閃いた技を使用する(閃き処理はその時点で打ち切り)、という流れになります。

個々の技の閃き処理ですが、いくつかの条件を満たしていないと、乱数による閃き判定を行う前に無条件で「閃き失敗」とみなされます。以下にその条件について説明します。

まず、閃こうとする技をすでに修得している場合は、当然ですが閃きません。また、武器固有技を閃こうとする場合はその武器で攻撃していないと閃きません。武器固有技でない場合は、技欄に空きがない場合も閃きません。

もう一つ、1戦闘中に閃くことのできる技の数は最大8つまでとなっています。これは、1人のキャラクタが8つということではなく、パーティ全員で8つです。この制限に触れた場合も閃きません。なお、見切り技の閃きは閃き回数に含まれません。カウンター技が閃き回数に含まれるかどうかはわかっていません。

他にも条件は存在すると思われますが、現時点では不明です。これらの条件をクリアした場合、乱数による閃き判定に進みます。

閃きタイプ

ここで、キャラクタごとの「閃きタイプ」をもとにして、これから閃こうとする技について、閃き適性があるかどうかをチェックします。閃き適性の有無によって、以後の閃き確率の計算が大きく異なります。

まず、各キャラクタには閃きタイプ11種類のうちのどれかが設定されています。そして、閃きタイプごとに、すべての技について閃き適性の有無が設定されています。実際にキャラクタに設定されている「閃きタイプ」については『キャラクタのフラグ系データ(3)(rs3chrflag.txt)』を、閃きタイプごとの閃き適性については『技修得のフラグ系データ(3)(rs3techlearnflag.txt)』をご覧ください。

この後、乱数による閃き判定に進むわけですが、閃き適性の有無によって閃き処理が分岐します。以下、2つの場合について順に説明します。

閃き確率(閃き適性がある技の場合)

閃き確率の算出には、主に「モンスターの閃きレベル」と「技の閃き難易度」の値が使われます。まず、「モンスターの閃きレベル」ですが、これは攻撃対象のモンスターに設定されている「閃きレベル」のことを示していて、この値が高いほど技を閃きやすくなります。実際の値については『モンスターの数値系データ(3)(rs3monparam.txt)』をご覧ください。

「技の閃き難易度」は、先ほどの『技修得の各種データ(3)(rs3techlearndata.txt)』に載っている値で、文字通り難易度が高いほど技を閃きにくくなります。注意すべき点として、同じ技でも「派生元」の技の種類によって難易度が異なることです。例えば、「残像剣」を閃こうとする場合、「剣(No.001)」から閃こうとすると難易度は"28"となりますが、「かすみ二段(No.017)」からだと難易度は"23"に、「分身剣(No.027)」からだと難易度は"15"になります。

さて、実際の閃き確率の算出処理ですが、まずは「モンスターの閃きレベル - 技の閃き難易度」の値を求めます。そして、その値から以下の表をもとにして「閃き判定の乱数の境界値(以下、「境界値」)」を求めます。2つのテーブルがありますが、キャラクタが「技の王冠がついている or 最大術ポイントが0である」か「技の王冠がついていない & 最大術ポイントが1以上である」かによって、どちらかのテーブルを選択します(注1)。

閃き判定の乱数の境界値
差分値 王冠有 or 最大JP0 王冠無 & 最大JP1以上
-10以下 0 0
-9 1 0
-8 2 0
-7 4 1
-6 6 3
-5 9 5
-4 12 8
-3 15 10
-2 18 13
-1 21 16
0 25 20
1 28 23
2 31 26
3 34 29
4 37 31
5 39 34
6 42 36
7 44 37
8 46 39
9 47 39
10以上 50 40

ここで求めた「境界値」が大きいほど、技の閃きに成功しやすくなります。なお、上の表を見るとわかりますが、「技の王冠がついていない & 最大術ポイントが1以上である」場合は境界値が低くなっています。つまり、技を閃きやすくするには術を極力修得しない方がよいということがいえます。

その後、「1戦闘中の閃き回数」によって境界値に対してマイナス修正がかかります。例えば、同じ戦闘中に他の技を1回閃いている場合、境界値の値が本来の値の7/8となります(端数切り捨て)。以降、閃き回数が2回・3回・4回……と増えるに従って、境界値の値も6/8・5/8・4/8……と減少していきます。なお、「1戦闘中の閃き回数」に見切り技の閃きは含まれません。カウンター技が閃き回数に含まれるかどうかはわかっていません。

最後に、ここで乱数ルーチンから1〜255の範囲の乱数値を取得して、ここまでに算出した最終的な境界値と比較して閃き判定を行います。具体的には、乱数値が境界値未満であれば、閃きに成功したことになります(この時点で境界値が1以下になっていた場合は、判定には必ず失敗することになります)。よって、閃き成功確率は(およそ)「(境界値 - 1) / 255」となります。

ところが、ロマンシング サ・ガ3の乱数ルーチンは得られる乱数値に偏りがあり、単純に「(境界値 - 1) / 255」で計算すると微妙に誤差が生じます。例えば、最終的な境界値が"11"の場合だと、1〜255の範囲の乱数値で10以下が出れば閃きに成功することになるので、閃き成功確率は10/255(≒ 3.92%)であるように見えます。しかし、実際には乱数ルーチンが10以下を出す確率は33/1024なので、正確な閃き成功確率も33/1024(≒ 3.22%)となります。この乱数ルーチンの偏りを考慮した、より正確な閃き成功確率は以下のようになります。

境界値と成功確率の関係
境界値 成功確率
0 0
1 0
2 9/1024
3 11/1024
4 14/1024
5 18/1024
6 21/1024
7 22/1024
8 24/1024
9 27/1024
10 30/1024
11 33/1024
12 37/1024
13 44/1024
14 50/1024
15 54/1024
16 60/1024
17 64/1024
18 73/1024
19 76/1024
20 82/1024
21 85/1024
22 91/1024
23 97/1024
24 97/1024
25 104/1024
26 108/1024
27 113/1024
28 117/1024
29 123/1024
30 128/1024
31 130/1024
32 132/1024
33 136/1024
34 141/1024
35 144/1024
36 148/1024
37 150/1024
38 161/1024
39 164/1024
40 168/1024
41 170/1024
42 182/1024
43 187/1024
44 188/1024
45 195/1024
46 198/1024
47 202/1024
48 205/1024
49 211/1024
50 214/1024
閃き確率(閃き適性がない技の場合)

閃き適性がない場合、閃き処理は単純化されたものとなります。まず、閃き適性がある場合の処理と同様に、「モンスターの閃きレベル - 技の閃き難易度」の値をもとに、表から「境界値」を求めます。このとき、王冠や最大術ポイントに関係なく「技の王冠がついている or 最大術ポイントが0である」方のテーブルを強制的に使用します。

ここで求めた「境界値」が1以上の場合、乱数ルーチンから0〜254の乱数値を取得して、"0"が出れば閃きに成功します。それ以外の場合はすべて閃き失敗となります。乱数ルーチンが"0"を出す確率は9/1024なので、この場合の閃き成功確率は9/1024(≒ 0.88%)で固定となります。このように、閃き適性がない場合は、「境界値」がいくら大きくても閃き成功確率は非常に低い値で一定となります。

ただし、閃き適性がある場合だと境界値が2以上ないと閃きに成功しないのに対して、閃き適性がない場合だと境界値が1以上で閃き成功の可能性があります。そして、境界値を求める際に、常に「技の王冠がついている or 最大術ポイントが0である」場合のテーブルを使用することができるので、閃き適性がない場合の方が有利なこともあります。

見切り技の閃き確率

見切り技の閃きにも、通常の技と同様に「モンスターの閃きレベル」と「見切り技の閃き難易度」の値が関係します。「見切り技の閃き難易度」の値については、『見切り技の各種データ(3)(rs3techevadedata.txt)』をご覧ください。

見切り技の閃き確率の算出は、基本的には前述の「閃き確率(閃き適性がある技の場合)」と同じです。ただし、技の王冠や最大術ポイントなどに関係なく、常に「技の王冠がついている or 最大術ポイントが0である」場合のテーブルを使用することになります。

さて、見切れない技として有名な「ゴブリンの脳天割り」について見てみます。「ゴブリンの閃きレベル」が"3"であるのに対して、「脳天割りの見切り閃き難易度」は"12"となっています。そうすると、「モンスターの閃きレベル - 技の閃き難易度」は"-9"となり、「境界値」は"1"となります。しかし、「境界値」が"1"の場合の閃き成功確率は0%であるため、やはり「ゴブリンから脳天割りの見切りを閃くのは不可能である」ということになります。

(注1)

ちなみに、技の王冠がつく条件は「(最大技ポイント + 5) ÷ (最大術ポイント + 5) ≧ 10」の式が成り立っている場合です。

戦闘終了後のキャラクタ成長処理

ロマンシング サ・ガ3では、キャラクタの成長システムに「経験値」のような概念がなく、戦闘終了後に「確率」によって各パラメータが成長するかどうかが決まります。ここでは、このキャラクタ成長システムを解析した結果について述べます。

各パラメータが成長する確率

最初に、各パラメータが成長する確率を計算します。パラメータが成長する確率の決まり方は『技閃き判定時の処理』での技閃き確率の決まり方と似ています。具体的には、まず「成長しやすさ」を決める値と「成長難易度」を決める値があり、この両者の差分値を求めます。そして、その値から以下の表をもとにして「成長判定の乱数の境界値(以下、「境界値」)」を求めます。ここで求めた「境界値」が大きいほど、パラメータが成長しやすくなります。

成長判定の乱数の境界値
差分値 乱数の境界値
-10以下 0
-9 0
-8 1
-7 1
-6 1
-5 1
-4 2
-3 3
-2 5
-1 8
0 16
1 32
2 36
3 40
4 50
5 60
6 60
7 70
8 80
9 90
10以上 100

ここで、この「成長しやすさ」と「成長難易度」の値について説明する前に、まずはこれらの値を算出するのに大きく関わりのあるデータについて説明しておきます。

リーダーモンスターの「技能上昇レベル」

「モンスターの技能上昇レベル」は、モンスターごとに設定されている数値で、この値が高いほど戦闘終了時にパラメータが上昇しやすくなります。基本的には「成長しやすさ」のベースとなる値です。実際の値については『モンスターの数値系データ(3)(rs3monparam.txt)』をご覧ください。

キャラクタの「成長特性」

各キャラクタには、各種パラメータの「成長特性」が設定されています。この値も「成長しやすさ」に関わりのある値です。実際の値については『キャラクタの成長特性データ(3)(rs3chrlvup.txt)』をご覧ください。

なお、「成長特性」が"255"(FFh)の場合、そのパラメータは(基本的には)成長しないことを意味します。

どのパラメータも成長しなかった戦闘の回数

キャラクタごとに、どのパラメータも成長しなかった戦闘の回数を記録するカウンタ(以下、「戦闘回数カウンタ」)が存在していて、戦闘終了時にパラメータの成長がなかった場合は、このカウンタが1増加します。この値は、武器/術レベルの「成長しやすさ」に影響します。

なお、どのキャラクタもパラメータが成長しなかった場合、パーティで最大ヒットポイントが最も低いキャラクタの最大ヒットポイントが1上昇しますが(後述)、ここでの成長によって「戦闘回数カウンタ」が0になることはありません。

さて、この「成長しやすさ」と「成長難易度」の値の算出方法について説明します。値の算出方法はパラメータごとに異なりますが、大きく分けて「最大ヒットポイント」「最大技ポイント/最大術ポイント」「各種武器レベル/術レベル」の3種類に分類されます。以下、順に説明します。

最大ヒットポイント

最大ヒットポイントの「成長しやすさ」の値は、「リーダーモンスターの技能上昇レベル」と「(キャラクタの)最大ヒットポイントの成長特性」との合計値です。「成長難易度」の値は、「現在の最大ヒットポイント×5÷128」となります。そして、前述の説明通り、「成長しやすさ」と「成長難易度」との差分値から「境界値」を決定します。

最大技ポイント/最大術ポイント

まずは、戦闘で技/術を使用したかどうかを判定します。剣/大剣・斧/棍棒・槍/小剣・弓・体術のどれかに属する技を使用していない場合、最大技ポイントが上昇する確率(境界値)は無条件で0となります。同様に、蒼竜・朱鳥・白虎・玄武・太陽・月のどれかに属する術を使用していない場合、最大術ポイントが上昇する確率(境界値)は無条件で0となります。

最大技(術)ポイントの「成長しやすさ」の値は、「最高値の武器(術)レベル×3 + その他の武器(術)レベル」です。「成長難易度」の値は、「現在の最大技(術)ポイント」です。そして、「成長しやすさ」と「成長難易度」との差分値から「境界値」を決定します。なお、前述の「成長特性」には、最大技(術)ポイントについての「成長特性」も設定されていますが、実際には使用されていないようです。

各種武器レベル/術レベル

武器/術レベルの場合も、まずは該当する系統の技/術を戦闘で使用したかどうかを判定します。例えば、剣/大剣レベルの判定では、剣/大剣に属する技を使用していない場合、剣/大剣レベルが上昇する確率(境界値)は無条件で0となります。他の武器/術レベルについても同様の判定を行います。

武器/術レベルの「成長しやすさ」の値は、「リーダーモンスターの技能上昇レベル」と「(キャラクタの)武器/術レベルの成長特性」と「戦闘回数カウンタ×20÷256」との合計値です。「成長難易度」の値は、「現在の武器/術レベル」です。そして、「成長しやすさ」と「成長難易度」との差分値から「境界値」を決定します。

武器/術レベルが高くなると(40を超えるあたりから)、何度も戦闘回数を重ねることでようやく武器/術レベルが上がるようになりますが、これは「戦闘回数カウンタ」による補正の効果です。

各パラメータの成長判定処理

次に、ここまでの過程で算出した「各パラメータが成長する確率(境界値)」に基づいて、各パラメータの成長判定処理を行います。

さて、成長判定を行うパラメータは全部で14種類ありますが、どのような順番で成長判定を行うかについては、キャラクタごとに決まっています。成長判定の順番は、『キャラクタの成長特性データ(3)(rs3chrlvup.txt)』の「成長タイプ」によって決まります。「成長タイプ」と「成長判定の順番」との関係は以下のとおりです。なお、なぜ「成長判定の順番」に意味があるのかについては後述します。

成長タイプと成長判定の順番
順番 タイプ0 タイプ1 タイプ2 タイプ3 タイプ4 タイプ5 タイプ6 タイプ7
1 剣/大剣 最大HP 太陽 最大HP 最大JP なし 最大WP
2 最大HP 槍/小剣 体術 最大WP 蒼龍 最大HP 最大JP
3 最大WP 剣/大剣 最大HP 最大WP 最大JP 朱鳥 最大WP 剣/大剣
4 槍/小剣 最大WP 槍/小剣 斧/棍棒 最大HP 白虎 槍/小剣 最大HP
5 斧/棍棒 なし 槍/小剣 槍/小剣 玄武 剣/大剣 蒼龍
6 最大JP 太陽 最大JP 最大JP 太陽 最大JP 朱鳥
7 最大WP 剣/大剣 最大HP 白虎
8 体術 斧/棍棒 剣/大剣 蒼龍 太陽 太陽 玄武
9 太陽 体術 蒼龍 蒼龍 朱鳥
10 最大JP 朱鳥 朱鳥 白虎 最大WP 斧/棍棒 太陽
11 蒼龍 蒼龍 白虎 白虎 玄武 槍/小剣 体術
12 朱鳥 朱鳥 玄武 玄武 剣/大剣 なし 蒼龍 槍/小剣
13 白虎 白虎 太陽 なし 剣/大剣 朱鳥 斧/棍棒
14 玄武 玄武 体術 体術 斧/棍棒 白虎 体術
15 なし なし 斧/棍棒 なし 斧/棍棒 体術 玄武 なし
16 なし なし なし なし なし なし なし なし

後は、この順番にしたがって成長判定を行っていきます。判定処理は各パラメータ共通で、乱数ルーチンから1〜255の範囲の乱数値を取得して、パラメータごとの境界値と比較して成長判定を行います。具体的には、乱数値が境界値未満であれば、パラメータが成長することになります。成長確率は(およそ)「(境界値 - 1) / 255」ということになります。しかし、ロマンシング サ・ガ3の乱数ルーチンは得られる乱数値に偏りがあるため、わずかに誤差があります。乱数ルーチンの挙動を考慮した上でのより正確な確率は、以下のようになります。

境界値と成長確率の関係
境界値 成長確率
0 0
1 0
2 9/1024
3 11/1024
4 14/1024
5 18/1024
6 21/1024
7 22/1024
8 24/1024
9 27/1024
10 30/1024
11 33/1024
12 37/1024
13 44/1024
14 50/1024
15 54/1024
16 60/1024
17 64/1024
18 73/1024
19 76/1024
20 82/1024
21 85/1024
22 91/1024
23 97/1024
24 97/1024
25 104/1024
26 108/1024
27 113/1024
28 117/1024
29 123/1024
30 128/1024
31 130/1024
32 132/1024
33 136/1024
34 141/1024
35 144/1024
36 148/1024
37 150/1024
38 161/1024
39 164/1024
40 168/1024
41 170/1024
42 182/1024
43 187/1024
44 188/1024
45 195/1024
46 198/1024
47 202/1024
48 205/1024
49 211/1024
50 214/1024
51 217/1024
52 223/1024
53 230/1024
54 232/1024
55 234/1024
56 236/1024
57 242/1024
58 244/1024
59 251/1024
60 254/1024
61 257/1024
62 262/1024
63 266/1024
64 272/1024
65 280/1024
66 289/1024
67 292/1024
68 294/1024
69 297/1024
70 300/1024
71 301/1024
72 307/1024
73 308/1024
74 312/1024
75 316/1024
76 317/1024
77 319/1024
78 321/1024
79 326/1024
80 329/1024
81 333/1024
82 340/1024
83 344/1024
84 347/1024
85 352/1024
86 355/1024
87 359/1024
88 362/1024
89 367/1024
90 372/1024
91 376/1024
92 380/1024
93 383/1024
94 386/1024
95 392/1024
96 395/1024
97 399/1024
98 404/1024
99 407/1024
100 412/1024
各パラメータの成長処理

成長判定に成功した場合、パラメータが上昇します。最大ヒットポイントの場合、成長一回につき「(体力÷4 + 2) + 乱数値(範囲: 1〜体力÷4)」ポイント上昇します。最大技(術)ポイントの場合は成長一回につき1ポイント、武器/術レベルの場合は成長一回につき1レベル上昇します。

ただし、すでにパラメータが最高値に達している場合は、成長判定に成功しても実際には成長しません。そして、それ以外の場合(実際に成長した場合)は、前述の「戦闘回数カウンタ(どのパラメータも成長しなかった戦闘の回数)」が0に戻ります。

さて、パラメータが成長した際にはもう一つ「全パラメータの成長確率(境界値)を一定値だけ下げる」という処理が行われます。先ほどの「成長判定の順番」が意味を持ってくるのはこの処理があるためです。つまり、一度の戦闘でいくつものパラメータが上昇するような場合(リーダーモンスターの技能上昇レベルが極端に高い場合など)に、成長判定の順番が後の方のパラメータほど成長確率が下がっていくわけです。

この「一定値」の具体的な値ですが、各技能レベルの合計値によって以下のように変化します。なお、各キャラクタの技能レベルには、武器レベル・術レベル以外にもう一つ(レベル扱いの)隠しパラメータが存在していて、ここの「各技能レベルの合計値」の算出にはその隠しパラメータの値も合計して計算します。

技能レベル合計値と確率低下修正値
合計値 確率低下修正値
0〜3 0
4〜15 1
16〜35 2
36〜63 3
64〜99 4
100〜143 5
144〜195 6
196〜255 7
256〜323 8
324〜399 9
誰も成長しなかった場合

以上の処理を全キャラクタの全パラメータに対して行っていきます。キャラクタが成長しなかった場合、そのキャラクタの「戦闘回数カウンタ(どのパラメータも成長しなかった戦闘の回数)」が1増加します。

そして、もしパーティのどのキャラクタも成長しなかった場合、パーティ内で最大ヒットポイントが最も低いキャラクタの最大ヒットポイントが1だけ上昇します(パーティ全員の最大ヒットポイントが999の場合を除く)。ここでは、前述の「成長特性」データで最大ヒットポイントの成長特性が"255"(FFh)の場合でも上昇します。

戦闘終了後のアイテム入手時の処理

戦闘終了時に入手できるアイテムは、内部では4種類設定されています。その内訳は「100%入手できるアイテム」「高確率で入手できるアイテム」「中確率で入手できるアイテム」「低確率で入手できるアイテム」の4種類です。詳しくはrs_analyzerの『モンスターの所持アイテムデータ(3)(rs3monitem.txt)』をご覧ください。

4種類のアイテムを入手できる確率は、それぞれ1/1(100%)・約1/16(高確率)・約1/32(中確率)・約1/64(低確率)となっています。内部的な処理では、例えば「1/16」の確率計算の場合、「0〜15までの乱数値を取得して、値が0であれば判定成功」といった処理になっています。しかし、ロマンシング サ・ガ3の乱数ルーチンは得られる乱数値に偏りがあるため、この場合は正確に「1/16」の確率とはいえず、わずかに誤差があります。乱数ルーチンの挙動を考慮した上でのより正確な確率は、以下のようになります(注1)。

アイテム入手確率
アイテム 確率
100% 1024/1024
高確率 85/1024
中確率 40/1024
低確率 24/1024

実際の判定処理の流れですが、基本的には入手確率の高いアイテムから順番に、倒したモンスターの数だけ入手判定を行っています。そして、アイテムの入手判定に成功した時点で判定処理を打ち切って、アイテムを入手することになります。アイテム入手判定を行う順番は、以下のようになります(注2)。

アイテム入手判定を行う順番
100% 高確率 中確率 低確率
モンスター1 1 6 11 16
モンスター2 2 7 12 17
モンスター3 3 8 13 18
モンスター4 4 9 14 19
モンスター5 5 10 15 20

また、入手できるアイテムを持ちきれない(アイテム欄に空きがない/すでにそのアイテムを最大個数所持している)場合、いったん入手判定処理を打ち切って、次のアイテムの入手判定処理が行われます。つまり、いわゆる「レアアイテム」を入手したい場合は、あらかじめ他の入手可能アイテムを持ちきれない状態にしておけば、ごくわずかながらレアアイテムの入手確率が上がることになります(注3)。

(注1)

さらに正確な確率を求めるためには、アイテム入手判定を行う順番をも考慮しないといけません。アイテム入手判定には「高確率アイテムが先に判定される」「入手判定に成功した時点で入手判定処理を打ち切る」という2つの性質があるため、中確率・低確率アイテムを入手できる確率がわずかながら低くなっている可能性があります。乱数表を詳しく調べればわかるはずなのですが、ほとんど誤差程度にしか違わないはずなので調べていません。

(注2)

この部分の処理を詳しく説明します。ここでは仮に、モンスターを3体倒した場合のアイテム入手判定を行うものとします。まずはこの3体のモンスターについて、「100%入手できるアイテム」から判定していきます(上の表中の"1"〜"3")。大部分のモンスターは「100%入手できるアイテム」を持っていないように設定されているので、無条件で判定に失敗します。

次に「高確率で入手できるアイテム」の入手判定を行います。例えば、ここでモンスター2のアイテム(表中の"7")について乱数による入手判定に成功した場合、この時点でいったん「高確率で入手できるアイテム」の入手判定処理を打ち切ります。そして、すでに「高確率で入手できるアイテム」を持ちきれるかどうかを判定します。持ちきれる場合は、この時点で入手判定処理を終了してアイテムを入手します。

入手アイテムを持ちきれない場合は入手判定処理が再開されるのですが、「高確率で入手できるアイテム」の続き(表中の"8")からではなく、「中確率で入手できるアイテム」の始め(表中の"11")から再開されます。その後は同様に入手判定処理を進めていき、最後(表中の"18")の入手判定までに一度も成功しなかった場合、アイテムは入手できないことになります。

(注3)

本当にごくわずかしか入手確率は上がりません。ほとんど誤差の範疇といえます。

出現モンスター決定の処理

ロマンシング サ・ガ3には、エンディングや攻略本ではその姿を見ることができるものの、実際のプレイでは出現しない、いわゆる「レアモンスター」が存在します。

これらのモンスターが実際に出現するのかどうかについて調べてみました。

最初に断っておきますが、ロマンシング サ・ガ3の出現モンスター決定処理はかなり複雑であるため、現段階では完全には解析しきれていません。ここでの調査結果も、ごく一般的(と思われる)ケースでの出現モンスター決定処理のみを解析したものであり、この調査結果に当てはまらない例外ケースも存在します。

また、処理の内容が複雑であるため、説明文が非常に煩雑でわかりにくくなってしまいました。

用語の説明

まずは、この項で使用する用語について説明しておきます。

リーダーモンスター・従属モンスター

モンスターのシンボルと接触した場合、内部的な処理では、モンスターパーティに追加するモンスターとして、まずはそのシンボルに属する種族からモンスターを1体選択します。このモンスターを、ここでは「リーダーモンスター」と呼びます。リーダーモンスターの種類によって、モンスターパーティの最大モンスター数・最大モンスターサイズ・編成パターンなどが決まります。また、『戦闘終了後のキャラクタ成長処理』では、リーダーモンスターの「技能上昇レベル」の大小がキャラクタのパラメータ上昇確率に大きく影響します。

そして、モンスターパーティにはリーダーモンスター以外の種類のモンスターも追加されます。リーダーモンスター以外の種類のモンスターを、ここでは「従属モンスター」と呼びます。モンスターパーティは一般に「1体以上のリーダーモンスター(単一種類)」+「0体以上の従属モンスター(複数種類)」からなります。

モンスターレベル

ロマンシング サ・ガ3では、戦闘を重ねるごとに出現するモンスターも徐々に強くなっていきます。これは、内部的に「モンスターレベル」というような値が存在していて、戦闘に勝利するとこの値が徐々に上昇していき、この値が高いほど強力なモンスターが出現するようになっているからです。

この「モンスターレベル」はモンスターの種族(全16種類)ごとに別々に記録されています。また、それに加えて従属モンスターのレベルも別に記録されています。そして、リーダーモンスターを決定する際には「種族ごとのモンスターレベル」を、従属モンスターを決定する際には「従属モンスターのレベル」をそれぞれ使用することになります。

モンスターレベル上昇処理

出現モンスターの決定には「モンスターレベル」が大きく関係していることについては前述しましたが、出現モンスター決定処理を説明する前に、まずはモンスターレベルがどのように上昇するかについて説明しておきます。

まず、戦闘に勝利した場合は必ず従属モンスターレベルの上昇処理が行われます。従属モンスターレベルの基本上昇値は、「(該当種族モンスターレベル - 従属モンスターレベル)÷16 (値がマイナスになる場合は0)」となります。さらに、この基本上昇値に、乱数によって0〜8までの修正値が加わります。

イベントバトルでない場合は、接触したシンボルに該当する種族のモンスターレベルの上昇処理が行われます。該当種族のモンスターレベルの基本上昇値は、「(従属モンスターレベル - 該当種族モンスターレベル)÷16 (値がマイナスになる場合は0)」となります。さらに、この基本上昇値に、乱数によって0〜8までの修正値が加わります。

なお、基本上昇値も修正値も0になった場合は、上昇値が0ということになり、モンスターレベルは上昇しません。

「乱数による0〜8までの修正値」の決定方法ですが、乱数ルーチンから0〜255の乱数値を取得して、その乱数値の範囲によって修正値が決まります。乱数値と修正値の関係については以下の表をご覧ください。

乱数値とレベル上昇修正値との関係
系統 +8Lv +7Lv +6Lv +5Lv +4Lv +3Lv +2Lv +1Lv ±0Lv
骸骨系 0 1〜2 3〜5 6〜9 10〜14 15〜20 21〜36 37〜68 69〜255
悪魔系 0 1〜2 3〜5 6〜9 10〜14 15〜20 21〜36 37〜68 69〜255
獣系 0 1〜2 3〜5 6〜9 10〜14 15〜20 21〜36 37〜68 69〜255
魚系 0 1〜2 3〜5 6〜9 10〜14 15〜20 21〜36 37〜68 69〜255
獣人系 0 1〜2 3〜5 6〜9 10〜14 15〜20 21〜36 37〜68 69〜255
植物系 0 1 2〜3 4〜6 7〜10 11〜16 17〜34 35〜71 72〜255
水棲系 0 1 2〜3 4〜6 7〜10 11〜15 16〜30 31〜61 62〜255
精霊系 0 1 2〜3 4〜6 7〜10 11〜15 16〜30 31〜61 62〜255
ゾンビ系 0 1〜2 3〜5 6〜9 10〜14 15〜20 21〜36 37〜68 69〜255
両棲系 0 1〜2 3〜5 6〜9 10〜14 15〜20 21〜36 37〜68 69〜255
蛇系 0 1 2〜3 4〜5 6〜8 9〜12 13〜26 27〜56 57〜255
無機系 0 1 2〜3 4〜6 7〜10 11〜15 16〜30 31〜61 62〜255
昆虫系 0 1 2〜3 4〜6 7〜10 11〜16 17〜34 35〜71 72〜255
鳥系 0 1 2〜3 4〜6 7〜10 11〜16 17〜34 35〜71 72〜255
亡霊系 0 1〜2 3〜5 6〜9 10〜14 15〜20 21〜36 37〜68 69〜255
妖精系 0 1〜2 3〜5 6〜9 10〜14 15〜20 21〜36 37〜68 69〜255
従属モンスター 0 1 2 3〜4 5〜7 8〜11 12〜18 19〜30 31〜255

乱数ルーチンの偏りを考慮に入れると、0〜8までのレベル上昇修正値のそれぞれの値をとる確率は以下のようになります。

各レベル上昇修正値をとる確率
系統 +8Lv +7Lv +6Lv +5Lv +4Lv +3Lv +2Lv +1Lv ±0Lv
骸骨系 9/1024 5/1024 8/1024 11/1024 27/1024 31/1024 70/1024 139/1024 724/1024
悪魔系 9/1024 5/1024 8/1024 11/1024 27/1024 31/1024 70/1024 139/1024 724/1024
獣系 9/1024 5/1024 8/1024 11/1024 27/1024 31/1024 70/1024 139/1024 724/1024
魚系 9/1024 5/1024 8/1024 11/1024 27/1024 31/1024 70/1024 139/1024 724/1024
獣人系 9/1024 5/1024 8/1024 11/1024 27/1024 31/1024 70/1024 139/1024 724/1024
植物系 9/1024 2/1024 7/1024 6/1024 13/1024 36/1024 75/1024 160/1024 716/1024
水棲系 9/1024 2/1024 7/1024 6/1024 13/1024 27/1024 68/1024 134/1024 758/1024
精霊系 9/1024 2/1024 7/1024 6/1024 13/1024 27/1024 68/1024 134/1024 758/1024
ゾンビ系 9/1024 5/1024 8/1024 11/1024 27/1024 31/1024 70/1024 139/1024 724/1024
両棲系 9/1024 5/1024 8/1024 11/1024 27/1024 31/1024 70/1024 139/1024 724/1024
蛇系 9/1024 2/1024 7/1024 4/1024 8/1024 20/1024 67/1024 127/1024 780/1024
無機系 9/1024 2/1024 7/1024 6/1024 13/1024 27/1024 68/1024 134/1024 758/1024
昆虫系 9/1024 2/1024 7/1024 6/1024 13/1024 36/1024 75/1024 160/1024 716/1024
鳥系 9/1024 2/1024 7/1024 6/1024 13/1024 36/1024 75/1024 160/1024 716/1024
亡霊系 9/1024 5/1024 8/1024 11/1024 27/1024 31/1024 70/1024 139/1024 724/1024
妖精系 9/1024 5/1024 8/1024 11/1024 27/1024 31/1024 70/1024 139/1024 724/1024
従属モンスター 9/1024 2/1024 3/1024 7/1024 6/1024 17/1024 38/1024 50/1024 892/1024

また、モンスターレベルには種族ごとに上限値が設定されています。以下に、種族ごとのモンスターレベル上限値を示します。

モンスターレベルの上限値
系統 上限Lv
骸骨系 159
悪魔系 168
獣系 155
魚系 168
獣人系 159
植物系 145
水棲系 131
精霊系 131
ゾンビ系 159
両棲系 159
蛇系 126
無機系 131
昆虫系 146
鳥系 153
亡霊系 159
妖精系 168
従属モンスター 158

これらを踏まえた上で、出現モンスター決定の処理について説明します。

リーダーモンスター決定処理

リーダーモンスターの決定処理は、基本的には、接触したシンボルが属する種族のモンスターの中から、現在のモンスターレベルに応じたレベルのモンスターが選択されます。ただし、現在のモンスターレベルの値がそのまま使用されるわけではなく、乱数などによる修正が加わります。

具体的な計算式は、「モンスターレベル×7÷8」+「乱数値(範囲: 1〜モンスターレベル÷8)」+「乱数値(範囲: 1〜モンスターレベル÷8)」+「パーティの人数」-「乱数値(範囲: 1〜8)」となります。整理して、「モンスターレベル±約12.5%」+「パーティの人数」-「乱数値(範囲: 1〜8)」とみなしてもよいでしょう(実際には端数切り捨ての関係上「±12.5%」よりも若干低めになります)。

しかし、乱数取得ルーチンでは「完全な乱数」が得られるわけではないため、実際には上記の計算式どおりにはなりません。これについては後で詳しく説明します。

ここで、「地域の最低モンスターレベル算出処理」を行います。場所ごとに「地域の最低モンスターレベル」が決まっていて、この値と先ほど求めたモンスターレベルとを比較して、大きい方の値が最終的なモンスターレベルとして使用されます。この「地域の最低モンスターレベル」にも、乱数などによる修正が加わります。具体的な計算式は、「地域の最低モンスターレベル」+「パーティの人数」-「乱数値(範囲: 1〜8)」となります。なお、「地域の最低モンスターレベル」については、具体的な値はまだわかっていません。

最終的なモンスターレベルが決まったら、その値に応じてリーダーモンスターが選択されます。モンスターレベルと選択されるモンスターとの関係については、rs_analyzerの『モンスター出現レベルデータ(リーダーモンスター)(3)(rs3monencmain.txt)』をご覧ください。なお、モンスターレベルとリーダーモンスターの種類とによって、モンスターパーティの最大モンスター数・最大モンスターサイズ・編成パターンなども同時に決まります。

表の見方ですが、例えば、無機系のシンボルと接触して、最終的なモンスターレベルが"147"になったとします。この場合、"147"は「144以上(160未満)」であるため、リーダーモンスターとしてNo.9のゴールデンバウムが選択されます。また、「最大数」の項目が"3"となっているため、モンスターパーティは(リーダーモンスターを含めて)最大で3体までということになります。

ここで、モンスターパーティの最大モンスター数が"1"と決まった場合、この時点(リーダーモンスター決定時)でのモンスター数がすでに"1"であるため、出現モンスター決定処理はここで終了となります。

従属モンスタータイプの判別

リーダーモンスターの種類が決まった後は、従属モンスターの決定処理に移ります。ここで、「従属モンスタータイプ」によって従属モンスターの決定処理が大きく異なります。

「従属モンスタータイプ」は従属モンスターにどのようなモンスターが選択されるかを決める値で、おそらくは場所ごとに設定されています。従属モンスタータイプは全部で16種類あり、タイプ0〜14は従属モンスターが全種族のモンスターから選択され、タイプ15は従属モンスターはリーダーモンスターと同種族のモンスターから選択されます。

この後、従属モンスター決定処理に進むわけですが、従属モンスタータイプによって処理が2通りに分岐します。以下、この2つの場合について順に説明します。

従属モンスター決定処理(タイプ0〜14)

従属モンスタータイプが0〜14の場合、通常の従属モンスター決定処理となります。まずは、リーダーモンスターを何体か増加して、その後、従属モンスタータイプごとに対応する「従属モンスターテーブル」から従属モンスターを選択して追加していきます。

リーダーモンスター増加処理

まずは、リーダーモンスターを増加する処理を行います。基本的には、以下のような処理の流れで、最終的なリーダーモンスターの数が決定します。

  1. 以下の処理を「モンスターパーティの最大モンスター数 - 現在のモンスター数」回繰り返す(なお、この時点では「現在のモンスター数」は1)。
    1. 計算により「境界値」を決定する。
    2. 1〜15の範囲の乱数値を取得する。
    3. 乱数値が境界値未満である場合は、リーダーモンスターを1体増加する。

「境界値」の計算処理ですが、境界値の基本値は「(リーダーモンスター決定時の)最終的なモンスターレベル」を16で割った余りの値となります。その値に「(最終的なモンスターレベル - 従属モンスターレベル)÷16 (値がマイナスになる場合は0)」を加えて、「現在のモンスター数」を引きます。この値が最終的な境界値となります(値がマイナスになる場合は0)。

この処理の内容から、以下のような傾向があると言えそうです。

従属モンスター選択処理

次に、従属モンスターを選択する処理を行います。処理の流れは以下のようになります。

  1. 計算により「境界値」を決定する。
  2. 以下の処理を「モンスターパーティの最大モンスター数 - 現在のモンスター数」回繰り返す。
    1. 1〜15の範囲の乱数値を取得する。
    2. 乱数値が境界値未満である場合は、「従属モンスター選択・追加処理」を行う。
    3. 従属モンスターの追加処理に成功した場合は、「境界値」を1減らす。

構造としては先ほどの「リーダーモンスター増加処理」と似ていますが、ループごとに「境界値」を計算し直さない点が異なります。

「境界値」の計算処理も「リーダーモンスター増加処理」とほとんど同じです。境界値の基本値は「(リーダーモンスター決定時の)最終的なモンスターレベル」を16で割った余りの値となります。その値に「(最終的なモンスターレベル - 従属モンスターレベル)÷16 (値がマイナスになる場合は0)」を加えて、さらに「4」を加えて、「現在のモンスター数」を引きます。この値が最終的な境界値となります(値がマイナスになる場合は0)。

さて、「従属モンスター選択・追加処理」の詳しい内容について説明します。この部分は「リーダーモンスター決定処理」と少し似ていて、現在の従属モンスターレベルに応じたレベルの従属モンスターが選択されます。ただし、現在の従属モンスターレベルの値がそのまま使用されるわけではなく、乱数などによる修正が加わります。

具体的な計算式は、「モンスターレベル×7÷8」+「乱数値(範囲: 1〜モンスターレベル÷8)」+「乱数値(範囲: 1〜モンスターレベル÷8)」+「4」-「乱数値(範囲: 1〜8)」となります。整理して、「モンスターレベル±約12.5%」+「4」-「乱数値(範囲: 1〜8)」とみなしてもよいでしょう(実際には端数切り捨ての関係上「±12.5%」よりも若干低めになります)。

そして、やはり「リーダーモンスター決定処理」と同様に、「地域の最低モンスターレベル算出処理」も行います。処理の内容は、前述のものと同じです。この値と先ほど求めたモンスターレベルとを比較して、大きい方の値が最終的なモンスターレベルとして使用されます。

最終的なモンスターレベルが決まったら、その値に応じて従属モンスターが選択されます。モンスターレベルと選択されるモンスターとの関係については、『モンスター出現レベルデータ(従属モンスター)(3)(rs3monencsub.txt)』をご覧ください。

表の見方ですが、例えば、従属モンスタータイプ2で、最終的なモンスターレベルが"169"になったとします。この場合、"169"は「168以上(172未満)」であるため、従属モンスターとしてNo.3のウエットルビーが選択されます。

しかし、ここで選択されたモンスターが必ず従属モンスターとして追加されるわけではありません。「最大種類数の判定」と「最大モンスターサイズの判定」とを行い、判定に失敗した場合は追加されません。

「最大種類数の判定」では、モンスターパーティ内のモンスターの種類が3種類を超えるかどうかの判定を行います。ロマンシング サ・ガ3では、モンスターパーティに含まれるモンスターは最大3種類となっています。そのため、すでに3種類のモンスターが含まれている状態で、従属モンスターとして4種類目となるモンスターが選択された場合は、追加に失敗します。

「最大モンスターサイズの判定」では、追加しようとする従属モンスターのサイズが大きすぎないかどうかの判定を行います。「リーダーモンスター決定処理」で説明しましたが、モンスターレベルとリーダーモンスターの種類とによって、モンスターパーティの最大モンスターサイズが決まっています。もしも、追加しようとする従属モンスターのサイズが最大モンスターサイズよりも大きかった場合は、追加に失敗します。各モンスターのサイズについては、『モンスターのその他のデータ(3)(rs3monmisc.txt)』をご覧ください。

ここまでの「従属モンスター選択・追加処理」を、追加判定に成功するまで3回まで行います。3回とも追加判定に失敗した場合、ここで「従属モンスター選択処理」自体を打ちきります。前述の通り、「従属モンスター選択処理」は『「モンスターパーティの最大モンスター数 - 現在のモンスター数」回繰り返す』ことになっているのですが、この場合は残りの処理も行われず、出現モンスター決定処理は終了となります。

従属モンスター決定処理(タイプ15)

従属モンスタータイプが15の場合、特殊な従属モンスター決定処理となります。まず、タイプ0〜14の場合と異なり、「リーダーモンスター増加処理」は行いません。また、「従属モンスター選択処理」において、従属モンスターは「従属モンスターテーブル」からは選択されず、リーダーモンスターと同種族のモンスターからのみ選択されます。処理の流れは以下のようになります。

  1. 以下の処理を「モンスターパーティの最大モンスター数 - 現在のモンスター数」回繰り返す。
    1. 「従属モンスター選択処理」を行う。
    2. 計算により「境界値」を決定する。
    3. 1〜15の範囲の乱数値を取得する。
    4. 乱数値が境界値未満である場合は、「従属モンスター追加処理」を行う。

「従属モンスター選択処理」は「リーダーモンスター決定処理」のそれと同じ処理です。種族モンスターレベルをもとにモンスターレベルを算出して、「地域の最低モンスターレベル」を算出して大きい方の値を選択して、最終的なその値に応じて従属モンスターが選択されます。「リーダーモンスター決定処理」と同じ処理を行っているので、ここで選択される従属モンスターはリーダーモンスターと同種族のモンスターになります。

「境界値」の計算処理は「リーダーモンスター増加処理」のそれと同じ処理です。境界値の基本値は「(従属モンスター決定時の)最終的なモンスターレベル」を16で割った余りの値となります。その値に「(最終的なモンスターレベル - 従属モンスターレベル)÷16 (値がマイナスになる場合は0)」を加えて、「現在のモンスター数」を引きます。この値が最終的な境界値となります(値がマイナスになる場合は0)。

「従属モンスター追加処理」では、「最大種類数の判定」と「最大モンスターサイズの判定」とを行い、判定に失敗した場合は追加に失敗します。

「レアモンスター」は出現するのか

さて、冒頭で紹介したいわゆる「レアモンスター」が出現することがあるのかどうかについて、検証してみます。

まず、『モンスター出現レベルデータ(リーダーモンスター)(3)(rs3monencmain.txt)』にも『モンスター出現レベルデータ(従属モンスター)(3)(rs3monencsub.txt)』にも入っていないモンスターは、(少なくともここで解析している出現処理においては)出現する可能性はありません。よって、ヤマ・スフィンクスは出現しないことになります。

リーダーモンスターとして出現する可能性

トウテツ・蒼天女・ザッハーク・ワンダーラストの4体については、『モンスター出現レベルデータ(リーダーモンスター)(3)(rs3monencmain.txt)』のテーブルの中に入っています。これらのレアモンスターがリーダーモンスターとして出現する可能性について考察してみます。

まず、「リーダーモンスター決定処理」における計算式をもとに、モンスターレベルが最高値をとる場合を考えてみます。そうすると、「種族モンスターレベルが最高値」で「パーティ人数が6人」の状態で、理想的な(都合のいい)乱数値が出た場合に、モンスターレベルが最高値になることがわかります。このように、モンスターレベルが計算上の理想値をとった場合に、そのモンスターレベルに対応する出現モンスターは以下のようになります。

計算上の理想値をとった場合の出現モンスター
系統 上限Lv 修正後Lv 対応モンスター
獣系 155 178 トウテツ
植物系 145 167 ウエットルビー
蛇系 126 145 ザッハーク
鳥系 153 176 ワンダーラスト

この計算結果を見る限りでは、蒼天女を除く3体のモンスターは、リーダーモンスターとして出現する可能性があるように見えます。

しかし、乱数ルーチンの処理の関係上、「理想的な乱数値」がうまく出てくれるかどうかの検証が必要です。まず、ロマンシング サ・ガ3の乱数ルーチンは乱数表から1つずつ数値を拾って乱数値を取得しているアルゴリズムであるため、乱数生成の試行は独立ではありません。つまり、3回連続で乱数値を取得した場合に3回とも理想的な乱数値が出るには、乱数表の中に理想的な乱数値が3つ並んでいる箇所がないといけないわけです。

さらに、戦闘開始時には「乱数表内の現在位置」を変更する処理があり、これが「リーダーモンスター決定処理」に大きな影響を及ぼしています。

ロマンシング サ・ガ3のメモリ内には、プレイ時間をカウントするために1/60秒ごとに1ずつ増加するカウンタが存在します。このカウンタの初期値は0で、60に達したときにプレイ時間を1秒増やし、カウンタを0に戻します。

そして、敵シンボルと接触した際に、その時点でのカウンタを16倍した値を「現在位置」の初期値とする処理が行われます。その後、戦闘開始時の処理の中で最初に乱数を使用するのは「リーダーモンスター決定処理」です。よって、出現モンスター決定処理において、乱数値の出方は60通りしかないということになります。従って、各種条件(シンボルの種類・種族モンスターレベル・従属モンスターレベル・地域ごとの最低モンスターレベル・パーティ人数)が同じ場合、とりうるモンスターパーティの編成も高々60通りしかないということになります。

そうなると、「計算上の理想値」を満たすための「理想的な乱数値」が出ることを期待するのは難しくなります。60通りの中で最高値をとった場合に出現するモンスターは以下のようになります。

実際の最高値をとった場合の出現モンスター
系統 上限Lv 修正後Lv 対応モンスター
獣系 155 172 キマイラ
植物系 145 160 ウエットルビー
蛇系 126 142 ドラゴンパンジー
鳥系 153 170 ブラックドラゴン

結局のところ、トウテツ・ザッハーク・ワンダーラストの3体のモンスターも、リーダーモンスターとして出現する可能性はないようです。

参考までに、内部のモンスターレベルが上限値まで上昇している(& パーティの人数が6人いる)状態で、各ランクのモンスターがどの程度の確率で出現するかをまとめた表を以下に示します。

モンスターレベル上限値における出現モンスターのランク
系統 ランク6 ランク7 ランク8 ランク9 ランク10 ランク11 ランク12
骸骨系 0 0 1/60 28/60 30/60 1/60 0
悪魔系 0 0 0 9/60 28/60 23/60 0
獣系 0 0 3/60 36/60 21/60 0 0
魚系系 0 0 0 9/60 28/60 23/60 0
獣人系 0 0 1/60 28/60 30/60 1/60 0
植物系 0 0 22/60 37/60 1/60 0 0
水棲系 0 19/60 38/60 3/60 0 0 0
精霊系 0 19/60 38/60 3/60 0 0 0
ゾンビ系 0 0 1/60 28/60 30/60 1/60 0
両棲系 0 0 1/60 28/60 30/60 1/60 0
蛇系 0 26/60 34/60 0 0 0 0
無機系 0 19/60 38/60 3/60 0 0 0
昆虫系 0 0 14/60 41/60 5/60 0 0
鳥系 0 0 8/60 38/60 14/60 0 0
亡霊系 0 0 1/60 28/60 30/60 1/60 0
妖精系 0 0 0 9/60 28/60 23/60 0
従属モンスターとして出現する可能性

蒼天女・ザッハークの2体については、『モンスター出現レベルデータ(従属モンスター)(3)(rs3monencsub.txt)』のテーブルの中に入っています。これらのレアモンスターが従属モンスターとして出現する可能性について考察してみます。

蒼天女は従属モンスタータイプ6の地域で出現することになっていて、出現モンスターレベルは"182"となっています。しかし、従属モンスターレベルが最高値(158)の状態で、(乱数ルーチンの処理を無視して)理想的な乱数値が出たケースを想定しても、最終的なモンスターレベルは"179"にしかならないため、蒼天女が出現する可能性はなさそうです。

ザッハークは従属モンスタータイプ10〜13の地域で出現することになっていて、出現モンスターレベルはいずれも"160"となっています。この値は、従属モンスターレベルが高ければ達成できる値です。しかし、「従属モンスター選択・追加処理」には「最大モンスターサイズの判定」の処理があります。ザッハークのサイズは16×20であり、このサイズのモンスターが従属モンスターとして追加できるケースはありません。というわけで、ザッハークの方も出現する可能性はないようです。

技術資料

この文書を作成するにあたって、実際に解析したプログラムコードを以下に示します。

ファイナルファンタジーIV

乱数生成

;________________________________________________________________
;
; 乱数生成
;   [入力]
;       Xレジスタ:  乱数値域の下限値
;       Aレジスタ:  乱数値域の上限値
;   [出力]
;       Aレジスタ:  乱数値
;   [使用]
;       $97:        乱数テーブル内の現在位置(1バイト)
;       $1900:      乱数テーブル(256バイト)
;________________________________________________________________
;
L038379:
        SEP     #$10
        STX     $96         ; $96にX(乱数値域の下限値)を格納する
        CPX     #$FF
        BNE     $8383       ; X(乱数値域の下限値)が255でなければ次の処理に進む

        BRA     $83B6       ; X(乱数値域の下限値)が255であればサブルーチンを終了する

L038383:
        CMP     #$00
        BEQ     $83B6       ; A(乱数値域の上限値)が0であればサブルーチンを終了する

        CMP     $96
        BEQ     $83B6       ; A(乱数値域の上限値)とX(下限値)が同じ値であればサブルーチンを終了する

        LDX     $97         ; Xに乱数位置を格納する
        SEC
        SBC     $96         ; A(乱数値域の上限値)から$96の内容(下限値)を減算した値がAに入る
        CMP     #$FF
        BNE     $8399       ; A(乱数値域の上限値と下限値との差)が255でなければ次の処理に進む

        LDA     $1900,X     ; 乱数テーブルのX(乱数位置)番目から乱数値を取得して、Aに格納する
        BRA     $83B6       ; サブルーチンを終了する(ジャンプ先は$83B4の方が適切では?)

L038399:
        INC     A
        STA     $3947       ; $3947の内容(除数の下位バイト)にA(乱数値域の上限値と下限値との差 + 1)を格納する
        STZ     $3948       ; $3948の内容(除数の上位バイト)を0クリアする
        LDA     $1900,X     ; 乱数テーブルのX(乱数位置)番目から乱数値を取得して、Aに格納する
        TAX                 ; Aの内容をXにコピーする
        STX     $3945       ; $3945(被除数)にX(乱数値)を格納する
        REP     #$10
        JSR     $8407       ; 除算サブルーチンをコールする
        SEP     #$10
        CLC
        LDA     $394B       ; Aに$394B(乱数値÷(乱数値域の上限値と下限値との差 + 1)の余)を格納する
        ADC     $96         ; Aと$96(乱数値域の上限値)を加算した値がAに入る
        INC     $97         ; $97(乱数位置)を1つ進める

L0383B6:
        REP     #$10
        RTS

;________________________________________________________________
;
; 除算(16ビット÷16ビット)
;   [入力]
;       $3945:  被除数(2バイト)
;       $3947:  除数(2バイト)
;   [出力]
;       $3949:  商(2バイト)
;       $394B:  余(2バイト)
;________________________________________________________________
;
L038407:
        REP     #$20
        STZ     $3949
        STZ     $394B
        LDA     $3945
        BEQ     $843F       ; $3945(被除数)が0であればサブルーチンを終了する

        LDA     $3947
        BEQ     $843F       ; $3947(除数)が0であればサブルーチンを終了する

        CLC
        LDX     #$0010      ; Xをループカウンタとして使用する

L03841D:
        ROL     $3945
        ROL     $394B
        SEC
        LDA     $394B
        SBC     $3947
        STA     $394B
        BCS     $8439

        LDA     $394B
        ADC     $3947
        STA     $394B
        CLC

L038439:
        ROL     $3949
        DEX
        BNE     $841D

L03843F:
        TDC
        SEP     #$20
        RTS
;________________________________________________________________
;
; 乱数生成(0〜98の範囲)
;   [出力]
;       Aレジスタ:  乱数値
;________________________________________________________________
;
L03858B:
        TDC                 ; D(おそらく0)の内容をAにコピーする
        TAX                 ; A(0)の内容をXにコピーする
        LDA     #$62        ; Aに98を格納する
        JSR     $8379       ; 乱数生成サブルーチンをコールする
        RTS
;________________________________________________________________
;
; 乱数生成(0〜255の範囲)
;   [出力]
;       Aレジスタ:  乱数値
;________________________________________________________________
;
L038593:
        TDC                 ; D(おそらく0固定)の内容をAにコピーする
        TAX                 ; A(0)の内容をXにコピーする
        LDA     #$FF        ; Aに256を格納する
        JSR     $8379       ; 乱数生成サブルーチンをコールする
        RTS
/*________________________________________________________________
 *
 *  乱数生成
 *  [入力]
 *      range_low:  乱数値域の下限値
 *      range_high: 乱数値域の上限値
 *  [出力]
 *      ret:        乱数値
 *  [使用]
 *      index:      乱数位置
 *      tbl_rnd:    乱数テーブル
 *________________________________________________________________
 */
static int index = 0;   /* 便宜上、初期値を0としておく */
extern const int tbl_rnd[256];
int get_rnd(int range_low, int range_high)
{
    int ret;

    /* 範囲のチェック */
    if (range_low >= 255)
        return range_low;
    if (range_high <= 0)
        return range_high;
    if (range_low == range_high)
        return range_high;

    /* 0〜0xffまでの範囲の乱数を求める場合 */
    if (range_high - range_low == 255)
        return tbl_rnd[index];  /* この場合、indexが増加しない */

    /* それ以外の範囲の乱数を求める場合 */
    ret = range_low + (tbl_rnd[index] % (range_high - range_low + 1));
    index = (index + 1) & 0xff;

    return ret;
}

ファイナルファンタジーIVで主に使用されている乱数生成ルーチンです。乱数の上限値と下限値を設定してからこのルーチンをコールすると、その範囲内の乱数値を取得できる、というものです。

上にも書きましたが、この乱数にはけっこう偏りがあります。ある範囲内の乱数値を求める際にはよく「X mod N」という方法が使われますが、このアルゴリズムでは範囲Nに比べて乱数の最大値Xが十分に大きな値でないと乱数に偏りが出てしまいます。まあ、しょせんゲームに使う乱数ですから、乱数の質が悪くても表立って問題にはならないでしょうけど。

ちょっと気になるのが、乱数値の範囲として0〜255が指定された場合、乱数の現在位置が移動しないということです。仮に、0〜255の範囲の乱数を取得する処理が連続で行われてることがあったとしたら、乱数値として毎回同じ値が返ってくることになります(戦闘中であれば、常に「1/60秒ごとに乱数の現在位置を1ずつ増加する」処理を行っているので問題ありませんが)。プログラム中のコメントにも書きましたが、どうもジャンプ先アドレスが間違っているような気がします。

$1900以降のRAM領域には、ROMからコピーされた乱数テーブルが格納されています。乱数テーブルの初期化処理は以下のようになっています。ちなみに、この乱数テーブルはファイナルファンタジーIV〜VIのすべてで共通のものが使用されています。

;________________________________________________________________
;
; 乱数テーブル初期化
;________________________________________________________________
;
L15CA05:
;       (略)

        LDX     #$0000

L15CA0F:
        LDA     $14EE00,X   ; ROMから乱数表データを取得して……
        STA     $1900,X     ; ……RAMに格納する
        INX
        CPX     #$0100
        BNE     $CA0F

        RTL

L14EE00:
        DB      $07,$B6,$F0,$1F,$55,$5B,$37,$E3,$AE,$4F,$B2,$5E,$99,$F6,$77,$CB
        DB      $60,$8F,$43,$3E,$A7,$4C,$2D,$88,$C7,$68,$D7,$D1,$C2,$F2,$C1,$DD
        DB      $AA,$93,$16,$F7,$26,$04,$36,$A1,$46,$4E,$56,$BE,$6C,$6E,$80,$D5
        DB      $B5,$8E,$A4,$9E,$E7,$CA,$CE,$21,$FF,$0F,$D4,$8C,$E6,$D3,$98,$47
        DB      $F4,$0D,$15,$ED,$C4,$E4,$35,$78,$BA,$DA,$27,$61,$AB,$B9,$C3,$7D
        DB      $85,$FC,$95,$6B,$30,$AD,$86,$00,$8D,$CD,$7E,$9F,$E5,$EF,$DB,$59
        DB      $EB,$05,$14,$C9,$24,$2C,$A0,$3C,$44,$69,$40,$71,$64,$3A,$74,$7C
        DB      $84,$13,$94,$9C,$96,$AC,$B4,$BC,$03,$DE,$54,$DC,$C5,$D8,$0C,$B7
        DB      $25,$0B,$01,$1C,$23,$2B,$33,$3B,$97,$1B,$62,$2F,$B0,$E0,$73,$CC
        DB      $02,$4A,$FE,$9B,$A3,$6D,$19,$38,$75,$BD,$66,$87,$3F,$AF,$F3,$FB
        DB      $83,$0A,$12,$1A,$22,$53,$90,$CF,$7A,$8B,$52,$5A,$49,$6A,$72,$28
        DB      $58,$8A,$BF,$0E,$06,$A2,$FD,$FA,$41,$65,$D2,$4D,$E2,$5C,$1D,$45
        DB      $1E,$09,$11,$B3,$5F,$29,$79,$39,$2E,$2A,$51,$D9,$5D,$A6,$EA,$31
        DB      $81,$89,$10,$67,$F5,$A9,$42,$82,$70,$9D,$92,$57,$E1,$3D,$F1,$F9
        DB      $EE,$08,$91,$18,$20,$B1,$A5,$BB,$C6,$48,$50,$9A,$D6,$7F,$7B,$E9
        DB      $76,$DF,$32,$6F,$34,$A8,$D0,$B8,$63,$C8,$C0,$EC,$4B,$E8,$17,$F8

お宝入手時の処理

;________________________________________________________________
;
; お宝入手時の処理(戦闘勝利時の処理)
;________________________________________________________________
;
L03EC72:
        TDC
        TAX
        STX     $3591       ;
        STX     $3593       ; 獲得経験値の合計値を0に初期化する
        STX     $3594       ;
        STX     $3595       ; 獲得ギルの合計値を0に初期化する
        STX     $B5         ; 入手アイテム数を0に初期化する
        STX     $B7

L03EC84:
        LDX     $B7
        LDA     $3585,X
        STA     $B1
        BNE     $EC90       ;
        JMP     $ED68       ; モンスターを1体も倒していない場合は最後までジャンプする

L03EC90:
        LDX     $B7
        LDA     $358B,X
        STA     $AF
        STZ     $B0
        ASL     $AF
        ROL     $B0
        LDX     $AF
        CLC                 ;
        LDA     $0EA1C0,X   ;
        ADC     $3591       ;
        STA     $3591       ;
        LDA     $0EA1C1,X   ;
        ADC     $3592       ;
        STA     $3592       ;
        LDA     $3593       ;
        ADC     #$00        ;
        STA     $3593       ; 獲得経験値の合計値に加算する

        LDX     $B7
        LDA     $3588,X
        STA     $AF
        STZ     $B0
        ASL     $AF
        ROL     $B0
        LDX     $AF
        CLC                 ;
        LDA     $0EA000,X   ;
        ADC     $3594       ;
        STA     $3594       ;
        LDA     $0EA001,X   ;
        ADC     $3595       ;
        STA     $3595       ;
        LDA     $3596       ;
        ADC     #$00        ;
        STA     $3596       ; 獲得ギルの合計値に加算する

        LDX     $B7
        LDA     $358E,X
        STA     $B3
        LDA     $358E,X

        AND     #$C0        ; お宝を入手できる確率を示す2ビットの領域を取得する
        CMP     #$C0        ;
        BEQ     $ED0F       ; "11"(3)の場合、無条件でお宝入手後の処理にジャンプする

        CMP     #$40
        BNE     $ED00

        LDA     #$05        ; "01"(1)の場合、お宝を入手できる確率は5%となる
        BRA     $ED06

L03ED00:
        CMP     #$80
        BNE     $ED5F       ; ("00"(0)の場合、無条件でお宝は入手できない)

        LDA     #$19        ; "10"(2)の場合、お宝を入手できる確率は25%となる

L03ED06:
        STA     $B4         ; お宝を入手できる確率を$B4に格納する
        JSR     $858B       ; 乱数生成サブルーチンをコールして、0〜98の範囲の乱数値を取得する
        CMP     $B4         ; 乱数値と$B4(お宝を入手できる確率)とを比較して……
        BCS     $ED5F       ; ……乱数値が$B4(お宝を入手できる確率)以上であればお宝は入手できない

L03ED0F:
        ASL     $B3
        ASL     $B3
        LDA     $B3
        TAX
        TDC
        TAY
        STY     $A9

L03ED1A:
        LDA     $0E9F00,X   ; お宝として残すアイテムを読み込む
        STA     $289C,Y
        INX
        INY
        INC     $A9         ;
        LDA     $A9         ;
        CMP     #$04        ;
        BNE     $ED1A       ; アイテム4種類分繰り返す

        LDA     $16A3       ;
        ADC     $97         ;
        STA     $97         ; $97(現在の乱数位置)に$16A3(16ビットのカウンタの下位8ビット)を加算する

        JSR     $8593       ; 乱数生成サブルーチンをコールして、0〜255の範囲の乱数値を取得する

        CMP     #$80        ; 乱数値と128とを比較して……
        BCS     $ED3D       ; ……乱数値が128以上であれば次の処理に進む

        LDA     #$00        ; (乱数値が128未満(0〜127)の場合)入手するアイテムは1番目となる
        BRA     $ED4F       ; アイテム選択処理を終了する

L03ED3D:
        CMP     #$D0        ; 乱数値と208とを比較して……
        BCS     $ED45       ; ……乱数値が208以上であれば次の処理に進む

        LDA     #$01        ; (乱数値が208未満(128〜207)の場合)入手するアイテムは2番目となる
        BRA     $ED4F       ; アイテム選択処理を終了する

L03ED45:
        CMP     #$FC        ; 乱数値と252とを比較して……
        BCS     $ED4D       ; ……乱数値が252以上であれば次の処理に進む

        LDA     #$02        ; (乱数値が252未満(208〜251)の場合)入手するアイテムは3番目となる
        BRA     $ED4F       ; アイテム選択処理を終了する

L03ED4D:
        LDA     #$03        ; (乱数値が252〜255の場合)入手するアイテムは4番目(「レアアイテム」)となる

L03ED4F:
        TAX
        LDA     $289C,X
        LDX     $B5         ;
        CPX     #$0008      ;
        BEQ     $ED5F       ; $B5(入手アイテム数)が8個ならば、入手アイテム欄にアイテムを追加しない

        STA     $1804,X     ; 入手アイテム欄にアイテムを追加する
        INC     $B5         ;

L03ED5F:
        DEC     $B1         ;
        LDA     $B1         ;
        BEQ     $ED68       ;
        JMP     $EC90       ; 倒したモンスターの数だけ繰り返す

L03ED68:
        INC     $B7         ;
        LDA     $B7         ;
        CMP     #$03        ;
        BEQ     $ED73       ;
        JMP     $EC84       ; モンスター3種類分繰り返す

L03ED73:
;       (略)

戦闘勝利時の処理からお宝入手時の処理の部分を抜き出してみました。経験値・ギル獲得の処理、そしてお宝入手関連の処理を、倒したモンスターの数だけ繰り返しています。

モンスター遭遇時のモンスターパーティ選択処理

;________________________________________________________________
;
; モンスター遭遇時のモンスターパーティ選択処理
;________________________________________________________________
;
L008CF2:
        STA     $3D
        STZ     $3E
        ASL     $3D
        ROL     $3E
        ASL     $3D
        ROL     $3E
        ASL     $3D
        ROL     $3E
        LDA     $C0
        BNE     $0D21       ; アラームを使ってのモンスター出現の場合はジャンプする

        LDA     $87
        TAX
        LDA     $14EE00,X
        CLC
        ADC     $17EE
        INC     $87
        BNE     $0D23

        LDA     $17EE
        CLC
        ADC     #$11
        STA     $17EE
        JMP     $8D23

L008D21:
        LDA     #$FF        ; アラームを使ってのモンスター出現の場合は、乱数値のかわりに固定値$FF(255)を使う

L008D23:
        LDX     $3D
        CMP     #$2B        ; 乱数値と43とを比較して……
        BCC     $0D48       ; ……乱数値が43未満(0〜42)であれば、サブルーチンの最後にジャンプする

        INX
        CMP     #$56        ; 乱数値と86とを比較して……
        BCC     $0D48       ; ……乱数値が86未満(43〜85)であれば、サブルーチンの最後にジャンプする

        INX
        CMP     #$81        ; 乱数値と129とを比較して……
        BCC     $0D48       ; ……乱数値が129未満(86〜128)であれば、サブルーチンの最後にジャンプする

        INX
        CMP     #$AC        ; 乱数値と172とを比較して……
        BCC     $0D48       ; ……乱数値が172未満(129〜171)であれば、サブルーチンの最後にジャンプする

        INX
        CMP     #$CC        ; 乱数値と204とを比較して……
        BCC     #$0D48      ; ……乱数値が204未満(172〜203)であれば、サブルーチンの最後にジャンプする

        INX
        CMP     #$EC        ; 乱数値と236とを比較して……
        BCC     $0D48       ; ……乱数値が236未満(204〜235)であれば、サブルーチンの最後にジャンプする

        INX
        CMP     #$FC        ; 乱数値と252とを比較して……
        BCC     $0D48       ; ……乱数値が252未満(236〜251)であれば、サブルーチンの最後にジャンプする

        INX                 ; (ここに到達するのは乱数値が252〜255の場合)

L008D48:
        STX     $3D
        RTS

「ぬすむ」処理

;________________________________________________________________
;
; 「ぬすむ」処理
;________________________________________________________________
;
L03E1CF:
        LDA     #$17
        STA     $34C8
        LDA     #$10
        STA     $34C7
        LDA     #$F8
        STA     $33C6
        LDA     #$04
        STA     $33C7
        JSR     $85B1
        LDA     $CE
        BMI     $E1ED

        JMP     $E23C

L03E1ED:
        JSR     $858B       ; 乱数生成サブルーチンをコールして、0〜98の範囲の乱数値を取得する
        STA     $A9
        CLC
        LDA     #$32        ; $32(50)に……
        ADC     $2682       ; ……自分のレベルを加算して……
        SEC                 ;
        SBC     $272F       ; ……相手の隠しパラメータ(初期値は相手のレベル + 10)を減算した値が成功確率となる
        BCS     $E202

        LDA     #$01        ; 成功確率がマイナスになった場合、成功確率を1%に設定する
        BRA     $E208

L03E202:
        CMP     #$63        ; 成功確率と$63(99)とを比較して……
        BCC     $E208

        LDA     #$63        ; 成功確率が$63(99)を超えていた場合、成功確率を99%(必ず成功する)に設定する

L03E208:
        CMP     $A9         ; 成功確率と乱数値とを比較して……
        BCS     $E242       ; 成功確率が乱数値以上であれば、盗み成功処理にジャンプする

        JSR     $858B       ; 乱数生成サブルーチンをコールして、0〜98の範囲の乱数値を取得する
        CMP     $272F       ; 乱数値と相手の隠しパラメータとを比較して……
        BCC     $E23C       ; 

        REP     #$20
        LDA     $2689       ; 自分の最大ヒットポイントを……
        JSR     $8484       ; ……16で除算する
        STA     $A9
        LDA     #$0000
        SEP     #$20
        LDA     $CD
        JSR     $CA62       ; 不明
        LDA     $A9         ;
        STA     $34D4,X     ;
        LDA     $AA         ;
        STA     $34D5,X     ; 受けるダメージの値を設定する
        JSR     $CA6E       ; 不明
        LDA     #$1C        ; 表示するメッセージ番号は$1C("モンスターにみつかった")
        STA     $34CA
        BRA     $E241

L03E23C:
        LDA     #$1B        ; 表示するメッセージ番号は$1B("ぬすみそこなった")
        STA     $34CA

L03E241:
        RTS

L03E242:
        LDA     $2773       ;
        AND     #$C0        ;
        CMP     #$C0        ; 必ずアイテムを落とす敵の場合……
        BNE     $E24C       ;

        RTS                 ; ……アイテムは盗めない("ぬすみそこなった"の表示も出ない)

L03E24C:
        TDC                 ;
        INC                 ;
        STA     $AA         ; 盗むアイテムの個数を1に設定する
        LDA     $2773       ;
        AND     #$3F        ;
        JSR     $847F       ;
        TAX                 ;
        LDA     $0E9F00,X   ; 盗んだアイテムの番号を取得する
        BEQ     $E23C       ; アイテム0番の場合、盗み失敗処理にジャンプ

        STA     $A9         ;
        CMP     #$61        ;
        BCS     $E26D       ; アイテム番号が$61(97)以上(= 矢ではない)の場合はジャンプ
        CMP     #$54        ;
        BCC     $E26D       ; アイテム番号が$54(84)未満(= 矢ではない)の場合はジャンプ

        LDA     #$0A        ;
        STA     $AA         ; 矢の場合は盗む個数を10に設定する

L03E26D:    
        TDC
        TAX
        TXY

        (略)

L03E2C4:
        JSR     $E2D2
        LDA     $A9
        STA     359A
        LDA     #$1D        ; 表示するメッセージ番号は$1D("(アイテム名) を ぬすんだ")
        STA     $34CA
        RTS

「うそなき」の効果

;________________________________________________________________
;
; 「うそなき」処理
;________________________________________________________________
;
L03EAE9:
        LDA     #$12
        STA     $34C8
        LDA     #$10
        STA     $34C7
        LDX     $A6
        LDA     $202F,X     ; 自分の隠しパラメータ(初期値は初期レベルと同じ値)を取得して……
        LSR                 ; ……2で割る(この値の分だけ相手の隠しパラメータを下げる)
        STA     $A9
        LDX     #$0005
        STX     $AB

L03EB00:
        LDX     $AB
        LDA     $3540,X
        BNE     $EB1C

        TXA
        JSR     $8489       ; 不明
        LDX     $A6
        SEC
        LDA     $202F,X     ; 相手の隠しパラメータを取得する
        SBC     $A9         ; 相手の隠しパラメータから$A9(自分の隠しパラメータの半分)を減算する
        BEQ     $EB17       ; 計算結果が0になった場合、1にする

        BCS     $EB19

L03EB17:
        LDA     #$01        ; 計算結果が0以下の値になった場合、1にする

L03EB19:
        STA     $202F,X     ; 最終結果を相手の隠しパラメータをして格納する

L03EB1C:
        INC     $AB         ;
        LDA     $AB         ;
        CMP     #$0D        ;
        BNE     $EB00       ; 敵8体分繰り返す

        LDA     #$13        ; 表示するメッセージ番号は$1C("まものを あわてさせた")
        STA     $34CA
        JMP     $85A6

ファイナルファンタジーV

乱数生成

;________________________________________________________________
;
; 乱数生成(モンスターが出現するかどうかを判定する処理で使用)
;   [出力]
;       Aレジスタ:  乱数値
;   [使用]
;       $4F:        乱数テーブル内の現在位置(1バイト)
;       $0B60:      乱数テーブルの値に加算する値(1バイト)
;       $C0FEC0:    乱数テーブル(256バイト)
;________________________________________________________________
;
LC0CC52:
        PHX
        INC     $4F         ; $4F(乱数位置)を1つ進める
        BNE     $CC60       ; $4F(乱数位置)が0でなければ次の処理に進む

        LDA     $0B60       ;
        CLC                 ;
        ADC     #$11        ;
        STA     $0B60       ; $0B60(乱数に加算する値)に17を加算する

LC0CC60:
        LDA     $4F         ;
        TAX                 ; Xに乱数位置を格納する
        LDA     $C0FEC0,X   ; 乱数テーブルのX(乱数位置)番目から乱数値を取得して、Aに格納する
        CLC                 ;
        ADC     $0B60       ; 乱数値に$0B60(乱数に加算する値)を加算した値がAに入る
        PLX
        RTS
;________________________________________________________________
;
; 乱数生成(どのモンスターパーティが出現するかを選択する処理で使用)
;   [出力]
;       Aレジスタ:  乱数値
;   [使用]
;       $50:        乱数テーブル内の現在位置(1バイト)
;       $0B5F:      乱数テーブルの値に加算する値(1バイト)
;       $C0FEC0:    乱数テーブル(256バイト)
;________________________________________________________________
;
LC0CC6D:
        PHX
        INC     $50         ; $50(乱数位置)を1つ進める
        BNE     $CC7B       ; $50(乱数位置)が0でなければ次の処理に進む

        LDA     $0B5F       ;
        CLC                 ;
        ADC     #$17        ;
        STA     $0B5F       ; $0B5F(乱数に加算する値)に23を加算する

LC0CC7B:
        LDA     $50         ;
        TAX                 ; Xに乱数位置を格納する
        LDA     $C0FEC0,X   ; 乱数テーブルのX(乱数位置)番目から乱数値を取得して、Aに格納する
        CLC                 ;
        ADC     $0B5F       ; 乱数値に$0B5F(乱数に加算する値)を加算した値がAに入る
        PLX
        RTS
;________________________________________________________________
;
; 乱数テーブル
;________________________________________________________________
;
LC0FEC0:
        DB      $07,$B6,$F0,$1F,$55,$5B,$37,$E3,$AE,$4F,$B2,$5E,$99,$F6,$77,$CB
        DB      $60,$8F,$43,$3E,$A7,$4C,$2D,$88,$C7,$68,$D7,$D1,$C2,$F2,$C1,$DD
        DB      $AA,$93,$16,$F7,$26,$04,$36,$A1,$46,$4E,$56,$BE,$6C,$6E,$80,$D5
        DB      $B5,$8E,$A4,$9E,$E7,$CA,$CE,$21,$FF,$0F,$D4,$8C,$E6,$D3,$98,$47
        DB      $F4,$0D,$15,$ED,$C4,$E4,$35,$78,$BA,$DA,$27,$61,$AB,$B9,$C3,$7D
        DB      $85,$FC,$95,$6B,$30,$AD,$86,$00,$8D,$CD,$7E,$9F,$E5,$EF,$DB,$59
        DB      $EB,$05,$14,$C9,$24,$2C,$A0,$3C,$44,$69,$40,$71,$64,$3A,$74,$7C
        DB      $84,$13,$94,$9C,$96,$AC,$B4,$BC,$03,$DE,$54,$DC,$C5,$D8,$0C,$B7
        DB      $25,$0B,$01,$1C,$23,$2B,$33,$3B,$97,$1B,$62,$2F,$B0,$E0,$73,$CC
        DB      $02,$4A,$FE,$9B,$A3,$6D,$19,$38,$75,$BD,$66,$87,$3F,$AF,$F3,$FB
        DB      $83,$0A,$12,$1A,$22,$53,$90,$CF,$7A,$8B,$52,$5A,$49,$6A,$72,$28
        DB      $58,$8A,$BF,$0E,$06,$A2,$FD,$FA,$41,$65,$D2,$4D,$E2,$5C,$1D,$45
        DB      $1E,$09,$11,$B3,$5F,$29,$79,$39,$2E,$2A,$51,$D9,$5D,$A6,$EA,$31
        DB      $81,$89,$10,$67,$F5,$A9,$42,$82,$70,$9D,$92,$57,$E1,$3D,$F1,$F9
        DB      $EE,$08,$91,$18,$20,$B1,$A5,$BB,$C6,$48,$50,$9A,$D6,$7F,$7B,$E9
        DB      $76,$DF,$32,$6F,$34,$A8,$D0,$B8,$63,$C8,$C0,$EC,$4B,$E8,$17,$F8
/*________________________________________________________________
 *
 *  乱数生成(モンスターが出現するかどうかを判定する処理で使用)
 *  [出力]
 *      戻り値:     乱数値
 *  [使用]
 *      index:      乱数テーブル内の現在位置
 *      base:       乱数テーブルの値に加算する値
 *      tbl_rnd:    乱数テーブル
 *________________________________________________________________
 */
static int index = 0;   /* 便宜上、初期値を0としておく */
static int base = 0;    /* 便宜上、初期値を0としておく */
extern const int tbl_rnd[256];
int get_rnd(void)
{
    index = (index + 1) & 0xff;
    if (index == 0)
        base = (base + 17) & 0xff;

    return (tbl_rnd[index] + base) & 0xff;
}
/*________________________________________________________________
 *
 *  乱数生成(どのモンスターパーティが出現するかを選択する処理で使用)
 *  [出力]
 *      戻り値:     乱数値
 *  [使用]
 *      index:      乱数テーブル内の現在位置
 *      base:       乱数テーブルの値に加算する値
 *      tbl_rnd:    乱数テーブル
 *________________________________________________________________
 */
static int index = 0;   /* 便宜上、初期値を0としておく */
static int base = 0;    /* 便宜上、初期値を0としておく */
extern const int tbl_rnd[256];
int get_rnd(void)
{
    index = (index + 1) & 0xff;
    if (index == 0)
        base = (base + 23) & 0xff;

    return (tbl_rnd[index] + base) & 0xff;
}

ファイナルファンタジーVではプログラム中のあちこちに乱数生成ルーチンが存在していて、それぞれ別々の用途に使用されています。ここに挙げたもの以外にもいくつか乱数生成ルーチンがありますが、どれもほぼ同じアルゴリズムです。さすがに乱数テーブルだけは各ルーチンで共通のものを使っているようです。

また、ここには挙げていませんが、ファイナルファンタジーIVの乱数生成ルーチンとほとんど同じ乱数生成ルーチンも使用されています。

モンスター遭遇時のモンスターパーティ選択処理

;________________________________________________________________
;
; モンスター遭遇判定
;________________________________________________________________
;
LC0CB2C:
;       (略)

;________________________________________________________________
;
; モンスターパーティ選択処理
;________________________________________________________________
;
LC0CBCD:
        LDA     $0AD9
        AND     #$E0
        REP     #$20
        ASL
        STA     $0D
        LDA     $0AD8
        LSR
        LSR
        AND     $0038
        CLC
        ADC     $0D
        STA     $23
        LDA     $0AD6
        XBA
        ASL
        CLC
        ADC     $23
        CLC
        ADC     $0F
        TAX
        LDA     $D07A00,X
        ASL
        ASL
        ASL
        TAX
        LDA     $06
        SEP     #$20
        JSR     $CC6D       ; 乱数生成サブルーチンをコールして、0〜255の範囲の乱数値を取得する
        CMP     #$5A        ; 乱数値と90とを比較して……
        BCC     $CC11       ; ……乱数値が90未満(0〜89)であれば、サブルーチンの最後にジャンプする

        INX
        INX
        CMP     #$B4        ; 乱数値と180とを比較して……
        BCC     $CC11       ; ……乱数値が180未満(90〜179)であれば、サブルーチンの最後にジャンプする

        INX
        INX
        CMP     #$F0        ; 乱数値と240とを比較して……
        BCC     $CC11       ; ……乱数値が240未満(180〜239)であれば、サブルーチンの最後にジャンプする

        INX                 ; (ここに到達するのは乱数値が240〜255の場合)
        INX

LC0CC11:
        REP     #$20
        LDA     $D06800,X
        STA     $04F0
        LDA     $06
        SEP     #$20
        INC     $55

LC0CC20:
        RTS

ファイナルファンタジーVI

乱数生成

;________________________________________________________________
;
; 乱数生成(モンスターが出現するかどうかを判定する処理で使用)
;   [出力]
;       Aレジスタ:  乱数値
;   [使用]
;       $1FA1:      乱数テーブル内の現在位置(1バイト)
;       $1FA4:      乱数テーブルの値に加算する値(1バイト)
;       $C0FD00:    乱数テーブル(256バイト)
;________________________________________________________________
;
LC0C3AB:
        PHX
        INC     $1FA1       ; $1FA1(乱数位置)を1つ進める
        BNE     $C3BA       ; $1FA1(乱数位置)が0でなければ次の処理に進む

        LDA     $1FA4       ;
        CLC                 ;
        ADC     #$11        ;
        STA     $1FA4       ; $1FA4(乱数に加算する値)に17を加算する

LC0C3BA:
        LDA     $1FA1       ;
        TAX                 ; Xに乱数位置を格納する
        LDA     $C0FD00,X   ; 乱数テーブルのX(乱数位置)番目から乱数値を取得して、Aに格納する
        CLC                 ;
        ADC     $1FA4       ; 乱数値に$1FA4(乱数に加算する値)を加算した値がAに入る
        PLX
        RTS
;________________________________________________________________
;
; 乱数生成(どのモンスターパーティが出現するかを選択する処理で使用)
;   [出力]
;       Aレジスタ:  乱数値
;   [使用]
;       $1FA2:      乱数テーブル内の現在位置(1バイト)
;       $1FA3:      乱数テーブルの値に加算する値(1バイト)
;       $C0FD00:    乱数テーブル(256バイト)
;________________________________________________________________
;
LC0C3C8:
        PHX
        INC     $1FA2       ; $1FA2(乱数位置)を1つ進める
        BNE     $C3D7       ; $1FA2(乱数位置)が0でなければ次の処理に進む

        LDA     $1FA3       ;
        CLC                 ;
        ADC     #$17        ;
        STA     $1FA3       ; $1FA3(乱数に加算する値)に23を加算する

LC0C3D7:
        LDA     $1FA2       ;
        TAX                 ; Xに乱数位置を格納する
        LDA     $C0FD00,X   ; 乱数テーブルのX(乱数位置)番目から乱数値を取得して、Aに格納する
        CLC                 ;
        ADC     $1FA3       ; 乱数値に$1FA3(乱数に加算する値)を加算した値がAに入る
        PLX
        RTS
;________________________________________________________________
;
; 乱数生成(0〜1の範囲)
;   [出力]
;       Cフラグ:  乱数値
;________________________________________________________________
;
LC24B3B:
        PHA
        JSR     $4B42
        LSR
        PLA
        RTS
;________________________________________________________________
;
; 乱数生成(0〜255の範囲)
;   [出力]
;       Aレジスタ:  乱数値
;   [使用]
;       $BE:        乱数テーブル内の現在位置(1バイト)
;       $C0FD00:    乱数テーブル(256バイト)
;________________________________________________________________
;
LC24B42:
        PHX
        INC     $BE         ; $BE(乱数位置)を1つ進める
        LDX     $BE         ; Xに乱数位置を格納する
        LDA     $C0FD00,X   ; 乱数テーブルのX(乱数位置)番目から乱数値を取得して、Aの下位8ビットに格納する
        PLX
        RTS
;________________________________________________________________
;
; 乱数生成
;   [入力]
;       Aレジスタ:  乱数値域の上限値
;   [出力]
;       Aレジスタ:  乱数値
;   [使用]
;       $BE:        乱数テーブル内の現在位置(1バイト)
;       $C0FD00:    乱数テーブル(256バイト)
;________________________________________________________________
;
LC24B4D:
        PHX
        PHP
        SEP     #$30
        XBA                 ; Aの下位8ビット(乱数値域の上限値)を上位8ビット部分と入れ替える
        PHA
        INC     $BE         ; $BE(乱数位置)を1つ進める
        LDX     $BE         ; Xに乱数位置を格納する
        LDA     $C0FD00,X   ; 乱数テーブルのX(乱数位置)番目から乱数値を取得して、Aの下位8ビットに格納する
        JSR     $4769       ; Aの上位8ビット(乱数値域の上限値)と下位8ビット(乱数値)とを乗算する
        PLA
        XBA                 ; A(乱数値域の上限値×乱数値)の上位8ビット分を最終的な乱数値とする
        PLP
        PLX
        RTS

;________________________________________________________________
;
; 乗算(8ビット×8ビット)
;   [入力]
;       Aレジスタ:  乗算値1
;       Bレジスタ:  乗算値2
;   [出力]
;       Aレジスタ:  積
;________________________________________________________________
;
LC24769:
        PHP
        REP     $20
        STA     $004202     ; $4202(乗算器の乗算値1の入力レジスタ)にA(乗算値1)を、
                            ; $4203(乗算器の乗算値2の入力レジスタ)にB(乗算値2)をそれぞれ格納する
        NOP                 ;
        NOP                 ;
        NOP                 ;
        NOP                 ; 乗算器の計算処理を待つため、8サイクルのウェイトを入れる
        LDA     $004216     ; $4216(乗算器の積の出力レジスタ)の内容をAに格納する
        PLP
        RTS
;________________________________________________________________
;
; 乱数テーブル
;________________________________________________________________
;
LC0FD00:
        DB      $07,$B6,$F0,$1F,$55,$5B,$37,$E3,$AE,$4F,$B2,$5E,$99,$F6,$77,$CB
        DB      $60,$8F,$43,$3E,$A7,$4C,$2D,$88,$C7,$68,$D7,$D1,$C2,$F2,$C1,$DD
        DB      $AA,$93,$16,$F7,$26,$04,$36,$A1,$46,$4E,$56,$BE,$6C,$6E,$80,$D5
        DB      $B5,$8E,$A4,$9E,$E7,$CA,$CE,$21,$FF,$0F,$D4,$8C,$E6,$D3,$98,$47
        DB      $F4,$0D,$15,$ED,$C4,$E4,$35,$78,$BA,$DA,$27,$61,$AB,$B9,$C3,$7D
        DB      $85,$FC,$95,$6B,$30,$AD,$86,$00,$8D,$CD,$7E,$9F,$E5,$EF,$DB,$59
        DB      $EB,$05,$14,$C9,$24,$2C,$A0,$3C,$44,$69,$40,$71,$64,$3A,$74,$7C
        DB      $84,$13,$94,$9C,$96,$AC,$B4,$BC,$03,$DE,$54,$DC,$C5,$D8,$0C,$B7
        DB      $25,$0B,$01,$1C,$23,$2B,$33,$3B,$97,$1B,$62,$2F,$B0,$E0,$73,$CC
        DB      $02,$4A,$FE,$9B,$A3,$6D,$19,$38,$75,$BD,$66,$87,$3F,$AF,$F3,$FB
        DB      $83,$0A,$12,$1A,$22,$53,$90,$CF,$7A,$8B,$52,$5A,$49,$6A,$72,$28
        DB      $58,$8A,$BF,$0E,$06,$A2,$FD,$FA,$41,$65,$D2,$4D,$E2,$5C,$1D,$45
        DB      $1E,$09,$11,$B3,$5F,$29,$79,$39,$2E,$2A,$51,$D9,$5D,$A6,$EA,$31
        DB      $81,$89,$10,$67,$F5,$A9,$42,$82,$70,$9D,$92,$57,$E1,$3D,$F1,$F9
        DB      $EE,$08,$91,$18,$20,$B1,$A5,$BB,$C6,$48,$50,$9A,$D6,$7F,$7B,$E9
        DB      $76,$DF,$32,$6F,$34,$A8,$D0,$B8,$63,$C8,$C0,$EC,$4B,$E8,$17,$F8

ファイナルファンタジーVIの乱数生成ルーチンは、ファイナルファンタジーVのそれと非常に似通っています。よって、詳しい説明は省略します。

モンスター遭遇時のモンスターパーティ選択処理

;________________________________________________________________
;
; 固定モンスター出現の際にどのモンスターパーティを選択するか
;   [使用]
;       $CF5000:    固定モンスターのモンスターパーティテーブル(1024バイト)
;________________________________________________________________
;
LC0A4DC:
        LDA     $EB
        REP     #$20
        ASL
        ASL
        TAX
        TDC
        SEP     #$20
        JSR     $C3C8       ; 乱数生成サブルーチンをコールして、0〜255の範囲の乱数値を取得する
        CMP     #$C0        ; 乱数値と192とを比較して……
        BCC     $A4EF       ; ……乱数値が192未満であればジャンプする

        INX                 ;
        INX                 ; モンスターパーティの番号を1つ(2バイト分)進める

LC0A4EF:
        REP     #$20
        LDA     $CF5000,X   ; 出現するモンスターパーティの番号を読み込む
        STA     $0011E0
        TDC
        SEP     #$20
        LDA     $EC
        AND     #$C0
        STA     $078A
        LDA     $EC
        AND     #$3F
        CMP     #$3F
        BNE     $A510

        LDA     $0522
        AND     #$7F

LC0A510:
        STA     $0011E2
        TDC
        STA     $0011E3
        LDA     $1ED7
        AND     #$10
        LSR
        STA     $0011E4
        LDA     #$01
        STA     $56
        RTS
;________________________________________________________________
;
; 通常モンスター遭遇の際にどのモンスターパーティを選択するか
;   [使用]
;       $CF4800:    通常モンスターのモンスターパーティテーブル(2048バイト)
;________________________________________________________________
;
LC0C15D:
        CMP     $1F6F
        BCS     $C1AA

        STZ     $1F6E
        STZ     $1F6F
        LDA     $24
        CMP     #$FF        ; ("$FF"(255)は獣ヶ原を意味する)
        BNE     $C171       ; "$FF"(255)でなければ通常のモンスターパーティ選択処理にジャンプする

        JMP     $C211       ; 獣ヶ原のモンスターパーティ選択処理にジャンプする

LC0C171:
        REP     #$20
        ASL
        ASL
        ASL
        TAX
        TDC
        SEP     #$20
        JSR     $C3C8       ; 乱数生成サブルーチンをコールして、0〜255の範囲の乱数値を取得する
        CMP     #$50        ; 乱数値と80とを比較して……
        BCC     $C18F       ; ……乱数値が80未満(0〜79)であれば、サブルーチンの最後にジャンプする

        INX
        INX
        CMP     #$A0        ; 乱数値と160とを比較して……
        BCC     $C18F       ; ……乱数値が160未満(80〜159)であれば、サブルーチンの最後にジャンプする

        INX
        INX
        CMP     #$F0        ; 乱数値と240とを比較して……
        BCC     $C18F       ; ……乱数値が240未満(160〜239)であれば、サブルーチンの最後にジャンプする

        INX                 ; (ここに到達するのは乱数値が240〜255の場合)
        INX

LC0C18F:
        REP     #$20
        LDA     $CF4800,X   ; 出現するモンスターパーティの番号を読み込む
        STA     $0011E0
        TDC
        SEP     #$20
        LDA     $1ED7
        AND     #$10
        LSR
        STA     $0011E4
        LDA     #$01
        BRA     $C1AB

LC0C1AA:
        TDC

LC0C1AB:
        PHA
        JSR     $0505
        PLA
        RTL
;________________________________________________________________
;
; 獣ヶ原での敵出現の際にどのモンスターパーティを選択するか
;   [使用]
;       $1DDD:  モンスターパーティに遭遇したことがあるかどうかを示すフラグ?(64バイト)
;       $1FA5:  現在のモンスターグループ(1バイト)
;________________________________________________________________
;
LC0C211:
        INC     $1FA5
        LDA     $1FA5
        AND     #$3F        ; 64種類のモンスターグループの中から選択される
        TAX

LC0C21A:
        LDA     $1DDD,X
        BNE     $C226       ; 遭遇したことのあるモンスターパーティが含まれていればジャンプする

        TXA
        INC
        AND     #$3F
        TAX
        BRA     $C21A

LC0C226:
        STA     $1A
        TXA
        STA     $1FA5
        REP     #$20
        ASL                 ;
        ASL                 ;
        ASL                 ; モンスターグループの番号を8倍した値が、モンスターパーティの番号(の基本値)になる
        STA     $1E
        TDC
        SEP     #$20
        JSR     $C3C8       ; 乱数生成サブルーチンをコールして、0〜255の範囲の乱数値を取得する
        AND     #$07        ; 乱数値の下位3ビットのみ使用する
        TAX

LC0C23C:
        LDA     $1A
        AND     $C0BA31,X   ; ($C0BA31以降の内容は、$01,$02,$04,$08,$10,$20,$40,$80)
        BNE     $C24B       ; 遭遇したことのあるモンスターパーティであればジャンプする

        TXA
        INC
        AND     #$07
        TAX
        BRA     $C23C

LC0C24B:
        REP     #$21
        TXA
        ADC     $1E
        STA     $0011E0
        TDC
        SEP     #$20
        PHA
        JSR     $0505
        PLA
        LDA     #$01
        RTL

「ぬすむ」処理

;________________________________________________________________
;
; 「ぬすむ」処理
;________________________________________________________________
;
LC2398E:
        LDA     $05,S
        TAX
        LDA     #$01
        STA     $3401
        CPX     #$08
        BCS     $39F9       ; モンスターが「ぬすむ」をしてきた場合は、モンスターの盗み処理にジャンプする

        REP     #$20
        LDA     $3308,Y     ; モンスターの所持アイテムの番号を読み込む
        INC
        SEP     #$21        ; (Cフラグをセットしている)
        BEQ     $39F1       ; アイテムを持っていない場合は、盗み失敗処理にジャンプする

        INC     $3401
        LDA     $3B18,X     ; Aに盗むキャラクタのレベル(以下、「自分レベル」)を読み込む
        ADC     #$32        ; Aに50を加算する(Cフラグがセットされているのでさらに1加算される)
        BCS     $39C8       ; A(自分レベル + 51)が256以上ならば、盗み成功処理にジャンプする

        SBC     $3B18,Y     ; A(自分レベル + 51)から盗むモンスターのレベル(以下、「相手レベル」)を減算する
                            ; (Cフラグがリセットされているのでさらに1減算される)
        BCC     $39F1       ; A(自分レベル + 50 - 相手レベル)が0より下ならば、盗み失敗処理にジャンプする

        BMI     $39C8       ; A(自分レベル + 50 - 相手レベル)が128以上ならば、盗み成功処理にジャンプする

        STA     $EE         ; Aの内容を$EEに格納する(これ以降、$EEは「盗み成功確率」と解釈される)

        LDA     $3C45,X     ; 盗むキャラクタの装備品による特殊効果を読み込む
        LSR                 ; 
        BCC     $39BF       ; 「とうぞくのうでわ」を装備していない場合は次の処理に進む

        ASL     $EE         ; 「とうぞくのうでわ」を装備していた場合、盗み成功確率が2倍になる

LC239BF:
        LDA     #$64        ;
        JSR     $4B4D       ; 0〜99の範囲の乱数値を取得する
        CMP     $EE         ; 乱数値と$EE(盗み成功確率)とを比較して……
        BCS     $39F1       ; ……乱数値が$EE(盗み成功確率)以上であれば、盗み失敗処理にジャンプする

LC239C8:
        PHY
        JSR     $4B42       ; 0〜256の範囲の乱数値を取得する
        CMP     #$20        ; 乱数値と32とを比較して……
        BCC     $39D1       ; ……乱数値が32未満であれば、次の処理に進む

        INY                 ; 入手するアイテムは、「高確率(で盗める)アイテム」の方になる

LC239D1:
        LDA     $3308,Y     ; モンスターの所持アイテムの番号を読み込む
        PLY
        CMP     #$FF        ;
        BEQ     $39F1       ; アイテムを持っていない場合は、盗み失敗処理にジャンプする

        STA     $2F35
        STA     $32F4,X
        LDA     $3018,X
        TSB     $3A8C
        LDA     #$FF        ;
        STA     $3308,Y     ;
        STA     $3309,Y     ; 一度盗みに成功したら、そのモンスターの所持アイテムはなくなる
        INC     $3401
        RTS

LC239F1:
        SEP     #$20
        LDA     #$00
        STA     $3D48,Y
        RTS

LC239F9:
;       (略)


ラグナロックのアイテム変化処理

;________________________________________________________________
;
; ラグナロックのアイテム変化処理
;________________________________________________________________
;
LC23A2C:
        CPY     #$08
        BCC     $3A7A

        LDA     $3C94,Y     ; モンスターのアイテム変化の情報を読み込む
        PHA
        AND     #$1F        ; アイテム変化テーブル番号を取得する
        JSR     $4B3B       ;
        ROL                 ;
        JSR     $4B3B       ;
        ROL                 ; 4倍しながら0〜3の乱数値を加算する
        TAX
        LDA     $C47F40,X   ; 変化するアイテムの番号を読み込む
        STA     $2F35
        LDA     #$02
        STA     $3A28
        LDA     #$1D
        STA     $3A29
        JSR     $35B9
        JSR     $35A8
        PLA                 ;
        LSR                 ;
        LSR                 ;
        LSR                 ;
        LSR                 ;
        LSR                 ; アイテム変化の難易度を取得する
        TAX
        JSR     $4B42       ; 0〜256の範囲の乱数値を取得する
        CMP     $C23DAD,X   ; 乱数値と(アイテム変化の難易度に対応した)変化成功の境界値とを比較して……
        BCS     $3A7A       ; ……乱数値が変化成功の境界値以上であれば、ジャンプする(変化失敗)

        LDA     $05,S
        TAX
        LDA     $2F35
        STA     $32F4,X
        LDA     $3018,X
        TSB     $3A8C
        LDA     #$80
        JMP     $0E2A

LC23A7A:
        JMP     $3B03

LC23DAD:
        DB      $FF,$C0,$80,$40,$20,$10,$08,$00     ; 成功確率のテーブル

ドラゴンクエストV

乱数生成

;________________________________________________________________
;
; 乱数生成(8ビット)
;   [出力]
;       Aレジスタ:  乱数値(0〜255)
;   [使用]
;       $075B〜$075C:   乱数シード?
;       $075D:          最終出力結果に加算する値?
;________________________________________________________________
;
L009878:
        PHP
        SEP     #$20
        LDA     #$FF
        STA     $10
        JSR     $9895
        LDA     #$FF
        STA     $10
        JSR     $9895
        INC     $075D
        LDA     $075B
        CLC
        ADC     $075D
        PLP
        RTS

L009895:
        LDA     #$08
        STA     $11

L009899:
        LDA     $075C
        EOR     $10
        ASL     $075B
        ROL     $075C
        ASL     $10
        ASL
        BCC     $98B9

        LDA     $075B
        EOR     #$21
        STA     $075B
        LDA     $075C
        EOR     #$10
        STA     $075C

L0098B9:
        DEC     $11
        BNE     $9899

        RTS
;________________________________________________________________
;
; 乱数生成(0〜Aの範囲)
;   [入力]
;       Aレジスタ:  乱数の最大値
;   [出力]
;       Aレジスタ:  乱数値(0〜A)
;________________________________________________________________
;
L0098D9:
        PHP
        REP     #$10
        SEP     #$20
        PHX
        TAX
        JSR     $9878
        JSR     $9D50
        PHA
        PHX
        PLA
        PLA
        XBA
        PLA
        XBA
        PLX
        PLP
        RTS

L009D50:
        PHB
        PHK
        PLB
        STX     $10
        STA     $4202
        LDA     $10
        STA     $4203
        NOP
        NOP
        NOP
        NOP
        LDA     $4217
        STA     $12
        LDA     $4216
        STA     $10
        LDA     $11
        STA     $4203
        NOP
        NOP
        NOP
        CLC
        LDA     $4216
        ADC     $12
        STA     $11
        LDA     $4217
        ADC     #$00
        STA     $12
        LDX     $10
        LDA     $12
        PLB
        RTS
;________________________________________________________________
;
; 乱数生成(0〜Aの範囲) (他バンクからの呼び出し用)
;   [入力]
;       Aレジスタ:  乱数の最大値
;   [出力]
;       Aレジスタ:  乱数値(0〜A)
;________________________________________________________________
;
L00953E:
        JSR     $98D9
        RTL

ドラゴンクエストVの乱数生成ルーチンです。処理の内容が今一つよくわからないのですが、おそらくCRCのアルゴリズムを使って乱数を生成しているのだろうと思います。

なお、上記プログラム内のメモリ"$075B"の内容は、約1/60秒ごとに1ずつ増加しています(プログラム"$008894"の処理)。これにより、乱数列が一定のパターンになるのを防いでいます。

宝箱入手判定時の処理

;________________________________________________________________
;
; 宝箱入手判定時の処理
;________________________________________________________________
;
L258956:
        PHP
        REP     #$30
        PHA
        PHX
        PHY
        SEP     #$30
        LDA     $208000     ; $208000(ROM領域)の……
        AND     #$20        ; ……bit5が……
        BNE     $89A7       ; ……セットされている場合、宝箱を入手できる(デバッグ用?)

        LDA     $1116
        CMP     #$FF
        BNE     $8970

        BRL     $8A86

L258970:
        STZ     $42
        BRK     #$88
        DB      $78
        LDA     $46
        CMP     $1113
        BEQ     $898C

        INC     $42
        CMP     #$10
        BCC     $8970
        ADC     $42
        LDA     $1113
        STA     $43
        BRK     #$88
        DB      $EE

L25898C:
        BRK     #$88
        DB      $74
        LDA     $46
        ASL
        TAX
        REP     #$20
        LDA     $278218,X   ; 乱数の最大値を決める
        JSL     $00953E     ; 乱数を取得する
        CMP     #$0000      ; 乱数値と0とを比較して……
        SEP     #$20
        BEQ     $89A7       ; ……0でない場合、ジャンプする(宝箱を入手できる)

        BRL     $8A86       ; ジャンプする(宝箱は入手できない)

L2589A7:
        BRK     #$88
        DB      $75
        LDA     $46
        CMP     #$FF
        BNE     $89B3

        BRL     $8A86

L2589B3:
        STA     $10F7
        LDA     $42
        ORA     #$A0
        STA     $F5

L258A86:
;       (略)

L278218:
        DW      $0001,$0008,$0010,$0020,$0040,$0080,$0100,$1000     ; 宝箱入手確率用のテーブル

モンスターが仲間になるかどうかの判定処理

;________________________________________________________________
;
; モンスターが仲間になるかどうかの判定処理
;________________________________________________________________
;
L20C1CE:
        PHP
        REP     #$30
        PHA
        PHX
        PHY
        SEP     #$30
        JSR     $C1F6       ; 不明
        BCS     $C1E6

        JSL     $218A63     ; 不明
        JSR     $C2BB       ; 不明
        JSL     $218A7A     ; 不明

L20C1E6:
        REP     #$30
        PLY
        PLX
        PLA
        PLP
        RTS

        LDA     $208000
        LSR
        BCS     $C227

        BRK     #$0B
        DB      $40,$21
        BEQ     $C23F
        LDA     $1010
        BEQ     $C23F
        BRK     #$88
        DB      $A6
        LDA     $46
        CMP     #$32
        BCS     $C23F

        LDA     #$00
        BRK     #$8A
        DB      $DB
        LDA     $47
        BRK     #$8A
        DB      $2A
        LDA     $100F
        SEC
        SBC     $46
        BCC     $C227

        CMP     #$08
        BCS     $C23F

L20C227:
        LDA     $1117
        CMP     #$FF
        BEQ     $C23F

        LDA     #$00
        BRK     #$8A
        DB      $78
        LDX     $46
        CPX     $1117
        BEQ     $C241

        INC
        CMP     #$10
        BCC     $C230

L20C23F:
        SEC                 ; 仲間にならない場合は、Cフラグをセットする
        RTS

L20C241:
        BRK     #$8A
        DB      $76
        LDX     $46
        STX     $74
        BRK     #$88
        DB      $77
        LDX     $46
        STX     $71
        LDA     $7E29EA,X
        AND     #$0F
        STA     $72
        TAX
        BEQ     $C29E       ; 同種のモンスターが1匹も仲間になっていない場合、1匹目用の判定処理にジャンプ

        LDA     $278153,X   ; 立っているビットの数を数えて、すでに仲間になっている同種のモンスターの数を取得する
        CMP     #$02
        BCC     $C281       ; 同種のモンスターがすでに1匹仲間になっている場合、2匹目用の判定処理にジャンプ

        BNE     $C23F       ; 同種のモンスターがすでに3匹仲間になっている場合、ジャンプする(仲間にならない)

        JSL     $268D0A     ; 主人公が特定のアイテムを特定の順番で所持しているかチェックして……
        BCS     $C2B9       ; ……条件を満たしている場合、ジャンプする(仲間になる)
        LDA     $74         ; 仲間になりやすさを取得する
        ASL                 ; 仲間になりやすさを2倍して確率用テーブルのインデックスを算出する
        TAX
        REP     #$20
        LDA     $278182,X   ; 3匹目用確率テーブルを使用して、乱数の最大値を決める
        JSL     $00953E     ; 乱数を取得する
        CMP     #$0000      ; 乱数値と0とを比較して……
        SEP     #$20
        BNE     $C23F       ; ……0でない場合、ジャンプする(仲間にならない)

        BEQ     $C2B9       ; ジャンプする(仲間になる)

L20C281:
        JSL     $268D0A     ; 主人公が特定のアイテムを特定の順番で所持しているかチェックして……
        BCS     $C2B9       ; ……条件を満たしている場合、ジャンプする(仲間になる)
        LDA     $74         ; 仲間になりやすさを取得する
        ASL                 ; 仲間になりやすさを2倍して確率用テーブルのインデックスを算出する
        TAX
        REP     #$20
        LDA     $278172,X   ; 2匹目用確率テーブルを使用して、乱数の最大値を決める
        JSL     $00953E     ; 乱数を取得する
        CMP     #$0000      ; 乱数値と0とを比較して……
        SEP     #$20
        BNE     $C23F       ; ……0でない場合、ジャンプする(仲間にならない)

        BEQ     $C2B9       ; ジャンプする(仲間になる)

L20C29E:
        JSL     $268D0A     ; 主人公が特定のアイテムを特定の順番で所持しているかチェックして……
        BCS     $C2B9       ; ……条件を満たしている場合、ジャンプする(仲間になる)
        LDA     $74         ; 仲間になりやすさを取得する
        ASL                 ; 仲間になりやすさを2倍して確率用テーブルのインデックスを算出する
        TAX
        REP     #$20
        LDA     $278162,X   ; 1匹目用確率テーブルを使用して、乱数の最大値を決める
        JSL     $00953E     ; 乱数を取得する
        CMP     #$0000      ; 乱数値と0とを比較して……
        SEP     #$20
        BNE     $C23F       ; ……0でない場合、ジャンプする(仲間にならない)

L20C2B9:
        CLC                 ; 仲間になる場合は、Cフラグをクリアする
        RTS

L278153:
        DB      $00,$01,$01,$02,$01,$02,$02,$03,$01,$02,$02,$03,$02,$03,$03
L278162:
        DW      $0000,$0100,$0040,$0020,$0010,$0004,$0002,$0002     ; 仲間になる確率用テーブル(1匹目用)
L278172:
        DW      $0000,$0400,$0080,$0040,$0040,$0040,$0040,$0020     ; 仲間になる確率用テーブル(2匹目用)
L278182:
        DW      $0000,$0400,$0100,$0080,$0040,$0040,$0040,$0010     ; 仲間になる確率用テーブル(3匹目用)

L268D0A:
        PHP
        REP     #$30
        PHA
        PHX
        PHY
        SEP     #$30
        LDX     #$00

L268D14:
        LDA     $7E2056,X   ; 特定のアイテムX番目と……
        CMP     $268D33,X   ; ……主人公のアイテムX番目とを比較して……
        BNE     $8D2B       ; ……異なっていた場合、ジャンプする(仲間にならない)

        INX
        CPX     #$07        ;
        BCC     $8D14       ; アイテム7つ分(終端を示す値を含む)繰り返す

        REP     #$30
        PLY
        PLX
        PLA
        PLP
        SEC                 ; すべて等しかった場合、Cフラグをセットする(仲間になる)
        RTL

L268D2B:
        REP     #$30
        PLY
        PLX
        PLA
        PLP
        CLC                 ; 異なっていた場合、Cフラグをクリアする(仲間にならない)
        RTL

L268D33:
        DB      $00,$0A,$91,$02,$3C,$64,$FF     ; 特定のアイテムを示すテーブル
                                                ; $00: ひのきのぼう
                                                ; $0A: とがったホネ
                                                ; $91: しあわせのぼうし
                                                ; $02: こんぼう
                                                ; $3C: のこぎりがたな
                                                ; $64: みかわしのふく
                                                ; $FF: (終端)

ドラゴンクエストVI

乱数生成

;________________________________________________________________
;
; 乱数生成(8ビット)
;   [出力]
;       Aレジスタ:  乱数値(0〜255)
;   [使用]
;       $584A〜$584D:   不明
;________________________________________________________________
;
LC00E97:
        PHP
        PHB
        SEI
        REP     #$20
        PEA     $7E7E
        PLB
        PLB
        LDA     $584A
        ASL
        ASL
        EOR     $584C
        ASL
        AND     #$FF00
        XBA
        SEP     #$20
        PHA
        LDA     $584C
        STA     $584D
        LDA     $584B
        STA     $584C
        LDA     $584A
        STA     $584B
        PLA
        STA     $584A
        PLB
        PLP
        PHA
        PLA
        RTL
;________________________________________________________________
;
; 乱数生成(16ビット)
;   [出力]
;       Aレジスタ:  乱数値(0〜65535)
;________________________________________________________________
;
LC00F6E:
        PHP
        SEI
        SEP     #$20
        JSL     $C00E97     ; 乱数値の下位8ビット分を設定する
        PHA
        JSL     $C00E97     ; 乱数値の上位8ビット分を設定する
        XBA
        PLA
        PLP
        PHA
        PLA
        RTL
;________________________________________________________________
;
; 乱数生成(0〜Aの範囲)
;   [入力]
;       Aレジスタ:  乱数の最大値
;   [出力]
;       Aレジスタ:  乱数値(0〜A)
;________________________________________________________________
;
LC00F49:
        PHP
        SEI
        REP     #$30
        PHX
        INC                 ; A(乱数の最大値)に1を加算して……
        BNE     $0F5A       ; ……その結果が0以外(= 乱数の最大値が$FFFF未満である)場合、ジャンプする

        JSL     $C00F6E     ; 乱数の最大値が$FFFFの場合、単に16ビットの乱数値を取得するだけ
        PLX
        PLP
        PHA
        PLA
        RTL

LC00F5A:
        STA     $30
        JSL     $C00F6E     ; 16ビットの乱数値を取得する
        LDX     #$0030      ;
        JSL     $C00D0C     ; (乱数の最大値 + 1)×16ビットの乱数値の乗算を行う
        LDA     $32         ; 計算結果(32ビット)の上位16ビットを最終結果とする
        PLX
        PLP
        PHA
        PLA
        RTL

宝箱入手判定時の処理

;________________________________________________________________
;
; 宝箱入手判定時の処理
;________________________________________________________________
;
LC2B13F:
        PEA     $2511
        PEA     $00FF
        PEA     $7E00
        JSL     $C92965     ; モンスター番号を取得?
        STA     $5A22
        STA     $2587
        JSR     $B1B1       ; モンスターの宝箱入手難易度を取得して、乱数の最大値を決める
        JSL     $C00F49     ; 乱数を取得する
        BNE     $B1B0       ; 乱数値が0でない場合、ジャンプする(宝箱は入手できない)

        LDX     $2587
        JSL     $C2F136     ; 宝箱のアイテム番号を取得する
        DW      $0174,$00FF ; (オフセット$0174(372)バイト目の全ビット($FF)を意味する)
        CMP     #$0000      ; アイテム番号が0番の場合……
        BEQ     $B1B0       ; ……宝箱は入手できない

        STA     $5A2A
        JSL     $C02A16     ; メッセージを表示する
        DB      $0002       ; (メッセージの番号)
        JSL     $C02A16     ; メッセージを表示する
        DB      $0045       ; (メッセージの番号)
        JSL     $C1F32A     ; BGM/SEを鳴らす
        DB      $0040       ; (BGM/SEの番号)
        LDA     #$0042
        STA     $2555
        JSL     $C02A16     ; メッセージを表示する
        DB      $0047       ; (メッセージの番号)
        LDA     #$0049
        STA     $2593
        LDA     $5A2A
        JSL     $C3ED1D     ; アイテムを入手する
        STA     $5A28
        BCS     $B1B0

        CMP     #$09C8
        BEQ     $B1A9

        LDA     #$0048
        STA     $2593

LC2B1A9:
        LDA     $2593
        JSL     $C02A29     ; メッセージを表示する

LC2B1B0:
        RTS

LC2B1B1:
        LDX     $2587
        JSL     $C2F136     ; 宝箱の入手難易度を取得する
        DW      $0163,$001C ; (オフセット$0163(355)バイト目のビット2〜4($1C)を意味する)
        ASL
        TAX
        LDA     $C2B1C3,X   ; 宝箱入手難易度をもとにして、乱数の最大値を決める
        RTS

LC2B1C3:
        DW      $0000,$0007,$000F,$001F,$003F,$007F,$00FF,$0FFF     ; 宝箱入手確率用のテーブル

モンスターが仲間になるかどうかの判定処理

;________________________________________________________________
;
; モンスターが仲間になるかどうかの判定処理
;________________________________________________________________
;
LC2B320:
        PEA     $2011
        PEA     $0020
        PEA     $7E00
        JSL     $C92965     ; 不明
        BNE     $B39B

        JSL     $C1CEDA     ; 不明
        BCS     $B39B

        JSL     $C1CEB7     ; 不明
        BCS     $B39B

        JSL     $C1CEF3     ; 不明
        BCS     $B39B

        JSL     $C1CF02     ; 不明
        BCS     $B39B

        PEA     $2512
        PEA     $00FF
        PEA     $7E00
        JSL     $C92965     ; 不明(仲間になる可能性がある状況の場合、モンスターの番号がAに格納される?)
        CMP     #$0000
        BEQ     $B39B

        STA     $2587
        JSL     $C2B4AF     ; モンスターの仲間になりやすさを取得して、乱数の最大値を決める
        CMP     #$FFFF      ; 乱数最大値が$FFFFの場合……
        BEQ     $B39B       ; ……仲間にできない

        JSL     $C9064A     ; デバッグ用仲間加入判定処理
        BCS     $B371       ; Cフラグがセットされている場合、ジャンプする(仲間になる)

        JSL     $C00F49     ; 乱数を取得する
        BNE     $B39B       ; 乱数値が0でない場合、ジャンプする(仲間にならない)

LC2B371:
        JSL     $C02A16     ; メッセージを表示する
        DW      $0002       ; (メッセージの番号)
        LDX     $2587
        JSL     $C489A8
        BCS     $B39B

        LDX     $2587
        JSL     $C48D42
        STA     $25D5
        JSR     $B39C
        LDX     $25D5
        JSL     $C49079
        DB      $2A,$97,$C4
        JSL     $C48FE7

LC2B39B:
        RTS

LC2B4AF:
        PHP
        PHB
        REP     #$30
        PEA     $7E7E
        PLB
        PLB
        LDA     #$FFFF
        PHA
        JSR     $B532
        BEQ     $B4FE

        INC
        PHA
        LDX     $2587
        JSL     $C2F136     ; モンスターレベルを取得する
        DW      $0161,$00FE ; (オフセット$0161(353)バイト目のビット1〜7($FE)を意味する)
        CMP     $01,S
        PLA
        BCS     $B4FE

        LDA     $2587
        JSL     $C43D74     ; 仲間になっている同種のモンスターの数を取得する?
        DW      $FFFF
        BCS     $B4FE
        CMP     #$0003      ; すでに同種のモンスターが3匹いる場合……
        BCS     $B4FE       ; ……仲間にならない
        ASL                 ;
        ASL                 ;
        ASL                 ; 仲間になっている同種のモンスターの数を8倍する
        STA     $01,S
        LDX     $2587
        JSL     $C2F136     ; モンスターの仲間になりやすさを取得する
        DW      $0165,$00E0 ; (オフセット$0165(357)バイト目のビット5〜7($E0)を意味する)
        CLC                 ;
        ADC     $01,S       ; 仲間になりやすさと同種のモンスターの数×8を加算して……
        ASL                 ; ……2倍して確率用テーブルのインデックスを算出する
        TAX                   
        LDA     $C2B502,X   ; 乱数の最大値を決める
        STA     $01,S

LC2B4FE:
        PLA
        PLB
        PLP
        RTL

LC2B502:
        DW      $FFFF,$00FF,$00FF,$003F,$001F,$000F,$0003,$0001     ; 仲間になる確率用テーブル(1匹目用)
        DW      $FFFF,$FFFF,$03FF,$03FF,$00FF,$00FF,$007F,$001F     ; 仲間になる確率用テーブル(2匹目用)
        DW      $FFFF,$FFFF,$03FF,$03FF,$00FF,$00FF,$00FF,$007F     ; 仲間になる確率用テーブル(3匹目用)

LC9064A:
        REP     #$30
        PEA     $7E7E
        PLB
        PLB
        PHA
        LDA     $C1FFFE     ; ROM領域$C1FFFEの……
        BPL     $0663       ; ……最上位ビットが0の場合はジャンプする(仲間にならない)

        LDA     $3D00       ; RAM領域$7E3D00の……
        AND     #$0010      ; ……4ビット目が……
        BEQ     $0663       ; ……0の場合はジャンプする(仲間にならない)

        PLA
        SEC                 ; Cフラグをセットする(仲間になる)
        RTL

PC90663:
        PLA
        CLC                 ; Cフラグをクリアする(仲間にならない)
        RTL

ドラゴンクエストI・II

乱数生成

;________________________________________________________________
;
; 乱数生成(8ビット)
;   [出力]
;       Aレジスタ:  乱数値(0〜255)
;________________________________________________________________
;
L0BA550:
        REP     #$20
        LDA     $E2
        PHA
        LDA     $E0
        ASL     $E0
        ROL     $E2
        CLC
        ADC     $E0
        STA     $E0
        PLA
        ADC     $E2
        STA     $E2
        LDA     $E0
        CLC
        ADC     #$3549
        ADC     $67
        STA     $E0
        LDA     $E2
        ADC     #$0000
        STA     $E2
        SEP     #$20
        LDA     #$00
        XBA
        LDA     $E2
        RTL

宝箱入手判定時の処理

;________________________________________________________________
;
; 宝箱入手判定時の処理
;________________________________________________________________
;
L00DE40:
        LDA     $1080
        BNE     $DE78

        LDA     $70
        BPL     $DE69

        LDX     $0F7E
        JSL     $0B8B7A
        LDA     $0B000D,X   ; 宝箱の入手難易度を取得する
        STX     $02
        JSR     $CF75       ; 5ビット右シフトする
        AND     #$03        ; 下位2ビットのみ取得する(最終的に、宝箱の入手難易度として0〜3の値が得られる)
        TAY
        LDA     $DEAB,Y     ; 宝箱入手難易度をもとにして、宝箱取得判定の境界値を取得する
        STA     $00
        JSL     $0BA550     ; 乱数を取得する
        CMP     $00         ; 乱数値と宝箱取得判定の境界値とを比較して……
        BCC     $DE6D       ; ……乱数値が宝箱取得判定の境界値未満であれば、ジャンプする(宝箱を入手できる)

L00DE69:
        LDY     #$0002
        RTS

L00DE6D:
        LDX     $02
        LDA     $0B000F,X   ; 宝箱のアイテム番号を取得する
        AND     #$7F        ;
        CLC
        ADC     #$24

L00DE78:
        STA     $E8
        JSR     $CA8A
        CPY     #$0002
        BNE     $DE69

        REP     #$20
        LDA     $E8
        AND     #$00FF
        ASL
        TAX
        LDA     $09E9FB,X
        STA     $0C8D
        SEP     #$20
        LDY     #$0000
        STY     $AE
        LDA     $0C09
        BNE     $DEA7

        INC     $AE
        LDA     $0C0A

        BNE     $DEA7
        INC     $AE

L00DEA7:
        LDY     #$0000
        RTS

L00DEAB:
        DB      $20,$10,$08,$02     ; 宝箱入手確率用のテーブル

ドラゴンクエストIII

乱数生成

;________________________________________________________________
;
; 乱数生成(8ビット)
;   [出力]
;       Aレジスタ:  乱数値(0〜255)
;   [使用]
;       $7F7A〜$7F7E:   不明
;________________________________________________________________
;
LC012E3:
        LDA     #$0001
        STA     $7F7E
        LDA     $7F7A
        ASL
        ASL
        EOR     $7F7C
        ASL
        AND     #$FF00
        XBA
        SEP     #$20
        PHA
        LDA     $7F7C
        STA     $7F7D
        LDA     $7F7B
        STA     $7F7C
        LDA     $7F7A
        STA     $7F7B
        PLA
        STA     $7F7A
        REP     #$20
        STZ     $7F7E
        RTL
;________________________________________________________________
;
; 乱数生成(16ビット)
;   [出力]
;       Aレジスタ:  乱数値(0〜65535)
;________________________________________________________________
;
LC01383:
        PHP
        SEI
        SEP     #$20
        JSL     $C012D1     ; 乱数値の下位8ビット分を設定する
        PHA
        JSL     $C012D1     ; 乱数値の上位8ビット分を設定する
        XBA
        PLA
        PLP
        PHA
        PLA
        RTL
;________________________________________________________________
;
; 乱数生成(0〜Aの範囲)
;   [入力]
;       Aレジスタ:  乱数の最大値
;   [出力]
;       Aレジスタ:  乱数値(0〜A)
;________________________________________________________________
;
LC0135F:
        PHP
        REP     #$30
        PHX
        INC                 ; A(乱数の最大値)に1を加算して……
        BNE     $136F       ; ……その結果が0以外(= 乱数の最大値が$FFFF未満である)場合、ジャンプする

        JSL     $C0138      ; 乱数の最大値が$FFFFの場合、単に16ビットの乱数値を取得するだけ
        PLX
        PLP
        PHA
        PLA
        RTL

LC0136F:
        STA     $30
        JSL     $C0138      ; 16ビットの乱数値を取得する
        LDX     #$0030      ;
        JSL     $C0114      ; (乱数の最大値 + 1)×16ビットの乱数値の乗算を行う
        LDA     $32         ; 計算結果(32ビット)の上位16ビットを最終結果とする
        PLX
        PLP
        PHA
        PLA
        RTL

宝箱入手判定時の処理

;________________________________________________________________
;
; 宝箱入手判定時の処理
;________________________________________________________________
;
LC2A9AE:
        PEA     $23A9
        PEA     $00FF
        PEA     $7E00
        JSL     $C9029E     ; 不明
        BEQ     $AA14

        STA     $BE71
        JSR     $AA15       ; モンスターの宝箱入手難易度を取得して、乱数の最大値を決める
        JSL     $C0135F     ; 乱数を取得する
        BNE     $AA14       ; 乱数値が0でない場合、ジャンプする(宝箱は入手できない)

        LDA     $242C       ; 宝箱のアイテム番号が……
        CMP     #$0000      ; ……0番である場合……
        BEQ     $AA14       ; ……宝箱は入手できない

        STA     $BE79
        JSR     $AAF3
        JSL     $C1A867     ; メッセージを表示する
        DW      $0033       ; (メッセージの番号)
        LDA     #$0042
        STA     $23E4
        JSL     $C1A867     ; メッセージを表示する
        DW      $0034       ; (メッセージの番号)
        JSL     $C1E32E     ; BGM/SEを鳴らす
        DW      $0040       ; (BGM/SEの番号)
        JSL     $C1A867     ; メッセージを表示する
        DW      $0035       ; (メッセージの番号)
        LDA     $242C
        JSL     $C44824     ; 不明
        DW      $FFFF
        STA     $BE77
        LDX     #$0037
        CMP     #$0020
        BEQ     $AA0C

        LDX     #$0036

LC2AA0C:
        JSR     $AAF3       ; 不明
        TXA
        JSL     $C1A87A     ; 不明

LC2AA14:
        RTS

LC2AA15:
        PHX
        PHY
        TAY
        JSL     $C2CC92     ; 宝箱のアイテム番号を取得する
        DW      $000C,$00FF ; (オフセット$000C(12)バイト目の全ビット($FF)を意味する)
        STA     $242C
        JSL     $C2CC92     ; 宝箱の入手難易度を取得する
        DW      $001D,$0038 ; (オフセット$001D(29)バイト目のビット3〜5($38)を意味する)
        ASL
        TAX
        LDA     $C2AA34,X   ; 宝箱入手難易度をもとにして、乱数の最大値を決める
        PLY
        PLX
        RTS

        DW      $0000,$0007,$000F,$001F,$003F,$007F,$00FF,$03FF     ; 宝箱入手確率用のテーブル

ロマンシング サ・ガ2

乱数生成

;________________________________________________________________
;
; 乱数生成(8ビット)
;   [入力]
;       $A0:        乱数値域の下限値
;       $A1:        乱数値域の上限値
;   [出力]
;       $A0:        乱数値
;   [使用]
;       $1F:        乱数テーブル内の現在位置(1バイト)
;       $C2EF04:    乱数テーブル(256バイト)
;________________________________________________________________
;
LC2EE18:
        SEP     #$20
        LDA     $A1
        BEQ     $EE22

        CMP     $A0
        BCS     $EE26

LC2EE22:
        STZ     $A0
        BRA     $EE56

LC2EE26:
        LDA     $A0
        PHA
        LDA     #$00
        XBA
        LDA     $1F
        TAX
        LDA     $C2EF04,X
        STA     $A5
        STZ     $A6
        LDA     $A1
        SEC
        SBC     $A0
        INC
        STA     $A0
        JSR     $ED86
        PLA
        STA     $A0
        LDA     $A9
        CLC
        ADC     $A0
        STA     $A0
        LDA     $1F
        CMP     #$FF
        BCC     $EE54

        STZ     $1F

LC2EE54:
        INC     $1F

LC2EE56:
        RTS

LC2EF04:
        DB      $EA,$65,$5A,$7B,$F4,$47,$0E,$AA,$47,$9F,$39,$9B,$5A,$E3,$B1,$84
        DB      $8D,$EE,$72,$80,$54,$34,$33,$18,$79,$A9,$D2,$E4,$23,$19,$22,$61
        DB      $09,$D7,$5D,$CA,$03,$28,$DC,$2B,$5E,$B3,$C9,$E8,$27,$66,$66,$F8
        DB      $50,$9E,$30,$0D,$64,$F2,$EB,$DC,$2E,$84,$E7,$67,$07,$23,$7A,$BF
        DB      $AE,$30,$93,$CE,$60,$8E,$E2,$98,$91,$0C,$61,$EC,$FC,$89,$D1,$14
        DB      $73,$D8,$F5,$DE,$90,$91,$93,$2B,$4D,$50,$0A,$44,$8E,$28,$0A,$2D
        DB      $A6,$B6,$B9,$BF,$F1,$1E,$D1,$33,$F6,$60,$00,$E5,$3B,$D0,$98,$0C
        DB      $B6,$25,$66,$1C,$14,$D2,$22,$11,$22,$42,$DF,$68,$2E,$89,$7C,$EC
        DB      $A8,$B0,$58,$B1,$C8,$B8,$68,$56,$11,$E4,$71,$6F,$EC,$7C,$6C,$34
        DB      $48,$85,$EF,$46,$55,$B5,$9B,$B6,$E4,$8D,$5A,$9C,$08,$E5,$09,$DF
        DB      $D7,$DF,$44,$94,$21,$7A,$F0,$F8,$CD,$4A,$CC,$7F,$4A,$08,$0B,$F9
        DB      $C0,$7A,$4E,$3C,$66,$F4,$90,$E2,$3A,$60,$38,$06,$69,$96,$73,$03
        DB      $43,$01,$1E,$34,$E2,$BC,$C1,$AE,$87,$BC,$F6,$6A,$B6,$2B,$BC,$E7
        DB      $A5,$FE,$87,$B7,$86,$86,$9D,$76,$B1,$64,$82,$A5,$CC,$31,$0A,$6E
        DB      $65,$CD,$53,$38,$A3,$93,$BC,$27,$83,$E3,$1F,$5E,$C1,$59,$D7,$25
        DB      $67,$89,$EE,$CD,$20,$1E,$6A,$EE,$47,$BF,$8F,$58,$56,$87,$29,$56

;________________________________________________________________
;
; 除算(8ビット÷8ビット)
;   [入力]
;       $A5:    被除数(1バイト)
;       $A0:    除数(1バイト)
;   [出力]
;       $A7:    商(1バイト)
;       $A9:    余(1バイト)
;________________________________________________________________
;
LC2ED86:
        SEP     #$20
        LDX     $A5
        STX     $4204
        LDA     $A0
        STA     $4206
        NOP
        NOP
        NOP
        NOP
        NOP
        NOP
        NOP
        NOP
        LDX     $4214
        STX     $A7
        LDX     $4216
        STX     $A9
        RTS

ロマンシング サ・ガ2の乱数生成ルーチンです。乱数表に256個の数値があるにもかかわらず、最初の1個目が使われないため、256周期ではなくて255周期になっています。また、乱数表の数値に妙に偏りがあり、例えば$66・$B6・$BCなどは乱数表中にそれぞれ4個ずつも存在していたりします。乱数の最大値も$FFではなくて$FEが最大です。

技閃き判定時の処理

;________________________________________________________________
;
; 技閃き判定時の処理
;________________________________________________________________
;

LC2C443:
        LDY     #$0000
        LDA     [$9A],Y     ; 閃き判定を行う技の番号
        STA     $6F
        INY
        LDA     [$9A],Y     ; 閃き判定を行う技の閃き難易度
        STA     $70
        LDA     $6F         ; 技番号と……
        CMP     #$86        ; ……$86(でたらめ矢)とを比較して……
        BNE     $C460       ; ……一致しない場合(閃こうとする技がでたらめ矢以外の場合)ジャンプする(通常の閃き判定を行う)

        LDY     #$0005
        LDA     [$94],Y     ; キャラクタの状態が……
        BIT     #$10        ; ……「暗い」状態であるか判定して……
        BEQ     $C460       ; ……一致しない場合はジャンプする(通常の閃き判定を行う)

        BRA     $C465       ; それ以外の場合、無条件で閃く

LC2C460:
        JSR     $CA5C       ; 乱数による閃き判定を行う
        BEQ     $C468       ; 結果が$00(技閃きに失敗したことを意味する)の場合はジャンプする

LC2C465:
        JSR     $C47A       ; 武器固有技関連の判定(?)を行う

LC2C468:
        RTS


LC2CA5C:
        STZ     $A5         ;
        STZ     $A6         ; 技能レベルの合計値を初期化する
        LDY     #$0018

LC2CA63:
        LDA     [$97],Y     ; 技能レベル
        CLC 
        ADC     $A5
        STA     $A5
        INY 
        CPY     #$001D
        BNE     $CA63       ; 技能レベル5種類の合計値を求める

        LDA     #$05        ; 除数に5を設定する
        STA     $A0         ; 被除数に技能レベルの合計値を設定する
        JSR     $ED86       ; 除算を行う
        LDA     $A7         ; 除算結果(技能レベルの平均値)
        STA     $71
        LDA     $71         ; 技能レベルの平均値と……
        CMP     $70         ; ……技閃き難易度とを比較して……
        BCC     $CA9C       ; ……技能レベルの平均値が技閃き難易度より大きければジャンプする

        SEC 
        SBC     $70
        STA     $71         ; 技能レベルの平均値と技閃き難易度の差(絶対値)
        LDX     #$0000

LC2CA89:
        LDA     $C2CAE5,X   ;
        CMP     $71         ;
        BCS     $CA95       ; 差分値から境界値を選択する

        INX 
        INX 
        BRA     $CA89

LC2CA95:
        INX 
        LDA     $C2CAE5,X   ; 境界値を取得する
        BRA     $CAB7

LC2CA9C:
        LDA     $70
        SEC 
        SBC     $71
        STA     $71         ; 技能レベルの平均値と技閃き難易度の差(絶対値)
        LDX     #$0000

LC2CAA6:
        LDA     $C2CAD1,X   ;
        CMP     $71         ;
        BCS     $CAB2       ; 差分値から境界値を選択する

        INX 
        INX 
        BRA     $CAA6

LC2CAB2:
        INX 
        LDA     $C2CAD1,X   ; 境界値を取得する

LC2CAB7:
        STA     $71         ; 境界値を格納する
        LDA     #$01        ; 1から……
        STA     $A0         ;
        LDA     #$FF        ; ……255の範囲で……
        STA     $A1         ;
        JSR     $EE18       ; ……乱数値を取得する
        LDA     $71         ; 境界値と……
        CMP     $A0         ; 1〜255の乱数値とを比較して……
        BCS     $CACE       ; 境界値が乱数値以上の場合はジャンプする(技を閃く)

        LDA     #$00        ; Aに$00を格納してサブルーチンを終了する(技閃きに失敗したことを意味する)
        BRA     $CAD0

LC2CACE:
        LDA     #$FF        ; Aに$FFを格納してサブルーチンを終了する(技閃きに成功したことを意味する)

LC2CAD0:
        RTS

LC2CAD1:                    ; 閃き確率用テーブル(-1〜-255)
        DB      $01,$0B
        DB      $02,$08
        DB      $03,$05
        DB      $04,$03
        DB      $05,$01
        DB      $06,$00
        DB      $07,$00
        DB      $08,$00
        DB      $09,$00
        DB      $FF,$00

LC2CAE5:                    ; 閃き確率用テーブル(±0〜+255)
        DB      $00,$32
        DB      $01,$12
        DB      $02,$15
        DB      $03,$18
        DB      $04,$1A
        DB      $05,$1C
        DB      $06,$1D
        DB      $07,$1E
        DB      $08,$1E
        DB      $09,$1E
        DB      $FF,$1E

戦闘終了後のアイテム入手時の処理

;________________________________________________________________
;
; 戦闘終了後のアイテム入手時の処理
;________________________________________________________________
;
LC2E025:
        LDA     #$07
        STA     $18
        STA     $307F90
        LDA     #$1F        ;
        STA     $5D         ; アイテム入手確率判定用乱数の最大値(高確率)
        LDX     #$004F      ;
        STX     $88         ; 入手できるアイテム(高確率)の番号へのインデックス
        JSR     $E04D       ; 倒した全モンスターの中を対象に、アイテム入手判定を行う
        BNE     $E049       ; アイテム入手判定に成功した場合、ジャンプする

LC2E03B:
        LDA     #$3F        ;
        STA     $5D         ; アイテム入手確率判定用乱数の最大値(低確率)
        LDX     #$0050      ;
        STX     $88         ; 入手できるアイテム(低確率)の番号へのインデックス
        JSR     $E04D       ; 倒した全モンスターの中を対象に、アイテム入手判定を行う
        BEQ     $E04C       ; アイテム入手判定に失敗した場合、ジャンプする

LC2E049:
        JSR     $E10E

LC2E04C:
        RTS


LC2E04D:
        LDX     #$A000
        STX     $94
        LDA     #$7E
        STA     $96
        LDA     $22

LC2E058:
        PHA
        LDY     #$0007
        LDA     [$94],Y
        BIT     #$80
        BEQ     $E082

        LDY     #$0006
        LDA     [$94],Y
        BIT     #$02
        BNE     $E082

        STZ     $A0         ; 0から……
        LDA     $5D         ; ……アイテム入手確率判定用乱数の最大値の範囲で……
        STA     $A1
        JSR     $EE18       ; ……乱数値を取得する
        LDA     $A0
        BNE     $E082       ; 乱数値が0以外であった場合、ジャンプする(アイテム入手判定失敗)

        JSR     $E093       ; アイテム欄に空きがあるかどうかの判定を行う
        BEQ     $E082       ; アイテム欄に空きがない場合、ジャンプする

        PLA
        LDA     #$FF        ; Aに$FFを格納して……
        BRA     $E092       ; ……サブルーチンを終了する(アイテム入手判定に成功したことを意味する)

LC2E082:
        REP     #$20
        LDA     $94         ;
        CLC                 ;
        ADC     #$0100      ;
        STA     $94         ; 次のモンスターの判定に進む
        SEP     #$20
        PLA
        DEC
        BNE     $E058

LC2E092:
        RTS


LC2E093:
        LDY     $88         ; 入手アイテムの番号へのインデックス
        LDA     [$94],Y     ; 入手アイテム番号が……
        CMP     #$FF        ; ……$FF(アイテムなし)の場合……
        BEQ     $E0D3       ; ……ジャンプする(アイテム入手失敗)

        STA     $6F
        LDA     #$20
        STA     $70
        LDX     #$0000

LC2E0A4:
        LDA     $7EF622,X   ; X番目のアイテム欄の所持数が……
        BEQ     $E0C2       ; ……0の場合、ループ脱出(アイテム欄に空きがある)

        LDA     $7EF621,X   ; X番目のアイテム欄のアイテム番号が……
        CMP     $6F         ; ……入手アイテム番号と同じ場合……
        BEQ     $E0BA       ; ……ループ脱出

        INX                 ;
        INX                 ; アイテム欄を1つ進める
        DEC     $70
        BNE     $E0A4

LC2E0BA:
        LDA     $7EF622,X   ; 入手アイテムの所持数が……
        CMP     #$63        ; ……99個の場合……
        BEQ     $E0D3       ; ……ジャンプする(アイテム入手失敗)

LC2E0C2:
        LDA     $6F
        STA     $7EF621,X   ; アイテム欄に入手アイテムのアイテム番号を格納する
        LDA     $7EF622,X   ;
        INC                 ;
        STA     $7EF622,X   ; 入手アイテムの所持数を1増加する
        LDA     #$FF        ; Aに$FFを格納してサブルーチンを終了する(アイテム入手判定に成功したことを意味する)

LC2E0D3:
        RTS

ロマンシング サ・ガ3

乱数生成

;________________________________________________________________
;
; 乱数生成(8ビット)
;   [入力]
;       $BF:        乱数値域の下限値
;       $C0:        乱数値域の上限値
;   [出力]
;       $BF:        乱数値
;   [使用]
;       $14:        乱数テーブル内の現在位置(1バイト)
;       $D7E63C:    乱数テーブル(1024バイト)
;________________________________________________________________
;
LC2032E:
        SEP     #$20
        LDA     $BF
        CMP     $C0
        BEQ     $033E

        LDA     $C0
        BEQ     $033E

        CMP     $BF
        BCS     $0342

LC2033E:
        STZ     $BF
        BRA     $0378

LC20342:
        LDA     $BF
        PHA
        LDX     $14
        LDA     $D7E63C,X
        STA     $C4
        STZ     $C5
        LDA     $C0
        SEC
        SBC     $BF
        REP     #$20
        AND     #$00FF
        INC
        STA     $C6
        JSR     $02A3
        SEP     #$20
        PLA
        STA     $BF
        LDA     $CA
        CLC
        ADC     $BF
        STA     $BF
        LDX     $14
        INX
        CPX     #$0400
        BCC     $0376

        LDX     #$0000

LC20376:
        STX     $14

LC20378:
        RTS

LD7E63C:
        DB      $E5,$7F,$72,$82,$6C,$87,$FA,$CC,$3D,$6A,$87,$26,$A8,$E8,$DC,$E3
        DB      $B0,$66,$D0,$22,$39,$5D,$18,$99,$BA,$07,$A6,$A5,$50,$A0,$D8,$38
        DB      $20,$59,$C4,$B1,$F5,$55,$6A,$5F,$14,$D8,$A9,$19,$07,$74,$AB,$BB
        DB      $0F,$D9,$A9,$F6,$60,$AA,$3E,$B5,$D2,$60,$30,$10,$3E,$AB,$5C,$0C
        DB      $A0,$65,$B1,$27,$49,$EC,$E3,$5F,$20,$11,$CA,$C0,$53,$DA,$0E,$AC
        DB      $F1,$E0,$15,$D6,$46,$72,$DB,$BA,$77,$3F,$26,$FA,$C0,$55,$AD,$73
        DB      $C7,$0C,$43,$6B,$62,$46,$0C,$B1,$D3,$92,$40,$15,$CC,$1B,$23,$7A
        DB      $3F,$F0,$13,$09,$4D,$1A,$EA,$AA,$E1,$72,$94,$5D,$3C,$4A,$81,$10
        DB      $7F,$D2,$71,$04,$0B,$B4,$B3,$F6,$AD,$F8,$4D,$8A,$7F,$10,$B6,$25
        DB      $E7,$9D,$12,$50,$24,$63,$12,$C4,$D5,$62,$73,$A9,$E3,$94,$3A,$BF
        DB      $40,$D8,$1F,$F1,$57,$68,$D6,$8C,$38,$7B,$1F,$90,$43,$70,$BF,$68
        DB      $69,$94,$6A,$6C,$46,$6C,$24,$83,$A3,$94,$27,$4D,$B4,$98,$65,$1C
        DB      $0D,$5B,$9B,$B2,$28,$6D,$1F,$0A,$09,$ED,$50,$94,$BB,$CF,$E2,$3B
        DB      $4D,$A0,$61,$18,$79,$2F,$9F,$9D,$28,$2B,$7F,$33,$F8,$17,$3C,$FA
        DB      $F4,$32,$A1,$3F,$2B,$AB,$60,$45,$C2,$BF,$E6,$FD,$D8,$9C,$EE,$52
        DB      $A8,$28,$28,$0B,$D1,$02,$AE,$06,$4B,$E2,$B8,$41,$46,$2D,$24,$ED
        DB      $14,$D2,$58,$0D,$58,$67,$1B,$4E,$14,$FB,$D4,$B0,$D6,$22,$DF,$9C
        DB      $9C,$AD,$5B,$F7,$2D,$96,$28,$EA,$81,$95,$7A,$59,$7E,$D3,$AF,$C2
        DB      $90,$CC,$52,$0D,$74,$40,$7C,$72,$37,$CA,$F7,$0E,$3D,$87,$DC,$C6
        DB      $D6,$4F,$84,$0E,$B6,$7A,$0F,$B7,$CA,$B8,$D9,$5A,$4F,$DF,$1B,$03
        DB      $9E,$CC,$10,$AC,$11,$32,$5C,$39,$72,$EE,$9A,$71,$5F,$CE,$B9,$37
        DB      $90,$C7,$19,$79,$65,$98,$91,$92,$34,$DD,$D5,$1E,$33,$03,$51,$F4
        DB      $7D,$1C,$7B,$D4,$8A,$15,$BF,$E8,$18,$48,$73,$33,$DD,$58,$76,$92
        DB      $8F,$ED,$79,$60,$FB,$B5,$8A,$5E,$D5,$B2,$5B,$FA,$6F,$49,$67,$1A
        DB      $78,$9D,$EB,$6B,$0A,$9D,$57,$01,$86,$52,$A3,$A7,$24,$DD,$BD,$B8
        DB      $24,$34,$72,$66,$09,$F4,$00,$3A,$D3,$00,$C1,$C2,$95,$1C,$9E,$AF
        DB      $E6,$53,$A4,$D0,$04,$DA,$00,$BE,$A7,$24,$B9,$9E,$6A,$F6,$68,$44
        DB      $AC,$28,$3E,$AA,$68,$53,$25,$00,$5E,$2B,$CD,$C4,$84,$40,$E4,$AF
        DB      $2C,$D8,$54,$E2,$39,$39,$41,$1B,$F2,$F1,$AF,$65,$B3,$96,$F8,$0E
        DB      $92,$75,$81,$48,$BF,$AB,$58,$47,$32,$B6,$AF,$C9,$E4,$D6,$D3,$50
        DB      $37,$E6,$96,$7A,$37,$80,$D0,$C9,$69,$8A,$EB,$43,$D0,$8B,$9F,$A9
        DB      $C9,$61,$CC,$57,$02,$33,$24,$62,$17,$3F,$82,$19,$AD,$DC,$B0,$82
        DB      $83,$D1,$72,$EC,$56,$D4,$8E,$BC,$9A,$59,$40,$7C,$5D,$01,$B7,$66
        DB      $55,$4F,$9D,$E9,$EE,$7C,$3F,$60,$62,$7E,$4F,$74,$9F,$2B,$ED,$74
        DB      $19,$8A,$DA,$8B,$3B,$36,$87,$20,$9F,$66,$6A,$51,$C0,$7D,$C8,$CF
        DB      $C1,$3D,$5D,$8F,$90,$F4,$8C,$8B,$73,$C9,$0A,$1A,$49,$F6,$28,$8F
        DB      $8A,$9C,$2F,$23,$57,$80,$74,$DC,$20,$54,$15,$7E,$2F,$64,$86,$2E
        DB      $28,$46,$E0,$D3,$3E,$E6,$99,$6A,$37,$13,$92,$C4,$84,$D0,$29,$F9
        DB      $77,$31,$B9,$FD,$E6,$EB,$39,$17,$4D,$E3,$56,$BB,$A8,$74,$50,$05
        DB      $2E,$20,$E8,$BD,$1A,$78,$22,$40,$26,$E6,$B4,$A9,$F6,$26,$E6,$95
        DB      $0B,$0D,$B2,$DF,$73,$0C,$E6,$AF,$66,$6F,$30,$3D,$78,$C8,$32,$14
        DB      $85,$1D,$A2,$50,$93,$2B,$0C,$8B,$C3,$EF,$29,$FB,$92,$3F,$03,$FE
        DB      $FC,$10,$3C,$0B,$D0,$D0,$B9,$44,$35,$6E,$90,$B3,$37,$D8,$E3,$57
        DB      $EA,$AC,$A7,$0B,$E5,$5D,$6A,$07,$21,$72,$14,$69,$15,$42,$CA,$11
        DB      $90,$36,$E5,$3C,$21,$86,$1B,$AC,$10,$F4,$51,$CA,$C7,$76,$48,$85
        DB      $28,$D8,$FC,$69,$17,$C8,$7B,$29,$5A,$D0,$84,$9C,$08,$AE,$B7,$E0
        DB      $15,$99,$AA,$AC,$CF,$D4,$9E,$7D,$59,$32,$39,$2B,$DA,$51,$EE,$93
        DB      $92,$C7,$13,$E1,$F9,$03,$2A,$25,$97,$08,$F7,$BA,$C1,$E2,$6F,$C0
        DB      $65,$EC,$F1,$12,$17,$40,$06,$08,$00,$F1,$79,$78,$EB,$74,$94,$30
        DB      $0B,$3C,$C7,$E7,$2E,$FE,$8C,$E9,$8D,$B1,$55,$67,$E3,$96,$C3,$BD
        DB      $69,$81,$0E,$1D,$FA,$28,$BC,$D8,$7D,$1B,$31,$53,$C2,$C6,$9F,$C7
        DB      $FE,$94,$E3,$6B,$9D,$0A,$E5,$21,$7C,$83,$71,$40,$DC,$DF,$B2,$A1
        DB      $14,$44,$BE,$7B,$4C,$C8,$DB,$B8,$D8,$31,$E9,$58,$73,$0B,$24,$02
        DB      $68,$4B,$1C,$D6,$00,$4E,$24,$32,$B0,$4E,$0C,$DE,$65,$AE,$E4,$F2
        DB      $65,$BC,$2F,$D5,$28,$3A,$A7,$2C,$24,$54,$99,$1F,$5D,$DF,$61,$42
        DB      $4C,$76,$12,$91,$D7,$D1,$62,$40,$82,$00,$D1,$5A,$04,$D0,$B0,$72
        DB      $E7,$10,$F5,$D1,$77,$EF,$91,$F3,$7D,$3F,$A2,$BB,$2D,$41,$C3,$A8
        DB      $BB,$49,$D2,$FE,$F3,$F5,$E6,$29,$56,$22,$D9,$C4,$8A,$EE,$17,$1E
        DB      $33,$FD,$96,$90,$EE,$BA,$B5,$8C,$8F,$C9,$53,$3F,$D9,$85,$E1,$10
        DB      $D3,$12,$D6,$FD,$EE,$79,$24,$87,$1C,$5A,$29,$2C,$96,$0E,$46,$AF
        DB      $EA,$E3,$00,$AE,$0F,$C5,$5C,$2F,$90,$67,$E4,$35,$28,$5F,$00,$91
        DB      $BE,$3B,$84,$E9,$AF,$F5,$39,$33,$D0,$69,$2F,$9A,$12,$0F,$17,$9D
        DB      $3E,$B9,$8D,$C6,$A5,$19,$7A,$50,$C2,$A7,$7E,$A5,$A6,$5E,$8D,$7F
        DB      $B1,$CA,$2B,$9A,$69,$E1,$70,$3E,$7C,$2D,$48,$96,$33,$AE,$10,$18

;________________________________________________________________
;
; 除算(16ビット÷16ビット)
;   [入力]
;       $C4:    被除数(2バイト)
;       $C6:    除数(2バイト)
;   [出力]
;       $C8:    商(2バイト)
;       $CA:    余(2バイト)
;________________________________________________________________
;
LC202A3:
        REP     #$20
        LDA     $C4
        PHA
        LDA     $C6
        PHA
        LDA     #$0000
        STA     $C8
        STA     $CA
        LDX     #$0010

LC202B5:
        ASL     $C8
        ASL     $C4
        ROL
        CMP     $C6
        BCC     $02C2

        SBC     $C6
        INC     $C8

LC202C2:
        DEX
        BNE     $02B5

        STA     $CA
        PLA
        STA     $C6
        PLA
        STA     $C4
        RTS

ロマンシング サ・ガ3の乱数生成ルーチンです。乱数表の数値の数はやや多めで1024個です。ロマンシング サ・ガ2と同様に、やはり乱数表の数値には偏りがあります。乱数の最大値も2と同じく$FFではなくて$FEが最大です。

技閃き判定時の処理

;________________________________________________________________
;
; 技閃き判定時の処理
;________________________________________________________________
;

LC2C0D5:
        LDA     $43         ; 見切り技閃き難易度
        STA     $83
        LDA     $44         ; 敵閃きレベル
        STA     $84
        LDA     $45         ; $00が設定されているはず
        STA     $85
        JSL     $FEE8A7     ; 閃き判定の乱数の境界値を取得する
        STA     $8A
        STZ     $8B
        STZ     $BF         ; 0から……
        LDA     #$FF        ; ……255の範囲で……
        STA     $C0         ;
        JSR     $032E       ; ……乱数値を取得する
        LDA     $BF
        REP     #$20
        AND     #$00FF
        INC                 ; 乱数値に1を加えて
        CMP     $8A         ; ……境界値と比較して……
        SEP     #$20
        BCC     $C104       ; ……「乱数値 + 1」が境界値未満であった場合、ジャンプする(見切り技を閃く)

        LDA     #$FF        ; Aに$FFを格納してサブルーチンを終了する(見切り技閃きに失敗したことを意味する)
        BRA     $C106

LC2C104:
        LDA     #$00        ; Aに$00を格納してサブルーチンを終了する(見切り技閃きに成功したことを意味する)

LC2C106:
        RTS


LC2C107:
        LDA     $143C       ; 閃き成功回数が……
        CMP     #$08        ; ……8回の場合……
        BCS     $C151       ; ……ジャンプする(技を閃かない)

        LDA     $43         ; 技閃き難易度
        STA     $83
        LDA     $44         ; 敵閃きレベル
        STA     $84
        LDA     $45         ; 技の王冠があるか、最大術ポイントが0であれば$00が設定されている
        STA     $85
        JSL     $FEE8A7     ; 閃き判定の乱数の境界値を取得する
        STA     $C4         ; この境界値を被乗数とする
        STZ     $C5
        LDA     #$08        ;
        SEC                 ;
        SBC     $143C       ; 「8 - 閃き成功回数」を……
        STA     $C6         ; ……乗数とする
        STZ     $C7
        JSR     $0242       ; 乗算を行う
        REP     #$20
        LDA     $C8         ; 乗算結果を……
        JSR     $0413       ; ……8で除算する
        STA     $8A         ; この値を最終的な境界値とする
        SEP     #$20
        STZ     $BF         ; 0から……
        LDA     #$FF        ; ……255の範囲で……
        STA     $C0         ;
        JSR     $032E       ; ……乱数値を取得する
        LDA     $BF
        REP     #$20
        AND     #$00FF
        INC                 ; 乱数値に1を加えて
        CMP     $8A         ; ……境界値と比較して……
        SEP     #$20
        BCC     $C155       ; ……「乱数値 + 1」が境界値未満であった場合、ジャンプする(技を閃く)

LC2C151:
        LDA     #$FF        ; Aに$FFを格納してサブルーチンを終了する(技閃きに失敗したことを意味する)
        BRA     $C15A

LC2C155:
        INC     $143C       ; 閃き成功回数に1を加える
        LDA     #$00        ; Aに$00を格納してサブルーチンを終了する(技閃きに成功したことを意味する)

LC2C15A:
        RTS


LC2C15B:
        LDA     $143C       ; 閃き成功回数が……
        CMP     #$08        ; ……8回の場合……
        BCS     $C188       ; ……ジャンプする(技を閃かない)

        LDA     $43         ; 技閃き難易度
        STA     $83
        LDA     $44         ; 敵閃きレベル
        STA     $84
        LDA     $45         ; $00が設定されているはず
        STA     $85
        JSL     $FEE8A7     ; 閃き判定の乱数の境界値を取得する
        BEQ     $C188       ; 境界値が0であれば、ジャンプする(技を閃かない)

        STZ     $BF         ; 0から……
        LDA     #$FF        ; ……255の範囲で……
        STA     $C0         ;
        JSR     $032E       ; ……乱数値を取得する
        LDA     $BF
        BNE     $C188       ; 乱数値が0以外であれば、ジャンプする(技を閃かない)

        INC     $143C       ; 閃き成功回数に1を加える
        LDA     #$00        ; Aに$00を格納してサブルーチンを終了する(技閃きに成功したことを意味する)
        BRA     $C18A

LC2C188:
        LDA     #$FF        ; Aに$FFを格納してサブルーチンを終了する(技閃きに失敗したことを意味する)

LC2C18A:
        RTS

;________________________________________________________________
;
; 閃き判定の乱数の境界値を取得
;   [入力]
;       $83:    技の閃き難易度
;       $84:    敵の閃きレベル
;       $85:    使用するテーブル
;   [出力]
;       Aレジスタ:  閃き判定の乱数の境界値
;________________________________________________________________
;
LFEE8A7:
        LDA     #$00
        XBA
        LDA     $83         ; 技閃き難易度と……
        CMP     $84         ; ……敵閃きレベルとを比較して……
        BCS     $E8C7       ; ……技閃き難易度が敵閃きレベル以上であった場合はジャンプする

        LDA     $84
        SEC
        SBC     $83
        CMP     #$0A
        BEQ     $EABD

        BCC     $EABD

        LDA     #$0A

LFEEABD:
        STA     $86
        LDA     #$0A
        SEC
        SBC     $86
        TAX                 ; 最終的には「技閃き難易度 - 敵閃きレベル + 10(最低値は0)」がXに格納される
        BRA     $E8D6

LFEE8C7:
        SEC
        SBC     $84
        CMP     #$0A
        BEQ     $E8D2

        BCC     $E8D2

        LDA     #$0A

LFEE8D2:
        CLC
        ADC     #$0A
        TAX                 ; 最終的には「技閃き難易度 - 敵閃きレベル + 10(最高値は20)」がXに格納される

LFEE8D6:
        LDA     $85
        BNE     $E8E0       ; 技の王冠がなく最大術ポイントが0でない場合、ジャンプする(閃き確率が低くなる)

        LDA     $FE3180,X   ; 閃き確率が高いテーブルを使用して、閃き判定の乱数の境界値を取得する
        BRA     $E8E4

LFEE8E0:
        LDA     $FE3195,X   ; 閃き確率が低いテーブルを使用して、閃き判定の乱数の境界値を取得する

LFEE8E4:
        RTL

LFE3180:
        DB      $32,$2F,$2E,$2C,$2A,$27,$25,$22,$1F,$1C,$19,$15,$12,$0F,$0C,$09,$06,$04,$02,$01,$00
                            ; 閃き確率用テーブル(高確率)
LFE3195:
        DB      $28,$27,$27,$25,$24,$22,$1F,$1D,$1A,$17,$14,$10,$0D,$0A,$08,$05,$03,$01,$00,$00,$00
                            ; 閃き確率用テーブル(低確率)

戦闘終了後のキャラクタ成長処理

;________________________________________________________________
;
; キャラクタ成長処理
;________________________________________________________________
;
LC2DB7C:
        LDX     #$153D
        STX     $9E
        LDX     #$2280
        STX     $B8
        LDA     $22         ;
        AND     #$FE        ;
        STA     $22         ; 「フラグ0」をクリアする
        LDA     #$00

LC2DB8E:
        PHA
        LDY     #$0000
        STA     ($9E),Y
        LDX     $B8
        CPX     $143E
        BEQ     $DBBC

        LDY     #$0007      ;
        LDA     ($B8),Y     ; キャラクタの状態を取得する
        BIT     #$84        ; 戦闘不能であるか離脱しているかを判定する
        BNE     $DBBC       ;

        LDY     #$0005      ;
        LDA     ($B8),Y     ; キャラクタの状態を取得する
        BIT     #$C0        ; 気絶であるか石化しているかを判定する
        BNE     $DBBC       ;

        JSR     $DE63       ; 最大ヒットポイントが上昇する確率を計算する
        JSR     $DDCE       ; 最大技ポイント・最大術ポイントが上昇する確率を計算する
        JSR     $DEBE       ; 各武器/術レベルが上昇する確率を計算する
        JSR     $DF47       ; 確率低下修正値を計算する
        JSR     $DBE6       ; 成長判定と成長処理を行う

LC2DBBC:
        REP     #$20
        LDA     $9E
        CLC
        ADC     #$000F
        STA     $9E
        LDA     $B8
        CLC
        ADC     #$0080
        STA     $B8
        SEP     #$20
        PLA
        INC
        CMP     $2D
        BNE     $DB8E

        LDA     $22         ;
        BIT     #$01        ;
        BNE     $DBDF       ; 「フラグ0」がセットされている場合、ジャンプする

        JSR     $DF6E       ; パーティの中で最大ヒットポイントが最も低いキャラクタの最大ヒットポイントを1上げる

LC2DBDF:
        LDA     $22         ;
        AND     #$FC        ;
        STA     $22         ; 「フラグ0」と「フラグ1」をクリアする
        RTS

;________________________________________________________________
;
; 最大ヒットポイントが上昇する確率の計算
;________________________________________________________________
;
LC2DE63:
        REP     #$20
        LDY     #$0016      ;
        LDA     ($B8),Y     ; 最大ヒットポイントを取得する
        STA     $C4         ; 被乗数に最大ヒットポイントを設定する
        SEP     #$20
        LDA     $FE3170     ; ($FE3170の内容は$05(5))
        STA     $C6         ; 乗数に5を設定する
        STZ     $C7
        JSR     $0242       ; 「最大ヒットポイント×5」の計算をして、結果を$C8に格納する
        SEP     #$20
        LDX     $C8         ; 「最大ヒットポイント×5」を取得して……
        STX     $C4         ; ……被乗数に設定する
        LDA     $FE3171     ; ($FE3171の内容は$80(128))
        STA     $C6         ; 乗数に128を設定する
        STZ     $C7
        JSR     $02A3       ; 「最大ヒットポイント×5÷128」の計算をして、結果を$C8に(剰余を$CAに)格納する
        SEP     #$20
        LDA     $C8         ; 最終的な計算結果は「最大ヒットポイント×5÷128」となる
        STA     $83
        LDA     $2032       ; リーダー(1体目)のモンスターの「レベルの上がりやすさ」を取得する
        STA     $82
        LDY     #$0000      ;
        LDA     ($B8),Y     ; キャラクタ番号を取得する
        REP     #$20
        AND     #$00FF
        JSR     $0407       ; キャラクタ番号を16倍する
        TAX
        SEP     #$20
        LDA     $FE31CE,X   ; キャラクタごとの「最大ヒットポイントの上がりやすさ」を取得する
        CMP     #$FF        ; (「最大ヒットポイントの上がりやすさ」が$FFの場合、(原則的に)最大ヒットポイントは上昇しない)
        BNE     $DEB1

        LDA     #$00
        BRA     $DEBA

LC2DEB1:
        CLC
        ADC     $82         ; 「最大ヒットポイントの上がりやすさ」と「リーダーのモンスターのレベルの上がりやすさ」を加算する
        STA     $84
        JSL     $FEE8E5     ; 「最大ヒットポイントの上がりやすさ + リーダーのモンスターのレベルの上がりやすさ」と
                            ; 「最大ヒットポイント×5÷128」との差から、「最大ヒットポイントが上昇する確率」を計算する

LC2DEBA:
        STA     $1498       ; 「最大ヒットポイントが上昇する確率」を格納する
        RTS

;________________________________________________________________
;
; 最大技ポイント・最大術ポイントが上昇する確率の計算
;________________________________________________________________
;
LC2DDCE:
        LDX     $9E
        PHX
        STZ     $1496       : 「最大技ポイントが上昇する確率」を0で初期化する
        STZ     $1497       : 「最大術ポイントが上昇する確率」を0で初期化する
        REP     #$20
        LDY     #$0034      ;
        LDA     ($B8),Y     ; 使用した技・術の系統を表すビット列を取得する
        BIT     #$F800      ; 剣/大剣・斧/棍棒・槍/小剣・弓・体術のどれかに属する技(術)を使用したか判定する
        SEP     #$20
        BEQ     $DE1B       ; どれも使用していない場合、ジャンプする(最大技ポイントは上がらない)

        LDY     #$0000      ;
        LDA     ($B8),Y     ; キャラクタ番号を取得する
        REP     #$20
        AND     #$00FF
        JSR     $0407       ; キャラクタ番号を16倍する
        TAX
        SEP     #$20
        LDA     $FE31CC,X   ; キャラクタごとの「最大技ポイントの上がりやすさ」を取得する(実際には値は使用されていない)
        CMP     #$FF        ; (「最大技ポイントの上がりやすさ」が$FFの場合、最大技ポイントは上昇しない)
        BEQ     $DE1B

        LDY     #$001B      ;
        LDA     ($B8),Y     ; 最大技ポイントを取得する
        STA     $83
        LDY     #$0025      ; 剣レベルから……
        STY     $9E         ;
        LDY     #$002A      ; ……体術レベルの範囲で……
        STY     $A0         ;
        JSL     $FECCA7     ; 現在の武器レベルでの基準最大技ポイントを計算する(武器レベル5種類の合計値 + 最高レベルの値×2)
        STA     $84
        JSL     $FEE8E5     ; 「現在の武器レベルでの基準最大技ポイント」と
                            ; 「現在の最大技ポイント」との差から、「最大技ポイントが上昇する確率」を計算する
        STA     $1496       ; 「最大技ポイントが上昇する確率」を格納する

LC2DE1B:
        REP     #$20
        LDY     #$0034      ;
        LDA     ($B8),Y     ; 使用した技・術の系統を表すビット列を取得する
        BIT     #$07E0      ; 蒼竜・朱鳥・白虎・玄武・太陽・月のどれかに属する術(技)を使用したか判定する
        SEP     #$20
        BEQ     $DE5F       ; どれも使用していない場合、ジャンプする(最大術ポイントは上がらない)

        LDY     #$0000      ;
        LDA     ($B8),Y     ; キャラクタ番号を取得する
        REP     #$20
        AND     #$00FF
        JSR     $0407       ; キャラクタ番号を16倍する
        TAX
        SEP     #$20
        LDA     $FE31CD,X   ; キャラクタごとの「最大術ポイントの上がりやすさ」を取得する(実際には値は使用されていない)
        CMP     #$FF        ; (「最大術ポイントの上がりやすさ」が$FFの場合、最大術ポイントは上昇しない)
        BEQ     $DE5F

        LDY     #$001D      ;
        LDA     ($B8),Y     ; 最大術ポイントを取得する
        STA     $83
        LDY     #$002A      ; 蒼竜術レベルから……
        STY     $9E         ;
        LDY     #$0030      ; ……月術レベルの範囲で……
        STY     $A0         ;
        JSL     $FECCA7     ; 現在の術レベルでの基準最大術ポイントを計算する(術レベル2種類の合計値 + 最高レベルの値×2)
        STA     $84
        JSL     $FEE8E5     ; 「現在の術レベルでの基準最大術ポイント」と
                            ; 「現在の最大術ポイント」との差から、「最大術ポイントが上昇する確率」を計算する
        STA     $1497       ; 「最大術ポイントが上昇する確率」を格納する

LC2DE5F:
        PLX
        STX     $9E
        RTS

;________________________________________________________________
;
; 各武器/術レベルが上昇する確率の計算
;________________________________________________________________
;
LC2DEBE:
        LDX     $9E
        PHX
        LDA     $2032       ; リーダー(1体目)のモンスターの「レベルの上がりやすさ」を取得して……
        STA     $82         ; ……$82に格納する
        LDX     #$1489
        STX     $9E
        LDY     #$0000      ;
        LDA     ($B8),Y     ; キャラクタ番号を取得する
        REP     #$20
        AND     #$00FF
        JSR     $0407       ; キャラクタ番号を16倍する
        CLC
        ADC     #$0000
        TAX
        LDY     #$0034      ;
        LDA     ($B8),Y     ; 使用した技・術の系統を表すビット列を取得する
        STA     $8A
        SEP     #$20
        LDY     #$0025      ; 剣レベルから(月術レベルまで)順番に判定する

LC2DEE9:
        PHX
        PHY
        REP     #$20
        ASL     $8A         ; (現在判定中の系統に属する)技・術を使用した場合、Cフラグがセットされる
        SEP     #$20
        BCC     $DF10       ; (現在判定中の系統に属する)技・術を使用していない場合、ジャンプする(その武器/術レベルは上昇しない)

        LDA     #$00
        XBA
        LDA     ($B8),Y     ; (現在判定中の)武器/術レベルを取得する
        STA     $83
        LDA     $FE31BF,X   ; キャラクタごとの(現在判定中の)武器/術レベルの上がりやすさを取得する
        CMP     #$FF        ; (「(現在判定中の)武器/術レベルの上がりやすさ」が$FFの場合、その武器/術レベルは上昇しない)
        BEQ     $DF10

        CLC
        ADC     $82         ; 「(現在判定中の系統の)武器/術レベルの上がりやすさ」にリーダー(1体目)のモンスターの「レベルの上がりやすさ」を加算する
        STA     $84
        JSR     $DF26       ; さらに「(成長しなかった)戦闘の回数」に応じて「レベルの上がりやすさ」が修正される
        JSL     $FEE8E5     ; 「最終的なレベルの上がりやすさ」と「(現在判定中の系統の)現在の武器/術レベル」との差から、
                            ; 「(現在判定中の系統の)武器/術レベルが上昇する確率」を計算する
        BRA     $DF12

LC2DF10:
        LDA     #$00

LC2DF12:
        STA     ($9E)       ; 「(現在判定中の系統の)武器/術レベルが上昇する確率」を格納する
        LDX     $9E         ;
        INX                 ;
        STX     $9E         ; 次の系統の武器/術レベルに進む
        PLY
        PLX
        INX
        INY
        CPY     #$0030      ; (剣レベルから)月術レベルまで判定を繰り返す
        BNE     $DEE9

        PLX
        STX     $9E
        RTS

LC2DF26:
        LDY     #$007A      ;
        LDA     ($B8),Y     ; 「(成長しなかった)戦闘の回数」を取得する
        BEQ     $DF46       ; 「(成長しなかった)戦闘の回数」が0であればジャンプする(修正なし)

        STA     $BF         ; 被乗数「(成長しなかった)戦闘の回数」を設定する
        LDA     $FE317E     ; ($FE317Eの内容は$1A(20))
        STA     $C0         ; 乗数に20を設定する
        JSR     $0227       ; 「(成長しなかった)戦闘の回数×20」の計算をして、結果を$C4に格納する
        REP     #$20
        LDA     $C4         ; 「(成長しなかった)戦闘の回数×20」を取得して……
        JSR     $040E       ; ……256で割る
        SEP     #$20
        CLC
        ADC     $84         ;
        STA     $84         ; 「レベルの上がりやすさ」に「(成長しなかった)戦闘の回数×20÷256」を加算する

LC2DF46:
        RTS

;________________________________________________________________
;
; 確率低下修正値の計算
;________________________________________________________________
;
LC2DF47:
        STZ     $C4         ;
        STZ     $C5         ; レベル合計値を0で初期化する
        LDY     #$0025      ; 剣レベルから(不明レベルまで)順番に処理する

LC2DF4E:
        LDA     ($B8),Y     ; (現在処理中の)武器/術レベルを取得する
        REP     #$20
        AND     #$00FF
        CLC
        ADC     $C4         ;
        STA     $C4         ; レベル合計値に加算する
        SEP     #$20
        INY
        CPY     #$0031      ; (剣レベルから)不明レベルまで順番に処理する
        BNE     $DF4E

        JSR     $03B1       ; レベル合計値から確率低下修正値を計算する
        SEP     #$20
        LDA     $C4
        LSR
        STA     $1499       ; 確率低下修正値を格納する
        RTS

LC203B1:
        REP     #$20
        LDA     $C4
        STA     $C8
        LDA     #$0001
        STA     $C6
        STZ     $C4
        BRA     $03C6

LC203C0:
        INC     $C4
        INC     $C6
        INC     $C6

LC203C6:
        LDA     $C8
        SEC
        SBC     $C6
        STA     $C8
        BCS     $03C0

        RTS

;________________________________________________________________
;
; 成長判定 & 成長処理を行う
;________________________________________________________________
;
LC2DBE6:
        LDA     $22         ;
        AND     #$FD        ;
        STA     $22         ; 「フラグ1」をクリアする
        LDY     #$0032      ;
        LDA     ($B8),Y     ; 成長タイプを取得する
        REP     #$20
        AND     #$00FF
        JSR     $0407       ; 成長タイプを16倍する
        CLC
        ADC     #$34BF      ;
        STA     $B0         ;
        SEP     #$20        ;
        LDA     #$FE        ;
        STA     $B2         ; アドレスを生成する
        LDA     #$10

LC2DC07:
        PHA
        LDX     $B0         ;
        PHX                 ;
        LDA     $B2         ;
        PHA                 ; アドレスを退避する
        LDA     [$B0]       ; 成長判定を行うパラメータの種類を取得する
        CMP     #$FF
        BEQ     $DC35

        CMP     #$0C        ; ($0Cは対応するレベルが存在しない)
        BEQ     $DC35       ; 

        CMP     #$0B        ;
        BCS     $DC21       ;

        JSR     $DD54       ; 各種武器/術レベルの上昇判定と上昇処理を行う
        BRA     $DC35

LC2DC21:
        CMP     #$0D        ; ($0Dは最大技ポイントを示す)
        BEQ     $DC29       ; 

        CMP     #$0E        ; ($0Eは最大術ポイントを示す)
        BNE     $DC2E       ;

LC2DC29:
        JSR     $DCED       ; 最大技ポイント/最大術ポイントの上昇判定と上昇処理を行う
        BRA     $DC35

LC2DC2E:
        CMP     #$0F        ; ($0Fは最大ヒットポイントを示す)
        BNE     $DC35       ; 

        JSR     $DC53       ; 最大ヒットポイントの上昇判定と上昇処理を行う

LC2DC35:
        PLA
        STA     $B2
        PLX
        INX
        STX     $B0
        PLA
        DEC
        BNE     $DC07

        LDA     $22
        BIT     #$02
        BNE     $DC52

        LDY     #$007A      ;
        LDA     ($B8),Y     ; 「(成長しなかった)戦闘の回数」を取得して……
        CMP     #$FF        ; ……$FF(255)と比較して……
        BEQ     $DC52       ; ……「(成長しなかった)戦闘の回数」が255回であれば、ジャンプする(「(成長しなかった)戦闘の回数」は増加しない)

        INC                 ;
        STA     ($B8),Y     ; 「(成長しなかった)戦闘の回数」を1増加する

LC2DC52:
        RTS

;________________________________________________________________
;
; 最大ヒットポイントの上昇判定 & 上昇処理
;________________________________________________________________
;
LC2DC53:
        REP     #$20
        LDY     #$0016      ;
        LDA     ($B8),Y     ; 最大ヒットポイントを取得する
        CMP     #$03E7      ; 最大ヒットポイントと$03E7(999)とを比較して……
        BCC     $DC68       ; ……最大ヒットポイントが999未満の場合、ジャンプする

        LDA     #$03E7      ;
        STA     ($B8),Y     ; 最大ヒットポイントが999以上の場合、999にする
        SEP     #$20
        BRA     $DC8A       ; ジャンプする(最大ヒットポイントは上昇しない)

LC2DC68:
        SEP     #$20
        LDA     $1498       ; 「最大ヒットポイントが上昇する確率」を取得する
        BEQ     $DC8A       ; 「最大ヒットポイントが上昇する確率」が0の場合、ジャンプする(最大ヒットポイントは上昇しない)

        STA     $8A
        STZ     $8B
        STZ     $BF         ; 0から……
        LDA     #$FF        ; ……255の範囲で……
        STA     $C0         ;
        JSR     $032E       ; ……乱数値を取得する
        LDA     $BF
        REP     #$20
        AND     #$00FF
        INC                 ; 乱数値に1を加えて
        CMP     $8A         ; ……「最大ヒットポイントが上昇する確率」と比較して……
        SEP     #$20
        BCC     $DC8B       ; ……「乱数値 + 1」が「最大ヒットポイントが上昇する確率」未満であった場合、ジャンプする

LC2DC8A:
        RTS

LC2DC8B:
        LDY     #$007A      ;
        LDA     #$00        ;
        STA     ($B8),Y     ; 「(成長しなかった)戦闘の回数」を0に戻す
        LDA     $22         ;
        ORA     #$02        ;
        STA     $22         ; 「フラグ1」をセットする
        JSR     $DCB3       ; 最大ヒットポイントを増加する
        LDA     $22         ;
        BIT     #$20        ;
        BNE     $DC8A       ; 不明

        LDA     $22         ;
        ORA     #$01        ;
        STA     $22         ; 「フラグ0」をセットする
        JSL     $FEEBC4     ; 一回転して足を上げるアニメーション
        JSR     $CD7A       ; 「(能力)がアップ!」の表示
        JSR     $DDB1       ; レベルアップ確率を軒並み低下させる
        BRA     $DC8A

LC2DCB3:
        LDY     #$0021      ;
        LDA     ($B8),Y     ; 体力を取得する
        LSR                 ;
        LSR                 ; 体力の値を4で割る
        STA     $8A
        STZ     $8B
        STA     $C0         ; (最高値は「体力÷4」)
        LDA     #$01
        STA     $BF         ; (最低値は1)
        JSR     $032E       ; 1〜「体力÷4」の範囲の乱数値を取得する
        LDA     $BF
        REP     #$20
        AND     #$00FF
        CLC
        ADC     $8A         ; 1〜「体力÷4」の範囲の乱数値に「体力÷4」を加算して……
        ADC     #$0002      ; ……さらに2を加算して……
        STA     $8A         ; ……最終的な最大ヒットポイント増加量とする
        LDY     #$0016      ;
        LDA     ($B8),Y     ; 最大ヒットポイントを取得して……
        CLC                 ;
        ADC     $8A         ; ……最大ヒットポイント増加量を加算する
        CMP     #$03E7      ; 最大ヒットポイントと$03E7(999)とを比較して……
        BEQ     $DCE8       ; ……最大ヒットポイントが999と等しい場合は、ジャンプする

        BCC     $DCE8       ; ……最大ヒットポイントが999未満の場合は、ジャンプする

        LDA     #$03E7      ; 最大ヒットポイントが999以上の場合、999にする

LC2DCE8:
        STA     ($B8),Y
        SEP     #$20
        RTS

;________________________________________________________________
;
; 最大技ポイント/最大術ポイントの上昇判定 & 上昇処理
;________________________________________________________________
;
LC2DCED:
        CMP     #$0D        ; ($0Dは最大技ポイントを示す)
        BNE     $DCF9       ;
        LDY     #$001B      ; (最大技ポイントへのインデックス)
        LDX     #$000D      ; (「最大技ポイントが上昇する確率」へのインデックス)
        BRA     $DCFF

LC2DCF9:
        LDY     #$001D      ; (最大術ポイントへのインデックス)
        LDX     #$000E      ; (「最大術ポイントが上昇する確率」へのインデックス)

LC2DCFF:
        SEC
        SBC     #$0D
        STA     $3D
        LDA     ($B8),Y     ; 最大技(術)ポイントを取得する
        CMP     #$FA        ; 最大技(術)ポイントと$FA(250)とを比較して……
        BCC     $DD10       ; ……最大技(術)ポイントが250未満の場合は、ジャンプする

        LDA     #$FA        ;
        STA     ($B8),Y     ; 最大技(術)ポイントが999以上の場合、999にする
        BRA     $DD34

LC2DD10:
        SEP     #$20
        LDA     $1489,X     ; 「最大技(術)ポイントが上昇する確率」を取得する
        BEQ     $DD34       ; 「最大技(術)ポイントが上昇する確率」が0の場合、ジャンプする(最大技(術)ポイントは上昇しない)

        PHY
        STA     $8A
        STZ     $8B
        STZ     $BF         ; 0から……
        LDA     #$FF        ; ……255の範囲で……
        STA     $C0         ;
        JSR     $032E       ; ……乱数値を取得する
        LDA     $BF
        REP     #$20
        AND     #$00FF
        INC                 ; 乱数値に1を加えて
        CMP     $8A         ; ……「最大技(術)ポイントが上昇する確率」と比較して……
        SEP     #$20
        BCC     $DD35       ; ……「乱数値 + 1」が「最大技(術)ポイントが上昇する確率」未満であった場合、ジャンプする

        PLY

LC2DD34:
        RTS

LC2DD35:
        PLY
        LDA     ($B8),Y     ;
        INC                 ;
        STA     ($B8),Y     ; 最大技(術)ポイントを1増加する
        LDY     #$007A      ;
        LDA     #$00        ;
        STA     ($B8),Y     ; 「(成長しなかった)戦闘の回数」を0に戻す
        LDA     $22         ;
        ORA     #$03        ;
        STA     $22         ; 「フラグ0」と「フラグ1」をセットする
        JSL     $FEEBC4     ; 一回転して足を上げるアニメーション
        JSR     $CDB7       ; 「(能力)がアップ!」の表示
        JSR     $DDB1       ; レベルアップ確率を軒並み低下させる
        BRA     $DD34

;________________________________________________________________
;
; 各種武器/術レベルの上昇判定 & 上昇処理
;________________________________________________________________
;
LC2DD54:
        STA     $3D
        REP     #$20
        AND     #$00FF
        TAX
        CLC
        ADC     #$0025
        TAY
        SEP     #$20
        LDA     ($B8),Y     ; (現在判定中の)武器/術レベルを取得する
        CMP     #$32        ; (現在判定中の)武器/術レベルと$32(50)とを比較して……
        BCC     $DD6F       ; ……(現在判定中の)武器/術レベルが50未満の場合、ジャンプする

        LDA     #$32        ;
        STA     ($B8),Y     ; (現在判定中の)武器/術レベルが50以上の場合、50にする
        BRA     $DD91       ; ジャンプする((現在判定中の)武器/術レベルは上昇しない)

LC2DD6F:
        LDA     $1489,X     ; 「(現在判定中の)武器/術レベルが上昇する確率」を取得する
        BEQ     $DD91       ; 「(現在判定中の)武器/術レベルが上昇する確率」が0の場合、ジャンプする((現在判定中の)武器/術レベルは上昇しない)

        PHY
        STA     $8A
        STZ     $8B
        STZ     $BF         ; 0から……
        LDA     #$FF        ; ……255の範囲で……
        STA     $C0         ;
        JSR     $032E       ; ……乱数値を取得する
        LDA     $BF
        REP     #$20
        AND     #$00FF
        INC                 ; 乱数値に1を足して
        CMP     $8A         ; ……「(現在判定中の)武器/術レベルが上昇する確率」と比較して……
        SEP     #$20
        BCC     $DD92       ; ……「乱数値 + 1」が「(現在判定中の)武器/術レベルが上昇する確率」未満であった場合、ジャンプする

        PLY

LC2DD91:
        RTS

LC2DD92:
        PLY
        LDA     ($B8),Y     ;
        INC                 ;
        STA     ($B8),Y     ; (現在判定中の)武器/術レベルを1増加する
        LDY     #$007A      ;
        LDA     #$00        ;
        STA     ($B8),Y     ; 「(成長しなかった)戦闘の回数」を0に戻す
        LDA     $22         ;
        ORA     #$03        ;
        STA     $22         ; 「フラグ0」と「フラグ1」をセットする
        JSL     $FEEBC4     ; 一回転して足を上げるアニメーション
        JSR     $CDB7       ; 「(能力)がアップ!」の表示
        JSR     $DDB1       ; レベルアップ確率を軒並み低下させる
        BRA     $DD91

;________________________________________________________________
;
; レベルアップする確率を低下
;________________________________________________________________
;
LC2DDB1:
        LDX     #$0000

LC2DDB4:
        LDA     $1489,X     ; レベルアップする確率を取得して……
        CMP     $1499       ; ……確率低下修正値と比較して……
        BCS     $DDC0       ; ……レベルアップする確率が確率低下修正値以上の場合はジャンプする

        LDA     #$00        ; レベルアップする確率を0にする
        BRA     $DDC4

LC2DDC0:
        SEC
        SBC     $1499       ; レベルアップする確率から確率低下修正値を引く

LC2DDC4:
        STA     $1489,X
        INX
        CPX     #$0010      ; 全パラメータのレベルアップ確率について処理する
        BNE     $DDB4

        RTS

;________________________________________________________________
;
; パーティの中で最大ヒットポイントが最も低いキャラクタの最大ヒットポイントを1上げる
;________________________________________________________________
;
LC2DF6E:
        LDX     #$153D
        STX     $9E
        LDX     #$2280
        STX     $B8
        LDX     #$03E7      ;
        STX     $8A         ; パーティの中で最も低い最大ヒットポイント(を算出するための領域)
        LDA     #$00

LC2DF7F:
        PHA
        LDY     #$0000
        STA     ($9E),Y
        LDY     #$0007      ;
        LDA     ($B8),Y     ; キャラクタの状態を取得する
        BIT     #$84        ; 戦闘不能であるか離脱しているかを判定する
        BNE     $DFAE       ;

        LDY     #$0005      ;
        LDA     ($B8),Y     ; キャラクタの状態を取得する
        BIT     #$C0        ; 気絶であるか石化しているかを判定する
        BNE     $DFAE       ;

        REP     #$20
        LDY     #$0016      ;
        LDA     ($B8),Y     ; 最大ヒットポイントを取得して……
        CMP     $8A         ; ……パーティの中で最も低い最大ヒットポイントと比較して……
        BCS     $DFAE       ; ……最大ヒットポイントがパーティの中で最も低い最大ヒットポイント以上の場合はジャンプする

        STA     $8A
        SEP     #$20
        LDX     $9E
        STX     $A0
        LDX     $B8
        STX     $B6

LC2DFAE:
        REP     #$20
        LDA     $9E
        CLC
        ADC     #$000F
        STA     $9E
        LDA     $B8
        CLC
        ADC     #$0080
        STA     $B8
        SEP     #$20
        PLA
        INC
        CMP     $2D
        BNE     $DF7F

        LDX     $8A         ; パーティの中で最も低い最大ヒットポイントと……
        CPX     #$03E7      ; ……$03E7(999)を比較して……
        BEQ     $DFEA       ; ……パーティの中で最も低い最大ヒットポイントが999である場合、ジャンプする(最大ヒットポイントは上昇しない)

        LDX     $A0
        STX     $9E
        LDX     $B6
        STX     $B8
        REP     #$20
        LDY     #$0016      ;
        LDA     ($B8),Y     ;
        INC                 ;
        STA     ($B8),Y     ; パーティで最も最大ヒットポイントの低いキャラクタの最大ヒットポイントを1上げる
        SEP     #$20
        JSL     $FEEBC4     ; 一回転して足を上げるアニメーション
        JSR     $CD7A       ; 「(能力)がアップ!」の表示

LC2DFEA:
        RTS

;________________________________________________________________
;
; レベルアップ判定の乱数の境界値を取得
;   [入力]
;       $83:    レベルアップの難易度
;       $84:    レベルの上がりやすさ
;   [出力]
;       Aレジスタ:  レベルアップ判定の乱数の境界値
;________________________________________________________________
;
LFEE8E5:
        LDA     #$00
        XBA
        LDA     $83         ; レベルアップの難易度と……
        CMP     $84         ; ……レベルの上がりやすさを比較して……
        BCS     $E905       ; ……レベルアップの難易度がレベルの上がりやすさ以上であった場合はジャンプする

        LDA     $84
        SEC
        SBC     $83
        CMP     #$0A
        BEQ     $E8FB

        BCC     $E8FB

        LDA     #$0A

LFEE8FB:
        STA     $85
        LDA     #$0A
        SEC
        SBC     $85
        TAX                 ; 最終的には「レベルアップの難易度 - レベルの上がりやすさ + 10(最低値は0)」がXに格納される
        BRA     $E914

LFEE905:
        SEC
        SBC     $84
        CMP     #$0A
        BEQ     $E910

        BCC     $E910

        LDA     #$0A

LFEE910:
        CLC
        ADC     #$0A
        TAX                 ; 最終的には「レベルアップの難易度 - レベルの上がりやすさ + 10(最低値は0)」がXに格納される

LFEE914:
        LDA     $FE31AA,X   ; レベルアップ判定の乱数の境界値を取得する
        RTL

LFE31AA:
        DB      $64,$5A,$50,$46,$3C,$3C,$32,$28,$24,$20,$10,$08,$05,$03,$02,$01,$01,$01,$01,$00,$00
                            ; レベルアップ確率用テーブル

戦闘終了後のアイテム入手時の処理

;________________________________________________________________
;
; 戦闘終了後のアイテム入手時の処理
;________________________________________________________________
;
LC2E0A8:
        STZ     $0A3A       ; ループ回数

LC2E0AB:
        LDA     #$00
        XBA
        LDA     $0A3A
        TAX
        LDA     $C2E0D4,X   ; アイテム入手確率テーブルから、判定用乱数の最大値を決める
        STA     $0A3B
        JSR     $E0D8       ; アイテム入手判定を行う
        BEQ     $E0C9       ; 判定に失敗した場合はジャンプする

        JSL     $FEEBE4     ; アイテムの個数を調べる
        BNE     $E0C9       ; アイテム欄に空きがない or すでに最大個数持っている場合、ジャンプする(アイテム入手判定の続き)

        JSR     $CE72       ; アイテムを入手する
        BRA     $E0D3       ; アイテム入手判定を途中で打ち切る

LC2E0C9:
        INC     $0A3A       ; 次のアイテムの判定に移る
        LDA     $0A3A
        CMP     #$04        ;
        BNE     $E0AB       ; 4種類のアイテムすべてについて判定を行う

LC2E0D3:
        RTS

LC2E0D4:
        DB      $00,$0F,$1F,$3F     ; アイテム入手確率用のテーブル


LC2E0D8:
        LDX     #$2000
        STX     $B8
        LDA     $34         ; 倒したモンスターの数

LC2E0DF:
        PHA
        REP     #$20
        LDY     #$0000
        LDA     ($B8),Y
        BIT     #$2000      ;
        SEP     #$20
        BNE     $E153       ; 不明

        LDY     #$0007
        LDA     ($B8),Y     ;
        BIT     #$80        ; 一撃死技(?)の判定
        BEQ     $E153       ; 一撃死技(?)で倒した場合はジャンプする(アイテム入手判定失敗)

        LDY     #$0005
        LDA     ($B8),Y     ;
        BIT     #$04        ; 一撃死技(?)の判定
        BNE     $E153       ; 一撃死技(?)で倒した場合はジャンプする(アイテム入手判定失敗)

        LDY     #$004F
        LDA     ($B8),Y     ;
        AND     #$3F        ; アイテムテーブルのインデックスを取得する
        STA     $BF         ; 被乗数にアイテムテーブルのインデックスを設定する
        LDA     #$05        ;
        STA     $C0         ; 乗数に5を設定する
        LDA     $0A3A
        STA     $8A
        STZ     $8B
        JSR     $0227       ; 「アイテムテーブルのインデックス×5」を計算する
        REP     #$20
        LDA     $C4
        CLC
        ADC     $8A         ; ループ回数(現在何番目のアイテムの入手判定をしているか)を加算する
        TAX
        SEP     #$20
        LDA     #$00
        XBA
        LDA     $FE678B,X   ; アイテムテーブルから、入手アイテム番号を取得する
        CMP     #$FF        ; 入手アイテム番号が$FF(アイテムなし)の場合……
        BEQ     $E153       ; ……ジャンプする(アイテム入手判定失敗)

        CMP     #$FD        ; アイテム番号が$FD未満(通常アイテム)の場合……
        BCC     $E13D       ; ……ジャンプする

        SEC
        SBC     #$FD
        CLC
        ADC     #$47
        TAY
        LDA     ($B8),Y     ; 装備武器1または2が入手アイテムとなる
        CMP     #$FF        ; 入手アイテム番号が$FF(アイテムなし)の場合……
        BEQ     $E153       ; ……ジャンプする(アイテム入手判定失敗)

LC2E13D:
        STA     $0946
        STZ     $BF         ; 0から……
        LDA     $0A3B       ; ……アイテム入手確率判定用乱数の最大値の範囲で……
        STA     $C0
        JSR     $032E       ; ……乱数値を取得する
        LDA     $BF
        BNE     $E153       ; 乱数値が0以外であった場合、ジャンプする(アイテム入手判定失敗)

        PLA
        LDA     #$FF        ; Aに$FFを格納してサブルーチンを終了する(アイテム入手判定に成功したことを意味する)
        BRA     $E166

LC2E153:
        REP     #$20
        LDA     $B8
        CLC
        ADC     #$0080      ; 次のモンスターの判定に移る
        STA     $B8
        SEP     #$20
        PLA
        DEC
        BEQ     $E166

        JMP     $E0DF       ; Aに$00が格納された状態でサブルーチンを終了する(アイテム入手判定に失敗したことを意味する)

LC2E166:
        RTS

;________________________________________________________________
;
; モンスターレベルの上昇処理
;________________________________________________________________
;
LC2DA6B:
        JSR     $DB4C       ; $142Fと$1430に値を設定する
        JSR     $DA7C       ; 従属モンスターレベルの上昇処理を行う
        LDA     $1314       ; バトルの種類を取得して……
        CMP     #$19        ; ……$19(イベントバトル)と比較して……
        BEQ     $DA7B       ; ……バトルの種類がイベントバトルである場合はジャンプする

        JSR     $DAD8       ; 種族ごとのモンスターレベルの上昇処理を行う

LC2DA7B:
        RTS

;________________________________________________________________
;
; 従属モンスターレベルの上昇処理
;________________________________________________________________
;
LC2DA7C:
        STZ     $BF         ; 0から……
        LDA     #$FF        ; ……255の範囲で……
        STA     $C0         ;
        JSR     $032E       ; ……乱数値を取得する
        LDA     #$08        ;
        STA     $8A         ; レベル上昇修正値の初期値として8を設定する
        STZ     $8B         ;
        LDX     #$0000

LC2DA8E:
        LDA     $FE9B7D,X   ; 判定用境界値を取得する
        CMP     $BF         ; 乱数値と比較して……
        BCS     $DA9B       ; ……境界値が乱数値以上である場合はジャンプする(ループから抜ける)

        INX                 ; 次の境界値に移動する
        DEC     $8A         ; レベル上昇修正値を1減らす
        BNE     $DA8E       ; レベル上昇値が1以上であればジャンプする(ループを繰り返す)

LC2DA9B:
        LDA     $1430       ; 種族モンスターレベル÷16と……
        CMP     $142F       ; ……従属モンスターレベル÷16とを比較して……
        BCS     $DAA7       ; ……種族モンスターレベル÷16が従属モンスターレベル以上であればジャンプする

        LDA     #$00        ; レベル上昇基本値は0とする
        BRA     $DAAB

LC2DAA7:
        SEC
        SBC     $142F       ; レベル上昇基本値は、「種族モンスターレベル÷16 - 従属モンスターレベル÷16」とする

LC2DAAB:
        REP     #$20
        AND     #$00FF      ;
        CLC                 ;
        ADC     $8A         ; レベル上昇基本値と、レベル上昇修正値とを加算して……
        STA     $8A         ; ……最終的な結果を、レベル上昇値として格納する
        SEP     #$20
        LDA     $FE9C05     ; 従属モンスターレベルの上限値を取得する
        STA     $8C
        STZ     $8D
        LDA     $F532       ; 現在の従属モンスターレベルと……
        REP     #$20        ;
        AND     #$00FF      ;
        CLC                 ;
        ADC     $8A         ; ……レベル上昇値とを加算して……
        CMP     $8C         ; ……レベル上限値と比較する
        SEP     #$20
        BEQ     $DAD4       ;
        BCC     $DAD4       ; 「従属モンスターレベル + レベル上昇値」がレベル上限値以下の場合はジャンプする

        LDA     $8C         ; 最終的な従属モンスターレベルは、レベル上限値になる

LC2DAD4:
        STA     $F532       ; 最終的な従属モンスターレベルを設定する
        RTS

;________________________________________________________________
;
; 種族ごとのモンスターレベルの上昇処理
;________________________________________________________________
;
LC2DAD8:
        STZ     $BF         ; 0から……
        LDA     #$FF        ; ……255の範囲で……
        STA     $C0         ;
        JSR     $032E       ; ……乱数値を取得する
        LDA     #$08        ;
        STA     $8A         ; レベル上昇修正値の初期値として8を設定する
        STZ     $8B         ;
        REP     #$20
        LDA     $2000       ; リーダーモンスターの番号から……
        AND     #$00F0      ; ……上位4ビット(種族)を取得して……
        JSR     $0412       ; ……16で割って……
        JSR     $0408       ; ……8倍する
        TAX
        SEP     #$20
        LDA     $FE9B85,X   ; 種族ごとの判定用境界値を取得する
        CMP     $BF         ; 乱数値と比較して……
        BCS     $DB05       ; ……境界値が乱数値以上である場合はジャンプする(ループから抜ける)

        INX                 ; 次の境界値に移動する
        DEC     $8A         ; レベル上昇修正値を1減らす
        BNE     $DAF8       ; レベル上昇値が1以上であればジャンプする(ループを繰り返す)

LC2DB05:
        LDA     $142F       ; 従属モンスターレベル÷16と……
        CMP     $1430       ; ……種族モンスターレベル÷16とを比較して……
        BCS     $DB11       ; ……従属モンスターレベル÷16が種族モンスターレベル以上であればジャンプする

        LDA     #$00        ; レベル上昇基本値は0とする
        BRA     $DB15

LC2DB11:
        SEC
        SBC     $1430       ; レベル上昇基本値は、「従属モンスターレベル÷16 - 種族モンスターレベル÷16」とする

LC2DB15:
        REP     #$20
        AND     #$00FF      ;
        CLC                 ;
        ADC     $8A         ; レベル上昇基本値と、レベル上昇修正値とを加算して……
        STA     $8A         ; ……最終的な結果を、レベル上昇値として格納する
        LDA     $2000       ; リーダーモンスターの番号から……
        AND     #$00F0      ; ……上位4ビット(種族)を取得して……
        JSR     $0412       ; ……16で割る
        TAX
        SEP     #$20
        LDA     $FE9C06,X   ; 種族ごとのモンスターレベルの上限値を取得する
        STA     $8C
        STZ     $8D
        LDA     $F533,X     ; 現在の種族ごとのモンスターレベルと……
        REP     #$20        ;
        AND     #$00FF      ;
        CLC                 ;
        ADC     $8A         ; ……レベル上昇値とを加算して……
        CMP     $8C         ; ……レベル上限値と比較する
        SEP     #$20
        BEQ     $DB48       ;
        BCC     $DB48       ;「種族ごとのモンスターレベル + レベル上昇値」がレベル上限値以下の場合はジャンプする

        LDA     $8C         ; 最終的な種族ごとのモンスターレベルは、レベル上限値になる

LC2DB48:
        STA     $F533,X     ; 最終的な種族ごとのモンスターレベルを設定する
        RTS

出現モンスター決定の処理

;________________________________________________________________
;
; 出現モンスター決定処理
;________________________________________________________________
;
LC213EA:
        LDA     $141B       ;
        AND     #$0F        ; モンスターの種族を取得する
        STA     $5D
        JSR     $1411       ; 種族を元に、リーダーモンスターを決定する
        LDA     $5A         ; 最大モンスター数と……
        CMP     $34         ; ……現在のモンスター数とを比較して……
        BEQ     $1410       ; ……モンスター数が最大数に達した場合はジャンプする

        LDA     $141B       ;
        AND     #$F0        ; 従属モンスタータイプ(16倍されている)を取得する
        CMP     #$F0        ;
        BNE     $1408       ; 従属モンスタータイプが$Fでない場合はジャンプする

        JSR     $1461       ; 従属モンスター決定処理(同種族のモンスターから選択)
        BRA     $1410

LC21408:
        JSR     $14D0       ; リーダーモンスターを増加する
        BEQ     $1410       ; 現在のモンスター数が最大数に達していた場合はジャンプする

        JSR     $150C       ; 従属モンスター決定処理(従属モンスターテーブルから選択)

LC21410:
        RTS

;________________________________________________________________
;
; リーダーモンスター決定処理
;________________________________________________________________
;
LC21411:
        LDA     $5D         ; 種族番号を取得して……
        REP     #$20
        AND     #$00FF
        JSR     $0406       ; ……32倍する
        STA     $8A
        SEP     #$20
        JSR     $15A0       ; 種族モンスターレベルに乱数修正をかけて、モンスターレベルを決定する
        LDA     $56         ; 乱数修正後のモンスターレベルを取得して……
        REP     #$20
        AND     #$00FF
        JSR     $0412       ; ……16で割って……
        ASL                 ; ……2倍して……
        CLC
        ADC     $8A         ; ……種族番号×32を加算して……
        TAX                 ; ……テーブルのインデックスとする
        SEP     #$20
        LDA     $FE77BB,X   ; 乱数修正後のモンスターレベルから、リーダーモンスターの番号を取得する
        REP     #$20
        AND     #$00FF
        STA     $16D2       ; リーダーモンスターの番号を格納する
        LDY     #$0000
        ORA     #$8000
        STA     ($B8),Y     ; 1体目のモンスターの番号を設定する
        SEP     #$20
        LDA     $FE77BC,X   ; モンスターパーティの編成データを取得する
        STA     $59
        JSR     $176F       ; モンスターパーティの各種データを設定する
        REP     #$20
        LDA     $B8         ;
        CLC                 ;
        ADC     #$0080      ;
        STA     $B8         ; 次のモンスターのアドレスに移動する
        SEP     #$20
        INC     $34         ; モンスター数を1増加する
        RTS

;________________________________________________________________
;
; 従属モンスター決定処理(同種族のモンスターから選択)
;________________________________________________________________
;
LC21461:
        LDA     $5A         ; モンスターの最大数から……
        SEC
        SBC     $34         ; ……現在のモンスター数を引く(ループ残り回数)

LC21466:
        PHA                 ; ループ残り回数をスタックに格納する
        JSR     $15A0       ; 種族モンスターレベルに乱数修正をかけて、モンスターレベルを決定する
        JSL     $FED0AF     ; 境界値を決定する
        LDA     #$01        ; 1から……
        STA     $BF         ;
        LDA     #$0F        ; ……15の範囲で……
        STA     $C0         ;
        JSR     $032E       ; ……乱数値を取得する
        LDA     $57         ; 境界値と……
        CMP     $BF         ; ……乱数値とを比較して……
        BCC     $14CB       ; ……乱数値が境界値以上であった場合はジャンプする

        LDA     $5D         ; 種族番号を取得して……
        REP     #$20
        AND     #$00FF
        JSR     $0406       ; ……32倍する
        STA     $8A
        SEP     #$20
        LDA     $56         ; 乱数修正後のモンスターレベルを取得して……
        REP     #$20
        AND     #$00FF
        JSR     $0412       ; ……16で割って……
        ASL                 ; ……2倍して……
        CLC
        ADC     $8A         ; ……種族番号×32を加算して……
        TAX                 ; ……テーブルのインデックスとする
        SEP     #$20
        LDA     $FE77BB,X   ; 乱数修正後のモンスターレベルから、種族モンスターの番号を取得する
        REP     #$20
        AND     #$00FF
        LDY     #$0000
        ORA     #$8000
        STA     ($B8),Y     ; モンスターの番号を設定する
        SEP     #$20
        JSL     $FED107     ; モンスターサイズの判定を行う
        BNE     $14CB       ; モンスターサイズがモンスターパーティの最大サイズを超えた場合はジャンプする

        JSL     $FED139     ; モンスターの種類の判定を行う
        BNE     $14CB       ; モンスターパーティにすでに3種類のモンスターが存在する場合はジャンプする

        REP     #$20
        LDA     $B8         ;
        CLC                 ;
        ADC     #$0080      ;
        STA     $B8         ; 次のモンスターのアドレスに移動する
        SEP     #$20
        INC     $34         ; モンスター数を1増加する

LC214CB:
        PLA                 ; ループ残り回数をスタックから取得する
        DEC                 ; ループ残り回数を1減らす
        BNE     $1466       ; ループ残り回数が0でなければジャンプする

        RTS

;________________________________________________________________
;
; リーダーモンスターを増加する
;________________________________________________________________
;
LC214D0:
        LDA     $5A         ; モンスターの最大数から……
        SEC
        SBC     $34         ; ……現在のモンスター数を引く(ループ残り回数)

LC214D5:
        PHA                 ; ループ残り回数をスタックに格納する
        JSL     $FED0AF     ; 境界値を決定する
        LDA     #$01        ; 1から……
        STA     $BF         ;
        LDA     #$0F        ; ……15の範囲で……
        STA     $C0         ;
        JSR     $032E       ; ……乱数値を取得する
        LDA     $57         ; 境界値と……
        CMP     $BF         ; ……乱数値とを比較して……
        BCS     $14F4       ; ……乱数値が境界値未満であった場合はジャンプする

LC214EB:
        PLA                 ; ループ残り回数をスタックから取得する
        DEC                 ; ループ残り回数を1減らす
        BNE     $14D5       ; ループ残り回数が0でなければジャンプする

        LDA     $34         ; 現在のモンスター数と……
        CMP     $5A         ; ……モンスターの最大数を比較する
        RTS


LC214F4:
        REP     #$20
        LDY     #$0000      ;
        LDA     $2000       ; リーダーモンスターの番号を取得する
        STA     ($B8),Y     ; モンスターの番号を設定する
        LDA     $B8         ;
        CLC                 ;
        ADC     #$0080      ;
        STA     $B8         ; 次のモンスターのアドレスに移動する
        SEP     #$20
        INC     $34         ; モンスター数を1増加する
        BRA     $14EB

;________________________________________________________________
;
; 従属モンスター決定処理(従属モンスターテーブルから選択)
;________________________________________________________________
;
LC2150C:
        JSL     $FED0D9     ; 境界値を決定する
        LDA     $5A         ; モンスターの最大数から……
        SEC
        SBC     $34         ; ……現在のモンスター数を引く(ループ残り回数)

LC21515:
        PHA                 ; ループ残り回数をスタックに格納する
        LDA     #$01        ; 1から……
        STA     $BF         ;
        LDA     #$0F        ; ……15の範囲で……
        STA     $C0         ;
        JSR     $032E       ; ……乱数値を取得する
        LDA     $58         ; 境界値と……
        CMP     $BF         ; ……乱数値とを比較して……
        BCS     $152C       ; ……乱数値が境界値未満であった場合はジャンプする

LC21527:
        PLA                 ; ループ残り回数をスタックから取得する
        DEC                 ; ループ残り回数を1減らす
        BNE     $1515       ; ループ残り回数が0でなければジャンプする

        RTS


LC2152C:
        LDA     #$03        ; 内部ループ回数の初期値は3とする

LC2152E:
        PHA                 ; 内部ループ残り回数をスタックに格納する
        JSR     $15C3       ; 従属モンスターレベルに乱数修正をかけて、モンスターレベルを決定する
        LDA     $141B       ;
        AND     #$F0        ;
        JSR     $0412       ; 従属モンスタータイプを取得する
        STA     $BF         ; 被乗数に従属モンスタータイプを設定する
        LDA     #$60        ;
        STA     $C0         ; 乗数に$60(96)を設定する
        JSR     $0227       ; 「従属モンスタータイプ×96」の計算をする
        REP     #$20
        LDA     $C4         ;
        CLC                 ;
        ADC     #$0060      ;
        STA     $8A         ; インデックスの最大値を設定する
        SEP     #$20
        LDX     $C4         ; インデックスを設定する

LC21551:
        LDA     $FE79BB,X   ; 従属モンスターテーブルからモンスターレベルを取得して……
        CMP     $56         ; ……乱数修正後のモンスターレベルと比較して……
        BEQ     $1563       ;
        BCC     $1563       ; ……乱数修正後のモンスターレベルがテーブルから取得したモンスターレベル以上だった場合はジャンプする

        INX                 ;
        INX                 ; 現在のインデックスを2バイト分進めて……
        CPX     $8A         ; ……インデックスの最大値と比較して……
        BNE     $1551       ; ……現在のインデックスが最大値に到達していない場合はジャンプする

        BRA     $159A

LC21563:
        LDA     $FE79BC,X   ; 従属モンスターテーブルから出現モンスターを取得する
        REP     #$20
        AND     #$00FF
        LDY     #$0000
        ORA     #$8000
        STA     ($B8),Y     ; モンスターの番号を設定する
        SEP     #$20
        JSL     $FED107     ; モンスターサイズの判定を行う
        BNE     $159A       ; モンスターサイズがモンスターパーティの最大サイズを超えた場合はジャンプする

        JSL     $FED139     ; モンスターの種類の判定を行う
        BNE     $159A       ; モンスターパーティにすでに3種類のモンスターが存在する場合はジャンプする

        PLA                 ; 内部ループ回数をスタックから破棄する
        REP     #$20
        LDA     $B8         ;
        CLC                 ;
        ADC     #$0080      ;
        STA     $B8         ; 次のモンスターのアドレスに移動する
        SEP     #$20
        INC     $34         ; モンスター数を1増加する
        LDA     $58         ; 境界値を取得して……
        BEQ     $159E       ; ……境界値が0であればジャンプする(処理終了) (あり得ない?)

        DEC                 ;
        STA     $58         ; 境界値を1減らす
        BRA     $1527

LC2159A:
        PLA                 ; 内部ループ残り回数をスタックから取得する
        DEC                 ; 内部ループ残り回数を1減らす
        BNE     $152E       ; 内部ループ残り回数が0でなければジャンプする

LC2159E:
        PLA                 ; ループ残り回数をスタックから破棄する
        RTS

;________________________________________________________________
;
; 最終的な種族モンスターレベルを算出する
;________________________________________________________________
;
LC215A0:
        LDA     $82
        PHA
        LDX     $8A
        PHX
        LDX     $8C
        PHX
        LDX     $8E
        PHX
        JSR     $15E6       ; 種族モンスターレベルに乱数修正をかける
        JSR     $16B0       ; 地域ごとに設定された最低モンスターレベルに乱数修正をかける
        JSL     $FED097     ; 大きい方の値を最終的なモンスターレベルとして採用する
        PLX
        STX     $8E
        PLX
        STX     $8C
        PLX
        STX     $8A
        PLA
        STA     $82
        RTS

;________________________________________________________________
;
; 最終的な従属モンスターレベルを算出する
;________________________________________________________________
;
LC215C3:
        LDA     $82
        PHA
        LDX     $8A
        PHX
        LDX     $8C
        PHX
        LDX     $8E
        PHX
        JSR     $16F1       ; 従属モンスターレベルに乱数修正をかける
        JSR     $16B0       ; 地域ごとに設定された最低モンスターレベルに乱数修正をかける
        JSL     $FED097     ; 大きい方の値を最終的なモンスターレベルとして採用する
        PLX
        STX     $8E
        PLX
        STX     $8C
        PLX
        STX     $8A
        PLA
        STA     $82
        RTS

;________________________________________________________________
;
; 種族モンスターレベルに乱数修正をかける
;________________________________________________________________
;
LC215E6:
        LDA     $141C       ; 修正値を取得する
        BEQ     $1624       ; 修正値が0の場合はジャンプする(種族モンスターレベルからモンスターレベルを算出)

        LDA     $F532       ; 従属モンスターレベルを取得する
        STA     $8A
        STZ     $8B
        LDA     $141C       ; 修正値を取得する
        REP     #$20
        AND     #$00FF
        BIT     #$0080      ; 修正値の最上位ビットが……
        BEQ     $1614       ; ……0の場合はジャンプする(プラス修正)

        AND     #$FF7F      ;
        STA     $8C         ; 修正値の下位7ビットを格納する
        LDA     $8A         ; 従属モンスターレベルと……
        CMP     $8C         ; ……修正値の下位7ビットとを比較して……
        BCS     $160F       ; ……従属モンスターレベルが修正値以上の場合はジャンプする

        LDA     #$0000      ; モンスターレベル基本値は0とする
        BRA     $1617

LC2160F:
        SEC
        SBC     $8C         ; モンスターレベル基本値は「従属モンスターレベル - 修正値」とする
        BRA     $1617

LC21614:
        CLC
        ADC     $8A         ; モンスターレベル基本値は「従属モンスターレベル + 修正値」とする

LC21617:
        CMP     #$00FF      ; モンスターレベル基本値と$FF(255)とを比較して……
        SEP     #$20
        BEQ     $162D       ;
        BCC     $162D       ; ……モンスターレベル基本値が255以下の場合はジャンプする

        LDA     #$FF        ; モンスターレベル基本値は255とする。
        BRA     $162D

LC21624:
        LDA     #$00        ;
        XBA                 ;
        LDA     $5D         ;
        TAX                 ; 種族番号をインデックスとする
        LDA     $F533,X     ; 種族モンスターレベルをモンスターレベル基本値とする

LC2162D:
        STA     $82         ; モンスターレベル基本値を格納する
        STA     $BF         ; 被乗数にモンスターレベル基本値を設定する
        LDA     #$07        ;
        STA     $C0         ; 乗数に$07(7)を設定する
        JSR     $0227       ; 「モンスターレベル基本値×7」の計算をする
        REP     #$20
        LDA     $C4         ; 「モンスターレベル基本値×7」を取得して……
        JSR     $0413       ; ……8で割る
        STA     $8A         ; 現時点のモンスターレベルとして格納する
        SEP     #$20
        LDA     #$01        ; 1から……
        STA     $BF         ;
        LDA     $82         ; (モンスターレベル基本値を取得して……)
        JSR     $0413       ; (……8で割る)
        STA     $C0         ; ……モンスターレベル基本値÷8の範囲で……
        JSR     $032E       ; ……乱数値を取得する
        LDA     $BF         ;
        REP     #$20        ;
        AND     #$00FF      ;
        CLC                 ;
        ADC     $8A         ;
        STA     $8A         ; 現時点のモンスターレベルに「1〜モンスターレベル基本値÷8の乱数値」を加算する
        SEP     #$20
        LDA     #$01        ; 1から……
        STA     $BF         ;
        LDA     $82         ; (モンスターレベル基本値を取得して……)
        JSR     $0413       ; (……8で割る)
        STA     $C0         ; ……モンスターレベル基本値÷8の範囲で……
        JSR     $032E       ; ……乱数値を取得する
        LDA     $BF         ;
        REP     #$20        ;
        AND     #$00FF      ;
        CLC                 ;
        ADC     $8A         ;
        STA     $8A         ; 現時点のモンスターレベルに「1〜モンスターレベル基本値÷8の乱数値」を加算する
        SEP     #$20
        LDA     $F319       ; パーティ人数を取得して……
        REP     #$20        ;
        AND     #$00FF      ;
        CLC                 ;
        ADC     $8A         ;
        STA     $8A         ; 現時点のモンスターレベルにパーティ人数を加算する
        SEP     #$20
        LDA     #$01        ; 1から……
        STA     $BF         ;
        LDA     #$08        ; ……8の範囲で……
        STA     $C0         ;
        JSR     $032E       ; ……乱数値を取得する
        LDA     $BF
        STA     $8C
        STZ     $8D
        REP     #$20
        LDA     $8A         ; 現時点のモンスターレベルと……
        CMP     $8C         ; ……1〜8の乱数値とを比較して……
        BCS     $16A8       ; ……現時点のモンスターレベルが1〜8の乱数値以上であればジャンプする

        LDA     #$0000      ; モンスターレベルは0とする
        BRA     $16AB

LC216A8:
        SEC
        SBC     $8C         ; 現時点のモンスターレベルから1〜8の乱数値を引く

LC216AB:
        STA     $8A         ; 最終的なモンスターレベルを格納する
        SEP     #$20
        RTS

;________________________________________________________________
;
; 地域ごとに設定された最低モンスターレベルに乱数修正をかける
;________________________________________________________________
;
LC216B0:
        LDA     $1308       ; 地域ごとに設定された最低モンスターレベルを取得する
        REP     #$20
        AND     #$00F0      ; 上位4ビットをクリアする
        STA     $8C         ; 現時点のモンスターレベルとして格納する
        SEP     #$20
        LDA     $F319       ; パーティ人数を取得して……
        REP     #$20        ;
        AND     #$00FF      ;
        CLC                 ;
        ADC     $8C         ;
        STA     $8C         ; 現時点のモンスターレベルにパーティ人数を加算する
        SEP     #$20
        LDA     #$01        ; 1から……
        STA     $BF         ;
        LDA     #$08        ; ……8の範囲で……
        STA     $C0         ;
        JSR     $032E       ; ……乱数値を取得する
        LDA     $BF
        STA     $8E
        STZ     $8F
        REP     #$20
        LDA     $8C         ; 現時点のモンスターレベルと……
        CMP     $8E         ; ……1〜8の乱数値とを比較して……
        BCS     $16E9       ; ……現時点のモンスターレベルが1〜8の乱数値以上であればジャンプする

        LDA     #$0000      ; モンスターレベルは0とする
        BRA     $16EC

LC216E9:
        SEC
        SBC     $8E         ; 現時点のモンスターレベルから1〜8の乱数値を引く

LC216EC:
        STA     $8C         ; 最終的なモンスターレベルを格納する
        SEP     #$20
        RTS

;________________________________________________________________
;
; 従属モンスターレベルに乱数修正をかける
;________________________________________________________________
;
LC216F1:
        STZ     $8A
        STZ     $8B
        LDA     $F532       ; 従属モンスターレベルを取得する
        STA     $82
        STA     $BF         ; 被乗数に従属モンスターレベルを設定する
        LDA     #$07        ;
        STA     $C0         ; 乗数に$07(7)を設定する
        JSR     $0227       ; 「従属モンスターレベル×7」の計算をする
        REP     #$20
        LDA     $C4         ; 「従属モンスターレベル×7」を取得して……
        JSR     $0413       ; ……8で割る
        STA     $8A         ; 現時点のモンスターレベルとして格納する
        SEP     #$20
        LDA     #$01        ; 1から……
        STA     $BF         ;
        LDA     $82         ; (従属モンスターレベルを取得して……)
        JSR     $0413       ; (……8で割る)
        STA     $C0         ; ……従属モンスターレベル÷8の範囲で……
        JSR     $032E       ; ……乱数値を取得する
        LDA     $BF         ;
        REP     #$20        ;
        AND     #$00FF      ;
        CLC                 ;
        ADC     $8A         ;
        STA     $8A         ; 現時点のモンスターレベルに「1〜従属モンスターレベル÷8の乱数値」を加算する
        SEP     #$20
        LDA     #$01        ; 1から……
        STA     $BF         ;
        LDA     $82         ; (従属モンスターレベルを取得して……)
        JSR     $0413       ; (……8で割る)
        STA     $C0         ; ……従属モンスターレベル÷8の範囲で……
        JSR     $032E       ; ……乱数値を取得する
        LDA     $BF         ;
        REP     #$20        ;
        AND     #$00FF      ;
        CLC                 ;
        ADC     $8A         ;
        ADC     #$0004      ;
        STA     $8A         ; 現時点のモンスターレベルに「1〜従属モンスターレベル÷8の乱数値」と「4」とを加算する
        SEP     #$20
        LDA     #$01        ; 1から……
        STA     $BF         ;
        LDA     #$08        ; ……8の範囲で……
        STA     $C0         ;
        JSR     $032E       ; ……乱数値を取得する
        LDA     $BF
        STA     $8C
        STZ     $8D
        REP     #$20
        LDA     $8A         ; 現時点のモンスターレベルと……
        CMP     $8C         ; ……1〜8の乱数値とを比較して……
        BCS     $1767       ; ……現時点のモンスターレベルが1〜8の乱数値以上であればジャンプする

        LDA     #$0000      ; モンスターレベルは0とする
        BRA     $176A

LC21767:
        SEC
        SBC     $8C         ; 現時点のモンスターレベルから1〜8の乱数値を引く

LC2176A:
        STA     $8A         ; 最終的なモンスターレベルを格納する
        SEP     #$20
        RTS

;________________________________________________________________
;
; リーダーモンスター増加処理における「境界値」を設定する
;________________________________________________________________
;
LFED0AF:
        STZ     $82         ; 修正値の初期値は0とする
        LDA     $F532       ; 従属モンスターレベルを取得して……
        CMP     $56         ; ……乱数修正後のモンスターレベルと比較して……
        BEQ     $D0C3       ;
        BCC     $D0C3       ; ……従属モンスターレベルが乱数修正後のモンスターレベル以下だった場合はジャンプする

        SEC                 ;
        SBC     $56         ; 従属モンスターレベルから乱数修正後のモンスターレベルを引いて……
        LSR                 ;
        LSR                 ;
        LSR                 ;
        LSR                 ; ……16で割る
        STA     $82         ; 修正値として格納する

LFED0C3:
        LDA     $56         ; 乱数修正後のモンスターレベルの……
        AND     #$0F        ; ……下位4ビットを取得して……
        LSR                 ; ……2で割って……
        CLC                 ;
        ADC     $82         ; ……修正値を加えたものを現時点の境界値とする
        CMP     $34         ; 現在のモンスター数と比較する
        BCS     $D0D3

        LDA     #$00        ; 境界値は0とする
        BRA     $D0D6

LFED0D3:
        SEC
        SBC     $34         ; 現時点の境界値から現在のモンスター数を引く

LFED0D6:
        STA     $57         ; 最終的な境界値を格納する
        RTL

;________________________________________________________________
;
; 従属モンスター決定処理における「境界値」を設定する
;________________________________________________________________
;
LFED0D9:
        STZ     $82         ; 修正値の初期値は0とする
        LDA     $F532       ; 従属モンスターレベルを取得して……
        CMP     $56         ; ……乱数修正後のモンスターレベルと比較して……
        BEQ     $D0ED       ;
        BCC     $D0ED       ; ……従属モンスターレベルが乱数修正後のモンスターレベル以下だった場合はジャンプする

        SEC                 ;
        SBC     $56         ; 従属モンスターレベルから乱数修正後のモンスターレベルを引いて……
        LSR                 ;
        LSR                 ;
        LSR                 ;
        LSR                 ; ……16で割る
        STA     $82         ; 修正値として格納する

LFED0ED:
        LDA     $56         ; 乱数修正後のモンスターレベルの……
        AND     #$0F        ; ……下位4ビットを取得して……
        LSR                 ; ……2で割って……
        CLC                 
        ADC     $FE317A     ; ……$FE317Aの内容(4)を加えて……
        ADC     $82         ; ……修正値を加えたものを現時点の境界値とする
        CMP     $34         ; 現在のモンスター数と比較する
        BCS     $D101

        LDA     #$00        ; 境界値は0とする
        BRA     $D104

LFED101:
        SEC
        SBC     $34         ; 現時点の境界値から現在のモンスター数を引く

LFED104:
        STA     $58         ; 最終的な境界値を格納する
        RTL

今後の予定

「予定」というよりは「調査したいことの羅列」といった方が正確かもしれません。このリストの中には、「すでに調査は終わっていて、ドキュメントを書くだけ」というものから「今の私のスキルでは無理だが、いつかはやってみたい」といったものまで含まれています。

おわりに

くれぐれも、解析結果を盲信しないでください。例によって、私は解析結果の検証はほとんどやっていません。また、65816やスーパーファミコンのアーキテクチャについての知識にも乏しいため、プログラムコードの解釈に間違いがある可能性は大いにあります。誤りがあった場合はご連絡ください。

Author: Shingo Endo <s-endo@yk.rim.or.jp>
Last Updated: 2004-04-12
Copyright ©2001, 2002, 2004 Shingo Endo