DQ3 エンカウント時の出現モンスター決定方法3

さて、前回の時点で、1番目のモンスターを決定する実装まで説明しました。

2番目以降のモンスターを決定するSRは

7F01混成モンスター1~5用
7F581体のみ+混成5種をお供にするモンスター用
7F71単一種出現モンスター1~4,夜のみモンスター用
7FAE1体のみ出現用
7FB5固定パーティ1,2用

の5種類です。これを順番に見ていきます。

  • SR: $067F01 2種以上混成モンスター出現種・出現数決定
067F01STA $2000$7E2000=AモンスターIDを1種類目にセット
067F04JSR $80E6SR: $0680E6出現閾値均等化
067F07JSR $80AFSR: $0680AF出現種打ち止め判定
067F0ALDA #$041FA=#$041F混成1~5,夜のみ出現が対象
067F0DJSR $8059SR: $068059出現モンスター決定
067F10STA $2002$7E2002=AモンスターIDを2種類目にセット
067F13JSR $80AFSR: $0680AF出現種打ち止め判定
067F16JSL $0012D1SR: $0012D1乱数発生 $00-FF
067F1ACMP $F7B4A>=$7EF7B4?3種以上出現させるか判定
067F1DBCS #$21if(c==on) goto $067F40
067F1FLDA #$041FA=#$041F混成1~5,夜のみ出現が対象
067F22JSR $8059SR: $068059出現モンスター決定
067F25STA $2004$7E2004=AモンスターIDを3種類目にセット
067F28JSR $80AFSR: $0680AF出現種打ち止め判定
067F2BJSL $0012D1SR: $0012D1乱数発生 $00-FF
067F2FCMP $F7B6A>=$7EF7B6?4種以上出現させるか判定
067F32BCS #$0Cif(c==on) goto $067F40
067F34LDA #$041FA=#$041F混成1~5,夜のみ出現が対象
067F37JSR $8059SR: $068059出現モンスター決定
067F3ASTA $2006$7E2006=AモンスターIDを4種類目にセット
067F3DJSR $80AFSR: $0680AF出現種打ち止め判定
067F40STZ $1C$00001C=#$00ここから出現数の決定
067F42JSR $80FCSR: $0680FCモンスターIDがセットされている場合に出現数カウンタを全て1増やす
067F45INC $1C$00001C++
067F47LDA $1CA=$00001C
067F49CMP #$0008A>=#$0008?各グループ出現数が8になったらストップ
067F4CBCS #$09if(c==on) goto $067F57
067F4ELDA #$0002A=#$0002
067F51JSL $00133ESR: $00133E乱数発生 00-A A(1B) 1/3の確率で出現数を増やす
067F55BNE #$EBif(z==off) goto $067F42
067F57RTSreturn

2種類目からは混成1~5+夜のみ出現の閾値は全て同じ40になるので出現確率は同じになります。また、3種類、4種類出現するかどうかは個別の閾値(1Byte)が用意されていて、乱数がそれ以下の場合のみ出現判定が行われます。さらにこのSRでは、出現数はどのグループも全て同じ数になります(実際は画面幅の制限などで削られますが)。

  • SR: $0680E6 出現閾値均等化
0680E6LDX #$0000X=#$0000
0680E9LDA $F798,XA=$7EF798+X
0680ECBEQ #$06if(z==on) goto $0680F4
0680EELDA #$0028A=#$0028閾値に全て40をセット(最大6種まで)
0680F1STA $F798,X$7EF798+X=A
0680F4INXX++
0680F5INXX++
0680F6CPX #$001CX>=#$001C ?
0680F9BCC #$EEif(c==off) goto $0680E9
0680FBRTSreturn

  • SR: $0680AF 出現種打ち止め判定
