基礎知識
戦闘関係
本作の敵味方の行動順は「行動ポイント」「順序ポイント」というパラメータで決定されている。
戦闘関係の解説 > ターンや行動順の詳細でも触れているが、ここではサブルーチンを含めて解説をする。
大まかには、行動ポイントが0以上256未満の時は味方のターン、256以上なら敵のターンである。
敵ターンでは、すべての敵に設定された順序ポイントが一番高い敵が行動する仕組み。
順序ポイントが同じ敵がいる時は、敵番号がより大きな敵が優先となる。
味方ターンの味方行動順は隊形の上・左・右・下の順で、該当キャラが技をタメている最中、または行動不能な状態異常だと飛ばされ次のキャラが選ばれることになる。
なお、順序ポイントの増減は条件による分岐が多くややこしいため、このページでは行動ポイント中心に説明をしていく。
味方行動順の決定方法は敵ほど複雑ではないため、このページ一番下で紹介している。
順序ポイントについては次ページで説明するが、まずは行動ポイントについてお読みいただきたい。
また、敵ターンにおける行動選択も後で別ページで説明している。
[$00:03AF][$00:03AE]2バイトで戦闘中の行動ポイントの値。
敵味方共通。
[$00:03B8]行動ポイントと共に、敵ターンにまわるか、味方ターンにまわるかを判定するため重要なメモリアドレスである。
味方ターンが回ってきた時は、[$00:035B][$00:035A]の2バイトに入っている値でどのキャラが行動するかが決まる。
基本は隊形の上・左・右・下の順で、該当キャラが技をタメている最中、または行動不能な状態異常だと飛ばされる。
詳細は味方行動順決定用のサブルーチンを。
行動ポイント計算・判定関係のサブルーチンを紹介していく。
戦闘開始時の処理は以下の通り。
;行動ポイント初期値設定 $C1/EBAD LDX #$0000 ;Xに$0000をロード $C1/EBB0 STX $AE [$00:03AE] ;Xを[$00:03AF][$00:03AE]に書き込み $C1/EBB2 STX $AC [$00:03AC] ;Xを[$00:03AD][$00:03AC]に書き込み $C1/EBB4 LDX #$1B00 ;Xに$1B00をロード $C1/EBB7 LDA $0001,x[$00:1B01] ;Aに[$00:1B01]をロード $C1/EBBA CMP #$80 ;Aと$80を減算比較(ステータスレジスタ変更のみ) $C1/EBBC BEQ $02 [$EBC0] ;ゼロフラグが立っているとき[$EBC0]分岐 $C1/EBBE STX $AC [$00:03AC] ;Xを[$00:03AC]に書き込み $C1/EBC0 JSR $EBC4 [$C1:EBC4] ;[$C1:EBC4]へジャンプ
$C1/EBAD~$C1/EBB0で、$0000を[$00:03AF][$00:03AE]に書き込んでいる。
[$00:03AF][$00:03AE]が行動ポイント(2バイト)なので、戦闘開始時の初期値は、
[$00:03AF] = $00
[$00:03AE] = $00
ということになる。
行動ポイントが0以上256未満の時は味方のターンなので、戦闘開始直後は必ず味方にターンが回ってくる。
$C1/F3CE STZ $AA [$00:03AA] ;[$00:03AA]に$00を書き込み $C1/F3D0 STZ $8B [$00:038B] ;[$00:038B]に$00を書き込み $C1/F3D2 STZ $95 [$00:0395] ;[$00:0395]に$00を書き込み $C1/F3D4 STZ $96 [$00:0396] ;[$00:0396]に$00を書き込み $C1/F3D6 STZ $B7 [$00:03B7] ;[$00:03B7]に$00を書き込み $C1/F3D8 STZ $B8 [$00:03B8] ;[$00:03B8]に$00を書き込み
後に敵味方ターンを判定するために必要となる[$00:03B8]も、初期値は$00である。
ここからは、戦闘中の行動ポイントの計算について説明する。
まず、味方の行動について。
味方が技を出した時(タメ時間のある技はタメ時間が終わって技を出した時)、行動ポイント2バイト[$00:03AF][$00:03AE]は以下のサブルーチンで変化する。
以下、味方1(X:1C00)の場合のアドレスとする。
$C1/93A0 BEQ $1D [$93BF] ;ゼロフラグが立っているとき[$93BF]分岐 $C1/93A2 LDA $0005,x[$00:1C05] ;Aに[$00:1C05](技関係状態 $40:タメ時間中)をロード $C1/93A5 CMP #$40 ;Aと$40を減算比較(ステータスレジスタ変更のみ) $C1/93A7 BNE $16 [$93BF] ;ゼロフラグが立っていないとき[$93BF]分岐 $C1/93A9 LDA $0039,x[$00:1C39] ;Aに[$00:1C39](状態異常)をロード $C1/93AC BIT #$B0 ;Aと$B0(%1011 0000)で論理積(ステータスフラグ変更のみ) $C1/93AE BNE $0F [$93BF] ;ゼロフラグが立っていないとき[$93BF]分岐 ;ゼロフラグOFF(石化,眠り,マヒではない) $C1/93B0 LDA $0006,x[$00:1C06] ;Aに[$00:1C06](タメ時間ありの技発動までの時間)をロード $C1/93B3 BEQ $10 [$93C5] ;ゼロフラグが立っているとき[$93C5]分岐 ;ゼロフラグOFF(タメ時間中、または石化,眠り,マヒである) $C1/93BF CPX #$1CC0 ;Xと$1CC0を減算比較(ステータスレジスタ変更のみ) $C1/93C2 BNE $D9 [$939D] ;ゼロフラグが立っていないとき[$939D]分岐 $C1/939D JSR $9F5A [$C1:9F5A] ;[$C1:9F5A]へジャンプ ;ゼロフラグON(タメ時間中ではない) $C1/93C5 LDA #$10 ;Aに$10をロード $C1/93C7 STA $B7 [$00:03B7] ;A($10)を[$00:03B7]に書き込み $C1/93C9 STZ $B8 [$00:03B8] ;[$00:03B8]に$00を書き込み $C1/93CB LDA #$F0 ;Aに$F0をロード $C1/93CD STA $0005,x[$00:1C05] ;Aを[$00:1C05](技関係状態)に書き込み $C1/93D0 LDA $62 [$00:0362] ;Aに[$00:0362](初期値$00)をロード $C1/93D2 ORA #$10 ;Aと$10で論理和 $C1/93D4 STA $62 [$00:0362] ;Aを[$00:0362]に書き込み $C1/93D6 JSR $2826 [$C1:2826] ;[$C1:2826]へジャンプ ; $C1/2826 LDA #$FF ;Aに$FFをロード $C1/2828 REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/282A AND #$00FF ;Aと$00FFで論理積 $C1/282D ADC $AE [$00:03AE] ;A + [$00:03AF][$00:03AE] $C1/282F STA $AE [$00:03AE] ;Aを[$00:03AF][$00:03AE]に書き込み $C1/2831 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/2833 RTS ;サブルーチン戻り ; $C1/93D9 JSR $2826 [$C1:2826] ;[$C1:2826]へジャンプ ; $C1/2826 LDA #$FF ;Aに$FFをロード $C1/2828 REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/282A AND #$00FF ;Aと$00FFで論理積 $C1/282D ADC $AE [$00:03AE] ;A + [$00:03AF][$00:03AE] $C1/282F STA $AE [$00:03AE] ;Aを[$00:03AF][$00:03AE]に書き込み $C1/2831 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/2833 RTS ;サブルーチン戻り ; $C1/93DC LDA #$80 ;Aに$80をロード $C1/93DE STA $B8 [$00:03B8] ;Aを[$00:03B8]に書き込み $C1/93E0 RTS ;サブルーチン戻り
$C1/93C5までが行動ポイント2バイト[$00:03AF][$00:03AE]を変更するかどうかの判定になっている。
処理を追っていくと、技を出した味方キャラが、
であれば、$C1/93C5からの処理を行う。
$C1/93C5~$C1/93D6は、以下のように各アドレスに値を書き込む。
| アドレス | 数値 |
|---|---|
[$00:03B7] | $10 |
[$00:03B8] | $00 |
[$00:1C05](技関係状態) | $F0(技を出している最中) |
[$00:0362] | [$00:0362]と$10の論理和 |
$C1/93D6~からが行動ポイントの計算で、$C1/2826~$C1/2833を2回繰り返していることがわかる。
$C1/2826~$C1/2833の処理は、
$00FF + [$00:03AF][$00:03AE]
を、行動ポイント[$00:03AF][$00:03AE]に書き込んでいる。
要するに、行動ポイント[$00:03AF][$00:03AE]に$00FFを加算するサブルーチンである。
これを2回繰り返しているから、
[$00:03AF][$00:03AE] + $00FF + $00FF
が新たな行動ポイント[$00:03AF][$00:03AE]になる。
結果として、行動ポイントは、
[$00:03AF][$00:03AE] + $01FE
というように、元の行動ポイントに$01FEを加算した値になる。
技を出した場合、[$00:03AF]が必ず$01以上になることがわかる。
この処理の後に$C1/93DC~$C1/93E0で[$00:03B8]に$80を書き込んでいる。
これにより、
| アドレス | 値 |
|---|---|
[$00:03B7] | $10 |
[$00:03B8] | $80 |
となる。
味方が向き変え時の行動ポイント処理は以下の通り。
後で説明するが、移動と処理が一部共通。
$C1/281B JSR $2808 [$C1:2808] ;[$C1:2808]へジャンプ $C1/2808 LDA $0035,x[$00:1C35] ;Aに[$00:1C35](速(現在値))をロード $C1/280B CMP #$E2 ;Aと$E2を減算比較(ステータスレジスタ変更のみ) $C1/280D BCC $02 [$2811] ;キャリーフラグが立っていないとき[$2811]分岐 ;キャリーフラグON $C1/280F LDA #$E2 ;Aに$E2をロード ;キャリーフラグOFF $C1/2811 LSR A ;Aを論理右シフト (/2) $C1/2812 LSR A ;Aを論理右シフト (/2) $C1/2813 STA $10 [$00:0310] ;Aを[$00:0310]に書き込み $C1/2815 LDA #$40 ;Aに$40をロード $C1/2817 SEC ;キャリーフラグON $C1/2818 SBC $10 [$00:0310] ;A - [$00:0310] $C1/281A RTS ;サブルーチン戻り $C1/281E LSR A ;Aを論理右シフト (/2) $C1/281F BRA $07 [$2828] ;フラグにかかわりなく常に分岐[$2828] $C1/2828 REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/282A AND #$00FF ;Aと$00FFで論理積 $C1/282D ADC $AE [$00:03AE] ;A + [$00:03AF][$00:03AE] $C1/282F STA $AE [$00:03AE] ;Aを[$00:03AF][$00:03AE]に書き込み $C1/2831 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/2833 RTS ;サブルーチン戻り $C1/9920 LDA #$40 ;Aに$40をロード $C1/9922 STA $B8 [$00:03B8] ;Aを[$00:03B8]に書き込み $C1/9924 LSR A ;Aを論理右シフト (/2) $C1/9925 STA $6C [$00:036C] ;Aを[$00:036C]に書き込み $C1/9927 RTS ;サブルーチン戻り
$C1/2808~$C1/281Aの処理は、
$40 - trunc(trunc(速(現在値)/2)/2)
つまり、
$40 - trunc(速(現在値)/4)
だが、該当キャラの(速(現在値))が$E2(10進数226)以上の場合は、速(現在値)を$E2として計算している。
そうしないと$40 - trunc(速(現在値)/4)が$40以上の値となり、$C1/2818の引き算で答えが負の値になってしまうからであろう。
なお、キャラの素の上限99に装備補正最大値127を加えた値も226である。つまりキャラの通常状態の速の上限が226であるが、バフで255まで上げることができるので、上のような処理が必要になる。
なので、速(現在値)を単に「速」とすると、
$40 - trunc(trunc(min(速, $E2)/2)/2)
= $40 - trunc(min(速, $E2)/4)
が、$C1/281Aの時点でAに入ることになり、最小値は$02で最大値は$40である。
$C1/281Eで、この値を更に論理右シフトするので、
trunc($40 - trunc(min(速, $E2)/4))/2)
= $20 - trunc(min(速, $E2)/8)
この値が、$C1/282D~の処理で、行動ポイント[$00:03AF][$00:03AE]に加算される。
つまり向き変えで行動ポイントに加算される値は$01~$20(1~32)ということになる。
速が高いキャラほど、行動ポイントの加算量が少なくなる。
行動ポイントの処理後、[$00:03B8]に$40、[$00:036C]に$20を書き込み、処理終了となる。
味方が移動時の行動ポイント処理は以下の通り。
$C1/96CB JSR $2821 [$C1:2821] ;[$C1/2821]へジャンプ $C1/2821 JSR $2808 [$C1:2808] ;[$C1:2808]へジャンプ $C1/2808 LDA $0035,x[$00:1C35] ;Aに[$00:1C35](速(現在値))をロード $C1/280B CMP #$E2 ;Aと$E2を減算比較(ステータスレジスタ変更のみ) $C1/280D BCC $02 [$2811] ;キャリーフラグが立っていないとき[$2811]分岐 ;キャリーフラグON $C1/280F LDA #$E2 ;Aに$E2をロード ;キャリーフラグOFF $C1/2811 LSR A ;Aを論理右シフト (/2) $C1/2812 LSR A ;Aを論理右シフト (/2) $C1/2813 STA $10 [$00:0310] ;Aを[$00:0310]に書き込み $C1/2815 LDA #$40 ;Aに$40をロード $C1/2817 SEC ;キャリーフラグON $C1/2818 SBC $10 [$00:0310] ;A - [$00:0310] $C1/281A RTS ;サブルーチン戻り $C1/2824 BRA $02 [$2828] ;フラグにかかわりなく常に分岐[$2828] $C1/2828 REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/282A AND #$00FF ;Aと$00FFで論理積 $C1/282D ADC $AE [$00:03AE] ;A + [$00:03AF][$00:03AE] $C1/282F STA $AE [$00:03AE] ;Aを[$00:03AF][$00:03AE]に書き込み $C1/2831 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/2833 RTS ;サブルーチン戻り $C1/96CE LDA #$40 ;Aに$40をロード $C1/96D0 STA $B8 [$00:03B8] ;Aを[$00:03B8]に書き込み $C1/96D2 STA $6C [$00:036C] ;Aを[$00:036C]に書き込み $C1/96D4 LDA #$00 ;Aに$00をロード $C1/96D6 STA $001E,x[$00:1C1E] ;Aを[$00:1C1E]に書き込み $C1/96D9 LDA #$04 ;Aに$04をロード $C1/96DB STA $001F,x[$00:1C1F] ;Aを[$00:1C1F]に書き込み $C1/96DE LDA #$08 ;Aに$08をロード $C1/96E0 STA $62 [$00:0362] ;Aを[$00:0362]に書き込み $C1/96E2 LDA #$20 ;Aに$20をロード $C1/96E4 STA $0005,x[$00:1C05] ;Aを[$00:1C05]に書き込み $C1/96E7 LDA #$0C ;Aに$0Cをロード $C1/96E9 STA $0007,x[$00:1C07] ;Aを[$00:1C07]に書き込み $C1/96EC STZ $0006,x[$00:1C06] ;[$00:1C06]に$00を書き込み $C1/96EF JSR $4343 [$C1:4343] ;[$C1:4343]へジャンプ
$C1/2808~$C1/281Aは、向き変えと共通処理なので、Aに$40 - trunc(min(速, $E2)/4)が入る。
その後の$C1/2824~だが、向き変えのように論理右シフトが挟まることなく、そのまま行動ポイント[$00:03AF][$00:03AE]に加算される。
つまり、移動またはYボタン足踏みで行動ポイントに加算される値は$02~$40(2~64)ということになる。
速が高いキャラほど、行動ポイントの加算量が少なくなる。
行動ポイントの処理後、[$00:03B8]に$40、[$00:036C]に$40を書き込む。
$C1/96D4~の説明はここでは省略。
パスとYボタン足踏みはまったく同じサブルーチンを通る。
$C1/9572 JSR $2821 [$C1:2821] ;[$C1:2821]へジャンプ $C1/2821 JSR $2808 [$C1:2808] ;[$C1:2808]へジャンプ $C1/2808 LDA $0035,x[$00:1C35] ;Aに[$00:1C35](速(現在値))をロード $C1/280B CMP #$E2 ;Aと$E2を減算比較(ステータスレジスタ変更のみ) $C1/280D BCC $02 [$2811] ;キャリーフラグが立っていないとき[$2811]分岐 $C1/2811 LSR A ;Aを論理右シフト (/2) $C1/2812 LSR A ;Aを論理右シフト (/2) $C1/2813 STA $10 [$00:0310] ;Aを[$00:0310]に書き込み $C1/2815 LDA #$40 ;Aに$40をロード $C1/2817 SEC ;キャリーフラグON $C1/2818 SBC $10 [$00:0310] ;A - [$00:0310] $C1/281A RTS ;サブルーチン戻り $C1/2824 BRA $02 [$2828] ;フラグにかかわりなく常に分岐[$2828] $C1/2828 REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/282A AND #$00FF ;Aと$00FFで論理積 $C1/282D ADC $AE [$00:03AE] ;A + [$00:03AF][$00:03AE] $C1/282F STA $AE [$00:03AE] ;Aを[$00:03AF][$00:03AE]に書き込み $C1/2831 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/2833 RTS ;サブルーチン戻り $C1/9575 LDA #$40 ;Aに$40をロード $C1/9577 STA $6C [$00:036C] ;Aを[$00:036C]に書き込み $C1/9579 STA $B8 [$00:03B8] ;Aを[$00:03B8]に書き込み $C1/957B LDX $5A [$00:035A] ;Xに[$00:035A]をロード $C1/957D JSR $2CB9 [$C1:2CB9] ;[$C1:2CB9]へジャンプ
$C1/2808~$C1/281A、$C1/2824~$C1/2833と、移動時の処理とまったく同じであるから、行動ポイントの変動も同一となる。
行動ポイントの処理後、[$00:03B8]に$40、[$00:036C]に$40を書き込むのも同じ。
味方の行動について、以上を整理してみると以下のようになる。
| 行動 | 行動ポイント[$00:03AF][$00:03AE] | [$00:03B7] | [$00:03B8] | [$00:036C] |
|---|---|---|---|---|
| 技を出す | +$01FE | $10 | $80 | - |
| 移動 | +($40 - trunc(min(速, $E2)/4)) | - | $40 | $40 |
| パス, Yボタン足踏み | +($40 - trunc(min(速, $E2)/4)) | - | $40 | $40 |
| 向き変え | +($20 - trunc(min(速, $E2)/8)) | - | $40 | $20 |
行動ポイントが256($0100)を越えたら敵ターンに回ってしまうので、速が高いキャラほど味方ターンに移動・向き変えが多くできる、ということになる。
また、どの処理においても、行動ポイントの加算時、キャリー(繰り上がり)を考慮していない。
つまり、行動ポイント2バイトが$FFFF以上になってオーバーフローする場合を考慮していない。
このため、行動ポイントの加算時に$FFFFを越えたら5桁に達し下4桁は$0000へ戻ることになる。
$0000~$00FFの間なら味方ターンが回ってくるので、うまく調整することで味方が連続行動できる、ということになる。
ただ、通常はやろうと思ってもかなり難しい。
敵が自分から行動しない、SF編の6ステージ目のジェムパラペット戦で、キャプテンスクウェアが敵のいないマスにひたすら攻撃したり向き変えやYボタン連打などを繰り返せば、時間はかかるがオーバーフローを起こすことができる。
なお、先の戦闘関係の解説 > ターンや行動順の詳細でも触れているが、技使用時、技の範囲決定画面で向き変えのLボタンまたはRボタンを押すと、敵は一切行動できない状態で行動ポイントのみ上昇させることができる。おそらくバグである。
この方法ならどの戦闘でも連続して味方ターン状態にできるが、非常に面倒なので、実用的とは言い難い。
ここまでが味方の行動について。
以下、敵の行動による行動ポイント計算を記す。
敵が技を出す時の行動ポイント関係の処理は下の通り。
敵番号0(X:1B00)での処理とする。
$C1/941E BEQ $1F [$943F] ;ゼロフラグが立っているとき[$943F]分岐 $C1/9420 STZ $B8 [$00:03B8] ;[$00:03B8]に$00を書き込み $C1/9422 STZ $B7 [$00:03B7] ;[$00:03B7]に$00を書き込み $C1/9424 STZ $AF [$00:03AF] ;[$00:03AF](行動ポイント上1バイト)に$00を書き込み $C1/9426 LDA $AE [$00:03AE] ;Aに[$00:03AE](行動ポイント下1バイト)をロード $C1/9428 AND #$6F ;Aと$6F(%0110 1111)で論理積 $C1/942A ORA #$10 ;Aと$10(%0001 0000)で論理和 $C1/942C STA $AE [$00:03AE] ;Aを[$00:03AE](行動ポイント下1バイト)に書き込み $C1/942E LDX $AC [$00:03AC] ;Xに[$00:03AC]をロード $C1/9430 LDA #$20 ;Aに$20をロード $C1/9432 STA $0005,x[$00:1B05] ;Aを[$00:1B05]に書き込み $C1/9435 LDA $63 [$00:0363] ;Aに[$00:0363]をロード $C1/9437 ORA #$10 ;Aと$10で論理和 $C1/9439 STA $63 [$00:0363] ;Aを[$00:0363]に書き込み $C1/943B PLY ;Yレジスタにスタックからプル $C1/943C STY $AC [$00:03AC] ;Yを[$00:03AC]に書き込み $C1/943E RTS ;サブルーチン戻り
行動ポイントの処理の前に、
[$00:03B8]
[$00:03B7]
[$00:03AF](行動ポイント上1バイト)
に$00を書き込んでいる。
[$00:03B7]と[$00:03B8]は、味方が行動した時に技を使用した時に値を書き込んだアドレスである。
ここでどちらも初期値の$00にに戻ったことになる。
また、行動ポイント上1バイトにあたる[$00:03AF]にも$00を書き込んでいることから、ここで行動ポイントが$100未満になり、敵が技を出すと味方ターンに回ることもわかる。
$C1/9426からは[$00:03AE](行動ポイント下1バイト)の処理である。
[$00:03AE]と$6F(%0110 1111)で論理積を取り、更に$10(%0001 0000)と論理和を取った値が、新たに[$00:03AE](行動ポイント下1バイト)に書き込まれている。
[$00:03AE] & $6F | $10
(&はビット論理積演算子、|はビット論理和演算子)
を、新たな行動ポイントにするということである。元の行動ポイントに加算・減算の処理ではない。
[$00:03AE]は$00~$FFの値のはずだから、$6Fと論理積を取ると、$00~$6Fのいずれかの値になる。
更に$10と論理和を取ると、$10~$7Fのいずれかになる。10進数なら16~127となる。
つまり、敵が技を出した時、行動ポイント2バイトは、$0010~$007F(16~127)のいずれかの値となって味方ターンになる。
あとは[$00:1B05](敵の状態)に$20を書き込み、[$00:0363]と$10の論理和を新たに[$00:0363]に書き込んで、処理終了である。
敵が移動する時の処理は以下のとおり。
$C1/283A JSR $2800 [$C1:2800] ;[$C1:2800]へジャンプ $C1/2800 LDX $AC [$00:03AC] ;Xに[$00:03AC]をロード $C1/2802 LDA $7E8F04,x[$7E:AA04] ;Aに[$7E:AA04](速(現在値))をロード $C1/2806 BRA $03 [$280B] ;フラグにかかわりなく常に分岐[$280B] $C1/280B CMP #$E2 ;A(速(現在値))と$E2を減算比較(ステータスレジスタ変更のみ) $C1/280D BCC $02 [$2811] ;キャリーフラグが立っていないとき[$2811]分岐 $C1/2811 LSR A ;Aを論理右シフト (/2) $C1/2812 LSR A ;Aを論理右シフト (/2) $C1/2813 STA $10 [$00:0310] ;Aを[$00:0310]に書き込み $C1/2815 LDA #$40 ;Aに$40をロード $C1/2817 SEC ;キャリーフラグON $C1/2818 SBC $10 [$00:0310] ;A - [$00:0310] $C1/281A RTS ;サブルーチン戻り $C1/283D BRA $02 [$2841] ;フラグにかかわりなく常に分岐[$2841] $C1/2841 REP #$20 ;Aを16bit幅に変更、Mフラグをクリア $C1/2843 AND #$00FF ;Aと$00FFで論理積 $C1/2846 STA $20 [$00:0320] ;Aを[$00:0321][$00:0320]に書き込み $C1/2848 LDA $AE [$00:03AE] ;Aに[$00:03AF][$00:03AE]をロード $C1/284A SEC ;キャリーフラグON $C1/284B SBC $20 [$00:0320] ;A - [$00:0321][$00:0320] $C1/284D BCS $03 [$2852] ;キャリーフラグが立っているとき[$2852]分岐 ;キャリーフラグOFF $C1/284F LDA #$0010 ;Aに$0010をロード ;キャリーフラグON $C1/2852 STA $AE [$00:03AE] ;Aを[$00:03AE][$00:03AF]に書き込み $C1/2854 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/2856 RTS ;サブルーチン戻り $C1/E3FD STZ $B8 [$00:03B8] ;[$00:03B8]に$00を書き込み $C1/E3FF LDX $AC [$00:03AC] ;Xに[$00:03AC]をロード $C1/E401 JSR $4317 [$C1:4317] ;[$C1:4317]へジャンプ
味方移動時と処理は似ている。
$C1/2802で、[$7E:AAn4](敵番号nの速(現在値))をロードしている。この値を「速」とする。
$C1/280B~$C1/281Aで、Aに、
$40- trunc(min(速, $E2)/4)
と、味方時とまったく同じ計算式で値を算出していることがわかる。
ただし、$C1/283D以降の処理では、行動ポイント[$00:03AF][$00:03AE]から$40 - trunc(min(速, $E2)/4)を引いている。味方時の処理のように加算ではない。
減算のため負の値になる可能性もあり得るが、キャリーフラグで分岐させている。
キャリーフラグが立たない、つまり減算結果が0または負の値だった時は、Aに$0010をロードし、これを新たに行動ポイント[$00:03AF][$00:03AE]に書き込んでいる。
よって、
[$00:03AF][$00:03AE] - ($40 - trunc(min(速, $E2)/4)) > 0[$00:03AF][$00:03AE]に書き込む[$00:03AF][$00:03AE] - ($40 - trunc(min(速, $E2)/4)) ≦ 0[$00:03AF][$00:03AE]に$0010を書き込むということになる。
行動ポイントが負の値にならないよう、きちんと処理されていることがわかる。
減算結果が$01~$09なら$0001~$0009が行動ポイントになるが、減算結果が$00以下だと$0010が行動ポイントになるという、少しおもしろいことが起きている。
最後に、[$00:03B8]に$00を書き込んでいる。これは敵が技を出した時と共通。
敵が移動する時と共通処理部分がある。
$C1/2834 JSR $2800 [$C1:2800] ;[$C1:2800]へジャンプ $C1/2800 LDX $AC [$00:03AC] ;Xに[$00:03AC]をロード $C1/2802 LDA $7E8F04,x[$7E:AA04] ;Aに[$7E:AA04](速(現在値))をロード $C1/2806 BRA $03 [$280B] ;フラグにかかわりなく常に分岐[$280B] $C1/280B CMP #$E2 ;A(速(現在値))と$E2を減算比較(ステータスレジスタ変更のみ) $C1/280D BCC $02 [$2811] ;キャリーフラグが立っていないとき[$2811]分岐 $C1/2811 LSR A ;Aを論理右シフト (/2) $C1/2812 LSR A ;Aを論理右シフト (/2) $C1/2813 STA $10 [$00:0310] ;Aを[$00:0310]に書き込み $C1/2815 LDA #$40 ;Aに$40をロード $C1/2817 SEC ;キャリーフラグON $C1/2818 SBC $10 [$00:0310] ;A - [$00:0310] $C1/281A RTS ;サブルーチン戻り $C1/2837 LSR A ;Aを論理右シフト (/2) $C1/2838 BRA $07 [$2841] ;フラグにかかわりなく常に分岐[$2841] $C1/2841 REP #$20 ;Aを16bit幅に変更、Mフラグをクリア $C1/2843 AND #$00FF ;Aと$00FFで論理積 $C1/2846 STA $20 [$00:0320] ;Aを[$00:0320]に書き込み $C1/2848 LDA $AE [$00:03AE] ;Aに[$00:03AF][$00:03AE]をロード $C1/284A SEC ;キャリーフラグON $C1/284B SBC $20 [$00:0320] ;A - [$00:0320] $C1/284D BCS $03 [$2852] ;キャリーフラグが立っているとき[$2852]分岐 ;キャリーフラグOFF $C1/284F LDA #$0010 ;Aに$0010をロード ;キャリーフラグON $C1/2852 STA $AE [$00:03AE] ;Aを[$00:03AF][$00:03AE]に書き込み $C1/2854 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/2856 RTS ;サブルーチン戻り $C1/E463 STZ $B8 [$00:03B8] ;[$00:03B8]に$00を書き込み $C1/E465 RTS ;サブルーチン戻り $C1/908D RTS ;サブルーチン戻り
$C1/2800~$C1/281Aは共通処理で、異なるのは$C1/2837で論理右シフトしていることのみ。
味方キャラの処理同様に向き変えだと変動は移動の1/2になる。
結果、
[$00:03AF][$00:03AE] - ($20 - trunc(min(速, $E2)/8)) > 0[$00:03AF][$00:03AE]に書き込む[$00:03AF][$00:03AE] - ($20 - trunc(min(速, $E2)/8)) ≦ 0[$00:03AF][$00:03AE]に$0010を書き込むこのようになる。
向き変え時も、最後に、[$00:03B8]に$00を書き込んでいる。
つまり、敵が何か行動すると、必ず[$00:03B8]に$00を書き込むことがわかる。
ここまでが行動ポイントの増減方法だが、では、行動ポイントのチェック自体はどうやっているのか。
$C1/8E51 LDA $AF [$00:03AF] ;Aに[$00:03AF](行動ポイント上1バイト)をロード $C1/8E53 BNE $01 [$8E56] ;ゼロフラグが立っていないとき[$8E56]分岐 ;ゼロフラグON(味方ターンへ) $C1/8E55 RTS ;サブルーチン戻り ;ゼロフラグOFF $C1/8E56 LDA $B8 [$00:03B8] ;Aに[$00:03B8]をロード $C1/8E58 BNE $01 [$8E5B] ;ゼロフラグが立っていないとき[$8E5B]分岐 ;ゼロフラグON(味方ターンへ) $C1/8E5A RTS ;サブルーチン戻り ;ゼロフラグOFF(敵ターンへ) $C1/8E5B JSR $92C3 [$C1:92C3] ;[$C1:92C3]へジャンプ
このサブルーチンで、行動ポイントをチェックしている。
ただし行動ポイント2バイト[$00:03AF][$00:03AE]の中で、上1バイト[$00:03AF]のみチェックしていることに注意。
$C1/8E51~$C1/8E53は、[$00:03AF]のゼロフラグ分岐である。
[$00:03AF][$00:03AE]2バイトで見ると、行動ポイントが$100以上か$100未満かをチェックしていることと同義になる。
行動ポイントが$100以上なら[$00:03AF]には$00以外の値が入るし、行動ポイントが$100未満なら[$00:03AF]には必ず$00が入ることになる。
ゼロフラグON、つまり行動ポイントが$100未満の時は$C1/8E55に進みサブルーチンを抜ける。
この分岐の後は味方の行動ターンになる。
ゼロフラグOFF、つまり行動ポイントが$100以上の場合、続いて$C1/8E58で、[$00:03B8]のゼロフラグ判定をする。
ここまで[$00:03B8]に書き込まれた数値についてまとめると、
| 行動 | [$00:03B8] |
|---|---|
| 味方が技を出す | $80 |
| 味方が移動 | $40 |
| 味方がパスまたはYボタン足踏み | $40 |
| 味方が向き変え | $40 |
| 敵の行動すべて | $00 |
つまり味方の行動後は必ず$00以外の値で、敵の行動後は必ず$00である。
ゼロフラグが立つ、つまり敵の行動後は$C1/8E5Aに進みサブルーチンを抜ける。
「行動ポイントが$100以上」かつ「敵の行動後」だと、必ず敵ターンが終了する仕組みがここにある。
本来、行動ポイントが$100以上なら敵ターンにまわるはずなのだが、敵の行動後に限り、敵ターンが終わって味方ターンが回ることになる。
ゼロフラグが立たない場合、つまり味方の行動後は$C1/8E5Bに進み、更に[$C1:92C3]以降の処理を行う。
つまり、「行動ポイントが$100以上」かつ「味方の行動後」は、必ず敵ターンに移行する。
[$C1:92C3]以降の処理は敵ターン時の処理、ということである。
以上で行動ポイントについての解説になる。
行動ポイントの増減後、行動ポイントをチェックし、敵ターンと味方ターンどちらに移行するかの分岐を行っていることがわかる。
味方ターンが回ってきた時、味方の誰が行動するかは、隊形順及び[$00:035B][$00:035A]に入る値で決まる。
簡単に言えば、味方は隊形の上・左・右・下の順に行動し、次に行動可能なキャラが技をタメている最中、または行動不能な状態異常だと順番を飛ばされる。
隊形と味方キャラの対応値は以下アドレスに記録されている(フィールド、戦闘共通)。
| アドレス | キャラ |
|---|---|
$00:0AB0 | 主人公の行動順-1 |
$00:0AB1 | 味方キャラ1の行動順-1 |
$00:0AB2 | 味方キャラ2の行動順-1 |
$00:0AB3 | 味方キャラ3の行動順-1 |
上アドレスに入る値は、$00~$03のいずれか、味方キャラ順は加入順。
例えば功夫編なら、主人公は老師、味方キャラ1~3は加入順により変動するがユン、レイ、サモとしたら、上にレイ、左にサモ、右に老師、下にユンだと、$00:0AB0~$00:0AB3には順に、
| アドレス | キャラ | 値 |
|---|---|---|
$00:0AB0 | 老師の行動順-1 | $02(3番目) |
$00:0AB1 | ユンの行動順-1 | $03(4番目) |
$00:0AB2 | レイの行動順-1 | $00(1番目) |
$00:0AB3 | サモの行動順-1 | $01(2番目) |
こんな感じで値が入る。
$00:0AB0~$00:0AB3の値に対応した順で、戦闘中のキャラアドレス開始位置が決まる。
| キャラ | アドレス |
|---|---|
| 1 | $00:1C00 |
| 2 | $00:1C40 |
| 3 | $00:1C80 |
| 4 | $00:1CC0 |
[$00:035B][$00:035A]には行動可能な味方キャラのアドレス部分($1C00, $1C40, $1C80, $1CC0)が入る。
味方が行動すると更新されていく。
戦闘中は、$00:0AB0~$00:0AB3に入っている値の小さい順に行動していくことになる。
戦闘開始時、どのキャラが1番最初に行動するか、つまり$00:0AB0~$00:0AB3のどれに$00が入っているかは、以下サブルーチンで判断している。
$C1/F55D LDA $0040 [$00:0040] ;Aに[$00:0040]をロード ;(中略) $C1/F570 LDX #$1CC0 ;Xに$1CC0をロード $C1/F573 STX $5A [$00:035A] ;Xを[$00:035B][$00:035A]に書き込み ;(中略) $C1/F621 STZ $60 [$00:0360] ;[$00:0360]に$00を書き込み $C1/F623 JSR $FB2B [$C1:FB2B] ;[$C1:FB2B]へジャンプ ; $C1/FB2B LDA $56 [$00:0356] ;Aに[$00:0356]をロード $C1/FB2D AND #$F0 ;Aと$F0で論理積 $C1/FB2F BEQ $04 [$FB35] ;ゼロフラグが立っているとき[$FB35]分岐 $C1/FB35 LDY #$0AB0 ;Yに$0AB0をロード $C1/FB38 STZ $08 [$00:0308] ;[$00:0308]に$00を書き込み ; ;ループ処理開始 $C1/FB3A LDA $0000,y[$00:0AB0+n] ;Aに[$00:0AB0+n]をロード $C1/FB3D CMP $60 [$00:0360] ;Aと[$00:0360]($00)を減算比較(ステータスレジスタ変更のみ) $C1/FB3F BEQ $0C [$FB4D] ;ゼロフラグが立っているとき[$FB4D]分岐 ;ゼロフラグOFF(行動順が$00ではない) $C1/FB41 INY ;Yをインクリメント +1 $C1/FB42 INC $08 [$00:0308] ;[$00:0308]をインクリメント +1 $C1/FB44 LDA $08 [$00:0308] ;Aに[$00:0308]($00+n)をロード $C1/FB46 CMP #$04 ;Aと$04を減算比較(ステータスレジスタ変更のみ) $C1/FB48 BNE $F0 [$FB3A] ;ゼロフラグが立っていないとき[$FB3A]分岐 ;ループ処理ここまで ; ;ゼロフラグON ;行動順が$00のキャラでループ抜ける ;[$00:0308]にループ回数 $C1/FB4D LDA $08 [$00:0308] ;Aに[$00:0308]をロード $C1/FB4F XBA ;Aレジスタの上位バイトと下位バイトを交換 $C1/FB50 REP #$20 ;Aを16bit幅に変更、Mフラグをクリア $C1/FB52 AND #$0300 ;Aと$0300で論理積 $C1/FB55 LSR A ;Aを論理右シフト (/2) $C1/FB56 LSR A ;Aを論理右シフト (/2) $C1/FB57 ADC #$1C00 ;A + $1C00 $C1/FB5A TAY ;Aの値をYレジスタに転送 $C1/FB5B SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/FB5D RTS ;サブルーチン戻り
$C1/FB3A~$C1/FB48のループ処理で、$00:0AB0から順に値をチェックするが、$00が入っている場合ループを抜ける。[$00:0308]にはループ回数が入る。
$C1/FB4D~の処理で、$C1/FB55ではAに$0n00(nはループ回数)が入り、$C1/FB55~の計算で、該当キャラのアドレス部分($1C00, $1C40, $1C80, $1CC0)が算出され、$C1/FB5AでYレジスタに送られる。
また、この時点で、[$00:035B][$00:035A]に$1CC0が書き込まれる。
後は、初期値が$00の[$00:0360]の値を加算しながら$C1/FB2B~$C1/FB5Dの処理を行うことで、n番目に行動するキャラのアドレス部分($1C00, $1C40, $1C80, $1CC0)を全員分計算できる、ということになる。
[$00:0360]の加算(インクリメント)処理が以下。
$C1/F661 INX ;Xをインクリメント +1 $C1/F662 INC $60 [$00:0360] ;A[$00:0360]をインクリメント +1 $C1/F664 LDA $60 [$00:0360] ;Aに[$00:0360]をロード $C1/F666 CMP #$04 ;Aと$04を減算比較(ステータスレジスタ変更のみ) $C1/F668 BNE $B9 [$F623] ;ゼロフラグが立っていないとき[$F623]分岐 $C1/F623 JSR $FB2B [$C1:FB2B] ;[$C1:FB2B]へジャンプ
全キャラ分判定が終わった所で、[$00:0360]が$00の状態でもう一度$C1/FB2B~$C1/FB5Dの処理を行い(二度手間なような気もするが)、最初に行動するキャラのアドレス部分がYに入った状態で以下処理が入る。
$C1/F70C INC $60 [$00:0360] ;[$00:0360]をインクリメント +1 $C1/F70E LDA $0001,y[$00:1CC1] ;Aに[$00:1C01+40y]をロード $C1/F711 BIT #$40 ;Aと$40で論理積(ステータスフラグ変更のみ) $C1/F713 BNE $0D [$F722] ;ゼロフラグが立っていないとき[$F722]分岐 ;ゼロフラグOFF $C1/F722 STY $5A [$00:035A] ;Yを[$00:035B][$00:035A]に書き込み $C1/F724 JSR $F728 [$C1:F728] ;[$C1:F728]へジャンプ
$C1/F70E~$C1/F713の判定は最初に行動するキャラの戦闘状態の確認で、ゼロフラグが立つのは戦闘状態が$00(戦闘離脱)、$20(味方キャラ敵対)の時。つまり、プレイヤーが該当キャラを操作できない場合である。
それ以外は味方ターンが回ることとなり(実際にはさらに判定が続くが)、これで$C1/F722にて、最初に行動するキャラのアドレス($1C00, $1C40, $1C80, $1CC0)が[$00:035B][$00:035A]に書き込まれることになる。
以上で最初に行動するキャラと、$1C00, $1C40, $1C80, $1CC0をどのキャラに割り振るかが決まる。
以降は、Xレジスタや[$00:035B][$00:035A]の値を参照して、味方ターンが回った時に次の行動キャラを判定していく。
サブルーチンは以下の通り。
サブルーチン開始時点でXに入っているのが、ひとつ前に行動した味方キャラのアドレス部分($1C00, $1C40, $1C80, $1CC0)の値になる。
$C1/9F02 TXA ;Xレジスタの値をAレジスタに転送 $C1/9F03 ROL A ;Aをキャリーフラグを含めた9bitで左ローテート $C1/9F04 ROL A ;Aをキャリーフラグを含めた9bitで左ローテート $C1/9F05 ROL A ;Aをキャリーフラグを含めた9bitで左ローテート $C1/9F06 AND #$03 ;Aと$03で論理積 $C1/9F08 STA $10 [$00:0310] ;Aを[$00:0310]に書き込み($1C??の??部分) $C1/9F0A STZ $11 [$00:0311] ;[$00:0311]に$00を書き込み $C1/9F0C LDY $10 [$00:0310] ;Yに[$00:0311][$00:0310]をロード $C1/9F0E LDA $0AB0,y ;Aに[$00:0AB0+n](ひとつ前に行動したキャラ$00~$03)をロード $C1/9F11 STA $12 [$00:0312] ;Aを[$00:0312]に書き込み $C1/9F13 LDA #$04 ;Aに$04をロード $C1/9F15 STA $09 [$00:0309] ;Aを[$00:0309]に書き込み $C1/9F17 LDA $12 [$00:0312] ;Aに[$00:0312](ひとつ前に行動したキャラ$00~$03)をロード $C1/9F19 INC A ;Aをインクリメント +1 $C1/9F1A AND #$03 ;Aと$03で論理積 $C1/9F1C STA $12 [$00:0312] ;Aを[$00:0312](ひとつ前に行動したキャラ$01~$04)に書き込み $C1/9F1E STZ $08 [$00:0308] ;[$00:0308]に$00を書き込み $C1/9F20 LDY #$0000 ;Yに$0000をロード ; ;ループ処理 $C1/9F23 LDA $0AB0,y[$00:0AB0] ;Aに[$00:0AB0+n]をロード $C1/9F26 CMP $12 [$00:0312] ;Aと[$00:0312]を減算比較(ステータスレジスタ変更のみ) $C1/9F28 BEQ $0B [$9F35] ;ゼロフラグが立っているとき[$9F35]分岐 $C1/9F2A INC $08 [$00:0308] ;[$00:0308](初期値$00)をインクリメント +1 $C1/9F2C INY ;Yをインクリメント +1 $C1/9F2D CPY #$0004 ;Yと$0004を減算比較(ステータスレジスタ変更のみ) $C1/9F30 BNE $F1 [$9F23] ;ゼロフラグが立っていないとき[$9F23]分岐 ;ループ処理ここまで $C1/9F35 LDA $08 [$00:0308] ;Aに[$00:0308](ループ回数1~4)をロード $C1/9F37 ROR A ;Aをキャリーフラグを含めた9bitで右ローテート $C1/9F38 ROR A ;Aをキャリーフラグを含めた9bitで右ローテート $C1/9F39 ROR A ;Aをキャリーフラグを含めた9bitで右ローテート $C1/9F3A AND #$C0 ;Aと$C0で論理積 $C1/9F3C STA $10 [$00:0310] ;Aを[$00:0310]に書き込み $C1/9F3E LDA #$1C ;Aに$1Cをロード $C1/9F40 STA $11 [$00:0311] ;Aを[$00:0311]に書き込み $C1/9F42 LDX $10 [$00:0310] ;Xに[$00:0310]をロード $C1/9F44 LDA $0000,x ;Aに[$00:1C00+40n]をロード $C1/9F47 INC A ;Aをインクリメント +1 $C1/9F48 BEQ $08 [$9F52] ;ゼロフラグが立っているとき[$9F52]分岐 $C1/9F4A LDA $0001,x ;Aに[$00:1C01+40n](戦闘状態)をロード $C1/9F4D BIT #$40 ;Aと$40で論理積(ステータスフラグ変更のみ) $C1/9F4F BEQ $01 [$9F52] ;ゼロフラグが立っているとき[$9F52]分岐 $C1/9F51 RTS ;サブルーチン戻り $C1/9EFF STX $5A [$00:035A] ;Xを[$00:035B][$00:035A]に書き込み $C1/9F01 RTS ;サブルーチン戻り $C1/9963 JSR $7AED [$C1:7AED] ;[$C1:7AED]へジャンプ $C1/7AED LDX $5A [$00:035A] ;Xに[$00:035B][$00:035A]をロード $C1/7AEF LDA $0039,x ;Aに[$00:1C39+40n](状態異常)をロード $C1/7AF2 BIT #$B0 ;Aと$B0で論理積(ステータスフラグ変更のみ) $C1/7AF4 BNE $0C [$7B02] ;ゼロフラグが立っていないとき[$7B02]分岐 $C1/7AF6 LDA $0005,x ;Aに[$00:1C05+40n](技関係状態)をロード $C1/7AF9 BIT #$60 ;Aと$60で論理積(ステータスフラグ変更のみ) $C1/7AFB BNE $05 [$7B02] ;ゼロフラグが立っていないとき[$7B02]分岐 $C1/7AFD STX $5A [$00:035A] ;Xを[$00:035B][$00:035A]に書き込み $C1/7AFF LDA #$FF ;Aに$FFをロード $C1/7B01 RTS ;サブルーチン戻り
簡単にまとめてしまうと、
$00:0AB0~3の誰かを判定$00:0AB0~3に格納されている数値を+1する($01~$04) = [$00:0312][$00:0312]と$00:0AB0~3が一致するまでループ処理(次の行動順のキャラ検索)[$00:0308]($01~$04)を右ローテート3回 & $C0で、次のキャラの$1C??の$??部分が算出できる$C1/9F3Aで[$00:0310]に書き込まれたのが$1C??の$??部分である。
これで、$C1/9F42でXにロードする値が、次に行動する味方キャラのアドレス部分になった。
$C1/9F4Aでは、次に行動する味方キャラの戦闘状態をロードしており、$40と論理積を取ってゼロフラグ判定なので、戦闘離脱・味方キャラ敵対状態ではないかの判定になる。
ゼロフラグが立たない場合、更に$C1/7AED~$C1/7B01で、
$C1/7AEF~)$C1/7AF6~)ことを確認した上で、現在の行動キャラとしてXが[$00:035B][$00:035A]に書き込まれる。
味方ターンが回る度に、上の処理で次に行動するキャラが決まる。
次ページでは、順序ポイントについて説明する。