Фэндом


Lua.png

Lua ([лу́а], «луна») — интерпретируемый язык программирования, разработанный подразделением Tecgraf Католического университета Рио-де-Жанейро (Computer Graphics Technology Group of Pontifical Catholic University of Rio de Janeiro in Brazil). Является свободно распространяемым, с открытыми исходными текстами на языке Си.

Это замечательный скриптовый язык, который позволяет вам программировать скрипты для игры, таким образом реализовывать какую-ту свою логику в Worms 3D, Worms Forts: Under Siege или Worms 4: Mayhem.

Здесь будет рассказано о использовании Lua на примере Worms4 (для Worms3D срипты необходимо к тому же компилировать из *.lua в *.lub файл с помощью программы luac.exe)

Смысл скриптов Править

Итак, приступим! Сначала определимся что же такое скрипт? Понимать можно по-разному но мы будем называть это программкой, которая выполняется не операционной системой, а какой-то средой, в нашем случае это интерпретатор языка lua, встроенный в червяков.

Интерпретатор - это программа, которая способна выполнять определённые программы, которые она понимает. Если это интерпретатор lua, то она выполняет наш скрипт на языке lua.

Интерпретатор языка lua имеет чудесное свойство - с помощью него скрипту можно дать возможность управлять той программой, которая исполняет скрипт. То есть интерпретатор языка lua это лишь прослойка между нашим скриптом и червяками.

Разработчики Worms заранее придумали, что им потребуется делать в скриптах. В частности они решили, что в их скриптах будут некоторые способы по-особому начать игру, управлять игровым процессом, изменять набор оружий у червей, делать взрывы, убивать и оживлять червей. Таким образом они "сообщили" интерпретатору, что скрипты могут делать, и всем скриптам стали доступны те возможности, которые придумали разработчики червей.

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

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

В чём работать? Править

Всё о чём мы будем далее говорить требует попыток воспроизвести это всё и понять, как всё работает. Конечно lua - код можно тестировать непосредственно в червях(об этом будет рассказано позже), однако так совершенно неудобно изучать язык, его самые простые конструкции, поэтому нужно другое решение. Для тестирования рекомендуем использовать другой lua-интерпретатор с редактором SciTE.

Установка и настройка SciTE с lua интерпретатором Править

  1. Скачайте редактор SciTE и интерпретатор lua
  2. Установите SciTE.
  3. Извлекаем содержимое второго архива в какое-либо надёжное место, желательно без пробелов в пути, например C:\lua
  4. На рабочем столе щёлкаем правой кнопкой на иконке "Мой компьютер", выбираем в меню "Свойства", переходим на вкладку "Дополнительно", жмём по кнопке "Переменные среды", ищем в списке системных переменных строчку Path, выбираем её и жмём кнопку изменить. В текстовом поле "Значение переменной" в конце добавляем текст ";C:\lua", жмём OK. В этом же окне под списком системных переменных жмём кнопку "Создать". В текстовом поле "Имя переменной" вводим "LUA_DIR", а в текстовом поле "Значение переменной" вводим "C:\lua", жмём OK. Аналогично добавляем ещё 2 переменные LUA_PATH = "?.lua;%LUA_DIR%\?.lua;%LUA_DIR%\L_DIR\?.lua" и LUA_CPATH = "?.dll;%LUA_DIR%\?.dll;%LUA_DIR%\C_DIR\?.dll".
  5. Скачайте файл настройки для редактора SciTE для языка lua тут и замените файл C:\Program Files\SciTE\languages\lua.properties на скаченный.
  6. Запустите SciTE. Наберите в редакторе текст:
print("Hello world!")

Сохраните файл как Hello.lua, а затем нажмите "Выполнить" в меню "Tools"(или кнопку F5). Внизу появится окошко консоли, в котором будет выведен результат работы вашего первого скрипта

>lua.exe "C:\Documents and Settings\You\Рабочий стол\1111.lua"
Hello world!
>Exit code: 0 Time: 0.24

Теперь любой код в статье, не относящийся к червякам, вы сможете тестировать прямо из редактора, набрав текст и нажав F5. Обратите внимание на то, что в статье приведены примеры с псевдокодом. К примеру там используется несуществующая фунция message. В большинстве случаев можно написать в начале скрипта:

message = print

Основы программирования Править

