[NES] Prince of Persiaのレベルエディタを作成しています。 第2章 花束とキャンディー期間

第1章第2章第3 第4 第5章エピローグ



免責事項


ユーティリティが私のために撮ったスクリーンショットを画像エディタで見ると(フォルダ内の画像を切り替えるのは非常に便利でした)、目覚まし時計から目が覚めました。 次のスクリーンショットは、モニター画面に表示されていました。これは、合計の最初の3分の1のリストにありました。 質問は他の方法で解決する必要がありました。



同じ日の夕方に...





瓶の中を見る。 メソッド番号2。


メモリ内の16進データセットを見るとき(上記のように、最初の2 kBのデータを見るだけで十分です)-私たちにとって重要なものを「見る」ことが重要です。 しかし、どれですか?

次の明白な仮定を採用します。



部屋やレベルのデータをどのように保存できるかを確実に言うことはできません。 繰り返しますが、構造は非常に単純であると仮定できます。

これらの仮定に基づいて、見つける必要があるものを想像してみましょう。

  1. データは、部屋またはレベル間の遷移の瞬間(画面が黒の場合)にROMファイルから読み取られます。
  2. データは、表示されたときにタイルのブロックに変換するために、小さな部分(1バイトも可能)で読み取られます。




そのため、レベルの部屋またはシリアル番号が変更されたときに検索します。 私たちがまだ知らない別の部屋に移動すると何が変わります。 したがって、レベル番号が保存されているセルを探します。



検索方法 FCEUXDSPでRAMフィルターを使用できますが、目で見ることもできます。 私は間違いなく何を探すべきか推測できなかったので、2番目の方法に頼りました。



これらのオプションを使用するか、状態を保存(状態を保存)して、次のレベルに進む前にもう一度見てください。 そして何度も。 率直に言って、これは運の方法です。 運が悪い場合は、RAMフィルターを適用してください。



ワシの視力の発達


ゲームを開始し、レベルを終了するために実行し、状態を保存(状態を保存)し、[ツール]-> [Hexエディター]を開いて...

私はすぐに「ぴくぴくする」バイトをスキップしました。 約80ドルから、主人公のスプライトの現在の画像が明らかに保存されます。 そして、残りは原則として目に見える。 1回目から2回目、そして2回目から3回目までの2、3回のパスの後、ワシの目は70ドルのセルをキャッチしました。



最初のレベルを開始します。 セルには実際に0があり、それを1つずつ変更して、最初の部屋から次の部屋に下がっています。 しかし、それは何ですか? 下の部屋に入ると、奈落の底に落ちます。それはすでに第2レベルの終わりにあります! 王子がcrash落した後、ゲームはスタートを押すように求めます。 そこから始めたかのように、私たちはプッシュして第2レベルの先頭に到達します。



ほとんどの場合、これです。 このすべてで私たちを混乱させているのは、ゲームを開始したときに、9番のセルがこのセルにあるということです。 後で、これは実際にそうであることが判明しましたが、今のところは、レベルを構築するレンガを見つける必要があります。



缶切りで缶を開けます。 メソッド番号1


このプロセスをゲームプロセスに適用せずにコードシートを学習するのはまだ楽しいので、この方法を純粋な形で考えることはしません。 いずれにせよ、バックグラウンドメロディの再現、スプライトのレンダリング、およびその他の公式の手順については、さまざまな手順に逆らうことになりますが、現在はほとんど関心がありません。 必要な手順は1つだけです(今のところ)。



デバッガーを開き([ツール]-> [デバッガー])、ブレークポイントを追加します。

今では、それを置くことができる特定のアドレスはありませんが、デバッガーは特定のアドレスだけでなくブレークポイントを設定する機会を与えてくれます。 特に、メモリセル(またはセルの範囲)が変更されたときに停止させることができます。

[追加]をクリックしてポイントを追加します。 ウィンドウにアドレス「70」を示します。このセルへの書き込みに関心があることに注意してください。 また、CPUメモリに関心があることも示しています。 どういうわけか、[名前]フィールドでポイントに名前を付けて待機します。



実際、スタートルームから最初のレベルに移動すると、ゲームがフリーズし、デバッガーに転送されます。

