なるほどえたきちのブログじゃねーの

チラ裏雑記帳

ポケモン過去作の解析とか乱数調整とかそこら辺。不定期更新。

【ポケモンBDSP】LCG in 2021【日替わり乱数】

この記事はPokémon Past Generation Advent Calender 2021 3日目の記事です。
adventar.org

あと固定乱数とは全く関係のない内容になっていますので悪しからず。

概要



先月発売されたポケットモンスターブリリアントダイヤモンド/シャイニングパール(以下BDSP)にて、発売前の解析によりグローバルPRNGにXorshift128(Unity標準関数)、ローカルPRNGにXoroshiro128+が使用されていることが分かっていたが、その後の解析により日替わりseedの遷移に64bitのLCGが使用されていることが判明した。
この日替わりseedは原作のDPと同様にIDくじ、大量発生の種族、ヒンバスの釣れるマス等に使用されているため、何らかの手段で逆算ができればそれらのランダム要素の予測が可能となる。

また、この調査はBDSPver1.0.0のROMデータ解析により行っている。
私が最後に確認したver1.1.1の時点では計算内容の再現が取れたが、先日のアップデート(ver1.1.2)で何かしらの修正が入っている可能性がある。

追記(2021/12/23)
ver1.1.3にて当該処理の修正が行われた。
seedの更新処理等は変更されていないが、IDの決定処理のみ以下のように修正されている。
これにより、1つのIDから未来のIDを予測することはできなくなったが、32bitの日替わりseedの予測が容易となった。
以前のバージョンまでは6日分の大量発生の情報が必要だったが、この修正により2日分のIDくじの結果で絞り込めるようになっている。
また、この計算処理の仕様上IDの下位5桁が00000-48575の場合は他のIDより1.1倍程くじに当選しやすい。

// くじ当たり番号の決定
void FieldLotteryWork__UpdateNumber(int64_t days)
{
	// 前後省略
	uint seed = RandomGroupWork__GetDefaultRandom();
	seed = seed * 0x41c64e6d + 0x3039;
	
	// くじ当たり番号の決定
	int WinningNumber = (seed >> 0xC) % 100000;
}

LCGのよくない実装



この予測についてだが、IDくじとヒンバスの釣れるマスについてはIDくじの結果を1度確認するだけで可能となってしまう。
これを可能とする原因箇所は以下の通りである。

// 日替わりseed更新
void RandomGroupWork__Update(int64_t days)
{
	// 前後省略
	ulong seed = PlayerWork__get_RandomGroup();
	for (int i = days; i > 0; i--)
	{
		seed = seed * 0x6c078965 + 1;
	}
}

// くじ当たり番号の決定
void FieldLotteryWork__UpdateNumber(int64_t days)
{
	// 前後省略
	uint seed = RandomGroupWork__GetDefaultRandom();
	seed = seed * 0x41c64e6d + 0x3039;
	
	// くじ当たり番号の決定
	int WinningNumber = seed & 0xFFFF;
}

勘のいい方は気付いたかもしれないが、DPPtとほぼ同じである。
ヒンバスタイルの決定処理は長くなりそうなので省くが、こちらもDPPtとほぼ同じ決定処理だった。
但し、IDくじ当たり番号の決定処理については原作と少し異なっている。
原作では32bitのseed値上位16bitを使用していたのに対し、今作は下位16bitを使用してしまっている。カルドセプトサーガ
これによりどのような問題が発生するかと言うと、IDくじに限り実質的に16bitのLCGとなる上にその内部状態が1つの結果を確認した時点で完全にリークしてしまうことになる。
また、この使い方ではLCGの性質上取られる値に規則性が生まれてしまう為、そもそも乱数として成り立っていない。(1日毎にIDの偶奇が変わる、等)
1度のくじ結果確認で未来予測が可能となる理由については以上の通りである。

Xoroshiro128の初項(64bit)に32bitの値入れてたりする辺りILCAが自前で実装した乱数生成器は大概何かしらの問題を抱えてる気がする

IDくじのバグ



また、そもそものIDくじの挙動にも問題がある。
BDSPではトレーナーIDが6桁(000000-999999)の値となる為、5桁でIDを取得するにしても00000-99999の範囲が得られなければならない。
しかし、BDSPの実装では0x0000-0xFFFF(00000-65535)までの値しか取得できない仕様となる為、34464通りのIDが完全に無視されることとなる。
更に、IDの比較処理にもバグがあり、6桁IDの内下位5桁しかチェックされていない。
その為、上位5桁が完全に一致しているポケモンを所持していたとしても以下の挙動になる。




おいふざけんな
剣盾のIDくじの仕様調べてみたら仕様通りらしい、謹んでお詫び申し上げます

つまり、6桁ID下位5桁が65536以上の人は一生掛かってもくじに当選しないこととなる。(修正アプデが入らなければ)

各種要素の未来予測



計算用のツールを作成したのでそちらを適当に触って欲しい。
ファイル置き場 - チラ裏雑記帳
IDくじの結果とヒンバスの釣れるマスについては1度のくじ結果確認により予測できるようになる。
大量発生の予測には日替わりseed下位32bitの特定が必要となる。
これはIDくじの結果と6日分の大量発生の内容の記録によって可能。





くじの結果からヒンバスタイルを予測した場合、緑のマスか赤のマスのどちらかが対象のタイルとなる。

また、大湿原の出現ポケモン決定や地下大洞窟の道具交換にも日替わりseedが使用されている。
但しこちらは乱数値の32bitキャストを行わずに計算している為、今回は対応しなかった。