0680AFPHAPush A
0680B0PHXPush X
0680B1PHYPush Y
0680B2LDY #$0000Y=#$0000
0680B5LDA $2000,YA=$7E2000+Y
0680B8CMP #$0000A==#$0000?
0680BBBEQ #$1Eif(z==on) goto $0680DB
0680BDPHAPush A
0680BELDX #$0000X=#$0000
0680C1LDA $F7B8,XA=$7EF7B8+XモンスターIDが混成1~5に一致しているか
0680C4CMP $01,SA==Stack($01)?
0680C6BNE #$0Bif(z==off) goto $0680D3
0680C8LDA $F7D4,XA=$7EF7D4+X
0680CBCMP #$0001A==#$0001?対応した打ち止めフラグを見る(ON=1)
0680CEBEQ #$03if(z==on) goto $0680D3
0680D0STZ $F798,X$7EF798+X=#$00ONになっていたら混成1~固定パーティ2までの出現閾値を0にする
0680D3INXX++
0680D4INXX++
0680D5CPX #$0018X>=#$0018 ?
0680D8BCC #$E7if(c==off) goto $0680C1
0680DAPLAPull A
0680DBINYY++
0680DCINYY++
0680DDCPY #$0008Y>=#$0008 ?
0680E0BCC #$D3if(c==off) goto $0680B5
0680E2PLYPull Y
0680E3PLXPull X
0680E4PLAPull A
0680E5RTSreturn

ちょっとわかりにくいですが、それぞれのRAMの意味がわかっていれば理解できるはずです。打ち止めフラグがONになっている場合、閾値が全て0になるのでこれ以降何度SR: $068059出現モンスター決定を呼んでも結果は空になります(多分)。

  • SR: $0680FC モンスターIDがセットされている場合に出現数カウンタを全て1増やす
0680FCLDX #$0000X=#$0000
0680FFLDA $2000,XA=$7E2000+X
068102CMP #$0000A==#$0000?
068105BEQ #$03if(z==on) goto $06810A
068107INC $2008,X$7E2008+X++モンスターIDがセットされているグループの出現数を1増やす
06810AINXX++
06810BINXX++
06810CCPX #$0008X>=#$0008 ?
06810FBCC #$EEif(c==off) goto $0680FF
068111RTSreturn
  • SR: $067F58 1体+混成5種をお供(最大8体)モンスター出現数決定
067F58STA $2000$7E2000=AモンスターIDを1種類目にセット
067F5BJSR $80FCSR: $0680FCモンスターIDがセットされている場合に出現数カウンタを全て1増やす
067F5EJSR $80E6SR: $0680E6出現閾値均等化
067F61LDA #$001FA=#$001F混成1~5のみが対象
067F64JSR $8059SR: $068059出現モンスター決定
067F67STA $2002$7E2002=A2種類目を決定
067F6ALDA #$0008A=#$0008出現数は8に固定
067F6DSTA $200A$7E200A=A
067F70RTSreturn

ロマリア周辺のさまようよろい+ギズモたくさんやムオル南部?のスカイドラゴン+しびれあげはたくさん、のような出現パターンが相当します。この場合、出現数は固定で画面幅に収まるだけ出現することになるので、お供の数はいつも同じ数だけ出てくることになります。

  • SR: $067F71 単一種出現モンスター1~4+夜のみ
067F71STA $2000$7E2000=AモンスターIDを1種類目にセット
067F74TXAA=X
067F75SECc=on
067F76SBC #$000CA-=#$000C
067F79BCC #$32 -> $067FADif(c==off) goto $067FAD
067F7BTAXX=A
067F7CLDA $F7F0,XA=$7EF7F0+X単一種出現モンスター1~4出現数IDをセット
067F7FTAXX=A
067F80JSL $0903EESR: $0903EE 引数:1#$00 引数:2#$0002 引数:3#$C8B72C 引数:4#$0000出現数最小を取得
067F8CAND #$00FFA&=#$00FF
067F8FSTA $1C$00001C=A
067F91JSL $0903EESR: $0903EE 引数:1#$00 引数:2#$0002 引数:3#$C8B72C 引数:4#$0001出現数最大を取得
067F9DAND #$00FFA&=#$00FF
067FA0SECc=on
067FA1SBC $1CA-=$00001C
067FA3JSL $00133ESR: $00133E最小~最大の幅で乱数を作成
067FA7CLCc=off
067FA8ADC $1CA+=$00001C
067FAASTA $2008$7E2008=A出現数をセット
067FADRTSreturn

1種類しか出現しないパターンです。$08B72Cは以下のようなデータ構造です。

