TOP > プログラミング関係解説&調査 > ダメージフィールド

ダメージフィールド

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

ここでは、戦闘における4種類のダメージフィールド(毒、火炎、電撃、水)関係の仕様を解説する。
攻略上における解説は、戦闘関係の知識 > フィールドダメージで行っているので参照していただきたい。

世界の合言葉は森部様に、ダメージフィールドについて説明がある。以下引用。

■特殊フィールド
火炎ぼたる等の技によって生成される、特殊フィールド
ダメージ発動は毒→火炎→電撃→水→の順の4周期で、敵か味方の技使用で発動ターンが進む
戦闘をまたいでも発動ターンは維持されるが、
メニューを開くかデータロード時にリセットされ、毒からになる
(例えば、メニュー開いた次の戦闘で、ウキッを使えば直後に毒フィールドのダメージが出る)

ダメージ発動時に、特殊フィールドの消去判定が入る
消去率は各マスで1/16
判定は横書き順(左上から左→右で端まで行ったら次の行)で、
最後のマスの判定で消去となった場合、フィールドダメージ・エフェクトが不発となる
フィールドの消去もその時点では見た目変わらず、次の敵か味方の技使用直前にフィールドの見た目も変わる

仕様は上で説明している通りだが、

  • 複数マスにまたがる敵がフィールドダメージを受ける時の仕様(ダメージを受ける時は1マス分のダメージだが、ダメージ吸収時は踏んでいるマスの合計値分回復する、しかし画面表示は1マス分の回復量のみ)
  • 最終編ラストバトル(オディオモール/アイ/マウス~ピュアオディオ戦)では、ダメージフィールドを発生させる技を使っても、ダメージフィールドが表示されない

などは説明がないので、ここでサブルーチンを見つつ説明をする。
なお、解説は長くなるので、結論だけ先にまとめておく。

フィールドダメージとキャラのサイズについて

ダメージフィールドが発動した時、7×7マスの戦闘フィールドにおいて、1マスずつ、

  1. そのマスにダメージフィールドがあるか
  2. ダメージフィールドがある場合、敵または味方キャラが乗っているか

という判定を行うが、キャラが複数マスにまたがるサイズで、かつ、ダメージフィールドマスも複数踏んでいる場合、1マス毎に判定をしているから、同じキャラでもマス目の数だけ判定を行うことになる。
例えばキングマンモー(3×3マスサイズ)なら、火炎フィールドを吸収し、他フィールドはダメージをくらうが、

  • 火炎フィールドを3×3マス踏んでいたら、3×3マス=9回のダメージフィールド判定を行うので、火炎フィールドでの回復+24を9回繰り返すことにより、HPが24×9=216回復する。
  • 毒フィールドを3×3マス踏んでいたら、一番最初の判定(左上マス)を行った時に特定のフラグが立ち、2マス目からの毒フィールド判定をスキップするので、ダメージ量は16×1=16となる。

このように、「敵がフィールドでダメージをくらう時だけ、1マス分のダメージを食らった後は、他のマスのダメージ処理をスキップ」という処理を行っている。
味方キャラの場合は、ダメージフィールド吸収でもダメージでも、全てのマスの判定分吸収またはダメージとなるが、味方キャラは1×1マスサイズなので、必ず1マス分の吸収またはダメージとなる。

味方キャラの例外は最終編オルステッド主人公時で、操作キャラが本来敵の各シナリオラストボスだから、サイズが1×1ではない。
ただし味方キャラ扱いなので、ダメージフィールド吸収でもダメージでも、全てのマスの判定分吸収またはダメージとなる。
このため、おーでぃーおー戦では、ゴリが毒フィールドを発生させた場合、おーでぃーおーが毒フィールドで受けるダメージは1マス分ではなく、おーでぃーおーが乗っているマス全てとなる。つまりダメージ量が増加する。

最終編ラストバトル(オディオモール/アイ/マウス~ピュアオディオ戦)

戦闘開始時に戦闘背景関係の値が[$00:0041]に入り、更にその上6ビットが[$00:0354]に入るのだが、この値で「現在何の戦闘が行われているか」を判定するようになっている。
[$00:0354]の値から最終編ラストバトルだと判定されると、ダメージフィールドを発生させる技において、ダメージフィールド発生処理だけスキップするという分岐があるため、ダメージフィールドを発生させる技を使っても、ダメージフィールドだけ発生しない(その他の処理は行われる)。

以降は解説になる。
以下のように各段階に分けてサブルーチンと共に説明していく。
また、長くなるので2ページに分けている。

ダメージフィールド関連のメモリアドレス

ダメージフィールド関係の処理を見る上で重要なメモリアドレスを記しておく。

戦闘フィールドの状態

戦闘フィールドは7×7マスで構成されているが、各マスの状態を$00:04C8$00:04FEに記録している。
対応したアドレスは以下の通りで、$00:04????の値部分のみ記している。
各アドレスに、現在居るキャラクターと、ダメージフィールドの状態が記録される。

C8C9CACBCCCDCECF
D0D1D2D3D4D5D6D7
D8D9DADBDCDDDEDF
E0E1E2E3E4E5E6E7
E8E9EAEBECEDEEEF
F0F1F2F3F4F5F6F7
F8F9FAFBFCFDFEFF

数字の通り、アドレスは左上から始まり、左方向1行分の次は2列目の左から……という順になっている。
このため、戦闘フィールドに関する計算や処理は、上のアドレス順、つまり左上から開始され右方向へ、そして下方向へ……という順番で行われる。

一番右の灰色背景部分は実際には戦闘フィールドではないため、$00が入っている。
プログラミング上、7という数字はキリが悪いので、横8×縦7でアドレスを設定しているようである(行の区切りとしても利用されている)。

各アドレスに入る数値は、何もなければ$00、それ以外はキャラクターの数値+ダメージフィールド状態の合計値になる。
敵が複数マスにまたがっている場合は、該当マスに同じ数値が入る。

