TOP > プログラミング関係解説&調査 > サモに与えるアイテム

サモに与えるアイテム

当ページの内容は、ある程度のプログラミングの知識を必要とする。
まず、プログラミング関係解説&調査をひととおり読んでいただきたい。

心山拳師範にサモを選び、最終編でサモ以外を主人公にして開始した場合、サモを仲間にする時には特定のアイテムを一定数与える必要がある。
この時、プログラム上ではどのように処理されているのか。

何をいくつ与えたら仲間になるのかは、与える前にセーブして色々なアイテムを与えることでもわかる。
最終編攻略にも掲載しているが、仕様は以下の通りである。

アイテムには、それぞれ「サモに与えることができるかどうか」「与えられる場合、サモを仲間にする為のポイント」が設定されており、与えることができるアイテムを累計20ポイント以上与えると仲間にした判定になる。
このページでは便宜上、サモにアイテムを与えることで増える数値をSFC版攻略本から引用し「満腹度」、満腹度を増やす数値を「ポイント」としておく。

  • 1ポイント:なおり草、ももまん、あんまん、たい焼き
  • 2ポイント:バナナクレープ、かすていら、てんむす、テキーラ、ヨシュアの実、アリスのビスケ、ホネ肉
  • 4ポイント:どでかホネ肉、エデンズアップル
  • 5ポイント:ポーションNO9

なお、以下で説明するプログラムは、「アイテム一覧を開いて何かのアイテムを選ぶことで進行するイベント」用のサブルーチンを使っている。
本作は「アイテム一覧を開いて何かのアイテムを選ぶことで進行するイベント」が多数存在しているが、その為の汎用サブルーチンがあり、サモを仲間にする時にアイテムを与える時にも使われている。
今回は紹介を省いたが、実際にはサブルーチンの間に「現在プレイしているシナリオは何か」などの判定も入っており、「アイテム一覧を開いて何かのアイテムを選ぶことで進行するイベント」の中のどのイベントかの判定も行っているようだ。

プログラム上での処理がどうなっているかの話の前に、アイテムの仕様について説明する。

アイテムについて

本作のアイテムは、データ上では装備品・攻撃・回復アイテム含めて255種類あるが、実際のゲームでは使われていない未使用アイテムも含まれている。
また、最終編のキューブのバッテリーは「鉄の箱」「????」「なんかの部品」「バッテリー」と、最終編主人公によって名前が変わるようになっているが、データ上は4種類の別アイテムだったり、ハッシュが装備できるのにオルステッドは装備できない「ブライオン」と、オルステッドも装備できる「ブライオン」が別アイテムであるなど、面白い仕様も存在する。
アイテムにはIDが16進数で振られているが、IDの$00には何のデータも入っていない。アイテム欄に何もない箇所には$00を入れる処理をしている。
それ以上のID、$01$FFに255種類のアイテムが割り振られている。
(このあたりは、技IDなどと似た処理である)
IDとアイテムの対応は、世界の合言葉は森部様のアイテムデータを参照していただきたい。

1アイテムあたり、32バイトの容量を使って各種データが記録されている。
例えば最後の1バイト分はほとんどのアイテムで$00で、$00以外の値が入っているのは「ヨシユキ($10)」と「ムラサメ($20)」だけである。
このふたつのみということからもピンと来る方が多いだろうが、「武器自体についている状態異常追加効果」の値が記録されている。
アイテムの基礎値データは$D5:71C5$D5:81C4にまとめて入っている。

持ち物一覧

メニュー画面→持ち物や、戦闘で「アイテムを使う」コマンドでアイテム一覧が見られるが、シナリオによって所持できるアイテムの種類数・個数が異なる。
今回は最終編の話なので、最終編に絞って説明するが(中世編も仕様は同一)、最終編でのアイテム一覧は255種類分のスペースがある。
わざわざ一番下までアイテムを移動させることはほぼないだろうからわかりにくいのだが、アイテム一覧の一番下の右の枠はアイテムを移動できない。
よって、持ち物欄のスペースに01から番号を振ると、

001002
003004
005006
……
251252
253254
255 

であり、新たにアイテムを入手すると上の順番で埋まっていく(間に空欄がある時は隙間を埋めていく)。
255番目のアイテムの右の空欄には、アイテムを入れることができない。カーソル移動もできない。
データ上ではアイテムは255種類なので、全ての欄を埋められるスペースが確保されていることになる。
実際には未使用アイテムや、別名だが同一アイテム扱いのアイテムもあるし、最終編であっても全アイテムが登場することはないため、全ての欄が埋まることはない。他シナリオでも同様。

持ち物一覧の並び順及び、それぞれのアイテムの個数はセーブデータに記録されている。
最終編では、所持しているアイテム名のID一覧が$00:0B01$00:0C00に入り、一覧に対応したアイテム個数が$00:0C01$00:0D00に入る。
順番は上の持ち物欄に01から振った位置である。
たとえば、持ち物欄が、

