Создание диалогов (полный обзор)

Материал из Mod Wiki.

(Различия между версиями)
Перейти к: навигация, поиск
Версия 09:12, 5 июля 2008 (править)
BAC9-FLCL (Обсуждение | вклад)

← К предыдущему изменению
Текущая версия (16:21, 12 мая 2011) (править) (отменить)
ILdarKOrotkov (Обсуждение | вклад)

 
(22 промежуточные версии не показаны)
Строка 9: Строка 9:
* stable_dialogs_x.xml * stable_dialogs_x.xml
-''(где '''x''' - название уровня)''+В них нам важны, соотвественно, списки присвоения диалогов персонажам, структуры диалогов и текстовые массивы для фраз.
- +
-Главными являются файлы dialogs_x.xml, на них, собственно, и будет направлена основная работа инструмента. В этих файлах хранится структура, скелет диалога. Кстати, '''x''' - это не обязательно название уровня. В принципе, диалоги можно помещать абсолютно произвольно, просто по локациям - это удобней для последующей работы.+
- +
===Структура фраз=== ===Структура фраз===
Строка 35: Строка 32:
<source lang="xml"> <source lang="xml">
<dialog id="escape_trader_letat_gusi"> <dialog id="escape_trader_letat_gusi">
- <phrase_list>+ <phrase_list>
- <phrase id="0">+ <phrase id="0">
- <text>Так, чего хотел-то?</text>+ <text>Так, чего хотел-то?</text>
- <next>1</next>+ <next>1</next>
- </phrase>+ </phrase>
- <phrase id="1">+ <phrase id="1">
- <text>Задание для тебя есть. Возьмешься?</text>+ <text>Задание для тебя есть. Возьмешься?</text>
- <next>21</next>+ <next>21</next>
- <next>22</next>+ <next>22</next>
- </phrase>+ </phrase>
- <phrase id="21">+ <phrase id="21">
- <text>Ну, давай.</text>+ <text>Ну, давай.</text>
- <next>3</next>+ <next>3</next>
- </phrase>+ </phrase>
- <phrase id="22">+ <phrase id="22">
- <text>Не, иди к черту.</text>+ <text>Не, иди к черту.</text>
- <action>dialogs.break_dialog</action>+ <action>dialogs.break_dialog</action>
- </phrase>+ </phrase>
- [...]+ [...]
- </phrase_list>+ </phrase_list>
</dialog> </dialog>
- 
</source> </source>
Строка 79: Строка 75:
<source lang="xml"> <source lang="xml">
- <phrase id="0"> -- открывающий тег с ID фразы+<phrase id="0"> -- открывающий тег с ID фразы
- <text>Привет.</text> -- текст фразы+ <text>Привет.</text> -- текст фразы
- <next>1</next> -- ссылка на следующую фразу+ <next>1</next> -- ссылка на следующую фразу
- </phrase> -- закрытие тега фразы+</phrase> -- закрытие тега фразы
</source> </source>
Строка 88: Строка 84:
<source lang="xml"> <source lang="xml">
- <phrase id="1">+<phrase id="1">
- <give_info>propusk_given</give_info> -- выдача инфопорции (см. объяснение ниже)+ <give_info>propusk_given</give_info> -- выдача инфопорции (см. объяснение №1 ниже)
- <text>Вот, держи пропуск. Теперь тебе охранник позволит войти.</text>+ <text>Вот, держи пропуск. Теперь тебе охранник позволит войти.</text>
- <action>dialogs.give_a_weapon</action> -- ссылка на скрипт, выдающий игроку пропуск в инвентарь; дается в формате имя_файла.имя_функции+ <action>dialogs.give_propusk_item</action> -- ссылка на скрипт (см. объяснение №2 ниже)
- <next>21</next>+ <next>21</next>
- <next>22</next>+ <next>22</next>
- <next>23</next>+ <next>23</next>
- </phrase>+</phrase>
</source> </source>
-* 1. здесь у нас выдается [[Инфопорция|инфопорция]] которая может потом использоваться в различных местах (например, её наличие может проверяться каким-нибудь охранником - и если она есть, то он, скажем, отойдет и пропустит игрока внутрь).+* 1. Здесь у нас выдается [[Инфопорция|инфопорция]], которая может потом использоваться в различных местах (например, её наличие может проверяться каким-нибудь охранником - и если она есть, то он, скажем, отойдет и пропустит игрока внутрь). Важно понимать отличие инфопорции от предмета. Инфопорция - это ''факт наличия'' пропуска, а лежащий в инвентаре пропуск - ''материальный предмет''. Можно, кстати, обойтись и без инфопорций, впоследствии пользуясь скриптами, проверяющими инвентарь игрока и ищущими нужный предмет, но этот способ сложен и нам пока не понадобится.
 + 
 +* 2. Это скрипт, выдающий игроку предмет "пропуск" в инвентарь. Ссылка на скрипты дается в формате имя_файла.имя_функции.
