Логика

**Логика** — это способ управления игровыми объектами, который появился в версии игры 6.0. В данный момент существует три вида процессоров: микропроцессор, логический процессор и гипер процессор. Между собой отличаются только своим радиусом действия. С помощью них вы можете контролировать ***блоки*** и ***юнитов***: получать информацию о врагах и союзниках, которые появляются в зоне видимости блока или юнита, заставить юнитов отправиться в нужные координаты и выполнять разные действия: стрелять, перевозить материалы. Для крупных схем из множества процессоров имеется ***ячейка памяти***, которую могут использовать для чтения и хранения данных сразу несколько процессоров, обмениваясь таким образом информацией. Чтобы игрок мог получить результат работы процессора в виде текста (например, о типе вражеского юнита, которого обнаружила турель) используется сообщение, а чтобы не ограничивать фантазию игрока текстом есть два типа ***логических дисплеев***, которые могут отображать графику. Последний элемент логических схем это ***переключатель***, с которым игрок может взаимодействовать кликнув мышкой. Состояние кнопки можно считать или изменить с помощью процессора, что может найти применение в некоторых схемах.

## Программы

**Программы** это основа работы *****логики***** в **Mindustry**. Программа выполняется процессором, и хранится в нем, сохраняется с ним при сохранении ***схемы***. Программы в логике **Mindustry** пишутся на специально созданном ***Anuke*** скриптовом языке ***mlog.*** В **Mindustry** доступно два способа создания программ: визуальный во встроенном редакторе и текстовый, в блокноте. Первый отлично подходит для обучения процессу и позволяет выбирать типы ***блоков***, ***юнитов*** и параметров из списка, получить к нему доступ можно кликнув на процессор, способ подходит для быстрого написания небольших программ. Второй способ позволяет вам написать очень большую, сложную и запутанную программу, не ограничиваясь визуальным интерфейсом процессора, скопировать и вставить в процессор, или поделится ей с другими игроками. Структура программы в **Mindustry** напоминает BASIC или ассемблер, операции выполняются сверху вниз, одна за другой, пока не достигнут конца. Чтобы прерывать и изменять выполнение программы, можно использовать операции условного и безусловного перехода. Как гласит ***официальное руководство*** **Mindustry**, чтобы начать написание своих программ в игре, вам понадобятся некоторые знания программирования, как минимум теоретические, чтобы разобраться в основах языка ***mlog,*** но гораздо важнее, чтобы у вас были "терпение и открытый ум", так как многое может показаться пугающе сложным, пока вы их не попробуете, и потому многое придётся менять и испытывать снова и снова при создании программы.

## Типы данных

В Mindustry есть 4 типа данных: **числа**, **строки**, **здания** и **юниты**.

### Number

Десятичное число. Может быть отрицательным или положительным и может представлять истинные (все, что не равно 0) или ложные (0) значения. Null также представляется как 0.
Некоторые инструкции могут принимать только целые числа, поэтому в данном руководстве они указаны соответствующим образом.
Внутри процессора числа хранятся в виде 64-разрядных значений с плавающей точкой (*`double`*).

### String

Строка, объект, представляющий собой текст, заключенный в кавычки (пример: "hello mindustry").

### Building

Объект, который представляет собой здание в мире.
Building отличается от ***Блока***, **Блок** - это тип данных, включающих все здания, а здание - конкретный блок, он имеет прочность,

```
координаты места расположения, использует энергили  и предметы.<brДругими словами, здание — блок, который в данный момент существует в текущем мире.ре.
Например, инструкция getlink вернет объект Здание, с которым соединен процессор, из этого объекта после можно получить информацию используя sensor.

```

### Unit

Объект, который представляет собой юнит в мире, включая игрока.
Например, инструкция `unitbind` установит переменную процессора `@unit` как объект `Unit`, который будет представлять собой конкретную боевую единицу, привязанную к процессору и управляемую им.

## Параметров

Тип данных, непосредственно описывающие конкретное здание или юнит.

### BuildingType

BuildingType. Начинается с `@`.

 В отличие от предметов и жидкостей, вы не можете использовать это в инструкции `sensor`. Однако вы можете использовать `@type` в `sensor`, и сравнить его используя `jump`.
Пример: `@scatter,` если нужно найти ближайший рассеиватель`.`

