TOP > プログラミング関係解説&調査 > ラーニング

ラーニング

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

本作には、現代編と幕末編に、レベルアップでなくても敵の技から技を覚えることができるシステム「ラーニング」がある。
SFC版では「ラーニング」は正式名称ではないが、リメイク版では「ラーニング」となっているため、本攻略でも「ラーニング」という用語で説明している。
功夫編は、主人公の心山拳老師が弟子に技を当てて覚えさせる、逆のラーニングの仕組みだが、ここでは現代編及び幕末編のラーニングについて、実際のサブルーチンがどうなっているのかなどを紹介する。
ちなみに仕組み自体は、現代編と幕末編のラーニング、功夫編の逆ラーニング、ともにほぼ同じである。

現代編と幕末編では、ラーニングの仕組みに相違点がある。なお、いずれの場合も、敵の攻撃を回避した時には習得不可。

  • 現代編では、主人公の高原日勝が、敵からラーニング可能な技で攻撃された直後に、その技を習得し、すぐに使えるようになる。
  • 幕末編では、主人公のおぼろ丸またはカラクリ丸がパーティにいる時、敵がおぼろ丸またはカラクリ丸がラーニング可能な技で攻撃して味方キャラの誰かに命中した場合、その戦闘終了後に該当の技を習得する。

幕末編では、ラーニング可能な技をくらうのが味方側の誰であっても構わない。
ラーニングとは無関係のとらわれの男が技をくらったとしてもラーニングできる。
実質、「敵が戦闘でラーニング可能な技を見せる(かつ命中する)」ことがラーニングの条件のようになっている。
現代編では、味方キャラが高原のみで、技を食らうのも高原だけだから、条件は「敵が戦闘でラーニング可能な技を見せる(かつ命中する)」と同一と言っても良いことになる。

では、実際にはどのようにして技を習得するのか。
まずはラーニングに必要となるメモリアドレスやステータスなどを紹介する。

シナリオ別キャラデータ

習得済みの技のデータはシナリオ別キャラデータの開始アドレス+$0D$0Eに入っている。
アドレス+$0Dには技0~7の習得状況、アドレス+$0Eには技8~15の習得状況が入っている。
2進数8ビットの値が8種類の技のON/OFFに対応していて、各アドレスに合計値が入る仕組みである。

キャラデータ開始アドレス+$0D(技0~7)+$0E(技8~15)
高原 日勝$00:0E40$00:0E4D$00:0E4E
おぼろ丸$00:0EC0$00:0ECD$00:0ECE
カラクリ丸$00:0F40$00:0F4D$00:0F4E
+$0E+$0Dレベル高原 日勝おぼろ丸カラクリ丸
%0000 0000%0000 00000烈風正拳づき忍び斬り忍び斬り
%0000 0000%0000 00011どう回し回転げり十文字斬り十文字斬り
%0000 0000%0000 00102気合いため忍法火炎ぼたる忍法火炎ぼたる
%0000 0000%0000 01003M・ボンバー水トンの術火トンの術
%0000 0000%0001 00004Gスープレックス火トンの術水トンの術
%0000 0000%0010 00005アームロック毒きりシュラのイン
%0000 0000%0100 00006C.H.ホールド手裏剣乱糸切り下ろし
%0000 0000%1000 00007パンチャマキック忍法夢幻蝶手裏剣乱糸
%0000 0000%0000 00008スパイラル・ニー砂ジンの術風魔手裏剣
%0000 0001%0000 00009Fシュタイナー忍法雪木がらしエレキテル放電
%0000 0010%0000 000010トルネードプレス忍法カマイタチ火炎放射
%0000 0100%0000 000011アロハリテシュラのイン忍法コママワリ
%0001 0000%0000 000012鬼不動返し忍法火の鳥尾出流手裏剣術
%0010 0000%0000 000013あびせげり忍法コマまわし忍法コマまわし
%0100 0000%0000 000014通打影一文字とろけるせっぷん
%1000 0000%0000 000016大激怒岩バン割り忍法矢車草大激怒岩バン割り

習得できる技の数はキャラにより変わるが、ラーニングができる高原・おぼろ丸・カラクリ丸は16種類の技を習得できる。
レベルアップ時は、レベルに応じた技を習得する。
レベル0の技はレベル1の時点で習得済みであり、シナリオ開始時にレベル1のキャラであっても、最低限1種類は技が使用可能になっている。

高原であれば、現代編開始時にレベル2であり、「烈風正拳づき」「どう回し回転げり」「気合いため」を習得済みだから、値は以下のようになる。

アドレス$00:0E4D(技0~7)$00:0E4E(技8~15)
%0000 0111
$07
%0000 0000
$00

