СКРИПТОВАЯ СИСТЕМА ЯТК, ИЛИ, КАК ПИСАТЬ СКРИПТЫ
1. Особенности JavaScript, переменные, функции и объекты
Данное руководство не может претендовать на исчерпывающее руководство по языку JavaScript?, но я попытаюсь помочь со знакомством с ним, а также показать некоторые нюансы использования яваскрипт для взаимодействия с ЯТК. Для начала, коснёмся переменных. В яваскрипт, для использования переменной, сначала необходимо её создать, для этого служит ключевое слово var. Например строка var value; // создать переменную value Для удобства программирования в ЯТК предопределены две переменные, благодаря которым переменные определять не надо. Например, можно писать:
_G['value'] = 'test!';
это же можно написать и так:
_G.value = 'test!';
Переменные сохраненные в _G (альтернативное название globals) существуют во всех параграфах. Т.е. значения в этом массиве постоянны. Но есть ещё массив _L (альтернативное название locals), где переменные сохраняются только в "пределах" параграфа - после перехода на другой параграф, массив будет абсолютно пустым.
Для создания своих функций в тексте скрипта параграфа, вы можете использовать конструкцию вида:
_L['my_func'] = function(x, y)
{
return x * y;
}
А использовать её можно так:
addText('Результат 2*2=' + _L['my_func']());
Конечно же можно использовать и _G вместо _L, но при использовании _G для хранения ф-ий желательно не забывать их оттуда удалять. Удалить значение из массивов _G и _L в простейшем случае можно методом _delete:
_G._delete('my_func');
В яваскрипт нет полноценной объектно-ориентированной модели, но, тем не менее, в языке реализована поддержка объектов, позволяя повысить качество кода. Создать свой объект можно например вот так:
_G.player = OBJECT();
_G.player.health_max = 10;
_G.player.health = 10;
_G.player.hit = function(damage)
{
this.health -= damage;
if (this.health < 1)
{
alert('Вы умерли!);
}
else
{
alert('Здоровье: ' + this.health);
}
}
теперь такой объект можно использовать, например так:
_G.player.hit(5); _G.player.hit(5);
Объекты могут быть "вложенными", т.е. вы можете создавать и такие конструкции:
_G.player = OBJECT(); _G.player.health = OBJECT(); _G.player.health.current = 10; _G.player.health.max = 10; ...
В случае, когда доступ к каким-то переменным, хрянящимся в _G (не относится к _L т.к. он "регулярно чистится"!) вы планируете обращаться часто, например, к тому же _G.player имеет смысл сделать более короткий путь к этой переменной вот таким образом:
var player = _G.player;
при этом, имя новой переменной может быть любым. Можно даже вот так:
var player_health = _G.player.health;
При этом важно помнить, что полученная переменная и переменная всё-ещё хранящаяся в _G являются одним и темже. Поэтому скрипт:
_G.text = 'test'; var myvar = _G.text; myvar.text = 'new test'; alert(_G.text);
Выведет на экран сообщение с текстом "new test"
Логические конструкции языка не имеют отношения к ЯТК, но заслуживают внимания для того, чтобы ваши скрипты были функциональнее. Конструкция условия if имеет следующий вид:
if (условие)
{
блок выполняющийся если условие выполнено ("правда")
}
else // не обязательная часть
{
блок выполняющийся если условие НЕ выполнено ("ложь")
}
примеры:
1.
if (_G['text'] == 'test')
{
alert('ok!');
}
2.
if (_G.player.health > 0)
{
alert('ok!');
}
else
{
alert('player died!');
}
Цикл это конструкция, которая позволяет повторное выполнение инструкций, обычно для контролируемого числа раз.
for (Начальное значение; условие; Инструкция обновления)
{
инструкции
}
Пример:
for (_G.i = 0; _G.i < 5; _G.i++)
{
alert('Номер: ' + _G.i);
}
Дополнительно с управляющими конструкциями языка можно познакомиться здесь.
2. API-функции ЯТК
Здесь и далее поразумевается, что:
- Параграф
- Локация в игре описанная текстовой формой
- Действие
- Один из вариантов выбора игроком ведущий на другой параграф. Подразумевается, что действие - это блок созданный в книге конструкцией вида div id="action"...
- function addText(text)
-
Добавить текст text к тексту параграфа. Текст может быть html-отформатирован, но в Internet Explorer замечен глюк с добавлением тэга <p>:
// НЕ РАБОТАЕТ!!! addText('<p>Какойто текст</p>'); // работает addText('<' + 'p>Какойто текст</' + 'p>'); // работает addText('<span>Какойто текст</span>');
- function setText(text)
- Заменить текст параграфа на содержимое text. Текст может быть html-отформатирован.
- function addAction(text, action, evaltext, visible, style)
- Добавить новое действие к списку действий параграфа
- function showAction(n)
- Показать действие номер n
- function hideAction(n)
- Спрятать действие номер n
- function showAllActions()
- Показать все действия
- function hideAllActions()
- Спрятать все действия
- function showArticle(n)
- Перейти на параграф n, причем n - всегда строка. Если необходимо перейти на параграф "по цифре", используйте goto_str()
- function get_url(text, action)
- Возвращает строку с html-кодом ссылки, выполняющей скрипт action и текстом text, где action должен быть строкой
- function goto_str(p1, p2)
-
Сформировать строку вида "p1_p2", где p2 - не обязателен, тогда результат будет - строка "p1"
Может пригодиться при написании скриптов вложенных друг-в-друга, например:
... onclick="addText('<a href=\'#\' onclick=\'showArticle(goto_str(5, 2));\'>Перейти</a>')" ...
- function rnd(min, max)
- Вернуть случайное число от min до max
- function customDice(dice, count, mod1, mod2, res)
-
Кинуть count кубиков с dice количеством граней (подразумевается, что на гранях числа от 1 до dice), к каждому результату прибавить mod1, к сумме прибавить mod2, вернуть сумму
Если при вызове передать массив последним параметром, ф-ия сохранит в этот массив результаты каждого броска
_G.result = customDice(6, 2); // кинуть 2d6 без модификаторов
3. Описание дополнительных ЯТК-модулей (плагинов)
3.1 Инвентарь
3.1.1 Объект инвентаря
- INVENTORY()
-
Создать новый объект инвентаря
_G.inventory = INVENTORY();
методы объекта инвентаря:
- .isItem(name)
- Проверка наличия в инвентаре предмета с названием name. Если предмет будет найден, результат - его номер, иначе результат -1
- .isItemCount(name, at_least_count)
- Проверка наличия в инвентаре at_least_count штук предметов с названием name. Если нужное кол-во будет найдено, результат true, иначе false
- .getItem(name)
- Найти и "вернуть" предмет с названием name. Если предмет не найден, результат - null.
- .addItem(name, cnt, func)
- Создать и добавить в инвентарь предмет с названием name, количеством cnt (func - функция использования предмета, см. описание объекта ITEM)
- .removeItem(name, cnt)
- Убрать из инвентаря cnt штук предмета с названием name
- .on_update
-
Если задать этот callback, то он будет вызываться каждый раз при изменении содержимого инвентаря: при использовании методов .addItem и .removeItem
_G.inventory.on_update = function() { Alert('Инвентарь только-что изменился!'); } _G.inventory.addItem('предмет', 2);
- .removeItemByNum(n, cnt)
- Забрать cnt штук предметов номер n из инвентаря
- .getListAsHTML(delim, show_count)
- Получить список содержимого инвентаря в виде строки. При формировании списка, используется символ-разделитель delim (если не указно - строка "<br>"), а если show_count равен true, то отображается и кол-во каждого предмета.
3.1.2 Класс предмета ITEM
- ITEM(name, count, func)
-
Создать новый объект предмета
_L.new_item = ITEM('новый предмет', 2);
свойства объекта предмета:
- .name
- Название (обязательно)
- .count
- Кол-во предметов, если при создании не указано равно 1
- .on_use
- Ф-ия которая хранится вместе с предметом, например, в ней можно реализовать скрипт отрабатывающий "использование" предмета (не обязательно)
3.1.3 Комплексный пример
<div class="onload">
_G.inventory = INVENTORY();
_L.new_item = ITEM('весчь');
_G.inventory.add(new_item);
_L.new_item.cnt = 2; // изменяем кол-во предметов "весчь" прямо в инвентаре(!) (new_item "смотрит" на этот предмет!)
_G.inventory.addItem('большая штука', 1, function()
{
alert('Вы только что заюзали бАльшую штуку!');
});
_G.inventory.on_update = function()
{
alert('Содержимое инвентаря: ' + _G.inventory.getAsHTML(', ', true);
}
_G.inventory.add(ITEM('ещё одна весчь', 2));
alert('Предмет "большая штука" имеет в инвентаре номер ' + _G.inventory.isItem('большая штука'));
_G.inventory.getItem('большая штука').on_use(); // используем предмет
</div>
3.2 Изображение к параграфу
Самодостаточный плагин - не требует управления со стороны автора игры, но для правильной работы, необходима некоторая настройка:
- jsIQ.article_img_div
- HTML-элемент (обычно div) в который будет загружаться изображение
- jsIQ.article_default_img
- HTML-код который будет отображён, если к параграфу не указано изображение
<div class="preload">
jsIQ.article_img_div = $('#image'); // говорим, что отображать картинку в элементе с id="image"
jsIQ.article_default_img = '<b>нет картинки!</b>';
</div>
<div class="img">data/1.jpg</div>
3.3 Диалоговые окна
После подключения плагина, для отображения окна, его сначала необходимо создать:
- jsIQ.dialogs.add(eid, params)
- Ищет элемент с id=eid и инициализирует его с параметрами params
- jsIQ.dialogs.show(eid)
- Отображает диалоговое окно с содержимым элемента с id=eid
- jsIQ.dialogs.hide(eid)
- Закрывает диалоговое окно с содержимым элемента с id=eid
- DIALOG_INIT(eid, params)
- Тоже самое что jsIQ.dialogs.add(eid, params)
- DIALOG_SHOW(eid)
- Тоже самое что jsIQ.dialogs.show(eid)
- Пример
-
... <div id="myWindow" class="myWindowClass">Тут пусто, но это же всего пример! :)</div> ... <div id="book" ...> ... <div class="onload"> jsIQ.dialogs.add('#myWindow', {addClose:true}):: jsIQ.dialogs.show('#myWindow'); </div> ... </div>
(для правильного отображения окна, необходимо добавить описание класса myWindowClass в файл dialogs.css по аналогии с другими окнами)
3.4 FLV видео плеер
- jsIQ.video.play(link)
- Воспроизвести видеофайл link
- jsIQ.video.close()
- Удалить плеер со страницы
4. Функции работы с элементами страницы
- is_valid(v)
- Возвращает true если v не null и не undefined
- get_value(id)
- Возвращает значение элемента с id раным id (простите за каламбур). Под значением подразумевается value элементов типа input
- set_value(id, val)
- Устанавливает значение элемента с id в val. Под значением подразумевается value элементов типа input
- make_unclickable(elem)
- Делает гиперссылку неактивной, заодно меняя ей стиль для обозначения того, что она более не активна
- get_element(id)
- Получить указатель на элемент id
5. Расширенный функционал
- jsIQ.createActionEx(text, action, evaltext, visible, style)
- Создать новое действие
- setActionVisible(n, value)
- Установить видимость действия номер n в значение value (true/false)
- sys_msg(msg, level)
- Сохранить в системный лог jsIQ сообщение msg. level - не обязательный параметр обозначающий уровень ошибки, где 1 - ошибка, 2 - предупреждение, 3 - уведомление. jsIQ фильтрует поступающие сообщения по уровню сообщения.
