Сделать мутатор
Небольшой .oamut поверх основной игры или любого мода: папка, манифест, план, который возвращает mutate, параметры, песочница и порядок применения стека.
Эта глава кратко пересказывает docs/mutators/authoring.md и docs/mutators/oamut-standard.md.
Что такое мутатор
Мутатор — это небольшой пакет .oamut поверх основной игры или любого мода. Он меняет один матч. Библиотека устанавливает его в папку Mutators под id из манифеста, и установка его не включает. Игрок включает его сам для схватки, лобби или кампании. works-with указывает, к каким модам он подходит, а звёздочка означает любой мод и основную игру.
Пакет
В корне папки лежит oamut.yaml. Рядом с ним — входной скрипт: mutator.lua, если entry не называет другой, и никогда не в files/, rules/ или lua/. В lua/ лежит остальной исходный код Lua, и только эти файлы читает require. В files/ лежат байты, которые может добавить слой Files. В rules/ лежат файлы правил с именами на .sm. Значок — это PNG, который называет манифест. Заметка с именем на .md или .txt предназначена для людей, и игра её не загружает. Файл вне этого списка отклоняется. При сравнении регистр букв ASCII не учитывается.
my-mutator.oamutфайл, который получает игрок├─ oamut.yamlобязательно манифест├─ mutator.luaвходной скрипт, mutate(ctx)├─ lua/необязательно. Модули Lua, единственные файлы, которые читает require├─ files/необязательно. Модели, скрипты и другие байты├─ rules/необязательно. Файлы правил .sm├─ icon.pngнеобязательно. PNG, который называет icon└─ README.mdзаметка. Игра её не загружаетМанифест
Строгий YAML по тем же правилам, что и профиль мода: один документ, одно отображение верхнего уровня, без якорей и блочных скаляров. Файл начинается с oamut, равного целому числу 1. Ключ, которого нет в стандарте, отклоняется. Значение, которое начинается со знака «больше», и звёздочку берите в кавычки, иначе парсер примет их за что-то другое. Поэтому requires.engine пишется в кавычках. Версия тоже пишется в кавычках: простое число отклоняется.
| Ключ | Обязательно | Что делает |
|---|---|---|
oamut | да | Формат. Целое число 1. 1.0 и 1 в кавычках отклоняются. |
id | да | Строчные буквы, kebab-case, от 1 до 64 байт. Без дефиса в начале и в конце и без двойного дефиса. Имя папки установки. |
name | да | От 1 до 64 байт, без управляющих символов. Название, которое видят игроки. |
version | да | В кавычках, не больше 32 байт. От одной до трёх частей через точку, каждая — число от 0 до 65535 без ведущего нуля. |
author | да | Отображение. name обязателен, от 1 до 128 байт. email необязателен. |
description | нет | Необязательно, от 1 до 2 000 байт. Перевод строки допустим. Первая строка, обрезанная до 200 байт, — это краткое описание, которое показывает каталог. |
homepage | нет | Необязательно, от 1 до 256 байт. Адрес http или https. |
icon | нет | Необязательно. Путь в пакете к квадратному PNG, оканчивается на .png. Установщик проверяет изображение. |
tags | да | От одного до четырёх id без повторов. Восемь, которые рисует Библиотека, приведены ниже. |
works-with | да | От одного до 32 условий, без повторов id. Звёздочка означает любой мод и основную игру и тогда должна быть единственной записью. ta-3.1c означает основную игру без мода. Любой другой id — это мод, с необязательным диапазоном версий. |
requires | нет | Необязательно. Только engine и mutators. engine — диапазон в кавычках, который сверяется с этой сборкой. mutators называет пакеты, которые должны быть включены. Они применяются раньше этого, в записанном порядке. |
conflicts-with | нет | Необязательно. Мутаторы, рядом с которыми этот отказывается работать. id здесь не может быть одним из тех, что называет requires.mutators, и не может быть id самого мутатора. |
layers | да | От одного до девяти имён без повторов: files, units, weapons, features, sides, tables, menus, maps и hacks. План может писать только в слой, названный здесь. |
clashes | нет | Необязательно, add или replace: что этот мутатор делает с юнитом или оружием, имя которого уже есть в игре. Сначала действует выбор игрока, затем этот ключ, затем настройка mutators.clash-default, которая без значения равна replace. |
options | нет | Необязательно, не больше 16. Настройки, которые игрок выбирает перед матчем. Их читает ctx.options. |
strings | нет | Необязательно, не больше 16 языковых тегов. Переводы названия, описания и подписей параметров. |
entry | нет | Необязательно. Входной скрипт: путь в пакете на .lua, не в files/, rules/ или lua/. Если не указан — mutator.lua. |
legacy | нет | Необязательно, от 1 до 16 записей о мутаторах TA: Mutation, которые заменяет этот пакет. Каждая запись — name, prefix, compatibility и files. Одиночное отображение без списка отклоняется. |
Восемь тегов
Парсер принимает любой тег в kebab-case строчными буквами длиной от 1 до 32 байт, не больше четырёх. Для этих восьми id при точном совпадении Библиотека рисует значок и переведённую подпись. Любой другой id показывается так, как написан, без значка. Если манифест не называет icon, значок пакета берётся у первого тега, когда этот id — один из восьми.
| Ключ | Что делает |
|---|---|
statistics | Характеристики |
economy | Экономика |
commanders | Командиры |
new-units | Новые юниты |
disable | Отключение |
gameplay | Геймплей |
ai | ИИ |
maps | Карты |
План
Входной скрипт определяет mutate. Движок вызывает mutate(ctx) один раз, в фазе плана, и сам этот вызов игру не меняет. mutate возвращает одну таблицу. Пустая таблица ничего не меняет. Ключ, которого движок не знает, отклоняется.
files — это таблица из add и mask. Каждый из них — список строк, и любой можно опустить. add называет папки в пакете по порядку, и если путь есть в обеих, побеждает более поздняя папка. mask скрывает пути. rules — это список готовых блоков, созданных через where, all, named или on и затем :change, а также путей sm, которые указывают на файл .sm. Изменение — это set, scale, lock, remove или append. scale может принимать нижнюю и верхнюю границы, и граница ограничивает только этот один множитель. Хуки — это функции. Они выполняются в таком порядке: units, weapons, features, sides, tables, затем menus. maps выполняется после всех мутаторов и только когда в матче выбрана карта. hacks задаёт на этот один матч параметр, который реестр открывает для мутаторов. Запись в слой разрешает именно его объявление.
Параметры и ctx
Во время mutate в ctx есть мод (его id, версия и игра), версия движка, параметры и ctx.incompatible. Если мод не включён, ctx.mod.id равен ta-3.1c. Вызов ctx.incompatible с причиной останавливает этот мутатор, и причина — это текст, который увидит игрок. Коллекции ещё не загружены. Хук может читать units, weapons, features, sides, tables и menus из ctx без объявления слоя. Для записи слой нужен.
В ctx.options по одному полю на каждый id параметра. Переключатель — true или false. Число, а также выбор, значения которого — числа, дают число. Выбор, значения которого — идентификаторы, даёт текст. Параметр, который игрок не трогал, имеет значение по умолчанию. type — toggle, choice или number. Выбор перечисляет от 2 до 16 значений, только числа или только идентификаторы, а также labels, когда слова отличаются от значений. У числа есть min, max, step и default. Игрок может выбрать только значение от min до max, которое попадает на шаг, поэтому скрипту не нужно снова проверять диапазон: значение вне шага отклоняется до запуска скрипта. id параметра — это имя Lua, и ключевое слово Lua отклоняется.
Песочница
Скрипт выполняется как Lua в одной песочнице. У него нет файлов, сети, часов, окружения и процессов. io, os, debug, package и coroutine не открыты, а предкомпилированный чанк отклоняется. Каждый чанк — исходный код. Два мутатора не делят никакого состояния.
Каждая фаза начинается заново с полного лимита инструкций, 50 000 000, и с полного лимита реального времени, 10 секунд. Предел памяти — 64 МиБ, и для следующей фазы он заново не выдаётся. Одна строка — не больше 65 536 байт. Для характеристики, которую вычисляет скрипт, используйте fixed. Он считает в 65 536-х долях, поэтому один и тот же скрипт пишет один и тот же текст на любой машине. pairs обходит ключи в фиксированном порядке. Результат не зависит от машины.
Стек
Игрок выстраивает мутаторы по порядку, и они применяются сверху вниз. Первый применяется первым. Каждый следующий видит игру такой, какой её оставили те, что выше. Мутаторы, названные в requires.mutators, включаются вместе с этим и применяются раньше него, в том порядке, в котором их записывает этот список. Больше 32 мутаторов, id, указанный дважды, требование, которое не выполняет ни один мутатор выше, или два конфликтующих мутатора — и отклоняется весь список, ничего не запускается.
Сначала накладываются файлы всех мутаторов в порядке списка, и за путь побеждает более поздний мутатор. Затем каждый мутатор в том же порядке читает свои файлы юнитов, оружия и download как записи, применяет свои правила и запускает свои хуки. Правила применяются по одному изменению за раз в фиксированном порядке. Множитель умножает текущее число, а ограничение действует только на этот множитель, а не на последующие. Присваивание заменяет текущее значение. lock задаёт значение и не даёт ни одному последующему мутатору менять это поле. Внутри одного блока Lua изменения выполняются по имени поля после приведения ASCII к нижнему регистру, а не в том порядке, в котором написана таблица. Усреднения между мутаторами нет. Когда применились все мутаторы, число юнита или оружия, выходящее за разрядность, в которой его хранит игра, и число объекта за пределами диапазона, который читает игра, один раз прижимается к краю этого диапазона.