なおり草    20ユニコーンホーン 01
         聖水       03

のような状態だったら、$00:0B01~は「なおり草のID」「ユニコーンホーンのID」「$00」「聖水のID」となり、$00:0C01~は「$14」「$01」「$00」「$03」と個数が記されることになる。

サモにアイテムを与える場合

以上を踏まえた上で、最終編でサモを仲間にする時にどんな処理が行われているか紹介する。
アイテムを与えることでサモの満腹度が増えるということは、各アイテムに満腹度用のポイントが設定されているのだろうか。
だが、アイテムの基礎値データは$D5:71C5$D5:81C4を見ても、それらしき数値がない。
たとえば、「なおり草」はサモに与えることができるアイテムの中のひとつだが、アイテムの基礎値データを見ると、32バイト分のデータの内1バイト目の「$03」と11バイト目の「$C1」以外は$00で埋まっている。
ここから読み取れるのは、「なおり草」は回復・消費アイテムで、使うと「自分・中回復」の効果がある、ということだけである。

つまり、「サモに与えることができるアイテムかどうか」は、アイテムの基礎値データでは判定されておらず、まったく別の何かの方法で判定しているということだ。
答えを書いてしまうと、「最終編用のデータ内に、サモに与えることができるアイテムID一覧表が存在している」のである。
この方法だと、最終編でしか使われない「サモに与えることができるアイテムかどうか」の判定だけのためにアイテムの基礎値データを1枠(1バイト×アイテム255種)使うより、容量を節約できる。
そもそもこの基礎値データには、戦闘において必要なデータのみを格納しており、イベント関係のデータは一切入っていないようだ。

本作のデータの中には、各シナリオ専用ごとのデータが存在しており、各シナリオ開始時に$7F:8E00~に読み込まれている。セーブデータから開始した時ももちろん読み込まれる。
「サモに与えることができるアイテムID一覧表」は、その中の$7F:AE80$7F:AE99にある。
後で紹介するが、更にその後の$7F:AE9A~以降に、満腹度用のポイント計算のための数値も入っている。
更に言えば、一覧表のひとつ前の数値$7F:AE7Fに、「サモに与えることができるアイテムID一覧表」に入っているアイテムの種類数「$1A」が入っている。

一覧表といっても、アイテムIDが26個(26バイト分)並んでいるだけだが、IDと対応するアイテムの表は以下の通りである。
未使用アイテムや最終編には登場しないアイテムも含まれるため、実際に最終編をプレイした時のみ入手できるアイテムは太字にした。

IDアイテム
$01なおり草
$02ヨシュアの実
$03アリスのビスケ
$06エデンズアップル
$28ホネ肉
$29どでかホネ肉
$4Dバーボン
$4Eテキーラ
$66にんじん
$67てんむす
$68かすていら
$8Aド根性焼き
$A4たい焼き
$AFバナナクレープ
$B7ミサワ焼き
$BDあんまん
$BE肉まん
$BFももまん
$C0フカヒレまん
$CF老酒
$DBシロツメ草
$DCペンペン草
$DDブタ草
$DEオオイヌノフグリ
$DF守体草
$8BポーションNO9

未使用アイテムの「ペンペン草」「ブタ草」や、最終編には登場しない「バーボン」「にんじん」「肉まん」「ド根性焼き」「ミサワ焼き」「フカヒレまん」「シロツメ草」「オオイヌノフグリ」「守体草」も混ざっている。
よって、実際のプレイで意味があるのは太字部分の15種類しかない。

ゲーム開発中、最終編に出てくるかなどは横に置いて、とりあえず食べ物っぽいアイテムを片っ端から「サモに与えることができるアイテムID一覧表」に登録しておいたのかもしれない。
プログラムでは、これらのアイテムIDと、サモに渡したアイテムのIDが一致するかどうかを調べるので、一覧表に未使用アイテムや最終編には登場しないアイテムが混ざっていても、ゲームをプレイする上でエラーが出るなどの支障はない(はず)。
必要ないからと下手に削除すると、アドレスの指定位置などの修正も行う必要があるため、余計な手間を省くため、更には新たなバグの発生を防ぐために製品版でもそのまま残されたのかもしれない。
功夫編における重要アイテムの「守体草」が混ざっていることから、開発中は「守体草」も回復アイテムとして想定されていた可能性も想像できるのは面白い点である。ただし、功夫編において、「守体草」を戦闘で使い切ってしまうと、ユンの祖母を回復させることができなくなってしまうので止めたのかもしれない。

(ちなみに上のアイテム一覧は、最後の「ポーションNO9」を除いて、SFC版攻略本にもそのまま掲載されている。実際のゲーム内に登場しないアイテムも含まれているあたりからしても、開発段階での資料がそのまま攻略本に載っているのではないかと思われるが……。最後の「ポーションNO9」はIDの数値からして、開発段階の終盤に追加された可能性があり、「ポーションNO9」だけが攻略本に載っていない理由もなんとなく推測できるが、あくまでも推測なのでここまでにする)