$08B72C- 単一種出現数範囲(2Byte*5rec)

Byte意味
0出現数最小
1出現数最大

この値を取得して、その範囲の数値をランダムで作成して出現数を決定しています。

  • SR: $067FAE 1体のみ出現用
067FAESTA $2000$7E2000=AモンスターIDを1種類目にセット
067FB1JSR $80FC ($0680FC)SR: $0680FCモンスターIDがセットされている場合に出現数カウンタを全て1増やす
067FB4RTSreturn

これは見てのとおり。特に説明することはありません。

  • SR: $067FB5 固定パーティ出現種類・出現数決定
067FB5TAYY=A固定パーティレコードIDをセット
067FB6JSL $0903E2SR: $0903E2 引数:1#$00 引数:2#$0005 引数:3#$C8B736 引数:4#$0002
067FC2AND #$00FFA&=#$00FF
067FC5STA $2000$7E2000=A固定パーティ1を1種類目にセット
067FC8JSL $090566SR: $090566 引数:1#$00 引数:2#$0005 引数:3#$C8B736 引数:4#$0000 引数:5#$00000F
067FD7JSR $802C ($06802C)SR: $06802C固定パーティ出現数決定
067FDASTA $2008$7E2008=A
067FDDJSL $0903E2SR: $0903E2 引数:1#$00 引数:2#$0005 引数:3#$C8B736 引数:4#$0003
067FE9AND #$00FFA&=#$00FF
067FECSTA $2002$7E2002=A固定パーティ2を2種類目にセット
067FEFJSL $090566SR: $090566 引数:1#$00 引数:2#$0005 引数:3#$C8B736 引数:4#$0000 引数:5#$0000F0
067FFEJSR $802CSR: $06802C固定パーティ出現数決定
068001STA $200A$7E200A=A
068004JSL $0903E2SR: $0903E2 引数:1#$00 引数:2#$0005 引数:3#$C8B736 引数:4#$0004
068010AND #$00FFA&=#$00FF
068013STA $2004$7E2004=A固定パーティ3を3種類目にセット
068016JSL $090566SR: $090566 引数:1#$00 引数:2#$0005 引数:3#$C8B736 引数:4#$0001 引数:5#$00000F
068025JSR $802CSR: $06802C固定パーティ出現数決定
068028STA $200C$7E200C=A
06802BRTSreturn

これも必要な固定長データからデータを取ってきてセットするだけです。

以上でエンカウントモンスター+出現数が決定したわけですが、最後に$08ADD1- エンカウントの出現数(19Byte目)で各グループの出現数をクリップします。

  • SR: $067E19 最大出現数を見て出現モンスター数調整(画面幅考慮なし)
067E19LDX $18X=$000018エンカウントIDをXにセット
067E1BJSL $0903EESR: $0903EE 引数:1#$01 引数:2#$0014 引数:3#$C8B5DD 引数:4#$0013
067E27AND #$00FFA&=#$00FF最大出現数を取得
067E2ASTA $1C$00001C=A
067E2CSTZ $F7FA$7EF7FA=#$00バッファを初期化
067E2FSTZ $F7FC$7EF7FC=#$00
067E32STZ $F7FE$7EF7FE=#$00
067E35STZ $F800$7EF800=#$00
067E38LDX #$0000X=#$0000
067E3BLDA $2000,XA=$7E2000+X
067E3ECMP #$0000A==#$0000?
067E41BNE #$03 -> $067E46if(z==off) goto $067E46
067E43STZ $2008,X$7E2008+X=#$00モンスターIDが設定されていない場合は出現数に0をセット
067E46INXX++
067E47INXX++
067E48CPX #$0008X>=#$0008 ?
067E4BBCC #$EEif(c==off) goto $067E3B
067E4DLDA $1CA=$00001C
067E4FBEQ #$27if(z==on) goto $067E78
067E51PHAPush A
067E52LDX #$0000X=#$0000
067E55LDA $2000,XA=$7E2000+X
067E58CMP #$0000A==#$0000?
067E5BBEQ #$0Dif(z==on) goto $067E6A
067E5DLDA $2008,XA=$7E2008+X
067E60BEQ #$08if(z==on) goto $067E6A
067E62DEC $2008,X$7E2008+X–カレントの出現数をデクリメントする
067E65INC $F7FA,X$7EF7FA+X++テンポラリの出現数をインクリメントする
067E68DEC $1C$00001C–最大出現数をデクリメントする
067E6AINXX++
067E6BINXX++
067E6CCPX #$0008X>=#$0008 ?
067E6FBCC #$E4 -> $067E55if(c==off) goto $067E55
067E71PLAPull A
067E72CMP $1CA==$00001C?もともと取得した最大出現数と比較?
067E74BEQ #$02if(z==on) goto $067E78同じなら終わり
067E76BRA #$D5goto $067E4D
067E78LDX #$0000X=#$0000
067E7BLDA $F7FA,XA=$7EF7FA+X
067E7ESTA $2008,X$7E2008+X=A各グループに出現数をセット
067E81INXX++
067E82INXX++
067E83CPX #$0008X>=#$0008 ?
067E86BCC #$F3if(c==off) goto $067E7B
067E88RTSreturn

