TOP > プログラミング関係解説&調査 > 攻撃技のヒット数

攻撃技のヒット数

ここでは、攻撃技のヒット数がどう計算されているのか解説する。
特に、多段ヒット技、つまり最大連発数が2以上に設定されている技について説明する。

世界の合言葉は森部様の技データを見てみると、「最大連発数」の欄がある。
ここに書かれている数値が文字通りの最大連発数であるが、数値の後、カッコ内に注意が追記されている項目もある。
「(範囲全体)」は、「範囲内に1ヒット」の時の注意書きであるので、命中判定さえすれば「範囲内に1ヒット」の攻撃をする。
命中判定については、既に前ページで述べた通りである。

多段ヒット技、つまり最大連発数が2以上の技について注目してみると、数値の後に何もない場合もあれば、
「(ランダムに減)」
「(レベルにより減)」
と書かれている技もある。
どの技でも、命中判定で命中することが決まった場合、最低でも1ヒットとなるはずである。

  • 数値のみの技:
    最大連発数 = ヒット数
  • 「ランダムに減」の技:
    ヒット数は、1~最大連発数である(ランダムで決まる。つまり乱数で計算している)
  • 「レベルにより減」の技:
    ヒット数は使用者のレベルに依存して計算され、1~最大連発数である。

この3パターンに分けられるということである。
これらヒット数のパターンを、とりあえず「ヒット数パターン」という名称にしておく。

「範囲内に1ヒット」や、「最大連発数 = ヒット数」は戦闘中に計算するまでもなく、ヒット数が決まっている。命中するかどうかの判定がされるのみである(そのはずである)。
だが、「ランダムに減」や「レベルにより減」の場合は、何かしらの方法で実際のヒット数が計算されているはずだ。
このページでは、「ランダムに減」や「レベルにより減」の技のヒット数計算方法を紹介する。
計算式だけ知りたいという方は、最後の「まとめ」までジャンプしていただきたい。

技データ19について

ヒット数の計算の前に、技データ19について説明をする。
これまでも説明してきたが、各技のステータスなどは25バイト分(16進数2文字×25)のデータが記録されており、当コンテンツでは便宜上、25バイトのデータに0~24の番号をつけて、番号19のデータを「技データ19」とする。
技データ19には、最大連発数と、ヒット数パターンのデータが収められている。
つまり、ヒット数計算において重要なデータである。
技データ19には16進数2桁の数値、つまり2バイトのデータが入っている。
2進数だと8文字、つまり8ビットである。
その8ビットに以下のようにデータが入っている。

2進法の位2726252423222120
技データ1900100011
収録データ
  • ① 一番上の27の位。1だと「範囲内に1ヒット」
  • ② 上から3、4番目(25~24)の位(2ビット分)に、以下表のようにヒット数パターンが記録されている。
  • 数値ヒット数パターン
    00通常(最大連発数がヒット数)
    01レベルにより減
    10範囲内に1ヒット
    11ランダムに減
  • ③ 下4ビット分は、「範囲内に1ヒット」以外の技の最大連発数。
    2進数%0000~%1111が入り、16進数だと$0~$F、10進数だと0~15
    つまり本作の技の最大ヒット数は15
例:
ボコボコの技データ19は$42%0100 0010
最大連発数は%0010、10進数だと2
ヒット数パターンは「通常(最大連発数がヒット数)」

ローキックの技データ19は$12%0001 0010
最大連発数は%0010、10進数だと2
ヒット数パターンは「レベルにより減」

手裏剣乱糸の技データ19は$56%0101 0110
最大連発数は%0110、10進数だと6
ヒット数パターンは「レベルにより減」

ハリケンショットの技データ19は$7C%0111 1100
最大連発数は%1100、10進数だと12
ヒット数パターンは「ランダムに減」

インケイジの技データ19は$80%1000 0000
一番上の位が1なので、「範囲内に1ヒット」

ヒット数パターンの判断

ヒット数計算をする場合、まずは使用技の「ヒット数パターン」が何なのかを判定しなければならない。
ヒット数パターンによって、ヒット数計算方法が変わるからである。
まず、「ヒット数パターン」の判定をしているサブルーチン($C1/D6B9~)を説明する。
技データ19についての仕様を踏まえた上で見ていただきたい。