Для понимания работы скриптов в Worms крайне желательно иметь некоторые сведения о программировании, хотя реально и так понять. Расскажем, как пишутся скрипты(точнее как их правильно писать).

Программа - набор команд. Команды должны быть понятны для исполнителя(у нас это интерпретатор). Наш интерепретатор понимает только команды, записанные определённым образом.

Каждая команда записывается на отдельной строке(хотя вроде можно и на разных, но удобнее так).

Команды выполняются последовательно одна за другой. Порядок исполнения можно менять. Далее приведены стандартные команды(операторы):

Примечание: далее по тексту есть примеры с использованием псевдокода-под этим подразумевается, что он не должен работать в червях. Это просто абстрактный код. К примеру message(a) - некоторая функция, которая каким либо образом выводит свой параметр пользователю, не стоит воспринимать это так, как будто message есть в червях!

Комментарии Править

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

В Lua комментарии записываются двумя способами

  • Однострочный комментарий. После двойного знака "минус" в конце строки, например:
message(3) --пример однострочного комментария.
           --текст после двух минусов игнорируется

  • Многострочный комментарий. После двойного знака "минус" и двух открывающих квадратных скобок, до двух закрывающих двойных скобок, например:
message(3)
--[[
пример многострочного комментария.
текст можно записывать в несколько строк,
и всё что внутри будет проигнорировано,
даже если написать какие-либо операторы
чтобы окончить комментарий надо поставить
две скобки(см следующую строку)
]]

Операторы присваивания, типы данных и массивы
Править

Переменная - особая ячейка в памяти, где могут храниться данные. Например мы можем хранить числа, текст(строки), массивы или таблицы, как это принято называть в lua (сразу несколько значений в одной ячейке). Ячейки памяти(переменные) имеют имена, чтобы их можно было однозначно определить. Переменные можно использовать в различных выражениях-обычных математических(+ - * /), в функциях и т.д.

Данные, хранимые в переменных могут иметь следующие типы:

  • Число

Запись чисел обычная:

number1=12412.124
number2=7

  • Текст

Для записи используются кавычки, например так:

text="Привет!"

Соединение двух строк в одну делается с помощью оператора две точки(псевдокод):

text1="Привет,"
text2=" мир!"
text=text1..text2
message(text)

Данный код выведет Привет, мир!

  • Булево значение(логическое, или истина или ложь)

Особый тип данных, у которого всего 2 значения - ложь(false) или правда(true). Любая операция, в которой производится проверка значения(например сравнение) возвращает именно булево значение.

Примеры(псевдокод):

a=2
b=4
message(a==b)            --равенство, выведет false
message(a~=b)            --неравенство, выведет true
message(a>b)             --больше, выведет false
message(a<b)             --меньше, выведет true
message(a>=b)            --больше или равно, выведет false
message(a<=b)            --меньше или равно, выведет true

                         --Логическое отрицание
message(not true)        --выведет false
message(not false)       --выведет true

                         --Логическое И
message(true and true)   --выведет true
message(false and true)  --выведет false
message(true and false)  --выведет false
message(false and false) --выведет false

                         --Логическое ИЛИ
message(true or true)    --выведет true
message(false or true)   --выведет true
message(true or false)   --выведет true
message(false or false)  --выведет false

message((a>b) or (a+2)==b)  --выведет true, потому что хотя бы одно из условий выполнено
message((a>b) and (a+2)==b) --выведет false, потому что одно из условий не выполнено

Как видно из примера, к булевым значениям можно применять логические операторы and, or и not. Они позволяют составлять сложные условия.

  • Таблица

Таблицу можно описать в виде

sometable={ [индекс1] = значение1; [индекс2] = значение2; [индекс3] = значение3 <...> }

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

sometable={ ["name1"] = значение1; ["name2"] = значение2; ["name3"] = значение3 <...> }

эквивалентна следующей:

sometable={ name1 = значение1; name2 = значение2; name3 = значение3 <...> }

  • Функция

Это можно объяснить так - в переменной можно кроме реальных данных хранить и какое то действие, то есть когда необходимо совершить то действие, которое описано в ней. Для полноты приведём пример(псевдокод):

local somefunc
somefunc = function (a,b)
 return math.sin(a+b)   --не пугайтесь, так записывается стандартная функция sin - синус
end

message(somefunc(1,2))

