1657 lines
90 KiB
Plaintext
1657 lines
90 KiB
Plaintext
====== Базовая документация ======
|
||
===== Общие сведения =====
|
||
Код игр для STEAD пишется на //lua (5.1)//, поэтому, знание этого языка полезно, хотя и не необходимо. Код движка на lua занимает около ~3000 строк и лучшей документацией является изучение его кода.
|
||
|
||
//Главное окно// игры содержит информацию о статической и динамической части сцены, активные события и картинку сцены с возможными переходами в другие сцены (в графическом интерпретаторе).
|
||
|
||
//Статическая часть сцены// отображается только один раз, при показе сцены, или при повторении команды ''look'' (в графическом интерпретаторе -- клик на названии сцены).
|
||
//
|
||
|
||
Динамическая часть сцены// составлена из описаний объектов сцены, она отображается всегда.
|
||
|
||
Игроку доступны объекты, доступные на любой сцене -- //инвентарь//. Игрок может взаимодействовать с объектами инвентаря и действовать объектами инвентаря на другие объекты сцены или инвентаря.
|
||
|
||
<WRAP center round info>
|
||
Следует отметить, что понятие инвентаря является условным. Например, в "инвентаре" могут находиться такие объекты как "открыть", "осмотреть", "использовать" и т.д.
|
||
</WRAP>
|
||
|
||
|
||
//Действиями// игрока могут быть:
|
||
|
||
* осмотр сцены;
|
||
* действие на объект сцены;
|
||
* действие на объект инвентаря;
|
||
* действие объектом инвентаря на объект сцены;
|
||
* действие объектом инвентаря на объект инвентаря;
|
||
* действие объектом сцены на объект сцены (режим scene_use);
|
||
* действие объектом сцены на инвентарь (режим scene_use);
|
||
* переход в другую сцену;
|
||
|
||
Игра представляет из себя каталог, в котором должен находиться скрипт ''main.lua''. Другие ресурсы игры (скрипты на ''lua'', графика и музыка) должны находиться в рамках этого каталога. Все ссылки на ресурсы делаются относительно текущего каталога -- каталога игры.
|
||
|
||
В начале файла ''main.lua'' может быть определен заголовок, состоящий из тегов. Теги должны начинаться с символов ''--'': комментарий с точки зрения lua. На данный момент существует один тег: ''$Name:'', который должен содержать название игры в кодировке UTF-8. Пример использования тега:
|
||
<code lua>
|
||
-- $Name: Самая интересная игра!$
|
||
</code>
|
||
|
||
Сразу после заголовков вам необходимо указать версию STEAD API, которая требуется игре. На данный момент последняя версия **1.4.5**.
|
||
<code lua>
|
||
instead_version "1.4.5"
|
||
</code>
|
||
|
||
<WRAP center round important>
|
||
__Важно!__
|
||
|
||
Если version отсутствует, то STEAD API будет работать в режиме совместимости (устаревшее API).
|
||
</WRAP>
|
||
|
||
|
||
//Инициализацию// игры следует описывать в функции ''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''.
|
||
|
||
<WRAP center round info>
|
||
Вы можете использовать символ '';'' вместо '','' для разделения атрибутов. Например:
|
||
<code lua>
|
||
main = room {
|
||
nam = 'главная комната';
|
||
dsc = 'Вы в большой комнате.';
|
||
};
|
||
</code>
|
||
</WRAP>
|
||
|
||
<WRAP center round tip>
|
||
Если для вашего творческого замысла необходимо, чтобы описание статической части сцены выводилось каждый раз, вы можете определить для своей игры параметр ''forcedsc'' (в начале игры).
|
||
<code lua>
|
||
game.forcedsc = true;
|
||
</code>
|
||
Или, аналогично, задать атрибут forcedsc для конкретных сцен.
|
||
</WRAP>
|
||
|
||
Для длинных описаний удобно использовать запись вида:
|
||
|
||
<code lua>dsc = [[ Очень длинное описание... ]],</code>
|
||
|
||
При этом переводы строк игнорируются. Если вы хотите, чтобы в выводе описания сцены присутствовали абзацы -- используйте символ ''^''.
|
||
|
||
<code lua>
|
||
dsc = [[ Первый абзац. ^^
|
||
Второй Абзац.^^
|
||
|
||
Третий абзац.^
|
||
На новой строке.]],
|
||
</code>
|
||
|
||
===== 2. Объекты =====
|
||
|
||
//Объекты// -- это единицы сцены, с которыми взаимодействует игрок.
|
||
<code lua>
|
||
tabl = obj {
|
||
nam = 'стол',
|
||
dsc = 'В комнате стоит {стол}.',
|
||
act = 'Гм... Просто стол...',
|
||
};
|
||
</code>
|
||
Имя объекта ''nam'' используется при попадании его в инвентарь а также в текстовом интерпретаторе для адресации объекта.
|
||
|
||
''dsc'' -- описание объекта. Оно будет выведено в динамической части сцены. Фигурными скобками отображается фрагмент текста, который будет являться ссылкой в графическом интерпретаторе.
|
||
|
||
''act'' -- это обработчик, который вызывается при действии пользователя (действие на объект сцены). Его задача -- возвращение строки текста, которая станет частью событий сцены, или логического значения (см. раздел 5).
|
||
|
||
<WRAP center round important>
|
||
ВНИМАНИЕ: в пространстве имен //lua// уже существуют некоторые объекты (таблицы), например: //table//, //io//, //string//... Будьте внимательны при создании объекта. Например, в приведенном примере используется ''tabl'', а не ''table''. Лучше не использовать подобные названия, хотя в новых версиях INSTEAD эта проблема во многом решена.
|
||
</WRAP>
|
||
|
||
|
||
===== 3. Добавляем объекты в сцену =====
|
||
|
||
//Ссылкой// на объект называется текстовая строка, содержащая имя объекта при его создании. Например: 'tabl' -- ссылка на объект ''tabl''.
|
||
|
||
Для того, чтобы поместить в сцену объекты, нужно определить массив ''obj'', состоящий из ссылок на объекты:
|
||
<code lua>
|
||
main = room {
|
||
nam = 'главная комната',
|
||
dsc = 'Вы в большой комнате.',
|
||
obj = { 'tabl' },
|
||
};
|
||
</code>
|
||
Теперь, при отображении сцены мы увидим объект //"стол"// в динамической части.
|
||
|
||
<WRAP center round info>
|
||
Вы можете использовать ссылки на объекты без кавычек в том случае, если объект был определен ранее, но использование кавычек всегда безопасней.
|
||
</WRAP>
|
||
|
||
|
||
===== 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 ("текст")'' -- вывод текста как есть;
|
||
|
||
<WRAP center round tip>
|
||
Если ''p''/''pn''/''pr'' вызывается с одним текстовым параметром, то скобки можно опускать.
|
||
</WRAP>
|
||
|
||
Используйте ''..'' или '','' для склейки строк. Например:
|
||
|
||
<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>
|
||
|
||
<WRAP center round important>
|
||
Переменные записываются в файл сохранения, если они размещены в одном из перечисленных типов объектов: комната, объект, игра, игрок, глобальное пространство, при этом начинаются с символа ''_'' или определены с помощью ''var'' и ''global''.
|
||
</WRAP>
|
||
|
||
|
||
Начиная с версии 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>
|
||
|
||
<WRAP center round important>
|
||
Следует отметить, что при вызове обработчика enter текущая сцена может быть **еще не изменена**!!! Начиная с версии 1.2.0 добавлены обработчики left и entered, которые вызываются после того, как переход произошел. Эти обработчики рекомендованы к использованию всегда, когда нет необходимости запрещать переход.
|
||
</WRAP>
|
||
|
||
|
||
===== 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 lua>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'' -- замена объекта.
|
||
|
||
<WRAP center round info>
|
||
Следует отметить, что параметром ''add'', ''del'', ''purge'', ''replace'' и ''srch'' может быть не только сам объект или идентификатор объекта, но и имя объекта.
|
||
</WRAP>
|
||
|
||
Начиная с версии 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()'', выключающие и включающие вложенные в объект объекты.
|
||
|
||
<WRAP center round important>
|
||
Внимание!!! На данный момент для работы с инвентарем и объектами рекомендуется использовать более высокоуровневые функции: ''put''/''get''/''take''/''drop''/''remove''/''seen''/''have'' и др.
|
||
</WRAP>
|
||
|
||
===== 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>
|
||
|
||
<WRAP center round info>
|
||
Если вы хотите перенести объект из произвольной сцены, вам придется удалить его из старой сцены с помощью метода ''del''. Для создания сложно перемещающихся объектов, вам придется написать свой метод, который будет сохранять текущую позицию объекта в самом объекте и делать удаление объекта из старой сцены.
|
||
</WRAP>
|
||
Вы можете указать исходную позицию (комнату) объекта в качестве третьего параметра ''move''.
|
||
|
||
<code lua>move('mycat','inmycar', 'forest'); </code>
|
||
|
||
<WRAP center round info>
|
||
Начиная с версии 0.8 присутствует также функция ''movef'', аналогичная ''move'', но добавляющая объект в начало списка.
|
||
</WRAP>
|
||
|
||
|
||
* ''seen(o)'' -- если объект присутствует в текущей сцене:
|
||
<code lua>
|
||
if seen('mycat') then
|
||
move('mycat','inmycar');
|
||
end
|
||
</code>
|
||
Начиная с 0.8.6 -- необязательный второй параметр -- сцена.
|
||
|
||
* ''drop(o)'' -- положить объект из инвентаря на сцену:
|
||
<code lua>
|
||
drop('knife');
|
||
</code>
|
||
<WRAP center round info>
|
||
Начиная с версии 0.8 присутствует также функция ''dropf'', аналогичная ''drop'', но добавляющая объект в начало списка. Начиная с версии 0.8.5 второй необязательный параметр -- комната, куда помещается предмет. Кроме того, для версий >=0.8.5 доступны похожие функции ''put''/''putf'', которые не удаляют предмет из инвентаря.
|
||
|
||
Начиная с 0.8.9 -- присутствует функция ''remove(o, [from])'', удаляет объект из текущей сцены или сцены ''from''.
|
||
</WRAP>
|
||
|
||
* ''take(o)'' -- взять объект.
|
||
<code lua>
|
||
take('knife');
|
||
</code>
|
||
<WRAP center round info>
|
||
Начиная с версии 0.8.5 второй необязательный параметр -- комната, с которой берется предмет.
|
||
</WRAP>
|
||
|
||
* ''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>
|
||
<WRAP center round important>
|
||
**Внимание!!!**
|
||
|
||
После вызова ''goto'' выполнение обработчика продолжится до его завершения.
|
||
</WRAP>
|
||
* ''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'').
|
||
|
||
<WRAP center round tip>
|
||
Вы можете включать/выключать/удалять/проверять фразы не только текущего, но и произвольного диалога, с помощью методов объекта диалог ''pon''/''poff''/''prem''/''pseen''/''punseen''. Например: ''shopman:pon(5);''
|
||
</WRAP>
|
||
|
||
|
||
===== 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 lua>
|
||
-- main.lua
|
||
dofile "episode1.lua"
|
||
dofile "npc.lau"
|
||
dofile "start.lua"
|
||
</code>
|
||
|
||
Для динамической подгрузки частей игры (с возможностью переопределения существующих объектов), вы можете воспользоваться ''gamefile'':
|
||
|
||
<code lua>
|
||
...
|
||
act = code [[ gamefile ("episode2.lua"); ]]
|
||
...
|
||
</code>
|
||
|
||
''gamefile'' позволяет загрузить новый файл и забыть стек предыдущих загрузок, запустив этот новый файл как самостоятельную игру.
|
||
|
||
|
||
<code lua>
|
||
...
|
||
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>
|
||
При этом, объект может быть объектом или именем объекта.
|
||
<WRAP center round info>
|
||
**Примечание**: до версии 1.2.2 использовался следующий формат ссылок: {объект:строка}.
|
||
</WRAP>
|
||
|
||
|
||
В этом модуле определены также такие объекты как ''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')..'.',
|
||
}
|
||
</code>
|
||
Начиная с версии 1.1.0 вы также можете создавать неразрываемые строки с помощью: ''txtnb()''.
|
||
==== Меню ====
|
||
Вы можете делать меню в области инвентаря, определяя объекты с типом ''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>
|
||
<WRAP center round info>
|
||
Начиная с версии 0.9.1 движок сам разрывает рекурсию.
|
||
</WRAP>
|
||
|
||
|
||
Вы можете также делать ''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''):
|
||
|
||
<code lua>
|
||
-- $Name: Моя закрытая игра!$
|
||
doencfile("game");
|
||
</code>
|
||
|
||
<WRAP center round important>
|
||
Не используйте компиляцию игр с помощью luac, так как luac создает платформозависимый код!
|
||
Однако, компиляция игр может быть использована для поиска ошибок в коде.
|
||
</WRAP>
|
||
|
||
|
||
==== Запаковка ресурсов (начиная с версии 1.4.0) ====
|
||
Вы можете упаковать ресурсы игры (графику, музыку, темы) в файл .idf, для этого поместите все ресурсы в каталог data и запустите INSTEAD:
|
||
|
||
''instead -idf <путь к data>''
|
||
|
||
При этом в текущем каталоге должен будет создастся файл ''data.idf''. Поместите его в каталог с игрой. Теперь ресурсы игры в виде отдельных файлов можно удалить.
|
||
|
||
Вы можете запаковать в формат ''.idf'' всю игру:
|
||
|
||
''instead -idf <путь к игре>''
|
||
|
||
Игры в формате ''idf'' можно запускать как обычные игры ''instead'' (как если бы это были каталоги) а также из командной строки:
|
||
|
||
''instead game.idf''
|
||
==== Переключение между игроками ====
|
||
Вы можете создать игру с несколькими персонажами и время от времени переключаться между ними (см. ''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>
|
||
<WRAP center round info>
|
||
Начиная с версии 0.8.5 функции save_music и restore_music уже присутствуют в библиотеке.
|
||
</WRAP>
|
||
|
||
|
||
==== Живые объекты ====
|
||
Если вашему герою нужен друг, одним из способов может стать метод ''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,
|
||
forcedsc = 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 = '_',
|
||
forcedsc = 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>
|
||
|
||
<WRAP center round important>
|
||
Внимание!!! Начиная с 1.2.0 рекомендуется использовать модуль click.
|
||
</WRAP>
|
||
|
||
==== Динамическое создание объектов ====
|
||
Вы можете использовать функции ''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'' очень прост.
|
||
|
||
<code ini>
|
||
<параметр> = <значение>
|
||
</code>
|
||
или
|
||
|
||
<code ini>; комментарий</code>
|
||
|
||
Значения могут быть следующих типов: строка, цвет, число.
|
||
|
||
Цвет задается в форме #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 ini>
|
||
; $Name:Новая тема$
|
||
; модификация темы book
|
||
include = book
|
||
scr.gfx.h = 500
|
||
</code>
|
||
|
||
<WRAP center round info>
|
||
Интерпретатор выполняет поиск тем в каталоге ''themes''. Unix версия кроме этого каталога, просматривает также каталог ''~/.instead/themes/''
|
||
Windows версия (>=0.8.7): ''Documents and Settings/USER/Local Settings/Application Data/instead/themes''
|
||
</WRAP>
|