Lapis & Lazuli

ゆきれいむぅのにっき

ポケモン改造:配布限定ポケモンを入手可能にしよう!

さいはてのことうでのイベント

こんにちは。ポケモン改造第3弾です。

これまでの記事も良かったら読んでね。

今回は、配布限定アイテムの入手方法の拡張にチャレンジしました。

第3世代はなかなかカオスで、ゲーム外の要素と連携してポケモンやアイテムを入手できるものが多かったです。ゲームキューブのポケモンシリーズ(ポケモンボックス、ポケモンコロシアム、ポケモンXD)や、ポケモンバトルカードe+、そしてイベント配布などですね。

厄介なことに上記の手段無しでは入手できない限定ポケモン(例:幻ポケモン)や限定アイテム(例:チイラ系統のきのみ)も多く、令和の時代に新しく第3世代のポケモンをやりこみ始めても、なんとなくそういったところでモヤモヤしてしまうことも多いのでは?と思います。全国図鑑を埋めたいときとか、強いポロックを作りたいときとかは特に。

エミュレータでプレイする分には、困った時はPAR(改造コード)等を解禁してポケモンやらアイテムやらを無理やり入手してしまえばいいんですけど、それはなんか味気ないので、ゲームの中に入手手段を用意してあげようというのが今回の目的になります。また、改造コードはエミュレータや環境によっては動かなかったりするので、これもモチベーションが湧く理由の一つになりますね。(「いやいや、そもそもROMの改造も味気ないだろ!」という意見は今回は聞かなかったことにします。)

 

というわけで、今回のターゲットとなる配布限定ポケモン&アイテムをリストアップ!

  1. 「むげんのチケット」「みなみのことう」に行ける。ラティオスorラティアスを入手可能
    • 2003年頃のワールドホビーフェアで抽選で配布された。その後も数回ほど各地のポケモンセンターで配布イベントが開催された。直接「むげんのチケット」を入手したソフトは、レコードを混ぜることによって最大100人分だけ他のソフトに配信することができた。
    • ルビー・サファイア向けの配布だった。
  2. 「オーロラチケット」「たんじょうのしま」に行ける。デオキシスを入手可能
    • 2004年に公開された映画「劇場版ポケットモンスター アドバンスジェネレーション 裂空の訪問者 デオキシス」の映画前売り券を購入するとついてくる「オーロラチケット引換券」を持って各地のポケモンセンターやショッピング施設等に行くと交換できた。
    • エメラルド発売前に開催されたイベントで、入手できたのはファイアレッド・リーフグリーンのソフトに限られた。
  3. 「しんぴのチケット」「へそのいわ」に行ける。ルギアホウオウを入手可能
    • 2004年頃に各地のポケットモンスターやジョイスポット等で配布された。
    • ファイアレッド・リーフグリーン・エメラルド向けに配布された。
  4. 「ふるびたかいず」「さいはてのことう」に行ける。ミュウを入手可能
    • 2005年に開催されたポケモンフェスタで入手できた。愛知万博と同時開演した Pokémon The Park 2005 でも入手できたとか。
    • ちなみに、2005年に公開された映画「劇場版ポケットモンスター アドバンスジェネレーション ミュウと波導の勇者 ルカリオ」の映画前売り券を購入するとついてきたのは、ただのミュウ引換券であり、ふるびたかいずの引換券ではない。

私も当時「しんぴのチケット」と「ふるびたかいず」については実際に現地に足を運んで入手したこともあり思い出深いです。親の説得もなかなか大変でしたが、当日の大混雑と長蛇の列でかなりハードな1日を過ごしたものです。

さて、これらのアイテムを入手するだけなら、改造コードさえ解禁してしまえばそう難しくはありません。例えば以下のX-TAコードを使用すれば、コトキタウン以外のショップで好きなアイテムを購入できるようになります。

コトキタウン以外のショップで購入できるアイテムを変更(X-TA)

83005B9A XXXX

  • XXXX にはアイテムコード(16進数表記)をそのまま入れる。
  • 例:ふるびたかいずのアイテムコードは「0178」なのでX-TAコードは「83005B9A 0178」。PARコードに変換すると「FA9AF79E C094A769」らしい。

「ふるびたかいず」を不正に入手...!!

