1637 lines
86 KiB
Plaintext
1637 lines
86 KiB
Plaintext
====== Базовая документация ======
|
||
===== Общие сведения =====
|
||
Код игр для STEAD пишется на lua (5.1), поэтому, знание этого языка полезно, хотя и не необходимо. Код движка на lua занимает около ~3000 строк и лучшей документацией является изучение его кода.
|
||
|
||
Главное окно игры содержит информацию о статической и динамической части сцены, активные события и картинку сцены с возможными переходами в другие сцены (в графическом интерпретаторе).
|
||
|
||
Динамическая часть сцены составлена из описаний объектов сцены, она отображается всегда.
|
||
|
||
Статическая часть сцены отображается только один раз, при показе сцены, или при повторении команды look (в графическом интерпретаторе -- клик на названии сцены).
|
||
|
||
Игроку доступны объекты доступные на любой сцене -- инвентарь. Игрок может взаимодействовать с объектами инвентаря и действовать объектами инвентаря на другие объекты сцены или инвентаря.
|
||
|
||
Следует отметить, что понятие инвентаря является условным. Например, в "инвентаре" могут находиться такие объекты как "открыть", "осмотреть", "использовать" и т.д.
|
||
|
||
Действиями игрока могут быть:
|
||
|
||
* осмотр сцены;
|
||
* действие на объект сцены;
|
||
* действие на объект инвентаря;
|
||
* действие объектом инвентаря на объект сцены;
|
||
* действие объектом инвентаря на объект инвентаря;
|
||
* действие объектом сцены на объект сцены (режим scene_use);
|
||
* действие объектом сцены на инвентарь (режим scene_use);
|
||
* переход в другую сцену;
|
||
|
||
Игра представляет из себя каталог, в котором должен находиться скрипт main.lua. Другие ресурсы игры (скрипты на lua, графика и музыка) должны находиться в рамках этого каталога. Все ссылки на ресурсы делаются относительно текущего каталога -- каталога игры.
|
||
|
||
В начале файла main.lua может быть определен заголовок, состоящий из тегов. Теги должны начинаться с символов '--': комментарий с точки зрения lua. На данный момент существует один тег: $Name:, который должен содержать название игры в кодировке UTF8. Пример использования тега:
|
||
<code lua>
|
||
-- $Name: Самая интересная игра!$
|
||
</code>
|
||
|
||
Сразу после заголовков вам необходимо указать версию STEAD API, которая требуется игре. На данный момент последняя версия 1.4.0.
|
||
<code lua>
|
||
instead_version "1.4.0"
|
||
</code>
|
||
|
||
Если version отсутствует, то STEAD API будет работать в режиме совместимости (устаревшее API).
|
||
|
||
Инициализацию игры следует описывать в функции init:
|
||
<code lua>
|
||
function init()
|
||
me()._know_truth = false
|
||
take(knife);
|
||
take(paper);
|
||
end
|
||
</code>
|
||
|
||
Графический интерпретатор ищет доступные игры в каталоге games. Unix версия интерпретатора кроме этого каталога просматривает также игры в каталоге ~/.instead/games.
|
||
Windows версия: Documents and Settings/USER/Local Settings/Application Data/instead/games.
|
||
В Windows и standalone Unix версии игры ищутся в каталоге ./appdata/games, если он существует.
|
||
|
||
===== 1. Сцена =====
|
||
|
||
Сцена -- это единица игры, в рамках которой игрок может изучать все объекты сцены и взаимодействовать с ними. В игре должна быть хотя бы одна сцена с именем main.
|
||
<code lua>
|
||
main = room {
|
||
nam = 'главная комната',
|
||
dsc = 'Вы в большой комнате.',
|
||
};
|
||
</code>
|
||
Запись означает создание объекта main типа room. У каждого объекта игры есть атрибуты и обработчики. Например, атрибут nam (имя) является необходимым для любого объекта.
|
||
|
||
Атрибут nam для сцены это то, что будет заголовком сцены при ее отображении. Имя сцены также используется для ее идентификации при переходах.
|
||
|
||
Атрибут dsc это описание статической части сцены, которое выводится один раз при входе в сцену или явном выполнении команды look.
|
||
|
||
Внимание!!! Вы можете использовать символ ; вместо , для разделения атрибутов. Например:
|
||
<code lua>
|
||
main = room {
|
||
nam = 'главная комната';
|
||
dsc = 'Вы в большой комнате.';
|
||
};
|
||
</code>
|
||
Внимание!!! Если для вашего творческого замысла необходимо, чтобы описание статической части сцены выводилось каждый раз, вы можете определить для своей игры параметр forcedsc (в начале игры).
|
||
<code lua>
|
||
game.forcedsc = true;
|
||
</code>
|
||
Или, аналогично, задать атрибут forcedsc для конкретных сцен.
|
||
|
||
Для длинных описаний удобно использовать запись вида:
|
||
|
||
<code lua>dsc = [[ Очень длинное описание... ]],</code>
|
||
|
||
При этом переводы строк игнорируются. Если вы хотите, чтобы в выводе описания сцены присутствовали абзацы -- используйте символ ^.
|
||
|
||
<code lua>
|
||
dsc = [[ Первый абзац. ^^
|
||
Второй Абзац.^^
|
||
|
||
Третий абзац.^
|
||
На новой строке.]],
|
||
</code>
|
||
|
||
===== 2. Объекты =====
|
||
|
||
Объекты -- это единицы сцены, с которыми взаимодействует игрок.
|
||
<code lua>
|
||
tabl = obj {
|
||
nam = 'стол',
|
||
dsc = 'В комнате стоит {стол}.',
|
||
act = 'Гм... Просто стол...',
|
||
};
|
||
</code>
|
||
Имя объекта nam используется при попадании его в инвентарь а также в текстовом интерпретаторе для адресации объекта.
|
||
|
||
dsc -- описатель объекта. Он будет выведен в динамической части сцены. Фигурными скобками отображается фрагмент текста, который будет являться ссылкой в графическом интерпретаторе.
|
||
|
||
act -- это обработчик, который вызывается при действии пользователя (действие на объект сцены). Его задача -- возвращение строки текста, которая станет частью событий сцены, или логического значения (см. раздел 5).
|
||
|
||
ВНИМАНИЕ: в пространстве имен lua уже существуют некоторые объекты (таблицы), например: table, io, string... Будьте внимательны, при создании объекта. Например, в приведенном примере используется tabl, а не table. Правда, в новых версиях INSTEAD эта проблема во многом решена.
|
||
|
||
===== 3. Добавляем объекты в сцену =====
|
||
|
||
Ссылкой на объект называется текстовая строка, содержащая имя объекта при его создании. Например: 'tabl' -- ссылка на объект tabl.
|
||
|
||
Для того, чтобы поместить в сцену объекты, нужно определить массив obj, состоящий из ссылок на объекты:
|
||
<code lua>
|
||
main = room {
|
||
nam = 'главная комната',
|
||
dsc = 'Вы в большой комнате.',
|
||
obj = { 'tabl' },
|
||
};
|
||
</code>
|
||
Теперь, при отображении сцены мы увидим объект стол в динамической части.
|
||
|
||
Внимание!!! Вы можете использовать ссылки на объекты без кавычек в том случае, если объект был определен ранее, но использование кавычек всегда безопасней.
|
||
|
||
===== 4. Объекты связанные с объектами =====
|
||
|
||
Объекты тоже могут содержать атрибут obj. При этом, список будет последовательно разворачиваться. Например, поместим на стол яблоко.
|
||
<code lua>
|
||
apple = obj {
|
||
nam = 'яблоко',
|
||
dsc = 'На столе лежит {яблоко}.',
|
||
act = 'Взять что-ли?',
|
||
};
|
||
|
||
tabl = obj {
|
||
nam = 'стол',
|
||
dsc = 'В комнате стоит {стол}.',
|
||
act = 'Гм... Просто стол...',
|
||
obj = { 'apple' },
|
||
};
|
||
</code>
|
||
При этом, в описании сцены мы увидим описание объектов стол и яблоко, так как apple -- связанный с tabl объект.
|
||
|
||
|
||
===== 5. Атрибуты и обработчики как функции =====
|
||
|
||
Большинство атрибутов и обработчиков могут быть также функциями. Так, например:
|
||
<code lua>
|
||
nam = function()
|
||
return 'яблоко';
|
||
end,
|
||
</code>
|
||
Это синоним записи: nam = 'яблоко';
|
||
|
||
Обработчик должен вернуть строку. Если вам удобнее, для возвращения текста вы можете использовать функции:
|
||
|
||
* p ("текст") -- вывод текста и пробела;
|
||
* pn ("текст") -- вывод текста с переводом строки;
|
||
* pr ("текст") -- вывод текста как есть;
|
||
|
||
Если p/pn/pr вызывается с одним текстовым параметром, то скобки можно опускать. Используйте .. или , для склейки строк. Например:
|
||
|
||
<code lua>
|
||
pn "Нет скобкам!";
|
||
pn ("Строка 1".." Строка 2");
|
||
pn ("Строка 1", "Строка 2");
|
||
</code>
|
||
|
||
Функции сильно расширяют возможности STEAD, например:
|
||
<code lua>
|
||
apple = obj {
|
||
nam = 'яблоко',
|
||
dsc = function(s)
|
||
if not s._seen then
|
||
p 'На столе {что-то} лежит.';
|
||
else
|
||
p 'На столе лежит {яблоко}.';
|
||
end
|
||
end,
|
||
act = function(s)
|
||
if s._seen then
|
||
p 'Это яблоко!';
|
||
else
|
||
s._seen = true;
|
||
p 'Гм... Это же яблоко!';
|
||
end
|
||
end,
|
||
};
|
||
</code>
|
||
Если атрибут или обработчик оформлен как функция, то обычно первый аргумент функции (s) сам объект.
|
||
|
||
В данном примере, при показе сцены будет в динамической части сцены будет текст: 'На столе что-то лежит'. При взаимодействии с 'что-то', переменная `_seen` объекта apple будет установлена в true и мы увидим, что это было яблоко.
|
||
|
||
Запись `s._seen` означает, что переменная `_seen` размещена в объекте s (то-есть apple). Подчеркивание означает, что эта переменная попадет в файл сохранения игры.
|
||
|
||
Начиная с версии 1.2.0 вы можете определять переменные следующим образом:
|
||
|
||
<code lua>
|
||
global {
|
||
global_var = 1;
|
||
}
|
||
main = room {
|
||
var {
|
||
i = "a";
|
||
z = "b";
|
||
};
|
||
nam = 'Моя первая комната';
|
||
var {
|
||
new_var = 3;
|
||
};
|
||
dsc = function(s)
|
||
p ("i == ", s.i);
|
||
p ("new_var == ", s.new_var);
|
||
p ("global_var == ", global_var);
|
||
end;
|
||
</code>
|
||
|
||
Внимание!!! Переменные записываются в файл сохранения, если они размещены в одном из перечисленных типов объектов: комната, объект, игра, игрок, глобальное пространство, при этом начинаются с символа _ или определены с помощью var и global.
|
||
|
||
Начиная с версии 1.2.0 вы можете определять функции следующим образом:
|
||
<code lua>
|
||
dsc = code [[
|
||
if not self._seen then
|
||
p 'На столе {что-то} лежит.';
|
||
else
|
||
p 'На столе лежит {яблоко}.';
|
||
end
|
||
]],
|
||
</code>
|
||
|
||
При этом в self записан текущий объект, arg1 .. arg9 и массив args[] -- параметры.
|
||
|
||
В файл сохранения могут быть записаны:
|
||
* строки;
|
||
* булевы величины;
|
||
* числовые величины;
|
||
* ссылки на объекты;
|
||
* конструкции code;
|
||
|
||
Иногда может понадобиться обработчик, который совершал бы некоторое действие, но не выводил никакого описания. Например:
|
||
<code lua>
|
||
button = obj {
|
||
nam = "кнопка",
|
||
dsc = "На стене комнаты видна большая красная {кнопка}.",
|
||
act = function (s)
|
||
here()._dynamic_dsc = [[После того как я нажал на кнопку, комната преобразилась.
|
||
Книжный шкаф куда-то исчез вместе со столом и комодом, а на его месте
|
||
появился странного вида аппарат.]];
|
||
return true;
|
||
end,
|
||
}
|
||
r12 = room {
|
||
nam = 'комната',
|
||
_dynamic_dsc = 'Я нахожусь в комнате.',
|
||
dsc = function (s) return s._dynamic_dsc end,
|
||
obj = {'button'}
|
||
}
|
||
</code>
|
||
В данном случае обработчик `act` нужен для того, чтобы поменять описание комнаты, и не нужно, чтобы чтобы он выводил результат действия. Для отключения результата можно вернуть из обработчика значение true -- это будет означать, что действие успешно выполнено, но не требует дополнительного описания.
|
||
|
||
Если необходимо показать, что действие невыполнимо, ничего не возвращайте. При этом будет отображено описание по умолчанию, заданное с помощью обработчика `game.act`. Обычно описание по умолчанию содержит описание невыполнимых действий.
|
||
|
||
Обратите внимание, что для создания динамического описания сцены в рассмотренном выше примере использовалось новая переменная _dynamic_dsc. Это сделано для того, чтобы изменённое описание попало в файл сохранения игры. Поскольку имя ''dsc'' не начинается с подчёркивания или заглавной буквы, по умолчанию оно не попадёт в файл сохранения.
|
||
|
||
Данный пример мог бы выглядеть более разумно:
|
||
<code lua>
|
||
button = obj {
|
||
nam = "кнопка";
|
||
dsc = "На стене комнаты видна большая красная {кнопка}.";
|
||
act = function (s)
|
||
here().dsc = [[Теперь комната выглядит совсем по-другому!!!]];
|
||
pn [[После того как я нажал на кнопку, комната преобразилась.
|
||
Книжный шкаф куда-то исчез вместе со столом и комодом, а на его месте
|
||
появился странного вида аппарат.]];
|
||
end,
|
||
}
|
||
|
||
r12 = room {
|
||
nam = 'комната';
|
||
forcedsc = true;
|
||
var {
|
||
dsc = 'Я нахожусь в комнате.';
|
||
};
|
||
obj = {'button'}
|
||
}
|
||
</code>
|
||
|
||
===== 6. Инвентарь =====
|
||
|
||
Простейший вариант сделать объект, который можно брать -- определить обработчик tak.
|
||
|
||
Например:
|
||
<code lua>
|
||
apple = obj {
|
||
nam = 'яблоко',
|
||
dsc = 'На столе лежит {яблоко}.',
|
||
inv = function(s)
|
||
inv():del(s);
|
||
return 'Я съел яблоко.';
|
||
end,
|
||
tak = 'Вы взяли яблоко.',
|
||
};
|
||
</code>
|
||
При этом, при действии игрока на объект яблоко -- яблоко будет убрано из сцены и добавлено в инвентарь. При действии игрока на инвентарь -- вызывается обработчик inv.
|
||
|
||
В нашем примере -- при действии игроком на яблоко в инвентаре - яблоко будет съедено.
|
||
|
||
===== 7. Переходы между сценами =====
|
||
|
||
Для перехода между сценами используется атрибут сцены -- список way.
|
||
<code lua>
|
||
room2 = room {
|
||
nam = 'зал',
|
||
dsc = 'Вы в огромном зале.',
|
||
way = { 'main' },
|
||
};
|
||
|
||
|
||
main = room {
|
||
nam = 'главная комната',
|
||
dsc = 'Вы в большой комнате.',
|
||
obj = { 'tabl' },
|
||
way = { 'room2' },
|
||
};
|
||
</code>
|
||
При этом, вы сможете переходить между сценами main и room2. Как вы помните, nam может быть функцией, и вы можете генерировать имена сцен на лету, например, если вы хотите, чтобы игрок не знал название сцены, пока не попал на нее.
|
||
|
||
При переходе между сценами движок вызывает обработчик exit из текущей сцены и enter в той сцены, куда идет игрок. Например:
|
||
<code lua>
|
||
room2 = room {
|
||
enter = 'Вы заходите в зал.',
|
||
nam = 'зал',
|
||
dsc = 'Вы в огромном зале.',
|
||
way = { 'main' },
|
||
exit = 'Вы выходите из зала.',
|
||
};
|
||
</code>
|
||
|
||
exit и enter могут быть функциями. Тогда первый параметр это (как всегда) сам объект, а второй это комната куда игрок хочет идти (для exit) или из которой уходит (для enter). Например:
|
||
<code lua>
|
||
room2 = room {
|
||
enter = function(s, f)
|
||
if f == main then
|
||
return 'Вы пришли из комнаты.';
|
||
end
|
||
end,
|
||
nam = 'зал',
|
||
dsc = 'Вы в огромном зале.',
|
||
way = { 'main' },
|
||
exit = function(s, t)
|
||
if t == main then
|
||
return 'Я не хочу назад!', false
|
||
end
|
||
end,
|
||
};
|
||
</code>
|
||
Как видим, обработчики могут возвращать два значения: строку и статус. В нашем примере функция exit вернет false, если игрок попытается уйти из зала в main комнату. false означает, что переход не будет выполнен. Такая же логика работает и для enter. Кроме того, она работает и для обработчика tak.
|
||
|
||
Если вы используете функции p/pn/pr, то просто возвращайте статус операции с помощью return:
|
||
<code lua>
|
||
room2 = room {
|
||
enter = function(s, f)
|
||
if f == main then
|
||
p 'Вы пришли из комнаты.';
|
||
end
|
||
end,
|
||
nam = 'зал',
|
||
dsc = 'Вы в огромном зале.',
|
||
way = { 'main' },
|
||
exit = function(s, t)
|
||
if t == main then
|
||
p 'Я не хочу назад!'
|
||
return false
|
||
end
|
||
end,
|
||
};
|
||
</code>
|
||
|
||
Следует отметить, что при вызове обработчика enter текущая сцена может быть еще не изменена!!! Начиная с версии 1.2.0 добавлены обработчики left и entered, которые вызываются после того, как переход произошел. Эти обработчики рекомендованы к использованию всегда, когда нет необходимости запрещать переход.
|
||
|
||
===== 8. Действие объектов друг на друга =====
|
||
|
||
Игрок может действовать объектом инвентаря на другие объекты. При этом вызывается обработчик use у объекта которым действуют и used -- на которого действуют.
|
||
|
||
Например:
|
||
<code lua>
|
||
knife = obj {
|
||
nam = 'нож',
|
||
dsc = 'На столе лежит {нож}',
|
||
inv = 'Острый!',
|
||
tak = 'Я взял нож!',
|
||
use = 'Вы пытаетесь использовать нож.',
|
||
};
|
||
|
||
tabl = obj {
|
||
nam = 'стол',
|
||
dsc = 'В комнате стоит {стол}.',
|
||
act = 'Гм... Просто стол...',
|
||
obj = { 'apple', 'knife' },
|
||
used = 'Вы пытаетесь сделать что-то со столом...',
|
||
};
|
||
</code>
|
||
Если игрок возьмет нож и использует его на стол -- то увидит текст обработчиков use и used. use и used могут быть функциями. Тогда первый параметр это сам объект,
|
||
а второй -- объект на который направлено действие в случае use и объект, которым действие осуществляется в случае used.
|
||
|
||
use может вернуть статус false, в этом случае обработчик used не вызовется (если он вообще был). Статус обработчика used -- игнорируется.
|
||
|
||
Пример:
|
||
<code lua>
|
||
knife = obj {
|
||
nam = 'нож',
|
||
dsc = 'На столе лежит {нож}',
|
||
inv = 'Острый!',
|
||
tak = 'Я взял нож!',
|
||
use = function(s, w)
|
||
if w ~= tabl then
|
||
p 'Не хочу это резать.'
|
||
return false
|
||
else
|
||
p 'Вы вырезаете на столе свои инициалы.';
|
||
end
|
||
end
|
||
};
|
||
</code>
|
||
Нож можно использовать только на стол.
|
||
|
||
===== 9. Объект игрок =====
|
||
|
||
Игрок в STEAD представлен объектом pl. Тип объекта -- player. В движке объект создается следующим образом:
|
||
<code lua>
|
||
pl = player {
|
||
nam = "Incognito",
|
||
where = 'main',
|
||
obj = { }
|
||
};
|
||
</code>
|
||
Атрибут obj представляет собой инвентарь игрока.
|
||
|
||
===== 10. Объект game =====
|
||
|
||
Игра также представлена объектом game с типом game. В движке он определяется следующим образом:
|
||
<code lua>
|
||
game = game {
|
||
nam = "INSTEAD -- Simple Text Adventure interpreter v"..version.." '2009 by Peter Kosyh",
|
||
dsc = [[
|
||
Commands:^
|
||
look(or just enter), act <on what> (or just what), use <what> [on what], go <where>,^
|
||
back, inv, way, obj, quit, save <fname>, load <fname>.]],
|
||
pl ='pl',
|
||
showlast = true,
|
||
};
|
||
</code>
|
||
Как видим, объект хранит в себе указатель на текущего игрока ('pl') и некоторые параметры. Например, вы можете указать в начале своей игры кодировку текста следующим образом:
|
||
<code> game.codepage="UTF-8"; </code>
|
||
|
||
Поддержка произвольных кодировок изначально присутствует в UNIX версии интерпретатора, в windows версии -- начиная с 0.7.7.
|
||
|
||
Кроме того, объект game может содержать обработчики по умолчанию act, inv, use, которые будут вызваны, если в результате действий пользователя не будут найдены никакие другие обработчики. Например, вы можете написать в начале игры:
|
||
<code lua>
|
||
game.act = 'Не получается.';
|
||
game.inv = 'Гм.. Странная штука..';
|
||
game.use = 'Не сработает...';
|
||
</code>
|
||
|
||
===== 11. Атрибуты - списки =====
|
||
|
||
Атрибуты списки (такие как way или obj) позволяют работать с собой, таким образом позволяя реализовать динамически определяемые переходы между сценами, живые объекты и т.д.
|
||
|
||
Методы списков: add, del, look, srch, purge, replace. Из них наиболее часто используемые: add и del.
|
||
|
||
add - добавляет в список. del -- удаляет из него. purge -- удаляет даже выключенный объект. srch -- выполняет поиск объекта. replace -- замена объекта. Следует отметить, что параметром del, purge, replace и srch может быть не только сам объект или идентификатор объекта, но и имя объекта.
|
||
|
||
Начиная с версии 0.8 параметром add может быть сам объект. Кроме того, с этой версии добавляется необязательный второй параметр -- позиция в списке. Начиная с версии 0.8 вы можете также выполнять модификацию списка по индексу с помощью метода set. Например:
|
||
<code lua>
|
||
objs():set('knife',1);
|
||
</code>
|
||
|
||
Выше, вы уже видели пример со съеденным яблоком, там использовалась конструкция inv():del('apple');
|
||
|
||
inv() -- это функция, которая возвращает список инвентаря. del после ':'-- метод, удаляющий элемент инвентаря.
|
||
|
||
Аналогично, собственная реализация tak может быть такой:
|
||
<code lua>
|
||
knife = obj {
|
||
nam = 'нож',
|
||
dsc = 'На столе лежит {нож}',
|
||
inv = 'Острый!',
|
||
act = function(s)
|
||
objs():del(s);
|
||
inv():add(s);
|
||
end,
|
||
};
|
||
</code>
|
||
|
||
Кроме добавления, удаления объектов из списков вы можете использовать выключение/включение объектов с помощью методов enable() и disable(). Например: knife:disable(). При этом объект knife пропадает из описания сцены, но в последствии может быть опять быть включен, с помощью knife:enable().
|
||
|
||
Начиная с версии 0.9.1 доступны методы zap и cat. zap() -- обнуляет список. cat(b, [pos]) -- добавляет в список содержимое b на позицию pos.
|
||
|
||
Начиная с версии 0.9.1 доступны методы disable_all и enable_all, выключающие и включающие вложенные в объект объекты.
|
||
|
||
Внимание!!! На данный момент для работы с инвентарем и объектами рекомендуется использовать более высокоуровневые функции: put/get/take/drop/remove/seen/have и др.
|
||
|
||
===== 12. Функции, которые возвращают объекты =====
|
||
|
||
В STEAD определены некоторые функции, которые возвращают наиболее часто используемые объекты. Например:
|
||
* inv() возвращает список инвентаря;
|
||
* objs() возвращает список объектов текущей сцены; (начиная с 0.8.5 -- необязательный параметр -- сцена, для которой возвращается список);
|
||
* ways() возвращает список возможных переходов из текущей сцены; (начиная с 0.8.5 -- необязательный параметр -- сцена, для которой возвращается список);
|
||
* me() возвращает объект-игрок;
|
||
* here() возвращает объект текущую сцену; (начиная с 0.8.5 -- еще одна функция where(obj) -- возвращает сцену на которой находится объект, если он был помещен туда с помощью put/move/drop)
|
||
* from() возвращает объект прошлой сцены;
|
||
* seen(obj, [scene]) возвращает объект, если он присутствует и не отключен на сцене, есть второй необязательный параметр -- сцена;
|
||
* have(obj, [scene]) возвращает объект, если он есть в инвентаре и не отключен, есть второй необязательный параметр -- сцена;
|
||
* exist(obj, [scene]) возвращает объект, если он присутствует на сцене, есть второй необязательный параметр -- сцена;
|
||
* live(obj) возвращает объект, если он присутствует среди живых объектов;
|
||
* path(объект,[комната]) – найти элемент в way, даже если он disabled;
|
||
|
||
Комбинируя эти функции с методами add, del можно динамически менять сцену, например:
|
||
<code lua>
|
||
ways():add('nextroom'); -- добавить переход на новую сцену;
|
||
</code>
|
||
<code lua>
|
||
objs():add('chair'); -- добавить объект в текущую сцену;
|
||
</code>
|
||
|
||
Еще одна функция, которая получает объект по ссылке:
|
||
**ref()**.
|
||
|
||
Например, мы можем добавить объект в локацию 'home' следующим образом:
|
||
<code lua>
|
||
ref('home').obj:add('chair');
|
||
</code>
|
||
|
||
Впрочем, следующая более простая запись тоже является корректной:
|
||
<code lua>
|
||
home.obj:add('chair');
|
||
</code>
|
||
|
||
Или, для версии >=0.8.5:
|
||
<code lua>
|
||
objs('home'):add('chair');
|
||
</code>
|
||
или, наконец:
|
||
<code lua>
|
||
put('chair', 'home');
|
||
</code>
|
||
или даже:
|
||
<code lua>
|
||
put(chair, home);
|
||
</code>
|
||
|
||
Начиная с 0.8.5 -- **deref(o)**, возвращает ссылку-строку для объекта;
|
||
|
||
===== 13. Некоторые вспомогательные функции. =====
|
||
|
||
В STEAD определены некоторые высокоуровневые функции, которые могут оказаться полезными при написании игры.
|
||
|
||
have() -- проверяет, есть ли объект в инвентаре. По объекту, его ссылке или по атрибуту nam объекта. Например:
|
||
<code lua>
|
||
...
|
||
act = function(s)
|
||
if have('knife') then
|
||
return 'Но у меня же есть нож!';
|
||
end
|
||
end
|
||
...
|
||
</code>
|
||
Следующие варианты тоже будут работать:
|
||
<code lua>
|
||
...
|
||
if have 'knife' then
|
||
...
|
||
if have (knife) then
|
||
...
|
||
</code>
|
||
В следующих примерах вы также можете использовать все варианты адресации объектов.
|
||
|
||
move(o, w) -- переносит объект из текущей сцены в другую:
|
||
|
||
<code lua>move('mycat','inmycar');</code>
|
||
|
||
Если вы хотите перенести объект из произвольной сцены, вам придется удалить его из старой сцены с помощью метода del. Для создания сложно перемещающихся объектов, вам придется написать свой метод, который будет сохранять текущую позицию объекта в самом объекте и делать удаление объекта из старой сцены. Вы можете указать исходную позицию (комнату) объекта в качестве третьего параметра move.
|
||
|
||
<code lua>move('mycat','inmycar', 'forest'); </code>
|
||
|
||
Начиная с версии 0.8 присутствует также функция movef, аналогичная move, но добавляющая объект в начало списка.
|
||
|
||
seen(o) -- если объект присутствует в текущей сцене:
|
||
<code lua>
|
||
if seen('mycat') then
|
||
move('mycat','inmycar');
|
||
end
|
||
</code>
|
||
Начиная с 0.8.6 -- необязательный второй параметр -- сцена.
|
||
|
||
drop(o) -- положить объект из инвентаря на сцену:
|
||
|
||
drop('knife');
|
||
|
||
Начиная с версии 0.8 присутствует также функция dropf, аналогичная drop, но добавляющая объект в начало списка. Начиная с версии 0.8.5 второй необязательный параметр -- комната, куда помещается предмет. Кроме того, для версий >=0.8.5 доступны похожие функции put/putf, которые не удаляет предмет из инвентаря.
|
||
|
||
Начиная с 0.8.9 -- присутствует функция remove(o, [from]), удаляет объект из текущей сцены или сцены from.
|
||
|
||
take(o) -- взять объект.
|
||
<code lua>
|
||
take('knife');
|
||
</code>
|
||
Начиная с версии 0.8.5 второй необязательный параметр -- комната, с которой берется предмет.
|
||
|
||
taken(o) -- если объект взят -- вернет true (взят с помощью tak или take());
|
||
|
||
rnd(m) -- случайное значение от 1 до m.
|
||
|
||
goto(w) -- перейти в сцену w, при этом, если вы не используете p/pn/pr обработчику нужно вернуть возвращаемое значение goto. Например:
|
||
<code lua>
|
||
act = code [[
|
||
pn "Я иду в следующую комнату..."
|
||
goto (nextroom);
|
||
]]
|
||
...
|
||
act = code [[
|
||
return cat('Я иду в следующую комнату', goto (nextroom));
|
||
]]
|
||
</code>
|
||
Внимание!!! После вызова goto выполнение обработчика продолжится до его завершения.
|
||
change_pl(p) -- переключиться на другого игрока (со своим инвентарем и позицией). При этом функция возвращает описание сцены нового игрока и это возвращаемое значение должно быть передано из обработчика (см. goto()).
|
||
|
||
<code lua>
|
||
mycar = obj {
|
||
nam = 'моя машина',
|
||
dsc = 'Перед хижиной стоит мой старенький {пикап} Toyota.',
|
||
act = function(s)
|
||
return goto('inmycar');
|
||
end
|
||
};
|
||
</code>
|
||
goback() -- возвращается из сцены в прошлую.
|
||
|
||
back() -- возвращается из сцены в прошлую. Если это переход из диалога в комнату, то не вызываются: dsc, enter, entered у комнаты. exit/left диалога вызываются. В других случаях аналогична goback.
|
||
|
||
goin(комната) -- перейти в сцену, при этом exit/left текущей комнаты не вызывается;
|
||
|
||
goout() -- вернуться в прошлую сцену, при этом enter/entered этой сцены не вызовется;
|
||
|
||
time() -- возвращает текущее время игры. Время игры считается в активных действиях.
|
||
|
||
cat(...) -- возвращает строку -- склейку строк-аргументов. Если первый аргумент nil, то функция возвращает nil.
|
||
|
||
par(...) -- возвращает строку -- склейку строк-аргументов, разбитых строкой-первым параметром.
|
||
|
||
disable/enable/disable_all/enable_all -- аналог одноименных методов у объекта;
|
||
|
||
visited([комната]) -- счетчик посещений комнаты или nil;
|
||
|
||
path(объект,[комната]) -- найти элемент в way, даже если он disabled;
|
||
|
||
nameof(объект) -- вернуть имя объекта (nam атрибут);
|
||
|
||
purge (объект, [откуда]) -- см. remove, удаляет даже выключенные объекты;
|
||
|
||
replace(объект, на объект, [где]) -- замена одного объекта другим;
|
||
|
||
disabled(объект) -- возвращает true, если объект отключен;
|
||
|
||
===== 14. Диалоги =====
|
||
|
||
Диалоги это сцены, содержащие объекты -- фразы. Например, простейший диалог может выглядеть следующим образом.
|
||
<code lua>
|
||
povardlg = dlg {
|
||
nam = 'на кухне',
|
||
dsc = 'Передо мной полное лицо женщины - повара в белом колпаке и усталым взглядом...',
|
||
obj = {
|
||
[1] = phr('Мне вот-этих зелененьких... Ага -- и бобов!', 'На здоровье!'),
|
||
[2] = phr('Картошку с салом, пожалуйста!', 'Приятного аппетита!'),
|
||
[3] = phr('Две порции чесночного супа!!!', 'Прекрасный выбор!'),
|
||
[4] = phr('Мне что-нибудь легонькое, у меня язва...', 'Овсянка!'),
|
||
},
|
||
};
|
||
</code>
|
||
phr -- создание фразы. Фраза содержит вопрос, ответ и реакцию (реакция в данном примере отсутствует). Когда игрок выбирает одну из фраз, фраза отключается. Когда все фразы отключатся диалог заканчивается. Реакция -- это строка кода на lua который выполнится после отключения фразы. Например:
|
||
<code lua>
|
||
food = obj {
|
||
nam = 'еда',
|
||
inv = function (s)
|
||
inv():del('food');
|
||
return 'Я ем.';
|
||
end
|
||
};
|
||
|
||
gotfood = function(w)
|
||
inv():add('food');
|
||
food._num = w;
|
||
back();
|
||
end
|
||
|
||
povardlg = dlg {
|
||
nam = 'на кухне',
|
||
dsc = 'Передо мной полное лицо женщины - повара в белом колпаке и усталым взглядом...',
|
||
obj = {
|
||
[1] = phr('Мне вот-этих зелененьких... Ага -- и бобов!', 'На здоровье!', [[pon(); gotfood(1);]]),
|
||
[2] = phr('Картошку с салом, пожалуйста!', 'Приятного аппетита!', [[pon(); gotfood(2);]]),
|
||
[3] = phr('Две порции чесночного супа!!!', 'Прекрасный выбор!', [[pon();gotfood(3);]]),
|
||
[4] = phr('Мне что-нибудь легонькое, у меня язва...', 'Овсянка!', [[pon(); gotfood(4);]]),
|
||
},
|
||
};
|
||
</code>
|
||
В данном примере, игрок выбирает еду. Получает ее (запомнив выбор в переменной food._num) и возвращается обратно (в ту сцену откуда попал в диалог).
|
||
|
||
В реакции может быть любой lua код, но в STEAD определены наиболее часто используемые функции:
|
||
|
||
* pon(n..) -- включить фразы диалога с номерами n... (в нашем примере -- чтобы игрок мог повторно взять еду того-же вида).
|
||
* poff(n...) -- выключить фразы диалога с номерами n...
|
||
* prem(n...) -- удалить (заблокировать) фразы диалога с номерами n... (удаление означает невозможность включения фраз. pon(n..) не приведет к включению фраз).
|
||
* pseen(n..) -- вернет true, если все заданные фразы диалога видимы.
|
||
* punseen(n..) -- вернет true, если все заданные фразы диалога невидимы.
|
||
|
||
Если параметр n не указан, действие относится к текущей фразе.
|
||
|
||
Переход в диалог осуществляется как переход на сцену:
|
||
<code lua>
|
||
povar = obj {
|
||
nam = 'повар',
|
||
dsc = 'Я вижу {повара}.',
|
||
act = function()
|
||
return goto('povardlg');
|
||
end,
|
||
};
|
||
</code>
|
||
Вы можете переходить из одного диалога в другой диалог -- организовывая иерархические диалоги.
|
||
|
||
Также, вы можете прятать некоторые фразы при инициализации диалога и показывать их при некоторых условиях.
|
||
<code lua>
|
||
facectrl = dlg {
|
||
nam = 'фэйсконтроль',
|
||
dsc = 'Я вижу перед собой неприятное лицо полного охранника.',
|
||
obj = {
|
||
[1] = phr('Я пришел послушать лекцию Белина...',
|
||
'-- Я не знаю кто вы -- ухмыляется охранник -- но мне велели пускать сюда только приличных людей.',
|
||
[[pon(2);]]),
|
||
[2] = _phr('У меня есть приглашение!',
|
||
'-- А мне плевать! Посмотри на себя в зеркало!!! Ты пришел слушать самого Белина -- правую руку самого... -- охранник почтительно помолчал -- Так что пошел вон..', [[pon(3,4)]]),
|
||
[3] = _phr('Сейчас я дам тебе по роже!', '-- Ну все... Мощные руки выталкивают меня в коридор...',
|
||
[[poff(4)]]),
|
||
[4] = _phr('Ты, кабан! Я же тебе сказал -- у меня есть приглашение!',
|
||
'-- Чтоооооо? Глаза охранника наливаются кровью... Мощный пинок отправляет меня в коридор...',
|
||
[[poff(3)]]),
|
||
},
|
||
exit = function(s,w)
|
||
s:pon(1);
|
||
end,
|
||
};
|
||
</code>
|
||
|
||
`_phr` -- создает выключенную фразу, которую можно включить. Данный пример показывает также возможность использования методов pon, poff, prem для диалога (см. exit).
|
||
|
||
Вы можете включать/выключать/удалять/проверять фразы не только текущего, но и произвольного диалога, с помощью методов объекта диалог pon/poff/prem/pseen/punseen. Например: shopman:pon(5);
|
||
|
||
===== 15. Облегченные объекты =====
|
||
|
||
Иногда, сцену нужно наполнить декорациями, которые обладают ограниченной функциональностью, но делают игру разнообразней. Для этого можно использовать облегченный объект. Например:
|
||
<code lua>
|
||
sside = room {
|
||
nam = 'южная сторона',
|
||
dsc = [[Я нахожусь у южной стены здания института. ]],
|
||
act = function(s, w)
|
||
if w == "подъезд" then
|
||
ways():add('stolcorridor');
|
||
p "Я подошел к подъезду. На двери подъезда надпись -- 'Столовая'. Хм -- зайти внутрь?";
|
||
elseif w == "люди" then
|
||
p 'Те, кто выходят, выглядят более довольными...';
|
||
end
|
||
end,
|
||
obj = { vobj("подъезд", "У восточного угла находится небольшой {подъезд}."),
|
||
vobj("люди", "Время от времени дверь подъезда хлопает впуская и выпуская {людей}.")},
|
||
};
|
||
</code>
|
||
Как видим, vobj позволяет сделать легкую версию статического объекта, с которым тем не менее можно взаимодействовать (за счет определения обработчика act в сцене и анализа имени объекта). vobj также вызывает метод used, при этом в качестве третьего параметра передается объект, воздействующий на виртуальный объект.
|
||
|
||
Синтаксис vobj: vobj(имя, описатель);
|
||
|
||
Существует модификация объекта vobj -- vway. vway реализует ссылку.
|
||
Синтаксис vway: vway(имя, описатель, сцена назначения); например:
|
||
|
||
<code lua>
|
||
obj = { vway("дальше", "Нажмите {здесь}.", 'nextroom') }
|
||
</code>
|
||
|
||
Вы можете динамически заполнять сцену объектами vobj или vway с помощью методов add и del. Например:
|
||
|
||
<code lua>
|
||
objs(home):add(vway("next", "{Дальше}.", 'next_room'));
|
||
-- здесь какой-нибудь код
|
||
home.obj:del("next");
|
||
</code>
|
||
|
||
Определена также упрощенная сцена vroom.
|
||
Синтаксис: vroom(имя перехода, сцена назначения). Например:
|
||
|
||
<code lua>
|
||
home.obj:add(vroom("идти на запад", 'mountains');
|
||
</code>
|
||
|
||
===== 16. Динамические события =====
|
||
|
||
Вы можете определять обработчики, которые выполняются каждый раз, когда время игры увеличивается на 1. Например:
|
||
<code lua>
|
||
mycat = obj {
|
||
nam = 'Барсик',
|
||
lf = {
|
||
[1] = 'Барсик шевелится у меня за пазухой.',
|
||
[2] = 'Барсик выглядывает из-за пазухи.',
|
||
[3] = 'Барсик мурлычит у меня за пазухой.',
|
||
[4] = 'Барсик дрожит у меня за пазухой.',
|
||
[5] = 'Я чувствую тепло Барсика у себя за пазухой.',
|
||
[6] = 'Барсик высовывает голову из-за пазухи и осматривает местность.',
|
||
},
|
||
life = function(s)
|
||
local r = rnd(6);
|
||
if r > 2 then
|
||
return;
|
||
end
|
||
r = rnd(6);
|
||
return s.lf[r];
|
||
end,
|
||
....
|
||
|
||
profdlg2 = dlg {
|
||
nam = 'Белин',
|
||
dsc = 'Белин бледен. Он смотрит на дробовик рассеянным взглядом.',
|
||
obj = {
|
||
[1] = phr('Я пришел за своим котом.',
|
||
'Я выхватываю Барсика из руки Белина и засовываю себе за пазуху.',
|
||
[[inv():add('mycat'); lifeon('mycat')]]),
|
||
....
|
||
</code>
|
||
Любой объект или сцена могут иметь свой обработчик life, который вызывается каждый раз при смене текущего времени игры, если объект или сцена были добавлены в список живых объектов с помощью lifeon. Не забывайте удалять живые объекты из списка с помощью lifeoff, когда они больше не нужны. Это можно сделать, например, в обработчике exit, или любым другим способом.
|
||
|
||
life метод может возвращать текст события, который печатается после описания сцены.
|
||
|
||
Начиная с версии 0.9.1 вы можете вернуть из обработчика life второй код возврата, важность. (true или false). Например:
|
||
<code lua>
|
||
return 'В комнату вошел охранник.', true
|
||
</code>
|
||
Или:
|
||
<code lua>
|
||
p 'В комнату вошел охранник.'
|
||
return true
|
||
</code>
|
||
|
||
При этом текст события будет выведен до описания объектов.
|
||
===== 17. Графика и музыка =====
|
||
|
||
Графический интерпретатор анализирует атрибут сцены pic, и воспринимает его как путь к картинке, например:
|
||
|
||
<code lua>
|
||
home = room {
|
||
pic = 'gfx/home.png',
|
||
nam = 'дома',
|
||
dsc = 'Я у себя дома',
|
||
};
|
||
</code>
|
||
|
||
Конечно, pic может быть функцией, расширяя возможности разработчика.
|
||
Если в текущей сцене не определен атрибут pic, то берется атрибут game.pic. Если не определен и он, то картинка не отображается.
|
||
|
||
Начиная с версии 0.9.2 вы можете использовать в качестве картинок анимированные gif файлы.
|
||
|
||
Начиная с версии 0.9.2 вы можете встраивать графические изображения в текст или в инвентарь с помощью функции img. Например:
|
||
<code lua>
|
||
knife = obj {
|
||
nam = 'Нож'..img('img/knife.png'),
|
||
}
|
||
</code>
|
||
|
||
А начиная с 1.3.0 поддерживается обтекание картинок текстом. Если картинка вставляется с помощью функции imgl/imgr, она будет расположена у левого/правого края. Такие картинки не могут быть ссылками.
|
||
|
||
Для задания отступов вокруг изображения используйте pad, например:
|
||
<code lua>
|
||
imgl 'pad:16,picture.png' -- отступы по 16 от каждого края
|
||
imgl 'pad:0 16 16 4,picture.png' -- отступы: вверху 0, справа 16, внизу 16, слева 4
|
||
imgl 'pad:0 16,picture.png' -- отступы: вверху 0, справа 16, внизу 0, слева 16
|
||
</code>
|
||
|
||
Вы можете использовать псевдо-файлы для изображений прямоугольников и пустых областей:
|
||
<code lua>
|
||
dsc = img 'blank:32x32'..[[Строка с пустым изображением.]];
|
||
dsc = img 'box:32x32,red,128'..[[Строка красным полупрозрачным квадратом.]];
|
||
</code>
|
||
|
||
В современной версии INSTEAD вы можете использовать атрибут disp:
|
||
<code lua>
|
||
knife = obj {
|
||
nam = 'Нож';
|
||
disp = 'Нож'..img('img/knife.png'),
|
||
}
|
||
</code>
|
||
|
||
Начиная с версии 1.0.0 интерпретатор может обрабатывать составные картинки, например:
|
||
<code lua>
|
||
pic = 'gfx/mycat.png;gfx/milk.png@120,25;gfx/fish.png@32,32'
|
||
</code>
|
||
|
||
Интерпретатор проигрывает в цикле текущую музыку, которая задается с помощью функции:
|
||
set_music(имя музыкального файла).
|
||
|
||
Например:
|
||
<code lua>
|
||
street = room {
|
||
pic = 'gfx/street.png',
|
||
enter = function()
|
||
set_music('mus/rain.ogg');
|
||
end,
|
||
nam = 'на улице',
|
||
dsc = 'На улице идет дождь.',
|
||
};
|
||
</code>
|
||
|
||
get_music() возвращает текущее имя трека.
|
||
|
||
Начиная с версии 0.7.7 в функцию set_music() можно передавать второй параметр -- количество проигрываний. Получить текущий счетчик можно с помощью get_music_loop. 0 - означает вечный цикл. 1..n -- количество проигрываний. -1 -- проигрывание текущего трека закончено.
|
||
|
||
Начиная с версии 0.9.2 set_sound() позволяет проиграть звуковой файл. get_sound() возвращает имя звукового файла, который будет проигран.
|
||
|
||
Для того, чтобы отменить проигрывание, вы можете использовать stop_music() (с версии 1.0.0).
|
||
|
||
is_music() позволяет узнать, проигрывается ли музыка. (с версии 1.0.0)
|
||
===== 18. Полезные советы =====
|
||
|
||
==== Разбиение на файлы ====
|
||
|
||
Для разбиения текста игры на файлы вы можете использовать dofile. Вы должны использовать dofile в глобальном контексте таким образом, чтобы во время загрузки main.lua загрузились и все остальные фрагменты игры, например.
|
||
|
||
<code>
|
||
-- main.lua
|
||
dofile "episode1.lua"
|
||
dofile "npc.lau"
|
||
dofile "start.lua"
|
||
</code>
|
||
|
||
Для динамической подгрузки частей игры (с возможностью переопределения существующих объектов), вы можете воспользоваться gamefile:
|
||
|
||
<code>
|
||
...
|
||
act = code [[ gamefile ("episode2.lua"); ]]
|
||
...
|
||
</code>
|
||
|
||
gamefile позволяет загрузить новый файл и забыть стек предыдущих загрузок, запустив этот новый файл как самостоятельную игру.
|
||
|
||
|
||
<code>
|
||
...
|
||
act = code [[ gamefile ("episode3.lua", true); ]]
|
||
...
|
||
</code>
|
||
|
||
==== Модули ====
|
||
**//[[ru:gamedev:modules|Подробнее о модулях]]//**
|
||
|
||
Начиная с версии 1.2.0 появилась возможность использования модулей с помощью require. На данный момент существуют следующие модули:
|
||
|
||
* dbg — модуль отладки (require "dbg" – включить отладчик);
|
||
* goto — улучшенный вариант реализации переходов;
|
||
* xact — множественные ссылки;
|
||
* input — клавиатурный ввод;
|
||
* click — модуль перехвата кликов мыши по картинке сцены;
|
||
* vars — модуль определения переменных;
|
||
* prefs — модуль настроек;
|
||
* snapshots — модуль поддержки снапшотов;
|
||
* format — модуль оформления вывода;
|
||
* object — модуль улучшенных объектов;
|
||
* theme — управление темой;
|
||
|
||
Использование модуля выглядит так:
|
||
<code lua>
|
||
--$Name: Моя игра!$
|
||
instead_version "1.2.0"
|
||
require "para"
|
||
require "dbg"
|
||
...
|
||
</code>
|
||
Следующие модули подключаются автоматически, если вы задали version >= 1.2.0: vars, object, goto.
|
||
|
||
Объект prefs (находится в модуле prefs) служит для сохранения настроек игры, например, его можно использовать для реализации системы достижений или счетчика количества прохождений…
|
||
<code lua>
|
||
require "prefs"
|
||
...
|
||
prefs.counter = 0
|
||
...
|
||
exit = function(s)
|
||
prefs.counter = prefs.counter + 1
|
||
prefs:store()
|
||
end
|
||
...
|
||
enter = function(s)
|
||
return 'Вы прошли игру '..prefs.counter..' раз(а)';
|
||
end
|
||
...
|
||
act = function(s)
|
||
prefs:purge()
|
||
return "Настройки обнулены"
|
||
end
|
||
</code>
|
||
|
||
Модуль xact позволяет делать ссылки на объекты из других объектов, реакций и life методов в форме {объект:строка} следующим образом:
|
||
<code lua>
|
||
...
|
||
act = [[ Под столом я заметил {knife:нож}.]]
|
||
...
|
||
</code>
|
||
При этом, объект может быть объектом или именем объекта.
|
||
|
||
**Примечание**: начиная с версии 1.2.2 используется следующий формат ссылок: {объект|строка}.
|
||
|
||
В этом модуле определены также такие объекты как xact и xdsc.
|
||
|
||
xact -- объект - простейшая реакция. Например:
|
||
|
||
<code lua>
|
||
main = room {
|
||
forcedsc = true;
|
||
dsc = [[От автора. Эту игру я писал очень {note1:долго}.]];
|
||
obj = {
|
||
xact('note1', [[Больше 10 лет.]]);
|
||
}
|
||
}
|
||
</code>
|
||
Реакция может содержать код:
|
||
<code lua>
|
||
xact('note1', code [[p "Больше 10 лет."]]);
|
||
</code>
|
||
|
||
xdsc позволяет вставить в список объектов множественное описание:
|
||
<code lua>
|
||
main = room {
|
||
forcedsc = true;
|
||
dsc = [[Я в комнате.]];
|
||
xdsc = [[ Я вижу {apple:яблоко} и {knife:нож}. ]];
|
||
other = [[ Еще здесь лежат {chain:цепь} и {tool:пила}.]];
|
||
obj = {
|
||
xdsc(), -- 'xdsc method by default'
|
||
xdsc('other'),
|
||
'apple', 'knife', 'chain', 'tool',
|
||
}
|
||
}
|
||
</code>
|
||
Вы можете также использовать комнату xroom:
|
||
<code lua>
|
||
main = xroom {
|
||
forcedsc = true;
|
||
dsc = [[Я в комнате.]];
|
||
xdsc = [[ Я вижу {apple:яблоко} и {knife:нож}. ]];
|
||
obj = {
|
||
'apple', 'knife', 'chain', 'tool',
|
||
}
|
||
}
|
||
</code>
|
||
|
||
Модуль input позволяет реализовывать простые поля ввода, а click отслеживает щелчки по картинке сцены.
|
||
|
||
Модуль format выполняет форматирование вывода. По умолчанию все настройки выключены :
|
||
<code lua>
|
||
format.para = false -- отступы в начале абзаца;
|
||
format.dash = false -- замена двойного - на тире;
|
||
format.quotes = false -- замена " " на << >>;
|
||
format.filter = nil -- пользовательская функция замены;
|
||
</code>
|
||
|
||
Вы можете пользоваться модулями para, dash, quotes для включения отдельных настроек.
|
||
==== Форматирование ====
|
||
Вы можете делать простое форматирование текста с помощью функций:
|
||
|
||
* txtc() - разместить по центру;
|
||
* txtr() - разместить справа;
|
||
* txtl() - разместить слева;
|
||
* txttop() - сверху строки;
|
||
* txtbottom() - снизу строки;
|
||
* txtmiddle() - середина строки (по умолчанию);
|
||
|
||
Например:
|
||
<code lua>
|
||
main = room {
|
||
nam = 'Intro',
|
||
dsc = txtc('Добро пожаловать!'),
|
||
}
|
||
</code>
|
||
|
||
Вы также можете менять оформление текста с помощью комбинаций функций:
|
||
|
||
* txtb() - жирный;
|
||
* txtem() - курсив;
|
||
* txtu() - подчеркнутый;
|
||
* txtst() - перечеркнутый;
|
||
|
||
Например:
|
||
<code lua>
|
||
main = room {
|
||
nam = 'Intro',
|
||
dsc = 'Вы находитесь в комнате '..txtb('main')..'.',
|
||
}
|
||
|
||
Начиная с версии 1.1.0 вы также можете создавать неразрываемые строки с помощью: txtnb();
|
||
</code>
|
||
|
||
==== Меню ====
|
||
Вы можете делать меню в области инвентаря, определяя объекты с типом menu. При этом, обработчик меню будет вызван после одного клика мыши. Если обработчик не возвращает текст, то состояние игры не изменяется. Например, реализация кармана:
|
||
<code lua>
|
||
pocket = menu {
|
||
State = false,
|
||
nam = function(s)
|
||
if s.State then
|
||
return txtu('карман');
|
||
end
|
||
return 'карман';
|
||
end,
|
||
gen = function(s)
|
||
if s.State then
|
||
s:enable_all();
|
||
else
|
||
s:disable_all();
|
||
end
|
||
end,
|
||
menu = function(s)
|
||
if s.State then
|
||
s.State = false;
|
||
else
|
||
s.State = true;
|
||
end
|
||
s:gen();
|
||
end,
|
||
};
|
||
|
||
knife = obj {
|
||
nam = 'нож',
|
||
inv = 'Это нож',
|
||
};
|
||
|
||
function init()
|
||
inv():add(pocket);
|
||
put(knife, pocket);
|
||
pocket:gen();
|
||
end
|
||
|
||
main = room {
|
||
nam = 'test',
|
||
};
|
||
</code>
|
||
|
||
==== Статус игрока ====
|
||
Ниже представлена реализация статуса игрока в виде текста, который появляется в инвентаре, но не может быть выбран.
|
||
|
||
<code lua>
|
||
global {
|
||
life = 10;
|
||
power = 10;
|
||
}
|
||
|
||
status = stat {
|
||
nam = function(s)
|
||
p ('Жизнь: ', life, 'Сила: ', power)
|
||
end
|
||
};
|
||
function init()
|
||
inv():add('status');
|
||
end
|
||
</code>
|
||
|
||
==== goto из обработчика exit ===
|
||
|
||
Если вы выполните goto из обработчика exit, то получите переполнение стека, так как goto снова и снова будет вызывать метод exit. Вы можете избавиться от этого, если вставите проверку, разрушающую рекурсию. Например:
|
||
<code lua>
|
||
exit = function(s, t)
|
||
if t == 'dialog' then return; end
|
||
return goto('dialog');
|
||
end
|
||
</code>
|
||
Начиная с версии 0.9.1 движок сам разрывает рекурсию.
|
||
|
||
Вы можете также делать goto из обработчиков enter.
|
||
|
||
==== Динамически создаваемые ссылки. ====
|
||
Динамически создаваемые ссылки могут быть реализованы разным способом. Ниже приводится пример, основанный на использовании объектов vway. Для добавления ссылки можно использовать запись:
|
||
<code lua>
|
||
objs(home):add(vway('Дорога', 'Я заметил {дорогу}, ведущую в лес...', 'forest'));
|
||
</code>
|
||
Для удаления ссылки можно использовать метод del.
|
||
<code lua>
|
||
objs(home):del('Дорога');
|
||
</code>
|
||
Для определения наличия ссылки в сцене -- метод srch.
|
||
<code lua>
|
||
if not objs(home):srch('Дорога') then
|
||
objs(home):add(vway('Дорога', 'Я заметил {дорогу}, ведущую в лес...', 'forest'));
|
||
end
|
||
</code>
|
||
Динамические ссылки удобно создавать в обработчике enter, или по мере необходимости в любом месте кода игры. Если ссылки создаются в текущей сцене, то последний пример можно упростить:
|
||
<code lua>
|
||
if not seen('Дорога') then
|
||
objs():add(vway('Дорога', 'Я заметил {дорогу}, ведущую в лес...', 'forest'));
|
||
end
|
||
</code>
|
||
Кроме того, вы можете просто включать и выключать ссылки с помощью enable(), disable(), например:
|
||
<code lua>
|
||
seen('Дорога', home):disable();
|
||
exsist('Дорога', home):enable();
|
||
</code>
|
||
|
||
Вы можете создавать выключенные vobj и vway следующим образом:
|
||
<code lua>
|
||
obj = {vway('Дорога', 'Я заметил {дорогу}, ведущую в лес...', 'forest'):disable()},
|
||
</code>
|
||
И затем включать их по индексу в массиве obj или иным способом (seen/srch/exist):
|
||
<code lua>
|
||
objs()[1]:enable();
|
||
</code>
|
||
|
||
==== Кодирование исходного кода игры (начиная с версии 0.9.3) ====
|
||
Если вы не хотите показывать исходный код своих игр, вы можете закодировать исходный код с помощью sdl-instead -encode <путь к файлу> [выходной путь] и использовать его с помощью lua функции doencfile. При этом главный файл main.lua необходимо оставлять текстовым. Таким образом схема выглядит следующим образом (game -- закодированный game.lua):
|
||
|
||
main.lua
|
||
<code lua>
|
||
-- $Name: Моя закрытая игра!$
|
||
doencfile("game");
|
||
</code>
|
||
|
||
ЗАМЕЧАНИЕ:
|
||
Не используйте компиляцию игр с помощью luac, так как luac создает платформозависимый код!
|
||
Однако, компиляция игр может быть использована для поиска ошибок в коде.
|
||
|
||
==== Переключение между игроками ====
|
||
Вы можете создать игру с несколькими персонажами и время от времени переключаться между ними (см. change_pl). Но вы можете также использовать этот трюк для того, что бы иметь возможность переключаться между разными типами инвентаря.
|
||
|
||
==== Использование первого параметра обработчика ====
|
||
Пример кода.
|
||
<code lua>
|
||
stone = obj {
|
||
nam = 'камень',
|
||
dsc = 'На краю лежит {камень}.',
|
||
act = function()
|
||
objs():del('stone');
|
||
return 'Я толкнул камень, он сорвался и улетел вниз...';
|
||
end
|
||
</code>
|
||
|
||
Обработчик act мог бы выглядеть проще:
|
||
<code lua>
|
||
act = function(s)
|
||
objs():del(s);
|
||
return 'Я толкнул камень, он сорвался и улетел вниз...';
|
||
end
|
||
</code>
|
||
|
||
==== Использование set_music ====
|
||
Вы можете использовать set_music для проигрывания звуков, задавая второй параметр -- счетчик циклов проигрывания звукового файла.
|
||
|
||
Вы можете написать для игры свой проигрыватель музыки, создав его на основе живого объекта, например:
|
||
<code lua>
|
||
-- играет треки в случайном порядке, начиная со 2-го
|
||
tracks = {"mus/astro2.mod", "mus/aws_chas.xm", "mus/dmageofd.xm", "mus/doomsday.s3m"}
|
||
mplayer = obj {
|
||
nam = 'плеер',
|
||
life = function(s)
|
||
local n = get_music();
|
||
local v = get_music_loop();
|
||
if not n or not v then
|
||
set_music(tracks[2], 1);
|
||
elseif v == -1 then
|
||
local n = get_music();
|
||
while get_music() == n do
|
||
n = tracks[rnd(4)]
|
||
end
|
||
set_music(n, 1);
|
||
end
|
||
end,
|
||
};
|
||
lifeon('mplayer');
|
||
</code>
|
||
|
||
Вы можете использовать функции get_music_loop и get_music, для того, чтобы запоминать прошлую мелодию, и потом восстанавливать ее, например:
|
||
|
||
<code lua>
|
||
function save_music(s)
|
||
s._oldMusic = get_music();
|
||
s._oldMusicLoop = get_music_loop();
|
||
end
|
||
|
||
function restore_music(s)
|
||
set_music(s._oldMusic, s._oldMusicLoop);
|
||
end
|
||
|
||
-- ....
|
||
enter = function(s)
|
||
save_music(s);
|
||
end,
|
||
exit = function(s)
|
||
restore_music(s);
|
||
end,
|
||
-- ....
|
||
|
||
</code>
|
||
|
||
Начиная с версии 0.8.5 функции save_music и restore_music уже присутствуют в библиотеке.
|
||
|
||
==== Живые объекты ====
|
||
Если вашему герою нужен друг, одним из способов может стать метод life этого персонажа, который всегда переносит объект в локацию игрока:
|
||
<code lua>
|
||
horse = obj {
|
||
nam = 'лошадь',
|
||
dsc = 'Рядом со мной стоит {лошадь}.',
|
||
life = function(s)
|
||
if not seen('horse') then
|
||
move('horse', here(), s.__where);
|
||
s.__where = pl.where;
|
||
end
|
||
end,
|
||
};
|
||
function init()
|
||
lifeon('horse');
|
||
end
|
||
</code>
|
||
|
||
==== Таймер ====
|
||
Начиная с версии 1.1.0 в instead появлилась возможность использовать таймер. (Только в графической версии интерпретатора.)
|
||
|
||
Таймер программируется с помощью объекта timer.
|
||
|
||
* timer:set(ms) -- задать интервал таймера в ms
|
||
* timer:stop() -- остановить таймер
|
||
* timer.callback(s) -- функция-обработчик таймера, которая вызывается через заданный диапазон времени
|
||
|
||
Функция таймера может возвратить команду интерфейса stead, которую нужно выполнить после того, как движок выполнит обработчик. Например:
|
||
<code lua>
|
||
timer.callback = function(s)
|
||
main._time = main._time + 1;
|
||
return "look";
|
||
end
|
||
timer:set(100);
|
||
main = room {
|
||
_time = 1,
|
||
force_dsc = true,
|
||
nam = 'Таймер',
|
||
dsc = function(s)
|
||
return 'Демонстрация: '..tostring(s._time);
|
||
end
|
||
};
|
||
</code>
|
||
|
||
==== Клавиатура ====
|
||
Начиная с версии 1.1.0 в instead появилась возможность анализировать ввод с клавиатуры (только в графической версии интерпретатора). Для этого используется объект input.
|
||
|
||
input.key(s, pressed, key) -- обработчик клавиатуры; pressed -- нажатие или отжатие. key -- символьное имя клавиши;
|
||
|
||
Обработчик может вернуть команду интерфейса stead, в этом случае клавиша не будет обработана интерпретатором.
|
||
Например:
|
||
<code lua>
|
||
input.key = function(s, pr, key)
|
||
if not pr or key == "escape"then
|
||
return
|
||
elseif key == 'space' then
|
||
key = ' '
|
||
elseif key == 'return' then
|
||
key = '^';
|
||
end
|
||
if key:len() > 1 then return end
|
||
main._txt = main._txt:gsub('_$','');
|
||
main._txt = main._txt..key..'_';
|
||
return "look";
|
||
end
|
||
|
||
main = room {
|
||
_txt = '_',
|
||
force_dsc = true,
|
||
nam = 'Клавиатура',
|
||
dsc = function(s)
|
||
return 'Демонстрация: '..tostring(s._txt);
|
||
end
|
||
};
|
||
</code>
|
||
|
||
==== Мышь ====
|
||
Начиная с версии 1.1.5 в instead появилась возможность анализировать события мыши. (Только в графической версии интерпретатора.) Для этого используется объект input.
|
||
|
||
input.click(s, pressed, mb, x, y, px, py) -- обработчик клика мыши; pressed -- нажатие или отжатие. mb -- номер кнопки (1 - левая), x и y -- координаты клика относительно левого верхнего угла. px и py присутствуют, если клик произошел в области картинки сцены и содержит координаты клика относительно левого верхнего угла картинки.
|
||
|
||
Обработчик может вернуть команду интерфейса stead, в этом случае клик не будет обработан интерпретатором.
|
||
|
||
Например:
|
||
<code lua>
|
||
input.click = function(s, press, mb, x, y, px, py)
|
||
if press and px then
|
||
click.x = px;
|
||
click.y = py;
|
||
click:enable();
|
||
return "look"
|
||
end
|
||
end
|
||
|
||
click = obj {
|
||
nam = 'клик',
|
||
x = 0,
|
||
y = 0,
|
||
dsc = function(s)
|
||
return "Вы кликнули по картинке в позиции: "..s.x..','..s.y..'.';
|
||
end
|
||
}:disable();
|
||
|
||
main = room {
|
||
nam = 'test',
|
||
pic ='picture.png',
|
||
dsc = 'Демонстрация.',
|
||
obj = { 'click' },
|
||
};
|
||
</code>
|
||
|
||
Пример прослойки, которая реализует вызов метода click в текущей комнате при клике на картинку:
|
||
<code lua>
|
||
input.click = function(s, press, mb, x, y, px, py)
|
||
if press and px then
|
||
return "click "..px..','..py;
|
||
end
|
||
end
|
||
|
||
game.action = function(s, cmd, x, y)
|
||
if cmd == 'click' then
|
||
return call(here(), 'click', x, y);
|
||
end
|
||
end
|
||
----------------------------------------------------------------------
|
||
main = room {
|
||
nam = 'test',
|
||
pic ='picture.png',
|
||
dsc = 'Демонстрация.',
|
||
click = function(s, x, y)
|
||
return "Вы кликнули по картинке в позиции: "..x..','..y..'.';
|
||
end
|
||
};
|
||
</code>
|
||
|
||
Внимание!!! Начиная с 1.2.0 рекомендуется использовать модуль click.
|
||
|
||
==== Динамическое создание объектов ====
|
||
Вы можете использовать функции new и delete для создания и удаления динамических объектов. Примеры:
|
||
|
||
<code lua>
|
||
new ("obj { nam = 'test', act = 'test' }")
|
||
put(new [[obj {nam = 'test' } ]]);
|
||
put(new('myconstructor()');
|
||
n = new('myconstructor()');
|
||
delete(n)
|
||
</code>
|
||
|
||
new воспринимает строку-аргумент как конструктор объекта. Результатом выполнения конструктора должен быть объект. Таким образом в аргументе обычно задан вызов функции-конструктора. Например:
|
||
<code lua>
|
||
function myconstructor()
|
||
local v = {}
|
||
v.nam = 'тестовый объект',
|
||
v.act = 'Тестовая реакция',
|
||
return obj(v);
|
||
end
|
||
</code>
|
||
Созданный объект будет попадать в файл сохранения. new() возвращает реальный объект; чтобы получить его имя, если это нужно, используйте функцию deref:
|
||
<code lua>
|
||
o_name = deref(new('myconstructor()'));
|
||
delete(o_name);
|
||
</code>
|
||
==== Сложный вывод из обработчиков ====
|
||
Иногда вывод обработчика может формироваться сложным образом, в зависимости от условий. В таких случаях удобно пользоваться функциями p() и pn(). Эти функции добавляют текст в буфер, связанный с обработчиком, который будет возвращен из обработчика.
|
||
<code lua>
|
||
dsc = function(s)
|
||
p "На полу стоит {бочка}."
|
||
if s._opened then
|
||
p "Крышка от бочки лежит рядом."
|
||
end
|
||
end
|
||
</code>
|
||
Функция pn() выполняет вывод текста в буфер, дополняя его переводом строки. Функция p() дополняет вывод пробелом.
|
||
|
||
Начиная с версии 1.1.6 существует функция pr(), которая не выполняет дополнение вывода.
|
||
|
||
Для очистки буфера, используйте pclr(). Если вам нужно вернуть статус действия, используйте pget(), или просто используйте return.
|
||
<code lua>
|
||
use = function(s, w)
|
||
if w == apple then
|
||
p 'Гм... Я почистил яблоко.';
|
||
apple._peeled = true
|
||
return
|
||
end
|
||
p 'Это нельзя использовать так!'
|
||
return false; -- или return pget(), false
|
||
end
|
||
</code>
|
||
|
||
==== Отладка ====
|
||
Для того, чтобы во время ошибки увидеть стек вызовов функций lua, вы можете запустить sdl-instead с параметром -debug. При этом в windows версии интерпретатора будет создана консоль отладки.
|
||
|
||
Вы можете отлаживать свою игру вообще без instead. Например, вы можете создать следующий файл game.lua:
|
||
<code lua>
|
||
dofile("/usr/share/games/stead/stead.lua"); -- путь к stead.lua
|
||
dofile("main.lua"); -- ваша игра
|
||
game:ini();
|
||
iface:shell();
|
||
</code>
|
||
И запустите игру в lua: lua game.lua.
|
||
При этом игра будет работать в примитивном shell окружении. Полезные команды: ls, go, act, use....
|
||
|
||
Для включения простого отладчика, после version вначале файла напишите:
|
||
<code lua>
|
||
require "dbg"
|
||
</code>
|
||
Отладчик вызывается по F7.
|
||
===== 19. Темы для sdl-instead =====
|
||
|
||
Графический интерпретатор поддерживает механизм тем. Тема представляет из себя каталог, с файлом theme.ini внутри.
|
||
|
||
Тема, которая является минимально необходимой -- это тема default. Эта тема всегда загружается первой. Все остальные темы наследуются от нее и могут частично или полностью заменять ее параметры. Выбор темы осуществляется пользователем через меню настроек, однако конкретная игра может содержать собственную тему и таким образом влиять на свой внешний вид. В этом случае в каталоге с игрой должен находиться свой файл theme.ini. Тем не-менее пользователь свободен отключить данный механизм, при этом интерпретатор будет предупреждать о нарушении творческого замысла автора игры.
|
||
|
||
Синтаксис theme.ini очень прост.
|
||
|
||
<параметр> = <значение>
|
||
|
||
или
|
||
|
||
; комментарий
|
||
|
||
Значения могут быть следующих типов: строка, цвет, число.
|
||
|
||
Цвет задается в форме #rgb, где r g и b компоненты цвета в шестнадцатеричном виде. Кроме того некоторые основные цвета распознаются по своим именам. Например: yellowgreen, или violet.
|
||
|
||
Параметры могут принимать значения:
|
||
|
||
scr.w = ширина игрового пространства в пикселях (число)
|
||
|
||
scr.h = высота игрового пространства в пикселях (число)
|
||
|
||
scr.col.bg = цвет фона
|
||
|
||
scr.gfx.bg = путь к картинке фонового изображения (строка)
|
||
|
||
scr.gfx.cursor.x = x координата центра курсора (число) (версия >= 0.8.9)
|
||
|
||
scr.gfx.cursor.y = y координата центра курсора (число) (версия >= 0.8.9)
|
||
|
||
scr.gfx.cursor.normal = путь к картинке-курсору (строка) (версия >= 0.8.9)
|
||
|
||
scr.gfx.cursor.use = путь к картинке-курсору режима использования (строка) (версия >= 0.8.9)
|
||
|
||
scr.gfx.use = путь к картинке-индикатору режима использования (строка) (версия < 0.8.9)
|
||
|
||
scr.gfx.pad = размер отступов к скролл-барам и краям меню (число)
|
||
|
||
scr.gfx.x, scr.gfx.y, scr.gfx.w, scr.gfx.h = координаты, ширина и высота окна изображений. Области в которой располагается картинка сцены. Интерпретация зависит от режима расположения (числа)
|
||
|
||
win.gfx.h - синоним scr.gfx.h (для совместимости)
|
||
|
||
scr.gfx.mode = режим расположения (строка fixed, embedded или float). Задает режим изображения. embedded -- картинка является частью содержимого главного окна, параметры scr.gfx.x, scr.gfx.y, scr.gfx.w игнорируются. float -- картинка расположена по указанным координатам (scr.gfx.x, scr.gfx.y) и масштабируется к размеру scr.gfx.w x scr.gfx.h если превышает его. fixed -- картинка является частью сцены как в режиме embedded, но не скроллируется вместе с текстом а расположена непосредственно над ним.
|
||
|
||
win.x, win.y, win.w, win.h = координаты, ширина и высота главного окна. Области в которой располагается описание сцены (числа)
|
||
|
||
win.fnt.name = путь к файлу-шрифту (строка)
|
||
|
||
win.fnt.size = размер шрифта главного окна (размер)
|
||
|
||
win.fnt.height = междустрочный интервал как число с плавающей запятой (1.0 по умолчанию)
|
||
|
||
win.gfx.up, win.gfx.down = пути к файлам-изображениям скорллеров вверх/вниз для главного окна (строка)
|
||
|
||
win.up.x, win.up.y, win.down.x, win.down.y = координаты скроллеров (координата или -1)
|
||
|
||
win.col.fg = цвет текста главного окна (цвет)
|
||
|
||
win.col.link = цвет ссылок главного окна (цвет)
|
||
|
||
win.col.alink = цвет активных ссылок главного окна (цвет)
|
||
|
||
inv.x, inv.y, inv.w, inv.h = координаты, высота и ширина области инвентаря. (числа)
|
||
|
||
inv.mode = строка режима инвентаря (horizontal или vertical). В горизонтальном режиме инвентаря в одной строке могут быть несколько предметов. В вертикальном режиме, в каждой строке инвентаря содержится только один предмет. (число)
|
||
|
||
inv.col.fg = цвет текста инвентаря (цвет)
|
||
|
||
inv.col.link = цвет ссылок инвентаря (цвет)
|
||
|
||
inv.col.alink = цвет активных ссылок инвентаря (цвет)
|
||
|
||
inv.fnt.name = путь к файлу-шрифту инвентаря (строка)
|
||
|
||
inv.fnt.size = размер шрифта инвентаря (размер)
|
||
|
||
inv.fnt.height = междустрочный интервал как число с плавающей запятой (1.0 по умолчанию)
|
||
|
||
inv.gfx.up, inv.gfx.down = пути к файлам-изображениям скорллеров вверх/вниз для инвентаря (строка)
|
||
|
||
inv.up.x, inv.up.y, inv.down.x, inv.down.y = координаты скроллеров (координата или -1)
|
||
|
||
menu.col.bg = фон меню (цвет)
|
||
|
||
menu.col.fg = цвет текста меню (цвет)
|
||
|
||
menu.col.link = цвет ссылок меню (цвет)
|
||
|
||
menu.col.alink = цвет активных ссылок меню (цвет)
|
||
|
||
menu.col.alpha = прозрачность меню 0-255 (число)
|
||
|
||
menu.col.border = цвет бордюра меню (цвет)
|
||
|
||
menu.bw = толщина бордюра меню (число)
|
||
|
||
menu.fnt.name = путь к файлу-шрифту меню (строка)
|
||
|
||
menu.fnt.size = размер шрифта меню (размер)
|
||
|
||
menu.fnt.height = междустрочный интервал как число с плавающей запятой (1.0 по умолчанию)
|
||
|
||
menu.gfx.button = путь к файлу изображению значка меню (строка)
|
||
|
||
menu.button.x, menu.button.y = координаты кнопки меню (числа)
|
||
|
||
snd.click = путь к звуковому файлу щелчка (строка)
|
||
|
||
include = имя темы (последний компонент в пути каталога) (строка)
|
||
|
||
Кроме того, заголовок темы может включать в себя комментарии с тегами. На данный момент существует только один тег: $Name:, содержащий UTF-8 строку с именем темы. Например:
|
||
<code lua>
|
||
; $Name:Новая тема$
|
||
; модификация темы book
|
||
include = book
|
||
scr.gfx.h = 500
|
||
</code>
|
||
|
||
Интерпретатор выполняет поиск тем в каталоге themes. Unix версия кроме этого каталога, просматривает также каталог ~/.instead/themes/
|
||
|
||
Windows версия (>=0.8.7): Documents and Settings/USER/Local Settings/Application Data/instead/themes |