終わりに



ここまで読んでくださってありがとうございました。
まさか最新作でこんな内容の乱数調整(?)ができるとは思っていませんでした。
今回の日替わり乱数とは別にBDSP固定乱数、SWSH野生シンボル乱数も本体改造無しで出来ることが分かったのでそちらのツール制作/調査も進めたいなと思います。

4日目は剣心氏による4gen捕獲チュートリアルです。

【カスタムGBA】電子工作初心者がGBAを組んでみた話【名取さなEdition】

はじめに

強いGBA、欲しいですよね。
マイコン内蔵のGBAは過去に組んだのですが、ボタンの押し感が悪かったり加工が雑だったりとお世辞にもクオリティの高いモノとは言えませんでした。
機能面だけ見たらこれに相当するものは中々無いはずですが個人的にはまあ微妙でした。


マイコンなんかよりマジコンの方が普段から使いまくるのでそっちを内蔵してしまう方がいいのでは?と考えた訳です。
しかし、どう考えても配線がヤバいことになる気しかしないので二の足を踏んでいました。
電子工作は全くの専門外なので中々手こずりそうです。

後はカラーリングが全く思い付かなかったのもあります。
というかそっちの方が圧倒的に大きいです。

何だかんだカラーの候補が絞れてきて、グレー統一にするかかクリア統一にするかで迷っていた所、机の上にあるフィギュアが目に留まりました。
f:id:BZL:20210803003943j:plain
………これや!
そんな訳で名取さなEditionなるGBAを組むこととなりました。(なんで?)
機能としては先に紹介したGBAのものに加えてEzFlashΩを内蔵する感じになります。
また、FunnyPlaying(IPS液晶出してるメーカー)が新しい液晶キットの取り扱いを始めたのでそちらの検証も兼ねてます。
制作過程の写真は殆どないので悪しからず。
普通に組み込んだパーツ類は個別紹介しておきます。

液晶

f:id:BZL:20210803004011j:plain
FunnyPlayingの『ITA NEW AGB TFT BACKLIGHT KIT』を使用しました。
DSiの下画面をGBAに移植するキットみたいです。
私が買った時はセールか何かで2500円くらいで買えちゃいました。
おまけに送料無料です。

国内で買ってる人あまり見ないので簡易レビュー的なものも書いておきます。

液晶の質について

発色はIPSキットと比較してもかなり綺麗でした。
スケーリング無しで表示されるので映り方はDSLiteとかAGS101みたいな感じです。
また、画面サイズもAGS101と同じなのでIPS用のガラスレンズは合わないです。
映り方も画面サイズも全然違うのでIPSキットの進化系ではなく新たな選択肢として見るのが適切ですね。
人によってはIPSキットの方がいいやと感じるかもしれません。
個人的にはITAキットの方が好みです。

DSiの下画面液晶が使えるということで、使える液晶の種類は思ったより多いです。(互換品にも色々種類があるらしい)
ただ、モノによっては相性問題で上手く映らなかったりするみたいです。
綺麗な状態の純正液晶が手元にあったので接続してみましたが、発色は付属の互換液晶の方が普通に綺麗です。
その為、液晶が基板に貼り付けられて送られてきたら基本弄らない方がいいです。
因みに私は基板に貼り付いた液晶剥がそうとしてフレキ基板にキズ入れました。

消費電力

公式サイトでは消費電力0.15Wとか書いてありますが実際の所そんなに低くないです。
IPSよりちょっと低いくらいなので省電力化を目的に組み込むことは推奨しません。
液晶変えてもほぼ変わらなかったので恐らくは基板側で電力食ってそうな気がします。

2021/08/22 追記
追加でITAキットを購入した所、基板に変更が加えられていました。
回路自体の変更に加え、輝度調節用のパッドに印字されている文字が若干見やすくなっていたりします。
また、消費電力がIPSキットの半分程度にまで下がっていました。

輝度調節

1chip液晶モジュールでお馴染み(?)のタッチ式輝度調節が使われてます。
個人的には好きじゃないので無効化しました。
画像の緑丸で囲った部分をGBA側のGNDと繋げればOKです。
f:id:BZL:20210802211251p:plain
一応IPSキットと同じ方式での輝度調節も可能です。

他Modとの相性とか

クロックアップとの相性は良くないです。
画面がかなり荒ぶるので推奨はしません。
手持ちの互換品/純正品全て試しましたが同じような挙動になりました。
f:id:BZL:20210803021654j:plain
また、全体的にデカいので今回のような機能盛りGBAには向きません。
サイズ的にはIPSキットが何だかんだ一番扱いやすいのかな...と思います。

シェル

こちらもFunnyPlayingのものを使用しました。
前面はライトピンク、背面はベージュを使っています。

IPS液晶は無加工で入りますが、ITAキットの場合はそこそこの範囲をカットする必要があります。
ITA対応の金型が出来ているらしいのでこの作業はその内不要になりそうです。
f:id:BZL:20210803004204j:plain

RetroSixシェルにITAキットを導入する場合は画像の赤枠部分をカットします。
ちゃんと検証してる訳ではないので位置が合うかどうかは知りません。
f:id:BZL:20210803205646j:plain

ボタン

今回は白とピンクの組み合わせにしました。
色がそれっぽければ何でも良かったので昔買った中華ボタンを適当に使いました。

ラバー

昔RetroModdingで組んで貰ったGBAのボタンの感度が良かったのでこっちはまあまあ拘りました。
Start/SelectはRetroModding、AB/十字はCloudGameStoreのものを使っています。
AB/十字に関しては純正品もかなり良いです。
残念ながら私の手元にある純正ラバーは全部劣化してました。

