Реализация НПС в Instead
Эта заметка предназначена начинающим авторам на Instead.
Во всех квестах конечно есть НПС с которыми можно общаться, получать задания и т.д. Исторически разработчики не заморачивались разнообразием реплик НПС-болванчиков. Один и тот же диалог запускался при каждом обращении. Я лично считаю это вполне нормальным поведением и данью классическим квестам и рпг, но некоторые считают иначе и ниже я приведу пару способов разнообразить поведение НПС.
Обычно НПС выглядит как-то так:
Заключение: Конечно можно всё это сделать в самом диалоге при помощи cond и тегов, но иногда в результате получается настолько запутанная конструкция, что реально проще раскидать всё это на несколько более простых диалогов, а логику оставить в самом объекте-НПС, как в примерах выше. Впрочем образцы диалогов я возможно опишу в отдельной заметке.
А ещё есть интересная функция seen(), которая тоже часто пригождается в условиях.
Ответьте на опрос ниже и конечно лайк, шер и ретвит! Вопросы пишите в комментариях.
Во всех квестах конечно есть НПС с которыми можно общаться, получать задания и т.д. Исторически разработчики не заморачивались разнообразием реплик НПС-болванчиков. Один и тот же диалог запускался при каждом обращении. Я лично считаю это вполне нормальным поведением и данью классическим квестам и рпг, но некоторые считают иначе и ниже я приведу пару способов разнообразить поведение НПС.
Обычно НПС выглядит как-то так:
obj {
nam = 'Трактирщик';
dsc = 'За барной стойкой {трактирщик} протирает стаканы ветхим полотенцем.';
act = function()
walk 'Разговор с трактирщиком';
end;
};
Итак вариант №1: завести специальную квестовую переменную отвечающую за реплики трактирщика. Пишу:
global { -- определение глобальных переменных
q1 = 0;
};
Переписываю трактирщика:obj {
nam = 'Трактирщик';
dsc = 'За барной стойкой {трактирщик} протирает стаканы ветхим полотенцем.';
act = function()
if q1 == 0 then
walk 'Разговор с трактирщиком';
q1 = 1;
else
walk 'Другой разговор с трактирщиком';
end;
end;
};
Ладно, но может есть способ попроще? Вариант №2: использование функции visits(). visits() возвращает количество посещений комнаты или диалога. Код тогда будет такой:obj {
nam = 'Трактирщик';
dsc = 'За барной стойкой {трактирщик} протирает стаканы ветхим полотенцем.';
act = function()
if visits('Разговор с трактирщиком') == 0 then
walk 'Разговор с трактирщиком';
else
walk 'Другой разговор с трактирщиком';
end;
end;
};
Хорошо, а если трактирщик выдает какой-то предмет для выполнения квеста? Как например в Fallout 2 Мамаша в Дыре даёт обед для Смитти?obj {
nam = 'Трактирщик';
dsc = 'За барной стойкой {трактирщик} протирает стаканы ветхим полотенцем.';
act = function()
if not have 'Обед для Смитти' then
walk 'Разговор с трактирщиком';
else
p 'Ты ещё не отнёс обед для Смитти? Поторопись, остынет же!';
end;
end;
};
Кстати реакцию по else я заменил просто кратким напоминанием о задании. Но вот герой отнёс обед, вернулся и опять получает диалог про обед? Нелогично, хотя во многих ММОРПГ обычное дело — дейлики всякие. Можно использовать переменную или опять visits().obj {
nam = 'Трактирщик';
dsc = 'За барной стойкой {трактирщик} протирает стаканы ветхим полотенцем.';
act = function()
if not have 'Обед для Смитти' and visits('Разговор с трактирщиком') == 0 then
walk 'Разговор с трактирщиком';
elseif have 'Обед для Смитти' then
p 'Ты ещё не отнёс обед для Смитти? Поторопись, остынет же!';
else
walk 'Другой разговор с трактирщиком';
end;
end;
};
На самом деле тут получается небольшая нелогичность, если в диалоге например предусмотрена возможность отказаться от квеста с намерением вернуться к нему позже. Тогда остаётся только переменная:obj {
nam = 'Трактирщик';
dsc = 'За барной стойкой {трактирщик} протирает стаканы ветхим полотенцем.';
act = function()
if q1 == 0 then
walk 'Разговор с трактирщиком';
elseif have 'Обед для Смитти' then
p 'Ты ещё не отнёс обед для Смитти? Поторопись, остынет же!';
else
walk 'Другой разговор с трактирщиком';
end;
end;
};
И уже в диалоге если герой согласился сделать задание, присвойте q1 = 1;Заключение: Конечно можно всё это сделать в самом диалоге при помощи cond и тегов, но иногда в результате получается настолько запутанная конструкция, что реально проще раскидать всё это на несколько более простых диалогов, а логику оставить в самом объекте-НПС, как в примерах выше. Впрочем образцы диалогов я возможно опишу в отдельной заметке.
А ещё есть интересная функция seen(), которая тоже часто пригождается в условиях.
Ответьте на опрос ниже и конечно лайк, шер и ретвит! Вопросы пишите в комментариях.
можно сказать и так
И насчет глобальных квестовых переменных — тоже спорный вопрос. Я предпочитаю объявлять эти переменные внутри объекта, раз уж у нас есть ООП :) В приведенном выше примере можно было бы сделать переменную quest1 частью объекта 'Трактирщик'. За пределами объекта проверку на то, дал ли нам трактирщик квест, можно делать как-то так:
К тому же сразу понятно, за чей квест отвечает переменная quest1.
В общем, полезная статья. Пиши ещё! :)
Если q1 == 1, то другой НПС может начать разговор например «Трактирщик мне уже все рассказал, герой...»
Если б кто-то реализовал этот подход на Instead, мог бы выйти толк, я считаю.