5.18. 命名神解析

5.18.1. 解析
5.18.1.1. 命名神共通処理サブルーチン
5.18.1.2. 入力がふざけた名前かチェック
5.18.1.3. 入力が予約名かどうかチェック
5.18.1.4. 名前テスト共通サブルーチン
5.18.1.5. 入力が一文字しか使っていないか調べるサブルーチン
5.18.1.6. 選択キャラの現在の名前を先にチェック

本節では SFC 版ドラクエ 6 から引き継いだ機能である、パーティーキャラクターの名前を変更する処理について解析する。 SFC 版ドラクエ 3 の場合はキャラクターのデフォルトの名前という概念がないので、 対応する SFC 版ドラクエ 6 の処理コードよりも量が少ないと予想して解析を開始したが、 しかし期待は外れた。

5.18.1. 解析

命名神に仕える神官(以下婆サン)に「はなす」とすぐに命名神共通処理サブルーチンが開始する。 ここから処理をたどっていく。 関係するサブルーチンは、婆サンの台詞表示にサブルーチン $C1A92E を用い、 それ以外のメッセージ表示はサブルーチン $C1A8D4 を用いる。 これを手掛かりに処理の流れをつかむことができるので、そこから細かい処理を解読していくのが基本だ。

5.18.1.1. 命名神共通処理サブルーチン

