fallout.ru

Текст и Диалог

Многие из этих функций используются не только в скриптах, но и в поле результата окна редактора диалогов. Диалоги – это само по себе искусство, которое нельзя полностью описать здесь, но я дам краткое представление об этом.

Краткое описание создания диалога

Концепция диалога в Морровинде

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

Верхний уровень, различные «подразделения» диалога:
Тема (Topic): непосредственно сами фразы тем, появляющиеся в окне диалога в игре.
Приветствия (Greetings): фразы, которыми приветствует NPC игрока при инициализации разговора.
Убеждение (Persuasion): ответы, получаемые игроком в результате попыток поднять отношение NPC.
Журнал (Journal): журнальные заметки игрока.
Голоса (Voices): Звуковые файлы в формате .mp3, которые NPC произносят в тех или иных ситуациях.

Подуровень 1:

Каждый из этих верхних уровней имеет подуровни, которые я называю топиками – для подразделения Тем, существуют «ключевые слова», которые появятся на правой панели окна диалога в игре. Для Голосов подразделение определяется разными игровыми кондициями. Для Приветствий это просто тематические категории, определяемые например, тем, что персонаж серьёзно ранен. Для Убеждения это специальные фразы, сообщающие об отказе в услугах или успехе/неудаче подкупа.

Подуровень 2:

Для каждой темы существует одна или несколько описывающих её фраз. Для Тем и Приветствий это просто ответы NPC. Для Журнала это могут быть записи, появляющиеся по мере выполнения квестов.

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

Каждой из этих фраз можно задать определённые условия появления в окне редактора диалогов. Вы увидите большой список кондиций, который определяет какой NPC (его ID) или группа людей (их раса, класс, отношение к игроку и т.д.) может ответить соответствующим образом. Также там есть две проверки на то, в какой гильдии и в каком ранге находится игрок. А в списке правее Вы можете задать до шести проверок, которые могут относиться как к игроку и NPC, так и к значению глобальных переменных и многому другому (смотрите ниже).

Очень полезным свойством окна редактора диалогов является возможность в списке “filter for” (в левом нижнем углу) выбрать темы, которые «знает» только какой-то один NPC. Заметьте, что когда Вы создаетё новый топик, он ещё не содержит никаких ответов. Таким образом, в темах любого из NPC он не будет виден, поскольку они его «не знают». Вам придётся в списке фильтра выбрать пустой слот (самая верхняя строчка), чтобы вновь увидеть все топики для разговора, написать хотя бы одну фразу, и лишь потом вновь включить фильтр, если это необходимо.

Как работает диалог

Для определения того, что тема должна отображаться во время диалога с NPC, игра проверяет следующие условия:

  1. «Знает» ли NPC тему – это определяется условиями, проставленными в поле “speaker conditions” – если NPC выполняет все условия хотя бы к одному ответу в этой теме, он «знает» её.
  2. Знает ли игровой персонаж тему. Он узнаёт её, если её название было ранее упомянуто в разговоре с NPC или было специально добавлено функцией AddTopic.
  3. Если и игрок, и NPC «знают» тему, она показывается в списке тем и подсвечивается в тексте – теперь она может быть выбрана, и на неё будет дан соответствующий ответ.

Когда игре нужно выбрать правильный ответ из списка ответов на эту тему, движок делает следующее:

  • Он начинает просмотр сверху списка, проверяя, удовлетворяются ли условия для соответствующего ответа.
  • Если нет -> Движок переходит к следующему ответу в списке и снова проверяет условия.
  • Если да -> Эта запись используется, как ответ, – появляется в окне диалога.

Специальное правило действует для приветствий: если ни один из ответов из списка “Приветствие 0” не подходит по условиям, начинается проверка “Приветствие 1”.
Специальное правило для Журнала: здесь только одно условие, индекс, вызываемый функцией Journal. Оно должно строго выполняться.

Когда ответ выбран, движок:

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

Учтите, что Поле результата позволяет Вам обмениваться информацией со скриптами (например, изменяя переменные или добавляя записи в журнал игрока). К тому же, Вы можете скриптами осуществлять обратную связь, влияя на диалог, устанавливая условия, которые можно проверить (например, вы можете проверять локальную или глобальные переменные в Поле условий диалога). Простейший скрипт, оказывающий влияние на диалог – это скрипт “nolore”, который используется только для того, чтобы удержать NPC от использования стандартных веток диалога.