つまり、$00:0E4D$07$00:0E4E$00が入った状態で開始になる。
ラーニングの際には、くらった技が既に習得済みか否かのチェック及び、ラーニングした技を上書きする処理が必要になるため、このふたつのアドレスの読み込みと書き込みが行われる。

敵データ

敵の使用技及び、使用技IDを敵技一覧から取得するか、味方技一覧から取得するかの確認が必要。
ラーニングできる技は味方技にしか収納されていないため、必然的に、ラーニングできる技を使ってくる敵も味方技IDの技しか使わない。
よって、敵データ09の上1ビットが「1」になっている。

戦闘中、敵種類データの$20$3Fに敵データの32バイトがそっくり入るため、敵データはそこから獲得できる。

敵種類データ内容
$29敵データ09 上1ビット:使用技を敵技IDから取得するなら0、味方技IDから取得するなら1 / 下7ビット:レベル
$2B敵データ11 使用技1 技ID 敵データ09上1ビットが0なら敵技ID / 1なら味方技ID、以下敵データ14まで同じ
$2C敵データ12 使用技2 技ID
$2D敵データ13 使用技3 技ID
$2E敵データ14 使用技4 技ID

敵が使った技

後で処理を掲載するが、現代編と幕末編では、$7E:9200~に、すべての敵が使用した技IDが順に入っていく。他のシナリオではこの処理は行われない。
ただし、その技が味方に命中した場合に限る。
また、既に使用した技は書き込まれない。
どの敵が使ったか、また、どの味方キャラに命中したかの区別はない。
また、技IDを書き込むと同時に、その次のアドレスに$00を書き込む。

$7E:9200の初期値は$00で、技IDを書き込む時には、$7E:9200から順に入っている値をチェックし、もしこれから書き込もうとしている技IDに一致した値がない場合、「最初に$00が入っているアドレスに、技IDを上書きし、更に次のアドレスに$00を書き込む」という手順で行われる。

結論を書いてしまうと、$7E:9200~に書き込まれた技IDと、ラーニング可能な味方キャラが未習得の技IDをチェックし、もし同一の値があるのならラーニング判定となって、味方キャラが該当の技を覚える、という仕組みである。
$7E:9200~の仕組み上、幕末編では、味方の中の誰かがラーニング可能な技をくらえば、ラーニングが可能というシステムになっている。

なお、「現代編と幕末編では」と書いたとおり、サブルーチン中にシナリオによる分岐が入る。
$00:0A00に、現在プレイ中のシナリオの数値が入っている。

シナリオ[$00:0A00]
中世$00
原始$01
SF$02
功夫$03
西部$04
現代$05
近未来$06
幕末$07
最終$08

現代編のサブルーチン

では、まず、現代編におけるラーニングのサブルーチン・処理を見てみよう。
現代編の場合は、高原が対戦相手から、ラーニング可能な技を食らった直後、技を習得する。
例として、ナムキャット戦で、「スパイラル・ニー」を食らってラーニングした処理を紹介する。

ラーニング前、高原は初期状態で、まだ何の技もラーニングしていない。
高原の技の習得状況$00:0E4D$00:0E4Eは以下の状態である。
「スパイラル・ニー」は技8にあたり、習得すると$00:0E4Eの一番下の位に1が立つはずである。

アドレス
$00:0E4D(技0~7)%0000 0111
$07
$00:0E4E(技8~15)%0000 0000
$00

ナムキャットの敵種類データは以下の通り。
敵データ09の上1ビットが1なので、技IDは味方技一覧から取得する。
「スパイラル・ニー」は味方技IDで$88にあたる。

アドレス内容
$00:1A29$83敵データ09
$00:1A2B$79敵データ11 使用技1 技ID(イナズマアッパー)
$00:1A2C$87敵データ12 使用技2 技ID(パンチャマキック)
$00:1A2D$88敵データ13 使用技3 技ID(スパイラル・ニー)
$00:1A2E$5E敵データ14 使用技4 技ID(ローキック)

まず、ナムキャットが「スパイラル・ニー」を出すまで(画面上ウィンドウに「スパイラル・ニー」と表示されている最中)の処理で、重要な部分を抜粋する。