$D0E6:A2 00 LDX #$00 $D0E8:86 15 STX $0015 = #$00 $D0EA:8E 35 07 STX $0735 = #$00 $D0ED:86 70 STX $0070 = #$09 ;;; <<<<<< $D0EF:8E 01 20 STX $2001 = #$18 $D0F2:CA DEX $D0F3:9A TXS
      
      







率直に言って、有用な情報はまったくありません。 ここで、変数の一部と...スタックのゼロ化を確認できます。 DEXの後、Xには#FFがあり、これはスタックレジスタに配置されます。これは、スタックが最大サイズになったことを意味し、そこには何もありません。 ここには情報がないため、このポイントを参照ポイントとして使用できます。 この瞬間から、トレースロガーに移動して[開始]をクリックし、最初のレベルの最初の部屋が画面に表示されるまで待ちます。 さらに、ブレークポイントを切り替えて、セル$ 70から読み取ることができます。 トレーサーのデータを読み取りながら、セルにアクセスしている場所を確認します。



[編集]をクリックし、チェックマークを[書き込み]から[読み取り]に移動します。



コンテンツを知る


最初のヒットは私たちをここに導くでしょう:

 $CB2E:A6 70 LDX $0070 = #$00 ;;; <<<<<< $CB30:BD F5 EA LDA $EAF5,X @ $EAF9 = #$01 $CB33:8D BB 04 STA $04BB = #$00
      
      





レベルのシーケンス番号は、バイトが抽出されてセル$ 04BBに配置されるデータの配列のインデックスとして使用されることがわかります。 ここで、記憶がどのように構成され、マッパーがどのように機能するかを思い出してください。



最後のバンクは$ C000- $ FFFFのアドレスに配置されますが、残りは前の16 kBのRAM、つまり$ 8000から$ BFFFに動的に配置されます。 このメモリは変更できず、ROMファイルから取得されます。 したがって、$ 8000〜$ FFFFのアドレスを持つセルからの読み取りは、ROMファイルから直接読み取ると見なすことができます。 オフセットROMファイル内のAPのアドレスを変換する必要がない限り。 どうやってやるの?



算術


アドレス$ C000- $ FFFFに到達した場合、すべてが非常に簡単です。 これらのアドレスには、ROMファイルの最後のバンクがあります。つまり、その中の最後の16 kBです。 計算してみましょう:16(ヘッダーサイズ)+ 8(バンクの数)* 16 kB(1バンクのサイズ)= 131088バイト。これはソースファイルのサイズに正確に対応しています。 銀行のオフセットを考慮します。

$EAF5-$C000=0x2AF5





ファイルでは、銀行はオフセットで始まります:

131088 - 16 = 114704 = 0x1C010





今、非常に簡単です:

0x1C010+0x2AF5=0x1EB05





これらの計算をすべて通過するために、違いを見つけます。

0x1EB05-0xEAF5=0x10010





将来、メモリ内のアドレスをファイル内のオフセットに変換する必要がある場合(これはアドレス$ C000- $ FFFFに対してのみ行うことができます)、単純に0x10010を追加し、そうでない場合はそれを減算します。

他の銀行では、もう少し難しくなります。



ヒット!


そのため、16進エディターを開き、オフセット0x1EB05に移動して以下を確認します。

00 00 00 01 01 01 00 00 00 01 01 00 00 01 03 12 14 ...





明らかに、最後の(ここにリストされているものの)3バイトは、ゼロと1のシーケンスからノックアウトされます。 これは偶然かもしれませんが、そうではないかもしれません。 ノックアウトされたものを破棄し、残りのゼロと1をカウントします。

正確に14です。レベルも14です。実行が停止したコードを見ると、レベル番号はこのシーケンスのインデックスであることがわかります。つまり、すべての0または1がレベル全体の典型的なものを担当しています。 。

ゼロを1に、またはその逆に変更しようとすることができます。 個人的に、このシーケンスを見たとき、私はすぐに、第1レベルから第3レベルにダンジョンがあり、第4から第6レベルに宮殿があることを思い出しました。 はい、これはレベルの外観です!

最初のゼロを1からスイングして、エミュレーターを開始します。



確かに宮殿ですが、疑わしいようです。 地下宮殿の一種。

したがって、左官は見つかりましたが、画家と建築者は見つかりませんでした。 どうやら、ダンジョンを宮殿に変えるには、ゼロを1に変更するだけでは不十分です。



