TA: Kingdomsの.gui — 空白文字区切りのウィジェットツリー
TA: Kingdomsは、メインメニュー、ロビー、ゲーム中のHUD、ダイアログボックスを
.guiファイルから描いていました。癖のある、空白文字区切りのウィジェット記述形式です。TA自身のGUIファイル(こちらも.gui)と見た目は似ていますが、TA:Kの形式は構造が異なり、互換性はありません。
Note
現在のkbotには、TA:Kの.gui用のサブコマンドはありません。この形式は、網羅性のため、そして今後のツール作りの参考にするためにここで説明しています。ファイルはプレーンなASCIIテキストなので、自分の目で確認することはできます。
ファイルの中身
.guiファイルは、ウィジェットが平らに並んだものです。ファイルの先頭にあるヘッダーウィジェットが、ウィジェットの総数と全体に関わるメタデータ(背景画像、ホットキー)を宣言し、それ以降の各ウィジェットがUIの要素を1つずつ記述します。
典型的なウィジェットは次のようになります。
4 1 ← widget type (4 = button), unused flag (always 1)
1 ← unused (always 1 except in headers)
2 196 79 95 20 1 0 0 0 ← bounds: type, X, Y, W, H, flags…
3 0 0 0 0 ← colour: type, R, G, B, A
1 0 0 ← unused (always 1 0 0)
1 14 hattfont11.gaf ← font: type, len, name
12 PlayerColor 2 12 ← control name + state count
3 ← number of gaf frames that follow
1 17 singlemachine.gaf 14 SingleMachine0 0 18 ← disabled frame
1 17 singlemachine.gaf 14 SingleMachine0 1 18 ← pressed frame
1 17 singlemachine.gaf 14 SingleMachine0 2 18 ← released frame
3 ← number of strings that follow
2 0 0 2 0 4 Exit 2 0 4 Exit 3 ← state strings (disabled, pressed, up)
1 7 Default
1 12 skirmish.wav ← sound played when activated
1 7 Default
2 0 16 Play the Machine ← tooltip / mouseover help
0 ← number of child widgets
トークンは空白文字で区切られています。各ウィジェットの最初のトークンは、ウィジェットの種類のIDです。それ以降は、種類ごとのスキーマに従います。
長さが前に付いた文字列
この形式で最も重要な仕掛けは、どの文字列にも、その文字数を表す整数のトークンが前に付いていることです。そのため文字列にスペースを含めることができますが、パーサーは先に長さを読まなければなりません。
1 14 MainScreen.gaf
^ ^^ ^^^^^^^^^^^^^^
│ │ │
│ │ └─ the string itself (14 characters)
│ └─ length
└─ string-flavour prefix (1 = literal string)
空の文字列は1 0 0です(接頭辞、長さ0、そして空のペイロードが「空の文字列」を表します)。繰り返し出てくる1/0の接頭辞は、単純に空白文字でトークンに分割して数え始めると、とても読み違えやすいものです。ウィジェットの順に、先頭から順番に読んでいく必要があります。
Important
.guiファイルを「3番目のボタン」でgrepしても意味のある結果は得られません。構造は順番に読むもので、位置を指定して参照できるものではないからです。この形式向けに書かれたエディターは、どれも先頭から順に読むパーサーです。
ウィジェットの種類
確認されているウィジェットの種類のID:
| ID | ウィジェット | 備考 |
|---|---|---|
2 |
ヘッダー / フォーム | ファイルの最初のウィジェット。背景、ホットキー、子の数を持つ。 |
4 |
ボタン | 3状態(無効 / 押下 / 通常)。 |
5 |
チェックボックス | 5状態の組み合わせ(無効、オフ押下、オン押下、オフ通常、オン通常)。 |
9 |
枠(Frame) | 目に見えないコンテナ。ウィジェットを見た目の上でまとめるだけ。 |
12 |
スクロールバーのコンテナ | スライダーと、その増減ボタンの範囲を決める。 |
14 |
スクロールバーのボタン(増 / 減 / つまみ) | 各12の後に3つ続く。 |
15 |
リストボックス | 実行時に中身が入る。テンプレートはほとんど空。 |
17 |
ラジオボタン | 3状態。 |
18 |
多状態ボタン | N個の状態を切り替えるボタン(例:「AIの難易度」の選択)。 |
19 |
画像+ラベル | 静止画と見出しを組み合わせた、TA:K独自のウィジェット。 |
種類ごとに、種類のIDの後に続くトークンのスキーマが決まっています。Dark Rainがリバースエンジニアリングで明らかにした正規のスキーマは、このリポジトリに付属する資料に保存されています。
ウィジェットの一般的な形
[TYPE] 1
1
2 [X] [Y] [W] [H] 1 0 0 0
3 [colour: A R G B]
1 0 0
1 [font: length name]
[control-name length] [name] 2 3
[N]
1 [len] [gaf] [len] [seq] [frame] 9 × N
[N]
2 0 0 2 [string set] × N entries inline
1 7 Default
1 [len] [activate.wav]
1 7 Default
2 0 [help length] [help text]
[child-count]
[N]の大きさと文字列セットの構造は、ウィジェットの種類ごとに異なります。それぞれについては、資料にあるスキーマが説明しています。
配置コード
文字列セットの中で使われます。
| コード | 配置 |
|---|---|
0 |
中央揃え |
1 |
左揃え |
2 |
右揃え |
状態が1つのウィジェットなら、たとえば2 0 6 Playerのようになります。3状態のボタンなら、3つの状態すべてがつながって、たとえば2 0 0 2 0 6 Player 2 3 6 Play2r 3のようになります。
実例 — メインメニュー
2 1
2 0 0 640 480 1 1 0 0
3 255 255 255 255
1 0 0
1 0
8 MainMenu 1 2
2
1 15 TitleScreen.tsf 7 JPGTest 0 9
1 15 TitleScreen.tsf 7 JPGTest 1 9
2
2 0 0 2 0 0 2
1 0
1 0
2 0 24 #Enter#Play#Esc#Previous
6
上から順に読むと、次のようになります。
2 1:ウィジェットの種類2(ヘッダー)、フラグ1。2 0 0 640 480 1 1 0 0:原点にある640×480の範囲と、4つのフラグのトークン。3 255 255 255 255:不透明な白の色のエントリ。8 MainMenu 1 2:コントロール名「MainMenu」(8文字)と、それに続く1 2。- 2つの
TitleScreen.tsf JPGTestのエントリは背景画像です(同じものへの参照が2つありますが、エンジンは両方を必要とします)。 2 0 24 #Enter#Play#Esc#Previous:キー割り当てです。Enterは「Play」という名前のコントロールを、Escは「Previous」を動作させます。6:このフォームには6個の子ウィジェットがあり、すぐ後に続きます。
TSFとGAFの背景
ヘッダーウィジェットは、2種類の背景の元に対応しています。
.tsf:TA:Kのトゥルーカラーアニメーションのテキスト形式で、GUIのローダーはこれを直接読みます。静止したメニューでは、JPGを運ぶだけの薄い入れ物です(例のTitleScreen.tsfはTitleScreen.jpgを包んでいます)。ただ、同じ形式で複数フレームの本格的なアニメーションも記述できます。バイナリとテキストの配置についてはTAF / TSFを参照してください。kbotはどちらも解析し、ラウンドトリップできます。.gaf:TA: Kingdomsの標準のアニメーションです。ヘッダーはGAFの中のシーケンスを参照し、エンジンはそれを背景として再生します。
どちらの場合も、この形式では画像のエントリを2回続けて書く必要があり、実際に描画されるのは2つ目だけです。これは既知の癖です。
注意点
Warning
.guiファイルには、チェックサムも復旧用のマーカーもありません。子の数のトークンを1つ数え間違えるだけで、それ以降のすべてのウィジェットが何の警告もなくずれます。エンジンはファイルを読み込みますが(構造を検証しないため)、ウィジェットが間違った場所に表示されたり、コントロール名が見つからなかったり、存在しないはずのボタンが現れたりします。
- 空白文字には、トークンを区切る以上の意味はありません。Cavedogが同梱したファイルにはスペースとタブの両方が使われているので、連続した空白文字はすべて1つの区切りとして扱ってください。
- 子の数は正確でなければなりません。
4で終わる枠ウィジェット(種類9)は、次の4つのトップレベルのウィジェットを子として取り込みます。数を間違えると、フォームの残りがばらばらになります。 - リストボックスとスクロールバーのウィジェットは、同梱のファイルでは実質的に空のテンプレートです。エンジンが実行時にスクリプトの状態から中身を入れるので、静的に中身を入れようとしても意味がありません。
- 改造した
.guiファイルの大半を読み込むには、TA:Kのコマンドラインフラグ-disablecavedogverificationが必要です。これがないと、エンジンはハッシュが埋め込みのリストと一致しないファイルをすべて拒否します。 - 展開するとクラッシュするファイルもあれば、まとめるとクラッシュするファイルもあります。形式そのものは安定していますが、エンジンのローダーは、仮想ファイルシステムの層から読む場合と、ディレクトリから直接読む場合とで挙動が異なります。MODを作るときは、両方の状態でテストしてください。