$C1/8F28 BEQ $1F    [$8F49]      ;ゼロフラグが立っているとき[$8F49]分岐
$C1/8F2A LDA $002B,y[$00:1A2D]   ;Aに[$00:1A2D](敵データ13 使用技3 技ID(スパイラル・ニー))をロード
$C1/8F2D JSR $E251  [$C1:E251]   ;[$C1:E251]へ
;
$C1/E251 LDA $002B,y[$00:1A2D]   ;Aに[$00:1A2D]をロード
$C1/E254 STA $7E9100,x[$7E:AC00] ;Aを[$7E:AC00]に書き込み
$C1/E258 JSR $3D5C  [$C1:3D5C]   ;[$C1:3D5C]へ
;(中略)
$C1/D13B LDX $78    [$00:0378]   ;Xに[$00:0378]をロード
$C1/D13D LDA $7E9100,x[$7E:AC00] ;Aに[$7E:AC00]をロード
$C1/D141 STA $6A    [$00:036A]   ;Aを[$00:036A]に書き込み
$C1/D143 JSR $3D5C  [$C1:3D5C]   ;[$C1:3D5C]へ
;(中略)

ナムキャットの敵データ13、つまり使用技「スパイラル・ニー」の技IDが入っている[$00:1A2D]は、まず[$7E:AC00]に書き込まれる。
更に、[$7E:AC00]から[$00:036A]にコピーされる。

$C1/0CF2 LDA $0A00  [$00:0A00]   ;Aに[$00:0A00](シナリオID)をロード
$C1/0CF5 CMP #$05                ;Aと$05を減算比較(ステータスレジスタ変更のみ)
$C1/0CF7 BEQ $1E    [$0D17]      ;ゼロフラグが立っているとき[$0D17]分岐
$C1/0D17 LDX #$0000              ;Xに$0000をロード
;
;[$7E:9200]~に敵が使用した技IDを書き込むループ処理
$C1/0D1A LDA $7E9200,x           ;Aに[$7E:9200+x]をロード
$C1/0D1E BEQ $0B    [$0D2B]      ;ゼロフラグが立っているとき[$0D2B]分岐
$C1/0D20 CMP $6A    [$00:036A]   ;Aと[$00:036A](技ID)を減算比較(ステータスレジスタ変更のみ)
$C1/0D22 BEQ $06    [$0D2A]      ;ゼロフラグが立っているとき[$0D2A]分岐
$C1/0D24 INX                     ;Xをインクリメント +1
$C1/0D25 CPX #$00FF              ;Xと$00FFを減算比較(ステータスレジスタ変更のみ)
$C1/0D28 BCC $F0    [$0D1A]      ;キャリーフラグが立っていないとき[$0D1A]分岐
;ループ処理ここまで
$C1/0D2A RTS                     ;サブルーチン戻り
;
$C1/0D2B LDA $6A    [$00:036A]   ;Aに[$00:036A]をロード
$C1/0D2D STA $7E9200,x           ;Aを[$7E:9200+x]に書き込み
$C1/0D31 LDA #$00                ;Aに$00をロード
$C1/0D33 STA $7E9201,x           ;Aを[$7E:9201+x]に書き込み
$C1/0D37 RTS                     ;サブルーチン戻り

$C1/0CF2で、[$00:0A00]をロードしているが、[$00:0A00]に入っているのは現在プレイ中のシナリオIDであり、現代編の場合、[$00:0A00]には$05が入っている。
$C1/0CF5$05と減算比較し、$C1/0CF7でゼロフラグ判定をしている。
ゼロフラグが立つのは[$00:0A00]$05、つまり現代編のみなので、この先の処理は$C1/0D37まで現代編専用である。
(実際には$C1/0CF7の後に幕末編判定が続き、一部処理が共通するので、厳密には現代編『専用』ではないのだが、そのあたりは次ページで説明する)

X$0000をロードした後は、Aにロードした[$7E:9200]~に敵が使用した技IDを書き込むためのループ処理に入る。
[$7E:9200]の初期値は$00である。
よって、それまでに敵が一度も技を使っていないのなら、$C1/0D1Eでゼロフラグが立つから、ループを抜けて$C1/0D2Bにジャンプする。
つまり、敵の最初の攻撃時はループが発生せず、$C1/0D2B$C1/0D2Dで、使用技IDが入っている[$00:036A][$7E:9200]に書き込まれる。
更に、書き込まれたアドレス[$7E:9200]+1した[$7E:9201]には$00が書き込まれて処理終了である。

つまり、[$7E:9200]には「使用技のID」、[$7E:9201]$00が入った。
既にこの状態で同じループ処理を行った場合は、ループに入った$C1/0D1Eでゼロフラグが立たないから、$C1/0D20に進む。
$C1/0D20は、既に技IDが入っている[$7E:9200]と、新たに敵が使用した技IDの減算比較だから、「新たに敵が使用した技は、既に使用している技と同じ技かどうか」の確認である。
同じ技なら$C1/0D22でゼロフラグが立ち、$C1/0D2Aにジャンプして、何もせずループを抜ける。つまり、「既に使用していた技は、もう一度書き込まれない」ことがわかる。
異なる技なら$C1/0D22でゼロフラグが立って、X+1してから、X$00FFを減算比較する。
Xはループ回数が入ることになるから、X - $00FFでキャリーフラグが立たないのはX$00FF以下、つまりループ回数が$01$FFの間の時である。
この時はループの頭の$C1/0D1Aに戻り、00の入ったアドレスにたどりつくまで、ループを繰り返すことになる。