Несколько золотых правил

  • Самые специфические (с наибольшим количеством условий) ответы должны быть вверху списка ответов, а ответы с минимальным количеством условий в самом низу. Поскольку движок использует первый ответ, удовлетворяющий условиям (начиная сверху), ответ с наибольшим количеством условий должен быть первым иначе движок его не будет использовать вообще. Например, у вас есть два условия:
    1. NPC, с которым разговаривает игрок находится в Вивек
    2. Этого NPC зовут Валас Рарлас (он находится в этом городе)
    Если Вы поставите ответ, удовлетворяющий условию нахождения в Вивеке первым, вы никогда не увидите ответ для Валаса Рарласа, так как первый же ответ удовлетворяет всем условиям.
  • Если вы хотите, чтобы NPC мог говорить с игроком о чем-то особенном, вы должны объявить о наличии данной темы диалога, то есть вставить ключевые слова названия топика в диалог, например в приветствие, либо в ответ на тему «последние слухи» (“latest rumors”). В виде альтернативы вы можете использовать скрипт с функцией AddTopic.
  • Темы, Приветствия, Журнал (Topic, Greeting, Journal) находятся в одной базе данных – именно поэтому журнальные записи используют формат вроде A1_сны. Если бы называние было просто “сны”, то тогда журнальная запись “сны” появлялась бы в ответ на ключевое слово “сны” в диалоге.

Функции, управляющие диалогом

Сообщения

MessageBox, “Сообщение”, [пер1], [пер2], …, [“кнопка1”], [“кнопка2”], …

Функция MessageBox позволяет выводить информацию в окне сообщения, которое остаётся на экране определённое время или пока игрок не выберет вариант ответа. Если игрок разговаривает с каким-то NPC, функция выведет сообщение не в отдельном окошке, а в самом окне диалога. К счастью, подобные сообщения будут отличаться по цвету от текста разговора. ”MessageBox” имеет несколько режимов операций. Самый простой состоит в том, чтобы просто вывести сообщение на несколько секунд, как в следующем скрипте. Как только игрок поднимает предмет, срабатывает функция MessageBox:

Begin informplayer

Short OnPCEquip

if ( MenuMode == 1 )
            return
endif

if (OnPCEquip ==1 )
            MessageBox, “Меч вибрирует в Ваших руках”
            Set OnPCEquip to 0
Endif

End informplayer

Другой режим состоит в том, что сообщение остаётся на экране, пока игрок не нажмёт специальную кнопку:

MessageBox, “Улия поднимает руки и произносит некое заклинание. Вы переноситесь в регион Шеогорад”, “Ok”

Благодаря третьему режиму Вы можете запросить у игрока некое решение с помощью окна сообщения с несколькими кнопками (до 9), используя функцию GetButtonPressed:

GetButtonPressed (возвращает short)

Возвращает порядковый номер кнопки, начиная с 0. Если же ничего ещё не было выбрано, то значение будет –1.

Пример:

Begin choices

Short button ;определить как переменную – иначе будут ошибки
Short status
Short OnPCEquip

if ( OnPCEquip ==1 )
            MessageBox, “Клинок вибрирует в Ваших руках”, “Взяться за рукоять”, “Выбросить меч”
            Set OnPCEquip to 0 ;показывать окно сообщения только один раз
            Set status to 1
Endif

If ( status == 1 ); ждать решения игрока
            Set button to GetButtonPressed
            If ( button == -1 ) ;решение ещё не принято: ничего не делать
                        return
            Elseif ( button == 0 ) ;продолжить
                        Set status to 0 ;сброс для следующего раза
            Elseif ( button == 1 )
                        Player -> drop, "power_sword" ;бросить предмет
                        Set status to 0
            Endif
Endif

End

Отображение переменных и текстовых значений в окне сообщений

Чтобы использовать переменные в окне сообщения, Вам нужно использовать синтаксис, описывающий числа. ВНИМАНИЕ – в стандартном файле помощи очень много ошибок на этот счёт!

MessageBox "You have %.0f дней", days_left

Символ % указывает на наличие переменной. Цифра после точки определяет количество выводимых знаков после запятой. "f" указывает, что переменная типа “float”. Файл помощи сообщает, что “D” можно использовать для переменных типа short и long, а “S” для текстовых переменных, но мне удалось удачно использовать только тип “f”. Однако %g и %G прекрасно работает и с short, и с long. Возможно также использование конструкции %.3g.

Тестовые переменные упоминаются в файле помощи, но, насколько мне известно, не были введены. Однако Вы можете использовать некоторые предопределённые текстовые значения в сообщениях. Для этого надо писать не %, а ^:

Текстовые значения:

