3.11. エンカウント制御

3.11.1. 概要
3.11.2. グループ
3.11.3. 特別エンカウントの場合
3.11.4. 出現グループ数が単独の場合
3.11.5. 出現グループ数が複数の場合

移動モードから戦闘モードに移行するときのプログラムの制御について述べる。 この項は、計算機の知識なしには読解できないような記述を含むかもしれない。

また、「エンカウント」「一歩移動」「乱数」などの ドラクエ用語、符丁や計算機用語を定義を与えずに用いる。

3.11.1. 概要

フィールドやダンジョンなどを一歩移動するごとに、トヘロスやせいすいなどを 使用していなければ、プログラムは次の評価をする:

  1. 移動しているフィールド地域、ダンジョンレベル等からタイルエンカウント ID [dq5.data.encounter]を決定する。

  2. ID に対応するエンカウント確率を計算し、乱数的要素によりエンカウントするかどうかを決定する。

移動地域とタイルエンカウントID の対応表は、偉大なる先人によって解析済である。 dq_analyzer - スーパーファミコン版ドラゴンクエスト データ解析プログラム (Shingo Endo 氏解析資料 [URL1]) から入手できるテキストファイル (dq5monmap.txt) に克明に記述されている。

エンカウント率を決定する要因は、以下のものが確認されている。 これによって、乱数がエンカウントデータと歩行状況から決まる値より小さければ、エンカウントを免れる。 そうでなければ「とりあえず」エンカウント決定となる。

  • タイルエンカウントデータから間接的に取得できる定数である エンカウント決定係数

  • 前回戦闘終了後からの歩数、現在位置の地形……といった歩行状況

  • 0 以上 255 以下をとる乱数

そしてすぐに、次のような感じで戦闘モード初期状態の設定処理を行う。 最後の処理で、データとしてはあり得ないが、和 $0F がゼロであれば、 エンカウントの処理はキャンセルされる。

  1. 謎のパラメータをセットする。 「しょきじょうたい」(© PS 版ドラクエ 7 デバッグモード) の決定に関与か?

  2. タイルエンカウントデータから、レベルを取得し、 然るべきアドレスに値をセットしておく。

  3. 戦闘終了後に仲間チェックをするかどうかを決定する。

  4. グループのモンスター ID および構成匹数を無効な値で初期化。

  5. モンスターID 決定用データ 0~A をそれぞれ $00, $01,..,$0A にセット、その和を $0F にセットする。

3.11.2. グループ

前項の処理で、エンカウントがキャンセルされなかったときの続きの処理を述べる。

  1. 乱数 R(0 以上 $0F 以下)を取得しておく。

  2. 前項でセットした $00 から $0A までの i-部分和 S(i) = $00 + ... + $0i を計算していく。 i = 0, 1, .., A とインクリメントしていく。 ただしセットされている項がゼロである場合は、その項を部分和に勘定しない。

  3. こうして、S(i) > R となるような 決定用データ 0~A のインデックス i を見つける。

例えば、 $00 != 0, $01 != 0, $00 + $01 <= R かつ $00 + $01 + $02 > R であれば、 i = 2 がセットされるということである。 ゼロの項は、タイルエンカウントデータの対応する値がダミーであることを意味する。 詳しく述べると、タイルエンカウント ID = 0 において「がいこつへい」、 その他の ID においては、モンスター ID = 0 の「スライム」である。 この i によって、出現するグループの傾向が決定するのである:

以上の処理を終了した後に、エンカウント処理を終了することになる。 つまり、移動モードが続行となるか、戦闘モードに突入するかが決定される。

3.11.3. 特別エンカウントの場合

特別エンカウントが適用されることが決定した場合、以降の処理は一本道である。

  1. タイルエンカウントデータにある、謎のフラグをチェックする しかし、この値はデータ ID によらずゼロなので、説明は省略する。

  2. タイルエンカウントデータより、特別エンカウントデータ ID を取得する。 そのデータからモンスターグループの構成が特別エンカウントID により一意に決まる。 また、各グループの匹数を非特別エンカウントの場合に準じた形で決定する。

3.11.4. 出現グループ数が単独の場合

i >= 5 のときは、出現グループ数が 1 で確定する。 あとはモンスターと匹数を決定するだけである。 ただし、下記の数式によって得られた匹数は、 実際に登場するそれよりもかなり大きいことがある。 エンカウント設定よりだいぶ後の処理で、匹数を減らすのである。

  1. グループを構成する匹数は、M(j) + 乱数(0 以上 E(j) 未満)とする。 ここで、M, E はそれぞれアドレス $23EA63, $23EA73 に存在する配列であり、 j は i に等しい。

  2. グループを構成するモンスターのモンスターID を決定する。その値は タイルエンカウントデータ内のモンスターID i である。

最小匹数決定列 M - ROM アドレス $23EA63 (ロムイメージオフセット $11EA63) にある 1byte 値、サイズ 16 の配列である:

M[16] = {1, 2, 3, 1, 2, 3, 4, 8, 1, 1, 1, 1, 1, 1, 1, 1};

プラスアルファ匹数決定列 E - ROM アドレス $23EA73 (ロムイメージオフセット $11EA73) にある 1byte 値、サイズ 16 の配列である:

E[16] = {1, 1, 1, 2, 2, 2, 4, 1, 1, 2, 3, 4, 5, 6, 7, 8};

3.11.5. 出現グループ数が複数の場合

i < 5 のときは、出現グループ数は 2 以上である。 この i は、エンカウントデータのモンスターID i が、 第1グループのモンスターID として決定されることを意味する。

続いて、数 0, 1, 2 の中からランダムに数を選択する。すなわち (グループ数 - 2) である。 なお、ランダムの重みにエンカウントデータの「グループ数決定用データ」を用いる。 具体的なアルゴリズムは以下のようになっている:

  1. エンカウントデータのグループ数決定用データ 0..2を使い、 以下のような数列を $00, $01, ... にセットする。 ここで、0, 1, 2 はそれぞれグループ数決定用データ k (k = 0, 1, 2) にある値と同じだけ連続して並べるものとする。 例を挙げよう。エンカウント ID = 11 において、 データ 0、データ 1、データ 2 の値はそれぞれ 3, 2, 1 であるから、 セットする数列は {0, 0, 0, 1, 1, 2} である。

    {0,..,0,1,..,1,2,..,2};
    
  2. さらに、グループ数決定用データ 3 項の和、すなわちセットした配列のサイズを計算しておく。 エンカウント ID = 11 の例では、3 + 2 + 1 = 6 である。

  3. データ的にあり得ないが、この 3 項の和がゼロであれば、エンカウントはキャンセルされる。

  4. 乱数 j を取得する。この乱数は 0 以上かつ 3 項の和を超えない。

  5. グループ数 = $0j の値 + 2 となる。$0C に $0j の値を記憶させておく。

各グループのモンスター ID を、 出現グループ数が単数の場合と同様のアルゴリズムで決定する。 すなわち $06,..,$09 に記憶させておき、すぐに然るべきアドレスにセットする。

各グループの匹数を、 出現グループ数が単数の場合と同様のアルゴリズムで決定する。 ただし、相当する数式は M(i + 7) + 乱数(0 以上 E(i + 7) 未満)となる。 また、グループが単数の場合と同様に、 上記の数式によって得られた匹数が必要以上に大きいときは、 後の処理で、各グループの匹数を減らす。