GFF Creature and Dialogue - OpenKotOR/PyKotor GitHub Wiki

GFF Types: Creature and Dialogue

Creature templates and dialogue trees are the two GFF types that most directly define how characters behave and speak. A UTC stores everything about a creature β€” stats, appearance, inventory, scripts [UTC] β€” while DLG encodes branching conversation logic with conditions, animations, and voice-over references [DLG].

Contents


UTC (Creature)

Part of the GFF File Format Documentation.

UTC files define creature templates including NPCs, party members, enemies, and the player character. They are comprehensive GFF files containing all data needed to spawn and control a creature in the game world. UTC files are loaded with the same resource resolution order as other resources (override, MOD/SAV, KEY/BIF).

Official Bioware Documentation: For the authoritative Bioware Aurora Engine Creature format specification, see Bioware Aurora Creature Format.

For mod developers:

Related formats:

  • 2DA (appearance, portraits, classes, feats, racialtypes, creaturespeed)
  • SSF
  • TLK
  • MDL
  • TPC
  • GFF-UTI (inventory items)

UTC support in PyKotor is implemented by the in-memory UTC model and GFF reader/writer pipeline (utc.py L36+, construct_utc L494+, read_utc L982+, write_utc L992+). UTC is identified as GFFContent.UTC in the shared GFF type map and uses the common binary GFF loader (gff_data.py L150, io_gff.py L82+). The Holocron Toolset exposes these fields in its creature editor (toolset/gui/editors/utc.py), and other engines parse UTC through their generic GFF stacks (reone gff.cpp, reone gffreader.cpp, KotOR.js GFFObject.ts L24+, Kotor.NET GFF.cs L18+). For practical creature-editing workflow examples and troubleshooting, the community index at Home links to current forum threads.

Core Identity fields

Field Type Description
TemplateResRef ResRef Template identifier for this creature (max 16 characters; should match UTC filename without extension)
Tag CExoString Unique tag for script/conversation references
FirstName CExoLocString Creature's first name (localized)
LastName CExoLocString Creature's last name (localized)
Comment CExoString Developer comment/notes

Appearance & Visuals

Field Type Description
Appearance_Type UInt32 Index into appearance.2da
PortraitId word Index into portraits.2da; 65535 (0xFFFF) = use Portrait ResRef instead
Gender byte 0=Male, 1=Female, 2=Both, 3=Other, 4=None [utc.py L221]
Race byte Index into racialtypes.2da [utc.py L219].
SubraceIndex byte Index into subrace.2da; refines race (e.g. subspecies).
BodyVariation byte Body model variation index [utc.py L231]
TextureVar byte texture variation index [utc.py L232]
SoundSetFile word Index into sound set table

Core Stats & Attributes

Field Type Description
Str byte Strength score (3-255)
Dex byte Dexterity score (3-255)
Con byte Constitution score (3-255)
Int byte Intelligence score (3-255)
Wis byte Wisdom score (3-255)
Cha byte Charisma score (3-255)
HitPoints int16 Current hit points
CurrentHitPoints int16 Alias for hit points
MaxHitPoints int16 Maximum hit points
ForcePoints int16 Current Force points (KotOR specific)
CurrentForce int16 Alias for Force points
MaxForcePoints int16 Maximum Force points

Character Progression

Field Type Description
ClassList List List of character classes with levels
Experience UInt32 Total experience points
LevelUpStack List Pending level-up choices
SkillList List Skill ranks (index + rank)
FeatList List Acquired feats
SpecialAbilityList List Special abilities/powers

ClassList Struct fields:

SkillList Struct fields:

  • Rank (byte): Skill rank value

FeatList Struct fields:

Combat & Behavior

Field Type Description
FactionID word Faction identifier (determines hostility)
NaturalAC byte Natural armor class bonus
ChallengeRating float CR for encounter calculations
PerceptionRange byte Perception distance category
WalkRate int32 Row index into creaturespeed.2da; sets walk/run movement speed used for pathfinding and animation.
Interruptable byte Can be interrupted during actions
NoPermDeath byte Cannot permanently die
IsPC byte Is player character
Plot byte Plot-critical (cannot die)
MinOneHP byte Cannot drop below 1 HP
PartyInteract byte Shows party selection interface
Hologram byte Rendered as hologram

Equipment & Inventory

Field Type Description
ItemList List Inventory items
Equip_ItemList List Equipped items with slots
EquippedRes ResRef Deprecated equipment field

ItemList Struct fields:

  • InventoryRes (ResRef): UTI template ResRef
  • Repos_PosX (word): Inventory grid X position
  • Repos_Posy (word): Inventory grid Y position
  • Dropable (byte): Can be dropped/removed

Equip_ItemList Struct fields:

  • EquippedRes (ResRef): UTI template ResRef
  • Equipment slots reference equipmentslots.2da

Script Hooks

