TOP > プログラミング関係解説&調査 > 「ほいこーろー」の仕様

「ほいこーろー」の仕様

前ページのオディオモールのダメージ量処理の続き。

オディオモールのダメージ量処理から、「ほいこーろー」の仕様はどうなっているのかが気になってくるところである。
「ほいこーろー」そのものの計算方法もさることながら、単発ダメージ量を強制的に1にするオディオモールに「ほいこーろー」を当てた時、オディオモールにだけ、STEP数+1のダメージを与えられる理由は何だろうか。

筆者も以前から「ほいこーろー」の仕様については気になってはいたが、筆者のプログラミングに関する知識程度ではどうにもならない部分が多々ある。
とはいえ、多少はわかったこともあるので、以下で紹介しておく。

筆者は以前、 技 > 「ほいこーろー」についてで、実際に1000回「ほいこーろー」を使い、STEP数をカウントしてみたことがあるので、そちらも参照していただきたい。
検証において、STEP数の平均値は32.4で、出現する値は2~99だった。
中央の値である50付近が平均ではない。

また、上の「ほいこーろー」の検証内でも紹介しているが、世界の合言葉は森部様によれば、SFC版での「ほいこーろー」は、

ほいこーろーは、踊る前にSTEP数を設定するわけではなく、
踊りながらここで終わるか続けるかを決めている気がする。
具体的な確率はわからない。
STEP数は分布で言うと一様分布ではなく幾何分布になりそう。

とのことである。

では、実際のプログラムではどうなっているのだろうか。
上にある通り、「ほいこーろー」のモーションの踊りが開始する前の乱数でSTEP数が決まっているのではなさそうで、

乱数計算→特定のアドレスに値を追加→乱数計算→特定のアドレスに値を追加→……

を繰り返し、メモリに蓄積された値がSTEP数となる、という仕様は間違いないようである。
これまでも述べた通り、戦闘中の乱数は、必要な時にだけ計算される。
マップ上での乱数のように常に計算され続けているのではない。
このため、「ほいこーろー」開始直前に、バーチャルコンソールの「まるごと保存」で保存してから「まるごと復元」した場合、その後に「ほいこーろー」を選択すると、すぐにAボタンで「ほいこーろー」を開始しようが、しばらく待ってからAボタンで「ほいこーろー」を開始しようが、「ほいこーろー」のSTEPSは変わらない。
戦闘中の乱数は、前4つの乱数が常に記録されている状態であるが、ただ待機するだけではそれら乱数が変化することはないからである。
逆に言えば、「ほいこーろー」のダメージ量を確認してから「まるごと復元」してわざと敵に行動させるなどして乱数を動かし、それから「ほいこーろー」を開始するとSTEP数が変わる可能性がある、ということでもある。バーチャルコンソール限定ではあるが、「ほいこーろー」で高ダメージ量だけを狙い続けたい場合に使えるテクニックである。

ただ、具体的にどういう条件だと踊りを続けるのか、また止めるのかはよくわからない。
乱数計算は何度も繰り返されている上、間にサモのモーション関係のサブルーチンも動くようであり、筆者のような素人には非常に難解なプログラムになっている。
とりあえず最低限わかったことを、以下に記す。

「ほいこーろー」が始まると、サモが踊るたびにアドレス[$7E:A01A]に値が蓄積されていく。
また、[$7E:A01A]への数値の蓄積は、下のサブルーチンが関わっている。

$C1/A73F LDA $7E0000,x[$7E:A01A] ;[$7E:A01A]をロード
$C1/A743 CLC                     ;キャリーフラグをクリア
$C1/A744 ADC $11    [$00:0311]   ;[$7E:A01A]+[$00:0311]
$C1/A746 STA $7E0000,x[$7E:A01A] ;[$7E:A01A]に書き込み