ラバーを取り付ける前に裏面の接点部分を洗浄すると若干感度が良くなります。
リレークリーナーを吹き付けてから綿棒で適当に擦る感じです。
新品であっても結構汚れ(?)が付着しているみたいです。
f:id:BZL:20210803004232j:plain

サウンドモジュール

アンプ

RetroModdingで購入したものを使用しました。
注意点として、公式サイトで紹介されている配線方法では電源ラインの取り方に問題があります。
公式サイトの通りに導入した場合、電池の電圧降下によりアンプの最低駆動電圧を満たさなくなってしまうケースが発生します。
その為、電池残量が少なくなると音声にノイズが乗ったり音が出なくなったりします。
今回は以下の画像の通りに配線しました。
f:id:BZL:20210802220405p:plain

スピーカー

丁度東京の方に用事があったので秋葉原に寄るついでに23mmスピーカーを買ってみました。
付属スピーカーより高域の発音が若干綺麗に聞こえます。
また、サランネットが付いていたりと質感も結構良い感じでした。
f:id:BZL:20210803004310j:plain
f:id:BZL:20210803004317j:plain

組み立て

地獄の作業の始まりです。

仕様策定

まずはどんな仕様のGBAにするか予め決めておきます。
今回組むものは以下の通りとします。

  1. ITA液晶キット実装
  2. 輝度調節は外付けしたボタンで行うようにする
  3. 電源ランプのカラー変更
  4. サウンドモジュール実装
  5. ワイヤレスアダプタを内蔵、外部スイッチでON/OFFの切り替え
  6. クロックアップ実装、外部スイッチで等速/倍速の切り替え
  7. 外部接続端子は1ポートのUSB TypeC
  8. MicroSDカードスロットをUSB端子の隣に配置
  9. 充電式バッテリーを使用、充電はUSBで行う
  10. マイコン(ProMicro)を内蔵、PC経由での操作を可能とする
  11. SDカードを挿した上でUSB接続することによりSDカードリーダーとしても機能する
  12. カートリッジが何も挿入されていない時に内蔵EzFlashが起動するようにする
  13. 内蔵EzFlashはMicroSDカードスロットに繋げる
  14. 干渉防止の為、GBA起動時はSDカードリーダーの機能を停止する


………本当に組めるのこれ?

シェル加工

どう考えても普通に閉まる配線ができる訳ないので先に中をスカスカにしておきます。
電池Boxなんかは跡形も残さず切り落とします。
f:id:BZL:20210803004609j:plain

また、お馴染みUSB-Cポートの穴開けに加えてSDカードスロットの穴も開けておきます。
f:id:BZL:20210803004617j:plain

クロックアップ/ワイヤレスアダプタ用のスイッチも取り付けます。
f:id:BZL:20210803004624j:plain

取り敢えず大掛かりな所は以上となります。
後は配線が干渉した時にチマチマニッパーで切り落とせばいいと思います。

ボタン加工

ボタン加工ってなんだよって思われるかもしれませんがそのまんまの意味です。
輝度調節ボタンを外付けする為、バンパーに穴を開けます。
今回はゲームボーイミクロに合わせて右側のバンパーを加工しました。
f:id:BZL:20210803004633j:plain
既に色々付いちゃってますがこんな感じです。
因みに追加したボタンと基板は白のDSiから移植したものです。
音量調節ボタンがかなり丁度良さそうだったので使ってみたら結構ピッタリでした。

f:id:BZL:20210803004640j:plain
裏面はこんな感じで残してあります。
全部くり抜いてしまうと基板を押さえるものが無くなってしまうので逆に面倒な感じになります。
どちらにせよ結構大変なのでもうやりたくないですね...

電源ランプ変更

f:id:BZL:20210803004650j:plain
緑ランプを白に変更してみました。
ただ変えるだけだと光量が強すぎて目が痛くなりそうなのでLEDに挟む抵抗値を変更します。

f:id:BZL:20210803004708p:plain
画像で示したR10の抵抗を変更します。
白のLEDだと20KΩくらいが丁度良かった気がします。

ワイヤレスアダプタ内蔵

お馴染みのやつですね。
gaito0826.hatenablog.com
がいと氏の記事に大体書いてあるのでそちらを参考にどうぞ。

可変クロックアップ

これもお馴染みのやつです。

f:id:BZL:20210803004736j:plain
元々あったパッドを流用し、パターンカットを利用して基板上に実装する形にしてみました。
水晶の隣にICが置いてあるタイプの基板では難しいやり方かもしれません...

マイコン内蔵

これは多分お馴染みじゃないやつですね。
今回はトランジスタアレイを使用し、マイコンの出力信号に合わせてTP-GND間を導通させるようにしました。
これにより、PCからGBAを操作できるようになります。
自動操作以外にも色々できることがあると思うのでそこら辺は自分で色々試してみてください。
フルカラーLEDの制御とか結構面白いと思いますよ。

輝度調節ボタン

今回使用した液晶モジュールはITAキットですが、こちらもIPSキットと同様にSEL/L/Rポイントの3つが存在します。
この3つの内、SELポイントをGNDに直結し、L/Rポイントを先程加工したバンパーへ接続します。
液晶モジュール側では常にSELECTが押されている扱いとなる為、残るL/R入力信号が入ってきた時点で輝度が変更されます。
ボタンのどこにハンダ付けするかは使用するボタンによって変わるので色々試してみてください。

USB機器周りの配線準備

