Создание гоночной миссии для GTA Vice City
В этой статье я вам расскажу о принципах создания гонки для GTA VC, для этой игры пока еще не создали Race Mission Builder, но и с VC Mission Builder'ом можно научиться создавать гонки.
Итак, для создания понадобится VC Mission Builder(желательно v1.5) и сама игра GTA Vice City.
Итак, запускаем скачанный VCMissionBuilder и открываем файл Stripped_complete.txt (это скрипт 100% прохождения) (он в: папка Mission Builder'aStripped scripts), и вот у нас перед глазами код, ищем где у нас
DEFINE MISSIONS 1 ;; количество миссий
DEFINE MISSION 0 AT ЈЈLabel031F34 ;; всегда номера миссий начинаются с 0
Это прописка миссий, здесь только одна(это создание всех припаркованных тачек, оружия, пикапов(типа здоровья, брони) и тд), эти строки мы меняем на:
DEFINE MISSIONS 2
DEFINE MISSION 0 AT ЈЈLabel031F34
DEFINE MISSION 1 AT ЈЈRACE ;; прописка нашей гонки
P.S. Label'ы, это метки, на которые переходит игра
Далее создаем стартер для миссии, для этого ищем где у нас все create_thread'ы и ставим там в конце вот такую строчку:
004F: create_thread ЈЈstartracer ;; это ссылка на метку с стартером, startracer - метка, но в Mission Builder'e есть такой баг, что компилятор не всегда понимает JJ в ссылках, например:
0002: jump ЈЈLabel00994C
(0002: - опкод, команда jump компилятором игнорируется и поэтому можно записать и так:
0002: JJLabel00994C )
JJ ставится только в области MAIN, а
J ставится только в миссиях, если же ставить JJ в миссиях, то компилятор это примет, но игра может выдавать ошибки, а если J в MAIN'е писать, то компилятор выдаст сообщение, что в MAIN'e следует использовать только JJ.
Возвращаемся к стартеру гонки:
:startracer
02A7: $icon = create_icon_marker_and_sphere 35 at -236.929 -465.912 10.300 ;; создаём маркер с именем $icon типа 35(типы можно узнать в текстовом файле radar_icons.txt, опять же он в папке MissionBuilder'a) на карте и отметку
:strt1
0001: wait 250 ms ;; ждем 250 мс
00D6: if 0 ;; если
0256: player $PLAYER_CHAR defined ;; жив и не арестован
004D: jump_if_false ЈЈstrt1 ;; если ложь то на метку strt1, если правда то идем дальше
00D6: if 0
00F9: player $PLAYER_CHAR stopped 0 ()near_point_on_foot -236.929 -465.912 10.300 radius 1.0 1.0 2.0 ;; игрок на точке
004D: jump_if_false ЈЈstrt1
00D6: if 0
0038: $ONMISSION == 0 ;; integer values ;; игрок не на миссии
004D: jump_if_false ЈЈstrt1
00D6: if 0
03EE: player $PLAYER_CHAR controllable ;; игрок управляемый(сам незнаю зачем это но писать это надо)
004D: jump_if_false ЈЈstrt1
0164: disable_marker $icon ;; убрать маркер $icon с карты
0417: start_mission 1 ;; начать миссию
004E: end_thread ;; завершить стартер(ну.. или поток, как это обобщенно сказать)
Всё это пишется только в области MAIN'a, и, как видно здесь юзается JJ
в самом конце кода пишем:
;---------------Mission 1--------------
:RACE ;;метка начала миссии
0050: gosub Јstarting ;; gosub - это некое обращение к другой метке которое можно завершить командой 0051: return
00D6: if 0
0112: wasted_or_busted
004D: jump_if_false Јend
0050: gosub ЈFAIL
:end
0050: gosub Јclean
004E: end_thread
;;всё что выше, нужно, чтоб если Томми умер во время миссии, то миссия завершится с провалом.
:starting
0317: increment_mission_attempts ;; команда, для того чтобы в статистике к попытке миссий прибавилось 1
03A4: name_thread "RACE" ;; начинаем поток с названием RACE
01E8: create_forbidden_for_cars_cube -252.929 -337.286 9.307 -455.861 -499.581 10.210 ;; создаем запрещенную для машин область где старт гонки, чтоб машины не мешали стартовать
0004: $checkpoint = 1 ;; integer values ;; как бы флаг, сколько отметок прошел игрок
0004: $crd = 1 ;; integer values ;; как бы флаг, сколько отметок прошел противник
0005: $x = -527.164 ;; floating-point values
0005: $y = -487.341 ;; floating-point values
0005: $z = 10.087 ;; floating-point values
0005: $xZ = -527.164 ;; floating-point values
0005: $yZ = -487.341 ;; floating-point values
0005: $zZ = 10.087 ;; floating-point values
0005: $x1 = -829.568 ;; floating-point values
0005: $y1 = -710.641 ;; floating-point values
0005: $z1 = 9.947 ;; floating-point values
0005: $x2 = -973.242 ;; floating-point values
0005: $y2 = -1074.749 ;; floating-point values
0005: $z2 = 13.717 ;; floating-point values
0005: $x3 = -1198.370 ;; floating-point values
0005: $y3 = -934.293 ;; floating-point values
0005: $z3 = 13.717 ;; floating-point values
0005: $x4 = -1420.124 ;; floating-point values
0005: $y4 = -783.965 ;; floating-point values
0005: $z4 = 13.717 ;; floating-point values
;;координаты гонки
0004: $finish = 0 ;; integer values ;; флаг конечной контрольной точки гонки
0004: $race = 0 ;; integer values ;; флаг времени гонки
0004: $ONMISSION = 1 ;; флаг "игрок на миссии", если 1 - то на миссии, если 0 - то не на миссии
0247: request_model #HOTRING ;; запрашиваем модель машины Хотринг, это обязательно!!!
0247: request_model #WMYGO ;;запрашиваем модель водителя этой машины
038B: load_requested_models ;; как бы загрузка запрошенных моделей, без нее могут быть вылеты
:ava ;; метка с именем ava
00D6: if 1 ;; если 1(это значит если то и то), если 21(значит если то или то)
8248: NOT model #HOTRING available ;; модель не существует
8248: NOT model #WMYGO available
004D: jump_if_false Јstart ;; идем на start если ложь
0001: wait 0 ms ;; если правда то ждем 0 мс и идем к началу метки ava
0002: jump Јava
;; P.S. тут все "джампы" юзаются с J , потому что в миссии
:start
00A5: $zbr = create_car #HOTRING at -238.277 -477.260 10.092 ;; создаем тачку хотринг с именем $zbr на координатах -238.277 -477.260 10.092, координаты берутся программой PlayerPos(лучше версии 1.3)
0129: $vd = create actor 4 #WMYGO in car $zbr driverseat ;; создаем актёра 4(сам незнаю что это значит) в машине $zbr водителем
00AD: set_car $zbr max_speed_to 127.9 ;; задаем нашей тачке максимальную скорость 127.9 миль в час
00AF: set car $zbr driver behaviour to 2 ;; нужно для реальности
00A9: set car $zbr to normal driver ;; делаем водителя тачки аккуратным
00AE: unknown set car $zbr to ignore traffic lights 2 ;; машина игнорирует всё, что на дороге, стоит отметить, что цифра 2 - тачка объезжает всё, 1 - толкает, 0 - похоже что вообще едет по ПДД
020A: set_car $zbr door_status_to 2 ;; состояние дверей тачки, 1 - открыты, 2 - закрыты
01ED: reset_actor $vd flags ;; удаляем все флаги противника (какие я незнаю, но писать это надо)
0224: set car $zbr health to 2000 ;; устанавливаем для машины как бы здоровье на 2000
02C2: car $zbr drive_to_point -238.277 -477.260 10.092 ;; машина никуда не едет, стоит на начальных координатах, это нужно, потому что в вайсе есть такой баг, что если поставить на дорогу тачку с водителем, то тачка куда-то всё время едет
0428: unknown_car $zbr flag 0 ;; нужно тоже, для чего точно я незнаю
0175: set_car $zbr z_angle_to 90.0 ;; тачка изначально повёрнута на север, мы её поворачиваем на 90 градусов против часовой стрелки, таким образом тачка поворачивается на запад
03AB: (unknown) $zbr 1 ;; unknown - что-то неизвестное с тачкой, писать надо, чтоб не вылетело
039C: (unknown) $zbr 1 ;; аналогично тому, что выше
03ED: (unknown) $zbr 1 ;; здесь тоже
018A: $chk = create_checkpoint_at $x $y $z ;; создаем чекпоинт (маркер) на карте с именем $chk и координатами $x $y $z - это переменные, их мы писали в самом начале миссии
0165: set marker $chk color to 1 ;; задаем цвет нашему маркеру под номером 1(это зеленый)
0186: $mrk = create_marker_above_car $zbr ;; создаем ещё один маркер с именем $mrk, только уже над машиной, он будет всё время над ней
0168: show_on_radar $mrk 1 ;; наш маркер $mrk на радаре будет смотреться как маленький квадратик
03BC: $sph = create_sphere -238.262 -481.053 10.082 2.0 ;; создаем отметку $sph на координатах -238.262 -481.053 10.082 с радиусом 2.0 метра
:inc
00D6: if 1 ;; если
80FA: NOT player $PLAYER_CHAR stopped 0 (in-sphere)near_point_in_car -238.262 -481.053 10.082 radius 2.0 2.0 2.0 ;; игрок не на точке -238.262 -481.053 10.082 в машине с радиусами 2.0 2.0 2.0
0001: wait 0 ms
004D: jump_if_false Јcount ;; если ложь, т.е. если игрок на точке в машине
;; если правда то:
00D6: if 1 ;; если
8118: NOT actor $vd dead ;; актёр (водитель) $vd не умер
0001: wait 0 ms
004D: jump_if_false ЈPROTD ;; если умер то переходим к метке PROTD
0002: jump Јinc ;; переходим в начало метки inc
:count ;; от этой метки начинается отсчёт
03BD: destroy_sphere $sph ;; удалить отметку $sph
03C1: $playcar = player $PLAYER_CHAR car ;; машина игрока записывается в память с именем $playcar
03AB: (unknown) $playcar 1 ;; что-то неизвестное, писать всё равно надо
0224: set car $playcar health to 2000 ;; задаем здоровье тачке игрока, равное 2000
0428: unknown_car $zbr flag 1 ;; задаем какой-то флаг машине противника - $zbr
01B4: set player $PLAYER_CHAR frozen state 0 (frozen) ;; отключаем управление игрока
00BA: text_styled "RACE2" 1000 ms 5 ;; выводим текст - "3"
018C: play_sound 1 at 0.0 0.0 0.0 ;; проигрываем звук (номера звуков нигде не описаны, но разобрать постараюсь)
0001: wait 1000 ms
00BA: text_styled "RACE3" 1000 ms 5 ;; выводим текст - "2"
018C: play_sound 1 at 0.0 0.0 0.0
0001: wait 1000 ms
00BA: text_styled "RACE4" 1000 ms 5 ;; выводим текст - "1"
018C: play_sound 1 at 0.0 0.0 0.0
0001: wait 1000 ms
00BA: text_styled "RACE5" 1000 ms 5 ;; выводим текст - "GO!"
018C: play_sound 10 at 0.0 0.0 0.0
;; 010E: set player $PLAYER_CHAR minimum wanted level to 4 ;; этооо, мы задаем игроку уровень розыска 4, это ставить не обязательно
01B4: set player $PLAYER_CHAR frozen state 1 (frozen) ;; включаем управление игроку
014E: set_timer_to $race type 0 ;; создаём таймер отсчета гонки с переменной $race, мы её указывали в начале типа 0 - это отсчет от 0, а 1 - это обратный отсчет - до 0
:startrace ;; начало гонки после отсчета
02C2: car $zbr drive_to_point $x $y $z ;; машина противника едет на координаты $x $y $z - переменные с координатами, указанные в начале
:cnt
00D6: if 1
80E3: NOT player $PLAYER_CHAR 0 ()near_point $x $y radius 6.0 6.0 ;; игрок на на координатах $x $y с радиусами 6.0 6.0
0001: wait 0 ms
004D: jump_if_false Јpank
0050: gosub Јcorona ;; обращение к метке с короной(т.е. большим кругом)
00D6: if 1
81AF: NOT car $zbr 0 ()near point $xZ $yZ $zZ radius 6.0 6.0 6.0 ;; машина противника не на точке $xZ $yZ $zZ (тоже переменные) с радиусами 6.0 6.0 6.0
0001: wait 0 ms
004D: jump_if_false Јchangecrd
0050: gosub Јcorona
00D6: if 1
8118: NOT actor $vd dead ;; если актёр $vd жив
0001: wait 0 ms
004D: jump_if_false ЈPROTD ;; если мёртв то идем к метке провала миссии, для чего это? ну.. бывает, что застрелишь своего противника и поедешь один, это защита от этого
0050: gosub Јcorona
0002: jump Јcnt
:corona
00D6: if 0
0038: $finish == 1 ;; integer values ;; если флаг финиша = 1
004D: jump_if_false Јgreen ;; если нет то идем к green
;; если да то:
024F: create_corona 6.0 6 0 with_color 255 0 0 at_point $x $y $z ;; создаем круг с радиусом 6.0, 6 0 - незнаю что это, с цветом 255 0 0 (цвет как видно получается при помощи RGB палитры) на координатах $x $y $z
0051: return ;; возврат назад
:green
024F: create_corona 6.0 6 0 with_color 14 235 50 at_point $x $y $z
0051: return
:pank
00D6: if 1
8039: NOT $checkpoint == 1 ;; integer values ;; игрок не прошел 1ую отметку
0001: wait 0 ms
004D: jump_if_false Јx1 ;; если прошел то идем к x1, то же самое и дальше кроме 5 - последней
00D6: if 1
8039: NOT $checkpoint == 2 ;; integer values
0001: wait 0 ms
004D: jump_if_false Јx2
00D6: if 1
8039: NOT $checkpoint == 3 ;; integer values
0001: wait 0 ms
004D: jump_if_false Јx3
00D6: if 1
8039: NOT $checkpoint == 4 ;; integer values
0001: wait 0 ms
004D: jump_if_false Јx4
00D6: if 1
8039: NOT $checkpoint == 5 ;; integer values
0001: wait 0 ms
004D: jump_if_false ЈPASSED ;; если игрок прошел последнюю метку, то идем к метке с выводом сообщения о выигрыше
0002: jump Јpank
:x1
018C: play_sound 1 at 0.0 0.0 0.0 ;; проигрываем звук
0164: disable_marker $chk ;; удаляем маркер $chk
0086: $x = $x1 ;; floating-point values only ;; задаем конкретно переменной $x значение переменной $x1
0086: $y = $y1 ;; floating-point values only
0086: $z = $z1 ;; floating-point values only
018A: $chk = create_checkpoint_at $x $y $z
0165: set marker $chk color to 1
0008: $checkpoint += 1 ;; integer values ;; прибавляем 1 пункт к числу пройденных отметок
0002: jump Јcnt
:x2
018C: play_sound 1 at 0.0 0.0 0.0
0164: disable_marker $chk
0086: $x = $x2 ;; floating-point values only
0086: $y = $y2 ;; floating-point values only
0086: $z = $z2 ;; floating-point values only
018A: $chk = create_checkpoint_at $x $y $z
0165: set marker $chk color to 1
0008: $checkpoint += 1 ;; integer values
0002: jump Јcnt
:x3
018C: play_sound 1 at 0.0 0.0 0.0
0164: disable_marker $chk
0086: $x = $x3 ;; floating-point values only
0086: $y = $y3 ;; floating-point values only
0086: $z = $z3 ;; floating-point values only
018A: $chk = create_checkpoint_at $x $y $z
0165: set marker $chk color to 1
0008: $checkpoint += 1 ;; integer values
0002: jump Јcnt
:x4
018C: play_sound 1 at 0.0 0.0 0.0
0164: disable_marker $chk
0086: $x = $x4 ;; floating-point values only
0086: $y = $y4 ;; floating-point values only
0086: $z = $z4 ;; floating-point values only
018A: $chk = create_checkpoint_at $x $y $z
0165: set marker $chk color to 5
0008: $checkpoint += 1 ;; integer values
0008: $finish += 1 ;; integer values
0002: jump Јcnt
:changecrd ;; это аналогично тому, что с игроком, только если противник наберет 5 пунктов числа пройденных им отметок, то гонка проиграна
00D6: if 1
8039: NOT $crd == 1 ;; integer values
0001: wait 0 ms
004D: jump_if_false Јx11
00D6: if 1
8039: NOT $crd == 2 ;; integer values
0001: wait 0 ms
004D: jump_if_false Јx21
00D6: if 1
8039: NOT $crd == 3 ;; integer values
0001: wait 0 ms
004D: jump_if_false Јx31
00D6: if 1
8039: NOT $crd == 4 ;; integer values
0001: wait 0 ms
004D: jump_if_false Јx41
00D6: if 1
8039: NOT $crd == 5 ;; integer values
0001: wait 0 ms
004D: jump_if_false ЈRACEFA ;; идем на метку с выводом текста о провале миссии
0002: jump Јchangecrd
:x11
0086: $xZ = $x1 ;; floating-point values only
0086: $yZ = $y1 ;; floating-point values only
0086: $zZ = $z1 ;; floating-point values only
0008: $crd += 1 ;; integer values ;; прибавляем 1 пункт к числу пройденных противником отметок
02C2: car $zbr drive_to_point $xZ $yZ $zZ ;; тачка противника гонит на координаты $xZ $yZ $zZ
0002: jump Јcnt
;; всё что ниже, аналогично описанию метки x11
:x21
0086: $xZ = $x2 ;; floating-point values only
0086: $yZ = $y2 ;; floating-point values only
0086: $zZ = $z2 ;; floating-point values only
0008: $crd += 1 ;; integer values
02C2: car $zbr drive_to_point $xZ $yZ $zZ
0002: jump Јcnt
:x31
0086: $xZ = $x3 ;; floating-point values only
0086: $yZ = $y3 ;; floating-point values only
0086: $zZ = $z3 ;; floating-point values only
0008: $crd += 1 ;; integer values
02C2: car $zbr drive_to_point $xZ $yZ $zZ
0002: jump Јcnt
:x41
0086: $xZ = $x4 ;; floating-point values only
0086: $yZ = $y4 ;; floating-point values only
0086: $zZ = $z4 ;; floating-point values only
0008: $crd += 1 ;; integer values
02C2: car $zbr drive_to_point $xZ $yZ $zZ
0002: jump Јcnt
:PASSED ;; метка с выводом сообщения о выигрыше гонки и о пройденной миссии
0394: play_music 1 ;; проигрываем музыку пройденной миссии
0014: $race /= 1000 ;; integer values ;; делим число таймера гонки на 1000
01E5: text_1number_highpriority "TIME" $race 5000 ms 1 ;; выводим текст с именем TIME и с числом $race, т.е. выводит "время: (число $race) "
0110: clear_player $PLAYER_CHAR wanted_level ;; ставим уровень розыска игрока на 0
01E3: text_1number_styled "RACES18" 30000 3000 ms 1 ;; вывод сообщения о выигрыше гонки
0109: player $PLAYER_CHAR money += 30000 ;; даем игроку приз в $30000
042F: save_record 1 $race ;; вроде как сохраняем рекорд гонки - число $race, но в статистике он не отобразится
0002: jump Јclean ;; идем к метке очистки миссии
:RACEFA ;; метка с текстом о провале гонки
00BC: text_highpriority "RACEFA" 4000 ms 1 ;; выводим текст о том, что гонка не выиграна
0002: jump ЈFAIL
:PROTD ;; метка для ожидания 0 мс, можно не использовать, но мешать это не будет
0001: wait 0 ms
:FAIL
00BA: text_styled "M_FAIL" 4000 ms 1 ;; выводим текст о провале миссии, кстати, 4000 ms - это время, сколько будет текст на экране, 1 - это тип текста, поизменяйте его на 2 3 4 5 6, увидите разницу
0051: return ;; возврат к чему-то, не знаю только к чему, писать всё-таки следует
:clean ;; метка очистки миссии
0004: $ONMISSION = 0 ;; ставим флаг "игрок не на миссии"
004F: create_thread ЈЈstartracer ;; создаем ссылку на поток startracer
;; P.S. create_thread - исключение из правил J, JJ будет везде и в миссии, и в MAIN'e.
03BD: destroy_sphere $sph ;; убираем отметку $sphere
01E7: remove_forbidden_for_cars_cube -252.929 -337.286 9.307 -455.861 -499.581 10.210 ;; убираем запрещённую область для машин на старте гонки
014F: stop_timer $race ;; останавливаем и убираем таймер $race
0164: disable_marker $mrk ;; убираем с карты маркер над противником $mrk
0164: disable_marker $chk ;; убираем с карты маркер контрольной точки $chk
01C3: remove_references_to_car $zbr ;; Like turning a car into any random car ;; делаем тачку противника "уличной"
01C3: remove_references_to_car $playcar ;; Like turning a car into any random car ;; делаем тачку игрока "уличной"
01C2: remove_references_to_actor $vd ;; Like turning an actor into a random pedestrian ;; делаем противника в гонке обычным прохожим
0249: release_model #HOTRING ;; удаляем из памяти модель тачки
0249: release_model #WMYGO ;; удаляем из памяти модели водителя
00D8: mission_cleanup ;; удаляем код миссии из памяти
0051: return ;; возвращаемся к прежнему состоянию, которое было до миссии
Ну вот! Я научил вас созданию гонки, с этим материалом вы научитесь создавать гонки на 2 гонщиков.
С уважением, zx300