踊るたびに乱数計算をし、このサブルーチンに到達して、[$7E:A01A]が増加するのだが、$C1/A73Fは、
LDA $7E0000,x
と指定されており、この前までの計算でX:A01Aとなっていなければ[$7E:A01A]は増加しない。
乱数によって他のメモリが選ばれることがあり、それが分岐となって[$7E:A01A]が増えなくなり、実際のSTEP数が決まるはずだが、そのあたりもよくわからない。
このサブルーチンはサモが踊っている間に回るので、踊りつつ戦闘乱数を計算し踊り続けるかどうかを決めているのは間違いない。

$C1/A744では[$00:0311]が足されているが、[$00:0311]の値は常に一定ではなく、踊った回数に従い1ずつ増加していくのではない。
16進数であるにも関わらず、

00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 0A, 10, 11, 12, 13……, 18, 19, 1A, 20, 21……

と、一番下の桁のB~Fが飛ばされている。
どうやら[$00:0311]は、[$7E:A01A]に収納されている数値により変化し、通常は「$01」で、一番下の桁がAの時だけ「$06」になるようだ。
しかも一番下の桁がAだと、その直後にすぐ「$01」を加える処理が入るため、実質的には「$09」の後はすぐに「$10」に変わる。
何故このような処理にしているのかは、後でわかる。

最終的に何かしらの条件で踊りが止まる。つまり、[$7E:A01A]の増加が止まる。
そうすると、諸々の計算を挟んだ後に、以下のアドレスに飛ぶ。

$C1/A4F7 LDA $7EA01A[$7E:A01A]
$C1/A4FB STA $6E    [$00:036E]

ここで[$7E:A01A]の値は、[$00:036E]に収納され、STEP数として「●●STEPS」と画面上に表示される。
面白いことに、この時の数値は16進数2桁なのに、10進数に変換せず、そのままで表示される。
たとえば[$00:036E]$50が入った場合、16進数の「50」は10進数に変換すると「80」なのに、80ではなく「50 STEPS」と表示されるのである。
このために、[$7E:A01A]の増加量は「$01」か「$06」のどちらかであったのだ。

また、STEPS最大値が99である以上、何かしらの処理で最大値を「$99」までと制限しているはずである。

更に、STEPSの表示の後に、実際のダメージ量計算が別に挟まっている。
このままでは、画面上では「50 STEPS」と表示されていても、10進数では「80」だから、例えば攻撃した敵の現在HPからダメージ量を引く場合などに矛盾が生じてしまう。
よって、STEPSから実際のダメージ量に変換する必要がある。
その変換は「ゲーム画面に実際のダメージ量を表示する前」に行われ、

「計算した総ダメージ量から、実際に画面上に表示する数値を計算する」

サブルーチンとなる。
そのサブルーチンは以下のようになっており、STEPS数が画面に表示されてから、実際のダメージ量(敵が回復技や吸収技を使った時は回復量)が敵の上に表示されるまでの間に処理される。
実は通常の攻撃技と共通のサブルーチンを使っているので、他の味方の技などでもこのサブルーチンは通過する。
ただ、「ほいこーろー」のダメージ量のみ[$00:036E]に格納され、それ以外の技だと[$00:036E]に「00」が収納されており、そこでのみ分岐が起きる仕組みである。
(このサブルーチンは、「ほいこーろー」とほぼ同じ仕組みである幕末編の商人などが使用してくる「わいろ」にも使用されているかもしれないが、未確認)

なお以下は、オディオモールに「ほいこーろー」を当てた前提でメモリの位置を記している。