### UnitType

UnitType. Начинается с `@`.

Пример: `@toxopid`

Полный список отображается под кнопкой карандаша в блоке инструкций `"Unit Bind"`.

**Sensor**
Предмет, жидкость, ***Здания*** или ***Юниты***, которые могут быть обнаружены с помощью `sensor`. Начинается с `@`.
Примеры: *`@scrap, @slag, @totalAmmo`*

Полный список отображается под кнопкой карандаша в блоке инструкций `"sensor"`.

Сенсор может считать в переменную различные параметры указанного ***здания*** или ***юнита***, например его координаты, здоровье, содержимое.

**Radar**
Признак, по которому можно отфильтровать цель ***Здания*** или ***Юнита***. Главным образом используется внутри `radar`*,* `unitradar` и `unitlocate`. R`adar` и unit`radar` могут возвращать в качестве цели юниты, но `unitlocate` это другое дело, так как он ищет здания, обнаруживаемые ведомой процессором боевой единицей.
Полный список отображается нажатием кнопки `parameters` после `"target"` в меню `radar` и `unitradar.`

**Operation**
Математическая операция.
Полный список операций отображается под кнопкой `" + "` в блоке инструкций `"operation"`.

**Jump**
Условная операция. Используется для перехода к необходимому месту программы в процессоре. В случае возврата True переход выполняется, в ином случае программа продолжается. `always` вернет True в любом случае и, следовательно, выполнит переход.
Полный список отображается под кнопкой сравнения в блоке инструкций `"jump"`.

Редактируя код в текстовом редакторе, можно использовать дополнительные возможности команды `jump`, которые сделают написание кода проще, когда этого кода становится много или он часто меняется. Как и в редакторах ассемблера в mlog можно применять метки для условных переходов:

`jump **label**`

`<любое количество строк кода>`

`**label**:`

`printflush message1`

При обработке кода игра сама подставит в `jump` нужный номер строки. `<Label>` должна иметь уникальное название для правильной работы. К сожалению, в визуальном редакторе данная инструкция никак не отображается и не может быть создана, но значительно облегчает написание программ в текстовом редакторе. Работающий пример кода:

set red 0

set green 0

set blue 0

sensor sw1 switch1 @enabled

sensor sw2 switch2 @enabled

sensor sw3 switch3 @enabled

jump redfull equal sw1 1

set red 0

jump nextgreen always x false

redfull:

set red 255

nextgreen:

jump greenfull equal sw2 1

set green 0

jump nextblue always x false

greenfull:

set green 255

nextblue:

jump bluefull equal sw3 1

set blue 0

jump drawall always x false

bluefull:

set blue 255

drawall:

draw clear red green blue 0 0 0

drawflush display1

end

Для проверки постройте и соедините три кнопки, процессор и дисплей.

## Переменные и константы ***mlog***

*Для тех, кто уже владеет теорией программирования: **Mlog*** использует автоматическое приведение типов переменных, наследуя его из Java. Переменной может быть присвоено числовое значение, строка, указатель на экземпляр объекта (`Building`). Переменная доступна только в том процессоре, в программе которого она применена, и ее значение недоступно в других процессорах, несмотря на то, что в их программах могут быть переменные с таким же именем, все они будут иметь различные значения. Переменная может быть объявлена в любой инструкции или инструкцией `"set".`

*Для тех кто только начал интересоваться программированием. **Mlog*** как и многие другие языки программирования использует переменные для того чтобы хранить данные программы, выполнять над ними операции. Переменная — это ячейка памяти процессора, в которой сохраняется сохраняется определённое значение под выбранным именем. В ***Mlog*** в переменных может хранится практически любая информация: десятичные числа, логические значения, и даже ссылка на экземпляр объекта, которую можно считать к примеру инструкцией `"get link"`

