Автоматизация (скрипты) - ihsoft/TimberbornMods GitHub Wiki
ЭТО ЧЕРНОВИК! Загляните позже, чтобы увидеть финальную версию документа.
Начиная с версии 2.0.0
, мод поддерживает новый формат правил: скрипты. То есть, вы можете задавать условия и действия через простой скриптовый язык. Причем эти действия можно менять прямо во время игры!
-
Существуют "сигналы", которые представляют собой строковые или числовые значения. Они в основном используются в условиях, но также могут применяться как параметры значений в действиях. Когда что-то происходит во вселенной Timberborn, сигнал может сработать. Если для него задано условие — оно будет обработано, и тогда выполнится действие (если условие возвращает
true
). -
Сигналы могут быть глобальными (например, смена сезона погоды), привязанными к определенному зданию (например, изменения в инвентаре склада) или ограниченными уровнем района (например, изменения в численности населения в районе).
-
Действия всегда привязаны к определенному зданию. Они выполняются только на том здании, к которому относится правило. Разные здания могут иметь разные действия. Например, шлюз может иметь действие
SetHeight
, но оно не будет иметь смысла для склада. -
Условия, зависящие от сигнала, проверяются только при изменении значения сигнала. Например, сигнал сезона погоды сработает только при его изменении. Условия, основанные на нем, не будут проверяться пока изменение не случится!
Вы можете добавлять свои скрипты через новое диалоговое окно редактора правил. Простые скрипты можно создать через визуальный конструктор, но для сложных условий необходимо писать их вручную.
При ручном создании скриптов необходимо понимать, для какого здания они предназначены и поддерживает ли оно необходимые условия и действия. Иначе скрипт не скомпилируется.
Скрипт следует конвенции синтаксиса языка 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.