$C1/D6B9 LDX $78    [$00:0378]   ;Xに[$00:0378]をロード(技使用者の番号)
$C1/D6BB LDA $0038,x[$00:1CF8]   ;Aに[$00:1CF8]をロード(技使用者のLV現在値)
$C1/D6BE STA $11    [$00:0311]   ;A(技使用者のLV現在値)を[$00:0311]に書き込み
$C1/D6C0 LDA $7E9023[$7E:9023]   ;Aに[$7E:9023]をロード(技データ19)
$C1/D6C4 AND #$0F                ;技データ19と$0Fで論理積(技データ19から最大連発数を取り出す)
$C1/D6C6 STA $10    [$00:0310]   ;A(最大連発数)を[$00:0310]に書き込み
$C1/D6C8 LDA $7E9023[$7E:9023]   ;Aに[$7E:9023]をロード(技データ19)
$C1/D6CC BIT #$80                ;技データ19と$80(10000000)と論理積(範囲内に1ヒットかどうかの判定)
$C1/D6CE BNE $DE    [$D6AE]      ;ゼロフラグが立っていないとき(範囲内に1ヒットの場合)[$D6AE]分岐
$C1/D6D0 AND #$30                ;技データ19と$30で論理積(00110000)(ヒット数タイプ取り出し)
$C1/D6D2 CMP #$20                ;Aと$20を減算比較(00100000) = 10
$C1/D6D4 BEQ $D8    [$D6AE]      ;ゼロフラグが立っているとき[$D6AE]分岐
$C1/D6D6 CMP #$00                ;Aと$00を減算比較(00000000) = 通常(最大連発数がヒット数)
$C1/D6D8 BNE $02    [$D6DC]      ;ゼロフラグが立っていないとき[$D6DC]分岐
$C1/D6DA BRA $47    [$D723]      ;「通常(最大連発数がヒット数)」の処理
$C1/D6DC CMP #$10                ;Aと$10を減算比較(00010000) = 「レベルにより減」(11だったら「ランダムに減」)
$C1/D6DE BNE $2A    [$D70A]      ;ゼロフラグが立っていないとき(=「ランダムに減」)[$D70A]分岐

順に説明する。

$C1/D6B9 A6 LDX $78    [$00:0378]   ;Xに[$00:0378]をロード(技使用者の番号)
$C1/D6BB BD LDA $0038,x[$00:1CF8]   ;Aに[$00:1CF8]をロード(技使用者のLV現在値)
$C1/D6BE 85 STA $11    [$00:0311]   ;A(技使用者のLV現在値)を[$00:0311]に書き込み

$C1/D6B9は、攻撃技を使う味方キャラの番号である。
味方キャラには隊形順に1C00, 1C40, 1C80, 1CC0と番号がふってあり、ここではそれをXにロードしている。
$C1/D6BBは、攻撃技を使う味方キャラの現在のレベルである。
戦闘中ではバフやデバフでレベルが変動するが、技使用時点でのレベルの値をAにロードし、続いてその値は[$00:0311]に書き込まれている。

$C1/D6C0 LDA $7E9023[$7E:9023]   ;Aに[$7E:9023]をロード(技データ19)
$C1/D6C4 AND #$0F                ;技データ19と$0Fで論理積(技データ19から最大連発数を取り出す)
$C1/D6C6 STA $10    [$00:0310]   ;A(最大連発数)を[$00:0310]に書き込み

$C1/D6C0では、A[$7E:9023]をロードしているが、これが使用しようとしている技の技データ19の値である。
$C1/D6C4で、$0Fと論理積を取り、技データ19の下1桁、「最大連発数」を取り出す。
「最大連発数」は[$00:0310]に書き込まれている。
この次からが「ヒット数パターン」の判定である。