ということで、サモにアイテムを渡す時の大まかな手順は以下の通りである。
判定のため、サモにわたすアイテムIDはメモリアドレスの[$00:013D]に、満腹度は[$00:11F2]に記録される。
満腹度の初期値は$00で、渡したアイテムに設定されたポイントの分だけ加算されていく。つまり累計値であり、最終的に$14(10進数20)未満か以上かで分岐になる。

  1. アイテム一覧からサモにわたすアイテムを選ぶと、[$00:013D]にそのアイテムのIDが入る。
  2. [$00:013D]と「サモに与えることができるアイテムID一覧表」のアイテムを一致するか、ループ処理でチェックする。
  3. アイテムID一覧表に一致しない場合は処理終了で、サモのセリフ「いくら オラでも そりゃ 食えんッチ‥‥」を表示して終了。
  4. アイテムID一覧表に一致するアイテムがあったら、アイテム毎のサブルーチンで、アイテムに設定された満腹度のポイント分、満腹度[$00:11F2]に加算する。
  5. 所持しているアイテムから、渡したアイテムの個数を-1する。
  6. 満腹度が20$14)未満なら、サモは再び倒れ処理終了。満腹度が20$14)以上なら、サモが仲間になる会話へ。
※余談だが、[$00:013D]は持ち物を使ったり得たりした時、つまりアイテム個数が増減する時に、そのアイテムのIDが入るアドレスである。調べて何かを拾った時や、近未来編で藤兵衛に改造して欲しいアイテムを渡す時(渡した時にアイテムが減り、改造後に増える)などでも使われるアドレスである。
また、満腹度が記録される[$00:11F2]は、功夫編だとレイの修行回数が記録されるメモリである。
この[$00:11F?]あたりのアドレスは、シナリオによって異なる値が記録されていくのだが、基本的には「何かの回数をカウントするためのメモリ」である。
功夫編だと[$00:11F0]に修行回数の累計、[$00:11F1][$00:11F2][$00:11F1]にユン・レイ・サモの修行回数が入る、幕末編なら[$00:11F0]に「X人斬り」のXの値がカウントされる、最終編はサモの満腹度以外に[$00:11F6]に戦闘から逃げた回数が入ってデスプロフェット出現判定に使われる、など。

以下、サブルーチンの重要な部分のみ紹介。
まず、上の1.~3.部分を取り上げる。

$C0/1E18 LDA $53    [$00:0053] ;Aに[$00:0053](サモに与えたアイテムID)をロード
$C0/1E1A BEQ $1B    [$1E37]    ;ゼロフラグが立っているとき[$1E37]分岐
$C0/1E1C STA $00013D[$00:013D] ;A(サモに与えたアイテムID)を[$00:013D]に書き込み
;(中略)
$C0/37D8 LDA $00013D[$00:013D] ;Aに[$00:013D](アイテムID)をロード
$C0/37DC STA $22    [$00:0022] ;A(アイテムID)を[$00:0022]に書き込み
$C0/37DE LDA $8E00,y[$7F:AE7F] ;Aに[$7F:AE7F](= $1A,10進数26)をロード
$C0/37E1 INY                   ;Yをインクリメント(+1) = $7F+$01 = $80
$C0/37E2 STA $30    [$00:0030] ;A(= $1A)を[$00:0030]に書き込み
$C0/37E4 STA $20    [$00:0020] ;A(= $1A)を[$00:0020]に書き込み
$C0/37E6 STZ $21    [$00:0021] ;[$00:0021]に0を書き込み
$C0/37E8 REP #$20              ;Mフラグをクリア Aレジスタは16bit幅
$C0/37EA TYA                   ;Yレジスタの値($2080)をAに転送
$C0/37EB CLC                   ;キャリーフラグをクリア
$C0/37EC ADC $20    [$00:0020] ;A($2080) + [$00:0020]($001A) = $209A
$C0/37EE TAX                   ;Aの値をXレジスタに転送(X = $209A)
$C0/37EF SEP #$20              ;MフラグON Aレジスタは8bit幅
;
;ループ処理
;サモに与えることができるアイテムID一覧表をチェック
$C0/37F1 LDA $8E00,y           ;Aに[$8E00,y]($7F:AE80~$7F:AE99)をロード
$C0/37F4 CMP $22    [$00:0022] ;Aと[$00:0022](アイテムID)を減算比較
$C0/37F6 BEQ $0B    [$3803]    ;ゼロフラグが立っているとき[$3803]分岐
$C0/37F8 INX                   ;Xをインクリメント(+1)
$C0/37F9 INX                   ;Xをインクリメント(+1)
$C0/37FA INY                   ;Yをインクリメント(+1)
$C0/37FB DEC $30    [$00:0030] ;[$00:0030](初期値$1A)をデクリメント(-1)
$C0/37FD BNE $F2    [$37F1]    ;ゼロフラグが立っていないとき[$37F1]分岐
;ループ処理ここまで
;(最大で[$00:0030]が$00になるまでループ)
;
;アイテムID一致なし処理
$C0/37FF TXY                   ;Xレジスタの値($20CE)をYレジスタに転送
$C0/3800 BRL $E39E  [$1BA1]    ;[$1BA1]へ
;
;アイテムID一致あり処理
$C0/3803 LDY $8E00,x           ;Yに[$8E00,x]をロード
$C0/3806 BRL $E398  [$1BA1]    ;[$1BA1]へ

