Lua scripting

Материал из Dwarf Fortress Wiki
(перенаправлено с «Lua»)
Перейти к навигацииПерейти к поиску

Эта статья посвящена процедурной генерации сырых данных. Информацию о скриптах Utility:DFHack можно найти по адресу https://docs.dfhack.org/en/stable/.

Lua-скрипты — это один из инструментов моддинга Dwarf Fortress. Они используются для записи определений процедурно генерируемых объектов и со временем станут основой для будущих магических обновлений. [1]

Подержка Lua-скриптов была добавлена в качестве экспериментальной функции в версии 51.06 и полностью включена в игру версии 52.01.

Неорганические материалы, языки, существа, взаимодействия, предметы (в настоящее время за исключением музыкальных инструментов), реакции, сообщества и растения доступны для этой системы.

Скрипты загружаются из файла scripts/init.lua мода и могут require() требовать другие файлы.

Видео

Видео-анонс:

Уроки:

Структура

На данный момент работа скриптов на Lua ограничено генерацией процедурных объектов. Это осуществляется с помощью функции generate() — глобальной функции, загружаемой в data/init/generators.lua. Она запускает модульные тесты, предварительную обработку, do_once (или do_once_early), материалы, предметы, языки, существа, взаимодействия, сущности и постобработку — именно в таком порядке.

При первой генерации случайных объектов игра заполняет две глобальные таблицы: world и random_object_parameters.

  • world содержит информацию о мире, который в данный момент генерируется. Она содержит параметры генерации мира, определения raw-объектов и несколько других полей.
  • random_object_parameters содержит то, что игра ожидает сгенерировать в текущем вызове генерации.

Вы можете вывести содержимое этих таблиц в лог, чтобы увидеть доступные данные. Мод Runtime Dataminer включает скрипт для чтения этих таблиц.

У DFHack также есть версия df.world, хотя эти таблицы не обязательно эквивалентны. Заголовки и пути могут различаться, даже если они ссылаются на одни и те же данные.

Отладка

Вы можете задать глобальную переменную debug_level для вывода отладочной информации. Это число, но его значения совершенно арбитрарно. Если оно >0, будут запускаться модульные тесты; если >=0.5, на каждом этапе генерации будет отображаться текущий этап. Вы можете использовать get_debug_logger(x) для возврата функции, которая записывает данные в lualog.txt, если debug_level не ниже x.

Модульные тесты — это функции, возвращающие таблицу, содержащую значение good, и если оно истинно, тест считается пройденным, и info — строку с информацией о прохождении или провале теста. Эти модульные тесты не должны иметь побочных эффектов, то есть не должны влиять на глобальное состояние. Вот пример модульного теста, добавленного по умолчанию:

Генерация объектов

При вызове generate() переменная random_object_parameters определяет, что именно будет сгенерировано.

Перед генерацией карты мира переменная random_object_parameters.pre_gen_randoms имеет значение true на одну генерацию. После завершения создания карты переменная random_object_parameters.main_world_randoms имеет значение true на одну генерацию при "генерации предыстории"; большая часть начальной рандомизации происходит именно здесь. Дальнейшие вызовы генерации, например, для создания экспериментов, не устанавливают эти переменные в значение true.

Если вы регистрируете совершенно новый тип процедурного объекта, вы можете сгенерировать его на этих этапах. Игра включает в себя ряд таблиц, в которые можно добавлять функции; игра запускает каждую из них при генерации raw-данных.

  • do_once запускается только в вызове random_object_parameters.main_world_randoms и является наиболее безопасным вариантом для добавления новых объектов.
  • do_once_early запускается в вызове random_object_parameters.pre_gen_randoms и может использоваться для объектов, которые необходимо разместить на карте, например, минералов или популяций животных на поверхности.
  • preprocess запускается перед любой из первых таблиц, но запускается во время каждого вызова generate(), и невозможно предсказать, когда это произойдет.
  • postprocess запускается в конце каждого вызова generate(), после завершения остальных шагов.

Примеры регистрации объектов с помощью этих шагов можно найти на странице Lua script examples.

Если вы хотите использовать preprocess или postprocess для генерации raw-объектов, вы можете проверить правильность выбранного этапа генерации, прочитав вышеупомянутый random_object_parameters. Пример "Адамантиновые сплавы" включает такую проверку.

Вы также можете экспериментировать с random_object_parameters в препроцессинге. Здесь назначаются типы демонов из обычной игры, и вы можете изменить пропорции, если хотите.

Генерация из списка

После preprocess и do_once игра генерирует все отдельные объекты, ожидаемые random_object_parameters. Общая процедура заключается в том, что игра вызывает функцию generate_from_list() для таблицы функций, которая вызывает каждую функцию и выбирает одно из полученных значений случайным образом в зависимости от их весов.