数値内容
$01味方キャラ1
$02味方キャラ2
$03味方キャラ3
$04味方キャラ4
$11敵キャラ1
$12敵キャラ2
$13敵キャラ3
$14敵キャラ4
$15敵キャラ5
$16敵キャラ6
$17敵キャラ7
$18敵キャラ8
$19敵キャラ9
$1A敵キャラA
$1B敵キャラB
$1C敵キャラC
$1D敵キャラD
$1E敵キャラE
$80水フィールド
$A0毒フィールド
$C0火炎フィールド
$E0電撃フィールド

つまり、

  • 上1~3ビット:フィールドの状態、%000ならダメージフィールドなし
  • 上4ビット:敵キャラなら1、それ以外は0
  • 下4ビット:%0000ならキャラなし

と、各ビットに値が入っているので、特定の値と論理積を取ると、ダメージフィールドの有無やキャラの有無などを判定できることになる。

例えば、フィールドの一番左上のマスに味方キャラ1がいて、かつ、そのマスが火炎フィールドになっていたら、$00:04C8には$01 + $C0 = $C1が入る。

戦闘フィールド計算値

上で紹介した$00:04C8$00:04FEは戦闘フィールドの現在の状況が入るアドレスだが、ダメージフィールドを発生させる技の処理中など、計算途中の値を入れるアドレスが別に存在している。
それが$00:0488$00:04BEで、下には$00:04????の値部分のみ記している。

88898A8B8C8D8E
90919293949596
98999A9B9C9D9E
A0A1A2A3A4A5A6
A8A9AAABACADAE
B0B1B2B3B4B5B6
B8B9BABBBCBDBE

ターン数

$7E:FEFDには、フィールドダメージの発動タイミング用に、戦闘開始時からのターン数が記録されている。
ただし、$7E:FEFDは戦闘開始時に毎回リセットされるのではない。
ゲーム開始時に$00がセットされるが、メニュー画面を開くか、ゲームがリセットされない限りターン数が累積していく。
このため、例えば、ゲームを開始して最初の戦闘が2ターンで終わると$7E:FEFDには$02が記録され、次の戦闘までメニューを開かない場合、$7E:FEFD$02が入った状態で戦闘開始になり、$03, $04,……と増えていくことになる。
$FFまで増えたとしても、増加時の処理にキャリーオーバーの分岐処理が見られないため、次ターンは+1されて$7E:FEFD$00が入りキャリーフラグが立つはずだが、これにより特に問題は起こらないはずである。実際の処理の説明時に解説する。

キャラクターのいるマスの位置

戦闘フィールドの状態とは別に、キャラ毎に現在どのマスにいるかが記録される。
味方キャラ1であれば、$00:1C00~の戦闘中の味方キャラデータに以下のように値が入る。

