В этом уроке мы разберемся как устроен стандартный диалог в Корсарах, из каких элементов он состоит и как с этим работать.
Из чего состоит диалог?
Все диалоги лежат по пути ..\PROGRAM\DIALOGS\
Если вы откроете несколько файлов, то обязательно заметите, что все они очень похожи. Возьмем следующий кусок кода:
Если вы откроете несколько файлов, то обязательно заметите, что все они очень похожи. Возьмем следующий кусок кода:
void ProcessDialogEvent() {
ref NPChar, PChar;
aref Link;
PChar = GetMainCharacter();
DeleteAttribute(&Dialog,"Links");
makeref(NPChar,CharacterRef);
makearef(Link, Dialog.Links);
switch(Dialog.CurrentNode) {
case "First Time":
Dialog.Text = "Здравствуйте! Меня зовут " + NPChar.Name + ". Могу ли я узнать как вас зовут?";
Link.l1 = "Меня зовут " + PChar.Name + ". Я капитан корабля " + PChar.Ship.Name + ".";
Link.l1.go = "speak";
Link.l2 = "Это не твое дело, " + NPChar.Name + "! Пока!";
Link.l2.go = "exit";
break;
case "speak":
Dialog.Text = "Что вы от меня хотели?";
Link.l1 = "Да нет, ничего! До свидания!";
Link.l1.go = "exit";
break;
case "exit":
NPChar.Dialog.CurrentNode = NPChar.Dialog.TempNode;
DialogExit();
break;
}
}
Функция ProcessDialogEvent() обрабатывает наш диалог. Строго говоря это метод обработки прерывания "разговор". Внутри нее уже доступна основная информация: диалог, персонаж с которым мы разговариваем и т.д. Но для удобства работы принято создавать переменные-ссылки («алиасы») с короткими, интуитивно понятными именами.
Справка:Alias (с англ. — «псевдоним») — это имя, назначенное источнику данных в запросе при использовании выражения в качестве источника данных или для упрощения ввода и прочтения инструкции. Такая возможность полезна, если имя источника данных слишком длинное или его трудно вводить.
С этого приведённая в примере ф-ция и начинается:
ref NPChar, PChar;
aref Link;
PChar = GetMainCharacter(); // наш ГГ
DeleteAttribute(&Dialog,"Links"); // чистим варианты ответов от предыдущего диалога
makeref(NPChar,CharacterRef); // НПЦ с которым разговариваем
makearef(Link, Dialog.Links); // ссылка на атрибут NPChar.Dialog.Links
Далее идет само тело диалога. И реализовано оно посредством перехода по нодам при помощи конструкции switch.
Ноду вы можете понимать как страницу в диалоге. В процессе станет более понятно.
Ноду вы можете понимать как страницу в диалоге. В процессе станет более понятно.
По умолчанию стартовой нодой является "First Time". Рассмотрим её наполнение:
case "First Time":
// текст, который отображается как реплика НПЦ
Dialog.Text = "Здравствуйте! Меня зовут " + NPChar.Name + ". Могу ли я узнать как вас зовут?";
// текст, который отображается как доступный ответ ГГ
Link.l1 = "Меня зовут " + PChar.Name + ". Я капитан корабля " + PChar.Ship.Name + ".";
// нода, на которую ведет данная реплика
Link.l1.go = "speak";
// вторая реплика ГГ
Link.l2 = "Это не твое дело, " + NPChar.Name + "! Пока!";
// и её нода
Link.l2.go = "exit";
break;
С текстом, который говорит нам НПЦ, думаю все понятно. А что за линки такие?
Это ссылки на другие ноды диалога. Тобишь, наши реплики ответов в диалоге.
Собственно, Link.l2 - это текст, который мы видим в окне диалога, а Link.l2.go - название ноды, на которую эта реплика ведет.
В данном примере вариантов ответа у нас два - Link.l1 и Link.l2, но, разумеется, у вас их может быть сколь угодно много.
Итак, первая реплика ведет нас к кейсу "speak". И здесь, в принципе, ничего нового не происходит:
Это ссылки на другие ноды диалога. Тобишь, наши реплики ответов в диалоге.
Собственно, Link.l2 - это текст, который мы видим в окне диалога, а Link.l2.go - название ноды, на которую эта реплика ведет.
В данном примере вариантов ответа у нас два - Link.l1 и Link.l2, но, разумеется, у вас их может быть сколь угодно много.
Итак, первая реплика ведет нас к кейсу "speak". И здесь, в принципе, ничего нового не происходит:
case "speak":
Dialog.Text = "Что вы от меня хотели?"; // реплика НПЦ
Link.l1 = "Да нет, ничего! До свидания!"; // вариант ответа
Link.l1.go = "exit"; // нода
break;
И последний кейс - "exit". Он выводит нас из диалога:
case "exit":
// помещаем в текущую ноду ссылку на открывающую ноду диалога
NPChar.Dialog.CurrentNode = NPChar.Dialog.TempNode;
// ф-ция выхода из диалога
DialogExit();
break;
Закрытие окна диалога осуществляется вызовом ф-ции DialogExit(). Но есть еще кое-что.
Здесь важно запомнить, что разговор с любым персонажем всегда инициируется с Dialog.CurrentNode.
Поэтому перед завершением разговора важно поместить туда открывающую ноду - по умолчанию это "First Time".
Иначе при следующем начале разговора вы попадете в ту ноду, на которой закончили - т.е. в ноду выхода из диалога.
Как правило, при создании персонажа, в NPChar.Dialog.TempNode помещают ссылку на начальную ноду диалога.
Отсюда использование конструкции NPChar.Dialog.CurrentNode = NPChar.Dialog.TempNode; ведь в TempNode уже лежит наш "First Time".
Поэтому перед завершением разговора важно поместить туда открывающую ноду - по умолчанию это "First Time".
Иначе при следующем начале разговора вы попадете в ту ноду, на которой закончили - т.е. в ноду выхода из диалога.
Как правило, при создании персонажа, в NPChar.Dialog.TempNode помещают ссылку на начальную ноду диалога.
Отсюда использование конструкции NPChar.Dialog.CurrentNode = NPChar.Dialog.TempNode; ведь в TempNode уже лежит наш "First Time".
Стоит также отметить, что ноды могут называться как угодно. В том числе и открывающая - совсем не обязательно должна называться "First Time", главное чтобы вы правильно указали её название при инициации персонажа.
Разделение мух и котлет
В файлах диалогов оригинальной игры (или серьезных аддонов с переводом на другие языки) вас ожидает следующая картина:
// ..\PROGRAM\DIALOGS\Alan Milds_dialog.c
case "Meeting":
dialog.snd = "Voice\ALMI\ALMI006";
d.Text = DLG_TEXT[14] + NPChar.name + " " + NPChar.lastname + DLG_TEXT[15];
Link.l1 = DLG_TEXT[16] + NPChar.name + DLG_TEXT[17];
if(CheckAttribute(Pchar, "Quest.Story_OxbayCaptured"))
{
Link.l1.go = "no trade";
}
else
{
Link.l1.go = "trade";
}
Link.l2 = DLG_TEXT[18] + NPChar.name + DLG_TEXT[19];
Link.l2.go = "quest lines";
Link.l3 = DLG_TEXT[20];
Link.l3.go = "exit";
break;
Куда делся текст и что это за переменные DLG_TEXT[14] ?
Во-первых, текст никуда не делся, он лежит в массиве DLG_TEXT.
Массив этот объявляется в заголовочном файле (*.h), который, как правило, имеет такое же название и лежит в той же папке. Подключается он в самом начале файла с диалогом:
Во-первых, текст никуда не делся, он лежит в массиве DLG_TEXT.
Массив этот объявляется в заголовочном файле (*.h), который, как правило, имеет такое же название и лежит в той же папке. Подключается он в самом начале файла с диалогом:
#include "DIALOGS\Alan Milds_dialog.h"
Таким образом, вы всегда можете узнать где данный файл находится и как называется.
Наполнение самого файла - обычный массив строк:
Наполнение самого файла - обычный массив строк:
// ..\PROGRAM\DIALOGS\Alan Milds_dialog.h
string DLG_TEXT[50] = {
"Будем торговать по-крупному или вам нужна всякая мелочевка, капитан?",
"Я хочу продать груз, который привез.",
"Хочу прикупить пару вещей себе лично.",
"Вообще не будем. Всего хорошего.",
"Здравствуйте, ",
". Мой магазин к вашим услугам.",
"Благодарю, меня зовут ",
// ...
}
Используется такой подход для того, чтобы можно было легко подключать диалоги на разных якыках, а также облегчения самого процесса перевода.
Обратите внимание, что нумерация элементов массива начинается с нуля. То есть строка "Будем торговать по-крупному или вам нужна всякая мелочевка, капитан?" будет находиться в DLG_TEXT[0].
Обратите внимание, что нумерация элементов массива начинается с нуля. То есть строка "Будем торговать по-крупному или вам нужна всякая мелочевка, капитан?" будет находиться в DLG_TEXT[0].
С теоретическим примером разобрались.
Если у вас остались какие-либо вопросы - вы можете задать их в коментариях или разделе Q/A.
В следующем уроке мы разберем живой пример из игры и посмотрим какие дополнительные функции используются в диалогах.
Если у вас остались какие-либо вопросы - вы можете задать их в коментариях или разделе Q/A.
В следующем уроке мы разберем живой пример из игры и посмотрим какие дополнительные функции используются в диалогах.