基礎知識
戦闘関係
先に背景グラフィックと効果に目を通していただきたい。
背景(BG)関係の設定はI/Oレジスタで設定をすることになる。
本作の場合、BGMode1(背景を3枚使う通常状態)と、ゲーム開始時のロゴ表示及びSF編キャプテンスクウェア開始時で使うBGMode7(回転縮小が使えるモード)で背景関係の設定が大きく変わる。
BGMode1の時の初期値設定は以下のサブルーチンで、Mode7だと$C0/0EDF~$C0/0F7Cで設定するが、ここではゲームプレイの大半を占めるMode1を中心として説明をしていく。
フィールドがBGMode1の時について大まかにまとめると、だいたい以下のようになる。
| 背景 | 背景サイズ (横×縦、タイル数) | VRAMアドレス(単位byte) | |
|---|---|---|---|
| タイルデータ | BGマップデータ | ||
| BG1 | 64×32 | $0000~$5FFF | $8000~$8FFF |
| BG2 | 64×32 | $0000~$5FFF | $A000~$AFFF |
| BG3 | 32×32 | $6000~$6FFF(吹き出しや枠)$7000~$7FFF(文字) | $9000~$9FFF |
$C000~$FFFFはスプライト(OBJ)の画像データ以下ではサブルーチンを説明していく。
以下がグラフィックのI/Oレジスタ関係初期設定になる。
;シナリオ開始時、またはセーブデータから再開時 $C0/0DF6 LDA #$48 ;Aに$48をロード $C0/0DF8 STA $2109 [$00:2109] ;Aを[$00:2109]に書き込み BG3タイルマップアドレスとサイズ $C0/0DFB LDA #$00 ;Aに$00をロード $C0/0DFD STA $210A [$00:210A] ;Aを[$00:210A]に書き込み BG4タイルマップアドレスとサイズ $C0/0E00 LDA #$00 ;Aに$00をロード $C0/0E02 STA $210B [$00:210B] ;Aを[$00:210B]に書き込み BG1,BG2タイルデータ領域設定 $C0/0E05 LDA #$03 ;Aに$03をロード $C0/0E07 STA $210C [$00:210C] ;Aを[$00:210C]に書き込み BG3,BG4タイルデータ領域設定 $C0/0E0A LDA #$80 ;Aに$80をロード $C0/0E0C STA $2115 [$00:2115] ;Aを[$00:2115]に書き込み ビデオポート調整 $C0/0E0F LDA #$00 ;Aに$00をロード $C0/0E11 STA $2133 [$00:2133] ;Aを[$00:2133]に書き込み スクリーンモード/ビデオ設定 $C0/0E14 LDA $014F [$00:014F] ;Aに[$00:014F]をロード $C0/0E17 STA $420C [$00:420C] ;Aを[$00:420C]に書き込み HDMA有効 ; ;マップ切り替え時はここから開始 $C0/0E1A LDA #$09 ;Aに$09をロード $C0/0E1C STA $2105 [$00:2105] ;Aを[$00:2105]に書き込み BGモード・キャラクタサイズ設定 $C0/0E1F STZ $2106 [$00:2106] ;[$00:2106]に$00を書き込み モザイク表示用サイズ・スクリーン設定 $C0/0E22 STZ $2111 [$00:2111] ;[$00:2111]に$00を書き込み BG3水平スクロール量 $C0/0E25 STZ $2111 [$00:2111] ;[$00:2111]に$00を書き込み $C0/0E28 LDA #$FF ;Aに$FFをロード $C0/0E2A STA $2112 [$00:2112] ;Aを[$00:2112]に書き込み BG3垂直スクロール量 $C0/0E2D STA $2112 [$00:2112] ;Aを[$00:2112]に書き込み $C0/0E30 LDA $0145 [$00:0145] ;Aに[$00:0145]をロード $C0/0E33 STA $2123 [$00:2123] ;Aを[$00:2123]に書き込み BG1,BG2ウィンドウマスク設定 $C0/0E36 LDA $0146 [$00:0146] ;Aに[$00:0146]をロード $C0/0E39 STA $2124 [$00:2124] ;Aを[$00:2124]に書き込み BG3,BG4ウィンドウマスク設定 $C0/0E3C LDA $0147 [$00:0147] ;Aに[$00:0147]をロード $C0/0E3F STA $2125 [$00:2125] ;Aを[$00:2125]に書き込み スプライトウィンドウマスク設定 $C0/0E42 STZ $2126 [$00:2126] ;[$00:2126]に$00を書き込み ウィンドウ1左座標設定 $C0/0E45 STZ $2127 [$00:2127] ;[$00:2127]に$00を書き込み ウィンドウ1右座標設定 $C0/0E48 STZ $2128 [$00:2128] ;[$00:2128]に$00を書き込み ウィンドウ2左座標設定 $C0/0E4B STZ $2129 [$00:2129] ;[$00:2129]に$00を書き込み ウィンドウ2右座標設定 $C0/0E4E LDA $0148 [$00:0148] ;Aに[$00:0148]をロード $C0/0E51 STA $212A [$00:212A] ;Aを[$00:212A]に書き込み BGウインドウマスクロジック設定 $C0/0E54 LDA $0149 [$00:0149] ;Aに[$00:0149]をロード $C0/0E57 STA $212B [$00:212B] ;Aを[$00:212B]に書き込み スプライトウインドウマスクロジック設定 $C0/0E5A LDA $0142 [$00:0142] ;Aに[$00:0142]をロード $C0/0E5D STA $212E [$00:212E] ;Aを[$00:212E]に書き込み メインスクリーンウインドウマスク指定 $C0/0E60 LDA $0143 [$00:0143] ;Aに[$00:0143]をロード $C0/0E63 STA $212F [$00:212F] ;Aを[$00:212F]に書き込み サブスクリーンウインドウマスク指定 $C0/0E66 LDA $0A48 [$00:0A48] ;Aに[$00:0A48]をロード $C0/0E69 BNE $1D [$0E88] ;ゼロフラグが立っていないとき[$0E88]分岐 ;ゼロフラグON $C0/0E6B LDA $0140 [$00:0140] ;Aに[$00:0140]をロード $C0/0E6E STA $212C [$00:212C] ;Aを[$00:212C]に書き込み メインスクリーン指定 $C0/0E71 LDA $0141 [$00:0141] ;Aに[$00:0141]をロード $C0/0E74 STA $212D [$00:212D] ;Aを[$00:212D]に書き込み サブスクリーン指定 $C0/0E77 LDA $0A04 [$00:0A04] ;Aに[$00:0A04]をロード $C0/0E7A BNE $3D [$0EB9] ;ゼロフラグが立っていないとき[$0EB9]分岐 ;ゼロフラグON $C0/0E7C LDA $0144 [$00:0144] ;Aに[$00:0144]をロード $C0/0E7F STA $2131 [$00:2131] ;Aを[$00:2131]に書き込み 色計算指定 $C0/0E82 BNE $1D [$0EA1] ;ゼロフラグが立っていないとき[$0EA1]分岐 ;ゼロフラグON $C0/0E84 LDA #$30 ;Aに$30をロード $C0/0E86 BRA $1B [$0EA3] ;フラグにかかわりなく常に分岐[$0EA3] $C0/0EA3 STA $2130 [$00:2130] ;Aを[$00:2130]に書き込み 色追加選択 $C0/0EA6 LDA $0240 [$00:0240] ;Aに[$00:0240]をロード $C0/0EA9 BNE $07 [$0EB2] ;ゼロフラグが立っていないとき[$0EB2]分岐 ;ゼロフラグON $C0/0EAB LDA #$E0 ;Aに$E0をロード $C0/0EAD STA $2132 [$00:2132] ;Aを[$00:2132]に書き込み 固定色のデータ $C0/0EB0 BRA $25 [$0ED7] ;フラグにかかわりなく常に分岐[$0ED7] $C0/0ED7 RTS ;サブルーチン戻り
シナリオ開始時、またはセーブデータから再開時は$C0/0DF6から、プレイ中にマップ切り替えなどを行った場合は途中の$C0/0E1Aから、背景(BG)関係のI/Oレジスタ初期設定が行われる。
$C0/0E69以降は、エリアなどで決まる[$00:0A??]~などの数値で決まるがここでは詳細を省略する。
上はすべての分岐でゼロフラグが立った場合。大抵の場合が当てはまる。
なお、$C0/0E77で呼び出される[$00:0A04]は、SF編はシナリオ開始時に$83が書き込まれて固定、他シナリオでは$00のようである(要確認)。
[$00:0A04]は[$00:2131]の初期値に関わってくるが、その話は固定色処理で説明している。
$00:21??というアドレスはすべてグラフィック関連のI/Oレジスタアドレスである。
| アドレス | 名称 | 内容 | 値 |
|---|---|---|---|
[$00:2109] | BG3SC | BG3のBGマップ設定 | $48 |
[$00:210A] | BG4SC | BG4のBGマップ設定 | $00 |
[$00:210B] | BG12NBA | BG1,BG2キャラクタデータ領域設定 | $00 |
[$00:210C] | BG34NBA | BG3,BG4キャラクタデータ領域設定 | $03 |
[$00:2115] | VMAINC | ビデオポート調整 | $80 |
[$00:2133] | SETINI | スクリーンモード/ビデオ設定 | $00 |
[$00:2105] | BGMODE | BG制御レジスタ(BGMode設定) | $09 |
[$00:2106] | MOSAIC | モザイク表示用サイズ・スクリーン設定 | $00 |
[$00:2111] | BG3HOFS | BG3水平スクロール量 | $00 |
[$00:2112] | BG3VOFS | BG3垂直スクロール量 | $FF |
[$00:2123] | W12SEL | BG1,BG2ウィンドウマスク設定 | $00 |
[$00:2124] | W34SEL | BG3,BG4ウィンドウマスク設定 | $00 |
[$00:2125] | WOBJSEL | スプライトウィンドウマスク設定 | $00 |
[$00:2126] | WH0 | ウィンドウ1左座標設定 | $00 |
[$00:2127] | WH1 | ウィンドウ1右座標設定 | $00 |
[$00:2128] | WH2 | ウィンドウ2左座標設定 | $00 |
[$00:2129] | WH3 | ウィンドウ2右座標設定 | $00 |
[$00:212A] | WBGLOG | BGウインドウマスクロジック設定 | $00 |
[$00:212B] | WOBJLOG | スプライトウインドウマスクロジック設定 | $00 |
[$00:212E] | TMW | メインスクリーンウインドウマスク指定 | $00 |
[$00:212F] | TSW | サブスクリーンウインドウマスク指定 | $00 |
[$00:212C] | TM | メインスクリーン指定 | $13 |
[$00:212D] | TS | サブスクリーン指定 | $00 |
[$00:2131] | CGADSUB | カラーマス制御レジスタB 色計算指定 | $00 |
[$00:2130] | CGSWSEL | カラーマス制御レジスタA 色追加選択 | $30 |
[$00:2132] | COLDATA | サブスクリーン固定色のデータ | $E0 |
グラフィック(主に背景関係)だけでもこれだけの初期設定がある。
ここでは重要な部分の説明にとどめ、他は必要な時に説明していくこととする。
[$00:2105][$00:2109][$00:210B][$00:210C]は、背景グラフィックと効果 > 背景についてで説明したので、ここでは詳細を省く。
上サブルーチンで、シナリオ開始時やセーブデータからの再開時に、BG3のBGマップ設定[$00:2109]や、BG1~BG4タイルデータ領域設定[$00:210B]~[$00:210C]は共通して決まる、ということがわかる。
BG3のBGマップ設定から、BG3の背景サイズ(横×縦)は64×32、VRAM内におけるBG3のデータ開始アドレスは$4000。
BG1~BG4タイルデータ領域設定から、
である。
$C0/0E1A~から先がマップ切り替え毎に設定しなおされる数値であるが、本作のフィールドでは大半が上のように[$00:2105]が$09で指定される。
つまり、BGモードはMode1、BG3優先度は1(高)、BG1~BG4タイルサイズは8×8ピクセル、というのが基本の設定である。
BGモードがMode1なら、BG1~BG3の3枚の背景を使うことが可能で、使用可能な色数はBG毎に異なり、
となる。
背景の重ね順は、手前からBG1→BG2→BG3だが、先にBG3優先度を1に設定したので、BG3→BG1→BG2である。
さらに、ほとんどの場合で、BG2をBG1より上に設定しており(これはタイル毎に設定できる)、結果としてBG3→BG2→BG1という順で重ねることがほとんどである。
また、キャラのスプライトはBG3→BG2→スプライト→BG1と、BG2とBG1の間に挟まる。
これにより、BG2に建物の屋根や壁を置いてキャラをその後ろに設置する、といったことが可能となる。
また、セリフ・テキストウィンドウはすべての背景及びスプライトに優先して手前に置かれるということになる。
[$00:212C]・[$00:212D]はメインスクリーンとサブスクリーン指定用レジスタである。
スーパーファミコンには、メインスクリーンとサブスクリーンという2つの仮想的な画面があって、実際のゲーム画面はメインスクリーンとサブスクリーンを重ねて描画する。
BG1~4及び、OBJ(スプライトのこと)をどちらのスクリーンに表示するかを設定するのが[$00:212C]・[$00:212D]である。
上サブルーチンを見ると、$C0/0E66~から[$00:212C]・[$00:212D]の指定を行うのだが、その前に[$00:0A48]の値によるゼロフラグ分岐がある。
$C0/0E66 LDA $0A48 [$00:0A48] ;Aに[$00:0A48]をロード $C0/0E69 BNE $1D [$0E88] ;ゼロフラグが立っていないとき[$0E88]分岐 ;ゼロフラグON $C0/0E6B LDA $0140 [$00:0140] ;Aに[$00:0140]をロード $C0/0E6E STA $212C [$00:212C] ;Aを[$00:212C]に書き込み メインスクリーン指定 $C0/0E71 LDA $0141 [$00:0141] ;Aに[$00:0141]をロード $C0/0E74 STA $212D [$00:212D] ;Aを[$00:212D]に書き込み サブスクリーン指定 ;ゼロフラグOFF $C0/0E88 STA $212C [$00:212C] ;Aを[$00:212C]に書き込み $C0/0E8B LDA $0A49 [$00:0A49] ;Aに[$00:0A49]をロード $C0/0E8E STA $212D [$00:212D] ;Aを[$00:212D]に書き込み $C0/0E91 LDA $0A4A [$00:0A4A] ;Aに[$00:0A4A]をロード $C0/0E94 STA $2131 [$00:2131] ;Aを[$00:2131]に書き込み $C0/0E97 LDA #$02 ;Aに$02をロード $C0/0E99 STA $2130 [$00:2130] ;Aを[$00:2130]に書き込み
[$00:0A48]の値によって、どの値を書き込むか分岐することになる。
| アドレス | 内容 | 書き込む値(アドレス) | |
|---|---|---|---|
[$00:0A48]が0 | [$00:0A48]が0以外 | ||
[$00:212C] | メインスクリーン指定 | [$00:0140] | [$00:0A48] |
[$00:212D] | サブスクリーン指定 | [$00:0141] | [$00:0A49] |
ちなみに、大半の場合で[$00:0A48]は$00であり、ゼロフラグ分岐に進む。
その場合は[$00:0140][$00:0141]がそれぞれ[$00:212C][$00:212D]に書き込まれるが、大抵の場合で[$00:0140] = $13(%0001 0011), [$00:0141] = $00である。
[$00:212C]・[$00:212D]どちらも共通設定で、
| Bit | 内容 |
|---|---|
| Bit0 | BG1 (0: 無効, 1: 有効) |
| Bit1 | BG2 (0: 無効, 1: 有効) |
| Bit2 | BG3 (0: 無効, 1: 有効) |
| Bit3 | BG4 (0: 無効, 1: 有効) |
| Bit4 | OBJ(スプライト) (0: 無効, 1: 有効) |
であり、メインスクリーン指定の[$00:212C]に$13(%0001 0011)が書き込まれるということは、
| Bit | 内容 |
|---|---|
| Bit0 | BG1は1: 有効 |
| Bit1 | BG2は1: 有効 |
| Bit2 | BG3は0: 無効 |
| Bit3 | BG4は0: 無効 |
| Bit4 | OBJは1: 有効 |
であり、サブスクリーンには何も指定しない、ということを意味している。
マップ切り替え直後はBG3を表示しない、ということになるが、BG3はセリフウィンドウなどである。マップ切り替え直後にセリフが表示される場面でない限り、上の設定で問題ないし、仮に有効にしていたら、BG3に入っている直前のセリフウィンドウが表示されてしまうことになる、という意味でもある。
$C0/0E7A以降はカラーマス、つまりカラーパレットで指定した色にさらに色を加算または減算するか、といった設定である。
マップ切り替え時にカラーマスを使わない場合は、$C0/0E7A以降の分岐で常にゼロフラグが立つはずである。
その場合、
| アドレス | 名称 | 内容 | 値 |
|---|---|---|---|
[$00:2130] | CGSWSEL | カラーマス制御レジスタA 色追加選択 | $30(%0011 0000) |
[$00:2131] | CGADSUB | カラーマス制御レジスタB 色計算指定 | $00 |
[$00:2132] | COLDATA | サブスクリーン固定色のデータ | $E0(%1110 0000) |
と値が入る。
カラーマスを使わないのに値が入るレジスタ[$00:2130]があるが、
| Bit | 内容 | 値 |
|---|---|---|
| Bit0 | 256色のBG用 ダイレクトカラーモード | %0=パレットを使う %1=ダイレクトカラー |
| Bit1 | 固定色の変わりに サブスクリーン追加 | %0=未使用 %1=使用 |
| Bit2~3 | 不使用 | - |
| Bit4~5 | カラーマス有効化 | %00=常に使用 %01=ウインドウの外側の色のみ %10=ウインドウの内側の色のみ %11=使用しない |
| Bit6~7 | 計算前の黒に クリッピングする色 | %11=常に使用 %10=ウインドウの内側の色のみ %01=ウインドウの外側の色のみ %00=なし |
[$00:2130]のBit4~5に入る値が、カラーマス有効化するかどうかであるため、[$00:2130]に%0011 0000を書き込むことで「カラーマスを有効化しない」になるのである。
もうひとつ、$E0が入る[$00:2132]はサブスクリーンの特定の色の輝度を変更する設定で、そもそもサブスクリーンを使わないマップでは影響しない。
サブスクリーンを活用して輝度を変えるのは、最終編の時のダンジョンで、マップ(背景)だけ徐々に暗くしていく演出などで使われているようである。
(画面全体の輝度を変更するのなら$00:2100(ディスプレイ制御レジスタ)で可能)
| Bit | 内容 |
|---|---|
| Bit7 | 青に輝度設定 (0=設定しない, 1=設定する) |
| Bit6 | 緑に輝度設定 (0=設定しない, 1=設定する) |
| Bit5 | 赤に輝度設定 (0=設定しない, 1=設定する) |
| Bit4~0 | 輝度(%00000~%11111, つまり0~31) |
実際、最終編の時のダンジョンだと、鐘が鳴った時に$C0/0E66~からの処理を行って、
$C0/0E66 LDA $0A48 [$00:0A48] ;Aに[$00:0A48]をロード $C0/0E69 BNE $1D [$0E88] ;ゼロフラグが立っていないとき[$0E88]分岐 ;ゼロフラグON $C0/0E6B LDA $0140 [$00:0140] ;Aに[$00:0140]をロード $C0/0E6E STA $212C [$00:212C] ;Aを[$00:212C]に書き込み $C0/0E71 LDA $0141 [$00:0141] ;Aに[$00:0141]をロード $C0/0E74 STA $212D [$00:212D] ;Aを[$00:212D]に書き込み $C0/0E77 LDA $0A04 [$00:0A04] ;Aに[$00:0A04]をロード $C0/0E7A BNE $3D [$0EB9] ;ゼロフラグが立っていないとき[$0EB9]分岐 ;ゼロフラグOFF $C0/0EB9 STA $2131 [$00:2131] ;Aを[$00:2131]に書き込み $C0/0EBC STZ $2130 [$00:2130] ;[$00:2130]に$00を書き込み $C0/0EBF LDA $0A05 [$00:0A05] ;Aに[$00:0A05]をロード $C0/0EC2 ORA #$80 ;Aと$80で論理和 $C0/0EC4 STA $2132 [$00:2132] ;Aを[$00:2132]に書き込み $C0/0EC7 LDA $0A06 [$00:0A06] ;Aに[$00:0A06]をロード $C0/0ECA ORA #$40 ;Aと$40で論理和 $C0/0ECC STA $2132 [$00:2132] ;Aを[$00:2132]に書き込み $C0/0ECF LDA $0A07 [$00:0A07] ;Aに[$00:0A07]をロード $C0/0ED2 ORA #$20 ;Aと$20で論理和 $C0/0ED4 STA $2132 [$00:2132] ;Aを[$00:2132]に書き込み $C0/0ED7 RTS ;サブルーチン戻り
というように、[$00:2132]に値を加算していく。
(おそらくだが、$C0/0EB9以降は実質、時のダンジョン用処理と思われる。未確認だが、原始編の洞窟地下などでも使われているかもしれない)
ちなみに[$00:0A05]~[$00:0A07]は、時のダンジョンの鐘の鳴った回数($00:014A~$00:014Cのコピー)に対応している。
鐘の回数に従い1ずつ値が増えていくのではなく、以下のようにやや変則的な増え方をしているのは、輝度計算のためだった、ということがわかる。
| 鐘回数 | $00:014A | $00:014B | $00:014C |
|---|---|---|---|
| 0回 | $0F | $1F | $0F |
| 1回 | $02 | $02 | $02 |
| 2回 | $04 | $04 | $04 |
| 3回 | $06 | $06 | $06 |
| 4回 | $08 | $08 | $08 |
| 5回 | $0B | $0B | $0B |
| 6回 | $0F | $0F | $0F |
| 7回 | $14 | $14 | $14 |
| 8回 | $1A | $1A | $1A |
8×8マスのタイルの中のどれをどのように並べるかを指定するBGマップ関係の初期設定用サブルーチンは以下から。
$C0/0FB1 LDA $0114 [$00:0114] ;Aに[$00:0114]をロード $C0/0FB4 BEQ $13 [$0FC9] ;ゼロフラグが立っているとき[$0FC9]分岐 ;ゼロフラグOFF $C0/0FB6 LDA #$03 ;Aに$03をロード $C0/0FB8 SEC ;キャリーフラグON $C0/0FB9 SBC $0114 [$00:0114] ;A - [$00:0114] $C0/0FBC STA $0134 [$00:0134] ;Aを[$00:0134]に書き込み $C0/0FBF LDA $0117 [$00:0117] ;Aに[$00:0117]をロード $C0/0FC2 BNE $20 [$0FE4] ;ゼロフラグが立っていないとき[$0FE4]分岐 $C0/0FC4 LDA $0134 [$00:0134] ;Aに[$00:0134]をロード $C0/0FC7 BRA $29 [$0FF2] ;フラグにかかわりなく常に分岐[$0FF2] ;$C0/0FB4でゼロフラグON $C0/0FC9 LDA #$01 ;Aに$01をロード $C0/0FCB STA $0134 [$00:0134] ;Aを[$00:0134]に書き込み $C0/0FCE LDA $0117 [$00:0117] ;Aに[$00:0117]をロード $C0/0FD1 BNE $11 [$0FE4] ;ゼロフラグが立っていないとき[$0FE4]分岐 $C0/0FD3 LDA $0116 [$00:0116] ;Aに[$00:0116]をロード $C0/0FD6 BEQ $18 [$0FF0] ;ゼロフラグが立っているとき[$0FF0]分岐 ;ゼロフラグOFF $C0/0FD8 CMP #$01 ;Aと$01を減算比較(ステータスレジスタ変更のみ) $C0/0FDA BEQ $10 [$0FEC] ;ゼロフラグが立っているとき[$0FEC]分岐 $C0/0FDC CMP #$02 ;Aと$02を減算比較(ステータスレジスタ変更のみ) $C0/0FDE BEQ $08 [$0FE8] ;ゼロフラグが立っているとき[$0FE8]分岐 $C0/0FE0 LDA #$03 ;Aに$03をロード $C0/0FE2 BRA $0E [$0FF2] ;フラグにかかわりなく常に分岐[$0FF2] $C0/0FE4 LDA #$00 ;Aに$00をロード $C0/0FE6 BRA $0A [$0FF2] ;フラグにかかわりなく常に分岐[$0FF2] $C0/0FE8 LDA #$01 ;Aに$01をロード $C0/0FEA BRA $06 [$0FF2] ;フラグにかかわりなく常に分岐[$0FF2] $C0/0FEC LDA #$02 ;Aに$02をロード $C0/0FEE BRA $02 [$0FF2] ;フラグにかかわりなく常に分岐[$0FF2] ;$C0/0FD6でゼロフラグON $C0/0FF0 LDA #$01 ;Aに$01をロード $C0/0FF2 STA $0135 [$00:0135] ;Aを[$00:0135]に書き込み $C0/0FF5 LDA #$40 ;Aに$40をロード $C0/0FF7 CLC ;キャリーフラグクリア $C0/0FF8 ADC $0134 [$00:0134] ;A + [$00:0134]($01) $C0/0FFB STA $2107 [$00:2107] ;Aを[$00:2107]に書き込み $C0/0FFE LDA #$50 ;Aに$50をロード $C0/1000 CLC ;キャリーフラグクリア $C0/1001 ADC $0135 [$00:0135] ;A + [$00:0135]($01) $C0/1004 STA $2108 [$00:2108] ;Aを[$00:2108]に書き込み $C0/1007 RTS ;サブルーチン戻り
シナリオ開始時またはセーブデータから開始時に、[$00:2109](BG3のBGマップ設定)はほぼ固定で決まる、ということが先のサブルーチンでわかったが、BG1のBGマップ設定[$00:2107]と、BG2のBGマップ設定[$00:2108]は上で決まる。
マップによりBGマップ設定は変わってくるが、一部イベントシーンや多重スクロールがあるマップなど以外では、だいたい上のサブルーチンにより、$C0/0FB4でゼロフラグON、$C0/0FD6でゼロフラグONとなるため、[$00:2107]に$41、[$00:2108]に$51が書き込まれる。
上の処理をもう少し詳しく見ると、結果的に[$00:0114]がBG1のサイズ、[$00:0116]がBG2のサイズ決定に関わっていることがわかるが詳細は省略。
[$00:0116]の値は多重スクロールのマップかどうかの判定値でもある。詳細はスクロールを参照のこと。
| 背景 | アドレス | 値 | 背景サイズ | VRAM内の データ開始アドレス |
|---|---|---|---|---|
| BG1 | [$00:2107] | $41(%0100 0001) | 64×32 | $8000 |
| BG2 | [$00:2108] | $51(%0101 0001) | 64×32 | $A000 |
以上がフィールドにおける基本である。
先の[$00:2109]に書き込まれた値$48も加えて、
| 背景 | アドレス | 値 | 背景サイズ | VRAM内の データ開始アドレス |
|---|---|---|---|---|
| BG1 | [$00:2107] | $41(%0100 0001) | 64×32 | $8000 |
| BG2 | [$00:2108] | $51(%0101 0001) | 64×32 | $A000 |
| BG3 | [$00:2109] | $48(%0100 1000) | 32×32 | $9000 |
これが、ライブ・ア・ライブにおけるフィールドでの背景3枚(BG1~BG3)の基本設定、と見て問題ない。
例外としては、たとえばSF編のオープニングの中で、地球を背景に文字が表示される場面では、[$00:2107]に$42、[$00:2108]に$01が書き込まれる。
この場合変更されるのは背景サイズで、VRAM内のデータ開始アドレスは変わらない。
さらに、[$00:210B][$00:210C]の設定、
これと合わせて考えると、フィールドでは、
スプライトの処理同様、VRAMへデータをGDMA転送をしているとしたら、VRAMアドレスの指定で何のデータを送っているかわかるはずだ。
ただし、VRAMアドレスの指定は、バイト(byte)ではなくワード(word)単位であることに注意。
ワード単位としたら上の値を半分にしなければならない。
書き換えると、
である。
また、マップに出たタイミングなど、セリフやテキストウィンドウが出ない、つまりBG3を使わないタイミングでは、BG1とBG2の転送しかしないはずである。
後で説明するが、BG3については、シナリオ開始時やセーブデータから開始した時点で、セリフウィンドウ枠などの画像データを予め転送しておき、セリフなどのテキストのみ、セリフ表示の時に転送する、という方法を使っている。
ということで該当箇所を探してみると、まず、以下の処理が見つかる。
以下の処理を見ると[$00:2117][$00:2116]のVRAMアドレスコピー先が[$00:016D][$00:016C]の値で決まるのだが、この値は計算上$4000以上で(後で説明する)、キャラ位置・向きによる画面内の背景表示に関する数値になっている、と思われる(詳細不明)。
結果としてVRAMアドレス$4000word ($8000byte)以降にコピーされる値になる。
以下、[$00:016D][$00:016C]が$4000としてのアドレス計算。
$C0/5812 LDA $0114 [$00:0114] ;Aに[$00:0114]をロード $C0/5815 BEQ $03 [$581A] ;ゼロフラグが立っているとき[$581A]分岐 $C0/581A LDX $016C [$00:016C] ;Xに[$00:016D][$00:016C]($4000)をロード $C0/581D STX $30 [$00:0030] ;Xを[$00:0031][$00:0030]($4000)に書き込み $C0/581F LDA #$01 ;Aに$01をロード $C0/5821 STA $4300 [$00:4300] ;Aを[$00:4300]に書き込み $C0/5824 LDA #$18 ;Aに$18をロード $C0/5826 STA $4301 [$00:4301] ;Aを[$00:4301]に書き込み $C0/5829 LDX #$3A00 ;Xに$3A00をロード $C0/582C STX $4302 [$00:4302] ;Xを[$00:4303][$00:4302]に書き込み $C0/582F LDA #$7F ;Aに$7Fをロード $C0/5831 STA $4304 [$00:4304] ;Aを[$00:4304]に書き込み $C0/5834 LDA $0116 [$00:0116] ;Aに[$00:0116]をロード $C0/5837 ORA $0117 [$00:0117] ;Aと[$00:0117]で論理和 $C0/583A BNE $05 [$5841] ;ゼロフラグが立っていないとき[$5841]分岐 $C0/583C LDY #$0002 ;Yに$0002をロード $C0/583F BRA $03 [$5844] ;フラグにかかわりなく常に分岐[$5844] $C0/5844 REP #$20 ;Aを16bit幅に変更、Mフラグをクリア $C0/5846 LDA $30 [$00:0030] ;Aに[$00:0031][$00:0030]をロード $C0/5848 CLC ;キャリーフラグクリア $C0/5849 ADC #$0020 ;A + $0020 $C0/584C STA $32 [$00:0032] ;A($4020)を[$00:0033][$00:0032]に書き込み $C0/584E CLC ;キャリーフラグクリア $C0/584F ADC #$03E0 ;A + $03E0 $C0/5852 STA $34 [$00:0034] ;A($4400)を[$00:0035][$00:0034]に書き込み $C0/5854 CLC ;キャリーフラグクリア $C0/5855 ADC #$0020 ;A + $0020 $C0/5858 STA $36 [$00:0036] ;A($4420)を[$00:0037][$00:0036]に書き込み $C0/585A SEP #$20 ;MフラグON Aレジスタは8bit幅 $C0/585C LDX #$0040 ;Xに$0040をロード $C0/585F STX $4305 [$00:4305] ;Xを[$00:4306][$00:4305]に書き込み $C0/5862 LDX $30 [$00:0030] ;Xに[$00:0031][$00:0030]をロード $C0/5864 STX $2116 [$00:2116] ;Xを[$00:2117][$00:2116]に書き込み $C0/5867 LDA #$01 ;Aに$01をロード $C0/5869 STA $420B [$00:420B] ;Aを[$00:420B]に書き込み ; ;[$00:2117][$00:2116] VRAMアドレス ※word単位 $4000 ;[$00:4300] GDMA / HDMA設定レジスタ $01 ;[$00:4301] 転送先指定 $18=VRAM ;[$00:4303][$00:4302] データ元アドレス(開始位置) $3A00 ;[$00:4304] データ元バンク $7F ;[$00:4306][$00:4305] 転送するデータ量 $0040 ;$7F:3A00 -> VRAM $4000word($8000byte) +$0040byte ; $C0/586C LDX #$0040 ;Xに$0040をロード $C0/586F STX $4305 [$00:4305] ;Xを[$00:4306][$00:4305]に書き込み $C0/5872 LDX $34 [$00:0034] ;Xに[$00:0035][$00:0034]($4400)をロード $C0/5874 STX $2116 [$00:2116] ;Xを[$00:2117][$00:2116]に書き込み $C0/5877 LDA #$01 ;Aに$01をロード $C0/5879 STA $420B [$00:420B] ;Aを[$00:420B]に書き込み ; ;[$00:2117][$00:2116] VRAMアドレス ※word単位 $4400 ;[$00:4300] GDMA / HDMA設定レジスタ $01 ;[$00:4301] 転送先指定 $18=VRAM ;[$00:4303][$00:4302] データ元アドレス(開始位置) $3A00+40 ;[$00:4304] データ元バンク $7F ;[$00:4306][$00:4305] 転送するデータ量 $0040 ;$7F:3A40 -> VRAM $4400word($8800byte) +$0040byte ; $C0/587C LDX #$0040 ;Xに$0040をロード $C0/587F STX $4305 [$00:4305] ;Xを[$00:4306][$00:4305]に書き込み $C0/5882 LDX $32 [$00:0032] ;Xに[$00:0033][$00:0032]($4020)をロード $C0/5884 STX $2116 [$00:2116] ;Xを[$00:2117][$00:2116]に書き込み $C0/5887 LDA #$01 ;Aに$01をロード $C0/5889 STA $420B [$00:420B] ;Aを[$00:420B]に書き込み ; ;[$00:2117][$00:2116] VRAMアドレス ※word単位 $4020 ;[$00:4300] GDMA / HDMA設定レジスタ $01 ;[$00:4301] 転送先指定 $18=VRAM ;[$00:4303][$00:4302] データ元アドレス(開始位置) $3A00+40+40 ;[$00:4304] データ元バンク $7F ;[$00:4306][$00:4305] 転送するデータ量 $0040 ;$7F:3A80 -> VRAM $4020word($8040byte) +$0040byte ; $C0/588C LDX #$0040 ;Xに$0040をロード $C0/588F STX $4305 [$00:4305] ;Xを[$00:4306][$00:4305]に書き込み $C0/5892 LDX $36 [$00:0036] ;Xに[$00:0037][$00:0036]($4420)をロード $C0/5894 STX $2116 [$00:2116] ;Xを[$00:2117][$00:2116]に書き込み $C0/5897 LDA #$01 ;Aに$01をロード $C0/5899 STA $420B [$00:420B] ;Aを[$00:420B]に書き込み ; ;[$00:2117][$00:2116] VRAMアドレス ※word単位 $4420 ;[$00:4300] GDMA / HDMA設定レジスタ $01 ;[$00:4301] 転送先指定 $18=VRAM ;[$00:4303][$00:4302] データ元アドレス(開始位置) $3A00+40+40+40 ;[$00:4304] データ元バンク $7F ;[$00:4306][$00:4305] 転送するデータ量 $0040 ;$7F:3AC0 -> VRAM $4420word($8840byte) +$0040byte ; $C0/589C REP #$20 ;Aを16bit幅に変更、Mフラグをクリア $C0/589E LDA $30 [$00:0030] ;Aに[$00:0031][$00:0030]($4000)をロード $C0/58A0 CLC ;キャリーフラグクリア $C0/58A1 ADC #$1000 ;A + $1000 $C0/58A4 STA $30 [$00:0030] ;A($5000)を[$00:0031][$00:0030]に書き込み $C0/58A6 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C0/58A8 DEY ;Yをデクリメント -1 $C0/58A9 BNE $99 [$5844] ;ゼロフラグが立っていないとき[$5844]分岐 $C0/5844 REP #$20 ;Aを16bit幅に変更、Mフラグをクリア $C0/5846 LDA $30 [$00:0030] ;A($5000)に[$00:0031][$00:0030]をロード $C0/5848 CLC ;キャリーフラグクリア $C0/5849 ADC #$0020 ;A + $0020 $C0/584C STA $32 [$00:0032] ;A($5020)を[$00:0033][$00:0032]に書き込み $C0/584E CLC ;キャリーフラグクリア $C0/584F ADC #$03E0 ;A + $03E0 $C0/5852 STA $34 [$00:0034] ;A($5400)を[$00:0035][$00:0034]に書き込み $C0/5854 CLC ;キャリーフラグクリア $C0/5855 ADC #$0020 ;A + $0020 $C0/5858 STA $36 [$00:0036] ;A($5420)を[$00:0037][$00:0036]に書き込み $C0/585A SEP #$20 ;MフラグON Aレジスタは8bit幅 $C0/585C LDX #$0040 ;Xに$0040をロード $C0/585F STX $4305 [$00:4305] ;Xを[$00:4306][$00:4305]に書き込み $C0/5862 LDX $30 [$00:0030] ;Xに[$00:0031][$00:0030]($5000)をロード $C0/5864 STX $2116 [$00:2116] ;Xを[$00:2117][$00:2116]に書き込み $C0/5867 LDA #$01 ;Aに$01をロード $C0/5869 STA $420B [$00:420B] ;Aを[$00:420B]に書き込み ; ;[$00:2117][$00:2116] VRAMアドレス ※word単位 $5000 ;[$00:4300] GDMA / HDMA設定レジスタ $01 ;[$00:4301] 転送先指定 $18=VRAM ;[$00:4303][$00:4302] データ元アドレス(開始位置) $3A00+40+40+40+40 ;[$00:4304] データ元バンク $7F ;[$00:4306][$00:4305] 転送するデータ量 $0040 ;$7F:3B00 -> VRAM $5000word($A000byte) +$0040byte ; $C0/586C LDX #$0040 ;Xに$0040をロード $C0/586F STX $4305 [$00:4305] ;Xを[$00:4306][$00:4305]に書き込み $C0/5872 LDX $34 [$00:0034] ;Xに[$00:0035][$00:0034]($5400)をロード $C0/5874 STX $2116 [$00:2116] ;Xを[$00:2117][$00:2116]に書き込み $C0/5877 LDA #$01 ;Aに$01をロード $C0/5879 STA $420B [$00:420B] ;Aを[$00:420B]に書き込み ; ;[$00:2117][$00:2116] VRAMアドレス ※word単位 $5400 ;[$00:4300] GDMA / HDMA設定レジスタ $01 ;[$00:4301] 転送先指定 $18=VRAM ;[$00:4303][$00:4302] データ元アドレス(開始位置) $3A00+40+40+40+40+40 ;[$00:4304] データ元バンク $7F ;[$00:4306][$00:4305] 転送するデータ量 $0040 ;$7F:3B40 -> VRAM $5400word($A800byte) +$0040byte ; $C0/587C LDX #$0040 ;Xに$0040をロード $C0/587F STX $4305 [$00:4305] ;Xを[$00:4306][$00:4305]に書き込み $C0/5882 LDX $32 [$00:0032] ;Xに[$00:0033][$00:0032]($5020)をロード $C0/5884 STX $2116 [$00:2116] ;Xを[$00:2117][$00:2116]に書き込み $C0/5887 LDA #$01 ;Aに$01をロード $C0/5889 STA $420B [$00:420B] ;Aを[$00:420B]に書き込み ; ;[$00:2117][$00:2116] VRAMアドレス ※word単位 $5020 ;[$00:4300] GDMA / HDMA設定レジスタ $01 ;[$00:4301] 転送先指定 $18=VRAM ;[$00:4303][$00:4302] データ元アドレス(開始位置) $3A00+40+40+40+40+40+40 ;[$00:4304] データ元バンク $7F ;[$00:4306][$00:4305] 転送するデータ量 $0040 ;$7F:3B80 -> VRAM $5020word($A040byte) +$0040byte ; $C0/588C LDX #$0040 ;Xに$0040をロード $C0/588F STX $4305 [$00:4305] ;Xを[$00:4306][$00:4305]に書き込み $C0/5892 LDX $36 [$00:0036] ;Xに[$00:0037][$00:0036]($5420)をロード $C0/5894 STX $2116 [$00:2116] ;Xを[$00:2117][$00:2116]に書き込み $C0/5897 LDA #$01 ;Aに$01をロード $C0/5899 STA $420B [$00:420B] ;Aを[$00:420B]に書き込み ; ;[$00:2117][$00:2116] VRAMアドレス ※word単位 $5420 ;[$00:4300] GDMA / HDMA設定レジスタ $01 ;[$00:4301] 転送先指定 $18=VRAM ;[$00:4303][$00:4302] データ元アドレス(開始位置) $3A00+40+40+40+40+40+40+40 ;[$00:4304] データ元バンク $7F ;[$00:4306][$00:4305] 転送するデータ量 $0040 ;$7F:3BC0 -> VRAM $5420word($A040byte) +$0040byte ; $C0/589C REP #$20 ;Aを16bit幅に変更、Mフラグをクリア $C0/589E LDA $30 [$00:0030] ;Aに[$00:0030]をロード $C0/58A0 CLC ;キャリーフラグクリア $C0/58A1 ADC #$1000 ;A + $1000 $C0/58A4 STA $30 [$00:0030] ;Aを[$00:0030]に書き込み $C0/58A6 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C0/58A8 DEY ;Yをデクリメント -1 $C0/58A9 BNE $99 [$5844] ;ゼロフラグが立っていないとき[$5844]分岐 $C0/58AB RTS ;サブルーチン戻り
まとめると、
| 転送元アドレス (開始位置) | 転送先VRAMアドレス (開始位置) | 転送量 |
|---|---|---|
$7F:3A00 | $4000word($8000byte) | $0040byte |
$7F:3A40 | $4400word($8800byte) | $0040byte |
$7F:3A80 | $4020word($8040byte) | $0040byte |
$7F:3AC0 | $4420word($8840byte) | $0040byte |
$7F:3B00 | $5000word($A000byte) | $0040byte |
$7F:3B40 | $5400word($A800byte) | $0040byte |
$7F:3B80 | $5020word($A040byte) | $0040byte |
$7F:3BC0 | $5420word($A040byte) | $0040byte |
$7F:3A00~$7F:3AFFの$100バイトをBG1のBGマップデータ領域へ、$7F:3B00~$7F:3BFFの$100バイトをBG2のBGマップデータ領域へ転送していることがわかる。
キャラ位置などでVRAMのどこへ送るかは多少前後する。
では、$7F:3A00~$7F:3BFFは何なのかというと、$C0/546B~$C0/5811にて、$7F:3008~$7F:308Dからコピーされた値であり、さらに遡るとバンク$CDあたりからのコピーになるが、ここでは詳細を省く。
なお、$C0/546B~$C0/5811の最後で、
$C0/57F8 LDA $0A3C [$00:0A3C] ;Aに[$00:0A3D][$00:0A3C]をロード $C0/57FB LSR A ;Aを論理右シフト (/2) $C0/57FC LSR A ;Aを論理右シフト (/2) $C0/57FD LSR A ;Aを論理右シフト (/2) $C0/57FE LSR A ;Aを論理右シフト (/2) $C0/57FF CLC ;キャリーフラグクリア $C0/5800 ADC $016A [$00:016A] ;A + [$00:016B][$00:016A] $C0/5803 AND #$00F0 ;Aと$00F0で論理積 $C0/5806 ASL A ;Aを算術左シフト *2 $C0/5807 ASL A ;Aを算術左シフト *2 $C0/5808 CLC ;キャリーフラグクリア $C0/5809 ADC #$4000 ;A + $4000 $C0/580C STA $016C [$00:016C] ;Aを[$00:016D][$00:016C]に書き込み $C0/580F SEP #$20 ;MフラグON Aレジスタは8bit幅 $C0/5811 RTS ;サブルーチン戻り
先に記した[$00:016D][$00:016C]、つまりVRAMへのコピー先アドレスが計算されている。
$C0/5809で$4000を加算する都合で、[$00:016D][$00:016C]は必ず$4000以上の値になるのである。
さて、以上でVRAMに転送されるデータはほんのわずかである。
上の処理の後、VRAMアドレス$0000を開始アドレスとした転送処理が以下になる。
$C0/4DC6 STA $4300 [$00:4300] ;Aを[$00:4300]に書き込み $C0/4DC9 LDA #$18 ;Aに$18をロード $C0/4DCB STA $4301 [$00:4301] ;Aを[$00:4301]に書き込み $C0/4DCE LDX #$0000 ;Xに$0000をロード $C0/4DD1 STX $2116 [$00:2116] ;Xを[$00:2117][$00:2116]に書き込み $C0/4DD4 LDX #$2000 ;Xに$2000をロード $C0/4DD7 STX $26 [$00:0026] ;Xを[$00:0027][$00:0026]に書き込み $C0/4DD9 LDA $0120 [$00:0120] ;Aに[$00:0120]をロード $C0/4DDC STA $20 [$00:0020] ;Aを[$00:0020]に書き込み $C0/4DDE STZ $22 [$00:0022] ;[$00:0022]に$00を書き込み $C0/4DE0 JSR $4E8A [$C0:4E8A] ;[$C0:4E8A]へジャンプ ; ;(中略) ; $CE/D47E PHB ;DBレジスタをスタックにプッシュ $CE/D47F LDA $65 [$00:0065] ;Aに[$00:0065]をロード $CE/D481 PHA ;Aレジスタをスタックにプッシュ $CE/D482 PLB ;DBレジスタにスタックからプル $CE/D483 LDY #$0001 ;Yに$0001をロード $CE/D486 LDX $63 [$00:0063] ;Xに[$00:0063]をロード ;$CE/D521の戻り先 $CE/D488 LDA [$60],y ;Aに[$60],yをロード $CE/D48A INY ;Yをインクリメント +1 $CE/D48B CMP #$F0 ;Aと$F0を減算比較(ステータスレジスタ変更のみ) $CE/D48D BCC $0E [$D49D] ;キャリーフラグが立っていないとき[$D49D]分岐 $CE/D48F STX $63 [$00:0063] ;Xを[$00:0063]に書き込み $CE/D491 REP #$20 ;Aを16bit幅に変更、Mフラグをクリア $CE/D493 AND #$000F ;Aと$000Fで論理積 $CE/D496 ASL A ;Aを算術左シフト *2 $CE/D497 TAX ;Aの値をXレジスタに転送 $CE/D498 SEP #$20 ;MフラグON Aレジスタは8bit幅 $CE/D49A JMP ($D89E,x)[$CE:D4F3] ;[$CE:D4F3]へジャンプ(レジスタをスタックに積まない) $CE/D4F3 LDX $63 [$00:0063] ;Xに[$00:0063]をロード $CE/D4F5 LDA [$60],y ;Aに[$60],yをロード $CE/D4F7 STA $66 [$00:0066] ;Aを[$00:0066]に書き込み $CE/D4F9 STZ $67 [$00:0067] ;[$00:0067]に$00を書き込み $CE/D4FB INY ;Yをインクリメント +1 $CE/D4FC LDA [$60],y[$CA:2BF3] ;Aに[$60]をロード $CE/D4FE STA $68 [$00:0068] ;Aを[$00:0068]に書き込み $CE/D500 STA $69 [$00:0069] ;Aを[$00:0069]に書き込み $CE/D502 INY ;Yをインクリメント +1 $CE/D503 LSR $66 [$00:0066] ;A[$00:0066]を論理右シフト (/2) $CE/D505 BCC $06 [$D50D] ;キャリーフラグが立っていないとき[$D50D]分岐 $CE/D50D REP #$20 ;Aを16bit幅に変更、Mフラグをクリア $CE/D50F LDA $68 [$00:0068] ;Aに[$00:0068]をロード $CE/D511 STA $0000,x[$7E:8000] ;Aを[$7E:8000]に書き込み $CE/D514 INX ;Xをインクリメント +1 $CE/D515 INX ;Xをインクリメント +1 ;ループ開始 $CE/D516 STA $0000,x[$7E:8002] ;Aを[$7E:8002]に書き込み $CE/D519 INX ;Xをインクリメント +1 $CE/D51A INX ;Xをインクリメント +1 $CE/D51B DEC $66 [$00:0066] ;[$00:0066]をデクリメント -1 $CE/D51D BPL $F7 [$D516] ;ネガティブフラグが立っていないとき[$D516]分岐 ;ループここまで $CE/D51F SEP #$20 ;MフラグON Aレジスタは8bit幅 $CE/D521 BRL $FF64 [$D488] ;フラグにかかわりなく常に分岐[$D488] ;(中略) $CE/D507 LDA $68 [$00:0068] ;Aに[$00:0068]をロード $CE/D509 STA $0000,x[$7E:9EFF] ;Aを[$7E:9EFF]に書き込み $CE/D50C INX ;Xをインクリメント +1 $CE/D50D REP #$20 ;Aを16bit幅に変更、Mフラグをクリア $CE/D50F LDA $68 [$00:0068] ;Aに[$00:0068]をロード $CE/D511 STA $0000,x[$7E:9F00] ;Aを[$7E:9F00]に書き込み $CE/D514 INX ;Xをインクリメント +1 $CE/D515 INX ;Xをインクリメント +1 $CE/D516 STA $0000,x[$7E:9F02] ;Aを[$7E:9F02]に書き込み $CE/D519 INX ;Xをインクリメント +1 $CE/D51A INX ;Xをインクリメント +1 $CE/D51B DEC $66 [$00:0066] ;[$00:0066]をデクリメント -1 $CE/D51D BPL $F7 [$D516] ;ネガティブフラグが立っていないとき[$D516]分岐 ;(中略) $CE/D51D BPL $F7 [$D516] ;ネガティブフラグが立っていないとき[$D516]分岐 $CE/D516 STA $0000,x[$7E:9FFE] ;Aを[$7E:9FFE]に書き込み $CE/D519 INX ;Xをインクリメント +1 $CE/D51A INX ;Xをインクリメント +1 $CE/D51B DEC $66 [$00:0066] ;[$00:0066]をデクリメント -1 $CE/D51D BPL $F7 [$D516] ;ネガティブフラグが立っていないとき[$D516]分岐 $CE/D51F SEP #$20 ;MフラグON Aレジスタは8bit幅 $CE/D521 BRL $FF64 [$D488] ;フラグにかかわりなく常に分岐[$D488] $CE/D488 LDA [$60],y ;Aに[$60],yをロード $CE/D48A INY ;Yをインクリメント +1 $CE/D48B CMP #$F0 ;Aと$F0を減算比較(ステータスレジスタ変更のみ) $CE/D48D BCC $0E [$D49D] ;キャリーフラグが立っていないとき[$D49D]分岐 $CE/D48F STX $63 [$00:0063] ;Xを[$00:0063]に書き込み $CE/D491 REP #$20 ;Aを16bit幅に変更、Mフラグをクリア $CE/D493 AND #$000F ;Aと$000Fで論理積 $CE/D496 ASL A ;Aを算術左シフト *2 $CE/D497 TAX ;Aの値をXレジスタに転送 $CE/D498 SEP #$20 ;MフラグON Aレジスタは8bit幅 $CE/D49A JMP ($D89E,x)[$CE:D89C] ;[$CE:D89C]へジャンプ(レジスタをスタックに積まない) $CE/D89C PLB ;DBレジスタにスタックからプル $CE/D89D RTL ;サブルーチン戻り $C0/4ECE LDX #$8000 ;Xに$8000をロード $C0/4ED1 STX $4302 [$00:4302] ;Xを[$00:4303][$00:4302]に書き込み $C0/4ED4 LDA #$7E ;Aに$7Eをロード $C0/4ED6 STA $4304 [$00:4304] ;Aを[$00:4304]に書き込み $C0/4ED9 LDY #$2000 ;Yに$2000をロード $C0/4EDC STY $4305 [$00:4305] ;Yを[$00:4306][$00:4305]に書き込み $C0/4EDF LDA #$01 ;Aに$01をロード $C0/4EE1 STA $420B [$00:420B] ;Aを[$00:420B]に書き込み ; ;[$00:2117][$00:2116] VRAMアドレス ※word単位 $0000 ;[$00:4300] GDMA / HDMA設定レジスタ $01 ;[$00:4301] 転送先指定 $18=VRAM ;[$00:4303][$00:4302] データ元アドレス(開始位置) $8000 ;[$00:4304] データ元バンク $7E ;[$00:4306][$00:4305] 転送するデータ量 $2000 ;$7E:8000 -> VRAM $2000word($4000byte) +$2000byte ; ;(後略)
非常に大雑把にまとめると、$CE/D47E~$CE/D89Dで[$7E:8000]~[$7E:9FFE]にコピーされた値を、GDMA転送でVRAMアドレス開始位置$0000word($0000byte)に転送する処理である。BG1とBG2用のタイルデータの送信ということになる。
つまりVRAMアドレス$0000~$1FFFまでの転送となるが、背景タイルの画像データは$0000~$5FFFの領域を使用可能である($6000からはBG3用タイルデータの領域)。
タイルの画像データが$2000バイトで済むなら上の転送だけで終わりだが、足りない場合は、[$7E:8000]~[$7E:9FFE]に次の$2000バイト分のタイルのデータをコピーして転送、を繰り返すことになる。
[$00:2117][$00:2116]の転送位置は、上書きして変更しない限り、転送したアドレス+1され続けるため、VRAMアドレス$0000~$1FFFの転送を終えた後に続いて転送を始めると、VRAMアドレス$2000~から転送を開始してくれるようになっている。
マップやエリア毎に、$0000~$5FFFのどこまでタイル画像データを送るかは変わってくる。
BGマップデータの転送処理は以下。
まず、BG1、BG2のマップデータについて説明する。
BG1、BG2のマップデータ転送は2回に分けて行うのだが、最初にそれぞれ$1000バイト分転送後に、さらに$700バイトを転送して上書き、という方法を取っている。
BGマップデータはタイル1個(8×8ピクセル)で2バイトで、実際にゲーム画面に表示されるのは横256ピクセル×縦224ピクセルだから、タイル896個分、$700バイトである。
しかし、フィールドでの背景サイズは横64×縦32タイルで指定するため、$1000バイト分のデータを送らなければならない。
実際には表示されない領域部分も含めて最初に初期化用$1000バイトを転送し、続けて、実際に画面に表示される部分の$700バイトを送る、という方法を取っている。
$CE/D3BF PHB ;DBレジスタをスタックにプッシュ $CE/D3C0 LDA #$7E ;Aに$7Eをロード $CE/D3C2 PHA ;Aレジスタをスタックにプッシュ $CE/D3C3 PLB ;DBレジスタにスタックからプル $CE/D3C4 LDA $000110[$00:0110] ;Aに[$00:0110]をロード $CE/D3C8 REP #$20 ;Aを16bit幅に変更、Mフラグをクリア $CE/D3CA AND #$00FF ;Aと$00FFで論理積 $CE/D3CD ASL A ;Aを算術左シフト *2 $CE/D3CE ASL A ;Aを算術左シフト *2 $CE/D3CF ASL A ;Aを算術左シフト *2 $CE/D3D0 TAX ;Aの値をXレジスタに転送 $CE/D3D1 LDA $7F3000,x ;Aに[$7F3000,x]をロード $CE/D3D5 LDX #$C000 ;Xに$C000をロード $CE/D3D8 LDY #$0800 ;Yに$0800をロード ;ループ処理 $CE/D3DB STA $0000,x ;Aを[$7E:C000]~[$7E:CFFE]に書き込み $CE/D3DE INX ;Xをインクリメント +1 $CE/D3DF INX ;Xをインクリメント +1 $CE/D3E0 DEY ;Yをデクリメント -1 $CE/D3E1 BNE $F8 [$D3DB] ;ゼロフラグが立っていないとき[$D3DB]分岐 ;ループ処理ここまで $CE/D3E3 SEP #$20 ;MフラグON Aレジスタは8bit幅 $CE/D3E5 PLB ;DBレジスタにスタックからプル $CE/D3E6 LDA #$01 ;Aに$01をロード $CE/D3E8 STA $4300 [$00:4300] ;Aを[$00:4300]に書き込み $CE/D3EB LDA #$18 ;Aに$18をロード $CE/D3ED STA $4301 [$00:4301] ;Aを[$00:4301]に書き込み $CE/D3F0 LDX #$C000 ;Xに$C000をロード $CE/D3F3 STX $4302 [$00:4302] ;Xを[$00:4303][$00:4302]に書き込み $CE/D3F6 LDA #$7E ;Aに$7Eをロード $CE/D3F8 STA $4304 [$00:4304] ;Aを[$00:4304]に書き込み $CE/D3FB LDX #$4000 ;Xに$4000をロード $CE/D3FE STX $2116 [$00:2116] ;Xを[$00:2117][$00:2116]に書き込み $CE/D401 LDX #$1000 ;Xに$1000をロード $CE/D404 STX $4305 [$00:4305] ;Xを[$00:4306][$00:4305]に書き込み $CE/D407 LDA #$01 ;Aに$01をロード $CE/D409 STA $420B [$00:420B] ;Aを[$00:420B]に書き込み ; ;[$00:2117][$00:2116] VRAMアドレス ※word単位 $4000 ;[$00:4300] GDMA / HDMA設定レジスタ $01 ;[$00:4301] 転送先指定 $18=VRAM ;[$00:4303][$00:4302] データ元アドレス(開始位置) $C000 ;[$00:4304] データ元バンク $7E ;[$00:4306][$00:4305] 転送するデータ量 $1000 ;$7E:C000 -> VRAM $4000word($8000byte) +$1000byte ; $CE/D40C LDA #$09 ;Aに$09をロード $CE/D40E STA $4300 [$00:4300] ;Aを[$00:4300]に書き込み $CE/D411 LDA #$18 ;Aに$18をロード $CE/D413 STA $4301 [$00:4301] ;Aを[$00:4301]に書き込み $CE/D416 LDX #$0030 ;Xに$0030をロード $CE/D419 STX $4302 [$00:4302] ;Xを[$00:4303][$00:4302]に書き込み $CE/D41C STZ $4304 [$00:4304] ;[$00:4304]に$00を書き込み $CE/D41F STZ $30 [$00:0030] ;[$00:0030]に$00を書き込み $CE/D421 LDX #$5000 ;Xに$5000をロード $CE/D424 STX $2116 [$00:2116] ;Xを[$00:2117][$00:2116]に書き込み $CE/D427 LDX #$1000 ;Xに$1000をロード $CE/D42A STX $4305 [$00:4305] ;Xを[$00:4306][$00:4305]に書き込み $CE/D42D LDA #$01 ;Aに$01をロード $CE/D42F STA $420B [$00:420B] ;Aを[$00:420B]に書き込み ; ;[$00:2117][$00:2116] VRAMアドレス ※word単位 $5000 ;[$00:4300] GDMA / HDMA設定レジスタ $09 *アドレスはfixed ;[$00:4301] 転送先指定 $18=VRAM ;[$00:4303][$00:4302] データ元アドレス(開始位置) $0030 ;[$00:4304] データ元バンク $00 ;[$00:4306][$00:4305] 転送するデータ量 $1000 ;$00:0030 -> VRAM $5000word($A000byte) +$1000byte ; $CE/D432 RTL ;サブルーチン戻り
上が、$7E:C000~$7E:CFFFをVRAMアドレス$8000~$8FFFに転送する処理(BG1のBGマップデータ)と、$00:0030をVRAMアドレス$A000~$AFFFに転送する処理(BG2のBGマップデータ)である。
$7E:C000~$7E:CFFFの内容だが、$CE/D3DB~$CE/D3E1のループ処理で書き込みを行っているものの、その書き込んでいる数値は、$CE/D3D1でロードした、$7F3000,xであり、固定値である。
つまり、$CE/D409でVRAMのBG1マップデータ領域へGDMA転送した値はすべて同じである。
ではBG2マップデータ領域の転送はどうなっているかというと、[$00:4300]に書き込む値に注目していただきたい。
BG1のBGマップデータ転送は、[$00:4300]に$01(%0000 0001)を書き込み、BG2のBGマップデータ転送は、[$00:4300]に$09(%0000 1001)を書き込む、という相違点がある。
どちらもGDMA転送チャネル0の設定であるが、GDMA / HDMA設定レジスタ[$00:43n0]には以下のように値を書き込む。
| Bit | 内容 |
|---|---|
| Bit0~2 | 転送モード ※snes-docs-ja/memory/dma/ioreg.md参照 |
| Bit3~4 | 転送元のアドレス増加設定 %00: インクリメント %01: 固定(fixed) %10: デクリメント %11: 固定(fixed) |
| Bit5~6 | 不使用 |
| Bit7 | 転送方向 (0: Aバス->Bバス, 1: Bバス->Aバス) |
細かい説明は省くが、今回重要なのはBit3~4の転送元のアドレス増加設定である。
[$00:4300]に$09(%0000 1001)が書き込まれている、ということは、Bit3~4が%01だから、「固定」である($01を書き込んだ時は「%00: インクリメント」)。
つまり、転送元のアドレスは指定したアドレスで固定という意味である。
$CE/D40C以降のBG2のBGマップデータ転送の設定を見ると、転送元アドレスは$00:0030と設定されている。
([$00:4304]及び、[$00:4303][$00:4302]の設定)
そして、VRAMアドレス$A000~$AFFFが転送先となるが、$A000~$AFFF全てに、転送元アドレス$00:0030の値をコピーしろ、という意味になる。
以上から、結局のところ、$CE/D3BF~$CE/D432の処理はBGマップデータの初期化だったということがわかる。
初期化のため書き込む$7F3000,xや$00:0030はエリアやマップにより多少異なる。
部屋内部など、周囲が黒一色塗りつぶしの場合は黒一色タイルのデータだったり、近未来編のワールドマップのように、草原のようなタイルが敷き詰められるマップもある。
初期化後に実際に表示するデータの転送は以下のようになる。
$C0/5337 LDA #$01 ;Aに$01をロード $C0/5339 STA $4300 [$00:4300] ;Aを[$00:4300]に書き込み $C0/533C LDA #$18 ;Aに$18をロード $C0/533E STA $4301 [$00:4301] ;Aを[$00:4301]に書き込み $C0/5341 LDX #$C000 ;Xに$C000をロード $C0/5344 STX $4302 [$00:4302] ;Xを[$00:4303][$00:4302]に書き込み $C0/5347 LDA #$7E ;Aに$7Eをロード $C0/5349 STA $4304 [$00:4304] ;Aを[$00:4304]に書き込み $C0/534C LDA $0114 [$00:0114] ;Aに[$00:0114]をロード $C0/534F BNE $08 [$5359] ;ゼロフラグが立っていないとき[$5359]分岐 $C0/5351 LDX #$0700 ;Xに$0700をロード $C0/5354 STX $4305 [$00:4305] ;Xを[$00:4306][$00:4305]に書き込み $C0/5357 BRA $18 [$5371] ;フラグにかかわりなく常に分岐[$5371] $C0/5371 LDX #$4000 ;Xに$4000をロード $C0/5374 STX $2116 [$00:2116] ;Xを[$00:2117][$00:2116]に書き込み $C0/5377 LDA #$01 ;Aに$01をロード $C0/5379 STA $420B [$00:420B] ;Aを[$00:420B]に書き込み ; ;[$00:2117][$00:2116] VRAMアドレス ※word単位 $4000 ;[$00:4300] GDMA / HDMA設定レジスタ $01 ;[$00:4301] 転送先指定 $18=VRAM ;[$00:4303][$00:4302] データ元アドレス(開始位置) $C000 ;[$00:4304] データ元バンク $7E ;[$00:4306][$00:4305] 転送するデータ量 $0700 ;$7E:C000 -> VRAM $4000word($8000byte) +$0700byte ; $C0/537C LDX #$D000 ;Xに$D000をロード $C0/537F STX $4302 [$00:4302] ;Xを[$00:4303][$00:4302]に書き込み $C0/5382 LDA $0117 [$00:0117] ;Aに[$00:0117]をロード $C0/5385 BNE $12 [$5399] ;ゼロフラグが立っていないとき[$5399]分岐 $C0/5387 LDA $0116 [$00:0116] ;Aに[$00:0116]をロード $C0/538A BNE $0D [$5399] ;ゼロフラグが立っていないとき[$5399]分岐 $C0/538C LDA $0114 [$00:0114] ;Aに[$00:0114]をロード $C0/538F BNE $0F [$53A0] ;ゼロフラグが立っていないとき[$53A0]分岐 $C0/5391 LDX #$0700 ;Xに$0700をロード $C0/5394 STX $4305 [$00:4305] ;Xを[$00:4306][$00:4305]に書き込み $C0/5397 BRA $18 [$53B1] ;フラグにかかわりなく常に分岐[$53B1] $C0/53B1 LDX #$5000 ;Xに$5000をロード $C0/53B4 STX $2116 [$00:2116] ;Xを[$00:2117][$00:2116]に書き込み $C0/53B7 LDA #$01 ;Aに$01をロード $C0/53B9 STA $420B [$00:420B] ;Aを[$00:420B]に書き込み ; ;[$00:2117][$00:2116] VRAMアドレス ※word単位 $5000 ;[$00:4300] GDMA / HDMA設定レジスタ $01 ;[$00:4301] 転送先指定 $18=VRAM ;[$00:4303][$00:4302] データ元アドレス(開始位置) $D000 ;[$00:4304] データ元バンク $7E ;[$00:4306][$00:4305] 転送するデータ量 $0700 ;$7E:D000 -> VRAM $5000word($A000byte) +$0700byte ; $C0/53BC STZ $0165 [$00:0165] ;[$00:0165]に$00を書き込み $C0/53BF RTS ;サブルーチン戻り
BG1のBGマップデータの転送は、
$7E:C000~$7E:C6FF -> VRAMアドレス$8000~$8700
BG2のBGマップデータの転送は、
$7E:D000~$7E:D6FF -> VRAMアドレス$A000~$A700
となっており、1画面分のデータが送られたことがわかる。
$7E:C000~のデータは$C0/5043~$C0/5333のサブルーチンで計算されているが、(筆者には)ややこしいので省略。
VRAMの$6000~に入るBG3のテキストや吹き出しの画像データ(タイルデータ)や、$9000~に入るBG3のBGマップデータだが、$6000~$6FFFは8×8ピクセルサイズの文字画像や吹き出し形状など共通部分のデータ、$7000以降にセリフ部分のデータが入る仕組みである。
よって、$6000~$6FFFはシナリオ開始時や、セーブデータをロードした時に入る。
一方、$7000以降は、誰かに話しかけた時などに転送され更新されることになる。
まず、シナリオ開始時や、セーブデータをロードした時の処理を紹介する。
$C0/9AF7 LDA #$09 ;Aに$09をロード $C0/9AF9 STA $4300 [$00:4300] ;Aを[$00:4300]に書き込み $C0/9AFC LDA #$18 ;Aに$18をロード $C0/9AFE STA $4301 [$00:4301] ;Aを[$00:4301]に書き込み $C0/9B01 LDX #$0020 ;Xに$0020をロード $C0/9B04 STX $4302 [$00:4302] ;Xを[$00:4303][$00:4302]に書き込み $C0/9B07 STZ $4304 [$00:4304] ;[$00:4304]に$00を書き込み $C0/9B0A LDX #$0200 ;Xに$0200をロード $C0/9B0D STX $4305 [$00:4305] ;Xを[$00:4306][$00:4305]に書き込み $C0/9B10 STZ $20 [$00:0020] ;[$00:0020]に$00を書き込み $C0/9B12 LDX #$3000 ;Xに$3000をロード $C0/9B15 STX $2116 [$00:2116] ;Xを[$00:2117][$00:2116]に書き込み $C0/9B18 LDA #$01 ;Aに$01をロード $C0/9B1A STA $420B [$00:420B] ;Aを[$00:420B]に書き込み ; ;[$00:2117][$00:2116] VRAMアドレス ※word単位 $3000 ;[$00:4300] GDMA / HDMA設定レジスタ $09 fixed ;[$00:4301] 転送先指定 $18=VRAM ;[$00:4303][$00:4302] データ元アドレス(開始位置) $0020 ;[$00:4304] データ元バンク $00 ;[$00:4306][$00:4305] 転送するデータ量 $0200 ;$00:0200 -> VRAM $3000word($6000byte) +$0200byte ; $C0/9B1D LDA #$01 ;Aに$01をロード $C0/9B1F STA $4300 [$00:4300] ;Aを[$00:4300]に書き込み $C0/9B22 LDX #$F200 ;Xに$F200をロード $C0/9B25 STX $4302 [$00:4302] ;Xを[$00:4303][$00:4302]に書き込み $C0/9B28 LDA #$D4 ;Aに$D4をロード $C0/9B2A STA $4304 [$00:4304] ;Aを[$00:4304]に書き込み $C0/9B2D LDX #$0E00 ;Xに$0E00をロード $C0/9B30 STX $4305 [$00:4305] ;Xを[$00:4306][$00:4305]に書き込み $C0/9B33 LDA #$01 ;Aに$01をロード $C0/9B35 STA $420B [$00:420B] ;Aを[$00:420B]に書き込み ; ;[$00:2117][$00:2116] VRAMアドレス ※word単位 $3100 ;[$00:4300] GDMA / HDMA設定レジスタ $01 ;[$00:4301] 転送先指定 $18=VRAM ;[$00:4303][$00:4302] データ元アドレス(開始位置) $F200 ;[$00:4304] データ元バンク $D4 ;[$00:4306][$00:4305] 転送するデータ量 $0E00 ;$D4:F200 -> VRAM $3100word($6200byte) +$0E00byte ; $C0/9B38 LDA $70 [$00:0070] ;Aに[$00:0070]をロード $C0/9B3A CMP #$01 ;Aと$01を減算比較(ステータスレジスタ変更のみ) $C0/9B3C BEQ $26 [$9B64] ;ゼロフラグが立っているとき[$9B64]分岐 $C0/9B3E STZ $30 [$00:0030] ;[$00:0030]に$00を書き込み $C0/9B40 LDA #$09 ;Aに$09をロード $C0/9B42 STA $4300 [$00:4300] ;Aを[$00:4300]に書き込み $C0/9B45 LDA #$18 ;Aに$18をロード $C0/9B47 STA $4301 [$00:4301] ;Aを[$00:4301]に書き込み $C0/9B4A LDX #$0030 ;Xに$0030をロード $C0/9B4D STX $4302 [$00:4302] ;Xを[$00:4303][$00:4302]に書き込み $C0/9B50 STZ $4304 [$00:4304] ;[$00:4304]に$00を書き込み $C0/9B53 LDX #$0800 ;Xに$0800をロード $C0/9B56 STX $4305 [$00:4305] ;Xを[$00:4306][$00:4305]に書き込み $C0/9B59 LDX #$4800 ;Xに$4800をロード $C0/9B5C STX $2116 [$00:2116] ;Xを[$00:2117][$00:2116]に書き込み $C0/9B5F LDA #$01 ;Aに$01をロード $C0/9B61 STA $420B [$00:420B] ;Aを[$00:420B]に書き込み ; ;[$00:2117][$00:2116] VRAMアドレス ※word単位 $4800 ;[$00:4300] GDMA / HDMA設定レジスタ $09 fixed ;[$00:4301] 転送先指定 $18=VRAM ;[$00:4303][$00:4302] データ元アドレス(開始位置) $0030 ;[$00:4304] データ元バンク $00 ;[$00:4306][$00:4305] 転送するデータ量 $0800 ;$00:0030 -> VRAM $4800word($9000byte) +$0800byte ; $C0/9B64 RTS A:0001 X:4800 Y:0002 P:envMxdIzC;サブルーチン戻り
$C0/9AF7~$C0/9B1Aは、VRAMの$6000~$61FFに、$00:0200の値を書き込む処理$C0/9B1D~$C0/9B35は、VRAMの$6200~$6FFFに、$D4:F200~$D4:FFFFを書き込む処理$C0/9B38~$C0/9B35は、VRAMの$9000~$9800に、$00:0030の値を書き込む処理と、なる。
[$00:4300]に$09が書き込まれた場合、書き込み元アドレスの値は固定になる、と先に説明した通りである。
つまり、BG3タイルデータは、
| VRAMアドレス | 内容 |
|---|---|
| $6000~$61FF | $00:0200で固定 |
| $6200~$6FFF | $D4:F200~$D4:FFFF |
これが初期値で、$D4:F200~$D4:FFFFに8×8ピクセルサイズの文字画像や吹き出し形状などが格納されている、ということがわかる。
$9000~に入るBG3のBGマップデータは、$9000~$9800に初期値として$00:0030の値が書き込まれている。
ゲーム中で実際に話しかけてテキスト表示がされた時の処理は以下の通り。
$C0/A2CB LDA #$01 ;Aに$01をロード $C0/A2CD STA $4300 [$00:4300] ;Aを[$00:4300]に書き込み $C0/A2D0 LDA #$18 ;Aに$18をロード $C0/A2D2 STA $4301 [$00:4301] ;Aを[$00:4301]に書き込み $C0/A2D5 LDX #$C000 ;Xに$C000をロード $C0/A2D8 STX $4302 [$00:4302] ;Xを[$00:4303][$00:4302]に書き込み $C0/A2DB LDA #$7E ;Aに$7Eをロード $C0/A2DD STA $4304 [$00:4304] ;Aを[$00:4304]に書き込み $C0/A2E0 LDX #$0800 ;Xに$0800をロード $C0/A2E3 STX $4305 [$00:4305] ;Xを[$00:4306][$00:4305]に書き込み $C0/A2E6 LDX #$4800 ;Xに$4800をロード $C0/A2E9 STX $2116 [$00:2116] ;Xを[$00:2117][$00:2116]に書き込み $C0/A2EC LDA #$01 ;Aに$01をロード $C0/A2EE STA $420B [$00:420B] ;Aを[$00:420B]に書き込み ; ;BG3のBGマップデータ ;[$00:2117][$00:2116] VRAMアドレス ※word単位 $4800 ;[$00:4300] GDMA / HDMA設定レジスタ $01 ;[$00:4301] 転送先指定 $18=VRAM ;[$00:4303][$00:4302] データ元アドレス(開始位置) $C000 ;[$00:4304] データ元バンク $7E ;[$00:4306][$00:4305] 転送するデータ量 $0800 ;$7E:C000 -> VRAM $4800word($9000byte) +$0800byte ; $C0/A2F1 JSR $A91A [$C0:A91A] ;[$C0:A91A]へジャンプ $C0/A91A LDA #$01 ;Aに$01をロード $C0/A91C STA $4300 [$00:4300] ;Aを[$00:4300]に書き込み $C0/A91F LDA #$18 ;Aに$18をロード $C0/A921 STA $4301 [$00:4301] ;Aを[$00:4301]に書き込み $C0/A924 LDX $01CA [$00:01CA] ;Xに[$00:01CB][$00:01CA]をロード $C0/A927 STX $4302 [$00:4302] ;Xを[$00:4303][$00:4302]に書き込み $C0/A92A LDA #$7E ;Aに$7Eをロード $C0/A92C STA $4304 [$00:4304] ;Aを[$00:4304]に書き込み $C0/A92F LDX #$0900 ;Xに$0900をロード $C0/A932 STX $4305 [$00:4305] ;Xを[$00:4306][$00:4305]に書き込み $C0/A935 LDX #$3800 ;Xに$3800をロード $C0/A938 STX $2116 [$00:2116] ;Xを[$00:2117][$00:2116]に書き込み $C0/A93B LDA #$01 ;Aに$01をロード $C0/A93D STA $420B [$00:420B] ;Aを[$00:420B]に書き込み ; ;[$00:2117][$00:2116] VRAMアドレス ※word単位 $3800 ;[$00:4300] GDMA / HDMA設定レジスタ $01 ;[$00:4301] 転送先指定 $18=VRAM ;[$00:4303][$00:4302] データ元アドレス(開始位置) [$00:01CB][$00:01CA] = $C800 ;[$00:4304] データ元バンク $7E ;[$00:4306][$00:4305] 転送するデータ量 $0900 ;$7E:C800 -> VRAM $3800word($7000byte) +$0900byte ; $C0/A940 RTS ;サブルーチン戻り
$7E:C000~$7E:C7FFを、VRAMアドレス$9000~$97FF(BG3のBGマップデータ)に転送する処理と、$7E:C800~$7E:D0FFを、VRAMアドレス$7000~$7900(BG3タイルデータの文字部分)に転送する処理となる。
ただ、$7000~$7900(BG3タイルデータの文字部分)の処理は上で終わりではない。
$C0/A91A~$C0/A93Dの処理はセリフ1文字を表示する毎に入る。
1文字表示すると、次の1文字は1フレーム置いてから(つまり、次のHBlankに)表示する。
ゲーム画面を注意して見ていればわかるが、誰かのセリフの場合、ウィンドウの文字が流れるように1文字ずつ表示されているように見える。1フレームに1文字表示する仕組みなのである。
(であるから、本作でタイムアタックをする場合、キャラに名前をつける時は短い名前の方がわずかながら時間短縮できる……はずである。SF編のように明らかに主人公名を短縮した方が良いシナリオもあるので、名前を短めにするに越したことはないだろう)
$7E:C800~$7E:D0FFに値を書き込む処理は$C0/A64B~$C0/A86Bで行っているが、詳細は省く。
CGRAMにはカラーパレットが16パターン格納され、CGRAMアドレス$0000~$00FFが背景(BG)用、$0100~$01FFがスプライト用と分かれている。
スプライト用カラーパレットのサブルーチンはスプライトについて > サブルーチンで既に紹介しているので、背景(BG)用サブルーチンを紹介していく。
$C0/9ACA LDA #$00 ;Aに$00をロード $C0/9ACC STA $4300 [$00:4300] ;Aを[$00:4300]に書き込み $C0/9ACF LDA #$22 ;Aに$22をロード $C0/9AD1 STA $4301 [$00:4301] ;Aを[$00:4301]に書き込み $C0/9AD4 LDX #$F920 ;Xに$F920をロード $C0/9AD7 STX $4302 [$00:4302] ;Xを[$00:4303][$00:4302]に書き込み $C0/9ADA LDA #$CF ;Aに$CFをロード $C0/9ADC STA $4304 [$00:4304] ;Aを[$00:4304]に書き込み $C0/9ADF LDA $70 [$00:0070] ;Aに[$00:0070]をロード $C0/9AE1 CMP #$01 ;Aと$01を減算比較(ステータスレジスタ変更のみ) $C0/9AE3 BEQ $11 [$9AF6] ;ゼロフラグが立っているとき[$9AF6]分岐 $C0/9AE5 JSR $B925 [$C0:B925] ;[$C0:B925]へジャンプ ;VBlankフラグ判定ループ $C0/B925 LDA #$80 ;Aに$80をロード ;ループ処理 $C0/B927 BIT $4212 [$00:4212] ;Aと[$00:4212]で論理積(ステータスフラグ変更のみ) $C0/B92A BNE $FB [$B927] ;ゼロフラグが立っていないとき[$B927]分岐 ;ループ処理ここまで ;ループ処理 $C0/B92C BIT $4212 [$00:4212] ;Aと[$00:4212]で論理積(ステータスフラグ変更のみ) $C0/B92F BEQ $FB [$B92C] ;ゼロフラグが立っているとき[$B92C]分岐 ;ループ処理ここまで $C0/B931 RTS ;サブルーチン戻り $C0/9AE8 STZ $2121 [$00:2121] ;[$00:2121]に$00を書き込み $C0/9AEB LDX #$0040 ;Xに$0040をロード $C0/9AEE STX $4305 [$00:4305] ;Xを[$00:4306][$00:4305]に書き込み $C0/9AF1 LDA #$01 ;Aに$01をロード $C0/9AF3 STA $420B [$00:420B] ;Aを[$00:420B]に書き込み ; ;[$00:2121] CGRAMのパレットアドレス開始位置 ※word単位 $00 ;[$00:4300] GDMA / HDMA設定レジスタ $00 ;[$00:4301] 転送先指定 $22=CGRAM ;[$00:4303][$00:4302] データ元アドレス(開始位置) $F920 ;[$00:4304] データ元バンク $CF ;[$00:4306][$00:4305] 転送するデータ量 $0040 ;$CF:F920 -> CGRAM $0000word($0000byte) +$0040byte ; $C0/9AF6 RTS ;サブルーチン戻り
まず最初のCGRAM転送は上のサブルーチンで、間にVBlankフラグ、つまりI/Oレジスタ[$00:4212]の上1ビットに1が入っているかどうかのチェック$C0/B925~$C0/B931を挟み、VBlankに入ったのを確認できたタイミングで$C0/9AE8~の転送処理を行っている。
転送処理は、$CF:F920~$CF:F95Fの$40バイトを、CGRAMのアドレス$0000~$0040へ転送している。CGRAMのアドレス表記はword単位であることに注意。
カラーパレット1個分のデータが$20バイトだから、カラーパレットNo.00とNo.01のデータを転送したことになる。
また、フィールドにおけるカラーパレットNo.00とNo.01のデータは、$CF:F920~$CF:F95Fで固定ということもわかった。
$C0/4D17 LDA $0A00 [$00:0A00] ;Aに[$00:0A00](シナリオID)をロード $C0/4D1A CMP #$08 ;Aと$08を減算比較(ステータスレジスタ変更のみ) $C0/4D1C BEQ $05 [$4D23] ;ゼロフラグが立っているとき[$4D23]分岐 ;ゼロフラグOFF(最終編以外) $C0/4D1E LDA $0123 [$00:0123] ;Aに[$00:0123]をロード $C0/4D21 BRA $05 [$4D28] ;フラグにかかわりなく常に分岐[$4D28] ;ゼロフラグON(最終編) $C0/4D23 LDA $0123 [$00:0123] ;Aに[$00:0123]をロード $C0/4D26 INC A ;Aをインクリメント +1 $C0/4D27 INC A ;Aをインクリメント +1 ;処理合流 $C0/4D28 CLC ;キャリーフラグクリア $C0/4D29 ADC $0A0A [$00:0A0A] ;A + [$00:0A0A] $C0/4D2C REP #$20 ;Aを16bit幅に変更、Mフラグをクリア $C0/4D2E AND #$00FF ;Aと$00FFで論理積 $C0/4D31 ASL A ;Aを算術左シフト *2 $C0/4D32 ASL A ;Aを算術左シフト *2 $C0/4D33 STA $30 [$00:0030] ;Aを[$00:0031][$00:0030]に書き込み $C0/4D35 ASL A ;Aを算術左シフト *2 $C0/4D36 ASL A ;Aを算術左シフト *2 $C0/4D37 STA $32 [$00:0032] ;Aを[$00:0033][$00:0032]に書き込み $C0/4D39 ASL A ;Aを算術左シフト *2 $C0/4D3A STA $34 [$00:0034] ;Aを[$00:0035][$00:0034]に書き込み $C0/4D3C ASL A ;Aを算術左シフト *2 $C0/4D3D ASL A ;Aを算術左シフト *2 $C0/4D3E CLC ;キャリーフラグクリア $C0/4D3F ADC $30 [$00:0030] ;A + [$00:0031][$00:0030] $C0/4D41 CLC ;キャリーフラグクリア $C0/4D42 ADC $32 [$00:0032] ;A + [$00:0033][$00:0032] $C0/4D44 CLC ;キャリーフラグクリア $C0/4D45 ADC $34 [$00:0034] ;A + [$00:0035][$00:0034] $C0/4D47 CLC ;キャリーフラグクリア $C0/4D48 ADC #$E000 ;A + $E000 $C0/4D4B TAX ;Aの値をXレジスタに転送 $C0/4D4C SEP #$20 ;MフラグON Aレジスタは8bit幅 $C0/4D4E PHB ;DBレジスタをスタックにプッシュ $C0/4D4F LDA #$7E ;Aに$7Eをロード $C0/4D51 PHA ;Aレジスタをスタックにプッシュ $C0/4D52 PLB ;DBレジスタにスタックからプル $C0/4D53 REP #$20 ;Aを16bit幅に変更、Mフラグをクリア $C0/4D55 LDY #$3840 ;Yに$3840をロード $C0/4D58 LDA #$0006 ;Aに$0006をロード $C0/4D5B STA $30 [$00:0030] ;Aを[$00:0030]に書き込み $C0/4D5D LDA #$0000 ;Aに$0000をロード $C0/4D60 STA $0000,y[$7E:3840] ;Aを[$7E:3840]に書き込み $C0/4D63 INY ;Yをインクリメント +1 $C0/4D64 INY ;Yをインクリメント +1 $C0/4D65 LDA #$001D ;Aに$001Dをロード $C0/4D68 MVN DE 7E ;データ転送 ;A: 1D (転送データサイズ-1) ;X: ???? (転送元アドレス) ;Y: $3842 (転送先アドレス) ;オペランド: 転送元バンクDE 転送先バンク7E ;$CF:???? -> $7E:39A0 +$1E $C0/4D6B DEC $30 [$00:0030] ;[$00:0030]をデクリメント -1 $C0/4D6D BNE $EE [$4D5D] ;ゼロフラグが立っていないとき[$4D5D]分岐 $C0/4D5D LDA #$0000 ;Aに$0000をロード $C0/4D60 STA $0000,y[$7E:3860] ;Aを[$7E:3860]に書き込み $C0/4D63 INY ;Yをインクリメント +1 $C0/4D64 INY ;Yをインクリメント +1 $C0/4D65 LDA #$001D ;Aに$001Dをロード $C0/4D68 MVN DE 7E ;データ転送 ;A: 1D (転送データサイズ-1) ;X: ???? + $1E (転送元アドレス) ;Y: $3862 (転送先アドレス) ;オペランド: 転送元バンクDE 転送先バンク7E ;$CF:????+$1E -> $7E:3862 +$1E $C0/4D6B DEC $30 [$00:0030] ;[$00:0030]をデクリメント -1 $C0/4D6D BNE $EE [$4D5D] ;ゼロフラグが立っていないとき[$4D5D]分岐 $C0/4D5D LDA #$0000 ;Aに$0000をロード $C0/4D60 STA $0000,y[$7E:3880] ;Aを[$7E:3880]に書き込み $C0/4D63 INY ;Yをインクリメント +1 $C0/4D64 INY ;Yをインクリメント +1 $C0/4D65 LDA #$001D ;Aに$001Dをロード $C0/4D68 MVN DE 7E ;データ転送 ;A: 1D (転送データサイズ-1) ;X: ???? + $1E + $1E (転送元アドレス) ;Y: $3882 (転送先アドレス) ;オペランド: 転送元バンクDE 転送先バンク7E ;$CF:????+$1E+$1E -> $7E:3882 +$1E $C0/4D6B DEC $30 [$00:0030] ;[$00:0030]をデクリメント -1 $C0/4D6D BNE $EE [$4D5D] ;ゼロフラグが立っていないとき[$4D5D]分岐 $C0/4D5D LDA #$0000 ;Aに$0000をロード $C0/4D60 STA $0000,y[$7E:38A0] ;Aを[$7E:38A0]に書き込み $C0/4D63 INY ;Yをインクリメント +1 $C0/4D64 INY ;Yをインクリメント +1 $C0/4D65 LDA #$001D ;Aに$001Dをロード $C0/4D68 MVN DE 7E ;データ転送 ;A: 1D (転送データサイズ-1) ;X: ???? + $1E + $1E + $1E (転送元アドレス) ;Y: $38A2 (転送先アドレス) ;オペランド: 転送元バンクDE 転送先バンク7E ;$CF:????+$1E+$1E+$1E -> $7E:38A2 +$1E $C0/4D6B DEC $30 [$00:0030] ;[$00:0030]をデクリメント -1 $C0/4D6D BNE $EE [$4D5D] ;ゼロフラグが立っていないとき[$4D5D]分岐 $C0/4D5D LDA #$0000 ;Aに$0000をロード $C0/4D60 STA $0000,y[$7E:38C0] ;Aを[$7E:38C0]に書き込み $C0/4D63 INY ;Yをインクリメント +1 $C0/4D64 INY ;Yをインクリメント +1 $C0/4D65 LDA #$001D ;Aに$001Dをロード $C0/4D68 MVN DE 7E ;データ転送 ;A: 1D (転送データサイズ-1) ;X: ???? + $1E + $1E + $1E + $1E (転送元アドレス) ;Y: $38C2 (転送先アドレス) ;オペランド: 転送元バンクDE 転送先バンク7E ;$CF:????+$1E+$1E+$1E+$1E -> $7E:38C2 +$1E $C0/4D6B DEC $30 [$00:0030] ;[$00:0030]をデクリメント -1 $C0/4D6D BNE $EE [$4D5D] ;ゼロフラグが立っていないとき[$4D5D]分岐 $C0/4D5D LDA #$0000 ;Aに$0000をロード $C0/4D60 STA $0000,y[$7E:38E0] ;Aを[$7E:38E0]に書き込み $C0/4D63 INY ;Yをインクリメント +1 $C0/4D64 INY ;Yをインクリメント +1 $C0/4D65 LDA #$001D ;Aに$001Dをロード $C0/4D68 MVN DE 7E ;データ転送 ;A: 1D (転送データサイズ-1) ;X: ???? + $1E + $1E + $1E + $1E + $1E (転送元アドレス) ;Y: $38E2 (転送先アドレス) ;オペランド: 転送元バンクDE 転送先バンク7E ;$CF:????+$1E+$1E+$1E+$1E+$1E -> $7E:38E2 +$1E $C0/4D6B DEC $30 [$00:0030] ;[$00:0030]をデクリメント -1 $C0/4D6D BNE $EE [$4D5D] ;ゼロフラグが立っていないとき[$4D5D]分岐 $C0/4D6F SEP #$20 ;MフラグON Aレジスタは8bit幅 $C0/4D71 PLB ;DBレジスタにスタックからプル $C0/4D72 LDA $0240 [$00:0240] ;Aに[$00:0240]をロード $C0/4D75 BEQ $20 [$4D97] ;ゼロフラグが立っているとき[$4D97]分岐 $C0/4D97 LDY #$3840 ;Yに$3840をロード $C0/4D9A LDA #$06 ;Aに$06をロード $C0/4D9C JSR $C449 [$C0:C449] ;[$C0:C449]へジャンプ $C0/C449 STA $30 [$00:0030] ;Aを[$00:0030]に書き込み $C0/C44B LDA $10E2 [$00:10E2] ;Aに[$00:10E2]をロード $C0/C44E BEQ $4D [$C49D] ;ゼロフラグが立っているとき[$C49D]分岐 $C0/C49D RTS ;サブルーチン戻り $C0/4D9F LDA #$00 ;Aに$00をロード $C0/4DA1 STA $4300 [$00:4300] ;Aを[$00:4300]に書き込み $C0/4DA4 LDA #$22 ;Aに$22をロード $C0/4DA6 STA $4301 [$00:4301] ;Aを[$00:4301]に書き込み $C0/4DA9 LDX #$3840 ;Xに$3840をロード $C0/4DAC STX $4302 [$00:4302] ;Xを[$00:4303][$00:4302]に書き込み $C0/4DAF LDA #$7E ;Aに$7Eをロード $C0/4DB1 STA $4304 [$00:4304] ;Aを[$00:4304]に書き込み $C0/4DB4 LDX #$00C0 ;Xに$00C0をロード $C0/4DB7 STX $4305 [$00:4305] ;Xを[$00:4306][$00:4305]に書き込み $C0/4DBA LDA #$20 ;Aに$20をロード $C0/4DBC STA $2121 [$00:2121] ;Aを[$00:2121]に書き込み $C0/4DBF LDA #$01 ;Aに$01をロード $C0/4DC1 STA $420B [$00:420B] ;Aを[$00:420B]に書き込み ; ;[$00:2121] CGRAMのパレットアドレス開始位置 ※word単位 $20 ;[$00:4300] GDMA / HDMA設定レジスタ $00 ;[$00:4301] 転送先指定 $22=CGRAM ;[$00:4303][$00:4302] データ元アドレス(開始位置) $3840 ;[$00:4304] データ元バンク $7E ;[$00:4306][$00:4305] 転送するデータ量 $00C0 ;$7E:3840 -> CGRAM $20word($0040byte) +$00C0byte ; $C0/4DC4 LDA #$01 ;Aに$01をロード $C0/4DC6 STA $4300 [$00:4300] ;Aを[$00:4300]に書き込み $C0/4DC9 LDA #$18 ;Aに$18をロード $C0/4DCB STA $4301 [$00:4301] ;Aを[$00:4301]に書き込み $C0/4DCE LDX #$0000 ;Xに$0000をロード $C0/4DD1 STX $2116 [$00:2116] ;Xを[$00:2116]に書き込み $C0/4DD4 LDX #$2000 ;Xに$2000をロード $C0/4DD7 STX $26 [$00:0026] ;Xを[$00:0026]に書き込み $C0/4DD9 LDA $0120 [$00:0120] ;Aに[$00:0120]をロード $C0/4DDC STA $20 [$00:0020] ;Aを[$00:0020]に書き込み $C0/4DDE STZ $22 [$00:0022] ;[$00:0022]に$00を書き込み $C0/4DE0 JSR $4E8A [$C0:4E8A] ;[$C0:4E8A]へジャンプ
$C0/4D17~$C0/4D9Cで、$7E:3840~$7E:38FFにコピーされた値を、$C0/4D9F~$C0/4DE0で、CGRAMのアドレス$0040~$00FFにGDMA転送、という一連の処理が上。
これで背景用カラーパレットの値(CGRAMのアドレス$0000~$00FF)が揃ったことになる。
$7E:3840~$7E:38FFに入る値だが、バンクは$CF固定で、アドレスは[$00:0123]と[$00:0A0A]の値から決まる。
処理を見ると、
最終編:N = [$00:0123]+2
最終編以外:N = [$00:0123]
アドレス = ((N + [$00:0A0A]) & $00FF)*$4*$B4 + $E000
こんな感じで計算されているようだ。
次ページでは、戦闘でのサブルーチンを紹介する。