さらに掘ります。 実行をクリックします...

 $C0D5:A5 70 LDA $0070 = #$00 ;;    A   $C0D7:0A ASL ;;     $C0D8:AA TAX ;;     (!)  $C0D9:60 RTS ;; .
      
      





ここではそれほど単純ではありません。 インデックスレジスタに、ダブルレベルの数値を入れて(インデックスが作成されたら、再び何らかの配列に入ります)、終了します。 さらに進めます。

 $C0DD:BD 56 EB LDA $EB56,X @ $EB56 = #$30 $C0E0:85 6D STA $006D = #$1C $C0E2:BD 57 EB LDA $EB57,X @ $EB57 = #$83 $C0E5:85 6E STA $006E = #$30 $C0E7:60 RTS
      
      





繰り返しになりますが、最後の銀行の住所で何かを読み、$ 6D:$ 6Eで入金します。 エディターに再び入ります( 0xEB56+0x10010=0x1EB66



):

D9 82 61 86 91 89 F1 8C ...





$ 6D:$ 6Eに#D9:#82が必要です。 ここから出発します:

 $F225:B1 6D LDA ($6D),Y @ $82D9 = #$01
      
      





ここで、間接アドレス指定に6D:6Eセルを使用します(さらに、インデックスレジスタYと0が含まれています)。



複素数演算


$ 82D9で銀行のコンテンツのメモリを直接調べることができます(その後、エディターで検索して検索できます)が、それを把握しましょう。 銀行切り替え手順で思い出したように、銀行番号は$ 06D1に保存されています。 番号#06があります。これは、バンク7がオンになっていることを意味します(7番目のアカウントで)。つまり、最後から2番目です。 メモリの先頭は8000ドルであるため、セルのオフセットは$ 82D9- $ 8000 = $ 02D9です。 ファイル内のオフセットを考慮します。

16()+6( )*16 ( ) + 0x2D9( ) = 0x182E9





これは、ファイル内のオフセットになります。



おridge ...


01 00 00 9E 1E 11 1E 1E...





何も言わないでしょ? 次に、実験します。

01から02に変更すると、下の部屋から始まります。 つまり、シーケンスの最初のバイトは、レベルが始まる部屋を何らかの形で担当します。 値を調べてみると、特定のロジックなしで自分自身をあちこちで見つけることができます。 次の2つのゼロを変更しても、結果はまったく得られません。 そして、4バイト目を9Eからより小さな値(02または03)に変更し、ゲームを開始し、レベルの入り口で...すぐにガードに殺されます!

完全なナンセンス。 ROMファイルのさまざまな部分で[実行...]ボタンを押し続けることはできますが、ある時点でうんざりしています。



組み合わせを作る


コードを歩き回らないようにするため、セル$ 70が変更されてから画面に画像が表示されるまでのトレーサーで収集されたデータを確認することにしました。 私たちは(今のところ!)デバッガーによって画像が表示される瞬間を把握できないため、器用さを訓練します。 これは時間通りに行わなければなりません。なぜなら、遅れると余剰金を手に入れ、急いだ場合は不足分を手に入れるからです。

ツール->トレースロガーに進みます...



ファイルから読み取ったコードは必要ありません。データのみが必要です。 ボックスをチェックし、ファイルを選択してデータを保存し、セルに書き込むためのブレークポイントの後に[ログの開始]をクリックします。

データ収集を停止すると、出力は元のROMファイルと同じサイズのファイルになりますが、トレーサーの操作中に元のファイルから取得されたデータのみが含まれます。 残りのセクションはゼロで埋められます。

明らかに、最初の2つのバンクはスキップできます。タイルがあるため、デバッグ中に見つかったデータもスキップします。 試行錯誤により、オフセット0x18010に落ち着きました。



分析


もちろん、より直接的な方法は、デバッガーでコードを分析し、手順を実行して、データで次に何が起こるかを確認することですが、これまでのところ経験はほとんどなく、ストローは1つしかありません-セル番号70。ますます多くなり、そのような粗雑な方法にますます頼ることが可能になります。 最終的に、デバッガーと16進エディターに限定することができます。



しかし、それはもっと遅くなりますが、今のところは第3章「コードの最初の行」が先にあります。



All Articles