> For the complete documentation index, see [llms.txt](https://lessons.sannybuilder.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lessons.sannybuilder.com/00100/00300/0009.-redaktirovanie-main.scm.-potoki-i-opkody-chast-1.md).

# 0009. Редактирование main.scm. Потоки и опкоды (Часть 1)

Редактирование main.scm. Потоки и опкоды (Часть 1)|В этом уроке мы ознакомимся с базовыми понятиями скриптов: потоками, командами, метками, прыжками и задержкой. Будет введено понятие опкода.|wmysterio|wmysterio||||Для начала сделаем резервную копию игровых файлов. А именно **main.scm** и\*\* script.img\*\*. Найти их можно в папке с игрой: "Игра\data\script".

Теперь открываем Санни Билдер. И нажимаем "Файл->Открыть" и указываем "main.scm" ( не забывайте в скобках указать формат "SCM", иначе нужного файла не найти ). Открыли? Хорошо. Видите сколько строк? Дух захватывает правда? А представьте, что это всё напечатали вы! Если у Вас будет упорство и терпение, то всё вполне реально, хотя как правило обходится всё меньшим количеством кода. Но раз мы хотим что то сделать самим, то давайте выделим всё и нажмем кнопку DEL\`. Чистый лист! Какое облегчение! Теперь можно делать что то своё! Но для минимальной работы скрипта, нужно указать некоторую необходимую информацию. Скопируйте эти строки:

```

// This file was decompiled using sascm.ini published by Seemann (http://sannybuilder.com/files/SASCM.rar) on 13.10.2007
// WMYSTERIO, ru-script.3dn.ru
DEFINE OBJECTS 0 

DEFINE MISSIONS 0

DEFINE EXTERNAL_SCRIPTS 0

DEFINE UNKNOWN_EMPTY_SEGMENT 0

DEFINE UNKNOWN_THREADS_MEMORY 574

//-------------MAIN---------------

thread 'MAIN'
set_wb_check_to 0
set_weather 0
select_interior 0
fade 1 0
0180: set_on_mission_flag_to $ONMISSION
00C0: set_current_time_hours_to 8 minutes_to 0
04E4: unknown_refresh_game_renderer_at 2491.1572 -1670.3434
Camera.SetAtPos(2491.1572, -1670.3434, 12.3359)
$PLAYER_CHAR = Player.Create(#NULL, 2491.1572, -1670.3434, 12.3359)
$PLAYER_ACTOR = Actor.EmulateFromPlayer($PLAYER_CHAR)
Actor.Angle($PLAYER_ACTOR) = 66.3548
07AF: $PLAYER_GROUP = player $PLAYER_CHAR group
Camera.SetBehindPlayer
Player.Build($PLAYER_CHAR)
Player.CanMove($PLAYER_CHAR) = true
end_thread
```

Затем нажмите кнопку F7`. Запустите игру ( <kbd>F8` ), обязательно нажимаем "НОВАЯ ИГРА"! Посмотрите что изменилось. Думаю большинство заметило, что нету вступительного ролика и прочего. Такой мейн называется "Чистым".

× \*\*ВАЖНО:\*\* При редактировании потоков начинать новую игру обязательно.

Начнем с потоков думаю. Я не буду выражаться какими то сложными выражениями. Скажу только несколько слов о них. Я назову это отдельным блоком, в котором делаются некоторые действия. Каждый поток имеет свое имя, как и каждый человек. Нельзя создать два потоки с одинаковыми именами и длиной больше 15 символов. Рекомендую брать пример с оригинального "main.scm", где длина потока составляет не больше 7 символов. Лучше делать так, как это делали разработчики игры.

× \*\*Примечание:\*\* Названия потоков должно состоять только с латинких символов, чисел и символа \*\*\_\*\*

Как же создать поток? Для начала изучим правила написания потока. Каждый поток начинается командой:

```
thread 'POTOK' // POTOK - это имя нашего потока
```

и заканчивается командой ( команда завершения или деактивации ):

```
end_thread // команда завершения потока
```

Это очень легкие команды, думаю за небольшой промежуток времени вы запомните их.

Что такое метка? На этот вопрос я очень легко могу ответить, и этот ответ станет основой скриптинга, поэтому запоминайте.

1. \- Как узнать метку и её создать? Создание метки очень просто. Нужно написать сначала символ \*\*:\*\* а затем ввести имя метки. Вот пример:
2. ```
   :METKA
   ```
3. Узнать метку можно за правилами написания, о котором я написал выше. Принято писать метки с теми именами, что и поток, далее уже после имени потока добавляют несколько чисел или букв. С техничекой точки зрения метка - это смещение в файле "main.scm" и представляет собой обычное число. В прочем, для нас это не важно, так как Sanny Builder все эти смещения высчитывает самостоятельно, основываясь на наших метках.
4. *
5. Пример написания потока и и его меткок:
6. ```
   :POTOK
   thread 'POTOK'

   :POTOK_1

   :POTOK_2

   :POTOK_3

   end_thread
   ```
7. Весь скриптинг основан на построчном считывании информации. То есть одна команда - одна строка. В примере показано, что сначала будет выполняться команды от метки ":POTOK\_1", затем ":POTOK\_2" и вконце ":POTOK\_3". Естественно можно изменить порядок выполнения меток, не изменяя их положения. Для этого служит команда **jump**. Если перевести дословно, то это значит прыжок. Далее мы будем использовать именно это выражение. Что же, давайте напишем пример, где используются прыжки:
8. ```
   :POTOK
   thread 'POTOK' 
   jump @POTOK_4

   :POTOK_1
   jump @POTOK_3

   :POTOK_2
   jump @POTOK_5

   :POTOK_3
   jump @POTOK_2

   :POTOK_4
   jump @POTOK_1

   :POTOK_5
   end_thread
   ```
9. Сложновато, правда? Далее будет ещё сложнее. Особенно если вы решили увидеть чужой скрипт. :) Но не будем о грустном! Разобраться не так уже и сложно. Давайте представим маленький шарик. Представили? Назовём его "Указатель". Нет, пусть будет просто "Шарик" :) Этому шарику предстоит пройти определенный путь. Начинает путь наш шарик с имени потока, то есть с команды "thread", и начинает идти вниз. Используя прыжки ( jump ) можно нарисовать путь прохождения шарика. Я уже нарисовал путь. Вот по примеру должно примерно так получится:
10. ![](https://github.com/wmysterio/scm-scripting-lessons/raw/resources/_pu/0/06743791.png)
11. Итак, вы увидели шарика. Оранжевым указано куда именно я направлял шарика. Я специально загрузил этот рисунок, что бы вам легче было представить себе принцип работы скриптов. Если шарик достиг места финиша, то он автоматично отправляется на заслуженную пенсию и больше использоваться в потоке не будет, пока его не вызовут опять на службу. :)
12. Как запустить поток и что нужно для его правильной работы? Хороший вопрос. Особенно интересно слово "правильной"! Что же, думаю самое время познакомиться с опкодами! Это наши верные помощники! Так и будем называть их, потому что они помогают выполнить кое-какие действия. Для правильной работы нам нужно запомнить помощника по имени **0001:**, то есть опкод:
13. ```
    0001: wait 0 ms // 0 - это задержка
    ```
14. Он обычно стоит после названия метки. Они там должны находится не всегда, а только в в случаи необходиомости, например в циклах ( будет рассматриваться в следующих уроках ). Но в целях обучения мы будем располагать опкод после каждой метки.
15. С новой версией СБ и Клео, в целях удобства, ему присвоили статус команды ( так званный кейворд ), и мы можем писать просто
16. ```
    wait 0 // 0 - это задержка
    ```
17. Технически разницы между опкодами и командами нету - команда имеет упрощённый синтаксис, но в процессе преобразования заменяется на опкод. **Опкод** - это операционная код ( команда ).
18. Что бы запустить наш поток, то есть призвать нашего шарика на старт, используется такая команда:
19. ```
    create_thread @POTOK // POTOK - имя потока, который нужно запустить
    ```
20. Она, собственно, делает поток активным. Таким образом, пишем правильный запуск потока:
21. ```
    // This file was decompiled using sascm.ini published by Seemann (http://sannybuilder.com/files/SASCM.rar) on 13.10.2007
    // WMYSTERIO, ru-script.3dn.ru
    DEFINE OBJECTS 1
    DEFINE OBJECT SANNY BUILDER 3.04 

    DEFINE MISSIONS 0

    DEFINE EXTERNAL_SCRIPTS 0

    DEFINE UNKNOWN_EMPTY_SEGMENT 0

    DEFINE UNKNOWN_THREADS_MEMORY 574

    //-------------MAIN---------------
    thread 'MAIN'
    set_wb_check_to 0
    set_weather 0
    select_interior 0
    fade 1 0
    0180: set_on_mission_flag_to $ONMISSION
    00C0: set_current_time_hours_to 8 minutes_to 0
    04E4: unknown_refresh_game_renderer_at 2491.1572 -1670.3434
    Camera.SetAtPos(2491.1572, -1670.3434, 12.3359)
    $PLAYER_CHAR = Player.Create(#NULL, 2491.1572, -1670.3434, 12.3359)
    $PLAYER_ACTOR = Actor.EmulateFromPlayer($PLAYER_CHAR)
    Actor.Angle($PLAYER_ACTOR) = 66.3548
    07AF: $PLAYER_GROUP = player $PLAYER_CHAR group
    Camera.SetBehindPlayer
    Player.Build($PLAYER_CHAR)
    Player.CanMove($PLAYER_CHAR) = True
    create_thread @POTOK
    end_thread 

    :POTOK
    thread 'POTOK'
    wait 0 
    jump @POTOK_4

    :POTOK_1
    wait 0
    jump @POTOK_3

    :POTOK_2
    wait 0
    jump @POTOK_5

    :POTOK_3
    wait 0
    jump @POTOK_2

    :POTOK_4
    wait 0
    jump @POTOK_1

    :POTOK_5
    wait 0
    end_thread
    ```
22. Конечно, толку от нашего примера никакого, но, думаю, вы приобрели необходимый опыт в написании потоков.
23. × \*\*ВАЖНО:\*\* Команду запуска потока нужно давать в \*\*активном потоке\*\*, иначе поток не запустится!
24. В нашем случае, поток вызывается с активного потока ( "MAIN" ), а когда поток запущен командой "thread", то вызванный поток сам стает активным, так сказать вызывается тогда, когда шарик при деле :) Первый поток называется ГЛАВНЫМ, или MAIN.
25. × \*\*Примечание:\*\* пустые строки игнорируется Sanny Builder и носит только косметический характер.|4763|1|0|06743791\`png\`480\`510\`400\`425\`\`\\||redaktirovanie\_main\_scm\_potoki\_i\_opkody\_chast\_1|1498200845