Как видите, фраза, в которой некий NPC выдает игроку пропуск, позволяющий пройти дальше, достаточно сложна. Как видите, фраза, в которой некий NPC выдает игроку пропуск, позволяющий пройти дальше, достаточно сложна.
Строка 105: Строка 103:
<source lang="xml"> <source lang="xml">
- <phrase id="4">+<phrase id="4">
- <has_info>propusk_given</has_info> -- проверка на наличие инфопорции propusk_given+ <has_info>propusk_given</has_info> -- проверка на наличие инфопорции propusk_given
- <text>Да, пропуск у меня есть.</text>+ <text>Да, пропуск у меня есть.</text>
- <action>dialogs.break_dialog</action> -- ссылка на скрипт, завершающий диалог+ <action>dialogs.break_dialog</action> -- ссылка на скрипт, завершающий диалог
- </phrase>+</phrase>
</source> </source>
-Здесь у нас фраза из диалога игрока с NPC - после вопроса NPC "А пропуск у тебя есть?" фраза 4, с вариантом ответа "Да, пропуск у меня есть.", появится только при соблюдении условия.+Здесь у нас фраза из диалога игрока с NPC - та, что после вопроса NPC "А пропуск у тебя есть?". Это один из вариантов ответа на неё. Особенность в том, что этот вариант не появится, если пропуска у вас на самом деле нет - она появляется только при наличии нужной инфопорции (за это отвечает строка с <has_info>).
-Далее, поподробнее остановимся на задании условий появления фразы.+Далее, поподробнее остановимся на задании условий появления фразы.<br>
Способов это сделать - два. Способов это сделать - два.
Строка 120: Строка 118:
* проверка через скриптовую функцию * проверка через скриптовую функцию
 +Первый метод мы видели выше, а второй - гораздо более комплексный и многофункциональный. Он запускает скрипт, который проводит проверку определенных вещей, и возвращает true/false. Простой пример - NPC требует денег (скажем, 5000 рублей), а нам нужно, чтобы ответная фраза игрока "Вот, держи свои 5000.", могла быть доступна для выбора, только если у нас действительно есть эти деньги. Для этого пишем такую фразу:
-Первый метод мы видели выше, а второй - гораздо более комплексный и многофункциональный. Он запускает скрипт, который проводит проверку определенных вещей, и возвращает true/false. Простой пример - NPC требует денег (скажем, 5000 рублей), а нам нужно, чтобы ответная фраза игрока "Вот, держи, ровно 5000.", могла быть доступна для выбора, только если у нас действительно есть эти деньги. Для этого пишем такую фразу:+<source lang="xml">
 +<phrase id="8">
 + <text>Вот, держи, ровно 5000.</text>
 + <precondition>dialogs.actor_have_5000</precondition> -- вызываем условие (см. объяснение №1 ниже)
 + <action>dialogs.transfer_5000</action> -- передача денег скриптом (см. объяснение №2 ниже)
 + <next>9</next>
 +</phrase>
 +</source>