使ったもの
USB-Cコネクタ
MicroSDカードスロット
マイコン(ProMicro)
TP4056モジュール
1300mAhバッテリー:
1000mAhバッテリー(今回は未使用)
SDカードリーダー
USBハブ
EzFlashΩ
マイクロスイッチ

SDカードリーダーとUSBハブはダイソーに小型のものがあるらしいです。
私は見つけられなかったのでAmazonでそれっぽいのものを買いました...
カードリーダーとUSBハブは当然既製品なのでまず分解します。
f:id:BZL:20210803004751j:plain
f:id:BZL:20210803004757j:plain
SDカードリーダーは期待通りのサイズでした。
分解は容易で、基板も薄くて非常に扱いやすそうです。

f:id:BZL:20210803004805j:plain
f:id:BZL:20210803004811j:plain
USBハブの方の分解はかなり大変でした。
基板がグルーで完全にコーティングされていたのでまずはそれを全て剥がす必要があります。
ハンダごてを当てて無理矢理溶かしたので部屋が身体に悪そうな臭いで充満しました。
また、2分岐の割に基板がまあまあ大きいのであまり嬉しくないです。
そもそもこの基板自体4分岐用に見えます。
コンデンサ追加すれば更にポート拡張できそう?
どちらにせよ同じようなことがやりたい方はもう少し小さい2分岐ハブ探した方がいいかもしれません。

USB機器の接続

f:id:BZL:20210803004822j:plain
f:id:BZL:20210803004828j:plain
f:id:BZL:20210803222158j:plain
完全にすっ飛ばしました。
反省はしていません。
途中経過の画像なので未配線だったり上手く動いてない箇所が結構あります。
参考にはしないでください。

f:id:BZL:20210803004836p:plain
超雑ですが配線図はこんなんです。
コレ見て何をどこに繋げるのか微塵も分からないって人は多分真似しない方がいいと思います。
GBAマイコン間の接続はやりたいことに合わせて各自適当に変えてみてください。
マイコンいらないよって人はそもそもUSBハブもいらないのでカードリーダーに直結してしまって問題ないです。
注意点として、SDカードへの電源ラインを普通に繋げると上手く動かないので別の所から適当に引っ張ってきてください。
EzFlashへの電源ラインを通すマイクロスイッチはカートリッジが挿入された時にONになるように配置します。
これがちゃんと閉まれば本体側は完成となります。


動かすとこんな感じです。

f:id:BZL:20210803004848j:plain
f:id:BZL:20210803004854j:plain
SDカードリーダーもしっかり機能しています。

外観を整える

中身が完成したので後はガワを整えていきます。
公式素材使えばそこまで手間は掛からんやろ...と思ってましたが公式ガイドラインに以下の記述が。

・当方に帰属する素材(動画や写真、イラスト、音声等)を引用の範囲を超えて利用することを禁止します。

・「名取さなの公式写真や公式イラストを○○に使いたいので許可をください。」
公式のものと誤解される可能性がある為お断りしています。
素材はご自身で用意してください。

規約についてのお問い合わせについては基本的にお答えしかねます。
確認しないとわからないものはだめだと思ってください

………まあ多分使っちゃダメなんだろうなと思います。
久々のお絵描き作業が確定しました。

レンズ

早速デザインを決めます。
f:id:BZL:20210803011002p:plain

作りました。
これを適当に印刷してガラスレンズに貼り付けます。
接着にはゴリラグルークリアを使いました。
一回貼り付いたらデザインナイフで力一杯削らないと取れません。
Retro○ixのUVレンズより強度高くなる気がします。

f:id:BZL:20210803010352j:plain
画像はロゴがズレた失敗作ですが割と綺麗に作れます。
かなり大変ですが...

ぶっちゃけBluish Squirrel辺りに頼む方がいいです。

ステッカー

こっちは普通にイラスト使いたいのでお絵描きします。


普段絵描かない割にはそこそこちゃんと描けた気がします。
これを上手いこと使ってステッカーもデザインします。
f:id:BZL:20210803011405p:plain
できました。
これを適当に印刷してカッティングマシンでそれっぽい形にカットします。

f:id:BZL:20210803011637j:plain
貼りました。(印刷したシートの写真は撮ってませんでした)

こっちもレンズと同様Bluish Squirrelでオーダー可能ですが、プリントが剥がれ落ちるという話も聞くので安定択かどうかは分かりません。
カッティングマシンと良いプリンターを持ってる方は多分自作する方がいいですね。

おわりに


f:id:BZL:20210803012419j:plain
f:id:BZL:20210803012529j:plain
f:id:BZL:20210803012734j:plain
というわけで完成です!
恐らく初めて真面目に組もうと思って組んだGBAですが、中々良い感じの出来になったのではないでしょうか。(自画自賛)
少なくともEzFlash内蔵は他にやっている人を見たことがないので、機能面に関しては十分な水準かと思います。
何だかんだでまともに使えるGBAは昔RetroModdingで組んで貰った個体だけだったりするので実質2台目ですね。

かなり大変だったのでもう二度と組みたくないです。
基板上に生やした配線の数は約100本、ハンダ付けポイントは約220箇所となります。

馬鹿じゃねぇの(嘲笑)
f:id:BZL:20210803013532j:plain

モンスターハンターライズ 護石リセマラ自動化ツール

護石スナイプしてやろうと思ったけどダンプしたコード読むのがめんどくさくなったので代わりに自動化ツール作りました。
取り敢えず当記事ではツールの使い方だけ纏めておこうと思います。
最初の2行書いた時点でかなりめんどくさくなってるのでかなり大雑把な纏めとなりますが悪しからず。