;通常技と共通処理
$C1/CDE7 STZ $22    [$00:0322]   ;[$00:0322]に0を書き込み
$C1/CDE9 STZ $23    [$00:0323]   ;[$00:0323]に0を書き込み
$C1/CDEB LDA $77    [$00:0377]   ;Aに[$00:0377]をロード
$C1/CDED AND #$0F                ;Aと$0Fで論理積
$C1/CDEF CMP #$08                ;Aと$08を減算比較
$C1/CDF1 BNE $17    [$CE0A]      ;ゼロフラグが立っていないとき[$C1/CE0A]分岐
$C1/CDF3 LDA $6E    [$00:036E]   ;Aに[$00:036E]をロード(= 「ほいこーろー」STEP数)
$C1/CDF5 BEQ $13    [$CE0A]      ;ゼロフラグが立っているとき[$C1/CE0A]分岐(※おそらく「ほいこーろー」以外の技は00)
;
;ここから「ほいこーろー」用処理
$C1/CDF7 AND #$F0                ;Aと$F0で論理積
$C1/CDF9 LSR A                   ;Aを論理右シフト(A/2)
$C1/CDFA STA $22    [$00:0322]   ;Aを[$00:0322]に書き込み
$C1/CDFC LSR A                   ;Aを論理右シフト(A/2)
$C1/CDFD LSR A                   ;Aを論理右シフト(A/2)
$C1/CDFE ADC $22    [$00:0322]   ;A+[$00:0322]
$C1/CE00 STA $22    [$00:0322]   ;Aを[$00:0322]に書き込み
$C1/CE02 LDA $6E    [$00:036E]   ;Aに[$00:036E]をロード
$C1/CE04 AND #$0F                ;Aと$0Fで論理積
$C1/CE06 ADC $22    [$00:0322]   ;A+[$00:0322]
$C1/CE08 STA $22    [$00:0322]   ;Aを[$00:0322]に書き込み
;ここまで「ほいこーろー」用処理
;
$C1/CE0A RTS                     ;サブルーチンここまで
;
;通常技と共通処理
$C1/CD32 REP #$20                ;Mフラグをクリア Aレジスタは16bit幅
$C1/CD34 LDA $2134  [$00:2134]   ;Aに[$00:2134]をロード(= この時点での総ダメージ量)
$C1/CD37 STA $20    [$00:0320]   ;Aを[$00:0320]に書き込み
$C1/CD39 LDA $7E920A,x[$7E:AD2A] ;Aに[$7E:AD2A]をロード
$C1/CD3D AND #$00FF              ;Aと$00FFで論理積
$C1/CD40 BEQ $04    [$CD46]      ;ゼロフラグが立っているとき[$C1/CD46]分岐
$C1/CD46 LDA $20    [$00:0320]   ;Aに[$00:0320]をロード
$C1/CD48 CLC                     ;キャリーフラグをクリア
$C1/CD49 ADC $22    [$00:0322]   ;A+[$00:0322]
$C1/CD4B CMP #$03E7              ;Aと$03E7(=10進数999)を減算比較
$C1/CD4E BCC $03    [$CD53]      ;キャリーフラグが立っていないとき[$C1/CD53]分岐
$C1/CD53 STA $7E9200,x[$7E:AD20] ;Aを[$7E:AD20]に書き込み

順に説明する。

;通常技と共通処理
$C1/CDE7 STZ $22    [$00:0322]   ;[$00:0322]に0を書き込み
$C1/CDE9 STZ $23    [$00:0323]   ;[$00:0323]に0を書き込み
$C1/CDEB LDA $77    [$00:0377]   ;Aに[$00:0377]をロード
$C1/CDED AND #$0F                ;Aと$0Fで論理積
$C1/CDEF CMP #$08                ;Aと$08を減算比較
$C1/CDF1 BNE $17    [$CE0A]      ;ゼロフラグが立っていないとき[$C1/CE0A]分岐
$C1/CDF3 LDA $6E    [$00:036E]   ;Aに[$00:036E]をロード(= 「ほいこーろー」STEP数)
$C1/CDF5 BEQ $13    [$CE0A]      ;ゼロフラグが立っているとき[$C1/CE0A]分岐(※おそらく「ほいこーろー」以外の技は00)

「ほいこーろー」専用処理前の部分。
敵にダメージを与えたり、敵が回復するなど、敵側のHPの値に変動が起きる場合、敵のHPの増減分が画面に表示される直前に、必ずここの処理を通るようである。

