В этой статье я вам расскажу о принципах создания гонки для 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