個別処理
以下の話題をまとめています。
乱数管理
概要
乱数は、0x7e01ce~0x7e01d5の8バイトで管理しており、場面に応じて連続する2バイト(ワード)を使い分けます。
乱数計算自体は、15次M系列によるLFSRのビット列更新で賄うため規則そのものは単純ですが、各フレームで更新が何回走るかは次フレーム移行までに充てられる処理時間に依存するため、予測困難となっています。
乱数計算自体は、15次M系列によるLFSRのビット列更新で賄うため規則そのものは単純ですが、各フレームで更新が何回走るかは次フレーム移行までに充てられる処理時間に依存するため、予測困難となっています。
乱数更新
乱数更新は次図の通り、8バイト64ビットを1ビットずつずらしつつ、0x7e01ceのMSBを新たに計算するように行います。


これは、b[n]=b[n-7]+b[n-15] mod 2 の漸化式に基づく15次M系列LFSRを実装したものです。そのため、周期32767での繰り返しになっています。
実際は、乱数はワード(2バイト)単位で使用するため、ワードの値として次の関係式があると見なすことができます。なお、初期値は電源投入/リセット直後に W[0]=1 が設定されます。
実際は、乱数はワード(2バイト)単位で使用するため、ワードの値として次の関係式があると見なすことができます。なお、初期値は電源投入/リセット直後に W[0]=1 が設定されます。
- ワード漸化式: W[n]=f(W[n-1]), f(w)=((w&1)<<15) | ((w&0xfeff)>>1) | ( ((w&0x200)>>2)^((w&2)<<6) )
※リトルエンディアンのため、ビット順が一部ねじれているように見えることに注意 - 保持しているワード: 偶数アドレス開始だと順にW[n],W[n-16],W[n-32],W[n-48]の4ワードですが、奇数アドレス開始の場合もあり、その場合 W[n-8],W[n-24]等、中間の世代の値になります。

乱数用途
- 揺れの間隔のランダム補正
揺れの次の周期までのフレーム数(ワード) 0x7e034c を 0x82abfa からのルーチンで計算する際の補正値として、0x7e01d0 の乱数ワードを用います。
乱数の下位9bit(0~511)をxとした場合、xが奇数の場合 3600-x、偶数の場合 3600+x を新しい値として決定します。 - 傾きパターンA/Bの決定
10秒間の揺れが終わって次の周期に移行する際、傾きがAパターン(一段階傾き変化して終わり)、Bパターン(一段階変化直後に元の傾きに戻る)の判断を行うときに、0x7e01ceの乱数ワードを用います。
乱数ワードの下位3bitが7であればBパターン、それ以外はAパターンになります。そのため、Bパターンになる確率は単純には 1/8 と言えます。
なお、具体的な判断の箇所は 0x82991a のルーチンの 0x829bfd の処理からです。 - 傾き方向の決定
揺れの周期が次に移るときに傾きが限界でない場合 (例えばボイラー爆発前で反時計+22.5°の場合は時計回りしかないので除外)、乱数0x7e01ceの偶奇で傾きの回転方向の判定を行います。
偶数の場合は時計回り、奇数なら反時計となります。
上記傾きパターンA/Bの決定がAだった場合、同一フレームでA/B判定と共通の乱数で判定を行うため、反時計の方が割をくって起こりにくくなっています。逆にBだった場合は次のフレームまで待って乱数が更新されてから判定を行うため、確率は純粋に半々です。つまり、4/8の確率でA+時計回り、3/8の確率でA+反時計回り、B+時計回り/反時計回りがそれぞれ1/16の確率ということです。
なお、具体的な判断箇所は、Aの場合は 0x82991aのルーチンの0x829c6aから、Bの場合は 0x829dabのルーチンの 0x829df8からです。 - 悲鳴SEの選択
揺れの周期で傾きが変化する時、演出効果として悲鳴のSEが0x829b34からのサブルーチン0x809745のコールによって、小さな音で鳴らされます。
この際、まず演出が入るかどうかに 0x7e01ce の乱数を用います。(確率1/4で鳴らす)。
そして演出が入る場合、7種類の悲鳴SE(34~40)のどれを選ぶかに、0x7e01cf の乱数を使用します。(40番のみ2/8、他は1/8ずつの確率) - 雷鳴演出
おそらくプロローグの場面で、演出効果として SE ID1の雷鳴(音量200)を 0x82aabf からのサブルーチン 0x809745 で鳴らすかどうかを、0x7e01ce の乱数で判定します。( 確率1/512 )
低確率に見えますが、判定自体は毎bf行うと考えられるため、実際は平均17秒間隔で雷鳴がとどろくような演出になります。 - 爆発演出
裏エリアの吹き抜けで、爆発の演出のため 0x82c1f2~ の SE 12,13 を鳴らす等の処理を行うかの判定を、0x7e01ceの乱数で行います。( 確率1/128 ) - 愚痴メッセージ表示
下の「メッセージ処理」で解説している、カテゴリ6の「愚痴」に相当するメッセージ表示時に、0x7e01ce の乱数ワードを使用します。( 確率1/512 )
判定はキャラ毎ですが、同一タイミングなら乱数も共通です。ただし、キャラの順番に応じて 2,4,6,… の補正値を加算して判定に用いるため、結果が共通になるとは限りません。
コード
乱数更新は、0x808012からのルーチンで行います。
;乱数更新(A:8bit,X:16bit)
L808012: ldx.w #$01ce ; a2 ce 01
808015: lda.b $00, x ; b5 00
808017: eor.b $01, x ; 55 01
808019: and.b #$02 ; 29 02
80801b: clc ; 18
L80801c: beq L80801f ; f0 01
80801e: sec ; 38
L80801f: ror.b $00, x ; 76 00
808021: ror.b $01, x ; 76 01
808023: ror.b $02, x ; 76 02
808025: ror.b $03, x ; 76 03
808027: ror.b $04, x ; 76 04
808029: ror.b $05, x ; 76 05
80802b: ror.b $06, x ; 76 06
80802d: ror.b $07, x ; 76 07
80802f: rts ; 60
上記乱数更新ルーチンを呼び出すのは、0x808030からのルーチンのうち、以下の部分です。
;見かけ上無限ループ
808061: inc.b $0180 ; ee 80 01
L808064: jsr L808012 ; 20 12 80
808067: lda.b $0180 ; ad 80 01
L80806a: bne L808064 ; d0 f8
上記処理は、フラグバイト 0x7e0180 が一旦設定された後無限ループになるように見えますが、実際はNMI(V-Blank)による 0x8090b3 からの割り込みルーチンの以下の箇所でゼロクリアされるため、無限ではありません。
しかしこのことにより、処理内のループ回数が処理時間依存になっており、乱数変化の事前予測が非常に困難となっています。
※フレームによっては乱数更新の 0x7e0180 フラグ設定に至ってない状況も想定されているようで、フラグ未設定時の分岐もあります。おそらくフレーム内にメインの処理が完結したかどうかのフラグを兼ねていると推測できます。
しかしこのことにより、処理内のループ回数が処理時間依存になっており、乱数変化の事前予測が非常に困難となっています。
※フレームによっては乱数更新の 0x7e0180 フラグ設定に至ってない状況も想定されているようで、フラグ未設定時の分岐もあります。おそらくフレーム内にメインの処理が完結したかどうかのフラグを兼ねていると推測できます。
;フラグクリア箇所
8090c7: lda.b $0180 ; ad 80 01
L8090ca: beq L8090db ; f0 0f
8090cc: stz.b $0180 ; 9c 80 01
メッセージ処理
概要
ここで言うメッセージ処理は、アクション領域の下部の様々なメッセージが表示される際の処理を指します。
※各キャラのセリフだけでなく、OPデモの英文和訳やEDでの後日談エピソード表示、またキャラと会話する際のプロンプト表示にも関係します。
※各キャラのセリフだけでなく、OPデモの英文和訳やEDでの後日談エピソード表示、またキャラと会話する際のプロンプト表示にも関係します。
メッセージ処理は4系統(内1系統はおそらく不使用)ありますが、いずれも 0x7e024c~の16文字2行分のバッファを更新することで、最終的に画面表示に反映させます。
※実際は16文字目の分は画面に収まりきらないので、最大でも15文字以内で行が構成されます。
メッセージの内容を識別する数値を、ここではメッセージIDとします。しかし、同じメッセージIDでも状況によって異なる内容になります。これは、メッセージの参照先が複数あるからですが、これを区別するものをカテゴリと呼ぶことにします。
メッセージは特定の値を終端とする不定長のバイト列で管理され、ここから表示される文字が決定されるのですが、この時に使用される文字コード表も場面に応じて複数使い分けられています。
※実際は16文字目の分は画面に収まりきらないので、最大でも15文字以内で行が構成されます。
メッセージの内容を識別する数値を、ここではメッセージIDとします。しかし、同じメッセージIDでも状況によって異なる内容になります。これは、メッセージの参照先が複数あるからですが、これを区別するものをカテゴリと呼ぶことにします。
メッセージは特定の値を終端とする不定長のバイト列で管理され、ここから表示される文字が決定されるのですが、この時に使用される文字コード表も場面に応じて複数使い分けられています。
具体的なメッセージの一覧については、wikiのメニューの「メッセージ一覧」から、各カテゴリに応じたページをご覧ください。
処理の系統
前述の4系統は次の通りです
- 汎用メッセージ表示処理
会話イベント、ストーリー表示等で汎用的に使われる処理です。 - プロンプト表示
ANSWER? や COMMUNICATION? という2種類のプロンプト表示の処理です。 - 操作状況に対応したメッセージの表示処理
イベント以外のキャラ操作・アクション状況に応じて表示されるメッセージに関わる処理です。
具体的には、ロスト状態のキャラを呼んだときの「まるできこえていないな」といったメッセージや、体力を消耗したキャラが「わたしすこしやすみたいわ」と訴えるようなものが該当します。
また、案内板(船内各所に設置された地図)の説明文表示も、同じ処理で対応しています。 - 合成メッセージ処理※不使用と思われる処理
こちらは、キャラの名前とその他のパーツを合成して、それを表示するという二段階になっている処理です。
合成したデータを保持するために0x7e149e~の領域を使用します。
おそらく、誰がアクションを行っているかを明示するために名前を表示するような想定で設けられた機能かと思いますが、実際に使われている場面に遭遇することはないため、没になった機能と思われます。
メッセージのカテゴリ
以下のように7種類のカテゴリに分けられます。カテゴリの番号については適当に割り振ったものです。
- カテゴリ1: OP/ED用メッセージ
OPデモ、キャラセレクト・ゲーム開始時と、エンディングに関わるメッセージをまとめて管理するカテゴリです。 - カテゴリ2: 生存者氏名
エンディングで生存者がリストアップされる時の氏名を管理するカテゴリです。 - カテゴリ3: プロローグ時共通メッセージ
プロローグで各NPCがしゃべるセリフの中で、主人公キャラの選択に依らないものを管理するカテゴリです。 - カテゴリ4: 地図説明文
船内の案内板(地図)を見た時の、場所の説明文を管理するカテゴリです。 - カテゴリ5: メッセージパーツ
前述の処理系統のうち「合成メッセージ処理」に使う、パーツを管理するカテゴリです。キャラ名を保持する5yとそれ以外の5zのサブカテゴリに分かれます。ただし、実際には使われないものと思われます。 - カテゴリ6: 操作に対応するメッセージ
前述の処理系統のうち「操作状況に対応したメッセージの表示機能」で用いるメッセージを管理するカテゴリです。これは更に、誰を主人公にするかで4つのサブカテゴリに分かれます。ここではキ/レ/ル/ジに応じて 6c,6r,6l,6j としています。 - カテゴリ7: 一般のメッセージ
その他一般のメッセージ(各種イベントやプロローグ・エピローグのストーリー含む)を管理するカテゴリで、大量のメッセージ情報を含みます。こちらも誰を主人公にするかで4つのサブカテゴリに分かれるため、ここでは 7c,7r,7l,7j としています。
コード表
各文字は1バイト(0~255)のデータとして管理されます。
このうち、254は行終端、255は文字列終端として特別な意味を持つため、実際に表示される文字の対応はありません。また、252,253は他に使用しているメモリ領域と被るため使えませんが、残りの252種類の値にはそれぞれ表示用のフォントデータが対応します。
※メッセージの中には終端の255の1バイトのみのものもあります。これは使われないメッセージあるいは空メッセージを意味します。
このフォントデータ(コード表)は5種類存在し、場面に応じて使い分けられます。
これらは、コード表3をベースに一部を差し替える形で整備されています。
このうち、254は行終端、255は文字列終端として特別な意味を持つため、実際に表示される文字の対応はありません。また、252,253は他に使用しているメモリ領域と被るため使えませんが、残りの252種類の値にはそれぞれ表示用のフォントデータが対応します。
※メッセージの中には終端の255の1バイトのみのものもあります。これは使われないメッセージあるいは空メッセージを意味します。
このフォントデータ(コード表)は5種類存在し、場面に応じて使い分けられます。
これらは、コード表3をベースに一部を差し替える形で整備されています。
- コード表1: OPデモで流れるストーリーの和訳の表示用
コード表3の先頭144文字以外を差し替えたものです - コード表2: キャラ選択と決定時の説明文の表示用
コード表3と先頭174文字が共通、176文字目(0xb0)からの48文字を差し替えたものです。
なお使用しませんが、214文字目(0xe0)からの24文字はコード表3の48文字目(0x30)からの繰り返しになっています。 - コード表3: プロローグ~エピローグまで、メインで使用するもの
- コード表4: エンディング(生存者リストアップまで)での後日談ストーリーの表示用
コード表3と先頭174文字が共通、176文字目(0xb0)からを差し替えています。 - コード表5: ベストエンディングでの追加ストーリー分の表示用
コード表3の先頭112文字以外を差し替えたものです
コード表中の灰色部分は、明示的なデータ割り当てがないものの、ゼロクリアされたメモリに対応することで結果的に空白と同じ効果を持つものを表します。
※基本使われない部分なのですが、なぜか 0xf8 の文字だけは使われる場面があります。
なお、文字データは基本的に仮名や漢字1文字ずつに対応するものですが、中には特殊なフォントや、異なるピッチで文章を表示するために複数文字をまとめて分割したものも含まれます。
※基本使われない部分なのですが、なぜか 0xf8 の文字だけは使われる場面があります。
なお、文字データは基本的に仮名や漢字1文字ずつに対応するものですが、中には特殊なフォントや、異なるピッチで文章を表示するために複数文字をまとめて分割したものも含まれます。