Например, таблица interactions.secrets содержит одну запись для некромантов; она возвращает таблицу из трёх записей: {raws=tbl,weight=1,spheres=spheres}.

  • raws — это полный raw-текст взаимодействия.
  • weight — это случайный вес взаимодействия, т.е. если добавить ещё одну функцию, возвращающую таблицу, содержащую weight=2, вероятность такого взаимодействия будет вдвое выше, чем у некромантов.
  • spheres — это дополнительные данные, которые может использовать генератор. На самом деле, на данный момент это не так, но можно переопределить generate_random_interactions() собственной версией, которая учитывает spheres и, например, пытается равномерно распределить сгенерированные секреты по доступным сферам. (Это не вошло в обычную игру, в первую очередь из-за опасений возникновения ошибок).

Языки

Однако языки — это нечто особенное; как видно из Divine language/script или языка идентичности. Таблица languages просто ожидает возврата таблицы с переводами, например, tbl["ABBEY"]="abbey". Если вы хотите процедурно добавлять слова или символы (и да, оба варианта реализуемы), вы можете сделать это с помощью raws.register_languages() в другой таблице функций.

Существа

Существа обладают гораздо большей специфичностью, чем другие процедурные объекты. Забытые твари в некотором смысле самые простые из них:

Сначала создаётся таблица options; можно создать полный список опций, используемых в игре, но другие моды также могут использовать вполне произвольные опции. Затем добавляются все обычные токены special-to-forgotten-beast в большую строку, после чего вызываеся add_regular_tokens(tbl,options), что добавляет некоторые вещи, общие для всех (ванильных) процедурных существ, на основе предоставленных опций.

Также добавляется do_water и сфера WATER, если тварь находится в водной пещере, опция, которая добавляет в белый список определённые случайные профили существ, а также случайную злую сферу.

populate_sphere_info() аналогична add_regular_tokens(); она добавляет все сферы из options.spheres к существу, используя токен [SPHERE], а затем, если заданы определённые параметры, выполняет дополнительные действия.

Затем выбирается случайный профиль существа с помощью get_random_creature_profile() и параметров, используется add_body_size() для установки токенов [BODY_SIZE] и сопутствующих параметров, задаётся тайл существа и, наконец, запускается большая функция build_procgen_creature(), которая создаёт описание, тело, ткани и так далее.

Случайные профили существ

Основная статья: Random creature profile

Случайный профиль существа — это шаблон, которые определяет в первую очередь форму тела для процедурного существа. Например:

Из этого кода только cannot_have_get_more_legs является необязательным. build_procgen_creature() имеет прямой доступ к профилю в качестве первого аргумента, поэтому дополнительные записи в таблице можно использовать по своему усмотрению.

body_base указывает на ключ в body_base_fun, который используется для настройки параметров существа (ходьба и слой процедурной графики задаются таким образом) и возвращает список токенов тела. Четвероногие используют специальную функцию для изменения спрайта, поэтому вот базовая функция тела для обычного гуманоида:

c_class также относится к другому классу, который определяет тип слоёв тканей существа. "FLESHY", "MAMMAL", "CHITIN_EXO" и т. д. подразумевают биологическое существо с сухожилиями, кровью, различными органами, нервами и так далее. "UNIFORM" описывает существо, состоящее из одного материала, выбор которого зависит от его параметров. Таблицы random_creature_class и random_creature_material хранят информацию об этих характеристиках.

Органических существ можно модифицировать, изменяя их внешний вид, например, делая их безкожими, волосатыми или даже однородными по материалу.

Твики

В самом широком смысле, твики (tweaks) — это любое отклонение от профиля существа. Вышеупомянутые изменения внешнего вида, новые части тела и взаимодействия при атаке — всё это примеры изменений.

Ряд опций изменяют доступные твики или принудительно вызывают их, например:

  • options.no_tweak отключает случайные твики.
  • options.strong_attack_tweak позволяет существу всегда выбирать из таблицы attack_tweaks; например: "Beware its webs!"
  • options.humanoidable_only делает существо "искажённым до гуманоидной формы" (если оно злое) или "<существом> в гуманоидной форме" (в противном случае).

Одним из возможных вариантов использования btc1_tweaks (см. Lua functions#Патчинг существ) является добавление пользовательских кандидатов на твик, указывая на ключи в tweaks.

Выбор цвета

Функции выбора цвета (color pickers) могут предоставлять более подходящие варианты цветов на основе параметров, вместо полностью случайного спектра по умолчанию. Существуют функции выбора цвета для некоторых злых сфер, придающие им тёмный вид. Оборотни имеют специальный флаг, чтобы получать только натуральные коричневые или чёрные цвета.

Если существо соответствует условию cond и заданный дескриптор цвета соответствует color, то оно добавляется в список кандидатов. Цвета имеют значения h, s, v (цветовой тон, насыщенность и значение) и r, g, b (красный, зелёный и синий) в диапазоне от 0 до 1 (за исключением цветового тона, который находится в диапазоне от 0 до 360 градусов).

options.blood_color работает как функция выбора цвета. Если какой-либо цвет соответствует её функции, то кровь будет окрашена в один из них. Например, у бугименов и кошмаров есть функция, которая даёт им пурпурный цвет крови, но вы можете создать свои собственные функции цвета крови.

Существа с другими типами крови, например, ихором, не подвержены этому эффекту.