- <phrase id="8">+* 1. Этот скрипт который проверяет наличие денег: если было возвращено true, то фраза доступна.
- <text>Вот, держи, ровно 5000.</text>+* 2. Вызываем другой скрипт, действие - он осуществляет саму передачу денег.
- <precondition>dialogs.actor_have_5000</precondition> -- запускается скрипт, который проверяет наличие денег: если было возвращено true, то фраза доступна+
- <action>dialogs.transfer_5000</action> -- ну, раз деньги действительно есть, то по нажатию на эту фразу они будут переданы - с помощью этого действия+
- <next>9</next>+
- </phrase>+
-Да, кстати, порядок расстановки тегов внутри фразы не играет никакой роли - они все выполняются одновременно. Единственное - <next> всегда последний.+Да, кстати, порядок расстановки тегов внутри фразы не играет никакой роли - они все выполняются одновременно. Единственное - <next> всегда последний. Еще одно - есть второй вид проверки на инфопорцию - он наоборот, проверяет её отсутствие. Применяется точно так же, но называется не has_info, а dont_has_info.
-Еще нюанс: все эти условия можно использовать только в фразах игрока.+
- +
-А, да, есть еще второй вид проверки на инфопорцию - он наоборот, проверяет её отсутствие.+
-Применяется точно так же, но называется не has_info, а dont_has_info.+
Итак, что у нас есть: Итак, что у нас есть:
- * <phrase id="..."></phrase>+* '''<phrase id="..."></phrase>''' - общий тег фразы, задание номера фразы
- * <text>...</text>+* '''<text>...</text>''' - тег, содержащий текст фразы
- * <give_info>...</give_info>+* '''<give_info>...</give_info>''' - выдача инфопорции с именем, записанным в теге
- * <has_info>...</has_info>+* '''<has_info>...</has_info>''' - проверка на наличие инфопорции с именем, записанным в теге
- * <dont_has_info>...</dont_has_info>+* '''<dont_has_info>...</dont_has_info>''' - проверка на отсутствие инфопорции с именем, записанным в теге
- * <precondition>...</precondition>+* '''<precondition>...</precondition>''' - запуск скрипта, возвращающего true или false в зависимости от чего-либо (скриптовая проверка)
- * <action>...</action>+* '''<action>...</action>''' - запуск скрипта
- * <next>...</next>+* '''<next>...</next>''' - тег ссылки на следующую фразу
-В первой версии - достаточно просто окна с формами для ввода этих параметров. А программа на основе введенных данных будет собирать фразу.+В первой версии - достаточно просто окна с формами для ввода этих параметров. А программа на основе введенных данных будет собирать фразу. Например, на основе вот таких введенных в поля данных:
-Например, на основе вот таких введенных в поля данных:+
-Номер фразы: 12+Номер фразы: '''12'''<br><br>Текст: ''Да, там сейчас база военных.<br>Я не в курсе, сколько их там точно, но<br>могу сказать, не меньше, чем один два отряда.''<br><br>Выдать инфопорцию: '''info_about_military_base'''<br><br>Проверить наличие инфопорции: '''info_1'''<br>Проверить отсутствие инфопорции: '''нет'''<br>Проверить через скрипт: '''dialogs.is_npc_a_friend'''<br>Совершить действие: '''dialogs.break_dialog'''<br><br>Номера следующих фраз: '''13'''<br><br>
-Текст: Да, там сейчас база военных. Я не в курсе, сколько их там, но могу сказать, военных там не меньше, чем один взвод.+
-Выдать инфопорцию: info_about_military_base+Нам нужна вот такая запись:
 + 
 +<source lang="xml">
 +<phrase id="12">
 + <has_info>info_1</has_info>
 + <text>Да, там сейчас база военных. Я не в курсе, сколько их там точно [...]</text>
 + <precondition>dialogs.is_npc_a_friend</precondition>
 + <action>dialogs.break_dialog</action>
 + <give_info>info_about_military_base</give_info>
 + <next>13</next>
 +</phrase>
 +</source>
 + 
 + 
 +===Текстовые (строковые) массивы===
 + 
 +Мы упустили один важный нюанс, критичный для крупных диалогов.
 + 
 +<source lang="xml">
 +<phrase id="54">
 + <text>Здравствуй, сталкер. Чем я могу помочь тебе?</text>
 + <next>55</next>
 +</phrase>
 +</source>
 + 
 +Мы записывали текст фразы в <'''text>...</text>'''. Это, безусловно, удобно, но на самом деле - может привести к проблемам. Дело в том, что таким образом можно использовать только короткие фразы. Стоит ввести в тег длинный текст, и игра... так сказать, не переварит наш диалог.
 + 
 +Поэтому нужно использовать не тексты, а ссылки на них. Работает это так:
 + 
 +[[Изображение:Text massive explain.jpg]]
 + 
 +То есть фразу мы записываем так:
 + 
 +<source lang="xml">
 +<phrase id="54">
 + <text>my_text_1</text>
 + <next>55</next>
 +</phrase>
 +</source>
 + 
 +А в игре видим нормальный текст - игра по названию my_text_1 находит его в массиве.<br>
 +Массивы (для русскоязычной версии игры) находятся в папке:
 + 
 +<pre>S.T.A.L.K.E.R\gamedata\config\text\rus</pre>
 + 
 +Нужные вам тексты фраз вы можете прописывать в любом из находящихся там .xml-файлов, их разделение на специализации - чисто формальное. Лучше всего держать тексты всех ваших диалогов в одном месте, поэтому выберите один файл - этим вы упростите работу тем, кто будет скрещивать ваш мод с другими.
 + 
 +Запись текста происходит в такой форме:
 + 
 +<source lang="xml">
 +<string id="my_text_1"> -- в заголовке указывается имя текста, которое вызывается из диалога
 + <text>Здравствуй, сталкер. Чем я могу помочь тебе?</text> -- собственно, сам текст
 +</string>
 +</source>
 + 
 +===Диалоги===
 + 
 +Ну что же, структуру фраз мы полностью разобрали. Теперь попробуем собрать из них полноценный диалог. Для начала выберем жертву для экспериментов - Сидорович вполне подойдет :)
 + 
 +Откроем папку:
 + 
 +<pre>S.T.A.L.K.E.R\gamedata\config\gameplay</pre>
 + 
 +Сейчас нас интересует файл '''character_desc_escape.xml''', хранящий профили персонажей с локации "Кордон" (остальные файлы названы по аналогичной системе - вместо '''escape''', соответственно, идет название других уровней). Открываем его и видим профиль Сидоровича '''escape_trader''' - он находится в самом начале файла.
 + 
 +<source lang="xml">
 +<specific_character id="escape_trader" no_random = "1">
 + <name>escape_trader_name</name>
 + <icon>ui_npc_u_trader</icon>
 + <bio>escape_trader_bio</bio>
 + 
 + <class>trader</class>
 + <community>trader</community>
 + <visual>actors\trader\trader</visual>
 + 
 + <rank>330</rank>
 + <reputation>23</reputation>
 + <money min="100000" max="100000" infinitive="1"/>
 + <supplies>
 + [spawn] \n
 + wpn_knife \n
 + </supplies>
 + 
 + <start_dialog>escape_trader_start_dialog</start_dialog>
 + <actor_dialog>escape_trader_talk_info</actor_dialog>
 + <actor_dialog>escape_trader_jobs</actor_dialog>
 + <actor_dialog>tm_trader_dialog</actor_dialog>
 + <actor_dialog>tm_trader_reward</actor_dialog>
 + <actor_dialog>escape_trader_done_blockpost_box</actor_dialog>
 +</specific_character>
 +</source>
 + 
 +Подробный разбор параметров профиля мы делать не будем - для этого существует [[Редактирование_NPC|отдельная статья]]. Сейчас нас интересуют теги <actor_dialog>...</actor_dialog>, ссылающиеся на доступные у этого NPC диалоги. Добавим в этот список и ссылку на наш будущий диалог:
 + 
 +<source lang="xml">
 +<start_dialog>escape_trader_start_dialog</start_dialog>
 +<actor_dialog>my_dialog_1</actor_dialog>
 +<actor_dialog>escape_trader_talk_info</actor_dialog>
 +<actor_dialog>escape_trader_jobs</actor_dialog>
 +<actor_dialog>tm_trader_dialog</actor_dialog>
 +<actor_dialog>tm_trader_reward</actor_dialog>
 +<actor_dialog>escape_trader_done_blockpost_box</actor_dialog>
 +</source>
 + 
 +Далее добавим в любой диалоговый файл, например, в '''dialogs_escape.xml''', следующий диалог:
 + 
 +<source lang="xml">
 +<dialog id="my_dialog_1">
 + <precondition>my_script_for_dialogs.my_function_1</precondition> -- условия можно вызывать и здесь
 + <phrase_list>
 + <phrase id="0"> -- фразы Меченого
 + <text>my_text_0</text> -- "Ага, вот эти ребята..."
 + <next>1</next>
 + </phrase>
 + <phrase id="1"> -- фразы Сидоровича
 + <text>my_text_1</text> -- "Ненене!!! Нет, Меченый, нет!"
 + <next>2</next>
 + </phrase>
 + <phrase id="2">
 + <text>my_text_2</text> -- "Я делаю особую, уличную магию. Кто хочет увидеть немного магии?"
 + <next>3</next>
 + </phrase>
 + <phrase id="3">
 + <text>my_text_3</text> -- "Что я тебе, Толик какой-нибудь? Целый день у этих идиотов из лагеря
 + <next>4</next> разный хлам скупал, устал, хочу просто отдохнуть..."
 + </phrase>
 + <phrase id="4">
 + <text>my_text_4</text> -- "И что купил?"
 + <next>5</next>
 + </phrase>
 + <phrase id="5">
 + <text>my_text_5</text> -- "Я купил зеленый свитер, если ты так хочешь знать! Сорок долларов,
 + <next>6</next> между прочим."
 + </phrase>
 + <phrase id="6">
 + <text>my_text_6</text> -- "Зеленый свитер? А ты уверен, что не купил тедди-бир?"
 + <next>7</next>
 + </phrase>
 + <phrase id="7">
 + <text>my_text_7</text> -- "Тедди-бир?... ТЕДДИ-БИР!!! Где мой зеленый свитер, ты что делаешь, демон?!"
 + <next>8</next>
 + </phrase>
 + <phrase id="8">
 + <text>my_text_8</text> -- "Ладно, ладно... еще один фокус. Будь добр, взгляни на телевизор
 + <next>9</next> рядом с тобой. Что он показывает?"
 + </phrase>
 + <phrase id="9">
 + <text>my_text_9</text> -- "Билд 1154!!! Ты что делаешь, демон, ты что делаешь?! Проваливай отсюда!"
 + <next>10</next>
 + </phrase>
 + <phrase id="10">
 + <text>my_text_10</text> -- "Ладно."
 + <action>dialogs.break_dialog</action> -- выход из диалога
 + </phrase>
 + </phrase_list>
 +</dialog>
 +</source>