数値内容
$18キャラ位置のマス目のX座標(左から$00$06
$19キャラ位置のマス目のY座標(上から$00$06
$28技の範囲指定~使用中、キャラ位置のマス目のX座標
$29技の範囲指定~使用中、キャラ位置のマス目のY座標

$00:1C28$00:1C29は、味方の技一覧で技を選んだ時点で値が更新される。

技の範囲

何かしらのダメージフィールドを発生させる場合、技の範囲に関するデータも必要になる。
技の射程や範囲に関する値は技データ内に散らばっているので、判定が少々ややこしい。
判定順は技データ13→技データ21→技データ12になる。
具体的な処理方法は後で説明する。

  • 技データ13
    上4ビット:周囲攻撃2、反撃専用4、回復8/下4ビット:技の属性
  • 技データ21
    上4ビット:特殊なタイプ/下3ビット:効果範囲(2)
  • 技データ12
    上2~4ビット:必中状態異常(腕・足・首)/下2ビット:効果範囲(1)

技データ22

技にはダメージフィールドを発生させるかどうかが設定されているが、技データ22の上2~4ビットの値が該当する。
(なお、下4ビットは上1ビットが1の時、発生させる行動異常の値が記録される)

上4ビットフィールド
$4%0100
$5%0101
$6%0110火炎
$7%0111電撃

例えばおぼろ丸の技「忍法火炎ぼたる」は火炎フィールドを発生させるが、技データ22の値は「$60(%0110 0000)」である。
(「忍法火炎ぼたる」の技データ22は、$D5:2D2Eに入っている)
味方キャラが技を使っている最中は、味方キャラ番号が1なら$7E:9010$7E:9028、番号2なら$7E:9050$7E:9068……に該当の技データがそのまま入る。
おぼろ丸が番号1だったら、「忍法火炎ぼたる」を使用する時、技データ22が$7E:9026にコピーされる。

少しややこしいのは、ダメージフィールドと行動異常どちらも発生可能な技の時で、「プラズマボール」の技データ22は「$F3」だが、2進数で見ると%1111 0011であり、上2~4ビットが「111」だから電撃フィールドを発生させる。
かつ、上1ビットが1なので、下4ビットが行動異常に対応し、行動異常%0011 = $03を発生させる、ということになる。

味方キャラのフィールド吸収

味方キャラは、フィールド吸収能力がある装備を身に着けていないとフィールドダメージを吸収できない。
シナリオ別キャラデータの$31番目の下4ビットに、フィールド吸収の値が入っている。
たとえばおぼろ丸なら、シナリオ別キャラデータは$00:0EC0から開始だが、$31を加算した$00:0EF1の下4ビットがフィールド吸収の値である。

下4ビットフィールド吸収
$8%1000
$4%0100
$2%0010火炎
$1%0001電撃

フィールド吸収は複数のフィールドを吸収できる場合もあるため、以上の合計値が$00:0EF1の下4ビットに入ることになる。
たとえばおぼろ丸が「水神のたび」のみ装備であれば、水フィールド吸収だけであるから、$00:0EF1には$08が入る。
「げんじのタビ」だと火炎フィールド吸収だけであるから、$00:0EF1には$02が入る。
「コイツぁタマゲタ」だと全フィールド吸収可能なので、$00:0EF1には$0Fが入る。

味方キャラの場合、他にフィールド吸収能力がつくのは「サンゴのゆびわ」「マーメイドボトム」だけ、しかもどちらも水フィールド吸収だから、味方キャラのフィールド吸収の値は、何も吸収しない$00以外だと、$02, $08, $0Fのいずれかだけということになる。

敵キャラのフィールド吸収/無効

敵の場合は、敵データ01の上4ビットがフィールド吸収の値になる。
入る値は味方キャラのフィールド吸収の値と同じである。
味方キャラとの違いは、敵データ31の下1ビットにダメージフィールド無効かどうかが入ること。ダメージフィールド無効だと%1である。
戦闘中は、敵種類データの$21番目に敵データ01が、$3F番目に敵データ31が入る。
例えば敵が1体だけなら、敵種類1のデータは$00:1A00$00:1A3Fに入るから、$00:1A21が敵データ01、$00:1A3Fが敵データ31である。
その他、必要な値はその都度解説していく。

ダメージフィールドの発生

ここでは例として、おぼろ丸が「忍法火炎ぼたる」で火炎フィールドを発生させた場合の処理を紹介する。
手順としては、

  1. 「忍法火炎ぼたる」の範囲を、$00:0488$00:04BEに仮値として書き込み(範囲に当たるアドレスには$0Fを書き込む)
  2. $00:0488$00:04BEに書き込まれた値から、火炎フィールドであることを$00:04C8$00:04FEに書き込み

となる。
先に説明した通り、戦闘中の戦闘フィールドの状態は最終的に$00:04C8$00:04FEに記録されていくのだが、そこに書き込むまでの計算値を記録するために$00:0488$00:04BEが確保されている。

「忍法火炎ぼたる」を使う前はダメージフィールドはなく、$00:04C8$00:04FEには、味方キャラと敵キャラの値のみが入っているものとする。

戦闘フィールドは7×7マスだが、左上マスを(0,0)とした時に右方向をX軸、下方向をY軸とする。
$00:04C8$00:04FEをマス目に対応させると以下のようになる。

C8C9CACBCCCDCE
D0D1D2D3D4D5D6
D8D9DADBDCDDDE
E0E1E2E3E4E5E6
E8E9EAEBECEDEE
F0F1F2F3F4F5F6
F8F9FAFBFCFDFE

この戦闘では、おぼろ丸(味方キャラ1)、とらわれの男(味方キャラ2)、カラクリ丸(味方キャラ3)、浪人(敵キャラ1)がいるとして、

キャラアドレス
おぼろ丸(味方キャラ1)$00:04E4$01
とらわれの男(味方キャラ2)$00:04EB$02
カラクリ丸(味方キャラ3)$00:04ED$03
浪人(敵キャラ1)$00:04E0$00:04E8$11

このように配置されているものとする。

おぼろ丸のいるマスは上の「E4」の位置で、ここで「忍法火炎ぼたる」を使う。
「忍法火炎ぼたる」の範囲は、使用者を中心とした5×5マス(下の背景赤色部分)になる。

C8C9CACBCCCDCE
D0D1D2D3D4D5D6
D8D9DADBDCDDDE
E0E1E2E3E4E5E6
E8E9EAEBECEDEE
F0F1F2F3F4F5F6
F8F9FAFBFCFDFE

今回は5×5マス範囲がフィールド内に収まるが、おぼろ丸がもう1マス右にいるなどすると5×5マス範囲がはみ出すから、別途処理が入ることになる。

先に述べた通り、フィールド関係の値を計算するため、$00:0488$00:04BEの領域が確保されているが、この領域は技を使う時に毎回、一度すべて$00で埋める処理をしてから、計算値が入る。
その$00で埋める処理は$C1/3D2B$C1/3D38にあたるのだが、ここでは詳細は省略する。

$C1/3D38の後は、$C1/D2E4$C1/380Eとジャンプするので、$C1/380E以降からサブルーチンを紹介する。
このあたりの処理は、ダメージフィールド発生技に限らず、範囲攻撃における範囲の計算を行うサブルーチンとして共通で使われる。

$C1/380E LDY $5A    [$00:035A]   ;Yに[$00:035A]をロード
$C1/3810 LDA $0001,y[$00:1C01]   ;Aに[$00:1C01](キャラ1 戦闘状態)をロード
$C1/3813 CMP #$40                ;Aと$40を減算比較(ステータスレジスタ変更のみ)
$C1/3815 BNE $05    [$381C]      ;ゼロフラグが立っていないとき[$381C]分岐
$C1/381C LDA $0028,y[$00:1C28]   ;Aに[$00:1C28](X座標 $04)をロード
$C1/381F STA $16    [$00:0316]   ;Aを[$00:0316](X座標 $04)に書き込み
$C1/3821 LDA $0029,y[$00:1C29]   ;Aに[$00:1C29](Y座標 $03)をロード
$C1/3824 STA $17    [$00:0317]   ;Aを[$00:0317](Y座標 $03)に書き込み
$C1/3826 CPY #$1C00              ;Yと$1C00を減算比較(ステータスレジスタのみ変更)
$C1/3829 BCS $05    [$3830]      ;キャリーフラグが立っているとき[$3830]分岐
$C1/3830 STZ $0A    [$00:030A]   ;[$00:030A]に$00を書き込み
$C1/3832 STZ $09    [$00:0309]   ;[$00:0309]に$00を書き込み
$C1/3834 LDX $68    [$00:0368]   ;Xに[$00:0368]をロード
$C1/3836 LDA $D5000D,x[$D5:2D25] ;Aに[$D5:2D25](技データ13 $28)をロード
$C1/383A BIT #$20                ;Aと$20で論理積(ステータスフラグ変更のみ)
$C1/383C BEQ $0B    [$3849]      ;ゼロフラグが立っているとき[$3849]分岐
$C1/383E LDA $D50015,x[$D5:2D2D] ;Aに[$D5:2D2D](技データ21 $60)をロード
$C1/3842 AND #$0F                ;Aと$0Fで論理積
$C1/3844 BEQ $07    [$384D]      ;ゼロフラグが立っているとき[$384D]分岐
$C1/384D LDA $D5000C,x[$D5:2D24] ;Aに[$D5:2D24](技データ12 $02)をロード
$C1/3851 AND #$03                ;Aと$03で論理積
$C1/3853 BEQ $0C    [$3861]      ;ゼロフラグが立っているとき[$3861]分岐→範囲:全体
$C1/3855 CMP #$01                ;Aと$01を減算比較(ステータスレジスタ変更のみ)
$C1/3857 BEQ $1D    [$3876]      ;ゼロフラグが立っているとき[$3876]分岐→範囲:3×3
$C1/3859 CMP #$02                ;Aと$02を減算比較(ステータスレジスタ変更のみ)
$C1/385B BEQ $2E    [$388B]      ;ゼロフラグが立っているとき[$388B]分岐→範囲:5×5

以上は、おぼろ丸のいる座標及び、使用した「忍法火炎ぼたる」の射程・範囲確認の処理である。
[$00:1C28][$00:1C29]には、技を選択して範囲が表示された時点で、技使用者の座標X,Yが順に入る。
今回で言えば$04,$03が入っているが、$C1/381C$C1/3824[$00:0316][$00:0317]にそれぞれコピーされる。

$C1/3836からが射程・範囲の確認である。
必要となるのは技データ13、技データ21、技データ12である。
上の処理を見ると、

  1. 技データ13と$20で論理積をとり、$00なら[$C1/3849]へジャンプ
  2. 技データ21と$0Fで論理積をとり、$00なら[$C1/384D]へジャンプ
  3. 技データ12と$03で論理積をとり、$00なら[$C1/3861]へジャンプ
  4. 技データ12と$03の論理積が$01なら[$C1/3876]へジャンプ
  5. 技データ12と$03の論理積が$02なら[$C1/388B]へジャンプ

という順序で判定を行っている。

技データ13

$20 (%0010 0000)との論理積をとって判定を行っているが、上から3ビット目に1が立っている時は周囲攻撃になる。
よってここでゼロフラグが立つのは周囲攻撃以外、ゼロフラグが立たないのは周囲攻撃である。
「忍法火炎ぼたる」の技データ13の値は$28で、ゼロフラグが立たない、つまり周囲攻撃なので、次の判定に進む。

技データ21

$0F (%0000 1111)との論理積をとって判定を行っている。
つまり技データ21の下4ビットについての判定である。
技データ21の下3ビットは以下のように値が入っている。

数値効果範囲
%000(技データ12に効果範囲が入る)
%001縦±0×横全体
%010縦±1×横全体
%011縦±2×横全体
%100縦全体×横±0
%101縦全体×横±1
%111縦全体×横±2

ゼロフラグが立つ場合、つまり技データ21の下3ビットに%000が入っている時は、周囲攻撃かつ、技データ12に効果範囲の値が入っている。
ゼロフラグが立たない場合は、上の法則で効果範囲が決まる。つまり周囲攻撃かつ、範囲の縦と横の幅が異なる時である。
「忍法火炎ぼたる」は使用者の周囲5×5マスが範囲であり、技データ21の値は$60で、下4ビットは0のため、次の判定に進む。

技データ12

技データ21の下3ビットが%000の時のみ、技データ12の下2ビットが以下のように範囲を示す。

数値効果範囲
%001×1
%013×3
%105×5
%11全体

技データ12と$03で論理積を取ると、下2ビットが取得できる。
「忍法火炎ぼたる」の技データ12の値は$02(%10)で、上の通りに範囲が5×5になる。

ということで、「忍法火炎ぼたる」の場合、$C1/3836以降の分岐で、$C1/385Bでゼロフラグが立ち[$C1/388B]へジャンプする。

$C1/388B LDA #$05                ;Aに$05をロード
$C1/388D CLC                     ;キャリーフラグクリア
$C1/388E ADC $0A    [$00:030A]   ;A + [$00:030A](初期値$00)
$C1/3890 STA $0A    [$00:030A]   ;A($05)を[$00:030A]に書き込み
$C1/3892 LDA #$05                ;Aに$05をロード
$C1/3894 ADC $09    [$00:0309]   ;A + [$00:0309](初期値$00)
$C1/3896 STA $09    [$00:0309]   ;A($05)を[$00:0309]に書き込み
$C1/3898 LDA #$02                ;Aに$02をロード
$C1/389A STA $10    [$00:0310]   ;A($02)を[$00:0310]に書き込み
$C1/389C STA $11    [$00:0311]   ;A($02)を[$00:0311]に書き込み
$C1/389E BRA $00    [$38A0]      ;フラグにかかわりなく常に分岐[$38A0]

飛び先の$C1/388B~の処理は範囲が5×5の場合専用で、範囲の横幅と縦幅である$05を、[$00:030A][$00:0309]に書き込んでいる。
更に、[$00:0310][$00:0311]に書き込んだ$02だが、これは技使用者から2マスの距離までが範囲、という意味での$02である。

$C1/38A0 LDA $16    [$00:0316]   ;Aに[$00:0316](X座標 $04)をロード
$C1/38A2 SEC                     ;キャリーフラグON
$C1/38A3 SBC $10    [$00:0310]   ;A - [$00:0310]($04 - $02) ※範囲左端
$C1/38A5 STA $12    [$00:0312]   ;A($02)を[$00:0312]に書き込み
$C1/38A7 LDA $17    [$00:0317]   ;Aに[$00:0317](Y座標 $03)をロード
$C1/38A9 SEC                     ;キャリーフラグON
$C1/38AA SBC $11    [$00:0311]   ;A - [$00:0311]($03 - $02) ※範囲上端
$C1/38AC STA $11    [$00:0311]   ;A($01)を[$00:0311]に書き込み
$C1/38AE STZ $15    [$00:0315]   ;[$00:0315]に$00を書き込み

このあたりから、範囲の座標位置の算出である。
7×7のフィールドに座標を書き込むとこのような図になり、おぼろ丸は(4,3)にいて、薄い赤色をつけた部分が「忍法火炎ぼたる」の範囲である。

$C1/38A0$C1/38A5では、おぼろ丸がいるX座標から$02を引いているから、「忍法火炎ぼたる」の範囲の一番左のXの値「$02」を計算し、[$00:0312]に書き込んでいる。
$C1/38A7$C1/38ACでは、おぼろ丸がいるY座標から$02を引いているから、「忍法火炎ぼたる」の範囲の一番上のYの値「$01」を計算し、[$00:0311]に書き込んでいる。
技範囲の最も左上のマスである(2,1)が記録されたことになる。
今回は引き算した値が0以上だったが、おぼろ丸がいるマス次第で、引き算すると0以下の負の値(符号付き8ビット整数の$FF以下)になる場合もあり得る。
とりあえずここでは、負の値になったからといって分岐はない。

;$00:0492~$00:0496の処理開始位置
$C1/38B0 LDA $11    [$00:0311]   ;Aに[$00:0311]($01)をロード
$C1/38B2 CMP #$07                ;Aと$07を減算比較(ステータスレジスタ変更のみ)
$C1/38B4 BCS $27    [$38DD]      ;キャリーフラグが立っているとき[$38DD]分岐
$C1/38B6 ASL A                   ;Aを算術左シフト *2
$C1/38B7 ASL A                   ;Aを算術左シフト *2
$C1/38B8 ASL A                   ;Aを算術左シフト *2
$C1/38B9 STA $13    [$00:0313]   ;Aを[$00:0313]($01*8)に書き込み
$C1/38BB LDA $0A    [$00:030A]   ;Aに[$00:030A]($05)をロード
$C1/38BD STA $08    [$00:0308]   ;A($05)を[$00:0308]に書き込み
$C1/38BF LDA $12    [$00:0312]   ;Aに[$00:0312]($02)をロード
$C1/38C1 STA $10    [$00:0310]   ;A($02)を[$00:0310]に書き込み
;
;$00:0492の処理
$C1/38C3 LDA $10    [$00:0310]   ;Aに[$00:0310]をロード
$C1/38C5 CMP #$07                ;Aと$07を減算比較(ステータスレジスタ変更のみ)
$C1/38C7 BCS $0E    [$38D7]      ;キャリーフラグが立っているとき[$38D7]分岐
$C1/38C9 ADC $13    [$00:0313]   ;A + [$00:0313]
$C1/38CB STA $14    [$00:0314]   ;Aを[$00:0314]に書き込み
$C1/38CD LDX $14    [$00:0314]   ;Xに[$00:0314]をロード
$C1/38CF LDA $0488,x[$00:0492]   ;Aに[$00:0492]をロード
$C1/38D2 ORA #$0F                ;Aと$0Fで論理和
$C1/38D4 STA $0488,x[$00:0492]   ;Aを[$00:0492]に書き込み
$C1/38D7 INC $10    [$00:0310]   ;[$00:0310]をインクリメント +1
$C1/38D9 DEC $08    [$00:0308]   ;[$00:0308]をデクリメント -1
$C1/38DB BNE $E6    [$38C3]      ;ゼロフラグが立っていないとき[$38C3]分岐
;
;$00:0493~$00:0496の処理省略
;
$C1/38DD INC $11    [$00:0311]   ;[$00:0311]をインクリメント +1
$C1/38DF DEC $09    [$00:0309]   ;[$00:0309]をデクリメント -1
$C1/38E1 BNE $CD    [$38B0]      ;ゼロフラグが立っていないとき[$38B0]分岐
;
;$00:049A~$00:049Eの処理に続く

$C1/38B0が、計算値を書き込む$00:0488$00:04BEの5×5範囲のアドレスのみに、「$0F」を加算するというループ処理の開始位置になる。

88898A8B8C8D8E
90919293949596
98999A9B9C9D9E
A0A1A2A3A4A5A6
A8A9AAABACADAE
B0B1B2B3B4B5B6
B8B9BABBBCBDBE

この中の、5×5範囲内にあたる、

$00:0492$00:0496
$00:049A$00:049E
$00:04A2$00:04A6
$00:04AA$00:04AE
$00:04B2$00:04B6

に、元から入っている値+$0Fを論理和という形で書き込む、という処理である。
横一列(5マス分)の処理を5行分繰り返すループ処理になる。
上で紹介したサブルーチンは、一番上の行である$00:0492$00:0496の抜粋である。
簡単に言えば、おぼろ丸の居る位置と、技の効果範囲から、対応する$00:0488$00:04BEのアドレスを計算し、該当アドレスの値と$0Fで論理和を取ってから、その値をそのまま該当アドレスに上書きする、という処理である。
$00:0488$00:04BEは、予め$00で埋めてあるため、実質、「技の範囲のアドレスだけ$0Fを入れる」という処理である。

$C1/DFAF LDX #$1B00              ;Xに$1B00をロード
$C1/DFB2 STX $10    [$00:0310]   ;Xを[$00:0310]に書き込み
$C1/DFB4 LDY #$0000              ;Yに$0000をロード
$C1/DFB7 LDA #$07                ;Aに$07をロード
$C1/DFB9 STA $09    [$00:0309]   ;Aを[$00:0309]に書き込み
$C1/DFBB LDA #$07                ;Aに$07をロード
$C1/DFBD STA $08    [$00:0308]   ;Aを[$00:0308]に書き込み
;
;ループここから
;1マス毎に、技範囲と敵がいるか判定
$C1/DFBF LDA $0488,y             ;Aに[$00:0488~$00:04BE]をロード
$C1/DFC2 BEQ $21    [$DFE5]      ;ゼロフラグが立っているとき[$DFE5]分岐
;ゼロフラグOFF(技の範囲内)
$C1/DFC4 LDA $04C8,y             ;Aに[$00:04C8~$00:04FE]をロード
$C1/DFC7 BIT #$10                ;Aと$10で論理積(ステータスフラグ変更のみ)
$C1/DFC9 BEQ $1A    [$DFE5]      ;ゼロフラグが立っているとき[$DFE5]分岐
;ゼロフラグOFF(該当マスに敵がいる)
$C1/DFCB AND #$0F                ;Aと$0Fで論理積
$C1/DFCD DEC A                   ;Aをデクリメント -1
$C1/DFCE CLC                     ;キャリーフラグクリア
$C1/DFCF ASL A                   ;Aを算術左シフト *2
$C1/DFD0 ASL A                   ;Aを算術左シフト *2
$C1/DFD1 ASL A                   ;Aを算術左シフト *2
$C1/DFD2 ASL A                   ;Aを算術左シフト *2
$C1/DFD3 STA $10    [$00:0310]   ;Aを[$00:0310]に書き込み
$C1/DFD5 LDX $10    [$00:0310]   ;Xに[$00:0310]をロード
$C1/DFD7 LDA $7E9001,x[$7E:AB01] ;Aに[$7E:AB01]をロード
$C1/DFDB BNE $08    [$DFE5]      ;ゼロフラグが立っていないとき[$DFE5]分岐
$C1/DFDD LDA $7B    [$00:037B]   ;Aに[$00:037B]をロード
$C1/DFDF STA $7E9001,x[$7E:AB01] ;Aを[$7E:AB01]に書き込み
$C1/DFE3 INC $7B    [$00:037B]   ;[$00:037B]をインクリメント +1
;分岐合流
$C1/DFE5 INY                     ;Yをインクリメント +1
$C1/DFE6 DEC $08    [$00:0308]   ;[$00:0308]をデクリメント -1
$C1/DFE8 BNE $D5    [$DFBF]      ;ゼロフラグが立っていないとき[$DFBF]分岐
;ループここまで

続いて、「技の範囲内に敵がいるか」の判定が入る。
$00:0488$00:04BEの中で、5×5範囲内なら$0Fが入っているが、$0Fが入っているマスに対応した、フィールドの状態が記録されている$00:04C8$00:04FEをロードし、$10と論理積を取っている。
フィールドの状態が記録されている$00:04C8$00:04FEには、味方キャラと敵キャラの値が書き込まれているが、味方キャラだったら$01$04、敵キャラだったら$11$1E、ダメージフィールドがあるなら$80以上が入っている。
よって、$10と論理積を取ってゼロフラグが立たないのは、該当マスに敵キャラが居る、$11$1Eが入っている時のみである。
その場合は$C1/DFCB$C1/DFE3の処理が入って、[$7E9001,x]$01~を書き込む処理が行われる。
[$7E9001,x]は、敵番号により変わるが、例えば敵番号0なら上のように[$7E:AB01]が該当する。
このアドレスには、敵ターゲット決定方法で紹介した通り、攻撃/回復技の対象の範囲内にいる敵には順に$01~が入り、範囲外だと$FFが入る。
$7E:AB?1の値により、範囲攻撃の技の命中判定などが行われるのだが、上処理で数値を入れていたことがわかる。

以上の処理の後、今回の本題である、フィールドの状態が記録されている$00:04C8$00:04FEに火炎フィールドの値を加算するサブルーチンに入る。

$C1/10B3 LDA $54    [$00:0354]   ;Aに[$00:0354]をロード
$C1/10B5 CMP #$23                ;Aと$23を減算比較(ステータスレジスタ変更のみ)
$C1/10B7 BEQ $0B    [$10C4]      ;ゼロフラグが立っているとき[$10C4]分岐
$C1/10B9 LDX $68    [$00:0368]   ;Xに[$00:0368]をロード

上の処理は、[$00:0354]の値と$23を減算比較して、ゼロフラグが立たないなら先に進むという意味になる。
つまり、この先のフィールドダメージ関係のサブルーチンに入るのは、[$00:0354]の値が$23ではない場合になる。
[$00:0354]の値は、戦闘に入った直後に計算される、その戦闘固有の値になる。
その処理は以下の通り。

$C1/F575 LDA $0041  [$00:0041]   ;Aに[$00:0041]をロード
$C1/F578 AND #$FC                ;Aと$FCで論理積
$C1/F57A LSR A                   ;Aを論理右シフト (/2)
$C1/F57B LSR A                   ;Aを論理右シフト (/2)
$C1/F57C STA $54    [$00:0354]   ;Aを[$00:0354]に書き込み

以前にも紹介したが、[$00:0041]は戦闘の背景番号だと思われる(詳細は未調査)。
処理を追ってみると、[$00:0041]$FCで論理積を取ってから、論理右シフトを2回、つまり÷4した値が[$00:0354]になることがわかる。
つまり、[$00:0354]は、[$00:0041]の上6ビットの値ということである。
この値は戦闘の背景番号から計算されているので、戦闘による固有値と見て良いことになるのだが、では、先の処理の「[$00:0354]$23」とは何の戦闘なのか。
実は、[$00:0354]$23の戦闘は最終編ラストバトル(オディオモール/アイ/マウス~ピュアオディオ戦)である。
この戦闘では、ダメージフィールドを発生させる技を使っても、ダメージフィールドが発生しない仕様があるが、上のサブルーチンにより、ダメージフィールド発生処理をスキップするためである。

では改めて、最終編ラストバトル以外、ダメージフィールドが発生する戦闘の処理を見ていこう。

$C1/10BB LDA $D50016,x[$D5:2D2E] ;Aに[$D5:2D2E](「忍法火炎ぼたる」の技データ22 = $60)をロード
$C1/10BF ASL A                   ;Aを算術左シフト *2($60*2 = $C0)
$C1/10C0 AND #$E0                ;Aと$E0で論理積
$C1/10C2 BMI $01    [$10C5]      ;ネガティブフラグが立っているとき[$10C5]分岐
;
$C1/10C5 STA $1F    [$00:031F]   ;A($C0)を[$00:031F]に書き込み
$C1/10C7 LDX #$0000              ;Xに$0000をロード
$C1/10CA STA $1C    [$00:031C]   ;A($C0)を[$00:031C]に書き込み
$C1/10CC LDA #$07                ;Aに$07をロード
$C1/10CE STA $09    [$00:0309]   ;A($07)を[$00:0309]に書き込み
$C1/10D0 LDA #$07                ;Aに$07をロード
$C1/10D2 STA $08    [$00:0308]   ;A($07)を[$00:0308]に書き込み

ここで、「忍法火炎ぼたる」の技データ22をロードする。
ダメージフィールドを発生させる場合、技データ22の上2~4ビットに、以下のような値が入っている。

上4ビットフィールド
$4%0100
$5%0101
$6%0110火炎
$7%0111電撃

「忍法火炎ぼたる」の技データ22は$60であり、火炎フィールドを発生させる。
呼び出した$60は算術左シフトで2倍になり、$C0となる。

「忍法火炎ぼたる」の技データ22の場合は、下4ビットが0で何の値も入っていないが、「上1ビットが1の時、下4ビットは発生させる行動異常の値」となっている。
$C1/10C0$E0と論理積を取ることで、行動異常の値が入っていたとしても、フィールドの値のみ取り出せる。
$C1/10C0の処理の時点で、何かのフィールドを発生させる場合、Aに入っているのは$80, $A0, $C0, $E0のいずれかになったはずである。
そして、必ずネガティブフラグが立つ(2進数で一番上の桁に1が立つ)ため、$C1/10C2のネガティブフラグ判定で[$10C5]にジャンプする。
$C1/10C5~の処理は、技により何かしらのフィールドが発生する場合ということになる。

$C1/10C5$C1/10D2は、この後のループ処理用の値のセットになる。

;ループここから
;1マス毎に、技範囲かどうか判定
$C1/10D4 LDA $0488,x             ;Aに[$00:0488~$00:04BE]をロード
$C1/10D7 AND #$0F                ;Aと$0Fで論理積
$C1/10D9 BEQ $0A    [$10E5]      ;ゼロフラグが立っているとき[$10E5]分岐
;$0Fが入っている時(5×5範囲内のマス
$C1/10DB LDA $04C8,x             ;Aに[$00:04C8~$00:04FE]をロード
$C1/10DE AND #$1F                ;Aと$1Fで論理積
$C1/10E0 ORA $1F    [$00:031F]   ;Aと[$00:031F]($C0)で論理和
$C1/10E2 STA $04C8,x             ;Aを[$00:04C8~$00:04FE]に書き込み
;分岐合流
$C1/10E5 INX                     ;Xをインクリメント +1
$C1/10E6 DEC $08    [$00:0308]   ;[$00:0308]をデクリメント -1
$C1/10E8 BNE $EA    [$10D4]      ;ゼロフラグが立っていないとき[$10D4]分岐
;ループここまで

$00:0488$00:04BEの5×5範囲内なら$0Fが入っているので、1マス毎のループ処理ではまず、$C1/10D4$C1/10D9$0Fが入っているかどうかを論理積で判定する。
入っている場合は$C1/10DBに進み、該当の$00:04C8$00:04FEをロードする。
敵や味方キャラがいるマスだったり、既にダメージフィールドが存在している場合もあるが、既にダメージフィールドがあるマスだった場合、そのマスからダメージフィールドを消して、新たなダメージフィールド(今回は火炎フィールド)で上書きする、という処理をする。
よって一度、$00:04C8$00:04FEから既に入っているダメージフィールドの値を消してから、新たなダメージフィールドの値を加算、というのが$C1/10DE$C1/10E2の処理である。
ダメージフィールドの値は以下のようになっている。
先の処理で、[$00:031F][$00:031C]に入った値に対応していることにも注目。

数値内容
$80水フィールド
$A0毒フィールド
$C0火炎フィールド
$E0電撃フィールド

2進数で見ると上3ビットがフィールドの値に対応しているので、上3ビット分の値を%000に変えるため、$C1/10DE$1Fと論理積を取っているのである。
たとえば、もし該当のマスに味方キャラ1がいて($01)、かつ毒フィールド($A0)だと、合計した$A1という値が該当アドレスに入っているのだが、$A1$1Fで論理積を取ると$01になる。つまり味方キャラ1の値だけ残る、という仕組みである。
その上で、$C1/10E0では、[$00:031F]に入った、各フィールドの対応値との論理和を取る、つまり加算するので、「マスに乗っているキャラの状況はそのままで、フィールドのみ火炎フィールドに書き換え」という処理を行ったことになる。

これで、ダメージフィールドの発生の処理終了である。

フィールドダメージの発動

フィールドダメージの発動タイミングだが、敵か味方が技を出した直後、ダメージ量計算など諸々の処理が行われた後に、フィールドダメージの判定・発動処理が入る(味方の場合アイテム使用時も技として扱われる)。
まずは$7E:FEFDに記録されていく、戦闘のターン数増加時、4種類のフィールドの中でどのフィールドダメージを発生させるかを決定する。

$7E:FEFDは初期値が$00で、戦闘をまたいでも値は保持される。
敵または味方キャラが何かの技を出す、アイテムを使うなどした直後に、値が1ずつ加算されていく。
つまり1ターン終了時に値が加算される。
移動やパスのみでは増えないので、例えば幕末編のひとだまのように、使用技がなく戦闘中は移動しかしないような敵だと、ダメージフィールドを作って味方がパスや移動で時間経過させたとしても、ダメージフィールドはいつまでたっても発動しない。
(行動ポイントの増加などとは関係なく、単純に誰かが技を出した後に$7E:FEFDを増加する処理が入る、という仕組みのようだ)

ゲームがリセットされるか、メニュー画面を開くと$7E:FEFDの値は$00に上書きされる。
つまりセーブデータに保存される値ではない。
下のサブルーチンを見るとわかるが、オーバーフローは考慮されておらず、$FFまで増えた状態で更に+1されると$00が入る(+キャリーフラグが立つ)。
だが、仕様上、オーバーフローしても問題は生じない。

以下では引き続き、おぼろ丸が「忍法火炎ぼたる」で発生させた、火炎フィールドの発動時についての処理で説明を進める。

$C1/1F06 LDA $7EFEFD[$7E:FEFD]   ;Aに[$7E:FEFD]をロード
$C1/1F0A INC A                   ;Aをインクリメント +1
$C1/1F0B STA $7EFEFD[$7E:FEFD]   ;Aを[$7E:FEFD]に書き込み
$C1/1F0F AND #$03                ;Aと$03で論理積
$C1/1F11 BEQ $12    [$1F25]      ;ゼロフラグが立っているとき[$1F25]分岐→水フィールド
$C1/1F13 CMP #$01                ;Aと$01を減算比較(ステータスレジスタ変更のみ)
$C1/1F15 BEQ $18    [$1F2F]      ;ゼロフラグが立っているとき[$1F2F]分岐→毒フィールド
$C1/1F17 CMP #$02                ;Aと$02を減算比較(ステータスレジスタ変更のみ)
$C1/1F19 BEQ $1E    [$1F39]      ;ゼロフラグが立っているとき[$1F39]分岐→火炎フィールド
;ゼロフラグOFFで電撃フィールド

ここが、$7E:FEFDに値が加算される処理と、その値によりどのダメージフィールドを発動させるかを判断するサブルーチンである。
$C1/1F06$C1/1F0Bで、$7E:FEFDの値を+1している。
オーバーフロー時の分岐はない。

その後、$C1/1F0Fで、Aに入ったままの$7E:FEFDの値と$03で論理積を取り、論理積の値により分岐している。
何かの値と$03で論理積を取る場合、値は$00$03のいずれかであり、実質、「4で割った余り」と同値である。
後の処理を追いかけてみるとわかるが、論理積の値こと、「4で割った余り」によって発動するフィールドダメージは以下の通り。

論理積フィールドダメージ
$00水フィールド
$01毒フィールド
$02火炎フィールド
$03電撃フィールド

ゲーム開始時の$7E:FEFDの初期値は$00であり、戦闘に入って、誰かが技を出すなどして1ターン経過すると、[$7E:FEFD]には$01が入る。
$01に対応しているのは、上表より毒フィールドである。
つまり、1ターン目に毒フィールドを出せる技を使っておくと、技を出した直後、毒フィールドが発動することになる。
その後は1ターン経過毎に火炎→電撃→水→と続いて、毒に戻る。
これが、4ターン毎に各フィールドダメージが発動する仕組みである。
この仕組みのため、異なる種類のダメージフィールドが場にあったとしても、4種類の中のどれかしか一度に発動しないことになる。

また、フィールドでメニュー画面を開かない限り、$7E:FEFDの値は蓄積され続けるため、ターン数をカウントし調整すれば、任意の戦闘で初めて発動するダメージフィールドをプレイヤー側でコントロール可能であることもわかる。タイムアタックなど制限プレイでフィールドダメージを活用する場合、時短に繋がるかもしれない。

なお、$7E:FEFD$FFの時は、$FF$03の論理積が$03だから、電撃フィールドの発動ターンにあたる。
次のターンでは$7E:FEFDがオーバーフローして$00が入るが、$00$03の論理積が$00なので水フィールドが発動する。
このように、オーバーフローしたとしても、4ターン毎に各フィールドが発動する法則は崩れないので、オーバーフローに関する処理を入れていないのだろう、と推測される。

分岐先のフィールド毎の処理は以下のようになる。

;電撃フィールド
$C1/1F1B LDY #$2001              ;Yに$2001をロード
$C1/1F1E LDX #$3FFF              ;Xに$3FFFをロード
$C1/1F21 LDA #$E0                ;Aに$E0をロード
$C1/1F23 BRA $1C    [$1F41]      ;フラグにかかわりなく常に分岐[$1F41]
;
;水フィールド
$C1/1F25 LDY #$0808              ;Yに$0808をロード
$C1/1F28 LDX #$7FE0              ;Xに$7FE0をロード
$C1/1F2B LDA #$80                ;Aに$80をロード
$C1/1F2D BRA $12    [$1F41]      ;フラグにかかわりなく常に分岐[$1F41]
;
;毒フィールド
$C1/1F2F LDY #$1004              ;Yに$1004をロード
$C1/1F32 LDX #$7C1F              ;Xに$7C1Fをロード
$C1/1F35 LDA #$A0                ;Aに$A0をロード
$C1/1F37 BRA $08    [$1F41]      ;フラグにかかわりなく常に分岐[$1F41]
;
;火炎フィールド
$C1/1F39 LDY #$1802              ;Yに$1802をロード
$C1/1F3C LDX #$001F              ;Xに$001Fをロード
$C1/1F3F LDA #$C0                ;Aに$C0をロード
;
;処理合流
$C1/1F41 STY $06    [$00:0306]   ;Yを[$00:0307][$00:0306]に書き込み※[$00:0307]にダメージ量
$C1/1F43 STX $60    [$00:0360]   ;Xを[$00:0360]に書き込み
$C1/1F45 STA $10    [$00:0310]   ;Aを[$00:0310]に書き込み
$C1/1F47 JSR $3D2B  [$C1:3D2B]   ;[$C1:3D2B]へジャンプ

分岐先では4種類のフィールド毎にレジスタに読み込む数値が異なるが、実質、Yレジスタに読み込む2バイトの値の上1桁が、ダメージフィールドのダメージ量になっている。
処理合流後、$C1/1F41で、Yの値2バイト分が[$00:0307][$00:0306]に分かれて入るため、この時点で[$00:0307]にダメージフィールドのダメージ量が記録されたことになる。
[$00:0306]も後々で重要な値なので併記しておく。
以下、カッコ内は10進数。

フィールド[$00:0307][$00:0306]
電撃$20(32)$01
$08(8)$08
$10(16)$04
火炎$18(24)$02

また、A[$00:0310]に書き込まれるが、この値は該当マスに書き込まれるフィールドの値と同一である。

今回は「忍法火炎ぼたる」で火炎フィールドが発生しており、かつ、火炎フィールドが発動した前提で後の処理を見ていく。
実は発動が決まった直後に、発動後該当のダメージフィールドが消去されるかどうか、1マス毎の判定が入ることになる。

次ページで、ダメージフィールドの消去以降の処理について続ける。



このページをシェアする

上へ