Автоматизация (скрипты) - ihsoft/TimberbornMods GitHub Wiki

ЭТО ЧЕРНОВИК! Загляните позже, чтобы увидеть финальную версию документа.

Начиная с версии 2.0.0, мод поддерживает новый формат правил: скрипты. То есть, вы можете задавать условия и действия через простой скриптовый язык. Причем эти действия можно менять прямо во время игры!

Основные концепции скриптового подхода

  • Существуют "сигналы", которые представляют собой строковые или числовые значения. Они в основном используются в условиях, но также могут применяться как параметры значений в действиях. Когда что-то происходит во вселенной Timberborn, сигнал может сработать. Если для него задано условие — оно будет обработано, и тогда выполнится действие (если условие возвращает true).

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

  • Действия всегда привязаны к определенному зданию. Они выполняются только на том здании, к которому относится правило. Разные здания могут иметь разные действия. Например, шлюз может иметь действие SetHeight, но оно не будет иметь смысла для склада.

  • Условия, зависящие от сигнала, проверяются только при изменении значения сигнала. Например, сигнал сезона погоды сработает только при его изменении. Условия, основанные на нем, не будут проверяться пока изменение не случится!

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

image

При ручном создании скриптов необходимо понимать, для какого здания они предназначены и поддерживает ли оно необходимые условия и действия. Иначе скрипт не скомпилируется.

Синтаксис скрипта

Скрипт следует конвенции синтаксиса языка Lisp. Как условие, так и действие являются операторами:

  • Условие должно быть логическим оператором.
  • Действие должно быть оператором act.

Операторы

Оператор записывается как (<ИмяОператора> арг1 арг2 ...). Количество аргументов зависит от конкретного оператора. Также есть ограничения на допустимые значения аргументов. Иногда в качестве значения может быть другой оператор, но бывает, что требуется только константа. Ознакомьтесь с руководством ниже, чтобы узнать, какие операторы что поддерживают.

Аргументы могут быть:

  • Строковой константой. Текст обязательно заключать в одинарные кавычки. Например: 'MapleSyrup'.
  • Числом. Все числа в скриптах — это вещественные числа с фиксированной точностью до двух знаков. То есть, значение 1.50 записывается как 150. А значение 1.555 нельзя записать напрямую — нужно округлить его до 1.56. Примеры:
    • Значение скрипта 100 означает 1 в игре.
    • Значение скрипта 123 означает 1.23 в игре.
    • Значение скрипта 1234 означает 12.30 в игре.
  • Сигналом. Сигнал возвращает строку или число. Его можно использовать везде, кроме случаев, когда требуется константа.

Логические операторы

Это набор операторов для проверки условий.

Бинарные операторы

Как следует из названия, у них всегда ровно два аргумента. Допустимы любые значения, но важно, чтобы хотя бы один из них был сигналом. Иначе условие никогда не будет вызвано: нет сигнала — нет возможности отреагировать на изменение.

Бинарные операторы принимают аргументы числовых значений и возвращают логический результат.

Доступные бинарные операторы:

  • eq — "равно".
  • ne — "не равно".
  • gt — "больше чем". Только для чисел.
  • ge — "больше или равно". Только для чисел.
  • lt — "меньше чем". Только для чисел.
  • le — "меньше или равно". Только для чисел.

Примеры:

  • (eq (sig Wather.Season) 'drought') — корректное условие, которое вернет true, когда сезон погоды сменится на Засуху.
  • (eq 'drought' (sig Wather.Season)) — то же самое, тоже корректно.
  • (eq 'drought' 'drought') — синтаксически верно, но... ошибочно! Такое выражение не подойдет для условий, так как не содержит в себе сигнал. Однако будет работать в препроцессоре (всегда возвращает true).
  • (eq (sig Wather.Season) (sig Wather.Season)) — абсурдный пример который всегда возвращает true, но он иллюстрирует собой, что второе значение не обязано быть константой.

Булевы операторы

Поддерживаются только два: and (И) и or (ИЛИ). Эти операторы принимают любое количество аргументов, но не менее двух. Каждый аргумент должен быть логическим оператором.

  • (and арг1 арг2 ...)
  • (or арг1 арг2 ...)

Примеры:

  • (and (eq ...) (eq ...) (eq ...)) — три условия, проверяются как <arg1> И <arg2> И <arg3>.
  • (and (eq ...) (or (eq ...) (eq ...))) — три условия, в виде <arg1> И (<arg2> ИЛИ <arg3>).

Математические операторы

Эти операторы принимают и возвращают только числа.

  • (add arg1 arg2) — сложение.
  • (sub arg1 arg2) — вычитание.
  • (mul arg1 arg2) — умножение.
  • (div arg1 arg2) — деление.
  • (min arg1 arg2 ...) — минимальное значение из набора.
  • (max arg1 arg2 ...) — максимальное значение из набора.
  • (round arg1) — округляет до ближайшего целого. Например, (round (sub 100 40)) вернёт 100 (1.0f).