メッセージデータ管理詳細
各メッセージは、同一カテゴリのデータは同一のバンク(SFC/SNES空間を16bitずつに区切った単位)のROM領域で管理されます。
※異なるカテゴリで同一のバンクになるものもあります。
※異なるカテゴリで同一のバンクになるものもあります。
メッセージデータは不定長であるため、メッセージIDに応じた先頭アドレス(16bit)を管理する配列領域と、各メッセージデータをつなげた領域の2段階での管理となります。両者は同一バンクに存在します。
例えばカテゴリ4の場合、バンク0x9cのアドレス0x8002(0x9c8002)に、メッセージID 1番のアドレス0x8048(0x9c8048)が載っていて、0x8055にあるバイト255までで一区切り、アドレス0x8004(0x9c8004)にはメッセージ2番のアドレス0x8056が載っていて、これは1つ前のメッセージの次の領域になっている…といった配置になっています。
なお、ROM上の管理はバイト単位ですが、実際に2行分のメッセージデータバッファ 0x7e024c~に保存する際にはワードデータに変換します。
変換規則は、バイトデータ x に対して、0x1c00|((x&f8)<<2)|((x&7)<<1) です。特にデータ 0 は 0x1c00 に変換され、これは空白による表示位置調整に使用されます。
以下、カテゴリ毎のデータ配置の詳細です。
例えばカテゴリ4の場合、バンク0x9cのアドレス0x8002(0x9c8002)に、メッセージID 1番のアドレス0x8048(0x9c8048)が載っていて、0x8055にあるバイト255までで一区切り、アドレス0x8004(0x9c8004)にはメッセージ2番のアドレス0x8056が載っていて、これは1つ前のメッセージの次の領域になっている…といった配置になっています。
なお、ROM上の管理はバイト単位ですが、実際に2行分のメッセージデータバッファ 0x7e024c~に保存する際にはワードデータに変換します。
変換規則は、バイトデータ x に対して、0x1c00|((x&f8)<<2)|((x&7)<<1) です。特にデータ 0 は 0x1c00 に変換され、これは空白による表示位置調整に使用されます。
以下、カテゴリ毎のデータ配置の詳細です。
| カテゴリ | バンク | 管理配列 ベースアドレス |
メッセージID 範囲 |
メッセージ 保存範囲 |
備考 |
|---|---|---|---|---|---|
| 1 | 0x84 | 0x8000 | 0~0x48 | 0x809e~0x8568 | このカテゴリのみ、適用するコード表が 1,2,4,5と複数存在します |
| 2 | 0x87 | 0x8000 | 0~0x3e | 0x807e~0x8210 | 生存者となりうるキャラの氏名で構成され、適用するコード表は4です。 中に「ブライアン=ディクスター」という氏名もあります。 おそらく没キャラです。 |
| 3 | 0x9b | 0x8348 | 0~0xc6 | 0x84d6~0x8f1f | 主人公依存と思われるネルソン君との会話も含まれてますが使用されません。 ※カテゴリ7j収録のメッセージが使われます。 |
| 4 | 0x9c | 0x8000 | 0~0x23 | 0x8048~0x821c | |
| 5y | 0x86 | 0x8000 | 0~0x3e | 0x8073~0x817c | |
| 5z | 0x85 | 0x8000 | 0~0x18 | 0x8032~0x812a | |
| 6c | 0x8b | 0x82d0 | 1~0x85 | 0x83dc~0x8af9 | |
| 6r | 0x8b | 0x8afa | 1~0x7b | 0x8bf2~0x9282 | |
| 6l | 0x8b | 0x9283 | 1~0x76 | 0x9371~0x9a04 | |
| 6j | 0x8b | 0x9a05 | 1~0x70 | 0x9ae7~0xa132 | |
| 7c | 0x90 | 0x8000 | 0~0x815 | 0x902c~0xd3a8 | メッセージID 0,1 は全主人公共通の「プロンプト表示」用です。 |
| 7r | 0x9d | 0x8000 | 0~0x80a | 0x9016~0xdd28 | |
| 7l | 0x83 | 0x8000 | 0~0x884 | 0x910a~0xdf9d | |
| 7j | 0x88 | 0x8000 | 0~0x81b | 0x9038~0xe1ea |
各系統処理概要
- 汎用メッセージ表示処理
- 0x80cd2cのルーチンで処理を行います、予め $024a にメッセージIDをセットしておきます。
- $02ecが非ゼロの場合は、プロローグの共通メッセージと判断し、カテゴリ3のメッセージをロードします。
なお、$02ec は場面 (部屋や表エリアの各ブロック) に入る毎に切り替わります。つまり、主人公固有のキャラがいる領域ならゼロが、共通のキャラがいる領域なら非ゼロがセットされるということです。 - 進行度$0354が特定の値の場合、対応したカテゴリのメッセージをロードします。
進行度5(OPデモ~ゲームスタート)、-2(エンディング共通)、-3(ベストエンディング)ならカテゴリ1、進行度10(エンディングでの生存者表示)ならカテゴリ2のメッセージをロードします。 - その他のケース(プロローグ~エピローグ)では、$02c8の示す主人公に応じて7c,7r,7l,7jのカテゴリのメッセージをロードします。
- プロンプト表示
- 0x80ce98のルーチンで処理を行います。メッセージIDを保存するのは $024a ではなく $02a0 です。
- 対応するメッセージIDは0,1のみですが、$02a0には+1した値として1,2を予め指定します。
- 主人公によらず、カテゴリ7cのメッセージをロードします。0,1に対してそれぞれ"ANSWER?","COMMUNICATION?"のプロンプトが対応します。
- カテゴリ7r,7l,7jのメッセージID0,1にも同様のデータが保存されていますが、こちらは使いません。
- 他のメッセージ処理と異なり、このプロンプトは左詰めで表示されます。
- 操作状況に対応したメッセージの表示処理
- 0x80e129のルーチンで処理を行います。予め $024a にメッセージIDをセットしておきます。
- 案内板(船内各所に配置されている地図)を見る場合、$0390に非ゼロがセットされているのを検出し、カテゴリ4のメッセージをロードします。
- $0390がゼロの場合、主人公または同行者のメッセージを、$02c8の示す主人公に応じて6c,6r,6l,6jのカテゴリから選んでロードします。
- 合成メッセージ処理
- 0x82d29fのルーチンからそれぞれ呼び出される、0x82d748, 0x82d748の各ルーチンでパーツをロードし、合成して$149e~のバッファに格納します。
- 最初にロードするのがカテゴリ5yのキャラクター名、続いてロードするのがカテゴリ5zのその他のパーツです。
- $149e~のバッファから0x7e024c~のバッファへ反映するのは、別途0x80e23fのルーチンが対応します。
メッセージチャンク
※外部サイト紹介に挙げているサイト運営者のたままーさんに頂いた解析資料により詳細が判明しました。この場を借りてお礼申し上げます!
イベントにおいては、上で整理したメッセージは個別に扱われるのではなく、ある程度のまとまりで管理されています。これをここでは(メッセージ)チャンクと呼ぶことにします。
チャンクには1~のIDが割り振られており、別々の主人公キャラでIDは重複します。また、主人公に依存しないプロローグの共通イベントにも同様にIDが割り振られています。
チャンクの一覧については、メニューの「メッセージチャンク一覧」からご参照ください。
チャンクには1~のIDが割り振られており、別々の主人公キャラでIDは重複します。また、主人公に依存しないプロローグの共通イベントにも同様にIDが割り振られています。
チャンクの一覧については、メニューの「メッセージチャンク一覧」からご参照ください。
例えばキャラと会話してメッセージが表示されると、会話が収まるまで関連するメッセージが自動で流れるのが分かります。この「自動で流れる一連のメッセージ」がチャンクに相当します。
メッセージの一覧をご覧いただくと、関連するメッセージが固まって存在することにお気付きかと思いますが、チャンクは連続するIDのメッセージから構成されます。
また、"ANSWER?"とプロンプトが出るような会話のケースの場合、応答次第で分岐してさらに自動でメッセージが流れます。この遷移もチャンクの管理データとして保持しています。( プロンプトが出ない場合の自動遷移もあります )
以下、管理データの概要です。
メッセージの一覧をご覧いただくと、関連するメッセージが固まって存在することにお気付きかと思いますが、チャンクは連続するIDのメッセージから構成されます。
また、"ANSWER?"とプロンプトが出るような会話のケースの場合、応答次第で分岐してさらに自動でメッセージが流れます。この遷移もチャンクの管理データとして保持しています。( プロンプトが出ない場合の自動遷移もあります )
以下、管理データの概要です。
- 主人公別チャンク管理データ
- バンク0x9aの0x8000から、チャンクあたり5バイトのデータの配列として管理されます。
- キ/レ/ル/ジのそれぞれチャンクID1から順に、522, 524, 539, 522 のチャンクが収録されています。
- チャンク内の5バイトを16進数として AB,CD,EF,GH,IJ とした場合、以下の構成になっています。
- DAB … 開始メッセージIDから1引いた値
- C … チャンクに含まれるメッセージ数 ( 1~15 )
- G … 8以上の場合、チャンク終了時に"ANSWER?"のプロンプトが出ることを示します
- GHE&0x7ff … "ANSWER?"のプロンプトが出るケースで、応答した場合の遷移先のチャンクIDです。
- FIJ … "ANSWER?"のプロンプトが出るケースで、無視した場合の遷移先のチャンクIDです。
遷移がなく一旦会話が途切れる場合は 0 が設定されています。
- 例えばレドウィンのチャンクID 5 は、それ以前のキャプリスの分も併せると 527番目の 9a8a46 ( 9a8a00+5*526 ) に格納されており、 1a,20,20,80,05 というバイトの並びから、開始メッセージ27、メッセージ数2、"ANSWER?"のプロンプトあり、応答すると次のチャンクは2、無視すると次のチャンクは5(同じチャンクの繰り返し)であることが分かります。
- プロローグ時共通メッセージ用
- バンク0x9bの0x8000から、チャンクあたり10バイトのデータの配列として管理されます。
- チャンク内は2バイトワードデータ×5で以下のような構成になっています。
- オフセット0 … 開始メッセージIDから1引いた値
- オフセット2 … チャンクに含まれるメッセージ数 ( 1~ )
- オフセット4 … 4 もしくは 0 で、4の場合はチャンク終了時に"ANSWER?"のプロンプトが出ることを示します。
- オフセット6 … "ANSWER?"のプロンプトが出るケースで、応答した場合の遷移先のチャンクIDです。
- オフセット8 … "ANSWER?"のプロンプトが出るケースで無視した場合、あるいはプロンプトが出ないケースの遷移先のチャンクIDです。
遷移がなく一旦会話が途切れる場合は 0 が設定されています。
「操作状況に対応したメッセージ」に関してはチャンクという管理にはなっていませんが、複数メッセージを連続で流すケースも想定して、先頭メッセージ・連続メッセージ数のペアで管理している部分もあります。
- 82d172~82d1a5
- 地図の案内図ID(1~26)に応じた、カテゴリ4の先頭メッセージIDと連続メッセージ数のペアが保持されています
- ペアの選択は、案内図ID($03ca: 1~26)を配列のインデクス(1開始)として行います
- 82cba3~82cbb2
- 単発の主人公メッセージとして、カテゴリ6のメッセージIDが保持されています
- メッセージIDの選択は、$03c8を配列のインデクス(0開始)として、サブルーチン0x82cbf3で行います
- メッセージIDそのものは、各主人公で共通です。( 参照するメッセージの内容は異なります )
- 選択されたメッセージIDが7以下の場合、50%のランダムで+1の補正が入ります。
つまり、同じシチュエーションに2つのメッセージが半々で現れることになります。 - 実際に使われるのは、施錠されているドア、同行者のミス、自身の体力枯渇の予兆、ロスト状態のキャラをL/Rで呼んだ時の4パターンのみです。
- 82cbb3~82cbf2
- 連続した複数の主人公メッセージとして、カテゴリ6の先頭メッセージIDとメッセージ数の組が保持されています
- メッセージIDの選択は、$03c8-16を配列のインデクス(0開始)として、サブルーチン0x82cbf3で行います
※$03c8が16未満の場合は、前項の単発メッセージと解釈されます - このテーブルは主人公毎に分かれています
- 実際に使われるのは、インデクス0,1の、転覆直前/直後の主人公の独白のみです
- その他
- 同行者が場面に応じて発する単発のメッセージは直接メッセージIDを計算します
- 対象のキャラに応じて同一内容でも8種類(0~7)のバリエーションがあり、メッセージIDに対する補正値として効果を表します。
その補正値は82d0c3~82d102にあります。モブキャラ用の値は0xffで「メッセージ表示なし」という扱いですが、なぜか救出可能キャラの中で唯一、クレイバーにもこの0xffが割り当てられています。 - メッセージIDは、主人公毎のオフセット値(82d103~82d106にある)+内容に応じた値(0~6)×8+キャラ毎の補正値(0~7)で決定されます。
※キャラ毎の補正値についてはキャラクターデータの表でmsg種として記載しています。 - 内容に応じた値の内訳は次の通りです
- 0: 一画面引き離し
画面切り替えを司るサブルーチン 0x81b516 内で値 0 がセットされます。対象となるキャラは同行者の先頭(最後に救出したキャラ)です。 - 1: 再合流
イベント処理のトップのサブルーチン 0x81c440 内で値 1 がセットされます。対象となるキャラは、ロスト者の末尾(残存している中で最初に救出したキャラ)です。 - 2: 非難
主人公を非難するメッセージですがゲーム内では使用されません。メモリ書き換え等で他のメッセージの代わりに表示させるようにすると、非常に心苦しい誘導を経験できます。 - 3: 体力消耗
キャラ個別処理を行うサブルーチン 0x81be02 から呼び出されるサブルーチン 0x81a8b9 内で値 3 がセットされます。対象は条件を満たした同行者キャラです。
契機は2酒類あり、非連れ歩き状態で体力32を切った場合と (強制休憩)、マーカー到着時に体力64を切っている場合です。 - 4: 体力枯渇ミス
キャラ個別処理を行うサブルーチン 0x81be02 から呼び出されるサブルーチン 0x81a8b9 内で値 4 がセットされます。対象は条件を満たした同行者キャラです。
条件は、マーカー到着時に体力枯渇でミスになることで、通常は強制休憩により起こらないため、再合流直後マーカーに到着した時に体力枯渇している状況限定というレアなメッセージになります。 - 5: ケガ
ケガを負ったことを訴えるメッセージです。ゲーム内では使用されません。 - 6: 愚痴
キャラ個別処理を行うサブルーチン 0x81be02 から呼び出されるサブルーチン 0x81a8b9 内で値 6 がセットされます。
対象キャラはマーカーに到着した疲労状態にない(体力64以上の)キャラ全てで、確率1/512です。
同一タイミングで判定する場合、乱数が共通なので確率が人数分とはいきませんが、補正値を加算しての判定になるので全員揃って条件を満たす/満たさないと決まるわけではありません。
- 0: 一画面引き離し
エンディング選択
ボイラー室の脱出口に入った時の、エンディング選択処理についてまとめます。
エンディング選択は、最終的な救助者の確定と、ポイント計算によるエンディング分岐の2段階で行われます。
エンディング選択は、最終的な救助者の確定と、ポイント計算によるエンディング分岐の2段階で行われます。
最終的な救助者の確定
同行者それぞれに判定を行って、最終的な救助者を確定します。
生存エンディングの際に、エンディングで生存者として表示されるキャラの情報の決定でもあります。
生存エンディングの際に、エンディングで生存者として表示されるキャラの情報の決定でもあります。
- 処理箇所
0x81b516からのルーチンの、0x81b534からのループが対象です - 対象者
$021aで示される人数から-1した、主人公以外の同行者分が対象です。
ロスト状態で再合流していないキャラはこの人数に含まれないため、対象外となります。 - 判定対象データ
$04d0~のキャラ管理データAの中で、ユーザ毎の32バイトのブロックの中のオフセット22バイトのワード(マップ内のy座標)により位置を判定します。 - 判定基準
y座標が0x9000未満(上の方が座標が小さい)の場合が対象者となります。0x9000以上の場合は0x8183f1からのルーチンによってキャラ管理データAからデータが削除され、$021aの人数もデクリメントされます。
ゲームの流れで取り上げている、「高台2つ前の足場」のy座標が0x8ff0で、ここがギリギリ範囲内となっています。
ポイント計算
エンディング分岐は、上記処理で残ったキャラのポイントで行われます。重要時運物関連の判定もポイントだけで行われます。
- 処理箇所
場面切り替わり時のイベントID判断を行う0x9feaaeからのルーチンで、場所ID R-63 の場合の特別処理として、エンディング分岐判断も行います。 - ポイント計算
- 0x9feafcからのループで、$021a-1の示す人数(主人公以外の同行者)分、ポイント合計を計算します。
- $04d0~のキャラ管理データAの中で、ユーザ毎の32バイトブロックの中のオフセット8バイトのワード(キャラID)を元に、キャラポイントテーブルからポイントを参照します。
- キャラポイントテーブルは予め主人公$02c8を元に先頭アドレスをc8ee,c96e,c9ee,c96eのいずれかから決定しておきます
- 重要人物の場合は、ポイントの上位バイトに特定の値が設定されているため、後の判断の際の識別情報となります。
エイミー、イスメイ、アデラの場合は0x8000を加算したポイントになっていますが、ステラ、ハリー、ジャックは0x8000を分割して設定されており、全員分揃って「重要人物救出」という判定になるよう調整されています。 - ポイント計算と同時に、各キャラに対してルーチン0x82ea30を呼び、$14d4~の領域へのキャラIDの追加と、$14d2の救出者人数インクリメントも行われます。
※主人公分はまた別の箇所で処理されます。
- エンディング分岐
- ポイント計算で得られた合計値に従い、エンディングIDのベースを決定します。
- そもそも同行者ゼロ($021aの値が1)の場合は、上記ポイント計算なしに、ベース0が決定します。
- ポイント合計が負(重要人物分の0x8000が加算されていると、内部的に負の値と判定されます)の場合、重要人物ありEDと判定されます。
- ポイント合計の下位バイトが25以上の場合エンディングIDのベースが4となります。
- ポイント合計の下位バイトが25未満の場合8がベースとなります。
- ポイント合計が非負の場合(重要人物分の0x8000が揃っていない場合)、重要人物なし/不足のEDと判定されます。
- $0400の値を見て、負の場合「重要人物を説得したが救助できなかった」と判定し、エンディングIDのベースが20となります。
※$0400は、説得完了した生存者のポイントを単純に合計していた値です。
※レドウィンの場合、ステラ、ハリー、ジャック全員を説得した上で、誰か1人でも途中で欠けた場合にこの条件が成立します。 - $0400が非負で、ポイント合計の下位バイトが25以上の場合、エンディングIDのベースが12となります。
- $0400が非負で、ポイント合計の下位バイトが25未満の場合、エンディングIDのベースが16となります。
- $0400の値を見て、負の場合「重要人物を説得したが救助できなかった」と判定し、エンディングIDのベースが20となります。
- 最終的に、主人公を示す$02c8の値(0~3)を足して、エンディングID 0~23 の24通りが決定されます。
※実際には異なるIDで同一エンディングとなるものがあり、エンディングは実質19通りです。 - なお、この時計算したポイント合計値は$0400に反映されます。(スタッフロール後のポイント合計表示に使われます)
揺れの周期と傾き変化
周期的な揺れと、それに伴う傾きの変化は、操作・ルート進行上大きく影響のある、かつ運の絡む要素になっています。
時間の管理
- ワード0x7e0344がフレームカウント(単位はf、1bfに2増加)となっており、各種周期の判定に使われます。
※60分の時間制限の判定のためのカウントとは別です - フレームカウントの一番の利用目的は、進行度更新に関わる周期の蓄積の判断です。その際、3種類の上限値が使われます。
- 周期フレーム上限1(0x7e034c)
傾きの変化が発生する時間を表します。
周期の始まりに、3600fを基準として-511~+510の幅でランダムに変動します。
※正確には、0~511の乱数を引いて、奇数だった場合はマイナスに、偶数だった場合はプラスに補正します。 - 周期フレーム上限2(0x7e034e)
揺れが始まる時間を表します。
上記周期フレーム上限1より常に600f小さい値が設定されます。 - 周期フレーム上限3(0x7e14ec)
揺れに連動して特定の場所で障害物が落下し始める時間を表します。
上記周期フレーム上限1より常に480f小さい値が設定されます。
- 周期フレーム上限1(0x7e034c)
- このフレームカウントは、周期判定以外にも使われることがあります。
- 転覆までの時間
プロローグで自動進行部分(レドウィンの場合は子供とのやりとり含む)が終わるか、プロローグスキップした時点から、2900f (ルークのみ3150f) で転覆直前の予兆の揺れが始まります。
転覆の発生はルークも含め 3600f後です。
この判定に0x7e0344のフレームカウントが使用されます。 - 多段階の傾き
傾きの変化が1段階で収まらない場合、0x7e0344が一旦ゼロクリアされ、次の段階までの上限240fあるいは300fで判定が行われます。
これは、後述するパターンBの傾き変化、+90°をまたいだ傾き変化、ボイラー爆発時の傾き変化が該当します。
※300fはボイラー爆発の場合です
- 転覆までの時間
- 制限時間超過の判定は、経過時間の分を保存する0x7f03e2によって行います。
60分経過ですぐにゲームオーバーになるわけではなく、そこから0x7e14deが最終カウントダウンのタイマーとして使用されます。
まずは揺れが始まり200bf(400f)で沈没の画像のカットイン、その後1000bf(2000f)でボイラー室に到達できなければゲームオーバーとなります。
周期的な傾き変化
周期フレーム上限1に達したところで、傾きの変化が始まります。
この変化にはパターンA,Bの2酒類があり、挙動が変わってきます。
この変化にはパターンA,Bの2酒類があり、挙動が変わってきます。
ただ、どちらの場合も3種類のパラメータ管理が関わってきます。
- 現在の傾き(0x7e0212)
0~512で傾きを管理しており、転覆前の正常時が傾き0、転覆直後の反転状態が傾き256、時計回りに増加 ( 511から増えると0に戻る ) という数値です。
ただし、基本は32単位の16段階となっており、中間的な傾きは傾き変化時限定です。( 傾き変化が終わる時に32単位に丸められる ) - 傾き変化量(0x7e0214)
変化が始まる時点で±32の値が設定されます。+32は反時計回り、-32は時計回りです。毎bfこの値が0に近づくと共に、同じ分だけ上記0x7e0212が更新され、一段階で22.5°の変化が発生します。 - 変化後予定値(0x7e14e0)
傾きの変化が終わった後の予定値を管理するものです。
大抵は、上の2つの値の差と等しいのですが、そうでないことがあり、想定外の動きにつながる場合があります。
敢えて冗長的なこの値を設けているのは、場面切り替えをした時の傾き反映のためと思われます。
そして、パターンA,Bについては、次のように決定されます。
- サブルーチン0x82991aの処理0x829bfd からパターンA/B判断が始まり、乱数ワード 0x7e01|ce の下位3bitが7ならパターンB (確率1/8)、それ以外はパターンAとなります。
- パターンAの場合
- 同一フレームの同サブルーチンの処理 0x829c6a からどっち向きに回転するかを判断し、傾き変化量、変化後予定値に反映します。。
- 乱数ワード 0x7e01ce が奇数なら反時計回り、偶数なら時計回りです。
※乱数が、パターンA/Bの時の使い回しになるため3:4に頻度が偏ります - 変化後に傾きが反時計+90°( 内部の値として 128 ) になる場合、変化後予定値はもう一段階進めた値が設定されます。
- パターンAが決定したフレームで次の周期が計算されますが、反時計+90°を超えて二段階変化する場合、二段階目の変化用に傾き変化量が設定されるフレームで、周期の再計算とフレームカウントのリセットが行われます。
- 傾き変化中 (二段階変化の途中含む) に画面切り替えを行った場合、即座に変化後予定値への切り替わりが起こり、傾き変化処理が終了します。
放っておけば二段階変化する状況であっても、画面切り替えで処理が終了した場合は、周期の再計算・フレームカウントリセットが発せしません。
- パターンBの場合
- 変数 0x7e14e2 をパターンB中の管理用に使用します。各パラメータの決定は、サブルーチン0x829dabにおいて複数フレームに渡って行います。
- パターンBが決定されたフレーム:
0x7e14e2 に-2をセットするだけで、次のフレームに処理を持ち越します。 - 次のフレームの処理 ( 0x7e14e2の値-2 ):
どっち向きに回転するか判断し、0x7e14e2 を -3 に更新します。
判断の際使用する乱数および偶奇での判定はパターンAの時と同じですが、次のフレームで乱数更新されているため、確率は半々となります。
また、二段階目のタイミングを計るため、ここでフレームカウントがリセットされます。
なお、変化後予定値は現在の傾きと同じ値が設定されます。( 揺り戻しがあるため ) - 揺り戻しの処理 ( 0x7e14e2の値-3 ):
前段の傾き変化が終わったら、効果音6を鳴らし、再び微振動を発生させます。
フレームのカウントが240f(4秒)を超えたら、逆向きの傾き変化量をセットして 0x7e14e2 に -4 をセットします。 - 揺り戻し完了 ( 0x7e14e2の値-4 ):
揺り戻しの傾き変化が終わったら、次の周期を計算しパターンBの処理を終えます。 ( 0x7e14e2 もゼロクリアされます ) - 前段の傾き変化中に画面切り替えを行った場合、傾き変化処理は完了せずに、変化後予定値に一旦傾きがリセットされます。この次の後段の傾きは時計回りに固定されます。
なお、傾き変化の方向の判断には、限界との比較があります。
- 傾きが許容範囲限界の場合は、回転方向のランダム判定は行われません。時計回りの向きの限界は0x730352、反時計回りの向きの限界は0x730353のバイトの値を0x10倍して用います。これらの限界値は進行度が進むたびに更新されます。
- つまり、時計回り上限に達している(超過含む)場合は反時計回り処理確定、それ以外で反時計回り上限に達している(超過含む)場合は時計回り処理確定、そうでなければ上記のように乱数で判断という区分になります。
- なお、反時計+180°(転覆前の水平状態)は、必ず反時計回り上限抵触と判断されるため、時計回り処理が確定します。
周期の蓄積とボイラー爆発
前項パターンA/B決定時に、周期 0x7e0348 が加算されます。パターンAの場合に限り、この周期が12になると進行度が進み周期がリセットされます。
※これにより進行度が2→1と変化すると傾き変化の代わりにボイラー爆発となります。
それ以外にも、主人公ミスでも周期+4の加算があり、12以上となると進行度が進みます。
なお、周期が12を超えていても次の進行度は周期0から始まります。超過分を持ち越すことはありません。
※これにより進行度が2→1と変化すると傾き変化の代わりにボイラー爆発となります。
それ以外にも、主人公ミスでも周期+4の加算があり、12以上となると進行度が進みます。
なお、周期が12を超えていても次の進行度は周期0から始まります。超過分を持ち越すことはありません。
なお、イベントのある部屋 ( イベントがあっても終了していると除く ) だと、周期上限2に達した時点で次の周期に進みます。パターンA/Bの判定も傾き変化もありません。なお12以上で進行度が進むのは同様です。
ボイラー爆発時は、傾きが反時計+67.5°( 内部数値 160 ) になるまで、傾きが断続的に変わっていきます。
その際、フレームカウントが300fになると変化量が+32 ( 反時計回り )、変化後予定値が現在の傾きから-32 になって更に傾きが変わります。反時計+67.5°に到達すると、初めて次の周期に移ります。
その際、フレームカウントが300fになると変化量が+32 ( 反時計回り )、変化後予定値が現在の傾きから-32 になって更に傾きが変わります。反時計+67.5°に到達すると、初めて次の周期に移ります。
なお、イベントのある部屋にいる場合、ボイラー爆発時の傾き変化も保留されます。しかし、300fおきのパラメータ設定自体は継続します。そのため、イベント終了のタイミングによっては変化後予定値が+67.5°を少し上回ることがあります。
具体的には、イベント終了→傾き変化再開→300fおきのパラメータ設定(変化中の傾きからの差分で予定値が中途半端になる)→画面切り替えで中途半端な傾きが設定される、という手順です。
そうすると、傾き反時計+67.5°になるまでほぼ1回転するという「大回転」という現象が発生します。
具体的には、イベント終了→傾き変化再開→300fおきのパラメータ設定(変化中の傾きからの差分で予定値が中途半端になる)→画面切り替えで中途半端な傾きが設定される、という手順です。
そうすると、傾き反時計+67.5°になるまでほぼ1回転するという「大回転」という現象が発生します。
浸水管理
ボイラー爆発以降、船内各所で浸水が始まり、水中の移動を余儀なくされる場面も出てきます。
ここでは、その浸水状況の管理についてまとめます。
ここでは、その浸水状況の管理についてまとめます。
水位概要
水位情報自体はゲーム開始時から管理されていますが、水位の情報はボイラー爆発直後、水の出現はボイラー爆発時の傾き変化が収まった瞬間から始まります。
特に部屋ID25の浸水通路は、早急に浸水の影響が出る場所となっており、この場所でボイラー爆発を迎えると、傾きの変化が収まった瞬間にいきなり水が現れる様子を観測することができます。
特に部屋ID25の浸水通路は、早急に浸水の影響が出る場所となっており、この場所でボイラー爆発を迎えると、傾きの変化が収まった瞬間にいきなり水が現れる様子を観測することができます。
水位の数値は、地図上のx座標(px単位)として管理されており、表エリア(0x7e032e)および各部屋(0x7e1340~)それぞれに保持されます。
実際の水面の位置は船の傾きにより変化しますが、水位の数値に応じた固定点を通る画面横方向に水平な面として計算されます。その固定点はx座標(px換算)が水位の数値と等しく、y座標がマップの中間 ( 表エリアならy座標 0x1000, 0x3000, 0x5000、それ以外なら 0x7000 ) となっている点です。表エリア底層での例として、次の図をご覧ください。
実際の水面の位置は船の傾きにより変化しますが、水位の数値に応じた固定点を通る画面横方向に水平な面として計算されます。その固定点はx座標(px換算)が水位の数値と等しく、y座標がマップの中間 ( 表エリアならy座標 0x1000, 0x3000, 0x5000、それ以外なら 0x7000 ) となっている点です。表エリア底層での例として、次の図をご覧ください。