最初の2行、STZ $22STZ $23は、該当アドレスに0を書き込むという命令なのだが、この後の計算の都合などで一度0を書き込んでいるのだと思われる。
その後に$C1/CDEB LDA $77で、アドレス[$00:0377]の値をロードし、次に$0Fで論理積を取っていることから、必要なのは[$00:0377]の値の下1桁だけなのだろうという推測ができる。

次の
$C1/CDEF CMP #$08
は、「[$00:0377]の値の下1桁」と$08を引き算して比較しており、その次でゼロフラグが立っていないのなら[$C1/CE0A]へジャンプする。
ここの「[$00:0377]の値の下1桁」は、敵のHPをマイナスするか(攻撃技か)、それともプラスするか(回復または吸収技か)、という判定のようである。
「ほいこーろー」はじめ、敵にダメージを与える場合は、ここで「[$00:0377]の値の下1桁」が$08となり、ゼロフラグが必ず立つようである。
(このあたりの詳しい処理は確認していない)
回復や吸収だと、戦闘画面に出る数値が緑色になることや、後の計算処理の関係から、ここで条件分岐して何かしら指定しているのだと思われる。

問題は次の
$C1/CDF3 LDA $6E [$00:036E]
である。
先に述べた通りに、[$00:036E]には「ほいこーろー」のSTEPS数が収納されており、「ほいこーろー」を使った時以外は0が入っているようである。
このため、「ほいこーろー」使用時だとここでゼロフラグが立たず、[$C1/CE0A]へは飛ばないで、「ほいこーろー」用処理へ続く。

;ここから「ほいこーろー」用処理
$C1/CDF7 AND #$F0                ;Aと$F0で論理積
$C1/CDF9 LSR A                   ;Aを論理右シフト(A/2)
$C1/CDFA STA $22    [$00:0322]   ;Aを[$00:0322]に書き込み
$C1/CDFC LSR A                   ;Aを論理右シフト(A/2)
$C1/CDFD LSR A                   ;Aを論理右シフト(A/2)
$C1/CDFE ADC $22    [$00:0322]   ;A+[$00:0322]
$C1/CE00 STA $22    [$00:0322]   ;Aを[$00:0322]に書き込み
$C1/CE02 LDA $6E    [$00:036E]   ;Aに[$00:036E]をロード
$C1/CE04 AND #$0F                ;Aと$0Fで論理積
$C1/CE06 ADC $22    [$00:0322]   ;A+[$00:0322]
$C1/CE08 STA $22    [$00:0322]   ;Aを[$00:0322]に書き込み
;ここまで「ほいこーろー」用処理

ここからが「ほいこーろー」用の処理になる。
Aには、STEP数である[$00:036E]がロードされている状態である。
STEP数は16進数なのに、そのまま「10進数のSTEP数」という扱いで画面に表示されてしまったので、ここで[$00:036E]を10進数から16進数に変換する処理が行われているのだろう、ということは想像に難くない。
調べてみたところ、やはりその通りであったが、アセンブラ言語の教科書にも載っているような基本の「2桁の16進数の値を10進数に解釈し直すプログラム」であるらしいので、わかる方は以下の説明は飛ばしてしまっても構わない。
結論だけ述べると、最後の
$C1/CE08 STA $22 [$00:0322]
で、STEP数が16進数としてA[$00:0322]に書き込まれた状態になり、通常技と共通処理の$C1/CDF7~に続く。

前提として、STEP数の最大値は99であるから、10進数1~2桁の数値を、16進数1~2桁に変換することになる。
また、これまでも何度か記しているが、2進数と16進数について理解しておく必要がある。
16進数2桁の数は、上1桁を2進数4桁+下1桁を2進数4桁という形で表記できる。
たとえば、16進数67は、2進数だと「01100111」だが、2進数の上4桁「0110」は16進数だと「6」で、2進数の下4桁「0111」は16進数だと「7」である。

では、「2桁の16進数の値を10進数に解釈し直す」には、どうしたら良いか。
10進数では、上1桁が10の位であるから、「上1桁×10 + 下4桁」で、10進数に見なした値に変換できる、という理屈である。
ここからの目的は「上1桁×10 + 下4桁」の実行である。