Field Type Description
ScriptAttacked ResRef Fires when attacked
ScriptDamaged ResRef Fires when damaged
ScriptDeath ResRef Fires on death
ScriptDialogue ResRef Fires when conversation starts
ScriptDisturbed ResRef Fires when inventory disturbed
ScriptEndRound ResRef Fires at combat round end
ScriptEndDialogue ResRef Fires when conversation ends
ScriptHeartbeat ResRef Fires periodically
ScriptOnBlocked ResRef Fires when movement blocked
ScriptOnNotice ResRef Fires when notices something
ScriptRested ResRef Fires after rest
ScriptSpawn ResRef Fires on spawn
ScriptSpellAt ResRef Fires when spell cast at creature
ScriptUserDefine ResRef Fires on user-defined events

KotOR-Specific Features

Alignment:

  • GoodEvil (byte): 0-100 scale (0=Dark, 100=Light)
  • LawfulChaotic (byte): Unused in KotOR

Multiplayer (Unused in KotOR):

Special Abilities:

  • Stored in SpecialAbilityList referencing spells.2da or feat-based abilities

Editor reference (min/max and usage)

When editing UTCs in the Holocron Toolset, numeric fields use the following ranges (from GFF types and engine behavior):

  • TemplateResRef, Conversation, script ResRefs: Max 16 characters (engine ResRef limit).
  • Tag: No engine-enforced max length; keep unique per module for script lookups (e.g. GetObjectByTag).
  • FirstName, LastName, Comment: Localized or plain string; no fixed max in GFF.
  • Appearance_Type, PortraitId, SoundSetFile, FactionID: WORD (0–65535); use valid 2DA row indices.
  • Race, Gender, SubraceIndex, PerceptionRange, NaturalAC, ability scores (Str–Cha), skill Rank: BYTE (0–255). Race: row index into racialtypes.2da (0 to row count βˆ’ 1). Save bonuses (fortbonus, refbonus, willbonus): SHORT (-32768–32767).
  • WalkRate: INT; row index into creaturespeed.2da (0 to row count βˆ’ 1). Invalid index can cause default or broken movement.
  • HitPoints, CurrentHitPoints, MaxHitPoints, CurrentForce, ForcePoints: SHORT (0–32767 typical; game does not use negative HP/FP).
  • ChallengeRating: Float (0–100 typical). GoodEvil (alignment): 0–100 (0=Dark, 100=Light).
  • ClassLevel: SHORT (0–32767); typical level 1–20. MultiplierSet (K2): INT32; 0 = default.
  • BlindSpot (K2): Float 0–360 degrees.

All script hooks store a ResRef to an NCS file; leave blank for no script. The toolset provides tooltips on each field describing how the game uses it and how modders can change it.

Implementation Notes

UTC files are loaded during module initialization or creature spawning. PyKotor reads a UTC via construct_utc, which deserializes each GFF field into the UTC data object [utc.py L354].

Common Use Cases:

  • Party Members: Full UTC with all progression data, complex equipment
  • Plot NPCs: Basic stats, specific appearance, dialogue scripts
  • Generic Enemies: Minimal data, shared appearance, basic AI scripts
  • Vendors: Specialized with store inventory, merchant scripts
  • Placeables As Creatures: Invisible creatures for complex scripting

See also


DLG (Dialogue)

Part of the GFF File Format Documentation.

DLG files store conversation trees, forming the core of KotOR's narrative interaction. A dialogue consists of a hierarchy of Entry nodes (NPC lines) and Reply nodes (Player options), connected by Links.

Official Bioware Documentation: For the authoritative Bioware Aurora Engine Conversation format specification, see Bioware Aurora Conversation Format.

DLG files are loaded with the same resource resolution order as other resources:

For mod developers:

Related formats:

  • TLK / StrRef β€” displayed text
  • WAV β€” voice-over
  • NCS β€” scripts
  • GFF-JRL β€” journal updates
  • MDL β€” camera models

PyKotor implements DLG as a graph of entries, replies, and links with GFF-based read/write support (dlg/base.py L36+, construct_dlg L29+, read_dlg L566+, write_dlg L593+). DLG is identified as GFFContent.DLG and decoded by the shared GFF binary reader (gff_data.py L160, io_gff.py L82+). PyKotor also supports optional Twine interchange for dialogue authoring flows (dlg/io/twine.py). The Holocron Toolset exposes DLG editing in the GUI workflow (Holocron Toolset: Getting Started), and other engines/tools load DLG through generic GFF or dialogue-specific wrappers (reone gff.cpp, reone gffreader.cpp, KotOR.js DLGObject.ts L31+, KotOR.js GFFObject.ts L24+, Kotor.NET GFF.cs L18+).

Conversation Properties

Field Type Description
DelayEntry int32 Delay before conversation starts
DelayReply int32 Delay before player reply options appear
NumWords int32 Total word count (unused)
PreventSkipping byte Prevents skipping dialogue lines
Skippable byte Allows skipping dialogue
Sound ResRef Background sound loop
AmbientTrack int32 Background music track ID
CameraModel ResRef Camera model for cutscenes
ComputerType byte Interface style (0=Modern, 1=Ancient)
ConversationType byte 0=Human, 1=Computer, 2=Other
OldHitCheck byte Legacy hit check flag (unused)

