4.8. 教会解析

4.8.1. 解析
4.8.1.1. サブルーチン $C3D3AE - 教会共通処理
4.8.1.2. サブルーチン $C3D3E3 - 教会標準処理
4.8.1.3. 構造体 $C58E9F - 教会データ構造体
4.8.2. データ
4.8.3. TODO リスト

教会の処理について簡単に述べる。

4.8.1. 解析

いつものように、GSD の Breakpoint Exec を $C0CACA にセットする。 そして、いろいろな教会に行き、神父やシスターに「はなす」。 複数のアセンブリコードを控えておき、比較して共通部分を見る。

ゼニスのしろ教会神父
$C0/CACA DC B0 06    JML [$06B0][$CE:1823]   A:00CE X:0C14 Y:000A
$CE/1823 AD 39 3D    LDA $3D39  [$7E:3D39]   A:00CE X:0C14 Y:000A
$CE/1826 29 80 00    AND #$0080              A:001F X:0C14 Y:000A
$CE/1829 D0 03       BNE $03    [$182E]      A:0000 X:0C14 Y:000A
$CE/182B 4C 34 18    JMP $1834  [$7E:1834]   A:0000 X:0C14 Y:000A
$CE/1834 22 DD 65 CD JSL $CD65DD[$CD:65DD]   A:0000 X:0C14 Y:000A
$CD/65DD A2 01 00    LDX #$0001              A:0000 X:0C14 Y:000A
$CD/65E0 A9 A8 00    LDA #$00A8              A:0000 X:0001 Y:000A
$CD/65E3 A0 A8 00    LDY #$00A8              A:00A8 X:0001 Y:000A
$CD/65E6 22 AE D3 C3 JSL $C3D3AE[$C3:D3AE]   A:00A8 X:0001 Y:00A8
シエーナ教会シスター
$C0/CACA DC B0 06    JML [$06B0][$CA:B67B]   A:00CA X:022E Y:000A
$CA/B67B 22 C5 64 CD JSL $CD64C5[$CD:64C5]   A:00CA X:022E Y:000A
$CD/64C5 A2 02 00    LDX #$0002              A:00CA X:022E Y:000A
$CD/64C8 A9 90 00    LDA #$0090              A:00CA X:0002 Y:000A
$CD/64CB A0 90 00    LDY #$0090              A:0090 X:0002 Y:000A
$CD/64CE 22 AE D3 C3 JSL $C3D3AE[$C3:D3AE]   A:0090 X:0002 Y:0090
レイドック教会神父
$C0/CACA DC B0 06    JML [$06B0][$CC:97CF]   A:00CC X:0360 Y:000A
$CC/97CF A2 01 00    LDX #$0001              A:00CC X:0360 Y:000A
$CC/97D2 A9 A2 00    LDA #$00A2              A:00CC X:0001 Y:000A
$CC/97D5 A0 A2 00    LDY #$00A2              A:00A2 X:0001 Y:000A
$CC/97D8 22 AE D3 C3 JSL $C3D3AE[$C3:D3AE]   A:00A2 X:0001 Y:00A2
デスコッド教会魔物
$C0/CACA DC B0 06    JML [$06B0][$C9:DC7E]   A:00C9 X:0282 Y:000A
$C9/DC7E 22 F9 65 CD JSL $CD65F9[$CD:65F9]   A:00C9 X:0282 Y:000A
$CD/65F9 A2 06 00    LDX #$0006              A:00C9 X:0282 Y:000A
$CD/65FC A9 A9 00    LDA #$00A9              A:00C9 X:0006 Y:000A
$CD/65FF A0 A9 00    LDY #$00A9              A:00A9 X:0006 Y:000A
$CD/6602 22 AE D3 C3 JSL $C3D3AE[$C3:D3AE]   A:00A9 X:0006 Y:00A9

以上のコードの比較により、教会処理の序盤について以下のようなことが想像できる。

  • サブルーチン $C3D3AE が各教会に共通する処理を行う

  • 同サブルーチンは X, A, Y 各レジスタの値を参照する

4.8.1.1. サブルーチン $C3D3AE - 教会共通処理

それではサブルーチン $C3D3AE のアセンブリコードを見ていこう。 DisPel による逆アセンブルコードリストを以下に示す。

