5.16. 仲間登録所解析

5.16.1. 解析
5.16.1.1. 登録所共通処理サブルーチン
5.16.1.2. キャラクター削除サブルーチン
5.16.1.3. 入力が仲間の名前と同じかチェック
5.16.1.4. パラメータ増加処理サブルーチン
5.16.1.5. 性格決定サブルーチン
5.16.1.6. 登録屋が性格を告げるサブルーチン
5.16.2. データ
5.16.2.1. $C30EFD 構造体 - 登録所・性格条件群
5.16.2.2. $C30FFC 構造体 - 登録所・性格群

このセクションではルイーダの酒場二階に開設されている登録所の処理を解析する。 新規キャラクターの追加処理において、リメイク版は、オリジナル版とは決定的に違う処理を含んでいる。 それはタネ・木の実による能力パラメーターの調整処理であり、それに依存する初期性格の決定という処理が伴う。 この過程を可能な限り詳細に調査していこう。

5.16.1. 解析

まだアリアハン王に旅立ちの報告を済ませていない等の、特殊なイベント中でない限り、 登録屋に「はなす」とすぐに登録所共通処理サブルーチンが開始する。 ここから処理をたどっていき、どのように仲間キャラクターが追加・削除されるのかを調べていく。

登録所共通処理サブルーチンおよび、 それが呼び出すすべてのサブルーチンは、 登録屋による台詞表示と、 システムメッセージ表示には、 メッセージ表示サブルーチンとして $C1A92E$C1A8D4 をそれぞれ用いるようだ。 この事実を利用して、逆アセンブルコードと台詞メッセージ表とをにらめっこしながら処理を読み解いていくことになる。

5.16.1.1. 登録所共通処理サブルーチン

