TOP > プログラミング関係解説&調査 > 敵ターンにおける行動選択

敵ターンにおける行動選択

当ページの内容は、ある程度のプログラミングの知識を必要とする。
まず、プログラミング関係解説&調査をひととおり読んでいただきたい。

行動ポイントと順序ポイントで、どの敵が行動するかが決まるが、では実際にどのように行動を決めるのか。
詳しくは、ZsnsK's F**kin' Site様にある。
前ページまでの行動ポイント順序ポイントの知識を前提としているので、予め御覧いただきたい。

敵ターンが回ってきた時、順序ポイント最大の敵が行動するが、それは$C1/9335までで決まる。
その後、$C1/8E5E$C1/8E7Fで、「行動不能な状態異常(石化、マヒ、眠り)で行動順が回ってきたかどうか」の判定をする。
行動不能な状態異常でなければ、$C1/90A2$C1/90C4で、敵行動前の行動異常解除判定を行う(行動異常回復判定)。

その後の、$C1/8E82からが行動選択になる。

移動または向き変え判定

この先は敵種類1、敵番号0の前提で進める。

$C1/8E82 JSR $1CF7  [$C1:1CF7]   ;[$C1:1CF7]へジャンプ
;
;行動異常のデータ呼び出し
$C1/1CF7 PHX                     ;Xをスタックにプッシュ
$C1/1CF8 LDA $7E8F02,x           ;Aに[$7E:AAn2](敵番号nの行動異常)をロード ($00をロード)
$C1/1CFC ASL A                   ;Aを算術左シフト *2
$C1/1CFD ASL A                   ;Aを算術左シフト *2
$C1/1CFE ASL A                   ;Aを算術左シフト *2
$C1/1CFF REP #$21                ;Aを16bit幅に変更、キャリーフラグクリア
$C1/1D01 AND #$00F8              ;Aと$00F8で論理積
$C1/1D04 ADC $D50060[$D5:0060]   ;A + [$D5:0060]
$C1/1D08 TAX                     ;Aの値をXレジスタに転送
$C1/1D09 SEP #$20                ;MフラグON Aレジスタは8bit幅
$C1/1D0B LDY #$0320              ;Yに$0320をロード
;
;ループ処理ここから
$C1/1D0E LDA $D50000,x[$D5:644B] ;Aに[$D5:644B+n]をロード
$C1/1D12 STA $0000,y[$00:0320]   ;Aを[$00:0320+n]に書き込み
$C1/1D15 INX                     ;Xをインクリメント +1
$C1/1D16 INY                     ;Yをインクリメント +1
$C1/1D17 CPY #$0328              ;Yと$0328を減算比較(ステータスレジスタ変更のみ)
$C1/1D1A BNE $F2    [$1D0E]      ;ゼロフラグが立っていないとき[$1D0E]分岐
;ループ処理ここまで
;
$C1/1D1C PLX                     ;Xレジスタにスタックからプル
$C1/1D1D RTS                     ;サブルーチン戻り
;
;移動・向き変え判定
$C1/8E85 LDA $7E9106,x[$7E:AC06] ;Aに[$7E:AC06]をロード
$C1/8E89 LDY $0002,x[$00:1B02]   ;Yに[$00:1B02]をロード
$C1/8E8C REP #$20                ;Aを16bit幅に変更、Mフラグをクリア
$C1/8E8E AND #$000F              ;Aと$000Fで論理積
$C1/8E91 ASL A                   ;Aを算術左シフト *2
$C1/8E92 ADC #$8DFE              ;A + $8DFE
$C1/8E95 TAX                     ;Aの値をXレジスタに転送
$C1/8E96 LDA $C10000,x[$C1:8DFE] ;Aに[$C1:8DFE]をロード
$C1/8E9A STA $1C    [$00:031C]   ;Aを[$00:031C]に書き込み
$C1/8E9C LDX $AC    [$00:03AC]   ;Xに[$00:03AC]をロード
$C1/8E9E SEP #$20                ;MフラグON Aレジスタは8bit幅
$C1/8EA0 JMP ($031C)[$C1:8EA3]   ;[$C1:8EA3]へジャンプ(レジスタをスタックに積まない)
;
$C1/8EA3 LDA $0021,y[$00:1A21]   ;Aに[$00:1A21](敵種類1の敵データ01)をロード
$C1/8EA6 AND #$0F                ;Aと$0Fで論理積
$C1/8EA8 STA $10    [$00:0310]   ;Aを[$00:0310](移動頻度)に書き込み
$C1/8EAA JSR $6150  [$C1:6150]   ;[$C1:6150]へジャンプ
;
;戦闘乱数計算
$C1/6150 PHX                     ;戦闘乱数計算
;(省略)
$C1/61A4 RTS                     ;乱数がAと[$00:033B]に入る
;
;判定
$C1/8EAD AND #$1F                ;A(乱数$00~$FF)と$1F(%0001 1111)で論理積
$C1/8EAF CMP $10    [$00:0310]   ;Aと[$00:0310](移動頻度)を減算比較(ステータスレジスタ変更のみ)
$C1/8EB1 BCS $03    [$8EB6]      ;キャリーフラグが立っているとき[$8EB6]分岐
;キャリーフラグOFF(移動・向き変え判定ON)
$C1/8EB3 BRL $00A4  [$8F5A]      ;フラグにかかわりなく常に分岐[$8F5A]
;キャリーフラグON(移動・向き変え判定OFF)
$C1/8EB6 JSR $6150  [$C1:6150]   ;[$C1:6150]へジャンプ

行動異常のデータ呼び出し($C1/1CF7$C1/1D1D)は、順序ポイントで説明した通り。
該当の敵の行動異常データ0~7が、[$00:0320][$00:0327]にコピーされる。
その後の$C1/8E85から、まず、移動・向き変え判定を行うのだが、ここから先はここで呼び出される[$7E:ACn6](nは敵番号)が重要になる。
[$7E:ACn6]は初期値$00である。

