5.19. 格闘場マッチメイク解析

5.19.1. 解析
5.19.1.1. 格闘場マッチメイクサブルーチン
5.19.1.2. 主人公のレベルを取得するサブルーチン
5.19.1.3. オッズ設定サブルーチン
5.19.1.4. マッチメイク構造体

本節では、格闘場のマッチメイク処理の解析を行う。 リメイク版では、オリジナル版のように多様なマッチメイクが実現することはない。 格闘場に出てくるモンスターたちの組み合わせには、すでに何個かのパターンが決まっており、 そこから無作為に選択されるというのが、一般的なプレイヤーの認識だろう。 以下では、出場選手モンスターとオッズがどのように決まるのかを見ていこう。

5.19.1. 解析

格闘場のあるフロアに場面が切り替わる直前に、マッチメイク処理を行っているようだ。 すなわちフロア進入時と観戦終了後に、ここで紹介するサブルーチンの呼び出しが発生する。

5.19.1.1. 格闘場マッチメイクサブルーチン

マッチメイクを担当するサブルーチンは $C3EC84 で定義されている。 逆アセンブルコードから読み下したアウトラインを説明する。

  • 主人公のレベルを取得するサブルーチンを呼び出し、 取得した主人公のレベル A$337A にセットする。

  • 【乱数取得のための幅を設定】

    range を以下のように決める。

    • A < #$000Brange = $C3ED78

    • A < #$0010range = $C3ED7A

    • A < #$0016range = $C3ED7C

    • A < #$001Erange = $C3ED7E

    • A がそれ以外の値ならば range = $C3ED80

  • 乱数生成サブルーチン $C0133E の呼び出しにより、 A レジスタに 0 から range までのランダムに決まった値をセットする。 この値がマッチメイク ID となる。

  • $3370 = マッチメイク ID

  • $78 = マッチメイク ID のデータが格納されているアドレス となるように、 構造体データアドレス取得サブルーチン $C9050D を呼び出す。

  • 【各選手のオッズを初期化】

    オッズ設定サブルーチンX レジスタの値を変えつつ 4 回呼び出すことで、 以下のアドレスに値をセットする。 見栄えの都合上、アドレスの順序でセット内容を記すが、実際の処理順序は選手の登場順序と一致する。

    • $337C: マッチメイク構造体データにある選手[0] のオッズ整数部

    • $337E: マッチメイク構造体データにある選手[1] のオッズ整数部

    • $3380: マッチメイク構造体データにある選手[2] のオッズ整数部

    • $3382: マッチメイク構造体データにある選手[3] のオッズ整数部

    • $3384: マッチメイク構造体データにある選手[0] のオッズ小数点以下

    • $3386: マッチメイク構造体データにある選手[1] のオッズ小数点以下

    • $3388: マッチメイク構造体データにある選手[2] のオッズ小数点以下

    • $338A: マッチメイク構造体データにある選手[3] のオッズ小数点以下

  • 【各選手のモンスター ID を初期化】

    単純作業で以下の各アドレスに値をセットする。 ここでも見栄えの都合上、アドレスの順序でセット内容を記す。

    • $2000: マッチメイク構造体データにある選手[0] のモンスター ID

    • $2002: マッチメイク構造体データにある選手[1] のモンスター ID

    • $2004: マッチメイク構造体データにある選手[2] のモンスター ID

    • $2006: マッチメイク構造体データにある選手[3] のモンスター ID

    • $2008: 選手[0] のモンスター ID が 0 でなければ 1 とし、 0 ならば 0 とする。

    • $200A: 選手[1] のモンスター ID が 0 でなければ 1 とし、 0 ならば 0 とする。

    • $200C: 選手[2] のモンスター ID が 0 でなければ 1 とし、 0 ならば 0 とする。

    • $200E: 選手[3] のモンスター ID が 0 でなければ 1 とし、 0 ならば 0 とする。

    • $3372: 参戦選手数。すなわち $2008 + $200A + $200C + $200E と同じ値

  • 【予想屋の予想を初期化】

    • A = $3372 - 1

    • A が正の値であれば、0 から A までの乱数を取得するべく、 乱数取得サブルーチン $C0133E を呼び出す。

    • $3378 = 乱数 * 2

      例えば、選手が 4 匹いるとき、 $3378 のとり得る値は 0, 2, 4, 6 のいずれかである。

まず最初に主人公キャラクターのレベルを参照している。 レベルにより、五段階で選択肢の個数が変化するというわけだ。 配列 $C3ED78 の内容は次のようになっている。

C3/ED78:    0A00    1
C3/ED7A:    1300    2
C3/ED7C:    1800    3
C3/ED7E:    2100    4
C3/ED80:    2600    5

1

主人公のレベルが 11 未満の場合、10 通りの組み合わせだけが観戦できる。

2

主人公のレベルが 16 未満の場合、19 通りの組み合わせだけが観戦できる。

3

主人公のレベルが 22 未満の場合、24 通りの組み合わせだけが観戦できる。

4

主人公のレベルが 30 未満の場合、33 通りの組み合わせだけが観戦できる。

5

主人公のレベルがそれより大きければ、38 通りの組み合わせが観戦できる。 この個数は、後述するマッチメイク配列 $C30DC5 の要素数と一致する。

その後は、乱数処理でマッチメイクデータを制限範囲内から一つ取り、 胴元と予想屋の処理と台詞に必要なパラメータを然るべきアドレスにセットするという処理となる。 格闘場の胴元共通処理サブルーチン予想屋の共通処理サブルーチンの実装は、 当サブルーチンの処理結果に依存するということだ。