^PCNameИмя игрового персонажа.
^PCClassЕго класс.
^PCRaceЕго раса.
^PCRankЕго ранг в гильдии, в которой состоит говорящий.
^NextPCRankСледующий ранг в этой гильдии.
^CellЛокация, в которой находится игрок.
^GlobalЗначение любой глобальной переменной.

Переменные типа float выводятся в следующем формате: 1.1. Хорошим примером является ^Gamehour. Также для вывода глобальных переменных Вы можете использовать синтаксис %.1f, это будет равнозначно. Если Вы используете ^Global в книге, которая в данный момент открыта, и пытаетесь поменять или просмотреть значение этой переменной, игра «вылетит»!

^NameИмя говорящего NPC.
^RaceЕго раса.
^ClassЕго класс.
^FactionЕго гильдия. Если он не принадлежит ни к какой из гильдии, здесь будет стоять пропуск.
^RankРанг NPC.

Заметьте: в окне сообщения последние значения работают не так, как в диалоге, потому что не задан NPC по умолчанию. Таким образом, и ^Name, и ^PCName будут отображать имя игрока.

Пример скрипта: Дурацкий пример, показывающий использование всего возможного синтаксиса:

Begin test1

short var_1
long var_2
float var_3
; GameHour – глобальная переменная типа float

set var_1 to 1
set var_2 to 2
set var_3 to 3

MessageBox "^PCName, у тебя %g голова, %G руки, и %.5f золотых монет. Можно сказать, что в ^cell время просто летит. Сейчас ^GameHour часов, точнее %.2f часов!", var_1, var_2, var_3, GameHour

End

Добавление темы диалога

AddTopic, "Тема"

После того, как Вы написали новую тему для разговора в TES CS, Вы можете обнаружить, что необходимый NPC не может говорить о ней, потому что Ваш персонаж ещё о ней не слышал. Чтобы исправить это, существует два способа. Можно упомянуть тему в ходе разговора или приветствия или ввести её с помощью скрипта. Второй вариант полезен, если Вы хотите иметь возможность спросить о чём-то, не дожидаясь специального приглашения. Например, если NPC состоит под водопадом, логично, что персонаж может захотеть спросить именно о нём. Чтобы осуществить это, надо прикрепить к этому NPC небольшой скрипт:

Begin AddSpecialDialogue

;добавить возможность спросить о водопаде
AddTopic, "почему Вы не мокнете?"

End AddSpecialDialogue

Естественно, что Вам сначала необходимо создать соответствующую тему, чтобы компилятор не «ругался».

Нет возможности удалить тему с помощью скрипта, однако можно в полях условий окна диалога, прописать условие, относящееся к локальной переменной некого скрипта. Допустим, если все фразы темы могут быть показаны лишь при значении переменной A равном 1, то, если его поменять на 2, то на эту тему NPC сказать будет нечего, и она пропадёт.

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

ForceGreeting

Функция “ForceGreeting” может быть использована для инициализации обычного диалога NPC. Так что, если Вы хотите начать с некого определенного приветствия, Вам придётся использовать для этого поля условий в окне редактора диалогов. Не имеет значения, где находится NPC, диалог будет начат в любом случае. Поэтому лучше использовать эту функцию вместе с “GetDistance” и “GetPCCell”

Пример скрипта: скрипт демонстрирует прекрасную проверку перед тем, как начинать диалог.

Begin balynScript

float timer
short doOnce

if ( GetJournalIndex "DA_Mephala" < 40 )
            Return
endif

if ( GetJournalIndex DA_Mephala >= 60 )
            Return
endif

Set timer to ( timer + GetSecondsPassed )

if ( timer < 5 )
            Return
endif

Set timer to 0

if ( doOnce == 0 )
            if ( GetDistance Player <= 1024 )
                        if ( player->GetDistance "hlaalu_loaddoor_ 02_balyn" <=256 )
                                    if ( GetLOS Player == 1 )
                                                ForceGreeting
                                                Journal DA_Mephala 55
                                                set doOnce to -1
                                    endif
                        endif
            endif
endif

End

Goodbye

“Goodbye” означает конец диалога. После вызова этой функции (она обычно используется в поле результате в окне редактора диалогов) игрок может выбрать лишь вариант, завершающий разговор.

Варианты ответов на заданные вопросы

Choice, “выбор 1”, выбор1_числ [, "выбор 2", выбор2_числ, …]
Choice "Да", 1, "Нет!", 2

Подобные условия используются в поле результата, чтобы заставить игрока принять некоторое решение или просто разбить длинную речь на несколько кусков, соединенных вариантом «Продолжить». После того, как игрок сделал свой выбор, движок проверит тему ещё раз в поисках нужной фразы. Чтобы определить эту фразу в окне условий надо выбрать function / choice / = / выбор_числ. Насколько я знаю, в скриптах подобное не используется.

