Quantumleap
3298 words
16 minutes
イカッチャでビッグラン向けのステージを遊ぶための方法

イカッチャ#

通常、イカッチャにおけるサーモンランのモードは次のうちのどちらかです。

  1. プライベート
  2. レギュラー
項目プライベートレギュラー
条件レギュラー以外いつものバイトのシナリオ保存
編成緑ランダムのみ(自由選択可)固定
ブキ固定           変動
キケン度200%まで任意
オカシラシャケ出現しない任意
レアブキ枠なしあり

大まかに分けると上のような違いがあります。レギュラーで遊ぶためにはオンラインで「いつものバイト」をするか「いつものバイト」のリザルトをシナリオ保存する以外に方法はありません。それ以外の遊び方をすれば必ずプライベート扱いになります。

一応、ビッグラン開催時はいつものバイトをすればビッグラン扱いになりますがシナリオが保存できないため確認できないのでここでは割愛します

レギュラーの場合は編成は固定されており、シナリオで遊んだとしてもたとえ緑ランダムであってもブキを変えることができません。一方、プライベートの場合は他人のシナリオコードを保存した場合などはブキが表示されていることがありますが、内部的には全て緑ランダム(任意)扱いのため、自由にブキを変えることができます。

プライベートとレギュラーの違い#

また、プライベートでレギュラーと似たようなバイトを再現しようとしても以下のような違いがあります。

  1. オカシラシャケが出現しない
  2. ブキを選択した場合、選択したブキで固定される
    • レギュラーでは編成四種からランダムにローテーションですが、プライベートの場合は選択したブキで固定です
  3. ランダム枠でクマサン印のレアブキが支給されない

更に、イカッチャの場合は

  1. 「クマサン」が「ナゾの声」になる
  2. バイト終了後のクマサンからのメッセージがない
  3. イカリング 3 にリザルトが登録されない

の違いがあります。要するに、レギュラーのフリをしてリザルトを提出することはできません。ズルはダメということです。

シナリオ#

シナリオはバイトを再現するための必要最低限の情報をまとめたものです。シナリオはクマサン商会の端末からシナリオコードを入力して取得するか、自分のリザルトから発行することでセーブデータに書き込むことができます。

保存できるシナリオの上限は 50 です

また、プライベートバイトは通常、キケン度を 200%までしか上げることができないため、200%以上のキケン度のシナリオがあるならそれは必ずレギュラーのシナリオになります

通常はビッグランのバイトをシナリオとして保存することはできませんが、データを書き換えることにそのようなデータを作成することは可能です。

シナリオのデータ#

セーブデータとして書き込まれているシナリオの情報について解説します。

ここで解説しているものに加えて、ハイスコアも記録されていますがめんどくさいので割愛します。

モード#

  1. レギュラー
  2. プライベート
  3. チームコンテスト
  4. コンテスト
  5. ビッグラン

の五つのモードが存在します。一時期、イカリング 3 ではPRIVATE_SCENARIOというモードが存在していましたが、現在はなくなって単純にPRIVATEに統一されました。

ランダムシード#

支給ブキ、スペシャル、出現するオオモノシャケの種類と順番などのありとあらゆる WAVE の内容を決定するシードです。

ステージ ID#

ビッグランを含む、全てのステージの中から任意の一つ。

キケン度#

四人の内部的レートの平均なので、キケン度 x5 の値となる。

キケン度 200%なら 1000、キケン度 333%であれば 1665 の値が入っている。

シナリオコード#

NPLN サーバーから発行された値。シナリオとシナリオコードは一対一関係であるだけなので、意味のある値ではなかったりする。

オカシラシャケ#

シーズン 4 時点ではヨコヅナ(23)またはタツ(24)のみが有効。ランダム設定もあるかも知れないが、不明。

実は出現しない(0)という値も有効。プライベートの場合はオカシラシャケが出現しないので常に 0 になっています。

モードがプライベートの場合は後述するオカシラメーターの値を 20(出現率 100%)に設定しても出現しません。

ただし後述するが 0 という値は意味がない

バージョン#