順に見ていく。

$C0/1E18 LDA $53    [$00:0053] ;Aに[$00:0053](サモに与えたアイテムID)をロード
$C0/1E1A BEQ $1B    [$1E37]    ;ゼロフラグが立っているとき[$1E37]分岐
$C0/1E1C STA $00013D[$00:013D] ;A(サモに与えたアイテムID)を[$00:013D]に書き込み
;(中略)
$C0/37D8 LDA $00013D[$00:013D] ;Aに[$00:013D](アイテムID)をロード
$C0/37DC STA $22    [$00:0022] ;A(アイテムID)を[$00:0022]に書き込み
$C0/37DE LDA $8E00,y[$7F:AE7F] ;Aに[$7F:AE7F](= $1A,10進数26)をロード
$C0/37E1 INY                   ;Yをインクリメント(+1) = $7F+$01 = $80
$C0/37E2 STA $30    [$00:0030] ;A(= $1A)を[$00:0030]に書き込み
$C0/37E4 STA $20    [$00:0020] ;A(= $1A)を[$00:0020]に書き込み
$C0/37E6 STZ $21    [$00:0021] ;[$00:0021]に0を書き込み
;
$C0/37E8 REP #$20              ;Mフラグをクリア Aレジスタは16bit幅
$C0/37EA TYA                   ;Yレジスタの値($2080)をAに転送
$C0/37EB CLC                   ;キャリーフラグをクリア
$C0/37EC ADC $20    [$00:0020] ;A($2080) + [$00:0020]($001A) = $209A
$C0/37EE TAX                   ;Aの値をXレジスタに転送(X = $209A)
$C0/37EF SEP #$20              ;MフラグON Aレジスタは8bit幅

サモに与えたアイテムIDは[$00:013D]に入る、と最初に説明したが、実際はそれ以前に[$00:0053]に入っていて、そこから[$00:013D]に移す。
移す前に$C0/1E1AでアイテムIDが$00かどうかのチェックが入っている。
アイテムIDが$00というのは、持ち物欄の空白を選んだ時になり、何も行われないままウィンドウが閉じる。
$00以外だと、何かしらのアイテムを与えたことになって処理が続く。

(中略)の部分をかなり端折っているが、この間に、最終編で倒れているサモにアイテムを与えた処理を開始という判断が入っている。
$C0/37D8$C0/37EFは、「サモに与えることができるアイテムID一覧表」をループ処理でチェックする前の準備である。
まず、[$00:013D]に入っているアイテムIDを、[$00:0022]へ書き込む。
続いて$C0/37DE[$8E00,y]Aにロードしているが、このイベント時はY$207Fが入っているため(ここまでの計算で処理されているので)、必ず[$7F:AE7F]をロードする。
前に記した通り、[$7F:AE7F]に入っているのは「サモに与えることができるアイテムID一覧表」に入っているアイテムの種類数「$1A」である。
種類数は要するに、ループ処理を行う回数でもある。
ループ処理を行う回数$1A[$00:0030]に書き込まれる。

$C0/37E1では、Y+1しているが、これは[$7F:AE7F]の次の[$7F:AE80]から「サモに与えることができるアイテムID一覧表」が開始になるためである。
ここで必ずY$2080になる。
$C0/37EAで、Yレジスタの値($2080)をAに転送し、更にこの$2080にアイテムの種類数$1Aを加えた$209Aが、最終的に$C0/37EEXレジスタに入っている。
何やらややこしいように見えるが、これは後々で与えたアイテムに対応したポイントをロードするためのアドレス計算に使っている。
とりあえず、ループ開始前にXに入る値は$209Aで固定、ということを覚えておけば良い。

;ループ処理
;サモに与えることができるアイテムID一覧表をチェック
$C0/37F1 LDA $8E00,y           ;Aに[$8E00,y]($7F:AE80~$7F:AE99)をロード
$C0/37F4 CMP $22    [$00:0022] ;Aと[$00:0022](アイテムID)を減算比較
$C0/37F6 BEQ $0B    [$3803]    ;ゼロフラグが立っているとき[$3803]分岐
$C0/37F8 INX                   ;Xをインクリメント(+1)
$C0/37F9 INX                   ;Xをインクリメント(+1)
$C0/37FA INY                   ;Yをインクリメント(+1)
$C0/37FB DEC $30    [$00:0030] ;[$00:0030](初期値$1A)をデクリメント(-1)
$C0/37FD BNE $F2    [$37F1]    ;ゼロフラグが立っていないとき[$37F1]分岐
;ループ処理ここまで
;(最大で[$00:0030]が$00になるまでループ)