Добавление и проверка журнальных записей

Journal, "ID_записи", индекс_числ
Journal, MG_BCShroomsCombat, 10

Функция позволяет добавить журнальную запись, которая должна быть заранее создана в окне редактора диалогов. Индекс определяет, какая фраза темы добавляется. Не используйте стандартных названий для записей, иначе они могут быть показаны в обычном диалоге, если это название вдруг появится в ходе диалога. BethSoft предлагает стандарт использования двух букв и подчёркивания перед смысловой частью (смотрите пример выше).

SetJournalIndex "ID_записи" индекс_числ

Я, так же как и Bethesda, не использовал эту функцию, поэтому не уверен, отличается ли она от функции Journal. В файле помощи написано: «Устанавливает индекс журнальной записи. Может как опускать, так и поднимать его». Возможно, это значит, что Вы можете устанавливать индекс, не добавляя в журнал игрока записи. Тогда это может быть использовано, чтобы сделать квест, который будет даваться вновь и вновь (как в TES2: Daggerfall) простым сбрасыванием индекса на 0.

ClearInfoActor

Эта функция используется в окне результата редактора диалогов. С её помощью можно удалить тему из раздела «Темы» журнала игрока. Полезно для избежания переполнения этой секции ненужной информацией.

GetJournalIndex, "JournalID" (возвращает short)

if ( GetJournalIndex, MG_BCShroomsCombat == 10 )

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

Пример скрипта: Скрипт демонстрирует работу некоторых функций:

Begin attack_slave

short nolore

If ( GetDeadCount "Vorar Helas" > 0 )
            return
endif

if ( GetJournalIndex "MV_SlaveMule" < 102 )
            If ( GetDistance, "Rabinna" < 512 )
                        Rabinna->AiWander 0 0 0 0 0 0 0
                        StartCombat, "Rabinna"
                        Journal "MV_SlaveMule", 102 ; добавляет запись в журнал
            endif
endif

End

Специальные диалоговые функции

Среди функций, используемых для задания условий в окне редактора диалоге есть несколько, которые не имеют схожих себе в обычных скриптовых функциях. Используя диалог (например, используя “ForceGreeting”, голосовой диалог или специально созданных квестовых NPC) и диалоговое результирующее поле, вы все же можете использовать эти функции для целей скриптования, например, изменяя глобальную переменную в результирующем поле диалога. Примером таких функций являются:

Пол игрока - PC Sex (диалог)

Это значение равно 0 если игровой персонаж – мужчина или 1, если женщина.

Говорил с игроком - Talked to PC (диалог)

1 – если говорящий когда-либо говорил с игроком и 0 – если нет. Вы можете использовать это, чтобы кто-то сказал нечто определённое, когда Вы заговорите с ним впервые – или для наших целей скриптования, чтобы помечать этого человека, как «известного» игроку.

Похоже, что эта функция будет сбрасываться на 0, если игрок потратил больше 72 игровых часов вне локации с необходимым NPC. Этот же временной лимит относится и к “ForceGreeting”: NPC может говорить первым только в течение 72 часов. В то же время, существует возможность обойти это ограничение, используя на NPC функцию PositionCell раз в день, пересылая NPC в служебную локацию, а затем вновь возвращая его в изначальное местоположение. Тогда движок будет запутан, и ему будет непонятно, относительно какой локации делать проверку. В итоге связь с 72 часами будет нарушена.

Требования для повышения – Rank Requirement (диалог)

Проверяет, «годится» ли игрок для повышения в гильдии говорящего.
Возвращает 0, если у Вас недостаточная репутация во фракции и низкие навыки.
Возвращает 1, если у Вас достаточно развиты навыки, но низкая репутация во фракции.
Возвращает 2, если у Вас достаточная репутация во фракции, но низкие навыки.
Возвращает 3, если Вы годитесь.

Множитель одежды игрока - PC Clothing Modifier (диалог)

Это суммарная стоимость всей одежды и брони, которая надета на игроке. Полученное значение изменяет расположение персонажей к игроку в игре.

Ударил друга - Friend Hit (диалог)

Используется в диалоге, когда Вы атакуете члена своей группы (например спутника).
Возвращаемые значения:
0 – удар по нему никогда не наносился
1 – игрок ударил 1 раз
2 – игрок ударил 2 раза
3 – игрок ударил 3 раза
4 – игрок ударил 4 раза и NPC/Существо не находится в схватке с ним