Repository navigation
Communication Text (Dialogs & Strings)
Last verified: 23.09.2026 | Game version: S.T.A.L.K.E.R.: Call of Pripyat (Steam, patch 1.6.02) | OS tested: Debian (Linux)
Status: Active — core workflow verified end-to-end
No visible text lives directly inside dialog/character files — everything is a two-step lookup: id → string_table entry → actual text. To change what a player reads, you usually edit a string_table file. To change dialog structure (branches, conditions, who says what) you edit a separate dialog file. Both are plain XML, in Windows-1251 encoding when they contain Cyrillic.
Communication text in CoP is split across three kinds of files that reference each other by id:
character_desc_.xml (who the NPC is, which dialogs they can have)
⭣
dialogs_.xml (dialog structure: phrases, branching, conditions)
⭣
st_dialogs_.xml (the actual text the player reads, in string_table format)
Defines each NPC (<specific_character id="...">): name, bio, appearance, inventory, and — importantly — which dialogs they can have:
<specific_character id="zat_a2_stalker_nimble" team_default="1">
<name>st_zat_a2_stalker_nimble_name</name>
<bio>Опытный сталкер. Немногословен, добродушен.</bio>
...
<start_dialog>zat_b51_stalker_nimble_start</start_dialog>
<actor_dialog>zat_b51_stalker_nimble_b52_about_gun_questions</actor_dialog>
<actor_dialog>zat_b51_stalker_nimble_place_order</actor_dialog>
<actor_dialog>zat_b51_stalker_nimble_get_order</actor_dialog>
<actor_dialog>zat_b51_stalker_nimble_about</actor_dialog>
<actor_dialog>actor_break_dialog</actor_dialog>
</specific_character>-
<name>and<bio>areids into a string_table too, not literal text. -
<start_dialog>— the dialog the NPC opens with automatically when the player talks to them. -
<actor_dialog>(can repeat) — dialog options available in the conversation menu; the player can pick between these. -
One file per location (
character_desc_zaton.xml,character_desc_jupiter.xml,character_desc_pripyat.xml,character_desc_general.xmlfor common/shared NPCs).
Defines the actual branching structure, referenced by the ids from <start_dialog>/<actor_dialog>:
<dialog id="zat_b51_stalker_nimble_get_order">
<phrase_list>
<phrase id="0">
<text>zat_b51_stalker_nimble_get_order_0</text>
<next>1</next>
<next>2</next>
</phrase>
<phrase id="1111">
<text>zat_b51_stalker_nimble_get_order_1111</text>
<precondition>dialogs_zaton.zat_b51_has_item_cost</precondition>
<action>dialogs_zaton.zat_b51_buy_item</action>
<disable_info>zat_b51_order_refused</disable_info>
<give_info>zat_b51_order_in_process</give_info>
<next>11111</next>
</phrase>
...
</phrase_list>
</dialog>Key elements per <phrase>:
| Tag | Meaning |
|---|---|
<text> |
an id, not literal text — looked up in the matching st_dialogs_*.xml
|
<next> |
id of the next phrase(s); multiple <next> = player gets multiple reply options |
<precondition> |
script_file.function_name — a Lua condition; phrase only shows/fires if it returns true |
<action> |
script_file.function_name — Lua code run when this phrase is selected (give item, take money, etc.) |
<has_info> / <dont_has_info>
|
phrase only available if a given info_portion is/isn't set |
<give_info> / <disable_info>
|
sets/clears an info_portion when this phrase fires |
<is_final>1</is_final> |
ends the dialog after this phrase |
Empty <text /> is normal, not a bug. Some phrases exist purely as branching/logic nodes (checking has_info, routing to the next real phrase) with nothing for the player to read. In-game, when an NPC's reply is split across several such nodes, the player sees a "[next…]" option to step through them — that's the empty-text phrases being traversed one by one until a phrase with real text is reached.
Preconditions and actions point to Lua functions in matching .script files (e.g. dialogs_zaton.script), covered in the upcoming Quests page.
The actual player-facing text, keyed by id:
<string id="zat_b51_stalker_nimble_get_order_0">
<text>I'm here to collect my order.</text>
</string>This is the only layer you need to touch if you're just rewording existing dialog without changing its structure/logic.
Other st_*.xml files in the same folder cover different content categories, not just dialogs — worth knowing they exist:
| File | Contains |
|---|---|
st_dialogs_<location>.xml, st_dialogs.xml
|
dialog line text, per location + shared |
st_dialog_manager.xml |
generic dialog manager strings |
st_characters.xml |
NPC names/bios not tied to a specific location |
st_quests_<location>.xml, st_quests_general.xml
|
quest journal / PDA text |
st_items_*.xml |
item, weapon, outfit, artifact names & descriptions |
st_subtitles.xml |
subtitles for voiced lines/cutscenes |
ui_st_*.xml |
UI text (menus, inventory, PDA, keybinding screen, etc.) — not dialog-related |
Dialog and string files are split per location, matching the game's zones: zaton, jupiter, pripyat, plus a shared/general set with no location suffix. When looking for a specific NPC's dialog, check the file matching their location first.
Same rule as .script/.ltx files (see Environment & Tools): these XML files are windows-1251-encoded when they contain Cyrillic (Russian text, comments, bios). Reading them with plain cat/grep on Linux shows garbled text — use grep -a to force text mode for searching, and open/save with the correct encoding in your editor (VS Code: bottom-right corner → Reopen/Save with Encoding → Cyrillic Windows 1251).
English text itself is plain ASCII and not affected — encoding only matters when the file contains Cyrillic somewhere (bios, Russian string tables, comments).
Same rule as Environment & Tools: resources/configs.db → xpatch_02.db → gamedata. Check this per file and per language — the patch doesn't necessarily update every file/language. Example found in this project: xpatch_02.db only contains an updated rus string_table for st_dialogs_zaton.xml; the eng version was never touched by the patch, so the base-archive eng file is still the current source — always check both patch/configs/text/<lang>/ and localization/configs/text/<lang>/ for the specific file/language you're editing before assuming which one is authoritative.
Changed the reply text NPC "Pilot" (zat_b215_stalker_guide) and Nimble (zat_a2_stalker_nimble) use, both found in st_dialogs_zaton.xml.
grep -rl "<string_id>" ~/stalker_unpacked/localization/configs/text/eng/Also check whether the patch has a newer version for your language:
grep -rl "<string_id>" ~/stalker_unpacked/patch/configs/text/eng/ 2>/dev/nullmkdir -p "/path/to/Stalker Call of Pripyat/gamedata/configs/text/eng"
cp ~/stalker_unpacked/localization/configs/text/eng/st_dialogs_zaton.xml \
"/path/to/Stalker Call of Pripyat/gamedata/configs/text/eng/"The whole file is copied — the engine loads files as a unit, not individual lines inside them. Multiple lines in the same file can be edited in one copy.
code "/path/to/Stalker Call of Pripyat/gamedata/configs/text/eng/st_dialogs_zaton.xml"<string id="zat_b215_stalker_guide_start_31">
<text>Nice to see you, comrade! What can old Pilot do for you?</text>
</string>cd "/path/to/Stalker Call of Pripyat"
/path/to/xray-16/bin/x86_64/<config>/xr_3da -copTalk to the NPC in question — the edited line appears.
Verified: both edited lines (Nimble and Pilot) show correctly in-game.
-
<text>inside a dialog file is always anid, never literal text — the real text lives in a separatest_dialogs_*.xml. - Empty
<text />phrases are normal branching/logic nodes, not missing content — they surface in-game as the "[Далее…]" step-through option. - File priority (
patchoverriding base archives) must be checked per file and per language, not assumed globally — a patch may only touch one language's string table for a given file. - Files containing Cyrillic are
windows-1251-encoded; usegrep -aon Linux to search them as text, and set the correct encoding in your editor before saving. - Copy the entire source file into
gamedata, not just the line you're changing — the engine overrides whole files, not individual entries within them. - Dialog structure (branching, conditions, actions) lives in a different file (
dialogs_<location>.xml) than the text (st_dialogs_<location>.xml) — know which one you actually need to touch before starting.