先に言っておきますが自動化ツールである都合上多少の相性問題っぽいのはあるかもしれないです。(操作のラグとかドライバ周りとか)
此方で再現できない問題については基本的に対応見送るので、上手くいったらラッキーくらいに思っておいてください。

注意:
当ツールの動作確認に使用したMHRiseのバージョンは2.0となります。
今後のバージョンでの動作保証は出来かねますのでご了承下さい。

https://drive.google.com/drive/folders/1iMORqLJzt35WOH1e5-2FpvnDm5JzgY-a?usp=sharingdrive.google.com

使い方

0:事前設定

必要なもの:
キャプチャーボード
CSR製チップ内蔵のBluetoothドングル
64bitのWindowsOS

Switch/モンハン側の設定:
[Switch]本体設定->テレビ出力->テレビの解像度 - 1080p
[Switch]本体設定->テレビ出力->RGBレンジ - フル
[Switch]本体設定->テレビ出力->画面の大きさ - 100%
[モンハン]オプション->DISPLAY->明るさ - 50%
[モンハン]オプション->SAVE DATA->オートセーブの設定 - オートセーブしない

1:映像

適当に繋げてるキャプボ選んで接続ボタン押すだけです。

2:無線接続セットアップ

Bluetoothドングルを使用する場合はドライバの置換が必要となります。
接続したBluetoothドングルを選択し、インストールボタンを押すとドライバの置換が完了します。
注意点として、ここでドライバ置換を行ったドングルは他のBluetooth機器との接続には使用できなくなります。
元のドライバに戻す場合はデバイスマネージャーから手動で操作してください。

3:コントローラー接続

Bluetoothドングルを使用する場合はそのままでおk。
マイコンを使用する場合は適切なCOMポートを選択してください。
書き込むhexファイルはNX2用のアレです。
モンハン起動中であればそのまま待っているだけで接続画面に移行するはずです。
接続画面に自動移行しない場合は[ホーム]→[コントローラー]→[持ちかた/順番を変える]の待機画面でも接続可能です。
接続後はPCに接続しているゲームパッドからSwitchの操作が行えます。多分。


4:マクロ

実行したいマクロを選びます。以上。

各マクロの説明

リセマラ厳選

村の中であればどこからでも開始可能です。
錬金に使用する素材は1ページ目から無差別に放り込んでいく感じなので素材に余裕のある方向けです。
検索条件の設定は勘でなんとかしてください。

マクロの内容
 マカ錬金(幽玄)を50個分セット
  ↓
 闘技ラー10周
  ↓
 護石確認
  ↓
 検索条件に設定した護石があればセーブして最初に戻る、無ければセーブせずリセット
  ↓
 護石を1個分セット
  ↓
 闘技ラー1周
  ↓
 護石確認後セーブしてリセット、最初に戻る

テーブル記録用

ほぼ自分用、普通に遊ぶ分には必要ないかも?
ひたすら錬金して出現したおまもりをcsvに記録していくだけのマクロです。
村の中であればどこからでも開始可能です。

マクロの内容
 マカ錬金(幽玄)を50個分セット
  ↓
 闘技ラー10周
  ↓
 護石確認、シートに記録して最初に戻る

所持おまのシート出力

装備Boxを開き、護石のみでフィルタリングしてから1ページ目の左上にカーソルを合わせてからスタートです。
装備Box内の護石を全て読み込んでcsv出力します。
また、ここで出力されたcsvは泣きシミュの護石インポートにそのまま使用可能です。(2021/05/09時点)



最後に

生成と乱数列の遷移が分かれば多分ツール作るので良い感じの情報があったら起こしてください。

関係ないですがNX2の更新と鯖の再起動しておきました。
NX2で作れるレベルのマクロはこっちに追加する気ないので作った人は適当に共有してあげると喜ぶ人がいると思います。

色違いデオキシスゲット!

簡単で
す!
因みにこれを実行するとセーブデータが消えるので注意
まず初めに 以下の記事の通りにバグポケモン0x085Fをゲットする。
bzl.hatenablog.com
以下の通りにボックス名を変更する。
赤字の「ヘ」「ベ」はカタカナです!

ボックス ボックス名
ボックス1 『 みオむけいオぅ』
ボックス2 『アれめつい l』
ボックス3 『9ぇつい9ぇせも』
ボックス4 『アひか…や l』
ボックス5 『コエエシエねミ』
ボックス6 『アねあぃ l』
ボックス7 『ッやコエエシエ』
ボックス8 『アねミァゆ l』
ボックス9 いクスあぃコエ』
ボックス10 『アエシエ l』
ボックス11 『クオ k』

ボックス名を変えた後にバグポケモン0x085Fの様子を見るとソフトが自動でリセットされる。

再開すると警告文が出ますが無視してください。
ボックスを確認するとレベル1の色違いデオキシスがいます。

結果
デオキシスゲット!

エメラルドID調整の調査記録

サムネは魔除けです。
この記事はPokémon RNG Advent Calendar 2020 6日目の記事です。

エメラルドID調整の手順そのものについては数ヶ月前に上げているので、調査の詳細に興味のある方向けの記事となります。
まあ調査記録といっても当時の記憶の書き起こしだしそこまで厳密には纏めてないけどね。
めんどくさいので画像も特にないです。
すごく読みづらいと思いますが何卒ご容赦下さい。
それと調査にあたってROMHackやマジコンを利用している為、苦手な方はブラウザバック推奨です。