-Проверить наличие инфопорции: info_1+Для начала лучше попробовать свои силы в простом линейном диалоге вроде этого.<br>
-Проверить отсутствие инфопорции: нет+Да, и не забудьте добавить строки с текстовыми фразами в массив.<br><br>
-Проверить через скрипт: dialogs.is_npc_a_friend+* Если вам неясно, что за ахинея написана в текстах, вам [http://ru.youtube.com/watch?v=CdTIQ6BVlvw&feature=related сюда] xD
-Совершить действие: dialogs.break_dialog+
-Номера следующих фраз: 13+===Дополнительные сведения по диалогам===
-Он должен сгенерировать такой код:+===Скрипт-генерируемые диалоги===
- <phrase id="12">+[[en:Dialogs]]
- <has_info>info_1</has_info>+[[Категория:Статьи участников]]
- <text>Да, там сейчас база военных. Я не в курсе, сколько их там, но могу сказать, военных там не меньше, чем один взвод.</text>+
- <precondition>dialogs.is_npc_a_friend</precondition>+
- <action>dialogs.break_dialog</action>+
- <give_info>info_about_military_base</give_info>+
- <next>13</next>+
- </phrase>+

Текущая версия

Статья в процессе написания...

Содержание

Общие данные

В диалогах обычно задействуются три .xml-файла:

  • character_desc_x.xml
  • dialogs_x.xml
  • stable_dialogs_x.xml

В них нам важны, соотвественно, списки присвоения диалогов персонажам, структуры диалогов и текстовые массивы для фраз.

Структура фраз

В общем виде диалог выглядит так:


диалог 001

фраза 0
"Так, чего хотел-то?"
следующие фразы: 1

фраза 1
"Задание для тебя есть. Возьмешься?"
следующие фразы: 21, 22

фраза 21
"Ну, давай."
следующие фразы: 3

фраза 22
"Не, иди к черту."
следующие фразы: нет
действие: выйти из диалога

[фраза 3 и дальнейшее продолжение...]

конец диалога


В файлах эта структура записывается следующим образом:

<dialog id="escape_trader_letat_gusi">
	<phrase_list>
 
		<phrase id="0">
			<text>Так, чего хотел-то?</text>
			<next>1</next>
		</phrase>
 
		<phrase id="1">
			<text>Задание для тебя есть. Возьмешься?</text>
			<next>21</next>
			<next>22</next>
		</phrase>
 
		<phrase id="21">
			<text>Ну, давай.</text>
			<next>3</next>
		</phrase>
 
		<phrase id="22">
			<text>Не, иди к черту.</text>
			<action>dialogs.break_dialog</action>
		</phrase>
 
		[...]
 
	</phrase_list>
</dialog>

Разберемся подробнее.

Во-первых, принадлежность фраз. Они могут принадлежать или игроку, или NPC, причем:

  • фраза, принадлежащая игроку, всегда идет первой, а за ней уже по древу диалога игра понимает, чья фраза кому принадлежит (например, у нас 0, 21, 22 - игрока; а 1, 3 - NPC)
  • только у фразы, принадлежащей NPC, можно выбрать несколько вариантов ответа игрока

Впрочем, и у фразы игрока можно сделать несколько вариантов ответов, но поскольку компьютер не обладает способностью самостоятельно выбирать, то каждый из вариантов должен быть заранее определен по условиям выбора (например, по наличию у игрока какого-нибудь предмета, или количества денег, или репутации и т.д.), причем условия выбора различных вариантов никогда не должны одновременно становиться подходящими. Это мы разберем позднее.

Во-вторых, структура фразы. Простейшая фраза выглядит так:

<phrase id="0">    -- открывающий тег с ID фразы
	<text>Привет.</text>    -- текст фразы
	<next>1</next>    -- ссылка на следующую фразу
</phrase>    -- закрытие тега фразы

Но есть возможность строить и такие фразы (в данном случае она принадлежит NPC, а игрок на неё будет давать ответ):

<phrase id="1">
	<give_info>propusk_given</give_info> -- выдача инфопорции (см. объяснение №1 ниже)
	<text>Вот, держи пропуск. Теперь тебе охранник позволит войти.</text>
	<action>dialogs.give_propusk_item</action> -- ссылка на скрипт (см. объяснение №2 ниже)
	<next>21</next>
	<next>22</next>
	<next>23</next>
</phrase>
  • 1. Здесь у нас выдается инфопорция, которая может потом использоваться в различных местах (например, её наличие может проверяться каким-нибудь охранником - и если она есть, то он, скажем, отойдет и пропустит игрока внутрь). Важно понимать отличие инфопорции от предмета. Инфопорция - это факт наличия пропуска, а лежащий в инвентаре пропуск - материальный предмет. Можно, кстати, обойтись и без инфопорций, впоследствии пользуясь скриптами, проверяющими инвентарь игрока и ищущими нужный предмет, но этот способ сложен и нам пока не понадобится.
  • 2. Это скрипт, выдающий игроку предмет "пропуск" в инвентарь. Ссылка на скрипты дается в формате имя_файла.имя_функции.

Как видите, фраза, в которой некий NPC выдает игроку пропуск, позволяющий пройти дальше, достаточно сложна.

Вот еще один пример (здесь она принадлежит игроку):

<phrase id="4">
	<has_info>propusk_given</has_info> -- проверка на наличие инфопорции propusk_given
	<text>Да, пропуск у меня есть.</text>
	<action>dialogs.break_dialog</action> -- ссылка на скрипт, завершающий диалог
</phrase>

Здесь у нас фраза из диалога игрока с NPC - та, что после вопроса NPC "А пропуск у тебя есть?". Это один из вариантов ответа на неё. Особенность в том, что этот вариант не появится, если пропуска у вас на самом деле нет - она появляется только при наличии нужной инфопорции (за это отвечает строка с <has_info>).

Далее, поподробнее остановимся на задании условий появления фразы.
Способов это сделать - два.

   * проверка на наличие инфопорций
   * проверка через скриптовую функцию

Первый метод мы видели выше, а второй - гораздо более комплексный и многофункциональный. Он запускает скрипт, который проводит проверку определенных вещей, и возвращает true/false. Простой пример - NPC требует денег (скажем, 5000 рублей), а нам нужно, чтобы ответная фраза игрока "Вот, держи свои 5000.", могла быть доступна для выбора, только если у нас действительно есть эти деньги. Для этого пишем такую фразу:

<phrase id="8">
	<text>Вот, держи, ровно 5000.</text>
	<precondition>dialogs.actor_have_5000</precondition> -- вызываем условие (см. объяснение №1 ниже)
	<action>dialogs.transfer_5000</action> -- передача денег скриптом (см. объяснение №2 ниже)
	<next>9</next>
</phrase>
  • 1. Этот скрипт который проверяет наличие денег: если было возвращено true, то фраза доступна.
  • 2. Вызываем другой скрипт, действие - он осуществляет саму передачу денег.

Да, кстати, порядок расстановки тегов внутри фразы не играет никакой роли - они все выполняются одновременно. Единственное - <next> всегда последний. Еще одно - есть второй вид проверки на инфопорцию - он наоборот, проверяет её отсутствие. Применяется точно так же, но называется не has_info, а dont_has_info.

Итак, что у нас есть:

  • <phrase id="..."></phrase> - общий тег фразы, задание номера фразы
  • <text>...</text> - тег, содержащий текст фразы
  • <give_info>...</give_info> - выдача инфопорции с именем, записанным в теге
  • <has_info>...</has_info> - проверка на наличие инфопорции с именем, записанным в теге
  • <dont_has_info>...</dont_has_info> - проверка на отсутствие инфопорции с именем, записанным в теге
  • <precondition>...</precondition> - запуск скрипта, возвращающего true или false в зависимости от чего-либо (скриптовая проверка)
  • <action>...</action> - запуск скрипта
  • <next>...</next> - тег ссылки на следующую фразу


В первой версии - достаточно просто окна с формами для ввода этих параметров. А программа на основе введенных данных будет собирать фразу. Например, на основе вот таких введенных в поля данных:

Номер фразы: 12

Текст: Да, там сейчас база военных.
Я не в курсе, сколько их там точно, но
могу сказать, не меньше, чем один два отряда.


Выдать инфопорцию: info_about_military_base

Проверить наличие инфопорции: info_1
Проверить отсутствие инфопорции: нет
Проверить через скрипт: dialogs.is_npc_a_friend
Совершить действие: dialogs.break_dialog

Номера следующих фраз: 13

Нам нужна вот такая запись:

<phrase id="12">
	<has_info>info_1</has_info>
	<text>Да, там сейчас база военных. Я не в курсе, сколько их там точно [...]</text>
	<precondition>dialogs.is_npc_a_friend</precondition>
	<action>dialogs.break_dialog</action>
	<give_info>info_about_military_base</give_info>
	<next>13</next>
</phrase>


Текстовые (строковые) массивы

Мы упустили один важный нюанс, критичный для крупных диалогов.

<phrase id="54">
	<text>Здравствуй, сталкер. Чем я могу помочь тебе?</text>
	<next>55</next>
</phrase>

Мы записывали текст фразы в <text>...</text>. Это, безусловно, удобно, но на самом деле - может привести к проблемам. Дело в том, что таким образом можно использовать только короткие фразы. Стоит ввести в тег длинный текст, и игра... так сказать, не переварит наш диалог.

Поэтому нужно использовать не тексты, а ссылки на них. Работает это так:

Изображение:Text massive explain.jpg

То есть фразу мы записываем так:

<phrase id="54">
	<text>my_text_1</text>
	<next>55</next>
</phrase>

А в игре видим нормальный текст - игра по названию my_text_1 находит его в массиве.
Массивы (для русскоязычной версии игры) находятся в папке:

S.T.A.L.K.E.R\gamedata\config\text\rus

Нужные вам тексты фраз вы можете прописывать в любом из находящихся там .xml-файлов, их разделение на специализации - чисто формальное. Лучше всего держать тексты всех ваших диалогов в одном месте, поэтому выберите один файл - этим вы упростите работу тем, кто будет скрещивать ваш мод с другими.

Запись текста происходит в такой форме:

<string id="my_text_1"> -- в заголовке указывается имя текста, которое вызывается из диалога
	<text>Здравствуй, сталкер. Чем я могу помочь тебе?</text> -- собственно, сам текст
</string>

Диалоги

Ну что же, структуру фраз мы полностью разобрали. Теперь попробуем собрать из них полноценный диалог. Для начала выберем жертву для экспериментов - Сидорович вполне подойдет :)

