基礎知識
戦闘関係
ここでは、功夫編最終盤における、
について説明する。
シナリオ別キャラデータは、$00:0D00~$00:0FBFに入る、各シナリオのキャラ用データである。
各シナリオの主人公8キャラ+各シナリオの仲間キャラ最大3キャラ、合計11キャラのデータを保存している。
仲間キャラについては、3キャラ分の領域しかないので、各シナリオ内でのみ保存される。
$00:0DC0~$00:0DFFが功夫編主人公のデータ領域になるのだが、功夫編だと心山拳老師、最終編だと心山拳師範、つまり功夫編で伝承者に選んだ弟子のデータになる。
功夫編終盤からクリアまでのどこかのタイミングで、$00:0DC0~$00:0DFFに入っていた心山拳老師のデータが、弟子のデータに上書きされているはずである。
弟子3キャラは、功夫編において仲間キャラの扱いなので、シナリオ別キャラデータだと、
| ID | アドレス | キャラ |
|---|---|---|
| $08 | $00:0F00~$00:0F3F | ユン |
| $09 | $00:0F40~$00:0F7F | レイ |
| $0A | $00:0F80~$00:0FBF | サモ |
以上のようにデータが入っているが、これらのデータが$00:0DC0~$00:0DFFに上書きされる処理になるはずだ。
そのタイミングは、実は功夫編ラストバトル前である。
功夫編ラストバトル前の会話で、山頂にて老師が弟子に「旋牙連山拳」を見せるシーンの回想が入るが、この回想が終わる暗転のタイミングで$00:0DC0~$00:0DFFの領域が弟子のデータに上書きされ、そのままラストバトルに突入する。
シナリオ別キャラデータ以外の重要なアドレスは以下のとおり。
$00:0A11~$00:0A13は、各シナリオの仲間キャラのシナリオ別キャラデータIDが入っている。
| アドレス | 内容 |
|---|---|
$00:0A11 | 2人目のシナリオ別キャラデータID |
$00:0A12 | 3人目のシナリオ別キャラデータID |
$00:0A13 | 4人目のシナリオ別キャラデータID |
つまり、功夫編ラストバトル前は、$00:0A11に伝承者になる弟子のキャラIDが入っている。
| 弟子 | キャラID |
|---|---|
| ユン | $08 |
| レイ | $09 |
| サモ | $0A |
また、$00:0A15は、心山拳老師&師範が誰なのかの値が入り、初期値(功夫編開始時)は$00で、心山拳老師に該当する。
$00:0A15 | キャラ |
|---|---|
| $00 | 心山拳老師 |
| $01 | ユン |
| $02 | レイ |
| $03 | サモ |
回想終了のタイミングでデータが上書きされる処理は以下のようになっている。
$C0/24D3 LDA $0A11 [$00:0A11] ;Aに[$00:0A11]をロード $C0/24D6 SEC ;キャリーフラグON $C0/24D7 SBC #$07 ;A - $07 $C0/24D9 STA $0A15 [$00:0A15] ;Aを[$00:0A15]に書き込み
$C0/24D3~$C0/24D9でやっていることは、『「[$00:0A11] - $07」を[$00:0A15]に書き込む』である。
[$00:0A11]には伝承者になる弟子のキャラIDが入っているから、[$00:0A15]に書き込まれる[$00:0A11] - $07の解は以下の通り。
| 弟子 | キャラID | [$00:0A11] - $07 |
|---|---|---|
| ユン | $08 | $01 |
| レイ | $09 | $02 |
| サモ | $0A | $03 |
つまりここで、
$00:0A15 | キャラ |
|---|---|
| $00 | 心山拳老師 |
| $01 | ユン |
| $02 | レイ |
| $03 | サモ |
$00:0A15に、新たな値が計算されて書き込まれたことになる。
実質ここで功夫編主人公が交代になったとみなすこともできる。
続きはシナリオ別キャラデータの処理である。
上の処理で、Aには弟子に対応した$01~$03の値のいずれかが入っている。
$C0/24DC TAX ;Aの値をXレジスタに転送 $C0/24DD LDA $01B0,x[$00:01B2] ;Aに[$00:01B0+x]をロード x=1~3 $C0/24E0 STA $01B0 [$00:01B0] ;Aを[$00:01B0]に書き込み $C0/24E3 PHY ;Yをスタックへプッシュ $C0/24E4 LDA $0A15 [$00:0A15] ;Aに[$00:0A15]($01~$03)をロード $C0/24E7 DEC A ;Aをデクリメント -1 $C0/24E8 REP #$20 ;Aを16bit幅に変更、Mフラグをクリア $C0/24EA AND #$00FF ;Aと$00FFで論理積 $C0/24ED ASL A ;Aを算術左シフト *2 $C0/24EE ASL A ;Aを算術左シフト *2 $C0/24EF ASL A ;Aを算術左シフト *2 $C0/24F0 ASL A ;Aを算術左シフト *2 $C0/24F1 ASL A ;Aを算術左シフト *2 $C0/24F2 ASL A ;Aを算術左シフト *2 $C0/24F3 CLC ;キャリーフラグクリア $C0/24F4 ADC #$0F00 ;A + $0F00 $C0/24F7 TAX ;Aの値をXレジスタに転送 $C0/24F8 LDY #$0DC0 ;Yに$0DC0をロード $C0/24FB LDA #$0033 ;Aに$0033をロード
この先で、シナリオ別キャラデータを丸ごと転送するため、その前処理が上のサブルーチンで行われている。
弟子が誰なのかによって、元となるシナリオ別キャラデータのアドレスが変わるため、アドレスを計算している。
処理を見ると、([$00:0A15]-1)*40 + $0F00がXレジスタに転送されている。
([$00:0A15]-1)*40 + $0F00の計算値(Xに入った値)は以下の通り。
$00:0A15 | キャラ | X |
|---|---|---|
| $01 | ユン | $0F00 |
| $02 | レイ | $0F40 |
| $03 | サモ | $0F80 |
つまり、シナリオ別キャラデータの開始アドレスの値そのままである。例えばユンなら、上にバンク$00をつければ$00:0F00になる。
これで、転送元になる弟子のシナリオ別キャラデータのアドレスが計算できた。
転送先は固定($00:0DC0~)だから、計算の必要はない。
続きはニーモニックMVNによる転送処理である。
;MVN データ転送 $C0/24FE MVN 00 00 ;A:0033 X:0FX0 Y:0DC0 データ転送開始 $C0/24FE MVN 00 00 ;A:0032 X:0FX1 Y:0DC1 A:転送したいデータサイズ-1=$0033 $C0/24FE MVN 00 00 ;A:0031 X:0FX2 Y:0DC2 X:コピー元アドレス=$0FX0(弟子により変更) $C0/24FE MVN 00 00 ;A:0030 X:0FX3 Y:0DC3 Y:コピー先アドレス=$0DC0 $C0/24FE MVN 00 00 ;A:002F X:0FX4 Y:0DC4 オペランド:コピー元バンク=$00 コピー先バンク=$00 $C0/24FE MVN 00 00 ;A:002E X:0FX5 Y:0DC5 コピー元 $00:0FX0~$00:0FX3 $C0/24FE MVN 00 00 ;A:002D X:0FX6 Y:0DC6 コピー先 $00:0DC0~$00:0DF3 $C0/24FE MVN 00 00 ;A:002C X:0FX7 Y:0DC7 ;(中略) $C0/24FE MVN 00 00 ;A:0001 X:0FX2 Y:0DF2 $C0/24FE MVN 00 00 ;A:0000 X:0FX3 Y:0DF3 データ転送ここまで
MVNは、あるアドレスの範囲の値を他のアドレスにまとめて転送(コピー)するニーモニックである。
以下のように各レジスタに値を設定する。オペランドはMVNの後に指定される数値のこと。
| レジスタ | 内容 |
|---|---|
A | 転送したいデータサイズ-1 |
X | コピー元アドレス |
Y | コピー先アドレス |
| オペランド | コピー元バンク, コピー先バンク |
MVNの前に、Aに$0033、Yに$0DC0が固定値として入っている。
オペランドは00,00なので、転送元も転送先もバンク$00である。
弟子により異なるのはX、つまりコピー元アドレスで、それらは先に$C0/24DC~$C0/24FBにて計算した通り。
上の処理から、弟子のコピー元アドレス範囲が以下のようになっていることがわかる。
| キャラ | コピー元アドレス |
|---|---|
| ユン | $00:0F00~$00:0F33 |
| レイ | $00:0F40~$00:0F73 |
| サモ | $00:0F80~$00:0FB3 |
例えばユンなら、本来、シナリオ別キャラデータは$00:0F00~$00:0F3Fである。
だが、転送は$00:0F33までしか指定されていない。
コピー先も、$00:0DC0~$00:0DF3で、$00:0DFFではない。
どうして最後の12バイト($00:0DF4~$00:0DFF)は転送しないのだろうか?
シナリオ別キャラデータの最後の12バイトだが、以下のように値が入る。
| 数値 | 内容 |
|---|---|
| $34 | 名前1文字目 |
| $35 | 名前2文字目 |
| $36 | 名前3文字目 |
| $37 | 名前4文字目 |
| $38 | 名前5文字目 |
| $39 | 名前6文字目 |
| $3A | 名前7文字目 |
| $3B | 名前8文字目 |
| $3C | 名前9文字目 |
| $3D | 名前10文字目 |
| $3E | 名前11文字目 |
| $3F | 名前12文字目 |
この通り、キャラクター名が入っている。
功夫編だと拳法の名前であるが、転送前は各キャラ、どのような値(名前)が入っていたのか。
拳法名がデフォルトの「心山」だった場合は以下のようになる。
| キャラ | アドレス | 16進数 | デコード |
|---|---|---|---|
| 老師 | $00:0DF4~$00:0DFF | 1E 72 1E 00 1D B2 00 00 00 00 00 00 | 心山拳(00)(00)(00)(00)(00)(00) |
| ユン | $00:0F34~$00:0F3F | 85 8D 3C 9D 90 63 00 00 00 00 00 00 | ユン・ジョウ(00)(00)(00)(00)(00)(00) |
| レイ | $00:0F74~$00:0F7F | 8A 62 3C 68 63 9B 00 00 00 00 00 00 | レイ・クウゴ(00)(00)(00)(00)(00)(00) |
| サモ | $00:0FB4~$00:0FBF | 6B 83 3C 7A 91 66 00 00 00 00 00 00 | サモ・ハッカ(00)(00)(00)(00)(00)(00) |
つまり、名前だけは弟子のデータからコピーせず、それ以外、戦闘関係のステータスなどだけシナリオ別キャラデータからコピーして、ラストバトルに突入するということである。
そしてこのまま、功夫編をクリアして最終編に入っても、名前部分だけは変わらない。
というのは、功夫編主人公は、功夫編だと名前が「心山拳老師」、最終編だと「心山拳師範」である。
$00:0DF4~$00:0DFFに入っている名前データ+「老師」または「師範」がキャラ名になるため、以上のコピーだけで充分なのである。
逆に名前まで上書きしてしまうと、プレイヤーが付けた拳法の名前が消えてしまうので、名前の上書きまで行わないという意味でもある。
ユン・レイ・サモのキャラ名自体はデフォルトネームで変更不可であり、最終編ではセリフなどで使われるのみなのでコピーする必要はない。
ただ、功夫編ラストバトルでは、キャラ名は弟子のフルネームのままである。
そのあたりの処理は後で説明する。
$C0/2501 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C0/2503 PLY ;Yレジスタにスタックからプル $C0/2504 BRA $2D [$2533] ;フラグにかかわりなく常に分岐[$2533] $C0/2533 DEC $0A14 [$00:0A14] ;[$00:0A14]をデクリメント -1 $C0/2536 LDA $0A14 [$00:0A14] ;Aに[$00:0A14]をロード $C0/2539 CMP #$02 ;Aと$02を減算比較(ステータスレジスタ変更のみ) $C0/253B BNE $08 [$2545] ;ゼロフラグが立っていないとき[$2545]分岐 $C0/2545 PLB ;DBレジスタに値をプル $C0/2546 JSR $4104 [$C0:4104] ;[$C0:4104]へジャンプ
転送が終わると、[$00:0A14]をデクリメントして処理が一通り終わる。
[$00:0A14]はパーティ内の仲間キャラの数である(パーティ人数-1でもある)。
寸前までは老師+弟子の2人パーティで、[$00:0A14]には$01が入っていたが、ここでデクリメント(-1)されて$00となり、主人公1人パーティという扱いになる。
功夫編ラストバトルにおける、この戦闘専用の処理を紹介する。
まず戦闘開始時の処理について。
$C1/1ADD LDA $0040 [$00:0040] ;Aに[$00:0040]をロード $C1/1AE0 CMP #$F4 ;Aと$F4を減算比較(ステータスレジスタ変更のみ) $C1/1AE2 BNE $05 [$1AE9] ;ゼロフラグが立っていないとき[$1AE9]分岐 $C1/1AE4 LDA $0A00 [$00:0A00] ;Aに[$00:0A00](シナリオID$03 = 功夫編)をロード $C1/1AE7 CMP #$03 ;Aと$03を減算比較(ステータスレジスタ変更のみ) $C1/1AE9 RTS ;サブルーチン戻り ; $C1/1AED BNE $26 [$1B15] ;ゼロフラグが立っていないとき[$1B15]分岐 $C1/1AEF LDA #$01 ;Aに$01をロード $C1/1AF1 STA $0A14 [$00:0A14] ;Aを[$00:0A14]($01)に書き込み $C1/1AF4 LDA $0A15 [$00:0A15] ;Aに[$00:0A15](弟子の値$01~$03)をロード $C1/1AF7 CLC ;キャリーフラグクリア $C1/1AF8 ADC #$07 ;A + $07 $C1/1AFA STA $0A11 [$00:0A11] ;Aを[$00:0A11](キャラID$08~$0A)に書き込み $C1/1AFD LDX #$0DC0 ;Xに$0DC0をロード $C1/1B00 JSR $1B16 [$C1:1B16] ;[$C1:1B16]へジャンプ ; ;シナリオ別キャラデータ 功夫編主人公 $C1/1B16 LDA $000E,x[$00:0DCE] ;Aに[$00:0DCE](習得技(上位バイト))をロード $C1/1B19 STA $001F,x[$00:0DDF] ;Aを[$00:0DDF]に書き込み $C1/1B1C ORA #$80 ;Aと$80で論理和 $C1/1B1E STA $000E,x[$00:0DCE] ;Aを[$00:0DCE]に書き込み $C1/1B21 RTS ;サブルーチン戻り ; $C1/1B03 LDX #$0F00 ;Xに$0F00をロード $C1/1B06 JSR $1B16 [$C1:1B16] ;[$C1:1B16]へジャンプ ; ;シナリオ別キャラデータ 仲間1人目(ユン・ジョウ) $C1/1B16 LDA $000E,x[$00:0F0E] ;Aに[$00:0F0E]をロード $C1/1B19 STA $001F,x[$00:0F1F] ;Aを[$00:0F1F]に書き込み $C1/1B1C ORA #$80 ;Aと$80で論理和 $C1/1B1E STA $000E,x[$00:0F0E] ;Aを[$00:0F0E]に書き込み $C1/1B21 RTS ;サブルーチン戻り ; $C1/1B09 LDX #$0F40 ;Xに$0F40をロード $C1/1B0C JSR $1B16 [$C1:1B16] ;[$C1:1B16]へジャンプ ; ;シナリオ別キャラデータ 仲間2人目(レイ・クウゴ) $C1/1B16 LDA $000E,x[$00:0F4E] ;Aに[$00:0F4E]をロード $C1/1B19 STA $001F,x[$00:0F5F] ;Aを[$00:0F5F]に書き込み $C1/1B1C ORA #$80 ;Aと$80で論理和 $C1/1B1E STA $000E,x[$00:0F4E] ;Aを[$00:0F4E]に書き込み $C1/1B21 RTS ;サブルーチン戻り ; $C1/1B0F LDX #$0F80 ;Xに$0F80をロード $C1/1B12 JSR $1B16 [$C1:1B16] ;[$C1:1B16]へジャンプ ; ;シナリオ別キャラデータ 仲間3人目(サモ・ハッカ) $C1/1B16 LDA $000E,x[$00:0F8E] ;Aに[$00:0F8E]をロード $C1/1B19 STA $001F,x[$00:0F9F] ;Aを[$00:0F9F]に書き込み $C1/1B1C ORA #$80 ;Aと$80で論理和 $C1/1B1E STA $000E,x[$00:0F8E] ;Aを[$00:0F8E]に書き込み $C1/1B21 RTS ;サブルーチン戻り
$C1/1ADD~$C1/1AE9~$C1/1AEDが功夫編分岐にあたる。
最初に[$00:0040]の値が$F4かを判定しているが、これは(おそらく)功夫編ラストバトル固有の数値である。詳細未調査。
[$00:0A00]に入っているのはシナリオIDで、$C1/1AE7で$03と減算比較しているが、ここでゼロフラグが立つのはシナリオIDが$03、つまり功夫編のみである。
よって$C1/1AEDのゼロフラグ分岐では、そのまま次の$C1/1AEFに処理が進む。
[$00:0040]の値と[$00:0A00]のシナリオIDで、功夫編ラストバトルかどうかを判定している。
$C1/1AF1の処理だが、[$00:0A14]は直前のシナリオ別キャラデータの処理の時に一度$00になったにもかかわらず、ここでもう一度$01が書き込まれている。つまり仲間キャラが1人いる戦闘という扱いになっている。
$C1/1AF4~は[$00:0A15]に書き込まれた弟子の値($01 = ユン、$02 = レイ、$03 = サモ)に$07を足すことで、味方キャラ2人目のシナリオ別キャラデータIDを再度[$00:0A11]に書き込む処理である。
$C1/1B16~が「旋牙連山拳」の処理である。
[$00:0DCE]は、前に弟子の名前以外のデータをコピーした、功夫編主人公のシナリオ別キャラデータ$00:0DC0~$00:0DF3における、習得技2バイトのデータの中で、上位1バイト部分にあたる。
つまり、習得可能な技の中で、後半にあたる8種類、技LV08~技LV16の習得状況にあたり、2進数8ビットで表した時、下の位から順に技を習得していれば%1、そうでなければ%0が入っている。
「旋牙連山拳」は技LV16だから、一番上の桁に1が入っていれば習得している扱いである。つまり、%1000 0000(=$80)である。
[$00:0DCE]の値を一度[$00:0DDF]に書き込んでから、$80と論理和を取っているから、%1000 0000を加算したことになる。
$C1/1B1Eで、[$00:0DCE]に上書きしたので、この処理で、弟子は「旋牙連山拳」を覚えたことになる。
更に、Xの値を変更して$C1/1B16~$C1/1B21の処理を行っている。
上の通り、シナリオ別キャラデータの仲間3キャラ分のアドレスに繰り返して処理している。
離脱した他2人の弟子分もまとめて、「旋牙連山拳」を習得技に書き込んでいるのである。
伝承者の弟子のデータだけ処理すれば良いはずだが、ここでは3キャラ分の分岐はつくらずにまとめて処理していることがわかる。
これが、功夫編ラストバトルでのみ、弟子が「旋牙連山拳」を使える仕組みである。
ここまでの処理で、功夫編の主人公・仲間3キャラ(弟子3人)すべてが「旋牙連山拳」を習得した扱いとなる。
この後だが、「仲間キャラが1人いる戦闘=味方キャラ2人目がいる戦闘」になっているため、弟子のデータは仲間1人目としてステータスなどがコピーされていくことになる。
実際には味方キャラは弟子1人のみなのだが、味方キャラ1人目は誰なのか?
戦闘開始時、味方キャラのデータは、1人目から順に、$00:1C00~, $00:1C40~, $00:1C80~, $00:1CC0~に入る。
該当キャラが居ない、パーティメンバーが4人以下の場合でも、「該当キャラはいない」という処理のために値を入れていく。
$C1/EE56 LDA $0000,y[$00:0DC0] ;Aに[$00:0DC0]($09, $0A, $0B)をロード $C1/EE59 STA $1C00 [$00:1C00] ;Aを[$00:1C00]に書き込み $C1/EE5C STY $1C02 [$00:1C02] ;Yを[$00:1C02]に書き込み $C1/EE5F LDA #$FF ;Aに$FFをロード $C1/EE61 STA $1C01 [$00:1C01] ;Aを[$00:1C01]に書き込み
まずは味方1人目、プレイ中のシナリオの主人公IDを、シナリオ別キャラデータから取得する。
功夫編であれば、[$00:0DC0]に功夫編主人公のIDが入っているが、功夫編ラストバトルの時点では、功夫編シナリオ別キャラデータに、弟子のデータが上書き済みだから、ここで呼び出される[$00:0DC0]の中身は老師のID$08ではなく、弟子のID$09, $0A, $0Bのいずれかである。
よって、「味方キャラ1人目は弟子」である。
だが、功夫編シナリオ別キャラデータに、弟子の名前はコピーされていないため、厳密には、
「味方キャラ1人目は心山拳老師という名前で、ステータスは弟子」
というキャラのはずだ。
なお、[$00:1C01]は該当キャラの戦闘状態で、$FFは通常状態を意味する。
このままだと、
「味方キャラ1人目は心山拳老師という名前で、ステータスは弟子」
が、戦闘フィールドに登場することになってしまうが、後できちんと処理が入る。
$C1/EE8E STY $1CC2 [$00:1CC2] ;Yを[$00:1CC2]に書き込み $C1/EE91 LDA $0A14 [$00:0A14] ;Aに[$00:0A14](仲間の人数$01)をロード $C1/EE94 BEQ $32 [$EEC8] ;ゼロフラグが立っているとき[$EEC8]分岐 $C1/EE96 CMP #$01 ;Aと$01を減算比較(ステータスレジスタ変更のみ) $C1/EE98 BEQ $20 [$EEBA] ;ゼロフラグが立っているとき[$EEBA]分岐 $C1/EEBA LDA $0A11 [$00:0A11] ;Aに[$00:0A11](2人目のシナリオ別キャラデータID)をロード $C1/EEBD JSR $EC7A [$C1:EC7A] ;[$C1:EC7A]へジャンプ $C1/EC7A CMP #$0A ;Aと$0Aを減算比較(ステータスレジスタ変更のみ) $C1/EC7C BEQ $0E [$EC8C] ;ゼロフラグが立っているとき[$EC8C]分岐(サモ) $C1/EC7E CMP #$09 ;Aと$09を減算比較(ステータスレジスタ変更のみ) $C1/EC80 BEQ $05 [$EC87] ;ゼロフラグが立っているとき[$EC87]分岐(レイ) $C1/EC82 LDA $D60001,x[$D6:513C] ;(ユン)Aに[$D6:513C]をロード $C1/EC86 RTS ;サブルーチン戻り $C1/EC87 LDA $D60002,x[$D6:513D] ;(レイ)Aに[$D6:513D]をロード $C1/EC8B RTS ;サブルーチン戻り $C1/EC8C LDA $D60003,x[$D6:513E] ;(サモ)Aに[$D60003,x]をロード $C1/EC90 RTS ;サブルーチン戻り $C1/EEC0 STA $1C40 [$00:1C40] ;Aを[$00:1C40]に書き込み $C1/EEC3 LDA #$FF ;Aに$FFをロード $C1/EEC5 STA $1C41 [$00:1C41] ;Aを[$00:1C41]に書き込み $C1/EEC8 RTS ;サブルーチン戻り
この$C1/EE8E~の処理は、味方との戦闘でも紹介したことがある、シナリオ別キャラデータIDから味方キャラIDを呼び出す処理である。
$C1/EE91で、仲間の人数から、[$00:0A11](2人目のシナリオ別キャラデータID)をロードする。
つまり弟子に対応した$08~$0Aの値の呼び出しである。
$C1/EC7A~は、味方パーティIDリスト($D6:512F~$D6:514F)から味方キャラIDを呼び出す処理である。
| 弟子 | キャラID | ロード先アドレス |
|---|---|---|
| ユン $08 | [$D6:513C] | $09 |
| レイ $09 | [$D6:513D] | $0A |
| サモ $0A | [$D6:513E] | $0B |
こうして呼び出された値が、味方キャラ2人目の味方キャラIDとして、$C1/EEC0で[$00:1C40]に書き込まれる。
戦闘状態[$00:1C41]には$FFが書き込まれる。
ということで、ここまでだと、
という、なんともおかしな状態になっている。
だが、この後に、先程と同じ、シナリオ分岐処理$C1/1ADD~$C1/1AE9が入る。
$C1/1ADD LDA $0040 [$00:0040] ;Aに[$00:0040]をロード $C1/1AE0 CMP #$F4 ;Aと$F4を減算比較(ステータスレジスタ変更のみ) $C1/1AE2 BNE $05 [$1AE9] ;ゼロフラグが立っていないとき[$1AE9]分岐 $C1/1AE4 LDA $0A00 [$00:0A00] ;Aに[$00:0A00]をロード $C1/1AE7 CMP #$03 ;Aと$03を減算比較(ステータスレジスタ変更のみ) $C1/1AE9 RTS ;サブルーチン戻り $C1/1AC6 BNE $0D [$1AD5] ;ゼロフラグが立っていないとき[$1AD5]分岐 $C1/1AC8 LDA $1C41 [$00:1C41] ;Aに[$00:1C41]をロード $C1/1ACB CMP #$FF ;Aと$FFを減算比較(ステータスレジスタ変更のみ) $C1/1ACD BNE $06 [$1AD5] ;ゼロフラグが立っていないとき[$1AD5]分岐 $C1/1ACF STZ $1C01 [$00:1C01] ;[$00:1C01]に$00を書き込み $C1/1AD2 JSR $C489 [$C1:C489] ;[$C1:C489]へジャンプ
$C1/1AC8~が功夫編ラストバトル専用処理ということになるが、[$00:1C41](味方2人目の戦闘状態)が$FF(通常状態)なら、[$00:1C01](味方1人目の戦闘状態)に$00を書き込む。
戦闘状態$00は、戦闘離脱状態にあたるので、味方キャラ1人目は戦闘開始時点で戦闘離脱状態、つまり戦闘フィールドにいないことになる。
これで、味方キャラは、味方キャラ2人目にあたる弟子のみという状態になる。
表示する名前の都合で、味方キャラ2人目として弟子を戦闘に参加させる処理が行われたのだろう。
先の処理で、弟子は「旋牙連山拳」を習得している扱いになっている。
では、一度「旋牙連山拳」を使うとその後は使用不可になる処理はどうなっているのか。
ここまでの処理で、弟子は味方2人目という扱いになっていることがわかった。
つまり、戦闘中の味方キャラデータ$00:1C40~に値が入り、技関連の値は$7E:E940~$7E:E97Fに入ることになる。
以下は、「旋牙連山拳」を使った直後の処理になる。
ひとつ前に使った技として、味方2人目の戦闘中データ[$00:1C54]に、「旋牙連山拳」の技ID$94が書き込まれる。
実際に書き込む処理については省略するが、その後、以下のような処理で、[$00:1C54]の値は[$00:036A]にコピーされる。
$C1/D1A2 LDX $78 [$00:0378] ;Xに[$00:0378]をロード $C1/D1A4 LDY $0002,x[$00:1C42] ;Yに[$00:1C42]をロード $C1/D1A7 LDA $0014,x[$00:1C54] ;Aに[$00:1C54]をロード $C1/D1AA STA $6A [$00:036A] ;Aを[$00:036A]に書き込み $C1/D1AC JSR $3D7A [$C1:3D7A] ;[$C1:3D7A]へジャンプ
この後、上でもおなじみの、功夫編ラストバトル判定処理の$C1/1ADD~$C1/1AE9が入る。
$C1/1ADD LDA $0040 [$00:0040] ;Aに[$00:0040]をロード $C1/1AE0 CMP #$F4 ;Aと$F4を減算比較(ステータスレジスタ変更のみ) $C1/1AE2 BNE $05 [$1AE9] ;ゼロフラグが立っていないとき[$1AE9]分岐 $C1/1AE4 LDA $0A00 [$00:0A00] ;Aに[$00:0A00]をロード $C1/1AE7 CMP #$03 ;Aと$03を減算比較(ステータスレジスタ変更のみ) $C1/1AE9 RTS ;サブルーチン戻り
功夫編ラストバトルだと判定されると、以下のループ処理が入る。
$C1/1BBE BNE $21 [$1BE1] ;ゼロフラグが立っていないとき[$1BE1]分岐 $C1/1BC0 LDA $6A [$00:036A] ;Aに[$00:036A]をロード $C1/1BC2 CMP #$94 ;Aと$94を減算比較(ステータスレジスタ変更のみ) $C1/1BC4 BNE $1B [$1BE1] ;ゼロフラグが立っていないとき[$1BE1]分岐 $C1/1BC6 LDX $78 [$00:0378] ;Xに[$00:0378]をロード $C1/1BC8 LDA #$10 ;Aに$10をロード $C1/1BCA STA $08 [$00:0308] ;A($10)を[$00:0308]に書き込み ; ;ループ処理開始 最大$10回ループ $C1/1BCC LDA $7ECD00,x ;Aに[$7E:E940+n]をロード $C1/1BD0 CMP #$94 ;Aと$94(旋牙連山拳の技ID)を減算比較(ステータスレジスタ変更のみ) $C1/1BD2 BNE $08 [$1BDC] ;ゼロフラグが立っていないとき[$1BDC]分岐 ;ゼロフラグON $C1/1BD4 LDA #$00 ;Aに$00をロード $C1/1BD6 STA $7ECD00,x ;Aを[$7E:E940+n]に書き込み $C1/1BDA BRA $05 [$1BE1] ;フラグにかかわりなく常に分岐[$1BE1] ;ゼロフラグOFF $C1/1BDC INX ;Xをインクリメント +1 $C1/1BDD DEC $08 [$00:0308] ;[$00:0308]をデクリメント -1 $C1/1BDF BNE $EB [$1BCC] ;ゼロフラグが立っていないとき[$1BCC]分岐 ;ループ処理ここまで $C1/1BE1 RTS ;サブルーチン戻り
ループ前に、ひとつ前に使った技の技IDが入っている[$00:036A]と$94を減算比較し、ゼロフラグ判定をしている。
つまり、ひとつ前に使った技の技IDが$94(旋牙連山拳の技ID)かどうかの判定である。
「旋牙連山拳」を使った直後だと、$C1/1BCC~からのループ処理を行う。
味方2人目の習得技関連の値が入る$7E:E940~$7E:E97Fの中で、$7E:E940~$7E:E94Fは技IDにあたるのだが、$C1/1BCC~$C1/1BDFのループ処理では、$7E:E940~$7E:E94Fに、$94(旋牙連山拳の技ID)が入っていないかを確認している。
$7E:E940~$7E:E94Fは、レベル順に技IDが入っていくのだが、功夫編のようにラーニングで技習得がレベル順でない場合は詰めて記録されるため、「旋牙連山拳」の技IDが$7E:E940~$7E:E94Fのどこに入っているか、判定する必要がある。
「旋牙連山拳」の技IDが入っているアドレスがあると、$C1/1BD2でゼロフラグが立ち、$00を該当のアドレスに上書きする。
こうして「旋牙連山拳」が技一覧から削除されるのである。
$C1/1BBE~$C1/1BCAで、ひとつ前に使った技が「旋牙連山拳」の場合にループ処理に入ることになっているから、$C1/1BCC~$C1/1BDFのループ処理は、どこかで必ず$C1/1BD2にてゼロフラグが経ってループを抜けるはずである。
戦闘中における処理はここまでである。
シナリオ別キャラデータの技習得状況の4キャラ分のアドレス[$00:0DCE][$00:0F0E][$00:0F4E][$00:0F8E]には、「旋牙連山拳」が習得済みと記録されたままだが、これらから「旋牙連山拳」の削除処理が行われるのはラストバトルに勝利したタイミングである。
すっかりおなじみの$C1/1ADD~$C1/1AE9の功夫編ラストバトル判定後に処理が入る。
$C1/1ADD LDA $0040 [$00:0040] ;Aに[$00:0040]をロード $C1/1AE0 CMP #$F4 ;Aと$F4を減算比較(ステータスレジスタ変更のみ) $C1/1AE2 BNE $05 [$1AE9] ;ゼロフラグが立っていないとき[$1AE9]分岐 $C1/1AE4 LDA $0A00 [$00:0A00] ;Aに[$00:0A00]をロード $C1/1AE7 CMP #$03 ;Aと$03を減算比較(ステータスレジスタ変更のみ) $C1/1AE9 RTS ;サブルーチン戻り $C1/1B7C BNE $1B [$1B99] ;ゼロフラグが立っていないとき[$1B99]分岐 $C1/1B7E STZ $0A14 [$00:0A14] ;[$00:0A14]に$00を書き込み $C1/1B81 LDX #$0DC0 ;Xに$0DC0をロード $C1/1B84 JSR $1B9A [$C1:1B9A] ;[$C1:1B9A]へジャンプ $C1/1B9A LDA $001F,x[$00:0DDF] ;Aに[$00:0DDF]をロード $C1/1B9D STA $000E,x[$00:0DCE] ;Aを[$00:0DCE]に書き込み $C1/1BA0 RTS ;サブルーチン戻り $C1/1B87 LDX #$0F00 ;Xに$0F00をロード $C1/1B8A JSR $1B9A [$C1:1B9A] ;[$C1:1B9A]へジャンプ $C1/1B9A LDA $001F,x[$00:0F1F] ;Aに[$00:0F1F]をロード $C1/1B9D STA $000E,x[$00:0F0E] ;Aを[$00:0F0E]に書き込み $C1/1BA0 RTS ;サブルーチン戻り $C1/1B8D LDX #$0F40 ;Xに$0F40をロード $C1/1B90 JSR $1B9A [$C1:1B9A] ;[$C1:1B9A]へジャンプ $C1/1B9A LDA $001F,x[$00:0F5F] ;Aに[$00:0F5F]をロード $C1/1B9D STA $000E,x[$00:0F4E] ;Aを[$00:0F4E]に書き込み $C1/1BA0 RTS ;サブルーチン戻り $C1/1B93 LDX #$0F80 ;Xに$0F80をロード $C1/1B96 JSR $1B9A [$C1:1B9A] ;[$C1:1B9A]へジャンプ $C1/1B9A LDA $001F,x[$00:0F9F] ;Aに[$00:0F9F]をロード $C1/1B9D STA $000E,x[$00:0F8E] ;Aを[$00:0F8E]に書き込み $C1/1BA0 RTS ;サブルーチン戻り
「旋牙連山拳」習得処理の前に、習得前のデータを[$00:0DDF][$00:0F1F][$00:0F5F][$00:0F9F]にコピーしていたから、
[$00:0DDF]→[$00:0DCE](功夫編主人公)[$00:0F1F]→[$00:0F0E](仲間キャラ1人目)[$00:0F5F]→[$00:0F4E](仲間キャラ2人目)[$00:0F9F]→[$00:0F8E](仲間キャラ3人目)と、習得状況を書き戻したことになる。
これで、シナリオ別キャラデータの技習得状況から、「旋牙連山拳」が削除された。
もっとも、この戦闘がラストバトルだから、削除するのは功夫編主人公用のアドレス[$00:0DCE]だけでも問題はないはずであるが、このあたりはサブルーチンの再利用であろうし、諸々のエラーを防ぐために行われているのかもしれない。
以上が、功夫編ラストバトル関連の処理となる。
シナリオ別キャラデータのコピーがラストバトル前に行われているというのは少々意外だったが、老師の離脱タイミングで行っておこうという意味合いなのだろうか。
今回の処理で書き込まれた、功夫編・最終編のみ心山拳老師&師範が誰なのかの値$00:0A15は最終編にそのまま引き継ぎになり、最終編でも心山拳師範が誰なのかの分岐で使われることになる。