Уроки

Здесь будут публиковаться уроки по скриптингу, написанные лично мной. Надеюсь, что эти уроки помогут Вам быстрее научиться делать свои скрипты. Удачи! 
Уважаемые посетители! Я уже давно создал плейлист Sanny Builder: Мои примеры, где можно увидеть мои примеры скриптов с полным разбором кода.


  • Урок №1: Создание актеров
Перед созданием необходимо загрузить модель актера, например #ARMY.
Вот и команда для создания актера:
Actor.create(1@,4,#ARMY,X,Y,Z)
1@ - это переменная актера, с помощью которой им можно манипулировать.
4 - тип актера (коп, мужчина, бандит и т.д.)
#ARMY - имя загруженной нами модели
X, Y, Z - координаты (ТОЛЬКО ДРОБНЫЕ)

Вот мы и создали актера, теперь надо что-нибудь с ним сделать, например, увеличить здоровье.
Это делается вот этой командой
Actor.health(1@) = 350
1@ - переменная актера, которого мы создали
350 - количество здоровья (не может быть дробным числом!)
Теперь дадим ему броню
Actor.armour(1@) = 200
1@ - переменная актера
200 - количество боони (тоже не дробное!)
Теперь повернем его
Actor.angle(1@) = 90.0
1@ - переменная актера
90.0 - угол в градусах (ТОЛЬКО ДРОБНЫЙ)
И напоследок дадим ему оружие. Перед этим модель оружия необходимо загрузить.
01B2: give_actor 1@ weapon 18 ammo 250
1@ - переменная актера
18 - номер оружия (это револьвер из ВС)
250 - количество патронов к оружию.
Чтобы сделать актера простым пешеходом и убрать о нем сведения, используйте вот эту команду
actor.RemoveReferences(1@)
1@ - переменная актера
 Смотрите пример и разбирайтесь. Пример для VC, но, если выбрать другую модель оружия, то и для SA подойдет.


:MyScript01 //начало
wait 0 // чтобы не вылетело ждем 0 миллисекунд
model.load(#ARMY) // объявляем модель актера
model.load(#PYTHON) // объявляем модель оружия
038B: load_requested_models // загружаем объявленные модели

:MyScript02 // вторая метка
wait 0 // чтоб не вылетало
if and // проверка нескольких условий
model.Available(#ARMY) // проверка на загруженность модели
model.Available(#PYTHON) // проверка на загруженность модели
jf @MyScript02
wait 10 //ждем 10 миллисекунд
// ну а дальше все уже понятно...
actor.create(1@,6,#ARMY,-1200.1,550.5,12.3)
actor.health(1@) = 150
actor.armour(1@) = 200
actor.angle(1@) = 270.0
01B2: give_actor 1@ weapon 18 ammo 250
wait 1500
actor.RemoveReferences(1@) //удаляем из памяти сведения об актере
model.destroy(#ARMY) // выгружаем модели
model.destroy(#PYTHON)
end_thread // завершаем скрипт


  • Урок №2: Создание транспорта   
Опкод, создающий транспорт:
car.Create(1@,#ADMIRAL,X,Y,Z)
1@ - переменная авто. нужна для разных действий
#ADMIRAL - модель авто. перед созданием, нужно загрузить модель командой model.load(#модель)
X,Y,Z - координаты
Вот, машина создана, теперь посмотрим, что можно с ней делать.
Чтобы задать машине определенную скорость, используйте эту команду:
car.SetSpeedInstantly(1@,100.0)
1@ - переменная машины

100.0 - скорость (мили/час) (только дробное число) car.Health(1@) = 1000
Здоровье машины.

1000 - кол-во здоровья (1000 - обычное здоровье машины)
Можно переместить авто в определенное место
car.PutAt(1@,X,Y,Z)
1@ - все та же переменная машины

X,Y,Z - координаты, в которые мы перемещаем машину
Еще машине можно поставить защиту от чего-либо
car.SetImmunities(1@,1,1,1,1,1)
1@ - переменная авто
"тут первая цифра - защита от пуль, вторая - от огня, третья - от взрывов, четвертая - от оружия ближнего боя,пятая от столкновений." (цитата из справки SB)

car.ToggleHydraulics(1@,1)
Этой командой на машину ставится гидравлика (как у лоурайдеров)
1@ - переменная авто
1 - параметр. 1 - вкл. 2 - выкл.

car.destroy(1@)
уничтожает машину

car.RemoveReferences(1@)
убирает сведения о машине. машина теперь исчезнет, если игрок находится далеко от нее

Перейдем к проверкам:
car.Wrecked(1@)
Проверяет уничтожена ли машина с переменной 1@

car.HasHydraulics(1@)
Если ли у машины гидравлика

Пример создания машины:

:Car //начинаем скрипт
wait 0 //ждем 0 мс, чтобы не вылетело
model.load(#ADMIRAL) //объявляем модель
038B: load_requested_models //загружаем объявленную модель

:Car_2 //вторая часть скрипта
wait 0 //ждем, чтобы не вылетело
if  //одиночное условие
model. Available(#ADMIRAL)  //загружена ли модель?
jf @Car_2 //если нет, идем на начало
car.create(1@,#ADMIRAL,2488.56,-1667.84,13.38) //само создание машины
car.removereferences(1@) //удаляем сведения о машине из памяти, чтобы не нагружать игру
model.destroy(#ADMIRAL) //удаляем модель из памяти, чтобы не нагружать игру
end_thread //завершаем скрипт


  • Урок №3: Самодельный таймер
Итак, многие, кто начал изучать скриптинг, знают, что в cleo скриптах нельзя использовать глобальные переменные (точнее не рекомендуется, это не относится к общим, таким, как $PLAYER_ACTOR, $ONMISSION и т.п.). Но если попробовать использовать локальные переменные (1@, например) для создания таймера, игра вылетит, ведь этому опкоду нужна именно глобальная переменная. Поэтому приходится либо отказываться от таймера вовсе, либо рисковать и использовать глобальные переменные. Я (конечно, думаю, что я не первый) придумал новый способ создания таймера, простой и имеющий "гибкие" настройки. Ему не нужны глобальные переменные, он, так же, как и стандартный его собрат, выводится на экран, так же есть звуки, когда значения таймера малы, но все в нем можно изменить по собственному желанию. Итак, сначала приведу сам код, затем объясню все по порядку.


:Cicl
wait 0
if and
not actor.Dead($PLAYER_ACTOR)
not actor.Driving($PLAYER_ACTOR)
0AB0: key_pressed 0xD  //проверки на то, что игрок жив, не в авто, и на нажатие клавиши "Enter"
jf @Cicl
actor.StorePos($PLAYER_ACTOR,2@,3@,4@) //сохраняем текущие координаты игрока в переменные
02CE: 4@ = ground_z_at 2@ 3@ 4@ //получаем координату поверхности, чтобы действие не происходило в воздухе

//начало самого таймера, то есть простого цикла, известного многим по школьному курсу программирования (в Turbo Pascal)
for 1@ = 15 downto 0  //берем downto, чтобы счет шел от большего к меньшему
01E5: show_text_1number_highpriority GXT 'VAR' number 1@ time 1000 flag 1  //выводим значение переменной (секунды), которая в цикле изменяется с 15 до 0
if  //начало условия. эта часть необязательна, она нужна для звука, который будет проигрываться, когда время будет меньше 5 секунд
1@ <= 5 //если значение времени таймера меньше или равно 5, то...
then
018C: play_sound 1084 at 0.0 0.0 0.0  //...проигрываем звук №1084
end //конец условия. else не нужно в данном случае
wait 1000 //ждем 1 секунду, иначе таймер закончится сразу же, да и таймер в секундах
end //конец цикла, это и конец таймера
020C: create_explosion_with_radius 10 at 2@ 3@ 4@ //создаем два больших взрыва
020C: create_explosion_with_radius 6 at 2@ 3@ 4@
wait 750  //ждем 750 мс, чтобы игрок не сразу мог перезапустить скрипт
 jump @Cicl //идем на начало 



Суть скрипта в том, что спустя 15 секунд после нажатия Enter произойдет взрыв (в той точке, в которой игрок нажал клавишу). Как видите, сам код прост и мал по размеру. К тому же есть еще плюсы:

-Не нужно проверять, что время таймера равно нулю, цикл сам завершается

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

Помимо того, что можно выводить разные варианты текста (как по стилям написания, так и по цвету, например, сделать текст красным, когда значение таймера меньше 5 секунд), Вы сможете вывести текст как текст-бокс (серый прямоугольник в верхнем левом углу экрана, примером будет сообщение о том, как сменить оружие на другое). Для этого понадобится команда 0513, только не забудьте применить команду 03E6 после цикла, чтобы текст-бокс не держался на экране все время и исчез (сам он не исчезает).

Единственная проблема состоит в том, что выводятся именно секунды,а не минуты, но это, конечно, можно исправить, немного поломав голову.

В целом можно сказать, что такой таймер гораздо проще создается, его можно изменить по своему желанию, так что, если Вам понравился этот способ, дерзайте, у Вас все получится, если подключить фантазию. Можно сделать разноцветный текст,  "музыкальный" таймер (звук на каждой секунде) и т.д. 


  • Урок №4: Создание .fxt файлов
Многие cleo скрипты содержат в себе текст, созданный автором скрипта. Но для того, чтобы он выводился на экран, необходимо сделать кое-какие вещи. Помимо того, что у Вас должна быть библиотека CLEO (той версии, которая необходима для работы скрипта), для отображения текстов нужен скрипт GxtHook.cleo. Он идет в комплекте с Sanny Builder или с некоторыми cleo скриптами (если автор поместит этот файл). Его следует поместить в папку CLEO. После этого создайте в папке CLEO папку CLEO_TEXT. В ней и должны быть файлы с расширением .fxt. Если Вы скачали чей-то скрипт, просто поместите .fxt файл в CLEO_TEXT. А если Вы делаете свой скрипт, которому понадобится текст, то делайте следующее:
1) Создайте текстовой файл (.txt) в CLEO_TEXT и поменяйте его расширение на .fxt. Имя файла должно быть английским
2) Теперь заполняйте файл текстом. Выглядит это так: 
ИМЯ СТРОКИ<пробел>Текст
Имя строки должно быть написано большими английскими буквами, а также кол-во символов не должно превышать 7

Пример:
TEXT1 Take the car and drive to San Fierro!

Текст может быть и на русском, но для этого понадобится специальная программа, переводящая русские буквы в символы. Без подобной программы русский текст не будет отображаться.
Имя строки нужно писать в опкодах, чтобы игра отображала именно Ваш текст.
Пример:
03E5: show_text_box ‘TEXT1’

Мы указали имя той строки, которую мы хотим вывести. Строк может быть больше одной. Пример:

TEXT2 Now park the car near the house.
TEXT3 Exit the car and then blow it up.

Итак, мы научились правильно использовать одну из лучших возможностей CLEO!


  • Урок №5 - Миссия "Ярость" (Rampage)

Итак, спустя долгое время я решил опубликовать здесь ещё одну статью. На сей раз речь пойдёт о заданиях Rampage (которые ещё называются Kill Frenzy). Это задание состоит в убийстве определённых или всех подряд людей, иногда в уничтожении транспорта. При этом игроку дают определённый вид оружия, которое имеет бесконечный боезапас. По стандарту в SA отсутствует это задание, так как я, просматривая в Sanny Builder код main.scm, не нашёл тех опкодов, которые относятся к данному заданию. У меня появилась идея вернуть утерянное наследие прошлых GTA и сделать это в виде отдельной миссии. Итак, вот код:

:Rampage
$ONMISSION = 1
while true
gosub @Rampage2
    if
    wasted_or_busted
    then
    00BA: show_text_styled GXT "RPFL" time 1000 style 1
    break
    else
        if
        0@ == 2
        then                
        player.Money(0) += 100000
        00BA: show_text_styled GXT "RPCP" time 1000 style 1
        break
        else
        00BA: show_text_styled GXT "RPFL" time 1000 style 1
        break
        end
    end
end
0110: clear_player 0 wanted_level
mission_cleanup
$ONMISSION = 0
end_thread

:Rampage2
increment_mission_attempts
player.WantedLevel(0) = 3
model.Load(#MINIGUN)
038B: load_requested_models
01F9: init_rampage_gxt 'RAMPAGE' weapon 38 time_limit 130000 targets 100 target_models -1 -1 -1 -1 completed_text 0
model.Destroy(#MINIGUN)
while true
wait 0
01FA: 0@ = rampage_status
    if or
    0@ == 2
    0@ == 3
    then
    break
    end
end
return    

Рассмотрим всё по порядку.
Во-первых, всё это - миссия. Шаблон я немного переделал под цикл while true, который достаточно хорошо упрощает работу и к тому же может быть использовать для cleo миссии.
Во-вторых, игроку дают миниган и три звезды розыска, чтобы было больше возможности пройти миссию.
В-третьих, использовано два опкода, касающихся Rampage.
В-четвёртых, игра сама создаёт таймер и счётчик убийств, Вам остаётся лишь настроить параметры.
Что ж, давайте разберём опкоды:

01F9: init_rampage_gxt 'RAMPAGE' weapon 38 time_limit 130000 targets 100 target_models -1 -1 -1 -1 completed_text 0
  • 'RAMPGAE' - текст, который будет выведен в начале задания
  • 38 - номер оружия, с которым игроку предстоит сражаться
  • 130000 - количество времени в миллисекундах
  • 100 - число "жертв" Вашего буйства
  • -1 -1 -1 -1 - имена или номера (ID) моделей людей и машин, которые засчитываются за одно убийство (-1 - любой человек, -2 - любой транспорт)
  • 0 - выводить ли текст завершения задания (1 - да, 0 - нет)

С текстом в данном опкоде есть некоторые проблемы: неизвестно, с чем это связано, но текст здесь выводится дважды. В связи с этим я поставил последний параметр на 0 и взял стандартный текст 'RAMPAGE', который, к счастью, не выводится, так что можно теперь использовать свой текст.
И ещё один опкод по этой теме:

01FA: 0@ = rampage_status

Записывает в 0@ состояние задания. Экспериментально, а также с помощью исследований на других сайтах я установил, что:
  • 1 - задание в процессе выполнения
  • 2 - успешное выполнение "Ярости"
  • 3 - провал задания


Вот и всё! Можете экспериментировать с этими опкодами и создавать новые миссии Rampage. Можно делать это в виде обыкновенного потока, я же решил взять шаблон миссии, чтобы игра сама заканчивала действие "Ярости", когда игрок мёртв или арестован.

Вот такая миссия, которая уложилась всего в 44 строки! 
Удачных Вам перестрелок!