000161. Очень длинные миссии в main.scm
Очень длинные миссии в main.scm||wmysterio|wmysterio|[email protected]|||Всем привет! Мы возвращаемся к кодингу 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 [email protected] [email protected] [email protected] from_actor $PLAYER_ACTOR with_offset 0.0 1.0 -1.0 [email protected] = Actor.Angle($PLAYER_ACTOR) [email protected] += 180.0 $SWEET_ACTOR = Actor.Create(7, #SPECIAL01, [email protected], [email protected], [email protected]) Actor.Angle($SWEET_ACTOR) = [email protected] 0296: unload_special_actor 1 Actor.SetImmunities($SWEET_ACTOR, 1, 1, 1, 1, 1) // получаем координаты позиции камеры и её поинта относительно CJ'я 04C4: store_coords_to [email protected] [email protected] [email protected] from_actor $PLAYER_ACTOR with_offset 3.0 0.5 0.0 04C4: store_coords_to [email protected] [email protected] [email protected] from_actor $PLAYER_ACTOR with_offset 0.0 0.5 0.0 Camera.SetPosition([email protected], [email protected], [email protected], 0.0, 0.0, 0.0) 0160: set_camera_point_at [email protected] [email protected] [email protected] switchstyle 2 Т |12|1|0||05219952png754504400267\|93392058png1310624400190||ochen_dlinnye_missii_v_main_scm|1403157306
Copy link
Edit on GitHub