00055. Cleo. Основные понятия, отличия от main'а, простые примеры

Cleo. Основные понятия, отличия от main'а, простые примеры|Здравствуйте, уважаемые пользователи сайта. Пришло время немного оставить скриптить main.scm и перейти к Cleo.|wmysterio|wmysterio||||Большинство приёмов и возможностей мы рассмотрели, и дальше нет смысла писать их в мейне, так как постоянное начало новой игры думаю достаёт. Поэтому уроки дальше будут на Cleo.

Действуют Cleo-скрипты также, как и внешние скрипты из main.scm, только загружать их не нужно. Они сами загружаются в начале игры. Особенностью этих скриптов в том, что не нужно начинать новую игру, как это было в мейне. Так же важно, что в клео нельзя создавать новые потоки. То есть "create_thread" здесь не пройдёт. Один скрипт - один поток. Рассмотрим написание простейшего скрипта:

{$CLEO}
0000:

:POTOK
thread 'POTOK'
wait 5000
0A93: end_custom_thread

Здесь: {$CLEO} - указываем компилятору, что это будет cleo-скрипт ( обязательно ставьте эту строку, иначе компилятор скомпилирует его как "*.scm" и закинет его папку игры "data/script", указанной в настройке СБ ). Такую конструкцию принято называть директивой. 0000: - опкод, который устраняет ошибку "Переход на нулевой оффсет". Эта ошибка возникает, когда идёт переход на первую метку потока. В нашем случаи такого перехода нет, но я всегда его пишу, что бы не приходилось его добавлять в будущем. Эта ошибка унаследовалась от внешних скриптов, которые также не поддерживают переход на первую метку потока. 0A93: end_custom_thread - именно этим опкодом завершаются клео-скрипты. Это очень важно, потому что end_thread вызывает ошибку при загрузке ( сохранении ) игры.

В Cleo-скриптах не рекомендуется использовать глобальные переменные. Это нужно, как минимум, для того, что бы случайно не изменить переменную в main.scm. То есть глобальные переменные действуют и на CLEO. Однако некоторые переменные всё же можно ( и нужно :) ) используются в CLEO. Это такие, как "$PLAYER_CHAR", "$PLAYER_ACTOR", "$ONMISSION" и "$PLAYER_GROUP". Если всё-же можно использовать собственные глобальные переменные, создавайте как можно длинные и запутанные имена или такие, каких нет в main.scm. Например: "$KOLICHESTVO".

Но всё же рекомендую использовать локальные переменные. Переменные от "0@" до "31@" Вы можете свободно использовать для хранения даных. А переменные "32@" и "33@" - использовать в качестве таймера, которые, кстати ( как написано в справке ), не запускаются опкодом "03C3", также не рекомендовано использовать опкоды "03C4" и "04F7" ( статус-тексты ). У меня, например, постоянные проблемы с ней, хотя в других ничего плохого не происходит. Можете протестировать. Если у вас в всё окей, то юзайте на здоровье :) Особенности потоков те же, что и в мейне. Можно использовать циклы, переходы, массивы и т.п.

Скрипт мы написали. Когда мы компилируем его в первый раз, то компилятор предложит нам сохранить его. Указываем папку CLEO ( что в папке с игрой ). Другой способ - создать текстовый файл в папке "Cleo" и переместить его на санник, затем скомпилировать. Имя файла может быть любое, но обычно его называют так же, как и поток. Потоки, кстати, можно и не называть, то есть сразу писать скрипт без "thread".

Раз мы будем писать на CLEO , то полностью отредактируем мейн, сделаем его минимальным и работоспособным. Немного позже я скажу зачем мы это сделали. Вот код нашего мейна:

// by WMYSTERIO, http://www.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 3072

{$VERSION 3.1.0027}

