基礎知識
戦闘関係
前ページからの続き。
前ページでは、
まで、サブルーチンでの処理を説明した。
その続きを以下で紹介する。
ここまでは仲間キャラのデータの呼び出しが続いたが、以降は敵対する味方キャラ(修行だと仲間2人目)が敵種類1かつ敵番号1という処理が入っていく。
[$00:1C40]に、敵として戦うサモの値が入る前提で話を進めていくが、他シナリオでも処理自体は同じ。
$C1/F9B0 LDY #$1A00 ;Yに$1A00をロード $C1/F9B3 LDA $0018,x[$00:1C58] ;Aに[$00:1C58](キャラ位置のマス目のX座標)をロード $C1/F9B6 STA $23 [$00:0323] ;Aを[$00:0323]に書き込み $C1/F9B8 LDA $0019,x[$00:1C59] ;Aに[$00:1C59](キャラ位置のマス目のY座標)をロード $C1/F9BB STA $24 [$00:0324] ;Aを[$00:0324]に書き込み $C1/F9BD LDA $0010,x[$00:1C50] ;Aに[$00:1C50](キャラの位置のX軸(ピクセル単位))をロード $C1/F9C0 STA $25 [$00:0325] ;Aを[$00:0325]に書き込み $C1/F9C2 LDA $0012,x[$00:1C52] ;Aに[$00:1C52](キャラの位置のY軸(ピクセル単位))をロード $C1/F9C5 CLC ;キャリーフラグクリア $C1/F9C6 ADC #$08 ;A + $08 $C1/F9C8 STA $26 [$00:0326] ;Aを[$00:0326]に書き込み
上はアドレスからして、戦闘におけるキャラの初期位置に関するデータの読み書きになるが、今回は詳細を省く。
問題はこの後の処理である。
$C1/F9CA LDA $0A00 [$00:0A00] ;Aに[$00:0A00](シナリオID)をロード $C1/F9CD CMP #$08 ;Aと$08を減算比較(ステータスレジスタ変更のみ) $C1/F9CF BNE $04 [$F9D5] ;ゼロフラグが立っていないとき[$F9D5]分岐 ;最終編用処理 $C1/F9D1 LDA #$FF ;Aに$FFをロード $C1/F9D3 BRA $06 [$F9DB] ;フラグにかかわりなく常に分岐[$F9DB] ;最終編以外の処理 $C1/F9D5 LDA $0000,x[$00:1C40] ;Aに[$00:1C40]をロード $C1/F9D8 CLC ;キャリーフラグクリア $C1/F9D9 ADC #$EB ;A + $EB $C1/F9DB STA $10 [$00:0310] ;Aを[$00:0310]に書き込み $C1/F9DD PHX ;Xをスタックにプッシュ $C1/F9DE JSR $FB81 [$C1:FB81] ;[$C1:FB81]へジャンプ
$C1/F9CAで[$00:0A00]、つまりシナリオIDを呼び出し、最終編のみの分岐がある。
最終編の場合は、Aに$FFをロードしてから、$C1/F9DBへ飛ぶ。
最終編以外だと、[$00:1C40]をロードし、$EBを加算して、$C1/F9DBに進む。
どのシナリオでも$C1/F9DBで合流するが、その前の処理は、
A = $FFA = [$00:1C40](味方キャラID) + $EBとなっていて、この値を[$00:0310]に書き込み、[$C1:FB81]へジャンプ、となる。
この計算は何にあたるのか。
功夫編のサモ相手の修行だったら、[$00:1C40]にサモのキャラIDの$0Bが入っているから、
$0B + $EB = $F6
という計算をして、Aに$F6が入る。
この$F6という値は、敵キャラデータに入っているサモのIDにあたる。
敵キャラデータIDの$EB~$FFに登録されている21キャラ分は、$EBを加算することで、敵キャラデータのIDを呼び出せるのである。
だが、先に記した通りに、カラクリ丸についてはここで妙なことが起こる。
カラクリ丸の味方キャラIDは$16だから、
$16 + $EB = $101
となり、キャリーフラグがONになって、Aには$01が入る(この時点では8bitモードである)。
上の処理を見る限りキャリーフラグでの分岐処理などはなく、$C1/F9DBで加算の答えが[$00:0310]に書き込まれる。
サモなら[$00:0310]に$F6が入るが、カラクリ丸だと$01が入ってしまう。
敵キャラデータIDの$01は、最終編のころころムシにあたる。
このことが、最終的には、世界の合言葉は森部様の説明にある、
カラクリ丸はころころムシの側面背面補正と回避となっているようだ。
に繋がるのであるが、その説明は後ほど。
とにかく、敵キャラデータIDにデータがないカラクリ丸については、上の計算で一度、敵キャラデータID・$01のころころムシが呼び出されてしまうことになる。
そしてもうひとつ、最終編の処理に注目していただきたい。
最終編でも、
[$00:1C40](味方キャラID) + $EB
で、敵キャラデータのIDが呼び出せるはずなのに、それを行わずに$FFと固定値を指定してしまっている。
敵キャラデータID・$FFは、一覧の一番下、キューブの敵キャラデータにあたる。
最終編だと、戦う相手がどの仲間キャラであろうが、敵キャラデータID・$FFを指定することになる。
これが後々で、「最終編で仲間キャラと戦う時、無効状態異常に眠り状態だけ指定されている」ことに繋がる。
では、$C1/FB81に飛んだ後の処理を見てみる。
上で計算した値は、Aと[$00:0310]に入っている。
$C1/FB81 LDA $0001,y[$00:1A01] ;Aに[$00:1A01]をロード $C1/FB84 BEQ $23 [$FBA9] ;ゼロフラグが立っているとき[$FBA9]分岐 $C1/FBA9 LDA $10 [$00:0310] ;Aに[$00:0310]をロード $C1/FBAB STA $0000,y[$00:1A00] ;Aを[$00:1A00]に書き込み $C1/FBAE LDA #$FF ;Aに$FFをロード $C1/FBB0 STA $0001,y[$00:1A01] ;A($FF)を[$00:1A01]に書き込み $C1/FBB3 LDA #$00 ;Aに$00をロード $C1/FBB5 STA $000A,y[$00:1A0A] ;A($00)を[$00:1A0A]に書き込み $C1/FBB8 JSR $FC0A [$C1:FC0A] ;[$C1:FC0A]へジャンプ
$00:1A00~には、戦闘における敵種類1のデータが入る。
仲間との戦闘では、敵の種類は1種類(対戦相手)だけなので、$00:1A00~に敵になる仲間キャラのステータスが入っていく。
$00:1A00に入るのは、敵種類1の敵IDである。
$C1/FBA9~$C1/FBABで、[$00:0310]の値が[$00:1A00]に書き込まれる。
つまり、先に計算した値が敵種類1の敵IDで決定である。
整理してみると、敵種類1の敵IDの値は、以下のようになる。
カラクリ丸と最終編の仲間キャラとの戦闘については、全く異なるキャラのIDが指定されたことになる。
今回は別調査とするが、最終編オルステッドルートで戦う仲間キャラも、一番下のID$FFが書き込まれる。
この後に元の味方キャラのデータで上書きしていくため、ほとんどの場合で問題にはならない。
無効状態異常など一部データが上書きされないので、元の味方キャラのデータが完全に再現されることはない、ということになるが、それにより大幅に戦闘バランスがおかしくなるといったことは起こらない。
こういった処理がどこまで意図したものなのかは、今となってはわからないままである。
一方で、ストレイボウのように、味方キャラ時とは異なる敵データを用意したことで、戦闘においてきちんと意味が出ている場合もある(敵対時のみ電撃フィールド吸収能力を付けたことで、中世編ラストバトルで「アンバーストーム」による電撃フィールド吸収が反映される)。
話が横に逸れたが、続きである$C1:FC0A~を見てみる。
以下はサモの場合の処理として値に注意書きをつけてある。
$C1/FC0A PHX ;Xをスタックにプッシュ $C1/FC0B PHY ;Yをスタックへプッシュ $C1/FC0C LDA $0000,y[$00:1A00] ;Aに[$00:1A00]($F6)をロード $C1/FC0F STA $211B [$00:211B] ;Aを[$00:211B]に書き込み $C1/FC12 LDA #$00 ;Aに$00をロード $C1/FC14 STA $211B [$00:211B] ;Aを[$00:211B]に書き込み $C1/FC17 LDA #$20 ;Aに$20をロード $C1/FC19 STA $211C [$00:211C] ;Aを[$00:211C]に書き込み $C1/FC1C STA $211C [$00:211C] ;Aを[$00:211C]に書き込み $C1/FC1F REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/FC21 LDA $2134 [$00:2134] ;Aに[$00:2134]($1EC0)をロード $C1/FC24 ADC $D50010[$D5:0010] ;A + [$D5:0011][$D5:0010](=$04CB) = $238B $C1/FC28 TAX ;Aレジスタの値をXレジスタに転送 $C1/FC29 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/FC2B LDA #$20 ;Aに$20をロード $C1/FC2D STA $09 [$00:0309] ;A($20)を[$00:0309]に書き込み ; ;ループ処理 ;$D5:238B~$D5:23AAを、$00:1A20~$00:1A3Fに書き込み($20=32回分) $C1/FC2F LDA $D50000,x[$D5:238B] ;Aに[$D5:238B+n]をロード(敵データID $F6 サモ) $C1/FC33 INX ;Xをインクリメント +1 $C1/FC34 STA $0020,y[$00:1A20] ;Aを[$00:1A20+n]に書き込み $C1/FC37 INY ;Yをインクリメント +1 $C1/FC38 DEC $09 [$00:0309] ;[$00:0309]をデクリメント -1 $C1/FC3A BNE $F3 [$FC2F] ;ゼロフラグが立っていないとき[$FC2F]分岐 ;ループここまで ; $C1/FC3C PLY ;Yレジスタにスタックからプル $C1/FC3D PLX ;Xレジスタにスタックからプル $C1/FC3E RTS ;サブルーチン戻り
$C1/FC0Cで[$00:1A00]をロードしているが、ここには前に計算した、「敵キャラデータに入っているサモのID」である$F6が入っている。
カラクリ丸なら敵ID$01(ころころムシ)、最終編だとID$FF(キューブ)が入っているが、他の味方キャラは「敵キャラデータに入っている味方キャラのID」である$EB~$FFのいずれかが入っている。
$C1/FC0F~$C1/FC24は、敵IDから、敵データが入っているアドレスを計算する処理なので詳細を省くが、「敵キャラデータに入っているサモのID」の開始位置は$D5:238Bである。
$C1/FC2F~$C1/FC3Aのループ処理で、「サモの敵キャラデータ」32バイト分を、$00:1A20~$00:1A3Fへコピーしている。
敵種類1のデータは、$20以降に敵キャラデータ32バイトがそのまま入るため、その作業を上で行ったことになる。
味方キャラとの戦闘時、戦う相手は必ず1体で、敵種類1に登録されるため、この処理は共通である。
カラクリ丸の場合、ころころムシの敵データが丸ごとコピーされてしまったため、力・速・体・知がオール200($C8)など、とんでもない数値が入ってしまったことになるが、この後の処理で上書きされていく。
最終編だとキューブの敵データが入ることになり、ほとんどの値が00で埋まっているものの、先に紹介した通り、敵キャラデータ10だけ$20が入っている。
敵キャラデータ10は無効状態異常の値であり、8ビットの各ビットで状態異常8種が無効かどうかを表しているが、$20は眠り状態のみ無効を意味する。
この値は上書きされずに残ってしまうために、最終編での仲間との戦闘では、眠り状態のみ無効が付くことになる。
では、実際に、どのようにして味方キャラのデータで上書きしていくか、続きを見ていく。
$C1/FD76 LDA $0A00 [$00:0A00] ;Aに[$00:0A00](プレイ中のシナリオID)をロード $C1/FD79 CMP #$08 ;Aと$08を減算比較(ステータスレジスタ変更のみ) $C1/FD7B BNE $03 [$FD80] ;ゼロフラグが立っていないとき[$FD80]分岐 ;[$00:0A00] = $08,最終編のみの処理 $C1/FD7D LDA $0A10 [$00:0A10] ;Aに[$00:0A10](最終編主人公の値)をロード $C1/FD80 RTS ;サブルーチン戻り ; $C1/FD13 BEQ $01 [$FD16] ;ゼロフラグが立っているとき[$FD16]分岐(最終編主人公 = $00はオルステッド) $C1/FD15 RTS ;サブルーチン戻り ; $C1/F6FC JSR $F959 [$C1:F959] ;[$C1:F959]へジャンプ ; $C1/F959 JSR $FD76 [$C1:FD76] ;[$C1:FD76]へジャンプ ; $C1/FD76 LDA $0A00 [$00:0A00] ;Aに[$00:0A00](プレイ中のシナリオID)をロード $C1/FD79 CMP #$08 ;Aと$08を減算比較(ステータスレジスタ変更のみ) $C1/FD7B BNE $03 [$FD80] ;ゼロフラグが立っていないとき[$FD80]分岐 ;[$00:0A00] = $08,最終編のみの処理 $C1/FD7D LDA $0A10 [$00:0A10] ;Aに[$00:0A10]をロード $C1/FD80 RTS ;サブルーチン戻り
[$00:0A00]に格納されているのはプレイ中のシナリオIDである。
$C1/FD76~$C1/FD79で、プレイ中のシナリオIDが$08かどうかを判定しているが、シナリオID$08は最終編である。
$C1/FD7Bでゼロフラグが立つのは最終編のみで、その場合は$C1/FD7Dで[$00:0A10]をAにロードする。他シナリオだと$C1/FD7Dはスキップされ、$C1/FD80に進むのみである。
最終編における[$00:0A10]には、最終編の主人公の値が入っている。
$C1/FD13でゼロフラグの判定をしているが、最終編以外だと$C1/FD79で「シナリオID - $08」の計算をした直後で、$C1/FD13は立っていない。
最終編の場合、[$00:0A10]をロードした直後になり、[$00:0A10]に$00が入っていた時のみゼロフラグが立つ。
最終編で[$00:0A10]に$00が入るのは、主人公がオルステッドの時のみである。
よって、$C1/FD13のゼロフラグ分岐は「最終編かつオルステッドが主人公」の判定で、その場合は[$C1/FD16]にジャンプする。
ここでは最終編オルステッドルートについては説明を省く。
「最終編かつオルステッドが主人公」の分岐後に、もう一度$C1/FD76~の処理を行い、最終編かどうかを判定している。
ここでゼロフラグが立つ、つまり最終編である場合は、「最終編かつオルステッド以外が主人公」であることを意味する。
その時は、$C1/FD7DでAに[$00:0A10](最終編主人公の値)をロードして続きの処理を行う。
最終編以外のシナリオだと、実質この処理では何も変化はなく、AにシナリオIDを呼び出しただけである。
$C1/F95C BEQ $2B [$F989] ;ゼロフラグが立っているとき[$F989]分岐 $C1/F95E LDX $52 [$00:0352] ;Xに[$00:0352]をロード $C1/F960 LDA $D60001,x[$D6:4D3F] ;Aに[$D6:4D3F]をロード $C1/F964 AND #$F0 ;Aと$F0で論理積 $C1/F966 BNE $01 [$F969] ;ゼロフラグが立っていないとき[$F969]分岐 $C1/F969 STA $27 [$00:0327] ;A($40)を[$00:0327]に書き込み
$C1/FD80の続きだが、ここが重要な分岐である。
$C1/F95Cでゼロフラグが立っているかどうか判定しているが、(おそらく)ここでゼロフラグが立っていることはない。
$C1/F95E~$C1/F960はXの値により$C1/F960で呼び出されるアドレスが変わるが、$C1/F960でロードされる$D60001,xは、この戦闘の敵パーティデータ01にあたる。
上では功夫編修行の敵パーティデータID$ACの、敵パーティデータ01[$D6:4D3F]の値がロードされている。
先に説明したが、敵パーティデータ01は、操作キャラと敵対キャラが味方側か敵側かの数値が入る。
| 値 | 内容 |
|---|---|
| $00 | 味方キャラ 対 敵キャラ(通常) |
| $01 | 敵キャラ 対 敵キャラ(ブリキ大王戦など) |
| $10 | 原始編 ざき1戦目 |
| $20 | カラクリ丸戦(とらわれの男がいる時) |
| $40 | 味方1キャラ 対 味方1キャラ(功夫編修行など) |
つまり、対戦相手が味方キャラだと、上1桁に0以外の数が入る。
$C1/F964で、敵パーティデータ01と$F0で論理積を取っているが、上1桁に0以外の値が入っている、敵対相手が味方キャラの戦闘だと、ここでゼロフラグが立たない。
ここで、「この戦闘で戦う相手は味方キャラ」という判定が入った。
功夫編修行の場合は論理積を取った結果、$40となり、[$00:0327]に書き込まれる。
仲間キャラとの戦闘だと、敵パーティデータ01の下1桁は必ず0なので、論理積を取っても取らなくても、[$00:0327]に入るのは敵パーティデータ01と同値である。
$C1/F96B LDX #$1C00 ;Xに$1C00をロード $C1/F96E STX $1C [$00:031C] ;Xを[$00:031C]に書き込み $C1/F970 LDA #$04 ;Aに$04をロード $C1/F972 STA $08 [$00:0308] ;A($04)を[$00:0308]に書き込み $C1/F974 ASL $27 [$00:0327] ;[$00:0327]($40)を算術左シフト *2 (=$40*2) $C1/F976 BCC $03 [$F97B] ;キャリーフラグが立っていないとき[$F97B]分岐 $C1/F97B LDA $1C [$00:031C] ;Aに[$00:031C]($00)をロード $C1/F97D CLC ;キャリーフラグクリア $C1/F97E ADC #$40 ;A + $40 $C1/F980 STA $1C [$00:031C] ;Aを[$00:031C]($40)に書き込み $C1/F982 LDX $1C [$00:031C] ;Xに[$00:031C]($1C40)をロード $C1/F984 DEC $08 [$00:0308] ;[$00:0308]($04)をデクリメント -1 $C1/F986 BNE $EC [$F974] ;ゼロフラグが立っていないとき[$F974]分岐 $C1/F974 ASL $27 [$00:0327] ;[$00:0327]($80)を算術左シフト *2 $C1/F976 BCC $03 [$F97B] ;キャリーフラグが立っていないとき[$F97B]分岐 $C1/F978 JSR $F9A7 [$C1:F9A7] ;[$C1:F9A7]へジャンプ
$C1/F96B~$C1/F978は次のジャンプ先のアドレスの計算や分岐になる。
詳細は省略するが、先程の敵パーティデータ01が書きこまれた[$00:0327]は、$C1/F974と$C1/F974でそれぞれ算術左シフトされ2倍になっている。
その後にキャリーフラグが立つかどうか判定をして分岐になるが、1回目の算術左シフトでは2倍で$80になるのでキャリーフラグが立たない。
敵パーティデータ01が$10や$20の時も同様である。
だが、2回目の算術左シフトだと、最初の値が4倍されることになるから、$80*2 = $100でキャリーフラグが立つ。
だが、敵パーティデータ01が$10や$20だと、4倍してもキャリーフラグは立たない。
$C1/F976で、敵パーティデータ01が$40の場合と、$10または$20の場合とで、分岐になったということがわかる。
敵パーティデータ01が$40の場合は、X = $1C40で[$C1:F9A7]へジャンプする、ということも覚えておいていただきたい。
$10または$20の場合の分岐先、$C1/F97B~は、最終的に上処理と合流するが、それまでの処理を紹介しておく。
敵パーティデータ01が$10は原始編のざき1戦目、$20は幕末編でとらわれの男がいる場合のカラクリ丸戦だが、これらはプレイヤー操作キャラが2キャラ以上いるので処理が別になっている。
実は$C1/F974~$C1/F986のループ処理になっていて、$C1/F976でキャリーフラグが立つとループを抜けて、$C1/F978に合流、という手順である。
[$00:0327]は、ループに入った時点で$20または$40になっているはずである。
;ループここから $C1/F974 ASL $27 [$00:0327] ;[$00:0327]($20または$40)を算術左シフト *2 $C1/F976 BCC $03 [$F97B] ;キャリーフラグが立っていないとき[$F97B]分岐(ループを抜ける) $C1/F97B LDA $1C [$00:031C] ;Aに[$00:031C]($40~)をロード $C1/F97D CLC ;キャリーフラグクリア $C1/F97E ADC #$40 ;A + $40 $C1/F980 STA $1C [$00:031C] ;Aを[$00:031C]に書き込み $C1/F982 LDX $1C [$00:031C] ;Xに[$00:031C]をロード $C1/F984 DEC $08 [$00:0308] ;[$00:0308]($03~)をデクリメント -1 $C1/F986 BNE $EC [$F974] ;ゼロフラグが立っていないとき[$F974]分岐 ;ループここまで
ざき1戦目は、ループ1周目で[$00:0327]が$20の状態で、ループ頭で毎回*2するから、$40, $80, $100と、3回目の頭で$C1/F97Bでキャリーフラグが立ってループを抜ける。
ループ中に毎回、Xを+$40しているから、ループを抜けた時にX = $1CC0である。
カラクリ丸戦は、ループ1周目で[$00:0327]が$40の状態なので、2回目の頭でループを抜ける。
ループを抜けた時にX = $1C80である。
どの場合でも、$C1/F978で[$C1:F9A7]へジャンプする。
$C1/F9A7からの処理は以下のようになっている。
$C1/F9A7 LDA #$20 ;Aに$20をロード $C1/F9A9 STA $0001,x[$00:1C?1] ;A($20)を[$00:1C?1]に書き込み $C1/F9AC JSR $F9B0 [$C1:F9B0] ;[$C1:F9B0]へジャンプ
敵パーティデータ01が$40の場合は、X = $1C40だった。
$10(ざき1戦目)だとX = $1CC0、$20(カラクリ丸戦)だとX = $1C80である。
$C1/F9A9で、A($20)を[$0001,x]に書き込むが、これは特定の味方キャラの戦闘状態を$20(味方キャラ敵対時の値)にセットするという意味である。
| 敵パーティ データ01 | $20を書き込む アドレス | 内容 |
|---|---|---|
| $40 | [$00:1C41] | 味方キャラ番号2の戦闘状態 |
| $10 | [$00:1CC1] | 味方キャラ番号4の戦闘状態 |
| $20 | [$00:1C81] | 味方キャラ番号3の戦闘状態 |
つまり、主人公対味方キャラ1人の時は、味方2人目を「味方キャラ敵対」状態にセットする。
ざき1戦目は、味方キャラ番号4、ざきを「味方キャラ敵対」状態にセットする。
カラクリ丸戦(とらわれの男がいる時)は、味方キャラ番号3、カラクリ丸を「味方キャラ敵対」状態にセットする。
敵パーティデータ01の上1桁の違いは、「どの味方キャラ番号のキャラが敵扱いになるか」だったのだ。
なお、幕末編については、とらわれの男・カラクリ丸どちらもパーティにいる場合、パーティに加入する順序は必ずとらわれの男→カラクリ丸の順なので、味方キャラ番号3がカラクリ丸になる。
カラクリ丸を先に仲間にするということは、その時点でからくり源内を撃破しており、とらわれの男は地下牢からいなくなっている。よって、カラクリ丸が虚無僧戦前に自爆した後でなければ、とらわれの男が加入しない。
では、以降の処理を見ていく。
ひとまずは、功夫編のサモの修行での処理を追っていく。
ステータスとともに、使用する技も書き込んでいく必要があるが、ここから先で、敵として戦う味方キャラの技関係の値を呼び出していく。
(実際には、主人公の技の呼び出しなどの処理も並行して行っているが、ここでは割愛して、対戦相手についてのみ掲載する)
ここではサモの技を呼び出す。
手順としては、
となるが、下にはサモの技レベル00「クマの手」(技ID$A5)の処理を載せておく。
サモの味方キャラデータ05~20は$D5:02B4~$D5:02C3で、「クマの手」の技データは、$D5:34E8~に入っている。
$C1/E94B PHX ;Xをスタックにプッシュ $C1/E94C STX $14 [$00:0314] ;Xを[$00:0314]に書き込み $C1/E94E LDY $0002,x[$00:1C42] ;Yに[$00:1C42]をロード $C1/E951 LDX $0004,y[$00:0F84] ;Xに[$00:0F84]をロード $C1/E954 REP #$20 ;Aを16bit幅に変更、Mフラグをクリア $C1/E956 LDA $000D,y[$00:0F8D] ;Aに[$00:0F8E][$00:0F8D](覚えた技2バイト)をロード $C1/E959 STA $10 [$00:0310] ;Aを[$00:0311][$00:0310]に書き込み $C1/E95B SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/E95D LDY $14 [$00:0314] ;Yに[$00:0314]をロード $C1/E95F LDA #$10 ;Aに$10をロード $C1/E961 STA $08 [$00:0308] ;Aを[$00:0308]に書き込み $C1/E963 STA $09 [$00:0309] ;Aを[$00:0309]に書き込み $C1/E965 LDA $D50005,x[$D5:02B4] ;Aに[$D5:02B4](レベル00の技ID)をロード $C1/E969 STA $12 [$00:0312] ;A(技ID)を[$00:0312]に書き込み $C1/E96B BNE $06 [$E973] ;ゼロフラグが立っていないとき[$E973]分岐 $C1/E973 STX $14 [$00:0314] ;Xを[$00:0314]に書き込み $C1/E975 JSR $3D93 [$C1:3D93] ;[$C1:3D93]へジャンプ ; ;ここから習得技のステータス移動ループ処理 $C1/3D93 STA $211B [$00:211B] ;Aを[$00:211B]に書き込み $C1/3D96 LDA #$00 ;Aに$00をロード $C1/3D98 STA $211B [$00:211B] ;Aを[$00:211B]に書き込み $C1/3D9B LDA #$19 ;Aに$19をロード $C1/3D9D STA $211C [$00:211C] ;Aを[$00:211C]に書き込み $C1/3DA0 STA $211C [$00:211C] ;Aを[$00:211C]に書き込み $C1/3DA3 REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/3DA5 LDA $2134 [$00:2134] ;Aに[$00:2134]をロード $C1/3DA8 ADC $D50018[$D5:0018] ;A + [$D5:0018] $C1/3DAC TAX ;Aレジスタの値をXレジスタに転送 $C1/3DAD SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/3DAF RTS ;サブルーチン戻り ; $C1/E978 LDA $D50008,x[$D5:34F0] ;Aに[$D5:34F0]をロード $C1/E97C STA $13 [$00:0313] ;Aを[$00:0313]に書き込み $C1/E97E LDA $D5000D,x[$D5:34F5] ;Aに[$D5:34F5]をロード $C1/E982 STA $18 [$00:0318] ;Aを[$00:0318]に書き込み $C1/E984 ROL A ;Aをキャリーフラグを含めた9bitで左ローテート $C1/E985 ROL A ;Aをキャリーフラグを含めた9bitで左ローテート $C1/E986 ROL A ;Aをキャリーフラグを含めた9bitで左ローテート $C1/E987 AND #$01 ;Aと#$01で論理積 $C1/E989 STA $17 [$00:0317] ;Aを[$00:0317]に書き込み $C1/E98B LDA $D5000F,x[$D5:34F7] ;Aに[$D5:34F7]をロード $C1/E98F AND #$FE ;Aと$FEで論理積 $C1/E991 ORA $17 [$00:0317] ;Aと[$00:0317]で論理和 $C1/E993 STA $17 [$00:0317] ;Aを[$00:0317]に書き込み $C1/E995 LDA $D5000E,x[$D5:34F6] ;Aに[$D5:34F6]をロード $C1/E999 STA $16 [$00:0316] ;Aを[$00:0316]に書き込み $C1/E99B TYX ;Yレジスタの値をXレジスタに転送 ; $C1/E99C LSR $11 [$00:0311] ;[$00:0311]を論理右シフト (/2) [$00:0311][$00:0310]覚えた技2バイト $C1/E99E ROR $10 [$00:0310] ;[$00:0310]をキャリーフラグを含めた9bitで右ローテート $C1/E9A0 BCS $04 [$E9A6] ;キャリーフラグが立っているとき[$E9A6]分岐 $C1/E9A6 LDA $12 [$00:0312] ;Aに[$00:0312](技ID)をロード $C1/E9A8 STA $7ECD00,x[$7E:E940] ;Aを[$7E:E940]に書き込み $C1/E9AC LDA $13 [$00:0313] ;Aに[$00:0313]をロード $C1/E9AE STA $7ECD10,x[$7E:E950] ;Aを[$7E:E950]に書き込み $C1/E9B2 LDA $16 [$00:0316] ;Aに[$00:0316]をロード $C1/E9B4 STA $7ECD20,x[$7E:E960] ;Aを[$7E:E960]に書き込み $C1/E9B8 LDA $17 [$00:0317] ;Aに[$00:0317]をロード $C1/E9BA STA $7ECD30,x[$7E:E970] ;Aを[$7E:E970]に書き込み $C1/E9BE LDA $18 [$00:0318] ;Aに[$00:0318]をロード $C1/E9C0 STA $7ECE10,x[$7E:EA50] ;Aを[$7E:EA50]に書き込み $C1/E9C4 LDX $14 [$00:0314] ;Xに[$00:0314]をロード $C1/E9C6 INY ;Yをインクリメント +1 $C1/E9C7 DEC $09 [$00:0309] ;[$00:0309]をデクリメント -1 $C1/E9C9 INX ;Xをインクリメント +1 $C1/E9CA DEC $08 [$00:0308] ;[$00:0308]をデクリメント -1 $C1/E9CC BNE $97 [$E965] ;ゼロフラグが立っていないとき[$E965]分岐 $C1/E965 LDA $D50005,x[$D5:02B5] ;Aに[$D5:02B5](レベル01の技ID)をロード $C1/E969 STA $12 [$00:0312] ;Aを[$00:0312]に書き込み $C1/E96B BNE $06 [$E973] ;ゼロフラグが立っていないとき[$E973]分岐 $C1/E973 STX $14 [$00:0314] ;Xを[$00:0314]に書き込み $C1/E975 JSR $3D93 [$C1:3D93] ;[$C1:3D93]へジャンプ ;ループ処理ここまで
ややこしいので、どういう処理なのかをざっとまとめる。
$C1/E965で「クマの手」の技ID$A5を呼び出している。
$C1/E956~でサモのシナリオ別キャラデータ[$00:0F8E][$00:0F8D](習得済みの技2バイト)を[$00:0311][$00:0310]にコピーし、$C1/E99C~で一番下の1ビットに値が入っているかどうかで、現在呼び出している技IDの技を習得しているかどうかを判定する。
習得済みなら1が立っているため、右ローテート時にキャリーフラグが立ち(2で割り切れないため)、技習得と判断され、$C1/E9A6~以降で以下のように値がコピー先アドレスにコピーされる。
| 内容 | 値 | コピー先 |
|---|---|---|
| 技ID | $A5 | $7E:E940 |
| 技データ08(使用不能状態異常) | $F4 | $7E:E950 |
| 技データ13 | $00 | $7E:EA50 |
| 技データ14(反撃属性1) | $00 | $7E:E960 |
| 技データ15などから計算した反撃属性2の値 | $00 | $7E:E970 |
反撃属性1・反撃属性2は、2バイトで各属性への反撃属性(15種)が記録されている。
$7E:E970に入る反撃属性2の値は、$C1/E97E~あたりで計算されているが、詳細は省く。
ループの最後のあたり、$C1/E965で、次の技(レベル01の技ID)をロードしている。
$C1/E96Bでゼロフラグ判定をしているので、そのレベルでの習得技がない、つまり00が入っているのなら処理はスキップで、次のレベルの技をループしつつ判定していく。
次のレベルの技のコピー先は、上のアドレスを+1した場所になる。
つまり、技データ08のコピー先は、$7E:E950, $7E:E951, $7E:E952, ……となる。
もしサモがすべての技を覚えていたら$7E:E95Fまで値が入るが、今回は「サモがレベル5で功夫編の修行を行った場合」なので、サモは技レベル05までの6種類の技のデータしかコピーしない。
上コピー先は、あくまでも「習得済みの技」だけである、という点に注意。
つまり、この先は、$7E:E940~$7E:E94Fをチェックすることで、サモがどの技を習得済みか、かつ、習得済みの技IDが何なのかもわかるのである。
上の値は後で、敵種類1のデータと、敵番号0のデータにコピーされることになる。
なお、ざきとの戦闘では、前ページでの処理が入り、2戦目以降の使用技が変更されているので、上処理などで決まる使用技が1戦目とは変わることになる。
$C1/E894 STZ $0005,x[$00:1C45] ;[$00:1C45](味方キャラ番号2 経験値)に$00を書き込み $C1/E897 STZ $001E,x[$00:1C5E] ;[$00:1C5E]に$00を書き込み $C1/E89A LDA #$04 ;Aに$04をロード $C1/E89C STA $001F,x[$00:1C5F] ;A($04)を[$00:1C5F]に書き込み $C1/E89F STZ $11 [$00:0311] ;[$00:0311]に$00を書き込み $C1/E8A1 STX $14 [$00:0314] ;Xを[$00:0314]に書き込み $C1/E8A3 LDY $0002,x[$00:1C42] ;Yに[$00:1C42]をロード $C1/E8A6 LDA $0006,y[$00:0F86] ;Aに[$00:0F86](シナリオ別キャラデータ サモ レベル)をロード $C1/E8A9 STA $0038,x[$00:1C78] ;Aを[$00:1C78](味方キャラデータ2人目 LV(現在値))に書き込み $C1/E8AC LDA #$00 ;Aに$00をロード $C1/E8AE STA $0039,x[$00:1C79] ;Aを[$00:1C79](味方キャラデータ2人目 状態異常)に書き込み $C1/E8B1 LDA #$04 ;Aに$04をロード $C1/E8B3 STA $08 [$00:0308] ;Aを[$00:0308]に書き込み
ここから、「サモの敵キャラデータ」を、実際のサモのステータスに上書きしていく処理が開始になる。
カラクリ丸やざき1戦目の場合は、味方キャラ番号が異なる、つまりXの値が変わり[$0005,x]などのアドレスが変わっていくが、とりあえずサモの場合で追っていく。
$00:1C40~以降が味方キャラ番号2の数値で、ここまでで、
| アドレス | 値 | 内容 |
|---|---|---|
$00:1C40 | $0B | サモのキャラID |
$00:1C41 | $20 | 戦闘状況 |
この2つの値が入ったが、上の処理で更に値が入っている。
$00:0F80~がサモのシナリオ別キャラデータであり、LV(現在値)はそこからコピーしている。一方で経験値に$00がセットされている。
$00:1C79の状態異常は戦闘開始時なので$00にセットされている。
| アドレス | 値 | 内容 |
|---|---|---|
$00:1C40 | $0B | サモのキャラID |
$00:1C41 | $20 | 戦闘状況 |
$00:1C45 | $00 | 経験値 |
$00:1C5F | $04 | ? |
$00:1C78 | $05 | シナリオ別キャラデータのLV(現在値) |
$00:1C79 | $00 | 状態異常 |
この後は、力・速・体・知を、シナリオ別キャラデータから$00:1C??へコピーするループ処理である。
;ループ処理(1回目) $C1/E8B5 LDA $0010,y[$00:0F90] ;Aに[$00:0F90](サモ 力(力+装備上昇分))をロード $C1/E8B8 STA $0030,x[$00:1C70] ;Aを[$00:1C70](味方キャラデータ2人目 力(通常値))に書き込み $C1/E8BB STA $0034,x[$00:1C74] ;Aを[$00:1C74](味方キャラデータ2人目 力(現在値))に書き込み $C1/E8BE INX ;Xをインクリメント +1 $C1/E8BF INY ;Yをインクリメント +1 $C1/E8C0 INY ;Yをインクリメント +1 $C1/E8C1 INY ;Yをインクリメント +1 $C1/E8C2 DEC $08 [$00:0308] ;[$00:0308]をデクリメント -1 $C1/E8C4 BNE $EF [$E8B5] ;ゼロフラグが立っていないとき[$E8B5]分岐 ;ループ処理(1回目)ここまで ; ;ループ処理(2回目~4回目)省略 ; $C1/E8C6 LDX $14 [$00:0314] ;Xに[$00:0314]をロード $C1/E8C8 RTS ;サブルーチン戻り
シナリオ別キャラデータには、素のステータスと、装備補正分を加算したステータスが記録されているのだが、装備補正分を考慮したステータスが味方キャラデータの通常値及び現在値(現在値は戦闘中にバフやデバフで変動した値が入る)にコピーされる。
後にこの値がそのまま敵データにもコピーされるため、味方キャラとの戦闘時、力・速・体・知は、装備による増減が考慮された値になっていることがわかる。
功夫編の修行時、弟子の装備を外しておく方が戦闘の難易度が下がるということである。
中世編ラストバトルのストレイボウも、離脱前に装備を外しておけば少しは楽になるということである(ストレイボウ戦の場合は完封する方法もあるので、大差ないかもしれないが)。
| アドレス | 値 | 内容 |
|---|---|---|
$00:1C40 | $0B | サモのキャラID |
$00:1C41 | $20 | 戦闘状況 |
$00:1C45 | $00 | 経験値 |
$00:1C5F | $04 | ? |
$00:1C70 | $1C | シナリオ別キャラデータ 力(通常値) |
$00:1C71 | $05 | シナリオ別キャラデータ 速(通常値) |
$00:1C72 | $2B | シナリオ別キャラデータ 体(通常値) |
$00:1C73 | $07 | シナリオ別キャラデータ 知(通常値) |
$00:1C74 | $1C | シナリオ別キャラデータ 力(現在値) |
$00:1C75 | $05 | シナリオ別キャラデータ 速(現在値) |
$00:1C76 | $2B | シナリオ別キャラデータ 体(現在値) |
$00:1C77 | $07 | シナリオ別キャラデータ 知(現在値) |
$00:1C78 | $05 | シナリオ別キャラデータ LV(現在値) |
$00:1C79 | $00 | 状態異常 |
$C1/FA31 PHX ;Xをスタックにプッシュ $C1/FA32 REP #$20 ;Aを16bit幅に変更、Mフラグをクリア $C1/FA34 LDA $7E900E,x[$7E:AB0E] ;Aに[$7E:AB0F][$7E:AB0E]をロード $C1/FA38 TAY ;Aレジスタの値をYレジスタに転送 $C1/FA39 PHX ;Xをスタックにプッシュ $C1/FA3A LDX $0002,y[$00:1C42] ;Xに[$00:1C42]をロード $C1/FA3D LDA $0031,x[$00:0FB1] ;Aに[$00:0FB2][$00:0FB1](シナリオ別キャラデータ$31~32)をロード ;シナリオ別キャラデータ$32の下4ビットはフィールド吸収 $C1/FA40 STA $10 [$00:0310] ;Aを[$00:0311][$00:0310]に書き込み ;($00:0310:フィールド吸収) $C1/FA42 LDA $000A,x[$00:0F8A] ;Aに[$00:0F8B][$00:0F8A](シナリオ別キャラデータ 最大HP(2バイト))をロード $C1/FA45 PLX ;Xレジスタにスタックからプル $C1/FA46 STA $7E8F00,x[$7E:AA00] ;Aを[$7E:AA01][$7E:AA00](敵番号0のHP2バイト)に書き込み $C1/FA4A SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/FA4C LDA $001D,y[$00:1C5D] ;Aに[$00:1C5D]をロード $C1/FA4F ROR A ;Aをキャリーフラグを含めた9bitで右ローテート $C1/FA50 ROR A ;Aをキャリーフラグを含めた9bitで右ローテート $C1/FA51 ROR A ;Aをキャリーフラグを含めた9bitで右ローテート $C1/FA52 AND #$C0 ;Aと$C0で論理積 $C1/FA54 STA $0004,x[$00:1B04] ;Aを[$00:1B04]に書き込み
ここから敵データへステータスを書き込んでいく。
サモの場合、シナリオ別キャラデータの[$00:0F8B][$00:0F8A]の2バイトがHPの値だが、$C1/FA46で、[$7E:AA01][$7E:AA00](敵番号0のHP・2バイト分)に書き込まれている。
$C1/FA57 LDA $0030,y[$00:1C70] ;Aに[$00:1C70](味方キャラデータ2人目 力(通常値))をロード $C1/FA5A STA $7E8F03,x[$7E:AA03] ;Aを[$7E:AA03](敵番号0 力(現在値))に書き込み $C1/FA5E LDA $0031,y[$00:1C71] ;Aに[$00:1C71](味方キャラデータ2人目 速(通常値))をロード $C1/FA61 STA $7E8F04,x[$7E:AA04] ;Aを[$7E:AA04](敵番号0 速(現在値))に書き込み $C1/FA65 LDA $0032,y[$00:1C72] ;Aに[$00:1C72](味方キャラデータ2人目 体(通常値))をロード $C1/FA68 STA $7E8F05,x[$7E:AA05] ;Aを[$7E:AA05](敵番号0 体(現在値))に書き込み $C1/FA6C LDA $0033,y[$00:1C73] ;Aに[$00:1C73](味方キャラデータ2人目 知(通常値))をロード $C1/FA6F STA $7E8F06,x[$7E:AA06] ;Aを[$7E:AA06](敵番号0 知(現在値))に書き込み $C1/FA73 LDA $0038,y[$00:1C78] ;Aに[$00:1C78](味方キャラデータ2人目 LV(現在値))をロード $C1/FA76 STA $7E9000,x[$7E:AB00] ;Aを[$7E:AB00](敵番号0 LV(現在値))に書き込み $C1/FA7A LDY $0002,x[$00:1B02] ;Yに[$00:1B02]をロード $C1/FA7D LDA $7E8F03,x[$7E:AA03] ;Aに[$7E:AA03](味方キャラデータ2人目 力(通常値))をロード $C1/FA81 STA $0025,y[$00:1A25] ;Aを[$00:1A25](敵種類1 敵データ05 力)に書き込み $C1/FA84 LDA $7E8F04,x[$7E:AA04] ;Aに[$7E:AA04](味方キャラデータ2人目 速(通常値))をロード $C1/FA88 STA $0026,y[$00:1A26] ;Aを[$00:1A26](敵種類1 敵データ06 速)に書き込み $C1/FA8B LDA $7E8F05,x[$7E:AA05] ;Aに[$7E:AA05](味方キャラデータ2人目 体(通常値))をロード $C1/FA8F STA $0027,y[$00:1A27] ;Aを[$00:1A27](敵種類1 敵データ07 体)に書き込み $C1/FA92 LDA $7E8F06,x[$7E:AA06] ;Aに[$7E:AA06](味方キャラデータ2人目 知(通常値))をロード $C1/FA96 STA $0028,y[$00:1A28] ;Aを[$00:1A28](敵種類1 敵データ08 知)に書き込み $C1/FA99 LDA $7E9000,x[$7E:AB00] ;Aに[$7E:AB00](味方キャラデータ2人目 LV(現在値))をロード $C1/FA9D STA $000B,y[$00:1A0B] ;Aを[$00:1A0B](敵種類1 レベル)に書き込み
ここで、味方キャラデータの力・速・体・知・レベルが、敵番号0のステータス関係のアドレス及び、敵種類1のステータス関係のアドレスに一斉にコピーされている。ループ処理ではない。
この処理で、カラクリ丸と戦う場合、ころころムシのステータスが入っていた箇所の大半はカラクリ丸のステータスで上書きされることにもなる。
最終編の味方キャラとの戦闘時も、敵データのキューブのステータスに上書きされていく。
まだ全てが上書きされてはいない点に注意。
| アドレス | 値 | 内容 |
|---|---|---|
$7E:AA00 | $F0 | 敵番号0 現在HP(下1バイト) |
$7E:AA01 | $00 | 敵番号0 現在HP(上1バイト) |
$7E:AA03 | $1C | 敵番号0 力(現在値) |
$7E:AA04 | $05 | 敵番号0 速(現在値) |
$7E:AA05 | $2B | 敵番号0 体(現在値) |
$7E:AA06 | $07 | 敵番号0 知(現在値) |
$7E:AB00 | $05 | 敵番号0 LV(現在値) |
$00:1A0B | $05 | 敵種類1 レベル |
$00:1A25 | $1C | 敵種類1 敵データ05 力 |
$00:1A26 | $05 | 敵種類1 敵データ06 速 |
$00:1A27 | $2B | 敵種類1 敵データ07 体 |
$00:1A28 | $07 | 敵種類1 敵データ08 知 |
$C1/FAA0 LDA $10 [$00:0310] ;Aに[$00:0310](下4ビット:フィールド吸収)をロード $C1/FAA2 ASL A ;Aを算術左シフト *2 $C1/FAA3 ASL A ;Aを算術左シフト *2 $C1/FAA4 ASL A ;Aを算術左シフト *2 $C1/FAA5 ASL A ;Aを算術左シフト *2 $C1/FAA6 ORA $0021,y[$00:1A21] ;Aと[$00:1A21](敵データ01)で論理和 $C1/FAA9 STA $0021,y[$00:1A21] ;Aを[$00:1A21](上4ビット:フィールド吸収)に書き込み $C1/FAAC REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/FAAE LDA $7E8F00,x[$7E:AA00] ;Aに[$7E:AA01][$7E:AA00](敵番号0のHP2バイト)をロード $C1/FAB2 STA $0010,y[$00:1A10] ;Aを[$00:1A11][$00:1A10](敵種類1のHP2バイト)に書き込み
[$00:0310]には先に[$00:0FB1](シナリオ別キャラデータ$32)が入ったが、これは下1桁がフィールド吸収の値になる。
敵種類データ$21にあたる[$00:1A21]には敵データ01が入っており、上4ビット:フィールド吸収/下4ビット:移動頻度である。
シナリオ別キャラデータ$32の下1桁は、算術左シフト *2を4回繰り返すと上1桁に移動する。
元々の敵データに入っている[$00:1A21]上4ビットのフィールド吸収の値と、シナリオ別キャラデータ$32にあるフィールド吸収の値を加算して、新たに[$00:1A21]に設置、というのが$C1/FAA9の処理ということである。
ここでは「上書き処理」ではなく、「論理和」で処理しているのがポイントである。
つまり、元のシナリオ別キャラデータ$32の値も反映される。
シナリオ別キャラデータ$32のフィールド吸収の値は装備品の値を反映しているため、幕末編でカラクリ丸と戦う場合や、最終編でおぼろ丸を仲間にするための戦闘で、カラクリ丸やおぼろ丸が「水神のたび」「げんじのタビ」「コイツぁタマゲタ」のいずれかを装備していると、フィールド吸収能力がきちんと発動することになる。
他には、最終編でアキラを仲間にする時、アキラが「サンゴのゆびわ」を装備した状態で近未来編をクリアしていれば、水フィールド吸収能力が発動する。
装備品のフィールド吸収能力が反映されるのは、以上3キャラのみのはずである。
他にフィールド吸収能力がある装備は「マーメイドボトム」だが、「マーメイドボトム」は最終編でしか入手できないので、仲間との戦闘で装備しているキャラは存在しない。
なお、「論理和」で処理している理由は、敵データ01の下4ビットが移動頻度だからという理由もあると思われる。直前に算術左シフト4回行っているため、$C1/FAA6で論理和を取る時、Aに入っているのは下1桁が0の値なので、移動頻度に影響はない。
よって、敵データ01の下4ビットは上の計算で変動せず、元の値のまま維持される。
いずれにしても、功夫編の修行においては、弟子がフィールド吸収能力を持つことはないし、功夫編でダメージフィールドを発生させる手段もない。
$C1/FAAE~$C1/FAB2は、敵番号0のHPの値を敵種類1のHPの値にコピーしている。各2バイト。
これで、以下のように敵関係の値が決まった。
| アドレス | 値 | 内容 |
|---|---|---|
$7E:AA00 | $F0 | 敵番号0 現在HP(下1バイト) |
$7E:AA01 | $00 | 敵番号0 現在HP(上1バイト) |
$7E:AA03 | $1C | 敵番号0 力(現在値) |
$7E:AA04 | $05 | 敵番号0 速(現在値) |
$7E:AA05 | $2B | 敵番号0 体(現在値) |
$7E:AA06 | $07 | 敵番号0 知(現在値) |
$7E:AB00 | $05 | 敵番号0 LV(現在値) |
$00:1A0B | $05 | 敵種類1 レベル |
$00:1A10 | $F0 | 敵種類1 現在HP(下1バイト) |
$00:1A11 | $00 | 敵種類1 現在HP(上1バイト) |
$00:1A21 | $00 | 敵種類1 敵データ01(上4ビット:フィールド吸収/下4ビット:移動頻度) |
$00:1A25 | $1C | 敵種類1 敵データ05 力 |
$00:1A26 | $05 | 敵種類1 敵データ06 速 |
$00:1A27 | $2B | 敵種類1 敵データ07 体 |
$00:1A28 | $07 | 敵種類1 敵データ08 知 |
$C1/FAB5 LDA $7E900E,x[$7E:AB0E] ;Aに[$7E:AB0E]をロード $C1/FAB9 ADC #$000F ;A + $000F $C1/FABC TAX ;Aレジスタの値をXレジスタに転送 $C1/FABD SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/FABF PHY ;Yをスタックへプッシュ $C1/FAC0 LDY #$0310 ;Yに$0310をロード $C1/FAC3 LDA #$04 ;Aに$04をロード $C1/FAC5 STA $08 [$00:0308] ;Aを[$00:0308]に書き込み ; ;サモの習得技及び技IDチェックループ処理(1回目) $C1/FAC7 TXA ;Xレジスタの値をAレジスタに転送 $C1/FAC8 AND #$0F ;Aと$0Fで論理積 $C1/FACA BNE $06 [$FAD2] ;ゼロフラグが立っていないとき[$FAD2]分岐 $C1/FAD2 LDA $7ECD00,x[$7E:E94F] ;Aに[$7E:E94F]をロード $C1/FAD6 BEQ $20 [$FAF8] ;ゼロフラグが立っているとき[$FAF8]分岐 $C1/FAF8 TXA ;Xレジスタの値をAレジスタに転送 $C1/FAF9 AND #$0F ;Aと$0Fで論理積 $C1/FAFB BEQ $CA [$FAC7] ;ゼロフラグが立っているとき[$FAC7]分岐 $C1/FAFD DEX ;Xをデクリメント -1 $C1/FAFE BRA $C7 [$FAC7] ;フラグにかかわりなく常に分岐[$FAC7] ;ループ処理ここまで
ここから、敵データとして、サモの使用技関係の処理を行っていく。
既にだいぶ前の処理になってしまうが、サモが習得済みの技のみ、以下のように値をコピー済みである。
16種類の技IDが入るアドレス$7E:E940~$7E:E94Fは、習得済みでない場合(または該当レベルで覚えられる技がない場合)は$00が入っている。
| 値 | コピー先 |
|---|---|
| 技ID | $7E:E940~$7E:E94F |
| 技データ08(使用不能状態異常) | $7E:E950~$7E:E95F |
| 技データ13 | $7E:EA50~$7E:EA5F |
| 技データ14(反撃属性1) | $7E:E960~$7E:E96F |
| 技データ15(反撃属性2) | $7E:E970~$7E:E97F |
$C1/FAC7~$C1/FAFEは、サモの技を一番高レベルから順に、習得済みかどうか調べるためのループ処理である。
$C1/FAD2で、技IDが入るアドレスの中で、一番高レベルのアドレス$7E:E94Fから順に、低レベルへ向けてチェックしている。
上の1回目のループは、技レベル16の技を習得しているかどうかであり、レベル5のサモは未習得なので、$C1/FAD6でゼロフラグが立っている。
技レベル05(サモの場合は「ちんじゃおろーす」、技ID$AA)のループまでたどり着かないと、$C1/FAD6でゼロフラグが立たない。
;サモの習得技及び技IDチェックループ処理(11回目) $C1/FAC7 TXA ;Xレジスタの値をAレジスタに転送 $C1/FAC8 AND #$0F ;Aと$0Fで論理積 $C1/FACA BNE $06 [$FAD2] ;ゼロフラグが立っていないとき[$FAD2]分岐 $C1/FAD2 LDA $7ECD00,x[$7E:E945] ;Aに[$7E:E945]をロード $C1/FAD6 BEQ $20 [$FAF8] ;ゼロフラグが立っているとき[$FAF8]分岐 ;習得技IDが入っている(ゼロフラグOFF) $C1/FAD8 STA $0000,y[$00:0310] ;Aを[$00:0310]に書き込み $C1/FADB INY ;Yをインクリメント +1 $C1/FADC LDA $7ECD10,x[$7E:E955] ;Aに[$7E:E955]をロード $C1/FAE0 STA $0000,y[$00:0311] ;Aを[$00:0311]に書き込み $C1/FAE3 INY ;Yをインクリメント +1 $C1/FAE4 LDA $7ECD20,x[$7E:E965] ;Aに[$7E:E965]をロード $C1/FAE8 STA $0000,y[$00:0312] ;Aを[$00:0312]に書き込み $C1/FAEB INY ;Yをインクリメント +1 $C1/FAEC LDA $7ECD30,x[$7E:E975] ;Aに[$7E:E975]をロード $C1/FAF0 STA $0000,y[$00:0313] ;Aを[$00:0313]に書き込み $C1/FAF3 INY ;Yをインクリメント +1 $C1/FAF4 DEC $08 [$00:0308] ;[$00:0308]をデクリメント -1 $C1/FAF6 BEQ $08 [$FB00] ;ゼロフラグが立っているとき[$FB00]分岐 ;習得技IDなし(ゼロフラグON) $C1/FAF8 TXA ;Xレジスタの値をAレジスタに転送 $C1/FAF9 AND #$0F ;Aと$0Fで論理積 $C1/FAFB BEQ $CA [$FAC7] ;ゼロフラグが立っているとき[$FAC7]分岐 $C1/FAFD DEX ;Xをデクリメント -1 $C1/FAFE BRA $C7 [$FAC7] ;フラグにかかわりなく常に分岐[$FAC7] ;ループ処理ここまで
ループ11回目が、技レベル05のループにあたり、これ以下のレベルの技は習得済みであるから、$C1/FAD6でゼロフラグが立たない処理$C1/FAD8へ進む。
$C1/FAD8~の処理は、先に以下のように書き込まれた技ID、使用不能状態異常、反撃属性1、反撃属性2を、[$00:0310]、[$00:0311]、[$00:0312]、[$00:0313]に書き込む処理である。
| 値 | コピー先 |
|---|---|
| 技ID | $7E:E940~$7E:E94F |
| 技データ08(使用不能状態異常) | $7E:E950~$7E:E95F |
| 技データ13 | $7E:EA50~$7E:EA5F |
| 技データ14(反撃属性1) | $7E:E960~$7E:E96F |
| 技データ15(反撃属性2) | $7E:E970~$7E:E97F |
書き込むたびにYをインクリメント(+1)しているから、書き込み先のアドレスは[$00:0310]から順に1ずつ増えていくことになる。
要するにこのループでは、「習得済みの技の中で、高レベルの技から順に、技ID、使用不能状態異常、反撃属性1、反撃属性2を、[$00:0310]~に順にコピーしていく」という処理を行っている。
レベル5のサモの場合、
| 技レベル | 技名 | 技ID | 使用不能状態異常 | 反撃属性1 | 反撃属性2 |
|---|---|---|---|---|---|
| 技レベル05 | ちんじゃおろーす | $00:0310 | $00:0311 | $00:0312 | $00:0313 |
| 技レベル04 | トン足 | $00:0314 | $00:0315 | $00:0316 | $00:0317 |
| 技レベル03 | ばんばんじー | $00:0318 | $00:0319 | $00:031A | $00:031B |
| 技レベル02 | とうばんじゃん | $00:031C | $00:031D | $00:031E | $00:031F |
ここまで書き込まれるとループを抜ける。
というのは、ループ前に[$00:0308]に$04が入り、ループで[$00:0310]~に値が入った時は、$C1/FAF4で[$00:0308]をデクリメント(-1)している。
つまり、技のデータを4種類分、[$00:0310]~に入れた後([$00:031F]まで埋まる)、[$00:0308]の値は$00になり、$C1/FAF6でゼロフラグが立って[$FB00]にジャンプし、ループを抜けるのである。
技を4種類以上覚えていない場合はループ終わり近くの$C1/FAFBでループの戻りになる。初期レベル(レベル1)のユンの修行などが該当。
というのは、ループの最後でXはデクリメント(-1)されており、ループ前処理でXの下1桁が必ずFなので、-1されていくと技レベル00に到達した時に、Xの下1桁が必ず0になる。
$C1/FAF8で、Xレジスタの値をAレジスタに転送してから、Aと$0Fで論理積をとり、$C1/FAFBでゼロフラグ判定をしている。
下1桁が0の値と$0Fで論理積をとると、必ず$00になるため、ゼロフラグが立つが、ジャンプ先はループ頭である。
つまりXをデクリメントせずにまたループ処理をするのである。
すると、初期レベルのユンだったら、習得技が技レベル01と技レベル00しかないから、技レベル01→技レベル00→技レベル00→技レベル00とループすることになり、$00:031Fまで値が埋まる。
結局のところ、
「習得している技の中で高レベルから順に4種類の技のデータを$00:0310~$00:031Fに書き込む」
というループにより、味方キャラが敵対時の使用技4種が決まったことになる。
習得技が4種類未満ならデータにダブりが起きるが、結局のところ習得技すべてが選ばれることになる。
敵対時の使用技は以上のようにして決まっている。
最終編で高原やおぼろ丸を仲間にする時の戦闘で、現代編または幕末編のラーニング状況が反映され、高レベルで覚える技をラーニングで覚えていたら使ってくる仕組みは、以上のサブルーチンで生まれていることがわかった。
$C1/FAF6でゼロフラグが立って[$FB00]にジャンプし、ループを抜けた後の処理は以下のようになる。
$C1/FAF6 BEQ $08 [$FB00] ;ゼロフラグが立っているとき[$FB00]分岐 ; $C1/FB00 PLX ;Xレジスタにスタックからプル $C1/FB01 LDY #$0310 ;Yに$0310をロード $C1/FB04 LDA #$04 ;Aに$04をロード $C1/FB06 STA $08 [$00:0308] ;Aを[$00:0308]に書き込み ; ;$00:0310~を敵データに書き込むループ処理(1回目) $C1/FB08 LDA $0000,y[$00:0310] ;Aに[$00:0310]をロード $C1/FB0B INY ;Yをインクリメント +1 $C1/FB0C STA $002B,x[$00:1A2B] ;Aを[$00:1A2B](敵データ11 使用技1 技ID)に書き込み $C1/FB0F LDA $0000,y[$00:0311] ;Aに[$00:0311]をロード $C1/FB12 INY ;Yをインクリメント +1 $C1/FB13 STA $001A,x[$00:1A1A] ;Aを[$00:1A1A](技1が使用不可になるステータス異常)に書き込み $C1/FB16 LDA $0000,y[$00:0312] ;Aに[$00:0312]をロード $C1/FB19 INY ;Yをインクリメント +1 $C1/FB1A STA $0012,x[$00:1A12] ;Aを[$00:1A12](技1の反撃属性1)に書き込み $C1/FB1D LDA $0000,y[$00:0313] ;Aに[$00:0313]をロード $C1/FB20 INY ;Yをインクリメント +1 $C1/FB21 STA $0016,x[$00:1A16] ;Aを[$00:1A16](技1の反撃属性2)に書き込み $C1/FB24 INX ;Xをインクリメント +1 $C1/FB25 DEC $08 [$00:0308] ;[$00:0308]をデクリメント -1 $C1/FB27 BNE $DF [$FB08] ;ゼロフラグが立っていないとき[$FB08]分岐 ;ループ処理ここまで ; $C1/FB29 PLX ;Xレジスタにスタックからプル $C1/FB2A RTS ;サブルーチン戻り
$00:0310~$00:031Fに書き込まれた値を、1種類の技毎に、敵種類1のデータに書き込んでいくループ処理になる。
サモは以下のように値が入っていたが、
| 技レベル | 技名 | 技ID | 使用不能状態異常 | 反撃属性1 | 反撃属性2 |
|---|---|---|---|---|---|
| 技レベル05 | ちんじゃおろーす | $00:0310 | $00:0311 | $00:0312 | $00:0313 |
| 技レベル04 | トン足 | $00:0314 | $00:0315 | $00:0316 | $00:0317 |
| 技レベル03 | ばんばんじー | $00:0318 | $00:0319 | $00:031A | $00:031B |
| 技レベル02 | とうばんじゃん | $00:031C | $00:031D | $00:031E | $00:031F |
以下に書き込まれていくことになる。
つまり高レベルの技から順に使用技として登録されていくことがわかる。
| アドレス | 内容 |
|---|---|
$00:1A12 | 技1の反撃属性1 |
$00:1A13 | 技2の反撃属性1 |
$00:1A14 | 技3の反撃属性1 |
$00:1A15 | 技4の反撃属性1 |
$00:1A16 | 技1の反撃属性2 |
$00:1A17 | 技2の反撃属性2 |
$00:1A18 | 技3の反撃属性2 |
$00:1A19 | 技4の反撃属性2 |
$00:1A1A | 技1が使用不可になるステータス異常 |
$00:1A1B | 技2が使用不可になるステータス異常 |
$00:1A1C | 技3が使用不可になるステータス異常 |
$00:1A1D | 技4が使用不可になるステータス異常 |
$00:1A2B | 敵データ11 使用技1 技ID |
$00:1A2C | 敵データ12 使用技2 技ID |
$00:1A2D | 敵データ13 使用技3 技ID |
$00:1A2E | 敵データ14 使用技4 技ID |
ユンの場合だと、技1に「技レベル01」のデータが入り、技2~技4に「技レベル00」のデータが入ることで、結果的に使用技が2種類になる。
以上で、HP・力・速・体・知・レベル・使用技4種のデータが敵データとして登録された。
ここまでで戦闘前のデータが決まったことになる。
では、ここまでに決まった値を整理してみよう。
ほとんどの値が元の味方キャラのデータからコピーされたようではあるが、幾つか例外もある。
まず、敵に攻撃や防御の値を設定するメモリ(アドレス)がないため、反映されないことがわかる。
敵にも設定できる値はどうなっているかを見てみよう。
$00:1A20~$00:1A3Fには、「サモの敵キャラデータ」32バイト分をまずコピーしてから、以下の値で上書きされた、ということになる。
| アドレス | 内容 |
|---|---|
$7E:AA00 | 敵番号0 現在HP(下1バイト) |
$7E:AA01 | 敵番号0 現在HP(上1バイト) |
$7E:AA03 | 敵番号0 力(現在値) |
$7E:AA04 | 敵番号0 速(現在値) |
$7E:AA05 | 敵番号0 体(現在値) |
$7E:AA06 | 敵番号0 知(現在値) |
$7E:AB00 | 敵番号0 LV(現在値) |
$00:1A0B | 敵種類1 レベル |
$00:1A04 | 敵種類1 横の幅(必ず$01) |
$00:1A05 | 敵種類1 縦の幅(必ず$01) |
$00:1A10 | 敵種類1 現在HP(下1バイト) |
$00:1A11 | 敵種類1 現在HP(上1バイト) |
$00:1A12 | 敵種類1 技1の反撃属性1 |
$00:1A13 | 敵種類1 技2の反撃属性1 |
$00:1A14 | 敵種類1 技3の反撃属性1 |
$00:1A15 | 敵種類1 技4の反撃属性1 |
$00:1A16 | 敵種類1 技1の反撃属性2 |
$00:1A17 | 敵種類1 技2の反撃属性2 |
$00:1A18 | 敵種類1 技3の反撃属性2 |
$00:1A19 | 敵種類1 技4の反撃属性2 |
$00:1A1A | 敵種類1 技1が使用不可になるステータス異常 |
$00:1A1B | 敵種類1 技2が使用不可になるステータス異常 |
$00:1A1C | 敵種類1 技3が使用不可になるステータス異常 |
$00:1A1D | 敵種類1 技4が使用不可になるステータス異常 |
$00:1A20 | 敵種類1 敵データ00 (移動パターン味方キャラの敵キャラデータがそのまま入る) |
$00:1A21 | 敵種類1 敵データ01 (上4ビット:フィールド吸収/下4ビット:移動頻度。味方キャラの敵キャラデータがそのまま入る) |
$00:1A25 | 敵種類1 敵データ05 力 |
$00:1A26 | 敵種類1 敵データ06 速 |
$00:1A27 | 敵種類1 敵データ07 体 |
$00:1A28 | 敵種類1 敵データ08 知 |
$00:1A2B | 敵種類1 敵データ11 使用技1 技ID |
$00:1A2C | 敵種類1 敵データ12 使用技2 技ID |
$00:1A2D | 敵種類1 敵データ13 使用技3 技ID |
$00:1A2E | 敵種類1 敵データ14 使用技4 技ID |
味方キャラの元の値が反映されないのは、以下のステータスになる。
| アドレス | 内容 |
|---|---|
$00:1A2A | 敵データ10 無効状態異常 |
$00:1A3D | 敵データ29 背後補正/側面補正 |
$00:1A3E | 敵データ30 回避属性 8ビットが手足突鋭鈍締飛背に対応 |
$00:1A3F | 敵データ31 回避属性 8ビットが火水風土精善悪無に対応 |
上の値はシナリオ別キャラデータにも存在するが、その値が敵種類1の敵データに読み込まれない。
このため、サモなら「サモの敵キャラデータ」に入っていた値がそのまま適用されることになる。
敵キャラデータ(味方データが入っているID$EB以降)を見ると、キューブ(ID$FF)の敵データ10に$20が入っている以外、味方キャラのデータには$00が入っている。
よって、サモの場合、無効状態異常なし、背後補正も側面補正も0、回避属性もなし、となる。
サモは味方キャラデータだと、背後補正6、側面補正4、回避属性は突であり、装備によって無効状態異常や回避属性が変動するが、敵として登場する時にはそれらはすべて無視されることになる。
背後補正や側面補正が0になるということは、ほとんどのキャラで強化されることになる(側面や背面から攻撃しても、補正分のレベルが引かれないことになるため)。
ただし無効状態異常や回避属性がなくなるので、弱体化する部分もある。
そしてカラクリ丸だが、前述の通り、ころころムシのデータにカラクリ丸のデータを上書きしたため、上書きされない上の4種のステータスはころころムシと同一になってしまう。
ころころムシは、無効状態異常なし、回避属性は無属性以外すべて(15種)、側面補正4、背後補正6である。
味方キャラデータのカラクリ丸は、無効状態異常が毒・麻・眠・酔・石、回避属性は精、側面補正1、背後補正1である。
まったく別のデータに変わってしまっていることがわかる。
これが想定内なのかバグなのかはわからないが、プレイする上で重大な不具合が生じることはないし、HPやステータス、レベル、使用技などはカラクリ丸のデータなので、実際のプレイではさほど問題にはならないだろう。通常プレイなら、カラクリ丸と戦う機会はパーティに加わる時くらいだろうし、本作は無効状態異常や回避属性などが戦闘画面にはっきりと表示されることもないので気づかれにくいということもある。
更に、最終編での仲間との戦闘時も、敵データのキューブの値を上書きしたため、敵データ10の無効状態異常が$20、つまり眠り無効耐性がどのキャラにも付くことになる。
背後補正・側面補正はどちらも0で、回避属性もいっさいない。
元の味方キャラのデータは反映されないことになる。
これまた、これが想定内なのかバグなのかはわからないし、何かしらのバグが起こることもない。
そもそもキューブのデータにあたる敵データID$FFに、無効状態異常として$20が設定されているのが何故なのかもわからない。最初にも記したが、キューブ本人には眠り耐性はない。
何を意図した設定なのか、どうにもわからない。
元々味方キャラにはなかったステータスとして移動パターンがあるが、敵キャラデータで$00以外の移動パターンが設定されているのはストレイボウ、サンダウン、マッドドッグだけで、他は$00が入っている。
$00だとだいたい接近してきて技を出せるなら技を出すというパターンである。
ストレイボウと戦う時は妙な方向を向いたり移動することがあるが、移動パターン$06が設定されているためであり、おかげで3×2対角線を維持しつつ嵌めて倒すことが可能である。
以上が、最終編オルステッド主人公時以外の、味方キャラとの戦闘におけるステータス設定である。
最終編オルステッド主人公時は別途説明するが、実はこちらでも、敵対する味方キャラのデータとして敵データID$FFが全キャラで読み込まれてから上書きしていく。
このため、同じ仕組みで全キャラに眠り耐性がつくことになる。
高原 日勝の敵キャラデータ08(知)にだけ$08が入っていたが、結局このデータは使われないことになり、なぜここだけ$08が入っていたのかは謎のままである。
次ページからは、最終編オルステッド主人公時のサブルーチンや処理方法を解説していく。