$C1/D6C8 LDA $7E9023[$7E:9023]   ;Aに[$7E:9023]をロード(技データ19)
$C1/D6CC BIT #$80                ;技データ19と$80(10000000)と論理積(範囲内に1ヒットかどうかの判定)
$C1/D6CE BNE $DE    [$D6AE]      ;ゼロフラグが立っていないとき(範囲内に1ヒットの場合)[$D6AE]分岐
$C1/D6D0 AND #$30                ;技データ19と$30で論理積(00110000)(ヒット数タイプ取り出し)
$C1/D6D2 CMP #$20                ;Aと$20を減算比較(00100000) = 10
$C1/D6D4 BEQ $D8    [$D6AE]      ;ゼロフラグが立っているとき[$D6AE]分岐
$C1/D6D6 CMP #$00                ;Aと$00を減算比較(00000000) = 通常(最大連発数がヒット数)
$C1/D6D8 BNE $02    [$D6DC]      ;ゼロフラグが立っていないとき[$D6DC]分岐
$C1/D6DA BRA $47    [$D723]      ;「通常(最大連発数がヒット数)」の処理
$C1/D6DC CMP #$10                ;Aと$10を減算比較(00010000) = 「レベルにより減」(11だったら「ランダムに減」)
$C1/D6DE BNE $2A    [$D70A]      ;ゼロフラグが立っていないとき(=「ランダムに減」)[$D70A]分岐

もう一度技データ19([$7E:9023])をAに読み込み、まずは$80と論理積を取る。
これは技データ19の中の「範囲内に1ヒット」かどうかが記録されている部分で、「範囲内に1ヒット」なら論理積は$80、それ以外だと$00である。
$C1/D6CEはゼロフラグが立っていない場合の分岐なので、『「範囲内に1ヒット」なら[$D6AE]へジャンプ』である。

続いて、$C1/D6D0では、技データ19と$30で論理積を取っている。
ここで「ヒット数パターン」を取り出しており、$C1/D6D2では$20と減算比較し、$C1/D6D4ではゼロフラグが立っているなら[$D6AE]へジャンプという処理になる。
この条件は、ヒット数パターンが「範囲内に1ヒット」の時なので、やはり[$D6AE]にジャンプする。
(「範囲内に1ヒット」の記録方法が2通りあるのは多分意味があるのだろうが、筆者にはわからない)
「範囲内に1ヒット」は、ヒット数が1ヒットで決定である。

$C1/D6D6はヒット数パターンと$00の比較になるが、ヒット数パターンから0を引いてゼロフラグが立つのは、ヒット数パターンが「最大連発数がヒット数」の時。
ヒット数パターンが「最大連発数がヒット数」ならそのまま$C1/D6DAに進み、更に[$D723]へジャンプするが、この先が「最大連発数がヒット数」の時のヒット数計算処理になる。
(といっても、「最大連発数がヒット数」なので、ヒット数は確定である)

ヒット数パターンが「最大連発数がヒット数」ではないのなら、$C1/D6DCへと進み、ヒット数パターンと$10を比較する。
ヒット数パターンが$10なら「レベルにより減」であり、そうでない時は「ランダムに減」である。
よってここでゼロフラグが立っていない場合は、「ランダムに減」パターンのヒット数計算処理の[$D70A]へジャンプする。
「レベルにより減」の場合はこのまま処理が進むことになる。
つまり、$C1/D6DEより先は、「レベルにより減」の時のヒット数計算である。

「レベルにより減」のヒット数計算方法

まずはこのまま、「レベルにより減」の時のヒット数計算方法を見てみよう。

$C1/D6E0 LDA $10    [$00:0310]   ;Aに[$00:0310](最大連発数)をロード
$C1/D6E2 ASL A                   ;A×2
$C1/D6E3 ASL A                   ;A×2
$C1/D6E4 ASL A                   ;A×2
$C1/D6E5 ASL A                   ;A×2
$C1/D6E6 STA $211B  [$00:211B]   ;符号付16bit x 8bit 被乗数の下位バイト(最大連発数*$10)
$C1/D6E9 LDA #$00                ;Aに$00をロード
$C1/D6EB STA $211B  [$00:211B]   ;符号付16bit x 8bit 被乗数の上位バイト($00)
$C1/D6EE LDA $11    [$00:0311]   ;Aに[$00:0311](LV現在値)をロード
$C1/D6F0 CMP #$10                ;LV現在値と$10(10進数16)を減算比較(LV現在値-$10)
$C1/D6F2 BCC $02    [$D6F6]      ;キャリーフラグが立っていないとき(「LV現在値-$10」が負)、[$D6F6]へ分岐
$C1/D6F4 LDA #$0F                ;Aに$0Fをロード
$C1/D6F6 STA $211C  [$00:211C]   ;符号付16bit x 8bit 乗数
$C1/D6F9 STA $211C  [$00:211C]   ;符号付16bit x 8bit 乗数
$C1/D6FC LDA $2135  [$00:2135]   ;Aに乗算結果の中央2バイトをロード
$C1/D6FF INC A                   ;Aをインクリメント(+1)
$C1/D700 CMP #$10                ;Aと$10を減算比較
$C1/D702 BCC $02    [$D706]      ;キャリーフラグが立っていないとき、分岐
$C1/D704 LDA #$0F                ;Aが$10以上なら、Aに$0Fを書き込む
$C1/D706 STA $10    [$00:0310]   ;Aを[$00:0310]に書き込み(ヒット数)
$C1/D708 BRA $19    [$D723]      ;オーバーフローフラグが立っているとき、分岐
$C1/D723 LDA #$FF                ;Aに$FFを書き込み
$C1/D725 RTS                     ;サブルーチン戻り

