基礎知識
戦闘関係
最終編ラストバトルの、オディオアイ×2・オディオモール・オディオマウス~ピュアオディオ戦は、本作においてかなり特殊な戦闘である。
これまでも、
ということは紹介したが、他にも、
といった、この戦闘専用の処理が行われている。
これらの仕様・処理がどうなっているのかを解説する。
まず、敵パーティデータについて見てみよう。
世界の合言葉は森部様の敵パーティデータ一覧を見ると、敵パーティデータの一番下、敵パーティデータID$FFがオディオアイ×2・オディオモール・オディオマウス戦に該当する。
だが、敵パーティデータID$FFに、ピュアオディオのデータは含まれていない。
敵は戦闘の最初に出現する4体のみが登録されており、5体目にピュアオディオ(敵ID$D1)がセットされている、ということはない。
| アドレス | No. | 数値 | 内容 |
|---|---|---|---|
$D6:512F | 00 | $00 | 敵パーティレベル |
$D6:5130 | 01 | $00 | 味方・敵の状態 |
$D6:5131 | 02 | $85 | 味方1 向き/初期座標 |
$D6:5132 | 03 | $8E | 味方2 向き/初期座標 |
$D6:5133 | 04 | $EE | 味方3 向き/初期座標 |
$D6:5134 | 05 | $F5 | 味方4 向き/初期座標 |
$D6:5135 | 06 | $04 | 上位8ビット:アイテム入手率補正 下位8ビット:敵の総数 |
$D6:5136 | 07 | $CD | 敵ID(0) オディオアイ |
$D6:5137 | 08 | $4A | 向き/初期座標(0) |
$D6:5138 | 09 | $CD | 敵ID(1) オディオアイ |
$D6:5139 | 10 | $22 | 向き/初期座標(1) |
$D6:513A | 11 | $D0 | 敵ID(2) オディオモール |
$D6:513B | 12 | $18 | 向き/初期座標(2) |
$D6:513C | 13 | $CE | 敵ID(3) オディオマウス |
$D6:513D | 14 | $15 | 向き/初期座標(3) |
$D6:513E | 15 | $00 | ラストバトル判定用数値 |
仕様について大雑把に種明かしをすると、本作では一度の戦闘に敵の種類は4種まで、敵総数は15体まで登録できるが、戦闘開始時に、
| 敵種類 | 敵 |
|---|---|
| 1 | オディオアイ |
| 2 | オディオモール |
| 3 | オディオマウス |
| 4 | (なし) |
| 敵番号 | 敵 |
|---|---|
| 0 | オディオアイ(左) |
| 1 | オディオアイ(右) |
| 2 | オディオモール |
| 3 | オディオマウス |
| 4 | (なし) |
と登録され、ピュアオディオは出現時に、
| 敵種類 | 敵 |
|---|---|
| 1 | オディオアイ |
| 2 | オディオモール |
| 3 | オディオマウス |
| 4 | ピュアオディオ |
| 敵番号 | 敵 |
|---|---|
| 0 | オディオアイ(左) |
| 1 | オディオアイ(右) |
| 2 | オディオモール |
| 3 | オディオマウス |
| 4 | ピュアオディオ |
このようにピュアオディオが追加される(同時にオディオモールは倒された扱いとなり、ピュアオディオだけ残る)。
まず、オディオアイ×2・オディオマウスを倒し、オディオモールのみ残った時にピュアオディオ戦に移行する時のサブルーチンについて紹介する。
敵のステータスなどが登録されるアドレスは以下の通り。
ピュアオディオ出現前まで、敵種類4の$00:1AC0~$00:1AFF、敵番号4の$00:1B40~, $7E:AA40~は敵が存在していない扱いである(ほとんどが$00で埋まっているが、全てではない)。
| 敵種類 | アドレス | 名前 |
|---|---|---|
| 1 | $00:1A00~$00:1A3F | オディオアイ |
| 2 | $00:1A40~$00:1A7F | オディオモール |
| 3 | $00:1A80~$00:1ABF | オディオマウス |
| 4 | $00:1AC0~$00:1AFF | ピュアオディオ |
| 敵番号 | アドレス | 名前 |
|---|---|---|
| 0 | $00:1B00~$00:1B0F, $7E:AA00~ | オディオアイ(左) |
| 1 | $00:1B10~$00:1B1F, $7E:AA10~ | オディオアイ(右) |
| 2 | $00:1B20~$00:1B2F, $7E:AA20~ | オディオモール |
| 3 | $00:1B30~$00:1B3F, $7E:AA30~ | オディオマウス |
| 4 | $00:1B40~$00:1B4F, $7E:AA40~ | ピュアオディオ |
重要となるのが、それぞれの敵が生存しているか倒されたかの判定である。
敵番号$00:1Bx1に、敵の戦闘状態が記録される。
| 値 | 状態 |
|---|---|
| $00 | 戦闘離脱 |
| $20 | 敵キャラをプレイヤーが操作 |
| $40 | 味方キャラが敵状態 |
| $80 | 敵総数+1の敵番号 |
| $FF | 通常 |
戦闘開始時、オディオアイ、オディオモール、オディオマウスは戦闘状態が通常で、存在しない5体目の敵であるアドレス$00:1B41には$80が入る。
| 敵番号 | アドレス | 名前 | 値 |
|---|---|---|---|
| 0 | $00:1B01 | オディオアイ(左) | $FF |
| 1 | $00:1B11 | オディオアイ(右) | $FF |
| 2 | $00:1B21 | オディオモール | $FF |
| 3 | $00:1B31 | オディオマウス | $FF |
| 4 | $00:1B41 | (なし) | $80 |
オディオモール以外の敵を倒すと、オディオアイとオディオマウスの戦闘状態には、戦闘離脱を意味する$00が入る。
| 敵番号 | アドレス | 名前 | 値 |
|---|---|---|---|
| 0 | $00:1B01 | オディオアイ(左) | $00 |
| 1 | $00:1B11 | オディオアイ(右) | $00 |
| 2 | $00:1B21 | オディオモール | $FF |
| 3 | $00:1B31 | オディオマウス | $00 |
| 4 | $00:1B41 | (なし) | $80 |
この状況だと、何らかの判定の後にピュアオディオ戦へ移行する処理が入るはずだ。
ピュアオディオ出現処理に移行するかどうか、また移行後の処理は$C1/7BCE~$C1/7F92で判定されている。
$C1/7BCE自体はどの戦闘でも判定のために通過するのだが、後述の処理で、ピュアオディオ出現時以外は$C1/7BD3でサブルーチンを抜ける。
ここでは、敵を撃破して$00:1B?1に$00(戦闘離脱)が入るまでの処理の説明は端折る。
処理自体は以下。
$C1/0552 STZ $0001,x ;[$00:1Bx1]に$00を書き込み $C1/0555 LDA #$FF ;Aに$FFをロード $C1/0557 STA $FF [$00:03FF] ;Aを[$00:03FF]に書き込み $C1/0559 JSR $6121 [$C1:6121] ;[$C1:6121]へジャンプ
$C1/7BCE~の処理は以下のようになっている。
$C1/7BCE JSR $03FA [$C1:03FA] ;[$C1:03FA]へジャンプ ; $C1/03FA LDX #$1B00 ;Xに$1B00をロード ;敵番号nが通常状態の時、敵IDが$D0=オディオモールかループ判定 $C1/03FD LDA $0001,x ;Aに[$00:1Bn1](敵番号nの戦闘状態 $FF=通常)をロード $C1/0400 BEQ $11 [$0413] ;ゼロフラグが立っているとき[$0413]分岐 $C1/0402 CMP #$80 ;Aと$80を減算比較(ステータスレジスタ変更のみ) $C1/0404 BEQ $1B [$0421] ;ゼロフラグが立っているとき[$0421]分岐 $C1/0406 LDA $0000,x ;Aに[$00:1Bn0](敵番号nの敵ID)をロード $C1/0409 CMP #$D0 ;Aと$D0を減算比較(ステータスレジスタ変更のみ) $C1/040B BNE $17 [$0424] ;ゼロフラグが立っていないとき[$0424]分岐 $C1/040D LDA #$00 ;Aに$00をロード $C1/040F STA $7E8F02,x ;A($00)を[$7E8F02,x]に書き込み $C1/0413 REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/0415 TXA ;Xレジスタの値をAレジスタに転送 $C1/0416 ADC #$0010 ;A + $0010 $C1/0419 TAX ;Aの値をXレジスタに転送 $C1/041A SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/041C CPX #$1C00 ;Xと$1C00を減算比較(ステータスレジスタ変更のみ) $C1/041F BNE $DC [$03FD] ;ゼロフラグが立っていないとき[$03FD]分岐 ;ループここまで ;$C1/0404でゼロフラグON $C1/0421 LDA #$00 ;Aに$00をロード $C1/0423 RTS ;サブルーチン戻り ;$C1/040BでゼロフラグOFF $C1/0424 LDA #$FF ;Aに$FFをロード $C1/0426 RTS ;サブルーチン戻り
$C1/03FA~$C1/0426が、敵番号0から順に、敵がオディオモールかどうかループ判定していくサブルーチンである。
まず、$C1/03FDで、[$00:1Bn1](敵番号nの戦闘状態)が$00、つまり既に撃破しており戦闘離脱かを判定している。
戦闘離脱だとゼロフラグが立って$C1/0413にジャンプするから、$C1/0402~$C1/040Fがスキップされる。
$C1/0402~$C1/0404は、戦闘状態が$80かの判定。
戦闘状態が$80は、敵番号の末尾がどこかを判定するために入る値であり、たとえばこの戦闘のように敵が4体なら、5体目に戦闘状態$80が入る。
$C1/0406に入った時点で戦闘状態は$00でも$80でもないことになる。つまり、この判定の時点で生存している敵である。
ここで、[$00:1Bn0](敵ID)と$D0を減算比較し、ゼロフラグ判定をしている。
敵IDが$D0はオディオモールなので、ここでゼロフラグが立つのはオディオモールのみである。
オディオモール以外なら、$C1/0424に飛ぶので、Aに$FFをロードして$C1/0426でサブルーチンを抜けて終了となる。
オディオモールだと[$7E8F02,x]に$00を読み込んでループ末尾まで飛び、ループ頭へ戻る。
さて、この処理で何が起こるのか。
敵が生存している場合は、$C1/040Bでオディオモールでない限り$C1/0424にジャンプしてループから抜ける。
つまり、オディオモールがいない戦闘だと、必ず$C1/0424にジャンプしてループから抜ける。
また、オディオモールがいる場合でも、オディオモール以外が生存していたら、結局$C1/0424にジャンプしてループから抜ける。
判定順はオディオアイ(左)→オディオアイ(右)→オディオモール→オディオマウスであるから、オディオアイを両方倒していないとオディオモール自身のオディオモール判定までたどり着かないし、オディオモールの処理までたどり着いてもオディオマウスが生存していたらオディオモール判定で弾かれて$C1/0424にジャンプしてしまう。
つまり上のループは、最終編ラストバトルかつ、オディオアイ・マウスが倒されている状態で、オディオモールだけが生存している、という状態の時だけ、ループ5周目にたどりつくことになる。
ループ5周目で、$C1/0404のゼロフラグがONになり、$C1/0421にジャンプする。
この場合はAに$00をロードしてサブルーチンが戻る。
整理すると、
Aに$00をロードしてサブルーチン戻りAに$FFをロードしてサブルーチン戻りということになり、1.がピュアオディオ戦発生分岐だったということがわかる。
オディオモールを先に倒してしまった場合、1.の条件は絶対に満たせなくなるため、ピュアオディオは出現しないのである。
$C1/7BD1 BEQ $01 [$7BD4] ;ゼロフラグが立っているとき[$7BD4]分岐 ;ゼロフラグOFF $C1/7BD3 RTS ;サブルーチン戻り ;ゼロフラグON $C1/7BD4 LDA #$10 ;Aに$10をロード $C1/7BD6 JSR $121C [$C1:121C] ;[$C1:121C]へジャンプ
サブルーチンが戻った先が上で、ゼロフラグ判定になる。
ゼロフラグが立つのは「最終編ラストバトルかつ、オディオアイ・マウスが倒されている状態で、オディオモールだけが生存」の時だけで、この時のみ$C1/7BD4に処理が進み、そうでなければ$C1/7BD3でサブルーチンを抜けてピュアオディオ戦へ移行しない。
$C1/7BD4以降は、ピュアオディオ戦発生処理へと進むことになる。
この後はしばらくモーションなどの処理があるので紹介は端折る。
$C1/7BD6の戻り先が$C1/7BDEなのだが、ここでサウンド関係の処理が入る。
筆者はサウンド関連のサブルーチンについては詳しくないため、とりあえずわかる箇所のみ解説する。
$C1/7BDE LDA #$1C ;Aに$1Cをロード $C1/7BE0 JSR $12FE [$C1:12FE] ;[$C1:12FE]へジャンプ
まず、$C1/7BDEでAに読み込まれる$1Cという値なのだが、これはBGMのID$1C、サウンドトラックの曲名の「PURE ODIO」である。
つまり、ラストバトル後半、ピュアオディオ出現後のBGMのIDがここでAに読み込まれたことになる。
$C1/12FE STA $10 [$00:0310] ;A($1C)を[$00:0310]に書き込み $C1/1300 LDA $AA [$00:03AA] ;Aに[$00:03AA]をロード $C1/1302 BEQ $04 [$1308] ;ゼロフラグが立っているとき[$1308]分岐 $C1/1304 LDA #$10 ;Aに$10をロード $C1/1306 BRA $3C [$1344] ;フラグにかかわりなく常に分岐[$1344] $C1/1344 STA $1D00 [$00:1D00] ;A($10)を[$00:1D00]に書き込み $C1/1347 LDA $10 [$00:0310] ;Aに[$00:0310]($1C)をロード $C1/1349 AND #$7F ;Aと$7Fで論理積 $C1/134B STA $1D01 [$00:1D01] ;A($1C)を[$00:1D01]に書き込み $C1/134E LDA #$FF ;Aに$FFをロード $C1/1350 STA $1D02 [$00:1D02] ;A($FF)を[$00:1D02]に書き込み $C1/1353 JSR $11D8 [$C1:11D8] ;[$C1:11D8]へジャンプ ; $C1/11D8 LDA $0040 [$00:0040] ;Aに[$00:0040]をロード $C1/11DB CMP #$04 ;Aと$04を減算比較(ステータスレジスタ変更のみ) $C1/11DD BEQ $04 [$11E3] ;ゼロフラグが立っているとき[$11E3]分岐 $C1/11DF JSL $C30004[$C3:0004] ;[$C3:0004]へジャンプ ; $C3/0004 JMP $0131 [$C3:0131] ;[$C3:0131]へジャンプ(レジスタをスタックに積まない) ;(中略) $C3/0160 JMP ($0734,x)[$C3:0180] ;[$C3:0180]へジャンプ(レジスタをスタックに積まない) $C3/0180 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C3/0182 LDA $01 [$00:1D01] ;Aに[$00:1D01]($1C)をロード $C3/0184 CMP $05 [$00:1D05] ;Aと[$00:1D05](現在のBGM)を減算比較(ステータスレジスタ変更のみ) $C3/0186 BEQ $E9 [$0171] ;ゼロフラグが立っているとき[$0171]分岐 $C3/0188 CMP $C33FC8[$C3:3FC8] ;Aと[$C3:3FC8]を減算比較(ステータスレジスタ変更のみ) $C3/018C BCS $E3 [$0171] ;キャリーフラグが立っているとき[$0171]分岐 $C3/018E JSR $062F [$C3:062F] ;[$C3:062F]へジャンプ
細かい説明は省くが(というか筆者の知識が足らないが)、Aから[$00:1D01]に$1Cの値がコピーされ、おそらく各種のフラグ判定後、最後の$C3/0182で、現在のBGMのIDが書き込まれている[$00:1D05]と、[$00:1D01]($1C)を減算比較しゼロフラグ判定をしている。
つまり、現在のBGMが「PURE ODIO」かどうかの判定である。
この時点では、ピュアオディオ戦への移行が決まっただけで、BGMには変化がない。前半戦のBGM「ILLUSION…」(BGMのID$4B)が入っている。
よって、この時点ではゼロフラグが立たず、BGMの切り替え処理に続くことになる。
[$00:1D05](現在のBGM)にピュアオディオ戦のBGMである$1Cが書き込まれるのは以下の処理。
$C3/04F1 STA $1E [$00:1D1E] ;Aを[$00:1D1E]に書き込み $C3/04F3 INY ;Yをインクリメント +1 $C3/04F4 INY ;Yをインクリメント +1 $C3/04F5 CPY #$0020 ;Yと$0020を減算比較(ステータスレジスタ変更のみ) $C3/04F8 BNE $E1 [$04DB] ;ゼロフラグが立っていないとき[$04DB]分岐 $C3/04FA LDA #$F0 ;Aに$F0をロード $C3/04FC STA $1E [$00:1D1E] ;Aを[$00:1D1E]に書き込み $C3/04FE SEP #$20 ;MフラグON Aレジスタは8bit幅 $C3/0500 LDA $05 [$00:1D05] ;Aに[$00:1D05]をロード $C3/0502 BMI $08 [$050C] ;ネガティブフラグが立っているとき[$050C]分岐 $C3/0504 LDX $04 [$00:1D04] ;Xに[$00:1D03][$00:1D04]をロード $C3/0506 STX $08 [$00:1D08] ;Xを[$00:1D07][$00:1D08]に書き込み $C3/0508 LDX $06 [$00:1D06] ;Xに[$00:1D05][$00:1D06]をロード $C3/050A STX $0A [$00:1D0A] ;Xを[$00:1D0B][$00:1D0A]に書き込み $C3/050C LDX $00 [$00:1D00] ;Xに[$00:1D01][$00:1D00]($1C10)をロード $C3/050E STX $04 [$00:1D04] ;Xを[$00:1D05][$00:1D04]に書き込み $C3/0510 LDX $02 [$00:1D02] ;Xに[$00:1D03][$00:1D02]をロード $C3/0512 STX $06 [$00:1D06] ;Xを[$00:1D07][$00:1D06]に書き込み
$C3/050CでXに[$00:1D01][$00:1D00]をロードしている(2バイト)。
$C1/1344で[$00:1D00]に$10が、[$00:1D01]に$1C(「PURE ODIO」のBGMID)が書き込まれたから、ここでXにロードされた値は$1C10である。
それを$C3/050Eで[$00:1D05][$00:1D04]に書き込んでいるから、[$00:1D05]に$1C、[$00:1D04]に$10がコピーされたことになる。
ここで、[$00:1D05](現在のBGM)に$1Cが入り、ピュアオディオ戦のBGMのIDがセットされた。
この後のBGMデータの呼び出しや転送については端折る。
一通りBGM関係の処理が終わるのが$C3/017Fで、そこから$C1/11E3→$C1/1241→$C1/1359~$C1/1363とサブルーチンが戻ると、$C1/7BE0からの戻り位置、$C1/7BE3に処理が続く。
$C1/7BE3 LDA #$FE ;Aに$FEをロード $C1/7BE5 STA $77 [$00:0377] ;Aを[$00:0377]に書き込み $C1/7BE7 LDA #$FF ;Aに$FFをロード $C1/7BE9 STA $85 [$00:0385] ;Aを[$00:0385]に書き込み $C1/7BEB JSR $6145 [$C1:6145] ;[$C1:6145]へジャンプ ;(戦闘タイマー処理など省略) $C1/7BEE JSR $8702 [$C1:8702] ;[$C1:8702]へジャンプ ; ;($C1/8702~$C1/8713 省略) ; $C1/7BF1 LDY #$1B40 ;Yに$1B40をロード $C1/7BF4 STY $1E [$00:031E] ;Yを[$00:031E]に書き込み $C1/7BF6 LDA #$D1 ;Aに$D1をロード(敵ID$D1はピュアオディオ) $C1/7BF8 JSR $FB7C [$C1:FB7C] ;[$C1:FB7C]へジャンプ
$C1/7BE3~$C1/7BF4までは説明を省く。
重要なのは$C1/7BF6でAにロードした$D1で、敵ID$D1はピュアオディオである。
この状態で$C1/FB7Cにジャンプする。
$C1/FB7C STA $10 [$00:0310] ;A($D1)を[$00:0310]に書き込み $C1/FB7E LDY #$1A00 ;Yに$1A00をロード ;敵種類nの判定ループ $C1/FB81 LDA $0001,y ;Aに[$00:1An1]をロード $C1/FB84 BEQ $23 [$FBA9] ;ゼロフラグが立っているとき[$FBA9]分岐 $C1/FB86 LDA $10 [$00:0310] ;Aに[$00:0310]($D1)をロード $C1/FB88 CMP #$FF ;Aと$FFを減算比較(ステータスレジスタ変更のみ) $C1/FB8A BEQ $07 [$FB93] ;ゼロフラグが立っているとき[$FB93]分岐 $C1/FB8C LDA $0000,y ;Aに[$00:1An0](敵種類nの敵ID$CD)をロード $C1/FB8F CMP $10 [$00:0310] ;Aと[$00:0310]($D1)を減算比較(ステータスレジスタ変更のみ) $C1/FB91 BEQ $2B [$FBBE] ;ゼロフラグが立っているとき[$FBBE]分岐 $C1/FB93 REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/FB95 TYA ;Yレジスタの値をAレジスタに転送 $C1/FB96 ADC #$0040 ;A + $0040 $C1/FB99 TAY ;Aの値をYレジスタに転送 $C1/FB9A SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/FB9C CPY #$1B00 ;Yと$1B00を減算比較(ステータスレジスタ変更のみ) $C1/FB9F BNE $E0 [$FB81] ;ゼロフラグが立っていないとき[$FB81]分岐 ;ループここまで $C1/FBA9 LDA $10 [$00:0310] ;Aに[$00:0310]($D1)をロード $C1/FBAB STA $0000,y[$00:1AC0] ;A($D1)を[$00:1AC0]に書き込み $C1/FBAE LDA #$FF ;Aに$FFをロード $C1/FBB0 STA $0001,y[$00:1AC1] ;A($FF)を[$00:1AC1]に書き込み $C1/FBB3 LDA #$00 ;Aに$00をロード $C1/FBB5 STA $000A,y[$00:1ACA] ;Aを[$00:1ACA]に書き込み $C1/FBB8 JSR $FC0A [$C1:FC0A] ;[$C1:FC0A]へジャンプ
まず、[$00:0310]に$D1(ピュアオディオの敵ID)を書き込んでから、ループ処理に入る。
ループ頭$C1/FB81で、[$00:1A01], [$00:1A41], [$00:1A81], [$00:1AC1]……をロードするが、これは該当の敵種類が敵パーティ内に存在しているなら$FF、存在していないなら$00が入るアドレスのため、3種類の敵が出現したこの戦闘では、[$00:1A01], [$00:1A41], [$00:1A81]に$FF、[$00:1AC1]に$00が入っている。
$C1/FB8Cでは、[$00:1A00], [$00:1A40], [$00:1A80]と、敵種類1~4の敵IDを読み込み、$D1と減算比較してゼロフラグ判定をしている。
現時点では、「最終編ラストバトルかつ、オディオアイ・マウスが倒されている状態で、オディオモールだけが生存」という状況のため、ピュアオディオはいない。
以上から、ループ4周目頭で$C1/FB84でゼロフラグが立ち、$C1/FBA9に分岐することになる。
$C1/FBA9以降の処理を見ると、[$00:1AC0]に$D1、[$00:1AC1]に$FF、[$00:1ACA]に$00を書き込んでいる。
つまり、ここで敵種類4の敵IDが入る[$00:1AC0]に$D1(ピュアオディオ)、[$00:1AC1]の敵種類存在状態に$FFが登録された。
こうしてピュアオディオが敵パーティに加わったことになる。
ジャンプ先の$C1:FC0A以降はこれまでも紹介したことがあるが、敵データIDから、敵データのロード&$00:1AC0~への書き込み処理になる。
更にその後は$C1:FC3F~$C1:FC58で技1~4の反撃属性1/反撃属性2/使用不可になるステータス異常を書き込む。
これでピュアオディオのステータスの大半がセットされたことになる。
ひとつ問題なのは、ピュアオディオは敵パーティデータにデータがないので、初期座標と向きが敵パーティデータから読み出せない。
つまり、他の敵キャラとは異なる方法で初期座標と向きを設定していることになる。
これまでにも紹介したことがある、敵IDや敵座標セット用サブルーチン$C1:FBBE~$C1:FBFD自体は今回でも処理が行われる。
$C1/FBBE STY $12 [$00:0312] ;Yを[$00:0312]に書き込み $C1/FBC0 LDY $1E [$00:031E] ;Yに[$00:031E](1AC0)をロード $C1/FBC2 LDA $10 [$00:0310] ;Aに[$00:0310]($D1)をロード $C1/FBC4 STA $0000,y[$00:1B40] ;Aを[$00:1B40](敵ID $D1 ピュアオディオ)に書き込み $C1/FBC7 LDA #$FF ;Aに$FFをロード $C1/FBC9 STA $0001,y[$00:1B41] ;Aを[$00:1B41](戦闘状態$FF)に書き込み $C1/FBCC LDA #$00 ;Aに$00をロード $C1/FBCE STA $0005,y[$00:1B45] ;Aを[$00:1B45]に書き込み $C1/FBD1 STA $0006,y[$00:1B46] ;Aを[$00:1B46]に書き込み $C1/FBD4 STA $0007,y[$00:1B47] ;Aを[$00:1B47]に書き込み $C1/FBD7 LDA $12 [$00:0312] ;Aに[$00:0312]をロード $C1/FBD9 STA $0002,y[$00:1B42] ;Aを[$00:1B42]に書き込み $C1/FBDC LDA $13 [$00:0313] ;Aに[$00:0313]をロード $C1/FBDE STA $0003,y[$00:1B43] ;Aを[$00:1B43]に書き込み $C1/FBE1 LDA $D60008,x[$D6:1B48] ;Aに[$D6:1B48]($69)をロード $C1/FBE5 STA $10 [$00:0310] ;Aを[$00:0310]($69)に書き込み $C1/FBE7 AND #$C0 ;Aと$C0で論理積 $C1/FBE9 STA $0004,y[$00:1B44] ;A($40)を[$00:1B44](向き)に書き込み $C1/FBEC LDA $10 [$00:0310] ;Aに[$00:0310]($69)をロード $C1/FBEE AND #$38 ;Aと$38で論理積 $C1/FBF0 LSR A ;Aを論理右シフト (/2) $C1/FBF1 LSR A ;Aを論理右シフト (/2) $C1/FBF2 LSR A ;Aを論理右シフト (/2) $C1/FBF3 STA $000A,y[$00:1B4A] ;A($05)を[$00:1B4A](現在のマス目のX座標)に書き込み $C1/FBF6 LDA $10 [$00:0310] ;Aに[$00:0310]($69)をロード $C1/FBF8 AND #$07 ;Aと$07で論理積 $C1/FBFA STA $000B,y[$00:1B4B] ;A($01)を[$00:1B4B](現在のマス目のY座標)に書き込み $C1/FBFD JSR $FC78 [$C1:FC78] ;[$C1:FC78]へジャンプ
本来、$C1/FBE1でロードする$D60008,x([$D6:1B48])は、敵パーティデータの向き/初期座標が記録されたアドレスになる。
なのだが、敵パーティデータが記録されているアドレスは$D6:4280~$D6:512Eなのに、範囲外の$D6:1B48が呼び出されている。
敵パーティデータにピュアオディオが登録されていないため、上サブルーチンではXの値が正しく計算されておらず(X:1B40)、敵パーティデータ内のアドレスが呼び出せていない。
それならそれで、[$D6:1B48](=$69)でピュアオディオの初期位置や向きが正しく計算されているなら問題がないのだが、上の結果を見ると、
| 内容 | アドレス | 値 |
|---|---|---|
| 向き | [$00:1B44] | $40(%0100 0000)/左下 |
| X座標 | [$00:1B4A] | $05 |
| Y座標 | [$00:1B4B] | $01 |
ピュアオディオの初期での向きは左下なので合っている。
だが、座標は合っていない。
座標(5,1)だと以下の位置になってしまう(敵の左上マスが原点(0,0)にあたる)。
★が座標(5,1)である。
座標は敵の左上マスで指定されるため、横3マス×縦2マスサイズのピュアオディオは戦闘フィールドからはみ出すことになる。
そもそもX座標もY座標も実際のゲームでの出現位置とはまったく一致していない。
ということで、向きだけは上の処理で左下向きに決定されるのだが、座標についてはピュアオディオ用の専用処理で修正が入る。
$C1/7BF8の続きにサブルーチンが戻ってくる。
$C1/7BFB LDA #$80 ;Aに$80をロード $C1/7BFD STA $1B51 [$00:1B51] ;Aを[$00:1B51](敵番号5の戦闘状態)に書き込み $C1/7C00 LDX #$1B40 ;Xに$1B40をロード $C1/7C03 LDA #$02 ;Aに$02をロード $C1/7C05 STA $000A,x[$00:1B4A] ;Aを[$00:1B4A](敵番号4のマス目のX座標)に書き込み $C1/7C08 INC A ;Aをインクリメント +1 $C1/7C09 STA $000B,x[$00:1B4B] ;Aを[$00:1B4B](敵番号4のマス目のY座標)に書き込み $C1/7C0C LDA #$06 ;Aに$06をロード $C1/7C0E STA $9E [$00:039E] ;Aを[$00:039E]に書き込み $C1/7C10 LDX #$1AC0 ;Xに$1AC0をロード $C1/7C13 STX $9A [$00:039A] ;Xを[$00:039A]に書き込み $C1/7C15 JSR $63F6 [$C1:63F6] ;[$C1:63F6]へジャンプ
敵4体目が登録されたため、敵番号5戦闘状態[$00:1B51]に終了を意味する$80を書き込む。
更に、先の処理で妙な位置に指定された初期座標アドレス[$00:1B4A][$00:1B4B]を修正する。
上処理を見ると[$00:1B4A]に$02、[$00:1B4B]に$03を書き込んでいる。
つまり、初期座標が(2,3)に決定した。この位置はピュアオディオ(横3マス×縦2マス)の左上位置になる。
下図の★が座標(2,3)である。
上ではピュアオディオが占める位置を■で書き込んでいるが、実際には縦幅と横幅を計算・書き込む必要がある。
それが$C1/63F6からの処理だが、重要な箇所だけ抜粋する。
敵種類4の横の幅は[$00:1AC3]、縦の幅は[$00:1AC4]に書き込まれる。
$C1/63F6 PHX ;Xをスタックにプッシュ $C1/63F7 JSR $65E9 [$C1:65E9] ;[$C1:65E9]へジャンプ ; $C1/65E9 STX $9A [$00:039A] ;X(1AC0)を[$00:039A]に書き込み $C1/65EB LDA $0000,x[$00:1AC0] ;Aに[$00:1AC0](敵種類4 ピュアオディオ敵ID$D1)をロード ;(中略) $C1/660A JSR $6706 [$C1:6706] ;[$C1:6706]へジャンプ ;(中略) $C1/6706 JSR $6612 [$C1:6612] ;[$C1:6612]へジャンプ ;(中略) $C1/6612 STZ $A5 [$00:03A5] ;[$00:03A5]に$00を書き込み $C1/6614 REP #$20 ;Aを16bit幅に変更、Mフラグをクリア $C1/6616 AND #$00FF ;Aと$00FFで論理積 $C1/6619 STA $10 [$00:0310] ;A($00EC)を[$00:0311][$00:0310]に書き込み $C1/661B ASL A ;Aを算術左シフト *2 $C1/661C ADC $10 [$00:0310] ;A + [$00:0311][$00:0310]=02C4 $C1/661E ADC $D50050[$D5:0050] ;A + [$D5:0051][$D5:0050]=FC3D $C1/6622 TAX ;Aの値(FC3D)をXレジスタに転送 $C1/6623 LDA $D50000,x[$D5:FC3D] ;Aに[$D5:FC3E][$D5:FC3D](88D9)をロード $C1/6627 STA $A2 [$00:03A2] ;A(88D9)を[$00:03A3][$00:03A2]に書き込み $C1/6629 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/662B LDA $D50002,x[$D5:FC3F] ;Aに[$D5:FC3F]($DA)をロード $C1/662F STA $9C [$00:039C] ;A($DA)を[$00:039C]に書き込み ;(中略) $C1/663D JSR $6B43 [$C1:6B43] ;[$C1:6B43]へジャンプ
敵の縦・横幅は、敵キャラデータの中にはなく、上のサブルーチンで敵ごとに計算している。
まず重要なのが$C1/662Bでロードする[$D5:FC3F]で、[$D5:FC3F]のアドレス計算がそれ以前の処理だが詳細は省略。
[$D5:FC3F]には$DAが格納されており、[$00:039C]に書き込まれる。
この後の処理は(たぶん)グラフィック関連なので少し省略する。
敵の縦・横幅のサブルーチンの一部は味方との戦闘 > 最終編オルステッド主人公時(1)でも紹介したが、そのあたりが以下の処理。
$C1/6641 LDA $9C [$00:039C] ;Aに[$00:039C]をロード $C1/6643 AND #$38 ;Aと$38で論理積 $C1/6645 LSR A ;Aを論理右シフト (/2) $C1/6646 STA $10 [$00:0310] ;Aを[$00:0310]に書き込み $C1/6648 LSR A ;Aを論理右シフト (/2) $C1/6649 LSR A ;Aを論理右シフト (/2) $C1/664A STA $20 [$00:0320] ;Aを[$00:0320]に書き込み $C1/664C LDA $9C [$00:039C] ;Aに[$00:039C]をロード $C1/664E AND #$07 ;Aと$07で論理積 $C1/6650 CMP #$07 ;Aと$07を減算比較(ステータスレジスタ変更のみ) $C1/6652 BEQ $08 [$665C] ;ゼロフラグが立っているとき[$665C]分岐 $C1/6654 STA $21 [$00:0321] ;Aを[$00:0321]に書き込み $C1/6656 ASL A ;Aを算術左シフト *2 $C1/6657 ADC $21 [$00:0321] ;A + [$00:0321] $C1/6659 STA $11 [$00:0311] ;Aを[$00:0311]に書き込み $C1/665B RTS ;サブルーチン戻り $C1/670C LDX $9A [$00:039A] ;Xに[$00:039A]をロード $C1/670E LDA $10 [$00:0310] ;Aに[$00:0310]をロード $C1/6710 STA $0002,x[$00:1AC2] ;Aを[$00:1AC2]に書き込み $C1/6713 LDA $11 [$00:0311] ;Aに[$00:0311]をロード $C1/6715 STA $0003,x[$00:1AC3] ;Aを[$00:1AC3]に書き込み $C1/6718 LDA $20 [$00:0320] ;Aに[$00:0320]をロード $C1/671A STA $0004,x[$00:1AC4] ;Aを[$00:1AC4](敵種類4 横の幅)に書き込み $C1/671D LDA $21 [$00:0321] ;Aに[$00:0321]をロード $C1/671F STA $0005,x[$00:1AC5] ;Aを[$00:1AC5](敵種類4 縦の幅)に書き込み $C1/6722 LDY #$3000 ;Yに$3000をロード $C1/6725 JSR $6665 [$C1:6665] ;[$C1:6665]へジャンプ
[$D5:FC3F] = [$00:039C] = $DAを元として計算した以下の値が、敵種類4のアドレスに以下のように書き込まれる。
| 敵種類4アドレス | 元アドレス | 計算値 |
|---|---|---|
[$00:1AC2] | [$00:0310] | $DA & $38 /2 = $0C |
[$00:1AC3] | [$00:0311] | $DA & $07 *2 + $DA & $07 = $06 |
[$00:1AC4] | [$00:0320] | $DA & $38 /2/2/2 = $03 |
[$00:1AC5] | [$00:0321] | $DA & $07 = $02 |
ピュアオディオの横幅が$03、縦幅が$02と計算されて[$00:1AC4][$00:1AC5]にそれぞれ書き込まれたことがわかる。
なお、このあたりまでが、最後のオディオアイまたはマウスを撃破して、戦闘フィールドにオディオモールだけが残った状態になり、サウンドも一時消えたタイミングである。
この後、BGMが切り替わり、オディオモールがピュアオディオ初期配置へと移動し始める。
BGM切り替わり~オディオモール移動開始までは、いわばウェイトをかけて、キャラが動く処理などは行われないのだが、そのウェイト処理が以下。
;(中略) $C1/614D BPL $FB [$614A] ;ネガティブフラグが立っていないとき[$614A]分岐 $C1/614A LDA $4212 [$00:4212] ;Aに[$00:4212]をロード *** NMI ;マスク不可能割り込み $00/00F8 JMP $C1856C[$C1:856C] ;[$C1:856C]へジャンプ(レジスタをスタックに積まない) ;(中略) $C1/66BC DEC $08 [$00:0308] ;[$00:0308]をデクリメント -1 $C1/66BE BNE $CA [$668A] ;ゼロフラグが立っていないとき[$668A]分岐 $C1/668A LDY $1E [$00:031E] ;Yに[$00:031E]をロード $C1/668C STY $2116 [$00:2116] ;Yを[$00:2116]に書き込み $C1/668F LDY $12 [$00:0312] ;Yに[$00:0312]をロード $C1/6691 STY $4302 [$00:4302] ;Yを[$00:4302]に書き込み $C1/6694 LDA $12 [$00:0312] ;Aに[$00:0312]をロード $C1/6696 CLC ;キャリーフラグクリア $C1/6697 ADC #$80 ;A + $80 $C1/6699 STA $12 [$00:0312] ;Aを[$00:0312]に書き込み $C1/669B BCC $02 [$669F] ;キャリーフラグが立っていないとき[$669F]分岐 $C1/669D INC $13 [$00:0313] ;A[$00:0313]をインクリメント +1 $C1/669F LDA $0000,x[$00:1AC0] ;Aに[$00:1AC0]をロード $C1/66A2 CMP #$D1 ;Aと$D1を減算比較(ステータスレジスタ変更のみ) $C1/66A4 BNE $03 [$66A9] ;ゼロフラグが立っていないとき[$66A9]分岐 $C1/66A6 JSR $6145 [$C1:6145] ;[$C1:6145]へジャンプ ; $C1/6145 LDA $4212 [$00:4212] ;Aに[$00:4212]をロード $C1/6148 BMI $FB [$6145] ;ネガティブフラグが立っているとき[$6145]分岐 ;(中略)
$C1/6145~$C1/614Fはコントローラーのボタン判定で、何かしらのボタンを押すまでループ処理を繰り返し、1フレーム毎にNMIという割り込み処理で強引に終了させている。
本作では、「その場面で必要な何らかの処理→コントローラーのボタン判定ループ→ボタンが押されないならNMIで割り込んで次処理」を1フレーム毎に繰り返す、がプログラムの基本である。
ここでは、「その場面で必要な何らかの処理」が、戦闘用タイマー[$7E:FEF0]を減らすことくらいなのである。
上処理を見ると$C1/669Fで、敵種類4の[$00:1AC0](敵ID)と$D1を減算比較しているが、敵ID$D1、つまりピュアオディオだと$C1/66A4でゼロフラグが立って、コントローラーのボタン判定ループに移行する。
つまり、このタイミングでは必要な処理がここで終了となっており、演出上ウェイトをかけていることがわかる。
ピュアオディオの敵IDを指定しているので、ピュアオディオ戦専用処理ということになる。
ちなみにこのウェイトは36回(36フレーム)分である。[$00:0308]のデクリメントでループ回数が指定されている。
1秒で60フレームなので、だいたい0.5秒くらいになる。
さて、ピュアオディオ戦に移行する時に重要な処理がもうひとつある。
ピュアオディオの初期位置にいる味方キャラの処理である。
実際にやってみればわかるとおりに、ピュアオディオの初期位置にいる味方キャラは戦闘フィールド隅に強制的に移動させられるが、この処理はどうなっているのか。
戦闘フィールド上の居場所の処理であるから、どのマスに誰がいるのかを把握しなければならない。
$00:04C8~$00:04FEが戦闘フィールドの状況であり、敵味方の居場所及び、ダメージフィールドの状態を記録できるようになっている。
$00:04??の??部分のみが以下。
| C8 | C9 | CA | CB | CC | CD | CE |
| D0 | D1 | D2 | D3 | D4 | D5 | D6 |
| D8 | D9 | DA | DB | DC | DD | DE |
| E0 | E1 | E2 | E3 | E4 | E5 | E6 |
| E8 | E9 | EA | EB | EC | ED | EE |
| F0 | F1 | F2 | F3 | F4 | F5 | F6 |
| F8 | F9 | FA | FB | FC | FD | FE |
つまり、ピュアオディオの初期位置は、
| アドレス | 内容 |
|---|---|
$00:04E2 | ピュアオディオ初期位置1 |
$00:04E3 | ピュアオディオ初期位置2 |
$00:04E4 | ピュアオディオ初期位置3 |
$00:04EA | ピュアオディオ初期位置4 |
$00:04EB | ピュアオディオ初期位置5 |
$00:04EC | ピュアオディオ初期位置6 |
にあたる。
便宜上、上のようにピュアオディオ位置1~6と番号を振っておく。
これら座標の処理は、$C1/7C15の戻り位置、$C1/7C18から処理が開始になる。
$C1/7C18 LDX #$1B40 ;Xに$1B40をロード $C1/7C1B JSR $51FB [$C1:51FB] ;[$C1:51FB]へジャンプ ; $C1/51FB LDA #$10 ;Aに$10をロード $C1/51FD STA $12 [$00:0312] ;A($10)を[$00:0312]に書き込み $C1/51FF LDY $0002,x[$00:1B42] ;Yに[$00:1B42]をロード $C1/5202 LDA $0004,y[$00:1AC4] ;Aに[$00:1AC4](ピュアオディオ横幅 $03)をロード $C1/5205 STA $0A [$00:030A] ;A($03)を[$00:030A]に書き込み $C1/5207 LDA $0005,y[$00:1AC5] ;Aに[$00:1AC5](ピュアオディオ縦幅 $02)をロード $C1/520A STA $09 [$00:0309] ;A($02)を[$00:0309]に書き込み $C1/520C LDA $000B,x[$00:1B4B] ;Aに[$00:1B4B](敵番号4のマス目のY座標)をロード $C1/520F ASL A ;Aを算術左シフト *2 $C1/5210 ASL A ;Aを算術左シフト *2 $C1/5211 ASL A ;Aを算術左シフト *2 $C1/5212 ADC $000A,x[$00:1B4A] ;A + [$00:1B4A](敵番号4のマス目のX座標) $C1/5215 STA $10 [$00:0310] ;Aを[$00:0310]に書き込み $C1/5217 STZ $11 [$00:0311] ;[$00:0311]に$00を書き込み $C1/5219 LDY $10 [$00:0310] ;Yに[$00:0310]をロード $C1/521B TXA ;Xレジスタの値をAレジスタに転送 $C1/521C LSR A ;Aを論理右シフト (/2) $C1/521D LSR A ;Aを論理右シフト (/2) $C1/521E LSR A ;Aを論理右シフト (/2) $C1/521F LSR A ;Aを論理右シフト (/2) $C1/5220 INC A ;Aをインクリメント +1 $C1/5221 ORA $12 [$00:0312] ;Aと[$00:0312]($10)で論理和 $C1/5223 STA $12 [$00:0312] ;A($15)を[$00:0312]に書き込み $C1/5225 LDA $0A [$00:030A] ;Aに[$00:030A]($03)をロード $C1/5227 STA $08 [$00:0308] ;A($03)を[$00:0308]に書き込み
ここまでがピュアオディオの初期位置マス判定処理のための準備である。
要するに、初期位置の座標から、横方向は横幅の分、縦方向は縦幅の分だけマス目のアドレスをチェックしていくことになる。
;ループ処理ここから $C1/5229 LDA $04C8,y[$00:04E4] ;Aに[$04C8,y](ピュアオディオ初期位置n)をロード $C1/522C AND #$F0 ;Aと$F0で論理積 $C1/522E ORA $12 [$00:0312] ;Aと[$00:0312]($15)で論理和 $C1/5230 STA $04C8,y[$00:04E4] ;Aを[$04C8,y](ピュアオディオ初期位置n)に書き込み $C1/5233 INY ;Yをインクリメント +1 $C1/5234 DEC $08 [$00:0308] ;[$00:0308]をデクリメント -1 $C1/5236 BNE $F1 [$5229] ;ゼロフラグが立っていないとき[$5229]分岐 ;ゼロフラグON(横1列分アドレスチェック後) $C1/5238 LDA $10 [$00:0310] ;Aに[$00:0310]をロード $C1/523A CLC ;キャリーフラグクリア $C1/523B ADC #$08 ;A + $08 $C1/523D STA $10 [$00:0310] ;Aを[$00:0310]に書き込み $C1/523F LDY $10 [$00:0310] ;Yに[$00:0310]をロード $C1/5241 DEC $09 [$00:0309] ;[$00:0309]をデクリメント -1 $C1/5243 BNE $E0 [$5225] ;ゼロフラグが立っていないとき[$5225]分岐 ;ループ処理ここまで $C1/5245 RTS ;サブルーチン戻り ; $C1/7D2B JSR $7D2E [$C1:7D2E] ;[$C1:7D2E]へジャンプ ; $C1/7D2E JSR $7D37 [$C1:7D37] ;[$C1:7D37]へジャンプ ; $C1/7D37 JSR $7D3A [$C1:7D3A] ;[$C1:7D3A]へジャンプ ; $C1/7D3A JSR $6145 [$C1:6145] ;[$C1:6145]へジャンプ
$00:04C8~$00:04FEの戦闘フィールドの状況だが、何もないのなら$00が入る。
上1桁か下1桁に0以外の数値が入っている場合は味方キャラまたは敵キャラ、更にはダメージフィールドが存在していることを示す。
上1桁が0なら味方キャラ、1なら敵キャラ、8以上ならダメージフィールドが存在していることになる。
つまり、初期位置のアドレスを呼び出して、$F0と論理積を取ると上1桁だけが取り出せるのだが、この戦闘ではダメージフィールドを作ることができないので、8以上の値は入ることがない。
また、オディオモールは初期位置から動かないし動かせないため、ピュアオディオ初期位置にはいない。
つまり、ピュアオディオ戦移行のタイミングで、ピュアオディオ初期位置マスには、何もないカラマスか、味方キャラがいるかのどちらかなのである。
よって、$F0と論理積を取ると必ず$00である。
$C1/522Eは、A+[$00:0312]($15)だが、上の理由から必ず0+$15の計算になり、$15がピュアオディオ初期位置マスに書き込まれる。
では、$15は何を意味するのか。
戦闘フィールドの状況は、上1桁が1なら敵キャラがいる扱いである。
下1桁は1~Eが入り、これは敵番号+1にあたる。
つまり、$15は「敵番号4=ピュアオディオがいるマス」を意味する。
ここで、ピュアオディオが該当マスにいる処理がなされたことになる。
味方キャラが初期位置マスに居た場合の処理はまだされていない。
| アドレス | 内容 | 値 |
|---|---|---|
$00:04E2 | ピュアオディオ初期位置1 | $15 |
$00:04E3 | ピュアオディオ初期位置2 | $15 |
$00:04E4 | ピュアオディオ初期位置3 | $15 |
$00:04EA | ピュアオディオ初期位置4 | $15 |
$00:04EB | ピュアオディオ初期位置5 | $15 |
$00:04EC | ピュアオディオ初期位置6 | $15 |
$C1/5245まで処理を終えると、上のように各アドレスに値が入ったことになる。
このままでは、味方キャラが初期位置マスに居た場合、該当キャラが消えてしまうことになる。
味方キャラの座標は戦闘中の味方キャラデータの$00:1C18+40nにX座標、$00:1C19+40nにY座標が記録されているため、完全に消えてしまったのではないが、この後の処理で新たな座標が決まる。
上処理の後少しウェイトがかかるのでやや処理が飛ぶが、以下が味方キャラの座標の処理である。
$C1/7D36 RTS ;サブルーチン戻り ; $C1/7C21 JSR $7DAB [$C1:7DAB] ;[$C1:7DAB]へジャンプ ; $C1/7DAB LDX #$1C00 ;Xに$1C00をロード $C1/7DAE JSR $7DC4 [$C1:7DC4] ;[$C1:7DC4]へジャンプ ; $C1/7DC4 LDA $0001,x[$00:1C01] ;Aに[$00:1C01](味方キャラ1 戦闘状態)をロード $C1/7DC7 CMP #$FF ;Aと$FFを減算比較(ステータスレジスタ変更のみ) $C1/7DC9 BNE $25 [$7DF0] ;ゼロフラグが立っていないとき[$7DF0]分岐 $C1/7DCB LDA $0019,x[$00:1C19] ;Aに[$00:1C19](味方キャラ1 Y座標)をロード $C1/7DCE ASL A ;Aを算術左シフト *2 $C1/7DCF ASL A ;Aを算術左シフト *2 $C1/7DD0 ASL A ;Aを算術左シフト *2 $C1/7DD1 ADC $0018,x[$00:1C18] ;A + [$00:1C18](味方キャラ1 X座標) $C1/7DD4 STA $10 [$00:0310] ;Aを[$00:0310]に書き込み $C1/7DD6 STZ $11 [$00:0311] ;[$00:0311]に$00を書き込み $C1/7DD8 LDY $10 [$00:0310] ;Yに[$00:0310]をロード $C1/7DDA LDA $04C8,y[$00:04E3] ;Aに[$00:04E3]をロード $C1/7DDD BIT #$10 ;Aと$10で論理積(ステータスフラグ変更のみ) $C1/7DDF BEQ $0F [$7DF0] ;ゼロフラグが立っているとき[$7DF0]分岐 $C1/7DE1 STZ $0005,x[$00:1C05] ;[$00:1C05]に$00を書き込み $C1/7DE4 JSR $190F [$C1:190F] ;[$C1:190F]へジャンプ
$C1/7DC4からの処理だが、まず味方キャラ1の戦闘状態が通常($FF)かを判定している。このタイミングで戦闘離脱($00)なら、座標判定の必要はないためである。
ここでは例として、ピュアオディオ戦移行時、味方キャラ1の座標が(3,3)の場合だとしよう。
つまり下図の「1」、$00:04E3に味方キャラ1がいるとする。
ピュアオディオ初期位置と被るマスである。
さて、$C1/7DCBでまず味方キャラ1のY座標[$00:1C19]をロードする。ここでは[$00:1C19] = $03である。
$C1/7DCE~$C1/7DD0で算術左シフトを3回行ってから、$C1/7DD1で[$00:1C18](味方キャラ1 X座標) = $03をAに加算している。
これで何を計算したのか。
座標は0~6のいずれかなので、2進数だと3ビット分の値で表すことができる。
[$00:1C19] = $03 = %0000 0011である。
算術左シフトを3回行うと、桁が3つ左にズレるから、%0001 1000となり、下3ビットが空く。
ここにX座標 = $03 = %0000 0011を加算すると、下3ビット部分にX座標が入る。
よって、$C1/7DD1で計算される$1B = %0001 1011は、下から3ビットがX座標、そこから更に3ビット分がY座標、ということになる。
左上座標(原点位置)のアドレス$00:04C8に、$1Bを足すと、ちょうど味方キャラ1がいる位置のアドレス$00:04E3が計算できるのだ。
$C1/7DDAで呼び出した[$04C8,y]が味方キャラ1の座標[$00:04E3]である。
ここにはピュアオディオがいるので、先の処理で$15が入っている。
$C1/7DDDで、$10と論理積を取っている。実質、上1桁が1かどうか(敵がいるかどうか)の判定である。
$15 & $10 = $10であり、$C1/7DDFでゼロフラグが立たない。
ここで、味方キャラ1とピュアオディオの位置が被っているという判定がなされたことになる。
この後の処理の説明は少し飛ばして、座標計算部分を紹介する。
$C1/7DEA JSR $7DF1 [$C1:7DF1] ;[$C1:7DF1]へジャンプ ; $C1/7DF1 LDA $0018,x[$00:1C18] ;Aに[$00:1C18](味方キャラ1 X座標$03)をロード $C1/7DF4 CMP #$02 ;Aと$02を減算比較(ステータスレジスタ変更のみ) $C1/7DF6 BEQ $0F [$7E07] ;ゼロフラグが立っているとき[$7E07]分岐 $C1/7DF8 LDY #$7E6E ;Yに$7E6Eをロード $C1/7DFB LDA $0019,x[$00:1C19] ;Aに[$00:1C19](味方キャラ1 Y座標$03)をロード $C1/7DFE CMP #$03 ;Aと$03を減算比較(ステータスレジスタ変更のみ) $C1/7E00 BEQ $12 [$7E14] ;ゼロフラグが立っているとき[$7E14]分岐
まず、味方キャラの座標が、ピュアオディオの位置のどこに被っているかどうか判定する。
$C1/7DF1~$C1/7DF6の処理を見ると、X座標=$02なら$C1/7E07へ、それ以外は$C1/7DF8に進む。
つまり、ピュアオディオのいるマスの一番左のいずれかのマスにいるかどうかの分岐である。下図の●位置にあたる。
ひとまず今回は味方キャラ1の座標が(3,3)で話を進めるので、$C1/7DF8に進む。
この場合はYに$7E6Eをロードし、更にY座標の判定$C1/7DFB~$C1/7E00に進む。
こちらの判定はY座標=$03なら$C1/7E14、そうでなければ$C1/7E02に進む。
つまり、ピュアオディオのいるマスの一番上列のいずれかのマスにいるかどうかの分岐である。下図の●位置にあたる。
$C1/7E02以降を見ると以下のようになる。
$C1/7E02 LDY #$7E76 ;Yに$7E76をロード $C1/7E05 BRA $0D [$7E14] ;フラグにかかわりなく常に分岐[$7E14] $C1/7E07 LDY #$7E5E ;Yに$7E5Eをロード $C1/7E0A LDA $0019,x[$00:1C19] ;Aに[$00:1C19]をロード $C1/7E0D CMP #$03 ;Aと$03を減算比較(ステータスレジスタ変更のみ) $C1/7E0F BEQ $03 [$7E14] ;ゼロフラグが立っているとき[$7E14]分岐 $C1/7E11 LDY #$7E66 ;Yに$7E66をロード
分岐によってYにロードする値が変わってくることがわかる。
整理すると以下のようになる。
| パターン | 条件 | Yの値 |
|---|---|---|
| 1 | X座標=$02 かつ Y座標=$03 | $7E5E |
| 2 | X座標=$02 かつ Y座標≠$03 | $7E66 |
| 3 | X座標≠$02 かつ Y座標=$03 | $7E6E |
| 4 | X座標≠$02 かつ Y座標≠$03 | $7E76 |
以上のように、味方キャラ位置によって、Yに読み込まれる値が変わる。
また、最終的にどの分岐も$C1/7E14に進む。
以上の分岐により、味方キャラが吹き飛ぶマスがどこになるか決まる。
だいたい察しがつくが、1が左上隅、2が左下隅、3が右上隅、4が右下隅である。
ただ、3と4は2マス分あるから、例えば3に味方が2キャラいた場合はどうなるのか。
更に言えば、元々他の味方キャラが隅に居た場合はどうなるのか。
その処理は後を見ていくとわかる。
ここでは引き続き味方キャラ1の座標が(3,3)で処理を見てみる。
つまり、Yにロードする値が$7E6Eである。
$C1/7E14 STX $60 [$00:0360] ;Xを[$00:0360]に書き込み(X:1C00) $C1/7E16 TYX ;Yレジスタの値(Y:7E6E)をXレジスタに転送 $C1/7E17 LDA $C10001,x[$C1:7E6F] ;Aに[$C10001,x]($C1:7E6F = $00)をロード $C1/7E1B ASL A ;Aを算術左シフト *2 $C1/7E1C ASL A ;Aを算術左シフト *2 $C1/7E1D ASL A ;Aを算術左シフト *2 $C1/7E1E ADC $C10000,x[$C1:7E6E] ;A($00) + [$C10000,x]($C1:7E6E = $06) $C1/7E22 STA $10 [$00:0310] ;A($06)を[$00:0310]に書き込み $C1/7E24 STZ $11 [$00:0311] ;[$00:0311]に$00を書き込み $C1/7E26 LDY $10 [$00:0310] ;Yに[$00:0311][$00:0310]($0006)をロード $C1/7E28 LDA $04C8,y[$00:04CE] ;Aに[$04C8,y]($00:04CE フィールド右上マス)をロード $C1/7E2B AND #$0F ;Aと$0Fで論理積 $C1/7E2D BEQ $04 [$7E33] ;ゼロフラグが立っているとき[$7E33]分岐 ;ゼロフラグOFF $C1/7E2F INX ;Xをインクリメント +1 $C1/7E30 INX ;Xをインクリメント +1 $C1/7E31 BRA $E4 [$7E17] ;フラグにかかわりなく常に分岐[$7E17]
Yに書き込んだ$7E6Eは、$C1/7E16でXにコピーされる。
$C1/7E17でロードする[$C10001,x]及び、$C1/7E1Eで呼び出される[$C10000,x]は、Xの値によって呼び出し先が変わることになる。
| パターン | 条件 | Yの値 | $C10001,x | $C10000,x |
|---|---|---|---|---|
| 1 | X座標=$02 かつ Y座標=$03 | $7E5E | $C1:7E5E($00) | $C1:7E5F($00) |
| 2 | X座標=$02 かつ Y座標≠$03 | $7E66 | $C1:7E66($00) | $C1:7E67($06) |
| 3 | X座標≠$02 かつ Y座標=$03 | $7E6E | $C1:7E6E($06) | $C1:7E6F($00) |
| 4 | X座標≠$02 かつ Y座標≠$03 | $7E76 | $C1:7E76($06) | $C1:7E77($06) |
$C1:7E5E以降は、このピュアオディオ戦用の計算用数値が格納されていて、上のように呼び出されることになる。
$C1/7E17~$C1/7E22の処理は、先にもあったとおり、下3ビットにX座標、その上の3ビットにY座標を入れる処理である。
その座標が、吹き飛ばされる先の座標の仮値である。
つまり、
| パターン | 条件 | Yの値 | 飛び先座標アドレス |
|---|---|---|---|
| 1 | X座標=$02 かつ Y座標=$03 | (0,0) | $00:04C8 |
| 2 | X座標=$02 かつ Y座標≠$03 | (0,6) | $00:04F8 |
| 3 | X座標≠$02 かつ Y座標=$03 | (6,0) | $00:04CE |
| 4 | X座標≠$02 かつ Y座標≠$03 | (6,6) | $00:04FE |
ということになる。
$C1/7E28でロードする[$04C8,y]は対応マスのアドレスの値である。
該当のマスに既に味方キャラがいるかどうかを、$C1/7E2Bで、対応マスのアドレスの値と$0Fで論理積を取ることでゼロフラグ判定している。
味方キャラがいる場合、$01~$04のいずれかの値が入っているから、$0Fと論理積を取った時にゼロフラグが立つ時は該当マスに味方はいない。
よって$C1/7E33に進む。
ゼロフラグが立たない、つまり既に味方キャラが居る場合、$C1/7E2F~$C1/7E31の処理を行うが、ここでの処理を見るとXを+2して$C1/7E17へ戻る。
そうなると呼び出し先アドレスと値が変わる。
| パターン | 条件 | Yの値 | $C10001,x+2 | $C10000,x+2 |
|---|---|---|---|---|
| 1 | X座標=$02 かつ Y座標=$03 | $7E5E | $C1:7E60($00) | $C1:7E61($01) |
| 2 | X座標=$02 かつ Y座標≠$03 | $7E66 | $C1:7E68($00) | $C1:7E69($05) |
| 3 | X座標≠$02 かつ Y座標=$03 | $7E6E | $C1:7E70($06) | $C1:7E71($01) |
| 4 | X座標≠$02 かつ Y座標≠$03 | $7E76 | $C1:7E78($06) | $C1:7E79($05) |
1マスずれた位置が指定された。
その位置にも味方がいる場合は再び$C1/7E2F~$C1/7E31でXを+2して$C1/7E17へ戻る(合計でXを+4)、というように、味方がいない位置が見つかるまでループしていく。
Xを+4した時は、
| パターン | 条件 | Yの値 | $C10001,x+2 | $C10000,x+4 |
|---|---|---|---|---|
| 1 | X座標=$02 かつ Y座標=$03 | $7E5E | $C1:7E62($01) | $C1:7E63($00) |
| 2 | X座標=$02 かつ Y座標≠$03 | $7E66 | $C1:7E6A($01) | $C1:7E6B($06) |
| 3 | X座標≠$02 かつ Y座標=$03 | $7E6E | $C1:7E72($05) | $C1:7E73($00) |
| 4 | X座標≠$02 かつ Y座標≠$03 | $7E76 | $C1:7E7A($05) | $C1:7E7B($06) |
Xを+6した時は、
| パターン | 条件 | Yの値 | $C10001,x+2 | $C10000,x+4 |
|---|---|---|---|---|
| 1 | X座標=$02 かつ Y座標=$03 | $7E5E | $C1:7E64($01) | $C1:7E65($01) |
| 2 | X座標=$02 かつ Y座標≠$03 | $7E66 | $C1:7E6C($01) | $C1:7E6D($05) |
| 3 | X座標≠$02 かつ Y座標=$03 | $7E6E | $C1:7E74($05) | $C1:7E75($01) |
| 4 | X座標≠$02 かつ Y座標≠$03 | $7E76 | $C1:7E7C($05) | $C1:7E7D($05) |
ということになる。
味方は最大4キャラだから、判定はここまでのはずである。
たとえば、以下のような配置だったら、●位置の味方キャラはパターン3で右上に吹き飛ぶはずだ。
この判定を味方キャラ1から順に行うから、味方キャラ1が右上(6,0)に飛んだ後に味方キャラ2も右上に飛ぶ場合もあり得る。
その時は既に味方キャラ1が該当位置のアドレスに書き込まれているから、ループ処理で次のマスを判定する。
以下、飛ぶ先のマスが決まった$C1/7E33以降の処理。
(3,3)にいた場合、(6,0)に味方キャラが既にいない状態なら(6,0)、アドレスだと[$00:04CE]に飛ぶことになるが、座標関連の書き込みが以下。
$C1/7E33 LDA $C10000,x[$C1:7E6E] ;Aに[$C1:7E6E]($06)をロード $C1/7E37 STA $10 [$00:0310] ;A($06)を[$00:0310]に書き込み $C1/7E39 LDA $C10001,x[$C1:7E6F] ;Aに[$C1:7E6F]($00)をロード $C1/7E3D STA $11 [$00:0311] ;A($00)を[$00:0311]に書き込み $C1/7E3F LDX $60 [$00:0360] ;Xに[$00:0360]をロード $C1/7E41 LDA $10 [$00:0310] ;Aに[$00:0310]($06)をロード $C1/7E43 STA $001A,x[$00:1C1A] ;A($06)を[$00:1C1A](味方キャラ1 X座標仮値)に書き込み $C1/7E46 LDA $11 [$00:0311] ;Aに[$00:0311]($00)をロード $C1/7E48 STA $001B,x[$00:1C1B] ;A($00)を[$00:1C1B](味方キャラ1 Y座標仮値)に書き込み $C1/7E4B TXA ;Xレジスタの値をAレジスタに転送 $C1/7E4C ROL A ;Aをキャリーフラグを含めた9bitで左ローテート $C1/7E4D ROL A ;Aをキャリーフラグを含めた9bitで左ローテート $C1/7E4E ROL A ;Aをキャリーフラグを含めた9bitで左ローテート $C1/7E4F AND #$03 ;Aと$03で論理積 $C1/7E51 INC A ;Aをインクリメント +1 $C1/7E52 ORA $04C8,y[$00:04CE] ;A($01)と[$00:04CE]($00)で論理和 $C1/7E55 STA $04C8,y[$00:04CE] ;Aを[$00:04CE]($01)に書き込み $C1/7E58 LDA #$00 ;Aに$00をロード $C1/7E5A STA $003B,x[$00:1C3B] ;Aを[$00:1C3B]に書き込み $C1/7E5D RTS ;サブルーチン戻り ; $C1/7DED JSR $C733 [$C1:C733] ;[$C1:C733]へジャンプ
X座標の$06は、[$C1:7E6E]→[$00:0310]→[$00:1C1A]と書き込まれ、Y座標の$00は[$C1:7E6F]→[$00:0311]→[$00:1C1B]と書き込まれる。
[$00:1C1A]と[$00:1C1B]は、味方キャラ1のX座標仮値・Y座標仮値である。
後で実際の座標のアドレス[$00:1C18][$00:1C19]に書き込まれる。
また、$C1/7E4B~では、味方キャラの番号を算出している。
この時点でのXは味方キャラ番号により、$1C00, $1C40, $1C80, $1CC0だから、Xレジスタの値をAレジスタに転送すると下2桁だけ、$00, $40, $80, $C0が転送される。
この値をキャリーフラグ含め左ローテート3回し、$03と論理積をとってインクリメント+1すると$01, $02, $03, $04になり、この値を飛ばされる先のマスに対応したアドレスに書き込むことで、該当キャラの位置が確定となった。
$C1/4450 LDA $0001,x[$00:1C01] ;Aに[$00:1C01](味方キャラID)をロード $C1/4453 CMP #$40 ;Aと$40を減算比較(ステータスレジスタ変更のみ) $C1/4455 BNE $14 [$446B] ;ゼロフラグが立っていないとき[$446B]分岐 $C1/446B INC $0006,x[$00:1C06] ;[$00:1C06](タメ時間ありの技発動までの時間)をインクリメント +1 $C1/446E LDA $0006,x[$00:1C06] ;Aに[$00:1C06](タメ時間ありの技発動までの時間)をロード $C1/4471 CMP $0007,x[$00:1C07] ;Aと[$00:1C07](実行しようとしている技のタメ時間)を減算比較(ステータスレジスタ変更のみ) $C1/4474 BNE $24 [$449A] ;ゼロフラグが立っていないとき[$449A]分岐 $C1/4476 LDA $001A,x[$00:1C1A] ;Aに[$00:1C1A](味方キャラ1 X座標仮値)をロード $C1/4479 STA $0018,x[$00:1C18] ;Aを[$00:1C18](味方キャラ1 X座標)に書き込み $C1/447C LDA $001B,x[$00:1C1B] ;Aに[$00:1C1B](味方キャラ1 Y座標仮値)をロード $C1/447F STA $0019,x[$00:1C19] ;Aを[$00:1C19](味方キャラ1 Y座標)に書き込み $C1/4482 JSR $45D5 [$C1:45D5] ;[$C1:45D5]へジャンプ
[$00:1C1A]→[$00:1C18]、[$00:1C1B]→[$00:1C19]の処理は上の通り。
以上が、
という一連の処理の流れである。
フィールド隅に飛ぶ場合の法則も、処理からわかった。
味方1人分の処理の後に実際に該当のフィールド隅に飛ぶ処理をしてから2人目の判定に移るので、4キャラとも吹き飛ぶケースでは、ゲーム画面をよく見ていると、ほんの僅かだが4キャラ吹き飛ぶタイミングがずれている。
この後も処理は続くが、とりあえずピュアオディオ戦移行判定と初期位置による味方キャラの吹き飛ばし処理の説明は以上である。
ただ、ここまでだと、ピュアオディオ出現の処理はなされていても、最後に残っていたオディオモールの処理まで行っていない。
ついでなので、倒していないはずのオディオモールを削除する処理を紹介する。
ゲーム画面上ではオディオモールが画面中央に移動してピュアオディオに変わる、という演出だが、実際にはオディオモールという敵自体はいなくなるから、オディオモールが最初からいた座標のアドレスや、オディオモール関係の値が入る$00:1B2?に、何らかの処理を行わなければならない。
オディオモール初期位置は、$00:04CBと$00:04D3で、味方側からの向き変えや吹き飛ばしは無効、オディオモール自身が移動をすることもない。
| C8 | C9 | CA | CB | CC | CD | CE |
| D0 | D1 | D2 | D3 | D4 | D5 | D6 |
| D8 | D9 | DA | DB | DC | DD | DE |
| E0 | E1 | E2 | E3 | E4 | E5 | E6 |
| E8 | E9 | EA | EB | EC | ED | EE |
| F0 | F1 | F2 | F3 | F4 | F5 | F6 |
| F8 | F9 | FA | FB | FC | FD | FE |
戦闘開始の時点で、敵番号3のオディオモールは、$00:04CB・$00:04D3に$13が入ることになる。
また、オディオ戦ではダメージフィールドを生成できないため、上の戦闘フィールドの状況にダメージフィールド関係の値が加算されることはない。
まず、オディオモールの座標に関する処理だが、上の味方キャラの吹き飛ばしの処理の後に実行される。
$C1/7C2A JSR $4277 [$C1:4277] ;[$C1:4277]へジャンプ ; $C1/4277 LDA $000B,x[$00:1B2B] ;Aに[$00:1B2B]をロード $C1/427A ASL A ;Aを算術左シフト *2 $C1/427B ASL A ;Aを算術左シフト *2 $C1/427C ASL A ;Aを算術左シフト *2 $C1/427D ADC $000A,x[$00:1B2A] ;A + [$00:1B2A] $C1/4280 STA $14 [$00:0314] ;Aを[$00:0314]に書き込み $C1/4282 STZ $15 [$00:0315] ;[$00:0315]に$00を書き込み $C1/4284 LDY $14 [$00:0314] ;Yに[$00:0314]をロード $C1/4286 LDA $0B [$00:030B] ;Aに[$00:030B]をロード $C1/4288 STA $09 [$00:0309] ;Aを[$00:0309]に書き込み ;敵の横幅確認ループ開始(1回目) $C1/428A LDA $0A [$00:030A] ;Aに[$00:030A]をロード $C1/428C STA $08 [$00:0308] ;Aを[$00:0308]に書き込み $C1/428E LDA $04C8,y[$00:04CB] ;Aに[$00:04CB](オディオモール初期位置1)をロード $C1/4291 AND #$E0 ;Aと$E0で論理積 $C1/4293 STA $04C8,y[$00:04CB] ;Aを[$00:04CB](オディオモール初期位置1)に書き込み $C1/4296 INY ;Yをインクリメント +1 $C1/4297 DEC $08 [$00:0308] ;[$00:0308]をデクリメント -1 $C1/4299 BNE $F3 [$428E] ;ゼロフラグが立っていないとき[$428E]分岐 $C1/429B REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/429D TYA ;Yレジスタの値をAレジスタに転送 $C1/429E ADC $12 [$00:0312] ;A + [$00:0312] $C1/42A0 AND #$00FF ;Aと$00FFで論理積 $C1/42A3 TAY ;Aの値をYレジスタに転送 $C1/42A4 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/42A6 DEC $09 [$00:0309] ;[$00:0309]をデクリメント -1 $C1/42A8 BNE $E0 [$428A] ;ゼロフラグが立っていないとき[$428A]分岐 ;敵の横幅確認ループ開始(1回目)ここまで ;敵の横幅確認ループ開始(2回目) $C1/428A LDA $0A [$00:030A] ;Aに[$00:030A]をロード $C1/428C STA $08 [$00:0308] ;Aを[$00:0308]に書き込み $C1/428E LDA $04C8,y[$00:04D3] ;Aに[$00:04D3](オディオモール初期位置2)をロード $C1/4291 AND #$E0 ;Aと$E0で論理積 $C1/4293 STA $04C8,y[$00:04D3] ;Aを[$00:04D3](オディオモール初期位置2)に書き込み $C1/4296 INY ;Yをインクリメント +1 $C1/4297 DEC $08 [$00:0308] ;[$00:0308]をデクリメント -1 $C1/4299 BNE $F3 [$428E] ;ゼロフラグが立っていないとき[$428E]分岐 $C1/429B REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/429D TYA ;Yレジスタの値をAレジスタに転送 $C1/429E ADC $12 [$00:0312] ;A + [$00:0312] $C1/42A0 AND #$00FF ;Aと$00FFで論理積 $C1/42A3 TAY ;Aの値をYレジスタに転送 $C1/42A4 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/42A6 DEC $09 [$00:0309] ;[$00:0309]をデクリメント -1 $C1/42A8 BNE $E0 [$428A] ;ゼロフラグが立っていないとき[$428A]分岐 ;敵の横幅確認ループ開始(2回目)ここまで $C1/42AA RTS ;サブルーチン戻り
$C1/4277~$C1/42AAは、位置変化・向き変えでの吹き飛ばし処理で紹介した、「敵がどこかに移動する場合、元の座標に誰もいない状態にする」というサブルーチンである。
重要な部分は$C1/428E~$C1/4293で、オディオモールがいたアドレスをロードし(この時点では$13)、$E0と論理積を取った値をアドレスに描き戻す。
$E0と論理積を取ると、ダメージフィールドの値だけが残るのだが、ダメージフィールドは発生しない戦闘だから、$13 & $E0 = $00、つまり誰もいないしダメージフィールドも存在しない、という状況になる。
こうして$00:04CB・$00:04D3に$00が入って、オディオモールがいない状態になった。
もうひとつ必要な処理は戦闘状態である。
敵番号2のオディオモールは、$00:1B21に戦闘状態($00なら戦闘離脱、$FFなら通常)が入っており、ピュアオディオ出現までは通常状態の$FFが入っている。
ピュアオディオの出現条件のひとつが、オディオモールの戦闘状態が$FFである($00:1B21に$FFが入っている)だから当然である。
だがピュアオディオが出現したら、$00:1B21に$00を入れて戦闘離脱状態にしなければフィールドに残ってしまう。
その処理が下である。
$C1/7CCA RTS ;サブルーチン戻り ; $C1/7C30 LDA #$00 ;Aに$00をロード $C1/7C32 STA $1B21 [$00:1B21] ;Aを[$00:1B21]に書き込み $C1/7C35 LDX #$1B40 ;Xに$1B40をロード $C1/7C38 JSR $51FB [$C1:51FB] ;[$C1:51FB]へジャンプ
処理自体はシンプルで、$C1/7C30でAにロードした$00を、$C1/7C32で[$00:1B21]に書き入れるのみである。
実際にはこの処理までに、オディオモールがマップ中央まで移動してくる。
直前まで、オディオモールを中央に移動させる処理、つまりオディオモールのいる位置(ドット単位での座標)が必要なので、[$00:1B21]の戦闘状態が$FFでなければならない。
移動が終わると削除して、ピュアオディオのドット絵を出現させる処理へ移行する、という仕組みである。
以上でピュアオディオ関係の説明を終了とする。