000133. Делаем диалоги в миссиях

Делаем диалоги в миссиях|Всем привет! В этом, неожиданном для меня уроке, речь пойдёт о диалогах и о том, как можно использовать их, например, в процессе выполнения миссии, где нужно приехать в какую-то точку, и при этом персонажи разговаривали между собой.|wmysterio|wmysterio||||Одним из способов является введение переменной-счётчика для цикла, и при выполнении условия с этим счётчиком мы выводим нужный нам текст. К этому же мы должны создать переменную-индекс, которая будет выводить текст по порядку. Для этого создадим в начале миссии транспорт и случайного актёра, после чего посадим их в транспорт:

Model.Load(#ADMIRAL)
038B: load_requested_models
4@ = car.Create(#ADMIRAL, 2495.6694, -1657.3169, 12.3608)
car.Angle(4@) = 89.0987
0229: set_car 4@ primary_color_to 1 secondary_color_to 1
Model.Destroy(#ADMIRAL)
0560: create_random_actor_in_car 4@ handle_as 3@
0430: put_actor 3@ into_car 4@ passenger_seat 0
072A: put_actor $PLAYER_ACTOR into_car 4@ driverseat

Дальше осветляем экран и вводим переменную-индекс и переменную-счётчик:

fade 1 1000
wait 1000
player.CanMove(0, 1)
actor.SetImmunities($PLAYER_ACTOR, 0, 0, 0, 0, 0)
0@ = 0 // index dialog
1@ = 0.0 // mini-timer dialog

Теперь нужно создать цикл, который будет увеличивать счётчик на 0.25. Это более менее хорошмй вариант. Дальше осуществим перебор условий:

:MISSION_AA_LOOP
wait 0
if
7 > 0@
then
jump @MISSION_AA_LOOP
end

if AND
0@ == 0
1@ >= 40.0
then
0AD0: show_formatted_text_lowpriority "CJ: I drive car in point!" time 5000
0@ += 1
1@ = 0.0
end

if AND
0@ == 1
1@ >= 45.0
then
0AD0: show_formatted_text_lowpriority "Friend: Ok. I sead down in this car!" time 5000
0@ += 1
1@ = 0.0
end

if AND
0@ == 2
1@ >= 45.0
then
0AD0: show_formatted_text_lowpriority "CJ: This point in location Observatory!" time 5000
0@ += 1
1@ = 0.0
end

if AND
0@ == 3
1@ >= 45.0
then
0AD0: show_formatted_text_lowpriority "Friend: I known. Is this car heavy?" time 5000
0@ += 1
1@ = 0.0
end

if AND
0@ == 4
1@ >= 45.0
then
0AD0: show_formatted_text_lowpriority "CJ: No. Light." time 3000
0@ += 1
1@ = 0.0
end

if AND
0@ == 5
1@ >= 25.0
then
0AD0: show_formatted_text_lowpriority "Friend: You drive very good!" time 5000
0@ += 1
1@ = 0.0
end

if AND
0@ == 6
1@ >= 45.0
then
0AD0: show_formatted_text_lowpriority "CJd: Thank you! I drive vehicles very time" time 5000
0@ += 1
1@ = 0.0
end

1@ += 0.25
jump @MISSION_AA_LOOP

У нас будет 7 фраз, каждая из которых имеет индекс, начинающийся с нуля. Сделаем проверку, что если индекс больше 6-ти, то прыгаем на метку начала цикла. Как показала практика, так будет более-менее оптимально для производительности. Дальше уже следуют ряд условий, в которых определяется какой текст и когда нужно выводить. К примеру, "0@ == 3" - идёт проверка на индекс. Если текущий индекс равен 3, то проверяем счётчик: "1@ >= 45.0" - если он больше, чем заданное число, то выводим текст, прибавляем индексу единицу и сбиваем счётчик на ноль.

И так текст будет по очереди выводится, пока индекс будет в заданном диапазоне. Чем меньше число для проверки 1@, тем быстрее выводится текст. В остановился на числе 45.0, так как оно хорошо подходит под время выводимого текста. Как я его получил? Просто:

  • Беру длительность предыдущего текста ( текста выше по коду ) - в нашем случае это 5000;

  • Делю его на 100, получаю 50. Отнимаю 5, получаю 45 и перевожу в дробное 45.0 - это примерно равно 5000 милисекундам ( ЭТО ЕСЛИ К 1@ ПРИБАВЛЯТЬ 0.25, КАК НАПИСАНО В КОДЕ ВЫШЕ. ЕСЛИ ПОМЕНЯТЬ ЭТО ЗНАЧЕНИЕ, ТО ПРОВЕРКУ НУЖНО БУДЕТ ПОДСТРАИВАТЬ )

Хорошо, фразы выводится по очереди. Теперь напишем условия, когда миссия считается проваленной:

if OR
car.Wrecked(4@)
02BF: car 4@ sunk
then
jump @MISSION_29_144_END_CAR
end
if
actor.Dead(3@)
then
jump @MISSION_29_144_END_ACT
end

И создадим соответствующие метки:

:MISSION_29_144_END_CAR
wait 0
gosub @MISSION_END
00BA: show_text_styled GXT 'M_FAIL' time 5000 style 1 // MISSION FAILED
0AD0: show_formatted_text_lowpriority "You car wrecked!" time 4000
return

:MISSION_29_144_END_ACT
wait 0
gosub @MISSION_END
00BA: show_text_styled GXT 'M_FAIL' time 5000 style 1 // MISSION FAILED
0AD0: show_formatted_text_lowpriority "You Friend dai!" time 4000
return

Теперь перед циклом добавим код, который будет говорить о том, куда ехать и создавать сферу и чекпоинт в нужном месте:

:MISSION_AA
wait 0
marker.Disable(5@)
marker.Disable(7@)
018A: 5@ = create_checkpoint_at 1695.4817 -2107.7493 13.5469
03BC: 6@ = create_sphere_at 1695.4817 -2107.7493 13.5469 radius 2.0
0AD0: show_formatted_text_lowpriority "Drive to point!" time 4000

Добавим проверку, что когда игрок с актёром в этой точке, то завершить миссию и сообщить о успешном её выполнении:

:MISSION_AA_LOOP
wait 0

// ...

if AND
actor.InCar($PLAYER_ACTOR, 4@)
actor.InCar(3@, 4@)
00EC: actor $PLAYER_ACTOR sphere 0 near_point 1695.4817 -2107.7493 radius 2.0 2.0
then
jump @MISSION_CC
end

// ...

jump @MISSION_AA_LOOP

:MISSION_CC
marker.Disable(5@)
03BD: destroy_sphere 6@
00BE: text_clear_all
player.CanMove(0, 0)
actor.SetImmunities($PLAYER_ACTOR, 1, 1, 1, 1, 1)
fade 0 1000
wait 1000
0633: AS_actor $PLAYER_ACTOR exit_car

while actor.InCar($PLAYER_ACTOR, 4@)
wait 0
end

gosub @MISSION_END
actor.PutAt($PLAYER_ACTOR, 1698.6144, -2096.208, 12.5469)
actor.Angle($PLAYER_ACTOR) = 181.9148
camera.Restore_WithJumpCut
Camera.SetBehindPlayer
wait 500
fade 1 1000
wait 1000
player.CanMove(0, 1)
actor.SetImmunities($PLAYER_ACTOR, 0, 0, 0, 0, 0)
0394: play_music 1
00BA: show_text_styled GXT 'M_PASSR' time 5000 style 1 // MISSION PASSED
return

Осталось добавить ещё одну вещь: организовать проверку на то, что актёр или игрок покинули транспорт. Я сделал это следующим образом:

:MISSION_AA_LOOP
wait 0

// ...

if OR
not actor.InCar($PLAYER_ACTOR, 4@)
not actor.InCar(3@, 4@)
then
jump @MISSION_BB
end

// ...

jump @MISSION_AA_LOOP

:MISSION_BB
wait 0
marker.Disable(5@)
03BD: destroy_sphere 6@
00BE: text_clear_all
5@ = marker.CreateAboveActor(3@)
07E0: set_marker 5@ type_to 1
7@ = marker.CreateAboveCar(4@)
07E0: set_marker 7@ type_to 1
0AD0: show_formatted_text_lowpriority "Hey, run in car!" time 4000

:MISSION_BB_LOOP
wait 0
if OR
car.Wrecked(4@)
02BF: car 4@ sunk
then
jump @MISSION_29_144_END_CAR
end
if
actor.Dead(3@)
then
jump @MISSION_29_144_END_ACT
end
if AND
actor.InCar($PLAYER_ACTOR, 4@)
actor.InCar(3@, 4@)
then
jump @MISSION_AA
end
jump @MISSION_BB_LOOP

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

{$CLEO .cm}

//------------- Mission ---------------

:MISSION
thread 'MISSION'
gosub @MISSION_29_57 
if 
wasted_or_busted 
jf @MISSION_29_46 
gosub @MISSION_29_144 

:MISSION_29_46
$ONMISSION = 0 
mission_cleanup 
end_thread 

:MISSION_29_57
increment_mission_attempts 
$ONMISSION = 1 
Model.Load(#ADMIRAL)
038B: load_requested_models
4@ = car.Create(#ADMIRAL, 2495.6694, -1657.3169, 12.3608)
car.Angle(4@) = 89.0987
0229: set_car 4@ primary_color_to 1 secondary_color_to 1
Model.Destroy(#ADMIRAL)
0560: create_random_actor_in_car 4@ handle_as 3@
0430: put_actor 3@ into_car 4@ passenger_seat 0
072A: put_actor $PLAYER_ACTOR into_car 4@ driverseat
wait 1000
camera.Restore_WithJumpCut
Camera.SetBehindPlayer
fade 1 1000
wait 1000
player.CanMove(0, 1)
actor.SetImmunities($PLAYER_ACTOR, 0, 0, 0, 0, 0)
0@ = 0 // index dialog
1@ = 0.0 // mini-timer dialog

:MISSION_AA
wait 0
marker.Disable(5@)
marker.Disable(7@)
018A: 5@ = create_checkpoint_at 1695.4817 -2107.7493 13.5469
03BC: 6@ = create_sphere_at 1695.4817 -2107.7493 13.5469 radius 2.0
0AD0: show_formatted_text_lowpriority "Drive to point!" time 4000

:MISSION_AA_LOOP
wait 0
if OR
car.Wrecked(4@)
02BF: car 4@ sunk
then
jump @MISSION_29_144_END_CAR
end
if
actor.Dead(3@)
then
jump @MISSION_29_144_END_ACT
end
if OR
not actor.InCar($PLAYER_ACTOR, 4@)
not actor.InCar(3@, 4@)
then
jump @MISSION_BB
end
if AND
actor.InCar($PLAYER_ACTOR, 4@)
actor.InCar(3@, 4@)
00EC: actor $PLAYER_ACTOR sphere 0 near_point 1695.4817 -2107.7493 radius 2.0 2.0
then
jump @MISSION_CC
end

if
0@ > 6
then
jump @MISSION_AA_LOOP
end
if AND
0@ == 0
1@ >= 40.0
then
0AD0: show_formatted_text_lowpriority "CJ: I drive car in point!" time 5000
0@ += 1
1@ = 0.0
end
if AND
0@ == 1
1@ >= 45.0
then
0AD0: show_formatted_text_lowpriority "Friend: Ok. I sead down in this car!" time 5000
0@ += 1
1@ = 0.0
end
if AND
0@ == 2
1@ >= 45.0
then
0AD0: show_formatted_text_lowpriority "CJ: This point in location Observatory!" time 5000
0@ += 1
1@ = 0.0
end
if AND
0@ == 3
1@ >= 45.0
then
0AD0: show_formatted_text_lowpriority "Friend: I known. Is this car heavy?" time 5000
0@ += 1
1@ = 0.0
end
if AND
0@ == 4
1@ >= 45.0
then
0AD0: show_formatted_text_lowpriority "CJ: No. Light." time 3000
0@ += 1
1@ = 0.0
end
if AND
0@ == 5
1@ >= 25.0
then
0AD0: show_formatted_text_lowpriority "Friend: You drive very good!" time 5000
0@ += 1
1@ = 0.0
end
if AND
0@ == 6
1@ >= 45.0
then
0AD0: show_formatted_text_lowpriority "CJd: Thank you! I drive vehicles very time" time 5000
0@ += 1
1@ = 0.0
end
1@ += 0.25
jump @MISSION_AA_LOOP

:MISSION_BB
wait 0
marker.Disable(5@)
03BD: destroy_sphere 6@
00BE: text_clear_all
5@ = marker.CreateAboveActor(3@)
07E0: set_marker 5@ type_to 1
7@ = marker.CreateAboveCar(4@)
07E0: set_marker 7@ type_to 1
0AD0: show_formatted_text_lowpriority "Hey, run in car!" time 4000

:MISSION_BB_LOOP
wait 0
if OR
car.Wrecked(4@)
02BF: car 4@ sunk
then
jump @MISSION_29_144_END_CAR
end
if
actor.Dead(3@)
then
jump @MISSION_29_144_END_ACT
end
if AND
actor.InCar($PLAYER_ACTOR, 4@)
actor.InCar(3@, 4@)
then
jump @MISSION_AA
end
jump @MISSION_BB_LOOP

:MISSION_CC
marker.Disable(5@)
03BD: destroy_sphere 6@
00BE: text_clear_all
player.CanMove(0, 0)
actor.SetImmunities($PLAYER_ACTOR, 1, 1, 1, 1, 1)
fade 0 1000
wait 1000
0633: AS_actor $PLAYER_ACTOR exit_car

while actor.InCar($PLAYER_ACTOR, 4@)
wait 0
end

gosub @MISSION_END
actor.PutAt($PLAYER_ACTOR, 1698.6144, -2096.208, 12.5469)
actor.Angle($PLAYER_ACTOR) = 181.9148
camera.Restore_WithJumpCut
Camera.SetBehindPlayer
wait 500
fade 1 1000
wait 1000
player.CanMove(0, 1)
actor.SetImmunities($PLAYER_ACTOR, 0, 0, 0, 0, 0)
0394: play_music 1
00BA: show_text_styled GXT 'M_PASSR' time 5000 style 1 // MISSION PASSED
return 

:MISSION_29_144
wait 0 
gosub @MISSION_END
00BA: show_text_styled GXT 'M_FAIL' time 5000 style 1 // MISSION FAILED
return

:MISSION_29_144_END_CAR
wait 0 
gosub @MISSION_END
00BA: show_text_styled GXT 'M_FAIL' time 5000 style 1 // MISSION FAILED
0AD0: show_formatted_text_lowpriority "You car wrecked!" time 4000
return

:MISSION_29_144_END_ACT
wait 0 
gosub @MISSION_END
00BA: show_text_styled GXT 'M_FAIL' time 5000 style 1 // MISSION FAILED
0AD0: show_formatted_text_lowpriority "You Friend dai!" time 4000
return

:MISSION_END
wait 0
if
056D: actor 3@ defined
then
actor.RemoveReferences(3@)
actor.DestroyInstantly(3@)
end
if
056E: car 4@ defined
then
car.RemoveReferences(4@)
 if
 not actor.InCar($PLAYER_ACTOR, 4@)
 then
 car.Destroy(4@)
 end
end
marker.Disable(5@)
marker.Disable(7@)
03BD: destroy_sphere 6@
return

Что же, это один из способов вывода текста последовательно, имитируя диалог между персонажами. Надеюсь, он поможет Вам у проектах ;)|1550|1|0||delaem_dialogi_v_missijakh|1504590898

Last updated