При создании своих программ, придется часто прибегать к использованию переменных, они — единственный способ переносить данные внутри программы между инструкциями, и из-за этого у начинающих программистов, переходящих от простых программ к более сложным, часто возникает путаница в названиях переменных. Для того чтобы упростить себе процесс создания программы, переменным необходимо присваивать названия, которые легко запоминаемы и дают понять, что в этой переменной хранится. Например, хорошим вариантом будет использовать так называемый "`camelCase`", чье название и написание говорит само за себя. Следует выбирать максимально короткие, чтобы уместить в окне редактора, но максимально емкие слова, которые будут отличать конкретную переменную от всех остальных. Например, для того чтобы сохранить координаты игрока можно выбрать переменные `x` и `y`, но если используются так же координаты других объектов, причем одновременно с координатами игрока, то называть последующие переменные x2, y2, x3 идея не очень. Рекомендуется использовать подобные названия: `playerX, playerY, coreXcoord, targetY.`

**Константы** в ***mlog*** являются частью внутриигровых блоков, они создаются только процессором и недоступны к изменению или созданию игроком. Константу можно прочитать в переменную с помощью `"set",` и использовать ее значение в дальнейшем. Пример таких констант: `@maph, @mapw,` они содержат высоту и ширину текущей карты и могут быть вызваны напрямую, то есть они всегда есть в программе, создаются с процессором и их не надо объявлять или читать из объекта`.` Туда же относятся константы `@time,` которая отражает время в UNIX формате, `и @unit,` которая содержит текущий управляемый процессором юнит. Из последней можно вытаскивать информацию о текущем юните, которым управляет процессор с помощью `sensor`.

Последний тип констант — это ссылки на подключенные к процессору объекты. Как правило это название блока и цифра без пробелов. Ссылку можно получить командой `getlink` или посмотреть, выбрав процессор (`message2` и `wall1` на рисунке выше)

## Примеры программ: от простого к тоже простому.

Для того, чтобы понять как работает логика в Mindustry нет лучше ничего, чем попробовать написать программу самому. Особенно хорошо, когда есть пример, который точно работает и от которого можно оттолкнуться. Множество простых, сложных, полезных и бессмысленных, а так же просто занятных примеров копится в ветке ***Discord*** Mindustry #schematics, именно там вы, вероятно, найдете полезные для себя образцы программ.

Ниже представлена пара примеров программ, которые могут быть интересны:

### Программа 1. Бомбовый ковер

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

Мы строим процессор рядом с пушкой рябь, мы присоединяем рябь к процессору, теперь ее можно контролировать используя константу `ripple1` и вводим только одну инструкцию "control", в которой выбираем "стрелять" и координаты, куда собственно стрелять. Всё. Координаты можно узнать включив отображение координат в настройках игры. Повторить для всех пушек. Пушка будет стрелять пока не кончатся боеприпасы и пока она связана с процессором.

Можно взять больше пушек, больше процессоров и засыпать бомбами вражескую позицию с безопасного расстояния! А можно заставить пушки целится по врагам за пределами их радиуса действия? Можно, если как то узнать его координаты. Один из путей -- использовать радар. Он позволяет узнать информацию о юнитах, которые попали в радиус действия здания. К примеру можно заставить рассеиватель палить на дистанцию ряби:

(*дальше я буду приводить программы в текстовом виде, можете скопировать их, вставить в свой процессор и попробовать в игре*)

`set shootFlag 0`

`radar enemy flying any distance ripple1 1 enemyFly`

`sensor targetX enemyFly @x`

`sensor targetY enemyFly @y`

`jump 6 equal targetX 0`

`set shoot 1`

`control shoot scatter1 targetX targetY shootFlag 0`

`jump 0 always x false`

Для того чтобы попробовать постройте рядом процессор, рябь и рассеиватель, соедините их с процессором. Команда `"radar"` считает в переменную `enemyFly` ссылку на ближайший (директива distance) летающий объект противника. Команда `"sensor"` считывает в переменные `targetX` и `targetY` координаты из `enemyFly`, а дальше знакомая нам команда `"control"` заставляет scatter стрелять по этим координатам. Когда в радиусе действия радара ряби нет противников `"radar"` возвращает на любой запрос ноль, и наш рассеиватель развернется в левый нижний угол карты и будет палить туда. чтобы этого не было мы введем переменную `shootFlag`, которую обнуляем каждый раз в первой строчке программы. Затем, после получения координат проверяем командой `"jump"` не является ли случайно координата х нулем, и если является, просто пропускаем строчку с командой `"set shootFlag 1"`. Теперь рассеиватель не будет стрелять, когда нет противников в зоне обзора.

### Программа 2. Юнит лунатик, доставщик, разведчик.