しかし残念ながら、無理やりこれらのチケット系アイテムを入手したとしても、船着き場でのイベントが発生せず、特別なエリアに入場することはできない仕様になっています。

どうして・・・

その理由は、船着き場でのイベント発生には「チケットを所持しているか?」という条件だけでなく、実は2つ目の「イベント開始フラグがセットされているか?」という条件が必要だからです。この2つ目の条件となるフラグは、正規の手段では「配達員からアイテムを受け取るとき」にセットされます。(配達員は確か、ふしぎなおくりもの等を受け取った際にポケモンセンターの2階に出現したはずです。)

このイベント開始フラグをセットするのは、改造コードを使う手段では実現が難しく、どうしてもという場合には苦肉の策で直接該当のマップにワープできるようなものを使用することになると思います。一部の限定イベントを見ることができなくなるので、不完全燃焼な感じになります。

マップ移動先を「さいはてのことう」に変更(PAR)

C88758CA B308BAA7

最近では「ザロクバグ」を使用して任意コード実行が行う方法も確立されています。準備こそ大変ですが、こちらはアイテムの準備とフラグの設定を両立できるので、ニーズを完全に満足させることができます。(が、準備の過程でボックスが非常に汚いことになります…最悪...)

 

背景ごとを説明し終えたところで、今回の目的を改めて説明しましょう。それは「エメラルドのゲーム内でこれらの限定チケットアイテムを入手できる手段を設けること」です。ROM改造という手段を用いることになりますが、ゲームプレイ中は改造コードの力を頼ることなくアイテムを入手できて、限定イベントも見れる!たのしい!という状態を目指します。より快適に楽しく遊べる(※個人の感想です)エメラルドに改造仕上げることが私の長い長い目標になります。

(ちなみに、ROM改造による新イベントの定義と任意コード実行は、独自に定義できるイベントスクリプトを実行して処理するという点で、どちらもやってることはあんまり変わらないかもしれません。)

必要なツール

はじめに、今回の作業で使用するソフトウェア・ツール等を紹介しておきます。

  1. Stirling
    • バイナリエディタになります。最強アイテムです。
  2. Advance Map
    • ワールドマップの編集・作成、イベントの割り当て、野生のポケモンの設定等ができるツールです。バージョンは個人的には「v1.82」がオススメです。
  3. PokeDataChanger
    • 主にゲーム内のテキスト/セリフデータを変更・作成するためのツールです。今回は新しく作成するアイテム入手イベントで表示するメッセージを作成するのに使います。

Step1: 解析

まず先に解析結果をぺたり。

  ID フラグ1 フラグ2 正規イベントのオフセット
むげんのチケット 0x0113 0x8B3 - 0x08246842
オーロラチケット 0x0173 0x13A 0x8D5 0x085FD0D4
しんぴのチケット 0x0172 0x13B 0x8E0 0x085FD21C
ふるびたかいず 0x0178 0x13C 0x8D6 0x085FD3FF

フラグ変数のむげんのチケット以外はフラグを2箇所設定する必要があります。エメラルドの場合フラグ変数は2,000個以上あって、2バイトの値でフラグの位置を指定します。例えばフラグ「8B3」は、フラグ変数の2,227番目のビットの値を指しています。

正規イベントのオフセットには、正規に配達員から各チケットを入手する際のイベントスクリプトのアドレスが書かれています。このイベントスクリプトを解析することで実際にセットされるフラグの位置を特定することができました。

デモンストレーションとして、オーロラチケットを例に取って実際にスクリプトを解析してみましょう。バイナリエディタ(Stirling)でROMを開き、アドレス「0x5FD0D4」にジャンプします。(0x08~はROMアドレスの意味)ジャンプした位置からイベントスクリプトの終端を意味する「02」までをデータ列として抽出してみましょう。

1A 00 80 73 01 1A 01 80 01 00 09 00 29 D5 08 29 3A 01 BD 4B D1 5F 08 66 6D 6C 02

これがオーロラチケットをくれる配達員のイベントスクリプトです。詳しくない人には「そもそもイベントスクリプトってなんやねん」って感じだと思いますが、簡単には「メッセージを表示して、アイテムをくれる処理をして、会話を終了する」みたいにイベントの内容が定義されているものだと思ってください。実際に解析された結果を見てみるとよりイメージしやすくなると思います。

