SCM
Материал из GTAModding.ru
Версия от 20:42, 30 августа 2010; Seemann (обсуждение | вклад)
Игровые скрипты заключены в файле main.scm. Данный файл представляет собой нетипизированный бинарный файл с определенной структурой. При декомпиляции получается исходный файл, строение которого выстроено в точности по данной структуре.
Содержание |
Общая структура
Нас будет интересовать прежде всего строение текстового исходника, поскольку работа с бинарным, скомпилированным файлом прерогатива декомпилятора. Итак, какое строение должен иметь типичный исходник, чтобы быть успешно скомпилированным в рабочий main.scm.
Файл main.scm состоит из следующих частей:
- заголовок
- «майн»
- миссии
Заголовок
В самом верху исходного файла вы можете увидеть заголовок. Он представляет собой набор полей, определяющих часть структуры заголовка. Каждое поле начинается со слова DEFINE.
Первой частью заголовка является сегмент (или блок) моделей. Он начинается со строки
DEFINE OBJECTS 389
Слово DEFINE указывает на то, что эта строка – часть заголовка. OBJECTS указывает на то, что мы определяем размер сегмента объектов, а точнее – число объектов, чьи названия будут указаны ниже. 389 – число этих объектов (число может отличаться в разных исходниках). Допустимые значения – положительные числа и ноль. Смотрите также Лимиты объектов.
После этой строки перечисляются имена объектов.
DEFINE OBJECT INFO // Object number -1
Слово OBJECT указывает компилятору, что данная строка содержит имя импортируемой модели. Особенностью данных моделей является то, что они не требуют загрузки при использовании, а обращение к ним в скрипте происходит не по их реальному ID, а по порядковому номеру, который указан в комментарии (-1). Например,
0213: $PICKUP_INFO_HOSPITAL = create_pickup #INFO type 3 at 2027.77 -1420.52 16.49
или
0213: $PICKUP_INFO_HOSPITAL = create_pickup -1 type 3 at 2027.77 -1420.52 16.49
[color=brown]INFO[/color] – имя DFF-модели из gta3.img или другого архива.
Самая первая модель в списке не используется игрой.
Обратите внимание, что данный сегмент заголовка опционален и не обязателен к указыванию. Если вы не укажете какие модели следует компилировать как импортируемые, компилятор сделает это за вас, когда будет обнаруживать использование имен моделей в скрипте, чьи имена не содержатся в IDE-файлах (модели из IDE-файлов можно использовать по их ID, не требуется указывать их в заголовке). См. также: Объекты (SA).
Второй частью заголовка является сегмент миссий. Он начинается со строки
DEFINE MISSIONS 135
Здесь указывается, какое число миссий будет присутствовать в данном исходнике. Компилятор будет искать именно заданное число миссий и если их будет меньше или больше возникнет ошибка.
После указания общего числа миссий следует перечисление миссий:
DEFINE MISSION 0 AT @INITIAL // Initial 1
Разберем данную строку. После слова DEFINE стоит слово MISSION, указывающее что здесь определяется начало миссии. После него стоит порядковый номер миссии. Этот номер используется в опкоде start_mission. После слова AT вы должны указать метку миссии, с которой она начнется.
На этой строке может также стоять комментарий с названием миссии из оригинального main.scm. Вы можете отключить показ оригинальных имен миссий в опциях программы. См. также Создание миссии в SA.
Указанные выше части заголовка являются общими для всех игр, поддерживаемых Sanny Builder’ом. Следующие части заголовка указываются только для игры San Andreas.
DEFINE EXTERNAL_SCRIPTS 78 // Use -1 in order not to compile AAA script
В данной части заголовка определяются внешние скрипты. После слова EXTERNAL_SCRIPTS указывается общее число внешних скриптов. В исходном файле эти скрипты должны располагаться сразу после всех миссий. Как и в случае с последними, компилятор будет искать заданное количество скриптов.
Обратите внимание, что внешние скрипты имеют в своем составе особый скрипт с названием AAA. Содержимое этого скрипта заполняется компилятором и делается это исключительно с целью максимального соответствия оригинальным файлам игры. Если вы указываете число EXTERNAL_SCRIPTS как 0, скрипт AAA тем не менее будет скомпилирован. Для того чтобы не делать этого, укажите в качестве значения число -1. Тогда script.img вообще не будет создаваться.
Версия 3.0 позволяет также перезаписать скрипт AAA. Для этого создайте свой собственный скрипт и назовите его этим именем.
Определение внешнего скрипта происходит в строке
DEFINE SCRIPT PLAYER_PARACHUTE AT @PLCHUTE // 0
Здесь PLAYER_PARACHUTE – имя скрипта в файле script.img. [color=green]@PLCHUTE[/color] – имя метки с которой начинает тело скрипта.
В комментарии указан порядковый номер скрипта, который используется в опкодах, например:
08A9: load_external_script 0
После сегмента внешних скриптов идут еще два блока, назначение которых неизвестно. Скорее всего игра не использует эти значения.
DEFINE UNKNOWN_EMPTY_SEGMENT 0 DEFINE UNKNOWN_THREADS_MEMORY 574
Если вы пользуетесь урезанным скриптом (stripped.txt) без миссий и скриптов, вы можете не указывать заголовок совсем.
Шаблон заголовка можно вызывать в редакторе, используя макрос headsa или headvc.
Главная часть
Сразу после заголовка идет основной блок скрипта, именуемый майном. Здесь находятся все потоки, которые создаются и работают во время игры. Начало майна обозначено комментарием
//-------------MAIN---------------.
Майн состоит из набора отдельных потоков. Самым первым потоком, который автоматически запускает игра, является поток MAIN (начинается с опкода 03A4: name_thread 'MAIN'). Все остальные потоки активируются уже из данного потока опкодами 004F или 00D7 (обратите внимание, эти опкоды по сути одинаковы, только 004F еще дополнительно может передавать в создаваемый поток параметры). Замечание по поводу создания потоков из MAIN верно только для новой игры. При загрузке сейва игра уже сама восстанавливает ранее созданные потоки.
Потоки состоят из опкодов, выражений и меток. Также при компиляции в скрипте могут встречаться конструкции (VAR..END, CONST..END, FOR..END и т.д.) и директивы, которые служат исключительно для удобства работы с кодом (cм. Кодинг в Sanny Builder 3). После компиляции эти конструкции так или иначе преобразуются в опкоды, выражения или метки.
Опкод
Опкод – (OpCode - Operation Code - код операции) - число, обозначающее одну из инструкций для парсера скриптов игры и указывающее на определенную последовательность действий, которые необходимо выполнить с учетом переданных параметров.
Например, 0001 это код операции wait, которое указывает машине, что нужно приостановить выполнение потока на число миллисекунд, переданных как параметр этого опкода. Все опкоды хранятся в INI-файле.
Выражение
Выражение – это опкод с математической или логической операцией. Например,
$var += 1 10 < 5@ &10 = 0
и т.д. Некоторые выражения могут писаться без указания номера опкода (как в примере выше). Логические выражения (условия) используются для проверки каких-либо значений.
Метка
Метка – это идентификатор, обозначающий позицию в скрипте. Имя метки должно быть уникальным. По своей сути это число, обозначающее смещение от начала майна или миссии до того места, где стоит метка. В коде она обозначается символом :
:MAIN_177
Сами по себе метки бесполезны, если их не используют. Под использованием метки понимается переход на нее в одном из специальных опкодов. Существуют два вида перехода на метку: условное и безусловное. Безусловный переход осуществляется опкодами jump, gosub.
jump @MAIN_177
Обратите внимание, что имя метки для перехода обозначается символом [color=green]@[/color] в начале. При включении автоматического списка, редактор будет выводить список используемых меток в коде.
Когда игра достигнет этого опкода, она сразу перейдет на то место в скрипте, где стоит метка (:MAIN_177
Отличительной особенностью команды gosub является то, что после перехода на метку игра может (и должна) вернуться обратно после того, как встретит команду return.
… gosub @MAIN_177 $var += 1 … :MAIN_177 $var = 1 return
$var = 1
$var += 1
Условный переход в отличие от безусловного осуществляется только при определенном условии. Для этого используется опкод jump_if_false (jf). Он является составной частью любого условия в скриптах.
00D6: if 08AB: external_script 75 loaded 004D: jump_if_false @MAIN_4492 0913: run_external_script 75
В данном примере сначала проверяется загружен ли в память внешний скрипт 75. После опкода 08AB: состояние условия будет либо правдивым (True) либо ложным (False), в зависимости от того, загружен скрипт или нет. Состояние условия определяет два различных поведения игры после проверки условия. Если условие было правдивым (т.е. скрипт был загружен) игра пропустит опкод jump_if_false. Следующим шагом, таким образом, станет опкод 0913.
Если условие было ложным (т.е. скрипт не был загружен) игра выполнит опкод jump_if_false и перейдет на метку@MAIN_4492
Собственно из перевода слов jump_if_false видно, что это переход, если ложь.
Майн заканчивается там, где начинаются миссии.
Миссии
Блок миссий начинается с метки нулевой миссии из заголовка (в оригинале [color=green]:INITIAL[/color]). Обычно там стоит комментарий
//-------------Mission 0---------------.
Особенностью миссий является то, что в игре может одновременно быть запущена только одна миссия. После команды start_mission игра полностью загружает тело миссии в отдельную область памяти, после чего начинает работать с ним как с обычным потоком из майна. Все сказанное по поводу опкодов, выражений и меток в майне действительно и для миссий. Миссия как и обычный поток заканчивается командой end_thread.
Все миссии в исходном файле должны идти в той же последовательности, что и в заголовке файла. Миссия должна идти одним блоком, не допускается вложение части одной миссии в тело другой.
Внешние скрипты
В San Andreas’е часть игровых скриптов вынесена в отдельный файл script.img. Он состоит из набора небольших scm-файлов. Их отличие от главного main.scm заключается в отсутствии заголовка.
При декомпиляции эти скрипты добавляются в конец исходника, составляя таким образом четвертую его часть. Таким образом началом данного блока является конец блока миссий. Там должна стоять метка первого внешнего скрипта (если таковые используются). Обычно там стоит комментарий
//-------------External script 0 (PLAYER_PARACHUTE)---------------.
Внешний скрипт представляет собой обычный поток со своими опкодами, выражениями и метками. Этот поток загружается в отдельную область памяти.