教会共通
C3/D3AE:    08          PHP 
C3/D3AF:    C230        REP #$30
C3/D3B1:    48          PHA 
C3/D3B2:    DA          PHX 
C3/D3B3:    5A          PHY 
C3/D3B4:    8B          PHB 
C3/D3B5:    F47E7E      PEA $7E7E
C3/D3B8:    AB          PLB 
C3/D3B9:    AB          PLB 
C3/D3BA:    8DAF3B      STA $3BAF           // (Unknown)
C3/D3BD:    8CB13B      STY $3BB1           // (Unknown)
C3/D3C0:    8E753B      STX $3B75           // 教会 ID に相当する
C3/D3C3:    E220        SEP #$20
C3/D3C5:    22B52AC9    JSR $C92AB5         ■A = C58E9Fh + 0006h * x [05];
            00
            0600
            9F8E
            C5
            0500                            // A は教会構造体メンバ[05]だ
C3/D3D1:    48          PHA                 // この 1 byte の値をプッシュ
C3/D3D2:    C220        REP #$20
C3/D3D4:    22B52AC9    JSR $C92AB5         ■a = C58E9Fh + 0006h * x [03];
            00
            0600
            9F8E
            C5
            0300                            // a == 教会構造体メンバ[03-04]
C3/D3E0:    3A          DEC A               // それを DEC
C3/D3E1:    48          PHA                 // この 2 byte の値をプッシュ
C3/D3E2:    6B          RTL                 // すなわち RTL で戻る先のアドレスを改竄している

いつものように、サブルーチン $C92AB5 の呼び出しがあることから、 その直後のインラインデータを見ることにより、 $C58E9F6 バイト長の構造体データがいくつか直列していることが断定できる。 この サブルーチンは $C92AB5 呼び出しを二回行うことで、 アドレスデータをスタックにプッシュし、そのまま RTL 命令を用いることで、 教会の処理に移る、ということを意図して行っている。

4.8.1.2. サブルーチン $C3D3E3 - 教会標準処理

教会の処理は後で見るように 4 通り存在する。 ここでは、一般的な教会の処理を行うサブルーチン $C3D3E3 をおおまかに見ていく。

まず、神父やシスターに話しかけてから、 メニューウィンドウが表示されるまでのコードリストを以下に示す。 各コメントは、店屋解析や、 宿屋解析で得た解読結果を利用したものを含む 例えば LDA 直後の JSR $D7B9 はセリフ表示ルーチンであることを既に知っている。

C3/D3E3:    F47E7E      PEA $7E7E
C3/D3E6:    AB          PLB 
C3/D3E7:    AB          PLB 
C3/D3E8:    AE753B      LDX $3B75           // 教会 ID をセット
C3/D3EB:    22B52AC9    JSR $C92AB5         // 先頭のアドレス値をセット
            00          // ($09,S),01h
            0600        // ($09,S),02h
            9F8E        // ($09,S),04h
            C5          // ($09,S),06h
            0000        // ($09,S),07h
C3/D3F7:    8D793B      STA $3B79           $7E3B79 = 教会構造体データ先頭アドレス;
C3/D3FA:    A90200      LDA #$0002          a = 0002h;
C3/D3FD:    223672C3    JSR $C37236         ●処理が深そうなため、今は調査しない
C3/D401:    A90000      LDA #$0000          // セリフ配列のインデックス
C3/D404:    20B9D7      JSR $D7B9           ■生きとし生けるものは~
.label  メニュー項目を選択させる
C3/D407:    A90000      LDA #$0000
C3/D40A:    8DE43A      STA $3AE4           // 不明
C3/D40D:    AEB038      LDX $38B0           // 不明
C3/D410:    224D2BC9    JSR $C92B4D         ■$7E38B4 構造体[16] らしいが意味不明
            00          // ($09,S),01h:  00 であればいい
            2000        // ($09,S),02h:  sizeof
            B438        // ($09,S),04h:  addr-lo
            7E          // ($09,S),06h:  addr-hi
            1600        // ($09,S),07h:  addr-lo に足す; $7E38B4[16]
C3/D41C:    AE753B      LDX $3B75           // 教会 ID をセット
C3/D41F:    22392CC9    JSR $C92C39         //a = $C58E9F[02] & 01h
            00
            0600
            9F8E
            C5          // $C58E9F[02] & 01
            0200        // メニューの内容を決め
            01
            0000
