3.9. 戦闘コマンド

3.9.1. 戦闘コマンドを分類する
3.9.2. 防御系のコマンド
3.9.3. 一般のコマンド
3.9.3.1. 名前
3.9.3.2. 数値の変化量を評価するコード
3.9.3.3. 実行時に表示するメッセージ
3.9.3.4. 必要 MP
3.9.3.5. 有効範囲
3.9.3.6. 目標が敵側に作用するものかどうかのフラグ
3.9.3.7. 実行コード
3.9.4. 装備を変更するコマンド
3.9.5. 道具を使用するコマンド
3.9.5.1. アイテム
3.9.5.2. 実行コード
3.9.6. データ

この節では戦闘コマンドについて述べる。 戦闘コマンドとは、戦闘中の一ターン内において、敵や味方それぞれに対する命令をカプセル化した概念だと定義する。 プログラムコードの観点では、戦闘中に配列 $1073 などに格納される 1 バイトの値を ID とする何らかの配列要素を戦闘コマンドと表現していると解釈する。

本節では最初に実際のプログラムコードに沿う形で戦闘コマンドの分類を行う。 戦闘コマンドと関連性のあるデータについても併せて見ていく。 それから、戦闘コマンド分類のそれぞれについて、付随するモデルの物理的構造やコードの挙動を検討していく。 最後に、コードを分析して得た戦闘コマンドデータを CSV 形式のテキストファイルで提供する。

3.9.1. 戦闘コマンドを分類する

戦闘コマンドを理解するには、配列 $1037 と配列 $1073 について理解する必要がある。 まずはこれらの配列について説明する。

配列 $1037 は次の構造の 1 バイト型データを要素とするものだ:

表 3.24 構造体 $1037: 戦闘コマンド情報

意味
#$03 戦闘コマンド種別
#$7C 戦闘コマンドの相手のインデックス
#$80 戦闘コマンドの相手が敵側かどうか

本節では、戦闘コマンド情報構造体の下位 2 ビットの値で戦闘コマンドを分類する。 戦闘処理のコードを解析すると、次のように分類するのが妥当なように思える:

表 3.25 戦闘コマンド種別

意味
0 防御系
1 一般
2 装備変更
3 道具使用

さらに、この戦闘コマンド情報配列と一対一対応する配列がアドレス $1073 にあり、 こちらには戦闘コマンドを示す 1 バイトの値を格納する。 戦闘コマンド情報配列と戦闘コマンド配列は両方とも、プレイヤー側馬車外のキャラクター群と 敵側パーティーのキャラクター群の関連情報を保持するのに十分な長さがある。

例えば、自陣側の馬車外メンバーが主人公、スラリンの 2 名で、敵陣がメタルスライム 3 匹 だとしよう。 このときのキャラクター、コマンド情報のアドレス、そしてコマンドのアドレスの対応関係は次のようになる:

主人公 $1037 $1073
スラリン $1038 $1074
メタルスライムA $1039 $1075
メタルスライムB $103A $1076
メタルスライムC $103B $1077

実は本節での配列の説明は、戦闘コマンド自身を理解し易くするためにかなり簡略化してある。 配列の有効性やコマンド連続実行時の挙動等、言及しなかった事実があることを断っておく。

3.9.2. 防御系のコマンド

種別が 0 の戦闘コマンドは、一般コマンドの意味で防御系のコマンドをとることが必要のようだ:

20/8862:    20809F      JSR $9F80           ; $1073,X に戦闘コマンドをセット
20/8865:    C900        CMP #$00
20/8867:    F039        BEQ $88A2
20/8869:    C971        CMP #$71            ; みをまもる1
20/886B:    F02F        BEQ $889C
20/886D:    C972        CMP #$72            ; みをまもる2
20/886F:    F02B        BEQ $889C
20/8871:    C9AC        CMP #$AC            ; 防御中に同種の仲間が登場
20/8873:    F027        BEQ $889C

20/889C:    A900        LDA #$00            ; 戦闘コマンド情報構造体
20/889E:    206B9F      JSR $9F6B           ; $1037,X に戦闘コマンド情報をセット
20/88A1:    60          RTS

3.9.3. 一般のコマンド

種別が 1 の戦闘コマンドには次に挙げる性質、属性がある:

  • 名前

  • 数値の変化量を評価するコード

  • 実行時に表示するメッセージ

  • 必要 MP

  • 有効範囲

  • 目標が敵側に作用するものかどうかのフラグ

  • 実行コード