オーロラチケットを受け取るイベントのスクリプト解析結果

1A 00 80 [73 01] 1A 01 80 [01 00] 09 00 :オーロラチケットをもらう処理
29 [D5 08] :フラグをセット(たんじょうのしまに行ける)
29 [3A 01] :フラグをセット(チケットを受け取った)
BD [4B D1 5F 08]:【ふしぎなおくりもの用】virtualmsgbox/仮想オフセット用メッセージ表示

  (0x085FD14Bに格納されているメッセージ)
   ミナモシティの ふなつきば で\n
   つかえる ようですね\p
   ぜひ ごりよう してみては\n
   いかがでしょうか?終
66:メッセージウェイト
6D:ボタンを押すまでウェイト
6C:ロック解除
02:スクリプトの終了

解説

【イベントスクリプトテンプレート】アイテム入手「1A 00 80 [v1 v1] 1A 01 80 [v2 v2] 09」に該当。これはアイテムコード [v1 v1] (リトルエンディアン)のものを [v2 v2] 個入手する処理。

後ろに「00」がある場合はアイテム入手処理完了後にそのまま後続の処理へと進む。

(→オーロラチケット0x0173を0x0001個入手する)

②③

【イベントスクリプト】setflag/フラグをON「29 [va va]」に該当。フラグ [va va] をONにします。

(→フラグ0x08D5とフラグ0x013AをONに)

【イベントスクリプト】ふしぎなおくりもの用 virtualcallif/条件付き仮想オフセット呼び出し「BD [vp vp vp vp]」に該当。[vp vp vp vp]は表示するメッセージが格納されたオフセット。かなり特殊な呼び出しだが、いつもとちょっと違ったウィンドウでメッセージを表示できる機能というイメージでOK。

(→実際に 0x085FD14B に格納されているメッセージをデコードすると上記の通りになる。)

⑤~⑧

これはお約束の締め方みたいなもの。スクリプトを自作する際には内容の理解が必須。

イベントスクリプトの解析には、改造ポケモン制作資料Wikiに記載されている情報が非常に参考になります。

イベントスクリプト - 改造ポケモン制作資料 Wiki*

イベントスクリプトテンプレート - 改造ポケモン制作資料 Wiki*

作戦

解析結果を元に、目的を実現するための道のり(作戦)を考えましょう。

まず、具体的なアイテム入手方法についてですが、これは「NPCからアイテムを受け取る」というのが一番考えやすいアプローチになると思います。要するにイベントの発火方法を決めるってことになるんですけど、特定のタイミング(例:殿堂入り後)とか、特定のマップ入場時(例えば船着き場に入ったとき)とかにすることもできなくはないと思うけど、そこまでする必要はないと思うので、シンプルに「NPCに話しかけたらアイテムがもらえる」という方向性で実現することにしましょう。

そうしたら次は「NPCをどの場所に配置するか」という問題になります。既存のNPCのイベントを置き換えるということもできますが、せっかくなので今回は「新しいNPCを配置して新しいイベントを定義する」という方向性でやってみましょう。新規のNPCを配置する場所ですが、なんとなくミナモシティの船着き場がいいかなと思ったのでそこにしました。もうちょっとミステリアスな場所でもいいんだけど、良いところが思いつかなくて。。

NPCが配置できたら、あとはそのNPC用のイベントスクリプトを作成するだけになります。「それっぽいメッセージを表示しつつ、各チケットがもらえて、必要なフラグもセットされる」、そんなイベントスクリプトを頑張って作ってましょう!

実装手順
  1. 新しいNPCを配置する
  2. イベントスクリプトを作成して、1. で配置したNPCにイベントを割り当てる

Step 1: 新しいNPCを配置する

Advance Map でROMを開きます。

今回はミナモシティの船着き場にNPCを配置したいので、同マップが格納されているBank13の10番目のマップを開きます。

ミナモシティ ふなつきば (13, 10)

今回はNPCの設定をしたいので「イベントの設定」タブを開きます。まずはNPCの数を増やしたいので、赤枠で囲っている部分を操作してNPCの数を変更してみましょう。「人の数」を 5 → 6 に変更して「設定」をクリック!