//-------------MAIN---------------
thread 'MAIN'
set_wb_check_to 0
set_weather 0
select_interior 0
fade 0 0
0180: set_on_mission_flag_to $ONMISSION // Note: your missions have to use the variable defined here
00C0: set_current_time_hours_to 8 minutes_to 0
04E4: unknown_refresh_game_renderer_at 2491.157 -1670.343
Camera.SetAtPos(2491.157, -1670.343, 12.3359)
$PLAYER_CHAR = Player.Create(#NULL, 2491.157, -1670.343, 12.3359)
$PLAYER_ACTOR = Actor.EmulateFromPlayer($PLAYER_CHAR)
Actor.Angle($PLAYER_ACTOR) = 66.3548
07AF: $PLAYER_GROUP = player $PLAYER_CHAR group
Camera.SetBehindPlayer
Player.SetClothes($PLAYER_CHAR, "WORKTRCAMOGRN", "WORKTR", Legs)
Player.SetClothes($PLAYER_CHAR, "SNEAKERBINCGANG", "SNEAKER", Shoes)
Player.SetClothes($PLAYER_CHAR, "TSHIRTERISORN", "TSHIRT", Torso)
Player.Build($PLAYER_CHAR)
Player.CanMove($PLAYER_CHAR) = True
0629: change_integer_stat 181 to 4
016C: restart_if_wasted_at 2027.77 -1420.52 15.99 angle 137.0 town_number 0
016C: restart_if_wasted_at 1180.85 -1325.57 12.58 angle 271.4 town_number 0
016D: restart_if_busted_at 1550.68 -1675.49 14.51 angle 90.0 town_number 0
016C: restart_if_wasted_at 1244.437 331.2261 18.5547 angle 7.5465 town_number 1
016D: restart_if_busted_at 632.2344 -571.7104 15.3515 angle 267.2 town_number 1
016C: restart_if_wasted_at -2199.719 -2308.075 29.6181 angle 322.8928 town_number 1
016D: restart_if_busted_at -2163.829 -2387.817 29.625 angle 134.2066 town_number 1
016C: restart_if_wasted_at -2670.285 616.4364 13.4531 angle 183.1042 town_number 1
016D: restart_if_busted_at -1605.792 716.8598 11.0241 angle 355.2978 town_number 1
016C: restart_if_wasted_at -316.3832 1056.045 18.7344 angle 1.6017 town_number 2
016D: restart_if_busted_at -212.1889 979.4168 18.3219 angle 278.0478 town_number 2
016C: restart_if_wasted_at -1514.823 2527.119 54.7443 angle 2.3546 town_number 2
016D: restart_if_busted_at -1393.072 2633.116 54.9491 angle 86.0424 town_number 2
016C: restart_if_wasted_at 1578.446 1770.682 9.8358 angle 99.7567 town_number 2
016D: restart_if_busted_at 2337.083 2453.802 13.9765 angle 90.7643 town_number 2
fade 1 0
create_thread @SAVE
end_thread

:SAVE
thread 'SAVE'
wait 0
if AND
not actor.Dead($PLAYER_ACTOR)
8741: not actor $PLAYER_ACTOR busted
then
 if AND
 $ONMISSION == 0
 8A0C: not player $PLAYER_CHAR on_jetpack 
 then
 if AND
 8818: not actor $PLAYER_ACTOR in_air
 8965: not actor $PLAYER_ACTOR swimming
 then
 if AND
 not actor.Driving($PLAYER_ACTOR)
 0AB0: key_pressed 115 // F4
 then
 03D8: show_save_screen
 end
 end
 end
end 
jump @SAVE

Компилируем его и запускаем новую игру. Как видим, никаких ошибок не возникало. По этому смело закрываем мейн и начинаем писать Cleo-скрипты ;)

Прежде всего напишем скрипт спавна транспорта. Создаем в папке CLEO текстовый файл и называем его, например, "CAR.txt". Дальше запускаем ярлык санника и ожидаем запуска программы. После этого перемещаем файл в окно программы:

Как видим появилось поле редактора :) Дальше уже пишем сам скрипт:

{$CLEO}
0000:

:car
thread 'car'
wait 0
if
0AB0: key_pressed 50 // Кнопка 2
then
0ADD: spawn_car_with_model #BULLET at_player_location
end
jump @car

Суть скрипта проста - нажимаем кнопку 2` и перед СЖ появится кар "Bullet". Как видите, мы не использовали опкод "0A93" в нашем скрипте, так как мы возвращаемся постоянно на метку "@CAR". В таких случаях обычно не пишут опкод завершения потока, так как он никогда не выполнится :) Компилируем. Думаю вы заметите, что в папке создался и "*.cs"-файл, так что клео-скрипт создан :)

Давайте удалим опкод "0000" и попробуем скомпилировать. Как видите, в нас ошибка: "Переход на нулевой оффсет". Как уже было написано выше, это случается когда идёт переход на первую метку. Именно для этого создан опкод "0000" - он делает небольшое смещение от начала потока, что позволяет избежать перехода нулевой оффсет. Также можно написать вместо него задержку "wait 0" или любой другой опкод, не влияющий на процесс игры. Это тоже помогает ;)

Давайте протестируем скрипт. Результат виден на лицо - тачка отлично "спавнится" возле Карла:

В нас ещё есть много материала, поэтому в ближайшие дня напишу ещё парочку уроков.|3456|1|0|43780319png600375400250``\|01129892png393270

`\||cleo_osnovnye_ponjatija_otlichija_ot_main_39_a_prostye_primery|1499524917

Last updated