-
Notifications
You must be signed in to change notification settings - Fork 42
Объекты
Объекты -- это единицы сцены, с которыми взаимодействует игрок.
obj {
nam = 'стол';
dsc = 'В комнате стоит {стол}.';
act = 'Гм... Просто стол...';
};
Имя объекта ''nam'' используется при попадании его в инвентарь. Хотя, в нашем случае, стол вряд ли туда попадет. Если у объекта определен 'disp', то при попадании в инвентарь для его отображения будет использоваться именно этот атрибут. Например:
obj {
nam = 'стол';
disp = 'угол стола';
dsc = 'В комнате стоит {стол}.';
tak = 'Я взялся за угол стола';
inv = 'Я держусь за угол стола.';
};
Все-таки стол попал к нам в инвентарь.
Вы можете скрывать отображение предмета в инвентаре, если 'disp' атрибут будет равен 'false'.
'dsc' -- описание объекта. Оно будет выведено в динамической части сцены, при наличии объекта в сцене. Фигурными скобками отображается фрагмент текста, который будет являться ссылкой в окне INSTEAD. Если объектов в сцене много, то все описания выводятся одно за другим, через пробел,
'act' -- это обработчик события, который вызывается при действии пользователя (действие на объект сцены, обычно -- клик мышкой по ссылке). Его основная задача -- вывод (возвращение) строки текста, которая станет частью событий сцены, и изменение состояния игрового мира.
Простейший вариант сделать объект, который можно брать -- определить обработчик 'tak'.
Например:
obj {
nam = 'яблоко';
dsc = 'На столе лежит {яблоко}.';
inv = function(s)
p 'Я съел яблоко.'
remove(s); -- удалить яблоко из инвентаря
end;
tak = 'Вы взяли яблоко.';
};
При этом, при действии игрока на объект "яблоко" (щелчок мыши на ссылку в сцене) -- яблоко будет убрано из сцены и добавлено в инвентарь. При действии игрока на инвентарь (двойной щелчок мыши на названии объекта) -- вызывается обработчик 'inv'.
В нашем примере, при действии игроком на яблоко в инвентаре -- яблоко будет съедено.
Конечно, мы могли бы реализовать код взятия объекта в ''act'', например, так:
obj {
nam = 'яблоко';
dsc = 'На столе лежит {яблоко}.';
inv = function(s)
p 'Я съел яблоко.'
remove(s); -- удалить яблоко из инвентаря
end;
act = function(s)
take(s)
p 'Вы взяли яблоко.';
end
};
Если у объекта в инвентаре не объявлен обработчик 'inv', будет вызван 'game.inv'.
Если обработчик 'tak' вернет false, то предмет не будет взят, например:
obj {
nam = 'яблоко';
dsc = 'На столе лежит {яблоко}.';
tak = function(s)
p "Оно же червивое!"
return false
end;
};
Игровой мир представлен объектом типа world. Имя такого объекта 'game'. Существует ссылка-переменная, которая также называется game.
Обычно вы не работаете с этим объектом напрямую, однако иногда вы можете вызывать его методы, или менять значения переменных этого объекта.
Например, переменная game.codepage содержит кодировку исходного кода игры, и по-умолчанию равна "UTF-8". Я не рекомендую использовать другие кодировки, но иногда, выбор кодировки может стать необходимостью.
Переменная game.player -- содержит текущего игрока.
Кроме того, как вы уже знаете, объект 'game' может содержать обработчики по умолчанию: 'act', 'inv', 'use', 'tak', которые будут вызваны, если в результате действий пользователя не будут найдены никакие другие обработчики (или все они вернули false). Например, вы можете написать в начале игры:
game.act = 'Не получается.';
game.inv = 'Гм.. Странная штука..';
game.use = 'Не сработает...';
game.tak = 'Не нужно мне это...';
Конечно, все они могут быть функциями.
Также, объект game может содержать обработчики: onact, ontak, onuse, oninv, onwalk -- которые могут прерывать действия, в случае возврата false.
Еще, у объекта game можно задать обработчики: afteract, afterinv, afteruse, afterwalk -- которые вызываются в случае успешного выполнения соответствующего действия.
Объекты, которые могут быть перенесены из одной сцены в другую (или попадать в инвентарь), обычно имеют имя и/или переменную-ссылку. Так как таким образом вы всегда можете найти объект где угодно и работать с ним.
Но немалую часть игрового мира составляют объекты, которые занимают конкретную локацию и служат в качестве декораций.
Таких объектов может быть очень много, и более того, обычно это однотипные объекты вроде деревьев и тому подобных объектов.
Для создания декораций можно использовать различные подходы.
Вы можете создать один объект, например, 'дерево' и помещать их в разные комнаты.
obj {
nam = 'дерево';
dsc = [[Тут стоит {дерево}.]];
act = [[Все деревья выглядят похожими.]];
}
room {
nam = 'Лес';
obj = { 'дерево' };
}
room {
nam = 'Улица';
obj = { 'дерево' };
}
Если вам не нравится придумывать уникальные имена для однотипных декоративных объектов, вы можете использовать для таких объектов теги. Теги задаются атрибутом tag и всегда начинаются с символа '#':
obj {
tag = '#цветы';
dsc = [[Тут есть {цветы}.]]
}
В данном примере, имя у объекта будет сформировано автоматически, но обращаться к объекту вы сможете по тегу. При этом объект будет искаться в текущей комнате. Например:
dprint(_'#цветы') -- ищем в текущей комнате первый объект с тегом '#цветы'
Теги, это в каком то смысле, синоним локальных имен, поэтому существует альтернативная запись создания предмета с тегом:
obj {
nam = '#цветы';
dsc = [[Тут есть {цветы}.]]
}
Если имя у объекта начинается с символа '#', то такой объект получает тег и автоматически сгенерированное числовое имя.
В INSTEAD определены некоторые функции, которые возвращают различные объекты. При описании функции используются следующие соглашения о параметрах.
- в символах [ ] описаны необязательные параметры;
- 'что' или 'где' - означает объект (в том числе комнату), заданный тегом, именем или переменной-ссылкой;
Итак, основные функции:
- '_(что)' - получить объект;
- 'me()' возвращает текущего объекта-игрока;
- 'here()' возвращает текущую сцену;
- 'where(что)' возвращает комнату или объект в котором находится заданный объект, если объект находится в нескольких местах, то можно передать второй параметр -- таблицу Lua, в которую будут добавлены эти объекты;
- 'inroom(что)' аналогично where(), но вернет комнату, в которой расположен объект (это важно для объектов в объектах);
- 'from([где])' возвращает прошлую комнату, из которой игрок перешел в заданную комнату. Необязательный параметр -- получить прошлую комнату не для текущей комнаты, а для заданной;
- 'seen(что, [где])' возвращает объект или переход, если он присутствует и видим, есть второй необязательный параметр -- выбрать сцену или объект/список в котором искать;
- 'lookup(что, [где])' возвращает объект или переход, если он существует в сцене или объекте/списке;
- 'inspect(что)' возвращает объект, если он виден/доступен на сцене. Поиск производится по переходам и объектам, в том числе, в объектах игрока;
- 'have(что)' возвращает объект, если он есть в инвентаре и не отключен;
- 'live(что)' возвращает объект, если он присутствует среди живых объектов (описано далее);
Эти функции в основном используются в условиях, либо для поиска объекта с последующей модификацией. Например, вы можете использовать 'seen' для написания условия:
onexit = function(s)
if seen 'монстр' then -- если у функции 1 параметр,
--- скобки писать не обязательно
p 'Монстр загораживает проход!'
return false
end
end
А также, для нахождения объекта в сцене:
use = function(s, w)
if w^'окно' then
local ww = lookup 'собака'
if not ww then
p [[А где моя собака?]]
return
end
place(ww, 'улица')
p 'Я разбил окно! Моя собака выпрыгнула на улицу.'
return
end
return false
end
Пример с функцией 'have':
...
act = function(s)
if have 'нож' then
p 'Но у меня же есть нож!';
return
end
take 'нож'
end
...
Может возникнуть вопрос, в чем разница между функциями lookup и _ ()? Дело в том, что lookup() ищет объект, и в случае, если объект не найден -- просто ничего не вернет. А запись _ () предполагает, что вы точно знаете, что за предмет вы получаете. Другими словами, _ () это безусловное получение объекта по имени. Эта функция в общем случае не занимается поиском. Только если в качестве параметра задан тег, будет осуществлен поиск среди доступных объектов. Если вы используете _ () на несуществующий объект или недоступный тег -- вы получите ошибку!
Объекты тоже могут содержать в себе атрибут 'obj' (или конструкцию 'with'). При этом, при выводе объектов, INSTEAD будет разворачивать списки последовательно. Такая техника может использоваться для создания объектов-контейнеров или просто для связывания нескольких описаний вместе. Например, поместим на стол яблоко.
obj {
nam = 'яблоко';
dsc = [[На столе лежит {яблоко}.]];
act = 'Взять что-ли?';
};
obj {
nam = 'стол';
dsc = [[В комнате стоит {стол}.]];
act = 'Гм... Просто стол...';
obj = { 'яблоко' };
};
room {
nam = 'Дом';
obj = { 'стол' };
}
При этом, в описании сцены мы увидим описание объектов 'стол' и 'яблоко', так как 'яблоко' -- связанный со столом объект и движок при выводе объекта 'стол' вслед за его 'dsc' выведет последовательно ''dsc'' всех вложенных в него объектов.
Также, следует отметить, что оперируя объектом 'стол' (например, перемещая его из комнаты в комнату) мы автоматически будем перемещать и вложенный в него объект 'яблоко'.
Конечно, данный пример мог бы быть написан и по другому, например, так:
room {
nam = 'Дом';
}:with {
obj {
nam = 'стол';
dsc = [[В комнате стоит {стол}.]];
act = 'Гм... Просто стол...';
}: with {
obj {
nam = 'яблоко';
dsc = [[На столе лежит {яблоко}.]];
act = 'Взять что-ли?';
};
}
}
Выбирайте тот способ, который для вас понятней.