C3/D42E:    C90100      CMP #$0001
C3/D431:    F009        BEQ $D43C           if(a != 0001h)
C3/D433:    A91000      LDA #$0010              a = 0010h;
C3/D436:    223672C3    JSR $C37236             ■教会メニュー;「おいのりをする」なし
C3/D43A:    8007        BRA $D443           }else{
C3/D43C:    A90F00      LDA #$000F              a = 000Fh;
C3/D43F:    223672C3    JSR $C37236             ■教会メニュー;「おいのりをする」あり
                                            }
C3/D443:    9015        BCC $D45A           if(キャンセル){
.label  教会::やめる
C3/D445:    2228B7C3    JSR $C3B728             // 今は調査しない
C3/D449:    2016D8      JSR $D816               // 今は調査しない
C3/D44C:    A90100      LDA #$0001              // セリフ配列のインデックス
C3/D44F:    20B9D7      JSR $D7B9               ■おお 神よ![AD]この者[B2]に~
C3/D452:    AB          PLB 
C3/D453:    C230        REP #$30
C3/D455:    7A          PLY 
C3/D456:    FA          PLX 
C3/D457:    68          PLA 
C3/D458:    28          PLP 
C3/D459:    6B          RTL
                                            }
.label  選択項目をチェック
C3/D45A:    AD7438      LDA $3874
C3/D45D:    C9BD00      CMP #$00BD          // 「やめる」
C3/D460:    D005        BNE $D467           if($3874 == 00BDh){
C3/D462:    CEB038      DEC $38B0               --$38B0;
C3/D465:    80DE        BRA $D445               goto 教会::やめる;
                                            }

ここで押さえておくべきことは以下の通りだ。

  • メニューに「おいのりをする」を含むかどうかは、 教会構造体のデータだけで決まる。

  • メニューウィンドウで項目を選択すると、その文字列の ID がメモリ $7E3874 に格納される(らしい)

メニュー分岐は以下のように実装されている。 JMP 命令で処理を分けている。

.label  ここは不明
C3/D467:    CEB038      DEC $38B0
C3/D46A:    2228B7C3    JSR $C3B728
C3/D46E:    A99DD4      LDA #$D49D
C3/D471:    38          SEC 
C3/D472:    E98DD4      SBC #$D48D
C3/D475:    8D0030      STA $3000
C3/D478:    A20000      LDX #$0000
.label  find-if
                                            for(x = 0000h; ; x += 4){
C3/D47B:    AD7438      LDA $3874               // 選択文字列 ID と一致するか
C3/D47E:    DF8DD4C3    CMP $C3D48D,X           if($3874 == $C3D48D[x])
C3/D482:    F006        BEQ $D48A                   break;
C3/D484:    E8          INX 
C3/D485:    E8          INX 
C3/D486:    E8          INX 
C3/D487:    E8          INX
C3/D488:    80F1        BRA $D47B           }
.label
C3/D48A:    7C8FD4      JMP ($D48F,X)       ■メニュー項目によってジャンプ
@end
.dataarea  map<メニュー項目, 処理アドレス>
// [00-01]: 文字列配列のインデックス
// [02-03]: 処理アドレス
C3/D48D:    AD009DD4  // おいのりをする
C3/D491:    AE008BD5  // おつげをきく
C3/D495:    AF000CD6  // いきかえらせる
C3/D499:    B000B6D6  // どくのちりょう
@end

4.8.1.3. 構造体 $C58E9F - 教会データ構造体

構造体 $C58E9F が教会のデータだ。 データ長が 6 バイトと小さいため、 各メンバの意味を特定するのに ROM 改造を試すのが有効だ。 この構造体の各メンバは、以下の表のとおりだ。

表 4.21 構造体 $C58E9F - 教会データ構造体 メモリレイアウト

Byte:Bit 80 40 20 10 08 04 02 01
00 セリフ種別
01
02 未使用 おいのりフラグ
03 処理アドレス
04
05

セリフ種別

店屋宿屋のデータ構造体の対応するメンバーと同じ役割を果たす。 値の意味は以下のとおり。

表 4.22 セリフ種別

意味
#$01 神父系のセリフ ID 配列のアドレス
#$02 シスター系のセリフ ID 配列のアドレス
#$03 上記のどちらでもない