シナリオを保存したときのスプラトゥーン 3 のバージョン。ここが現在のバージョンよりも低いと「正しく再現されないかも知れません」的な警告が表示されます。

タイムスタンプ#

最後にそのシナリオを遊んだ時間。

オカシラメーター#

四人の合計の値。一人あたりの最高値は 5 なので合計 20 が最高で、20 に設定すれば 100%、EX-WAVE が発生します。

レアブキ#

ランダム枠で 20%の確率で選ばれるクマサン印のブキの種類。

0 を指定するとレアブキが支給されず、プライベートの場合は常にこの値は 0 になっています。

シーズン ID#

シナリオを保存したときのシーズン。ランダムブキの抽選で必要になる値。

例えば、シーズン 3 までのランダム編成のシナリオでは何度遊んでもシーズン 4 で実装されたフィンセントは絶対に支給されません。

ここのシーズンチェックの判定が誤っているため、保存したシナリオのシーズンとモードによっては選択したブキに関わらずボールドマーカーが支給されてしまうというバグが発生します。

有効性チェック#

0 か 1 が入っています。

0 にするとその他全てのパラメータの値に関わらずそのシナリオが無効になり、選択することができなくなります。

よって、基本的には 1 を入れておいて良いパラメータです。

シナリオの有効性#

有効性チェックとは別にシナリオの有効性チェックがあります。

というか、多分シナリオをセーブから読み込んだときに特定の条件を満たすと有効性チェックが上書きされています。

以下、シナリオが無効になってしまうパターン

  1. モードがレギュラーでもプライベートでもない
    • モードは五種類ありますが、この二つ以外は無効になります
  2. レギュラーでオカシラシャケ ID が 0 になっている
    • オカシラシャケが出現しない可能性のあるレギュラーのバイトは存在しないのでエラーになります
    • オカシラシャケを出現させたくない場合はオカシラメーターを 0 にしましょう(出現率 0%)
  3. ビッグラン用のステージを選択する
    • 未確認ですが、多分そう
  4. レギュラーでレアブキ ID が 0 になっている
    • 未確認ですが、多分そう

というわけで、一般的にはビッグランのステージを遊ぶことはできません。

それもこれもisValidの値が上書きされてしまうからなので、それを無効化するためのパッチの開発に取り組んでいました。

このパッチが完成すれば本来は弾かれているはずのシナリオを遊ぶことができ、楽しいことになるはずです。が、意外と難しかったのでこちら方面での対応は行き詰まっていました。

パッチをつくろう#

で、いろいろあってめんどくさいなということで放置気味だったのですが「ビッグラン用のステージ、ステージのパラメータを変えれば遊べますよ」という情報を頂いたので、自分でもパッチを作ってみることにしました。

ステージのパラメータ#

サーモンランのステージ情報は/RSDB/CoopSceneInfo.Product.400.rstbl.byml.zsというファイルの中に書き込まれています。

  • DisplayOrder
    • 並び順です
  • Id
    • 内部 ID(数値)です
  • isBigRun
    • ビッグラン用のステージかどうかのフラグ
  • Season
    • 開放されたシーズン
  • __RowId
    • 内部 ID(文字列)

ステージに設定されているデータはこの五つです。サーモンランの部屋を立てたときに選択可能であるかどうかはisBigRunDisplayOrderで制御されていそうな気がするのでこれらを弄ってみることにします。

ビッグラン用のステージはisBigRun=TrueDisplayOrder=-1となっていてどちらかを使って非表示にされている可能性が高い

解析する#

となればサーモンラン用のステージ情報であるCoopSceneInfo.Product.400.rstbl.bymlを読み込んでいるところをバイナリを解析して探します。

これは検索すればすぐに見つかって、バージョン 4.0.2 であればsigned __int64 __fastcall sub_14CEBE4(CoopSceneInfo *a1, unsigned __int16 **a2)であることがわかります。

また、このとき 0 番目の引数であるCoopSceneInfoの構造体は以下のような定義になっています。