この部分ですが、もしかしたらバグなのかも知れません。出現するモンスターの総数が指定された「最大出現数」以下になるようにするプログラムだと思われるのですが、意図した動作をしていないようです(結局画面幅等で制限がかかるので表面化しにくい)。たとえば、スライム:6匹、いっかくうさぎ:6匹、最大出現数:4匹の場合、実際にデバッガ上での動作を追っていくと関連する変数の変遷は以下のようになります。

AX7E20087E200A7EF7FA7EF7FC1Cコメント
067E52#$00#$06#$06#$00#$00#$04
067E62#$00#$05#$06#$00#$00#$041ループ目
067E65#$00#$05#$06#$01#$00#$04
067E68#$00#$05#$06#$01#$00#$03
067E6B#$02#$05#$06#$01#$00#$03
067E62#$02#$05#$05#$01#$00#$032ループ目
067E65#$02#$05#$05#$01#$01#$03
067E68#$02#$05#$05#$01#$01#$02
067E6B#$04#$05#$05#$01#$01#$023ループ目
067E6B#$06#$05#$05#$01#$01#$024ループ目
067E71#$04#$08#$05#$05#$01#$01#$02
067E72#$04#$08#$05#$05#$01#$01#$02Aと$1Cを比較して異なるので$067E4Dへ
067E4D#$02#$08#$05#$05#$01#$01#$02
067E52#$00#$05#$05#$01#$01#$02
067E62#$00#$04#$05#$01#$01#$021ループ目
067E65#$00#$04#$05#$02#$01#$02
067E68#$00#$04#$05#$02#$01#$01
067E6B#$02#$04#$05#$02#$01#$01
067E62#$02#$04#$04#$02#$01#$012ループ目
067E65#$02#$04#$04#$02#$02#$01
067E68#$02#$04#$04#$02#$02#$00
067E6B#$04#$04#$04#$02#$02#$003ループ目
067E6B#$06#$04#$04#$02#$02#$004ループ目
067E71#$02#$08#$04#$04#$02#$02#$00
067E72#$02#$08#$04#$04#$02#$02#$00 Aと$1Cを比較して異なるので$067E4Dへ
067E4D#$00#$08#$04#$04#$02#$02#$00
067E52#$00#$04#$04#$02#$02#$00
067E62#$00#$03#$04#$02#$02#$001ループ目
067E65#$00#$03#$04#$03#$02#$02
067E68#$00#$03#$04#$03#$02#$FFFF
067E6B#$02#$04#$03#$03#$02#$FFFF
067E62#$02#$03#$03#$03#$02#$FFFF2ループ目
067E65#$02#$03#$03#$03#$03#$FFFF
067E68#$02#$03#$03#$03#$03#$FFFE
067E6B#$04#$03#$03#$03#$03#$FFFE3ループ目
067E6B#$06#$03#$03#$03#$03#$FFFE4ループ目

…以降7E2008,7E200Aが0になるまでループ、その結果7EF7FA,7EF7FCには#06がセットされ、最大出現数#$04は無視される。