また、筆者は乱数調整にあまり詳しい人間ではないので細かい所で「ん?」と思う所があるかと思いますがどうか生温かい目で見てあげてください。
文句言われてもスルーするので言うだけ無駄です。

概要



ポケットモンスターエメラルド自体は16年程前に発売されたそれなりに古いゲームで、殆どの要素において乱数調整方法が確立されていたが、トレーナーIDの決定に関しては1年くらい前まで調整不可能とされていた。
この記事では、不可能とされていた理由やその後調整できるようになった経緯等について適当に解説する。(正しく解説できる自信はない)

解説



まずはエメラルドのトレーナーID決定処理について。

// 名前入力開始
static void NameInStart(u8 type, u8* buff, u16 work0, u16 work1, u32 work2, pFunc rec_proc)
{

	Namein = (NAME_IN*)AllocMemory(sizeof(NAME_IN));
	if (Namein == NULL){
		MainProcChange(rec_proc);
		return;
	}

	Namein->name_type = type;
	Namein->arg_work0 = work0;
	Namein->arg_work1 = work1;
	Namein->arg_work2 = work2;
	Namein->set_name_buf = buff;
	Namein->rec_proc  = rec_proc;

	// 主人公名の決定時間を乱数のタネとする
	if(type == NAMEIN_HERO)
	{
		RandomTimerStart();
	}


	MainProcChange(InitNameInTask);
}
 
// 名前入力終了
static u8 NameInEnd(void)
{
	if (FadeData.fade_sw == 0){
		// 時間計測終了
		if (Namein->name_type == NAMEIN_HERO)
		{
			RandomTimerEnd();
		}

		MainProcChange(Namein->rec_proc);
		DelTask(CheckTaskNo(NameInMainTask));
		BMPWIN_SysExit();
		MEM_RELEASE(Namein);
	}
	return 0;
}

名前入力画面への遷移時にタイマーを開始し、名前決定後に経過時間をそのままトレーナーIDとして使用するという非常に単純な処理である。
ちなみにこの処理はFRLGでも使用されている。

「入力に掛かった時間がTIDになるならその入力時間を調整すれば任意のトレーナーIDが引けるのでは?」と思うかもしれないがこの「入力時間の調整」がとても難しい。
エメラルドの実行環境であるゲームボーイアドバンスはマルチスレッドに対応していない為、裏で何かしらのタスクを処理したい場合は割り込み処理を利用して実装することが多い。
割り込み処理の実行中はメインタスクの処理が停止するが、その前にセットされたハードウェアタイマーはそのまま動き続ける。
これが「入力時間の調整」を難しくしている原因となる。

この時裏で割り込み処理によって動いている処理とは何か?
BGMの再生処理である。

ゲームボーイアドバンスには先代のゲームボーイが持っていたチャンネルに加えて8bitのPCMが追加されており、サンプリングされた音源をそのまま再生できるようになっている。
これによってソフトウェアによって生成された合成音声を再生し、擬似的に同時発音数を増やすことに成功している。
ちなみにポケットモンスターエメラルドにおいて使用されているサウンドドライバは任天堂純正のMusicPlayer2000である。(Sappyとも呼ばれる。こちらの方が親しみのある名前だろうか?)
この「ソフトウェアによる音声合成」が中々に曲者で、BGMの再生位置によって合成するデータ量が大きく変動する為、処理に要するCPUサイクル数にムラが生じやすい。
ハードウェアタイマーのスタート/ストップの起点となるVBLANK割り込みから当該処理までのステップ数は一定だが、途中で割り込んでくる音声合成処理によって経過時間が変動してしまうのである。
しかし、逆に言えばBGMの再生位置と経過時間の管理によってトレーナーIDの調整が可能である、ということになる。

理論的な説明は以上の通り。後は全て力技で解決します。

ここまで分かったら「BGMの再生位置(OP開始からの経過時間)」と「名前入力画面内での経過時間」を渡してIDを概算できるようにしたい。
今回はハードウェアタイマーのスタート/ストップ処理のそれぞれに対応した「BGMの再生位置」と「処理実行までのクロック数」を紐付けたテーブルを作成する。

まずはタイマーストップ処理用のテーブル作成手順を紹介する。
BGMの再生処理を潰したROMを用意し、1フレームずつ名前入力の経過時間をズラしながら出現するトレーナーIDを確認する。
すると、1フレームにつき18752値が増えていた。
16777216(GBAのCPUクロック数) / 59.7275(リフレッシュレート) = 280896.002....
280896 % 65536 = 18752
なので、計算上でもこの結果はまあまあ正しそう。
後は未改造ROMで取得できたトレーナーIDと比較して音声合成処理によって生じたサイクル数のズレを記録していく。
この時、名前入力画面へ遷移する際のBGMの再生位置は固定するようにする。

次はタイマースタート処理用のテーブル作成手順。
名前入力画面遷移後にBGM再生処理が停止するようHackを施したROMを用意し、名前入力画面へ遷移する際のBGM再生位置を1フレームずつズラしながら出現するトレーナーIDを確認する。
この時、名前入力画面へ遷移した後の経過時間は固定するようにする。
その後、BGMの再生処理を潰したROMで同じ操作を行い、トレーナーIDの差分を取る。
この差分がタイマースタート処理実行までに発生した音声合成処理によるズレとなる。

後は記録した差分を2つ合わせた値と実際の値のズレを基準値とし、[基準値 + タイマースタートのズレ + タイマーストップのズレ = ID]が成り立つようにする。
かなりの荒技になってしまうが、一応これでエメラルドのIDの予測ができるようになった。