コードは簡単なので省略する。データの概要だけを以下に示す。 セリフ ID と実際のメッセージについては、 メッセージ解析の成果を参照すること。

.dataarea  教会セリフグループアドレスの配列
C3/D9F8:    FCD9  // セリフグループ 1
C3/D9FB:    32DA  // セリフグループ 2
@end
.dataarea  教会セリフグループ 1
C3/D9FC:    CA18  // 00: [DE]生きとし生けるものは~
C3/D9FE:    E418  // 01: [DE]おお 神よ![AD]この者[B2]に~
C3/DA00:    CB18  // 02: [DE]では 神のまえに[AD]これまでの~
C3/DA02:    CE18  // 03: [DE]なんばんの 冒険の書に[AD]記録するのじゃ?
C3/DA04:    D318  // 04: [DE]たしかに 記録しましたぞ~
C3/DA06:    D418  // 05: [DE]おお神よ![AD]この者[B2]に ひとときの~
C3/DA08:    CD18  // 06: [DE]記録しないと申されるか~
C3/DA0A:    D018  // 07: [DE]まだ 冒険を~
C3/DA0C:    D118  // 08: [DE]なんと 記録せずに~
C3/DA0E:    D218  // 09: [DE]では そなたの冒険が~
C3/DA10:    CC18  // 0A: [DE]そして この冒険の書に~
C3/DA12:    CF18  // 0B: [DE]そうすると [B2]LV[BB]の[AD]記録が~
C3/DA14:    D518  // 0C: [DE]神の声が 聞こえます。[AF][D5]
C3/DA16:    D618  // 0D: [DE][C0]よ。[AD]あと[BB]の経験で~
C3/DA18:    E318  // 0E: [DE]ほかに ご用は おありかな?
C3/DA1A:    D718  // 0F: [DE][C0]よ。[AD]そなたは もう~
C3/DA1C:    D818  // 10: [DE]どなたを 生きかえして~
C3/DA1E:    D918  // 11: [DE]なんと [B3]どのは~
C3/DA20:    E218  // 12: [DE]なんと やめると申されるか。[AF]
C3/DA22:    DF18  // 13: [DE]さすれば わが教会に[AD][BB]ゴールドの~
C3/DA24:    E018  // 14: [DE]なんと 寄付をするには~
C3/DA26:    E118  // 15: [DE]それもまた そなたの意志~
C3/DA28:    DA18  // 16: [DE]おお わが主よ![AD]全知全能の神よ~
C3/DA2A:    DB18  // 17: [DE][B3]は よみがえった![AF][D5]
C3/DA2C:    DC18  // 18: [DE]どなたの毒を~
C3/DA2E:    DE18  // 19: [DE]おお神よ! わが主よ![AD][B3]の身体より~
C3/DA30:    DD18  // 1A: [DE]はて [B3]どのは~
@end
シスター系のセリフ ID 配列も同様に存在する
おいのりフラグ

教会のメニューに「おいのりをする」があるかどうかを示す。 1 のとき、「おいのりをする」がメニューに現れる。

処理アドレス

教会の実装は、前処理をまず行い、 その直後に個々の教会での処理が続く構成になっている。 その「個々の教会での処理」のサブルーチンのアドレスデータだ。 JSL ではなく RTL でここへ飛ぶように「工夫」がされている。

このアドレスは 4 通り存在して、 それぞれの処理の内容は以下の通りだ。

表 4.23 処理アドレス

意味
$C3D3E3 普通の教会処理
$C3D849 アモールの教会が掃除をしている最中
$C3D8C3 下の世界で、パーティが実体化していないとき
$C3D910 マウントスノー初期状態の教会

4.8.2. データ

データの総数が 8 しかないので、ここに直接記述する。

表 4.24 $C58E9F 構造体データ

ID セリフ おいのり 処理アドレス
0000 #$0000 0 $C3D3E3
0001 #$0001 1 $C3D3E3
0002 #$0002 1 $C3D3E3
0003 #$0003 1 $C3D849
0004 #$0003 1 $C3D8C3
0005 #$0003 1 $C3D910
0006 #$0001 0 $C3D3E3
0007 #$0002 0 $C3D3E3

4.8.3. TODO リスト

  • 「おつげをきく」の処理を解読して、各キャラの経験値-レベル対応表をサーチ