例えばSTEP数が「67」の時、実際には16進数の67であるが、上1桁の「6」と下1桁の「7」に分離し、上1桁の「6」を10倍した後、下1桁の「7」を足せば、10進数の扱いにできる。
各桁を分離する方法だが、上の通りに16進数67は、2進数の上4桁「0110」が「6」にあたり、2進数の下4桁「0111」が「7」に当たる。
2進数に一度変換することで、上1桁と下1桁の分離が簡単にできる(……といっても、人間には2進数や16進数の時点で簡単には見えないが、2進数が基本のコンピュータにとっては都合が良い)。

上1桁と下1桁の分離については、論理積を使えば良い。
ここまででも何度か紹介しているが、論理積は2つのものを見比べて、「AかつBなら真とする」「それ以外は偽」という演算のこと。
2進数での計算においては、2つの値を見比べて「どちらも1の桁は1とし、それ以外の桁は0とする」演算である。
16進数67は、2進数だと「01100111」であるが、上4桁だけ取り出したいのなら、上4桁が1で下4桁が0の値とで論理積を取る。
つまり「01100111」と「11110000」との論理積で、上4桁「01100000」になる。
これを16進数で書き直すと、「$67$F0との論理積で、$60になる」ということになる。
「ほいこーろー」用処理の最初の行である、

$C1/CDF7 AND #$F0                ;Aと$F0で論理積

これはまさに「16進数の上1桁だけ取り出す」という計算である。
ただしこの時点では「01100000」と、下に0が4個ついた状態である($60である)ということに注意。
$6」だけだと、「0110」である。

16進数の上1桁が取り出せたので、まずは「上1桁×10 + 下4桁」の最初の「上1桁×10」を行うのだが、上の処理を見ると、$C1/CDF7以降に「上1桁×10」の計算はしておらず、なぜか割り算と足し算を繰り返している。
割り算と足し算でいったい何を計算しているのだろうか。

ここまででも紹介してきた通り、スーパーファミコンのプログラム言語の65C816用アセンブリで乗算や除算をするのは処理に時間がかかるし、容量もかさむ。
ただし×2÷2は、ビットシフトという方法で簡単にできるようになっている。
命令だと「ASL」が×2で(算術左シフト)、「LSR」が÷2である(論理右シフト)。

2進数は÷2すると、数字列がそのまま右へ移動していく(ビットシフト。右に移動する場合、論理右シフト)。
16進数67を1回論理右シフトすると(÷2)、「01100111」→「00110011」である。

では、「$C1/CDF7 AND #$F0」で算出した、16進数の上4桁部分であり2進数の「01100000」に1回論理右シフトするとどうなるか。
右に1回移動するから、「00110000」である。
この値は、「$6」である「0110」を、左に3回移動(×2を3回)と同じである。
0110」を左に3回移動することは、下に0を3個つけるのと同じことだから、「0110000」、8桁表示にすれば「00110000」である。

つまり、「$60」を1回論理右シフト(÷2)と、「$6」を左に3回算術左シフト(×2を3回)は、同じ結果となる。

現在の目的は、「上1桁×10」である。上1桁に0がひとつついている「$60」ではなく、「$6」を×10したい。
ここまでで、「$6」を左に3回算術左シフト(×2を3回)したことになる。つまり「$6」を×8することはできた。

$C1/CDF9 LSR A                   ;Aを論理右シフト(A/2)
$C1/CDFA STA $22    [$00:0322]   ;Aを[$00:0322]に書き込み

これは結局、「16進数の上1桁の数を×8」して、[$00:0322]に書き込んだ、という手順であった。
だが実際にやりたいのは「16進数の上1桁の数を×10」である。
この後の処理の続きを見てみよう。