一方、ループ回数が$FFを越えていたら$C1/0D2Aにジャンプして、何もせずループを抜ける。
だが、ループ回数が$FFを越えるということは、既に敵が異なる種類の技を$FF種類使用して$7E:9200$7E:92FFがすべて技IDで埋まっていることを意味する。
本作では、一度の戦闘で、異なる種類の敵は最大4種まで出現できるように設定されている。そして敵が使う技の種類も最大4種である。敵4種がそれぞれ全く異なる技を使うとしても、敵が使用してくる技の種類は、4×4 = 16種が最大のはずである。
$7E:9200~で必要となる枠は、実際には$7E:9200$7E:9210あたりまでで充分であり、$7E:92FFまで埋まることはまずない。
このため、$C1/0D25でキャリーフラグが立つことはないはずである。

何にしても、以上の処理で、$7E:9200~には、敵が使った技IDが順に入っていき(重複はしない)、かつ最後に書き込まれたアドレス+1のアドレスに$00が書き込まれることがわかる。
そしてこの処理は現代編(と、幕末編)でしか行われない。
ここまでが技名表示あたりまでのサブルーチン処理にあたる。

以降、$7E:9200に「スパイラル・ニー」の技IDである$88$7E:9201$00が入っている前提で説明する。

続いて、「スパイラル・ニー」を高原がくらってダメージ表示が出た後の処理が以下のとおり。

$C1/71AC LDA $0A00  [$00:0A00]   ;Aに[$00:0A00](シナリオID)をロード
$C1/71AF CMP #$05                ;Aと$05を減算比較(ステータスレジスタ変更のみ)
$C1/71B1 BNE $1D    [$71D0]      ;ゼロフラグが立っていないとき[$71D0]分岐
$C1/71B3 LDX #$1C00              ;Xに$1C00をロード
$C1/71B6 LDA $0039,x[$00:1C39]   ;Aに[$00:1C39](味方キャラデータ 状態異常)をロード
$C1/71B9 BMI $15    [$71D0]      ;ネガティブフラグが立っているとき[$71D0]分岐
$C1/71BB LDX $78    [$00:0378]   ;Xに[$00:0378]をロード
$C1/71BD PHX                     ;Xをスタックにプッシュ
$C1/71BE LDA $6A    [$00:036A]   ;Aに[$00:036A]をロード
$C1/71C0 PHA                     ;Aをスタックにプッシュ
$C1/71C1 JSR $156D  [$C1:156D]   ;[$C1:156D]へジャンプ

$C1/71ACで、再びシナリオIDを確認するため[$00:0A00]がロードされ、$05と減算比較しているから、現代編であるかどうかの確認であり、$C1/71C1まで現代編用処理になる。
[$00:1C39]でロードされたのは、高原の現在の状態異常の値になる。
状態異常の値は8ビットで、上から順に石化・酔い・眠り・マヒ・毒・腕かため・足かため・首かために対応しているから、$C1/71B9でネガティブフラグが立つのは一番上の位が1の時、つまり石化状態がONになっている時か、すべてに1が入っている戦闘不能状態にあたり、この時は処理から外れる。
ただ、現代編において敵の中に石化の追加効果を持つ敵がいないから、実質、戦闘不能かどうかの判定になる。
戦闘不能であればラーニング処理は当然行われない。
その後は、使用技IDが入っている[$00:036A]Aに読み込まれて[$C1:156D]へジャンプする。

$C1/156D LDA $0A00  [$00:0A00]   ;Aに[$00:0A00](シナリオID)をロード
$C1/1570 CMP #$05                ;Aと$05を減算比較(ステータスレジスタ変更のみ)
$C1/1572 BEQ $04    [$1578]      ;ゼロフラグが立っているとき[$1578]分岐
$C1/1578 JSR $157C  [$C1:157C]   ;[$C1:157C]へジャンプ
;
$C1/157C LDX #$1A00              ;Xに$1A00をロード
$C1/157F JSR $1595  [$C1:1595]   ;[$C1:1595]へジャンプ
;
$C1/1595 LDA $0001,x[$00:1A01]   ;Aに[$00:1A01]をロード
$C1/1598 BEQ $08    [$15A2]      ;ゼロフラグが立っているとき[$15A2]分岐
$C1/159A LDA $0029,x[$00:1A29]   ;Aに[$00:1A29]をロード
$C1/159D BEQ $03    [$15A2]      ;ゼロフラグが立っているとき[$15A2]分岐
$C1/159F JSR $15A3  [$C1:15A3]   ;[$C1:15A3]へジャンプ

