📌 Обновление Форума
 📌 Популярные темы
 📌 Топ Сталкеров
Anubis Anubis ✒️825.Сообщ ⚖️Реп: 158 💠О-Сознание
Митяй Митяй ✒️100.Сообщ ⚖️Реп: 12 💠Чистое Небо
s-stalk s-stalk ✒️94.Сообщ ⚖️Реп: 46 💠Чистое Небо
LISSZ10 LISSZ10 ✒️74.Сообщ ⚖️Реп: 37 💠Наёмники
stalkercom stalkercom ✒️65.Сообщ ⚖️Реп: 8 💠Монолит
Стриж Стриж ✒️58.Сообщ ⚖️Реп: 14 💠Одиночки
 📌 Новые сталкеры на форуме
maximdalechuk maximdalechuk 📅Суббота 🕑22:13:09
gfotyrjrjcnz gfotyrjrjcnz 📅Суббота 🕑21:24:22
kofanovds kofanovds 📅Суббота 🕑18:53:00
directedbytsa19 directedbytsa19 📅Суббота 🕑16:20:37
valerijvrn valerijvrn 📅Суббота 🕑15:01:16
odincovao1991 odincovao1991 📅Суббота 🕑13:44:16



  • Страница 1 из 1
  • 1
Создание диалогов (полный обзор)
Anubis

Anubis

Офлайн

Титул: Хранитель Зоны

825

57

158


Сообщение 1 01:08:52, 2022.01.05
Сталкерское уважение +1 Сталкерское уважение +2 Постоянный житель портала Постоянный житель портала + Постоянный житель портала +2 Постоянный житель портала +2 Постоянный житель портала +2
Общие данные по созданию диалогов сталкер


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

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

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


В файлах эта структура записывается следующим образом:
Код
<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 "А пропуск у тебя есть?". Это один из вариантов ответа на неё. Особенность в том, что этот вариант не появится, если пропуска у вас на самом деле нет - она появляется только при наличии нужной инфопорции (за это отвечает строка с ).

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

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


Первый метод мы видели выше, а второй - гораздо более комплексный и многофункциональный. Он запускает скрипт, который проводит проверку определенных вещей, и возвращает 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. Вызываем другой скрипт, действие - он осуществляет саму передачу денег.
Да, кстати, порядок расстановки тегов внутри фразы не играет никакой роли - они все выполняются одновременно. Единственное - всегда последний. Еще одно - есть второй вид проверки на инфопорцию - он наоборот, проверяет её отсутствие. Применяется точно так же, но называется не 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>

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

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



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

Код
<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>

Подробный разбор параметров профиля мы делать не будем - для этого существует отдельная статья. Сейчас нас интересуют теги ..., ссылающиеся на доступные у этого 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
"Динамические диалоги"
Выше был изложен вариант написания простых диалогов вопрос-ответ. Но в этой части статьи я расскажу как написать "динамические диалоги", которые предполагают выбор ответа не только ГГ, но и НПС с которым мы говорим. Рассчитано на опытных пользователей диалога.

Вообще урок это копия предыдущей статьи, с той лишь небольшой разницей, что у как и у ГГ, так и у НПС будет несколько вариантов ответов. Получившаяся структура диалога:

Код
<dialog id="название диалога">
    <phrase_list>
  <phrase id="0">
   <text>слушаю</text>
   <next>10</next>
  </phrase>
  <phrase id="10">
   <text>Привет, как дела?</text>
   <next>1</next>
   <next>2</next>
   <next>3</next>
  </phrase>
  <phrase id="1">
   <text>Отлично!</text>
   <next>11</next>
  </phrase>
  <phrase id="2">
   <text>Нормик, что хотел?</text>
   <next>21</next>
  </phrase>
  <phrase id="3">
   <text>Плохо, иди отсюда(</text>
   <action>dialogs.break_dialog</action>
  </phrase>
  <phrase id="11">
   <text>Это хорошо =)</text>
  </phrase>
  <phrase id="21">
   <text>Да вот {....}</text>
  </phrase>
  [и так далее]
    </phrase_list>
</dialog>

Ну вот как-то так. Рассмотрим наиболее интересную часть:

Код
<phrase id="10">
   <text>Привет, как дела?</text>
   <next>1</next>
   <next>2</next>
   <next>3</next>


Здесь мы предоставляем выбор дальнейшего диалога для НПС, причём в этой структуре его выбор получается абсолютно рандомным. Скриншоты:



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

