Оглавление | Сообщение об ошибках | Ваше мнение о проекте | E-Mail автору |
Введение в скриптописание Х2
Использование переменных является простым способом хранения временных данных в вашем НС и передачи их в нужном виде ScE Х2. Переменные могут являться указателями на объект, хранить в себе данные его типе ($station = [HOMEBASE]), а также результаты математических, логических или операций сравнения ($res = 2+2), принимать значения ЛОЖЬ или ИСТИНА ($res= [FALSE]), содержать текст ($text=Hello world !!!). Имя переменной задается пользователем и отображается после знака $<имя> . Имя должно состоять из одного слова, может содержать цифры, строчные и прописные буквы латинского алфавита (но начинаться должно с буквы). При создании переменной желательно давать ей максимально информативное имя, т.к. в сложных скриптах используется не один десяток переменных и чтобы избежать путаницы имена должны быть понятны и сообщать о содержимом переменной. Например, переменная содержащая информацию о свободном месте в трюме корабля может иметь имя $ShipFreeAmount. Такое имя сообщает пользователю о том какие данные содержит переменная.
В ScE присутствуют следующие типы переменных:
Приватные переменные – переменные относящиеся непосредственно к скрипту в котором они созданы. Над этим типом переменных можно производить любые операции, математические, логические, сравнения. Приватные переменные недоступны другим скриптам. Формат записи $<имя>.
…
002 $test = 5
003 $total = $test+10
004 if $total < 10
…
Локальные переменные – переменные этого типа относятся к определенному объекту, но доступны другим скриптам. Все операции с локальными переменными осуществляются по принципу Считал-Изменил-Записал. Для выполнения каких либо действий над локальной переменной, нужно получить ее значение при помощи команды get local variable в приватную переменную. Произвести над приватной переменной нужные операции и командой set local variable записать полученный результат обратно в локальную переменную.
...
005 $test = [THIS] get local variable: name= localVar
006 $test = $test + 1
007 [THIS] set local variable: name= localVar value=$test
…
Глобальные переменные – этот тип переменных не привязан ни к одному объекту, это делает их доступными для любого скрипта просто по имени этой переменной. В связи с этим, объявляя глобальную переменную следует позаботиться о том, чтобы ее имя было оригинальным и информативным. Принцип выполнения операций на глобальными переменными тот же, что и у локальных. Команды для работы с глобальными переменными get global variable и set global variable.
…
008 $test = get global variable: name=globVar
009 $test = $test + 1
010 set global variable: name=globVar value=$test
…
Теперь мы разобрались какие бывают типы переменных и для чего они
нужны. Осталось разобраться как они устроены.
В ScE любая переменная состоит из двух частей. Первая, это тип данных. Вторая часть сами данные. Тип данных сообщает ScE как работать с содержащимися в переменной данными. Сделано это для того, что бы работая с переменными мы могли не задумываясь помещать в них как информацию о какой либо точке в пространстве сектора, так и просто какое ни будь числовое значение не выполняя никаких дополнительных манипуляций, кроме как указать тип данных который будет хранится в создаваемой переменной. Всего в ScE "X2 The Threat" имеется 22 типа данных:
DATATYP_NULL |
Переменная имеет нулевую величину |
DATATYP_UNKNOWN |
Это тип данных устанавливается ScE если он не может определить тип данных переменной. |
DATATYP_VAR |
Этот тип является внутренним типом переменной ScE. Этот тип является внутренним типом переменной и значение задается непосредственно ScE |
DATATYP_CONST |
Переменная-константа описанная в ScE. Этот тип является внутренним типом переменной и значение задается непосредственно ScE |
DATATYP_INT |
Численная переменная в диапазоне [-2147483648,2147483647] или [-0x80000000,0x7FFFFFFF] |
DATATYP_STRING |
Переменная содержащая данные в виде текста. Пример: $str= Hello World!!! |
DATATYP_SHIP |
Указатель на корабль. Переменная ссылается на объект Корабль |
DATATYP_STATION |
Указатель на станцию. Переменная ссылается на объект Станция |
DATATYP_SECTOR |
Указатель на сектор. Переменная ссылается на объект Сектор |
DATATYP_WARE |
Переменная Товар в "X2 The Threat" это, все что можно купить или продать (кроме кораблей станций) |
DATATYP_RACE |
Переменная-указатель на расу объекта (Аргон, Борон, Сплит, Игрок и т.д.). |
DATATYP_STATIONSERIAL |
Порядковый номере объекта Станции и соответствующая ему буква в греческом алфавите. (альфа, бета, гама, и т.д.) |
DATATYP_OBJCLASS |
|
DATATYP_TRANSPORTCLASS |
Переменная константа принимающая значение класса транспорта (ST, XL, L, etc.)
|
DATATYP_RELATION |
Отношение Друг (Friendly)– Нейтральный (Neutral)– Враг (Enemy) |
DATATYP_OP |
Тип данных Оператор. Этот тип является внутренним типом переменной и используется непосредственно самим ScE |
DATATYP_EXPR |
Выражение. Этот тип является внутренним типом переменной и используется непосредственно самим ScE |
DATATYP_OBJECT |
Указатель на объект. Переменная ссылается на объект не являющийся кораблем, станцией или сектором, а только солнцем, туманностью или астероидом. |
DATATYP_OBJCOMMAND |
Переменная содержит мнемосхему команды |
DATATYP_FLRET |
Переменная содержит код возврата команды fly to (описание далее) |
DATATYP_DATATYP |
Переменная содержит тип данных. Используется в инструкциях типа get datatype
|
DATATYP_ARRAY |
Переменная является массивом |
Большинство используемых НС инструкций возвращают результат который может быть помещен в переменную для дальнейших действий. А непосредственно над переменной, вы сможете выполнять арифметические, логические и т.п. операции как было описано в начале главы.
Для объявления переменной используется инструкция из раздела «Основные команды» “<RetVar/IF><Expression>”. Выбрав данную инструкцию в списке редактор предложит ввести имя переменной. После ввода нажимайте «Enter». Редактор вернется к листингу скрипта и вы увидите следующие выражение:
001 $MainVar = «?»
«?» красным цветом, говорит о том что редактор ожидает дальнейшего ввода данных. Нажимайте «Enter» выберете тип данных из открывшегося списка, а затем и сами данные. Например: выбираем тип данных станция, далее редактор предлагает выбрать сектор и станцию при помощи открывающихся интерфейсов. Выбираем сектор Аргон Прайм станцию Арогонская торговая станция.
001 $MainVar = Аргонская торговая станция [Аргон Прайм]
Теперь объявленная нами переменная $MainVar указывает на Аргонскую торговую станцию находящуюся в секторе Аргон Прайм.
Продолжая рассматривать наш пример предположим, что у нас возникает потребность в том, чтобы наша переменная содержала в себе указатель не на одну станцию, а на целый список. Мы могли бы это решить объявив для каждой станции из списка свою собственную переменную, но если в нашем списке несколько десятков или даже сотен станций, то время и силы потраченные на эту работу начисто отбили бы интерес к скриптописанию. Здесь на помощь нам приходит особая переменная, которая умеет хранить в себе огромное количество однотипных данных, название этой переменной МАССИВ. В массиве данные расположены как в таблице с пронумерованными строками. Номера строк называются индексом массива, общее количество строк размером массива, а данные элементами массива. То есть, для того чтобы использовать данные из массива нам необходимо установить указатель индекса на нужный элемент и получить его значение в переменную. Синтаксис такой операции с массивом в ScE выглядит так:
…
006 $MainVar = $array [2]
…
В данном примере элемент массива $array с индексом [2] будет помещен в переменную $MainVar.
Следует обратить внимание на то, что индексация массивов начинается с 0, а не с 1. То есть, в массиве размерностью в десять элементов, первый элемент будет иметь индекс 0, а последний 9.
Теперь давайте рассмотрим как в ScE организован сам массив.
Прежде всего запомните, что переменная типа <Var/Array> в ScE Х2 сама по себе не является массивом, а только указателем на область памяти где он храниться. То есть когда вы используете инструкцию <RetVar>=array alloc: size=<Var/Number> для того чтобы создать новый массив, вы даете ScE указание распределить память под указанное в инструкции количество элементов и вернуть в переменную указатель на эту область. Этот указатель называется – пойнтер. Именно из-за этого, в ScE для выполнения копирования массивов предусмотрены специальные инструкции, т.к. скопировать массив в другую переменную при помощи инструкции $array2=$array1 на удастся. После того как ScE выполнит эту команду, мы будем иметь две переменные указывающие на один и тот же массив.
соответственно если произвести работу с каким либо элементом массива $array1, значения изменяться и для псевдо массива $array2:
…
005 $array2=$array1
006 $array1 [2] = 5
007 $var = $array2 [2]
…
значение переменной $var = 5, так как пойнтеры $array1 и $array2 указывают на одну и ту же область памяти.
Для того, чтобы получить копию массива, нам следует использовать команду <RetVar>=clone array <Var/Array>: index <Var/Number> <Var/Number>. Если в нашем примере заменить строку 005 на :
005 $array2=clone array $array1: index 0 … 2
Теперь мы имеем два независимых массива, а переменная $array2 содержит пойнтер на новую область памяти в которой расположена копия трех элементов из массива $array1.
Не забывайте учитывать данную особенность работы ScE с массивами при написании своих скриптов.
При создании массива, также надо учитывать тип данных хранящийся в нем. Например если массив содержит данные о точке в секторе Var/Sector Position, то данные будут располагаться следующим образом: координата x[0], y[1], z[2], sector[3]. Соответственно если в массиве информация о трех точках, то размерность массива составит 12 элементов с 0 по 11, первая точка индексы [0-3], вторая [4-7], третья [8-11].
Константы – это величины имеющие постоянное значение. В ScE Х2 используется несколько типов констант: первый тип Глобальные константы, это константы которые может использовать практически любая команда, и приватные константы, это константы зарезервированные для каких либо команд и используются только ими.
В таблице указанны все используемые константы имеющиеся в Х2:
Глобальные константы |
THIS |
указатель на объект, который только что получил команду и занялся ее выполнением. Например, вы запустили на корабле команду "Покупать товар". Этот корабль и будет THIS. |
PLAYERSHIP |
Указывает на корабль в котором сидит игрок |
HOMEBASE |
Указывает на базу приписки текущего объекта |
ENVIRONMENT |
возвращает объект-окружение для другого объекта. Например, если корабль в космосе, то его окружение объект "сектор", а если пристыкован к базе - "база" и т.п. |
SECTOR |
возвращает объект-сектор, в котором находится текущий объект. |
OWNER |
Константа указатель на владельца текущего объекта |
NEAREST |
Константа указывающая на ближайший объект, по отношению к текущему объекту. |
FALSE |
Константа ЛОЖЬ |
TRUE |
Константа ИСТИНА |
DOCKEDAT |
Константа указывает на станцию или носитель в доке которого находится текущий корабль. Если корабль не в доке, то принимает значение FALSE |
Приватные константы:
Formation.Delta |
Константы указывающие на тип построения для команды set formation подробно рассмотрены в описании команды. |
Formation.Line |
|
Formation.X |
|
Formation.XDelta |
|
Formation.BigShipEscort |
|
Formation.Pyramid |
|
Formation.Random |
|
Find.Random |
Константы Find являются флагами при организации поиска, каждая константа имеет числовое значение, допускается использовать эти константы в виде комбинаций составленных через побитовое ИЛИ «|». |
Find.Nearest |
|
Find.ExactJumps |
|
Find.Enemy |
|
Find.Neutral |
|
Find.Friend |
|
Find.Multiple |
|
Find.TypeAsWareCategorie |
|
Find.IllegalWare |
|
Find.ForceUsePos |
|
CmdConCheck.Available |
Константы используемые командой set script command upgrade … script, как флаги возвращаемые проверочным скриптом. Флаги используются для активации или деактивации строки в командном меню. (См. описание команды) |
CmdConCheck.Disabled |
|
CmdConCheck.OneTime |
|
CmdConCheck.Infinite |
|
CmdConCheck.NeedHomeStation |
|
CmdConCheck.NeedHomeBase |
|
IncomingTransmission.SOS |
Набор констант для аудиокоманды play sample: incoming transmission, (подробное описание этих констант в описании команды) |
IncomingTransmission.Message |
|
IncomingTransmission.Greeting |
|
IncomingTransmission.Scanned |
|
Comm.DLG_C_START_FIGHTING |
Используется аудиокомандой send audio message, (см. описание команды) |
Comm.DLG_POL_ILLEGAL_GOODS |
|
Comm.DLG_POL_LAST_WARNING |
|
Comm.DLG_POL_LEGAL_GOODS |
Если вы просматривали список констант который предлагает редактор, то наверняка заметили, что в этот список не вошли несколько групп констант. Это специальные внутренние константы ScE (SSTYPE, ACTION, GalaxyFlight) и нам для использования они недоступны (то есть выбрать мы их можем, но они не имеют никакого информативного содержания).
Под операцией подразумевается, нахождение некоторой величины полученной в результате выполнения некой последовательности действий, производимых над одной или несколькими величинами. Величины, представляющие из себя сами объекты операций, называются операндами.
В ScE Х2 операндами могут являться константы, числа, переменные, строковое выражение, указатели на объект. Какие именно действия нужно произвести над операндами, ScE сообщает знак операции (+,-,*,/ и т.п.).
Все операции производимые в ScE, можно разделить на несколько групп:
· Арифметические;
· Сравнения;
· Логические
· Побитовые (формальная логика)
· Отрицания и дополнения
Давайте подробнее рассмотрим каждую группу:
Арифметические операции выполняют общий набор математических действий (сложение, вычитание, умножение, деление и т.п.). Обратите внимание, что в ScE все операции цельно-численные, то есть не допускается использования дробных чисел, все числовые операнды должны являться целыми числами. Последовательность выполнения вычислений математическая, то есть слева на право, умножение имеет более высокий приоритет чем сложение. В выражениях можно изменять последовательность вычислений используя скобки (угловые скобки), допускается многоуровневое построение выражений используя вложенность скобок, например математическое выражение ((3+2)*5)+10, в ScE будет выглядеть так: [[3+2]*5]+10.
+ |
сложение |
- |
вычитание |
* |
умножение |
/ |
Деление |
mod |
Получение остатка от деления |
[ |
Математические скобки |
] |
Сложение:
001 $MainVal = 3 *Присвоить переменной $MainVal значение 3
002 $Total = $MainVal + 8 *Прибавить к $MainVal число 8, $Total = 11
003 $Total = $Total - $MainVal *Операция вычитания $Total = 8
004 $Total = 5 * 6 *Умножение $Total = 30
005 $Total = [2+3]*5 *Использование скобок $Total = 25
006 $Total = 7+[-2] *Использование отрицательных чисел $Total = 5
007 $Total = 49 / 10 *Деление $Total = 4 (результат цельно-численный)
008 $Total = 49 / [-10] *$Total = -4
009 $Total = 49 mod 10 *Остаток от деления $Total = 9 (10*4=40+9=49)
010 $Total = 49 mod [-10] *$Total = 9
011 $Total = -49 mod [-10] *$Total = -9
Диапазон используемых чисел ограничен от -2 147 483 648 до 2 147 483 647 или в шестнадцатеричном исчислении от -0x80000000 до 0x7FFFFFFF.
Следует заметить о еще одной особенности оператора «+», это возможность работать со строковыми переменными. При помощи этого знака можно сложить две переменные содержащие текстовые строки.
Пример:
001 $str1 = ‘Наша Маша’
002 $str2 = ‘ громко плачет.’
003 $str1 = $str1 + $str2
Теперь переменная, $str1 содержит строку «Наша Маша громко плачет.» Для того, чтобы соединяемые фразы были разделены пробелом, не забывайте добавлять его в конце первой или начале второй.
Операции сравнения, формируют значение [FALSE] (0 Ложь) или [TRUE] (1 Истина) в зависимости от результата обработки операндов. Возвращаемое операцией значение используется для обработки такими операторами как IF, IF NOT, SKIP IF. SKIP IF NOT, WHILE и т.п. Операции сравнения выполняются слева на право.
== |
проверка условия «равно» |
!= |
проверка условия «не равно» |
> |
проверка условия «больше» |
< |
проверка условия «меньше» |
>= |
проверка условия «больше или равно» |
<= |
проверка условия «меньше или равно» |
Примеры использования:
001 $variable = 10 *присвоить переменной $variable значение 10
002 if $variable == 10 *сравнить равно ли значение $variable, 10 [TRUE]
003 skip $variable > 5 *сравнить $variable больше 5 [TRUE]
004 skip not $variable < 5 *сравнить $variable меньше 5 [FALSE]
005 while $variable >= 20 *сравнить $variable больше или равно 20 [FALSE]
006 while not $variable != 20 *сравнить значение $variable не равно 20 [TRUE]
К логическим операциям относиться операция логического «И» (оператор AND) и логического «ИЛИ» (оператор OR). Логические операции не вызывают ни каких арифметических преобразований. Они оценивают каждый операнд с точки зрения его эквивалентности нулю. Результатом логической операции является [FALSE] (0 Ложь) или [TRUE] (1 Истина). Операции выполняются слева на право.
Операция логического И (оператор AND) вырабатывает значение 1, если оба операнда имеют значение 1. Если один из операндов равен 0, то результат будет равен 0.
Примеры:
001 $variable = 10
002 if $variable == 10 AND 5+5==10 *результат 1 [TRUE]
003 if $variable == 10 AND 5+5==11 *результат 0 [FALSE]
Операция логического ИЛИ (оператор OR) выполняет над операндами операцию включающего ИЛИ. Она вырабатывает значение 0, если оба операнда имеют значение 0, если какой-либо из операндов имеет ненулевое значение, то результат операции равен 1.
Примеры:
001 $variable = 10
002 if $variable == 10 OR 5+5==10 *результат 1 [TRUE]
003 if $variable == 10 OR 5+5==11 *результат 1 [TRUE]
004 if $variable == 11 OR 5+5==11 *результат 0 [FALSE]
К поразрядным операциям относятся: операция поразрядного логического "И" (&), операция поразрядного логического "ИЛИ" ( | ), операция поразрядного "исключающего ИЛИ" (^).
Операция поразрядного логического И (&) сравнивает каждый бит первого операнда с соответствующим битом второго операнда. Если оба сравниваемых бита единицы, то соответствующий бит результата устанавливается в 1, в противном случае в 0.
Операция поразрядного логического ИЛИ (|) сравнивает каждый бит первого операнда с соответствующим битом второго операнда. Если любой (или оба) из сравниваемых битов равен 1, то соответствующий бит результата устанавливается в 1, в противном случае результирующий бит равен 0.
Операция поразрядного исключающего ИЛИ (^) сравнивает каждый бит первого операнда с соответствующими битами второго операнда. Если один из сравниваемых битов равен 0, а второй бит равен 1, то соответствующий бит результата устанавливается в 1, в противном случае, т.е. когда оба бита равны 1 или 0, бит результата устанавливается в 0.
Пример.
001 $int = 17919 *0100 0101 1111 1111
002 $int2=255 *0000 0000 1111 1111
003 $res = $int ^ $int2 *0100 0101 0000 0000
004 $res = $int | $int2 *0100 0101 1111 1111
005 $res = $int & $int2 *0000 0000 1111 1111
Операция арифметического отрицания (-) вырабатывает отрицание своего операнда. Операнд должен быть целой величиной. При выполнении осуществляются обычные арифметические преобразования.
Пример:
001 $int = 5
002 $int= - $int *Значение $int = -5
Операция логического отрицания "НЕ" (!) вырабатывает значение 0, если операнд есть истина (не нуль), и значение 1, если операнд равен нулю (0).
Пример:
001 $int = 5
002 $int= ! $int *Значение 0 [FALSE] т.к. $int Истина
Операция двоичного отрицания (~) вырабатывает двоичное отрицание своего операнда. Операнд должен быть целого типа. Осуществляется обычное арифметическое преобразование, все биты операнда инвертируются.
Пример:
001 $int = 17919 *0100 0101 1111 1111
002 $int=~$int *1011 1010 0000 0000
v Операторы условного перехода
Операторы условного перехода используются для того, чтобы изменить последовательность выполнения команд в скрипте в зависимости от определенного условия. Простейшим примером оператора условного перехода может служить оператор «if» применяющийся в паре с оператором «end». Логика его работы следующая:
if (выражение принимающее значение «Истина» или «Ложь»)
операторы, исполняющиеся в случае, если выражение принимает значение «Истина»
end
Пример:
210 if [HOMEBASE]
220 @ = [THIS] -> fly to homebase
230 end
В строке 210 проверяется, задана ли база для данного корабля. Если она установлена (функция [HOMEBASE] вернула значение, которое может быть интерпретировано как «Истина»), то управление переходит в строку 220, где корабль получает команду возвращаться на неё. Поскольку нам может быть необходимо, чтобы при выполнении определенного условия исполнялся не один, а целая группа операторов, мы должны указать, где именно заканчивается эта группа. Для этой цели и служит оператор «end». Оператор «if» может принимать и более сложные формы:
if (выражение, принимающее значение «Истина» или «Ложь»)
операторы, исполняющиеся в случае, если выражение принимает значение «Истина»
else
операторы, исполняющиеся в случае, если выражение принимает значение «Ложь»
end
if not (выражение, принимающее значение «Истина» или «Ложь»)
операторы исполняющиеся в случае если выражение принимает значение «Ложь»
else
операторы исполняющиеся в случае если выражение принимает значение «Истина»
end
if (выражение1, принимающее значение «Истина» или «Ложь»)
операторы исполняющиеся в случае, если выражение1 принимает значение «Истина»
else if (выражение2, принимающее значение «Истина» или «Ложь»)
операторы исполняющиеся в случае, если выражение1 принимает значение «Ложь», а выражение2 принимает значение «Истина»
else
операторы исполняющиеся в случае, если выражение1 принимает значение «Ложь» и выражение2 принимает значение «Ложь»
end
if not (выражение1, принимающее значение «Истина» или «Ложь»)
операторы исполняющиеся в случае, если выражение1 принимает значение «Ложь»
else if not (выражение2, принимающее значение «Истина» или «Ложь»)
операторы, исполняющиеся в случае, если выражение1 принимает значение «Истина» а выражение2 принимает значение «Ложь»
else
операторы, исполняющиеся в случае, если выражение1 принимает значение «Истина» и выражение2 принимает значение «Истина»
end
skip if (выражение, принимающее значение «Истина» или «Ложь»)
оператор, исполняющийся в случае, если выражение принимает значение «Ложь»
В данной форме записи оператора «if» оператор «end» не требуется, поскольку в случае если выражение принимает значение «Истина» пропускается (не выполняется) только один оператор (не группа операторов), следующий в строке сразу за «skip if»
skip if not (выражение принимающее значение «Истина» или «Ложь»)
оператор, исполняющийся в случае, если выражение принимает значение «Истина»
v Операторы безусловного перехода
К операторам безусловного перехода относится оператор «goto label», который используется для перехода к определенной строке скрипта. Прежде чем использовать «goto label» необходимо объявить метку для строки, в которую мы хотим осуществить переход. Делается это при помощи оператора «define label» из раздела «Общие команды=>Команды исполнения».
Пример:
100 StartCalculation:
110 $Total = $Price * $Amount
120 …
…
430 goto label StartCalculation
Само ключевое слово «define label» в тексте скрипта не указывается, вместо него указывается имя метки со знаком «:» – двоеточие после него. Будьте особенно внимательны используя конструкцию «define label» «goto label» так как с её помощью очень легко получить «вечный» цикл, т.е. закольцованный кусок программы, выход из которого не предусмотрен, а при отсутствии в сегменте кода между меткой и оператором goto команд wait и команд со знаком @ произойдет зависание игры.
Х2 help Dimaxx & Pegasus script MAD_Kuzia
Циклы используются для повторения действия (или последовательности действий) нужное нам кол-во раз. Сколько в цикле будет витков (проходов цикла), определяется условием цикла. В развитых языках программирования существуют циклы 3-х типов: с проверкой условия в начале, с проверкой условия в конце и итерационные (с явно заданным кол-вом витков). В принципе, все они являются взаимозаменяемыми, однако выделены в разные типы для нашего удобства. Скриптовый движок Х2 использует только один тип цикла – с проверкой условия в начале.
Бывает 2-х видов:
while <условие>
…
end
Этот цикл выполняется, пока условие имеет значение “Истина” (TRUE).
while not <условие>
…
end
Этот цикл выполняется, пока условие имеет значение “Ложь” (FALSE).
В качестве условия могут быть использованы числа, переменные, логические выражения, сложные логические выражения использующие логические операторы AND, OR, сложные вычисляемые выражения, возвращаемые значения инструкций. Оператор цикла While интерпретирует любое значение как логическое значение Истина или Ложь. Истиной является любое значение большее 0, ложью считается значение 0 или null.
Часто возникает ситуация, когда требуется совершить строго заданное кол-во витков цикла, например, отыскать в массиве ячейку с определенным значением. В этом случае кол-во витков цикла должно ограничиваться кол-вом ячеек в массиве (размером массива). Как это сделать, ведь у нас в игре нет специального цикла с итерацией? Как я уже говорил, все типы циклов взаимозаменяемы, и при определенных ухищрениях можно использовать один тип цикла вместо другого. В нашем случае можно ввести специальную переменную-счетчик витков, анализируя значение которой как условие для цикла, мы добьемся того же результата. Например:
001 $count = 0
002 while $count < 20
…
…
007 inc $count =
008 end
Здесь у нас счетчик – переменная $count, которой перед началом цикла мы присваиваем начальное значение 0. Далее мы организуем цикл, который будет продолжаться, пока наш счетчик будет меньше 20. Перед каждым последующим витком цикла мы увеличиваем значение счетчика на 1. Как видите, процесс неложный.
Это цикл, который выполняется бесконечное число раз, если мы не прервем его специально. Такие циклы широко используются в скриптах для различных команд корабля: торговли, патрулирования и т.п. Например, команда «Продавать товар по лучшей цене» выполняется постоянно, пока мы не прервем ее другой командой. Такие бесконечные циклы организуются просто: достаточно оператору цикла задать в качестве условия заведомо неизменное значение. Например:
while [TRUE]
…
end
или
while 1
…
end
Бесконечные циклы нужно использовать очень аккуратно, внутри них обязательно надо предусматривать временные задержки (команды wait), иначе можно легко «подвесить» игру. Это связано с тем, что все запущенные скрипты выполняются в игре по-очереди, т.к. движок игры основан на принципе «Не вытесняющей многозадачности» (будет рассмотрено в следующей главе). Задержки внутри скриптов позволяют приостановить текущий скрипт и дать в это время возможность выполняться другим скриптам. Если внутри бесконечного цикла не будет задержки (или вызова команды, которая имеет свои задержки, команды перед которыми стоит значок @), то этот скрипт захватит все процессорное время и подвесит игру.
Бесконечный цикл можно получить ненарочно, задав некорректное условие оператору цикла. Например:
while $a !=1 OR $a = 1
…
end
Здесь цикл будет выполняться при любом значении $а, что приведет к бесконечному “зацикливанию”. Зацикливание можно получить в итерационном цикле (см. пример выше), забыв изменить значение счетчика (оператор inc). Ошибочных вариантов много, всех не перечислишь, поэтому всегда будьте внимательны с циклами, условными и бесконечными, тщательно все продумывайте, чтобы не получилось неприятностей. И возьмите за правило, добавлять в тело любого цикла команду wait с небольшой задержкой, это убережет игру от зависания в случае некорректного условия и сохранит возможность принудительной остановки некорректно работающего скрипта.
Скриптовый язык Х2 имеет, подобно прочим языкам, команды break и continue. Эти команды служат для дополнительного гибкого контроля над циклами. Команда break позволяет в любой (нужный нам) момент прервать текущий цикл, а команда continue – прервать текущий виток и сразу перейти на следующий.
Пример для команды break:
while $i < 40
… последовательность действий 1
skip if $i != 20
break
… последовательность действий 2
end
Здесь цикл будет выполняться, пока $i меньше 40, и принудительно прервется, если $i станет равным 20. При этом успеет выполнится последовательность действий 1, а до последовательности действий 2 дело не дойдет.
Пример для команды continue:
while $i < 40
… последовательность действий 1
skip if $i != 20
continue
… последовательность действий 2
end
Здесь цикл будет выполняться, пока $i меньше 40, и принудительно начнется новый его виток, если $i станет равным 20. При этом успеет выполнится последовательность действий 1, а последовательность действий 2 – нет.
Также можно прервать текущий цикл, используя операторы безусловного перехода. Например:
while $i < 40
… последовательность действий 1
skip if $i != 20
goto label metka
… последовательность действий 2
end
… последовательность действий 3
metka:
… последовательность действий 4
Здесь цикл будет выполняться, пока $i меньше 40, и принудительно прервется, если $i станет равным 20. При этом успеет выполнится только последовательность действий 1, после чего мы сразу перейдем к последовательности действий 4, минуя последовательность 2, принадлежащую циклу, и последовательность 3, которая наступила бы при нормальном завершении цикла. Как видите, оператор безусловного перехода goto label можно использовать даже более гибко, чем команду break.
Далее давайте рассмотри несколько примеров использования циклов в навигационных скриптах:
И так, циклы используются, когда вам необходимо повторять определенную последовательность команд, пока не будет достигнуто некоторое условие. Конечно, получить зацикленный кусок кода можно и используя операторы безусловного перехода, однако подобный подход не рекомендуется, поскольку он ухудшает читаемость кода, к тому же использовать команды цикла гораздо удобнее и проще. Вот пример простейшего цикла:
010 while [ENVIRONMENT] != [HOMEBASE]
011 @=wait randomly from 5000 to 10000 ms
012 @=[THIS] ->fly to home base
013 end
В строке 010, заголовке цикла («while»), задано условие цикла (пока корабль не пристыкован к своей базе), пока оно истинно, т.е. принимает значение «истина», цикл выполняется, т.е. выполняются строки с номерами 011 и 012 (ждать 5-10 сек, возвращаться на базу). Как только выполнение скрипта доходит до строки 013, управление передается в строку 010, проверяется условие и если оно выполняется (принимает значение «истина»), то снова выполняются строки 011 и 012, и так до тех пор, пока условие не примет значение «ложь». Как только условие становится ложно, управление переходит в строку, следующую за «end». Если срока с ключевым словом «end» последняя в скрипте, выполнение скрипта завершается. Однако нам может понадобится выйти из цикла до того как условие цикла примет значение «ложь» (например, базу уничтожили, в этом случае корабль никогда не сядет на свою базу, и цикл окажется «вечным»). Для этих целей служит команда «break». Она передает управление в строку, следующую за «end». С учетом проверки на существование базы наш цикл можно записать следующим образом:
010 while [ENVIRONMENT] != [HOMEBASE]
011 if not [HOMEBASE]
012 break
013 end
014 @ =wait randomly from 5000 to 10000 ms
015 @ =[THIS] ->fly to home base
016 end
Ключевое слово «end» стоящее в строке 013 относится к оператору «if» стоящему в строке 011, «end» всегда относится к ближайшему «if» или «while». Оператор «while» можно записать и как «while not», в этом случае значение выражения, задающего условие цикла, инвертируется. Вот так будет выглядеть предыдущий пример в форме «while not»:
010 while not [ENVIRONMENT] == [HOMEBASE]
011 if not [HOMEBASE]
012 break
013 end
014 @ =wait randomly from 5000 to 10000 ms
015 @ =[THIS] ->fly to home base
016 end
Оглавление | Сообщение об ошибках | Ваше мнение о проекте | E-Mail автору |