Conversation types:

  • Human: Cinematic camera, voice-over support, standard UI
  • Computer: Full-screen terminal interface, no voice-over, green text
  • Other: Overhead text bubbles (bark strings)

Script Hooks

Field Type Description
EndConversation ResRef Fires when conversation ends normally
EndConverAbort ResRef Fires when conversation is aborted

node Lists

DLG files use two main lists for nodes and one for starting points:

List field Contains Description
EntryList DLGEntry NPC dialogue lines
ReplyList DLGReply Player response options
StartingList DLGLink Entry points into the dialogue tree

Graph structure:

  • StartingList links to EntryList nodes (NPC starts)
  • EntryList nodes link to ReplyList nodes (Player responds)
  • ReplyList nodes link to EntryList nodes (NPC responds)
  • Links can be conditional (Script checks)

DLGNode Structure (Entries & Replies)

Both Entry and Reply nodes share common fields:

Field Type Description
Text CExoLocString Dialogue text
VO_ResRef ResRef Voice-over audio file
Sound ResRef Sound effect ResRef
Script ResRef Script to execute (Action)
Delay int32 Delay before text appears
Comment CExoString Developer comment
Speaker CExoString Speaker tag (Entry only)
Listener CExoString Listener tag (unused)
Quest CExoString Journal tag to update
QuestEntry int32 journal entry ID
PlotIndex int32 Plot index (legacy)
PlotXPPercentage float XP reward percentage

Cinematic fields:

  • CameraAngle: Camera angle ID
  • CameraID: Specific camera ID
  • CameraAnimation: animation to play
  • CamFieldOfView: Camera FOV
  • CamHeightOffset: Camera height
  • CamVidEffect: Video effect ID

animation List:

  • List of animations to play on participants
  • Participant: Tag of object to animate
  • Animation: animation ID

DLGLink structure

Links connect nodes and define flow control:

Field Type Description
Index int32 Index of target node in Entry/Reply list
Active ResRef Conditional script (returns TRUE/FALSE)
Script ResRef Action script (executed on transition)
IsChild byte 1 if linking to node in list, 0 if logic link
LinkComment CExoString Developer comment

Conditional Logic:

  • Active script determines if link is available
  • If script returns FALSE, link is skipped
  • Engine evaluates links top-to-bottom
  • First valid link is taken (for NPC lines)
  • All valid links displayed (for Player replies)

KotOR 2 Logic Extensions:

  • Logic: 0=AND, 1=OR (combines Active conditions)
  • Not: Negates condition result

Implementation Notes

Flow Evaluation:

  1. Conversation starts
  2. Engine evaluates StartingList links
  3. First link with valid Active condition is chosen
  4. Transition to target EntryList node
  5. Execute Entry Script, play VO, show Text
  6. Evaluate Entry's links to ReplyList
  7. Display all valid Replies to player
  8. Player selects Reply
  9. Transition to target ReplyList node
  10. Evaluate Reply's links to EntryList
  11. Loop until no links remain or EndConversation called

Computer Dialogues:

  • ComputerType=1 (Ancient) changes font/background
  • No cinematic cameras
  • Used for terminals and datapads

Bark strings:

  • ConversationType=2
  • No cinematic mode, text floats over head
  • Non-blocking interaction

Journal Integration:

  • Quest and QuestEntry fields update journal entries directly
  • Eliminates need for scripts to update quests

Twine Interoperability

PyKotor exposes a Twine bridge for DLGs to support authoring and visualization in story tools:

  • Export uses Libraries/PyKotor/src/pykotor/resource/generics/dlg/io/twine.py::_dlg_to_story to turn starters, entries, and replies into TwinePassage objects. It emits unique names for duplicate speakers, preserves is_child and Active script on links, and writes KotOR metadata into PassageMetadata.custom (camera anim/angle/id, fade type, quest, sound, VO, plus text_<language>_<gender> variants).
  • Import uses Libraries/PyKotor/src/pykotor/resource/generics/dlg/io/twine.py::_story_to_dlg together with FormatConverter.restore_kotor_metadata to hydrate DLGEntry/DLGReply objects, restoring multilingual text from custom keys and mapping camera/sound/quest metadata back onto the nodes.
  • Twine-only data (style, script, tag colors, format info, zoom, creator metadata) is stored in [DLG](GFF-File-Format#dlg-dialogue).comment as JSON via FormatConverter.store_twine_metadata and restored on export
  • tag_colors are kept as Color values (see Libraries/PyKotor/src/pykotor/resource/generics/dlg/io/twine_data.py).
  • Start node selection mirrors engine behavior: first starter becomes startnode when exporting, and missing startnode on import falls back to the first entry passage.

See also


⚠️ **GitHub.com Fallback** ⚠️