$C1/156DでもシナリオIDを確認しており、この先の処理も現代編専用になる……と思いきや、実際には幕末編の戦闘終了後もここに飛ぶようになっている。

$C1/159A[$00:1A29]は、敵種類1の敵データ09にあたる。
ここには上1ビットに使用技IDを敵一覧から取るか、味方一覧から取るかの値が入り、下7ビットはレベルが入る。
現代編においてこの値に$00が入っていることはないはずであり、ゼロフラグが立つこともないはずである。

$C1/15A3 LDY #$030C              ;Yに$030Cをロード
;
;対戦相手の使用技1~4を[$00:030C]~に書き込むループ処理
$C1/15A6 LDA $002B,x[$00:1A2B]   ;Aに[$00:1A2B+x]をロード(敵データ11~敵データ14)
$C1/15A9 INX                     ;Xをインクリメント +1
$C1/15AA STA $0000,y[$00:030C]   ;Aを[$00:030C+n]に書き込み
$C1/15AD INY                     ;Yをインクリメント +1
$C1/15AE CPY #$0310              ;Yと$0310を減算比較(ステータスレジスタのみ変更)
$C1/15B1 BNE $F3    [$15A6]      ;ゼロフラグが立っていないとき[$15A6]分岐
;ループここまで
;
$C1/15B3 JSR $0D38  [$C1:0D38]  ;[$C1:0D38]へジャンプ

上は、敵データ11~敵データ14、つまり対戦相手の使用技1~4の技IDを、順に[$00:030C][$00:030D][$00:030E][$00:030F]に書き込むループ処理である。
つまり、以下のように値が入ったことになる。

アドレス数値内容
[$00:030C]$79敵データ11 技1 イナズマアッパー
[$00:030D]$87敵データ12 技2 パンチャマキック
[$00:030E]$88敵データ13 技3 スパイラル・ニー
[$00:030F]$5E敵データ14 技4 ローキック
$C1/0D38 LDY #$030C              ;Yに$030Cをロード
;
;[$7E:9200]とナムキャットの使用技の確認ループ処理(1回目)
$C1/0D3B LDX #$0000              ;Xに$0000をロード
$C1/0D3E LDA $7E9200,x[$7E:9200] ;Aに[$7E:9200]をロード
$C1/0D42 BEQ $0B    [$0D4F]      ;ゼロフラグが立っているとき[$0D4F]分岐
$C1/0D44 CMP $0000,y[$00:030C]   ;Aと[$00:030C]を減算比較(ステータスレジスタ変更のみ)
$C1/0D47 BEQ $0B    [$0D54]      ;ゼロフラグが立っているとき[$0D54]分岐
$C1/0D49 INX                     ;Xをインクリメント +1
$C1/0D4A CPX #$00FF              ;Xと$00FFを減算比較(ステータスレジスタ変更のみ)
$C1/0D4D BCC $EF    [$0D3E]      ;キャリーフラグが立っていないとき[$0D3E]分岐
$C1/0D3E LDA $7E9200,x[$7E:9201] ;Aに[$7E:9201]をロード
$C1/0D42 BEQ $0B    [$0D4F]      ;ゼロフラグが立っているとき[$0D4F]分岐
$C1/0D4F LDA #$00                ;Aに$00をロード
$C1/0D51 STA $0000,y[$00:030C]   ;Aを[$00:030C]に書き込み =$00
$C1/0D54 INY                     ;Yをインクリメント +1
$C1/0D55 CPY #$0310              ;Yと$0310を減算比較(ステータスレジスタのみ変更)
$C1/0D58 BNE $E1    [$0D3B]      ;ゼロフラグが立っていないとき[$0D3B]分岐
;ループここまで

次のループ処理は少々ややこしいように見えるのだが、実際には、

[$00:030C][$00:030F]にコピーしたナムキャットの技4種類と、ナムキャットが使った技ID[$7E:9200]が一致するか確認し、一致しないなら[$00:030?]$00を上書きし、一致するならそのままとする。

という処理にあたる。
なお、既にナムキャットが2種類以上の技を使っていて、[$7E:9201]以降に00以外の値が入っている時は、[$7E:9201]以降の処理も一緒に行うので更にややこしくなるが、とりあえず今回は[$7E:9201]$00が入っている前提にしておく。