Процессор может контролировать юнитов, юниты будут делать то, что не стали бы делать самостоятельно. Например, бесцельно блуждать по карте.

Для контроля юнита процессор должен его "захватить". За это отвечает команда `unitBind`. Она устанавливает в константу `@Unit` тип юнита, которым будет управлять процессор — он может быть только один для процессора в данный момент времени, для управления разными типами юнитов одновременно следует построить еще процессоры.

Каждый раз как выполняется команда `unitBind`, одна единица такого типа (точнее сказать "ещё одна") привязывается к процессору. Она еще самостоятельна, но уже готова реагировать на команды `unitControl`. Получив первую такую команду юнит перестаёт выполнять действия вшитые в его программу действия и начинает выполнять только команды процессора, у него появляется соответствующий значок шестеренки, стрелочка направленная на процессор, и странности в поведении. А также у него появляется `tag`, метка в виде цифры. Ее можно прочитать и записать, она может явно отметить юнит, пока тот находится под управлением процессором, её можно использовать для того чтобы захватить один конкретный юнит и не трогать другие.

Здесь стоит подойти к одному из принципов создания программ: программа делится условно на "зону объявлений" и "основной цикл". Это не строгое деление, но оно возникает естественным образом, если программа мало-мальски усложняется. Программа в миндастри, как и много в каких случаях, например в микроконтроллерах (тот же ардуино), достигнув конца начинает выполнятся сначала. А если мы к примеру не хотим чтобы у нас захватывалось много юнитов, а только один, нам не нужно повторять всю программу, мы выбираем `"jump always"`, ставим в конце программы и указываем его стрелку на место где юнит уже захвачен и должен что нибудь делать. Так мы создадим основной цикл программы, а до него как раз получится код, в котором всё инициализируется и настраивается как надо. Сложно? Ничуть, вперед, к примерам!

Заставим летучий юнит блуждать по карте без цели и плана, потому что мы можем!

`set k 1`

`ubind @flare`

`ucontrol flag k 0 0 0 0`

`op rand driftX 150 b`

`op rand driftY 150 b`

`op idiv driftX driftX 1`

`op idiv driftY driftY 1`

`ucontrol move driftX driftY 0 0 0`

`ucontrol within driftX driftY 5 reached 0`

`jump 7 equal reached false`

`jump 3 always x false`

Скопируйте, вставьте в процессор и код обретет цвета и понятность. По шагам: в нулевой (счет здесь идет с 0!) строчке мы объявляем переменную `k` и присваиваем ей 1 на будущее. Первой строчкой мы захватываем в управление вспышку. Вторая строчка ставит флаг нашей вспышки в значение `k`, пока это 1. следующие четыре строчки генерируют в переменные `driftX, driftY` случайные координаты от 0 до 150. Инструкция `rand` возвращает дробное значение, которое нам непригодно и следующая инструкция его подрезает до целого. Дальше юнит отправляется по этим координатам, а чтобы он точно долетел, а программа не приступила к каким то другим делам или не началась с начала, мы проверяем строчкой "`ucontrol within driftX driftY 5 reached 0`", достиг ли наш юнит заданных ему координат. Результат этой команды в виде `1/0, yes/no, true/false,` возвращается в переменную `reached.` Ее мы и сравниваем в следующей инструкции, и если `reached` еще не true, то возвращаемся на седьмую строчку (счет с нуля!) `ucontrol move` и всё повторяется по маленькому кругу, пока юнит не достигнет заданных координат. Тогда `reached` проходит проверку `"jump"` программа достигает последней строчки, а та в свою очередь ведет нас к месту где создаются новые координаты.

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

`set k 10`

`ubind @flare`

`ucontrol flag k 0 0 0 0`

`sensor sourceX container1 @x`

`sensor sourceY container1 @y`

`ulocate building core false @copper coreX coreY found bCore`

`sensor unitPayload @unit @totalItems`

`jump 11 equal unitPayload 0`

`ucontrol move coreX coreY 0 0 0`

`ucontrol itemDrop bCore 1000 0 0 0`

`jump 6 always x false`

`ucontrol move sourceX sourceY 0 0 0`

`ucontrol itemTake container1 @titanium 1000 0 0`

`jump 6 always x false`

