# 00054. Внешние скрипты в main.scm

Внешние скрипты в main.scm|Начинаем новый урок по Sanny Builder. И на этот раз мы рассмотрим внешние скрипты.|wmysterio|wmysterio||||Всем привет! Что значит"внешние"? Это те скрипты, которые загружаются из файлы "script.img". Например: скрипт авто-тюнинга, парашюта или казино. Сегодня мы создадим один такой скрипт и рассмотрим основные опкоды для загрузки таких скриптов.

Прежде всего нужно написать сам скрипт ( пишутся как и обычные потоки в мейне ). Для примера у меня будет внешний скрипт, суть которого заключается в том, что когда машина игрока перевернута, то при нажатии кнопки CTRL\` машина будет перекидываться обратно на колёса.

Прежде всего напишем поток ":NOFLIP". И переместим его в самый конец мейна ( все внешние скрипты пишутся после блока с миссиями ). Вот сам код:

```
:NOFLIP
thread 'NOFLIP'
wait 0

while actor.Driving($PLAYER_ACTOR)
wait 0
 03C0: 0@ = actor $PLAYER_ACTOR car
 if
 01F4: car 0@ flipped
 then
 if
 0AB0: key_pressed 17 // CTRL
 then
 00A0: store_actor $PLAYER_ACTOR position_to 1@ 2@ 3@
 4@ = car.Angle(0@)
 car.PutAt(0@, 1@, 2@, 3@)
 car.Angle(0@) = 4@
 end
 end
end

end_thread
```

Можно было и запустить этот поток командой "create\_thread", но раз мы учимся создавать внешние скрипты, то мы запускать его мы будем иным образом. Прежде всего нужно объявить этот поток как внешний. Находим стоку вначале мейна:

```
DEFINE EXTERNAL_SCRIPTS 0
```

Меняем значение 0 на 1, это указывается общее количество внешних скриптов. Так, как мы планируем создать новый внешний скрипт, то значение нужно прибавить. Далее нужно написать сам потом и дать имя нашему внешнему скрипту. Сразу после этого допишем строку:

```
DEFINE SCRIPT NO_FLIPPED AT @NOFLIP // 0
```

Здесь:\
NO\_FLIPPED - имя нашего внешнего скрипта\
@NOFLIP - указываем метку с которой будет начинаться сам скрипт\
// 0 - это обычный комментарий, но я специально его написал, так как каждый скрипт имеет свой номер, счёт которых начинается с нуля. Дальше вы увидите зачем я это сделал.

Таким образом мы получим:

```
DEFINE EXTERNAL_SCRIPTS 1
DEFINE SCRIPT NO_FLIPPED AT @NOFLIP // 0
```

Теперь рассмотрим основные опкоды для работы внешних скриптов. Опкод записует в переменную текущий статус внешнего скрипта:

```
0926: $SCRIPT_STATUS = external_script_status 0 (NO_FLIPPED) // return 0 if not active
```

Далее:

```
08A9: load_external_script 0 (NO_FLIPPED)
```

Опкод загружает внешний скрипт.

```
08AB: external_script 0 (NO_FLIPPED) loaded
```

Проверка: "Внешний скрипт загружен?"

```
0913: run_external_script 0 (NO_FLIPPED)
```

Опкод запускает внешний скрипт.

```
090F: end_external_script 0 (NO_FLIPPED)
```

Опкод выгружает с памяти внешний скрипт ( завершает его ).

Здесь:\
0 - номер внешнего скрипта\
NO\_FLIPPED - указываем имя нашего внешнего скрипта<br>

Это основные команды. Давайте теперь напишем поток, который будет запускать, написанный нами, внешний скрипт. Создадим поток с именем ":TRIGGER" и напишем необходимые условия:

```
:TRIGGER
thread 'TRIGGER'
wait 0
0926: $SCRIPT_STATUS = external_script_status 0 (NO_FLIPPED)
if AND
actor.Driving($PLAYER_ACTOR)
$SCRIPT_STATUS == 0
then
 if
 08AB: external_script 0 (NO_FLIPPED) loaded
 then
 0913: run_external_script 0 (NO_FLIPPED)
 else
 08A9: load_external_script 0 (NO_FLIPPED)
 jump @TRIGGER
 end