となり、だらだらと書きましたが、要は設定した「最大出現数」が効きません(効くケースもあります)。これが意図した実装なのかどうか判断がつかないので「バグ」と断定するのは早計です。しかし、DQ3SFC K.Mixに関して言えば、序盤の一人旅の部分でモンスター数をコントロールできないのは具合が悪いので、以下のように修正することにします。これにより、エンカウントで設定された「最大出現数」を超えてモンスターが出現することはなくなります。$067E4D-76をSR化して外部に出し、さらに変更を加えます。

  • SR: $067E19 最大出現数を見て出現モンスター数調整(画面幅考慮なし)
067E51JSL $06F6D3SR: $06F6D3モンスター出現数を出現最大値以下に調整する
067E55-77NOP

  • SR: $0F6D3 モンスター出現数を出現最大値以下に調整する
06F6D3LDA $1EA=$00001E$1Eを念のため退避しておく
06F6D5PHAPush A
06F6D6STZ $1E$00001E=#$00
06F6D8LDX #$0000X=#$0000
06F6DBLDA $2000,XA=$7E2000+X
06F6DECMP #$0000A==#$0000?
06F6E1BEQ #$0Aif(z==on) goto $06F6ED
06F6E3LDA $2008,XA=$7E2008+X
06F6E6BEQ #$05if(z==on) goto $06F6ED
06F6E8CLCc=off
06F6E9ADC $1EA+=$00001E
06F6EBSTA $1E$00001E=A現出現総数を$1Eにセット
06F6EDINXX++
06F6EEINXX++
06F6EFCPX #$0008X>=#$0008 ?
06F6F2BCC #$E7if(c==off) goto $06F6DB
06F6F4LDX #$0000X=#$0000
06F6F7LDA $2000,XA=$7E2000+X
06F6FACMP #$0000A==#$0000?
06F6FDBEQ #$17if(z==on) goto $06F716
06F6FFLDA $2008,XA=$7E2008+X
06F702BEQ #$12if(z==on) goto $06F716
06F704DEC $2008,X$7E2008+X–
06F707INC $F7FA,X$7EF7FA+X++
06F70ADEC $1C$00001C–
06F70CDEC $1E$00001E–$1C,$1Eをデクリメントし、どちらかが0になったら終了
06F70ELDA $1CA=$00001C
06F710BEQ #$0Dif(z==on) goto $06F71F
06F712LDA $1EA=$00001E
06F714BEQ #$09if(z==on) goto $06F71F
06F716INXX++
06F717INXX++
06F718CPX #$0008X>=#$0008 ?
06F71BBCC #$DAif(c==off) goto $06F6F7
06F71DBRA #$D5goto $06F6F44グループ目まで来ていたらXを0にリセット
06F71FPLAPull A
06F720STA $1E$00001E=A
06F722RTLreturn

変更点は以下の2点です。

  • 調整前の出現総数を$1Eに保存し、1体出現数を増やすごとにデクリメントし、0になったら調整終了(調整前の出現総数が出現最大数を下回っている場合の対処)
  • $1Cの値も1体出現数を増やすごとにデクリメントする。1体ごとに$1C,$1Eの値をチェックし、どちらかが0になっていたら処理終了。1体ごとにグループを移動させ、4グループ目まできたら1グループ目に戻す。

以上でエンカウントデータにセットされている情報がどのように使用されて出現モンスターが決定されているかの説明は終わりです。何度も言いますが、このSRをコールした時点では、画面幅等を考慮した最終的に出現するモンスターは決定していません(3グループそれぞれ6体出現とか結構あるので)。ここからさらに各モンスターに設定されている最大出現数によるクリップ、各モンスターの幅や使用可能なメモリ量やハードウェア制限?により出現数、種類が削られていくことになります。具体的には、SR: $04797Fでその調整をしていますが、まだざっくりしたところまでしか解析できていません。解析できたら続きのエントリを投下します。また、この部分をこれ以上(プログラム的に)変更する予定はありません。画面幅等の条件で削られてしまうので、いくら凝っても結局削られて終わり、ということになり、効果のほどが不明だからです。この解析結果に従って改めて自分の設定したエンカウント情報を見ると、いかにいい加減だったかがわかります。このあたりも要調整でしょう。

コメント

タイトルとURLをコピーしました