「サモに与えることができるアイテムID一覧表」を1つずつチェックするためのループ処理は上の通り。
最初のLDA $8E00,yで、アイテムID一覧表に入っている数値を呼び出している。
ループ開始前、Yは必ず$2080なので、最初のループの時には$8E00 + $2080 = $AE80である。
よって、最初のループで読み込みに行くアドレスは[$7F:AE80]、「サモに与えることができるアイテムID一覧表」の一番最初に入っている「なおり草」のID$01である。

$C0/37F4ではAに読み込みした「サモに与えることができるアイテムID一覧表」の値と、[$00:0022]に入っている、サモに渡したアイテムIDを減算比較する。
引き算して0になるのは、両者の値が一致した時だけなので、$C0/37F6でゼロフラグが立っていたら「サモに与えることができるアイテムID一覧表」の値と一致したことになり[$3803]にジャンプする。
一致しなかった場合は、X+2Y+1[$00:0030]-1している。
ループ開始前にXに入る値は$209AYに入る値は$2080で固定であるから、1回目のループ、つまり「アイテムIDがなおり草だったかどうか」の判定で「なおり草ではなかった」時は、X$209A + $2 = $209CY$2080 + $1 = $2081[$00:0030]に入っている$1A-1して$19、となる。
これでループ1周分の処理が終了し、最後の[$00:0030]のデクリメントで$00になっていないのならループの頭の$C0/37F1に戻る。

……というようにループ処理をしていくと、サモに渡したアイテムIDと、「サモに与えることができるアイテムID一覧表」が一致するかどうか、最大で26回ループ処理をしてチェックすることになる。
ループ回数が+1される度に、X+2Y+1されていく。
ループ中に一致するアイテムがあればループを抜けるので、サモに渡したアイテムIDにより、ループ終了時のXYの値が異なる。

IDアイテムXY
$01なおり草$209A$2080
$02ヨシュアの実$209C$2081
$03アリスのビスケ$209E$2082
$06エデンズアップル$20A0$2083
$28ホネ肉$20A2$2084
$29どでかホネ肉$20A4$2085
$4Dバーボン$20A6$2086
$4Eテキーラ$20A8$2087
$66にんじん$20AA$2088
$67てんむす$20AC$2089
$68かすていら$20AE$208A
$8Aド根性焼き$20B0$208B
$A4たい焼き$20B2$208C
$AFバナナクレープ$20B4$208D
$B7ミサワ焼き$20B6$208E
$BDあんまん$20B8$208F
$BE肉まん$20BA$2090
$BFももまん$20BC$2091
$C0フカヒレまん$20BE$2092
$CF老酒$20C0$2093
$DBシロツメ草$20C2$2094
$DCペンペン草$20C4$2095
$DDブタ草$20C6$2096
$DEオオイヌノフグリ$20C8$2097
$DF守体草$20CA$2098
$8BポーションNO9$20CC$2099
-それ以外$20CE$2099
;アイテムID一致なし処理
$C0/37FF TXY                   ;Xレジスタの値($20CE)をYレジスタに転送
$C0/3800 BRL $E39E  [$1BA1]    ;[$1BA1]へ
;
;アイテムID一致あり処理
$C0/3803 LDY $8E00,x           ;Yに[$8E00,x]をロード
$C0/3806 BRL $E398  [$1BA1]    ;[$1BA1]へ

サモに渡したアイテムIDと、「サモに与えることができるアイテムID一覧表」のどれも一致しなかった場合はループ処理を26回行った後に$C0/37FFに進み、この時点のXレジスタの値$20CEYレジスタに転送してから、[$1BA1]へジャンプする。
サモに渡したアイテムIDと、「サモに与えることができるアイテムID一覧表」のどれかが一致した場合は途中でループ処理を抜け、$C0/3803でその時点でのXレジスタの値 + $8E00Yレジスタにロードしてから、[$1BA1]へジャンプする。

つまり、この先の[$1BA1]以降は、サモに渡したアイテムIDにより、Yレジスタに入っている値が異なる。
「サモに与えることができるアイテムID一覧表」のどれにも一致しなかった場合は共通してYレジスタに$20CEが入っている。
「サモに与えることができるアイテムID一覧表」のどれかに一致していた場合は、Xレジスタの値 + $8E00を計算したアドレスの値をYレジスタに入れる。
下表の「X + $8E00」の欄が該当のアドレスになる。ループでX+2ずつしているから、2ずつ飛び飛びのアドレスである。
この、$7F:AE9A$7F:AECCに入っている値が満腹度を上げるポイント……ではない。
表の一番右の「数値」が、該当アドレスに入っている1バイトの値であるが、これらはポイントではない。
ただし、この時点で、満腹度+1ポイントの「なおり草」や「ももまん」に「$E1」、+2ポイントの「ヨシュアの実」「アリスのビスケ」に「$E6」、+4ポイントの「エデンズアップル」「どでかホネ肉」どちらも「$F2」、+5ポイントの「ポーションNO9」に唯一「$F8」と、この時点で実質、満腹度を上げるポイントが決まっているのだろうということは察せられる。

