00059. Подключение текстовых файлов, scm-функции

Подключение текстовых файлов, scm-функции|Сегодня мы рассмотрим одну из интереснейших тем - создание SCM-функций.|wmysterio|wmysterio||||Здравствуйте, дорогие друзья. Начинаем очередной урок по скриптингу. Использование функций очень удобно, когда нужно выполнять один и тот же код несколько раз. Действуют функции по аналогии с gosub, только в функции можно передавать параметры. Есть два опкода для работы с функциями:

0AB1: call_scm_func @GetSQR 1 10 $result

Здесь: @GetSQR - указывается метка, где будет выполнятся функция 1 - количество передаваемых параметров 10 - это сами параметры $result - результат выполнения функции ( если такой есть )

0AB2: ret 1 0@

Здесь: 1 - количество возвращаемых параметров 0@ - сами параметры

Давайте напишем саму функцию:

:GetSQR
wait 0
006A: 0@ *= 0@ // (int)
0AB2: ret 1 0@

Обратите внимание, что передаваемые параметры имеют переменные 0@, 1@, 2@ и так до 32-х штук. Но они не влияют на переменные в самом потоке. То есть если у нас был раньше актёр в переменной 0@, то после выполнения функции он так и останется в ней. Рассмотрим лучший пример:

:LABEL
thread 'LABEL'
wait 0 
0AB1: call_scm_func @SPAWN_ACTOR 4 spawn_at -1390.0 14.0 39.0 angle 180.0 $ACTOR
05E2: AS_actor $ACTOR kill_actor $PLAYER_ACTOR
end_thread
 
:SPAWN_ACTOR
wait 0
model.Load(#WMYDRUG)
038B: load_requested_models

:SPAWN_ACTOR_1
wait 0
if
model.Available(#WMYDRUG)
jf @SPAWN_ACTOR_1
4@ = actor.Create(4, #WMYDRUG, 0@, 1@, 2@)
actor.Angle(4@) = 3@
model.Destroy(#WMYDRUG)
0AB2: ret 1 4@

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

Запускаем игру - отлично! Созданный нами актёр хочет убить нас, что и нужно было доказать :)

Один интересный факт насчет опкода 0AB1. Как видите, в нём мы можем дописывать различные строки, например: "pawn_at" и в любых местах. Компилятору будет по-барабану :) Даже если функция будет написана так:

0AB1: @SPAWN_ACTOR 4 2475.1167 -1674.4192 13.3368 287.7152 $ACTOR

Главное, что бы были параметры и метка ;)

"Зачем это нужно?" - Спросите Вы. Ведь функцию всё равно нужно будет писать каждый раз в скрипте. Естественно можно и обойтись без функций, но что если нужно одну и туже функцию применять в 2-х разных скриптах? Зачем писать их две штуки, если можно написать только одну, которая будет хранится в файле! Мы только подключим его в нужный скрипт и будем использовать функцию.

Подключение файла напоминает команду из языка программирования C/C++: #include "file.h", только здесь нужно писать так:

{$I file.txt}

Здесь: $i - указываем компилятору, что нужно подключить файл ( include ) file.txt - название файла. Расширение может быть любое, но в нём должен быть текст, то есть что бы мы могли его редактировать блокнотом и прочими текстовыми редакторами

Поиск файла ведётся относительно следующих папок:

  • Папка, где находится файл, содержащий данную директиву;

  • Папка Sanny Builder\data\<game>

  • Корневая папка Sanny Builder;

  • Корневая папка игры;

Давайте создадим текстовый файл "function.txt" в папке с "gta_sa.exe". Открываем файл. Копируем код функции с SB в текстовый файл. После этого очищаем скрипт от кода функции. В скрипте должно быть только эти строки:

{$CLEO}
{$I function.txt}

:LABEL
thread 'LABEL'
wait 0 
0AB1: call_scm_func @SPAWN_ACTOR 4 spawn_actor_at 2475.1167 -1674.4192 13.3368 angle 287.7152 $ACTOR
05E2: AS_actor $ACTOR kill_actor $PLAYER_ACTOR
0A93: end_custom_thread

Сохраняем файл "function.txt" и пытаемся скомпилировать скрипт. В нас ошибка: "Переход на нулевой оффсет". Давайте поставим опкод "0000". Та же ошибка! Что делать? А спасёт нас оператор goto. Действует он точно как и "jump". Нам нужно отредактировать текстовый файл. Для этого создадим метку ":SPAWN_ACTOR_END" в самом конце файла "function.txt". А в самом верху, перед меткой ":SPAWN_ACTOR" делаем переход с помощью оператора "goto". Таким образом содержимое "function.txt" будет таково:

goto @SPAWN_ACTOR_END // начало "обёртки" функции
:SPAWN_ACTOR
wait 0
model.Load(#WMYDRUG)
038B: load_requested_models

:SPAWN_ACTOR_1
wait 0
if
model.Available(#WMYDRUG)
jf @SPAWN_ACTOR_1
4@ = actor.Create(6, #WMYDRUG, 0@, 1@, 2@)
actor.Angle(4@) = 3@
model.Destroy(#WMYDRUG)
0AB2: ret 1 4@
:SPAWN_ACTOR_END // конец "обёртки" функции

Думаю постоянно метку писать как то неудобно, да большинство из них можно и не запомнить а постоянно открывать файл ещё неудобнее. Поэтому давайте дадим имя метки с помощью констант:

const
spawn_actor = @SPAWN_ACTOR
end

и добавим этот текст в начало файла "function.txt". Теперь сама функция может иметь такой вид:

0AB1: spawn_actor 4 at 2475.1167 -1674.4192 13.3368 angle 287.7152 handle $ACTOR

Как видите мы сократили длину функции, что очень удобно и легко запоминается! Теперь эту функцию можно использовать в любом скрипте, подключив этот файл :)

× **Примечание:** испольховать такие константы в крупных проектах проблематично, по-этому рекомендую использовать метки× **ВАЖНО:** функции нужно объявлять в начале скрипта и только потом писать его код

Задания!

  • Написать две функции:

  • Функция считывает цвета машины и заносит их в ini-файл "color.ini";

  • Функция устанавливает цвета машины, используя параметры ini-файла "color.ini";

  • Написать скрипт, что бы каждая новая машина, в которую входит СЖ, меняла свои цвета на цвета предыдущей машины;

Посмотрите на картинку выше. На ней есть незначительная ошибка. Тот, кто первый найдёт её - получит + к репутации :D|1496|1|0|36274742png1171564399`192``||podkljuchenie_tekstovykh_fajlov_scm_funkcii|1499599651

Last updated