Переходы между сценами
Традиционные переходы в INSTEAD выглядят как ссылки над описанием сцены. Для определения таких переходов между сценами используется атрибут сцены -- список 'way'. В списке определяются комнаты, в виде имён комнат или переменных-ссылок, аналогично списку 'obj'. Например:
room {
nam = 'room2';
disp = 'Зал';
dsc = 'Вы в огромном зале.';
way = { 'main' };
};
room {
nam = 'main';
disp = 'Главная комната';
dsc = 'Вы в большой комнате.';
way = { 'room2' };
};При этом, вы сможете переходить между сценами 'main' и 'room2'. Как вы помните, 'disp' может быть функцией, и вы можете генерировать имена переходов на лету. Или использовать title, для разделения имени сцены как заголовка и как имени перехода:
room {
nam = 'room2';
disp = 'В зал';
title = 'В зале';
dsc = 'Вы в огромном зале.';
way = { 'main' };
};
room {
nam = 'main';
title = 'В главной комнате';
disp = 'В главную комнату';
dsc = 'Вы в большой комнате.';
way = { 'room2' };
};При переходе между сценами движок вызывает обработчик 'onexit' из текущей сцены и 'onenter' в той сцене, куда идёт игрок. Например:
room {
onenter = 'Вы заходите в зал.';
nam = 'Зал';
dsc = 'Вы в огромном зале.';
way = { 'main' };
onexit = 'Вы выходите из зала.';
};Конечно, как и все обработчики, 'onexit' и 'onenter' могут быть функциями. Тогда первый параметр это (как всегда) сам объект - комната, а второй -- это комната куда игрок собирается идти (для 'onexit') или из которой собирается уйти (для 'onenter'). Например:
room {
onenter = function(s, f)
if f^'main' then
p 'Вы идёте из комнаты main.';
end
end;
nam = 'Зал';
dsc = 'Вы в огромном зале.';
way = { 'main' };
onexit = function(s, t)
if t^'main' then
p 'Я не хочу назад!'
return false
end
end;
};Запись вида:
if f^'main' then
Это сопоставление объекта с именем. Это альтернатива записям:
if f == _'main' then
Или:
if f.nam == 'main' then
Или:
if std.nameof(f) == 'main' then
Как видим на примере onexit, эти обработчики, кроме строки, могут возвращать булевое значение статуса. Аналогично обработчику onact, мы может отменить переход, вернув false из onexit/onenter.
Вы можете сделать возврат статуса и другим способом, если это кажется вам удобным:
return "Я не хочу назад", falseЕсли же вы используете функции 'p'/'pn'/'pr', то просто возвращайте статус операции с помощью завершающего 'return', как показано в примере выше.
Важно!
Следует отметить, что при вызове обработчика 'onenter' указатель на текущую сцену (here()) ещё не изменён!!! В INSTEAD есть обработчики 'exit' (уход из комнаты) и 'enter' (заход в комнату), которые вызываются уже после того, как переход произошёл. Эти обработчики рекомендованы к использованию всегда, когда нет необходимости запрещать переход.
Иногда есть необходимость, чтобы название перехода отличалось от названия комнаты, в которую ведёт этот переход. Существует несколько способов сделать это. Например, с помощью 'path'.
room {
nam = 'room2';
title = 'Зал';
dsc = 'Вы в огромном зале.';
way = { path { 'В главную комнату', 'main'} };
};
room {
nam = 'main';
title = 'Главная комната';
dsc = 'Вы в большой комнате.';
way = { path {'В зал', 'room2'} };
};На самом деле, 'path' создаёт комнату с атрибутом 'disp', который равен первому параметру, и специальной функцией 'onenter', которая перенаправляет игрока в комнату, заданную вторым параметром 'path'.
Если вы укажете три параметра:
way = { path {'#взал', 'В зал', 'room2'} };
То первый параметр станет именем (или тегом, как в приведённом примере) такой комнаты.
Альтернативная форма записи с явным заданием атрибута nam:
way = { path { nam = '#взал', 'В зал', 'room2'} };
Вы можете менять название перехода после того, как переход происходил хотя бы раз, и вы узнали, что же это за комната:
way = { path {'#вдверь', 'В дверь', after = 'В гостиную', 'room2'} };
Все параметры, кроме имени перехода, могут быть функциями.
Таким образом, 'path' позволяет именовать переходы удобным способом.
Иногда вам может потребоваться включать и выключать переходы. На самом деле это требуется не часто. Идея переходов состоит в том, что переход виден даже тогда, когда он невозможен. Например, представим себе сцену перед домом у входной двери. Войти в дом нельзя, так как дверь закрыта.
Нет особого смысла прятать переход "дверь". Просто в функции 'onenter' сцены внутри дома мы проверяем, а есть ли у героя ключ? И если ключа нет, говорим о том, что дверь закрыта и запрещаем переход. Это повышает интерактивность и упрощает код. Если же вы хотите сделать дверь объектом сцены, поместите её в комнату, но в 'act' обработчике сделайте осмотр двери, или дайте возможность игроку открыть её ключом (как это сделать - мы рассмотрим позже), но сам переход дайте сделать игроку привычным способом через строку переходов.
Тем не менее, бывают ситуации, когда переход не очевиден и он появляется в результате каких-то событий. Например, мы осмотрели часы и увидели там секретный лаз.
obj {
nam = 'часы';
dsc = [[Тут есть старинные {часы}.]];
act = function(s)
enable '#часы'
p [[Вы видите, что в часах есть потайной ход!]];
end;
}
room {
nam = 'Зал';
dsc = 'Вы в огромном зале.';
obj = { 'часы' };
way = { path { '#часы', 'В часы', 'inclock' }:disable() };
};В данном примере, мы создали отключённый переход, за счёт вызова метода 'disable' у комнаты, созданной с помощью 'path'. Метод 'disable' есть у всех объектов (не только комнат), он переводит объект в отключённое состояние, которое означает, что объект перестаёт быть доступным игроку. Замечательным свойством отключённого объекта является то, что его можно включить с помощью 'enable()';
Далее, когда игрок нажимает на ссылку, описывающую часы, вызывается обработчик 'act', который с помощью функции 'enable()' делает переход видимым.
Альтернативный вариант заключается не в выключении, а 'закрытии' объекта:
obj {
nam = 'часы';
dsc = [[Тут есть старинные {часы}.]];
act = function(s)
open '#часы'
p [[Вы видите, что в часах есть потайной ход!]];
end;
}
room {
nam = 'Зал';
dsc = 'Вы в огромном зале.';
obj = { 'часы' };
way = { path { '#часы', 'В часы', 'inclock' }:close() };
};В чём разница? Выключение объекта означает то, что объект перестаёт быть доступным для игрока. Если в объекте вложены другие объекты, то и эти объекты становятся недоступными.
Закрытие объекта делает недоступным содержимое данного объекта, но не сам объект.
Однако, в случае комнат, и закрытие комнаты и отключённые комнаты приводят к одному результату -- переход на них становится недоступным.
Ещё один вариант:
room {
nam = 'inclock';
dsc = [[Я в часах.]];
}:close()
obj {
nam = 'часы';
dsc = [[Тут есть старинные {часы}.]];
act = function(s)
open 'inclock'
p [[Вы видите, что в часах есть потайной ход!]];
end;
}
room {
nam = 'Зал';
dsc = 'Вы в огромном зале.';
obj = { 'часы' };
way = { path { 'В часы', 'inclock' } };
};Здесь мы закрываем и открываем не переход, а комнату, в которую ведёт переход. path не показывает себя, если комната, в которую он ведёт, отключена или закрыта.