特に、表エリア以外は y 座標が 0x6000 側に偏っていることが多いため、傾きが反時計+45°,+67.5°の時の方が、+112.5°の時よりより水面が高くなっているように見えます。
水位の数値は、基本的にどの場所も 57bf 毎に 2px ずつ減少 ( 水位が上がる方向、ほぼ 1px/秒 ) となります。
ただし、イベント中の部屋にいる場合、その部屋のみ数値は変動しません。
表エリア全域が浸水することは船の広さ的に不可能ですが、その他の部屋によっては限界まで浸水することもあります。その場合の上限は 64px になります。
なお、エイミー船室とアデラ船室は例外的に、タイムアップ演出まで一切浸水はありません。
ただし、イベント中の部屋にいる場合、その部屋のみ数値は変動しません。
表エリア全域が浸水することは船の広さ的に不可能ですが、その他の部屋によっては限界まで浸水することもあります。その場合の上限は 64px になります。
なお、エイミー船室とアデラ船室は例外的に、タイムアップ演出まで一切浸水はありません。
水位初期値
水位の初期値はゲーム開始時に設定されます。表エリアの数値はコード内固定、各部屋の数値は 0x828030~の値に依ります。ただ、現実的な時間で浸水が現れない箇所もあるため、その分は割愛します。
| 部屋ID | 場所 | 数値(px) | 地形の端との差(px) | 水出現見積もり(分) | 備考 |
|---|---|---|---|---|---|
| - | 表エリア | 3775 | 207 | 3.3 | 各層共通、差分は中層で計算 |
| 0 | ブリッジ | 1671 | 935 | 14.8 | |
| 3 | 裏エリア吹き抜け中央上層部 | 2119 | 1639 | 26.0 | |
| 4 | 裏エリア吹き抜け中央底層部 | 2119 | 1639 | 26.0 | |
| 5 | 裏エリア吹き抜け船首側上層部 | 1519 | 1039 | 16.5 | |
| 6 | 裏エリア吹き抜け船首側底層部 | 1519 | 1039 | 16.5 | |
| 9 | バー | 1607 | 1127 | 17.8 | |
| 11 | 売店#2 | 1127 | 743 | 11.8 | シアターにつながっている中層の売店 |
| 12 | 売店#1 | 2055 | 1575 | 24.9 | クレイバー・バーバラのいる部屋 |
| 13 | 売店#3 | 1863 | 1639 | 26.0 | 上層の売店 |
| 15 | 底層連絡部屋 | 527 | 111 | 1.8 | 中層の小広間とR35を介して連結している部屋 |
| 16 | ホール2F | 1423 | 687 | 10.9 | |
| 17 | エントランス | 1911 | 1687 | 26.7 | |
| 21 | 裏エリア配管部中央 | 2311 | 1575 | 24.9 | |
| 22 | 裏エリア底層船首倉庫 | 807 | 327 | 5.2 | 船首エレベータの先 |
| 23 | 制御室 | 783 | 303 | 4.8 | |
| 24 | 船首エレベータ | 959 | 735 | 11.6 | |
| 25 | 小部屋#2 | 1015 | 551 | 8.7 | ルークのいる部屋 |
| 26 | 小広間 | 887 | 407 | 6.4 | アンナ・フランクのいた部屋 |
| 28 | 図書館 | 1943 | 1367 | 21.6 | |
| 29 | ホール(メイン) | 1599 | 863 | 13.7 | |
| 30 | レストラン | 2367 | 1887 | 29.9 | |
| 31 | 医務室 | 1847 | 1431 | 22.7 | |
| 32 | 休憩室 | 1727 | 1247 | 19.7 | |
| 33 | シアター#1 | 1663 | 1183 | 18.7 | |
| 35 | 小広間先中底層連絡通路 | 863 | 639 | 10.1 | R15,R26を連結する部屋 |
| 36 | 教会トイレ | 1823 | 1599 | 25.3 | |
| 37 | 連絡階段 | 1471 | 1247 | 19.7 | |
| 38 | 船員船室 | 1471 | 1151 | 18.2 | 広い方の船室で見積もり |
| 52 | トレーニングルーム | 1287 | 887 | 14.0 | |
| 54 | 浸水通路 | 647 | -89 | - | ボイラー爆発直後に水出現 |
| 55 | 調理室 | 1191 | 983 | 15.6 |
浸水によるイベントキャンセル
浸水がある程度進むと、その場所で発生するはずのイベントがキャンセルされるようになります。
具体的に救出イベントとして影響があるのはルークのいる部屋ID25の小部屋#2です。爆発直後から6分弱の猶予しかありません。
具体的に救出イベントとして影響があるのはルークのいる部屋ID25の小部屋#2です。爆発直後から6分弱の猶予しかありません。
タイムアップ時処理
タイムアップ時、沈没する演出の後は、表エリア・全室の水位数値変動ペースが 6px/bf と約170倍になります。これはエイミー船室も含みます。そのため、短時間で全域が水没状態になります。
※ただし、ボイラー爆発を迎えずにタイムアップとなった場合は浸水は発生しません。
※ただし、ボイラー爆発を迎えずにタイムアップとなった場合は浸水は発生しません。
なお、アデラ船室に関しては 0x7e1340~ の領域をオーバーランしてしまいます。ただ、こちらは瞬間で水没する程度の影響しかありません。
バグと思われる挙動
- 浸水不発
水位の数値の変動はボイラー爆発後のみのはずですが、爆発前もダミー値の反映の処理だけ残っています。これにより、一度立ち寄って出た部屋に関しては、ボイラー爆発後浸水が発生しなくなります。
顕著なのが部屋ID54の浸水通路で、爆発前に浸水通路に入ったのち部屋を出ると、水が全く現れなくなります。 - 水位変動停止
ある部屋を出て表エリアにいる状態だと、その部屋の数値が固定されるという挙動があります。 - 想定外の傾きでの水位
水位の計算では船の傾きに応じて三角比のtanの計算を行いますが、ROM内には ( 船尾が垂直上向きを基準として ) 角度差分 90°未満の分のtan数値テーブルしか用意されていません。そのため、90°以上の差分 ( 水平基準で反時計-180°~0° ) が生じる状況では範囲外の値を参照して計算が行われるため、水位がめちゃくちゃになります。
※ただ、そのような傾きは通常発生しないため、実用上の影響はありません。
その他
トイレや一般の船室は、様々な入口から共通のマップに移動する関係上扱いが特別で、入口のある表エリアの浸水状況に応じて部屋の中の浸水状況が変化するようになっています。
※詳細は未調査です。
※詳細は未調査です。
アクション管理
地上状態、ジャンプ、水中等の状況に応じた各キャラの状態は、管理データAのオフセット0xeにより管理されており。状態の判断を行う際にはRAM $0048 にコピーされて用いられます。このパラメータに付随し、同オフセット0xa,0xcのパラメータも補助的に管理に使用されます。
状態一覧
管理データAオフセット0xe/RAM $0048 の取りうる状態は次の通りです。
※一部値はRAM $0048 のみに出現し、管理データA には反映されません。
※一部値はRAM $0048 のみに出現し、管理データA には反映されません。
| 値 | 概要 | 詳細 |
|---|---|---|
| 0 | 地上・立ち状態 | 階段以外の場所で立ったり、床に張り付いている一番基本の状態です。 歩いたり床を這っている状態も含みます。 |
| 1 | 垂直ジャンプ | 垂直ジャンプに伴う上り・下りの状態です。 最後の着地だけは値3の状態になります。 |
| 2 | 横ジャンプ上り | 横ジャンプ開始から頂点に到達するまでの状態です。 |
| 3 | 落下・横ジャンプ下り | 足場を失って落下している状態です。 横ジャンプでの頂点到達以降も含みます。 |
| 4 | 掴まり | 床の出っ張りや階段に掴まっている状態です。 段差を乗り越える時のよじ登る状態も含みます。 また、床の端から身を乗り出してぶら下がり状態になっているものも含みます。 |
| 5 | しゃがみ移行 | 次項6と0の相互の移行段階です。 |
| 6 | しゃがみ状態 | しゃがんでいる状態です。しゃがみ歩きも含みます。 |
| 7 | 階段上 | 階段に乗って立ったり歩いたりしている状態です。 角度によっては階段に沿って這っている状態にもなります。 |
| 8 | ミス後落下 | ミスを起こして空中を落下している状態です。 落下ミスの場合は自動的にこの状態になります。 |
| 9 | 号令 | L/Rボタンで呼ぶ動作をしている状態です。 |
| 10 | 水中 | 水中にいる状態です。静止中、泳いでの移動両方を含みます。 |
| 11 | 無効 | 値は設定されていますが、おそらく使用されません。 |
| 12 | ハシゴ掴まり | ハシゴに掴まって、静止あるいは上り下りしている状態です。 ハシゴが垂直方向になっている必要があります。 ※ハシゴの上に立っている状態は0に含まれます。 |
| 13 | 転倒 | 転覆直後や、ミスからの復帰時の転倒状態です。 ラットラーを受け止めて転倒した時のキャプリスの状態も含みます。 |
| 14 | 同行者補助 | Yボタンで同行者を引き上げている状態です。 |
| 15 | 被補助 | Yボタンで引き上げられている同行者に設定される状態です。 |
| 16 | 落下以外でのミス | 炎・障害物への接触や、体力枯渇を起こした状態です。 ただし空中では、すぐに状態8へ移行します |
| 64 | イベント固有 | イベントの各種コマンドにより設定されるステータスです。 移動せずに左右の向きだけを変更する目的で瞬間的に設定されます。 対象は、コマンド1の対象キャラ位置到着時、コマンド2の持続時間切れ時、コマンド131の最初です。 その他イベント外でも、誘導されているキャラのマーカーへの到着時にも設定されます。 この値が管理データA上に現れるかは未調査です。 |
| 65 | イベント固有 | イベントのコマンド64により設定されるステータスです。 このステータスに紐づき、姿勢IDの変更が行われます |
| 66,67 | イベント固有 | それぞれイベントのコマンド5,6により設定されるステータスです。 このステータスに紐づき、姿勢IDの変更が行われます。 この値は管理データAには反映されません。 |
| 68 | イベント固有 | ミッシェルのバイオリン演奏を引き起こすコマンド129により設定されるステータスです。 このステータスに紐づき、演奏用の姿勢IDの設定が行われます。 |
| 69~72 | 不明 | 処理は設定されていますが、おそらく使用されない状態です。 |
| 255 | 別画面 | 画面切り替えをしてから呼んだ時に引き起こされる一画面遅延状態の時に RAM $0048 に一時的に設定されます。 管理データAに反映する際は、0,2,3 いずれかに差し替えられます |
ジャンプと空中移動
ジャンプを含む空中移動に関して、内部的には各4バイト 1/1048576 単位で細かく管理されています。
※座標として有効なのは上位2バイトに対応する 1/16px 単位のため、残りの2バイトは端数ということになります。
※座標として有効なのは上位2バイトに対応する 1/16px 単位のため、残りの2バイトは端数ということになります。
位置および速度は地図上のx,y座標の2方向で管理されており、管理データAのオフセット0x10~が該当します。
速度・移動距離自体は状況に依って変化ありませんが、傾きに応じて各方向に数値が分配されます。
垂直ジャンプおよび横ジャンプ時に初速が付与され、空中にいると画面下向きに一定の加速度が働きます。加速度に関しては、速度が一定のペースで変化するような扱いがなされます。
なお、座標に関しては船尾側がx座標小、上層側がy座標小ですが、正の速度は座標が小さくなる方向に働きます。ただ、以下では符号なしの数値で整理します。
速度・移動距離自体は状況に依って変化ありませんが、傾きに応じて各方向に数値が分配されます。
垂直ジャンプおよび横ジャンプ時に初速が付与され、空中にいると画面下向きに一定の加速度が働きます。加速度に関しては、速度が一定のペースで変化するような扱いがなされます。
なお、座標に関しては船尾側がx座標小、上層側がy座標小ですが、正の速度は座標が小さくなる方向に働きます。ただ、以下では符号なしの数値で整理します。
- 加速
いずれの場合でも、共通で約0.242px/bf^2 ( 217.8px/s^2 ) の、画面下方への加速が働きます。つまり、1bf毎に速度が 0.242px/bf 変化することになります。
なお、加速には限界があり、x,y方向それぞれの成分で 8px/bf の速度が上限となります。 - 垂直ジャンプ
初速 3.875px/bf ( 116.25px/s ) で、画面上方に垂直にジャンプします。
そのため、16bfで頂点に到達し、1bfの滞空後、16bfで降りてくる形になります。最高到達点は約 32.9px です。 - 横ジャンプ
初速 1.75px/bf ( 52.5px/s ) で、まず画面横方向にスライドを始めます。その4bf後、上方に 3.25px/bf ( 97.5px/s ) の速度を得て斜めにジャンプします。
そのため、水平な場所で横ジャンプした場合は、4bfの横移動、14bfの上昇、15bfの下降で、最高到達点は約 23.5px、横移動距離は 57.75px です。 - 落下
画面切り替え等で空中で足場を失った場合、初速 0 で落下を始めます。 - 空中補正
空中での十字キー横操作により、上述の速度・加速度管理とは別に、移動に補正効果があります。
効果はキーを押している間のみ画面横方向に 0.75px/bf ( 22.5px/s ) です。
この補正は端数管理していないため、水平でない場合は若干の誤差が出ます。( つまり、x,y方向の影響を加味しても0.75px/bfからのズレが出る )
ジャンプで滞空している約1秒でも20px以上の差が出るので、意外と効果は馬鹿にできません。
数値データに関しては、0x80bf69~の各配列に格納されており、傾きを22.5単位にまるめた16段階から値を選択します。先頭は転覆前の水平の角度、以降時計回りに段階が進みます。
符号やx,y軸の交換等を除けば、結局は 0°, 22.5°, 45°の3段階分のバリエーションになります。以下、符号無しの数字を px/bf, px/bf^2 換算した小数値で挙げます。
符号やx,y軸の交換等を除けば、結局は 0°, 22.5°, 45°の3段階分のバリエーションになります。以下、符号無しの数字を px/bf, px/bf^2 換算した小数値で挙げます。
| 傾き | 加速度 | 垂直ジャンプ初速 | 横ジャンプ横初速 | 横ジャンプ縦速度 | 十字キー補正 | |||||
|---|---|---|---|---|---|---|---|---|---|---|
| x方向 | y方向 | x方向 | y方向 | x方向 | y方向 | x方向 | y方向 | x方向 | y方向 | |
| 0° | 0.0000 | 0.2420 | 0.0000 | 3.8750 | 1.7500 | 0.0000 | 0.0000 | 3.2500 | 0.7500 | 0.0000 |
| 22.5° | 0.0926 | 0.2236 | 1.4829 | 3.5800 | 1.6168 | 0.6697 | 1.2437 | 3.0026 | 0.6875 | 0.3125 |
| 45° | 0.1711 | 0.1711 | 2.7400 | 2.7400 | 1.2374 | 1.2374 | 2.2981 | 2.2981 | 0.5000 | 0.5000 |
落下ミス判定
空中の移動により、x,y方向のいずれかで160pxの移動があった場合、落下ミスという判定になります。
なので、メモリ書き換えでも行わないと通常は起こりえませんが、ハイジャンプのように高く上るジャンプでも、160pxの移動があった時点でミスになります。
あくまでx,y方向のいずれかなので直線距離ではありません。例えば45°の傾きなら直線距離で220px程度まで耐えられる計算になります。
なので、メモリ書き換えでも行わないと通常は起こりえませんが、ハイジャンプのように高く上るジャンプでも、160pxの移動があった時点でミスになります。
あくまでx,y方向のいずれかなので直線距離ではありません。例えば45°の傾きなら直線距離で220px程度まで耐えられる計算になります。
なお、この判定の基準とする座標は管理データCのオフセット0xc,0xeに1/16px単位の数値として保存されます。
注意が必要なのは、ジャンプ(垂直、横両方)の場合、この座標の決定がジャンプ時点で行われるという点です。つまり、例えば垂直ジャンプで高さを上げてから落下しても、ジャンプの上昇分は移動距離にカウントされないことになります。
注意が必要なのは、ジャンプ(垂直、横両方)の場合、この座標の決定がジャンプ時点で行われるという点です。つまり、例えば垂直ジャンプで高さを上げてから落下しても、ジャンプの上昇分は移動距離にカウントされないことになります。
また、落下ミスとは別に、同行者に限り特定の地形への接触で即ミスとなる条件があります。以下の動画で詳細を解説しています。
こちらは、空中判定(状態1~3)かつ、裏エリア吹き抜けの画面切り替え境界部分に接触した時が該当します。
落下ミスや体力枯渇と異なり、即座に同行者消滅となるため、画面切り替えでのキャンセルも効きません。
再現操作としては、境界部分を連れ歩きで抜ける際にジャンプして空中で画面切り替えすると、確率で同行者が反対方向に飛んで空中接触してしまう、というものになります。
こちらは、空中判定(状態1~3)かつ、裏エリア吹き抜けの画面切り替え境界部分に接触した時が該当します。
落下ミスや体力枯渇と異なり、即座に同行者消滅となるため、画面切り替えでのキャンセルも効きません。
再現操作としては、境界部分を連れ歩きで抜ける際にジャンプして空中で画面切り替えすると、確率で同行者が反対方向に飛んで空中接触してしまう、というものになります。
落下ミス判定のバグ
判定のための距離計算の基準となる座標を更新するタイミングはいくつかあるのですが、その処理にバグがあることで距離計算がおかしくなり、本来起こらないはずの落下ミスが引き起こされる事例があります。
詳細は一つ上で取り上げている動画で併せて解説していますが、非連れ歩き状態で部屋に入って同行者を呼んで、同行者が入室する直前で主人公が部屋を出る、という操作で引き起こされます。
詳細は一つ上で取り上げている動画で併せて解説していますが、非連れ歩き状態で部屋に入って同行者を呼んで、同行者が入室する直前で主人公が部屋を出る、という操作で引き起こされます。
道連れについて
同行者の状態に関して、主人公の状態がコピーされる状況が存在します。
そのため、落下や障害物接触による主人公のミスがコピーされると、道連れで同行者もミスになることを意味します。
そのため、落下や障害物接触による主人公のミスがコピーされると、道連れで同行者もミスになることを意味します。
一つは道連れ全滅です。
連れ歩き状態で画面切り替え ( 扉に入る、画面境界をまたぐ等 ) を行った場合、同行者全員の状態値に主人公と同じ値をコピーすることから発生します。
主人公がミスを起こしてその後の落下で画面切り替えを起こした場合 ( 例えば裏エリア吹き抜け部分で落下ミスする等 )、連れ歩きを維持していると、同行者全員にミスの状態値 8 もしくは 16 がコピーされ、結果として同行者が全員消滅します。これが道連れ全滅の原因となっています。
そのため、連れ歩き中に主人公がミスを起こした場合は、即座にL/Rボタンを離すクセをつけた方が良いと思います。
連れ歩き状態で画面切り替え ( 扉に入る、画面境界をまたぐ等 ) を行った場合、同行者全員の状態値に主人公と同じ値をコピーすることから発生します。
主人公がミスを起こしてその後の落下で画面切り替えを起こした場合 ( 例えば裏エリア吹き抜け部分で落下ミスする等 )、連れ歩きを維持していると、同行者全員にミスの状態値 8 もしくは 16 がコピーされ、結果として同行者が全員消滅します。これが道連れ全滅の原因となっています。
そのため、連れ歩き中に主人公がミスを起こした場合は、即座にL/Rボタンを離すクセをつけた方が良いと思います。
もう一つはYボタン補助による道連れミスです。
Yボタンによる補助で引き上げられた同行者は、引き上げ直後に主人公の状態値がコピーされます。
そのため、引き上げ最中に落下物で主人公がミスしてしまうと、引き上げられた同行者にもミスの状態値 16 がコピーされ、結果としてその同行者がミスとなります。こちらは、暗転していく画面の中で、微かに同行者がミスになる場面を観測することができます。
Yボタンによる補助で引き上げられた同行者は、引き上げ直後に主人公の状態値がコピーされます。
そのため、引き上げ最中に落下物で主人公がミスしてしまうと、引き上げられた同行者にもミスの状態値 16 がコピーされ、結果としてその同行者がミスとなります。こちらは、暗転していく画面の中で、微かに同行者がミスになる場面を観測することができます。