$C1/8E85$C1/8EA0は敵データのアドレスを呼び出すための計算。
$C1/8EA0の飛び先はJMP ($031C)で指定しているが、これは[$00:031C]に入っている値がアドレスになるという意味で、辿ってみると、$C1/8E85でロードする[$7E:AC06]の値で変わってくるのだが、ここはひとまず、[$7E:AC06]が初期値$00の前提で説明する。

$C1/8EA3で呼び出した[$00:1A21]は敵種類1の敵データ01である。
$C1/8EA6$0Fと論理積を取っているが、敵データ01の下1桁は「移動頻度」というパラメータになる($0~$F)。
移動頻度は[$00:0310]に書き込まれる。

続いて$C1/8EAAから戦闘乱数を生成し、$C1/8EADで、乱数($00$FF)と$1F(%0001 1111)で論理積を取るから、乱数幅が$00$1F0~31)になる。
更に、この値と[$00:0310](移動頻度)で減算比較、

乱数($00~$1F) - 移動頻度($0~$F)
=乱数(0~31) - 移動頻度(0~15)

の結果でキャリーフラグ判定となっている。
減算結果が負の数の時、キャリーフラグOFFで、この時点で移動または向き変えが決定となる。
確率としては、

移動頻度/32

で移動または向き変えである。
移動頻度の値が高いほど、この時点で移動または向き変えの確率が高いことになる。

敵の多くは移動頻度が0で、この最初の移動または向き変え判定では、移動または向き変えになる確率が0となり、技使用判定に移行する。
大半の敵が、「味方に技を出せる位置・向きなら攻撃し、それ以外なら移動」という行動を取るのは、移動頻度が0に設定されているためである。
移動頻度が0だから移動しないということではなく、技使用判定をしても技を出せない状況下なら移動、という判定をしていることになる。

なお、技判定使用をすべて通過し最後の移動判定にたどり着いた場合は以下のように$C1/8EA0の飛び先が$C1/8F5A固定になって、移動確定となる。

$C1/8EA0 JMP ($031C)[$C1:8F5A]   ;[$C1:8F5A]へジャンプ(レジスタをスタックに積まない)
$C1/8F5A LDA #$00                ;Aに$00をロード
$C1/8F5C STA $7E9106,x           ;Aを[$7E9106,x]に書き込み
$C1/8F60 LDA $7E8F07,x           ;Aに[$7E8F07,x]をロード
$C1/8F64 BIT #$02                ;Aと$02で論理積(ステータスフラグ変更のみ)
$C1/8F66 BNE $0F    [$8F77]      ;ゼロフラグが立っていないとき[$8F77]分岐
$C1/8F68 JSR $913A  [$C1:913A]   ;[$C1:913A]へジャンプ

技使用判定

上の移動または向き変え判定で、移動または向き変えとならなかった場合、技使用判定に移る。
つまり$C1/8EB1の判定でキャリーフラグが立った時、$C1/8EB6に進み、戦闘乱数を生成する。

また、敵は技1~4の4種類の技を使うが、敵キャラデータ11~14に技IDが入っている。
敵キャラデータ11から、つまり使用技1から順に技を使用するか判定していく。
なお、敵キャラデータ09の上1ビットが0なら敵技ID、1なら味方技ID一覧から技を選ぶ。

最初に使用技1の判定を行う。

;使用技1の判定
$C1/8EB6 JSR $6150  [$C1:6150]   ;[$C1:6150]へジャンプ
;
;戦闘乱数計算
$C1/6150 PHX                     ;戦闘乱数計算
;(省略)
$C1/61A4 RTS                     ;乱数がAと[$00:033B]に入る
;
;使用技1使用判定
$C1/8EB9 AND #$C0                ;A(乱数$00~$FF)と$C0(%1100 0000)で論理積
$C1/8EBB BNE $03    [$8EC0]      ;ゼロフラグが立っていないとき[$8EC0]分岐
;ゼロフラグON(使用技1の使用は見送り、次判定へ)
$C1/8EBD BRL $0089  [$8F49]      ;フラグにかかわりなく常に分岐[$8F49]
;ゼロフラグOFF(行動異常チェックへ)
$C1/8EC0 LDA $20    [$00:0320]   ;Aに[$00:0320](行動異常0 使用不可技判定)をロード
$C1/8EC2 BPL $58    [$8F1C]      ;ネガティブフラグが立っていないとき[$8F1C]分岐
;ネガティブフラグON(行動異常で使用不可)
$C1/8EC4 BRL $0082  [$8F49]      ;フラグにかかわりなく常に分岐[$8F49]
;ネガティブフラグOFF(行動異常で使用不可ではない)
$C1/8F1C LDA $AF    [$00:03AF]   ;Aに[$00:03AF](行動ポイント上1バイト)をロード
$C1/8F1E BEQ $29    [$8F49]      ;ゼロフラグが立っているとき[$8F49]分岐
;ゼロフラグOFF 技1使用
$C1/8F20 JSR $9252  [$C1:9252]   ;[$C1:9252]へジャンプ

;使用技1の使用は見送り、次判定へ
$C1/8F49 LDX $AC    [$00:03AC]   ;Xに[$00:03AC]をロード
$C1/8F4B STZ $0005,x[$00:1B05]   ;[$00:1B05](技関係状態)に$00を書き込み
$C1/8F4E LDA $7E9106,x[$7E:AC06] ;Aに[$7E:AC06]をロード
$C1/8F52 INC A                   ;Aをインクリメント +1
$C1/8F53 AND #$0F                ;Aと$0Fで論理積
$C1/8F55 STA $7E9106,x[$7E:AC06] ;Aを[$7E:AC06]に書き込み
$C1/8F59 RTS                     ;サブルーチン戻り