Код примера выведет значение синуса 1+2. Обратите внимание, что somefunc - это переменная, а не функция. Сама функция является безымянной.

Переменные могут иметь разную область видимости-глобальные и локальные. Локальные действуют только в пределах определённого логического куска кода, например внутри функции, цикла и т.д. Глобальные действуют на самом высоком уровне. Если мы хотим воспользоваться(получить или присвоить) значение перемнной с именем foo, то сначала переменная с именем foo ищется среди локальных, а потом среди глобальных.

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

<имя переменной> = <значение>

Создание переменной с ограниченной областью видимости(к примеру только в функции)

local <имя переменной> = <значение>

Примеры(псевдокод):

a = 12
b = 17
c = a+b
message(c)

При выполнении сначала переменная a примет значение 12, и b значение 17, а зачем c примет значение a+b, то есть 12+17, поэтому message(c) выведет 29

d=10
g=15
message(d)
message(g)

function a()
 local d = 5
 g=20
 message(d)
 message(g)
end

a()
message(d)
message(g)

При выполнении выведется сначала 10 и 15, потом 5 и 20, а потом 10 и 20, что говорит о том, что локальная и глобальная переменная не одно и то же. Локальная переменная пропадает, когда заканчивается работа функции.

Есть особый вид присваивания переменных - параллельное присваивание. Оно позволяет в одной строке присвоить значения сразу нескольким переменным, к примеру можно поменять местами значения двух переменных(псевдокод):

x=10
y=20

message(x,y)   --выведет 10, а затем 20

x, y = y, x    --параллельное присваивание

message(x,y)   --выведет 20, а затем 1

Этот код аналогичен следующему:

x=10
y=20

message(x,y)   --выведет 10, а затем 20

t = x          --приходится использовать дополнительную переменную
x = y
y = t

message(x,y)   --выведет 20, а затем 1

Существует особый тип перменных - массивы или таблицы. Таблица - это набор из элементов с общим именем. Чтобы их отличать используется индекс. Таблицу в lua можно представить в виде таблицы с двумя столбцами. Пусть у нас есть таблица с именем foo

Индекс Значение Как обращаться
1 15 foo[1]
2 55 foo[2]

Создание переменной-массива, делается как и в случае обычной переменной, однако в конце надо ставить ={} что означает создание пустого массива. Его наполнение производится после этого.

Для создания массива foo, приведённого в таблице выше, можно написать следующее.

local foo={}
foo[1]=15
foo[2]=55

Можно создавать массив, сразу заполняя его:

local foo={[1]=15; [2]=55 }

Для того, чтобы получить значение какого-либо элемента можно написать так(псевдокод):

message(foo[1])

Иногда бывает нужно узнать длину массива, для этого надо написать # перед именем массива, например:

local foo={}
foo[1]=15
foo[2]=55
message(#foo) --выведет 


Чудесная возможность, которую даёт lua - это создавать так называемые ассоциативные массивы, то есть такие, где в качестве индекса выступает текстовая строка(на самом деле в качестве индекса может быть что угодно, даже другой массив, но это редко применяется). Рассмотрим пример массива car.

Индекс Значение Как обращаться
"model" "BMW" car["model"] или car.model
"speed" 350 car["speed"] или car.speed
"price" 1000000000 car["price"] или car.price

Для создания такого массива можно написать следующее:

car={}
car["model"]="BMW"
car["speed"]=350
car["price"]=1000000000

или так:

car={}
car.model="BMW"
car.speed=350
car.price=1000000000

или даже так:

car={ model = "BMW"; speed = 350; price = 1000000000 }

Как видно, третья запись намного удобнее. При этом на массив можно смотреть, как на некоторое описание реального объекта, в нашем случае-машины с маркой BMW и большущей ценой. Для того, чтобы получить значение какого-либо элемента, например скорости можно написать так(псевдокод):

message(car["speed"])

ну и намного проще так:

message(car.speed)

Условные операторы Править

Эти операторы позволяют исполнять часть команд по условию

if <условие> then
  <последовательность команд, которая будет выполнена при выполнении условия>
end

if <условие> then
  <последовательность команд, которая будет выполнена при выполнении условия>
else
  <последовательность команд, которая будет выполнена, если условие не выполнено>
end

if <условие 1> then
  <последовательность команд, которая будет выполнена при выполнении условия 1>
elseif <условие 2> then
  <последовательность команд, которая будет выполнена, если прошлые условия не выполнены, и  при выполнении условия 2>
        ...
elseif <условие n> then
  <последовательность команд, которая будет выполнена, если прошлые условия не выполнены, при выполнении условия n>
else
  <последовательность команд, которая будет выполнена, если ни одно условие не выполнено>
end


Пример(псевдокод):

number=InputNumber()
if number>10 then
 message("Число больше 10")
elseif number==3 then
 message("Число равно 3")
else
 message("Число меньше 11 и не равно 3")
end 

Операторы цикла Править

Цикл - цепочка действий, которая может повторяться несколько раз. Житейский пример: вам сказали подпрыгнуть 10 раз - это цикл, в котором повторяется одно и тоже действие - прыжок - ровно 10 раз.

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

Цикл for-do-end позволяет повторять действие определённое количество раз, он называется цикл со счётчиком(то есть в нём задана переменная, которая хранит номер повтора). Цикл for устроен просто:

for <переменная-счётчик> = <начало цикла>,<конец цикла>, <шаг> do
  <цепочка действий, повторяемых для всех значений переменной-счётчика из указонного диапазона> 
end

Цепочка действий, выполняемая циклом также называется телом цикла. Например(псевдокод):

for i = 1, 10 do
  message(i)      --Выведет числа 1,2,3,4,5,6,7,8,9,10         
end

В этом примере показана укороченная версия цикла(не пишется шаг-он необязателен). При этом значение переменной растёт с каждым шагом ровно на 1.

Можно задать шаг, как в следующем примере(псевдокод):

for i = 1, 10 ,2 do
  message(i)      --Выведет все нечётные числа 1,3,5,7,9
                  --11 выведено не будет, так как не попадает в заданные пределы         
end

Существует другая разновидность циклов - циклы с условием(repeat–until и while–do-end). Данный вид цикла может повторяться пока будет выполняться или не выполняться какое-либо условие.

Цикл repeat–until устроен следующим образом:

repeat
  <цепочка действий, которая будет выполнена хотя бы 1 раз, а если выполнится условие после until, то будет повторено> 
until <условие продолжения>

Цикл repeat–until оканчивается условием, идущим следом за until, поэтому в условии можно ссылаться на локальные переменные, описанные внутри цикла. Цикл обязательно выполняется хотя бы 1 раз, а затем проверяется условие, необходимо ли продолжать повтор цикла.

Пример для repeat(псевдокод):

a=0
repeat
  message("Введите число > 0")
  a=input()                         --Пользователь вводит число
until (a<1)                         --Повторяем, если введено не положительное число

Цикл while-do-end позволяет делать циклы, в котором тело может быть никогда не выполнено. Основное отличие от прошлого цикла в том, что условие стоит в начале цикла, на входе в него. То есть сначала проверяется, нужно ли выполнять цикл, а затем происходит выполнение и, если условие всё ещё выполняется, цикл повторяется.

Цикл while-do-end устроен следующим образом:

 while <условие> do
  <цепочка действий, которая может быть не выполнена ни разу, выполняется, только если выполнено условие выше> 
end

В качестве примера для while рассмотрим, как сделать аналогию цикла for:

local <переменная-счётчик>=<начало цикла>
while <переменная-счётчик> < <конец цикла> do
    <тело цикла>
    <переменная-счётчик> = <переменная-счётчик> + 1
end

Для управления циклами, надо уметь выходить из них по необходимости. Выйти из цикла можно с помощью оператора break.

Пример для break(псевдокод):

a=0
repeat
  message("Введите число")
  a=input()                         --Пользователь вводит число
  if a==0 then
    break                           --Если введён 0, то выходим
  end
  
  message(a)
until true                         --Это означает правду, то есть цикл выполняется всегда

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

Функции Править

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

  1. желания сократить код
  2. сделать его более понятным
  3. лучше контролировать работу программы, искать ошибки

Важной особенностью lua-функций является то, что они могут быть вызваны интерпретатором. Таким образом можно осуществлять обработку различных событий. К примеру таким способом интерпретатор в червяках оповещает lua скрипт о том, что ранен червь, начался ход и т.д.

В Lua функция имеет следующий формат:

function <имя функции>(<параметр 1>, <параметр 2>, <...>)
  <тело функции>
  return <результат>
end

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

Вызов функции происходит в следующем виде:

<имя функции>(<значение параметра 1>, <значение параметра 2>, <...>)

Вызов функции возвращает её значение, то есть можно использовать в различных выражениях, например:

<переменная>=<имя функции>(<значение параметра 1>, <значение параметра 2>, <...>)

В самом lua уже есть несколько предопределённых функций. Они, как правило разделены на библиотеки(то есть при вызове функции sin надо указывать её библиотеку, то есть math.sin() ) и конкретная версия интерпретатора может не включать в себя некоторые из них. Список функций можно узнать на этой странице

В прошлых примерах мы рассматривали псевдо-функцию message. В worms её можно реализовать так:

function message(text)
  SetData("Text.TestComment", text)	
  SetData("CommentaryPanel.Comment", "Text.TestComment")
  SendMessage("CommentaryPanel.ScriptText")
end

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

Функция становится доступной после её определения, то есть нет смысла писать строку:

message("Привет")

если функция ещё не определена. 

Есть достаточно лёгкое для понимания, но порой сложное для реализации понятие под названием рекурсия. Рекурсия - это вызов из функции этой же функции. Вот пример(вычисляет факториал числа):

function factorial(number)
  if (number>1) then
    return number*factorial(number-1)
  else
    return 1
  end
end

message(factorial(6))

Выведет 720. Работа этого кода довольно проста. Сначала мы вызваем factorial(6), она возвращает 6*factorial(5), factorial(5) возвращает 5*factorial(4), и так далее до factorial(1), который вернёт 1. Получим, что factorial(6)=6*5*4*3*2*1=720.

Программируем червяков
Править

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

Работа интерпретатора в червяках
Править

Напомним, интерпретатор - это программа, которая способна выполнять определённые программы, которые она понимает. Он даёт нам некоторые возможности, но и требует от нас определённого порядка работы.

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

Рассмотрим, в чём же проявляются особенности интерпретатора lua в worms

Функции Править

Интерпретатор в червях предоставляет несколько функций. Рассмотрим их.

SetData(container_name, value) Править

Позволяет изменять содержимое xml(или xom в Worms3D) контейнера с помощью скрипта. Чтобы понять смысл этого, откройте любой xml файл из папки W4/data/tweak - там вы увидите данные в xml-разметке, которая очень похожа на html. В этих файлах хранится игровая информация: все параметры червя, настройки оружия и так далее. К тому же там есть контейнеры, которые на первый взгляд не имеют смысла, к примеру CommenteryPanel.Comment. Вот он (часть содержимого файла Local.xml):

<XStringResourceDetails id='CommentaryPanel.Comment'>
 <Value></Value>
 <Name>CommentaryPanel.Comment</Name>
 <Flags>96</Flags>
</XStringResourceDetails>

Непонятно, зачем в настройках хранить текст на панели комментариев, тем более что он постоянно меняется, а к тому же поле Value пусто
Оказывается xml файлы предназначены не только для хранения данных, но и для определения "общих рабочих ячеек" для совместной работы скрипта и хоста. Внутренние функции червяков работают с различными данными, находящимися в xml, а скрипт может их менять с помощью SetData. Обычно в червяках для совершения какого-либо действия надо сначала установить все необходимые контейнеры, а затем уже совершить действие. То есть SetData сама по себе ничего не делает. Не ждите мгновенного проявления результата после вызова SetData. Обратите внимание, SetData не изменяет xml файл на диске. Эта функция работает только с версией файла в памяти! Пример использования SetData:

SetData("CommentaryPanel.Comment", "Hello!")

Для вывода этого текста к тому же надо добавить строчку

SendMessage("CommentaryPanel.ScriptText")


SendMessage(message) Править

Данная функция "просит" червей выполнить какое-либо действие. К примеру можно вызвать так:

SendMessage("CommentaryPanel.ScriptText")

Это заставит червей посмотреть, что в данный момент записано в контейнере CommentaryPanel.Comment и вывести его содержимое или содержимое контейнера с таким именем на экран в панель комментариев. Поэтому обычно для вывода текста сначала необходимо в какой-либо текстовый контейнер записать сам комментарий, затем в контейнер CommentaryPanel.Comment записать имя 1-го контейнера, а затем послать сообщение CommentaryPanel.ScriptText

SetData("Text.TestComment",Text)
SetData("CommentaryPanel.Comment", "Text.TestComment")
SendMessage("CommentaryPanel.ScriptText")

SendMessage после вызова может изменять значения различных контейнеров. Это свойство используется функцией GetData. Приведём список всех известных сообщений(все они найдены в стандартных скриптах):

AI.ExecuteActions
AI.PerformDefaultAITurn
Camera.ShakeStart
Comment.SuddenDeath
Commentary.Clear
Commentary.EnableDefault
Commentary.NoDefault 
CommentaryPanel.ScriptText
CommentaryPanel.TimedText
DoubleDamage.Activated
EFMV.End
EFMV.Play 
Earthquake.End
Explosion.Construct
Game.PlaceObjects
GameLogic.AboutToApplyDamage
GameLogic.AboutToWaterRise
GameLogic.ActivateNextWorm
GameLogic.AddInventory
GameLogic.ApplyDamage
GameLogic.Challenge.Failure
GameLogic.Challenge.Success
GameLogic.ClearInventories
GameLogic.CrateShower
GameLogic.CreateAirstrike
GameLogic.CreateCrate
GameLogic.CreateNuclearEffect
GameLogic.CreateRandMineFactory
GameLogic.CreateRandomMine
GameLogic.CreateRandomOildrum
GameLogic.CreateRandomTelepad
GameLogic.CreateSentryGun
GameLogic.CreateTelepad
GameLogic.CreateTrigger
GameLogic.Draw
GameLogic.DropRandomCrate
GameLogic.EndTurn
GameLogic.GetAllTeamsHadTurn
GameLogic.IncrementInventory
GameLogic.Mission.Failure
GameLogic.Mission.Success
GameLogic.PlaceObjects
GameLogic.PlaceTelepads 
GameLogic.ResetCrateParameters
GameLogic.ResetTriggerParams
GameLogic.SetNoFallDamage
GameLogic.SetSpecialWeapon
GameLogic.StartMineFactory
GameLogic.Turn.Ended 
GameLogic.Turn.Started 
GameLogic.Tutorial.Failure
Jetpack.UpdateFuel
Land.Clear
Net.DisableAllInput
Particle.NewEmitter
RandomNumber.Get
SentryGun.FireAt
SentryGun.LookAt
String.Substitute
String.SubstituteIndirect
Team.Surrender
Timer.EndRetreatTimer
Timer.EndTurn 
Timer.StartGame
Timer.StartHotSeatTimer 
Timer.StartPostActivity
Timer.StartTurn
Utility.Delete
Weapon.Create
Weapon.Delete
Weapon.DisableWeaponChange
Worm.ApplyPoison
WormManager.GetActiveAlliances
WormManager.GetSurvivingTeam
WormManager.Reinitialise
WormManager.TeleportIn
WormSelect.OptionSelected
Wormpot.SetupModes

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

SendIntMessage(message,number) Править

Эта функция - аналог SendMessage, однако позволяет передавать числовой параметр. Список допустимых сообщений:

Имя сообщения message Параметр number
Crate.Delete индекс ящика или триггера, который удаляем
Crate.RadarHide индекс ящика, который надо скрыть
GameLogic.CreateTeamStatues индекс команды, для которой надо создать статуи
GameLogic.DestroyTrigger индекс триггера, который надо уничтожить
GameLogic.Win индекс команды, которая объявляется победителем
Particle.DelGraphicalEmitter индекс эмиттера
SpawnVolume.Remap индекс команды
WXWormManager.UnspawnWorm индекс червя, которого убрать
Worm.DieQuietly индекс червя, которого "по-тихому" убиваем =)
Worm.Poison индекс червя, которого заражаем
Worm.QueueAnim индекс червя
Worm.ResetAnim индекс червя
Worm.Respawn индекс червя, которого оживляем
SendStringMessage(message,text) Править