5.19.1.2. 主人公のレベルを取得するサブルーチン

サブルーチン $ED82 は主人公のレベルを A レジスタにロードする。

  • キャラクター人数取得サブルーチン $C4297C 呼び出しにより、 X = パーティ内の人数 - 1 とする。

  • 【主人公チェック】

    キャラクター X が主人公であるかを調べるべく、 主人公判定サブルーチン $C42DA1 を呼び出す (キャラクターデータのあるビット列が 1 と等しいか否かをテストするサブルーチンである)。

    • キャラクター X が主人公であれば 【パーティの中に主人公を見つけた】 に制御を移す。

    • キャラクター X が主人公でなければ、 前のキャラクターに関して 【主人公チェック】を行う。

    • パーティ内に調べたいキャラクターがいなくなったら、 【酒場チェック】に制御を移す。

  • 【パーティの中に主人公を見つけた】

    • キャラクターレベル取得サブルーチン $C42FEB を呼び出す。 これで A レジスタの値はパーティキャラ X のレベルとなっている。

    • 呼び出し元に制御を戻す。

  • キャラクター人数取得サブルーチン $C4297C 呼び出しにより、 X = パーティ内の人数 - 1 とする。

  • 【酒場内のキャラクターをチェック】

    • キャラクター人数取得サブルーチン $C4297C 呼び出しにより、 X = 酒場内の人数 - 1 とする。

    • 【酒場にいるキャラの主人公チェック】

      パーティ内のチェックと同様に、キャラクター X を調べるべく、 主人公判定サブルーチン $C42DA1 を呼び出す。

      • キャラクター X が主人公であれば 【酒場に主人公を見つけた】 に制御を移す。

      • キャラクター X が主人公でなければ、 前のキャラクターに関して 【酒場にいるキャラの主人公チェック】を行う。

      • パーティ内に調べたいキャラクターがいなくなったら、 そのまま (X == #$FFFF) 【酒場に主人公を見つけた】へ進む。

  • 【酒場に主人公を見つけた】

    • キャラクターレベル取得サブルーチン $C42FEB を呼び出す。 これで A レジスタの値は酒場にいるキャラ X のレベルとなっている。

    • 呼び出し元に制御を戻す。

5.19.1.3. オッズ設定サブルーチン

サブルーチン $EDBB は、格闘場に出場する選手一匹のオッズを決定する。

  • 【事前条件】

    • A == マッチメイク構造体にあるオッズデータ

    • X == 選手の順番 * 2 (== 0, 2, 4, 6)

  • 【初期化】

    $337C,X = A, $3384,X = 0

  • 【乱数】

    マッチメイク構造体データの与える初期値 A により、 さらに A を変更する。

    • A#$0006 未満 ⇒ A = #$0006

    • A#$000B 未満 ⇒ A = #$000E

    • A#$001F 未満 ⇒ A = #$0028

    • A#$0065 未満 ⇒ A = #$0064

    • A#$0065 以上 ⇒ A = #$00C8

  • 乱数取得サブルーチン $C0133E で乱数を取得する。 この乱数は 0 以上 A 以下の値である。

  • A = 乱数 - (A >> 1) とする。

    • A >= 0 ⇒ 【プラス】へ制御を移す。

    • それ以外 ⇒ 次に進む。

  • 【マイナス】

    • A = -A + 1

    • $70 = A / 10; A %= 10 とする(汎用除算サブルーチン $C0121C 利用)

    • A = 10 - A をテストする。

      • A == 0 ⇒ 【減算】へスキップ。

    • $3384,X = A

    • $337C,X = #$FFFF if $337C,X == 0

    • 【減算】

      A = $337C,X - $70 に対して、

      • A > 0$337C,X = A

      • A <= 0$3384,X = 0 $337C,X = 1

    • 【終了】へ進む。

  • 【プラス】

    • $70 = A / 10; A %= 10 とする(汎用除算サブルーチン $C0121C 利用)

    • $3384,X = A

    • $337C,X += $70

    • 【終了】へ進む。

  • 【終了】

    制御を呼び出し元に戻す。

  • 【事後条件】

    • $337C,X >= 1

    • 0 <= $3384,X && $3384,X < 10

オッズが各選手の持つある定数を元に生成する乱数から決まることが読み取れる。 モンスターたちの持つオッズ用定数にそれを乗じて、実オッズが 1.0 を下回らないようにスケーリングする数値計算が、本サブルーチンの主要な処理だ。

オッズは小数点を持つ値なので、整数部分と小数点以下の部分両方を扱っている。 $337C,X が整数部で、$3384,X が小数部だ。 さらに言えば、小数部は一桁しかない。

5.19.1.4. マッチメイク構造体

配列 $C30DC5 が全マッチメイク 38 パターンを定義する。 マッチメイク一つ当たり、8 バイトサイズの構造体として表現する。 その構造体のメモリレイアウトは以下のように解釈できる。

表 5.28 マッチメイク構造体

Byte:Bit 80 40 20 10 08 04 02 01
00 モンスター ID[0]
01 オッズ[0]
02 モンスター ID[1]
03 オッズ[1]
04 モンスター ID[2]
05 オッズ[2]
06 モンスター ID[3]
07 オッズ[3]

モンスター ID

リングに出場する選手のモンスター ID を示す。

オッズ

オッズを算定するために用いる定数。前項参照。