基礎知識
戦闘関係
戦闘に勝利すると経験値を得るが、本作の経験値計算の仕様は経験値で述べている通り、独特である。
味方キャラのレベルと敵パーティに設定された「敵パーティレベル」から取得経験値が計算されることや、その計算方法は経験値に掲載している通りであるが、実際にプログラムではどう処理されているのかを紹介する。
まず復習として、本作における経験値の計算方法は以下のようになっている。
以上で計算された経験値を、キャラの現在の経験値を足して、100を越えたらレベルが1上がる。ただしレベルの最大値は99。
レベルアップ時に余剰の経験値が出ても、繰り越されない。
また、レベルは一度の戦闘で1しか上がらない。
本作の経験値の仕様は以上である。
経験値を計算する上で、味方キャラの現在のレベル、現在の経験値、敵パーティレベルといったステータス値が必要になることがわかる。
ということでまずは、味方キャラのレベルと経験値が、メモリのどこに格納されているのか、という話から始める。
味方キャラのステータスは、全シナリオ共通で、マップ上でも戦闘でも、メモリのアドレス$00:0D00~$00:0FBFにまとめて入っている。
また、同じ値が$7E:0D00~$7E:0FBFにミラーリングされている。
1キャラあたり64バイトの容量が使われているので、$00:0D00~$00:0FBFに入るのは11キャラ分のデータである。
シナリオにより、どこに誰のデータが入るか決まっているので、便宜上、「シナリオ別キャラデータ」としておく。
(データ上は、戦闘に参加しないキャラのデータが入ることもあるのだが、以下の表では省いた)
| メモリ | 原始 | SF | 功夫 | 西部 | 現代 | 近未来 | 幕末 | 中世 | 最終 |
|---|---|---|---|---|---|---|---|---|---|
$00:0D00~ | - | - | - | - | - | - | - | オルステッド | オルステッド |
$00:0D40~ | ポゴ | - | - | - | - | - | - | - | ポゴ |
$00:0D80~ | - | キャプテン スクウェア /キューブ | - | - | - | - | - | - | キューブ |
$00:0DC0~ | - | - | 心山拳老師 | - | - | - | - | - | 心山拳師範 |
$00:0E00~ | - | - | - | サンダウン | - | - | - | - | サンダウン |
$00:0E40~ | - | - | - | - | 高原 日勝 | - | - | - | 高原 日勝 |
$00:0E80~ | - | - | - | - | - | アキラ | - | - | アキラ |
$00:0EC0~ | - | - | - | - | - | - | おぼろ丸 | - | おぼろ丸 |
$00:0F00~ | ゴリ | - | ユン・ジョウ | マッドドッグ | - | タロイモ | とらわれの男 | ストレイボウ | - |
$00:0F40~ | べる | - | レイ・クウゴ | - | - | 無法松 | カラクリ丸 | ウラヌス | - |
$00:0F80~ | ざき | - | サモ・ハッカ | - | - | ブリキ大王 | - | ハッシュ | ブリキ大王 |
最初の8キャラ分のデータは各シナリオの主人公、残り3キャラは各シナリオで仲間になるキャラのデータが入ることがわかる。
(このデータに限ったことではないが、ほとんどのデータで一番上に来るのは中世編のデータであり、攻略本などで言われている通り「中世編を最初に制作した」ことからデータの並びが中世編から始まっているのだろう、と推測できる)
SF編は、ミニゲーム「キャプテンスクウェア」用のキャプテンスクウェアのデータ($00:0D80~)がラストバトル前まで使われている。内部データでは、プレイヤーがキューブに対して付けた名前が「キャプテンスクウェアの名前」として扱われ、$00:0D80~内にもそのまま入っている。プレイ中に名前を入力して扉を開く場面などでも、$00:0D80~に登録したキャラ名と一致しているかを判定しており、ラストバトルのみキューブのデータに変更する仕組みで、キャプテンスクウェアの画面が止まり「KILL YOU‥‥」が表示される寸前あたりに変更されている。
功夫編の枠である$00:0DC0~は、功夫編だと老師、最終編だと心山拳師範に選んだキャラのデータが入る。
経験値計算では、レベルと経験値を計算するため、各キャラに対応した値を$00:0D00~$00:0FBFからロードして使用している。
例えば同じ$00:0F00~のデータでも、原始編ならゴリ、中世編ならストレイボウ、というように異なるキャラの値が入っているという点に注意が必要。
シナリオ別キャラデータには、各キャラ64バイト分のデータがあると説明したが、そのデータに16進数で$00~$3Fと番号を付けたとすると、現在のレベルが入っているのが$06、経験値が入っているのが$1Eの位置に当たる。
オルステッドなら$00:0D06にレベル、$00:0D1Eに経験値の値が入っている。
アキラなら$00:0E86にレベル、$00:0E9Eに経験値の値が入っている。
$00:0F06に入っているのは、原始編ならゴリのレベル、功夫編ならユンのレベル、幕末編ならとらわれの男のレベル、中世編ならストレイボウのレベル、ということになる。
以上の$00:0D00~$00:0FBFのシナリオ別キャラデータは、どのシナリオでも共通で存在している。
たとえば中世編プレイ中、他シナリオのキャラは一切登場しないが、$00:0D40~には原始編クリア時のポゴのデータが入ったままである。他シナリオの主人公たちのデータも同様に残っていて、最終編ではそれらデータがそのまま読み出されることになる。
また中世編シナリオが出現する前だと、$00:0D00~$00:0D3Fのオルステッドのデータは、初期値(オルステッドのレベル1のデータ)が入っている。この仕様は未プレイのシナリオなら共通。
つまりシナリオ別キャラデータには、各キャラのステータスに加え、現代編で高原がラーニングした技や、プレイヤーが主人公につけた名前(拳法名)及び装備品のデータも格納されており、セーブデータにも記録され、最終編に引き継がれている。
シナリオ別キャラデータとは別に、戦闘中のみ読み書きされる味方のデータがある。
こちらのデータは毎回の戦闘でのみ使われ、味方1人目が$00:1C00~$00:1C3F、2人目が$00:1C40~$00:1C7F、3人目が$00:1C80~$00:1CBF、4人目が$00:1CC0~$00:1CFFに読み込まれる。
($7E:1C00~$7E:1CFFのミラーリングもある)
こちらは戦闘中のみ変動する値(残りHPや状態異常の状況など)を読み書きするために使うようだが、ここにも各キャラの通常時のレベルと経験値が読み込まれる。
最初のアドレスには各キャラのIDが入り、レベルは+$02したアドレスに、経験値は+$05したアドレスに入る。
また、+$01したアドレスには、その時点でのキャラの状態が入っているのだが、通常は$FF、戦闘離脱すると$00、ブリキ大王操作時及び、最終編でオルステッド主人公時に各シナリオのラストボスを操作する時には$40が入る。
ブリキ大王を操作する際、ブリキ大王のステータスは実は敵データとして登録されているので、「敵操作時かどうか」「戦闘離脱かどうか」のフラグをチェックしている値ということになる。
このあたりが、経験値計算に必要な味方側の値となる。
経験値計算では、シナリオ別キャラデータ内のキャラのレベル&経験値、戦闘中用データのキャラのレベル&経験値、どちらも使われることになる。
戦闘前にはシナリオ別キャラデータからレベル&経験値の数値を呼び出し、サブルーチン中では戦闘中用データで計算処理、最終的にシナリオ別キャラデータを新たなレベル&経験値に更新しなければならないからである。
経験値計算のサブルーチンでは、Xに「戦闘中用データを呼び出すための数値」、Yに「シナリオ別キャラデータを呼び出すための数値」が入るため、
[$00??,x]のアドレスで読み書きされるのが戦闘中用データ[$00??,y]のアドレスで読み書きされるのがシナリオ別キャラデータと見分けることができる。
もうひとつ必要になるのが「敵パーティレベル」である。
敵パーティ関係の値は、戦闘開始時に読み込まれている。
$C1/F60E LDA $D60000,x ;Aに[$D60000,x](敵パーティレベル)をロード $C1/F612 STA $55 [$00:0355] ;Aを[$00:0355]に書き込み $C1/F614 LDA $D60001,x ;Aに[$D60001,x](ブリキ大王操作時は$01、それ以外は$00)をロード $C1/F618 STA $56 [$00:0356] ;Aを[$00:0356]に書き込み $C1/F61A LDA $D60006,x ;Aに[$D60006,x](上1桁がアイテム入手率補正、下1桁が敵の総数)をロード $C1/F61E STA $58 [$00:0358] ;Aを[$00:0358]に書き込み
経験値計算に関係のない値もおまけで紹介したが、[$00:0355]に敵パーティレベル、[$00:0356]に操作キャラ(ブリキ大王かどうかの判定の模様)、[$00:0358]にアイテム入手率補正と敵の総数が書き込まれる。最後についてはドロップアイテム判定でも紹介した通りである。
経験値計算に必要となるのは、[$00:0355]に入った敵パーティレベルの値である。
前置きが長くなったが、実際にどのように経験値計算をしているのか、該当のサブルーチンを紹介する。
このサブルーチンは戦闘勝利時の「勝利ッ!!」という表示が出た直後に処理される。
順序としては、味方キャラの人数だけ「経験値取得判定と計算→レベルアップするキャラがいるならレベルアップ表示」を繰り返した後、ドロップアイテム判定→ドロップアイテムがあれば表示、という順序になっている。
$C1/2363 LDA $55 [$00:0355] ;Aに[$00:0355](敵パーティレベル)をロード $C1/2365 BEQ $18 [$237F] ;ゼロフラグが立っているとき[$237F]分岐 $C1/2367 LDX #$1C00 ;(味方キャラ1用処理)Xに$1C00をロード $C1/236A JSR $2397 [$C1:2397] ;[$C1:2397]にジャンプ $C1/236D LDX #$1C40 ;(味方キャラ2用処理)Xに$1C40をロード $C1/2370 JSR $2397 [$C1:2397] ;[$C1:2397]にジャンプ $C1/2373 LDX #$1C80 ;(味方キャラ3用処理)Xに$1C80をロード $C1/2376 JSR $2397 [$C1:2397] ;[$C1:2397]にジャンプ $C1/2379 LDX #$1CC0 ;(味方キャラ4用処理)Xに$1CC0をロード $C1/237C JSR $2397 [$C1:2397] ;[$C1:2397]にジャンプ $C1/237F RTS ;サブルーチン終了 $C1/2397 LDA $0001,x ;Aに[$0001,x]をロード(キャラの状態) $C1/239A BIT #$40 ;Aと$40で論理積(ステータスフラグの変更のみ) $C1/239C BEQ $38 [$23D6] ;ゼロフラグが立っているとき[$23D6]分岐 $C1/239E LDY $0002,x ;Yに[$0002,x](味方キャラレベル)をロード $C1/23A1 LDA $0000,x ;Aに[$0000,x](味方キャラID)をロード $C1/23A4 CMP #$08 ;Aと$08を減算比較(キャラID$08は心山拳老師) $C1/23A6 BEQ $2E [$23D6] ;ゼロフラグが立っているとき[$23D6]分岐 $C1/23A8 CMP #$12 ;Aと$12を減算比較(キャラID$08はタロイモ) $C1/23AA BEQ $2A [$23D6] ;ゼロフラグが立っているとき[$23D6]分岐 $C1/23AC CMP #$14 ;Aと$14を減算比較(キャラID$14はキューブ) $C1/23AE BEQ $26 [$23D6] ;ゼロフラグが立っているとき[$23D6]分岐 $C1/23B0 LDA $C0FFBC[$C0:FFBC] ;Aに[$C0:FFBC]をロード $C1/23B4 BNE $08 [$23BE] ;ゼロフラグが立っていないとき[$23BE]分岐 $C1/23BE LDA $0020,x ;Aに[$0020,x]をロード(戦闘中行動フラグ 行動すると80) $C1/23C1 BPL $14 [$23D7] ;ネガティブフラグが立っていないとき[$23D7]分岐 $C1/23C3 LDA $0006,y ;Aに[$0006,y](味方キャラレベル)をロード $C1/23C6 CMP #$63 ;Aと$63(99・レベル最大値)を減算比較 $C1/23C8 BCS $0C [$23D6] ;キャリーフラグが立っているとき[$23D6]分岐 $C1/23CA LDA $55 [$00:0355] ;Aに[$00:0355](敵パーティレベル)をロード $C1/23CC SEC ;キャリーフラグを立てる(引き算用) $C1/23CD SBC $0006,y ;A - [$0006,y] ※「敵パーティレベル - 味方キャラレベル」 $C1/23D0 BCC $05 [$23D7] ;キャリーフラグが立っていないとき[$23D7]分岐 $C1/23D2 BEQ $03 [$23D7] ;ゼロフラグが立っているとき[$23D7]分岐 $C1/23D4 BRA $2C [$2402] ;フラグにかかわりなく常に[$2402]分岐 $C1/23D6 RTS ;サブルーチン終了 ;敵パーティレベル≦味方キャラレベル、または経験値が増えない行動を取った場合 $C1/23D7 LDA #$10 ;Aに$10(10進数16)をロード $C1/23D9 STA $4204 [$00:4204] ;符号付16bit / 8bit 被除数(下2バイト) $C1/23DC LDA #$00 ;Aに$00をロード $C1/23DE STA $4205 [$00:4205] ;符号付16bit / 8bit 被除数(上2バイト) $C1/23E1 LDA $0006,y ;Aに[0006,y](味方キャラレベル)をロード $C1/23E4 STA $4206 [$00:4206] ;符号付16bit / 8bit 除数 ※除算は「$0010/味方キャラレベル = 16/味方キャラレベル」 $C1/23E7 JSR $46C8 [$C1:46C8] ;[$C1:46C8]へジャンプ(計算待機用) $C1/46C8 NOP ;(符号付16bit / 8bitの計算待機) $C1/46C9 RTS ;サブルーチン終了 $C1/23EA LDA $55 [$00:0355] ;Aに[$00:0355](敵パーティレベル)をロード $C1/23EC LSR A ;Aを論理右シフト(/2) ※敵パーティレベル/2 $C1/23ED CLC ;キャリーフラグをクリア $C1/23EE ADC $4214 [$00:4214] ;A + [$00:4214] ※敵パーティレベル/2 + 16/味方キャラレベル $C1/23F1 BNE $01 [$23F4] ;ゼロフラグが立っていないとき[$23F4]分岐 $C1/23F3 INC A ;Aをインクリメント(+1) ※「敵パーティレベル/2 + 16/味方キャラレベル」の結果が0の時は+1 $C1/23F4 CLC ;キャリーフラグをクリア $C1/23F5 ADC $001E,y ;A + [$001E,y] ※キャラの経験値に計算結果を足す $C1/23F8 BCS $25 [$241F] ;キャリーフラグが立っているとき[$241F]分岐 $C1/23FA CMP #$64 ;Aと$64(100)を減算比較 $C1/23FC BCS $21 [$241F] ;キャリーフラグが立っているとき[$241F]分岐 $C1/23FE STA $001E,y ;Aを[$001E,y]に書き込み ※経験値の値を更新 $C1/2401 RTS ;サブルーチン終了 ;敵パーティレベル≦味方キャラレベル、または経験値が増えない行動を取った場合 ここまで ;敵パーティレベル>味方キャラレベル、かつ経験値が増える行動を取った場合 $C1/2402 LDA $55 [$00:0355] ;Aに[$00:0355](敵パーティレベル)をロード $C1/2404 SEC ;キャリーフラグを立てる(引き算用) $C1/2405 SBC $0006,y ;A - [$0006,y] ※「敵パーティレベル - 味方キャラレベル」 $C1/2408 BIT #$F0 ;Aと$F0で論理積(フラグだけ変更) ※「敵パーティレベル - 味方キャラレベル」の161の位の判定 $C1/240A BNE $13 [$241F] ;ゼロフラグが立っていないとき[$241F]分岐 ※「敵パーティレベル - 味方キャラレベル」が$10以上なのでレベルアップ確定 $C1/240C ASL A ;算術左シフト(×2) $C1/240D ASL A ;算術左シフト(×2) $C1/240E ASL A ;算術左シフト(×2) $C1/240F ASL A ;算術左シフト(×2) ※(「敵パーティレベル - 味方キャラレベル」)*$10 $C1/2410 ORA #$08 ;Aと$08(%0000 1000)で論理和(+$08) $C1/2412 ADC $001E,y ;A + [$001E,y](味方キャラ経験値) $C1/2415 BCS $08 [$241F] ;キャリーフラグが立っているとき[$241F]分岐 $C1/2417 CMP #$64 ;Aと$64(100)を減算比較 $C1/2419 BCS $04 [$241F] ;キャリーフラグが立っているとき[$241F]分岐 $C1/241B STA $001E,y ;Aを[$001E,y]に書き込み ※経験値の値を更新 $C1/241E RTS ;サブルーチン終了 ;敵パーティレベル>味方キャラレベル、かつ経験値が増える行動を取った場合 ここまで ;レベルアップ時の処理 $C1/241F LDA $0005,x ;Aに[$0005,x](味方キャラ経験値)をロード $C1/2422 STA $001C,x ;Aを[$001C,x]に書き込み $C1/2425 LDA #$00 ;Aに$00をロード $C1/2427 STA $0005,x ;Aを[$0005,x](味方キャラ経験値)に書き込み $C1/242A LDA $0006,y ;Aに[$0006,y](味方キャラレベル)をロード $C1/242D INC A ;Aをインクリメント(+1) $C1/242E CMP #$64 ;Aと$64(100)を減算比較(レベルが100かどうか) $C1/2430 BEQ $A4 [$23D6] ;ゼロフラグが立っているとき[$23D6]分岐 $C1/2432 STA $0006,y ;Aを[$0006,y](味方キャラレベル)に書き込み ※レベル更新 $C1/2435 LDA #$00 ;Aに$00をロード $C1/2437 STA $001E,y ;Aを[$001E,y](キャラ経験値)に書き込み $C1/243A PHX ;Xをスタックにプッシュ $C1/243B PHY ;Yをスタックにプッシュ $C1/243C TXY ;Xの値をYに転送 $C1/243D JSR $273C [$C1:273C] ;[$C1:273C]へ ;(レベルアップ時の表示&モーション表示のサブルーチンへ) ;(味方キャラが複数なら次キャラの判定へ)
長いが順に説明していく。
$C1/2363 LDA $55 [$00:0355] ;Aに[$00:0355](敵パーティレベル)をロード $C1/2365 BEQ $18 [$237F] ;ゼロフラグが立っているとき[$237F]分岐 $C1/2367 LDX #$1C00 ;(味方キャラ1用処理)Xに$1C00をロード $C1/236A JSR $2397 [$C1:2397] ;[$C1:2397]にジャンプ $C1/236D LDX #$1C40 ;(味方キャラ2用処理)Xに$1C40をロード $C1/2370 JSR $2397 [$C1:2397] ;[$C1:2397]にジャンプ $C1/2373 LDX #$1C80 ;(味方キャラ3用処理)Xに$1C80をロード $C1/2376 JSR $2397 [$C1:2397] ;[$C1:2397]にジャンプ $C1/2379 LDX #$1CC0 ;(味方キャラ4用処理)Xに$1CC0をロード $C1/237C JSR $2397 [$C1:2397] ;[$C1:2397]にジャンプ $C1/237F RTS ;サブルーチン終了
最初に行われるのは[$00:0355]の値、つまり敵パーティレベルの値による分岐で、敵パーティレベルが0の時はこの後の経験値計算処理すべてが飛ばされる。
各シナリオのラストバトル、現代編や西部編、SF編などの戦闘は敵パーティレベルがすべて0に設定されているので、この最初の分岐により、経験値計算自体がされない。
よって、経験値計算が行われるのは、敵パーティレベルが1以上の時、ということになる。
その後は、これ以前の処理で、味方キャラ1~4番目によりXに読み込む値を変え、経験値計算処理をするため、以下の[$C1:2397]にジャンプすることになる。
$C1/2397 LDA $0001,x ;Aに[$0001,x]をロード(キャラの状態) $C1/239A BIT #$40 ;Aと$40で論理積(ステータスフラグの変更のみ) $C1/239C BEQ $38 [$23D6] ;ゼロフラグが立っているとき[$23D6]分岐 $C1/239E LDY $0002,x ;Yに[$0002,x](味方キャラレベル)をロード $C1/23A1 LDA $0000,x ;Aに[$0000,x](味方キャラID)をロード $C1/23A4 CMP #$08 ;Aと$08を減算比較(キャラID$08は心山拳老師) $C1/23A6 BEQ $2E [$23D6] ;ゼロフラグが立っているとき[$23D6]分岐 $C1/23A8 CMP #$12 ;Aと$12を減算比較(キャラID$08はタロイモ) $C1/23AA BEQ $2A [$23D6] ;ゼロフラグが立っているとき[$23D6]分岐 $C1/23AC CMP #$14 ;Aと$14を減算比較(キャラID$14はキューブ) $C1/23AE BEQ $26 [$23D6] ;ゼロフラグが立っているとき[$23D6]分岐 $C1/23B0 LDA $C0FFBC[$C0:FFBC] ;Aに[$C0:FFBC]をロード $C1/23B4 BNE $08 [$23BE] ;ゼロフラグが立っていないとき[$23BE]分岐
この後も経験値計算を行うかどうかの判断が続く。
$C1/2397で呼び出している[$0001,x]は、先に説明した「キャラの状態」で、戦闘終了時の状況をロードする。
通常は$FF、戦闘離脱すると$00、ブリキ大王操作時及び、最終編でオルステッド主人公時に各シナリオのラストボスを操作する時には$40が入っている。
次の$C1/239AでAと$40で論理積を取り、ゼロフラグが立っているとき[$23D6]分岐、と処理されている。
$00と$40の論理積は0、$40と$40の論理積は$40、$FFと$40の論理積は$40なので、ゼロフラグが立つのは「戦闘離脱しているキャラ」の時であり、[$23D6]へジャンプすることになる。
飛び先の[$23D6]は経験値計算を飛ばすことになるため、ここで「戦闘離脱しているキャラ」は経験値計算をしない、という条件分岐が行われたことになる。
この先も「ゼロフラグが立っているとき[$23D6]分岐」が続く。
$C1/239EでYに味方キャラレベルをロードした後、Aに[$0000,x]をロードしているが、これは味方キャラのIDである。
操作可能な味方キャラには$00から$16までIDが振られており、上では$C1/23A4~$C1/23AEで連続して、$08、$12、$14と比較しているが、これはそれぞれ心山拳老師、タロイモ、キューブのIDである。
つまり戦闘で経験値が得られないキャラ3人は、ここで経験値計算をしない、という条件分岐が行われて[$23D6]にジャンプする。
最後の$C1/23B0についてはなぜこれを行っているのかよくわからないが、[$C0:FFBC]には$06が入っているので、ゼロフラグは立たずに[$23BE]に飛ぶ。
ここまでの処理でネガティブフラグが立っている場合、$C1/23B0でネガティブフラグをオフにできるので、その手のフラグ操作を行っているのかもしれないが、筆者にはよくわからない。
$C1/23BE LDA $0020,x ;Aに[$0020,x]をロード(戦闘中行動フラグ 行動すると80) $C1/23C1 BPL $14 [$23D7] ;ネガティブフラグが立っていないとき[$23D7]分岐 $C1/23C3 LDA $0006,y ;Aに[$0006,y](味方キャラレベル)をロード $C1/23C6 CMP #$63 ;Aと$63(99・レベル最大値)を減算比較 $C1/23C8 BCS $0C [$23D6] ;キャリーフラグが立っているとき[$23D6]分岐 $C1/23CA LDA $55 [$00:0355] ;Aに[$00:0355](敵パーティレベル)をロード $C1/23CC SEC ;キャリーフラグを立てる(引き算用) $C1/23CD SBC $0006,y ;A - [$0006,y] ※「敵パーティレベル - 味方キャラレベル」 $C1/23D0 BCC $05 [$23D7] ;キャリーフラグが立っていないとき[$23D7]分岐 $C1/23D2 BEQ $03 [$23D7] ;ゼロフラグが立っているとき[$23D7]分岐 $C1/23D4 BRA $2C [$2402] ;フラグにかかわりなく常に[$2402]分岐 $C1/23D6 RTS ;サブルーチン終了
$C1/23BEではAに[$0020,x]をロードしているが、このアドレスは、「戦闘開始時は$00が入っており、技を出すかアイテムを使うと$80が入る」処理が行われるメモリである。
つまり、経験値計算で必要な、「経験値が増える行動を取ったかどうか」を判断するフラグである。
次の$C1/23C1で、ネガティブフラグが立っていない場合は[$23D7]に分岐となっているが、$80は2進数の%1000 0000で、頭に「1」がついているので負数(最上位ビットが1なら負数)であり、ネガティブフラグが立つ。
よって、「経験値が増える行動を取っていない」時に[$23D7]にジャンプということであり、[$23D7]からの処理は「敵パーティレベル≦味方キャラレベル、または経験値が増えない行動を取った場合」の経験値計算であろう、と推測できるが、実際にその通りである。
$C1/23C3ではAに[$0006,y](味方キャラレベル)をロードし、$63と比較しているが、$63は10進数だと99。
味方キャラのレベルが99の場合、レベルアップ処理をする必要がないので、[$23D6]にジャンプする。
$C1/23CAからは、「敵パーティレベル - 味方キャラレベル」の計算を行っている。
[$00:0355]に入っている敵パーティレベルをロードしてから、キャリーフラグを立て(引き算の繰り下がりに備えている)、[$0006,y](味方キャラレベル)を引いている。
引き算の結果が負の時は$C1/23D0のキャリーフラグが立っていないときに当たり、引き算の結果が0の時は$C1/23D2のゼロフラグが立っているときであり、どちらも[$23D7]にジャンプする。
つまり、「敵パーティレベル≦味方キャラレベル、または経験値が増えない行動を取った場合」の経験値計算に飛ぶ。
引き算の結果が正の時だけ、$C1/23D4で[$2402]にジャンプすることから、この先が「敵パーティレベル>味方キャラレベル、かつ経験値が増える行動を取った場合」の経験値計算である。
;敵パーティレベル≦味方キャラレベル、または経験値が増えない行動を取った場合 $C1/23D7 LDA #$10 ;Aに$10(10進数16)をロード $C1/23D9 STA $4204 [$00:4204] ;符号付16bit / 8bit 被除数(下2バイト) $C1/23DC LDA #$00 ;Aに$00をロード $C1/23DE STA $4205 [$00:4205] ;符号付16bit / 8bit 被除数(上2バイト) $C1/23E1 LDA $0006,y ;Aに[0006,y](味方キャラレベル)をロード $C1/23E4 STA $4206 [$00:4206] ;符号付16bit / 8bit 除数 ※除算は「$0010/味方キャラレベル = 16/味方キャラレベル」 $C1/23E7 JSR $46C8 [$C1:46C8] ;[$C1:46C8]へジャンプ(計算待機用) $C1/46C8 NOP ;(符号付16bit / 8bitの計算待機) $C1/46C9 RTS ;サブルーチン終了 $C1/23EA LDA $55 [$00:0355] ;Aに[$00:0355](敵パーティレベル)をロード $C1/23EC LSR A ;Aを論理右シフト(/2) ※敵パーティレベル/2 $C1/23ED CLC ;キャリーフラグをクリア $C1/23EE ADC $4214 [$00:4214] ;A + [$00:4214] ※敵パーティレベル/2 + 16/味方キャラレベル $C1/23F1 BNE $01 [$23F4] ;ゼロフラグが立っていないとき[$23F4]分岐 $C1/23F3 INC A ;Aをインクリメント(+1) ※「敵パーティレベル/2 + 16/味方キャラレベル」の結果が0の時は+1 $C1/23F4 CLC ;キャリーフラグをクリア $C1/23F5 ADC $001E,y ;A + [$001E,y] ※キャラの経験値に計算結果を足す $C1/23F8 BCS $25 [$241F] ;キャリーフラグが立っているとき[$241F]分岐 $C1/23FA CMP #$64 ;Aと$64(100)を減算比較 $C1/23FC BCS $21 [$241F] ;キャリーフラグが立っているとき[$241F]分岐 $C1/23FE STA $001E,y ;Aを[$001E,y]に書き込み ※経験値の値を更新 $C1/2401 RTS ;サブルーチン終了
以上が、「敵パーティレベル≦味方キャラレベル、または経験値が増えない行動を取った場合」の経験値計算である。
ここでは65C816命令表 ロード・ストア命令 - 乗除算の符号付16bit / 8bit、つまり16進数4ビット÷16進数2ビットの割り算のやり方で計算を行っている。
被除数(下2バイト)として$10(10進数16)、被除数(上2バイト)として$00、除数に[0006,y](味方キャラレベル)をセットしていることから、
$0010 / 味方キャラレベル
という割り算を行っている。
$0010は10進数で16なので、
16 / 味方キャラレベル
ということになる。10進数計算なら小数点は切り捨てである。
つまり、
獲得経験値 = trunc(敵パーティレベル / 2) + trunc(16 / 味方キャラレベル)
の、trunc(16 / 味方キャラレベル)の部分になる。
割り算の計算結果は[$00:4214]に入るのだが、計算結果が出る前の$C1/23EA~$C1/23ECで、敵パーティレベルを論理右シフト、つまり÷2している。
これは上の計算式のtrunc(敵パーティレベル / 2)の部分である。
最終的に、$C1/23EEで、trunc(敵パーティレベル / 2)に割り算の結果を足し算しているから、$C1/23EEの計算結果は、
獲得経験値 = trunc(敵パーティレベル / 2) + trunc(16 / 味方キャラレベル)
まさにこれである。
$C1/23F1~$C1/23F3は、上の計算結果が0の時のみインクリメント(+1)する処理である。
ただし、上の計算結果が0になるのは、敵パーティレベルが1で味方キャラレベルが17以上という、あまりない状況の時である。
(たとえば中世編のアイアンビートル×3の敵パーティレベルが1なので、中世編の味方キャラのレベルが17以上の時が該当する)
あまりない状況とはいえ、「経験値が得られる戦闘では、最低でも経験値を1得られるようにする」という処理がきちんと入っていることがわかる。
このようにして、「敵パーティレベル≦味方キャラレベル、または経験値が増えない行動を取った場合」の経験値が計算できた。
$C1/23F5は、[$001E,y]と計算結果を足し算している。つまり、戦闘前のキャラの経験値と、戦闘で得た経験値を足している。
足し算の計算結果が10進数で100以上になればレベルアップというのが本作の仕様であるから、ここでレベルアップするかしないかの判定が行われていることになる。
$C1/23F8では、足し算の時点でキャリーフラグが立っているのなら[$241F]へジャンプとなっているが、[$241F]以降がレベルアップ処理である。
この時点では8bitモードなので、キャリーフラグは2バイトを越えた時、つまり$FFより1多い$100(10進数256)以上の計算結果となった時に立つ。
256は100を越えているから、当然レベルアップである。
続いて、$C1/23FAでは足し算結果と$64(10進数100)を減算比較している。減算の結果0以上ならキャリーフラグが立ち、レベルアップ処理に飛ぶ。
キャリーフラグが立たない時はレベルアップしないので、足し算結果がそのまま戦闘終了時の経験値ということになり、[$001E,y]、つまりシナリオ別キャラデータの経験値として新たに書き込まれて経験値計算終了である。
;敵パーティレベル>味方キャラレベル、かつ経験値が増える行動を取った場合 $C1/2402 LDA $55 [$00:0355] ;Aに[$00:0355](敵パーティレベル)をロード $C1/2404 SEC ;キャリーフラグを立てる(引き算用) $C1/2405 SBC $0006,y ;A - [$0006,y] ※「敵パーティレベル - 味方キャラレベル」 $C1/2408 BIT #$F0 ;Aと$F0で論理積(フラグだけ変更) ※「敵パーティレベル - 味方キャラレベル」の161の位の判定 $C1/240A BNE $13 [$241F] ;ゼロフラグが立っていないとき[$241F]分岐 ※「敵パーティレベル - 味方キャラレベル」が$10以上なのでレベルアップ確定 $C1/240C ASL A ;算術左シフト(×2) $C1/240D ASL A ;算術左シフト(×2) $C1/240E ASL A ;算術左シフト(×2) $C1/240F ASL A ;算術左シフト(×2) ※(「敵パーティレベル - 味方キャラレベル」)*$10 $C1/2410 ORA #$08 ;Aと$08(%0000 1000)で論理和(+$08) $C1/2412 ADC $001E,y ;A + [$001E,y](味方キャラ経験値) $C1/2415 BCS $08 [$241F] ;キャリーフラグが立っているとき[$241F]分岐 $C1/2417 CMP #$64 ;Aと$64(100)を減算比較 $C1/2419 BCS $04 [$241F] ;キャリーフラグが立っているとき[$241F]分岐 $C1/241B STA $001E,y ;Aを[$001E,y]に書き込み ※経験値の値を更新 $C1/241E RTS ;サブルーチン終了
こちらは、「敵パーティレベル>味方キャラレベル、かつ経験値が増える行動を取った場合」の経験値計算処理である。
まず、先の$C1/23CA~$C1/23CDと同じ方法で、「敵パーティレベル - 味方キャラレベル」を計算する。
$C1/2408では「敵パーティレベル - 味方キャラレベル」と$F0で論理積を取っているが、これで「敵パーティレベル - 味方キャラレベル」の161の位の値だけ残り、160の位は0になる。
$C1/240Aの判定はゼロフラグが立っているかどうかだが、ゼロフラグが立つのは161の位が0の時だけである。
161の位が1以上だと、「敵パーティレベル - 味方キャラレベル」の結果が$10以上、10進数で16以上であることが確定になる。
取得経験値 = ( 敵パーティレベル - 味方キャラレベル ) * 16 + 8
なので、16 * 16 + 8 = 264になるから、取得経験値が100を越えていてレベルアップ確定となる。
このため、$C1/240Aの「ゼロフラグが立っていないとき[$241F]分岐」は、「取得経験値が100以上確定なので、レベルアップ処理へジャンプ」になる。
続いて、「敵パーティレベル - 味方キャラレベル」の結果が$10未満の処理になるが、4回連続でASL、算術左シフトを行っているので、×2を4回繰り返している。
よって10進数なら×16、16進数なら×$10の処理である。
取得経験値 = ( 敵パーティレベル - 味方キャラレベル ) * 16 + 8
の、「( 敵パーティレベル - 味方キャラレベル ) * 16」部分の計算である。
次に$C1/2410で、「( 敵パーティレベル - 味方キャラレベル ) * 16」と$08の論理和を取っている。
「( 敵パーティレベル - 味方キャラレベル ) * 16」、つまり「( 敵パーティレベル - 味方キャラレベル ) * $10」は、16進数だと161の位が( 敵パーティレベル - 味方キャラレベル )で、160の位が0だから、$08と論理和を取るということは、160の位が0から8に変わる、という処理と同じ意味である。
結局、論理和を取ることは、「( 敵パーティレベル - 味方キャラレベル ) * 16」に$08を足すことと同じ処理になる。
「( 敵パーティレベル - 味方キャラレベル ) * 16 + 8」
の計算がここで終了したということである。
後の処理は、「敵パーティレベル≦味方キャラレベル、または経験値が増えない行動を取った場合」と同じである。
$C1/2412で、戦闘前のキャラの経験値と、戦闘で得た経験値を足し、キャリーフラグが立っていたらレベルアップ処理へジャンプ。
$C1/2417で、足し算結果と$64(10進数100)を減算比較し、0以上ならキャリーフラグが立ち、レベルアップ処理へジャンプ。
それ以外は足し算結果がそのまま戦闘終了時の経験値となり、$C1/241Bで[$001E,y](シナリオ別キャラデータの経験値)に書き込まれて経験値計算終了である。
;レベルアップ時の処理 $C1/241F LDA $0005,x ;Aに[$0005,x](味方キャラ経験値)をロード $C1/2422 STA $001C,x ;Aを[$001C,x]に書き込み $C1/2425 LDA #$00 ;Aに$00をロード $C1/2427 STA $0005,x ;Aを[$0005,x](味方キャラ経験値)に書き込み $C1/242A LDA $0006,y ;Aに[$0006,y](味方キャラレベル)をロード $C1/242D INC A ;Aをインクリメント(+1) $C1/242E CMP #$64 ;Aと$64(100)を減算比較(レベルが100かどうか) $C1/2430 BEQ $A4 [$23D6] ;ゼロフラグが立っているとき[$23D6]分岐 $C1/2432 STA $0006,y ;Aを[$0006,y](味方キャラレベル)に書き込み ※レベル更新 $C1/2435 LDA #$00 ;Aに$00をロード $C1/2437 STA $001E,y ;Aを[$001E,y](キャラ経験値)に書き込み $C1/243A PHX ;Xをスタックにプッシュ $C1/243B PHY ;Yをスタックにプッシュ $C1/243C TXY ;Xの値をYに転送 $C1/243D JSR $273C [$C1:273C] ;[$C1:273C]へ ;(レベルアップ時の表示&モーション表示のサブルーチンへ)
最後にレベルアップ時の処理を紹介しておく。
($C1/2422の[$001C,x]の処理はよくわからないのでパス)
レベルアップした時、経験値の余剰は繰り越しにならず、0になるので、$C1/2425~$C1/2427でキャラの経験値[$0005,x]に$00を書き込んでいる。
$C1/242Aでは、シナリオ別キャラデータのキャラレベルが読み込まれ、$C1/242Dではレベルアップしたのでレベルを+1している。
ただし$C1/242Eで、上がったレベルの値と$64(10進数100)と比較し、ゼロフラグが立っている場合、つまりレベルが100になっていたら、$C1/23D6へ戻る。
「$C1/23D6 RTS」の後は、「敵パーティレベル≦味方キャラレベル、または経験値が増えない行動を取った場合」の処理であり、レベル99、かつ[$0005,x](味方キャラ経験値)に$00を入れた状態で再び経験値計算処理に戻されたということになるが、この状況ではどうやっても「trunc(敵パーティレベル / 2) + trunc(16 / 味方キャラレベル=99)」が100を越えてレベルアップすることはない。本作の敵パーティレベルの最大値が45(イシュタール×1)だからである。
よってレベル99以上にはレベルアップしない、という処理になるようだ。
レベルアップで上がったレベルが99以下の場合はそのまま、シナリオ別キャラデータのキャラレベル[$0006,y]に上書きされる。
また、シナリオ別キャラデータのキャラ経験値[$001E,y]には、$C1/2437で$00が書き込まれて更新される。
以上で、レベルアップ時のレベル・経験値の値の更新が終了となる。
この後はレベルアップ時の表示やモーションなどのサブルーチンへと飛び、それが終わると、味方キャラが複数の場合、他の味方キャラの取得経験値計算&レベルアップ処理を行い、全員分の処理を行った後は、ドロップアイテム判定処理を行って戦闘終了である。