IDアイテムX + $8E00数値
$01なおり草$7F:AE9A$E1
$02ヨシュアの実$7F:AE9C$E6
$03アリスのビスケ$7F:AE9E$E6
$06エデンズアップル$7F:AEA0$F2
$28ホネ肉$7F:AEA2$E6
$29どでかホネ肉$7F:AEA4$F2
$4Dバーボン$7F:AEA6$E1
$4Eテキーラ$7F:AEA8$E6
$66にんじん$7F:AEAA$E1
$67てんむす$7F:AEAC$E6
$68かすていら$7F:AEAE$E6
$8Aド根性焼き$7F:AEB0$F2
$A4たい焼き$7F:AEB2$E1
$AFバナナクレープ$7F:AEB4$E6
$B7ミサワ焼き$7F:AEB6$EC
$BDあんまん$7F:AEB8$E1
$BE肉まん$7F:AEBA$E6
$BFももまん$7F:AEBC$E1
$C0フカヒレまん$7F:AEBE$EC
$CF老酒$7F:AEC0$E1
$DBシロツメ草$7F:AEC2$D2
$DCペンペン草$7F:AEC4$D2
$DDブタ草$7F:AEC6$D2
$DEオオイヌノフグリ$7F:AEC8$D2
$DF守体草$7F:AECA$D2
$8BポーションNO9$7F:AECC$F8

整理すると、ここまでで、満腹度を上げるポイントによりYレジスタの値が固定となっているはずだ。
(実際のプレイでは登場しないアイテムは、ここでは除く)

ポイントアイテムYレジスタの値
+1なおり草など$20E1
+2ヨシュアの実など$20E6
+4どでかホネ肉など$20F2
+5ポーションNO9$20F8
0一覧表にないアイテム$20CE

この先が少々ややこしいのでざっと説明してしまうが、後々で各アイテムのポイント数は[$00:0030]に入る。
+2ポイント~+5ポイントについては、Yレジスタの値 + $7F8E02のアドレスに該当のポイント数が入っており、ロードして[$00:0030]に入れる。
なおり草など+1ポイントについては、[$00:0030]に直接$01を入れる。
一覧表にないアイテムは増減が行われないので、この先の処理については記載しない。

アイテムID一致なし処理・一致あり処理どちらも最後は[$1BA1]に飛ぶが、その先のポイント数を読み込むための処理は省略する。
ポイント毎に飛び先が異なり、+1ポイントのアイテムは[$C0/263E]から、それ以外のアイテムは[$C0/2646]から処理が開始になる。
また、それまでの処理でYレジスタの値はいずれも+1されている。
まず、+1ポイントのアイテムの処理を見てみる。

;+1ポイント処理
$C0/263E LDA #$01              ;Aに$01をロード
$C0/2640 BRA $10    [$2652]    ;フラグにかかわりなく常に分岐[$2652]

$C0/2652 STA $30    [$00:0030] ;Aを[$00:0030]に書き込み
$C0/2654 LDA $8E00,y[$7F:AEE2] ;[$7F:AEE2]をロード
$C0/2657 INY                   ;Y + 1

A$01をロードして、それを[$00:0030]に入れる、というシンプルな処理である。
その後の[$8E00,y]のロードだが、これは後で満腹度の入っているアドレス[$00:11F2]を呼び出すための前処理である。
+1ポイント処理の場合、Yレジスタは必ず$20E2が入っており、[$8E00,y]で呼び出されるのは[$7F:AEE2]なのだが、ここには$02が格納されていて、A$0102になる。

;+2ポイント~+5ポイント処理
$C0/2646 LDA $8E01,y           ;[$8E01,y]をロード
$C0/2649 STA $30    [$00:0030] ;[$00:0030]に書き込み
$C0/264B LDA $8E00,y           ;[$8E00,y]をロード
$C0/264E INY                   ;Y + 1
$C0/264F INY                   ;Y + 1
$C0/2650 BRA $06    [$2658]    ;フラグにかかわりなく常に分岐[$2658]

+2ポイント~+5ポイントの時は、[$8E01,y]Aにロードしているが、これが各ポイントに対応した数値の入っているアドレスである。

ポイントアイテムアドレス数値
+2ヨシュアの実など$7F:AEE8$02
+4どでかホネ肉など$7F:AEF4$04
+5ポーションNO9$7F:AEFA$05

読み込まれた数値は[$00:0030]に書き込まれる。
$C0/264Bは、+1ポイント処理の時と同じく、満腹度の入っているアドレス[$00:11F2]を呼び出すための前処理にあたる。
この時点での[$8E00,y]には、どれでも$02が入っている。