サブルーチン $C3E8D3 は、婆サンに「はなす」と始まる処理だ。

  • 台詞「わしは 命名神マリナン様につかえる神官じゃ(略)だれか 名前をかえるか?」(ID: #$09CD) を表示する。

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

    • キャンセルボタン ⇒【終了】へジャンプする。

    • 「はい」⇒【だれをかえる】へジャンプする。

    • 「いいえ」⇒【終了】へジャンプする。

  • 【だれをかえる】

    • 台詞「だれの名前をかえたいと いうのじゃ?」(ID: #$09CE) を表示する。

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

      • キャンセルボタン ⇒【キャンセル抜け】へジャンプする。

    • $33D6 = 選択キャラクターの番号 とする。

    • サブルーチン $C3EBCD を呼び出すことで、 選択したキャラクターの現在の名前が 命名神の怒りに触れているものかどうかをテストする。

      • 現在の名前が怒りに触れている名前 ⇒【既にダメな名前】へジャンプ。

      • パーティーメンバーを選択⇒【名前を変える対象を選択した】へジャンプ。

    • 台詞「むう それは……ふくろか?」(ID: #$09D7) を表示する。

  • 【名前を変える対象を選択した】

    • 【名前を決める】へジャンプ。

  • 【既にダメな名前】

    • サブルーチン $C1E32E 呼び出しにより効果音 (ID: #$002A) を鳴らす。終わるまで待つ。

    • 台詞「なんと! その名は命名神の怒りにふれておる!」(ID: #$09E5) を表示する。

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

      • キャンセルボタン or 「いいえ」⇒【5000 ゴールドを拒否】

    • X = #$1388, A = #$0000 として、所持金変更サブルーチン $C45B66 を呼び出す。 これにより、パーティの現在の所持金から 5000 ゴールドを減らすことを試みる。

      • 所持金の変更に成功した ⇒【5000 ゴールド支払う】へジャンプ。

      • 所持金の変更に失敗した ⇒ 台詞「そんな大金はないようじゃな」(ID: #$09E9) を表示する。

  • 【キャンセル抜け】

    • 【ほかに誰か】へジャンプ。

  • 【5000 ゴールド支払う】

    • メッセージ「○○○○は 5000ゴールドをさしだした」(ID: #$09E7) を表示する。

    • 台詞「○○○○の新しい名前を教えてくれ」(ID: #$09E8) を表示する。

    • 【新しい名前】へジャンプ。

  • 【5000 ゴールドを拒否】

    • 台詞「ではやはりそのままじゃ」(ID: #$09E6) を表示する。

    • 【ほかに誰か】へジャンプ。

  • 【名前を変える】

    • 台詞「新しい名前をわしに教えてくれ」(ID: #$09CF) を表示する。

  • 【新しい名前】

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

      • 何か名前を入力した状態で終わった ⇒【入力直後】へジャンプ。

  • 【入力の名前が現在の名前と完全一致】

    • 【名前を変えるのをやめる】へジャンプ。

  • 【入力直後】

    • サブルーチン $C3C37F を呼び出し、 プレイヤーが入力した文字列を $3332,X$4056,X にコピーする。 ちなみに $3332,X$4056,X はそれぞれキャラクターの名前文字列用、 ふくろの名前文字列用メモリだ。

    • パーティ人数取得サブルーチン $C4297C を呼び出し、 現在のパーティの総人数を取得 (A) する。

      • A == $33D6 ⇒【ふくろ】へジャンプ。

    • A = $33D6 とする。 「だれの」ウィンドウで選択したキャラクターの番号だ。

    • サブルーチン $C3DDE5 を呼び出す。 これは「現在の名前と $3332,X と比較する」仕事をする。

      • 入力した名前が現在の選択キャラクターのそれと一致している ⇒【入力の名前が現在の名前と完全一致】へジャンプ。

  • 【ふくろ】

    • サブルーチン $C3DDDC を呼び出す。 これは「現在の名前と $3332,X と比較する」仕事をするが、 ふくろに特化したコードが走ることになる。

      • 入力した名前が現在のふくろのそれと一致している ⇒【入力の名前が現在の名前と完全一致】へジャンプ。

  • 【ロトテスト】

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

      • マッチしない場合は【入力した名前が許されているか調べる】へジャンプ。

  • 【予約名が入力された】

    • 台詞「命名神がその名はイカンといっておる」(ID: #$09D9) を表示する。

    • 【他の名前にする?】へジャンプ。

  • 【入力した名前が許されているか調べる】

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

      • 入力が予約名 ⇒【予約名が入力された】へジャンプ。

    • サブルーチン $C3DDBF を呼び出して、 入力が仲間の名前と同じかチェックする。

      • 入力がどの仲間の名前とも異なる ⇒【入力がふざけた名前か調べる】へジャンプ。

    • 台詞「その名前の者がおぬしの仲間にいるようじゃな」(ID: #$09DD) を表示する。

    • 【他の名前にする?】へジャンプ。

  • 【入力がふざけた名前か調べる】

    • サブルーチン $C3EB2B を呼び出して、 入力がふざけた名前かどうかを調べる。

      • ふざけていない名前であれば、【一文字テスト】へジャンプする。

    • ふざけた名前であれば、台詞「本気でそのような名前をつけようというのか」(ID: #$09DE) を表示する。

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

      • キャンセルボタン or 「いいえ」⇒【他の名前にする?】

  • 【警告】

    • 台詞「命名神様の怒りにふれてもわしはしらんぞ」(ID: #$09DF) を表示する。

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

      • キャンセルボタン or 「いいえ」⇒【他の名前にする?】

    • 台詞「……おお 命名神マリナンよ 新たなる名××××に神の祝福……うわっ!!」(ID: #$09E0) を表示する。

    • サブルーチン $C3EC66 呼び出しにより、画面を激しくフラッシュする。

    • サブルーチン $C3EC0D 呼び出しにより、画面フラッシュをゆっくり戻す。

    • サブルーチン $C1E32E 呼び出しにより、効果音 (ID: #$002A) を鳴らす。終わるまで待つ。

    • 台詞「おぬしは 命名神の怒りにふれてしまったぞ!!」(ID: #$09E1) を表示する。

    • 【名前更新】へジャンプ。

  • 【一文字テスト】

    • サブルーチン $C3EBAB を呼び出して、 入力した名前が「ああああ」パターンかどうか調べる。

      • 複数の文字が使用されている ⇒【適切な名前が入力された】へジャンプ。

    • 台詞「おぬし名前というものをなめておるのか」(ID: #$09E2) を表示する。

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

      • キャンセルボタン ⇒【なめていない】へジャンプ。

      • 「はい」⇒【警告】へジャンプ。

  • 【なめていない】

    • 台詞「では名をなめてはおらぬが~」(ID: #$09E3) を表示する。

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

      • キャンセルボタン ⇒【ほかの名にすることじゃ】へジャンプ。

      • 「はい」⇒【警告】へジャンプ。

  • 【ほかの名にすることじゃ】

    • 台詞「ならばほかの名にすることじゃ」(ID: #$09E4) を表示する。

    • 【新しい名前】へジャンプ。

  • 【適切な名前が入力された】

    • 台詞「○○○○の名前を××××にかえるのじゃな」(ID: #$09D0) を表示する。

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

      • キャンセルボタン or 「いいえ」⇒ 他の名前にする?

    • 台詞「新たなる名に神の祝福を!!」(ID: #$09D1) を表示する。

    • サブルーチン $C3EC0D 呼び出しにより、画面フラッシュをゆっくり戻す。

    • 台詞「これで○○○○は××××と名のることがゆるされたぞ!」(ID: #$09D2) を表示する。

  • 【名前更新】

    • パーティ人数取得サブルーチン $C4297C を呼び出し、 現在のパーティの総人数を取得 (A) する。

      • A == $33D6 ⇒【ふくろ名前更新】へジャンプ。

    • A = $33D6 とする。 「だれの」ウィンドウで選択したキャラクターの番号だ。

    • キャラクターの名前更新サブルーチン $C42FAE を呼び出し、 選択キャラクターの名前を入力した名前に更新する。

    • 【ほかに誰か】へジャンプ。

  • 【ふくろ名前更新】

    • サブルーチン $C455D2 を呼び出し、ふくろの名前を入力した名前に更新する (ちなみに $368B,X = $4056,X のような処理が走る)。

    • 【ほかに誰か】へジャンプ。

  • 【名前を変えるのをやめる】

    • 台詞「なんじゃ名前をかえないのか?」(ID: #$09D8) を表示する。

    • 【ほかに誰か】へジャンプ。

  • 【他の名前にする?】

    • 台詞「他の名前にかえるか?」(ID: #$09D5) を表示する。

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

      • キャンセルボタン or 「いいえ」⇒【ほかに誰か】へジャンプ。

      • その他 ⇒【名前を変える】へジャンプ。

  • 【ほかに誰か】

    • 台詞「他にだれか名前をかえたい者はおるか?」(ID: #$09D3) を表示する。

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

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

      • その他 ⇒【だれをかえる】へジャンプ。

  • 【終了】

    • 台詞「名前をかえたくなったら いつでも来るがよいぞ」(ID: #$09D4) を表示する。

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

名前変更の本流サブルーチンは、ほぼ一枚岩の処理だった。

5.18.1.2. 入力がふざけた名前かチェック

サブルーチン $C3EB2B は、プレイヤーが入力した名前がふざけたものであるかどうかをテストする。

$72 の示す値の型は、見るからに絶対アドレスだ。 実際 $C30AF5 周辺をダンプして、既に解析済みの文字列表と照合すれば、 これが文字列 ID の配列であることがわかる。 内容は以下の通り、エロ&バカ系統の単語が配列されている。 平仮名と片仮名が入り交じっていることに注意したい。

C3/0AF5:    F602  ; ちんこ
C3/0AF7:    F702  ; きんたま
C3/0AF9:    F802  ; ちんちん
C3/0AFB:    F902  ; あほ
C3/0AFD:    FA02  ; ちんぽこ
C3/0AFF:    FB02  ; ちんポこ
C3/0B01:    FC02  ; へんたい
C3/0B03:    FD02  ; ちんぼ
C3/0B05:    FE02  ; ちんボ
C3/0B07:    FF02  ; ちかん
C3/0B09:    0003  ; おめこ
C3/0B0B:    0103  ; まんこ
C3/0B0D:    0203  ; おまんこ
C3/0B0F:    0303  ; あそこ
C3/0B11:    0403  ; うんこ
C3/0B13:    0503  ; でべそ
C3/0B15:    0603  ; デべそ
C3/0B17:    0703  ; うんち
C3/0B19:    0803  ; はなたれ
C3/0B1B:    0903  ; おしっこ
C3/0B1D:    0A03  ; せっくす
C3/0B1F:    0B03  ; ばか
C3/0B21:    0C03  ; バか
C3/0B23:    0D03  ; おしり
C3/0B25:    0E03  ; まぬけ
C3/0B27:    0F03  ; あなる
C3/0B29:    1003  ; きちがい
C3/0B2B:    1103  ; すけべ
C3/0B2D:    1203  ; きちガい
C3/0B2F:    1303  ; すけべ

5.18.1.3. 入力が予約名かどうかチェック

サブルーチン $C3EB3F は、プレイヤーが入力した名前が、 ゲームにより予約された名前であるかどうかをテストする。

前項と同様に、 $C31368 に予約名を表現する文字列の文字列 ID 配列が存在する。 内容は以下の通り、重要キャラクターの名前を表す単語が配列されている ここでも平仮名と片仮名が入り交じっていることに注意したい。

C3/1368:    2403  ; おるてが
C3/136A:    2503  ; かんだた
C3/136C:    2603  ; がらい
C3/136E:    2703  ; おるてガ
C3/1370:    2803  ; かんダた
C3/1372:    2903  ; ガらい
C3/1374:    2A03  ; えりっく
C3/1376:    2B03  ; おりびあ
C3/1378:    2C03  ; ばらもす
C3/137A:    2D03  ; ぞーま
C3/137C:    2E03  ; おりビあ
C3/137E:    2F03  ; バらもす
C3/1380:    3003  ; ゾーま
C3/1382:    3103  ; ひみこ
C3/1384:    3203  ; るびす
C3/1386:    3303  ; のるど
C3/1388:    3403  ; ばこた
C3/138A:    3503  ; ぜにす
C3/138C:    3603  ; るビす
C3/138E:    3703  ; のるド
C3/1390:    3803  ; バこた
C3/1392:    3903  ; ゼにす

5.18.1.4. 名前テスト共通サブルーチン

サブルーチン $C3EB53 は、呼び出し元が指定する文字列型配列から、文字列を検索する。

  • 【事前条件】

    • $70 は配列のサイズ、すなわち検索対象となる文字列の個数を指定する。

    • $72 は、3 バイト長で、その配列の存在するアドレスを指定する。

  • 文字列の格納アドレス配列アクセスサブルーチン $C1BA53 と 文字列 Peeking サブルーチン $C1BACC を反復的に呼び出して、 [$72],Y (Y == $70 * 2 ... 0) と $3332,X にある文字のペアを比較していく。 ただし、一つのペアにつき、最高二度比較を行う。 一度目は素の文字コードを比較し、 それらが一致していなければ、[$72],Y 側の文字コードを #$0043 - #$000C 分だけ加算した値と比較する (それぞれの値は「ア」と「あ」の文字コードだ)。

    • 一致する文字列が見つかるか、配列を最後まで調べつくすまでは、上記処理を繰り返す。

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

  • 【事後条件】

    • 一致するものがあれば、そのときに限り Carry ビットがセットされている。

これは平仮名と片仮名を区別せずに文字列を比較するアルゴリズムのように読める。

5.18.1.5. 入力が一文字しか使っていないか調べるサブルーチン

サブルーチン $C3EBAB は、プレイヤーが入力した名前が、

  • ちょうど 4 文字分の長さを持っていて

  • 使われている文字数が 1 であるか

を調べる。

  • A レジスタへのアクセスモードを 1 バイトモードにする。

  • X = 0

  • 【文字を比較】

    • $3332,X == #$AC ⇒【X をチェック】へジャンプ。

    • $3333,X != $3332,X ⇒【X をチェック】へジャンプ。

    • ++X

    • 【文字を比較】へジャンプ。

  • 【X をチェック】

    • X < 3:

      • A レジスタへのアクセスモードを 2 バイトモードにする。

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

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

    • X >= 3:

      • A レジスタへのアクセスモードを 2 バイトモードにする。

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

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

「ああああ」のようなパターンの名前のときに Carry ビットをセットする。 「あ」「ああ」「あああ」パターンには関与しない。

5.18.1.6. 選択キャラの現在の名前を先にチェック

サブルーチン $C3EBCD は、指定したキャラクターの現在の名前が、 命名神の怒りにふれているものかどうかをテストする。

  • 【事前条件】

    • Overflow ビットがセットされていれば、ふくろの名前を調べるものとする。

  • A に文字列 ID をセットする:

    • ふくろの名前文字列を調べたければ、A = #$0020 をセットする。

    • パーティメンバーの名前文字列を調べたければ、 サブルーチン $C42F5E を呼び出し、 キャラクター (A) の名前文字列 ID を取得 (A) する。

  • $33D8 = A として、 サブルーチン $C1BA53 を呼び出して、文字列格納アドレス配列へアクセスする ($BA に文字列のあるアドレスがセットされる)。

  • サブルーチン $C1BACC を反復して呼び出すことで、 配列 $3332,X にキャラクターまたはふくろの名前を示す文字列を格納する。 配列の最後には #$AC がセットされている状態になる。

  • サブルーチン $C3EB2B を呼び出して、 ふざけた名前かどうかを調べる。

    • ふざけた名前 ⇒【怒りにふれている】へジャンプ。

  • サブルーチン $C3EBAB を呼び出して、 名前が「ああああ」パターンかどうか調べる。

    • 「ああああ」パターンの名前 ⇒【怒りにふれている】へジャンプ。

  • 【怒りにふれている】

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

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

  • 【問題なし】

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

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

  • 【事後条件】

    • 命名神の怒りにふれている名前であれば、Carry ビットがセットされている。