000161. Очень длинные миссии в main.scm
Last updated
Last updated
Очень длинные миссии в main.scm||wmysterio|wmysterio|wmysterio@yandex.ru|||Всем привет! Мы возвращаемся к кодингу MAIN.SCM, и в этом уроке разговор пойдёт об очень длинных миссиях. Случается так, что задание выходит очень длинным для прохождения и часто игроку не удаётся долго пройти миссию из за её длины и сложности. Логично было бы разбить миссию на некоторые этапы прохождения, вместо того, чтобы писать несколько миссий (в пределах её размера). Сегодня я покажу пример такой миссии. Для реализации такой модели, нам будет нужна глобальная переменная, которая будет разбивать миссию на этапы. Допустим, эта переменная будет называться $MISSION_CJ_STAGE, которая изначально будет равна нулю. Я начинаю писать код в новом мейне, по-этому скрипт у меня такой:
КодDEFINE OBJECTS 0
DEFINE MISSIONS 1
DEFINE MISSION 0 AT @LONG_MISSION
DEFINE EXTERNAL_SCRIPTS 0
DEFINE UNKNOWN_EMPTY_SEGMENT 0
DEFINE UNKNOWN_THREADS_MEMORY 2048
//-------------MAIN---------------
:MAIN
thread 'MAIN'
fade 0 0
01F0: set_max_wanted_level_to 6
00C0: set_current_time_hours_to 8 minutes_to 0
04E4: unknown_refresh_game_renderer_at 2491.1572 -1670.3434
Camera.SetAtPos(2491.1572, -1670.3434, 12.3359)
$PLAYER_CHAR = Player.Create(#NULL, 2491.1572, -1670.3434, 12.3359)
$PLAYER_ACTOR = Actor.EmulateFromPlayer($PLAYER_CHAR)
Actor.Angle($PLAYER_ACTOR) = 66.3548
07AF: $PLAYER_GROUP = player $PLAYER_CHAR group
Camera.SetBehindPlayer
Player.SetClothes($PLAYER_CHAR, "WORKTRCAMOGRN", "WORKTR", 2)
Player.SetClothes($PLAYER_CHAR, "SNEAKERBINCGANG", "SNEAKER", 3)
Player.SetClothes($PLAYER_CHAR, "TSHIRTERISORN", "TSHIRT", 0)
Player.Build($PLAYER_CHAR)
Player.CanMove($PLAYER_CHAR) = True
0180: set_on_mission_flag_to $ONMISSION
fade 1 1000
wait 1000
016C: restart_if_wasted_at 2027.77 -1420.52 15.99 angle 137.0 town_number 0
016C: restart_if_wasted_at 1180.85 -1325.57 12.58 angle 271.4 town_number 0
016D: restart_if_busted_at 1550.68 -1675.49 14.51 angle 90.0 town_number 0
016C: restart_if_wasted_at 1244.437 331.2261 18.5547 angle 7.5465 town_number 1
016D: restart_if_busted_at 632.2344 -571.7104 15.3515 angle 267.2 town_number 1
016C: restart_if_wasted_at -2199.719 -2308.075 29.6181 angle 322.8928 town_number 1
016D: restart_if_busted_at -2163.829 -2387.817 29.625 angle 134.2066 town_number 1
016C: restart_if_wasted_at -2670.285 616.4364 13.4531 angle 183.1042 town_number 1
016D: restart_if_busted_at -1605.792 716.8598 11.0241 angle 355.2978 town_number 1
016C: restart_if_wasted_at -316.3832 1056.045 18.7344 angle 1.6017 town_number 2
016D: restart_if_busted_at -212.1889 979.4168 18.3219 angle 278.0478 town_number 2
016C: restart_if_wasted_at -1514.823 2527.119 54.7443 angle 2.3546 town_number 2
016D: restart_if_busted_at -1393.072 2633.116 54.9491 angle 86.0424 town_number 2
016C: restart_if_wasted_at 1578.446 1770.682 9.8358 angle 99.7567 town_number 2
016D: restart_if_busted_at 2337.083 2453.802 13.9765 angle 90.7643 town_number 2
create_thread @SAVE
// Параметры запуска стартера
$POS_MIS_X_CJ = 2515.5813
$POS_MIS_Y_CJ = -1671.6604
$POS_MIS_Z_CJ = 13.7364
$MISSION_CJ_TOTAL = 0
$MISSION_CJ_STAGE = 0 // Текущий этам миссии
create_thread @STARTER
end_thread
:SAVE
thread 'SAVE'
while true
wait 0
if
0AB0: key_pressed 115 // F4
then
03D8: show_save_screen
wait 250
end
end
:STARTER
thread 'STARTER'
wait 0
$ICON_MIS_CJ = marker.CreateIconAndSphere(15, $POS_MIS_X_CJ, $POS_MIS_Y_CJ, $POS_MIS_Z_CJ)
:STARTER_A
wait 0
if AND
$ONMISSION == 0
$MISSION_CJ_TOTAL == 0
00EC: actor $PLAYER_ACTOR 0 near_point $POS_MIS_X_CJ $POS_MIS_Y_CJ radius 2.0 2.0
then
Player.CanMove($PLAYER_CHAR) = false
Actor.SetImmunities($PLAYER_ACTOR, 1, 1, 1, 1, 1)
0ACF: show_formatted_styled_text "Long mission" time 5000 style 2
fade 0 1000
wait 1000
start_mission 0
jump @STARTER_END
end
jump @STARTER_A
:STARTER_END
marker.Disable($ICON_MIS_CJ)
end_thread
//-------------Mission 0---------------
// Originally: MISSION_0
:LONG_MISSION
thread 'LONG_MISSION'
gosub @LONG_MISSION_29_57
if
wasted_or_busted
jf @LONG_MISSION_29_46
gosub @LONG_MISSION_29_144
:LONG_MISSION_29_46
$ONMISSION = 0
mission_cleanup
end_thread
:LONG_MISSION_29_57
increment_mission_attempts
$ONMISSION = 1
// ЗДЕСЬ БУДЕТ КОД НАШЕЙ МИССИИ!!!
gosub @LONG_MISSION_END
01E3: show_text_1number_styled GXT 'M_PASS' number 20000 time 5000 style 1
Player.Money($PLAYER_CHAR) += 20000
0394: play_music 1
return
:LONG_MISSION_29_144
wait 0
gosub @LONG_MISSION_END
create_thread @STARTER
00BA: show_text_styled GXT 'M_FAIL' time 5000 style 1
return
:LONG_MISSION_END
wait 0
returnВооружившись моей программой, создадим таблицу переходов, которая будет определять этапы прохождения. В качестве переменной выбора мы указываем наш флаг этапа а в метке выхода - название потока миссии. Думаю, 5 этапов будет достаточно для примера, по-этому оставим обычные пробелы в 5 первых полях, чтобы сгенерировать код:
В результате у нас получится примерно вот такая таблица:
Код// Определите переменную $MISSION_CJ_STAGE по которой будет осуществлятся выбор.
// Диапазон этой переменной должен быть от 0 до 4 и типа INTEGER.
0871: init_jump_table $MISSION_CJ_STAGE total_jumps 6 default_jump 0 @LONG_MISSION_1663_EXIT jumps 0 @LONG_MISSION_1663_0 1 @LONG_MISSION_1663_1 2 @LONG_MISSION_1663_2 3 @LONG_MISSION_1663_3 4 @LONG_MISSION_1663_4 -1 @LONG_MISSION_1663_EXIT -1 @LONG_MISSION_1663_EXIT
:LONG_MISSION_1663_0 // будет выполнятся этот участок кода, если переменная $MISSION_CJ_STAGE будет равна 0
jump @LONG_MISSION_1663_EXIT
:LONG_MISSION_1663_1 // будет выполнятся этот участок кода, если переменная $MISSION_CJ_STAGE будет равна 1
jump @LONG_MISSION_1663_EXIT
:LONG_MISSION_1663_2 // будет выполнятся этот участок кода, если переменная $MISSION_CJ_STAGE будет равна 2
jump @LONG_MISSION_1663_EXIT
:LONG_MISSION_1663_3 // будет выполнятся этот участок кода, если переменная $MISSION_CJ_STAGE будет равна 3
jump @LONG_MISSION_1663_EXIT
:LONG_MISSION_1663_4 // будет выполнятся этот участок кода, если переменная $MISSION_CJ_STAGE будет равна 4
jump @LONG_MISSION_1663_EXIT
:LONG_MISSION_1663_EXIT
// Продолжайте ваш код ...Убираем все метки из этого участка кода, кроме метки выхода, и копируем код в скрипт миссии, перед gosub'ом на метку очищения памяти от объектов миссии:
Код:LONG_MISSION_29_57
increment_mission_attempts
$ONMISSION = 1
0871: init_jump_table $MISSION_CJ_STAGE total_jumps 6 default_jump 0 @LONG_MISSION_1663_EXIT jumps 0 @LONG_MISSION_1663_0 1 @LONG_MISSION_1663_1 2 @LONG_MISSION_1663_2 3 @LONG_MISSION_1663_3 4 @LONG_MISSION_1663_4 -1 @LONG_MISSION_1663_EXIT -1 @LONG_MISSION_1663_EXIT
:LONG_MISSION_1663_0 // Когда $MISSION_CJ_STAGE == 0
:LONG_MISSION_1663_1 // Когда $MISSION_CJ_STAGE == 1
:LONG_MISSION_1663_2 // Когда $MISSION_CJ_STAGE == 2
:LONG_MISSION_1663_3 // Когда $MISSION_CJ_STAGE == 3
:LONG_MISSION_1663_4 // Когда $MISSION_CJ_STAGE == 4
:LONG_MISSION_1663_EXIT
// Продолжаем код...
gosub @LONG_MISSION_END
01E3: show_text_1number_styled GXT 'M_PASS' number 20000 time 5000 style 1
Player.Money($PLAYER_CHAR) += 20000
0394: play_music 1
returnТаким образом, в зависимости от значения переменной $MISSION_CJ_STAGE скрипт будет переходить между этапами. После прохождения определённого этапа, мы должны увеличить его флаг на единицу:
Код:LONG_MISSION_1663_0
wait 1000
// Код для 1 этапа
fade 0 1000
$MISSION_CJ_STAGE += 1
:LONG_MISSION_1663_1
wait 1000
// Код для 2 этапа
fade 0 1000
$MISSION_CJ_STAGE += 1
:LONG_MISSION_1663_2
wait 1000
// Код для 3 этапа
fade 0 1000
$MISSION_CJ_STAGE += 1
:LONG_MISSION_1663_3
wait 1000
// Код для 4 этапа
fade 0 1000
$MISSION_CJ_STAGE += 1
:LONG_MISSION_1663_4
wait 1000
// Код для 5 этапа
fade 0 1000
$MISSION_CJ_STAGE += 1
:LONG_MISSION_1663_EXIT
Получается, что когда игрок начинает миссию после провала, таблица переходов определяет место продолжения миссии. Это напоминает "точку сохранения (она же контрольная точка)" из других игр. Схематически такую систему можно изобразить следующим образом:
Также нужно учесть, что в последнем этапе мы должны очистить флаг этапа, чтобы следующая миссия в стартере начинала свой сюжет с первого этапа а также нужно увеличить счётчик стартера:
Код:LONG_MISSION_1663_4
wait 1000
// Код для 5 этапа
fade 0 1000
$MISSION_CJ_STAGE = 0
$MISSION_CJ_TOTAL += 1
:LONG_MISSION_1663_EXIT
Я не стану делать сейчас сложную в прохождении миссию, по-этому ограничусь несколькими условиями. Первый этап начнётся видеороликом, в котором Свит разговаривает с CJ. Допустим, они собирались пострелять по бутылкам:
Код:LONG_MISSION_1663_0
01EB: set_traffic_density_multiplier_to 0.0
03DE: set_pedestrians_density_multiplier_to 0.0
0395: clear_area 0 at 2527.4084 -1666.8297 14.1683 radius 3.0
Actor.PutAt($PLAYER_ACTOR, 2527.4084, -1666.8297, 14.1683)
Actor.Angle($PLAYER_ACTOR) = 179.7592
023C: load_special_actor 'SWEET' as 1
repeat
wait 0
until 023D: special_actor 1 loaded
// создаём Свита, относительно CJ'я
04C4: store_coords_to 0@ 1@ 2@ from_actor $PLAYER_ACTOR with_offset 0.0 1.0 -1.0
3@ = Actor.Angle($PLAYER_ACTOR)
3@ += 180.0
$SWEET_ACTOR = Actor.Create(7, #SPECIAL01, 0@, 1@, 2@)
Actor.Angle($SWEET_ACTOR) = 3@
0296: unload_special_actor 1
Actor.SetImmunities($SWEET_ACTOR, 1, 1, 1, 1, 1)
// получаем координаты позиции камеры и её поинта относительно CJ'я
04C4: store_coords_to 0@ 1@ 2@ from_actor $PLAYER_ACTOR with_offset 3.0 0.5 0.0
04C4: store_coords_to 3@ 4@ 5@ from_actor $PLAYER_ACTOR with_offset 0.0 0.5 0.0
Camera.SetPosition(0@, 1@, 2@, 0.0, 0.0, 0.0)
0160: set_camera_point_at 3@ 4@ 5@ switchstyle 2
Т
|12|1|0||05219952png
754504
400267\|93392058
png1310
624400
190||ochen_dlinnye_missii_v_main_scm|1403157306