Здесь можно видеть уже знакомые инструкции в начале, так что перейдем сразу к "`sensor sourceX container1 @x".` Сенсор дает нам координаты контейнера, который связан с процессором, сохраняем из в `sourceX, sourceY,` будем отправлять по ним юнит когда он пустой. Следующая интересная команда "`ulocate"` она позволяет нам получить информацию о зданиях, которые юнит может обнаружить, при чем на выводе у нее сразу же координаты здания, найдено ли здание юнитом и ссылка на экземпляр здания. Мы используем координаты `coreX coreY,` чтобы отправлять юнит к ядру, когда он загружен, и ссылку на ядро `bCore,` чтобы сложить в него ресурсы. На этом кончается инициализация и начинается основной цикл: мы считываем сенсором сколько сейчас он несет предметов и начинаем проверять, не равно ли их количество нулю. Если равно, то мы отправляем юнит по координатам хранилища, говорим ему поднять предметы (@titanium, например), отправляем назад и снова считываем количество предметов у юнита, проверяем не равны ли они нулю и снова по кругу. Если юнит не достиг контейнера, то команда "`ucontrol itemTake"` выполнится не может и пропускается, и вспышка спокойно летит к контейнеру. Как только она окажется в зоне действия, то должна набрать 1000 титана, но, конечно, лимит предметов у вспышки только 20, и поднимет вспышка только 20. После снова пройдет проверка на количество предметов у юнита, и на этот раз оно равно нулю не будет, так что будет выполнятся другой участок программы -- тот, который приведет вспышку к ядру и заставит ее выгрузить ресурсы. Юнит небезнадежен!

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

Следующий пример. Не самая очевидная идея - юниты могут видеть то, что недоступно игроку. Например, можно считать содержимое вражеского хранилища! Отличное подспорье для PvP игр. Постройте пару вспышек, микропроцессор, «сообщение» на карте, где есть вражеское хранилище с какими-нибудь предметами. То же сработает и для ядра, если поменять в программе тип здания. Большая часть программы вам уже знакома, другая требует пояснений:

`ubind @flare`

`sensor deadDead @unit @dead`

`jump 0 strictEqual deadDead null`

`jump 0 strictEqual deadDead 1`

`ulocate building storage true @copper targetX targetY foundOr enemyBuilding`

`ucontrol flag 666 targetY 0 0 0`

`ucontrol move targetX targetY 0 0 0`

`ucontrol getBlock targetX targetY 0 target 0`

`sensor copperEn target @copper`

`sensor leadEn target @lead`

`sensor metaglassEn target @metaglass`

`sensor graphiteEn target @graphite`

`print "[#b87333] Copper "`

`print copperEn`

`print "\n"`

`print "[#706b7a] Lead "`

`print leadEn`

`print "\n"`

`print "[#caffff] Metaglass "`

`print metaglassEn`

`print "\n"`

`print "[#b2c0d2] Graphite "`

`print graphiteEn`

`print "\n"`

`print deadDead`

`printflush message1`

`jump 1 always x false`

