Кодинг в Sanny Builder 3
Материал из GTAModding.ru
Версия от 08:38, 29 марта 2009; Seemann (обсуждение | вклад)
|
В этой статье не хватает введения. Согласно правилам оформления статья должна начинаться с вводной информации, содержащей краткие сведения о предмете статьи. Вы можете помочь проекту, написав введение. |
Типы данных
[COLOR=BLUE]$[/COLOR] - обозначение глобальных переменных. Их значения могут использоваться в любом месте кода.
0004: $MyVar = 100
[COLOR=GREEN]@[/COLOR] - в начале: метка
0002: jump @MyLabel
[COLOR=BLUE]@[/COLOR] - в конце: локальная переменная. Их значения используются только в пределах одного потока
0006: 100@ = 10
[COLOR=RED]'...'[/COLOR] - текст (макс. 15 символов).
Допускается пустое значение: [COLOR=RED]' '[/COLOR]
03A4: name_thread 'MAIN'
[COLOR=RED]
"..."[/COLOR] - текст (максимум определяется опкодом)
Также вы можете использовать в тексте одинарные кавычки или двойные кавычки. Для двойных кавычек необходимо использовать специальный префикс \.
Допускается пустое значение: [COLOR=RED]" "[/COLOR]
0662: write_debug_message "Hello, \"world\"! 'Here we go!'"
[COLOR=BLUE]s$[/COLOR] - глобальная стринговая переменная
05A9: s$MyString = 'GLOBAL'
[COLOR=BLUE]@s[/COLOR] - локальная стринговая переменная
05AA: 1@s = 'LOCAL'
[COLOR=BLUE]v$[/COLOR] - глобальная стринговая переменная
06D1: v$MyString = "LONG_GLOBAL"
[COLOR=BLUE]@v[/COLOR] - локальная стринговая переменная
06D2: 1@v = "LONG_LOCAL"
[COLOR=BROWN]
'''#''' [/COLOR]- имя модели из одного из IDE - файлов игры
0247: request_model #CELLPHONE
[COLOR=BLUE]&[/COLOR] - прямой байтовый адрес (ADMA). Читает и пишет значения по указанному адресу Может использоваться в тех же случаях, когда используется тип $.
&57 += &120(&231,4i)
(примечание: число после & - локальное смещение внутри файла main.scm, относительно его начала; адрес, куда будет записано значение)
[COLOR=BROWN]
0x[/COLOR] - число в шестнадцатиричном формате.
[COLOR=BROWN]-0x[/COLOR] - отрицательное значение
0004: $var = -0xBB08
Число должно быть в интервале [COLOR=BROWN]-80000000..7FFFFFFF[/COLOR]
Переменные
Переменные используются для хранения каких-либо данных. Вы можете читать их значения, записывать в них новые. Переменные бывают двух типов: глобальные (их значения доступны из любой миссии или потока) и локальные (только в пределах одного потока). Переменные используются в качестве операндов (членов) математических и логических выражений. Sanny Builder позволяет не использовать опкоды в подобных выражениях. Например, вы можете писать
$var = 0
вместо
0004: $var = 0
Во многих случаях это будет даже правильнее, потому что часто в таких выражениях скриптеры используют неверные опкоды.
Однако, если в выражении в обоих сторон участвуют переменные, то компилятор может не знать, какой именно опкод необходим в данном случае. Это происходит из-за того, что возможны два варианта: если обе переменные типа Integer или типа Float.
Для того чтобы подсказать компилятору тип переменной, она должна быть объявлена через конструкцию VAR..END. Она позволяет объявлять переменные и их типы, для последующего манипулирования ими.
Синтаксис:
var <имя переменно>: <ноы тип> end
(При нажатии Ctrl+[space] появится список типов)
Например используйте код
var $1stIntVar : Integer $2ndIntVar : Integer end
и вы можете использовать их в математических операциях подобно
$1stIntVar = $2ndIntVar $1stIntVar *= $2ndIntVar
Поддерживаются следующие типы переменных:
- Integer, Int - integer values (целые)
- Float - floating-points values (дробные)
- String, ShortString - Fixed length string variable (только для массивов, используйте s$, @s для переменных)
- LongString - Variable length string variable (только для массивов, используйте v$, @v для переменных)
Кроме глобальных переменных можно объявлять и локальные переменные. Но нужно помнить, что в этом случае все такие переменные во всех потоках будут иметь один и тот же тип. Чтобы избежать этого, вы можете переобъявлять переменные в каждом потоке.
Например:
Thread 'Food' Var 10@ : Float $Var : Float End $var = 1 10@ = $Var end_thread Thread 'Loop' Var 10@ : Int $Var : Int End $var = 1 10@ = $Var end_thread
В первом потоке переменная [color=blue]10@[/color] будет расцениваться как float, во втором - как integer. Вообще вы можете переобъявлять переменные сколько угодно раз.
Также вы можете инициализировать значение переменной сразу при объявлении. Для этого после указания типа поставьте знак = и стартовое значение:
var $fVar: float = 1.0 end
Переменная $fVar будет запомнена как Float и одновременно в SCM будет записан опкод:
0005: $fVar = 1.0
Инициализация доступна только для переменных, но не массивов!
Константы
Константа представляет собой идентификатор, которому присваивается определенное значение. В отличие от переменных значение константы не может изменяться. При компиляции имя константы заменяется на то значение, которое ей было присвоено. Константы могут быть числовыми и строковыми, а также содержать в себе выражение.
Чтобы создать константу, используйте конструкцию CONST..END. Ее синтаксис выглядит следующим образом:
CONST <имя константы> = <значение> END
Имя константы - любой допустимый идентификатор (латинские буквы, цифры и знак подчеркивания). Не допускается использование преопределенных имен вроде Continue, True, And и т.д. Значение - число (метка, модель); строка; выражение (например, класс или переменная); другая константа.
Пример использования:
const MoneyRequired = 30 PlayerMoney = $PLAYER_CHAR.Money end if PlayerMoney > MoneyRequired then PlayerMoney += -1 end
При компиляции константа MoneyRequired будет заменена на число 30, а PlayerMoney на выражение $PLAYER_CHAR.Money
Компилятор также использует 2 внутренние константы True и False, значения которых равны 1 и 0 соответственно.
Вы можете использовать константы в любом месте кода, за исключением данного случая:
const VarName = $Var IndexName = 25 end VarName[IndexName] = 0
Для компиляции такого выражения вы должны указать опкод, например:
0004: VarName[IndexName] = 0
Также определенные ограничения возникают при компиляции констант-выражений.
Список констант можно вызвать в любом месте кода нажатием Ctrl + [space].
Массивы
Массивы представляют собой набор индексированных элементов одного типа (тип массива). К каждому элементу массива можно обратиться напрямую, используя его индекс (номер элемента в массиве). Нумерация элементов идет, начиная с нуля.
Массивы поддерживаются играми SA и LCS, VCS.
Синтаксис:
San Andreas:
- <имя массива>(<имя индексной переменной>,<размер><тип>)
Liberty City Stories, Vice City Stories:
- <имя массива>(<имя индексной переменной>,<размер>)
<Имя массива>: локальная или глобальная переменная.
Имя переменной должно быть выбрано с учетом размера массива. Например, в потоке нельзя использовать в качестве имени переменную [COLOR=BLUE]33@[/COLOR], если размер массива больше 1, так как в потоках максимально допустимая локальная переменная это [COLOR=BLUE]33@[/COLOR], а элемент массива [COLOR=BLUE]33@[/COLOR] с индексом больше 0 будет за этими границами.
<Имя индексной переменной>: любая переменная.
<Размер>: любое целое число больше нуля.
<Тип>: буквы i f s v обозначающие один из типов массива:
- i: integer, только целые значения, размер элемента 4 байта
- f: float, дробные значения, размер элемента 4 байта
- s: string, строки с фиксированной длиной 8 байтов
- v: longstring, строки с фиксированной длиной 16 байтов
В LCS, VCS элементы массива могут иметь только размер 4 байта, поэтому указание типа не требуется. Массив может содержать элементы только одного типа.
Пример: чтобы обратиться к первому элементу массива, состоящего из десяти элементов, нужно использовать такую запись:
$index = 0 $array($index,10i) = 1
Sanny Builder позволяет упростить работу с массивами двумя способами:
1) определить его в блоке VAR..END
Используется следующая запись:
var <array name>: array <size> of <type> end
Например:
var $FloatArray: array 10 of Float end
После этого вы можете работать с этим массивом без указания его типа и размера. Например:
$FloatArray[$RndIndex] += 100.0
2) использовать индексированные переменные
Допустим, у вас есть массив [color=blue]$strings[/color], состоящий из 10 элементов типа s. Вы можете обратиться к его элементам, напрямую через переменную [color=blue]$strings[/color]. Например, для записи в последную ячейку массива используйте запись:
s$strings[9] = 'str10'
Индексированные переменные очень удобно использовать для инициализации массива с разными стартовыми значениями элементов:
s$strings[0] = 'str1' s$strings[1] = 'str2' //... s$strings[9] = 'str10'
После этого вы можете использовать и полный вариант записи:
$index = 9 if s$strings($index,10s) == 'str10' then 0@ += 1 end
Такие переменные могут использоваться и в качестве имени класса, когда они объявлены как массив, например
$cars[0].Destroy
По умолчанию при декомпиляции в режиме SA элементы массива записываются как индексированные переменные. Вы можете отключить эту возможность через консоль (команда toggle constant_indexes off). Тогда переменные будут декомпилироваться как обычно. Возможность декомпилировать с данной опцией доступна и для LCS, VCS (по умолчанию выключено).
Условия
Для проверки условия (-ий) необходимо использовать оператор IF.
Допускается использование двух видов проверки:
- низкоуровневый
- высокоуровневый
Низкоуровневые условия
00d6: if {<N>} //... <condition 1> //... <condition 2> //... //... <condition n+1> 004d: jump_if_false {<label>}
<N> - параметр, обозначающий количество условий. 0 - проверяется 1 условие 1..8 - 2 и более условий (максимум 9), связанных логическим оператором AND. Это значит что проверка выполнится, если ВСЕ условия, входящие в нее, верны. 21..28 - 2 и более условий (максимум 9), связанных логическим оператором OR. Это значит что проверка выполнится, если хотя бы ОДНО условие, входящее в нее, верно.
<label> - имя метки, на которую должен перейти скрипт, если условие ложно.
Sanny Builder допускает не использовать параметр 0 для одиночного условия. Таким образом, IF тоже самое что IF 0.
Также вы можете использовать ключевые слова AND или OR вместо числовых параметров*. Тогда компилятор сам будет высчитывать необходимое значение.
Например:
if and $var > 0 $var2 == 10.0 jf @anywhere
Компилятор подставит цифру 1 вместо and.
* В опциях должна быть включена проверка условий. IF AND - условия связываются логическим оператором AND (1..8) IF OR - условия связываются логическим оператором OR (21..28)
Высокоуровневые условия
Sanny Builder поддерживает конструкции IF..THEN..END и IF..THEN..ELSE..END*
Создание условия происходит по правилам, описанным выше. После слова THEN вы указываете команду (-ы), которые должны выполняться, если условие верно. После слова ELSE вы указываете команду (-ы), которые должны выполняться, если условие ложно. Условие заканчивается словом End.
if $var == 5 then Inc($var) else Dec($var) end
Допускается использование вложенных условий.
*В опциях должна быть включена проверка условий.
В качестве операторов сравнения в условиях могут использоваться следующие их виды*:
a == b a равно b a >= b a больше либо равно b a > b a больше b a < b a меньше b a <= b a меньше либо равно b a <> b a не равно b
Поддерживаются также их вариации со словом NOT.
* При условии, что вы не используете опкод в выражении.
Циклы
В SB используются следующие виды циклов:
- FOR..END
- WHILE..END
- REPEAT..UNTIL
Циклы могут быть вложенными (т.е. один цикл внутри другого).
Внимание: не забывайте устанавливать задержку (0001: wait) в циклах, чтобы предотвратить зависание игры.
FOR..END
Этот оператор задает цикл со строго определенным числом итераций (повторений) Для него используется следующий синтаксис:
FOR <counter> = <initial value> TO/DOWNTO <final value> [step <int> = 1] ... END
Основные параметры: <counter> - переменная, которая используется в качестве счетчика итераций (повторений) цикла.
<initial value> - стартовое значение счетчика: любое число (может быть имя модели).
TO/DOWNTO - при TO счетчик будет наращивать свое значение, при DOWNTO уменьшать.
<final value> - конечное значение цикла, при котором он завершит работу: любое число (может быть имя модели). Помните, что при DOWNTO конечное значение должно быть меньше стартового.
<step> - (необязательный параметр) значение приращения или уменьшения счетчика при итерациях. По умолчанию его значение равно 1. При использовании дробных чисел в качестве значений счетчика, вы должны также указать параметр step с дробным значением.
Пример цикла:
var $value: int = 0 $final: int = 100 end FOR $MyCounter = 1 to $final step 2 $value += $mycounter end
WHILE..END
Синтаксис:
WHILE <condition> ... END
Цикл WHILE работает до тех пор, пока выполняется условие. Условие проверяется перед итерациями, поэтому если оно будет сразу ложным, то цикл не выполнится никогда.
$var = 10 while $var > 11 inc($var) end
так как условие в цикле ложно, скрипт никогда не придет на команду Inc([COLOR=BLUE]$var[/COLOR])
Оператор While может принимать в качестве условий логические константы True и False: While True .. End - цикл будет выполняться бесконечно, пока вы не прервете его командой Break. While False .. End - цикл будет игнорироваться компилятором.
В текущей версии для цикла WHILE доступно только одно условие. Вы можете проверять большее кол-во условий внутри тела цикла и использовать команды Break и Continue.
REPEAT..UNTIL
Синтаксис:
REPEAT ... UNTIL <condition>
Цикл Repeat работает до тех пор пока не выполнится условие после команды Until. Условие проверяется после итераций, поэтому цикл всегда будет иметь минимум одну итерацию.
Оператор Repeat может принимать в качестве условий логические константы True и False: Repeat .. Until True - цикл будет иметь только одну итерацию Repeat .. Until False - цикл будет выполняться бесконечно, пока вы не прервете его командой Break.
В текущей версии для цикла REPEAT доступно только одно условие. Вы можете проверять большее кол-во условий внутри тела цикла и использовать команды Break и Continue.
Использование Continue и Break
Иногда вам может потребоваться пропустить текущую итерацию и перейти к следующей, например после проверки условия. Для этого существует ключевое слово Continue. Оно может использоваться в качестве параметра. Тогда оно обозначает метку, после которой происходит приращение счетчика и переход к следующей итерации.
Например:
if $currentactor.dead jf continue // 'continue' это внутренняя метка в начале цикла
В качестве отдельной команды оно обозначает опкод 0002 (jump), с переходом на следующую итерацию.
if not $currentactor.dead jf @next Continue // jump continue :next
Кроме этого существует команда Break, которая прерывает цикл. Она может использоваться как отдельная команда так и как параметр (jf break)
Примеры :
1) Пример использование цикла REPEAT...UNTIL:
Смысл следующий: мы создаём машину и актёра в ней , затем заставляем машину понтоваться, т.е. поднимать и удерживать колёса разными способами, прям как на соревновании лоурайдеров.
create_thread @Anims // создаём поток с именем Anims ... :Anims // начинаем поток wait 0 // ждём 0 мс,если не напишем,то может вылететь #REMINGTN.Load // объявляем нужную модель машины - Ремингтон #FAM2.Load // объявляем нужную модель актёра - Член Грув Стрит банды 038B: load_requested_models // загружаем ранее объявленые модели :Anims_2 // создаём второй label wait 0 // ждём 0 мс,если не напишем,то может вылететь if and // условие с выполнением всех подусловий(проверок) #REMINGTN.Available // проверка (загрузилась ли модель #REMINGTN) #FAM2.Available // проверка (загрузилась ли модель #FAM2) player.Defined($PLAYER_CHAR) // проверка (существует ли игрок) jf @Anims_2 // если хоть одна из проверок возвратила значение False, // т.е. не выполнилась, то переходим к началу label'a wait 5000 // ждём 5 мс,просто для удобства car.Create(4@,#REMINGTN,2492.6,-1669.5,13.4) // создаём тачку напротив дома Карла 0129: 5@ = create_actor 4 #FAM2 in_car 4@ driverseat // создаём актёра в этой машине wait 3000 // ждём 3 мс,просто для удобства Car.ToggleHydraulics(4@) = True // устанавливаем на машину гидравлику, если // не поставим, то финтов машина делать не будет $Timer = 25 // Создаём переменную,и приравниваем её к 25, это будет наш таймер :Anims_3 // создаём следующий label wait 0 // ждём 0 мс,если не напишем,то может вылететь REPEAT // начинаем цикл wait 10 // ждём 10 мс 07F5: car 4@ control_hydraulics 1000.0 0.0 0.0 0.0 // машина поднимает к-л колесо, вот номера колёс 1000.0 - переднее левое, // 0.0 - заднее левое, следующий 0.0 - переднее правое и // последний 0.0 - заднее правое. $Timer -= 1 // отнимаем от нашей переменной 1 UNTIL $Timer <= 1 // пока таймер не будет меньше либо равен 1, наш цикл будет выполнятся, // так всё запутано из-за того, что чтобы поднять колесо надо выоплнить // эту команду большое количество раз и за маленькое время, и чтобы колесо // держалось навису эту команду тоже надо поддерживать // принцип действия заключается в том, что мы задаём переменной $Timer //значение 25, и с каждым разом когда мы выполняем команду поднятия колеса, // от этой переменной отнимается еденица, // команда выполняется каждые 10 мс(wait 10), и когда $Timer становится //равной или меньше единицы, мы переходим к следующему действию, //поднятие уже другого колеса, но предварительно опять // задаём переменной $Timer значение 25, а то если она равна нулю, // то выполнение перекинется на поднятие другого колеса, // и так пока не будет найдено хоть одно нормальное значение $Timer $Timer = 25 REPEAT wait 10 07F5: car 4@ control_hydraulics 0.0 1000.0 0.0 0.0 $Timer -= 1 UNTIL $Timer <= 1 $Timer = 25 REPEAT wait 10 07F5: car 4@ control_hydraulics 0.0 0.0 1000.0 0.0 $Timer -= 1 UNTIL $Timer <= 1 $Timer = 25 REPEAT wait 10 07F5: car 4@ control_hydraulics 0.0 0.0 0.0 1000.0 $Timer -= 1 UNTIL $Timer <= 1 $Timer = 25 REPEAT wait 10 07F5: car 4@ control_hydraulics 1000.0 0.0 1000.0 0.0 $Timer -= 1 UNTIL $Timer <= 1 $Timer = 25 REPEAT wait 10 07F5: car 4@ control_hydraulics 0.0 1000.0 0.0 1000.0 $Timer -= 1 UNTIL $Timer <= 1 $Timer = 25 REPEAT wait 10 07F5: car 4@ control_hydraulics 1000.0 1000.0 0.0 0.0 $Timer -= 1 UNTIL $Timer <= 1 $Timer = 25 REPEAT wait 10 07F5: car 4@ control_hydraulics 0.0 0.0 1000.0 1000.0 $Timer -= 1 UNTIL $Timer <= 1 $Timer = 120 REPEAT wait 10 07F5: car 4@ control_hydraulics 1000.0 0.0 0.0 1000.0 $Timer -= 1 UNTIL $Timer <= 1 $Timer = 120 REPEAT wait 10 07F5: car 4@ control_hydraulics 0.0 1000.0 1000.0 0.0 $Timer -= 1 UNTIL $Timer <= 1 $Timer = 25 jump @Anims_3 // тут прыгаем на начало label'a , чтобы все действия
Если вытащить из машины актёра,то машина перестанет поднимать колёса.
2) Пример использование цикла FOR...END:
Давайте создадим последовательно 10 актёров на одинаковом расстоянии друг от друга,используя данный тип цикла и массив:
create_thread @Actors // создаём поток с именем Actors :Actors // начинаем поток wait 5000 // делаем задержку в 5 секунд,чтобы увидить действие цикла в игре самому var // объявляем переменные $num: Integer = 10 // это количесво актёров $actor: array 10 of Actor // это массив из 10 актёров $X: Float // координата по оси X $Y: Float // координата по оси Y end // заканчивание объявления переменных #WMOPJ.Load // объявляем нужную модель 038B: load_requested_models // загружаем модель while not #WMOPJ.Available //цикл-пока модель не загрузится,действие скрипта дальше не пойдёт wait 0 // задержка,даже нулевая,неотемлемая часть любого цикла end // конец цикла wait 0 // ждём 0 мс, желательно писать после любого цикла,на всякий случай Actor.StorePos($PLAYER_ACTOR, $x, $y, $z) // записываем коорд-ы игрока в переменные $x,$y и $z inc($y,2) // прибавляем к Y координате число 2 dec($x,3) // отнимаем от X координаты число 3 FOR $CurrentIndex = 1 TO $num // начинаем цикл создания актёра inc($x)// прибавляем к координате X число 1, // 1 - число,которое задаётся автоматически $actor[$CurrentIndex].Create(4, #WMOPJ, $x, $y, $z) //тут создаём актёра,теперь поподробнее: // $actor - имя массива актёров, // $CurrentIndex - номер элемента массива, мы номера // элементов перебираем этим циклом,сами посмотрите wait 250 //задержка - неотемлемая часть любого цикла,// если не писать, то толку от цикла не будет end // конец цикла #WMOPJ.Destroy // удаление модели из памяти
Классы
Sanny Builder допускает использование классов при написании кода. Классы - это группа опкодов, относящихся к какому-либо виду объектов в игре: игрок, актер, машина и т.д.
Все классы заранее определены в файле classes.db и изменять их в процессе кодинга невозможно. Все изменения вносятся напрямую в этот файл.
Каждый класс обладает набором команд (опкодов). Их можно разделить на несколько групп:
- условные
- процедуры (методы)
- свойства
Условные команды
Условные опкоды в списке команд, вызываемом нажатием Ctrl + [space], обозначаются словом Check. Чаще всего у них один параметр - это хендл (имя) владельца класса: машины, игрока и т.д. Например:
if Player.Defined($PLAYER_CHAR) jf @anywhere
Процедуры
Процедурные опкоды предназначены для выполнения какого-либо конкретного действия в игре: движение объекта, уничтожение его и т.п. Отдельный вид таких опкодов - это конструкторы, которые создают объект (актера, машину) и возвращают его хендл. В SB конструкторы могут использоваться как процедура, так и как свойство.
Player.Create($PLAYER_CHAR, #NULL, 2488.5601, -1666.84, 13.38) - процедура $PLAYER_CHAR = Player.Create(#NULL, 2488.5601, -1666.84, 13.38) - свойство-конструктор
Эффект будет одинаков.
Свойства
Свойства класса используются для чтения или записи каких-либо значений внутри класса. Например свойство Money класса Player позволяет оперировать с тремя опкодами:
0109: player $PLAYER_CHAR money += 1000000 010A: player $PLAYER_CHAR money > 461@ 010B: 4@ = player $PLAYER_CHAR money
После того как это свойство описано в файле classes.db вы можете использовать следующие команды:
player($PLAYER_CHAR).Money += 1000000 player($PLAYER_CHAR).Money > 461@ 4@ = player($PLAYER_CHAR).Money
В настоящий момент существует серьезное ограничение по использованию свойств в качестве операндов выражений. Sanny Builder может скомпилировать только такие выражения, которые заранее прописаны в файле classes.db. Т.е. вы не можете, например, использовать такое выражение:
player($PLAYER_CHAR).Money -= 1000000
поскольку для операции вычитания нет отдельного опкода.
Члены класса
Начиная с версии 2.6 также можно инициализировать переменные как члены класса и оперировать с ними как с классом. Например:
var
$PLAYER_CHAR: Player
end
Мы объявили переменную [COLOR=BLUE]$PLAYER_CHAR[/COLOR] как класс Player. Теперь для нее доступны все команды, какие есть для этого класса. Например:
if $PLAYER_CHAR.Defined jf @anywhere
Обратите внимание, что такие переменные будут компилироваться как первый параметр, поэтому дублировать ее не следует.
Player.SetClothes($PLAYER_CHAR, "PLAYER_FACE", "HEAD", Head) = $PLAYER_CHAR.SetClothes("PLAYER_FACE", "HEAD", Head)
Такие переменные также можно переобъявлять и изменять их тип.
Класс Model
Класс Model можно использовать при помощи имен моделей, которые всегда будут являться членами этого класса. Например, вы можете использовать следующий код:
#AK47.Load :loop wait 0 if #AK47.Available jf @loop
Это будет тоже самое что
Model.Load(#AK47) :loop wait 0 if Model.Available(#AK47) jf @loop
Расширенные названия параметров
В классах вы можете использовать текстовые названия для параметров для повышения читабельности кода. Например:
Player.SetClothes($PLAYER_CHAR, "VEST", "VEST", Torso)
Torso - это параметр типа Extended.
Для облегчения использования расширенных названий, их список для текущей команды может вызываться нажатием Ctrl + [space]. Просто установите курсор туда, где должен быть расширенный параметр, (обозначается словом Extended во всплывающей подсказке), нажмите ctrl + [space] и в редакторе появится список возможных имен с указанием числового значения для каждого из них.
Ключевые слова
Заменяют собой опкоды для простых команд. Например кейворд WAIT при компиляции будет заменен на опкод 0001. Т.е. можно писать
wait 0
вместо
0001: wait 0
Список кейвордов содержится в файле keywords.txt (свой для каждой игры). В редакторе его можно вызвать нажатием Ctrl + [space]
Дополнительные команды
INC - эта команда увеличивает значение переменной, переданной как первый параметр, на значение второго параметра. Второй параметр может не использоваться, тогда вместо него будет установлена 1.
Inc($IntVariable, $Value) = $IntVariable += $Value Inc(1@) = 1@ += 1
DEC - эта команда уменьшает значение переменной, переданной как первый параметр, на значение второго параметра. Второй параметр может не использоваться, тогда вместо него будет установлена 1.
Dec($IntVariable, $Value) = $IntVariable -= $Value Dec(1@) = 1@ -= 1
MUL - эта команда умножает значение переменной, переданной как первый параметр, на значение второго параметра.
Mul($IntVariable, $Value) = $IntVariable = $IntVariable * $Value
Второй параметр может не использоваться, тогда вместо него будет установлена 2.
Mul(1@) = 1@ = 1@ * 2
DIV - эта команда делит значение переменной, переданной как первый параметр, на значение второго параметра.
Div($IntVariable, $Value) = $IntVariable = $IntVariable / $Value
Второй параметр может не использоваться, тогда вместо него будет установлена 2.
Div(1@) = 1@ = 1@ / 2
(sys) ALLOC* - эта команда устанавливает адрес памяти для переменной. Должна использоваться только для переменных с ТЕКСТОВЫМИ именами. Для остальных адрес памяти устанавливается по их имени: переменная $40 всегда будет иметь ячейку памяти #40.
Alloc($MyVar, 40) - переменная $MyVar будет иметь адрес 40.
- команды, обозначенные словом (sys), не отражаются в коде, а являются вспомогательными для компилятора.
SQR - эта команда вычисляет квадрат значения (вторую степень) переменной, переданной в качестве параметра.
sqr($var) = $var *= $var
Тип переменной должен быть определен.
RANDOM - эта функция возвращает случайное число в интервале, указанном параметрами.
$rnd = random(1, $high)
Данную функцию можно использовать как для типа Integer, так и для типа Float. Выбор опкода будет зависеть от типа объявленной переменной, в которую записывается случайное значение ([color=blue]$rnd[/color]).
HEX..END
Данная конструкция предназначена для прямой записи шестнадцатиричных значений в SCM или IMG файл*. Например:
hex 04 00 02 0800 04 01 end
0004: $2 = 1
В качестве значений в данной конструкции можно указывать метки и глобальные переменные. Они будут компилироваться как числа, без указания типа данных.
:get_offset hex 04 00 02 $PLAYER_CHAR 01 @get_offset end
0004: $PLAYER_CHAR = @get_offset
Также можно использовать в конструкции hex..end тип aDMA. Это удобно использовать для записи чисел. Число после знака & может быть как положительным, так и отрицательным; как в десятичном, так и в шестнадцатиричном формате.
hex &1000 &-0xA33500 end
Также можно компилировать строковые значения. Для этого заключите слово в двойные кавычки ([color=red]"..."[/color]) и поставьте перед ними пробел.
Например,
hex 09 "Word1" 20 "Word2" end
Допускается написание только одного слова в кавычках. Для записи фразы оформите каждое слово в кавычки. Для компиляции пробела поставьте между словами число 20 (ASCII код символа пробел).
- Рекомендуется только для опытных скриптеров. Любые ошибки повлекут невозможность последующего декомпилирования файла и чтения его игрой.
Директивы
Препроцессорные директивы - это специальные слова, которые указывают компилятору на необходимое поведение в процессе компиляции. Они обозначаются символом $, а также заключены в фигурные скобки {}.
Список доступных директив:
- $VERSION
- $VERSION_RESTORE
- $INCLUDE
- $EXTERNAL
- $CLEO
$VERSION
Данная директива указывает компилятору, какую версию опкодов необходимо использовать из INI-файла (SASCM.INI, VICESCM.INI и т.д.). В настоящий момент INI-файлы содержат только одну версию опкодов, поэтому данная директива может не использоваться.
Синтаксис:
$VERSION x.y.zzzz x - код игры. 1 - gta3; 2 - vc; 3 - sa; 4 - lcs; 5 - vcs; y - вид порядка следования параметров в опкоде. 0 - оригинальный (параметры в INI идут последовательно 0, 1, 2 и т.д.) 1 - неоригинальный (параметры в INI идут непоследовательно 2, 0, 1, и т.д.) zzzz - код версии файла
По умолчанию компилятор использует версию:
<текущий режим редактирования>.1.0000
$VERSION_RESTORE
Данная директива восстанавливает прежнюю версию, которая была до использования директивы $VERSION. В настоящий момент INI-файлы содержат только одну версию опкодов, поэтому данная директива может не использоваться.
Основная идея состоит в том, чтобы позволить одновременно компилировать куски кода, написанные на разных версиях опкодов, путем заключения их в данные директивы.
[color=green]{$VERSION 3.1.0001}[/color] ... <код, написанный на версии 0001> .... [color=green]{$VERSION 3.1.0000}[/color] ... <код, написанный на версии 0000> .... [color=green]{$VERSION_RESTORE}[/color] [color=navy]// восстанавливаем версию 0001[/color] ... <код, написанный на версии 0001> ....
$INCLUDE
Эта директива позволяет подключать внешние текстовые файлы к исходнику. Когда компилятор находит указанную директиву, он открывает файл по адресу, переданному в качестве параметра директивы и продолжает компиляцию того кода, который записан во внешнем файле. Когда компилятор достигает конца данного файла, он возвращается обратно в предыдущий файл.
Синтаксис:
[color=green]{$INCLUDE file_path}[/color]
или
[color=green]{$I file_path}[/color]
Например,
[color=green]{$I loadwav.txt}[/color]
или
[color=green]{$I C:\dev\getarrayindex.txt}[/color]
Если в имени файла указан относительный путь, компилятор ищет файлы в следующем порядке:
- папка, где находится файл, содержащий данную директиву
- Sanny Builder\data\<game>
- корневая папка Sanny Builder'а
- корневая папка игры
Если ни в одной из указанных папок не содержится такой файл, компилятор сообщит об ошибке.
Вы можете использовать данную директиву неограниченное число раз. Вкладываемые файлы могут также содержать в себе данную директиву.
$EXTERNAL
Данная директива заставляет скомпилировать файл как внешний скрипт. Это означает, что получившийся файл будет без заголовка и с локальными метками, т.е. полным аналогом scm-файлов из файла script.img. Использование данной директивы подразумевает, что в скрипте будет только один поток (также без миссий и внешних скриптов). Аналогом использования данной директивы является опция SKIP_SCM_HEADER. Данную опцию также можно переключить на главной панели инструментов. Вместо $EXTERNAL можно использовать короткий вариант $E.
Синтаксис:
[color=green]{$EXTERNAL}[/color]
или
[color=green]{$E}[/color]
$CLEO
Данная директива является аналогом директивы $E, однако полученный файл автоматически копируется в директорию ‘игра\CLEO’, и получает расширение, указанное в директиве.
Синтаксис:
[color=green]{$CLEO <расширение файла>}[/color]
Например,
[color=green]{$CLEO .cm}[/color]
или
[color=green]{$CLEO}[/color] [color=navy]// файл получит расширение по умолчанию - .cs[/color]
Таким образом, данная директива является идеальным решением для написания CLEO-скриптов