順に見ていく。

$C1/D6E0 LDA $10    [$00:0310]   ;Aに[$00:0310](最大連発数)をロード
$C1/D6E2 ASL A                   ;A×2
$C1/D6E3 ASL A                   ;A×2
$C1/D6E4 ASL A                   ;A×2
$C1/D6E5 ASL A                   ;A×2

ヒット数パターンの分岐前に、最大連発数の値を[$00:0310]に書き込んだが、ここでその値がAにロードされている。
その後、ASL AAの値を算術左シフトしているが、これはAの値を2倍しているのと同じことである。
4回繰り返しているから、最大連発数×$10(10進数では×16)ということになる。

$C1/D6E6 STA $211B  [$00:211B]   ;符号付16bit x 8bit 被乗数の下位バイト(最大連発数*$10)
$C1/D6E9 LDA #$00                ;Aに$00をロード
$C1/D6EB STA $211B  [$00:211B]   ;符号付16bit x 8bit 被乗数の上位バイト($00)

ここから、符号付16bit x 8bitの乗算が開始になっている。
まず、$C1/D6E6で、計算した「最大連発数×$10」を被乗数の下位バイトとしてセットしている。
続いてAに$00をロードし、被乗数の上位バイトとしてセットした。
ということは、結局、被乗数は「最大連発数×$10」と変わらない(ただし16進数4桁の数値になっている)。

$C1/D6EE LDA $11    [$00:0311]   ;Aに[$00:0311](LV現在値)をロード
$C1/D6F0 CMP #$10                ;LV現在値と$10(10進数16)を減算比較(LV現在値-$10)
$C1/D6F2 BCC $02    [$D6F6]      ;キャリーフラグが立っていないとき(「LV現在値-$10」が負)、[$D6F6]へ分岐
$C1/D6F4 LDA #$0F                ;Aに$0Fをロード
$C1/D6F6 STA $211C  [$00:211C]   ;符号付16bit x 8bit 乗数
$C1/D6F9 STA $211C  [$00:211C]   ;符号付16bit x 8bit 乗数

一方、乗数の方だが、まずヒット数パターンの分岐前に[$00:0311]に入れた「LV現在値」をAにロードしている。
続いて、LV現在値と$10(10進数16)を減算比較している。つまり「LV現在値 - $10」である。
次でキャリーフラグが立つかどうかを判断しているが、「減算の時は、繰り下がりが発生しないとキャリーフラグが立つ(減算の結果が0か正の数の時)」であるから、

  • 技を使用するキャラのレベルが(10進数で)16以上ならキャリーフラグが立つ→そのまま$C1/D6F4
  • 技を使用するキャラのレベルが(10進数で)15以下ならキャリーフラグが立たない→[$D6F6]へ分岐

ということである。
そして、$C1/D6F4では、A$0Fをロードしている。
その後に、Aが乗数としてセットされている。
つまり、キャラのレベルが15以下の時はレベルの値が乗数としてセットされるが、キャラのレベルが16以上だと、乗数は$0F(10進数の16)に変更されることになる。
これは、数学関数min()(複数の値から最小値を求める関数)を使って、

min(LV現在値, $0F)

と表記することが可能である。
つまり乗数は「min(LV現在値, $0F)」である。

計算したい乗算は、
「最大連発数×$10」×「min(LV現在値, $0F)」
ということがここで判明した。

$C1/D6FC LDA $2135  [$00:2135]   ;Aに乗算結果の中央2バイトをロード
$C1/D6FF INC A                   ;Aをインクリメント(+1)