サブルーチン $C3DAEB は、登録屋に「はなす」と通常始まる処理だ。 キャラクター新規追加処理をメインとするプログラムの体裁をとっている。 一枚岩の長いアセンブリコードを文章化すると、大体以下のような感じになった。

  • 台詞「ここは冒険者たちの登録所」(ID: #$0B31) を表示する。

  • フラグチェックサブルーチン $C909AE を呼び出し、 $7E353A の最下位ビットから見て #$0014 ビット目をテストする。

    • フラグが未セット⇒

      • 台詞「あなたが仲間にしたい人をさがしだし~」(ID: #$0B32) を表示する。

      • フラグセットサブルーチン $C908F0 を呼び出し、 $7E353A の最下位ビットから見て #$0014 ビット目をセットする。

  • 台詞「新しい人を名簿に登録しますか」(ID: #$0B33) を表示する。

  • 「はい・いいえ」ウィンドウを表示して、プレイヤーの入力を待つ。

    • キャンセルボタン or 「いいえ」⇒【またおいで】へジャンプ。

  • 【新しく登録する】

    • キャラクター削除サブルーチン $C3DD13 を呼び出す。

      • キャラクターがいっぱいだが、削除しなかった ⇒【またおいで】へジャンプ。

    • 台詞「どんな人をご希望ですか?」(ID: #$0B34) を表示する。

    • サブルーチン $C3C345 を呼び出すことで、名前文字列入力用バッファを初期化する。

  • 【名前入力ループ】

    • 「なまえをいれてください」ウィンドウを表示し、プレイヤーの入力を待つ。

      • キャンセルボタン ⇒【まだ登録する?】へジャンプ。

    • サブルーチン $C3C37F を呼び出し、 プレイヤーが入力した文字列を配列 $3332,X にコピーする。

    • ロトテストサブルーチン $C3C66B を呼び出し、 入力した名前が「ロト」「ろと」「ロと」……等(アドレス $C3C6A4 で定義)とマッチしないかテストする。

      • マッチしない ⇒【入力と予約名と照合】へジャンプ。

      • マッチする ⇒

        • 台詞「ロト!? ロトでございますか!?」(ID: #$09C8) を表示する。

        • 【名前入力ループ】へジャンプ。入力ウィンドウは変更されていない。

  • 【入力と予約名と照合】

    • サブルーチン $C3EB3F を呼び出して、 入力が予約名かどうかチェックする。

      • 入力が予約名でない ⇒【入力と同名のキャラクター検索】へジャンプ。

      • 入力が予約名である ⇒

        • 台詞「申し訳ありませんがその名前の人を~」(ID: #$0B45) を表示する。

        • 【別の人を探す?】へジャンプ。

  • 【入力と同名のキャラクター検索】

    • サブルーチン $C3DDBF を呼び出して、入力と同じ名前の仲間キャラクターがいるかテストする。

      • いない ⇒【同名チェックをクリア】へジャンプ。

      • いる ⇒

        • 台詞「その人ならすでに登録されていますが」(ID: #$0B44) を表示する。

        • 【別の人を探す?】へジャンプ。

  • 【別の人を探す?】

    • 「はい・いいえ」ウィンドウを表示して、プレイヤーの入力を待つ。

      • キャンセルボタン or 「いいえ」⇒【またおいで】へジャンプ。

      • 「はい」⇒【新しく登録する】へジャンプ。

  • 【同名チェックをクリア】

    • 「おとこ・おんな」ウィンドウを表示して、プレイヤーの入力を待つ。

      • キャンセルボタン ⇒【名前入力ループ】へジャンプ。入力ウィンドウは変更されていない。

    • サブルーチン $C3C3D5 を呼び出して、プレイヤーの入力を 「おとこ」だったら 0 へ、「おんな」だったら 1 へ変換する。

    • $405F = A; 性別

    • 職業リストウィンドウを表示して、プレイヤーの入力を待つ。

      • キャンセルボタン ⇒【同名チェックをクリア】へジャンプ。

  • $4063 = A; 職業 ID

  • $4061 = 0; 詳細不明

  • $4054 = 2; 詳細不明

  • サブルーチン $C441AE を呼び出し、 新規作成キャラクターのデータ格納領域を $3925 系統のアドレスに割り当てる (同時に決定分のパラメータをセットする)。

  • $2BB4 = A; キャラクターのデータアドレス

  • サブルーチン $C42F5E を呼び出し、 キャラクター (A) の ID を取得 (A) する。

  • 新規作成キャラクター (A) の名前・職業・性別・レベルを表示するウィンドウと、 ちから~さいだいMPまでのパラメータリストを表示するウィンドウを表示する。

  • 台詞「ご希望の条件だとこの人が見つかりましたが~」(ID: #$0B35) を表示する。

  • 「はい・いいえ」ウィンドウを表示して、プレイヤーの入力を待つ。

    • キャンセルボタン or 「いいえ」⇒【その人ではダメ】へジャンプ。

  • フラグチェックサブルーチン $C909AE を呼び出し、 $7E353A の最下位ビットから見て #$0015 ビット目をテストする。

    • フラグが未セット⇒

      • 台詞「お仲間には王さまから特別に激励の品が~」(ID: #$0B36) を表示する。

      • フラグセットサブルーチン $C908F0 を呼び出し、 $7E353A の最下位ビットから見て #$0015 ビット目をセットする。

  • 台詞「では ○○○○さんへのたねの使い方はどうしますか?」(ID: #$0B37) を表示する。

  • A = #$003F

  • 乱数取得サブルーチン $C0133E を呼び出し、乱数を取得 (A) する。 A レジスタには 0 以上 63 以下のいずれかの値がロードされる。 1/64 の確率で新規作成キャラに 6 回タネ・木の実が使えることを意味する。

    • A != 0A = 5

    • A == 0A = 6

  • 【タネ個数決定直後】へジャンプ。

  • 【その人ではダメ】

    • 表示ウィンドウ周りの処理を行う(詳細不明)。

    • 【まだ登録する?】へジャンプ。

  • 【タネ個数決定直後】

    • $2BB2 = A; 使えるタネ・木の実の個数

    • 「じぶんで やる・おまかせにする」ウィンドウを表示して、プレイヤーの入力を待つ。

      • キャンセルボタン ⇒【まだ登録する?】へジャンプ。

      • 「じぶんで やる」⇒【じぶんで】へジャンプ。

    • $2A60 = 1; 「登録屋がタネを使う」フラグ

    • 【タネ蒔き】へジャンプ。

  • 【じぶんで】

    • 台詞「使える回数は ○回です。ではどうぞ」(ID: #$0B38) を表示する。

  • 【タネ蒔き】

    • 以下の反復処理を行う。反復回数はタネ・木の実の個数、つまり $2BB2 だ。

      • A = 4

      • 乱数取得サブルーチン $C0133E を用いて、0 以上 4 以下の乱数を得る。

      • $2A62 = A; 乱数

      • プレイヤーまたは登録屋がパラメータ種別を入力するのを待つ。

      • サブルーチン $DE20 を呼び出すことで、 選択パラメータの増分を決定する。

    • メッセージ「[CE][D6][AF][AC]」(ID: #$0150) を表示する。

      • $2A60 != 0

        • 台詞「さて……。おわりました」(ID: #$0B3E) を表示する。

        • $2A60 = 0

    • A = $2BB4; キャラクター ID

    • サブルーチン $C3DE95 を呼び出し、 新規作成キャラクターの初期性格を決定する。

    • サブルーチン $E2D0 を呼び出し、 登録屋に性格を言わせる。

    • 台詞「では○○○○さんを登録します。よろしいですか?」(ID: #$0B39) を表示する。

    • 「はい・いいえ」ウィンドウを表示して、プレイヤーの入力を待つ。

      • キャンセルボタン or 「いいえ」⇒【登録しない】へジャンプ。

    • サブルーチン $C44566 を呼び出し、新規作成キャラクターを正式に登録する。

    • 台詞「たしかに登録しました」(ID: #$0B3A) を表示する。

    • 【まだ登録する?】 へジャンプ。

  • 【登録しない】

    • 台詞「それは残念です」(ID: #$0B3B) を表示する。

  • 【まだ登録する?】

    • 台詞「他の人も名簿に登録しますか?」(ID: #$0B3C) を表示する。

    • 「はい・いいえ」ウィンドウを表示して、プレイヤーの入力を待つ。

      • キャンセルボタン or 「いいえ」⇒【またおいで】へジャンプ。

      • 「はい」⇒【新しく登録する】へジャンプ。

  • 【やっぱりやめる】

    • 台詞「おや やめるのですね」(ID: #$0B46) を表示する。

  • 【またおいで】

    • 台詞「では新しい仲間を欲しくなったとき またおいでください」(ID: #$0B47) を表示する。

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

オリジナル版に比べると、キャラクターの追加処理が遥かに複雑になっている。 名前の決定に関しては、有名な新規作成キャラクターの名前の「ロトテスト」に加えて、「予約名との照合テスト」が仕様追加されている。 これはリメイク版では改名機能システムが追加されているので、そちらで利用されている機能を登録所システムにも採り入れたということだろう。

さらに、キャラクターの能力値をプレイヤーがある程度底上げできるという、面白い仕様がここには追加されている。 タネ・木の実を定数個を使ってよいというルールがある。 この個数は通常 5 だが、1/64 という決して高くない確率で 6 になる。 この事実一つとっても、ドラクエというゲームが不思議なバランス感覚を有する設計の上にあるものだということを強く認識させられる。

5.16.1.2. キャラクター削除サブルーチン

サブルーチン $C3DD13 は、既存のキャラクターのいずれかを削除することができる処理だ。

  • サブルーチン $C4467F を呼び出し、登録済みのキャラクター数が上限に達しているか (Carry) 調べる。

    • 上限に達していない場合は【終了】へジャンプ。

    • 台詞「これ以上登録するにはだれかを名簿から外さないと~」(ID: #$0B3F) を表示する。

    • 「はい・いいえ」ウィンドウを表示して、プレイヤーの入力を待つ。

      • キャンセルボタン or 「いいえ」⇒【やめる】へジャンプ。

  • 【誰を外す】

    • 台詞「誰を外しますか?」(ID: #$0B40) を表示する。

    • ウィンドウ「だれを」を表示し、酒場にいるキャラクターだけをリストする。 そしてプレイヤーの入力を待つ。

      • キャンセルボタン ⇒【やめる】へジャンプ。

      • キャラクターを選択 ⇒ $33D6 = 選択番号

    • キャラクター登録 ID 取得サブルーチン $C42F5E を呼び出し、 選択キャラクター (A) の登録 ID を取得 (X) する。

    • $BE77 = X

    • キャラクターデータ格納アドレス取得サブルーチン $C429DA を呼び出し、 選択キャラクター (A) のアドレスを取得 (X) する。

      • X == $3604 ⇒【削除不可】へジャンプ。

    • 主人公判定サブルーチン $C42DA1 を呼び出し、 選択キャラクター (A) が主人公であるか否かを調べる。

      • 主人公である ⇒【主人公が選択された】へジャンプ。

    • 台詞「○○○○さんを外すのですね?そうすると2度と会えないかも~」(ID: #$0B41) を表示する。

    • 「はい・いいえ」ウィンドウを表示して、プレイヤーの入力を待つ。

      • キャンセルボタン or 「いいえ」⇒【やめる】へジャンプ。

    • サブルーチン $C3DAC4 を呼び出し、選択キャラクター (A) のすべての所持品をふくろへ移す。

    • キャラクター削除サブルーチン $C445F8 を呼び出し、選択キャラクター (X) を削除する。

    • 台詞「残念ですが○○○○さんを外しました。これで新しい人を登録できます」(ID: #$0B42) を表示する。

  • 【終了】

    • Carry ビットをクリアする。

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

  • 【やめる】

    • 台詞「おや気が変わりましたか」(ID: #$0B43) を表示する。

    • Carry ビットをセットする。

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

  • 【主人公が選択された】

    • 台詞「えっ○○○○さんをっ!?無茶を言わないでください」(ID: #$0B4C) を表示する。

    • 【誰を外す】へジャンプ。

  • 【削除不可】

    • 台詞「申し訳ありませんがその人を消すことはできません」(ID: #$0B4D) を表示する。

    • 【誰を外す】へジャンプ。

  • 【事後条件】

    • キャラクターを削除した場合に限り、Carry ビットはセット状態。

オリジナル版の処理を踏襲したものになっている。 削除できないキャラクターがいるらしいことが、プログラムコードから確認できる。 これはバークに預けた商人キャラクターのはずだ。

5.16.1.3. 入力が仲間の名前と同じかチェック

サブルーチン $C3DDBF は入力した名前を持つ仲間キャラクターが既に存在するかどうかを調べる。

  • キャラクター人数取得サブルーチン $C4297C を呼び出し、 パーティとルイーダの酒場にいるキャラクターの人数 ($36E2 + $36E4) を得る ($78) 。

  • for A in $78 - 1 .. 0

    • 名前文字列照合サブルーチン $C3DDE5 を呼び出し、 キャラクター (A) の名前と、プレイヤーが入力した名前文字列 $3332,X と比較する。

      • 入力文字列がキャラクター (A) のそれと完全に一致 ⇒【終了】へジャンプ。

  • Carry ビットをクリアする。

  • 【終了】

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

  • 【事後条件】

    • 入力した名前を持つキャラクターが既にいる場合に限り、Carry ビットがセットされている。

5.16.1.4. パラメータ増加処理サブルーチン

サブルーチン $DE20 は、作成キャラクターに対し、 「ちから」「すばやさ」といった指定のパラメータを上げる処理だ。 これは「何ポイント上がった」というメッセージ表示を含む。

  • 【事前条件】

    • A レジスタはタネウィンドウで選択した項目の番号を示す。 実際は 0 以上 4 以下の値がセットされている。

  • A = $C3DE40,(A * 2) として、 A レジスタにタネウィンドウで選択した項目のアイテムのアイテム構造体 ID をセットする。

  • サブルーチン $C45254 を呼び出し、 このアイテムに対応する戦闘行動構造体 ID を取得 (A) する。

  • X = A

  • ダメージ値サブルーチン $C90B3A を呼び出し、 行動 (X) によるダメージを決定 (A) する。 文脈上、これはダメージと呼ばず、パラメータ上昇値と呼ぶことにする。

  • メッセージ表示用に $BE81 = A とし、パラメータ上昇値を覚えておく。

  • X = (呼び出し直後の A) * 2 とする。ジャンプテーブルのインデックスをセットだ。

  • Y = $2BB4 とする。作成キャラクターを示す何かの値だ。

  • ジャンプテーブル $DE45 に従いジャンプ (X) する。 呼び出し元に制御を戻すのはジャンプ先のどこかになる。

配列 $C3DE40,X は以下のようになっている。 タネウィンドウで表示するアイテムリストに対応するアイテム ID を配列したものだ。

C3/DE40:    B2  ; ちからのたね
C3/DE41:    B3  ; すばやさのたね
C3/DE42:    B4  ; スタミナのたね
C3/DE43:    B6  ; かしこさのたね
C3/DE44:    B5  ; ラックのたね

ジャンプテーブル $DE45 は、 各パラメータに対応するパラメータ上昇処理コードのアドレス配列だ。 以下にジャンプテーブルを示す。

C3/DE45:    4FDE  ; ちから
C3/DE47:    5DDE  ; すばやさ
C3/DE49:    6BDE  ; たいりょく
C3/DE4B:    79DE  ; かしこさ
C3/DE4D:    87DE  ; うんのよさ

これを見ると、例えば「ちから」を上げる場合は $DE4F にジャンプすることがわかる。 実装は以下のようになっていて、キャラクターの能力値上限を更新し、 メッセージを表示するという処理だ。 その他のパラメータに関しても、同様のコードになっている。

C3/DE4F:    226834C4    JSR $C43468 ; (RTL+3) キャラクター::ちからアップ
C3/DE53:    06FDFF
C3/DE56:    22D4A8C1    JSR $C1A8D4 ; [B2]の ちからが[AD][BB]あがった![AC]
C3/DE5A:    CF00
C3/DE5C:    60          RTS

5.16.1.5. 性格決定サブルーチン

サブルーチン $C3DE95 は、作成キャラクターの初期の性格を決定する処理だ。 説明を詳細にし過ぎるすると解析の要点がボケる恐れがあるので、ここでは記述の粒度を粗くする。 概略は以下の通り。

  • 下の表に示すアドレスに、 新規作成キャラクター (A) に関する表の値をそれぞれ取得または計算し、セットする。

    表 5.20 $C3DE95 前半部処理

    Address Value
    $2BB8 職業 ID
    $2BBA 性別
    $2BBC キャラクター ID
    $2BBE,X (X = 0,2,4,6,8) パラメータ種別を表す数値。以下の通り。
    • $2BBE = #$0000: ちから

    • $2BC0 = #$0001: すばやさ

    • $2BC2 = #$0002: たいりょく

    • $2BC4 = #$0003: かしこさ

    • $2BC6 = #$0004: うんのよさ

    $2BC8,X (X = 0,2,4,6,8) パラメータ値の増分(後述)。 ちから、すばやさ、たいりょく、かしこさ、うんのよさの順に格納する。
    $2BD2,X (X = 0,2,4,6,8) パラメータ値デフォルト。 職業構造体で定義されているレベル 1 での各パラメータの値を格納する。 パラメータ種別の格納順序は上記 ($2BC8,X) と合わせる。

  • サブルーチン $DF8E を呼び出すことで、 新規作成キャラクターのパラメータ増分値配列 $2BC8,X を降順にソートする。 かつ、対になっている配列 $2BBE,X$2BD2,X も対応関係を保つように並び替える。

  • サブルーチン $DFF9 を呼び出すことで、 新規作成キャラクターの性格条件群 ID を決定 (A) する。

  • サブルーチン $E018 を呼び出すことで、 性格条件群構造体 ID (A) のデータから、 性格グループ構造体 ID を決定 (A) する。

  • サブルーチン $E134 を呼び出すことで、 決定した性格グループ構造体データから、性格を決定する。

  • X = $2BB4

  • キャラクター性格セットサブルーチン $C42ED6 を呼び出し、 新規キャラクター (X) の性格 ID をキャラクターデータ内にセット (A) する。

  • 【事後条件】

    • A == 決定した性格の性格構造体 ID

パラメータ値の増分とは、 タネ・木の実を使ったことによる能力パラメータの増加ポイントということだ。 このサブルーチンでは、 それらを「タネを使い切ったときの値」と「タネを全然使っていないときの値」の差をとることで得ている。

5.16.1.5.1. パラメータ増分値配列を降順ソート

サブルーチン $DF8E は前項サブルーチンで初期化した三配列を、ある基準に従ってソートする。 ゲームロジックとは直接関係のない処理なので、 アルゴリズムに興味のない読者は読み飛ばして構わない。

  • 【事前条件】

    • $2BBE,X (X = 0,2,4,6,8) が前項の説明のようにセット済

    • $2BC8,X (X = 0,2,4,6,8) が前項の説明のようにセット済

    • $2BD2,X (X = 0,2,4,6,8) が前項の説明のようにセット済

  • 【古典的なバブルソート】

    • パラメータ増分値配列 $2BC8,X に対して、降順ソートを行う。 すなわち、大きいほうが前に来るように隣接要素を交換する。

      • 隣接する二項が等しい場合、 初期パラメータ値配列 $2BD2,X において隣接する二項の大小比較を行う。 これも、大きいほうが前に来るように隣接要素を交換する。

        • そこでも隣接する二項が等しい場合、 A = #$0001 とした上で、乱数取得サブルーチン $C0133E を呼び出す。 これにより、乱数 0 または 1 を得る。 0 の場合に限り、隣接する二要素を交換する。

  • 【事後条件】

    • $2BBE,X$2BC8,X$2BD2,X が各 X (X = 0,2,4,6,8) について、それぞれ対応している。

    • $2BC6,X > $2BC8,X (for X = 2,4,6,8)

      • ただし $2BC6,X == $2BC8,X のときは $2BD0,X >= $2BD2,X が成り立つ。

上のロジックで、配列内の隣接要素の交換はサブルーチン $DFCF の呼び出しにより行う。 三配列間の対応関係を保つべく、三配列それぞれに対して隣接要素交換操作を行う。

5.16.1.5.2. 性格条件群の決定

サブルーチン $DFF9 は、新規作成キャラクターのための性格条件群構造体データを決定する。 かいつまんで言うと、初期性格候補一覧が定義されたデータ (これを性格条件群と呼ぶ)を選択する処理だ。

  • 【事前条件】

    • $2BBE == 最も増分が大きいパラメータの種別 0..4 のどれか。 すなわち、ちから、すばやさ、たいりょく、かしこさ、うんのよさのいずれかだ。

  • X = $C3E00E,X (where X == $2BBE) に対して、 職業構造体サブルーチン $C46AFD を呼び出し、 作成キャラクターの職業に対応する職業構造体データの X バイト目の値 & #$00FF を取得 (A) する。

  • 【事後条件】

    • A == 性格条件群構造体 ID

配列 $C3E00E,X#$0006 から #$000A の値が連続して配列されているだけだ。 取りも直さず、 職業構造体のメモリレイアウトにおいて #$0006 バイト目から #$000A バイト目は、 性格条件群構造体 ID の配列になっていることがわかる。

5.16.1.5.3. 性格グループ構造体 ID 決定

サブルーチン $E018 は新規作成キャラクターの初期性格の性格 ID を決定する。

  • 【事前条件】

  • X = A

  • 構造体アクセス汎用サブルーチン $C9050D を呼び出し、 $C30EFD 構造体データを格納しているアドレスを取得 ($78) する。

  • 【判定 0】

    • データの二位フラグ [0] を見る。

      • 1 ⇒ 作成キャラクターのパラメータ種別 [0] の増分が、 五種類のパラメータの中で二番目に増加が大きいものであるか調べる。

        • YES ⇒ A = ID [0] をセットし、呼び出し元に制御を戻す。

        • NO ⇒【判定 1】へジャンプ。

      • 0 ⇒ 作成キャラクターのパラメータ種別 [0] の増分が、 閾値 [0] 以上であるか調べる。

        • YES ⇒ A = ID [0] をセットし、呼び出し元に制御を戻す。

  • 【判定 1】

    • 【判定 0】と同様。説明省略。

  • 【判定 2】

    • 【判定 1】と同様。説明省略。

  • 【判定 3】

    • 【判定 2】と同様。説明省略。

  • 【判定 4】

    • 【判定 3】と同様。説明省略。

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

  • 【事後条件】

    • A == 性格 ID

こう書いておいてなんだが、上記プログラムコードの書き下しは理解しにくい。 最低限 $C30EFD 構造体のダンプを手許に置いて、 それを見ながらコードを机上トレースしないと、ここでの処理が感覚でわからぬのではないかと思う。

5.16.1.5.4. 性格を決定

サブルーチン $E134 は、新規作成キャラクターの初期の性格を決める。

  • 【事前条件】

  • X = A

  • 汎用構造体アドレス取得サブルーチン $C9050D 呼び出しにより、 指定 ID (X) に対する構造体 $C30FFC のデータアドレスを ($78) 得る。

  • 下の表の各アドレスにある値をゼロにセットする。

    表 5.21 $E134 ゼロクリア表

    Address Value
    $2BBE 配列 $2BD2,X の要素数を表すために用いる
    $2BC0 配列 $2BD2,X の各要素の和
    $2BC2,X (X = 0,2,..E) 性格 ID の配列
    $2BD2,X (X = 0,2,..E) 配列 $2BC2,X の各要素の「重み」

  • 下の表の各アドレスに、構造体データの各フィールドをセットする。 これらの値は性格 ID だ。

    表 5.22 $E134 配列表 1

    Address Value
    $2BC2 構造体データ[#$0004] & #$00FF
    $2BC4 構造体データ[#$0005] & #$00FF
    $2BC6 構造体データ[#$0006] & #$00FF
    $2BC8 構造体データ[#$0007] & #$00FF
    $2BCA 構造体データ[#$0008] & #$00FF
    $2BCC 構造体データ[#$0009] & #$00FF
    $2BCE 構造体データ[#$000A] & #$00FF
    $2BD0 構造体データ[#$000B] & #$00FF

  • 下の表の各アドレスに、 サブルーチン $C90717 を用いることで構造体データの各フィールドを (必要に応じて右シフトされた値を)セットする。 これらの値は、上記配列に格納されている各性格の「重み」だ。

    表 5.23 $E134 配列表 2

    Address Value
    $2BD2 構造体データ[#$0000] & #$000F
    $2BD4 構造体データ[#$0000] & #$00F0
    $2BD6 構造体データ[#$0001] & #$000F
    $2BD8 構造体データ[#$0001] & #$00F0
    $2BDA 構造体データ[#$0002] & #$000F
    $2BDC 構造体データ[#$0002] & #$00F0
    $2BDE 構造体データ[#$0003] & #$000F
    $2BD0 構造体データ[#$0003] & #$00F0

  • 性格 ID 配列 $2BC2,X に対して以下の反復処理を行う。

    • A = $2BC2,X

      • A == 0 ⇒ 反復処理を次へ進める

    • 性格サブルーチン $C46BED を呼び出して、性格 (A) の性別情報を取得 (A) する。

      • もしその性格が新規作成キャラクターのそれと相容れないものであれば、 配列 $2BC2,X$2BD2,X を前方へ詰める。 そして反復処理を次へ進める。

    • 「重みの和」を加算する: $2BC0 += $2BD2,X

    • $2BD2,X に今の和を格納する: $2BD2,X = $2BC0

  • 【乱数取得】

    • 乱数の範囲を決める: A = $2BC0 - 1

    • 乱数取得サブルーチン $C0135F を呼び出し、乱数を取得 (A) する。

    • 配列 $2BD2,X (X = 0,..,$2BBE) に対して、 A を超える値を前方から検索する。 この配列は単調増加だ。

      • そのような値を検索できたならば、 $2BC2,X の値を A にロードして、呼び出し元に制御を戻す。

      • 見つからなかった場合は、 $2BC2 の値を A にロードして、呼び出し元に制御を戻す。

  • 【事後条件】

    • A == 性格 ID

紙面の都合上説明できないが 「配列 $2BC2,X$2BD2,X を前方へ詰める」のは、 補助サブルーチン $C3E2B4 の呼び出しで行う。

キャラクターの能力値、およびそのバランスだけで初期性格が一意に決まるのではないことが読み取れる。 ちょっとした乱数的要素も性格決定に関与する。

5.16.1.6. 登録屋が性格を告げるサブルーチン

サブルーチン $E2D0 は、 性格が決まったばかりのキャラクターに対する寸評を登録屋が与える処理だ。 これは見方を変えれば、ゲームからプレイヤーに向けてのレポート処理だ。

  • 【事前条件】

    • A == 性格 ID

  • 性格名文字列 ID 取得サブルーチン $C42F28 を呼び出し、 性格 (A) の名前文字列 ID を取得 (X) する。

  • 次のメッセージ表示のため、$BE77 = X とする。

  • 性格構造体の 7バイト目 & #$001C ビット取得サブルーチン $C46C28 を呼び出す。

  • A = $C3E2EA,X (where X = A * 2) とし、 A の値をメッセージ ID と解釈する台詞表示サブルーチン $C1A95A を呼び出す。

配列 $C3E2EA,X は小さいので、すぐに中身を確認できる。 登録屋は性格の名前によって、台詞回しを微妙に変える。

C3/E2EA:    480B  ; [D6]なかなか [B2][AD]のようですね。[AF][AC]
C3/E2EC:    490B  ; [D6]なかなか [B2][AD]なようですね。[AF][AC]
C3/E2EE:    4A0B  ; [D6]なかなか [B2][AD]ようですね。[AF][AC]
C3/E2F0:    4B0B  ; [D6]なかなか [B2]さん[AD]のようですね。[AF][AC]

5.16.2. データ

5.16.2.1. $C30EFD 構造体 - 登録所・性格条件群

アドレス $C30EFD には登録所処理で参照される構造体データが定義されている。 この構造体のメモリレイアウトは以下の通り。

表 5.24 $C30EFD 構造体 - 登録所・性格条件群

Byte:Bit 80 40 20 10 08 04 02 01
00 二位フラグ[0] 増分の閾値[0]
01 パラメータ種別[0]
02 $C30FFC 構造体 ID [0]
03 二位フラグ[1] 増分の閾値[1]
04 パラメータ種別[1]
05 $C30FFC 構造体 ID [1]
06 二位フラグ[2] 増分の閾値[2]
07 パラメータ種別[2]
08 $C30FFC 構造体 ID [2]
09 二位フラグ[3] 増分の閾値[3]
0A パラメータ種別[3]
0B $C30FFC 構造体 ID [3]
0C 二位フラグ[4] 増分の閾値[4]
0D パラメータ種別[4]
0E $C30FFC 構造体 ID [4]

各フィールドの意味は以下の通りだが、決してわかりやすいものではない。

増分の閾値[i]

二位フラグ[i] == 0 のとき、判定サブルーチンは登録時のタネによるパラメータ種別[i] のパラメータ増分値がこの値以上であるかを調べる。

二位フラグ[i] == 1 のとき、このフィールドは未使用。

二位フラグ[i]

二位フラグ[i] == 1 のとき、 新規作成キャラクターのパラメータ種別[i] の増分値が、 二番目に大きいパラメータであるか調べる。

パラメータ種別 [i]

パラメータ種別を表す値だ。値とパラメータ名との対応は 性格決定サブルーチンの表を参照。

$C30FFC 構造体 ID [i]

$C30FFC 構造体の ID だ。 そこから初期性格を絞り込む。

5.16.2.2. $C30FFC 構造体 - 登録所・性格群

アドレス $C30FFC には登録所処理で参照される構造体データが定義されている。 新規作成キャラクターの初期性格を抽選するための表だ。 この構造体のメモリレイアウトは以下の通り。

表 5.25 $C30FFC 構造体 - 登録所・性格群

Byte:Bit 80 40 20 10 08 04 02 01
00 性格[1] 確率 性格[0] 確率
01 性格[3] 確率 性格[2] 確率
02 性格[5] 確率 性格[4] 確率
03 性格[7] 確率 性格[6] 確率
04 性格[0]
05 性格[1]
06 性格[2]
07 性格[3]
08 性格[4]
09 性格[5]
0A 性格[6]
0B 性格[7]

各フィールドの意味は以下の通り。

性格[i] 確率

新規作成キャラクターの性格が性格[i] になる確率の分子。 分母は(性別によるなれる性格の違いを無視すれば) 性格[0] 確率から性格[7] 確率までの和だ。

性格[i]

新規作成キャラクターのなり得る性格の性格 ID だ。