ふなつきばのイベント設定

そうしたらこのようなダイアログウィンドウが出てくると思います。これはNPCの数を増やすにあたり、新しいデータ領域を確保する必要があるためです。このダイアログでイベントテーブルの引っ越し先(の先頭アドレス)を探してあげる必要があります。

Q. 詳しく

A. イベントテーブルのデータ量が拡大→ そのままデータを末尾に追加してテーブルを拡張しようにも、普通その後ろはすでに別のデータが詰まっている(隣のマップのイベントとか) → 別の空いている領域にテーブルを丸ごと引っ越しで後ろにデータを追加+元のデータテーブルのポインタを参照している箇所を移動先のオフセットに変更(前記事の技拡張と同じ流れ)

イベントテーブルの作成ダイアログ

これはまあよくある空き領域(「00」とか「FF」が並んでいる部分)を検索する機能ですが、データを入れる位置を自動で見つけてもらうより、バイナリエディタ等で自分でROMを観察して配置場所を決めておくのが個人的にはオススメです。ここを自動的にやってしまうと、メモし忘れて後でどこにテーブルが移動したのか分からなくなることもあるからね。

今回私は「0x08FF1F40」にテーブルを移動することにしました。私は空き領域をROMの後ろの方から前に遡る形で埋めていっているので、その流れでこの位置になりました。この位置を指定できるように、以下のように値を入力して、無理やり検索させます。

前もって決めていたアドレスを無理やり見つけさせる

決めていたアドレスが見つかったら選んで「Re-Point」をクリック!新規にNPCが1人追加されます。右メニュー一番上のプルダウンで「人」を選択して、イベント番号「5」(6人目)を指定してみましょう。今回追加されたNPCの情報が表示されると思います。

新規のNPC - 設定前

当然このままではいけないので、NPCの情報を設定していきましょう。イベントスクリプトの位置をこのタイミングで指定する必要があるので、場所だけ決めておきます。私は「0x08FF1E30」に設定しました。

  • 人No: マップ内で一意である必要があるので「6」に設定します。
  • 画像No: NPCの種類を決められます。「0」のままだと男主人公のグラフィックになってしまうので、お好みの姿に変更してしまいましょう。画像Noと実際の姿の対応表はまだ用意できていないので、好きな姿を決める→その姿のNPCがいるマップを開き、画像Noを調べる、という様に探すのが効率的です。「28」に設定するとバトルチューブにいるメイドNPCの見た目になります。
  • 座標: NPCの位置を決めます。16進数で座標を設定します。左上のマップタイルが (0x00, 0x00)。今回は (0x08, 0x0A) に設定。
  • オフセット: ここでイベントスクリプトの先頭アドレスを指定します。「FF1E30」を入力します。
  • その他のパラメータ: ぶっちゃけまだ良く分かっていません…色々入れてみて遊んでみましょう

新規のNPC - 設定後

ここまでできたら、動作確認用に簡単なイベントスクリプトをセットしてみましょう。

Advance MapでROMを保存後、バイナリエディタでROMを開き、スクリプトのオフセットに指定したアドレスに飛びます。(ここでは「0x08FF1E30」)

試しに「0F 00 D7 51 26 08 09 02」と入れてみましょう。これは非常に簡単なイベントスクリプトテンプレートで、指定オフセット(→0x082651D7)に定義されたメッセージを表示してくれます。バイナリエディタで保存後、ゲームを起動して新しく配置したNPCに話しかければ、特徴的な声で叫んでくれると思います。

動作確認

これで新規NPCの追加は完了です。

Step 2: イベントスクリプトの作成

さて、難しいですがイベントスクリプトの作成に挑戦してみましょう。

その前にまず、イベントの流れを想像して言葉にして書いてみましょう。

  • 1. メッセージを表示する。(チケットいりますか?的なメッセージ)
  • 2. 「はい」「いいえ」の選択肢を作成
  • 3-A.(「はい」を選択した場合)メッセージを表示する。(どうぞ。的なメッセージ)
  • 4-A. 各チケットを渡す&必要なフラグをセットする。
  • 5-A. 締めのメッセージを表示する。(そこで使えますよ。的なメッセージ)
  • 3-B.(「いいえ」を選択した場合)メッセージを表示する。(いらないの?的なメッセージ)