Эта функция - аналог SendMessage, однако позволяет передавать текстовый параметр. Список сообщений:

WXMsg.EasterEggFound строка вида "Lock.EasterEgg.номер"
Land.GetLandRemaining код куска земли
Land.EnablePointLight имя эмиттера света
GameLogic.PlaceMine имя эмиттера мины
GameLogic.CreateBriefingBox тип ящика
GetData(container_name) Править

Обратное действие к SetData. Позволяет считать содержимое xml(или xom в Worms3D) контейнера с помощью скрипта. Чаще всего вызов GetData производится при каком-то событии, чтобы узнать что именно произошло. Понятие события вы поймёте дальше, а сейчас надо понять такой пример:

function Worm_Died() 
 DeadWorm = GetData("DeadWorm.Id")   --узнаём, кто умер
end

При смерти червя интерпретатор вызовет событие - Worm_Died(). При этом мы можем узнать номер умершего червя. В другом, менее распространённом случае, мы сначала с помощью SendMessage "просим" червей вернуть нам какое-либо значение, а потом мы его считываем из контейнера, например:

SendMessage("RandomNumber.Get")                --запрашиваем случайное число
local RawRand = GetData("RandomNumber.Uint")   --"забираем" число из контейнера

QueryContainer(container_name) Править

Эта функция похожа на GetData. Она принимает на вход имя контенера из xml(или xom) файла и возвращает значение, однако QueryContainer используется немного для других целей, а именно для извлечения сложных контенерных типов данных. Вот пример таких данных:

<XContainerResourceDetails id='Worm.Data00'>
 <Value href='Worm.Data00-0'/>
 <Name>Worm.Data00</Name>
 <Flags>369</Flags>
</XContainerResourceDetails>
<WormDataContainer id='Worm.Data00-0'>
 <Name></Name>
 <Active>false</Active>
 <PlayedInGame>false</PlayedInGame>
 <Position x='0' y='0' z='0' />
 <ForcedCameraOffset x='0' y='0' z='0' />
 <Velocity x='0' y='0' z='0' />
 <Aftertouch x='0' y='0' z='0' />
 <InputImpulse x='0' y='0' z='0' />
 <Acceleration x='0' y='0' z='0' />
 <SupportNormal x='0' y='0' z='0' />
 <Orientation x='0' y='0' z='0' />
 <AngularVelocity x='0' y='0' z='0' />
 <ControlX>0</ControlX>
 <ControlY>0</ControlY>
 <LastLogicalUpdate>0</LastLogicalUpdate>
 <SupportFrame>0</SupportFrame>
 <SupportVoxel>0</SupportVoxel>
 <WeaponAngle>0.6</WeaponAngle>
 <WeaponFuse>3</WeaponFuse>
 <WeaponIsBounceMax>false</WeaponIsBounceMax>
 <WeaponHerd>3</WeaponHerd>
 <TeamIndex>0</TeamIndex>
 <PositionInTeam>0</PositionInTeam>
 <PhysicsOverride>0</PhysicsOverride>
 <Flags>0</Flags>
 <PhysicsState>8</PhysicsState>
 <WeaponIndex>0</WeaponIndex>
 <InitialEnergy>0</InitialEnergy>
 <Energy>0</Energy>
 <CPUFixedWeapon>0</CPUFixedWeapon>
 <CPUActionRadius>0</CPUActionRadius>
 <ArtilleryMode>false</ArtilleryMode>
 <PoisonRate>0</PoisonRate>
 <PendingPoison>0</PendingPoison>
 <PlaceWormAtPosition>false</PlaceWormAtPosition>
 <SfxBankName></SfxBankName>
 <Spawn></Spawn>
 <IsParachuteSpawn>false</IsParachuteSpawn>
 <IsAllowedToTakeTurn>true</IsAllowedToTakeTurn>
 <GunWobblePitch>0</GunWobblePitch>
 <GunWobbleYaw>0</GunWobbleYaw>
 <LipSynchBank>255</LipSynchBank>
 <ATT_Hat></ATT_Hat>
 <ATT_Glasses></ATT_Glasses>
 <ATT_Gloves></ATT_Gloves>
 <ATT_Tash></ATT_Tash>
 <MovedByImpulse>true</MovedByImpulse>
 <GraphicalOrientation x='0' y='0' z='0' />
 <Scale x='0' y='0' z='0' />
 <LastCollisionNormal x='0' y='0' z='0' />
 <LogicAnimState>0</LogicAnimState>
 <SlopeAngle>0</SlopeAngle>
 <DamagePending>0</DamagePending>
 <CurrentEnergy>0</CurrentEnergy>
 <IsAfterTouching>false</IsAfterTouching>
 <AfterTouchVector x='0' y='0' z='0' />
 <IsHatWearer>false</IsHatWearer>
 <IsQuickWalking>false</IsQuickWalking>
 <AllowBazooka>1</AllowBazooka>
 <AllowGrenade>1</AllowGrenade>
 <AllowClusterGrenade>1</AllowClusterGrenade>
 <AllowAirstrike>1</AllowAirstrike>
 <AllowDynamite>1</AllowDynamite>
 <AllowHolyHandGrenade>1</AllowHolyHandGrenade>
 <AllowBananaBomb>1</AllowBananaBomb>
 <AllowLandmine>1</AllowLandmine>
 <AllowShotgun>1</AllowShotgun>
 <AllowBaseballBat>1</AllowBaseballBat>
 <AllowProd>1</AllowProd>
 <AllowFirePunch>1</AllowFirePunch>
 <AllowHomingMissile>1</AllowHomingMissile>
 <AllowFlood>1</AllowFlood>
 <AllowSheep>1</AllowSheep>
 <AllowGasCanister>1</AllowGasCanister>
 <AllowOldWoman>1</AllowOldWoman>
 <AllowConcreteDonkey>1</AllowConcreteDonkey>
 <AllowSuperSheep>1</AllowSuperSheep>
 <AllowGirder>1</AllowGirder>
 <AllowBridgeKit>1</AllowBridgeKit>
 <AllowNinjaRope>1</AllowNinjaRope>
 <AllowParachute>1</AllowParachute>
 <AllowLowGravity>1</AllowLowGravity>
 <AllowTeleport>1</AllowTeleport>
 <AllowJetpack>1</AllowJetpack>
 <AllowSkipGo>1</AllowSkipGo>
 <AllowSurrender>1</AllowSurrender>
 <AllowChangeWorm>1</AllowChangeWorm>
 <AllowRedbull>1</AllowRedbull>
 <AllowArmour>1</AllowArmour>
 <AllowWeaponFactoryWeapon>1</AllowWeaponFactoryWeapon>
 <AllowStarburst>1</AllowStarburst>
 <AllowAlienAbduction>1</AllowAlienAbduction>
 <AllowFatkins>1</AllowFatkins>
 <AllowScouser>1</AllowScouser>
 <AllowNoMoreNails>1</AllowNoMoreNails>
 <AllowPipe>1</AllowPipe>
 <AllowPoisonArrow>1</AllowPoisonArrow>
 <AllowSentryGun>1</AllowSentryGun>
 <AllowSniperRifle>1</AllowSniperRifle>
 <AllowSuperAirstrike>1</AllowSuperAirstrike>
 <AllowBubbleTrouble>1</AllowBubbleTrouble>
 <TeleportIn>false</TeleportIn>
 <IsEmotional>true</IsEmotional>
 <HasDrunkRedbull>false</HasDrunkRedbull>
 <Armoured>false</Armoured>