end

:TRIGGER_3_1
wait 0
090F: end_external_script 0 (NO_FLIPPED)
jump @TRIGGER
```

Как видите сначала мы запишем в переменную статус внешнего скрипта, дале мы проверяем: "СЖ в машине?" и "внешний скрипт отключен?". Если эти условие выполняются, то проверяем "Внешний скрипт загружен?". Если скрипт не загружен, то загружаем его, и так дальше, пока скрипт всё таки не загрузится. После загрузки идёт старт внешнего скрипта опкодом **0913**. Дальше игра ждёт окончания потока ":NOFLIP". То есть, когда СЖ выйдет с тачки, то поток завершится, а затем и завершится внешний скрипт опкодом **090F**.

Теперь запускаем поток ":TRIGGER" командой "create\_thread" из потока "MAIN". В результате мы получили неплохую палочку-выручалочку. Теперь машина всегда будет под вашим контролем ;) Вот код мейна: [main.txt](https://github.com/wmysterio/scm-scripting-lessons/blob/main/data_base/sa/EXTERNAL.txt). Это один из самых простых примеров, по этому разобраться в них думаю сложно не будет.

Теперь поговорим о том, зачем они нужны. Я сначала не понимал зачем они вообще нужны. Работал только с обычными потоками. Но вдруг игра начала сильно тормозить. Я не мог понять с чего это вдруг. Потом увидел статью о внешних скриптах и попробовал сделать несколько. На моё удивление, игра перестала тормозить. Как оказалось, игра выделяет дополнительную память под внешние скрипты, что значительно увеличивает быстродействие.

Особенно помогает, если в потоке идёт очень много проверок и арифметических операций. Максимальное количество внешних скриптов - 70 ( одновременно работающих ), то есть мы так же получаем дополнительный бонус в потоках ( 70+96=166 ) 166 штук!!! Однако не стоит злоупотреблять этим, поэтому старайтесь максимально снизить количество потоков. Например, не нужно делать потоки для каждого внешнего скрипта, а стараться объединять их в один.

И напоследок рассмотрим ещё несколько полезных опкодов:

```
07D3: 'HOUSE' = init_external_script_named_handle 23 (BURG_BRAINS)
0884: 'DANCER' = init_external_script_named_handle 52 (DANCER)
```

Внешние скрипты инициализируются как строки ( задают им строковые имена ( не больше 7 символов! ) ). Привязываются к интерьеру, однако точный принцип работы этих опкодов я точно не знаю.

```
0928: init_external_script_trigger 19 (DEALER) with_actor_model #BMYDRUG priority 100
08E8: assign_external_script_handle 'DEALER' to_model #BMYDRUG
```

Внешний скрипт будут выполнять актёры с определённой моделью. В оригинальном мейне эти опкоды идут в паре. Здесь:

Здесь:\
\#BMYDRUG - модель актёра, который будет выполнять действия во внешнем скрипте\
'DEALER' - строковое имя скрипта\
19 (DEALER) - номер и имя скрипта\
100 - приоритет в процентах ( целое число )<br>

```
0929: init_external_script_trigger 7 (ARCADE) with_object_model #CJ_COIN_OP_3 priority 100 radius 4.0 type -1
```

Внешний скрипт привязывается к объекту.

× \*\*Примечание:\*\* опкоды 08E8, 0928 и 0929 не требуют запуска. Они запускаются автоматически× \*\*ВАЖНО:\*\* Если Вы добавили внешний скрипт, то компилировать его нужно после выхода с игры ( полностью )!

P.S Попробуйте тоже сделать какой-то примитивный внешний скипт, чтобы попрактиковаться. На этом урок окончен. Спасибо за внимание! :)|1621|1|0||vneshnie\_skripty\_v\_main\_scm|1499523457