;$C1/8F20のジャンプ先、使用技1使用可能
$C1/9252 LDA $002B,y[$00:1A2B]   ;Aに[$00:1A2B](敵データ11 使用技1 技ID)をロード
$C1/9255 JSR $3D5C  [$C1:3D5C]   ;[$C1:3D5C]へジャンプ

まず、戦闘乱数と$C0(%1100 0000)で論理積をとり、ゼロフラグ判定をしている。
つまり乱数が$00$3F%0011 1111)ならゼロフラグが立ち、$40$FFはゼロフラグが立たない。
64/256 = 1/4の確率でゼロフラグが立ち、$C1/8EBD$C1/8F49に進む。
後述するが、$C1/8F49に進む場合は、ここでの判定を抜けた(使用技1の使用を選択しなかった)ことになる。

3/4の確率で使用技1の使用を選択して、$C1/8EC0に進む。
その場合、まず、[$00:0320]をロードしてネガティブフラグ判定をする。
[$00:0320]には先に、行動異常データ0がロードされており、上1バイトの4ビット分に、使用技1~4が使用可能かどうか1ビットずつ記録されている。
ネガティブフラグの判定ということは、一番上の1ビットが01かの判定である。つまり敵の使用技1が、行動異常により使用不可になっていないかどうかの判定である。
ここで使用不可の判定をされたら、$C1/8EC4$C1/8F49と飛ぶ。
一方、使用可能なら$C1/8F1Cにジャンプして、[$00:03AF](行動ポイント上1バイト)が1以上かどうか、つまり敵ターンか判定して、$C1/8F20に進む。
ここで、敵は使用技1使用確定である。[$C1:9252]へジャンプして技の使用処理を行う。

以上の判定を抜けた場合、つまり使用技1の使用は見送った時は$C1/8F49に進むが、次の判定へ進むための処理を$C1/8F49$C1/8F59で行う。
[$7E:AC06]をインクリメント+1するのがポイントである。
ここで[$7E:AC06]$01になる。

一方、$C1/8F20で使用技1の使用が選択された場合は$C1/9252にジャンプし、A[$00:1A2B](敵データ11 使用技1 技ID)をロードして[$C1:3D5C]へと進むが、この時点で使用技1の使用が確定ではない。
$C1/3D5C以降の、技使用判定後のサブルーチンについては後で説明するとして、ここでは使用技1が選択されず次の判定に進む場合($C1/8F59以降)を説明する。
使用技1の判定で選択されなかった場合、次は使用技2の判定へ移るのだが、そこまで別処理を挟んでおり、1フレーム後に判定する。

