3.6. 移動モードメッセージ解析

3.6.1. メッセージデータ格納位置を特定する
3.6.2. ハフマン符号を復号する
3.6.3. ハフマン木の表現
3.6.4. 復号した文字列をメモリに格納
3.6.5. まとめ

本節では、移動モードにおける、大きいフォントを用いて表示されるメッセージの文字列としてのデータを解析する。 実は、というか予想通りというか、移動モードメッセージの抽出の仕組みは、 戦闘モードメッセージのやり方をコピーしたような実装で実現されている。 メッセージデータの抽出ロジックの入口こそ戦闘用と移動用で異なるものの、 ある処理地点から先は、戦闘モードメッセージのプログラムコードと並行して移動モードメッセージのプログラムコードが存在するのがよくわかる。 以下の解説では、戦闘モードメッセージと同じ考えに基づいてプログラムコードが実装されている箇所については説明を省く。 必要に応じて前節に戻り、対応する項目の説明を当たっていただきたい。

3.6.1. メッセージデータ格納位置を特定する

方式は戦闘モードメッセージデータと同じようで、 対応する格納位置特定サブルーチンは $248BAF だ。 プログラムコードは、定数の違いを除けば同一と言える。

3byte 構造体の配列 $24AF1E がまさにそのテーブルであり、 構造体のメモリレイアウトはごく単純で、上位 21bit がバイト単位でのアドレス、 下位 3bit がビット単位でのアドレスをそれぞれ示す。

戦闘モードメッセージの個数調査と同じ理屈により、 移動モードメッセージの個数は、配列 $24AF1E の長さに 16 を乗じた数を超えない。 この配列をダンプしてみると配列長が 0xC8 らしいことがわかるので、 移動モードメッセージの総数は高々 3200 ということになる。

既に戦闘モードメッセージデータ格納位置取得サブルーチンの説明を済ませている今となっては、 似たような別のサブルーチンの説明をすることに意義はない。 故に、サブルーチン $248BAF を簡単に掲載するだけにとどめる。

24/8BAF:    PHP 
24/8BB0:    PHB 
24/8BB1:    REP #$30
24/8BB3:    PHA                 1
24/8BB4:    LSR A
24/8BB5:    LSR A
24/8BB6:    LSR A
24/8BB7:    LSR A
24/8BB8:    STA $0E09
24/8BBB:    ASL A
24/8BBC:    CLC 
24/8BBD:    ADC $0E09
24/8BC0:    TAX                 x = a / 16 * 3  2
24/8BC1:    SEP #$20
24/8BC3:    LDA #$24
24/8BC5:    PHA 
24/8BC6:    PLB 
24/8BC7:    LDA $AF1E,X
24/8BCA:    STA $00
24/8BCC:    LDA $AF1F,X
24/8BCF:    STA $01
24/8BD1:    LDA $AF20,X
24/8BD4:    STA $02             $00 = $24AF1E[x] (3byte)  3
24/8BD6:    JSR $8C8D           ■$F3 = $00 & 07h, $F0 = $00 >> 3 (3byte)
24/8BD9:    REP #$20
24/8BDB:    PLA 
24/8BDC:    AND #$000F          a = メッセージ ID & 0x000F
24/8BDF:    BEQ $8BF9           if(a == 0) return
24/8BE1:    STA $00             $00 = a
                                do{  4
24/8BE3:    JSR $9E02               ■decode
24/8BE6:    CMP #$1001
24/8BE9:    BEQ $8BF5               if(a == 1001h) --$00
24/8BEB:    CMP #$1010
24/8BEE:    BEQ $8BF5               if(a == 1010h) --$00
24/8BF0:    CMP #$1018
24/8BF3:    BNE $8BE3               if(a == 1018h) --$00
24/8BF5:    DEC $00
24/8BF7:    BNE $8BE3           }while($00)

24/8BF9:    PLB 
24/8BFA:    PLP 
24/8BFB:    RTS 

1 2 3

3.6.1 メッセージデータ格納位置を特定する参照。

4

メッセージ ID が 16 の倍数でない場合は、このループで終端文字を ID mod 16 個検出する。 終端文字が #$1001, #$1010, #$1018 であることが窺える。

3.6.2. ハフマン符号を復号する

サブルーチン $249E02 は、移動モードメッセージ一文字分の復号を行う。 戦闘モードメッセージと同様、移動モードメッセージもハフマン符号化されたビット列としてデータ化されている。 ロジックは3.6.2 ハフマン符号を復号するで述べたものと同じで、違いは各種定数だけだ。