Цитата
ГГ: Привет, у меня тут есть некоторые вещи, взгляни, нужно что?
НПС ответ1: (проверка на АК-47) Да, мне нужна эта пушка!
НПС ответ2: (проверка на консервы) Ух как кушать хочется, можешь мне дать консерву?
НПС ответ3: (без предпроверки) Есть ли у тебя водка?
ГГ на ответ 1 и 2: Да, держи!
ГГ на ответ 3: (проверка) Держи/ Извини, нету((

Ну и напоследок скажу, что можно даже управлять вероятностью ответа НПС на фразу ГГ, если прописать несколько номер ответа. Например, если написать:

Код
<next>1</next>
<next>3</next>
<next>3</next>
<next>3</next>


То вероятность ответа "3" будет составлять 75%

P.S.: Это не просто увлекательная и интересная вещь, но и очень уж трудоёмкая - у меня день уходил на создание простого диалога. Для огромной модификации только на диалоги нужно человек 20-30. Но зато одних диалогов хватит чтобы впечатлить! Аналогов быть не должно, а сама игра использует этот приём только в ЗП и то в 2-х местах(на Затоне, другие локации не глядел).

Пример реализации динамического диалога
А теперь я(Ким) покажу, как выглядит вышеописанный диалог в игре(точнее в файлах конфигурации). На самом деле это не так уж и сложно и такой диалог можно сделать минут за 15(я сам сделал за 5 минут). Диалоги такого типа активно используются всё в том же Oblivion Lost. Начнём. Сам диалог:

Код
<dialog id="dinamic_dialog_1_test">
   <dont_has_info>dialog_done</dont_has_info>
<phrase_list>
    <phrase id="0">
        <text>Привет. У меня есть некоторые вещи из того, что ты просил. Выбери, что тебе нужнее.</text>
  <next>3</next>
  <next>4</next>
  <next>5</next>
    </phrase>
  <phrase id="3">
  <precondition>dialogs_gr.is_has_ak_74</precondition>
        <text>Да, мне нужна эта пушка!</text>
  <next>31</next>
    </phrase>
   <phrase id="31">
        <text>Бери, ты мне помог, я тебе.</text>
  <give_info>dialog_done</give_info>
  <action>dialogs_gr.give_ak_74</action>
  <action>dialogs.break_dialog</action>
    </phrase>
  <phrase id="4">
  <precondition>dialogs_gr.is_has_conserva</precondition>
        <text>Ух как кушать хочется, можешь мне дать консерву?</text>
  <next>41</next>
    </phrase>
  <phrase id="41">
        <text>На, ешь на здоровье!</text>
  <give_info>dialog_done</give_info>
  <action>dialogs_gr.give_conserva</action>
  <action>dialogs.break_dialog</action>
    </phrase>
  <phrase id="5">
        <text>Есть ли у тебя водка?</text>
  <next>51</next>
    </phrase>
  <phrase id="51">
        <text>Извини, ничего нет</text>
  <action>dialogs.break_dialog</action>
    </phrase>
   <phrase id="52">
  <precondition>dialogs_gr.is_has_vodka</precondition>
        <text>На, похмелись.</text>
  <action>dialogs_gr.give_vodka</action>
  <give_info>dialog_done</give_info>
  <action>dialogs.break_dialog</action>
    </phrase>
</phrase_list>
</dialog>

Скрипты для него:

Код
function   give_conserva (first_speaker, second_speaker)
    dialogs.relocate_item_section_from_actor(first_speaker, second_speaker, "conserva")
end
function is_has_conserva()
    if db.actor:object("conserva") then
        return true
    end
    return false
end

   function   give_ak_74 (first_speaker, second_speaker)
    dialogs.relocate_item_section_from_actor(first_speaker, second_speaker, "wpn_ak74")
end
function is_has_ak_74()
    if db.actor:object("wpn_ak74") then
        return true
    end
    return false
end

   function   give_vodka (first_speaker, second_speaker)
    dialogs.relocate_item_section_from_actor(first_speaker, second_speaker, "vodka")
end
function is_has_vodka()
    if db.actor:object("vodka") then
        return true
    end
    return false
end

Как видите - ничего сложного удачи вам.

Прикрепления: 3188289.jpg (23.7 Kb) · 3904581.jpg (296.3 Kb) · 2377583.jpg (294.3 Kb)



Митяй

Митяй

Офлайн

Звание: Опытный

100

4

12


Сообщение 2 16:16:07, 2023.11.13
Постоянный житель портала
интересно

Зона - самое удивительное, с чем сталкивался человек!

  • Страница 1 из 1
  • 1
Поиск:

Banner


🔰Заходили сегодня: | dance6024, nik-sazonov, necr0s7, GlebSafin, Ohaegodzaimas, dima228usas12, andrejresetov79714, vexaxpamov, sergeicherkasov45, Smaili-fly, aleksdeep18, maximdalechuk