$C1/CDFC LSR A                   ;Aを論理右シフト(A/2)
$C1/CDFD LSR A                   ;Aを論理右シフト(A/2)
$C1/CDFE ADC $22    [$00:0322]   ;A+[$00:0322]
$C1/CE00 STA $22    [$00:0322]   ;Aを[$00:0322]に書き込み

$60」を1回論理右シフト(÷2)した後の数値を、更に2回続けて論理右シフト(÷2)している。
現在、「01100000」を1回右シフトして「00110000」になっており、ここから更に2回右シフトすると、「00001100」である。
この値は、「$6」である「0110」を、左に1回移動(×2を1回)と同じである。
よって、ここで行ったことは、$C1/CDFC$C1/CDFDで「16進数の上1桁の数を×2」してから、$C1/CDFEで、既に[$00:0322]に入っていた「16進数の上1桁の数を×8」と足し算をする、という計算である。
$C1/CE00では足し算した結果を[$00:0322]に書き込んでいるので、[$00:0322]の中は、

「16進数の上1桁の数を×8」+「16進数の上1桁の数を×2」

に変化した。
これは、

「16進数の上1桁の数」×(8 + 2)

と、まとめることができ、結局、

「16進数の上1桁の数」×10

である。
論理右シフトという割り算と、足し算を組み合わせて、「16進数の上1桁の数」×10ができたのである。

さて、ここまで計算したら、後は、
上1桁×10 + 下4桁
の、最後の「 + 下4桁」をするだけである。

$C1/CE02 LDA $6E    [$00:036E]   ;Aに[$00:036E]をロード
$C1/CE04 AND #$0F                ;Aと$0Fで論理積
$C1/CE06 ADC $22    [$00:0322]   ;A+[$00:0322]
$C1/CE08 STA $22    [$00:0322]   ;Aを[$00:0322]に書き込み
;ここまで「ほいこーろー」用処理

上1桁と下1桁の分離の話で述べた通り、下1桁だけ取り出したいのなら、STEP数と$0Fの論理積を取れば良い。
16進数67の下1桁だったら、$67$0Fの論理積を取って「$07」である。
$C1/CE02でSTEP数をAにロードし、$C1/CE04でSTEP数と$0Fの論理積を取っている。
この値と、[$00:0322]に収納されている「上1桁×10」を足したのが$C1/CE06である。
最後に、足した結果を[$00:0322]に書き込みして、「2桁の16進数の値を10進数に解釈し直す」作業が終了した。

実際の計算だけ取り出すと以下の通り。
67」を10進数と見なし、16進数に変換する場合、

$60/2 + $60/8 + $7 = $43

である。

;通常技と共通処理
$C1/CD32 REP #$20                ;Mフラグをクリア Aレジスタは16bit幅
$C1/CD34 LDA $2134  [$00:2134]   ;Aに[$00:2134]をロード(総ダメージ量)
$C1/CD37 STA $20    [$00:0320]   ;Aを[$00:0320]に書き込み
$C1/CD39 LDA $7E920A,x[$7E:AD2A] ;Aに[$7E:AD2A]をロード
$C1/CD3D AND #$00FF              ;Aと$00FFで論理積
$C1/CD40 BEQ $04    [$CD46]      ;ゼロフラグが立っているとき[$C1/CD46]分岐
$C1/CD46 LDA $20    [$00:0320]   ;Aに[$00:0320]をロード
$C1/CD48 CLC                     ;キャリーフラグをクリア
$C1/CD49 ADC $22    [$00:0322]   ;A+[$00:0322]
$C1/CD4B CMP #$03E7              ;Aと$03E7(=999)を減算比較(0033-03E7)
$C1/CD4E BCC $03    [$CD53]      ;キャリーフラグが立っていないとき[$C1/CD53]分岐
$C1/CD53 STA $7E9200,x[$7E:AD20] ;Aを[$7E:AD20]に書き込み