24/9E02:    PHP 
24/9E03:    PHB 
24/9E04:    PHK 
24/9E05:    PLB 
24/9E06:    SEP #$20
24/9E08:    REP #$10
24/9E0A:    STZ $F4
24/9E0C:    LDX #$07BA          x = 0x07BA 1
                                for(;;){
24/9E0F:    SEP #$20
24/9E11:    LDA [$F0]               2
24/9E13:    LDY $F3
24/9E15:    AND $9E8C,Y
24/9E18:    REP #$20
24/9E1A:    BEQ $9E21               if(a){ 3
24/9E1C:    LDA $8CB6,X                 a = $248CB6[x]
24/9E1F:    BRA $9E24               }else{
24/9E21:    LDA $9472,X                 a = $249472[x]
                                    }
24/9E24:    PHA 
24/9E25:    INC $F3                 //[[
24/9E27:    INY
24/9E28:    CPY #$0008
24/9E2B:    BCC $9E37
24/9E2D:    STZ $F3
24/9E2F:    INC $F0
24/9E31:    BNE $9E37
24/9E33:    INC $F2
24/9E35:    ROR $F0                 //]] 4
24/9E37:    PLA 
24/9E38:    BMI $9E41               if(a & 0x8000) break
24/9E3A:    AND #$1FFF
24/9E3D:    ASL A
24/9E3E:    TAX                     x = ((a & 0x1FFF) << 1) 5
24/9E3F:    BRA $9E0F           }
24/9E41:    AND #$1FFF          a &= 0x1FFF 6
24/9E44:    PLB 
24/9E45:    PLP 
24/9E46:    RTS

1 2 4

3.6.2 ハフマン符号を復号する参照。

3

そのビットが 0 か 1 かにより、アクセスする子ノードが異なる。 0 側の子ノードは $248CB6[x] で、 1 側の子ノードは $249472[x] だ。

5

ノードの 2byte の上位ビットが立っていれば末端ノードだから、ループを抜け出す。 そうでない場合、0x1FFF でマスクした部分が子ノードの位置を示す。 X レジスタにそれを格納し、ループを繰り返す。

6

末端ノードの値を 0x1FFF でマスクし、これが目的の文字となる。

3.6.3. ハフマン木の表現

移動モードメッセージ文字列のハフマン木の図をここに掲載しようと考えていたが、 画像サイズがブラウザで表示し切れぬほど巨大になることがわかっている。 よって、グラフを作成することなく断念した。

前述のサブルーチンのプログラムコードを観察することにより、 移動モードメッセージのハフマン木のノード構造体のメモリレイアウトがわかる。 ルートからの左右の部分木のノード個数はそれぞれ 0x07BA / 2 + 1 個である それ以外は、木の構造の特徴が戦闘モードのそれ (3.5.3 ハフマン木の表現参照)と同じだ。

表 3.15 メモリレイアウト

Byte:Bit 80 40 20 10 08 04 02 01
00 子ノード or 文字 (L)
01 末端フラグ n/a 子ノード or 文字 (H)

3.6.4. 復号した文字列をメモリに格納

サブルーチン $248B98 では、復号した結果の文字を特定の配列に格納していく。 3.5.4 復号した文字列をメモリに格納の移動モードバージョンだ。 ただし、配列は大きい文字を格納するため 16bit 値を扱う。

24/8B98:    PHP 
24/8B99:    REP #$30            1
24/8B9B:    LDX #$0000
                                for(x = 0; x < #$0080; x += 2){
24/8B9E:    PHX 
24/8B9F:    JSR $9E02               2
24/8BA2:    PLX
24/8BA3:    STA $0E4B,X             3
24/8BA6:    INX 
24/8BA7:    INX
24/8BA8:    CPX #$0080
24/8BAB:    BCC $8B9E           }
24/8BAD:    PLP 
24/8BAE     RTS

1

戦闘モードメッセージでの対応するサブルーチンとは対照的に、 A レジスタを 16bit モードで扱う。

2

一符号ずつ文字に変換するサブルーチン。 前述の3.6.2 ハフマン符号を復号するを参照。

3

その文字は A レジスタに 16bit モードで格納されている。 これを配列 $0E4B に先頭から格納していく。

3.6.5. まとめ

本節で扱ったサブルーチンおよびデータ領域を以下に表としてまとめておく。 いくつかのサブルーチン・データが、戦闘モードメッセージ復号システムでも利用されている (3.5.5 まとめ を参照)。 また、メッセージをテキストファイルとして再現したものを 付録 B データ に置く。

表 3.16 移動モードメッセージ解析

アドレス 分類 役割
$248B98 ルーチン 復号して得た文字を $0E4B,X に先頭から格納していく。
$248BAF ルーチン メッセージ ID に対応する、符号化メッセージデータの厳密なアドレスを取得する。
$248C8D ルーチン 符号化戦闘メッセージデータのアドレス情報構造体オブジェクトを分析する。
$248CB6 データ ハフマン木のノードを表現する配列。ビット 1 側。
$249472 データ ハフマン木のノードを表現する配列。ビット 0 側。
$249E02 ルーチン 復号ルーチン。可変長符号を抽出しながら、その符号に対応する文字を得る。
$249E8C データ 符号を 1 ビット分抽出するために用いる、1 バイト値マスク配列。
$24AF1E データ 符号化戦闘メッセージデータのアドレス情報構造体配列。3byte * #$C8