最後に



以上がポケットモンスターエメラルドのID調整を行うにあたっての調査内容です。
少し頭のいい方なら「もう少しスマートなやり方あるだろ!アレをソレしてこうして...」とツッコミたくなってしまうと思いますが、突っ込まれた所で基本スルーするつもりなので心の内にしまっておいて頂けると幸いです。

明日はpo氏が何か書くそうです。
当記事執筆時点では「何も考えていません。」とのことですが何が上がってくるんでしょう?
楽しみにしていますね。

【BW/BW2】全28バージョンパラメータ纏め

5世代海外版ROMのパラメータについて、適当に調べてもNazo値くらいしか見つからなかった為、海外版ROMを所持している方々と協力して全28バージョンの具体的なパラメータ調査を行った。なんと私は日本版BWすら持っていません

まずは無印BW。
Nazoはほぼ既出だが、スペインブラックのみ誤った情報が出回っているので注意。

Nazo値計算法:
Nazo1:(Nazo1)
Nazo2:(Nazo1 + 0xFC)
Nazo3:(Nazo1 + 0xFC)
Nazo4:(Nazo1 + 0x148)
Nazo5:(Nazo1 + 0x148)

バージョン名
Nazo1
VCount
Timer0
日本ブラック
0x02215F10
0x60
0xC79~0xC7A
日本ホワイト
0x02215F30
0x5F
0xC67~0xC69
韓国ブラック
0x022167B0
0x60
0xC84~0xC85
韓国ホワイト
0x022167B0
0x60
0xC7B~0xC7C
北米ブラック
0x022160B0
0x60
0xC7B~0xC7C
北米ホワイト
0x022160D0
0x60
0xC7E~0xC80
ドイツブラック
0x02215FF0
0x5F
0xC77~0xC78
ドイツホワイト
0x02216010
0x60
0xC7A~0xC7B
フランスブラック
0x02216030
0x5F
0xC73~0xC74
フランスホワイト
0x02216050
0x5F
0xC6E~0xC6F
スペインブラック
0x02216070
0x60
0xC86~0xC87
スペインホワイト
0x02216070
0x5F
0xC70~0xC71
イタリアブラック
0x02215FB0
0x5F
0xC6A~0xC6B
イタリアホワイト
0x02215FD0
0x60
0xC7B~0xC7C

次はBW2。
こちらもNazoは既出。
VCountズレという新たな概念の存在するバージョンがある為注意。

Nazo値計算法:
Nazo1:(Nazo1)
Nazo2:(Nazo2)
Nazo3:(Nazo3)
Nazo4:(Nazo3 + 0x54)
Nazo5:(Nazo3 + 0x54)

バージョン名
Nazo1
Nazo2
Nazo3
VCount
Timer0
日本ブラック2
0x0209A8DC
0x02039AC9
0x021FF9B0
0x82
0x1102~0x1108
日本ホワイト2
0x0209A8FC
0x02039AF5
0x021FF9D0
0x82
0x10F5~0x10FB
韓国ブラック2
0x0209B60C
0x0203A4D5
0x02200750
0x82
0x10EF~0x10F4
韓国ホワイト2
0x0209B62C
0x0203A501
0x02200770
0x81
0x10E4~0x10E9
北米ブラック2
0x0209AEE8
0x02039DE9
0x02200010
0x82
0x1102~0x1108
北米ホワイト2
0x0209AF28
0x02039E15
0x02200050
0x82
0x10F2~0x10F6
ドイツブラック2
0x0209AE28
0x02039D69
0x021FFF50
0x81~0x82※1
0x10E5~0x10EC※1
ドイツホワイト2
0x0209AE48
0x02039D95
0x021FFF70
0x82
0x10E5~0x10ED
フランスブラック2
0x0209AF08
0x02039DF9
0x02200030
0x82
0x10F4~0x10F8
フランスホワイト2
0x0209AF28
0x02039E25
0x02200050
0x82
0x10EC~0x10F0
スペインブラック2
0x0209AEA8
0x02039DB9
0x021FFFD0
0x82
0x1101~0x1106
スペインホワイト2
0x0209AEC8
0x02039DE5
0x021FFFF0
0x82
0x10EF~0x10F4
イタリアブラック2
0x0209ADE8
0x02039D69
0x021FFF10
0x82~0x83※2
0x1107~0x110D※2
イタリアホワイト2
0x0209AE28
0x02039D95
0x021FFF50
0x82
0x10FF~0x1104
※1 ドイツブラック2
Timer0の値が0x10E5~0x10E8の場合はVCount-0x81、0x10E9~0x10ECの場合はVCount-0x82となる。
※2 イタリアブラック2
Timer0の値が0x1107~0x1109の場合はVCount-0x82、0x1109~0x110Dの場合はVCount-0x83となる。
Timer0-0x1109に限りVCount-0x82とVCount-0x83の両パターンが存在する。

【ポケモンXY】ID調整

事の発端はこちら。
 ↓
sina-poke.hatenablog.com


XYのID調整に成功したので適当に調整手順等を纏めます。
(元々纏める気なかったけど)




疑似乱数周りの仕組み



IDの決定自体はORASと同様にTinyMTが用いられており、初期seedも同様に起動時刻によって決まっている。
但し、OP内でキャラクターオブジェクトのまばたきによる不定消費が発生している為、ORASと同様の手順ではseedの特定が難しい。
ここで使用されているまばたき処理は以下の通り。
(滅茶苦茶単純である)

u32 _counter;