上はループ1回目を抜粋したもので、[$00:030C]、つまり技1「イナズマアッパー」についての確認である。
[$7E:9200]に入っているのは「スパイラル・ニー」の技ID$88だから、「イナズマアッパー」の技ID$79とは一致しない。
その場合、$C1/0D4F$C1/0D51の処理で、[$00:030C]$00が上書きされてしまう。

よってこのループで$00を上書きされないのは、ループ3回目の「スパイラル・ニー」の確認のみである。
実際は下のようになる。

;ループ処理(3回目)
$C1/0D3B LDX #$0000              ;Xに$0000をロード
$C1/0D3E LDA $7E9200,x[$7E:9200] ;Aに[$7E:9200]をロード
$C1/0D42 BEQ $0B    [$0D4F]      ;ゼロフラグが立っているとき[$0D4F]分岐
$C1/0D44 CMP $0000,y[$00:030E]   ;Aと[$00:030E]を減算比較(ステータスレジスタ変更のみ)
$C1/0D47 BEQ $0B    [$0D54]      ;ゼロフラグが立っているとき[$0D54]分岐
$C1/0D54 INY                     ;Yをインクリメント +1
$C1/0D55 CPY #$0310              ;Yと$0310を減算比較(ステータスレジスタのみ変更)
$C1/0D58 BNE $E1    [$0D3B]      ;ゼロフラグが立っていないとき[$0D3B]分岐
;ループここまで
;(中略)
$C1/0D5A RTS                     ;サブルーチン戻り

「スパイラル・ニー」のIDが入った[$00:030E]のみ、何の処理もされずにループが終わる。
[$00:030F]まで同じ処理が入るとループ処理終了である。

以上の処理で、以下のように値が変更された。
つまり使用した技のIDだけが残ったことになる。

アドレス数値内容
[$00:030C]$00 
[$00:030D]$00 
[$00:030E]$88敵データ13 技3 スパイラル・ニー
[$00:030F]$00 
$C1/15B6 LDY #$030C              ;Yに$030Cをロード
$C1/15B9 STY $60    [$00:0360]   ;Yを[$00:0360]に書き込み
;
;[$00:030C]~ループ処理開始
$C1/15BB LDA $0000,y[$00:030C]   ;Aに[$00:030C+n]をロード
$C1/15BE BEQ $05    [$15C5]      ;ゼロフラグが立っているとき[$15C5]分岐
$C1/15C5 LDY $60    [$00:0360]   ;Yに[$00:0360]をロード
$C1/15C7 INY                     ;Yをインクリメント +1
$C1/15C8 STY $60    [$00:0360]   ;Yを[$00:0360]に書き込み
$C1/15CA CPY #$0310              ;Yと$0310を減算比較(ステータスレジスタのみ変更)
$C1/15CD BNE $EC    [$15BB]      ;ゼロフラグが立っていないとき[$15BB]分岐
;ループここまで
;
$C1/15C0 STA $6A    [$00:036A]   ;Aを[$00:036A]に書き込み
$C1/15C2 JSR $15D0  [$C1:15D0]   ;[$C1:15D0]へ

このループ処理は、[$00:030C][$00:030F]の中で00以外の値が入っているアドレスを検索し、その値を[$00:036A]に書き込む、という作業になる。
[$00:030E]のスパイラル・ニー以外は00が入っているから、[$00:030E]に入っている技ID$88が、[$00:036A]に書き込まれて、[$C1:15D0]にジャンプする。

$C1/15D0 STZ $84    [$00:0384]   ;[$00:0384] = $00
$C1/15D2 LDX #$1C00              ;Xに$1C00をロード
$C1/15D5 JSR $15E5  [$C1:15E5]   ;[$C1:15E5]へ
;
$C1/15E5 LDA $0001,x[$00:1C01]   ;Aに[$00:1C01]をロード(味方キャラ1・戦闘状態 $FF:通常)
$C1/15E8 CMP #$FF                ;Aと$FFを減算比較(ステータスレジスタ変更のみ)
$C1/15EA BEQ $01    [$15ED]      ;ゼロフラグが立っているとき[$1609]分岐
$C1/15ED STX $78    [$00:0378]   ;Xを[$00:0378]に書き込み
$C1/15EF LDY $0002,x[$00:1C02]   ;Yに[$00:1C02]をロード
$C1/15F2 LDX $0004,y[$00:0E44]   ;Xに[$00:0E44]をロード
$C1/15F5 STZ $08    [$00:0308]   ;[$00:0308]に$00を書き込み
;
;高原の技一覧に[$00:036A]と同値があるか確認ループ処理
$C1/15F7 LDA $D50005,x[$D5:0395] ;Aに[$D5:0395+n]をロード
$C1/15FB INX                     ;Xをインクリメント +1
$C1/15FC CMP $6A    [$00:036A]   ;Aと[$00:036A]を減算比較(ステータスレジスタ変更のみ)
$C1/15FE BEQ $09    [$1609]      ;ゼロフラグが立っているとき[$1609]分岐
$C1/1600 INC $08    [$00:0308]   ;[$00:0308]をインクリメント +1
$C1/1602 LDA $08    [$00:0308]   ;Aに[$00:0308]をロード
$C1/1604 CMP #$10                ;Aと$10を減算比較(ステータスレジスタ変更のみ)
$C1/1606 BNE $EF    [$15F7]      ;ゼロフラグが立っていないとき[$15F7]分岐
;ループここまで

