基礎知識
戦闘関係
戦闘では味方にターンが回った時にAボタンを押すと、コマンドが表示される。
通常は、
と、4つのコマンドが並ぶが、アキラがいるなら最後のコマンドが「テレポート」、キャプテンスクウェアのプレイ中なら「やめる」、最終編オルステッド主人公時に特定の条件を満たすと「ハルマゲドン」となる。
また、「ハルマゲドン」は操作キャラのHPが最大HPの25%以下になると出現するが、25%以上に回復すると表示が「逃げる」になり、選択すると「ハルマゲドン」が発動する、というバグっぽい挙動もある。
その他、「アイテムを使う」は一定条件下(SF・現代編、ブリキ大王操作時、最終編オルステッド主人公時)だと文字色が灰色になって使えないし、「逃げる」もボス戦など一部イベント戦闘では文字色が灰色になって選択できない。
というような表示の判別は、どう行っているのかを調べてみた。
ハルマゲドンのバグっぽい挙動は、最後の「ハルマゲドン用コマンドについて」で説明している。
重要なメモリアドレスを紹介。
$00:0043
「逃げる」が選べる戦闘は$00、選べない(逃げられない)戦闘は$01が入るアドレス。
「逃げる」だけではなく、「テレポート」「やめる」も含まれる。
戦闘に入る直前に$00:0043の値が決まる。シナリオ進行やエンカウントするエリアで値が決まるようだが未調査。
$00:1C00 + 40n (n = 0~3)
戦闘中に味方キャラIDが入るアドレス。
戦闘コマンド判定にも使うが、必要となるのはキャプテンスクウェアのキャラID$15と、テレポート判定のためのアキラのキャラID$11である。
| ID | キャラクター名 |
|---|---|
| $00 | オルステッド |
| $01 | ストレイボウ |
| $02 | ウラヌス |
| $03 | ハッシュ |
| $04 | ポゴ |
| $05 | ゴリ |
| $06 | べる |
| $07 | ざき |
| $08 | 心山拳老師 |
| $09 | ユン・ジョウ |
| $0A | レイ・クウゴ |
| $0B | サモ・ハッカ |
| $0C | サンダウン |
| $0D | マッドドッグ |
| $0E | おぼろ丸 |
| $0F | とらわれの男 |
| $10 | 高原 日勝 |
| $11 | アキラ |
| $12 | タロイモ |
| $13 | 無法松 |
| $14 | キューブ |
| $15 | キャプテンS |
| $16 | カラクリ丸 |
戦闘コマンドのテキストは4種類用意されていて、戦闘では$C1:FDA6~$C1:FDFCからロードする。
テキストのデコード・エンコードは文字コードの通り。
各コマンドの間は$01で区切られており、種類毎に$00で区切り。
デコード済みのテキストは以下のようになる。カッコ内は区切りの値。
| アドレス | テキスト |
|---|---|
$C1:FDA6~$C1:FDBA | 戦う($01)パス($01)アイテムを使う($01)逃げる($00) |
$C1:FDBB~$C1:FDCE | 戦う($01)パス($01)アイテムを使う($01)やめる($00) |
$C1:FDCF~$C1:FDE4 | 戦う($01)パス($01)アイテムを使う($01)テレポート($00) |
$C1:FDE5~$C1:FDFC | 戦う($01)パス($01)アイテムを使う($01)ハルマゲドン($00) |
上から順に、通常、キャプテンスクウェア、テレポート、ハルマゲドン時の戦闘コマンドということになる。
ここからは便宜上、「通常用コマンド」「キャプテンスクウェア用コマンド」「テレポート用コマンド」「ハルマゲドン用コマンド」とする。
味方ターンの時にAボタンを押すとコマンド表示用サブルーチンが回り、戦闘コマンドが「通常用コマンド」「キャプテンスクウェア用コマンド」「テレポート用コマンド」「ハルマゲドン用コマンド」とのどれが選ばれるか、以下のように判定される。
$C1/998E JSR $4FFB [$C1:4FFB] ;[$C1:4FFB]へジャンプ $C1/4FFB JSR $4FDC [$C1:4FDC] ;[$C1:4FDC]へジャンプ $C1/4FDC JSR $FD76 [$C1:FD76] ;[$C1:FD76]へジャンプ $C1/FD76 LDA $0A00 [$00:0A00] ;Aに[$00:0A00](シナリオID)をロード $C1/FD79 CMP #$08 ;Aと$08を減算比較(ステータスレジスタ変更のみ) $C1/FD7B BNE $03 [$FD80] ;ゼロフラグが立っていないとき[$FD80]分岐 ;ゼロフラグON 最終編 $C1/FD7D LDA $0A10 [$00:0A10] ;Aに[$00:0A10](最終編主人公ID)をロード ;ゼロフラグOFF 最終編ではない $C1/FD80 RTS ;サブルーチン戻り
最初の分岐は、[$00:0A00](シナリオID) - $08のゼロフラグ判定である。
| シナリオ | ID | 対応キャラクター |
|---|---|---|
| 中世 | $00 | オルステッド |
| 原始 | $01 | ポゴ |
| SF | $02 | キューブ |
| 功夫 | $03 | 心山拳老師 |
| 西部 | $04 | サンダウン |
| 現代 | $05 | 高原日勝 |
| 近未来 | $06 | アキラ |
| 幕末 | $07 | おぼろ丸 |
| 最終 | $08 | (主人公のシナリオIDが入る) |
$08は最終編であり、ゼロフラグが立って$C1/FD7Dに進む。その場合は[$00:0A10](最終編主人公ID)をAにロードする。
最終編以外のシナリオだと、減算結果は必ず負の値である。
一方、最終編以外は$C1/FD80でサブルーチンを抜ける。
よって、$C1/FD80の時点でゼロフラグが立っているのは、最終編主人公IDが$00、つまり最終編オルステッド主人公時のみということになる。
$C1/4FDF BNE $19 [$4FFA] ;ゼロフラグが立っていないとき[$4FFA]分岐 ;ゼロフラグON 最終編オルステッド主人公時 $C1/4FE1 LDX #$0D00 ;Xに$0D00をロード $C1/4FE4 REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/4FE6 LDA $000A,x[$00:0D0A] ;Aに[$00:0D0B][$00:0D0A](操作キャラ最大HP)をロード $C1/4FE9 LSR A ;Aを論理右シフト (/2) $C1/4FEA LSR A ;Aを論理右シフト (/2) $C1/4FEB CMP $0008,x[$00:0D08] ;Aと[$00:0D09][$00:0D08](操作キャラ現在HP)を減算比較(ステータスレジスタ変更のみ) $C1/4FEE SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/4FF0 BCC $08 [$4FFA] ;キャリーフラグが立っていないとき[$4FFA]分岐 ;キャリーフラグON ハルマゲドンコマンドON $C1/4FF2 LDA #$FF ;Aに$FFをロード $C1/4FF4 STA $7EFEFA[$7E:FEFA] ;Aを[$7E:FEFA]に書き込み $C1/4FF8 LDA #$00 ;Aに$00をロード ;ゼロフラグOFF 最終編オルステッド主人公時以外 またはハルマゲドンコマンドOFF $C1/4FFA RTS ;サブルーチン戻り $C1/4FFE BNE $02 [$5002] ;ゼロフラグが立っていないとき[$5002]分岐 ;ゼロフラグON ハルマゲドンコマンドON $C1/5000 BRA $13 [$5015] ;フラグにかかわりなく常に分岐[$5015] ;ゼロフラグOFF ハルマゲドンコマンドOFF $C1/5002 LDA #$15 ;Aに$15をロード $C1/5004 JSR $5040 [$C1:5040] ;[$C1:5040]へジャンプ ;ゼロフラグON ハルマゲドンコマンドONの飛び先 $C1/5015 LDX #$FDE5 ;Xに$FDE5をロード $C1/5018 BRA $08 [$5022] ;[$C1:5022]へジャンプ
$C1/4FDFに戻った時点でゼロフラグが立つのは、前述の通り最終編オルステッド主人公時のみ。
その場合、$C1/4FE1に進むが、$C1/4FE6でロードする[$00:0D0B][$00:0D0A]は、本来ならシナリオ別キャラデータのオルステッドの最大HPである。
$C1/4FEBでロードする[$00:0D09][$00:0D08]も、シナリオ別キャラデータのオルステッドの現在HPである。
だが、最終編オルステッド主人公時(2)で説明した通り、最終編オルステッド主人公時は、オルステッドのステータスの一部を、操作するボスキャラのステータスで上書きしながら戦闘を行う。
つまり、ここで呼び出すのは、最終編オルステッド主人公時の戦闘で操作しているボスキャラの現在HPと最大HPなのである。
$C1/4FE6~の処理を見てみると、
trunc(操作キャラ最大HP/4) - 操作キャラ現在HP
の計算結果でキャリーフラグ判定である。
減算の結果が0か正ならキャリーフラグONだが、これは現在HPがtrunc(操作キャラ最大HP/4)以下ということを意味する。
つまり、ハルマゲドンコマンド出現条件であり、この場合は$C1/4FF2に進んで、[$7E:FEFA]に$FFを書き込み、Aに$00をロードして、$C1/4FFAでサブルーチンを抜ける。
「ハルマゲドン用コマンド」の条件を満たす場合、[$7E:FEFA]に$FFが入り、この先の判定にも使われることになる。
一方、減算の結果が負ならキャリーフラグOFFで、$C1/4FFAでサブルーチンを抜けるが、これは他処理と合流である。
つまり、現在HPがtrunc(操作キャラ最大HP/4)より大きい場合は、他処理と合流である。
$C1/4FFEに戻った時点でゼロフラグ判定だが、ここでゼロフラグが立つのは、$C1/4FFAでゼロフラグONでサブルーチンを抜けてきた「ハルマゲドン用コマンド」の条件時のみである。
この時は、$C1/5000→$C1/5015とジャンプするが、その場合はXに$FDE5をロードしてから[$C1:5022]へジャンプとなる。
$C1/5022からが、戦闘コマンドテキスト呼び出しのサブルーチンになり、他処理との合流地点でもあるが、後述する。
以上から、$C1/4FDF~$C1/4FFAが、「ハルマゲドン用コマンド」の判定用サブルーチンということがわかった。
「ハルマゲドン用コマンド」出現条件は、最終編オルステッド主人公時、かつ、現在HPがtrunc(操作キャラ最大HP/4)以下ということも判明した。
一方、最終編以外か、最終編でもオルステッド主人公時のハルマゲドンコマンドOFFだと、$C1/4FFEでゼロフラグが立たない。
よって、$C1/5002に進み、Aに$15をロードして$C1/5040へジャンプする。
この先はキャプテンスクウェア用判定である。
$C1/5040 STA $10 [$00:0310] ;A($15)を[$00:0310]に書き込み $C1/5042 LDX #$1C00 ;Xに$1C00をロード $C1/5045 LDA $0001,x[$00:1C01] ;Aに[$00:1C01]をロード $C1/5048 BIT #$40 ;Aと$40で論理積(ステータスフラグ変更のみ) $C1/504A BEQ $0E [$505A] ;ゼロフラグが立っているとき[$505A]分岐 ;ゼロフラグOFF $00:戦闘離脱 $20:味方キャラ敵対 ではない $C1/504C LDA $0039,x[$00:1C39] ;Aに[$00:1C39](状態異常)をロード $C1/504F CMP #$FF ;Aと$FFを減算比較(ステータスレジスタ変更のみ) $C1/5051 BEQ $07 [$505A] ;ゼロフラグが立っているとき[$505A]分岐 ;ゼロフラグOFF 戦闘不能ではない $C1/5053 LDA $0000,x[$00:1C00] ;Aに[$00:1C00](キャラID)をロード $C1/5056 CMP $10 [$00:0310] ;Aと[$00:0310]($15)を減算比較(ステータスレジスタ変更のみ) $C1/5058 BEQ $0F [$5069] ;ゼロフラグが立っているとき[$5069]分岐 ;ゼロフラグOFF キャプテンスクウェアではない、または該当キャラが戦闘不能・戦闘離脱 $C1/505A REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/505C TXA ;Xレジスタの値をAレジスタに転送 $C1/505D ADC #$0040 ;A + $0040 $C1/5060 TAX ;Aの値をXレジスタに転送 $C1/5061 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/5063 CPX #$1D00 ;Xと$1D00を減算比較(ステータスレジスタ変更のみ) $C1/5066 BNE $DD [$5045] ;ゼロフラグが立っていないとき[$5045]分岐 ;ゼロフラグON 操作キャラにキャプテンスクウェアが含まれない $C1/5068 RTS ;サブルーチン戻り ;$C1/5058でゼロフラグON キャプテンスクウェア $C1/5069 LDA #$FF ;Aに$FFをロード $C1/506B RTS ;サブルーチン戻り
[$00:0310]に$15を書き込んだ後は、戦闘コマンドを開く味方キャラの状態の判定である。
ここでは、味方キャラ1としておく。その場合はX:1C00である。
$C1/5045から、[$00:1C01]、つまり味方キャラの現在の状態をロードし、$40と論理積をとってゼロフラグ判定だが、ゼロフラグが立たないのは、戦闘離脱状態か、味方キャラが敵対状態の時であり、通常、戦闘中に戦闘コマンドを開く時点で、どちらでもないはずである。
続いて、$C1/504Cから、[$00:1C39](状態異常)と$FFで減算比較し、ゼロフラグ判定である。
つまり[$00:1C39](状態異常)が$FFかどうかだが、状態異常が$FFということは戦闘不能状態のことなので、こちらでも通常、戦闘中に戦闘コマンドを開く時点で、戦闘不能はありえないはずである。
ということで、おそらく通常なら$C1/5053まで処理が進むはずである。
$C1/5053からは[$00:1C00](味方キャラID)と[$00:0310]($15)との減算比較でゼロフラグ判定である。
味方キャラIDが$15はキャプテンS、つまりキャプテンスクウェアである。
ゼロフラグが立っているのなら、$C1/5058→$C1/5069でAに$FFをロードしてサブルーチンが戻る。
ゼロフラグが立っていないのなら$C1/505Aからの処理だが、これは味方キャラ全員を判定するための処理へ飛ぶ準備になる。
キャプテンスクウェアかどうかの判定なら、X:1C00の時だけ判定すれば良いような気もするが、後述の通り、このサブルーチンはテレポート判定(アキラがパーティにいるかどうか)にも使っている汎用サブルーチンなので、全員分の判定となる。
$C1/505Dで、X:1C00 + $0040を計算しているから、味方キャラ2呼び出し用のX:1C40を算出している。
$C1/5063でXと$1D00の減算比較をし、ゼロフラグOFFなら$C1/5045に戻るから、
X:1C00, 1C40, 1C80ならループ頭に戻るX:1CC0だと+$40して$1D00になるからループを抜け、$C1/5068でサブルーチンを戻るという処理であり、味方キャラ4人全員分、味方キャラIDが$15かどうかの判定を行うことになる。
4キャラ全員がキャプテンスクウェアではない場合、最後の減算比較は$1D00 - $1D00で、ゼロフラグが立った状態で$C1/5068でサブルーチンを抜けることになる。
$C1/5007 BNE $11 [$501A] ;ゼロフラグが立っていないとき[$501A]分岐 ;ゼロフラグON キャプテンスクウェアではない $C1/5009 LDA #$11 ;Aに$11をロード $C1/500B JSR $5040 [$C1:5040] ;[$C1:5040]へジャンプ ;ゼロフラグOFF キャプテンスクウェア $C1/501A LDX #$FDBB ;Xに$FDBBをロード $C1/501D BRA $03 [$5022] ;[$C1:5022]へジャンプ
$C1/5007でゼロフラグ分岐となり、ゼロフラグOFF、つまり操作キャラがキャプテンスクウェアの時は、「キャプテンスクウェア用コマンド」確定で、Xに$FDBBをロードして、[$C1:5022]へジャンプである。
ハルマゲドンコマンドに続き、ここでキャプテンスクウェア時の判定が終了である。
一方、キャプテンスクウェアが操作キャラに含まれなかった場合はゼロフラグが立ち、Aに$11をロードして[$C1:5040]へジャンプだが、これは先程、キャプテンスクウェアのIDと一致するかどうかを判定したサブルーチンと同じである。
今度は比較するキャラIDが$11、つまりアキラかどうかに変わるということである。
$C1/5040 STA $10 [$00:0310] ;A($11)を[$00:0310]に書き込み $C1/5042 LDX #$1C00 ;Xに$1C00をロード $C1/5045 LDA $0001,x[$00:1C01] ;Aに[$00:1C01](戦闘状態)をロード $C1/5048 BIT #$40 ;Aと$40で論理積(ステータスフラグ変更のみ) $C1/504A BEQ $0E [$505A] ;ゼロフラグが立っているとき[$505A]分岐 ;ゼロフラグOFF 戦闘離脱ではない $C1/504C LDA $0039,x[$00:1C39] ;Aに[$00:1C39](状態異常)をロード $C1/504F CMP #$FF ;Aと$FFを減算比較(ステータスレジスタ変更のみ) $C1/5051 BEQ $07 [$505A] ;ゼロフラグが立っているとき[$505A]分岐 ;ゼロフラグOFF 戦闘不能ではない $C1/5053 LDA $0000,x[$00:1C00] ;Aに[$00:1C00]をロード $C1/5056 CMP $10 [$00:0310] ;Aと[$00:0310]($11 アキラのID)を減算比較(ステータスレジスタ変更のみ) $C1/5058 BEQ $0F [$5069] ;ゼロフラグが立っているとき[$5069]分岐 ;ゼロフラグOFF キャラがアキラではない、または該当キャラが戦闘不能・戦闘離脱 $C1/505A REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/505C TXA ;Xレジスタの値をAレジスタに転送 $C1/505D ADC #$0040 ;A + $0040 $C1/5060 TAX ;Aの値をXレジスタに転送 $C1/5061 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/5063 CPX #$1D00 ;Xと$1D00を減算比較(ステータスレジスタ変更のみ) $C1/5066 BNE $DD [$5045] ;ゼロフラグが立っていないとき[$5045]分岐 ;ゼロフラグON 操作キャラにアキラが含まれない $C1/5068 RTS ;サブルーチン戻り ;$C1/5058でゼロフラグON キャラがアキラ かつ戦闘不能・戦闘離脱ではない $C1/5069 LDA #$FF ;Aに$FFをロード $C1/506B RTS ;サブルーチン戻り
判定はキャプテンスクウェア時と同じなのだが、今回は、近未来編・最終編両方に登場するアキラの判定で、他に仲間キャラがいる場合もある、という点が重要。
処理を追って考えると、
アキラが戦闘離脱または戦闘不能ではない状態で、パーティ内にいる状態なら、$C1/5069にたどりつく(「テレポート用コマンド」ON)
と、いうことがわかる。
このため、アキラが戦闘離脱または戦闘不能ではない状態でパーティにいるのなら、アキラ以外のキャラの戦闘コマンドを開いた時でも、「逃げる」が「テレポート」に変わるのである。
また、「テレポート」コマンドが表示される条件は、アキラが戦闘離脱または戦闘不能ではない状態、ということもわかる。
アキラ自身が行動できない、マヒや眠り、石化状態の時でも、テレポートが可能なのはここの分岐処理のためである。
さて、アキラが戦闘離脱または戦闘不能ではない状態で、パーティ内にいる状態なら、Aに$FFをロードしてサブルーチンを戻り、それ以外はゼロフラグが立った状態でサブルーチンが戻る。
$C1/500E BNE $0F [$501F] ;ゼロフラグが立っていないとき[$501F]分岐 ;ゼロフラグON 「テレポート用コマンド」OFF $C1/5010 LDX #$FDA6 ;Xに$FDA6をロード $C1/5013 BRA $0D [$5022] ;フラグにかかわりなく常に分岐[$5022] ;ゼロフラグOFF 「テレポート用コマンド」ON $C1/501F LDX #$FDCF ;Xに$FDCFをロード ;ハルマゲドンコマンド・キャプテンスクウェア処理と合流 $C1/5022 STX $DC [$00:03DC] ;Xを[$00:03DD][$00:03DC]に書き込み $C1/5024 LDX #$1200 ;Xに$1200をロード $C1/5027 STX $D8 [$00:03D8] ;Xを[$00:03D9][$00:03D8]に書き込み $C1/5029 JSR $506C [$C1:506C] ;[$C1:506C]へジャンプ
$C1/500Eはキャプテンスクウェアと同じくゼロフラグ分岐で、「テレポート用コマンド」ONならXに$FDCFをロード、それ以外ならXに$FDA6をロードである。
その先の$C1/5022が、これまでの「ハルマゲドン用コマンド」「キャプテンスクウェア用コマンド」確定時のジャンプ先であり、ここで処理が合流である。
それぞれ直前に、Xに別の値を読み込んでいる。
| 戦闘コマンド | Xの値 |
|---|---|
| ハルマゲドン用コマンド | $FDE5 |
| キャプテンスクウェア用コマンド | $FDBB |
| テレポート用コマンド | $FDCF |
| 通常 | $FDA6 |
ここまでで実質、戦闘コマンド表示の分岐は終了である。
後はコマンドを実際にゲーム画面に表示するための処理になる。
ここまでで決まったのは、あくまでも戦闘コマンドに表示する文字列である。
該当コマンドが使用可能かどうか、つまり文字色が黒になるか灰色になるかは、まだ判定していない。
また、もうひとつ、味方キャラの座標によって戦闘コマンドの表示位置が4ヶ所あるのだが(味方キャラ位置を隠さないようにするため、右上・右下・左上・左下の4ヶ所のいずれかに戦闘コマンドが表示される)、その分岐も行っていないため、この先で味方キャラ座標から判定をする。
ということで以降はある意味おまけではあるが、続けて説明していく。
Xの値は$C1/5022で[$00:03DD][$00:03DC]に書き込まれ、Xに$1200をロードしてから[$00:03D9][$00:03D8]に書き込み、[$C1:506C]にジャンプする。
$C1/506C LDX #$B000 ;Xに$B000をロード $C1/506F STX $D6 [$00:03D6] ;Xを[$00:03D7][$00:03D6]に書き込み $C1/5071 LDA #$00 ;Aに$00をロード $C1/5073 STZ $E0 [$00:03E0] ;[$00:03E0]に$00を書き込み $C1/5075 RTS ;サブルーチン戻り $C1/502C LDA #$08 ;Aに$08をロード $C1/502E STA $E3 [$00:03E3] ;A($08)を[$00:03E3]に書き込み $C1/5030 STA $E1 [$00:03E1] ;A($08)を[$00:03E1]に書き込み $C1/5032 LDA #$04 ;Aに$04をロード $C1/5034 STA $E2 [$00:03E2] ;A($04)を[$00:03E2]に書き込み $C1/5036 LDA #$C1 ;Aに$C1をロード $C1/5038 JSR $3E4B [$C1:3E4B] ;[$C1:3E4B]へジャンプ $C1/3E4B JSR $3E61 [$C1:3E61] ;[$C1:3E61]へジャンプ
この先から戦闘コマンドの文字列の取得用ループ処理に移るのだが、その前の準備が上。
| アドレス | 値 |
|---|---|
[$00:03DD][$00:03DC] | (コマンド別の値) |
[$00:03D9][$00:03D8] | $1200 |
[$00:03D7][$00:03D6] | $B000 |
[$00:03E0] | $00 |
[$00:03E1] | $08 |
[$00:03E2] | $04 |
[$00:03E3] | $08 |
このように値が入った状態、かつ、Aに$C1が入った状態で[$C1:3E61]へジャンプする。
;文字列取得 $7E:FF00~$7E:FF60 $C1/3E61 LDX #$0000 ;Xに$0000をロード $C1/3E64 PHB ;DBレジスタをスタックにプッシュ $C1/3E65 PHA ;Aをスタックにプッシュ $C1/3E66 PLB ;DBレジスタに値をプル $C1/3E67 PHY ;Yをスタックへプッシュ $C1/3E68 LDY $DC [$00:03DC] ;Yに[$00:03DD][$00:03DC]をロード $C1/3E6A CMP #$7E ;A($C1)と$7Eを減算比較(ステータスレジスタ変更のみ) $C1/3E6C BNE $04 [$3E72] ;ゼロフラグが立っていないとき[$3E72]分岐 ;ゼロフラグON $C1/3E6E LDA #$0C ;Aに$0Cをロード $C1/3E70 BRA $02 [$3E74] ;フラグにかかわりなく常に分岐[$3E74] ;ゼロフラグOFF $C1/3E72 LDA #$60 ;Aに$60をロード $C1/3E74 STA $08 [$00:0308] ;A($60)を[$00:0308]に書き込み $C1/3E76 STZ $09 [$00:0309] ;[$00:0309]に$00を書き込み ;ループ処理開始 X:$0000で開始 $C1/3E78 LDA $0000,y[$C1:FDCF] ;Aに[$0000,y]をロード $C1/3E7B INY ;Yをインクリメント +1 $C1/3E7C CMP #$1D ;Aと$1Dを減算比較(ステータスレジスタ変更のみ) $C1/3E7E BEQ $2D [$3EAD] ;ゼロフラグが立っているとき[$3EAD]分岐 ;ゼロフラグOFF 漢字判定(1)$1Dではない $C1/3E80 CMP #$1E ;Aと$1Eを減算比較(ステータスレジスタ変更のみ) $C1/3E82 BEQ $29 [$3EAD] ;ゼロフラグが立っているとき[$3EAD]分岐 ;ゼロフラグOFF 漢字判定(2)$1Eではない $C1/3E84 CMP #$1F ;Aと$1Fを減算比較(ステータスレジスタ変更のみ) $C1/3E86 BEQ $25 [$3EAD] ;ゼロフラグが立っているとき[$3EAD]分岐 ;ゼロフラグOFF 漢字判定(3)$1Fではない $C1/3E88 CMP #$0E ;Aと$0Eを減算比較(ステータスレジスタ変更のみ) $C1/3E8A BEQ $16 [$3EA2] ;ゼロフラグが立っているとき[$3EA2]分岐 ;ゼロフラグOFF $0Eではない $C1/3E8C CMP #$07 ;Aと$07を減算比較(ステータスレジスタ変更のみ) $C1/3E8E BNE $26 [$3EB6] ;ゼロフラグが立っていないとき[$3EB6]分岐 ;ゼロフラグON $07「‥‥」 $C1/3E90 LDA #$3D ;Aに$3D「‥」をロード $C1/3E92 STA $7EFF00,x[$7E:FF00] ;Aを[$7EFF00,x]に書き込み $C1/3E96 INX ;Xをインクリメント +1 $C1/3E97 LDA #$3D ;Aに$3D「‥」をロード $C1/3E99 STA $7EFF00,x[$7E:FF00] ;Aを[$7EFF00,x+1]に書き込み $C1/3E9D INX ;Xをインクリメント +1 $C1/3E9E LDA #$00 ;Aに$00(終了用)をロード $C1/3EA0 BRA $14 [$3EB6] ;フラグにかかわりなく常に分岐[$3EB6] ;$C1/3E8AでゼロフラグON $0Eである $C1/3EA2 LDA #$21 ;Aに$21をロード $C1/3EA4 STA $7EFF00,x[$7E:FF00] ;Aを[$7EFF00,x]に書き込み $C1/3EA8 INX ;Xをインクリメント +1 $C1/3EA9 LDA #$00 ;Aに$00をロード $C1/3EAB BRA $09 [$3EB6] ;フラグにかかわりなく常に分岐[$3EB6] ;漢字処理($1D, $1E $1F) $C1/3EAD STA $7EFF00,x[$7E:FF00] ;Aを[$7EFF00,x]に書き込み $C1/3EB1 INX ;Xをインクリメント +1 $C1/3EB2 LDA $0000,y[$C1:FDD0] ;Aに[$0000,y+1]をロード $C1/3EB5 INY ;Yをインクリメント +1 ;処理合流 $C1/3EB6 STA $7EFF00,x[$7E:FF01] ;Aを[$7EFF00,x]に書き込み $C1/3EBA INX ;Xをインクリメント +1 $C1/3EBB CPX $08 [$00:0308] ;Xと[$00:0308](初期値$60)を減算比較(ステータスレジスタ変更のみ) $C1/3EBD BCC $B9 [$3E78] ;キャリーフラグが立っていないとき[$3E78]分岐 ;ループ処理ここまで $C1/3EBF LDA #$00 ;Aに$00をロード $C1/3EC1 STA $7EFF00,x[$7E:AF00] ;$00を[$7EFF00,x]に書き込み $C1/3EC5 PLY ;Yレジスタにスタックからプル $C1/3EC6 PLB ;DBレジスタにスタックからプル $C1/3EC7 RTS ;サブルーチン戻り
$0000,y(yはコマンド別の値)のYを増やしながらを$7E:FF00から$7E:FF60まで61バイト分埋める(厳密には$7E:FF5Fまでで、最後の$7E:FF60は$00を書き込むから、60バイトのコピー)というループ処理である。
ループ前、X初期値として$0000を入れ、X:0060まで増加したら($7E:FF5Fまで値を書き込んだら)ループをぬける仕組み。
文字コードによって分岐がある。
テキストのデコード・エンコードは文字コードにあり、今回はデコードしながら$7E:FF00~へ書き込む作業になるが、
という分岐があり、これ以外ならそのままの値を$7E:FF00~へ書き込んでいる。
例として、テレポート用コマンドだった場合を考えてみよう。
この場合、[$00:03DD][$00:03DC]に入っているのは$FDCFで、$C1/3E78のループ1周目の$0000,yのアドレスは$C1:FDCFである。
つまり、テレポート用コマンド文字列の開始位置は$C1:FDCFである。
ループを開始すると、まずYを+1する(次のアドレス呼び出し用)。
$C1:FDCFからの値は、
と入っているのだが、$C1:FDCFは「$1E」だから、ループ処理にかけると$C1/3E82の$1Eかどうかの判定でゼロフラグが立って、漢字処理の$C1/3EADに飛ぶ。
$C1/3EADで、まず[$7E:FF00]に$1Eを書き込み、Xを+1する。
続いて、$C1:FDCFの次のアドレス、$C1:FDD0($A4)をロードし、Yをインクリメント+1して、他処理との合流$C1/3EB6にて[$7EFF00,x]、つまり$7E:FF01にAを書き込み、Xをインクリメント+1してループ頭に戻る。
というように処理が進む。
60バイト分コピーするが、戦闘用コマンドの場合、長くても23バイト分の読み込みで事足りる。
つまり過剰に読み込んでいるのだが、この文字列コピー処理は他でも使われる汎用のサブルーチンであるため。
また、漢字は2バイトで成立しているため、最後の$7E:FF5Fへのコピー時に漢字2バイト分、$7E:FF5Fと$7E:FF60に書き込むというケースもあり得る。
その時も最終的に$C1/3EBFでと$7E:FF60を00を上書きするので、最後の漢字は完全な形ではコピーされないことになる。
それも含めて、60バイトと余分に文字列を読み込み、$7E:FF00~$7E:FF60へコピーしているのだと思われる。
この先は、$7E:FF00~$7E:FF60へコピーしたデータから、文字の画像データをロードしていくサブルーチンである。
$C1/3E4E BRL $0077 [$3EC8] ;フラグにかかわりなく常に分岐[$3EC8] $C1/3EC8 LDX #$0000 ;Xに$0000をロード $C1/3ECB STX $DC [$00:03DC] ;X($0000)を[$00:03DD][$00:03DC]に書き込み $C1/3ECD STZ $DF [$00:03DF] ;[$00:03DF]に$00を書き込み $C1/3ECF STZ $A7 [$00:03A7] ;[$00:03A7]に$00を書き込み ;ループ処理開始 $C1/3ED1 LDA $A7 [$00:03A7] ;Aに[$00:03A7](初期値$00)をロード $C1/3ED3 BEQ $04 [$3ED9] ;ゼロフラグが立っているとき[$3ED9]分岐 $C1/3ED9 LDX $DC [$00:03DC] ;Xに[$00:03DD][$00:03DC](初期値$0000)をロード $C1/3EDB LDA $7EFF00,x ;Aに[$7E:FF00+x]をロード $C1/3EDF STA $DE [$00:03DE] ;Aを[$00:03DE]に書き込み $C1/3EE1 INX ;Xをインクリメント +1 $C1/3EE2 STX $DC [$00:03DC] ;Xを[$00:03DD][$00:03DC](初期値$0000+1)に書き込み $C1/3EE4 CMP #$00 ;A([$7E:FF00+x])と$00を減算比較(ステータスレジスタ変更のみ) $C1/3EE6 BNE $03 [$3EEB] ;ゼロフラグが立っていないとき[$3EEB]分岐 ;ゼロフラグON($00は文字列終了) $C1/3EE8 BRL $0054 [$3F3F] ;フラグにかかわりなく常に分岐[$3F3F]→★ループ抜ける ;ゼロフラグOFF(文字列終了ではない) $C1/3EEB CMP #$01 ;Aと$01を減算比較(ステータスレジスタ変更のみ) $C1/3EED BNE $03 [$3EF2] ;ゼロフラグが立っていないとき[$3EF2]分岐 ;ゼロフラグON(01は改行) $C1/3EEF BRL $0062 [$3F54] ;フラグにかかわりなく常に分岐[$3F54]→☆ループ抜ける ;ゼロフラグOFF(改行ではない) $C1/3EF2 CMP #$0A ;Aと$0Aを減算比較(ステータスレジスタ変更のみ) $C1/3EF4 BEQ $0C [$3F02] ;ゼロフラグが立っているとき[$3F02]分岐 ;ゼロフラグOFF $0A「スペース×2」ではない $C1/3EF6 CMP #$0B ;Aと$0Bを減算比較(ステータスレジスタ変更のみ) $C1/3EF8 BEQ $06 [$3F00] ;ゼロフラグが立っているとき[$3F00]分岐 ;ゼロフラグOFF $0B「スペース×3」ではない $C1/3EFA CMP #$0C ;Aと$0Cを減算比較(ステータスレジスタ変更のみ) $C1/3EFC BNE $0A [$3F08] ;ゼロフラグが立っていないとき[$3F08]分岐 ;ゼロフラグON $0B「スペース×4」 $C1/3EFE INC $A7 [$00:03A7] ;[$00:03A7]をインクリメント +1 $C1/3F00 INC $A7 [$00:03A7] ;[$00:03A7]をインクリメント +1 $C1/3F02 INC $A7 [$00:03A7] ;[$00:03A7]をインクリメント +1 $C1/3F04 STZ $DE [$00:03DE] ;[$00:03DE]に$00を書き込み $C1/3F06 BRA $1B [$3F23] ;フラグにかかわりなく常に分岐[$3F23] ;ゼロフラグOFF $0B「スペース×4」ではない $C1/3F08 CMP #$1D ;Aと$1Dを減算比較(ステータスレジスタ変更のみ) $C1/3F0A BEQ $08 [$3F14] ;ゼロフラグが立っているとき[$3F14]分岐 ;ゼロフラグOFF 漢字判定(1)$1Dではない $C1/3F0C CMP #$1E ;Aと$1Eを減算比較(ステータスレジスタ変更のみ) $C1/3F0E BEQ $04 [$3F14] ;ゼロフラグが立っているとき[$3F14]分岐 ;ゼロフラグOFF 漢字判定(2)$1Eではない $C1/3F10 CMP #$1F ;Aと$1Fを減算比較(ステータスレジスタ変更のみ) $C1/3F12 BNE $0F [$3F23] ;ゼロフラグが立っているとき[$3F23]分岐 ;ゼロフラグOFF 漢字判定 $1D, $1E, $1Fのいずれか $C1/3F14 SBC #$1C ;A([$7E:FF00+x]) - $1C $C1/3F16 STA $DF [$00:03DF] ;Aを[$00:03DF]に書き込み $C1/3F18 LDA $7EFF00,x ;Aに[$7E:FF00+ x+1]をロード $C1/3F1C INX ;Xをインクリメント +1 $C1/3F1D STX $DC [$00:03DC] ;Xを[$00:03DC]に書き込み $C1/3F1F STA $DE [$00:03DE] ;Aを[$00:03DE]に書き込み $C1/3F21 BRA $02 [$3F25] ;フラグにかかわりなく常に分岐[$3F25] ;$C1/3F12でゼロフラグON 漢字ではない $C1/3F23 STZ $DF [$00:03DF] ;[$00:03DF]に$00を書き込み ;処理合流 $C1/3F25 JSR $5095 [$C1:5095] ;[$C1:5095]へジャンプ ;文字ビットマップ呼び出し ;符号付16bit x 8bitでアドレスを計算 [$00:03DF][$00:03DE] * $18 $C1/5095 LDA $DE [$00:03DE] ;Aに[$00:03DE]をロード $C1/5097 STA $211B [$00:211B] ;Aを[$00:211B]に書き込み $C1/509A LDA $DF [$00:03DF] ;Aに[$00:03DF]をロード $C1/509C STA $211B [$00:211B] ;Aを[$00:211B]に書き込み $C1/509F LDA #$18 ;Aに$18をロード $C1/50A1 STA $211C [$00:211C] ;Aを[$00:211C]に書き込み $C1/50A4 STA $211C [$00:211C] ;Aを[$00:211C]に書き込み $C1/50A7 REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/50A9 LDA #$9200 ;Aに$9200をロード $C1/50AC ADC $2134 [$00:2134] ;A + [$00:2135][$00:2134] ;$9200 + [$00:03DF][$00:03DE] * $18 $C1/50AF TAX ;Aの値をXレジスタに転送 $C1/50B0 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/50B2 LDA $E0 [$00:03E0] ;Aに[$00:03E0](初期値$00)をロード $C1/50B4 AND #$01 ;Aと$01で論理積 $C1/50B6 BEQ $03 [$50BB] ;ゼロフラグが立っているとき[$50BB]分岐 ;ゼロフラグOFF $C1/50B8 BRL $0030 [$50EB] ;フラグにかかわりなく常に分岐[$50EB] ;ゼロフラグON([$00:03E0]が偶数処理) $C1/50BB PHB ;DBレジスタをスタックにプッシュ $C1/50BC LDA #$7E ;Aに$7Eをロード $C1/50BE PHA ;Aをスタックにプッシュ $C1/50BF PLB ;DBレジスタに値をプル $C1/50C0 LDY $D6 [$00:03D6] ;Yに[$00:03D7][$00:03D6](初期値$B000)をロード $C1/50C2 LDA #$0C ;Aに$0Cをロード $C1/50C4 STA $08 [$00:0308] ;Aを[$00:0308]に書き込み ;ループ処理ここから $C1/50C6 LDA $D40000,x ;Aに[$D40000,x]をロード $C1/50CA STA $0005,y ;Aを[$7E:B005,y]に書き込み $C1/50CD LDA $D40001,x ;Aに[$D40001,x]をロード $C1/50D1 STA $0025,y ;Aを[$7E:B025,y]に書き込み $C1/50D4 INX ;Xをインクリメント +1 $C1/50D5 INX ;Xをインクリメント +1 $C1/50D6 INY ;Yをインクリメント +1 $C1/50D7 INY ;Yをインクリメント +1 $C1/50D8 DEC $08 [$00:0308] ;[$00:0308]をデクリメント -1 $C1/50DA BNE $EA [$50C6] ;ゼロフラグが立っていないとき[$50C6]分岐 ;ループ処理ここまで $C1/50DC REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/50DE LDA $D6 [$00:03D6] ;Aに[$00:03D7][$00:03D6](初期値$B000)をロード $C1/50E0 ADC #$0020 ;A + $0020 $C1/50E3 STA $D6 [$00:03D6] ;Aを[$00:03D7][$00:03D6](初期値$B000 + $0020)に書き込み $C1/50E5 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/50E7 INC $E0 [$00:03E0] ;[$00:03E0]をインクリメント +1 $C1/50E9 PLB ;DBレジスタに値をプル $C1/50EA RTS ;サブルーチン戻り ;$C1/50B8から([$00:03E0]が奇数処理) $C1/50EB PHB ;DBレジスタをスタックにプッシュ $C1/50EC LDA #$7E ;Aに$7Eをロード $C1/50EE PHA ;Aレジスタをスタックにプッシュ $C1/50EF PLB ;DBレジスタにスタックからプル $C1/50F0 LDY $D6 [$00:03D6] ;Yに[$00:03D7][$00:03D6](初期値$B000)をロード $C1/50F2 LDA #$0C ;Aに$0Cをロード $C1/50F4 STA $08 [$00:0308] ;Aを[$00:0308]に書き込み ;ループ処理ここから $C1/50F6 LDA $D40001,x ;Aに[$D40001,x]をロード $C1/50FA STA $00211B[$00:211B] ;Aを[$00:211B]に書き込み $C1/50FE LDA $D40000,x ;Aに[$D40000,x]をロード $C1/5102 STA $00211B[$00:211B] ;Aを[$00:211B]に書き込み $C1/5106 LDA #$10 ;Aに$10をロード $C1/5108 STA $00211C[$00:211C] ;Aを[$00:211C]に書き込み $C1/510C STA $00211C[$00:211C] ;Aを[$00:211C]に書き込み $C1/5110 LDA $002136[$00:2136] ;Aに[$00:2136]をロード $C1/5114 AND #$0F ;Aと$0Fで論理積 $C1/5116 ORA $0005,y ;Aと[$7E:B005+y]で論理和 $C1/5119 STA $0005,y ;Aを[$7E:B005+y]に書き込み $C1/511C LDA $002135[$00:2135] ;Aに[$00:2135]をロード $C1/5120 STA $0025,y ;Aを[$7E:B025+y]に書き込み $C1/5123 INX ;Xをインクリメント +1 $C1/5124 INX ;Xをインクリメント +1 $C1/5125 INY ;Yをインクリメント +1 $C1/5126 INY ;Yをインクリメント +1 $C1/5127 DEC $08 [$00:0308] ;[$00:0308]をデクリメント -1 $C1/5129 BNE $CB [$50F6] ;ゼロフラグが立っていないとき[$50F6]分岐 ;ループ処理ここまで $C1/512B REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/512D LDA $D6 [$00:03D6] ;Aに[$00:03D6](初期値$B000)をロード $C1/512F ADC #$0040 ;A + $0040 $C1/5132 STA $D6 [$00:03D6] ;Aを[$00:03D6](初期値$B000 + $0020)に書き込み $C1/5134 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/5136 INC $E0 [$00:03E0] ;[$00:03E0]をインクリメント +1 $C1/5138 PLB ;DBレジスタにスタックからプル $C1/5139 RTS ;サブルーチン戻り ;文字ビットマップ呼び出しここまで $C1/3F28 DEC $E1 [$00:03E1] ;[$00:03E1]をデクリメント -1 $C1/3F2A BNE $A5 [$3ED1] ;ゼロフラグが立っていないとき[$3ED1]分岐 ;ループここまで ;$C1/3EE8 $00で文字列終了、★ループ抜ける $C1/3F3F LDA $8B [$00:038B] ;Aに[$00:038B]をロード $C1/3F41 BEQ $03 [$3F46] ;ゼロフラグが立っているとき[$3F46]分岐 $C1/3F46 JSR $3F72 [$C1:3F72] ;[$C1:3F72]へジャンプ ;$C1/3EEF $01は改行、☆ループ抜ける $C1/3F54 LDA $E1 [$00:03E1] ;Aに[$00:03E1]をロード $C1/3F56 CMP $E3 [$00:03E3] ;Aと[$00:03E3]を減算比較(ステータスレジスタ変更のみ) $C1/3F58 BEQ $06 [$3F60] ;ゼロフラグが立っているとき[$3F60]分岐 $C1/3F5A JSR $3F72 [$C1:3F72] ;[$C1:3F72]へジャンプ ;$C1/3F46または$C1/3F5Aからのジャンプ先 $C1/3F72 STZ $DF [$00:03DF] ;[$00:03DF]に$00を書き込み $C1/3F74 STZ $DE [$00:03DE] ;[$00:03DE]に$00を書き込み $C1/3F76 JSR $5095 [$C1:5095] ;[$C1:5095]へジャンプ→文字ビットマップ呼び出し $C1/3F79 DEC $E1 [$00:03E1] ;[$00:03E1]をデクリメント -1 $C1/3F7B BNE $F9 [$3F76] ;ゼロフラグが立っていないとき[$3F76]分岐 ;ゼロフラグON $C1/3F7D RTS ;サブルーチン戻り ;ここで1行分終わり $C1/3F49 LDA $E3 [$00:03E3] ;Aに[$00:03E3]をロード $C1/3F4B STA $E1 [$00:03E1] ;Aを[$00:03E1]に書き込み $C1/3F4D DEC $E2 [$00:03E2] ;[$00:03E2]をデクリメント -1 $C1/3F4F BNE $F5 [$3F46] ;ゼロフラグが立っていないとき[$3F46]分岐 $C1/3F51 BRL $FFE7 [$3F3B] ;フラグにかかわりなく常に分岐[$3F3B] $C1/3F3B JSR $5076 [$C1:5076] ;[$C1:5076]へジャンプ $C1/5076 LDA $E0 [$00:03E0] ;Aに[$00:03E0]をロード $C1/5078 INC A ;Aをインクリメント +1 $C1/5079 AND #$FE ;Aと$FEで論理積 $C1/507B STA $211B [$00:211B] ;Aを[$00:211B]に書き込み $C1/507E LDA #$00 ;Aに$00をロード $C1/5080 STA $211B [$00:211B] ;Aを[$00:211B]に書き込み $C1/5083 LDA #$30 ;Aに$30をロード $C1/5085 STA $211C [$00:211C] ;Aを[$00:211C]に書き込み $C1/5088 STA $211C [$00:211C] ;Aを[$00:211C]に書き込み $C1/508B LDX $2134 [$00:2134] ;Xに[$00:2134]をロード $C1/508E STX $DA [$00:03DA] ;Xを[$00:03DA]に書き込み $C1/5090 LDA #$FF ;Aに$FFをロード $C1/5092 STA $FB [$00:03FB] ;Aを[$00:03FB]に書き込み $C1/5094 RTS ;サブルーチン戻り $C1/3F3E RTS ;サブルーチン戻り $C1/503B LDA #$FF ;Aに$FFをロード $C1/503D STA $FB [$00:03FB] ;Aを[$00:03FB]に書き込み $C1/503F RTS ;サブルーチン戻り $C1/9991 JSR $8A60 [$C1:8A60] ;[$C1:8A60]へジャンプ
今回のサブルーチン開始位置、$C1/998E JSR $4FFBの戻り先が$C1/9991であり、ここまでが戦闘コマンド判定~コマンド用文字列呼び出しのサブルーチンだった、ということがわかる。
長いし分岐も多いのでざっくりと説明する。
$7E:FF00~$7E:FF60にコピーされたテキストデータ(文字コード)は、$C1/3ED1~$C1/3F2Aのループ処理で、1文字ずつどの文字かを判定する。
漢字なら2バイトだし、$0A~$0Dのように全角スペースが連続する場合は文字としては存在しないので、その分を空欄としてあけておく必要がある。
文字画像のアドレスの呼び出しについては、文字データ > 文字の画像ファイルを参照。
[$00:03DF][$00:03DE]の2バイトが文字コードになり、$C1/5095からアドレスを計算する。
$D40000 + $9200 + [$00:03DF][$00:03DE] * $18
が、該当文字の画像データ開始位置である。
呼び出した値は、[$7E:B005]、さらにその次のアドレスが[$7E:B025]に書き込まれる。
この作業をアドレスを増やしながらループ処理するが、24バイト分のデータが、
[$7E:B005][$7E:B025]
[$7E:B007][$7E:B027]
[$7E:B009][$7E:B029]
[$7E:B00B][$7E:B02B]
[$7E:B00D][$7E:B02D]
[$7E:B00F][$7E:B02F]
[$7E:B011][$7E:B031]
[$7E:B013][$7E:B033]
[$7E:B015][$7E:B035]
[$7E:B017][$7E:B037]
[$7E:B019][$7E:B039]
[$7E:B01B][$7E:B03B]
と、ちょっと妙なアドレスにコピーされる。
これで1文字分のデータである。
さらに、1文字分読み込んだ後は、初期値として00を入れた[$00:03E0]の値を+1していく。
$C1/50B2~$C1/50B6の処理を見ると、[$00:03E0]が奇数か偶数かで、文字読み込みサブルーチンが分岐する。
偶数なら$C1/50BB~、奇数なら$C1/50EB~である。
これは次に読み込む文字の表示位置の調整のためと思われる。
というのは、本作における1文字分のサイズは横16ピクセル、縦12ピクセルで収めている。ただし横16ピクセルの中で右隅4ピクセル幅は透過部分でデータがないので、実質12×12ピクセルである。
右隅4ピクセル幅のうち、2ピクセル分は次の文字と被せて表示させており、実際には12×12ピクセルの文字を2ピクセル間隔で横に並べている。
その被せ部分を$C1/50EB~の処理において、$C1/5116の論理和で処理しているのである。
とりあえず$C1/9991までで全データが送られたと考えてもらえばよい。
最終的に$7E:B5FBまで値が送られる。
$C1/9991の後は以下のようになる。
$C1/9991 JSR $8A60 [$C1:8A60] ;[$C1:8A60]へジャンプ $C1/8A60 LDA #$0F ;Aに$0Fをロード $C1/8A62 STA $40 [$00:0340] ;Aを[$00:0340]に書き込み $C1/8A64 STA $41 [$00:0341] ;Aを[$00:0341]に書き込み $C1/8A66 RTS ;サブルーチン戻り $C1/9994 LDX $5A [$00:035A] ;Xに[$00:035A]をロード $C1/9996 LDY $0002,x ;Yに[$00:1C02 + 40x]をロード $C1/9999 LDA #$00 ;Aに$00をロード $C1/999B STA $E6 [$00:03E6] ;Aを[$00:03E6]に書き込み $C1/999D STA $E7 [$00:03E7] ;Aを[$00:03E7]に書き込み $C1/999F JSR $E6BD [$C1:E6BD] ;[$C1:E6BD]へジャンプ $C1/E6BD LDX $5A [$00:035A] ;Xに[$00:035A]をロード $C1/E6BF LDA $0018,x ;Aに[$00:1C18 + 40x](キャラのX座標)をロード $C1/E6C2 CMP #$04 ;Aと$04を減算比較(ステータスレジスタ変更のみ) $C1/E6C4 BPL $11 [$E6D7] ;ネガティブフラグが立っていないとき[$E6D7]分岐 ;ネガティブフラグON(X座標0~3) $C1/E6C6 LDA $0019,x ;Aに[$00:1C19 + 40x](キャラのY座標)をロード $C1/E6C9 CMP #$04 ;Aと$04を減算比較(ステータスレジスタ変更のみ) $C1/E6CB BPL $05 [$E6D2] ;ネガティブフラグが立っていないとき[$E6D2]分岐 ;ネガティブフラグON(Y座標0~3) $C1/E6CD LDX #$C45E ;Xに$C45Eをロード $C1/E6D0 BRA $14 [$E6E6] ;フラグにかかわりなく常に分岐[$E6E6] ;$C1/E6CBでネガティブフラグOFF(Y座標4~6) $C1/E6D2 LDX #$C11E ;Xに$C11Eをロード $C1/E6D5 BRA $0F [$E6E6] ;フラグにかかわりなく常に分岐[$E6E6] ;$C1/E6C4でネガティブフラグOFF(X座標4~6) $C1/E6D7 LDA $0019,x ;Aに[$00:1C19 + 40x](キャラのY座標)をロード $C1/E6DA CMP #$04 ;Aと$04を減算比較(ステータスレジスタ変更のみ) $C1/E6DC BPL $05 [$E6E3] ;ネガティブフラグが立っていないとき[$E6E3]分岐 ;ネガティブフラグON(Y座標0~3) $C1/E6DE LDX #$C442 ;Xに$C442をロード $C1/E6E1 BRA $03 [$E6E6] ;フラグにかかわりなく常に分岐[$E6E6] ;$C1/E6DCでネガティブフラグOFF(Y座標4~6) $C1/E6E3 LDX #$C102 ;Xに$C102をロード ;処理合流 $C1/E6E6 STX $E4 [$00:03E4] ;Xを[$00:03E4]に書き込み $C1/E6E8 PHB ;DBレジスタをスタックにプッシュ $C1/E6E9 LDA #$7E ;Aに$7Eをロード $C1/E6EB PHA ;Aをスタックにプッシュ $C1/E6EC PLB ;DBレジスタに値をプル $C1/E6ED JSR $E77A [$C1:E77A] ;[$C1:E77A]へジャンプ
$C1/999B~で[$00:03E7][$00:03E6]に$00を書き込んでいるが、[$00:03E6]は戦闘コマンドにおけるカーソル位置である。
上から順に$00, $01, $02, $03が入る。
技一覧やアイテム一覧を開いた時でも、このアドレスにカーソル位置が入る。
戦闘コマンドを開いた時は必ず一番上にカーソルがある状態なので、$00を書き込んでいる。
$C1/E6BDからは、キャラのX座標、Y座標がそれぞれ0~3か、4~6かで分岐し、Xに異なる値をロードして、$C1/E6E6で合流している。
Xの値は$C1/E6E6で[$00:03E4]に書き込まれている。
まとめてみると、
| X座標 | Y座標 | [$00:03E4] | 戦闘コマンド位置 |
|---|---|---|---|
| 0~3 | 0~3 | $C45E | 右下 |
| 0~3 | 4~6 | $C11E | 右上 |
| 4~6 | 0~3 | $C442 | 左下 |
| 4~6 | 4~6 | $C102 | 左上 |
となる。
これは戦闘コマンド表示位置用の分岐である。今回は戦闘コマンド位置判定は省略するが、上に記した通り、キャラのいる対角位置にウィンドウが表示されるようになっている。
最終編オルステッド主人公時やブリキ大王操作時など、大型のキャラ操作時は、該当キャラの座標(左上マス)が基準になる(このためX座標・Y座標ともに3の位置などだと、キャラとコマンドが被ることがある)。
また、上の値は戦闘コマンドの中で灰色文字にしなければならない時の位置判定にも使う。
この後から少し飛んで、戦闘コマンドの灰色部分、つまり使用可能なコマンドの判定処理まで飛ばそう。
$C1/99A2 JSR $14DD [$C1:14DD] ;[$C1:14DD]へジャンプ $C1/14DD LDA $7EFEFA[$7E:FEFA] ;Aに[$7E:FEFA](ハルマゲドンフラグ)をロード $C1/14E1 BNE $08 [$14EB] ;ゼロフラグが立っていないとき[$14EB]分岐 ;ゼロフラグON ハルマゲドンフラグが立っていない $C1/14E3 LDA $0043 [$00:0043] ;Aに[$00:0043]をロード $C1/14E6 BEQ $03 [$14EB] ;ゼロフラグが立っているとき[$14EB]分岐 ;ゼロフラグOFF(「逃げる」が選べない) $C1/14E8 JSR $14FD [$C1:14FD] ;[$C1:14FD]へジャンプ ;ゼロフラグON(「逃げる」が選べる) $C1/14EB JSR $14C7 [$C1:14C7] ;[$C1:14C7]へジャンプ
$C1/14DD~の[$7E:FEFA]は戦闘コマンド表示の判定時、ハルマゲドンコマンド表示の時だけ$FFが入っており、それ以外は$00が入っているアドレスである。
$C1/14E3~の[$00:0043]は、最初に紹介した通り、詳細は省くが「逃げる」が選べる戦闘なら$00、選べない戦闘なら$01が戦闘開始直前に入る。
この「逃げる」は「テレポート」や「やめる」も含まれる。
以上から、「逃げる」が選べない時は[$C1:14FD]にジャンプ、ハルマゲドンコマンドと「逃げる」が選べる時は[$C1:14C7]にジャンプすることがわかる。
$C1/14FD~が「逃げる」(「テレポート」や「やめる」含む)を選択不可にし灰色文字にする処理になるが、詳細は省く。
一方、ハルマゲドンコマンドと「逃げる」が選べる時は$C1/14C7に処理が続く。
($C1/14FD~にジャンプした後でも、この処理は通る)
この$C1/14C7からの処理が実は「アイテムを使う」が選択可能かの判定である。
$C1/14C7 LDA $0A00 [$00:0A00] ;Aに[$00:0A00](シナリオID)をロード $C1/14CA CMP #$02 ;Aと$02(SF)を減算比較(ステータスレジスタ変更のみ) $C1/14CC BEQ $0E [$14DC] ;ゼロフラグが立っているとき[$14DC]分岐 ;ゼロフラグOFF $C1/14CE CMP #$05 ;Aと$05(現代)を減算比較(ステータスレジスタ変更のみ) $C1/14D0 BEQ $0A [$14DC] ;ゼロフラグが立っているとき[$14DC]分岐 ;ゼロフラグOFF $C1/14D2 LDX $5A [$00:035A] ;Xに[$00:035A]をロード $C1/14D4 LDA $0001,x ;Aに[$00:1C01 + 40x](戦闘状態)をロード $C1/14D7 CMP #$40 ;Aと$40($40:敵操作状態)を減算比較(ステータスレジスタ変更のみ) $C1/14D9 BEQ $01 [$14DC] ;ゼロフラグが立っているとき[$14DC]分岐 ;ゼロフラグOFF $C1/14DB RTS ;サブルーチン戻り ;ゼロフラグON SF編、現代編、最終編オルステッド主人公、ブリキ大王 $C1/14DC RTS ;サブルーチン戻り $C1/14EE BEQ $01 [$14F1] ;ゼロフラグが立っているとき[$14F1]分岐 ;ゼロフラグOFF $C1/14F0 RTS ;サブルーチン戻り ;ゼロフラグON SF編、現代編、最終編オルステッド主人公、ブリキ大王 $C1/14F1 REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア ... ...
最終的に$C1/14EEのゼロフラグ判定でゼロフラグが立っている場合は「アイテムを使う」が選択できず灰色表示になる分岐なのだが、それまでを辿ってみると、
この場合は「アイテムを使う」が選択できない。
アイテムの所持数で判定ということはなく、上の状況以外なら、アイテム所持数が0でも「アイテムを使う」を選んでアイテム欄を開くことができる。
とはいえ開いてもアイテムはひとつもないが。
(近未来編や中世編の最初の戦闘など、初期状態でアイテムがない、かつイベント戦闘から始まるシナリオなら必ず見られる)
ブリキ大王操作時はアイテムを使えると戦闘バランスが崩れてしまうなどの問題も起こるので、上の処理でアイテムを選べないようにしているのだろう。
以上でざっとだが戦闘コマンド関係の処理の紹介を終了とする。
最後に、「ハルマゲドン用コマンド」関係について。
$C1/4FDF~$C1/4FFAの処理から、
trunc(操作キャラ最大HP/4) - 操作キャラ現在HP ≧ 0
が、「ハルマゲドン用コマンド」の条件ということが判明した。
ただ、本作の敵は、仕様上HPが$80(128)以上だと(味方キャラデータ00 & $7F) * $10で最大HPを計算するため、trunc(操作キャラ最大HP/4)は必ず割り切れる。
よって、最終編オルステッド主人公時は、
操作キャラ最大HP/4 - 操作キャラ現在HP ≧ 0
が「ハルマゲドン用コマンド」の条件になる、ということで問題ない。
つまり最大HPの1/4以下で「ハルマゲドン」コマンドに切り替えである。
また、処理からして、最大HPの1/4以下からHPが回復したら、「逃げる」に表示が戻ることもわかる。
さらに、「ハルマゲドン用コマンド」条件の処理中に、[$7E:FEFA]に$FFを書き込むことで処理分岐を行うこともわかった。
ただし、
最大HPの1/4以下からHPが回復したら、[$7E:FEFA]に$00を書き込んで初期状態に戻す
という処理は存在していない。
$C1/4FDF~$C1/4FFAの処理で、最大HPの1/4以下からHPが回復し、「逃げる」に表示が戻った状態で、$C1/14DD~の処理を通るとどうなるか。
$C1/14DD LDA $7EFEFA[$7E:FEFA] ;Aに[$7E:FEFA](ハルマゲドンフラグ)をロード $C1/14E1 BNE $08 [$14EB] ;ゼロフラグが立っていないとき[$14EB]分岐 ;ゼロフラグON ハルマゲドンフラグが立っていない $C1/14E3 LDA $0043 [$00:0043] ;Aに[$00:0043]をロード $C1/14E6 BEQ $03 [$14EB] ;ゼロフラグが立っているとき[$14EB]分岐 ;ゼロフラグOFF(「逃げる」が選べない) $C1/14E8 JSR $14FD [$C1:14FD] ;[$C1:14FD]へジャンプ ;ゼロフラグON(「逃げる」が選べる) $C1/14EB JSR $14C7 [$C1:14C7] ;[$C1:14C7]へジャンプ
[$7E:FEFA]だけでハルマゲドンフラグを判断しているため、$C1/14E1の時点で「逃げる」可能と判定されてしまう。
よって、本来なら最終編オルステッド主人公時では選べないはずの「逃げる」が選べる状態になる。
だが、最終編オルステッド主人公時の戦闘コマンドでは、一番下のコマンドを選ぶと、文字列が「ハルマゲドン」だろうが「逃げる」だろうが、「ハルマゲドン」を実行するようサブルーチンが組まれている。
よって、一度「ハルマゲドン」コマンドが出てからHPを回復した場合、「逃げる」表示に戻るが、選ぶとハルマゲドン発動、というバグっぽい挙動が発生することになる。