大体こんな感じでしょうか...

それと、既にチケットをもらっている場合は、チケットを貰わないようにする必要がありますね。そうなると、上記の流れを覆う形で

  • 1. チケットを配る必要があるか判定する
  • 2-A. (チケットを持っていない場合)上記処理に進む。
  • 2-B. (チケットを持っている場合)メッセージを表示する。(そこで使えますよ。的なメッセージ)

という感じにできそうですね。

ここまで決めたら次は表示するメッセージを考えましょう。ちょっと恥ずかしいですが、メイドっぽい話し方も意識しつつ私は以下のように作ってみました。(ChatGPT先生と一緒に考えました。)PokeDataChangerでセリフをエンコードしたら、ROM内空き領域の好きな場所に書き込みます。

セリフ① チケットを持っていない場合のセリフ
とつぜん ですが……\p
めずらしい ばしょ まで\n
つれていって もらえる チケット\m
ほしい ですか……?終
14 12 3f 2e 00 44 0d 37 b0 b0 fb 22 3e 27 0c 02 
00 46 0c 36 00 1f 44 fe 3b 01 2e 15 02 00 44 07 
29 00 61 59 a0 64 fa 1e 0c 08 00 01 28 1f 0e 2e 
06 b0 b0 ac ff

セリフ② 「いいえ」を選んだあと
そう ですか……終
0f 03 00 44 0d 06 b0 b0 ff

セリフ③ 「はい」を選んだあと
でしたら これを……終
44 0c 10 27 00 0a 2a 2d b0 b0 ff

セリフ④ チケットをもらったあとorチケットを既に持っている
どうぞ おたのしみ ください……終
45 03 40 00 05 10 19 0c 20 00 08 41 0b 02 b0 b0 ff

セリフのエンコードには PokeDataChanger を使用

最後に上記のイベントの流れを実現するスクリプトを作成します。手元にメモ書きが残っているので共有しますね。

完成したスクリプト(変数埋め込み前)

Script

------------------------------------------------------------

5A                          

└ プレイヤーの方向を向く

2B [3C 01] 06              

└ フラグを見て処理を分岐(手抜きポイント:ふるびたかいずの受け取りフラグだけ確認してる)

01 [X0 X0 X0 X0]            

└ フラグがONの場合は指定オフセットのスクリプト実行

0F 00 [M1 M1 M1 M1] 09      

└ メッセージ表示

05 21 0D 80                

└ はい/いいえの選択肢で分岐

01                          

└ はいを選択した場合に①の分岐へ、いいえは②

00 06 01 [X1 X1 X1 X1]      

└ 分岐①のスクリプトのオフセット

0F 00 [M2 M2 M2 M2] 09 02  

└ 分岐②:いいえのメッセージ表示

 

Script:X1(各種チケットをもらう処理)

------------------------------------------------------------

0F 00 [M3 M3 M3 M3] 09    

└ 分岐①:はいのメッセージ表示

04                        

└ メッセージの表示完了後に後続のスクリプト実行

1A 00 80 [13 01] 1A 01 80 [01 00] 09 00    

└ むげんのチケットをもらう

29 [B3 08]                  

└ フラグをセット(みなみのことうにいける)

1A 00 80 [72 01] 1A 01 80 [01 00] 09 00        

└ しんぴのチケットをもらう

29 [E0 08]                    

└ フラグをセット(へそのいわに行ける)

29 [3B 01]                    

└ フラグをセット(チケットを受け取った)

1A 00 80 [73 01] 1A 01 80 [01 00] 09 00    

└ オーロラチケットをもらう

29 [D5 08]                    

└ フラグをセット(たんじょうのしまに行ける)

29 [3A 01]                    

└ フラグをセット(チケットを受け取った)

1A 00 80 [78 01] 1A 01 80 [01 00] 09 00        

└ ふるびたかいずをもらう

29 [D6 08]                    

└ フラグをセット(さいはてのことうに行ける)

29 [3C 01]                    

└ フラグをセット(チケットを受け取った)

0F 00 [M4 M4 M4 M4] 09      

└ メッセージ表示