ここまではナムキャット側の確認・処理が続いたが、ここからは高原日勝側の確認・処理になる。
$C1/15E5$C1/15E8で、高原の味方キャラデータ01の戦闘状態を確認している。味方キャラは通常$FFが入り、戦闘離脱など特殊な状況下は別の値が入るので、$FFかどうかの確認である。
ループ処理は、[$D5:0395][$D5:03A5]の値を取得することから開始になっているが、これは$D5:00C0$D5:04CAに入っている、味方キャラデータの中の値である。
[$D5:0395][$D5:03A5]は、高原のキャラデータ05~20、技レベル00~レベル16の16種類の技IDにあたる。
要するに高原が習得可能な技一覧で、ここではまだ、高原が習得しているかどうかの判断はされない。
この値と、[$00:036A]に入った、ナムキャットが使用した技「スパイラル・ニー」の技IDを減算比較して、ゼロフラグが立つかどうかの確認のループである。
つまり、
「高原が習得可能な技一覧の中に、スパイラル・ニーがあるか」
をループ処理で調べていることになる。
ループ回数は、ループ前に$00を入れた[$00:0308]+1していき、最大で$10になるまで。
10進数の16にあたり、16種類の技すべてを調べることになる。

今回は、高原の技レベル08にあたる[$D5:039D]に「スパイラル・ニー」のID$88が入っている。
このため、ループ9回目で$C1/15FEでゼロフラグが立つことになり、ループを抜けて$C1/1609へジャンプする。
この時、ループ回数を記録した[$00:0308]$08になっている。
ループを抜ける前後の処理は以下のようになる。

$C1/15F7 LDA $D50005,x[$D5:039D] ;Aに[$D5:039D]をロード
$C1/15FB INX                     ;Xをインクリメント +1
$C1/15FC CMP $6A    [$00:036A]   ;Aと[$00:036A]を減算比較(ステータスレジスタ変更のみ)
$C1/15FE BEQ $09    [$1609]      ;ゼロフラグが立っているとき[$1609]分岐

$C1/1609 STZ $09    [$00:0309]   ;[$00:0309]に$00を書き込み
$C1/160B REP #$20                ;Aを16bit幅に変更、Mフラグをクリア
$C1/160D INC $08    [$00:0308]   ;[$00:0308]をインクリメント +1 ([$00:0308] = $09)
$C1/160F LDA #$0000              ;Aに$0000をロード

ループを抜けた後に、[$00:0308]+1されたので、この時点で[$00:0308] = $09である。
また、[$00:0309] = $00となる。
16bitモードに変更されたため、A = $0000である。
また、$C1/15FCの減算でキャリーフラグが立っており、$C1/160Fでもまだキャリーフラグが立った状態であることに注意。

;習得技処理ループ
$C1/1612 ROL A                   ;Aをキャリーフラグを含めた17bitで左ローテート
$C1/1613 DEC $08    [$00:0308]   ;[$00:0308]をデクリメント -1 ([$00:0308] = $08)
$C1/1615 BNE $FB    [$1612]      ;ゼロフラグが立っていないとき[$1612]分岐
;ループここまで

このループが少しわかりにくい。
ROL Aは、Aをキャリーフラグを含めて左ローテートするニーモニックである。
つまりAに入った値を2進数にし、かつその上にキャリーフラグの値を載せて、左へ1桁ずつ値をずらして回していく処理である。
Aには16ビットの$0000が入っているから、2進数にすると、

0000 0000 0000 0000

であり、キャリーフラグが立った状態なので、一番左にキャリーフラグ分の「1」を付けて、

1 0000 0000 0000 0000

この値を左へ回す。すると、キャリーフラグの「1」は、これ以上左の桁がないから、一番右の桁へ移動する。

0000 0000 0000 0001