符号付16bit x 8bitの計算結果は、16進数6桁(24バイト)として、[$00:2134][$00:2135][$00:2136]に3分割されて出力される。
$C1/D6FCでは、3分割された乗算結果の中央の[$00:2135]Aにロードされている。
これまでも何度か似たような処理を見てきたが、下2桁を切り捨て次の2桁を取り出すという行為は、「計算結果/$100」を取り出す行為と同じである。
つまりここまでをまとめると、

「最大連発数*$10」×「min(LV現在値, $0F)」/$100

である。
分数部分(割り算部分)は$10で約分できるから、

「最大連発数」×「min(LV現在値, $0F)」/$10

ということになる。
$C1/D6FFではこの値をインクリメント(+1)したので、

「最大連発数」×「min(LV現在値, $0F)」/$10 + 1

となった。
実を言えば、この計算値こそがヒット数であるが、もう少し続きを見てみよう。

$C1/D700 CMP #$10                ;Aと$10を減算比較
$C1/D702 BCC $02    [$D706]      ;キャリーフラグが立っていないとき、分岐
$C1/D704 LDA #$0F                ;Aが$10以上なら、Aに$0Fを書き込む
$C1/D706 STA $10    [$00:0310]   ;Aを[$00:0310]に書き込み(ヒット数)
$C1/D708 BRA $19    [$D723]      ;オーバーフローフラグが立っているとき、分岐
$C1/D723 LDA #$FF                ;Aに$FFを書き込み
$C1/D725 RTS                     ;サブルーチン戻り

$C1/D700では、この値と、$10(10進数16)を減算比較している。
$10(10進数16)以上の時は$C1/D704に分岐して、A$0Fを書き込んでいる。
つまり、計算値が$10(10進数16)以上だったら、$0F(10進数15)に変更する、という意味である。
要するに、本作のヒット数の最大値は15なので、計算上16以上になった場合は15に変更するという処理だろう。
そして最終的にA[$00:0310](元は最大連発数が入っていた値)に書き込んでいるが、これが最終的なヒット数として扱われる。
$C1/D708はエラー時の処理らしいので説明は省く。

「レベルにより減」の時のヒット数計算方法を改めてまとめると、

min(『「最大連発数」×「min(LV現在値, $0F)」/$10 + 1』, $0F)

ということになった。
ただ、最後に$C1/D704で、ヒット数が計算上$10以上の時はヒット数を$0Fに変更する処理が入っていたものの、それまでの計算で$10以上になることはおそらくない。
というのは、技に設定された「最大連発数」の最大値は$0F(10進数で15)で、LV現在値がどれほど大きくても、「min(LV現在値, $0F)」という処理を挟む以上、「min(LV現在値, $0F)」の最大値は$0F(10進数で15)である。
よって、
「最大連発数」×「min(LV現在値, $0F)」/$10 + 1
の最大値は、
$0F * $0F / $10 + 1 = $0F
であり、$10より小さい。
何かしらのエラーの際の対策なのかもしれないが、基本的には、

「最大連発数」×「min(LV現在値, $0F)」/$10 + 1

が、ヒット数の計算方法と考えて問題ないのではないかと思う。
とはいえ、こういう処理を入れている以上は何か意味があるのだろうと思うが、エラー対策以外、筆者にはわからない。

数値を10進数にして、もう少し整理してみると、

「レベルにより減」のヒット数
= 最大連発数 * min(LV現在値, 15) / 16 + 1
※計算途中の小数点以下は切り捨て

である。
つまり、「レベルにより減」と指定されている技のヒット数は、技使用者の「LV現在値」だけがヒット数計算に関わっていて、敵のステータスは関係しない。
乱数も一切関わらない。

例として、「レベルにより減」の「ローキック」と「手裏剣乱糸」のヒット数を計算してみよう。

ローキック

最大連発数は2,
ヒット数 = trunc(2 * min(LV現在値, 15) / 16) + 1
であるから、使用者のレベルが1~7だと1ヒット、8以上なら2ヒットである。

手裏剣乱糸

最大連発数は6,
ヒット数 = trunc(6 * min(LV現在値, 15) / 16) + 1
であるから、使用者のレベルが1~2だと1ヒット、3~5だと2ヒット、6~7だと3ヒット、8~10だと4ヒット、12~13だと5ヒット、14以上だと6ヒットである。