</WormDataContainer>

Этот контейнер описывает червя. При извлечении этого контейнера из xml с помощью QueryContainer мы получим таблицу, содержащую все элементы xml структуры:

local worm = QueryContainer("Worm.Data00")      --worm - таблица
message(worm.Energy)                            --выведет оставшуюсь жизнь червяка
                    --поскольку worm-таблица, то можно и так:
message(worm["Energy"])
message(worm.Armoured)                          --есть ли броня?

EditContainer(container_name) Править

Как и прошлая функция, работает с контейнерами в xml или xom, но она позволяет менять их содержимое. Эта функция возвращает два значения. Первое - "блокировка" - необходима для того, чтобы после изменения контейнера освободить его. Второе - сама таблица с контейнером, которую можно изменять. EditContainer всегда используется вместе с CloseContainer. Пример(запрет на использование оружия наводнение):

lock, scheme = EditContainer("GM.SchemeData")       --блокируем контейнер и начинаем редактирование
 scheme.FloodMystery.Crate = 0
 scheme.Flood.Crate = 0
 scheme.Flood.Ammo = 0
CloseContainer(lock)                                --разблокируем и даём червям сигнал применить изменения

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

CloseContainer(lock) Править
CopyContainer(from_container_name,to_container_name) Править
StartTimer(timer_function,delay) Править
CancelTimer(timer_handle) Править

Обнаружено использование расширения AdBlock.


Викия — это свободный ресурс, который существует и развивается за счёт рекламы. Для блокирующих рекламу пользователей мы предоставляем модифицированную версию сайта.

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

Также на Фэндоме

Случайная вики