これが新たなAの値となる。
そして、[$00:0308]-1し、ゼロフラグが立つまで左ローテートのループを繰り返すことになる。
なお、[$00:0308]をデクリメントした時点でキャリーフラグがクリアされるため、これ以降の左ローテートでは、キャリーフラグ分の値として0が入る。

[$00:0308]にはループ前に$09が入った。よって、$09回、ループ処理を行うことになる。
すると、結局Aの値はどうなるのか。
1回目のループで、16ビットの一番下の値に1が入り、残り8回、この「1」が左にずれ続けることになる。
すると、

0000 0001 0000 0000

ここまで「1」が移動した。
右から順番に、高原の技の技レベル00、技レベル01、……、技レベル13、技レベル14、技レベル16に対応していて、今回ナムキャットから受けた「スパイラル・ニー」の位置、技レベル08にだけ「1」が立ったことになる。
つまり、各ビットは、高原が習得している技の値が入っている、アドレス[$00:0E4E][$00:0E4D]に対応していることになり、新たにラーニングした技の位置にだけ「1」が立っている。
この値を算出するための左ローテートなのである。

では、左ローテート$09回を終えて、ループ処理を抜けた後を見てみる。
Aには%0000 0001 0000 0000 = $0100が入っている。

$C1/1617 STA $12    [$00:0312]   ;A($0100)を[$00:0313][$00:0312]に書き込み
$C1/1619 LDX $78    [$00:0378]   ;Xに[$00:0379][$00:0378]をロード
$C1/161B LDY $0002,x[$00:1C02]   ;Yに[$00:1C03][$00:1C02]をロード
$C1/161E LDA $000D,y[$00:0E4D]   ;Aに[$00:0E4E][$00:0E4D]をロード(高原の習得技2バイト)
$C1/1621 BIT $12    [$00:0312]   ;Aと[$00:0313][$00:0312]で論理積(ステータスフラグフラグ変更のみ)
$C1/1623 BNE $20    [$1645]      ;ゼロフラグが立っていないとき[$1645]分岐
$C1/1625 ORA $12    [$00:0312]   ;Aと[$00:0313][$00:0312]で論理和
$C1/1627 STA $000D,y[$00:0E4D]   ;Aを[$00:0E4E][$00:0E4D]に書き込み(高原の習得技2バイト)
$C1/162A SEP #$20                ;MフラグON Aレジスタは8bit幅
$C1/162C LDA $84    [$00:0384]   ;Aに[$00:0384]をロード
$C1/162E BNE $15    [$1645]      ;ゼロフラグが立っていないとき[$1645]分岐
$C1/1630 JSR $2787  [$C1:2787]   ;[$C1:2787]へ

計算したAの値$0100は、$C1/1617で、[$00:0313][$00:0312]に分けて書き込まれる。
[$00:0313] = $01, [$00:0312] = $00である。
その後、$C1/161Eで、高原が習得した技の値が入る[$00:0E4E][$00:0E4D]Aにロードされる。
ナムキャット戦開始の時点で、初期技3種しか覚えていない状態だから、[$00:0E4E] = $00, [$00:0E4D] = $07となっている。
[$00:0E4D] = $07 = %0000 0111であり、下3ビット分だけ1が入っている。

まず、$C1/1621で、[$00:0E4E][$00:0E4D](=$0007)と[$00:0313][$00:0312](=$0100)で論理積を取る。
もし、高原が「スパイラル・ニー」を習得済みなら、論理積を取った時、「スパイラル・ニー」にあたる、上から8ビット目の値が一致して、論理積が$0100になるはずである。
だが、習得済みでなければ、論理積は$0000である。
ゼロフラグが立つなら処理が進むことから、ここで判定しているのは、「ナムキャットから食らったラーニング可能な技を、高原は既に習得しているかどうか」であり、習得していないのなら処理が進む。

$C1/1625で、A[$00:0E4E][$00:0E4D])と[$00:0313][$00:0312]の論理和を取る。
これは実質加算するのと同じであり、ここで、A$0007 + $0100 = $0107が入る。
$C1/1627で加算した値$0107が、高原の習得技アドレス[$00:0E4E][$00:0E4D]に書き込まれる。
つまり[$00:0E4E] = $01, [$00:0E4D] = $07となり、「高原日勝の習得技にスパイラル・ニーが加わった」ことになる。

以上が、現代編におけるラーニングの仕組みである。
技を受けた直後に上の処理が入るため、高原はラーニング可能な技をくらうとすぐに該当の技を習得できることになる。

次ページでは、幕末編におけるラーニングの処理を見てみることにしよう。



このページをシェアする

上へ