void init()
{
	_counter= 0x021E - ((rand() * 0xB4) >> 0x20) << 0x01);
}

void next()
{
	_counter--;
	if (_counter == 0)
	{
		init();
	}
}

また、名前入力画面に遷移した際の1消費以外にその他消費は行われていない模様。
OP内ではキャラクターの数が変動する箇所があり、これによって時間あたりのおおよその消費速度が変化する。
キャラクター数の変動の仕方は以下の通り。


1人 (博士)
 ↓
2人 (博士,メェークル?)
 ↓
1人 (博士)
 ↓
3人 (博士,男主人公,女主人公)
 ↓
文字入力画面 (まばたき判定停止)
 ↓
3人 (博士,男主人公,女主人公)
 ↓
4人 (博士,男主人公,女主人公,選んだ方の主人公)


また、OPの最後に現れる主人公は名前確定時にまばたきカウンタのリセットを行っているよう。
名前確定→まばたきカウンタリセットまでの空白時間は主人公の性別によって異なっている。


ID調整方法の考察



TinyMTの初期seedはORASと同様に決定されている為、TinyMTを元に生成された値を観測することができれば32bitの総当たりによって初期seedの特定が可能となる。
但し、ID決定までの消費数が不定である都合上ORASと同じ手法は使えない。(使えたとしてもミリ秒ゲー以上の難易度になるが)
ID決定以外の乱数消費には「キャラクターのまばたき処理」があり、これは「まばたきのインターバル」という形で乱数値を使用する。
その為、今回はキャラクターのまばたきの長さを利用して32bitの総当たりを行い、現在seedを求める。
キャラクターが1人である状態なら、「現在seed」と「1人のキャラクターが持つまばたきカウンタの値」の2つを得ることで乱数値の制御が可能となる。
シーンの切り替わりによって新たに登場するキャラクターのまばたき処理についても、前述した2つの値が分かっていれば「シーン切り替わりの契機となる操作タイミング」を管理するだけで制御可能。
その為、今回の乱数調整では「キャラクターが1人である状態からまばたきのインターバルを複数記録して現在seedを特定した後、3DSの操作タイミングを管理することによって後に現れるキャラクターのまばたき処理を全て制御する」といった形でOP中の乱数消費を再現する。

キャラクターのまばたきのインターバルは最長542F(約9秒)、最短でも184F(約3秒)である為、時間あたりの消費速度はかなり遅めである。
また、まばたき以外の不定消費が存在していない為、消費速度を踏まえると操作精度が余程低くない限りは消費数がズレる可能性は低い。

調整にあたっての理論的な説明っぽいのは以上の通り。
これらの作業を簡潔に行う為のツールを作成したので使い方を適当に紹介する。
DL:https://bzl.hatenablog.com/entry/2090/11/11/000000#6genTidSearch


基準seedの特定



o3DSではラグの影響で消費の進む速度に若干の遅れが生じるようです。
このツールはラグの考慮を一切行っていない為、極力n3DSを使用して乱数調整を行うことを推奨します。

OP開始後、この画面まで進めておく。

6genTidSearchを起動し、[XY]→[基準seed検索]タブを開く。
初回は『全範囲探索』を選択し、その後OP内のプラターヌのまばたきに合わせて『瞬き』ボタンを押してまばたきの空白時間を記録する。
(数分間見つめ合ってるとちょっとロマンチックな雰囲気になってくる)
まばたきの空白時間を10個程記録したら検索を開始する。
2回目以降の検索を行う際は『基準seedから探索』を選択し、前回特定した初期seedを入力する。

seedが見つかった後、セルをダブルクリック又は『seedを選択』を押しておく。


目的のIDの検索



ID検索タブを開き、許容する消費数と目標IDを入力して検索を開始する。
ここで目標のIDが見つからなかった場合はリセットし、再度seedを特定する。
(複数候補の検索したかったら3DSRNGTool使ってね)


まばたきズレの補正



目標IDが出現するseedであった場合は消費数管理タブを開く。
『瞬き調整』内の開始ボタンを押すとプラターヌの瞬きに合わせて音が鳴るようになる。
但し、目視でまばたきを観測している都合上、実際のまばたきタイミングとはズレが生じている。
ここではその誤差の補正を行っていく。
基本的にはプラターヌのまばたきより遅く音が鳴っている為、『早める』を押してズレを縮めていく形となる。
プラターヌのまばたきと鳴る音のタイミングが一致したらこの手順は終了。


まばたき消費制御



ツール内で主人公の性別を選択する。
その後、以下のシーンでAボタンを押すのと同時に『ステップ(F9)』を押して消費の制御を行っていく。
また、名前確定時を待機フレームの始点としている為、CCTimerを使用している場合はF9キーを使用することを推奨する。


>> 主人公の性別選択

>> 名前入力画面

>> 名前決定

>> 名前確定



操作終了後はこの画面で待機を行う。

消費範囲を指定後、『計算』を押してリスト出力を行う。
ハイライト部分は「現段階でAボタンを押すと引くことのできるID」となっている。

出力されたフレーム数に合わせて待機を行い、出現したIDを確認する。
目標のIDが無事に引けていれば成功。


あとがき



XYの方は特に纏める予定はなかったのですが、任せられてしまったのでこちらも書くことにしました。
以前纏めたORASと比較すると手順は若干ややこしいものの、狙ったIDを引きやすいのでNN目的でID調整を行う方はこちらの方が都合良いかもしれませんね。
これを応用するとフィールド上でTinyMTのseedが特定できるようですが使い道がよく分からない...