4.4. はなす

4.4.1. モデル
4.4.1.1. 構造体 $FF08DA: 「はなす」対象簡易版
4.4.1.2. 構造体 $FF243C: 「はなす」対象標準版
4.4.1.3. データ
4.4.2. 処理手順

本節では移動コマンド「はなす」の実装詳細について述べる。 まずは「はなす」コマンドの対象であるオブジェクトのすべてを表現する ROM データの構造について説明する。 また、それらの構造それぞれについて、その型のオブジェクトデータを解釈して得られるテキスト CSV ファイルを提示する。 それから「はなす」コマンドを実行するときのプログラムの手順を、可能な限りコードを引用した上で説明する。

4.4.1. モデル

移動モードではプレイヤーの操作するパーティーとは他に、人々や動物、ときには魔物のが画面内をフラフラとしている。 基本的にはパーティーの先頭の正面にこれらのオブジェクトが存在すれば、コマンド「はなす」が成功することになっている。 これらの「はなす対象オブジェクト」のデータとして、いつものように配列の形式で定義されている。 以下、この「はなす対象オブジェクト」の構造を説明する。

4.4.1.1. 構造体 $FF08DA: 「はなす」対象簡易版

ROM のアドレス $FF08DA には次の表で示すような型のオブジェクトが配列されている:

表 4.18 構造体 $FF08DA

オフセット 属性
#$00 #$003F (調査中)
#$00 #$3FC0 スプライト ID
#$01 #$00C0 向き
#$02 #$01FF MX
#$03 #$03FE MY
#$04 #$001C LV
#$04 #$0020 描画
#$04 #$00C0 (未使用)
#$05 #$FFFF 歩行処理サブルーチン
#$07 #$00FF
#$08 #$FFFF メッセージ ID
#$09 #$00FF

スプライト ID

スプライト ID とは、「はなす」対象オブジェクトの図像的表現であるスプライトを管理するための ID の値をとる属性だ。 スプライト ID と内容との対応については別項で述べたい。

向き

向きとは、「はなす」対象オブジェクトのスプライトの「向き」を示す 0 から 4 の値をとる属性だ。 これは初期値であり、このオブジェクトが配置される空間にプレイヤーが入場した瞬間にしか保証されない。

次に示す表は向きの値と意味の対応だ:

表 4.19 向き

向き
0
1
2
3

MX

MX とは、「はなす」対象オブジェクトのスプライトを配置する空間の M 座標系における位置の X 座標成分のための属性だ。

座標系については別の節で説明したいが、本作の移動モードでは座標系は M と W の二つがある。 スプライトの関係するオブジェクトについては、前者で管理されている。

MY

MY とは、「はなす」対象オブジェクトのスプライトを配置する空間の M 座標系における位置の Y 座標成分のための属性だ。

LV

LV とは、「はなす」対象オブジェクトのスプライト配置に関する情報のための属性であり、 同一空間内の対象オブジェクト群を仮想的な標高で分類するために用いられる。

これはわかりづらいので例を出す。 ロンガデセオのホックは最初は家屋の屋上にいる。こういう状況を表現するための値が LV だ。

描画

描画とは、「はなす」対象オブジェクトを実際に描画するかどうかを示すブーリアン値の属性だろう。詳細不明。

歩行処理サブルーチン

歩行処理サブルーチンとは、「はなす」コマンドが実行されていない状態において、 オブジェクトがたまに移動したり、あるいは静止したままだったりする様子を与えるコードのアドレス値の属性だ。

メッセージ ID

メッセージ ID とは、このオブジェクトに対して「はなす」コマンドが実行されるときに、 画面メッセージウィンドウに出力されるメッセージの ID の値の属性だ。

移動モードのテキストについては 4.3 テキスト を参照して欲しい。

この型は面白くない。「はなす」コマンド実行によって引き起こされる結果が常に同じだからだ。 それどころか、実際のデータを観察してみると、メッセージの指定すらなく、 単に画面内にいることしか目的としないようなオブジェクトさえ存在する。 一般には、「はなす」コマンドの対象として意味がある振る舞いを提供するのは、次節で示す型だ。

4.4.1.2. 構造体 $FF243C: 「はなす」対象標準版

ROM のアドレス $FF243C には次の表で示すような型のオブジェクトが配列されている:

表 4.20 構造体 $FF243C

オフセット 属性
#$00 #$003F (調査中)
#$00 #$3FC0 スプライト ID
#$01 #$00C0 向き
#$02 #$01FF MX
#$03 #$03FE MY
#$04 #$001C LV
#$04 #$0020 描画
#$04 #$0040 ウィンドウ消去
#$04 #$0080 (未使用)
#$05 #$FFFF 歩行処理サブルーチン
#$07 #$00FF
#$08 #$FFFF はなす処理サブルーチン
#$0A #$00FF

属性のほとんどが前節と共通している。以下、こちらの構造体に固有の属性を述べる。

ウィンドウ消去

ウィンドウ消去とは、ブーリアン値の属性であり、 「はなす」コマンドの出力メッセージウィンドウを処理後に消去するかどうかを示すためのものだ。

はなす処理サブルーチン

はなす処理サブルーチンとは、対象オブジェクトの会話内容の出力を主として実行するための処理コードの開始アドレスを指定する属性だ。