Вставьте этот код в ваш микропроцессор и посмотрите, что будет в подключенном к нему сообщении, когда "вспышка" доберется до вражеского хранилища. Если нет хранилища, найдите в коде строчку "`ulocate building storage true @copper targetX targetY foundOr enemyBuilding"` и поменяйте storage на core, тогда "вспышка" будет пытаться добраться до ближайшего вражеского ядра. Если она успеет достигнуть его и выполнить команду `"getBlock"`, то в переменную target сохранится ссылка на настоящее вражеское ядро и мы, как обычно сенсором прочитаем его содержимое. Я не стал расписывать все возможные ресурсы, так как для них операция однотипна, лист программы станет очень длинным, а если сделать изящно, через цикл, то будет еще и запутанным для понимания. Изящно и все возможные ресурсы я предлагаю дописать вам самостоятельно).

Стоит так же уделить пару слов проверке на `@dead` и выводу цветных строчек в сообщение.

`@dead` это новый параметр, добавленный в версии ***126***, если `@unit` жив, то значение `@dead` будет 0. Если юнит погиб, `@dead` принимает значение 1. Если же юнит после гибели отписан от процессора, а другой не приписан, например не был построен в нужный момент и не захвачен программой, то `@dead` принимает значение `null`. чтобы быть уверенным, что мы не пропустим момент, когда нашего юнита не станет и обязательно захватим нового, `deadDead` проходит две проверки: на равно `null` и равно `1.` При этом проверка на равенство null должна быть строгой `"==="`, иначе простое равенство не сможет отличить `0` от `null`. Для новичков: `0` это число, и оно несет значение, от `0` можно отнять сколько нибудь и получить отрицательное число. `Null` же это совсем ничто никакого типа, на этом месте пусто и ничего нет, на это место можно только что нибудь положить, чтобы оно обрело форму и значение. В разнице между этими двумя типами кроется источник многих ошибок, и следует внимательно следить, где у вас на входе/выходе 0, а где `null.` Если `deadDead` проходит мимо обеих проверок, у нас выполняется обычный код, если срабатывает хоть она проверка, то у нас выполняется инструкция `unitBind` и всё идет по кругу с новой "вспышкой".

Для вывода текста в «сообщение» используются две команды: "`print`" и "`print flush`". Первая добавляет текст в буфер, каждая последующая команда добавляет свою строку в конец предыдущей. "print" понимает символ переноса строки \n, а также HEX-код цвета: [#FF00AA]. Текст будет выделен этим цветом до следующей смены цвета.

Если вы пробуете эту программу у себя в игре и у вас в сообщении ничего не меняется, все четыре строчки показывают null, значит "вспышка не может "дотянутся" до хранилища или ядра. Попробуйте вместо нее юнит по мощнее или выберите ей другую цель.

### Программа 3. Управление производством с цветными штуками

Логика может контролировать не только турели и юнитов. С других зданий можно получать их параметры, и все здания можно включить и выключить, при этом завод перестанет производить что производил, ресурсы на конвейере замрут на месте, а ядерный реактор не бахнет без криогенной жидкости. Еще можно считать на что настроен сейчас сортировщик и установить ему новую настройку используя `sensor` и c`ontrol "set config"` . На выключенном блоке игра нарисует жирный красный крест, если навести на него мышь. Как это можно использовать? Очевидно, сразу же сделать защиту ядерному реактору от взрыва! Это первое что пришло всем на ум, когда появилась логика, и таких примеров много на дискорде. Сделаем что нибудь более полезное, будем подрывать реактор при приближении врага! С таймером на экране. Не то чтобы очень полезно, но эффектно. Используем в программе всё что уже пробовали и что нибудь новое, погнали!

Для начала просто взорвем реактор. Если присмотреться, это не так уж и просто, жидкости ему надо совсем немного, и если ее перекрыть, то реактор еще 15 секунд будет работать на той жидкости, что внутри до взрыва. Подумаем об этом позже, а пока прикинем как логика сможет подорвать реактор:

код проще некуда

`sensor switchState switch1 @enabled`

`control enabled conduit1 switchState 0 0 0`

`end`

Sensor считывает состояние переключателя и через переменную switchState сообщает его секции трубопровода: выключатель выключен? Труба тоже. После выключения реактор бахнет через 15 секунд. Добавим радар для врагов:

screenshot\_9.png

`control enabled conduit1 1 0 0 0`

`radar enemy any any distance ripple1 1 enemyAtgate`

`jump 0 strictEqual enemyAtgate null`

`control enabled conduit1 0 0 0 0`

`jump 3 always false false`

Если попробовать этот код, то окажется, что враги успеют далеко убежать, пока наша недешевая мина сработает. Сделаем с этим что нибудь, например мы можем отключить реактор прямо перед взрывом, и включить его по сигналу радара. В новых версиях Anuke добавил измерение времени (таймер), можем использовать его, а можем считать количество криогенной жидкости внутри реактора и затормозить его когда останется чучуть. И сюда можно приплести графический дисплей!

`sensor crioLevel reactor1 @cryofluid`

`op div crioDraw crioLevel 30`

`op mul crioDraw crioDraw 80`

`draw clear 0 0 0 0 0 0`

`draw color 0 0 255 255 0 0`

`draw rect 0 0 80 crioDraw 0 0`

`drawflush display1`

`jump 0 greaterThanEq crioLevel 5`

`control enabled reactor1 0 0 0 0`

`draw clear 0 0 0 0 0 0`

`draw color 255 20 20 255 0 0`

`draw stroke 10 0 0 0 0 0`

`draw line 40 15 40 16 0 0`

`draw line 40 30 40 60 0 0`

`drawflush display1`

`jump 8 always x false`

Теперь реактор затормозит при количестве жидкости 5, а на дисплее можно будет видеть состояние мины пролетая мимо. Немного про то, что происходит с дисплеем. Графика выводится на дисплеи по той же логике, что и текст, вы наполняете буфер, то что в коде программы ниже, то выводится последним, а значит перекрывает предыдущее. Что можно сделать:

`clear` - залить дисплей целиком выбранным цветом, используется для создания фона и для очистки дисплея, обычно идет первым;

`color` - устанавливает цвет для последующих за ней команд, перекрывается следующей командой color, так же устанавливает прозрачность, где 255 непрозрачный;

`stroke` - устанавливает толщину линии для следующих за ней фигур;

`line` - рисует линию, толщина будет как указано в stroke, начало и конец указываются в команде как x1 y1, x2 y2. Кстати дисплеи здесь 80x80 и 180x180, малый и большой;

`rect и lineRect` - прямоугольник закрашенный и пустой, указываем нижний левый угол и ширину с высотой. Его мы используем для того чтобы показать уровень утекающей жидкости кстати, и как аргумент "высота" задаем масштабированное к 80 пикселям значение количества жидкости в реакторе;

`poly и linePoly` - рисует многоугольник, аргументами будут координаты центра, число сторон и радиус круга, в который он вписан;

`triangle` - треугольник, закрашенный, всё тоже понятно, три точки вершин как аргументы;

`image` - внутриигровой спрайт. То есть любая картинка в игре, объект которой может быть вызван в логике. Здесь все картинки из базы данных ядра и некоторые другие, полный список и как их вызвать смотрите на diskord/mindustry, когда нибудь у меня дойдут руки собрать их и выложить списком в подстатье. Картинку можно вывести в нужные координаты, она принимает параметр color, задается ее размер и поворот вокруг оси, поворот задается в градусах, строго 0..360, будьте внимательны;

Здесь в программе не происходит чего то особо нового, добавилось только отображение на дисплей. Пока жидкости в реакторе больше 5 синяя полоса показывает ее уровень, как только станет меньше/равно, нарисует жирный восклицательный знак и отключит реактор. Можно заниматься украшением графики бесконечно, но тогда код разбухнет и будет непригоден для учебной статьи, так что ограничимся минимумом спецэффектов. Осталось запустить реактор, как только появятся враги на нужном расстоянии, думаю вы уже догадываетесь как это сделать;)

`control enabled reactor1 1 0 0 0`

`sensor crioLevel reactor1 @cryofluid`

`op div crioDraw crioLevel 30`

`op mul crioDraw crioDraw 80`

`draw clear 0 0 0 0 0 0`

`draw color 0 0 255 255 0 0`

`draw rect 0 0 80 crioDraw 0 0`

`drawflush display1`

`jump 1 greaterThanEq crioLevel 5`

`control enabled reactor1 0 0 0 0`

`draw clear 0 0 0 crioDraw 0 0`

`draw stroke 10 20 @blast-compound 40 0 0`

`draw color 255 150 20 255 0 0`

`draw triangle 5 5 40 75 75 5`

`draw color 255 20 20 255 0 0`

`draw line 40 15 40 16 0 0`

`draw line 40 30 40 60 0 0`

`drawflush display1`

`radar enemy any any distance ripple1 1 enemyAtgate`

`jump 9 strictEqual enemyAtgate null`

`control enabled reactor1 1 0 0 0`

`jump 20 always x false`

Дисплей решает две задачи: он может подтолкнуть вас к творчеству и утолить жажду самовыражения, а еще он может показывать состояние вашего производства или ресурсов, чтобы не заглядывать каждые пятнадцать секунд в ядро или хранилище. Еще он позволяет сделать внутри Mindustry другую игру, правда на это пойдет больше строчек кода, чем в этой вики, но у игроков получается, получится с логикой и у вас! Удачи в игре!

*Игра развивается, логика в ней обретает и теряет возможности, не стесняйтесь править эту вики если увидите ошибки или устаревшую инфу, только тестируйте свой код)*