04 6C 02                    

└ クロージング

 

Script:X0(すでにチケットをもらっている場合の処理)

------------------------------------------------------------

0F 00 [M4 M4 M4 M4] 09 02  

└ メッセージ表示

あとはこのスクリプトをバイナリエディタを使用して地道に入力するだけです。このスクリプトは実際には3つのスクリプトから構成されていて、1つ目のスクリプトが条件に応じて2,3個目のスクリプトを呼び出すという作りになっています。

セリフ用のオフセット(M1~M4)やスクリプトのオフセット(X0~X1)は、どこにデータを格納するかによって個人差が出ると思うので、後は皆さんの方で頑張ってみてください。

完成したものがこちら... (NPCの位置が上の説明と少しズレています)

おまけ(2025/10/14 追記)

固定シンボル復活 NPC用スクリプト

全ての固定シンボルの伝説ポケモンを復活させます。グラードンとカイオーガは異常気象イベントごと復活します。徘徊枠のラティオスorラティアスは復活しません。

上記と同様の手順でNPCを作成し、以下のスクリプトを当ててください。表示するメッセージは自力で頑張ってください。

Script

------------------------------------------------------------

0F 00 [M1 M1 M1 M1] 09

└ メッセージ表示

05 21 0D 80

└ はい/いいえの選択肢で分岐

01

└ はいを選択した場合に①の分岐へ、いいえは②

00 06 01 [X1 X1 X1 X1]

└ 分岐①のスクリプトのオフセット

0F 00 [M2 M2 M2 M2] 09 02

└ 分岐②:いいえのメッセージ表示

Script: X1

------------------------------------------------------------

0F 00 [M3 M3 M3 M3] 09

└ 分岐①:はいのメッセージ表示

04

└ メッセージの表示完了後に後続のスクリプト実行

2A 91 00

2A 92 00

2A AD 01

2A BB 01

2A BC 01

2A BD 01

2A BE 01

2A BF 01

2A C0 01

2A C9 01

2A CA 01

└ 各種フラグをオフに(全固定シンボルの捕獲フラグを折っています)

6C 02

└ クロージング

みなみのことう ラティオス/ラティアス変更 NPC用スクリプト

みなみのことうに出現するポケモンを切り替えます。実行するたびにもう一方にすぐに変更されます。徘徊中のポケモンには影響はありません。

これも同様の手順でNPCを作成し、以下のスクリプトを当ててください。

Script

------------------------------------------------------------

0F 00 [M1 M1 M1 M1] 09

└ メッセージ表示

05 21 0D 80

└ はい/いいえの選択肢で分岐

01

└ はいを選択した場合に①の分岐へ、いいえは②

00 06 01 [X1 X1 X1 X1]

└ 分岐①のスクリプトのオフセット

0F 00 [M2 M2 M2 M2] 09 02

└ 分岐②:いいえのメッセージ表示

Script: X1

------------------------------------------------------------

0F 00 [M3 M3 M3 M3] 09

└ 分岐①:はいのメッセージ表示

04

└ メッセージの表示完了後に後続のスクリプト実行

21 [d5 40] [00 00] 06

└ イベント変数を比較

01 [X2 X2 X2 X2]

└ ラティオスを徘徊する方に選択している場合はオフセット先を実行

16 [d5 40] [00 00]

└ ラティアスを徘徊する方に選択していた場合はラティオスに

6C 02

└ クロージング

Script: X2

------------------------------------------------------------

16 [d5 40] [01 00]

└ ラティオスを徘徊する方に選択していた場合はラティアスに

6C 02

└ クロージング

パッチ配布

ミナモの船着き場にチケット配布NPC追加.ips

使用領域:$FF1E30-$FF1FFF

レポート課題

  • 内容:本日の講義内容を踏まえ、NPCからチケットを入手できる条件に「殿堂入り済みである」という条件を追加したスクリプトを自作し、実行結果をまとめたレポートを提出せよ。
  • 提出物:スクリプトの構成が分かるもの(16進数表記、上記スクリプトメモ参考)、レポート(PDF1-2頁)
  • 〆切:【YYYY/MM/DD 23:59】
  • 注意:他者作品の流用・無断転載は不可。生成AI使用は出力箇所を明記。