3.9.3.1. 名前

一般の戦闘コマンドの大半は、ウィンドウのテキスト表示処理に利用できる名前文字列と対応付けられている。 実体はアドレス $228000 にある文字列だが、 3.3.3.1 機能表 のキー #$2B の参照機能を引き起こす BRK 命令を実行することで、戦闘コマンドの名前にアクセスする。

3.9.3.2. 数値の変化量を評価するコード

何らかのパラメーターを増加または減少するコマンドは、その変化量を評価するためのサブルーチンを必要とする。 そのサブルーチンのアドレスはジャンプテーブル $20B7F9 で定義されていて、 対応するサブルーチンアドレスがあるテーブル列の ID は、戦闘コマンドのそれと一致している。

変化評価を必要としないような戦闘コマンドには、空サブルーチンのアドレスが割り当てられている。

3.9.3.3. 実行時に表示するメッセージ

戦闘コマンドの実行直後には、画面中央下のメッセージウィンドウに臨場感豊かな文言が出力される。 各戦闘コマンドはそのような戦闘メッセージの ID を一つ有する。 このメッセージ ID は配列 $268565 の要素として定義されていて、 配列のインデックスとコマンドの ID が対応している。

3.9.3.4. 必要 MP

戦闘コマンドを実行するために、実行者の MP を消費する必要があるものが多い。 この情報が配列 $268765 で定義されている。 これは 1 バイトの値を要素とする配列なのだが、MP 情報は #$1F 部分のビットで定義されている。 そして、配列のインデックスはコマンドの ID と対応している。

さらに、特殊な MP 消費をするコマンドのために、一部はプログラムで消費量を上書きする:

26/83A1:    BF658726    LDA $268765,X
26/83A5:    291F        AND #$1F            ; 必要 MP
26/83A7:    C91F        CMP #$1F
26/83A9:    F01D        BEQ $83C8           if(MP != 0x1F){
26/83AB:    C91E        CMP #$1E
26/83AD:    D004        BNE $83B3               if(MP == 0x1E){
26/83AF:    A924        LDA #$24                    MP = 36d
26/83B1:    8006        BRA $83B9               }
26/83B3:    C91D        CMP #$1D
26/83B5:    D002        BNE $83B9               else if(AL == 0x1D){
26/83B7:    A9FF        LDA #$FF                    MP = 255d
                                                }
26/83B9:    2C1610      BIT $1016
26/83BC:    C210        REP #$10
26/83BE:    5004        BVC $83C4               ; このあたりの処理は
26/83C0:    0A          ASL A                   ; パルプンテのはやぶさ効果を
26/83C1:    9001        BCC $83C4               ; 考慮するものゆえ
26/83C3:    6A          ROR A                   ; 今は議論しない
26/83C4:    FA          PLX
                                            }
26/83C8:    A900        LDA #$00            ; 消費なし

このコードの解析によると、マジックナンバーがかなり多いことがわかる。 全ビットがオン、つまり MP が 31 ならばそれは呪文コマンドではないという取り扱いになるようだ。 ベホマズンに対応する消費 MP #$1E は 36 ポイントに変更する。 さらにメガザルに対応する消費 MP #$1D は 255 ポイントに変更する。 ここには表れていないが、値 #$FF もまた「現在の MP の残り全て」を表現するマジックナンバーだろう。

3.9.3.5. 有効範囲

戦闘コマンドの有効範囲とは、次の表に示す区分のことだ。

表 3.26 戦闘コマンド有効範囲

意味
0 その他
1 単体
2 グループ
3 全体

この情報も配列 $268765 で定義されている。 各バイトの #$60 部分のビットを占める。

3.9.3.6. 目標が敵側に作用するものかどうかのフラグ

例えば「メラゾーマ」は敵の誰かに作用するコマンドであるが、「ザオラル」はそうではない。 この情報も配列 $268765 で定義されている。 各バイトの #$80 部分のビットを占める。

3.9.3.7. 実行コード

戦闘コマンドを実行するサブルーチンのアドレスは配列 $268865 で定義されている。 配列のインデックスはコマンドの ID と対応している。

ちなみに、この配列は論理的にはジャンプテーブルであるはずなのだが、サブルーチンの呼び出し方が変則的だ。 所定の変数にアドレス値をロードし、直接 JSR する。

3.9.4. 装備を変更するコマンド