;使用技2の判定
$C1/8E85 LDA $7E9106,x[$7E:AC06] ;Aに[$7E:AC06]($01)をロード
$C1/8E89 LDY $0002,x[$00:1B02]   ;Yに[$00:1B02]をロード
$C1/8E8C REP #$20                ;Aを16bit幅に変更、Mフラグをクリア
$C1/8E8E AND #$000F              ;Aと$000Fで論理積
$C1/8E91 ASL A                   ;Aを算術左シフト *2
$C1/8E92 ADC #$8DFE              ;A + $8DFE
$C1/8E95 TAX                     ;Aの値をXレジスタに転送
$C1/8E96 LDA $C10000,x[$C1:8E00] ;Aに[$C1:8E00]をロード
$C1/8E9A STA $1C    [$00:031C]   ;Aを[$00:031C]に書き込み
$C1/8E9C LDX $AC    [$00:03AC]   ;Xに[$00:03AC]をロード
$C1/8E9E SEP #$20                ;MフラグON Aレジスタは8bit幅
$C1/8EA0 JMP ($031C)[$C1:8EC7]   ;[$C1:8EC7]へジャンプ(レジスタをスタックに積まない)
$C1/8EC7 JSR $6150  [$C1:6150]   ;[$C1:6150]へジャンプ
;
;戦闘乱数計算
$C1/6150 PHX                     ;戦闘乱数計算
;(省略)
$C1/61A4 RTS                     ;乱数がAと[$00:033B]に入る
;
;使用技2使用判定
$C1/8ECA AND #$C0                ;Aと$C0で論理積
$C1/8ECC BNE $03    [$8ED1]      ;ゼロフラグが立っていないとき[$8ED1]分岐
;ゼロフラグON(使用技2の使用は見送り、次判定へ)
$C1/8ECE BRL $0078  [$8F49]      ;フラグにかかわりなく常に分岐[$8F49]
;ゼロフラグOFF(行動異常チェックへ)
$C1/8ED1 INY                     ;Yをインクリメント +1
$C1/8ED2 LDA $20    [$00:0320]   ;Aに[$00:0320](行動異常0 使用不可技判定をロード
$C1/8ED4 BIT #$40                ;Aと$40(0100 0000)で論理積(ステータスフラグ変更のみ)
$C1/8ED6 BEQ $44    [$8F1C]      ;ゼロフラグが立っているとき[$8F1C]分岐
;ゼロフラグON(行動異常で使用不可ではない)
$C1/8F1C LDA $AF    [$00:03AF]   ;Aに[$00:03AF]をロード
$C1/8F1E BEQ $29    [$8F49]      ;ゼロフラグが立っているとき[$8F49]分岐
$C1/8F20 JSR $9252  [$C1:9252]   ;[$C1:9252]へジャンプ
;ゼロフラグOFF(行動異常で使用不可)
$C1/8ED8 BRL $006E  [$8F49]      ;フラグにかかわりなく常に分岐[$8F49]

;使用技2の使用は見送り、次判定へ
$C1/8F49 LDX $AC    [$00:03AC]   ;Xに[$00:03AC]をロード
$C1/8F4B STZ $0005,x[$00:1B05]   ;[$00:1B05]に$00を書き込み
$C1/8F4E LDA $7E9106,x[$7E:AC06] ;Aに[$7E:AC06]をロード
$C1/8F52 INC A                   ;Aをインクリメント +1
$C1/8F53 AND #$0F                ;Aと$0Fで論理積
$C1/8F55 STA $7E9106,x[$7E:AC06] ;Aを[$7E:AC06]に書き込み
$C1/8F59 RTS                     ;サブルーチン戻り

;$C1/8F20のジャンプ先、使用技2使用可能
$C1/9252 LDA $002B,y[$00:1A2C]   ;Aに[$00:1A2C](敵データ12 使用技2 技ID)をロード
$C1/9255 JSR $3D5C  [$C1:3D5C]   ;[$C1:3D5C]へジャンプ

$C1/8E85$C1/8EA0は移動・向き変え判定でも使用したアドレスの呼び出しサブルーチンなのだが、$C1/8E85でロードする[$7E:AC06]は、この時点で$01に増加している。
このため、$C1/8EA0で呼び出すジャンプ先が変わる。
[$7E:AC06]$01の時、つまり使用技2の判定の時は、ジャンプ先が$C1/8EC7に変わっている。

その後の戦闘乱数計算と、戻り先の$C1/8ECAからの処理は、使用技1の時とは少し処理が変わっているのだが、判定自体は同じ。
$C1/8ECAからは、戦闘乱数と$C0で論理積をとり、ゼロフラグ判定なので、今回も1/4の確率でゼロフラグが立ち、$C1/8ECE$C1/8F49に進む。
つまり使用技2も、3/4の確率で使用を選択して、$C1/8ED1に進む。
この先からが少し異なり、Yをインクリメント(+1)してから、行動異常データ0で使用技2が使える状態かを判定する。
行動異常0の上から2ビット目に使用技2が使える状態か入っているため、$C1/8ED4$40(%0100 0000)と論理積を取り、ゼロフラグ判定になる。
つまり、使用技1とは判定のための計算方法が変わるが、判定自体は「行動異常により技が使える状態かどうか」という共通の内容である。
ここで使用不可の判定をされたら、$C1/8ED8$C1/8F49と飛ぶ。
使用可能なら、使用技1と同じく、$C1/8F1Cにジャンプして、[$00:03AF](行動ポイント上1バイト)が1以上かどうか、つまり敵ターンか判定して、$C1/8F20に進む。
ここで、敵は使用技2使用確定である。[$C1:9252]へジャンプして技の使用処理を行う。
$C1/9252で呼び出すのは敵データ12の使用技2であるが、先程Yの値をインクリメントしたので、呼び出すアドレスが使用技2になったのである。

使用技2を使わないと判定された場合、使用技1判定の時と同じく、$C1/8F49$C1/8F59のサブルーチンに移るが、[$7E:AC06]が再びインクリメントされるので、ここで[$7E:AC06] = $02となる。

この後も使用技3、使用技4と順に判定が進むが、$C1/8EA0のジャンプ先が[$7E:AC06]の値で決まることにより、何番目の使用技を判定しているか、分岐するという仕組みである。

ということで、使用技3の判定([$7E:AC06] = $02)は、以下のようになる。

;[$7E:AC06]が$02の時(使用技3判定)
$C1/8EDB JSR $6150  [$C1:6150]   ;[$C1:6150]へジャンプ
;
;戦闘乱数計算
$C1/6150 PHX                     ;戦闘乱数計算
;(省略)
$C1/61A4 RTS                     ;乱数がAと[$00:033B]に入る
;
;使用技3使用判定
$C1/8EDE AND #$C0                ;Aと$C0で論理積
$C1/8EE0 BNE $03    [$8EE5]      ;ゼロフラグが立っていないとき[$8EE5]分岐
;ゼロフラグON(使用技3の使用は見送り、次判定へ)
$C1/8EE2 BRL $0064  [$8F49]      ;フラグにかかわりなく常に分岐[$8F49]
;ゼロフラグOFF(行動異常チェックへ)
$C1/8EE5 INY                     ;Yをインクリメント +1
$C1/8EE6 INY                     ;Yをインクリメント +1
$C1/8EE7 LDA $20    [$00:0320]   ;Aに[$00:0320](行動異常0 使用不可技判定)をロード
$C1/8EE9 BIT #$20                ;Aと$20(%0010 0000)で論理積(ステータスフラグ変更のみ)
$C1/8EEB BEQ $2F    [$8F1C]      ;ゼロフラグが立っているとき[$8F1C]分岐
;ゼロフラグOFF(行動異常で使用不可)
$C1/8EED BRL $0059  [$8F49]      ;フラグにかかわりなく常に分岐[$8F49]

行動異常の判定が行動異常データ1の上から3ビット目、$20(%0010 0000)との論理積で判断していることと、Yのインクリメント回数が変わる。
Yの数値が変わったので、使用技3を使用すると決定した後、[$00:1A2D](敵データ13 使用技3 技ID)をロードすることになる。
次判定に飛ぶ時は$C1/8EED$C1/8F49なので、[$7E:AC06]がインクリメントされ、$03になり、使用技4の判定へ続く。

使用技4の判定([$7E:AC06] = $03)は、以下のようになる。

;[$7E:AC06]が$03の時(使用技4判定)
$C1/8EF0 JSR $6150  [$C1:6150]   ;[$C1:6150]へジャンプ
;
;戦闘乱数計算
$C1/6150 PHX                     ;戦闘乱数計算
;(省略)
$C1/61A4 RTS                     ;乱数がAと[$00:033B]に入る
;
;使用技4使用判定
$C1/8EF3 AND #$C0                ;Aと$C0で論理積
$C1/8EF5 BNE $03    [$8EFA]      ;ゼロフラグが立っていないとき[$8EFA]分岐
;ゼロフラグON(使用技4の使用は見送り、次判定へ)
$C1/8EF7 BRL $004F  [$8F49]      ;フラグにかかわりなく常に分岐[$8F49]
;ゼロフラグOFF(行動異常チェックへ)
$C1/8EFA INY                     ;Yをインクリメント +1
$C1/8EFB INY                     ;Yをインクリメント +1
$C1/8EFC INY                     ;Yをインクリメント +1
$C1/8EFD LDA $20    [$00:0320]   ;Aに[$00:0320]をロード
$C1/8EFF BIT #$10                ;Aと$10(%0001 0000)で論理積(ステータスフラグ変更のみ)
$C1/8F01 BEQ $19    [$8F1C]      ;ゼロフラグが立っているとき[$8F1C]分岐
;ゼロフラグON(行動異常で使用不可ではない)
$C1/8F1C LDA $AF    [$00:03AF]   ;Aに[$00:03AF]をロード
$C1/8F1E BEQ $29    [$8F49]      ;ゼロフラグが立っているとき[$8F49]分岐
$C1/8F20 JSR $9252  [$C1:9252]   ;[$C1:9252]へジャンプ

;ゼロフラグOFF(行動異常で使用不可)
$C1/8F03 BRL $0043  [$8F49]      ;フラグにかかわりなく常に分岐[$8F49]

$C1/8F49 LDX $AC    [$00:03AC]   ;Xに[$00:03AC]をロード
$C1/8F4B STZ $0005,x[$00:1B05]   ;[$00:1B05]に$00を書き込み
$C1/8F4E LDA $7E9106,x[$7E:AC06] ;Aに[$7E:AC06]をロード
$C1/8F52 INC A                   ;Aをインクリメント +1
$C1/8F53 AND #$0F                ;Aと$0Fで論理積
$C1/8F55 STA $7E9106,x[$7E:AC06] ;Aを[$7E:AC06]に書き込み
$C1/8F59 RTS                     ;サブルーチン戻り

$C1/9477 RTS                     ;サブルーチン戻り

$C1/0261 JSR $9480  [$C1:9480]   ;[$C1:9480]へジャンプ

$C1/9480 LDA $F0    [$00:03F0]   ;Aに[$00:03F0]($FF)をロード
$C1/9482 BIT #$EF                ;Aと$EFで論理積(ステータスフラグ変更のみ)
$C1/9484 BEQ $01    [$9487]      ;ゼロフラグが立っているとき[$9487]分岐
$C1/9486 RTS                     ;サブルーチン戻り

$C1/0264 JSR $169E  [$C1:169E]   ;[$C1:169E]へジャンプ

こちらも、行動異常の判定が行動異常データ1の上から4ビット目、$10(%0001 0000)との論理積で判断していることと、Yのインクリメント回数が変わる。
Yの数値が変わったので、使用技4を使用すると決定した後、[$00:1A2E](敵データ14 使用技3 技ID)をロードすることになる。

ここまで、

  1. 移動または向き変え判定
  2. 使用技1の使用判定
  3. 使用技2の使用判定
  4. 使用技3の使用判定
  5. 使用技4の使用判定

まで行ってきたことになるが、使用技4の使用判定で使用しないと判定されると、もう一度移動または向き変え判定に戻ることになる。
使用技4の使用判定まで終わると、$C1/9477$C1/0261$C1/9480と進むが、一度目の使用技4の使用判定終了時には[$00:03F0]$FFが入っていて、$C1/9484のゼロフラグの分岐処理により、$C1/9486でサブルーチンが終了する。
ところが、二度目の一度目の使用技4の使用判定終了時には[$00:03F0]$00が入っていて、再び「移動または向き変え判定」に戻ることなく、「移動または向き変え」で決定になる。

$C1/9480 LDA $F0    [$00:03F0]   ;Aに[$00:03F0]($00)をロード
$C1/9482 BIT #$EF                ;Aと$EFで論理積(ステータスフラグ変更のみ)
$C1/9484 BEQ $01    [$9487]      ;ゼロフラグが立っているとき[$9487]分岐
$C1/9487 LDA $62    [$00:0362]   ;Aに[$00:0362]をロード
$C1/9489 BIT #$80                ;Aと$80で論理積(ステータスフラグ変更のみ)
$C1/948B BNE $07    [$9494]      ;ゼロフラグが立っていないとき[$9494]分岐
;(省略)
$C1/9533 JSR $9589  [$C1:9589]   ;[$C1:9589]へジャンプ

整理すると、

  1. 移動または向き変え判定(確率:移動頻度/32)
  2. 使用技1の使用判定(確率:3/4)
  3. 使用技2の使用判定(確率:3/4)
  4. 使用技3の使用判定(確率:3/4)
  5. 使用技4の使用判定(確率:3/4)
  6. 移動または向き変え判定(確率:移動頻度/32)
  7. 使用技1の使用判定(確率:3/4)
  8. 使用技2の使用判定(確率:3/4)
  9. 使用技3の使用判定(確率:3/4)
  10. 使用技4の使用判定(確率:3/4)
  11. 移動または向き変えで確定

という順に判定していくことになる。
ただし、使用技の使用判定で使用することが決まっても、その先で更に判定がある。

  1. その技が使用できる状態異常か判定
  2. 技のタイプの判定(反撃技なら使用しない)
  3. 回復技の時、使用するか乱数判定
  4. 攻撃技の時、攻撃範囲内に味方がいるか判定

ここまで判定してから、該当の技を使用するかどうかが決まる。
この先で、使用技判定について説明する。

使用技判定

技を使用する場合、以下サブルーチンから続く。
ここでは、使用技1の使用を選択したものとする。

$C1/8F1C LDA $AF    [$00:03AF]   ;Aに[$00:03AF]をロード
$C1/8F1E BEQ $29    [$8F49]      ;ゼロフラグが立っているとき[$8F49]分岐
$C1/8F20 JSR $9252  [$C1:9252]   ;[$C1:9252]へジャンプ

$C1/9252 LDA $002B,y[$00:1A2B]   ;Aに[$00:1A2B](敵データ11 使用技1 技ID)をロード
$C1/9255 JSR $3D5C  [$C1:3D5C]   ;[$C1:3D5C]へジャンプ

$C1/3D5C STA $211B  [$00:211B]   ;Aを[$00:211B]に書き込み
$C1/3D5F LDA $0001,x[$00:1B01]   ;Aに[$00:1B01]をロード
$C1/3D62 AND #$BF                ;Aと$BFで論理積
$C1/3D64 BEQ $32    [$3D98]      ;ゼロフラグが立っているとき[$3D98]分岐
$C1/3D66 PHY                     ;Yをスタックへプッシュ
$C1/3D67 LDY $0002,x[$00:1B02]   ;Yに[$00:1B02]をロード
$C1/3D6A LDA $0029,y[$00:1A29]   ;Aに[$00:1A29](敵データ09)をロード
$C1/3D6D PLY                     ;Yレジスタにスタックからプル
$C1/3D6E ROL A                   ;Aをキャリーフラグを含めた9bitで左ローテート
$C1/3D6F ROL A                   ;Aをキャリーフラグを含めた9bitで左ローテート
$C1/3D70 AND #$01                ;Aと$01で論理積
$C1/3D72 EOR #$01                ;Aと$01で排他的論理和XOR
$C1/3D74 BEQ $22    [$3D98]      ;ゼロフラグが立っているとき[$3D98]分岐
;ゼロフラグOFF(敵データ09の上1ビットが0、敵技)
$C1/3D76 LDA #$01                ;Aに$01をロード
$C1/3D78 BRA $1E    [$3D98]      ;フラグにかかわりなく常に分岐[$3D98]
;ゼロフラグON(敵データ09の上1ビットが1、味方技)
$C1/3D98 STA $211B  [$00:211B]   ;Aを[$00:211B]に書き込み
$C1/3D9B LDA #$19                ;Aに$19をロード
$C1/3D9D STA $211C  [$00:211C]   ;Aを[$00:211C]に書き込み
$C1/3DA0 STA $211C  [$00:211C]   ;Aを[$00:211C]に書き込み
$C1/3DA3 REP #$21                ;Aを16bit幅に変更、キャリーフラグクリア
$C1/3DA5 LDA $2134  [$00:2134]   ;Aに[$00:2134]をロード
$C1/3DA8 ADC $D50018[$D5:0018]   ;A + [$D5:0018]
$C1/3DAC TAX                     ;Aの値をXレジスタに転送
$C1/3DAD SEP #$20                ;MフラグON Aレジスタは8bit幅
$C1/3DAF RTS                     ;サブルーチン戻り

;周囲攻撃・反撃専用・回復技判定
$C1/9258 LDA $D5000D,x           ;Aに[$D5000D,x](技データ13)をロード
$C1/925C BIT #$40                ;Aと$40(%0100 0000)で論理積(ステータスフラグ変更のみ)
$C1/925E BNE $5B    [$92BB]      ;ゼロフラグが立っていないとき[$92BB]分岐
;ゼロフラグON 反撃専用技ではない
$C1/9260 BIT #$80                ;Aと$80(%1000 0000)で論理積(ステータスフラグ変更のみ)
$C1/9262 BEQ $5A    [$92BE]      ;ゼロフラグが立っているとき[$92BE]分岐
;ゼロフラグON 回復技ではない
$C1/92BE LDX $AC    [$00:03AC]   ;Xに[$00:03AC]をロード
$C1/92C0 LDA #$FF                ;Aに$FFをロード
$C1/92C2 RTS                     ;サブルーチン戻り

$C1/8F23 BEQ $24    [$8F49]      ;ゼロフラグが立っているとき[$8F49]分岐
$C1/8F25 JSR $920C  [$C1:920C]   ;[$C1:920C]へジャンプ

$C1/3D5C$C1/3DAFは、敵データ09の上1ビットに記録されている、使用技を敵技IDから取得するなら0、味方技IDから取得するなら1であり、敵技データのアドレスを取得するための計算である。詳細は省略。

$C1/9258で呼び出す[$D5000D,x]が、選択した技の技データ13の値である。
技データ13は、上から2ビット目に1が立っていたら反撃専用技であり、$C1/925C$40と論理積を取ってゼロフラグがOFFなら反撃専用技である。
敵自身から反撃専用技を選択できないので、ここで判定が終了となり、次の判定へ移ることになる。

更に、技データ13の一番上のビットに1が立っていたら回復技であり、$C1/9260$80と論理積を取ってゼロフラグがOFFなら回復技である。
回復技の場合、更に判定処理が続くので、回復技判定のページで詳しく紹介する。

ここでゼロフラグがONなら攻撃技判定となり$C1/92BEに進む。
更に$C1/920Cに判定が続くこととなる。

$C1/920C JSR $6150  [$C1:6150]   ;[$C1:6150]へジャンプ
;
;戦闘乱数計算
$C1/6150 PHX                     ;戦闘乱数計算
;(省略)
$C1/61A4 RTS                     ;乱数がAと[$00:033B]に入る
;
$C1/920F AND #$F0                ;Aと$F0(%1111 0000)で論理積
$C1/9211 BEQ $35    [$9248]      ;ゼロフラグが立っているとき[$9248]分岐
;ゼロフラグOFF
$C1/9213 STZ $10    [$00:0310]   ;[$00:0310]に$00を書き込み
$C1/9215 LDX #$1C00              ;Xに$1C00をロード

;ループ処理開始
$C1/9218 LDA $0001,x[$00:1C01]   ;Aに[$00:1C01+40n](キャラ1~4戦闘状態)をロード
$C1/921B BIT #$40                ;Aと$40で論理積(ステータスフラグ変更のみ)
$C1/921D BEQ $0B    [$922A]      ;ゼロフラグが立っているとき[$922A]分岐
;ゼロフラグOFF($40:敵操作状態 $FF:通常,戦闘離脱ではない)
$C1/921F LDA $0039,x[$00:1C39]   ;Aに[$00:1C39+40n](キャラ1~4状態異常)をロード
$C1/9222 CMP #$FF                ;Aと$FFを減算比較(ステータスレジスタ変更のみ)
$C1/9224 BEQ $04    [$922A]      ;ゼロフラグが立っているとき[$922A]分岐
;ゼロフラグOFF(状態異常が%1111 1111=戦闘不能ではない)
$C1/9226 ORA $10    [$00:0310]   ;Aと[$00:0310]で論理和
$C1/9228 STA $10    [$00:0310]   ;Aを[$00:0310]に書き込み
;$C1/921D, $C1/9224でゼロフラグON
$C1/922A REP #$21                ;Aを16bit幅に変更、キャリーフラグクリア
$C1/922C TXA                     ;Xレジスタの値をAレジスタに転送
$C1/922D ADC #$0040              ;A + $0040
$C1/9230 TAX                     ;Aの値をXレジスタに転送
$C1/9231 SEP #$20                ;MフラグON Aレジスタは8bit幅
$C1/9233 CPX #$1D00              ;Xと$1D00を減算比較(ステータスレジスタ変更のみ)
$C1/9236 BNE $E0    [$9218]      ;ゼロフラグが立っていないとき[$9218]分岐
;ループ処理ここまで

$C1/9238 LDX $AC    [$00:03AC]   ;Xに[$00:03AC]をロード
$C1/923A LDA $002B,y[$00:1A2C]   ;Aに[$00:1A2B](敵データ11 使用技1 技ID)をロード
$C1/923D JSR $3D5C  [$C1:3D5C]   ;[$C1:3D5C]へジャンプ

$C1/3D5C STA $211B  [$00:211B]   ;Aを[$00:211B]に書き込み
;(アドレス計算処理、中略)
$C1/3DAF RTS                     ;サブルーチン戻り

$C1/9240 LDA $D50009,x           ;Aに[$D50009,x](技データ09 状態異常(8ビット))をロード
$C1/9244 AND $10    [$00:0310]   ;Aと[$00:0310]で論理積
$C1/9246 BNE $05    [$924D]      ;ゼロフラグが立っていないとき[$924D]分岐
;ゼロフラグON(使用技と敵の状態異常が被っていない)
;$C1/9211でゼロフラグON
$C1/9248 LDX $AC    [$00:03AC]   ;Xに[$00:03AC]をロード
$C1/924A LDA #$FF                ;Aに$FFをロード
$C1/924C RTS                     ;サブルーチン戻り
;ゼロフラグOFF(使用技と敵の状態異常が被り)
$C1/924D LDX $AC    [$00:03AC]   ;Xに[$00:03AC]をロード
$C1/924F LDA #$00                ;Aに$00をロード
$C1/9251 RTS                     ;サブルーチン戻り

$C1/8F28 BEQ $1F    [$8F49]      ;ゼロフラグが立っているとき[$8F49]分岐
;ゼロフラグOFF(技範囲判定へ続く)
$C1/8F2A LDA $002B,y[$00:1A2C]   ;Aに[$00:1A2B](敵データ11 使用技1 技ID)をロード
$C1/8F2D JSR $E251  [$C1:E251]   ;[$C1:E251]へジャンプ

$C1/920C$C1/9211で、戦闘乱数($00$FF)と$F0(%1111 0000)で論理積を取り、ゼロフラグ判定をしている。
つまり、乱数が$10(%0001 0000)より大きい場合はゼロフラグが立たず、$10未満ならゼロフラグが立つ。
ゼロフラグが立っている時は$C1/9248まで処理が飛ぶことになるのだが、その間の$C1/9213$C1/9246の処理は、「味方全員の状態異常と、敵の使用技で発生する状態異常が被っていないか」の判定で、味方全員の状態異常と、敵の使用技で発生する状態異常が被っている時は技使用処理を抜ける、つまり該当技を使わない。

つまり、15/16の確率で「味方全員の状態異常と、敵の使用技で発生する状態異常が被っていないか」を判定し、被っていたら技を使用しないことになる。
これが、「味方キャラがある状態異常の時、敵は同じ状態異常の追加効果のついた技の使用確率が減る(15/16になる)」という現象の正体である。
先に乱数で確率計算してから処理をする、という、ちょっと珍しいパターンである。
「味方全員の状態異常と、敵の使用技で発生する状態異常が被っている」という判定をしてから乱数計算をした方が処理を省けるように思えるが、このあたりの処理手順の理由はよくわからない。

$C1/9213$C1/9246の処理は、$C1/9218$C1/9236のループ処理で、フィールドにいる味方キャラ全員(戦闘不能キャラ除く)の[$00:1C39+40n](味方58キャラ1~4の状態異常)を、初期値00が入った[$00:0310]と論理和を取っていく、という処理になる。
結果、[$00:0310]には、フィールドにいる味方キャラ全員の状態異常をすべて重ねた値が入った状態でループ処理が終わる。
$C1/9240$C1/9246で、敵の使用技の技データ09(技の追加効果の状態異常)と[$00:0310]で論理積を取るが、ここでゼロフラグが立つなら、「味方全員の状態異常と、敵の使用技で発生する状態異常が被っていない」ことになる。
その場合、$C1/924AA$FFをロードし、$C1/8F28にジャンプして、ゼロフラグがOFFだから$C1/8F2Dへ続く。
この先は、敵自身が該当の使用技を出せる状態異常かどうかの判定$C1/E251~に続くことになる。

一方、使用技と敵の状態異常が被っていたら、$C1/924Dに進み、A$00をロードし、$C1/8F28にジャンプして、ゼロフラグがONだから$C1/8F49にジャンプする。
つまり、次の技の判定に進むことになり、現在の技判定から抜けることになる。

$C1/E251 LDA $002B,y[$00:1A2C]   ;Aに[$00:1A2B](敵データ11 使用技1 技ID)をロード
$C1/E254 STA $7E9100,x[$7E:AC00] ;Aを[$7E:AC00]に書き込み
$C1/E258 JSR $3D5C  [$C1:3D5C]   ;[$C1:3D5C]へジャンプ

$C1/3D5C STA $211B  [$00:211B]   ;Aを[$00:211B]に書き込み
;(アドレス計算処理、中略)
$C1/3DAF RTS                     ;サブルーチン戻り

$C1/E25B STX $68    [$00:0368]   ;Xを[$00:0368]に書き込み
$C1/E25D LDA $D50008,x           ;Aに[$D50008,x](技データ08 使用不能状態異常(8ビット))をロード
$C1/E261 LDX $AC    [$00:03AC]   ;Xに[$00:03AC]をロード
$C1/E263 AND $7E8F07,x[$7E:AA07] ;Aと[$7E:AA07](敵の状態異常)で論理積
$C1/E267 BNE $56    [$E2BF]      ;ゼロフラグが立っていないとき[$E2BF]分岐
;ゼロフラグON(技を出せる状態異常の状態である)
$C1/E269 JSR $3D2B  [$C1:3D2B]   ;[$C1:3D2B]へジャンプ

;ゼロフラグOFF(技を出せる状態異常の状態ではない)
$C1/E2BF LDX $AC    [$00:03AC]   ;Xに[$00:03AC]をロード
$C1/E2C1 LDA #$00                ;Aに$00をロード
$C1/E2C3 RTS                     ;サブルーチン戻り

$C1/E25D~の処理で、使用技の技データ08を呼び出し、[$7E:AAn7](敵番号nの状態異常)と論理積を取って、ゼロフラグ判定をしている。
技データ08には使用不能状態異常の値が入っているから、論理積が0なら該当技を出せる状態異常の状態である、ということになる。
この場合、次の判定である、技を出せる範囲に味方キャラがいるかどうかの判定$C1:3D2B~にジャンプする。

ゼロフラグOFF、つまり技を出せる状態異常の状態ではないなら、$C1/E2BFにジャンプしてA$00をロード、サブルーチン終了となる。

$C1/E269から先、つまり$C1/3D2B~からの処理だが、技を出せる範囲に味方キャラがいるかどうか、いる場合どの座標の味方キャラを攻撃するかの判定になる。
技の範囲判定は説明が長くなるので、次ページの技の範囲判定で詳しく述べる。

余談

結局、使用技1~4それぞれを使用する確率はどれくらいなのかを計算してみるとどうなるのか。
大半の敵が移動頻度0なので、移動頻度0で計算すると、2回判定を考慮して以下のようになるはず。

行動計算式確率
使用技1(3/4) + (1/4)4*(3/4)0.753
使用技2(1/4)*(3/4) + (1/4)4*(1/4)*(3/4)0.188
使用技3(1/4)2*(3/4) + (1/4)4*(1/4)2*(3/4)0.0471
使用技4(1/4)3*(3/4) + (1/4)4*(1/4)3*(3/4)0.0118
移動または向き変え(1/4)80.0000153

使用技2は19%くらいなので、そこそこ出るように思えるが、使用技3は5%程度、使用技4は1%程度で、ほとんど選ばれないような確率に見える。
だが、上の計算は、使用技1~4全てが「その技を出せる状況である」場合の確率計算である。
実際は、その技を出せる位置に攻撃相手(味方キャラ)がいないと出せないので、使用技3や4が選ばれる状況もそれなりにあるはずである。
逆に、使用技1~4全てが出せる状況なのに、移動頻度0の敵が移動する確率は0.0015%と、まずありえない確率である。
このため、移動頻度0の敵は、使用技1~4のどれかが出せるならほぼ確実に何かの技で攻撃してくることになる。

逆に、移動頻度が高めの敵だとどうなるかを計算してみる。
例えば、中世編で戦う時のストレイボウは移動頻度が6である。

行動計算式確率
使用技1(1-6/32)*(3/4) + (1-6/32)*(1/4)4*(1-6/32)*(3/4)0.611
使用技2(1-6/32)*(1/4)*(3/4) + (1-6/32)*(1/4)4*(1-6/32)*(1/4)*(3/4)0.153
使用技3(1-6/32)*(1/4)2*(3/4) + (1-6/32)*(1/4)4*(1-6/32)*(1/4)2*(3/4)0.0382
使用技4(1-6/32)*(1/4)3*(3/4) + (1-6/32)*(1/4)4*(1-6/32)*(1/4)3*(3/4)0.00955
移動または向き変え(6/32) + (1-6/32)*(1/4)4*(6/32) + (1-6/32)*(1/4)^4*(1-6/32)*(1/4)^40.188

使用技1~4全てが出せる状況でも、移動または向き変えの確率が19%まで上がる。
使用技2を選ぶ確率15%より高く、それなりの確率で移動を選ぶことがわかる。



このページをシェアする

上へ