- •Скрипты Морровинда для чайников
- •Предисловие к восьмому изданию
- •Вступление Как использовать это руководство.
- •Что такое скрипт?
- •Что могут скрипты?
- •Чего не могут скрипты:
- •Обучающий курс
- •Поехали!
- •Окно редактора скриптов
- •Чего мы хотим?
- •Написание скрипта
- •Имя для скрипта: Begin и End
- •Обнаружение действий игрока
- •Вывод текста и получение решений игрока
- •Как выполняются локальные скрипты
- •Ваш первый баг
- •Наложение заклинания на игрока
- •Как узнать больше?
- •Синтаксис
- •Начало и завершение скриптов
- •Общий синтаксис функций:
- •Общий синтаксис: запятые, скобки и пробелы.
- •Комментарии
- •Отступы / использование табуляторов
- •Переменные Типы переменных
- •Локальные переменные
- •Глобальные переменные
- •Использование переменных в других локальных скриптах и объектах
- •Использование переменных в функциях
- •Операторы / математические расчеты
- •Проверка условий Использование условий if… elseif
- •Условия While
- •Создание булевых операторов в скриптах tes
- •Список функций tes Объяснение формата
- •Работа с объектами Работа с вещами в инвентаре Добавление и удаление вещей из инвентаря
- •Сброс предмета на пол
- •Отслеживание активности инвентаря: Добавление, сброс и использование камней душ
- •Надевание предметов
- •Отслеживание, был ли надет предмет
- •Выключение возможности надеть предмет
- •Проверка присутствия предметов в инвентаре
- •Починка предметов
- •Информация о надетых объектах
- •Функция UsedOnMe
- •Движение и создание объектов
- •Движение вдоль оси объекта
- •Движение вдоль оси мира
- •Установка позиции (другой путь, чтобы сгенерировать движение)
- •Позиционирование объектов в мире или во внутренних ячейках
- •Перемещение объекта в его оригинальную позицию
- •Помещение предмета рядом с игроком
- •Создание предметов рядом с объектом
- •Создание копий объектов с помощью PlaceItem
- •Вращение и углы
- •Вращение объектов
- •Установка углов
- •Функции размеров
- •Определения локации, относительного положения и движения Определение нахождения игрока в интерьере или в экстерьере
- •Определения ячейки игрока
- •Расстояние от одного объекта до другого
- •Определяем позицию и поворот объекта
- •Линия видимости
- •Определяем, замечен ли один актер другим
- •Определяем, когда игрок покинул ячейку
- •Определяем, путешествует ли игрок
- •Триггеры для актеров, стоящих на объектах
- •Повреждение актера, стоящего на объекте
- •Функции сталкивания объектов
- •Проверка активации предмета и его активация
- •Запирание и отпирание дверей или сундуков
- •Анимирование объектов
- •Доступные и недоступные объекты
- •Полное удаление копии
- •Не сохранять изменений объекта
- •Скрипты для npc: ии и движение npc идет в новую локацию
- •Проверка, завершил ли npc свое движение
- •Поворачиваем актера в нужном направлении
- •Задание случайного перемещения Актера
- •Актеры активируют объекты
- •Следование и эскорт
- •Определение текущего пакета ии
- •Заставляем актера красться
- •Заставляем актера бегать и прыгать: Движения в Трибунале
- •Проверка действий игрока: бежит, прыгает, крадется?
- •Определение готовности к бою
- •Заставляем кого-то падать
- •Доля в экипировке и другие функции компаньонов
- •Раса, Фракция и Ранг Определение расы
- •Определение статуса игрока во фракции
- •Изменение реакции и положения во фракции
- •Определение и изменение реакции
- •Функции для оборотней Установка атрибутов оборотня
- •Специальные глобальные переменные для оборотней
- •Текст и Диалог Краткая инструкция по диалогам
- •Концепция диалогов в Морре
- •Как работает диалог
- •Несколько золотых правил
- •Диалог 101
- •Функции для диалогов
- •Показ сообщений
- •Показ переменных и предопределенного текста в окне сообщения
- •Пример: Дурацкий простой скрипт, демонстрирующий весь возможный синтаксис:
- •Добавление темы для диалога
- •Начало и окончание диалога
- •Инициация диалога с оборотнем (Bloodmoon)
- •Множественный выбор – как задавать вопросы
- •Добавление записей в журнал и тест записей журнала
- •Специальные диалоговые функции
- •Изменение значения Hello
- •Полезные диалоговые переменные
- •Изменяем и проверяем Навыки, Атрибуты и другие характеристики Get, Set, and Mod Stats – общие замечания
- •Определение и изменение характеристик игрока и актеров: Определение и изменение атрибутов:
- •Определение и изменение Здоровья, Магии и Усталости:
- •Определяем и изменяем скиллы:
- •Определение и изменение уровня
- •Начало и конец боя
- •Обнаружение атак
- •Функции Get/Mod/Set ии для Боя: Fight, Flee, Alarm
- •Отслеживание убийств и нокаутов
- •Воскрешение мертвого Актера
- •Преступления Определение и изменение уровня преступлений
- •Заключение игрока в тюрьму
- •Очистка игрока от преступлений
- •Уровень преступления игрока
- •Полезные глобальные переменные
- •Магия Ограничение на телепортацию
- •Ограничение левитации
- •Проверка и работа с душами и камнями душ
- •Id камней душ:
- •Добавление и удаление заклинаний и проклятий
- •Кастование заклинаний
- •Управление и тестирование заклинаний
- •Управление и тестирование эффектов заклинаний
- •Тестирование болезней
- •Функции Get/Mod/Set для магии:
- •Звук Пусть актеры говорят
- •Проигрывание музыки
- •Проигрывание звуков
- •Управление звуком
- •Форматы звуковых файлов:
- •Следим за временем
- •Глобальные переменные, зависящие от времени
- •Течение дней
- •Фазы лун
- •Погода Изменение погоды
- •Изменение установок погоды для региона
- •Определение текущей погоды
- •Определение скорости ветра
- •Средства управления игрока Игрок спит
- •Включение и выключение средств управления и интерфейса Отключение средств управления
- •Включение средств управления
- •Проверка статуса средств управления
- •Переключение в вид от первого и от третьего лица
- •Функции для меню генерации персонажа
- •Определение открыл ли игрок меню
- •Использование MenuTest, чтобы открыть и закрыть меню
- •Различные функции и переменные Прерывание выполнения скрипта
- •Управление глобальными скриптами
- •Уменьшение и увеличение яркости
- •Добавление локации на карту
- •Присваивание случайных значений переменным
- •Проигрывание видео
- •Функции Уровневых Списков
- •Квадратный корень
- •Функции уровня воды
- •Советы и трюки Маленькие помощники: поиск, копирование и вставка текста
- •Альтернативные скриптовые редакторы
- •Используйте стиль для написания нормальных скриптов
- •Чистка вашего мода
- •Ограничения редактора скриптов
- •Сохранение процессорного времени
- •Нацеленные скрипты: запуск «глобальных» скриптов, привязанных к объекту
- •Проверяем, когда игрок загружает игру
- •Использование переменной CharGenState – отключение сохранения и меню
- •Обнаружение использования свитков или книг
- •Заставляем Актеров переключать оружие
- •Магические и механические ловушки
- •Скриптовая телепортация
- •Тестируем на присутствие другого мода
- •Безопасный старт глобальных скриптов — избегая скрипт main
- •Использование звука для обнаружения событий
- •Большие сражения
- •Руководство по созданию объектов для езды
- •Выбор объектов
- •Создание/Удаление объектов
- •Падение с объектов
- •Обнаружение столкновений
- •Проблема с сохранением
- •Скрипт по тригонометрии – быстрый синус и косинус
- •Манекены
- •Она на меня смотрит?
- •Кинематическая последовательность
- •Решение проблем Основные советы
- •Консоль Использование консоли для проверки переменных:
- •Использование консоли для быстрой проверки скриптов:
- •Сообщения об ошибках, неправильная работа и обычные причины в игре, когда исполняется скрипт: в редакторе
- •Внутриигровые сообщения:
- •AiTravel не работает
- •Вылет при исполнении скрипта
- •Вылет при загрузке плагина
- •Приложение Новые функции Трибунала
- •Изменения / исправления скриптов Морровинда:
- •Список новых функций Трибунала:
- •Новые функции Бладмуна
- •Список новых функций и переменных Бладмуна:
- •Ранее недокументированные функции
- •Единицы измерения:
- •Список магических эффектов
- •Список консольных команд
- •Игровые установки
- •Алфавитный указатель
Условия While
While ( condition )
; что-то делать
EndWhile
Команда while отличается от if тем, что она повторяется в течение одного фрейма, пока условие не будет выполнено. Вот хороший пример:
Short desiredAmnt
SetStrength 0
while( GetStrength < desiredAmnt ) ; переменная для совпадения
modStrength 1
endwhile
Это установит значение силы равным значению desiredAmnt за один фрейм. Следующий скрипт сделает это за неизвестное количество фреймов, потому что скрипт вызывается каждый фрейм:
if(getStrength < desiredAmnt) ; переменная для совпадения
modStrength 1
endif
С другой стороны, из-за первого примера компьютер может повиснуть на некоторое время (если значение велико), а из-за второго нет15.
Заметьте, что этим можно обойти некоторые функции, которые не принимают переменные как параметры.
Создание булевых операторов в скриптах tes
К сожалению, нет булевых операторов в скриптах (AND, OR, NOT, XOR, …). Потому вам придется имитировать их условиями if…endif.
Вместо AND:
if ( variable1 AND variable2 ); не существует
[делать что-то]
endif
вам придется использовать:
If ( variable1 )
If ( variable2 )
[делать что-то]
endif
endif
Для кострукции OR:
if
( variable1 OR variable2 ) [делать
что-то] endif
используйте конструкции elseif:
If
( variable1 ) [делай
это] elseif
( variable2 ) [делай
то] endif
Список функций tes Объяснение формата
В начале я буду записывать функцию и аргументы следующим образом:
[no fix] Code "string", arg_enum, var_float, [optional] (returns short)
[no fix] Указывает, что эта функция никогда не используется со стрелкой, то есть не может быть вызвана определенным объектом. Функции без этого префикса могут быть вызваны актером, объектом или теми, и другими.
Code: Имя функции
Аргументы функции: “string” указывает на строку, например ID объекта. arg_enum указывает на явное значение (не переменную). var_float указывает на переменную определенного типа (например, float). Скобки [] указывают на необязательные параметры. (returns short) или (returns float) указывают, что функция возвращает значение и обозначает его тип. Я буду использовать (returns Boolean/short), чтобы указать, что функция возвращает 1 или 0, так как в игре они имеют тип short.
Пример использования приводится курсивом и с отступом:
Code "ID", var_enum, var_float
Примеры скриптов заключены в рамку:
Begin script
[функции скрипта]
End script
С 8-ой редакции функции из Трибунала и Бладмуна находятся в соответствующих разделах руководства. Они обозначены:
для функций Трибунала
для функций Бладмуна.
Чтобы использовать эти функции нужно установить соответствующее дополнение (но не обязательно его активировать16). Бладмун и (выпуск GOTY) включает все функции и из Трибунала.
Работа с объектами Работа с вещами в инвентаре Добавление и удаление вещей из инвентаря
AddItem, "ObjectID", count_enum
RemoveItem, "ObjectID", count_enum
Actor -> AddItem, "item_ID", 1
Container -> RemoveItem, "itme_ID", 5
Эти функции достаточно просты, они добавляют и удаляют предметы из инвентаря игрока или других инвентарей, включая контейнеры. RemoveItem может удалить объект из инвентаря навсегда, и он исчезнет.
Примечание: Удаление предметов, которые отсутствуют в инвентаре, уменьшит общий вес предметов, даже если их там нет. Так что всегда проверяйте количество предметов в инвентаре, прежде чем будете их удалять. (Спасибо DinkumThinkum за эту инфу)
Не пытайтесь, чтобы предмет удалил сам себя через скрипт – это приведет к вылету (см скрипт-пример.)
Можно использовать отдельный глобальный или локальный скрипт, чтобы удалить такой предмет. Однако, если игрок имеет несколько копий одного предмета с скриптом, то RemoveItem может запороть данные на других объектах (вы это увидите в виде непонятных цифр). Экипировка или использование этого испорченного объекта может привести к вылету игры17 (DinkumThinkum, Информация с форумов)
Чтобы этого избежать:
1. Если объект не имеет скрипта, используйте GetItemCount, чтобы убедиться что игрок имеет хотя бы 1 объект.
2. Если на объекте есть скрипт, используйте GetItemCount, чтобы знать, что у игрока ровно 1 объект, или сделайте объект уникальным.
Функция Drop не имеет этого бага. Однако она может вызвать удвоение, если используется с OnPCEquip / SkipEquip, что может быть устранено добавлением и удалением любого предмета как описано для этих функций.
Использование Additem / Removeitem в диалогах: Эти функции могут принимать глобальные переменные и только в поле результатов диалога, и только если глобальная переменная не была установлена в том же диалоге (Информация с форума / Argent; Согласно нему, максимальное количество, которое ему удалось добавить, равнялось 65534 (используя переменную типа long = 2147483520)). Также убедитесь, что эта переменная не изменяется в этом же диалоге. Например, var_a равняется 3 в момент, когда ответ выбран в диалоге. Если поле результата выглядит так:
set var_a to var_a + 10 ;
AddItem gold_001, var_a
То только три дрейка будут добавлено, а нет 13. Если возникнет необходимость, то все вычисления объедините в одном ответе, добавьте оператор choice, ведущий на следующий ответ, и добавляйте уже там. Также, даже используя переменные типа long, я не смог добавлять предметов больше 32767. (Тестировалось на Морре без дополнений) (Информация с форумов / Kir)
Примечание по использованию контейнеров: Утверждалось, что только первая функция AddItem всегда работает с контейнерами, но после этого, игрок должен вручную получить доступ к сундуку (напр. добавить предмет), прежде чем AddItem будет иметь какой-то эффект (непроверенная информация с форумов). Если вы хотите добавить что-то в контейнер, который был опустошен, единственный способ, похоже, это удалить старый пустой контейнер и добавить новый вместо него (новый будет работать, пока в него что-то не положили, а затем вытащили. После этого его также нужно заменить.) К сожалению, единственный способ убедится, пуст ли контейнер – это узнать, есть ли там каждый предмет в игре (Информация с форумов / ThePal).
Пример:
Следующий скрипт обсуждался на форумах (извините, не помню, кто сделал его первым). Он должен спрашивать игрока, не желает ли он «переработать» предмет, который надет на нем, а затем заменить этот предмет «переработанным».
Begin scr_thing
short button
short OnPcEquip
short state
if ( MenuMode == 1 )
return
endif
if ( OnPCEquip == 1 ) ; когда предмет надет
set state to 1
set OnPCEquip to 0 ; делать это один раз после каждого одевания
endif
if ( state ==1 )
MessageBox "recycle?" , "yes", "no"
set state to 2
elseif ( state == 2 )
set button to GetButtonPressed
if ( button == 0 )
PlaySound "mysticism cast"
player->RemoveItem "item_a", 1 ;эта строка обрушит игру!!!
player->AddItem "item_b", 1
set state to 0
elseif ( button == 1 )
set state to 0 ; все сделано, сбрасываем в ноль
endif
endif
end
Он отлично работает без функции RemoveItem в нем, но с этой строкой игра рушится. Причина в том, что скрипт присоединен к item_a, а так как данный скрипт удалит этот предмет и должен удалить себя самого, игра вылетает. Так что эта идея должна реализовываться посредством глобального скрипта.