• (SFC) DQ5 TASの補足 [任意コード実行]

    2020-04-28 18:252

     挙動自体については動画内でほぼ全て説明しきっているので、任意コードの詳細等も記載はしますが余談がメインです。
     冗長ですので、スクロールしながら興味のある箇所だけご覧ください。

    お品書き

    1. データ関係
    2. オープニングカットチャートの可能性
    3. 今回使用の任意コード
    4. Lsnes Edit movieの見方
    5. 主人公名前文字コード表(2020/5/2追記)

    データ関係

    SRAM(セーブデータ)

     まず、初回起動時にSRAMが00で埋められます。なので、SFCDQ1,2のような悪さは出来ません。当たり前だよなあ?

     以下、全て冒険の書1での説明。


     冒険の書1の頭は$0012[冒険の書Lv表示]で、末尾がチェックサムです。
     今回のTASで関わってくるのは、$002B[所持金下位]$002F[PT-1]のみです。この2つの差し引きが±0になるよう、所持金の管理を行います。
     今回のサブフレームリセット箇所は、$002F[PT-1]書き込み後、$0030書き込み前です。
    データ消去
     チェックサム不一致、$0012[冒険の書Lv表示]=0、の少なくとも2種類があります。
     また、手動・自動に関わらずデータ消去時は冒険の書内の全ての値が00に書き換わります。
    WRAM <--> SRAM

     MVNによる転送命令によりWRAM7E:2000($2000) -> SRAM70:0012($0012)へコピー、以降チェックサム領域までそのまま一連の流れでコピーされます。
     ですので、SRAMとWRAMの番地の対応は±0x12をすれば概ねわかります。

     SFCDQ1,2は1byteあたり数サブフレーム(rlowの値)を要していたのが、DQ5の場合は値が1進むごとに1byte書き込んでいました。おそらく上記画像どおりMVNで即書き込む形になっているおかげと思われます。疎いので説明に誤りがあったらすみません。
     なので、人力リセットを狙うにはなかなか厳しいのではないかなと思います。(他のゲームがどのようなセーブ形式なのかは全く存じておりませんが。)もしくは猶予bytesを広く取る必要があるかもしれません。

    オープニングカットチャートの可能性

     サブフレームリセットによるオープニングカットは、可能です。
     新規データ作成時、チェックサムが0x0000になるようなキャラクター名を付け, $0045[冒険再開場所]が0になるようにそれ以前でサブフレリセをします。ですが…。


     キャラクターデータはリセット時の書き込み範囲より後ろのため、全て00になってしまいます。
     $0012[冒険の書Lv表示]は、初回開始時こそ1になっていますが、以降の教会セーブでは主人公Lvを書き込むためにもれなく0となり先述のデータ消去条件に当てはまってしまうため、セーブ後の起動時・リセット時はデータが消去されてしまいます。

     となると、これ以降はセーブをせずにENDまで突っ走りたいところです。
     起動時は中身が棺桶状態なので移動できませんが目の前の神父で蘇生できます。蘇生後動けるようになるので、ヘンリー誘拐イベントを進めて外に出ると…。

     本来オープニングの下船後に起こる強制戦闘が始まり、その後パパスに連れられて移動が始まります。そして海岸線に引っかかり、メニューも開けないのでうみでつみです。なお、戦闘中のキメラの翼も効果がありませんし、敵を倒してもLvは上がりません。

     また、どういうわけか世界地図を見ることでもスライム戦が始まります。

     戦闘終了後に移動が始まるので、強制イベント突破か!?と思うのですが…。

     外に出ると再び強制戦闘→強制移動で詰みます。ちなみにパパスが2人に増えるので無駄に強いですが、どのみち移動で詰むので意味はないです。

     というわけで、オープニングカットへの道のりは険しいのでした。突破方法はあるのでしょうか。

    今回使用の任意コード

    言語は65C816(65816)です。
    ニーモックオペコードバイナリ摘要
    48730f
    REP #$20C2 2011000010 00100000;A:16bit
    LDA #$BED1A9 D1 BE10101001 11010001 10111110;A=0xBED1
    WAICB11001011;Wait for Interrupt
    48731f
    BRA F880 F810000000 11111000;-8へ分岐
    STA $07,s83 0710000011 00000111;S+0x07=A(=0xBE01)
    LDA #$02ECA9 EC 0210101001 11101100 00000010;A=0x02EC
    WAICB11001011;Wait for Interrupt
    48732f
    BRA F880 F810000000 11111000;-8へ分岐
    STA $7E21EA8F EA 21 7E10001111 11101010 00100001 01111110;$7E21EA=A(=0x02EC)
    TCS/TAS1B00011011;Stack pointer=A(=$02EC)
    WAICB11001011;Wait for Interrupt
    48733f
    BRA F880 F810000000 11111000;-8へ分岐
    SEP #$20E2 2011100010 00100000;A:8bit
    STA $210C8D 0C 2110001101 00001100 00100001;$210C=A(=0xEC)
    WAICB11001011;Wait for Interrupt
    48734f
    BRA F880 F810000000 11111000;-8へ分岐
    JML $02:FD075C 07 FD 0201011100 00000111 11111101 00000010;Jump to $02:FD07


     4つのコントローラで2バイトずつ、1フレームあたり計8バイト分のコードを入力できます。
    WAI / BRA F8
     塊ごとに共通しているこれらは、実行プログラムをコントローラ領域で循環させるための魔法の言葉のようなものです。
     WAIで割り込み待ち、次のフレームに進みます。
     BRAはフラグに関わらず常に分岐。今回、BRA F8は常に$421E,Fで実行させているため、F8つまり-8、$4218(コントローラ1つ目)へ実行アドレスが移動するようになっています。
    REP #$20 / SEP #$20
     A(アキュムレータ)の扱いを変更します。REP#$20は16bitに、SEP#$20は8bitの扱いです。
    LDA #$BED1 / LDA #$02EC
     Aに値をロードします。
    STA $07,s
     7つ先のスタックにAの値を書き込みます。

     命令時点のスタックポインタは$0989なので、7つ先の$0990へ、事前にLDAした0xBED1を書き込みます。
     で、このスタックへの書き込みはなんぞやというお話ですが。
     DQ5には(おそらく毎フレーム?)、WRAM上に命令を展開してそれを実行するルーチンが存在します。

     このルーチンが何をしているのかは正直わからないのですが、$2bbf0c rtsの戻り先がおかしくなっていると、任意コードでエンディングムービーに飛ぼうとしてもうまく行かなかったために、修正をかけているわけです。
    TCS/TAS
     Transfer Accumulator to Stack pointer、つまりAの値をスタックポインタへ転送します。事前にLDAした0x02ECを転送し、スタックポインタ(スタックの現在位置)を$02ECへ変更しています。
     これは先程のWRAM展開ルーチンとも関わりがあります。
     どうやらこのルーチンは特殊な扱いのようで、安定して実行するためにスタックポインタの位置を毎回$098Dに変更した上で実行しています。おそらくこの近辺のスタックは、このWRAM実行ルーチン周辺でしか使用していないのではないかと推測します。
     ですが、STA $07,sの項目で説明したとおり、任意コード実行開始時点のスタックポインタが$0989、つまり本来はWRAM展開ルーチンでしか使わないはずのスタックへ既に侵入しているわけです。
     ですので、通常使用するスタックの範囲へと戻してやるわけです。
     …長々説明しましたが、実際問題としては「よくわからないけどここでスタックポインタを$02ECにしたらうまくエンディングに飛べた」レベルです。ごめんなさい。ENDに行かない原因を一つ一つ潰していった結果です。
    STA $7E21EA
     $7E21EAはイベントフラグです。エンディングムービーへ飛ぶには0x80以上が必須で、今回はスタックポインタ変更で使用した0xECが偶然条件を満たす形だったので流用しています。なお、Aを16bitのまま処理しているので隣の$7E21EBが0x02ECの0x02に汚染されていますが、影響が出なかったので放置しています。
     ちなみに、このイベントフラグを端折るとどうなるかと言いますと…。

     こうなります。任意コードで初めてムービーに飛ばした時は、思わず笑ってしまいました。そうくるか。まさかムービーを共有していたとは。
    STA $210C
     $210CはIOポートのバックグラウンド設定領域です。
     $7E21EAのイベントフラグも設定し、いよいよENDへ、と思ったら思わぬ壁がそびえ立ちました。
      が、  になってしまう。
     いや、なんだよこれまじで…となりました。
     DQ5はグラフィックにも圧縮がかかっているので、解凍処理がおかしいのか?などと色々な方向で探っていたのですが全く埒が明かず。
     2週間ほど悩み続けてからno$snsというエミュレータを発見し、世界が変わりました。


     これだ!!!!!ということで無事解決したのでした。
     bit1,2が0、bit3が1なら作動しそうだったので、スタックポインタのための0x02ECSEP #$20でAを8bitにしているのでここでは0xEC)が偶然使えました。(‭0xECはbit表記で11101100‬)
    JML $02:FD07
     エンディングムービーへジャンプする命令です。$7E21EAのイベントフラグがきちんと設定されていれば、ゴールドオーブは落ちてきません。やったぜ。

    Lsnes Edit movieの見方


     色々な要因が重なり、任意コードで何を入力しているのかが読み取りにくくなっています。
    1. Lsnesのキー受付タイミング
    2. 任意コードとして反映される順番
    3. WAIとBRA F8とコントローラの順番とフレームの関係
    Lsnesのキー受付タイミング
     上記画像で、背景色が赤と青とで分かれていますが、青の部分つまりBYsS↑キー表示よりも1フレーム遅く入力されます。(DQ1,2,5の仕様なのか、他のゲームも共通なのかは未調査。)
     雑に画像を直すと、実際は以下のようなフレームで入力がされています。

    任意コードとして反映される順番
     キー入力が命令に変換される順番は、エディターの左から右へ順番に…ではありません。

     このようにジグザグな感じで命令が反映されます。
     例えば48730fの場合は、[11000010:C2][00100000:20][10101001:A9][11010001:D1][10111110:BE][11001011:CB]となるわけです。
    WAIとBRA F8とコントローラの順番とフレームの関係
     だいぶ上の方で解説した任意コード一覧の表だと、各フレームの先頭にBRA F8を記載していますが、上記画像では一番右、7番8番がBRA F8に相当します。
     これは、6番のWAI命令で次のフレームに進めてキー入力内容を更新した後、フレームの最初でBRA F8によりコントローラ1-1へ戻るところから始まっているためです。
     フレーム単位で見ると、コントローラ2-2(BRA F8) → 1-1 → 2-1 → 1-2(WAI)の順になります。
    最後に
     もう一度未加工のエディター画像を表示してお別れしましょう。

     なんとなく分かりましたでしょうか。
     少しでも理解の助けになれば幸いです。それでは。

    主人公名前文字コード表

     (2020/5/2追記)
     それでは、と言いつつの追記です。
     なおゲーム中テキストは別に管理されているので、この文字コードでは解析できません。
    主人公名前文字コード表

    10

    11

    12

    13

    14
     

    42

    43

    44

    45

    46

    15

    16

    17

    18

    19

    47

    48

    49

    4a

    4b

    1a

    1b

    1c

    1d

    1e

    4c

    4d

    4e

    4f

    50

    1f

    20

    21

    22

    23

    51

    52

    53

    54

    55

    24

    25

    26

    27

    28

    56

    57

    58

    59

    5a

    29

    2a

    2b

    2c

    2d

    5b

    5c

    5d

    5e

    5f

    2e

    2f

    30

    31

    32

    60

    61

    62

    63

    64

    33

    34

    35


    65

    66

    67


    36

    37

    38

    39

    3a

    68

    69

    6a

    6b

    6c

    3b

    3c

    3d


    6d

    6e

    6f


    3e

    3f

    40

    41


    70

    71

    72

    73

    nil
    01
    ※1

    78


    83

    84
    ※2
    ※1
     主人公の名前領域は8バイト(SRAM$13~1A
     それに満たない名前の場合、残りは01で埋まります。
     例:[あいうえ] → [10 11 12 13 01 01 01 01]
    ※2
     半濁点゜濁点゛は、適応文字の直前に格納されます。
     例:[ぱばパバ] → [83 29 84 29 83 5b 84 5b]

  • 広告
  • (SFC) DQ1, DQ2 TASの補足 [サブフレームリセット]

    2019-03-22 23:144

     スーファミのエミュレータはいくつも存在していますが、サブフレームリセットが実行可能なエミュはまだあまりありません(そういう意味ではエミュ依存です)。
     今回はTASVideosでも推奨されているLsnesを使用しました。
     Lsnes rr2-β23のSRAMは初期値がFFで埋まっているので、以下はそれを前提に説明します。実機はどうなの?とコメントも頂くのですが、気になるようならご自身で実機を使って確かめてください。Lsnesは現行エミュの中では最も実機に近い挙動をするといわれていますので、私はそれを信じます。
     なお、SFCのドラクエ1,2は同一カセットに収録されており基本的なシステムも共用しているので、以下で説明する内容は1,2共通です。

    SRAM(セーブデータ)の概要

    どの項目も左からDQ1:冒険の書1,2,3・DQ2:冒険の書1,2,3の順となっています。
    $0002~$0007
     冒険の書の有無です。あり=01、なし=00となっています。
     ちなみに「呪いの音楽」が流れた時や冒険の書を「消す」時は、実はここが0100に変更されるのみで、以下で説明するチェックサムやセーブの中身そのものは全く変更のないまま残っており、いわゆるエラー処理は一切ありません。
     いわゆるエラー処理が一切されない点が本攻略の鍵の一つとなりますが、これはゲームによって異なっており、例えばFC版ドラクエ4では全てを4Bで埋め尽くす処理が入るようです。
    $0008~$000D(進行),$000E~0013(名前)
     チェックサムです。進行データと名前データにそれぞれチェックサムが用意されており、各冒険の書ごとにその2つが合致しないと呪いの音楽が流れます。

     なお、チェックサムの計算方法は対象範囲の単純な総和です。
    $0014~$01B1

     名前データです。$0014~$0058,$0059~$009D,…とセーブ毎に69bytesずつ格納されています。
     濁点・半濁点を分けているもの(DQ1初期能力決定用?)と、濁点等を含めて1文字で管理しているもの(表示用)とがあり、名前の終わりには必ず終了を示すFFが挿入されます。
     セーブのコピー途中でサブフレームリセットを使用したデータでは名前データが全てFFで埋まる場合があり、その場合は名前が一切表示されない名無し状態となりますが、ゲーム進行に支障はありません(少なくとも本TAS動画中では)。
    $01B2~$13B1
     進行データです。$01B2~$04B1,$04B2~$07B1,…とセーブ毎に768bytesずつ割り当てがあります。

    SRAMへの書き込み順序

     状況によって少し順番が異なります。
    冒険の書の新規作成・王様等でのセーブ
     冒険の書の有無→進行→名前→チェックサム の順に書き込まれます。
    「うつす」でのセーブコピー
     冒険の書の有無→チェックサム→進行→名前 の順に書き込まれます。

    サブフレームリセットでのセーブデータ操作

    核となるデータの作成1(正常データ
    (本動画ではどちらも冒険の書2に作成)
     進行データにサブフレームリセットを加えていない、いわゆる普通にゲームを開始した状態のセーブが最低1つは必要と考えています。
     理由としては、進行データの途中でリセットをすると名前データおよびチェックサムが書き込まれません。つまり、名前は全てFFで埋まり、チェックサム保存値もFFとなるのですが、名前がFFで埋まった状態のチェックサムはFFではないため、必ず呪いの音楽が流れてセーブがないものとみなされてしまいます。
    核となるデータの作成2(進行データの後半をFFで埋めた不正データ
    (本動画ではどちらも冒険の書3に作成)
     最終的に正常な値FFとを交互に上塗りしていくために、冒険の書として選択できる「一部をFFで埋めた不正データ」が核として必要になります。
     セーブのコピー途中でサブフレームリセットをすることで、進行データの後半をSRAM初期値であるFFのままに出来ます(もちろんチェックサムが合うタイミングでリセットする)。
     このデータを冒険の書として認識させるためには正常データをコピーします。進行データの途中でサブフレームリセットをしても、「うつす」でのセーブコピーはチェックサムが先に書き込まれるため、名前チェックサムにも不都合が生じずに核データの作成ができます。
     ただし名前データ自体は書き込まれないため、名前が全てFFで埋まっている際のチェックサムにあらかじめしておく必要があります。
     その際の名前チェックサムはBBで、対応する名前はDQ1では「か」DQ2では「ふ」です。他にも該当する名前はあると思いますが調べていません。
    進行データの捏造
     正常データ不正データを交互に上書きしていくことでデータの捏造を行います。SRAMの上から下に向かって書き込み処理がされるので、最終形にするには最下部から徐々に残してゆく形をイメージしてください。
     なお、セーブコピー中のサブフレームリセットを行う度に、「タイトル画面でDQ1か2を選んで、該当タイトルのロゴが一瞬出て、(ほぼ全ての場合でチェックサムが合わないので)呪いの音楽を聞いて・・・」と、かなりのタイムロスが生まれてしまいます。
     本動画のDQ2は強引にデータ作成を行ったのでリセット回数がかなりの数になっており、時間的ロスも凄まじいし何よりも呪いの音楽をたれ流しすぎなのですが、今回は通常のオープニングを見る時間(5分超)よりも速ければひとまずOKとしました。

    バグアイテムID:7Fでのワープ

    アイテムの仕様
     DQ1,2でのアイテムの仕様として、「装備状態」のアイテムは元々のアイテムIDに80が加算されます。例えばDQ1のかわのたてはID:0Fですが装備することでID:8Fになります。
     アイテムリストを見ていただくと分かるのですがアイテムIDは65までしか割り振られておらず、装備状態として80を加算しても他のアイテムIDとは競合せずに判別が出来るようです。
    ID:7Fへの変化
     データ捏造でアイテムID:FFを持たせた場合、ID:7Fを装備した状態として認識されています。つまり装備解除をすることでアイテムはID:7F(アイテム名:「なし」)へと変化します。
     このID:7Fはワープアイテムとして利用することができ、過去に投稿されたTASやRTAの動画で使用した物と偶然同じアイテムIDです。(今まではマドハンドバグを利用してアイテムを生成していました。)

     ワープアイテム7Fの細かい仕様を知りたい方は「やる夫がDQ2で最強データを目指すようです」の810-830あたりを、ワープ可能位置とワープ先を知りたい方は「SFC版DQ2 ワープポイント」(DQ1にチェックを入れると1のマップも見られます)をご覧ください。
     余談ですが調査中の頃、「そういえばアイテムFFって7Fになるし、ワープできるなあ。何かに使えるかな」的な呟きをしたところ、上記動画の両名からほぼ同時に「それあればDQ2バグでクリアできます。過去に使ってます。」的なコメントが速攻返ってきました。自分ひとりだったらクリアまでの道筋に気付かなかったかもしれません。ありがとうございました。
    ID:7Fの利用
     DQ1では城の2階から1階に降りるため、DQ2では幻ローレシア城での「夢落ち状態」を回避しつつエンカして全滅するために利用しています。
     DQ1は降りるだけなのでワープアイテムがなくてもクリアできそうに思えるのですが、王様の正面に回れないため地味に詰みます。

    マップチェンジバグ

    条件
     通常フィールドマップ以外のエリア80以降に出現するとエンディングに移行することがあります(100%ではない)。通常ではありえない状況ですが、アイテム7Fでワープすると本来情報が書き換わるべきタイミングで書き換わらないため、このような状況が生まれる場合があります。
     今回のDQ2は、リレミト情報をマップ92(ロンダルキア)・エリアFFにすることで実現しています。
    実行手順
     フィールドから施設に入るとリレミト情報が書き換わります。リレミトマップをロンダルキア92へ変更するには、単純にロンダルキアマップから城等に入ればOKです。
     また、全滅するとルーラ情報をリレミト情報へと上書きする処理が入るのですが、なぜかエリアと座標のみが上書きされリレミトマップは書き換わりません
     つまり、リレミトマップをロンダルキア92にしたあとに全滅したことで、あらかじめデータ捏造で用意しておいたルーラエリア情報FFリレミトエリアFFへと上書きされ、一方リレミトマップは書き換わらず92のままとなるので、バグの条件を満たします。
     あとはリレミトをすれば…というところなのですが、本動画の全滅後に再開した真っ暗なバグマップは外に出ると偶然リレミト扱いになっていたので、特に考える必要はありませんでした。
     ちなみにバグマップを利用しない場合は、アイテム7Fのワープで出入口が1つしかないダンジョン(湖の洞窟等)にワープし、外へ出ることでリレミト扱いとなります。
     なお、ルーラ・リレミトの仕様説明は「やる夫がDQ2で最強データを目指すようです」の824,964-970あたりもご覧ください。

    サブフレームリセットで関わったSRAM

     動画内で述べたこととそんなには変わりませんが、見やすいようにこちらにも書いておきます。なお一ヶ所動画での説明に誤りがありました。うろ覚えで書いててすみません。
    DQ1(冒険の書1)
     $023A:オープニング(最初の王様のコメント)フラグ。FFにすると王の導入コメは無くなるけど人外の言語を延々しゃべり続けるマンになります(詰み)。
     $0270:主人公の所持品1番目のアイテムID(~$0279が10番目のアイテム)。WRAM$0CBE~0CC7に対応。
     $02A3:竜王撃破フラグ。毒沼が花畑となりエンカもしなくなります。
     $02A6:世界の半分フラグ。リムルダール宿屋で悪夢から復活。が、オープニングフラグがそのままだと、そのあと王様のOPコメントが割り込んできます。王様強い。
    DQ2(冒険の書1)
     $0B39:1以上でローレシア王がイベント用の位置へ移動。エンカしなくなります。WRAM$0C87。
     $0B3A:オープニングフラグ。0だとオープニング見てない扱い。
     $0B70:ローレの所持品1番目のアイテムID(~$0B79が10番目のアイテム)。WRAM$0CBE~0CC7。
     $0B98:パーティメンバー数。WRAM$0CE6。
     $0BA6:会話終了や全滅後にハーゴン城へ強制ワープ。
     $0BA7:動画内で「会話ウィンドウ閉じない」と書きましたが正しくは「呪いで王様の会話中に追い出される」の間違いでしたすみません。全滅後のハーゴン城から海に投げ出されてロンダルキアへ行けなくなるので、FFにしてしまうとうみでつみです。WRAM$0CF5。
     $0BB540以上でシドー撃破扱い。WRAM$0D03に対応。ちなみにWRAM$0C87=5ジャスト、$0D03=40以上で王様に話しかけることでもEDに行けるそうです
     $0C9D:$0C9B~$0C9Eが冒険再開や全滅時の再開場所(座標x,y,マップ,エリア)。結局FFを入れずに通常の値が一番使えました。WRAM$0DE9~$0DEC。
     $0CA1:$0C9F~$0CA1がルーラ情報(座標x,y,エリア)。マップ情報はありません。WRAM$0DED~$0DEF。
    動画で使ったSRAMプラン
    DQ1(冒険の書1$01B2~$04B1)


    DQ2(冒険の書1$0AB2~$0DB1)


    ひとまず以上で補足を終わります。
  • コントローラーを分解する

    2015-01-17 18:09
    生存報告ともいう。



    SFCのアスキーパッドと純正コンを分解




    裏のネジを外したところ。




    基盤を外したところ。
    LRキーは若干アスキーの方が大きい。




    ゴムとか全部外したところ。
    色は違いますが形大きさは一緒ですね。




    せっかくなので純正コンのゴムをアスキーに入れてみる。




    入りました。




    遊べました。


    さて次。




    SFCのホリコマンダーとPS純正コン。
    SFC系は以前にも何度か分解してましたが、PSは初めて。
    (したことあった気がしていたのは完全に気のせい。)




    裏のネジを外したところ。




    純正とアスキーはLRキーに棒が突き刺さってますが、
    ホリコンは一体化してるのが違う点。


    しかしPSコンはなんだか面倒そう。



    中央のネジ外さないと基盤とれません。
    持ち手部分にある変な部品は引っ張ればとれます。




    基盤を外したところ。




    なんとか全部外せました。


    しかしPSコンの組み立てがうまくいかない。
    なんでかなと思っていたら。











    こいつを外さないとどうやっても基盤がぶつかることが発覚。
    (なぜ基盤外せたんだ。)

    しかしそれでもうまく入らない。




    こいつは基盤より後に入れないとダメみたいでした。
    (なぜry


    で、組み立て終わったのですが。


    PSコン断線しました( ゚д゚ )



    写真撮り忘れましたがここの赤線が切れてました。
    皆さんも気を付けましょう。。。
    (試しに使ってみたら、すべてのキーが使えたのは謎。)

    でもSFCコンは単純な作りしてるんで、
    掃除とかゴム交換とかすればいいんじゃないかな( ゚д゚ )
    (隙間にゴミとかが入り込んでるので結構汚れてます。)