といっても、おぼろ丸の場合、手裏剣乱糸を覚えるのはレベル6なので、覚えた直後でも3ヒットということになる。
もちろん、戦闘中にバフやデバフでレベル変動が起こればヒット数も変わるので、おぼろ丸が手裏剣乱糸を覚えている状態でもレベルダウン状態になれば、ヒット数が2以下になることもあり得る。

「ランダムに減」のヒット数計算方法

「ランダムに減」の時は、「ヒット数パターン」の判定の最後で[$D70A]へジャンプすることになる。

$C1/D6DE BNE $2A    [$D70A]      ;ゼロフラグが立っていないとき(=ランダムに減)[$D70A]分岐
;
$C1/D70A JSR $6150  [$C1:6150]   ;[$C1:6150]にジャンプ

飛び先の$C1/D70Aでは更に[$C1:6150]へジャンプするよう命令があるのだが、この$C1:6150というアドレスは、既に戦闘用乱数の計算で紹介した、戦闘用乱数の計算サブルーチンの開始アドレスである。
つまり、「ランダムに減」の計算をするため、さっそく戦闘用乱数の生成を行うのである。
[$C1:6150]にジャンプしてからの処理を以下に載せる。

$C1/6150 PHX                     ;乱数計算サブルーチンここから開始
$C1/6151 PHB                     ;↓
$C1/6152 LDA #$00                ;↓
$C1/6154 PHA                     ;↓
$C1/6155 PLB                     ;↓
$C1/6156 LDA $38    [$00:0338]   ;↓
$C1/6158 ORA $39    [$00:0339]   ;↓
$C1/615A ORA $3A    [$00:033A]   ;↓
$C1/615C ORA $3B    [$00:033B]   ;↓
$C1/615E BNE $24    [$6184]      ;↓
$C1/6184 LDX $38    [$00:0338]   ;↓
$C1/6186 STX $4204  [$00:4204]   ;↓
$C1/6189 LDA #$0D                ;↓
$C1/618B STA $4206  [$00:4206]   ;↓
$C1/618E JSR $46C8  [$C1:46C8]   ;↓
;
$C1/46C8 NOP                     ;↓
$C1/46C9 RTS                     ;↓
;
$C1/6191 LDA $39    [$00:0339]   ;↓
$C1/6193 STA $38    [$00:0338]   ;↓
$C1/6195 LDA $3A    [$00:033A]   ;↓
$C1/6197 STA $39    [$00:0339]   ;↓
$C1/6199 LDA $3B    [$00:033B]   ;↓
$C1/619B STA $3A    [$00:033A]   ;↓
$C1/619D LDA $4214  [$00:4214]   ;↓
$C1/61A0 STA $3B    [$00:033B]   ;↓
$C1/61A2 PLB                     ;↓
$C1/61A3 PLX                     ;↓
$C1/61A4 RTS                     ;乱数計算サブルーチンここまで(Aに乱数入る)
;
$C1/D70D STA $211B  [$00:211B]   ;符号付16bit x 8bit 被乗数の下位バイト(乱数)
$C1/D710 LDA #$00                ;Aに$00をロード
$C1/D712 STA $211B  [$00:211B]   ;符号付16bit x 8bit 被乗数の上位バイト($00)
$C1/D715 LDA $10    [$00:0310]   ;Aに[$00:0310]をロード
$C1/D717 STA $211C  [$00:211C]   ;符号付16bit x 8bit 乗数(最大連発数[$00:0310])
$C1/D71A STA $211C  [$00:211C]   ;符号付16bit x 8bit 乗数
$C1/D71D LDA $2135  [$00:2135]   ;Aに乗算結果の中央2バイトをロード
$C1/D720 INC A                   ;Aをインクリメント(+1)
$C1/D721 STA $10    [$00:0310]   ;Aを[$00:0310]に書き込み(ヒット数)
$C1/D723 LDA #$FF                ;Aに$FFを書き込み
$C1/D725 RTS                     ;サブルーチン戻り

乱数計算サブルーチンは、戦闘用乱数の計算で紹介済みであるから、ここでの説明は省く。
残りの部分について説明する。

