TOP > プログラミング関係解説&調査 > 回復技

回復技

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

回復技の回復量については、既に世界の合言葉は森部様に計算式がある。

 ・単発回復量:
(回復係数(LV差係数と同じ)*4*乱数(1~1.25) (敵が使用する場合は、回復係数*乱数)

回復量は回復技に設定された「LV差係数」だけで決まる(乱数でのブレもある)。
使用者や回復するキャラのステータスなどは一切関係しない。キャラの向きなども関係ない。
また、味方と敵とでは、計算方法が異なることがわかる。
上計算式はあくまでも単発の回復量で、これにヒット数を掛け算した値が実際の回復量である。

ちなみに、回復技の処理を追っていくと、使用した相手の眠り状態を解除する処理が入る。
攻撃技の場合、技を当てた相手の眠り状態を解除するが(眠りの状態異常の追加効果がある場合は別途状態異常発生判定がある)、回復技でも「技を当てた相手の眠り状態を解除」という処理を行っているために起こる現象である。
それも含めて以下で説明していく。

なお、結論だけ先に書くと、計算式は以下のようになる。

味方に回復技を使用した時の単発回復量:
LV差係数*乱数($00~$FF)/$100 + LV差係数*4
= LV差係数*4*(256~319)/256

敵に回復技を使用した時の単発回復量:
LV差係数/4 * 乱数($00~$FF)/$100 + LV差係数
= LV差係数*(256~319)/256

(256~319)/256は1以上1.25未満の乱数ということになる。

メモリアドレス

回復技関係のメモリアドレスは以下のとおり。
技使用中、敵も味方も$7E:9010$7E:9028に技データ00~34が入る(次技使用直前まで値が残る)。

技データ10($7E:901A

技データ10は$7E:900Bにもコピーされる。
技データ10と$FC(%1111 1100)の論理積がLV差係数になる。

技データ13($7E:901D

技データ13は$7E:9009にもコピーされる。
上4ビットは、技のタイプ関係の値の合計値が入る。

上4ビット内容
$0通常
$2範囲が周囲
$4反撃専用
$8回復

たとえば、周囲かつ回復技だと$2 + $8$Aが入ることになる。

サブルーチン(味方キャラ)

味方キャラが回復技を使用した時のサブルーチンは以下の通り。

$C1/D568 LDA $D5000A,x           ;Aに[$D5000A,x](技データ10)をロード
$C1/D56C STA $7E900B[$7E:900B]   ;Aを[$7E:900B]に書き込み
$C1/D570 LDA $D50016,x           ;Aに[$D50016,x](技データ22)をロード
$C1/D574 STA $7E900A[$7E:900A]   ;Aを[$7E:900A]に書き込み
$C1/D578 LDA $D5000D,x           ;Aに[$D5000D,x](技データ13)をロード
$C1/D57C STA $7E9009[$7E:9009]   ;Aを[$7E:9009]に書き込み
$C1/D580 BIT #$80                ;Aと$80で論理積(ステータスフラグ変更のみ)
$C1/D582 BNE $07    [$D58B]      ;ゼロフラグが立っていないとき[$D58B]分岐
$C1/D58B JSR $D614  [$C1:D614]   ;[$C1:D614]へジャンプ

味方技データは$D5:24CB$D5:3DB1に入っており、1つの技につき25バイト分のデータになるが、それらは技使用時に$7E:9010$7E:9028にコピーされる。
それとは別に、上処理で、

内容アドレス
技データ10$7E:900B
技データ22$7E:900A
技データ13$7E:9009

と、値がコピーされる。
そのすぐ後に以下の処理がある。

$C1/D8BE LDA $7E901D[$7E:901D]   ;Aに[$7E:901D](技データ13)をロード
$C1/D8C2 BPL $02    [$D8C6]      ;ネガティブフラグが立っていないとき[$D8C6]分岐
;回復技だとネガティブフラグON
$C1/D8C4 BRA $34    [$D8FA]      ;フラグにかかわりなく常に分岐[$D8FA]
$C1/D8FA LDA #$FF                ;Aに$FFをロード
$C1/D8FC RTS                     ;サブルーチン戻り
;
$C1/D7A0 BEQ $14    [$D7B6]      ;ゼロフラグが立っているとき[$D7B6]分岐
;ゼロフラグOFF
$C1/D7A2 LDA $003B,x             ;Aに[$003B,x](技ヒット数 初期値$00)をロード
$C1/D7A5 INC A                   ;Aをインクリメント +1
$C1/D7A6 STA $003B,x             ;A($01)を[$003B,x]に書き込み
$C1/D7A9 CMP #$01                ;Aと$01を減算比較(ステータスレジスタ変更のみ)
$C1/D7AB BNE $09    [$D7B6]      ;ゼロフラグが立っていないとき[$D7B6]分岐
$C1/D7AD JSR $D8FD  [$C1:D8FD]   ;[$C1:D8FD]へジャンプ

$C1/D8BE~で、技データ13をロードした時にネガティブフラグ判定をしている。
技データ13の上1ビットは回復技だと1が入っており、ネガティブフラグが立つ。
つまりここは回復技かどうかの判定である。
その場合の処理を追いかけていくと、回復技なら$C1/D7A2に進む。
ロードする[$003B,x]は、味方キャラ1~4の$00:1C3B, $00:1C7B, $00:1CBB, $00:1CFBにあたり、使用技のヒット数を格納しておくアドレスにあたる。技使用直後に初期値として00が入る。
$C1/D7A5~でインクリメント+1した値を[$003B,x]に書き込むから、ここで使用技のヒット数が$01になる。
回復技は必ず命中するので、ここで使用技のヒット数を$01と書き込んでいることになる。
実際の回復技のヒット数はこれ以降に上書きされていくのだが、上では「命中したか否か」の判定に$01を入れたという意味合いである。
回復技の大半はヒット数1に設定されているが、アップグレードはヒット数3(レベルにより減)、プラズマチャージは4、自分・大回復は15と、例外もある。

以下からが単発回復量計算になる。

$C1/D912 LDA $7E900B[$7E:900B]   ;Aに[$7E:900B](技データ10)ロード
$C1/D916 LDX $10    [$00:0310]   ;Xに[$00:0310]をロード
$C1/D918 REP #$21                ;Aを16bit幅に変更、キャリーフラグクリア
$C1/D91A AND #$00FC              ;Aと$00FC(%1111 1100)で論理積
$C1/D91D ASL A                   ;Aを算術左シフト *2
$C1/D91E ASL A                   ;Aを算術左シフト *2
$C1/D91F STA $20    [$00:0320]   ;A(LV差係数*4)を[$00:0321][$00:0320]に書き込み
$C1/D921 LSR A                   ;Aを論理右シフト (/2)
$C1/D922 LSR A                   ;Aを論理右シフト (/2)
$C1/D923 STA $22    [$00:0322]   ;A(LV差係数)を[$00:0323][$00:0322]に書き込み
$C1/D925 SEP #$20                ;MフラグON Aレジスタは8bit幅
$C1/D927 JSR $7835  [$C1:7835]   ;[$C1:7835]へジャンプ
;
$C1/7835 LDA $22    [$00:0322]   ;Aに[$00:0322](LV差係数)をロード
$C1/7837 STA $4202  [$00:4202]   ;Aを[$00:4202]に書き込み
;符号付8bit x 8bit $4202(LV差係数)*$4203
$C1/783A JSR $6150  [$C1:6150]   ;[$C1:6150]へジャンプ

上の処理を見ると、$C1/D91Aで技データ10と$00FCの論理積を取っているので、この時点でAに入るのは技データ10から上6ビットを取った「LV差係数」の値になる。
この値を算術左シフト2回してから[$00:0321][$00:0320]に書き込んでいる。つまり「LV差係数*4」を書き込んでいる。
更に/4した値がを[$00:0323][$00:0322]に入るから、上1バイト$00[$00:0323]に、下1バイト・LV差係数が[$00:0322]に書き込まれる。

$C1/7835[$00:0322](LV差係数)を[$00:4202]に書き込んでいるが、これはこの後に符号付8bit x 8bitの乗算の計算を行うからである。
[$00:4202]に被乗数、[$00:4203]に乗数を書き込むと、[$00:4216][$00:4217]の2バイトに乗算の解が入るが、上の時点では[$00:4202]にしか書き込みをしていない。
$C1/783A[$C1:6150]にジャンプするが、このジャンプ先は戦闘乱数計算のサブルーチンなので、ここから戦闘乱数計算である。

;戦闘乱数計算
$C1/6150 PHX                     ;↓戦闘乱数計算
;(中略)
$C1/61A4 RTS                     ;乱数がAと[$00:033B]に入る
;
$C1/783D STA $4203  [$00:4203]   ;A(乱数)を[$00:4203]に書き込み
$C1/7840 JSR $46C9  [$C1:46C9]   ;[$C1:46C9]へジャンプ
;
$C1/46C9 RTS                     ;サブルーチン戻り

戦闘乱数計算サブルーチンの処理は省略する。$C1/61A4で戦闘乱数($00$FF)がA[$00:033B]に入る。
計算した乱数は[$00:4203]に入るため、符号付8bit x 8bitの計算は、「LV差係数」×「戦闘乱数($00~$FF)」だったことがわかる。

$C1/7843 LDA $4217  [$00:4217]   ;Aに[$00:4217]をロード
$C1/7846 REP #$21                ;Aを16bit幅に変更、キャリーフラグクリア
$C1/7848 AND #$00FF              ;Aと$00FFで論理積
$C1/784B ADC $20    [$00:0320]   ;A + [$00:0321][$00:0320]
$C1/784D STA $20    [$00:0320]   ;Aを[$00:0321][$00:0320]に書き込み
$C1/784F SEP #$20                ;MフラグON Aレジスタは8bit幅
$C1/7851 RTS                     ;サブルーチン戻り
;
$C1/D92A BRA $15    [$D941]      ;フラグにかかわりなく常に分岐[$D941]
$C1/D941 REP #$21                ;Aを16bit幅に変更、キャリーフラグクリア
$C1/D943 LDA $20    [$00:0320]   ;Aに[$00:0321][$00:0320]をロード
$C1/D945 STA $003C,x             ;Aを[$003C,x+1][$003C,x](使用技の単発値)に書き込み
$C1/D948 SEP #$20                ;MフラグON Aレジスタは8bit幅
$C1/D94A LDA $0039,x             ;Aに[$0039,x](対象の状態異常)をロード
$C1/D94D CMP #$FF                ;Aと$FFを減算比較(ステータスレジスタ変更のみ)
$C1/D94F BEQ $0B    [$D95C]      ;ゼロフラグが立っているとき[$D95C]分岐
$C1/D951 AND #$DF                ;Aと$DF($1101 1111)で論理積
$C1/D953 STA $0039,x             ;Aを[$0039,x](対象の状態異常)に書き込み
$C1/D956 LDA #$00                ;Aに$00をロード
$C1/D958 STA $7ECE05,x           ;Aを[$7ECE05,x](眠り状態継続時間)に書き込み
$C1/D95C RTS                     ;サブルーチン戻り

$C1/7843で、乗算結果の[$00:4216][$00:4217]のうち、上1バイトが入っている[$00:4217]をロードする。
つまり[$00:4217]に入っているのは、LV差係数*乱数/$100である。
$C1/784Bで、A+[$00:0321][$00:0320]を計算し、$C1/784Dで計算結果を[$00:0321][$00:0320]に上書きする。

A + [$00:0321][$00:0320] = LV差係数*乱数/$100 + LV差係数*4

$C1/D943$C1/D945で、この値が[$003C,x+1][$003C,x](使用技の単発値)に書き込まれる。
味方キャラ1人目なら[$00:1C3D][$00:1C3C]に入る。
つまり、

LV差係数*乱数($00~$FF)/$100 + LV差係数*4

これが単発回復量にあたる。
LV差係数*4で因数分解すると、

LV差係数*4*(1/4*乱数($00~$FF)/$100 + 1)
=LV差係数*4*(1/4*(乱数0~255/256) + 1)
=LV差係数*4*((乱数0~63)/256 + 1)
=LV差係数*4*(乱数1~319/256)

となるから、結局、

(回復係数(LV差係数と同じ)*4*乱数(1~1.25)

これとほぼ同じである(実際には乱数が1以上1.25未満となる)。

以上で単発回復量計算が終了で、$C1/D948~は関係がないのだが、見てみると、回復技使用時、状態異常の値の眠り状態だけ解除して、眠り状態継続時間にも$00を書き込んでいる。
攻撃技を当てた時に眠り状態を解除するのと同じ処理になるが(眠り状態を発生させる技はその後に別途状態異常発生に関する処理を行う)、回復技の場合でも、回復技を当てると眠り状態を解除する仕様がある。
回復技の中にはもともと眠りの状態異常を回復可能な技があるが、そうでない技でも眠り状態が解除できるということになる。
例えばアキラの「ヒールタッチ」はHP回復は可能だが、状態異常を回復させる追加効果はついていない。
だが、眠り状態の味方キャラを回復させると、HPだけではなく、眠り状態の解除もできる。

サブルーチン(敵キャラ)

敵が回復技を使う場合、処理自体は味方と似ているが、アドレスは異なる。
味方でいうところの$C1/D8BE~の処理が、敵だと$C1/D870~から開始になる。

$C1/D870 LDA $7E901D[$7E:901D]   ;Aに[$7E:901D](技データ13)をロード
$C1/D874 BPL $02    [$D878]      ;ネガティブフラグが立っていないとき[$D878]分岐
;回復技だとネガティブフラグON
$C1/D876 BRA $3A    [$D8B2]      ;フラグにかかわりなく常に分岐[$D8B2]
$C1/D8B2 JSR $03F1  [$C1:03F1]   ;[$C1:03F1]へジャンプ

$C1/03F1 LDY $0002,x             ;Yに[$0002,x]をロード
$C1/03F4 LDA $002F,y             ;Aに[$002F,y](敵データ15 タイプ)をロード
$C1/03F7 BIT #$04                ;Aと$04で論理積(ステータスフラグ変更のみ)
$C1/03F9 RTS                     ;サブルーチン戻り

$C1/D8B5 BEQ $F8    [$D8AF]      ;ゼロフラグが立っているとき[$D8AF]分岐
;ゼロフラグON タイプOBJECT以外
$C1/D8AF LDA #$FF                ;Aに$FFをロード
$C1/D8B1 RTS                     ;サブルーチン戻り

$C1/D7F7 BEQ $1C    [$D815]      ;ゼロフラグが立っているとき[$D815]分岐
$C1/D7F9 LDA $7E9003,x[$7E:AB03] ;Aに[$7E9003,x](ヒット数)をロード
$C1/D7FD INC A                   ;Aをインクリメント +1
$C1/D7FE STA $7E9003,x[$7E:AB03] ;Aを[$7E9003,x](ヒット数)に書き込み
$C1/D802 JSR $D81A  [$C1:D81A]   ;[$C1:D81A]へジャンプ

ここまでが、技データ13が回復技か判定し、[$7E9003,x](敵番号1なら[$7E:AB03])にヒット数$01を書き込むという、味方側とほとんど同じ処理である。
ひとつ異なるのが、$C1/03F1$C1/03F9の処理が挟まっていることである。
ここでは敵データ15(タイプ)をロードして、$04かどうか判定している。
タイプが$04はOBJECTで、ここでOBJECTだと判定されたら$C1/D8B5以降のゼロフラグ判定でサブルーチンを抜ける。
つまり、OBJECT(岩やしょく台など)に回復技は効果がなく、HPが回復しないことになる。
OBJECTタイプ自身が回復技を使うことはないので、他の敵が周囲回復などをした場合が該当する。

$C1/D81A PHA                     ;Aをスタックにプッシュ
$C1/D81B LDA $0001,x             ;Aに[$0001,x](敵の状態)をロード
$C1/D81E CMP #$40                ;Aと$40を減算比較(ステータスレジスタ変更のみ)
$C1/D820 BNE $0E    [$D830]      ;ゼロフラグが立っていないとき[$D830]分岐
$C1/D830 PLA                     ;Aレジスタに値をプル
$C1/D831 RTS                     ;サブルーチン戻り

$C1/D805 CMP #$01                ;Aと$01を減算比較(ステータスレジスタ変更のみ)
$C1/D807 BNE $0C    [$D815]      ;ゼロフラグが立っていないとき[$D815]分岐
$C1/D809 JSR $D95D  [$C1:D95D]   ;[$C1:D95D]へジャンプ

$C1/D95D JSR $0D0D  [$C1:0D0D]   ;[$C1:0D0D]へジャンプ

$C1/0D0D LDX $78    [$00:0378]   ;Xに[$00:0378]をロード
$C1/0D0F LDA $0000,x             ;Aに[$0000,x](敵ID)をロード
$C1/0D12 CMP #$08                ;Aと$08を減算比較(ステータスレジスタ変更のみ)
$C1/0D14 BEQ $01    [$0D17]      ;ゼロフラグが立っているとき[$0D17]分岐
$C1/0D16 RTS                     ;サブルーチン戻り

敵の状態チェックで敵操作状態($40)でなければ処理が進む。
$C1/0D0D$C1/0D16なのだが、これは本来、功夫編修行で、味方キャラID$08(心山拳老師)での分岐を行うための処理である(功夫編・修行を参照)。
修行だと$0000,x[$00:1C00](味方キャラID)を呼び出すが、敵だと[$00:1B00](敵ID)をロードすることになってしまう。
敵ID$08は中世編のザコ敵であるフリーザインである。
このままだと、フリーザインだけ、回復技で別処理を行うということになってしまうのだが、フリーザイン自身も、一緒に登場する敵(ファングイーター、クールバルブ、アームストロング)も、回復技を使用しない。
よって、功夫編修行の時でしか$C1/0D0D$C1/0D16は意味をなさない(と思われる)。

$C1/D978 LDA $7E900B[$7E:900B]   ;Aに[$7E:900B](技データ10)をロード
$C1/D97C LDX $10    [$00:0310]   ;Xに[$00:0310]をロード
$C1/D97E REP #$21                ;Aを16bit幅に変更、キャリーフラグクリア
$C1/D980 AND #$00FC              ;Aと$00FCで論理積
$C1/D983 STA $20    [$00:0320]   ;Aを[$00:0321][$00:0320]に書き込み
$C1/D985 LSR A                   ;Aを論理右シフト (/2)
$C1/D986 LSR A                   ;Aを論理右シフト (/2)
$C1/D987 STA $22    [$00:0322]   ;A(LV差係数/4)を[$00:0323][$00:0322]に書き込み
$C1/D989 SEP #$20                ;MフラグON Aレジスタは8bit幅
$C1/D98B JSR $7835  [$C1:7835]   ;[$C1:7835]へジャンプ

$C1/7835 LDA $22    [$00:0322]   ;Aに[$00:0322]をロード
$C1/7837 STA $4202  [$00:4202]   ;Aを[$00:4202]に書き込み
;符号付8bit x 8bit $4202(LV差係数/4)*$4203
$C1/783A JSR $6150  [$C1:6150]   ;[$C1:6150]へジャンプ

戦闘乱数計算前の処理だが、味方キャラとはメモリに書き込む値が異なる。
味方の時には算術左シフト2回(*4)の処理が挟まっていたが、敵だとない。
このため、[$00:0321][$00:0320]にはLV差係数、[$00:0323][$00:0322]にはLV差係数/4が入る。

;戦闘乱数計算
$C1/6150 PHX                     ;↓戦闘乱数計算
;(中略)
$C1/61A4 RTS                     ;乱数がAと[$00:033B]に入る
;
;味方回復と処理合流
$C1/783D STA $4203  [$00:4203]   ;A(乱数)を[$00:4203]に書き込み
$C1/7840 JSR $46C9  [$C1:46C9]   ;[$C1:46C9]へジャンプ
;
$C1/46C9 RTS                     ;サブルーチン戻り
;
$C1/7843 LDA $4217  [$00:4217]   ;Aに[$00:4217]をロード
$C1/7846 REP #$21                ;Aを16bit幅に変更、キャリーフラグクリア
$C1/7848 AND #$00FF              ;Aと$00FFで論理積
$C1/784B ADC $20    [$00:0320]   ;A + [$00:0321][$00:0320]
$C1/784D STA $20    [$00:0320]   ;Aを[$00:0321][$00:0320]に書き込み
$C1/784F SEP #$20                ;MフラグON Aレジスタは8bit幅
$C1/7851 RTS                     ;サブルーチン戻り

乱数計算から$C1/7851までは、味方の処理と同じである。
ただ、符号付8bit x 8bitの計算は、「LV差係数/4」×「戦闘乱数($00~$FF)」と、内容が変わった。
よって、$C1/7843でロードするのは、LV差係数/4 * 戦闘乱数($00~$FF)/$100になる。
$C1/784Bでの計算も、

A + [$00:0321][$00:0320]
= LV差係数/4 * 戦闘乱数($00~$FF)/$100 + LV差係数

となる。
これが敵が回復技を使用した時の単発回復量になる。
味方の場合、単発回復量は、

LV差係数*乱数($00~$FF)/$100 + LV差係数*4

と、ちょうど4倍の値であった。
これが味方と敵との回復量計算の相違点ということになる。

;敵用処理
$C1/D98E BRA $17    [$D9A7]      ;フラグにかかわりなく常に分岐[$D9A7]
$C1/D9A7 REP #$21                ;Aを16bit幅に変更、キャリーフラグクリア
$C1/D9A9 LDA $20    [$00:0320]   ;Aに[$00:0321][$00:0320]をロード
$C1/D9AB STA $7E9004,x           ;Aを[$7E9004,x+1][$7E9004,x](回復量の単発値 2バイト)に書き込み
$C1/D9AF SEP #$20                ;MフラグON Aレジスタは8bit幅
$C1/D9B1 LDA $7E8F07,x           ;Aに[$7E8F07,x](状態異常)をロード
$C1/D9B5 AND #$DF                ;Aと$DF($1101 1111)で論理積
$C1/D9B7 STA $7E8F07,x           ;Aを[$7E8F07,x](状態異常)に書き込み
$C1/D9BB LDA #$00                ;Aに$00をロード
$C1/D9BD STA $7E8F0D,x           ;Aを[$7E8F0D,x](眠り状態継続時間)に書き込み
$C1/D9C1 LDA $0000,x             ;Aに[$0000,x](敵ID)をロード
$C1/D9C4 CMP #$D0                ;Aと$D0を減算比較(ステータスレジスタ変更のみ)
$C1/D9C6 BNE $11    [$D9D9]      ;ゼロフラグが立っていないとき[$D9D9]分岐
$C1/D9D9 RTS                     ;サブルーチン戻り

$C1/D98E~は敵用のサブルーチンだが、処理は味方キャラとほぼ同じ。
単発回復量[$00:0321][$00:0320]を、敵番号0なら[$7E:AB05][$7E:AB04]に書き込むことになる。
回復量の処理自体はこれで終わりだが、味方キャラと同じく、敵の状態異常の値から眠り状態のみ削除して、眠り状態継続時間に$00を書き込んでいる。
よって、敵でも、回復技に付随する状態異常の追加効果は関係なしに、回復技を使用すると眠り状態を解除することがわかる。

$C1/D9C1~は敵IDが$D0の時、つまりオディオモール専用処理である。
これについてはオディオモールのダメージ量処理で説明しているので詳細は省く。



このページをシェアする

上へ