Откроем папку:

S.T.A.L.K.E.R\gamedata\config\gameplay

Сейчас нас интересует файл character_desc_escape.xml, хранящий профили персонажей с локации "Кордон" (остальные файлы названы по аналогичной системе - вместо escape, соответственно, идет название других уровней). Открываем его и видим профиль Сидоровича escape_trader - он находится в самом начале файла.

<specific_character id="escape_trader" no_random = "1">
	<name>escape_trader_name</name>
	<icon>ui_npc_u_trader</icon>
	<bio>escape_trader_bio</bio>
 
	<class>trader</class>
	<community>trader</community>
	<visual>actors\trader\trader</visual>
 
	<rank>330</rank>
	<reputation>23</reputation>
	<money min="100000" max="100000" infinitive="1"/> 
	<supplies>
		[spawn] \n
		wpn_knife \n
	</supplies>
 
	<start_dialog>escape_trader_start_dialog</start_dialog>
	<actor_dialog>escape_trader_talk_info</actor_dialog>
	<actor_dialog>escape_trader_jobs</actor_dialog>
	<actor_dialog>tm_trader_dialog</actor_dialog>
	<actor_dialog>tm_trader_reward</actor_dialog>
	<actor_dialog>escape_trader_done_blockpost_box</actor_dialog>