単に台詞を表示するだけでなく、店屋処理に制御を委譲したり、フラグを参照や更新をしたり、あるいはゲーム上のイベントを引き起こしたりする等、 柔軟な振る舞いを実現するのにこの属性は重要だ。

4.4.1.3. データ

付録 B データ で前述の二構造体オブジェクトデータを解釈して作成した CSV ファイルを提供する。

4.4.2. 処理手順

サブルーチン $C0C9B9 が「はなす」処理の主要部だ。 処理手順の構造は直線的なもので、次のように進む:

パーティーが「はなす」コマンドを実行可能かどうかテストする

馬車外のメンバーで最低一人は生存状態であることを確認する。

テストに成功すれば次の工程へ進むが、 もし馬車外の全員が死亡状態であれば、メッセージ ID #$17D7 の文言 このままでは 話せない! を出力する。 ユーザーがコントローラーのボタンを押すまでウィンドウを表示し続けるが、 ボタンを押すとウィンドウを消去して、それからこの処理全体を終了する。

各種変数を設定・保存する

馬車外の生存状態のパーティーメンバー、 「はなす」処理最中であることを示すフラグ、 「はなす」対象者の(話し始める直前の)向きの各値を設定・保存しておく。

パーティー先頭のほぼ正面に「はなす」対象者がいるかどうかテストする

パーティー先頭の向き(上右下左)によって座標比較アルゴリズムを分岐する。 対象者がいなければ、後述の「はなす」実施マークをテストする工程にジャンプする。

右向きのときの処理を説明する。 先頭の座標 (MX, MY) に対して座標が (MX + 1, MY), (MX + 1, MY - 1), (MX + 1, MY + 1) の位置にいる「はなす」オブジェクトを現在空間内から検索する。 このとき前述の LV 値も一致している必要がある。

これら四方向それぞれの処理は対称的なのかと思いきや、そうではない。 実は左向きや下向きの処理は、上向きや右向きの処理より若干複雑なものになっている。 余談だが、初代ドラクエにはサブコマンドに「きた」「ひがし」「みなみ」「にし」があった。 本コードを観察すると、ユーザーが向きを指示するだけで相当の処理コードを手抜きできることを実感できる。

「はなす」対象者の向きを変更するかテストする

対象者がパーティー先頭に対して向かい合わせる必要があるかどうかを、はなすオブジェクト属性の値で決める。 必要があれば、実際に対象者のスプライトを適当な向きのものに更新する。

プログラムではキャラクターの向きは 0 から 7 までの数で表現している(スプライトの構造に由来する)。 0, 1, 2, 3, 4, 5, 6, 7 はそれぞれ上上右右下下左左を意味する。 ここではこれらの値から 4, 4, 6, 6, 0, 0, 2, 2 に変換するだけでよいらしく、 先頭の向き値に 4 を加えて 6 で論理積を取るだけで済ませている。

移動モードメッセージを出力するかテストする

「はなす」対象者がメッセージ ID を持っているかどうかを確認する。 もし持っていれば、そのメッセージをメッセージウィンドウに出力する。

メッセージ ID を持っているということは、この「はなす」オブジェクトが 先述の簡易版構造体 $FF08DA 配列から得られたものであることを意味し、 作業用変数の値が #$168F でないことと同値だ。

「はなす」対象者に関連付けられている処理を実行する

対象の「はなす」オブジェクトが構造体 $FF243C 配列から得られたものであれば、 固有のアドレスが得られるが、そうでない場合には既定の空処理コードアドレスが得られる。 その完全アドレスをアドレス $0006B0 にロードしてジャンプする。 この処理が「はなす」オブジェクトそれぞれに固有の振る舞いを表現している。

「はなす」実施済みマークを更新する

変数 $7E5E8C をインクリメントする。 後ほど本処理および便利コマンド処理がこの値を参照する。

「はなす」オブジェクトのメッセージウィンドウ消去フラグ属性をテストする

先述の属性の値が 1 であれば、ユーザーのコントローラー入力を待たずにウィンドウを消去する。 そうでなければ、コントローラー入力があるまでウィンドウを消去しない。

「はなす」対象者の向きを復元するかテストする

もし会話が終わった後に「はなす」対象者の向きを元に戻す必要があれば、そのようにする。 このために先ほど退避させておいた変数を参照する。

テストの結果にかかわらず、終了する工程までジャンプする。

「はなす」実施済みマークをテストする

変数 $7E5E8C の値を見る。ゼロでなければ終了する。 ゼロならば、メッセージ ID #$1777 の文言 [D4]その方向には 誰もいない。を出力し、 ユーザーのボタン押しを待ってウィンドウを消去する

余談だが、便利コマンドから本処理を実行する場合には、 あらかじめ $7E5E8C の値を水増ししておくことでこのメッセージ出力を抑止させるようになっている。 そして復帰後に値が増えていなければ「しらべる」本処理へ進む。

終了する

「はなす」処理最中であることを示すフラグをオフにして、本処理を終了する。

オブジェクトの細かい属性値や、オブジェクトの位置や向きが影響するとはいえ、 「はなす」コマンドの本処理は、基本的に一本道の処理だと言える。