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

ラーニング(幕末編)

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

ラーニング・幕末編のサブルーチン

前ページの現代編のラーニングに続き、このページでは幕末編のラーニングの処理について説明する。
現代編の処理と共通点も多いため、まずは前ページに目を通していただきたい。

現代編のラーニングと、幕末編のラーニングの大きな違いは、技習得のタイミングである。
幕末編はラーニングできる技をくらった後、戦闘終了時に技習得の処理が入る。
それ以外は共通のサブルーチンが使われている箇所もある。

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

上は、$C1/8F2Aにて、敵データ11~敵データ14のいずれか(敵の使用技ID)をロードして、$C1/E254[$7E:ACx0]に書き込む処理である。
現代編だと、敵は1体、つまり1種類なので、敵の使用技IDをロード後、その値は[$7E:AC00]に書き込まれていた。
だが、幕末編だと敵は複数で登場することがあり、書き込み先の[$7E9100,x]は、敵番号をxとした時、[$7E:ACx0]に書き込まれる。
例えば、カラクリ丸がラーニング可能な技を多く使う五忍者戦は、五忍者(本体)が敵番号0で、五忍者(分身)4体は敵番号1~4である。
五忍者(分身)の中の敵番号2から攻撃されたのなら、[$7E:AC20]に技IDが書き込まれることになる。
技IDの値が[$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/0CF9 CMP #$07                ;Aと$07を減算比較(ステータスレジスタ変更のみ)
$C1/0CFB BNE $0F    [$0D0C]      ;ゼロフラグが立っているとき[$0D0C]分岐
;
;幕末編用処理
$C1/0CFD LDX $78    [$00:0378]   ;Xに[$00:0378]をロード
$C1/0CFF CPX #$1C00              ;Xと$1C00を減算比較(ステータスレジスタ変更のみ)
$C1/0D02 BCS $08    [$0D0C]      ;キャリーフラグが立っているとき[$0D0C]分岐
$C1/0D04 LDY $0002,x             ;Yに[$0002,x]をロード(敵番号Xの呼び出し先アドレス[$00:1Bx2])
$C1/0D07 LDA $0029,y             ;Aに[$0029,y]をロード(敵種族yの敵データ09)
$C1/0D0A BMI $0B    [$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$C1/0CF7のシナリオID判定で[$0D17]にジャンプするのだが、その直後にシナリオIDが$07かどうかを判定している。
シナリオIDが$07だと幕末編だから、$C1/0CFBでゼロフラグが立たずに、$C1/0CFDに進む。
$C1/0CFD$C1/0D0Aが幕末編用の処理で、$C1/0D17から現代編の[$7E:9200]~に敵が使用した技IDを書き込むループ処理に合流している。
$C1/0CFD$C1/0D0Aは、攻撃してきた敵の敵データ09を呼び出すためのアドレス計算と、敵データ09にネガティブフラグが立っているかどうかの判定である。
敵データ09の上1ビットが1の時、技IDは味方技IDとして判断する。つまり、ネガティブフラグが立つ時は、該当の敵は使用技に味方技IDを使っている。
敵が使用してきた技が味方技IDでなければ、ラーニング自体ができないので、ここで判定していることになる。
現代編だと、対戦相手6キャラはすべて味方技IDの技しか使わないので、敵データ09の上1ビットを判定する必要がない。
幕末編の場合、「敵が味方技IDの技を使う場合だけ、ラーニング関係の処理をする」という分岐がここで入っていることがわかる。

$C1/0D17$C1/0D37の処理は、現代編と同じなので、説明は割愛。
ここで、$7E:9200~には、敵が使った技IDが順に入っていき(重複はしない)、かつ最後に書き込まれたアドレス+1のアドレスに$00が書き込まれる。
技名表示あたりまでのサブルーチン処理は以上になる。

現代編の場合は、敵が技を出し、高原がくらった直後にラーニングの処理が入るが、幕末編では入らない。
幕末編の場合は、戦闘勝利後、経験値計算・レベルアップ判定などの後に、ラーニング関係の処理が入る。

$C1/0186 JSR $156D  [$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/1574 CMP #$07                ;Aと$07を減算比較(ステータスレジスタ変更のみ)
$C1/1576 BNE $03    [$157B]      ;ゼロフラグが立っていないとき[$157B]分岐
$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]は、現代編で技を食らった後の処理のジャンプ地点と同じなのである。
現代編だと、$C1/1570でゼロフラグが立って$C1/1578に飛ぶが、幕末編だと$C1/1574でゼロフラグが立って$C1/1578に進む。
要するに、現代編・幕末編共通処理に繋がるのである。

この先は基本的に現代編と処理は共通なのだが、敵の種類が2種類以上の場合があることと、味方側もおぼろ丸とカラクリ丸のふたりがラーニングの可能性があるという点が異なる。

[$00:030C][$00:030F]にコピーした敵種類1の技4種類と、[$7E:9200]以降に入った技IDが一致するか確認し、一致しないなら[$00:030?]$00を上書きし、一致するならそのままとする。

という処理自体は同じだが、現代編だと対戦相手が技を一回出す度に判定をするので、一度の判定でラーニングできる技は1種類だけである。
だが、幕末編では、戦闘終了後にまとめて処理をするから、[$7E:9200]以降に入っている値と、敵の技4種類の技IDの中で、複数の技が一致する可能性がある。

ひとまず敵種類1の処理が済んだら、今度は味方側の処理である。
現代編は、高原の技一覧の技IDの中に、くらった技IDが書き込まれた[$00:036A]があるかどうかを調べれば良いのだが、幕末編の場合、ラーニングができるおぼろ丸とカラクリ丸について調べなければならない。
……と思いきや、実は、パーティメンバーが最大の3キャラ、つまりとらわれの男とカラクリ丸がいる状態だと、3キャラ全てで判定を行うのである。
以下がその処理で、ここでは例として、五忍者(本体)から「切り下ろし」をくらった場合について紹介する。
味方キャラ番号1がおぼろ丸、味方キャラデータは$7E:1C00~。
味方キャラ番号2はとらわれの男、味方キャラデータは$7E:1C40~。
味方キャラ番号3はカラクリ丸、味方キャラデータは$7E:1C80~になる。
「切り下ろし」をラーニング可能なのはカラクリ丸だけである。技IDは$73

$C1/15D0 STZ $84    [$00:0384]   ;[$00:0384] = $00
$C1/15D2 LDX #$1C00              ;Xに$1C00をロード
$C1/15D5 JSR $15E5  [$C1:15E5]   ;[$C1:15E5]へ
;
;味方キャラ番号1・おぼろ丸
$C1/15E5 LDA $0001,x[$00:1C01]   ;Aに[$00:1C01]をロード(味方キャラ1・戦闘状態 $FF:通常)
$C1/15E8 CMP #$FF                ;Aと$FFを減算比較(ステータスレジスタ変更のみ)
$C1/15EA BEQ $01    [$15ED]      ;ゼロフラグが立っているとき[$15ED]分岐
$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:0EC4]   ;Xに[$00:0E44]をロード
$C1/15F5 STZ $08    [$00:0308]   ;[$00:0308]に$00を書き込み
;
;おぼろ丸の技一覧に[$00:036A]と同値があるか確認ループ処理
$C1/15F7 LDA $D50005,x[$D5:033B] ;Aに[$D5:033B+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/1608 RTS                     ;サブルーチン戻り
;
$C1/15D8 LDX #$1C40              ;Xに$1C40をロード
$C1/15DB JSR $15E5  [$C1:15E5]   ;[$C1:15E5]へジャンプ
;
;味方キャラ番号2・とらわれの男
$C1/15E5 LDA $0001,x[$00:1C41]   ;Aに[$00:1C41]をロード(味方キャラ2・戦闘状態 $FF:通常)
$C1/15E8 CMP #$FF                ;Aと$FFを減算比較(ステータスレジスタ変更のみ)
$C1/15EA BEQ $01    [$15ED]      ;ゼロフラグが立っているとき[$15ED]分岐
$C1/15ED STX $78    [$00:0378]   ;Xを[$00:0378]に書き込み
$C1/15EF LDY $0002,x[$00:1C42]   ;Yに[$00:1C42]をロード
$C1/15F2 LDX $0004,y[$00:0F04]   ;Xに[$00:0E44]をロード
$C1/15F5 STZ $08    [$00:0308]   ;[$00:0308]に$00を書き込み
;
;とらわれの男の技一覧に[$00:036A]と同値があるか確認ループ処理
;(技を3種類しか所持していないので、
; 4回目以降のループ時、とらわれの男の技IDは00が入っている)
$C1/15F7 LDA $D50005,x[$D5:0368] ;Aに[$D5:0368+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/1608 RTS                     ;サブルーチン戻り
;
$C1/15DE LDX #$1C80              ;Xに$1C80をロード
$C1/15E1 JSR $15E5  [$C1:15E5]   ;[$C1:15E5]へジャンプ
;
;味方キャラ番号3・カラクリ丸
$C1/15E5 LDA $0001,x[$00:1C81]   ;Aに[$00:1C81]をロード(味方キャラ3・戦闘状態 $FF:通常)
$C1/15E8 CMP #$FF                ;Aと$FFを減算比較(ステータスレジスタ変更のみ)
$C1/15EA BEQ $01    [$15ED]      ;ゼロフラグが立っているとき[$15ED]分岐
$C1/15ED STX $78    [$00:0378]   ;Xを[$00:0378]に書き込み
$C1/15EF LDY $0002,x[$00:1C82]   ;Yに[$00:1C82]をロード
$C1/15F2 LDX $0004,y[$00:0F44]   ;Xに[$00:0E44]をロード
$C1/15F5 STZ $08    [$00:0308]   ;[$00:0308]に$00を書き込み
;
;カラクリ丸の技一覧に[$00:036A]と同値があるか確認ループ処理
$C1/15F7 LDA $D50005,x[$D5:04A3] ;Aに[$D5:04A3+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]分岐
;ループここまで

;カラクリ丸 ループ7回目 技レベル06「切り下ろし」技IDは$73
$C1/15F7 LDA $D50005,x[$D5:04A9] ;Aに[$D5:04A3+n]をロード
$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を書き込み

上の通り、おぼろ丸・とらわれの男・カラクリ丸と順に判定をしていることがわかる。
ただし、とらわれの男の使用技の中に、敵が使ってくる技はない上、とらわれの男はパーティ加入時点で習得可能な技をすべて覚えているため、何かの技をラーニングすることは決してない。
「とらわれの男は判定しない」という例外分岐をわざわざ作るよりは、全キャラ判定させてしまう方が処理上複雑にならない、というような判断なのかもしれない。

さて、上の処理では、カラクリ丸の技一覧に「切り下ろし」があるから、カラクリ丸の判定のループ7回目でループ処理を抜け、現代編と同じ処理が続く。

$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] = $07)
$C1/160F LDA #$0000              ;Aに$0000をロード
;
;習得技処理ループ
$C1/1612 ROL A                   ;Aをキャリーフラグを含めた17bitで左ローテート
$C1/1613 DEC $08    [$00:0308]   ;[$00:0308]をデクリメント -1 ([$00:0308] = $06~$00)
$C1/1615 BNE $FB    [$1612]      ;ゼロフラグが立っていないとき[$1612]分岐
;ループここまで
;
;左ローテートの結果、Aは$0040 (=%0000 0000 0100 0000)
$C1/1617 STA $12    [$00:0312]   ;A($0040)を[$00:0313][$00:0312]に書き込み
$C1/1619 LDX $78    [$00:0378]   ;Xに[$00:0379][$00:0378]をロード
$C1/161B LDY $0002,x[$00:1C82]   ;Yに[$00:1C03][$00:1C02]をロード
$C1/161E LDA $000D,y[$00:0F4D]   ;Aに[$00:0F4E][$00:0F4D]をロード(カラクリ丸の習得技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:0F4D]   ;Aを[$00:0F4E][$00:0F4D]に書き込み(カラクリ丸の習得技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]へ

$C1/1621の論理積で、カラクリ丸が「切り下ろし」を覚えていないと判定された場合は、上のように$C1/1625で、カラクリ丸の習得技2バイト[$00:0F4E][$00:0F4D]と、「切り下ろし」の$0040で論理和をとり、[$00:0F4E][$00:0F4D]にセットすることで、「切り下ろし」の習得が完了である。

以上でようやく五忍者(本体)の1つ目の技「切り下ろし」の処理終了である。
五忍者(本体)は、「尾出流手裏剣術」「大激怒岩バン割り」も使うため、これらの技が[$7E:9200]~に入っている場合、つまり[$00:030C][$00:030F]00以外が入っている時はまたしても延々と判定を繰り返す。
そして、五忍者戦では、五忍者(本体)と五忍者(分身)の2種類の敵が出現するため、次は五忍者(分身)でも同じ処理を繰り返すことになる。
ただし、五忍者(本体)と五忍者(分身)では使用技がほぼ被っている。
異なるのは「火トンの術」だけだが、習得レベルの関係で、おぼろ丸・カラクリ丸ともに五忍者戦のラーニングで習得する可能性はかなり低い(カラクリ丸に至っては、初期レベルで五忍者戦に連れてきても、五忍者戦でレベルアップしてレベル3になり、ラーニングとは関係なく「火トンの術」を覚える)。
よって、五忍者(分身)分も処理自体は入るが、既に五忍者(本体)の判定でラーニングされている技ばかりで、上の$C1/1621$C1/1623の時点で処理が終了する可能性の方が高い。

本作のラーニングの仕組みは以上になる。
なお、功夫編の修行の仕組みもだいたい同じようなもの。
ただ、$7E:9200~に入るのは心山拳老師が使用した技で、習得判定は弟子のレベルアップ後になり、かつ、習得する技は技IDは一番小さい技を1種のみ、という判定になるというだけである。
また、現代編や幕末編は、どの戦闘でも$7E:9200~に技が入っていくが、功夫編は修行の戦闘のみ$7E:9200~に値が入る。
といった違いがある。



このページをシェアする

上へ