</specific_character>

Подробный разбор параметров профиля мы делать не будем - для этого существует отдельная статья. Сейчас нас интересуют теги <actor_dialog>...</actor_dialog>, ссылающиеся на доступные у этого NPC диалоги. Добавим в этот список и ссылку на наш будущий диалог:

<start_dialog>escape_trader_start_dialog</start_dialog>
<actor_dialog>my_dialog_1</actor_dialog>
<actor_dialog>escape_trader_talk_info</actor_dialog>
<actor_dialog>escape_trader_jobs</actor_dialog>
<actor_dialog>tm_trader_dialog</actor_dialog>
<actor_dialog>tm_trader_reward</actor_dialog>
<actor_dialog>escape_trader_done_blockpost_box</actor_dialog>

Далее добавим в любой диалоговый файл, например, в dialogs_escape.xml, следующий диалог:

<dialog id="my_dialog_1">
	<precondition>my_script_for_dialogs.my_function_1</precondition> -- условия можно вызывать и здесь
	<phrase_list>
		<phrase id="0"> -- фразы Меченого
			<text>my_text_0</text> -- "Ага, вот эти ребята..."
			<next>1</next>
		</phrase>
		<phrase id="1"> -- фразы Сидоровича
			<text>my_text_1</text> -- "Ненене!!! Нет, Меченый, нет!"
			<next>2</next>
		</phrase>
		<phrase id="2">
			<text>my_text_2</text> -- "Я делаю особую, уличную магию. Кто хочет увидеть немного магии?"
			<next>3</next>
		</phrase>
		<phrase id="3">            
			<text>my_text_3</text> -- "Что я тебе, Толик какой-нибудь? Целый день у этих идиотов из лагеря 
			<next>4</next>             разный хлам скупал, устал, хочу просто отдохнуть..."
		</phrase>
		<phrase id="4">
			<text>my_text_4</text> -- "И что купил?"
			<next>5</next>
		</phrase>
		<phrase id="5">
			<text>my_text_5</text> -- "Я купил зеленый свитер, если ты так хочешь знать! Сорок долларов,
			<next>6</next>             между прочим."
		</phrase>
		<phrase id="6">
			<text>my_text_6</text> -- "Зеленый свитер? А ты уверен, что не купил тедди-бир?"
			<next>7</next>
		</phrase>
		<phrase id="7">
			<text>my_text_7</text> -- "Тедди-бир?... ТЕДДИ-БИР!!! Где мой зеленый свитер, ты что делаешь, демон?!"
			<next>8</next>
		</phrase>
		<phrase id="8">
			<text>my_text_8</text> -- "Ладно, ладно... еще один фокус. Будь добр, взгляни на телевизор 
			<next>9</next>             рядом с тобой. Что он показывает?"
		</phrase>
		<phrase id="9">
			<text>my_text_9</text> -- "Билд 1154!!! Ты что делаешь, демон, ты что делаешь?! Проваливай отсюда!"
			<next>10</next>
		</phrase>
		<phrase id="10">          
			<text>my_text_10</text> -- "Ладно."
			<action>dialogs.break_dialog</action> -- выход из диалога
		</phrase>
	</phrase_list>
</dialog>

Для начала лучше попробовать свои силы в простом линейном диалоге вроде этого.
Да, и не забудьте добавить строки с текстовыми фразами в массив.

  • Если вам неясно, что за ахинея написана в текстах, вам сюда xD

Дополнительные сведения по диалогам

Скрипт-генерируемые диалоги

Личные инструменты
На других языках