00052. Пример полноценной миссии "Взрывчатка"

Пример полноценной миссии "Взрывчатка"|Всем привет! Давно не было уроков по скриптингу Санни Билдер, так как все известные моменты мы рассмотрели, я решил писать уже не уроки, а примеры полноценных миссий. Сегодня мы будем "хардкорить" в написании миссии, которую я назвал "Взрывчатка".|wmysterio|wmysterio||||Суть миссии в том, что к CJ обращается Свит и сообщает что его машину заминировали. Допустим, что Свит насколько привязан к этой тачки, что решает разминировать её. Нам необходимо привести сапёра, чтобы тот взялся за это нелёгкое дело. Как оказалось, что для этого дела понадобится неординарное решение - чтобы успешно разминировать её, нужно держать скорость автомобиля примерно на скорости 100 км/час. В противном случаи машину не разминировать. Думаю идея понятна.

Хочу добавить, что данная статья не для новичков, а для тех, что более-менее уже понимает чужой код и может дополнить его.

Давайте приступим к написанию кода. Миссию мы будем делать, используя CLEO. Я сочинил простейший стартер, который запустит нашу миссию.

{$CLEO .cm}
thread 'BOMB'

gosub @BOMB_RUN
if
wasted_or_busted
jf @BOMB_FINISH
gosub @BOMB_FAILED

:BOMB_FINISH
$ONMISSION = 0
mission_cleanup
end_thread

:BOMB_RUN
increment_mission_attempts
$ONMISSION = 1
wait 1000
fade 1 1000

// Код миссии

gosub @BOMB_END
0394: play_music 1
01E3: show_text_1number_styled GXT 'M_PASS' number 5000 time 5000 style 1
Player.Money(0) += 5000
return

:BOMB_FAILED
gosub @BOMB_END
00BA: show_text_styled GXT 'M_FAIL' time 5000 style 1 
return

:BOMB_END
return

А необходимую конструкцию миссии я привёл к такому виду:

{$CLEO .cm}
thread 'BOMB'

gosub @BOMB_RUN
if
wasted_or_busted
jf @BOMB_FINISH
gosub @BOMB_FAILED

:BOMB_FINISH
$ONMISSION = 0
mission_cleanup
end_thread

:BOMB_RUN
increment_mission_attempts
$ONMISSION = 1
wait 1000
fade 1 1000

// Код миссии

gosub @BOMB_END
0394: play_music 1
01E3: show_text_1number_styled GXT 'M_PASS' number 5000 time 5000 style 1
Player.Money(0) += 5000
return

:BOMB_FAILED
gosub @BOMB_END
00BA: show_text_styled GXT 'M_FAIL' time 5000 style 1 
return

:BOMB_END
return

Приступаем к написанию последовательности скрипта. Прежде всего очищаем местность от всего хлама и рендерим местность для камеры, убрав трафик пешеходов и автомобилей. Создаём неподалёку тачку Свита и садовим его в транспорт. Перемещаем СЖ к нему:

03DE: set_pedestrians_density_multiplier_to 0.0
01EB: set_traffic_density_multiplier_to 0.0
00C0: set_current_time 4 0
0395: clear_area 0 at 2514.7581 -1670.5378 12.5749 radius 3.0
04E4: refresh_game_renderer_at 2514.7581 -1670.5378
023C: load_special_actor 'SWEET' as 1
model.Load(#GREENWOO)
038B: load_requested_models

repeat
wait 0
until 023D: special_actor 1 loaded

0@ = Car.Create(#GREENWOO, 2517.1985, -1665.6057, 12.7179)
Car.Angle(0@) = 96.3102
0229: set_car 0@ primary_color_to 0 secondary_color_to 1
01C8: 1@ = create_actor_pedtype 23 model #SPECIAL01 in_car 0@ passenger_seat 0
077A: set_actor 1@ acquaintance 0 to_actors_pedtype 0
0296: unload_special_actor 1
Model.Destroy(#GREENWOO)
Actor.PutAt($PLAYER_ACTOR, 2516.5964, -1663.8156, 12.8959)
Actor.Angle($PLAYER_ACTOR) = 203.1531

Ставим нашим героям иммунитеты и устанавливаем камеру для видеоролика. Дальше пишем код пропуска этого видеоролика:

Car.SetImmunities(0@, 1, 1, 1, 1, 1)
Actor.SetImmunities(1@, 1, 1, 1, 1, 1)
015F: set_camera_position 2513.7539 -1666.6892 14.5696 rotation 0.0 0.0 0.0
0160: set_camera_point_at 2516.5203 -1664.2532 13.8745 switchstyle 2
wait 1000
00BE: text_clear_all
03E6: remove_text_box
0826: enable_hud 0
0581: enable_radar 0
02A3: enable_widescreen 1
05BF: AS_actor 1@ look_at_actor $PLAYER_ACTOR 20000 ms
05BF: AS_actor $PLAYER_ACTOR look_at_actor 1@ 20000 ms
fade 1 1000
0707: start_scene_skip_to @BOMB_END_SCENE_1
wait 1000
// Диалог

:BOMB_END_SCENE_1
fade 0 1000
0701: end_scene_skip
wait 1000

Используется анимация PED, актёры смотрят друг на друга и шевелят губами. По окончанию диалога, как и при нажатии клавиши Пробел` идёт затемнение экрана, СЖ перемещается в транспорт, за руль. Камера сбрасывается в обычный режим.

Далее, по-сюжету, мы должны приехать к сапёру, и подобрать его. Организуем простой цикл, в котором нельзя ехать больше 100 км/час. В нём же не допустим смерти тачки и Свита:

Player.CanMove(0, 1)
Actor.SetImmunities($PLAYER_ACTOR, 0, 0, 0, 0, 0)
Car.SetImmunities(0@, 0, 0, 0, 0, 0)
Actor.SetImmunities(1@, 0, 0, 0, 0, 0)
2@ = 99
5@ = 0

while 5@ == 0
wait 0
 if or
 0741: actor $PLAYER_ACTOR busted
 Actor.Dead($PLAYER_ACTOR)
 then
 5@ = -3
 continue
 end 
 if or
 02BF: car 0@ sunk
 car.Wrecked(0@)
 then
 5@ = -1
 continue
 end 
 if
 Actor.Dead(1@)
 then
 5@ = -2
 continue
 end 
 02E3: 10@ = car 0@ speed
 10@ *= 4.2
 if
 10@ > 99.0
 then
 then
 5@ = -4
 continue
 end
 if and
 not 2@ == 1
 Actor.InCar($PLAYER_ACTOR, 0@)
 Actor.InCar(1@, 0@)
 then
 Marker.Disable(6@)
 Marker.Disable(7@)
 018A: 3@ = create_checkpoint_at 2336.2732 -1679.54 12.2143
 03BC: 4@ = create_sphere_at 2336.2732 -1679.54 12.2143 radius 2.0
 0AD1: show_formatted_text_highpriority "O¦£pa¢ž¬¦ec© k ~y~ca£epy~w~!" time 3000
 2@ = 1
 continue
 end 
 if or
 not Actor.InCar($PLAYER_ACTOR, 0@)
 not Actor.InCar(1@, 0@)
 then
 if
 2@ == 1
 then
 Marker.Disable(3@)
 03BD: destroy_sphere 4@
 6@ = Marker.CreateAboveActor(1@)
 7@ = Marker.CreateAboveCar(0@)
 0AD1: show_formatted_text_highpriority "Cašœ¦ec© ¢ ~b~¯a¥œ®y~w~!" time 3000
 2@ = 2
 continue
 end
 end 
 if AND
 2@ == 1
 00EC: actor $PLAYER_ACTOR sphere 0 near_point 2336.2732 -1679.54 radius 2.0 2.0
 then
 5@ = 1
 end
end

Marker.Disable(3@)
03BD: destroy_sphere 4@
Marker.Disable(6@)
Marker.Disable(7@)
if
5@ == -1
then
jump @BOMB_FINISH_SWEET_DEAD
end
if
5@ == -2
then
jump @BOMB_FINISH_CAR_DEAD
end
if
5@ == -3
then
jump @BOMB_FAILED
end
if
5@ == -4
then
jump @BOMB_SPEED
end

Player.CanMove(0, 0)
Actor.SetImmunities($PLAYER_ACTOR, 1, 1, 1, 1, 1)
Car.SetImmunities(0@, 1, 1, 1, 1, 1)
Actor.SetImmunities(1@, 1, 1, 1, 1, 1)
fade 0 1000
wait 1000
// Следующая мини-сцена

{ блоки провала }
:BOMB_FINISH_SWEET_DEAD
gosub @BOMB_END
00BA: show_text_styled GXT 'M_FAIL' time 5000 style 1
0AD1: show_formatted_text_highpriority "Cўњ¦ yЇep!" time 3000
return

:BOMB_FINISH_CAR_DEAD
gosub @BOMB_END
00BA: show_text_styled GXT 'M_FAIL' time 5000 style 1
0AD1: show_formatted_text_highpriority "–aҐњ®a y®њ¤¦o›e®a!" time 3000
return

:BOMB_SPEED
gosub @BOMB_END
00BA: show_text_styled GXT 'M_FAIL' time 5000 style 1
0AD1: show_formatted_text_highpriority "‹Ё ЈpeўЁcњћњ ckopoc¦©!" time 3000
return

Дальше нужно организовать цикл, в котором будут условия обезвреживания бомбы. Как сказал в диалогах сапёр, нужно проверить на открытия двери, чтобы взорвать транспорт. Это можно осуществить путём проверки к-ва занятых мест. Если такое число превышает 0, то это значит, что кто-то покинул траспорт, тем самым открыв дверь. Цикл будел разделён на три этапа:

  • Когда игрок не набрал 100 км/час

  • Когда уже набрал такую скорость, включается таймер

  • Ожидание времени. Для полного хардкора включим трафик, чтобы игрок попотел :)

5@ = 0
3@ = 1 // etap
02E3: $CAR_SPEED = car 0@ speed
008C: $CAR_SPEED = float $CAR_SPEED to_integer
04F7: status_text $CAR_SPEED type 0 line 1 GXT 'DEF0' // global_variable // Score
$TIMER = 60000

while 5@ == 0
wait 0
 if or
 02BF: car 0@ sunk
 car.Wrecked(0@)
 then
 5@ = -1
 continue
 end
 if
 Actor.Dead(1@)
 then
 5@ = -2
 continue
 end 
 if
 Actor.Dead(11@)
 then
 5@ = -3
 continue
 end 
 
 01E9: 10@ = car 0@ num_passengers
 046C: 12@ = car 0@ driver

 if OR
 87D6: not 12@ == $PLAYER_ACTOR // @ == $ (int)
 not 10@ == 2
 then
 020B: explode_car 0@
 continue
 end
 
 02E3: $CAR_SPEED = car 0@ speed
 $CAR_SPEED *= 3.2 
 008C: $CAR_SPEED = float $CAR_SPEED to_integer
 
 if AND
 3@ == 1
 $CAR_SPEED > 100
 then
 3@ = 2
 continue
 end
 
 if
 3@ == 2
 then 
 03C3: set_timer_to $TIMER type 1 GXT 'DEF1' // global_variable // Time
 3@ = 3
 end
 
 if AND
 3@ == 3
 Actor.InCar($PLAYER_ACTOR, 0@)
 100 > $CAR_SPEED
 then
 020B: explode_car 0@
 continue
 end
 
 if AND
 3@ == 3
 Actor.InCar($PLAYER_ACTOR, 0@)
 $TIMER == 0
 then
 5@ = 1
 end 
end

014F: stop_timer $TIMER
0151: remove_status_text $CAR_SPEED
if
5@ == -1
then
jump @BOMB_FINISH_CAR_DEAD
end
if
5@ == -2
then
jump @BOMB_FINISH_SWEET_DEAD
end
if
5@ == -3
then
jump @BOMB_FINISH_SAP_DEAD
end

Нам осталось только написать код, который выгружает из памяти все ненужные объекты:

:BOMB_END
if
056D: actor 1@ defined
then
Actor.RemoveReferences(1@)
Actor.DestroyInstantly(1@)
end
if
056D: actor 11@ defined
then
Actor.RemoveReferences(11@)
Actor.DestroyInstantly(11@)
end
if
056E: car 0@ defined
then
Car.RemoveReferences(0@)
 if
 not Actor.InCar($PLAYER_ACTOR, 0@)
 then
 Car.Destroy(0@)
 end
end
return

Результат нашей миссии:

Вам задание: Дописать миссию до логического завершения - нужно приехать к дому Свита. На этом урок окончен. С Вами был wmysterio, всего доброго!

P.S Исходники вы можете скачать здесь. Улучшайте миссию на свой вкус.|1238|1|0|12857216png800480400240``\|79472534png800480400240``||primer_polnocennoj_missii_vzryvchatka|1504598907

Last updated