⚙️ NWN2:EE DLGファイル技術仕様 - 開発者編
開発者・システム実装者向けのNWN2:EE DLGファイルの詳細技術仕様書です。
🎯 概要
本仕様書では、NWN2:EE DLGファイルの技術的詳細について、実装者向けの詳細な情報を提供します。
📊 バージョン情報
- GFFバージョン: V3.2
- 対応エンジン: Neverwinter Nights 2: Enhanced Edition
- ファイル識別子: "DLG "(4バイト、末尾にスペース)
🏗️ GFFファイル形式詳細
ヘッダ構造
struct GFFHeader {
char file_type[4]; // "DLG "
char version[4]; // "V3.2"
uint32_t struct_offset; // 構造体オフセット
uint32_t struct_count; // 構造体数
uint32_t field_offset; // フィールドオフセット
uint32_t field_count; // フィールド数
uint32_t label_offset; // ラベルオフセット
uint32_t label_count; // ラベル数
uint32_t field_data_offset; // フィールドデータオフセット
uint32_t field_data_count; // フィールドデータサイズ
uint32_t field_indices_offset; // フィールドインデックスオフセット
uint32_t field_indices_count; // フィールドインデックス数
uint32_t list_indices_offset; // リストインデックスオフセット
uint32_t list_indices_count; // リストインデックス数
};
フィールドタイプ定義
タイプID | タイプ名 | サイズ | 説明 |
---|---|---|---|
0 | BYTE |
1 | 8ビット符号なし整数 |
4 | DWORD |
4 | 32ビット符号なし整数 |
5 | INT |
4 | 32ビット符号付き整数 |
8 | FLOAT |
4 | 32ビット浮動小数点数 |
10 | CExoString |
可変 | 文字列 |
11 | CResRef |
16 | リソース参照 |
12 | CExoLocString |
可変 | ローカライズ文字列 |
14 | Struct |
可変 | 構造体 |
15 | List |
可変 | リスト |
📋 フィールド仕様
ルートレベル基本設定
EndConversation
- type: CResRef
- description: 会話終了時に実行されるスクリプト
- default: "nw_walk_wp"
- required: true
QuickChat
- type: INT
- description: クイックチャットモードの有効/無効
- values: 0=無効, 1=有効
- default: 0
DelayReplyF
- type: FLOAT
- description: プレイヤーの返答選択肢表示までの遅延時間(秒)
- range: 0.0 - 10.0
- default: 0.0
EntryList仕様
必須フィールド
Text:
- type: CExoLocString
- description: 表示テキストのStrRef
- format: [strref, [(language_id, text)]]
- required: true
Speaker:
- type: CExoString
- description: 話者のリソース参照名
- max_length: 32
- required: false
Sound:
- type: CResRef
- description: 音声ファイルのリソース参照
- max_length: 16
- required: false
🔧 スクリプトシステム
ScriptList構造
Script:
type: CResRef
description: 実行するスクリプトファイル名
max_length: 16
required: true
Parameters:
type: List
description: スクリプトパラメータリスト
required: false
一般的なスクリプト例
スクリプト名 | 用途 | パラメータ |
---|---|---|
gc_global_int |
グローバル変数チェック | STRING(変数名), STRING(比較値) |
gc_is_male |
性別チェック(男性) | なし |
gc_is_female |
性別チェック(女性) | なし |
gc_is_enemy_near |
敵の近接チェック | FLOAT(距離), INT(チェック方法) |
⚡ 条件分岐システム
ActiveConditiona構造
Not:
type: INT
description: 条件の否定フラグ
values: 0=通常条件, 1=NOT条件
default: 0
And:
type: INT
description: 論理演算子
values: 0=OR演算, 1=AND演算
default: 1
Script:
type: CResRef
description: 条件判定スクリプト
max_length: 16
required: true
条件評価ルール
- 複数条件の評価順序: リスト内の条件を順番に評価
- 論理演算:
And
フィールドに基づいてAND/OR演算 - NOT条件の処理:
Not=1
の場合、スクリプト結果を反転 - 短絡評価: AND演算でfalseまたはOR演算でtrueが出た時点で評価停止
📹 カメラシステム
CameraInfo詳細構造
フィールド | タイプ | 説明 | 値 |
---|---|---|---|
ShotType |
INT | ショットタイプ | 0=デフォルト, 1=クローズアップ, 2=ミディアム, 3=ロング |
StaticCamera |
CExoString | 固定カメラ名 | max_length: 32 |
OverrideMode |
INT | オーバーライドモード | 0=なし, 1=あり |
MovementType |
INT | 移動タイプ | 0=固定, 1=滑らか, 2=瞬間移動 |
💻 実装ガイドライン
パーサー実装のベストプラクティス
1. エラーハンドリング
def find_field(struct, label, field_type=None):
for field in struct.value:
if field.label == label:
if field_type is None or isinstance(field, field_type):
return field
return None
2. 型安全性
def get_int_field(struct, label, default=0):
field = find_field(struct, label, Field.INT)
return field.value if field else default
3. データ検証
def validate_entry(entry_struct):
# 必須フィールドチェック
text_field = find_field(entry_struct, 'Text', Field.CExoLocString)
if not text_field:
raise ValueError("Entry missing required Text field")
# データ範囲チェック
animation_field = find_field(entry_struct, 'Animation', Field.DWORD)
if animation_field and animation_field.value > 65535:
raise ValueError("Animation ID out of range")
🔍 トラブルシューティング
一般的な問題と解決策
❌ StrRef解決の失敗
問題: text_strref が null または無効
解決: TLKファイルの存在確認、StrRefの有効性チェック
⚠️ スクリプト参照エラー
問題: Script フィールドが空または無効
解決: スクリプトファイルの存在確認、デフォルト値設定
🔄 循環参照の検出
def detect_circular_reference(entries, visited=None):
if visited is None:
visited = set()
for entry in entries:
if entry['node_id'] in visited:
return True
visited.add(entry['node_id'])
# 再帰的にチェック
🐛 デバッグ支援
def debug_dlg_structure(gff_data, max_depth=3):
"""DLG構造をデバッグ出力"""
def print_field(field, depth=0):
if depth > max_depth:
return
indent = " " * depth
print(f"{indent}{field.label}: {field.name}")
if hasattr(field, 'value') and hasattr(field.value, '__iter__'):
for sub_field in field.value:
print_field(sub_field, depth + 1)
print_field(gff_data.root)
🔗 関連記事
基本的な構造理解については、「NWN2:EE DLGファイル構造解析 - 基礎編」をご覧ください。
最終更新: 2025年7月26日
バージョン: 1.0
対象読者: 開発者・システム実装者
0 件のコメント:
コメントを投稿