$C1/D70D STA $211B  [$00:211B]   ;符号付16bit x 8bit 被乗数の下位バイト(乱数)
$C1/D710 LDA #$00                ;Aに$00をロード
$C1/D712 STA $211B  [$00:211B]   ;符号付16bit x 8bit 被乗数の上位バイト($00)
$C1/D715 LDA $10    [$00:0310]   ;Aに[$00:0310]をロード
$C1/D717 STA $211C  [$00:211C]   ;符号付16bit x 8bit 乗数(最大連発数[$00:0310])
$C1/D71A STA $211C  [$00:211C]   ;符号付16bit x 8bit 乗数
$C1/D71D LDA $2135  [$00:2135]   ;Aに乗算結果の中央2バイトをロード
$C1/D720 INC A                   ;Aをインクリメント(+1)
$C1/D721 STA $10    [$00:0310]   ;Aを[$00:0310]に書き込み(ヒット数)
$C1/D723 LDA #$FF                ;Aに$FFを書き込み
$C1/D725 RTS                     ;サブルーチン戻り

どこかで見たようなプログラムである。「レベルにより減」の計算をよりシンプルにしたようなものである。
符号付16bit x 8bitの計算は、「乱数」×「最大連発数[$00:0310]」であり、$C1/D71Dで乗算結果の中央2バイトをAにロードしているから、乗算結果を÷$100していることと同じである。
$C1/D720はその値を+1している。
最終的にこの値がヒット数ということになり、[$00:0310]に書き込まれている。
ということは、「ランダムに減」パターンのヒット数は、

「乱数($00~$FF)」×「最大連発数」/$100 + 1

である。
数値を10進数にして、もう少し整理してみると、

「ランダムに減」のヒット数
= 最大連発数 * (0~255の乱数) / 256 + 1
※計算途中の小数点以下は切り捨て

ということになる。
使用者のステータスは一切関係なく、乱数だけで決まっていることがわかる。

例として、「ランダムに減」の「影一文字」と「ハリケンショット」のヒット数を計算してみよう。

影一文字

最大連発数は2,
ヒット数 = trunc(2 * (0~255の乱数) / 256) + 1
であるから、以下のようになる。

ヒット数12
乱数0~127128~255
確率1/21/2

1ヒットと2ヒット、どちらになるかはそれぞれ確率1/2である。

ハリケンショット

最大連発数は12,
ヒット数 = trunc(12 * (0~255の乱数) / 256) + 1
であるから、以下のようになる。

ヒット数123456
乱数0~2122~4243~6364~8586~106107~127
確率22/25621/25621/25622/25621/25621/256
ヒット数789101112
乱数128~149150~170171~191192~213214~234235~255
確率22/25621/25621/25622/25621/25621/256

22/256は約8.6%21/256は約8.2%
計算式を見る限りどのヒット数も同確率で出るはずだが、「計算途中で小数点以下を切り捨てる」ルールがあるために、上のようにヒット数によってわずかに差が出ることになる。
とはいえ、大雑把にいえば、各ヒット数が8.5%くらいの確率で出現することになる。


以上、ヒット数が「レベルにより減」「ランダムに減」どちらも、最終的にヒット数が[$00:0310]に書き込まれる。
[$00:0310]に書き込まれたヒット数は、技が命中する場合、

[$00:0308]にヒット数書き込み

[$7E:AB?2](※「?」は敵番号0~F)にヒット数書き込み

(命中判定で命中するなら[$7E:AB?3]$01を書き込み)

[$7E:AB?3]にヒット数書き込み

技モーションのサブルーチンをヒット数の回数だけ繰り返す

総ダメージ量 = 単発ダメージ量×[$7E:AB?3]
の計算に使用

というように後々の計算に使われるようだが、詳細は省く(筆者も詳細は未確認であるため)。

まとめ

多段ヒット技の中で、ヒット数が「レベルにより減」「ランダムに減」と設定されている技の実際のヒット数は、以下のように計算されていることがわかった。
(数値はすべて10進数表記)

  • 「レベルにより減」のヒット数
    = 最大連発数 * min(LV現在値, 15) / 16 + 1
    ※LV現在値は、技使用者の技使用時のレベル(バフ・デバフでの変動込みの値)
    min(a,b)は、abを比較して最小値を選ぶ関数
    ※計算途中の小数点以下は切り捨て
  • 「ランダムに減」のヒット数
    = 最大連発数 * (0~255の乱数) / 256 + 1
    ※計算途中の小数点以下は切り捨て


このページをシェアする

上へ