Abstract
Problem: How did Arcanum: Of Steamworks and Magick Obscura implement its dialogue system without dedicated tools?
Approach: Tim Cain walks through an actual example NPC dialogue file he created during Arcanum's development, explaining each column's purpose and the system's design rationale.
Findings: Arcanum's dialogues were authored entirely in Excel spreadsheets using a column-based format with test conditions, result opcodes, and generated subtrees β then exported to plain text
.dlgfiles for the game engine.Key insight: A "primitive but very powerful" spreadsheet-based dialogue system can support complex branching conversations, conditional logic, gender-aware localization, and world-affecting side effects β all without building a custom editor.
The Spreadsheet-Based Dialogue Format
Arcanum's dialogue files were written in Excel. The team didn't have time to build a dedicated dialogue editor, so they used spreadsheets with a specific column layout. Each row represented either an NPC line (highlighted in blue) or a player response (lines between NPC lines).
Column Breakdown
- Column B β Line Number: A unique dialogue line ID, independent of the Excel row number. Error messages would reference this number, not the row. This separation was intentional and important for reorganization.
- Column D β Text Field: The NPC's spoken line if the player character is male.
- Column F β G Field: The NPC's spoken line if the player character is female. This existed for localization β many languages require gender-differentiated translations, even though in English 90% of the time the lines were identical (e.g., "How are you today, sir?" vs "How are you today, ma'am?").
- Column H β IQ Field: For player lines, the minimum intelligence required to say that line. A negative value meant a maximum IQ (e.g.,
-5means only players with INT 5 or lower see that option). Not used for NPC lines. - Column J β Test Field: A conditional test determining whether a player line appears. Left empty for NPC lines (they always speak if directed to by script). About two dozen test codes existed, usable on PCs, NPCs, or both.
- Column L β Response Line: The dialogue line to jump to after selection. Zero meant exit/end conversation. A negative number meant jump to the corresponding line in an associated dialogue script file (for complex logic that exceeded the result field's capacity).
- Column N β Result Field: Script opcodes executed when a line is spoken (player selects it, or NPC says it in conversation). About two dozen result opcodes existed. Results were not executed if the line was used as a bark/float message rather than in conversation.
- Columns past P: Ignored by the parser β dialogue writers could use these for personal notes.
Generated Dialogue Subtrees
Several special codes in the text field triggered auto-generated dialogue subtrees rather than displaying literal text:
Bon(Barter On): Generated a complete barter interaction β the player asks to buy items, the NPC agrees, the barter UI opens, and upon completion the conversation continues to a specified line (e.g., "Is there anything else?").U:12(Use Skill): Generated a skill-use subtree. Skills were numbered; skill 12 was Repair. The system would generate lines for item selection, cost negotiation, payment, and refusal β all automatically.Kon(Ask a Question): Generated a question subtree populated with context-sensitive questions based on the current story state of the game.
Follower Commands as Dialogue
Follower management was handled through the dialogue system. The test code fo checked whether the NPC was currently a follower; wa checked if they were in wait mode. Player options like "Move away," "Move closer," "Wait here," "Disband," and "Let's go" each had corresponding result opcodes:
SOβ Spread Out (move away, maintain farther follow distance)SCβ Stay Close (tighten formation)WAβ Wait (leave party, stand at current position)LVβ Leave (disband from party entirely)UWβ Unwait (rejoin after waiting)
Why Excel, Not the Excel File Format
The game did not parse .xls files directly. Tim had three reasons:
- Speed: Extracting to plain text and reading that was faster than parsing Excel's format, which contained a lot of extraneous data. In the late '90s/early 2000s, every CPU cycle counted.
- Memory: Excel files were much larger than the extracted text. Memory was at a premium, and the dialogue data needed to be loaded at runtime.
- Format stability: Microsoft changed the Excel file format frequently. Tim refused to rewrite parsing functions every time a new Excel version shipped. Plain text only needed one import function, written once.
Jason Anderson wrote an Excel macro that exported the spreadsheet to a .dlg text file with a single button press.
The Decoupled Line Number Advantage
Keeping dialogue line numbers (column B) separate from Excel row numbers was a deliberate design choice. It meant writers could freely insert, delete, and reorganize rows β adding new player responses or grouping related NPC statements together β without breaking any jump references. When exported to .dlg files, row numbers were discarded entirely since they served no purpose in the final data.
Summary
Tim Cain describes the system as "primitive but very powerful." The Excel-based approach let dialogue writers create complex branching trees where NPC or player lines could trigger world effects, lines could be conditionally hidden based on player state (intelligence, follower status, story progress), and common interactions (barter, skill use, questions) were auto-generated. For anything the built-in opcodes couldn't handle, writers could jump to full scripts via negative line numbers.
References
- Tim Cain. YouTube video. https://www.youtube.com/watch?v=GYWEgQAh6So