種別が 2 の戦闘コマンドとは、プレイヤーの通常の入力操作において次の条件を満たす、味方側キャラクター限定のものをいう:

  • 指定キャラクターのコマンド選択ウィンドウで「どうぐ」を選択した

  • どうぐウィンドウで選択した物のアイテム種別が武器である

  • 指定キャラクターがその武器を装備することが可能である

  • 「つかう・そうび」ウィンドウで「そうび」を選択した

言い換えると、キャラクターが武器の装備を変更して、さらに直接攻撃をするという流れを生じるコマンドを意味する。 この定義から、武器でないアイテムが関わるどのようなコマンドも、ここで議論するものには該当しないことを意味する。 例えば「ほしふるうでわ」を選択すると、そのターンで実際にそれを装備するが、これは種別 2 のコマンドではない。 後述する種別 3 のコマンドに分類される。

実際には、戦闘コマンド情報を評価するタイミングで次のような操作を施す:

  1. 現在装備している武器があれば、それを外す。 これに伴って、対象キャラクターの攻撃力と守備力を再評価する。

  2. 選択したアイテムを装備する。 やはり対象キャラクターの攻撃力と守備力を再評価する。

  3. 戦闘コマンドとコマンド種別を「こうげき」コマンドと一般コマンドにそれぞれ置き換える。 この際、装備を変更したことを示すメッセージを表示する(下記コード片参照)。

20/8583:    A973        LDA #$73            ; 「こうげき」
20/8585:    8DF710      STA $10F7           ; 戦闘コマンド ID
20/8588:    20809F      JSR $9F80           ; コマンドキャラクターの戦闘コマンド ID を設定
20/858B:    20419F      JSR $9F41           ; コマンドキャラクターの戦闘コマンド情報を参照
20/858E:    29FC        AND #$FC
20/8590:    0901        ORA #$01            ; 種別 1: 一般コマンド
20/8592:    206B9F      JSR $9F6B           ; コマンドキャラクターの戦闘コマンド情報を設定
20/8595:    20DF9E      JSR $9EDF           ; コマンドキャラクターを参照
20/8598:    85F5        STA $F5
20/859A:    85F7        STA $F7
20/859C:    00A1        BRK #$A1            ; message #$0028: [F7]は ぶきを [F5]にもちかえた!
20/859E:    28
20/859F:    20D69D      JSR $9DD6           ; 待ち
20/85A2:    ADF710      LDA $10F7           ; 戦闘コマンド ID
20/85A5:    82A6FE      BRL $844E           ; (戦闘コマンド ID による分岐)

なお、戦闘コマンド ID を収める変数には、 そこに「こうげき」を示す値 #$73 が入るまでは新しく装備する武器のアイテム ID が収められていた。

3.9.5. 道具を使用するコマンド

種別 3 の戦闘コマンドとは、味方側キャラクターに限定された、道具に関する戦闘コマンドを意味する。 先に述べたように、実行時のメッセージに「そうびした!」とあっても、実質的にはこちらの種別になるコマンドが普通にある。

種別が 3 の戦闘コマンドには次に挙げる性質、属性がある:

  • アイテム

  • 実行コード

3.9.5.1. アイテム

戦闘コマンド ID はアイテム ID でもあるので、処理コードはアイテムの属性をすべて参照することが可能だ。 例えば、コマンド処理中にアイテムが消耗品であるかどうかを知る必要がある。 アイテムについては 3.13 アイテム で議論する。

3.9.5.2. 実行コード

実行コードはサブルーチンで実装されている。ジャンプテーブルはアドレス $20C162 にあるのだが、 このテーブルの列 ID は戦闘コマンド ID すなわちアイテム ID とは一致していない。 アイテム ID から列 ID への対応表がアドレス $27819A にあり、これを用いて変換する。 たいていのアイテムは「しかし なにも おこらなかった」というメッセージ表示しか引き起こさないので、 それ以外の戦闘コマンドに対してしか意味のある実行コードを用意しなくて済むようにこのような構造になっている。

使用コマンドが何らかの固有処理を有する場合には、その処理コードを特定した直後に、 そのアイテムを消費するかどうかを判定し、消耗品であれば実際にキャラクターの持ち物袋からそれを一つだけ削除する。 その後に固有処理をするサブルーチンを呼び出す。

3.9.6. データ

戦闘コマンドデータを CSV で表現したファイルを 付録 B データ から参照できる。 本節で述べた複数の配列とテーブルを水平に結合したり、コメント欄を付加してあったりするので利用者は注意して欲しい。