基礎知識
戦闘関係
前ページの続き。
ステータス変動が起きた場合、その後元の値へと復元処理をしていくのだが、その処理は何かしらの行動のタイミングで行われる。
いわゆる、1ターンでの時間経過や、向き変え・移動・Yボタン足踏みによる時間経過、または誰も行動できる状態ではない場合(味方全員が技のタメ時間中で敵も行動できない時など)で復元処理が挟まる。
レベルと、力・速・体・知とでは、復元処理のサブルーチンが変わる。
また、復元に際して重要なアドレスが、[$00:036C][$00:036D]である。
これらアドレスが時間経過の値になる。
処理の解説をしながら合わせて説明していく。
味方キャラは以下のサブルーチンでレベル復元が行われる。
$C1/21C1 LDY $0002,x[$00:1C02] ;Yに[$00:1C0x]をロード $C1/21C4 LDA $0006,y[$00:0E46] ;Aに[$0006,y](シナリオ別キャラデータ06 LV(通常値))をロード $C1/21C7 STA $20 [$00:0320] ;A(LV(通常値))を[$00:0320]に書き込み $C1/21C9 LDA $6D [$00:036D] ;Aに[$00:036D]をロード $C1/21CB BIT #$F0 ;Aと$F0で論理積(ステータスフラグ変更のみ) $C1/21CD BEQ $11 [$21E0] ;ゼロフラグが立っているとき[$21E0]分岐 $C1/21CF PHA ;Aをスタックにプッシュ $C1/21D0 LDA #$01 ;Aに$01をロード $C1/21D2 STA $6D [$00:036D] ;A($01)を[$00:036D]に書き込み $C1/21D4 LDA $0038,x[$00:1C38] ;Aに[$00:1C38](LV(現在値))をロード $C1/21D7 JSR $20CD [$C1:20CD] ;[$C1:20CD]へジャンプ ; $C1/20CD CMP $20 [$00:0320] ;A(LV(現在値))と[$00:0320](LV(通常値))を減算比較(ステータスレジスタ変更のみ) $C1/20CF BCS $0D [$20DE] ;キャリーフラグが立っているとき[$20DE]分岐 ;キャリーフラグOFF デバフまたはバフ・デバフなし $C1/20D1 ADC $6D [$00:036D] ;A(LV(現在値)) + [$00:036D]($01) $C1/20D3 BCS $04 [$20D9] ;キャリーフラグが立っているとき[$20D9]分岐 ;キャリーフラグOFF $C1/20D5 CMP $20 [$00:0320] ;Aと[$00:0320]を減算比較(ステータスレジスタ変更のみ) $C1/20D7 BCC $0D [$20E6] ;キャリーフラグが立っていないとき[$20E6]分岐 ;キャリーフラグON $C1/20DE SBC $6D [$00:036D] ;A(LV(現在値)) - [$00:036D]($01) $C1/20E0 BCC $F7 [$20D9] ;キャリーフラグが立っていないとき[$20D9]分岐 ;キャリーフラグOFF $C1/20E2 CMP $20 [$00:0320] ;A((LV(現在値))-1)と[$00:0320](LV(通常値))を減算比較(ステータスレジスタ変更のみ) $C1/20E4 BCC $F3 [$20D9] ;キャリーフラグが立っていないとき[$20D9]分岐 ;キャリーフラグON $C1/20D9 LDA $20 [$00:0320] ;Aに[$00:0320](LV(通常値))をロード $C1/20DB CMP $20 [$00:0320] ;A(LV(通常値))と[$00:0320]を減算比較(ステータスレジスタ変更のみ) $C1/20DD RTS ;サブルーチン戻り ; $C1/20E6 CMP $20 [$00:0320] ;Aと[$00:0320]を減算比較(ステータスレジスタ変更のみ) $C1/20E8 RTS ;サブルーチン戻り ; $C1/21DA STA $0038,x[$00:1C38] ;Aを[$00:1C38](LV(現在値))に書き込み $C1/21DD PLA ;Aレジスタに値をプル $C1/21DE STA $6D [$00:036D] ;Aを[$00:036D]に書き込み $C1/21E0 RTS ;サブルーチン戻り
レベル処理の説明の前に、[$00:036D]の処理だけ追いかけてみると、
$C1/21C9で[$00:036D]をロード、$F0と論理積を取った値が0なら、処理は$C1/21E0までスキップ。そうでない場合は一度スタックにプッシュ$C1/21D2で[$00:036D]に$01を書き込み、計算処理に使う$C1/21DEで1.の値をプルして[$00:036D]に書き戻しと、なっている。
つまり$C1/21C9の時点での[$00:036D]は、$C1/21CF~$C1/21DEで一時的に退避している状態で、$C1/21DEで書き戻される。
では$C1/21C9の時点での[$00:036D]はどこから来た数値なのか? ということは、ひとまず横に置いておく。
ここではレベル処理だけ絞って説明する。
$C1/21C4で、味方キャラのシナリオ別キャラデータ06からLV(通常値)の値をロードし、[$00:0320]にコピーする。
LV(通常値)は戦闘中には変動しない元々のキャラのレベルである。つまり、戦闘中、ステータス変動が起きても変動しない。
続いて、[$00:036D]に$01を書き込む。
$C1/21D4で、Aに[$00:1C38](LV(現在値))をロードし、$C1/20CDで[$00:0320](LV(通常値))と減算比較する。
レベル(現在値)がステータス変動中だったら、LV(通常値)の値と減算比較した時、0以外の値になる。
レベル(現在値)がデバフされていてLV(通常値)より低ければ、減算の結果は負の値だし、バフ状態でLV(通常値)より高ければ、減算の結果は正の値になる。
$C1/20CFでキャリーフラグが立つのは、減算の結果が正か0の時だから、デバフまたはバフ・デバフなしの状態。
キャリーフラグが立たないのは、減算の結果が負の時だから、バフの状態。
……というように、現在のレベルの状況で処理が分岐していく。
ポイントは[$00:036D]に入っている$01で、例えばバフ状態だけ追いかけていくと、$C1/20CFでキャリーフラグONだから$C1/20DEに飛び、A(LV(現在値)) - [$00:036D]($01)を計算、負の値になっていなければ最終的に$C1/21DAでそのまま[$00:1C38](LV(現在値))に上書きしている。
デバフ状態だったら、$C1/20D1でA(LV(現在値)) + [$00:036D]($01)を計算、LV(通常値)と計算値を比較して、計算値がLV(通常値)を上回っていない時には$C1/21DAでそのまま[$00:1C38](LV(現在値))に上書きしている。
つまり、
と、レベルの値がLV(通常値)へと1ずつ復元していくことがわかる。
レベルに対する割合ではなく、必ず1ずつ復元していく。
敵の処理もほぼ同じである。
$C1/2111 LDY $0002,x[$00:1B02] ;Yに[$00:1B02]をロード $C1/2114 LDA $000B,y[$00:1A0B] ;Aに[$00:1A0B](敵種類$0B LV(通常値))をロード $C1/2117 STA $20 [$00:0320] ;Aを[$00:0320]に書き込み $C1/2119 LDA $6D [$00:036D] ;Aに[$00:036D]をロード $C1/211B BIT #$F0 ;Aと$F0で論理積(ステータスフラグ変更のみ) $C1/211D BEQ $13 [$2132] ;ゼロフラグが立っているとき[$2132]分岐 $C1/211F PHA ;Aをスタックにプッシュ $C1/2120 LDA #$01 ;Aに$01をロード $C1/2122 STA $6D [$00:036D] ;Aを[$00:036D]に書き込み $C1/2124 LDA $7E9000,x[$7E:AB00] ;Aに[$7E:AB00](LV(現在値))をロード $C1/2128 JSR $20CD [$C1:20CD] ;[$C1:20CD]へジャンプ ; $C1/20CD CMP $20 [$00:0320] ;A(LV(現在値))と[$00:0320](LV(通常値))を減算比較(ステータスレジスタ変更のみ) $C1/20CF BCS $0D [$20DE] ;キャリーフラグが立っているとき[$20DE]分岐 $C1/20D1 ADC $6D [$00:036D] ;A(LV(現在値)) + [$00:036D]($01) $C1/20D3 BCS $04 [$20D9] ;キャリーフラグが立っているとき[$20D9]分岐 $C1/20D5 CMP $20 [$00:0320] ;Aと[$00:0320]を減算比較(ステータスレジスタ変更のみ) $C1/20D7 BCC $0D [$20E6] ;キャリーフラグが立っていないとき[$20E6]分岐 $C1/20DE SBC $6D [$00:036D] ;A(LV(現在値)) - [$00:036D]($01) $C1/20E0 BCC $F7 [$20D9] ;キャリーフラグが立っていないとき[$20D9]分岐 $C1/20E2 CMP $20 [$00:0320] ;A((LV(現在値))-1)と[$00:0320](LV(通常値))を減算比較(ステータスレジスタ変更のみ) $C1/20E4 BCC $F3 [$20D9] ;キャリーフラグが立っていないとき[$20D9]分岐 $C1/20D9 LDA $20 [$00:0320] ;Aに[$00:0320](LV(通常値))をロード $C1/20DB CMP $20 [$00:0320] ;A(LV(通常値))と[$00:0320]を減算比較(ステータスレジスタ変更のみ) $C1/20DD RTS ;サブルーチン戻り ; $C1/212B STA $7E9000,x[$7E:AB00] ;Aを[$7E:AB00](LV(現在値))に書き込み $C1/212F PLA ;Aレジスタに値をプル $C1/2130 STA $6D [$00:036D] ;Aを[$00:036D]に書き込み $C1/2132 RTS ;サブルーチン戻り
LV(通常値)は敵種類データのLV(通常値)からロード、LV(現在値)は敵番号nの$7E:ABn0からロードするだけで、[$00:036D]に$01を書き込むことや、$C1/20CD~$C1/20DDの処理が共通であるため、敵でも同じく、
という処理を行うことがわかった。
それぞれのステータスがループ処理で復元される。
味方キャラは以下のサブルーチン。
以下処理は味方キャラ1とする。
$C1/21E1 LDA #$04 ;Aに$04をロード $C1/21E3 STA $08 [$00:0308] ;A($04)を[$00:0308]に書き込み $C1/21E5 LDA $0030,x[$00:1C30] ;Aに[$00:1C30](味方1 力(通常値))をロード $C1/21E8 STA $20 [$00:0320] ;Aを[$00:0320]に書き込み $C1/21EA LDA $0034,x[$00:1C34] ;Aに[$00:1C34](味方1 力(現在値))をロード $C1/21ED JSR $20CD [$C1:20CD] ;[$C1:20CD]へジャンプ ; ;ループ処理ここから ;ループ回数は[$00:0308] = $04 $C1/20CD CMP $20 [$00:0320] ;A(ステータス(現在値))と[$00:0320]を減算比較(ステータスレジスタ変更のみ) $C1/20CF BCS $0D [$20DE] ;キャリーフラグが立っているとき[$20DE]分岐 $C1/20D1 ADC $6D [$00:036D] ;A(ステータス(現在値)) + [$00:036D] $C1/20D3 BCS $04 [$20D9] ;キャリーフラグが立っているとき[$20D9]分岐 $C1/20D5 CMP $20 [$00:0320] ;Aと[$00:0320]を減算比較(ステータスレジスタ変更のみ) $C1/20D7 BCC $0D [$20E6] ;キャリーフラグが立っていないとき[$20E6]分岐 $C1/20DE SBC $6D [$00:036D] ;A(ステータス(現在値)) - [$00:036D] $C1/20E0 BCC $F7 [$20D9] ;キャリーフラグが立っていないとき[$20D9]分岐 $C1/20E2 CMP $20 [$00:0320] ;A((ステータス(現在値))-1)と[$00:0320](ステータス(通常値))を減算比較(ステータスレジスタ変更のみ) $C1/20E4 BCC $F3 [$20D9] ;キャリーフラグが立っていないとき[$20D9]分岐 $C1/20D9 LDA $20 [$00:0320] ;Aに[$00:0320](ステータス(通常値))をロード $C1/20DB CMP $20 [$00:0320] ;A(ステータス(通常値))と[$00:0320]を減算比較(ステータスレジスタ変更のみ) $C1/20DD RTS ;サブルーチン戻り ; $C1/21F0 STA $0034,x[$00:1C34] ;Aを[$00:1C3n]に書き込み $C1/21F3 INX ;Xをインクリメント +1 $C1/21F4 DEC $08 [$00:0308] ;[$00:0308](ループ回数)をデクリメント -1 $C1/21F6 BNE $ED [$21E5] ;ゼロフラグが立っていないとき[$21E5]分岐 $C1/21E5 LDA $0030,x[$00:1C31] ;Aに[$00:1C3n](ステータス(通常値))をロード $C1/21E8 STA $20 [$00:0320] ;Aを[$00:0320]に書き込み $C1/21EA LDA $0034,x[$00:1C35] ;Aに[$00:1C3n+4](ステータス(現在値))をロード $C1/21ED JSR $20CD [$C1:20CD] ;[$C1:20CD]へジャンプ ;ループ処理ここまで
味方キャラ1だと、各ステータスは以下アドレスに入っている。
| アドレス | 内容 |
|---|---|
$00:1C30 | 力(通常値) |
$00:1C31 | 速(通常値) |
$00:1C32 | 体(通常値) |
$00:1C33 | 知(通常値) |
$00:1C34 | 力(現在値) |
$00:1C35 | 速(現在値) |
$00:1C36 | 体(現在値) |
$00:1C37 | 知(現在値) |
よって、ループ処理にて、$00:1C30以降を+1しながらステータス(通常値)、$00:1C34以降を+1しながらステータス(現在値)をロードしていくことで、力・速・体・知の処理が行えることになる。
そして、$C1/20CD~$C1/20DDのサブルーチンは、レベル復元処理と共通である。
つまり、
[$00:036D]の値だけ減らし、ステータス(通常値)の値以下になっていなければステータス(現在値)に上書き[$00:036D]の値だけ増やし、ステータス(通常値)の値以上になっていなければステータス(現在値)に上書きというサブルーチンである。
レベルの時は[$00:036D]の値が$01で固定になっていたが、上のサブルーチンでは固定値ではない。
上サブルーチン前に[$00:036D]に入った値により、増減量が変動する。
敵の場合は以下。
$C1/2133 LDY $0002,x[$00:1B02] ;Yに[$00:1B02]をロード $C1/2136 LDA #$04 ;Aに$04をロード $C1/2138 STA $08 [$00:0308] ;A($04)を[$00:0308]に書き込み $C1/213A LDA $0025,y[$00:1A25] ;Aに[$00:1A25](敵データ05 力)をロード $C1/213D STA $20 [$00:0320] ;Aを[$00:0320]に書き込み $C1/213F LDA $7E8F03,x[$7E:AA03] ;Aに[$7E:AA03](力(現在値))をロード $C1/2143 JSR $20CD [$C1:20CD] ;[$C1:20CD]へジャンプ ; ;ループ処理ここから ;ループ回数は[$00:0308] = $04 $C1/20CD CMP $20 [$00:0320] ;A(ステータス(現在値))と[$00:0320]を減算比較(ステータスレジスタ変更のみ) $C1/20CF BCS $0D [$20DE] ;キャリーフラグが立っているとき[$20DE]分岐 $C1/20D1 ADC $6D [$00:036D] ;A(ステータス(現在値)) + [$00:036D] $C1/20D3 BCS $04 [$20D9] ;キャリーフラグが立っているとき[$20D9]分岐 $C1/20D5 CMP $20 [$00:0320] ;Aと[$00:0320]を減算比較(ステータスレジスタ変更のみ) $C1/20D7 BCC $0D [$20E6] ;キャリーフラグが立っていないとき[$20E6]分岐 $C1/20DE SBC $6D [$00:036D] ;A(ステータス(現在値)) - [$00:036D] $C1/20E0 BCC $F7 [$20D9] ;キャリーフラグが立っていないとき[$20D9]分岐 $C1/20E2 CMP $20 [$00:0320] ;A((ステータス(現在値))-1)と[$00:0320](ステータス(通常値))を減算比較(ステータスレジスタ変更のみ) $C1/20E4 BCC $F3 [$20D9] ;キャリーフラグが立っていないとき[$20D9]分岐 $C1/20D9 LDA $20 [$00:0320] ;Aに[$00:0320](ステータス(通常値))をロード $C1/20DB CMP $20 [$00:0320] ;A(ステータス(通常値))と[$00:0320]を減算比較(ステータスレジスタ変更のみ) $C1/20DD RTS ;サブルーチン戻り ; $C1/2146 STA $7E8F03,x[$7E:AA03] ;Aを[$7E:AAnn]に書き込み $C1/214A INX ;Xをインクリメント +1 $C1/214B INY ;Yをインクリメント +1 $C1/214C DEC $08 [$00:0308] ;[$00:0308]をデクリメント -1 $C1/214E BNE $EA [$213A] ;ゼロフラグが立っていないとき[$213A]分岐 $C1/213A LDA $0025,y[$00:1A26] ;Aに[$00:1A2n]をロード $C1/213D STA $20 [$00:0320] ;Aを[$00:0320]に書き込み $C1/213F LDA $7E8F03,x[$7E:AA04] ;Aに[$7E:AAnn+1]をロード $C1/2143 JSR $20CD [$C1:20CD] ;[$C1:20CD]へジャンプ ;ループ処理ここまで
やはり、ステータスのアドレスが異なるだけで、味方キャラと処理は変わらない。
敵1体目であれば以下アドレスから、ステータスの通常値と現在値を取って計算を行っている。
| アドレス | 内容 |
|---|---|
$00:1A25 | 敵データ05 力 |
$00:1A26 | 敵データ06 速 |
$00:1A27 | 敵データ07 体 |
$00:1A28 | 敵データ08 知 |
$7E:AA03 | 力(現在値) |
$7E:AA04 | 速(現在値) |
$7E:AA05 | 体(現在値) |
$7E:AA06 | 知(現在値) |
[$00:036C][$00:036D]の算出では、ステータスの増減量にあたる[$00:036D]はどのように計算されるのか。
まず、技使用時だが、敵味方共通して、技名が出たあたりで以下処理が入る。
$C1/7F1C LDA $86 [$00:0386] ;Aに[$00:0386]をロード $C1/7F1E BEQ $01 [$7F21] ;ゼロフラグが立っているとき[$7F21]分岐 $C1/7F20 RTS ;サブルーチン戻り $C1/7F21 LDA #$10 ;Aに$10をロード $C1/7F23 STA $6D [$00:036D] ;Aを[$00:036D]に書き込み $C1/7F25 JSR $20F2 [$C1:20F2] ;[$C1:20F2]へジャンプ
タメ時間のある技も、技名が出たタイミングで処理が入るので、どの技でも技発動時の処理になる。
もちろん、アイテム使用時も技使用扱いだから同じ処理が入る。
[$00:0386]に$00が入っている場合は[$00:036D]に$10を書き込んでいる。
[$00:0386]の処理は横に置いておくとして、技名が出てから上のステータス変動処理が終わる0.5秒程度? の間だけ[$00:036D]は$10が入ったままになる。
上の処理の通り、レベルの増減処理の最中だけ一時的にスタックに値が避難されて$01が入るが、それ以外だと[$00:036D]=$10で処理される。
では、技使用時以外では[$00:036D]はどう計算されているか。
戦闘中タイマー($7E:FEF0~$7E:FEF1)の計算の少し後、つまり1フレーム毎に下の処理が入るようだ。
$C1/9357 LDA $6C [$00:036C] ;Aに[$00:036C]をロード $C1/9359 LSR A ;Aを論理右シフト (/2) $C1/935A LSR A ;Aを論理右シフト (/2) $C1/935B LSR A ;Aを論理右シフト (/2) $C1/935C LSR A ;Aを論理右シフト (/2) $C1/935D STA $6D [$00:036D] ;Aを[$00:036D]に書き込み $C1/935F JSR $7A42 [$C1:7A42] ;[$C1:7A42]へジャンプ
[$00:036C]を論理右シフト4回した値が、[$00:036D]に書き込まれることがわかる。
つまり、[$00:036C]に入っている1バイトの値の上1桁が[$00:036D]と同値になる、ということである。
では、[$00:036C]は何なのか。
[$00:036C]の処理を見てみると、直前の行動で入る値が変わっていることがわかる。
まず、直前の行動の判定のため、プレイヤーがコントローラの何のボタンを押したか、または何も押していないかを判断する。
ボタン判定は1フレームに1回行われている。
詳細はボタン判定を見ていただきたい。
戦闘において、メニュー画面を開いていない時、十字キーでマス移動したり、Yボタンで足踏み、LRボタンで向き変えをすると時間経過する。
メニュー画面を開いている場合、パスを決定した時に時間経過である。
どのボタンを押したか、判定するためのサブルーチンの説明まですると長くなってしまうため、ボタン判定後の分岐先で、[$00:036C]の値を書き込む処理だけ紹介する。
;十字キー(1マス移動) $C1/96CE LDA #$40 ;Aに$40をロード $C1/96D0 STA $B8 [$00:03B8] ;A($40)を[$00:03B8]に書き込み $C1/96D2 STA $6C [$00:036C] ;A($40)を[$00:036C]に書き込み
;Yボタン $C1/9575 LDA #$40 ;Aに$40をロード $C1/9577 STA $6C [$00:036C] ;A($40)を[$00:036C]に書き込み $C1/9579 STA $B8 [$00:03B8] ;A($40)を[$00:03B8]に書き込み $C1/957B LDX $5A [$00:035A] ;Xに[$00:035A]をロード $C1/957D JSR $2CB9 [$C1:2CB9] ;[$C1:2CB9]へジャンプ
;Lボタン・Rボタン $C1/9920 LDA #$40 ;Aに$40をロード $C1/9922 STA $B8 [$00:03B8] ;A($40)を[$00:03B8]に書き込み $C1/9924 LSR A ;Aを論理右シフト (/2) $C1/9925 STA $6C [$00:036C] ;A($20)を[$00:036C]に書き込み $C1/9927 RTS ;サブルーチン戻り
更に、何のボタンも押されず、味方全員が技のタメ時間など、敵も行動できない状況下、つまりプレイヤーも行動不能な状況下で入る処理が以下の通り。
$C1/7A42 LDA $6C [$00:036C] ;Aに[$00:036C]をロード $C1/7A44 BNE $1D [$7A63] ;ゼロフラグが立っていないとき[$7A63]分岐 $C1/7A46 LDA $F0 [$00:03F0] ;Aに[$00:03F0]をロード $C1/7A48 CMP #$80 ;Aと$80を減算比較(ステータスレジスタ変更のみ) $C1/7A4A BNE $17 [$7A63] ;ゼロフラグが立っていないとき[$7A63]分岐 $C1/7A4C LDA #$10 ;Aに$10をロード $C1/7A4E STA $6C [$00:036C] ;A($10)を[$00:036C]に書き込み $C1/7A50 LDA #$01 ;Aに$01をロード $C1/7A52 STA $6D [$00:036D] ;A($01)を[$00:036D]に書き込み ;(省略) $C1/7A63 RTS ;サブルーチン戻り
これ以外の状況では時間経過せず、[$00:036C][$00:036D]には$00が入った状態である。
また、先に説明した通り、技発動時なら、[$00:036D]には[$00:036C]を$10で割った値、上1桁が入る。
まとめると、
| 行動 | [$00:036C] | [$00:036C] |
|---|---|---|
| 技発動時 | $00 | $10 |
| 十字キー(1マス移動) | $40 | $04 |
| Yボタン | $40 | $04 |
| Lボタン・Rボタン | $20 | $02 |
| 行動不能 | $10 | $01 |
このようになる。
そして、[$00:036C]に入った値が、ステータス変動からの力・速・体・知の復元の値になる。
行動不能の時だけは、$C1/7A42~$C1/7A63が1フレームに1回入るから、1フレームで1ずつ復元ということになる。
全員が技をタメている時、ステータスやタメ時間が1フレームで1ずつ変動(復元)する仕組みはここにある。
ステータス復元量を10進数でまとめると以下のようになる。
| 行動 | レベル復元 | 力速体知 復元 |
|---|---|---|
| 技発動時 | 1 | 16 |
| 1マス移動 | 0 | 4 |
| Yボタン足踏み | 0 | 4 |
| LR向き変え | 0 | 2 |
| 敵味方行動不能※ | 0 | 1 |
※1フレームにつき1復元
以上がステータス復元処理となる。
ステータス変動は割合だが、復元は固定値なので、レベルやステータスが高いほど変動は大きくなり、元の数値に戻るまで時間がかかる。
現代編の高原が「気合いため」を使ってステータス変動が起きても、すぐ復元するため、実質HP回復の効果しかないのは、高原がレベル2なので、割合で増加してもごくわずか、そしてすぐに復元してしまう、という理屈である。