ここで+1ポイント処理と+2ポイント~+5ポイント処理が合流する。

;共通処理
$C0/2658 REP #$20              ;Mフラグをクリア Aレジスタは16bit幅
$C0/265A AND #$00FF            ;Aと$00FFで論理積
$C0/265D CLC                   ;キャリーフラグクリア
$C0/265E ADC #$11F0            ;A + $11F0
$C0/2661 TAX                   ;Aレジスタの値をXレジスタに転送
$C0/2662 SEP #$20              ;MフラグON Aレジスタは8bit幅
$C0/2664 LDA $00,x  [$00:11F2] ;Aに[$00:11F2](満腹度)をロード
$C0/2666 CLC                   ;キャリーフラグクリア
$C0/2667 ADC $30    [$00:0030] ;A + [$00:0030](与えたアイテムのポイント)
$C0/2669 STA $00,x  [$00:11F2] ;Aを[$00:11F2](満腹度)に書き込み
$C0/266B BRL $F533  [$1BA1]    ;[$1BA1]へ

$C0/2658$C0/265Aで、Aは16bitモードのため、論理積を取ると必ず$0002になる。
$C0/265E$11F0を加算することで、A$11F2になり、そのままXレジスタに転送されている。
$C0/2664ではA[$00,x]をロードしているが、$00 + $11F2だから、呼び出したアドレスは[$00:11F2]、つまり満腹度のアドレスである。
$C0/2667で、ポイント数の入っている[$00:0030]と、満腹度[$00:11F2]を足している。
つまりサモに与えたアイテムのポイントが、満腹度に加算された、ということになる。
これでサモの満腹度が新たな値に更新されたことになる。

この後も処理が続くが、重要な部分のみ取り上げる。
サモにアイテムを与えた場合は、持ち物欄から与えたアイテムの個数を1減らす必要があるので、その処理の部分を紹介する。

;持ち物欄ループ処理
$C0/4839 LDA $00,x   ;Aに[$00,x](持ち物欄$00~$FFの中のアイテムID)をロード
$C0/483B CMP $013D   ;Aと[$00:013D](与えたアイテムID)を比較
$C0/483E BNE $05     ;ゼロフラグが立っていないとき[$4845]分岐
$C0/4845 INX         ;Xをインクリメント
$C0/4846 INY         ;Yをインクリメント
$C0/4847 CPX #$0C00  ;Xレジスタと$0C00を減算比較
$C0/484A BNE $ED     ;ゼロフラグが立っていないとき[$C0/4839]分岐
;ループ処理ここまで
;
$C0/4840 LDA $0000,y ;Aに[$0000,y](持ち物欄の該当アイテムの個数)をロード
$C0/4843 BNE $0A     ;ゼロフラグが立っていないとき[$484F]分岐
$C0/484F DEC A       ;Aをデクリメント(-1)
$C0/4850 STA $0000,y ;Aを[$0000,y]に書き込み
$C0/4853 BNE $02     ;ゼロフラグが立っていないとき[$4857]分岐

最初の方に書いたが、持ち物欄関係のアドレスは、

  • 所持しているアイテム名のID一覧:$00:0B01$00:0C00
  • 一覧に対応したアイテム個数:$00:0C01$00:0D00

にある。
上の持ち物欄ループ処理の部分は、開始時点でX$0B01が入っている。
ループ処理を開始すると、サモに与えたアイテムIDと、持ち物欄に入っているアイテムのID([$00:0B01][$00:0C00])を一致するまでXを増やしつつチェックしている。
ループの終了は、$0C00Xを減算比較してゼロになるまでである。これで持ち物欄の255枠をすべてチェックできる。
ループ処理で該当アイテムを見つけたらループ処理を抜けて、今度はAに該当アイテムの個数をロードし、個数を-1して新たに該当アイテムの個数に書き込みして処理終了である。
一応、$C0/4843で、持ち物欄の該当アイテムの個数がゼロかどうか、ゼロフラグで判断しているが、意味があるのかどうかは筆者にはわからない(エラーやバグがない限り、所持アイテムの個数が0というのはなさそうな気がするが)。
最後の$C0/4853でのゼロフラグチェックは、該当アイテムの個数が0になった時、アイテム欄の枠自体からアイテムを削除する処理へ飛ぶかどうかの分岐である。

ここまで処理したところで、与えたアイテムをサモが食べるモーションやセリフが入る。
満腹度が20(16進数だと$14)を越えているかどうかを判定するのは、食べ終えた直後である。

$C0/2696 LDA $00,x  [$00:11F2]   ;Aに[$00:11F2](満腹度)をロード
$C0/2698 CMP $8E01,y[$7F:AF52]   ;Aと[$7F:AF52](=$14)と減算比較
$C0/269B BEQ $12    [$26AF]      ;ゼロフラグが立っているとき[$26AF]分岐
$C0/269D BCC $09    [$26A8]      ;キャリーフラグが立っていないとき[$26A8]分岐

