ハイハイスクールアドベンチャー技術資料
概要
この文書は、ハイハイスクールアドベンチャーの技術的な資料である。
データファイル構成
プログラム本体以外には以下のファイルを使用している。
- シナリオデータファイル
- 画面データファイル
- 部屋データ
- アイテムデータ
- 語句辞書ファイル
- 初期データ
- 音データファイル
- メッセージファイル1)
ゲームエンジン仕様
ゲームエンジンは、汎用のアドベンチャーゲームエンジンを目指してデザインしたものの、入出力と強く結びついた動作をきれいに落とし込み切れていないので事実上のハイハイスクールアドベンチャー専用エンジンとなっている。
エンジンはフロントエンドからコマンド(動詞+目的語)を受け取るとシナリオデータの集合を走査し、条件を満たしているものを実行する。 エンジン単体でできることは、システム内のフラグや状態変数を書き換えることだけで、入出力を伴うものはターゲット環境に合わせて実装された入出力部が処理する。
シナリオデータは、32bitの条件ブロックに続いて、32bitを1単位とし、複数の語からなる動作節がある。 最大で256組の動作を定義でき、一つの動作は96byte (4byteの条件ブロック + 23シナリオ語)からなる。 条件ブロックは、場所、動詞、目的語の3byteをキーとし、1byteは未使用である。
場所、動詞、目的語にはワイルドカードがあり、例えば、どの部屋であっても、北へ移動しろというコマンドが来たら、アクションを起こすというような場合には、場所と目的語にはワイルドカードを渡しておく。
エンジンは条件ブロックを評価し、条件を満たしたら、動作節を実行する。 複数の条件ブロックを満たす場合には先にある条件ブロックが優先的にマッチし、以下のものは対象外となる
動作節は、複数の条件語からなる条件節に続いて、アクション節が続く構成となっている。 条件ブロックに続いて条件節が来るのは奇異に映るかもしれないが、最初の条件ブロックは、場所、動詞、目的語だけをキーとしたものであり、続く条件節は、さらに詳細な条件の確認のためのものである。
たとえば、任意の場所で、「拾う」「ネクタイ」というコマンドが来たとして、その場所に「ネクタイ」がある場合とない場合とで動作は変わってくる。 この「ネクタイ」の有無をチェックするのが条件節の働きになる。 。
フォーマット
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
act | op | pad | typ | id | offset | value | |||||||||||||||||||||||||
typ | id |
actビットで、条件語(act=0)かアクション語(act=1)かを判別している。 opは条件やアクションを具体的に示す。 3bit 8種類を持つことができる。 padはパディングエリアで、この4bitは使用されていない。 typとidはペアで、typで示される種類のデータのid番目にアクセスする。 offsetは8ビットのデータとしても使われるし、typ(3)+id(5)としても使われる。 typ(id)同士を比較したり内容をコピーしたりするときには offsetをこのように分割する。 valueは8ビットのデータである。
条件語
条件語はactビットが0のものを指す。 条件語は以下のようなフォーマットを持つ。
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | cond | typ1 | id1 | typ2 | id2 | value |
cond
condは以下の8種類がある。
値 | 意味 |
---|---|
0 | NOP(常に成功) |
1 | EQ |
2 | NE |
3 | GT |
4 | GE |
5 | LT |
6 | LE |
7 | 未定義 |
オペランド
第一オペランドは typ1 + id1 であらわされ、第二オペランドは typ2 + id2または valueが使われる。 第二オペランドが typ2 + id2なのか valueなのかは、typ2によって決まる。
typは以下のものがある。
値 | 意味 |
---|---|
0 | None (typ2ならvalueを使う) |
1 | Fact |
2 | Place |
3 | System |
4 | Vector |
Factおよび Placeはフラグである。 ハイハイスクールアドベンチャーにおいては、Factは懐中電灯が使用中かとか、先生が出現しているかとかそいうい情報を、Placeはアイテムの場所を管理している。idは5ビットあるので32種類ずつ持つことができるが、そんなには使っていない。
Systemは文字通りシステム変数で、Vectorは部屋と部屋のリンク情報を管理している。
例えば、
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 1 | - | - | - | - | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | - | - | - | - | - | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
このビット列0x1021000A2)は、Fact(1) == 10 を意味している。
アクション語
アクション語は act == 1のものを指し、以下のようなフォーマットを持つ。
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | action | typ1 | id1 | typ2 | id2 | value |
アクション
アクションは以下の8種類である。
値 | 意味 |
---|---|
0 | Nop |
1 | Move(部屋の移動) |
2 | Asgn(値の代入) |
3 | Mesg(メッセージの出力) |
4 | Dlog(選択ダイアログの表示) |
5 | Look(Look動作) |
6 | Snd(音を鳴らす) |
7 | Over(ゲームオーバー) |
Move
指定された方向への移動を試みる。 方向は value で与えられる、0~7が有効で、以下のような意味を持っている。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|
北 | 南 | 西 | 東 | 上 | 下 | 入 | 出 |
現在いる場所から与えられた方向への移動を試みるが、移動先が0になっている場合はその方向へは移動できない。 それ以外の場合には与えられた数字で示される場所へ移動する。
Asgn
オペランド1 (typ1 + id1)で示されるフラグに、与えられた値をセットする。 値はオペランド2 (typ2 + id2)で与えられる。
typ2 == 0 なら value(即値)が値として採用される。 typは条件語で用いているものと同じである。
Mesg
valueで与えられた番号の文字列を出力する。
Dlog
選択ダイアログを表示する。 ダイアログ番号は value で与えられる。 つまり256種類持たせられるが、もちろんそんなに使ってはいない。 ダイアログの実装、および得られた値の処理は実装依存になっている。
Look
「見る」コマンドに特化した動作である。 特定の目的語を与えられた「見る」コマンドは一種の移動として処理されるが、移動ベクタには登録されていない。 valueで与えられた「部屋」へ移動したかのように処理される。 value==0が与えられると元の部屋に戻る。
これら特殊な「部屋」は、どの部屋ともつながっていない。 もしつながりのある部屋を与えれば、そこから移動することができるだろうが、想定外の動作である。
Snd
valueで与えられた番号の音を鳴らす。 0はハイハイスクールの校歌である。 全ての音が存在しているかどうかは保証されない。 M5版では音を鳴らす機能は実装されていない。
Over
valueで表されるゲームオーバーを迎える。
画面データ仕様
部屋データ
部屋データは、一部屋 0xa00バイト(2.5KB)からなり、各部屋は1KBの画像描画データおよび、0x500バイトの部屋固有のメッセージデータおよび、0x100バイトの特定のコマンドとメッセージとのリンク情報からなる。
部屋にしても、ものにしても、FM-7上で、BASICを使って描画することを前提につくられている。 線を引き、色を塗るという動作を座標と色データの形で格納している。
線の描画は繊細で、BASICで使っているであろうロジックに近しいもので描画しないと、色を塗るときの座標が想定している境界線とマッチしなくなる可能性がある。3)
このため、移植する際には、まずグラフィックスの描画ルーチンを実装し、データを実際に描かせてみてから先へ進めることにしている。 とはいえ、昨今は256×152のビットマップバッファを作って、それをターゲットの環境にレンダリングさせているだけなので、ほぼほぼ、問題なく動いている。
描画データ
先頭には、トーンパターンが何色分定義されているのかが1byteで表されている。 トーンパターンは、1-7の色を指定されたパターンで置き換えるためのもので、カラーパレット機能のようなものである。
その後ろに3バイト(BRG)のトーンデータが指定された数だけ続き、その後ろがようやく最初の描画データになる。
描画を始める前に、描画域全体を青(色コード1)で塗りつぶす。
(x,y)のポイントデータの羅列で、最初のペアから次のペアへの線を白(色コード7)で描いていく。 読みだした(x,y)がともに0xffなら線描パートは終わりである。 yだけが0xffの場合はそのペアを捨てて、次のペアを新しい始点として線を描いていく。
続いて、(x,y,c)のペアで色塗りデータが続く。(x,y)ともに0xffなら色塗りは終了である。
画像によっては、この後ろに、白線での輪郭描画、黒線での輪郭描画のデータが続き、最後にトーン処理を行う。
トーンデータは最初に書いたように、パターン数+パターン数*3バイトのパターンデータとして登録されている。 最大で6 (カラーコード1-7に対応)のパターンがあり、対応するカラーコードを置き換えていく。
PC-9801では、パターンデータのままに、縞模様を使った中間色画像として描画されたが、PalmOS以降ではそれらしい色に置き換えるように変更してある。
PalmOSとAndroidには縞模様の中間色画像を表示する機能も付けてあるが、あえて表示する価値はないと思われる。
トーンデータ | 線画データ | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
n | t1(B) | t1(R) | t1(G) | … | x0 | y0 | x1 | y1 | … | xn | 0xff | x0 | y0 | x1 | y1 | … | 0xff | 0xff |
ペイントデータ | 白線データ | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
x | y | c | x | y | c | … | 0xff | 0xff | x0 | y0 | … | xn | 0xff | x0 | y0 | x1 | y1 | … | 0xff | 0xff |
黒線データ | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
x0 | y0 | x1 | y1 | … | xn | 0xff | x0 | y0 | x1 | y1 | … | 0xff | 0xff |
トーンデータ
トーンデータは、3バイトを一組として、BRGの横8dot分のトーンパターンを定義している。 カラーコード1-7で描かれている部分をこのトーンパターンで置き換え、中間色表現による色表現を行う。
要は、当該カラーコードのある点に対して、
((b >> (7 - (x % 8)) & 1) | (((r >> (7 - (x % 8)) & 1) << 1) | (((g >> (7 - (x % 8)) & 1) << 2)
の色を置いていく(8色モードの場合)ことになる。
なお、今どきの端末の多くはRGB565であったり ARGB8888であったりと、より多色を使った表示がかのうなので、あえて中間色を使う必要性は高くない。
中間色は、要は、交互に色を並べることで、その中間の色に見せる(白+赤ならピンクに見えるように)というものなので、パターンのうち1が立っているビットの密度を数えて、それをB/R/Gそれぞれの色の輝度(0~7)と見なし、疑似的にRGB333の色コードとして変換、これをさらにRGB565やARGB8888に変換して表示している。
メッセージデータ
メッセージデータは、部屋データのオフセット 0x500から0x500バイトの領域に配置される。 先頭からメッセージ番号0,1,2… と続く。
メッセージは最初の2バイトがメッセージ長で、その後ろに長さ分のメッセージデータが続き、その後ろに次のメッセージが配置される。 メッセージはUTF-8でエンコーディングされている。 オリジナルとなったPC-9801版はShift_JISだったが、時代にそぐわないので、PalmOS版を作るときにすべてUTF-8にした。 メッセージ長はbig endianであるので、処理には注意。 メッセージ長0の文字列が現れたらメッセージは終わりである。
メッセージ番号0のメッセージは、そのマップが表示されたときに表示されるメッセージで、それ以外のメッセージは、その場所で特定の動作をしたときに表示されるメッセージである。 その特定の動作は、コマンド・メッセージリンクで定義されている。
メッセージ長 | メッセージ | メッセージ長 | メッセージ | 終端マーク | ||||
---|---|---|---|---|---|---|---|---|
上位 | 下位 | 文字列0(UTF-8)… | 上位 | 下位 | 文字列1(UTF-8)… | … | 0 | 0 |
コマンド・メッセージリンク
描画データのあと、オフセット0x400から0x100バイトのデータが、コマンド・メッセージリンクになる。 3バイト一組のデータで、動詞+目的語+メッセージIDである。 後続のメッセージ部のメッセージ数分だけのエントリーが存在している。
その場所で、動詞+目的語の動作をしたときに、ID番目のメッセージを表示する。
ただ表示するだけなので、ゲーム中で何ら作用を持たないものであることは明らかであるが、 こういう仕掛けを一所懸命しこんだであろう原作者たちの思いを表すものである。
リンクデータ0 | 終端マーク | |||
---|---|---|---|---|
動詞 | 目的語 | メッセージ番号 | … | 0 |
ものデータ
ものデータは、落ちているものと○○先生の描画データである。 それぞれの描画データは0.5KBである。
ものデータは、そのものがある部屋に来たときに、部屋の画像の上に表示される。 このことにより、任意の部屋にものを置けば、そのものが即座に表示されるし、拾えば即座に消える。
なお、通常のアイテムの描画データの扱いは一意だが、先生だけは異なった処理を行う。