STEP数が16進数としてA[$00:0322]に書き込まれた状態で、残りの処理が進む。
経緯は省略するが、この時点で[$00:2134]には総ダメージ量(= 単発ダメージ量×ヒット数)が入っている。
とはいえ、「ほいこーろー」の場合、この値は敵味方のステータスに関係なく0で、例外はオディオモールのみ。
単発ダメージ量が強制的に1に変更される都合で、オディオモールに対しての「ほいこーろー」の総ダメージ量は必ず「1」である。
総ダメージ量は一度、[$00:0320]に書き込まれる。

次の$C1/CD39 LDA $7E920A,xは、攻撃相手の回避属性関係・場の属性関係の値を取得しており、$C1/CD3Dで$00FFで論理積を取った結果、ゼロフラグが立つのであれば回避属性によるダメージ量半減計算が挟まる。
「ほいこーろー」は無属性の攻撃なので回避属性での半減は起こらないが(ついでに、オディオモールには回避属性が設定されていない)、ここで回避属性のダメージ量半減が起こる場合は、

$C1/CD42 LSR $20    [$00:0320] ;論理右シフト(÷2)
$C1/CD44 INC $20    [$00:0320] ;[$00:0320]の値をインクリメント(+1)

このような処理が挟まって、[$00:0320]に書き込まれた総ダメージ量は÷2された後+1される。
SF編キャプテンスクウェアで、ラ・ラに攻撃を当てた時、実際の総ダメージ量が0でも回避属性で「0÷2+1」と計算されてダメージ量が1になる、という有名なネタがあるが、その計算はここで生まれているのである。

とはいえ、「ほいこーろー」では上の処理は入らないので、次の$C1/CD46以降の話を続ける。

この後は$C1/CD48でキャリーフラグをクリアし(キャリーフラグが立っていると、この後の「ADC $22」の計算で余計な繰り上がりが生じるので)、$C1/CD49 ADC $22では、

[$00:0320](=総ダメージ量) + [$00:0322](=「ほいこーろー」でのダメージ量)

を計算している。
「ほいこーろー」以外では、[$00:0322]の値は0であるから、[$00:0320](=総ダメージ量)に変化はない。
一方、「ほいこーろー」の場合、ここで「ほいこーろー」のSTEP数が足されることになる。
「ほいこーろー」の単発ダメージ量は、敵味方のステータスに関係なく、計算値は「0」にされる。
よって、通常、「ほいこーろー」のダメージ量は、

0 + 「ほいこーろー」のSTEP数

である。
しかし、オディオモールのダメージ量処理で記したとおり、オディオモールは自身への「単発ダメージ量を無条件で1に変更する」という仕様がある。
このため、オディオモールに対してだけは、「ほいこーろー」のダメージ量は、

1 + 「ほいこーろー」のSTEP数

になる。
これが、オディオモールに対して「ほいこーろー」を使った場合、画面に表示されるSTEPSの数と、実際にオディオモールへ与えるダメージ量が「1」だけ異なる理由である。

最後に、以下の処理が入っている。

$C1/CD4B CMP #$03E7              ;Aと$03E7(=10進数999)を減算比較
$C1/CD4E BCC $03    [$CD53]      ;キャリーフラグが立っていないとき[$C1/CD53]分岐
$C1/CD53 STA $7E9200,x[$7E:AD20] ;Aを[$7E:AD20]に書き込み

総ダメージ量と、$03E7(=10進数999)を比較している。
この計算でキャリーフラグが立つのは、2進数で計算した時、引き算で繰り下がりが起きない時であり、つまりは引き算の結果が0以上の時である。
要するに、総ダメージ量が999以上の時は[$C1/CD53]に飛ばずにそのまま計算が続くのだが、$C1/CD4E$C1/CD53の間は、

$C1/CD50 LDA #$03E7 ;Aに$03E7(=10進数999)を書き込む

これが挟まっている。
つまり、総ダメージ量が999以上の時は、ダメージ量を999に変更する、という処理である。
ダメージ量(または回復量)のカウンターストップはここで処理されていた、ということがわかる。
ただし「ほいこーろー」のダメージ量は最大で99なので、この処理を通ることはない。



このページをシェアする

上へ