$C0/269Bでゼロフラグが立つのは、最後に与えたアイテムでちょうど満腹度が満たされた、つまりぴったり20になった時である。
$C0/269Dでキャリーフラグが立つのは、最後に与えたアイテムで満腹度が21以上になった時である。
よって、$C0/269Bの分岐先[$26AF]と、$C0/269Dでキャリーフラグが立たずそのまま処理を続けた先は、サモが仲間になる判定である。
$C0/269Dでキャリーフラグが立たない場合は満腹度が20未満なので、[$26A8]に飛び、サモは再び倒れることになる。

未登場アイテムの処理

以上で、ゲーム内における通常の処理は終了である。
気になるのは、「サモに与えることができるアイテムID一覧表」における、最終編には実際に登場しないアイテムについてである。
途中で以下の表を載せたが、X + $8E00のアドレスに入っている数値から、満腹度用のポイントが割り出せることが判明している。

IDアイテムX + $8E00数値
$01なおり草$7F:AE9A$E1
$02ヨシュアの実$7F:AE9C$E6
$03アリスのビスケ$7F:AE9E$E6
$06エデンズアップル$7F:AEA0$F2
$28ホネ肉$7F:AEA2$E6
$29どでかホネ肉$7F:AEA4$F2
$4Dバーボン$7F:AEA6$E1
$4Eテキーラ$7F:AEA8$E6
$66にんじん$7F:AEAA$E1
$67てんむす$7F:AEAC$E6
$68かすていら$7F:AEAE$E6
$8Aド根性焼き$7F:AEB0$F2
$A4たい焼き$7F:AEB2$E1
$AFバナナクレープ$7F:AEB4$E6
$B7ミサワ焼き$7F:AEB6$EC
$BDあんまん$7F:AEB8$E1
$BE肉まん$7F:AEBA$E6
$BFももまん$7F:AEBC$E1
$C0フカヒレまん$7F:AEBE$EC
$CF老酒$7F:AEC0$E1
$DBシロツメ草$7F:AEC2$D2
$DCペンペン草$7F:AEC4$D2
$DDブタ草$7F:AEC6$D2
$DEオオイヌノフグリ$7F:AEC8$D2
$DF守体草$7F:AECA$D2
$8BポーションNO9$7F:AECC$F8

$E1」なら+1ポイント、「$E6」なら+2ポイント、「$F2」なら+4ポイント、「$F8」なら+5ポイントである。
では、これ以外の値、「$EC」と「$D2」は一体何だろうか。
$EC」については察しがつく。「$E6」と「$F2」の間だから、+3ポイントに設定されているのだろう。該当するのは最終編には出てこない「ミサワ焼き」「フカヒレまん」である。
だが、表の最後の方の「シロツメ草」~「守体草」の「$D2」は何なのか。

諸々を端折って、「$D2」だった場合どうなったかを見てみると、まず、満腹度が$00かどうかを判断する。
満腹度が$00なら、[$00:0030]$00を入れ、それ以外なら[$00:0030]$FFを入れる。
すると、満腹度[$00:11F2][$00:0030]を足す共通処理の時にどうなるか。

$C0/2664 LDA $00,x  [$00:11F2] ;Aに[$00:11F2](満腹度)をロード
$C0/2666 CLC                   ;キャリーフラグクリア
$C0/2667 ADC $30    [$00:0030] ;A + [$00:0030](与えたアイテムのポイント)
$C0/2669 STA $00,x  [$00:11F2] ;Aを[$00:11F2](満腹度)に書き込み
$C0/266B BRL $F533  [$1BA1]    ;[$1BA1]へ

満腹度が$00の時は、$00を足すから何の変化もなく$00のままである。
一方、満腹度が$01以上の時に$FFを足すと、桁溢れが起こる。
例えば満腹度が$05の時だったら、$05 + $FF = $104 である。
ここでは8bitモードなので、桁溢れが起きてキャリーフラグが立ち、$C0/2669には下2桁1バイト分だけが入るから$04となる。
結局、$05から$04に減った。
つまり、-1と同じ処理が起きたのである。

ということは、「シロツメ草」~「守体草」をサモに与えると、満腹度が0の時は0のまま、1以上ならポイントが-1される、ということである。
製品版では使われていないが、満腹度が減った時用のサモのセリフもデータとして存在している。
SFC版攻略本にも、これらアイテムを与えると満腹度が-1される、とあるが、その通りだったのである。
セリフまで用意されていることも含め、製品版に入れられる状態まで完成していたが、没にしたのだろう。
理由はわからないが、ただでさえ20ポイント分アイテムを与えなければならないのに、ポイントが減ってしまうアイテムがあるのはさすがにきつい、と判断されたのだろうか。
アイディアとしては面白くても、ゲームプレイの快適さと天秤にかけた場合、快適さを取ったということかもしれない。



このページをシェアする

上へ