struct CoopInfo {
    _QWORD __rowId;
    _DWORD displayOrder;
    _DWORD id;
    _DWORD season;
    _BYTE isBigRun;
}

これだけだとわかりにくいと思うのでポインタを表示すると、

00000000 CoopSceneInfo
00000000 __rowId
00000008 displayOrder
0000000C id
00000010 season
00000014 isBigRun
00000015 undefined
00000016 undefined
00000017 undefined

になります。後半 3 バイトは謎の値が入っていますがまあそれはどうでも良いです。

やりたかったことは、ステージのビッグラン設定を無効化することなので、CoopSceneInfoのインスタンスのポインタをa2とすれば

a2->isBigRun = 0;

となるわけですが、アセンブラではこのような書き方はできず直接ポインタをいじるしかないので、a2のポインタが格納されているレジスタを仮にX2とすれば、

STRB XZR, [X2, #0x14]

XZR は読み込めば常に 0 が返る、魔法のようなレジスタです、便利

のようなコードを書けば良いことになります。ここまでできれば答えは出たも同然ですね。

isBigRunは 1 バイトの情報しか持たないので(真理値なので 1 ビットでも良いような気もするがそのような命令がなさそう)、32 ビットの値をコピーする STR ではなく 8 ビットコピーの STRB を使いましょう。

よって、上記のアセンブラはゼロレジスタを読み取って 64 ビットの長さの 0 を読み込んで、下位 8 桁を X2[0x14]に代入する、という内容になります。

32 ビットコピーが STR、半分の 16 ビットコピーが STRH(Half)なので 8 ビットコピーは STRB(Binary)なのだろうか

ちなみに XZR の代わりに WZR を使えば 32 ビットの 0 が返ります

こうすることで、ファイルからステージ情報を読み込んだ段階でisBigRunの値を強制的に 0(False)で上書きすることができます。

注意点としてはステージ情報をファイルから読み込むのは起動直後のブート画面(黄色と青のインクのところ)で、一回しか読み込まれないため Edizon 形式のパッチではこの方法は利用できません。

あとはこれを IPSwitch 形式に変換すれば OK です。DisplayOrderも変更する必要があるかと思ったのですが、こちらは特に不要でした。

パッチの効果#

最後にパッチの効果と制限を書いておきます。ホストがパッチを当てている必要があるのは言うまでもないので、クライアントがパッチを当てているときと当てていないときで挙動がどう変わったかをメモしておきます。

モードパッチ未パッチ
レギュラーOKNG
プライベートOKOK
ビッグランNGNG

とあるように、パッチを当てた本体がホストになれば部屋を立ててビッグラン用のステージを選択できるようになり、ビッグラン用のステージが設定されたシナリオを読み込むことができるようになります。

ステージが選択可能なものかどうかはホストしかチェックしないため、ホストがパッチを当てているだけでビッグラン用のステージは遊べます。

実はスプラトゥーン 2 でも初期はステージの整合性チェックはホストしか行っていなかったが、ある時からクライアントもチェックするようになった

ただし、以下の制限があります。

  1. モードとしてビッグランは指定できない
    • レギュラーまたはプライベートを選択してください
  2. プライベートを選択した場合、強制的に緑ランダムになる
    • プライベートバイトの仕様上、そうなります
    • クマサン印のレアブキは支給されません(シナリオ自体に設定すればいけるかも)
    • オカシラシャケは出現しません(オカシラメーター 20 を設定しても出現しません)
  3. レギュラーを指定した場合、クライアントもパッチを当てている必要があります
    • パッチを当てていない場合、ゲーム開始直後に通信エラーが発生します
    • 任意のブキやクマブキを使いたい場合は全員がパッチを当てている必要があります

よって、未パッチのユーザーと遊びたい場合はモードをプライベートにする必要があります。通常の金ランダムであれば普通に未パッチのユーザーとも遊べるだけに、ビッグランだけ弾かれてしまうのがちょっと悲しいですね。

記事は以上。

イカッチャでビッグラン向けのステージを遊ぶための方法
https://fuwari.vercel.app/posts/2023/06/bigrun/
Author
tkgling
Published at
2023-06-26