Примеры:

  • (round (sub 100 40))1.0f - 0.4f = 0.6f, округляется до 1.0f, результат: 100.
  • (min 0 (sub 0 100) 200)min(0, -1.0f, 2.0f) = 0.
  • (div 1 0) — это ошибка выполнения скрипта: деление на ноль. Игра не упадет, но правило отключится и больше не будет исполняться.

Сигналы

Оператор сигнала: (sig <ИмяСигнала> арг1 арг2 ...). Сейчас нет сигналов с аргументами, но они могут появиться позже. Сигналы возвращают либо число, либо строку. Один и тот же сигнал не может возвращать и то, и другое одновременно.

  • Weather.Season — возвращает текущий сезон как строку: "drought" (Засуха), "badtide" (Плохая вода), "temperate" (Хорошая погода).
  • Inventory.InputGood.<good_id> — возвращает количество ресурса во входном инвентаре здания. <good_id> указывает, какой ресурс проверяется.
  • Inventory.OutputGood.<good_id> — возвращает количество продукции в выходном инвентаре.
  • District.Bots — количество ботов в районе, к которому подключено здание. Если здание не подключено ни к какому району — результат 0.
  • District.Beavers — количество бобров (взрослых и детенышей) в районе. Если здание не подключено ни к какому району — результат 0.
  • District.NumberOfBeds — количество спальных мест (кроватей) для бобров в районе. Без подключения — 0.

Примеры использования:

  • (eq (sig Weather.Season) 'drought') — срабатывает при смене сезона на Засуху.
  • (gt (sig Inventory.InputGood.Planks) 10000) — срабатывает, если в инвентаре более 100 досок (10000 = 100 в игре).

Действия

Оператор действия изменяет состояние здания. Синтаксис: (act <ИмяДействия> арг1 арг2 ...). Некоторые действия требуют аргументы, но в основном - нет. Если аргумент требуется, то он может быть как константой, так и сигналом. Здание должно иметь компонент, который обеспечивает исполнение действия. Если это не так - компиляция завершится ошибкой.

  • Debug.LogStr — принимает один строковый аргумент. Эта строка записывается в лог. Например: (act Debug.LogStr 'Hello!').
  • Debug.LogNum — то же, что и выше, но аргумент - это число. Например: (act Debug.LogNum 123) напечатает в журнал число 1.23.
  • Pausable.Pause / Pausable.Unpause — ставит здание на паузу или снимает с неё.
  • Inventory.StartEmptying / Inventory.StopEmptying — включает или выключает режим "очистки" склада. Используется в основном для хранилищ, но может применяться и к другим зданиям.
    • Будьте осторожны! В этом режиме рабочие выносят все ресурсы из здания, даже если это ингредиенты для рецепта.
  • Floodgate.SetHeight — устанавливает высоту шлюза. Игра корректно обрабатывает граничные значения, но мод показывает значения "как есть". Чтобы избежать "странных" значений в интерфейсе, используйте функции min/max.

Примеры использования:

  • (act Floodgate.SetHeight 100) — устанавливает высоту шлюза в 1.
  • (act Floodgate.SetHeight (sig Signals.MyCustomSignal)) — устанавливает высоту шлюза в соответствии со значением пользовательского сигнала MyCustomSignal.
    • Пользовательские сигналы ещё не реализованы по состоянию на 09.03.2025.

ВНИМАНИЕ!. Если вы используете значение сигнала как аргумент, помните: действие связано с условием. Без срабатывания условия действие не выполнится. То есть, если вы хотите, чтобы действие выполнялось при изменении сигнала, он должен быть частью условия.

Операторы доступа

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

  • (getnum ComponentName.PropertyName) — возвращает числовое значение свойства. Поддерживаются типы: int, float, bool. Для bool: true = 100, false = 0. Если тип другой, то это приведёт к ошибке.
  • (getstr ComponentName.PropertyName) — возвращает строковое значение свойства. Если тип другой, то это приведёт к ошибке.

При доступе к коллекциям, данный оператор имеет расширенный синтаксис:

  • (getnum ComponentName.ListPropertyName) — возвращает количество элементов в коллекции.
  • (getnum ComponentName.ListPropertyName 2) — возвращает 3-й элемент коллекции (индексация с нуля). Если элементов меньше, то это приведёт к ошибке.

В отличие от сигналов, операторы доступа НЕ отслеживают изменения значений. Они не смогут исполнить правило если значение изменится.

Препроцессор

Скрипты могут содержать выражения, исполняемые при компиляции. Результат исполнения таких выражений заменяет их текст. Затем выражение компилируется как обычно. Это имеет смысл только в шаблонах — препроцессор срабатывает при применении шаблона к зданию.

Пример: (act Floodgate.SetHeight {% (getnum Floodgate.MaxHeight) %}) превратится в (act Floodgate.SetHeight 2), если максимальная высота шлюза высота равна 2.

Также препроцессор может обрабатывать логические выражения. В этом случае, выражение должно вернуть значение true. Если результат исполнения оказался false, то возникает ошибка компиляции, и шаблон не применяется. Пример: {% (ge (getnum Floodgate.MaxHeight) 2) %}(act Floodgate.SetHeight 2) не сработает на шлюзах с высотой < 2.

⚠️ **GitHub.com Fallback** ⚠️