From 3b5174634cd3ccdc172484718ee9b7a65c4ba8da Mon Sep 17 00:00:00 2001 From: JezuzLizard Date: Tue, 12 May 2020 10:36:10 -0700 Subject: [PATCH] uploading 64 scripts as a baseline from zm_tomb_patch --- .../maps/mp/gametypes_zm/zstandard.gsc | 43 + zm_tomb_patch/maps/mp/zm_tomb.gsc | 2238 ++++++++++++ zm_tomb_patch/maps/mp/zm_tomb_achievement.gsc | 239 ++ zm_tomb_patch/maps/mp/zm_tomb_amb.gsc | 713 ++++ .../maps/mp/zm_tomb_ambient_scripts.gsc | 122 + .../maps/mp/zm_tomb_capture_zones.gsc | 2777 ++++++++++++++ .../maps/mp/zm_tomb_capture_zones_ffotd.gsc | 27 + zm_tomb_patch/maps/mp/zm_tomb_challenges.gsc | 383 ++ zm_tomb_patch/maps/mp/zm_tomb_chamber.gsc | 349 ++ zm_tomb_patch/maps/mp/zm_tomb_classic.gsc | 36 + zm_tomb_patch/maps/mp/zm_tomb_craftables.gsc | 1489 ++++++++ zm_tomb_patch/maps/mp/zm_tomb_dig.gsc | 1034 ++++++ .../maps/mp/zm_tomb_distance_tracking.gsc | 433 +++ zm_tomb_patch/maps/mp/zm_tomb_ee_lights.gsc | 197 + zm_tomb_patch/maps/mp/zm_tomb_ee_main.gsc | 527 +++ .../maps/mp/zm_tomb_ee_main_step_1.gsc | 29 + .../maps/mp/zm_tomb_ee_main_step_2.gsc | 159 + .../maps/mp/zm_tomb_ee_main_step_3.gsc | 153 + .../maps/mp/zm_tomb_ee_main_step_4.gsc | 249 ++ .../maps/mp/zm_tomb_ee_main_step_5.gsc | 151 + .../maps/mp/zm_tomb_ee_main_step_6.gsc | 156 + .../maps/mp/zm_tomb_ee_main_step_7.gsc | 93 + .../maps/mp/zm_tomb_ee_main_step_8.gsc | 105 + zm_tomb_patch/maps/mp/zm_tomb_ee_side.gsc | 668 ++++ zm_tomb_patch/maps/mp/zm_tomb_ffotd.gsc | 240 ++ zm_tomb_patch/maps/mp/zm_tomb_fx.gsc | 147 + zm_tomb_patch/maps/mp/zm_tomb_gamemodes.gsc | 13 + zm_tomb_patch/maps/mp/zm_tomb_giant_robot.gsc | 2364 ++++++++++++ .../maps/mp/zm_tomb_giant_robot_ffotd.gsc | 35 + zm_tomb_patch/maps/mp/zm_tomb_main_quest.gsc | 1351 +++++++ zm_tomb_patch/maps/mp/zm_tomb_quest_air.gsc | 283 ++ zm_tomb_patch/maps/mp/zm_tomb_quest_crypt.gsc | 377 ++ zm_tomb_patch/maps/mp/zm_tomb_quest_elec.gsc | 476 +++ zm_tomb_patch/maps/mp/zm_tomb_quest_fire.gsc | 525 +++ zm_tomb_patch/maps/mp/zm_tomb_quest_ice.gsc | 357 ++ zm_tomb_patch/maps/mp/zm_tomb_standard.gsc | 27 + zm_tomb_patch/maps/mp/zm_tomb_tank.gsc | 1835 ++++++++++ zm_tomb_patch/maps/mp/zm_tomb_teleporter.gsc | 432 +++ zm_tomb_patch/maps/mp/zm_tomb_utility.gsc | 1923 ++++++++++ zm_tomb_patch/maps/mp/zm_tomb_vo.gsc | 2789 ++++++++++++++ .../maps/mp/zombies/_zm_ai_mechz.gsc | 2175 +++++++++++ .../maps/mp/zombies/_zm_ai_mechz_booster.gsc | 300 ++ .../maps/mp/zombies/_zm_ai_mechz_claw.gsc | 637 ++++ .../maps/mp/zombies/_zm_ai_mechz_dev.gsc | 505 +++ .../maps/mp/zombies/_zm_ai_mechz_ffotd.gsc | 33 + .../maps/mp/zombies/_zm_ai_mechz_ft.gsc | 589 +++ .../maps/mp/zombies/_zm_ai_quadrotor.gsc | 1264 +++++++ .../maps/mp/zombies/_zm_challenges.gsc | 884 +++++ .../maps/mp/zombies/_zm_craftables.gsc | 3241 +++++++++++++++++ .../maps/mp/zombies/_zm_magicbox_tomb.gsc | 298 ++ .../maps/mp/zombies/_zm_melee_weapon.gsc | 627 ++++ .../maps/mp/zombies/_zm_perk_divetonuke.gsc | 180 + .../mp/zombies/_zm_powerup_zombie_blood.gsc | 217 ++ .../maps/mp/zombies/_zm_riotshield_tomb.gsc | 671 ++++ .../mp/zombies/_zm_weap_ballistic_knife.gsc | 308 ++ .../maps/mp/zombies/_zm_weap_beacon.gsc | 1008 +++++ .../maps/mp/zombies/_zm_weap_claymore.gsc | 482 +++ .../mp/zombies/_zm_weap_one_inch_punch.gsc | 369 ++ .../mp/zombies/_zm_weap_riotshield_tomb.gsc | 783 ++++ .../maps/mp/zombies/_zm_weap_staff_air.gsc | 640 ++++ .../maps/mp/zombies/_zm_weap_staff_fire.gsc | 452 +++ .../mp/zombies/_zm_weap_staff_lightning.gsc | 444 +++ .../maps/mp/zombies/_zm_weap_staff_revive.gsc | 74 + .../maps/mp/zombies/_zm_weap_staff_water.gsc | 545 +++ zm_tomb_patch/readme.md | 73 + 65 files changed, 42343 insertions(+) create mode 100644 zm_tomb_patch/maps/mp/gametypes_zm/zstandard.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_achievement.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_amb.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_ambient_scripts.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_capture_zones.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_capture_zones_ffotd.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_challenges.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_chamber.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_classic.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_craftables.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_dig.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_distance_tracking.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_ee_lights.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_ee_main.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_1.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_2.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_3.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_4.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_5.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_6.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_7.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_8.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_ee_side.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_ffotd.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_fx.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_gamemodes.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_giant_robot.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_giant_robot_ffotd.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_main_quest.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_quest_air.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_quest_crypt.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_quest_elec.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_quest_fire.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_quest_ice.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_standard.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_tank.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_teleporter.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_utility.gsc create mode 100644 zm_tomb_patch/maps/mp/zm_tomb_vo.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz_booster.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz_claw.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz_dev.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz_ffotd.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz_ft.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_ai_quadrotor.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_challenges.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_craftables.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_magicbox_tomb.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_melee_weapon.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_perk_divetonuke.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_powerup_zombie_blood.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_riotshield_tomb.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_weap_ballistic_knife.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_weap_beacon.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_weap_claymore.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_weap_one_inch_punch.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_weap_riotshield_tomb.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_weap_staff_air.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_weap_staff_fire.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_weap_staff_lightning.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_weap_staff_revive.gsc create mode 100644 zm_tomb_patch/maps/mp/zombies/_zm_weap_staff_water.gsc diff --git a/zm_tomb_patch/maps/mp/gametypes_zm/zstandard.gsc b/zm_tomb_patch/maps/mp/gametypes_zm/zstandard.gsc new file mode 100644 index 0000000..95e51ef --- /dev/null +++ b/zm_tomb_patch/maps/mp/gametypes_zm/zstandard.gsc @@ -0,0 +1,43 @@ +#include maps/mp/zombies/_zm; +#include maps/mp/zombies/_zm_ai_dogs; +#include maps/mp/zombies/_zm_stats; +#include common_scripts/utility; +#include maps/mp/gametypes_zm/_hud_util; +#include maps/mp/_utility; + +main() +{ + maps/mp/gametypes_zm/_zm_gametype::main(); + level.onprecachegametype = ::onprecachegametype; + level.onstartgametype = ::onstartgametype; + level._game_module_custom_spawn_init_func = ::maps/mp/gametypes_zm/_zm_gametype::custom_spawn_init_func; + level._game_module_stat_update_func = ::maps/mp/zombies/_zm_stats::survival_classic_custom_stat_update; + maps/mp/gametypes_zm/_zm_gametype::post_gametype_main( "zstandard" ); +} + +onprecachegametype() +{ + level.playersuicideallowed = 1; + level.canplayersuicide = ::canplayersuicide; + level.suicide_weapon = "death_self_zm"; + precacheitem( "death_self_zm" ); + maps/mp/zombies/_zm_ai_dogs::init(); + maps/mp/gametypes_zm/_zm_gametype::rungametypeprecache( "zstandard" ); +} + +onstartgametype() +{ + maps/mp/gametypes_zm/_zm_gametype::setup_classic_gametype(); + maps/mp/gametypes_zm/_zm_gametype::rungametypemain( "zstandard", ::zstandard_main ); +} + +zstandard_main() +{ + level.dog_rounds_allowed = getgametypesetting( "allowdogs" ); + if ( level.dog_rounds_allowed ) + { + maps/mp/zombies/_zm_ai_dogs::enable_dog_rounds(); + } + level thread maps/mp/zombies/_zm::round_start(); + level thread maps/mp/gametypes_zm/_zm_gametype::kill_all_zombies(); +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb.gsc b/zm_tomb_patch/maps/mp/zm_tomb.gsc new file mode 100644 index 0000000..422153a --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb.gsc @@ -0,0 +1,2238 @@ +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/zombies/_zm_challenges; +#include maps/mp/zombies/_zm_score; +#include maps/mp/zombies/_zm_devgui; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/_visionset_mgr; +#include maps/mp/zm_tomb_chamber; +#include maps/mp/zombies/_zm_zonemgr; +#include maps/mp/zm_tomb_main_quest; +#include maps/mp/zm_tomb_dig; +#include maps/mp/zm_tomb_ambient_scripts; +#include maps/mp/zm_tomb_challenges; +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/zm_tomb_distance_tracking; +#include maps/mp/zm_tomb; +#include maps/mp/zombies/_zm_weap_one_inch_punch; +#include maps/mp/zombies/_zm_perk_electric_cherry; +#include maps/mp/zombies/_zm_perks; +#include maps/mp/zombies/_zm_perk_divetonuke; +#include maps/mp/zm_tomb_vo; +#include maps/mp/gametypes_zm/_spawning; +#include maps/mp/animscripts/zm_death; +#include maps/mp/zm_tomb_capture_zones; +#include maps/mp/zm_tomb_ffotd; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +gamemode_callback_setup() +{ + maps/mp/zm_tomb_gamemodes::init(); +} + +survival_init() +{ + level.force_team_characters = 1; + level.should_use_cia = 0; + if ( randomint( 100 ) > 50 ) + { + level.should_use_cia = 1; + } + level.precachecustomcharacters = ::precache_team_characters; + level.givecustomcharacters = ::give_team_characters; + flag_wait( "start_zombie_round_logic" ); +} + +zstandard_preinit() +{ +} + +createfx_callback() +{ + ents = getentarray(); + i = 0; + while ( i < ents.size ) + { + if ( ents[ i ].classname != "info_player_start" ) + { + ents[ i ] delete(); + } + i++; + } +} + +main() +{ + level._no_equipment_activated_clientfield = 1; + level._no_navcards = 1; + level._wallbuy_override_num_bits = 1; + maps/mp/zm_tomb_fx::main(); + level thread maps/mp/zm_tomb_ffotd::main_start(); + level.default_game_mode = "zclassic"; + level.default_start_location = "tomb"; + setup_rex_starts(); + maps/mp/zm_tomb_tank::init_animtree(); + maps/mp/zm_tomb_quest_fire::init_animtree(); + maps/mp/zm_tomb_capture_zones::init_pap_animtree(); + maps/mp/zm_tomb_teleporter::init_animtree(); + maps/mp/zm_tomb_giant_robot::init_animtree(); + level.fx_exclude_edge_fog = 1; + level.fx_exclude_tesla_head_light = 1; + level.fx_exclude_default_explosion = 1; + level.fx_exclude_footsteps = 1; + level._uses_sticky_grenades = 1; + level.disable_fx_zmb_wall_buy_semtex = 1; + level._uses_taser_knuckles = 0; + level.disable_fx_upgrade_aquired = 1; + level._uses_default_wallbuy_fx = 0; + maps/mp/zombies/_zm::init_fx(); + maps/mp/animscripts/zm_death::precache_gib_fx(); + level.zombiemode = 1; + level._no_water_risers = 1; + level.riser_fx_on_client = 1; + maps/mp/zm_tomb_amb::main(); + maps/mp/zombies/_zm_ai_mechz::precache(); + maps/mp/zombies/_zm_ai_quadrotor::precache(); + level.n_active_ragdolls = 0; + level.ragdoll_limit_check = ::ragdoll_attempt; + level._limited_equipment = []; + level._limited_equipment[ level._limited_equipment.size ] = "equip_dieseldrone_zm"; + level._limited_equipment[ level._limited_equipment.size ] = "staff_fire_zm"; + level._limited_equipment[ level._limited_equipment.size ] = "staff_air_zm"; + level._limited_equipment[ level._limited_equipment.size ] = "staff_lightning_zm"; + level._limited_equipment[ level._limited_equipment.size ] = "staff_water_zm"; + level.a_func_vehicle_damage_override = []; + level.callbackvehicledamage = ::tomb_vehicle_damage_override_wrapper; + level.level_specific_stats_init = ::init_tomb_stats; + maps/mp/zombies/_load::main(); + setdvar( "zombiemode_path_minz_bias", 13 ); + setdvar( "tu14_bg_chargeShotExponentialAmmoPerChargeLevel", 1 ); + if ( getDvar( "createfx" ) == "1" ) + { + return; + } + level_precache(); + maps/mp/gametypes_zm/_spawning::level_use_unified_spawning( 1 ); + level thread setup_tomb_spawn_groups(); + spawner_main_chamber_capture_zombies = getent( "chamber_capture_zombie_spawner", "targetname" ); + spawner_main_chamber_capture_zombies add_spawn_function( ::chamber_capture_zombie_spawn_init ); + level.has_richtofen = 0; + level.givecustomloadout = ::givecustomloadout; + level.precachecustomcharacters = ::precache_personality_characters; + level.givecustomcharacters = ::give_personality_characters; + level.setupcustomcharacterexerts = ::setup_personality_character_exerts; + level._zmbvoxlevelspecific = ::maps/mp/zm_tomb_vo::init_level_specific_audio; + level.custom_player_track_ammo_count = ::tomb_custom_player_track_ammo_count; + level.custom_player_fake_death = ::zm_player_fake_death; + level.custom_player_fake_death_cleanup = ::zm_player_fake_death_cleanup; + level.initial_round_wait_func = ::initial_round_wait_func; + level.zombie_init_done = ::zombie_init_done; + level._zombies_round_spawn_failsafe = ::tomb_round_spawn_failsafe; + level.random_pandora_box_start = 1; + level.zombiemode_using_pack_a_punch = 1; + level.zombiemode_reusing_pack_a_punch = 1; + level.zombiemode_using_juggernaut_perk = 1; + level.zombiemode_using_revive_perk = 1; + level.zombiemode_using_sleightofhand_perk = 1; + level.zombiemode_using_additionalprimaryweapon_perk = 1; + level.zombiemode_using_marathon_perk = 1; + level.zombiemode_using_deadshot_perk = 1; + level.zombiemode_using_doubletap_perk = 1; + level.zombiemode_using_random_perk = 1; + level.zombiemode_using_divetonuke_perk = 1; + maps/mp/zombies/_zm_perk_divetonuke::enable_divetonuke_perk_for_level(); + level.custom_electric_cherry_perk_threads = maps/mp/zombies/_zm_perks::register_perk_threads( "specialty_grenadepulldeath", ::tomb_custom_electric_cherry_reload_attack, ::maps/mp/zombies/_zm_perk_electric_cherry::electric_cherry_perk_lost ); + level.zombiemode_using_electric_cherry_perk = 1; + maps/mp/zombies/_zm_perk_electric_cherry::enable_electric_cherry_perk_for_level(); + level.flopper_network_optimized = 1; + level.perk_random_vo_func_usemachine = ::maps/mp/zm_tomb_vo::wunderfizz_used_vo; + maps/mp/zombies/_zm_weap_one_inch_punch::one_inch_precache(); + maps/mp/zombies/_zm_weap_staff_fire::precache(); + maps/mp/zombies/_zm_weap_staff_water::precache(); + maps/mp/zombies/_zm_weap_staff_lightning::precache(); + maps/mp/zombies/_zm_weap_staff_air::precache(); + level._custom_turn_packapunch_on = ::maps/mp/zm_tomb_capture_zones::pack_a_punch_dummy_init; + level.custom_vending_precaching = ::custom_vending_precaching; + level.register_offhand_weapons_for_level_defaults_override = ::offhand_weapon_overrride; + level.zombiemode_offhand_weapon_give_override = ::offhand_weapon_give_override; + level._zombie_custom_add_weapons = ::custom_add_weapons; + level._allow_melee_weapon_switching = 1; + include_equipment( "equip_dieseldrone_zm" ); + include_equipment( "tomb_shield_zm" ); + level.custom_ai_type = []; + level.raygun2_included = 1; + include_weapons(); + include_powerups(); + include_perks_in_random_rotation(); + level maps/mp/zm_tomb_achievement::init(); + precacheitem( "death_throe_zm" ); + if ( level.splitscreen && getDvarInt( "splitscreen_playerCount" ) > 2 ) + { + level.optimise_for_splitscreen = 1; + } + else + { + level.optimise_for_splitscreen = 0; + } + if ( isDefined( level.optimise_for_splitscreen ) && level.optimise_for_splitscreen ) + { + level.culldist = 2500; + } + else + { + level.culldist = 5500; + } + setculldist( level.culldist ); + level thread maps/mp/zm_tomb_distance_tracking::zombie_tracking_init(); + maps/mp/zombies/_zm_magicbox_tomb::init(); + level.special_weapon_magicbox_check = ::tomb_special_weapon_magicbox_check; + maps/mp/zombies/_zm::init(); + level.callbackactordamage = ::tomb_actor_damage_override_wrapper; + level._weaponobjects_on_player_connect_override = ::tomb_weaponobjects_on_player_connect_override; + maps/mp/zombies/_zm_spawner::register_zombie_death_event_callback( ::tomb_zombie_death_event_callback ); + level.player_intersection_tracker_override = ::tomb_player_intersection_tracker_override; + maps/mp/zm_tomb_challenges::challenges_init(); + maps/mp/zombies/_zm_perk_random::init(); + tomb_register_client_fields(); + register_burn_overlay(); + level thread maps/mp/_sticky_grenade::init(); + maps/mp/zm_tomb_tank::init(); + maps/mp/zombies/_zm_weap_beacon::init(); + maps/mp/zombies/_zm_weap_claymore::init(); + maps/mp/zombies/_zm_weap_riotshield_tomb::init(); + maps/mp/zombies/_zm_weap_staff_air::init(); + maps/mp/zombies/_zm_weap_staff_fire::init(); + maps/mp/zombies/_zm_weap_staff_lightning::init(); + maps/mp/zombies/_zm_weap_staff_water::init(); + maps/mp/zombies/_zm_weap_staff_revive::init(); + maps/mp/zombies/_zm_weap_cymbal_monkey::init(); + level._melee_weapons = []; + maps/mp/zm_tomb_giant_robot::init_giant_robot_glows(); + maps/mp/zm_tomb_giant_robot::init_giant_robot(); + level.can_revive = ::maps/mp/zm_tomb_giant_robot::tomb_can_revive_override; + maps/mp/zm_tomb_capture_zones::init_capture_zones(); + level.a_e_slow_areas = getentarray( "player_slow_area", "targetname" ); + maps/mp/zm_tomb_ambient_scripts::init_tomb_ambient_scripts(); + level thread maps/mp/zombies/_zm_ai_mechz::init(); + level thread maps/mp/zombies/_zm_perk_random::init_animtree(); + level thread maps/mp/zombies/_zm_ai_quadrotor::init(); + level.zombiemode_divetonuke_perk_func = ::tomb_custom_divetonuke_explode; + set_zombie_var( "zombie_perk_divetonuke_min_damage", 500 ); + set_zombie_var( "zombie_perk_divetonuke_max_damage", 2000 ); + level.custom_laststand_func = ::tomb_custom_electric_cherry_laststand; + maps/mp/zm_tomb_dig::init_shovel(); + level.n_crystals_pickedup = 0; + level thread maps/mp/zm_tomb_main_quest::main_quest_init(); + level thread maps/mp/zm_tomb_teleporter::teleporter_init(); + level thread maps/mp/zombies/_zm_perk_random::start_random_machine(); + level.closest_player_override = ::tomb_closest_player_override; + level.validate_enemy_path_length = ::tomb_validate_enemy_path_length; + level thread maps/mp/zm_tomb_ee_main::init(); + level thread maps/mp/zm_tomb_ee_side::init(); + level.zones = []; + level.zone_manager_init_func = ::working_zone_init; + init_zones[ 0 ] = "zone_start"; + level thread maps/mp/zombies/_zm_zonemgr::manage_zones( init_zones ); + if ( isDefined( level.optimise_for_splitscreen ) && level.optimise_for_splitscreen ) + { + if ( is_classic() ) + { + level.zombie_ai_limit = 20; + } + setdvar( "fx_marks_draw", 0 ); + setdvar( "disable_rope", 1 ); + setdvar( "cg_disableplayernames", 1 ); + setdvar( "disableLookAtEntityLogic", 1 ); + } + else + { + level.zombie_ai_limit = 24; + } + level thread drop_all_barriers(); + level thread traversal_blocker(); + onplayerconnect_callback( ::on_player_connect ); + maps/mp/zombies/_zm::register_player_damage_callback( ::tomb_player_damage_callback ); + level.custom_get_round_enemy_array_func = ::zm_tomb_get_round_enemy_array; + flag_wait( "start_zombie_round_logic" ); + wait_network_frame(); + level notify( "specialty_additionalprimaryweapon_power_on" ); + wait_network_frame(); + level notify( "additionalprimaryweapon_on" ); + set_zombie_var( "zombie_use_failsafe", 0 ); + level check_solo_status(); + level thread adjustments_for_solo(); + level thread zone_capture_powerup(); + level thread clean_up_bunker_doors(); + level setclientfield( "lantern_fx", 1 ); + level thread maps/mp/zm_tomb_chamber::tomb_watch_chamber_player_activity(); +/# + maps/mp/zm_tomb_utility::setup_devgui(); +#/ + init_weather_manager(); + level thread maps/mp/zm_tomb_ffotd::main_end(); +} + +tomb_register_client_fields() +{ + registerclientfield( "scriptmover", "stone_frozen", 14000, 1, "int" ); + n_bits = getminbitcountfornum( 5 ); + registerclientfield( "world", "rain_level", 14000, n_bits, "int" ); + registerclientfield( "world", "snow_level", 14000, n_bits, "int" ); + registerclientfield( "toplayer", "player_weather_visionset", 14000, 2, "int" ); + n_bits = getminbitcountfornum( 6 ); + registerclientfield( "toplayer", "player_rumble_and_shake", 14000, n_bits, "int" ); + registerclientfield( "scriptmover", "sky_pillar", 14000, 1, "int" ); + registerclientfield( "scriptmover", "staff_charger", 14000, 3, "int" ); + registerclientfield( "toplayer", "player_staff_charge", 14000, 2, "int" ); + registerclientfield( "toplayer", "player_tablet_state", 14000, 2, "int" ); + registerclientfield( "actor", "zombie_soul", 14000, 1, "int" ); + registerclientfield( "zbarrier", "magicbox_runes", 14000, 1, "int" ); + registerclientfield( "scriptmover", "barbecue_fx", 14000, 1, "int" ); + registerclientfield( "world", "cooldown_steam", 14000, 2, "int" ); + registerclientfield( "world", "mus_zmb_egg_snapshot_loop", 14000, 1, "int" ); + registerclientfield( "world", "sndMaelstromPlr0", 14000, 1, "int" ); + registerclientfield( "world", "sndMaelstromPlr1", 14000, 1, "int" ); + registerclientfield( "world", "sndMaelstromPlr2", 14000, 1, "int" ); + registerclientfield( "world", "sndMaelstromPlr3", 14000, 1, "int" ); + registerclientfield( "world", "sndChamberMusic", 14000, 3, "int" ); + registerclientfield( "actor", "foot_print_box_fx", 14000, 1, "int" ); + registerclientfield( "scriptmover", "foot_print_box_glow", 14000, 1, "int" ); + registerclientfield( "world", "crypt_open_exploder", 14000, 1, "int" ); + registerclientfield( "world", "lantern_fx", 14000, 1, "int" ); + registerclientfield( "allplayers", "oneinchpunch_impact", 14000, 1, "int" ); + registerclientfield( "actor", "oneinchpunch_physics_launchragdoll", 14000, 1, "int" ); +} + +register_burn_overlay() +{ + level.zm_transit_burn_max_duration = 2; + if ( !isDefined( level.vsmgr_prio_overlay_zm_transit_burn ) ) + { + level.vsmgr_prio_overlay_zm_transit_burn = 20; + } + maps/mp/_visionset_mgr::vsmgr_register_info( "overlay", "zm_transit_burn", 14000, level.vsmgr_prio_overlay_zm_transit_burn, 15, 1, ::maps/mp/_visionset_mgr::vsmgr_duration_lerp_thread_per_player, 0 ); +} + +tomb_closest_player_override( v_zombie_origin, a_players_to_check ) +{ + e_player_to_attack = undefined; + while ( !isDefined( e_player_to_attack ) ) + { + e_player_to_attack = tomb_get_closest_player_using_paths( v_zombie_origin, a_players_to_check ); + a_players = maps/mp/zm_tomb_tank::get_players_on_tank( 1 ); + if ( a_players.size > 0 ) + { + e_player_closest_on_tank = undefined; + n_dist_tank_min = 99999999; + _a471 = a_players; + _k471 = getFirstArrayKey( _a471 ); + while ( isDefined( _k471 ) ) + { + e_player = _a471[ _k471 ]; + n_dist_sq = distance2dsquared( self.origin, e_player.origin ); + if ( n_dist_sq < n_dist_tank_min ) + { + n_dist_tank_min = n_dist_sq; + e_player_closest_on_tank = e_player; + } + _k471 = getNextArrayKey( _a471, _k471 ); + } + if ( is_player_valid( e_player_to_attack ) ) + { + n_dist_for_path = distance2dsquared( self.origin, e_player_to_attack.origin ); + if ( n_dist_tank_min < n_dist_for_path ) + { + e_player_to_attack = e_player_closest_on_tank; + } + break; + } + else + { + if ( is_player_valid( e_player_closest_on_tank ) ) + { + e_player_to_attack = e_player_closest_on_tank; + } + } + } + wait 0,5; + } + return e_player_to_attack; +} + +zm_tomb_get_round_enemy_array() +{ + enemies = []; + valid_enemies = []; + enemies = getaispeciesarray( level.zombie_team, "all" ); + i = 0; + while ( i < enemies.size ) + { + if ( isDefined( enemies[ i ].ignore_enemy_count ) && enemies[ i ].ignore_enemy_count || !isDefined( enemies[ i ].script_noteworthy ) && enemies[ i ].script_noteworthy != "capture_zombie" ) + { + i++; + continue; + } + else + { + valid_enemies[ valid_enemies.size ] = enemies[ i ]; + } + i++; + } + return valid_enemies; +} + +tomb_player_damage_callback( e_inflictor, e_attacker, n_damage, n_dflags, str_means_of_death, str_weapon, v_point, v_dir, str_hit_loc, psoffsettime, b_damage_from_underneath, n_model_index, str_part_name ) +{ + if ( isDefined( str_weapon ) ) + { + if ( issubstr( str_weapon, "staff" ) ) + { + return 0; + } + else + { + if ( str_weapon == "t72_turret" ) + { + return 0; + } + else + { + if ( str_weapon == "quadrotorturret_zm" || str_weapon == "quadrotorturret_upgraded_zm" ) + { + return 0; + } + else + { + if ( str_weapon == "zombie_markiv_side_cannon" ) + { + return 0; + } + else + { + if ( str_weapon == "zombie_markiv_turret" ) + { + return 0; + } + else + { + if ( str_weapon == "zombie_markiv_cannon" ) + { + return 0; + } + } + } + } + } + } + } + return n_damage; +} + +tomb_random_perk_weights() +{ + temp_array = []; + if ( randomint( 4 ) == 0 ) + { + arrayinsert( temp_array, "specialty_rof", 0 ); + } + if ( randomint( 4 ) == 0 ) + { + arrayinsert( temp_array, "specialty_deadshot", 0 ); + } + if ( randomint( 4 ) == 0 ) + { + arrayinsert( temp_array, "specialty_additionalprimaryweapon", 0 ); + } + if ( randomint( 4 ) == 0 ) + { + arrayinsert( temp_array, "specialty_flakjacket", 0 ); + } + if ( randomint( 4 ) == 0 ) + { + arrayinsert( temp_array, "specialty_grenadepulldeath", 0 ); + } + temp_array = array_randomize( temp_array ); + level._random_perk_machine_perk_list = array_randomize( level._random_perk_machine_perk_list ); + level._random_perk_machine_perk_list = arraycombine( level._random_perk_machine_perk_list, temp_array, 1, 0 ); + keys = getarraykeys( level._random_perk_machine_perk_list ); + return keys; +} + +level_precache() +{ + precacheshader( "specialty_zomblood_zombies" ); + precachemodel( "c_zom_guard" ); + precachemodel( "p6_zm_tm_orb_fire" ); + precachemodel( "p6_zm_tm_orb_wind" ); + precachemodel( "p6_zm_tm_orb_lightning" ); + precachemodel( "p6_zm_tm_orb_ice" ); + precachemodel( "fx_tomb_vortex_beam_mesh" ); + precachemodel( "fxuse_sky_pillar_new" ); +} + +on_player_connect() +{ + self thread revive_watcher(); + wait_network_frame(); + self thread player_slow_movement_speed_monitor(); + self thread sndmeleewpnsound(); +} + +sndmeleewpnsound() +{ + self endon( "disconnect" ); + level endon( "end_game" ); + while ( 1 ) + { + while ( !self ismeleeing() ) + { + wait 0,05; + } + current_melee_weapon = self get_player_melee_weapon(); + current_weapon = self getcurrentweapon(); + while ( current_weapon == "tomb_shield_zm" ) + { + self playsound( "fly_riotshield_zm_swing" ); + while ( self ismeleeing() ) + { + wait 0,05; + } + } + alias = "zmb_melee_whoosh_"; + if ( isDefined( self.is_player_zombie ) && self.is_player_zombie ) + { + alias = "zmb_melee_whoosh_zmb_"; + } + else if ( current_melee_weapon == "bowie_knife_zm" ) + { + alias = "zmb_bowie_swing_"; + } + else if ( current_melee_weapon == "one_inch_punch_zm" ) + { + alias = "wpn_one_inch_punch_"; + } + else if ( current_melee_weapon == "one_inch_punch_upgraded_zm" ) + { + alias = "wpn_one_inch_punch_"; + } + else if ( current_melee_weapon == "one_inch_punch_fire_zm" ) + { + alias = "wpn_one_inch_punch_fire_"; + } + else if ( current_melee_weapon == "one_inch_punch_air_zm" ) + { + alias = "wpn_one_inch_punch_air_"; + } + else if ( current_melee_weapon == "one_inch_punch_ice_zm" ) + { + alias = "wpn_one_inch_punch_ice_"; + } + else if ( current_melee_weapon == "one_inch_punch_lightning_zm" ) + { + alias = "wpn_one_inch_punch_lightning_"; + } + else + { + if ( sndmeleewpn_isstaff( current_melee_weapon ) ) + { + alias = "zmb_melee_staff_upgraded_"; + } + } + self playsoundtoplayer( alias + "plr", self ); + wait_network_frame(); + if ( maps/mp/zombies/_zm_audio::sndisnetworksafe() ) + { + self playsound( alias + "npc" ); + } + while ( self ismeleeing() ) + { + wait 0,05; + } + wait 0,05; + } +} + +sndmeleewpn_isstaff( weapon ) +{ + switch( weapon ) + { + case "staff_air_melee_zm": + case "staff_fire_melee_zm": + case "staff_lightning_melee_zm": + case "staff_melee_zm": + case "staff_watermelee_zm": + isstaff = 1; + break; + default: + isstaff = 0; + } + return isstaff; +} + +revive_watcher() +{ + self endon( "death_or_disconnect" ); + while ( 1 ) + { + self waittill( "do_revive_ended_normally" ); + if ( self hasperk( "specialty_quickrevive" ) ) + { + self notify( "quick_revived_player" ); + continue; + } + else + { + self notify( "revived_player" ); + } + } +} + +setup_tomb_spawn_groups() +{ + level.use_multiple_spawns = 1; + level.spawner_int = 1; + level waittill( "start_zombie_round_logic" ); + level.zones[ "ug_bottom_zone" ].script_int = 2; + level.zones[ "zone_nml_19" ].script_int = 2; + level.zones[ "zone_chamber_0" ].script_int = 3; + level.zones[ "zone_chamber_1" ].script_int = 3; + level.zones[ "zone_chamber_2" ].script_int = 3; + level.zones[ "zone_chamber_3" ].script_int = 3; + level.zones[ "zone_chamber_4" ].script_int = 3; + level.zones[ "zone_chamber_5" ].script_int = 3; + level.zones[ "zone_chamber_6" ].script_int = 3; + level.zones[ "zone_chamber_7" ].script_int = 3; + level.zones[ "zone_chamber_8" ].script_int = 3; + level.zones[ "zone_ice_stairs" ].script_int = 2; + level.zones[ "zone_bolt_stairs" ].script_int = 2; + level.zones[ "zone_air_stairs" ].script_int = 2; + level.zones[ "zone_fire_stairs" ].script_int = 2; + level.zones[ "zone_bolt_stairs_1" ].script_int = 2; + level.zones[ "zone_air_stairs_1" ].script_int = 2; + level.zones[ "zone_fire_stairs_1" ].script_int = 2; +} + +chamber_capture_zombie_spawn_init() +{ + self endon( "death" ); + self waittill( "completed_emerging_into_playable_area" ); + self setclientfield( "zone_capture_zombie", 1 ); +} + +tomb_round_spawn_failsafe() +{ + self endon( "death" ); + prevorigin = self.origin; + while ( 1 ) + { + if ( isDefined( self.ignore_round_spawn_failsafe ) && self.ignore_round_spawn_failsafe ) + { + return; + } + wait 15; + if ( isDefined( self.is_inert ) && self.is_inert ) + { + continue; + } + while ( isDefined( self.lastchunk_destroy_time ) ) + { + while ( ( getTime() - self.lastchunk_destroy_time ) < 8000 ) + { + continue; + } + } + if ( self.origin[ 2 ] < -3000 ) + { + if ( isDefined( level.put_timed_out_zombies_back_in_queue ) && level.put_timed_out_zombies_back_in_queue && !flag( "dog_round" ) && isDefined( self.isscreecher ) && !self.isscreecher ) + { + level.zombie_total++; + level.zombie_total_subtract++; + } + self dodamage( self.health + 100, ( 0, 0, 0 ) ); + return; + } + else if ( distancesquared( self.origin, prevorigin ) < 576 ) + { + if ( isDefined( level.put_timed_out_zombies_back_in_queue ) && level.put_timed_out_zombies_back_in_queue && !flag( "dog_round" ) ) + { + if ( !self.ignoreall && isDefined( self.nuked ) && !self.nuked && isDefined( self.marked_for_death ) && !self.marked_for_death && isDefined( self.isscreecher ) && !self.isscreecher && isDefined( self.has_legs ) && self.has_legs && isDefined( self.is_brutus ) && !self.is_brutus ) + { + level.zombie_total++; + level.zombie_total_subtract++; + } + } + level.zombies_timeout_playspace++; + self dodamage( self.health + 100, ( 0, 0, 0 ) ); + return; + } + else + { + prevorigin = self.origin; + } + } +} + +givecustomloadout( takeallweapons, alreadyspawned ) +{ + self giveweapon( "knife_zm" ); + self give_start_weapon( 1 ); +} + +precache_team_characters() +{ + precachemodel( "c_zom_player_cdc_fb" ); + precachemodel( "c_zom_hazmat_viewhands" ); + precachemodel( "c_zom_player_cia_fb" ); + precachemodel( "c_zom_suit_viewhands" ); +} + +precache_personality_characters() +{ + character/c_usa_dempsey_dlc4::precache(); + character/c_rus_nikolai_dlc4::precache(); + character/c_ger_richtofen_dlc4::precache(); + character/c_jap_takeo_dlc4::precache(); + precachemodel( "c_zom_richtofen_viewhands" ); + precachemodel( "c_zom_nikolai_viewhands" ); + precachemodel( "c_zom_takeo_viewhands" ); + precachemodel( "c_zom_dempsey_viewhands" ); +} + +give_personality_characters() +{ + if ( isDefined( level.hotjoin_player_setup ) && [[ level.hotjoin_player_setup ]]( "c_zom_arlington_coat_viewhands" ) ) + { + return; + } + self detachall(); + if ( !isDefined( self.characterindex ) ) + { + self.characterindex = assign_lowest_unused_character_index(); + } + self.favorite_wall_weapons_list = []; + self.talks_in_danger = 0; +/# + if ( getDvar( #"40772CF1" ) != "" ) + { + self.characterindex = getDvarInt( #"40772CF1" ); +#/ + } + switch( self.characterindex ) + { + case 0: + self character/c_usa_dempsey_dlc4::main(); + self setviewmodel( "c_zom_dempsey_viewhands" ); + level.vox maps/mp/zombies/_zm_audio::zmbvoxinitspeaker( "player", "vox_plr_", self ); + self set_player_is_female( 0 ); + self.character_name = "Dempsey"; + break; + case 1: + self character/c_rus_nikolai_dlc4::main(); + self setviewmodel( "c_zom_nikolai_viewhands" ); + level.vox maps/mp/zombies/_zm_audio::zmbvoxinitspeaker( "player", "vox_plr_", self ); + self set_player_is_female( 0 ); + self.character_name = "Nikolai"; + break; + case 2: + self character/c_ger_richtofen_dlc4::main(); + self setviewmodel( "c_zom_richtofen_viewhands" ); + level.vox maps/mp/zombies/_zm_audio::zmbvoxinitspeaker( "player", "vox_plr_", self ); + self set_player_is_female( 0 ); + self.character_name = "Richtofen"; + break; + case 3: + self character/c_jap_takeo_dlc4::main(); + self setviewmodel( "c_zom_takeo_viewhands" ); + level.vox maps/mp/zombies/_zm_audio::zmbvoxinitspeaker( "player", "vox_plr_", self ); + self set_player_is_female( 0 ); + self.character_name = "Takeo"; + break; + } + self setmovespeedscale( 1 ); + self setsprintduration( 4 ); + self setsprintcooldown( 0 ); + self thread set_exert_id(); +} + +set_exert_id() +{ + self endon( "disconnect" ); + wait_network_frame(); + wait_network_frame(); + self maps/mp/zombies/_zm_audio::setexertvoice( self.characterindex + 1 ); +} + +assign_lowest_unused_character_index() +{ + charindexarray = []; + charindexarray[ 0 ] = 0; + charindexarray[ 1 ] = 1; + charindexarray[ 2 ] = 2; + charindexarray[ 3 ] = 3; + players = get_players(); + if ( players.size == 1 ) + { + charindexarray = array_randomize( charindexarray ); + if ( charindexarray[ 0 ] == 2 ) + { + level.has_richtofen = 1; + } + return charindexarray[ 0 ]; + } + else + { + n_characters_defined = 0; + _a1010 = players; + _k1010 = getFirstArrayKey( _a1010 ); + while ( isDefined( _k1010 ) ) + { + player = _a1010[ _k1010 ]; + if ( isDefined( player.characterindex ) ) + { + arrayremovevalue( charindexarray, player.characterindex, 0 ); + n_characters_defined++; + } + _k1010 = getNextArrayKey( _a1010, _k1010 ); + } + if ( charindexarray.size > 0 ) + { + if ( n_characters_defined == ( players.size - 1 ) ) + { + if ( isDefined( level.has_richtofen ) && !level.has_richtofen ) + { + level.has_richtofen = 1; + return 2; + } + } + charindexarray = array_randomize( charindexarray ); + if ( charindexarray[ 0 ] == 2 ) + { + level.has_richtofen = 1; + } + return charindexarray[ 0 ]; + } + } + return 0; +} + +give_team_characters() +{ + self detachall(); + self set_player_is_female( 0 ); + if ( !isDefined( self.characterindex ) ) + { + self.characterindex = 1; + if ( self.team == "axis" ) + { + self.characterindex = 0; + } + } + switch( self.characterindex ) + { + case 0: + case 2: + self setmodel( "c_zom_player_cia_fb" ); + self.voice = "american"; + self.skeleton = "base"; + self setviewmodel( "c_zom_suit_viewhands" ); + self.characterindex = 0; + break; + case 1: + case 3: + self setmodel( "c_zom_player_cdc_fb" ); + self.voice = "american"; + self.skeleton = "base"; + self setviewmodel( "c_zom_hazmat_viewhands" ); + self.characterindex = 1; + break; + } + self setmovespeedscale( 1 ); + self setsprintduration( 4 ); + self setsprintcooldown( 0 ); +} + +initcharacterstartindex() +{ + level.characterstartindex = randomint( 4 ); +} + +zm_player_fake_death_cleanup() +{ + if ( isDefined( self._fall_down_anchor ) ) + { + self._fall_down_anchor delete(); + self._fall_down_anchor = undefined; + } +} + +zm_player_fake_death( vdir ) +{ + level notify( "fake_death" ); + self notify( "fake_death" ); + stance = self getstance(); + self.ignoreme = 1; + self enableinvulnerability(); + self takeallweapons(); + if ( isDefined( self.insta_killed ) && self.insta_killed ) + { + self maps/mp/zombies/_zm::player_fake_death(); + self allowprone( 1 ); + self allowcrouch( 0 ); + self allowstand( 0 ); + wait 0,25; + self freezecontrols( 1 ); + } + else + { + self freezecontrols( 1 ); + self thread fall_down( vdir, stance ); + wait 1; + } +} + +fall_down( vdir, stance ) +{ + self endon( "disconnect" ); + level endon( "game_module_ended" ); + self ghost(); + origin = self.origin; + xyspeed = ( 0, 0, 0 ); + angles = self getplayerangles(); + angles = ( angles[ 0 ], angles[ 1 ], angles[ 2 ] + randomfloatrange( -5, 5 ) ); + if ( isDefined( vdir ) && length( vdir ) > 0 ) + { + xyspeedmag = 40 + randomint( 12 ) + randomint( 12 ); + xyspeed = xyspeedmag * vectornormalize( ( vdir[ 0 ], vdir[ 1 ], 0 ) ); + } + linker = spawn( "script_origin", ( 0, 0, 0 ) ); + linker.origin = origin; + linker.angles = angles; + self._fall_down_anchor = linker; + self playerlinkto( linker ); + self playsoundtoplayer( "zmb_player_death_fall", self ); + falling = stance != "prone"; + if ( falling ) + { + origin = playerphysicstrace( origin, origin + xyspeed ); + eye = self get_eye(); + floor_height = ( 10 + origin[ 2 ] ) - eye[ 2 ]; + origin += ( 0, 0, floor_height ); + lerptime = 0,5; + linker moveto( origin, lerptime, lerptime ); + linker rotateto( angles, lerptime, lerptime ); + } + self freezecontrols( 1 ); + if ( falling ) + { + linker waittill( "movedone" ); + } + self giveweapon( "death_throe_zm" ); + self switchtoweapon( "death_throe_zm" ); + if ( falling ) + { + bounce = randomint( 4 ) + 8; + origin = ( origin + ( 0, 0, bounce ) ) - ( xyspeed * 0,1 ); + lerptime = bounce / 50; + linker moveto( origin, lerptime, 0, lerptime ); + linker waittill( "movedone" ); + origin = ( origin + ( 0, 0, bounce * -1 ) ) + ( xyspeed * 0,1 ); + lerptime /= 2; + linker moveto( origin, lerptime, lerptime ); + linker waittill( "movedone" ); + linker moveto( origin, 5, 0 ); + } + wait 15; + linker delete(); +} + +initial_round_wait_func() +{ + flag_wait( "initial_blackscreen_passed" ); +} + +offhand_weapon_overrride() +{ + register_lethal_grenade_for_level( "frag_grenade_zm" ); + level.zombie_lethal_grenade_player_init = "frag_grenade_zm"; + register_lethal_grenade_for_level( "sticky_grenade_zm" ); + register_tactical_grenade_for_level( "cymbal_monkey_zm" ); + register_tactical_grenade_for_level( "emp_grenade_zm" ); + register_tactical_grenade_for_level( "beacon_zm" ); + register_placeable_mine_for_level( "claymore_zm" ); + register_melee_weapon_for_level( "knife_zm" ); + register_melee_weapon_for_level( "staff_air_melee_zm" ); + register_melee_weapon_for_level( "staff_fire_melee_zm" ); + register_melee_weapon_for_level( "staff_lightning_melee_zm" ); + register_melee_weapon_for_level( "staff_water_melee_zm" ); + level.zombie_melee_weapon_player_init = "knife_zm"; + register_equipment_for_level( "tomb_shield_zm" ); + level.zombie_equipment_player_init = undefined; + level.equipment_safe_to_drop = ::equipment_safe_to_drop; +} + +equipment_safe_to_drop( weapon ) +{ + if ( !isDefined( self.origin ) ) + { + return 1; + } + return 1; +} + +offhand_weapon_give_override( str_weapon ) +{ + self endon( "death" ); + if ( is_tactical_grenade( str_weapon ) && isDefined( self get_player_tactical_grenade() ) && !self is_player_tactical_grenade( str_weapon ) ) + { + self setweaponammoclip( self get_player_tactical_grenade(), 0 ); + self takeweapon( self get_player_tactical_grenade() ); + } + return 0; +} + +tomb_weaponobjects_on_player_connect_override() +{ + level.retrievable_knife_init_names = []; + onplayerconnect_callback( ::weaponobjects_on_player_connect_override_internal ); +} + +tomb_player_intersection_tracker_override( e_player ) +{ + if ( isDefined( e_player.b_already_on_tank ) || e_player.b_already_on_tank && isDefined( self.b_already_on_tank ) && self.b_already_on_tank ) + { + return 1; + } + if ( isDefined( e_player.giant_robot_transition ) || e_player.giant_robot_transition && isDefined( self.giant_robot_transition ) && self.giant_robot_transition ) + { + return 1; + } + return 0; +} + +init_tomb_stats() +{ + self maps/mp/zm_tomb_achievement::init_player_achievement_stats(); +} + +custom_add_weapons() +{ + level.laststandpistol = "c96_zm"; + level.default_laststandpistol = "c96_zm"; + level.default_solo_laststandpistol = "c96_upgraded_zm"; + level.start_weapon = "c96_zm"; + add_zombie_weapon( "mg08_zm", "mg08_upgraded_zm", &"ZOMBIE_WEAPON_MG08", 50, "wpck_mg", "", undefined, 1 ); + add_zombie_weapon( "hamr_zm", "hamr_upgraded_zm", &"ZOMBIE_WEAPON_HAMR", 50, "wpck_mg", "", undefined, 1 ); + add_zombie_weapon( "type95_zm", "type95_upgraded_zm", &"ZOMBIE_WEAPON_TYPE95", 50, "wpck_rifle", "", undefined, 1 ); + add_zombie_weapon( "galil_zm", "galil_upgraded_zm", &"ZOMBIE_WEAPON_GALIL", 50, "wpck_rifle", "", undefined, 1 ); + add_zombie_weapon( "fnfal_zm", "fnfal_upgraded_zm", &"ZOMBIE_WEAPON_FNFAL", 50, "wpck_rifle", "", undefined, 1 ); + add_zombie_weapon( "m14_zm", "m14_upgraded_zm", &"ZOMBIE_WEAPON_M14", 500, "wpck_rifle", "", undefined, 1 ); + add_zombie_weapon( "mp44_zm", "mp44_upgraded_zm", &"ZMWEAPON_MP44_WALLBUY", 1400, "wpck_rifle", "", undefined, 1 ); + add_zombie_weapon( "scar_zm", "scar_upgraded_zm", &"ZOMBIE_WEAPON_SCAR", 50, "wpck_rifle", "", undefined, 1 ); + add_zombie_weapon( "870mcs_zm", "870mcs_upgraded_zm", &"ZOMBIE_WEAPON_870MCS", 900, "wpck_shotgun", "", undefined, 1 ); + add_zombie_weapon( "srm1216_zm", "srm1216_upgraded_zm", &"ZOMBIE_WEAPON_SRM1216", 50, "wpck_shotgun", "", undefined, 1 ); + add_zombie_weapon( "ksg_zm", "ksg_upgraded_zm", &"ZOMBIE_WEAPON_KSG", 1100, "wpck_shotgun", "", undefined, 1 ); + add_zombie_weapon( "ak74u_zm", "ak74u_upgraded_zm", &"ZOMBIE_WEAPON_AK74U", 1200, "wpck_smg", "", undefined, 1 ); + add_zombie_weapon( "ak74u_extclip_zm", "ak74u_extclip_upgraded_zm", &"ZOMBIE_WEAPON_AK74U", 1200, "wpck_smg", "", undefined, 1 ); + add_zombie_weapon( "pdw57_zm", "pdw57_upgraded_zm", &"ZOMBIE_WEAPON_PDW57", 1000, "wpck_smg", "", undefined, 1 ); + add_zombie_weapon( "thompson_zm", "thompson_upgraded_zm", &"ZMWEAPON_THOMPSON_WALLBUY", 1500, "wpck_smg", "", 800, 1 ); + add_zombie_weapon( "qcw05_zm", "qcw05_upgraded_zm", &"ZOMBIE_WEAPON_QCW05", 50, "wpck_smg", "", undefined, 1 ); + add_zombie_weapon( "mp40_zm", "mp40_upgraded_zm", &"ZOMBIE_WEAPON_MP40", 1300, "wpck_smg", "", undefined, 1 ); + add_zombie_weapon( "mp40_stalker_zm", "mp40_stalker_upgraded_zm", &"ZOMBIE_WEAPON_MP40", 1300, "wpck_smg", "", undefined, 1 ); + add_zombie_weapon( "evoskorpion_zm", "evoskorpion_upgraded_zm", &"ZOMBIE_WEAPON_EVOSKORPION", 50, "wpck_smg", "", undefined, 1 ); + add_zombie_weapon( "ballista_zm", "ballista_upgraded_zm", &"ZMWEAPON_BALLISTA_WALLBUY", 500, "wpck_snipe", "", undefined, 1 ); + add_zombie_weapon( "dsr50_zm", "dsr50_upgraded_zm", &"ZOMBIE_WEAPON_DR50", 50, "wpck_snipe", "", undefined, 1 ); + add_zombie_weapon( "beretta93r_zm", "beretta93r_upgraded_zm", &"ZOMBIE_WEAPON_BERETTA93r", 1000, "wpck_pistol", "", undefined, 1 ); + add_zombie_weapon( "beretta93r_extclip_zm", "beretta93r_extclip_upgraded_zm", &"ZOMBIE_WEAPON_BERETTA93r", 1000, "wpck_pistol", "", undefined, 1 ); + add_zombie_weapon( "kard_zm", "kard_upgraded_zm", &"ZOMBIE_WEAPON_KARD", 50, "wpck_pistol", "", undefined, 1 ); + add_zombie_weapon( "fiveseven_zm", "fiveseven_upgraded_zm", &"ZOMBIE_WEAPON_FIVESEVEN", 1100, "wpck_pistol", "", undefined, 1 ); + add_zombie_weapon( "python_zm", "python_upgraded_zm", &"ZOMBIE_WEAPON_PYTHON", 50, "wpck_pistol", "", undefined, 1 ); + add_zombie_weapon( "c96_zm", "c96_upgraded_zm", &"ZOMBIE_WEAPON_C96", 50, "wpck_pistol", "", undefined, 1 ); + add_zombie_weapon( "fivesevendw_zm", "fivesevendw_upgraded_zm", &"ZOMBIE_WEAPON_FIVESEVENDW", 50, "wpck_duel", "", undefined, 1 ); + add_zombie_weapon( "m32_zm", "m32_upgraded_zm", &"ZOMBIE_WEAPON_M32", 50, "wpck_crappy", "", undefined, 1 ); + add_zombie_weapon( "beacon_zm", undefined, &"ZOMBIE_WEAPON_BEACON", 2000, "wpck_explo", "", undefined, 1 ); + add_zombie_weapon( "claymore_zm", undefined, &"ZOMBIE_WEAPON_CLAYMORE", 1000, "wpck_explo", "", undefined, 1 ); + add_zombie_weapon( "cymbal_monkey_zm", undefined, &"ZOMBIE_WEAPON_SATCHEL_2000", 2000, "wpck_monkey", "", undefined, 1 ); + add_zombie_weapon( "frag_grenade_zm", undefined, &"ZOMBIE_WEAPON_FRAG_GRENADE", 250, "wpck_explo", "", 250 ); + add_zombie_weapon( "ray_gun_zm", "ray_gun_upgraded_zm", &"ZOMBIE_WEAPON_RAYGUN", 10000, "wpck_ray", "", undefined, 1 ); + if ( isDefined( level.raygun2_included ) && level.raygun2_included ) + { + add_zombie_weapon( "raygun_mark2_zm", "raygun_mark2_upgraded_zm", &"ZOMBIE_WEAPON_RAYGUN_MARK2", 10000, "wpck_raymk2", "", undefined ); + } + add_zombie_weapon( "sticky_grenade_zm", undefined, &"ZOMBIE_WEAPON_STICKY_GRENADE", 250, "wpck_explo", "", 250 ); + add_zombie_weapon( "staff_air_zm", undefined, &"AIR_STAFF", 50, "wpck_rpg", "", undefined, 1 ); + add_zombie_weapon( "staff_air_upgraded_zm", undefined, &"AIR_STAFF_CHARGED", 50, "wpck_rpg", "", undefined, 1 ); + add_zombie_weapon( "staff_fire_zm", undefined, &"FIRE_STAFF", 50, "wpck_rpg", "", undefined, 1 ); + add_zombie_weapon( "staff_fire_upgraded_zm", undefined, &"FIRE_STAFF_CHARGED", 50, "wpck_rpg", "", undefined, 1 ); + add_zombie_weapon( "staff_lightning_zm", undefined, &"LIGHTNING_STAFF", 50, "wpck_rpg", "", undefined, 1 ); + add_zombie_weapon( "staff_lightning_upgraded_zm", undefined, &"LIGHTNING_STAFF_CHARGED", 50, "wpck_rpg", "", undefined, 1 ); + add_zombie_weapon( "staff_water_zm", undefined, &"WATER_STAFF", 50, "wpck_rpg", "", undefined, 1 ); + add_zombie_weapon( "staff_water_zm_cheap", undefined, &"WATER_STAFF", 50, "wpck_rpg", "", undefined, 1 ); + add_zombie_weapon( "staff_water_upgraded_zm", undefined, &"WATER_STAFF_CHARGED", 50, "wpck_rpg", "", undefined, 1 ); + add_zombie_weapon( "staff_revive_zm", undefined, &"ZM_TOMB_WEAP_STAFF_REVIVE", 50, "wpck_rpg", "", undefined, 1 ); + change_weapon_cost( "mp40_zm", 1300 ); + level.weapons_using_ammo_sharing = 1; + add_shared_ammo_weapon( "ak74u_extclip_zm", "ak74u_zm" ); + add_shared_ammo_weapon( "mp40_stalker_zm", "mp40_zm" ); + add_shared_ammo_weapon( "beretta93r_extclip_zm", "beretta93r_zm" ); +} + +include_weapons() +{ + include_weapon( "hamr_zm" ); + include_weapon( "hamr_upgraded_zm", 0 ); + include_weapon( "mg08_zm" ); + include_weapon( "mg08_upgraded_zm", 0 ); + include_weapon( "type95_zm" ); + include_weapon( "type95_upgraded_zm", 0 ); + include_weapon( "galil_zm" ); + include_weapon( "galil_upgraded_zm", 0 ); + include_weapon( "fnfal_zm" ); + include_weapon( "fnfal_upgraded_zm", 0 ); + include_weapon( "m14_zm", 0 ); + include_weapon( "m14_upgraded_zm", 0 ); + include_weapon( "mp44_zm", 0 ); + include_weapon( "mp44_upgraded_zm", 0 ); + include_weapon( "scar_zm" ); + include_weapon( "scar_upgraded_zm", 0 ); + include_weapon( "870mcs_zm", 0 ); + include_weapon( "870mcs_upgraded_zm", 0 ); + include_weapon( "ksg_zm" ); + include_weapon( "ksg_upgraded_zm", 0 ); + include_weapon( "srm1216_zm" ); + include_weapon( "srm1216_upgraded_zm", 0 ); + include_weapon( "ak74u_zm", 0 ); + include_weapon( "ak74u_upgraded_zm", 0 ); + include_weapon( "ak74u_extclip_zm" ); + include_weapon( "ak74u_extclip_upgraded_zm", 0 ); + include_weapon( "pdw57_zm" ); + include_weapon( "pdw57_upgraded_zm", 0 ); + include_weapon( "thompson_zm" ); + include_weapon( "thompson_upgraded_zm", 0 ); + include_weapon( "qcw05_zm" ); + include_weapon( "qcw05_upgraded_zm", 0 ); + include_weapon( "mp40_zm", 0 ); + include_weapon( "mp40_upgraded_zm", 0 ); + include_weapon( "mp40_stalker_zm" ); + include_weapon( "mp40_stalker_upgraded_zm", 0 ); + include_weapon( "evoskorpion_zm" ); + include_weapon( "evoskorpion_upgraded_zm", 0 ); + include_weapon( "ballista_zm", 0 ); + include_weapon( "ballista_upgraded_zm", 0 ); + include_weapon( "dsr50_zm" ); + include_weapon( "dsr50_upgraded_zm", 0 ); + include_weapon( "beretta93r_zm", 0 ); + include_weapon( "beretta93r_upgraded_zm", 0 ); + include_weapon( "beretta93r_extclip_zm" ); + include_weapon( "beretta93r_extclip_upgraded_zm", 0 ); + include_weapon( "kard_zm" ); + include_weapon( "kard_upgraded_zm", 0 ); + include_weapon( "fiveseven_zm", 0 ); + include_weapon( "fiveseven_upgraded_zm", 0 ); + include_weapon( "python_zm" ); + include_weapon( "python_upgraded_zm", 0 ); + include_weapon( "c96_zm", 0 ); + include_weapon( "c96_upgraded_zm", 0 ); + include_weapon( "fivesevendw_zm" ); + include_weapon( "fivesevendw_upgraded_zm", 0 ); + include_weapon( "m32_zm" ); + include_weapon( "m32_upgraded_zm", 0 ); + include_weapon( "beacon_zm", 0 ); + include_weapon( "claymore_zm", 0 ); + include_weapon( "cymbal_monkey_zm" ); + include_weapon( "frag_grenade_zm", 0 ); + include_weapon( "knife_zm", 0 ); + include_weapon( "ray_gun_zm" ); + include_weapon( "ray_gun_upgraded_zm", 0 ); + include_weapon( "sticky_grenade_zm", 0 ); + include_weapon( "tomb_shield_zm", 0 ); + add_limited_weapon( "c96_zm", 0 ); + add_limited_weapon( "ray_gun_zm", 4 ); + add_limited_weapon( "ray_gun_upgraded_zm", 4 ); + include_weapon( "staff_air_zm", 0 ); + include_weapon( "staff_air_upgraded_zm", 0 ); + precacheitem( "staff_air_upgraded2_zm" ); + precacheitem( "staff_air_upgraded3_zm" ); + include_weapon( "staff_fire_zm", 0 ); + include_weapon( "staff_fire_upgraded_zm", 0 ); + precacheitem( "staff_fire_upgraded2_zm" ); + precacheitem( "staff_fire_upgraded3_zm" ); + include_weapon( "staff_lightning_zm", 0 ); + include_weapon( "staff_lightning_upgraded_zm", 0 ); + precacheitem( "staff_lightning_upgraded2_zm" ); + precacheitem( "staff_lightning_upgraded3_zm" ); + include_weapon( "staff_water_zm", 0 ); + include_weapon( "staff_water_zm_cheap", 0 ); + include_weapon( "staff_water_upgraded_zm", 0 ); + precacheitem( "staff_water_upgraded2_zm" ); + precacheitem( "staff_water_upgraded3_zm" ); + include_weapon( "staff_revive_zm", 0 ); + add_limited_weapon( "staff_air_zm", 0 ); + add_limited_weapon( "staff_air_upgraded_zm", 0 ); + add_limited_weapon( "staff_fire_zm", 0 ); + add_limited_weapon( "staff_fire_upgraded_zm", 0 ); + add_limited_weapon( "staff_lightning_zm", 0 ); + add_limited_weapon( "staff_lightning_upgraded_zm", 0 ); + add_limited_weapon( "staff_water_zm", 0 ); + add_limited_weapon( "staff_water_zm_cheap", 0 ); + add_limited_weapon( "staff_water_upgraded_zm", 0 ); + if ( isDefined( level.raygun2_included ) && level.raygun2_included ) + { + include_weapon( "raygun_mark2_zm", 1 ); + include_weapon( "raygun_mark2_upgraded_zm", 0 ); + add_weapon_to_content( "raygun_mark2_zm", "dlc3" ); + add_limited_weapon( "raygun_mark2_zm", 1 ); + add_limited_weapon( "raygun_mark2_upgraded_zm", 1 ); + } +} + +include_powerups() +{ + include_powerup( "nuke" ); + include_powerup( "insta_kill" ); + include_powerup( "double_points" ); + include_powerup( "full_ammo" ); + include_powerup( "fire_sale" ); + include_powerup( "free_perk" ); + include_powerup( "zombie_blood" ); + include_powerup( "bonus_points_player" ); + include_powerup( "bonus_points_team" ); + level.level_specific_init_powerups = ::tomb_powerup_init; + level._zombiemode_powerup_grab = ::tomb_powerup_grab; +/# + setup_powerup_devgui(); +#/ +/# + setup_oneinchpunch_devgui(); +#/ +/# + setup_tablet_devgui(); +#/ +} + +include_perks_in_random_rotation() +{ + include_perk_in_random_rotation( "specialty_armorvest" ); + include_perk_in_random_rotation( "specialty_quickrevive" ); + include_perk_in_random_rotation( "specialty_fastreload" ); + include_perk_in_random_rotation( "specialty_rof" ); + include_perk_in_random_rotation( "specialty_longersprint" ); + include_perk_in_random_rotation( "specialty_deadshot" ); + include_perk_in_random_rotation( "specialty_additionalprimaryweapon" ); + include_perk_in_random_rotation( "specialty_flakjacket" ); + include_perk_in_random_rotation( "specialty_grenadepulldeath" ); + level.custom_random_perk_weights = ::tomb_random_perk_weights; +} + +tomb_powerup_init() +{ + maps/mp/zombies/_zm_powerup_zombie_blood::init( "c_zom_tomb_german_player_fb" ); +} + +tomb_powerup_grab( s_powerup, e_player ) +{ + if ( s_powerup.powerup_name == "zombie_blood" ) + { + level thread maps/mp/zombies/_zm_powerup_zombie_blood::zombie_blood_powerup( s_powerup, e_player ); + } +} + +setup_powerup_devgui() +{ +/# + setdvar( "zombie_blood", "off" ); + adddebugcommand( "devgui_cmd "Zombies:2/Power Ups:2/Now:1/Drop Zombie Blood:1" "zombie_blood on"\n" ); + level thread watch_devgui_zombie_blood(); +#/ +} + +setup_oneinchpunch_devgui() +{ +/# + setdvar( "test_oneinchpunch", "off" ); + adddebugcommand( "devgui_cmd "Zombies:2/Tomb:1/OneInchPunch:2/OneInchPunch:1" "test_oneinchpunch on"\n" ); + setdvar( "test_oneinchpunch_upgraded", "off" ); + adddebugcommand( "devgui_cmd "Zombies:2/Tomb:1/OneInchPunch:2/OneInchPunch_Upgraded:1" "test_oneinchpunch_upgraded on"\n" ); + setdvar( "test_oneinchpunch_air", "off" ); + adddebugcommand( "devgui_cmd "Zombies:2/Tomb:1/OneInchPunch:2/OneInchPunch_Air:1" "test_oneinchpunch_air on"\n" ); + setdvar( "test_oneinchpunch_fire", "off" ); + adddebugcommand( "devgui_cmd "Zombies:2/Tomb:1/OneInchPunch:2/OneInchPunch_Fire:1" "test_oneinchpunch_fire on"\n" ); + setdvar( "test_oneinchpunch_ice", "off" ); + adddebugcommand( "devgui_cmd "Zombies:2/Tomb:1/OneInchPunch:2/OneInchPunch_Ice:1" "test_oneinchpunch_ice on"\n" ); + setdvar( "test_oneinchpunch_lightning", "off" ); + adddebugcommand( "devgui_cmd "Zombies:2/Tomb:1/OneInchPunch:2/OneInchPunch_Lightning:1" "test_oneinchpunch_lightning on"\n" ); + level thread watch_devgui_oneinchpunch(); +#/ +} + +watch_devgui_oneinchpunch() +{ +/# + while ( 1 ) + { + if ( getDvar( "test_oneinchpunch" ) == "on" ) + { + setdvar( "test_oneinchpunch", "off" ); + player = get_players()[ 0 ]; + player thread maps/mp/zombies/_zm_weap_one_inch_punch::one_inch_punch_melee_attack(); + } + else if ( getDvar( "test_oneinchpunch_upgraded" ) == "on" ) + { + setdvar( "test_oneinchpunch_upgraded", "off" ); + player = get_players()[ 0 ]; + player.b_punch_upgraded = 1; + player.str_punch_element = "upgraded"; + player thread maps/mp/zombies/_zm_weap_one_inch_punch::one_inch_punch_melee_attack(); + } + else if ( getDvar( "test_oneinchpunch_air" ) == "on" ) + { + setdvar( "test_oneinchpunch_air", "off" ); + player = get_players()[ 0 ]; + player.b_punch_upgraded = 1; + player.str_punch_element = "air"; + player thread maps/mp/zombies/_zm_weap_one_inch_punch::one_inch_punch_melee_attack(); + } + else if ( getDvar( "test_oneinchpunch_fire" ) == "on" ) + { + setdvar( "test_oneinchpunch_fire", "off" ); + player = get_players()[ 0 ]; + player.b_punch_upgraded = 1; + player.str_punch_element = "fire"; + player thread maps/mp/zombies/_zm_weap_one_inch_punch::one_inch_punch_melee_attack(); + } + else if ( getDvar( "test_oneinchpunch_ice" ) == "on" ) + { + setdvar( "test_oneinchpunch_ice", "off" ); + player = get_players()[ 0 ]; + player.b_punch_upgraded = 1; + player.str_punch_element = "ice"; + player thread maps/mp/zombies/_zm_weap_one_inch_punch::one_inch_punch_melee_attack(); + } + else + { + if ( getDvar( "test_oneinchpunch_lightning" ) == "on" ) + { + setdvar( "test_oneinchpunch_lightning", "off" ); + player = get_players()[ 0 ]; + player.b_punch_upgraded = 1; + player.str_punch_element = "lightning"; + player thread maps/mp/zombies/_zm_weap_one_inch_punch::one_inch_punch_melee_attack(); + } + } + wait 0,1; +#/ + } +} + +setup_tablet_devgui() +{ +/# + setdvar( "test_player_tablet", "3" ); + adddebugcommand( "devgui_cmd "Zombies:2/Tomb:1/Easter Ann:3/Tablet-None:1" "test_player_tablet 0"\n" ); + adddebugcommand( "devgui_cmd "Zombies:2/Tomb:1/Easter Ann:3/Tablet-Clean:1" "test_player_tablet 1"\n" ); + adddebugcommand( "devgui_cmd "Zombies:2/Tomb:1/Easter Ann:3/Tablet-Dirty:1" "test_player_tablet 2"\n" ); + level thread watch_devgui_tablet(); +#/ +} + +watch_devgui_tablet() +{ +/# + while ( 1 ) + { + if ( getDvar( "test_player_tablet" ) != "3" ) + { + player = get_players()[ 0 ]; + n_tablet_state = int( getDvar( "test_player_tablet" ) ); + player setclientfieldtoplayer( "player_tablet_state", n_tablet_state ); + setdvar( "test_player_tablet", "3" ); + } + wait 0,1; +#/ + } +} + +watch_devgui_zombie_blood() +{ +/# + while ( 1 ) + { + if ( getDvar( "zombie_blood" ) == "on" ) + { + setdvar( "zombie_blood", "off" ); + level thread maps/mp/zombies/_zm_devgui::zombie_devgui_give_powerup( "zombie_blood", 1 ); + } + wait 0,1; +#/ + } +} + +watch_devgui_double_points() +{ +/# + while ( 1 ) + { + if ( getDvar( "double_points" ) == "on" ) + { + setdvar( "double_points", "off" ); + level thread maps/mp/zombies/_zm_devgui::zombie_devgui_give_powerup( "double_points", 1 ); + iprintlnbold( "change" ); + } + wait 0,1; +#/ + } +} + +setup_rex_starts() +{ + add_gametype( "zclassic", ::dummy, "zclassic", ::dummy ); + add_gameloc( "tomb", ::dummy, "tomb", ::dummy ); +} + +dummy() +{ +} + +working_zone_init() +{ + flag_init( "always_on" ); + flag_set( "always_on" ); + add_adjacent_zone( "zone_robot_head", "zone_robot_head", "always_on" ); + add_adjacent_zone( "zone_start", "zone_start_a", "always_on" ); + add_adjacent_zone( "zone_start", "zone_start_b", "always_on" ); + add_adjacent_zone( "zone_start_a", "zone_start_b", "always_on" ); + add_adjacent_zone( "zone_start_a", "zone_bunker_1a", "activate_zone_bunker_1" ); + add_adjacent_zone( "zone_bunker_1a", "zone_bunker_1", "activate_zone_bunker_1" ); + add_adjacent_zone( "zone_bunker_1a", "zone_bunker_1", "activate_zone_bunker_3a" ); + add_adjacent_zone( "zone_bunker_1", "zone_bunker_3a", "activate_zone_bunker_3a" ); + add_adjacent_zone( "zone_bunker_3a", "zone_bunker_3b", "activate_zone_bunker_3a" ); + add_adjacent_zone( "zone_bunker_3a", "zone_bunker_3b", "activate_zone_bunker_3b" ); + add_adjacent_zone( "zone_bunker_3b", "zone_bunker_5a", "activate_zone_bunker_3b" ); + add_adjacent_zone( "zone_bunker_5a", "zone_bunker_5b", "activate_zone_bunker_3b" ); + add_adjacent_zone( "zone_start_b", "zone_bunker_2a", "activate_zone_bunker_2" ); + add_adjacent_zone( "zone_bunker_2a", "zone_bunker_2", "activate_zone_bunker_2" ); + add_adjacent_zone( "zone_bunker_2a", "zone_bunker_2", "activate_zone_bunker_4a" ); + add_adjacent_zone( "zone_bunker_2", "zone_bunker_4a", "activate_zone_bunker_4a" ); + add_adjacent_zone( "zone_bunker_4a", "zone_bunker_4b", "activate_zone_bunker_4a" ); + add_adjacent_zone( "zone_bunker_4a", "zone_bunker_4c", "activate_zone_bunker_4a" ); + add_adjacent_zone( "zone_bunker_4b", "zone_bunker_4f", "activate_zone_bunker_4a" ); + add_adjacent_zone( "zone_bunker_4c", "zone_bunker_4d", "activate_zone_bunker_4a" ); + add_adjacent_zone( "zone_bunker_4c", "zone_bunker_4e", "activate_zone_bunker_4a" ); + add_adjacent_zone( "zone_bunker_4e", "zone_bunker_tank_c1", "activate_zone_bunker_4a" ); + add_adjacent_zone( "zone_bunker_4e", "zone_bunker_tank_d", "activate_zone_bunker_4a" ); + add_adjacent_zone( "zone_bunker_tank_c", "zone_bunker_tank_c1", "activate_zone_bunker_4a" ); + add_adjacent_zone( "zone_bunker_tank_d", "zone_bunker_tank_d1", "activate_zone_bunker_4a" ); + add_adjacent_zone( "zone_bunker_4a", "zone_bunker_4b", "activate_zone_bunker_4b" ); + add_adjacent_zone( "zone_bunker_4a", "zone_bunker_4c", "activate_zone_bunker_4b" ); + add_adjacent_zone( "zone_bunker_4b", "zone_bunker_4f", "activate_zone_bunker_4b" ); + add_adjacent_zone( "zone_bunker_4c", "zone_bunker_4d", "activate_zone_bunker_4b" ); + add_adjacent_zone( "zone_bunker_4c", "zone_bunker_4e", "activate_zone_bunker_4b" ); + add_adjacent_zone( "zone_bunker_4b", "zone_bunker_5a", "activate_zone_bunker_4b" ); + add_adjacent_zone( "zone_bunker_5a", "zone_bunker_5b", "activate_zone_bunker_4b" ); + add_adjacent_zone( "zone_bunker_4e", "zone_bunker_tank_c1", "activate_zone_bunker_4b" ); + add_adjacent_zone( "zone_bunker_4e", "zone_bunker_tank_d", "activate_zone_bunker_4b" ); + add_adjacent_zone( "zone_bunker_tank_c", "zone_bunker_tank_c1", "activate_zone_bunker_4b" ); + add_adjacent_zone( "zone_bunker_tank_d", "zone_bunker_tank_d1", "activate_zone_bunker_4b" ); + add_adjacent_zone( "zone_bunker_tank_a", "zone_nml_7", "activate_zone_nml" ); + add_adjacent_zone( "zone_bunker_tank_a", "zone_nml_7a", "activate_zone_nml" ); + add_adjacent_zone( "zone_bunker_tank_a", "zone_bunker_tank_a1", "activate_zone_nml" ); + add_adjacent_zone( "zone_bunker_tank_a1", "zone_bunker_tank_a2", "activate_zone_nml" ); + add_adjacent_zone( "zone_bunker_tank_a1", "zone_bunker_tank_b", "activate_zone_nml" ); + add_adjacent_zone( "zone_bunker_tank_b", "zone_bunker_tank_c", "activate_zone_nml" ); + add_adjacent_zone( "zone_bunker_tank_c", "zone_bunker_tank_c1", "activate_zone_nml" ); + add_adjacent_zone( "zone_bunker_tank_d", "zone_bunker_tank_d1", "activate_zone_nml" ); + add_adjacent_zone( "zone_bunker_tank_d1", "zone_bunker_tank_e", "activate_zone_nml" ); + add_adjacent_zone( "zone_bunker_tank_e", "zone_bunker_tank_e1", "activate_zone_nml" ); + add_adjacent_zone( "zone_bunker_tank_e1", "zone_bunker_tank_e2", "activate_zone_nml" ); + add_adjacent_zone( "zone_bunker_tank_e1", "zone_bunker_tank_f", "activate_zone_nml" ); + add_adjacent_zone( "zone_bunker_tank_f", "zone_nml_1", "activate_zone_nml" ); + add_adjacent_zone( "zone_bunker_5b", "zone_nml_2a", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_0", "zone_nml_1", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_0", "zone_nml_farm", "activate_zone_farm" ); + add_adjacent_zone( "zone_nml_1", "zone_nml_2", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_1", "zone_nml_4", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_1", "zone_nml_20", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_2", "zone_nml_2a", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_2", "zone_nml_2b", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_2", "zone_nml_3", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_3", "zone_nml_4", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_3", "zone_nml_13", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_4", "zone_nml_5", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_4", "zone_nml_13", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_5", "zone_nml_farm", "activate_zone_farm" ); + add_adjacent_zone( "zone_nml_6", "zone_nml_2b", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_6", "zone_nml_7", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_6", "zone_nml_7a", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_6", "zone_nml_8", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_7", "zone_nml_7a", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_7", "zone_nml_9", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_7", "zone_nml_10", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_8", "zone_nml_10a", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_8", "zone_nml_14", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_8", "zone_nml_16", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_9", "zone_nml_7a", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_9", "zone_nml_9a", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_9", "zone_nml_11", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_10", "zone_nml_10a", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_10", "zone_nml_11", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_10a", "zone_nml_12", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_10a", "zone_village_4", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_11", "zone_nml_9a", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_11", "zone_nml_11a", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_11", "zone_nml_12", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_12", "zone_nml_11a", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_12", "zone_nml_12a", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_13", "zone_nml_15", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_14", "zone_nml_15", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_15", "zone_nml_17", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_15a", "zone_nml_14", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_15a", "zone_nml_15", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_16", "zone_nml_2b", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_16", "zone_nml_16a", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_16", "zone_nml_18", "activate_zone_ruins" ); + add_adjacent_zone( "zone_nml_17", "zone_nml_17a", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_17", "zone_nml_18", "activate_zone_ruins" ); + add_adjacent_zone( "zone_nml_18", "zone_nml_19", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_farm", "zone_nml_celllar", "activate_zone_farm" ); + add_adjacent_zone( "zone_nml_farm", "zone_nml_farm_1", "activate_zone_farm" ); + add_adjacent_zone( "zone_nml_19", "ug_bottom_zone", "activate_zone_crypt" ); + add_adjacent_zone( "zone_village_0", "zone_nml_15", "activate_zone_village_0" ); + add_adjacent_zone( "zone_village_0", "zone_village_4b", "activate_zone_village_0" ); + add_adjacent_zone( "zone_village_1", "zone_village_1a", "activate_zone_village_0" ); + add_adjacent_zone( "zone_village_1", "zone_village_2", "activate_zone_village_1" ); + add_adjacent_zone( "zone_village_1", "zone_village_4b", "activate_zone_village_0" ); + add_adjacent_zone( "zone_village_1", "zone_village_5b", "activate_zone_village_0" ); + add_adjacent_zone( "zone_village_2", "zone_village_3", "activate_zone_village_1" ); + add_adjacent_zone( "zone_village_3", "zone_village_3a", "activate_zone_village_1" ); + add_adjacent_zone( "zone_village_3", "zone_ice_stairs", "activate_zone_village_1" ); + add_adjacent_zone( "zone_ice_stairs", "zone_ice_stairs_1", "activate_zone_village_1" ); + add_adjacent_zone( "zone_village_3a", "zone_village_3b", "activate_zone_village_1" ); + add_adjacent_zone( "zone_village_4", "zone_nml_14", "activate_zone_village_0" ); + add_adjacent_zone( "zone_village_4", "zone_village_4a", "activate_zone_village_0" ); + add_adjacent_zone( "zone_village_4", "zone_village_4b", "activate_zone_village_0" ); + add_adjacent_zone( "zone_village_5", "zone_nml_4", "activate_zone_village_0" ); + add_adjacent_zone( "zone_village_5", "zone_village_5a", "activate_zone_village_0" ); + add_adjacent_zone( "zone_village_5a", "zone_village_5b", "activate_zone_village_0" ); + add_adjacent_zone( "zone_village_6", "zone_village_5b", "activate_zone_village_0" ); + add_adjacent_zone( "zone_village_6", "zone_village_6a", "activate_zone_village_0" ); + add_adjacent_zone( "zone_chamber_0", "zone_chamber_1", "activate_zone_chamber" ); + add_adjacent_zone( "zone_chamber_0", "zone_chamber_3", "activate_zone_chamber" ); + add_adjacent_zone( "zone_chamber_0", "zone_chamber_4", "activate_zone_chamber" ); + add_adjacent_zone( "zone_chamber_1", "zone_chamber_2", "activate_zone_chamber" ); + add_adjacent_zone( "zone_chamber_1", "zone_chamber_3", "activate_zone_chamber" ); + add_adjacent_zone( "zone_chamber_1", "zone_chamber_4", "activate_zone_chamber" ); + add_adjacent_zone( "zone_chamber_1", "zone_chamber_5", "activate_zone_chamber" ); + add_adjacent_zone( "zone_chamber_2", "zone_chamber_4", "activate_zone_chamber" ); + add_adjacent_zone( "zone_chamber_2", "zone_chamber_5", "activate_zone_chamber" ); + add_adjacent_zone( "zone_chamber_3", "zone_chamber_4", "activate_zone_chamber" ); + add_adjacent_zone( "zone_chamber_3", "zone_chamber_6", "activate_zone_chamber" ); + add_adjacent_zone( "zone_chamber_3", "zone_chamber_7", "activate_zone_chamber" ); + add_adjacent_zone( "zone_chamber_4", "zone_chamber_5", "activate_zone_chamber" ); + add_adjacent_zone( "zone_chamber_4", "zone_chamber_6", "activate_zone_chamber" ); + add_adjacent_zone( "zone_chamber_4", "zone_chamber_7", "activate_zone_chamber" ); + add_adjacent_zone( "zone_chamber_4", "zone_chamber_8", "activate_zone_chamber" ); + add_adjacent_zone( "zone_chamber_5", "zone_chamber_7", "activate_zone_chamber" ); + add_adjacent_zone( "zone_chamber_5", "zone_chamber_8", "activate_zone_chamber" ); + add_adjacent_zone( "zone_chamber_6", "zone_chamber_7", "activate_zone_chamber" ); + add_adjacent_zone( "zone_chamber_7", "zone_chamber_8", "activate_zone_chamber" ); + add_adjacent_zone( "zone_bunker_1", "zone_bunker_1a", "activate_zone_bunker_1_tank" ); + add_adjacent_zone( "zone_bunker_1a", "zone_fire_stairs", "activate_zone_bunker_1_tank" ); + add_adjacent_zone( "zone_fire_stairs", "zone_fire_stairs_1", "activate_zone_bunker_1_tank" ); + add_adjacent_zone( "zone_bunker_2", "zone_bunker_2a", "activate_zone_bunker_2_tank" ); + add_adjacent_zone( "zone_bunker_4a", "zone_bunker_4b", "activate_zone_bunker_4_tank" ); + add_adjacent_zone( "zone_bunker_4a", "zone_bunker_4c", "activate_zone_bunker_4_tank" ); + add_adjacent_zone( "zone_bunker_4c", "zone_bunker_4d", "activate_zone_bunker_4_tank" ); + add_adjacent_zone( "zone_bunker_4c", "zone_bunker_4e", "activate_zone_bunker_4_tank" ); + add_adjacent_zone( "zone_bunker_4e", "zone_bunker_tank_c1", "activate_zone_bunker_4_tank" ); + add_adjacent_zone( "zone_bunker_4e", "zone_bunker_tank_d", "activate_zone_bunker_4_tank" ); + add_adjacent_zone( "zone_bunker_tank_c", "zone_bunker_tank_c1", "activate_zone_bunker_4_tank" ); + add_adjacent_zone( "zone_bunker_tank_d", "zone_bunker_tank_d1", "activate_zone_bunker_4_tank" ); + add_adjacent_zone( "zone_bunker_tank_b", "zone_bunker_6", "activate_zone_bunker_6_tank" ); + add_adjacent_zone( "zone_bunker_1", "zone_bunker_6", "activate_zone_bunker_6_tank" ); + level thread activate_zone_trig( "trig_zone_bunker_1", "activate_zone_bunker_1_tank" ); + level thread activate_zone_trig( "trig_zone_bunker_2", "activate_zone_bunker_2_tank" ); + level thread activate_zone_trig( "trig_zone_bunker_4", "activate_zone_bunker_4_tank" ); + level thread activate_zone_trig( "trig_zone_bunker_6", "activate_zone_bunker_6_tank", "activate_zone_bunker_1_tank" ); + add_adjacent_zone( "zone_bunker_1a", "zone_fire_stairs", "activate_zone_bunker_1" ); + add_adjacent_zone( "zone_fire_stairs", "zone_fire_stairs_1", "activate_zone_bunker_1" ); + add_adjacent_zone( "zone_bunker_1a", "zone_fire_stairs", "activate_zone_bunker_3a" ); + add_adjacent_zone( "zone_fire_stairs", "zone_fire_stairs_1", "activate_zone_bunker_3a" ); + add_adjacent_zone( "zone_nml_9", "zone_air_stairs", "activate_zone_nml" ); + add_adjacent_zone( "zone_air_stairs", "zone_air_stairs_1", "activate_zone_nml" ); + add_adjacent_zone( "zone_nml_celllar", "zone_bolt_stairs", "activate_zone_farm" ); + add_adjacent_zone( "zone_bolt_stairs", "zone_bolt_stairs_1", "activate_zone_farm" ); +} + +activate_zone_trig( str_name, str_zone1, str_zone2 ) +{ + trig = getent( str_name, "targetname" ); + trig waittill( "trigger" ); + if ( isDefined( str_zone1 ) ) + { + flag_set( str_zone1 ); + } + if ( isDefined( str_zone2 ) ) + { + flag_set( str_zone2 ); + } + trig delete(); +} + +check_tank_platform_zone() +{ + while ( 1 ) + { + level waittill( "newzoneActive", activezone ); + if ( activezone == "zone_bunker_3" ) + { + break; + } + else + { + wait 1; + } + } + flag_set( "activate_zone_nml" ); +} + +tomb_vehicle_damage_override_wrapper( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime, damagefromunderneath, modelindex, partname ) +{ + if ( isDefined( level.a_func_vehicle_damage_override[ self.vehicletype ] ) ) + { + return level.a_func_vehicle_damage_override[ self.vehicletype ]; + } + return idamage; +} + +drop_all_barriers() +{ + zkeys = getarraykeys( level.zones ); + z = 0; + while ( z < level.zones.size ) + { + zbarriers = get_all_zone_zbarriers( zkeys[ z ] ); + if ( !isDefined( zbarriers ) ) + { + z++; + continue; + } + else + { + _a2041 = zbarriers; + _k2041 = getFirstArrayKey( _a2041 ); + while ( isDefined( _k2041 ) ) + { + zbarrier = _a2041[ _k2041 ]; + zbarrier_pieces = zbarrier getnumzbarrierpieces(); + i = 0; + while ( i < zbarrier_pieces ) + { + zbarrier hidezbarrierpiece( i ); + zbarrier setzbarrierpiecestate( i, "open" ); + i++; + } + wait 0,05; + _k2041 = getNextArrayKey( _a2041, _k2041 ); + } + } + z++; + } +} + +get_all_zone_zbarriers( zone_name ) +{ + if ( !isDefined( zone_name ) ) + { + return undefined; + } + zone = level.zones[ zone_name ]; + return zone.zbarriers; +} + +tomb_special_weapon_magicbox_check( weapon ) +{ + if ( isDefined( level.raygun2_included ) && level.raygun2_included ) + { + if ( weapon == "ray_gun_zm" ) + { + if ( self has_weapon_or_upgrade( "raygun_mark2_zm" ) ) + { + return 0; + } + } + if ( weapon == "raygun_mark2_zm" ) + { + if ( self has_weapon_or_upgrade( "ray_gun_zm" ) ) + { + return 0; + } + if ( randomint( 100 ) >= 33 ) + { + return 0; + } + } + } + if ( weapon == "beacon_zm" ) + { + if ( isDefined( self.beacon_ready ) && self.beacon_ready ) + { + return 1; + } + else + { + return 0; + } + } + if ( isDefined( level.zombie_weapons[ weapon ].shared_ammo_weapon ) ) + { + if ( self has_weapon_or_upgrade( level.zombie_weapons[ weapon ].shared_ammo_weapon ) ) + { + return 0; + } + } + return 1; +} + +custom_vending_precaching() +{ + while ( level._custom_perks.size > 0 ) + { + a_keys = getarraykeys( level._custom_perks ); + i = 0; + while ( i < a_keys.size ) + { + if ( isDefined( level._custom_perks[ a_keys[ i ] ].precache_func ) ) + { + level [[ level._custom_perks[ a_keys[ i ] ].precache_func ]](); + } + i++; + } + } + if ( isDefined( level.zombiemode_using_pack_a_punch ) && level.zombiemode_using_pack_a_punch ) + { + precacheitem( "zombie_knuckle_crack" ); + precachemodel( "p6_anim_zm_buildable_pap" ); + precachemodel( "p6_anim_zm_buildable_pap_on" ); + precachestring( &"ZOMBIE_PERK_PACKAPUNCH" ); + precachestring( &"ZOMBIE_PERK_PACKAPUNCH_ATT" ); + level._effect[ "packapunch_fx" ] = loadfx( "maps/zombie/fx_zombie_packapunch" ); + level.machine_assets[ "packapunch" ] = spawnstruct(); + level.machine_assets[ "packapunch" ].weapon = "zombie_knuckle_crack"; + } + if ( isDefined( level.zombiemode_using_additionalprimaryweapon_perk ) && level.zombiemode_using_additionalprimaryweapon_perk ) + { + precacheitem( "zombie_perk_bottle_additionalprimaryweapon" ); + precacheshader( "specialty_additionalprimaryweapon_zombies" ); + precachemodel( "p6_zm_tm_vending_three_gun" ); + precachestring( &"ZOMBIE_PERK_ADDITIONALWEAPONPERK" ); + level._effect[ "additionalprimaryweapon_light" ] = loadfx( "misc/fx_zombie_cola_arsenal_on" ); + level.machine_assets[ "additionalprimaryweapon" ] = spawnstruct(); + level.machine_assets[ "additionalprimaryweapon" ].weapon = "zombie_perk_bottle_additionalprimaryweapon"; + level.machine_assets[ "additionalprimaryweapon" ].off_model = "p6_zm_tm_vending_three_gun"; + level.machine_assets[ "additionalprimaryweapon" ].on_model = "p6_zm_tm_vending_three_gun"; + level.machine_assets[ "additionalprimaryweapon" ].power_on_callback = ::maps/mp/zm_tomb_capture_zones::custom_vending_power_on; + level.machine_assets[ "additionalprimaryweapon" ].power_off_callback = ::maps/mp/zm_tomb_capture_zones::custom_vending_power_off; + } + if ( isDefined( level.zombiemode_using_deadshot_perk ) && level.zombiemode_using_deadshot_perk ) + { + precacheitem( "zombie_perk_bottle_deadshot" ); + precacheshader( "specialty_ads_zombies" ); + precachemodel( "zombie_vending_ads" ); + precachemodel( "zombie_vending_ads_on" ); + precachestring( &"ZOMBIE_PERK_DEADSHOT" ); + level._effect[ "deadshot_light" ] = loadfx( "misc/fx_zombie_cola_dtap_on" ); + level.machine_assets[ "deadshot" ] = spawnstruct(); + level.machine_assets[ "deadshot" ].weapon = "zombie_perk_bottle_deadshot"; + level.machine_assets[ "deadshot" ].off_model = "zombie_vending_ads"; + level.machine_assets[ "deadshot" ].on_model = "zombie_vending_ads_on"; + level.machine_assets[ "deadshot" ].power_on_callback = ::maps/mp/zm_tomb_capture_zones::custom_vending_power_on; + level.machine_assets[ "deadshot" ].power_off_callback = ::maps/mp/zm_tomb_capture_zones::custom_vending_power_off; + } + if ( isDefined( level.zombiemode_using_divetonuke_perk ) && level.zombiemode_using_divetonuke_perk ) + { + precacheitem( "zombie_perk_bottle_nuke" ); + precacheshader( "specialty_divetonuke_zombies" ); + precachemodel( "zombie_vending_nuke" ); + precachemodel( "zombie_vending_nuke_on" ); + precachestring( &"ZOMBIE_PERK_DIVETONUKE" ); + level._effect[ "divetonuke_light" ] = loadfx( "misc/fx_zombie_cola_dtap_on" ); + level.machine_assets[ "divetonuke" ] = spawnstruct(); + level.machine_assets[ "divetonuke" ].weapon = "zombie_perk_bottle_nuke"; + level.machine_assets[ "divetonuke" ].off_model = "zombie_vending_nuke"; + level.machine_assets[ "divetonuke" ].on_model = "zombie_vending_nuke_on"; + level.machine_assets[ "divetonuke" ].power_on_callback = ::maps/mp/zm_tomb_capture_zones::custom_vending_power_on; + level.machine_assets[ "divetonuke" ].power_off_callback = ::maps/mp/zm_tomb_capture_zones::custom_vending_power_off; + } + if ( isDefined( level.zombiemode_using_doubletap_perk ) && level.zombiemode_using_doubletap_perk ) + { + precacheitem( "zombie_perk_bottle_doubletap" ); + precacheshader( "specialty_doubletap_zombies" ); + precachemodel( "zombie_vending_doubletap2" ); + precachemodel( "zombie_vending_doubletap2_on" ); + precachestring( &"ZOMBIE_PERK_DOUBLETAP" ); + level._effect[ "doubletap_light" ] = loadfx( "misc/fx_zombie_cola_dtap_on" ); + level.machine_assets[ "doubletap" ] = spawnstruct(); + level.machine_assets[ "doubletap" ].weapon = "zombie_perk_bottle_doubletap"; + level.machine_assets[ "doubletap" ].off_model = "zombie_vending_doubletap2"; + level.machine_assets[ "doubletap" ].on_model = "zombie_vending_doubletap2_on"; + level.machine_assets[ "doubletap" ].power_on_callback = ::maps/mp/zm_tomb_capture_zones::custom_vending_power_on; + level.machine_assets[ "doubletap" ].power_off_callback = ::maps/mp/zm_tomb_capture_zones::custom_vending_power_off; + } + if ( isDefined( level.zombiemode_using_juggernaut_perk ) && level.zombiemode_using_juggernaut_perk ) + { + precacheitem( "zombie_perk_bottle_jugg" ); + precacheshader( "specialty_juggernaut_zombies" ); + precachemodel( "zombie_vending_jugg" ); + precachemodel( "zombie_vending_jugg_on" ); + precachestring( &"ZOMBIE_PERK_JUGGERNAUT" ); + level._effect[ "jugger_light" ] = loadfx( "misc/fx_zombie_cola_jugg_on" ); + level.machine_assets[ "juggernog" ] = spawnstruct(); + level.machine_assets[ "juggernog" ].weapon = "zombie_perk_bottle_jugg"; + level.machine_assets[ "juggernog" ].off_model = "zombie_vending_jugg"; + level.machine_assets[ "juggernog" ].on_model = "zombie_vending_jugg_on"; + level.machine_assets[ "juggernog" ].power_on_callback = ::maps/mp/zm_tomb_capture_zones::custom_vending_power_on; + level.machine_assets[ "juggernog" ].power_off_callback = ::maps/mp/zm_tomb_capture_zones::custom_vending_power_off; + } + if ( isDefined( level.zombiemode_using_marathon_perk ) && level.zombiemode_using_marathon_perk ) + { + precacheitem( "zombie_perk_bottle_marathon" ); + precacheshader( "specialty_marathon_zombies" ); + precachemodel( "zombie_vending_marathon" ); + precachemodel( "zombie_vending_marathon_on" ); + precachestring( &"ZOMBIE_PERK_MARATHON" ); + level._effect[ "marathon_light" ] = loadfx( "maps/zombie/fx_zmb_cola_staminup_on" ); + level.machine_assets[ "marathon" ] = spawnstruct(); + level.machine_assets[ "marathon" ].weapon = "zombie_perk_bottle_marathon"; + level.machine_assets[ "marathon" ].off_model = "zombie_vending_marathon"; + level.machine_assets[ "marathon" ].on_model = "zombie_vending_marathon_on"; + level.machine_assets[ "marathon" ].power_on_callback = ::maps/mp/zm_tomb_capture_zones::custom_vending_power_on; + level.machine_assets[ "marathon" ].power_off_callback = ::maps/mp/zm_tomb_capture_zones::custom_vending_power_off; + } + if ( isDefined( level.zombiemode_using_revive_perk ) && level.zombiemode_using_revive_perk ) + { + precacheitem( "zombie_perk_bottle_revive" ); + precacheshader( "specialty_quickrevive_zombies" ); + precachemodel( "p6_zm_tm_vending_revive" ); + precachemodel( "p6_zm_tm_vending_revive_on" ); + precachestring( &"ZOMBIE_PERK_QUICKREVIVE" ); + level._effect[ "revive_light" ] = loadfx( "misc/fx_zombie_cola_revive_on" ); + level._effect[ "revive_light_flicker" ] = loadfx( "maps/zombie/fx_zmb_cola_revive_flicker" ); + level.machine_assets[ "revive" ] = spawnstruct(); + level.machine_assets[ "revive" ].weapon = "zombie_perk_bottle_revive"; + level.machine_assets[ "revive" ].off_model = "p6_zm_tm_vending_revive"; + level.machine_assets[ "revive" ].on_model = "p6_zm_tm_vending_revive_on"; + level.machine_assets[ "revive" ].power_on_callback = ::maps/mp/zm_tomb_capture_zones::custom_vending_power_on; + level.machine_assets[ "revive" ].power_off_callback = ::maps/mp/zm_tomb_capture_zones::custom_vending_power_off; + } + if ( isDefined( level.zombiemode_using_sleightofhand_perk ) && level.zombiemode_using_sleightofhand_perk ) + { + precacheitem( "zombie_perk_bottle_sleight" ); + precacheshader( "specialty_fastreload_zombies" ); + precachemodel( "zombie_vending_sleight" ); + precachemodel( "zombie_vending_sleight_on" ); + precachestring( &"ZOMBIE_PERK_FASTRELOAD" ); + level._effect[ "sleight_light" ] = loadfx( "misc/fx_zombie_cola_on" ); + level.machine_assets[ "speedcola" ] = spawnstruct(); + level.machine_assets[ "speedcola" ].weapon = "zombie_perk_bottle_sleight"; + level.machine_assets[ "speedcola" ].off_model = "zombie_vending_sleight"; + level.machine_assets[ "speedcola" ].on_model = "zombie_vending_sleight_on"; + level.machine_assets[ "speedcola" ].power_on_callback = ::maps/mp/zm_tomb_capture_zones::custom_vending_power_on; + level.machine_assets[ "speedcola" ].power_off_callback = ::maps/mp/zm_tomb_capture_zones::custom_vending_power_off; + } + if ( isDefined( level.zombiemode_using_tombstone_perk ) && level.zombiemode_using_tombstone_perk ) + { + precacheitem( "zombie_perk_bottle_tombstone" ); + precacheshader( "specialty_tombstone_zombies" ); + precachemodel( "zombie_vending_tombstone" ); + precachemodel( "zombie_vending_tombstone_on" ); + precachemodel( "ch_tombstone1" ); + precachestring( &"ZOMBIE_PERK_TOMBSTONE" ); + level._effect[ "tombstone_light" ] = loadfx( "misc/fx_zombie_cola_on" ); + level.machine_assets[ "tombstone" ] = spawnstruct(); + level.machine_assets[ "tombstone" ].weapon = "zombie_perk_bottle_tombstone"; + level.machine_assets[ "tombstone" ].off_model = "zombie_vending_tombstone"; + level.machine_assets[ "tombstone" ].on_model = "zombie_vending_tombstone_on"; + level.machine_assets[ "tombstone" ].power_on_callback = ::maps/mp/zm_tomb_capture_zones::custom_vending_power_on; + level.machine_assets[ "tombstone" ].power_off_callback = ::maps/mp/zm_tomb_capture_zones::custom_vending_power_off; + } + if ( isDefined( level.zombiemode_using_chugabud_perk ) && level.zombiemode_using_chugabud_perk ) + { + precacheitem( "zombie_perk_bottle_whoswho" ); + precacheshader( "specialty_quickrevive_zombies" ); + precachemodel( "p6_zm_vending_chugabud" ); + precachemodel( "p6_zm_vending_chugabud_on" ); + precachemodel( "ch_tombstone1" ); + precachestring( &"ZOMBIE_PERK_TOMBSTONE" ); + level._effect[ "tombstone_light" ] = loadfx( "misc/fx_zombie_cola_on" ); + level.machine_assets[ "whoswho" ] = spawnstruct(); + level.machine_assets[ "whoswho" ].weapon = "zombie_perk_bottle_whoswho"; + level.machine_assets[ "whoswho" ].off_model = "p6_zm_vending_chugabud"; + level.machine_assets[ "whoswho" ].on_model = "p6_zm_vending_chugabud_on"; + level.machine_assets[ "whoswho" ].power_on_callback = ::maps/mp/zm_tomb_capture_zones::custom_vending_power_on; + level.machine_assets[ "whoswho" ].power_off_callback = ::maps/mp/zm_tomb_capture_zones::custom_vending_power_off; + } +} + +tomb_actor_damage_override_wrapper( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, shitloc, psoffsettime, boneindex ) +{ + if ( isDefined( self.b_zombie_blood_damage_only ) && self.b_zombie_blood_damage_only ) + { + if ( !isplayer( attacker ) || !attacker.zombie_vars[ "zombie_powerup_zombie_blood_on" ] ) + { + return 0; + } + } + if ( isDefined( self.script_noteworthy ) && self.script_noteworthy == "capture_zombie" && isDefined( attacker ) && isplayer( attacker ) ) + { + if ( damage >= self.health ) + { + if ( ( 100 * level.round_number ) > attacker.n_capture_zombie_points ) + { + attacker maps/mp/zombies/_zm_score::player_add_points( "rebuild_board", 10 ); + attacker.n_capture_zombie_points += 10; + } + } + } + return_val = self maps/mp/zombies/_zm::actor_damage_override_wrapper( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, shitloc, psoffsettime, boneindex ); + if ( damage >= self.health ) + { + if ( weapon == "zombie_markiv_cannon" && meansofdeath == "MOD_CRUSH" ) + { + self thread zombie_gib_guts(); + } + else + { + if ( isDefined( self.b_on_tank ) || self.b_on_tank && isDefined( self.b_climbing_tank ) && self.b_climbing_tank ) + { + self maps/mp/zm_tomb_tank::zombie_on_tank_death_animscript_callback( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, shitloc, psoffsettime, boneindex ); + } + } + } + return return_val; +} + +tomb_zombie_death_event_callback() +{ + if ( isDefined( self ) && isDefined( self.damagelocation ) && isDefined( self.damagemod ) && isDefined( self.damageweapon ) && isDefined( self.attacker ) && isplayer( self.attacker ) ) + { + if ( is_headshot( self.damageweapon, self.damagelocation, self.damagemod ) && maps/mp/zombies/_zm_challenges::challenge_exists( "zc_headshots" ) && !isDefined( self.script_noteworthy ) && isDefined( "capture_zombie" ) && isDefined( self.script_noteworthy ) && isDefined( "capture_zombie" ) && self.script_noteworthy != "capture_zombie" ) + { + self.attacker maps/mp/zombies/_zm_challenges::increment_stat( "zc_headshots" ); + } + } +} + +zombie_init_done() +{ + self.allowpain = 0; + self thread maps/mp/zm_tomb_distance_tracking::escaped_zombies_cleanup_init(); +} + +tomb_validate_enemy_path_length( player ) +{ + max_dist = 1296; + d = distancesquared( self.origin, player.origin ); + if ( d <= max_dist ) + { + return 1; + } + return 0; +} + +show_zombie_count() +{ + self endon( "death_or_disconnect" ); + flag_wait( "start_zombie_round_logic" ); + while ( 1 ) + { + n_round_zombies = get_current_zombie_count(); + str_hint = "Alive: " + n_round_zombies + "\nTo Spawn: " + level.zombie_total; + iprintln( str_hint ); + wait 5; + } +} + +tomb_custom_divetonuke_explode( attacker, origin ) +{ + radius = level.zombie_vars[ "zombie_perk_divetonuke_radius" ]; + min_damage = level.zombie_vars[ "zombie_perk_divetonuke_min_damage" ]; + max_damage = level.zombie_vars[ "zombie_perk_divetonuke_max_damage" ]; + if ( isDefined( level.flopper_network_optimized ) && level.flopper_network_optimized ) + { + attacker thread tomb_custom_divetonuke_explode_network_optimized( origin, radius, max_damage, min_damage, "MOD_GRENADE_SPLASH" ); + } + else + { + radiusdamage( origin, radius, max_damage, min_damage, attacker, "MOD_GRENADE_SPLASH" ); + } + playfx( level._effect[ "divetonuke_groundhit" ], origin ); + attacker playsound( "zmb_phdflop_explo" ); + maps/mp/_visionset_mgr::vsmgr_activate( "visionset", "zm_perk_divetonuke", attacker ); + wait 1; + maps/mp/_visionset_mgr::vsmgr_deactivate( "visionset", "zm_perk_divetonuke", attacker ); +} + +tomb_custom_divetonuke_explode_network_optimized( origin, radius, max_damage, min_damage, damage_mod ) +{ + self endon( "disconnect" ); + a_all_zombies = getaispeciesarray( "axis", "all" ); + a_zombies = get_array_of_closest( origin, a_all_zombies, undefined, undefined, radius ); + network_stall_counter = 0; + while ( isDefined( a_zombies ) ) + { + i = 0; + while ( i < a_zombies.size ) + { + e_zombie = a_zombies[ i ]; + if ( !isDefined( e_zombie ) || !isalive( e_zombie ) ) + { + i++; + continue; + } + else + { + dist = distance( e_zombie.origin, origin ); + damage = min_damage + ( ( max_damage - min_damage ) * ( 1 - ( dist / radius ) ) ); + e_zombie dodamage( damage, e_zombie.origin, self, self, 0, damage_mod ); + network_stall_counter--; + + if ( network_stall_counter <= 0 ) + { + wait_network_frame(); + network_stall_counter = randomintrange( 1, 3 ); + } + } + i++; + } + } +} + +tomb_custom_electric_cherry_laststand() +{ + visionsetlaststand( "zombie_last_stand", 1 ); + if ( isDefined( self ) ) + { + playfx( level._effect[ "electric_cherry_explode" ], self.origin ); + self playsound( "zmb_cherry_explode" ); + self notify( "electric_cherry_start" ); + wait 0,05; + a_zombies = getaispeciesarray( "axis", "all" ); + a_zombies = get_array_of_closest( self.origin, a_zombies, undefined, undefined, 500 ); + i = 0; + while ( i < a_zombies.size ) + { + if ( isalive( self ) ) + { + if ( a_zombies[ i ].health <= 1000 ) + { + a_zombies[ i ] thread maps/mp/zombies/_zm_perk_electric_cherry::electric_cherry_death_fx(); + if ( isDefined( self.cherry_kills ) ) + { + self.cherry_kills++; + } + self maps/mp/zombies/_zm_score::add_to_player_score( 40 ); + } + else + { + a_zombies[ i ] thread maps/mp/zombies/_zm_perk_electric_cherry::electric_cherry_stun(); + a_zombies[ i ] thread maps/mp/zombies/_zm_perk_electric_cherry::electric_cherry_shock_fx(); + } + wait 0,1; + a_zombies[ i ] dodamage( 1000, self.origin, self, self, "none" ); + } + i++; + } + self notify( "electric_cherry_end" ); + } +} + +tomb_custom_electric_cherry_reload_attack() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "stop_electric_cherry_reload_attack" ); + self.wait_on_reload = []; + self.consecutive_electric_cherry_attacks = 0; + while ( 1 ) + { + self waittill( "reload_start" ); + str_current_weapon = self getcurrentweapon(); + while ( isinarray( self.wait_on_reload, str_current_weapon ) ) + { + continue; + } + self.wait_on_reload[ self.wait_on_reload.size ] = str_current_weapon; + self.consecutive_electric_cherry_attacks++; + n_clip_current = self getweaponammoclip( str_current_weapon ); + n_clip_max = weaponclipsize( str_current_weapon ); + n_fraction = n_clip_current / n_clip_max; + perk_radius = linear_map( n_fraction, 1, 0, 32, 128 ); + perk_dmg = linear_map( n_fraction, 1, 0, 1, 1045 ); + self thread maps/mp/zombies/_zm_perk_electric_cherry::check_for_reload_complete( str_current_weapon ); + if ( isDefined( self ) ) + { + switch( self.consecutive_electric_cherry_attacks ) + { + case 0: + case 1: + n_zombie_limit = undefined; + break; + case 2: + n_zombie_limit = 8; + break; + case 3: + n_zombie_limit = 4; + break; + case 4: + n_zombie_limit = 2; + break; + default: + n_zombie_limit = 0; + } + self thread maps/mp/zombies/_zm_perk_electric_cherry::electric_cherry_cooldown_timer( str_current_weapon ); + if ( isDefined( n_zombie_limit ) && n_zombie_limit == 0 ) + { + continue; + } + self thread electric_cherry_reload_fx( n_fraction ); + self notify( "electric_cherry_start" ); + self playsound( "zmb_cherry_explode" ); + a_zombies = getaispeciesarray( "axis", "all" ); + a_zombies = get_array_of_closest( self.origin, a_zombies, undefined, undefined, perk_radius ); + n_zombies_hit = 0; + i = 0; + while ( i < a_zombies.size ) + { + if ( isalive( self ) && isalive( a_zombies[ i ] ) ) + { + if ( isDefined( n_zombie_limit ) ) + { + if ( n_zombies_hit < n_zombie_limit ) + { + n_zombies_hit++; + break; + } + else } + else if ( a_zombies[ i ].health <= perk_dmg ) + { + a_zombies[ i ] thread maps/mp/zombies/_zm_perk_electric_cherry::electric_cherry_death_fx(); + if ( isDefined( self.cherry_kills ) ) + { + self.cherry_kills++; + } + self maps/mp/zombies/_zm_score::add_to_player_score( 40 ); + } + else + { + if ( !isDefined( a_zombies[ i ].is_mechz ) ) + { + a_zombies[ i ] thread maps/mp/zombies/_zm_perk_electric_cherry::electric_cherry_stun(); + } + a_zombies[ i ] thread maps/mp/zombies/_zm_perk_electric_cherry::electric_cherry_shock_fx(); + } + wait 0,1; + if ( isalive( a_zombies[ i ] ) ) + { + a_zombies[ i ] dodamage( perk_dmg, self.origin, self, self, "none" ); + } + } + i++; + } + self notify( "electric_cherry_end" ); + } + } +} + +tomb_custom_player_track_ammo_count() +{ + self notify( "stop_ammo_tracking" ); + self endon( "disconnect" ); + self endon( "stop_ammo_tracking" ); + ammolowcount = 0; + ammooutcount = 0; + while ( 1 ) + { + wait 0,5; + weap = self getcurrentweapon(); + while ( isDefined( weap ) || weap == "none" && !tomb_can_track_ammo_custom( weap ) ) + { + continue; + } + while ( self getammocount( weap ) > 5 || self maps/mp/zombies/_zm_laststand::player_is_in_laststand() ) + { + ammooutcount = 0; + ammolowcount = 0; + } + if ( self getammocount( weap ) > 0 ) + { + if ( ammolowcount < 1 ) + { + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "ammo_low" ); + ammolowcount++; + } + } + else + { + if ( ammooutcount < 1 ) + { + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "ammo_out" ); + ammooutcount++; + } + } + wait 20; + } +} + +tomb_can_track_ammo_custom( weap ) +{ + if ( !isDefined( weap ) ) + { + return 0; + } + switch( weap ) + { + case "alcatraz_shield_zm": + case "chalk_draw_zm": + case "death_throe_zm": + case "equip_dieseldrone_zm": + case "equip_gasmask_zm": + case "falling_hands_tomb_zm": + case "humangun_upgraded_zm": + case "humangun_zm": + case "lower_equip_gasmask_zm": + case "no_hands_zm": + case "none": + case "one_inch_punch_air_zm": + case "one_inch_punch_fire_zm": + case "one_inch_punch_ice_zm": + case "one_inch_punch_lightning_zm": + case "one_inch_punch_upgraded_zm": + case "one_inch_punch_zm": + case "riotshield_zm": + case "screecher_arms_zm": + case "slowgun_upgraded_zm": + case "slowgun_zm": + case "staff_revive_zm": + case "tazer_knuckles_upgraded_zm": + case "tazer_knuckles_zm": + case "time_bomb_detonator_zm": + case "time_bomb_zm": + case "zombie_bowie_flourish": + case "zombie_builder_zm": + case "zombie_fists_zm": + case "zombie_knuckle_crack": + case "zombie_one_inch_punch_flourish": + case "zombie_one_inch_punch_upgrade_flourish": + case "zombie_sickle_flourish": + case "zombie_tazer_flourish": + return 0; + default: + if ( !is_zombie_perk_bottle( weap ) && !is_placeable_mine( weap ) && !is_equipment( weap ) && !issubstr( weap, "knife_ballistic_" ) && getsubstr( weap, 0, 3 ) != "gl_" || weaponfuellife( weap ) > 0 && weap == level.revive_tool ) + { + return 0; + } + } + return 1; +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_achievement.gsc b/zm_tomb_patch/maps/mp/zm_tomb_achievement.gsc new file mode 100644 index 0000000..bae34b5 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_achievement.gsc @@ -0,0 +1,239 @@ +#include maps/mp/gametypes_zm/_globallogic_score; +#include maps/mp/zombies/_zm_utility; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + level thread achievement_tomb_sidequest(); + level thread achievement_all_your_base(); + level thread achievement_playing_with_power(); + level.achievement_sound_func = ::achievement_sound_func; + onplayerconnect_callback( ::onplayerconnect ); +} + +achievement_sound_func( achievement_name_lower ) +{ + self endon( "disconnect" ); + if ( !sessionmodeisonlinegame() ) + { + return; + } + i = 0; + while ( i < ( self getentitynumber() + 1 ) ) + { + wait_network_frame(); + i++; + } + self thread do_player_general_vox( "general", "achievement" ); +} + +init_player_achievement_stats() +{ + if ( !is_gametype_active( "zclassic" ) ) + { + return; + } + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "zm_dlc4_tomb_sidequest", 0 ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "zm_dlc4_not_a_gold_digger", 0 ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "zm_dlc4_all_your_base", 0 ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "zm_dlc4_kung_fu_grip", 0 ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "zm_dlc4_playing_with_power", 0 ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "zm_dlc4_im_on_a_tank", 0 ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "zm_dlc4_saving_the_day_all_day", 0 ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "zm_dlc4_master_of_disguise", 0 ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "zm_dlc4_overachiever", 0 ); + self maps/mp/gametypes_zm/_globallogic_score::initpersstat( "zm_dlc4_master_wizard", 0 ); +} + +onplayerconnect() +{ + self thread achievement_not_a_gold_digger(); + self thread achievement_kung_fu_grip(); + self thread achievement_im_on_a_tank(); + self thread achievement_saving_the_day_all_day(); + self thread achievement_master_of_disguise(); + self thread achievement_master_wizard(); + self thread achievement_overachiever(); +} + +achievement_tomb_sidequest() +{ + level endon( "end_game" ); + level waittill( "tomb_sidequest_complete" ); +/# +#/ + level giveachievement_wrapper( "ZM_DLC4_TOMB_SIDEQUEST", 1 ); +} + +achievement_all_your_base() +{ + level endon( "end_game" ); + level waittill( "all_zones_captured_none_lost" ); +/# +#/ + level giveachievement_wrapper( "ZM_DLC4_ALL_YOUR_BASE", 1 ); +} + +achievement_playing_with_power() +{ + level endon( "end_game" ); + flag_wait( "ee_all_staffs_crafted" ); +/# +#/ + level giveachievement_wrapper( "ZM_DLC4_PLAYING_WITH_POWER", 1 ); +} + +achievement_overachiever() +{ + level endon( "end_game" ); + self endon( "disconnect" ); + self waittill( "all_challenges_complete" ); +/# +#/ + self giveachievement_wrapper( "ZM_DLC4_OVERACHIEVER" ); +} + +achievement_not_a_gold_digger() +{ + level endon( "end_game" ); + self endon( "disconnect" ); + self waittill( "dig_up_weapon_shared" ); +/# +#/ + self giveachievement_wrapper( "ZM_DLC4_NOT_A_GOLD_DIGGER" ); +} + +achievement_kung_fu_grip() +{ + level endon( "end_game" ); + self endon( "disconnect" ); + self waittill_multiple( "mechz_grab_released_self", "mechz_grab_released_friendly" ); +/# +#/ + self giveachievement_wrapper( "ZM_DLC4_KUNG_FU_GRIP" ); +} + +achievement_im_on_a_tank() +{ + level endon( "end_game" ); + self endon( "disconnect" ); + self waittill( "rode_tank_around_map" ); +/# +#/ + self giveachievement_wrapper( "ZM_DLC4_IM_ON_A_TANK" ); +} + +achievement_saving_the_day_all_day() +{ + level endon( "end_game" ); + self endon( "disconnect" ); + self waittill_multiple( "revived_player", "quick_revived_player", "revived_player_with_quadrotor", "revived_player_with_upgraded_staff" ); +/# +#/ + self giveachievement_wrapper( "ZM_DLC4_SAVING_THE_DAY_ALL_DAY" ); +} + +_zombie_blood_achievement_think() +{ + self endon( "zombie_blood_over" ); + b_finished_achievement = 0; + if ( !isDefined( self.zombie_blood_revives ) ) + { + self.zombie_blood_revives = 0; + } + if ( !isDefined( self.zombie_blood_generators_started ) ) + { + self.zombie_blood_generators_started = 0; + } + b_did_capture = 0; + n_revives = 0; + while ( 1 ) + { + str_action = waittill_any_return( "completed_zone_capture", "do_revive_ended_normally", "revived_player_with_quadrotor", "revived_player_with_upgraded_staff" ); + if ( issubstr( str_action, "revive" ) ) + { + self.zombie_blood_revives++; + } + else + { + if ( str_action == "completed_zone_capture" ) + { + self.zombie_blood_generators_started++; + } + } + if ( self.zombie_blood_generators_started > 0 && self.zombie_blood_revives >= 3 ) + { + return 1; + } + } +} + +achievement_master_of_disguise() +{ + level endon( "end_game" ); + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "zombie_blood" ); + b_finished_achievement = self _zombie_blood_achievement_think(); + if ( isDefined( b_finished_achievement ) && b_finished_achievement ) + { + break; + } + else + { + } + } +/# +#/ + self giveachievement_wrapper( "ZM_DLC4_MASTER_OF_DISGUISE" ); +} + +watch_equipped_weapons_for_upgraded_staffs() +{ + self endon( "disconnect" ); + self endon( "stop_weapon_switch_watcher_thread" ); + while ( 1 ) + { + self waittill( "weapon_change", str_weapon ); + while ( self.sessionstate != "playing" ) + { + continue; + } + if ( str_weapon == "staff_water_upgraded_zm" ) + { + self notify( "upgraded_water_staff_equipped" ); + continue; + } + else if ( str_weapon == "staff_lightning_upgraded_zm" ) + { + self notify( "upgraded_lightning_staff_equipped" ); + continue; + } + else if ( str_weapon == "staff_fire_upgraded_zm" ) + { + self notify( "upgraded_fire_staff_equipped" ); + continue; + } + else + { + if ( str_weapon == "staff_air_upgraded_zm" ) + { + self notify( "upgraded_air_staff_equipped" ); + } + } + } +} + +achievement_master_wizard() +{ + level endon( "end_game" ); + self endon( "disconnect" ); + self thread watch_equipped_weapons_for_upgraded_staffs(); + self waittill_multiple( "upgraded_air_staff_equipped", "upgraded_lightning_staff_equipped", "upgraded_water_staff_equipped", "upgraded_fire_staff_equipped" ); + self notify( "stop_weapon_switch_watcher_thread" ); +/# +#/ + self giveachievement_wrapper( "ZM_DLC4_MASTER_WIZARD" ); +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_amb.gsc b/zm_tomb_patch/maps/mp/zm_tomb_amb.gsc new file mode 100644 index 0000000..378a80a --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_amb.gsc @@ -0,0 +1,713 @@ +#include maps/mp/zombies/_zm_zonemgr; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zombies/_zm_sidequests; +#include maps/mp/_ambientpackage; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +main() +{ + level thread sndsetupendgamemusicstates(); + if ( is_classic() ) + { + thread sndmusicegg(); + thread snd115egg(); + thread sndstingersetup(); + onplayerconnect_callback( ::sndtrackers ); + level thread sndmaelstrom(); + } +} + +sndsetupendgamemusicstates() +{ + flag_wait( "start_zombie_round_logic" ); + level thread maps/mp/zombies/_zm_audio::setupmusicstate( "game_over_ee", "mus_zombie_game_over_ee", 1, 0, undefined, "SILENCE" ); +} + +sndtrackers() +{ +} + +sndstingersetup() +{ + level.sndmusicstingerevent = ::sndplaystinger; + level.sndstinger = spawnstruct(); + level.sndstinger.ent = spawn( "script_origin", ( 0, 0, 0 ) ); + level.sndstinger.queue = 0; + level.sndstinger.isplaying = 0; + level.sndstinger.states = []; + level.sndroundwait = 1; + flag_wait( "start_zombie_round_logic" ); + level sndstingersetupstates(); + level thread sndstingerroundwait(); + level thread sndboardmonitor(); + level thread locationstingerwait(); + level thread snddoormusictrigs(); +} + +sndstingersetupstates() +{ + createstingerstate( "door_open", "mus_event_group_03", 2,5, "ignore" ); + createstingerstate( "boards_gone", "mus_event_group_02", 0,5, "ignore" ); + createstingerstate( "zone_nml_18", "mus_event_location_hilltop", 0,75, "queue" ); + createstingerstate( "zone_village_2", "mus_event_location_church", 0,75, "queue" ); + createstingerstate( "ug_bottom_zone", "mus_event_location_crypt", 0,75, "queue" ); + createstingerstate( "zone_robot_head", "mus_event_location_robot", 0,75, "queue" ); + createstingerstate( "zone_air_stairs", "mus_event_cave_air", 0,75, "queue" ); + createstingerstate( "zone_fire_stairs", "mus_event_cave_fire", 0,75, "queue" ); + createstingerstate( "zone_bolt_stairs", "mus_event_cave_bolt", 0,75, "queue" ); + createstingerstate( "zone_ice_stairs", "mus_event_cave_ice", 0,75, "queue" ); + createstingerstate( "poweron", "mus_event_poweron", 0, "reject" ); + createstingerstate( "tank_ride", "mus_event_tank_ride", 0, "queue" ); + createstingerstate( "generator_1", "mus_event_generator_1", 1, "reject" ); + createstingerstate( "generator_2", "mus_event_generator_2", 1, "reject" ); + createstingerstate( "generator_3", "mus_event_generator_3", 1, "reject" ); + createstingerstate( "generator_4", "mus_event_generator_4", 1, "reject" ); + createstingerstate( "generator_5", "mus_event_generator_5", 1, "reject" ); + createstingerstate( "generator_6", "mus_event_generator_6", 1, "reject" ); + createstingerstate( "staff_fire", "mus_event_staff_fire", 0,1, "reject" ); + createstingerstate( "staff_ice", "mus_event_staff_ice", 0,1, "reject" ); + createstingerstate( "staff_lightning", "mus_event_staff_lightning", 0,1, "reject" ); + createstingerstate( "staff_wind", "mus_event_staff_wind", 0,1, "reject" ); + createstingerstate( "staff_fire_upgraded", "mus_event_staff_fire_upgraded", 0,1, "reject" ); + createstingerstate( "staff_ice_upgraded", "mus_event_staff_ice_upgraded", 0,1, "reject" ); + createstingerstate( "staff_lightning_upgraded", "mus_event_staff_lightning_upgraded", 0,1, "reject" ); + createstingerstate( "staff_wind_upgraded", "mus_event_staff_wind_upgraded", 0,1, "reject" ); + createstingerstate( "staff_all_upgraded", "mus_event_staff_all_upgraded", 0,1, "reject" ); + createstingerstate( "side_sting_1", "mus_side_stinger_1", 0,1, "reject" ); + createstingerstate( "side_sting_2", "mus_side_stinger_2", 0,1, "reject" ); + createstingerstate( "side_sting_3", "mus_side_stinger_3", 0,1, "reject" ); + createstingerstate( "side_sting_4", "mus_side_stinger_4", 0,1, "reject" ); + createstingerstate( "side_sting_5", "mus_side_stinger_5", 0,1, "reject" ); + createstingerstate( "side_sting_6", "mus_side_stinger_6", 0,1, "reject" ); +} + +createstingerstate( state, alias, prewait, interrupt ) +{ + s = level.sndstinger; + if ( !isDefined( s.states[ state ] ) ) + { + s.states[ state ] = spawnstruct(); + s.states[ state ].alias = alias; + s.states[ state ].prewait = prewait; + s.states[ state ].interrupt = interrupt; + } +} + +sndboardmonitor() +{ + while ( 1 ) + { + level waittill( "last_board_torn", barrier_origin ); + players = getplayers(); + _a122 = players; + _k122 = getFirstArrayKey( _a122 ); + while ( isDefined( _k122 ) ) + { + player = _a122[ _k122 ]; + if ( distancesquared( player.origin, barrier_origin ) <= 22500 ) + { + level thread maps/mp/zombies/_zm_audio::sndmusicstingerevent( "boards_gone" ); + break; + } + else + { + _k122 = getNextArrayKey( _a122, _k122 ); + } + } + } +} + +locationstingerwait( zone_name, type ) +{ + array = sndlocationsarray(); + sndnorepeats = 3; + numcut = 0; + level.sndlastzone = undefined; + level.sndlocationplayed = 0; + level thread sndlocationbetweenroundswait(); + for ( ;; ) + { + while ( 1 ) + { + level waittill( "newzoneActive", activezone ); + wait 0,1; + while ( !sndlocationshouldplay( array, activezone ) ) + { + continue; + } + if ( is_true( level.sndroundwait ) ) + { + } + } + else while ( is_true( level.sndstinger.isplaying ) ) + { + level thread sndlocationqueue( activezone ); + } + level thread maps/mp/zombies/_zm_audio::sndmusicstingerevent( activezone ); + level.sndlocationplayed = 1; + array = sndcurrentlocationarray( array, activezone, numcut, sndnorepeats ); + level.sndlastzone = activezone; + if ( numcut >= sndnorepeats ) + { + numcut = 0; + } + else + { + numcut++; + } + level waittill( "between_round_over" ); + while ( is_true( level.sndroundwait ) ) + { + wait 0,1; + } + level.sndlocationplayed = 0; + } +} + +sndlocationsarray() +{ + array = []; + array[ 0 ] = "zone_nml_18"; + array[ 1 ] = "zone_village_2"; + array[ 2 ] = "ug_bottom_zone"; + array[ 3 ] = "zone_air_stairs"; + array[ 4 ] = "zone_fire_stairs"; + array[ 5 ] = "zone_bolt_stairs"; + array[ 6 ] = "zone_ice_stairs"; + return array; +} + +sndlocationshouldplay( array, activezone ) +{ + shouldplay = 0; + if ( activezone == "zone_start_lower" && !flag( "fountain_transport_active" ) ) + { + return shouldplay; + } + if ( is_true( level.music_override ) ) + { + return shouldplay; + } + _a206 = array; + _k206 = getFirstArrayKey( _a206 ); + while ( isDefined( _k206 ) ) + { + place = _a206[ _k206 ]; + if ( place == activezone ) + { + shouldplay = 1; + } + _k206 = getNextArrayKey( _a206, _k206 ); + } + if ( shouldplay == 0 ) + { + return shouldplay; + } + playersinlocal = 0; + players = getplayers(); + _a217 = players; + _k217 = getFirstArrayKey( _a217 ); + while ( isDefined( _k217 ) ) + { + player = _a217[ _k217 ]; + if ( player maps/mp/zombies/_zm_zonemgr::is_player_in_zone( activezone ) ) + { + if ( !is_true( player.afterlife ) ) + { + playersinlocal++; + } + } + _k217 = getNextArrayKey( _a217, _k217 ); + } + if ( playersinlocal >= 1 ) + { + shouldplay = 1; + } + else + { + shouldplay = 0; + } + return shouldplay; +} + +sndcurrentlocationarray( current_array, activezone, numcut, max_num_removed ) +{ + if ( numcut >= max_num_removed ) + { + current_array = sndlocationsarray(); + } + _a240 = current_array; + _k240 = getFirstArrayKey( _a240 ); + while ( isDefined( _k240 ) ) + { + place = _a240[ _k240 ]; + if ( place == activezone ) + { + arrayremovevalue( current_array, place ); + break; + } + else + { + _k240 = getNextArrayKey( _a240, _k240 ); + } + } + return current_array; +} + +sndlocationbetweenrounds() +{ + level endon( "newzoneActive" ); + activezones = maps/mp/zombies/_zm_zonemgr::get_active_zone_names(); + _a257 = activezones; + _k257 = getFirstArrayKey( _a257 ); + while ( isDefined( _k257 ) ) + { + zone = _a257[ _k257 ]; + if ( isDefined( level.sndlastzone ) && zone == level.sndlastzone ) + { + } + else + { + players = getplayers(); + _a263 = players; + _k263 = getFirstArrayKey( _a263 ); + while ( isDefined( _k263 ) ) + { + player = _a263[ _k263 ]; + if ( is_true( player.afterlife ) ) + { + } + else + { + if ( player maps/mp/zombies/_zm_zonemgr::is_player_in_zone( zone ) ) + { + wait 0,1; + level notify( "newzoneActive" ); + return; + } + } + _k263 = getNextArrayKey( _a263, _k263 ); + } + } + _k257 = getNextArrayKey( _a257, _k257 ); + } +} + +sndlocationbetweenroundswait() +{ + while ( is_true( level.sndroundwait ) ) + { + wait 0,1; + } + while ( 1 ) + { + level thread sndlocationbetweenrounds(); + level waittill( "between_round_over" ); + while ( is_true( level.sndroundwait ) ) + { + wait 0,1; + } + } +} + +sndlocationqueue( zone ) +{ + level endon( "newzoneActive" ); + while ( is_true( level.sndstinger.isplaying ) ) + { + wait 0,5; + } + level notify( "newzoneActive" ); +} + +sndplaystinger( state, player ) +{ + s = level.sndstinger; + if ( !isDefined( s.states[ state ] ) ) + { + return; + } + interrupt = s.states[ state ].interrupt == "ignore"; + if ( !is_true( s.isplaying ) || is_true( interrupt ) ) + { + if ( interrupt ) + { + wait s.states[ state ].prewait; + playstinger( state, player, 1 ); + } + else if ( !level.sndroundwait ) + { + s.isplaying = 1; + wait s.states[ state ].prewait; + playstinger( state, player, 0 ); + level notify( "sndStingerDone" ); + s.isplaying = 0; + } + else + { + if ( s.states[ state ].interrupt == "queue" ) + { + level thread sndqueuestinger( state, player ); + } + } + return; + } + if ( s.states[ state ].interrupt == "queue" ) + { + level thread sndqueuestinger( state, player ); + } +} + +playstinger( state, player, ignore ) +{ + s = level.sndstinger; + if ( !isDefined( s.states[ state ] ) ) + { + return; + } + if ( is_true( level.music_override ) ) + { + return; + } + if ( is_true( ignore ) ) + { + if ( isDefined( player ) ) + { + player playsoundtoplayer( s.states[ state ].alias, player ); + } + else + { + s.ent playsound( s.states[ state ].alias ); + s.ent thread playstingerstop(); + } + } + else if ( isDefined( player ) ) + { + player playsoundtoplayer( s.states[ state ].alias, player ); + wait 8; + } + else + { + s.ent playsoundwithnotify( s.states[ state ].alias, "sndStingerDone" ); + s.ent thread playstingerstop(); + s.ent waittill( "sndStingerDone" ); + } +} + +sndqueuestinger( state, player ) +{ + s = level.sndstinger; + count = 0; + if ( is_true( s.queue ) ) + { + return; + } + else + { + s.queue = 1; + while ( 1 ) + { + if ( is_true( level.sndroundwait ) || is_true( s.isplaying ) ) + { + wait 0,5; + count++; + if ( count >= 120 ) + { + return; + } + continue; + } + else + { + } + } + level thread sndplaystinger( state, player ); + s.queue = 0; + } +} + +sndstingerroundwait() +{ + wait 25; + level.sndroundwait = 0; + while ( 1 ) + { + level waittill( "end_of_round" ); + level thread sndstingerroundwait_start(); + } +} + +sndstingerroundwait_start() +{ + level.sndroundwait = 1; + wait 0,05; + level thread sndstingerroundwait_end(); +} + +sndstingerroundwait_end() +{ + level endon( "end_of_round" ); + level waittill( "between_round_over" ); + wait 28; + level.sndroundwait = 0; +} + +playstingerstop() +{ + self endon( "sndStingerDone" ); + level endon( "sndStingerDone" ); + level waittill_any( "end_of_round", "sndStingerForceStop" ); + wait 2; + self stopsounds(); +} + +sndmusicegg() +{ + origins = []; + origins[ 0 ] = ( 2682,23, 4456,15, -302,352 ); + origins[ 1 ] = ( 721,043, -87,7068, 285,986 ); + origins[ 2 ] = ( -674,048, 2536,67, -112,483 ); + level.meteor_counter = 0; + level.music_override = 0; + i = 0; + while ( i < origins.size ) + { + level thread sndmusicegg_wait( origins[ i ] ); + i++; + } +} + +sndmusicegg_wait( bottle_origin ) +{ + temp_ent = spawn( "script_origin", bottle_origin ); + temp_ent playloopsound( "zmb_meteor_loop" ); + temp_ent thread maps/mp/zombies/_zm_sidequests::fake_use( "main_music_egg_hit", ::sndmusicegg_override ); + temp_ent waittill( "main_music_egg_hit", player ); + temp_ent stoploopsound( 1 ); + player playsound( "zmb_meteor_activate" ); + level.meteor_counter += 1; + if ( level.meteor_counter == 3 ) + { + level thread sndmuseggplay( temp_ent, "mus_zmb_secret_song", 310 ); + } + else + { + wait 1,5; + temp_ent delete(); + } +} + +sndmusicegg_override() +{ + if ( is_true( level.music_override ) ) + { + return 0; + } + return 1; +} + +sndmuseggplay( ent, alias, time ) +{ + level.music_override = 1; + wait 1; + ent playsound( alias ); + level setclientfield( "mus_zmb_egg_snapshot_loop", 1 ); + level notify( "sndStingerForceStop" ); + level thread sndeggmusicwait( time ); + level waittill_either( "end_game", "sndSongDone" ); + ent stopsounds(); + level setclientfield( "mus_zmb_egg_snapshot_loop", 0 ); + wait 0,05; + ent delete(); + level.music_override = 0; +} + +sndeggmusicwait( time ) +{ + level endon( "end_game" ); + wait time; + level notify( "sndSongDone" ); +} + +sndplaystingerwithoverride( alias, length ) +{ + shouldplay = sndwait(); + if ( !shouldplay ) + { + return; + } + level.music_override = 1; + level setclientfield( "mus_zmb_egg_snapshot_loop", 1 ); + level notify( "sndStingerForceStop" ); + ent = spawn( "script_origin", ( 0, 0, 0 ) ); + ent playsound( alias ); + wait length; + level setclientfield( "mus_zmb_egg_snapshot_loop", 0 ); + level.music_override = 0; + wait 0,05; + ent delete(); +} + +sndwait() +{ + counter = 0; + while ( is_true( level.music_override ) ) + { + wait 1; + counter++; + if ( counter >= 60 ) + { + return 0; + } + } + return 1; +} + +snddoormusictrigs() +{ + trigs = getentarray( "sndMusicDoor", "script_noteworthy" ); + _a557 = trigs; + _k557 = getFirstArrayKey( _a557 ); + while ( isDefined( _k557 ) ) + { + trig = _a557[ _k557 ]; + trig thread snddoormusic(); + _k557 = getNextArrayKey( _a557, _k557 ); + } +} + +snddoormusic() +{ + self endon( "sndDoorMusic_Triggered" ); + for ( ;; ) + { + while ( 1 ) + { + self waittill( "trigger" ); + if ( is_true( level.music_override ) ) + { + wait 0,1; + } + } + else } + if ( isDefined( self.target ) ) + { + ent = getent( self.target, "targetname" ); + ent notify( "sndDoorMusic_Triggered" ); + } + level thread sndplaystingerwithoverride( self.script_sound, self.script_int ); +} + +sndmaelstrom() +{ + trig = getent( "sndMaelstrom", "targetname" ); + if ( !isDefined( trig ) ) + { + return; + } + while ( 1 ) + { + trig waittill( "trigger", who ); + if ( isplayer( who ) && !is_true( who.sndmaelstrom ) ) + { + who.sndmaelstrom = 1; + level setclientfield( "sndMaelstromPlr" + who getentitynumber(), 1 ); + } + who thread sndmaelstrom_timeout(); + wait 0,1; + } +} + +sndmaelstrom_timeout() +{ + self notify( "sndMaelstrom_Timeout" ); + self endon( "sndMaelstrom_Timeout" ); + wait 2; + self.sndmaelstrom = 0; + level setclientfield( "sndMaelstromPlr" + self getentitynumber(), 0 ); +} + +snd115egg() +{ + level.snd115count = 0; + oneorigin = []; + oneorigin[ 0 ] = ( 2168, 4617, -289 ); + oneorigin[ 1 ] = ( 2170, 4953, -289 ); + fiveorigin = []; + fiveorigin[ 0 ] = ( -2459, 176, 243 ); + fiveorigin[ 1 ] = ( -2792, 175, 243 ); + _a625 = oneorigin; + _k625 = getFirstArrayKey( _a625 ); + while ( isDefined( _k625 ) ) + { + origin = _a625[ _k625 ]; + level thread snd115egg_wait( origin, 0 ); + _k625 = getNextArrayKey( _a625, _k625 ); + } + _a628 = fiveorigin; + _k628 = getFirstArrayKey( _a628 ); + while ( isDefined( _k628 ) ) + { + origin = _a628[ _k628 ]; + level thread snd115egg_wait( origin, 1 ); + _k628 = getNextArrayKey( _a628, _k628 ); + } +} + +snd115egg_wait( origin, shouldwait ) +{ + level endon( "sndEnd115" ); + temp_ent = spawn( "script_origin", origin ); + temp_ent thread snddelete115ent(); + if ( shouldwait ) + { + temp_ent thread maps/mp/zombies/_zm_sidequests::fake_use( "main_music_egg_hit", ::snd115egg_5_override ); + } + else + { + temp_ent thread maps/mp/zombies/_zm_sidequests::fake_use( "main_music_egg_hit", ::snd115egg_1_override ); + } + temp_ent waittill( "main_music_egg_hit", player ); + player playsound( "zmb_meteor_activate" ); + level.snd115count++; + if ( level.snd115count == 3 ) + { + temp_ent notify( "sndDeleting" ); + level thread sndmuseggplay( temp_ent, "mus_zmb_secret_song_aether", 135 ); + level notify( "sndEnd115" ); + } + else + { + temp_ent notify( "sndDeleting" ); + temp_ent delete(); + } +} + +snd115egg_1_override() +{ + stance = self getstance(); + if ( is_true( level.music_override ) || stance != "prone" ) + { + return 0; + } + return 1; +} + +snd115egg_5_override() +{ + stance = self getstance(); + if ( !is_true( level.music_override ) || stance != "prone" && level.snd115count < 2 ) + { + return 0; + } + return 1; +} + +snddelete115ent() +{ + self endon( "sndDeleting" ); + level waittill( "sndEnd115" ); + self delete(); +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_ambient_scripts.gsc b/zm_tomb_patch/maps/mp/zm_tomb_ambient_scripts.gsc new file mode 100644 index 0000000..4f344bb --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_ambient_scripts.gsc @@ -0,0 +1,122 @@ +#include maps/mp/animscripts/zm_death; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/zombies/_zm_score; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +#using_animtree( "fxanim_props_dlc4" ); + +tomb_ambient_precache() +{ + precachemodel( "veh_t6_dlc_zm_zeppelin" ); +} + +init_tomb_ambient_scripts() +{ + tomb_ambient_precache(); + registerclientfield( "world", "sky_battle_ambient_fx", 14000, 1, "int" ); + level thread start_sky_battle(); + level thread init_zeppelin( "sky_cowbell_zeppelin_low", "stop_ambient_zeppelins" ); + delay_thread( 20, ::init_zeppelin, "sky_cowbell_zeppelin_mid", "stop_ambient_zeppelins" ); + delay_thread( 40, ::init_zeppelin, "sky_cowbell_zeppelin_high", "stop_ambient_zeppelins" ); + level thread vista_robot_pose(); +} + +init_zeppelin( str_script_noteworthy, str_ender ) +{ + level endon( str_ender ); + a_path_structs = getstructarray( str_script_noteworthy, "script_noteworthy" ); + while ( a_path_structs.size > 0 ) + { + m_zeppelin = spawn( "script_model", ( 0, 0, 0 ) ); + m_zeppelin setmodel( "veh_t6_dlc_zm_zeppelin" ); + m_zeppelin setforcenocull(); + while ( 1 ) + { + m_zeppelin move_zeppelin_down_new_path( a_path_structs ); + } + } +} + +move_zeppelin_down_new_path( a_structs ) +{ + s_path_start = get_unused_struct( a_structs ); + self ghost(); + self moveto( s_path_start.origin, 0,1 ); + self rotateto( s_path_start.angles, 0,1 ); + self waittill( "movedone" ); + self show(); + if ( !isDefined( s_path_start.goal_struct ) ) + { +/# + assert( isDefined( s_path_start.target ), "move_zeppelin_down_new_path found start struct at " + s_path_start.origin + " without a target! These are needed for zeppelin splines!" ); +#/ + s_path_start.goal_struct = getstruct( s_path_start.target, "targetname" ); +/# + assert( isDefined( s_path_start.goal_struct ), "move_zeppelin_down_new_path couldn't find goal for path start struct at " + s_path_start.origin ); +#/ + } + n_move_time = randomfloatrange( 120, 150 ); + self moveto( s_path_start.goal_struct.origin, n_move_time ); + self waittill( "movedone" ); +} + +get_unused_struct( a_structs ) +{ + a_valid_structs = []; + b_no_unused_structs = 0; + while ( !a_valid_structs.size ) + { + _a90 = a_structs; + _k90 = getFirstArrayKey( _a90 ); + while ( isDefined( _k90 ) ) + { + struct = _a90[ _k90 ]; + if ( !isDefined( struct.used ) || b_no_unused_structs ) + { + struct.used = 0; + } + if ( !struct.used ) + { + a_valid_structs[ a_valid_structs.size ] = struct; + } + _k90 = getNextArrayKey( _a90, _k90 ); + } + if ( !a_valid_structs.size ) + { + b_no_unused_structs = 1; + } + } + s_unused = random( a_valid_structs ); + s_unused.used = 1; + return s_unused; +} + +start_sky_battle() +{ + flag_wait( "start_zombie_round_logic" ); + level setclientfield( "sky_battle_ambient_fx", 1 ); +} + +vista_robot_pose() +{ + flag_wait( "start_zombie_round_logic" ); + a_robots = getstructarray( "trench_downed_robot_struct", "targetname" ); + i = 0; + while ( i < a_robots.size ) + { + if ( !isDefined( a_robots[ i ].angles ) ) + { + a_robots[ i ].angles = ( 0, 0, 0 ); + } + v_origin = getstartorigin( a_robots[ i ].origin, a_robots[ i ].angles, %ai_zombie_giant_robot_vista ); + v_angles = getstartangles( a_robots[ i ].origin, a_robots[ i ].angles, %ai_zombie_giant_robot_vista ); + e_robot = spawn( "script_model", v_origin ); + e_robot.angles = v_angles; + e_robot setmodel( "veh_t6_dlc_zm_robot" ); + e_robot useanimtree( -1 ); + e_robot setanim( %ai_zombie_giant_robot_vista, 1, 0, 1 ); + i++; + } +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_capture_zones.gsc b/zm_tomb_patch/maps/mp/zm_tomb_capture_zones.gsc new file mode 100644 index 0000000..de7a73c --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_capture_zones.gsc @@ -0,0 +1,2777 @@ +#include maps/mp/zombies/_zm_powerups; +#include maps/mp/zombies/_zm_magicbox_tomb; +#include maps/mp/zombies/_zm_challenges; +#include maps/mp/zombies/_zm_stats; +#include maps/mp/zombies/_zm_ai_basic; +#include maps/mp/zombies/_zm_unitrigger; +#include maps/mp/zombies/_zm_perks; +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/zm_tomb_capture_zones_ffotd; +#include maps/mp/zm_tomb_vo; +#include maps/mp/zombies/_zm_magicbox; +#include maps/mp/zm_tomb_utility; +#include maps/mp/animscripts/zm_death; +#include maps/mp/zombies/_zm_zonemgr; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/zombies/_zm_score; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +#using_animtree( "fxanim_props_dlc4" ); + +init_capture_zones() +{ + maps/mp/zm_tomb_capture_zones_ffotd::capture_zone_init_start(); + precache_everything(); + declare_objectives(); + flag_init( "zone_capture_in_progress" ); + flag_init( "recapture_event_in_progress" ); + flag_init( "capture_zones_init_done" ); + flag_init( "recapture_zombies_cleared" ); + flag_init( "generator_under_attack" ); + flag_init( "all_zones_captured" ); + flag_init( "generator_lost_to_recapture_zombies" ); + root = %root; + i = %fxanim_zom_tomb_generator_start_anim; + i = %fxanim_zom_tomb_generator_up_idle_anim; + i = %fxanim_zom_tomb_generator_down_idle_anim; + i = %fxanim_zom_tomb_generator_end_anim; + i = %fxanim_zom_tomb_generator_fluid_down_anim; + i = %fxanim_zom_tomb_generator_fluid_up_anim; + i = %fxanim_zom_tomb_generator_fluid_rotate_down_anim; + i = %fxanim_zom_tomb_generator_fluid_rotate_up_anim; + i = %fxanim_zom_tomb_packapunch_pc1_anim; + i = %fxanim_zom_tomb_packapunch_pc2_anim; + i = %fxanim_zom_tomb_packapunch_pc3_anim; + i = %fxanim_zom_tomb_packapunch_pc4_anim; + i = %fxanim_zom_tomb_packapunch_pc5_anim; + i = %fxanim_zom_tomb_packapunch_pc6_anim; + i = %fxanim_zom_tomb_packapunch_pc7_anim; + i = %fxanim_zom_tomb_pack_return_pc1_anim; + i = %fxanim_zom_tomb_pack_return_pc2_anim; + i = %fxanim_zom_tomb_pack_return_pc3_anim; + i = %fxanim_zom_tomb_pack_return_pc4_anim; + i = %fxanim_zom_tomb_pack_return_pc5_anim; + i = %fxanim_zom_tomb_pack_return_pc6_anim; + i = %fxanim_zom_tomb_monolith_inductor_pull_anim; + i = %fxanim_zom_tomb_monolith_inductor_pull_idle_anim; + i = %fxanim_zom_tomb_monolith_inductor_release_anim; + i = %fxanim_zom_tomb_monolith_inductor_shake_anim; + i = %fxanim_zom_tomb_monolith_inductor_idle_anim; + level thread setup_capture_zones(); +} + +precache_everything() +{ + precachemodel( "p6_zm_tm_zone_capture_hole" ); + precachemodel( "p6_zm_tm_packapunch" ); + precacherumble( "generator_active" ); + precachestring( &"ZM_TOMB_OBJ_CAPTURE_1" ); + precachestring( &"ZM_TOMB_OBJ_RECAPTURE_1" ); + precachestring( &"ZM_TOMB_OBJ_CAPTURE_2" ); + precachestring( &"ZM_TOMB_OBJ_RECAPTURE_2" ); + precachestring( &"ZM_TOMB_OBJ_RECAPTURE_ZOMBIE" ); +} + +declare_objectives() +{ + objective_add( 0, "invisible", ( 0, 0, 1 ), &"ZM_TOMB_OBJ_CAPTURE_1" ); + objective_add( 1, "invisible", ( 0, 0, 1 ), &"ZM_TOMB_OBJ_RECAPTURE_2" ); + objective_add( 2, "invisible", ( 0, 0, 1 ), &"ZM_TOMB_OBJ_CAPTURE_2" ); + objective_add( 3, "invisible", ( 0, 0, 1 ), &"ZM_TOMB_OBJ_RECAPTURE_ZOMBIE" ); +} + +init_pap_animtree() +{ + scriptmodelsuseanimtree( -1 ); +} + +setup_capture_zones() +{ + spawner_capture_zombie = getent( "capture_zombie_spawner", "targetname" ); + spawner_capture_zombie add_spawn_function( ::capture_zombie_spawn_init ); + a_s_generator = getstructarray( "s_generator", "targetname" ); + registerclientfield( "world", "packapunch_anim", 14000, 3, "int" ); + registerclientfield( "actor", "zone_capture_zombie", 14000, 1, "int" ); + registerclientfield( "scriptmover", "zone_capture_emergence_hole", 14000, 1, "int" ); + registerclientfield( "world", "zc_change_progress_bar_color", 14000, 1, "int" ); + registerclientfield( "world", "zone_capture_hud_all_generators_captured", 14000, 1, "int" ); + registerclientfield( "world", "zone_capture_perk_machine_smoke_fx_always_on", 14000, 1, "int" ); + registerclientfield( "world", "pap_monolith_ring_shake", 14000, 1, "int" ); + _a149 = a_s_generator; + _k149 = getFirstArrayKey( _a149 ); + while ( isDefined( _k149 ) ) + { + struct = _a149[ _k149 ]; + registerclientfield( "world", struct.script_noteworthy, 14000, 7, "float" ); + registerclientfield( "world", "state_" + struct.script_noteworthy, 14000, 3, "int" ); + registerclientfield( "world", "zone_capture_hud_generator_" + struct.script_int, 14000, 2, "int" ); + registerclientfield( "world", "zone_capture_monolith_crystal_" + struct.script_int, 14000, 1, "int" ); + registerclientfield( "world", "zone_capture_perk_machine_smoke_fx_" + struct.script_int, 14000, 1, "int" ); + _k149 = getNextArrayKey( _a149, _k149 ); + } + flag_wait( "start_zombie_round_logic" ); + level.magic_box_zbarrier_state_func = ::set_magic_box_zbarrier_state; + level.custom_perk_validation = ::check_perk_machine_valid; + level thread track_max_player_zombie_points(); + _a168 = a_s_generator; + _k168 = getFirstArrayKey( _a168 ); + while ( isDefined( _k168 ) ) + { + s_generator = _a168[ _k168 ]; + s_generator thread init_capture_zone(); + _k168 = getNextArrayKey( _a168, _k168 ); + } + register_elements_powered_by_zone_capture_generators(); + setup_perk_machines_not_controlled_by_zone_capture(); + pack_a_punch_init(); + level thread recapture_round_tracker(); + level.zone_capture.recapture_zombies = []; + level.zone_capture.last_zone_captured = undefined; + level.zone_capture.spawn_func_capture_zombie = ::init_capture_zombie; + level.zone_capture.spawn_func_recapture_zombie = ::init_recapture_zombie; +/# + level thread watch_for_open_sesame(); + level thread debug_watch_for_zone_capture(); + level thread debug_watch_for_zone_recapture(); +#/ + maps/mp/zombies/_zm_spawner::register_zombie_death_event_callback( ::recapture_zombie_death_func ); + level.custom_derive_damage_refs = ::zone_capture_gib_think; + setup_inaccessible_zombie_attack_points(); + level thread quick_revive_game_type_watcher(); + level thread quick_revive_solo_leave_watcher(); + level thread all_zones_captured_vo(); + flag_set( "capture_zones_init_done" ); + level setclientfield( "zone_capture_perk_machine_smoke_fx_always_on", 1 ); + maps/mp/zm_tomb_capture_zones_ffotd::capture_zone_init_end(); +} + +all_zones_captured_vo() +{ + flag_wait( "all_zones_captured" ); + flag_waitopen( "story_vo_playing" ); + set_players_dontspeak( 1 ); + flag_set( "story_vo_playing" ); + e_speaker = get_closest_player_to_richtofen(); + if ( isDefined( e_speaker ) ) + { + e_speaker set_player_dontspeak( 0 ); + e_speaker create_and_play_dialog( "zone_capture", "all_generators_captured" ); + e_speaker waittill_any( "done_speaking", "disconnect" ); + } + e_richtofen = get_player_named( "Richtofen" ); + if ( isDefined( e_richtofen ) ) + { + e_richtofen set_player_dontspeak( 0 ); + e_richtofen create_and_play_dialog( "zone_capture", "all_generators_captured" ); + } + set_players_dontspeak( 0 ); + flag_clear( "story_vo_playing" ); +} + +get_closest_player_to_richtofen() +{ + a_players = get_players(); + e_speaker = undefined; + e_richtofen = get_player_named( "Richtofen" ); + if ( isDefined( e_richtofen ) ) + { + if ( a_players.size > 1 ) + { + arrayremovevalue( a_players, e_richtofen, 0 ); + e_speaker = arraysort( a_players, e_richtofen.origin, 1 )[ 0 ]; + } + else + { + e_speaker = undefined; + } + } + else + { + e_speaker = get_random_speaker(); + } + return e_speaker; +} + +get_player_named( str_character_name ) +{ + e_character = undefined; + _a269 = get_players(); + _k269 = getFirstArrayKey( _a269 ); + while ( isDefined( _k269 ) ) + { + player = _a269[ _k269 ]; + if ( isDefined( player.character_name ) && player.character_name == str_character_name ) + { + e_character = player; + } + _k269 = getNextArrayKey( _a269, _k269 ); + } + return e_character; +} + +quick_revive_game_type_watcher() +{ + while ( 1 ) + { + level waittill( "revive_hide" ); + wait 1; + t_revive_machine = level.zone_capture.zones[ "generator_start_bunker" ].perk_machines[ "revive" ]; + if ( level.zone_capture.zones[ "generator_start_bunker" ] ent_flag( "player_controlled" ) ) + { + level notify( "revive_on" ); + t_revive_machine.is_locked = 0; + t_revive_machine maps/mp/zombies/_zm_perks::reset_vending_hint_string(); + continue; + } + else + { + level notify( "revive_off" ); + t_revive_machine.is_locked = 1; + t_revive_machine sethintstring( &"ZM_TOMB_ZC" ); + } + } +} + +quick_revive_solo_leave_watcher() +{ + if ( flag_exists( "solo_revive" ) ) + { + flag_wait( "solo_revive" ); + level setclientfield( "zone_capture_perk_machine_smoke_fx_1", 0 ); + } +} + +revive_perk_fx_think() +{ + if ( flag_exists( "solo_revive" ) ) + { + return !flag( "solo_revive" ); + } +} + +setup_inaccessible_zombie_attack_points() +{ + set_attack_point_as_inaccessible( "generator_start_bunker", 5 ); + set_attack_point_as_inaccessible( "generator_start_bunker", 11 ); + set_attack_point_as_inaccessible( "generator_tank_trench", 4 ); + set_attack_point_as_inaccessible( "generator_tank_trench", 5 ); + set_attack_point_as_inaccessible( "generator_tank_trench", 6 ); +} + +set_attack_point_as_inaccessible( str_zone, n_index ) +{ +/# + assert( isDefined( level.zone_capture.zones[ str_zone ] ), "set_attack_point_as_inaccessible couldn't find " + str_zone + " in level.zone_capture's zone array!" ); +#/ + level.zone_capture.zones[ str_zone ] ent_flag_wait( "zone_initialized" ); +/# + assert( isDefined( level.zone_capture.zones[ str_zone ].zombie_attack_points[ n_index ] ), "set_attack_points_as_inaccessible couldn't find index " + n_index + " on zone " + str_zone ); +#/ + level.zone_capture.zones[ str_zone ].zombie_attack_points[ n_index ].inaccessible = 1; +} + +setup_perk_machines_not_controlled_by_zone_capture() +{ + level.zone_capture.perk_machines_always_on = array( "specialty_additionalprimaryweapon" ); +} + +track_max_player_zombie_points() +{ + while ( 1 ) + { + a_players = get_players(); + _a356 = a_players; + _k356 = getFirstArrayKey( _a356 ); + while ( isDefined( _k356 ) ) + { + player = _a356[ _k356 ]; + player.n_capture_zombie_points = 0; + _k356 = getNextArrayKey( _a356, _k356 ); + } + level waittill( "between_round_over" ); + } +} + +pack_a_punch_dummy_init() +{ +} + +pack_a_punch_init() +{ + vending_weapon_upgrade_trigger = getentarray( "specialty_weapupgrade", "script_noteworthy" ); + level.pap_triggers = vending_weapon_upgrade_trigger; + t_pap = getent( "specialty_weapupgrade", "script_noteworthy" ); + t_pap.machine ghost(); + t_pap.machine notsolid(); + t_pap.bump enablelinkto(); + t_pap.bump linkto( t_pap ); + level thread pack_a_punch_think(); +} + +pack_a_punch_think() +{ + while ( 1 ) + { + flag_wait( "all_zones_captured" ); + pack_a_punch_enable(); + flag_waitopen( "all_zones_captured" ); + pack_a_punch_disable(); + } +} + +pack_a_punch_enable() +{ + t_pap = getent( "specialty_weapupgrade", "script_noteworthy" ); + t_pap trigger_on(); + flag_set( "power_on" ); + level setclientfield( "zone_capture_hud_all_generators_captured", 1 ); + if ( !flag( "generator_lost_to_recapture_zombies" ) ) + { + level notify( "all_zones_captured_none_lost" ); + } +} + +pack_a_punch_disable() +{ + t_pap = getent( "specialty_weapupgrade", "script_noteworthy" ); + level setclientfield( "zone_capture_hud_all_generators_captured", 0 ); + flag_waitopen( "pack_machine_in_use" ); + t_pap trigger_off(); +} + +register_elements_powered_by_zone_capture_generators() +{ + register_random_perk_machine_for_zone( "generator_start_bunker", "starting_bunker" ); + register_perk_machine_for_zone( "generator_start_bunker", "revive", "vending_revive", ::revive_perk_fx_think ); + register_mystery_box_for_zone( "generator_start_bunker", "bunker_start_chest" ); + register_random_perk_machine_for_zone( "generator_tank_trench", "trenches_right" ); + register_mystery_box_for_zone( "generator_tank_trench", "bunker_tank_chest" ); + register_random_perk_machine_for_zone( "generator_mid_trench", "trenches_left" ); + register_perk_machine_for_zone( "generator_mid_trench", "sleight", "vending_sleight" ); + register_mystery_box_for_zone( "generator_mid_trench", "bunker_cp_chest" ); + register_random_perk_machine_for_zone( "generator_nml_right", "nml" ); + register_perk_machine_for_zone( "generator_nml_right", "juggernog", "vending_jugg" ); + register_mystery_box_for_zone( "generator_nml_right", "nml_open_chest" ); + register_random_perk_machine_for_zone( "generator_nml_left", "farmhouse" ); + register_perk_machine_for_zone( "generator_nml_left", "marathon", "vending_marathon" ); + register_mystery_box_for_zone( "generator_nml_left", "nml_farm_chest" ); + register_random_perk_machine_for_zone( "generator_church", "church" ); + register_mystery_box_for_zone( "generator_church", "village_church_chest" ); +} + +register_perk_machine_for_zone( str_zone_name, str_perk_name, str_machine_targetname, func_perk_fx_think ) +{ +/# + assert( isDefined( level.zone_capture.zones[ str_zone_name ] ), "register_perk_machine_for_zone can't find " + str_zone_name + " has not been initialized in level.zone_capture.zones array!" ); +#/ + if ( !isDefined( level.zone_capture.zones[ str_zone_name ].perk_machines ) ) + { + level.zone_capture.zones[ str_zone_name ].perk_machines = []; + } + if ( !isDefined( level.zone_capture.zones[ str_zone_name ].perk_machines[ str_perk_name ] ) ) + { + e_perk_machine_trigger = get_perk_machine_trigger_from_vending_entity( str_machine_targetname ); + e_perk_machine_trigger.str_zone_name = str_zone_name; + level.zone_capture.zones[ str_zone_name ].perk_machines[ str_perk_name ] = e_perk_machine_trigger; + } + level.zone_capture.zones[ str_zone_name ].perk_fx_func = func_perk_fx_think; +} + +register_random_perk_machine_for_zone( str_zone_name, str_identifier ) +{ +/# + assert( isDefined( level.zone_capture.zones[ str_zone_name ] ), "register_random_perk_machine_for_zone can't find " + str_zone_name + " has not been initialized in level.zone_capture.zones array!" ); +#/ + if ( !isDefined( level.zone_capture.zones[ str_zone_name ].perk_machines_random ) ) + { + level.zone_capture.zones[ str_zone_name ].perk_machines_random = []; + } + a_random_perk_machines = getentarray( "random_perk_machine", "targetname" ); + _a492 = a_random_perk_machines; + _k492 = getFirstArrayKey( _a492 ); + while ( isDefined( _k492 ) ) + { + random_perk_machine = _a492[ _k492 ]; + if ( isDefined( random_perk_machine.script_string ) && random_perk_machine.script_string == str_identifier ) + { + level.zone_capture.zones[ str_zone_name ].perk_machines_random[ level.zone_capture.zones[ str_zone_name ].perk_machines_random.size ] = random_perk_machine; + } + _k492 = getNextArrayKey( _a492, _k492 ); + } +} + +register_mystery_box_for_zone( str_zone_name, str_identifier ) +{ +/# + assert( isDefined( level.zone_capture.zones[ str_zone_name ] ), "register_mystery_box_for_zone can't find " + str_zone_name + " has not been initialized in level.zone_capture.zones array!" ); +#/ + if ( !isDefined( level.zone_capture.zones[ str_zone_name ].mystery_boxes ) ) + { + level.zone_capture.zones[ str_zone_name ].mystery_boxes = []; + } + s_mystery_box = get_mystery_box_from_script_noteworthy( str_identifier ); + s_mystery_box.unitrigger_stub.prompt_and_visibility_func = ::magic_box_trigger_update_prompt; + s_mystery_box.unitrigger_stub.zone = str_zone_name; + s_mystery_box.zone_capture_area = str_zone_name; + s_mystery_box.zbarrier.zone_capture_area = str_zone_name; + level.zone_capture.zones[ str_zone_name ].mystery_boxes[ level.zone_capture.zones[ str_zone_name ].mystery_boxes.size ] = s_mystery_box; +} + +get_mystery_box_from_script_noteworthy( str_script_noteworthy ) +{ + s_box = undefined; + _a524 = level.chests; + _k524 = getFirstArrayKey( _a524 ); + while ( isDefined( _k524 ) ) + { + s_mystery_box = _a524[ _k524 ]; + if ( isDefined( s_mystery_box.script_noteworthy ) && s_mystery_box.script_noteworthy == str_script_noteworthy ) + { + s_box = s_mystery_box; + } + _k524 = getNextArrayKey( _a524, _k524 ); + } +/# + assert( isDefined( s_mystery_box ), "get_mystery_box_from_script_noteworthy() couldn't find a mystery box with script_noteworthy = " + str_script_noteworthy ); +#/ + return s_box; +} + +enable_perk_machines_in_zone() +{ + while ( isDefined( self.perk_machines ) && isarray( self.perk_machines ) ) + { + a_keys = getarraykeys( self.perk_machines ); + i = 0; + while ( i < a_keys.size ) + { + level notify( a_keys[ i ] + "_on" ); + i++; + } + i = 0; + while ( i < a_keys.size ) + { + e_perk_trigger = self.perk_machines[ a_keys[ i ] ]; + e_perk_trigger.is_locked = 0; + e_perk_trigger maps/mp/zombies/_zm_perks::reset_vending_hint_string(); + i++; + } + } +} + +disable_perk_machines_in_zone() +{ + while ( isDefined( self.perk_machines ) && isarray( self.perk_machines ) ) + { + a_keys = getarraykeys( self.perk_machines ); + i = 0; + while ( i < a_keys.size ) + { + level notify( a_keys[ i ] + "_off" ); + i++; + } + i = 0; + while ( i < a_keys.size ) + { + e_perk_trigger = self.perk_machines[ a_keys[ i ] ]; + e_perk_trigger.is_locked = 1; + e_perk_trigger sethintstring( &"ZM_TOMB_ZC" ); + i++; + } + } +} + +enable_random_perk_machines_in_zone() +{ + while ( isDefined( self.perk_machines_random ) && isarray( self.perk_machines_random ) ) + { + _a586 = self.perk_machines_random; + _k586 = getFirstArrayKey( _a586 ); + while ( isDefined( _k586 ) ) + { + random_perk_machine = _a586[ _k586 ]; + random_perk_machine.is_locked = 0; + random_perk_machine sethintstring( &"ZM_TOMB_RPB", level._random_zombie_perk_cost ); + _k586 = getNextArrayKey( _a586, _k586 ); + } + } +} + +disable_random_perk_machines_in_zone() +{ + while ( isDefined( self.perk_machines_random ) && isarray( self.perk_machines_random ) ) + { + _a598 = self.perk_machines_random; + _k598 = getFirstArrayKey( _a598 ); + while ( isDefined( _k598 ) ) + { + random_perk_machine = _a598[ _k598 ]; + random_perk_machine.is_locked = 1; + _k598 = getNextArrayKey( _a598, _k598 ); + } + } +} + +enable_mystery_boxes_in_zone() +{ + _a608 = self.mystery_boxes; + _k608 = getFirstArrayKey( _a608 ); + while ( isDefined( _k608 ) ) + { + mystery_box = _a608[ _k608 ]; + mystery_box.is_locked = 0; + mystery_box.zbarrier set_magic_box_zbarrier_state( "player_controlled" ); + mystery_box.zbarrier setclientfield( "magicbox_runes", 1 ); + _k608 = getNextArrayKey( _a608, _k608 ); + } +} + +disable_mystery_boxes_in_zone() +{ + _a621 = self.mystery_boxes; + _k621 = getFirstArrayKey( _a621 ); + while ( isDefined( _k621 ) ) + { + mystery_box = _a621[ _k621 ]; + mystery_box.is_locked = 1; + mystery_box.zbarrier set_magic_box_zbarrier_state( "zombie_controlled" ); + mystery_box.zbarrier setclientfield( "magicbox_runes", 0 ); + _k621 = getNextArrayKey( _a621, _k621 ); + } +} + +get_perk_machine_trigger_from_vending_entity( str_vending_machine_targetname ) +{ + e_trigger = getent( str_vending_machine_targetname, "target" ); +/# + assert( isDefined( e_trigger ), "get_perk_machine_trigger_from_vending_entity couldn't find perk machine trigger with target = " + str_vending_machine_targetname ); +#/ + return e_trigger; +} + +check_perk_machine_valid( player ) +{ + if ( isDefined( self.script_noteworthy ) && isinarray( level.zone_capture.perk_machines_always_on, self.script_noteworthy ) ) + { + b_machine_valid = 1; + } + else + { +/# + assert( isDefined( self.str_zone_name ), "str_zone_name field missing on perk machine! This is required by the zone capture system!" ); +#/ + b_machine_valid = level.zone_capture.zones[ self.str_zone_name ] ent_flag( "player_controlled" ); + } + if ( !b_machine_valid ) + { + player create_and_play_dialog( "lockdown", "power_off" ); + } + return b_machine_valid; +} + +init_capture_zone() +{ +/# + assert( isDefined( self.script_noteworthy ), "capture zone struct is missing script_noteworthy KVP! This is required for init_capture_zone()" ); +#/ + if ( !isDefined( level.zone_capture ) ) + { + level.zone_capture = spawnstruct(); + } + if ( !isDefined( level.zone_capture.zones ) ) + { + level.zone_capture.zones = []; + } +/# + assert( !isDefined( level.zone_capture.zones[ self.script_noteworthy ] ), "init_capture_zone() attempting to initialize an existing zone with name '" + self.script_noteworthy + "'" ); +#/ + self.n_current_progress = 0; + self.n_last_progress = 0; + self setup_generator_unitrigger(); + self.str_zone = get_zone_from_position( self.origin, 1 ); + self.sndent = spawn( "script_origin", self.origin ); +/# + assert( isDefined( self.script_int ), "script_int KVP is required by init_capture_zone() to identify the objective index, but it's missing on zone '" + self.script_noteworthy + "'" ); +#/ + self ent_flag_init( "attacked_by_recapture_zombies" ); + self ent_flag_init( "current_recapture_target_zone" ); + self ent_flag_init( "player_controlled" ); + self ent_flag_init( "zone_contested" ); + self ent_flag_init( "zone_initialized" ); + level.zone_capture.zones[ self.script_noteworthy ] = self; + self set_zombie_controlled_area( 1 ); + self setup_zombie_attack_points(); + self ent_flag_set( "zone_initialized" ); + self thread wait_for_capture_trigger(); +} + +setup_generator_unitrigger() +{ + s_unitrigger_stub = spawnstruct(); + s_unitrigger_stub.origin = self.origin; + s_unitrigger_stub.angles = self.angles; + s_unitrigger_stub.radius = 32; + s_unitrigger_stub.script_length = 128; + s_unitrigger_stub.script_width = 128; + s_unitrigger_stub.script_height = 128; + s_unitrigger_stub.cursor_hint = "HINT_NOICON"; + s_unitrigger_stub.hint_string = &"ZM_TOMB_CAP"; + s_unitrigger_stub.hint_parm1 = [[ ::get_generator_capture_start_cost ]](); + s_unitrigger_stub.script_unitrigger_type = "unitrigger_box_use"; + s_unitrigger_stub.require_look_at = 1; + s_unitrigger_stub.prompt_and_visibility_func = ::generator_trigger_prompt_and_visibility; + s_unitrigger_stub.generator_struct = self; + unitrigger_force_per_player_triggers( s_unitrigger_stub, 1 ); + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( s_unitrigger_stub, ::generator_unitrigger_think ); +} + +generator_trigger_prompt_and_visibility( e_player ) +{ + b_can_see_hint = 1; + s_zone = self.stub.generator_struct; + if ( s_zone ent_flag( "zone_contested" ) || s_zone ent_flag( "player_controlled" ) ) + { + b_can_see_hint = 0; + } + if ( flag( "zone_capture_in_progress" ) ) + { + self sethintstring( &"ZM_TOMB_ZCIP" ); + } + else + { + self sethintstring( &"ZM_TOMB_CAP", get_generator_capture_start_cost() ); + } + self setinvisibletoplayer( e_player, !b_can_see_hint ); + return b_can_see_hint; +} + +generator_unitrigger_think() +{ + self endon( "kill_trigger" ); + while ( 1 ) + { + self waittill( "trigger", e_player ); + while ( is_player_valid( e_player ) || e_player is_reviving_any() && e_player != self.parent_player ) + { + continue; + } + while ( e_player.score < get_generator_capture_start_cost() ) + { + e_player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "no_money_capture" ); + } + while ( flag( "zone_capture_in_progress" ) ) + { + continue; + } + self setinvisibletoall(); + self.stub.generator_struct notify( "start_generator_capture" ); + } +} + +setup_zombie_attack_points() +{ + self.zombie_attack_points = []; + v_right = anglesToRight( self.angles ); + self add_attack_points_from_anchor_origin( self.origin, 0, 52 ); + self add_attack_points_from_anchor_origin( self.origin + ( v_right * 170 ), 4, 32 ); + self add_attack_points_from_anchor_origin( self.origin + ( ( v_right * -1 ) * 170 ), 8, 32 ); +} + +add_attack_points_from_anchor_origin( v_origin, n_start_index, n_scale ) +{ + v_forward = anglesToForward( self.angles ); + v_right = anglesToRight( self.angles ); + self.zombie_attack_points[ n_start_index ] = init_attack_point( v_origin + ( v_forward * n_scale ), v_origin ); + self.zombie_attack_points[ n_start_index + 1 ] = init_attack_point( v_origin + ( v_right * n_scale ), v_origin ); + self.zombie_attack_points[ n_start_index + 2 ] = init_attack_point( v_origin + ( ( v_forward * -1 ) * n_scale ), v_origin ); + self.zombie_attack_points[ n_start_index + 3 ] = init_attack_point( v_origin + ( ( v_right * -1 ) * n_scale ), v_origin ); +} + +init_attack_point( v_origin, v_center_pillar ) +{ + s_temp = spawnstruct(); + s_temp.is_claimed = 0; + s_temp.claimed_by = undefined; + s_temp.origin = v_origin; + s_temp.inaccessible = 0; + s_temp.v_center_pillar = v_center_pillar; + return s_temp; +} + +wait_for_capture_trigger() +{ + while ( 1 ) + { + self waittill( "start_generator_capture", e_player ); + if ( !flag( "zone_capture_in_progress" ) ) + { + flag_set( "zone_capture_in_progress" ); + self.generator_cost = get_generator_capture_start_cost(); + e_player minus_to_player_score( self.generator_cost ); + e_player delay_thread( 2,5, ::create_and_play_dialog, "zone_capture", "capture_started" ); + self maps/mp/zm_tomb_capture_zones_ffotd::capture_event_start(); + self thread monitor_capture_zombies(); + self thread activate_capture_zone(); + self ent_flag_wait( "zone_contested" ); + capture_event_handle_ai_limit(); + self ent_flag_waitopen( "zone_contested" ); + self maps/mp/zm_tomb_capture_zones_ffotd::capture_event_end(); + wait 1; + if ( isDefined( e_player ) && self ent_flag( "player_controlled" ) ) + { + self refund_generator_cost_if_player_captured_it( e_player ); + } + } + else + { + flag_wait( "zone_capture_in_progress" ); + flag_waitopen( "zone_capture_in_progress" ); + } + capture_event_handle_ai_limit(); + if ( self ent_flag( "player_controlled" ) ) + { + self ent_flag_waitopen( "player_controlled" ); + } + } +} + +refund_generator_cost_if_player_captured_it( e_player ) +{ + if ( isinarray( self get_players_in_capture_zone(), e_player ) ) + { + n_refund_amount = self.generator_cost; + b_double_points_active = level.zombie_vars[ "allies" ][ "zombie_point_scalar" ] == 2; + n_multiplier = 1; + if ( b_double_points_active ) + { + n_multiplier = 0,5; + } + e_player add_to_player_score( int( n_refund_amount * n_multiplier ) ); + } +} + +get_generator_capture_start_cost() +{ + return 200 * get_players().size; +} + +capture_event_handle_ai_limit() +{ + n_capture_zombies_needed = calculate_capture_event_zombies_needed(); + level.zombie_ai_limit = 24 - n_capture_zombies_needed; + while ( get_current_zombie_count() > level.zombie_ai_limit ) + { + ai_zombie = get_zombie_to_delete(); + if ( isDefined( ai_zombie ) ) + { + ai_zombie thread delete_zombie_for_capture_event(); + } + wait_network_frame(); + } +} + +get_zombie_to_delete() +{ + ai_zombie = undefined; + a_zombies = get_round_enemy_array(); + if ( a_zombies.size > 0 ) + { + ai_zombie = random( a_zombies ); + } + return ai_zombie; +} + +delete_zombie_for_capture_event() +{ + if ( isDefined( self ) ) + { + playfx( level._effect[ "tesla_elec_kill" ], self.origin ); + self ghost(); + } + wait_network_frame(); + if ( isDefined( self ) ) + { + self delete(); + } +} + +calculate_capture_event_zombies_needed() +{ + n_capture_zombies_needed = get_capture_zombies_needed(); + n_recapture_zombies_needed = 0; + if ( flag( "recapture_event_in_progress" ) ) + { + n_recapture_zombies_needed = get_recapture_zombies_needed(); + } + return n_capture_zombies_needed + n_recapture_zombies_needed; +} + +get_capture_zombies_needed( b_per_zone ) +{ + if ( !isDefined( b_per_zone ) ) + { + b_per_zone = 0; + } + a_contested_zones = get_contested_zones(); + switch( a_contested_zones.size ) + { + case 0: + n_capture_zombies_needed = 0; + n_capture_zombies_needed_per_zone = 0; + break; + case 1: + n_capture_zombies_needed = 4; + n_capture_zombies_needed_per_zone = 4; + break; + case 2: + n_capture_zombies_needed = 6; + n_capture_zombies_needed_per_zone = 3; + break; + case 3: + n_capture_zombies_needed = 6; + n_capture_zombies_needed_per_zone = 2; + break; + case 4: + n_capture_zombies_needed = 8; + n_capture_zombies_needed_per_zone = 2; + break; + default: +/# + iprintlnbold( "get_capture_zombies_needed() unhandled case. active capture events = " + a_contested_zones.size ); +#/ + n_capture_zombies_needed = 2 * a_contested_zones.size; + n_capture_zombies_needed_per_zone = 2; + break; + } + if ( b_per_zone ) + { + b_capture_zombies_needed = n_capture_zombies_needed_per_zone; + } + return n_capture_zombies_needed; +} + +set_capture_zombies_needed_per_zone() +{ + a_contested_zones = get_contested_zones(); + n_zombies_needed_per_zone = get_capture_zombies_needed( 1 ); + _a1032 = a_contested_zones; + _k1032 = getFirstArrayKey( _a1032 ); + while ( isDefined( _k1032 ) ) + { + zone = _a1032[ _k1032 ]; + if ( zone ent_flag( "current_recapture_target_zone" ) ) + { + } + else + { + zone.capture_zombie_limit = n_zombies_needed_per_zone; + } + _k1032 = getNextArrayKey( _a1032, _k1032 ); + } + return n_zombies_needed_per_zone; +} + +get_recapture_zombies_needed() +{ + if ( level.is_forever_solo_game ) + { + n_recapture_zombies_needed = 4; + } + else + { + n_recapture_zombies_needed = 6; + } + return n_recapture_zombies_needed; +} + +activate_capture_zone( b_show_emergence_holes ) +{ + if ( !isDefined( b_show_emergence_holes ) ) + { + b_show_emergence_holes = 1; + } + if ( !flag( "recapture_event_in_progress" ) ) + { + self thread generator_initiated_vo(); + } + self.a_emergence_hole_structs = getstructarray( self.target, "targetname" ); + self show_emergence_holes( b_show_emergence_holes ); + if ( flag( "recapture_event_in_progress" ) && self ent_flag( "current_recapture_target_zone" ) ) + { + flag_wait_any( "generator_under_attack", "recapture_zombies_cleared" ); + if ( flag( "recapture_zombies_cleared" ) ) + { + return; + } + } + self capture_progress_think(); + self destroy_emergence_holes(); +} + +show_emergence_holes( b_show_emergence_holes ) +{ + self destroy_emergence_holes(); + while ( b_show_emergence_holes ) + { + self.a_spawner_holes = []; + self.a_emergence_holes = []; + _a1097 = self.a_emergence_hole_structs; + _k1097 = getFirstArrayKey( _a1097 ); + while ( isDefined( _k1097 ) ) + { + s_spawner_hole = _a1097[ _k1097 ]; + self.a_emergence_holes[ self.a_emergence_holes.size ] = s_spawner_hole emergence_hole_spawn(); + _k1097 = getNextArrayKey( _a1097, _k1097 ); + } + } +} + +destroy_emergence_holes() +{ + while ( isDefined( self.a_emergence_holes ) && self.a_emergence_holes.size > 0 ) + { + _a1108 = self.a_emergence_holes; + _k1108 = getFirstArrayKey( _a1108 ); + while ( isDefined( _k1108 ) ) + { + m_emergence_hole = _a1108[ _k1108 ]; + if ( isDefined( m_emergence_hole ) ) + { + m_emergence_hole setclientfield( "zone_capture_emergence_hole", 0 ); + m_emergence_hole ghost(); + m_emergence_hole thread delete_self_after_time( randomfloatrange( 0,5, 2 ) ); + } + wait_network_frame(); + _k1108 = getNextArrayKey( _a1108, _k1108 ); + } + } +} + +delete_self_after_time( n_time ) +{ + wait n_time; + if ( isDefined( self ) ) + { + self delete(); + } +} + +monitor_capture_zombies() +{ + self ent_flag_wait( "zone_contested" ); + e_spawner_capture_zombie = getent( "capture_zombie_spawner", "targetname" ); + self.capture_zombies = []; + self.capture_zombie_limit = self set_capture_zombies_needed_per_zone(); + while ( self ent_flag( "zone_contested" ) ) + { + self.capture_zombies = array_removedead( self.capture_zombies ); + if ( self.capture_zombies.size < self.capture_zombie_limit ) + { + ai = spawn_zombie( e_spawner_capture_zombie ); + s_spawn_point = self get_emergence_hole_spawn_point(); + ai thread [[ level.zone_capture.spawn_func_capture_zombie ]]( self, s_spawn_point ); + self.capture_zombies[ self.capture_zombies.size ] = ai; + } + wait 0,5; + } +} + +monitor_recapture_zombies() +{ + e_spawner_capture_zombie = getent( "capture_zombie_spawner", "targetname" ); + self.capture_zombie_limit = get_recapture_zombies_needed(); + n_capture_zombie_spawns = 0; + self thread play_vo_when_generator_is_attacked(); + while ( flag( "recapture_event_in_progress" ) && n_capture_zombie_spawns < self.capture_zombie_limit ) + { + level.zone_capture.recapture_zombies = array_removedead( level.zone_capture.recapture_zombies ); + ai = spawn_zombie( e_spawner_capture_zombie ); + n_capture_zombie_spawns++; + s_spawn_point = self get_emergence_hole_spawn_point(); + ai thread [[ level.zone_capture.spawn_func_recapture_zombie ]]( self, s_spawn_point ); + level.zone_capture.recapture_zombies[ level.zone_capture.recapture_zombies.size ] = ai; + wait 0,5; + } + level monitor_recapture_zombie_count(); +} + +play_vo_when_generator_is_attacked() +{ + self endon( "zone_contested" ); + level endon( "recapture_event_in_progress" ); + self waittill( "zombies_attacking_generator" ); + broadcast_vo_category_to_team( "recapture_generator_attacked", 3,5 ); +} + +get_emergence_hole_spawn_point() +{ + while ( 1 ) + { + if ( isDefined( self.a_emergence_hole_structs ) && self.a_emergence_hole_structs.size > 0 ) + { + s_spawn_point = self get_unused_emergence_hole_spawn_point(); + s_spawn_point.spawned_zombie = 1; + return s_spawn_point; + } + else + { + self.a_emergence_hole_structs = getstructarray( self.target, "targetname" ); + } + wait 0,05; + } +} + +get_unused_emergence_hole_spawn_point() +{ + a_valid_spawn_points = []; + b_all_points_used = 0; + while ( !a_valid_spawn_points.size ) + { + _a1237 = self.a_emergence_hole_structs; + _k1237 = getFirstArrayKey( _a1237 ); + while ( isDefined( _k1237 ) ) + { + s_emergence_hole = _a1237[ _k1237 ]; + if ( !isDefined( s_emergence_hole.spawned_zombie ) || b_all_points_used ) + { + s_emergence_hole.spawned_zombie = 0; + } + if ( !s_emergence_hole.spawned_zombie ) + { + a_valid_spawn_points[ a_valid_spawn_points.size ] = s_emergence_hole; + } + _k1237 = getNextArrayKey( _a1237, _k1237 ); + } + if ( !a_valid_spawn_points.size ) + { + b_all_points_used = 1; + } + } + s_spawn_point = random( a_valid_spawn_points ); + return s_spawn_point; +} + +emergence_hole_spawn() +{ + m_emergence_hole = spawn( "script_model", self.origin ); + m_emergence_hole.angles = self.angles; + m_emergence_hole setmodel( "p6_zm_tm_zone_capture_hole" ); + wait_network_frame(); + m_emergence_hole setclientfield( "zone_capture_emergence_hole", 1 ); + return m_emergence_hole; +} + +init_zone_capture_zombie_common( s_spawn_point ) +{ + self setphysparams( 15, 0, 72 ); + self.ignore_enemy_count = 1; + self dug_zombie_rise( s_spawn_point ); + self playsound( "zmb_vocals_capzomb_spawn" ); + self setclientfield( "zone_capture_zombie", 1 ); + self init_anim_rate(); +} + +init_anim_rate() +{ + self setclientfield( "anim_rate", 1 ); + n_rate = self getclientfield( "anim_rate" ); + self setentityanimrate( n_rate ); +} + +zone_capture_gib_think( refs, point, weaponname ) +{ + if ( isDefined( self.is_recapture_zombie ) && self.is_recapture_zombie ) + { + arrayremovevalue( refs, "right_leg", 0 ); + arrayremovevalue( refs, "left_leg", 0 ); + arrayremovevalue( refs, "no_legs", 0 ); + } + return refs; +} + +init_capture_zombie( zone_struct, s_spawn_point ) +{ + self endon( "death" ); + self init_zone_capture_zombie_common( s_spawn_point ); + if ( isDefined( self.zombie_move_speed ) && self.zombie_move_speed == "walk" ) + { + self.zombie_move_speed = "run"; + self set_zombie_run_cycle( "run" ); + } + self thread maps/mp/zombies/_zm_ai_basic::find_flesh(); + find_flesh_struct_string = "find_flesh"; + self notify( "zombie_custom_think_done" ); + self thread capture_zombies_only_attack_nearby_players( zone_struct ); +} + +init_recapture_zombie( zone_struct, s_spawn_point ) +{ + self endon( "death" ); + self.is_recapture_zombie = 1; + self init_zone_capture_zombie_common( s_spawn_point ); + self.goalradius = 30; + self.zombie_move_speed = "sprint"; + self.s_attack_generator = zone_struct; + self.attacking_new_generator = 1; + self.attacking_point = undefined; + self thread recapture_zombie_poi_think(); + while ( 1 ) + { + self.is_attacking_zone = 0; + if ( self.zombie_has_point_of_interest ) + { + v_attack_origin = self.point_of_interest; + } + else + { + if ( self.attacking_new_generator || !isDefined( self.attacking_point ) ) + { + if ( isDefined( self.attacking_point ) ) + { + self.attacking_point unclaim_attacking_point(); + } + self.attacking_point = self get_unclaimed_attack_point( self.s_attack_generator ); + } + v_attack_origin = self.attacking_point.origin; + } + self setgoalpos( v_attack_origin ); + self waittill_either( "goal", "poi_state_changed" ); + if ( !self.zombie_has_point_of_interest ) + { + while ( distance( self.attacking_point.origin, self.origin ) > 50 ) + { + continue; + } + self.is_attacking_zone = 1; + if ( !isDefined( level.zone_capture.recapture_target ) || !isDefined( self.s_attack_generator.script_noteworthy ) && isDefined( level.zone_capture.recapture_target ) && isDefined( self.s_attack_generator.script_noteworthy ) && level.zone_capture.recapture_target == self.s_attack_generator.script_noteworthy ) + { + flag_set( "generator_under_attack" ); + self.s_attack_generator ent_flag_set( "attacked_by_recapture_zombies" ); + self.attacking_new_generator = 0; + zone_struct notify( "zombies_attacking_generator" ); + } + } + else + { + if ( isDefined( self.attacking_point ) ) + { + self.attacking_point unclaim_attacking_point(); + } + } + self play_melee_attack_animation(); + } +} + +capture_zombie_rise_fx( ai_zombie ) +{ + playfx( level._effect[ "zone_capture_zombie_spawn" ], self.origin, anglesToForward( self.angles ), anglesToUp( self.angles ) ); +} + +get_unclaimed_attack_point( s_zone ) +{ + s_zone clean_up_unused_attack_points(); + n_claimed_center = s_zone get_claimed_attack_points_between_indicies( 0, 3 ); + n_claimed_left = s_zone get_claimed_attack_points_between_indicies( 4, 7 ); + n_claimed_right = s_zone get_claimed_attack_points_between_indicies( 8, 11 ); + b_use_center_pillar = n_claimed_center < 3; + b_use_left_pillar = n_claimed_left < 1; + b_use_right_pillar = n_claimed_right < 1; + if ( b_use_center_pillar ) + { + a_valid_attack_points = s_zone get_unclaimed_attack_points_between_indicies( 0, 3 ); + } + else if ( b_use_left_pillar ) + { + a_valid_attack_points = s_zone get_unclaimed_attack_points_between_indicies( 4, 7 ); + } + else if ( b_use_right_pillar ) + { + a_valid_attack_points = s_zone get_unclaimed_attack_points_between_indicies( 8, 11 ); + } + else + { + a_valid_attack_points = s_zone get_unclaimed_attack_points_between_indicies( 0, 11 ); + } + if ( a_valid_attack_points.size == 0 ) + { + a_valid_attack_points = s_zone get_unclaimed_attack_points_between_indicies( 0, 11 ); + } +/# + assert( a_valid_attack_points.size > 0, "get_unclaimed_attack_point() couldn't find any valid attack points in zone " + s_zone.script_noteworthy ); +#/ + s_attack_point = random( a_valid_attack_points ); + s_attack_point.is_claimed = 1; + s_attack_point.claimed_by = self; + return s_attack_point; +} + +clean_up_unused_attack_points() +{ + _a1472 = self.zombie_attack_points; + _k1472 = getFirstArrayKey( _a1472 ); + while ( isDefined( _k1472 ) ) + { + s_attack_point = _a1472[ _k1472 ]; + if ( s_attack_point.is_claimed && !isDefined( s_attack_point.claimed_by ) ) + { + s_attack_point.is_claimed = 0; + s_attack_point.claimed_by = undefined; + } + _k1472 = getNextArrayKey( _a1472, _k1472 ); + } +} + +get_unclaimed_attack_points_between_indicies( n_start, n_end ) +{ + a_valid_attack_points = []; + i = n_start; + while ( i < n_end ) + { + if ( !self.zombie_attack_points[ i ].is_claimed && !self.zombie_attack_points[ i ].inaccessible ) + { + a_valid_attack_points[ a_valid_attack_points.size ] = self.zombie_attack_points[ i ]; + } + i++; + } + return a_valid_attack_points; +} + +get_claimed_attack_points_between_indicies( n_start, n_end ) +{ + a_valid_points = []; + i = n_start; + while ( i < n_end ) + { + if ( self.zombie_attack_points[ i ].is_claimed ) + { + a_valid_points[ a_valid_points.size ] = self.zombie_attack_points[ i ]; + } + i++; + } + return a_valid_points.size; +} + +unclaim_attacking_point() +{ + self.is_claimed = 0; + self.claimed_by = undefined; +} + +clear_all_zombie_attack_points_in_zone() +{ + _a1523 = self.zombie_attack_points; + _k1523 = getFirstArrayKey( _a1523 ); + while ( isDefined( _k1523 ) ) + { + s_attack_point = _a1523[ _k1523 ]; + s_attack_point unclaim_attacking_point(); + _k1523 = getNextArrayKey( _a1523, _k1523 ); + } +} + +capture_zombies_only_attack_nearby_players( s_zone ) +{ + self endon( "death" ); + n_goal_radius = self.goalradius; + while ( 1 ) + { + self.goalradius = n_goal_radius; + while ( self should_capture_zombie_attack_generator( s_zone ) ) + { + self notify( "stop_find_flesh" ); + self notify( "zombie_acquire_enemy" ); + self.goalradius = 30; + if ( !isDefined( self.attacking_point ) ) + { + self.attacking_point = self get_unclaimed_attack_point( s_zone ); + } + self setgoalpos( self.attacking_point.origin ); + self thread cancel_generator_attack_if_player_gets_close_to_generator( s_zone ); + str_notify = self waittill_any_return( "goal", "stop_attacking_generator" ); + if ( !isDefined( str_notify ) || !isDefined( "stop_attacking_generator" ) && isDefined( str_notify ) && isDefined( "stop_attacking_generator" ) && str_notify == "stop_attacking_generator" ) + { + self.attacking_point unclaim_attacking_point(); + break; + } + else + { + self play_melee_attack_animation(); + } + } + wait 0,5; + } +} + +cancel_generator_attack_if_player_gets_close_to_generator( s_zone ) +{ + self notify( "generator_attack_cancel_think" ); + self endon( "generator_attack_cancel_think" ); + self endon( "death" ); + while ( 1 ) + { + if ( !self should_capture_zombie_attack_generator( s_zone ) ) + { + self notify( "stop_attacking_generator" ); + self thread maps/mp/zombies/_zm_ai_basic::find_flesh(); + return; + } + else + { + wait randomfloatrange( 0,2, 1,5 ); + } + } +} + +should_capture_zombie_attack_generator( s_zone ) +{ + a_players = get_players(); + a_valid_targets = arraysort( a_players, s_zone.origin, 1, undefined, 700 ); + _a1598 = a_players; + _k1598 = getFirstArrayKey( _a1598 ); + while ( isDefined( _k1598 ) ) + { + player = _a1598[ _k1598 ]; + if ( !isDefined( self.ignore_player ) ) + { + self.ignore_player = []; + } + if ( isinarray( a_valid_targets, player ) ) + { + b_is_valid_target = is_player_valid( player ); + } + b_is_currently_ignored = isinarray( self.ignore_player, player ); + if ( b_is_valid_target && b_is_currently_ignored ) + { + arrayremovevalue( self.ignore_player, player, 0 ); + } + else + { + if ( !b_is_valid_target && !b_is_currently_ignored ) + { + self.ignore_player[ self.ignore_player.size ] = player; + } + } + _k1598 = getNextArrayKey( _a1598, _k1598 ); + } + if ( isDefined( self.enemy ) ) + { + if ( a_valid_targets.size != 0 ) + { + b_should_attack_generator = self.ignore_player.size == a_players.size; + } + } + return b_should_attack_generator; +} + +play_melee_attack_animation() +{ + self endon( "death" ); + self endon( "poi_state_changed" ); + v_angles = self.angles; + if ( isDefined( self.attacking_point ) ) + { + v_angles = self.attacking_point.v_center_pillar - self.origin; + v_angles = vectorToAngle( ( v_angles[ 0 ], v_angles[ 1 ], 0 ) ); + } + self animscripted( self.origin, v_angles, "zm_generator_melee" ); + while ( 1 ) + { + self waittill( "static_melee_anim", note ); + if ( note == "end" ) + { + return; + } + else + { + } + } +} + +recapture_zombie_poi_think() +{ + self endon( "death" ); + self.zombie_has_point_of_interest = 0; + while ( isDefined( self ) && isalive( self ) ) + { + if ( isDefined( level._poi_override ) ) + { + zombie_poi = self [[ level._poi_override ]](); + } + if ( !isDefined( zombie_poi ) ) + { + zombie_poi = self get_zombie_point_of_interest( self.origin ); + } + self.using_poi_last_check = self.zombie_has_point_of_interest; + if ( isDefined( zombie_poi ) && isarray( zombie_poi ) && isDefined( zombie_poi[ 1 ] ) ) + { + self.goalradius = 16; + self.zombie_has_point_of_interest = 1; + self.is_attacking_zone = 0; + self.point_of_interest = zombie_poi[ 0 ]; + } + else + { + self.goalradius = 30; + self.zombie_has_point_of_interest = 0; + self.point_of_interest = undefined; + zombie_poi = undefined; + } + if ( self.using_poi_last_check != self.zombie_has_point_of_interest ) + { + self notify( "poi_state_changed" ); + self stopanimscripted( 0,2 ); + } + wait 1; + } +} + +kill_all_capture_zombies() +{ + while ( isDefined( self.capture_zombies ) && self.capture_zombies.size > 0 ) + { + _a1702 = self.capture_zombies; + _k1702 = getFirstArrayKey( _a1702 ); + while ( isDefined( _k1702 ) ) + { + zombie = _a1702[ _k1702 ]; + if ( isDefined( zombie ) && isalive( zombie ) ) + { + playfx( level._effect[ "tesla_elec_kill" ], zombie.origin ); + zombie dodamage( zombie.health + 100, zombie.origin ); + } + wait_network_frame(); + _k1702 = getNextArrayKey( _a1702, _k1702 ); + } + self.capture_zombies = array_removedead( self.capture_zombies ); + } + self.capture_zombies = []; +} + +kill_all_recapture_zombies() +{ + while ( isDefined( level.zone_capture.recapture_zombies ) && level.zone_capture.recapture_zombies.size > 0 ) + { + _a1726 = level.zone_capture.recapture_zombies; + _k1726 = getFirstArrayKey( _a1726 ); + while ( isDefined( _k1726 ) ) + { + zombie = _a1726[ _k1726 ]; + if ( isDefined( zombie ) && isalive( zombie ) ) + { + playfx( level._effect[ "tesla_elec_kill" ], zombie.origin ); + zombie dodamage( zombie.health + 100, zombie.origin ); + } + wait_network_frame(); + _k1726 = getNextArrayKey( _a1726, _k1726 ); + } + level.zone_capture.recapture_zombies = array_removedead( level.zone_capture.recapture_zombies ); + } + level.zone_capture.recapture_zombies = []; +} + +is_capture_area_occupied( parent_zone ) +{ + if ( parent_zone.is_occupied ) + { + return 1; + } + _a1754 = parent_zone.child_capture_zones; + _k1754 = getFirstArrayKey( _a1754 ); + while ( isDefined( _k1754 ) ) + { + s_child_zone = _a1754[ _k1754 ]; + if ( s_child_zone.is_occupied ) + { + return 1; + } + _k1754 = getNextArrayKey( _a1754, _k1754 ); + } + return 0; +} + +set_player_controlled_area() +{ + level.zone_capture.last_zone_captured = self; + self set_player_controlled_zone(); + self play_pap_anim( 1 ); +} + +update_captured_zone_count() +{ + level.total_capture_zones = get_captured_zone_count(); + if ( level.total_capture_zones == 6 ) + { + flag_set( "all_zones_captured" ); + } + else + { + flag_clear( "all_zones_captured" ); + } +} + +get_captured_zone_count() +{ + n_player_controlled_zones = 0; + _a1795 = level.zone_capture.zones; + _k1795 = getFirstArrayKey( _a1795 ); + while ( isDefined( _k1795 ) ) + { + generator = _a1795[ _k1795 ]; + if ( generator ent_flag( "player_controlled" ) ) + { + n_player_controlled_zones++; + } + _k1795 = getNextArrayKey( _a1795, _k1795 ); + } + return n_player_controlled_zones; +} + +get_contested_zone_count() +{ + return get_contested_zones().size; +} + +get_contested_zones() +{ + a_contested_zones = []; + _a1815 = level.zone_capture.zones; + _k1815 = getFirstArrayKey( _a1815 ); + while ( isDefined( _k1815 ) ) + { + generator = _a1815[ _k1815 ]; + if ( generator ent_flag( "zone_contested" ) ) + { + a_contested_zones[ a_contested_zones.size ] = generator; + } + _k1815 = getNextArrayKey( _a1815, _k1815 ); + } + return a_contested_zones; +} + +set_player_controlled_zone() +{ + self ent_flag_set( "player_controlled" ); + self ent_flag_clear( "attacked_by_recapture_zombies" ); + level setclientfield( "zone_capture_hud_generator_" + self.script_int, 1 ); + level setclientfield( "zone_capture_monolith_crystal_" + self.script_int, 0 ); + if ( !isDefined( self.perk_fx_func ) || [[ self.perk_fx_func ]]() ) + { + level setclientfield( "zone_capture_perk_machine_smoke_fx_" + self.script_int, 1 ); + } + self ent_flag_set( "player_controlled" ); + update_captured_zone_count(); + self enable_perk_machines_in_zone(); + self enable_random_perk_machines_in_zone(); + self enable_mystery_boxes_in_zone(); + level notify( "zone_captured_by_player" ); +} + +set_zombie_controlled_area( b_is_level_initializing ) +{ + if ( !isDefined( b_is_level_initializing ) ) + { + b_is_level_initializing = 0; + } + update_captured_zone_count(); + if ( b_is_level_initializing ) + { + level setclientfield( "state_" + self.script_noteworthy, 3 ); + wait_network_frame(); + level setclientfield( "state_" + self.script_noteworthy, 0 ); + } + if ( self ent_flag( "player_controlled" ) ) + { + flag_set( "generator_lost_to_recapture_zombies" ); + } + self set_zombie_controlled_zone( b_is_level_initializing ); + self play_pap_anim( 0 ); +} + +play_pap_anim( b_assemble ) +{ + level setclientfield( "packapunch_anim", get_captured_zone_count() ); +} + +set_zombie_controlled_zone( b_is_level_initializing ) +{ + if ( !isDefined( b_is_level_initializing ) ) + { + b_is_level_initializing = 0; + } + n_hud_state = 2; + if ( b_is_level_initializing ) + { + n_hud_state = 0; + } + self ent_flag_clear( "player_controlled" ); + level setclientfield( "zone_capture_hud_generator_" + self.script_int, n_hud_state ); + level setclientfield( "zone_capture_monolith_crystal_" + self.script_int, 1 ); + level setclientfield( "zone_capture_perk_machine_smoke_fx_" + self.script_int, 0 ); + update_captured_zone_count(); + self disable_perk_machines_in_zone(); + self disable_random_perk_machines_in_zone(); + self disable_mystery_boxes_in_zone(); +} + +capture_progress_think() +{ + self init_capture_progress(); + self clear_zone_objective_index(); + self show_zone_capture_objective( 1 ); + self get_zone_objective_index(); + while ( self ent_flag( "zone_contested" ) ) + { + a_players = get_players(); + a_players_in_capture_zone = self get_players_in_capture_zone(); + _a1930 = a_players; + _k1930 = getFirstArrayKey( _a1930 ); + while ( isDefined( _k1930 ) ) + { + player = _a1930[ _k1930 ]; + if ( isinarray( a_players_in_capture_zone, player ) ) + { + if ( !flag( "recapture_event_in_progress" ) || !self ent_flag( "current_recapture_target_zone" ) ) + { + objective_setplayerusing( self.n_objective_index, player ); + } + } + else + { + if ( is_player_valid( player ) ) + { + objective_clearplayerusing( self.n_objective_index, player ); + } + } + _k1930 = getNextArrayKey( _a1930, _k1930 ); + } + self.n_last_progress = self.n_current_progress; + self.n_current_progress += self get_progress_rate( a_players_in_capture_zone.size, a_players.size ); + if ( self.n_last_progress != self.n_current_progress ) + { + self.n_current_progress = clamp( self.n_current_progress, 0, 100 ); + objective_setprogress( self.n_objective_index, self.n_current_progress / 100 ); + self zone_capture_sound_state_think(); + level setclientfield( self.script_noteworthy, self.n_current_progress / 100 ); + self generator_set_state(); + if ( !flag( "recapture_event_in_progress" ) || !self ent_flag( "attacked_by_recapture_zombies" ) ) + { + b_set_color_to_white = a_players_in_capture_zone.size > 0; + if ( !flag( "recapture_event_in_progress" ) && self ent_flag( "current_recapture_target_zone" ) ) + { + b_set_color_to_white = 1; + } + level setclientfield( "zc_change_progress_bar_color", b_set_color_to_white ); + } + update_objective_on_momentum_change(); + if ( self.n_current_progress == 0 || self.n_current_progress == 100 && !self ent_flag( "attacked_by_recapture_zombies" ) ) + { + self ent_flag_clear( "zone_contested" ); + } + } + show_zone_capture_debug_info(); + wait 0,1; + } + self ent_flag_clear( "attacked_by_recapture_zombies" ); + self handle_generator_capture(); + self clear_all_zombie_attack_points_in_zone(); +} + +update_objective_on_momentum_change() +{ + if ( self ent_flag( "current_recapture_target_zone" ) && !flag( "recapture_event_in_progress" ) && self.n_objective_index == 1 && self.n_current_progress > self.n_last_progress ) + { + self clear_zone_objective_index(); + self show_zone_capture_objective( 1 ); + level setclientfield( "zc_change_progress_bar_color", 1 ); + } +} + +get_zone_objective_index() +{ + if ( !isDefined( self.n_objective_index ) ) + { + if ( self ent_flag( "current_recapture_target_zone" ) ) + { + if ( flag( "recapture_event_in_progress" ) ) + { + n_objective = 1; + } + else + { + n_objective = 2; + } + } + else + { + n_objective = 0; + } + self.n_objective_index = n_objective; + } + return self.n_objective_index; +} + +get_zones_using_objective_index( n_index ) +{ + n_zones_using_objective_index = 0; + _a2040 = level.zone_capture.zones; + _k2040 = getFirstArrayKey( _a2040 ); + while ( isDefined( _k2040 ) ) + { + zone = _a2040[ _k2040 ]; + if ( isDefined( zone.n_objective_index ) && zone.n_objective_index == n_index ) + { + n_zones_using_objective_index++; + } + _k2040 = getNextArrayKey( _a2040, _k2040 ); + } + return n_zones_using_objective_index; +} + +zone_capture_sound_state_think() +{ + if ( !isDefined( self.is_playing_audio ) ) + { + self.is_playing_audio = 0; + } + if ( self.n_current_progress > self.n_last_progress ) + { + if ( self.is_playing_audio ) + { + self.sndent stoploopsound(); + self.is_playing_audio = 0; + } + } + else + { + if ( !self.is_playing_audio && flag( "generator_under_attack" ) ) + { + self.sndent playloopsound( "zmb_capturezone_generator_alarm", 0,25 ); + self.is_playing_audio = 1; + } + } +} + +handle_generator_capture() +{ + level setclientfield( "zc_change_progress_bar_color", 0 ); + self show_zone_capture_objective( 0 ); + if ( self.n_current_progress == 100 ) + { + self players_capture_zone(); + self kill_all_capture_zombies(); + } + else if ( self.n_current_progress == 0 ) + { + while ( self ent_flag( "player_controlled" ) ) + { + self.sndent stoploopsound( 0,25 ); + self thread generator_deactivated_vo(); + self.is_playing_audio = 0; + _a2095 = get_players(); + _k2095 = getFirstArrayKey( _a2095 ); + while ( isDefined( _k2095 ) ) + { + player = _a2095[ _k2095 ]; + player maps/mp/zombies/_zm_stats::increment_client_stat( "tomb_generator_lost", 0 ); + player maps/mp/zombies/_zm_stats::increment_player_stat( "tomb_generator_lost" ); + _k2095 = getNextArrayKey( _a2095, _k2095 ); + } + } + self set_zombie_controlled_area(); + if ( flag( "recapture_event_in_progress" ) && get_captured_zone_count() > 0 ) + { + } + else + { + self kill_all_capture_zombies(); + } + } + if ( get_contested_zone_count() == 0 ) + { + flag_clear( "zone_capture_in_progress" ); + } +} + +init_capture_progress() +{ + if ( !isDefined( level.zone_capture.rate_capture ) ) + { + level.zone_capture.rate_capture = get_update_rate( 10 ); + } + if ( !isDefined( level.zone_capture.rate_capture_solo ) ) + { + level.zone_capture.rate_capture_solo = get_update_rate( 12 ); + } + if ( !isDefined( level.zone_capture.rate_decay ) ) + { + level.zone_capture.rate_decay = get_update_rate( 20 ) * -1; + } + if ( !isDefined( level.zone_capture.rate_recapture ) ) + { + level.zone_capture.rate_recapture = get_update_rate( 40 ) * -1; + } + if ( !isDefined( level.zone_capture.rate_recapture_players ) ) + { + level.zone_capture.rate_recapture_players = get_update_rate( 10 ); + } + if ( !self ent_flag( "player_controlled" ) ) + { + self.n_current_progress = 0; + self ent_flag_clear( "attacked_by_recapture_zombies" ); + } + self ent_flag_set( "zone_contested" ); +} + +get_progress_rate( n_players_in_zone, n_players_total ) +{ + if ( flag( "recapture_event_in_progress" ) && self ent_flag( "current_recapture_target_zone" ) ) + { + if ( self get_recapture_attacker_count() > 0 ) + { + n_rate = level.zone_capture.rate_recapture; + } + else if ( !self ent_flag( "attacked_by_recapture_zombies" ) ) + { + n_rate = 0; + } + else + { + n_rate = level.zone_capture.rate_recapture_players; + } + } + else + { + if ( self ent_flag( "current_recapture_target_zone" ) ) + { + n_rate = level.zone_capture.rate_recapture_players; + } + else if ( n_players_in_zone > 0 ) + { + if ( isDefined( level.is_forever_solo_game ) && level.is_forever_solo_game ) + { + n_rate = level.zone_capture.rate_capture_solo; + } + else + { + n_rate = level.zone_capture.rate_capture * ( n_players_in_zone / n_players_total ); + } + } + else + { + n_rate = level.zone_capture.rate_decay; + } + } + return n_rate; +} + +show_zone_capture_objective( b_show_objective ) +{ + self get_zone_objective_index(); + if ( b_show_objective ) + { + objective_position( self.n_objective_index, self.origin ); + objective_setgamemodeflags( self.n_objective_index, self.script_int ); + objective_state( self.n_objective_index, "active" ); + } + else + { + self clear_zone_objective_index(); + } +} + +clear_zone_objective_index() +{ + while ( isDefined( self.n_objective_index ) && get_zones_using_objective_index( self.n_objective_index ) < 2 ) + { + objective_state( self.n_objective_index, "invisible" ); + a_players = get_players(); + _a2205 = a_players; + _k2205 = getFirstArrayKey( _a2205 ); + while ( isDefined( _k2205 ) ) + { + player = _a2205[ _k2205 ]; + objective_clearplayerusing( self.n_objective_index, player ); + _k2205 = getNextArrayKey( _a2205, _k2205 ); + } + } + self.n_objective_index = undefined; +} + +hide_zone_objective_while_recapture_group_runs_to_next_generator( b_hide_icon ) +{ + self clear_zone_objective_index(); + flag_clear( "generator_under_attack" ); + if ( !b_hide_icon ) + { + recapture_zombie_group_icon_show(); + } + wait 1; + if ( !flag( "recapture_zombies_cleared" ) && !flag( "recapture_zombies_cleared" ) ) + { + self thread generator_compromised_vo(); + } +} + +recapture_zombie_group_icon_show() +{ + level endon( "recapture_zombies_cleared" ); + if ( isDefined( level.zone_capture.recapture_zombies ) && flag( "recapture_event_in_progress" ) ) + { + while ( !level.zone_capture.recapture_zombies.size ) + { + wait_network_frame(); + level.zone_capture.recapture_zombies = array_removedead( level.zone_capture.recapture_zombies ); + } + flag_waitopen( "generator_under_attack" ); + if ( level.zone_capture.recapture_zombies.size > 0 ) + { + ai_zombie = random( level.zone_capture.recapture_zombies ); + objective_state( 3, "active" ); + objective_onentity( 3, ai_zombie ); + ai_zombie thread recapture_zombie_icon_think(); + } + } +} + +recapture_zombie_icon_think() +{ + while ( isalive( self ) && !flag( "generator_under_attack" ) ) + { +/# + debugstar( self.origin, 20, ( 0, 0, 1 ) ); +#/ + wait 1; + } + recapture_zombie_group_icon_hide(); + wait_network_frame(); + if ( !flag( "recapture_zombies_cleared" ) ) + { + recapture_zombie_group_icon_show(); + } +} + +recapture_zombie_group_icon_hide() +{ + objective_state( 3, "invisible" ); + if ( isalive( self ) ) + { + objective_clearentity( 3 ); + } +} + +players_capture_zone() +{ + self.sndent playsound( "zmb_capturezone_success" ); + self.sndent stoploopsound( 0,25 ); + wait_network_frame(); + if ( !flag( "recapture_event_in_progress" ) && !self ent_flag( "player_controlled" ) ) + { + self thread zone_capture_complete_vo(); + } + reward_players_in_capture_zone(); + self set_player_controlled_area(); + wait_network_frame(); + playfx( level._effect[ "capture_complete" ], self.origin ); + level thread sndplaygeneratormusicstinger(); +} + +reward_players_in_capture_zone() +{ + b_challenge_exists = maps/mp/zombies/_zm_challenges::challenge_exists( "zc_zone_captures" ); + while ( !self ent_flag( "player_controlled" ) ) + { + _a2321 = get_players_in_capture_zone(); + _k2321 = getFirstArrayKey( _a2321 ); + while ( isDefined( _k2321 ) ) + { + player = _a2321[ _k2321 ]; + player notify( "completed_zone_capture" ); + player maps/mp/zombies/_zm_score::player_add_points( "bonus_points_powerup", 100 ); + if ( b_challenge_exists ) + { + player maps/mp/zombies/_zm_challenges::increment_stat( "zc_zone_captures" ); + } + player maps/mp/zombies/_zm_stats::increment_client_stat( "tomb_generator_captured", 0 ); + player maps/mp/zombies/_zm_stats::increment_player_stat( "tomb_generator_captured" ); + _k2321 = getNextArrayKey( _a2321, _k2321 ); + } + } +} + +show_zone_capture_debug_info() +{ +/# + while ( getDvarInt( #"1AD074DA" ) > 0 ) + { + print3d( self.origin, "progress = " + self.n_current_progress, ( 0, 0, 1 ) ); + circle( groundtrace( self.origin, self.origin - vectorScale( ( 0, 0, 1 ), 1000 ), 0, undefined )[ "position" ], 220, ( 0, 0, 1 ), 0, 4 ); + _a2349 = self.zombie_attack_points; + n_index = getFirstArrayKey( _a2349 ); + while ( isDefined( n_index ) ) + { + attack_point = _a2349[ n_index ]; + if ( attack_point.inaccessible ) + { + v_color = ( 0, 0, 1 ); + } + else if ( attack_point.is_claimed ) + { + v_color = ( 0, 0, 1 ); + } + else + { + v_color = ( 0, 0, 1 ); + } + debugstar( attack_point.origin, 4, v_color ); + print3d( attack_point.origin + vectorScale( ( 0, 0, 1 ), 10 ), n_index, v_color, 1, 1, 4 ); + n_index = getNextArrayKey( _a2349, n_index ); +#/ + } + } +} + +get_players_in_capture_zone() +{ + a_players_in_capture_zone = []; + _a2376 = get_players(); + _k2376 = getFirstArrayKey( _a2376 ); + while ( isDefined( _k2376 ) ) + { + player = _a2376[ _k2376 ]; + if ( is_player_valid( player ) && distance2dsquared( player.origin, self.origin ) < 48400 && player.origin[ 2 ] > ( self.origin[ 2 ] + -20 ) ) + { + a_players_in_capture_zone[ a_players_in_capture_zone.size ] = player; + } + _k2376 = getNextArrayKey( _a2376, _k2376 ); + } + return a_players_in_capture_zone; +} + +get_update_rate( n_duration ) +{ + n_change_per_update = ( 100 / n_duration ) * 0,1; + return n_change_per_update; +} + +generator_set_state() +{ + n_generator_state = level getclientfield( "state_" + self.script_noteworthy ); + if ( self.n_current_progress == 0 ) + { + self generator_state_turn_off(); + } + else if ( n_generator_state == 0 && self.n_current_progress > 0 ) + { + self generator_state_turn_on(); + } + else + { + if ( self can_start_generator_power_up_anim() ) + { + self generator_state_power_up(); + return; + } + else + { + if ( n_generator_state == 2 && self.n_current_progress < self.n_last_progress ) + { + self generator_state_power_down(); + if ( !flag( "recapture_event_in_progress" ) ) + { + self thread generator_interrupted_vo(); + } + } + } + } +} + +generator_state_turn_on() +{ + level setclientfield( "state_" + self.script_noteworthy, 1 ); + self.n_time_started_generator = getTime(); +} + +generator_state_power_up() +{ + level setclientfield( "state_" + self.script_noteworthy, 2 ); +} + +generator_state_power_down() +{ + if ( self ent_flag( "attacked_by_recapture_zombies" ) ) + { + n_state = 5; + } + else + { + n_state = 3; + } + level setclientfield( "state_" + self.script_noteworthy, n_state ); +} + +generator_state_turn_off() +{ + level setclientfield( "state_" + self.script_noteworthy, 4 ); + self thread generator_turns_off_after_anim(); +} + +generator_turns_off_after_anim() +{ + wait getanimlength( %fxanim_zom_tomb_generator_end_anim ); + self generator_state_off(); +} + +generator_state_off() +{ + level setclientfield( "state_" + self.script_noteworthy, 0 ); +} + +can_start_generator_power_up_anim() +{ + if ( !isDefined( self.n_time_started_generator ) ) + { + self.n_time_started_generator = 0; + } + if ( !isDefined( self.n_time_start_anim ) ) + { + self.n_time_start_anim = getanimlength( %fxanim_zom_tomb_generator_start_anim ); + } + if ( self.n_current_progress > self.n_last_progress ) + { + return ( ( getTime() - self.n_time_started_generator ) * 0,001 ) > self.n_time_start_anim; + } +} + +get_recapture_attacker_count() +{ + n_zone_attacker_count = 0; + _a2475 = level.zone_capture.recapture_zombies; + _k2475 = getFirstArrayKey( _a2475 ); + while ( isDefined( _k2475 ) ) + { + zombie = _a2475[ _k2475 ]; + if ( isalive( zombie ) && isDefined( zombie.is_attacking_zone ) && zombie.is_attacking_zone && !isDefined( self.script_noteworthy ) || !isDefined( level.zone_capture.recapture_target ) && isDefined( self.script_noteworthy ) && isDefined( level.zone_capture.recapture_target ) && self.script_noteworthy == level.zone_capture.recapture_target ) + { + n_zone_attacker_count++; + } + _k2475 = getNextArrayKey( _a2475, _k2475 ); + } + return n_zone_attacker_count; +} + +watch_for_open_sesame() +{ +/# + level waittill( "open_sesame" ); + level.b_open_sesame = 1; + a_generators = getstructarray( "s_generator", "targetname" ); + _a2495 = a_generators; + _k2495 = getFirstArrayKey( _a2495 ); + while ( isDefined( _k2495 ) ) + { + s_generator = _a2495[ _k2495 ]; + s_temp = level.zone_capture.zones[ s_generator.script_noteworthy ]; + s_temp debug_set_generator_active(); + wait_network_frame(); + _k2495 = getNextArrayKey( _a2495, _k2495 ); +#/ + } +} + +debug_watch_for_zone_capture() +{ +/# + while ( 1 ) + { + level waittill( "force_zone_capture", n_zone ); + _a2510 = level.zone_capture.zones; + _k2510 = getFirstArrayKey( _a2510 ); + while ( isDefined( _k2510 ) ) + { + zone = _a2510[ _k2510 ]; + if ( zone.script_int == n_zone && !zone ent_flag( "player_controlled" ) ) + { + zone debug_set_generator_active(); + } + _k2510 = getNextArrayKey( _a2510, _k2510 ); + } +#/ + } +} + +debug_watch_for_zone_recapture() +{ +/# + while ( 1 ) + { + level waittill( "force_zone_recapture", n_zone ); + _a2526 = level.zone_capture.zones; + _k2526 = getFirstArrayKey( _a2526 ); + while ( isDefined( _k2526 ) ) + { + zone = _a2526[ _k2526 ]; + if ( zone.script_int == n_zone && zone ent_flag( "player_controlled" ) ) + { + zone debug_set_generator_inactive(); + } + _k2526 = getNextArrayKey( _a2526, _k2526 ); + } +#/ + } +} + +debug_set_generator_active() +{ +/# + self set_player_controlled_area(); + self.n_current_progress = 100; + self generator_state_power_up(); + level setclientfield( self.script_noteworthy, self.n_current_progress / 100 ); +#/ +} + +debug_set_generator_inactive() +{ +/# + self set_zombie_controlled_area(); + self.n_current_progress = 0; + self generator_state_turn_off(); + level setclientfield( self.script_noteworthy, self.n_current_progress / 100 ); +#/ +} + +set_magic_box_zbarrier_state( state ) +{ + i = 0; + while ( i < self getnumzbarrierpieces() ) + { + self hidezbarrierpiece( i ); + i++; + } + self notify( "zbarrier_state_change" ); + switch( state ) + { + case "away": + self showzbarrierpiece( 0 ); + self.state = "away"; + self.owner.is_locked = 0; + break; + case "arriving": + self showzbarrierpiece( 1 ); + self thread magic_box_arrives(); + self.state = "arriving"; + break; + case "initial": + self showzbarrierpiece( 1 ); + self thread magic_box_initial(); + thread maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( self.owner.unitrigger_stub, ::maps/mp/zombies/_zm_magicbox::magicbox_unitrigger_think ); + self.state = "close"; + break; + case "open": + self showzbarrierpiece( 2 ); + self thread maps/mp/zombies/_zm_magicbox_tomb::magic_box_opens(); + self.state = "open"; + break; + case "close": + self showzbarrierpiece( 2 ); + self thread maps/mp/zombies/_zm_magicbox_tomb::magic_box_closes(); + self.state = "close"; + break; + case "leaving": + self showzbarrierpiece( 1 ); + self thread magic_box_leaves(); + self.state = "leaving"; + self.owner.is_locked = 0; + break; + case "zombie_controlled": + if ( isDefined( level.zombie_vars[ "zombie_powerup_fire_sale_on" ] ) && level.zombie_vars[ "zombie_powerup_fire_sale_on" ] ) + { + self showzbarrierpiece( 2 ); + self setclientfield( "magicbox_amb_fx", 0 ); + } + if ( self.state == "initial" || self.state == "close" ) + { + self showzbarrierpiece( 1 ); + self setclientfield( "magicbox_amb_fx", 1 ); + } + else + { + if ( self.state == "away" ) + { + self showzbarrierpiece( 0 ); + self setclientfield( "magicbox_amb_fx", 0 ); + } + else + { + if ( self.state == "open" || self.state == "leaving" ) + { + self showzbarrierpiece( 2 ); + self setclientfield( "magicbox_amb_fx", 0 ); + } + } + } + break; + case "player_controlled": + if ( self.state == "arriving" || self.state == "close" ) + { + self showzbarrierpiece( 2 ); + self setclientfield( "magicbox_amb_fx", 2 ); + break; + } + else + { + if ( self.state == "away" ) + { + self showzbarrierpiece( 0 ); + self setclientfield( "magicbox_amb_fx", 3 ); + } + break; + return; + default: + if ( isDefined( level.custom_magicbox_state_handler ) ) + { + self [[ level.custom_magicbox_state_handler ]]( state ); + } + break; + return; + } +} +} + +magic_box_trigger_update_prompt( player ) +{ + can_use = self magic_box_stub_update_prompt( player ); + if ( isDefined( self.stub.hint_string ) ) + { + if ( isDefined( self.stub.hint_parm1 ) ) + { + self sethintstring( self.stub.hint_string, self.stub.hint_parm1 ); + } + else + { + self sethintstring( self.stub.hint_string ); + } + } + return can_use; +} + +magic_box_stub_update_prompt( player ) +{ + self setcursorhint( "HINT_NOICON" ); + if ( !self trigger_visible_to_player( player ) ) + { + return 0; + } + self.stub.hint_parm1 = undefined; + if ( isDefined( self.stub.trigger_target.grab_weapon_hint ) && self.stub.trigger_target.grab_weapon_hint ) + { + self.stub.hint_string = &"ZOMBIE_TRADE_WEAPONS"; + } + else + { + if ( !level.zone_capture.zones[ self.stub.zone ] ent_flag( "player_controlled" ) ) + { + self.stub.hint_string = &"ZM_TOMB_ZC"; + return 0; + } + else + { + self.stub.hint_parm1 = self.stub.trigger_target.zombie_cost; + self.stub.hint_string = get_hint_string( self, "default_treasure_chest" ); + } + } + return 1; +} + +recapture_round_tracker() +{ + n_next_recapture_round = 10; + while ( 1 ) + { +/# + iprintln( "Next Recapture Round = " + n_next_recapture_round ); +#/ + level waittill_any( "between_round_over", "force_recapture_start" ); +/# + if ( getDvarInt( #"EF89C4FC" ) > 0 ) + { + n_next_recapture_round = level.round_number; +#/ + } + if ( level.round_number >= n_next_recapture_round && !flag( "zone_capture_in_progress" ) && get_captured_zone_count() >= get_player_controlled_zone_count_for_recapture() ) + { + n_next_recapture_round = level.round_number + randomintrange( 3, 6 ); + level thread recapture_round_start(); + } + } +} + +get_player_controlled_zone_count_for_recapture() +{ + n_zones_required = 4; +/# + if ( getDvarInt( #"EF89C4FC" ) > 0 ) + { + n_zones_required = 1; +#/ + } + return n_zones_required; +} + +get_recapture_zone( s_last_recapture_zone ) +{ + a_s_player_zones = []; + _a2770 = level.zone_capture.zones; + str_key = getFirstArrayKey( _a2770 ); + while ( isDefined( str_key ) ) + { + s_zone = _a2770[ str_key ]; + if ( s_zone ent_flag( "player_controlled" ) ) + { + a_s_player_zones[ str_key ] = s_zone; + } + str_key = getNextArrayKey( _a2770, str_key ); + } + s_recapture_zone = undefined; + while ( a_s_player_zones.size ) + { + if ( isDefined( s_last_recapture_zone ) ) + { + n_distance_closest = undefined; + _a2788 = a_s_player_zones; + _k2788 = getFirstArrayKey( _a2788 ); + while ( isDefined( _k2788 ) ) + { + s_zone = _a2788[ _k2788 ]; + n_distance = distancesquared( s_zone.origin, s_last_recapture_zone.origin ); + if ( !isDefined( n_distance_closest ) || n_distance < n_distance_closest ) + { + s_recapture_zone = s_zone; + n_distance_closest = n_distance; + } + _k2788 = getNextArrayKey( _a2788, _k2788 ); + } + } + else s_recapture_zone = random( a_s_player_zones ); +/# + while ( getDvarInt( #"8178CABA" ) > 0 ) + { + n_zone = getDvarInt( #"8178CABA" ); + _a2808 = level.zone_capture.zones; + _k2808 = getFirstArrayKey( _a2808 ); + while ( isDefined( _k2808 ) ) + { + zone = _a2808[ _k2808 ]; + if ( n_zone == zone.script_int && zone ent_flag( "player_controlled" ) ) + { + s_recapture_zone = zone; + break; + } + else + { + _k2808 = getNextArrayKey( _a2808, _k2808 ); +#/ + } + } + } + } + return s_recapture_zone; +} + +recapture_round_start() +{ + flag_set( "recapture_event_in_progress" ); + flag_clear( "recapture_zombies_cleared" ); + flag_clear( "generator_under_attack" ); + level.recapture_zombies_killed = 0; + b_is_first_generator_attack = 1; + s_recapture_target_zone = undefined; + capture_event_handle_ai_limit(); + recapture_round_audio_starts(); + while ( !flag( "recapture_zombies_cleared" ) && get_captured_zone_count() > 0 ) + { + s_recapture_target_zone = get_recapture_zone( s_recapture_target_zone ); + level.zone_capture.recapture_target = s_recapture_target_zone.script_noteworthy; + s_recapture_target_zone maps/mp/zm_tomb_capture_zones_ffotd::recapture_event_start(); + if ( b_is_first_generator_attack ) + { + s_recapture_target_zone thread monitor_recapture_zombies(); + } + set_recapture_zombie_attack_target( s_recapture_target_zone ); + s_recapture_target_zone thread generator_under_attack_warnings(); + s_recapture_target_zone ent_flag_set( "current_recapture_target_zone" ); + s_recapture_target_zone thread hide_zone_objective_while_recapture_group_runs_to_next_generator( b_is_first_generator_attack ); + s_recapture_target_zone activate_capture_zone( b_is_first_generator_attack ); + s_recapture_target_zone ent_flag_clear( "attacked_by_recapture_zombies" ); + s_recapture_target_zone ent_flag_clear( "current_recapture_target_zone" ); + if ( b_is_first_generator_attack && !s_recapture_target_zone ent_flag( "player_controlled" ) ) + { + delay_thread( 3, ::broadcast_vo_category_to_team, "recapture_started" ); + } + b_is_first_generator_attack = 0; + s_recapture_target_zone maps/mp/zm_tomb_capture_zones_ffotd::recapture_event_end(); + wait 0,05; + } + if ( s_recapture_target_zone.n_current_progress == 0 || s_recapture_target_zone.n_current_progress == 100 ) + { + s_recapture_target_zone handle_generator_capture(); + } + capture_event_handle_ai_limit(); + kill_all_recapture_zombies(); + recapture_round_audio_ends(); + flag_clear( "recapture_event_in_progress" ); + flag_clear( "generator_under_attack" ); +} + +broadcast_vo_category_to_team( str_category, n_delay ) +{ + if ( !isDefined( n_delay ) ) + { + n_delay = 1; + } + a_players = get_players(); + a_speakers = []; + e_speaker = get_random_speaker( a_players ); + a_speakers[ a_speakers.size ] = e_speaker; + arrayremovevalue( a_players, e_speaker ); + a_players = e_speaker get_players_too_far_to_hear( a_players ); + i = 0; + while ( i < a_speakers.size ) + { + a_speakers[ i ] delay_thread( n_delay, ::create_and_play_dialog, "zone_capture", str_category ); + i++; + } +} + +get_players_too_far_to_hear( a_players ) +{ + a_distant = []; + _a2921 = a_players; + _k2921 = getFirstArrayKey( _a2921 ); + while ( isDefined( _k2921 ) ) + { + player = _a2921[ _k2921 ]; + if ( distancesquared( player.origin, self.origin ) > 640000 && is_player_valid( player ) && !player isplayeronsamemachine( self ) ) + { + a_distant[ a_distant.size ] = player; + } + _k2921 = getNextArrayKey( _a2921, _k2921 ); + } + return a_distant; +} + +get_random_speaker( a_players ) +{ + if ( !isDefined( a_players ) ) + { + a_players = get_players(); + } + a_valid_players = []; + _a2942 = a_players; + _k2942 = getFirstArrayKey( _a2942 ); + while ( isDefined( _k2942 ) ) + { + player = _a2942[ _k2942 ]; + if ( is_player_valid( player ) ) + { + a_valid_players[ a_valid_players.size ] = player; + } + _k2942 = getNextArrayKey( _a2942, _k2942 ); + } + return random( a_valid_players ); +} + +set_recapture_zombie_attack_target( s_recapture_target_zone ) +{ + flag_clear( "generator_under_attack" ); + s_recapture_target_zone ent_flag_clear( "attacked_by_recapture_zombies" ); + _a2958 = level.zone_capture.recapture_zombies; + _k2958 = getFirstArrayKey( _a2958 ); + while ( isDefined( _k2958 ) ) + { + zombie = _a2958[ _k2958 ]; + zombie.is_attacking_zone = 0; + zombie.s_attack_generator = s_recapture_target_zone; + zombie.attacking_new_generator = 1; + _k2958 = getNextArrayKey( _a2958, _k2958 ); + } +} + +sndrecaptureroundloop() +{ + level endon( "sndEndRoundLoop" ); + wait 5; + ent = spawn( "script_origin", ( 0, 0, 1 ) ); + ent playloopsound( "mus_recapture_round_loop", 5 ); + ent thread sndrecaptureroundloop_stop(); +} + +sndrecaptureroundloop_stop() +{ + flag_wait( "recapture_zombies_cleared" ); + self stoploopsound( 2 ); + wait 2; + self delete(); +} + +monitor_recapture_zombie_count() +{ + while ( 1 ) + { + level.zone_capture.recapture_zombies = array_removedead( level.zone_capture.recapture_zombies ); + if ( level.zone_capture.recapture_zombies.size == 0 ) + { + flag_set( "recapture_zombies_cleared" ); + flag_clear( "recapture_event_in_progress" ); + flag_clear( "generator_under_attack" ); + if ( isDefined( level.zone_capture.recapture_target ) ) + { + level.zone_capture.zones[ level.zone_capture.recapture_target ] ent_flag_clear( "attacked_by_recapture_zombies" ); + level.zone_capture.recapture_target = undefined; + } + return; + } + else + { + wait 1; + } + } +} + +recapture_zombie_death_func() +{ + if ( isDefined( self.is_recapture_zombie ) && self.is_recapture_zombie ) + { + level.recapture_zombies_killed++; + while ( isDefined( self.attacker ) && isplayer( self.attacker ) && level.recapture_zombies_killed == get_recapture_zombies_needed() ) + { + self.attacker thread delay_thread( 2, ::create_and_play_dialog, "zone_capture", "recapture_prevented" ); + _a3017 = get_players(); + _k3017 = getFirstArrayKey( _a3017 ); + while ( isDefined( _k3017 ) ) + { + player = _a3017[ _k3017 ]; + player maps/mp/zombies/_zm_stats::increment_client_stat( "tomb_generator_defended", 0 ); + player maps/mp/zombies/_zm_stats::increment_player_stat( "tomb_generator_defended" ); + _k3017 = getNextArrayKey( _a3017, _k3017 ); + } + } + if ( level.recapture_zombies_killed == get_recapture_zombies_needed() && flag( "generator_under_attack" ) ) + { + self drop_max_ammo_at_death_location(); + } + } +} + +drop_max_ammo_at_death_location() +{ + if ( isDefined( self ) ) + { + v_powerup_origin = groundtrace( self.origin + vectorScale( ( 0, 0, 1 ), 10 ), self.origin + vectorScale( ( 0, 0, 1 ), 150 ), 0, undefined, 1 )[ "position" ]; + } + if ( isDefined( v_powerup_origin ) ) + { + level thread maps/mp/zombies/_zm_powerups::specific_powerup_drop( "full_ammo", v_powerup_origin ); + } +} + +generator_under_attack_warnings() +{ + flag_wait_any( "generator_under_attack", "recapture_zombies_cleared" ); + if ( !flag( "recapture_zombies_cleared" ) ) + { + e_alarm_sound = spawn( "script_origin", self.origin ); + e_alarm_sound playloopsound( "zmb_capturezone_losing" ); + e_alarm_sound thread play_flare_effect(); + wait 0,5; + flag_waitopen( "generator_under_attack" ); + e_alarm_sound stoploopsound( 0,2 ); + wait 0,5; + e_alarm_sound delete(); + } +} + +play_flare_effect() +{ + self endon( "death" ); + n_end_time = getTime() + 5000; + while ( flag( "generator_under_attack" ) ) + { + playfx( level._effect[ "lght_marker_flare" ], self.origin ); + wait 4; + } +} + +recapture_round_audio_starts() +{ + level.music_round_override = 1; + level thread maps/mp/zombies/_zm_audio::change_zombie_music( "dog_start" ); + level thread sndrecaptureroundloop(); +} + +recapture_round_audio_ends() +{ + level thread maps/mp/zombies/_zm_audio::change_zombie_music( "dog_end" ); + level.music_round_override = 0; + level notify( "sndEndRoundLoop" ); +} + +custom_vending_power_on() +{ +} + +custom_vending_power_off() +{ +} + +generator_initiated_vo() +{ + e_vo_origin = spawn( "script_origin", self.origin ); + level.maxis_generator_vo = 1; + e_vo_origin playsoundwithnotify( "vox_maxi_generator_initiate_0", "vox_maxi_generator_initiate_0_done" ); + e_vo_origin waittill( "vox_maxi_generator_initiate_0_done" ); + level.maxis_generator_vo = 0; + e_vo_origin delete(); +} + +zone_capture_complete_vo() +{ + e_vo_origin = spawn( "script_origin", self.origin ); + e_vo_origin playsoundwithnotify( "vox_maxi_generator_process_complete_0", "vox_maxi_generator_process_complete_0_done" ); + e_vo_origin waittill( "vox_maxi_generator_process_complete_0_done" ); + e_vo_origin playsoundwithnotify( "vox_maxi_generator_" + self.script_int + "_activated_0", "vox_maxi_generator_" + self.script_int + "_activated_0_done" ); + e_vo_origin waittill( "vox_maxi_generator_" + self.script_int + "_activated_0_done" ); + e_vo_origin delete(); +} + +generator_interrupted_vo() +{ + e_vo_origin = spawn( "script_origin", self.origin ); + e_vo_origin playsoundwithnotify( "vox_maxi_generator_interrupted_0", "vox_maxi_generator_interrupted_0_done" ); + e_vo_origin waittill( "vox_maxi_generator_interrupted_0_done" ); + e_vo_origin delete(); +} + +generator_compromised_vo() +{ + e_vo_origin = spawn( "script_origin", self.origin ); + e_vo_origin playsoundwithnotify( "vox_maxi_generator_" + self.script_int + "_compromised_0", "vox_maxi_generator_" + self.script_int + "_compromised_0_done" ); + e_vo_origin waittill( "vox_maxi_generator_" + self.script_int + "_compromised_0_done" ); + e_vo_origin delete(); +} + +generator_deactivated_vo() +{ + e_vo_origin = spawn( "script_origin", self.origin ); + e_vo_origin playsoundwithnotify( "vox_maxi_generator_" + self.script_int + "_deactivated_0", "vox_maxi_generator_" + self.script_int + "_deactivated_0_done" ); + e_vo_origin waittill( "vox_maxi_generator_" + self.script_int + "_deactivated_0_done" ); + e_vo_origin delete(); +} + +sndplaygeneratormusicstinger() +{ + num = get_captured_zone_count(); + level thread maps/mp/zombies/_zm_audio::sndmusicstingerevent( "generator_" + num ); +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_capture_zones_ffotd.gsc b/zm_tomb_patch/maps/mp/zm_tomb_capture_zones_ffotd.gsc new file mode 100644 index 0000000..4cb312d --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_capture_zones_ffotd.gsc @@ -0,0 +1,27 @@ +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +capture_zone_init_start() +{ +} + +capture_zone_init_end() +{ +} + +capture_event_start() +{ +} + +capture_event_end() +{ +} + +recapture_event_start() +{ +} + +recapture_event_end() +{ +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_challenges.gsc b/zm_tomb_patch/maps/mp/zm_tomb_challenges.gsc new file mode 100644 index 0000000..dabf5c9 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_challenges.gsc @@ -0,0 +1,383 @@ +#include maps/mp/zombies/_zm_weap_one_inch_punch; +#include maps/mp/zombies/_zm_perks; +#include maps/mp/zombies/_zm_powerup_zombie_blood; +#include maps/mp/zombies/_zm_audio_announcer; +#include maps/mp/zombies/_zm_powerups; +#include maps/mp/zombies/_zm_weapons; +#include raw/maps/mp/_zm_challenges; +#include maps/mp/zm_tomb_vo; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +#using_animtree( "fxanim_props_dlc4" ); + +challenges_init() +{ + level.challenges_add_stats = ::tomb_challenges_add_stats; + maps/mp/zombies/_zm_challenges::init(); +} + +tomb_challenges_add_stats() +{ + n_kills = 115; + n_zone_caps = 6; + n_points_spent = 30000; + n_boxes_filled = 4; +/# + if ( getDvarInt( "zombie_cheat" ) > 0 ) + { + n_kills = 1; + n_zone_caps = 2; + n_points_spent = 500; + n_boxes_filled = 1; +#/ + } + add_stat( "zc_headshots", 0, &"ZM_TOMB_CH1", n_kills, undefined, ::reward_packed_weapon ); + add_stat( "zc_zone_captures", 0, &"ZM_TOMB_CH2", n_zone_caps, undefined, ::reward_powerup_max_ammo ); + add_stat( "zc_points_spent", 0, &"ZM_TOMB_CH3", n_points_spent, undefined, ::reward_double_tap, ::track_points_spent ); + add_stat( "zc_boxes_filled", 1, &"ZM_TOMB_CHT", n_boxes_filled, undefined, ::reward_one_inch_punch, ::init_box_footprints ); +} + +track_points_spent() +{ + while ( 1 ) + { + level waittill( "spent_points", player, points ); + player increment_stat( "zc_points_spent", points ); + } +} + +init_box_footprints() +{ + level.n_soul_boxes_completed = 0; + flag_init( "vo_soul_box_intro_played" ); + flag_init( "vo_soul_box_continue_played" ); + a_boxes = getentarray( "foot_box", "script_noteworthy" ); + array_thread( a_boxes, ::box_footprint_think ); +} + +box_footprint_think() +{ + self.n_souls_absorbed = 0; + n_souls_required = 30; +/# + if ( getDvarInt( "zombie_cheat" ) > 0 ) + { + n_souls_required = 10; +#/ + } + self useanimtree( -1 ); + self thread watch_for_foot_stomp(); + wait 1; + self setclientfield( "foot_print_box_glow", 1 ); + wait 1; + self setclientfield( "foot_print_box_glow", 0 ); + while ( self.n_souls_absorbed < n_souls_required ) + { + self waittill( "soul_absorbed", player ); + self.n_souls_absorbed++; + if ( self.n_souls_absorbed == 1 ) + { + self clearanim( %o_zombie_dlc4_challenge_box_close, 0 ); + self setanim( %o_zombie_dlc4_challenge_box_open ); + self delay_thread( 1, ::setclientfield, "foot_print_box_glow", 1 ); + if ( isDefined( player ) && !flag( "vo_soul_box_intro_played" ) ) + { + player delay_thread( 1,5, ::richtofenrespondvoplay, "zm_box_start", 0, "vo_soul_box_intro_played" ); + } + } + if ( self.n_souls_absorbed == floor( n_souls_required / 4 ) ) + { + if ( isDefined( player ) && flag( "vo_soul_box_intro_played" ) && !flag( "vo_soul_box_continue_played" ) ) + { + player thread richtofenrespondvoplay( "zm_box_continue", 1, "vo_soul_box_continue_played" ); + } + } + if ( self.n_souls_absorbed == floor( n_souls_required / 2 ) || self.n_souls_absorbed == floor( n_souls_required / 1,3 ) ) + { + if ( isDefined( player ) ) + { + player create_and_play_dialog( "soul_box", "zm_box_encourage" ); + } + } + if ( self.n_souls_absorbed == n_souls_required ) + { + wait 1; + self clearanim( %o_zombie_dlc4_challenge_box_open, 0 ); + self setanim( %o_zombie_dlc4_challenge_box_close ); + } + } + self notify( "box_finished" ); + level.n_soul_boxes_completed++; + e_volume = getent( self.target, "targetname" ); + e_volume delete(); + self delay_thread( 0,5, ::setclientfield, "foot_print_box_glow", 0 ); + wait 1; + self movez( 30, 1, 1 ); + wait 0,5; + n_rotations = randomintrange( 5, 7 ); + v_start_angles = self.angles; + i = 0; + while ( i < n_rotations ) + { + v_rotate_angles = v_start_angles + ( randomfloatrange( -10, 10 ), randomfloatrange( -10, 10 ), randomfloatrange( -10, 10 ) ); + n_rotate_time = randomfloatrange( 0,2, 0,4 ); + self rotateto( v_rotate_angles, n_rotate_time ); + self waittill( "rotatedone" ); + i++; + } + self rotateto( v_start_angles, 0,3 ); + self movez( -60, 0,5, 0,5 ); + self waittill( "rotatedone" ); + trace_start = self.origin + vectorScale( ( 0, 1, 0 ), 200 ); + trace_end = self.origin; + fx_trace = bullettrace( trace_start, trace_end, 0, self ); + playfx( level._effect[ "mech_booster_landing" ], fx_trace[ "position" ], anglesToForward( self.angles ), anglesToUp( self.angles ) ); + playsoundatposition( "zmb_footprintbox_disappear", self.origin ); + self waittill( "movedone" ); + level maps/mp/zombies/_zm_challenges::increment_stat( "zc_boxes_filled" ); + if ( isDefined( player ) ) + { + if ( level.n_soul_boxes_completed == 1 ) + { + player thread richtofenrespondvoplay( "zm_box_complete" ); + } + else + { + if ( level.n_soul_boxes_completed == 4 ) + { + player thread richtofenrespondvoplay( "zm_box_final_complete", 1 ); + } + } + } + self delete(); +} + +watch_for_foot_stomp() +{ + self endon( "box_finished" ); + while ( 1 ) + { + self waittill( "robot_foot_stomp" ); + self clearanim( %o_zombie_dlc4_challenge_box_open, 0 ); + self setanim( %o_zombie_dlc4_challenge_box_close ); + self setclientfield( "foot_print_box_glow", 0 ); + self.n_souls_absorbed = 0; + wait 5; + } +} + +footprint_zombie_killed( attacker ) +{ + a_volumes = getentarray( "foot_box_volume", "script_noteworthy" ); + _a268 = a_volumes; + _k268 = getFirstArrayKey( _a268 ); + while ( isDefined( _k268 ) ) + { + e_volume = _a268[ _k268 ]; + if ( self istouching( e_volume ) && isDefined( attacker ) && isplayer( attacker ) ) + { + self setclientfield( "foot_print_box_fx", 1 ); + m_box = getent( e_volume.target, "targetname" ); + m_box notify( "soul_absorbed" ); + return 1; + } + _k268 = getNextArrayKey( _a268, _k268 ); + } + return 0; +} + +reward_packed_weapon( player, s_stat ) +{ + if ( !isDefined( s_stat.str_reward_weapon ) ) + { + a_weapons = array( "scar_zm", "galil_zm", "mp44_zm" ); + s_stat.str_reward_weapon = maps/mp/zombies/_zm_weapons::get_upgrade_weapon( random( a_weapons ) ); + } + m_weapon = spawn( "script_model", self.origin ); + m_weapon.angles = self.angles + vectorScale( ( 0, 1, 0 ), 180 ); + m_weapon playsound( "zmb_spawn_powerup" ); + m_weapon playloopsound( "zmb_spawn_powerup_loop", 0,5 ); + str_model = getweaponmodel( s_stat.str_reward_weapon ); + options = player maps/mp/zombies/_zm_weapons::get_pack_a_punch_weapon_options( s_stat.str_reward_weapon ); + m_weapon useweaponmodel( s_stat.str_reward_weapon, str_model, options ); + wait_network_frame(); + if ( !reward_rise_and_grab( m_weapon, 50, 2, 2, 10 ) ) + { + return 0; + } + weapon_limit = get_player_weapon_limit( player ); + primaries = player getweaponslistprimaries(); + if ( isDefined( primaries ) && primaries.size >= weapon_limit ) + { + player maps/mp/zombies/_zm_weapons::weapon_give( s_stat.str_reward_weapon ); + } + else + { + player giveweapon( s_stat.str_reward_weapon, 0, player maps/mp/zombies/_zm_weapons::get_pack_a_punch_weapon_options( s_stat.str_reward_weapon ) ); + player givestartammo( s_stat.str_reward_weapon ); + } + player switchtoweapon( s_stat.str_reward_weapon ); + m_weapon stoploopsound( 0,1 ); + player playsound( "zmb_powerup_grabbed" ); + m_weapon delete(); + return 1; +} + +reward_powerup_max_ammo( player, s_stat ) +{ + return reward_powerup( player, "full_ammo" ); +} + +reward_powerup_double_points( player, n_timeout ) +{ + return reward_powerup( player, "double_points", n_timeout ); +} + +reward_powerup_zombie_blood( player, n_timeout ) +{ + return reward_powerup( player, "zombie_blood", n_timeout ); +} + +reward_powerup( player, str_powerup, n_timeout ) +{ + if ( !isDefined( n_timeout ) ) + { + n_timeout = 10; + } + if ( !isDefined( level.zombie_powerups[ str_powerup ] ) ) + { + return; + } + s_powerup = level.zombie_powerups[ str_powerup ]; + m_reward = spawn( "script_model", self.origin ); + m_reward.angles = self.angles + vectorScale( ( 0, 1, 0 ), 180 ); + m_reward setmodel( s_powerup.model_name ); + m_reward playsound( "zmb_spawn_powerup" ); + m_reward playloopsound( "zmb_spawn_powerup_loop", 0,5 ); + wait_network_frame(); + if ( !reward_rise_and_grab( m_reward, 50, 2, 2, n_timeout ) ) + { + return 0; + } + m_reward.hint = s_powerup.hint; + if ( !isDefined( player ) ) + { + player = self.player_using; + } + switch( str_powerup ) + { + case "full_ammo": + level thread maps/mp/zombies/_zm_powerups::full_ammo_powerup( m_reward, player ); + player thread powerup_vo( "full_ammo" ); + level thread maps/mp/zombies/_zm_audio_announcer::leaderdialog( "full_ammo", player.pers[ "team" ] ); + break; + case "double_points": + level thread maps/mp/zombies/_zm_powerups::double_points_powerup( m_reward, player ); + player thread powerup_vo( "double_points" ); + level thread maps/mp/zombies/_zm_audio_announcer::leaderdialog( "double_points", player.pers[ "team" ] ); + break; + case "zombie_blood": + level thread maps/mp/zombies/_zm_powerup_zombie_blood::zombie_blood_powerup( m_reward, player ); + level thread maps/mp/zombies/_zm_audio_announcer::leaderdialog( "zombie_blood", player.pers[ "team" ] ); + } + wait 0,1; + m_reward stoploopsound( 0,1 ); + player playsound( "zmb_powerup_grabbed" ); + m_reward delete(); + return 1; +} + +reward_double_tap( player, s_stat ) +{ + m_reward = spawn( "script_model", self.origin ); + m_reward.angles = self.angles + vectorScale( ( 0, 1, 0 ), 180 ); + str_model = getweaponmodel( "zombie_perk_bottle_doubletap" ); + m_reward setmodel( str_model ); + m_reward playsound( "zmb_spawn_powerup" ); + m_reward playloopsound( "zmb_spawn_powerup_loop", 0,5 ); + wait_network_frame(); + if ( !reward_rise_and_grab( m_reward, 50, 2, 2, 10 ) ) + { + return 0; + } + if ( player hasperk( "specialty_rof" ) || player has_perk_paused( "specialty_rof" ) ) + { + m_reward thread bottle_reject_sink( player ); + return 0; + } + m_reward stoploopsound( 0,1 ); + player playsound( "zmb_powerup_grabbed" ); + m_reward thread maps/mp/zombies/_zm_perks::vending_trigger_post_think( player, "specialty_rof" ); + m_reward delete(); + return 1; +} + +bottle_reject_sink( player ) +{ + n_time = 1; + player playlocalsound( level.zmb_laugh_alias ); + self thread maps/mp/zombies/_zm_challenges::reward_sink( 0, 61, n_time ); + wait n_time; + self delete(); +} + +reward_one_inch_punch( player, s_stat ) +{ + m_reward = spawn( "script_model", self.origin ); + m_reward.angles = self.angles + vectorScale( ( 0, 1, 0 ), 180 ); + m_reward setmodel( "tag_origin" ); + playfxontag( level._effect[ "staff_soul" ], m_reward, "tag_origin" ); + m_reward playsound( "zmb_spawn_powerup" ); + m_reward playloopsound( "zmb_spawn_powerup_loop", 0,5 ); + wait_network_frame(); + if ( !reward_rise_and_grab( m_reward, 50, 2, 2, 10 ) ) + { + return 0; + } + player thread maps/mp/zombies/_zm_weap_one_inch_punch::one_inch_punch_melee_attack(); + m_reward stoploopsound( 0,1 ); + player playsound( "zmb_powerup_grabbed" ); + m_reward delete(); + player thread one_inch_punch_watch_for_death( s_stat ); + return 1; +} + +one_inch_punch_watch_for_death( s_stat ) +{ + self endon( "disconnect" ); + self waittill( "bled_out" ); + if ( s_stat.b_reward_claimed ) + { + s_stat.b_reward_claimed = 0; + } + s_stat.a_b_player_rewarded[ self.characterindex ] = 0; +} + +reward_beacon( player, s_stat ) +{ + m_reward = spawn( "script_model", self.origin ); + m_reward.angles = self.angles + vectorScale( ( 0, 1, 0 ), 180 ); + str_model = getweaponmodel( "beacon_zm" ); + m_reward setmodel( str_model ); + m_reward playsound( "zmb_spawn_powerup" ); + m_reward playloopsound( "zmb_spawn_powerup_loop", 0,5 ); + wait_network_frame(); + if ( !reward_rise_and_grab( m_reward, 50, 2, 2, 10 ) ) + { + return 0; + } + player maps/mp/zombies/_zm_weapons::weapon_give( "beacon_zm" ); + if ( isDefined( level.zombie_include_weapons[ "beacon_zm" ] ) && !level.zombie_include_weapons[ "beacon_zm" ] ) + { + level.zombie_include_weapons[ "beacon_zm" ] = 1; + level.zombie_weapons[ "beacon_zm" ].is_in_box = 1; + } + m_reward stoploopsound( 0,1 ); + player playsound( "zmb_powerup_grabbed" ); + m_reward delete(); + return 1; +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_chamber.gsc b/zm_tomb_patch/maps/mp/zm_tomb_chamber.gsc new file mode 100644 index 0000000..dfa3730 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_chamber.gsc @@ -0,0 +1,349 @@ +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/zombies/_zm_ai_basic; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +main() +{ + level thread inits(); + level thread chamber_wall_change_randomly(); +} + +inits() +{ + a_walls = getentarray( "chamber_wall", "script_noteworthy" ); + _a24 = a_walls; + _k24 = getFirstArrayKey( _a24 ); + while ( isDefined( _k24 ) ) + { + e_wall = _a24[ _k24 ]; + e_wall.down_origin = e_wall.origin; + e_wall.up_origin = ( e_wall.origin[ 0 ], e_wall.origin[ 1 ], e_wall.origin[ 2 ] + 1000 ); + _k24 = getNextArrayKey( _a24, _k24 ); + } + level.n_chamber_wall_active = 0; + flag_wait( "start_zombie_round_logic" ); + wait 3; + _a40 = a_walls; + _k40 = getFirstArrayKey( _a40 ); + while ( isDefined( _k40 ) ) + { + e_wall = _a40[ _k40 ]; + e_wall moveto( e_wall.up_origin, 0,05 ); + e_wall connectpaths(); + _k40 = getNextArrayKey( _a40, _k40 ); + } +/# + level thread chamber_devgui(); +#/ +} + +chamber_devgui() +{ +/# + setdvarint( "chamber_wall", 5 ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Chamber:1/Fire:1" "chamber_wall 1"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Chamber:1/Air:2" "chamber_wall 2"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Chamber:1/Lightning:3" "chamber_wall 3"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Chamber:1/Water:4" "chamber_wall 4"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Chamber:1/None:5" "chamber_wall 0"\n" ); + level thread watch_chamber_wall(); +#/ +} + +watch_chamber_wall() +{ +/# + while ( 1 ) + { + if ( getDvarInt( #"763A3046" ) != 5 ) + { + chamber_change_walls( getDvarInt( #"763A3046" ) ); + setdvarint( "chamber_wall", 5 ); + } + wait 0,05; +#/ + } +} + +cap_value( val, min, max ) +{ + if ( val < min ) + { + return min; + } + else + { + if ( val > max ) + { + return max; + } + else + { + return val; + } + } +} + +chamber_wall_dust() +{ + i = 1; + while ( i <= 9 ) + { + playfxontag( level._effect[ "crypt_wall_drop" ], self, "tag_fx_dust_0" + i ); + wait_network_frame(); + i++; + } +} + +chamber_change_walls( n_element ) +{ + if ( n_element == level.n_chamber_wall_active ) + { + return; + } + e_current_wall = undefined; + e_new_wall = undefined; + playsoundatposition( "zmb_chamber_wallchange", ( 10342, -7921, -272 ) ); + a_walls = getentarray( "chamber_wall", "script_noteworthy" ); + _a123 = a_walls; + _k123 = getFirstArrayKey( _a123 ); + while ( isDefined( _k123 ) ) + { + e_wall = _a123[ _k123 ]; + if ( e_wall.script_int == n_element ) + { + e_wall thread move_wall_down(); + } + else + { + if ( e_wall.script_int == level.n_chamber_wall_active ) + { + e_wall thread move_wall_up(); + } + } + _k123 = getNextArrayKey( _a123, _k123 ); + } + level.n_chamber_wall_active = n_element; +} + +is_chamber_occupied() +{ + a_players = getplayers(); + _a142 = a_players; + _k142 = getFirstArrayKey( _a142 ); + while ( isDefined( _k142 ) ) + { + e_player = _a142[ _k142 ]; + if ( is_point_in_chamber( e_player.origin ) ) + { + return 1; + } + _k142 = getNextArrayKey( _a142, _k142 ); + } + return 0; +} + +is_point_in_chamber( v_origin ) +{ + if ( !isDefined( level.s_chamber_center ) ) + { + level.s_chamber_center = getstruct( "chamber_center", "targetname" ); + level.s_chamber_center.radius_sq = level.s_chamber_center.script_float * level.s_chamber_center.script_float; + } + return distance2dsquared( level.s_chamber_center.origin, v_origin ) < level.s_chamber_center.radius_sq; +} + +chamber_wall_change_randomly() +{ + flag_wait( "start_zombie_round_logic" ); + a_element_enums = array( 1, 2, 3, 4 ); + level endon( "stop_random_chamber_walls" ); + n_elem_prev = undefined; + while ( 1 ) + { + while ( !is_chamber_occupied() ) + { + wait 1; + } + flag_wait( "any_crystal_picked_up" ); + n_round = cap_value( level.round_number, 10, 30 ); + f_progression_pct = ( n_round - 10 ) / ( 30 - 10 ); + n_change_wall_time = lerpfloat( 15, 5, f_progression_pct ); + n_elem = random( a_element_enums ); + arrayremovevalue( a_element_enums, n_elem, 0 ); + if ( isDefined( n_elem_prev ) ) + { + a_element_enums[ a_element_enums.size ] = n_elem_prev; + } + chamber_change_walls( n_elem ); + wait n_change_wall_time; + n_elem_prev = n_elem; + } +} + +move_wall_up() +{ + self moveto( self.up_origin, 1 ); + self waittill( "movedone" ); + self connectpaths(); +} + +move_wall_down() +{ + self moveto( self.down_origin, 1 ); + self waittill( "movedone" ); + rumble_players_in_chamber( 2, 0,1 ); + self thread chamber_wall_dust(); + self disconnectpaths(); +} + +random_shuffle( a_items, item ) +{ + b_done_shuffling = undefined; + if ( !isDefined( item ) ) + { + item = a_items[ a_items.size - 1 ]; + } + while ( isDefined( b_done_shuffling ) && !b_done_shuffling ) + { + a_items = array_randomize( a_items ); + if ( a_items[ 0 ] != item ) + { + b_done_shuffling = 1; + } + wait 0,05; + } + return a_items; +} + +tomb_chamber_find_exit_point() +{ + self endon( "death" ); + player = get_players()[ 0 ]; + dist_zombie = 0; + dist_player = 0; + dest = 0; + away = vectornormalize( self.origin - player.origin ); + endpos = self.origin + vectorScale( away, 600 ); + locs = array_randomize( level.enemy_dog_locations ); + i = 0; + while ( i < locs.size ) + { + dist_zombie = distancesquared( locs[ i ].origin, endpos ); + dist_player = distancesquared( locs[ i ].origin, player.origin ); + if ( dist_zombie < dist_player ) + { + dest = i; + break; + } + else + { + i++; + } + } + self notify( "stop_find_flesh" ); + self notify( "zombie_acquire_enemy" ); + if ( isDefined( locs[ dest ] ) ) + { + self setgoalpos( locs[ dest ].origin ); + } + self.b_wandering_in_chamber = 1; + flag_wait( "player_active_in_chamber" ); + self.b_wandering_in_chamber = 0; + self thread maps/mp/zombies/_zm_ai_basic::find_flesh(); +} + +chamber_zombies_find_poi() +{ + zombies = getaiarray( level.zombie_team ); + i = 0; + while ( i < zombies.size ) + { + if ( isDefined( zombies[ i ].b_wandering_in_chamber ) && zombies[ i ].b_wandering_in_chamber ) + { + i++; + continue; + } + else + { + if ( !is_point_in_chamber( zombies[ i ].origin ) ) + { + i++; + continue; + } + else + { + zombies[ i ] thread tomb_chamber_find_exit_point(); + } + } + i++; + } +} + +tomb_is_valid_target_in_chamber() +{ + a_players = getplayers(); + _a322 = a_players; + _k322 = getFirstArrayKey( _a322 ); + while ( isDefined( _k322 ) ) + { + e_player = _a322[ _k322 ]; + if ( e_player maps/mp/zombies/_zm_laststand::player_is_in_laststand() ) + { + } + else if ( isDefined( e_player.b_zombie_blood ) || e_player.b_zombie_blood && isDefined( e_player.ignoreme ) && e_player.ignoreme ) + { + } + else + { + if ( !is_point_in_chamber( e_player.origin ) ) + { + break; + } + else + { + return 1; + } + } + _k322 = getNextArrayKey( _a322, _k322 ); + } + return 0; +} + +is_player_in_chamber() +{ + if ( is_point_in_chamber( self.origin ) ) + { + return 1; + } + else + { + return 0; + } +} + +tomb_watch_chamber_player_activity() +{ + flag_init( "player_active_in_chamber" ); + flag_wait( "start_zombie_round_logic" ); + while ( 1 ) + { + wait 1; + if ( is_chamber_occupied() ) + { + if ( tomb_is_valid_target_in_chamber() ) + { + flag_set( "player_active_in_chamber" ); + break; + } + else + { + flag_clear( "player_active_in_chamber" ); + chamber_zombies_find_poi(); + } + } + } +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_classic.gsc b/zm_tomb_patch/maps/mp/zm_tomb_classic.gsc new file mode 100644 index 0000000..f40bb44 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_classic.gsc @@ -0,0 +1,36 @@ +#include maps/mp/zombies/_zm_magicbox; +#include maps/mp/zombies/_zm_game_module; +#include maps/mp/gametypes_zm/_zm_gametype; +#include maps/mp/zm_tomb_craftables; +#include maps/mp/zombies/_zm_craftables; +#include maps/mp/zombies/_zm_utility; +#include common_scripts/utility; +#include maps/mp/_utility; + +precache() +{ + if ( isDefined( level.createfx_enabled ) && level.createfx_enabled ) + { + return; + } + maps/mp/zombies/_zm_craftables::init(); + maps/mp/zm_tomb_craftables::randomize_craftable_spawns(); + maps/mp/zm_tomb_craftables::include_craftables(); + maps/mp/zm_tomb_craftables::init_craftables(); +} + +main() +{ + maps/mp/gametypes_zm/_zm_gametype::setup_standard_objects( "tomb" ); + maps/mp/zombies/_zm_game_module::set_current_game_module( level.game_module_standard_index ); + level thread maps/mp/zombies/_zm_craftables::think_craftables(); + flag_wait( "initial_blackscreen_passed" ); +} + +zm_treasure_chest_init() +{ + chest1 = getstruct( "start_chest", "script_noteworthy" ); + level.chests = []; + level.chests[ level.chests.size ] = chest1; + maps/mp/zombies/_zm_magicbox::treasure_chest_init( "start_chest" ); +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_craftables.gsc b/zm_tomb_patch/maps/mp/zm_tomb_craftables.gsc new file mode 100644 index 0000000..4c9aa27 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_craftables.gsc @@ -0,0 +1,1489 @@ +#include maps/mp/zombies/_zm_equipment; +#include maps/mp/zombies/_zm_ai_quadrotor; +#include maps/mp/zombies/_zm_zonemgr; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zombies/_zm_unitrigger; +#include maps/mp/zm_tomb_main_quest; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/zombies/_zm_craftables; +#include maps/mp/_utility; +#include common_scripts/utility; + +randomize_craftable_spawns() +{ + a_randomized_craftables = array( "gramophone_vinyl_ice", "gramophone_vinyl_air", "gramophone_vinyl_elec", "gramophone_vinyl_fire", "gramophone_vinyl_master", "gramophone_vinyl_player" ); + _a29 = a_randomized_craftables; + _k29 = getFirstArrayKey( _a29 ); + while ( isDefined( _k29 ) ) + { + str_craftable = _a29[ _k29 ]; + s_original_pos = getstruct( str_craftable, "targetname" ); + a_alt_locations = getstructarray( str_craftable + "_alt", "targetname" ); + n_loc_index = randomintrange( 0, a_alt_locations.size + 1 ); + if ( n_loc_index == a_alt_locations.size ) + { + } + else s_original_pos.origin = a_alt_locations[ n_loc_index ].origin; + s_original_pos.angles = a_alt_locations[ n_loc_index ].angles; + _k29 = getNextArrayKey( _a29, _k29 ); + } +} + +init_craftables() +{ + precachemodel( "p6_zm_tm_quadrotor_stand" ); + flag_init( "quadrotor_cooling_down" ); + level.craftable_piece_count = 4; + flag_init( "any_crystal_picked_up" ); + flag_init( "staff_air_zm_enabled" ); + flag_init( "staff_fire_zm_enabled" ); + flag_init( "staff_lightning_zm_enabled" ); + flag_init( "staff_water_zm_enabled" ); + register_clientfields(); + add_zombie_craftable( "equip_dieseldrone_zm", &"ZM_TOMB_CRQ", &"ZM_TOMB_CRQ", &"ZM_TOMB_TQ", ::onfullycrafted_quadrotor, 1 ); + add_zombie_craftable_vox_category( "equip_dieseldrone_zm", "build_dd" ); + make_zombie_craftable_open( "equip_dieseldrone_zm", "veh_t6_dlc_zm_quadrotor", ( 0, 0, 1 ), ( 0, -4, 10 ) ); + add_zombie_craftable( "tomb_shield_zm", &"ZM_TOMB_CRRI", undefined, &"ZOMBIE_BOUGHT_RIOT", undefined, 1 ); + add_zombie_craftable_vox_category( "tomb_shield_zm", "build_zs" ); + make_zombie_craftable_open( "tomb_shield_zm", "t6_wpn_zmb_shield_dlc4_dmg0_world", vectorScale( ( 0, 0, 1 ), 90 ), ( 0, 0, level.riotshield_placement_zoffset ) ); + add_zombie_craftable( "elemental_staff_fire", &"ZM_TOMB_CRF", &"ZM_TOMB_INS", &"ZM_TOMB_BOF", ::staff_fire_fullycrafted, 1 ); + add_zombie_craftable_vox_category( "elemental_staff_fire", "fire_staff" ); + add_zombie_craftable( "elemental_staff_air", &"ZM_TOMB_CRA", &"ZM_TOMB_INS", &"ZM_TOMB_BOA", ::staff_air_fullycrafted, 1 ); + add_zombie_craftable_vox_category( "elemental_staff_air", "air_staff" ); + add_zombie_craftable( "elemental_staff_lightning", &"ZM_TOMB_CRL", &"ZM_TOMB_INS", &"ZM_TOMB_BOL", ::staff_lightning_fullycrafted, 1 ); + add_zombie_craftable_vox_category( "elemental_staff_lightning", "light_staff" ); + add_zombie_craftable( "elemental_staff_water", &"ZM_TOMB_CRW", &"ZM_TOMB_INS", &"ZM_TOMB_BOW", ::staff_water_fullycrafted, 1 ); + add_zombie_craftable_vox_category( "elemental_staff_water", "ice_staff" ); + add_zombie_craftable( "gramophone", &"ZM_TOMB_CRAFT_GRAMOPHONE", &"ZM_TOMB_CRAFT_GRAMOPHONE", &"ZM_TOMB_BOUGHT_GRAMOPHONE", undefined, 0 ); + add_zombie_craftable_vox_category( "gramophone", "gramophone" ); + level.zombie_craftable_persistent_weapon = ::tomb_check_crafted_weapon_persistence; + level.custom_craftable_validation = ::tomb_custom_craftable_validation; + level.zombie_custom_equipment_setup = ::setup_quadrotor_purchase; + level thread hide_staff_model(); + level.quadrotor_status = spawnstruct(); + level.quadrotor_status.crafted = 0; + level.quadrotor_status.picked_up = 0; + level.num_staffpieces_picked_up = []; + level.n_staffs_crafted = 0; +} + +add_craftable_cheat( craftable ) +{ +/# + if ( !isDefined( level.cheat_craftables ) ) + { + level.cheat_craftables = []; + } + _a112 = craftable.a_piecestubs; + _k112 = getFirstArrayKey( _a112 ); + while ( isDefined( _k112 ) ) + { + s_piece = _a112[ _k112 ]; + id_string = undefined; + client_field_val = undefined; + if ( isDefined( s_piece.client_field_id ) ) + { + id_string = s_piece.client_field_id; + client_field_val = id_string; + } + else if ( isDefined( s_piece.client_field_state ) ) + { + id_string = "gem"; + client_field_val = s_piece.client_field_state; + } + else + { + } + tokens = strtok( id_string, "_" ); + display_string = "piece"; + _a134 = tokens; + _k134 = getFirstArrayKey( _a134 ); + while ( isDefined( _k134 ) ) + { + token = _a134[ _k134 ]; + if ( token != "piece" && token != "staff" && token != "zm" ) + { + display_string = ( display_string + "_" ) + token; + } + _k134 = getNextArrayKey( _a134, _k134 ); + } + level.cheat_craftables[ "" + client_field_val ] = s_piece; + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Craftables:1/" + craftable.name + "/" + display_string + "" "give_craftable " + client_field_val + ""\n" ); + s_piece.waste = "waste"; + _k112 = getNextArrayKey( _a112, _k112 ); + } + flag_wait( "start_zombie_round_logic" ); + _a149 = craftable.a_piecestubs; + _k149 = getFirstArrayKey( _a149 ); + while ( isDefined( _k149 ) ) + { + s_piece = _a149[ _k149 ]; + s_piece craftable_waittill_spawned(); + s_piece.piecespawn.model thread puzzle_debug_position( "C", vectorScale( ( 0, 0, 1 ), 255 ), undefined, "show_craftable_locations" ); + _k149 = getNextArrayKey( _a149, _k149 ); +#/ + } +} + +autocraft_staffs() +{ + setdvar( "autocraft_staffs", "off" ); +/# + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Craftables:1/Give All Staff Pieces:0" "autocraft_staffs on"\n" ); +#/ + while ( getDvar( "autocraft_staffs" ) != "on" ) + { + wait_network_frame(); + } + flag_wait( "start_zombie_round_logic" ); + keys = getarraykeys( level.cheat_craftables ); + a_players = getplayers(); + _a176 = keys; + _k176 = getFirstArrayKey( _a176 ); + while ( isDefined( _k176 ) ) + { + key = _a176[ _k176 ]; + if ( issubstr( key, "staff" ) || issubstr( key, "record" ) ) + { + s_piece = level.cheat_craftables[ key ]; + if ( isDefined( s_piece.piecespawn ) ) + { + a_players[ 0 ] maps/mp/zombies/_zm_craftables::player_take_piece( s_piece.piecespawn ); + } + } + _k176 = getNextArrayKey( _a176, _k176 ); + } + i = 1; + while ( i <= 4 ) + { + level notify( "player_teleported" ); + wait_network_frame(); + piece_spawn = level.cheat_craftables[ "" + i ].piecespawn; + if ( isDefined( piece_spawn ) ) + { + if ( isDefined( a_players[ i - 1 ] ) ) + { + a_players[ i - 1 ] maps/mp/zombies/_zm_craftables::player_take_piece( piece_spawn ); + wait_network_frame(); + } + } + wait_network_frame(); + i++; + } +} + +run_craftables_devgui() +{ +/# + level thread autocraft_staffs(); + setdvar( "give_craftable", "" ); + while ( 1 ) + { + craftable_id = getDvar( "give_craftable" ); + if ( craftable_id != "" ) + { + piece_spawn = level.cheat_craftables[ craftable_id ].piecespawn; + if ( isDefined( piece_spawn ) ) + { + players = getplayers(); + players[ 0 ] maps/mp/zombies/_zm_craftables::player_take_piece( piece_spawn ); + } + setdvar( "give_craftable", "" ); + } + wait 0,05; +#/ + } +} + +include_craftables() +{ + level thread run_craftables_devgui(); + craftable_name = "equip_dieseldrone_zm"; + quadrotor_body = generate_zombie_craftable_piece( craftable_name, "body", "veh_t6_dlc_zm_quad_piece_body", 32, 64, 0, undefined, ::onpickup_common, ::ondrop_common, undefined, undefined, undefined, undefined, "piece_quadrotor_zm_body", 1, "build_dd" ); + quadrotor_brain = generate_zombie_craftable_piece( craftable_name, "brain", "veh_t6_dlc_zm_quad_piece_brain", 32, 64, 0, undefined, ::onpickup_common, ::ondrop_common, undefined, undefined, undefined, undefined, "piece_quadrotor_zm_brain", 1, "build_dd_brain" ); + quadrotor_engine = generate_zombie_craftable_piece( craftable_name, "engine", "veh_t6_dlc_zm_quad_piece_engine", 32, 64, 0, undefined, ::onpickup_common, ::ondrop_common, undefined, undefined, undefined, undefined, "piece_quadrotor_zm_engine", 1, "build_dd" ); + quadrotor = spawnstruct(); + quadrotor.name = craftable_name; + quadrotor add_craftable_piece( quadrotor_body ); + quadrotor add_craftable_piece( quadrotor_brain ); + quadrotor add_craftable_piece( quadrotor_engine ); + quadrotor.triggerthink = ::quadrotorcraftable; + include_zombie_craftable( quadrotor ); + level thread add_craftable_cheat( quadrotor ); + craftable_name = "tomb_shield_zm"; + riotshield_top = generate_zombie_craftable_piece( craftable_name, "top", "t6_wpn_zmb_shield_dlc4_top", 48, 64, 0, undefined, ::onpickup_common, ::ondrop_common, undefined, undefined, undefined, undefined, "piece_riotshield_dolly", 1, "build_zs" ); + riotshield_door = generate_zombie_craftable_piece( craftable_name, "door", "t6_wpn_zmb_shield_dlc4_door", 48, 15, 25, undefined, ::onpickup_common, ::ondrop_common, undefined, undefined, undefined, undefined, "piece_riotshield_door", 1, "build_zs" ); + riotshield_bracket = generate_zombie_craftable_piece( craftable_name, "bracket", "t6_wpn_zmb_shield_dlc4_bracket", 48, 15, 0, undefined, ::onpickup_common, ::ondrop_common, undefined, undefined, undefined, undefined, "piece_riotshield_clamp", 1, "build_zs" ); + riotshield = spawnstruct(); + riotshield.name = craftable_name; + riotshield add_craftable_piece( riotshield_top ); + riotshield add_craftable_piece( riotshield_door ); + riotshield add_craftable_piece( riotshield_bracket ); + riotshield.onbuyweapon = ::onbuyweapon_riotshield; + riotshield.triggerthink = ::riotshieldcraftable; + include_craftable( riotshield ); + level thread add_craftable_cheat( riotshield ); + craftable_name = "elemental_staff_air"; + staff_air_gem = generate_zombie_craftable_piece( craftable_name, "gem", "t6_wpn_zmb_staff_crystal_air_part", 48, 64, 0, undefined, ::onpickup_aircrystal, ::ondrop_aircrystal, undefined, undefined, undefined, undefined, 2, 0, "crystal", 1 ); + staff_air_upper_staff = generate_zombie_craftable_piece( craftable_name, "upper_staff", "t6_wpn_zmb_staff_tip_air_world", 32, 64, 0, undefined, ::onpickup_staffpiece, ::ondrop_common, undefined, undefined, undefined, undefined, "piece_staff_zm_ustaff_air", 1, "staff_part" ); + staff_air_middle_staff = generate_zombie_craftable_piece( craftable_name, "middle_staff", "t6_wpn_zmb_staff_stem_air_part", 32, 64, 0, undefined, ::onpickup_staffpiece, ::ondrop_common, undefined, undefined, undefined, undefined, "piece_staff_zm_mstaff_air", 1, "staff_part" ); + staff_air_lower_staff = generate_zombie_craftable_piece( craftable_name, "lower_staff", "t6_wpn_zmb_staff_revive_part", 32, 64, 0, undefined, ::onpickup_staffpiece, ::ondrop_common, undefined, undefined, undefined, undefined, "piece_staff_zm_lstaff_air", 1, "staff_part" ); + staff = spawnstruct(); + staff.name = craftable_name; + staff add_craftable_piece( staff_air_gem ); + staff add_craftable_piece( staff_air_upper_staff ); + staff add_craftable_piece( staff_air_middle_staff ); + staff add_craftable_piece( staff_air_lower_staff ); + staff.triggerthink = ::staffcraftable_air; + staff.custom_craftablestub_update_prompt = ::tomb_staff_update_prompt; + include_zombie_craftable( staff ); + level thread add_craftable_cheat( staff ); + count_staff_piece_pickup( array( staff_air_upper_staff, staff_air_middle_staff, staff_air_lower_staff ) ); + craftable_name = "elemental_staff_fire"; + staff_fire_gem = generate_zombie_craftable_piece( craftable_name, "gem", "t6_wpn_zmb_staff_crystal_fire_part", 48, 64, 0, undefined, ::onpickup_firecrystal, ::ondrop_firecrystal, undefined, undefined, undefined, undefined, 1, 0, "crystal", 1 ); + staff_fire_upper_staff = generate_zombie_craftable_piece( craftable_name, "upper_staff", "t6_wpn_zmb_staff_tip_fire_world", 32, 64, 0, undefined, ::onpickup_staffpiece, ::ondrop_common, undefined, undefined, undefined, undefined, "piece_staff_zm_ustaff_fire", 1, "staff_part" ); + staff_fire_middle_staff = generate_zombie_craftable_piece( craftable_name, "middle_staff", "t6_wpn_zmb_staff_stem_fire_part", 32, 64, 0, undefined, ::onpickup_staffpiece, ::ondrop_common, undefined, undefined, undefined, undefined, "piece_staff_zm_mstaff_fire", 1, "staff_part" ); + staff_fire_lower_staff = generate_zombie_craftable_piece( craftable_name, "lower_staff", "t6_wpn_zmb_staff_revive_part", 64, 128, 0, undefined, ::onpickup_staffpiece, ::ondrop_common, undefined, undefined, undefined, undefined, "piece_staff_zm_lstaff_fire", 1, "staff_part" ); + level thread maps/mp/zm_tomb_main_quest::staff_mechz_drop_pieces( staff_fire_lower_staff ); + level thread maps/mp/zm_tomb_main_quest::staff_biplane_drop_pieces( array( staff_fire_middle_staff ) ); + level thread maps/mp/zm_tomb_main_quest::staff_unlock_with_zone_capture( staff_fire_upper_staff ); + staff = spawnstruct(); + staff.name = craftable_name; + staff add_craftable_piece( staff_fire_gem ); + staff add_craftable_piece( staff_fire_upper_staff ); + staff add_craftable_piece( staff_fire_middle_staff ); + staff add_craftable_piece( staff_fire_lower_staff ); + staff.triggerthink = ::staffcraftable_fire; + staff.custom_craftablestub_update_prompt = ::tomb_staff_update_prompt; + include_zombie_craftable( staff ); + level thread add_craftable_cheat( staff ); + count_staff_piece_pickup( array( staff_fire_upper_staff, staff_fire_middle_staff, staff_fire_lower_staff ) ); + craftable_name = "elemental_staff_lightning"; + staff_lightning_gem = generate_zombie_craftable_piece( craftable_name, "gem", "t6_wpn_zmb_staff_crystal_bolt_part", 48, 64, 0, undefined, ::onpickup_lightningcrystal, ::ondrop_lightningcrystal, undefined, undefined, undefined, undefined, 3, 0, "crystal", 1 ); + staff_lightning_upper_staff = generate_zombie_craftable_piece( craftable_name, "upper_staff", "t6_wpn_zmb_staff_tip_lightning_world", 32, 64, 0, undefined, ::onpickup_staffpiece, ::ondrop_common, undefined, undefined, undefined, undefined, "piece_staff_zm_ustaff_lightning", 1, "staff_part" ); + staff_lightning_middle_staff = generate_zombie_craftable_piece( craftable_name, "middle_staff", "t6_wpn_zmb_staff_stem_bolt_part", 32, 64, 0, undefined, ::onpickup_staffpiece, ::ondrop_common, undefined, undefined, undefined, undefined, "piece_staff_zm_mstaff_lightning", 1, "staff_part" ); + staff_lightning_lower_staff = generate_zombie_craftable_piece( craftable_name, "lower_staff", "t6_wpn_zmb_staff_revive_part", 32, 64, 0, undefined, ::onpickup_staffpiece, ::ondrop_common, undefined, undefined, undefined, undefined, "piece_staff_zm_lstaff_lightning", 1, "staff_part" ); + staff = spawnstruct(); + staff.name = craftable_name; + staff add_craftable_piece( staff_lightning_gem ); + staff add_craftable_piece( staff_lightning_upper_staff ); + staff add_craftable_piece( staff_lightning_middle_staff ); + staff add_craftable_piece( staff_lightning_lower_staff ); + staff.triggerthink = ::staffcraftable_lightning; + staff.custom_craftablestub_update_prompt = ::tomb_staff_update_prompt; + include_zombie_craftable( staff ); + level thread add_craftable_cheat( staff ); + count_staff_piece_pickup( array( staff_lightning_upper_staff, staff_lightning_middle_staff, staff_lightning_lower_staff ) ); + craftable_name = "elemental_staff_water"; + staff_water_gem = generate_zombie_craftable_piece( craftable_name, "gem", "t6_wpn_zmb_staff_crystal_water_part", 48, 64, 0, undefined, ::onpickup_watercrystal, ::ondrop_watercrystal, undefined, undefined, undefined, undefined, 4, 0, "crystal", 1 ); + staff_water_upper_staff = generate_zombie_craftable_piece( craftable_name, "upper_staff", "t6_wpn_zmb_staff_tip_water_world", 32, 64, 0, undefined, ::onpickup_staffpiece, ::ondrop_common, undefined, undefined, undefined, undefined, "piece_staff_zm_ustaff_water", 1, "staff_part" ); + staff_water_middle_staff = generate_zombie_craftable_piece( craftable_name, "middle_staff", "t6_wpn_zmb_staff_stem_water_part", 32, 64, 0, undefined, ::onpickup_staffpiece, ::ondrop_common, undefined, undefined, undefined, undefined, "piece_staff_zm_mstaff_water", 1, "staff_part" ); + staff_water_lower_staff = generate_zombie_craftable_piece( craftable_name, "lower_staff", "t6_wpn_zmb_staff_revive_part", 32, 64, 0, undefined, ::onpickup_staffpiece, ::ondrop_common, undefined, undefined, undefined, undefined, "piece_staff_zm_lstaff_water", 1, "staff_part" ); + a_ice_staff_parts = array( staff_water_lower_staff, staff_water_middle_staff, staff_water_upper_staff ); + level thread maps/mp/zm_tomb_main_quest::staff_ice_dig_pieces( a_ice_staff_parts ); + staff = spawnstruct(); + staff.name = craftable_name; + staff add_craftable_piece( staff_water_gem ); + staff add_craftable_piece( staff_water_upper_staff ); + staff add_craftable_piece( staff_water_middle_staff ); + staff add_craftable_piece( staff_water_lower_staff ); + staff.triggerthink = ::staffcraftable_water; + staff.custom_craftablestub_update_prompt = ::tomb_staff_update_prompt; + include_zombie_craftable( staff ); + level thread add_craftable_cheat( staff ); + count_staff_piece_pickup( array( staff_water_upper_staff, staff_water_middle_staff, staff_water_lower_staff ) ); + craftable_name = "gramophone"; + vinyl_pickup_player = vinyl_add_pickup( craftable_name, "vinyl_player", "p6_zm_tm_gramophone", "piece_record_zm_player", undefined, "gramophone" ); + vinyl_pickup_master = vinyl_add_pickup( craftable_name, "vinyl_master", "p6_zm_tm_record_master", "piece_record_zm_vinyl_master", undefined, "record" ); + vinyl_pickup_air = vinyl_add_pickup( craftable_name, "vinyl_air", "p6_zm_tm_record_wind", "piece_record_zm_vinyl_air", "quest_state2", "record" ); + vinyl_pickup_ice = vinyl_add_pickup( craftable_name, "vinyl_ice", "p6_zm_tm_record_ice", "piece_record_zm_vinyl_water", "quest_state4", "record" ); + vinyl_pickup_fire = vinyl_add_pickup( craftable_name, "vinyl_fire", "p6_zm_tm_record_fire", "piece_record_zm_vinyl_fire", "quest_state1", "record" ); + vinyl_pickup_elec = vinyl_add_pickup( craftable_name, "vinyl_elec", "p6_zm_tm_record_lightning", "piece_record_zm_vinyl_lightning", "quest_state3", "record" ); + vinyl_pickup_player.sam_line = "gramophone_found"; + vinyl_pickup_master.sam_line = "master_found"; + vinyl_pickup_air.sam_line = "first_record_found"; + vinyl_pickup_ice.sam_line = "first_record_found"; + vinyl_pickup_fire.sam_line = "first_record_found"; + vinyl_pickup_elec.sam_line = "first_record_found"; + level thread maps/mp/zm_tomb_vo::watch_one_shot_samantha_line( "vox_sam_1st_record_found_0", "first_record_found" ); + level thread maps/mp/zm_tomb_vo::watch_one_shot_samantha_line( "vox_sam_gramophone_found_0", "gramophone_found" ); + level thread maps/mp/zm_tomb_vo::watch_one_shot_samantha_line( "vox_sam_master_found_0", "master_found" ); + gramophone = spawnstruct(); + gramophone.name = craftable_name; + gramophone add_craftable_piece( vinyl_pickup_player ); + gramophone add_craftable_piece( vinyl_pickup_master ); + gramophone add_craftable_piece( vinyl_pickup_air ); + gramophone add_craftable_piece( vinyl_pickup_ice ); + gramophone add_craftable_piece( vinyl_pickup_fire ); + gramophone add_craftable_piece( vinyl_pickup_elec ); + gramophone.triggerthink = ::gramophonecraftable; + include_zombie_craftable( gramophone ); + level thread add_craftable_cheat( gramophone ); + staff_fire_gem thread watch_part_pickup( "quest_state1", 2 ); + staff_air_gem thread watch_part_pickup( "quest_state2", 2 ); + staff_lightning_gem thread watch_part_pickup( "quest_state3", 2 ); + staff_water_gem thread watch_part_pickup( "quest_state4", 2 ); + staff_fire_gem thread staff_crystal_wait_for_teleport( 1 ); + staff_air_gem thread staff_crystal_wait_for_teleport( 2 ); + staff_lightning_gem thread staff_crystal_wait_for_teleport( 3 ); + staff_water_gem thread staff_crystal_wait_for_teleport( 4 ); + level thread maps/mp/zm_tomb_vo::staff_craft_vo(); + level thread maps/mp/zm_tomb_vo::samantha_discourage_think(); + level thread maps/mp/zm_tomb_vo::samantha_encourage_think(); + level thread craftable_add_glow_fx(); +} + +register_clientfields() +{ + bits = 1; + registerclientfield( "world", "piece_quadrotor_zm_body", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_quadrotor_zm_brain", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_quadrotor_zm_engine", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_riotshield_dolly", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_riotshield_door", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_riotshield_clamp", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_staff_zm_gem_air", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_staff_zm_ustaff_air", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_staff_zm_mstaff_air", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_staff_zm_lstaff_air", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_staff_zm_gem_fire", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_staff_zm_ustaff_fire", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_staff_zm_mstaff_fire", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_staff_zm_lstaff_fire", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_staff_zm_gem_lightning", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_staff_zm_ustaff_lightning", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_staff_zm_mstaff_lightning", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_staff_zm_lstaff_lightning", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_staff_zm_gem_water", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_staff_zm_ustaff_water", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_staff_zm_mstaff_water", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_staff_zm_lstaff_water", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_record_zm_player", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_record_zm_vinyl_master", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_record_zm_vinyl_air", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_record_zm_vinyl_water", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_record_zm_vinyl_fire", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "piece_record_zm_vinyl_lightning", 14000, bits, "int", undefined, 0 ); + registerclientfield( "scriptmover", "element_glow_fx", 14000, 4, "int", undefined, 0 ); + registerclientfield( "scriptmover", "bryce_cake", 14000, 2, "int", undefined, 0 ); + registerclientfield( "scriptmover", "switch_spark", 14000, 1, "int", undefined, 0 ); + bits = getminbitcountfornum( 5 ); + registerclientfield( "world", "staff_player1", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "staff_player2", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "staff_player3", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "staff_player4", 14000, bits, "int", undefined, 0 ); + bits = getminbitcountfornum( 5 ); + registerclientfield( "world", "quest_state1", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "quest_state2", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "quest_state3", 14000, bits, "int", undefined, 0 ); + registerclientfield( "world", "quest_state4", 14000, bits, "int", undefined, 0 ); + registerclientfield( "toplayer", "sndMudSlow", 14000, 1, "int" ); +} + +craftable_add_glow_fx() +{ + flag_wait( "start_zombie_round_logic" ); + _a519 = level.zombie_include_craftables; + _k519 = getFirstArrayKey( _a519 ); + while ( isDefined( _k519 ) ) + { + s_craftable = _a519[ _k519 ]; + if ( !issubstr( s_craftable.name, "elemental_staff" ) ) + { + } + else + { + n_elem = 0; + if ( issubstr( s_craftable.name, "fire" ) ) + { + n_elem = 1; + } + else if ( issubstr( s_craftable.name, "air" ) ) + { + n_elem = 2; + } + else if ( issubstr( s_craftable.name, "lightning" ) ) + { + n_elem = 3; + } + else if ( issubstr( s_craftable.name, "water" ) ) + { + n_elem = 4; + } + else + { +/# + iprintlnbold( "ERROR: Unknown staff element type in craftable_add_glow_fx: " + s_craftable.name ); +#/ + return; + } + _a553 = s_craftable.a_piecestubs; + _k553 = getFirstArrayKey( _a553 ); + while ( isDefined( _k553 ) ) + { + s_piece = _a553[ _k553 ]; + if ( s_piece.piecename == "gem" ) + { + } + else + { + s_piece craftable_waittill_spawned(); + if ( n_elem != 3 ) + { + do_glow_now = n_elem == 2; + } + s_piece.piecespawn.model thread craftable_model_attach_glow( n_elem, do_glow_now ); + } + _k553 = getNextArrayKey( _a553, _k553 ); + } + } + _k519 = getNextArrayKey( _a519, _k519 ); + } +} + +craftable_model_attach_glow( n_elem, do_glow_now ) +{ + self endon( "death" ); + if ( !do_glow_now ) + { + self waittill( "staff_piece_glow" ); + } + self setclientfield( "element_glow_fx", n_elem ); +} + +tomb_staff_update_prompt( player, b_set_hint_string_now, trigger ) +{ + if ( isDefined( self.crafted ) && self.crafted ) + { + return 1; + } + self.hint_string = &"ZOMBIE_BUILD_PIECE_MORE"; + if ( isDefined( player ) ) + { + if ( !isDefined( player.current_craftable_piece ) ) + { + return 0; + } + if ( !self.craftablespawn craftable_has_piece( player.current_craftable_piece ) ) + { + self.hint_string = &"ZOMBIE_BUILD_PIECE_WRONG"; + return 0; + } + } + if ( level.staff_part_count[ self.craftablespawn.craftable_name ] == 0 ) + { + self.hint_string = level.zombie_craftablestubs[ self.equipname ].str_to_craft; + return 1; + } + else + { + return 0; + } +} + +init_craftable_choke() +{ + level.craftables_spawned_this_frame = 0; + while ( 1 ) + { + wait_network_frame(); + level.craftables_spawned_this_frame = 0; + } +} + +craftable_wait_your_turn() +{ + if ( !isDefined( level.craftables_spawned_this_frame ) ) + { + level thread init_craftable_choke(); + } + while ( level.craftables_spawned_this_frame >= 2 ) + { + wait_network_frame(); + } + level.craftables_spawned_this_frame++; +} + +quadrotorcraftable() +{ + craftable_wait_your_turn(); + maps/mp/zombies/_zm_craftables::craftable_trigger_think( "quadrotor_zm_craftable_trigger", "equip_dieseldrone_zm", "equip_dieseldrone_zm", &"ZM_TOMB_TQ", 1, 1 ); +} + +riotshieldcraftable() +{ + craftable_wait_your_turn(); + maps/mp/zombies/_zm_craftables::craftable_trigger_think( "riotshield_zm_craftable_trigger", "tomb_shield_zm", "tomb_shield_zm", &"ZOMBIE_GRAB_RIOTSHIELD", 1, 1 ); +} + +staffcraftable_air() +{ + craftable_wait_your_turn(); + maps/mp/zombies/_zm_craftables::craftable_trigger_think( "staff_air_craftable_trigger", "elemental_staff_air", "staff_air_zm", &"ZM_TOMB_PUAS", 1, 1 ); +} + +staffcraftable_fire() +{ + craftable_wait_your_turn(); + maps/mp/zombies/_zm_craftables::craftable_trigger_think( "staff_fire_craftable_trigger", "elemental_staff_fire", "staff_fire_zm", &"ZM_TOMB_PUFS", 1, 1 ); +} + +staffcraftable_lightning() +{ + craftable_wait_your_turn(); + maps/mp/zombies/_zm_craftables::craftable_trigger_think( "staff_lightning_craftable_trigger", "elemental_staff_lightning", "staff_lightning_zm", &"ZM_TOMB_PULS", 1, 1 ); +} + +staffcraftable_water() +{ + craftable_wait_your_turn(); + maps/mp/zombies/_zm_craftables::craftable_trigger_think( "staff_water_craftable_trigger", "elemental_staff_water", "staff_water_zm", &"ZM_TOMB_PUIS", 1, 1 ); +} + +gramophonecraftable() +{ + craftable_wait_your_turn(); + maps/mp/zombies/_zm_craftables::craftable_trigger_think( "gramophone_craftable_trigger", "gramophone", "gramophone", &"ZOMBIE_GRAB_GRAMOPHONE", 1, 1 ); +} + +tankcraftableupdateprompt( player, sethintstringnow, buildabletrigger ) +{ + if ( level.vh_tank getspeedmph() > 0 ) + { + if ( isDefined( self ) ) + { + self.hint_string = ""; + if ( isDefined( sethintstringnow ) && sethintstringnow && isDefined( buildabletrigger ) ) + { + buildabletrigger sethintstring( self.hint_string ); + } + } + return 0; + } + return 1; +} + +ondrop_common( player ) +{ + self.piece_owner = undefined; +} + +ondrop_crystal( player ) +{ + ondrop_common( player ); + s_piece = self.piecestub; + s_piece.piecespawn.canmove = 1; + maps/mp/zombies/_zm_unitrigger::reregister_unitrigger_as_dynamic( s_piece.piecespawn.unitrigger ); + s_original_pos = getstruct( ( self.craftablename + "_" ) + self.piecename ); + s_piece.piecespawn.unitrigger trigger_off(); + s_piece.piecespawn.model ghost(); + s_piece.piecespawn.model moveto( s_original_pos.origin, 0,05 ); + s_piece.piecespawn.model waittill( "movedone" ); + s_piece.piecespawn.model show(); + s_piece.piecespawn.unitrigger trigger_on(); +} + +ondrop_firecrystal( player ) +{ + level setclientfield( "piece_staff_zm_gem_fire", 0 ); + level setclientfield( "quest_state1", 1 ); + level setclientfield( "piece_record_zm_vinyl_fire", 0 ); + player clear_player_crystal( 1 ); + ondrop_crystal( player ); +} + +ondrop_aircrystal( player ) +{ + level setclientfield( "piece_staff_zm_gem_air", 0 ); + level setclientfield( "quest_state2", 1 ); + level setclientfield( "piece_record_zm_vinyl_air", 0 ); + player clear_player_crystal( 2 ); + ondrop_crystal( player ); +} + +ondrop_lightningcrystal( player ) +{ + level setclientfield( "piece_staff_zm_gem_lightning", 0 ); + level setclientfield( "quest_state3", 1 ); + level setclientfield( "piece_record_zm_vinyl_lightning", 0 ); + player clear_player_crystal( 3 ); + ondrop_crystal( player ); +} + +ondrop_watercrystal( player ) +{ + level setclientfield( "piece_staff_zm_gem_water", 0 ); + level setclientfield( "quest_state4", 1 ); + level setclientfield( "piece_record_zm_vinyl_water", 0 ); + player clear_player_crystal( 4 ); + ondrop_crystal( player ); +} + +clear_player_crystal( n_element ) +{ + if ( n_element == self.crystal_id ) + { + n_player = self getentitynumber() + 1; + level setclientfield( "staff_player" + n_player, 0 ); + self.crystal_id = 0; + } +} + +piece_pickup_conversation( player ) +{ + wait 1; + while ( isDefined( player.isspeaking ) && player.isspeaking ) + { + wait_network_frame(); + } + if ( isDefined( self.piecestub.vo_line_notify ) ) + { + level notify( "quest_progressed" ); + level notify( self.piecestub.vo_line_notify ); + } + else if ( isDefined( self.piecestub.sam_line ) ) + { + level notify( "quest_progressed" ); + level notify( self.piecestub.sam_line ); + } + else + { + level notify( "quest_progressed" ); + } +} + +onpickup_common( player ) +{ + player playsound( "zmb_craftable_pickup" ); + self.piece_owner = player; + self thread piece_pickup_conversation( player ); +/# + _a833 = self.spawns; + _k833 = getFirstArrayKey( _a833 ); + while ( isDefined( _k833 ) ) + { + spawn = _a833[ _k833 ]; + spawn notify( "stop_debug_position" ); + _k833 = getNextArrayKey( _a833, _k833 ); +#/ + } +} + +staff_pickup_vo() +{ + if ( !flag( "samantha_intro_done" ) ) + { + return; + } + if ( isDefined( level.sam_staff_line_played ) && !level.sam_staff_line_played ) + { + level.sam_staff_line_played = 1; + wait 1; + maps/mp/zm_tomb_vo::set_players_dontspeak( 1 ); + maps/mp/zm_tomb_vo::samanthasay( "vox_sam_1st_staff_found_1_0", self, 1 ); + maps/mp/zm_tomb_vo::samanthasay( "vox_sam_1st_staff_found_2_0", self ); + maps/mp/zm_tomb_vo::set_players_dontspeak( 0 ); + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "staff", "first_piece" ); + } +} + +onpickup_staffpiece( player ) +{ + onpickup_common( player ); + if ( !isDefined( level.num_staffpieces_picked_up[ self.craftablename ] ) ) + { + level.num_staffpieces_picked_up[ self.craftablename ] = 0; + } + level.num_staffpieces_picked_up[ self.craftablename ]++; + if ( level.num_staffpieces_picked_up[ self.craftablename ] == 3 ) + { + level notify( self.craftablename + "_all_pieces_found" ); + } + player thread staff_pickup_vo(); +} + +onpickup_crystal( player, elementname, elementenum ) +{ + onpickup_common( player ); + level setclientfield( "piece_staff_zm_gem_" + elementname, 1 ); + n_player = player getentitynumber() + 1; + level setclientfield( "staff_player" + n_player, elementenum ); + if ( flag( "any_crystal_picked_up" ) ) + { + self.piecestub.vox_id = undefined; + } + flag_set( "any_crystal_picked_up" ); +} + +onpickup_firecrystal( player ) +{ + level setclientfield( "quest_state1", 2 ); + player.crystal_id = 1; + onpickup_crystal( player, "fire", 1 ); +} + +onpickup_aircrystal( player ) +{ + level setclientfield( "quest_state2", 2 ); + player.crystal_id = 2; + onpickup_crystal( player, "air", 2 ); +} + +onpickup_lightningcrystal( player ) +{ + level setclientfield( "quest_state3", 2 ); + player.crystal_id = 3; + onpickup_crystal( player, "lightning", 3 ); +} + +onpickup_watercrystal( player ) +{ + level setclientfield( "quest_state4", 2 ); + player.crystal_id = 4; + onpickup_crystal( player, "water", 4 ); +} + +vinyl_add_pickup( str_craftable_name, str_piece_name, str_model_name, str_bit_clientfield, str_quest_clientfield, str_vox_id ) +{ + b_one_time_vo = 1; + craftable = generate_zombie_craftable_piece( str_craftable_name, str_piece_name, str_model_name, 32, 62, 0, undefined, ::onpickup_common, ::ondrop_common, undefined, undefined, undefined, undefined, str_bit_clientfield, 1, str_vox_id, b_one_time_vo ); + craftable thread watch_part_pickup( str_quest_clientfield, 1 ); + return craftable; +} + +watch_part_pickup( str_quest_clientfield, n_clientfield_val ) +{ + self craftable_waittill_spawned(); + self.piecespawn waittill( "pickup" ); + level notify( ( self.craftablename + "_" ) + self.piecename + "_picked_up" ); + if ( isDefined( str_quest_clientfield ) && isDefined( n_clientfield_val ) ) + { + level setclientfield( str_quest_clientfield, n_clientfield_val ); + } +} + +count_staff_piece_pickup( a_staff_pieces ) +{ + if ( !isDefined( level.staff_part_count ) ) + { + level.staff_part_count = []; + } + str_name = a_staff_pieces[ 0 ].craftablename; + level.staff_part_count[ str_name ] = a_staff_pieces.size; + _a963 = a_staff_pieces; + _k963 = getFirstArrayKey( _a963 ); + while ( isDefined( _k963 ) ) + { + piece = _a963[ _k963 ]; +/# + assert( piece.craftablename == str_name ); +#/ + piece thread watch_staff_pickup(); + _k963 = getNextArrayKey( _a963, _k963 ); + } +} + +craftable_waittill_spawned() +{ + while ( !isDefined( self.piecespawn ) ) + { + wait_network_frame(); + } +} + +watch_staff_pickup() +{ + self craftable_waittill_spawned(); + self.piecespawn waittill( "pickup" ); + level.staff_part_count[ self.craftablename ]--; + +} + +onfullycrafted_quadrotor( player ) +{ + level.quadrotor_status.crafted = 1; + pickup_trig = level.quadrotor_status.pickup_trig; + level.quadrotor_status.str_zone = maps/mp/zombies/_zm_zonemgr::get_zone_from_position( pickup_trig.origin, 1 ); + level.quadrotor_status.pickup_indicator = spawn( "script_model", pickup_trig.model.origin + vectorScale( ( 0, 0, 1 ), 10 ) ); + level.quadrotor_status.pickup_indicator setmodel( "p6_zm_tm_quadrotor_stand" ); + level notify( "quest_progressed" ); + return 1; +} + +onbuyweapon_riotshield( player ) +{ + if ( isDefined( player.player_shield_reset_health ) ) + { + player [[ player.player_shield_reset_health ]](); + } + if ( isDefined( player.player_shield_reset_location ) ) + { + player [[ player.player_shield_reset_location ]](); + } +} + +staff_fullycrafted( modelname, elementenum ) +{ + player = get_closest_player( self.origin ); + staff_model = getent( modelname, "targetname" ); + staff_info = get_staff_info_from_element_index( elementenum ); + staff_model useweaponmodel( staff_info.weapname ); + staff_model showallparts(); + level notify( "quest_progressed" ); + if ( !isDefined( staff_model.inused ) ) + { + staff_model show(); + staff_model.inused = 1; + level.n_staffs_crafted++; + if ( level.n_staffs_crafted == 4 ) + { + flag_set( "ee_all_staffs_crafted" ); + } + } + str_fieldname = "quest_state" + elementenum; + level setclientfield( str_fieldname, 3 ); + return 1; +} + +staff_fire_fullycrafted() +{ + level thread sndplaystaffstingeronce( "fire" ); + return staff_fullycrafted( "craftable_staff_fire_zm", 1 ); +} + +staff_air_fullycrafted() +{ + level thread sndplaystaffstingeronce( "wind" ); + return staff_fullycrafted( "craftable_staff_air_zm", 2 ); +} + +staff_lightning_fullycrafted() +{ + level thread sndplaystaffstingeronce( "lightning" ); + return staff_fullycrafted( "craftable_staff_lightning_zm", 3 ); +} + +staff_water_fullycrafted() +{ + level thread sndplaystaffstingeronce( "ice" ); + return staff_fullycrafted( "craftable_staff_water_zm", 4 ); +} + +sndplaystaffstingeronce( type ) +{ + if ( !isDefined( level.sndstaffbuilt ) ) + { + level.sndstaffbuilt = []; + } + if ( !isinarray( level.sndstaffbuilt, type ) ) + { + level.sndstaffbuilt[ level.sndstaffbuilt.size ] = type; + level thread maps/mp/zombies/_zm_audio::sndmusicstingerevent( "staff_" + type ); + } +} + +quadrotor_watcher( player ) +{ + quadrotor_set_unavailable(); + player thread quadrotor_return_condition_watcher(); + player thread quadrotor_control_thread(); + level waittill( "drone_available" ); + level.maxis_quadrotor = undefined; + if ( flag( "ee_quadrotor_disabled" ) ) + { + flag_waitopen( "ee_quadrotor_disabled" ); + } + quadrotor_set_available(); +} + +quadrotor_return_condition_watcher() +{ + self waittill_any( "bled_out", "disconnect" ); + if ( isDefined( level.maxis_quadrotor ) ) + { + level notify( "drone_should_return" ); + } + else + { + level notify( "drone_available" ); + } +} + +quadrotor_control_thread() +{ + self endon( "bled_out" ); + self endon( "disconnect" ); + while ( 1 ) + { + if ( self actionslottwobuttonpressed() && self hasweapon( "equip_dieseldrone_zm" ) ) + { + self waittill( "weapon_change_complete" ); + self playsound( "veh_qrdrone_takeoff" ); + weapons = self getweaponslistprimaries(); + self switchtoweapon( weapons[ 0 ] ); + self waittill( "weapon_change_complete" ); + if ( self hasweapon( "equip_dieseldrone_zm" ) ) + { + self takeweapon( "equip_dieseldrone_zm" ); + self setactionslot( 2, "" ); + } + str_vehicle = "heli_quadrotor_zm"; + if ( flag( "ee_maxis_drone_retrieved" ) ) + { + str_vehicle = "heli_quadrotor_upgraded_zm"; + } + qr = spawnvehicle( "veh_t6_dlc_zm_quadrotor", "quadrotor_ai", str_vehicle, self.origin + vectorScale( ( 0, 0, 1 ), 96 ), self.angles ); + level thread quadrotor_death_watcher( qr ); + qr thread quadrotor_instance_watcher( self ); + return; + } + wait 0,05; + } +} + +quadrotor_debug_send_home( player_owner ) +{ + self endon( "drone_should_return" ); + level endon( "drone_available" ); + while ( 1 ) + { + if ( player_owner actionslottwobuttonpressed() ) + { + self quadrotor_fly_back_to_table(); + } + wait 0,05; + } +} + +quadrotor_instance_watcher( player_owner ) +{ + self endon( "death" ); + self.player_owner = player_owner; + self.health = 200; + level.maxis_quadrotor = self; + self makevehicleunusable(); + self thread maps/mp/zombies/_zm_ai_quadrotor::quadrotor_think(); + self thread follow_ent( player_owner ); + self thread quadrotor_timer(); + level waittill( "drone_should_return" ); + self quadrotor_fly_back_to_table(); +} + +quadrotor_death_watcher( quadrotor ) +{ + level endon( "drone_available" ); + quadrotor waittill( "death" ); + level notify( "drone_available" ); +} + +quadrotor_fly_back_to_table() +{ + self endon( "death" ); + level endon( "drone_available" ); + if ( isDefined( self ) ) + { +/# + iprintln( "Maxis sez: time to bounce" ); +#/ + self.returning_home = 1; + self thread quadrotor_fly_back_to_table_timeout(); + self waittill_any( "attempting_return", "return_timeout" ); + } + if ( isDefined( self ) ) + { + self waittill_any( "near_goal", "force_goal", "reached_end_node", "return_timeout" ); + } + if ( isDefined( self ) ) + { + playfx( level._effect[ "tesla_elec_kill" ], self.origin ); + self playsound( "zmb_qrdrone_leave" ); + self delete(); +/# + iprintln( "Maxis deleted" ); +#/ + } + level notify( "drone_available" ); +} + +report_notify( str_notify ) +{ + self waittill( str_notify ); + iprintln( str_notify ); +} + +quadrotor_fly_back_to_table_timeout() +{ + self endon( "death" ); + level endon( "drone_available" ); + wait 30; + if ( isDefined( self ) ) + { + self delete(); +/# + iprintln( "Maxis deleted" ); +#/ + } + self notify( "return_timeout" ); +} + +quadrotor_timer() +{ + self endon( "death" ); + level endon( "drone_available" ); + wait 80; + vox_line = "vox_maxi_drone_cool_down_" + randomintrange( 0, 2 ); + self thread maps/mp/zm_tomb_vo::maxissay( vox_line, self ); + wait 10; + vox_line = "vox_maxi_drone_cool_down_2"; + self thread maps/mp/zm_tomb_vo::maxissay( vox_line, self ); + level notify( "drone_should_return" ); +} + +quadrotor_set_available() +{ +/# + iprintln( "Quad returned to table" ); +#/ + playfx( level._effect[ "tesla_elec_kill" ], level.quadrotor_status.pickup_trig.model.origin ); + level.quadrotor_status.pickup_trig.model playsound( "zmb_qrdrone_leave" ); + level.quadrotor_status.picked_up = 0; + level.quadrotor_status.pickup_trig.model show(); + flag_set( "quadrotor_cooling_down" ); + str_zone = level.quadrotor_status.str_zone; + switch( str_zone ) + { + case "zone_nml_9": + setclientfield( "cooldown_steam", 1 ); + break; + case "zone_bunker_5a": + setclientfield( "cooldown_steam", 2 ); + break; + case "zone_village_1": + setclientfield( "cooldown_steam", 3 ); + break; + } + vox_line = "vox_maxi_drone_cool_down_3"; + thread maxissay( vox_line, level.quadrotor_status.pickup_trig.model ); + wait 60; + flag_clear( "quadrotor_cooling_down" ); + setclientfield( "cooldown_steam", 0 ); + level.quadrotor_status.pickup_trig trigger_on(); + vox_line = "vox_maxi_drone_cool_down_4"; + maxissay( vox_line, level.quadrotor_status.pickup_trig.model ); +} + +quadrotor_set_unavailable() +{ + level.quadrotor_status.picked_up = 1; + level.quadrotor_status.pickup_trig trigger_off(); + level.quadrotor_status.pickup_trig.model ghost(); +} + +sqcommoncraftable() +{ + level.sq_craftable = maps/mp/zombies/_zm_craftables::craftable_trigger_think( "sq_common_craftable_trigger", "sq_common", "sq_common", "", 1, 0 ); +} + +droponmover( player ) +{ +} + +pickupfrommover() +{ +} + +setup_quadrotor_purchase( player ) +{ + if ( self.stub.weaponname == "equip_dieseldrone_zm" ) + { + if ( players_has_weapon( "equip_dieseldrone_zm" ) ) + { + return 1; + } + quadrotor = getentarray( "quadrotor_ai", "targetname" ); + if ( quadrotor.size >= 1 ) + { + return 1; + } + quadrotor_set_unavailable(); + player giveweapon( "equip_dieseldrone_zm" ); + player setweaponammoclip( "equip_dieseldrone_zm", 1 ); + player playsoundtoplayer( "zmb_buildable_pickup_complete", player ); + if ( isDefined( self.stub.craftablestub.use_actionslot ) ) + { + player setactionslot( self.stub.craftablestub.use_actionslot, "weapon", "equip_dieseldrone_zm" ); + } + else + { + player setactionslot( 2, "weapon", "equip_dieseldrone_zm" ); + } + player notify( "equip_dieseldrone_zm_given" ); + level thread quadrotor_watcher( player ); + player thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "build_dd_plc" ); + return 1; + } + return 0; +} + +players_has_weapon( weaponname ) +{ + players = getplayers(); + i = 0; + while ( i < players.size ) + { + if ( players[ i ] hasweapon( weaponname ) ) + { + return 1; + } + i++; + } + return 0; +} + +tomb_custom_craftable_validation( player ) +{ + if ( self.stub.equipname == "equip_dieseldrone_zm" ) + { + level.quadrotor_status.pickup_trig = self.stub; + if ( level.quadrotor_status.crafted ) + { + if ( !level.quadrotor_status.picked_up ) + { + return !flag( "quadrotor_cooling_down" ); + } + } + } + if ( !issubstr( self.stub.weaponname, "staff" ) ) + { + return 1; + } + str_craftable = self.stub.equipname; + if ( isDefined( level.craftables_crafted[ str_craftable ] ) && !level.craftables_crafted[ str_craftable ] ) + { + return 1; + } + if ( !player can_pickup_staff() ) + { + return 0; + } + s_elemental_staff = get_staff_info_from_weapon_name( self.stub.weaponname, 0 ); + str_weapon_check = s_elemental_staff.weapname; + a_weapons = player getweaponslistprimaries(); + _a1488 = a_weapons; + _k1488 = getFirstArrayKey( _a1488 ); + while ( isDefined( _k1488 ) ) + { + weapon = _a1488[ _k1488 ]; + if ( issubstr( weapon, "staff" ) && weapon != str_weapon_check ) + { + player takeweapon( weapon ); + } + _k1488 = getNextArrayKey( _a1488, _k1488 ); + } + return 1; +} + +tomb_check_crafted_weapon_persistence( player ) +{ + if ( self.stub.equipname == "equip_dieseldrone_zm" ) + { + if ( level.quadrotor_status.picked_up ) + { + return 1; + } + else + { + if ( level.quadrotor_status.crafted ) + { + return 0; + } + } + } + else + { + if ( self.stub.weaponname != "staff_air_zm" && self.stub.weaponname != "staff_fire_zm" || self.stub.weaponname == "staff_lightning_zm" && self.stub.weaponname == "staff_water_zm" ) + { + if ( self is_unclaimed_staff_weapon( self.stub.weaponname ) ) + { + s_elemental_staff = get_staff_info_from_weapon_name( self.stub.weaponname, 0 ); + player maps/mp/zombies/_zm_weapons::weapon_give( s_elemental_staff.weapname, 0, 0 ); + if ( isDefined( s_elemental_staff.prev_ammo_stock ) && isDefined( s_elemental_staff.prev_ammo_clip ) ) + { + player setweaponammostock( s_elemental_staff.weapname, s_elemental_staff.prev_ammo_stock ); + player setweaponammoclip( s_elemental_staff.weapname, s_elemental_staff.prev_ammo_clip ); + } + if ( isDefined( level.zombie_craftablestubs[ self.stub.equipname ].str_taken ) ) + { + self.stub.hint_string = level.zombie_craftablestubs[ self.stub.equipname ].str_taken; + } + else + { + self.stub.hint_string = ""; + } + self sethintstring( self.stub.hint_string ); + player track_craftables_pickedup( self.stub.craftablespawn ); + model = getent( "craftable_" + self.stub.weaponname, "targetname" ); + model ghost(); + self.stub thread track_crafted_staff_trigger(); + self.stub thread track_staff_weapon_respawn( player ); + set_player_staff( self.stub.weaponname, player ); + } + else + { + self.stub.hint_string = ""; + self sethintstring( self.stub.hint_string ); + } + return 1; + } + } + return 0; +} + +is_unclaimed_staff_weapon( str_weapon ) +{ + if ( !maps/mp/zombies/_zm_equipment::is_limited_equipment( str_weapon ) ) + { + return 1; + } + else + { + s_elemental_staff = get_staff_info_from_weapon_name( str_weapon, 0 ); + str_weapon_check = s_elemental_staff.weapname; + players = get_players(); + _a1573 = players; + _k1573 = getFirstArrayKey( _a1573 ); + while ( isDefined( _k1573 ) ) + { + player = _a1573[ _k1573 ]; + if ( isDefined( player ) && player has_weapon_or_upgrade( str_weapon_check ) ) + { + return 0; + } + _k1573 = getNextArrayKey( _a1573, _k1573 ); + } + } + return 1; +} + +get_staff_info_from_weapon_name( str_name, b_base_info_only ) +{ + if ( !isDefined( b_base_info_only ) ) + { + b_base_info_only = 1; + } + _a1592 = level.a_elemental_staffs; + _k1592 = getFirstArrayKey( _a1592 ); + while ( isDefined( _k1592 ) ) + { + s_staff = _a1592[ _k1592 ]; + if ( s_staff.weapname == str_name || s_staff.upgrade.weapname == str_name ) + { + if ( s_staff.charger.is_charged && !b_base_info_only ) + { + return s_staff.upgrade; + } + else + { + return s_staff; + } + } + _k1592 = getNextArrayKey( _a1592, _k1592 ); + } + return undefined; +} + +get_staff_info_from_element_index( n_index ) +{ + _a1612 = level.a_elemental_staffs; + _k1612 = getFirstArrayKey( _a1612 ); + while ( isDefined( _k1612 ) ) + { + s_staff = _a1612[ _k1612 ]; + if ( s_staff.enum == n_index ) + { + return s_staff; + } + _k1612 = getNextArrayKey( _a1612, _k1612 ); + } + return undefined; +} + +track_crafted_staff_trigger() +{ + s_elemental_staff = get_staff_info_from_weapon_name( self.weaponname, 1 ); + if ( !isDefined( self.base_weaponname ) ) + { + self.base_weaponname = s_elemental_staff.weapname; + } + flag_waitopen( self.base_weaponname + "_enabled" ); + self trigger_off(); + flag_wait( self.base_weaponname + "_enabled" ); + self trigger_on(); +} + +track_staff_weapon_respawn( player ) +{ + self notify( "kill_track_staff_weapon_respawn" ); + self endon( "kill_track_staff_weapon_respawn" ); + s_elemental_staff = get_staff_info_from_weapon_name( self.weaponname, 1 ); + s_upgraded_staff = s_elemental_staff.upgrade; + if ( !isDefined( self.base_weaponname ) ) + { + self.base_weaponname = s_elemental_staff.weapname; + } + flag_clear( self.base_weaponname + "_enabled" ); + has_weapon = 0; + while ( isalive( player ) ) + { + if ( isDefined( s_elemental_staff.charger.is_inserted ) && !s_elemental_staff.charger.is_inserted && isDefined( s_upgraded_staff.charger.is_inserted ) || s_upgraded_staff.charger.is_inserted && isDefined( s_upgraded_staff.ee_in_use ) && s_upgraded_staff.ee_in_use ) + { + has_weapon = 1; + } + else + { + weapons = player getweaponslistprimaries(); + _a1672 = weapons; + _k1672 = getFirstArrayKey( _a1672 ); + while ( isDefined( _k1672 ) ) + { + weapon = _a1672[ _k1672 ]; + n_melee_element = 0; + if ( weapon == self.base_weaponname ) + { + s_elemental_staff.prev_ammo_stock = player getweaponammostock( weapon ); + s_elemental_staff.prev_ammo_clip = player getweaponammoclip( weapon ); + has_weapon = 1; + } + else + { + if ( weapon == s_upgraded_staff.weapname ) + { + s_upgraded_staff.prev_ammo_stock = player getweaponammostock( weapon ); + s_upgraded_staff.prev_ammo_clip = player getweaponammoclip( weapon ); + has_weapon = 1; + n_melee_element = s_upgraded_staff.enum; + } + } + if ( player hasweapon( "staff_revive_zm" ) ) + { + s_upgraded_staff.revive_ammo_stock = player getweaponammostock( "staff_revive_zm" ); + s_upgraded_staff.revive_ammo_clip = player getweaponammoclip( "staff_revive_zm" ); + } + if ( has_weapon && isDefined( player.one_inch_punch_flag_has_been_init ) && !player.one_inch_punch_flag_has_been_init && n_melee_element != 0 ) + { + cur_weapon = player getcurrentweapon(); + if ( cur_weapon != weapon && isDefined( player.use_staff_melee ) && player.use_staff_melee ) + { + player update_staff_accessories( 0 ); + break; + } + else + { + if ( cur_weapon == weapon && isDefined( player.use_staff_melee ) && !player.use_staff_melee ) + { + player update_staff_accessories( n_melee_element ); + } + } + } + _k1672 = getNextArrayKey( _a1672, _k1672 ); + } + } + if ( !has_weapon ) + { + break; + } + else + { + wait 0,5; + has_weapon = 0; + } + } + b_staff_in_use = 0; + a_players = getplayers(); + _a1725 = a_players; + _k1725 = getFirstArrayKey( _a1725 ); + while ( isDefined( _k1725 ) ) + { + check_player = _a1725[ _k1725 ]; + weapons = check_player getweaponslistprimaries(); + _a1728 = weapons; + _k1728 = getFirstArrayKey( _a1728 ); + while ( isDefined( _k1728 ) ) + { + weapon = _a1728[ _k1728 ]; + if ( weapon == self.base_weaponname || weapon == s_upgraded_staff.weapname ) + { + b_staff_in_use = 1; + } + _k1728 = getNextArrayKey( _a1728, _k1728 ); + } + _k1725 = getNextArrayKey( _a1725, _k1725 ); + } + if ( !b_staff_in_use ) + { + model = getent( "craftable_" + self.base_weaponname, "targetname" ); + model show(); + flag_set( self.base_weaponname + "_enabled" ); + } + clear_player_staff( self.base_weaponname, player ); +} + +set_player_staff( str_weaponname, e_player ) +{ + s_staff = get_staff_info_from_weapon_name( str_weaponname ); + s_staff.e_owner = e_player; + n_player = e_player getentitynumber() + 1; + e_player.staff_enum = s_staff.enum; + level setclientfield( "staff_player" + n_player, s_staff.enum ); + e_player update_staff_accessories( s_staff.enum ); +/# + iprintlnbold( "Player " + n_player + " has staff " + s_staff.enum ); +#/ +} + +clear_player_staff_by_player_number( n_player ) +{ + level setclientfield( "staff_player" + n_player, 0 ); +} + +clear_player_staff( str_weaponname, e_owner ) +{ + s_staff = get_staff_info_from_weapon_name( str_weaponname ); + if ( isDefined( e_owner ) && isDefined( s_staff.e_owner ) && e_owner != s_staff.e_owner ) + { + return; + } + if ( !isDefined( e_owner ) ) + { + e_owner = s_staff.e_owner; + } + if ( isDefined( e_owner ) ) + { + if ( !isDefined( e_owner.staff_enum ) || !isDefined( s_staff.enum ) && isDefined( e_owner.staff_enum ) && isDefined( s_staff.enum ) && e_owner.staff_enum == s_staff.enum ) + { + n_player = e_owner getentitynumber() + 1; + e_owner.staff_enum = 0; + level setclientfield( "staff_player" + n_player, 0 ); + e_owner update_staff_accessories( 0 ); + } + } +/# + iprintlnbold( "Nobody has staff " + s_staff.enum ); +#/ + s_staff.e_owner = undefined; +} + +hide_staff_model() +{ + staffs = getentarray( "craftable_staff_model", "script_noteworthy" ); + _a1816 = staffs; + _k1816 = getFirstArrayKey( _a1816 ); + while ( isDefined( _k1816 ) ) + { + stave = _a1816[ _k1816 ]; + stave ghost(); + _k1816 = getNextArrayKey( _a1816, _k1816 ); + } +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_dig.gsc b/zm_tomb_patch/maps/mp/zm_tomb_dig.gsc new file mode 100644 index 0000000..e074dab --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_dig.gsc @@ -0,0 +1,1034 @@ +#include maps/mp/zombies/_zm_powerup_zombie_blood; +#include maps/mp/zombies/_zm_weap_claymore; +#include maps/mp/zombies/_zm_powerups; +#include maps/mp/zm_tomb_main_quest; +#include maps/mp/zombies/_zm_stats; +#include maps/mp/zombies/_zm_zonemgr; +#include maps/mp/zombies/_zm_audio_announcer; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_unitrigger; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init_shovel() +{ + precachemodel( "p6_zm_tm_dig_mound" ); + precachemodel( "p6_zm_tm_dig_mound_blood" ); + precachemodel( "p6_zm_tm_shovel" ); + precachemodel( "zombie_pickup_perk_bottle" ); + precachemodel( "t6_wpn_claymore_world" ); + maps/mp/zombies/_zm_audio_announcer::createvox( "blood_money", "powerup_blood_money" ); + onplayerconnect_callback( ::init_shovel_player ); + a_shovel_pos = getstructarray( "shovel_location", "targetname" ); + a_shovel_zone = []; + _a45 = a_shovel_pos; + _k45 = getFirstArrayKey( _a45 ); + while ( isDefined( _k45 ) ) + { + s_shovel_pos = _a45[ _k45 ]; + if ( !isDefined( a_shovel_zone[ s_shovel_pos.script_noteworthy ] ) ) + { + a_shovel_zone[ s_shovel_pos.script_noteworthy ] = []; + } + a_shovel_zone[ s_shovel_pos.script_noteworthy ][ a_shovel_zone[ s_shovel_pos.script_noteworthy ].size ] = s_shovel_pos; + _k45 = getNextArrayKey( _a45, _k45 ); + } + _a55 = a_shovel_zone; + _k55 = getFirstArrayKey( _a55 ); + while ( isDefined( _k55 ) ) + { + a_zone = _a55[ _k55 ]; + s_pos = a_zone[ randomint( a_zone.size ) ]; + m_shovel = spawn( "script_model", s_pos.origin ); + m_shovel.angles = s_pos.angles; + m_shovel setmodel( "p6_zm_tm_shovel" ); + generate_shovel_unitrigger( m_shovel ); + _k55 = getNextArrayKey( _a55, _k55 ); + } + level.get_player_perk_purchase_limit = ::get_player_perk_purchase_limit; + level.bonus_points_powerup_override = ::bonus_points_powerup_override; + level thread dig_powerups_tracking(); + level thread dig_spots_init(); + registerclientfield( "world", "shovel_player1", 14000, 2, "int", undefined, 0 ); + registerclientfield( "world", "shovel_player2", 14000, 2, "int", undefined, 0 ); + registerclientfield( "world", "shovel_player3", 14000, 2, "int", undefined, 0 ); + registerclientfield( "world", "shovel_player4", 14000, 2, "int", undefined, 0 ); + registerclientfield( "world", "helmet_player1", 14000, 1, "int", undefined, 0 ); + registerclientfield( "world", "helmet_player2", 14000, 1, "int", undefined, 0 ); + registerclientfield( "world", "helmet_player3", 14000, 1, "int", undefined, 0 ); + registerclientfield( "world", "helmet_player4", 14000, 1, "int", undefined, 0 ); +/# + level thread setup_dig_devgui(); +#/ +} + +init_shovel_player() +{ + self.dig_vars[ "has_shovel" ] = 0; + self.dig_vars[ "has_upgraded_shovel" ] = 0; + self.dig_vars[ "has_helmet" ] = 0; + self.dig_vars[ "n_spots_dug" ] = 0; + self.dig_vars[ "n_losing_streak" ] = 0; +} + +generate_shovel_unitrigger( e_shovel ) +{ + s_unitrigger_stub = spawnstruct(); + s_unitrigger_stub.origin = e_shovel.origin + vectorScale( ( 0, 0, -1 ), 32 ); + s_unitrigger_stub.angles = e_shovel.angles; + s_unitrigger_stub.radius = 32; + s_unitrigger_stub.script_length = 64; + s_unitrigger_stub.script_width = 64; + s_unitrigger_stub.script_height = 64; + s_unitrigger_stub.cursor_hint = "HINT_NOICON"; + s_unitrigger_stub.hint_string = &"ZM_TOMB_SHPU"; + s_unitrigger_stub.script_unitrigger_type = "unitrigger_box_use"; + s_unitrigger_stub.require_look_at = 1; + s_unitrigger_stub.prompt_and_visibility_func = ::shovel_trigger_prompt_and_visiblity; + s_unitrigger_stub.e_shovel = e_shovel; + unitrigger_force_per_player_triggers( s_unitrigger_stub, 1 ); + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( s_unitrigger_stub, ::shovel_unitrigger_think ); +} + +shovel_trigger_prompt_and_visiblity( e_player ) +{ + can_use = self.stub shovel_prompt_update( e_player ); + self setinvisibletoplayer( e_player, !can_use ); + self sethintstring( self.stub.hint_string ); + return can_use; +} + +shovel_prompt_update( e_player ) +{ + if ( !self unitrigger_stub_show_hint_prompt_valid( e_player ) ) + { + return 0; + } + self.hint_string = &"ZM_TOMB_SHPU"; + if ( isDefined( e_player.dig_vars[ "has_shovel" ] ) && e_player.dig_vars[ "has_shovel" ] ) + { + self.hint_string = &"ZM_TOMB_SHAG"; + } + return 1; +} + +shovel_unitrigger_think() +{ + self endon( "kill_trigger" ); + while ( 1 ) + { + self waittill( "trigger", e_player ); + while ( e_player != self.parent_player ) + { + continue; + } + if ( isDefined( e_player.dig_vars[ "has_shovel" ] ) && !e_player.dig_vars[ "has_shovel" ] ) + { + e_player.dig_vars[ "has_shovel" ] = 1; + e_player playsound( "zmb_craftable_pickup" ); + e_player dig_reward_dialog( "pickup_shovel" ); + n_player = e_player getentitynumber() + 1; + level setclientfield( "shovel_player" + n_player, 1 ); + e_player thread dig_disconnect_watch( n_player, self.stub.e_shovel.origin, self.stub.e_shovel.angles ); + self.stub.e_shovel delete(); + maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( self.stub ); + } + } +} + +dig_reward_dialog( str_category ) +{ + if ( isDefined( self.dig_vo_cooldown ) && !self.dig_vo_cooldown ) + { + self do_player_general_vox( "digging", str_category ); + if ( str_category != "pickup_shovel" ) + { + self thread dig_reward_vo_cooldown(); + } + } +} + +dig_reward_vo_cooldown() +{ + self endon( "disconnect" ); + self.dig_vo_cooldown = 1; + wait 60; + self.dig_vo_cooldown = undefined; +} + +unitrigger_stub_show_hint_prompt_valid( e_player ) +{ + if ( !is_player_valid( e_player ) ) + { + self.hint_string = ""; + return 0; + } + return 1; +} + +dig_disconnect_watch( n_player, v_origin, v_angles ) +{ + self waittill( "disconnect" ); + level setclientfield( "shovel_player" + n_player, 0 ); + level setclientfield( "helmet_player" + n_player, 0 ); + m_shovel = spawn( "script_model", v_origin ); + m_shovel.angles = v_angles; + m_shovel setmodel( "p6_zm_tm_shovel" ); + generate_shovel_unitrigger( m_shovel ); +} + +dig_spots_init() +{ + flag_wait( "start_zombie_round_logic" ); + level.n_dig_spots_cur = 0; + level.n_dig_spots_max = 15; + level.a_dig_spots = getstructarray( "dig_spot", "targetname" ); + _a242 = level.a_dig_spots; + _k242 = getFirstArrayKey( _a242 ); + while ( isDefined( _k242 ) ) + { + s_dig_spot = _a242[ _k242 ]; + if ( !isDefined( s_dig_spot.angles ) ) + { + s_dig_spot.angles = ( 0, 0, -1 ); + } + if ( isDefined( s_dig_spot.script_noteworthy ) && s_dig_spot.script_noteworthy == "initial_spot" ) + { + s_dig_spot thread dig_spot_spawn(); + } + else + { + s_dig_spot.dug = 1; + } + s_dig_spot.str_zone = maps/mp/zombies/_zm_zonemgr::get_zone_from_position( s_dig_spot.origin + vectorScale( ( 0, 0, -1 ), 32 ), 1 ); + if ( !isDefined( s_dig_spot.str_zone ) ) + { + s_dig_spot.str_zone = ""; +/# + assertmsg( "Dig spot at ( " + s_dig_spot.origin[ 0 ] + ", " + s_dig_spot.origin[ 1 ] + ", " + s_dig_spot.origin[ 2 ] + ") is not in a zone." ); +#/ + } + wait_network_frame(); + _k242 = getNextArrayKey( _a242, _k242 ); + } + level thread dig_spots_respawn(); +} + +dig_spots_respawn( a_dig_spots ) +{ + while ( 1 ) + { + level waittill( "end_of_round" ); + wait 2; + a_dig_spots = array_randomize( level.a_dig_spots ); + n_respawned = 0; + n_respawned_max = 3; + if ( level.weather_snow > 0 ) + { + n_respawned_max = 0; + } + else + { + if ( level.weather_rain > 0 ) + { + n_respawned_max = 5; + } + } + if ( level.weather_snow == 0 ) + { + n_respawned_max += randomint( get_players().size ); + } + i = 0; + while ( i < a_dig_spots.size ) + { + if ( isDefined( a_dig_spots[ i ].dug ) && a_dig_spots[ i ].dug && n_respawned < n_respawned_max && level.n_dig_spots_cur <= level.n_dig_spots_max ) + { + a_dig_spots[ i ].dug = undefined; + a_dig_spots[ i ] thread dig_spot_spawn(); + wait_network_frame(); + n_respawned++; + } + i++; + } + while ( level.weather_snow > 0 && level.ice_staff_pieces.size > 0 ) + { + _a316 = level.ice_staff_pieces; + _k316 = getFirstArrayKey( _a316 ); + while ( isDefined( _k316 ) ) + { + s_staff = _a316[ _k316 ]; + a_staff_spots = []; + n_active_mounds = 0; + _a321 = level.a_dig_spots; + _k321 = getFirstArrayKey( _a321 ); + while ( isDefined( _k321 ) ) + { + s_dig_spot = _a321[ _k321 ]; + if ( isDefined( s_dig_spot.str_zone ) && issubstr( s_dig_spot.str_zone, s_staff.zone_substr ) ) + { + if ( isDefined( s_dig_spot.dug ) && !s_dig_spot.dug ) + { + n_active_mounds++; + break; + } + else + { + a_staff_spots[ a_staff_spots.size ] = s_dig_spot; + } + } + _k321 = getNextArrayKey( _a321, _k321 ); + } + if ( n_active_mounds < 2 && a_staff_spots.size > 0 && level.n_dig_spots_cur <= level.n_dig_spots_max ) + { + n_index = randomint( a_staff_spots.size ); + a_staff_spots[ n_index ].dug = undefined; + a_staff_spots[ n_index ] thread dig_spot_spawn(); + arrayremoveindex( a_staff_spots, n_index ); + n_active_mounds++; + wait_network_frame(); + } + _k316 = getNextArrayKey( _a316, _k316 ); + } + } + } +} + +dig_spot_spawn() +{ + level.n_dig_spots_cur++; + self.m_dig = spawn( "script_model", self.origin + vectorScale( ( 0, 0, -1 ), 40 ) ); + self.m_dig setmodel( "p6_zm_tm_dig_mound" ); + self.m_dig.angles = self.angles; + self.m_dig moveto( self.origin, 3, 0, 1 ); + self.m_dig waittill( "movedone" ); + t_dig = tomb_spawn_trigger_radius( self.origin + vectorScale( ( 0, 0, -1 ), 20 ), 100, 1 ); + t_dig.prompt_and_visibility_func = ::dig_spot_trigger_visibility; + t_dig.require_look_at = 1; + t_dig waittill_dug( self ); + t_dig tomb_unitrigger_delete(); + t_dig = undefined; + self.m_dig delete(); + self.m_dig = undefined; +} + +dig_spot_trigger_visibility( player ) +{ + if ( isDefined( player.dig_vars[ "has_shovel" ] ) && player.dig_vars[ "has_shovel" ] ) + { + self sethintstring( &"ZM_TOMB_X2D" ); + } + else + { + self sethintstring( &"ZM_TOMB_NS" ); + } + return 1; +} + +waittill_dug( s_dig_spot ) +{ + while ( 1 ) + { + self waittill( "trigger", player ); + if ( isDefined( player.dig_vars[ "has_shovel" ] ) && player.dig_vars[ "has_shovel" ] ) + { + player playsound( "evt_dig" ); + s_dig_spot.dug = 1; + level.n_dig_spots_cur--; + + playfx( level._effect[ "digging" ], self.origin ); + player setclientfieldtoplayer( "player_rumble_and_shake", 1 ); + player maps/mp/zombies/_zm_stats::increment_client_stat( "tomb_dig", 0 ); + player maps/mp/zombies/_zm_stats::increment_player_stat( "tomb_dig" ); + s_staff_piece = s_dig_spot maps/mp/zm_tomb_main_quest::dig_spot_get_staff_piece( player ); + if ( isDefined( s_staff_piece ) ) + { + s_staff_piece maps/mp/zm_tomb_main_quest::show_ice_staff_piece( self.origin ); + player dig_reward_dialog( "dig_staff_part" ); + } + else n_good_chance = 50; + if ( player.dig_vars[ "n_spots_dug" ] == 0 || player.dig_vars[ "n_losing_streak" ] == 3 ) + { + player.dig_vars[ "n_losing_streak" ] = 0; + n_good_chance = 100; + } + if ( player.dig_vars[ "has_upgraded_shovel" ] ) + { + if ( !player.dig_vars[ "has_helmet" ] ) + { + n_helmet_roll = randomint( 100 ); + if ( n_helmet_roll >= 95 ) + { + player.dig_vars[ "has_helmet" ] = 1; + n_player = player getentitynumber() + 1; + level setclientfield( "helmet_player" + n_player, 1 ); + player playsoundtoplayer( "zmb_squest_golden_anything", player ); + player maps/mp/zombies/_zm_stats::increment_client_stat( "tomb_golden_hard_hat", 0 ); + player maps/mp/zombies/_zm_stats::increment_player_stat( "tomb_golden_hard_hat" ); + return; + } + } + n_good_chance = 70; + } + n_prize_roll = randomint( 100 ); + if ( n_prize_roll > n_good_chance ) + { + if ( cointoss() ) + { + player dig_reward_dialog( "dig_grenade" ); + self thread dig_up_grenade( player ); + } + else + { + player dig_reward_dialog( "dig_zombie" ); + self thread dig_up_zombie( player, s_dig_spot ); + } + player.dig_vars[ "n_losing_streak" ]++; + } + else if ( cointoss() ) + { + self thread dig_up_powerup( player ); + } + else + { + player dig_reward_dialog( "dig_gun" ); + self thread dig_up_weapon( player ); + } + if ( !player.dig_vars[ "has_upgraded_shovel" ] ) + { + player.dig_vars[ "n_spots_dug" ]++; + if ( player.dig_vars[ "n_spots_dug" ] >= 30 ) + { + player.dig_vars[ "has_upgraded_shovel" ] = 1; + player thread ee_zombie_blood_dig(); + n_player = player getentitynumber() + 1; + level setclientfield( "shovel_player" + n_player, 2 ); + player playsoundtoplayer( "zmb_squest_golden_anything", player ); + player maps/mp/zombies/_zm_stats::increment_client_stat( "tomb_golden_shovel", 0 ); + player maps/mp/zombies/_zm_stats::increment_player_stat( "tomb_golden_shovel" ); + } + } + return; + } + } +} + +dig_up_zombie( player, s_dig_spot ) +{ + ai_zombie = spawn_zombie( level.dig_spawners[ 0 ] ); + ai_zombie endon( "death" ); + ai_zombie ghost(); + e_linker = spawn( "script_origin", ( 0, 0, -1 ) ); + e_linker.origin = ai_zombie.origin; + e_linker.angles = ai_zombie.angles; + ai_zombie linkto( e_linker ); + e_linker moveto( player.origin + vectorScale( ( 0, 0, -1 ), 100 ), 0,1 ); + e_linker waittill( "movedone" ); + ai_zombie unlink(); + e_linker delete(); + ai_zombie show(); + ai_zombie playsound( "evt_zombie_dig_dirt" ); + ai_zombie dug_zombie_rise( s_dig_spot ); + find_flesh_struct_string = "find_flesh"; + ai_zombie notify( "zombie_custom_think_done" ); +} + +dig_up_powerup( player ) +{ + powerup = spawn( "script_model", self.origin ); + powerup endon( "powerup_grabbed" ); + powerup endon( "powerup_timedout" ); + a_rare_powerups = dig_get_rare_powerups( player ); + powerup_item = undefined; + if ( ( level.dig_n_powerups_spawned + level.powerup_drop_count ) > 4 && !level.dig_last_prize_rare || a_rare_powerups.size == 0 && randomint( 100 ) < 80 ) + { + if ( level.dig_n_zombie_bloods_spawned < 1 && randomint( 100 ) > 70 ) + { + powerup_item = "zombie_blood"; + level.dig_n_zombie_bloods_spawned++; + level.dig_n_powerups_spawned++; + player dig_reward_dialog( "dig_powerup" ); + } + else + { + powerup_item = "bonus_points_player"; + player dig_reward_dialog( "dig_cash" ); + } + level.dig_last_prize_rare = 0; + } + else + { + powerup_item = a_rare_powerups[ randomint( a_rare_powerups.size ) ]; + level.dig_last_prize_rare = 1; + level.dig_n_powerups_spawned++; + player dig_reward_dialog( "dig_powerup" ); + dig_set_powerup_spawned( powerup_item ); + } + powerup maps/mp/zombies/_zm_powerups::powerup_setup( powerup_item ); + powerup movez( 40, 0,6 ); + powerup waittill( "movedone" ); + powerup thread maps/mp/zombies/_zm_powerups::powerup_timeout(); + powerup thread maps/mp/zombies/_zm_powerups::powerup_wobble(); + powerup thread maps/mp/zombies/_zm_powerups::powerup_grab(); +} + +dig_get_rare_powerups( player ) +{ + a_rare_powerups = []; + a_possible_powerups = array( "nuke", "double_points" ); + if ( level.dig_magic_box_moved && !dig_has_powerup_spawned( "fire_sale" ) ) + { + a_possible_powerups[ a_possible_powerups.size ] = "fire_sale"; + } + if ( player.dig_vars[ "has_upgraded_shovel" ] ) + { + a_possible_powerups = combinearrays( a_possible_powerups, array( "insta_kill", "full_ammo" ) ); + } + _a639 = a_possible_powerups; + _k639 = getFirstArrayKey( _a639 ); + while ( isDefined( _k639 ) ) + { + powerup = _a639[ _k639 ]; + if ( !dig_has_powerup_spawned( powerup ) ) + { + a_rare_powerups[ a_rare_powerups.size ] = powerup; + } + _k639 = getNextArrayKey( _a639, _k639 ); + } + return a_rare_powerups; +} + +dig_up_grenade( player ) +{ + player endon( "disconnect" ); + v_spawnpt = self.origin; + grenade = "frag_grenade_zm"; + n_rand = randomintrange( 0, 4 ); + player magicgrenadetype( grenade, v_spawnpt, vectorScale( ( 0, 0, -1 ), 300 ), 3 ); + player playsound( "evt_grenade_digup" ); + if ( n_rand ) + { + wait 0,3; + if ( cointoss() ) + { + player magicgrenadetype( grenade, v_spawnpt, ( 50, 50, 300 ), 3 ); + } + } +} + +dig_up_weapon( digger ) +{ + a_common_weapons = array( "ballista_zm", "c96_zm", "870mcs_zm" ); + a_rare_weapons = array( "dsr50_zm", "srm1216_zm" ); + if ( digger.dig_vars[ "has_upgraded_shovel" ] ) + { + a_rare_weapons = combinearrays( a_rare_weapons, array( "claymore_zm", "ak74u_zm", "ksg_zm", "mp40_zm", "mp44_zm" ) ); + } + str_weapon = undefined; + if ( randomint( 100 ) < 90 ) + { + str_weapon = a_common_weapons[ getarraykeys( a_common_weapons )[ randomint( getarraykeys( a_common_weapons ).size ) ] ]; + } + else + { + str_weapon = a_rare_weapons[ getarraykeys( a_rare_weapons )[ randomint( getarraykeys( a_rare_weapons ).size ) ] ]; + } + v_spawnpt = self.origin + ( 0, 0, 40 ); + v_spawnang = ( 0, 0, -1 ); + str_spec_model = undefined; + if ( str_weapon == "claymore_zm" ) + { + str_spec_model = "t6_wpn_claymore_world"; + v_spawnang += vectorScale( ( 0, 0, -1 ), 90 ); + } + v_angles = digger getplayerangles(); + v_angles = ( 0, v_angles[ 1 ], 0 ) + vectorScale( ( 0, 0, -1 ), 90 ) + v_spawnang; + m_weapon = spawn_weapon_model( str_weapon, str_spec_model, v_spawnpt, v_angles ); + if ( str_weapon == "claymore_zm" ) + { + m_weapon setmodel( "t6_wpn_claymore_world" ); + v_spawnang += vectorScale( ( 0, 0, -1 ), 90 ); + } + m_weapon.angles = v_angles; + m_weapon playloopsound( "evt_weapon_digup" ); + m_weapon thread timer_til_despawn( v_spawnpt, 40 * -1 ); + m_weapon endon( "dig_up_weapon_timed_out" ); + playfxontag( level._effect[ "special_glow" ], m_weapon, "tag_origin" ); + m_weapon.trigger = tomb_spawn_trigger_radius( v_spawnpt, 100, 1 ); + m_weapon.trigger.hint_string = &"ZM_TOMB_X2PU"; + m_weapon.trigger.hint_parm1 = getweapondisplayname( str_weapon ); + m_weapon.trigger waittill( "trigger", player ); + m_weapon.trigger notify( "weapon_grabbed" ); + m_weapon.trigger thread swap_weapon( str_weapon, player ); + if ( isDefined( m_weapon.trigger ) ) + { + m_weapon.trigger tomb_unitrigger_delete(); + m_weapon.trigger = undefined; + } + if ( isDefined( m_weapon ) ) + { + m_weapon delete(); + } + if ( player != digger ) + { + digger notify( "dig_up_weapon_shared" ); + } +} + +swap_weapon( str_weapon, e_player ) +{ + str_current_weapon = e_player getcurrentweapon(); + if ( str_weapon == "claymore_zm" ) + { + if ( !e_player hasweapon( str_weapon ) ) + { + e_player thread maps/mp/zombies/_zm_weap_claymore::show_claymore_hint( "claymore_purchased" ); + e_player thread maps/mp/zombies/_zm_weap_claymore::claymore_setup(); + e_player thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "weapon_pickup", "grenade" ); + } + else + { + e_player givemaxammo( str_weapon ); + } + return; + } + if ( is_player_valid( e_player ) && !e_player.is_drinking && !is_placeable_mine( str_current_weapon ) && !is_equipment( str_current_weapon ) && level.revive_tool != str_current_weapon && str_current_weapon != "none" && !e_player hacker_active() ) + { + if ( !e_player hasweapon( str_weapon ) ) + { + e_player take_old_weapon_and_give_new( str_current_weapon, str_weapon ); + return; + } + else + { + e_player givemaxammo( str_weapon ); + } + } +} + +take_old_weapon_and_give_new( current_weapon, weapon ) +{ + a_weapons = self getweaponslistprimaries(); + if ( isDefined( a_weapons ) && a_weapons.size >= get_player_weapon_limit( self ) ) + { + self takeweapon( current_weapon ); + } + self giveweapon( weapon ); + self switchtoweapon( weapon ); +} + +timer_til_despawn( v_float, n_dist ) +{ + self endon( "weapon_grabbed" ); + putbacktime = 12; + self movez( n_dist, putbacktime, putbacktime * 0,5 ); + self waittill( "movedone" ); + self notify( "dig_up_weapon_timed_out" ); + if ( isDefined( self.trigger ) ) + { + self.trigger tomb_unitrigger_delete(); + self.trigger = undefined; + } + if ( isDefined( self ) ) + { + self delete(); + } +} + +get_player_perk_purchase_limit() +{ + if ( isDefined( self.player_perk_purchase_limit ) ) + { + return self.player_perk_purchase_limit; + } + return level.perk_purchase_limit; +} + +increment_player_perk_purchase_limit() +{ + if ( !isDefined( self.player_perk_purchase_limit ) ) + { + self.player_perk_purchase_limit = level.perk_purchase_limit; + } + if ( self.player_perk_purchase_limit < 8 ) + { + self.player_perk_purchase_limit++; + } +} + +ee_zombie_blood_dig() +{ + self endon( "disconnect" ); + n_z_spots_found = 0; + a_z_spots = getstructarray( "zombie_blood_dig_spot", "targetname" ); + self.t_zombie_blood_dig = spawn( "trigger_radius_use", ( 0, 0, -1 ), 0, 100, 50 ); + self.t_zombie_blood_dig.e_unique_player = self; + self.t_zombie_blood_dig triggerignoreteam(); + self.t_zombie_blood_dig setcursorhint( "HINT_NOICON" ); + self.t_zombie_blood_dig sethintstring( &"ZM_TOMB_X2D" ); + self.t_zombie_blood_dig maps/mp/zombies/_zm_powerup_zombie_blood::make_zombie_blood_entity(); + while ( n_z_spots_found < 4 ) + { + a_randomized = array_randomize( a_z_spots ); + n_index = undefined; + i = 0; + while ( i < a_randomized.size ) + { + if ( !isDefined( a_randomized[ i ].n_player ) ) + { + n_index = i; + break; + } + else + { + i++; + } + } +/# + assert( isDefined( n_index ), "No more zombie blood dig spots. Add more to the map." ); +#/ + s_z_spot = a_randomized[ n_index ]; + s_z_spot.n_player = self getentitynumber(); + s_z_spot create_zombie_blood_dig_spot( self ); + n_z_spots_found++; + level waittill( "end_of_round" ); + } + self.t_zombie_blood_dig delete(); +} + +ee_zombie_blood_dig_disconnect_watch() +{ + self waittill( "disconnect" ); + if ( isDefined( self.t_zombie_blood_dig ) ) + { + self.t_zombie_blood_dig delete(); + } + a_z_spots = getstructarray( "zombie_blood_dig_spot", "targetname" ); + _a917 = a_z_spots; + _k917 = getFirstArrayKey( _a917 ); + while ( isDefined( _k917 ) ) + { + s_pos = _a917[ _k917 ]; + if ( isDefined( s_pos.n_player ) && s_pos.n_player == self getentitynumber() ) + { + s_pos.n_player = undefined; + } + if ( isDefined( s_pos.m_dig ) ) + { + s_pos delete(); + } + _k917 = getNextArrayKey( _a917, _k917 ); + } +} + +create_zombie_blood_dig_spot( e_player ) +{ + self.m_dig = spawn( "script_model", self.origin + vectorScale( ( 0, 0, -1 ), 40 ) ); + self.m_dig.angles = self.angles; + self.m_dig setmodel( "p6_zm_tm_dig_mound_blood" ); + self.m_dig maps/mp/zombies/_zm_powerup_zombie_blood::make_zombie_blood_entity(); + self.m_dig moveto( self.origin, 3, 0, 1 ); + self.m_dig waittill( "movedone" ); + self.m_dig.e_unique_player = e_player; +/# + self thread puzzle_debug_position( "+", vectorScale( ( 0, 0, -1 ), 255 ), self.origin ); +#/ + e_player.t_zombie_blood_dig.origin = self.origin + vectorScale( ( 0, 0, -1 ), 20 ); + e_player.t_zombie_blood_dig waittill_zombie_blood_dug( self ); +/# + self notify( "stop_debug_position" ); +#/ +} + +waittill_zombie_blood_dug( s_dig_spot ) +{ + self endon( "death" ); + while ( 1 ) + { + self waittill( "trigger", player ); + if ( isDefined( player.dig_vars[ "has_shovel" ] ) && player.dig_vars[ "has_shovel" ] ) + { + player.t_zombie_blood_dig.origin = ( 0, 0, -1 ); + player playsound( "evt_dig" ); + playfx( level._effect[ "digging" ], self.origin ); + s_dig_spot.m_dig delete(); + spawn_perk_upgrade_bottle( s_dig_spot.origin, player ); + return; + } + } +} + +spawn_perk_upgrade_bottle( v_origin, e_player ) +{ + m_bottle = spawn( "script_model", v_origin + vectorScale( ( 0, 0, -1 ), 40 ) ); + m_bottle setmodel( "zombie_pickup_perk_bottle" ); + m_bottle.angles = vectorScale( ( 0, 0, -1 ), 10 ); + m_bottle setinvisibletoall(); + m_bottle setvisibletoplayer( e_player ); + m_fx = spawn( "script_model", m_bottle.origin ); + m_fx setmodel( "tag_origin" ); + m_fx setinvisibletoall(); + m_fx setvisibletoplayer( e_player ); + playfxontag( level._effect[ "special_glow" ], m_fx, "tag_origin" ); + m_bottle linkto( m_fx ); + m_fx thread rotate_perk_upgrade_bottle(); + while ( isDefined( e_player ) && !e_player istouching( m_bottle ) ) + { + wait 0,05; + } + m_bottle delete(); + m_fx delete(); + if ( isDefined( e_player ) ) + { + e_player increment_player_perk_purchase_limit(); + e_player maps/mp/zombies/_zm_stats::increment_client_stat( "tomb_perk_extension", 0 ); + e_player maps/mp/zombies/_zm_stats::increment_player_stat( "tomb_perk_extension" ); + } +} + +rotate_perk_upgrade_bottle() +{ + self endon( "death" ); + while ( 1 ) + { + self rotateyaw( 360, 5 ); + self waittill( "rotatedone" ); + } +} + +bonus_points_powerup_override() +{ + level thread maps/mp/zombies/_zm_audio_announcer::leaderdialog( "blood_money" ); + points = randomintrange( 1, 6 ) * 50; + return points; +} + +dig_powerups_tracking() +{ + level endon( "end_game" ); + level.dig_powerups_tracking = []; + level.dig_magic_box_moved = 0; + level.dig_last_prize_rare = 0; + level.dig_n_zombie_bloods_spawned = 0; + level.dig_n_powerups_spawned = 0; + while ( 1 ) + { + level waittill( "end_of_round" ); + _a1065 = level.dig_powerups_tracking; + str_powerup = getFirstArrayKey( _a1065 ); + while ( isDefined( str_powerup ) ) + { + value = _a1065[ str_powerup ]; + level.dig_powerups_tracking[ str_powerup ] = 0; + str_powerup = getNextArrayKey( _a1065, str_powerup ); + } + level.dig_n_zombie_bloods_spawned = 0; + level.dig_n_powerups_spawned = 0; + } +} + +dig_has_powerup_spawned( str_powerup ) +{ + if ( !isDefined( level.dig_powerups_tracking[ str_powerup ] ) ) + { + level.dig_powerups_tracking[ str_powerup ] = 0; + } + return level.dig_powerups_tracking[ str_powerup ]; +} + +dig_set_powerup_spawned( str_powerup ) +{ + level.dig_powerups_tracking[ str_powerup ] = 1; +} + +setup_dig_devgui() +{ +/# + setdvar( "give_shovel", "off" ); + setdvar( "give_golden_shovel", "off" ); + setdvar( "give_helmet", "off" ); + setdvar( "spawn_max_mounds", "off" ); + setdvar( "spawn_all_mounds", "off" ); + setdvar( "test_blood_mounds", "off" ); + setdvar( "force_weather_rain", "off" ); + setdvar( "force_weather_snow", "off" ); + setdvar( "force_weather_none", "off" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Digging:1/Give Shovel:1" "give_shovel on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Digging:1/Give Golden Shovel:2" "give_golden_shovel on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Digging:1/Give Helmet:3" "give_helmet on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Digging:1/Spawn Max Mounds:4" "spawn_max_mounds on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Digging:1/Spawn All Mounds:5" "spawn_all_mounds on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Digging:1/Test Blood Mounds:6" "test_blood_mounds on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Weather:1/Rain:1" "force_weather_rain on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Weather:1/Snow:2" "force_weather_snow on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Weather:1/Clear:3" "force_weather_none on"\n" ); + level thread watch_devgui_dig(); +#/ +} + +watch_devgui_dig() +{ +/# + while ( 1 ) + { + while ( getDvar( "give_shovel" ) == "on" ) + { + setdvar( "give_shovel", "off" ); + _a1131 = getplayers(); + _k1131 = getFirstArrayKey( _a1131 ); + while ( isDefined( _k1131 ) ) + { + player = _a1131[ _k1131 ]; + player.dig_vars[ "has_shovel" ] = 1; + n_player = player getentitynumber() + 1; + level setclientfield( "shovel_player" + n_player, 1 ); + _k1131 = getNextArrayKey( _a1131, _k1131 ); + } + } + while ( getDvar( "give_golden_shovel" ) == "on" ) + { + setdvar( "give_golden_shovel", "off" ); + _a1141 = getplayers(); + _k1141 = getFirstArrayKey( _a1141 ); + while ( isDefined( _k1141 ) ) + { + player = _a1141[ _k1141 ]; + player.dig_vars[ "has_shovel" ] = 1; + player.dig_vars[ "has_upgraded_shovel" ] = 1; + player thread ee_zombie_blood_dig(); + n_player = player getentitynumber() + 1; + level setclientfield( "shovel_player" + n_player, 2 ); + _k1141 = getNextArrayKey( _a1141, _k1141 ); + } + } + while ( getDvar( "give_helmet" ) == "on" ) + { + setdvar( "give_helmet", "off" ); + _a1153 = getplayers(); + _k1153 = getFirstArrayKey( _a1153 ); + while ( isDefined( _k1153 ) ) + { + player = _a1153[ _k1153 ]; + player.dig_vars[ "has_helmet" ] = 1; + n_player = player getentitynumber() + 1; + level setclientfield( "helmet_player" + n_player, 1 ); + _k1153 = getNextArrayKey( _a1153, _k1153 ); + } + } + while ( getDvar( "spawn_max_mounds" ) == "on" ) + { + setdvar( "spawn_max_mounds", "off" ); + a_dig_spots = array_randomize( level.a_dig_spots ); + i = 0; + while ( i < a_dig_spots.size ) + { + if ( isDefined( a_dig_spots[ i ].dug ) && a_dig_spots[ i ].dug && level.n_dig_spots_cur <= level.n_dig_spots_max ) + { + a_dig_spots[ i ].dug = undefined; + a_dig_spots[ i ] thread dig_spot_spawn(); + wait_network_frame(); + } + i++; + } + } + while ( getDvar( "spawn_all_mounds" ) == "on" ) + { + setdvar( "spawn_all_mounds", "off" ); + a_dig_spots = array_randomize( level.a_dig_spots ); + i = 0; + while ( i < a_dig_spots.size ) + { + if ( isDefined( a_dig_spots[ i ].dug ) && a_dig_spots[ i ].dug ) + { + a_dig_spots[ i ].dug = undefined; + a_dig_spots[ i ] thread dig_spot_spawn(); + wait_network_frame(); + } + i++; + } + } + while ( getDvar( "test_blood_mounds" ) == "on" ) + { + setdvar( "test_blood_mounds", "off" ); + a_z_spots = getstructarray( "zombie_blood_dig_spot", "targetname" ); + _a1193 = a_z_spots; + _k1193 = getFirstArrayKey( _a1193 ); + while ( isDefined( _k1193 ) ) + { + s_spot = _a1193[ _k1193 ]; + s_spot.m_dig = spawn( "script_model", s_spot.origin + vectorScale( ( 0, 0, -1 ), 40 ) ); + s_spot.m_dig.angles = s_spot.angles; + s_spot.m_dig setmodel( "p6_zm_tm_dig_mound_blood" ); + s_spot.m_dig moveto( s_spot.origin, 3, 0, 1 ); + wait_network_frame(); + _k1193 = getNextArrayKey( _a1193, _k1193 ); + } + } + while ( getDvar( "force_weather_rain" ) == "on" ) + { + setdvar( "force_weather_rain", "off" ); + level.weather_snow = 0; + level.weather_rain = 5; + level.weather_vision = 1; + level setclientfield( "rain_level", level.weather_rain ); + level setclientfield( "snow_level", level.weather_snow ); + wait 1; + _a1212 = getplayers(); + _k1212 = getFirstArrayKey( _a1212 ); + while ( isDefined( _k1212 ) ) + { + player = _a1212[ _k1212 ]; + if ( is_player_valid( player, 0, 1 ) ) + { + player set_weather_to_player(); + } + _k1212 = getNextArrayKey( _a1212, _k1212 ); + } + } + while ( getDvar( "force_weather_snow" ) == "on" ) + { + setdvar( "force_weather_snow", "off" ); + level.weather_snow = 5; + level.weather_rain = 0; + level.weather_vision = 2; + level setclientfield( "rain_level", level.weather_rain ); + level setclientfield( "snow_level", level.weather_snow ); + wait 1; + _a1229 = getplayers(); + _k1229 = getFirstArrayKey( _a1229 ); + while ( isDefined( _k1229 ) ) + { + player = _a1229[ _k1229 ]; + if ( is_player_valid( player, 0, 1 ) ) + { + player set_weather_to_player(); + } + _k1229 = getNextArrayKey( _a1229, _k1229 ); + } + } + while ( getDvar( "force_weather_none" ) == "on" ) + { + setdvar( "force_weather_none", "off" ); + level.weather_snow = 0; + level.weather_rain = 0; + level.weather_vision = 3; + level setclientfield( "rain_level", level.weather_rain ); + level setclientfield( "snow_level", level.weather_snow ); + wait 1; + _a1246 = getplayers(); + _k1246 = getFirstArrayKey( _a1246 ); + while ( isDefined( _k1246 ) ) + { + player = _a1246[ _k1246 ]; + if ( is_player_valid( player, 0, 1 ) ) + { + player set_weather_to_player(); + } + _k1246 = getNextArrayKey( _a1246, _k1246 ); + } + } + wait 0,05; +#/ + } +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_distance_tracking.gsc b/zm_tomb_patch/maps/mp/zm_tomb_distance_tracking.gsc new file mode 100644 index 0000000..be8efe5 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_distance_tracking.gsc @@ -0,0 +1,433 @@ +#include maps/mp/zm_tomb_chamber; +#include maps/mp/zombies/_zm_ai_basic; +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/zombies/_zm_zonemgr; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +zombie_tracking_init() +{ + level.zombie_respawned_health = []; + if ( !isDefined( level.zombie_tracking_dist ) ) + { + level.zombie_tracking_dist = 1520; + } + if ( !isDefined( level.zombie_tracking_high ) ) + { + level.zombie_tracking_high = 1000; + } + if ( !isDefined( level.zombie_tracking_wait ) ) + { + level.zombie_tracking_wait = 10; + } + for ( ;; ) + { + while ( 1 ) + { + a_players = get_players(); + _a33 = a_players; + _k33 = getFirstArrayKey( _a33 ); + while ( isDefined( _k33 ) ) + { + player = _a33[ _k33 ]; + if ( !player maps/mp/zombies/_zm_zonemgr::player_in_zone( "zone_air_stairs" ) && !player maps/mp/zombies/_zm_zonemgr::player_in_zone( "zone_bolt_stairs" ) || player maps/mp/zombies/_zm_zonemgr::player_in_zone( "zone_fire_stairs" ) && player maps/mp/zombies/_zm_zonemgr::player_in_zone( "zone_ice_stairs" ) ) + { + player.b_in_tunnels = 1; + } + else + { + player.b_in_tunnels = 0; + } + _k33 = getNextArrayKey( _a33, _k33 ); + } + zombies = get_round_enemy_array(); + if ( !isDefined( zombies ) || isDefined( level.ignore_distance_tracking ) && level.ignore_distance_tracking ) + { + wait level.zombie_tracking_wait; + } + } + else i = 0; + while ( i < zombies.size ) + { + if ( isDefined( zombies[ i ] ) && isDefined( zombies[ i ].ignore_distance_tracking ) && !zombies[ i ].ignore_distance_tracking ) + { + zombies[ i ] thread delete_zombie_noone_looking( level.zombie_tracking_dist, level.zombie_tracking_high ); + } + i++; + } + wait level.zombie_tracking_wait; + } +} + +delete_zombie_noone_looking( how_close, how_high ) +{ + self endon( "death" ); + if ( !isDefined( how_close ) ) + { + how_close = 1500; + } + if ( !isDefined( how_high ) ) + { + how_high = 600; + } + distance_squared_check = how_close * how_close; + too_far_dist = distance_squared_check * 3; + if ( isDefined( level.zombie_tracking_too_far_dist ) ) + { + too_far_dist = level.zombie_tracking_too_far_dist * level.zombie_tracking_too_far_dist; + } + self.inview = 0; + self.player_close = 0; + n_distance_squared = 0; + n_height_difference = 0; + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( players[ i ].sessionstate == "spectator" ) + { + i++; + continue; + } + else if ( isDefined( level.only_track_targeted_players ) ) + { + if ( !isDefined( self.favoriteenemy ) || self.favoriteenemy != players[ i ] ) + { + i++; + continue; + } + } + else + { + can_be_seen = self player_can_see_me( players[ i ] ); + if ( can_be_seen && distancesquared( self.origin, players[ i ].origin ) < too_far_dist ) + { + self.inview++; + } + n_modifier = 1; + if ( isDefined( players[ i ].b_in_tunnels ) && players[ i ].b_in_tunnels ) + { + n_modifier = 2,25; + } + n_distance_squared = distancesquared( self.origin, players[ i ].origin ); + n_height_difference = abs( self.origin[ 2 ] - players[ i ].origin[ 2 ] ); + if ( n_distance_squared < ( distance_squared_check * n_modifier ) && n_height_difference < how_high ) + { + self.player_close++; + } + } + i++; + } + if ( self.inview == 0 && self.player_close == 0 ) + { + if ( !isDefined( self.animname ) || self.animname != "zombie" && self.animname != "mechz_zombie" ) + { + return; + } + if ( isDefined( self.electrified ) && self.electrified == 1 ) + { + return; + } + if ( isDefined( self.in_the_ground ) && self.in_the_ground == 1 ) + { + return; + } + zombies = getaiarray( "axis" ); + if ( isDefined( self.damagemod ) && self.damagemod == "MOD_UNKNOWN" && self.health < self.maxhealth ) + { + if ( isDefined( self.exclude_distance_cleanup_adding_to_total ) && !self.exclude_distance_cleanup_adding_to_total && isDefined( self.isscreecher ) && !self.isscreecher ) + { + level.zombie_total++; + level.zombie_respawned_health[ level.zombie_respawned_health.size ] = self.health; + } + } + else + { + if ( ( zombies.size + level.zombie_total ) > 24 || ( zombies.size + level.zombie_total ) <= 24 && self.health >= self.maxhealth ) + { + if ( isDefined( self.exclude_distance_cleanup_adding_to_total ) && !self.exclude_distance_cleanup_adding_to_total && isDefined( self.isscreecher ) && !self.isscreecher ) + { + level.zombie_total++; + if ( self.health < level.zombie_health ) + { + level.zombie_respawned_health[ level.zombie_respawned_health.size ] = self.health; + } + } + } + } + self maps/mp/zombies/_zm_spawner::reset_attack_spot(); + self notify( "zombie_delete" ); + if ( isDefined( self.is_mechz ) && self.is_mechz ) + { + self notify( "mechz_cleanup" ); + level.mechz_left_to_spawn++; + wait_network_frame(); + level notify( "spawn_mechz" ); + } + self delete(); + recalc_zombie_array(); + } +} + +player_can_see_me( player ) +{ + playerangles = player getplayerangles(); + playerforwardvec = anglesToForward( playerangles ); + playerunitforwardvec = vectornormalize( playerforwardvec ); + banzaipos = self.origin; + playerpos = player getorigin(); + playertobanzaivec = banzaipos - playerpos; + playertobanzaiunitvec = vectornormalize( playertobanzaivec ); + forwarddotbanzai = vectordot( playerunitforwardvec, playertobanzaiunitvec ); + if ( forwarddotbanzai >= 1 ) + { + anglefromcenter = 0; + } + else if ( forwarddotbanzai <= -1 ) + { + anglefromcenter = 180; + } + else + { + anglefromcenter = acos( forwarddotbanzai ); + } + playerfov = getDvarFloat( "cg_fov" ); + banzaivsplayerfovbuffer = getDvarFloat( "g_banzai_player_fov_buffer" ); + if ( banzaivsplayerfovbuffer <= 0 ) + { + banzaivsplayerfovbuffer = 0,2; + } + playercanseeme = anglefromcenter <= ( ( playerfov * 0,5 ) * ( 1 - banzaivsplayerfovbuffer ) ); + return playercanseeme; +} + +escaped_zombies_cleanup_init() +{ + self endon( "death" ); + self.zombie_path_bad = 0; + while ( 1 ) + { + if ( !self.zombie_path_bad ) + { + self waittill( "bad_path" ); + } + found_player = undefined; + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( is_player_valid( players[ i ] ) && self maymovetopoint( players[ i ].origin, 1 ) ) + { + self.favoriteenemy = players[ i ]; + found_player = 1; + i++; + continue; + } + i++; + } + n_delete_distance = 1500; + n_delete_height = 1000; + if ( !isDefined( found_player ) && isDefined( self.in_the_ground ) && !isDefined( self.completed_emerging_into_playable_area ) ) + { + self thread delete_zombie_noone_looking( n_delete_distance, n_delete_height ); + self.zombie_path_bad = 1; + self escaped_zombies_cleanup(); + } + else + { + if ( !isDefined( found_player ) && isDefined( self.completed_emerging_into_playable_area ) && self.completed_emerging_into_playable_area ) + { + self thread delete_zombie_noone_looking( n_delete_distance, n_delete_height ); + self.zombie_path_bad = 1; + self escaped_zombies_cleanup(); + } + } + wait 0,1; + } +} + +escaped_zombies_cleanup() +{ + self endon( "death" ); + s_escape = self get_escape_position(); + self notify( "stop_find_flesh" ); + self notify( "zombie_acquire_enemy" ); + if ( isDefined( s_escape ) ) + { + self setgoalpos( s_escape.origin ); + self thread check_player_available(); + self waittill_any( "goal", "reaquire_player" ); + } + self.zombie_path_bad = !can_zombie_path_to_any_player(); + wait 0,1; + if ( !self.zombie_path_bad ) + { + self thread maps/mp/zombies/_zm_ai_basic::find_flesh(); + } +} + +get_escape_position() +{ + self endon( "death" ); + str_zone = get_current_zone(); + if ( !isDefined( str_zone ) ) + { + str_zone = self.zone_name; + } + if ( isDefined( str_zone ) ) + { + a_zones = get_adjacencies_to_zone( str_zone ); + a_dog_locations = get_dog_locations_in_zones( a_zones ); + s_farthest = self get_farthest_dog_location( a_dog_locations ); + } + return s_farthest; +} + +check_player_available() +{ + self notify( "_check_player_available" ); + self endon( "_check_player_available" ); + self endon( "death" ); + self endon( "goal" ); + while ( self.zombie_path_bad ) + { + wait randomfloatrange( 0,2, 0,5 ); + if ( self can_zombie_see_any_player() ) + { + self notify( "reaquire_player" ); + return; + } + } + self notify( "reaquire_player" ); +} + +can_zombie_path_to_any_player() +{ + a_players = get_players(); + i = 0; + while ( i < a_players.size ) + { + if ( !is_player_valid( a_players[ i ] ) ) + { + i++; + continue; + } + else + { + v_player_origin = a_players[ i ].origin; + if ( isDefined( self.b_on_tank ) ) + { + if ( isDefined( a_players[ i ].b_already_on_tank ) ) + { + if ( self.b_on_tank != a_players[ i ].b_already_on_tank ) + { + v_player_origin = level.vh_tank gettagorigin( "window_left_rear_jmp_jnt" ); + } + } + } + if ( findpath( self.origin, v_player_origin ) ) + { + return 1; + } + } + i++; + } + return 0; +} + +can_zombie_see_any_player() +{ + a_players = get_players(); + zombie_in_chamber = maps/mp/zm_tomb_chamber::is_point_in_chamber( self.origin ); + i = 0; + while ( i < a_players.size ) + { + if ( !is_player_valid( a_players[ i ] ) ) + { + i++; + continue; + } + else player_origin = a_players[ i ].origin; + if ( isDefined( a_players[ i ].b_already_on_tank ) && a_players[ i ].b_already_on_tank ) + { + if ( isDefined( self.b_on_tank ) && self.b_on_tank ) + { + return 1; + } + else + { + player_origin = level.vh_tank gettagorigin( "window_left_rear_jmp_jnt" ); + } + } + else + { + player_in_chamber = maps/mp/zm_tomb_chamber::is_point_in_chamber( a_players[ i ].origin ); + if ( player_in_chamber != zombie_in_chamber ) + { + i++; + continue; + } + } + else + { + path_length = 0; + path_length = self calcpathlength( player_origin ); + if ( self maymovetopoint( player_origin, 1 ) || path_length != 0 ) + { + return 1; + } + } + i++; + } + return 0; +} + +get_adjacencies_to_zone( str_zone ) +{ + a_adjacencies = []; + a_adjacencies[ 0 ] = str_zone; + a_adjacent_zones = getarraykeys( level.zones[ str_zone ].adjacent_zones ); + i = 0; + while ( i < a_adjacent_zones.size ) + { + if ( level.zones[ str_zone ].adjacent_zones[ a_adjacent_zones[ i ] ].is_connected ) + { + a_adjacencies[ a_adjacencies.size ] = a_adjacent_zones[ i ]; + } + i++; + } + return a_adjacencies; +} + +get_dog_locations_in_zones( a_zones ) +{ + a_dog_locations = []; + _a471 = a_zones; + _k471 = getFirstArrayKey( _a471 ); + while ( isDefined( _k471 ) ) + { + zone = _a471[ _k471 ]; + a_dog_locations = arraycombine( a_dog_locations, level.zones[ zone ].dog_locations, 0, 0 ); + _k471 = getNextArrayKey( _a471, _k471 ); + } + return a_dog_locations; +} + +get_farthest_dog_location( a_dog_locations ) +{ + n_farthest_index = 0; + n_distance_farthest = 0; + i = 0; + while ( i < a_dog_locations.size ) + { + n_distance_sq = distancesquared( self.origin, a_dog_locations[ i ].origin ); + if ( n_distance_sq > n_distance_farthest ) + { + n_distance_farthest = n_distance_sq; + n_farthest_index = i; + } + i++; + } + return a_dog_locations[ n_farthest_index ]; +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_ee_lights.gsc b/zm_tomb_patch/maps/mp/zm_tomb_ee_lights.gsc new file mode 100644 index 0000000..33edf11 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_ee_lights.gsc @@ -0,0 +1,197 @@ +#include maps/mp/zm_tomb_quest_crypt; +#include maps/mp/zombies/_zm_net; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_sidequests; +#include maps/mp/zombies/_zm_craftables; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +main() +{ + registerclientfield( "world", "light_show", 14000, 2, "int" ); + flag_init( "show_morse_code" ); + init_morse_code(); + flag_wait( "start_zombie_round_logic" ); + chamber_discs = getentarray( "crypt_puzzle_disc", "script_noteworthy" ); + lit_discs = []; + _a24 = chamber_discs; + _k24 = getFirstArrayKey( _a24 ); + while ( isDefined( _k24 ) ) + { + disc = _a24[ _k24 ]; + if ( isDefined( disc.script_int ) ) + { + lit_discs[ disc.script_int - 1 ] = disc; + } + _k24 = getNextArrayKey( _a24, _k24 ); + } + flag_wait_any( "ee_all_staffs_upgraded", "show_morse_code" ); + while ( 1 ) + { + setclientfield( "light_show", 1 ); + if ( randomint( 100 ) < 10 ) + { + turn_all_lights_off( lit_discs ); + wait 10; + setclientfield( "light_show", 3 ); + light_show_morse( lit_discs, "GIOVAN BATTISTA BELLASO" ); + setclientfield( "light_show", 1 ); + } + turn_all_lights_off( lit_discs ); + wait 10; + setclientfield( "light_show", 2 ); + light_show_morse( lit_discs, level.cipher_key ); + _a56 = level.morse_messages; + _k56 = getFirstArrayKey( _a56 ); + while ( isDefined( _k56 ) ) + { + message = _a56[ _k56 ]; + setclientfield( "light_show", 1 ); + cipher = phrase_convert_to_cipher( message, level.cipher_key ); + turn_all_lights_off( lit_discs ); + wait 10; + light_show_morse( lit_discs, cipher ); + _k56 = getNextArrayKey( _a56, _k56 ); + } + } +} + +init_morse_code() +{ + level.morse_letters = []; + level.morse_letters[ "A" ] = ".-"; + level.morse_letters[ "B" ] = "-..."; + level.morse_letters[ "C" ] = "-.-."; + level.morse_letters[ "D" ] = "-.."; + level.morse_letters[ "E" ] = "."; + level.morse_letters[ "F" ] = "..-."; + level.morse_letters[ "G" ] = "--."; + level.morse_letters[ "H" ] = "...."; + level.morse_letters[ "I" ] = ".."; + level.morse_letters[ "J" ] = ".---"; + level.morse_letters[ "K" ] = "-.-"; + level.morse_letters[ "L" ] = ".-.."; + level.morse_letters[ "M" ] = "--"; + level.morse_letters[ "N" ] = "-."; + level.morse_letters[ "O" ] = "---"; + level.morse_letters[ "P" ] = ".--."; + level.morse_letters[ "Q" ] = "--.-"; + level.morse_letters[ "R" ] = ".-."; + level.morse_letters[ "S" ] = "..."; + level.morse_letters[ "T" ] = "-"; + level.morse_letters[ "U" ] = "..-"; + level.morse_letters[ "V" ] = "...-"; + level.morse_letters[ "W" ] = ".--"; + level.morse_letters[ "X" ] = "-..-"; + level.morse_letters[ "Y" ] = "-.--"; + level.morse_letters[ "Z" ] = "--.."; + level.morse_messages = []; + level.morse_messages[ 0 ] = "WARN MESSINES"; + level.morse_messages[ 1 ] = "SOMETHING BLUE IN THE EARTH"; + level.morse_messages[ 2 ] = "NOT CLAY"; + level.morse_messages[ 3 ] = "WE GREW WEAK"; + level.morse_messages[ 4 ] = "THOUGHT IT WAS FLU"; + level.morse_messages[ 5 ] = "MEN BECAME BEASTS"; + level.morse_messages[ 6 ] = "BLOOD TURNED TO ASH"; + level.morse_messages[ 7 ] = "LIBERATE TUTE DE INFERNIS"; + level.cipher_key = "INFERNO"; +} + +turn_all_lights_off( a_discs ) +{ + _a114 = a_discs; + _k114 = getFirstArrayKey( _a114 ); + while ( isDefined( _k114 ) ) + { + disc = _a114[ _k114 ]; + disc maps/mp/zm_tomb_quest_crypt::bryce_cake_light_update( 0 ); + _k114 = getNextArrayKey( _a114, _k114 ); + } +} + +turn_all_lights_on( a_discs ) +{ + _a122 = a_discs; + _k122 = getFirstArrayKey( _a122 ); + while ( isDefined( _k122 ) ) + { + disc = _a122[ _k122 ]; + disc maps/mp/zm_tomb_quest_crypt::bryce_cake_light_update( 1 ); + _k122 = getNextArrayKey( _a122, _k122 ); + } +} + +phrase_convert_to_cipher( str_phrase, str_key ) +{ + alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + alphabet_vals = []; + num = 0; + i = 0; + while ( i < alphabet.size ) + { + letter = alphabet[ i ]; + alphabet_vals[ letter ] = num; + num++; + i++; + } + encrypted_phrase = []; + j = 0; + i = 0; + while ( i < str_phrase.size ) + { + cipher_letter = str_key[ j % str_key.size ]; + original_letter = str_phrase[ i ]; + n_original_letter = alphabet_vals[ original_letter ]; + if ( !isDefined( n_original_letter ) ) + { + encrypted_phrase[ encrypted_phrase.size ] = original_letter; + i++; + continue; + } + else + { + n_cipher_offset = alphabet_vals[ cipher_letter ]; + n_ciphered_letter = ( n_original_letter + n_cipher_offset ) % alphabet.size; + encrypted_phrase[ encrypted_phrase.size ] = alphabet[ n_ciphered_letter ]; + j++; + } + i++; + } + return encrypted_phrase; +} + +light_show_morse( a_discs, message ) +{ + i = 0; + while ( i < message.size ) + { + letter = message[ i ]; + letter_code = level.morse_letters[ letter ]; + if ( isDefined( letter_code ) ) + { + j = 0; + while ( j < letter_code.size ) + { + turn_all_lights_on( a_discs ); + if ( letter_code[ j ] == "." ) + { + wait 0,2; + } + else + { + if ( letter_code[ j ] == "-" ) + { + wait 1; + } + } + turn_all_lights_off( a_discs ); + wait 0,5; + j++; + } + } + else wait 2; + wait 1,5; + i++; + } +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_ee_main.gsc b/zm_tomb_patch/maps/mp/zm_tomb_ee_main.gsc new file mode 100644 index 0000000..dbec07d --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_ee_main.gsc @@ -0,0 +1,527 @@ +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm; +#include maps/mp/zm_tomb_amb; +#include maps/mp/gametypes_zm/_hud; +#include maps/mp/gametypes_zm/_hud_util; +#include maps/mp/zm_tomb_vo; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_sidequests; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + registerclientfield( "actor", "ee_zombie_fist_fx", 14000, 1, "int" ); + registerclientfield( "actor", "ee_zombie_soul_portal", 14000, 1, "int" ); + registerclientfield( "world", "ee_sam_portal", 14000, 2, "int" ); + registerclientfield( "vehicle", "ee_plane_fx", 14000, 1, "int" ); + registerclientfield( "world", "ee_ending", 14000, 1, "int" ); + precache_models(); + flag_init( "ee_all_staffs_crafted" ); + flag_init( "ee_all_staffs_upgraded" ); + flag_init( "ee_all_staffs_placed" ); + flag_init( "ee_mech_zombie_hole_opened" ); + flag_init( "ee_mech_zombie_fight_completed" ); + flag_init( "ee_maxis_drone_retrieved" ); + flag_init( "ee_all_players_upgraded_punch" ); + flag_init( "ee_souls_absorbed" ); + flag_init( "ee_samantha_released" ); + flag_init( "ee_quadrotor_disabled" ); + flag_init( "ee_sam_portal_active" ); + if ( !is_sidequest_allowed( "zclassic" ) ) + { + return; + } +/# + level thread setup_ee_main_devgui(); +#/ + declare_sidequest( "little_girl_lost", ::init_sidequest, ::sidequest_logic, ::complete_sidequest, ::generic_stage_start, ::generic_stage_end ); + maps/mp/zm_tomb_ee_main_step_1::init(); + maps/mp/zm_tomb_ee_main_step_2::init(); + maps/mp/zm_tomb_ee_main_step_3::init(); + maps/mp/zm_tomb_ee_main_step_4::init(); + maps/mp/zm_tomb_ee_main_step_5::init(); + maps/mp/zm_tomb_ee_main_step_6::init(); + maps/mp/zm_tomb_ee_main_step_7::init(); + maps/mp/zm_tomb_ee_main_step_8::init(); + flag_wait( "start_zombie_round_logic" ); + sidequest_start( "little_girl_lost" ); +} + +precache_models() +{ + precachemodel( "p_rus_alarm_button" ); + precachemodel( "p6_zm_tm_staff_holder" ); + precachemodel( "p6_zm_tm_runes" ); + precachemodel( "drone_collision" ); +} + +init_sidequest() +{ + level.n_ee_step = 0; + level.n_ee_robot_staffs_planted = 0; +} + +sidequest_logic() +{ + level._cur_stage_name = "step_0"; + flag_wait( "ee_all_staffs_crafted" ); + flag_wait( "all_zones_captured" ); + level.n_ee_step++; + level thread zombie_blood_hint_watch(); + stage_start( "little_girl_lost", "step_1" ); + level waittill( "little_girl_lost_step_1_over" ); + stage_start( "little_girl_lost", "step_2" ); + level waittill( "little_girl_lost_step_2_over" ); + level thread maps/mp/zm_tomb_amb::sndplaystingerwithoverride( "mus_event_ee_step2", 15 ); + stage_start( "little_girl_lost", "step_3" ); + level waittill( "little_girl_lost_step_3_over" ); + level thread maps/mp/zm_tomb_amb::sndplaystingerwithoverride( "mus_event_ee_step3", 35 ); + stage_start( "little_girl_lost", "step_4" ); + level waittill( "little_girl_lost_step_4_over" ); + level thread maps/mp/zm_tomb_amb::sndplaystingerwithoverride( "mus_event_ee_step4", 30 ); + stage_start( "little_girl_lost", "step_5" ); + level waittill( "little_girl_lost_step_5_over" ); + level thread maps/mp/zm_tomb_amb::sndplaystingerwithoverride( "mus_event_ee_step5", 29 ); + stage_start( "little_girl_lost", "step_6" ); + level waittill( "little_girl_lost_step_6_over" ); + level thread maps/mp/zm_tomb_amb::sndplaystingerwithoverride( "mus_event_ee_step6", 28 ); + stage_start( "little_girl_lost", "step_7" ); + level waittill( "little_girl_lost_step_7_over" ); + level thread maps/mp/zm_tomb_amb::sndplaystingerwithoverride( "mus_event_ee_step7", 31 ); + stage_start( "little_girl_lost", "step_8" ); + level waittill( "little_girl_lost_step_8_over" ); +} + +zombie_blood_hint_watch() +{ + n_curr_step = level.n_ee_step; + a_player_hint[ 0 ] = 0; + a_player_hint[ 1 ] = 0; + a_player_hint[ 2 ] = 0; + a_player_hint[ 3 ] = 0; + while ( !flag( "ee_samantha_released" ) ) + { + level waittill( "player_zombie_blood", e_player ); + while ( n_curr_step != level.n_ee_step ) + { + n_curr_step = level.n_ee_step; + i = 0; + while ( i < a_player_hint.size ) + { + a_player_hint[ i ] = 0; + i++; + } + } + if ( !a_player_hint[ e_player.characterindex ] ) + { + wait randomfloatrange( 3, 7 ); + if ( isDefined( e_player.vo_promises_playing ) && e_player.vo_promises_playing ) + { + continue; + } + while ( isDefined( level.sam_talking ) && level.sam_talking ) + { + wait 0,05; + } + if ( isDefined( e_player ) && isplayer( e_player ) && e_player.zombie_vars[ "zombie_powerup_zombie_blood_on" ] ) + { + a_player_hint[ e_player.characterindex ] = 1; + set_players_dontspeak( 1 ); + level.sam_talking = 1; + str_vox = get_zombie_blood_hint_vox(); + e_player playsoundtoplayer( str_vox, e_player ); + n_duration = soundgetplaybacktime( str_vox ); + wait ( n_duration / 1000 ); + level.sam_talking = 0; + set_players_dontspeak( 0 ); + } + continue; + } + else + { + if ( randomint( 100 ) < 20 ) + { + wait randomfloatrange( 3, 7 ); + if ( isDefined( e_player.vo_promises_playing ) && e_player.vo_promises_playing ) + { + continue; + } + while ( isDefined( level.sam_talking ) && level.sam_talking ) + { + wait 0,05; + } + if ( isDefined( e_player ) && isplayer( e_player ) && e_player.zombie_vars[ "zombie_powerup_zombie_blood_on" ] ) + { + str_vox = get_zombie_blood_hint_generic_vox(); + if ( isDefined( str_vox ) ) + { + set_players_dontspeak( 1 ); + level.sam_talking = 1; + e_player playsoundtoplayer( str_vox, e_player ); + n_duration = soundgetplaybacktime( str_vox ); + wait ( n_duration / 1000 ); + level.sam_talking = 0; + set_players_dontspeak( 0 ); + } + } + } + } + } +} + +get_step_announce_vox() +{ + switch( level.n_ee_step ) + { + case 1: + return "vox_sam_all_staff_upgrade_key_0"; + case 2: + return "vox_sam_all_staff_ascend_darkness_0"; + case 3: + return "vox_sam_all_staff_rain_fire_0"; + case 4: + return "vox_sam_all_staff_unleash_hoard_0"; + case 5: + return "vox_sam_all_staff_skewer_beast_0"; + case 6: + return "vox_sam_all_staff_fist_iron_0"; + case 7: + return "vox_sam_all_staff_raise_hell_0"; + default: + return undefined; + } +} + +get_zombie_blood_hint_vox() +{ + if ( flag( "all_zones_captured" ) ) + { + return "vox_sam_upgrade_staff_clue_" + level.n_ee_step + "_0"; + } + return "vox_sam_upgrade_staff_clue_" + level.n_ee_step + "_grbld_0"; +} + +get_zombie_blood_hint_generic_vox() +{ + if ( !isDefined( level.generic_clue_index ) ) + { + level.generic_clue_index = 0; + } + vo_array[ 0 ] = "vox_sam_heard_by_all_1_0"; + vo_array[ 1 ] = "vox_sam_heard_by_all_2_0"; + vo_array[ 2 ] = "vox_sam_heard_by_all_3_0"; + vo_array[ 3 ] = "vox_sam_slow_progress_0"; + vo_array[ 4 ] = "vox_sam_slow_progress_2"; + vo_array[ 5 ] = "vox_sam_slow_progress_3"; + if ( level.generic_clue_index >= vo_array.size ) + { + return undefined; + } + str_vo = vo_array[ level.generic_clue_index ]; + level.generic_clue_index++; + return str_vo; +} + +complete_sidequest() +{ + level.sndgameovermusicoverride = "game_over_ee"; + a_players = getplayers(); + _a293 = a_players; + _k293 = getFirstArrayKey( _a293 ); + while ( isDefined( _k293 ) ) + { + player = _a293[ _k293 ]; + player freezecontrols( 1 ); + player thread fadetoblackforxsec( 0, 5, 0,5, 0, "white" ); + _k293 = getNextArrayKey( _a293, _k293 ); + } + playsoundatposition( "zmb_squest_whiteout", ( 0, 0, -1 ) ); + delay_thread( 0,5, ::remove_portal_beam ); + level.custom_intermission = ::player_intermission_ee; + level setclientfield( "ee_ending", 1 ); + wait_network_frame(); + level notify( "end_game" ); +} + +remove_portal_beam() +{ + if ( isDefined( level.ee_ending_beam_fx ) ) + { + level.ee_ending_beam_fx delete(); + } +} + +generic_stage_start() +{ + str_vox = get_step_announce_vox(); + if ( isDefined( str_vox ) ) + { + level thread ee_samantha_say( str_vox ); + } +} + +generic_stage_end() +{ + level.n_ee_step++; + if ( level.n_ee_step <= 6 ) + { + flag_wait( "all_zones_captured" ); + } + wait_network_frame(); + wait_network_frame(); +} + +all_staffs_inserted_in_puzzle_room() +{ + n_staffs_inserted = 0; + _a350 = level.a_elemental_staffs; + _k350 = getFirstArrayKey( _a350 ); + while ( isDefined( _k350 ) ) + { + staff = _a350[ _k350 ]; + if ( staff.upgrade.charger.is_inserted ) + { + n_staffs_inserted++; + } + _k350 = getNextArrayKey( _a350, _k350 ); + } + if ( n_staffs_inserted == 4 ) + { + return 1; + } + else + { + return 0; + } +} + +ee_samantha_say( str_vox ) +{ + flag_waitopen( "story_vo_playing" ); + flag_set( "story_vo_playing" ); + set_players_dontspeak( 1 ); + samanthasay( str_vox, get_players()[ 0 ] ); + set_players_dontspeak( 0 ); + flag_clear( "story_vo_playing" ); +} + +player_intermission_ee() +{ + self closemenu(); + self closeingamemenu(); + level endon( "stop_intermission" ); + self endon( "disconnect" ); + self endon( "death" ); + self notify( "_zombie_game_over" ); + self.score = self.score_total; + self.sessionstate = "intermission"; + self.spectatorclient = -1; + self.killcamentity = -1; + self.archivetime = 0; + self.psoffsettime = 0; + self.friendlydamage = undefined; + points = getstructarray( "ee_cam", "targetname" ); + if ( !isDefined( points ) || points.size == 0 ) + { + points = getentarray( "info_intermission", "classname" ); + if ( points.size < 1 ) + { +/# + println( "NO info_intermission POINTS IN MAP" ); +#/ + return; + } + } + self.game_over_bg = newclienthudelem( self ); + self.game_over_bg.horzalign = "fullscreen"; + self.game_over_bg.vertalign = "fullscreen"; + self.game_over_bg setshader( "black", 640, 480 ); + self.game_over_bg.alpha = 1; + visionsetnaked( "cheat_bw", 0,05 ); + org = undefined; + while ( 1 ) + { + points = array_randomize( points ); + i = 0; + while ( i < points.size ) + { + point = points[ i ]; + if ( !isDefined( org ) ) + { + self spawn( point.origin, point.angles ); + } + if ( isDefined( points[ i ].target ) ) + { + if ( !isDefined( org ) ) + { + org = spawn( "script_model", self.origin + vectorScale( ( 0, 0, -1 ), 60 ) ); + org setmodel( "tag_origin" ); + } + org.origin = points[ i ].origin; + org.angles = points[ i ].angles; + j = 0; + while ( j < get_players().size ) + { + player = get_players()[ j ]; + player camerasetposition( org ); + player camerasetlookat(); + player cameraactivate( 1 ); + j++; + } + speed = 20; + if ( isDefined( points[ i ].speed ) ) + { + speed = points[ i ].speed; + } + target_point = getstruct( points[ i ].target, "targetname" ); + dist = distance( points[ i ].origin, target_point.origin ); + time = dist / speed; + q_time = time * 0,25; + if ( q_time > 1 ) + { + q_time = 1; + } + self.game_over_bg fadeovertime( q_time ); + self.game_over_bg.alpha = 0; + org moveto( target_point.origin, time, q_time, q_time ); + org rotateto( target_point.angles, time, q_time, q_time ); + wait ( time - q_time ); + self.game_over_bg fadeovertime( q_time ); + self.game_over_bg.alpha = 1; + wait q_time; + i++; + continue; + } + else + { + self.game_over_bg fadeovertime( 1 ); + self.game_over_bg.alpha = 0; + wait 5; + self.game_over_bg thread maps/mp/zombies/_zm::fade_up_over_time( 1 ); + } + i++; + } + } +} + +setup_ee_main_devgui() +{ +/# + wait 5; + b_activated = 0; + while ( !b_activated ) + { + _a507 = getplayers(); + _k507 = getFirstArrayKey( _a507 ); + while ( isDefined( _k507 ) ) + { + player = _a507[ _k507 ]; + if ( distance2d( player.origin, ( 2904, 5040, -336 ) ) < 100 && player usebuttonpressed() ) + { + wait 2; + if ( player usebuttonpressed() ) + { + b_activated = 1; + } + } + _k507 = getNextArrayKey( _a507, _k507 ); + } + wait 0,05; + } + setdvar( "ee_main_progress", "off" ); + setdvar( "ee_main_end_level", "off" ); + setdvar( "ee_upgrade_beacon", "off" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/EE Main:1/Next Step:1" "ee_main_progress on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/EE Main:1/Upgrade Beacon:2" "ee_upgrade_beacon on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/EE Main:1/End Level:3" "ee_main_end_level on"\n" ); + level thread watch_devgui_ee_main(); +#/ +} + +watch_devgui_ee_main() +{ +/# + while ( 1 ) + { + if ( getDvar( "ee_main_progress" ) == "on" ) + { + setdvar( "ee_main_progress", "off" ); + level.ee_debug = 1; + flag_set( "samantha_intro_done" ); + switch( level._cur_stage_name ) + { + case "step_0": + flag_set( "ee_all_staffs_crafted" ); + flag_set( "all_zones_captured" ); + break; + break; + case "step_1": + flag_set( "ee_all_staffs_upgraded" ); + level waittill( "little_girl_lost_step_1_over" ); + break; + break; + case "step_2": + flag_set( "ee_all_staffs_placed" ); + level waittill( "little_girl_lost_step_2_over" ); + break; + break; + case "step_3": + flag_set( "ee_mech_zombie_hole_opened" ); + m_floor = getent( "easter_mechzombie_spawn", "targetname" ); + if ( isDefined( m_floor ) ) + { + m_floor delete(); + } + level waittill( "little_girl_lost_step_3_over" ); + break; + break; + case "step_4": + flag_set( "ee_mech_zombie_fight_completed" ); + flag_set( "ee_quadrotor_disabled" ); + level waittill( "little_girl_lost_step_4_over" ); + break; + break; + case "step_5": + flag_set( "ee_maxis_drone_retrieved" ); + flag_clear( "ee_quadrotor_disabled" ); + level waittill( "little_girl_lost_step_5_over" ); + break; + break; + case "step_6": + flag_set( "ee_all_players_upgraded_punch" ); + level waittill( "little_girl_lost_step_6_over" ); + break; + break; + case "step_7": + flag_set( "ee_souls_absorbed" ); + level waittill( "little_girl_lost_step_7_over" ); + break; + break; + case "step_8": + flag_set( "ee_quadrotor_disabled" ); + level waittill( "little_girl_lost_step_8_over" ); + break; + break; + default: + } + } + if ( getDvar( "ee_main_end_level" ) == "on" ) + { + setdvar( "ee_main_end_level", "off" ); + level setclientfield( "ee_sam_portal", 2 ); + complete_sidequest(); + } + if ( getDvar( "ee_upgrade_beacon" ) == "on" ) + { + setdvar( "ee_upgrade_beacon", "off" ); + setdvar( "force_three_robot_round", "on" ); + flag_set( "fire_link_enabled" ); + array_thread( get_players(), ::maps/mp/zombies/_zm_weapons::weapon_give, "beacon_zm" ); + } + wait 0,05; +#/ + } + } +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_1.gsc b/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_1.gsc new file mode 100644 index 0000000..19b0993 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_1.gsc @@ -0,0 +1,29 @@ +#include maps/mp/zm_tomb_ee_main; +#include maps/mp/zombies/_zm_sidequests; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + declare_sidequest_stage( "little_girl_lost", "step_1", ::init_stage, ::stage_logic, ::exit_stage ); +} + +init_stage() +{ + level._cur_stage_name = "step_1"; +} + +stage_logic() +{ +/# + iprintln( level._cur_stage_name + " of little girl lost started" ); +#/ + flag_wait( "ee_all_staffs_upgraded" ); + wait_network_frame(); + stage_completed( "little_girl_lost", level._cur_stage_name ); +} + +exit_stage( success ) +{ +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_2.gsc b/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_2.gsc new file mode 100644 index 0000000..44b7357 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_2.gsc @@ -0,0 +1,159 @@ +#include maps/mp/zm_tomb_craftables; +#include maps/mp/zombies/_zm_unitrigger; +#include maps/mp/zombies/_zm_powerup_zombie_blood; +#include maps/mp/zm_tomb_ee_main; +#include maps/mp/zombies/_zm_sidequests; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + declare_sidequest_stage( "little_girl_lost", "step_2", ::init_stage, ::stage_logic, ::exit_stage ); + precachemodel( "p6_zm_tm_staff_holder" ); +} + +init_stage() +{ + level._cur_stage_name = "step_2"; + a_structs = getstructarray( "robot_head_staff", "targetname" ); + _a21 = a_structs; + _k21 = getFirstArrayKey( _a21 ); + while ( isDefined( _k21 ) ) + { + unitrigger_stub = _a21[ _k21 ]; + level thread create_robot_head_trigger( unitrigger_stub ); + wait_network_frame(); + wait_network_frame(); + wait_network_frame(); + _k21 = getNextArrayKey( _a21, _k21 ); + } +} + +stage_logic() +{ +/# + iprintln( level._cur_stage_name + " of little girl lost started" ); +#/ + flag_wait( "ee_all_staffs_placed" ); + playsoundatposition( "zmb_squest_robot_alarm_high", ( -14, -1, 871 ) ); + wait 3; + wait_network_frame(); + stage_completed( "little_girl_lost", level._cur_stage_name ); +} + +exit_stage( success ) +{ + a_structs = getstructarray( "robot_head_staff", "targetname" ); + _a52 = a_structs; + _k52 = getFirstArrayKey( _a52 ); + while ( isDefined( _k52 ) ) + { + struct = _a52[ _k52 ]; + struct thread remove_plinth(); + wait_network_frame(); + wait_network_frame(); + wait_network_frame(); + _k52 = getNextArrayKey( _a52, _k52 ); + } +} + +remove_plinth() +{ + playfx( level._effect[ "teleport_1p" ], self.m_plinth.origin ); + playsoundatposition( "zmb_footprintbox_disappear", self.m_plinth.origin ); + wait 3; + if ( isDefined( self.m_plinth.m_staff ) ) + { + self.m_plinth.m_staff unlink(); + self.m_plinth.m_staff.origin = self.m_plinth.v_old_origin; + self.m_plinth.m_staff.angles = self.m_plinth.v_old_angles; + self.m_plinth.e_staff.ee_in_use = undefined; + } + self.m_sign delete(); + self.m_plinth delete(); + self.m_coll delete(); + unregister_unitrigger( self ); +} + +create_robot_head_trigger( unitrigger_stub ) +{ + playfx( level._effect[ "teleport_1p" ], unitrigger_stub.origin ); + playsoundatposition( "zmb_footprintbox_disappear", unitrigger_stub.origin ); + wait 3; + unitrigger_stub.radius = 50; + unitrigger_stub.height = 256; + unitrigger_stub.script_unitrigger_type = "unitrigger_radius_use"; + unitrigger_stub.cursor_hint = "HINT_NOICON"; + unitrigger_stub.require_look_at = 1; + m_coll = spawn( "script_model", unitrigger_stub.origin ); + m_coll setmodel( "drone_collision" ); + unitrigger_stub.m_coll = m_coll; + wait_network_frame(); + m_plinth = spawn( "script_model", unitrigger_stub.origin ); + m_plinth.angles = unitrigger_stub.angles; + m_plinth setmodel( "p6_zm_tm_staff_holder" ); + unitrigger_stub.m_plinth = m_plinth; + wait_network_frame(); + m_sign = spawn( "script_model", unitrigger_stub.origin ); + m_sign setmodel( "p6_zm_tm_runes" ); + m_sign linkto( unitrigger_stub.m_plinth, "tag_origin", ( 0, 15, 40 ) ); + m_sign hidepart( "j_fire" ); + m_sign hidepart( "j_ice" ); + m_sign hidepart( "j_lightning" ); + m_sign hidepart( "j_wind" ); + switch( unitrigger_stub.script_noteworthy ) + { + case "fire": + m_sign showpart( "j_fire" ); + break; + case "water": + m_sign showpart( "j_ice" ); + break; + case "lightning": + m_sign showpart( "j_lightning" ); + break; + case "air": + m_sign showpart( "j_wind" ); + break; + } + m_sign maps/mp/zombies/_zm_powerup_zombie_blood::make_zombie_blood_entity(); + unitrigger_stub.m_sign = m_sign; + unitrigger_stub.origin += vectorScale( ( 0, 0, 1 ), 30 ); + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( unitrigger_stub, ::robot_head_trigger_think ); +} + +robot_head_trigger_think() +{ + self endon( "kill_trigger" ); + str_weap_staff = "staff_" + self.script_noteworthy + "_upgraded_zm"; + e_upgraded_staff = maps/mp/zm_tomb_craftables::get_staff_info_from_weapon_name( str_weap_staff ); + while ( 1 ) + { + self waittill( "trigger", player ); + if ( player hasweapon( str_weap_staff ) ) + { + e_upgraded_staff.ee_in_use = 1; + player takeweapon( str_weap_staff ); + maps/mp/zm_tomb_craftables::clear_player_staff( str_weap_staff ); + level.n_ee_robot_staffs_planted++; + if ( level.n_ee_robot_staffs_planted == 4 ) + { + flag_set( "ee_all_staffs_placed" ); + } + e_upgraded_staff thread place_staff( self.stub.m_plinth ); + } + } +} + +place_staff( m_plinth ) +{ + m_staff = getent( "craftable_" + self.weapname, "targetname" ); + m_plinth.e_staff = self; + m_plinth.m_staff = m_staff; + m_plinth.v_old_angles = m_staff.angles; + m_plinth.v_old_origin = m_staff.origin; + m_staff linkto( m_plinth, "tag_origin", ( 0, 10, 30 ), ( 345, 90, 0 ) ); + m_staff show(); + m_plinth playsound( "zmb_squest_robot_place_staff" ); +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_3.gsc b/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_3.gsc new file mode 100644 index 0000000..10a9051 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_3.gsc @@ -0,0 +1,153 @@ +#include maps/mp/zombies/_zm_unitrigger; +#include maps/mp/zm_tomb_ee_main; +#include maps/mp/zombies/_zm_sidequests; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + declare_sidequest_stage( "little_girl_lost", "step_3", ::init_stage, ::stage_logic, ::exit_stage ); +} + +init_stage() +{ + level._cur_stage_name = "step_3"; + level.check_valid_poi = ::mech_zombie_hole_valid; + create_buttons_and_triggers(); +} + +stage_logic() +{ +/# + iprintln( level._cur_stage_name + " of little girl lost started" ); +#/ + level thread watch_for_triple_attack(); + flag_wait( "ee_mech_zombie_hole_opened" ); + wait_network_frame(); + stage_completed( "little_girl_lost", level._cur_stage_name ); +} + +exit_stage( success ) +{ + level.check_valid_poi = undefined; + level notify( "fire_link_cooldown" ); + flag_set( "fire_link_enabled" ); + a_buttons = getentarray( "fire_link_button", "targetname" ); + array_delete( a_buttons ); + a_structs = getstructarray( "fire_link", "targetname" ); + _a51 = a_structs; + _k51 = getFirstArrayKey( _a51 ); + while ( isDefined( _k51 ) ) + { + unitrigger_stub = _a51[ _k51 ]; + unregister_unitrigger( unitrigger_stub ); + _k51 = getNextArrayKey( _a51, _k51 ); + } +} + +create_buttons_and_triggers() +{ + a_structs = getstructarray( "fire_link", "targetname" ); + _a60 = a_structs; + _k60 = getFirstArrayKey( _a60 ); + while ( isDefined( _k60 ) ) + { + unitrigger_stub = _a60[ _k60 ]; + unitrigger_stub.radius = 36; + unitrigger_stub.height = 256; + unitrigger_stub.script_unitrigger_type = "unitrigger_radius_use"; + unitrigger_stub.cursor_hint = "HINT_NOICON"; + unitrigger_stub.require_look_at = 1; + m_model = spawn( "script_model", unitrigger_stub.origin ); + m_model setmodel( "p_rus_alarm_button" ); + m_model.angles = unitrigger_stub.angles; + m_model.targetname = "fire_link_button"; + m_model thread ready_to_activate( unitrigger_stub ); + wait_network_frame(); + _k60 = getNextArrayKey( _a60, _k60 ); + } +} + +ready_to_activate( unitrigger_stub ) +{ + self endon( "death" ); + self playsoundwithnotify( "vox_maxi_robot_sync_0", "sync_done" ); + self waittill( "sync_done" ); + wait 0,5; + self playsoundwithnotify( "vox_maxi_robot_await_0", "ready_to_use" ); + self waittill( "ready_to_use" ); + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( unitrigger_stub, ::activate_fire_link ); +} + +watch_for_triple_attack() +{ + t_hole = getent( "fire_link_damage", "targetname" ); + while ( !flag( "ee_mech_zombie_hole_opened" ) ) + { + t_hole waittill( "damage", damage, attacker, direction, point, type, tagname, modelname, partname, weaponname ); + if ( isDefined( weaponname ) && weaponname == "beacon_zm" && flag( "fire_link_enabled" ) ) + { + playsoundatposition( "zmb_squest_robot_floor_collapse", t_hole.origin ); + wait 3; + m_floor = getent( "easter_mechzombie_spawn", "targetname" ); + m_floor delete(); + flag_set( "ee_mech_zombie_hole_opened" ); + t_hole delete(); + return; + } + } +} + +mech_zombie_hole_valid( valid ) +{ + t_hole = getent( "fire_link_damage", "targetname" ); + if ( self istouching( t_hole ) ) + { + return 1; + } + return valid; +} + +activate_fire_link() +{ + self endon( "kill_trigger" ); + while ( 1 ) + { + self waittill( "trigger", player ); + self playsound( "zmb_squest_robot_button" ); + if ( flag( "three_robot_round" ) ) + { + level thread fire_link_cooldown( self ); + self playsound( "zmb_squest_robot_button_activate" ); + self playloopsound( "zmb_squest_robot_button_timer", 0,5 ); + flag_waitopen( "fire_link_enabled" ); + self stoploopsound( 0,5 ); + self playsound( "zmb_squest_robot_button_deactivate" ); + continue; + } + else + { + self playsound( "vox_maxi_robot_abort_0" ); + self playsound( "zmb_squest_robot_button_deactivate" ); + wait 3; + } + } +} + +fire_link_cooldown( t_button ) +{ + level notify( "fire_link_cooldown" ); + level endon( "fire_link_cooldown" ); + flag_set( "fire_link_enabled" ); + if ( isDefined( t_button ) ) + { + t_button playsound( "vox_maxi_robot_activated_0" ); + } + wait 25; + if ( isDefined( t_button ) ) + { + t_button playsound( "vox_maxi_robot_deactivated_0" ); + } + flag_clear( "fire_link_enabled" ); +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_4.gsc b/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_4.gsc new file mode 100644 index 0000000..3b99b3a --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_4.gsc @@ -0,0 +1,249 @@ +#include maps/mp/animscripts/zm_shared; +#include maps/mp/zombies/_zm_powerups; +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/zombies/_zm_ai_mechz_ffotd; +#include maps/mp/zm_tomb_vo; +#include maps/mp/zombies/_zm_ai_mechz_booster; +#include maps/mp/zombies/_zm_ai_mechz_ft; +#include maps/mp/zombies/_zm_ai_mechz_claw; +#include maps/mp/zombies/_zm_ai_mechz_dev; +#include maps/mp/zombies/_zm_ai_mechz; +#include maps/mp/zm_tomb_ee_main; +#include maps/mp/zombies/_zm_sidequests; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + declare_sidequest_stage( "little_girl_lost", "step_4", ::init_stage, ::stage_logic, ::exit_stage ); +} + +init_stage() +{ + level._cur_stage_name = "step_4"; + level.ee_mech_zombies_killed = 0; + level.ee_mech_zombies_alive = 0; + level.ee_mech_zombies_spawned = 0; + level.quadrotor_custom_behavior = ::mech_zombie_hole_search; +} + +stage_logic() +{ +/# + iprintln( level._cur_stage_name + " of little girl lost started" ); +#/ + flag_wait( "ee_quadrotor_disabled" ); + level thread sndee4music(); + while ( !flag( "ee_mech_zombie_fight_completed" ) ) + { + while ( level.ee_mech_zombies_spawned < 8 ) + { + if ( level.ee_mech_zombies_alive < 4 ) + { + ai = spawn_zombie( level.mechz_spawners[ 0 ] ); + ai thread ee_mechz_spawn( level.ee_mech_zombies_spawned % 4 ); + level.ee_mech_zombies_alive++; + level.ee_mech_zombies_spawned++; + } + wait randomfloatrange( 0,5, 1 ); + } + } + flag_wait( "ee_mech_zombie_fight_completed" ); + wait_network_frame(); + stage_completed( "little_girl_lost", level._cur_stage_name ); +} + +exit_stage( success ) +{ + level.quadrotor_custom_behavior = undefined; +} + +mech_zombie_hole_search() +{ + s_goal = getstruct( "ee_mech_hole_goal_0", "targetname" ); + if ( distance2dsquared( self.origin, s_goal.origin ) < 250000 ) + { + self setvehgoalpos( s_goal.origin, 1, 2, 1 ); + self waittill_any( "near_goal", "force_goal", "reached_end_node" ); + s_goal = getstruct( "ee_mech_hole_goal_1", "targetname" ); + self setvehgoalpos( s_goal.origin, 1, 0, 1 ); + self waittill_any( "near_goal", "force_goal", "reached_end_node" ); + wait 2; + s_goal = getstruct( "ee_mech_hole_goal_2", "targetname" ); + self setvehgoalpos( s_goal.origin, 1, 0, 1 ); + self waittill_any( "near_goal", "force_goal", "reached_end_node" ); + playsoundatposition( "zmb_squest_maxis_folly", s_goal.origin ); + maxissay( "vox_maxi_drone_upgraded_3", self ); + flag_set( "ee_quadrotor_disabled" ); + self dodamage( 200, self.origin ); + self delete(); + level.maxis_quadrotor = undefined; + } +} + +ee_mechz_spawn( n_spawn_pos ) +{ + self maps/mp/zombies/_zm_ai_mechz_ffotd::spawn_start(); + self endon( "death" ); + level endon( "intermission" ); + self mechz_attach_objects(); + self mechz_set_starting_health(); + self mechz_setup_fx(); + self mechz_setup_snd(); + self.closest_player_override = ::maps/mp/zombies/_zm_ai_mechz::get_favorite_enemy; + self.animname = "mechz_zombie"; + self.has_legs = 1; + self.no_gib = 1; + self.ignore_all_poi = 1; + self.is_mechz = 1; + self.ignore_enemy_count = 1; + self.no_damage_points = 1; + self.melee_anim_func = ::melee_anim_func; + self.meleedamage = 75; + recalc_zombie_array(); + self setphysparams( 20, 0, 80 ); + self.zombie_init_done = 1; + self notify( "zombie_init_done" ); + self.allowpain = 0; + self animmode( "normal" ); + self orientmode( "face enemy" ); + self maps/mp/zombies/_zm_spawner::zombie_setup_attack_properties(); + self.completed_emerging_into_playable_area = 1; + self notify( "completed_emerging_into_playable_area" ); + self.no_powerups = 0; + self setfreecameralockonallowed( 0 ); + self thread maps/mp/zombies/_zm_spawner::zombie_eye_glow(); + level thread maps/mp/zombies/_zm_spawner::zombie_death_event( self ); + self thread maps/mp/zombies/_zm_spawner::enemy_death_detection(); + a_spawner_structs = getstructarray( "mech_hole_spawner", "targetname" ); + spawn_pos = a_spawner_structs[ n_spawn_pos ]; + if ( !isDefined( spawn_pos.angles ) ) + { + spawn_pos.angles = ( 0, 0, 0 ); + } + self thread mechz_death(); + self thread mechz_death_ee(); + self forceteleport( spawn_pos.origin, spawn_pos.angles ); + self set_zombie_run_cycle( "walk" ); + if ( isDefined( level.mechz_find_flesh_override_func ) ) + { + level thread [[ level.mechz_find_flesh_override_func ]](); + } + else + { + self thread mechz_find_flesh(); + } + self thread mechz_jump_think( spawn_pos ); + self ee_mechz_do_jump( spawn_pos ); + self maps/mp/zombies/_zm_ai_mechz_ffotd::spawn_end(); +} + +mechz_death_ee() +{ + self waittill( "death" ); + level.ee_mech_zombies_killed++; + level.ee_mech_zombies_alive--; + + if ( level.ee_mech_zombies_killed == 4 ) + { + v_max_ammo_origin = self.origin; + level thread maps/mp/zombies/_zm_powerups::specific_powerup_drop( "full_ammo", v_max_ammo_origin ); + } + if ( level.ee_mech_zombies_killed == 8 ) + { + v_nuke_origin = self.origin; + level thread maps/mp/zombies/_zm_powerups::specific_powerup_drop( "nuke", v_nuke_origin ); + flag_set( "ee_mech_zombie_fight_completed" ); + } +} + +ee_mechz_do_jump( s_spawn_pos ) +{ + self endon( "death" ); + self endon( "kill_jump" ); +/# + if ( getDvarInt( #"E7121222" ) > 0 ) + { + println( "\nMZ: Doing Jump-Teleport\n" ); +#/ + } +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\nMZ: Jump setting not interruptable\n" ); +#/ + } + self.not_interruptable = 1; + self setfreecameralockonallowed( 0 ); + self animscripted( self.origin, self.angles, "zm_fly_out" ); + self maps/mp/animscripts/zm_shared::donotetracks( "jump_anim" ); + self ghost(); + if ( isDefined( self.m_claw ) ) + { + self.m_claw ghost(); + } + old_fx = self.fx_field; + self thread maps/mp/zombies/_zm_spawner::zombie_eye_glow_stop(); + self fx_cleanup(); + self animscripted( self.origin, self.angles, "zm_fly_hover" ); + wait level.mechz_jump_delay; + s_landing_point = getstruct( s_spawn_pos.target, "targetname" ); + if ( !isDefined( s_landing_point.angles ) ) + { + s_landing_point.angles = ( 0, 0, 0 ); + } + self animscripted( s_landing_point.origin, s_landing_point.angles, "zm_fly_in" ); + self show(); + self.fx_field = old_fx; + self setclientfield( "mechz_fx", self.fx_field ); + self thread maps/mp/zombies/_zm_spawner::zombie_eye_glow(); + if ( isDefined( self.m_claw ) ) + { + self.m_claw show(); + } + self maps/mp/animscripts/zm_shared::donotetracks( "jump_anim" ); + self.not_interruptable = 0; + self setfreecameralockonallowed( 1 ); +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\nMZ: Jump clearing not interruptable\n" ); +#/ + } + mechz_jump_cleanup(); + self.closest_jump_point = s_landing_point; +} + +sndee4music() +{ + shouldplay = sndwait(); + if ( !shouldplay ) + { + return; + } + level.music_override = 1; + level setclientfield( "mus_zmb_egg_snapshot_loop", 1 ); + ent = spawn( "script_origin", ( 0, 0, 0 ) ); + ent playloopsound( "mus_mechz_fight_loop" ); + flag_wait( "ee_mech_zombie_fight_completed" ); + level setclientfield( "mus_zmb_egg_snapshot_loop", 0 ); + level.music_override = 0; + wait 0,05; + ent delete(); +} + +sndwait() +{ + counter = 0; + while ( is_true( level.music_override ) ) + { + wait 1; + counter++; + if ( counter >= 60 ) + { + return 0; + } + } + return 1; +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_5.gsc b/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_5.gsc new file mode 100644 index 0000000..d40024f --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_5.gsc @@ -0,0 +1,151 @@ +#include maps/mp/zombies/_zm_unitrigger; +#include maps/mp/zombies/_zm_powerup_zombie_blood; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zm_tomb_ee_main; +#include maps/mp/zombies/_zm_sidequests; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + declare_sidequest_stage( "little_girl_lost", "step_5", ::init_stage, ::stage_logic, ::exit_stage ); +} + +init_stage() +{ + level._cur_stage_name = "step_5"; + level.callbackvehicledamage = ::ee_plane_vehicledamage; + level.zombie_ai_limit--; + +} + +stage_logic() +{ +/# + iprintln( level._cur_stage_name + " of little girl lost started" ); +#/ + level thread spawn_zombie_blood_plane(); + flag_wait( "ee_maxis_drone_retrieved" ); + wait_network_frame(); + stage_completed( "little_girl_lost", level._cur_stage_name ); +} + +exit_stage( success ) +{ + level.zombie_ai_limit++; +} + +spawn_zombie_blood_plane() +{ + s_biplane_pos = getstruct( "air_crystal_biplane_pos", "targetname" ); + vh_biplane = spawnvehicle( "veh_t6_dlc_zm_biplane", "zombie_blood_biplane", "biplane_zm", ( 0, 0, 1 ), ( 0, 0, 1 ) ); + vh_biplane ent_flag_init( "biplane_down", 0 ); + vh_biplane maps/mp/zombies/_zm_powerup_zombie_blood::make_zombie_blood_entity(); + vh_biplane playloopsound( "zmb_zombieblood_3rd_plane_loop", 1 ); + vh_biplane.health = 10000; + vh_biplane setcandamage( 1 ); + vh_biplane setforcenocull(); + vh_biplane attachpath( getvehiclenode( "biplane_start", "targetname" ) ); + vh_biplane startpath(); + vh_biplane setclientfield( "ee_plane_fx", 1 ); + vh_biplane ent_flag_wait( "biplane_down" ); + vh_biplane playsound( "zmb_zombieblood_3rd_plane_explode" ); + e_special_zombie = getentarray( "zombie_spawner_dig", "script_noteworthy" )[ 0 ]; + ai_pilot = spawn_zombie( e_special_zombie, "zombie_blood_pilot" ); + ai_pilot magic_bullet_shield(); + ai_pilot.ignore_enemy_count = 1; + ai_pilot maps/mp/zombies/_zm_powerup_zombie_blood::make_zombie_blood_entity(); + ai_pilot forceteleport( vh_biplane.origin, vh_biplane.angles ); + ai_pilot.sndname = "capzomb"; + ai_pilot.ignore_nuke = 1; + ai_pilot.b_zombie_blood_damage_only = 1; + playfx( level._effect[ "biplane_explode" ], vh_biplane.origin ); + vh_biplane delete(); + a_start_pos = getstructarray( "pilot_goal", "script_noteworthy" ); + a_start_pos = get_array_of_closest( ai_pilot.origin, a_start_pos ); + linker = spawn( "script_model", ai_pilot.origin ); + linker setmodel( "tag_origin" ); + ai_pilot linkto( linker ); + linker moveto( a_start_pos[ 0 ].origin, 3 ); + linker waittill( "movedone" ); + linker delete(); + ai_pilot stop_magic_bullet_shield(); + level thread zombie_pilot_sound( ai_pilot ); + ai_pilot.ignoreall = 1; + ai_pilot.zombie_move_speed = "sprint"; + ai_pilot set_zombie_run_cycle( "sprint" ); + ai_pilot thread pilot_loop_logic( a_start_pos[ 0 ] ); + ai_pilot waittill( "death" ); + level thread spawn_quadrotor_pickup( ai_pilot.origin, ai_pilot.angles ); +} + +zombie_pilot_sound( ai_pilot ) +{ + sndent = spawn( "script_origin", ai_pilot.origin ); + sndent playloopsound( "zmb_zombieblood_3rd_loop_other" ); + while ( isDefined( ai_pilot ) && isalive( ai_pilot ) ) + { + sndent.origin = ai_pilot.origin; + wait 0,3; + } + sndent delete(); +} + +pilot_loop_logic( s_start ) +{ + self endon( "death" ); + s_goal = s_start; + while ( isalive( self ) ) + { + self setgoalpos( s_goal.origin ); + self waittill( "goal" ); + s_goal = getstruct( s_goal.target, "targetname" ); + } +} + +ee_plane_vehicledamage( e_inflictor, e_attacker, n_damage, n_dflags, str_means_of_death, str_weapon, v_point, v_dir, str_hit_loc, psoffsettime, b_damage_from_underneath, n_model_index, str_part_name ) +{ + if ( self.vehicletype == "biplane_zm" && !self ent_flag( "biplane_down" ) ) + { + if ( isplayer( e_attacker ) && e_attacker.zombie_vars[ "zombie_powerup_zombie_blood_on" ] ) + { + self ent_flag_set( "biplane_down" ); + } + return 0; + } + return n_damage; +} + +spawn_quadrotor_pickup( v_origin, v_angles ) +{ + m_quadrotor = spawn( "script_model", v_origin + vectorScale( ( 0, 0, 1 ), 30 ) ); + m_quadrotor.angles = v_angles; + m_quadrotor setmodel( "veh_t6_dlc_zm_quadrotor" ); + m_quadrotor.targetname = "quadrotor_pickup"; + unitrigger_stub = spawnstruct(); + unitrigger_stub.origin = v_origin; + unitrigger_stub.radius = 36; + unitrigger_stub.height = 256; + unitrigger_stub.script_unitrigger_type = "unitrigger_radius_use"; + unitrigger_stub.hint_string = &"ZM_TOMB_DIHS"; + unitrigger_stub.cursor_hint = "HINT_NOICON"; + unitrigger_stub.require_look_at = 1; + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( unitrigger_stub, ::quadrotor_pickup_think ); + flag_wait( "ee_maxis_drone_retrieved" ); + unregister_unitrigger( unitrigger_stub ); +} + +quadrotor_pickup_think() +{ + self endon( "kill_trigger" ); + m_quadrotor = getent( "quadrotor_pickup", "targetname" ); + while ( 1 ) + { + self waittill( "trigger", player ); + player playsound( "vox_maxi_drone_upgraded_0" ); + flag_clear( "ee_quadrotor_disabled" ); + flag_set( "ee_maxis_drone_retrieved" ); + m_quadrotor delete(); + } +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_6.gsc b/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_6.gsc new file mode 100644 index 0000000..0fc5dff --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_6.gsc @@ -0,0 +1,156 @@ +#include maps/mp/zombies/_zm_weap_one_inch_punch; +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/gametypes_zm/_hud; +#include maps/mp/gametypes_zm/_hud_util; +#include maps/mp/zm_tomb_ee_main; +#include maps/mp/zombies/_zm_sidequests; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + declare_sidequest_stage( "little_girl_lost", "step_6", ::init_stage, ::stage_logic, ::exit_stage ); +} + +init_stage() +{ + level._cur_stage_name = "step_6"; + maps/mp/zombies/_zm_spawner::add_custom_zombie_spawn_logic( ::ruins_fist_glow_monitor ); +} + +stage_logic() +{ +/# + iprintln( level._cur_stage_name + " of little girl lost started" ); +#/ + level setclientfield( "sndChamberMusic", 1 ); + flag_wait( "ee_all_players_upgraded_punch" ); + level setclientfield( "sndChamberMusic", 0 ); + wait_network_frame(); + stage_completed( "little_girl_lost", level._cur_stage_name ); +} + +exit_stage( success ) +{ +} + +ruins_fist_glow_monitor() +{ + if ( flag( "ee_all_players_upgraded_punch" ) ) + { + return; + } + while ( isDefined( self.zone_name ) && self.zone_name == "ug_bottom_zone" ) + { + wait 0,1; + self setclientfield( "ee_zombie_fist_fx", 1 ); + self.has_soul = 1; + while ( isalive( self ) ) + { + self waittill( "damage", amount, inflictor, direction, point, type, tagname, modelname, partname, weaponname, idflags ); + if ( !isDefined( inflictor.n_ee_punch_souls ) ) + { + inflictor.n_ee_punch_souls = 0; + inflictor.b_punch_upgraded = 0; + } + if ( self.has_soul && inflictor.n_ee_punch_souls < 20 && isDefined( weaponname ) && weaponname == "one_inch_punch_zm" && is_true( self.completed_emerging_into_playable_area ) ) + { + self setclientfield( "ee_zombie_fist_fx", 0 ); + self.has_soul = 0; + playsoundatposition( "zmb_squest_punchtime_punched", self.origin ); + inflictor.n_ee_punch_souls++; + if ( inflictor.n_ee_punch_souls == 20 ) + { + level thread spawn_punch_upgrade_tablet( self.origin, inflictor ); + } + } + } + } +} + +spawn_punch_upgrade_tablet( v_origin, e_player ) +{ + m_tablet = spawn( "script_model", v_origin + vectorScale( ( 0, 0, 1 ), 50 ) ); + m_tablet setmodel( "p6_zm_tm_tablet" ); + m_fx = spawn( "script_model", m_tablet.origin ); + m_fx setmodel( "tag_origin" ); + m_fx setinvisibletoall(); + m_fx setvisibletoplayer( e_player ); + m_tablet linkto( m_fx ); + playfxontag( level._effect[ "special_glow" ], m_fx, "tag_origin" ); + m_fx thread rotate_punch_upgrade_tablet(); + m_tablet playloopsound( "zmb_squest_punchtime_tablet_loop", 0,5 ); + m_tablet setinvisibletoall(); + m_tablet setvisibletoplayer( e_player ); + while ( isDefined( e_player ) && !e_player istouching( m_tablet ) ) + { + wait 0,05; + } + m_tablet delete(); + m_fx delete(); + e_player playsound( "zmb_squest_punchtime_tablet_pickup" ); + if ( isDefined( e_player ) ) + { + e_player thread fadetoblackforxsec( 0, 0,3, 0,5, 0,5, "white" ); + a_zombies = getaispeciesarray( level.zombie_team, "all" ); + _a137 = a_zombies; + _k137 = getFirstArrayKey( _a137 ); + while ( isDefined( _k137 ) ) + { + zombie = _a137[ _k137 ]; + if ( distance2dsquared( e_player.origin, zombie.origin ) < 65536 && !is_true( zombie.is_mechz ) && is_true( zombie.has_legs ) && is_true( zombie.completed_emerging_into_playable_area ) ) + { + zombie.v_punched_from = e_player.origin; + zombie animcustom( ::maps/mp/zombies/_zm_weap_one_inch_punch::knockdown_zombie_animate ); + } + _k137 = getNextArrayKey( _a137, _k137 ); + } + wait 1; + e_player.b_punch_upgraded = 1; + if ( e_player hasweapon( "staff_fire_upgraded_zm" ) ) + { + e_player.str_punch_element = "fire"; + } + else if ( e_player hasweapon( "staff_air_upgraded_zm" ) ) + { + e_player.str_punch_element = "air"; + } + else if ( e_player hasweapon( "staff_lightning_upgraded_zm" ) ) + { + e_player.str_punch_element = "lightning"; + } + else if ( e_player hasweapon( "staff_water_upgraded_zm" ) ) + { + e_player.str_punch_element = "ice"; + } + else + { + e_player.str_punch_element = "upgraded"; + } + e_player thread maps/mp/zombies/_zm_weap_one_inch_punch::one_inch_punch_melee_attack(); + a_players = getplayers(); + _a178 = a_players; + _k178 = getFirstArrayKey( _a178 ); + while ( isDefined( _k178 ) ) + { + player = _a178[ _k178 ]; + if ( !isDefined( player.b_punch_upgraded ) || !player.b_punch_upgraded ) + { + return; + } + _k178 = getNextArrayKey( _a178, _k178 ); + } + flag_set( "ee_all_players_upgraded_punch" ); + } +} + +rotate_punch_upgrade_tablet() +{ + self endon( "death" ); + while ( 1 ) + { + self rotateyaw( 360, 5 ); + self waittill( "rotatedone" ); + } +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_7.gsc b/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_7.gsc new file mode 100644 index 0000000..c8acc5f --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_7.gsc @@ -0,0 +1,93 @@ +#include maps/mp/zm_tomb_chamber; +#include maps/mp/zm_tomb_vo; +#include maps/mp/zm_tomb_ee_main; +#include maps/mp/zombies/_zm_sidequests; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + declare_sidequest_stage( "little_girl_lost", "step_7", ::init_stage, ::stage_logic, ::exit_stage ); +} + +init_stage() +{ + level._cur_stage_name = "step_7"; + level.n_ee_portal_souls = 0; +} + +stage_logic() +{ +/# + iprintln( level._cur_stage_name + " of little girl lost started" ); +#/ + level thread monitor_puzzle_portal(); + level setclientfield( "sndChamberMusic", 2 ); + flag_wait( "ee_souls_absorbed" ); + level setclientfield( "sndChamberMusic", 3 ); + wait_network_frame(); + stage_completed( "little_girl_lost", level._cur_stage_name ); +} + +exit_stage( success ) +{ +} + +ee_zombie_killed_override( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime ) +{ + if ( isDefined( attacker ) && isplayer( attacker ) && maps/mp/zm_tomb_chamber::is_point_in_chamber( self.origin ) ) + { + level.n_ee_portal_souls++; + if ( level.n_ee_portal_souls == 1 ) + { + level thread ee_samantha_say( "vox_sam_generic_encourage_3" ); + } + else if ( level.n_ee_portal_souls == floor( 33,33333 ) ) + { + level thread ee_samantha_say( "vox_sam_generic_encourage_4" ); + } + else if ( level.n_ee_portal_souls == floor( 66,66666 ) ) + { + level thread ee_samantha_say( "vox_sam_generic_encourage_5" ); + } + else + { + if ( level.n_ee_portal_souls == 100 ) + { + level thread ee_samantha_say( "vox_sam_generic_encourage_0" ); + flag_set( "ee_souls_absorbed" ); + } + } + self setclientfield( "ee_zombie_soul_portal", 1 ); + } +} + +monitor_puzzle_portal() +{ +/# + if ( is_true( level.ee_debug ) ) + { + flag_set( "ee_sam_portal_active" ); + level setclientfield( "ee_sam_portal", 1 ); + return; +#/ + } + while ( !flag( "ee_souls_absorbed" ) ) + { + if ( all_staffs_inserted_in_puzzle_room() && !flag( "ee_sam_portal_active" ) ) + { + flag_set( "ee_sam_portal_active" ); + level setclientfield( "ee_sam_portal", 1 ); + } + else + { + if ( !all_staffs_inserted_in_puzzle_room() && flag( "ee_sam_portal_active" ) ) + { + flag_clear( "ee_sam_portal_active" ); + level setclientfield( "ee_sam_portal", 0 ); + } + } + wait 0,5; + } +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_8.gsc b/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_8.gsc new file mode 100644 index 0000000..9c56f69 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_ee_main_step_8.gsc @@ -0,0 +1,105 @@ +#include maps/mp/zm_tomb_chamber; +#include maps/mp/gametypes_zm/_hud; +#include maps/mp/gametypes_zm/_hud_util; +#include maps/mp/zm_tomb_vo; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zm_tomb_ee_main; +#include maps/mp/zombies/_zm_sidequests; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + declare_sidequest_stage( "little_girl_lost", "step_8", ::init_stage, ::stage_logic, ::exit_stage ); +} + +init_stage() +{ + level._cur_stage_name = "step_8"; + level.quadrotor_custom_behavior = ::move_into_portal; +} + +stage_logic() +{ +/# + iprintln( level._cur_stage_name + " of little girl lost started" ); +#/ + level notify( "tomb_sidequest_complete" ); + _a34 = get_players(); + _k34 = getFirstArrayKey( _a34 ); + while ( isDefined( _k34 ) ) + { + player = _a34[ _k34 ]; + if ( player is_player_in_chamber() ) + { + player thread fadetoblackforxsec( 0, 1, 0,5, 0,5, "white" ); + } + _k34 = getNextArrayKey( _a34, _k34 ); + } + wait 0,5; + level setclientfield( "ee_sam_portal", 2 ); + level notify( "stop_random_chamber_walls" ); + a_walls = getentarray( "chamber_wall", "script_noteworthy" ); + _a51 = a_walls; + _k51 = getFirstArrayKey( _a51 ); + while ( isDefined( _k51 ) ) + { + e_wall = _a51[ _k51 ]; + e_wall thread maps/mp/zm_tomb_chamber::move_wall_up(); + e_wall hide(); + _k51 = getNextArrayKey( _a51, _k51 ); + } + flag_wait( "ee_quadrotor_disabled" ); + wait 1; + level thread ee_samantha_say( "vox_sam_all_staff_freedom_0" ); + s_pos = getstruct( "player_portal_final", "targetname" ); + t_portal = tomb_spawn_trigger_radius( s_pos.origin, 100, 1 ); + t_portal.require_look_at = 1; + t_portal.hint_string = &"ZM_TOMB_TELE"; + t_portal thread waittill_player_activates(); + level.ee_ending_beam_fx = spawn( "script_model", s_pos.origin + vectorScale( ( 0, 1, 0 ), 300 ) ); + level.ee_ending_beam_fx.angles = vectorScale( ( 0, 1, 0 ), 90 ); + level.ee_ending_beam_fx setmodel( "tag_origin" ); + playfxontag( level._effect[ "ee_beam" ], level.ee_ending_beam_fx, "tag_origin" ); + level.ee_ending_beam_fx playsound( "zmb_squest_crystal_sky_pillar_start" ); + level.ee_ending_beam_fx playloopsound( "zmb_squest_crystal_sky_pillar_loop", 3 ); + flag_wait( "ee_samantha_released" ); + t_portal tomb_unitrigger_delete(); + wait_network_frame(); + stage_completed( "little_girl_lost", level._cur_stage_name ); +} + +exit_stage( success ) +{ +} + +waittill_player_activates() +{ + while ( 1 ) + { + self waittill( "trigger", player ); + flag_set( "ee_samantha_released" ); + } +} + +move_into_portal() +{ + s_goal = getstruct( "maxis_portal_path", "targetname" ); + if ( distance2dsquared( self.origin, s_goal.origin ) < 250000 ) + { + self setvehgoalpos( s_goal.origin, 1, 2, 1 ); + self waittill_any( "near_goal", "force_goal", "reached_end_node" ); + maxissay( "vox_maxi_drone_upgraded_1", self ); + wait 1; + level thread maxissay( "vox_maxi_drone_upgraded_2", self ); + s_goal = getstruct( s_goal.target, "targetname" ); + self setvehgoalpos( s_goal.origin, 1, 0, 1 ); + self waittill_any( "near_goal", "force_goal", "reached_end_node" ); + self playsound( "zmb_qrdrone_leave" ); + flag_set( "ee_quadrotor_disabled" ); + self dodamage( 200, self.origin ); + self delete(); + level.maxis_quadrotor = undefined; + } +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_ee_side.gsc b/zm_tomb_patch/maps/mp/zm_tomb_ee_side.gsc new file mode 100644 index 0000000..3a3eee5 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_ee_side.gsc @@ -0,0 +1,668 @@ +#include maps/mp/zm_tomb_amb; +#include maps/mp/zombies/_zm_unitrigger; +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/zombies/_zm_zonemgr; +#include maps/mp/zombies/_zm_score; +#include maps/mp/zombies/_zm_powerups; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zm_tomb_ee_lights; +#include maps/mp/zm_tomb_vo; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_sidequests; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + precacheshader( "zm_tm_wth_dog" ); + precachemodel( "p6_zm_tm_tablet" ); + precachemodel( "p6_zm_tm_tablet_muddy" ); + precachemodel( "p6_zm_tm_radio_01" ); + precachemodel( "p6_zm_tm_radio_01_panel2_blood" ); + registerclientfield( "world", "wagon_1_fire", 14000, 1, "int" ); + registerclientfield( "world", "wagon_2_fire", 14000, 1, "int" ); + registerclientfield( "world", "wagon_3_fire", 14000, 1, "int" ); + registerclientfield( "actor", "ee_zombie_tablet_fx", 14000, 1, "int" ); + registerclientfield( "toplayer", "ee_beacon_reward", 14000, 1, "int" ); + onplayerconnect_callback( ::onplayerconnect_ee_jump_scare ); + onplayerconnect_callback( ::onplayerconnect_ee_oneinchpunch ); + sq_one_inch_punch(); + a_triggers = getentarray( "audio_bump_trigger", "targetname" ); + _a43 = a_triggers; + _k43 = getFirstArrayKey( _a43 ); + while ( isDefined( _k43 ) ) + { + trigger = _a43[ _k43 ]; + if ( isDefined( trigger.script_sound ) && trigger.script_sound == "zmb_perks_bump_bottle" ) + { + trigger thread check_for_change(); + } + _k43 = getNextArrayKey( _a43, _k43 ); + } + level thread wagon_fire_challenge(); + level thread wall_hole_poster(); + level thread quadrotor_medallions(); + level thread maps/mp/zm_tomb_ee_lights::main(); + level thread radio_ee_song(); +} + +quadrotor_medallions() +{ + flag_init( "ee_medallions_collected" ); + level thread quadrotor_medallions_vo(); + level.n_ee_medallions = 4; + flag_wait( "ee_medallions_collected" ); + level thread maps/mp/zombies/_zm_audio::sndmusicstingerevent( "side_sting_4" ); + s_mg_spawn = getstruct( "mgspawn", "targetname" ); + v_spawnpt = s_mg_spawn.origin; + v_spawnang = s_mg_spawn.angles; + player = get_players()[ 0 ]; + options = player maps/mp/zombies/_zm_weapons::get_pack_a_punch_weapon_options( "mg08_upgraded_zm" ); + m_mg_model = spawn_weapon_model( "mg08_upgraded_zm", undefined, v_spawnpt, v_spawnang, options ); + playfxontag( level._effect[ "special_glow" ], m_mg_model, "tag_origin" ); + t_weapon_swap = tomb_spawn_trigger_radius( v_spawnpt, 100, 1 ); + t_weapon_swap.require_look_at = 1; + t_weapon_swap.hint_string = &"ZM_TOMB_X2PU"; + t_weapon_swap.hint_parm1 = getweapondisplayname( "mg08_upgraded_zm" ); + b_retrieved = 0; + while ( !b_retrieved ) + { + t_weapon_swap waittill( "trigger", e_player ); + b_retrieved = swap_mg( e_player ); + } + t_weapon_swap tomb_unitrigger_delete(); + m_mg_model delete(); +} + +quadrotor_medallions_vo() +{ + n_vo_counter = 0; + while ( n_vo_counter < 4 ) + { + level waittill( "quadrotor_medallion_found", v_quadrotor ); + v_quadrotor playsound( "zmb_medallion_pickup" ); + if ( isDefined( v_quadrotor ) ) + { + maxissay( "vox_maxi_drone_pickups_" + n_vo_counter, v_quadrotor ); + n_vo_counter++; + if ( isDefined( v_quadrotor ) && n_vo_counter == 4 ) + { + maxissay( "vox_maxi_drone_pickups_" + n_vo_counter, v_quadrotor ); + } + } + } +} + +swap_mg( e_player ) +{ + str_current_weapon = e_player getcurrentweapon(); + str_reward_weapon = maps/mp/zombies/_zm_weapons::get_upgrade_weapon( "mg08_zm" ); + if ( is_player_valid( e_player ) && !e_player.is_drinking && !is_placeable_mine( str_current_weapon ) && !is_equipment( str_current_weapon ) && level.revive_tool != str_current_weapon && str_current_weapon != "none" && !e_player hacker_active() ) + { + if ( e_player hasweapon( str_reward_weapon ) ) + { + e_player givemaxammo( str_reward_weapon ); + } + else + { + a_weapons = e_player getweaponslistprimaries(); + if ( isDefined( a_weapons ) && a_weapons.size >= get_player_weapon_limit( e_player ) ) + { + e_player takeweapon( str_current_weapon ); + } + e_player giveweapon( str_reward_weapon, 0, e_player maps/mp/zombies/_zm_weapons::get_pack_a_punch_weapon_options( str_reward_weapon ) ); + e_player givestartammo( str_reward_weapon ); + e_player switchtoweapon( str_reward_weapon ); + } + return 1; + } + else + { + return 0; + } +} + +wall_hole_poster() +{ + m_poster = getent( "hole_poster", "targetname" ); + m_poster setcandamage( 1 ); + m_poster.health = 1000; + m_poster.maxhealth = m_poster.health; + while ( 1 ) + { + m_poster waittill( "damage" ); + if ( m_poster.health <= 0 ) + { + m_poster physicslaunch( m_poster.origin, ( 0, 0, 0 ) ); + } + } +} + +wagon_fire_challenge() +{ + flag_init( "ee_wagon_timer_start" ); + flag_init( "ee_wagon_challenge_complete" ); + s_powerup = getstruct( "wagon_powerup", "targetname" ); + flag_wait( "start_zombie_round_logic" ); + wagon_fire_start(); + while ( 1 ) + { + flag_wait( "ee_wagon_timer_start" ); + flag_wait_or_timeout( "ee_wagon_challenge_complete", 30 ); + if ( !flag( "ee_wagon_challenge_complete" ) ) + { + wagon_fire_start(); + flag_clear( "ee_wagon_timer_start" ); + continue; + } + else + { + maps/mp/zombies/_zm_powerups::specific_powerup_drop( "zombie_blood", s_powerup.origin ); + level waittill( "end_of_round" ); + waittillframeend; + while ( level.weather_rain > 0 ) + { + level waittill( "end_of_round" ); + waittillframeend; + } + wagon_fire_start(); + flag_clear( "ee_wagon_timer_start" ); + flag_clear( "ee_wagon_challenge_complete" ); + } + } +} + +wagon_fire_start() +{ + level.n_wagon_fires_out = 0; + a_triggers = getentarray( "wagon_damage_trigger", "targetname" ); + _a249 = a_triggers; + _k249 = getFirstArrayKey( _a249 ); + while ( isDefined( _k249 ) ) + { + trigger = _a249[ _k249 ]; + trigger thread wagon_fire_trigger_watch(); + level setclientfield( trigger.script_noteworthy, 1 ); + _k249 = getNextArrayKey( _a249, _k249 ); + } +} + +wagon_fire_trigger_watch() +{ + self notify( "watch_reset" ); + self endon( "watch_reset" ); + while ( 1 ) + { + self waittill( "damage", damage, attacker, direction, point, type, tagname, modelname, partname, weaponname ); + if ( isplayer( attacker ) || attacker getcurrentweapon() == "staff_water_zm" && attacker getcurrentweapon() == "staff_water_upgraded_zm" ) + { + level.n_wagon_fires_out++; + if ( !flag( "ee_wagon_timer_start" ) ) + { + flag_set( "ee_wagon_timer_start" ); + } + level setclientfield( self.script_noteworthy, 0 ); + if ( level.n_wagon_fires_out == 3 ) + { + flag_set( "ee_wagon_challenge_complete" ); + level thread maps/mp/zombies/_zm_audio::sndmusicstingerevent( "side_sting_1" ); + } + return; + } + } +} + +check_for_change() +{ + while ( 1 ) + { + self waittill( "trigger", e_player ); + if ( e_player getstance() == "prone" ) + { + e_player maps/mp/zombies/_zm_score::add_to_player_score( 25 ); + play_sound_at_pos( "purchase", e_player.origin ); + return; + } + else + { + wait 0,1; + } + } +} + +onplayerconnect_ee_jump_scare() +{ + self endon( "disconnect" ); + if ( !isDefined( level.jump_scare_lookat_point ) ) + { + level.jump_scare_lookat_point = getstruct( "struct_gg_look", "targetname" ); + } + if ( !isDefined( level.b_saw_jump_scare ) ) + { + level.b_saw_jump_scare = 0; + } + while ( !level.b_saw_jump_scare ) + { + n_time = 0; + while ( self adsbuttonpressed() && n_time < 25 ) + { + n_time++; + wait 0,05; + } + if ( n_time >= 25 && self adsbuttonpressed() && self maps/mp/zombies/_zm_zonemgr::is_player_in_zone( "zone_nml_18" ) && sq_is_weapon_sniper( self getcurrentweapon() ) && is_player_looking_at( level.jump_scare_lookat_point.origin, 0,998, 0, undefined ) ) + { + self playsoundtoplayer( "zmb_easteregg_scarydog", self ); + self.wth_elem = newclienthudelem( self ); + self.wth_elem.horzalign = "fullscreen"; + self.wth_elem.vertalign = "fullscreen"; + self.wth_elem.sort = 1000; + self.wth_elem.foreground = 0; + self.wth_elem setshader( "zm_tm_wth_dog", 640, 480 ); + self.wth_elem.hidewheninmenu = 1; + j_time = 0; + while ( self adsbuttonpressed() && j_time < 5 ) + { + j_time++; + wait 0,05; + } + self.wth_elem destroy(); + level.b_saw_jump_scare = 1; + } + wait 0,05; + } +} + +sq_is_weapon_sniper( str_weapon ) +{ + a_snipers = array( "dsr50" ); + _a380 = a_snipers; + _k380 = getFirstArrayKey( _a380 ); + while ( isDefined( _k380 ) ) + { + str_sniper = _a380[ _k380 ]; + if ( issubstr( str_weapon, str_sniper ) && !issubstr( str_weapon, "+is" ) ) + { + return 1; + } + _k380 = getNextArrayKey( _a380, _k380 ); + } + return 0; +} + +onplayerconnect_ee_oneinchpunch() +{ + self.sq_one_inch_punch_stage = 0; + self.sq_one_inch_punch_kills = 0; +} + +sq_one_inch_punch_disconnect_watch() +{ + self waittill( "disconnect" ); + if ( isDefined( self.sq_one_inch_punch_tablet ) ) + { + self.sq_one_inch_punch_tablet delete(); + } + spawn_tablet_model( self.sq_one_inch_punch_tablet_num, "bunker", "muddy" ); + level.n_tablets_remaining++; +} + +sq_one_inch_punch_death_watch() +{ + self endon( "disconnect" ); + self waittill( "bled_out" ); + if ( self.sq_one_inch_punch_stage < 6 ) + { + self.sq_one_inch_punch_stage = 0; + self.sq_one_inch_punch_kills = 0; + if ( isDefined( self.sq_one_inch_punch_tablet ) ) + { + self.sq_one_inch_punch_tablet delete(); + } + spawn_tablet_model( self.sq_one_inch_punch_tablet_num, "bunker", "muddy" ); + level.n_tablets_remaining++; + } +} + +sq_one_inch_punch() +{ + maps/mp/zombies/_zm_spawner::add_custom_zombie_spawn_logic( ::bunker_volume_death_check ); + maps/mp/zombies/_zm_spawner::add_custom_zombie_spawn_logic( ::church_volume_death_check ); + level.n_tablets_remaining = 4; + a_tablets = []; + n_player_id = 0; + while ( n_player_id < level.n_tablets_remaining ) + { + a_tablets[ n_player_id ] = spawn_tablet_model( n_player_id + 1, "bunker", "muddy" ); + n_player_id++; + } + t_bunker = getent( "trigger_oneinchpunch_bunker_table", "targetname" ); + t_bunker thread bunker_trigger_thread(); + t_bunker setcursorhint( "HINT_NOICON" ); + t_birdbath = getent( "trigger_oneinchpunch_church_birdbath", "targetname" ); + t_birdbath thread birdbath_trigger_thread(); + t_birdbath setcursorhint( "HINT_NOICON" ); +} + +bunker_trigger_thread() +{ + while ( 1 ) + { + self waittill( "trigger", player ); + if ( player.sq_one_inch_punch_stage == 0 ) + { + player.sq_one_inch_punch_stage++; + player.sq_one_inch_punch_tablet_num = level.n_tablets_remaining; + player setclientfieldtoplayer( "player_tablet_state", 2 ); + player playsound( "zmb_squest_oiptablet_pickup" ); + player thread sq_one_inch_punch_disconnect_watch(); + player thread sq_one_inch_punch_death_watch(); + m_tablet = getent( "tablet_bunker_" + level.n_tablets_remaining, "targetname" ); + m_tablet delete(); + level.n_tablets_remaining--; + +/# + iprintln( "1 - take the tablet to the church" ); +#/ + } + if ( player.sq_one_inch_punch_stage == 4 ) + { + player.sq_one_inch_punch_tablet = spawn_tablet_model( player.sq_one_inch_punch_tablet_num, "bunker", "clean" ); + player.sq_one_inch_punch_stage++; + player setclientfieldtoplayer( "player_tablet_state", 0 ); + player playsound( "zmb_squest_oiptablet_place_table" ); +/# + iprintln( "5 - charge the tablet in the bunker" ); +#/ + continue; + } + else + { + if ( player.sq_one_inch_punch_stage == 6 && isDefined( player.beacon_ready ) && player.beacon_ready ) + { + player setclientfieldtoplayer( "ee_beacon_reward", 0 ); + player maps/mp/zombies/_zm_weapons::weapon_give( "beacon_zm" ); + player thread richtofenrespondvoplay( "get_beacon" ); + if ( isDefined( level.zombie_include_weapons[ "beacon_zm" ] ) && !level.zombie_include_weapons[ "beacon_zm" ] ) + { + level.zombie_include_weapons[ "beacon_zm" ] = 1; + level.zombie_weapons[ "beacon_zm" ].is_in_box = 1; + } + player playsound( "zmb_squest_oiptablet_get_reward" ); + player.sq_one_inch_punch_stage++; +/# + iprintln( "7 - tablet is activated; bestow rewards" ); +#/ + } + } + } +} + +birdbath_trigger_thread() +{ + while ( 1 ) + { + self waittill( "trigger", player ); + if ( player.sq_one_inch_punch_stage == 1 ) + { + if ( isDefined( player.sq_one_inch_punch_reclean ) ) + { + player.sq_one_inch_punch_reclean = undefined; + player.sq_one_inch_punch_stage++; + player.sq_one_inch_punch_tablet = spawn_tablet_model( player.sq_one_inch_punch_tablet_num, "church", "clean" ); + level thread tablet_cleanliness_chastise( player, 1 ); + } + else + { + player.sq_one_inch_punch_tablet = spawn_tablet_model( player.sq_one_inch_punch_tablet_num, "church", "muddy" ); + } + player playsound( "zmb_squest_oiptablet_bathe" ); + player setclientfieldtoplayer( "player_tablet_state", 0 ); + player.sq_one_inch_punch_stage++; +/# + iprintln( "2 - charge the tablet in the church" ); +#/ + } + if ( player.sq_one_inch_punch_stage == 3 ) + { + player setclientfieldtoplayer( "player_tablet_state", 1 ); + player.sq_one_inch_punch_stage++; + if ( isDefined( player.sq_one_inch_punch_tablet ) ) + { + player.sq_one_inch_punch_tablet delete(); + } + player playsound( "zmb_squest_oiptablet_pickup_clean" ); + player thread tablet_cleanliness_thread(); +/# + iprintln( "4 - take the tablet to the tank bunker" ); +#/ + } + } +} + +tablet_cleanliness_thread() +{ + self endon( "death_or_disconnect" ); + while ( self.sq_one_inch_punch_stage == 4 ) + { + if ( self.is_player_slowed ) + { + self setclientfieldtoplayer( "player_tablet_state", 2 ); + self playsoundtoplayer( "zmb_squest_oiptablet_dirtied", self ); + self.sq_one_inch_punch_stage = 1; + self.sq_one_inch_punch_reclean = 1; + level thread tablet_cleanliness_chastise( self ); +/# + iprintln( "1 - take the tablet to the church" ); +#/ + } + wait 1; + } +} + +tablet_cleanliness_chastise( e_player, b_cleaned ) +{ + if ( !isDefined( b_cleaned ) ) + { + b_cleaned = 0; + } + if ( isDefined( e_player ) && isDefined( level.sam_talking ) || level.sam_talking && flag( "story_vo_playing" ) ) + { + return; + } + flag_set( "story_vo_playing" ); + e_player set_player_dontspeak( 1 ); + level.sam_talking = 1; + str_line = "vox_sam_generic_chastise_7"; + if ( b_cleaned ) + { + str_line = "vox_sam_generic_chastise_8"; + } + if ( isDefined( e_player ) ) + { + e_player playsoundtoplayer( str_line, e_player ); + } + n_duration = soundgetplaybacktime( str_line ); + wait ( n_duration / 1000 ); + level.sam_talking = 0; + flag_clear( "story_vo_playing" ); + if ( isDefined( e_player ) ) + { + e_player set_player_dontspeak( 0 ); + } +} + +bunker_volume_death_check() +{ + self waittill( "death" ); + if ( !isDefined( self ) ) + { + return; + } + volume_name = "oneinchpunch_bunker_volume"; + volume = getent( volume_name, "targetname" ); +/# + assert( isDefined( volume ), volume_name + " does not exist" ); +#/ + attacker = self.attacker; + if ( isDefined( attacker ) && isplayer( attacker ) ) + { + if ( attacker.sq_one_inch_punch_stage == 5 || self.damagemod == "MOD_MELEE" && self.damageweapon == "tomb_shield_zm" ) + { + if ( self istouching( volume ) ) + { + self setclientfield( "ee_zombie_tablet_fx", 1 ); + attacker.sq_one_inch_punch_kills++; +/# + iprintln( "kill count: " + attacker.sq_one_inch_punch_kills ); +#/ + if ( attacker.sq_one_inch_punch_kills >= 20 ) + { + attacker thread bunker_spawn_reward(); + attacker.sq_one_inch_punch_stage++; + level thread maps/mp/zombies/_zm_audio::sndmusicstingerevent( "side_sting_3" ); +/# + iprintln( "6 - activate the tablet in the bunker" ); +#/ + } + } + } + } +} + +bunker_spawn_reward() +{ + self endon( "disconnect" ); + wait 2; + self setclientfieldtoplayer( "ee_beacon_reward", 1 ); + wait 2; + self.beacon_ready = 1; +} + +church_volume_death_check() +{ + self waittill( "death" ); + if ( !isDefined( self ) ) + { + return; + } + volume_name = "oneinchpunch_church_volume"; + volume = getent( volume_name, "targetname" ); +/# + assert( isDefined( volume ), volume_name + " does not exist" ); +#/ + attacker = self.attacker; + if ( isDefined( attacker ) && isplayer( attacker ) ) + { + if ( attacker.sq_one_inch_punch_stage == 2 || self.damagemod == "MOD_MELEE" && self.damageweapon == "tomb_shield_zm" ) + { + if ( self istouching( volume ) ) + { + self setclientfield( "ee_zombie_tablet_fx", 1 ); + attacker.sq_one_inch_punch_kills++; +/# + iprintln( "kill count: " + attacker.sq_one_inch_punch_kills ); +#/ + if ( attacker.sq_one_inch_punch_kills >= 20 ) + { + attacker.sq_one_inch_punch_stage++; + attacker.sq_one_inch_punch_kills = 0; + attacker.sq_one_inch_punch_tablet delete(); + attacker.sq_one_inch_punch_tablet = spawn_tablet_model( attacker.sq_one_inch_punch_tablet_num, "church", "clean" ); + level thread maps/mp/zombies/_zm_audio::sndmusicstingerevent( "side_sting_6" ); +/# + iprintln( "3 - tablet is charged, pick up the tablet from the birdbath" ); +#/ + } + } + } + } +} + +spawn_tablet_model( n_player_id, str_location, str_state ) +{ + s_tablet_spawn = getstruct( "oneinchpunch_" + str_location + "_tablet_" + n_player_id, "targetname" ); + v_spawnpt = s_tablet_spawn.origin; + v_spawnang = s_tablet_spawn.angles; + m_tablet = spawn( "script_model", v_spawnpt ); + m_tablet.angles = v_spawnang; + if ( str_state == "clean" ) + { + m_tablet setmodel( "p6_zm_tm_tablet" ); + if ( str_location == "church" ) + { + m_tablet playsound( "zmb_squest_oiptablet_charged" ); + } + } + else + { + m_tablet setmodel( "p6_zm_tm_tablet_muddy" ); + } + m_tablet.targetname = "tablet_" + str_location + "_" + n_player_id; + return m_tablet; +} + +radio_ee_song() +{ + level.found_ee_radio_count = 0; + wait 3; + a_structs = getstructarray( "ee_radio_pos", "targetname" ); + _a775 = a_structs; + _k775 = getFirstArrayKey( _a775 ); + while ( isDefined( _k775 ) ) + { + unitrigger_stub = _a775[ _k775 ]; + unitrigger_stub.radius = 50; + unitrigger_stub.height = 128; + unitrigger_stub.script_unitrigger_type = "unitrigger_radius_use"; + unitrigger_stub.cursor_hint = "HINT_NOICON"; + unitrigger_stub.require_look_at = 1; + m_radio = spawn( "script_model", unitrigger_stub.origin ); + m_radio.angles = unitrigger_stub.angles; + m_radio setmodel( "p6_zm_tm_radio_01" ); + m_radio attach( "p6_zm_tm_radio_01_panel2_blood", "tag_j_cover" ); + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( unitrigger_stub, ::radio_ee_think ); +/# + unitrigger_stub thread radio_ee_debug(); +#/ + wait_network_frame(); + _k775 = getNextArrayKey( _a775, _k775 ); + } +} + +radio_ee_debug() +{ +/# + self endon( "stop_display" ); + while ( 1 ) + { + print3d( self.origin, "R", vectorScale( ( 0, 0, 0 ), 255 ), 1 ); + wait 0,05; +#/ + } +} + +radio_ee_think() +{ + self endon( "kill_trigger" ); + while ( 1 ) + { + self waittill( "trigger", player ); + if ( is_player_valid( player ) && isDefined( level.music_override ) && !level.music_override ) + { + level.found_ee_radio_count++; + if ( level.found_ee_radio_count == 3 ) + { + level.music_override = 1; + ent = spawn( "script_origin", ( 0, 0, 0 ) ); + level thread maps/mp/zm_tomb_amb::sndmuseggplay( ent, "mus_zmb_secret_song_a7x", 352 ); + } +/# + self.stub notify( "stop_display" ); +#/ + maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( self.stub ); + return; + } + } +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_ffotd.gsc b/zm_tomb_patch/maps/mp/zm_tomb_ffotd.gsc new file mode 100644 index 0000000..5bb88de --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_ffotd.gsc @@ -0,0 +1,240 @@ +#include codescripts/struct; +#include maps/mp/zombies/_zm_zonemgr; +#include maps/mp/zombies/_zm_utility; +#include common_scripts/utility; +#include maps/mp/_utility; + +main_start() +{ + level thread spawned_collision_ffotd(); + level thread spawn_kill_brushes(); + level thread respawn_struct_fix(); + onplayerconnect_callback( ::one_inch_punch_take_think ); +} + +main_end() +{ + level thread player_spawn_fix(); + level thread update_charger_position(); + level thread traversal_blocker_disabler(); +} + +update_charger_position() +{ + _a26 = level.a_elemental_staffs; + _k26 = getFirstArrayKey( _a26 ); + while ( isDefined( _k26 ) ) + { + e_staff = _a26[ _k26 ]; + e_staff moveto( e_staff.charger.origin, 0,05 ); + _k26 = getNextArrayKey( _a26, _k26 ); + } + _a31 = level.a_elemental_staffs_upgraded; + _k31 = getFirstArrayKey( _a31 ); + while ( isDefined( _k31 ) ) + { + e_staff = _a31[ _k31 ]; + e_staff moveto( e_staff.charger.origin, 0,05 ); + _k31 = getNextArrayKey( _a31, _k31 ); + } +} + +spawned_collision_ffotd() +{ + precachemodel( "collision_ai_64x64x10" ); + precachemodel( "collision_wall_256x256x10_standard" ); + precachemodel( "collision_wall_512x512x10_standard" ); + precachemodel( "collision_geo_256x256x10_standard" ); + precachemodel( "collision_geo_512x512x10_standard" ); + precachemodel( "collision_geo_ramp_standard" ); + precachemodel( "collision_player_512x512x512" ); + precachemodel( "collision_geo_32x32x128_standard" ); + precachemodel( "collision_geo_64x64x128_standard" ); + precachemodel( "collision_geo_64x64x256_standard" ); + precachemodel( "collision_player_wall_256x256x10" ); + precachemodel( "collision_player_wall_512x512x10" ); + precachemodel( "collision_player_wall_32x32x10" ); + precachemodel( "collision_geo_64x64x10_standard" ); + precachemodel( "p6_zm_tm_barbedwire_tube" ); + precachemodel( "p6_zm_tm_rubble_rebar_group" ); + flag_wait( "start_zombie_round_logic" ); + m_disconnector = spawn( "script_model", ( -568, -956, 160 ), 1 ); + m_disconnector setmodel( "collision_ai_64x64x10" ); + m_disconnector.angles = vectorScale( ( 0, 0, -1 ), 35 ); + m_disconnector disconnectpaths(); + m_disconnector ghost(); + if ( isDefined( level.optimise_for_splitscreen ) && !level.optimise_for_splitscreen ) + { + collision1a = spawn( "script_model", ( 1128, -2664,25, 122 ) ); + collision1a setmodel( "collision_player_wall_256x256x10" ); + collision1a.angles = vectorScale( ( 0, 0, -1 ), 285 ); + collision1a ghost(); + collision1b = spawn( "script_model", ( 909,5, -2856,5, -6 ) ); + collision1b setmodel( "collision_player_wall_512x512x10" ); + collision1b.angles = vectorScale( ( 0, 0, -1 ), 195 ); + collision1b ghost(); + collision1c = spawn( "script_model", ( 415, -2989, -6 ) ); + collision1c setmodel( "collision_player_wall_512x512x10" ); + collision1c.angles = vectorScale( ( 0, 0, -1 ), 195 ); + collision1c ghost(); + collision2a = spawn( "script_model", ( -6760, -6536, 280 ) ); + collision2a setmodel( "collision_geo_512x512x10_standard" ); + collision2a.angles = ( 0, 0, -1 ); + collision2a ghost(); + collision2b = spawn( "script_model", ( -6224, -6536, 280 ) ); + collision2b setmodel( "collision_geo_512x512x10_standard" ); + collision2b.angles = ( 0, 0, -1 ); + collision2b ghost(); + collision2c = spawn( "script_model", ( -5704, -6536, 280 ) ); + collision2c setmodel( "collision_geo_512x512x10_standard" ); + collision2c.angles = ( 0, 0, -1 ); + collision2c ghost(); + collision3a = spawn( "script_model", ( 1088, 4216, -192 ) ); + collision3a setmodel( "collision_geo_256x256x10_standard" ); + collision3a.angles = ( 0, 0, -1 ); + collision3a ghost(); + collision4a = spawn( "script_model", ( 545,36, -2382,3, 404 ) ); + collision4a setmodel( "collision_wall_256x256x10_standard" ); + collision4a.angles = ( 0, 293,8, 180 ); + collision4a ghost(); + collision4b = spawn( "script_model", ( 579,36, -2367,3, 264 ) ); + collision4b setmodel( "collision_geo_ramp_standard" ); + collision4b.angles = ( 0, 293,8, 180 ); + collision4b ghost(); + collision5a = spawn( "script_model", ( 67,87, -3193,25, 504 ) ); + collision5a setmodel( "collision_player_512x512x512" ); + collision5a.angles = vectorScale( ( 0, 0, -1 ), 14,1 ); + collision5a ghost(); + collision5b = spawn( "script_model", ( 292,5, -2865,5, 286 ) ); + collision5b setmodel( "collision_geo_32x32x128_standard" ); + collision5b.angles = ( 270, 22,4, 0 ); + collision5b ghost(); + collision5c = spawn( "script_model", ( 292,5, -2865,5, 266 ) ); + collision5c setmodel( "collision_geo_32x32x128_standard" ); + collision5c.angles = ( 270, 22,4, 0 ); + collision5c ghost(); + collision5d = spawn( "script_model", ( 339, -3024,5, 280 ) ); + collision5d setmodel( "collision_geo_64x64x128_standard" ); + collision5d.angles = ( 270, 18,2, 0 ); + collision5d ghost(); + model5a = spawn( "script_model", ( 248,15, -2917,26, 351,01 ) ); + model5a setmodel( "p6_zm_tm_barbedwire_tube" ); + model5a.angles = ( 6,00001, 188, 90 ); + collision6a = spawn( "script_model", ( -227,25, 4010,25, -96 ) ); + collision6a setmodel( "collision_player_wall_256x256x10" ); + collision6a.angles = vectorScale( ( 0, 0, -1 ), 265,299 ); + collision6a ghost(); + model6a = spawn( "script_model", ( -231,124, 4093,08, -230,685 ) ); + model6a setmodel( "p6_zm_tm_rubble_rebar_group" ); + model6a.angles = ( 25,883, 2,13901, 0,55601 ); + collision7a = spawn( "script_model", ( 599, -2478, 184 ) ); + collision7a setmodel( "collision_geo_64x64x128_standard" ); + collision7a.angles = ( 270, 14,7, 0 ); + collision7a ghost(); + collision8a = spawn( "script_model", ( -3190, -555, -111 ) ); + collision8a setmodel( "collision_player_wall_512x512x10" ); + collision8a.angles = vectorScale( ( 0, 0, -1 ), 1,8 ); + collision8a ghost(); + collision11a = spawn( "script_model", ( 812,812, -64,1434, 384 ) ); + collision11a setmodel( "collision_player_wall_256x256x10" ); + collision11a.angles = vectorScale( ( 0, 0, -1 ), 9,99998 ); + collision11a ghost(); + collision12a = spawn( "script_model", ( 180, 4128, 40 ) ); + collision12a setmodel( "collision_player_wall_512x512x10" ); + collision12a.angles = vectorScale( ( 0, 0, -1 ), 270 ); + collision12a ghost(); + collision13a = spawn( "script_model", ( 2088, 588, 240 ) ); + collision13a setmodel( "collision_player_wall_512x512x10" ); + collision13a.angles = ( 0, 0, -1 ); + collision13a ghost(); + collision14a = spawn( "script_model", ( -787, 375, 380 ) ); + collision14a setmodel( "collision_player_wall_256x256x10" ); + collision14a.angles = ( 0, 0, -1 ); + collision14a ghost(); + collision14b = spawn( "script_model", ( -899, 375, 236 ) ); + collision14b setmodel( "collision_player_wall_32x32x10" ); + collision14b.angles = ( 0, 0, -1 ); + collision14b ghost(); + collision15a = spawn( "script_model", ( 1704, 2969,34, -187,83 ) ); + collision15a setmodel( "collision_geo_64x64x10_standard" ); + collision15a.angles = vectorScale( ( 0, 0, -1 ), 47,4 ); + collision15a ghost(); + } +} + +spawn_kill_brushes() +{ + t_killbrush_1 = spawn( "trigger_box", ( 1643, 2168, 96 ), 0, 256, 1200, 512 ); + t_killbrush_1.script_noteworthy = "kill_brush"; + t_killbrush_2 = spawn( "trigger_box", ( -1277, 892, 184 ), 0, 148, 88, 128 ); + t_killbrush_2.script_noteworthy = "kill_brush"; +} + +one_inch_punch_take_think() +{ + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "bled_out" ); + self.one_inch_punch_flag_has_been_init = 0; + if ( self ent_flag_exist( "melee_punch_cooldown" ) ) + { + } + } +} + +player_spawn_fix() +{ + s_zone_nml_18 = level.zones[ "zone_nml_18" ]; + s_zone_nml_19 = level.zones[ "zone_nml_19" ]; + add_adjacent_zone( "zone_nml_18", "zone_nml_19", "activate_zone_ruins" ); +} + +respawn_struct_fix() +{ + spawn1 = createstruct(); + spawn1.model = undefined; + spawn1.origin = ( 2400, 120, 160 ); + spawn1.targetname = "nml_11_spawn_points"; + spawn1.radius = 32; + spawn1.script_int = 1; + spawn2 = createstruct(); + spawn2.model = undefined; + spawn2.origin = ( 2392, 360, 160 ); + spawn2.targetname = "nml_11_spawn_points"; + spawn2.radius = 32; + spawn2.script_int = 1; + spawn3 = createstruct(); + spawn3.model = undefined; + spawn3.origin = ( 2616, 152, 160 ); + spawn3.targetname = "nml_11_spawn_points"; + spawn3.radius = 32; + spawn3.script_int = 1; +} + +traversal_blocker_disabler() +{ + level endon( "activate_zone_nml" ); + pos1 = ( -1509, 3912, -168 ); + pos2 = ( 672, 3720, -179 ); + b_too_close = 0; + while ( level.round_number < 10 && !b_too_close ) + { + a_players = getplayers(); + _a310 = a_players; + _k310 = getFirstArrayKey( _a310 ); + while ( isDefined( _k310 ) ) + { + player = _a310[ _k310 ]; + if ( distancesquared( player.origin, pos1 ) < 4096 || distancesquared( player.origin, pos2 ) < 4096 ) + { + b_too_close = 1; + } + _k310 = getNextArrayKey( _a310, _k310 ); + } + wait 1; + } + m_traversal_blocker = getent( "traversal_blocker", "targetname" ); + m_traversal_blocker.origin += vectorScale( ( 0, 0, -1 ), 10000 ); + m_traversal_blocker connectpaths(); +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_fx.gsc b/zm_tomb_patch/maps/mp/zm_tomb_fx.gsc new file mode 100644 index 0000000..be5fb1f --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_fx.gsc @@ -0,0 +1,147 @@ +#include maps/mp/_utility; + +#using_animtree( "fxanim_props" ); +#using_animtree( "fxanim_props_dlc4" ); + +main() +{ + precache_createfx_fx(); + precache_scripted_fx(); + precache_fxanim_props(); + precache_fxanim_props_dlc4(); + maps/mp/createfx/zm_tomb_fx::main(); +} + +precache_scripted_fx() +{ + level._effect[ "eye_glow_blue" ] = loadfx( "maps/zombie/fx_zombie_eye_single_blue" ); + level._effect[ "switch_sparks" ] = loadfx( "env/electrical/fx_elec_wire_spark_burst" ); + level._effect[ "zapper_light_ready" ] = loadfx( "maps/zombie_tomb/fx_tomb_capture_light_green" ); + level._effect[ "zapper_light_notready" ] = loadfx( "maps/zombie_tomb/fx_tomb_capture_light_red" ); + level._effect[ "m14_zm_fx" ] = loadfx( "maps/zombie/fx_zmb_wall_buy_rifle" ); + level._effect[ "fx_tomb_ee_vortex" ] = loadfx( "maps/zombie_tomb/fx_tomb_ee_vortex" ); + level._effect[ "poltergeist" ] = loadfx( "misc/fx_zombie_couch_effect" ); + level._effect[ "door_steam" ] = loadfx( "maps/zombie_tomb/fx_tomb_dieselmagic_doors_steam" ); + level._effect[ "zomb_gib" ] = loadfx( "maps/zombie/fx_zmb_tranzit_lava_torso_explo" ); + level._effect[ "spawn_cloud" ] = loadfx( "maps/zombie/fx_zmb_race_zombie_spawn_cloud" ); + level._effect[ "robot_foot_stomp" ] = loadfx( "maps/zombie_tomb/fx_tomb_robot_dust" ); + level._effect[ "eject_warning" ] = loadfx( "maps/zombie_tomb/fx_tomb_robot_eject_warning" ); + level._effect[ "eject_steam" ] = loadfx( "maps/zombie_tomb/fx_tomb_robot_eject_steam" ); + level._effect[ "giant_robot_footstep_warning_light" ] = loadfx( "maps/zombie_tomb/fx_tomb_foot_warning_light_red" ); + level._effect[ "air_glow" ] = loadfx( "maps/zombie_tomb/fx_tomb_elem_reveal_air_glow" ); + level._effect[ "elec_glow" ] = loadfx( "maps/zombie_tomb/fx_tomb_elem_reveal_elec_glow" ); + level._effect[ "fire_glow" ] = loadfx( "maps/zombie_tomb/fx_tomb_elem_reveal_fire_glow" ); + level._effect[ "ice_glow" ] = loadfx( "maps/zombie_tomb/fx_tomb_elem_reveal_ice_glow" ); + level._effect[ "digging" ] = loadfx( "maps/zombie_tomb/fx_tomb_shovel_dig" ); + level._effect[ "mechz_death" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_death" ); + level._effect[ "mechz_sparks" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_dmg_sparks" ); + level._effect[ "mechz_steam" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_dmg_steam" ); + level._effect[ "mechz_claw" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_wpn_claw" ); + level._effect[ "mechz_claw_arm" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_wpn_source" ); + level._effect[ "staff_charge" ] = loadfx( "weapon/zmb_staff/fx_zmb_staff_charge" ); + level._effect[ "staff_soul" ] = loadfx( "weapon/zmb_staff/fx_zmb_staff_charge_souls" ); + level._effect[ "fire_muzzle" ] = loadfx( "weapon/zmb_staff/fx_zmb_staff_fire_muz_flash_1p" ); + level._effect[ "crypt_gem_beam" ] = loadfx( "weapon/zmb_staff/fx_zmb_staff_charge_souls" ); + level._effect[ "crypt_wall_drop" ] = loadfx( "maps/zombie_tomb/fx_tomb_chamber_walls_impact" ); + level._effect[ "air_puzzle_smoke" ] = loadfx( "maps/zombie_tomb/fx_tomb_puzzle_air_smoke" ); + level._effect[ "elec_piano_glow" ] = loadfx( "maps/zombie_tomb/fx_tomb_puzzle_elec_sparks" ); + level._effect[ "fire_ash_explosion" ] = loadfx( "maps/zombie_tomb/fx_tomb_puzzle_fire_exp_ash" ); + level._effect[ "fire_sacrifice_flame" ] = loadfx( "maps/zombie_tomb/fx_tomb_puzzle_fire_sacrifice" ); + level._effect[ "fire_torch" ] = loadfx( "maps/zombie_tomb/fx_tomb_puzzle_fire_torch" ); + level._effect[ "ice_explode" ] = loadfx( "maps/zombie_tomb/fx_tomb_puzzle_ice_pipe_burst" ); + level._effect[ "puzzle_orb_trail" ] = loadfx( "maps/zombie_tomb/fx_tomb_puzzle_plinth_trail" ); + level._effect[ "teleport_1p" ] = loadfx( "maps/zombie_tomb/fx_tomb_teleport_1p" ); + level._effect[ "teleport_3p" ] = loadfx( "maps/zombie_tomb/fx_tomb_teleport_3p" ); + level._effect[ "teleport_air" ] = loadfx( "maps/zombie_tomb/fx_tomb_portal_air" ); + level._effect[ "teleport_elec" ] = loadfx( "maps/zombie_tomb/fx_tomb_portal_elec" ); + level._effect[ "teleport_fire" ] = loadfx( "maps/zombie_tomb/fx_tomb_portal_fire" ); + level._effect[ "teleport_ice" ] = loadfx( "maps/zombie_tomb/fx_tomb_portal_ice" ); + level._effect[ "tesla_elec_kill" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_afterlife_zmb_tport" ); + level._effect[ "capture_progression" ] = loadfx( "maps/zombie_tomb/fx_tomb_capture_progression" ); + level._effect[ "capture_complete" ] = loadfx( "maps/zombie_tomb/fx_tomb_capture_complete" ); + level._effect[ "capture_exhaust" ] = loadfx( "maps/zombie_tomb/fx_tomb_capture_exhaust_back" ); + level._effect[ "screecher_hole" ] = loadfx( "maps/zombie_tomb/fx_tomb_screecher_vortex" ); + level._effect[ "zone_capture_zombie_spawn" ] = loadfx( "maps/zombie_tomb/fx_tomb_emergence_spawn" ); + level._effect[ "crusader_zombie_eyes" ] = loadfx( "maps/zombie/fx_zombie_crusader_eyes" ); + level._effect[ "zone_capture_zombie_torso_fx" ] = loadfx( "maps/zombie_tomb/fx_tomb_crusader_torso_loop" ); + level._effect[ "player_rain" ] = loadfx( "maps/zombie_tomb/fx_tomb_player_weather_rain" ); + level._effect[ "player_snow" ] = loadfx( "maps/zombie_tomb/fx_tomb_player_weather_snow" ); + level._effect[ "lightning_flash" ] = loadfx( "maps/zombie_alcatraz/fx_alcatraz_lightning_lg" ); + level._effect[ "tank_treads" ] = loadfx( "maps/zombie_tomb/fx_tomb_veh_tank_treadfx_mud" ); + level._effect[ "tank_light_grn" ] = loadfx( "maps/zombie_tomb/fx_tomb_capture_light_green" ); + level._effect[ "tank_light_red" ] = loadfx( "maps/zombie_tomb/fx_tomb_capture_light_red" ); + level._effect[ "tank_overheat" ] = loadfx( "maps/zombie_tomb/fx_tomb_veh_tank_exhaust_overheat" ); + level._effect[ "tank_exhaust" ] = loadfx( "maps/zombie_tomb/fx_tomb_veh_tank_exhaust" ); + level._effect[ "bottle_glow" ] = loadfx( "maps/zombie_tomb/fx_tomb_dieselmagic_portal" ); + level._effect[ "perk_pipe_smoke" ] = loadfx( "maps/zombie_tomb/fx_tomb_perk_machine_exhaust" ); + level._effect[ "wagon_fire" ] = loadfx( "maps/zombie_tomb/fx_tomb_ee_fire_wagon" ); + level._effect[ "zombie_fist_glow" ] = loadfx( "maps/zombie_tomb/fx_tomb_ee_fists" ); + level._effect[ "ee_vortex" ] = loadfx( "maps/zombie_tomb/fx_tomb_ee_vortex" ); + level._effect[ "ee_beam" ] = loadfx( "maps/zombie_tomb/fx_tomb_ee_beam" ); + level._effect[ "foot_box_glow" ] = loadfx( "maps/zombie_tomb/fx_tomb_challenge_fire" ); + level._effect[ "couch_fx" ] = loadfx( "maps/zombie_tomb/fx_tomb_debris_blocker" ); + level._effect[ "sky_plane_tracers" ] = loadfx( "maps/zombie_tomb/fx_tomb_sky_plane_tracers" ); + level._effect[ "sky_plane_trail" ] = loadfx( "maps/zombie_tomb/fx_tomb_sky_plane_trail" ); + level._effect[ "biplane_explode" ] = loadfx( "maps/zombie_tomb/fx_tomb_explo_airplane" ); + level._effect[ "special_glow" ] = loadfx( "maps/zombie_tomb/fx_tomb_elem_reveal_glow" ); +} + +precache_createfx_fx() +{ + level._effect[ "fx_sky_dist_aa_tracers" ] = loadfx( "maps/zombie_tomb/fx_tomb_sky_dist_aa_tracers" ); + level._effect[ "fx_tomb_vortex_glow" ] = loadfx( "maps/zombie_tomb/fx_tomb_vortex_glow" ); + level._effect[ "fx_pack_a_punch" ] = loadfx( "maps/zombie_tomb/fx_tomb_pack_a_punch_light_beams" ); + level._effect[ "fx_tomb_dust_fall" ] = loadfx( "maps/zombie_tomb/fx_tomb_dust_fall" ); + level._effect[ "fx_tomb_dust_fall_lg" ] = loadfx( "maps/zombie_tomb/fx_tomb_dust_fall_lg" ); + level._effect[ "fx_tomb_embers_flat" ] = loadfx( "maps/zombie_tomb/fx_tomb_embers_flat" ); + level._effect[ "fx_tomb_fire_lg" ] = loadfx( "maps/zombie_tomb/fx_tomb_fire_lg" ); + level._effect[ "fx_tomb_fire_sm" ] = loadfx( "maps/zombie_tomb/fx_tomb_fire_sm" ); + level._effect[ "fx_tomb_fire_line_sm" ] = loadfx( "maps/zombie_tomb/fx_tomb_fire_line_sm" ); + level._effect[ "fx_tomb_fire_sm_smolder" ] = loadfx( "maps/zombie_tomb/fx_tomb_fire_sm_smolder" ); + level._effect[ "fx_tomb_ground_fog" ] = loadfx( "maps/zombie_tomb/fx_tomb_ground_fog" ); + level._effect[ "fx_tomb_sparks" ] = loadfx( "maps/zombie_tomb/fx_tomb_sparks" ); + level._effect[ "fx_tomb_water_drips" ] = loadfx( "maps/zombie_tomb/fx_tomb_water_drips" ); + level._effect[ "fx_tomb_water_drips_sm" ] = loadfx( "maps/zombie_tomb/fx_tomb_water_drips_sm" ); + level._effect[ "fx_tomb_smoke_pillar_xlg" ] = loadfx( "maps/zombie_tomb/fx_tomb_smoke_pillar_xlg" ); + level._effect[ "fx_tomb_godray_md" ] = loadfx( "maps/zombie_tomb/fx_tomb_godray_md" ); + level._effect[ "fx_tomb_godray_mist_md" ] = loadfx( "maps/zombie_tomb/fx_tomb_godray_mist_md" ); + level._effect[ "fx_tomb_dust_motes_md" ] = loadfx( "maps/zombie_tomb/fx_tomb_dust_motes_md" ); + level._effect[ "fx_tomb_dust_motes_lg" ] = loadfx( "maps/zombie_tomb/fx_tomb_dust_motes_lg" ); + level._effect[ "fx_tomb_light_md" ] = loadfx( "maps/zombie_tomb/fx_tomb_light_md" ); + level._effect[ "fx_tomb_light_lg" ] = loadfx( "maps/zombie_tomb/fx_tomb_light_lg" ); + level._effect[ "fx_tomb_light_expensive" ] = loadfx( "maps/zombie_tomb/fx_tomb_light_expensive" ); + level._effect[ "fx_tomb_steam_md" ] = loadfx( "maps/zombie_tomb/fx_tomb_steam_md" ); + level._effect[ "fx_tomb_steam_lg" ] = loadfx( "maps/zombie_tomb/fx_tomb_steam_lg" ); + level._effect[ "fx_tomb_church_fire_vista" ] = loadfx( "maps/zombie_tomb/fx_tomb_church_fire_vista" ); + level._effect[ "fx_tomb_church_custom" ] = loadfx( "maps/zombie_tomb/fx_tomb_church_custom" ); + level._effect[ "fx_tomb_chamber_glow" ] = loadfx( "maps/zombie_tomb/fx_tomb_chamber_glow" ); + level._effect[ "fx_tomb_chamber_glow_blue" ] = loadfx( "maps/zombie_tomb/fx_tomb_chamber_glow_blue" ); + level._effect[ "fx_tomb_chamber_glow_purple" ] = loadfx( "maps/zombie_tomb/fx_tomb_chamber_glow_purple" ); + level._effect[ "fx_tomb_chamber_glow_yellow" ] = loadfx( "maps/zombie_tomb/fx_tomb_chamber_glow_yellow" ); + level._effect[ "fx_tomb_chamber_glow_red" ] = loadfx( "maps/zombie_tomb/fx_tomb_chamber_glow_red" ); + level._effect[ "fx_tomb_chamber_walls_impact" ] = loadfx( "maps/zombie_tomb/fx_tomb_chamber_walls_impact" ); + level._effect[ "fx_tomb_crafting_chamber_glow" ] = loadfx( "maps/zombie_tomb/fx_tomb_crafting_chamber_glow" ); + level._effect[ "fx_tomb_probe_elec_on" ] = loadfx( "maps/zombie_tomb/fx_tomb_probe_elec_on" ); + level._effect[ "fx_tomb_robot_ambient" ] = loadfx( "maps/zombie_tomb/fx_tomb_robot_ambient" ); + level._effect[ "fx_tomb_skybox_vortex" ] = loadfx( "maps/zombie_tomb/fx_tomb_skybox_vortex" ); +} + +precache_fxanim_props() +{ + level.scr_anim[ "fxanim_props" ][ "dogfights" ] = %fxanim_zom_tomb_dogfights_anim; +} + +precache_fxanim_props_dlc4() +{ + level.scr_anim[ "fxanim_props_dlc4" ][ "church_wires" ] = %fxanim_zom_tomb_church_wires_anim; + level.scr_anim[ "fxanim_props_dlc4" ][ "no_mans_wire" ] = %fxanim_zom_tomb_no_mans_wire_anim; + level.scr_anim[ "fxanim_props_dlc4" ][ "float_bunker" ] = %fxanim_zom_tomb_debris_float_bunker_anim; + level.scr_anim[ "fxanim_props_dlc4" ][ "chamber_rocks01" ] = %fxanim_zom_tomb_chamber_rocks01_anim; + level.scr_anim[ "fxanim_props_dlc4" ][ "chamber_rocks02" ] = %fxanim_zom_tomb_chamber_rocks02_anim; + level.scr_anim[ "fxanim_props_dlc4" ][ "head_fans" ] = %fxanim_zom_tomb_robot_head_fans_anim; + level.scr_anim[ "fxanim_props_dlc4" ][ "church_drain" ] = %fxanim_zom_tomb_church_drain_anim; + level.scr_anim[ "fxanim_props_dlc4" ][ "wires_ruins" ] = %fxanim_zom_tomb_wires_ruins_anim; + level.scr_anim[ "fxanim_props_dlc4" ][ "pap_ropes" ] = %fxanim_zom_tomb_pap_ropes_anim; + level.scr_anim[ "fxanim_props_dlc4" ][ "church_ceiling" ] = %fxanim_zom_tomb_church_ceiling_anim; + level.scr_anim[ "fxanim_props_dlc4" ][ "crane_hook" ] = %fxanim_zom_tomb_crane_hook_anim; +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_gamemodes.gsc b/zm_tomb_patch/maps/mp/zm_tomb_gamemodes.gsc new file mode 100644 index 0000000..981bb1b --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_gamemodes.gsc @@ -0,0 +1,13 @@ +#include maps/mp/zm_tomb_classic; +#include maps/mp/zm_tomb; +#include maps/mp/gametypes_zm/_zm_gametype; +#include maps/mp/zombies/_zm_game_module; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + add_map_gamemode( "zclassic", ::maps/mp/zm_tomb::zstandard_preinit, undefined, undefined ); + add_map_location_gamemode( "zclassic", "tomb", ::maps/mp/zm_tomb_classic::precache, ::maps/mp/zm_tomb_classic::main ); +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_giant_robot.gsc b/zm_tomb_patch/maps/mp/zm_tomb_giant_robot.gsc new file mode 100644 index 0000000..3f0de8a --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_giant_robot.gsc @@ -0,0 +1,2364 @@ +#include maps/mp/zombies/_zm; +#include maps/mp/zm_tomb_vo; +#include maps/mp/zombies/_zm_clone; +#include maps/mp/zombies/_zm_unitrigger; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zombies/_zm_stats; +#include maps/mp/zombies/_zm_zonemgr; +#include maps/mp/zm_tomb_teleporter; +#include maps/mp/zombies/_zm_weap_one_inch_punch; +#include maps/mp/zombies/_zm_ai_mechz; +#include maps/mp/animscripts/zm_shared; +#include maps/mp/zm_tomb_giant_robot_ffotd; +#include maps/mp/zombies/_zm_net; +#include maps/mp/gametypes_zm/_hud; +#include maps/mp/gametypes_zm/_hud_util; +#include maps/mp/animscripts/zm_utility; +#include maps/mp/animscripts/zm_death; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/zombies/_zm_score; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +#using_animtree( "zm_tomb_giant_robot_hatch" ); + +init_giant_robot_glows() +{ + maps/mp/zm_tomb_giant_robot_ffotd::init_giant_robot_glows_start(); + precacheitem( "falling_hands_tomb_zm" ); + precachemodel( "veh_t6_dlc_zm_robot_foot_hatch" ); + precachemodel( "veh_t6_dlc_zm_robot_foot_hatch_lights" ); + flag_init( "foot_shot" ); + flag_init( "three_robot_round" ); + flag_init( "fire_link_enabled" ); + flag_init( "timeout_vo_robot_0" ); + flag_init( "timeout_vo_robot_1" ); + flag_init( "timeout_vo_robot_2" ); + level thread setup_giant_robot_devgui(); + level.gr_foot_hatch_closed = []; + level.gr_foot_hatch_closed[ 0 ] = 1; + level.gr_foot_hatch_closed[ 1 ] = 1; + level.gr_foot_hatch_closed[ 2 ] = 1; + a_gr_head_triggers = getstructarray( "giant_robot_head_exit_trigger", "script_noteworthy" ); + _a51 = a_gr_head_triggers; + _k51 = getFirstArrayKey( _a51 ); + while ( isDefined( _k51 ) ) + { + struct = _a51[ _k51 ]; + gr_head_exit_trigger_start( struct ); + _k51 = getNextArrayKey( _a51, _k51 ); + } + level thread handle_wind_tunnel_bunker_collision(); + level thread handle_tank_bunker_collision(); + maps/mp/zm_tomb_giant_robot_ffotd::init_giant_robot_glows_end(); +} + +init_animtree() +{ + scriptmodelsuseanimtree( -1 ); +} + +init_giant_robot() +{ + maps/mp/zm_tomb_giant_robot_ffotd::init_giant_robot_start(); + registerclientfield( "actor", "register_giant_robot", 14000, 1, "int" ); + registerclientfield( "world", "start_anim_robot_0", 14000, 1, "int" ); + registerclientfield( "world", "start_anim_robot_1", 14000, 1, "int" ); + registerclientfield( "world", "start_anim_robot_2", 14000, 1, "int" ); + registerclientfield( "world", "play_foot_stomp_fx_robot_0", 14000, 2, "int" ); + registerclientfield( "world", "play_foot_stomp_fx_robot_1", 14000, 2, "int" ); + registerclientfield( "world", "play_foot_stomp_fx_robot_2", 14000, 2, "int" ); + registerclientfield( "world", "play_foot_open_fx_robot_0", 14000, 2, "int" ); + registerclientfield( "world", "play_foot_open_fx_robot_1", 14000, 2, "int" ); + registerclientfield( "world", "play_foot_open_fx_robot_2", 14000, 2, "int" ); + registerclientfield( "world", "eject_warning_fx_robot_0", 14000, 1, "int" ); + registerclientfield( "world", "eject_warning_fx_robot_1", 14000, 1, "int" ); + registerclientfield( "world", "eject_warning_fx_robot_2", 14000, 1, "int" ); + registerclientfield( "allplayers", "eject_steam_fx", 14000, 1, "int" ); + registerclientfield( "allplayers", "all_tubes_play_eject_steam_fx", 14000, 1, "int" ); + registerclientfield( "allplayers", "gr_eject_player_impact_fx", 14000, 1, "int" ); + registerclientfield( "toplayer", "giant_robot_rumble_and_shake", 14000, 2, "int" ); + registerclientfield( "world", "church_ceiling_fxanim", 14000, 1, "int" ); + level thread giant_robot_initial_spawns(); + level.custom_intermission = ::tomb_standard_intermission; + init_footstep_safe_spots(); + maps/mp/zm_tomb_giant_robot_ffotd::init_giant_robot_end(); +} + +init_footstep_safe_spots() +{ + level.giant_robot_footstep_safe_spots = []; + make_safe_spot_trigger_box_at_point( ( -493, -198, 389 ), ( 0, 0, 1 ), 80, 64, 150 ); +} + +make_safe_spot_trigger_box_at_point( v_origin, v_angles, n_length, n_width, n_height ) +{ + trig = spawn( "trigger_box", v_origin, 0, n_length, n_width, n_height ); + trig.angles = v_angles; + level.giant_robot_footstep_safe_spots[ level.giant_robot_footstep_safe_spots.size ] = trig; +} + +tomb_can_revive_override( player_down ) +{ + if ( isDefined( player_down.is_stomped ) && player_down.is_stomped ) + { + return 0; + } + return 1; +} + +giant_robot_initial_spawns() +{ + flag_wait( "start_zombie_round_logic" ); + level.a_giant_robots = []; + i = 0; + while ( i < 3 ) + { + level.gr_foot_hatch_closed[ i ] = 1; + trig_stomp_kill_right = getent( "trig_stomp_kill_right_" + i, "targetname" ); + trig_stomp_kill_left = getent( "trig_stomp_kill_left_" + i, "targetname" ); + trig_stomp_kill_right enablelinkto(); + trig_stomp_kill_left enablelinkto(); + clip_foot_right = getent( "clip_foot_right_" + i, "targetname" ); + clip_foot_left = getent( "clip_foot_left_" + i, "targetname" ); + sp_giant_robot = getent( "ai_giant_robot_" + i, "targetname" ); + ai = sp_giant_robot spawnactor(); + ai maps/mp/zm_tomb_giant_robot_ffotd::giant_robot_spawn_start(); + ai.is_giant_robot = 1; + ai.giant_robot_id = i; + tag_right_foot = ai gettagorigin( "TAG_ATTACH_HATCH_RI" ); + tag_left_foot = ai gettagorigin( "TAG_ATTACH_HATCH_LE" ); + trig_stomp_kill_right.origin = tag_right_foot + vectorScale( ( 0, 0, 1 ), 72 ); + trig_stomp_kill_right.angles = ai gettagangles( "TAG_ATTACH_HATCH_RI" ); + trig_stomp_kill_left.origin = tag_left_foot + vectorScale( ( 0, 0, 1 ), 72 ); + trig_stomp_kill_left.angles = ai gettagangles( "TAG_ATTACH_HATCH_LE" ); + wait 0,1; + trig_stomp_kill_right linkto( ai, "TAG_ATTACH_HATCH_RI", vectorScale( ( 0, 0, 1 ), 72 ) ); + wait_network_frame(); + trig_stomp_kill_left linkto( ai, "TAG_ATTACH_HATCH_LE", vectorScale( ( 0, 0, 1 ), 72 ) ); + wait_network_frame(); + ai.trig_stomp_kill_right = trig_stomp_kill_right; + ai.trig_stomp_kill_left = trig_stomp_kill_left; + clip_foot_right.origin = tag_right_foot + ( 0, 0, 1 ); + clip_foot_left.origin = tag_left_foot + ( 0, 0, 1 ); + clip_foot_right.angles = ai gettagangles( "TAG_ATTACH_HATCH_RI" ); + clip_foot_left.angles = ai gettagangles( "TAG_ATTACH_HATCH_LE" ); + wait 0,1; + clip_foot_right linkto( ai, "TAG_ATTACH_HATCH_RI", ( 0, 0, 1 ) ); + wait_network_frame(); + clip_foot_left linkto( ai, "TAG_ATTACH_HATCH_LE", ( 0, 0, 1 ) ); + wait_network_frame(); + ai.clip_foot_right = clip_foot_right; + ai.clip_foot_left = clip_foot_left; + ai.is_zombie = 0; + ai.targetname = "giant_robot_walker_" + i; + ai.animname = "giant_robot_walker"; + ai.script_noteworthy = "giant_robot"; + ai.audio_type = "giant_robot"; + ai.ignoreall = 1; + ai.ignoreme = 1; + ai setcandamage( 0 ); + ai magic_bullet_shield(); + ai setplayercollision( 1 ); + ai setforcenocull(); + ai setfreecameralockonallowed( 0 ); + ai.goalradius = 100000; + ai setgoalpos( ai.origin ); + ai setclientfield( "register_giant_robot", 1 ); + ai ghost(); + ai ent_flag_init( "robot_head_entered" ); + ai ent_flag_init( "kill_trigger_active" ); + level.a_giant_robots[ i ] = ai; + ai maps/mp/zm_tomb_giant_robot_ffotd::giant_robot_spawn_end(); + wait_network_frame(); + i++; + } + level thread robot_cycling(); +} + +robot_cycling() +{ + three_robot_round = 0; + last_robot = -1; + level thread giant_robot_intro_walk( 1 ); + level waittill( "giant_robot_intro_complete" ); + while ( 1 ) + { + if ( level.round_number % 4 && three_robot_round != level.round_number ) + { + flag_set( "three_robot_round" ); + } + if ( flag( "ee_all_staffs_placed" ) && !flag( "ee_mech_zombie_hole_opened" ) ) + { + flag_set( "three_robot_round" ); + } +/# + if ( isDefined( level.devgui_force_three_robot_round ) && level.devgui_force_three_robot_round ) + { + flag_set( "three_robot_round" ); +#/ + } + if ( flag( "three_robot_round" ) ) + { + level.zombie_ai_limit = 22; + random_number = randomint( 3 ); + if ( random_number == 2 ) + { + level thread giant_robot_start_walk( 2 ); + } + else + { + level thread giant_robot_start_walk( 2, 0 ); + } + wait 5; + if ( random_number == 0 ) + { + level thread giant_robot_start_walk( 0 ); + } + else + { + level thread giant_robot_start_walk( 0, 0 ); + } + wait 5; + if ( random_number == 1 ) + { + level thread giant_robot_start_walk( 1 ); + } + else + { + level thread giant_robot_start_walk( 1, 0 ); + } + level waittill( "giant_robot_walk_cycle_complete" ); + level waittill( "giant_robot_walk_cycle_complete" ); + level waittill( "giant_robot_walk_cycle_complete" ); + wait 5; + level.zombie_ai_limit = 24; + three_robot_round = level.round_number; + last_robot = -1; + flag_clear( "three_robot_round" ); + continue; + } + else + { + if ( !flag( "activate_zone_nml" ) ) + { + random_number = randomint( 2 ); + } + else + { + random_number = randomint( 3 ); + } +/# + if ( isDefined( level.devgui_force_giant_robot ) ) + { + random_number = level.devgui_force_giant_robot; +#/ + } + last_robot = random_number; + level thread giant_robot_start_walk( random_number ); + level waittill( "giant_robot_walk_cycle_complete" ); + wait 5; + } + } +} + +giant_robot_intro_walk( n_robot_id ) +{ + ai = getent( "giant_robot_walker_" + n_robot_id, "targetname" ); + ai attach( "veh_t6_dlc_zm_robot_foot_hatch", "TAG_ATTACH_HATCH_LE" ); + ai attach( "veh_t6_dlc_zm_robot_foot_hatch", "TAG_ATTACH_HATCH_RI" ); + ai thread giant_robot_think( ai.trig_stomp_kill_right, ai.trig_stomp_kill_left, ai.clip_foot_right, ai.clip_foot_left, undefined, 3 ); + level thread starting_spawn_light(); + wait 0,5; + level setclientfield( "play_foot_stomp_fx_robot_" + ai.giant_robot_id, 2 ); + level thread giant_robot_intro_exploder(); + a_players = getplayers(); + _a361 = a_players; + _k361 = getFirstArrayKey( _a361 ); + while ( isDefined( _k361 ) ) + { + player = _a361[ _k361 ]; + player setclientfieldtoplayer( "giant_robot_rumble_and_shake", 3 ); + player thread turn_clientside_rumble_off(); + _k361 = getNextArrayKey( _a361, _k361 ); + } + level waittill( "giant_robot_walk_cycle_complete" ); + level notify( "giant_robot_intro_complete" ); +} + +giant_robot_intro_exploder() +{ + exploder( 111 ); + wait 3; + stop_exploder( 111 ); +} + +giant_robot_start_walk( n_robot_id, b_has_hatch ) +{ + if ( !isDefined( b_has_hatch ) ) + { + b_has_hatch = 1; + } + ai = getent( "giant_robot_walker_" + n_robot_id, "targetname" ); + level.gr_foot_hatch_closed[ n_robot_id ] = 1; + ai.b_has_hatch = b_has_hatch; + ai ent_flag_clear( "kill_trigger_active" ); + ai ent_flag_clear( "robot_head_entered" ); + if ( isDefined( ai.b_has_hatch ) && ai.b_has_hatch ) + { + m_sole = getent( "target_sole_" + n_robot_id, "targetname" ); + } + if ( isDefined( m_sole ) && isDefined( ai.b_has_hatch ) && ai.b_has_hatch ) + { + m_sole setcandamage( 1 ); + m_sole.health = 99999; + m_sole useanimtree( -1 ); + m_sole unlink(); + } + wait 10; + if ( isDefined( m_sole ) ) + { + if ( cointoss() ) + { + ai.hatch_foot = "left"; + } + else + { + ai.hatch_foot = "right"; + } +/# + if ( isDefined( level.devgui_force_giant_robot_foot ) && isDefined( ai.b_has_hatch ) && ai.b_has_hatch ) + { + ai.hatch_foot = level.devgui_force_giant_robot_foot; +#/ + } + if ( ai.hatch_foot == "left" ) + { + n_sole_origin = ai gettagorigin( "TAG_ATTACH_HATCH_LE" ); + v_sole_angles = ai gettagangles( "TAG_ATTACH_HATCH_LE" ); + ai.hatch_foot = "left"; + str_sole_tag = "TAG_ATTACH_HATCH_LE"; + ai attach( "veh_t6_dlc_zm_robot_foot_hatch", "TAG_ATTACH_HATCH_RI" ); + } + else + { + if ( ai.hatch_foot == "right" ) + { + n_sole_origin = ai gettagorigin( "TAG_ATTACH_HATCH_RI" ); + v_sole_angles = ai gettagangles( "TAG_ATTACH_HATCH_RI" ); + ai.hatch_foot = "right"; + str_sole_tag = "TAG_ATTACH_HATCH_RI"; + ai attach( "veh_t6_dlc_zm_robot_foot_hatch", "TAG_ATTACH_HATCH_LE" ); + } + } + m_sole.origin = n_sole_origin; + m_sole.angles = v_sole_angles; + wait 0,1; + m_sole linkto( ai, str_sole_tag, ( 0, 0, 1 ) ); + m_sole show(); + ai attach( "veh_t6_dlc_zm_robot_foot_hatch_lights", str_sole_tag ); + } + if ( isDefined( ai.b_has_hatch ) && !ai.b_has_hatch ) + { + ai attach( "veh_t6_dlc_zm_robot_foot_hatch", "TAG_ATTACH_HATCH_RI" ); + ai attach( "veh_t6_dlc_zm_robot_foot_hatch", "TAG_ATTACH_HATCH_LE" ); + } + wait 0,05; + ai thread giant_robot_think( ai.trig_stomp_kill_right, ai.trig_stomp_kill_left, ai.clip_foot_right, ai.clip_foot_left, m_sole, n_robot_id ); +} + +giant_robot_think( trig_stomp_kill_right, trig_stomp_kill_left, clip_foot_right, clip_foot_left, m_sole, n_robot_id ) +{ + self thread robot_walk_animation( n_robot_id ); + self show(); + if ( isDefined( m_sole ) ) + { + self thread sole_cleanup( m_sole ); + } + self.is_walking = 1; + self thread monitor_footsteps( trig_stomp_kill_right, "right" ); + self thread monitor_footsteps( trig_stomp_kill_left, "left" ); + self thread monitor_footsteps_fx( trig_stomp_kill_right, "right" ); + self thread monitor_footsteps_fx( trig_stomp_kill_left, "left" ); + self thread monitor_shadow_notetracks( "right" ); + self thread monitor_shadow_notetracks( "left" ); + self thread sndgrthreads( "left" ); + self thread sndgrthreads( "right" ); + if ( isDefined( m_sole ) && level.gr_foot_hatch_closed[ n_robot_id ] && isDefined( self.b_has_hatch ) && self.b_has_hatch ) + { + self thread giant_robot_foot_waittill_sole_shot( m_sole ); + } + a_players = getplayers(); + if ( n_robot_id != 3 && isDefined( level.giant_robot_discovered ) && !level.giant_robot_discovered ) + { + _a511 = a_players; + _k511 = getFirstArrayKey( _a511 ); + while ( isDefined( _k511 ) ) + { + player = _a511[ _k511 ]; + player thread giant_robot_discovered_vo( self ); + _k511 = getNextArrayKey( _a511, _k511 ); + } + } + else while ( flag( "three_robot_round" ) && isDefined( level.three_robot_round_vo ) && !level.three_robot_round_vo ) + { + _a518 = a_players; + _k518 = getFirstArrayKey( _a518 ); + while ( isDefined( _k518 ) ) + { + player = _a518[ _k518 ]; + player thread three_robot_round_vo( self ); + _k518 = getNextArrayKey( _a518, _k518 ); + } + } + while ( n_robot_id != 3 && isDefined( level.shoot_robot_vo ) && !level.shoot_robot_vo ) + { + _a526 = a_players; + _k526 = getFirstArrayKey( _a526 ); + while ( isDefined( _k526 ) ) + { + player = _a526[ _k526 ]; + player thread shoot_at_giant_robot_vo( self ); + _k526 = getNextArrayKey( _a526, _k526 ); + } + } + self waittill( "giant_robot_stop" ); + self.is_walking = 0; + self stopanimscripted(); + sp_giant_robot = getent( "ai_giant_robot_" + self.giant_robot_id, "targetname" ); + self.origin = sp_giant_robot.origin; + level setclientfield( "play_foot_open_fx_robot_" + self.giant_robot_id, 0 ); + self ghost(); + self detachall(); + level notify( "giant_robot_walk_cycle_complete" ); +} + +sole_cleanup( m_sole ) +{ + self endon( "death" ); + self endon( "giant_robot_stop" ); + wait_network_frame(); + m_sole clearanim( %root, 0 ); + wait_network_frame(); + m_sole setanim( %ai_zombie_giant_robot_hatch_close, 1, 0,2, 1 ); +} + +giant_robot_foot_waittill_sole_shot( m_sole ) +{ + self endon( "death" ); + self endon( "giant_robot_stop" ); + if ( isDefined( self.hatch_foot ) && self.hatch_foot == "left" ) + { + str_tag = "TAG_ATTACH_HATCH_LE"; + n_foot = 2; + } + else + { + if ( isDefined( self.hatch_foot ) && self.hatch_foot == "right" ) + { + str_tag = "TAG_ATTACH_HATCH_RI"; + n_foot = 1; + } + } + self waittillmatch( "scripted_walk" ); + return "kill_zombies_leftfoot_1"; + wait 1; + m_sole waittill( "damage", amount, inflictor, direction, point, type, tagname, modelname, partname, weaponname, idflags ); + m_sole.health = 99999; + level.gr_foot_hatch_closed[ self.giant_robot_id ] = 0; + level setclientfield( "play_foot_open_fx_robot_" + self.giant_robot_id, n_foot ); + m_sole clearanim( %ai_zombie_giant_robot_hatch_close, 1 ); + m_sole setanim( %ai_zombie_giant_robot_hatch_open, 1, 0,2, 1 ); + n_time = getanimlength( %ai_zombie_giant_robot_hatch_open ); + wait n_time; + m_sole clearanim( %ai_zombie_giant_robot_hatch_open, 1 ); + m_sole setanim( %ai_zombie_giant_robot_hatch_open_idle, 1, 0,2, 1 ); +} + +giant_robot_close_head_entrance( foot_side ) +{ + wait 5; + level.gr_foot_hatch_closed[ self.giant_robot_id ] = 1; + level setclientfield( "play_foot_open_fx_robot_" + self.giant_robot_id, 0 ); + m_sole = getent( "target_sole_" + self.giant_robot_id, "targetname" ); + if ( isDefined( m_sole ) ) + { + m_sole clearanim( %ai_zombie_giant_robot_hatch_open, 1 ); + m_sole clearanim( %ai_zombie_giant_robot_hatch_open_idle, 1 ); + m_sole setanim( %ai_zombie_giant_robot_hatch_close, 1, 0,2, 1 ); + } + if ( isDefined( foot_side ) ) + { + if ( foot_side == "right" ) + { + str_tag = "TAG_ATTACH_HATCH_RI"; + } + else + { + if ( foot_side == "left" ) + { + str_tag = "TAG_ATTACH_HATCH_LE"; + } + } + self detach( "veh_t6_dlc_zm_robot_foot_hatch_lights", str_tag ); + } +} + +robot_walk_animation( n_robot_id ) +{ + if ( n_robot_id != 3 ) + { + level setclientfield( "start_anim_robot_" + n_robot_id, 1 ); + self thread start_footprint_warning_vo( n_robot_id ); + } + if ( n_robot_id == 0 ) + { + animationid = self getanimfromasd( "zm_robot_walk_nml", 0 ); + str_anim_scripted_name = "zm_robot_walk_nml"; + s_robot_path = getstruct( "anim_align_robot_nml", "targetname" ); + s_robot_path.angles = ( 0, 0, 1 ); + self animscripted( s_robot_path.origin, s_robot_path.angles, str_anim_scripted_name, 0 ); + self thread maps/mp/animscripts/zm_shared::donotetracks( "scripted_walk" ); + self waittillmatch( "scripted_walk" ); + return "end"; + animationid = self getanimfromasd( "zm_robot_walk_nml", 1 ); + self thread maps/mp/animscripts/zm_shared::donotetracks( "scripted_walk" ); + self animscripted( s_robot_path.origin, s_robot_path.angles, str_anim_scripted_name, 1 ); + self waittillmatch( "scripted_walk" ); + return "end"; + animationid = self getanimfromasd( "zm_robot_walk_nml", 2 ); + self thread maps/mp/animscripts/zm_shared::donotetracks( "scripted_walk" ); + self animscripted( s_robot_path.origin, s_robot_path.angles, str_anim_scripted_name, 2 ); + self waittillmatch( "scripted_walk" ); + return "end"; + self notify( "giant_robot_stop" ); + } + else if ( n_robot_id == 1 ) + { + animationid = self getanimfromasd( "zm_robot_walk_trenches", 0 ); + str_anim_scripted_name = "zm_robot_walk_trenches"; + s_robot_path = getstruct( "anim_align_robot_trenches", "targetname" ); + s_robot_path.angles = ( 0, 0, 1 ); + self animscripted( s_robot_path.origin, s_robot_path.angles, str_anim_scripted_name, 0 ); + self thread maps/mp/animscripts/zm_shared::donotetracks( "scripted_walk" ); + self waittillmatch( "scripted_walk" ); + return "end"; + animationid = self getanimfromasd( "zm_robot_walk_trenches", 1 ); + self thread maps/mp/animscripts/zm_shared::donotetracks( "scripted_walk" ); + self animscripted( s_robot_path.origin, s_robot_path.angles, str_anim_scripted_name, 1 ); + self waittillmatch( "scripted_walk" ); + return "end"; + animationid = self getanimfromasd( "zm_robot_walk_trenches", 2 ); + self thread maps/mp/animscripts/zm_shared::donotetracks( "scripted_walk" ); + self animscripted( s_robot_path.origin, s_robot_path.angles, str_anim_scripted_name, 2 ); + self waittillmatch( "scripted_walk" ); + return "end"; + self notify( "giant_robot_stop" ); + } + else if ( n_robot_id == 2 ) + { + animationid = self getanimfromasd( "zm_robot_walk_village", 0 ); + str_anim_scripted_name = "zm_robot_walk_village"; + s_robot_path = getstruct( "anim_align_robot_village", "targetname" ); + s_robot_path.angles = ( 0, 0, 1 ); + self animscripted( s_robot_path.origin, s_robot_path.angles, str_anim_scripted_name, 0 ); + self thread maps/mp/animscripts/zm_shared::donotetracks( "scripted_walk" ); + self waittillmatch( "scripted_walk" ); + return "end"; + animationid = self getanimfromasd( "zm_robot_walk_village", 1 ); + self thread maps/mp/animscripts/zm_shared::donotetracks( "scripted_walk" ); + self animscripted( s_robot_path.origin, s_robot_path.angles, str_anim_scripted_name, 1 ); + self waittillmatch( "scripted_walk" ); + return "end"; + animationid = self getanimfromasd( "zm_robot_walk_village", 2 ); + self thread maps/mp/animscripts/zm_shared::donotetracks( "scripted_walk" ); + self animscripted( s_robot_path.origin, s_robot_path.angles, str_anim_scripted_name, 2 ); + self waittillmatch( "scripted_walk" ); + return "end"; + self notify( "giant_robot_stop" ); + } + else + { + if ( n_robot_id == 3 ) + { + animationid = self getanimfromasd( "zm_robot_walk_intro", 0 ); + str_anim_scripted_name = "zm_robot_walk_intro"; + s_robot_path = getstruct( "anim_align_robot_trenches", "targetname" ); + s_robot_path.angles = ( 0, 0, 1 ); + self animscripted( s_robot_path.origin, s_robot_path.angles, str_anim_scripted_name, 0 ); + self thread maps/mp/animscripts/zm_shared::donotetracks( "scripted_walk" ); + self waittillmatch( "scripted_walk" ); + return "end"; + self notify( "giant_robot_stop" ); + } + } + if ( n_robot_id != 3 ) + { + level setclientfield( "start_anim_robot_" + n_robot_id, 0 ); + } +} + +sndgrthreads( side ) +{ + self thread sndrobot( "soundfootstart_" + side, "zmb_robot_leg_move_" + side, side ); + self thread sndrobot( "soundfootwarning_" + side, "zmb_robot_foot_alarm", side ); + self thread sndrobot( "soundfootdown_" + side, "zmb_robot_leg_whoosh", side ); + self thread sndrobot( "soundfootalarm_" + side, "zmb_robot_pre_stomp_a", side ); +} + +sndrobot( notetrack, alias, side ) +{ + self endon( "giant_robot_stop" ); + if ( side == "right" ) + { + str_tag = "TAG_ATTACH_HATCH_RI"; + } + else + { + if ( side == "left" ) + { + str_tag = "TAG_ATTACH_HATCH_LE"; + } + } + while ( 1 ) + { + self waittillmatch( "scripted_walk" ); + return notetrack; + self playsoundontag( alias, str_tag ); + wait 0,1; + } +} + +monitor_footsteps( trig_stomp_kill, foot_side ) +{ + self endon( "death" ); + self endon( "giant_robot_stop" ); + str_start_stomp = "kill_zombies_" + foot_side + "foot_1"; + str_end_stomp = "footstep_" + foot_side + "_large"; + while ( 1 ) + { + self waittillmatch( "scripted_walk" ); + return str_start_stomp; + self thread toggle_kill_trigger_flag( trig_stomp_kill, 1, foot_side ); + self waittillmatch( "scripted_walk" ); + return str_end_stomp; + if ( self.giant_robot_id == 0 && foot_side == "left" ) + { + self thread toggle_wind_bunker_collision(); + } + else + { + if ( self.giant_robot_id == 1 && foot_side == "left" ) + { + self thread toggle_tank_bunker_collision(); + } + } + wait 0,5; + self thread toggle_kill_trigger_flag( trig_stomp_kill, 0, foot_side ); + } +} + +monitor_footsteps_fx( trig_stomp_kill, foot_side ) +{ + self endon( "death" ); + self endon( "giant_robot_stop" ); + str_end_stomp = "footstep_" + foot_side + "_large"; + while ( 1 ) + { + level setclientfield( "play_foot_stomp_fx_robot_" + self.giant_robot_id, 0 ); + self waittillmatch( "scripted_walk" ); + return str_end_stomp; + if ( foot_side == "right" ) + { + level setclientfield( "play_foot_stomp_fx_robot_" + self.giant_robot_id, 1 ); + } + else + { + level setclientfield( "play_foot_stomp_fx_robot_" + self.giant_robot_id, 2 ); + } + trig_stomp_kill thread rumble_and_shake( self ); + if ( self.giant_robot_id == 2 ) + { + self thread church_ceiling_fxanim( foot_side ); + } + else + { + if ( self.giant_robot_id == 0 ) + { + self thread play_pap_shake_fxanim( foot_side ); + } + } + wait_network_frame(); + } +} + +monitor_shadow_notetracks( foot_side ) +{ + self endon( "death" ); + self endon( "giant_robot_stop" ); + while ( 1 ) + { + self waittillmatch( "scripted_walk" ); + return "shadow_" + foot_side; + start_robot_stomp_warning_vo( foot_side ); + } +} + +rumble_and_shake( robot ) +{ + a_players = get_players(); + wait 0,2; + _a893 = a_players; + _k893 = getFirstArrayKey( _a893 ); + while ( isDefined( _k893 ) ) + { + player = _a893[ _k893 ]; + if ( is_player_valid( player ) ) + { + if ( isDefined( player.in_giant_robot_head ) ) + { + if ( isDefined( player.giant_robot_transition ) && player.giant_robot_transition ) + { + break; + } + else + { + if ( player.in_giant_robot_head == robot.giant_robot_id ) + { + player setclientfieldtoplayer( "giant_robot_rumble_and_shake", 2 ); + } + else + { + } + } + else dist = distance( player.origin, self.origin ); + if ( dist < 1500 ) + { + player setclientfieldtoplayer( "giant_robot_rumble_and_shake", 3 ); + level notify( "sam_clue_giant" ); + } + else if ( dist < 3000 ) + { + player setclientfieldtoplayer( "giant_robot_rumble_and_shake", 2 ); + } + else if ( dist < 6000 ) + { + player setclientfieldtoplayer( "giant_robot_rumble_and_shake", 1 ); + } + else + { + } + player thread turn_clientside_rumble_off(); + } + } + _k893 = getNextArrayKey( _a893, _k893 ); + } +} + +toggle_kill_trigger_flag( trig_stomp, b_flag, foot_side ) +{ + if ( !isDefined( foot_side ) ) + { + foot_side = undefined; + } + if ( b_flag ) + { + self ent_flag_set( "kill_trigger_active" ); + trig_stomp thread activate_kill_trigger( self, foot_side ); + } + else + { + self ent_flag_clear( "kill_trigger_active" ); + level notify( "stop_kill_trig_think" ); + if ( self ent_flag( "robot_head_entered" ) ) + { + self ent_flag_clear( "robot_head_entered" ); + self thread giant_robot_close_head_entrance( foot_side ); + level thread giant_robot_head_teleport_timeout( self.giant_robot_id ); + } + } +} + +activate_kill_trigger( robot, foot_side ) +{ + level endon( "stop_kill_trig_think" ); + if ( foot_side == "left" ) + { + str_foot_tag = "TAG_ATTACH_HATCH_LE"; + } + else + { + if ( foot_side == "right" ) + { + str_foot_tag = "TAG_ATTACH_HATCH_RI"; + } + } + while ( robot ent_flag( "kill_trigger_active" ) ) + { + a_zombies = getaispeciesarray( level.zombie_team, "all" ); + a_zombies_to_kill = []; + _a985 = a_zombies; + _k985 = getFirstArrayKey( _a985 ); + while ( isDefined( _k985 ) ) + { + zombie = _a985[ _k985 ]; + if ( distancesquared( zombie.origin, self.origin ) < 360000 ) + { + if ( isDefined( zombie.is_giant_robot ) && zombie.is_giant_robot ) + { + break; + } + else + { + if ( isDefined( zombie.marked_for_death ) && zombie.marked_for_death ) + { + break; + } + else + { + if ( isDefined( zombie.robot_stomped ) && zombie.robot_stomped ) + { + break; + } + else + { + if ( zombie istouching( self ) ) + { + if ( isDefined( zombie.is_mechz ) && zombie.is_mechz ) + { + zombie thread maps/mp/zombies/_zm_ai_mechz::mechz_robot_stomp_callback(); + break; + } + else + { + zombie setgoalpos( zombie.origin ); + zombie.marked_for_death = 1; + a_zombies_to_kill[ a_zombies_to_kill.size ] = zombie; + break; + } + else + { + if ( isDefined( zombie.is_mechz ) && !zombie.is_mechz && isDefined( zombie.has_legs ) && zombie.has_legs && isDefined( zombie.completed_emerging_into_playable_area ) && zombie.completed_emerging_into_playable_area ) + { + n_my_z = zombie.origin[ 2 ]; + v_giant_robot = robot gettagorigin( str_foot_tag ); + n_giant_robot_z = v_giant_robot[ 2 ]; + z_diff = abs( n_my_z - n_giant_robot_z ); + if ( z_diff <= 100 ) + { + zombie.v_punched_from = self.origin; + zombie animcustom( ::maps/mp/zombies/_zm_weap_one_inch_punch::knockdown_zombie_animate ); + } + } + } + } + } + } + } + } + _k985 = getNextArrayKey( _a985, _k985 ); + } + if ( a_zombies_to_kill.size > 0 ) + { + level thread zombie_stomp_death( robot, a_zombies_to_kill ); + robot thread zombie_stomped_by_gr_vo( foot_side ); + } + if ( isDefined( level.maxis_quadrotor ) ) + { + if ( level.maxis_quadrotor istouching( self ) ) + { + level.maxis_quadrotor thread quadrotor_stomp_death(); + } + } + a_boxes = getentarray( "foot_box", "script_noteworthy" ); + _a1052 = a_boxes; + _k1052 = getFirstArrayKey( _a1052 ); + while ( isDefined( _k1052 ) ) + { + m_box = _a1052[ _k1052 ]; + if ( m_box istouching( self ) ) + { + m_box notify( "robot_foot_stomp" ); + } + _k1052 = getNextArrayKey( _a1052, _k1052 ); + } + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( is_player_valid( players[ i ], 0, 1 ) ) + { + if ( !players[ i ] istouching( self ) ) + { + i++; + continue; + } + else if ( players[ i ] is_in_giant_robot_footstep_safe_spot() ) + { + i++; + continue; + } + else if ( isDefined( players[ i ].in_giant_robot_head ) ) + { + i++; + continue; + } + else if ( isDefined( players[ i ].is_stomped ) && players[ i ].is_stomped ) + { + i++; + continue; + } + else + { + if ( !level.gr_foot_hatch_closed[ robot.giant_robot_id ] && isDefined( robot.hatch_foot ) && isDefined( robot.b_has_hatch ) && robot.b_has_hatch && issubstr( self.targetname, robot.hatch_foot ) && !self player_is_in_laststand() ) + { + players[ i ].ignoreme = 1; + players[ i ].teleport_initial_origin = self.origin; + if ( robot.giant_robot_id == 0 ) + { + level thread maps/mp/zm_tomb_teleporter::stargate_teleport_player( "head_0_teleport_player", players[ i ], 4, 0 ); + players[ i ].in_giant_robot_head = 0; + } + else if ( robot.giant_robot_id == 1 ) + { + level thread maps/mp/zm_tomb_teleporter::stargate_teleport_player( "head_1_teleport_player", players[ i ], 4, 0 ); + players[ i ].in_giant_robot_head = 1; + if ( players[ i ] maps/mp/zombies/_zm_zonemgr::player_in_zone( "zone_bunker_4d" ) || players[ i ] maps/mp/zombies/_zm_zonemgr::player_in_zone( "zone_bunker_4c" ) ) + { + players[ i ].entered_foot_from_tank_bunker = 1; + } + } + else + { + level thread maps/mp/zm_tomb_teleporter::stargate_teleport_player( "head_2_teleport_player", players[ i ], 4, 0 ); + players[ i ].in_giant_robot_head = 2; + } + robot ent_flag_set( "robot_head_entered" ); + players[ i ] maps/mp/zombies/_zm_stats::increment_client_stat( "tomb_giant_robot_accessed", 0 ); + players[ i ] maps/mp/zombies/_zm_stats::increment_player_stat( "tomb_giant_robot_accessed" ); + players[ i ] playsoundtoplayer( "zmb_bot_elevator_ride_up", players[ i ] ); + start_wait = 0; + black_screen_wait = 4; + fade_in_time = 0,01; + fade_out_time = 0,2; + players[ i ] thread fadetoblackforxsec( start_wait, black_screen_wait, fade_in_time, fade_out_time, "white" ); + n_transition_time = start_wait + black_screen_wait + fade_in_time + fade_out_time; + n_start_time = start_wait + fade_in_time; + players[ i ] thread player_transition_into_robot_head_start( n_start_time ); + players[ i ] thread player_transition_into_robot_head_finish( n_transition_time ); + players[ i ] thread player_death_watch_on_giant_robot(); + i++; + continue; + } + else if ( isDefined( players[ i ].dig_vars[ "has_helmet" ] ) && players[ i ].dig_vars[ "has_helmet" ] ) + { + players[ i ] thread player_stomp_fake_death( robot ); + } + else + { + players[ i ] thread player_stomp_death( robot ); + } + start_wait = 0; + black_screen_wait = 5; + fade_in_time = 0,01; + fade_out_time = 0,2; + players[ i ] thread fadetoblackforxsec( start_wait, black_screen_wait, fade_in_time, fade_out_time, "black", 1 ); + } + } + i++; + } + wait 0,05; + } +} + +is_in_giant_robot_footstep_safe_spot() +{ + b_is_in_safe_spot = 0; + while ( isDefined( level.giant_robot_footstep_safe_spots ) ) + { + _a1166 = level.giant_robot_footstep_safe_spots; + _k1166 = getFirstArrayKey( _a1166 ); + while ( isDefined( _k1166 ) ) + { + e_volume = _a1166[ _k1166 ]; + if ( self istouching( e_volume ) ) + { + b_is_in_safe_spot = 1; + break; + } + else + { + _k1166 = getNextArrayKey( _a1166, _k1166 ); + } + } + } + return b_is_in_safe_spot; +} + +player_stomp_death( robot ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self.is_stomped = 1; + self playsound( "zmb_zombie_arc" ); + self freezecontrols( 1 ); + if ( self player_is_in_laststand() ) + { + self shellshock( "explosion", 7 ); + } + else + { + self dodamage( self.health, self.origin, robot ); + } + self maps/mp/zombies/_zm_stats::increment_client_stat( "tomb_giant_robot_stomped", 0 ); + self maps/mp/zombies/_zm_stats::increment_player_stat( "tomb_giant_robot_stomped" ); + wait 5; + self.is_stomped = 0; + if ( isDefined( self.hostmigrationcontrolsfrozen ) && !self.hostmigrationcontrolsfrozen ) + { + self freezecontrols( 0 ); + } + self thread play_robot_crush_player_vo(); +} + +player_stomp_fake_death( robot ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self.is_stomped = 1; + self playsound( "zmb_zombie_arc" ); + self freezecontrols( 1 ); + self setstance( "prone" ); + self shellshock( "explosion", 7 ); + wait 5; + self.is_stomped = 0; + if ( isDefined( self.hostmigrationcontrolsfrozen ) && !self.hostmigrationcontrolsfrozen ) + { + self freezecontrols( 0 ); + } + if ( isDefined( self.ee_stepped_on ) && !self.ee_stepped_on ) + { + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "robot_crush_golden" ); + self.ee_stepped_on = 1; + } +} + +zombie_stomp_death( robot, a_zombies_to_kill ) +{ + n_interval = 0; + i = 0; + while ( i < a_zombies_to_kill.size ) + { + zombie = a_zombies_to_kill[ i ]; + if ( !isDefined( zombie ) || !isalive( zombie ) ) + { + i++; + continue; + } + else + { + zombie dodamage( zombie.health, zombie.origin, robot ); + n_interval++; + if ( n_interval >= 4 ) + { + wait_network_frame(); + n_interval = 0; + } + } + i++; + } +} + +quadrotor_stomp_death() +{ + self endon( "death" ); + self delete(); +} + +toggle_wind_bunker_collision() +{ + s_org = getstruct( "wind_tunnel_bunker", "script_noteworthy" ); + v_foot = self gettagorigin( "TAG_ATTACH_HATCH_LE" ); + if ( distance2dsquared( s_org.origin, v_foot ) < 57600 ) + { + level notify( "wind_bunker_collision_on" ); + wait 5; + level notify( "wind_bunker_collision_off" ); + } +} + +toggle_tank_bunker_collision() +{ + s_org = getstruct( "tank_bunker", "script_noteworthy" ); + v_foot = self gettagorigin( "TAG_ATTACH_HATCH_LE" ); + if ( distance2dsquared( s_org.origin, v_foot ) < 57600 ) + { + level notify( "tank_bunker_collision_on" ); + wait 5; + level notify( "tank_bunker_collision_off" ); + } +} + +handle_wind_tunnel_bunker_collision() +{ + e_collision = getent( "clip_foot_bottom_wind", "targetname" ); + e_collision notsolid(); + e_collision connectpaths(); + while ( 1 ) + { + level waittill( "wind_bunker_collision_on" ); + wait 0,1; + e_collision solid(); + e_collision disconnectpaths(); + level waittill( "wind_bunker_collision_off" ); + e_collision notsolid(); + e_collision connectpaths(); + } +} + +handle_tank_bunker_collision() +{ + e_collision = getent( "clip_foot_bottom_tank", "targetname" ); + e_collision notsolid(); + e_collision connectpaths(); + while ( 1 ) + { + level waittill( "tank_bunker_collision_on" ); + wait 0,1; + e_collision solid(); + e_collision disconnectpaths(); + level waittill( "tank_bunker_collision_off" ); + e_collision notsolid(); + e_collision connectpaths(); + } +} + +church_ceiling_fxanim( foot_side ) +{ + if ( foot_side == "left" ) + { + tag_foot = self gettagorigin( "TAG_ATTACH_HATCH_LE" ); + } + else + { + tag_foot = self gettagorigin( "TAG_ATTACH_HATCH_RI" ); + } + s_church = getstruct( "giant_robot_church_marker", "targetname" ); + n_distance = distance2dsquared( tag_foot, s_church.origin ); + if ( n_distance < 1000000 ) + { + level setclientfield( "church_ceiling_fxanim", 1 ); + wait_network_frame(); + level setclientfield( "church_ceiling_fxanim", 0 ); + } +} + +play_pap_shake_fxanim( foot_side ) +{ + if ( foot_side == "left" ) + { + tag_foot = self gettagorigin( "TAG_ATTACH_HATCH_LE" ); + } + else + { + tag_foot = self gettagorigin( "TAG_ATTACH_HATCH_RI" ); + } + s_pap = getstruct( "giant_robot_pap_marker", "targetname" ); + wait 0,2; + n_distance = distance2dsquared( tag_foot, s_pap.origin ); + if ( n_distance < 2250000 ) + { + level setclientfield( "pap_monolith_ring_shake", 1 ); + wait_network_frame(); + level setclientfield( "pap_monolith_ring_shake", 0 ); + } +} + +player_transition_into_robot_head_start( n_start_time ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self.giant_robot_transition = 1; + self.dontspeak = 1; + self setclientfieldtoplayer( "giant_robot_rumble_and_shake", 3 ); + wait 1,5; + self setclientfieldtoplayer( "player_rumble_and_shake", 4 ); +} + +player_transition_into_robot_head_finish( n_transition_time ) +{ + self endon( "death" ); + self endon( "disconnect" ); + wait n_transition_time; + self setclientfieldtoplayer( "player_rumble_and_shake", 0 ); + self setclientfieldtoplayer( "giant_robot_rumble_and_shake", 0 ); + self.giant_robot_transition = 0; + wait 2; + if ( !flag( "story_vo_playing" ) ) + { + self.dontspeak = 0; + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "enter_robot" ); + } + if ( !isDefined( level.sndrobotheadcount ) || level.sndrobotheadcount == 0 ) + { + level.sndrobotheadcount = 4; + level thread maps/mp/zombies/_zm_audio::sndmusicstingerevent( "zone_robot_head" ); + } + else + { + level.sndrobotheadcount--; + + } +} + +gr_head_exit_trigger_start( s_origin ) +{ + s_origin.unitrigger_stub = spawnstruct(); + s_origin.unitrigger_stub.origin = s_origin.origin; + s_origin.unitrigger_stub.radius = 36; + s_origin.unitrigger_stub.height = 256; + s_origin.unitrigger_stub.script_unitrigger_type = "unitrigger_radius_use"; + s_origin.unitrigger_stub.hint_string = &"ZM_TOMB_EHT"; + s_origin.unitrigger_stub.cursor_hint = "HINT_NOICON"; + s_origin.unitrigger_stub.require_look_at = 1; + s_origin.unitrigger_stub.target = s_origin.target; + s_origin.unitrigger_stub.script_int = s_origin.script_int; + s_origin.unitrigger_stub.is_available = 1; + s_origin.unitrigger_stub.prompt_and_visibility_func = ::gr_head_eject_trigger_visibility; + maps/mp/zombies/_zm_unitrigger::unitrigger_force_per_player_triggers( s_origin.unitrigger_stub, 1 ); + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( s_origin.unitrigger_stub, ::player_exits_giant_robot_head_trigger_think ); +} + +gr_head_eject_trigger_visibility( player ) +{ + if ( isDefined( self.stub.is_available )b_is_invis = !self.stub.is_available; + self setinvisibletoplayer( player, b_is_invis ); + self sethintstring( self.stub.hint_string ); + return !b_is_invis; +} + +reset_gr_head_unitriggers() +{ + maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( self.unitrigger_stub ); + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( self.unitrigger_stub, ::player_exits_giant_robot_head_trigger_think ); +} + +player_exits_giant_robot_head_trigger_think() +{ + self endon( "tube_used_for_timeout" ); + while ( 1 ) + { + self waittill( "trigger", player ); + if ( isDefined( self.stub.is_available ) && !self.stub.is_available ) + { + continue; + } + if ( !isplayer( player ) || !is_player_valid( player ) ) + { + continue; + } + level thread init_player_eject_logic( self.stub, player ); + self.stub.is_available = 0; + } +} + +init_player_eject_logic( s_unitrigger, player, b_timeout ) +{ + if ( !isDefined( b_timeout ) ) + { + b_timeout = 0; + } + s_unitrigger.is_available = 0; + s_origin = getstruct( s_unitrigger.target, "targetname" ); + v_origin = s_origin.origin; + v_angles = s_origin.angles; + m_linkpoint = spawn_model( "tag_origin", v_origin, v_angles ); + if ( isDefined( level.giant_robot_head_player_eject_thread_custom_func ) ) + { + player thread [[ level.giant_robot_head_player_eject_thread_custom_func ]]( m_linkpoint, s_origin.script_noteworthy, b_timeout ); + } + else + { + player thread giant_robot_head_player_eject_thread( m_linkpoint, s_origin.script_noteworthy, b_timeout ); + } + tube_clone = player maps/mp/zombies/_zm_clone::spawn_player_clone( player, player.origin, undefined ); + player thread giant_robot_eject_disconnect_watcher( m_linkpoint, tube_clone ); + tube_clone linkto( m_linkpoint, "tag_origin", ( 0, 0, 1 ), ( 0, 0, 1 ) ); + tube_clone.ignoreme = 1; + tube_clone show(); + tube_clone detachall(); + tube_clone setvisibletoall(); + tube_clone setinvisibletoplayer( player ); + tube_clone maps/mp/zombies/_zm_clone::clone_animate( "idle" ); + tube_clone thread tube_clone_falls_to_earth( m_linkpoint ); + m_linkpoint waittill( "movedone" ); + wait 6; + s_unitrigger.is_available = 1; +} + +giant_robot_head_player_eject_thread( m_linkpoint, str_tube, b_timeout ) +{ + if ( !isDefined( b_timeout ) ) + { + b_timeout = 0; + } + self endon( "death_or_disconnect" ); + self maps/mp/zm_tomb_giant_robot_ffotd::giant_robot_head_player_eject_start(); + str_current_weapon = self getcurrentweapon(); + self disableweapons(); + self disableoffhandweapons(); + self enableinvulnerability(); + self setstance( "stand" ); + self allowstand( 1 ); + self allowcrouch( 0 ); + self allowprone( 0 ); + self playerlinktodelta( m_linkpoint, "tag_origin", 1, 20, 20, 20, 20 ); + self setplayerangles( m_linkpoint.angles ); + self ghost(); + self.dontspeak = 1; + self setclientfieldtoplayer( "isspeaking", 1 ); + self notify( "teleport" ); + self.giant_robot_transition = 1; + self playsoundtoplayer( "zmb_bot_timeout_alarm", self ); + self.old_angles = self.angles; + if ( !b_timeout ) + { + self setclientfield( "eject_steam_fx", 1 ); + self thread in_tube_manual_looping_rumble(); + wait 3; + } + self stopsounds(); + wait_network_frame(); + self playsoundtoplayer( "zmb_giantrobot_exit", self ); + self notify( "end_in_tube_rumble" ); + self thread exit_gr_manual_looping_rumble(); + m_linkpoint moveto( m_linkpoint.origin + vectorScale( ( 0, 0, 1 ), 2000 ), 2,5 ); + self thread fadetoblackforxsec( 0, 2, 1, 0, "white" ); + wait 1; + m_linkpoint moveto( self.teleport_initial_origin + vectorScale( ( 0, 0, 1 ), 3000 ), 0,05 ); + m_linkpoint.angles = vectorScale( ( 0, 0, 1 ), 90 ); + self enableweapons(); + self giveweapon( "falling_hands_tomb_zm" ); + self switchtoweaponimmediate( "falling_hands_tomb_zm" ); + self setweaponammoclip( "falling_hands_tomb_zm", 0 ); + wait 1; + self playsoundtoplayer( "zmb_giantrobot_fall", self ); + self playerlinktodelta( m_linkpoint, "tag_origin", 1, 180, 180, 20, 20 ); + m_linkpoint moveto( self.teleport_initial_origin, 3, 1 ); + m_linkpoint thread play_gr_eject_impact_player_fx( self ); + m_linkpoint notify( "start_gr_eject_fall_to_earth" ); + self thread player_screams_while_falling(); + wait 2,75; + self thread fadetoblackforxsec( 0, 1, 0, 0,5, "black" ); + self waittill( "gr_eject_fall_complete" ); + self takeweapon( "falling_hands_tomb_zm" ); + if ( isDefined( str_current_weapon ) && str_current_weapon != "none" ) + { + self switchtoweaponimmediate( str_current_weapon ); + } + self enableoffhandweapons(); + self unlink(); + m_linkpoint delete(); + self teleport_player_to_gr_footprint_safe_spot(); + self show(); + self setplayerangles( self.old_angles ); + self disableinvulnerability(); + self.dontspeak = 0; + self allowstand( 1 ); + self allowcrouch( 1 ); + self allowprone( 1 ); + self setclientfieldtoplayer( "isspeaking", 0 ); + self.in_giant_robot_head = undefined; + self.teleport_initial_origin = undefined; + self.old_angles = undefined; + self thread gr_eject_landing_rumble(); + self thread gr_eject_landing_rumble_on_position(); + self setclientfield( "eject_steam_fx", 0 ); + n_post_eject_time = 2,5; + self setstance( "prone" ); + self shellshock( "explosion", n_post_eject_time ); + self.giant_robot_transition = 0; + self notify( "gr_eject_sequence_complete" ); + if ( !flag( "story_vo_playing" ) ) + { + self delay_thread( 3, ::maps/mp/zombies/_zm_audio::create_and_play_dialog, "general", "air_chute_landing" ); + } +/# + debug_level = getDvarInt( "zombie_cheat" ); + if ( isDefined( debug_level ) && debug_level ) + { + self enableinvulnerability(); +#/ + } + wait n_post_eject_time; + self.ignoreme = 0; + self maps/mp/zm_tomb_giant_robot_ffotd::giant_robot_head_player_eject_end(); +} + +player_screams_while_falling() +{ + self endon( "disconnect" ); + self stopsounds(); + wait_network_frame(); + self playsoundtoplayer( "vox_plr_" + self.characterindex + "_exit_robot_0", self ); +} + +tube_clone_falls_to_earth( m_linkpoint ) +{ + m_linkpoint waittill( "start_gr_eject_fall_to_earth" ); + self maps/mp/zombies/_zm_clone::clone_animate( "falling" ); + m_linkpoint waittill( "movedone" ); + self delete(); +} + +in_tube_manual_looping_rumble() +{ + self endon( "end_in_tube_rumble" ); + self endon( "death" ); + self endon( "disconnect" ); + while ( 1 ) + { + self setclientfieldtoplayer( "giant_robot_rumble_and_shake", 1 ); + wait_network_frame(); + self setclientfieldtoplayer( "giant_robot_rumble_and_shake", 0 ); + wait_network_frame(); + wait 0,1; + } +} + +exit_gr_manual_looping_rumble() +{ + self endon( "end_exit_gr_rumble" ); + self endon( "death" ); + self endon( "disconnect" ); + while ( 1 ) + { + self setclientfieldtoplayer( "giant_robot_rumble_and_shake", 1 ); + wait_network_frame(); + self setclientfieldtoplayer( "giant_robot_rumble_and_shake", 0 ); + wait_network_frame(); + wait 0,1; + } +} + +gr_eject_landing_rumble() +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "end_exit_gr_rumble" ); + wait_network_frame(); + self setclientfieldtoplayer( "giant_robot_rumble_and_shake", 0 ); + wait_network_frame(); + self setclientfieldtoplayer( "giant_robot_rumble_and_shake", 3 ); + wait_network_frame(); + self setclientfieldtoplayer( "giant_robot_rumble_and_shake", 0 ); +} + +gr_eject_landing_rumble_on_position() +{ + self endon( "death" ); + self endon( "disconnect" ); + a_players = getplayers(); + _a1781 = a_players; + _k1781 = getFirstArrayKey( _a1781 ); + while ( isDefined( _k1781 ) ) + { + player = _a1781[ _k1781 ]; + if ( player == self ) + { + } + else if ( isDefined( player.giant_robot_transition ) && player.giant_robot_transition ) + { + } + else + { + if ( distance2dsquared( player.origin, self.origin ) < 250000 ) + { + player thread gr_eject_landing_rumble(); + } + } + _k1781 = getNextArrayKey( _a1781, _k1781 ); + } +} + +teleport_player_to_gr_footprint_safe_spot() +{ + self endon( "death" ); + self endon( "disconnect" ); + if ( isDefined( self.entered_foot_from_tank_bunker ) && self.entered_foot_from_tank_bunker ) + { + a_s_orgs = getstructarray( "tank_platform_safe_spots", "targetname" ); + _a1809 = a_s_orgs; + _k1809 = getFirstArrayKey( _a1809 ); + while ( isDefined( _k1809 ) ) + { + struct = _a1809[ _k1809 ]; + if ( !positionwouldtelefrag( struct.origin ) ) + { + self setorigin( struct.origin ); + break; + } + else + { + _k1809 = getNextArrayKey( _a1809, _k1809 ); + } + } + self.entered_foot_from_tank_bunker = 0; + return; + } + a_s_footprints = getstructarray( "giant_robot_footprint", "targetname" ); + a_s_footprints = get_array_of_closest( self.teleport_initial_origin, a_s_footprints ); + s_footprint = a_s_footprints[ 0 ]; + a_v_offset = []; + a_v_offset[ 0 ] = ( 0, 0, 1 ); + a_v_offset[ 1 ] = vectorScale( ( 0, 0, 1 ), 50 ); + a_v_offset[ 2 ] = vectorScale( ( 0, 0, 1 ), 50 ); + a_v_offset[ 3 ] = vectorScale( ( 0, 0, 1 ), 50 ); + a_v_offset[ 4 ] = vectorScale( ( 0, 0, 1 ), 50 ); + a_v_offset[ 5 ] = vectorScale( ( 0, 0, 1 ), 50 ); + a_v_offset[ 6 ] = vectorScale( ( 0, 0, 1 ), 50 ); + a_v_offset[ 7 ] = vectorScale( ( 0, 0, 1 ), 50 ); + a_v_offset[ 8 ] = vectorScale( ( 0, 0, 1 ), 50 ); + i = 0; + while ( i < a_v_offset.size ) + { + v_origin = s_footprint.origin + a_v_offset[ i ]; + v_trace_start = v_origin + vectorScale( ( 0, 0, 1 ), 100 ); + v_final = playerphysicstrace( v_trace_start, v_origin ); + if ( !positionwouldtelefrag( v_final ) ) + { + self setorigin( v_final ); + return; + } + else + { + i++; + } + } +} + +giant_robot_head_teleport_timeout( n_robot_id ) +{ + wait 15; + n_players_in_robot = count_players_in_gr_head( n_robot_id ); + if ( n_players_in_robot == 0 ) + { + return; + } + while ( flag( "maxis_audiolog_gr" + n_robot_id + "_playing" ) ) + { + wait 0,1; + } + n_players_in_robot = count_players_in_gr_head( n_robot_id ); + if ( n_players_in_robot == 0 ) + { + return; + } + level thread play_timeout_warning_vo( n_robot_id ); + maps/mp/zm_tomb_vo::reset_maxis_audiolog_unitrigger( n_robot_id ); + level setclientfield( "eject_warning_fx_robot_" + n_robot_id, 1 ); + a_players = getplayers(); + a_players[ 0 ] setclientfield( "all_tubes_play_eject_steam_fx", 1 ); + level waittill( "timeout_warning_vo_complete_" + n_robot_id ); + a_gr_head_triggers = getstructarray( "giant_robot_head_exit_trigger", "script_noteworthy" ); + a_shutdown_triggers = []; + _a1896 = a_gr_head_triggers; + _k1896 = getFirstArrayKey( _a1896 ); + while ( isDefined( _k1896 ) ) + { + trigger = _a1896[ _k1896 ]; + if ( trigger.script_int == n_robot_id ) + { + if ( isDefined( trigger.unitrigger_stub.is_available ) && trigger.unitrigger_stub.is_available ) + { + maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( trigger.unitrigger_stub ); + a_shutdown_triggers[ a_shutdown_triggers.size ] = trigger; + } + } + _k1896 = getNextArrayKey( _a1896, _k1896 ); + } + a_players = getplayers(); + a_m_linkspots = []; + _a1911 = a_players; + _k1911 = getFirstArrayKey( _a1911 ); + while ( isDefined( _k1911 ) ) + { + player = _a1911[ _k1911 ]; + if ( isDefined( player.in_giant_robot_head ) && player.in_giant_robot_head == n_robot_id ) + { + if ( isDefined( player.giant_robot_transition ) && !player.giant_robot_transition ) + { + if ( player player_is_in_laststand() ) + { + if ( isDefined( player.waiting_to_revive ) && player.waiting_to_revive && a_players.size <= 1 ) + { + flag_set( "instant_revive" ); + player.stopflashingbadlytime = getTime() + 1000; + wait_network_frame(); + flag_clear( "instant_revive" ); + break; + } + else + { + player thread maps/mp/zombies/_zm_laststand::bleed_out(); + player notify( "gr_head_forced_bleed_out" ); + break; + } + } + else + { + if ( isalive( player ) ) + { + m_linkspot = spawn_model( "tag_origin", player.origin, player.angles ); + a_m_linkspots[ a_m_linkspots.size ] = m_linkspot; + player start_drag_player_to_eject_tube( n_robot_id, m_linkspot ); + wait 0,1; + } + } + } + } + _k1911 = getNextArrayKey( _a1911, _k1911 ); + } + wait 10; + maps/mp/zm_tomb_vo::restart_maxis_audiolog_unitrigger( n_robot_id ); + level setclientfield( "eject_warning_fx_robot_" + n_robot_id, 0 ); + a_players = getplayers(); + a_players[ 0 ] setclientfield( "all_tubes_play_eject_steam_fx", 0 ); + _a1958 = a_shutdown_triggers; + _k1958 = getFirstArrayKey( _a1958 ); + while ( isDefined( _k1958 ) ) + { + trigger = _a1958[ _k1958 ]; + if ( trigger.script_int == n_robot_id ) + { + trigger thread reset_gr_head_unitriggers(); + } + _k1958 = getNextArrayKey( _a1958, _k1958 ); + } + while ( a_m_linkspots.size > 0 ) + { + i = 0; + while ( i < a_m_linkspots.size ) + { + if ( isDefined( a_m_linkspots[ i ] ) ) + { + a_m_linkspots[ i ] delete(); + } + i++; + } + } +} + +start_drag_player_to_eject_tube( n_robot_id, m_linkspot ) +{ + self endon( "death" ); + self endon( "disconnect" ); + a_gr_head_triggers = getstructarray( "giant_robot_head_exit_trigger", "script_noteworthy" ); + a_gr_head_triggers = get_array_of_closest( self.origin, a_gr_head_triggers ); + _a1987 = a_gr_head_triggers; + _k1987 = getFirstArrayKey( _a1987 ); + while ( isDefined( _k1987 ) ) + { + trigger = _a1987[ _k1987 ]; + if ( trigger.unitrigger_stub.script_int == n_robot_id ) + { + if ( isDefined( trigger.unitrigger_stub.is_available ) && trigger.unitrigger_stub.is_available ) + { + self thread in_tube_manual_looping_rumble(); + trigger.unitrigger_stub.is_available = 0; + s_tube = getstruct( trigger.target, "targetname" ); + self playerlinktodelta( m_linkspot, "tag_origin", 1, 20, 20, 20, 20 ); + self thread move_player_to_eject_tube( m_linkspot, s_tube, trigger ); + return; + } + } + else + { + _k1987 = getNextArrayKey( _a1987, _k1987 ); + } + } +} + +move_player_to_eject_tube( m_linkspot, s_tube, trigger ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self.giant_robot_transition = 1; + n_speed = 500; + n_dist = distance( m_linkspot.origin, s_tube.origin ); + n_time = n_dist / n_speed; + m_linkspot moveto( s_tube.origin, n_time ); + m_linkspot waittill( "movedone" ); + m_linkspot delete(); + level thread init_player_eject_logic( trigger.unitrigger_stub, self, 1 ); +} + +sndalarmtimeout() +{ + self endon( "teleport" ); + self endon( "disconnect" ); + self playsoundtoplayer( "zmb_bot_timeout_alarm", self ); + wait 2,5; + self playsoundtoplayer( "zmb_bot_timeout_alarm", self ); +} + +play_gr_eject_impact_player_fx( player ) +{ + player endon( "death" ); + player endon( "disconnect" ); + self waittill( "movedone" ); + player setclientfield( "gr_eject_player_impact_fx", 1 ); + wait_network_frame(); + player notify( "gr_eject_fall_complete" ); + wait 1; + player setclientfield( "gr_eject_player_impact_fx", 0 ); +} + +player_death_watch_on_giant_robot() +{ + self endon( "disconnect" ); + self endon( "gr_eject_sequence_complete" ); + self waittill_either( "bled_out", "gr_head_forced_bleed_out" ); + self.entered_foot_from_tank_bunker = undefined; + self.giant_robot_transition = undefined; + self.in_giant_robot_head = undefined; + self.ignoreme = 0; + self.dontspeak = 0; +} + +giant_robot_eject_disconnect_watcher( m_linkpoint, tube_clone ) +{ + self endon( "gr_eject_sequence_complete" ); + self waittill( "disconnect" ); + if ( isDefined( m_linkpoint ) ) + { + m_linkpoint delete(); + } + if ( isDefined( tube_clone ) ) + { + tube_clone delete(); + } +} + +turn_clientside_rumble_off() +{ + self endon( "death" ); + self endon( "disconnect" ); + wait_network_frame(); + self setclientfieldtoplayer( "giant_robot_rumble_and_shake", 0 ); +} + +spawn_model( model_name, origin, angles, n_spawnflags ) +{ + if ( !isDefined( n_spawnflags ) ) + { + n_spawnflags = 0; + } + if ( !isDefined( origin ) ) + { + origin = ( 0, 0, 1 ); + } + model = spawn( "script_model", origin, n_spawnflags ); + model setmodel( model_name ); + if ( isDefined( angles ) ) + { + model.angles = angles; + } + return model; +} + +count_players_in_gr_head( n_robot_id ) +{ + n_players_in_robot = 0; + a_players = getplayers(); + _a2116 = a_players; + _k2116 = getFirstArrayKey( _a2116 ); + while ( isDefined( _k2116 ) ) + { + player = _a2116[ _k2116 ]; + if ( isDefined( player.in_giant_robot_head ) && player.in_giant_robot_head == n_robot_id ) + { + n_players_in_robot++; + } + _k2116 = getNextArrayKey( _a2116, _k2116 ); + } + return n_players_in_robot; +} + +tomb_standard_intermission() +{ + self closemenu(); + self closeingamemenu(); + level endon( "stop_intermission" ); + self endon( "disconnect" ); + self endon( "death" ); + self notify( "_zombie_game_over" ); + level thread setup_giant_robots_intermission(); + self.score = self.score_total; + self.sessionstate = "intermission"; + self.spectatorclient = -1; + self.killcamentity = -1; + self.archivetime = 0; + self.psoffsettime = 0; + self.friendlydamage = undefined; + points = getstructarray( "intermission", "targetname" ); + if ( !isDefined( points ) || points.size == 0 ) + { + points = getentarray( "info_intermission", "classname" ); + if ( points.size < 1 ) + { +/# + println( "NO info_intermission POINTS IN MAP" ); +#/ + return; + } + } + self.game_over_bg = newclienthudelem( self ); + self.game_over_bg.horzalign = "fullscreen"; + self.game_over_bg.vertalign = "fullscreen"; + self.game_over_bg setshader( "black", 640, 480 ); + self.game_over_bg.alpha = 1; + org = undefined; + while ( 1 ) + { + points = array_randomize( points ); + i = 0; + while ( i < points.size ) + { + point = points[ i ]; + if ( !isDefined( org ) ) + { + self spawn( point.origin, point.angles ); + } + if ( isDefined( points[ i ].target ) ) + { + if ( !isDefined( org ) ) + { + org = spawn( "script_model", self.origin + vectorScale( ( 0, 0, 1 ), 60 ) ); + org setmodel( "tag_origin" ); + } + org.origin = points[ i ].origin; + org.angles = points[ i ].angles; + j = 0; + while ( j < get_players().size ) + { + player = get_players()[ j ]; + player camerasetposition( org ); + player camerasetlookat(); + player cameraactivate( 1 ); + j++; + } + speed = 20; + if ( isDefined( points[ i ].speed ) ) + { + speed = points[ i ].speed; + } + target_point = getstruct( points[ i ].target, "targetname" ); + dist = distance( points[ i ].origin, target_point.origin ); + time = dist / speed; + q_time = time * 0,25; + if ( q_time > 1 ) + { + q_time = 1; + } + self.game_over_bg fadeovertime( q_time ); + self.game_over_bg.alpha = 0; + org moveto( target_point.origin, time, q_time, q_time ); + org rotateto( target_point.angles, time, q_time, q_time ); + wait ( time - q_time ); + self.game_over_bg fadeovertime( q_time ); + self.game_over_bg.alpha = 1; + wait q_time; + i++; + continue; + } + else + { + self.game_over_bg fadeovertime( 1 ); + self.game_over_bg.alpha = 0; + wait 5; + self.game_over_bg thread maps/mp/zombies/_zm::fade_up_over_time( 1 ); + } + i++; + } + } +} + +setup_giant_robots_intermission() +{ + i = 0; + while ( i < 3 ) + { + ai_giant_robot = getent( "giant_robot_walker_" + i, "targetname" ); + if ( !isDefined( ai_giant_robot ) ) + { + i++; + continue; + } + else + { + ai_giant_robot ghost(); + ai_giant_robot stopanimscripted( 0,05 ); + ai_giant_robot notify( "giant_robot_stop" ); + if ( i == 2 ) + { + wait_network_frame(); + ai_giant_robot show(); + str_anim_scripted_name = "zm_robot_walk_village"; + s_robot_path = getstruct( "anim_align_robot_village", "targetname" ); + s_robot_path.angles = ( 0, 0, 1 ); + animationid = ai_giant_robot getanimfromasd( "zm_robot_walk_village", 1 ); + ai_giant_robot thread maps/mp/animscripts/zm_shared::donotetracks( "scripted_walk" ); + ai_giant_robot animscripted( s_robot_path.origin, s_robot_path.angles, str_anim_scripted_name, 1 ); + } + } + i++; + } +} + +giant_robot_discovered_vo( ai_giant_robot ) +{ + ai_giant_robot endon( "giant_robot_stop" ); + self endon( "disconnect" ); + level endon( "giant_robot_discovered" ); + while ( 1 ) + { + if ( distance2dsquared( self.origin, ai_giant_robot.origin ) < 16000000 ) + { + if ( self is_player_looking_at( ai_giant_robot.origin + vectorScale( ( 0, 0, 1 ), 2000 ), 0,85 ) ) + { + if ( isDefined( self.dontspeak ) && !self.dontspeak ) + { + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "discover_robot" ); + level.giant_robot_discovered = 1; + level notify( "giant_robot_discovered" ); + return; + } + } + } + else + { + wait 0,1; + } + } +} + +three_robot_round_vo( ai_giant_robot ) +{ + ai_giant_robot endon( "giant_robot_stop" ); + self endon( "disconnect" ); + level endon( "three_robot_round_vo" ); + while ( 1 ) + { + if ( distance2dsquared( self.origin, ai_giant_robot.origin ) < 16000000 ) + { + if ( self is_player_looking_at( ai_giant_robot.origin + vectorScale( ( 0, 0, 1 ), 2000 ), 0,85 ) ) + { + if ( isDefined( self.dontspeak ) && !self.dontspeak ) + { + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "see_robots" ); + level.three_robot_round_vo = 1; + level notify( "three_robot_round_vo" ); + return; + } + } + } + else + { + wait 0,1; + } + } +} + +shoot_at_giant_robot_vo( ai_giant_robot ) +{ + ai_giant_robot endon( "giant_robot_stop" ); + self endon( "disconnect" ); + level endon( "shoot_robot_vo" ); + while ( 1 ) + { + while ( distance2dsquared( self.origin, ai_giant_robot.origin ) < 16000000 && self is_player_looking_at( ai_giant_robot.origin + vectorScale( ( 0, 0, 1 ), 2000 ), 0,7 ) ) + { + self waittill( "weapon_fired" ); + if ( distance2dsquared( self.origin, ai_giant_robot.origin ) < 16000000 && self is_player_looking_at( ai_giant_robot.origin + vectorScale( ( 0, 0, 1 ), 2000 ), 0,7 ) ) + { + if ( isDefined( self.dontspeak ) && !self.dontspeak ) + { + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "shoot_robot" ); + level.shoot_robot_vo = 1; + level notify( "shoot_robot_vo" ); + return; + } + } + } + wait 0,1; + } +} + +start_robot_stomp_warning_vo( foot_side ) +{ + if ( foot_side == "right" ) + { + str_tag = "TAG_ATTACH_HATCH_RI"; + } + else + { + if ( foot_side == "left" ) + { + str_tag = "TAG_ATTACH_HATCH_LE"; + } + } + v_origin = self gettagorigin( str_tag ); + a_s_footprint_all = getstructarray( "giant_robot_footprint_center", "targetname" ); + a_s_footprint = []; + _a2384 = a_s_footprint_all; + _k2384 = getFirstArrayKey( _a2384 ); + while ( isDefined( _k2384 ) ) + { + footprint = _a2384[ _k2384 ]; + if ( footprint.script_int == self.giant_robot_id ) + { + a_s_footprint[ a_s_footprint.size ] = footprint; + } + _k2384 = getNextArrayKey( _a2384, _k2384 ); + } + if ( a_s_footprint.size == 0 ) + { + return; + } + else + { + a_s_footprint = get_array_of_closest( v_origin, a_s_footprint ); + s_footprint = a_s_footprint[ 0 ]; + } + a_players = getplayers(); + _a2404 = a_players; + _k2404 = getFirstArrayKey( _a2404 ); + while ( isDefined( _k2404 ) ) + { + player = _a2404[ _k2404 ]; + if ( distance2dsquared( player.origin, s_footprint.origin ) < 160000 ) + { + player thread play_robot_stomp_warning_vo(); + } + _k2404 = getNextArrayKey( _a2404, _k2404 ); + } +} + +play_robot_stomp_warning_vo() +{ + a_players = getplayers(); + _a2417 = a_players; + _k2417 = getFirstArrayKey( _a2417 ); + while ( isDefined( _k2417 ) ) + { + player = _a2417[ _k2417 ]; + if ( player == self ) + { + } + else + { + if ( distance2dsquared( self.origin, player.origin ) < 640000 ) + { + if ( player is_player_looking_at( self.origin + vectorScale( ( 0, 0, 1 ), 60 ) ) ) + { + if ( isDefined( player.dontspeak ) && !player.dontspeak ) + { + player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "warn_robot_foot" ); + return; + } + } + } + } + else + { + _k2417 = getNextArrayKey( _a2417, _k2417 ); + } + } +} + +zombie_stomped_by_gr_vo( foot_side ) +{ + self endon( "giant_robot_stop" ); + if ( foot_side == "right" ) + { + str_tag = "TAG_ATTACH_HATCH_RI"; + } + else + { + if ( foot_side == "left" ) + { + str_tag = "TAG_ATTACH_HATCH_LE"; + } + } + v_origin = self gettagorigin( str_tag ); + a_players = getplayers(); + _a2454 = a_players; + _k2454 = getFirstArrayKey( _a2454 ); + while ( isDefined( _k2454 ) ) + { + player = _a2454[ _k2454 ]; + if ( distancesquared( v_origin, player.origin ) < 640000 ) + { + if ( player is_player_looking_at( v_origin, 0,25 ) ) + { + if ( isDefined( player.dontspeak ) && !player.dontspeak ) + { + player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "robot_crush_zombie" ); + return; + } + } + } + _k2454 = getNextArrayKey( _a2454, _k2454 ); + } +} + +play_robot_crush_player_vo() +{ + self endon( "disconnect" ); + if ( self player_is_in_laststand() ) + { + if ( cointoss() ) + { + n_alt = 1; + } + else + { + n_alt = 0; + } + self playsoundwithnotify( "vox_plr_" + self.characterindex + "_robot_crush_player_" + n_alt, "sound_done" + "vox_plr_" + self.characterindex + "_robot_crush_player_" + n_alt ); + } +} + +play_timeout_warning_vo( n_robot_id ) +{ + flag_set( "timeout_vo_robot_" + n_robot_id ); + s_origin = getstruct( "eject_warning_fx_robot_" + n_robot_id, "targetname" ); + e_vo_origin = spawn_model( "tag_origin", s_origin.origin ); + e_vo_origin playsoundwithnotify( "vox_maxi_purge_robot_0", "vox_maxi_purge_robot_0_done" ); + e_vo_origin waittill( "vox_maxi_purge_robot_0_done" ); + a_players = getplayers(); + _a2499 = a_players; + _k2499 = getFirstArrayKey( _a2499 ); + while ( isDefined( _k2499 ) ) + { + player = _a2499[ _k2499 ]; + if ( isDefined( player.in_giant_robot_head ) && player.in_giant_robot_head == n_robot_id ) + { + if ( isDefined( player.giant_robot_transition ) && !player.giant_robot_transition ) + { + if ( isDefined( player.dontspeak ) && !player.dontspeak ) + { + player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "purge_robot" ); + break; + } + } + } + else + { + _k2499 = getNextArrayKey( _a2499, _k2499 ); + } + } + while ( isDefined( player ) && isDefined( player.isspeaking ) && player.isspeaking ) + { + wait 0,1; + } + wait 1; + e_vo_origin playsoundwithnotify( "vox_maxi_purge_countdown_0", "vox_maxi_purge_countdown_0_done" ); + e_vo_origin waittill( "vox_maxi_purge_countdown_0_done" ); + wait 1; + level notify( "timeout_warning_vo_complete_" + n_robot_id ); + e_vo_origin playsoundwithnotify( "vox_maxi_purge_now_0", "vox_maxi_purge_now_0_done" ); + e_vo_origin waittill( "vox_maxi_purge_now_0_done" ); + e_vo_origin delete(); + flag_clear( "timeout_vo_robot_" + n_robot_id ); +} + +start_footprint_warning_vo( n_robot_id ) +{ + wait 20; + a_structs = getstructarray( "giant_robot_footprint_center", "targetname" ); + _a2540 = a_structs; + _k2540 = getFirstArrayKey( _a2540 ); + while ( isDefined( _k2540 ) ) + { + struct = _a2540[ _k2540 ]; + if ( struct.script_int == n_robot_id ) + { + struct thread footprint_check_for_nearby_players( self ); + } + _k2540 = getNextArrayKey( _a2540, _k2540 ); + } +} + +footprint_check_for_nearby_players( ai_giant_robot ) +{ + level endon( "footprint_warning_vo" ); + ai_giant_robot endon( "giant_robot_stop" ); + while ( 1 ) + { + a_players = getplayers(); + _a2558 = a_players; + _k2558 = getFirstArrayKey( _a2558 ); + while ( isDefined( _k2558 ) ) + { + player = _a2558[ _k2558 ]; + if ( distance2dsquared( player.origin, self.origin ) < 90000 ) + { + if ( distance2dsquared( player.origin, ai_giant_robot.origin ) < 16000000 ) + { + if ( player.origin[ 0 ] > ai_giant_robot.origin[ 0 ] ) + { + if ( isDefined( player.dontspeak ) && !player.dontspeak ) + { + player do_player_general_vox( "general", "warn_robot" ); + level.footprint_warning_vo = 1; + level notify( "footprint_warning_vo" ); + return; + } + } + } + } + _k2558 = getNextArrayKey( _a2558, _k2558 ); + } + wait 1; + } +} + +setup_giant_robot_devgui() +{ +/# + setdvar( "force_giant_robot_0", "off" ); + setdvar( "force_giant_robot_1", "off" ); + setdvar( "force_giant_robot_2", "off" ); + setdvar( "force_three_robot_round", "off" ); + setdvar( "force_left_foot", "off" ); + setdvar( "force_right_foot", "off" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Giant Robot:1/Force Robot 0 (NML):1" "force_giant_robot_0 on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Giant Robot:1/Force Robot 1 (Trench):2" "force_giant_robot_1 on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Giant Robot:1/Force Robot 2 (Village):3" "force_giant_robot_2 on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Giant Robot:1/Force Three Robot Round:4" "force_three_robot_round on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Giant Robot:1/Force Left Foot:5" "force_left_foot on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Giant Robot:1/Force Right Foot:6" "force_right_foot on"\n" ); + level thread watch_for_force_giant_robot(); +#/ +} + +watch_for_force_giant_robot() +{ +/# + while ( 1 ) + { + if ( getDvar( "force_giant_robot_0" ) == "on" ) + { + setdvar( "force_giant_robot_0", "off" ); + if ( isDefined( level.devgui_force_giant_robot ) && level.devgui_force_giant_robot == 0 ) + { + level.devgui_force_giant_robot = undefined; + iprintlnbold( "Force Giant Robot off" ); + break; + } + else + { + level.devgui_force_giant_robot = 0; + iprintlnbold( "Force Giant Robot 0 (NML)" ); + } + } + if ( getDvar( "force_giant_robot_1" ) == "on" ) + { + setdvar( "force_giant_robot_1", "off" ); + if ( isDefined( level.devgui_force_giant_robot ) && level.devgui_force_giant_robot == 1 ) + { + level.devgui_force_giant_robot = undefined; + iprintlnbold( "Force Giant Robot off" ); + break; + } + else + { + level.devgui_force_giant_robot = 1; + iprintlnbold( "Force Giant Robot 1 (Trench)" ); + } + } + if ( getDvar( "force_giant_robot_2" ) == "on" ) + { + setdvar( "force_giant_robot_2", "off" ); + if ( isDefined( level.devgui_force_giant_robot ) && level.devgui_force_giant_robot == 2 ) + { + level.devgui_force_giant_robot = undefined; + iprintlnbold( "Force Giant Robot off" ); + break; + } + else + { + level.devgui_force_giant_robot = 2; + iprintlnbold( "Force Giant Robot 2 (Village)" ); + } + } + if ( getDvar( "force_three_robot_round" ) == "on" ) + { + setdvar( "force_three_robot_round", "off" ); + if ( isDefined( level.devgui_force_three_robot_round ) && level.devgui_force_three_robot_round ) + { + level.devgui_force_three_robot_round = undefined; + iprintlnbold( "Force Three Robot Round off" ); + break; + } + else + { + level.devgui_force_three_robot_round = 1; + iprintlnbold( "Force Three Robot Round" ); + } + } + if ( getDvar( "force_left_foot" ) == "on" ) + { + setdvar( "force_left_foot", "off" ); + if ( isDefined( level.devgui_force_giant_robot_foot ) && level.devgui_force_giant_robot_foot == "left" ) + { + level.devgui_force_giant_robot_foot = undefined; + iprintlnbold( "Force Giant Robot Foot Off" ); + break; + } + else + { + level.devgui_force_giant_robot_foot = "left"; + iprintlnbold( "Force Giant Robot Hatch on Left Foot" ); + } + } + if ( getDvar( "force_right_foot" ) == "on" ) + { + setdvar( "force_right_foot", "off" ); + if ( isDefined( level.devgui_force_giant_robot_foot ) && level.devgui_force_giant_robot_foot == "right" ) + { + level.devgui_force_giant_robot_foot = undefined; + iprintlnbold( "Force Giant Robot Foot Off" ); + break; + } + else + { + level.devgui_force_giant_robot_foot = "right"; + iprintlnbold( "Force Giant Robot Hatch on Right Foot" ); + } + } + wait 0,05; +#/ + } +} + +starting_spawn_light() +{ + light = getent( "start_bunker_footprint_light", "targetname" ); + if ( !isDefined( light ) ) + { + return; + } + light setlightintensity( 0 ); + wait 5,4; + i = 8; + while ( i <= 16 ) + { + light setlightintensity( i ); + wait 0,1; + i += 8; + } +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_giant_robot_ffotd.gsc b/zm_tomb_patch/maps/mp/zm_tomb_giant_robot_ffotd.gsc new file mode 100644 index 0000000..273fab8 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_giant_robot_ffotd.gsc @@ -0,0 +1,35 @@ +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init_giant_robot_start() +{ +} + +init_giant_robot_end() +{ +} + +init_giant_robot_glows_start() +{ +} + +init_giant_robot_glows_end() +{ +} + +giant_robot_spawn_start() +{ +} + +giant_robot_spawn_end() +{ +} + +giant_robot_head_player_eject_start() +{ +} + +giant_robot_head_player_eject_end() +{ +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_main_quest.gsc b/zm_tomb_patch/maps/mp/zm_tomb_main_quest.gsc new file mode 100644 index 0000000..7d80c25 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_main_quest.gsc @@ -0,0 +1,1351 @@ +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zm_tomb_amb; +#include maps/mp/zm_tomb_challenges; +#include maps/mp/zm_tomb_ee_main_step_7; +#include maps/mp/zombies/_zm_challenges; +#include maps/mp/zombies/_zm_zonemgr; +#include maps/mp/zombies/_zm_unitrigger; +#include maps/mp/zm_tomb_craftables; +#include maps/mp/zombies/_zm_blockers; +#include maps/mp/zm_tomb_teleporter; +#include maps/mp/zm_tomb_vo; +#include maps/mp/zombies/_zm_net; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_sidequests; +#include maps/mp/zombies/_zm_craftables; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +#using_animtree( "fxanim_props_dlc4" ); + +main_quest_init() +{ + flag_init( "dug" ); + flag_init( "air_open" ); + flag_init( "fire_open" ); + flag_init( "lightning_open" ); + flag_init( "ice_open" ); + flag_init( "panels_solved" ); + flag_init( "fire_solved" ); + flag_init( "ice_solved" ); + flag_init( "chamber_puzzle_cheat" ); + flag_init( "activate_zone_crypt" ); + level.callbackvehicledamage = ::aircrystalbiplanecallback_vehicledamage; + level.game_mode_custom_onplayerdisconnect = ::player_disconnect_callback; + onplayerconnect_callback( ::onplayerconnect ); + staff_air = getent( "prop_staff_air", "targetname" ); + staff_fire = getent( "prop_staff_fire", "targetname" ); + staff_lightning = getent( "prop_staff_lightning", "targetname" ); + staff_water = getent( "prop_staff_water", "targetname" ); + staff_air.weapname = "staff_air_zm"; + staff_fire.weapname = "staff_fire_zm"; + staff_lightning.weapname = "staff_lightning_zm"; + staff_water.weapname = "staff_water_zm"; + staff_air.element = "air"; + staff_fire.element = "fire"; + staff_lightning.element = "lightning"; + staff_water.element = "water"; + staff_air.craftable_name = "elemental_staff_air"; + staff_fire.craftable_name = "elemental_staff_fire"; + staff_lightning.craftable_name = "elemental_staff_lightning"; + staff_water.craftable_name = "elemental_staff_water"; + staff_air.charger = getstruct( "staff_air_charger", "script_noteworthy" ); + staff_fire.charger = getstruct( "staff_fire_charger", "script_noteworthy" ); + staff_lightning.charger = getstruct( "zone_bolt_chamber", "script_noteworthy" ); + staff_water.charger = getstruct( "staff_ice_charger", "script_noteworthy" ); + staff_fire.quest_clientfield = "quest_state1"; + staff_air.quest_clientfield = "quest_state2"; + staff_lightning.quest_clientfield = "quest_state3"; + staff_water.quest_clientfield = "quest_state4"; + staff_fire.enum = 1; + staff_air.enum = 2; + staff_lightning.enum = 3; + staff_water.enum = 4; + level.a_elemental_staffs = []; + level.a_elemental_staffs[ level.a_elemental_staffs.size ] = staff_air; + level.a_elemental_staffs[ level.a_elemental_staffs.size ] = staff_fire; + level.a_elemental_staffs[ level.a_elemental_staffs.size ] = staff_lightning; + level.a_elemental_staffs[ level.a_elemental_staffs.size ] = staff_water; + _a90 = level.a_elemental_staffs; + _k90 = getFirstArrayKey( _a90 ); + while ( isDefined( _k90 ) ) + { + staff = _a90[ _k90 ]; + staff.charger.charges_received = 0; + staff.charger.is_inserted = 0; + staff thread place_staffs_encasement(); + staff thread staff_charger_check(); + staff ghost(); + _k90 = getNextArrayKey( _a90, _k90 ); + } + staff_air_upgraded = getent( "prop_staff_air_upgraded", "targetname" ); + staff_fire_upgraded = getent( "prop_staff_fire_upgraded", "targetname" ); + staff_lightning_upgraded = getent( "prop_staff_lightning_upgraded", "targetname" ); + staff_water_upgraded = getent( "prop_staff_water_upgraded", "targetname" ); + staff_air_upgraded.weapname = "staff_air_upgraded_zm"; + staff_fire_upgraded.weapname = "staff_fire_upgraded_zm"; + staff_lightning_upgraded.weapname = "staff_lightning_upgraded_zm"; + staff_water_upgraded.weapname = "staff_water_upgraded_zm"; + staff_air_upgraded.melee = "staff_air_melee_zm"; + staff_fire_upgraded.melee = "staff_fire_melee_zm"; + staff_lightning_upgraded.melee = "staff_lightning_melee_zm"; + staff_water_upgraded.melee = "staff_water_melee_zm"; + staff_air_upgraded.base_weapname = "staff_air_zm"; + staff_fire_upgraded.base_weapname = "staff_fire_zm"; + staff_lightning_upgraded.base_weapname = "staff_lightning_zm"; + staff_water_upgraded.base_weapname = "staff_water_zm"; + staff_air_upgraded.element = "air"; + staff_fire_upgraded.element = "fire"; + staff_lightning_upgraded.element = "lightning"; + staff_water_upgraded.element = "water"; + staff_air_upgraded.charger = staff_air.charger; + staff_fire_upgraded.charger = staff_fire.charger; + staff_lightning_upgraded.charger = staff_lightning.charger; + staff_water_upgraded.charger = staff_water.charger; + staff_fire_upgraded.enum = 1; + staff_air_upgraded.enum = 2; + staff_lightning_upgraded.enum = 3; + staff_water_upgraded.enum = 4; + staff_air.upgrade = staff_air_upgraded; + staff_fire.upgrade = staff_fire_upgraded; + staff_water.upgrade = staff_water_upgraded; + staff_lightning.upgrade = staff_lightning_upgraded; + level.a_elemental_staffs_upgraded = []; + level.a_elemental_staffs_upgraded[ level.a_elemental_staffs_upgraded.size ] = staff_air_upgraded; + level.a_elemental_staffs_upgraded[ level.a_elemental_staffs_upgraded.size ] = staff_fire_upgraded; + level.a_elemental_staffs_upgraded[ level.a_elemental_staffs_upgraded.size ] = staff_lightning_upgraded; + level.a_elemental_staffs_upgraded[ level.a_elemental_staffs_upgraded.size ] = staff_water_upgraded; + _a147 = level.a_elemental_staffs_upgraded; + _k147 = getFirstArrayKey( _a147 ); + while ( isDefined( _k147 ) ) + { + staff_upgraded = _a147[ _k147 ]; + staff_upgraded.charger.charges_received = 0; + staff_upgraded.charger.is_inserted = 0; + staff_upgraded.charger.is_charged = 0; + staff_upgraded.prev_ammo_clip = weaponclipsize( staff_upgraded.weapname ); + staff_upgraded.prev_ammo_stock = weaponmaxammo( staff_upgraded.weapname ); + staff_upgraded thread place_staffs_encasement(); + staff_upgraded ghost(); + _k147 = getNextArrayKey( _a147, _k147 ); + } + _a159 = level.a_elemental_staffs; + _k159 = getFirstArrayKey( _a159 ); + while ( isDefined( _k159 ) ) + { + staff = _a159[ _k159 ]; + staff.prev_ammo_clip = weaponclipsize( staff_upgraded.weapname ); + staff.prev_ammo_stock = weaponmaxammo( staff_upgraded.weapname ); + staff.upgrade.downgrade = staff; + staff.upgrade useweaponmodel( staff.weapname ); + staff.upgrade showallparts(); + _k159 = getNextArrayKey( _a159, _k159 ); + } + level.staffs_charged = 0; + array_thread( level.zombie_spawners, ::add_spawn_function, ::zombie_spawn_func ); + level thread watch_for_staff_upgrades(); + level thread chambers_init(); + level thread maps/mp/zm_tomb_quest_air::main(); + level thread maps/mp/zm_tomb_quest_fire::main(); + level thread maps/mp/zm_tomb_quest_ice::main(); + level thread maps/mp/zm_tomb_quest_elec::main(); + level thread maps/mp/zm_tomb_quest_crypt::main(); + level thread maps/mp/zm_tomb_chamber::main(); + level thread maps/mp/zm_tomb_vo::watch_occasional_line( "puzzle", "puzzle_confused", "vo_puzzle_confused" ); + level thread maps/mp/zm_tomb_vo::watch_occasional_line( "puzzle", "puzzle_good", "vo_puzzle_good" ); + level thread maps/mp/zm_tomb_vo::watch_occasional_line( "puzzle", "puzzle_bad", "vo_puzzle_bad" ); + level thread maps/mp/zm_tomb_vo::watch_one_shot_samantha_clue( "vox_sam_ice_staff_clue_0", "sam_clue_dig", "elemental_staff_water_all_pieces_found" ); + level thread maps/mp/zm_tomb_vo::watch_one_shot_samantha_clue( "vox_sam_fire_staff_clue_0", "sam_clue_mechz", "mechz_killed" ); + level thread maps/mp/zm_tomb_vo::watch_one_shot_samantha_clue( "vox_sam_fire_staff_clue_1", "sam_clue_biplane", "biplane_down" ); + level thread maps/mp/zm_tomb_vo::watch_one_shot_samantha_clue( "vox_sam_fire_staff_clue_2", "sam_clue_zonecap", "staff_piece_capture_complete" ); + level thread maps/mp/zm_tomb_vo::watch_one_shot_samantha_clue( "vox_sam_lightning_staff_clue_0", "sam_clue_tank", "elemental_staff_lightning_all_pieces_found" ); + level thread maps/mp/zm_tomb_vo::watch_one_shot_samantha_clue( "vox_sam_wind_staff_clue_0", "sam_clue_giant", "elemental_staff_air_all_pieces_found" ); + level.dig_spawners = getentarray( "zombie_spawner_dig", "script_noteworthy" ); + array_thread( level.dig_spawners, ::add_spawn_function, ::dug_zombie_spawn_init ); +} + +onplayerconnect() +{ +} + +player_disconnect_callback( player ) +{ + n_player = player getentitynumber() + 1; + level delay_thread( 0,5, ::clear_player_staff_by_player_number, n_player ); +} + +place_staffs_encasement() +{ + s_pos = getstruct( "staff_pos_" + self.element, "targetname" ); + self.origin = s_pos.origin; + self.angles = s_pos.angles; +} + +chambers_init() +{ + flag_init( "gramophone_placed" ); + array_thread( getentarray( "trigger_death_floor", "targetname" ), ::monitor_chamber_death_trigs ); + a_stargate_gramophones = getstructarray( "stargate_gramophone_pos", "targetname" ); + array_thread( a_stargate_gramophones, ::run_gramophone_teleporter ); + a_door_main = getentarray( "chamber_entrance", "targetname" ); + array_thread( a_door_main, ::run_gramophone_door, "vinyl_master" ); +} + +monitor_chamber_death_trigs() +{ + while ( 1 ) + { + self waittill( "trigger", ent ); + if ( isplayer( ent ) ) + { + ent.bleedout_time = 0; + } + ent dodamage( ent.health + 666, ent.origin ); + wait 0,05; + } +} + +watch_gramophone_vinyl_pickup() +{ + str_vinyl_record = "vinyl_main"; + switch( self.script_int ) + { + case 1: + str_vinyl_record = "vinyl_fire"; + break; + case 2: + str_vinyl_record = "vinyl_air"; + break; + case 3: + str_vinyl_record = "vinyl_elec"; + break; + case 4: + str_vinyl_record = "vinyl_ice"; + break; + default: + str_vinyl_record = "vinyl_master"; + break; + } + level waittill( "gramophone_" + str_vinyl_record + "_picked_up" ); + self.has_vinyl = 1; +} + +get_gramophone_song() +{ + switch( self.script_int ) + { + case 1: + return "mus_gramophone_fire"; + case 2: + return "mus_gramophone_air"; + case 3: + return "mus_gramophone_electric"; + case 4: + return "mus_gramophone_ice"; + default: + return "mus_gramophone_electric"; + } + } + } + } + } + } +} + +run_gramophone_teleporter( str_vinyl_record ) +{ + self.has_vinyl = 0; + self.gramophone_model = undefined; + self thread watch_gramophone_vinyl_pickup(); + t_gramophone = tomb_spawn_trigger_radius( self.origin, 60, 1 ); + t_gramophone set_unitrigger_hint_string( &"ZOMBIE_BUILD_PIECE_MORE" ); + level waittill( "gramophone_vinyl_player_picked_up" ); + str_craftablename = "gramophone"; + t_gramophone set_unitrigger_hint_string( &"ZM_TOMB_RU" ); + while ( !self.has_vinyl ) + { + wait 0,05; + } + t_gramophone set_unitrigger_hint_string( &"ZM_TOMB_PLGR" ); + while ( 1 ) + { + t_gramophone waittill( "trigger", player ); + if ( !isDefined( self.gramophone_model ) ) + { + if ( !flag( "gramophone_placed" ) ) + { + self.gramophone_model = spawn( "script_model", self.origin ); + self.gramophone_model.angles = self.angles; + self.gramophone_model setmodel( "p6_zm_tm_gramophone" ); + level setclientfield( "piece_record_zm_player", 0 ); + flag_set( "gramophone_placed" ); + t_gramophone set_unitrigger_hint_string( "" ); + t_gramophone trigger_off(); + str_song_id = self get_gramophone_song(); + self.gramophone_model playsound( str_song_id ); + player thread maps/mp/zm_tomb_vo::play_gramophone_place_vo(); + maps/mp/zm_tomb_teleporter::stargate_teleport_enable( self.script_int ); + flag_wait( "teleporter_building_" + self.script_int ); + flag_waitopen( "teleporter_building_" + self.script_int ); + t_gramophone trigger_on(); + t_gramophone set_unitrigger_hint_string( &"ZM_TOMB_PUGR" ); + if ( isDefined( self.script_flag ) ) + { + flag_set( self.script_flag ); + } + } + else + { + player door_gramophone_elsewhere_hint(); + } + continue; + } + else + { + self.gramophone_model delete(); + self.gramophone_model = undefined; + player playsound( "zmb_craftable_pickup" ); + flag_clear( "gramophone_placed" ); + level setclientfield( "piece_record_zm_player", 1 ); + maps/mp/zm_tomb_teleporter::stargate_teleport_disable( self.script_int ); + t_gramophone set_unitrigger_hint_string( &"ZM_TOMB_PLGR" ); + } + } +} + +door_watch_open_sesame() +{ +/# + level waittill_any( "open_sesame", "open_all_gramophone_doors" ); + self.has_vinyl = 1; + level.b_open_all_gramophone_doors = 1; + wait 0,5; + if ( isDefined( self.trigger ) ) + { + self.trigger notify( "trigger" ); +#/ + } +} + +run_gramophone_door( str_vinyl_record ) +{ + flag_init( self.targetname + "_opened" ); + trig_position = getstruct( self.targetname + "_position", "targetname" ); + trig_position.has_vinyl = 0; + trig_position.gramophone_model = undefined; + trig_position thread watch_gramophone_vinyl_pickup(); + trig_position thread door_watch_open_sesame(); + t_door = tomb_spawn_trigger_radius( trig_position.origin, 60, 1 ); + t_door set_unitrigger_hint_string( &"ZOMBIE_BUILD_PIECE_MORE" ); + level waittill_any( "gramophone_vinyl_player_picked_up", "open_sesame", "open_all_gramophone_doors" ); + str_craftablename = "gramophone"; + t_door set_unitrigger_hint_string( &"ZM_TOMB_RU" ); + trig_position.trigger = t_door; + while ( !trig_position.has_vinyl ) + { + wait 0,05; + } + t_door set_unitrigger_hint_string( &"ZM_TOMB_PLGR" ); + while ( 1 ) + { + t_door waittill( "trigger", player ); + if ( !isDefined( trig_position.gramophone_model ) ) + { + if ( !flag( "gramophone_placed" ) || isDefined( level.b_open_all_gramophone_doors ) && level.b_open_all_gramophone_doors ) + { + if ( isDefined( level.b_open_all_gramophone_doors ) && !level.b_open_all_gramophone_doors ) + { + trig_position.gramophone_model = spawn( "script_model", trig_position.origin ); + trig_position.gramophone_model.angles = trig_position.angles; + trig_position.gramophone_model setmodel( "p6_zm_tm_gramophone" ); + flag_set( "gramophone_placed" ); + level setclientfield( "piece_record_zm_player", 0 ); + } + t_door trigger_off(); + str_song = trig_position get_gramophone_song(); + playsoundatposition( str_song, self.origin ); + self playsound( "zmb_crypt_stairs" ); + wait 6; + chamber_blocker(); + flag_set( self.targetname + "_opened" ); + if ( isDefined( trig_position.script_flag ) ) + { + flag_set( trig_position.script_flag ); + } + level setclientfield( "crypt_open_exploder", 1 ); + self movez( -260, 10, 1, 1 ); + self waittill( "movedone" ); + self connectpaths(); + self delete(); + t_door trigger_on(); + t_door set_unitrigger_hint_string( &"ZM_TOMB_PUGR" ); + if ( isDefined( level.b_open_all_gramophone_doors ) && level.b_open_all_gramophone_doors ) + { + break; + } + else + { + } + else player door_gramophone_elsewhere_hint(); + continue; + } + else + { + trig_position.gramophone_model delete(); + trig_position.gramophone_model = undefined; + flag_clear( "gramophone_placed" ); + player playsound( "zmb_craftable_pickup" ); + level setclientfield( "piece_record_zm_player", 1 ); + break; + } + } + } + t_door tomb_unitrigger_delete(); + trig_position.trigger = undefined; +} + +chamber_blocker() +{ + a_blockers = getentarray( "junk_nml_chamber", "targetname" ); + m_blocker = getent( "junk_nml_chamber", "targetname" ); + s_blocker_end = getstruct( m_blocker.script_linkto, "script_linkname" ); + m_blocker thread maps/mp/zombies/_zm_blockers::debris_move( s_blocker_end ); + m_blocker_clip = getent( "junk_nml_chamber_clip", "targetname" ); + m_blocker_clip connectpaths(); + m_blocker waittill( "movedone" ); + m_blocker_clip delete(); +} + +watch_for_staff_upgrades() +{ + _a561 = level.a_elemental_staffs; + _k561 = getFirstArrayKey( _a561 ); + while ( isDefined( _k561 ) ) + { + staff = _a561[ _k561 ]; + staff thread staff_upgrade_watch(); + _k561 = getNextArrayKey( _a561, _k561 ); + } +} + +staff_upgrade_watch() +{ + flag_wait( self.weapname + "_upgrade_unlocked" ); + self thread place_staff_in_charger(); +} + +staff_get_pickup_message() +{ + if ( self.element == "air" ) + { + return &"ZM_TOMB_PUAS"; + } + else + { + if ( self.element == "fire" ) + { + return &"ZM_TOMB_PUFS"; + } + else + { + if ( self.element == "lightning" ) + { + return &"ZM_TOMB_PULS"; + } + else + { + return &"ZM_TOMB_PUIS"; + } + } + } +} + +staff_get_insert_message() +{ + if ( self.element == "air" ) + { + return &"ZM_TOMB_INAS"; + } + else + { + if ( self.element == "fire" ) + { + return &"ZM_TOMB_INFS"; + } + else + { + if ( self.element == "lightning" ) + { + return &"ZM_TOMB_INLS"; + } + else + { + return &"ZM_TOMB_INWS"; + } + } + } +} + +player_has_staff() +{ + a_weapons = self getweaponslistprimaries(); + _a617 = a_weapons; + _k617 = getFirstArrayKey( _a617 ); + while ( isDefined( _k617 ) ) + { + weapon = _a617[ _k617 ]; + if ( issubstr( weapon, "staff" ) ) + { + return 1; + } + _k617 = getNextArrayKey( _a617, _k617 ); + } + return 0; +} + +can_pickup_staff() +{ + b_has_staff = self player_has_staff(); + b_staff_equipped = issubstr( self getcurrentweapon(), "staff" ); + if ( b_has_staff && !b_staff_equipped ) + { + self thread swap_staff_hint(); + } + if ( b_has_staff ) + { + return b_staff_equipped; + } +} + +watch_for_player_pickup_staff() +{ + staff_picked_up = 0; + pickup_message = self staff_get_pickup_message(); + self.trigger set_unitrigger_hint_string( pickup_message ); + self show(); + self.trigger trigger_on(); + while ( !staff_picked_up ) + { + self.trigger waittill( "trigger", player ); + self notify( "retrieved" ); + if ( player can_pickup_staff() ) + { + weapon_drop = player getcurrentweapon(); + a_weapons = player getweaponslistprimaries(); + n_max_other_weapons = get_player_weapon_limit( player ) - 1; + if ( a_weapons.size > n_max_other_weapons || issubstr( weapon_drop, "staff" ) ) + { + player takeweapon( weapon_drop ); + } + player thread watch_staff_ammo_reload(); + self ghost(); + self setinvisibletoall(); + player giveweapon( self.weapname ); + player switchtoweapon( self.weapname ); + clip_size = weaponclipsize( self.weapname ); + player setweaponammoclip( self.weapname, clip_size ); + self.owner = player; + level notify( "stop_staff_sound" ); + self notify( "staff_equip" ); + staff_picked_up = 1; + self.charger.is_inserted = 0; + self setclientfield( "staff_charger", 0 ); + self.charger.full = 1; + maps/mp/zm_tomb_craftables::set_player_staff( self.weapname, player ); + } + } +} + +watch_staff_ammo_reload() +{ + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "zmb_max_ammo" ); + a_weapons = self getweaponslistprimaries(); + _a715 = a_weapons; + _k715 = getFirstArrayKey( _a715 ); + while ( isDefined( _k715 ) ) + { + weapon = _a715[ _k715 ]; + if ( issubstr( weapon, "staff" ) ) + { + self setweaponammoclip( weapon, weaponmaxammo( weapon ) ); + } + _k715 = getNextArrayKey( _a715, _k715 ); + } + } +} + +rotate_forever( rotate_time ) +{ + if ( !isDefined( rotate_time ) ) + { + rotate_time = 20; + } + self endon( "death" ); + while ( 1 ) + { + self rotateyaw( 360, 20, 0, 0 ); + self waittill( "rotatedone" ); + } +} + +staff_crystal_wait_for_teleport( n_element_enum ) +{ + flag_init( "charger_ready_" + n_element_enum ); + self craftable_waittill_spawned(); + self.origin = self.piecespawn.model.origin; + self.piecespawn.model ghost(); + self.piecespawn.model movez( -1000, 0,05 ); + e_plinth = getent( "crystal_plinth" + n_element_enum, "targetname" ); + e_plinth.v_start = e_plinth.origin; + e_plinth.v_start = ( e_plinth.v_start[ 0 ], e_plinth.v_start[ 1 ], e_plinth.origin[ 2 ] - 78 ); + e_plinth.v_crystal = e_plinth.origin; + e_plinth.v_crystal = ( e_plinth.v_crystal[ 0 ], e_plinth.v_crystal[ 1 ], e_plinth.origin[ 2 ] - 40 ); + e_plinth.v_staff = e_plinth.origin; + e_plinth.v_staff = ( e_plinth.v_staff[ 0 ], e_plinth.v_staff[ 1 ], e_plinth.origin[ 2 ] + 15 ); + e_plinth moveto( e_plinth.v_start, 0,05 ); + while ( 1 ) + { + level waittill( "player_teleported", e_player, n_teleport_enum ); + if ( n_teleport_enum == n_element_enum ) + { + break; + } + else + { + } + } + e_plinth moveto( e_plinth.v_crystal, 6 ); + e_plinth thread sndmoveplinth( 6 ); + lookat_dot = cos( 90 ); + dist_sq = 250000; + lookat_time = 0; + while ( lookat_time < 1 && isDefined( self.piecespawn.model ) ) + { + wait 0,1; + if ( !isDefined( self.piecespawn.model ) ) + { + } + else if ( self.piecespawn.model any_player_looking_at_plinth( lookat_dot, dist_sq ) ) + { + lookat_time += 0,1; + continue; + } + else + { + lookat_time = 0; + } + } + if ( isDefined( self.piecespawn.model ) ) + { + self.piecespawn.model movez( 985, 0,05 ); + self.piecespawn.model waittill( "movedone" ); + self.piecespawn.model show(); + self.piecespawn.model thread rotate_forever(); + self.piecespawn.model movez( 15, 2 ); + self.piecespawn.model playloopsound( "zmb_squest_crystal_loop", 4,25 ); + } + flag_wait( "charger_ready_" + n_element_enum ); + while ( !maps/mp/zm_tomb_chamber::is_chamber_occupied() ) + { + wait_network_frame(); + } + e_plinth moveto( e_plinth.v_staff, 3 ); + e_plinth thread sndmoveplinth( 3 ); + e_plinth waittill( "movedone" ); +} + +sndmoveplinth( time ) +{ + self notify( "sndMovePlinth" ); + self endon( "sndMovePlinth" ); + self playloopsound( "zmb_chamber_plinth_move", 0,25 ); + wait time; + self stoploopsound( 0,1 ); + self playsound( "zmb_chamber_plinth_stop" ); +} + +staff_mechz_drop_pieces( s_piece ) +{ + s_piece craftable_waittill_spawned(); + s_piece.piecespawn.model ghost(); + i = 0; + while ( i < 1 ) + { + level waittill( "mechz_killed", origin ); + i++; + } + s_piece.piecespawn.canmove = 1; + maps/mp/zombies/_zm_unitrigger::reregister_unitrigger_as_dynamic( s_piece.piecespawn.unitrigger ); + origin = groundpos_ignore_water_new( origin + vectorScale( ( 0, 0, 1 ), 40 ) ); + s_piece.piecespawn.model moveto( origin + vectorScale( ( 0, 0, 1 ), 32 ), 0,05 ); + s_piece.piecespawn.model waittill( "movedone" ); + if ( isDefined( s_piece.piecespawn.model ) ) + { + s_piece.piecespawn.model show(); + s_piece.piecespawn.model notify( "staff_piece_glow" ); + s_piece.piecespawn.model thread mechz_staff_piece_failsafe(); + } +} + +mechz_staff_piece_failsafe() +{ + min_dist_sq = 1000000; + self endon( "death" ); + wait 120; + while ( 1 ) + { + a_players = getplayers(); + b_anyone_near = 0; + _a891 = a_players; + _k891 = getFirstArrayKey( _a891 ); + while ( isDefined( _k891 ) ) + { + e_player = _a891[ _k891 ]; + dist_sq = distance2dsquared( e_player.origin, self.origin ); + if ( dist_sq < min_dist_sq ) + { + b_anyone_near = 1; + } + _k891 = getNextArrayKey( _a891, _k891 ); + } + if ( !b_anyone_near ) + { + break; + } + else + { + wait 1; + } + } + a_locations = getstructarray( "mechz_location", "script_noteworthy" ); + s_location = get_closest_2d( self.origin, a_locations ); + self moveto( s_location.origin + vectorScale( ( 0, 0, 1 ), 32 ), 3 ); +} + +biplane_clue() +{ + self endon( "death" ); + level endon( "biplane_down" ); + while ( 1 ) + { + cur_round = level.round_number; + while ( level.round_number == cur_round ) + { + wait 1; + } + wait randomfloatrange( 5, 15 ); + a_players = getplayers(); + _a933 = a_players; + _k933 = getFirstArrayKey( _a933 ); + while ( isDefined( _k933 ) ) + { + e_player = _a933[ _k933 ]; + level notify( "sam_clue_biplane" ); + _k933 = getNextArrayKey( _a933, _k933 ); + } + } +} + +staff_biplane_drop_pieces( a_staff_pieces ) +{ + _a942 = a_staff_pieces; + _k942 = getFirstArrayKey( _a942 ); + while ( isDefined( _k942 ) ) + { + staff_piece = _a942[ _k942 ]; + staff_piece craftable_waittill_spawned(); + staff_piece.origin = staff_piece.piecespawn.model.origin; + staff_piece.piecespawn.model notify( "staff_piece_glow" ); + staff_piece.piecespawn.model ghost(); + staff_piece.piecespawn.model movez( -500, 0,05 ); + _k942 = getNextArrayKey( _a942, _k942 ); + } + flag_wait( "activate_zone_village_0" ); + cur_round = level.round_number; + while ( level.round_number == cur_round ) + { + wait 1; + } + s_biplane_pos = getstruct( "air_crystal_biplane_pos", "targetname" ); + vh_biplane = spawnvehicle( "veh_t6_dlc_zm_biplane", "air_crystal_biplane", "biplane_zm", s_biplane_pos.origin, s_biplane_pos.angles ); + vh_biplane ent_flag_init( "biplane_down", 0 ); + vh_biplane thread biplane_clue(); + e_fx_tag = getent( "air_crystal_biplane_tag", "targetname" ); + e_fx_tag moveto( vh_biplane.origin, 0,05 ); + e_fx_tag waittill( "movedone" ); + e_fx_tag linkto( vh_biplane, "tag_origin" ); + vh_biplane.health = 10000; + vh_biplane setcandamage( 1 ); + vh_biplane setforcenocull(); + vh_biplane attachpath( getvehiclenode( "biplane_start", "targetname" ) ); + vh_biplane startpath(); + s_biplane_pos structdelete(); + e_fx_tag setclientfield( "element_glow_fx", 1 ); + vh_biplane ent_flag_wait( "biplane_down" ); + vh_biplane playsound( "zmb_zombieblood_3rd_plane_explode" ); + _a992 = a_staff_pieces; + _k992 = getFirstArrayKey( _a992 ); + while ( isDefined( _k992 ) ) + { + staff_piece = _a992[ _k992 ]; + staff_piece.e_fx = spawn( "script_model", e_fx_tag.origin ); + staff_piece.e_fx setmodel( "tag_origin" ); + staff_piece.e_fx setclientfield( "element_glow_fx", 1 ); + staff_piece.e_fx moveto( staff_piece.origin, 5 ); + _k992 = getNextArrayKey( _a992, _k992 ); + } + playfx( level._effect[ "biplane_explode" ], vh_biplane.origin ); + vh_biplane delete(); + e_fx_tag delete(); + a_staff_pieces[ 0 ].e_fx waittill( "movedone" ); + _a1009 = a_staff_pieces; + _k1009 = getFirstArrayKey( _a1009 ); + while ( isDefined( _k1009 ) ) + { + staff_piece = _a1009[ _k1009 ]; + staff_piece.e_fx delete(); + staff_piece.piecespawn.model show(); + staff_piece.piecespawn.model movez( 500, 0,05 ); + staff_piece.piecespawn.model waittill( "movedone" ); + _k1009 = getNextArrayKey( _a1009, _k1009 ); + } +} + +aircrystalbiplanecallback_vehicledamage( e_inflictor, e_attacker, n_damage, n_dflags, str_means_of_death, str_weapon, v_point, v_dir, str_hit_loc, psoffsettime, b_damage_from_underneath, n_model_index, str_part_name ) +{ + if ( isplayer( e_attacker ) && self.vehicletype == "biplane_zm" && !self ent_flag( "biplane_down" ) ) + { + self ent_flag_set( "biplane_down" ); + level notify( "biplane_down" ); + } + return n_damage; +} + +zone_capture_clue( str_zone ) +{ + level endon( "staff_piece_capture_complete" ); + while ( 1 ) + { + wait 5; + while ( !level.zones[ str_zone ].is_occupied ) + { + wait 1; + } + a_players = getplayers(); + _a1044 = a_players; + _k1044 = getFirstArrayKey( _a1044 ); + while ( isDefined( _k1044 ) ) + { + e_player = _a1044[ _k1044 ]; + level notify( "sam_clue_zonecap" ); + _k1044 = getNextArrayKey( _a1044, _k1044 ); + } + } +} + +staff_unlock_with_zone_capture( s_staff_piece ) +{ + flag_wait( "start_zombie_round_logic" ); + s_staff_piece craftable_waittill_spawned(); + str_zone = maps/mp/zombies/_zm_zonemgr::get_zone_from_position( s_staff_piece.piecespawn.model.origin, 1 ); + if ( !isDefined( str_zone ) ) + { +/# + assertmsg( "Zone capture staff piece is not in a zone." ); +#/ + return; + } + level thread zone_capture_clue( str_zone ); + s_staff_piece.piecespawn.model ghost(); + while ( 1 ) + { + level waittill( "zone_captured_by_player", str_captured_zone ); + if ( str_captured_zone == str_zone ) + { + break; + } + else + { + } + } + level notify( "staff_piece_capture_complete" ); + _a1082 = level.a_uts_challenge_boxes; + _k1082 = getFirstArrayKey( _a1082 ); + while ( isDefined( _k1082 ) ) + { + uts_box = _a1082[ _k1082 ]; + if ( uts_box.str_location == "church_capture" ) + { + uts_box.s_staff_piece = s_staff_piece; + level thread maps/mp/zombies/_zm_challenges::open_box( undefined, uts_box, ::reward_staff_piece ); + return; + } + _k1082 = getNextArrayKey( _a1082, _k1082 ); + } +} + +reward_staff_piece( player, s_stat ) +{ + m_piece = spawn( "script_model", self.origin ); + m_piece.angles = self.angles + vectorScale( ( 0, 0, 1 ), 180 ); + m_piece setmodel( "t6_wpn_zmb_staff_tip_fire_world" ); + m_piece.origin = self.origin; + m_piece.angles = self.angles + vectorScale( ( 0, 0, 1 ), 90 ); + m_piece setclientfield( "element_glow_fx", 1 ); + wait_network_frame(); + if ( !reward_rise_and_grab( m_piece, 50, 2, 2, -1 ) ) + { + return 0; + } + n_dist = 9999; + a_players = getplayers(); + a_players = get_array_of_closest( self.m_box.origin, a_players ); + if ( isDefined( a_players[ 0 ] ) ) + { + a_players[ 0 ] maps/mp/zombies/_zm_craftables::player_take_piece( self.s_staff_piece.piecespawn ); + } + m_piece delete(); + return 1; +} + +dig_spot_get_staff_piece( e_player ) +{ + level notify( "sam_clue_dig" ); + str_zone = self.str_zone; + _a1142 = level.ice_staff_pieces; + _k1142 = getFirstArrayKey( _a1142 ); + while ( isDefined( _k1142 ) ) + { + s_staff = _a1142[ _k1142 ]; + if ( !isDefined( s_staff.num_misses ) ) + { + s_staff.num_misses = 0; + } + if ( issubstr( str_zone, s_staff.zone_substr ) ) + { + miss_chance = 100 / ( s_staff.num_misses + 1 ); + if ( level.weather_snow <= 0 ) + { + miss_chance = 101; + } + if ( randomint( 100 ) > miss_chance || s_staff.num_misses > 3 && miss_chance < 100 ) + { + return s_staff; + } + else + { + s_staff.num_misses++; + break; + } + } + else + { + _k1142 = getNextArrayKey( _a1142, _k1142 ); + } + } + return undefined; +} + +show_ice_staff_piece( origin ) +{ + arrayremovevalue( level.ice_staff_pieces, self ); + wait 0,5; + self.piecespawn.canmove = 1; + maps/mp/zombies/_zm_unitrigger::reregister_unitrigger_as_dynamic( self.piecespawn.unitrigger ); + vert_offset = 32; + self.piecespawn.model moveto( origin + ( 0, 0, vert_offset ), 0,05 ); + self.piecespawn.model waittill( "movedone" ); + self.piecespawn.model showindemo(); + self.piecespawn.model show(); + self.piecespawn.model notify( "staff_piece_glow" ); + self.piecespawn.model playsound( "evt_staff_digup" ); + self.piecespawn.model playloopsound( "evt_staff_digup_lp" ); +} + +staff_ice_dig_pieces( a_staff_pieces ) +{ + flag_wait( "start_zombie_round_logic" ); + level.ice_staff_pieces = arraycopy( a_staff_pieces ); + _a1199 = level.ice_staff_pieces; + _k1199 = getFirstArrayKey( _a1199 ); + while ( isDefined( _k1199 ) ) + { + s_piece = _a1199[ _k1199 ]; + s_piece craftable_waittill_spawned(); + s_piece.piecespawn.model ghost(); + _k1199 = getNextArrayKey( _a1199, _k1199 ); + } + level.ice_staff_pieces[ 0 ].zone_substr = "bunker"; + level.ice_staff_pieces[ 1 ].zone_substr = "nml"; + level.ice_staff_pieces[ 2 ].zone_substr = "village"; + level.ice_staff_pieces[ 2 ].num_misses = 2; +} + +crystal_play_glow_fx( s_crystal ) +{ + flag_wait( "start_zombie_round_logic" ); + switch( s_crystal.modelname ) + { + case "t6_wpn_zmb_staff_crystal_air_part": + watch_for_crystal_pickup( s_crystal, 2 ); + break; + case "t6_wpn_zmb_staff_crystal_fire_part": + watch_for_crystal_pickup( s_crystal, 1 ); + break; + case "t6_wpn_zmb_staff_crystal_bolt_part": + watch_for_crystal_pickup( s_crystal, 3 ); + break; + case "t6_wpn_zmb_staff_crystal_water_part": + watch_for_crystal_pickup( s_crystal, 4 ); + break; + } +} + +watch_for_crystal_pickup( s_crystal, n_enum ) +{ + s_crystal.piecespawn.model setclientfield( "element_glow_fx", n_enum ); + s_crystal.piecespawn waittill( "pickup" ); + self playsound( "evt_crystal" ); + level.n_crystals_pickedup++; +} + +crystal_dropped( s_crystal ) +{ + flag_wait( "start_zombie_round_logic" ); + s_crystal.piecespawn waittill( "piece_released" ); + level.n_crystals_pickedup--; + + level thread crystal_play_glow_fx( s_crystal ); +} + +staff_charger_get_player_msg( e_player ) +{ + weapon_available = 1; + charge_ready = 0; + if ( self.stub.staff_data.charger.is_inserted ) + { + if ( self.stub.staff_data.charger.is_charged ) + { + charge_ready = 1; + } + } + if ( e_player hasweapon( self.stub.staff_data.weapname ) ) + { + msg = self.stub.staff_data staff_get_insert_message(); + return msg; + } + else + { + if ( charge_ready ) + { + msg = self.stub.staff_data staff_get_pickup_message(); + return msg; + } + else + { + return ""; + } + } +} + +place_staff_in_charger() +{ + flag_set( "charger_ready_" + self.enum ); + v_trigger_pos = self.charger.origin; + v_trigger_pos = ( v_trigger_pos[ 0 ], v_trigger_pos[ 1 ], v_trigger_pos[ 2 ] - 30 ); + if ( isDefined( self.charge_trigger ) ) + { + self.charge_trigger tomb_unitrigger_delete(); + } + self.charge_trigger = tomb_spawn_trigger_radius( v_trigger_pos, 120, 1, ::staff_charger_get_player_msg ); + self.charge_trigger.require_look_at = 1; + self.charge_trigger.staff_data = self; + waittill_staff_inserted(); +} + +debug_staff_charge() +{ +/# + if ( !isDefined( self.charger.charges_received ) ) + { + self.charger.charges_received = 0; + } + while ( self.charger.is_inserted ) + { + if ( self.charger.is_charged ) + { + maxammo = weaponmaxammo( self.weapname ); + if ( !isDefined( self.prev_ammo_stock ) ) + { + self.prev_ammo_stock = maxammo; + } + print3d( self.origin, ( self.prev_ammo_stock + "/" ) + maxammo, vectorScale( ( 0, 0, 1 ), 255 ), 1 ); + } + else + { + print3d( self.origin, ( self.charger.charges_received + "/" ) + 20, vectorScale( ( 0, 0, 1 ), 255 ), 1 ); + } + wait 0,05; +#/ + } +} + +waittill_staff_inserted() +{ + while ( 1 ) + { + self.charge_trigger waittill( "trigger", player ); + weapon_available = 1; + if ( isDefined( player ) ) + { + weapon_available = player hasweapon( self.weapname ); + if ( weapon_available ) + { + player takeweapon( self.weapname ); + } + } + if ( weapon_available ) + { + self.charger.is_inserted = 1; + self thread debug_staff_charge(); + maps/mp/zm_tomb_craftables::clear_player_staff( self.weapname ); + self.charge_trigger trigger_off(); + if ( isDefined( self.charger.angles ) ) + { + self.angles = self.charger.angles; + } + self moveto( self.charger.origin, 0,05 ); + self waittill( "movedone" ); + self setclientfield( "staff_charger", self.enum ); + self.charger.full = 0; + self show(); + self playsound( "zmb_squest_charge_place_staff" ); + return; + } + } +} + +zombie_spawn_func() +{ + self.actor_killed_override = ::zombie_killed_override; +} + +zombie_killed_override( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime ) +{ + if ( flag( "ee_sam_portal_active" ) && !flag( "ee_souls_absorbed" ) ) + { + maps/mp/zm_tomb_ee_main_step_7::ee_zombie_killed_override( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime ); + return; + } + if ( maps/mp/zm_tomb_challenges::footprint_zombie_killed( attacker ) ) + { + return; + } + n_max_dist_sq = 9000000; + if ( isplayer( attacker ) || sweapon == "one_inch_punch_zm" ) + { + if ( !flag( "fire_puzzle_1_complete" ) ) + { + maps/mp/zm_tomb_quest_fire::sacrifice_puzzle_zombie_killed( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime ); + } + s_nearest_staff = undefined; + n_nearest_dist_sq = n_max_dist_sq; + _a1434 = level.a_elemental_staffs; + _k1434 = getFirstArrayKey( _a1434 ); + while ( isDefined( _k1434 ) ) + { + staff = _a1434[ _k1434 ]; + if ( isDefined( staff.charger.full ) && staff.charger.full ) + { + } + else + { + if ( staff.charger.is_inserted || staff.upgrade.charger.is_inserted ) + { + if ( isDefined( staff.charger.is_charged ) && !staff.charger.is_charged ) + { + dist_sq = distance2dsquared( self.origin, staff.origin ); + if ( dist_sq <= n_nearest_dist_sq ) + { + n_nearest_dist_sq = dist_sq; + s_nearest_staff = staff; + } + } + } + } + _k1434 = getNextArrayKey( _a1434, _k1434 ); + } + if ( isDefined( s_nearest_staff ) ) + { + if ( s_nearest_staff.charger.is_charged ) + { + return; + } + else + { + s_nearest_staff.charger.charges_received++; + s_nearest_staff.charger thread zombie_soul_to_charger( self, s_nearest_staff.enum ); + } + } + } +} + +zombie_soul_to_charger( ai_zombie, n_element ) +{ + ai_zombie setclientfield( "zombie_soul", 1 ); + wait 1,5; + self notify( "soul_received" ); +} + +staff_charger_check() +{ + self.charger.is_charged = 0; + flag_wait( self.weapname + "_upgrade_unlocked" ); + self useweaponmodel( self.weapname ); + self showallparts(); + while ( 1 ) + { + if ( self.charger.charges_received >= 20 || getDvarInt( "zombie_cheat" ) >= 2 && self.charger.is_inserted ) + { + wait 0,5; + self.charger.is_charged = 1; + e_player = get_closest_player( self.charger.origin ); + e_player thread maps/mp/zm_tomb_vo::say_puzzle_completion_line( self.enum ); + self setclientfield( "staff_charger", 0 ); + self.charger.full = 1; + level setclientfield( self.quest_clientfield, 4 ); + level thread spawn_upgraded_staff_triggers( self.enum ); + level.staffs_charged++; + if ( level.staffs_charged == 4 ) + { + flag_set( "ee_all_staffs_upgraded" ); + } + self thread staff_sound(); + return; + } + else + { + wait 1; + } + } +} + +staff_sound() +{ + self thread sndstaffupgradedstinger(); + self playsound( "zmb_squest_charge_soul_full" ); + self playloopsound( "zmb_squest_charge_soul_full_loop", 0,1 ); + level waittill( "stop_staff_sound" ); + self stoploopsound( 0,1 ); +} + +sndstaffupgradedstinger() +{ + if ( level.staffs_charged == 4 ) + { + level thread maps/mp/zm_tomb_amb::sndplaystingerwithoverride( "mus_event_staff_all_upgraded", 55 ); + return; + } + if ( self.weapname == "staff_air_zm" ) + { + level thread maps/mp/zombies/_zm_audio::sndmusicstingerevent( "staff_wind_upgraded" ); + } + if ( self.weapname == "staff_fire_zm" ) + { + level thread maps/mp/zombies/_zm_audio::sndmusicstingerevent( "staff_fire_upgraded" ); + } + if ( self.weapname == "staff_lightning_zm" ) + { + level thread maps/mp/zombies/_zm_audio::sndmusicstingerevent( "staff_lightning_upgraded" ); + } + if ( self.weapname == "staff_water_zm" ) + { + level thread maps/mp/zombies/_zm_audio::sndmusicstingerevent( "staff_ice_upgraded" ); + } +} + +spawn_upgraded_staff_triggers( n_index ) +{ + e_staff_standard = get_staff_info_from_element_index( n_index ); + e_staff_standard_upgraded = e_staff_standard.upgrade; + e_staff_standard.charge_trigger trigger_on(); + e_staff_standard.charge_trigger.require_look_at = 1; + pickup_message = e_staff_standard staff_get_pickup_message(); + e_staff_standard.charge_trigger set_unitrigger_hint_string( pickup_message ); + e_staff_standard ghost(); + e_staff_standard_upgraded.trigger = e_staff_standard.charge_trigger; + e_staff_standard_upgraded.angles = e_staff_standard.angles; + e_staff_standard_upgraded moveto( e_staff_standard.origin, 0,05 ); + e_staff_standard_upgraded waittill( "movedone" ); + e_staff_standard_upgraded show(); + e_fx = spawn( "script_model", e_staff_standard_upgraded.origin + vectorScale( ( 0, 0, 1 ), 8 ) ); + e_fx setmodel( "tag_origin" ); + wait 0,6; + e_fx setclientfield( "element_glow_fx", e_staff_standard.enum ); + e_staff_standard_upgraded watch_for_player_pickup_staff(); + e_staff_standard_upgraded.trigger trigger_off(); + player = e_staff_standard_upgraded.owner; + e_fx delete(); + while ( 1 ) + { + if ( e_staff_standard.charger.is_charged ) + { + e_staff_standard_upgraded thread staff_upgraded_reload_monitor(); + return; + } + else + { + wait_network_frame(); + } + } +} + +staff_upgraded_reload_monitor() +{ + self.weaponname = self.weapname; + self thread track_staff_weapon_respawn( self.owner ); + while ( 1 ) + { + place_staff_in_charger(); + self thread staff_upgraded_reload(); + self watch_for_player_pickup_staff(); + self.trigger trigger_off(); + self.charger.is_inserted = 0; + maxammo = weaponmaxammo( self.weapname ); + n_ammo = int( min( maxammo, self.prev_ammo_stock ) ); + if ( isDefined( self.owner ) ) + { + self.owner setweaponammostock( self.weapname, n_ammo ); + self.owner setweaponammoclip( self.weapname, self.prev_ammo_clip ); + self thread track_staff_weapon_respawn( self.owner ); + } + } +} + +staff_upgraded_reload() +{ + self endon( "staff_equip" ); + max_ammo = weaponmaxammo( self.weapname ); + n_count = int( max_ammo / 20 ); + b_reloaded = 0; + while ( 1 ) + { + self.charger waittill( "soul_received" ); + self.prev_ammo_stock += n_count; + if ( self.prev_ammo_stock > max_ammo ) + { + self.prev_ammo_stock = max_ammo; + self setclientfield( "staff_charger", 0 ); + self.charger.full = 1; + } + if ( !b_reloaded ) + { + self.trigger trigger_on(); + b_reloaded = 1; + } + } +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_quest_air.gsc b/zm_tomb_patch/maps/mp/zm_tomb_quest_air.gsc new file mode 100644 index 0000000..d1c39b4 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_quest_air.gsc @@ -0,0 +1,283 @@ +#include maps/mp/zm_tomb_vo; +#include maps/mp/zombies/_zm_net; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_sidequests; +#include maps/mp/zombies/_zm_craftables; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +main() +{ + flag_init( "air_puzzle_1_complete" ); + flag_init( "air_puzzle_2_complete" ); + flag_init( "air_upgrade_available" ); + air_puzzle_1_init(); + air_puzzle_2_init(); + maps/mp/zm_tomb_vo::add_puzzle_completion_line( 2, "vox_sam_wind_puz_solve_1" ); + maps/mp/zm_tomb_vo::add_puzzle_completion_line( 2, "vox_sam_wind_puz_solve_0" ); + maps/mp/zm_tomb_vo::add_puzzle_completion_line( 2, "vox_sam_wind_puz_solve_2" ); + level thread maps/mp/zm_tomb_vo::watch_one_shot_line( "puzzle", "try_puzzle", "vo_try_puzzle_air1" ); + level thread maps/mp/zm_tomb_vo::watch_one_shot_line( "puzzle", "try_puzzle", "vo_try_puzzle_air2" ); + level thread air_puzzle_1_run(); + flag_wait( "air_puzzle_1_complete" ); + playsoundatposition( "zmb_squest_step1_finished", ( 0, 0, 0 ) ); + level thread air_puzzle_1_cleanup(); + level thread rumble_players_in_chamber( 5, 3 ); + level thread air_puzzle_2_run(); +} + +air_puzzle_1_init() +{ + level.a_ceiling_rings = getentarray( "ceiling_ring", "script_noteworthy" ); + _a56 = level.a_ceiling_rings; + _k56 = getFirstArrayKey( _a56 ); + while ( isDefined( _k56 ) ) + { + e_ring = _a56[ _k56 ]; + e_ring ceiling_ring_init(); + _k56 = getNextArrayKey( _a56, _k56 ); + } +} + +air_puzzle_1_cleanup() +{ + i = 1; + while ( i <= 3 ) + { + n_move = ( 4 - i ) * 20; + e_ring = getent( "ceiling_ring_0" + i, "targetname" ); + e_ring rotateyaw( 360, 1,5, 0,5, 0 ); + e_ring movez( n_move, 1,5, 0,5, 0 ); + e_ring waittill( "movedone" ); + i++; + } + playsoundatposition( "zmb_squest_wind_ring_disappear", level.a_ceiling_rings[ 0 ].origin ); +} + +air_puzzle_1_run() +{ + array_thread( level.a_ceiling_rings, ::ceiling_ring_run ); +} + +check_puzzle_solved() +{ + num_solved = 0; + _a85 = level.a_ceiling_rings; + _k85 = getFirstArrayKey( _a85 ); + while ( isDefined( _k85 ) ) + { + e_ring = _a85[ _k85 ]; + if ( e_ring.script_int != e_ring.position ) + { + return 0; + } + _k85 = getNextArrayKey( _a85, _k85 ); + } + return 1; +} + +ceiling_ring_randomize() +{ + n_offset_from_final = randomintrange( 1, 4 ); + self.position = ( self.script_int + n_offset_from_final ) % 4; + ceiling_ring_update_position(); +/# + assert( self.position != self.script_int ); +#/ +} + +ceiling_ring_update_position() +{ + new_angles = ( self.angles[ 0 ], self.position * 90, self.angles[ 2 ] ); + self rotateto( new_angles, 0,5, 0,2, 0,2 ); + self playsound( "zmb_squest_wind_ring_turn" ); + self waittill( "rotatedone" ); +} + +ceiling_ring_rotate() +{ + self.position = ( self.position + 1 ) % 4; +/# + if ( self.position == self.script_int ) + { + iprintlnbold( "Ring is in place." ); +#/ + } + self ceiling_ring_update_position(); + solved = check_puzzle_solved(); + if ( solved && !flag( "air_puzzle_1_complete" ) ) + { + self thread maps/mp/zm_tomb_vo::say_puzzle_completion_line( 2 ); + flag_set( "air_puzzle_1_complete" ); + } +} + +ceiling_ring_init() +{ + self.position = 0; +} + +ceiling_ring_run() +{ + level endon( "air_puzzle_1_complete" ); + self setcandamage( 1 ); + self.position = 0; + ceiling_ring_randomize(); + n_rotations = 0; + while ( 1 ) + { + self waittill( "damage", damage, attacker, direction_vec, point, mod, tagname, modelname, partname, weaponname ); + if ( weaponname == "staff_air_zm" ) + { + level notify( "vo_try_puzzle_air1" ); + self ceiling_ring_rotate(); + rumble_nearby_players( self.origin, 1500, 2 ); + n_rotations++; + if ( ( n_rotations % 4 ) == 0 ) + { + level notify( "vo_puzzle_bad" ); + } + continue; + } + else + { + level notify( "vo_puzzle_confused" ); + } + } +} + +air_puzzle_2_init() +{ + a_smoke_pos = getstructarray( "puzzle_smoke_origin", "targetname" ); + _a179 = a_smoke_pos; + _k179 = getFirstArrayKey( _a179 ); + while ( isDefined( _k179 ) ) + { + s_smoke_pos = _a179[ _k179 ]; + s_smoke_pos.detector_brush = getent( s_smoke_pos.target, "targetname" ); + s_smoke_pos.detector_brush ghost(); + _k179 = getNextArrayKey( _a179, _k179 ); + } +} + +air_puzzle_2_run() +{ + a_smoke_pos = getstructarray( "puzzle_smoke_origin", "targetname" ); + _a190 = a_smoke_pos; + _k190 = getFirstArrayKey( _a190 ); + while ( isDefined( _k190 ) ) + { + s_smoke_pos = _a190[ _k190 ]; + s_smoke_pos thread air_puzzle_smoke(); + _k190 = getNextArrayKey( _a190, _k190 ); + } + while ( 1 ) + { + level waittill( "air_puzzle_smoke_solved" ); + all_smoke_solved = 1; + _a200 = a_smoke_pos; + _k200 = getFirstArrayKey( _a200 ); + while ( isDefined( _k200 ) ) + { + s_smoke_pos = _a200[ _k200 ]; + if ( !s_smoke_pos.solved ) + { + all_smoke_solved = 0; + } + _k200 = getNextArrayKey( _a200, _k200 ); + } + if ( all_smoke_solved ) + { + a_players = getplayers(); + _a211 = a_players; + _k211 = getFirstArrayKey( _a211 ); + while ( isDefined( _k211 ) ) + { + e_player = _a211[ _k211 ]; + if ( e_player hasweapon( "staff_air_zm" ) ) + { + e_player thread maps/mp/zm_tomb_vo::say_puzzle_completion_line( 2 ); + break; + } + else + { + _k211 = getNextArrayKey( _a211, _k211 ); + } + } + flag_set( "air_puzzle_2_complete" ); + level thread play_puzzle_stinger_on_all_players(); + return; + } + else + { + } + } +} + +air_puzzle_smoke() +{ + self.e_fx = spawn( "script_model", self.origin ); + self.e_fx.angles = self.angles; + self.e_fx setmodel( "tag_origin" ); + self.e_fx playloopsound( "zmb_squest_wind_incense_loop", 2 ); + s_dest = getstruct( "puzzle_smoke_dest", "targetname" ); + playfxontag( level._effect[ "air_puzzle_smoke" ], self.e_fx, "tag_origin" ); + self thread air_puzzle_run_smoke_direction(); + flag_wait( "air_puzzle_2_complete" ); + self.e_fx movez( -1000, 1, 0,1, 0,1 ); + self.e_fx waittill( "movedone" ); + wait 5; + self.e_fx delete(); + self.detector_brush delete(); +} + +air_puzzle_run_smoke_direction() +{ + level endon( "air_puzzle_2_complete" ); + self endon( "death" ); + s_dest = getstruct( "puzzle_smoke_dest", "targetname" ); + v_to_dest = vectornormalize( s_dest.origin - self.origin ); + f_min_dot = cos( self.script_int ); + self.solved = 0; + self.detector_brush setcandamage( 1 ); + direction_failures = 0; + while ( 1 ) + { + self.detector_brush waittill( "damage", damage, attacker, direction_vec, point, mod, tagname, modelname, partname, weaponname ); + if ( weaponname == "staff_air_zm" ) + { + level notify( "vo_try_puzzle_air2" ); + new_yaw = vectoangles( direction_vec ); + new_orient = ( 0, new_yaw, 0 ); + self.e_fx rotateto( new_orient, 1, 0,3, 0,3 ); + self.e_fx waittill( "rotatedone" ); + f_dot = vectordot( v_to_dest, direction_vec ); + self.solved = f_dot > f_min_dot; + if ( !self.solved ) + { + direction_failures++; + if ( direction_failures > 4 ) + { + level notify( "vo_puzzle_confused" ); + } + } + else + { + if ( randomint( 100 ) < 10 ) + { + level notify( "vo_puzzle_good" ); + } + } + level notify( "air_puzzle_smoke_solved" ); + continue; + } + else + { + if ( issubstr( weaponname, "staff" ) ) + { + level notify( "vo_puzzle_bad" ); + } + } + } +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_quest_crypt.gsc b/zm_tomb_patch/maps/mp/zm_tomb_quest_crypt.gsc new file mode 100644 index 0000000..f93b64e --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_quest_crypt.gsc @@ -0,0 +1,377 @@ +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zm_tomb_vo; +#include maps/mp/zombies/_zm_net; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_sidequests; +#include maps/mp/zombies/_zm_craftables; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +#using_animtree( "fxanim_props_dlc4" ); + +main() +{ + precachemodel( "p6_power_lever" ); + onplayerconnect_callback( ::on_player_connect_crypt ); + flag_init( "staff_air_zm_upgrade_unlocked" ); + flag_init( "staff_water_zm_upgrade_unlocked" ); + flag_init( "staff_fire_zm_upgrade_unlocked" ); + flag_init( "staff_lightning_zm_upgrade_unlocked" ); + flag_init( "disc_rotation_active" ); + level thread maps/mp/zm_tomb_vo::watch_one_shot_line( "puzzle", "try_puzzle", "vo_try_puzzle_crypt" ); + init_crypt_gems(); + chamber_disc_puzzle_init(); +} + +on_player_connect_crypt() +{ + discs = getentarray( "crypt_puzzle_disc", "script_noteworthy" ); + _a42 = discs; + _k42 = getFirstArrayKey( _a42 ); + while ( isDefined( _k42 ) ) + { + disc = _a42[ _k42 ]; + disc delay_thread( 0,5, ::bryce_cake_light_update, 0 ); + _k42 = getNextArrayKey( _a42, _k42 ); + } +} + +chamber_disc_puzzle_init() +{ + level.gem_start_pos = []; + level.gem_start_pos[ "crypt_gem_fire" ] = 2; + level.gem_start_pos[ "crypt_gem_air" ] = 3; + level.gem_start_pos[ "crypt_gem_ice" ] = 0; + level.gem_start_pos[ "crypt_gem_elec" ] = 1; + chamber_discs = getentarray( "crypt_puzzle_disc", "script_noteworthy" ); + array_thread( chamber_discs, ::chamber_disc_run ); + flag_wait( "chamber_entrance_opened" ); + chamber_discs_randomize(); +} + +chamber_disc_run() +{ + flag_wait( "start_zombie_round_logic" ); + self.position = 0; + self bryce_cake_light_update( 0 ); + if ( isDefined( self.target ) ) + { + a_levers = getentarray( self.target, "targetname" ); + _a77 = a_levers; + _k77 = getFirstArrayKey( _a77 ); + while ( isDefined( _k77 ) ) + { + e_lever = _a77[ _k77 ]; + e_lever.trigger_stub = tomb_spawn_trigger_radius( e_lever.origin, 100, 1 ); + e_lever.trigger_stub.require_look_at = 0; + if ( !isDefined( e_lever.script_string ) && isDefined( "clockwise" ) ) + { + if ( isDefined( e_lever.script_string ) && isDefined( "clockwise" ) ) + { + clockwise = e_lever.script_string == "clockwise"; + } + } + e_lever.trigger_stub thread chamber_disc_trigger_run( self, e_lever, clockwise ); + _k77 = getNextArrayKey( _a77, _k77 ); + } + self thread chamber_disc_move_to_position(); + } + self useanimtree( -1 ); + n_wait = randomfloatrange( 0, 5 ); + wait n_wait; + self setanim( %fxanim_zom_tomb_chamber_piece_anim ); +} + +init_crypt_gems() +{ + disc = getent( "crypt_puzzle_disc_main", "targetname" ); + gems = getentarray( "crypt_gem", "script_noteworthy" ); + _a101 = gems; + _k101 = getFirstArrayKey( _a101 ); + while ( isDefined( _k101 ) ) + { + gem = _a101[ _k101 ]; + gem linkto( disc ); + gem thread run_crypt_gem_pos(); + _k101 = getNextArrayKey( _a101, _k101 ); + } +} + +light_discs_bottom_to_top() +{ + discs = getentarray( "crypt_puzzle_disc", "script_noteworthy" ); + i = 1; + while ( i <= 4 ) + { + _a113 = discs; + _k113 = getFirstArrayKey( _a113 ); + while ( isDefined( _k113 ) ) + { + disc = _a113[ _k113 ]; + if ( !isDefined( disc.script_int ) || !isDefined( i ) && isDefined( disc.script_int ) && isDefined( i ) && disc.script_int == i ) + { + disc bryce_cake_light_update( 1 ); + break; + } + else + { + _k113 = getNextArrayKey( _a113, _k113 ); + } + } + wait 1; + i++; + } +} + +run_crypt_gem_pos() +{ + str_weapon = undefined; + complete_flag = undefined; + str_orb_path = undefined; + str_glow_fx = undefined; + n_element = self.script_int; + switch( self.targetname ) + { + case "crypt_gem_air": + str_weapon = "staff_air_zm"; + complete_flag = "staff_air_zm_upgrade_unlocked"; + str_orb_path = "air_orb_exit_path"; + str_final_pos = "air_orb_plinth_final"; + break; + case "crypt_gem_ice": + str_weapon = "staff_water_zm"; + complete_flag = "staff_water_zm_upgrade_unlocked"; + str_orb_path = "ice_orb_exit_path"; + str_final_pos = "ice_orb_plinth_final"; + break; + case "crypt_gem_fire": + str_weapon = "staff_fire_zm"; + complete_flag = "staff_fire_zm_upgrade_unlocked"; + str_orb_path = "fire_orb_exit_path"; + str_final_pos = "fire_orb_plinth_final"; + break; + case "crypt_gem_elec": + str_weapon = "staff_lightning_zm"; + complete_flag = "staff_lightning_zm_upgrade_unlocked"; + str_orb_path = "lightning_orb_exit_path"; + str_final_pos = "lightning_orb_plinth_final"; + break; + default: +/# + assertmsg( "Unknown crypt gem targetname: " + self.targetname ); +#/ + return; + } + e_gem_model = puzzle_orb_chamber_to_crypt( str_orb_path, self ); + e_main_disc = getent( "crypt_puzzle_disc_main", "targetname" ); + e_gem_model linkto( e_main_disc ); + str_targetname = self.targetname; + self delete(); + e_gem_model setcandamage( 1 ); + while ( 1 ) + { + e_gem_model waittill( "damage", damage, attacker, direction_vec, point, mod, tagname, modelname, partname, weaponname ); + if ( weaponname == str_weapon ) + { + break; + } + else + { + } + } + e_gem_model setclientfield( "element_glow_fx", n_element ); + e_gem_model playsound( "zmb_squest_crystal_charge" ); + e_gem_model playloopsound( "zmb_squest_crystal_charge_loop", 2 ); + while ( 1 ) + { + if ( chamber_disc_gem_has_clearance( str_targetname ) ) + { + break; + } + else level waittill( "crypt_disc_rotation" ); + } + flag_set( "disc_rotation_active" ); + level thread maps/mp/zombies/_zm_audio::sndmusicstingerevent( "side_sting_5" ); + light_discs_bottom_to_top(); + level thread puzzle_orb_pillar_show(); + e_gem_model unlink(); + s_ascent = getstruct( "orb_crypt_ascent_path", "targetname" ); + v_next_pos = ( e_gem_model.origin[ 0 ], e_gem_model.origin[ 1 ], s_ascent.origin[ 2 ] ); + e_gem_model setclientfield( "element_glow_fx", n_element ); + playfxontag( level._effect[ "puzzle_orb_trail" ], e_gem_model, "tag_origin" ); + e_gem_model playsound( "zmb_squest_crystal_leave" ); + e_gem_model puzzle_orb_move( v_next_pos ); + flag_clear( "disc_rotation_active" ); + level thread chamber_discs_randomize(); + e_gem_model puzzle_orb_follow_path( s_ascent ); + v_next_pos = ( e_gem_model.origin[ 0 ], e_gem_model.origin[ 1 ], e_gem_model.origin[ 2 ] + 2000 ); + e_gem_model puzzle_orb_move( v_next_pos ); + s_chamber_path = getstruct( str_orb_path, "targetname" ); + str_model = e_gem_model.model; + e_gem_model delete(); + e_gem_model = puzzle_orb_follow_return_path( s_chamber_path, n_element ); + s_final = getstruct( str_final_pos, "targetname" ); + e_gem_model puzzle_orb_move( s_final.origin ); + e_new_gem = spawn( "script_model", s_final.origin ); + e_new_gem setmodel( e_gem_model.model ); + e_new_gem.script_int = n_element; + e_new_gem setclientfield( "element_glow_fx", n_element ); + e_gem_model delete(); + e_new_gem playsound( "zmb_squest_crystal_arrive" ); + e_new_gem playloopsound( "zmb_squest_crystal_charge_loop", 0,1 ); + flag_set( complete_flag ); +} + +chamber_disc_move_to_position() +{ + new_angles = ( self.angles[ 0 ], self.position * 90, self.angles[ 2 ] ); + self rotateto( new_angles, 1, 0, 0 ); + self playsound( "zmb_crypt_disc_turn" ); + wait ( 1 * 0,75 ); + self bryce_cake_light_update( 0 ); + wait ( 1 * 0,25 ); + self bryce_cake_light_update( 0 ); + self playsound( "zmb_crypt_disc_stop" ); + rumble_nearby_players( self.origin, 1000, 2 ); +} + +chamber_discs_move_all_to_position( discs ) +{ + if ( !isDefined( discs ) ) + { + discs = undefined; + } + flag_set( "disc_rotation_active" ); + if ( !isDefined( discs ) ) + { + discs = getentarray( "chamber_puzzle_disc", "script_noteworthy" ); + } + _a285 = discs; + _k285 = getFirstArrayKey( _a285 ); + while ( isDefined( _k285 ) ) + { + e_disc = _a285[ _k285 ]; + e_disc chamber_disc_move_to_position(); + _k285 = getNextArrayKey( _a285, _k285 ); + } + flag_clear( "disc_rotation_active" ); +} + +chamber_disc_get_gem_position( gem_name ) +{ + disc = getent( "crypt_puzzle_disc_main", "targetname" ); + return ( disc.position + level.gem_start_pos[ gem_name ] ) % 4; +} + +chamber_disc_gem_has_clearance( gem_name ) +{ + gem_position = chamber_disc_get_gem_position( gem_name ); + discs = getentarray( "crypt_puzzle_disc", "script_noteworthy" ); + _a303 = discs; + _k303 = getFirstArrayKey( _a303 ); + while ( isDefined( _k303 ) ) + { + disc = _a303[ _k303 ]; + if ( !isDefined( disc.targetname ) || !isDefined( "crypt_puzzle_disc_main" ) && isDefined( disc.targetname ) && isDefined( "crypt_puzzle_disc_main" ) && disc.targetname == "crypt_puzzle_disc_main" ) + { + } + else + { + if ( disc.position != gem_position ) + { + return 0; + } + } + _k303 = getNextArrayKey( _a303, _k303 ); + } + return 1; +} + +chamber_disc_rotate( b_clockwise ) +{ + if ( b_clockwise ) + { + self.position = ( self.position + 1 ) % 4; + } + else + { + self.position = ( self.position + 3 ) % 4; + } + self chamber_disc_move_to_position(); +} + +bryce_cake_light_update( b_on ) +{ + if ( !isDefined( b_on ) ) + { + b_on = 1; + } + if ( !isDefined( self.n_bryce_cake ) ) + { + self.n_bryce_cake = 0; + } + if ( !b_on ) + { + self.n_bryce_cake = ( self.n_bryce_cake + 1 ) % 2; + } + else + { + self.n_bryce_cake = 2; + } + self setclientfield( "bryce_cake", self.n_bryce_cake ); +} + +chamber_discs_randomize() +{ + discs = getentarray( "crypt_puzzle_disc", "script_noteworthy" ); + prev_disc_pos = 0; + _a345 = discs; + _k345 = getFirstArrayKey( _a345 ); + while ( isDefined( _k345 ) ) + { + disc = _a345[ _k345 ]; + if ( !isDefined( disc.target ) ) + { + } + else + { + disc.position = ( prev_disc_pos + randomintrange( 1, 3 ) ) % 4; + prev_disc_pos = disc.position; + } + _k345 = getNextArrayKey( _a345, _k345 ); + } + chamber_discs_move_all_to_position( discs ); +} + +chamber_disc_switch_spark() +{ + self setclientfield( "switch_spark", 1 ); + wait 0,5; + self setclientfield( "switch_spark", 0 ); +} + +chamber_disc_trigger_run( e_disc, e_lever, b_clockwise ) +{ + discs_to_rotate = array( e_disc ); + e_lever useanimtree( -1 ); + n_anim_time = getanimlength( %fxanim_zom_tomb_puzzle_lever_switch_anim ); + while ( 1 ) + { + self waittill( "trigger", e_triggerer ); + if ( !flag( "disc_rotation_active" ) ) + { + flag_set( "disc_rotation_active" ); + e_lever setanim( %fxanim_zom_tomb_puzzle_lever_switch_anim, 1, 0, 1 ); + e_lever playsound( "zmb_crypt_lever" ); + wait ( n_anim_time * 0,5 ); + e_lever thread chamber_disc_switch_spark(); + array_thread( discs_to_rotate, ::chamber_disc_rotate, b_clockwise ); + wait 1; + e_lever clearanim( %fxanim_zom_tomb_puzzle_lever_switch_anim, 0 ); + flag_clear( "disc_rotation_active" ); + level notify( "vo_try_puzzle_crypt" ); + } + level notify( "crypt_disc_rotation" ); + } +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_quest_elec.gsc b/zm_tomb_patch/maps/mp/zm_tomb_quest_elec.gsc new file mode 100644 index 0000000..58315eb --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_quest_elec.gsc @@ -0,0 +1,476 @@ +#include maps/mp/zombies/_zm_unitrigger; +#include maps/mp/zm_tomb_chamber; +#include maps/mp/zm_tomb_vo; +#include maps/mp/zombies/_zm_net; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_sidequests; +#include maps/mp/zombies/_zm_craftables; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +main() +{ + onplayerconnect_callback( ::onplayerconnect ); + flag_init( "electric_puzzle_1_complete" ); + flag_init( "electric_puzzle_2_complete" ); + flag_init( "electric_upgrade_available" ); + maps/mp/zm_tomb_vo::add_puzzle_completion_line( 3, "vox_sam_lightning_puz_solve_0" ); + maps/mp/zm_tomb_vo::add_puzzle_completion_line( 3, "vox_sam_lightning_puz_solve_1" ); + maps/mp/zm_tomb_vo::add_puzzle_completion_line( 3, "vox_sam_lightning_puz_solve_2" ); + level thread maps/mp/zm_tomb_vo::watch_one_shot_line( "puzzle", "try_puzzle", "vo_try_puzzle_lightning1" ); + level thread maps/mp/zm_tomb_vo::watch_one_shot_line( "puzzle", "try_puzzle", "vo_try_puzzle_lightning2" ); + electric_puzzle_1_init(); + electric_puzzle_2_init(); + level thread electric_puzzle_1_run(); + flag_wait( "electric_puzzle_1_complete" ); + playsoundatposition( "zmb_squest_step1_finished", ( 0, 0, -1 ) ); + level thread rumble_players_in_chamber( 5, 3 ); + level thread electric_puzzle_2_run(); + flag_wait( "electric_puzzle_2_complete" ); + level thread electric_puzzle_2_cleanup(); +} + +onplayerconnect() +{ + self thread electric_puzzle_watch_staff(); +} + +electric_puzzle_watch_staff() +{ + self endon( "disconnect" ); + a_piano_keys = getstructarray( "piano_key", "script_noteworthy" ); + while ( 1 ) + { + self waittill( "projectile_impact", str_weap_name, v_explode_point, n_radius, e_projectile, n_impact ); + while ( str_weap_name == "staff_lightning_zm" ) + { + while ( !flag( "electric_puzzle_1_complete" ) && maps/mp/zm_tomb_chamber::is_chamber_occupied() ) + { + n_index = get_closest_index( v_explode_point, a_piano_keys, 20 ); + while ( isDefined( n_index ) ) + { + a_piano_keys[ n_index ] notify( "piano_key_shot" ); + a_players = getplayers(); + _a77 = a_players; + _k77 = getFirstArrayKey( _a77 ); + while ( isDefined( _k77 ) ) + { + e_player = _a77[ _k77 ]; + if ( e_player hasweapon( "staff_lightning_zm" ) ) + { + level notify( "vo_try_puzzle_lightning1" ); + } + _k77 = getNextArrayKey( _a77, _k77 ); + } + } + } + } + } +} + +electric_puzzle_1_init() +{ + flag_init( "piano_chord_ringing" ); +} + +electric_puzzle_1_run() +{ + a_piano_keys = getstructarray( "piano_key", "script_noteworthy" ); + level.a_piano_keys_playing = []; + array_thread( a_piano_keys, ::piano_key_run ); + level thread piano_run_chords(); +} + +piano_keys_stop() +{ + level notify( "piano_keys_stop" ); + level.a_piano_keys_playing = []; +} + +show_chord_debug( a_chord_notes ) +{ +/# + if ( !isDefined( a_chord_notes ) ) + { + a_chord_notes = []; + } + a_piano_keys = getstructarray( "piano_key", "script_noteworthy" ); + _a129 = a_piano_keys; + _k129 = getFirstArrayKey( _a129 ); + while ( isDefined( _k129 ) ) + { + e_key = _a129[ _k129 ]; + e_key notify( "stop_debug_position" ); + _a132 = a_chord_notes; + _k132 = getFirstArrayKey( _a132 ); + while ( isDefined( _k132 ) ) + { + note = _a132[ _k132 ]; + if ( note == e_key.script_string ) + { + e_key thread puzzle_debug_position(); + break; + } + else + { + _k132 = getNextArrayKey( _a132, _k132 ); + } + } + _k129 = getNextArrayKey( _a129, _k129 ); +#/ + } +} + +piano_run_chords() +{ + a_chords = getstructarray( "piano_chord", "targetname" ); + _a147 = a_chords; + _k147 = getFirstArrayKey( _a147 ); + while ( isDefined( _k147 ) ) + { + s_chord = _a147[ _k147 ]; + s_chord.notes = strtok( s_chord.script_string, " " ); +/# + assert( s_chord.notes.size == 3 ); +#/ + _k147 = getNextArrayKey( _a147, _k147 ); + } + a_chord_order = array( "a_minor", "e_minor", "d_minor" ); + _a154 = a_chord_order; + _k154 = getFirstArrayKey( _a154 ); + while ( isDefined( _k154 ) ) + { + chord_name = _a154[ _k154 ]; + s_chord = getstruct( "piano_chord_" + chord_name, "script_noteworthy" ); +/# + show_chord_debug( s_chord.notes ); +#/ + chord_solved = 0; + while ( !chord_solved ) + { + level waittill( "piano_key_played" ); + while ( level.a_piano_keys_playing.size == 3 ) + { + correct_notes_playing = 0; + _a169 = level.a_piano_keys_playing; + _k169 = getFirstArrayKey( _a169 ); + while ( isDefined( _k169 ) ) + { + played_note = _a169[ _k169 ]; + _a171 = s_chord.notes; + _k171 = getFirstArrayKey( _a171 ); + while ( isDefined( _k171 ) ) + { + requested_note = _a171[ _k171 ]; + if ( requested_note == played_note ) + { + correct_notes_playing++; + } + _k171 = getNextArrayKey( _a171, _k171 ); + } + _k169 = getNextArrayKey( _a169, _k169 ); + } + if ( correct_notes_playing == 3 ) + { + chord_solved = 1; + break; + } + else + { + a_players = getplayers(); + _a185 = a_players; + _k185 = getFirstArrayKey( _a185 ); + while ( isDefined( _k185 ) ) + { + e_player = _a185[ _k185 ]; + if ( e_player hasweapon( "staff_lightning_zm" ) ) + { + level notify( "vo_puzzle_bad" ); + } + _k185 = getNextArrayKey( _a185, _k185 ); + } + } + } + } + a_players = getplayers(); + _a197 = a_players; + _k197 = getFirstArrayKey( _a197 ); + while ( isDefined( _k197 ) ) + { + e_player = _a197[ _k197 ]; + if ( e_player hasweapon( "staff_lightning_zm" ) ) + { + level notify( "vo_puzzle_good" ); + } + _k197 = getNextArrayKey( _a197, _k197 ); + } + flag_set( "piano_chord_ringing" ); + rumble_nearby_players( a_chords[ 0 ].origin, 1500, 2 ); + wait 4; + flag_clear( "piano_chord_ringing" ); + piano_keys_stop(); +/# + show_chord_debug(); +#/ + _k154 = getNextArrayKey( _a154, _k154 ); + } + e_player = get_closest_player( a_chords[ 0 ].origin ); + e_player thread maps/mp/zm_tomb_vo::say_puzzle_completion_line( 3 ); + flag_set( "electric_puzzle_1_complete" ); +} + +piano_key_run() +{ + piano_key_note = self.script_string; + while ( 1 ) + { + self waittill( "piano_key_shot" ); + if ( !flag( "piano_chord_ringing" ) ) + { + if ( level.a_piano_keys_playing.size >= 3 ) + { + piano_keys_stop(); + } + self.e_fx = spawn( "script_model", self.origin ); + self.e_fx playloopsound( "zmb_kbd_" + piano_key_note ); + self.e_fx.angles = self.angles; + self.e_fx setmodel( "tag_origin" ); + playfxontag( level._effect[ "elec_piano_glow" ], self.e_fx, "tag_origin" ); + level.a_piano_keys_playing[ level.a_piano_keys_playing.size ] = piano_key_note; + level notify( "piano_key_played" ); + level waittill( "piano_keys_stop" ); + self.e_fx delete(); + } + } +} + +electric_puzzle_2_init() +{ + level.electric_relays = []; + level.electric_relays[ "bunker" ] = spawnstruct(); + level.electric_relays[ "tank_platform" ] = spawnstruct(); + level.electric_relays[ "start" ] = spawnstruct(); + level.electric_relays[ "elec" ] = spawnstruct(); + level.electric_relays[ "ruins" ] = spawnstruct(); + level.electric_relays[ "air" ] = spawnstruct(); + level.electric_relays[ "ice" ] = spawnstruct(); + level.electric_relays[ "village" ] = spawnstruct(); + _a273 = level.electric_relays; + _k273 = getFirstArrayKey( _a273 ); + while ( isDefined( _k273 ) ) + { + s_relay = _a273[ _k273 ]; + s_relay.connections = []; + _k273 = getNextArrayKey( _a273, _k273 ); + } + level.electric_relays[ "tank_platform" ].connections[ 0 ] = "ruins"; + level.electric_relays[ "start" ].connections[ 1 ] = "tank_platform"; + level.electric_relays[ "elec" ].connections[ 0 ] = "ice"; + level.electric_relays[ "ruins" ].connections[ 2 ] = "chamber"; + level.electric_relays[ "air" ].connections[ 2 ] = "start"; + level.electric_relays[ "ice" ].connections[ 3 ] = "village"; + level.electric_relays[ "village" ].connections[ 2 ] = "air"; + level.electric_relays[ "bunker" ].position = 2; + level.electric_relays[ "tank_platform" ].position = 1; + level.electric_relays[ "start" ].position = 3; + level.electric_relays[ "elec" ].position = 1; + level.electric_relays[ "ruins" ].position = 3; + level.electric_relays[ "air" ].position = 0; + level.electric_relays[ "ice" ].position = 1; + level.electric_relays[ "village" ].position = 1; + a_switches = getentarray( "puzzle_relay_switch", "script_noteworthy" ); + _a303 = a_switches; + _k303 = getFirstArrayKey( _a303 ); + while ( isDefined( _k303 ) ) + { + e_switch = _a303[ _k303 ]; + level.electric_relays[ e_switch.script_string ].e_switch = e_switch; + _k303 = getNextArrayKey( _a303, _k303 ); + } + array_thread( level.electric_relays, ::relay_switch_run ); +} + +electric_puzzle_2_run() +{ + update_relays(); +} + +electric_puzzle_2_cleanup() +{ + _a320 = level.electric_relays; + _k320 = getFirstArrayKey( _a320 ); + while ( isDefined( _k320 ) ) + { + s_relay = _a320[ _k320 ]; + if ( isDefined( s_relay.trigger_stub ) ) + { + maps/mp/zombies/_zm_unitrigger::register_unitrigger( s_relay.trigger_stub ); + } + if ( isDefined( s_relay.e_switch ) ) + { + s_relay.e_switch stoploopsound( 0,5 ); + } + if ( isDefined( s_relay.e_fx ) ) + { + s_relay.e_fx delete(); + } + _k320 = getNextArrayKey( _a320, _k320 ); + } +} + +kill_all_relay_power() +{ + _a341 = level.electric_relays; + _k341 = getFirstArrayKey( _a341 ); + while ( isDefined( _k341 ) ) + { + s_relay = _a341[ _k341 ]; + s_relay.receiving_power = 0; + s_relay.sending_power = 0; + _k341 = getNextArrayKey( _a341, _k341 ); + } +} + +relay_give_power( s_relay ) +{ + if ( !flag( "electric_puzzle_1_complete" ) ) + { + return; + } + if ( !isDefined( s_relay ) ) + { + kill_all_relay_power(); + s_relay = level.electric_relays[ "elec" ]; + } + s_relay.receiving_power = 1; + str_target_relay = s_relay.connections[ s_relay.position ]; + if ( isDefined( str_target_relay ) ) + { + if ( str_target_relay == "chamber" ) + { + s_relay.e_switch thread maps/mp/zm_tomb_vo::say_puzzle_completion_line( 3 ); + level thread play_puzzle_stinger_on_all_players(); + flag_set( "electric_puzzle_2_complete" ); + return; + } + else + { + s_relay.sending_power = 1; + s_target_relay = level.electric_relays[ str_target_relay ]; + relay_give_power( s_target_relay ); + } + } +} + +update_relay_fx_and_sound() +{ + if ( !flag( "electric_puzzle_1_complete" ) ) + { + return; + } + _a398 = level.electric_relays; + _k398 = getFirstArrayKey( _a398 ); + while ( isDefined( _k398 ) ) + { + s_relay = _a398[ _k398 ]; + if ( s_relay.sending_power ) + { + if ( isDefined( s_relay.e_fx ) ) + { + s_relay.e_fx delete(); + } + s_relay.e_switch playloopsound( "zmb_squest_elec_switch_hum", 1 ); + } + else if ( s_relay.receiving_power ) + { + if ( !isDefined( s_relay.e_fx ) ) + { + v_offset = anglesToRight( s_relay.e_switch.angles ) * 1; + s_relay.e_fx = spawn( "script_model", s_relay.e_switch.origin + v_offset ); + s_relay.e_fx.angles = s_relay.e_switch.angles + vectorScale( ( 0, 0, -1 ), 90 ); + s_relay.e_fx setmodel( "tag_origin" ); + playfxontag( level._effect[ "fx_tomb_sparks" ], s_relay.e_fx, "tag_origin" ); + } + s_relay.e_switch playloopsound( "zmb_squest_elec_switch_spark", 1 ); + } + else + { + if ( isDefined( s_relay.e_fx ) ) + { + s_relay.e_fx delete(); + } + s_relay.e_switch stoploopsound( 1 ); + } + _k398 = getNextArrayKey( _a398, _k398 ); + } +} + +update_relay_rotation() +{ + self.e_switch rotateto( ( self.position * 90, self.e_switch.angles[ 1 ], self.e_switch.angles[ 2 ] ), 0,1, 0, 0 ); + self.e_switch playsound( "zmb_squest_elec_switch" ); + self.e_switch waittill( "rotatedone" ); +} + +update_relays() +{ + relay_give_power(); + update_relay_fx_and_sound(); +} + +relay_switch_run() +{ +/# + assert( isDefined( self.e_switch ) ); +#/ + self.trigger_stub = spawnstruct(); + self.trigger_stub.origin = self.e_switch.origin; + self.trigger_stub.radius = 50; + self.trigger_stub.cursor_hint = "HINT_NOICON"; + self.trigger_stub.hint_string = ""; + self.trigger_stub.script_unitrigger_type = "unitrigger_radius_use"; + self.trigger_stub.require_look_at = 1; + maps/mp/zombies/_zm_unitrigger::register_unitrigger( self.trigger_stub, ::relay_unitrigger_think ); + level endon( "electric_puzzle_2_complete" ); + self thread update_relay_rotation(); + n_tries = 0; + while ( 1 ) + { + self.trigger_stub waittill( "trigger", e_user ); + n_tries++; + level notify( "vo_try_puzzle_lightning2" ); + self.position = ( self.position + 1 ) % 4; + str_target_relay = self.connections[ self.position ]; + if ( isDefined( str_target_relay ) ) + { + if ( str_target_relay == "village" || str_target_relay == "ruins" ) + { + level notify( "vo_puzzle_good" ); + } + } + else if ( ( n_tries % 8 ) == 0 ) + { + level notify( "vo_puzzle_confused" ); + } + else + { + if ( ( n_tries % 4 ) == 0 ) + { + level notify( "vo_puzzle_bad" ); + } + } + self update_relay_rotation(); + update_relays(); + } +} + +relay_unitrigger_think() +{ + self endon( "kill_trigger" ); + while ( 1 ) + { + self waittill( "trigger", player ); + self.stub notify( "trigger" ); + } +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_quest_fire.gsc b/zm_tomb_patch/maps/mp/zm_tomb_quest_fire.gsc new file mode 100644 index 0000000..af28c27 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_quest_fire.gsc @@ -0,0 +1,525 @@ +#include maps/mp/zm_tomb_chamber; +#include maps/mp/zm_tomb_vo; +#include maps/mp/zombies/_zm_net; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_sidequests; +#include maps/mp/zombies/_zm_craftables; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +#using_animtree( "zm_tomb_basic" ); + +main() +{ + flag_init( "fire_puzzle_1_complete" ); + flag_init( "fire_puzzle_2_complete" ); + flag_init( "fire_upgrade_available" ); + onplayerconnect_callback( ::onplayerconnect ); + fire_puzzle_1_init(); + fire_puzzle_2_init(); + maps/mp/zm_tomb_vo::add_puzzle_completion_line( 1, "vox_sam_fire_puz_solve_0" ); + maps/mp/zm_tomb_vo::add_puzzle_completion_line( 1, "vox_sam_fire_puz_solve_1" ); + maps/mp/zm_tomb_vo::add_puzzle_completion_line( 1, "vox_sam_fire_puz_solve_2" ); + level thread maps/mp/zm_tomb_vo::watch_one_shot_line( "puzzle", "try_puzzle", "vo_try_puzzle_fire1" ); + level thread maps/mp/zm_tomb_vo::watch_one_shot_line( "puzzle", "try_puzzle", "vo_try_puzzle_fire2" ); + level thread fire_puzzle_1_run(); + flag_wait( "fire_puzzle_1_complete" ); + playsoundatposition( "zmb_squest_step1_finished", ( -1, 0, 0 ) ); + level thread rumble_players_in_chamber( 5, 3 ); + level thread fire_puzzle_1_cleanup(); + level thread fire_puzzle_2_run(); + flag_wait( "fire_puzzle_2_complete" ); + level thread fire_puzzle_2_cleanup(); + flag_wait( "staff_fire_zm_upgrade_unlocked" ); +} + +onplayerconnect() +{ + self thread fire_puzzle_watch_staff(); +} + +init_animtree() +{ + scriptmodelsuseanimtree( -1 ); +} + +fire_puzzle_1_init() +{ +} + +fire_puzzle_1_run() +{ + level.sacrifice_volumes = getentarray( "fire_sacrifice_volume", "targetname" ); + level.clone_list = []; + level thread clone_cleanup_watch_player_presence(); + array_thread( level.sacrifice_volumes, ::init_sacrifice_volume ); + b_any_volumes_unfinished = 1; + while ( b_any_volumes_unfinished ) + { + level waittill( "fire_sacrifice_completed" ); + b_any_volumes_unfinished = 0; + _a98 = level.sacrifice_volumes; + _k98 = getFirstArrayKey( _a98 ); + while ( isDefined( _k98 ) ) + { + e_volume = _a98[ _k98 ]; + if ( !e_volume.b_gods_pleased ) + { + b_any_volumes_unfinished = 1; + } + _k98 = getNextArrayKey( _a98, _k98 ); + } + } +/# + iprintlnbold( "Fire Chamber Puzzle Completed" ); +#/ + e_player = get_closest_player( level.sacrifice_volumes[ 0 ].origin ); + e_player thread maps/mp/zm_tomb_vo::say_puzzle_completion_line( 1 ); + flag_set( "fire_puzzle_1_complete" ); +} + +fire_puzzle_1_cleanup() +{ + array_delete( level.sacrifice_volumes ); + level.sacrifice_volumes = []; + array_delete( level.clone_list ); + level.clone_list = []; +} + +clone_cleanup_watch_player_presence() +{ + level endon( "fire_puzzle_1_complete" ); + while ( 1 ) + { + wait 1; + if ( level.clone_list.size > 0 ) + { + if ( !maps/mp/zm_tomb_chamber::is_chamber_occupied() ) + { + array_delete( level.clone_list ); + level.clone_list = []; + } + } + } +} + +init_sacrifice_volume() +{ + self.b_gods_pleased = 0; + self.num_sacrifices_received = 0; + self.pct_sacrifices_received = 0; + self.e_ignition_point = getstruct( self.target, "targetname" ); + self.e_ignition_point thread run_sacrifice_ignition( self ); +} + +run_sacrifice_plinth( e_volume ) +{ + while ( 1 ) + { + if ( flag( "fire_puzzle_1_complete" ) ) + { + break; + } + else if ( isDefined( e_volume ) ) + { + if ( e_volume.pct_sacrifices_received > self.script_float || e_volume.b_gods_pleased ) + { + break; + } + } + else + { + wait 0,5; + } + } + light_plinth(); +} + +run_sacrifice_ignition( e_volume ) +{ + e_volume ent_flag_init( "flame_on" ); + if ( flag( "fire_puzzle_1_complete" ) ) + { + return; + } + level endon( "fire_puzzle_1_complete" ); + a_torch_pos = getstructarray( self.target, "targetname" ); + array_thread( a_torch_pos, ::run_sacrifice_plinth, e_volume ); + sndorigin = a_torch_pos[ 0 ].origin; + if ( !isDefined( self.angles ) ) + { + self.angles = ( -1, 0, 0 ); + } + max_hit_distance_sq = 10000; + while ( !e_volume.b_gods_pleased ) + { + e_volume ent_flag_clear( "flame_on" ); + level waittill( "fire_staff_explosion", v_point, e_projectile ); + while ( !maps/mp/zm_tomb_chamber::is_chamber_occupied() ) + { + continue; + } + while ( !e_projectile istouching( e_volume ) ) + { + continue; + } + self.e_fx = spawn( "script_model", self.origin ); + self.e_fx.angles = vectorScale( ( -1, 0, 0 ), 90 ); + self.e_fx setmodel( "tag_origin" ); + self.e_fx setclientfield( "barbecue_fx", 1 ); + e_volume ent_flag_set( "flame_on" ); + wait 6; + self.e_fx delete(); + } + level notify( "fire_sacrifice_completed" ); +} + +light_plinth() +{ + e_fx = spawn( "script_model", self.origin ); + e_fx setmodel( "tag_origin" ); + playfxontag( level._effect[ "fire_torch" ], e_fx, "tag_origin" ); + e_fx.angles = vectorScale( ( -1, 0, 0 ), 90 ); + e_fx playsound( "zmb_squest_fire_torch_ignite" ); + e_fx playloopsound( "zmb_squest_fire_torch_loop", 0,6 ); + flag_wait( "fire_puzzle_1_complete" ); + wait 30; + e_fx stoploopsound( 0,1 ); + e_fx playsound( "zmb_squest_fire_torch_out" ); + e_fx delete(); +} + +is_church_occupied() +{ + return 1; +} + +sacrifice_puzzle_zombie_killed( einflictor, attacker, idamage, smeansofdeath, sweapon, vdir, shitloc, psoffsettime ) +{ + if ( isDefined( level.craftables_crafted[ "elemental_staff_fire" ] ) && !level.craftables_crafted[ "elemental_staff_fire" ] && getDvarInt( "zombie_cheat" ) <= 0 ) + { + return; + } + if ( isDefined( self.is_mechz ) && self.is_mechz ) + { + return; + } + if ( !isDefined( level.sacrifice_volumes ) ) + { + return; + } + if ( !maps/mp/zm_tomb_chamber::is_chamber_occupied() ) + { + return; + } + _a297 = level.sacrifice_volumes; + _k297 = getFirstArrayKey( _a297 ); + while ( isDefined( _k297 ) ) + { + e_volume = _a297[ _k297 ]; + if ( e_volume.b_gods_pleased ) + { + } + else + { + if ( self istouching( e_volume ) ) + { + level notify( "vo_try_puzzle_fire1" ); + self thread fire_sacrifice_death_clone( e_volume ); + return; + } + } + _k297 = getNextArrayKey( _a297, _k297 ); + } +} + +delete_oldest_clone() +{ + if ( level.clone_list.size == 0 ) + { + return; + } + clone = level.clone_list[ 0 ]; + arrayremoveindex( level.clone_list, 0, 0 ); + clone delete(); +} + +fire_sacrifice_death_clone( e_sacrifice_volume ) +{ + if ( level.clone_list.size >= 15 ) + { + level delete_oldest_clone(); + } + self ghost(); + clone = self spawn_zombie_clone(); + if ( self.has_legs ) + { + clone setanim( %ch_dazed_a_death, 1, 0, 1 ); + } + else + { + clone setanim( %ai_zombie_crawl_death_v1, 1, 0, 1 ); + } + n_anim_time = getanimlength( %ch_dazed_a_death ); + level.clone_list[ level.clone_list.size ] = clone; + clone endon( "death" ); + wait n_anim_time; + e_sacrifice_volume ent_flag_wait( "flame_on" ); + a_players = getplayers(); + _a359 = a_players; + _k359 = getFirstArrayKey( _a359 ); + while ( isDefined( _k359 ) ) + { + e_player = _a359[ _k359 ]; + if ( e_player hasweapon( "staff_fire_zm" ) ) + { + level notify( "vo_puzzle_good" ); + } + _k359 = getNextArrayKey( _a359, _k359 ); + } + playfx( level._effect[ "fire_ash_explosion" ], clone.origin, anglesToForward( clone.angles ), anglesToUp( clone.angles ) ); + e_sacrifice_volume.num_sacrifices_received++; + e_sacrifice_volume.pct_sacrifices_received = e_sacrifice_volume.num_sacrifices_received / 32; + if ( e_sacrifice_volume.num_sacrifices_received >= 32 ) + { + e_sacrifice_volume.b_gods_pleased = 1; + } + e_sacrifice_volume notify( "sacrifice_received" ); + arrayremovevalue( level.clone_list, clone ); + clone delete(); +} + +spawn_zombie_clone() +{ + clone = spawn( "script_model", self.origin ); + clone.angles = self.angles; + clone setmodel( self.model ); + if ( isDefined( self.headmodel ) ) + { + clone.headmodel = self.headmodel; + clone attach( clone.headmodel, "", 1 ); + } + clone useanimtree( -1 ); + return clone; +} + +fire_puzzle_2_init() +{ + i = 1; + while ( i <= 4 ) + { + a_ternary = getentarray( "fire_torch_ternary_group_0" + i, "targetname" ); + if ( a_ternary.size > 1 ) + { + index_to_save = randomintrange( 0, a_ternary.size ); + a_ternary[ index_to_save ] ghost(); + arrayremoveindex( a_ternary, index_to_save, 0 ); + array_delete( a_ternary ); + i++; + continue; + } + else + { + a_ternary[ 0 ] ghost(); + } + i++; + } + a_torches = getstructarray( "church_torch_target", "script_noteworthy" ); + array_thread( a_torches, ::fire_puzzle_torch_run ); +} + +fire_puzzle_2_run() +{ + a_ternary = getentarray( "fire_torch_ternary", "script_noteworthy" ); +/# + assert( a_ternary.size == 4 ); +#/ + _a434 = a_ternary; + _k434 = getFirstArrayKey( _a434 ); + while ( isDefined( _k434 ) ) + { + e_number = _a434[ _k434 ]; + e_number show(); + e_target_torch = getstruct( e_number.target, "targetname" ); + e_target_torch.b_correct_torch = 1; + e_target_torch thread puzzle_debug_position(); + _k434 = getNextArrayKey( _a434, _k434 ); + } +} + +fire_puzzle_2_cleanup() +{ + a_torches = getstructarray( "church_torch_target", "script_noteworthy" ); + _a446 = a_torches; + _k446 = getFirstArrayKey( _a446 ); + while ( isDefined( _k446 ) ) + { + s_torch = _a446[ _k446 ]; + if ( !isDefined( s_torch.e_fx ) ) + { + s_torch thread fire_puzzle_2_torch_flame(); + wait 0,25; + } + _k446 = getNextArrayKey( _a446, _k446 ); + } + wait 30; + _a459 = a_torches; + _k459 = getFirstArrayKey( _a459 ); + while ( isDefined( _k459 ) ) + { + s_torch = _a459[ _k459 ]; + if ( isDefined( s_torch.e_fx ) ) + { + s_torch.e_fx delete(); + wait 0,25; + } + _k459 = getNextArrayKey( _a459, _k459 ); + } +} + +fire_puzzle_2_is_complete() +{ + a_torches = getstructarray( "church_torch_target", "script_noteworthy" ); + wrong_torch = 0; + unlit_torch = 0; + _a476 = a_torches; + _k476 = getFirstArrayKey( _a476 ); + while ( isDefined( _k476 ) ) + { + e_torch = _a476[ _k476 ]; + if ( isDefined( e_torch.e_fx ) && !e_torch.b_correct_torch ) + { + wrong_torch = 1; + } + if ( !isDefined( e_torch.e_fx ) && e_torch.b_correct_torch ) + { + unlit_torch = 1; + } + _k476 = getNextArrayKey( _a476, _k476 ); + } + if ( !isDefined( level.n_torches_lit ) ) + { + level.n_torches_lit = 0; + } + if ( !isDefined( level.n_wrong_torches ) ) + { + level.n_wrong_torches = 0; + } + level.n_torches_lit++; + a_players = getplayers(); + _a504 = a_players; + _k504 = getFirstArrayKey( _a504 ); + while ( isDefined( _k504 ) ) + { + e_player = _a504[ _k504 ]; + if ( e_player hasweapon( "staff_fire_zm" ) ) + { + if ( ( level.n_torches_lit % 12 ) == 0 && !flag( "fire_puzzle_2_complete" ) ) + { + level notify( "vo_puzzle_confused" ); + break; + } + else + { + if ( wrong_torch && !flag( "fire_puzzle_2_complete" ) ) + { + level.n_wrong_torches++; + if ( ( level.n_wrong_torches % 5 ) == 0 ) + { + level notify( "vo_puzzle_bad" ); + } + break; + } + else + { + if ( unlit_torch ) + { + level notify( "vo_puzzle_good" ); + } + } + } + } + _k504 = getNextArrayKey( _a504, _k504 ); + } + if ( !wrong_torch ) + { + return !unlit_torch; + } +} + +fire_puzzle_watch_staff() +{ + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "projectile_impact", str_weap_name, v_explode_point, n_radius, e_projectile, n_impact ); + if ( str_weap_name == "staff_fire_zm" ) + { + level notify( "fire_staff_explosion" ); + } + } +} + +fire_puzzle_2_torch_flame() +{ + if ( isDefined( self.e_fx ) ) + { + self.e_fx delete(); + } + self.e_fx = spawn( "script_model", self.origin ); + self.e_fx.angles = vectorScale( ( -1, 0, 0 ), 90 ); + self.e_fx setmodel( "tag_origin" ); + playfxontag( level._effect[ "fire_torch" ], self.e_fx, "tag_origin" ); + self.e_fx playsound( "zmb_squest_fire_torch_ignite" ); + self.e_fx playloopsound( "zmb_squest_fire_torch_loop", 0,6 ); + rumble_nearby_players( self.origin, 1500, 2 ); + self.e_fx endon( "death" ); + if ( fire_puzzle_2_is_complete() && !flag( "fire_puzzle_2_complete" ) ) + { + self.e_fx thread maps/mp/zm_tomb_vo::say_puzzle_completion_line( 1 ); + level thread play_puzzle_stinger_on_all_players(); + flag_set( "fire_puzzle_2_complete" ); + } + wait 15; + self.e_fx stoploopsound( 0,1 ); + self.e_fx playsound( "zmb_squest_fire_torch_out" ); + if ( !flag( "fire_puzzle_2_complete" ) ) + { + self.e_fx delete(); + } +} + +fire_puzzle_torch_run() +{ + level endon( "fire_puzzle_2_complete" ); + self.b_correct_torch = 0; + max_hit_distance_sq = 4096; + while ( 1 ) + { + level waittill( "fire_staff_explosion", v_point ); + while ( !is_church_occupied() ) + { + continue; + } + dist_sq = distancesquared( v_point, self.origin ); + while ( dist_sq > max_hit_distance_sq ) + { + continue; + } + a_players = getplayers(); + _a614 = a_players; + _k614 = getFirstArrayKey( _a614 ); + while ( isDefined( _k614 ) ) + { + e_player = _a614[ _k614 ]; + if ( e_player hasweapon( "staff_fire_zm" ) ) + { + level notify( "vo_try_puzzle_fire2" ); + } + _k614 = getNextArrayKey( _a614, _k614 ); + } + self thread fire_puzzle_2_torch_flame(); + wait 2; + } +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_quest_ice.gsc b/zm_tomb_patch/maps/mp/zm_tomb_quest_ice.gsc new file mode 100644 index 0000000..2c81fed --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_quest_ice.gsc @@ -0,0 +1,357 @@ +#include maps/mp/zm_tomb_vo; +#include maps/mp/zombies/_zm_net; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_sidequests; +#include maps/mp/zombies/_zm_craftables; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +main() +{ + precachemodel( "p6_zm_tm_note_rock_01_anim" ); + flag_init( "ice_puzzle_1_complete" ); + flag_init( "ice_puzzle_2_complete" ); + flag_init( "ice_upgrade_available" ); + flag_init( "ice_tile_flipping" ); + maps/mp/zm_tomb_vo::add_puzzle_completion_line( 4, "vox_sam_ice_puz_solve_0" ); + maps/mp/zm_tomb_vo::add_puzzle_completion_line( 4, "vox_sam_ice_puz_solve_1" ); + maps/mp/zm_tomb_vo::add_puzzle_completion_line( 4, "vox_sam_ice_puz_solve_2" ); + level thread maps/mp/zm_tomb_vo::watch_one_shot_line( "puzzle", "try_puzzle", "vo_try_puzzle_water1" ); + level thread maps/mp/zm_tomb_vo::watch_one_shot_line( "puzzle", "try_puzzle", "vo_try_puzzle_water2" ); + ice_puzzle_1_init(); + level thread ice_puzzle_2_init(); + level thread ice_puzzle_1_run(); + flag_wait( "ice_puzzle_1_complete" ); + playsoundatposition( "zmb_squest_step1_finished", ( 0, 0, 0 ) ); + level thread rumble_players_in_chamber( 5, 3 ); + ice_puzzle_1_cleanup(); + level thread ice_puzzle_2_run(); + flag_wait( "ice_puzzle_2_complete" ); + flag_wait( "staff_water_zm_upgrade_unlocked" ); +} + +ice_puzzle_1_init() +{ + ice_tiles_randomize(); + a_ceiling_tile_brushes = getentarray( "ice_ceiling_tile", "script_noteworthy" ); + level.unsolved_tiles = a_ceiling_tile_brushes; + _a68 = a_ceiling_tile_brushes; + _k68 = getFirstArrayKey( _a68 ); + while ( isDefined( _k68 ) ) + { + tile = _a68[ _k68 ]; + tile.showing_tile_side = 0; + tile.value = int( tile.script_string ); + tile thread ceiling_tile_flip(); + tile thread ceiling_tile_process_damage(); + _k68 = getNextArrayKey( _a68, _k68 ); + } + a_ice_ternary_digit_brushes = getentarray( "ice_chamber_digit", "targetname" ); + _a77 = a_ice_ternary_digit_brushes; + _k77 = getFirstArrayKey( _a77 ); + while ( isDefined( _k77 ) ) + { + digit = _a77[ _k77 ]; + digit ghost(); + digit notsolid(); + _k77 = getNextArrayKey( _a77, _k77 ); + } + level.ternary_digits = []; + level.ternary_digits[ 0 ] = array( -1, 0, -1 ); + level.ternary_digits[ 1 ] = array( -1, 1, -1 ); + level.ternary_digits[ 2 ] = array( -1, 2, -1 ); + level.ternary_digits[ 3 ] = array( 1, -1, 0 ); + level.ternary_digits[ 4 ] = array( 1, -1, 1 ); + level.ternary_digits[ 5 ] = array( 1, -1, 2 ); + level.ternary_digits[ 6 ] = array( 2, -1, 0 ); + level.ternary_digits[ 7 ] = array( 2, -1, 1 ); + level.ternary_digits[ 8 ] = array( 2, -1, 2 ); + level.ternary_digits[ 9 ] = array( 1, 0, 0 ); + level.ternary_digits[ 10 ] = array( 1, 0, 1 ); + level.ternary_digits[ 11 ] = array( 1, 0, 2 ); + level thread update_ternary_display(); +} + +ice_puzzle_1_cleanup() +{ + a_ceiling_tile_brushes = getentarray( "ice_ceiling_tile", "script_noteworthy" ); + _a105 = a_ceiling_tile_brushes; + _k105 = getFirstArrayKey( _a105 ); + while ( isDefined( _k105 ) ) + { + tile = _a105[ _k105 ]; + tile thread ceiling_tile_flip( 0 ); + _k105 = getNextArrayKey( _a105, _k105 ); + } + a_ice_ternary_digit_brushes = getentarray( "ice_chamber_digit", "targetname" ); + array_delete( a_ice_ternary_digit_brushes ); +} + +ice_tiles_randomize() +{ + a_original_tiles = getentarray( "ice_tile_original", "targetname" ); + a_original_positions = []; + _a120 = a_original_tiles; + _k120 = getFirstArrayKey( _a120 ); + while ( isDefined( _k120 ) ) + { + e_tile = _a120[ _k120 ]; + a_original_positions[ a_original_positions.size ] = e_tile.origin; + _k120 = getNextArrayKey( _a120, _k120 ); + } + a_unused_tiles = getentarray( "ice_ceiling_tile", "script_noteworthy" ); + n_total_tiles = a_unused_tiles.size; + _a127 = a_original_positions; + _k127 = getFirstArrayKey( _a127 ); + while ( isDefined( _k127 ) ) + { + v_pos = _a127[ _k127 ]; + e_tile = random( a_unused_tiles ); + arrayremovevalue( a_unused_tiles, e_tile, 0 ); + e_tile moveto( v_pos, 0,5, 0,1, 0,1 ); + e_tile waittill( "movedone" ); + _k127 = getNextArrayKey( _a127, _k127 ); + } +/# + assert( a_unused_tiles.size == ( n_total_tiles - a_original_positions.size ) ); +#/ + array_delete( a_unused_tiles ); +} + +reset_tiles() +{ + a_ceiling_tile_brushes = getentarray( "ice_ceiling_tile", "script_noteworthy" ); + _a144 = a_ceiling_tile_brushes; + _k144 = getFirstArrayKey( _a144 ); + while ( isDefined( _k144 ) ) + { + tile = _a144[ _k144 ]; + tile thread ceiling_tile_flip( 1 ); + _k144 = getNextArrayKey( _a144, _k144 ); + } +} + +update_ternary_display() +{ + a_ice_ternary_digit_brushes = getentarray( "ice_chamber_digit", "targetname" ); + level endon( "ice_puzzle_1_complete" ); + while ( 1 ) + { + level waittill( "update_ice_chamber_digits", newval ); + _a160 = a_ice_ternary_digit_brushes; + _k160 = getFirstArrayKey( _a160 ); + while ( isDefined( _k160 ) ) + { + digit = _a160[ _k160 ]; + digit ghost(); + if ( isDefined( newval ) ) + { + digit_slot = int( digit.script_noteworthy ); + shown_value = level.ternary_digits[ newval ][ digit_slot ]; + digit_value = int( digit.script_string ); + if ( shown_value == digit_value ) + { + digit show(); + } + } + _k160 = getNextArrayKey( _a160, _k160 ); + } + } +} + +change_ice_gem_value() +{ + ice_gem = getent( "ice_chamber_gem", "targetname" ); + if ( level.unsolved_tiles.size != 0 ) + { + correct_tile = random( level.unsolved_tiles ); + ice_gem.value = correct_tile.value; + level notify( "update_ice_chamber_digits" ); + } + else + { + level notify( "update_ice_chamber_digits" ); + } +} + +process_gem_shooting() +{ + level endon( "ice_puzzle_1_complete" ); + ice_gem = getent( "ice_chamber_gem", "targetname" ); + ice_gem.value = -1; + ice_gem setcandamage( 1 ); + while ( 1 ) + { + self waittill( "damage", damage, attacker, direction_vec, point, mod, tagname, modelname, partname, weaponname ); + if ( weaponname == "staff_water_zm" ) + { + change_ice_gem_value(); + } + } +} + +ice_puzzle_1_run() +{ + level thread process_gem_shooting(); + change_ice_gem_value(); +} + +ceiling_tile_flip( b_flip_to_tile_side ) +{ + if ( !isDefined( b_flip_to_tile_side ) ) + { + b_flip_to_tile_side = !self.showing_tile_side; + } + if ( b_flip_to_tile_side == self.showing_tile_side ) + { + return; + } + self.showing_tile_side = !self.showing_tile_side; + self rotateroll( 180, 0,5, 0,1, 0,1 ); + self playsound( "zmb_squest_ice_tile_flip" ); + if ( !self.showing_tile_side ) + { + arrayremovevalue( level.unsolved_tiles, self, 0 ); + } + else + { + level.unsolved_tiles[ level.unsolved_tiles.size ] = self; + } + if ( level.unsolved_tiles.size == 0 && !flag( "ice_puzzle_1_complete" ) ) + { + self thread maps/mp/zm_tomb_vo::say_puzzle_completion_line( 4 ); + flag_set( "ice_puzzle_1_complete" ); + } + self waittill( "rotatedone" ); +} + +ceiling_tile_process_damage() +{ + level endon( "ice_puzzle_1_complete" ); + ice_gem = getent( "ice_chamber_gem", "targetname" ); + self setcandamage( 1 ); + ice_gem setcandamage( 1 ); + while ( 1 ) + { + self waittill( "damage", damage, attacker, direction_vec, point, mod, tagname, modelname, partname, weaponname ); + if ( issubstr( weaponname, "water" ) && self.showing_tile_side && !flag( "ice_tile_flipping" ) ) + { + level notify( "vo_try_puzzle_water1" ); + flag_set( "ice_tile_flipping" ); + if ( ice_gem.value == self.value ) + { + level notify( "vo_puzzle_good" ); + self ceiling_tile_flip( 0 ); + rumble_nearby_players( self.origin, 1500, 2 ); + wait 0,2; + } + else + { + level notify( "vo_puzzle_bad" ); + reset_tiles(); + rumble_nearby_players( self.origin, 1500, 2 ); + wait 2; + } + change_ice_gem_value(); + flag_clear( "ice_tile_flipping" ); + continue; + } + else + { + level notify( "vo_puzzle_confused" ); + } + } +} + +ice_puzzle_2_init() +{ +} + +ice_puzzle_2_run() +{ + a_stone_positions = getstructarray( "puzzle_stone_water", "targetname" ); + level.ice_stones_remaining = a_stone_positions.size; + _a328 = a_stone_positions; + _k328 = getFirstArrayKey( _a328 ); + while ( isDefined( _k328 ) ) + { + s_stone = _a328[ _k328 ]; + s_stone thread ice_stone_run(); + wait_network_frame(); + _k328 = getNextArrayKey( _a328, _k328 ); + } +} + +ice_stone_run() +{ + v_up = anglesToUp( self.angles ); + v_spawn_pos = self.origin - ( 64 * v_up ); + self.e_model = spawn( "script_model", v_spawn_pos ); + self.e_model.angles = self.angles; + self.e_model setmodel( "p6_zm_tm_note_rock_01_anim" ); + self.e_model moveto( self.origin, 1, 0,5, 0,5 ); + playfx( level._effect[ "digging" ], self.origin ); + self.e_model setcandamage( 1 ); + has_tried = 0; + while ( !flag( "ice_puzzle_2_complete" ) ) + { + self.e_model waittill( "damage", amount, inflictor, direction, point, type, tagname, modelname, partname, weaponname, idflags ); + level notify( "vo_try_puzzle_water2" ); + if ( issubstr( weaponname, "water" ) ) + { + level notify( "vo_puzzle_good" ); + break; + } + else if ( has_tried ) + { + level notify( "vo_puzzle_bad" ); + } + has_tried = 1; + } + self.e_model setclientfield( "stone_frozen", 1 ); + playsoundatposition( "zmb_squest_ice_stone_freeze", self.origin ); + while ( !flag( "ice_puzzle_2_complete" ) ) + { + self.e_model waittill( "damage", amount, inflictor, direction, point, type, tagname, modelname, partname, weaponname, idflags ); + if ( !issubstr( weaponname, "staff" ) && issubstr( type, "BULLET" ) ) + { + level notify( "vo_puzzle_good" ); + break; + } + else level notify( "vo_puzzle_confused" ); + } + self.e_model delete(); + playfx( level._effect[ "ice_explode" ], self.origin, anglesToForward( self.angles ), anglesToUp( self.angles ) ); + playsoundatposition( "zmb_squest_ice_stone_shatter", self.origin ); + level.ice_stones_remaining--; + + while ( level.ice_stones_remaining <= 0 && !flag( "ice_puzzle_2_complete" ) ) + { + flag_set( "ice_puzzle_2_complete" ); + e_player = get_closest_player( self.origin ); + e_player thread maps/mp/zm_tomb_vo::say_puzzle_completion_line( 4 ); + level thread play_puzzle_stinger_on_all_players(); + level.weather_snow = 5; + level.weather_rain = 0; + _a408 = getplayers(); + _k408 = getFirstArrayKey( _a408 ); + while ( isDefined( _k408 ) ) + { + player = _a408[ _k408 ]; + player set_weather_to_player(); + _k408 = getNextArrayKey( _a408, _k408 ); + } + wait 5; + level.weather_snow = 0; + level.weather_rain = 0; + _a419 = getplayers(); + _k419 = getFirstArrayKey( _a419 ); + while ( isDefined( _k419 ) ) + { + player = _a419[ _k419 ]; + player set_weather_to_player(); + _k419 = getNextArrayKey( _a419, _k419 ); + } + } +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_standard.gsc b/zm_tomb_patch/maps/mp/zm_tomb_standard.gsc new file mode 100644 index 0000000..4e51643 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_standard.gsc @@ -0,0 +1,27 @@ +#include maps/mp/zombies/_zm_magicbox; +#include maps/mp/zombies/_zm_game_module; +#include maps/mp/gametypes_zm/_zm_gametype; +#include maps/mp/zombies/_zm_utility; +#include common_scripts/utility; +#include maps/mp/_utility; + +precache() +{ +} + +main() +{ + maps/mp/gametypes_zm/_zm_gametype::setup_standard_objects( "tomb" ); + maps/mp/zombies/_zm_game_module::set_current_game_module( level.game_module_standard_index ); + flag_wait( "initial_blackscreen_passed" ); + flag_set( "power_on" ); + zm_treasure_chest_init(); +} + +zm_treasure_chest_init() +{ + chest1 = getstruct( "start_chest", "script_noteworthy" ); + level.chests = []; + level.chests[ level.chests.size ] = chest1; + maps/mp/zombies/_zm_magicbox::treasure_chest_init( "start_chest" ); +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_tank.gsc b/zm_tomb_patch/maps/mp/zm_tomb_tank.gsc new file mode 100644 index 0000000..c787a23 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_tank.gsc @@ -0,0 +1,1835 @@ +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/zombies/_zm_weap_staff_fire; +#include maps/mp/zombies/_zm_ai_basic; +#include maps/mp/gametypes_zm/_hud; +#include maps/mp/zombies/_zm_zonemgr; +#include maps/mp/zombies/_zm_score; +#include maps/mp/zm_tomb_amb; +#include maps/mp/zombies/_zm_powerups; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zm_tomb_vo; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_craftables; +#include maps/mp/_utility; +#include common_scripts/utility; + +#using_animtree( "zm_tomb_tank" ); + +tank_precache() +{ +} + +init() +{ + registerclientfield( "vehicle", "tank_tread_fx", 14000, 1, "int" ); + registerclientfield( "vehicle", "tank_flamethrower_fx", 14000, 2, "int" ); + registerclientfield( "vehicle", "tank_cooldown_fx", 14000, 2, "int" ); + tank_precache(); + onplayerconnect_callback( ::onplayerconnect ); + level.enemy_location_override_func = ::enemy_location_override; + level.adjust_enemyoverride_func = ::adjust_enemyoverride; + level.zm_mantle_over_40_move_speed_override = ::zm_mantle_over_40_move_speed_override; + level.vh_tank = getent( "tank", "targetname" ); + level.vh_tank tank_setup(); + level.vh_tank thread tankuseanimtree(); + level.vh_tank thread tank_discovery_vo(); + level thread maps/mp/zm_tomb_vo::watch_occasional_line( "tank", "tank_flame_zombie", "vo_tank_flame_zombie" ); + level thread maps/mp/zm_tomb_vo::watch_occasional_line( "tank", "tank_leave", "vo_tank_leave" ); + level thread maps/mp/zm_tomb_vo::watch_occasional_line( "tank", "tank_cooling", "vo_tank_cooling" ); +} + +onplayerconnect() +{ + self thread onplayerspawned(); +} + +onplayerspawned() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + self.b_already_on_tank = 0; + } +} + +tank_discovery_vo() +{ + max_dist_sq = 640000; + flag_wait( "activate_zone_village_0" ); + while ( 1 ) + { + a_players = getplayers(); + _a89 = a_players; + _k89 = getFirstArrayKey( _a89 ); + while ( isDefined( _k89 ) ) + { + e_player = _a89[ _k89 ]; + dist_sq = distance2dsquared( level.vh_tank.origin, e_player.origin ); + height_diff = abs( level.vh_tank.origin[ 2 ] - e_player.origin[ 2 ] ); + if ( dist_sq < max_dist_sq && height_diff < 150 && isDefined( e_player.isspeaking ) && !e_player.isspeaking ) + { + e_player maps/mp/zombies/_zm_audio::create_and_play_dialog( "tank", "discover_tank" ); + return; + } + _k89 = getNextArrayKey( _a89, _k89 ); + } + wait 0,1; + } +} + +tank_drop_powerups() +{ + flag_wait( "start_zombie_round_logic" ); + a_drop_nodes = []; + i = 0; + while ( i < 3 ) + { + drop_num = i + 1; + a_drop_nodes[ i ] = getvehiclenode( "tank_powerup_drop_" + drop_num, "script_noteworthy" ); + a_drop_nodes[ i ].next_drop_round = level.round_number + i; + s_drop = getstruct( "tank_powerup_drop_" + drop_num, "targetname" ); + a_drop_nodes[ i ].drop_pos = s_drop.origin; + i++; + } + a_possible_powerups = array( "nuke", "full_ammo", "zombie_blood", "insta_kill", "fire_sale", "double_points" ); + while ( 1 ) + { + self ent_flag_wait( "tank_moving" ); + _a129 = a_drop_nodes; + _k129 = getFirstArrayKey( _a129 ); + while ( isDefined( _k129 ) ) + { + node = _a129[ _k129 ]; + dist_sq = distance2dsquared( node.origin, self.origin ); + if ( dist_sq < 250000 ) + { + a_players = get_players_on_tank( 1 ); + if ( a_players.size > 0 ) + { + if ( level.staff_part_count[ "elemental_staff_lightning" ] == 0 && level.round_number >= node.next_drop_round ) + { + str_powerup = random( a_possible_powerups ); + level thread maps/mp/zombies/_zm_powerups::specific_powerup_drop( str_powerup, node.drop_pos ); + node.next_drop_round = level.round_number + randomintrange( 8, 12 ); + break; + } + else + { + level notify( "sam_clue_tank" ); + } + } + } + _k129 = getNextArrayKey( _a129, _k129 ); + } + wait 2; + } +} + +zm_mantle_over_40_move_speed_override() +{ + traversealias = "barrier_walk"; + switch( self.zombie_move_speed ) + { + case "chase_bus": + traversealias = "barrier_sprint"; + break; + default: +/# + assertmsg( "Zombie move speed of '" + self.zombie_move_speed + "' is not supported for mantle_over_40." ); +#/ + } + return traversealias; +} + +init_animtree() +{ + scriptmodelsuseanimtree( -1 ); +} + +tankuseanimtree() +{ + self useanimtree( -1 ); +} + +drawtag( tag, opcolor ) +{ +/# + org = self gettagorigin( tag ); + ang = self gettagangles( tag ); + box( org, vectorScale( ( 0, 0, 1 ), 8 ), vectorScale( ( 0, 0, 1 ), 8 ), ang[ 1 ], opcolor, 1, 0, 1 ); +#/ +} + +draw_tank_tag( tag, opcolor ) +{ +/# + self endon( "death" ); + for ( ;; ) + { + if ( self tank_tag_is_valid( tag ) ) + { + drawtag( tag.str_tag, vectorScale( ( 0, 0, 1 ), 255 ) ); + } + else + { + drawtag( tag.str_tag, vectorScale( ( 0, 0, 1 ), 255 ) ); + } + wait 0,05; +#/ + } +} + +tank_debug_tags() +{ +/# + setdvar( "debug_tank", "off" ); + adddebugcommand( "devgui_cmd "Zombies:2/Tomb:1/Tank Debug:5" "debug_tank on"\n" ); + flag_wait( "start_zombie_round_logic" ); + a_spots = getstructarray( "tank_jump_down_spots", "script_noteworthy" ); + while ( 1 ) + { + while ( getDvar( "debug_tank" ) == "on" ) + { + if ( isDefined( self.tags_drawing ) && !self.tags_drawing ) + { + _a224 = self.a_tank_tags; + _k224 = getFirstArrayKey( _a224 ); + while ( isDefined( _k224 ) ) + { + s_tag = _a224[ _k224 ]; + self thread draw_tank_tag( s_tag ); + _k224 = getNextArrayKey( _a224, _k224 ); + } + self.tags_drawing = 1; + } + ang = self.angles; + _a232 = a_spots; + _k232 = getFirstArrayKey( _a232 ); + while ( isDefined( _k232 ) ) + { + s_spot = _a232[ _k232 ]; + org = self tank_get_jump_down_offset( s_spot ); + box( org, vectorScale( ( 0, 0, 1 ), 4 ), vectorScale( ( 0, 0, 1 ), 4 ), ang[ 1 ], vectorScale( ( 0, 0, 1 ), 128 ), 1, 0, 1 ); + _k232 = getNextArrayKey( _a232, _k232 ); + } + a_zombies = get_round_enemy_array(); + _a239 = a_zombies; + _k239 = getFirstArrayKey( _a239 ); + while ( isDefined( _k239 ) ) + { + e_zombie = _a239[ _k239 ]; + if ( isDefined( e_zombie.tank_state ) ) + { + print3d( e_zombie.origin + vectorScale( ( 0, 0, 1 ), 60 ), e_zombie.tank_state, vectorScale( ( 0, 0, 1 ), 255 ), 1 ); + } + _k239 = getNextArrayKey( _a239, _k239 ); + } + } + wait 0,05; +#/ + } +} + +tank_jump_down_store_offset( s_pos ) +{ + v_up = anglesToUp( self.angles ); + v_right = anglesToRight( self.angles ); + v_fwd = anglesToForward( self.angles ); + offset = s_pos.origin - self.origin; + s_pos.tank_offset = ( vectordot( v_fwd, offset ), vectordot( v_right, offset ), vectordot( v_up, offset ) ); +} + +tank_get_jump_down_offset( s_pos ) +{ + v_up = anglesToUp( self.angles ); + v_right = anglesToRight( self.angles ); + v_fwd = anglesToForward( self.angles ); + v_offset = s_pos.tank_offset; + return ( ( self.origin + ( v_offset[ 0 ] * v_fwd ) ) + ( v_offset[ 1 ] * v_right ) ) + ( v_offset[ 2 ] * v_up ); +} + +tank_setup() +{ + self ent_flag_init( "tank_moving" ); + self ent_flag_init( "tank_activated" ); + self ent_flag_init( "tank_cooldown" ); + level.tank_boxes_enabled = 0; + self.tag_occupied = []; + self.health = 1000; + self.n_players_on = 0; + self.chase_pos_time = 0; + self hidepart( "tag_flamethrower" ); + self setmovingplatformenabled( 1 ); + self.e_roof = getent( "vol_on_tank_watch", "targetname" ); + self.e_roof enablelinkto(); + self.e_roof linkto( self ); + self.t_use = getent( "trig_use_tank", "targetname" ); + self.t_use enablelinkto(); + self.t_use linkto( self ); + self.t_use sethintstring( &"ZM_TOMB_X2AT", 500 ); + self.t_kill = spawn( "trigger_box", ( -8192, -4300, 0 ), 0, 200, 150, 128 ); + self.t_kill enablelinkto(); + self.t_kill linkto( self ); + m_tank_path_blocker = getent( "tank_path_blocker", "targetname" ); + m_tank_path_blocker delete(); + a_tank_jump_down_spots = getstructarray( "tank_jump_down_spots", "script_noteworthy" ); + _a312 = a_tank_jump_down_spots; + _k312 = getFirstArrayKey( _a312 ); + while ( isDefined( _k312 ) ) + { + s_spot = _a312[ _k312 ]; + self tank_jump_down_store_offset( s_spot ); + _k312 = getNextArrayKey( _a312, _k312 ); + } + self thread players_on_tank_update(); + self thread zombies_watch_tank(); + self thread tank_station(); + self thread tank_run_flamethrowers(); + self thread do_treadfx(); + self thread do_cooldown_fx(); + self thread tank_drop_powerups(); +/# + self thread tank_debug_tags(); +#/ + self playloopsound( "zmb_tank_idle", 0,5 ); +} + +do_cooldown_fx() +{ + self endon( "death" ); + flag_wait( "start_zombie_round_logic" ); + while ( 1 ) + { + self setclientfield( "tank_cooldown_fx", 2 ); + self ent_flag_wait( "tank_moving" ); + self setclientfield( "tank_cooldown_fx", 0 ); + self ent_flag_wait( "tank_cooldown" ); + self setclientfield( "tank_cooldown_fx", 1 ); + self ent_flag_waitopen( "tank_cooldown" ); + } +} + +do_treadfx() +{ + self endon( "death" ); + while ( 1 ) + { + self ent_flag_wait( "tank_moving" ); + self setclientfield( "tank_tread_fx", 1 ); + self ent_flag_waitopen( "tank_moving" ); + self setclientfield( "tank_tread_fx", 0 ); + } +} + +disconnect_reconnect_paths( vh_tank ) +{ + self endon( "death" ); + while ( 1 ) + { + self disconnectpaths(); + wait 1; + while ( vh_tank getspeedmph() < 1 ) + { + wait 0,05; + } + self connectpaths(); + wait 0,5; + } +} + +tank_rumble_update() +{ + while ( self.b_already_on_tank ) + { + if ( level.vh_tank ent_flag( "tank_moving" ) ) + { + self setclientfieldtoplayer( "player_rumble_and_shake", 6 ); + } + else + { + self setclientfieldtoplayer( "player_rumble_and_shake", 0 ); + } + wait 1; + } + self setclientfieldtoplayer( "player_rumble_and_shake", 0 ); +} + +players_on_tank_update() +{ + flag_wait( "start_zombie_round_logic" ); + self thread tank_disconnect_paths(); + while ( 1 ) + { + a_players = getplayers(); + _a422 = a_players; + _k422 = getFirstArrayKey( _a422 ); + while ( isDefined( _k422 ) ) + { + e_player = _a422[ _k422 ]; + if ( is_player_valid( e_player ) ) + { + if ( isDefined( e_player.b_already_on_tank ) && !e_player.b_already_on_tank && e_player entity_on_tank() ) + { + e_player.b_already_on_tank = 1; + self.n_players_on++; + if ( self ent_flag( "tank_cooldown" ) ) + { + level notify( "vo_tank_cooling" ); + } + e_player thread tank_rumble_update(); + e_player thread tank_rides_around_map_achievement_watcher(); + e_player thread tank_force_crouch_from_prone_after_on_tank(); + e_player allowcrouch( 1 ); + e_player allowprone( 0 ); + break; + } + else + { + if ( isDefined( e_player.b_already_on_tank ) && e_player.b_already_on_tank && !e_player entity_on_tank() ) + { + e_player.b_already_on_tank = 0; + self.n_players_on--; + + level notify( "vo_tank_leave" ); + e_player notify( "player_jumped_off_tank" ); + e_player setclientfieldtoplayer( "player_rumble_and_shake", 0 ); + e_player allowprone( 1 ); + } + } + } + _k422 = getNextArrayKey( _a422, _k422 ); + } + wait 0,05; + } +} + +tank_force_crouch_from_prone_after_on_tank() +{ + self endon( "disconnect" ); + self endon( "bled_out" ); + wait 1; + if ( self getstance() == "prone" ) + { + self setstance( "crouch" ); + } +} + +tank_rides_around_map_achievement_watcher() +{ + self endon( "death_or_disconnect" ); + self endon( "player_jumped_off_tank" ); + if ( level.vh_tank ent_flag( "tank_moving" ) ) + { + level.vh_tank ent_flag_waitopen( "tank_moving" ); + } + str_starting_location = level.vh_tank.str_location_current; + level.vh_tank ent_flag_wait( "tank_moving" ); + level.vh_tank ent_flag_waitopen( "tank_moving" ); + self notify( "rode_tank_around_map" ); +} + +entity_on_tank() +{ + if ( self istouching( level.vh_tank.e_roof ) ) + { + return 1; + } + return 0; +} + +tank_station() +{ + self thread tank_watch_use(); + self thread tank_movement(); + a_call_boxes = getentarray( "trig_tank_station_call", "targetname" ); + _a518 = a_call_boxes; + _k518 = getFirstArrayKey( _a518 ); + while ( isDefined( _k518 ) ) + { + t_call_box = _a518[ _k518 ]; + t_call_box thread tank_call_box(); + _k518 = getNextArrayKey( _a518, _k518 ); + } + self.t_use waittill( "trigger" ); + level.tank_boxes_enabled = 1; +} + +tank_left_behind() +{ + wait 4; + n_valid_dist_sq = 1000000; + a_riders = get_players_on_tank( 1 ); + if ( a_riders.size == 0 ) + { + return; + } + e_rider = random( a_riders ); + a_players = getplayers(); + a_victims = []; + v_tank_fwd = anglesToForward( self.angles ); + _a547 = a_players; + _k547 = getFirstArrayKey( _a547 ); + while ( isDefined( _k547 ) ) + { + e_player = _a547[ _k547 ]; + if ( isDefined( e_player.b_already_on_tank ) && e_player.b_already_on_tank ) + { + } + else + { + if ( distance2dsquared( e_player.origin, self.origin ) > n_valid_dist_sq ) + { + break; + } + else v_to_tank = self.origin - e_player.origin; + v_to_tank = vectornormalize( v_to_tank ); + if ( vectordot( v_to_tank, v_tank_fwd ) < 0 ) + { + break; + } + else v_player_fwd = anglesToForward( e_player.angles ); + if ( vectordot( v_player_fwd, v_to_tank ) < 0 ) + { + break; + } + else + { + a_victims[ a_victims.size ] = e_player; + } + } + _k547 = getNextArrayKey( _a547, _k547 ); + } + if ( a_victims.size == 0 ) + { + return; + } + e_victim = random( a_victims ); + maps/mp/zm_tomb_vo::tank_left_behind_vo( e_victim, e_rider ); +} + +tank_watch_use() +{ + while ( 1 ) + { + self.t_use waittill( "trigger", e_player ); + level thread maps/mp/zm_tomb_amb::sndplaystingerwithoverride( "mus_event_tank_ride", 70 ); + cooling_down = self ent_flag( "tank_cooldown" ); + if ( is_player_valid( e_player ) && e_player.score >= 500 && !cooling_down ) + { + self ent_flag_set( "tank_activated" ); + self ent_flag_set( "tank_moving" ); + e_player thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "tank", "tank_buy" ); + self thread tank_left_behind(); + e_player maps/mp/zombies/_zm_score::minus_to_player_score( 500 ); + self waittill( "tank_stop" ); + self playsound( "zmb_tank_stop" ); + self stoploopsound( 1,5 ); + if ( isDefined( self.b_call_box_used ) && self.b_call_box_used ) + { + self.b_call_box_used = 0; + self activate_tank_wait_with_no_cost(); + } + } + } +} + +activate_tank_wait_with_no_cost() +{ + self endon( "call_box_used" ); + self.b_no_cost = 1; + self.t_use waittill( "trigger", e_player ); + self ent_flag_set( "tank_activated" ); + self ent_flag_set( "tank_moving" ); + self.b_no_cost = 0; +} + +tank_call_box() +{ + while ( 1 ) + { + self waittill( "trigger", e_player ); + cooling_down = level.vh_tank ent_flag( "tank_cooldown" ); + if ( !level.vh_tank ent_flag( "tank_activated" ) && e_player.score >= 500 && !cooling_down ) + { + level.vh_tank notify( "call_box_used" ); + level.vh_tank.b_call_box_used = 1; + e_switch = getent( self.target, "targetname" ); + self setinvisibletoall(); + wait 0,05; + e_switch rotatepitch( -180, 0,5 ); + e_switch waittill( "rotatedone" ); + e_switch rotatepitch( 180, 0,5 ); + level.vh_tank.t_use useby( e_player ); + level.vh_tank waittill( "tank_stop" ); + } + } +} + +tank_call_boxes_update() +{ + str_loc = level.vh_tank.str_location_current; + a_trigs = getentarray( "trig_tank_station_call", "targetname" ); + moving = level.vh_tank ent_flag( "tank_moving" ); + cooling = level.vh_tank ent_flag( "tank_cooldown" ); + _a683 = a_trigs; + _k683 = getFirstArrayKey( _a683 ); + while ( isDefined( _k683 ) ) + { + trig = _a683[ _k683 ]; + at_this_station = trig.script_noteworthy == ( "call_box_" + str_loc ); + if ( moving ) + { + trig setvisibletoall(); + trig sethintstring( &"ZM_TOMB_TNKM" ); + } + else if ( !level.tank_boxes_enabled || at_this_station ) + { + trig setinvisibletoall(); + } + else + { + if ( cooling ) + { + trig setvisibletoall(); + trig sethintstring( &"ZM_TOMB_TNKC" ); + break; + } + else + { + trig setvisibletoall(); + trig sethintstring( &"ZM_TOMB_X2CT", 500 ); + } + } + _k683 = getNextArrayKey( _a683, _k683 ); + } +} + +tank_movement() +{ + n_path_start = getvehiclenode( "tank_start", "targetname" ); + self attachpath( n_path_start ); + self startpath(); + self thread follow_path( n_path_start ); + self setspeedimmediate( 0 ); + self.a_locations = array( "village", "bunkers" ); + n_location_index = 0; + self.str_location_current = self.a_locations[ n_location_index ]; + tank_call_boxes_update(); + while ( 1 ) + { + self ent_flag_wait( "tank_activated" ); +/# + iprintln( "The tank is moving." ); +#/ + self thread tank_connect_paths(); + self playsound( "evt_tank_call" ); + self setspeedimmediate( 8 ); + self.t_use setinvisibletoall(); + tank_call_boxes_update(); + self thread tank_kill_players(); + self thread tank_cooldown_timer(); + self waittill( "tank_stop" ); + self ent_flag_set( "tank_cooldown" ); + self.t_use setvisibletoall(); + self.t_use sethintstring( &"ZM_TOMB_TNKC" ); + self ent_flag_clear( "tank_moving" ); + self thread tank_disconnect_paths(); + self setspeedimmediate( 0 ); + n_location_index++; + if ( n_location_index == self.a_locations.size ) + { + n_location_index = 0; + } + self.str_location_current = self.a_locations[ n_location_index ]; + tank_call_boxes_update(); + self wait_for_tank_cooldown(); + self ent_flag_clear( "tank_cooldown" ); + if ( isDefined( self.b_no_cost ) && self.b_no_cost ) + { + self.t_use sethintstring( &"ZM_TOMB_X2ATF" ); + } + else + { + self.t_use sethintstring( &"ZM_TOMB_X2AT", 500 ); + } + self ent_flag_clear( "tank_activated" ); + tank_call_boxes_update(); + } +} + +tank_disconnect_paths() +{ + self endon( "death" ); + while ( self getspeedmph() > 0 ) + { + wait 0,05; + } + self disconnectpaths(); +} + +tank_connect_paths() +{ + self endon( "death" ); + self connectpaths(); +} + +tank_kill_players() +{ + self endon( "tank_cooldown" ); + while ( 1 ) + { + self.t_kill waittill( "trigger", player ); + player thread tank_ran_me_over(); + wait 0,05; + } +} + +tank_ran_me_over() +{ + self disableinvulnerability(); + self dodamage( self.health + 1000, self.origin ); + a_nodes = getnodesinradiussorted( self.origin, 256, 0, 72, "path", 15 ); + _a838 = a_nodes; + _k838 = getFirstArrayKey( _a838 ); + while ( isDefined( _k838 ) ) + { + node = _a838[ _k838 ]; + str_zone = maps/mp/zombies/_zm_zonemgr::get_zone_from_position( node.origin ); + if ( !isDefined( str_zone ) ) + { + } + else + { + if ( isDefined( node.b_player_downed_here ) && !node.b_player_downed_here ) + { + start_wait = 0; + black_screen_wait = 4; + fade_in_time = 0,01; + fade_out_time = 0,2; + self thread maps/mp/gametypes_zm/_hud::fadetoblackforxsec( start_wait, black_screen_wait, fade_in_time, fade_out_time, "black" ); + node.b_player_downed_here = 1; + e_linker = spawn( "script_origin", self.origin ); + self playerlinkto( e_linker ); + e_linker moveto( node.origin + vectorScale( ( 0, 0, 1 ), 8 ), 1 ); + e_linker wait_to_unlink( self ); + node.b_player_downed_here = undefined; + e_linker delete(); + return; + } + } + _k838 = getNextArrayKey( _a838, _k838 ); + } +} + +wait_to_unlink( player ) +{ + player endon( "disconnect" ); + wait 4; + self unlink(); +} + +tank_cooldown_timer() +{ + self.n_cooldown_timer = 0; + str_location_original = self.str_location_current; + self playsound( "zmb_tank_start" ); + self stoploopsound( 0,4 ); + wait 0,4; + self playloopsound( "zmb_tank_loop", 1 ); + while ( str_location_original == self.str_location_current ) + { + self.n_cooldown_timer += self.n_players_on * 0,05; + wait 0,05; + } +} + +wait_for_tank_cooldown() +{ + self thread snd_fuel(); + if ( self.n_cooldown_timer < 2 ) + { + self.n_cooldown_timer = 2; + } + else + { + if ( self.n_cooldown_timer > 120 ) + { + self.n_cooldown_timer = 120; + } + } + wait self.n_cooldown_timer; + level notify( "stp_cd" ); + self playsound( "zmb_tank_ready" ); + self playloopsound( "zmb_tank_idle" ); +} + +snd_fuel() +{ + snd_cd_ent = spawn( "script_origin", self.origin ); + snd_cd_ent linkto( self ); + wait 4; + snd_cd_ent playsound( "zmb_tank_fuel_start" ); + wait 0,5; + snd_cd_ent playloopsound( "zmb_tank_fuel_loop" ); + level waittill( "stp_cd" ); + snd_cd_ent stoploopsound( 0,5 ); + snd_cd_ent playsound( "zmb_tank_fuel_end" ); + wait 2; + snd_cd_ent delete(); +} + +follow_path( n_path_start ) +{ + self endon( "death" ); +/# + assert( isDefined( n_path_start ), "vehicle_path() called without a path" ); +#/ + self notify( "newpath" ); + self endon( "newpath" ); + n_next_point = n_path_start; + while ( isDefined( n_next_point ) ) + { + self.n_next_node = getvehiclenode( n_next_point.target, "targetname" ); + self waittill( "reached_node", n_next_point ); + self.n_current = n_next_point; + n_next_point notify( "trigger" ); + if ( isDefined( n_next_point.script_noteworthy ) ) + { + self notify( n_next_point.script_noteworthy ); + self notify( "noteworthy" ); + } + waittillframeend; + } +} + +tank_tag_array_setup() +{ + a_tank_tags = []; + a_tank_tags[ 0 ] = spawnstruct(); + a_tank_tags[ 0 ].str_tag = "window_left_1_jmp_jnt"; + a_tank_tags[ 0 ].disabled_at_bunker = 1; + a_tank_tags[ 0 ].disabled_at_church = 1; + a_tank_tags[ 0 ].side = "left"; + a_tank_tags[ 1 ] = spawnstruct(); + a_tank_tags[ 1 ].str_tag = "window_left_2_jmp_jnt"; + a_tank_tags[ 1 ].disabled_at_bunker = 1; + a_tank_tags[ 1 ].disabled_at_church = 1; + a_tank_tags[ 1 ].side = "left"; + a_tank_tags[ 2 ] = spawnstruct(); + a_tank_tags[ 2 ].str_tag = "window_left_3_jmp_jnt"; + a_tank_tags[ 2 ].disabled_at_bunker = 1; + a_tank_tags[ 2 ].disabled_at_church = 1; + a_tank_tags[ 2 ].side = "left"; + a_tank_tags[ 3 ] = spawnstruct(); + a_tank_tags[ 3 ].str_tag = "window_right_front_jmp_jnt"; + a_tank_tags[ 3 ].side = "front"; + a_tank_tags[ 4 ] = spawnstruct(); + a_tank_tags[ 4 ].str_tag = "window_right_1_jmp_jnt"; + a_tank_tags[ 4 ].side = "right"; + a_tank_tags[ 5 ] = spawnstruct(); + a_tank_tags[ 5 ].str_tag = "window_right_2_jmp_jnt"; + a_tank_tags[ 5 ].disabled_at_church = 1; + a_tank_tags[ 5 ].side = "right"; + a_tank_tags[ 6 ] = spawnstruct(); + a_tank_tags[ 6 ].str_tag = "window_right_3_jmp_jnt"; + a_tank_tags[ 6 ].disabled_at_church = 1; + a_tank_tags[ 6 ].side = "right"; + a_tank_tags[ 7 ] = spawnstruct(); + a_tank_tags[ 7 ].str_tag = "window_left_rear_jmp_jnt"; + a_tank_tags[ 7 ].side = "rear"; + return a_tank_tags; +} + +get_players_on_tank( valid_targets_only ) +{ + if ( !isDefined( valid_targets_only ) ) + { + valid_targets_only = 0; + } + a_players_on_tank = []; + a_players = getplayers(); + _a1032 = a_players; + _k1032 = getFirstArrayKey( _a1032 ); + while ( isDefined( _k1032 ) ) + { + e_player = _a1032[ _k1032 ]; + if ( is_player_valid( e_player ) && isDefined( e_player.b_already_on_tank ) && e_player.b_already_on_tank ) + { + if ( !valid_targets_only || isDefined( e_player.ignoreme ) && !e_player.ignoreme && is_player_valid( e_player ) ) + { + a_players_on_tank[ a_players_on_tank.size ] = e_player; + } + } + _k1032 = getNextArrayKey( _a1032, _k1032 ); + } + return a_players_on_tank; +} + +mechz_tag_array_setup() +{ + a_mechz_tags = []; + a_mechz_tags[ 0 ] = spawnstruct(); + a_mechz_tags[ 0 ].str_tag = "tag_mechz_1"; + a_mechz_tags[ 0 ].in_use = 0; + a_mechz_tags[ 0 ].in_use_by = undefined; + a_mechz_tags[ 1 ] = spawnstruct(); + a_mechz_tags[ 1 ].str_tag = "tag_mechz_2"; + a_mechz_tags[ 1 ].in_use = 0; + a_mechz_tags[ 1 ].in_use_by = undefined; + a_mechz_tags[ 2 ] = spawnstruct(); + a_mechz_tags[ 2 ].str_tag = "tag_mechz_3"; + a_mechz_tags[ 2 ].in_use = 0; + a_mechz_tags[ 2 ].in_use_by = undefined; + a_mechz_tags[ 3 ] = spawnstruct(); + a_mechz_tags[ 3 ].str_tag = "tag_mechz_4"; + a_mechz_tags[ 3 ].in_use = 0; + a_mechz_tags[ 3 ].in_use_by = undefined; + return a_mechz_tags; +} + +mechz_tag_in_use_cleanup( mechz, tag_struct_index ) +{ + mechz notify( "kill_mechz_tag_in_use_cleanup" ); + mechz endon( "kill_mechz_tag_in_use_cleanup" ); + mechz waittill_any_or_timeout( 30, "death", "kill_ft", "tank_flamethrower_attack_complete" ); + self.a_mechz_tags[ tag_struct_index ].in_use = 0; + self.a_mechz_tags[ tag_struct_index ].in_use_by = undefined; +} + +get_closest_mechz_tag_on_tank( mechz, target_org ) +{ + best_dist = -1; + best_tag_index = undefined; + i = 0; + while ( i < self.a_mechz_tags.size ) + { + if ( self.a_mechz_tags[ i ].in_use && self.a_mechz_tags[ i ].in_use_by != mechz ) + { + i++; + continue; + } + else + { + s_tag = self.a_mechz_tags[ i ]; + tag_org = self gettagorigin( s_tag.str_tag ); + dist = distancesquared( tag_org, target_org ); + if ( dist < best_dist || best_dist < 0 ) + { + best_dist = dist; + best_tag_index = i; + } + } + i++; + } + if ( isDefined( best_tag_index ) ) + { + i = 0; + while ( i < self.a_mechz_tags.size ) + { + if ( self.a_mechz_tags[ i ].in_use && self.a_mechz_tags[ i ].in_use_by == mechz ) + { + self.a_mechz_tags[ i ].in_use = 0; + self.a_mechz_tags[ i ].in_use_by = undefined; + } + i++; + } + self.a_mechz_tags[ best_tag_index ].in_use = 1; + self.a_mechz_tags[ best_tag_index ].in_use_by = mechz; + self thread mechz_tag_in_use_cleanup( mechz, best_tag_index ); + return self.a_mechz_tags[ best_tag_index ].str_tag; + } + return undefined; +} + +tank_tag_is_valid( s_tag, disable_sides ) +{ + if ( !isDefined( disable_sides ) ) + { + disable_sides = 0; + } + if ( disable_sides ) + { + if ( s_tag.side == "right" || s_tag.side == "left" ) + { + return 0; + } + } + if ( self ent_flag( "tank_moving" ) ) + { + if ( s_tag.side == "front" ) + { + return 0; + } + if ( !isDefined( self.n_next_node ) ) + { + return 1; + } + if ( !isDefined( self.n_next_node.script_string ) ) + { + return 1; + } + if ( issubstr( self.n_next_node.script_string, "disable_" + s_tag.side ) ) + { + return 0; + } + else + { + return 1; + } + } + at_church = self.str_location_current == "village"; + at_bunker = self.str_location_current == "bunkers"; + if ( at_church ) + { + if ( isDefined( s_tag.disabled_at_church )return !s_tag.disabled_at_church; + } + else + { + && at_bunker ) + { + if ( isDefined( s_tag.disabled_at_bunker )return !s_tag.disabled_at_bunker; + } + } + return 1; +} + +zombies_watch_tank() +{ + a_tank_tags = tank_tag_array_setup(); + self.a_tank_tags = a_tank_tags; + a_mechz_tags = mechz_tag_array_setup(); + self.a_mechz_tags = a_mechz_tags; + while ( 1 ) + { + a_zombies = get_round_enemy_array(); + _a1198 = a_zombies; + _k1198 = getFirstArrayKey( _a1198 ); + while ( isDefined( _k1198 ) ) + { + e_zombie = _a1198[ _k1198 ]; + if ( !isDefined( e_zombie.tank_state ) ) + { + e_zombie thread tank_zombie_think(); + } + _k1198 = getNextArrayKey( _a1198, _k1198 ); + } + wait_network_frame(); + } +} + +start_chasing_tank() +{ + self.tank_state = "tank_chase"; +} + +stop_chasing_tank() +{ + self.tank_state = "none"; + self.str_tank_tag = undefined; + self.tank_tag = undefined; + self.b_on_tank = 0; + self.tank_re_eval_time = undefined; + self notify( "change_goal" ); + if ( isDefined( self.zombie_move_speed_original ) ) + { + self set_zombie_run_cycle( self.zombie_move_speed_original ); + } +} + +choose_tag_and_chase() +{ + s_tag = self get_closest_valid_tank_tag(); + if ( isDefined( s_tag ) ) + { + self.str_tank_tag = s_tag.str_tag; + self.tank_tag = s_tag; + self.tank_state = "tag_chase"; + } + else + { + wait 1; + } +} + +choose_tag_and_jump_down() +{ + s_tag = self get_closest_valid_tank_tag( 1 ); + if ( isDefined( s_tag ) ) + { + self.str_tank_tag = s_tag.str_tag; + self.tank_tag = getstruct( s_tag.str_tag + "_down_start", "targetname" ); + self.tank_state = "exit_tank"; + self set_zombie_run_cycle( "walk" ); +/# + assert( isDefined( self.tank_tag ) ); +#/ + } + else + { + wait 1; + } +} + +climb_tag() +{ + self endon( "death" ); + self.tank_state = "climbing"; + self.b_on_tank = 1; + str_tag = self.str_tank_tag; + self linkto( level.vh_tank, str_tag ); + v_tag_origin = level.vh_tank gettagorigin( str_tag ); + v_tag_angles = level.vh_tank gettagangles( str_tag ); + str_anim_alias = str_tag; + if ( level.vh_tank ent_flag( "tank_moving" ) && str_tag == "window_left_rear_jmp_jnt" ) + { + str_anim_alias = "window_rear_long_jmp_jnt"; + } + if ( !self.has_legs ) + { + str_anim_alias += "_crawler"; + } + n_anim_index = self getanimsubstatefromasd( "zm_tank_jump_up", str_anim_alias ); + self.b_climbing_tank = 1; + self animscripted( v_tag_origin, v_tag_angles, "zm_tank_jump_up", n_anim_index ); + self zombieanimnotetrackthink( "tank_jump_up" ); + self unlink(); + self.b_climbing_tank = 0; + level.vh_tank tank_mark_tag_occupied( str_tag, self, 0 ); + set_zombie_on_tank(); +} + +set_zombie_on_tank() +{ + self setgoalpos( self.origin ); + self thread maps/mp/zombies/_zm_ai_basic::find_flesh(); + self.tank_state = "on_tank"; +} + +jump_down_tag() +{ + self endon( "death" ); + self.tank_state = "jumping_down"; + str_tag = self.str_tank_tag; + self linkto( level.vh_tank, str_tag ); + v_tag_origin = level.vh_tank gettagorigin( str_tag ); + v_tag_angles = level.vh_tank gettagangles( str_tag ); + self setgoalpos( v_tag_origin ); + str_anim_alias = str_tag; + if ( !self.has_legs ) + { + str_anim_alias += "_crawler"; + } + n_anim_index = self getanimsubstatefromasd( "zm_tank_jump_down", str_anim_alias ); + self.b_climbing_tank = 1; + self animscripted( v_tag_origin, v_tag_angles, "zm_tank_jump_down", n_anim_index ); + self zombieanimnotetrackthink( "tank_jump_down" ); + self unlink(); + self.b_climbing_tank = 0; + level.vh_tank tank_mark_tag_occupied( str_tag, self, 0 ); + self.pursuing_tank_tag = 0; + stop_chasing_tank(); +} + +watch_zombie_fall_off_tank() +{ + self endon( "death" ); + while ( 1 ) + { + if ( self.tank_state == "on_tank" || self.tank_state == "exit_tank" ) + { + if ( !self entity_on_tank() ) + { + stop_chasing_tank(); + } + wait 0,5; + } + else + { + if ( self.tank_state == "none" ) + { + if ( self entity_on_tank() ) + { + set_zombie_on_tank(); + } + wait 5; + } + } + wait_network_frame(); + } +} + +in_range_2d( v1, v2, range, vert_allowance ) +{ + if ( abs( v1[ 2 ] - v2[ 2 ] ) > vert_allowance ) + { + return 0; + } + return distance2dsquared( v1, v2 ) < ( range * range ); +} + +tank_zombie_think() +{ + self endon( "death" ); + self.tank_state = "none"; + self thread watch_zombie_fall_off_tank(); + think_time = 0,5; + while ( 1 ) + { + a_players_on_tank = get_players_on_tank( 1 ); + tag_range = 32; + if ( level.vh_tank ent_flag( "tank_moving" ) ) + { + tag_range = 64; + } + switch( self.tank_state ) + { + case "none": + if ( !isDefined( self.ai_state ) || self.ai_state != "find_flesh" ) + { + break; + } + else + { + if ( a_players_on_tank.size == 0 ) + { + break; + break; + } + else if ( is_player_valid( self.favoriteenemy ) ) + { + if ( isDefined( self.favoriteenemy.b_already_on_tank ) && self.favoriteenemy.b_already_on_tank ) + { + self start_chasing_tank(); + } + } + else a_players = getplayers(); + a_eligible_players = []; + _a1439 = a_players; + _k1439 = getFirstArrayKey( _a1439 ); + while ( isDefined( _k1439 ) ) + { + e_player = _a1439[ _k1439 ]; + if ( isDefined( e_player.ignoreme ) && !e_player.ignoreme && is_player_valid( e_player ) ) + { + a_eligible_players[ a_eligible_players.size ] = e_player; + } + _k1439 = getNextArrayKey( _a1439, _k1439 ); + } + if ( a_eligible_players.size > 0 ) + { + if ( a_players_on_tank.size == a_players.size ) + { + self.favoriteenemy = random( a_eligible_players ); + break; + } + else + { + self.favoriteenemy = tomb_get_closest_player_using_paths( self.origin, a_eligible_players ); + } + } + break; + break; + case "tank_chase": + if ( a_players_on_tank.size == 0 ) + { + self stop_chasing_tank(); + break; + break; + } + else dist_sq_to_tank = distancesquared( self.origin, level.vh_tank.origin ); + if ( dist_sq_to_tank < 250000 ) + { + self choose_tag_and_chase(); + } + if ( self.has_legs && self.zombie_move_speed != "super_sprint" && isDefined( self.is_traversing ) && !self.is_traversing && self.ai_state == "find_flesh" ) + { + if ( level.vh_tank ent_flag( "tank_moving" ) ) + { + self set_zombie_run_cycle( "super_sprint" ); + self thread zombie_chasing_tank_turn_crawler(); + } + } + break; + break; + case "tag_chase": + if ( !isDefined( self.tank_re_eval_time ) ) + { + self.tank_re_eval_time = 6; + } + else + { + if ( self.tank_re_eval_time <= 0 ) + { + if ( self entity_on_tank() ) + { + self set_zombie_on_tank(); + } + else + { + self stop_chasing_tank(); + } + break; + break; + } + } + else self notify( "stop_path_to_tag" ); + if ( a_players_on_tank.size == 0 ) + { + self stop_chasing_tank(); + break; + break; +} +else dist_sq_to_tank = distancesquared( self.origin, level.vh_tank.origin ); +if ( dist_sq_to_tank > 1000000 || a_players_on_tank.size == 0 ) +{ + start_chasing_tank(); + break; +break; +} +else +{ +v_tag = level.vh_tank gettagorigin( self.str_tank_tag ); +if ( in_range_2d( v_tag, self.origin, tag_range, tag_range ) ) +{ + tag_claimed = level.vh_tank tank_mark_tag_occupied( self.str_tank_tag, self, 1 ); + if ( tag_claimed ) + { + self thread climb_tag(); + } +} +else +{ + self thread update_zombie_goal_pos( self.str_tank_tag, "stop_path_to_tag" ); + self.tank_re_eval_time -= think_time; +} +break; +break; +case "climbing": +case "on_tank": + if ( a_players_on_tank.size == 0 ) + { + choose_tag_and_jump_down(); + } + else if ( !isDefined( self.favoriteenemy ) || !is_player_valid( self.favoriteenemy, 1 ) ) + { + self.favoriteenemy = random( a_players_on_tank ); + } + break; +break; +case "exit_tank": + self notify( "stop_exit_tank" ); + if ( a_players_on_tank.size > 0 ) + { + set_zombie_on_tank(); + break; + break; +} +else v_tag_pos = level.vh_tank tank_get_jump_down_offset( self.tank_tag ); +if ( in_range_2d( v_tag_pos, self.origin, tag_range, tag_range ) ) +{ + tag_claimed = level.vh_tank tank_mark_tag_occupied( self.str_tank_tag, self, 1 ); + if ( tag_claimed ) + { + self thread jump_down_tag(); + } +} +else +{ + self thread update_zombie_goal_pos( self.tank_tag.targetname, "stop_exit_tank" ); + wait 1; +} +break; +break; +case "jumping_down": +} +} +} +wait think_time; +} +} + +update_zombie_goal_pos( str_position, stop_notify ) +{ + self notify( "change_goal" ); + self endon( "death" ); + self endon( "goal" ); + self endon( "near_goal" ); + self endon( "change_goal" ); + if ( isDefined( stop_notify ) ) + { + self endon( stop_notify ); + } + s_script_origin = getstruct( str_position, "targetname" ); + while ( self.tank_state != "none" ) + { + if ( isDefined( s_script_origin ) ) + { + v_origin = level.vh_tank tank_get_jump_down_offset( s_script_origin ); +/# + if ( getDvar( "debug_tank" ) == "on" ) + { + line( self.origin + vectorScale( ( 0, 0, 1 ), 30 ), v_origin ); +#/ + } + } + else + { + v_origin = level.vh_tank gettagorigin( str_position ); + } + self setgoalpos( v_origin ); + wait 0,05; + } +} + +zombie_chasing_tank_turn_crawler() +{ + self notify( "tank_watch_turn_crawler" ); + self endon( "tank_watch_turn_crawler" ); + self endon( "death" ); + while ( self.has_legs ) + { + wait 0,05; + } + self set_zombie_run_cycle( self.zombie_move_speed_original ); +} + +tank_mark_tag_occupied( str_tag, ai_occupier, set_occupied ) +{ + current_occupier = self.tag_occupied[ str_tag ]; + min_dist_sq_to_tag = 1024; + if ( set_occupied ) + { + if ( !isDefined( current_occupier ) ) + { + self.tag_occupied[ str_tag ] = ai_occupier; + return 1; + } + else + { + if ( ai_occupier == current_occupier || !isalive( current_occupier ) ) + { + dist_sq_to_tag = distance2dsquared( ai_occupier.origin, self gettagorigin( str_tag ) ); + if ( dist_sq_to_tag < min_dist_sq_to_tag ) + { + self.tag_occupied[ str_tag ] = ai_occupier; + return 1; + } + } + } + return 0; + } + else + { + if ( !isDefined( current_occupier ) ) + { + return 1; + } + else + { + if ( current_occupier != ai_occupier ) + { + return 0; + } + else + { + return 1; + } + } + } +} + +is_tag_crowded( str_tag ) +{ + v_tag = self gettagorigin( str_tag ); + a_zombies = getaiarray( level.zombie_team ); + n_nearby_zombies = 0; + _a1714 = a_zombies; + _k1714 = getFirstArrayKey( _a1714 ); + while ( isDefined( _k1714 ) ) + { + e_zombie = _a1714[ _k1714 ]; + dist_sq = distancesquared( v_tag, e_zombie.origin ); + if ( dist_sq < 4096 ) + { + if ( isDefined( e_zombie.tank_state ) ) + { + if ( e_zombie.tank_state != "tank_chase" && e_zombie.tank_state != "tag_chase" && e_zombie.tank_state != "none" ) + { + break; + } + } + else + { + n_nearby_zombies++; + if ( n_nearby_zombies >= 4 ) + { + return 1; + } + } + } + _k1714 = getNextArrayKey( _a1714, _k1714 ); + } + return 0; +} + +get_closest_valid_tank_tag( jumping_down ) +{ + if ( !isDefined( jumping_down ) ) + { + jumping_down = 0; + } + closest_dist_sq = 100000000; + closest_tag = undefined; + disable_sides = 0; + if ( jumping_down && level.vh_tank ent_flag( "tank_moving" ) ) + { + disable_sides = 1; + } + _a1752 = level.vh_tank.a_tank_tags; + _k1752 = getFirstArrayKey( _a1752 ); + while ( isDefined( _k1752 ) ) + { + s_tag = _a1752[ _k1752 ]; + if ( level.vh_tank tank_tag_is_valid( s_tag, disable_sides ) ) + { + v_tag = level.vh_tank gettagorigin( s_tag.str_tag ); + dist_sq = distancesquared( self.origin, v_tag ); + if ( dist_sq < closest_dist_sq ) + { + if ( !level.vh_tank is_tag_crowded( s_tag.str_tag ) ) + { + closest_tag = s_tag; + closest_dist_sq = dist_sq; + } + } + } + _k1752 = getNextArrayKey( _a1752, _k1752 ); + } + return closest_tag; +} + +zombieanimnotetrackthink( str_anim_notetrack_notify, chunk, node ) +{ + self endon( "death" ); + while ( 1 ) + { + self waittill( str_anim_notetrack_notify, str_notetrack ); + if ( str_notetrack == "end" ) + { + return; + } + } +} + +tank_run_flamethrowers() +{ + self thread tank_flamethrower( "tag_flash", 1 ); + wait 0,25; + self thread tank_flamethrower( "tag_flash_gunner1", 2 ); + wait 0,25; + self thread tank_flamethrower( "tag_flash_gunner2", 3 ); +} + +tank_flamethrower_get_targets( str_tag, n_flamethrower_id ) +{ + a_zombies = getaiarray( level.zombie_team ); + a_targets = []; + v_tag_pos = self gettagorigin( str_tag ); + v_tag_angles = self gettagangles( str_tag ); + v_tag_fwd = anglesToForward( v_tag_angles ); + v_kill_pos = v_tag_pos + ( v_tag_fwd * 80 ); + _a1813 = a_zombies; + _k1813 = getFirstArrayKey( _a1813 ); + while ( isDefined( _k1813 ) ) + { + ai_zombie = _a1813[ _k1813 ]; + dist_sq = distance2dsquared( ai_zombie.origin, v_kill_pos ); + if ( dist_sq > ( 80 * 80 ) ) + { + } + else if ( isDefined( ai_zombie.tank_state ) ) + { + if ( ai_zombie.tank_state == "climbing" || ai_zombie.tank_state == "jumping_down" ) + { + } + } + else + { + v_to_zombie = vectornormalize( ai_zombie.origin - v_tag_pos ); + n_dot = vectordot( v_tag_fwd, ai_zombie.origin ); + if ( n_dot < 0,95 ) + { + break; + } + else + { + a_targets[ a_targets.size ] = ai_zombie; + } + } + _k1813 = getNextArrayKey( _a1813, _k1813 ); + } + return a_targets; +} + +tank_flamethrower_cycle_targets( str_tag, n_flamethrower_id ) +{ + self endon( "flamethrower_stop_" + n_flamethrower_id ); + while ( 1 ) + { + a_targets = tank_flamethrower_get_targets( str_tag, n_flamethrower_id ); + _a1854 = a_targets; + _k1854 = getFirstArrayKey( _a1854 ); + while ( isDefined( _k1854 ) ) + { + ai = _a1854[ _k1854 ]; + if ( isalive( ai ) ) + { + self setturrettargetent( ai ); + wait 1; + } + _k1854 = getNextArrayKey( _a1854, _k1854 ); + } + wait 1; + } +} + +tank_flamethrower( str_tag, n_flamethrower_id ) +{ + zombieless_waits = 0; + time_between_flames = randomfloatrange( 3, 6 ); + while ( 1 ) + { + wait 1; + if ( n_flamethrower_id == 1 ) + { + self setturrettargetvec( self.origin + ( anglesToForward( self.angles ) * 1000 ) ); + } + self ent_flag_wait( "tank_moving" ); + a_targets = tank_flamethrower_get_targets( str_tag, n_flamethrower_id ); + if ( a_targets.size > 0 || zombieless_waits > time_between_flames ) + { + self setclientfield( "tank_flamethrower_fx", n_flamethrower_id ); + self thread flamethrower_damage_zombies( n_flamethrower_id, str_tag ); + if ( n_flamethrower_id == 1 ) + { + self thread tank_flamethrower_cycle_targets( str_tag, n_flamethrower_id ); + } + if ( a_targets.size > 0 ) + { + wait 6; + } + else + { + wait 3; + } + self setclientfield( "tank_flamethrower_fx", 0 ); + self notify( "flamethrower_stop_" + n_flamethrower_id ); + zombieless_waits = 0; + time_between_flames = randomfloatrange( 3, 6 ); + continue; + } + else + { + zombieless_waits++; + } + } +} + +flamethrower_damage_zombies( n_flamethrower_id, str_tag ) +{ + self endon( "flamethrower_stop_" + n_flamethrower_id ); + while ( 1 ) + { + a_targets = tank_flamethrower_get_targets( str_tag, n_flamethrower_id ); + _a1926 = a_targets; + _k1926 = getFirstArrayKey( _a1926 ); + while ( isDefined( _k1926 ) ) + { + ai_zombie = _a1926[ _k1926 ]; + if ( isalive( ai_zombie ) ) + { + a_players = get_players_on_tank( 1 ); + if ( a_players.size > 0 ) + { + level notify( "vo_tank_flame_zombie" ); + } + if ( str_tag == "tag_flash" ) + { + ai_zombie do_damage_network_safe( self, ai_zombie.health, "zm_tank_flamethrower", "MOD_BURNED" ); + ai_zombie thread zombie_gib_guts(); + } + else + { + ai_zombie thread maps/mp/zombies/_zm_weap_staff_fire::flame_damage_fx( "zm_tank_flamethrower", self ); + } + wait 0,05; + } + _k1926 = getNextArrayKey( _a1926, _k1926 ); + } + wait_network_frame(); + } +} + +enemy_location_override() +{ + self endon( "death" ); + enemy = self.favoriteenemy; + location = enemy.origin; + tank = level.vh_tank; + if ( isDefined( self.is_mechz ) && self.is_mechz ) + { + return location; + } + if ( isDefined( self.item ) ) + { + return self.origin; + } + if ( is_true( self.reroute ) ) + { + if ( isDefined( self.reroute_origin ) ) + { + location = self.reroute_origin; + } + } + if ( isDefined( self.tank_state ) ) + { + if ( self.tank_state == "tank_chase" ) + { + self.goalradius = 128; + } + else if ( self.tank_state == "tag_chase" ) + { + self.goalradius = 16; + } + else + { + self.goalradius = 32; + } + if ( self.tank_state == "tank_chase" || self.tank_state == "none" && isDefined( enemy.b_already_on_tank ) && enemy.b_already_on_tank ) + { + tank_front = tank gettagorigin( "window_right_front_jmp_jnt" ); + tank_back = tank gettagorigin( "window_left_rear_jmp_jnt" ); + if ( tank ent_flag( "tank_moving" ) ) + { + self.ignoreall = 1; + if ( isDefined( self.close_to_tank ) && !self.close_to_tank ) + { + if ( getTime() != tank.chase_pos_time ) + { + tank.chase_pos_time = getTime(); + tank.chase_pos_index = 0; + tank_forward = vectornormalize( anglesToForward( level.vh_tank.angles ) ); + tank_right = vectornormalize( anglesToRight( level.vh_tank.angles ) ); + tank.chase_pos = []; + tank.chase_pos[ 0 ] = level.vh_tank.origin + vectorScale( tank_forward, -164 ); + tank.chase_pos[ 1 ] = tank_front; + tank.chase_pos[ 2 ] = tank_back; + } + location = tank.chase_pos[ tank.chase_pos_index ]; + tank.chase_pos_index++; + if ( tank.chase_pos_index >= 3 ) + { + tank.chase_pos_index = 0; + } + dist_sq = distancesquared( self.origin, location ); + if ( dist_sq < 4096 ) + { + self.close_to_tank = 1; + } + } + return location; + } + self.close_to_tank = 0; + front_dist = distance2dsquared( enemy.origin, level.vh_tank.origin ); + back_dist = distance2dsquared( enemy.origin, level.vh_tank.origin ); + if ( front_dist < back_dist ) + { + location = tank_front; + } + else + { + location = tank_back; + } + self.ignoreall = 0; + } + else + { + if ( self.tank_state == "tag_chase" ) + { + location = level.vh_tank gettagorigin( self.str_tank_tag ); + } + else + { + if ( self.tank_state == "exit_tank" ) + { + location = level.vh_tank tank_get_jump_down_offset( self.tank_tag ); + } + } + } + } + return location; +} + +adjust_enemyoverride() +{ + self endon( "death" ); + location = self.enemyoverride[ 0 ]; + tank = level.vh_tank; + ent = self.enemyoverride[ 1 ]; + return location; +} + +closest_player_tank( origin, players ) +{ + if ( isDefined( level.vh_tank ) || level.vh_tank.n_players_on > 0 && isDefined( level.calc_closest_player_using_paths ) && !level.calc_closest_player_using_paths ) + { + player = getclosest( origin, players ); + } + else + { + player = get_closest_player_using_paths( origin, players ); + } + if ( isDefined( player ) ) + { + return player; + } +} + +zombie_on_tank_death_animscript_callback( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, shitloc, psoffsettime, boneindex ) +{ + if ( isDefined( self.exploding ) && self.exploding ) + { + self notify( "killanimscript" ); + self maps/mp/zombies/_zm_spawner::reset_attack_spot(); + return 1; + } + if ( isDefined( self ) ) + { + level maps/mp/zombies/_zm_spawner::zombie_death_points( self.origin, meansofdeath, shitloc, attacker, self ); + launchvector = undefined; + self thread maps/mp/zombies/_zm_spawner::zombie_ragdoll_then_explode( launchvector, attacker ); + self notify( "killanimscript" ); + self maps/mp/zombies/_zm_spawner::reset_attack_spot(); + return 1; + } + return 0; +} + +tomb_get_path_length_to_tank() +{ + tank_front = level.vh_tank gettagorigin( "window_right_front_jmp_jnt" ) + vectorScale( ( 0, 0, 1 ), 30 ); + tank_back = level.vh_tank gettagorigin( "window_left_rear_jmp_jnt" ) + vectorScale( ( 0, 0, 1 ), 30 ); + path_length_1 = self calcpathlength( tank_front ); + path_length_2 = self calcpathlength( tank_back ); + if ( path_length_1 < path_length_2 ) + { + return path_length_1; + } + else + { + return path_length_2; + } +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_teleporter.gsc b/zm_tomb_patch/maps/mp/zm_tomb_teleporter.gsc new file mode 100644 index 0000000..0b643ad --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_teleporter.gsc @@ -0,0 +1,432 @@ +#include maps/mp/zombies/_zm_score; +#include maps/mp/zm_tomb_vo; +#include maps/mp/gametypes_zm/_hud; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_craftables; +#include maps/mp/zombies/_zm_powerups; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +#using_animtree( "fxanim_props_dlc4" ); + +teleporter_init() +{ + registerclientfield( "scriptmover", "teleporter_fx", 14000, 1, "int" ); + precacheshellshock( "lava" ); + level.teleport = []; + level.n_active_links = 0; + level.n_countdown = 0; + level.n_teleport_delay = 0; + level.teleport_cost = 0; + level.n_teleport_cooldown = 0; + level.is_cooldown = 0; + level.n_active_timer = -1; + level.n_teleport_time = 0; + level.a_teleport_models = []; + a_entrance_models = getentarray( "teleport_model", "targetname" ); + _a40 = a_entrance_models; + _k40 = getFirstArrayKey( _a40 ); + while ( isDefined( _k40 ) ) + { + e_model = _a40[ _k40 ]; + e_model useanimtree( -1 ); + level.a_teleport_models[ e_model.script_int ] = e_model; + _k40 = getNextArrayKey( _a40, _k40 ); + } + array_thread( a_entrance_models, ::teleporter_samantha_chamber_line ); + a_portal_frames = getentarray( "portal_exit_frame", "script_noteworthy" ); + level.a_portal_exit_frames = []; + _a51 = a_portal_frames; + _k51 = getFirstArrayKey( _a51 ); + while ( isDefined( _k51 ) ) + { + e_frame = _a51[ _k51 ]; + e_frame useanimtree( -1 ); + e_frame ghost(); + level.a_portal_exit_frames[ e_frame.script_int ] = e_frame; + _k51 = getNextArrayKey( _a51, _k51 ); + } + level.a_teleport_exits = []; + a_exits = getstructarray( "portal_exit", "script_noteworthy" ); + _a62 = a_exits; + _k62 = getFirstArrayKey( _a62 ); + while ( isDefined( _k62 ) ) + { + s_portal = _a62[ _k62 ]; + level.a_teleport_exits[ s_portal.script_int ] = s_portal; + _k62 = getNextArrayKey( _a62, _k62 ); + } + level.a_teleport_exit_triggers = []; + a_trigs = getstructarray( "chamber_exit_trigger", "script_noteworthy" ); + _a70 = a_trigs; + _k70 = getFirstArrayKey( _a70 ); + while ( isDefined( _k70 ) ) + { + s_trig = _a70[ _k70 ]; + level.a_teleport_exit_triggers[ s_trig.script_int ] = s_trig; + _k70 = getNextArrayKey( _a70, _k70 ); + } + a_s_teleporters = getstructarray( "trigger_teleport_pad", "targetname" ); + array_thread( a_s_teleporters, ::run_chamber_entrance_teleporter ); + spawn_stargate_fx_origins(); + root = %root; + i = %fxanim_zom_tomb_portal_open_anim; + i = %fxanim_zom_tomb_portal_collapse_anim; +} + +init_animtree() +{ + scriptmodelsuseanimtree( -1 ); +} + +teleporter_samantha_chamber_line() +{ + max_dist_sq = 640000; + level.sam_chamber_line_played = 0; + flag_wait( "samantha_intro_done" ); + while ( !level.sam_chamber_line_played ) + { + a_players = getplayers(); + _a103 = a_players; + _k103 = getFirstArrayKey( _a103 ); + while ( isDefined( _k103 ) ) + { + e_player = _a103[ _k103 ]; + dist_sq = distance2dsquared( self.origin, e_player.origin ); + height_diff = abs( self.origin[ 2 ] - e_player.origin[ 2 ] ); + if ( dist_sq < max_dist_sq && height_diff < 150 && isDefined( e_player.isspeaking ) && !e_player.isspeaking ) + { + level thread play_teleporter_samantha_chamber_line( e_player ); + return; + } + _k103 = getNextArrayKey( _a103, _k103 ); + } + wait 0,1; + } +} + +play_teleporter_samantha_chamber_line( e_player ) +{ + if ( level.sam_chamber_line_played ) + { + return; + } + level.sam_chamber_line_played = 1; + flag_waitopen( "story_vo_playing" ); + flag_set( "story_vo_playing" ); + set_players_dontspeak( 1 ); + maps/mp/zm_tomb_vo::samanthasay( "vox_sam_enter_chamber_1_0", e_player, 1 ); + maps/mp/zm_tomb_vo::samanthasay( "vox_sam_enter_chamber_2_0", e_player ); + set_players_dontspeak( 0 ); + flag_clear( "story_vo_playing" ); +} + +run_chamber_exit( n_enum ) +{ + s_portal = level.a_teleport_exits[ n_enum ]; + s_activate_pos = level.a_teleport_exit_triggers[ n_enum ]; + e_portal_frame = level.a_portal_exit_frames[ n_enum ]; + e_portal_frame show(); + str_building_flag = e_portal_frame.targetname + "_building"; + flag_init( str_building_flag ); + s_activate_pos.trigger_stub = tomb_spawn_trigger_radius( s_activate_pos.origin, 50, 1 ); + s_activate_pos.trigger_stub set_unitrigger_hint_string( &"ZM_TOMB_TELE" ); + s_portal.target = s_activate_pos.target; + s_portal.origin = e_portal_frame gettagorigin( "fx_portal_jnt" ); + s_portal.angles = e_portal_frame gettagangles( "fx_portal_jnt" ); + s_portal.angles = ( s_portal.angles[ 0 ], s_portal.angles[ 1 ] + 180, s_portal.angles[ 2 ] ); + str_fx = get_teleport_fx_from_enum( n_enum ); + collapse_time = getanimlength( %fxanim_zom_tomb_portal_collapse_anim ); + open_time = getanimlength( %fxanim_zom_tomb_portal_open_anim ); + flag_wait( "start_zombie_round_logic" ); + while ( 1 ) + { + s_activate_pos.trigger_stub waittill( "trigger", e_player ); + while ( !is_player_valid( e_player ) ) + { + continue; + } + while ( e_player.score < level.teleport_cost ) + { + continue; + } + s_activate_pos.trigger_stub set_unitrigger_hint_string( "" ); + s_activate_pos.trigger_stub trigger_off(); + if ( level.teleport_cost > 0 ) + { + e_player maps/mp/zombies/_zm_score::minus_to_player_score( level.teleport_cost ); + } + e_portal_frame playloopsound( "zmb_teleporter_loop_pre", 1 ); + e_portal_frame setanim( %fxanim_zom_tomb_portal_open_anim, 1, 0,1, 1 ); + flag_set( str_building_flag ); + e_portal_frame thread whirlwind_rumble_nearby_players( str_building_flag ); + wait open_time; + e_portal_frame setanim( %fxanim_zom_tomb_portal_open_1frame_anim, 1, 0,1, 1 ); + wait_network_frame(); + flag_clear( str_building_flag ); + e_fx = spawn( "script_model", s_portal.origin ); + e_fx.angles = s_portal.angles; + e_fx setmodel( "tag_origin" ); + e_fx setclientfield( "element_glow_fx", n_enum + 4 ); + rumble_nearby_players( e_fx.origin, 1000, 2 ); + e_portal_frame playloopsound( "zmb_teleporter_loop_post", 1 ); + s_portal thread teleporter_radius_think(); + wait 20; + e_portal_frame setanim( %fxanim_zom_tomb_portal_collapse_anim, 1, 0,1, 1 ); + e_portal_frame stoploopsound( 0,5 ); + e_portal_frame playsound( "zmb_teleporter_anim_collapse_pew" ); + s_portal notify( "teleporter_radius_stop" ); + e_fx setclientfield( "element_glow_fx", 0 ); + wait collapse_time; + e_fx delete(); + s_activate_pos.trigger_stub trigger_on(); + s_activate_pos.trigger_stub set_unitrigger_hint_string( &"ZM_TOMB_TELE" ); + } +} + +run_chamber_entrance_teleporter() +{ + self endon( "death" ); + fx_glow = get_teleport_fx_from_enum( self.script_int ); + e_model = level.a_teleport_models[ self.script_int ]; + self.origin = e_model gettagorigin( "fx_portal_jnt" ); + self.angles = e_model gettagangles( "fx_portal_jnt" ); + self.angles = ( self.angles[ 0 ], self.angles[ 1 ] + 180, self.angles[ 2 ] ); + self.trigger_stub = tomb_spawn_trigger_radius( self.origin - vectorScale( ( 0, 0, 0 ), 30 ), 50 ); + flag_init( "enable_teleporter_" + self.script_int ); + str_building_flag = "teleporter_building_" + self.script_int; + flag_init( str_building_flag ); + collapse_time = getanimlength( %fxanim_zom_tomb_portal_collapse_anim ); + open_time = getanimlength( %fxanim_zom_tomb_portal_open_anim ); + flag_wait( "start_zombie_round_logic" ); + e_model setanim( %fxanim_zom_tomb_portal_collapse_anim, 1, 0,1, 1 ); + wait collapse_time; + while ( 1 ) + { + flag_wait( "enable_teleporter_" + self.script_int ); + flag_set( str_building_flag ); + e_model thread whirlwind_rumble_nearby_players( str_building_flag ); + e_model setanim( %fxanim_zom_tomb_portal_open_anim, 1, 0,1, 1 ); + e_model playloopsound( "zmb_teleporter_loop_pre", 1 ); + wait open_time; + e_model setanim( %fxanim_zom_tomb_portal_open_1frame_anim, 1, 0,1, 1 ); + wait_network_frame(); + e_fx = spawn( "script_model", self.origin ); + e_fx.angles = self.angles; + e_fx setmodel( "tag_origin" ); + e_fx setclientfield( "element_glow_fx", self.script_int + 4 ); + rumble_nearby_players( e_fx.origin, 1000, 2 ); + e_model playloopsound( "zmb_teleporter_loop_post", 1 ); + if ( isDefined( self.exit_enabled ) && !self.exit_enabled ) + { + self.exit_enabled = 1; + level thread run_chamber_exit( self.script_int ); + } + self thread stargate_teleport_think(); + flag_clear( str_building_flag ); + flag_waitopen( "enable_teleporter_" + self.script_int ); + level notify( "disable_teleporter_" + self.script_int ); + e_fx setclientfield( "element_glow_fx", 0 ); + e_model stoploopsound( 0,5 ); + e_model playsound( "zmb_teleporter_anim_collapse_pew" ); + e_model setanim( %fxanim_zom_tomb_portal_collapse_anim, 1, 0,1, 1 ); + wait collapse_time; + e_fx delete(); + } +} + +teleporter_radius_think( radius ) +{ + if ( !isDefined( radius ) ) + { + radius = 120; + } + self endon( "teleporter_radius_stop" ); + radius_sq = radius * radius; + while ( 1 ) + { + a_players = getplayers(); + _a336 = a_players; + _k336 = getFirstArrayKey( _a336 ); + while ( isDefined( _k336 ) ) + { + e_player = _a336[ _k336 ]; + dist_sq = distancesquared( e_player.origin, self.origin ); + if ( dist_sq < radius_sq && e_player getstance() != "prone" && isDefined( e_player.teleporting ) && !e_player.teleporting ) + { + playfx( level._effect[ "teleport_3p" ], self.origin, ( 0, 0, 0 ), ( 0, 0, 0 ) ); + playsoundatposition( "zmb_teleporter_tele_3d", self.origin ); + level thread stargate_teleport_player( self.target, e_player ); + } + _k336 = getNextArrayKey( _a336, _k336 ); + } + wait_network_frame(); + } +} + +stargate_teleport_think() +{ + self endon( "death" ); + level endon( "disable_teleporter_" + self.script_int ); + e_potal = level.a_teleport_models[ self.script_int ]; + while ( 1 ) + { + self.trigger_stub waittill( "trigger", e_player ); + if ( e_player getstance() != "prone" && isDefined( e_player.teleporting ) && !e_player.teleporting ) + { + playfx( level._effect[ "teleport_3p" ], self.origin, ( 0, 0, 0 ), ( 0, 0, 0 ) ); + playsoundatposition( "zmb_teleporter_tele_3d", self.origin ); + level notify( "player_teleported" ); + level thread stargate_teleport_player( self.target, e_player ); + } + } +} + +stargate_teleport_enable( n_index ) +{ + flag_set( "enable_teleporter_" + n_index ); +} + +stargate_teleport_disable( n_index ) +{ + flag_clear( "enable_teleporter_" + n_index ); +} + +stargate_play_fx() +{ + self.e_fx setclientfield( "teleporter_fx", 1 ); + self waittill( "stop_teleport_fx" ); + self.e_fx setclientfield( "teleporter_fx", 0 ); +} + +spawn_stargate_fx_origins() +{ + a_teleport_positions = getstructarray( "teleport_room", "script_noteworthy" ); + _a406 = a_teleport_positions; + _k406 = getFirstArrayKey( _a406 ); + while ( isDefined( _k406 ) ) + { + s_teleport = _a406[ _k406 ]; + v_fx_pos = ( s_teleport.origin + ( 0, 0, 64 ) ) + ( anglesToForward( s_teleport.angles ) * 120 ); + s_teleport.e_fx = spawn( "script_model", v_fx_pos ); + s_teleport.e_fx setmodel( "tag_origin" ); + s_teleport.e_fx.angles = s_teleport.angles + vectorScale( ( 0, 0, 0 ), 180 ); + _k406 = getNextArrayKey( _a406, _k406 ); + } +} + +stargate_teleport_player( str_teleport_to, player, n_teleport_time_sec, show_fx ) +{ + if ( !isDefined( n_teleport_time_sec ) ) + { + n_teleport_time_sec = 2; + } + if ( !isDefined( show_fx ) ) + { + show_fx = 1; + } + player.teleporting = 1; + if ( show_fx ) + { + player thread fadetoblackforxsec( 0, 0,3, 0, 0,5, "white" ); + wait_network_frame(); + } + n_pos = player.characterindex; + prone_offset = vectorScale( ( 0, 0, 0 ), 49 ); + crouch_offset = vectorScale( ( 0, 0, 0 ), 20 ); + stand_offset = ( 0, 0, 0 ); + image_room = getstruct( "teleport_room_" + n_pos, "targetname" ); + player disableoffhandweapons(); + player disableweapons(); + player freezecontrols( 1 ); + wait_network_frame(); + if ( player getstance() == "prone" ) + { + desired_origin = image_room.origin + prone_offset; + } + else if ( player getstance() == "crouch" ) + { + desired_origin = image_room.origin + crouch_offset; + } + else + { + desired_origin = image_room.origin + stand_offset; + } + player.teleport_origin = spawn( "script_model", player.origin ); + player.teleport_origin setmodel( "tag_origin" ); + player.teleport_origin.angles = player.angles; + player playerlinktoabsolute( player.teleport_origin, "tag_origin" ); + player.teleport_origin.origin = desired_origin; + player.teleport_origin.angles = image_room.angles; + if ( show_fx ) + { + player playsoundtoplayer( "zmb_teleporter_tele_2d", player ); + } + wait_network_frame(); + player.teleport_origin.angles = image_room.angles; + if ( show_fx ) + { + image_room thread stargate_play_fx(); + } + wait n_teleport_time_sec; + if ( show_fx ) + { + player thread fadetoblackforxsec( 0, 0,3, 0, 0,5, "white" ); + wait_network_frame(); + } + image_room notify( "stop_teleport_fx" ); + a_pos = getstructarray( str_teleport_to, "targetname" ); + s_pos = get_free_teleport_pos( player, a_pos ); + player unlink(); + if ( isDefined( player.teleport_origin ) ) + { + player.teleport_origin delete(); + player.teleport_origin = undefined; + } + player setorigin( s_pos.origin ); + player setplayerangles( s_pos.angles ); + player enableweapons(); + player enableoffhandweapons(); + player freezecontrols( 0 ); + player.teleporting = 0; +} + +is_teleport_landing_valid( s_pos, n_radius ) +{ + n_radius_sq = n_radius * n_radius; + a_players = getplayers(); + _a514 = a_players; + _k514 = getFirstArrayKey( _a514 ); + while ( isDefined( _k514 ) ) + { + e_player = _a514[ _k514 ]; + if ( distance2dsquared( s_pos.origin, e_player.origin ) < n_radius_sq ) + { + return 0; + } + _k514 = getNextArrayKey( _a514, _k514 ); + } + return 1; +} + +get_free_teleport_pos( player, a_structs ) +{ + n_player_radius = 64; + while ( 1 ) + { + a_players = getplayers(); + _a534 = a_structs; + _k534 = getFirstArrayKey( _a534 ); + while ( isDefined( _k534 ) ) + { + s_pos = _a534[ _k534 ]; + if ( is_teleport_landing_valid( s_pos, n_player_radius ) ) + { + return s_pos; + } + _k534 = getNextArrayKey( _a534, _k534 ); + } + wait 0,05; + } +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_utility.gsc b/zm_tomb_patch/maps/mp/zm_tomb_utility.gsc new file mode 100644 index 0000000..bd983ed --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_utility.gsc @@ -0,0 +1,1923 @@ +#include maps/mp/zm_tomb_craftables; +#include maps/mp/zm_tomb_tank; +#include maps/mp/zm_tomb_challenges; +#include maps/mp/zombies/_zm_challenges; +#include maps/mp/zm_tomb_chamber; +#include maps/mp/zombies/_zm_zonemgr; +#include maps/mp/zombies/_zm_unitrigger; +#include maps/mp/animscripts/zm_shared; +#include maps/mp/zombies/_zm_ai_basic; +#include maps/mp/zm_tomb_vo; +#include maps/mp/zm_tomb_teleporter; +#include maps/mp/zombies/_zm_equipment; +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/zombies/_zm_net; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +setup_devgui() +{ +/# + execdevgui( "devgui_zombie_tomb" ); + level.custom_devgui = ::zombie_devgui_tomb; + setdvar( "complete_puzzles1", "off" ); + setdvar( "complete_puzzles2", "off" ); + setdvar( "open_all_teleporters", "off" ); + setdvar( "show_craftable_locations", "off" ); + setdvar( "show_morse_code", "off" ); + setdvar( "sam_intro_skip", "off" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Quest:1/Open All Teleporters:1" "open_all_teleporters on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Quest:1/Skip Chamber Puzzles:2" "complete_puzzles1 on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Quest:1/Skip Top-side Puzzles:3" "complete_puzzles2 on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Quest:1/Show Craftable Locations:4" "show_craftable_locations on "\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Quest:1/Skip Samantha Intro:5" "sam_intro_skip on"\n" ); + adddebugcommand( "devgui_cmd "Zombies:2/Tomb:1/Easter Ann:3/Show Morse Code:1" "show_morse_code on "\n" ); + level thread watch_devgui_quadrotor(); + level thread watch_devgui_complete_puzzles(); + level thread watch_for_upgraded_staffs(); +#/ +} + +zombie_devgui_tomb( cmd ) +{ +/# + cmd_strings = strtok( cmd, " " ); + switch( cmd_strings[ 0 ] ) + { + case "force_recapture_start": + level notify( "force_recapture_start" ); + break; + case "force_capture_zone_1": + case "force_capture_zone_2": + case "force_capture_zone_3": + case "force_capture_zone_4": + case "force_capture_zone_5": + case "force_capture_zone_6": + level notify( "force_zone_capture" ); + break; + case "force_recapture_zone_1": + case "force_recapture_zone_2": + case "force_recapture_zone_3": + case "force_recapture_zone_4": + case "force_recapture_zone_5": + case "force_recapture_zone_6": + level notify( "force_zone_recapture" ); + break; + } +#/ +} + +watch_for_upgraded_staffs() +{ +/# + cmd = ""; + while ( 1 ) + { + wait 0,25; + while ( !isDefined( level.zombie_devgui_gun ) || level.zombie_devgui_gun != cmd ) + { + a_players = get_players(); + _a102 = a_players; + _k102 = getFirstArrayKey( _a102 ); + while ( isDefined( _k102 ) ) + { + player = _a102[ _k102 ]; + has_upgraded_staff = 0; + a_str_weapons = player getweaponslist(); + _a107 = a_str_weapons; + _k107 = getFirstArrayKey( _a107 ); + while ( isDefined( _k107 ) ) + { + str_weapon = _a107[ _k107 ]; + if ( is_weapon_upgraded_staff( str_weapon ) ) + { + has_upgraded_staff = 1; + } + _k107 = getNextArrayKey( _a107, _k107 ); + } + if ( has_upgraded_staff ) + { + player update_staff_accessories(); + } + _k102 = getNextArrayKey( _a102, _k102 ); + } + } +#/ + } +} + +watch_devgui_complete_puzzles() +{ +/# + while ( 1 ) + { + if ( getDvar( "complete_puzzles1" ) == "on" || getDvar( "complete_puzzles2" ) == "on" ) + { + flag_set( "air_puzzle_1_complete" ); + flag_set( "ice_puzzle_1_complete" ); + flag_set( "electric_puzzle_1_complete" ); + flag_set( "fire_puzzle_1_complete" ); + flag_set( "chamber_puzzle_cheat" ); + setdvar( "complete_puzzles1", "off" ); + level notify( "open_all_gramophone_doors" ); + } + if ( getDvar( "show_morse_code" ) == "on" ) + { + flag_set( "show_morse_code" ); + setdvar( "show_morse_code", "off" ); + } + if ( getDvar( "complete_puzzles2" ) == "on" ) + { + flag_set( "air_puzzle_2_complete" ); + flag_set( "ice_puzzle_2_complete" ); + flag_set( "electric_puzzle_2_complete" ); + flag_set( "fire_puzzle_2_complete" ); + flag_set( "chamber_puzzle_cheat" ); + flag_set( "staff_air_zm_upgrade_unlocked" ); + flag_set( "staff_water_zm_upgrade_unlocked" ); + flag_set( "staff_fire_zm_upgrade_unlocked" ); + flag_set( "staff_lightning_zm_upgrade_unlocked" ); + setdvar( "complete_puzzles2", "off" ); + } + if ( getDvar( "sam_intro_skip" ) == "on" ) + { + flag_set( "samantha_intro_done" ); + setdvar( "sam_intro_skip", "off" ); + } + if ( getDvar( "open_all_teleporters" ) == "on" ) + { + maps/mp/zm_tomb_teleporter::stargate_teleport_enable( 1 ); + maps/mp/zm_tomb_teleporter::stargate_teleport_enable( 2 ); + maps/mp/zm_tomb_teleporter::stargate_teleport_enable( 3 ); + maps/mp/zm_tomb_teleporter::stargate_teleport_enable( 4 ); + setdvar( "open_all_teleporters", "off" ); + flag_set( "activate_zone_chamber" ); + } + wait 0,5; +#/ + } +} + +get_teleport_fx_from_enum( n_enum ) +{ + switch( n_enum ) + { + case 1: + return "teleport_fire"; + case 4: + return "teleport_ice"; + case 3: + return "teleport_elec"; + case 2: + default: + return "teleport_air"; + } +} + +watch_devgui_quadrotor() +{ +/# + while ( getDvar( #"7D075455" ) != "on" ) + { + wait 0,1; + } + players = getplayers(); + _a218 = players; + _k218 = getFirstArrayKey( _a218 ); + while ( isDefined( _k218 ) ) + { + player = _a218[ _k218 ]; + player set_player_equipment( "equip_dieseldrone_zm" ); + player giveweapon( "equip_dieseldrone_zm" ); + player setweaponammoclip( "equip_dieseldrone_zm", 1 ); + player thread show_equipment_hint( "equip_dieseldrone_zm" ); + player notify( "equip_dieseldrone_zm" + "_given" ); + player set_equipment_invisibility_to_player( "equip_dieseldrone_zm", 1 ); + player setactionslot( 1, "weapon", "equip_dieseldrone_zm" ); + _k218 = getNextArrayKey( _a218, _k218 ); +#/ + } +} + +include_craftable( craftable_struct ) +{ +/# + println( "ZM >> include_craftable = " + craftable_struct.name ); +#/ + maps/mp/zombies/_zm_craftables::include_zombie_craftable( craftable_struct ); +} + +is_craftable() +{ + return self maps/mp/zombies/_zm_craftables::is_craftable(); +} + +is_part_crafted( craftable_name, part_modelname ) +{ + return maps/mp/zombies/_zm_craftables::is_part_crafted( craftable_name, part_modelname ); +} + +wait_for_craftable( craftable_name ) +{ + level waittill( craftable_name + "_crafted", player ); + return player; +} + +check_solo_status() +{ + if ( getnumexpectedplayers() == 1 || !sessionmodeisonlinegame() && !sessionmodeisprivate() ) + { + level.is_forever_solo_game = 1; + } + else + { + level.is_forever_solo_game = 0; + } +} + +player_slow_movement_speed_monitor() +{ + self endon( "disconnect" ); + n_movescale_delta_no_perk = 0,4 / 4; + n_movescale_delta_staminup = 0,3 / 6; + n_new_move_scale = 1; + n_move_scale_delta = 1; + self.n_move_scale = n_new_move_scale; + while ( 1 ) + { + is_player_slowed = 0; + self.is_player_slowed = 0; + _a305 = level.a_e_slow_areas; + _k305 = getFirstArrayKey( _a305 ); + while ( isDefined( _k305 ) ) + { + area = _a305[ _k305 ]; + if ( self istouching( area ) ) + { + self setclientfieldtoplayer( "sndMudSlow", 1 ); + is_player_slowed = 1; + self.is_player_slowed = 1; + if ( isDefined( self.played_mud_vo ) && !self.played_mud_vo && isDefined( self.dontspeak ) && !self.dontspeak ) + { + self thread maps/mp/zm_tomb_vo::struggle_mud_vo(); + } + if ( self hasperk( "specialty_longersprint" ) ) + { + n_new_move_scale = 0,7; + n_move_scale_delta = n_movescale_delta_staminup; + } + else + { + n_new_move_scale = 0,6; + n_move_scale_delta = n_movescale_delta_no_perk; + } + break; + } + else + { + _k305 = getNextArrayKey( _a305, _k305 ); + } + } + if ( !is_player_slowed ) + { + self setclientfieldtoplayer( "sndMudSlow", 0 ); + self notify( "mud_slowdown_cleared" ); + n_new_move_scale = 1; + } + if ( self.n_move_scale != n_new_move_scale ) + { + if ( self.n_move_scale > ( n_new_move_scale + n_move_scale_delta ) ) + { + self.n_move_scale -= n_move_scale_delta; + } + else + { + self.n_move_scale = n_new_move_scale; + } + self setmovespeedscale( self.n_move_scale ); + } + wait 0,1; + } +} + +dug_zombie_spawn_init( animname_set ) +{ + if ( !isDefined( animname_set ) ) + { + animname_set = 0; + } + self.targetname = "zombie"; + self.script_noteworthy = undefined; + if ( !animname_set ) + { + self.animname = "zombie"; + } + if ( isDefined( get_gamemode_var( "pre_init_zombie_spawn_func" ) ) ) + { + self [[ get_gamemode_var( "pre_init_zombie_spawn_func" ) ]](); + } + self thread play_ambient_zombie_vocals(); + self.zmb_vocals_attack = "zmb_vocals_zombie_attack"; + self.ignoreall = 1; + self.ignoreme = 1; + self.allowdeath = 1; + self.force_gib = 1; + self.is_zombie = 1; + self.has_legs = 1; + self allowedstances( "stand" ); + self.zombie_damaged_by_bar_knockdown = 0; + self.gibbed = 0; + self.head_gibbed = 0; + self setphysparams( 15, 0, 72 ); + self.disablearrivals = 1; + self.disableexits = 1; + self.grenadeawareness = 0; + self.badplaceawareness = 0; + self.ignoresuppression = 1; + self.suppressionthreshold = 1; + self.nododgemove = 1; + self.dontshootwhilemoving = 1; + self.pathenemylookahead = 0; + self.badplaceawareness = 0; + self.chatinitialized = 0; + self.a.disablepain = 1; + self disable_react(); + if ( isDefined( level.zombie_health ) ) + { + self.maxhealth = level.zombie_health; + if ( isDefined( level.zombie_respawned_health ) && level.zombie_respawned_health.size > 0 ) + { + self.health = level.zombie_respawned_health[ 0 ]; + arrayremovevalue( level.zombie_respawned_health, level.zombie_respawned_health[ 0 ] ); + } + else + { + self.health = level.zombie_health; + } + } + else + { + self.maxhealth = level.zombie_vars[ "zombie_health_start" ]; + self.health = self.maxhealth; + } + self.freezegun_damage = 0; + self.dropweapon = 0; + level thread zombie_death_event( self ); + self init_zombie_run_cycle(); + self thread dug_zombie_think(); + self thread zombie_gib_on_damage(); + self thread zombie_damage_failsafe(); + self thread enemy_death_detection(); + if ( isDefined( level._zombie_custom_spawn_logic ) ) + { + if ( isarray( level._zombie_custom_spawn_logic ) ) + { + i = 0; + while ( i < level._zombie_custom_spawn_logic.size ) + { + self thread [[ level._zombie_custom_spawn_logic[ i ] ]](); + i++; + } + } + else self thread [[ level._zombie_custom_spawn_logic ]](); + } + if ( !isDefined( self.no_eye_glow ) || !self.no_eye_glow ) + { + if ( isDefined( self.is_inert ) && !self.is_inert ) + { + self thread delayed_zombie_eye_glow(); + } + } + self.deathfunction = ::zombie_death_animscript; + self.flame_damage_time = 0; + self.meleedamage = 60; + self.no_powerups = 1; + self zombie_history( "zombie_spawn_init -> Spawned = " + self.origin ); + self.thundergun_knockdown_func = level.basic_zombie_thundergun_knockdown; + self.tesla_head_gib_func = ::zombie_tesla_head_gib; + self.team = level.zombie_team; + if ( isDefined( get_gamemode_var( "post_init_zombie_spawn_func" ) ) ) + { + self [[ get_gamemode_var( "post_init_zombie_spawn_func" ) ]](); + } + if ( isDefined( level.zombie_init_done ) ) + { + self [[ level.zombie_init_done ]](); + } + self.zombie_init_done = 1; + self notify( "zombie_init_done" ); +} + +dug_zombie_think() +{ + self endon( "death" ); +/# + assert( !self.isdog ); +#/ + self.ai_state = "zombie_think"; + find_flesh_struct_string = undefined; + self waittill( "zombie_custom_think_done", find_flesh_struct_string ); + node = undefined; + desired_nodes = []; + self.entrance_nodes = []; + if ( isDefined( level.max_barrier_search_dist_override ) ) + { + max_dist = level.max_barrier_search_dist_override; + } + else + { + max_dist = 500; + } + if ( !isDefined( find_flesh_struct_string ) && isDefined( self.target ) && self.target != "" ) + { + desired_origin = get_desired_origin(); +/# + assert( isDefined( desired_origin ), "Spawner @ " + self.origin + " has a .target but did not find a target" ); +#/ + origin = desired_origin; + node = getclosest( origin, level.exterior_goals ); + self.entrance_nodes[ self.entrance_nodes.size ] = node; + self zombie_history( "zombie_think -> #1 entrance (script_forcegoal) origin = " + self.entrance_nodes[ 0 ].origin ); + } + else + { + if ( self should_skip_teardown( find_flesh_struct_string ) ) + { + self zombie_setup_attack_properties(); + if ( isDefined( self.target ) ) + { + end_at_node = getnode( self.target, "targetname" ); + if ( isDefined( end_at_node ) ) + { + self setgoalnode( end_at_node ); + self waittill( "goal" ); + } + } + if ( isDefined( self.start_inert ) && self.start_inert ) + { + self thread maps/mp/zombies/_zm_ai_basic::start_inert( 1 ); + self zombie_complete_emerging_into_playable_area(); + } + else + { + self thread maps/mp/zombies/_zm_ai_basic::find_flesh(); + self thread dug_zombie_entered_playable(); + } + return; + } + else if ( isDefined( find_flesh_struct_string ) ) + { +/# + assert( isDefined( find_flesh_struct_string ) ); +#/ + i = 0; + while ( i < level.exterior_goals.size ) + { + if ( level.exterior_goals[ i ].script_string == find_flesh_struct_string ) + { + node = level.exterior_goals[ i ]; + break; + } + else + { + i++; + } + } + self.entrance_nodes[ self.entrance_nodes.size ] = node; + self zombie_history( "zombie_think -> #1 entrance origin = " + node.origin ); + self thread zombie_assure_node(); + } + else + { + origin = self.origin; + desired_origin = get_desired_origin(); + if ( isDefined( desired_origin ) ) + { + origin = desired_origin; + } + nodes = get_array_of_closest( origin, level.exterior_goals, undefined, 3 ); + desired_nodes[ 0 ] = nodes[ 0 ]; + prev_dist = distance( self.origin, nodes[ 0 ].origin ); + i = 1; + while ( i < nodes.size ) + { + dist = distance( self.origin, nodes[ i ].origin ); + if ( ( dist - prev_dist ) > max_dist ) + { + break; + } + else + { + prev_dist = dist; + desired_nodes[ i ] = nodes[ i ]; + i++; + } + } + node = desired_nodes[ 0 ]; + if ( desired_nodes.size > 1 ) + { + node = desired_nodes[ randomint( desired_nodes.size ) ]; + } + self.entrance_nodes = desired_nodes; + self zombie_history( "zombie_think -> #1 entrance origin = " + node.origin ); + self thread zombie_assure_node(); + } + } +/# + assert( isDefined( node ), "Did not find a node!!! [Should not see this!]" ); +#/ + level thread draw_line_ent_to_pos( self, node.origin, "goal" ); + self.first_node = node; + self thread zombie_goto_entrance( node ); +} + +dug_zombie_entered_playable() +{ + self endon( "death" ); + if ( !isDefined( level.playable_areas ) ) + { + level.playable_areas = getentarray( "player_volume", "script_noteworthy" ); + } + while ( 1 ) + { + _a671 = level.playable_areas; + _k671 = getFirstArrayKey( _a671 ); + while ( isDefined( _k671 ) ) + { + area = _a671[ _k671 ]; + if ( self istouching( area ) ) + { + self dug_zombie_complete_emerging_into_playable_area(); + return; + } + _k671 = getNextArrayKey( _a671, _k671 ); + } + wait 1; + } +} + +dug_zombie_complete_emerging_into_playable_area() +{ + self.completed_emerging_into_playable_area = 1; + self notify( "completed_emerging_into_playable_area" ); + self.no_powerups = 1; + self thread zombie_free_cam_allowed(); +} + +dug_zombie_rise( spot, func_rise_fx ) +{ + if ( !isDefined( func_rise_fx ) ) + { + func_rise_fx = ::zombie_rise_fx; + } + self endon( "death" ); + self.in_the_ground = 1; + self.no_eye_glow = 1; + self.anchor = spawn( "script_origin", self.origin ); + self.anchor.angles = self.angles; + self linkto( self.anchor ); + if ( !isDefined( spot.angles ) ) + { + spot.angles = ( 0, 0, 1 ); + } + anim_org = spot.origin; + anim_ang = spot.angles; + self ghost(); + self.anchor moveto( anim_org, 0,05 ); + self.anchor waittill( "movedone" ); + target_org = get_desired_origin(); + if ( isDefined( target_org ) ) + { + anim_ang = vectorToAngle( target_org - self.origin ); + self.anchor rotateto( ( 0, anim_ang[ 1 ], 0 ), 0,05 ); + self.anchor waittill( "rotatedone" ); + } + self unlink(); + if ( isDefined( self.anchor ) ) + { + self.anchor delete(); + } + self thread hide_pop(); + level thread zombie_rise_death( self, spot ); + spot thread [[ func_rise_fx ]]( self ); + substate = 0; + if ( self.zombie_move_speed == "walk" ) + { + substate = randomint( 2 ); + } + else if ( self.zombie_move_speed == "run" ) + { + substate = 2; + } + else + { + if ( self.zombie_move_speed == "sprint" ) + { + substate = 3; + } + } + self orientmode( "face default" ); + self playsound( "zmb_vocals_capzomb_spawn" ); + self animscripted( self.origin, spot.angles, "zm_dug_rise" ); + self maps/mp/animscripts/zm_shared::donotetracks( "rise_anim", ::handle_rise_notetracks, spot ); + self.no_eye_glow = 0; + self thread zombie_eye_glow(); + self notify( "rise_anim_finished" ); + spot notify( "stop_zombie_rise_fx" ); + self.in_the_ground = 0; + self notify( "risen" ); +} + +is_weapon_upgraded_staff( weapon ) +{ + if ( weapon == "staff_water_upgraded_zm" ) + { + return 1; + } + else + { + if ( weapon == "staff_lightning_upgraded_zm" ) + { + return 1; + } + else + { + if ( weapon == "staff_fire_upgraded_zm" ) + { + return 1; + } + else + { + if ( weapon == "staff_air_upgraded_zm" ) + { + return 1; + } + } + } + } + return 0; +} + +watch_staff_usage() +{ + self notify( "watch_staff_usage" ); + self endon( "watch_staff_usage" ); + self endon( "disconnect" ); + self setclientfieldtoplayer( "player_staff_charge", 0 ); + while ( 1 ) + { + self waittill( "weapon_change", weapon ); + has_upgraded_staff = 0; + has_revive_staff = 0; + weapon_is_upgraded_staff = is_weapon_upgraded_staff( weapon ); + str_upgraded_staff_weapon = undefined; + a_str_weapons = self getweaponslist(); + _a820 = a_str_weapons; + _k820 = getFirstArrayKey( _a820 ); + while ( isDefined( _k820 ) ) + { + str_weapon = _a820[ _k820 ]; + if ( is_weapon_upgraded_staff( str_weapon ) ) + { + has_upgraded_staff = 1; + str_upgraded_staff_weapon = str_weapon; + } + if ( str_weapon == "staff_revive_zm" ) + { + has_revive_staff = 1; + } + _k820 = getNextArrayKey( _a820, _k820 ); + } +/# + if ( has_upgraded_staff && !has_revive_staff ) + { + has_revive_staff = 1; +#/ + } + if ( has_upgraded_staff && !has_revive_staff ) + { + self takeweapon( str_upgraded_staff_weapon ); + has_upgraded_staff = 0; + } + if ( !has_upgraded_staff && has_revive_staff ) + { + self takeweapon( "staff_revive_zm" ); + has_revive_staff = 0; + } + if ( !has_revive_staff || !weapon_is_upgraded_staff && weapon != "none" && weaponaltweaponname( weapon ) != "none" ) + { + self setactionslot( 3, "altmode" ); + } + else + { + self setactionslot( 3, "weapon", "staff_revive_zm" ); + } + if ( weapon_is_upgraded_staff ) + { + self thread staff_charge_watch_wrapper( weapon ); + } + } +} + +staff_charge_watch() +{ + self endon( "disconnect" ); + self endon( "player_downed" ); + self endon( "weapon_change" ); + self endon( "weapon_fired" ); + while ( !self attackbuttonpressed() ) + { + wait 0,05; + } + n_old_charge = 0; + while ( 1 ) + { + if ( n_old_charge != self.chargeshotlevel ) + { + self setclientfieldtoplayer( "player_staff_charge", self.chargeshotlevel ); + n_old_charge = self.chargeshotlevel; + } + wait 0,1; + } +} + +staff_charge_watch_wrapper( weapon ) +{ + self notify( "staff_charge_watch_wrapper" ); + self endon( "staff_charge_watch_wrapper" ); + self endon( "disconnect" ); + self setclientfieldtoplayer( "player_staff_charge", 0 ); + while ( is_weapon_upgraded_staff( weapon ) ) + { + self staff_charge_watch(); + self setclientfieldtoplayer( "player_staff_charge", 0 ); + weapon = self getcurrentweapon(); + } +} + +door_record_hint() +{ + hud = setting_tutorial_hud(); + hud settext( &"ZM_TOMB_RU" ); + wait 3; + hud destroy(); +} + +swap_staff_hint() +{ + level notify( "staff_Hint" ); + hud = setting_tutorial_hud(); + hud settext( &"ZM_TOMB_OSO" ); + level waittill_any_or_timeout( 3, "staff_hint" ); + hud destroy(); +} + +door_gramophone_elsewhere_hint() +{ + hud = setting_tutorial_hud(); + hud settext( &"ZM_TOMB_GREL" ); + wait 3; + hud destroy(); +} + +puzzle_debug_position( string_to_show, color, origin, str_dvar, n_show_time ) +{ +/# + self endon( "death" ); + self endon( "stop_debug_position" ); + if ( !isDefined( string_to_show ) ) + { + string_to_show = "+"; + } + if ( !isDefined( color ) ) + { + color = vectorScale( ( 0, 0, 1 ), 255 ); + } + while ( isDefined( str_dvar ) ) + { + while ( getDvar( "show_craftable_locations" ) != "on" ) + { + wait 1; + } + } + while ( 1 ) + { + if ( isDefined( origin ) ) + { + where_to_draw = origin; + } + else + { + where_to_draw = self.origin; + } + print3d( where_to_draw, string_to_show, color, 1 ); + wait 0,1; + if ( isDefined( n_show_time ) ) + { + n_show_time -= 0,1; + if ( n_show_time <= 0 ) + { + return; + } + } + else + { +#/ + } + } +} + +placeholder_puzzle_delete_ent( str_flag_name ) +{ + self endon( "death" ); + flag_wait( str_flag_name ); + self delete(); +} + +placeholder_puzzle_spin_model() +{ + self endon( "death" ); + while ( 1 ) + { + self rotateyaw( 360, 10, 0, 0 ); + wait 9,9; + } +} + +setting_tutorial_hud() +{ + client_hint = newclienthudelem( self ); + client_hint.alignx = "center"; + client_hint.aligny = "middle"; + client_hint.horzalign = "center"; + client_hint.vertalign = "bottom"; + client_hint.y = -120; + client_hint.foreground = 1; + client_hint.font = "default"; + client_hint.fontscale = 1,5; + client_hint.alpha = 1; + client_hint.color = ( 0, 0, 1 ); + return client_hint; +} + +tomb_trigger_update_message( func_per_player_msg ) +{ + a_players = getplayers(); + _a1041 = a_players; + _k1041 = getFirstArrayKey( _a1041 ); + while ( isDefined( _k1041 ) ) + { + e_player = _a1041[ _k1041 ]; + n_player = e_player getentitynumber(); + if ( !isDefined( self.stub.playertrigger[ n_player ] ) ) + { + } + else + { + new_msg = self [[ func_per_player_msg ]]( e_player ); + self.stub.playertrigger[ n_player ].stored_hint_string = new_msg; + self.stub.playertrigger[ n_player ] sethintstring( new_msg ); + } + _k1041 = getNextArrayKey( _a1041, _k1041 ); + } +} + +set_unitrigger_hint_string( str_message ) +{ + self.hint_string = str_message; + maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( self ); + maps/mp/zombies/_zm_unitrigger::register_unitrigger( self, ::tomb_unitrigger_think ); +} + +tomb_spawn_trigger_radius( origin, radius, use_trigger, func_per_player_msg ) +{ + if ( !isDefined( use_trigger ) ) + { + use_trigger = 0; + } + trigger_stub = spawnstruct(); + trigger_stub.origin = origin; + trigger_stub.radius = radius; + if ( use_trigger ) + { + trigger_stub.cursor_hint = "HINT_NOICON"; + trigger_stub.script_unitrigger_type = "unitrigger_radius_use"; + } + else + { + trigger_stub.script_unitrigger_type = "unitrigger_radius"; + } + if ( isDefined( func_per_player_msg ) ) + { + trigger_stub.func_update_msg = func_per_player_msg; + maps/mp/zombies/_zm_unitrigger::unitrigger_force_per_player_triggers( trigger_stub, 1 ); + } + maps/mp/zombies/_zm_unitrigger::register_unitrigger( trigger_stub, ::tomb_unitrigger_think ); + return trigger_stub; +} + +tomb_unitrigger_think() +{ + self endon( "kill_trigger" ); + if ( isDefined( self.stub.func_update_msg ) ) + { + self thread tomb_trigger_update_message( self.stub.func_update_msg ); + } + while ( 1 ) + { + self waittill( "trigger", player ); + self.stub notify( "trigger" ); + } +} + +tomb_unitrigger_delete() +{ + maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( self ); + self structdelete(); +} + +zombie_gib_all() +{ + if ( !isDefined( self ) ) + { + return; + } + if ( isDefined( self.is_mechz ) && self.is_mechz ) + { + return; + } + a_gib_ref = []; + a_gib_ref[ 0 ] = level._zombie_gib_piece_index_all; + self gib( "normal", a_gib_ref ); + self ghost(); + wait 0,4; + if ( isDefined( self ) ) + { + self self_delete(); + } +} + +zombie_gib_guts() +{ + if ( !isDefined( self ) ) + { + return; + } + if ( isDefined( self.is_mechz ) && self.is_mechz ) + { + return; + } + v_origin = self gettagorigin( "J_SpineLower" ); + if ( isDefined( v_origin ) ) + { + v_forward = anglesToForward( ( 0, randomint( 360 ), 0 ) ); + playfx( level._effect[ "zombie_guts_explosion" ], v_origin, v_forward ); + } + wait_network_frame(); + if ( isDefined( self ) ) + { + self ghost(); + wait randomfloatrange( 0,4, 1,1 ); + if ( isDefined( self ) ) + { + self self_delete(); + } + } +} + +link_platform_nodes( nd_1, nd_2 ) +{ + if ( !nodesarelinked( nd_1, nd_2 ) ) + { + link_nodes( nd_1, nd_2 ); + } + if ( !nodesarelinked( nd_2, nd_1 ) ) + { + link_nodes( nd_2, nd_1 ); + } +} + +unlink_platform_nodes( nd_1, nd_2 ) +{ + if ( nodesarelinked( nd_1, nd_2 ) ) + { + unlink_nodes( nd_1, nd_2 ); + } + if ( nodesarelinked( nd_2, nd_1 ) ) + { + unlink_nodes( nd_2, nd_1 ); + } +} + +init_weather_manager() +{ + level.weather_snow = 0; + level.weather_rain = 0; + level.weather_fog = 0; + level.weather_vision = 0; + level thread weather_manager(); + level thread rotate_skydome(); + onplayerconnect_callback( ::set_weather_to_player ); + level.force_weather = []; + if ( cointoss() ) + { + level.force_weather[ 3 ] = "snow"; + } + else + { + level.force_weather[ 4 ] = "snow"; + } + i = 5; + while ( i <= 9 ) + { + if ( cointoss() ) + { + level.force_weather[ i ] = "none"; + i++; + continue; + } + else + { + level.force_weather[ i ] = "rain"; + } + i++; + } + level.force_weather[ 10 ] = "snow"; +} + +randomize_weather() +{ + weather_name = level.force_weather[ level.round_number ]; + if ( !isDefined( weather_name ) ) + { + n_round_weather = randomint( 100 ); + rounds_since_snow = level.round_number - level.last_snow_round; + rounds_since_rain = level.round_number - level.last_rain_round; + if ( n_round_weather < 40 || rounds_since_snow > 3 ) + { + weather_name = "snow"; + } + else + { + if ( n_round_weather < 80 || rounds_since_rain > 4 ) + { + weather_name = "rain"; + } + else + { + weather_name = "none"; + } + } + } + if ( weather_name == "snow" ) + { + level.weather_snow = randomintrange( 1, 5 ); + level.weather_rain = 0; + level.weather_vision = 2; + level.last_snow_round = level.round_number; + } + else if ( weather_name == "rain" ) + { + level.weather_snow = 0; + level.weather_rain = randomintrange( 1, 5 ); + level.weather_vision = 1; + level.last_rain_round = level.round_number; + } + else + { + level.weather_snow = 0; + level.weather_rain = 0; + level.weather_vision = 3; + } +} + +weather_manager() +{ + level.last_snow_round = 0; + level.last_rain_round = 0; + while ( 1 ) + { + level waittill( "end_of_round" ); + randomize_weather(); + level setclientfield( "rain_level", level.weather_rain ); + level setclientfield( "snow_level", level.weather_snow ); + wait 2; + _a1330 = getplayers(); + _k1330 = getFirstArrayKey( _a1330 ); + while ( isDefined( _k1330 ) ) + { + player = _a1330[ _k1330 ]; + if ( is_player_valid( player, 0, 1 ) ) + { + player set_weather_to_player(); + } + _k1330 = getNextArrayKey( _a1330, _k1330 ); + } + } +} + +set_weather_to_player() +{ + self setclientfieldtoplayer( "player_weather_visionset", level.weather_vision ); +} + +rotate_skydome() +{ + level.sky_rotation = 360; + while ( 1 ) + { + level.sky_rotation -= 0,025; + if ( level.sky_rotation < 0 ) + { + level.sky_rotation += 360; + } + setdvar( "r_skyRotation", level.sky_rotation ); + wait 0,1; + } +} + +play_puzzle_stinger_on_all_players() +{ + players = getplayers(); + _a1367 = players; + _k1367 = getFirstArrayKey( _a1367 ); + while ( isDefined( _k1367 ) ) + { + player = _a1367[ _k1367 ]; + player playsound( "zmb_squest_step2_finished" ); + _k1367 = getNextArrayKey( _a1367, _k1367 ); + } +} + +puzzle_orb_move( v_to_pos ) +{ + dist = distance( self.origin, v_to_pos ); + if ( dist == 0 ) + { + return; + } + movetime = dist / 300; + self moveto( v_to_pos, movetime, 0, 0 ); + self waittill( "movedone" ); +} + +puzzle_orb_follow_path( s_start ) +{ + s_next_pos = s_start; + while ( isDefined( s_next_pos ) ) + { + self puzzle_orb_move( s_next_pos.origin ); + if ( isDefined( s_next_pos.target ) ) + { + s_next_pos = getstruct( s_next_pos.target, "targetname" ); + continue; + } + else + { + s_next_pos = undefined; + } + } +} + +puzzle_orb_follow_return_path( s_start, n_element ) +{ + a_path = []; + s_next = s_start; + while ( isDefined( s_next ) ) + { + a_path[ a_path.size ] = s_next; + if ( isDefined( s_next.target ) ) + { + s_next = getstruct( s_next.target, "targetname" ); + continue; + } + else + { + s_next = undefined; + } + } + v_start = a_path[ a_path.size - 1 ].origin + vectorScale( ( 0, 0, 1 ), 1000 ); + e_model = spawn( "script_model", v_start ); + e_model setmodel( s_start.model ); + e_model setclientfield( "element_glow_fx", n_element ); + playfxontag( level._effect[ "puzzle_orb_trail" ], e_model, "tag_origin" ); + i = a_path.size - 1; + while ( i >= 0 ) + { + e_model puzzle_orb_move( a_path[ i ].origin ); + i--; + + } + return e_model; +} + +puzzle_orb_pillar_show() +{ + level notify( "sky_pillar_reset" ); + level endon( "sky_pillar_reset" ); + s_pillar = getstruct( "crypt_pillar", "targetname" ); + exploder( 333 ); + if ( isDefined( s_pillar.e_model ) ) + { + s_pillar.e_model delete(); + } + s_pillar.e_model = spawn( "script_model", s_pillar.origin ); + s_pillar.e_model endon( "death" ); + s_pillar.e_model ghost(); + s_pillar.e_model setmodel( "fxuse_sky_pillar_new" ); + s_pillar.e_model setclientfield( "sky_pillar", 1 ); + wait_network_frame(); + s_pillar.e_model show(); + wait 1; + wait 27,5; + s_pillar.e_model setclientfield( "sky_pillar", 0 ); + wait 1; + s_pillar.e_model delete(); +} + +any_player_looking_at_plinth( min_lookat_dot, n_near_dist_sq ) +{ + players = getplayers(); + _a1482 = players; + _k1482 = getFirstArrayKey( _a1482 ); + while ( isDefined( _k1482 ) ) + { + player = _a1482[ _k1482 ]; + dist_sq = distance2dsquared( player.origin, self.origin ); + if ( dist_sq < n_near_dist_sq ) + { + fvec = anglesToForward( player.angles ); + to_self = self.origin - player.origin; + to_self = vectornormalize( to_self ); + dot_to_self = vectordot( to_self, fvec ); + if ( dot_to_self > min_lookat_dot ) + { + return 1; + } + } + _k1482 = getNextArrayKey( _a1482, _k1482 ); + } + return 0; +} + +puzzle_orb_ready_to_leave( str_zone, min_lookat_dot, n_near_dist_sq ) +{ + if ( !level.zones[ str_zone ].is_occupied || flag( "chamber_puzzle_cheat" ) ) + { + return 1; + } + return any_player_looking_at_plinth( min_lookat_dot, n_near_dist_sq ); +} + +puzzle_orb_chamber_to_crypt( str_start_point, e_gem_pos ) +{ + a_puzzle_flags = strtok( e_gem_pos.script_flag, " " ); +/# + assert( a_puzzle_flags.size == 2 ); +#/ + _a1517 = a_puzzle_flags; + _k1517 = getFirstArrayKey( _a1517 ); + while ( isDefined( _k1517 ) ) + { + str_flag = _a1517[ _k1517 ]; +/# + assert( level flag_exists( str_flag ) ); +#/ + _k1517 = getNextArrayKey( _a1517, _k1517 ); + } + flag_wait( a_puzzle_flags[ 0 ] ); + s_start = getstruct( str_start_point, "targetname" ); + e_model = spawn( "script_model", s_start.origin ); + e_model setmodel( s_start.model ); + e_model.script_int = e_gem_pos.script_int; + wait_network_frame(); + e_model playsound( "zmb_squest_crystal_leave" ); + wait_network_frame(); + e_model playloopsound( "zmb_squest_crystal_loop", 1 ); + str_zone = maps/mp/zombies/_zm_zonemgr::get_zone_from_position( s_start.origin, 1 ); + time_looking_at_orb = 0; + min_lookat_dot = cos( 30 ); + n_near_dist_sq = 32400; + while ( time_looking_at_orb < 1 ) + { + wait 0,1; + if ( s_start puzzle_orb_ready_to_leave( str_zone, min_lookat_dot, n_near_dist_sq ) ) + { + time_looking_at_orb += 0,1; + continue; + } + else + { + time_looking_at_orb = 0; + } + } + wait_network_frame(); + playfxontag( level._effect[ "puzzle_orb_trail" ], e_model, "tag_origin" ); + wait_network_frame(); + s_next_pos = getstruct( s_start.target, "targetname" ); + e_model puzzle_orb_follow_path( s_next_pos ); + v_sky_pos = e_model.origin; + v_sky_pos = ( v_sky_pos[ 0 ], v_sky_pos[ 1 ], v_sky_pos[ 2 ] + 1000 ); + e_model puzzle_orb_move( v_sky_pos ); + e_model ghost(); + s_descend_start = getstruct( "orb_crypt_descent_path", "targetname" ); + v_pos_above_gem = s_descend_start.origin + vectorScale( ( 0, 0, 1 ), 3000 ); + e_model moveto( v_pos_above_gem, 0,05, 0, 0 ); + e_model waittill( "movedone" ); + flag_wait( a_puzzle_flags[ 1 ] ); + e_model show(); + level thread puzzle_orb_pillar_show(); + e_model puzzle_orb_follow_path( s_descend_start ); + flag_set( "disc_rotation_active" ); + e_model puzzle_orb_move( e_gem_pos.origin ); + e_model_nofx = spawn( "script_model", e_model.origin ); + e_model_nofx setmodel( e_model.model ); + e_model_nofx.script_int = e_gem_pos.script_int; + e_model delete(); + wait_network_frame(); + e_model_nofx playsound( "zmb_squest_crystal_arrive" ); + wait_network_frame(); + e_model_nofx playloopsound( "zmb_squest_crystal_loop", 1 ); + flag_clear( "disc_rotation_active" ); + return e_model_nofx; +} + +capture_zombie_spawn_init( animname_set ) +{ + if ( !isDefined( animname_set ) ) + { + animname_set = 0; + } + self.targetname = "capture_zombie_ai"; + if ( !animname_set ) + { + self.animname = "zombie"; + } + self.sndname = "capzomb"; + if ( isDefined( get_gamemode_var( "pre_init_zombie_spawn_func" ) ) ) + { + self [[ get_gamemode_var( "pre_init_zombie_spawn_func" ) ]](); + } + self thread play_ambient_zombie_vocals(); + self.zmb_vocals_attack = "zmb_vocals_capzomb_attack"; + self.no_damage_points = 1; + self.deathpoints_already_given = 1; + self.ignore_enemy_count = 1; + self.ignoreall = 1; + self.ignoreme = 1; + self.allowdeath = 1; + self.force_gib = 1; + self.is_zombie = 1; + self.has_legs = 1; + self allowedstances( "stand" ); + self.zombie_damaged_by_bar_knockdown = 0; + self.gibbed = 0; + self.head_gibbed = 0; + self.disablearrivals = 1; + self.disableexits = 1; + self.grenadeawareness = 0; + self.badplaceawareness = 0; + self.ignoresuppression = 1; + self.suppressionthreshold = 1; + self.nododgemove = 1; + self.dontshootwhilemoving = 1; + self.pathenemylookahead = 0; + self.badplaceawareness = 0; + self.chatinitialized = 0; + self.a.disablepain = 1; + self disable_react(); + if ( isDefined( level.zombie_health ) ) + { + self.maxhealth = level.zombie_health; + if ( isDefined( level.zombie_respawned_health ) && level.zombie_respawned_health.size > 0 ) + { + self.health = level.zombie_respawned_health[ 0 ]; + arrayremovevalue( level.zombie_respawned_health, level.zombie_respawned_health[ 0 ] ); + } + else + { + self.health = level.zombie_health; + } + } + else + { + self.maxhealth = level.zombie_vars[ "zombie_health_start" ]; + self.health = self.maxhealth; + } + self.freezegun_damage = 0; + self.dropweapon = 0; + level thread zombie_death_event( self ); + self set_zombie_run_cycle(); + self thread dug_zombie_think(); + self thread zombie_gib_on_damage(); + self thread zombie_damage_failsafe(); + self thread enemy_death_detection(); + if ( !isDefined( self.no_eye_glow ) || !self.no_eye_glow ) + { + if ( isDefined( self.is_inert ) && !self.is_inert ) + { + self thread delayed_zombie_eye_glow(); + } + } + self.deathfunction = ::zombie_death_animscript; + self.flame_damage_time = 0; + self.meleedamage = 60; + self.no_powerups = 1; + self zombie_history( "zombie_spawn_init -> Spawned = " + self.origin ); + self.thundergun_knockdown_func = level.basic_zombie_thundergun_knockdown; + self.tesla_head_gib_func = ::zombie_tesla_head_gib; + self.team = level.zombie_team; + if ( isDefined( get_gamemode_var( "post_init_zombie_spawn_func" ) ) ) + { + self [[ get_gamemode_var( "post_init_zombie_spawn_func" ) ]](); + } + self.zombie_init_done = 1; + self notify( "zombie_init_done" ); +} + +rumble_players_in_chamber( n_rumble_enum, n_rumble_time ) +{ + if ( !isDefined( n_rumble_time ) ) + { + n_rumble_time = 0,1; + } + a_players = getplayers(); + a_rumbled_players = []; + _a1753 = a_players; + _k1753 = getFirstArrayKey( _a1753 ); + while ( isDefined( _k1753 ) ) + { + e_player = _a1753[ _k1753 ]; + if ( maps/mp/zm_tomb_chamber::is_point_in_chamber( e_player.origin ) ) + { + e_player setclientfieldtoplayer( "player_rumble_and_shake", n_rumble_enum ); + a_rumbled_players[ a_rumbled_players.size ] = e_player; + } + _k1753 = getNextArrayKey( _a1753, _k1753 ); + } + wait n_rumble_time; + _a1764 = a_rumbled_players; + _k1764 = getFirstArrayKey( _a1764 ); + while ( isDefined( _k1764 ) ) + { + e_player = _a1764[ _k1764 ]; + e_player setclientfieldtoplayer( "player_rumble_and_shake", 0 ); + _k1764 = getNextArrayKey( _a1764, _k1764 ); + } +} + +rumble_nearby_players( v_center, n_range, n_rumble_enum ) +{ + n_range_sq = n_range * n_range; + a_players = getplayers(); + a_rumbled_players = []; + _a1775 = a_players; + _k1775 = getFirstArrayKey( _a1775 ); + while ( isDefined( _k1775 ) ) + { + e_player = _a1775[ _k1775 ]; + if ( distancesquared( v_center, e_player.origin ) < n_range_sq ) + { + e_player setclientfieldtoplayer( "player_rumble_and_shake", n_rumble_enum ); + a_rumbled_players[ a_rumbled_players.size ] = e_player; + } + _k1775 = getNextArrayKey( _a1775, _k1775 ); + } + wait_network_frame(); + _a1786 = a_rumbled_players; + _k1786 = getFirstArrayKey( _a1786 ); + while ( isDefined( _k1786 ) ) + { + e_player = _a1786[ _k1786 ]; + e_player setclientfieldtoplayer( "player_rumble_and_shake", 0 ); + _k1786 = getNextArrayKey( _a1786, _k1786 ); + } +} + +whirlwind_rumble_player( e_whirlwind, str_active_flag ) +{ + if ( isDefined( self.whirlwind_rumble_on ) && self.whirlwind_rumble_on ) + { + return; + } + self.whirlwind_rumble_on = 1; + n_rumble_level = 1; + self setclientfieldtoplayer( "player_rumble_and_shake", 4 ); + dist_sq = distancesquared( self.origin, e_whirlwind.origin ); + range_inner_sq = 10000; + range_sq = 90000; + while ( dist_sq < range_sq ) + { + wait 0,05; + if ( !isDefined( e_whirlwind ) ) + { + break; + } + else if ( isDefined( str_active_flag ) ) + { + if ( !flag( str_active_flag ) ) + { + break; + } + } + else + { + dist_sq = distancesquared( self.origin, e_whirlwind.origin ); + if ( n_rumble_level == 1 && dist_sq < range_inner_sq ) + { + n_rumble_level = 2; + self setclientfieldtoplayer( "player_rumble_and_shake", 5 ); + continue; + } + else + { + if ( n_rumble_level == 2 && dist_sq >= range_inner_sq ) + { + n_rumble_level = 1; + self setclientfieldtoplayer( "player_rumble_and_shake", 4 ); + } + } + } + } + self setclientfieldtoplayer( "player_rumble_and_shake", 0 ); + self.whirlwind_rumble_on = 0; +} + +whirlwind_rumble_nearby_players( str_active_flag ) +{ + range_sq = 90000; + while ( flag( str_active_flag ) ) + { + a_players = getplayers(); + _a1853 = a_players; + _k1853 = getFirstArrayKey( _a1853 ); + while ( isDefined( _k1853 ) ) + { + player = _a1853[ _k1853 ]; + dist_sq = distancesquared( self.origin, player.origin ); + if ( dist_sq < range_sq ) + { + player thread whirlwind_rumble_player( self, str_active_flag ); + } + _k1853 = getNextArrayKey( _a1853, _k1853 ); + } + wait_network_frame(); + } +} + +clean_up_bunker_doors() +{ + a_door_models = getentarray( "bunker_door", "script_noteworthy" ); + array_thread( a_door_models, ::bunker_door_clean_up ); +} + +bunker_door_clean_up() +{ + self waittill( "movedone" ); + self delete(); +} + +adjustments_for_solo() +{ + if ( isDefined( level.is_forever_solo_game ) && level.is_forever_solo_game ) + { + a_door_buys = getentarray( "zombie_door", "targetname" ); + array_thread( a_door_buys, ::door_price_reduction_for_solo ); + a_debris_buys = getentarray( "zombie_debris", "targetname" ); + array_thread( a_debris_buys, ::door_price_reduction_for_solo ); + change_weapon_cost( "beretta93r_zm", 750 ); + change_weapon_cost( "870mcs_zm", 750 ); + } +} + +door_price_reduction_for_solo() +{ + if ( self.zombie_cost >= 750 ) + { + self.zombie_cost -= 250; + if ( self.zombie_cost >= 2500 ) + { + self.zombie_cost -= 250; + } + if ( self.targetname == "zombie_door" ) + { + self set_hint_string( self, "default_buy_door", self.zombie_cost ); + return; + } + else + { + self set_hint_string( self, "default_buy_debris", self.zombie_cost ); + } + } +} + +change_weapon_cost( str_weapon, n_cost ) +{ + level.zombie_weapons[ str_weapon ].cost = n_cost; + level.zombie_weapons[ str_weapon ].ammo_cost = round_up_to_ten( int( n_cost * 0,5 ) ); +} + +zone_capture_powerup() +{ + while ( 1 ) + { + flag_wait( "zone_capture_in_progress" ); + flag_waitopen( "zone_capture_in_progress" ); + wait 2; + _a1945 = level.zone_capture.zones; + _k1945 = getFirstArrayKey( _a1945 ); + while ( isDefined( _k1945 ) ) + { + generator = _a1945[ _k1945 ]; + while ( generator ent_flag( "player_controlled" ) ) + { + _a1950 = level.a_uts_challenge_boxes; + _k1950 = getFirstArrayKey( _a1950 ); + while ( isDefined( _k1950 ) ) + { + uts_box = _a1950[ _k1950 ]; + if ( uts_box.str_location == "start_bunker" ) + { + if ( isDefined( level.is_forever_solo_game ) && level.is_forever_solo_game ) + { + level thread maps/mp/zombies/_zm_challenges::open_box( undefined, uts_box, ::maps/mp/zm_tomb_challenges::reward_powerup_double_points, -1 ); + } + else + { + level thread maps/mp/zombies/_zm_challenges::open_box( undefined, uts_box, ::maps/mp/zm_tomb_challenges::reward_powerup_zombie_blood, -1 ); + } + return; + } + _k1950 = getNextArrayKey( _a1950, _k1950 ); + } + } + _k1945 = getNextArrayKey( _a1945, _k1945 ); + } + } +} + +traversal_blocker() +{ + flag_wait( "activate_zone_nml" ); + m_traversal_blocker = getent( "traversal_blocker", "targetname" ); + m_traversal_blocker connectpaths(); + m_traversal_blocker delete(); +} + +_kill_zombie_network_safe_internal( e_attacker, str_weapon ) +{ + if ( !isDefined( self ) ) + { + return; + } + if ( !isalive( self ) ) + { + return; + } + self.staff_dmg = str_weapon; + self dodamage( self.health, self.origin, e_attacker, e_attacker, "none", self.kill_damagetype, 0, str_weapon ); +} + +_damage_zombie_network_safe_internal( e_attacker, str_weapon, n_damage_amt ) +{ + if ( !isDefined( self ) ) + { + return; + } + if ( !isalive( self ) ) + { + return; + } + self dodamage( n_damage_amt, self.origin, e_attacker, e_attacker, "none", self.kill_damagetype, 0, str_weapon ); +} + +do_damage_network_safe( e_attacker, n_amount, str_weapon, str_mod ) +{ + if ( isDefined( self.is_mechz ) && self.is_mechz ) + { + self dodamage( n_amount, self.origin, e_attacker, e_attacker, "none", str_mod, 0, str_weapon ); + } + else + { + if ( n_amount < self.health ) + { + self.kill_damagetype = str_mod; + maps/mp/zombies/_zm_net::network_safe_init( "dodamage", 6 ); + self maps/mp/zombies/_zm_net::network_choke_action( "dodamage", ::_damage_zombie_network_safe_internal, e_attacker, str_weapon, n_amount ); + return; + } + else + { + self.kill_damagetype = str_mod; + maps/mp/zombies/_zm_net::network_safe_init( "dodamage_kill", 4 ); + self maps/mp/zombies/_zm_net::network_choke_action( "dodamage_kill", ::_kill_zombie_network_safe_internal, e_attacker, str_weapon ); + } + } +} + +_throttle_bullet_trace_think() +{ + level.bullet_traces_this_frame = 0; + wait_network_frame(); +} + +bullet_trace_throttled( v_start, v_end, e_ignore ) +{ + if ( !isDefined( level.bullet_traces_this_frame ) ) + { + level thread _throttle_bullet_trace_think(); + } + while ( level.bullet_traces_this_frame >= 2 ) + { + wait_network_frame(); + } + level.bullet_traces_this_frame++; + return bullettracepassed( v_start, v_end, 0, e_ignore ); +} + +tomb_get_closest_player_using_paths( origin, players ) +{ + min_length_to_player = 9999999; + n_2d_distance_squared = 9999999; + player_to_return = undefined; + dist_to_tank = undefined; + i = 0; + while ( i < players.size ) + { + player = players[ i ]; + if ( !isDefined( player ) ) + { + i++; + continue; + } + else if ( isDefined( player.b_already_on_tank ) && player.b_already_on_tank ) + { + if ( !isDefined( dist_to_tank ) ) + { + length_to_player = self maps/mp/zm_tomb_tank::tomb_get_path_length_to_tank(); + dist_to_tank = length_to_player; + } + else + { + length_to_player = dist_to_tank; + } + } + else + { + length_to_player = self get_path_length_to_enemy( player ); + } + if ( isDefined( level.validate_enemy_path_length ) ) + { + if ( length_to_player == 0 ) + { + valid = self thread [[ level.validate_enemy_path_length ]]( player ); + if ( !valid ) + { + i++; + continue; + } + } + } + else if ( length_to_player < min_length_to_player ) + { + min_length_to_player = length_to_player; + player_to_return = player; + n_2d_distance_squared = distance2dsquared( self.origin, player.origin ); + i++; + continue; + } + else + { + if ( length_to_player == min_length_to_player && length_to_player <= 5 ) + { + n_new_distance = distance2dsquared( self.origin, player.origin ); + if ( n_new_distance < n_2d_distance_squared ) + { + min_length_to_player = length_to_player; + player_to_return = player; + n_2d_distance_squared = n_new_distance; + } + } + } + i++; + } + return player_to_return; +} + +update_staff_accessories( n_element_index ) +{ +/# + if ( !isDefined( n_element_index ) ) + { + n_element_index = 0; + str_weapon = self getcurrentweapon(); + if ( is_weapon_upgraded_staff( str_weapon ) ) + { + s_info = maps/mp/zm_tomb_craftables::get_staff_info_from_weapon_name( str_weapon ); + if ( isDefined( s_info ) ) + { + n_element_index = s_info.enum; + s_info.charger.is_charged = 1; +#/ + } + } + } + if ( isDefined( self.one_inch_punch_flag_has_been_init ) && !self.one_inch_punch_flag_has_been_init ) + { + cur_weapon = self get_player_melee_weapon(); + weapon_to_keep = "knife_zm"; + self.use_staff_melee = 0; + if ( n_element_index != 0 ) + { + staff_info = maps/mp/zm_tomb_craftables::get_staff_info_from_element_index( n_element_index ); + if ( staff_info.charger.is_charged ) + { + staff_info = staff_info.upgrade; + } + if ( isDefined( staff_info.melee ) ) + { + weapon_to_keep = staff_info.melee; + self.use_staff_melee = 1; + } + } + melee_changed = 0; + if ( cur_weapon != weapon_to_keep ) + { + self takeweapon( cur_weapon ); + self giveweapon( weapon_to_keep ); + self set_player_melee_weapon( weapon_to_keep ); + melee_changed = 1; + } + } + has_revive = self hasweapon( "staff_revive_zm" ); + has_upgraded_staff = 0; + a_weapons = self getweaponslistprimaries(); + staff_info = maps/mp/zm_tomb_craftables::get_staff_info_from_element_index( n_element_index ); + _a2199 = a_weapons; + _k2199 = getFirstArrayKey( _a2199 ); + while ( isDefined( _k2199 ) ) + { + str_weapon = _a2199[ _k2199 ]; + if ( is_weapon_upgraded_staff( str_weapon ) ) + { + has_upgraded_staff = 1; + } + _k2199 = getNextArrayKey( _a2199, _k2199 ); + } + if ( has_revive && !has_upgraded_staff ) + { + self setactionslot( 3, "altmode" ); + self takeweapon( "staff_revive_zm" ); + } + else + { + if ( !has_revive && has_upgraded_staff ) + { + self setactionslot( 3, "weapon", "staff_revive_zm" ); + self giveweapon( "staff_revive_zm" ); + if ( isDefined( staff_info ) ) + { + if ( isDefined( staff_info.upgrade.revive_ammo_stock ) ) + { + self setweaponammostock( "staff_revive_zm", staff_info.upgrade.revive_ammo_stock ); + self setweaponammoclip( "staff_revive_zm", staff_info.upgrade.revive_ammo_clip ); + } + } + } + } +} + +get_round_enemy_array_wrapper() +{ + if ( isDefined( level.custom_get_round_enemy_array_func ) ) + { + a_enemies = [[ level.custom_get_round_enemy_array_func ]](); + } + else + { + a_enemies = get_round_enemy_array(); + } + return a_enemies; +} + +add_ragdoll() +{ + level.n_active_ragdolls++; + wait 1; + if ( level.n_active_ragdolls > 0 ) + { + level.n_active_ragdolls--; + + } +} + +ragdoll_attempt() +{ + if ( level.n_active_ragdolls >= 4 ) + { + return 0; + } + level thread add_ragdoll(); + return 1; +} diff --git a/zm_tomb_patch/maps/mp/zm_tomb_vo.gsc b/zm_tomb_patch/maps/mp/zm_tomb_vo.gsc new file mode 100644 index 0000000..7ca65f0 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zm_tomb_vo.gsc @@ -0,0 +1,2789 @@ +#include maps/mp/zombies/_zm_unitrigger; +#include maps/mp/gametypes_zm/_globallogic_score; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init_level_specific_audio() +{ + flag_init( "story_vo_playing" ); + flag_init( "round_one_narrative_vo_complete" ); + flag_init( "maxis_audiolog_gr0_playing" ); + flag_init( "maxis_audiolog_gr1_playing" ); + flag_init( "maxis_audiolog_gr2_playing" ); + flag_init( "maxis_audio_log_1" ); + flag_init( "maxis_audio_log_2" ); + flag_init( "maxis_audio_log_3" ); + flag_init( "maxis_audio_log_4" ); + flag_init( "maxis_audio_log_5" ); + flag_init( "maxis_audio_log_6" ); + flag_init( "generator_find_vo_playing" ); + flag_init( "samantha_intro_done" ); + flag_init( "maxis_crafted_intro_done" ); + level.oh_shit_vo_cooldown = 0; + level.remove_perk_vo_delay = 1; + setdvar( "zombie_kills", "5" ); + setdvar( "zombie_kill_timer", "6" ); + if ( is_classic() ) + { + level._audio_custom_response_line = ::tomb_audio_custom_response_line; + level.audio_get_mod_type = ::tomb_audio_get_mod_type_override; + level.custom_kill_damaged_vo = ::maps/mp/zombies/_zm_audio::custom_kill_damaged_vo; + level._custom_zombie_oh_shit_vox_func = ::tomb_custom_zombie_oh_shit_vox; + level.gib_on_damage = ::tomb_custom_crawler_spawned_vo; + level._audio_custom_weapon_check = ::tomb_audio_custom_weapon_check; + level._magic_box_used_vo = ::tomb_magic_box_used_vo; + level thread start_narrative_vo(); + level thread first_magic_box_seen_vo(); + level thread start_samantha_intro_vo(); + level.zombie_custom_craftable_built_vo = ::tomb_drone_built_vo; + level thread discover_dig_site_vo(); + level thread maxis_audio_logs(); + level thread discover_pack_a_punch(); + } + tomb_add_player_dialogue( "player", "general", "no_money_weapon", "nomoney_generic", undefined ); + tomb_add_player_dialogue( "player", "general", "no_money_box", "nomoney_generic", undefined ); + tomb_add_player_dialogue( "player", "general", "perk_deny", "nomoney_generic", undefined ); + tomb_add_player_dialogue( "player", "general", "no_money_capture", "nomoney_generic", undefined ); + tomb_add_player_dialogue( "player", "perk", "specialty_armorvest", "perk_jugga", undefined ); + tomb_add_player_dialogue( "player", "perk", "specialty_quickrevive", "perk_revive", undefined ); + tomb_add_player_dialogue( "player", "perk", "specialty_fastreload", "perk_speed", undefined ); + tomb_add_player_dialogue( "player", "perk", "specialty_longersprint", "perk_stamine", undefined ); + tomb_add_player_dialogue( "player", "perk", "specialty_additionalprimaryweapon", "perk_mule", undefined ); + tomb_add_player_dialogue( "player", "kill", "closekill", "kill_close", undefined, 15 ); + tomb_add_player_dialogue( "player", "kill", "damage", "kill_damaged", undefined, 50 ); + tomb_add_player_dialogue( "player", "kill", "headshot", "kill_headshot", "resp_kill_headshot", 25 ); + tomb_add_player_dialogue( "player", "kill", "raygun", "kill_ray", undefined, 15 ); + tomb_add_player_dialogue( "player", "kill", "raymk2", "kill_raymk2", undefined, 15 ); + tomb_add_player_dialogue( "player", "kill", "one_inch_punch", "kill_one_inch", undefined, 15 ); + tomb_add_player_dialogue( "player", "kill", "ice_staff", "kill_ice", undefined, 15 ); + tomb_add_player_dialogue( "player", "kill", "ice_staff_upgrade", "kill_ice_upgrade", undefined, 15 ); + tomb_add_player_dialogue( "player", "kill", "fire_staff", "kill_fire", undefined, 15 ); + tomb_add_player_dialogue( "player", "kill", "fire_staff_upgrade", "kill_fire_upgrade", undefined, 15 ); + tomb_add_player_dialogue( "player", "kill", "light_staff", "kill_light", undefined, 15 ); + tomb_add_player_dialogue( "player", "kill", "light_staff_upgrade", "kill_light_upgrade", undefined, 15 ); + tomb_add_player_dialogue( "player", "kill", "wind_staff", "kill_wind", undefined, 15 ); + tomb_add_player_dialogue( "player", "kill", "wind_staff_upgrade", "kill_wind_upgrade", undefined, 15 ); + tomb_add_player_dialogue( "player", "kill", "headshot_respond_to_plr_0_neg", "head_rspnd_to_plr_0_neg", undefined, 100 ); + tomb_add_player_dialogue( "player", "kill", "headshot_respond_to_plr_0_pos", "head_rspnd_to_plr_0_pos", undefined, 100 ); + tomb_add_player_dialogue( "player", "kill", "headshot_respond_to_plr_1_neg", "head_rspnd_to_plr_1_neg", undefined, 100 ); + tomb_add_player_dialogue( "player", "kill", "headshot_respond_to_plr_1_pos", "head_rspnd_to_plr_1_pos", undefined, 100 ); + tomb_add_player_dialogue( "player", "kill", "headshot_respond_to_plr_2_neg", "head_rspnd_to_plr_2_neg", undefined, 100 ); + tomb_add_player_dialogue( "player", "kill", "headshot_respond_to_plr_2_pos", "head_rspnd_to_plr_2_pos", undefined, 100 ); + tomb_add_player_dialogue( "player", "kill", "headshot_respond_to_plr_3_neg", "head_rspnd_to_plr_3_neg", undefined, 100 ); + tomb_add_player_dialogue( "player", "kill", "headshot_respond_to_plr_3_pos", "head_rspnd_to_plr_3_pos", undefined, 100 ); + tomb_add_player_dialogue( "player", "powerup", "zombie_blood", "powerup_zombie_blood", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "revive_up", "revive_player", "revive_player", 100 ); + tomb_add_player_dialogue( "player", "general", "heal_revived_pos", "heal_revived_pos", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "heal_revived_neg", "heal_revived_neg", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "exert_sigh", "exert_sigh", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "exert_laugh", "exert_laugh", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "pain_high", "pain_high", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "build_dd_pickup", "build_dd_pickup", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "build_dd_brain_pickup", "pickup_brain", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "build_dd_final", "build_dd_final", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "build_dd_plc", "build_dd_take", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "build_zs_pickup", "build_zs_pickup", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "build_zs_final", "build_zs_final", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "build_zs_plc", "build_zs_take", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "record_pickup", "pickup_record", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "gramophone_pickup", "pickup_gramophone", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "place_gramophone", "place_gramophone", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "staff_part_pickup", "pickup_staff_part", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "crystal_pickup", "pickup_crystal", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "pickup_fire", "pickup_fire", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "pickup_ice", "pickup_ice", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "pickup_light", "pickup_light", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "pickup_wind", "pickup_wind", undefined, 100 ); + tomb_add_player_dialogue( "player", "puzzle", "try_puzzle", "activate_generic", undefined ); + tomb_add_player_dialogue( "player", "puzzle", "puzzle_confused", "confusion_generic", undefined ); + tomb_add_player_dialogue( "player", "puzzle", "puzzle_good", "outcome_yes_generic", undefined ); + tomb_add_player_dialogue( "player", "puzzle", "puzzle_bad", "outcome_no_generic", undefined ); + tomb_add_player_dialogue( "player", "puzzle", "berate_respond", "generic_chastise", undefined ); + tomb_add_player_dialogue( "player", "puzzle", "encourage_respond", "generic_encourage", undefined ); + tomb_add_player_dialogue( "player", "staff", "first_piece", "1st_staff_found", undefined ); + tomb_add_player_dialogue( "player", "general", "build_pickup", "pickup_generic", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "reboard", "rebuild_boards", undefined, 100 ); + tomb_add_player_dialogue( "player", "weapon_pickup", "explo", "wpck_explo", undefined, 100 ); + tomb_add_player_dialogue( "player", "weapon_pickup", "raygun_mark2_zm", "wpck_raymk2", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "use_box_intro", "use_box_intro", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "use_box_2nd_time", "use_box_2nd_time", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "take_weapon_intro", "take_weapon_intro", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "take_weapon_2nd_time", "take_weapon_2nd_time", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "discover_wall_buy", "discover_wall_buy", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "generic_wall_buy", "generic_wall_buy", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "pap_arm", "pap_arm", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "pap_discovered", "capture_zones", undefined, 100 ); + tomb_add_player_dialogue( "player", "tank", "discover_tank", "discover_tank", undefined ); + tomb_add_player_dialogue( "player", "tank", "tank_flame_zombie", "kill_tank", undefined ); + tomb_add_player_dialogue( "player", "tank", "tank_buy", "buy_tank", undefined ); + tomb_add_player_dialogue( "player", "tank", "tank_leave", "exit_tank", undefined ); + tomb_add_player_dialogue( "player", "tank", "tank_cooling", "cool_tank", undefined ); + tomb_add_player_dialogue( "player", "tank", "tank_left_behind", "miss_tank", undefined ); + tomb_add_player_dialogue( "player", "general", "siren_1st_time", "siren_1st_time", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "siren_generic", "siren_generic", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "multiple_mechs", "multiple_mechs", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "discover_mech", "discover_mech", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "mech_defeated", "mech_defeated", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "mech_grab", "rspnd_mech_grab", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "shoot_mech_arm", "shoot_mech_arm", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "shoot_mech_head", "shoot_mech_head", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "shoot_mech_power", "shoot_mech_power", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "rspnd_mech_jump", "rspnd_mech_jump", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "enter_robot", "enter_robot", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "purge_robot", "purge_robot", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "exit_robot", "exit_robot", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "air_chute_landing", "air_chute_landing", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "robot_crush_golden", "robot_crush_golden", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "robot_crush_player", "robot_crush_player", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "discover_robot", "discover_robot", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "see_robots", "see_robots", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "robot_crush_zombie", "robot_crush_zombie", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "robot_crush_mech", "robot_crush_mech", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "shoot_robot", "shoot_robot", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "warn_robot_foot", "warn_robot_foot", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "warn_robot", "warn_robot", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "use_beacon", "use_beacon", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "srnd_rspnd_to_plr_0_neg", "srnd_rspnd_to_plr_0_neg", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "srnd_rspnd_to_plr_1_neg", "srnd_rspnd_to_plr_1_neg", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "srnd_rspnd_to_plr_2_neg", "srnd_rspnd_to_plr_2_neg", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "srnd_rspnd_to_plr_3_neg", "srnd_rspnd_to_plr_3_neg", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "srnd_rspnd_to_plr_0_pos", "srnd_rspnd_to_plr_0_pos", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "srnd_rspnd_to_plr_1_pos", "srnd_rspnd_to_plr_1_pos", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "srnd_rspnd_to_plr_2_pos", "srnd_rspnd_to_plr_2_pos", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "srnd_rspnd_to_plr_3_pos", "srnd_rspnd_to_plr_3_pos", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "achievement", "earn_acheivement", undefined, 100 ); + tomb_add_player_dialogue( "player", "quest", "find_secret", "find_secret", undefined, 100 ); + tomb_add_player_dialogue( "player", "perk", "one_inch", "perk_one_inch", undefined, 100 ); + tomb_add_player_dialogue( "player", "digging", "pickup_shovel", "pickup_shovel", undefined, 100 ); + tomb_add_player_dialogue( "player", "digging", "dig_gun", "dig_gun", undefined, 15 ); + tomb_add_player_dialogue( "player", "digging", "dig_grenade", "dig_grenade", undefined, 15 ); + tomb_add_player_dialogue( "player", "digging", "dig_zombie", "dig_zombie", undefined, 15 ); + tomb_add_player_dialogue( "player", "digging", "dig_staff_part", "dig_staff_part", undefined, 100 ); + tomb_add_player_dialogue( "player", "digging", "dig_powerup", "dig_powerup", undefined, 15 ); + tomb_add_player_dialogue( "player", "digging", "dig_cash", "dig_cash", undefined, 15 ); + tomb_add_player_dialogue( "player", "soul_box", "zm_box_encourage", "zm_box_encourage", undefined, 100 ); + tomb_add_player_dialogue( "player", "zone_capture", "capture_started", "capture_zombies", undefined, 100 ); + tomb_add_player_dialogue( "player", "zone_capture", "recapture_started", "roaming_zombies", undefined, 100 ); + tomb_add_player_dialogue( "player", "zone_capture", "recapture_generator_attacked", "recapture_initiated", undefined, 100 ); + tomb_add_player_dialogue( "player", "zone_capture", "recapture_prevented", "recapture_prevented", undefined, 100 ); + tomb_add_player_dialogue( "player", "zone_capture", "all_generators_captured", "zones_held", undefined, 100 ); + tomb_add_player_dialogue( "player", "lockdown", "power_off", "lockdown_generic", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "struggle_mud", "struggle_mud", undefined, 100 ); + tomb_add_player_dialogue( "player", "general", "discover_dig_site", "discover_dig_site", undefined, 100 ); + tomb_add_player_dialogue( "player", "quadrotor", "kill_drone", "kill_drone", undefined, 100 ); + tomb_add_player_dialogue( "player", "quadrotor", "rspnd_drone_revive", "rspnd_drone_revive", undefined, 100 ); + tomb_add_player_dialogue( "player", "wunderfizz", "perk_wonder", "perk_wonder", undefined, 100 ); + tomb_add_player_dialogue( "player", "samantha", "hear_samantha_1", "hear_samantha_1", undefined, 100 ); + tomb_add_player_dialogue( "player", "samantha", "heroes_confer", "heroes_confer", undefined, 100 ); + tomb_add_player_dialogue( "player", "samantha", "hear_samantha_3", "hear_samantha_3", undefined, 100 ); + init_sam_promises(); +} + +tomb_add_player_dialogue( speaker, category, type, alias, response, chance ) +{ + level.vox zmbvoxadd( speaker, category, type, alias, response ); + if ( isDefined( chance ) ) + { + add_vox_response_chance( type, chance ); + } +} + +tomb_audio_get_mod_type_override( impact, mod, weapon, zombie, instakill, dist, player ) +{ + close_dist = 4096; + med_dist = 15376; + far_dist = 75625; + a_str_mod = []; + if ( isDefined( zombie.staff_dmg ) ) + { + weapon = zombie.staff_dmg; + } + else + { + if ( isDefined( zombie ) && isDefined( zombie.damageweapon ) ) + { + weapon = zombie.damageweapon; + } + } + if ( weapon == "staff_water_zm" || weapon == "staff_water_upgraded_zm" ) + { + a_str_mod[ a_str_mod.size ] = "ice_staff"; + } + if ( weapon == "staff_water_upgraded2_zm" || weapon == "staff_water_upgraded3_zm" ) + { + a_str_mod[ a_str_mod.size ] = "ice_staff_upgrade"; + } + if ( weapon == "staff_fire_zm" || weapon == "staff_fire_upgraded_zm" ) + { + a_str_mod[ a_str_mod.size ] = "fire_staff"; + } + if ( weapon == "staff_fire_upgraded2_zm" || weapon == "staff_fire_upgraded3_zm" ) + { + a_str_mod[ a_str_mod.size ] = "fire_staff_upgrade"; + } + if ( weapon == "staff_lightning_zm" || weapon == "staff_lightning_upgraded_zm" ) + { + a_str_mod[ a_str_mod.size ] = "light_staff"; + } + if ( weapon == "staff_lightning_upgraded2_zm" || weapon == "staff_lightning_upgraded3_zm" ) + { + a_str_mod[ a_str_mod.size ] = "light_staff_upgrade"; + } + if ( weapon == "staff_air_zm" || weapon == "staff_air_upgraded_zm" ) + { + a_str_mod[ a_str_mod.size ] = "wind_staff"; + } + if ( weapon == "staff_air_upgraded2_zm" || weapon == "staff_air_upgraded3_zm" ) + { + a_str_mod[ a_str_mod.size ] = "wind_staff_upgrade"; + } + if ( is_headshot( weapon, impact, mod ) && dist >= far_dist ) + { + a_str_mod[ a_str_mod.size ] = "headshot"; + } + if ( weapon == "ray_gun_zm" || weapon == "ray_gun_upgraded_zm" ) + { + if ( dist > far_dist ) + { + if ( !instakill ) + { + a_str_mod[ a_str_mod.size ] = "raygun"; + } + else + { + a_str_mod[ a_str_mod.size ] = "weapon_instakill"; + } + } + } + if ( weapon == "raygun_mark2_zm" || weapon == "raygun_mark2_upgraded_zm" ) + { + if ( dist > far_dist ) + { + if ( !instakill ) + { + a_str_mod[ a_str_mod.size ] = "raymk2"; + } + else + { + a_str_mod[ a_str_mod.size ] = "weapon_instakill"; + } + } + } + if ( is_explosive_damage( mod ) && weapon != "ray_gun_zm" && weapon != "ray_gun_upgraded_zm" && weapon != "raygun_mark2_zm" && weapon != "raygun_mark2_upgraded_zm" && isDefined( zombie.is_on_fire ) && !zombie.is_on_fire ) + { + if ( !issubstr( weapon, "staff" ) ) + { + if ( !instakill ) + { + a_str_mod[ a_str_mod.size ] = "explosive"; + } + else + { + a_str_mod[ a_str_mod.size ] = "weapon_instakill"; + } + } + } + if ( instakill ) + { + if ( mod == "MOD_MELEE" ) + { + a_str_mod[ a_str_mod.size ] = "melee_instakill"; + } + else + { + a_str_mod[ a_str_mod.size ] = "weapon_instakill"; + } + } + if ( mod != "MOD_MELEE" && !zombie.has_legs ) + { + a_str_mod[ a_str_mod.size ] = "crawler"; + } + if ( mod != "MOD_BURNED" && dist < close_dist ) + { + a_str_mod[ a_str_mod.size ] = "closekill"; + } + if ( a_str_mod.size == 0 ) + { + str_mod_final = "default"; + } + else if ( a_str_mod.size == 1 ) + { + str_mod_final = a_str_mod[ 0 ]; + } + else + { + i = 0; + while ( i < a_str_mod.size ) + { + if ( cointoss() ) + { + str_mod_final = a_str_mod[ i ]; + } + i++; + } + str_mod_final = a_str_mod[ randomint( a_str_mod.size ) ]; + } + return str_mod_final; +} + +tomb_custom_zombie_oh_shit_vox() +{ + self endon( "death_or_disconnect" ); + while ( 1 ) + { + wait 1; + if ( isDefined( self.oh_shit_vo_cooldown ) && self.oh_shit_vo_cooldown ) + { + continue; + } + players = get_players(); + zombs = get_round_enemy_array(); + if ( players.size <= 1 ) + { + n_distance = 250; + n_zombies = 5; + n_chance = 30; + n_cooldown_time = 20; + } + else + { + n_distance = 250; + n_zombies = 5; + n_chance = 30; + n_cooldown_time = 15; + } + close_zombs = 0; + i = 0; + while ( i < zombs.size ) + { + if ( isDefined( zombs[ i ].favoriteenemy ) || zombs[ i ].favoriteenemy == self && !isDefined( zombs[ i ].favoriteenemy ) ) + { + if ( distancesquared( zombs[ i ].origin, self.origin ) < ( n_distance * n_distance ) ) + { + close_zombs++; + } + } + i++; + } + if ( close_zombs >= n_zombies ) + { + if ( randomint( 100 ) < n_chance && isDefined( self.giant_robot_transition ) && !self.giant_robot_transition && !isDefined( self.in_giant_robot_head ) ) + { + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "oh_shit" ); + self thread global_oh_shit_cooldown_timer( n_cooldown_time ); + wait n_cooldown_time; + } + } + } +} + +global_oh_shit_cooldown_timer( n_cooldown_time ) +{ + self endon( "disconnect" ); + self.oh_shit_vo_cooldown = 1; + wait n_cooldown_time; + self.oh_shit_vo_cooldown = 0; +} + +tomb_custom_crawler_spawned_vo() +{ + self endon( "death" ); + if ( isDefined( self.a.gib_ref ) && isalive( self ) ) + { + if ( self.a.gib_ref != "no_legs" || self.a.gib_ref == "right_leg" && self.a.gib_ref == "left_leg" ) + { + if ( isDefined( self.attacker ) && isplayer( self.attacker ) ) + { + if ( isDefined( self.attacker.crawler_created_vo_cooldown ) && self.attacker.crawler_created_vo_cooldown ) + { + return; + } + rand = randomintrange( 0, 100 ); + if ( rand < 15 ) + { + self.attacker maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "crawl_spawn" ); + self.attacker thread crawler_created_vo_cooldown(); + } + } + } + } +} + +crawler_created_vo_cooldown() +{ + self endon( "disconnect" ); + self.crawler_created_vo_cooldown = 1; + wait 30; + self.crawler_created_vo_cooldown = 0; +} + +tomb_audio_custom_weapon_check( weapon, magic_box ) +{ + self endon( "death" ); + self endon( "disconnect" ); + if ( isDefined( magic_box ) && magic_box ) + { + if ( isDefined( self.magic_box_uses ) && self.magic_box_uses == 1 ) + { + self thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "take_weapon_intro" ); + } + else + { + if ( isDefined( self.magic_box_uses ) && self.magic_box_uses == 2 ) + { + self thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "take_weapon_2nd_time" ); + } + else + { + type = self maps/mp/zombies/_zm_weapons::weapon_type_check( weapon ); + return type; + } + } + } + else + { + if ( issubstr( weapon, "staff" ) ) + { + if ( weapon == "staff_fire_zm" ) + { + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "pickup_fire" ); + level notify( "staff_crafted_vo" ); + } + else if ( weapon == "staff_water_zm" ) + { + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "pickup_ice" ); + level notify( "staff_crafted_vo" ); + } + else if ( weapon == "staff_air_zm" ) + { + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "pickup_wind" ); + level notify( "staff_crafted_vo" ); + } + else + { + if ( weapon == "staff_lightning_zm" ) + { + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "pickup_light" ); + level notify( "staff_crafted_vo" ); + } + } + } + else if ( !isDefined( self.wallbuys_purchased ) ) + { + self thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "discover_wall_buy" ); + self.wallbuys_purchased = 1; + } + else if ( weapon == "sticky_grenade_zm" || weapon == "claymore_zm" ) + { + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "weapon_pickup", "explo" ); + } + else + { + self thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "generic_wall_buy" ); + } + } + return "crappy"; +} + +tomb_magic_box_used_vo() +{ + if ( !isDefined( self.magic_box_uses ) ) + { + self.magic_box_uses = 1; + } + else + { + self.magic_box_uses++; + } + if ( self.magic_box_uses == 1 ) + { + self thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "use_box_intro" ); + } + else + { + if ( self.magic_box_uses == 2 ) + { + self thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "use_box_2nd_time" ); + } + } +} + +easter_egg_song_vo( player ) +{ + wait 3,5; + if ( isalive( player ) ) + { + player thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "quest", "find_secret" ); + } + else + { + while ( 1 ) + { + a_players = getplayers(); + _a643 = a_players; + _k643 = getFirstArrayKey( _a643 ); + while ( isDefined( _k643 ) ) + { + player = _a643[ _k643 ]; + if ( isalive( player ) ) + { + if ( isDefined( player.dontspeak ) && !player.dontspeak ) + { + player thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "quest", "find_secret" ); + } + } + _k643 = getNextArrayKey( _a643, _k643 ); + } + } + wait 0,1; + } +} + +play_gramophone_place_vo() +{ + if ( isDefined( self.dontspeak ) && !self.dontspeak ) + { + if ( isDefined( self.gramophone_place_vo ) && !self.gramophone_place_vo ) + { + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "place_gramophone" ); + self.gramophone_place_vo = 1; + } + } +} + +setup_personality_character_exerts() +{ + level.exert_sounds[ 1 ][ "burp" ][ 0 ] = "vox_plr_0_exert_burp_0"; + level.exert_sounds[ 1 ][ "burp" ][ 1 ] = "vox_plr_0_exert_burp_1"; + level.exert_sounds[ 1 ][ "burp" ][ 2 ] = "vox_plr_0_exert_burp_2"; + level.exert_sounds[ 1 ][ "burp" ][ 3 ] = "vox_plr_0_exert_burp_3"; + level.exert_sounds[ 1 ][ "burp" ][ 4 ] = "vox_plr_0_exert_burp_4"; + level.exert_sounds[ 1 ][ "burp" ][ 5 ] = "vox_plr_0_exert_burp_5"; + level.exert_sounds[ 1 ][ "burp" ][ 6 ] = "vox_plr_0_exert_burp_6"; + level.exert_sounds[ 2 ][ "burp" ][ 0 ] = "vox_plr_1_exert_burp_0"; + level.exert_sounds[ 2 ][ "burp" ][ 1 ] = "vox_plr_1_exert_burp_1"; + level.exert_sounds[ 2 ][ "burp" ][ 2 ] = "vox_plr_1_exert_burp_2"; + level.exert_sounds[ 2 ][ "burp" ][ 3 ] = "vox_plr_1_exert_burp_3"; + level.exert_sounds[ 3 ][ "burp" ][ 0 ] = "vox_plr_2_exert_burp_0"; + level.exert_sounds[ 3 ][ "burp" ][ 1 ] = "vox_plr_2_exert_burp_1"; + level.exert_sounds[ 3 ][ "burp" ][ 2 ] = "vox_plr_2_exert_burp_2"; + level.exert_sounds[ 3 ][ "burp" ][ 3 ] = "vox_plr_2_exert_burp_3"; + level.exert_sounds[ 3 ][ "burp" ][ 4 ] = "vox_plr_2_exert_burp_4"; + level.exert_sounds[ 3 ][ "burp" ][ 5 ] = "vox_plr_2_exert_burp_5"; + level.exert_sounds[ 3 ][ "burp" ][ 6 ] = "vox_plr_2_exert_burp_6"; + level.exert_sounds[ 4 ][ "burp" ][ 0 ] = "vox_plr_3_exert_burp_0"; + level.exert_sounds[ 4 ][ "burp" ][ 1 ] = "vox_plr_3_exert_burp_1"; + level.exert_sounds[ 4 ][ "burp" ][ 2 ] = "vox_plr_3_exert_burp_2"; + level.exert_sounds[ 4 ][ "burp" ][ 3 ] = "vox_plr_3_exert_burp_3"; + level.exert_sounds[ 4 ][ "burp" ][ 4 ] = "vox_plr_3_exert_burp_4"; + level.exert_sounds[ 4 ][ "burp" ][ 5 ] = "vox_plr_3_exert_burp_5"; + level.exert_sounds[ 4 ][ "burp" ][ 6 ] = "vox_plr_3_exert_burp_6"; + level.exert_sounds[ 1 ][ "hitmed" ][ 0 ] = "vox_plr_0_exert_pain_medium_0"; + level.exert_sounds[ 1 ][ "hitmed" ][ 1 ] = "vox_plr_0_exert_pain_medium_1"; + level.exert_sounds[ 1 ][ "hitmed" ][ 2 ] = "vox_plr_0_exert_pain_medium_2"; + level.exert_sounds[ 1 ][ "hitmed" ][ 3 ] = "vox_plr_0_exert_pain_medium_3"; + level.exert_sounds[ 2 ][ "hitmed" ][ 0 ] = "vox_plr_1_exert_pain_medium_0"; + level.exert_sounds[ 2 ][ "hitmed" ][ 1 ] = "vox_plr_1_exert_pain_medium_1"; + level.exert_sounds[ 2 ][ "hitmed" ][ 2 ] = "vox_plr_1_exert_pain_medium_2"; + level.exert_sounds[ 2 ][ "hitmed" ][ 3 ] = "vox_plr_1_exert_pain_medium_3"; + level.exert_sounds[ 3 ][ "hitmed" ][ 0 ] = "vox_plr_2_exert_pain_medium_0"; + level.exert_sounds[ 3 ][ "hitmed" ][ 1 ] = "vox_plr_2_exert_pain_medium_1"; + level.exert_sounds[ 3 ][ "hitmed" ][ 2 ] = "vox_plr_2_exert_pain_medium_2"; + level.exert_sounds[ 3 ][ "hitmed" ][ 3 ] = "vox_plr_2_exert_pain_medium_3"; + level.exert_sounds[ 4 ][ "hitmed" ][ 0 ] = "vox_plr_3_exert_pain_medium_0"; + level.exert_sounds[ 4 ][ "hitmed" ][ 1 ] = "vox_plr_3_exert_pain_medium_1"; + level.exert_sounds[ 4 ][ "hitmed" ][ 2 ] = "vox_plr_3_exert_pain_medium_2"; + level.exert_sounds[ 4 ][ "hitmed" ][ 3 ] = "vox_plr_3_exert_pain_medium_3"; + level.exert_sounds[ 1 ][ "hitlrg" ][ 0 ] = "vox_plr_0_exert_pain_high_0"; + level.exert_sounds[ 1 ][ "hitlrg" ][ 1 ] = "vox_plr_0_exert_pain_high_1"; + level.exert_sounds[ 1 ][ "hitlrg" ][ 2 ] = "vox_plr_0_exert_pain_high_2"; + level.exert_sounds[ 1 ][ "hitlrg" ][ 3 ] = "vox_plr_0_exert_pain_high_3"; + level.exert_sounds[ 2 ][ "hitlrg" ][ 0 ] = "vox_plr_1_exert_pain_high_0"; + level.exert_sounds[ 2 ][ "hitlrg" ][ 1 ] = "vox_plr_1_exert_pain_high_1"; + level.exert_sounds[ 2 ][ "hitlrg" ][ 2 ] = "vox_plr_1_exert_pain_high_2"; + level.exert_sounds[ 2 ][ "hitlrg" ][ 3 ] = "vox_plr_1_exert_pain_high_3"; + level.exert_sounds[ 3 ][ "hitlrg" ][ 0 ] = "vox_plr_2_exert_pain_high_0"; + level.exert_sounds[ 3 ][ "hitlrg" ][ 1 ] = "vox_plr_2_exert_pain_high_1"; + level.exert_sounds[ 3 ][ "hitlrg" ][ 2 ] = "vox_plr_2_exert_pain_high_2"; + level.exert_sounds[ 3 ][ "hitlrg" ][ 3 ] = "vox_plr_2_exert_pain_high_3"; + level.exert_sounds[ 4 ][ "hitlrg" ][ 0 ] = "vox_plr_3_exert_pain_high_0"; + level.exert_sounds[ 4 ][ "hitlrg" ][ 1 ] = "vox_plr_3_exert_pain_high_1"; + level.exert_sounds[ 4 ][ "hitlrg" ][ 2 ] = "vox_plr_3_exert_pain_high_2"; + level.exert_sounds[ 4 ][ "hitlrg" ][ 3 ] = "vox_plr_3_exert_pain_high_3"; +} + +tomb_audio_custom_response_line( player, index, category, type ) +{ + if ( type == "revive_up" ) + { + player thread play_pos_neg_response_on_closest_player( "general", "heal_revived", "kills" ); + } + else if ( type == "headshot" ) + { + player thread play_pos_neg_response_on_closest_player( "kill", "headshot_respond_to_plr_" + player.characterindex, "kills" ); + } + else + { + if ( type == "oh_shit" ) + { + player thread play_pos_neg_response_on_closest_player( "general", "srnd_rspnd_to_plr_" + player.characterindex, "kills" ); + player thread global_oh_shit_cooldown_timer( 15 ); + } + } +} + +play_vo_category_on_closest_player( category, type ) +{ + a_players = getplayers(); + if ( a_players.size <= 1 ) + { + return; + } + arrayremovevalue( a_players, self ); + a_closest = arraysort( a_players, self.origin, 1 ); + if ( distancesquared( self.origin, a_closest[ 0 ].origin ) <= 250000 ) + { + if ( isalive( a_closest[ 0 ] ) ) + { + a_closest[ 0 ] maps/mp/zombies/_zm_audio::create_and_play_dialog( category, type ); + } + } +} + +play_pos_neg_response_on_closest_player( category, type, str_stat ) +{ + a_players = getplayers(); + if ( a_players.size <= 1 ) + { + return; + } + arrayremovevalue( a_players, self ); + a_closest = arraysort( a_players, self.origin, 1 ); + _a801 = a_closest; + _k801 = getFirstArrayKey( _a801 ); + while ( isDefined( _k801 ) ) + { + player = _a801[ _k801 ]; + if ( distancesquared( self.origin, player.origin ) <= 250000 ) + { + if ( isalive( player ) ) + { + str_suffix = get_positive_or_negative_suffix( self, player, str_stat ); + if ( isDefined( str_suffix ) ) + { + type += str_suffix; + } + player maps/mp/zombies/_zm_audio::create_and_play_dialog( category, type ); + return; + } + } + else + { + _k801 = getNextArrayKey( _a801, _k801 ); + } + } +} + +get_positive_or_negative_suffix( e_player1, e_player2, str_stat ) +{ + n_player1_stat = e_player1 maps/mp/gametypes_zm/_globallogic_score::getpersstat( str_stat ); + n_player2_stat = e_player2 maps/mp/gametypes_zm/_globallogic_score::getpersstat( str_stat ); + if ( !isDefined( n_player1_stat ) || !isDefined( n_player2_stat ) ) + { + return undefined; + } + if ( n_player1_stat >= n_player2_stat ) + { + str_result = "_pos"; + } + else + { + str_result = "_neg"; + } + return str_result; +} + +struggle_mud_vo() +{ + self endon( "disconnect" ); + self.played_mud_vo = 1; + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "struggle_mud" ); + self waittill( "mud_slowdown_cleared" ); + self thread struggle_mud_vo_cooldown(); +} + +struggle_mud_vo_cooldown() +{ + self endon( "disconnect" ); + wait 600; + self.played_mud_vo = 0; +} + +discover_dig_site_vo() +{ + flag_wait( "activate_zone_nml" ); + s_origin = getstruct( "discover_dig_site_vo_trigger", "targetname" ); + s_origin.unitrigger_stub = spawnstruct(); + s_origin.unitrigger_stub.origin = s_origin.origin; + s_origin.unitrigger_stub.script_width = 320; + s_origin.unitrigger_stub.script_length = 88; + s_origin.unitrigger_stub.script_height = 256; + s_origin.unitrigger_stub.script_unitrigger_type = "unitrigger_box"; + s_origin.unitrigger_stub.angles = ( 0, 0, 0 ); + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( s_origin.unitrigger_stub, ::discover_dig_site_trigger_touch ); +} + +discover_dig_site_trigger_touch() +{ + while ( 1 ) + { + self waittill( "trigger", player ); + if ( isplayer( player ) ) + { + if ( isDefined( player.dontspeak ) && !player.dontspeak ) + { + player thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "discover_dig_site" ); + maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( self.stub ); + return; + } + } + else + { + } + } +} + +maxis_audio_logs() +{ + a_s_radios = getstructarray( "maxis_audio_log", "targetname" ); + _a912 = a_s_radios; + _k912 = getFirstArrayKey( _a912 ); + while ( isDefined( _k912 ) ) + { + s_origin = _a912[ _k912 ]; + s_origin.unitrigger_stub = spawnstruct(); + s_origin.unitrigger_stub.origin = s_origin.origin; + s_origin.unitrigger_stub.radius = 36; + s_origin.unitrigger_stub.height = 256; + s_origin.unitrigger_stub.script_unitrigger_type = "unitrigger_radius_use"; + s_origin.unitrigger_stub.hint_string = &"ZM_TOMB_MAXIS_AUDIOLOG"; + s_origin.unitrigger_stub.cursor_hint = "HINT_NOICON"; + s_origin.unitrigger_stub.require_look_at = 1; + s_origin.unitrigger_stub.script_int = s_origin.script_int; + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( s_origin.unitrigger_stub, ::maxis_audio_log_think ); + _k912 = getNextArrayKey( _a912, _k912 ); + } +} + +discover_pack_a_punch() +{ + t_pap_intro = getent( "pack_a_punch_intro_trigger", "targetname" ); + if ( !isDefined( t_pap_intro ) ) + { + return; + } + s_lookat = getstruct( t_pap_intro.target, "targetname" ); + while ( 1 ) + { + t_pap_intro waittill( "trigger", e_player ); + if ( !isDefined( e_player.discover_pap_vo_played ) ) + { + e_player.discover_pap_vo_played = 0; + } + while ( !e_player.discover_pap_vo_played ) + { + while ( vectordot( anglesToForward( e_player getplayerangles() ), vectornormalize( s_lookat.origin - e_player.origin ) ) > 0,8 && e_player can_player_speak() ) + { + e_player.discover_pap_vo_played = 1; + e_player create_and_play_dialog( "general", "pap_discovered" ); + _a955 = get_players(); + _k955 = getFirstArrayKey( _a955 ); + while ( isDefined( _k955 ) ) + { + player = _a955[ _k955 ]; + if ( distance( player.origin, e_player.origin ) < 800 ) + { + player.discover_pap_vo_played = 1; + } + _k955 = getNextArrayKey( _a955, _k955 ); + } + } + } + } +} + +can_player_speak() +{ + if ( isplayer( self ) && isDefined( self.dontspeak ) && !self.dontspeak ) + { + return self getclientfieldtoplayer( "isspeaking" ) == 0; + } +} + +maxis_audio_log_think() +{ + self waittill( "trigger", player ); + if ( !isplayer( player ) || !is_player_valid( player ) ) + { + return; + } + level thread play_maxis_audio_log( self.stub.origin, self.stub.script_int ); +} + +play_maxis_audio_log( v_trigger_origin, n_audiolog_id ) +{ + a_audiolog = get_audiolog_vo(); + a_audiolog_to_play = a_audiolog[ n_audiolog_id ]; + if ( n_audiolog_id == 4 ) + { + flag_set( "maxis_audiolog_gr0_playing" ); + } + else if ( n_audiolog_id == 5 ) + { + flag_set( "maxis_audiolog_gr1_playing" ); + } + else + { + if ( n_audiolog_id == 6 ) + { + flag_set( "maxis_audiolog_gr2_playing" ); + } + } + e_vo_origin = spawn( "script_origin", v_trigger_origin ); + flag_set( "maxis_audio_log_" + n_audiolog_id ); + a_s_triggers = getstructarray( "maxis_audio_log", "targetname" ); + _a1009 = a_s_triggers; + _k1009 = getFirstArrayKey( _a1009 ); + while ( isDefined( _k1009 ) ) + { + s_trigger = _a1009[ _k1009 ]; + if ( s_trigger.script_int == n_audiolog_id ) + { + break; + } + else + { + _k1009 = getNextArrayKey( _a1009, _k1009 ); + } + } + level thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( s_trigger.unitrigger_stub ); + i = 0; + while ( i < a_audiolog_to_play.size ) + { + e_vo_origin playsoundwithnotify( a_audiolog_to_play[ i ], a_audiolog_to_play[ i ] + "_done" ); + e_vo_origin waittill( a_audiolog_to_play[ i ] + "_done" ); + i++; + } + e_vo_origin delete(); + if ( n_audiolog_id == 4 ) + { + flag_clear( "maxis_audiolog_gr0_playing" ); + } + else if ( n_audiolog_id == 5 ) + { + flag_clear( "maxis_audiolog_gr1_playing" ); + } + else + { + if ( n_audiolog_id == 6 ) + { + flag_clear( "maxis_audiolog_gr2_playing" ); + } + } + level thread maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( s_trigger.unitrigger_stub, ::maxis_audio_log_think ); +} + +reset_maxis_audiolog_unitrigger( n_robot_id ) +{ + if ( n_robot_id == 0 ) + { + n_script_int = 4; + } + else if ( n_robot_id == 1 ) + { + n_script_int = 5; + } + else + { + if ( n_robot_id == 2 ) + { + n_script_int = 6; + } + } + if ( flag( "maxis_audio_log_" + n_script_int ) ) + { + return; + } + a_s_radios = getstructarray( "maxis_audio_log", "targetname" ); + _a1065 = a_s_radios; + _k1065 = getFirstArrayKey( _a1065 ); + while ( isDefined( _k1065 ) ) + { + s_origin = _a1065[ _k1065 ]; + if ( s_origin.script_int == n_script_int ) + { + if ( isDefined( s_origin.unitrigger_stub ) ) + { + maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( s_origin.unitrigger_stub ); + } + } + _k1065 = getNextArrayKey( _a1065, _k1065 ); + } +} + +restart_maxis_audiolog_unitrigger( n_robot_id ) +{ + if ( n_robot_id == 0 ) + { + n_script_int = 4; + } + else if ( n_robot_id == 1 ) + { + n_script_int = 5; + } + else + { + if ( n_robot_id == 2 ) + { + n_script_int = 6; + } + } + a_s_radios = getstructarray( "maxis_audio_log", "targetname" ); + _a1094 = a_s_radios; + _k1094 = getFirstArrayKey( _a1094 ); + while ( isDefined( _k1094 ) ) + { + s_origin = _a1094[ _k1094 ]; + if ( s_origin.script_int == n_script_int ) + { + if ( isDefined( s_origin.unitrigger_stub ) ) + { + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( s_origin.unitrigger_stub, ::maxis_audio_log_think ); + } + } + _k1094 = getNextArrayKey( _a1094, _k1094 ); + } +} + +get_audiolog_vo() +{ + a_audiologs = []; + a_audiologs[ 1 ] = []; + a_audiologs[ 1 ][ 0 ] = "vox_maxi_audio_log_1_1_0"; + a_audiologs[ 1 ][ 1 ] = "vox_maxi_audio_log_1_2_0"; + a_audiologs[ 1 ][ 2 ] = "vox_maxi_audio_log_1_3_0"; + a_audiologs[ 2 ] = []; + a_audiologs[ 2 ][ 0 ] = "vox_maxi_audio_log_2_1_0"; + a_audiologs[ 2 ][ 1 ] = "vox_maxi_audio_log_2_2_0"; + a_audiologs[ 3 ] = []; + a_audiologs[ 3 ][ 0 ] = "vox_maxi_audio_log_3_1_0"; + a_audiologs[ 3 ][ 1 ] = "vox_maxi_audio_log_3_2_0"; + a_audiologs[ 3 ][ 2 ] = "vox_maxi_audio_log_3_3_0"; + a_audiologs[ 4 ] = []; + a_audiologs[ 4 ][ 0 ] = "vox_maxi_audio_log_4_1_0"; + a_audiologs[ 4 ][ 1 ] = "vox_maxi_audio_log_4_2_0"; + a_audiologs[ 4 ][ 2 ] = "vox_maxi_audio_log_4_3_0"; + a_audiologs[ 5 ] = []; + a_audiologs[ 5 ][ 0 ] = "vox_maxi_audio_log_5_1_0"; + a_audiologs[ 5 ][ 1 ] = "vox_maxi_audio_log_5_2_0"; + a_audiologs[ 5 ][ 2 ] = "vox_maxi_audio_log_5_3_0"; + a_audiologs[ 6 ] = []; + a_audiologs[ 6 ][ 0 ] = "vox_maxi_audio_log_6_1_0"; + a_audiologs[ 6 ][ 1 ] = "vox_maxi_audio_log_6_2_0"; + return a_audiologs; +} + +start_narrative_vo() +{ + flag_wait( "start_zombie_round_logic" ); + set_players_dontspeak( 1 ); + wait 10; + if ( is_game_solo() ) + { + game_start_solo_vo(); + } + else + { + game_start_vo(); + } + level waittill( "end_of_round" ); + level thread round_two_end_narrative_vo(); + if ( is_game_solo() ) + { + round_one_end_solo_vo(); + } + else + { + round_one_end_vo(); + } + flag_set( "round_one_narrative_vo_complete" ); +} + +start_samantha_intro_vo() +{ + while ( 1 ) + { + level waittill( "start_of_round" ); + if ( level.round_number == 5 ) + { + samantha_intro_1(); + continue; + } + else if ( level.round_number == 6 ) + { + samantha_intro_2(); + continue; + } + else + { + if ( level.round_number == 7 ) + { + samantha_intro_3(); + flag_set( "samantha_intro_done" ); + return; + } + } + else + { + } + } +} + +samantha_intro_1() +{ +/# + iprintln( "samantha_intro_1" ); +#/ + players = getplayers(); + if ( !isDefined( players[ 0 ] ) ) + { + return; + } + flag_waitopen( "story_vo_playing" ); + flag_set( "story_vo_playing" ); + set_players_dontspeak( 1 ); + samanthasay( "vox_sam_sam_help_5_0", players[ 0 ], 1, 1 ); + players = getplayers(); + _a1221 = players; + _k1221 = getFirstArrayKey( _a1221 ); + while ( isDefined( _k1221 ) ) + { + player = _a1221[ _k1221 ]; + if ( player.character_name != "Richtofen" ) + { + player play_category_on_player_character_if_present( "hear_samantha_1", player.character_name ); + wait 1; + play_line_on_player_character_if_present( "vox_plr_2_hear_samantha_1_0", "Richtofen" ); + break; + } + else + { + _k1221 = getNextArrayKey( _a1221, _k1221 ); + } + } + set_players_dontspeak( 0 ); + flag_clear( "story_vo_playing" ); +} + +samantha_intro_2() +{ +/# + iprintln( "samantha_intro_2" ); +#/ + player_richtofen = get_player_character_if_present( "Richtofen" ); + if ( !isDefined( player_richtofen ) ) + { + return; + } + flag_waitopen( "story_vo_playing" ); + flag_set( "story_vo_playing" ); + set_players_dontspeak( 1 ); + if ( isDefined( player_richtofen ) ) + { + nearest_friend = get_nearest_friend_within_speaking_distance( player_richtofen ); + if ( isDefined( nearest_friend ) ) + { + nearest_friend play_category_on_player_character_if_present( "heroes_confer", nearest_friend.character_name ); + wait 1; + play_line_on_player_character_if_present( "vox_plr_2_heroes_confer_0", "Richtofen" ); + } + } + set_players_dontspeak( 0 ); + flag_clear( "story_vo_playing" ); +} + +samantha_intro_3() +{ +/# + iprintln( "samantha_intro_3" ); +#/ + players = getplayers(); + if ( !isDefined( players[ 0 ] ) ) + { + return; + } + flag_waitopen( "story_vo_playing" ); + flag_set( "story_vo_playing" ); + set_players_dontspeak( 1 ); + samanthasay( "vox_sam_hear_samantha_3_0", players[ 0 ], 1, 1 ); + players = getplayers(); + player = players[ randomintrange( 0, players.size ) ]; + if ( isDefined( player ) ) + { + player play_category_on_player_character_if_present( "hear_samantha_3", player.character_name ); + } + set_players_dontspeak( 0 ); + flag_clear( "story_vo_playing" ); +} + +play_category_on_player_character_if_present( category, character_name ) +{ + vox_line_prefix = undefined; + switch( character_name ) + { + case "Dempsey": + vox_line_prefix = "vox_plr_0_"; + break; + case "Nikolai": + vox_line_prefix = "vox_plr_1_"; + break; + case "Richtofen": + vox_line_prefix = "vox_plr_2_"; + break; + case "Takeo": + vox_line_prefix = "vox_plr_3_"; + break; + } + vox_line = vox_line_prefix + category + "_0"; + play_line_on_player_character_if_present( vox_line, character_name ); +} + +get_nearest_friend_within_speaking_distance( other_player ) +{ + distance_nearest = 800; + nearest_friend = undefined; + players = getplayers(); + _a1326 = players; + _k1326 = getFirstArrayKey( _a1326 ); + while ( isDefined( _k1326 ) ) + { + player = _a1326[ _k1326 ]; + distance_between_players = distance( player.origin, other_player.origin ); + if ( player != other_player && distance_between_players < distance_nearest ) + { + nearest_friend = player; + distance_nearest = distance_between_players; + } + _k1326 = getNextArrayKey( _a1326, _k1326 ); + } + if ( isDefined( nearest_friend ) ) + { + return nearest_friend; + } + else + { + return undefined; + } +} + +play_line_on_player_character_if_present( vox_line, character_name ) +{ + player_character = get_player_character_if_present( character_name ); + if ( isDefined( player_character ) ) + { +/# + iprintln( "" + character_name + " says " + vox_line ); +#/ + player_character playsoundwithnotify( vox_line, "sound_done" + vox_line ); + player_character waittill( "sound_done" + vox_line ); + return 1; + } + else + { + return 0; + } +} + +get_player_character_if_present( character_name ) +{ + players = getplayers(); + _a1366 = players; + _k1366 = getFirstArrayKey( _a1366 ); + while ( isDefined( _k1366 ) ) + { + player = _a1366[ _k1366 ]; + if ( player.character_name == character_name ) + { + return player; + } + _k1366 = getNextArrayKey( _a1366, _k1366 ); + } + return undefined; +} + +round_two_end_narrative_vo() +{ + level waittill( "end_of_round" ); + flag_wait( "round_one_narrative_vo_complete" ); + if ( flag( "generator_find_vo_playing" ) ) + { + flag_waitopen( "generator_find_vo_playing" ); + wait 3; + } + if ( is_game_solo() ) + { + round_two_end_solo_vo(); + } +} + +game_start_solo_vo() +{ + if ( flag( "story_vo_playing" ) ) + { + return; + } + players = getplayers(); + e_speaker = players[ 0 ]; + if ( !isDefined( e_speaker ) ) + { + return; + } + a_convo = build_game_start_solo_convo(); + flag_set( "story_vo_playing" ); + set_players_dontspeak( 1 ); + lines = a_convo[ e_speaker.character_name ]; + if ( isarray( lines ) ) + { + i = 0; + while ( i < lines.size ) + { + e_speaker playsoundwithnotify( lines[ i ], "sound_done" + lines[ i ] ); + e_speaker waittill( "sound_done" + lines[ i ] ); + wait 1; + i++; + } + } + else e_speaker playsoundwithnotify( a_convo[ e_speaker.character_name ], "sound_done" + a_convo[ e_speaker.character_name ] ); + e_speaker waittill( "sound_done" + a_convo[ e_speaker.character_name ] ); + set_players_dontspeak( 0 ); + flag_clear( "story_vo_playing" ); +} + +build_game_start_solo_convo() +{ + a_game_start_solo_convo = []; + a_game_start_solo_convo[ "Dempsey" ] = "vox_plr_0_game_start_0"; + a_game_start_solo_convo[ "Nikolai" ] = "vox_plr_1_game_start_0"; + a_game_start_solo_convo[ "Richtofen" ] = []; + a_game_start_solo_convo[ "Richtofen" ][ 0 ] = "vox_plr_2_game_start_0"; + a_game_start_solo_convo[ "Richtofen" ][ 1 ] = "vox_plr_2_game_start_1"; + a_game_start_solo_convo[ "Takeo" ] = "vox_plr_3_game_start_0"; + return a_game_start_solo_convo; +} + +game_start_vo() +{ + players = getplayers(); + if ( players.size <= 1 ) + { + return; + } + if ( flag( "story_vo_playing" ) ) + { + return; + } + a_game_start_convo = build_game_start_convo(); + flag_set( "story_vo_playing" ); + e_dempsey = undefined; + e_nikolai = undefined; + e_richtofen = undefined; + e_takeo = undefined; + _a1477 = players; + _k1477 = getFirstArrayKey( _a1477 ); + while ( isDefined( _k1477 ) ) + { + player = _a1477[ _k1477 ]; + if ( isDefined( player ) ) + { + switch( player.character_name ) + { + case "Dempsey": + e_dempsey = player; + break; + break; + case "Nikolai": + e_nikolai = player; + break; + break; + case "Richtofen": + e_richtofen = player; + break; + break; + case "Takeo": + e_takeo = player; + break; + break; + } + } + _k1477 = getNextArrayKey( _a1477, _k1477 ); + } + set_players_dontspeak( 1 ); + i = 0; + while ( i < a_game_start_convo.size ) + { + players = getplayers(); + if ( players.size <= 1 ) + { + set_players_dontspeak( 0 ); + flag_clear( "story_vo_playing" ); + return; + } + if ( !isDefined( e_richtofen ) ) + { + i++; + continue; + } + else line_number = i + 1; + if ( line_number == 2 ) + { + a_richtofen_lines = a_game_start_convo[ "line_" + line_number ]; + j = 0; + while ( j < a_richtofen_lines.size ) + { + e_richtofen playsoundwithnotify( a_richtofen_lines[ j ], "sound_done" + a_richtofen_lines[ j ] ); + e_richtofen waittill( "sound_done" + a_richtofen_lines[ j ] ); + j++; + } + } + else arrayremovevalue( players, e_richtofen ); + players = get_array_of_closest( e_richtofen.origin, players ); + e_speaker = players[ 0 ]; + if ( !isDefined( e_speaker ) ) + { + i++; + continue; + } + else + { + e_speaker playsoundwithnotify( a_game_start_convo[ "line_" + line_number ][ e_speaker.character_name ], "sound_done" + a_game_start_convo[ "line_" + line_number ][ e_speaker.character_name ] ); + e_speaker waittill( "sound_done" + a_game_start_convo[ "line_" + line_number ][ e_speaker.character_name ] ); + } + i++; + } + set_players_dontspeak( 0 ); + flag_clear( "story_vo_playing" ); +} + +build_game_start_convo() +{ + a_game_start_convo = []; + a_game_start_convo[ "line_1" ] = []; + a_game_start_convo[ "line_1" ][ "Dempsey" ] = "vox_plr_0_game_start_meet_2_0"; + a_game_start_convo[ "line_1" ][ "Nikolai" ] = "vox_plr_1_game_start_meet_1_0"; + a_game_start_convo[ "line_1" ][ "Takeo" ] = "vox_plr_3_game_start_meet_3_0"; + a_game_start_convo[ "line_2" ] = []; + a_game_start_convo[ "line_2" ][ 0 ] = "vox_plr_2_game_start_meet_4_0"; + a_game_start_convo[ "line_2" ][ 1 ] = "vox_plr_2_generator_find_0"; + a_game_start_convo[ "line_3" ] = []; + a_game_start_convo[ "line_3" ][ "Dempsey" ] = "vox_plr_0_generator_find_0"; + a_game_start_convo[ "line_3" ][ "Nikolai" ] = "vox_plr_1_generator_find_0"; + a_game_start_convo[ "line_3" ][ "Takeo" ] = "vox_plr_3_generator_find_0"; + return a_game_start_convo; +} + +run_staff_crafted_vo( str_sam_line ) +{ + wait 1; + while ( isDefined( self.isspeaking ) && self.isspeaking ) + { + wait_network_frame(); + } + if ( level.n_staffs_crafted == 4 ) + { + all_staffs_crafted_vo(); + } + else + { + if ( isDefined( str_sam_line ) ) + { + flag_waitopen( "story_vo_playing" ); + flag_set( "story_vo_playing" ); + set_players_dontspeak( 1 ); + samanthasay( str_sam_line, self, 1 ); + set_players_dontspeak( 0 ); + flag_clear( "story_vo_playing" ); + } + } +} + +staff_craft_vo() +{ + staff_crafted = []; + lines = array( "vox_sam_1st_staff_crafted_0", "vox_sam_2nd_staff_crafted_0", "vox_sam_3rd_staff_crafted_0" ); + while ( staff_crafted.size < 4 ) + { + level waittill( "staff_crafted_vo", e_crafter, n_element ); + if ( isDefined( staff_crafted[ n_element ] ) && !staff_crafted[ n_element ] ) + { + staff_crafted[ n_element ] = 1; + line = lines[ level.n_staffs_crafted - 1 ]; + e_crafter thread run_staff_crafted_vo( line ); + } + } +} + +all_staffs_crafted_vo() +{ + while ( flag( "story_vo_playing" ) ) + { + wait_network_frame(); + } + a_convo = build_all_staffs_crafted_vo(); + flag_set( "story_vo_playing" ); + set_players_dontspeak( 1 ); + i = 0; + while ( i < a_convo.size ) + { + line_number = i + 1; + index = "line_" + line_number; + if ( isDefined( a_convo[ index ][ "Sam" ] ) ) + { + samanthasay( a_convo[ index ][ "Sam" ], self ); + i++; + continue; + } + else + { + line = a_convo[ index ][ self.character_name ]; + self playsoundwithnotify( line, "sound_done" + line ); + self waittill( "sound_done" + line ); + } + i++; + } + set_players_dontspeak( 0 ); + flag_clear( "story_vo_playing" ); +} + +build_all_staffs_crafted_vo() +{ + a_staff_convo = []; + a_staff_convo[ "line_1" ] = []; + a_staff_convo[ "line_1" ][ "Sam" ] = "vox_sam_4th_staff_crafted_0"; + a_staff_convo[ "line_2" ] = []; + a_staff_convo[ "line_2" ][ "Dempsey" ] = "vox_plr_0_4th_staff_crafted_0"; + a_staff_convo[ "line_2" ][ "Nikolai" ] = "vox_plr_1_4th_staff_crafted_0"; + a_staff_convo[ "line_2" ][ "Richtofen" ] = "vox_plr_2_4th_staff_crafted_0"; + a_staff_convo[ "line_2" ][ "Takeo" ] = "vox_plr_3_4th_staff_crafted_0"; + a_staff_convo[ "line_3" ] = []; + a_staff_convo[ "line_3" ][ "Sam" ] = "vox_sam_4th_staff_crafted_1"; + a_staff_convo[ "line_4" ] = []; + a_staff_convo[ "line_4" ][ "Dempsey" ] = "vox_plr_0_4th_staff_crafted_1"; + a_staff_convo[ "line_4" ][ "Nikolai" ] = "vox_plr_1_4th_staff_crafted_1"; + a_staff_convo[ "line_4" ][ "Richtofen" ] = "vox_plr_2_4th_staff_crafted_1"; + a_staff_convo[ "line_4" ][ "Takeo" ] = "vox_plr_3_4th_staff_crafted_1"; + a_staff_convo[ "line_5" ] = []; + a_staff_convo[ "line_5" ][ "Sam" ] = "vox_sam_generic_encourage_6"; + return a_staff_convo; +} + +get_left_behind_plea() +{ + pl_num = 0; + if ( self.character_name == "Nikolai" ) + { + pl_num = 1; + } + else if ( self.character_name == "Richtofen" ) + { + pl_num = 2; + } + else + { + if ( self.character_name == "Takeo" ) + { + pl_num = 3; + } + } + return "vox_plr_" + pl_num + "_miss_tank_" + randomint( 3 ); +} + +get_left_behind_response( e_victim ) +{ + if ( self.character_name == "Dempsey" ) + { + if ( cointoss() ) + { + return "vox_plr_0_tank_rspnd_generic_0"; + } + else + { + if ( e_victim.character_name == "Nikolai" ) + { + return "vox_plr_0_tank_rspnd_to_plr_1_0"; + } + else + { + if ( e_victim.character_name == "Richtofen" ) + { + return "vox_plr_0_tank_rspnd_to_plr_2_0"; + } + else + { + if ( e_victim.character_name == "Takeo" ) + { + return "vox_plr_0_tank_rspnd_to_plr_3_0"; + } + } + } + } + } + else + { + if ( self.character_name == "Nikolai" ) + { + if ( cointoss() ) + { + return "vox_plr_1_tank_rspnd_generic_0"; + } + else + { + if ( e_victim.character_name == "Dempsey" ) + { + return "vox_plr_1_tank_rspnd_to_plr_0_0"; + } + else + { + if ( e_victim.character_name == "Richtofen" ) + { + return "vox_plr_1_tank_rspnd_to_plr_2_0"; + } + else + { + if ( e_victim.character_name == "Takeo" ) + { + return "vox_plr_1_tank_rspnd_to_plr_3_0"; + } + } + } + } + } + else + { + if ( self.character_name == "Richtofen" ) + { + if ( cointoss() ) + { + return "vox_plr_2_tank_rspnd_generic_0"; + } + else + { + if ( e_victim.character_name == "Dempsey" ) + { + return "vox_plr_2_tank_rspnd_to_plr_0_0"; + } + else + { + if ( e_victim.character_name == "Nikolai" ) + { + return "vox_plr_2_tank_rspnd_to_plr_1_0"; + } + else + { + if ( e_victim.character_name == "Takeo" ) + { + return "vox_plr_2_tank_rspnd_to_plr_3_0"; + } + } + } + } + } + else + { + if ( self.character_name == "Takeo" ) + { + if ( cointoss() ) + { + return "vox_plr_3_tank_rspnd_generic_0"; + } + else + { + if ( e_victim.character_name == "Dempsey" ) + { + return "vox_plr_3_tank_rspnd_to_plr_0_0"; + } + else + { + if ( e_victim.character_name == "Nikolai" ) + { + return "vox_plr_3_tank_rspnd_to_plr_1_0"; + } + else + { + if ( e_victim.character_name == "Richtofen" ) + { + return "vox_plr_3_tank_rspnd_to_plr_2_0"; + } + } + } + } + } + } + } + } + return undefined; +} + +tank_left_behind_vo( e_victim, e_rider ) +{ + if ( !isDefined( e_victim ) || !isDefined( e_rider ) ) + { + return; + } + if ( flag( "story_vo_playing" ) ) + { + return; + } + flag_set( "story_vo_playing" ); + set_players_dontspeak( 1 ); + e_victim.isspeaking = 1; + e_rider.isspeaking = 1; + str_plea_line = e_victim get_left_behind_plea(); + e_victim playsoundwithnotify( str_plea_line, "sound_done" + str_plea_line ); + e_victim waittill( "sound_done" + str_plea_line ); + str_rider_line = e_rider get_left_behind_response( e_victim ); + e_victim playsoundwithnotify( str_rider_line, "sound_done" + str_rider_line ); + e_victim waittill( "sound_done" + str_rider_line ); + e_victim.isspeaking = 0; + e_rider.isspeaking = 0; + set_players_dontspeak( 0 ); + flag_clear( "story_vo_playing" ); +} + +round_one_end_solo_vo() +{ + if ( flag( "story_vo_playing" ) ) + { + return; + } + players = getplayers(); + e_speaker = players[ 0 ]; + if ( !isDefined( e_speaker ) ) + { + return; + } + a_convo = build_round_one_end_solo_convo(); + flag_set( "story_vo_playing" ); + set_players_dontspeak( 1 ); + lines = a_convo[ e_speaker.character_name ]; + if ( isarray( lines ) ) + { + i = 0; + while ( i < lines.size ) + { + e_speaker playsoundwithnotify( lines[ i ], "sound_done" + lines[ i ] ); + e_speaker waittill( "sound_done" + lines[ i ] ); + wait 1; + i++; + } + } + else e_speaker playsoundwithnotify( a_convo[ e_speaker.character_name ], "sound_done" + a_convo[ e_speaker.character_name ] ); + e_speaker waittill( "sound_done" + a_convo[ e_speaker.character_name ] ); + set_players_dontspeak( 0 ); + flag_clear( "story_vo_playing" ); +} + +build_round_one_end_solo_convo() +{ + a_round_one_end_solo_convo = []; + a_round_one_end_solo_convo[ "Dempsey" ] = []; + a_round_one_end_solo_convo[ "Dempsey" ][ 0 ] = "vox_plr_0_end_round_1_5_0"; + a_round_one_end_solo_convo[ "Dempsey" ][ 1 ] = "vox_plr_0_end_round_1_6_1"; + a_round_one_end_solo_convo[ "Nikolai" ] = "vox_plr_1_end_round_1_9_0"; + a_round_one_end_solo_convo[ "Richtofen" ] = "vox_plr_2_end_round_1_7_0"; + a_round_one_end_solo_convo[ "Takeo" ] = "vox_plr_3_end_round_1_8_0"; + return a_round_one_end_solo_convo; +} + +round_one_end_vo() +{ + players = getplayers(); + if ( players.size <= 1 ) + { + return; + } + if ( flag( "story_vo_playing" ) ) + { + return; + } + a_convo = build_round_one_end_convo(); + flag_set( "story_vo_playing" ); + e_dempsey = undefined; + e_nikolai = undefined; + e_richtofen = undefined; + e_takeo = undefined; + _a1894 = players; + _k1894 = getFirstArrayKey( _a1894 ); + while ( isDefined( _k1894 ) ) + { + player = _a1894[ _k1894 ]; + if ( isDefined( player ) ) + { + switch( player.character_name ) + { + case "Dempsey": + e_dempsey = player; + break; + break; + case "Nikolai": + e_nikolai = player; + break; + break; + case "Richtofen": + e_richtofen = player; + break; + break; + case "Takeo": + e_takeo = player; + break; + break; + } + } + _k1894 = getNextArrayKey( _a1894, _k1894 ); + } + set_players_dontspeak( 1 ); + i = 0; + while ( i < a_convo.size ) + { + players = getplayers(); + if ( players.size <= 1 ) + { + set_players_dontspeak( 0 ); + flag_clear( "story_vo_playing" ); + return; + } + if ( !isDefined( e_richtofen ) ) + { + i++; + continue; + } + else line_number = i + 1; + if ( line_number == 2 ) + { + a_richtofen_lines = a_convo[ "line_" + line_number ]; + j = 0; + while ( j < a_richtofen_lines.size ) + { + e_richtofen playsoundwithnotify( a_richtofen_lines[ j ], "sound_done" + a_richtofen_lines[ j ] ); + e_richtofen waittill( "sound_done" + a_richtofen_lines[ j ] ); + j++; + } + } + else arrayremovevalue( players, e_richtofen ); + players = get_array_of_closest( e_richtofen.origin, players ); + e_speaker = players[ 0 ]; + if ( !isDefined( e_speaker ) ) + { + i++; + continue; + } + else + { + e_speaker playsoundwithnotify( a_convo[ "line_" + line_number ][ e_speaker.character_name ], "sound_done" + a_convo[ "line_" + line_number ][ e_speaker.character_name ] ); + e_speaker waittill( "sound_done" + a_convo[ "line_" + line_number ][ e_speaker.character_name ] ); + } + i++; + } + set_players_dontspeak( 0 ); + flag_clear( "story_vo_playing" ); +} + +build_round_one_end_convo() +{ + a_round_one_end_convo = []; + a_round_one_end_convo[ "line_1" ] = []; + a_round_one_end_convo[ "line_1" ][ "Dempsey" ] = "vox_plr_0_end_round_1_1_0"; + a_round_one_end_convo[ "line_1" ][ "Nikolai" ] = "vox_plr_1_end_round_1_3_0"; + a_round_one_end_convo[ "line_1" ][ "Takeo" ] = "vox_plr_3_end_round_1_2_0"; + a_round_one_end_convo[ "line_2" ] = []; + a_round_one_end_convo[ "line_2" ][ 0 ] = "vox_plr_2_story_exposition_4_0"; + a_round_one_end_convo[ "line_3" ] = []; + a_round_one_end_convo[ "line_3" ][ "Dempsey" ] = "vox_plr_0_during_round_1_0"; + a_round_one_end_convo[ "line_3" ][ "Nikolai" ] = "vox_plr_1_during_round_2_0"; + a_round_one_end_convo[ "line_3" ][ "Takeo" ] = "vox_plr_3_during_round_2_0"; + return a_round_one_end_convo; +} + +round_two_end_solo_vo() +{ + if ( flag( "story_vo_playing" ) ) + { + return; + } + players = getplayers(); + e_speaker = players[ 0 ]; + if ( !isDefined( e_speaker ) ) + { + return; + } + a_convo = build_round_two_end_solo_convo(); + flag_set( "story_vo_playing" ); + set_players_dontspeak( 1 ); + lines = a_convo[ e_speaker.character_name ]; + if ( isarray( lines ) ) + { + i = 0; + while ( i < lines.size ) + { + e_speaker playsoundwithnotify( lines[ i ], "sound_done" + lines[ i ] ); + e_speaker waittill( "sound_done" + lines[ i ] ); + wait 1; + i++; + } + } + else e_speaker playsoundwithnotify( a_convo[ e_speaker.character_name ], "sound_done" + a_convo[ e_speaker.character_name ] ); + e_speaker waittill( "sound_done" + a_convo[ e_speaker.character_name ] ); + set_players_dontspeak( 0 ); + flag_clear( "story_vo_playing" ); +} + +build_round_two_end_solo_convo() +{ + a_round_two_end_solo_convo = []; + a_round_two_end_solo_convo[ "Dempsey" ] = "vox_plr_0_end_round_2_1_0"; + a_round_two_end_solo_convo[ "Nikolai" ] = "vox_plr_1_end_round_2_5_0"; + a_round_two_end_solo_convo[ "Richtofen" ] = []; + a_round_two_end_solo_convo[ "Richtofen" ][ 0 ] = "vox_plr_2_end_round_2_2_0"; + a_round_two_end_solo_convo[ "Richtofen" ][ 1 ] = "vox_plr_2_end_round_2_3_1"; + a_round_two_end_solo_convo[ "Takeo" ] = "vox_plr_3_end_round_2_4_0"; + return a_round_two_end_solo_convo; +} + +first_magic_box_seen_vo() +{ + flag_wait( "start_zombie_round_logic" ); + magicbox = level.chests[ level.chest_index ]; + a_players = getplayers(); + _a2048 = a_players; + _k2048 = getFirstArrayKey( _a2048 ); + while ( isDefined( _k2048 ) ) + { + player = _a2048[ _k2048 ]; + player thread wait_and_play_first_magic_box_seen_vo( magicbox.unitrigger_stub ); + _k2048 = getNextArrayKey( _a2048, _k2048 ); + } +} + +wait_and_play_first_magic_box_seen_vo( struct ) +{ + self endon( "disconnect" ); + level endon( "first_maigc_box_discovered" ); + while ( 1 ) + { + if ( distancesquared( self.origin, struct.origin ) < 40000 ) + { + if ( self is_player_looking_at( struct.origin, 0,75 ) ) + { + if ( isDefined( self.dontspeak ) && !self.dontspeak ) + { + while ( flag( "story_vo_playing" ) ) + { + wait 0,1; + } + players = getplayers(); + a_speakers = []; + _a2077 = players; + _k2077 = getFirstArrayKey( _a2077 ); + while ( isDefined( _k2077 ) ) + { + player = _a2077[ _k2077 ]; + if ( isDefined( player ) && distance2dsquared( player.origin, self.origin ) <= 1000000 ) + { + switch( player.character_name ) + { + case "Dempsey": + e_dempsey = player; + a_speakers[ a_speakers.size ] = e_dempsey; + break; + break; + case "Nikolai": + e_nikolai = player; + a_speakers[ a_speakers.size ] = e_nikolai; + break; + break; + case "Richtofen": + e_richtofen = player; + a_speakers[ a_speakers.size ] = e_richtofen; + break; + break; + case "Takeo": + e_takeo = player; + a_speakers[ a_speakers.size ] = e_takeo; + break; + break; + } + } + _k2077 = getNextArrayKey( _a2077, _k2077 ); + } + while ( !isDefined( e_richtofen ) ) + { + wait 0,1; + } + while ( a_speakers.size < 2 ) + { + wait 0,1; + } + flag_set( "story_vo_playing" ); + set_players_dontspeak( 1 ); + a_convo = build_first_magic_box_seen_vo(); + if ( isDefined( e_richtofen ) ) + { + e_richtofen playsoundwithnotify( a_convo[ 0 ][ e_richtofen.character_name ], "sound_done" + a_convo[ 0 ][ e_richtofen.character_name ] ); + e_richtofen waittill( "sound_done" + a_convo[ 0 ][ e_richtofen.character_name ] ); + } + if ( isDefined( struct.trigger_target ) && isDefined( struct.trigger_target.is_locked ) ) + { + arrayremovevalue( a_speakers, e_richtofen ); + a_speakers = get_array_of_closest( e_richtofen.origin, a_speakers ); + e_speaker = a_speakers[ 0 ]; + if ( distancesquared( e_speaker.origin, e_richtofen.origin ) < 2250000 ) + { + if ( isDefined( e_speaker ) ) + { + e_speaker playsoundwithnotify( a_convo[ 1 ][ e_speaker.character_name ], "sound_done" + a_convo[ 1 ][ e_speaker.character_name ] ); + e_speaker waittill( "sound_done" + a_convo[ 1 ][ e_speaker.character_name ] ); + } + } + } + if ( isDefined( struct.trigger_target ) && isDefined( struct.trigger_target.is_locked ) ) + { + if ( struct.trigger_target.is_locked == 1 ) + { + if ( isDefined( e_richtofen ) ) + { + e_richtofen playsoundwithnotify( a_convo[ 2 ][ e_richtofen.character_name ], "sound_done" + a_convo[ 2 ][ e_richtofen.character_name ] ); + e_richtofen waittill( "sound_done" + a_convo[ 2 ][ e_richtofen.character_name ] ); + } + } + } + set_players_dontspeak( 0 ); + flag_clear( "story_vo_playing" ); + level notify( "first_maigc_box_discovered" ); + return; + } + } + } + else + { + wait 0,1; + } + } +} + +build_first_magic_box_seen_vo() +{ + a_first_magic_box_seen_convo = []; + a_first_magic_box_seen_convo[ 0 ] = []; + a_first_magic_box_seen_convo[ 0 ][ "Richtofen" ] = "vox_plr_2_respond_maxis_1_0"; + a_first_magic_box_seen_convo[ 1 ] = []; + a_first_magic_box_seen_convo[ 1 ][ "Dempsey" ] = "vox_plr_0_respond_maxis_2_0"; + a_first_magic_box_seen_convo[ 1 ][ "Takeo" ] = "vox_plr_3_respond_maxis_3_0"; + a_first_magic_box_seen_convo[ 1 ][ "Nikolai" ] = "vox_plr_1_respond_maxis_4_0"; + a_first_magic_box_seen_convo[ 2 ] = []; + a_first_magic_box_seen_convo[ 2 ][ "Richtofen" ] = "vox_plr_2_respond_maxis_5_0"; + return a_first_magic_box_seen_convo; +} + +tomb_drone_built_vo( s_craftable ) +{ + if ( s_craftable.weaponname != "equip_dieseldrone_zm" ) + { + return; + } + flag_waitopen( "story_vo_playing" ); + flag_set( "story_vo_playing" ); + set_players_dontspeak( 1 ); + wait 1; + e_vo_origin = get_speaking_location_maxis_drone( self, s_craftable ); + vox_line = "vox_maxi_maxis_drone_1_0"; + e_vo_origin playsoundwithnotify( vox_line, "sound_done" + vox_line ); +/# + iprintln( "Maxis says " + vox_line ); +#/ + e_vo_origin waittill( "sound_done" + vox_line ); + e_vo_origin delete(); + wait 1; + e_vo_origin = get_speaking_location_maxis_drone( self, s_craftable ); + vox_line = "vox_maxi_maxis_drone_4_0"; + e_vo_origin playsoundwithnotify( vox_line, "sound_done" + vox_line ); +/# + iprintln( "Maxis says " + vox_line ); +#/ + e_vo_origin waittill( "sound_done" + vox_line ); + e_vo_origin delete(); + wait 1; + if ( isDefined( self ) && self.character_name == "Richtofen" ) + { + vox_line = "vox_plr_2_maxis_drone_5_0"; +/# + iprintln( "" + self.character_name + " says " + vox_line ); +#/ + self playsoundwithnotify( vox_line, "sound_done" + vox_line ); + self waittill( "sound_done" + vox_line ); + } + set_players_dontspeak( 0 ); + flag_clear( "story_vo_playing" ); + flag_set( "maxis_crafted_intro_done" ); +} + +get_speaking_location_maxis_drone( player, s_craftable ) +{ + e_vo_origin = undefined; + if ( isDefined( level.maxis_quadrotor ) ) + { + e_vo_origin = spawn( "script_origin", level.maxis_quadrotor.origin ); + e_vo_origin linkto( level.maxis_quadrotor ); + } + else player = b_player_has_dieseldrone_weapon(); + if ( isDefined( player ) ) + { + e_vo_origin = spawn( "script_origin", player.origin ); + e_vo_origin linkto( player ); + } + else + { + e_vo_origin = spawn( "script_origin", s_craftable.origin ); + } + return e_vo_origin; +} + +b_player_has_dieseldrone_weapon() +{ + a_players = getplayers(); + _a2268 = a_players; + _k2268 = getFirstArrayKey( _a2268 ); + while ( isDefined( _k2268 ) ) + { + player = _a2268[ _k2268 ]; + if ( player hasweapon( "equip_dieseldrone_zm" ) ) + { + return player; + } + _k2268 = getNextArrayKey( _a2268, _k2268 ); + } + return undefined; +} + +set_players_dontspeak( bool ) +{ + players = getplayers(); + if ( bool ) + { + _a2289 = players; + _k2289 = getFirstArrayKey( _a2289 ); + while ( isDefined( _k2289 ) ) + { + player = _a2289[ _k2289 ]; + if ( isDefined( player ) ) + { + player.dontspeak = 1; + player setclientfieldtoplayer( "isspeaking", 1 ); + } + _k2289 = getNextArrayKey( _a2289, _k2289 ); + } + _a2298 = players; + _k2298 = getFirstArrayKey( _a2298 ); + while ( isDefined( _k2298 ) ) + { + player = _a2298[ _k2298 ]; + while ( isDefined( player ) && isDefined( player.isspeaking ) && player.isspeaking ) + { + wait 0,1; + } + _k2298 = getNextArrayKey( _a2298, _k2298 ); + } + } + else _a2308 = players; + _k2308 = getFirstArrayKey( _a2308 ); + while ( isDefined( _k2308 ) ) + { + player = _a2308[ _k2308 ]; + if ( isDefined( player ) ) + { + player.dontspeak = 0; + player setclientfieldtoplayer( "isspeaking", 0 ); + } + _k2308 = getNextArrayKey( _a2308, _k2308 ); + } +} + +set_player_dontspeak( bool ) +{ + if ( bool ) + { + self.dontspeak = 1; + self setclientfieldtoplayer( "isspeaking", 1 ); + while ( isDefined( self ) && isDefined( self.isspeaking ) && self.isspeaking ) + { + wait 0,1; + } + } + else self.dontspeak = 0; + self setclientfieldtoplayer( "isspeaking", 0 ); +} + +is_game_solo() +{ + players = getplayers(); + if ( players.size == 1 ) + { + return 1; + } + else + { + return 0; + } +} + +add_puzzle_completion_line( n_element_enum, str_line ) +{ + if ( !isDefined( level.puzzle_completion_lines ) ) + { + level.puzzle_completion_lines = []; + level.puzzle_completion_lines_count = []; + } + if ( !isDefined( level.puzzle_completion_lines[ n_element_enum ] ) ) + { + level.puzzle_completion_lines[ n_element_enum ] = []; + level.puzzle_completion_lines_count[ n_element_enum ] = 0; + } + level.puzzle_completion_lines[ n_element_enum ][ level.puzzle_completion_lines[ n_element_enum ].size ] = str_line; +} + +say_puzzle_completion_line( n_element_enum ) +{ + level notify( "quest_progressed" ); + wait 4; + if ( level.puzzle_completion_lines_count[ n_element_enum ] >= level.puzzle_completion_lines[ n_element_enum ].size ) + { +/# + iprintlnbold( "Out of puzzle completion lines for element " + n_element_enum ); +#/ + return; + } + str_line = level.puzzle_completion_lines[ n_element_enum ][ level.puzzle_completion_lines_count[ n_element_enum ] ]; + level.puzzle_completion_lines_count[ n_element_enum ]++; + set_players_dontspeak( 1 ); + level samanthasay( str_line, self ); + set_players_dontspeak( 0 ); +} + +watch_occasional_line( str_category, str_line, str_notify, n_time_between, n_times_to_play ) +{ + if ( !isDefined( n_time_between ) ) + { + n_time_between = 30; + } + if ( !isDefined( n_times_to_play ) ) + { + n_times_to_play = 100; + } + i = 0; + while ( i < n_times_to_play ) + { + level waittill( str_notify, e_player ); + if ( isDefined( e_player ) ) + { + e_player maps/mp/zombies/_zm_audio::create_and_play_dialog( str_category, str_line ); + wait n_time_between; + } + i++; + } +} + +watch_one_shot_line( str_category, str_line, str_notify ) +{ + while ( 1 ) + { + level waittill( str_notify, e_player ); + if ( isDefined( e_player ) ) + { + e_player maps/mp/zombies/_zm_audio::create_and_play_dialog( str_category, str_line ); + return; + } + } +} + +watch_one_shot_samantha_line( str_line, str_notify ) +{ + while ( 1 ) + { + level waittill( str_notify, e_play_on ); + if ( isDefined( e_play_on ) ) + { + set_players_dontspeak( 1 ); + if ( samanthasay( str_line, e_play_on ) ) + { + set_players_dontspeak( 0 ); + return; + } + set_players_dontspeak( 0 ); + } + } +} + +watch_one_shot_samantha_clue( str_line, str_notify, str_endon ) +{ + if ( isDefined( str_endon ) ) + { + level endon( str_endon ); + } + if ( !isDefined( level.next_samantha_clue_time ) ) + { + level.next_samantha_clue_time = getTime(); + } + while ( 1 ) + { + level waittill( str_notify, e_player ); + wait 10; + if ( isDefined( e_player ) && isDefined( e_player.vo_promises_playing ) && e_player.vo_promises_playing ) + { + continue; + } + while ( isDefined( level.sam_talking ) && level.sam_talking ) + { + wait_network_frame(); + } + while ( level.next_samantha_clue_time > getTime() ) + { + continue; + } + while ( !isplayer( e_player ) ) + { + a_players = getplayers(); + _a2486 = a_players; + _k2486 = getFirstArrayKey( _a2486 ); + while ( isDefined( _k2486 ) ) + { + player = _a2486[ _k2486 ]; + if ( player.zombie_vars[ "zombie_powerup_zombie_blood_on" ] ) + { + e_player = player; + break; + } + else + { + _k2486 = getNextArrayKey( _a2486, _k2486 ); + } + } + } + if ( isDefined( e_player ) && isplayer( e_player ) && e_player.zombie_vars[ "zombie_powerup_zombie_blood_on" ] && flag( "samantha_intro_done" ) ) + { + flag_waitopen( "story_vo_playing" ); + flag_set( "story_vo_playing" ); + while ( isDefined( e_player.isspeaking ) && e_player.isspeaking ) + { + wait_network_frame(); + } + while ( !is_player_valid( e_player ) ) + { + continue; + } + set_players_dontspeak( 1 ); + level.sam_talking = 1; + e_player playsoundtoplayer( str_line, e_player ); + n_duration = soundgetplaybacktime( str_line ); + wait ( n_duration / 1000 ); + level.sam_talking = 0; + level.next_samantha_clue_time = getTime() + 300000; + flag_clear( "story_vo_playing" ); + set_players_dontspeak( 0 ); + return; + } + } +} + +samantha_discourage_reset() +{ + n_min_time = 60000 * 5; + n_max_time = 60000 * 10; + level.sam_next_beratement = getTime() + randomintrange( n_min_time, n_max_time ); +} + +samantha_encourage_watch_good_lines() +{ + while ( 1 ) + { + level waittill( "vo_puzzle_good", e_player ); + wait 1; + level notify( "quest_progressed" ); + } +} + +samantha_encourage_think() +{ + original_list = array( "vox_sam_generic_encourage_0", "vox_sam_generic_encourage_1", "vox_sam_generic_encourage_2", "vox_sam_generic_encourage_3", "vox_sam_generic_encourage_4", "vox_sam_generic_encourage_5" ); + available_list = []; + n_min_time = 60000 * 5; + n_max_time = 60000 * 10; + next_encouragement = 0; + level thread samantha_encourage_watch_good_lines(); + while ( 1 ) + { + if ( available_list.size == 0 ) + { + available_list = arraycopy( original_list ); + } + e_player = undefined; + say_something = 0; + level waittill( "quest_progressed", e_player, say_something ); + samantha_discourage_reset(); + while ( getTime() < next_encouragement ) + { + continue; + } + if ( isDefined( say_something ) && !say_something ) + { + continue; + } + while ( !isDefined( e_player ) ) + { + continue; + } + while ( !is_player_valid( e_player ) ) + { + continue; + } + if ( isDefined( level.sam_talking ) && level.sam_talking ) + { + continue; + } + while ( flag( "story_vo_playing" ) || isDefined( e_player.isspeaking ) && e_player.isspeaking ) + { + wait_network_frame(); + } + line = random( available_list ); + arrayremovevalue( available_list, line ); + set_players_dontspeak( 1 ); + if ( samanthasay( line, e_player, 1 ) ) + { + set_players_dontspeak( 0 ); + e_player maps/mp/zombies/_zm_audio::create_and_play_dialog( "puzzle", "encourage_respond" ); + next_encouragement = getTime() + randomintrange( n_min_time, n_max_time ); + } + set_players_dontspeak( 0 ); + } +} + +samantha_discourage_think() +{ + level endon( "ee_all_staffs_upgraded" ); + original_list = array( "vox_sam_generic_chastise_0", "vox_sam_generic_chastise_1", "vox_sam_generic_chastise_2", "vox_sam_generic_chastise_3", "vox_sam_generic_chastise_4", "vox_sam_generic_chastise_5", "vox_sam_generic_chastise_6" ); + available_list = []; + flag_wait( "samantha_intro_done" ); + while ( 1 ) + { + if ( available_list.size == 0 ) + { + available_list = arraycopy( original_list ); + } + samantha_discourage_reset(); + while ( getTime() < level.sam_next_beratement ) + { + wait 1; + } + line = random( available_list ); + arrayremovevalue( available_list, line ); + a_players = getplayers(); + while ( a_players.size > 0 ) + { + e_player = random( a_players ); + arrayremovevalue( a_players, e_player ); + if ( is_player_valid( e_player ) ) + { + samanthasay( line, e_player, 1 ); + e_player maps/mp/zombies/_zm_audio::create_and_play_dialog( "puzzle", "berate_respond" ); + break; + } + else + { + } + } + } +} + +samanthasay( vox_line, e_source, b_wait_for_nearby_speakers, intro_line ) +{ + if ( !isDefined( b_wait_for_nearby_speakers ) ) + { + b_wait_for_nearby_speakers = 0; + } + if ( !isDefined( intro_line ) ) + { + intro_line = 0; + } + level endon( "end_game" ); + if ( !intro_line && !flag( "samantha_intro_done" ) ) + { + return 0; + } + else + { + if ( intro_line && flag( "samantha_intro_done" ) ) + { + return 0; + } + } + while ( isDefined( level.sam_talking ) && level.sam_talking ) + { + wait_network_frame(); + } + level.sam_talking = 1; + while ( b_wait_for_nearby_speakers ) + { + nearbyplayers = get_array_of_closest( e_source.origin, get_players(), undefined, undefined, 256 ); + while ( isDefined( nearbyplayers ) && nearbyplayers.size > 0 ) + { + _a2717 = nearbyplayers; + _k2717 = getFirstArrayKey( _a2717 ); + while ( isDefined( _k2717 ) ) + { + player = _a2717[ _k2717 ]; + while ( isDefined( player ) && isDefined( player.isspeaking ) && player.isspeaking ) + { + wait 0,05; + } + _k2717 = getNextArrayKey( _a2717, _k2717 ); + } + } + } + level thread samanthasayvoplay( e_source, vox_line ); + level waittill( "SamanthaSay_vo_finished" ); + return 1; +} + +samanthasayvoplay( e_source, vox_line ) +{ + e_source playsoundwithnotify( vox_line, "sound_done" + vox_line ); + e_source waittill( "sound_done" + vox_line ); + level.sam_talking = 0; + level notify( "SamanthaSay_vo_finished" ); +} + +maxissay( vox_line, m_spot_override, b_wait_for_nearby_speakers ) +{ + level endon( "end_game" ); + level endon( "intermission" ); + if ( isDefined( level.intermission ) && level.intermission ) + { + return; + } + if ( !flag( "maxis_crafted_intro_done" ) ) + { + return; + } + while ( isDefined( level.maxis_talking ) && level.maxis_talking ) + { + wait 0,05; + } + level.maxis_talking = 1; +/# + iprintlnbold( "Maxis Says: " + vox_line ); +#/ + if ( isDefined( m_spot_override ) ) + { + m_vo_spot = m_spot_override; + } + while ( isDefined( b_wait_for_nearby_speakers ) && b_wait_for_nearby_speakers ) + { + nearbyplayers = get_array_of_closest( m_vo_spot.origin, get_players(), undefined, undefined, 256 ); + while ( isDefined( nearbyplayers ) && nearbyplayers.size > 0 ) + { + _a2793 = nearbyplayers; + _k2793 = getFirstArrayKey( _a2793 ); + while ( isDefined( _k2793 ) ) + { + player = _a2793[ _k2793 ]; + while ( isDefined( player ) && isDefined( player.isspeaking ) && player.isspeaking ) + { + wait 0,05; + } + _k2793 = getNextArrayKey( _a2793, _k2793 ); + } + } + } + level thread maxissayvoplay( m_vo_spot, vox_line ); + level waittill( "MaxisSay_vo_finished" ); +} + +maxissayvoplay( m_vo_spot, vox_line ) +{ + m_vo_spot playsoundwithnotify( vox_line, "sound_done" + vox_line ); + m_vo_spot waittill_either( "sound_done" + vox_line, "death" ); + level.maxis_talking = 0; + level notify( "MaxisSay_vo_finished" ); +} + +richtofenrespondvoplay( vox_category, b_richtofen_first, str_flag ) +{ + if ( !isDefined( b_richtofen_first ) ) + { + b_richtofen_first = 0; + } + if ( flag( "story_vo_playing" ) ) + { + return; + } + flag_set( "story_vo_playing" ); + set_players_dontspeak( 1 ); + if ( b_richtofen_first ) + { + if ( self.character_name == "Richtofen" ) + { + str_vox_line = "vox_plr_" + self.characterindex + "_" + vox_category + "_0"; + self playsoundwithnotify( str_vox_line, "rich_done" ); + self waittill( "rich_done" ); + wait 0,5; + _a2846 = getplayers(); + _k2846 = getFirstArrayKey( _a2846 ); + while ( isDefined( _k2846 ) ) + { + player = _a2846[ _k2846 ]; + if ( player.character_name != "Richtofen" && distance2d( player.origin, self.origin ) < 800 ) + { + str_vox_line = "vox_plr_" + player.characterindex + "_" + vox_category + "_0"; + player playsoundwithnotify( str_vox_line, "rich_done" ); + player waittill( "rich_done" ); + } + _k2846 = getNextArrayKey( _a2846, _k2846 ); + } + } + else _a2859 = getplayers(); + _k2859 = getFirstArrayKey( _a2859 ); + while ( isDefined( _k2859 ) ) + { + player = _a2859[ _k2859 ]; + if ( player.character_name == "Richtofen" && distance2d( player.origin, self.origin ) < 800 ) + { + str_vox_line = "vox_plr_" + player.characterindex + "_" + vox_category + "_0"; + player playsoundwithnotify( str_vox_line, "rich_done" ); + player waittill( "rich_done" ); + wait 0,5; + } + _k2859 = getNextArrayKey( _a2859, _k2859 ); + } + if ( isDefined( self ) ) + { + str_vox_line = "vox_plr_" + self.characterindex + "_" + vox_category + "_0"; + self playsoundwithnotify( str_vox_line, "rich_response" ); + self waittill( "rich_response" ); + } + } + else if ( self.character_name == "Richtofen" ) + { + _a2886 = getplayers(); + _k2886 = getFirstArrayKey( _a2886 ); + while ( isDefined( _k2886 ) ) + { + player = _a2886[ _k2886 ]; + if ( player.character_name != "Richtofen" && distance2d( player.origin, self.origin ) < 800 ) + { + str_vox_line = "vox_plr_" + player.characterindex + "_" + vox_category + "_0"; + player playsoundwithnotify( str_vox_line, "rich_done" ); + player waittill( "rich_done" ); + wait 0,5; + } + _k2886 = getNextArrayKey( _a2886, _k2886 ); + } + if ( isDefined( self ) ) + { + str_vox_line = "vox_plr_" + self.characterindex + "_" + vox_category + "_0"; + self playsoundwithnotify( str_vox_line, "rich_done" ); + self waittill( "rich_done" ); + } + } + else + { + str_vox_line = "vox_plr_" + self.characterindex + "_" + vox_category + "_0"; + self playsoundwithnotify( str_vox_line, "rich_response" ); + self waittill( "rich_response" ); + wait 0,5; + _a2916 = getplayers(); + _k2916 = getFirstArrayKey( _a2916 ); + while ( isDefined( _k2916 ) ) + { + player = _a2916[ _k2916 ]; + if ( player.character_name == "Richtofen" && distance2d( player.origin, self.origin ) < 800 ) + { + str_vox_line = "vox_plr_" + player.characterindex + "_" + vox_category + "_0"; + player playsoundwithnotify( str_vox_line, "rich_done" ); + player waittill( "rich_done" ); + } + _k2916 = getNextArrayKey( _a2916, _k2916 ); + } + } + if ( isDefined( str_flag ) ) + { + flag_set( str_flag ); + } + set_players_dontspeak( 0 ); + flag_clear( "story_vo_playing" ); +} + +wunderfizz_used_vo() +{ + self endon( "death" ); + self endon( "disconnect" ); + if ( isDefined( self.has_used_perk_random ) && self.has_used_perk_random ) + { + return; + } + if ( isDefined( self.character_name ) && self.character_name != "Richtofen" ) + { + return; + } + if ( flag( "story_vo_playing" ) ) + { + return; + } + if ( isDefined( self.dontspeak ) && self.dontspeak ) + { + return; + } + set_players_dontspeak( 1 ); + self.has_used_perk_random = 1; + i = 1; + while ( i < 4 ) + { + vox_line = "vox_plr_2_discover_wonder_" + i + "_0"; + self playsoundwithnotify( vox_line, "sound_done" + vox_line ); + self waittill( "sound_done" + vox_line ); + wait 0,1; + i++; + } + set_players_dontspeak( 0 ); +} + +init_sam_promises() +{ + level.vo_promises[ "Richtofen_1" ][ 0 ] = "vox_sam_hear_samantha_2_plr_2_0"; + level.vo_promises[ "Richtofen_1" ][ 1 ] = "vox_plr_2_hear_samantha_2_0"; + level.vo_promises[ "Richtofen_2" ][ 0 ] = "vox_sam_sam_richtofen_1_0"; + level.vo_promises[ "Richtofen_2" ][ 1 ] = "vox_sam_sam_richtofen_2_0"; + level.vo_promises[ "Richtofen_2" ][ 2 ] = "vox_plr_2_sam_richtofen_3_0"; + level.vo_promises[ "Richtofen_3" ][ 0 ] = "vox_sam_sam_richtofen_4_0"; + level.vo_promises[ "Richtofen_3" ][ 1 ] = "vox_plr_2_sam_richtofen_5_0"; + level.vo_promises[ "Richtofen_3" ][ 2 ] = "vox_plr_2_sam_richtofen_6_0"; + level.vo_promises[ "Dempsey_1" ][ 0 ] = "vox_sam_hear_samantha_2_plr_0_0"; + level.vo_promises[ "Dempsey_1" ][ 1 ] = "vox_plr_0_hear_samantha_2_0"; + level.vo_promises[ "Dempsey_2" ][ 0 ] = "vox_sam_sam_dempsey_1_0"; + level.vo_promises[ "Dempsey_2" ][ 1 ] = "vox_sam_sam_dempsey_1_1"; + level.vo_promises[ "Dempsey_2" ][ 2 ] = "vox_plr_0_sam_dempsey_1_0"; + level.vo_promises[ "Dempsey_3" ][ 0 ] = "vox_sam_sam_dempsey_2_0"; + level.vo_promises[ "Dempsey_3" ][ 1 ] = "vox_sam_sam_dempsey_2_1"; + level.vo_promises[ "Dempsey_3" ][ 2 ] = "vox_plr_0_sam_dempsey_2_0"; + level.vo_promises[ "Nikolai_1" ][ 0 ] = "vox_sam_hear_samantha_2_plr_1_0"; + level.vo_promises[ "Nikolai_1" ][ 1 ] = "vox_plr_1_hear_samantha_2_0"; + level.vo_promises[ "Nikolai_2" ][ 0 ] = "vox_sam_sam_nikolai_1_0"; + level.vo_promises[ "Nikolai_2" ][ 1 ] = "vox_sam_sam_nikolai_1_1"; + level.vo_promises[ "Nikolai_2" ][ 2 ] = "vox_plr_1_sam_nikolai_1_0"; + level.vo_promises[ "Nikolai_3" ][ 0 ] = "vox_sam_sam_nikolai_2_0"; + level.vo_promises[ "Nikolai_3" ][ 1 ] = "vox_sam_sam_nikolai_2_1"; + level.vo_promises[ "Nikolai_3" ][ 2 ] = "vox_plr_1_sam_nikolai_2_0"; + level.vo_promises[ "Takeo_1" ][ 0 ] = "vox_sam_hear_samantha_2_plr_3_0"; + level.vo_promises[ "Takeo_1" ][ 1 ] = "vox_plr_3_hear_samantha_2_0"; + level.vo_promises[ "Takeo_2" ][ 0 ] = "vox_sam_sam_takeo_1_0"; + level.vo_promises[ "Takeo_2" ][ 1 ] = "vox_sam_sam_takeo_1_1"; + level.vo_promises[ "Takeo_2" ][ 2 ] = "vox_plr_3_sam_takeo_1_0"; + level.vo_promises[ "Takeo_3" ][ 0 ] = "vox_sam_sam_takeo_2_0"; + level.vo_promises[ "Takeo_3" ][ 1 ] = "vox_sam_sam_takeo_2_1"; + level.vo_promises[ "Takeo_3" ][ 2 ] = "vox_plr_3_sam_takeo_2_0"; + level thread sam_promises_watch(); +} + +sam_promises_watch() +{ + flag_wait( "samantha_intro_done" ); + while ( 1 ) + { + level waittill( "player_zombie_blood", e_player ); + a_players = get_players(); + if ( randomint( 100 ) < 20 ) + { + e_player thread sam_promises_conversation(); + } + } +} + +sam_promises_conversation() +{ + self endon( "disconnect" ); + self.vo_promises_playing = 1; + wait 3; + if ( !isDefined( self.n_vo_promises ) ) + { + self.n_vo_promises = 1; + } + if ( self.n_vo_promises > 3 && isDefined( self.b_promise_cooldown ) || self.b_promise_cooldown && flag( "story_vo_playing" ) ) + { + self.vo_promises_playing = undefined; + return; + } + a_promises = level.vo_promises[ ( self.character_name + "_" ) + self.n_vo_promises ]; + self.n_vo_promises++; + self thread sam_promises_cooldown(); + level.sam_talking = 1; + self set_player_dontspeak( 1 ); + flag_set( "story_vo_playing" ); + self play_sam_promises_conversation( a_promises ); + level.sam_talking = 0; + self set_player_dontspeak( 0 ); + flag_clear( "story_vo_playing" ); + self.vo_promises_playing = undefined; +} + +play_sam_promises_conversation( a_promises ) +{ + i = 0; + while ( i < a_promises.size ) + { + self endon( "zombie_blood_over" ); + self endon( "disconnect" ); + if ( issubstr( a_promises[ i ], "sam_sam" ) || issubstr( a_promises[ i ], "samantha" ) ) + { + self thread sam_promises_conversation_ended_early( a_promises[ i ] ); + self playsoundtoplayer( a_promises[ i ], self ); + n_duration = soundgetplaybacktime( a_promises[ i ] ); + wait ( n_duration / 1000 ); + self notify( "promises_VO_end_early" ); + } + else + { + self playsoundwithnotify( a_promises[ i ], "player_done" ); + self waittill( "player_done" ); + } + wait 0,3; + i++; + } +} + +sam_promises_conversation_ended_early( str_alias ) +{ + self notify( "promises_VO_end_early" ); + self endon( "promises_VO_end_early" ); + while ( self.zombie_vars[ "zombie_powerup_zombie_blood_on" ] ) + { + wait 0,05; + } + self stoplocalsound( str_alias ); +} + +sam_promises_cooldown() +{ + self endon( "disconnect" ); + self.b_promise_cooldown = 1; + level waittill( "end_of_round" ); + self.b_promise_cooldown = undefined; +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz.gsc new file mode 100644 index 0000000..38d1453 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz.gsc @@ -0,0 +1,2175 @@ +#include maps/mp/zombies/_zm_ai_basic; +#include maps/mp/zm_tomb_chamber; +#include maps/mp/zombies/_zm_powerups; +#include maps/mp/zombies/_zm_stats; +#include maps/mp/zombies/_zm_score; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/animscripts/zm_shared; +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/zombies/_zm_ai_mechz; +#include maps/mp/zombies/_zm_ai_mechz_ffotd; +#include maps/mp/zombies/_zm_ai_mechz_booster; +#include maps/mp/zombies/_zm_ai_mechz_ft; +#include maps/mp/zombies/_zm_ai_mechz_claw; +#include maps/mp/zombies/_zm_ai_mechz_dev; +#include maps/mp/zm_tomb_tank; +#include maps/mp/animscripts/zm_utility; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/zombies/_zm_net; +#include maps/mp/_utility; +#include common_scripts/utility; +#include maps/mp/zombies/_zm_zonemgr; + +#using_animtree( "mechz_claw" ); + +precache() +{ + level thread mechz_setup_armor_pieces(); + precachemodel( "c_zom_mech_claw" ); + precachemodel( "c_zom_mech_faceplate" ); + precachemodel( "c_zom_mech_powersupply_cap" ); + level._effect[ "mech_dmg_sparks" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_dmg_sparks" ); + level._effect[ "mech_dmg_steam" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_dmg_steam" ); + level._effect[ "mech_booster" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_jump_booster" ); + level._effect[ "mech_wpn_source" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_wpn_source" ); + level._effect[ "mech_wpn_flamethrower" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_wpn_flamethrower" ); + level._effect[ "mech_booster_landing" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_jump_landing" ); + level._effect[ "mech_faceplate_dmg" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_dmg_armor_face" ); + level._effect[ "mech_armor_dmg" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_dmg_armor" ); + level._effect[ "mech_exhaust" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_exhaust_smoke" ); + level._effect[ "mech_booster_feet" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_jump_booster_sm" ); + level._effect[ "mech_headlamp" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_head_light" ); + level._effect[ "mech_footstep_steam" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_foot_step_steam" ); + setdvar( "zombie_double_wide_checks", 1 ); + precacherumble( "mechz_footsteps" ); + precacheshellshock( "lava_small" ); +} + +init() +{ + maps/mp/zombies/_zm_ai_mechz_ffotd::mechz_init_start(); + level.mechz_spawners = getentarray( "mechz_spawner", "script_noteworthy" ); + if ( level.mechz_spawners.size == 0 ) + { + return; + } + i = 0; + while ( i < level.mechz_spawners.size ) + { + level.mechz_spawners[ i ].is_enabled = 1; + level.mechz_spawners[ i ].script_forcespawn = 1; + i++; + } + level.mechz_base_health = 5000; + level.mechz_health = level.mechz_base_health; + level.mechz_health_increase = 1000; + level.mechz_round_count = 0; + level.mechz_damage_percent = 0,1; + level.mechz_remove_helmet_head_dmg_base = 500; + level.mechz_remove_helmet_head_dmg = level.mechz_remove_helmet_head_dmg_base; + level.mechz_remove_helmet_head_dmg_increase = 250; + level.mechz_explosive_dmg_head_scaler = 0,25; + level.mechz_helmet_health_percentage = 0,1; + level.mechz_powerplant_expose_dmg_base = 300; + level.mechz_powerplant_expose_dmg = level.mechz_powerplant_expose_base_dmg; + level.mechz_powerplant_expose_dmg_increase = 100; + level.mechz_powerplant_destroy_dmg_base = 500; + level.mechz_powerplant_destroy_dmg = level.mechz_powerplant_destroy_dmg_base; + level.mechz_powerplant_destroy_dmg_increase = 150; + level.mechz_powerplant_expose_health_percentage = 0,05; + level.mechz_powerplant_destroyed_health_percentage = 0,025; + level.mechz_explosive_dmg_to_cancel_claw_percentage = 0,1; + level.mechz_min_round_fq = 3; + level.mechz_max_round_fq = 4; + level.mechz_min_round_fq_solo = 4; + level.mechz_max_round_fq_solo = 6; + level.mechz_reset_dist_sq = 65536; + level.mechz_sticky_dist_sq = 1048576; + level.mechz_aggro_dist_sq = 16384; + level.mechz_zombie_per_round = 1; + level.mechz_left_to_spawn = 0; + level.mechz_players_in_zone_spawn_point_cap = 120; + level.mechz_shotgun_damage_mod = 1,5; + level.mechz_failed_paths_to_jump = 3; + level.mechz_jump_dist_threshold = 4410000; + level.mechz_jump_delay = 3; + level.mechz_player_flame_dmg = 10; + level.mechz_half_front_arc = cos( 45 ); + level.mechz_ft_sweep_chance = 10; + level.mechz_aim_max_pitch = 60; + level.mechz_aim_max_yaw = 45; + level.mechz_custom_goalradius = 48; + level.mechz_custom_goalradius_sq = level.mechz_custom_goalradius * level.mechz_custom_goalradius; + level.mechz_tank_knockdown_time = 5; + level.mechz_robot_knockdown_time = 10; + level.mechz_dist_for_sprint = 129600; + level.mechz_dist_for_stop_sprint = 57600; + level.mechz_claw_cooldown_time = 7000; + level.mechz_flamethrower_cooldown_time = 5000; + level.mechz_min_extra_spawn = 8; + level.mechz_max_extra_spawn = 11; + level.mechz_points_for_killer = 250; + level.mechz_points_for_team = 500; + level.mechz_points_for_helmet = 100; + level.mechz_points_for_powerplant = 100; + level.mechz_flogger_stun_time = 3; + level.mechz_powerplant_stun_time = 4; + flag_init( "mechz_launching_claw" ); + flag_init( "mechz_claw_move_complete" ); + registerclientfield( "actor", "mechz_fx", 14000, 12, "int" ); + registerclientfield( "toplayer", "mechz_grab", 14000, 1, "int" ); + level thread init_flamethrower_triggers(); + if ( isDefined( level.mechz_spawning_logic_override_func ) ) + { + level thread [[ level.mechz_spawning_logic_override_func ]](); + } + else + { + level thread mechz_spawning_logic(); + } + scriptmodelsuseanimtree( -1 ); +/# + setup_devgui(); +#/ + maps/mp/zombies/_zm_ai_mechz_ffotd::mechz_init_end(); +} + +mechz_setup_armor_pieces() +{ + level.mechz_armor_info = []; + level.mechz_armor_info[ 0 ] = spawnstruct(); + level.mechz_armor_info[ 0 ].model = "c_zom_mech_armor_knee_left"; + level.mechz_armor_info[ 0 ].tag = "J_Knee_Attach_LE"; + level.mechz_armor_info[ 1 ] = spawnstruct(); + level.mechz_armor_info[ 1 ].model = "c_zom_mech_armor_knee_right"; + level.mechz_armor_info[ 1 ].tag = "J_Knee_attach_RI"; + level.mechz_armor_info[ 2 ] = spawnstruct(); + level.mechz_armor_info[ 2 ].model = "c_zom_mech_armor_shoulder_left"; + level.mechz_armor_info[ 2 ].tag = "J_ShoulderArmor_LE"; + level.mechz_armor_info[ 3 ] = spawnstruct(); + level.mechz_armor_info[ 3 ].model = "c_zom_mech_armor_shoulder_right"; + level.mechz_armor_info[ 3 ].tag = "J_ShoulderArmor_RI"; + level.mechz_armor_info[ 4 ] = spawnstruct(); + level.mechz_armor_info[ 4 ].tag = "J_Root_Attach_LE"; + level.mechz_armor_info[ 5 ] = spawnstruct(); + level.mechz_armor_info[ 5 ].tag = "J_Root_Attach_RI"; + i = 0; + while ( i < level.mechz_armor_info.size ) + { + if ( isDefined( level.mechz_armor_info[ i ].model ) ) + { + precachemodel( level.mechz_armor_info[ i ].model ); + } + i++; + } +} + +mechz_setup_fx() +{ + self.fx_field = 0; + self thread booster_fx_watcher(); + self thread flamethrower_fx_watcher(); +} + +clear_one_off_fx( fx_id ) +{ + self endon( "death" ); + wait 10; + self.fx_field &= fx_id; + self setclientfield( "mechz_fx", self.fx_field ); +} + +traversal_booster_fx_watcher() +{ + self endon( "death" ); + while ( 1 ) + { + self waittill( "traverse_anim", notetrack ); + if ( notetrack == "booster_on" ) + { + self.fx_field |= 128; + self.sndloopent playsound( "zmb_ai_mechz_rocket_start" ); + self.sndloopent playloopsound( "zmb_ai_mechz_rocket_loop", 0,75 ); + } + else + { + if ( notetrack == "booster_off" ) + { + self.fx_field &= 128; + self.sndloopent playsound( "zmb_ai_mechz_rocket_stop" ); + self.sndloopent stoploopsound( 1 ); + } + } + self setclientfield( "mechz_fx", self.fx_field ); + } +} + +booster_fx_watcher() +{ + self endon( "death" ); + self thread traversal_booster_fx_watcher(); + while ( 1 ) + { + self waittill( "jump_anim", notetrack ); + if ( isDefined( self.mechz_hidden ) && self.mechz_hidden ) + { + continue; + } + if ( notetrack == "booster_on" ) + { + self.fx_field |= 128; + self.sndloopent playsound( "zmb_ai_mechz_rocket_start" ); + self.sndloopent playloopsound( "zmb_ai_mechz_rocket_loop", 0,75 ); + } + else if ( notetrack == "booster_off" ) + { + self.fx_field &= 128; + self.sndloopent playsound( "zmb_ai_mechz_rocket_stop" ); + self.sndloopent stoploopsound( 1 ); + } + else + { + if ( notetrack == "impact" ) + { + self.fx_field |= 512; + if ( isDefined( self.has_helmet ) && self.has_helmet ) + { + self.fx_field |= 2048; + } + self thread clear_one_off_fx( 512 ); + } + } + self setclientfield( "mechz_fx", self.fx_field ); + } +} + +flamethrower_fx_watcher() +{ + self endon( "death" ); + while ( 1 ) + { + self waittill( "flamethrower_anim", notetrack ); + if ( notetrack == "start_ft" ) + { + self.fx_field |= 64; + } + else + { + if ( notetrack == "stop_ft" ) + { + self.fx_field &= 64; + } + } + self setclientfield( "mechz_fx", self.fx_field ); + } +} + +fx_cleanup() +{ + self.fx_field = 0; + self setclientfield( "mechz_fx", self.fx_field ); + wait_network_frame(); +} + +mechz_setup_snd() +{ + self.audio_type = "mechz"; + if ( !isDefined( self.sndloopent ) ) + { + self.sndloopent = spawn( "script_origin", self.origin ); + self.sndloopent linkto( self, "tag_origin" ); + self thread snddeleteentondeath( self.sndloopent ); + } + self thread play_ambient_mechz_vocals(); +} + +snddeleteentondeath( ent ) +{ + self waittill( "death" ); + ent delete(); +} + +play_ambient_mechz_vocals() +{ + self endon( "death" ); + wait randomintrange( 2, 4 ); + while ( 1 ) + { + if ( isDefined( self ) ) + { + if ( isDefined( self.favoriteenemy ) && distance( self.origin, self.favoriteenemy.origin ) <= 150 ) + { + break; + } + else + { + self playsound( "zmb_ai_mechz_vox_ambient" ); + } + } + wait randomfloatrange( 3, 6 ); + } +} + +enable_mechz_rounds() +{ +/# + if ( getDvarInt( "zombie_cheat" ) >= 2 ) + { + return; +#/ + } + level.mechz_rounds_enabled = 1; + flag_init( "mechz_round" ); + level thread mechz_round_tracker(); +} + +mechz_round_tracker() +{ + maps/mp/zombies/_zm_ai_mechz_ffotd::mechz_round_tracker_start(); + level.num_mechz_spawned = 0; + old_spawn_func = level.round_spawn_func; + old_wait_func = level.round_wait_func; + while ( !isDefined( level.zombie_mechz_locations ) ) + { + wait 0,05; + } + flag_wait( "activate_zone_nml" ); + mech_start_round_num = 8; + if ( isDefined( level.is_forever_solo_game ) && level.is_forever_solo_game ) + { + mech_start_round_num = 8; + } + while ( level.round_number < mech_start_round_num ) + { + level waittill( "between_round_over" ); + } + level.next_mechz_round = level.round_number; + level thread debug_print_mechz_round(); + while ( 1 ) + { + maps/mp/zombies/_zm_ai_mechz_ffotd::mechz_round_tracker_loop_start(); + if ( level.num_mechz_spawned > 0 ) + { + level.mechz_should_drop_powerup = 1; + } + while ( level.next_mechz_round <= level.round_number ) + { + a_zombies = getaispeciesarray( level.zombie_team, "all" ); + _a485 = a_zombies; + _k485 = getFirstArrayKey( _a485 ); + while ( isDefined( _k485 ) ) + { + zombie = _a485[ _k485 ]; + if ( isDefined( zombie.is_mechz ) && zombie.is_mechz && isalive( zombie ) ) + { + level.next_mechz_round++; + break; + } + else + { + _k485 = getNextArrayKey( _a485, _k485 ); + } + } + } + if ( level.mechz_left_to_spawn == 0 && level.next_mechz_round <= level.round_number ) + { + mechz_health_increases(); + if ( isDefined( level.is_forever_solo_game ) && level.is_forever_solo_game ) + { + level.mechz_zombie_per_round = 1; + } + else + { + if ( level.mechz_round_count < 2 ) + { + level.mechz_zombie_per_round = 1; + break; + } + else if ( level.mechz_round_count < 5 ) + { + level.mechz_zombie_per_round = 2; + break; + } + else + { + level.mechz_zombie_per_round = 3; + } + } + level.mechz_left_to_spawn = level.mechz_zombie_per_round; + mechz_spawning = level.mechz_left_to_spawn; + wait randomfloatrange( 10, 15 ); + level notify( "spawn_mechz" ); + if ( isDefined( level.is_forever_solo_game ) && level.is_forever_solo_game ) + { + n_round_gap = randomintrange( level.mechz_min_round_fq_solo, level.mechz_max_round_fq_solo ); + } + else + { + n_round_gap = randomintrange( level.mechz_min_round_fq, level.mechz_max_round_fq ); + } + level.next_mechz_round = level.round_number + n_round_gap; + level.mechz_round_count++; + level thread debug_print_mechz_round(); + level.num_mechz_spawned += mechz_spawning; + } + maps/mp/zombies/_zm_ai_mechz_ffotd::mechz_round_tracker_loop_end(); + level waittill( "between_round_over" ); + mechz_clear_spawns(); + } +} + +debug_print_mechz_round() +{ + flag_wait( "start_zombie_round_logic" ); +/# + iprintln( "Next mechz Round = " + level.next_mechz_round ); +#/ +} + +mechz_spawning_logic() +{ + level thread enable_mechz_rounds(); + while ( 1 ) + { + level waittill( "spawn_mechz" ); + while ( level.mechz_left_to_spawn ) + { + while ( level.zombie_mechz_locations.size < 1 ) + { + wait randomfloatrange( 5, 10 ); + } + ai = spawn_zombie( level.mechz_spawners[ 0 ] ); + ai thread mechz_spawn(); + level.mechz_left_to_spawn--; + + if ( level.mechz_left_to_spawn == 0 ) + { + level thread response_to_air_raid_siren_vo(); + } + ai thread mechz_hint_vo(); + wait randomfloatrange( 3, 6 ); + } + } +} + +mechz_prespawn() +{ +} + +mechz_attach_objects() +{ + self detachall(); + self.armor_state = []; + i = 0; + while ( i < level.mechz_armor_info.size ) + { + self.armor_state[ i ] = spawnstruct(); + self.armor_state[ i ].index = i; + self.armor_state[ i ].tag = level.mechz_armor_info[ i ].tag; + if ( isDefined( level.mechz_armor_info[ i ].model ) ) + { + self attach( level.mechz_armor_info[ i ].model, level.mechz_armor_info[ i ].tag, 1 ); + self.armor_state[ i ].model = level.mechz_armor_info[ i ].model; + } + i++; + } + if ( isDefined( self.m_claw ) ) + { + self.m_claw delete(); + self.m_claw = undefined; + } + org = self gettagorigin( "tag_claw" ); + ang = self gettagangles( "tag_claw" ); + self.m_claw = spawn( "script_model", org ); + self.m_claw setmodel( "c_zom_mech_claw" ); + self.m_claw.angles = ang; + self.m_claw linkto( self, "tag_claw" ); + self.m_claw useanimtree( -1 ); + if ( isDefined( self.m_claw_damage_trigger ) ) + { + self.m_claw_damage_trigger unlink(); + self.m_claw_damage_trigger delete(); + self.m_claw_damage_trigger = undefined; + } + trigger_spawnflags = 0; + trigger_radius = 3; + trigger_height = 15; + self.m_claw_damage_trigger = spawn( "trigger_damage", org, trigger_spawnflags, trigger_radius, trigger_height ); + self.m_claw_damage_trigger.angles = ang; + self.m_claw_damage_trigger enablelinkto(); + self.m_claw_damage_trigger linkto( self, "tag_claw" ); + self thread mechz_claw_damage_trigger_thread(); + self attach( "c_zom_mech_faceplate", "J_Helmet", 0 ); + self.has_helmet = 1; + self attach( "c_zom_mech_powersupply_cap", "tag_powersupply", 0 ); + self.has_powerplant = 1; + self.powerplant_covered = 1; + self.armor_state = array_randomize( self.armor_state ); +} + +mechz_set_starting_health() +{ + self.maxhealth = level.mechz_health; + self.helmet_dmg = 0; + self.helmet_dmg_for_removal = self.maxhealth * level.mechz_helmet_health_percentage; + self.powerplant_cover_dmg = 0; + self.powerplant_cover_dmg_for_removal = self.maxhealth * level.mechz_powerplant_expose_health_percentage; + self.powerplant_dmg = 0; + self.powerplant_dmg_for_destroy = self.maxhealth * level.mechz_powerplant_destroyed_health_percentage; + level.mechz_explosive_dmg_to_cancel_claw = self.maxhealth * level.mechz_explosive_dmg_to_cancel_claw_percentage; +/# + if ( getDvarInt( #"E7121222" ) > 0 ) + { + println( "\nMZ: MechZ Starting Health: " + self.maxhealth ); + println( "\nMZ: MechZ Required Helmet Dmg: " + self.helmet_dmg_for_removal ); + println( "\nMZ: MechZ Required Powerplant Cover Dmg: " + self.powerplant_cover_dmg_for_removal ); + println( "\nMZ: MechZ Required Powerplant Dmg: " + self.powerplant_dmg_for_destroy ); +#/ + } + self.health = level.mechz_health; + self.non_attacker_func = ::mechz_non_attacker_damage_override; + self.non_attack_func_takes_attacker = 1; + self.actor_damage_func = ::mechz_damage_override; + self.instakill_func = ::mechz_instakill_override; + self.nuke_damage_func = ::mechz_nuke_override; +} + +mechz_spawn() +{ + self maps/mp/zombies/_zm_ai_mechz_ffotd::spawn_start(); + self endon( "death" ); + level endon( "intermission" ); + self mechz_attach_objects(); + self mechz_set_starting_health(); + self mechz_setup_fx(); + self mechz_setup_snd(); + level notify( "sam_clue_mechz" ); + self.closest_player_override = ::get_favorite_enemy; + self.animname = "mechz_zombie"; + self.has_legs = 1; + self.no_gib = 1; + self.ignore_all_poi = 1; + self.is_mechz = 1; + self.ignore_enemy_count = 1; + self.no_damage_points = 1; + self.melee_anim_func = ::melee_anim_func; + self.meleedamage = 75; + self.custom_item_dmg = 2000; + recalc_zombie_array(); + self setphysparams( 20, 0, 80 ); + self setcandamage( 0 ); + self.zombie_init_done = 1; + self notify( "zombie_init_done" ); + self.allowpain = 0; + self animmode( "normal" ); + self orientmode( "face enemy" ); + self maps/mp/zombies/_zm_spawner::zombie_setup_attack_properties(); + self.completed_emerging_into_playable_area = 1; + self notify( "completed_emerging_into_playable_area" ); + self.no_powerups = 0; + self setfreecameralockonallowed( 0 ); + self notsolid(); + self thread maps/mp/zombies/_zm_spawner::zombie_eye_glow(); + level thread maps/mp/zombies/_zm_spawner::zombie_death_event( self ); + self thread maps/mp/zombies/_zm_spawner::enemy_death_detection(); + if ( level.zombie_mechz_locations.size ) + { + spawn_pos = self get_best_mechz_spawn_pos(); + } + if ( !isDefined( spawn_pos ) ) + { +/# + println( "ERROR: Tried to spawn mechz with no mechz spawn_positions!\n" ); + iprintln( "ERROR: Tried to spawn mechz with no mechz spawn_positions!" ); +#/ + self delete(); + return; + } + if ( isDefined( level.mechz_force_spawn_pos ) ) + { + spawn_pos = level.mechz_force_spawn_pos; + level.mechz_force_spawn_pos = undefined; + } + if ( !isDefined( spawn_pos.angles ) ) + { + spawn_pos.angles = ( 0, 0, 1 ); + } + self thread mechz_death(); + self forceteleport( spawn_pos.origin, spawn_pos.angles ); + self playsound( "zmb_ai_mechz_incoming_alarm" ); + if ( !isDefined( spawn_pos.angles ) ) + { + spawn_pos.angles = ( 0, 0, 1 ); + } + self animscripted( spawn_pos.origin, spawn_pos.angles, "zm_spawn" ); + self maps/mp/animscripts/zm_shared::donotetracks( "jump_anim" ); + self setfreecameralockonallowed( 1 ); + self solid(); + self set_zombie_run_cycle( "walk" ); + if ( isDefined( level.mechz_find_flesh_override_func ) ) + { + level thread [[ level.mechz_find_flesh_override_func ]](); + } + else + { + self thread mechz_find_flesh(); + } + self thread mechz_jump_think( spawn_pos ); + self setcandamage( 1 ); + self init_anim_rate(); + self maps/mp/zombies/_zm_ai_mechz_ffotd::spawn_end(); +} + +get_closest_mechz_spawn_pos( org ) +{ + best_dist = -1; + best_pos = undefined; + players = get_players(); + i = 0; + while ( i < level.zombie_mechz_locations.size ) + { + dist = distancesquared( org, level.zombie_mechz_locations[ i ].origin ); + if ( dist < best_dist || best_dist < 0 ) + { + best_dist = dist; + best_pos = level.zombie_mechz_locations[ i ]; + } + i++; + } +/# + if ( !isDefined( best_pos ) ) + { + println( "Error: Mechz could not find a valid jump pos from position ( " + self.origin[ 0 ] + ", " + self.origin[ 1 ] + ", " + self.origin[ 2 ] + " )" ); +#/ + } + return best_pos; +} + +get_best_mechz_spawn_pos( ignore_used_positions ) +{ + if ( !isDefined( ignore_used_positions ) ) + { + ignore_used_positions = 0; + } + best_dist = -1; + best_pos = undefined; + players = get_players(); + i = 0; + while ( i < level.zombie_mechz_locations.size ) + { + if ( !ignore_used_positions && isDefined( level.zombie_mechz_locations[ i ].has_been_used ) && level.zombie_mechz_locations[ i ].has_been_used ) + { + i++; + continue; + } + else + { + if ( ignore_used_positions == 1 && isDefined( level.zombie_mechz_locations[ i ].used_cooldown ) && level.zombie_mechz_locations[ i ].used_cooldown ) + { + i++; + continue; + } + else + { + j = 0; + while ( j < players.size ) + { + if ( is_player_valid( players[ j ], 1, 1 ) ) + { + dist = distancesquared( level.zombie_mechz_locations[ i ].origin, players[ j ].origin ); + if ( dist < best_dist || best_dist < 0 ) + { + best_dist = dist; + best_pos = level.zombie_mechz_locations[ i ]; + } + } + j++; + } + } + } + i++; + } + if ( ignore_used_positions && isDefined( best_pos ) ) + { + best_pos thread jump_pos_used_cooldown(); + } + if ( isDefined( best_pos ) ) + { + best_pos.has_been_used = 1; + } + else + { + if ( level.zombie_mechz_locations.size > 0 ) + { + return level.zombie_mechz_locations[ randomint( level.zombie_mechz_locations.size ) ]; + } + } + return best_pos; +} + +mechz_clear_spawns() +{ + i = 0; + while ( i < level.zombie_mechz_locations.size ) + { + level.zombie_mechz_locations[ i ].has_been_used = 0; + i++; + } +} + +jump_pos_used_cooldown() +{ + self.used_cooldown = 1; + wait 5; + self.used_cooldown = 0; +} + +mechz_health_increases() +{ + if ( !isDefined( level.mechz_last_spawn_round ) || level.round_number > level.mechz_last_spawn_round ) + { + a_players = getplayers(); + n_player_modifier = 1; + if ( a_players.size > 1 ) + { + n_player_modifier = a_players.size * 0,75; + } + level.mechz_health = int( n_player_modifier * ( level.mechz_base_health + ( level.mechz_health_increase * level.mechz_round_count ) ) ); + if ( level.mechz_health >= ( 22500 * n_player_modifier ) ) + { + level.mechz_health = int( 22500 * n_player_modifier ); + } + level.mechz_last_spawn_round = level.round_number; + } +} + +mechz_death() +{ + self endon( "mechz_cleanup" ); + thread mechz_cleanup(); + self waittill( "death" ); + death_origin = self.origin; + if ( isDefined( self.robot_stomped ) && self.robot_stomped ) + { + death_origin += vectorScale( ( 0, 0, 1 ), 90 ); + } + self mechz_claw_detach(); + self release_flamethrower_trigger(); + self.fx_field = 0; + self setclientfield( "mechz_fx", self.fx_field ); + self thread maps/mp/zombies/_zm_spawner::zombie_eye_glow_stop(); + self mechz_interrupt(); + if ( isDefined( self.favoriteenemy ) ) + { + if ( isDefined( self.favoriteenemy.hunted_by ) ) + { + self.favoriteenemy.hunted_by--; + + } + } + self thread mechz_explode( "tag_powersupply", death_origin ); + if ( get_current_zombie_count() == 0 && level.zombie_total == 0 ) + { + level.last_mechz_origin = self.origin; + level notify( "last_mechz_down" ); + } + if ( isplayer( self.attacker ) ) + { + event = "death"; + if ( issubstr( self.damageweapon, "knife_ballistic_" ) ) + { + event = "ballistic_knife_death"; + } + self.attacker delay_thread( 4, ::maps/mp/zombies/_zm_audio::create_and_play_dialog, "general", "mech_defeated" ); + self.attacker maps/mp/zombies/_zm_score::player_add_points( event, self.damagemod, self.damagelocation, 1 ); + self.attacker maps/mp/zombies/_zm_stats::increment_client_stat( "tomb_mechz_killed", 0 ); + self.attacker maps/mp/zombies/_zm_stats::increment_player_stat( "tomb_mechz_killed" ); + if ( isDefined( level.mechz_should_drop_powerup ) && level.mechz_should_drop_powerup ) + { + wait_network_frame(); + wait_network_frame(); + level.mechz_should_drop_powerup = 0; + if ( level.powerup_drop_count >= level.zombie_vars[ "zombie_powerup_drop_max_per_round" ] ) + { + level.powerup_drop_count = level.zombie_vars[ "zombie_powerup_drop_max_per_round" ] - 1; + } + level.zombie_vars[ "zombie_drop_item" ] = 1; + level thread maps/mp/zombies/_zm_powerups::powerup_drop( self.origin ); + } + } +} + +mechz_explode( str_tag, death_origin ) +{ + wait 2; + v_origin = self gettagorigin( str_tag ); + level notify( "mechz_exploded" ); + playsoundatposition( "zmb_ai_mechz_death_explode", v_origin ); + playfx( level._effect[ "mechz_death" ], v_origin ); + radiusdamage( v_origin, 128, 100, 25, undefined, "MOD_GRENADE_SPLASH" ); + earthquake( 0,5, 1, v_origin, 256 ); + playrumbleonposition( "grenade_rumble", v_origin ); + level notify( "mechz_killed" ); +} + +mechz_cleanup() +{ + self waittill( "mechz_cleanup" ); + self mechz_interrupt(); + level.sndmechzistalking = 0; + if ( isDefined( self.sndmechzmusicent ) ) + { + self.sndmechzmusicent delete(); + self.sndmechzmusicent = undefined; + } + if ( isDefined( self.favoriteenemy ) ) + { + if ( isDefined( self.favoriteenemy.hunted_by ) ) + { + self.favoriteenemy.hunted_by--; + + } + } +} + +mechz_interrupt() +{ + self notify( "kill_claw" ); + self notify( "kill_ft" ); + self notify( "kill_jump" ); +} + +mechz_stun( time ) +{ + self endon( "death" ); + if ( isalive( self ) && isDefined( self.not_interruptable ) || self.not_interruptable && isDefined( self.is_traversing ) && self.is_traversing ) + { + return; + } + curr_time = 0; + anim_time = self getanimlengthfromasd( "zm_stun", 0 ); + self mechz_interrupt(); + self mechz_claw_detach(); + wait 0,05; + self.not_interruptable = 1; +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\nMZ: Stun setting not interruptable\n" ); +#/ + } + while ( curr_time < time ) + { + self animscripted( self.origin, self.angles, "zm_stun" ); + self maps/mp/animscripts/zm_shared::donotetracks( "stun_anim" ); + self clearanim( %root, 0 ); + curr_time += anim_time; + } + self.not_interruptable = 0; +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\nMZ: Stun clearing not interruptable\n" ); +#/ + } +} + +mechz_tank_hit_callback() +{ + self endon( "death" ); + if ( isDefined( self.mechz_hit_by_tank ) && self.mechz_hit_by_tank ) + { + return; + } +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\nMZ: Tank damage setting not interruptable\n" ); +#/ + } + self.not_interruptable = 1; + self.mechz_hit_by_tank = 1; + self mechz_interrupt(); + v_trace_start = self.origin + vectorScale( ( 0, 0, 1 ), 100 ); + v_trace_end = self.origin - vectorScale( ( 0, 0, 1 ), 500 ); + v_trace = physicstrace( self.origin, v_trace_end, ( -15, -15, -5 ), ( 15, 15, 5 ), self ); + self.origin = v_trace[ "position" ]; + timer = 0; + self animscripted( self.origin, self.angles, "zm_tank_hit_in" ); + self maps/mp/animscripts/zm_shared::donotetracks( "pain_anim" ); + anim_length = self getanimlengthfromasd( "zm_tank_hit_loop", 0 ); + while ( timer < level.mechz_tank_knockdown_time ) + { + timer += anim_length; + self animscripted( self.origin, self.angles, "zm_tank_hit_loop" ); + self maps/mp/animscripts/zm_shared::donotetracks( "pain_anim" ); + } + self animscripted( self.origin, self.angles, "zm_tank_hit_out" ); + self maps/mp/animscripts/zm_shared::donotetracks( "pain_anim" ); +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\nMZ: Tank damage clearing not interruptable\n" ); +#/ + } + self.not_interruptable = 0; + self.mechz_hit_by_tank = 0; + if ( !level.vh_tank ent_flag( "tank_moving" ) && self istouching( level.vh_tank ) ) + { + self notsolid(); + self ghost(); + self.mechz_hidden = 1; + if ( isDefined( self.m_claw ) ) + { + self.m_claw ghost(); + } + self.fx_field_old = self.fx_field; + self thread maps/mp/zombies/_zm_spawner::zombie_eye_glow_stop(); + self fx_cleanup(); + self mechz_do_jump(); + self solid(); + self.mechz_hidden = 0; + } +} + +mechz_robot_stomp_callback() +{ + self endon( "death" ); + if ( isDefined( self.robot_stomped ) && self.robot_stomped ) + { + return; + } + self.not_interruptable = 1; + self.robot_stomped = 1; + self mechz_interrupt(); +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\nMZ: Robot stomp setting not interruptable\n" ); +#/ + } + self thread mechz_stomped_by_giant_robot_vo(); + v_trace_start = self.origin + vectorScale( ( 0, 0, 1 ), 100 ); + v_trace_end = self.origin - vectorScale( ( 0, 0, 1 ), 500 ); + v_trace = physicstrace( self.origin, v_trace_end, ( -15, -15, -5 ), ( 15, 15, 5 ), self ); + self.origin = v_trace[ "position" ]; + timer = 0; + self animscripted( self.origin, self.angles, "zm_robot_hit_in" ); + self maps/mp/animscripts/zm_shared::donotetracks( "pain_anim" ); + anim_length = self getanimlengthfromasd( "zm_robot_hit_loop", 0 ); + while ( timer < level.mechz_robot_knockdown_time ) + { + timer += anim_length; + self animscripted( self.origin, self.angles, "zm_robot_hit_loop" ); + self maps/mp/animscripts/zm_shared::donotetracks( "pain_anim" ); + } + self animscripted( self.origin, self.angles, "zm_robot_hit_out" ); + self maps/mp/animscripts/zm_shared::donotetracks( "jump_anim" ); +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\nMZ: Robot stomp clearing not interruptable\n" ); +#/ + } + self.not_interruptable = 0; + self.robot_stomped = 0; +} + +mechz_delayed_item_delete() +{ + wait 30; + self delete(); +} + +mechz_get_closest_valid_player() +{ + players = get_players(); + while ( isDefined( self.ignore_player ) ) + { + i = 0; + while ( i < self.ignore_player.size ) + { + arrayremovevalue( players, self.ignore_player[ i ] ); + i++; + } + } + i = 0; + while ( i < players.size ) + { + if ( isDefined( level._zombie_using_humangun ) && level._zombie_using_humangun && isai( players[ i ] ) ) + { + return players[ i ]; + } + if ( !is_player_valid( players[ i ], 1, 1 ) ) + { + arrayremovevalue( players, players[ i ] ); + i--; + + } + i++; + } + switch( players.size ) + { + case 0: + return undefined; + case 1: + return players[ 0 ]; + default: + if ( isDefined( level.closest_player_override ) ) + { + player = [[ level.closest_player_override ]]( self.origin, players ); + } + else if ( isDefined( level.calc_closest_player_using_paths ) && level.calc_closest_player_using_paths ) + { + player = get_closest_player_using_paths( self.origin, players ); + } + else + { + player = getclosest( self.origin, players ); + } + return player; + } +} + +get_favorite_enemy( origin, players ) +{ + mechz_targets = getplayers(); + least_hunted = undefined; + best_hunted_val = -1; + best_dist = -1; + distances = []; + if ( isDefined( self.favoriteenemy ) && is_player_valid( self.favoriteenemy, 1, 1 ) && !isDefined( self.favoriteenemy.in_giant_robot_head ) && !self.favoriteenemy maps/mp/zm_tomb_chamber::is_player_in_chamber() ) + { +/# + assert( isDefined( self.favoriteenemy.hunted_by ) ); +#/ + self.favoriteenemy.hunted_by--; + + least_hunted = self.favoriteenemy; + } + i = 0; + while ( i < mechz_targets.size ) + { + if ( !isDefined( mechz_targets[ i ].hunted_by ) || mechz_targets[ i ].hunted_by < 0 ) + { + mechz_targets[ i ].hunted_by = 0; + } + if ( !is_player_valid( mechz_targets[ i ], 1, 1 ) ) + { + i++; + continue; + } + else + { + distances[ i ] = distancesquared( self.origin, mechz_targets[ i ].origin ); + } + i++; + } + found_weapon_target = 0; + i = 0; + while ( i < mechz_targets.size ) + { + if ( abs( mechz_targets[ i ].origin[ 2 ] - self.origin[ 2 ] ) > 60 ) + { + i++; + continue; + } + else dist = distances[ i ]; + if ( !isDefined( dist ) ) + { + i++; + continue; + } + else + { + if ( dist < 50000 || dist < best_dist && best_dist < 0 ) + { + found_weapon_target = 1; + least_hunted = mechz_targets[ i ]; + best_dist = dist; + } + } + i++; + } + if ( found_weapon_target ) + { + least_hunted.hunted_by++; + return least_hunted; + } + if ( isDefined( self.favoriteenemy ) && is_player_valid( self.favoriteenemy, 1, 1 ) ) + { + if ( distancesquared( self.origin, self.favoriteenemy.origin ) <= level.mechz_sticky_dist_sq ) + { + self.favoriteenemy.hunted_by++; + return self.favoriteenemy; + } + } + i = 0; + while ( i < mechz_targets.size ) + { + if ( isDefined( mechz_targets[ i ].in_giant_robot_head ) ) + { + i++; + continue; + } + else if ( mechz_targets[ i ] maps/mp/zm_tomb_chamber::is_player_in_chamber() ) + { + i++; + continue; + } + else if ( isDefined( distances[ i ] ) ) + { + dist = distances[ i ]; + } + else + { + } + hunted = mechz_targets[ i ].hunted_by; + if ( !isDefined( least_hunted ) || hunted <= least_hunted.hunted_by ) + { + if ( dist < best_dist || best_dist < 0 ) + { + least_hunted = mechz_targets[ i ]; + best_dist = dist; + } + } + i++; + } + if ( isDefined( least_hunted ) ) + { + least_hunted.hunted_by++; + } + return least_hunted; +} + +mechz_check_in_arc( right_offset ) +{ + origin = self.origin; + if ( isDefined( right_offset ) ) + { + right_angle = anglesToRight( self.angles ); + origin += right_angle * right_offset; + } + facing_vec = anglesToForward( self.angles ); + enemy_vec = self.favoriteenemy.origin - origin; + enemy_yaw_vec = ( enemy_vec[ 0 ], enemy_vec[ 1 ], 0 ); + facing_yaw_vec = ( facing_vec[ 0 ], facing_vec[ 1 ], 0 ); + enemy_yaw_vec = vectornormalize( enemy_yaw_vec ); + facing_yaw_vec = vectornormalize( facing_yaw_vec ); + enemy_dot = vectordot( facing_yaw_vec, enemy_yaw_vec ); + if ( enemy_dot < cos( level.mechz_aim_max_yaw ) ) + { + return 0; + } + enemy_angles = vectorToAngle( enemy_vec ); + if ( abs( angleClamp180( enemy_angles[ 0 ] ) ) > level.mechz_aim_max_pitch ) + { + return 0; + } + return 1; +} + +mechz_get_aim_anim( anim_prefix, target_pos, right_offset ) +{ + in_arc = self mechz_check_in_arc( right_offset ); + if ( !in_arc ) + { + return undefined; + } + origin = self.origin; + if ( isDefined( right_offset ) ) + { + right_angle = anglesToRight( self.angles ); + origin += right_angle * right_offset; + } + aiming_vec = vectorToAngle( target_pos - origin ); + pitch = angleClamp180( aiming_vec[ 0 ] ); + yaw = angleClamp180( self.angles[ 1 ] - aiming_vec[ 1 ] ); + centered_ud = abs( pitch ) < ( level.mechz_aim_max_pitch / 2 ); + centered_lr = abs( yaw ) < ( level.mechz_aim_max_yaw / 2 ); + right_anim = angleClamp180( self.angles[ 1 ] - aiming_vec[ 1 ] ) > 0; + up_anim = pitch < 0; + if ( centered_ud && centered_lr ) + { + return anim_prefix + "_aim_5"; + } + else + { + if ( centered_ud && right_anim ) + { + return anim_prefix + "_aim_6"; + } + else + { + if ( centered_ud ) + { + return anim_prefix + "_aim_4"; + } + else + { + if ( centered_lr && up_anim ) + { + return anim_prefix + "_aim_8"; + } + else + { + if ( centered_lr ) + { + return anim_prefix + "_aim_2"; + } + else + { + if ( right_anim && up_anim ) + { + return anim_prefix + "_aim_9"; + } + else + { + if ( right_anim ) + { + return anim_prefix + "_aim_3"; + } + else + { + if ( up_anim ) + { + return anim_prefix + "_aim_7"; + } + else + { + return anim_prefix + "_aim_1"; + } + } + } + } + } + } + } + } +} + +mechz_start_basic_find_flesh() +{ + self.goalradius = level.mechz_custom_goalradius; + self.custom_goalradius_override = level.mechz_custom_goalradius; + if ( !isDefined( self.ai_state ) || self.ai_state != "find_flesh" ) + { + self.ai_state = "find_flesh"; + self thread maps/mp/zombies/_zm_ai_basic::find_flesh(); + } +} + +mechz_stop_basic_find_flesh() +{ + if ( isDefined( self.ai_state ) && self.ai_state == "find_flesh" ) + { + self.ai_state = undefined; + self notify( "stop_find_flesh" ); + self notify( "zombie_acquire_enemy" ); + } +} + +watch_for_player_dist() +{ + self endon( "death" ); + while ( 1 ) + { + player = mechz_get_closest_valid_player(); + if ( isDefined( player ) && isDefined( player.is_player_slowed ) && player.is_player_slowed ) + { + reset_dist = level.mechz_reset_dist_sq / 2; + } + else + { + reset_dist = level.mechz_reset_dist_sq; + } + if ( !isDefined( player ) || distancesquared( player.origin, self.origin ) > reset_dist ) + { + self.disable_complex_behaviors = 0; + } + wait 0,5; + } +} + +mechz_find_flesh() +{ + self endon( "death" ); + level endon( "intermission" ); + if ( level.intermission ) + { + return; + } + self.helitarget = 1; + self.ignoreme = 0; + self.nododgemove = 1; + self.ignore_player = []; + self.goalradius = 32; + self.ai_state = "spawning"; + self thread watch_for_player_dist(); + for ( ;; ) + { + while ( 1 ) + { +/# + while ( isDefined( self.force_behavior ) && self.force_behavior ) + { + wait 0,05; +#/ + } + while ( isDefined( self.not_interruptable ) && self.not_interruptable ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\nMZ: Not thinking since a behavior has set not_interruptable\n" ); +#/ + } + wait 0,05; + } + while ( isDefined( self.is_traversing ) && self.is_traversing ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\nMZ: Not thinking since mech is traversing\n" ); +#/ + } + wait 0,05; + } + player = [[ self.closest_player_override ]](); + self mechz_set_locomotion_speed(); +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\nMZ: Doing think\n" ); +#/ + } + self.favoriteenemy = player; + while ( !isDefined( player ) ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\tMZ: No Enemy, idling\n" ); +#/ + } + self.goal_pos = self.origin; + self setgoalpos( self.goal_pos ); + self.ai_state = "idle"; + self setanimstatefromasd( "zm_idle" ); + wait 0,5; + } + if ( player entity_on_tank() ) + { + if ( level.vh_tank ent_flag( "tank_moving" ) ) + { + if ( isDefined( self.jump_pos ) && self mechz_in_range_for_jump() ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\tMZ: Enemy on moving tank, do jump out and jump in when tank is stationary\n" ); +#/ + } + self mechz_do_jump( 1 ); + break; + } + else + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\tMZ: Enemy on moving tank, Jump Requested, going to jump pos\n" ); +#/ + } + if ( !isDefined( self.jump_pos ) ) + { + self.jump_pos = get_closest_mechz_spawn_pos( self.origin ); + } + if ( isDefined( self.jump_pos ) ) + { + self.goal_pos = self.jump_pos.origin; + self setgoalpos( self.goal_pos ); + } + wait 0,5; + } + } + } + else /# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\tMZ: Enemy on tank, targetting a tank pos\n" ); +#/ + } + self.disable_complex_behaviors = 0; + self mechz_stop_basic_find_flesh(); + self.ai_state = "tracking_tank"; + self.goalradius = level.mechz_custom_goalradius; + self.custom_goalradius_override = level.mechz_custom_goalradius; + closest_tank_tag = level.vh_tank get_closest_mechz_tag_on_tank( self, self.origin ); + while ( !isDefined( closest_tank_tag ) ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\tMZ: Enemy on tank, no closest tank pos found, continuing\n" ); +#/ + } + wait 0,5; + } + closest_tank_tag_pos = level.vh_tank gettagorigin( closest_tank_tag ); + while ( abs( self.origin[ 2 ] - closest_tank_tag_pos[ 2 ] ) >= level.mechz_custom_goalradius || distance2dsquared( self.origin, closest_tank_tag_pos ) >= level.mechz_custom_goalradius_sq ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\tMZ: Enemy on tank, setting tank pos as goal\n" ); +#/ + } + self.goal_pos = closest_tank_tag_pos; + self setgoalpos( self.goal_pos ); + self waittill_any_or_timeout( 0,5, "goal", "bad_path" ); + while ( !player entity_on_tank() ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\tMZ: Enemy got off tank by the time we reached our goal, continuing\n" ); +#/ + } + } + } + if ( abs( self.origin[ 2 ] - closest_tank_tag_pos[ 2 ] ) < level.mechz_custom_goalradius && distance2dsquared( self.origin, closest_tank_tag_pos ) < level.mechz_custom_goalradius_sq ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\tMZ: Enemy on tank, reached tank pos, doing flamethrower sweep\n" ); +#/ + } + self.angles = vectorToAngle( level.vh_tank.origin - self.origin ); + self mechz_do_flamethrower_attack( 1 ); + self notify( "tank_flamethrower_attack_complete" ); + } + } + } + else if ( isDefined( self.jump_requested ) || self.jump_requested && isDefined( self.force_jump ) && self.force_jump ) + { + if ( self mechz_in_range_for_jump() ) + { + self mechz_do_jump(); + } + else + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\tMZ: Jump Requested, going to jump pos\n" ); +#/ + } + self.goal_pos = self.jump_pos.origin; + self setgoalpos( self.goal_pos ); + wait 0,5; + } + } +} +else if ( self.zombie_move_speed == "sprint" && isDefined( player ) ) +{ +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\tMZ: Sprinting\n" ); +#/ + } + self.goal_pos = player.origin; + self setgoalpos( self.goal_pos ); + wait 0,5; +} +} +else if ( distancesquared( self.origin, player.origin ) < level.mechz_aggro_dist_sq ) +{ +/# +if ( getDvarInt( #"E7121222" ) > 1 ) +{ + println( "\n\tMZ: Player very close, switching to melee only\n" ); +#/ +} +self.disable_complex_behaviors = 1; +} +else if ( self should_do_claw_attack() ) +{ +self mechz_do_claw_grab(); +} +} +else while ( self should_do_flamethrower_attack() ) +{ +self mechz_do_flamethrower_attack(); +} +/# +if ( getDvarInt( #"E7121222" ) > 1 ) +{ +println( "\n\tMZ: No special behavior valid, heading after player\n" ); +#/ +} +self.goal_pos = player.origin; +if ( isDefined( level.damage_prone_players_override_func ) ) +{ +level thread [[ level.damage_prone_players_override_func ]](); +} +else +{ +self thread damage_prone_players(); +} +mechz_start_basic_find_flesh(); +wait 0,5; +} +} + +damage_prone_players() +{ + self endon( "death" ); + a_players = getplayers(); + _a1878 = a_players; + _k1878 = getFirstArrayKey( _a1878 ); + while ( isDefined( _k1878 ) ) + { + player = _a1878[ _k1878 ]; + if ( isDefined( self.favoriteenemy ) && self.favoriteenemy == player ) + { + n_dist = distance2dsquared( player.origin, self.origin ); + if ( n_dist < 2025 ) + { + player_z = player.origin[ 2 ]; + mechz_z = self.origin[ 2 ]; + if ( player_z < mechz_z && ( mechz_z - player_z ) <= 75 ) + { + if ( isDefined( self.meleedamage ) ) + { + idamage = self.meleedamage; + } + else + { + idamage = 50; + } + player dodamage( idamage, self.origin, self, self, "none", "MOD_MELEE" ); + } + } + } + _k1878 = getNextArrayKey( _a1878, _k1878 ); + } +} + +melee_anim_func() +{ + self.next_leap_time = getTime() + 1500; +} + +mechz_launch_armor_piece() +{ + if ( !isDefined( self.next_armor_piece ) ) + { + self.next_armor_piece = 0; + } + if ( !isDefined( self.armor_state ) || self.next_armor_piece >= self.armor_state.size ) + { +/# + println( "Trying to launch armor piece after all pieces have already been launched!" ); +#/ + return; + } + if ( isDefined( self.armor_state[ self.next_armor_piece ].model ) ) + { + self detach( self.armor_state[ self.next_armor_piece ].model, self.armor_state[ self.next_armor_piece ].tag ); + } + self.fx_field |= 1 << self.armor_state[ self.next_armor_piece ].index; + self setclientfield( "mechz_fx", self.fx_field ); + if ( sndmechzisnetworksafe( "destruction" ) ) + { + self playsound( "zmb_ai_mechz_destruction" ); + } + self.next_armor_piece++; +} + +mechz_damage_override( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, shitloc, poffsettime, boneindex ) +{ + num_tiers = level.mechz_armor_info.size + 1; + old_health_tier = int( ( num_tiers * self.health ) / self.maxhealth ); + bonename = getpartname( "c_zom_mech_body", boneindex ); + if ( isDefined( attacker ) && isalive( attacker ) && isplayer( attacker ) || level.zombie_vars[ attacker.team ][ "zombie_insta_kill" ] && isDefined( attacker.personal_instakill ) && attacker.personal_instakill ) + { + n_mechz_damage_percent = 1; + n_mechz_headshot_modifier = 2; + } + else + { + n_mechz_damage_percent = level.mechz_damage_percent; + n_mechz_headshot_modifier = 1; + } + if ( isDefined( weapon ) && is_weapon_shotgun( weapon ) ) + { + n_mechz_damage_percent *= level.mechz_shotgun_damage_mod; + n_mechz_headshot_modifier *= level.mechz_shotgun_damage_mod; + } + if ( damage <= 10 ) + { + n_mechz_damage_percent = 1; + } + if ( is_explosive_damage( meansofdeath ) || issubstr( weapon, "staff" ) ) + { + if ( n_mechz_damage_percent < 0,5 ) + { + n_mechz_damage_percent = 0,5; + } + if ( isDefined( self.has_helmet ) && !self.has_helmet && issubstr( weapon, "staff" ) && n_mechz_damage_percent < 1 ) + { + n_mechz_damage_percent = 1; + } + final_damage = damage * n_mechz_damage_percent; + if ( !isDefined( self.explosive_dmg_taken ) ) + { + self.explosive_dmg_taken = 0; + } + self.explosive_dmg_taken += final_damage; + self.helmet_dmg += final_damage; + if ( isDefined( self.explosive_dmg_taken_on_grab_start ) ) + { + if ( isDefined( self.e_grabbed ) && ( self.explosive_dmg_taken - self.explosive_dmg_taken_on_grab_start ) > level.mechz_explosive_dmg_to_cancel_claw ) + { + if ( isDefined( self.has_helmet ) && self.has_helmet || self.helmet_dmg < self.helmet_dmg_for_removal && isDefined( self.has_helmet ) && !self.has_helmet ) + { + self thread mechz_claw_shot_pain_reaction(); + } + self thread ent_released_from_claw_grab_achievement( attacker, self.e_grabbed ); + self thread mechz_claw_release(); + } + } + } + else + { + if ( shitloc != "head" && shitloc != "helmet" ) + { + if ( bonename == "tag_powersupply" ) + { + final_damage = damage * n_mechz_damage_percent; + if ( isDefined( self.powerplant_covered ) && !self.powerplant_covered ) + { + self.powerplant_dmg += final_damage; + } + else + { + self.powerplant_cover_dmg += final_damage; + } + } + if ( isDefined( self.e_grabbed ) && shitloc != "left_hand" || shitloc == "left_arm_lower" && shitloc == "left_arm_upper" ) + { + if ( isDefined( self.e_grabbed ) ) + { + self thread mechz_claw_shot_pain_reaction(); + } + self thread ent_released_from_claw_grab_achievement( attacker, self.e_grabbed ); + self thread mechz_claw_release( 1 ); + } + final_damage = damage * n_mechz_damage_percent; + } + else + { + if ( isDefined( self.has_helmet ) && !self.has_helmet ) + { + final_damage = damage * n_mechz_headshot_modifier; + } + else + { + final_damage = damage * n_mechz_damage_percent; + self.helmet_dmg += final_damage; + } + } + } + if ( !isDefined( weapon ) || weapon == "none" ) + { + if ( !isplayer( attacker ) ) + { + final_damage = 0; + } + } + new_health_tier = int( ( num_tiers * ( self.health - final_damage ) ) / self.maxhealth ); + while ( old_health_tier > new_health_tier ) + { + while ( old_health_tier > new_health_tier ) + { +/# + if ( getDvarInt( #"E7121222" ) > 0 ) + { + println( "\nMZ: Old tier: " + old_health_tier + " New Health Tier: " + new_health_tier + " Launching armor piece" ); +#/ + } + if ( old_health_tier < num_tiers ) + { + self mechz_launch_armor_piece(); + } + old_health_tier--; + + } + } + if ( isDefined( self.has_helmet ) && self.has_helmet && self.helmet_dmg >= self.helmet_dmg_for_removal ) + { + self.has_helmet = 0; + self detach( "c_zom_mech_faceplate", "J_Helmet" ); + if ( sndmechzisnetworksafe( "destruction" ) ) + { + self playsound( "zmb_ai_mechz_destruction" ); + } + if ( sndmechzisnetworksafe( "angry" ) ) + { + self playsound( "zmb_ai_mechz_vox_angry" ); + } + self.fx_field |= 1024; + self.fx_field &= 2048; + self setclientfield( "mechz_fx", self.fx_field ); + if ( isDefined( self.not_interruptable ) && !self.not_interruptable && isDefined( self.is_traversing ) && !self.is_traversing ) + { + self mechz_interrupt(); + self animscripted( self.origin, self.angles, "zm_pain_faceplate" ); + self maps/mp/animscripts/zm_shared::donotetracks( "pain_anim_faceplate" ); + } + self thread shoot_mechz_head_vo(); + } + if ( isDefined( self.powerplant_covered ) && self.powerplant_covered && self.powerplant_cover_dmg >= self.powerplant_cover_dmg_for_removal ) + { + self.powerplant_covered = 0; + self detach( "c_zom_mech_powersupply_cap", "tag_powersupply" ); + cap_model = spawn( "script_model", self gettagorigin( "tag_powersupply" ) ); + cap_model.angles = self gettagangles( "tag_powersupply" ); + cap_model setmodel( "c_zom_mech_powersupply_cap" ); + cap_model physicslaunch( cap_model.origin, anglesToForward( cap_model.angles ) ); + cap_model thread mechz_delayed_item_delete(); + if ( sndmechzisnetworksafe( "destruction" ) ) + { + self playsound( "zmb_ai_mechz_destruction" ); + } + if ( isDefined( self.not_interruptable ) && !self.not_interruptable && isDefined( self.is_traversing ) && !self.is_traversing ) + { + self mechz_interrupt(); + self animscripted( self.origin, self.angles, "zm_pain_powercore" ); + self maps/mp/animscripts/zm_shared::donotetracks( "pain_anim_powercore" ); + } + } + else + { + if ( isDefined( self.powerplant_covered ) && !self.powerplant_covered && isDefined( self.has_powerplant ) && self.has_powerplant && self.powerplant_dmg >= self.powerplant_dmg_for_destroy ) + { + self.has_powerplant = 0; + self thread mechz_stun( level.mechz_powerplant_stun_time ); + if ( sndmechzisnetworksafe( "destruction" ) ) + { + self playsound( "zmb_ai_mechz_destruction" ); + } + } + } +/# + if ( getDvarInt( #"E7121222" ) > 0 ) + { + println( "\nMZ: Doing " + final_damage + " damage to mechz, Health Remaining: " + self.health ); + if ( self.helmet_dmg < self.helmet_dmg_for_removal ) + { + println( "\nMZ: Current helmet dmg: " + self.helmet_dmg + " Required helmet dmg: " + self.helmet_dmg_for_removal ); +#/ + } + } + return final_damage; +} + +mechz_non_attacker_damage_override( damage, weapon, attacker ) +{ + if ( attacker == level.vh_tank ) + { + self thread mechz_tank_hit_callback(); + } + return 0; +} + +mechz_instakill_override() +{ + return; +} + +mechz_nuke_override() +{ + self endon( "death" ); + wait randomfloatrange( 0,1, 0,7 ); + self playsound( "evt_nuked" ); + self dodamage( self.health * 0,25, self.origin ); + return; +} + +mechz_set_locomotion_speed() +{ + self endon( "death" ); + self.prev_move_speed = self.zombie_move_speed; + if ( !isDefined( self.favoriteenemy ) ) + { + self.zombie_move_speed = "walk"; + } + else if ( isDefined( self.force_run ) && self.force_run ) + { + self.zombie_move_speed = "run"; + } + else + { + if ( isDefined( self.force_sprint ) && self.force_sprint ) + { + self.zombie_move_speed = "sprint"; + } + else + { + if ( isDefined( self.favoriteenemy ) && self.favoriteenemy entity_on_tank() && isDefined( level.vh_tank ) && level.vh_tank ent_flag( "tank_activated" ) ) + { + self.zombie_move_speed = "run"; + } + else + { + if ( isDefined( self.favoriteenemy ) && distancesquared( self.origin, self.favoriteenemy.origin ) > level.mechz_dist_for_sprint ) + { + self.zombie_move_speed = "run"; + } + else + { + if ( isDefined( self.has_powerplant ) && !self.has_powerplant ) + { + self.zombie_move_speed = "walk"; + } + else + { + self.zombie_move_speed = "walk"; + } + } + } + } + } + if ( self.zombie_move_speed == "sprint" && self.prev_move_speed != "sprint" ) + { + self mechz_interrupt(); + self animscripted( self.origin, self.angles, "zm_sprint_intro" ); + self maps/mp/animscripts/zm_shared::donotetracks( "jump_anim" ); + } + else + { + if ( self.zombie_move_speed != "sprint" && self.prev_move_speed == "sprint" ) + { + self animscripted( self.origin, self.angles, "zm_sprint_outro" ); + self maps/mp/animscripts/zm_shared::donotetracks( "jump_anim" ); + } + } + self set_zombie_run_cycle( self.zombie_move_speed ); +} + +response_to_air_raid_siren_vo() +{ + wait 3; + a_players = getplayers(); + if ( a_players.size == 0 ) + { + return; + } + a_players = array_randomize( a_players ); + _a2280 = a_players; + _k2280 = getFirstArrayKey( _a2280 ); + while ( isDefined( _k2280 ) ) + { + player = _a2280[ _k2280 ]; + if ( is_player_valid( player ) ) + { + if ( isDefined( player.dontspeak ) && !player.dontspeak ) + { + if ( !isDefined( level.air_raid_siren_count ) ) + { + player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "siren_1st_time" ); + level.air_raid_siren_count = 1; + while ( isDefined( player ) && isDefined( player.isspeaking ) && player.isspeaking ) + { + wait 0,1; + } + level thread start_see_mech_zombie_vo(); + return; + } + else if ( level.mechz_zombie_per_round == 1 ) + { + player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "siren_generic" ); + return; + } + else player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "multiple_mechs" ); + return; + } + } + else + { + _k2280 = getNextArrayKey( _a2280, _k2280 ); + } + } +} + +start_see_mech_zombie_vo() +{ + wait 1; + a_zombies = getaispeciesarray( level.zombie_team, "all" ); + _a2321 = a_zombies; + _k2321 = getFirstArrayKey( _a2321 ); + while ( isDefined( _k2321 ) ) + { + zombie = _a2321[ _k2321 ]; + if ( isDefined( zombie.is_mechz ) && zombie.is_mechz ) + { + ai_mechz = zombie; + } + _k2321 = getNextArrayKey( _a2321, _k2321 ); + } + a_players = getplayers(); + if ( a_players.size == 0 ) + { + return; + } + while ( isalive( ai_mechz ) ) + { + _a2337 = a_players; + _k2337 = getFirstArrayKey( _a2337 ); + while ( isDefined( _k2337 ) ) + { + player = _a2337[ _k2337 ]; + player thread player_looking_at_mechz_watcher( ai_mechz ); + _k2337 = getNextArrayKey( _a2337, _k2337 ); + } + } +} + +player_looking_at_mechz_watcher( ai_mechz ) +{ + self endon( "disconnect" ); + ai_mechz endon( "death" ); + level endon( "first_mech_zombie_seen" ); + while ( 1 ) + { + if ( distancesquared( self.origin, ai_mechz.origin ) < 1000000 ) + { + if ( self is_player_looking_at( ai_mechz.origin + vectorScale( ( 0, 0, 1 ), 60 ), 0,75 ) ) + { + if ( isDefined( self.dontspeak ) && !self.dontspeak ) + { + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "discover_mech" ); + level notify( "first_mech_zombie_seen" ); + return; + } + } + } + else + { + wait 0,1; + } + } +} + +mechz_grabbed_played_vo( ai_mechz ) +{ + self endon( "disconnect" ); + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "mech_grab" ); + while ( isDefined( self ) && isDefined( self.isspeaking ) && self.isspeaking ) + { + wait 0,1; + } + wait 1; + if ( isalive( ai_mechz ) && isDefined( ai_mechz.e_grabbed ) ) + { + ai_mechz thread play_shoot_arm_hint_vo(); + } +} + +play_shoot_arm_hint_vo() +{ + self endon( "death" ); + while ( 1 ) + { + if ( !isDefined( self.e_grabbed ) ) + { + return; + } + a_players = getplayers(); + _a2399 = a_players; + _k2399 = getFirstArrayKey( _a2399 ); + while ( isDefined( _k2399 ) ) + { + player = _a2399[ _k2399 ]; + if ( player == self.e_grabbed ) + { + } + else + { + if ( distancesquared( self.origin, player.origin ) < 1000000 ) + { + if ( player is_player_looking_at( self.origin + vectorScale( ( 0, 0, 1 ), 60 ), 0,75 ) ) + { + if ( isDefined( player.dontspeak ) && !player.dontspeak ) + { + player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "shoot_mech_arm" ); + return; + } + } + } + } + _k2399 = getNextArrayKey( _a2399, _k2399 ); + } + wait 0,1; + } +} + +mechz_hint_vo() +{ + self endon( "death" ); + wait 30; + while ( 1 ) + { + while ( self.health > ( self.maxhealth * 0,5 ) ) + { + wait 1; + } + while ( isDefined( self.powerplant_covered ) && !self.powerplant_covered ) + { + wait 1; + } + a_players = getplayers(); + _a2444 = a_players; + _k2444 = getFirstArrayKey( _a2444 ); + while ( isDefined( _k2444 ) ) + { + player = _a2444[ _k2444 ]; + if ( isDefined( self.e_grabbed ) && self.e_grabbed == player ) + { + } + else + { + if ( distancesquared( self.origin, player.origin ) < 1000000 ) + { + if ( player is_player_looking_at( self.origin + vectorScale( ( 0, 0, 1 ), 60 ), 0,75 ) ) + { + if ( isDefined( player.dontspeak ) && !player.dontspeak ) + { + player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "shoot_mech_power" ); + return; + } + } + } + } + _k2444 = getNextArrayKey( _a2444, _k2444 ); + } + wait 0,1; + } +} + +shoot_mechz_head_vo() +{ + self endon( "death" ); + a_players = getplayers(); + _a2473 = a_players; + _k2473 = getFirstArrayKey( _a2473 ); + while ( isDefined( _k2473 ) ) + { + player = _a2473[ _k2473 ]; + if ( isDefined( self.e_grabbed ) && self.e_grabbed == player ) + { + } + else + { + if ( distancesquared( self.origin, player.origin ) < 1000000 ) + { + if ( player is_player_looking_at( self.origin + vectorScale( ( 0, 0, 1 ), 60 ), 0,75 ) ) + { + if ( isDefined( player.dontspeak ) && !player.dontspeak ) + { + player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "shoot_mech_head" ); + return; + } + } + } + } + _k2473 = getNextArrayKey( _a2473, _k2473 ); + } +} + +mechz_jump_vo() +{ + a_players = getplayers(); + _a2497 = a_players; + _k2497 = getFirstArrayKey( _a2497 ); + while ( isDefined( _k2497 ) ) + { + player = _a2497[ _k2497 ]; + if ( distancesquared( self.origin, player.origin ) < 1000000 ) + { + if ( player is_player_looking_at( self.origin + vectorScale( ( 0, 0, 1 ), 60 ), 0,5 ) ) + { + if ( isDefined( player.dontspeak ) && !player.dontspeak ) + { + player delay_thread( 3, ::maps/mp/zombies/_zm_audio::create_and_play_dialog, "general", "rspnd_mech_jump" ); + return; + } + } + } + _k2497 = getNextArrayKey( _a2497, _k2497 ); + } +} + +mechz_stomped_by_giant_robot_vo() +{ + self endon( "death" ); + wait 5; + a_players = getplayers(); + _a2520 = a_players; + _k2520 = getFirstArrayKey( _a2520 ); + while ( isDefined( _k2520 ) ) + { + player = _a2520[ _k2520 ]; + if ( distancesquared( self.origin, player.origin ) < 1000000 ) + { + if ( player is_player_looking_at( self.origin + vectorScale( ( 0, 0, 1 ), 60 ), 0,75 ) ) + { + if ( isDefined( player.dontspeak ) && !player.dontspeak ) + { + player thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "robot_crush_mech" ); + return; + } + } + } + _k2520 = getNextArrayKey( _a2520, _k2520 ); + } +} + +init_anim_rate() +{ + self setclientfield( "anim_rate", 1 ); + n_rate = self getclientfield( "anim_rate" ); + self setentityanimrate( n_rate ); +} + +sndmechzisnetworksafe( type ) +{ + if ( !isDefined( level.sndmechz ) ) + { + level.sndmechz = []; + } + if ( !isDefined( level.sndmechz[ type ] ) ) + { + level thread sndmechznetworkchoke( type ); + } + if ( level.sndmechz[ type ] > 1 ) + { + return 0; + } + level.sndmechz[ type ]++; + return 1; +} + +sndmechznetworkchoke( type ) +{ + while ( 1 ) + { + level.sndmechz[ type ] = 0; + wait_network_frame(); + } +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz_booster.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz_booster.gsc new file mode 100644 index 0000000..a69f85f --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz_booster.gsc @@ -0,0 +1,300 @@ +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/animscripts/zm_shared; +#include maps/mp/zombies/_zm_ai_mechz; +#include maps/mp/zombies/_zm_ai_mechz_dev; +#include maps/mp/zm_tomb_tank; +#include maps/mp/animscripts/zm_utility; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/zombies/_zm_net; +#include maps/mp/_utility; +#include common_scripts/utility; +#include maps/mp/zombies/_zm_zonemgr; + +#using_animtree( "mechz_claw" ); + +mechz_in_range_for_jump() +{ + if ( !isDefined( self.jump_pos ) ) + { +/# + iprintln( "\nMZ Error: Trying to jump without valid jump_pos\n" ); +#/ + self.jump_requested = 0; + return 0; + } + dist = distancesquared( self.origin, self.jump_pos.origin ); + if ( dist <= 100 ) + { + return 1; + } + return 0; +} + +mechz_jump_think( spawn_pos ) +{ + self endon( "death" ); + self endon( "stop_jump_think" ); + self.closest_jump_point = spawn_pos; + self.goal_pos = self.origin; + self setgoalpos( self.goal_pos ); + self thread mechz_jump_stuck_watcher(); + while ( 1 ) + { + while ( isDefined( self.jump_requested ) && self.jump_requested ) + { + if ( !self mechz_should_jump() ) + { + self.jump_requested = 0; + self.jump_pos = undefined; + } + wait 1; + } + while ( !isDefined( self.ai_state ) || self.ai_state != "find_flesh" ) + { + wait 0,05; + } + while ( isDefined( self.not_interruptable ) && self.not_interruptable ) + { + wait 0,05; + } +/# + while ( isDefined( self.force_behavior ) && self.force_behavior ) + { + wait 0,05; +#/ + } + if ( self mechz_should_jump() ) + { + self.jump_requested = 1; + self.jump_pos = get_closest_mechz_spawn_pos( self.origin ); + if ( !isDefined( self.jump_pos ) ) + { + self.jump_requested = 0; + } + } + wait 1; + } +} + +watch_for_riot_shield_melee() +{ + self endon( "new_stuck_watcher" ); + self endon( "death" ); + while ( 1 ) + { + self waittill( "item_attack" ); +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\tMZ: Resetting fail count because of item attack\n" ); +#/ + } + self.fail_count = 0; + } +} + +watch_for_valid_melee() +{ + self endon( "new_stuck_watcher" ); + self endon( "death" ); + while ( 1 ) + { + self waittillmatch( "melee_anim" ); + return "end"; + if ( isDefined( self.favoriteenemy ) && distancesquared( self.origin, self.favoriteenemy.origin ) < 16384 ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\tMZ: Resetting fail count because of melee\n" ); +#/ + } + self.fail_count = 0; + } + } +} + +mechz_jump_stuck_watcher() +{ + self notify( "new_stuck_watcher" ); + self endon( "death" ); + self endon( "new_stuck_watcher" ); + self.fail_count = 0; + self thread watch_for_valid_melee(); + self thread watch_for_riot_shield_melee(); + while ( 1 ) + { + while ( !isDefined( self.goal_pos ) ) + { + wait 0,05; + } + while ( isDefined( self.not_interruptable ) && self.not_interruptable ) + { + wait 0,05; + } + while ( isDefined( self.ai_state ) && self.ai_state != "find_flesh" ) + { + wait 0,05; + } +/# + while ( isDefined( self.force_behavior ) && self.force_behavior ) + { + wait 0,05; +#/ + } + if ( !findpath( self.origin, self.goal_pos, self, 0, 0 ) ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\tMZ: Incrementing fail count\n" ); +#/ + } +/# + println( "Mechz could not path to goal_pos " + self.goal_pos ); +#/ + self.fail_count++; + } + else + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\tMZ: Resetting fail count because of good path\n" ); +#/ + } + self.fail_count = 0; + } + wait 1; + } +} + +mechz_should_jump() +{ +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\tMZ: Checking should jump\n" ); +#/ + } + if ( !isDefined( self.favoriteenemy ) ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\t\tMZ: Not doing jump because has no enemy\n" ); +#/ + } + return 0; + } + dist = distancesquared( self.origin, self.favoriteenemy.origin ); + if ( dist >= level.mechz_jump_dist_threshold ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\t\tMZ: Doing jump because target is too far\n" ); +#/ + } + return 1; + } + if ( self.fail_count >= level.mechz_failed_paths_to_jump ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\t\tMZ: Doing jump because has failed too many pathfind checks\n" ); +#/ + } + return 1; + } + return 0; +} + +mechz_do_jump( wait_for_stationary_tank ) +{ + self endon( "death" ); + self endon( "kill_jump" ); +/# + if ( getDvarInt( #"E7121222" ) > 0 ) + { + println( "\nMZ: Doing Jump-Teleport\n" ); +#/ + } +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\nMZ: Jump setting not interruptable\n" ); +#/ + } + self.not_interruptable = 1; + self setfreecameralockonallowed( 0 ); + self thread mechz_jump_vo(); + self animscripted( self.origin, self.angles, "zm_fly_out" ); + self maps/mp/animscripts/zm_shared::donotetracks( "jump_anim" ); + self ghost(); + self.mechz_hidden = 1; + if ( isDefined( self.m_claw ) ) + { + self.m_claw ghost(); + } + if ( self.fx_field ) + { + self.fx_field_old = self.fx_field; + } + self thread maps/mp/zombies/_zm_spawner::zombie_eye_glow_stop(); + self fx_cleanup(); + self animscripted( self.origin, self.angles, "zm_fly_hover" ); + wait level.mechz_jump_delay; + if ( isDefined( wait_for_stationary_tank ) && wait_for_stationary_tank ) + { + level.vh_tank ent_flag_waitopen( "tank_moving" ); + } + self notsolid(); + closest_jump_point = get_best_mechz_spawn_pos( 1 ); + if ( isDefined( closest_jump_point ) ) + { + self.closest_jump_point = closest_jump_point; + } + if ( !isDefined( self.closest_jump_point.angles ) ) + { + self.closest_jump_point.angles = ( 0, 0, 0 ); + } + self animscripted( self.closest_jump_point.origin, self.closest_jump_point.angles, "zm_fly_in" ); + self solid(); + self.mechz_hidden = 0; + self show(); + self.fx_field = self.fx_field_old; + self.fx_field_old = undefined; + self setclientfield( "mechz_fx", self.fx_field ); + self thread maps/mp/zombies/_zm_spawner::zombie_eye_glow(); + if ( isDefined( self.m_claw ) ) + { + self.m_claw show(); + } + self maps/mp/animscripts/zm_shared::donotetracks( "jump_anim" ); + self.not_interruptable = 0; + self setfreecameralockonallowed( 1 ); +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\nMZ: Jump clearing not interruptable\n" ); +#/ + } + mechz_jump_cleanup(); +} + +mechz_kill_jump_watcher() +{ + self endon( "jump_complete" ); + self waittill_either( "death", "kill_jump" ); + self mechz_jump_cleanup(); +} + +mechz_jump_cleanup() +{ + self.fx_field &= 128; + self setclientfield( "mechz_fx", self.fx_field ); + self stopanimscripted(); + self notify( "jump_complete" ); +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz_claw.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz_claw.gsc new file mode 100644 index 0000000..38e09ea --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz_claw.gsc @@ -0,0 +1,637 @@ +#include maps/mp/zombies/_zm_weap_riotshield_tomb; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/animscripts/zm_shared; +#include maps/mp/zombies/_zm_ai_mechz_ft; +#include maps/mp/zombies/_zm_ai_mechz; +#include maps/mp/zombies/_zm_ai_mechz_dev; +#include maps/mp/zm_tomb_tank; +#include maps/mp/animscripts/zm_utility; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/zombies/_zm_net; +#include maps/mp/_utility; +#include common_scripts/utility; +#include maps/mp/zombies/_zm_zonemgr; + +#using_animtree( "mechz_claw" ); + +mechz_claw_detach() +{ + if ( isDefined( self.m_claw ) ) + { + self.m_claw setanim( %ai_zombie_mech_grapple_arm_open_idle, 1, 0,2, 1 ); + if ( isDefined( self.m_claw.fx_ent ) ) + { + self.m_claw.fx_ent delete(); + } + self.m_claw unlink(); + self.m_claw physicslaunch( self.m_claw.origin, ( 0, 0, 0 ) ); + self.m_claw thread mechz_delayed_item_delete(); + self.m_claw = undefined; + } + if ( isDefined( self.m_claw_damage_trigger ) ) + { + self.m_claw_damage_trigger unlink(); + self.m_claw_damage_trigger delete(); + self.m_claw_damage_trigger = undefined; + } +} + +mechz_claw_release( bopenclaw ) +{ + self.explosive_dmg_taken_on_grab_start = undefined; + if ( isDefined( self.e_grabbed ) ) + { + if ( isplayer( self.e_grabbed ) ) + { + self.e_grabbed setclientfieldtoplayer( "mechz_grab", 0 ); + self.e_grabbed allowcrouch( 1 ); + self.e_grabbed allowprone( 1 ); + } + if ( !isDefined( self.e_grabbed._fall_down_anchor ) ) + { + trace_start = self.e_grabbed.origin + vectorScale( ( 0, 0, 0 ), 70 ); + trace_end = self.e_grabbed.origin + vectorScale( ( 0, 0, 0 ), 500 ); + drop_trace = playerphysicstrace( trace_start, trace_end ) + vectorScale( ( 0, 0, 0 ), 24 ); + self.e_grabbed unlink(); + self.e_grabbed setorigin( drop_trace ); + } + self.e_grabbed = undefined; + if ( isDefined( bopenclaw ) && bopenclaw ) + { + self.m_claw setanim( %ai_zombie_mech_grapple_arm_open_idle, 1, 0,2, 1 ); + } + } +} + +mechz_claw_shot_pain_reaction() +{ + self mechz_interrupt(); + self animscripted( self.origin, self.angles, "zm_head_pain" ); + self maps/mp/animscripts/zm_shared::donotetracks( "head_pain_anim" ); +} + +ent_released_from_claw_grab_achievement( e_releaser, e_held_by_mechz ) +{ + if ( isDefined( e_releaser ) && isDefined( e_held_by_mechz ) && isplayer( e_releaser ) && isplayer( e_held_by_mechz ) ) + { + if ( e_releaser == e_held_by_mechz ) + { + e_releaser notify( "mechz_grab_released_self" ); + return; + } + else + { + e_releaser notify( "mechz_grab_released_friendly" ); + } + } +} + +mechz_claw_notetracks() +{ + self endon( "death" ); + self endon( "kill_claw" ); + self waittillmatch( "grapple_anim" ); + return "muzzleflash"; + self waittillmatch( "grapple_anim" ); + return "end"; +} + +mechz_claw_aim( target_pos ) +{ + self endon( "death" ); + self endon( "kill_claw" ); + self endon( "claw_complete" ); + aim_anim = mechz_get_aim_anim( "zm_grapple", target_pos ); + self animscripted( self.origin, self.angles, "zm_grapple_aim_start" ); + self thread mechz_claw_notetracks(); + self maps/mp/animscripts/zm_shared::donotetracks( "grapple_anim" ); + while ( flag( "mechz_launching_claw" ) ) + { + self animscripted( self.origin, self.angles, aim_anim ); + self maps/mp/animscripts/zm_shared::donotetracks( "grapple_anim" ); + self clearanim( %root, 0 ); + } +} + +player_can_be_grabbed() +{ + if ( self getstance() == "prone" && isDefined( self.is_dtp ) && self.is_dtp ) + { + return 0; + } + if ( !is_player_valid( self, 1, 1 ) ) + { + return 0; + } + return 1; +} + +mechz_claw_explosive_watcher() +{ + if ( !isDefined( self.explosive_dmg_taken ) ) + { + self.explosive_dmg_taken = 0; + } + self.explosive_dmg_taken_on_grab_start = self.explosive_dmg_taken; +} + +mechz_unlink_on_laststand( mechz ) +{ + self endon( "death" ); + self endon( "disconnect" ); + mechz endon( "death" ); + mechz endon( "claw_complete" ); + mechz endon( "kill_claw" ); + while ( 1 ) + { + if ( isDefined( self ) && self maps/mp/zombies/_zm_laststand::player_is_in_laststand() ) + { + mechz thread mechz_claw_release(); + return; + } + wait 0,05; + } +} + +claw_grapple() +{ + self endon( "death" ); + self endon( "kill_claw" ); + if ( !isDefined( self.favoriteenemy ) ) + { + return; + } + v_claw_origin = self gettagorigin( "tag_claw" ); + v_claw_angles = vectorToAngle( self.origin - self.favoriteenemy.origin ); + self.fx_field |= 256; + self setclientfield( "mechz_fx", self.fx_field ); + self.m_claw setanim( %ai_zombie_mech_grapple_arm_open_idle, 1, 0, 1 ); + self.m_claw unlink(); + self.m_claw.fx_ent = spawn( "script_model", self.m_claw gettagorigin( "tag_claw" ) ); + self.m_claw.fx_ent.angles = self.m_claw gettagangles( "tag_claw" ); + self.m_claw.fx_ent setmodel( "tag_origin" ); + self.m_claw.fx_ent linkto( self.m_claw, "tag_claw" ); + network_safe_play_fx_on_tag( "mech_claw", 1, level._effect[ "mechz_claw" ], self.m_claw.fx_ent, "tag_origin" ); + v_enemy_origin = self.favoriteenemy.origin + vectorScale( ( 0, 0, 0 ), 36 ); + n_dist = distance( v_claw_origin, v_enemy_origin ); + n_time = n_dist / 1200; + self playsound( "zmb_ai_mechz_claw_fire" ); + self.m_claw moveto( v_enemy_origin, n_time ); + self.m_claw thread check_for_claw_move_complete(); + self.m_claw playloopsound( "zmb_ai_mechz_claw_loop_out", 0,1 ); + self.e_grabbed = undefined; + a_players = getplayers(); + _a260 = a_players; + _k260 = getFirstArrayKey( _a260 ); + while ( isDefined( _k260 ) ) + { + player = _a260[ _k260 ]; + if ( !is_player_valid( player, 1, 1 ) || !player player_can_be_grabbed() ) + { + } + else + { + n_dist_sq = distancesquared( player.origin + vectorScale( ( 0, 0, 0 ), 36 ), self.m_claw.origin ); + if ( n_dist_sq < 2304 ) + { + if ( isDefined( player.hasriotshield ) && player.hasriotshield && player getcurrentweapon() == level.riotshield_name ) + { + shield_dmg = level.zombie_vars[ "riotshield_hit_points" ]; + player maps/mp/zombies/_zm_weap_riotshield_tomb::player_damage_shield( shield_dmg - 1, 1 ); + wait 1; + player maps/mp/zombies/_zm_weap_riotshield_tomb::player_damage_shield( 1, 1 ); + } + else + { + self.e_grabbed = player; + self.e_grabbed setclientfieldtoplayer( "mechz_grab", 1 ); + self.e_grabbed playerlinktodelta( self.m_claw, "tag_attach_player" ); + self.e_grabbed setplayerangles( vectorToAngle( self.origin - self.e_grabbed.origin ) ); + self.e_grabbed playsound( "zmb_ai_mechz_claw_grab" ); + self.e_grabbed setstance( "stand" ); + self.e_grabbed allowcrouch( 0 ); + self.e_grabbed allowprone( 0 ); + self.e_grabbed thread mechz_grabbed_played_vo( self ); + if ( !flag( "mechz_claw_move_complete" ) ) + { + self.m_claw moveto( self.m_claw.origin, 0,05 ); + } + } + break; + } + } + else + { + _k260 = getNextArrayKey( _a260, _k260 ); + } + } + wait 0,05; + if ( !flag( "mechz_claw_move_complete" ) && !isDefined( self.e_grabbed ) ) + { + a_ai_zombies = get_round_enemy_array(); + _a306 = a_ai_zombies; + _k306 = getFirstArrayKey( _a306 ); + while ( isDefined( _k306 ) ) + { + ai_zombie = _a306[ _k306 ]; + if ( isalive( ai_zombie ) && isDefined( ai_zombie.is_giant_robot ) || ai_zombie.is_giant_robot && isDefined( ai_zombie.is_mechz ) && ai_zombie.is_mechz ) + { + } + else + { + n_dist_sq = distancesquared( ai_zombie.origin + vectorScale( ( 0, 0, 0 ), 36 ), self.m_claw.origin ); + if ( n_dist_sq < 2304 ) + { + self.e_grabbed = ai_zombie; + self.e_grabbed linkto( self.m_claw, "tag_attach_player", ( 0, 0, 0 ) ); + self.e_grabbed.mechz_grabbed_by = self; + self.e_grabbed animcustom( ::zombie_grabbed_by_mechz_claw ); + break; + } + } + else + { + _k306 = getNextArrayKey( _a306, _k306 ); + } + } + } + self.m_claw clearanim( %root, 0,2 ); + self.m_claw setanim( %ai_zombie_mech_grapple_arm_closed_idle, 1, 0,2, 1 ); + wait 0,5; + if ( isDefined( self.e_grabbed ) ) + { + n_time = n_dist / 200; + } + else + { + n_time = n_dist / 1000; + } + self mechz_claw_explosive_watcher(); + v_claw_origin = self gettagorigin( "tag_claw" ); + v_claw_angles = self gettagangles( "tag_claw" ); + self.m_claw moveto( v_claw_origin, max( 0,05, n_time ) ); + self.m_claw playloopsound( "zmb_ai_mechz_claw_loop_in", 0,1 ); + self.m_claw waittill( "movedone" ); + v_claw_origin = self gettagorigin( "tag_claw" ); + v_claw_angles = self gettagangles( "tag_claw" ); + self.m_claw playsound( "zmb_ai_mechz_claw_back" ); + self.m_claw stoploopsound( 1 ); + if ( maps/mp/zombies/_zm_ai_mechz::sndmechzisnetworksafe( "angry" ) ) + { + self playsound( "zmb_ai_mechz_vox_angry" ); + } + self.m_claw.origin = v_claw_origin; + self.m_claw.angles = v_claw_angles; + self.m_claw clearanim( %root, 0,2 ); + self.m_claw linkto( self, "tag_claw", ( 0, 0, 0 ) ); + self.m_claw setanim( %ai_zombie_mech_grapple_arm_closed_idle, 1, 0,2, 1 ); + self.m_claw.fx_ent delete(); + self.m_claw.fx_ent = undefined; + self.fx_field &= 256; + self setclientfield( "mechz_fx", self.fx_field ); + flag_clear( "mechz_launching_claw" ); + if ( isDefined( self.e_grabbed ) ) + { + if ( !isDefined( self.flamethrower_trigger ) ) + { + self mechz_flamethrower_initial_setup(); + } + if ( isplayer( self.e_grabbed ) && is_player_valid( self.e_grabbed ) ) + { + self.e_grabbed thread mechz_unlink_on_laststand( self ); + } + else + { + if ( isai( self.e_grabbed ) ) + { + self.e_grabbed thread mechz_zombie_flamethrower_gib( self ); + } + } + self thread check_for_claw_damaged( self.e_grabbed ); + self animscripted( self.origin, self.angles, "zm_flamethrower_claw_victim" ); + self maps/mp/animscripts/zm_shared::donotetracks( "flamethrower_anim" ); + } + flag_clear( "mechz_claw_move_complete" ); +} + +zombie_grabbed_by_mechz_claw() +{ + self endon( "death" ); + self setanimstatefromasd( "zm_grabbed_by_mech" ); + self.mechz_grabbed_by waittill_any( "death", "claw_complete", "kill_claw" ); +} + +check_for_claw_damaged( player ) +{ + player endon( "death" ); + player endon( "disconnect" ); + self endon( "death" ); + self endon( "claw_complete" ); + self endon( "kill_claw" ); + self thread claw_damaged_mechz_endon_watcher( player ); + player thread claw_damaged_player_endon_watcher( self ); + self.m_claw setcandamage( 1 ); + while ( isDefined( self.e_grabbed ) ) + { + self.m_claw waittill( "damage", amount, inflictor, direction, point, type, tagname, modelname, partname, weaponname, idflags ); + if ( is_player_valid( inflictor ) ) + { + self dodamage( 1, inflictor.origin, inflictor, inflictor, "left_hand", type ); + self.m_claw setcandamage( 0 ); + self notify( "claw_damaged" ); + return; + } + else + { + } + } +} + +claw_damaged_mechz_endon_watcher( player ) +{ + self endon( "claw_damaged" ); + player endon( "death" ); + player endon( "disconnect" ); + self waittill_any( "death", "claw_complete", "kill_claw" ); + if ( isDefined( self ) && isDefined( self.m_claw ) ) + { + self.m_claw setcandamage( 0 ); + } +} + +claw_damaged_player_endon_watcher( mechz ) +{ + mechz endon( "claw_damaged" ); + mechz endon( "death" ); + mechz endon( "claw_complete" ); + mechz endon( "kill_claw" ); + self waittill_any( "death", "disconnect" ); + if ( isDefined( mechz ) && isDefined( mechz.m_claw ) ) + { + mechz.m_claw setcandamage( 0 ); + } +} + +check_for_players_mid_grapple() +{ + self endon( "movedone" ); + while ( 1 ) + { + a_players = getplayers(); + _a471 = a_players; + _k471 = getFirstArrayKey( _a471 ); + while ( isDefined( _k471 ) ) + { + player = _a471[ _k471 ]; + if ( !is_player_valid( player, 1, 1 ) || !player player_can_be_grabbed() ) + { + } + else + { + n_dist_sq = distancesquared( player.origin + vectorScale( ( 0, 0, 0 ), 36 ), self.origin ); + if ( n_dist_sq < 2304 ) + { + self moveto( self.origin, 0,05 ); + self notify( "movedone" ); + return; + } + } + _k471 = getNextArrayKey( _a471, _k471 ); + } + wait 0,05; + } +} + +check_for_claw_move_complete() +{ + self waittill( "movedone" ); + wait 0,05; + flag_set( "mechz_claw_move_complete" ); +} + +mechz_zombie_flamethrower_gib( mechz ) +{ + mechz waittillmatch( "flamethrower_anim" ); + return "start_ft"; + if ( isalive( self ) ) + { + self thread zombie_gib_all(); + self dodamage( self.health, self.origin, self ); + } +} + +should_do_claw_attack() +{ +/# + assert( isDefined( self.favoriteenemy ) ); +#/ +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\tMZ: Checking should claw\n" ); +#/ + } + if ( isDefined( self.has_powerplant ) && !self.has_powerplant ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\t\tMZ: Not doing claw because powerplant has been destroyed\n" ); +#/ + } + return 0; + } + if ( isDefined( self.disable_complex_behaviors ) && self.disable_complex_behaviors ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\t\tMZ: Not doing claw because doing force aggro\n" ); +#/ + } + return 0; + } + if ( isDefined( self.not_interruptable ) && self.not_interruptable ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\t\tMZ: Not doing claw because another behavior has set not_interruptable\n" ); +#/ + } + return 0; + } + if ( isDefined( self.last_claw_time ) && ( getTime() - self.last_claw_time ) < level.mechz_claw_cooldown_time ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\t\tMZ: Not doing claw because claw is on cooldown\n" ); +#/ + } + return 0; + } + if ( !self mechz_check_in_arc() ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\t\tMZ: Not doing claw because target is not in front arc\n" ); +#/ + } + return 0; + } + n_dist_sq = distancesquared( self.origin, self.favoriteenemy.origin ); + if ( n_dist_sq < 90000 || n_dist_sq > 1000000 ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\t\tMZ: Not doing claw because target is not in range\n" ); +#/ + } + return 0; + } + if ( !self.favoriteenemy player_can_be_grabbed() ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\t\tMZ: Not doing claw because player is prone or dtp\n" ); +#/ + } + return 0; + } + curr_zone = get_zone_from_position( self.origin + vectorScale( ( 0, 0, 0 ), 36 ) ); + if ( isDefined( curr_zone ) && curr_zone == "ug_bottom_zone" ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\t\tMZ: Not doing claw because mech is in main chamber\n" ); +#/ + } + return 0; + } + clip_mask = level.physicstracemaskclip | level.physicstracemaskphysics; + claw_origin = self.origin + vectorScale( ( 0, 0, 0 ), 65 ); + trace = physicstrace( claw_origin, self.favoriteenemy.origin + vectorScale( ( 0, 0, 0 ), 30 ), ( -15, -15, -20 ), ( 15, 15, 40 ), self, clip_mask ); + if ( trace[ "fraction" ] != 1 ) + { + if ( isDefined( trace[ "entity" ] ) ) + { + b_cansee = trace[ "entity" ] == self.favoriteenemy; + } + } + if ( !b_cansee ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\t\tMZ: Not doing claw because capsule trace failed\n" ); +#/ + } + return 0; + } + return 1; +} + +mechz_do_claw_grab() +{ + self endon( "death" ); + self endon( "kill_claw" ); +/# + if ( getDvarInt( #"E7121222" ) > 0 ) + { + println( "\n\tMZ: Doing Claw Attack\n" ); +#/ + } +/# + assert( isDefined( self.favoriteenemy ) ); +#/ + self thread mechz_kill_claw_watcher(); + self.last_claw_time = getTime(); + target_pos = self.favoriteenemy.origin + vectorScale( ( 0, 0, 0 ), 30 ); + self thread mechz_stop_basic_find_flesh(); + self.ai_state = "grapple_attempt"; + flag_set( "mechz_launching_claw" ); + self thread mechz_claw_aim( target_pos ); + self orientmode( "face enemy" ); + self waittillmatch( "grapple_anim" ); + return "muzzleflash"; + self claw_grapple(); + self mechz_claw_cleanup(); +} + +mechz_kill_claw_watcher() +{ + self endon( "claw_complete" ); + self waittill_either( "death", "kill_claw" ); + self mechz_claw_cleanup(); +} + +mechz_claw_cleanup() +{ + self.fx_field &= 256; + self.fx_field &= 64; + self setclientfield( "mechz_fx", self.fx_field ); + self mechz_claw_release(); + if ( isDefined( self.m_claw ) ) + { + self.m_claw clearanim( %root, 0,2 ); + if ( isDefined( self.m_claw.fx_ent ) ) + { + self.m_claw.fx_ent delete(); + self.m_claw.fx_ent = undefined; + } + if ( isDefined( self.has_powerplant ) && !self.has_powerplant ) + { + self mechz_claw_detach(); + flag_clear( "mechz_launching_claw" ); + } + else + { + if ( !self.m_claw islinkedto( self ) ) + { + v_claw_origin = self gettagorigin( "tag_claw" ); + v_claw_angles = self gettagangles( "tag_claw" ); + n_dist = distance( self.m_claw.origin, v_claw_origin ); + n_time = n_dist / 1000; + self.m_claw moveto( v_claw_origin, max( 0,05, n_time ) ); + self.m_claw playloopsound( "zmb_ai_mechz_claw_loop_in", 0,1 ); + self.m_claw waittill( "movedone" ); + v_claw_origin = self gettagorigin( "tag_claw" ); + v_claw_angles = self gettagangles( "tag_claw" ); + self.m_claw playsound( "zmb_ai_mechz_claw_back" ); + self.m_claw stoploopsound( 1 ); + self.m_claw.origin = v_claw_origin; + self.m_claw.angles = v_claw_angles; + self.m_claw clearanim( %root, 0,2 ); + self.m_claw linkto( self, "tag_claw", ( 0, 0, 0 ) ); + } + self.m_claw setanim( %ai_zombie_mech_grapple_arm_closed_idle, 1, 0,2, 1 ); + } + } + self notify( "claw_complete" ); +} + +mechz_claw_damage_trigger_thread() +{ + self endon( "death" ); + self.m_claw_damage_trigger endon( "death" ); + while ( 1 ) + { + self.m_claw_damage_trigger waittill( "damage", amount, inflictor, direction, point, type, tagname, modelname, partname, weaponname, idflags ); + while ( self.m_claw islinkedto( self ) ) + { + continue; + } + if ( is_player_valid( inflictor ) ) + { + self dodamage( 1, inflictor.origin, inflictor, inflictor, "left_hand", type ); + self.m_claw setcandamage( 0 ); + self notify( "claw_damaged" ); + } + } +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz_dev.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz_dev.gsc new file mode 100644 index 0000000..fc5e842 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz_dev.gsc @@ -0,0 +1,505 @@ +#include maps/mp/animscripts/zm_shared; +#include maps/mp/zombies/_zm_ai_mechz; +#include maps/mp/animscripts/zm_utility; +#include maps/mp/zombies/_zm_net; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +#using_animtree( "mechz_claw" ); + +mechz_debug() +{ +/# + while ( 1 ) + { + debug_level = getDvarInt( #"E7121222" ); + while ( isDefined( debug_level ) && debug_level ) + { + while ( debug_level == 1 ) + { + mechz_array = getentarray( "mechz_zombie_ai" ); + i = 0; + while ( i < mechz_array.size ) + { + if ( isDefined( mechz_array[ i ].goal_pos ) ) + { + debugstar( mechz_array[ i ].goal_pos, ( 0, 0, 1 ), 1 ); + line( mechz_array[ i ].goal_pos, mechz_array[ i ].origin, ( 0, 0, 1 ), 0, 1 ); + } + i++; + } + } + } +#/ + } +} + +setup_devgui() +{ +/# + setdvar( "spawn_Mechz", "off" ); + setdvar( "force_mechz_jump", "off" ); + setdvar( "test_mechz_tank", "off" ); + setdvar( "test_mechz_robot", "off" ); + setdvar( "reset_mechz_thinking", "off" ); + setdvar( "test_mechz_sprint", "off" ); + setdvar( "mechz_force_behavior", "none" ); + setdvarint( "mechz_behavior_orient", 0 ); + setdvarint( "mechz_behavior_dist", 300 ); + adddebugcommand( "devgui_cmd "Zombies/Zombie Spawning:2/Spawn Zombie:1/Mech Zombie:1" "spawn_Mechz on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Force Behavior:1/Jump In:1" "mechz_force_behavior jump_in"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Force Behavior:1/Jump Out:2" "mechz_force_behavior jump_out"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Force Behavior:1/Flamethrower:3" "mechz_force_behavior flamethrower"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Force Behavior:1/Damage Armor:4" "mechz_force_behavior damage_armor"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Force Behavior:1/Damage Faceplate:5" "mechz_force_behavior damage_faceplate"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Force Behavior:1/Claw Attack:5" "mechz_force_behavior claw_attack"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Force Behavior:1/Melee:6" "mechz_force_behavior melee"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Force Behavior:1/Angles:7/zero degrees:1" "mechz_behavior_orient 0"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Force Behavior:1/Angles:7/forty-five degrees:2" "mechz_behavior_orient 45"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Force Behavior:1/Angles:7/ninety degrees:3" "mechz_behavior_orient 90"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Force Behavior:1/Angles:7/one thirty five degrees:4" "mechz_behavior_orient 135"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Force Behavior:1/Angles:7/one eighty degrees:5" "mechz_behavior_orient 180"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Force Behavior:1/Angles:7/two twenty five degrees:6" "mechz_behavior_orient 225"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Force Behavior:1/Angles:7/two seventy degrees:7" "mechz_behavior_orient 270"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Force Behavior:1/Angles:7/three fifteen degrees:8" "mechz_behavior_orient 315"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Force Behavior:1/Distance:8/one hundred:1" "mechz_behavior_dist 100"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Force Behavior:1/Distance:8/two hundred:2" "mechz_behavior_dist 200"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Force Behavior:1/Distance:8/three hundred:3" "mechz_behavior_dist 300"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Force Behavior:1/Distance:8/four hundred:4" "mechz_behavior_dist 400"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Force Behavior:1/Distance:8/five hundred:5" "mechz_behavior_dist 500"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Test Tank Knockdown:2" "test_mechz_tank on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Test Robot Knockdown:3" "test_mechz_robot on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Test Sprint:4" "test_mechz_sprint on"\n" ); + adddebugcommand( "devgui_cmd "Zombies/MechZ:3/Reset Mech:5" "reset_mechz_thinking on"\n" ); + level thread watch_devgui_mechz(); +#/ +} + +watch_devgui_mechz() +{ +/# + while ( 1 ) + { + if ( getDvar( "spawn_Mechz" ) == "on" ) + { + mechz_health_increases(); + level.mechz_left_to_spawn = 1; + if ( getDvarInt( "zombie_cheat" ) >= 2 ) + { + level.round_number++; + } + level notify( "spawn_mechz" ); + setdvar( "spawn_Mechz", "off" ); + level.mechz_last_spawn_round = 0; + } + if ( getDvar( "mechz_force_behavior" ) != "none" ) + { + behavior = getDvar( "mechz_force_behavior" ); + zombies = getaiarray( "axis" ); + i = 0; + while ( i < zombies.size ) + { + if ( isDefined( zombies[ i ].is_mechz ) && zombies[ i ].is_mechz ) + { + zombies[ i ] thread mechz_force_behavior( behavior ); + } + i++; + } + setdvar( "mechz_force_behavior", "none" ); + } + if ( getDvar( "test_mechz_tank" ) == "on" ) + { + setdvar( "test_mechz_tank", "off" ); + mechz = undefined; + zombies = getaiarray( "axis" ); + i = 0; + while ( i < zombies.size ) + { + if ( isDefined( zombies[ i ].is_mechz ) && zombies[ i ].is_mechz ) + { + mechz = zombies[ i ]; + } + i++; + } + while ( !isDefined( mechz ) ) + { + continue; + } + mechz.not_interruptable = 1; + mechz mechz_stop_basic_find_flesh(); + mechz.ai_state = "devgui"; + mechz.goal_pos = ( 446, -4318, 200 ); + mechz setgoalpos( mechz.goal_pos ); + } + if ( getDvar( "test_mechz_robot" ) == "on" ) + { + setdvar( "test_mechz_robot", "off" ); + mechz = undefined; + zombies = getaiarray( "axis" ); + i = 0; + while ( i < zombies.size ) + { + if ( isDefined( zombies[ i ].is_mechz ) && zombies[ i ].is_mechz ) + { + mechz = zombies[ i ]; + } + i++; + } + while ( !isDefined( mechz ) ) + { + continue; + } + mechz.not_interruptable = 1; + mechz mechz_stop_basic_find_flesh(); + mechz.ai_state = "devgui"; + mechz.goal_pos = ( 1657, -336, 92 ); + mechz setgoalpos( mechz.goal_pos ); + } + while ( getDvar( "test_mechz_sprint" ) == "on" ) + { + setdvar( "test_mechz_sprint", "off" ); + zombies = getaiarray( "axis" ); + i = 0; + while ( i < zombies.size ) + { + if ( isDefined( zombies[ i ].is_mechz ) && zombies[ i ].is_mechz ) + { + zombies[ i ].force_sprint = 1; + } + i++; + } + } + while ( getDvar( "reset_mechz_thinking" ) == "on" ) + { + setdvar( "reset_mechz_thinking", "off" ); + zombies = getaiarray( "axis" ); + i = 0; + while ( i < zombies.size ) + { + if ( isDefined( zombies[ i ].is_mechz ) && zombies[ i ].is_mechz ) + { + zombies[ i ].not_interruptable = 0; + zombies[ i ].force_sprint = 0; + } + i++; + } + } + wait 0,1; +#/ + } +} + +mechz_force_behavior( behavior ) +{ +/# + self notify( "kill_force_behavior" ); + self thread mechz_stop_basic_find_flesh(); + self.ignoreall = 1; + self.force_behavior = 1; + if ( behavior == "jump_in" ) + { + self thread mechz_force_jump_in(); + } + if ( behavior == "jump_out" ) + { + self thread mechz_force_jump_out(); + } + if ( behavior == "flamethrower" ) + { + self thread mechz_force_flamethrower(); + } + if ( behavior == "claw_attack" ) + { + self thread mechz_force_claw_attack(); + } + if ( behavior == "damage_armor" ) + { + self thread mechz_force_damage_armor(); + } + if ( behavior == "damage_faceplate" ) + { + self thread mechz_force_damage_faceplate(); + } + if ( behavior == "melee" ) + { + self thread mechz_force_melee(); + } + if ( behavior == "none" ) + { + self.ignoreall = 0; + self.force_behavior = 0; + self notify( "kill_force_behavior" ); +#/ + } +} + +get_behavior_orient() +{ +/# + behavior_orient = getDvarInt( #"2F660A7B" ); + return level.players[ 0 ].angles + vectorScale( ( 0, 0, 1 ), 180 ) + ( 0, behavior_orient, 0 ); +#/ +} + +setup_force_behavior() +{ +/# + if ( !isDefined( level.test_align_struct ) ) + { + player = get_players()[ 0 ]; + pos = player.origin; + offset = anglesToForward( player.angles ); + offset = vectornormalize( offset ); + level.test_align_struct = spawn( "script_model", pos + ( 300 * offset ) ); + level.test_align_struct setmodel( "tag_origin" ); + level.test_align_struct.angles = player.angles + vectorScale( ( 0, 0, 1 ), 180 ); + level.test_align_struct thread align_test_struct(); + level.test_align_struct.angles = player.angles + vectorScale( ( 0, 0, 1 ), 180 ); + } + self linkto( level.test_align_struct, "tag_origin", ( 0, 0, 1 ), ( 0, 0, 1 ) ); + self.fx_field &= 64; + self.fx_field &= 128; + self.fx_field &= 256; +#/ +} + +align_test_struct() +{ +/# + while ( 1 ) + { + pos = level.players[ 0 ].origin; + offset = anglesToForward( level.players[ 0 ].angles ); + offset = vectornormalize( offset ); + dist = getDvarInt( #"6DCD047E" ); + level.test_align_struct.origin = pos + ( dist * offset ); + level.test_align_struct.angles = get_behavior_orient(); + wait 0,05; +#/ + } +} + +scripted_behavior( anim_scripted_name, notify_name ) +{ +/# + self animscripted( level.test_align_struct.origin, level.test_align_struct.angles, anim_scripted_name ); + self maps/mp/animscripts/zm_shared::donotetracks( notify_name ); +#/ +} + +mechz_force_jump_in() +{ +/# + self endon( "kill_force_behavior" ); + self setup_force_behavior(); + while ( 1 ) + { + self animscripted( self.origin, self.angles, "zm_idle" ); + wait 0,2; + self scripted_behavior( "zm_spawn", "jump_anim" ); +#/ + } +} + +mechz_force_jump_out() +{ +/# + self endon( "kill_force_behavior" ); + self setup_force_behavior(); + while ( 1 ) + { + self animscripted( self.origin, self.angles, "zm_idle" ); + wait 0,2; + self scripted_behavior( "zm_fly_out", "jump_anim" ); + self ghost(); + self animscripted( self.origin, self.angles, "zm_fly_hover" ); + wait level.mechz_jump_delay; + self show(); + self scripted_behavior( "zm_fly_in", "jump_anim" ); +#/ + } +} + +mechz_force_flamethrower() +{ +/# + self endon( "kill_force_behavior" ); + self setup_force_behavior(); + curr_aim_anim = 1; + curr_timer = 0; + self animscripted( self.origin, self.angles, "zm_idle" ); + wait 0,2; + self scripted_behavior( "zm_flamethrower_aim_start", "flamethrower_anim" ); + while ( 1 ) + { + if ( curr_timer > 3 ) + { + curr_aim_anim++; + curr_timer = 0; + if ( curr_aim_anim < 10 ) + { + iprintln( "Testing aim_" + curr_aim_anim ); + } + } + if ( curr_aim_anim >= 10 ) + { + iprintln( "Testing flamethrower sweep" ); + curr_aim_anim = 1; + self scripted_behavior( "zm_flamethrower_sweep", "flamethrower_anim" ); + self.fx_field |= 64; + self setclientfield( "mechz_fx", self.fx_field ); + continue; + } + else + { + length = self getanimlengthfromasd( "zm_flamethrower_aim_" + curr_aim_anim, 0 ); + self clearanim( %root, 0 ); + self scripted_behavior( "zm_flamethrower_aim_" + curr_aim_anim, "flamethrower_anim" ); + curr_timer += length; + } +#/ + } +} + +fake_launch_claw() +{ +/# + self.launching_claw = 1; + v_claw_origin = self gettagorigin( "tag_claw" ); + v_claw_angles = vectorToAngle( self.origin - level.players[ 0 ].origin ); + self.fx_field |= 256; + self setclientfield( "mechz_fx", self.fx_field ); + self.m_claw setanim( %ai_zombie_mech_grapple_arm_open_idle, 1, 0, 1 ); + self.m_claw unlink(); + self.m_claw.fx_ent = spawn( "script_model", self.m_claw gettagorigin( "tag_claw" ) ); + self.m_claw.fx_ent.angles = self.m_claw gettagangles( "tag_claw" ); + self.m_claw.fx_ent setmodel( "tag_origin" ); + self.m_claw.fx_ent linkto( self.m_claw, "tag_claw" ); + network_safe_play_fx_on_tag( "mech_claw", 1, level._effect[ "mechz_claw" ], self.m_claw.fx_ent, "tag_origin" ); + self.m_claw clearanim( %root, 0,2 ); + self.m_claw setanim( %ai_zombie_mech_grapple_arm_open_idle, 1, 0,2, 1 ); + offset = anglesToForward( self.angles ); + offset = vectornormalize( offset ); + target_pos = self.origin + ( offset * 500 ) + vectorScale( ( 0, 0, 1 ), 36 ); + n_time = 0,08333334; + self.m_claw moveto( target_pos, n_time ); + self.m_claw waittill( "movedone" ); + self.m_claw clearanim( %root, 0,2 ); + self.m_claw setanim( %ai_zombie_mech_grapple_arm_closed_idle, 1, 0,2, 1 ); + wait 0,5; + self.m_claw moveto( v_claw_origin, 0,5 ); + self.m_claw waittill( "movedone" ); + self.m_claw.fx_ent delete(); + self.fx_field &= 256; + self setclientfield( "mechz_fx", self.fx_field ); + v_claw_origin = self gettagorigin( "tag_claw" ); + v_claw_angles = self gettagangles( "tag_claw" ); + self.m_claw.origin = v_claw_origin; + self.m_claw.angles = v_claw_angles; + self.m_claw linkto( self, "tag_claw" ); + self.launching_claw = 0; +#/ +} + +mechz_force_claw_attack() +{ +/# + self endon( "kill_force_behavior" ); + self setup_force_behavior(); + while ( 1 ) + { + self animscripted( self.origin, self.angles, "zm_idle" ); + wait 0,2; + self scripted_behavior( "zm_grapple_aim_start", "grapple_anim" ); + self thread fake_launch_claw(); + while ( isDefined( self.launching_claw ) && self.launching_claw ) + { + self clearanim( %root, 0 ); + wait 0,05; + self scripted_behavior( "zm_grapple_aim_5", "grapple_anim" ); + } + self scripted_behavior( "zm_flamethrower_claw_victim", "flamethrower_anim" ); +#/ + } +} + +mechz_force_damage_armor() +{ +/# + self endon( "kill_force_behavior" ); + self setup_force_behavior(); + if ( !isDefined( self.next_armor_piece ) ) + { + self.next_armor_piece = 0; + } + self thread scripted_behavior( "zm_idle", "idle_anim" ); + if ( self.next_armor_piece == self.armor_state.size ) + { + self.next_armor_piece = 0; + i = 0; + while ( i < self.armor_state.size ) + { + self.fx_field &= 1 << self.armor_state[ i ].index; + if ( isDefined( self.armor_state[ i ].model ) ) + { + self attach( self.armor_state[ i ].model, self.armor_state[ i ].tag ); + } + i++; + } + } + else self.fx_field |= 1 << self.armor_state[ self.next_armor_piece ].index; + if ( isDefined( self.armor_state[ self.next_armor_piece ].model ) ) + { + self detach( self.armor_state[ self.next_armor_piece ].model, self.armor_state[ self.next_armor_piece ].tag ); + } + self.next_armor_piece++; + self setclientfield( "mechz_fx", self.fx_field ); + while ( 1 ) + { + self scripted_behavior( "zm_idle", "idle_anim" ); +#/ + } +} + +mechz_force_damage_faceplate() +{ +/# + self endon( "kill_force_behavior" ); + self setup_force_behavior(); + self thread scripted_behavior( "zm_idle", "idle_anim" ); + if ( isDefined( self.has_helmet ) && self.has_helmet ) + { + self.has_helmet = 0; + self detach( "c_zom_mech_faceplate", "J_Helmet" ); + self.fx_field |= 1024; + self.fx_field &= 2048; + } + else + { + self.has_helmet = 1; + self.fx_field &= 1024; + self.fx_field |= 2048; + self attach( "c_zom_mech_faceplate", "J_Helmet" ); + } + self setclientfield( "mechz_fx", self.fx_field ); + while ( 1 ) + { + self scripted_behavior( "zm_idle", "idle_anim" ); +#/ + } +} + +mechz_force_melee() +{ +/# + self endon( "kill_force_behavior" ); + self setup_force_behavior(); + while ( 1 ) + { + self animscripted( self.origin, self.angles, "zm_idle" ); + wait 0,2; + self scripted_behavior( "zm_melee_stand", "melee_anim" ); +#/ + } +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz_ffotd.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz_ffotd.gsc new file mode 100644 index 0000000..8970ad3 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz_ffotd.gsc @@ -0,0 +1,33 @@ +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +mechz_init_start() +{ +} + +mechz_init_end() +{ +} + +spawn_start() +{ + self.not_interruptable = 1; +} + +spawn_end() +{ + self.not_interruptable = 0; +} + +mechz_round_tracker_start() +{ +} + +mechz_round_tracker_loop_start() +{ +} + +mechz_round_tracker_loop_end() +{ +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz_ft.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz_ft.gsc new file mode 100644 index 0000000..5910bb0 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_ai_mechz_ft.gsc @@ -0,0 +1,589 @@ +#include maps/mp/_visionset_mgr; +#include maps/mp/animscripts/zm_shared; +#include maps/mp/zombies/_zm_ai_mechz; +#include maps/mp/zombies/_zm_ai_mechz_dev; +#include maps/mp/zm_tomb_tank; +#include maps/mp/animscripts/zm_utility; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/zombies/_zm_net; +#include maps/mp/_utility; +#include common_scripts/utility; +#include maps/mp/zombies/_zm_zonemgr; + +#using_animtree( "mechz_claw" ); + +init_flamethrower_triggers() +{ + flag_wait( "initial_players_connected" ); + level.flamethrower_trigger_array = getentarray( "flamethrower_trigger", "script_noteworthy" ); +/# + if ( isDefined( level.flamethrower_trigger_array ) ) + { + assert( level.flamethrower_trigger_array.size >= 4 ); + } +#/ + i = 0; + while ( i < level.flamethrower_trigger_array.size ) + { + level.flamethrower_trigger_array[ i ] enablelinkto(); + i++; + } +} + +mechz_flamethrower_initial_setup() +{ + self endon( "death" ); + if ( isDefined( self.flamethrower_trigger ) ) + { + self release_flamethrower_trigger(); + } + self.flamethrower_trigger = get_flamethrower_trigger(); + if ( !isDefined( self.flamethrower_trigger ) ) + { +/# + println( "Error: No free flamethrower triggers! Make sure you haven't spawned more than 4 mech zombies" ); +#/ + return; + } + self.flamethrower_trigger.origin = self gettagorigin( "tag_flamethrower_FX" ); + self.flamethrower_trigger.angles = self gettagangles( "tag_flamethrower_FX" ); + self.flamethrower_trigger linkto( self, "tag_flamethrower_FX" ); + self thread mechz_watch_for_flamethrower_damage(); +} + +get_flamethrower_trigger() +{ + i = 0; + while ( i < level.flamethrower_trigger_array.size ) + { + if ( isDefined( level.flamethrower_trigger_array[ i ].in_use ) && !level.flamethrower_trigger_array[ i ].in_use ) + { + level.flamethrower_trigger_array[ i ].in_use = 1; + level.flamethrower_trigger_array[ i ].original_position = level.flamethrower_trigger_array[ i ].origin; + return level.flamethrower_trigger_array[ i ]; + } + i++; + } + return undefined; +} + +release_flamethrower_trigger() +{ + if ( !isDefined( self.flamethrower_trigger ) ) + { + return; + } + self.flamethrower_trigger.in_use = 0; + self.flamethrower_trigger unlink(); + self.flamethrower_trigger.origin = self.flamethrower_trigger.original_position; + self.flamethrower_linked = 0; + self.flamethrower_trigger = undefined; +} + +mechz_flamethrower_dist_watcher() +{ + self endon( "kill_ft" ); + wait 0,5; + while ( 1 ) + { + if ( isDefined( self.favoriteenemy ) || !is_player_valid( self.favoriteenemy, 1, 1 ) && distancesquared( self.origin, self.favoriteenemy.origin ) > 50000 ) + { + self notify( "stop_ft" ); + return; + } + wait 0,05; + } +} + +mechz_flamethrower_arc_watcher() +{ + self endon( "death" ); + self endon( "kill_ft" ); + self endon( "stop_ft" ); + aim_anim = undefined; + while ( 1 ) + { + old_anim = aim_anim; + aim_anim = mechz_get_aim_anim( "zm_flamethrower", self.favoriteenemy.origin, 26 ); + self.curr_aim_anim = aim_anim; + if ( !isDefined( aim_anim ) ) + { + self notify( "stop_ft" ); + return; + } + if ( !isDefined( old_anim ) || old_anim != aim_anim ) + { + self notify( "arc_change" ); + } + wait 0,05; + } +} + +mechz_play_flamethrower_aim() +{ + self endon( "death" ); + self endon( "kill_ft" ); + self endon( "stop_ft" ); + self endon( "arc_change" ); + if ( isDefined( self.curr_aim_anim ) ) + { + self stopanimscripted(); + self animscripted( self.origin, self.angles, self.curr_aim_anim ); + self maps/mp/animscripts/zm_shared::donotetracks( "flamethrower_anim" ); + } + else + { + wait 0,05; + } +} + +mechz_flamethrower_aim() +{ + self endon( "death" ); + self endon( "kill_ft" ); + self endon( "stop_ft" ); + self waittillmatch( "flamethrower_anim" ); + return "end"; + self thread mechz_flamethrower_dist_watcher(); + self thread mechz_flamethrower_arc_watcher(); + aim_anim = undefined; + while ( 1 ) + { + self mechz_play_flamethrower_aim(); + } +} + +mechz_flamethrower_tank_sweep() +{ + self endon( "death" ); + self endon( "kill_ft" ); + self endon( "stop_ft" ); + while ( 1 ) + { + self stopanimscripted(); + self.angles = vectorToAngle( level.vh_tank.origin - self.origin ); + self animscripted( self.origin, self.angles, "zm_flamethrower_sweep_up" ); + self maps/mp/animscripts/zm_shared::donotetracks( "flamethrower_anim" ); + if ( level.vh_tank ent_flag( "tank_moving" ) ) + { + break; + } + else a_players_on_tank = get_players_on_tank( 1 ); + if ( !a_players_on_tank.size ) + { + break; + } + else + { + } + } + self notify( "stop_ft" ); +} + +mechz_stop_firing_watcher() +{ + self endon( "death" ); + self endon( "kill_ft" ); + self endon( "flamethrower_complete" ); + self waittillmatch( "flamethrower_anim" ); + return "stop_ft"; + self.firing = 0; +} + +mechz_watch_for_flamethrower_damage() +{ + self endon( "death" ); + while ( 1 ) + { + self waittillmatch( "flamethrower_anim" ); + return "start_ft"; + self.firing = 1; + self thread mechz_stop_firing_watcher(); + while ( isDefined( self.firing ) && self.firing ) + { + if ( isDefined( self.doing_tank_sweep ) && self.doing_tank_sweep ) + { + do_tank_sweep_auto_damage = !level.vh_tank ent_flag( "tank_moving" ); + } + players = getplayers(); + i = 0; + while ( i < players.size ) + { + if ( isDefined( players[ i ].is_burning ) && !players[ i ].is_burning ) + { + if ( do_tank_sweep_auto_damage || players[ i ] entity_on_tank() && players[ i ] istouching( self.flamethrower_trigger ) ) + { + players[ i ] thread player_flame_damage(); + } + } + i++; + } + zombies = getaispeciesarray( "axis", "all" ); + i = 0; + while ( i < zombies.size ) + { + if ( isDefined( zombies[ i ].is_mechz ) && zombies[ i ].is_mechz ) + { + i++; + continue; + } + else + { + if ( isDefined( zombies[ i ].on_fire ) && zombies[ i ].on_fire ) + { + i++; + continue; + } + else + { + if ( do_tank_sweep_auto_damage || zombies[ i ] entity_on_tank() && zombies[ i ] istouching( self.flamethrower_trigger ) ) + { + zombies[ i ].on_fire = 1; + zombies[ i ] promote_to_explosive(); + } + } + } + i++; + } + wait 0,1; + } + } +} + +player_flame_damage() +{ + self endon( "zombified" ); + self endon( "death" ); + self endon( "disconnect" ); + n_player_dmg = 30; + n_jugga_dmg = 45; + n_burn_time = 1,5; + if ( isDefined( self.is_zombie ) && self.is_zombie ) + { + return; + } + self thread player_stop_burning(); + if ( !isDefined( self.is_burning ) && is_player_valid( self, 1, 0 ) ) + { + self.is_burning = 1; + maps/mp/_visionset_mgr::vsmgr_activate( "overlay", "zm_transit_burn", self, n_burn_time, level.zm_transit_burn_max_duration ); + self notify( "burned" ); + if ( !self hasperk( "specialty_armorvest" ) ) + { + self dodamage( n_player_dmg, self.origin ); + } + else + { + self dodamage( n_jugga_dmg, self.origin ); + } + wait 0,5; + self.is_burning = undefined; + } +} + +player_stop_burning() +{ + self notify( "player_stop_burning" ); + self endon( "player_stop_burning" ); + self endon( "death_or_disconnect" ); + self waittill( "zombified" ); + self notify( "stop_flame_damage" ); + maps/mp/_visionset_mgr::vsmgr_deactivate( "overlay", "zm_transit_burn", self ); +} + +zombie_burning_fx() +{ + self endon( "death" ); + self endon( "stop_flame_damage" ); + while ( 1 ) + { + if ( isDefined( level._effect ) && isDefined( level._effect[ "character_fire_death_torso" ] ) ) + { + if ( !self.isdog ) + { + playfxontag( level._effect[ "character_fire_death_torso" ], self, "J_SpineLower" ); + } + } + if ( isDefined( level._effect ) && isDefined( level._effect[ "character_fire_death_sm" ] ) ) + { + wait 1; + tagarray = []; + if ( randomint( 2 ) == 0 ) + { + tagarray[ 0 ] = "J_Elbow_LE"; + tagarray[ 1 ] = "J_Elbow_RI"; + tagarray[ 2 ] = "J_HEAD"; + } + else + { + tagarray[ 0 ] = "J_Wrist_RI"; + tagarray[ 1 ] = "J_Wrist_LE"; + tagarray[ 2 ] = "J_HEAD"; + } + tagarray = array_randomize( tagarray ); + self thread network_safe_play_fx_on_tag( "flamethrower", 2, level._effect[ "character_fire_death_sm" ], self, tagarray[ 0 ] ); + } + wait 12; + } +} + +zombie_burning_audio() +{ + self playloopsound( "zmb_fire_loop" ); + self waittill_any( "death", "stop_flame_damage" ); + if ( isDefined( self ) && isalive( self ) ) + { + self stoploopsound( 0,25 ); + } +} + +zombie_burning_dmg() +{ + self endon( "death" ); + self endon( "stop_flame_damage" ); + damageradius = 25; + damage = 2; + while ( 1 ) + { + eyeorigin = self geteye(); + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( is_player_valid( players[ i ], 1, 0 ) ) + { + playereye = players[ i ] geteye(); + if ( distancesquared( eyeorigin, playereye ) < ( damageradius * damageradius ) ) + { + players[ i ] dodamage( damage, self.origin, self ); + players[ i ] notify( "burned" ); + } + } + i++; + } + wait 1; + } +} + +promote_to_explosive() +{ + self endon( "death" ); + self thread zombie_burning_audio(); + self thread zombie_burning_fx(); + self thread explode_on_death(); + self thread zombie_burning_dmg(); + self thread on_fire_timeout(); +} + +explode_on_death() +{ + self endon( "stop_flame_damage" ); + self waittill( "death" ); + if ( !isDefined( self ) ) + { + return; + } + tag = "J_SpineLower"; + if ( isDefined( self.animname ) && self.animname == "zombie_dog" ) + { + tag = "tag_origin"; + } + if ( is_mature() ) + { + if ( isDefined( level._effect[ "zomb_gib" ] ) ) + { + playfx( level._effect[ "zomb_gib" ], self gettagorigin( tag ) ); + } + } + else + { + if ( isDefined( level._effect[ "spawn_cloud" ] ) ) + { + playfx( level._effect[ "spawn_cloud" ], self gettagorigin( tag ) ); + } + } + self radiusdamage( self.origin, 128, 30, 15, undefined, "MOD_EXPLOSIVE" ); + self ghost(); + if ( isDefined( self.isdog ) && self.isdog ) + { + self hide(); + } + else + { + self delay_thread( 1, ::self_delete ); + } +} + +on_fire_timeout() +{ + self endon( "death" ); + wait 12; + if ( isDefined( self ) && isalive( self ) ) + { + self.is_on_fire = 0; + self notify( "stop_flame_damage" ); + } +} + +should_do_flamethrower_attack() +{ +/# + assert( isDefined( self.favoriteenemy ) ); +#/ +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\tMZ: Checking should flame\n" ); +#/ + } + if ( isDefined( self.disable_complex_behaviors ) && self.disable_complex_behaviors ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\t\tMZ: Not doing flamethrower because doing force aggro\n" ); +#/ + } + return 0; + } + if ( isDefined( self.not_interruptable ) && self.not_interruptable ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\t\tMZ: Not doing flamethrower because another behavior has set not_interruptable\n" ); +#/ + } + return 0; + } + if ( !self mechz_check_in_arc( 26 ) ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\t\tMZ: Not doing flamethrower because target is not in front arc\n" ); +#/ + } + return 0; + } + if ( isDefined( self.last_flamethrower_time ) && ( getTime() - self.last_flamethrower_time ) < level.mechz_flamethrower_cooldown_time ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\t\tMZ: Not doing flamethrower because it is still on cooldown\n" ); +#/ + } + return 0; + } + n_dist_sq = distancesquared( self.origin, self.favoriteenemy.origin ); + if ( n_dist_sq < 10000 || n_dist_sq > 50000 ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\t\tMZ: Not doing flamethrower because target is not in range\n" ); +#/ + } + return 0; + } + b_cansee = bullettracepassed( self.origin + vectorScale( ( 0, 0, 1 ), 36 ), self.favoriteenemy.origin + vectorScale( ( 0, 0, 1 ), 36 ), 0, undefined ); + if ( !b_cansee ) + { +/# + if ( getDvarInt( #"E7121222" ) > 1 ) + { + println( "\n\t\tMZ: Not doing flamethrower because cannot see target\n" ); +#/ + } + return 0; + } + return 1; +} + +mechz_do_flamethrower_attack( tank_sweep ) +{ + self endon( "death" ); + self endon( "kill_ft" ); +/# + if ( getDvarInt( #"E7121222" ) > 0 ) + { + println( "\n\tMZ: Doing Flamethrower Attack\n" ); +#/ + } + self thread mechz_stop_basic_find_flesh(); + self.ai_state = "flamethrower_attack"; + self setgoalpos( self.origin ); + self clearanim( %root, 0,2 ); + self.last_flamethrower_time = getTime(); + self thread mechz_kill_flamethrower_watcher(); + if ( !isDefined( self.flamethrower_trigger ) ) + { + self mechz_flamethrower_initial_setup(); + } + n_nearby_enemies = 0; + a_players = getplayers(); + _a628 = a_players; + _k628 = getFirstArrayKey( _a628 ); + while ( isDefined( _k628 ) ) + { + player = _a628[ _k628 ]; + if ( distance2dsquared( player.origin, self.favoriteenemy.origin ) < 10000 ) + { + n_nearby_enemies++; + } + _k628 = getNextArrayKey( _a628, _k628 ); + } + if ( isDefined( tank_sweep ) && tank_sweep ) + { + self.doing_tank_sweep = 1; + self thread mechz_flamethrower_tank_sweep(); + } + else + { + if ( randomint( 100 ) < level.mechz_ft_sweep_chance && n_nearby_enemies > 1 ) + { + self.doing_ft_sweep = 1; + self animscripted( self.origin, self.angles, "zm_flamethrower_sweep" ); + self maps/mp/animscripts/zm_shared::donotetracks( "flamethrower_anim" ); + } + else + { + self animscripted( self.origin, self.angles, "zm_flamethrower_aim_start" ); + self thread mechz_flamethrower_aim(); + self maps/mp/animscripts/zm_shared::donotetracks( "flamethrower_anim" ); + } + } + self orientmode( "face default" ); + if ( isDefined( self.doing_ft_sweep ) && self.doing_ft_sweep ) + { + self.doing_ft_sweep = 0; + } + else + { + self.cant_melee = 1; + self waittill( "stop_ft" ); + self mechz_flamethrower_cleanup(); + wait 0,5; + self stopanimscripted(); + return; + } + self mechz_flamethrower_cleanup(); +} + +mechz_kill_flamethrower_watcher() +{ + self endon( "flamethrower_complete" ); + self waittill_either( "kill_ft", "death" ); + self mechz_flamethrower_cleanup(); +} + +mechz_flamethrower_cleanup() +{ + self.fx_field &= 64; + self setclientfield( "mechz_fx", self.fx_field ); + self.firing = 0; + self.doing_tank_sweep = 0; + self.cant_melee = 0; + self notify( "flamethrower_complete" ); +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_ai_quadrotor.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_ai_quadrotor.gsc new file mode 100644 index 0000000..2c2135b --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_ai_quadrotor.gsc @@ -0,0 +1,1264 @@ +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/zm_tomb_vo; +#include maps/mp/zombies/_zm_equipment; +#include maps/_vehicle; +#include maps/_quadrotor; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; +#include animscripts/utility; + +precache() +{ + precachemodel( "veh_t6_dlc_zm_quadrotor" ); + precachevehicle( "heli_quadrotor_zm" ); + precachevehicle( "heli_quadrotor_upgraded_zm" ); +} + +init() +{ + level._effect[ "quadrotor_nudge" ] = loadfx( "destructibles/fx_quadrotor_nudge01" ); + level._effect[ "qd_revive" ] = loadfx( "maps/zombie_tomb/fx_tomb_veh_quadrotor_revive_health" ); + maps/mp/zombies/_zm_equipment::register_equipment( "equip_dieseldrone_zm", &"ZM_TOMB_DIHS", &"ZM_TOMB_DIHO", "riotshield_zm_icon", "riotshield" ); +} + +quadrotor_dealt_no_damage_to_player( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime ) +{ + if ( isDefined( sweapon ) && sweapon == "quadrotorturret_zm" ) + { + return 0; + } + return idamage; +} + +quadrotor_think() +{ + self enableaimassist(); + self sethoverparams( 5, 60, 40 ); + self setneargoalnotifydist( 64 ); + self.flyheight = 128; + self setvehicleavoidance( 1 ); + self.vehfovcosine = 0; + self.vehfovcosinebusy = 0,574; + self.vehaircraftcollisionenabled = 1; + if ( !isDefined( self.goalradius ) ) + { + self.goalradius = 128; + } + if ( !isDefined( self.goalpos ) ) + { + self.goalpos = self.origin; + } + self thread quadrotor_death(); + self thread quadrotor_damage(); + quadrotor_start_ai(); + self thread quadrotor_set_team( "allies" ); +} + +follow_ent( e_followee ) +{ + level endon( "end_game" ); + self endon( "death" ); + while ( isDefined( e_followee ) ) + { + if ( !self.returning_home ) + { + v_facing = e_followee getplayerangles(); + v_forward = anglesToForward( ( 0, v_facing[ 1 ], 0 ) ); + candidate_goalpos = e_followee.origin + ( v_forward * 128 ); + trace_goalpos = physicstrace( self.origin, candidate_goalpos ); + if ( trace_goalpos[ "position" ] == candidate_goalpos ) + { + self.goalpos = e_followee.origin + ( v_forward * 128 ); + break; + } + else + { + self.goalpos = e_followee.origin + vectorScale( ( 0, 0, 1 ), 60 ); + } + } + wait randomfloatrange( 1, 2 ); + } +} + +quadrotor_start_ai() +{ + self.goalpos = self.origin; + self.returning_home = 0; + quadrotor_main(); +} + +quadrotor_main() +{ + self thread quadrotor_blink_lights(); + self thread quadrotor_fireupdate(); + self thread quadrotor_movementupdate(); + self thread quadrotor_collision(); + self thread quadrotor_ambient_vo(); + self thread quadrotor_watch_for_game_end(); +} + +quadrotor_ambient_vo() +{ + level endon( "end_game" ); + self endon( "death" ); + spawn_lines = []; + spawn_lines[ 0 ] = "vox_maxi_drone_standby_0"; + spawn_lines[ 1 ] = "vox_maxi_drone_hover_0"; + spawn_lines[ 2 ] = "vox_maxi_drone_holding_0"; + vox_line = spawn_lines[ randomintrange( 0, spawn_lines.size ) ]; + self thread maps/mp/zm_tomb_vo::maxissay( vox_line, self ); + current_ambient_line_cooldown = randomintrange( 10000, 30000 ); + wait current_ambient_line_cooldown; + while ( 1 ) + { + current_time = getTime(); + if ( ( current_time - self.time_last_spoke_attack_line ) > current_ambient_line_cooldown ) + { + if ( ( current_time - self.time_last_spoke_killed_line ) > current_ambient_line_cooldown ) + { + vox_line = "vox_maxi_drone_ambient_" + randomintrange( 0, 10 ) + "_0"; + self thread maps/mp/zm_tomb_vo::maxissay( vox_line, self ); + current_ambient_line_cooldown = randomintrange( 10000, 30000 ); + } + } + wait 0,1; + } +} + +quadrotor_fireupdate() +{ + level endon( "end_game" ); + self endon( "death" ); + current_time = getTime(); + self.time_last_spoke_attack_line = current_time; + self.time_last_spoke_killed_line = current_time; + current_attack_line_cooldown = 10000; + current_killed_line_cooldown = 10000; + while ( 1 ) + { + if ( isDefined( self.enemy ) && self vehcansee( self.enemy ) ) + { + dist_squared = distancesquared( self.enemy.origin, self.origin ); + if ( dist_squared < ( 384 * 384 ) && dist_squared > ( 96 * 96 ) ) + { + self setturrettargetent( self.enemy ); + current_time = getTime(); + if ( ( current_time - self.time_last_spoke_attack_line ) > current_attack_line_cooldown ) + { + vox_line = "vox_maxi_drone_attacking_" + randomintrange( 0, 3 ); + self thread maps/mp/zm_tomb_vo::maxissay( vox_line, self ); + self.time_last_spoke_attack_line = current_time; + current_attack_line_cooldown = randomintrange( 10000, 30000 ); + } + self quadrotor_fire_for_time( randomfloatrange( 1,5, 3 ) ); + } + if ( isDefined( self.enemy ) && isai( self.enemy ) ) + { + wait randomfloatrange( 0,5, 1 ); + } + else + { + current_time = getTime(); + if ( ( current_time - self.time_last_spoke_killed_line ) > current_killed_line_cooldown ) + { + vox_line = "vox_maxi_drone_killed_" + randomintrange( 0, 4 ); + self maps/mp/zm_tomb_vo::maxissay( vox_line, self ); + do_thank_maxis = randomintrange( 0, 2 ); + if ( do_thank_maxis > 0 ) + { + players = getplayers(); + player = players[ randomintrange( 0, players.size ) ]; + player thread do_player_general_vox( "quadrotor", "kill_drone", undefined, 100 ); + } + self.time_last_spoke_killed_line = current_time; + current_killed_line_cooldown = randomintrange( 10000, 30000 ); + } + wait randomfloatrange( 0,5, 1,5 ); + } + continue; + } + else + { + current_time = getTime(); + if ( ( current_time - self.time_last_spoke_attack_line ) > current_attack_line_cooldown ) + { + vox_line = "vox_maxi_drone_scan_0"; + self thread maps/mp/zm_tomb_vo::maxissay( vox_line, self ); + self.time_last_spoke_attack_line = current_time; + current_attack_line_cooldown = randomintrange( 10000, 30000 ); + } + wait 0,4; + } + } +} + +quadrotor_watch_for_game_end() +{ + self endon( "death" ); + level waittill( "end_game" ); + if ( isDefined( self ) ) + { + playfx( level._effect[ "tesla_elec_kill" ], self.origin ); + self playsound( "zmb_qrdrone_leave" ); + self delete(); +/# + iprintln( "Maxis deleted" ); +#/ + } +} + +quadrotor_check_move( position ) +{ + results = physicstrace( self.origin, position, ( -15, -15, -5 ), ( 15, 15, 5 ) ); + if ( results[ "fraction" ] == 1 ) + { + return 1; + } + return 0; +} + +quadrotor_adjust_goal_for_enemy_height( goalpos ) +{ + if ( isDefined( self.enemy ) ) + { + if ( isai( self.enemy ) ) + { + offset = 45; + } + else + { + offset = -100; + } + if ( ( self.enemy.origin[ 2 ] + offset ) > goalpos[ 2 ] ) + { + goal_z = self.enemy.origin[ 2 ] + offset; + if ( goal_z > ( goalpos[ 2 ] + 400 ) ) + { + goal_z = goalpos[ 2 ] + 400; + } + results = physicstrace( goalpos, ( goalpos[ 0 ], goalpos[ 1 ], goal_z ), ( -15, -15, -5 ), ( 15, 15, 5 ) ); + if ( results[ "fraction" ] == 1 ) + { + goalpos = ( goalpos[ 0 ], goalpos[ 1 ], goal_z ); + } + } + } + return goalpos; +} + +make_sure_goal_is_well_above_ground( pos ) +{ + start = pos + ( 0, 0, self.flyheight ); + end = pos + ( 0, 0, self.flyheight * -1 ); + trace = bullettrace( start, end, 0, self, 0, 0 ); + end = trace[ "position" ]; + pos = end + ( 0, 0, self.flyheight ); + z = self getheliheightlockheight( pos ); + pos = ( pos[ 0 ], pos[ 1 ], z ); + return pos; +} + +waittill_pathing_done() +{ + level endon( "end_game" ); + self endon( "death" ); + self endon( "change_state" ); + if ( self.vehonpath ) + { + self waittill_any( "near_goal", "reached_end_node", "force_goal" ); + } +} + +quadrotor_movementupdate() +{ + level endon( "end_game" ); + self endon( "death" ); + self endon( "change_state" ); +/# + assert( isalive( self ) ); +#/ + a_powerups = []; + old_goalpos = self.goalpos; + self.goalpos = self make_sure_goal_is_well_above_ground( self.goalpos ); + if ( !self.vehonpath ) + { + if ( isDefined( self.attachedpath ) ) + { + self script_delay(); + } + else if ( distancesquared( self.origin, self.goalpos ) < 10000 || self.goalpos[ 2 ] > ( old_goalpos[ 2 ] + 10 ) && ( self.origin[ 2 ] + 10 ) < self.goalpos[ 2 ] ) + { + self setvehgoalpos( self.goalpos, 1, 2, 0 ); + self pathvariableoffset( vectorScale( ( 0, 0, 1 ), 20 ), 2 ); + self waittill_any_or_timeout( 4, "near_goal", "force_goal" ); + } + else + { + goalpos = self quadrotor_get_closest_node(); + self setvehgoalpos( goalpos, 1, 2, 0 ); + self waittill_any_or_timeout( 2, "near_goal", "force_goal" ); + } + } +/# + assert( isalive( self ) ); +#/ + self setvehicleavoidance( 1 ); + goalfailures = 0; + for ( ;; ) + { + while ( 1 ) + { + self waittill_pathing_done(); + self thread quadrotor_blink_lights(); + if ( self.returning_home ) + { + self setneargoalnotifydist( 64 ); + self setheliheightlock( 0 ); + is_valid_exit_path_found = 0; + quadrotor_table = level.quadrotor_status.pickup_trig.model; + is_valid_exit_path_found = self setvehgoalpos( quadrotor_table.origin, 1, 2, 1 ); + while ( is_valid_exit_path_found ) + { + self notify( "attempting_return" ); + self waittill_any( "near_goal", "force_goal", "reached_end_node", "return_timeout" ); + } + self setneargoalnotifydist( 8 ); + str_zone = level.quadrotor_status.str_zone; +/# + iprintln( "EXIT ZONE: " + str_zone ); +#/ + switch( str_zone ) + { + case "zone_nml_9": + exit_path = getvehiclenode( "quadrotor_nml_exit_path", "targetname" ); + is_valid_exit_path_found = self setvehgoalpos( exit_path.origin, 1, 2, 1 ); + break; + case "zone_bunker_5a": + if ( flag( "activate_zone_nml" ) ) + { + exit_path = getvehiclenode( "quadrotor_bunker_north_exit_path", "targetname" ); + is_valid_exit_path_found = self setvehgoalpos( exit_path.origin, 1, 2, 1 ); + break; + } + if ( !is_valid_exit_path_found ) + { + if ( flag( "activate_zone_bunker_3b" ) ) + { + exit_path = getvehiclenode( "quadrotor_bunker_west_exit_path", "targetname" ); + is_valid_exit_path_found = self setvehgoalpos( exit_path.origin, 1, 2, 1 ); + break; + } + } + if ( !is_valid_exit_path_found ) + { + if ( flag( "activate_zone_bunker_4b" ) ) + { + exit_path = getvehiclenode( "quadrotor_bunker_south_exit_path", "targetname" ); + is_valid_exit_path_found = self setvehgoalpos( exit_path.origin, 1, 2, 1 ); + break; + } + } + case "zone_village_2": + } + if ( is_valid_exit_path_found ) + { + self waittill_any( "near_goal", "force_goal" ); + self cancelaimove(); + self clearvehgoalpos(); + self pathvariableoffsetclear(); + self pathfixedoffsetclear(); + self clearlookatent(); + self setvehicleavoidance( 0 ); + self.drivepath = 1; + self attachpath( exit_path ); + self pathvariableoffset( vectorScale( ( 0, 0, 1 ), 8 ), randomintrange( 1, 3 ) ); + self drivepath( exit_path ); + wait 1; + self notify( "attempting_return" ); + } + else self thread quadrotor_escape_into_air(); + self waittill_any( "near_goal", "force_goal", "reached_end_node", "return_timeout" ); + } + if ( !isDefined( self.revive_target ) ) + { + player = self player_in_last_stand_within_range( 500 ); + if ( isDefined( player ) ) + { + self.revive_target = player; + player.quadrotor_revive = 1; + vox_line = "vox_maxi_drone_revive_" + randomintrange( 0, 5 ); + maps/mp/zm_tomb_vo::maxissay( vox_line, self ); + } + } + if ( isDefined( self.revive_target ) ) + { + origin = self.revive_target.origin; + origin = ( origin[ 0 ], origin[ 1 ], origin[ 2 ] + 150 ); + z = self getheliheightlockheight( origin ); + origin = ( origin[ 0 ], origin[ 1 ], z ); + if ( self setvehgoalpos( origin, 1, 2, 1 ) ) + { + self waittill_any( "near_goal", "force_goal", "reached_end_node" ); + level thread watch_for_fail_revive( self ); + wait 1; + if ( isDefined( self.revive_target ) && self.revive_target maps/mp/zombies/_zm_laststand::player_is_in_laststand() ) + { + playfxontag( level._effect[ "staff_charge" ], self.revive_target, "tag_origin" ); + self.revive_target notify( "remote_revive" ); + self.revive_target do_player_general_vox( "quadrotor", "rspnd_drone_revive", undefined, 100 ); + self.player_owner notify( "revived_player_with_quadrotor" ); + } + self.revive_target = undefined; + self setvehgoalpos( origin, 1 ); + wait 1; + } + } + else player.quadrotor_revive = undefined; + wait 0,1; + } + a_powerups = []; + if ( level.active_powerups.size > 0 && isDefined( self.player_owner ) ) + { + a_powerups = get_array_of_closest( self.player_owner.origin, level.active_powerups, undefined, undefined, 500 ); + } + if ( a_powerups.size > 0 ) + { + b_got_powerup = 0; + _a565 = a_powerups; + _k565 = getFirstArrayKey( _a565 ); + while ( isDefined( _k565 ) ) + { + powerup = _a565[ _k565 ]; + if ( self setvehgoalpos( powerup.origin, 1, 2, 1 ) ) + { + self waittill_any( "near_goal", "force_goal", "reached_end_node" ); + if ( isDefined( powerup ) ) + { + self.player_owner.ignore_range_powerup = powerup; + b_got_powerup = 1; + } + wait 1; + break; + } + else + { + _k565 = getNextArrayKey( _a565, _k565 ); + } + } + while ( b_got_powerup ) + { + continue; + } + wait 0,1; + } + a_special_items = getentarray( "quad_special_item", "script_noteworthy" ); + if ( level.n_ee_medallions > 0 && isDefined( self.player_owner ) ) + { + e_special_item = getclosest( self.player_owner.origin, a_special_items, 500 ); + if ( isDefined( e_special_item ) ) + { + self setneargoalnotifydist( 4 ); + if ( isDefined( e_special_item.target ) ) + { + s_start_pos = getstruct( e_special_item.target, "targetname" ); + self setvehgoalpos( s_start_pos.origin, 1, 0, 1 ); + self waittill_any( "near_goal", "force_goal", "reached_end_node" ); + } + self setvehgoalpos( e_special_item.origin + vectorScale( ( 0, 0, 1 ), 30 ), 1, 0, 1 ); + self waittill_any( "near_goal", "force_goal", "reached_end_node" ); + wait 1; + playfx( level._effect[ "staff_charge" ], e_special_item.origin ); + e_special_item hide(); + level.n_ee_medallions--; + + level notify( "quadrotor_medallion_found" ); + if ( isDefined( e_special_item.target ) ) + { + s_start_pos = getstruct( e_special_item.target, "targetname" ); + self setvehgoalpos( s_start_pos.origin, 1, 0, 1 ); + self waittill_any( "near_goal", "force_goal", "reached_end_node" ); + } + if ( level.n_ee_medallions == 0 ) + { + s_mg_spawn = getstruct( "mgspawn", "targetname" ); + self setvehgoalpos( s_mg_spawn.origin + vectorScale( ( 0, 0, 1 ), 30 ), 1, 0, 1 ); + self waittill_any( "near_goal", "force_goal", "reached_end_node" ); + wait 1; + playfx( level._effect[ "staff_charge" ], s_mg_spawn.origin ); + e_special_item playsound( "zmb_perks_packa_ready" ); + flag_set( "ee_medallions_collected" ); + } + e_special_item delete(); + self setneargoalnotifydist( 30 ); + self setvehgoalpos( self.origin, 1 ); + } + } + if ( isDefined( level.quadrotor_custom_behavior ) ) + { + self [[ level.quadrotor_custom_behavior ]](); + } + goalpos = quadrotor_find_new_position(); + if ( self setvehgoalpos( goalpos, 1, 2, 1 ) ) + { + goalfailures = 0; + if ( isDefined( self.goal_node ) ) + { + self.goal_node.quadrotor_claimed = 1; + } + if ( isDefined( self.enemy ) && self vehcansee( self.enemy ) ) + { + if ( randomint( 100 ) > 50 ) + { + self setlookatent( self.enemy ); + } + } + self waittill_any_timeout( 12, "near_goal", "force_goal", "reached_end_node" ); + if ( isDefined( self.enemy ) && self vehcansee( self.enemy ) ) + { + self setlookatent( self.enemy ); + wait randomfloatrange( 1, 4 ); + self clearlookatent(); + } + if ( isDefined( self.goal_node ) ) + { + self.goal_node.quadrotor_claimed = undefined; + } + continue; + } + else + { + goalfailures++; + if ( isDefined( self.goal_node ) ) + { + self.goal_node.quadrotor_fails = 1; + } + if ( goalfailures == 1 ) + { + wait 0,5; + } + } + else if ( goalfailures == 2 ) + { + goalpos = self.origin; + } + else if ( goalfailures == 3 ) + { + goalpos = self quadrotor_get_closest_node(); + self setvehgoalpos( goalpos, 1 ); + self waittill( "near_goal" ); + } + else + { + if ( goalfailures > 3 ) + { +/# + println( "WARNING: Quadrotor can't find path to goal over 4 times." + self.origin + " " + goalpos ); + line( self.origin, goalpos, ( 0, 0, 1 ), 1, 100 ); +#/ + self.goalpos = make_sure_goal_is_well_above_ground( goalpos ); + } + } + old_goalpos = goalpos; + offset = ( randomfloatrange( -50, 50 ), randomfloatrange( -50, 50 ), randomfloatrange( 50, 150 ) ); + goalpos += offset; + goalpos = quadrotor_adjust_goal_for_enemy_height( goalpos ); + if ( self quadrotor_check_move( goalpos ) ) + { + self setvehgoalpos( goalpos, 1 ); + self waittill_any( "near_goal", "force_goal", "start_vehiclepath" ); + wait randomfloatrange( 1, 3 ); + if ( !self.vehonpath ) + { + self setvehgoalpos( old_goalpos, 1 ); + self waittill_any( "near_goal", "force_goal", "start_vehiclepath" ); + } + } + wait 0,5; + } + } + } +} + +quadrotor_escape_into_air() +{ +/# + iprintln( "couldn't path to exit" ); +#/ + self.goalpos = self.origin + vectorScale( ( 0, 0, 1 ), 2048 ); + can_path_straight_up = self setvehgoalpos( self.goalpos, 1, 0, 1 ); + trace_goalpos = physicstrace( self.origin, self.goalpos ); + if ( can_path_straight_up && trace_goalpos[ "position" ] == self.goalpos ) + { +/# + iprintln( "I can go straight up" ); +#/ + self notify( "attempting_return" ); + } + else + { +/# + iprintln( "Failed pathing straight up" ); +#/ + self notify( "attempting_return" ); + playfx( level._effect[ "tesla_elec_kill" ], self.origin ); + self playsound( "zmb_qrdrone_leave" ); + self delete(); + level notify( "drone_available" ); + } +} + +quadrotor_get_closest_node() +{ + nodes = getnodesinradiussorted( self.origin, 200, 0, 500, "Path" ); + if ( nodes.size == 0 ) + { + nodes = getnodesinradiussorted( self.goalpos, 3000, 0, 2000, "Path" ); + } + _a775 = nodes; + _k775 = getFirstArrayKey( _a775 ); + while ( isDefined( _k775 ) ) + { + node = _a775[ _k775 ]; + if ( node.type == "BAD NODE" || !node has_spawnflag( 2097152 ) ) + { + } + else + { + return make_sure_goal_is_well_above_ground( node.origin ); + } + _k775 = getNextArrayKey( _a775, _k775 ); + } + return self.origin; +} + +quadrotor_find_new_position() +{ + if ( !isDefined( self.goalpos ) ) + { + self.goalpos = self.origin; + } + origin = self.goalpos; + nodes = getnodesinradius( self.goalpos, self.goalradius, 0, self.flyheight + 300, "Path" ); + if ( nodes.size == 0 ) + { + nodes = getnodesinradius( self.goalpos, self.goalradius + 1000, 0, self.flyheight + 1000, "Path" ); + } + if ( nodes.size == 0 ) + { + nodes = getnodesinradius( self.goalpos, self.goalradius + 5000, 0, self.flyheight + 4000, "Path" ); + } + best_node = undefined; + best_score = 0; + _a812 = nodes; + _k812 = getFirstArrayKey( _a812 ); + while ( isDefined( _k812 ) ) + { + node = _a812[ _k812 ]; + if ( node.type == "BAD NODE" || !node has_spawnflag( 2097152 ) ) + { + } + else + { + if ( isDefined( node.quadrotor_fails ) || isDefined( node.quadrotor_claimed ) ) + { + score = randomfloat( 30 ); + } + else + { + score = randomfloat( 100 ); + } + if ( score > best_score ) + { + best_score = score; + best_node = node; + } + } + _k812 = getNextArrayKey( _a812, _k812 ); + } + if ( isDefined( best_node ) ) + { + origin = best_node.origin + ( 0, 0, self.flyheight + randomfloatrange( -30, 40 ) ); + z = self getheliheightlockheight( origin ); + origin = ( origin[ 0 ], origin[ 1 ], z ); + self.goal_node = best_node; + } + return origin; +} + +quadrotor_teleport_to_nearest_node() +{ + self.origin = self quadrotor_get_closest_node(); +} + +quadrotor_damage() +{ + self endon( "crash_done" ); + while ( isDefined( self ) ) + { + self waittill( "damage", damage ); + while ( isDefined( self.off ) ) + { + continue; + } + if ( type != "MOD_EXPLOSIVE" || type == "MOD_GRENADE_SPLASH" && type == "MOD_PROJECTILE_SPLASH" ) + { + self setvehvelocity( self.velocity + ( vectornormalize( dir ) * 300 ) ); + ang_vel = self getangularvelocity(); + ang_vel += ( randomfloatrange( -300, 300 ), randomfloatrange( -300, 300 ), randomfloatrange( -300, 300 ) ); + self setangularvelocity( ang_vel ); + } + else + { + ang_vel = self getangularvelocity(); + yaw_vel = randomfloatrange( -320, 320 ); + if ( yaw_vel < 0 ) + { + yaw_vel -= 150; + } + else + { + yaw_vel += 150; + } + ang_vel += ( randomfloatrange( -150, 150 ), yaw_vel, randomfloatrange( -150, 150 ) ); + self setangularvelocity( ang_vel ); + } + wait 0,3; + } +} + +quadrotor_cleanup_fx() +{ + if ( isDefined( self.stun_fx ) ) + { + self.stun_fx delete(); + } +} + +quadrotor_death() +{ + wait 0,1; + self notify( "nodeath_thread" ); + self waittill( "death", attacker, damagefromunderneath, weaponname, point, dir ); + self notify( "nodeath_thread" ); + if ( isDefined( self.goal_node ) && isDefined( self.goal_node.quadrotor_claimed ) ) + { + self.goal_node.quadrotor_claimed = undefined; + } + if ( isDefined( self.delete_on_death ) ) + { + if ( isDefined( self ) ) + { + self quadrotor_cleanup_fx(); + self delete(); + level.maxis_quadrotor = undefined; + } + return; + } + if ( !isDefined( self ) ) + { + return; + } + self endon( "death" ); + self disableaimassist(); + self death_fx(); + self thread death_radius_damage(); + self thread set_death_model( self.deathmodel, self.modelswapdelay ); + self thread quadrotor_crash_movement( attacker, dir ); + self quadrotor_cleanup_fx(); + self waittill( "crash_done" ); + self delete(); + level.maxis_quadrotor = undefined; +} + +death_fx() +{ + if ( isDefined( self.deathfx ) ) + { + playfxontag( self.deathfx, self, self.deathfxtag ); + } + self playsound( "veh_qrdrone_sparks" ); +} + +quadrotor_crash_movement( attacker, hitdir ) +{ + level endon( "end_game" ); + self endon( "crash_done" ); + self endon( "death" ); + self cancelaimove(); + self clearvehgoalpos(); + self clearlookatent(); + self setphysacceleration( vectorScale( ( 0, 0, 1 ), 800 ) ); + self.vehcheckforpredictedcrash = 1; + if ( !isDefined( hitdir ) ) + { + hitdir = ( 0, 0, 1 ); + } + side_dir = vectorcross( hitdir, ( 0, 0, 1 ) ); + side_dir_mag = randomfloatrange( -100, 100 ); + side_dir_mag += sign( side_dir_mag ) * 80; + side_dir *= side_dir_mag; + self setvehvelocity( self.velocity + vectorScale( ( 0, 0, 1 ), 100 ) + vectornormalize( side_dir ) ); + ang_vel = self getangularvelocity(); + ang_vel = ( ang_vel[ 0 ] * 0,3, ang_vel[ 1 ], ang_vel[ 2 ] * 0,3 ); + yaw_vel = randomfloatrange( 0, 210 ) * sign( ang_vel[ 1 ] ); + yaw_vel += sign( yaw_vel ) * 180; + ang_vel += ( randomfloatrange( -1, 1 ), yaw_vel, randomfloatrange( -1, 1 ) ); + self setangularvelocity( ang_vel ); + self.crash_accel = randomfloatrange( 75, 110 ); + if ( !isDefined( self.off ) ) + { + self thread quadrotor_crash_accel(); + } + self thread quadrotor_collision(); + self playsound( "veh_qrdrone_dmg_hit" ); + if ( !isDefined( self.off ) ) + { + self thread qrotor_dmg_snd(); + } + wait 0,1; + if ( randomint( 100 ) < 40 && !isDefined( self.off ) ) + { + self thread quadrotor_fire_for_time( randomfloatrange( 0,7, 2 ) ); + } + wait 15; + self notify( "crash_done" ); +} + +qrotor_dmg_snd() +{ + dmg_ent = spawn( "script_origin", self.origin ); + dmg_ent linkto( self ); + dmg_ent playloopsound( "veh_qrdrone_dmg_loop" ); + self waittill_any( "crash_done", "death" ); + dmg_ent stoploopsound( 1 ); + wait 2; + dmg_ent delete(); +} + +quadrotor_fire_for_time( totalfiretime ) +{ + level endon( "end_game" ); + self endon( "crash_done" ); + self endon( "change_state" ); + self endon( "death" ); + if ( isDefined( self.emped ) ) + { + return; + } + weaponname = self seatgetweapon( 0 ); + firetime = weaponfiretime( weaponname ); + time = 0; + firecount = 1; + while ( time < totalfiretime && !isDefined( self.emped ) ) + { + if ( isDefined( self.enemy ) && isDefined( self.enemy.attackeraccuracy ) && self.enemy.attackeraccuracy == 0 ) + { + self fireweapon( undefined, undefined, 1 ); + firecount++; + continue; + } + else + { + self fireweapon(); + } + firecount++; + wait firetime; + time += firetime; + } +} + +quadrotor_crash_accel() +{ + level endon( "end_game" ); + self endon( "crash_done" ); + self endon( "death" ); + count = 0; + while ( 1 ) + { + self setvehvelocity( self.velocity + ( anglesToUp( self.angles ) * self.crash_accel ) ); + self.crash_accel *= 0,98; + wait 0,1; + count++; + if ( ( count % 8 ) == 0 ) + { + if ( randomint( 100 ) > 40 ) + { + if ( self.velocity[ 2 ] > 150 ) + { + self.crash_accel *= 0,75; + break; + } + else if ( self.velocity[ 2 ] < 40 && count < 60 ) + { + if ( abs( self.angles[ 0 ] ) > 30 || abs( self.angles[ 2 ] ) > 30 ) + { + self.crash_accel = randomfloatrange( 160, 200 ); + break; + } + else + { + self.crash_accel = randomfloatrange( 85, 120 ); + } + } + } + } + } +} + +quadrotor_predicted_collision() +{ + level endon( "end_game" ); + self endon( "crash_done" ); + self endon( "death" ); + while ( 1 ) + { + self waittill( "veh_predictedcollision", velocity, normal ); + if ( normal[ 2 ] >= 0,6 ) + { + self notify( "veh_collision" ); + } + } +} + +quadrotor_collision_player() +{ + level endon( "end_game" ); + self endon( "change_state" ); + self endon( "crash_done" ); + self endon( "death" ); + while ( 1 ) + { + self waittill( "veh_collision", velocity, normal ); + driver = self getseatoccupant( 0 ); + if ( isDefined( driver ) && lengthsquared( velocity ) > 4900 ) + { + earthquake( 0,25, 0,25, driver.origin, 50 ); + driver playrumbleonentity( "damage_heavy" ); + } + } +} + +quadrotor_collision() +{ + level endon( "end_game" ); + self endon( "change_state" ); + self endon( "crash_done" ); + self endon( "death" ); + if ( !isalive( self ) ) + { + self thread quadrotor_predicted_collision(); + } + self.bounce_count = 0; + time_of_last_bounce = 0; + while ( 1 ) + { + self waittill( "veh_collision", velocity, normal ); + ang_vel = self getangularvelocity() * 0,5; + self setangularvelocity( ang_vel ); + if ( normal[ 2 ] < 0,6 || isalive( self ) && !isDefined( self.emped ) ) + { + self setvehvelocity( self.velocity + ( normal * 90 ) ); + self playsound( "veh_qrdrone_wall" ); + if ( normal[ 2 ] < 0,6 ) + { + fx_origin = self.origin - ( normal * 28 ); + } + else + { + fx_origin = self.origin - ( normal * 10 ); + } + playfx( level._effect[ "quadrotor_nudge" ], fx_origin, normal ); + current_time = getTime(); + if ( ( current_time - time_of_last_bounce ) < 1000 ) + { + self.bounce_count += 1; + if ( self.bounce_count > 2 ) + { + self notify( "force_goal" ); + self.bounce_count = 0; + } + } + else + { + self.bounce_count = 0; + } + time_of_last_bounce = getTime(); + continue; + } + else + { + if ( isDefined( self.emped ) ) + { + if ( isDefined( self.bounced ) ) + { + self playsound( "veh_qrdrone_wall" ); + self setvehvelocity( ( 0, 0, 1 ) ); + self setangularvelocity( ( 0, 0, 1 ) ); + if ( self.angles[ 0 ] < 0 ) + { + if ( self.angles[ 0 ] < -15 ) + { + self.angles = ( -15, self.angles[ 1 ], self.angles[ 2 ] ); + } + else + { + if ( self.angles[ 0 ] > -10 ) + { + self.angles = ( -10, self.angles[ 1 ], self.angles[ 2 ] ); + } + } + } + else if ( self.angles[ 0 ] > 15 ) + { + self.angles = ( 15, self.angles[ 1 ], self.angles[ 2 ] ); + } + else + { + if ( self.angles[ 0 ] < 10 ) + { + self.angles = ( 10, self.angles[ 1 ], self.angles[ 2 ] ); + } + } + self.bounced = undefined; + self notify( "landed" ); + return; + } + else + { + self.bounced = 1; + self setvehvelocity( self.velocity + ( normal * 120 ) ); + self playsound( "veh_qrdrone_wall" ); + if ( normal[ 2 ] < 0,6 ) + { + fx_origin = self.origin - ( normal * 28 ); + } + else + { + fx_origin = self.origin - ( normal * 10 ); + } + playfx( level._effect[ "quadrotor_nudge" ], fx_origin, normal ); + } + break; + } + else + { + createdynentandlaunch( self.deathmodel, self.origin, self.angles, self.origin, self.velocity * 0,01 ); + self playsound( "veh_qrdrone_explo" ); + self thread death_fire_loop_audio(); + self notify( "crash_done" ); + } + } + } +} + +death_fire_loop_audio() +{ + sound_ent = spawn( "script_origin", self.origin ); + sound_ent playloopsound( "veh_qrdrone_death_fire_loop", 0,1 ); + wait 11; + sound_ent stoploopsound( 1 ); + sound_ent delete(); +} + +quadrotor_set_team( team ) +{ + self.team = team; + self.vteam = team; + self setteam( team ); + if ( !isDefined( self.off ) ) + { + quadrotor_blink_lights(); + } +} + +quadrotor_blink_lights() +{ + level endon( "end_game" ); + self endon( "death" ); + self lights_off(); + wait 0,1; + self lights_on(); +} + +quadrotor_self_destruct() +{ + level endon( "end_game" ); + self endon( "death" ); + self endon( "exit_vehicle" ); + self_destruct = 0; + self_destruct_time = 0; + for ( ;; ) + { + while ( 1 ) + { + if ( !self_destruct ) + { + if ( level.player meleebuttonpressed() ) + { + self_destruct = 1; + self_destruct_time = 5; + } + wait 0,05; + } + } + else iprintlnbold( self_destruct_time ); + wait 1; + self_destruct_time -= 1; + if ( self_destruct_time == 0 ) + { + driver = self getseatoccupant( 0 ); + if ( isDefined( driver ) ) + { + driver disableinvulnerability(); + } + earthquake( 3, 1, self.origin, 256 ); + radiusdamage( self.origin, 1000, 15000, 15000, level.player, "MOD_EXPLOSIVE" ); + self dodamage( self.health + 1000, self.origin ); + } + } +} +} + +quadrotor_level_out_for_landing() +{ + level endon( "end_game" ); + self endon( "death" ); + self endon( "emped" ); + self endon( "landed" ); + while ( isDefined( self.emped ) ) + { + velocity = self.velocity; + self.angles = ( self.angles[ 0 ] * 0,85, self.angles[ 1 ], self.angles[ 2 ] * 0,85 ); + ang_vel = self getangularvelocity() * 0,85; + self setangularvelocity( ang_vel ); + self setvehvelocity( velocity ); + wait 0,05; + } +} + +quadrotor_temp_bullet_shield( invulnerable_time ) +{ + self notify( "bullet_shield" ); + self endon( "bullet_shield" ); + self.bullet_shield = 1; + wait invulnerable_time; + if ( isDefined( self ) ) + { + self.bullet_shield = undefined; + wait 3; + if ( isDefined( self ) && self.health < 40 ) + { + self.health = 40; + } + } +} + +lights_on() +{ + self clearclientflag( 10 ); +} + +lights_off() +{ + self setclientflag( 10 ); +} + +death_radius_damage() +{ + if ( !isDefined( self ) || self.radiusdamageradius <= 0 ) + { + return; + } + wait 0,05; + if ( isDefined( self ) ) + { + self radiusdamage( self.origin + vectorScale( ( 0, 0, 1 ), 15 ), self.radiusdamageradius, self.radiusdamagemax, self.radiusdamagemin, self, "MOD_EXPLOSIVE" ); + } +} + +set_death_model( smodel, fdelay ) +{ +/# + assert( isDefined( smodel ) ); +#/ + if ( isDefined( fdelay ) && fdelay > 0 ) + { + wait fdelay; + } + if ( !isDefined( self ) ) + { + return; + } + if ( isDefined( self.deathmodel_attached ) ) + { + return; + } + self setmodel( smodel ); +} + +player_in_last_stand_within_range( range ) +{ + players = getplayers(); + if ( players.size == 1 ) + { + return; + } + _a1448 = players; + _k1448 = getFirstArrayKey( _a1448 ); + while ( isDefined( _k1448 ) ) + { + player = _a1448[ _k1448 ]; + if ( player maps/mp/zombies/_zm_laststand::player_is_in_laststand() && distancesquared( self.origin, player.origin ) < ( range * range ) && !isDefined( player.quadrotor_revive ) ) + { + return player; + } + _k1448 = getNextArrayKey( _a1448, _k1448 ); + } + return; +} + +watch_for_fail_revive( quad_rotor ) +{ + quadrotor = quad_rotor; + owner = quad_rotor.player_owner; + revive_target = quad_rotor.revive_target; + revive_target endon( "bled_out" ); + revive_target endon( "disconnect" ); + level thread kill_fx_if_target_revive( quadrotor, revive_target ); + revive_target.revive_hud settext( &"GAME_PLAYER_IS_REVIVING_YOU", owner ); + revive_target revive_hud_show_n_fade( 1 ); + wait 1; + if ( isDefined( revive_target ) ) + { + revive_target.quadrotor_revive = undefined; + } +} + +kill_fx_if_target_revive( quadrotor, revive_target ) +{ + e_fx = spawn( "script_model", quadrotor gettagorigin( "tag_origin" ) ); + e_fx setmodel( "tag_origin" ); + e_fx playsound( "zmb_drone_revive_fire" ); + e_fx playloopsound( "zmb_drone_revive_loop", 0,2 ); + playfxontag( level._effect[ "qd_revive" ], e_fx, "tag_origin" ); + e_fx moveto( revive_target.origin, 1 ); + timer = 0; + while ( 1 ) + { + if ( isDefined( revive_target ) && revive_target maps/mp/zombies/_zm_laststand::player_is_in_laststand() && isDefined( quadrotor ) ) + { + wait 0,1; + timer += 0,1; + if ( timer >= 1 ) + { + playfxontag( level._effect[ "staff_soul" ], e_fx, "tag_origin" ); + e_fx stoploopsound( 0,1 ); + e_fx playsound( "zmb_drone_revive_revive_3d" ); + revive_target playsoundtoplayer( "zmb_drone_revive_revive_plr", revive_target ); + break; + } + else } + else } + e_fx delete(); +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_challenges.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_challenges.gsc new file mode 100644 index 0000000..fc2901d --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_challenges.gsc @@ -0,0 +1,884 @@ +#include maps/mp/zombies/_zm_score; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/zombies/_zm_unitrigger; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +#using_animtree( "fxanim_props_dlc4" ); + +init() +{ + level._challenges = spawnstruct(); + stats_init(); + level.a_m_challenge_boards = []; + level.a_uts_challenge_boxes = []; + a_m_challenge_boxes = getentarray( "challenge_box", "targetname" ); + array_thread( a_m_challenge_boxes, ::box_init ); + onplayerconnect_callback( ::onplayerconnect ); + n_bits = getminbitcountfornum( 14 ); + registerclientfield( "toplayer", "challenge_complete_1", 14000, 1, "int" ); + registerclientfield( "toplayer", "challenge_complete_2", 14000, 1, "int" ); + registerclientfield( "toplayer", "challenge_complete_3", 14000, 1, "int" ); + registerclientfield( "toplayer", "challenge_complete_4", 14000, 1, "int" ); +/# + level thread challenges_devgui(); +#/ +} + +onplayerconnect() +{ + player_stats_init( self.characterindex ); + _a55 = level._challenges.a_players[ self.characterindex ].a_stats; + _k55 = getFirstArrayKey( _a55 ); + while ( isDefined( _k55 ) ) + { + s_stat = _a55[ _k55 ]; + s_stat.b_display_tag = 1; + _a58 = level.a_m_challenge_boards; + _k58 = getFirstArrayKey( _a58 ); + while ( isDefined( _k58 ) ) + { + m_board = _a58[ _k58 ]; + m_board showpart( s_stat.str_medal_tag ); + m_board hidepart( s_stat.str_glow_tag ); + _k58 = getNextArrayKey( _a58, _k58 ); + } + _k55 = getNextArrayKey( _a55, _k55 ); + } + self thread onplayerspawned(); +} + +onplayerspawned() +{ + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "spawned_player" ); + _a81 = level._challenges.a_players[ self.characterindex ].a_stats; + _k81 = getFirstArrayKey( _a81 ); + while ( isDefined( _k81 ) ) + { + s_stat = _a81[ _k81 ]; + while ( s_stat.b_medal_awarded && !s_stat.b_reward_claimed ) + { + _a85 = level.a_m_challenge_boards; + _k85 = getFirstArrayKey( _a85 ); + while ( isDefined( _k85 ) ) + { + m_board = _a85[ _k85 ]; + self setclientfieldtoplayer( s_stat.s_parent.cf_complete, 1 ); + _k85 = getNextArrayKey( _a85, _k85 ); + } + } + _k81 = getNextArrayKey( _a81, _k81 ); + } + _a92 = level._challenges.s_team.a_stats; + _k92 = getFirstArrayKey( _a92 ); + while ( isDefined( _k92 ) ) + { + s_stat = _a92[ _k92 ]; + while ( s_stat.b_medal_awarded && s_stat.a_b_player_rewarded[ self.characterindex ] ) + { + _a96 = level.a_m_challenge_boards; + _k96 = getFirstArrayKey( _a96 ); + while ( isDefined( _k96 ) ) + { + m_board = _a96[ _k96 ]; + self setclientfieldtoplayer( s_stat.s_parent.cf_complete, 1 ); + _k96 = getNextArrayKey( _a96, _k96 ); + } + } + _k92 = getNextArrayKey( _a92, _k92 ); + } + } +} + +stats_init() +{ + level._challenges.a_stats = []; + if ( isDefined( level.challenges_add_stats ) ) + { + [[ level.challenges_add_stats ]](); + } + _a124 = level._challenges.a_stats; + _k124 = getFirstArrayKey( _a124 ); + while ( isDefined( _k124 ) ) + { + stat = _a124[ _k124 ]; + if ( isDefined( stat.fp_init_stat ) ) + { + level thread [[ stat.fp_init_stat ]](); + } + _k124 = getNextArrayKey( _a124, _k124 ); + } + level._challenges.a_players = []; + i = 0; + while ( i < 4 ) + { + player_stats_init( i ); + i++; + } + team_stats_init(); +} + +add_stat( str_name, b_team, str_hint, n_goal, str_reward_model, fp_give_reward, fp_init_stat ) +{ + if ( !isDefined( b_team ) ) + { + b_team = 0; + } + if ( !isDefined( str_hint ) ) + { + str_hint = &""; + } + if ( !isDefined( n_goal ) ) + { + n_goal = 1; + } + stat = spawnstruct(); + stat.str_name = str_name; + stat.b_team = b_team; + stat.str_hint = str_hint; + stat.n_goal = n_goal; + stat.str_reward_model = str_reward_model; + stat.fp_give_reward = fp_give_reward; + if ( isDefined( fp_init_stat ) ) + { + stat.fp_init_stat = fp_init_stat; + } + level._challenges.a_stats[ str_name ] = stat; + stat.cf_complete = "challenge_complete_" + level._challenges.a_stats.size; +} + +player_stats_init( n_index ) +{ + a_characters = array( "d", "n", "r", "t" ); + str_character = a_characters[ n_index ]; + if ( !isDefined( level._challenges.a_players[ n_index ] ) ) + { + level._challenges.a_players[ n_index ] = spawnstruct(); + level._challenges.a_players[ n_index ].a_stats = []; + } + s_player_set = level._challenges.a_players[ n_index ]; + n_challenge_index = 1; + _a196 = level._challenges.a_stats; + _k196 = getFirstArrayKey( _a196 ); + while ( isDefined( _k196 ) ) + { + s_challenge = _a196[ _k196 ]; + if ( !s_challenge.b_team ) + { + if ( !isDefined( s_player_set.a_stats[ s_challenge.str_name ] ) ) + { + s_player_set.a_stats[ s_challenge.str_name ] = spawnstruct(); + } + s_stat = s_player_set.a_stats[ s_challenge.str_name ]; + s_stat.s_parent = s_challenge; + s_stat.n_value = 0; + s_stat.b_medal_awarded = 0; + s_stat.b_reward_claimed = 0; + n_index = level._challenges.a_stats.size + 1; + s_stat.str_medal_tag = "j_" + str_character + "_medal_0" + n_challenge_index; + s_stat.str_glow_tag = "j_" + str_character + "_glow_0" + n_challenge_index; + s_stat.b_display_tag = 0; + n_challenge_index++; + } + _k196 = getNextArrayKey( _a196, _k196 ); + } + s_player_set.n_completed = 0; + s_player_set.n_medals_held = 0; +} + +team_stats_init( n_index ) +{ + if ( !isDefined( level._challenges.s_team ) ) + { + level._challenges.s_team = spawnstruct(); + level._challenges.s_team.a_stats = []; + } + s_team_set = level._challenges.s_team; + _a243 = level._challenges.a_stats; + _k243 = getFirstArrayKey( _a243 ); + while ( isDefined( _k243 ) ) + { + s_challenge = _a243[ _k243 ]; + if ( s_challenge.b_team ) + { + if ( !isDefined( s_team_set.a_stats[ s_challenge.str_name ] ) ) + { + s_team_set.a_stats[ s_challenge.str_name ] = spawnstruct(); + } + s_stat = s_team_set.a_stats[ s_challenge.str_name ]; + s_stat.s_parent = s_challenge; + s_stat.n_value = 0; + s_stat.b_medal_awarded = 0; + s_stat.b_reward_claimed = 0; + s_stat.a_b_player_rewarded = array( 0, 0, 0, 0 ); + s_stat.str_medal_tag = "j_g_medal"; + s_stat.str_glow_tag = "j_g_glow"; + s_stat.b_display_tag = 1; + } + _k243 = getNextArrayKey( _a243, _k243 ); + } + s_team_set.n_completed = 0; + s_team_set.n_medals_held = 0; +} + +challenge_exists( str_name ) +{ + if ( isDefined( level._challenges.a_stats[ str_name ] ) ) + { + return 1; + } + else + { + return 0; + } +} + +get_stat( str_stat, player ) +{ + s_parent_stat = level._challenges.a_stats[ str_stat ]; +/# + assert( isDefined( s_parent_stat ), "Challenge stat: " + str_stat + " does not exist" ); +#/ +/# + if ( !s_parent_stat.b_team ) + { + assert( isDefined( player ), "Challenge stat: " + str_stat + " is a player stat, but no player passed in" ); + } +#/ + if ( s_parent_stat.b_team ) + { + s_stat = level._challenges.s_team.a_stats[ str_stat ]; + } + else + { + s_stat = level._challenges.a_players[ player.characterindex ].a_stats[ str_stat ]; + } + return s_stat; +} + +increment_stat( str_stat, n_increment ) +{ + if ( !isDefined( n_increment ) ) + { + n_increment = 1; + } + s_stat = get_stat( str_stat, self ); + if ( !s_stat.b_medal_awarded ) + { + s_stat.n_value += n_increment; + check_stat_complete( s_stat ); + } +} + +set_stat( str_stat, n_set ) +{ + s_stat = get_stat( str_stat, self ); + if ( !s_stat.b_medal_awarded ) + { + s_stat.n_value = n_set; + check_stat_complete( s_stat ); + } +} + +check_stat_complete( s_stat ) +{ + if ( s_stat.b_medal_awarded ) + { + return 1; + } + if ( s_stat.n_value >= s_stat.s_parent.n_goal ) + { + s_stat.b_medal_awarded = 1; + if ( s_stat.s_parent.b_team ) + { + s_team_stats = level._challenges.s_team; + s_team_stats.n_completed++; + s_team_stats.n_medals_held++; + a_players = get_players(); + _a358 = a_players; + _k358 = getFirstArrayKey( _a358 ); + while ( isDefined( _k358 ) ) + { + player = _a358[ _k358 ]; + player setclientfieldtoplayer( s_stat.s_parent.cf_complete, 1 ); + player playsound( "evt_medal_acquired" ); + wait_network_frame(); + _k358 = getNextArrayKey( _a358, _k358 ); + } + } + else s_player_stats = level._challenges.a_players[ self.characterindex ]; + s_player_stats.n_completed++; + s_player_stats.n_medals_held++; + self playsound( "evt_medal_acquired" ); + self setclientfieldtoplayer( s_stat.s_parent.cf_complete, 1 ); + _a376 = level.a_m_challenge_boards; + _k376 = getFirstArrayKey( _a376 ); + while ( isDefined( _k376 ) ) + { + m_board = _a376[ _k376 ]; + m_board showpart( s_stat.str_glow_tag ); + _k376 = getNextArrayKey( _a376, _k376 ); + } + if ( isplayer( self ) ) + { + if ( ( level._challenges.a_players[ self.characterindex ].n_completed + level._challenges.s_team.n_completed ) == level._challenges.a_stats.size ) + { + self notify( "all_challenges_complete" ); + } + } + else + { + _a391 = get_players(); + _k391 = getFirstArrayKey( _a391 ); + while ( isDefined( _k391 ) ) + { + player = _a391[ _k391 ]; + if ( isDefined( player.characterindex ) ) + { + if ( ( level._challenges.a_players[ player.characterindex ].n_completed + level._challenges.s_team.n_completed ) == level._challenges.a_stats.size ) + { + player notify( "all_challenges_complete" ); + } + } + _k391 = getNextArrayKey( _a391, _k391 ); + } + } + wait_network_frame(); + } +} + +stat_reward_available( stat, player ) +{ + if ( isstring( stat ) ) + { + s_stat = get_stat( stat, player ); + } + else + { + s_stat = stat; + } + if ( !s_stat.b_medal_awarded ) + { + return 0; + } + if ( s_stat.b_reward_claimed ) + { + return 0; + } + if ( s_stat.s_parent.b_team && s_stat.a_b_player_rewarded[ player.characterindex ] ) + { + return 0; + } + return 1; +} + +player_has_unclaimed_team_reward() +{ + _a441 = level._challenges.s_team.a_stats; + _k441 = getFirstArrayKey( _a441 ); + while ( isDefined( _k441 ) ) + { + s_stat = _a441[ _k441 ]; + if ( s_stat.b_medal_awarded && !s_stat.a_b_player_rewarded[ self.characterindex ] ) + { + return 1; + } + _k441 = getNextArrayKey( _a441, _k441 ); + } + return 0; +} + +board_init( m_board ) +{ + self.m_board = m_board; + a_challenges = getarraykeys( level._challenges.a_stats ); + a_characters = array( "d", "n", "r", "t" ); + m_board.a_s_medal_tags = []; + b_team_hint_added = 0; + _a473 = level._challenges.a_players; + n_char_index = getFirstArrayKey( _a473 ); + while ( isDefined( n_char_index ) ) + { + s_set = _a473[ n_char_index ]; + str_character = a_characters[ n_char_index ]; + n_challenge_index = 1; + _a477 = s_set.a_stats; + _k477 = getFirstArrayKey( _a477 ); + while ( isDefined( _k477 ) ) + { + s_stat = _a477[ _k477 ]; + str_medal_tag = "j_" + str_character + "_medal_0" + n_challenge_index; + str_glow_tag = "j_" + str_character + "_glow_0" + n_challenge_index; + s_tag = spawnstruct(); + s_tag.v_origin = m_board gettagorigin( str_medal_tag ); + s_tag.s_stat = s_stat; + s_tag.n_character_index = n_char_index; + s_tag.str_medal_tag = str_medal_tag; + m_board.a_s_medal_tags[ m_board.a_s_medal_tags.size ] = s_tag; + m_board hidepart( str_medal_tag ); + m_board hidepart( str_glow_tag ); + n_challenge_index++; + _k477 = getNextArrayKey( _a477, _k477 ); + } + n_char_index = getNextArrayKey( _a473, n_char_index ); + } + _a495 = level._challenges.s_team.a_stats; + _k495 = getFirstArrayKey( _a495 ); + while ( isDefined( _k495 ) ) + { + s_stat = _a495[ _k495 ]; + str_medal_tag = "j_g_medal"; + str_glow_tag = "j_g_glow"; + s_tag = spawnstruct(); + s_tag.v_origin = m_board gettagorigin( str_medal_tag ); + s_tag.s_stat = s_stat; + s_tag.n_character_index = 4; + s_tag.str_medal_tag = str_medal_tag; + m_board.a_s_medal_tags[ m_board.a_s_medal_tags.size ] = s_tag; + m_board hidepart( str_glow_tag ); + b_team_hint_added = 1; + _k495 = getNextArrayKey( _a495, _k495 ); + } + level.a_m_challenge_boards[ level.a_m_challenge_boards.size ] = m_board; +} + +box_init() +{ + self useanimtree( -1 ); + s_unitrigger_stub = spawnstruct(); + s_unitrigger_stub.origin = self.origin + ( 0, 0, 0 ); + s_unitrigger_stub.angles = self.angles; + s_unitrigger_stub.radius = 64; + s_unitrigger_stub.script_length = 64; + s_unitrigger_stub.script_width = 64; + s_unitrigger_stub.script_height = 64; + s_unitrigger_stub.cursor_hint = "HINT_NOICON"; + s_unitrigger_stub.hint_string = &""; + s_unitrigger_stub.script_unitrigger_type = "unitrigger_box_use"; + s_unitrigger_stub.prompt_and_visibility_func = ::box_prompt_and_visiblity; + s_unitrigger_stub ent_flag_init( "waiting_for_grab" ); + s_unitrigger_stub ent_flag_init( "reward_timeout" ); + s_unitrigger_stub.b_busy = 0; + s_unitrigger_stub.m_box = self; + s_unitrigger_stub.b_disable_trigger = 0; + if ( isDefined( self.script_string ) ) + { + s_unitrigger_stub.str_location = self.script_string; + } + if ( isDefined( s_unitrigger_stub.m_box.target ) ) + { + s_unitrigger_stub.m_board = getent( s_unitrigger_stub.m_box.target, "targetname" ); + s_unitrigger_stub board_init( s_unitrigger_stub.m_board ); + } + unitrigger_force_per_player_triggers( s_unitrigger_stub, 1 ); + level.a_uts_challenge_boxes[ level.a_uts_challenge_boxes.size ] = s_unitrigger_stub; + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( s_unitrigger_stub, ::box_think ); +} + +box_prompt_and_visiblity( player ) +{ + if ( self.stub.b_disable_trigger ) + { + return 0; + } + self thread update_box_prompt( player ); + return 1; +} + +update_box_prompt( player ) +{ + self endon( "kill_trigger" ); + player endon( "death_or_disconnect" ); + str_hint = &""; + str_old_hint = &""; + m_board = self.stub.m_board; + self sethintstring( str_hint ); + while ( 1 ) + { + s_hint_tag = undefined; + b_showing_stat = 0; + self.b_can_open = 0; + if ( self.stub.b_busy ) + { + if ( self.stub ent_flag( "waiting_for_grab" ) || !isDefined( self.stub.player_using ) && self.stub.player_using == player ) + { + str_hint = &"ZM_TOMB_CH_G"; + } + else + { + str_hint = &""; + } + } + else str_hint = &""; + player.s_lookat_stat = undefined; + n_closest_dot = 0,996; + v_eye_origin = player getplayercamerapos(); + v_eye_direction = anglesToForward( player getplayerangles() ); + _a619 = m_board.a_s_medal_tags; + str_tag = getFirstArrayKey( _a619 ); + while ( isDefined( str_tag ) ) + { + s_tag = _a619[ str_tag ]; + if ( !s_tag.s_stat.b_display_tag ) + { + } + else + { + v_tag_origin = s_tag.v_origin; + v_eye_to_tag = vectornormalize( v_tag_origin - v_eye_origin ); + n_dot = vectordot( v_eye_to_tag, v_eye_direction ); + if ( n_dot > n_closest_dot ) + { + n_closest_dot = n_dot; + str_hint = s_tag.s_stat.s_parent.str_hint; + s_hint_tag = s_tag; + b_showing_stat = 1; + self.b_can_open = 0; + if ( s_tag.n_character_index == player.characterindex || s_tag.n_character_index == 4 ) + { + player.s_lookat_stat = s_tag.s_stat; + if ( stat_reward_available( s_tag.s_stat, player ) ) + { + str_hint = &"ZM_TOMB_CH_S"; + b_showing_stat = 0; + self.b_can_open = 1; + } + } + } + } + str_tag = getNextArrayKey( _a619, str_tag ); + } + if ( str_hint == &"" ) + { + s_player = level._challenges.a_players[ player.characterindex ]; + s_team = level._challenges.s_team; + if ( s_player.n_medals_held > 0 || player player_has_unclaimed_team_reward() ) + { + str_hint = &"ZM_TOMB_CH_O"; + self.b_can_open = 1; + break; + } + else + { + str_hint = &"ZM_TOMB_CH_V"; + } + } + if ( str_old_hint != str_hint ) + { + str_old_hint = str_hint; + self.stub.hint_string = str_hint; + if ( isDefined( s_hint_tag ) ) + { + str_name = s_hint_tag.s_stat.s_parent.str_name; + n_character_index = s_hint_tag.n_character_index; + if ( n_character_index != 4 ) + { + s_player_stat = level._challenges.a_players[ n_character_index ].a_stats[ str_name ]; + break; + } + } + self sethintstring( self.stub.hint_string ); + } + wait 0,1; + } +} + +box_think() +{ + self endon( "kill_trigger" ); + s_team = level._challenges.s_team; + while ( 1 ) + { + self waittill( "trigger", player ); + while ( !is_player_valid( player ) ) + { + continue; + } + while ( self.stub.b_busy ) + { + current_weapon = player getcurrentweapon(); + while ( isDefined( player.intermission ) && !player.intermission && !is_placeable_mine( current_weapon ) && !is_equipment_that_blocks_purchase( current_weapon ) && current_weapon != "none" && !player maps/mp/zombies/_zm_laststand::player_is_in_laststand() && !player isthrowinggrenade() && !player in_revive_trigger() || player isswitchingweapons() && player.is_drinking > 0 ) + { + wait 0,1; + } + if ( self.stub ent_flag( "waiting_for_grab" ) ) + { + if ( !isDefined( self.stub.player_using ) ) + { + self.stub.player_using = player; + } + if ( player == self.stub.player_using ) + { + self.stub ent_flag_clear( "waiting_for_grab" ); + } + } + wait 0,05; + } + if ( self.b_can_open ) + { + self.stub.hint_string = &""; + self sethintstring( self.stub.hint_string ); + level thread open_box( player, self.stub ); + } + } +} + +get_reward_category( player, s_select_stat ) +{ + if ( isDefined( s_select_stat ) || s_select_stat.s_parent.b_team && level._challenges.s_team.n_medals_held > 0 ) + { + return level._challenges.s_team; + } + if ( level._challenges.a_players[ player.characterindex ].n_medals_held > 0 ) + { + return level._challenges.a_players[ player.characterindex ]; + } + return undefined; +} + +get_reward_stat( s_category ) +{ + _a809 = s_category.a_stats; + _k809 = getFirstArrayKey( _a809 ); + while ( isDefined( _k809 ) ) + { + s_stat = _a809[ _k809 ]; + if ( s_stat.b_medal_awarded && !s_stat.b_reward_claimed ) + { + if ( s_stat.s_parent.b_team && s_stat.a_b_player_rewarded[ self.characterindex ] ) + { + break; + } + else + { + return s_stat; + } + } + _k809 = getNextArrayKey( _a809, _k809 ); + } + return undefined; +} + +open_box( player, ut_stub, fp_reward_override, param1 ) +{ + m_box = ut_stub.m_box; + while ( ut_stub.b_busy ) + { + wait 1; + } + ut_stub.b_busy = 1; + ut_stub.player_using = player; + if ( isDefined( player ) && isDefined( player.s_lookat_stat ) ) + { + s_select_stat = player.s_lookat_stat; + } + m_box setanim( %o_zombie_dlc4_challenge_box_open ); + m_box delay_thread( 0,75, ::setclientfield, "foot_print_box_glow", 1 ); + wait 0,5; + if ( isDefined( fp_reward_override ) ) + { + ut_stub [[ fp_reward_override ]]( player, param1 ); + } + else + { + ut_stub spawn_reward( player, s_select_stat ); + } + wait 1; + m_box setanim( %o_zombie_dlc4_challenge_box_close ); + m_box delay_thread( 0,75, ::setclientfield, "foot_print_box_glow", 0 ); + wait 2; + ut_stub.b_busy = 0; + ut_stub.player_using = undefined; +} + +spawn_reward( player, s_select_stat ) +{ + if ( isDefined( player ) ) + { + player endon( "death_or_disconnect" ); + if ( isDefined( s_select_stat ) ) + { + s_category = get_reward_category( player, s_select_stat ); + if ( stat_reward_available( s_select_stat, player ) ) + { + s_stat = s_select_stat; + } + } + if ( !isDefined( s_stat ) ) + { + s_category = get_reward_category( player ); + s_stat = player get_reward_stat( s_category ); + } + if ( self [[ s_stat.s_parent.fp_give_reward ]]( player, s_stat ) ) + { + if ( isDefined( s_stat.s_parent.cf_complete ) ) + { + player setclientfieldtoplayer( s_stat.s_parent.cf_complete, 0 ); + } + while ( s_stat.s_parent.b_team ) + { + s_stat.a_b_player_rewarded[ player.characterindex ] = 1; + a_players = get_players(); + _a917 = a_players; + _k917 = getFirstArrayKey( _a917 ); + while ( isDefined( _k917 ) ) + { + player = _a917[ _k917 ]; + if ( !s_stat.a_b_player_rewarded[ player.characterindex ] ) + { + return; + } + _k917 = getNextArrayKey( _a917, _k917 ); + } + } + s_stat.b_reward_claimed = 1; + s_category.n_medals_held--; + + } + } +} + +reward_grab_wait( n_timeout ) +{ + if ( !isDefined( n_timeout ) ) + { + n_timeout = 10; + } + self ent_flag_clear( "reward_timeout" ); + self ent_flag_set( "waiting_for_grab" ); + self endon( "waiting_for_grab" ); + if ( n_timeout > 0 ) + { + wait n_timeout; + self ent_flag_set( "reward_timeout" ); + self ent_flag_clear( "waiting_for_grab" ); + } + else + { + self ent_flag_waitopen( "waiting_for_grab" ); + } +} + +reward_sink( n_delay, n_z, n_time ) +{ + if ( isDefined( n_delay ) ) + { + wait n_delay; + if ( isDefined( self ) ) + { + self movez( n_z * -1, n_time ); + } + } +} + +reward_rise_and_grab( m_reward, n_z, n_rise_time, n_delay, n_timeout ) +{ + m_reward movez( n_z, n_rise_time ); + wait n_rise_time; + if ( n_timeout > 0 ) + { + m_reward thread reward_sink( n_delay, n_z, n_timeout + 1 ); + } + self reward_grab_wait( n_timeout ); + if ( self ent_flag( "reward_timeout" ) ) + { + return 0; + } + return 1; +} + +reward_points( player, s_stat ) +{ + player maps/mp/zombies/_zm_score::add_to_player_score( 2500 ); +} + +challenges_devgui() +{ +/# + setdvar( "award_challenge", "0" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Challenges:10/Award Player1" "award_challenge 1"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Challenges:10/Award Player2" "award_challenge 2"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Challenges:10/Award Player3" "award_challenge 3"\n" ); + adddebugcommand( "devgui_cmd "Zombies/Tomb:1/Challenges:10/Award Team" "award_challenge 4"\n" ); + thread watch_devgui_award_challenges(); +#/ +} + +watch_devgui_award_challenges() +{ +/# + while ( 1 ) + { + n_award_challenge = getDvarInt( "award_challenge" ); + if ( n_award_challenge != 0 ) + { + devgui_award_challenge( n_award_challenge ); + setdvarint( "award_challenge", 0 ); + } + wait 0,5; +#/ + } +} + +devgui_award_challenge( n_index ) +{ +/# + if ( n_index == 4 ) + { + s_team_stats = level._challenges.s_team; + s_team_stats.n_completed = 1; + s_team_stats.n_medals_held = 1; + a_keys = getarraykeys( level._challenges.s_team.a_stats ); + s_stat = level._challenges.s_team.a_stats[ a_keys[ 0 ] ]; + s_stat.b_medal_awarded = 1; + s_stat.b_reward_claimed = 0; + a_players = get_players(); + _a1055 = a_players; + _k1055 = getFirstArrayKey( _a1055 ); + while ( isDefined( _k1055 ) ) + { + player = _a1055[ _k1055 ]; + s_stat.a_b_player_rewarded[ player.characterindex ] = 0; + player setclientfieldtoplayer( s_stat.s_parent.cf_complete, 1 ); + _k1055 = getNextArrayKey( _a1055, _k1055 ); + } + _a1061 = level.a_m_challenge_boards; + _k1061 = getFirstArrayKey( _a1061 ); + while ( isDefined( _k1061 ) ) + { + m_board = _a1061[ _k1061 ]; + m_board showpart( s_stat.str_glow_tag ); + _k1061 = getNextArrayKey( _a1061, _k1061 ); + } + } + else a_keys = getarraykeys( level._challenges.a_players[ 0 ].a_stats ); + a_players = get_players(); + _a1071 = a_players; + _k1071 = getFirstArrayKey( _a1071 ); + while ( isDefined( _k1071 ) ) + { + player = _a1071[ _k1071 ]; + s_player_data = level._challenges.a_players[ player.characterindex ]; + s_player_data.n_completed++; + s_player_data.n_medals_held++; + s_stat = s_player_data.a_stats[ a_keys[ n_index - 1 ] ]; + s_stat.b_medal_awarded = 1; + s_stat.b_reward_claimed = 0; + player setclientfieldtoplayer( s_stat.s_parent.cf_complete, 1 ); + _a1082 = level.a_m_challenge_boards; + _k1082 = getFirstArrayKey( _a1082 ); + while ( isDefined( _k1082 ) ) + { + m_board = _a1082[ _k1082 ]; + m_board showpart( s_stat.str_glow_tag ); + _k1082 = getNextArrayKey( _a1082, _k1082 ); + } + _k1071 = getNextArrayKey( _a1071, _k1071 ); +#/ + } +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_craftables.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_craftables.gsc new file mode 100644 index 0000000..cd59548 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_craftables.gsc @@ -0,0 +1,3241 @@ +#include maps/mp/_demo; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_stats; +#include maps/mp/zombies/_zm_craftables; +#include maps/mp/zombies/_zm_equipment; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/gametypes_zm/_hud_util; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + precachestring( &"ZOMBIE_BUILDING" ); + precachestring( &"ZOMBIE_BUILD_PIECE_MISSING" ); + precachestring( &"ZOMBIE_BUILD_PIECE_GRAB" ); + precacheitem( "zombie_builder_zm" ); + precacheitem( "buildable_piece_zm" ); + level.craftable_piece_swap_allowed = 1; + zombie_craftables_callbacks = []; + level.craftablepickups = []; + level.craftables_crafted = []; + level.a_uts_craftables = []; + level.craftable_piece_count = 0; + level._effect[ "building_dust" ] = loadfx( "maps/zombie/fx_zmb_buildable_assemble_dust" ); + if ( isDefined( level.init_craftables ) ) + { + [[ level.init_craftables ]](); + } + open_table = spawnstruct(); + open_table.name = "open_table"; + open_table.triggerthink = ::opentablecraftable; + open_table.custom_craftablestub_update_prompt = ::open_craftablestub_update_prompt; + include_zombie_craftable( open_table ); + add_zombie_craftable( "open_table", &"" ); + if ( isDefined( level.use_swipe_protection ) ) + { + onplayerconnect_callback( ::craftables_watch_swipes ); + } +} + +anystub_update_prompt( player ) +{ + if ( player maps/mp/zombies/_zm_laststand::player_is_in_laststand() || player in_revive_trigger() ) + { + self.hint_string = ""; + return 0; + } + if ( isDefined( player.is_drinking ) && player.is_drinking > 0 ) + { + self.hint_string = ""; + return 0; + } + if ( isDefined( player.screecher_weapon ) ) + { + self.hint_string = ""; + return 0; + } + return 1; +} + +anystub_get_unitrigger_origin() +{ + if ( isDefined( self.origin_parent ) ) + { + return self.origin_parent.origin; + } + return self.origin; +} + +anystub_on_spawn_trigger( trigger ) +{ + if ( isDefined( self.link_parent ) ) + { + trigger enablelinkto(); + trigger linkto( self.link_parent ); + trigger setmovingplatformenabled( 1 ); + } +} + +craftables_watch_swipes() +{ + self endon( "disconnect" ); + self notify( "craftables_watch_swipes" ); + self endon( "craftables_watch_swipes" ); + while ( 1 ) + { + self waittill( "melee_swipe", zombie ); + while ( distancesquared( zombie.origin, self.origin ) > ( zombie.meleeattackdist * zombie.meleeattackdist ) ) + { + continue; + } + trigger = level._unitriggers.trigger_pool[ self getentitynumber() ]; + if ( isDefined( trigger ) && isDefined( trigger.stub.piece ) ) + { + piece = trigger.stub.piece; + if ( !isDefined( piece.damage ) ) + { + piece.damage = 0; + } + piece.damage++; + if ( piece.damage > 12 ) + { + thread maps/mp/zombies/_zm_equipment::equipment_disappear_fx( trigger.stub maps/mp/zombies/_zm_unitrigger::unitrigger_origin() ); + piece maps/mp/zombies/_zm_craftables::piece_unspawn(); + self maps/mp/zombies/_zm_stats::increment_client_stat( "cheat_total", 0 ); + if ( isalive( self ) ) + { + self playlocalsound( level.zmb_laugh_alias ); + } + } + } + } +} + +explosiondamage( damage, pos ) +{ +/# + println( "ZM CRAFTABLE Explode do " + damage + " damage to " + self.name + "\n" ); +#/ + self dodamage( damage, pos ); +} + +make_zombie_craftable_open( str_craftable, str_model, v_angle_offset, v_origin_offset ) +{ +/# + assert( isDefined( level.zombie_craftablestubs[ str_craftable ] ), "Craftable " + str_craftable + " has not been added yet." ); +#/ + precachemodel( str_model ); + s_craftable = level.zombie_craftablestubs[ str_craftable ]; + s_craftable.is_open_table = 1; + s_craftable.str_model = str_model; + s_craftable.v_angle_offset = v_angle_offset; + s_craftable.v_origin_offset = v_origin_offset; +} + +add_zombie_craftable( craftable_name, str_to_craft, str_crafting, str_taken, onfullycrafted, need_all_pieces ) +{ + if ( !isDefined( level.zombie_include_craftables ) ) + { + level.zombie_include_craftables = []; + } + if ( isDefined( level.zombie_include_craftables ) && !isDefined( level.zombie_include_craftables[ craftable_name ] ) ) + { + return; + } + if ( isDefined( str_to_craft ) ) + { + precachestring( str_to_craft ); + } + if ( isDefined( str_crafting ) ) + { + precachestring( str_crafting ); + } + if ( isDefined( str_taken ) ) + { + precachestring( str_taken ); + } + craftable_struct = level.zombie_include_craftables[ craftable_name ]; + if ( !isDefined( level.zombie_craftablestubs ) ) + { + level.zombie_craftablestubs = []; + } + craftable_struct.str_to_craft = str_to_craft; + craftable_struct.str_crafting = str_crafting; + craftable_struct.str_taken = str_taken; + craftable_struct.onfullycrafted = onfullycrafted; + craftable_struct.need_all_pieces = need_all_pieces; +/# + println( "ZM >> Looking for craftable - " + craftable_struct.name ); +#/ + level.zombie_craftablestubs[ craftable_struct.name ] = craftable_struct; + if ( !level.createfx_enabled ) + { + if ( level.zombie_craftablestubs.size == 2 ) + { + bits = getminbitcountfornum( level.craftable_piece_count ); + registerclientfield( "toplayer", "craftable", 9000, bits, "int" ); + } + } +} + +add_zombie_craftable_vox_category( craftable_name, vox_id ) +{ + craftable_struct = level.zombie_include_craftables[ craftable_name ]; + craftable_struct.vox_id = vox_id; +} + +include_zombie_craftable( craftablestub ) +{ + if ( !isDefined( level.zombie_include_craftables ) ) + { + level.zombie_include_craftables = []; + } +/# + println( "ZM >> Including craftable - " + craftablestub.name ); +#/ + level.zombie_include_craftables[ craftablestub.name ] = craftablestub; +} + +generate_zombie_craftable_piece( craftablename, piecename, modelname, radius, height, drop_offset, hud_icon, onpickup, ondrop, oncrafted, use_spawn_num, tag_name, can_reuse, client_field_value, is_shared, vox_id, b_one_time_vo ) +{ + if ( !isDefined( is_shared ) ) + { + is_shared = 0; + } + if ( !isDefined( b_one_time_vo ) ) + { + b_one_time_vo = 0; + } + precachemodel( modelname ); + if ( isDefined( hud_icon ) ) + { + precacheshader( hud_icon ); + } + piecestub = spawnstruct(); + craftable_pieces = []; + piece_alias = ""; + if ( !isDefined( piecename ) ) + { + piecename = modelname; + } + craftable_pieces_structs = getstructarray( ( craftablename + "_" ) + piecename, "targetname" ); +/# + if ( craftable_pieces_structs.size < 1 ) + { + println( "ERROR: Missing craftable piece <" + craftablename + "> <" + piecename + ">\n" ); +#/ + } + _a345 = craftable_pieces_structs; + index = getFirstArrayKey( _a345 ); + while ( isDefined( index ) ) + { + struct = _a345[ index ]; + craftable_pieces[ index ] = struct; + craftable_pieces[ index ].hasspawned = 0; + index = getNextArrayKey( _a345, index ); + } + piecestub.spawns = craftable_pieces; + piecestub.craftablename = craftablename; + piecestub.piecename = piecename; + piecestub.modelname = modelname; + piecestub.hud_icon = hud_icon; + piecestub.radius = radius; + piecestub.height = height; + piecestub.tag_name = tag_name; + piecestub.can_reuse = can_reuse; + piecestub.drop_offset = drop_offset; + piecestub.max_instances = 256; + piecestub.onpickup = onpickup; + piecestub.ondrop = ondrop; + piecestub.oncrafted = oncrafted; + piecestub.use_spawn_num = use_spawn_num; + piecestub.is_shared = is_shared; + piecestub.vox_id = vox_id; + if ( isDefined( b_one_time_vo ) && b_one_time_vo ) + { + piecestub.b_one_time_vo = b_one_time_vo; + } + if ( isDefined( client_field_value ) ) + { + if ( isDefined( is_shared ) && is_shared ) + { +/# + assert( isstring( client_field_value ), "Client field value for shared item (" + piecename + ") should be a string (the name of the ClientField to use)" ); +#/ + piecestub.client_field_id = client_field_value; + } + else + { + piecestub.client_field_state = client_field_value; + } + } + return piecestub; +} + +manage_multiple_pieces( max_instances ) +{ + self.max_instances = max_instances; + self.managing_pieces = 1; + self.piece_allocated = []; +} + +combine_craftable_pieces( piece1, piece2, piece3 ) +{ + spawns1 = piece1.spawns; + spawns2 = piece2.spawns; + spawns = arraycombine( spawns1, spawns2, 1, 0 ); + if ( isDefined( piece3 ) ) + { + spawns3 = piece3.spawns; + spawns = arraycombine( spawns, spawns3, 1, 0 ); + spawns = array_randomize( spawns ); + piece3.spawns = spawns; + } + else + { + spawns = array_randomize( spawns ); + } + piece1.spawns = spawns; + piece2.spawns = spawns; +} + +add_craftable_piece( piecestub, tag_name, can_reuse ) +{ + if ( !isDefined( self.a_piecestubs ) ) + { + self.a_piecestubs = []; + } + if ( isDefined( tag_name ) ) + { + piecestub.tag_name = tag_name; + } + if ( isDefined( can_reuse ) ) + { + piecestub.can_reuse = can_reuse; + } + self.a_piecestubs[ self.a_piecestubs.size ] = piecestub; +} + +player_drop_piece_on_downed() +{ + self endon( "craftable_piece_released" ); + self waittill( "bled_out" ); + onplayerlaststand(); +} + +onplayerlaststand() +{ + piece = self.current_craftable_piece; + if ( isDefined( piece ) ) + { + return_to_start_pos = 0; + if ( isDefined( level.safe_place_for_craftable_piece ) ) + { + if ( !( self [[ level.safe_place_for_craftable_piece ]]( piece ) ) ) + { + return_to_start_pos = 1; + } + } + if ( return_to_start_pos ) + { + piece piece_spawn_at(); + } + else + { + piece piece_spawn_at( self.origin + vectorScale( ( 0, 0, 1 ), 5 ), self.angles ); + } + if ( isDefined( piece.ondrop ) ) + { + piece [[ piece.ondrop ]]( self ); + } + self setclientfieldtoplayer( "craftable", 0 ); + } + self.current_craftable_piece = undefined; + self notify( "craftable_piece_released" ); +} + +piecestub_get_unitrigger_origin() +{ + if ( isDefined( self.origin_parent ) ) + { + return self.origin_parent.origin + vectorScale( ( 0, 0, 1 ), 12 ); + } + return self.origin; +} + +generate_piece_unitrigger( classname, origin, angles, flags, radius, script_height, moving ) +{ + if ( !isDefined( radius ) ) + { + radius = 64; + } + if ( !isDefined( script_height ) ) + { + script_height = 64; + } + script_width = script_height; + if ( !isDefined( script_width ) ) + { + script_width = 64; + } + script_length = script_height; + if ( !isDefined( script_length ) ) + { + script_length = 64; + } + unitrigger_stub = spawnstruct(); + unitrigger_stub.origin = origin; + if ( isDefined( script_length ) ) + { + unitrigger_stub.script_length = script_length; + } + else + { + unitrigger_stub.script_length = 13,5; + } + if ( isDefined( script_width ) ) + { + unitrigger_stub.script_width = script_width; + } + else + { + unitrigger_stub.script_width = 27,5; + } + if ( isDefined( script_height ) ) + { + unitrigger_stub.script_height = script_height; + } + else + { + unitrigger_stub.script_height = 24; + } + unitrigger_stub.radius = radius; + unitrigger_stub.cursor_hint = "HINT_NOICON"; + unitrigger_stub.hint_string = &"ZOMBIE_BUILD_PIECE_GRAB"; + unitrigger_stub.script_unitrigger_type = "unitrigger_box_use"; + unitrigger_stub.require_look_at = 0; + switch( classname ) + { + case "trigger_radius": + unitrigger_stub.script_unitrigger_type = "unitrigger_radius"; + break; + case "trigger_radius_use": + unitrigger_stub.script_unitrigger_type = "unitrigger_radius_use"; + break; + case "trigger_box": + unitrigger_stub.script_unitrigger_type = "unitrigger_box"; + break; + case "trigger_box_use": + unitrigger_stub.script_unitrigger_type = "unitrigger_box_use"; + break; + } + unitrigger_force_per_player_triggers( unitrigger_stub, 1 ); + unitrigger_stub.prompt_and_visibility_func = ::piecetrigger_update_prompt; + unitrigger_stub.originfunc = ::piecestub_get_unitrigger_origin; + unitrigger_stub.onspawnfunc = ::anystub_on_spawn_trigger; + if ( isDefined( moving ) && moving ) + { + maps/mp/zombies/_zm_unitrigger::register_unitrigger( unitrigger_stub, ::piece_unitrigger_think ); + } + else + { + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( unitrigger_stub, ::piece_unitrigger_think ); + } + return unitrigger_stub; +} + +piecetrigger_update_prompt( player ) +{ + can_use = self.stub piecestub_update_prompt( player ); + self setinvisibletoplayer( player, !can_use ); + self sethintstring( self.stub.hint_string ); + return can_use; +} + +piecestub_update_prompt( player ) +{ + if ( !self anystub_update_prompt( player ) ) + { + return 0; + } + if ( isDefined( player.current_craftable_piece ) && isDefined( self.piece.is_shared ) && !self.piece.is_shared ) + { + if ( !level.craftable_piece_swap_allowed ) + { + self.hint_string = &"ZM_CRAFTABLES_PIECE_NO_SWITCH"; + } + else + { + spiece = self.piece; + cpiece = player.current_craftable_piece; + if ( spiece.piecename == cpiece.piecename && spiece.craftablename == cpiece.craftablename ) + { + self.hint_string = ""; + return 0; + } + self.hint_string = &"ZOMBIE_BUILD_PIECE_SWITCH"; + } + } + else + { + self.hint_string = &"ZOMBIE_BUILD_PIECE_GRAB"; + } + return 1; +} + +piece_unitrigger_think() +{ + self endon( "kill_trigger" ); + while ( 1 ) + { + self waittill( "trigger", player ); + while ( player != self.parent_player ) + { + continue; + } + while ( isDefined( player.screecher_weapon ) ) + { + continue; + } + while ( !level.craftable_piece_swap_allowed && isDefined( player.current_craftable_piece ) && isDefined( self.stub.piece.is_shared ) && !self.stub.piece.is_shared ) + { + continue; + } + while ( !is_player_valid( player ) ) + { + player thread ignore_triggers( 0,5 ); + } + status = player player_can_take_piece( self.stub.piece ); + if ( !status ) + { + self.stub.hint_string = ""; + self sethintstring( self.stub.hint_string ); + continue; + } + else + { + player thread player_take_piece( self.stub.piece ); + } + } +} + +player_can_take_piece( piece ) +{ + if ( !isDefined( piece ) ) + { + return 0; + } + return 1; +} + +dbline( from, to ) +{ +/# + time = 20; + while ( time > 0 ) + { + line( from, to, ( 0, 0, 1 ), 0, 1 ); + time -= 0,05; + wait 0,05; +#/ + } +} + +player_throw_piece( piece, origin, dir, return_to_spawn, return_time, endangles ) +{ +/# + assert( isDefined( piece ) ); +#/ + if ( isDefined( piece ) ) + { +/# + thread dbline( origin, origin + dir ); +#/ + pass = 0; + done = 0; + altmodel = undefined; + while ( pass < 2 && !done ) + { + grenade = self magicgrenadetype( "buildable_piece_zm", origin, dir, 30000 ); + grenade thread watch_hit_players(); + grenade ghost(); + if ( !isDefined( altmodel ) ) + { + altmodel = spawn( "script_model", grenade.origin ); + altmodel setmodel( piece.modelname ); + } + altmodel.origin = grenade.angles; + altmodel.angles = grenade.angles; + altmodel linkto( grenade, "", ( 0, 0, 1 ), ( 0, 0, 1 ) ); + grenade.altmodel = altmodel; + grenade waittill( "stationary" ); + grenade_origin = grenade.origin; + grenade_angles = grenade.angles; + landed_on = grenade getgroundent(); + grenade delete(); + if ( isDefined( landed_on ) && landed_on == level ) + { + done = 1; + continue; + } + else + { + origin = grenade_origin; + dir = ( ( dir[ 0 ] * -1 ) / 10, ( dir[ 1 ] * -1 ) / 10, -1 ); + pass++; + } + } + if ( !isDefined( endangles ) ) + { + endangles = grenade_angles; + } + piece piece_spawn_at( grenade_origin, endangles ); + if ( isDefined( altmodel ) ) + { + altmodel delete(); + } + if ( isDefined( piece.ondrop ) ) + { + piece [[ piece.ondrop ]]( self ); + } + if ( isDefined( return_to_spawn ) && return_to_spawn ) + { + piece piece_wait_and_return( return_time ); + } + } +} + +watch_hit_players() +{ + self endon( "death" ); + self endon( "stationary" ); + while ( isDefined( self ) ) + { + self waittill( "grenade_bounce", pos, normal, ent ); + if ( isplayer( ent ) ) + { + ent explosiondamage( 25, pos ); + } + } +} + +piece_wait_and_return( return_time ) +{ + self endon( "pickup" ); + wait 0,15; + if ( isDefined( level.exploding_jetgun_fx ) ) + { + playfxontag( level.exploding_jetgun_fx, self.model, "tag_origin" ); + } + else + { + playfxontag( level._effect[ "powerup_on" ], self.model, "tag_origin" ); + } + wait ( return_time - 6 ); + self piece_hide(); + wait 1; + self piece_show(); + wait 1; + self piece_hide(); + wait 1; + self piece_show(); + wait 1; + self piece_hide(); + wait 1; + self piece_show(); + wait 1; + self notify( "respawn" ); + self piece_unspawn(); + self piece_spawn_at(); +} + +player_return_piece_to_original_spawn() +{ + self notify( "craftable_piece_released" ); + piece = self.current_craftable_piece; + self.current_craftable_piece = undefined; + if ( isDefined( piece ) ) + { + piece piece_spawn_at(); + self setclientfieldtoplayer( "craftable", 0 ); + } +} + +player_drop_piece_on_death() +{ + self notify( "craftable_piece_released" ); + self endon( "craftable_piece_released" ); + self thread player_drop_piece_on_downed(); + origin = self.origin; + angles = self.angles; + piece = self.current_craftable_piece; + self waittill( "disconnect" ); + piece piece_spawn_at( origin, angles ); + if ( isDefined( self ) ) + { + self setclientfieldtoplayer( "craftable", 0 ); + } +} + +player_drop_piece( piece ) +{ + if ( !isDefined( piece ) ) + { + piece = self.current_craftable_piece; + } + if ( isDefined( piece ) ) + { + piece.damage = 0; + piece piece_spawn_at( self.origin, self.angles ); + self setclientfieldtoplayer( "craftable", 0 ); + if ( isDefined( piece.ondrop ) ) + { + piece [[ piece.ondrop ]]( self ); + } + } + self.current_craftable_piece = undefined; + self notify( "craftable_piece_released" ); +} + +player_take_piece( piecespawn ) +{ + piecestub = piecespawn.piecestub; + damage = piecespawn.damage; + if ( isDefined( piecestub.is_shared ) && !piecestub.is_shared && isDefined( self.current_craftable_piece ) ) + { + other_piece = self.current_craftable_piece; + self player_drop_piece( self.current_craftable_piece ); + other_piece.damage = damage; + self do_player_general_vox( "general", "craft_swap" ); + } + if ( isDefined( piecestub.onpickup ) ) + { + piecespawn [[ piecestub.onpickup ]]( self ); + } + if ( isDefined( piecestub.is_shared ) && piecestub.is_shared ) + { + if ( isDefined( piecestub.client_field_id ) ) + { + level setclientfield( piecestub.client_field_id, 1 ); + } + } + else + { + if ( isDefined( piecestub.client_field_state ) ) + { + self setclientfieldtoplayer( "craftable", piecestub.client_field_state ); + } + } + piecespawn piece_unspawn(); + piecespawn notify( "pickup" ); + if ( isDefined( piecestub.is_shared ) && piecestub.is_shared ) + { + piecespawn.in_shared_inventory = 1; + } + else + { + self.current_craftable_piece = piecespawn; + self thread player_drop_piece_on_death(); + } + self track_craftable_piece_pickedup( piecespawn ); +} + +player_destroy_piece( piece ) +{ + if ( !isDefined( piece ) ) + { + piece = self.current_craftable_piece; + } + if ( isDefined( piece ) ) + { + self setclientfieldtoplayer( "craftable", 0 ); + } + self.current_craftable_piece = undefined; + self notify( "craftable_piece_released" ); +} + +claim_location( location ) +{ + if ( !isDefined( level.craftable_claimed_locations ) ) + { + level.craftable_claimed_locations = []; + } + if ( !isDefined( level.craftable_claimed_locations[ location ] ) ) + { + level.craftable_claimed_locations[ location ] = 1; + return 1; + } + return 0; +} + +is_point_in_craft_trigger( point ) +{ + candidate_list = []; + _a958 = level.zones; + _k958 = getFirstArrayKey( _a958 ); + while ( isDefined( _k958 ) ) + { + zone = _a958[ _k958 ]; + if ( isDefined( zone.unitrigger_stubs ) ) + { + candidate_list = arraycombine( candidate_list, zone.unitrigger_stubs, 1, 0 ); + } + _k958 = getNextArrayKey( _a958, _k958 ); + } + valid_range = 128; + closest = maps/mp/zombies/_zm_unitrigger::get_closest_unitriggers( point, candidate_list, valid_range ); + index = 0; + while ( index < closest.size ) + { + if ( isDefined( closest[ index ].registered ) && closest[ index ].registered && isDefined( closest[ index ].piece ) ) + { + return 1; + } + index++; + } + return 0; +} + +piece_allocate_spawn( piecestub ) +{ + self.current_spawn = 0; + self.managed_spawn = 1; + self.piecestub = piecestub; + if ( self.spawns.size >= 1 && self.spawns.size > 1 ) + { + any_good = 0; + any_okay = 0; + totalweight = 0; + spawnweights = []; + i = 0; + while ( i < self.spawns.size ) + { + if ( isDefined( piecestub.piece_allocated[ i ] ) && piecestub.piece_allocated[ i ] ) + { + spawnweights[ i ] = 0; + } + else + { + if ( is_point_in_craft_trigger( self.spawns[ i ].origin ) ) + { + any_okay = 1; + spawnweights[ i ] = 0,01; + break; + } + else + { + any_good = 1; + spawnweights[ i ] = 1; + } + } + totalweight += spawnweights[ i ]; + i++; + } +/# + if ( !any_good ) + { + assert( any_okay, "There is nowhere to spawn this piece" ); + } +#/ + if ( any_good ) + { + totalweight = float( int( totalweight ) ); + } + r = randomfloat( totalweight ); + i = 0; + while ( i < self.spawns.size ) + { + if ( !any_good || spawnweights[ i ] >= 1 ) + { + r -= spawnweights[ i ]; + if ( r < 0 ) + { + self.current_spawn = i; + piecestub.piece_allocated[ self.current_spawn ] = 1; + return; + } + } + i++; + } + self.current_spawn = randomint( self.spawns.size ); + piecestub.piece_allocated[ self.current_spawn ] = 1; + } +} + +piece_deallocate_spawn() +{ + if ( isDefined( self.current_spawn ) ) + { + self.piecestub.piece_allocated[ self.current_spawn ] = 0; + self.current_spawn = undefined; + } + self.start_origin = undefined; +} + +piece_pick_random_spawn() +{ + self.current_spawn = 0; + while ( self.spawns.size >= 1 && self.spawns.size > 1 ) + { + self.current_spawn = randomint( self.spawns.size ); + while ( isDefined( self.spawns[ self.current_spawn ].claim_location ) && !claim_location( self.spawns[ self.current_spawn ].claim_location ) ) + { + arrayremoveindex( self.spawns, self.current_spawn ); + if ( self.spawns.size < 1 ) + { + self.current_spawn = 0; +/# + println( "ERROR: All craftable spawn locations claimed" ); +#/ + return; + } + self.current_spawn = randomint( self.spawns.size ); + } + } +} + +piece_set_spawn( num ) +{ + self.current_spawn = 0; + if ( self.spawns.size >= 1 && self.spawns.size > 1 ) + { + self.current_spawn = int( min( num, self.spawns.size - 1 ) ); + } +} + +piece_spawn_in( piecestub ) +{ + if ( self.spawns.size < 1 ) + { + return; + } + if ( isDefined( self.managed_spawn ) && self.managed_spawn ) + { + if ( !isDefined( self.current_spawn ) ) + { + self piece_allocate_spawn( self.piecestub ); + } + } + if ( !isDefined( self.current_spawn ) ) + { + self.current_spawn = 0; + } + spawndef = self.spawns[ self.current_spawn ]; + self.unitrigger = generate_piece_unitrigger( "trigger_radius_use", spawndef.origin + vectorScale( ( 0, 0, 1 ), 12 ), spawndef.angles, 0, piecestub.radius, piecestub.height, 0 ); + self.unitrigger.piece = self; + self.radius = piecestub.radius; + self.height = piecestub.height; + self.craftablename = piecestub.craftablename; + self.piecename = piecestub.piecename; + self.modelname = piecestub.modelname; + self.hud_icon = piecestub.hud_icon; + self.tag_name = piecestub.tag_name; + self.drop_offset = piecestub.drop_offset; + self.start_origin = spawndef.origin; + self.start_angles = spawndef.angles; + self.client_field_state = piecestub.client_field_state; + self.is_shared = piecestub.is_shared; + self.model = spawn( "script_model", self.start_origin ); + if ( isDefined( self.start_angles ) ) + { + self.model.angles = self.start_angles; + } + self.model setmodel( piecestub.modelname ); + if ( isDefined( piecestub.onspawn ) ) + { + self [[ piecestub.onspawn ]](); + } + self.model ghostindemo(); + self.model.hud_icon = piecestub.hud_icon; + self.piecestub = piecestub; + self.unitrigger.origin_parent = self.model; +} + +piece_spawn_at( origin, angles, use_random_start ) +{ + if ( self.spawns.size < 1 ) + { + return; + } + if ( isDefined( self.managed_spawn ) && self.managed_spawn ) + { + if ( !isDefined( self.current_spawn ) && !isDefined( origin ) ) + { + self piece_allocate_spawn( self.piecestub ); + spawndef = self.spawns[ self.current_spawn ]; + self.start_origin = spawndef.origin; + self.start_angles = spawndef.angles; + } + } + else + { + if ( !isDefined( self.current_spawn ) ) + { + self.current_spawn = 0; + } + } + unitrigger_offset = vectorScale( ( 0, 0, 1 ), 12 ); + if ( isDefined( use_random_start ) && use_random_start ) + { + self piece_pick_random_spawn(); + spawndef = self.spawns[ self.current_spawn ]; + self.start_origin = spawndef.origin; + self.start_angles = spawndef.angles; + origin = spawndef.origin; + angles = spawndef.angles; + } + else + { + if ( !isDefined( origin ) ) + { + origin = self.start_origin; + } + else + { + origin += ( 0, 0, self.drop_offset ); + unitrigger_offset -= ( 0, 0, self.drop_offset ); + } + if ( !isDefined( angles ) ) + { + angles = self.start_angles; + } +/# + if ( !isDefined( level.drop_offset ) ) + { + level.drop_offset = 0; + } + origin += ( 0, 0, level.drop_offset ); + unitrigger_offset -= ( 0, 0, level.drop_offset ); +#/ + } + self.model = spawn( "script_model", origin ); + if ( isDefined( angles ) ) + { + self.model.angles = angles; + } + self.model setmodel( self.modelname ); + if ( isDefined( level.equipment_safe_to_drop ) ) + { + if ( !( [[ level.equipment_safe_to_drop ]]( self.model ) ) ) + { + origin = self.start_origin; + angles = self.start_angles; + self.model.origin = origin; + self.model.angles = angles; + } + } + if ( isDefined( self.onspawn ) ) + { + self [[ self.onspawn ]](); + } + if ( isDefined( self.model.canmove ) ) + { + self.unitrigger = generate_piece_unitrigger( "trigger_radius_use", origin + unitrigger_offset, angles, 0, self.radius, self.height, self.model.canmove ); + } + self.unitrigger.piece = self; + self.model.hud_icon = self.hud_icon; + self.unitrigger.origin_parent = self.model; +} + +piece_unspawn() +{ + if ( isDefined( self.managed_spawn ) && self.managed_spawn ) + { + self piece_deallocate_spawn(); + } + if ( isDefined( self.model ) ) + { + self.model delete(); + } + self.model = undefined; + if ( isDefined( self.unitrigger ) ) + { + thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( self.unitrigger ); + } + self.unitrigger = undefined; +} + +piece_hide() +{ + if ( isDefined( self.model ) ) + { + self.model ghost(); + } +} + +piece_show() +{ + if ( isDefined( self.model ) ) + { + self.model show(); + } +} + +generate_piece( piecestub ) +{ + piecespawn = spawnstruct(); + piecespawn.spawns = piecestub.spawns; + if ( isDefined( piecestub.managing_pieces ) && piecestub.managing_pieces ) + { + piecespawn piece_allocate_spawn( piecestub ); + } + else + { + if ( isDefined( piecestub.use_spawn_num ) ) + { + piecespawn piece_set_spawn( piecestub.use_spawn_num ); + } + else + { + piecespawn piece_pick_random_spawn(); + } + } + piecespawn piece_spawn_in( piecestub ); + if ( piecespawn.spawns.size >= 1 ) + { + piecespawn.hud_icon = piecestub.hud_icon; + } + if ( isDefined( piecestub.onpickup ) ) + { + piecespawn.onpickup = piecestub.onpickup; + } + else + { + piecespawn.onpickup = ::onpickuputs; + } + if ( isDefined( piecestub.ondrop ) ) + { + piecespawn.ondrop = piecestub.ondrop; + } + else + { + piecespawn.ondrop = ::ondroputs; + } + if ( isDefined( piecestub.oncrafted ) ) + { + piecespawn.oncrafted = piecestub.oncrafted; + } + return piecespawn; +} + +craftable_piece_unitriggers( craftable_name, origin ) +{ +/# + assert( isDefined( craftable_name ) ); +#/ +/# + assert( isDefined( level.zombie_craftablestubs[ craftable_name ] ), "Called craftable_think() without including the craftable - " + craftable_name ); +#/ + craftable = level.zombie_craftablestubs[ craftable_name ]; + if ( !isDefined( craftable.a_piecestubs ) ) + { + craftable.a_piecestubs = []; + } + flag_wait( "start_zombie_round_logic" ); + craftablespawn = spawnstruct(); + craftablespawn.craftable_name = craftable_name; + if ( !isDefined( craftablespawn.a_piecespawns ) ) + { + craftablespawn.a_piecespawns = []; + } + craftablepickups = []; + _a1320 = craftable.a_piecestubs; + _k1320 = getFirstArrayKey( _a1320 ); + while ( isDefined( _k1320 ) ) + { + piecestub = _a1320[ _k1320 ]; + if ( !isDefined( piecestub.generated_instances ) ) + { + piecestub.generated_instances = 0; + } + if ( isDefined( piecestub.piecespawn ) && isDefined( piecestub.can_reuse ) && piecestub.can_reuse ) + { + piece = piecestub.piecespawn; + } + else + { + if ( piecestub.generated_instances >= piecestub.max_instances ) + { + piece = piecestub.piecespawn; + break; + } + else + { + piece = generate_piece( piecestub ); + piecestub.piecespawn = piece; + piecestub.generated_instances++; + } + } + craftablespawn.a_piecespawns[ craftablespawn.a_piecespawns.size ] = piece; + _k1320 = getNextArrayKey( _a1320, _k1320 ); + } + craftablespawn.stub = self; + return craftablespawn; +} + +hide_craftable_table_model( trigger_targetname ) +{ + trig = getent( trigger_targetname, "targetname" ); + if ( !isDefined( trig ) ) + { + return; + } + if ( isDefined( trig.target ) ) + { + model = getent( trig.target, "targetname" ); + if ( isDefined( model ) ) + { + model ghost(); + model notsolid(); + } + } +} + +setup_unitrigger_craftable( trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ) +{ + trig = getent( trigger_targetname, "targetname" ); + if ( !isDefined( trig ) ) + { + return; + } + return setup_unitrigger_craftable_internal( trig, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ); +} + +setup_unitrigger_craftable_array( trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ) +{ + triggers = getentarray( trigger_targetname, "targetname" ); + stubs = []; + _a1382 = triggers; + _k1382 = getFirstArrayKey( _a1382 ); + while ( isDefined( _k1382 ) ) + { + trig = _a1382[ _k1382 ]; + stubs[ stubs.size ] = setup_unitrigger_craftable_internal( trig, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ); + _k1382 = getNextArrayKey( _a1382, _k1382 ); + } + return stubs; +} + +setup_unitrigger_craftable_internal( trig, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ) +{ + if ( !isDefined( trig ) ) + { + return; + } + unitrigger_stub = spawnstruct(); + unitrigger_stub.craftablestub = level.zombie_include_craftables[ equipname ]; + angles = trig.script_angles; + if ( !isDefined( angles ) ) + { + angles = ( 0, 0, 1 ); + } + unitrigger_stub.origin = trig.origin + ( anglesToRight( angles ) * -6 ); + unitrigger_stub.angles = trig.angles; + if ( isDefined( trig.script_angles ) ) + { + unitrigger_stub.angles = trig.script_angles; + } + unitrigger_stub.equipname = equipname; + unitrigger_stub.weaponname = weaponname; + unitrigger_stub.trigger_hintstring = trigger_hintstring; + unitrigger_stub.delete_trigger = delete_trigger; + unitrigger_stub.crafted = 0; + unitrigger_stub.persistent = persistent; + unitrigger_stub.usetime = int( 3000 ); + unitrigger_stub.onbeginuse = ::onbeginuseuts; + unitrigger_stub.onenduse = ::onenduseuts; + unitrigger_stub.onuse = ::onuseplantobjectuts; + unitrigger_stub.oncantuse = ::oncantuseuts; + if ( isDefined( trig.script_length ) ) + { + unitrigger_stub.script_length = trig.script_length; + } + else + { + unitrigger_stub.script_length = 32; + } + if ( isDefined( trig.script_width ) ) + { + unitrigger_stub.script_width = trig.script_width; + } + else + { + unitrigger_stub.script_width = 100; + } + if ( isDefined( trig.script_height ) ) + { + unitrigger_stub.script_height = trig.script_height; + } + else + { + unitrigger_stub.script_height = 64; + } + unitrigger_stub.target = trig.target; + unitrigger_stub.targetname = trig.targetname; + unitrigger_stub.script_noteworthy = trig.script_noteworthy; + unitrigger_stub.script_parameters = trig.script_parameters; + unitrigger_stub.cursor_hint = "HINT_NOICON"; + if ( isDefined( level.zombie_craftablestubs[ equipname ].str_to_craft ) ) + { + unitrigger_stub.hint_string = level.zombie_craftablestubs[ equipname ].str_to_craft; + } + unitrigger_stub.script_unitrigger_type = "unitrigger_box_use"; + unitrigger_stub.require_look_at = 1; + unitrigger_force_per_player_triggers( unitrigger_stub, 1 ); + if ( isDefined( unitrigger_stub.craftablestub.custom_craftablestub_update_prompt ) ) + { + unitrigger_stub.custom_craftablestub_update_prompt = unitrigger_stub.craftablestub.custom_craftablestub_update_prompt; + } + unitrigger_stub.prompt_and_visibility_func = ::craftabletrigger_update_prompt; + maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( unitrigger_stub, ::craftable_place_think ); + unitrigger_stub.piece_trigger = trig; + trig.trigger_stub = unitrigger_stub; + unitrigger_stub.zombie_weapon_upgrade = trig.zombie_weapon_upgrade; + if ( isDefined( unitrigger_stub.target ) ) + { + unitrigger_stub.model = getent( unitrigger_stub.target, "targetname" ); + if ( isDefined( unitrigger_stub.model ) ) + { + if ( isDefined( unitrigger_stub.zombie_weapon_upgrade ) ) + { + unitrigger_stub.model useweaponhidetags( unitrigger_stub.zombie_weapon_upgrade ); + } + unitrigger_stub.model ghost(); + unitrigger_stub.model notsolid(); + } + } + if ( unitrigger_stub.equipname == "open_table" ) + { + unitrigger_stub.a_uts_open_craftables_available = []; + unitrigger_stub.n_open_craftable_choice = -1; + unitrigger_stub.b_open_craftable_checking_input = 0; + } + unitrigger_stub.craftablespawn = unitrigger_stub craftable_piece_unitriggers( equipname, unitrigger_stub.origin ); + if ( delete_trigger ) + { + trig delete(); + } + level.a_uts_craftables[ level.a_uts_craftables.size ] = unitrigger_stub; + return unitrigger_stub; +} + +setup_craftable_pieces() +{ + unitrigger_stub = spawnstruct(); + unitrigger_stub.craftablestub = level.zombie_include_craftables[ self.name ]; + unitrigger_stub.equipname = self.name; + unitrigger_stub.craftablespawn = unitrigger_stub craftable_piece_unitriggers( self.name, unitrigger_stub.origin ); + level.a_uts_craftables[ level.a_uts_craftables.size ] = unitrigger_stub; + return unitrigger_stub; +} + +craftable_has_piece( piece ) +{ + i = 0; + while ( i < self.a_piecespawns.size ) + { + if ( self.a_piecespawns[ i ].piecename == piece.piecename && self.a_piecespawns[ i ].craftablename == piece.craftablename ) + { + return 1; + } + i++; + } + return 0; +} + +get_actual_uts_craftable() +{ + if ( self.craftable_name == "open_table" && self.n_open_craftable_choice != -1 ) + { + return self.stub.a_uts_open_craftables_available[ self.n_open_craftable_choice ]; + } + else + { + return self.stub; + } +} + +get_actual_craftablespawn() +{ + if ( self.craftable_name == "open_table" && self.stub.n_open_craftable_choice != -1 && isDefined( self.stub.a_uts_open_craftables_available[ self.stub.n_open_craftable_choice ].craftablespawn ) ) + { + return self.stub.a_uts_open_craftables_available[ self.stub.n_open_craftable_choice ].craftablespawn; + } + else + { + return self; + } +} + +craftable_can_use_shared_piece() +{ + uts_craftable = self.stub; + if ( isDefined( uts_craftable.n_open_craftable_choice ) && uts_craftable.n_open_craftable_choice != -1 && isDefined( uts_craftable.a_uts_open_craftables_available[ uts_craftable.n_open_craftable_choice ] ) ) + { + return 1; + } + if ( isDefined( uts_craftable.craftablestub.need_all_pieces ) && uts_craftable.craftablestub.need_all_pieces ) + { + _a1601 = self.a_piecespawns; + _k1601 = getFirstArrayKey( _a1601 ); + while ( isDefined( _k1601 ) ) + { + piece = _a1601[ _k1601 ]; + if ( isDefined( piece.in_shared_inventory ) && !piece.in_shared_inventory ) + { + return 0; + } + _k1601 = getNextArrayKey( _a1601, _k1601 ); + } + return 1; + } + else + { + _a1614 = self.a_piecespawns; + _k1614 = getFirstArrayKey( _a1614 ); + while ( isDefined( _k1614 ) ) + { + piece = _a1614[ _k1614 ]; + if ( isDefined( piece.crafted ) && !piece.crafted && isDefined( piece.in_shared_inventory ) && piece.in_shared_inventory ) + { + return 1; + } + _k1614 = getNextArrayKey( _a1614, _k1614 ); + } + } + return 0; +} + +craftable_set_piece_crafted( piecespawn_check, player ) +{ + craftablespawn_check = get_actual_craftablespawn(); + _a1631 = craftablespawn_check.a_piecespawns; + _k1631 = getFirstArrayKey( _a1631 ); + while ( isDefined( _k1631 ) ) + { + piecespawn = _a1631[ _k1631 ]; + if ( isDefined( piecespawn_check ) ) + { + if ( piecespawn.piecename == piecespawn_check.piecename && piecespawn.craftablename == piecespawn_check.craftablename ) + { + piecespawn.crafted = 1; + if ( isDefined( piecespawn.oncrafted ) ) + { + piecespawn thread [[ piecespawn.oncrafted ]]( player ); + } + } + } + else + { + if ( isDefined( piecespawn.is_shared ) && piecespawn.is_shared && isDefined( piecespawn.in_shared_inventory ) && piecespawn.in_shared_inventory ) + { + piecespawn.crafted = 1; + if ( isDefined( piecespawn.oncrafted ) ) + { + piecespawn thread [[ piecespawn.oncrafted ]]( player ); + } + piecespawn.in_shared_inventory = 0; + } + } + _k1631 = getNextArrayKey( _a1631, _k1631 ); + } +} + +craftable_set_piece_crafting( piecespawn_check ) +{ + craftablespawn_check = get_actual_craftablespawn(); + _a1670 = craftablespawn_check.a_piecespawns; + _k1670 = getFirstArrayKey( _a1670 ); + while ( isDefined( _k1670 ) ) + { + piecespawn = _a1670[ _k1670 ]; + if ( isDefined( piecespawn_check ) ) + { + if ( piecespawn.piecename == piecespawn_check.piecename && piecespawn.craftablename == piecespawn_check.craftablename ) + { + piecespawn.crafting = 1; + } + } + if ( isDefined( piecespawn.is_shared ) && piecespawn.is_shared && isDefined( piecespawn.in_shared_inventory ) && piecespawn.in_shared_inventory ) + { + piecespawn.crafting = 1; + } + _k1670 = getNextArrayKey( _a1670, _k1670 ); + } +} + +craftable_clear_piece_crafting( piecespawn_check ) +{ + if ( isDefined( piecespawn_check ) ) + { + piecespawn_check.crafting = 0; + } + craftablespawn_check = get_actual_craftablespawn(); + _a1699 = craftablespawn_check.a_piecespawns; + _k1699 = getFirstArrayKey( _a1699 ); + while ( isDefined( _k1699 ) ) + { + piecespawn = _a1699[ _k1699 ]; + if ( isDefined( piecespawn.is_shared ) && piecespawn.is_shared && isDefined( piecespawn.in_shared_inventory ) && piecespawn.in_shared_inventory ) + { + piecespawn.crafting = 0; + } + _k1699 = getNextArrayKey( _a1699, _k1699 ); + } +} + +craftable_is_piece_crafted( piece ) +{ + i = 0; + while ( i < self.a_piecespawns.size ) + { + if ( self.a_piecespawns[ i ].piecename == piece.piecename && self.a_piecespawns[ i ].craftablename == piece.craftablename ) + { + if ( isDefined( self.a_piecespawns[ i ].crafted ) ) + { + return self.a_piecespawns[ i ].crafted; + } + } + i++; + } + return 0; +} + +craftable_is_piece_crafting( piecespawn_check ) +{ + craftablespawn_check = get_actual_craftablespawn(); + _a1726 = craftablespawn_check.a_piecespawns; + _k1726 = getFirstArrayKey( _a1726 ); + while ( isDefined( _k1726 ) ) + { + piecespawn = _a1726[ _k1726 ]; + if ( isDefined( piecespawn_check ) ) + { + if ( piecespawn.piecename == piecespawn_check.piecename && piecespawn.craftablename == piecespawn_check.craftablename ) + { + return piecespawn.crafting; + } + } + if ( isDefined( piecespawn.is_shared ) && piecespawn.is_shared && isDefined( piecespawn.in_shared_inventory ) && piecespawn.in_shared_inventory && isDefined( piecespawn.crafting ) && piecespawn.crafting ) + { + return 1; + } + _k1726 = getNextArrayKey( _a1726, _k1726 ); + } + return 0; +} + +craftable_is_piece_crafted_or_crafting( piece ) +{ + i = 0; + while ( i < self.a_piecespawns.size ) + { + if ( self.a_piecespawns[ i ].piecename == piece.piecename && self.a_piecespawns[ i ].craftablename == piece.craftablename ) + { + if ( isDefined( self.a_piecespawns[ i ].crafted ) && !self.a_piecespawns[ i ].crafted ) + { + if ( isDefined( self.a_piecespawns[ i ].crafting ) ) + { + return self.a_piecespawns[ i ].crafting; + } + } + } + i++; + } + return 0; +} + +craftable_all_crafted() +{ + i = 0; + while ( i < self.a_piecespawns.size ) + { + if ( isDefined( self.a_piecespawns[ i ].crafted ) && !self.a_piecespawns[ i ].crafted ) + { + return 0; + } + i++; + } + return 1; +} + +waittill_crafted( craftable_name ) +{ + level waittill( craftable_name + "_crafted", player ); + return player; +} + +player_can_craft( craftablespawn, continuing ) +{ + if ( !isDefined( craftablespawn ) ) + { + return 0; + } + if ( !craftablespawn craftable_can_use_shared_piece() ) + { + if ( !isDefined( self.current_craftable_piece ) ) + { + return 0; + } + if ( !craftablespawn craftable_has_piece( self.current_craftable_piece ) ) + { + return 0; + } + if ( isDefined( continuing ) && continuing ) + { + if ( craftablespawn craftable_is_piece_crafted( self.current_craftable_piece ) ) + { + return 0; + } + } + else + { + if ( craftablespawn craftable_is_piece_crafted_or_crafting( self.current_craftable_piece ) ) + { + return 0; + } + } + } + if ( isDefined( craftablespawn.stub ) && isDefined( craftablespawn.stub.custom_craftablestub_update_prompt ) && isDefined( craftablespawn.stub.playertrigger[ 0 ] ) && isDefined( craftablespawn.stub.playertrigger[ 0 ].stub ) && !( craftablespawn.stub.playertrigger[ 0 ].stub [[ craftablespawn.stub.custom_craftablestub_update_prompt ]]( self, 1, craftablespawn.stub.playertrigger[ self getentitynumber() ] ) ) ) + { + return 0; + } + return 1; +} + +craftable_transfer_data() +{ + uts_craftable = self.stub; + if ( uts_craftable.n_open_craftable_choice == -1 || !isDefined( uts_craftable.a_uts_open_craftables_available[ uts_craftable.n_open_craftable_choice ] ) ) + { + return; + } + uts_source = uts_craftable.a_uts_open_craftables_available[ uts_craftable.n_open_craftable_choice ]; + uts_target = uts_craftable; + uts_target.craftablestub = uts_source.craftablestub; + uts_target.craftablespawn = uts_source.craftablespawn; + uts_target.crafted = uts_source.crafted; + uts_target.cursor_hint = uts_source.cursor_hint; + uts_target.custom_craftable_update_prompt = uts_source.custom_craftable_update_prompt; + uts_target.equipname = uts_source.equipname; + uts_target.hint_string = uts_source.hint_string; + uts_target.persistent = uts_source.persistent; + uts_target.prompt_and_visibility_func = uts_source.prompt_and_visibility_func; + uts_target.trigger_func = uts_source.trigger_func; + uts_target.trigger_hintstring = uts_source.trigger_hintstring; + uts_target.weaponname = uts_source.weaponname; + uts_target.craftablespawn.stub = uts_target; + thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( uts_source ); + uts_source craftablestub_remove(); + return uts_target; +} + +player_craft( craftablespawn ) +{ + craftablespawn craftable_set_piece_crafted( self.current_craftable_piece, self ); + if ( isDefined( self.current_craftable_piece ) && isDefined( self.current_craftable_piece.crafted ) && self.current_craftable_piece.crafted ) + { + player_destroy_piece( self.current_craftable_piece ); + } + if ( isDefined( craftablespawn.stub.n_open_craftable_choice ) ) + { + uts_craftable = craftablespawn craftable_transfer_data(); + craftablespawn = uts_craftable.craftablespawn; + update_open_table_status(); + } + else + { + uts_craftable = craftablespawn.stub; + } + if ( !isDefined( uts_craftable.model ) && isDefined( uts_craftable.craftablestub.str_model ) ) + { + craftablestub = uts_craftable.craftablestub; + s_model = getstruct( uts_craftable.target, "targetname" ); + if ( isDefined( s_model ) ) + { + m_spawn = spawn( "script_model", s_model.origin ); + if ( isDefined( craftablestub.v_origin_offset ) ) + { + m_spawn.origin += craftablestub.v_origin_offset; + } + m_spawn.angles = s_model.angles; + if ( isDefined( craftablestub.v_angle_offset ) ) + { + m_spawn.angles += craftablestub.v_angle_offset; + } + m_spawn setmodel( craftablestub.str_model ); + uts_craftable.model = m_spawn; + } + } + while ( isDefined( uts_craftable.model ) ) + { + i = 0; + while ( i < craftablespawn.a_piecespawns.size ) + { + if ( isDefined( craftablespawn.a_piecespawns[ i ].tag_name ) ) + { + uts_craftable.model notsolid(); + if ( isDefined( craftablespawn.a_piecespawns[ i ].crafted ) && !craftablespawn.a_piecespawns[ i ].crafted ) + { + uts_craftable.model hidepart( craftablespawn.a_piecespawns[ i ].tag_name ); + i++; + continue; + } + else + { + uts_craftable.model show(); + uts_craftable.model showpart( craftablespawn.a_piecespawns[ i ].tag_name ); + } + } + i++; + } + } + self track_craftable_pieces_crafted( craftablespawn ); + if ( craftablespawn craftable_all_crafted() ) + { + self player_finish_craftable( craftablespawn ); + self track_craftables_crafted( craftablespawn ); + if ( isDefined( level.craftable_crafted_custom_func ) ) + { + self thread [[ level.craftable_crafted_custom_func ]]( craftablespawn ); + } + self playsound( "zmb_buildable_complete" ); + } + else + { + self playsound( "zmb_buildable_piece_add" ); +/# + assert( isDefined( level.zombie_craftablestubs[ craftablespawn.craftable_name ].str_crafting ), "Missing builing hint" ); +#/ + if ( isDefined( level.zombie_craftablestubs[ craftablespawn.craftable_name ].str_crafting ) ) + { + return level.zombie_craftablestubs[ craftablespawn.craftable_name ].str_crafting; + } + } + return ""; +} + +update_open_table_status() +{ + b_open_craftables_remaining = 0; + _a1969 = level.a_uts_craftables; + _k1969 = getFirstArrayKey( _a1969 ); + while ( isDefined( _k1969 ) ) + { + uts_craftable = _a1969[ _k1969 ]; + if ( isDefined( level.zombie_include_craftables[ uts_craftable.equipname ] ) && isDefined( level.zombie_include_craftables[ uts_craftable.equipname ].is_open_table ) && level.zombie_include_craftables[ uts_craftable.equipname ].is_open_table ) + { + b_piece_crafted = 0; + _a1976 = uts_craftable.craftablespawn.a_piecespawns; + _k1976 = getFirstArrayKey( _a1976 ); + while ( isDefined( _k1976 ) ) + { + piecespawn = _a1976[ _k1976 ]; + if ( isDefined( piecespawn.crafted ) && piecespawn.crafted ) + { + b_piece_crafted = 1; + break; + } + else + { + _k1976 = getNextArrayKey( _a1976, _k1976 ); + } + } + if ( !b_piece_crafted ) + { + b_open_craftables_remaining = 1; + } + } + _k1969 = getNextArrayKey( _a1969, _k1969 ); + } + while ( !b_open_craftables_remaining ) + { + _a1995 = level.a_uts_craftables; + _k1995 = getFirstArrayKey( _a1995 ); + while ( isDefined( _k1995 ) ) + { + uts_craftable = _a1995[ _k1995 ]; + if ( uts_craftable.equipname == "open_table" ) + { + thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( uts_craftable ); + } + _k1995 = getNextArrayKey( _a1995, _k1995 ); + } + } +} + +player_finish_craftable( craftablespawn ) +{ + craftablespawn.crafted = 1; + craftablespawn.stub.crafted = 1; + craftablespawn notify( "crafted" ); + level.craftables_crafted[ craftablespawn.craftable_name ] = 1; + level notify( craftablespawn.craftable_name + "_crafted" ); +} + +complete_craftable( str_craftable_name ) +{ + _a2020 = level.a_uts_craftables; + _k2020 = getFirstArrayKey( _a2020 ); + while ( isDefined( _k2020 ) ) + { + uts_craftable = _a2020[ _k2020 ]; + if ( uts_craftable.craftablestub.name == str_craftable_name ) + { + player = getplayers()[ 0 ]; + player player_finish_craftable( uts_craftable.craftablespawn ); + thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( uts_craftable ); + if ( isDefined( uts_craftable.craftablestub.onfullycrafted ) ) + { + uts_craftable [[ uts_craftable.craftablestub.onfullycrafted ]](); + } + return; + } + _k2020 = getNextArrayKey( _a2020, _k2020 ); + } +} + +craftablestub_remove() +{ + arrayremovevalue( level.a_uts_craftables, self ); +} + +craftabletrigger_update_prompt( player ) +{ + can_use = self.stub craftablestub_update_prompt( player ); + self sethintstring( self.stub.hint_string ); + return can_use; +} + +craftablestub_update_prompt( player, unitrigger ) +{ + if ( !self anystub_update_prompt( player ) ) + { + return 0; + } + if ( isDefined( self.is_locked ) && self.is_locked ) + { + return 1; + } + can_use = 1; + if ( isDefined( self.custom_craftablestub_update_prompt ) && !( self [[ self.custom_craftablestub_update_prompt ]]( player ) ) ) + { + return 0; + } + if ( isDefined( self.crafted ) && !self.crafted ) + { + if ( !self.craftablespawn craftable_can_use_shared_piece() ) + { + if ( !isDefined( player.current_craftable_piece ) ) + { + self.hint_string = &"ZOMBIE_BUILD_PIECE_MORE"; + return 0; + } + else + { + if ( !self.craftablespawn craftable_has_piece( player.current_craftable_piece ) ) + { + self.hint_string = &"ZOMBIE_BUILD_PIECE_WRONG"; + return 0; + } + } + } +/# + assert( isDefined( level.zombie_craftablestubs[ self.equipname ].str_to_craft ), "Missing craftable hint" ); +#/ + self.hint_string = level.zombie_craftablestubs[ self.equipname ].str_to_craft; + } + else + { + if ( self.persistent == 1 ) + { + if ( maps/mp/zombies/_zm_equipment::is_limited_equipment( self.weaponname ) && maps/mp/zombies/_zm_equipment::limited_equipment_in_use( self.weaponname ) ) + { + self.hint_string = &"ZOMBIE_BUILD_PIECE_ONLY_ONE"; + return 0; + } + if ( player has_player_equipment( self.weaponname ) ) + { + self.hint_string = &"ZOMBIE_BUILD_PIECE_HAVE_ONE"; + return 0; + } + self.hint_string = self.trigger_hintstring; + } + else if ( self.persistent == 2 ) + { + if ( !maps/mp/zombies/_zm_weapons::limited_weapon_below_quota( self.weaponname, undefined ) ) + { + self.hint_string = &"ZOMBIE_GO_TO_THE_BOX_LIMITED"; + return 0; + } + else + { + if ( isDefined( self.str_taken ) && self.str_taken ) + { + self.hint_string = &"ZOMBIE_GO_TO_THE_BOX"; + return 0; + } + } + self.hint_string = self.trigger_hintstring; + } + else + { + self.hint_string = ""; + return 0; + } + } + return 1; +} + +choose_open_craftable( player ) +{ + self endon( "kill_choose_open_craftable" ); + n_playernum = player getentitynumber(); + self.b_open_craftable_checking_input = 1; + b_got_input = 1; + hinttexthudelem = newclienthudelem( player ); + hinttexthudelem.alignx = "center"; + hinttexthudelem.aligny = "middle"; + hinttexthudelem.horzalign = "center"; + hinttexthudelem.vertalign = "bottom"; + hinttexthudelem.y = -100; + if ( player issplitscreen() ) + { + hinttexthudelem.y = -50; + } + hinttexthudelem.foreground = 1; + hinttexthudelem.font = "default"; + hinttexthudelem.fontscale = 1; + hinttexthudelem.alpha = 1; + hinttexthudelem.color = ( 0, 0, 1 ); + hinttexthudelem settext( &"ZM_CRAFTABLES_CHANGE_BUILD" ); + if ( !isDefined( self.opencraftablehudelem ) ) + { + self.opencraftablehudelem = []; + } + self.opencraftablehudelem[ n_playernum ] = hinttexthudelem; + while ( isDefined( self.playertrigger[ n_playernum ] ) && !self.crafted ) + { + if ( player actionslotonebuttonpressed() ) + { + self.n_open_craftable_choice++; + b_got_input = 1; + } + else + { + if ( player actionslottwobuttonpressed() ) + { + self.n_open_craftable_choice--; + + b_got_input = 1; + } + } + if ( self.n_open_craftable_choice >= self.a_uts_open_craftables_available.size ) + { + self.n_open_craftable_choice = 0; + } + else + { + if ( self.n_open_craftable_choice < 0 ) + { + self.n_open_craftable_choice = self.a_uts_open_craftables_available.size - 1; + } + } + if ( b_got_input ) + { + self.equipname = self.a_uts_open_craftables_available[ self.n_open_craftable_choice ].equipname; + self.hint_string = self.a_uts_open_craftables_available[ self.n_open_craftable_choice ].hint_string; + self.playertrigger[ n_playernum ] sethintstring( self.hint_string ); + b_got_input = 0; + } + if ( player is_player_looking_at( self.playertrigger[ n_playernum ].origin, 0,76 ) ) + { + self.opencraftablehudelem[ n_playernum ].alpha = 1; + } + else + { + self.opencraftablehudelem[ n_playernum ].alpha = 0; + } + wait 0,05; + } + self.b_open_craftable_checking_input = 0; + self.opencraftablehudelem[ n_playernum ] destroy(); +} + +open_craftablestub_update_prompt( player ) +{ + if ( isDefined( self.crafted ) && !self.crafted ) + { + self.a_uts_open_craftables_available = []; + _a2241 = level.a_uts_craftables; + _k2241 = getFirstArrayKey( _a2241 ); + while ( isDefined( _k2241 ) ) + { + uts_craftable = _a2241[ _k2241 ]; + if ( isDefined( uts_craftable.craftablestub.is_open_table ) && uts_craftable.craftablestub.is_open_table && isDefined( uts_craftable.crafted ) && !uts_craftable.crafted && uts_craftable.craftablespawn.craftable_name != "open_table" && uts_craftable.craftablespawn craftable_can_use_shared_piece() ) + { + self.a_uts_open_craftables_available[ self.a_uts_open_craftables_available.size ] = uts_craftable; + } + _k2241 = getNextArrayKey( _a2241, _k2241 ); + } + if ( self.a_uts_open_craftables_available.size < 2 ) + { + self notify( "kill_choose_open_craftable" ); + self.b_open_craftable_checking_input = 0; + n_entitynum = player getentitynumber(); + if ( isDefined( self.opencraftablehudelem ) && isDefined( self.opencraftablehudelem[ n_entitynum ] ) ) + { + self.opencraftablehudelem[ n_entitynum ] destroy(); + } + } + switch( self.a_uts_open_craftables_available.size ) + { + case 0: + if ( !isDefined( player.current_craftable_piece ) ) + { + self.hint_string = &"ZOMBIE_BUILD_PIECE_MORE"; + self.n_open_craftable_choice = -1; + return 0; + } + case 1: + self.n_open_craftable_choice = 0; + self.equipname = self.a_uts_open_craftables_available[ self.n_open_craftable_choice ].equipname; + return 1; + default: + if ( !self.b_open_craftable_checking_input ) + { + thread choose_open_craftable( player ); + } + return 1; + } + } + else + { + if ( self.persistent == 1 || self.persistent == 2 && isDefined( self.bought ) && !self.bought ) + { + return 1; + } + } + return 0; + } +} + +player_continue_crafting( craftablespawn ) +{ + if ( self maps/mp/zombies/_zm_laststand::player_is_in_laststand() || self in_revive_trigger() ) + { + return 0; + } + if ( !self player_can_craft( craftablespawn, 1 ) ) + { + return 0; + } + if ( isDefined( self.screecher ) ) + { + return 0; + } + if ( !self usebuttonpressed() ) + { + return 0; + } + if ( !craftablespawn craftable_is_piece_crafting( self.current_craftable_piece ) ) + { + return 0; + } + trigger = craftablespawn.stub maps/mp/zombies/_zm_unitrigger::unitrigger_trigger( self ); + if ( craftablespawn.stub.script_unitrigger_type == "unitrigger_radius_use" ) + { + torigin = craftablespawn.stub unitrigger_origin(); + porigin = self geteye(); + radius_sq = 2,25 * craftablespawn.stub.radius * craftablespawn.stub.radius; + if ( distance2dsquared( torigin, porigin ) > radius_sq ) + { + return 0; + } + } + else + { + if ( !isDefined( trigger ) || !trigger istouching( self ) ) + { + return 0; + } + } + if ( isDefined( craftablespawn.stub.require_look_at ) && craftablespawn.stub.require_look_at && !self is_player_looking_at( trigger.origin, 0,76 ) ) + { + return 0; + } + return 1; +} + +player_progress_bar_update( start_time, craft_time ) +{ + self endon( "entering_last_stand" ); + self endon( "death" ); + self endon( "disconnect" ); + self endon( "craftable_progress_end" ); + while ( isDefined( self ) && ( getTime() - start_time ) < craft_time ) + { + progress = ( getTime() - start_time ) / craft_time; + if ( progress < 0 ) + { + progress = 0; + } + if ( progress > 1 ) + { + progress = 1; + } + self.usebar updatebar( progress ); + wait 0,05; + } +} + +player_progress_bar( start_time, craft_time ) +{ + self.usebar = self createprimaryprogressbar(); + self.usebartext = self createprimaryprogressbartext(); + self.usebartext settext( &"ZOMBIE_BUILDING" ); + if ( isDefined( self ) && isDefined( start_time ) && isDefined( craft_time ) ) + { + self player_progress_bar_update( start_time, craft_time ); + } + self.usebartext destroyelem(); + self.usebar destroyelem(); +} + +craftable_use_hold_think_internal( player ) +{ + wait 0,01; + if ( !isDefined( self ) ) + { + self notify( "craft_failed" ); + if ( isDefined( player.craftableaudio ) ) + { + player.craftableaudio delete(); + player.craftableaudio = undefined; + } + return; + } + if ( !isDefined( self.usetime ) ) + { + self.usetime = int( 3000 ); + } + self.craft_time = self.usetime; + self.craft_start_time = getTime(); + craft_time = self.craft_time; + craft_start_time = self.craft_start_time; + player disable_player_move_states( 1 ); + player increment_is_drinking(); + orgweapon = player getcurrentweapon(); + player giveweapon( "zombie_builder_zm" ); + player switchtoweapon( "zombie_builder_zm" ); + self.stub.craftablespawn craftable_set_piece_crafting( player.current_craftable_piece ); + player thread player_progress_bar( craft_start_time, craft_time ); + if ( isDefined( level.craftable_craft_custom_func ) ) + { + player thread [[ level.craftable_craft_custom_func ]]( self.stub ); + } + while ( isDefined( self ) && player player_continue_crafting( self.stub.craftablespawn ) && ( getTime() - self.craft_start_time ) < self.craft_time ) + { + wait 0,05; + } + player notify( "craftable_progress_end" ); + player maps/mp/zombies/_zm_weapons::switch_back_primary_weapon( orgweapon ); + player takeweapon( "zombie_builder_zm" ); + if ( isDefined( player.is_drinking ) && player.is_drinking ) + { + player decrement_is_drinking(); + } + player enable_player_move_states(); + if ( isDefined( self ) && player player_continue_crafting( self.stub.craftablespawn ) && ( getTime() - self.craft_start_time ) >= self.craft_time ) + { + self.stub.craftablespawn craftable_clear_piece_crafting( player.current_craftable_piece ); + self notify( "craft_succeed" ); + } + else + { + if ( isDefined( player.craftableaudio ) ) + { + player.craftableaudio delete(); + player.craftableaudio = undefined; + } + self.stub.craftablespawn craftable_clear_piece_crafting( player.current_craftable_piece ); + self notify( "craft_failed" ); + } +} + +craftable_play_craft_fx( player ) +{ + self endon( "kill_trigger" ); + self endon( "craft_succeed" ); + self endon( "craft_failed" ); + while ( 1 ) + { + playfx( level._effect[ "building_dust" ], player getplayercamerapos(), player.angles ); + wait 0,5; + } +} + +craftable_use_hold_think( player ) +{ + self thread craftable_play_craft_fx( player ); + self thread craftable_use_hold_think_internal( player ); + retval = self waittill_any_return( "craft_succeed", "craft_failed" ); + if ( retval == "craft_succeed" ) + { + return 1; + } + return 0; +} + +craftable_place_think() +{ + self endon( "kill_trigger" ); + player_crafted = undefined; + while ( isDefined( self.stub.crafted ) && !self.stub.crafted ) + { + self waittill( "trigger", player ); + while ( isDefined( level.custom_craftable_validation ) ) + { + valid = self [[ level.custom_craftable_validation ]]( player ); + while ( !valid ) + { + continue; + } + } + while ( player != self.parent_player ) + { + continue; + } + while ( isDefined( player.screecher_weapon ) ) + { + continue; + } + while ( !is_player_valid( player ) ) + { + player thread ignore_triggers( 0,5 ); + } + status = player player_can_craft( self.stub.craftablespawn ); + if ( !status ) + { + self.stub.hint_string = ""; + self sethintstring( self.stub.hint_string ); + if ( isDefined( self.stub.oncantuse ) ) + { + self.stub [[ self.stub.oncantuse ]]( player ); + } + continue; + } + else + { + if ( isDefined( self.stub.onbeginuse ) ) + { + self.stub [[ self.stub.onbeginuse ]]( player ); + } + result = self craftable_use_hold_think( player ); + team = player.pers[ "team" ]; + if ( isDefined( self.stub.onenduse ) ) + { + self.stub [[ self.stub.onenduse ]]( team, player, result ); + } + while ( !result ) + { + continue; + } + if ( isDefined( self.stub.onuse ) ) + { + self.stub [[ self.stub.onuse ]]( player ); + } + prompt = player player_craft( self.stub.craftablespawn ); + player_crafted = player; + self.stub.hint_string = prompt; + self sethintstring( self.stub.hint_string ); + } + } + if ( isDefined( self.stub.craftablestub.onfullycrafted ) ) + { + b_result = self.stub [[ self.stub.craftablestub.onfullycrafted ]](); + if ( !b_result ) + { + return; + } + } + if ( isDefined( player_crafted ) ) + { + } + if ( self.stub.persistent == 0 ) + { + self.stub craftablestub_remove(); + thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( self.stub ); + return; + } + if ( self.stub.persistent == 3 ) + { + stub_uncraft_craftable( self.stub, 1 ); + return; + } + if ( self.stub.persistent == 2 ) + { + if ( isDefined( player_crafted ) ) + { + self craftabletrigger_update_prompt( player_crafted ); + } + if ( !maps/mp/zombies/_zm_weapons::limited_weapon_below_quota( self.stub.weaponname, undefined ) ) + { + self.stub.hint_string = &"ZOMBIE_GO_TO_THE_BOX_LIMITED"; + self sethintstring( self.stub.hint_string ); + return; + } + if ( isDefined( self.stub.str_taken ) && self.stub.str_taken ) + { + self.stub.hint_string = &"ZOMBIE_GO_TO_THE_BOX"; + self sethintstring( self.stub.hint_string ); + return; + } + if ( isDefined( self.stub.model ) ) + { + self.stub.model notsolid(); + self.stub.model show(); + } + while ( self.stub.persistent == 2 ) + { + self waittill( "trigger", player ); + while ( isDefined( player.screecher_weapon ) ) + { + continue; + } + while ( isDefined( level.custom_craftable_validation ) ) + { + valid = self [[ level.custom_craftable_validation ]]( player ); + while ( !valid ) + { + continue; + } + } + if ( isDefined( self.stub.crafted ) && !self.stub.crafted ) + { + self.stub.hint_string = ""; + self sethintstring( self.stub.hint_string ); + return; + } + while ( player != self.parent_player ) + { + continue; + } + while ( !is_player_valid( player ) ) + { + player thread ignore_triggers( 0,5 ); + } + self.stub.bought = 1; + if ( isDefined( self.stub.model ) ) + { + self.stub.model thread model_fly_away( self ); + } + player maps/mp/zombies/_zm_weapons::weapon_give( self.stub.weaponname ); + if ( isDefined( level.zombie_include_craftables[ self.stub.equipname ].onbuyweapon ) ) + { + self [[ level.zombie_include_craftables[ self.stub.equipname ].onbuyweapon ]]( player ); + } + if ( !maps/mp/zombies/_zm_weapons::limited_weapon_below_quota( self.stub.weaponname, undefined ) ) + { + self.stub.hint_string = &"ZOMBIE_GO_TO_THE_BOX_LIMITED"; + } + else + { + self.stub.hint_string = &"ZOMBIE_GO_TO_THE_BOX"; + } + self sethintstring( self.stub.hint_string ); + player track_craftables_pickedup( self.stub.craftablespawn ); + } + } + else while ( !isDefined( player_crafted ) || self craftabletrigger_update_prompt( player_crafted ) ) + { + if ( isDefined( self.stub.model ) ) + { + self.stub.model notsolid(); + self.stub.model show(); + } + while ( self.stub.persistent == 1 ) + { + self waittill( "trigger", player ); + while ( isDefined( player.screecher_weapon ) ) + { + continue; + } + while ( isDefined( level.custom_craftable_validation ) ) + { + valid = self [[ level.custom_craftable_validation ]]( player ); + while ( !valid ) + { + continue; + } + } + if ( isDefined( self.stub.crafted ) && !self.stub.crafted ) + { + self.stub.hint_string = ""; + self sethintstring( self.stub.hint_string ); + return; + } + while ( player != self.parent_player ) + { + continue; + } + while ( !is_player_valid( player ) ) + { + player thread ignore_triggers( 0,5 ); + } + while ( player has_player_equipment( self.stub.weaponname ) ) + { + continue; + } + while ( isDefined( level.zombie_craftable_persistent_weapon ) ) + { + while ( self [[ level.zombie_craftable_persistent_weapon ]]( player ) ) + { + continue; + } + } + while ( isDefined( level.zombie_custom_equipment_setup ) ) + { + while ( self [[ level.zombie_custom_equipment_setup ]]( player ) ) + { + continue; + } + } + if ( !maps/mp/zombies/_zm_equipment::is_limited_equipment( self.stub.weaponname ) || !maps/mp/zombies/_zm_equipment::limited_equipment_in_use( self.stub.weaponname ) ) + { + player maps/mp/zombies/_zm_equipment::equipment_buy( self.stub.weaponname ); + player giveweapon( self.stub.weaponname ); + player setweaponammoclip( self.stub.weaponname, 1 ); + if ( isDefined( level.zombie_include_craftables[ self.stub.equipname ].onbuyweapon ) ) + { + self [[ level.zombie_include_craftables[ self.stub.equipname ].onbuyweapon ]]( player ); + } + else + { + if ( self.stub.weaponname != "keys_zm" ) + { + player setactionslot( 1, "weapon", self.stub.weaponname ); + } + } + if ( isDefined( level.zombie_craftablestubs[ self.stub.equipname ].str_taken ) ) + { + self.stub.hint_string = level.zombie_craftablestubs[ self.stub.equipname ].str_taken; + } + else + { + self.stub.hint_string = ""; + } + self sethintstring( self.stub.hint_string ); + player track_craftables_pickedup( self.stub.craftablespawn ); + continue; + } + else + { + self.stub.hint_string = ""; + self sethintstring( self.stub.hint_string ); + } + } + } +} + +model_fly_away( unitrigger ) +{ + self moveto( self.origin + vectorScale( ( 0, 0, 1 ), 40 ), 3 ); + direction = self.origin; + direction = ( direction[ 1 ], direction[ 0 ], 0 ); + if ( direction[ 1 ] < 0 || direction[ 0 ] > 0 && direction[ 1 ] > 0 ) + { + direction = ( direction[ 0 ], direction[ 1 ] * -1, 0 ); + } + else + { + if ( direction[ 0 ] < 0 ) + { + direction = ( direction[ 0 ] * -1, direction[ 1 ], 0 ); + } + } + self vibrate( direction, 10, 0,5, 4 ); + self waittill( "movedone" ); + self ghost(); + playfx( level._effect[ "poltergeist" ], self.origin ); +} + +find_craftable_stub( equipname ) +{ + _a2775 = level.a_uts_craftables; + _k2775 = getFirstArrayKey( _a2775 ); + while ( isDefined( _k2775 ) ) + { + stub = _a2775[ _k2775 ]; + if ( stub.equipname == equipname ) + { + return stub; + } + _k2775 = getNextArrayKey( _a2775, _k2775 ); + } + return undefined; +} + +uncraft_craftable( equipname, return_pieces, origin, angles ) +{ + stub = find_craftable_stub( equipname ); + stub_uncraft_craftable( stub, return_pieces, origin, angles ); +} + +stub_uncraft_craftable( stub, return_pieces, origin, angles, use_random_start ) +{ + if ( isDefined( stub ) ) + { + craftable = stub.craftablespawn; + craftable.crafted = 0; + craftable.stub.crafted = 0; + craftable notify( "uncrafted" ); + level.craftables_crafted[ craftable.craftable_name ] = 0; + level notify( craftable.craftable_name + "_uncrafted" ); + i = 0; + while ( i < craftable.a_piecespawns.size ) + { + craftable.a_piecespawns[ i ].crafted = 0; + if ( isDefined( craftable.a_piecespawns[ i ].tag_name ) ) + { + craftable.stub.model notsolid(); + if ( isDefined( craftable.a_piecespawns[ i ].crafted ) && !craftable.a_piecespawns[ i ].crafted ) + { + craftable.stub.model hidepart( craftable.a_piecespawns[ i ].tag_name ); + break; + } + else + { + craftable.stub.model show(); + craftable.stub.model showpart( craftable.a_piecespawns[ i ].tag_name ); + } + } + if ( isDefined( return_pieces ) && return_pieces ) + { + craftable.a_piecespawns[ i ] piece_spawn_at( origin, angles, use_random_start ); + } + i++; + } + if ( isDefined( craftable.stub.model ) ) + { + craftable.stub.model ghost(); + } + } +} + +player_explode_craftable( equipname, origin, speed, return_to_spawn, return_time ) +{ + self explosiondamage( 50, origin ); + stub = find_craftable_stub( equipname ); + if ( isDefined( stub ) ) + { + craftable = stub.craftablespawn; + craftable.crafted = 0; + craftable.stub.crafted = 0; + craftable notify( "uncrafted" ); + level.craftables_crafted[ craftable.craftable_name ] = 0; + level notify( craftable.craftable_name + "_uncrafted" ); + i = 0; + while ( i < craftable.a_piecespawns.size ) + { + craftable.a_piecespawns[ i ].crafted = 0; + if ( isDefined( craftable.a_piecespawns[ i ].tag_name ) ) + { + craftable.stub.model notsolid(); + if ( isDefined( craftable.a_piecespawns[ i ].crafted ) && !craftable.a_piecespawns[ i ].crafted ) + { + craftable.stub.model hidepart( craftable.a_piecespawns[ i ].tag_name ); + break; + } + else + { + craftable.stub.model show(); + craftable.stub.model showpart( craftable.a_piecespawns[ i ].tag_name ); + } + } + ang = randomfloat( 360 ); + h = 0,25 + randomfloat( 0,5 ); + dir = ( sin( ang ), cos( ang ), h ); + self thread player_throw_piece( craftable.a_piecespawns[ i ], origin, speed * dir, return_to_spawn, return_time ); + i++; + } + craftable.stub.model ghost(); + } +} + +think_craftables() +{ + _a2873 = level.zombie_include_craftables; + _k2873 = getFirstArrayKey( _a2873 ); + while ( isDefined( _k2873 ) ) + { + craftable = _a2873[ _k2873 ]; + if ( isDefined( craftable.triggerthink ) ) + { + craftable [[ craftable.triggerthink ]](); + } + _k2873 = getNextArrayKey( _a2873, _k2873 ); + } +} + +opentablecraftable() +{ + a_trigs = getentarray( "open_craftable_trigger", "targetname" ); + _a2887 = a_trigs; + _k2887 = getFirstArrayKey( _a2887 ); + while ( isDefined( _k2887 ) ) + { + trig = _a2887[ _k2887 ]; + setup_unitrigger_craftable_internal( trig, "open_table", "", "OPEN_CRAFTABLE", 1, 0 ); + _k2887 = getNextArrayKey( _a2887, _k2887 ); + } +} + +craftable_trigger_think( trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ) +{ + return setup_unitrigger_craftable( trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ); +} + +craftable_trigger_think_array( trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ) +{ + return setup_unitrigger_craftable_array( trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ); +} + +setup_vehicle_unitrigger_craftable( parent, trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ) +{ + trig = getent( trigger_targetname, "targetname" ); + if ( !isDefined( trig ) ) + { + return; + } + unitrigger_stub = spawnstruct(); + unitrigger_stub.craftablestub = level.zombie_include_craftables[ equipname ]; + unitrigger_stub.link_parent = parent; + unitrigger_stub.origin_parent = trig; + unitrigger_stub.trigger_targetname = trigger_targetname; + unitrigger_stub.originfunc = ::anystub_get_unitrigger_origin; + unitrigger_stub.onspawnfunc = ::anystub_on_spawn_trigger; + unitrigger_stub.origin = trig.origin; + unitrigger_stub.angles = trig.angles; + unitrigger_stub.equipname = equipname; + unitrigger_stub.weaponname = weaponname; + unitrigger_stub.trigger_hintstring = trigger_hintstring; + unitrigger_stub.delete_trigger = delete_trigger; + unitrigger_stub.crafted = 0; + unitrigger_stub.persistent = persistent; + unitrigger_stub.usetime = int( 3000 ); + unitrigger_stub.onbeginuse = ::onbeginuseuts; + unitrigger_stub.onenduse = ::onenduseuts; + unitrigger_stub.onuse = ::onuseplantobjectuts; + unitrigger_stub.oncantuse = ::oncantuseuts; + if ( isDefined( trig.script_length ) ) + { + unitrigger_stub.script_length = trig.script_length; + } + else + { + unitrigger_stub.script_length = 24; + } + if ( isDefined( trig.script_width ) ) + { + unitrigger_stub.script_width = trig.script_width; + } + else + { + unitrigger_stub.script_width = 64; + } + if ( isDefined( trig.script_height ) ) + { + unitrigger_stub.script_height = trig.script_height; + } + else + { + unitrigger_stub.script_height = 24; + } + if ( isDefined( trig.radius ) ) + { + unitrigger_stub.radius = trig.radius; + } + else + { + unitrigger_stub.radius = 64; + } + unitrigger_stub.target = trig.target; + unitrigger_stub.targetname = trig.targetname + "_trigger"; + unitrigger_stub.script_noteworthy = trig.script_noteworthy; + unitrigger_stub.script_parameters = trig.script_parameters; + unitrigger_stub.cursor_hint = "HINT_NOICON"; + if ( isDefined( level.zombie_craftablestubs[ equipname ].str_to_craft ) ) + { + unitrigger_stub.hint_string = level.zombie_craftablestubs[ equipname ].str_to_craft; + } + unitrigger_stub.script_unitrigger_type = "unitrigger_radius_use"; + unitrigger_stub.require_look_at = 1; + unitrigger_force_per_player_triggers( unitrigger_stub, 1 ); + unitrigger_stub.prompt_and_visibility_func = ::craftabletrigger_update_prompt; + maps/mp/zombies/_zm_unitrigger::register_unitrigger( unitrigger_stub, ::craftable_place_think ); + unitrigger_stub.piece_trigger = trig; + trig.trigger_stub = unitrigger_stub; + unitrigger_stub.craftablespawn = unitrigger_stub craftable_piece_unitriggers( equipname, unitrigger_stub.origin ); + if ( delete_trigger ) + { + trig delete(); + } + level.a_uts_craftables[ level.a_uts_craftables.size ] = unitrigger_stub; + return unitrigger_stub; +} + +vehicle_craftable_trigger_think( vehicle, trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ) +{ + return setup_vehicle_unitrigger_craftable( vehicle, trigger_targetname, equipname, weaponname, trigger_hintstring, delete_trigger, persistent ); +} + +onpickuputs( player ) +{ +/# + if ( isDefined( player ) && isDefined( player.name ) ) + { + println( "ZM >> Craftable piece recovered by - " + player.name ); +#/ + } +} + +ondroputs( player ) +{ +/# + if ( isDefined( player ) && isDefined( player.name ) ) + { + println( "ZM >> Craftable piece dropped by - " + player.name ); +#/ + } + player notify( "event_ended" ); +} + +onbeginuseuts( player ) +{ +/# + if ( isDefined( player ) && isDefined( player.name ) ) + { + println( "ZM >> Craftable piece begin use by - " + player.name ); +#/ + } + if ( isDefined( self.craftablestub.onbeginuse ) ) + { + self [[ self.craftablestub.onbeginuse ]]( player ); + } + if ( isDefined( player ) && !isDefined( player.craftableaudio ) ) + { + player.craftableaudio = spawn( "script_origin", player.origin ); + player.craftableaudio playloopsound( "zmb_craftable_loop" ); + } +} + +onenduseuts( team, player, result ) +{ +/# + if ( isDefined( player ) && isDefined( player.name ) ) + { + println( "ZM >> Craftable piece end use by - " + player.name ); +#/ + } + if ( !isDefined( player ) ) + { + return; + } + if ( isDefined( player.craftableaudio ) ) + { + player.craftableaudio delete(); + player.craftableaudio = undefined; + } + if ( isDefined( self.craftablestub.onenduse ) ) + { + self [[ self.craftablestub.onenduse ]]( team, player, result ); + } + player notify( "event_ended" ); +} + +oncantuseuts( player ) +{ +/# + if ( isDefined( player ) && isDefined( player.name ) ) + { + println( "ZM >> Craftable piece can't use by - " + player.name ); +#/ + } + if ( isDefined( self.craftablestub.oncantuse ) ) + { + self [[ self.craftablestub.oncantuse ]]( player ); + } +} + +onuseplantobjectuts( player ) +{ +/# + if ( isDefined( player ) && isDefined( player.name ) ) + { + println( "ZM >> Craftable piece crafted by - " + player.name ); +#/ + } + if ( isDefined( self.craftablestub.onuseplantobject ) ) + { + self [[ self.craftablestub.onuseplantobject ]]( player ); + } + player notify( "bomb_planted" ); +} + +is_craftable() +{ + if ( !isDefined( level.zombie_craftablestubs ) ) + { + return 0; + } + if ( isDefined( self.zombie_weapon_upgrade ) && isDefined( level.zombie_craftablestubs[ self.zombie_weapon_upgrade ] ) ) + { + return 1; + } + if ( isDefined( self.script_noteworthy ) && self.script_noteworthy == "specialty_weapupgrade" ) + { + if ( isDefined( level.craftables_crafted[ "pap" ] ) && level.craftables_crafted[ "pap" ] ) + { + return 0; + } + return 1; + } + return 0; +} + +craftable_crafted() +{ + self.a_piecespawns--; + +} + +craftable_complete() +{ + if ( self.a_piecespawns <= 0 ) + { + return 1; + } + return 0; +} + +get_craftable_hint( craftable_name ) +{ +/# + assert( isDefined( level.zombie_craftablestubs[ craftable_name ] ), craftable_name + " was not included or is not part of the zombie weapon list." ); +#/ + return level.zombie_craftablestubs[ craftable_name ].str_to_craft; +} + +delete_on_disconnect( craftable, self_notify, skip_delete ) +{ + craftable endon( "death" ); + self waittill( "disconnect" ); + if ( isDefined( self_notify ) ) + { + self notify( self_notify ); + } + if ( isDefined( skip_delete ) && !skip_delete ) + { + if ( isDefined( craftable.stub ) ) + { + thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( craftable.stub ); + craftable.stub = undefined; + } + if ( isDefined( craftable ) ) + { + craftable delete(); + } + } +} + +is_holding_part( craftable_name, piece_name ) +{ + if ( isDefined( self.current_craftable_piece ) ) + { + if ( self.current_craftable_piece.craftablename == craftable_name && self.current_craftable_piece.modelname == piece_name ) + { + return 1; + } + } + while ( isDefined( level.a_uts_craftables ) ) + { + _a3246 = level.a_uts_craftables; + _k3246 = getFirstArrayKey( _a3246 ); + while ( isDefined( _k3246 ) ) + { + craftable_stub = _a3246[ _k3246 ]; + while ( craftable_stub.craftablestub.name == craftable_name ) + { + _a3251 = craftable_stub.craftablespawn.a_piecespawns; + _k3251 = getFirstArrayKey( _a3251 ); + while ( isDefined( _k3251 ) ) + { + piece = _a3251[ _k3251 ]; + if ( piece.piecename == piece_name ) + { + if ( isDefined( piece.in_shared_inventory ) && piece.in_shared_inventory ) + { + return 1; + } + } + _k3251 = getNextArrayKey( _a3251, _k3251 ); + } + } + _k3246 = getNextArrayKey( _a3246, _k3246 ); + } + } + return 0; +} + +is_part_crafted( craftable_name, piece_name ) +{ + while ( isDefined( level.a_uts_craftables ) ) + { + _a3276 = level.a_uts_craftables; + _k3276 = getFirstArrayKey( _a3276 ); + while ( isDefined( _k3276 ) ) + { + craftable_stub = _a3276[ _k3276 ]; + while ( craftable_stub.craftablestub.name == craftable_name ) + { + if ( isDefined( craftable_stub.crafted ) && craftable_stub.crafted ) + { + return 1; + } + _a3287 = craftable_stub.craftablespawn.a_piecespawns; + _k3287 = getFirstArrayKey( _a3287 ); + while ( isDefined( _k3287 ) ) + { + piece = _a3287[ _k3287 ]; + if ( piece.piecename == piece_name ) + { + if ( isDefined( piece.crafted ) && piece.crafted ) + { + return 1; + } + } + _k3287 = getNextArrayKey( _a3287, _k3287 ); + } + } + _k3276 = getNextArrayKey( _a3276, _k3276 ); + } + } + return 0; +} + +track_craftable_piece_pickedup( piece ) +{ + if ( !isDefined( piece ) || !isDefined( piece.craftablename ) ) + { +/# + println( "STAT TRACKING FAILURE: NOT DEFINED IN track_craftable_piece_pickedup() \n" ); +#/ + return; + } + self add_map_craftable_stat( piece.craftablename, "pieces_pickedup", 1 ); + if ( isDefined( piece.piecestub.vox_id ) ) + { + if ( isDefined( piece.piecestub.b_one_time_vo ) && piece.piecestub.b_one_time_vo ) + { + if ( !isDefined( self.a_one_time_piece_pickup_vo ) ) + { + self.a_one_time_piece_pickup_vo = []; + } + if ( isDefined( self.dontspeak ) && self.dontspeak ) + { + return; + } + if ( isinarray( self.a_one_time_piece_pickup_vo, piece.piecestub.vox_id ) ) + { + return; + } + self.a_one_time_piece_pickup_vo[ self.a_one_time_piece_pickup_vo.size ] = piece.piecestub.vox_id; + } + self thread do_player_general_vox( "general", piece.piecestub.vox_id + "_pickup" ); + } + else + { + self thread do_player_general_vox( "general", "build_pickup" ); + } +} + +track_craftable_pieces_crafted( craftable ) +{ + if ( !isDefined( craftable ) || !isDefined( craftable.craftable_name ) ) + { +/# + println( "STAT TRACKING FAILURE: NOT DEFINED IN track_craftable_pieces_crafted() \n" ); +#/ + return; + } + bname = craftable.craftable_name; + if ( isDefined( craftable.stat_name ) ) + { + bname = craftable.stat_name; + } + self add_map_craftable_stat( bname, "pieces_built", 1 ); + if ( !craftable craftable_all_crafted() ) + { + self thread do_player_general_vox( "general", "build_add" ); + } +} + +track_craftables_crafted( craftable ) +{ + if ( !isDefined( craftable ) || !isDefined( craftable.craftable_name ) ) + { +/# + println( "STAT TRACKING FAILURE: NOT DEFINED IN track_craftables_crafted() \n" ); +#/ + return; + } + bname = craftable.craftable_name; + if ( isDefined( craftable.stat_name ) ) + { + bname = craftable.stat_name; + } + self add_map_craftable_stat( bname, "buildable_built", 1 ); + self maps/mp/zombies/_zm_stats::increment_client_stat( "buildables_built", 0 ); + self maps/mp/zombies/_zm_stats::increment_player_stat( "buildables_built" ); + if ( isDefined( craftable.stub.craftablestub.vox_id ) ) + { + if ( isDefined( level.zombie_custom_craftable_built_vo ) ) + { + self thread [[ level.zombie_custom_craftable_built_vo ]]( craftable.stub ); + } + self thread do_player_general_vox( "general", craftable.stub.craftablestub.vox_id + "_final" ); + } +} + +track_craftables_pickedup( craftable ) +{ + if ( !isDefined( craftable ) ) + { +/# + println( "STAT TRACKING FAILURE: NOT DEFINED IN track_craftables_pickedup() \n" ); +#/ + return; + } + stat_name = get_craftable_stat_name( craftable.craftable_name ); + if ( !isDefined( stat_name ) ) + { +/# + println( "STAT TRACKING FAILURE: NO STAT NAME FOR " + craftable.craftable_name + "\n" ); +#/ + return; + } + self add_map_craftable_stat( stat_name, "buildable_pickedup", 1 ); + if ( isDefined( craftable.stub.craftablestub.vox_id ) ) + { + self thread do_player_general_vox( "general", craftable.stub.craftablestub.vox_id + "_plc" ); + } + self say_pickup_craftable_vo( craftable, 0 ); +} + +track_craftables_planted( equipment ) +{ + if ( !isDefined( equipment ) ) + { +/# + println( "STAT TRACKING FAILURE: NOT DEFINED for track_craftables_planted() \n" ); +#/ + return; + } + craftable_name = undefined; + if ( isDefined( equipment.name ) ) + { + craftable_name = get_craftable_stat_name( equipment.name ); + } + if ( !isDefined( craftable_name ) ) + { +/# + println( "STAT TRACKING FAILURE: NO CRAFTABLE NAME FOR track_craftables_planted() " + equipment.name + "\n" ); +#/ + return; + } + maps/mp/_demo::bookmark( "zm_player_buildable_placed", getTime(), self ); + self add_map_craftable_stat( craftable_name, "buildable_placed", 1 ); +} + +placed_craftable_vo_timer() +{ + self endon( "disconnect" ); + self.craftable_timer = 1; + wait 60; + self.craftable_timer = 0; +} + +craftable_pickedup_timer() +{ + self endon( "disconnect" ); + self.craftable_pickedup_timer = 1; + wait 60; + self.craftable_pickedup_timer = 0; +} + +track_planted_craftables_pickedup( equipment ) +{ + if ( !isDefined( equipment ) ) + { + return; + } + if ( equipment != "equip_turbine_zm" && equipment != "equip_turret_zm" && equipment != "equip_electrictrap_zm" && equipment != "riotshield_zm" || equipment == "alcatraz_shield_zm" && equipment == "tomb_shield_zm" ) + { + self maps/mp/zombies/_zm_stats::increment_client_stat( "planted_buildables_pickedup", 0 ); + self maps/mp/zombies/_zm_stats::increment_player_stat( "planted_buildables_pickedup" ); + } + if ( isDefined( self.craftable_pickedup_timer ) && !self.craftable_pickedup_timer ) + { + self say_pickup_craftable_vo( equipment, 1 ); + self thread craftable_pickedup_timer(); + } +} + +track_placed_craftables( craftable_name ) +{ + if ( !isDefined( craftable_name ) ) + { + return; + } + self add_map_craftable_stat( craftable_name, "buildable_placed", 1 ); + vo_name = undefined; + if ( craftable_name == level.riotshield_name ) + { + vo_name = "craft_plc_shield"; + } + if ( !isDefined( vo_name ) ) + { + return; + } + self thread do_player_general_vox( "general", vo_name ); +} + +add_map_craftable_stat( piece_name, stat_name, value ) +{ + if ( isDefined( piece_name ) || piece_name == "sq_common" && piece_name == "keys_zm" ) + { + return; + } + if ( isDefined( level.zm_disable_recording_stats ) || level.zm_disable_recording_stats && isDefined( level.zm_disable_recording_buildable_stats ) && level.zm_disable_recording_buildable_stats ) + { + return; + } + self adddstat( "buildables", piece_name, stat_name, value ); +} + +say_pickup_craftable_vo( craftable_name, world ) +{ +} + +get_craftable_vo_name( craftable_name ) +{ +} + +get_craftable_stat_name( craftable_name ) +{ + if ( isDefined( craftable_name ) ) + { + switch( craftable_name ) + { + case "equip_riotshield_zm": + return "riotshield_zm"; + case "equip_turbine_zm": + return "turbine"; + case "equip_turret_zm": + return "turret"; + case "equip_electrictrap_zm": + return "electric_trap"; + case "equip_springpad_zm": + return "springpad_zm"; + case "equip_slipgun_zm": + return "slipgun_zm"; + } + } + return craftable_name; +} + +get_craftable_model( str_craftable ) +{ + _a3598 = level.a_uts_craftables; + _k3598 = getFirstArrayKey( _a3598 ); + while ( isDefined( _k3598 ) ) + { + uts_craftable = _a3598[ _k3598 ]; + if ( uts_craftable.craftablestub.name == str_craftable ) + { + if ( isDefined( uts_craftable.model ) ) + { + return uts_craftable.model; + } + } + else + { + _k3598 = getNextArrayKey( _a3598, _k3598 ); + } + } + return undefined; +} + +get_craftable_piece( str_craftable, str_piece ) +{ + _a3618 = level.a_uts_craftables; + _k3618 = getFirstArrayKey( _a3618 ); + while ( isDefined( _k3618 ) ) + { + uts_craftable = _a3618[ _k3618 ]; + if ( uts_craftable.craftablestub.name == str_craftable ) + { + _a3622 = uts_craftable.craftablespawn.a_piecespawns; + _k3622 = getFirstArrayKey( _a3622 ); + while ( isDefined( _k3622 ) ) + { + piecespawn = _a3622[ _k3622 ]; + if ( piecespawn.piecename == str_piece ) + { + return piecespawn; + } + _k3622 = getNextArrayKey( _a3622, _k3622 ); + } + } + else _k3618 = getNextArrayKey( _a3618, _k3618 ); + } + return undefined; +} + +player_get_craftable_piece( str_craftable, str_piece ) +{ + piecespawn = get_craftable_piece( str_craftable, str_piece ); + if ( isDefined( piecespawn ) ) + { + self player_take_piece( piecespawn ); + } +} + +get_craftable_piece_model( str_craftable, str_piece ) +{ + _a3654 = level.a_uts_craftables; + _k3654 = getFirstArrayKey( _a3654 ); + while ( isDefined( _k3654 ) ) + { + uts_craftable = _a3654[ _k3654 ]; + if ( uts_craftable.craftablestub.name == str_craftable ) + { + _a3658 = uts_craftable.craftablespawn.a_piecespawns; + _k3658 = getFirstArrayKey( _a3658 ); + while ( isDefined( _k3658 ) ) + { + piecespawn = _a3658[ _k3658 ]; + if ( piecespawn.piecename == str_piece && isDefined( piecespawn.model ) ) + { + return piecespawn.model; + } + _k3658 = getNextArrayKey( _a3658, _k3658 ); + } + } + else _k3654 = getNextArrayKey( _a3654, _k3654 ); + } + return undefined; +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_magicbox_tomb.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_magicbox_tomb.gsc new file mode 100644 index 0000000..ea9b7a3 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_magicbox_tomb.gsc @@ -0,0 +1,298 @@ +#include maps/mp/zombies/_zm_magicbox; +#include maps/mp/zombies/_zm_unitrigger; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + registerclientfield( "zbarrier", "magicbox_initial_fx", 2000, 1, "int" ); + registerclientfield( "zbarrier", "magicbox_amb_fx", 2000, 2, "int" ); + registerclientfield( "zbarrier", "magicbox_open_fx", 2000, 1, "int" ); + registerclientfield( "zbarrier", "magicbox_leaving_fx", 2000, 1, "int" ); + level._effect[ "lght_marker" ] = loadfx( "maps/zombie_tomb/fx_tomb_marker" ); + level._effect[ "lght_marker_flare" ] = loadfx( "maps/zombie/fx_zmb_tranzit_marker_fl" ); + level._effect[ "poltergeist" ] = loadfx( "system_elements/fx_null" ); + level._effect[ "box_powered" ] = loadfx( "maps/zombie_tomb/fx_tomb_magicbox_on" ); + level._effect[ "box_unpowered" ] = loadfx( "maps/zombie_tomb/fx_tomb_magicbox_off" ); + level._effect[ "box_gone_ambient" ] = loadfx( "maps/zombie_tomb/fx_tomb_magicbox_amb_base" ); + level._effect[ "box_here_ambient" ] = loadfx( "maps/zombie_tomb/fx_tomb_magicbox_amb_slab" ); + level._effect[ "box_is_open" ] = loadfx( "maps/zombie_tomb/fx_tomb_magicbox_open" ); + level._effect[ "box_portal" ] = loadfx( "maps/zombie_tomb/fx_tomb_magicbox_portal" ); + level._effect[ "box_is_leaving" ] = loadfx( "maps/zombie_tomb/fx_tomb_magicbox_leave" ); + level.chest_joker_model = "zombie_teddybear"; + precachemodel( level.chest_joker_model ); + level.chest_joker_custom_movement = ::custom_joker_movement; + level.custom_magic_box_timer_til_despawn = ::custom_magic_box_timer_til_despawn; + level.custom_magic_box_do_weapon_rise = ::custom_magic_box_do_weapon_rise; + level.custom_magic_box_weapon_wait = ::custom_magic_box_weapon_wait; + level.custom_magicbox_float_height = 50; + level.magic_box_zbarrier_state_func = ::set_magic_box_zbarrier_state; + level thread wait_then_create_base_magic_box_fx(); + level thread handle_fire_sale(); +} + +custom_joker_movement() +{ + v_origin = self.weapon_model.origin - vectorScale( ( 0, 1, 0 ), 5 ); + self.weapon_model delete(); + m_lock = spawn( "script_model", v_origin ); + m_lock setmodel( level.chest_joker_model ); + m_lock.angles = self.angles + vectorScale( ( 0, 1, 0 ), 270 ); + m_lock playsound( "zmb_hellbox_bear" ); + wait 0,5; + level notify( "weapon_fly_away_start" ); + wait 1; + m_lock rotateyaw( 3000, 4, 4 ); + wait 3; + v_angles = anglesToForward( self.angles - vectorScale( ( 0, 1, 0 ), 90 ) ); + m_lock moveto( m_lock.origin + ( 20 * v_angles ), 0,5, 0,5 ); + m_lock waittill( "movedone" ); + m_lock moveto( m_lock.origin + ( -100 * v_angles ), 0,5, 0,5 ); + m_lock waittill( "movedone" ); + m_lock delete(); + self notify( "box_moving" ); + level notify( "weapon_fly_away_end" ); +} + +custom_magic_box_timer_til_despawn( magic_box ) +{ + self endon( "kill_weapon_movement" ); + putbacktime = 12; + v_float = anglesToForward( magic_box.angles - vectorScale( ( 0, 1, 0 ), 90 ) ) * 40; + self moveto( self.origin - ( v_float * 0,25 ), putbacktime, putbacktime * 0,5 ); + wait putbacktime; + if ( isDefined( self ) ) + { + self delete(); + } +} + +custom_magic_box_weapon_wait() +{ + wait 0,5; +} + +wait_then_create_base_magic_box_fx() +{ + while ( !isDefined( level.chests ) ) + { + wait 0,5; + } + while ( !isDefined( level.chests[ level.chests.size - 1 ].zbarrier ) ) + { + wait 0,5; + } + _a125 = level.chests; + _k125 = getFirstArrayKey( _a125 ); + while ( isDefined( _k125 ) ) + { + chest = _a125[ _k125 ]; + chest.zbarrier setclientfield( "magicbox_initial_fx", 1 ); + _k125 = getNextArrayKey( _a125, _k125 ); + } +} + +set_magic_box_zbarrier_state( state ) +{ + i = 0; + while ( i < self getnumzbarrierpieces() ) + { + self hidezbarrierpiece( i ); + i++; + } + self notify( "zbarrier_state_change" ); + switch( state ) + { + case "away": + self showzbarrierpiece( 0 ); + self.state = "away"; + self.owner.is_locked = 0; + break; + case "arriving": + self showzbarrierpiece( 1 ); + self thread magic_box_arrives(); + self.state = "arriving"; + break; + case "initial": + self showzbarrierpiece( 1 ); + self thread magic_box_initial(); + thread maps/mp/zombies/_zm_unitrigger::register_static_unitrigger( self.owner.unitrigger_stub, ::maps/mp/zombies/_zm_magicbox::magicbox_unitrigger_think ); + self.state = "close"; + break; + case "open": + self showzbarrierpiece( 2 ); + self thread magic_box_opens(); + self.state = "open"; + break; + case "close": + self showzbarrierpiece( 2 ); + self thread magic_box_closes(); + self.state = "close"; + break; + case "leaving": + self showzbarrierpiece( 1 ); + self thread magic_box_leaves(); + self.state = "leaving"; + self.owner.is_locked = 0; + break; + default: + if ( isDefined( level.custom_magicbox_state_handler ) ) + { + self [[ level.custom_magicbox_state_handler ]]( state ); + } + break; + } +} + +magic_box_initial() +{ + self setzbarrierpiecestate( 1, "open" ); + wait 1; + self setclientfield( "magicbox_amb_fx", 1 ); +} + +magic_box_arrives() +{ + self setclientfield( "magicbox_leaving_fx", 0 ); + self setzbarrierpiecestate( 1, "opening" ); + while ( self getzbarrierpiecestate( 1 ) == "opening" ) + { + wait 0,05; + } + self notify( "arrived" ); + self.state = "close"; + s_zone_capture_area = level.zone_capture.zones[ self.zone_capture_area ]; + if ( isDefined( s_zone_capture_area ) ) + { + if ( !s_zone_capture_area ent_flag( "player_controlled" ) ) + { + self setclientfield( "magicbox_amb_fx", 1 ); + return; + } + else + { + self setclientfield( "magicbox_amb_fx", 2 ); + } + } +} + +magic_box_leaves() +{ + self setclientfield( "magicbox_leaving_fx", 1 ); + self setclientfield( "magicbox_open_fx", 0 ); + self setzbarrierpiecestate( 1, "closing" ); + self playsound( "zmb_hellbox_rise" ); + while ( self getzbarrierpiecestate( 1 ) == "closing" ) + { + wait 0,1; + } + self notify( "left" ); + s_zone_capture_area = level.zone_capture.zones[ self.zone_capture_area ]; + if ( isDefined( s_zone_capture_area ) ) + { + if ( s_zone_capture_area ent_flag( "player_controlled" ) ) + { + self setclientfield( "magicbox_amb_fx", 3 ); + } + else + { + self setclientfield( "magicbox_amb_fx", 0 ); + } + } + if ( isDefined( level.dig_magic_box_moved ) && !level.dig_magic_box_moved ) + { + level.dig_magic_box_moved = 1; + } +} + +magic_box_opens() +{ + self setclientfield( "magicbox_open_fx", 1 ); + self setzbarrierpiecestate( 2, "opening" ); + self playsound( "zmb_hellbox_open" ); + while ( self getzbarrierpiecestate( 2 ) == "opening" ) + { + wait 0,1; + } + self notify( "opened" ); + self thread magic_box_open_idle(); +} + +magic_box_open_idle() +{ + self endon( "stop_open_idle" ); + self hidezbarrierpiece( 2 ); + self showzbarrierpiece( 5 ); + while ( 1 ) + { + self setzbarrierpiecestate( 5, "opening" ); + while ( self getzbarrierpiecestate( 5 ) != "open" ) + { + wait 0,05; + } + } +} + +magic_box_closes() +{ + self notify( "stop_open_idle" ); + self hidezbarrierpiece( 5 ); + self showzbarrierpiece( 2 ); + self setzbarrierpiecestate( 2, "closing" ); + self playsound( "zmb_hellbox_close" ); + self setclientfield( "magicbox_open_fx", 0 ); + while ( self getzbarrierpiecestate( 2 ) == "closing" ) + { + wait 0,1; + } + self notify( "closed" ); +} + +custom_magic_box_do_weapon_rise() +{ + self endon( "box_hacked_respin" ); + wait 0,5; + self setzbarrierpiecestate( 3, "closed" ); + self setzbarrierpiecestate( 4, "closed" ); + wait_network_frame(); + self zbarrierpieceuseboxriselogic( 3 ); + self zbarrierpieceuseboxriselogic( 4 ); + self showzbarrierpiece( 3 ); + self showzbarrierpiece( 4 ); + self setzbarrierpiecestate( 3, "opening" ); + self setzbarrierpiecestate( 4, "opening" ); + while ( self getzbarrierpiecestate( 3 ) != "open" ) + { + wait 0,5; + } + self hidezbarrierpiece( 3 ); + self hidezbarrierpiece( 4 ); +} + +handle_fire_sale() +{ + while ( 1 ) + { + level waittill( "fire_sale_off" ); + i = 0; + while ( i < level.chests.size ) + { + if ( level.chest_index != i && isDefined( level.chests[ i ].was_temp ) ) + { + if ( isDefined( level.chests[ i ].zbarrier.zone_capture_area ) && level.zone_capture.zones[ level.chests[ i ].zbarrier.zone_capture_area ] ent_flag( "player_controlled" ) ) + { + level.chests[ i ].zbarrier setclientfield( "magicbox_amb_fx", 3 ); + i++; + continue; + } + else + { + level.chests[ i ].zbarrier setclientfield( "magicbox_amb_fx", 0 ); + } + } + i++; + } + } +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_melee_weapon.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_melee_weapon.gsc new file mode 100644 index 0000000..ed494ee --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_melee_weapon.gsc @@ -0,0 +1,627 @@ +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zombies/_zm_score; +#include maps/mp/zombies/_zm_pers_upgrades_functions; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init( weapon_name, flourish_weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name, cost, wallbuy_targetname, hint_string, vo_dialog_id, flourish_fn ) +{ + precacheitem( weapon_name ); + precacheitem( flourish_weapon_name ); + add_melee_weapon( weapon_name, flourish_weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name, cost, wallbuy_targetname, hint_string, vo_dialog_id, flourish_fn ); + melee_weapon_triggers = getentarray( wallbuy_targetname, "targetname" ); + i = 0; + while ( i < melee_weapon_triggers.size ) + { + knife_model = getent( melee_weapon_triggers[ i ].target, "targetname" ); + if ( isDefined( knife_model ) ) + { + knife_model hide(); + } + melee_weapon_triggers[ i ] thread melee_weapon_think( weapon_name, cost, flourish_fn, vo_dialog_id, flourish_weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name ); + if ( isDefined( level.monolingustic_prompt_format ) && !level.monolingustic_prompt_format ) + { + melee_weapon_triggers[ i ] sethintstring( hint_string, cost ); + if ( getDvarInt( #"1F0A2129" ) && isDefined( level.disable_melee_wallbuy_icons ) && !level.disable_melee_wallbuy_icons ) + { + cursor_hint = "HINT_WEAPON"; + cursor_hint_weapon = weapon_name; + melee_weapon_triggers[ i ] setcursorhint( cursor_hint, cursor_hint_weapon ); + } + else + { + melee_weapon_triggers[ i ] setcursorhint( "HINT_NOICON" ); + } + } + else + { + weapon_display = get_weapon_display_name( weapon_name ); + hint_string = &"ZOMBIE_WEAPONCOSTONLY"; + melee_weapon_triggers[ i ] sethintstring( hint_string, weapon_display, cost ); + if ( getDvarInt( #"1F0A2129" ) && isDefined( level.disable_melee_wallbuy_icons ) && !level.disable_melee_wallbuy_icons ) + { + cursor_hint = "HINT_WEAPON"; + cursor_hint_weapon = weapon_name; + melee_weapon_triggers[ i ] setcursorhint( cursor_hint, cursor_hint_weapon ); + break; + } + else + { + melee_weapon_triggers[ i ] setcursorhint( "HINT_NOICON" ); + } + } + melee_weapon_triggers[ i ] usetriggerrequirelookat(); + i++; + } + melee_weapon_structs = getstructarray( wallbuy_targetname, "targetname" ); + i = 0; + while ( i < melee_weapon_structs.size ) + { + prepare_stub( melee_weapon_structs[ i ].trigger_stub, weapon_name, flourish_weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name, cost, wallbuy_targetname, hint_string, vo_dialog_id, flourish_fn ); + i++; + } + register_melee_weapon_for_level( weapon_name ); + if ( !isDefined( level.ballistic_weapon_name ) ) + { + level.ballistic_weapon_name = []; + } + level.ballistic_weapon_name[ weapon_name ] = ballistic_weapon_name; + if ( !isDefined( level.ballistic_upgraded_weapon_name ) ) + { + level.ballistic_upgraded_weapon_name = []; + } + level.ballistic_upgraded_weapon_name[ weapon_name ] = ballistic_upgraded_weapon_name; +/# + if ( !isDefined( level.zombie_weapons[ weapon_name ] ) ) + { + if ( isDefined( level.devgui_add_weapon ) ) + { + [[ level.devgui_add_weapon ]]( weapon_name, "", weapon_name, cost ); +#/ + } + } +} + +prepare_stub( stub, weapon_name, flourish_weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name, cost, wallbuy_targetname, hint_string, vo_dialog_id, flourish_fn ) +{ + if ( isDefined( stub ) ) + { + if ( isDefined( level.monolingustic_prompt_format ) && !level.monolingustic_prompt_format ) + { + stub.hint_string = hint_string; + if ( getDvarInt( #"1F0A2129" ) && isDefined( level.disable_melee_wallbuy_icons ) && !level.disable_melee_wallbuy_icons ) + { + stub.cursor_hint = "HINT_WEAPON"; + stub.cursor_hint_weapon = weapon_name; + } + else + { + stub.cursor_hint = "HINT_NOICON"; + stub.cursor_hint_weapon = undefined; + } + } + else + { + stub.hint_parm1 = get_weapon_display_name( weapon_name ); + stub.hint_parm2 = cost; + stub.hint_string = &"ZOMBIE_WEAPONCOSTONLY"; + if ( getDvarInt( #"1F0A2129" ) && isDefined( level.disable_melee_wallbuy_icons ) && !level.disable_melee_wallbuy_icons ) + { + stub.cursor_hint = "HINT_WEAPON"; + stub.cursor_hint_weapon = weapon_name; + } + else + { + stub.cursor_hint = "HINT_NOICON"; + stub.cursor_hint_weapon = undefined; + } + } + stub.cost = cost; + stub.weapon_name = weapon_name; + stub.vo_dialog_id = vo_dialog_id; + stub.flourish_weapon_name = flourish_weapon_name; + stub.ballistic_weapon_name = ballistic_weapon_name; + stub.ballistic_upgraded_weapon_name = ballistic_upgraded_weapon_name; + stub.trigger_func = ::melee_weapon_think; + stub.flourish_fn = flourish_fn; + } +} + +add_stub( stub, weapon_name ) +{ + melee_weapon = undefined; + i = 0; + while ( i < level._melee_weapons.size ) + { + if ( level._melee_weapons[ i ].weapon_name == weapon_name ) + { + melee_weapon = level._melee_weapons[ i ]; + break; + } + else + { + i++; + } + } + if ( isDefined( stub ) && isDefined( melee_weapon ) ) + { + prepare_stub( stub, melee_weapon.weapon_name, melee_weapon.flourish_weapon_name, melee_weapon.ballistic_weapon_name, melee_weapon.ballistic_upgraded_weapon_name, melee_weapon.cost, melee_weapon.wallbuy_targetname, melee_weapon.hint_string, melee_weapon.vo_dialog_id, melee_weapon.flourish_fn ); + } +} + +give_melee_weapon_by_name( weapon_name ) +{ + melee_weapon = undefined; + i = 0; + while ( i < level._melee_weapons.size ) + { + if ( level._melee_weapons[ i ].weapon_name == weapon_name ) + { + melee_weapon = level._melee_weapons[ i ]; + break; + } + else + { + i++; + } + } + if ( isDefined( melee_weapon ) ) + { + self thread give_melee_weapon( melee_weapon.vo_dialog_id, melee_weapon.flourish_weapon_name, melee_weapon.weapon_name, melee_weapon.ballistic_weapon_name, melee_weapon.ballistic_upgraded_weapon_name, melee_weapon.flourish_fn, undefined ); + } +} + +add_melee_weapon( weapon_name, flourish_weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name, cost, wallbuy_targetname, hint_string, vo_dialog_id, flourish_fn ) +{ + melee_weapon = spawnstruct(); + melee_weapon.weapon_name = weapon_name; + melee_weapon.flourish_weapon_name = flourish_weapon_name; + melee_weapon.ballistic_weapon_name = ballistic_weapon_name; + melee_weapon.ballistic_upgraded_weapon_name = ballistic_upgraded_weapon_name; + melee_weapon.cost = cost; + melee_weapon.wallbuy_targetname = wallbuy_targetname; + melee_weapon.hint_string = hint_string; + melee_weapon.vo_dialog_id = vo_dialog_id; + melee_weapon.flourish_fn = flourish_fn; + if ( !isDefined( level._melee_weapons ) ) + { + level._melee_weapons = []; + } + level._melee_weapons[ level._melee_weapons.size ] = melee_weapon; +} + +player_can_see_weapon_prompt( weapon_name ) +{ + if ( is_true( level._allow_melee_weapon_switching ) ) + { + return 1; + } + if ( isDefined( self get_player_melee_weapon() ) && self hasweapon( self get_player_melee_weapon() ) ) + { + return 0; + } + return 1; +} + +spectator_respawn_all() +{ + i = 0; + while ( i < level._melee_weapons.size ) + { + self spectator_respawn( level._melee_weapons[ i ].wallbuy_targetname, level._melee_weapons[ i ].weapon_name ); + i++; + } +} + +spectator_respawn( wallbuy_targetname, weapon_name ) +{ + melee_triggers = getentarray( wallbuy_targetname, "targetname" ); + players = get_players(); + i = 0; + while ( i < melee_triggers.size ) + { + melee_triggers[ i ] setvisibletoall(); + while ( isDefined( level._allow_melee_weapon_switching ) && !level._allow_melee_weapon_switching ) + { + j = 0; + while ( j < players.size ) + { + if ( !players[ j ] player_can_see_weapon_prompt( weapon_name ) ) + { + melee_triggers[ i ] setinvisibletoplayer( players[ j ] ); + } + j++; + } + } + i++; + } +} + +trigger_hide_all() +{ + i = 0; + while ( i < level._melee_weapons.size ) + { + self trigger_hide( level._melee_weapons[ i ].wallbuy_targetname ); + i++; + } +} + +trigger_hide( wallbuy_targetname ) +{ + melee_triggers = getentarray( wallbuy_targetname, "targetname" ); + i = 0; + while ( i < melee_triggers.size ) + { + melee_triggers[ i ] setinvisibletoplayer( self ); + i++; + } +} + +has_any_ballistic_knife() +{ + if ( self hasweapon( "knife_ballistic_zm" ) ) + { + return 1; + } + if ( self hasweapon( "knife_ballistic_upgraded_zm" ) ) + { + return 1; + } + i = 0; + while ( i < level._melee_weapons.size ) + { + if ( self hasweapon( level._melee_weapons[ i ].ballistic_weapon_name ) ) + { + return 1; + } + if ( self hasweapon( level._melee_weapons[ i ].ballistic_upgraded_weapon_name ) ) + { + return 1; + } + i++; + } + return 0; +} + +has_upgraded_ballistic_knife() +{ + if ( self hasweapon( "knife_ballistic_upgraded_zm" ) ) + { + return 1; + } + i = 0; + while ( i < level._melee_weapons.size ) + { + if ( self hasweapon( level._melee_weapons[ i ].ballistic_upgraded_weapon_name ) ) + { + return 1; + } + i++; + } + return 0; +} + +give_ballistic_knife( weapon_string, upgraded ) +{ + current_melee_weapon = self get_player_melee_weapon(); + if ( isDefined( current_melee_weapon ) ) + { + if ( upgraded && isDefined( level.ballistic_upgraded_weapon_name ) && isDefined( level.ballistic_upgraded_weapon_name[ current_melee_weapon ] ) ) + { + weapon_string = level.ballistic_upgraded_weapon_name[ current_melee_weapon ]; + } + if ( !upgraded && isDefined( level.ballistic_weapon_name ) && isDefined( level.ballistic_weapon_name[ current_melee_weapon ] ) ) + { + weapon_string = level.ballistic_weapon_name[ current_melee_weapon ]; + } + } + return weapon_string; +} + +change_melee_weapon( weapon_name, current_weapon ) +{ + current_melee_weapon = self get_player_melee_weapon(); + if ( isDefined( current_melee_weapon ) && current_melee_weapon != weapon_name ) + { + self takeweapon( current_melee_weapon ); + unacquire_weapon_toggle( current_melee_weapon ); + } + self set_player_melee_weapon( weapon_name ); + had_ballistic = 0; + had_ballistic_upgraded = 0; + ballistic_was_primary = 0; + primaryweapons = self getweaponslistprimaries(); + i = 0; + while ( i < primaryweapons.size ) + { + primary_weapon = primaryweapons[ i ]; + if ( issubstr( primary_weapon, "knife_ballistic_" ) ) + { + had_ballistic = 1; + if ( primary_weapon == current_weapon ) + { + ballistic_was_primary = 1; + } + self notify( "zmb_lost_knife" ); + self takeweapon( primary_weapon ); + unacquire_weapon_toggle( primary_weapon ); + if ( issubstr( primary_weapon, "upgraded" ) ) + { + had_ballistic_upgraded = 1; + } + } + i++; + } + if ( had_ballistic ) + { + if ( had_ballistic_upgraded ) + { + new_ballistic = level.ballistic_upgraded_weapon_name[ weapon_name ]; + if ( ballistic_was_primary ) + { + current_weapon = new_ballistic; + } + self giveweapon( new_ballistic, 0, self maps/mp/zombies/_zm_weapons::get_pack_a_punch_weapon_options( new_ballistic ) ); + } + else + { + new_ballistic = level.ballistic_weapon_name[ weapon_name ]; + if ( ballistic_was_primary ) + { + current_weapon = new_ballistic; + } + self giveweapon( new_ballistic, 0 ); + } + } + return current_weapon; +} + +melee_weapon_think( weapon_name, cost, flourish_fn, vo_dialog_id, flourish_weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name ) +{ + self.first_time_triggered = 0; + while ( isDefined( self.stub ) ) + { + self endon( "kill_trigger" ); + if ( isDefined( self.stub.first_time_triggered ) ) + { + self.first_time_triggered = self.stub.first_time_triggered; + } + weapon_name = self.stub.weapon_name; + cost = self.stub.cost; + flourish_fn = self.stub.flourish_fn; + vo_dialog_id = self.stub.vo_dialog_id; + flourish_weapon_name = self.stub.flourish_weapon_name; + ballistic_weapon_name = self.stub.ballistic_weapon_name; + ballistic_upgraded_weapon_name = self.stub.ballistic_upgraded_weapon_name; + players = getplayers(); + while ( isDefined( level._allow_melee_weapon_switching ) && !level._allow_melee_weapon_switching ) + { + i = 0; + while ( i < players.size ) + { + if ( !players[ i ] player_can_see_weapon_prompt( weapon_name ) ) + { + self setinvisibletoplayer( players[ i ] ); + } + i++; + } + } + } + for ( ;; ) + { + self waittill( "trigger", player ); + if ( !is_player_valid( player ) ) + { + player thread ignore_triggers( 0,5 ); + continue; + } + else if ( player in_revive_trigger() ) + { + wait 0,1; + continue; + } + else if ( player isthrowinggrenade() ) + { + wait 0,1; + continue; + } + else if ( player.is_drinking > 0 ) + { + wait 0,1; + continue; + } + else if ( player hasweapon( weapon_name ) || player has_powerup_weapon() ) + { + wait 0,1; + continue; + } + else + { + if ( player isswitchingweapons() ) + { + wait 0,1; + break; + } + else current_weapon = player getcurrentweapon(); + if ( !is_placeable_mine( current_weapon ) || is_equipment( current_weapon ) && player has_powerup_weapon() ) + { + wait 0,1; + break; + } + else + { + if ( player maps/mp/zombies/_zm_laststand::player_is_in_laststand() || isDefined( player.intermission ) && player.intermission ) + { + wait 0,1; + break; + } + else + { + player_has_weapon = player hasweapon( weapon_name ); + if ( !player_has_weapon ) + { + cost = self.stub.cost; + if ( player maps/mp/zombies/_zm_pers_upgrades_functions::is_pers_double_points_active() ) + { + cost = int( cost / 2 ); + } + if ( player.score >= cost ) + { + if ( self.first_time_triggered == 0 ) + { + model = getent( self.target, "targetname" ); + if ( isDefined( model ) ) + { + model thread melee_weapon_show( player ); + } + else + { + if ( isDefined( self.clientfieldname ) ) + { + level setclientfield( self.clientfieldname, 1 ); + } + } + self.first_time_triggered = 1; + if ( isDefined( self.stub ) ) + { + self.stub.first_time_triggered = 1; + } + } + player maps/mp/zombies/_zm_score::minus_to_player_score( cost, 1 ); + bbprint( "zombie_uses", "playername %s playerscore %d round %d cost %d name %s x %f y %f z %f type %s", player.name, player.score, level.round_number, cost, weapon_name, self.origin, "weapon" ); + player thread give_melee_weapon( vo_dialog_id, flourish_weapon_name, weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name, flourish_fn, self ); + } + else + { + play_sound_on_ent( "no_purchase" ); + player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "no_money_weapon", undefined, 1 ); + } + break; + } + else + { + if ( isDefined( level._allow_melee_weapon_switching ) && !level._allow_melee_weapon_switching ) + { + self setinvisibletoplayer( player ); + } + } + } + } + } + } +} + +melee_weapon_show( player ) +{ + player_angles = vectorToAngle( player.origin - self.origin ); + player_yaw = player_angles[ 1 ]; + weapon_yaw = self.angles[ 1 ]; + yaw_diff = angleClamp180( player_yaw - weapon_yaw ); + if ( yaw_diff > 0 ) + { + yaw = weapon_yaw - 90; + } + else + { + yaw = weapon_yaw + 90; + } + self.og_origin = self.origin; + self.origin += anglesToForward( ( 0, yaw, 0 ) ) * 8; + wait 0,05; + self show(); + play_sound_at_pos( "weapon_show", self.origin, self ); + time = 1; + self moveto( self.og_origin, time ); +} + +give_melee_weapon( vo_dialog_id, flourish_weapon_name, weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name, flourish_fn, trigger ) +{ + if ( isDefined( flourish_fn ) ) + { + self thread [[ flourish_fn ]](); + } + gun = self do_melee_weapon_flourish_begin( flourish_weapon_name ); + self maps/mp/zombies/_zm_audio::create_and_play_dialog( "weapon_pickup", vo_dialog_id ); + self waittill_any( "fake_death", "death", "player_downed", "weapon_change_complete" ); + self do_melee_weapon_flourish_end( gun, flourish_weapon_name, weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name ); + if ( self maps/mp/zombies/_zm_laststand::player_is_in_laststand() || isDefined( self.intermission ) && self.intermission ) + { + return; + } + if ( isDefined( level._allow_melee_weapon_switching ) && !level._allow_melee_weapon_switching ) + { + if ( isDefined( trigger ) ) + { + trigger setinvisibletoplayer( self ); + } + self trigger_hide_all(); + } +} + +do_melee_weapon_flourish_begin( flourish_weapon_name ) +{ + self increment_is_drinking(); + self disable_player_move_states( 1 ); + gun = self getcurrentweapon(); + weapon = flourish_weapon_name; + self giveweapon( weapon ); + self switchtoweapon( weapon ); + return gun; +} + +do_melee_weapon_flourish_end( gun, flourish_weapon_name, weapon_name, ballistic_weapon_name, ballistic_upgraded_weapon_name ) +{ +/# + assert( !is_zombie_perk_bottle( gun ) ); +#/ +/# + assert( gun != level.revive_tool ); +#/ + self enable_player_move_states(); + weapon = flourish_weapon_name; + if ( self maps/mp/zombies/_zm_laststand::player_is_in_laststand() || isDefined( self.intermission ) && self.intermission ) + { + self takeweapon( weapon ); + self.lastactiveweapon = "none"; + return; + } + self takeweapon( weapon ); + self giveweapon( weapon_name ); + gun = change_melee_weapon( weapon_name, gun ); + if ( self hasweapon( "knife_zm" ) ) + { + self takeweapon( "knife_zm" ); + } + if ( self is_multiple_drinking() ) + { + self decrement_is_drinking(); + return; + } + else if ( gun == "knife_zm" ) + { + self switchtoweapon( weapon_name ); + self decrement_is_drinking(); + return; + } + else if ( gun != "none" && !is_placeable_mine( gun ) && !is_equipment( gun ) ) + { + self switchtoweapon( gun ); + } + else + { + primaryweapons = self getweaponslistprimaries(); + if ( isDefined( primaryweapons ) && primaryweapons.size > 0 ) + { + self switchtoweapon( primaryweapons[ 0 ] ); + } + } + self waittill( "weapon_change_complete" ); + if ( !self maps/mp/zombies/_zm_laststand::player_is_in_laststand() && isDefined( self.intermission ) && !self.intermission ) + { + self decrement_is_drinking(); + } +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_perk_divetonuke.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_perk_divetonuke.gsc new file mode 100644 index 0000000..9bc5e58 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_perk_divetonuke.gsc @@ -0,0 +1,180 @@ +#include maps/mp/_visionset_mgr; +#include maps/mp/zombies/_zm_perks; +#include maps/mp/zombies/_zm_net; +#include maps/mp/zombies/_zm_utility; +#include common_scripts/utility; +#include maps/mp/_utility; + +enable_divetonuke_perk_for_level() +{ + maps/mp/zombies/_zm_perks::register_perk_basic_info( "specialty_flakjacket", "divetonuke", 2000, &"ZOMBIE_PERK_DIVETONUKE", "zombie_perk_bottle_nuke" ); + maps/mp/zombies/_zm_perks::register_perk_precache_func( "specialty_flakjacket", ::divetonuke_precache ); + maps/mp/zombies/_zm_perks::register_perk_clientfields( "specialty_flakjacket", ::divetonuke_register_clientfield, ::divetonuke_set_clientfield ); + maps/mp/zombies/_zm_perks::register_perk_machine( "specialty_flakjacket", ::divetonuke_perk_machine_setup, ::divetonuke_perk_machine_think ); + maps/mp/zombies/_zm_perks::register_perk_host_migration_func( "specialty_flakjacket", ::divetonuke_host_migration_func ); +} + +init_divetonuke() +{ + level.zombiemode_divetonuke_perk_func = ::divetonuke_explode; + maps/mp/_visionset_mgr::vsmgr_register_info( "visionset", "zm_perk_divetonuke", 9000, 400, 5, 1 ); + level._effect[ "divetonuke_groundhit" ] = loadfx( "maps/zombie/fx_zmb_phdflopper_exp" ); + set_zombie_var( "zombie_perk_divetonuke_radius", 300 ); + set_zombie_var( "zombie_perk_divetonuke_min_damage", 1000 ); + set_zombie_var( "zombie_perk_divetonuke_max_damage", 5000 ); +} + +divetonuke_precache() +{ + if ( isDefined( level.divetonuke_precache_override_func ) ) + { + [[ level.divetonuke_precache_override_func ]](); + return; + } + precacheitem( "zombie_perk_bottle_nuke" ); + precacheshader( "specialty_divetonuke_zombies" ); + precachemodel( "zombie_vending_nuke" ); + precachemodel( "zombie_vending_nuke_on" ); + precachestring( &"ZOMBIE_PERK_DIVETONUKE" ); + level._effect[ "divetonuke_light" ] = loadfx( "misc/fx_zombie_cola_dtap_on" ); + level.machine_assets[ "divetonuke" ] = spawnstruct(); + level.machine_assets[ "divetonuke" ].weapon = "zombie_perk_bottle_nuke"; + level.machine_assets[ "divetonuke" ].off_model = "zombie_vending_nuke"; + level.machine_assets[ "divetonuke" ].on_model = "zombie_vending_nuke_on"; +} + +divetonuke_register_clientfield() +{ + registerclientfield( "toplayer", "perk_dive_to_nuke", 9000, 1, "int" ); +} + +divetonuke_set_clientfield( state ) +{ + self setclientfieldtoplayer( "perk_dive_to_nuke", state ); +} + +divetonuke_perk_machine_setup( use_trigger, perk_machine, bump_trigger, collision ) +{ + use_trigger.script_sound = "mus_perks_phd_jingle"; + use_trigger.script_string = "divetonuke_perk"; + use_trigger.script_label = "mus_perks_phd_sting"; + use_trigger.target = "vending_divetonuke"; + perk_machine.script_string = "divetonuke_perk"; + perk_machine.targetname = "vending_divetonuke"; + if ( isDefined( bump_trigger ) ) + { + bump_trigger.script_string = "divetonuke_perk"; + } +} + +divetonuke_perk_machine_think() +{ + init_divetonuke(); + while ( 1 ) + { + machine = getentarray( "vending_divetonuke", "targetname" ); + machine_triggers = getentarray( "vending_divetonuke", "target" ); + i = 0; + while ( i < machine.size ) + { + machine[ i ] setmodel( level.machine_assets[ "divetonuke" ].off_model ); + i++; + } + array_thread( machine_triggers, ::set_power_on, 0 ); + level thread do_initial_power_off_callback( machine, "divetonuke" ); + level waittill( "divetonuke_on" ); + i = 0; + while ( i < machine.size ) + { + machine[ i ] setmodel( level.machine_assets[ "divetonuke" ].on_model ); + machine[ i ] vibrate( vectorScale( ( 0, -1, 0 ), 100 ), 0,3, 0,4, 3 ); + machine[ i ] playsound( "zmb_perks_power_on" ); + machine[ i ] thread perk_fx( "divetonuke_light" ); + machine[ i ] thread play_loop_on_machine(); + i++; + } + level notify( "specialty_flakjacket_power_on" ); + array_thread( machine_triggers, ::set_power_on, 1 ); + if ( isDefined( level.machine_assets[ "divetonuke" ].power_on_callback ) ) + { + array_thread( machine, level.machine_assets[ "divetonuke" ].power_on_callback ); + } + level waittill( "divetonuke_off" ); + if ( isDefined( level.machine_assets[ "divetonuke" ].power_off_callback ) ) + { + array_thread( machine, level.machine_assets[ "divetonuke" ].power_off_callback ); + } + array_thread( machine, ::turn_perk_off ); + } +} + +divetonuke_host_migration_func() +{ + flop = getentarray( "vending_divetonuke", "targetname" ); + _a138 = flop; + _k138 = getFirstArrayKey( _a138 ); + while ( isDefined( _k138 ) ) + { + perk = _a138[ _k138 ]; + if ( isDefined( perk.model ) && perk.model == level.machine_assets[ "divetonuke" ].on_model ) + { + perk perk_fx( undefined, 1 ); + perk thread perk_fx( "divetonuke_light" ); + } + _k138 = getNextArrayKey( _a138, _k138 ); + } +} + +divetonuke_explode( attacker, origin ) +{ + radius = level.zombie_vars[ "zombie_perk_divetonuke_radius" ]; + min_damage = level.zombie_vars[ "zombie_perk_divetonuke_min_damage" ]; + max_damage = level.zombie_vars[ "zombie_perk_divetonuke_max_damage" ]; + if ( isDefined( level.flopper_network_optimized ) && level.flopper_network_optimized ) + { + attacker thread divetonuke_explode_network_optimized( origin, radius, max_damage, min_damage, "MOD_GRENADE_SPLASH" ); + } + else + { + radiusdamage( origin, radius, max_damage, min_damage, attacker, "MOD_GRENADE_SPLASH" ); + } + playfx( level._effect[ "divetonuke_groundhit" ], origin ); + attacker playsound( "zmb_phdflop_explo" ); + maps/mp/_visionset_mgr::vsmgr_activate( "visionset", "zm_perk_divetonuke", attacker ); + wait 1; + maps/mp/_visionset_mgr::vsmgr_deactivate( "visionset", "zm_perk_divetonuke", attacker ); +} + +divetonuke_explode_network_optimized( origin, radius, max_damage, min_damage, damage_mod ) +{ + self endon( "disconnect" ); + a_zombies = get_array_of_closest( origin, get_round_enemy_array(), undefined, undefined, radius ); + network_stall_counter = 0; + while ( isDefined( a_zombies ) ) + { + i = 0; + while ( i < a_zombies.size ) + { + e_zombie = a_zombies[ i ]; + if ( !isDefined( e_zombie ) || !isalive( e_zombie ) ) + { + i++; + continue; + } + else + { + dist = distance( e_zombie.origin, origin ); + damage = min_damage + ( ( max_damage - min_damage ) * ( 1 - ( dist / radius ) ) ); + e_zombie dodamage( damage, e_zombie.origin, self, self, 0, damage_mod ); + network_stall_counter--; + + if ( network_stall_counter <= 0 ) + { + wait_network_frame(); + network_stall_counter = randomintrange( 1, 3 ); + } + } + i++; + } + } +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_powerup_zombie_blood.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_powerup_zombie_blood.gsc new file mode 100644 index 0000000..b36a329 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_powerup_zombie_blood.gsc @@ -0,0 +1,217 @@ +#include maps/mp/_visionset_mgr; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/zombies/_zm_powerups; +#include maps/mp/_utility; +#include common_scripts/utility; + +init( str_zombie_model ) +{ + level.str_zombie_blood_model = str_zombie_model; + precachemodel( level.str_zombie_blood_model ); + registerclientfield( "allplayers", "player_zombie_blood_fx", 14000, 1, "int" ); + level._effect[ "zombie_blood" ] = loadfx( "maps/zombie_tomb/fx_tomb_pwr_up_zmb_blood" ); + level._effect[ "zombie_blood_1st" ] = loadfx( "maps/zombie_tomb/fx_zm_blood_overlay_pclouds" ); + add_zombie_powerup( "zombie_blood", "p6_zm_tm_blood_power_up", &"ZOMBIE_POWERUP_MAX_AMMO", ::func_should_always_drop, 1, 0, 0, undefined, "powerup_zombie_blood", "zombie_powerup_zombie_blood_time", "zombie_powerup_zombie_blood_on" ); + powerup_set_can_pick_up_in_last_stand( "zombie_blood", 0 ); + onplayerconnect_callback( ::init_player_zombie_blood_vars ); + level.a_zombie_blood_entities = []; + array_thread( getentarray( "zombie_blood_visible", "targetname" ), ::make_zombie_blood_entity ); + if ( !isDefined( level.vsmgr_prio_visionset_zm_powerup_zombie_blood ) ) + { + level.vsmgr_prio_visionset_zm_powerup_zombie_blood = 15; + } + if ( !isDefined( level.vsmgr_prio_overlay_zm_powerup_zombie_blood ) ) + { + level.vsmgr_prio_overlay_zm_powerup_zombie_blood = 16; + } + maps/mp/_visionset_mgr::vsmgr_register_info( "visionset", "zm_powerup_zombie_blood_visionset", 14000, level.vsmgr_prio_visionset_zm_powerup_zombie_blood, 15, 1 ); + maps/mp/_visionset_mgr::vsmgr_register_info( "overlay", "zm_powerup_zombie_blood_overlay", 14000, level.vsmgr_prio_overlay_zm_powerup_zombie_blood, 15, 1 ); +} + +init_player_zombie_blood_vars() +{ + self.zombie_vars[ "zombie_powerup_zombie_blood_on" ] = 0; + self.zombie_vars[ "zombie_powerup_zombie_blood_time" ] = 30; +} + +zombie_blood_powerup( m_powerup, e_player ) +{ + e_player notify( "zombie_blood" ); + e_player endon( "zombie_blood" ); + e_player endon( "disconnect" ); + e_player thread powerup_vo( "zombie_blood" ); + e_player.ignoreme = 1; + e_player._show_solo_hud = 1; + e_player.zombie_vars[ "zombie_powerup_zombie_blood_time" ] = 30; + e_player.zombie_vars[ "zombie_powerup_zombie_blood_on" ] = 1; + level notify( "player_zombie_blood" ); + maps/mp/_visionset_mgr::vsmgr_activate( "visionset", "zm_powerup_zombie_blood_visionset", e_player ); + maps/mp/_visionset_mgr::vsmgr_activate( "overlay", "zm_powerup_zombie_blood_overlay", e_player ); + e_player setclientfield( "player_zombie_blood_fx", 1 ); + __new = []; + _a73 = level.a_zombie_blood_entities; + __key = getFirstArrayKey( _a73 ); + while ( isDefined( __key ) ) + { + __value = _a73[ __key ]; + if ( isDefined( __value ) ) + { + if ( isstring( __key ) ) + { + __new[ __key ] = __value; + break; + } + else + { + __new[ __new.size ] = __value; + } + } + __key = getNextArrayKey( _a73, __key ); + } + level.a_zombie_blood_entities = __new; + _a74 = level.a_zombie_blood_entities; + _k74 = getFirstArrayKey( _a74 ); + while ( isDefined( _k74 ) ) + { + e_zombie_blood = _a74[ _k74 ]; + if ( isDefined( e_zombie_blood.e_unique_player ) ) + { + if ( e_zombie_blood.e_unique_player == e_player ) + { + e_zombie_blood setvisibletoplayer( e_player ); + } + } + else + { + e_zombie_blood setvisibletoplayer( e_player ); + } + _k74 = getNextArrayKey( _a74, _k74 ); + } + if ( !isDefined( e_player.m_fx ) ) + { + v_origin = e_player gettagorigin( "J_Eyeball_LE" ); + v_angles = e_player gettagangles( "J_Eyeball_LE" ); + m_fx = spawn( "script_model", v_origin ); + m_fx setmodel( "tag_origin" ); + m_fx.angles = v_angles; + m_fx linkto( e_player, "J_Eyeball_LE", ( 0, 0, 0 ), ( 0, 0, 0 ) ); + m_fx thread fx_disconnect_watch( e_player ); + playfxontag( level._effect[ "zombie_blood" ], m_fx, "tag_origin" ); + e_player.m_fx = m_fx; + e_player.m_fx playloopsound( "zmb_zombieblood_3rd_loop", 1 ); + if ( isDefined( level.str_zombie_blood_model ) ) + { + e_player.hero_model = e_player.model; + e_player setmodel( level.str_zombie_blood_model ); + } + } + e_player thread watch_zombie_blood_early_exit(); + while ( e_player.zombie_vars[ "zombie_powerup_zombie_blood_time" ] >= 0 ) + { + wait 0,05; + e_player.zombie_vars[ "zombie_powerup_zombie_blood_time" ] -= 0,05; + } + e_player notify( "zombie_blood_over" ); + if ( isDefined( e_player.characterindex ) ) + { + e_player playsound( "vox_plr_" + e_player.characterindex + "_exert_grunt_" + randomintrange( 0, 3 ) ); + } + e_player.m_fx delete(); + maps/mp/_visionset_mgr::vsmgr_deactivate( "visionset", "zm_powerup_zombie_blood_visionset", e_player ); + maps/mp/_visionset_mgr::vsmgr_deactivate( "overlay", "zm_powerup_zombie_blood_overlay", e_player ); + e_player.zombie_vars[ "zombie_powerup_zombie_blood_on" ] = 0; + e_player.zombie_vars[ "zombie_powerup_zombie_blood_time" ] = 30; + e_player._show_solo_hud = 0; + e_player setclientfield( "player_zombie_blood_fx", 0 ); + if ( !isDefined( e_player.early_exit ) ) + { + e_player.ignoreme = 0; + } + else + { + e_player.early_exit = undefined; + } + __new = []; + _a145 = level.a_zombie_blood_entities; + __key = getFirstArrayKey( _a145 ); + while ( isDefined( __key ) ) + { + __value = _a145[ __key ]; + if ( isDefined( __value ) ) + { + if ( isstring( __key ) ) + { + __new[ __key ] = __value; + break; + } + else + { + __new[ __new.size ] = __value; + } + } + __key = getNextArrayKey( _a145, __key ); + } + level.a_zombie_blood_entities = __new; + _a146 = level.a_zombie_blood_entities; + _k146 = getFirstArrayKey( _a146 ); + while ( isDefined( _k146 ) ) + { + e_zombie_blood = _a146[ _k146 ]; + e_zombie_blood setinvisibletoplayer( e_player ); + _k146 = getNextArrayKey( _a146, _k146 ); + } + if ( isDefined( e_player.hero_model ) ) + { + e_player setmodel( e_player.hero_model ); + e_player.hero_model = undefined; + } +} + +fx_disconnect_watch( e_player ) +{ + self endon( "death" ); + e_player waittill( "disconnect" ); + self delete(); +} + +watch_zombie_blood_early_exit() +{ + self notify( "early_exit_watch" ); + self endon( "early_exit_watch" ); + self endon( "zombie_blood_over" ); + self endon( "disconnect" ); + waittill_any_ents_two( self, "player_downed", level, "end_game" ); + self.zombie_vars[ "zombie_powerup_zombie_blood_time" ] = -0,05; + self.early_exit = 1; +} + +make_zombie_blood_entity() +{ +/# + assert( isDefined( level.a_zombie_blood_entities ), "zombie blood powerup not initiliazed in level" ); +#/ + level.a_zombie_blood_entities[ level.a_zombie_blood_entities.size ] = self; + self setinvisibletoall(); + _a196 = getplayers(); + _k196 = getFirstArrayKey( _a196 ); + while ( isDefined( _k196 ) ) + { + e_player = _a196[ _k196 ]; + if ( e_player.zombie_vars[ "zombie_powerup_zombie_blood_on" ] ) + { + if ( isDefined( self.e_unique_player ) ) + { + if ( self.e_unique_player == e_player ) + { + self setvisibletoplayer( e_player ); + } + break; + } + else + { + self setvisibletoplayer( e_player ); + } + } + _k196 = getNextArrayKey( _a196, _k196 ); + } +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_riotshield_tomb.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_riotshield_tomb.gsc new file mode 100644 index 0000000..c601f12 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_riotshield_tomb.gsc @@ -0,0 +1,671 @@ +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_equipment; +#include maps/mp/zombies/_zm_buildables; +#include maps/mp/zombies/_zm_weap_riotshield_tomb; +#include common_scripts/utility; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; + +init() +{ + level.riotshield_name = "tomb_shield_zm"; + level.deployedshieldmodel = []; + level.stowedshieldmodel = []; + level.carriedshieldmodel = []; + level.deployedshieldmodel[ 0 ] = "t6_wpn_zmb_shield_dlc4_dmg0_world"; + level.deployedshieldmodel[ 2 ] = "t6_wpn_zmb_shield_dlc4_dmg1_world"; + level.deployedshieldmodel[ 3 ] = "t6_wpn_zmb_shield_dlc4_dmg2_world"; + level.stowedshieldmodel[ 0 ] = "t6_wpn_zmb_shield_dlc4_dmg0_stow"; + level.stowedshieldmodel[ 2 ] = "t6_wpn_zmb_shield_dlc4_dmg1_stow"; + level.stowedshieldmodel[ 3 ] = "t6_wpn_zmb_shield_dlc4_dmg2_stow"; + level.carriedshieldmodel[ 0 ] = "t6_wpn_zmb_shield_dlc4_dmg0_world"; + level.carriedshieldmodel[ 2 ] = "t6_wpn_zmb_shield_dlc4_dmg1_world"; + level.carriedshieldmodel[ 3 ] = "t6_wpn_zmb_shield_dlc4_dmg2_world"; + level.viewshieldmodel[ 0 ] = "t6_wpn_zmb_shield_dlc4_dmg0_view"; + level.viewshieldmodel[ 2 ] = "t6_wpn_zmb_shield_dlc4_dmg1_view"; + level.viewshieldmodel[ 3 ] = "t6_wpn_zmb_shield_dlc4_dmg2_view"; + precachemodel( level.stowedshieldmodel[ 0 ] ); + precachemodel( level.stowedshieldmodel[ 2 ] ); + precachemodel( level.stowedshieldmodel[ 3 ] ); + precachemodel( level.carriedshieldmodel[ 0 ] ); + precachemodel( level.carriedshieldmodel[ 2 ] ); + precachemodel( level.carriedshieldmodel[ 3 ] ); + precachemodel( level.viewshieldmodel[ 0 ] ); + precachemodel( level.viewshieldmodel[ 2 ] ); + precachemodel( level.viewshieldmodel[ 3 ] ); + level.riotshield_placement_zoffset = 26; +} + +attachriotshield( model, tag ) +{ + if ( isDefined( self.prev_shield_model ) && isDefined( self.prev_shield_tag ) ) + { + self detachshieldmodel( self.prev_shield_model, self.prev_shield_tag ); + } + self.prev_shield_model = model; + self.prev_shield_tag = tag; + if ( isDefined( self.prev_shield_model ) && isDefined( self.prev_shield_tag ) ) + { + self attachshieldmodel( self.prev_shield_model, self.prev_shield_tag ); + } +} + +removeriotshield() +{ + if ( isDefined( self.prev_shield_model ) && isDefined( self.prev_shield_tag ) ) + { + self detachshieldmodel( self.prev_shield_model, self.prev_shield_tag ); + } + self.prev_shield_model = undefined; + self.prev_shield_tag = undefined; + if ( self getcurrentweapon() != level.riotshield_name ) + { + return; + } + self setheldweaponmodel( 0 ); +} + +setriotshieldviewmodel( modelnum ) +{ + self.prev_shield_viewmodel = modelnum; + if ( self getcurrentweapon() != level.riotshield_name ) + { + return; + } + if ( isDefined( self.prev_shield_viewmodel ) ) + { + self setheldweaponmodel( self.prev_shield_viewmodel ); + } + else + { + self setheldweaponmodel( 0 ); + } +} + +specialriotshieldviewmodel() +{ + if ( self getcurrentweapon() != level.riotshield_name ) + { + return; + } + self setheldweaponmodel( 3 ); +} + +restoreriotshieldviewmodel() +{ + if ( self getcurrentweapon() != level.riotshield_name ) + { + return; + } + if ( isDefined( self.prev_shield_viewmodel ) ) + { + self setheldweaponmodel( self.prev_shield_viewmodel ); + } + else + { + self setheldweaponmodel( 0 ); + } +} + +updateriotshieldmodel() +{ + if ( !isDefined( self.shield_damage_level ) ) + { + if ( isDefined( self.player_shield_reset_health ) ) + { + self [[ self.player_shield_reset_health ]](); + } + } + update = 0; + if ( !isDefined( self.prev_shield_damage_level ) || self.prev_shield_damage_level != self.shield_damage_level ) + { + self.prev_shield_damage_level = self.shield_damage_level; + update = 1; + } + if ( !isDefined( self.prev_shield_placement ) || self.prev_shield_placement != self.shield_placement ) + { + self.prev_shield_placement = self.shield_placement; + update = 1; + } + if ( update ) + { + if ( self.prev_shield_placement == 0 ) + { + self attachriotshield(); + return; + } + else if ( self.prev_shield_placement == 1 ) + { + self attachriotshield( level.carriedshieldmodel[ self.prev_shield_damage_level ], "tag_weapon_left" ); + self setriotshieldviewmodel( self.prev_shield_damage_level ); + return; + } + else if ( self.prev_shield_placement == 2 ) + { + self attachriotshield( level.stowedshieldmodel[ self.prev_shield_damage_level ], "tag_stowed_back" ); + return; + } + else + { + if ( self.prev_shield_placement == 3 ) + { + self attachriotshield(); + if ( isDefined( self.shield_ent ) ) + { + self.shield_ent setmodel( level.deployedshieldmodel[ self.prev_shield_damage_level ] ); + } + } + } + } +} + +updatestandaloneriotshieldmodel() +{ + update = 0; + if ( !isDefined( self.prev_shield_damage_level ) || self.prev_shield_damage_level != self.shield_damage_level ) + { + self.prev_shield_damage_level = self.shield_damage_level; + update = 1; + } + if ( update ) + { + self setmodel( level.deployedshieldmodel[ self.prev_shield_damage_level ] ); + } +} + +watchshieldlaststand() +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "watchShieldLastStand" ); + self endon( "watchShieldLastStand" ); + while ( 1 ) + { + self waittill( "weapons_taken_for_last_stand" ); + self.riotshield_hidden = 0; + if ( isDefined( self.hasriotshield ) && self.hasriotshield ) + { + if ( self.prev_shield_placement == 1 || self.prev_shield_placement == 2 ) + { + self.riotshield_hidden = 2; + self.shield_placement = 0; + self updateriotshieldmodel(); + } + } + str_notify = self waittill_any_return( "player_revived", "bled_out" ); + if ( str_notify == "player_revived" ) + { + if ( isDefined( self.riotshield_hidden ) && self.riotshield_hidden > 0 ) + { + self.shield_placement = self.riotshield_hidden; + self updateriotshieldmodel(); + } + } + else + { + self maps/mp/zombies/_zm_weap_riotshield_tomb::player_take_riotshield(); + } + self.riotshield_hidden = undefined; + } +} + +trackriotshield() +{ + self endon( "death" ); + self endon( "disconnect" ); + self.hasriotshield = self hasweapon( level.riotshield_name ); + self.hasriotshieldequipped = self getcurrentweapon() == level.riotshield_name; + self.shield_placement = 0; + if ( self.hasriotshield ) + { + if ( self.hasriotshieldequipped ) + { + self.shield_placement = 1; + self updateriotshieldmodel(); + } + else + { + self.shield_placement = 2; + self updateriotshieldmodel(); + } + } + for ( ;; ) + { + self waittill( "weapon_change", newweapon ); + if ( newweapon == level.riotshield_name ) + { + if ( self.hasriotshieldequipped ) + { + continue; + } + else if ( isDefined( self.riotshieldentity ) ) + { + self notify( "destroy_riotshield" ); + } + self.shield_placement = 1; + self updateriotshieldmodel(); + if ( self.hasriotshield ) + { + break; + } + self.hasriotshield = 1; + self.hasriotshieldequipped = 1; + continue; + } + else if ( self ismantling() && newweapon == "none" ) + { + continue; + } + else + { + if ( self.hasriotshieldequipped ) + { +/# + assert( self.hasriotshield ); +#/ + self.hasriotshield = self hasweapon( level.riotshield_name ); + if ( isDefined( self.riotshield_hidden ) && self.riotshield_hidden ) + { + } + else + { + if ( self.hasriotshield ) + { + self.shield_placement = 2; + break; + } + else if ( isDefined( self.shield_ent ) ) + { +/# + assert( self.shield_placement == 3 ); +#/ + break; + } + else + { + self.shield_placement = 0; + } + } + self updateriotshieldmodel(); + self.hasriotshieldequipped = 0; + break; + } + else if ( self.hasriotshield ) + { + if ( !self hasweapon( level.riotshield_name ) ) + { + self.shield_placement = 0; + self updateriotshieldmodel(); + self.hasriotshield = 0; + } + break; + } + else + { + if ( self hasweapon( level.riotshield_name ) ) + { + self.shield_placement = 2; + self updateriotshieldmodel(); + self.hasriotshield = 1; + } + } + } + } +} + +trackequipmentchange() +{ + self endon( "death" ); + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "equipment_dropped", equipname ); + self notify( "weapon_change" ); + } +} + +updateriotshieldplacement() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "deploy_riotshield" ); + self endon( "start_riotshield_deploy" ); + self endon( "weapon_change" ); + while ( 1 ) + { + placement = self canplaceriotshield( "raise_riotshield" ); + if ( placement[ "result" ] && riotshielddistancetest( placement[ "origin" ] ) ) + { + self restoreriotshieldviewmodel(); + self setplacementhint( 1 ); + } + else + { + self specialriotshieldviewmodel(); + self setplacementhint( 0 ); + } + wait 0,05; + } +} + +startriotshielddeploy() +{ + self notify( "start_riotshield_deploy" ); + self thread updateriotshieldplacement(); + self thread watchriotshielddeploy(); +} + +spawnriotshieldcover( origin, angles ) +{ + shield_ent = spawn( "script_model", origin, 1 ); + shield_ent.angles = angles; + shield_ent setowner( self ); + shield_ent.owner = self; + shield_ent.owner.shield_ent = shield_ent; + shield_ent.isriotshield = 1; + self.shield_placement = 3; + self updateriotshieldmodel(); + shield_ent setscriptmoverflag( 0 ); + self thread maps/mp/zombies/_zm_buildables::delete_on_disconnect( shield_ent, "destroy_riotshield", 1 ); + maps/mp/zombies/_zm_equipment::destructible_equipment_list_add( shield_ent ); + return shield_ent; +} + +watchriotshielddeploy() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "start_riotshield_deploy" ); + self endon( "destroy_riotshield" ); + self waittill( "deploy_riotshield", deploy_attempt ); + self restoreriotshieldviewmodel(); + self setplacementhint( 1 ); + placement_hint = 0; + if ( deploy_attempt ) + { + placement = self canplaceriotshield( "deploy_riotshield" ); + if ( placement[ "result" ] && riotshielddistancetest( placement[ "origin" ] ) && self check_plant_position( placement[ "origin" ], placement[ "angles" ] ) ) + { + self doriotshielddeploy( placement[ "origin" ], placement[ "angles" ] ); + } + else + { + placement_hint = 1; + clip_max_ammo = weaponclipsize( level.riotshield_name ); + self setweaponammoclip( level.riotshield_name, clip_max_ammo ); + } + } + else + { + placement_hint = 1; + } + if ( placement_hint ) + { + self setriotshieldfailhint(); + } +} + +check_plant_position( origin, angles ) +{ + if ( isDefined( level.equipment_safe_to_drop ) ) + { + ret = 1; + test_ent = spawn( "script_model", origin ); + test_ent setmodel( level.deployedshieldmodel[ 0 ] ); + test_ent.angles = angles; + if ( !( self [[ level.equipment_safe_to_drop ]]( test_ent ) ) ) + { + ret = 0; + } + test_ent delete(); + return ret; + } + return 1; +} + +doriotshielddeploy( origin, angles ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "start_riotshield_deploy" ); + self notify( "deployed_riotshield" ); + self maps/mp/zombies/_zm_buildables::track_placed_buildables( level.riotshield_name ); + if ( isDefined( self.current_equipment ) && self.current_equipment == level.riotshield_name ) + { + self maps/mp/zombies/_zm_equipment::equipment_to_deployed( level.riotshield_name ); + } + zoffset = level.riotshield_placement_zoffset; + shield_ent = self spawnriotshieldcover( origin + ( 0, 0, zoffset ), angles ); + item_ent = deployriotshield( self, shield_ent ); + primaries = self getweaponslistprimaries(); +/# + assert( isDefined( item_ent ) ); + assert( !isDefined( self.riotshieldretrievetrigger ) ); + assert( !isDefined( self.riotshieldentity ) ); +#/ + self maps/mp/zombies/_zm_weapons::switch_back_primary_weapon( primaries[ 0 ] ); + if ( isDefined( level.equipment_planted ) ) + { + self [[ level.equipment_planted ]]( shield_ent, level.riotshield_name, self ); + } + if ( isDefined( level.equipment_safe_to_drop ) ) + { + if ( !( self [[ level.equipment_safe_to_drop ]]( shield_ent ) ) ) + { + self notify( "destroy_riotshield" ); + shield_ent delete(); + item_ent delete(); + return; + } + } + self.riotshieldretrievetrigger = item_ent; + self.riotshieldentity = shield_ent; + self thread watchdeployedriotshieldents(); + self thread deleteshieldondamage( self.riotshieldentity ); + self thread deleteshieldmodelonweaponpickup( self.riotshieldretrievetrigger ); + self thread deleteriotshieldonplayerdeath(); + self thread watchshieldtriggervisibility( self.riotshieldretrievetrigger ); + self.riotshieldentity thread watchdeployedriotshielddamage(); + return shield_ent; +} + +riotshielddistancetest( origin ) +{ +/# + assert( isDefined( origin ) ); +#/ + min_dist_squared = getDvarFloat( "riotshield_deploy_limit_radius" ); + min_dist_squared *= min_dist_squared; + i = 0; + while ( i < level.players.size ) + { + if ( isDefined( level.players[ i ].riotshieldentity ) ) + { + dist_squared = distancesquared( level.players[ i ].riotshieldentity.origin, origin ); + if ( min_dist_squared > dist_squared ) + { +/# + println( "Shield placement denied! Failed distance check to other riotshields." ); +#/ + return 0; + } + } + i++; + } + return 1; +} + +watchdeployedriotshieldents() +{ +/# + assert( isDefined( self.riotshieldretrievetrigger ) ); + assert( isDefined( self.riotshieldentity ) ); +#/ + riotshieldretrievetrigger = self.riotshieldretrievetrigger; + riotshieldentity = self.riotshieldentity; + self waittill_any( "destroy_riotshield", "disconnect", "tomb_shield_zm_taken" ); + if ( isDefined( self ) ) + { + self.shield_placement = 0; + self updateriotshieldmodel(); + } + if ( isDefined( riotshieldretrievetrigger ) ) + { + riotshieldretrievetrigger delete(); + } + if ( isDefined( riotshieldentity ) ) + { + riotshieldentity delete(); + } +} + +watchdeployedriotshielddamage() +{ + self endon( "death" ); + damagemax = getDvarInt( "riotshield_deployed_health" ); + self.damagetaken = 0; + while ( 1 ) + { + self.maxhealth = 100000; + self.health = self.maxhealth; + self waittill( "damage", damage, attacker, direction, point, type, tagname, modelname, partname, weaponname, idflags ); + if ( isDefined( level.players_can_damage_riotshields ) && !level.players_can_damage_riotshields ) + { + continue; + } + if ( !isDefined( attacker ) || !isplayer( attacker ) ) + { + continue; + } +/# + if ( isDefined( self.owner ) ) + { + assert( isDefined( self.owner.team ) ); + } +#/ + while ( is_encounter() && attacker.team == self.owner.team && attacker != self.owner ) + { + continue; + } + if ( isDefined( level.riotshield_damage_callback ) ) + { + self.owner [[ level.riotshield_damage_callback ]]( damage, 0 ); + continue; + } + else + { + if ( type == "MOD_MELEE" ) + { + damage *= getDvarFloat( "riotshield_melee_damage_scale" ); + } + else if ( type == "MOD_PISTOL_BULLET" || type == "MOD_RIFLE_BULLET" ) + { + damage *= getDvarFloat( "riotshield_bullet_damage_scale" ); + } + else + { + if ( type != "MOD_GRENADE" && type != "MOD_GRENADE_SPLASH" && type != "MOD_EXPLOSIVE" && type != "MOD_EXPLOSIVE_SPLASH" || type == "MOD_PROJECTILE" && type == "MOD_PROJECTILE_SPLASH" ) + { + damage *= getDvarFloat( "riotshield_explosive_damage_scale" ); + break; + } + else + { + if ( type == "MOD_IMPACT" ) + { + damage *= getDvarFloat( "riotshield_projectile_damage_scale" ); + } + } + } + self.damagetaken += damage; + if ( self.damagetaken >= damagemax ) + { + self damagethendestroyriotshield(); + } + } + } +} + +damagethendestroyriotshield() +{ + self endon( "death" ); + self.owner.riotshieldretrievetrigger delete(); + self notsolid(); + self setclientflag( 14 ); + wait getDvarFloat( "riotshield_destroyed_cleanup_time" ); + self.owner notify( "destroy_riotshield" ); +} + +deleteshieldondamage( shield_ent ) +{ + shield_ent waittill( "death" ); + self notify( "destroy_riotshield" ); +} + +deleteshieldmodelonweaponpickup( shield_trigger ) +{ + shield_trigger waittill( "trigger", player ); + self maps/mp/zombies/_zm_equipment::equipment_from_deployed( level.riotshield_name ); + self notify( "destroy_riotshield" ); + if ( self != player ) + { + if ( isDefined( level.transferriotshield ) ) + { + [[ level.transferriotshield ]]( self, player ); + } + } +} + +watchshieldtriggervisibility( trigger ) +{ + self endon( "death" ); + trigger endon( "death" ); + while ( isDefined( trigger ) ) + { + players = get_players(); + _a760 = players; + _k760 = getFirstArrayKey( _a760 ); + while ( isDefined( _k760 ) ) + { + player = _a760[ _k760 ]; + pickup = 1; + if ( !isDefined( player ) ) + { + } + else if ( is_true( player.afterlife ) ) + { + trigger setinvisibletoplayer( player ); + wait 0,05; + } + else + { + if ( isDefined( level.cantransferriotshield ) ) + { + pickup = [[ level.cantransferriotshield ]]( self, player ); + } + if ( !isDefined( trigger ) ) + { + return; + } + if ( pickup ) + { + trigger setvisibletoplayer( player ); + } + else + { + trigger setinvisibletoplayer( player ); + } + wait 0,05; + } + _k760 = getNextArrayKey( _a760, _k760 ); + } + wait 0,05; + } +} + +deleteriotshieldonplayerdeath() +{ + self.riotshieldentity endon( "death" ); + self waittill( "death" ); + self notify( "destroy_riotshield" ); +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_weap_ballistic_knife.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_weap_ballistic_knife.gsc new file mode 100644 index 0000000..04f7af6 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_weap_ballistic_knife.gsc @@ -0,0 +1,308 @@ +#include maps/mp/zombies/_zm_stats; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + if ( !isDefined( level.ballistic_knife_autorecover ) ) + { + level.ballistic_knife_autorecover = 1; + } + if ( isDefined( level._uses_retrievable_ballisitic_knives ) && level._uses_retrievable_ballisitic_knives == 1 ) + { + precachemodel( "t5_weapon_ballistic_knife_projectile" ); + precachemodel( "t5_weapon_ballistic_knife_blade_retrieve" ); + } +} + +on_spawn( watcher, player ) +{ + player endon( "death" ); + player endon( "disconnect" ); + player endon( "zmb_lost_knife" ); + level endon( "game_ended" ); + self waittill( "stationary", endpos, normal, angles, attacker, prey, bone ); + isfriendly = 0; + if ( isDefined( endpos ) ) + { + retrievable_model = spawn( "script_model", endpos ); + retrievable_model setmodel( "t5_weapon_ballistic_knife_blade_retrieve" ); + retrievable_model setowner( player ); + retrievable_model.owner = player; + retrievable_model.angles = angles; + retrievable_model.name = watcher.weapon; + if ( isDefined( prey ) ) + { + if ( isplayer( prey ) && player.team == prey.team ) + { + isfriendly = 1; + } + else + { + if ( isai( prey ) && player.team == prey.team ) + { + isfriendly = 1; + } + } + if ( !isfriendly ) + { + retrievable_model linkto( prey, bone ); + retrievable_model thread force_drop_knives_to_ground_on_death( player, prey ); + } + else + { + if ( isfriendly ) + { + retrievable_model physicslaunch( normal, ( randomint( 10 ), randomint( 10 ), randomint( 10 ) ) ); + normal = ( 0, 0, 1 ); + } + } + } + watcher.objectarray[ watcher.objectarray.size ] = retrievable_model; + if ( isfriendly ) + { + retrievable_model waittill( "stationary" ); + } + retrievable_model thread drop_knives_to_ground( player ); + if ( isfriendly ) + { + player notify( "ballistic_knife_stationary" ); + } + else + { + player notify( "ballistic_knife_stationary" ); + } + retrievable_model thread wait_to_show_glowing_model( prey ); + } +} + +wait_to_show_glowing_model( prey ) +{ + level endon( "game_ended" ); + self endon( "death" ); + wait 2; + self setmodel( "t5_weapon_ballistic_knife_blade_retrieve" ); +} + +on_spawn_retrieve_trigger( watcher, player ) +{ + player endon( "death" ); + player endon( "disconnect" ); + player endon( "zmb_lost_knife" ); + level endon( "game_ended" ); + player waittill( "ballistic_knife_stationary", retrievable_model, normal, prey ); + if ( !isDefined( retrievable_model ) ) + { + return; + } + trigger_pos = []; + if ( isDefined( prey ) || isplayer( prey ) && isai( prey ) ) + { + trigger_pos[ 0 ] = prey.origin[ 0 ]; + trigger_pos[ 1 ] = prey.origin[ 1 ]; + trigger_pos[ 2 ] = prey.origin[ 2 ] + 10; + } + else + { + trigger_pos[ 0 ] = retrievable_model.origin[ 0 ] + ( 10 * normal[ 0 ] ); + trigger_pos[ 1 ] = retrievable_model.origin[ 1 ] + ( 10 * normal[ 1 ] ); + trigger_pos[ 2 ] = retrievable_model.origin[ 2 ] + ( 10 * normal[ 2 ] ); + } + if ( is_true( level.ballistic_knife_autorecover ) ) + { + trigger_pos[ 2 ] -= 50; + pickup_trigger = spawn( "trigger_radius", ( trigger_pos[ 0 ], trigger_pos[ 1 ], trigger_pos[ 2 ] ), 0, 50, 100 ); + } + else + { + pickup_trigger = spawn( "trigger_radius_use", ( trigger_pos[ 0 ], trigger_pos[ 1 ], trigger_pos[ 2 ] ) ); + pickup_trigger setcursorhint( "HINT_NOICON" ); + } + pickup_trigger.owner = player; + retrievable_model.retrievabletrigger = pickup_trigger; + hint_string = &"WEAPON_BALLISTIC_KNIFE_PICKUP"; + if ( isDefined( hint_string ) ) + { + pickup_trigger sethintstring( hint_string ); + } + else + { + pickup_trigger sethintstring( &"GENERIC_PICKUP" ); + } + pickup_trigger setteamfortrigger( player.team ); + player clientclaimtrigger( pickup_trigger ); + pickup_trigger enablelinkto(); + if ( isDefined( prey ) ) + { + pickup_trigger linkto( prey ); + } + else + { + pickup_trigger linkto( retrievable_model ); + } + if ( isDefined( level.knife_planted ) ) + { + [[ level.knife_planted ]]( retrievable_model, pickup_trigger, prey ); + } + retrievable_model thread watch_use_trigger( pickup_trigger, retrievable_model, ::pick_up, watcher.weapon, watcher.pickupsoundplayer, watcher.pickupsound ); + player thread watch_shutdown( pickup_trigger, retrievable_model ); +} + +debug_print( endpos ) +{ +/# + self endon( "death" ); + while ( 1 ) + { + print3d( endpos, "pickup_trigger" ); + wait 0,05; +#/ + } +} + +watch_use_trigger( trigger, model, callback, weapon, playersoundonuse, npcsoundonuse ) +{ + self endon( "death" ); + self endon( "delete" ); + level endon( "game_ended" ); + max_ammo = weaponmaxammo( weapon ) + 1; + autorecover = is_true( level.ballistic_knife_autorecover ); + while ( 1 ) + { + trigger waittill( "trigger", player ); + while ( !isalive( player ) ) + { + continue; + } + if ( !player isonground() && !is_true( trigger.force_pickup ) ) + { + continue; + } + if ( isDefined( trigger.triggerteam ) && player.team != trigger.triggerteam ) + { + continue; + } + if ( isDefined( trigger.claimedby ) && player != trigger.claimedby ) + { + continue; + } + ammo_stock = player getweaponammostock( weapon ); + ammo_clip = player getweaponammoclip( weapon ); + current_weapon = player getcurrentweapon(); + total_ammo = ammo_stock + ammo_clip; + hasreloaded = 1; + if ( total_ammo > 0 && ammo_stock == total_ammo && current_weapon == weapon ) + { + hasreloaded = 0; + } + if ( total_ammo >= max_ammo || !hasreloaded ) + { + continue; + } + if ( !autorecover && player usebuttonpressed() && !player.throwinggrenade || !player meleebuttonpressed() && is_true( trigger.force_pickup ) ) + { + if ( isDefined( playersoundonuse ) ) + { + player playlocalsound( playersoundonuse ); + } + if ( isDefined( npcsoundonuse ) ) + { + player playsound( npcsoundonuse ); + } + player thread [[ callback ]]( weapon, model, trigger ); + return; + } + else + { + } + } +} + +pick_up( weapon, model, trigger ) +{ + if ( self hasweapon( weapon ) ) + { + current_weapon = self getcurrentweapon(); + if ( current_weapon != weapon ) + { + clip_ammo = self getweaponammoclip( weapon ); + if ( !clip_ammo ) + { + self setweaponammoclip( weapon, 1 ); + } + else + { + new_ammo_stock = self getweaponammostock( weapon ) + 1; + self setweaponammostock( weapon, new_ammo_stock ); + } + } + else + { + new_ammo_stock = self getweaponammostock( weapon ) + 1; + self setweaponammostock( weapon, new_ammo_stock ); + } + } + self maps/mp/zombies/_zm_stats::increment_client_stat( "ballistic_knives_pickedup" ); + self maps/mp/zombies/_zm_stats::increment_player_stat( "ballistic_knives_pickedup" ); + model destroy_ent(); + trigger destroy_ent(); +} + +destroy_ent() +{ + if ( isDefined( self ) ) + { + if ( isDefined( self.glowing_model ) ) + { + self.glowing_model delete(); + } + self delete(); + } +} + +watch_shutdown( trigger, model ) +{ + self waittill_any( "death_or_disconnect", "zmb_lost_knife" ); + trigger destroy_ent(); + model destroy_ent(); +} + +drop_knives_to_ground( player ) +{ + player endon( "death" ); + player endon( "zmb_lost_knife" ); + for ( ;; ) + { + level waittill( "drop_objects_to_ground", origin, radius ); + if ( distancesquared( origin, self.origin ) < ( radius * radius ) ) + { + self physicslaunch( ( 0, 0, 1 ), vectorScale( ( 0, 0, 1 ), 5 ) ); + self thread update_retrieve_trigger( player ); + } + } +} + +force_drop_knives_to_ground_on_death( player, prey ) +{ + self endon( "death" ); + player endon( "zmb_lost_knife" ); + prey waittill( "death" ); + self unlink(); + self physicslaunch( ( 0, 0, 1 ), vectorScale( ( 0, 0, 1 ), 5 ) ); + self thread update_retrieve_trigger( player ); +} + +update_retrieve_trigger( player ) +{ + self endon( "death" ); + player endon( "zmb_lost_knife" ); + if ( isDefined( level.custom_update_retrieve_trigger ) ) + { + self [[ level.custom_update_retrieve_trigger ]]( player ); + return; + } + self waittill( "stationary" ); + trigger = self.retrievabletrigger; + trigger.origin = ( self.origin[ 0 ], self.origin[ 1 ], self.origin[ 2 ] + 10 ); + trigger linkto( self ); +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_weap_beacon.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_weap_beacon.gsc new file mode 100644 index 0000000..b3fd75e --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_weap_beacon.gsc @@ -0,0 +1,1008 @@ +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zombies/_zm_clone; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +#using_animtree( "zombie_beacon" ); + +init() +{ + if ( !beacon_exists() ) + { + return; + } +/# + level.zombiemode_devgui_beacon_give = ::player_give_beacon; +#/ + registerclientfield( "world", "play_launch_artillery_fx_robot_0", 14000, 1, "int" ); + registerclientfield( "world", "play_launch_artillery_fx_robot_1", 14000, 1, "int" ); + registerclientfield( "world", "play_launch_artillery_fx_robot_2", 14000, 1, "int" ); + registerclientfield( "scriptmover", "play_beacon_fx", 14000, 1, "int" ); + registerclientfield( "scriptmover", "play_artillery_barrage", 14000, 2, "int" ); + precachemodel( "jun_missile" ); + level._effect[ "beacon_glow" ] = loadfx( "maps/zombie_tomb/fx_tomb_beacon_glow" ); + level._effect[ "beacon_shell_explosion" ] = loadfx( "maps/zombie_tomb/fx_tomb_beacon_exp" ); + level._effect[ "beacon_shell_trail" ] = loadfx( "maps/zombie_tomb/fx_tomb_beacon_trail" ); + level._effect[ "beacon_launch_fx" ] = loadfx( "maps/zombie_tomb/fx_tomb_beacon_launch" ); + level._effect[ "grenade_samantha_steal" ] = loadfx( "maps/zombie/fx_zmb_blackhole_trap_end" ); + level.beacons = []; + level.zombie_weapons_callbacks[ "beacon_zm" ] = ::player_give_beacon; + scriptmodelsuseanimtree( -1 ); +} + +player_give_beacon() +{ + self giveweapon( "beacon_zm" ); + self set_player_tactical_grenade( "beacon_zm" ); + self thread player_handle_beacon(); +} + +player_handle_beacon() +{ + self notify( "starting_beacon_watch" ); + self endon( "disconnect" ); + self endon( "starting_beacon_watch" ); + attract_dist_diff = level.beacon_attract_dist_diff; + if ( !isDefined( attract_dist_diff ) ) + { + attract_dist_diff = 45; + } + num_attractors = level.num_beacon_attractors; + if ( !isDefined( num_attractors ) ) + { + num_attractors = 96; + } + max_attract_dist = level.beacon_attract_dist; + if ( !isDefined( max_attract_dist ) ) + { + max_attract_dist = 1536; + } + while ( 1 ) + { + grenade = get_thrown_beacon(); + self thread player_throw_beacon( grenade, num_attractors, max_attract_dist, attract_dist_diff ); + wait 0,05; + } +} + +watch_for_dud( model, actor ) +{ + self endon( "death" ); + self waittill( "grenade_dud" ); + model.dud = 1; + self.monk_scream_vox = 1; + wait 3; + if ( isDefined( model ) ) + { + model delete(); + } + if ( isDefined( actor ) ) + { + actor delete(); + } + if ( isDefined( self.damagearea ) ) + { + self.damagearea delete(); + } + if ( isDefined( self ) ) + { + self delete(); + } +} + +watch_for_emp( model, actor ) +{ + self endon( "death" ); + if ( !should_watch_for_emp() ) + { + return; + } + while ( 1 ) + { + level waittill( "emp_detonate", origin, radius ); + if ( distancesquared( origin, self.origin ) < ( radius * radius ) ) + { + break; + } + else + { + } + } + self.stun_fx = 1; + if ( isDefined( level._equipment_emp_destroy_fx ) ) + { + playfx( level._equipment_emp_destroy_fx, self.origin + vectorScale( ( 0, 0, 1 ), 5 ), ( 0, randomfloat( 360 ), 0 ) ); + } + wait 0,15; + self.attract_to_origin = 0; + self deactivate_zombie_point_of_interest(); + wait 1; + self detonate(); + wait 1; + if ( isDefined( model ) ) + { + model delete(); + } + if ( isDefined( actor ) ) + { + actor delete(); + } + if ( isDefined( self.damagearea ) ) + { + self.damagearea delete(); + } + if ( isDefined( self ) ) + { + self delete(); + } +} + +clone_player_angles( owner ) +{ + self endon( "death" ); + owner endon( "bled_out" ); + while ( isDefined( self ) ) + { + self.angles = owner.angles; + wait 0,05; + } +} + +show_briefly( showtime ) +{ + self endon( "show_owner" ); + if ( isDefined( self.show_for_time ) ) + { + self.show_for_time = showtime; + return; + } + self.show_for_time = showtime; + self setvisibletoall(); + while ( self.show_for_time > 0 ) + { + self.show_for_time -= 0,05; + wait 0,05; + } + self setvisibletoallexceptteam( level.zombie_team ); + self.show_for_time = undefined; +} + +show_owner_on_attack( owner ) +{ + owner endon( "hide_owner" ); + owner endon( "show_owner" ); + self endon( "explode" ); + self endon( "death" ); + self endon( "grenade_dud" ); + owner.show_for_time = undefined; + for ( ;; ) + { + owner waittill( "weapon_fired" ); + owner thread show_briefly( 0,5 ); + } +} + +hide_owner( owner ) +{ + owner notify( "hide_owner" ); + owner endon( "hide_owner" ); + owner setperk( "specialty_immunemms" ); + owner.no_burning_sfx = 1; + owner notify( "stop_flame_sounds" ); + owner setvisibletoallexceptteam( level.zombie_team ); + owner.hide_owner = 1; + if ( isDefined( level._effect[ "human_disappears" ] ) ) + { + playfx( level._effect[ "human_disappears" ], owner.origin ); + } + self thread show_owner_on_attack( owner ); + evt = self waittill_any_return( "explode", "death", "grenade_dud" ); +/# + println( "ZMCLONE: Player visible again because of " + evt ); +#/ + owner notify( "show_owner" ); + owner unsetperk( "specialty_immunemms" ); + if ( isDefined( level._effect[ "human_disappears" ] ) ) + { + playfx( level._effect[ "human_disappears" ], owner.origin ); + } + owner.no_burning_sfx = undefined; + owner setvisibletoall(); + owner.hide_owner = undefined; + owner show(); +} + +proximity_detonate( owner ) +{ + wait 1,5; + if ( !isDefined( self ) ) + { + return; + } + detonateradius = 96; + explosionradius = detonateradius * 2; + damagearea = spawn( "trigger_radius", self.origin + ( 0, 0, 0 - detonateradius ), 4, detonateradius, detonateradius * 1,5 ); + damagearea setexcludeteamfortrigger( owner.team ); + damagearea enablelinkto(); + damagearea linkto( self ); + self.damagearea = damagearea; + while ( isDefined( self ) ) + { + damagearea waittill( "trigger", ent ); + if ( isDefined( owner ) && ent == owner ) + { + continue; + } + if ( isDefined( ent.team ) && ent.team == owner.team ) + { + continue; + } + self playsound( "wpn_claymore_alert" ); + dist = distance( self.origin, ent.origin ); + radiusdamage( self.origin + vectorScale( ( 0, 0, 1 ), 12 ), explosionradius, 1, 1, owner, "MOD_GRENADE_SPLASH", "beacon_zm" ); + if ( isDefined( owner ) ) + { + self detonate( owner ); + } + else + { + self detonate( undefined ); + } + break; + } + if ( isDefined( damagearea ) ) + { + damagearea delete(); + } +} + +player_throw_beacon( grenade, num_attractors, max_attract_dist, attract_dist_diff ) +{ + self endon( "disconnect" ); + self endon( "starting_beacon_watch" ); + if ( isDefined( grenade ) ) + { + grenade endon( "death" ); + if ( self maps/mp/zombies/_zm_laststand::player_is_in_laststand() ) + { + if ( isDefined( grenade.damagearea ) ) + { + grenade.damagearea delete(); + } + grenade delete(); + return; + } + grenade hide(); + model = spawn( "script_model", grenade.origin ); + model endon( "weapon_beacon_timeout" ); + model setmodel( "t6_wpn_zmb_homing_beacon_world" ); + model useanimtree( -1 ); + model linkto( grenade ); + model.angles = grenade.angles; + model thread beacon_cleanup( grenade ); + model.owner = self; + clone = undefined; + if ( isDefined( level.beacon_dual_view ) && level.beacon_dual_view ) + { + model setvisibletoallexceptteam( level.zombie_team ); + clone = maps/mp/zombies/_zm_clone::spawn_player_clone( self, vectorScale( ( 0, 0, 1 ), 999 ), level.beacon_clone_weapon, undefined ); + model.simulacrum = clone; + clone maps/mp/zombies/_zm_clone::clone_animate( "idle" ); + clone thread clone_player_angles( self ); + clone notsolid(); + clone ghost(); + } + grenade thread watch_for_dud( model, clone ); + info = spawnstruct(); + info.sound_attractors = []; + grenade thread monitor_zombie_groans( info ); + grenade waittill( "stationary" ); + if ( isDefined( level.grenade_planted ) ) + { + self thread [[ level.grenade_planted ]]( grenade, model ); + } + if ( isDefined( grenade ) ) + { + if ( isDefined( model ) ) + { + model thread weapon_beacon_anims(); + if ( isDefined( grenade.backlinked ) && !grenade.backlinked ) + { + model unlink(); + model.origin = grenade.origin; + model.angles = grenade.angles; + } + } + if ( isDefined( clone ) ) + { + clone forceteleport( grenade.origin, grenade.angles ); + clone thread hide_owner( self ); + grenade thread proximity_detonate( self ); + clone show(); + clone setinvisibletoall(); + clone setvisibletoteam( level.zombie_team ); + } + grenade resetmissiledetonationtime(); + model setclientfield( "play_beacon_fx", 1 ); + valid_poi = check_point_in_enabled_zone( grenade.origin, undefined, undefined ); + if ( isDefined( level.check_valid_poi ) ) + { + valid_poi = grenade [[ level.check_valid_poi ]]( valid_poi ); + } + if ( valid_poi ) + { + grenade create_zombie_point_of_interest( max_attract_dist, num_attractors, 10000 ); + grenade.attract_to_origin = 1; + grenade thread create_zombie_point_of_interest_attractor_positions( 4, attract_dist_diff ); + grenade thread wait_for_attractor_positions_complete(); + grenade thread do_beacon_sound( model, info ); + model thread wait_and_explode( grenade ); + model.time_thrown = getTime(); + for ( ;; ) + { + while ( isDefined( level.weapon_beacon_busy ) && level.weapon_beacon_busy ) + { + wait 0,1; + } + } + if ( flag( "three_robot_round" ) && flag( "fire_link_enabled" ) ) + { + model thread start_artillery_launch_ee( grenade ); + } + else model thread start_artillery_launch_normal( grenade ); + level.beacons[ level.beacons.size ] = grenade; + } + else + { + grenade.script_noteworthy = undefined; + level thread grenade_stolen_by_sam( grenade, model, clone ); + } + return; + } + else + { + grenade.script_noteworthy = undefined; + level thread grenade_stolen_by_sam( grenade, model, clone ); + } + } +} + +weapon_beacon_anims() +{ + n_time = getanimlength( %o_zombie_dlc4_homing_deploy ); + self setanim( %o_zombie_dlc4_homing_deploy ); + wait n_time; + self setanim( %o_zombie_dlc4_homing_spin ); +} + +grenade_stolen_by_sam( ent_grenade, ent_model, ent_actor ) +{ + if ( !isDefined( ent_model ) ) + { + return; + } + direction = ent_model.origin; + direction = ( direction[ 1 ], direction[ 0 ], 0 ); + if ( direction[ 1 ] < 0 || direction[ 0 ] > 0 && direction[ 1 ] > 0 ) + { + direction = ( direction[ 0 ], direction[ 1 ] * -1, 0 ); + } + else + { + if ( direction[ 0 ] < 0 ) + { + direction = ( direction[ 0 ] * -1, direction[ 1 ], 0 ); + } + } + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( isalive( players[ i ] ) ) + { + players[ i ] playlocalsound( level.zmb_laugh_alias ); + } + i++; + } + playfxontag( level._effect[ "grenade_samantha_steal" ], ent_model, "tag_origin" ); + ent_model movez( 60, 1, 0,25, 0,25 ); + ent_model vibrate( direction, 1,5, 2,5, 1 ); + ent_model waittill( "movedone" ); + if ( isDefined( self.damagearea ) ) + { + self.damagearea delete(); + } + ent_model delete(); + if ( isDefined( ent_actor ) ) + { + ent_actor delete(); + } + if ( isDefined( ent_grenade ) ) + { + if ( isDefined( ent_grenade.damagearea ) ) + { + ent_grenade.damagearea delete(); + } + ent_grenade delete(); + } +} + +wait_for_attractor_positions_complete() +{ + self waittill( "attractor_positions_generated" ); + self.attract_to_origin = 0; +} + +beacon_cleanup( parent ) +{ + while ( 1 ) + { + if ( !isDefined( parent ) ) + { + if ( isDefined( self ) && isDefined( self.dud ) && self.dud ) + { + wait 6; + } + if ( isDefined( self.simulacrum ) ) + { + self.simulacrum delete(); + } + self_delete(); + return; + } + wait 0,05; + } +} + +do_beacon_sound( model, info ) +{ + self.monk_scream_vox = 0; + if ( isDefined( level.grenade_safe_to_bounce ) ) + { + if ( !( [[ level.grenade_safe_to_bounce ]]( self.owner, "beacon_zm" ) ) ) + { + self.monk_scream_vox = 1; + } + } + if ( !self.monk_scream_vox && level.music_override == 0 ) + { + if ( isDefined( level.beacon_dual_view ) && level.beacon_dual_view ) + { + self playsoundtoteam( "null", "allies" ); + } + else + { + self playsound( "null" ); + } + } + if ( !self.monk_scream_vox ) + { + self thread play_delayed_explode_vox(); + } + self waittill( "robot_artillery_barrage", position ); + level notify( "grenade_exploded" ); + beacon_index = -1; + i = 0; + while ( i < level.beacons.size ) + { + if ( !isDefined( level.beacons[ i ] ) ) + { + beacon_index = i; + break; + } + else + { + i++; + } + } + if ( beacon_index >= 0 ) + { + arrayremoveindex( level.beacons, beacon_index ); + } + i = 0; + while ( i < info.sound_attractors.size ) + { + if ( isDefined( info.sound_attractors[ i ] ) ) + { + info.sound_attractors[ i ] notify( "beacon_blown_up" ); + } + i++; + } + self delete(); +} + +play_delayed_explode_vox() +{ + wait 6,5; + if ( isDefined( self ) ) + { + } +} + +get_thrown_beacon() +{ + self endon( "disconnect" ); + self endon( "starting_beacon_watch" ); + while ( 1 ) + { + self waittill( "grenade_fire", grenade, weapname ); + if ( weapname == "beacon_zm" ) + { + grenade.use_grenade_special_long_bookmark = 1; + grenade.grenade_multiattack_bookmark_count = 1; + return grenade; + } + wait 0,05; + } +} + +monitor_zombie_groans( info ) +{ + self endon( "explode" ); + while ( 1 ) + { + if ( !isDefined( self ) ) + { + return; + } + while ( !isDefined( self.attractor_array ) ) + { + wait 0,05; + } + i = 0; + while ( i < self.attractor_array.size ) + { + if ( array_check_for_dupes( info.sound_attractors, self.attractor_array[ i ] ) ) + { + if ( isDefined( self.origin ) && isDefined( self.attractor_array[ i ].origin ) ) + { + if ( distancesquared( self.origin, self.attractor_array[ i ].origin ) < 250000 ) + { + info.sound_attractors[ info.sound_attractors.size ] = self.attractor_array[ i ]; + self.attractor_array[ i ] thread play_zombie_groans(); + } + } + } + i++; + } + wait 0,05; + } +} + +play_zombie_groans() +{ + self endon( "death" ); + self endon( "beacon_blown_up" ); + while ( 1 ) + { + if ( isDefined( self ) ) + { + self playsound( "zmb_vox_zombie_groan" ); + wait randomfloatrange( 2, 3 ); + continue; + } + else + { + return; + } + } +} + +beacon_exists() +{ + return isDefined( level.zombie_weapons[ "beacon_zm" ] ); +} + +wait_and_explode( grenade ) +{ + self endon( "beacon_missile_launch" ); + grenade waittill( "explode", position ); + self notify( "weapon_beacon_timeout" ); + if ( isDefined( grenade ) ) + { + grenade notify( "robot_artillery_barrage" ); + } +} + +start_artillery_launch_normal( grenade ) +{ + self endon( "weapon_beacon_timeout" ); + sp_giant_robot = undefined; + while ( !isDefined( sp_giant_robot ) ) + { + i = 0; + while ( i < 3 ) + { + if ( isDefined( level.a_giant_robots[ i ].is_walking ) && level.a_giant_robots[ i ].is_walking ) + { + if ( isDefined( level.a_giant_robots[ i ].weap_beacon_firing ) && !level.a_giant_robots[ i ].weap_beacon_firing ) + { + sp_giant_robot = level.a_giant_robots[ i ]; + self thread artillery_fx_logic( sp_giant_robot, grenade ); + self notify( "beacon_missile_launch" ); + level.weapon_beacon_busy = 1; + grenade.fuse_reset = 1; + grenade.fuse_time = 100; + grenade resetmissiledetonationtime( 100 ); + break; + } + } + else + { + i++; + } + } + wait 0,1; + } +} + +start_artillery_launch_ee( grenade ) +{ + self endon( "weapon_beacon_timeout" ); + sp_giant_robot = undefined; + n_index = 0; + a_robot_index = []; + a_robot_index[ 0 ] = 1; + a_robot_index[ 1 ] = 0; + a_robot_index[ 2 ] = 2; + while ( n_index < a_robot_index.size ) + { + n_robot_num = a_robot_index[ n_index ]; + if ( isDefined( level.a_giant_robots[ n_robot_num ].is_walking ) && level.a_giant_robots[ n_robot_num ].is_walking ) + { + if ( isDefined( level.a_giant_robots[ n_robot_num ].weap_beacon_firing ) && !level.a_giant_robots[ n_robot_num ].weap_beacon_firing ) + { + sp_giant_robot = level.a_giant_robots[ n_robot_num ]; + self thread artillery_fx_logic_ee( sp_giant_robot, grenade ); + self notify( "beacon_missile_launch" ); + level.weapon_beacon_busy = 1; + grenade.fuse_reset = 1; + grenade.fuse_time = 100; + grenade resetmissiledetonationtime( 100 ); + wait 2; + n_index++; + } + } + else + { + if ( n_index == 0 ) + { + if ( !flag( "three_robot_round" ) ) + { + self thread start_artillery_launch_normal( grenade ); + break; + } + else } + else if ( n_index > 0 ) + { + break; + } + } + else + { + wait 0,1; + } + } + self thread artillery_barrage_logic( grenade, 1 ); +} + +artillery_fx_logic( sp_giant_robot, grenade ) +{ + sp_giant_robot.weap_beacon_firing = 1; + level setclientfield( "play_launch_artillery_fx_robot_" + sp_giant_robot.giant_robot_id, 1 ); + self thread homing_beacon_vo(); + wait 0,5; + if ( isDefined( sp_giant_robot ) ) + { + level setclientfield( "play_launch_artillery_fx_robot_" + sp_giant_robot.giant_robot_id, 0 ); + wait 3; + self thread artillery_barrage_logic( grenade ); + wait 1; + sp_giant_robot.weap_beacon_firing = 0; + } +} + +artillery_fx_logic_ee( sp_giant_robot, grenade ) +{ + sp_giant_robot.weap_beacon_firing = 1; + sp_giant_robot playsound( "zmb_homingbeacon_missiile_alarm" ); + level setclientfield( "play_launch_artillery_fx_robot_" + sp_giant_robot.giant_robot_id, 1 ); + self thread homing_beacon_vo(); + wait 0,5; + if ( isDefined( sp_giant_robot ) ) + { + level setclientfield( "play_launch_artillery_fx_robot_" + sp_giant_robot.giant_robot_id, 0 ); + } + wait 1; + sp_giant_robot.weap_beacon_firing = 0; +} + +homing_beacon_vo() +{ + if ( isDefined( self.owner ) && isplayer( self.owner ) ) + { + n_time = getTime(); + if ( isDefined( self.time_thrown ) ) + { + if ( n_time < ( self.time_thrown + 3000 ) ) + { + self.owner maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "use_beacon" ); + } + } + } +} + +artillery_barrage_logic( grenade, b_ee ) +{ + if ( !isDefined( b_ee ) ) + { + b_ee = 0; + } + if ( isDefined( b_ee ) && b_ee ) + { + a_v_land_offsets = self build_weap_beacon_landing_offsets_ee(); + a_v_start_offsets = self build_weap_beacon_start_offsets_ee(); + n_num_missiles = 15; + n_clientfield = 2; + } + else + { + a_v_land_offsets = self build_weap_beacon_landing_offsets(); + a_v_start_offsets = self build_weap_beacon_start_offsets(); + n_num_missiles = 5; + n_clientfield = 1; + } + self.a_v_land_spots = []; + self.a_v_start_spots = []; + i = 0; + while ( i < n_num_missiles ) + { + self.a_v_start_spots[ i ] = self.origin + a_v_start_offsets[ i ]; + self.a_v_land_spots[ i ] = self.origin + a_v_land_offsets[ i ]; + v_start_trace = self.a_v_start_spots[ i ] - vectorScale( ( 0, 0, 1 ), 5000 ); + trace = bullettrace( v_start_trace, self.a_v_land_spots[ i ], 0, undefined ); + self.a_v_land_spots[ i ] = trace[ "position" ]; + wait 0,05; + i++; + } + i = 0; + while ( i < n_num_missiles ) + { + self setclientfield( "play_artillery_barrage", n_clientfield ); + self thread wait_and_do_weapon_beacon_damage( i ); + wait_network_frame(); + self setclientfield( "play_artillery_barrage", 0 ); + if ( i == 0 ) + { + wait 1; + i++; + continue; + } + else + { + wait 0,25; + } + i++; + } + level thread allow_beacons_to_be_targeted_by_giant_robot(); + wait 6; + grenade notify( "robot_artillery_barrage" ); +} + +allow_beacons_to_be_targeted_by_giant_robot() +{ + wait 3; + level.weapon_beacon_busy = 0; +} + +build_weap_beacon_landing_offsets() +{ + a_offsets = []; + a_offsets[ 0 ] = ( 0, 0, 1 ); + a_offsets[ 1 ] = vectorScale( ( 0, 0, 1 ), 72 ); + a_offsets[ 2 ] = vectorScale( ( 0, 0, 1 ), 72 ); + a_offsets[ 3 ] = vectorScale( ( 0, 0, 1 ), 72 ); + a_offsets[ 4 ] = vectorScale( ( 0, 0, 1 ), 72 ); + return a_offsets; +} + +build_weap_beacon_start_offsets() +{ + a_offsets = []; + a_offsets[ 0 ] = vectorScale( ( 0, 0, 1 ), 8500 ); + a_offsets[ 1 ] = ( -6500, 6500, 8500 ); + a_offsets[ 2 ] = ( 6500, 6500, 8500 ); + a_offsets[ 3 ] = ( 6500, -6500, 8500 ); + a_offsets[ 4 ] = ( -6500, -6500, 8500 ); + return a_offsets; +} + +build_weap_beacon_landing_offsets_ee() +{ + a_offsets = []; + a_offsets[ 0 ] = ( 0, 0, 1 ); + a_offsets[ 1 ] = vectorScale( ( 0, 0, 1 ), 72 ); + a_offsets[ 2 ] = vectorScale( ( 0, 0, 1 ), 72 ); + a_offsets[ 3 ] = vectorScale( ( 0, 0, 1 ), 72 ); + a_offsets[ 4 ] = vectorScale( ( 0, 0, 1 ), 72 ); + a_offsets[ 5 ] = vectorScale( ( 0, 0, 1 ), 72 ); + a_offsets[ 6 ] = vectorScale( ( 0, 0, 1 ), 72 ); + a_offsets[ 7 ] = vectorScale( ( 0, 0, 1 ), 72 ); + a_offsets[ 8 ] = vectorScale( ( 0, 0, 1 ), 72 ); + a_offsets[ 9 ] = vectorScale( ( 0, 0, 1 ), 72 ); + a_offsets[ 10 ] = vectorScale( ( 0, 0, 1 ), 72 ); + a_offsets[ 11 ] = vectorScale( ( 0, 0, 1 ), 72 ); + a_offsets[ 12 ] = vectorScale( ( 0, 0, 1 ), 72 ); + a_offsets[ 13 ] = vectorScale( ( 0, 0, 1 ), 72 ); + a_offsets[ 14 ] = vectorScale( ( 0, 0, 1 ), 72 ); + return a_offsets; +} + +build_weap_beacon_start_offsets_ee() +{ + a_offsets = []; + a_offsets[ 0 ] = vectorScale( ( 0, 0, 1 ), 8500 ); + a_offsets[ 1 ] = ( -6500, 6500, 8500 ); + a_offsets[ 2 ] = ( 6500, 6500, 8500 ); + a_offsets[ 3 ] = ( 6500, -6500, 8500 ); + a_offsets[ 4 ] = ( -6500, -6500, 8500 ); + a_offsets[ 5 ] = ( -6500, 6500, 8500 ); + a_offsets[ 6 ] = ( 6500, 6500, 8500 ); + a_offsets[ 7 ] = ( 6500, -6500, 8500 ); + a_offsets[ 8 ] = ( -6500, -6500, 8500 ); + a_offsets[ 9 ] = ( -6500, 6500, 8500 ); + a_offsets[ 10 ] = ( 6500, 6500, 8500 ); + a_offsets[ 11 ] = ( 6500, -6500, 8500 ); + a_offsets[ 12 ] = ( -6500, -6500, 8500 ); + a_offsets[ 13 ] = ( -6500, 6500, 8500 ); + a_offsets[ 14 ] = ( 6500, 6500, 8500 ); + return a_offsets; +} + +wait_and_do_weapon_beacon_damage( index ) +{ + wait 3; + v_damage_origin = self.a_v_land_spots[ index ]; + level.n_weap_beacon_zombie_thrown_count = 0; + a_zombies_to_kill = []; + a_zombies = getaispeciesarray( "axis", "all" ); + _a969 = a_zombies; + _k969 = getFirstArrayKey( _a969 ); + while ( isDefined( _k969 ) ) + { + zombie = _a969[ _k969 ]; + n_distance = distance( zombie.origin, v_damage_origin ); + if ( n_distance <= 200 ) + { + n_damage = linear_map( n_distance, 200, 0, 7000, 8000 ); + if ( n_damage >= zombie.health ) + { + a_zombies_to_kill[ a_zombies_to_kill.size ] = zombie; + break; + } + else + { + zombie thread set_beacon_damage(); + zombie dodamage( n_damage, zombie.origin, self.owner, self.owner, "none", "MOD_GRENADE_SPLASH", 0, "beacon_zm" ); + } + } + _k969 = getNextArrayKey( _a969, _k969 ); + } + if ( index == 0 ) + { + radiusdamage( self.origin + vectorScale( ( 0, 0, 1 ), 12 ), 10, 1, 1, self.owner, "MOD_GRENADE_SPLASH", "beacon_zm" ); + self ghost(); + self stopanimscripted( 0 ); + } + level thread weap_beacon_zombie_death( self, a_zombies_to_kill ); + self thread weap_beacon_rumble(); +} + +weap_beacon_zombie_death( model, a_zombies_to_kill ) +{ + n_interval = 0; + i = 0; + while ( i < a_zombies_to_kill.size ) + { + zombie = a_zombies_to_kill[ i ]; + if ( !isDefined( zombie ) || !isalive( zombie ) ) + { + i++; + continue; + } + else + { + zombie thread set_beacon_damage(); + zombie dodamage( zombie.health, zombie.origin, model.owner, model.owner, "none", "MOD_GRENADE_SPLASH", 0, "beacon_zm" ); + n_interval++; + zombie thread weapon_beacon_launch_ragdoll(); + if ( n_interval >= 4 ) + { + wait_network_frame(); + n_interval = 0; + } + } + i++; + } +} + +weapon_beacon_launch_ragdoll() +{ + if ( isDefined( self.is_mechz ) && self.is_mechz ) + { + return; + } + if ( isDefined( self.is_giant_robot ) && self.is_giant_robot ) + { + return; + } + if ( level.n_weap_beacon_zombie_thrown_count >= 5 ) + { + return; + } + level.n_weap_beacon_zombie_thrown_count++; + if ( isDefined( level.ragdoll_limit_check ) && !( [[ level.ragdoll_limit_check ]]() ) ) + { + level thread weap_beacon_gib( self ); + return; + } + self startragdoll(); + n_x = randomintrange( 50, 150 ); + n_y = randomintrange( 50, 150 ); + if ( cointoss() ) + { + n_x *= -1; + } + if ( cointoss() ) + { + n_y *= -1; + } + v_launch = ( n_x, n_y, randomintrange( 75, 250 ) ); + self launchragdoll( v_launch ); +} + +weap_beacon_gib( ai_zombie ) +{ + a_gib_ref = []; + a_gib_ref[ 0 ] = level._zombie_gib_piece_index_all; + ai_zombie gib( "normal", a_gib_ref ); +} + +weap_beacon_rumble() +{ + a_players = getplayers(); + _a1087 = a_players; + _k1087 = getFirstArrayKey( _a1087 ); + while ( isDefined( _k1087 ) ) + { + player = _a1087[ _k1087 ]; + if ( isalive( player ) && isDefined( player ) ) + { + if ( distance2dsquared( player.origin, self.origin ) < 250000 ) + { + player thread execute_weap_beacon_rumble(); + } + } + _k1087 = getNextArrayKey( _a1087, _k1087 ); + } +} + +execute_weap_beacon_rumble() +{ + self endon( "death" ); + self endon( "disconnect" ); + self setclientfieldtoplayer( "player_rumble_and_shake", 3 ); + wait_network_frame(); + self setclientfieldtoplayer( "player_rumble_and_shake", 0 ); +} + +set_beacon_damage() +{ + self endon( "death" ); + self.set_beacon_damage = 1; + wait 0,05; + self.set_beacon_damage = 0; +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_weap_claymore.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_weap_claymore.gsc new file mode 100644 index 0000000..47f5b66 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_weap_claymore.gsc @@ -0,0 +1,482 @@ +#include maps/mp/gametypes_zm/_weaponobjects; +#include maps/mp/zombies/_zm_stats; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zombies/_zm_score; +#include maps/mp/zombies/_zm_equipment; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + if ( !isDefined( level.claymores_max_per_player ) ) + { + level.claymores_max_per_player = 12; + } + trigs = getentarray( "claymore_purchase", "targetname" ); + i = 0; + while ( i < trigs.size ) + { + model = getent( trigs[ i ].target, "targetname" ); + if ( isDefined( model ) ) + { + model hide(); + } + i++; + } + array_thread( trigs, ::buy_claymores ); + level thread give_claymores_after_rounds(); + level.claymores_on_damage = ::satchel_damage; + level.pickup_claymores = ::pickup_claymores; + level.pickup_claymores_trigger_listener = ::pickup_claymores_trigger_listener; + level.claymore_detectiondot = cos( 70 ); + level.claymore_detectionmindist = 20; + level._effect[ "claymore_laser" ] = loadfx( "weapon/claymore/fx_claymore_laser" ); +} + +buy_claymores() +{ + self.zombie_cost = 1000; + self sethintstring( &"ZOMBIE_CLAYMORE_PURCHASE" ); + self setcursorhint( "HINT_WEAPON", "claymore_zm" ); + self endon( "kill_trigger" ); + if ( !isDefined( self.stub ) ) + { + return; + } + if ( isDefined( self.stub ) && !isDefined( self.stub.claymores_triggered ) ) + { + self.stub.claymores_triggered = 0; + } + self.claymores_triggered = self.stub.claymores_triggered; + while ( 1 ) + { + self waittill( "trigger", who ); + while ( who in_revive_trigger() ) + { + continue; + } + while ( who has_powerup_weapon() ) + { + wait 0,1; + } + if ( is_player_valid( who ) ) + { + if ( who.score >= self.zombie_cost ) + { + if ( !who is_player_placeable_mine( "claymore_zm" ) ) + { + play_sound_at_pos( "purchase", self.origin ); + who maps/mp/zombies/_zm_score::minus_to_player_score( self.zombie_cost ); + who thread claymore_setup(); + who thread show_claymore_hint( "claymore_purchased" ); + who thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "weapon_pickup", "grenade" ); + if ( isDefined( self.stub ) ) + { + self.claymores_triggered = self.stub.claymores_triggered; + } + if ( self.claymores_triggered == 0 ) + { + model = getent( self.target, "targetname" ); + if ( isDefined( model ) ) + { + model thread maps/mp/zombies/_zm_weapons::weapon_show( who ); + } + else + { + if ( isDefined( self.clientfieldname ) ) + { + level setclientfield( self.clientfieldname, 1 ); + } + } + self.claymores_triggered = 1; + if ( isDefined( self.stub ) ) + { + self.stub.claymores_triggered = 1; + } + } + trigs = getentarray( "claymore_purchase", "targetname" ); + i = 0; + while ( i < trigs.size ) + { + trigs[ i ] setinvisibletoplayer( who ); + i++; + } + } + else who thread show_claymore_hint( "already_purchased" ); + break; + } + else + { + who play_sound_on_ent( "no_purchase" ); + who maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "no_money_weapon" ); + } + } + } +} + +claymore_unitrigger_update_prompt( player ) +{ + if ( player is_player_placeable_mine( "claymore_zm" ) ) + { + self sethintstring( "" ); + self setcursorhint( "HINT_NOICON" ); + return 0; + } + self sethintstring( &"ZOMBIE_CLAYMORE_PURCHASE" ); + self setcursorhint( "HINT_WEAPON", "claymore_zm" ); + return 1; +} + +set_claymore_visible() +{ + players = get_players(); + trigs = getentarray( "claymore_purchase", "targetname" ); + while ( 1 ) + { + j = 0; + while ( j < players.size ) + { + while ( !players[ j ] is_player_placeable_mine( "claymore_zm" ) ) + { + i = 0; + while ( i < trigs.size ) + { + trigs[ i ] setinvisibletoplayer( players[ j ], 0 ); + i++; + } + } + j++; + } + wait 1; + players = get_players(); + } +} + +claymore_safe_to_plant() +{ + if ( self.owner.claymores.size >= level.claymores_max_per_player ) + { + return 0; + } + if ( isDefined( level.claymore_safe_to_plant ) ) + { + return self [[ level.claymore_safe_to_plant ]](); + } + return 1; +} + +claymore_wait_and_detonate() +{ + wait 0,1; + self detonate( self.owner ); +} + +claymore_watch() +{ + self endon( "death" ); + self notify( "claymore_watch" ); + self endon( "claymore_watch" ); + while ( 1 ) + { + self waittill( "grenade_fire", claymore, weapname ); + if ( weapname == "claymore_zm" ) + { + claymore.owner = self; + claymore.team = self.team; + self notify( "zmb_enable_claymore_prompt" ); + if ( claymore claymore_safe_to_plant() ) + { + if ( isDefined( level.claymore_planted ) ) + { + self thread [[ level.claymore_planted ]]( claymore ); + } + claymore thread claymore_detonation(); + claymore thread play_claymore_effects(); + self maps/mp/zombies/_zm_stats::increment_client_stat( "claymores_planted" ); + self maps/mp/zombies/_zm_stats::increment_player_stat( "claymores_planted" ); + break; + } + else + { + claymore thread claymore_wait_and_detonate(); + } + } + } +} + +claymore_setup() +{ + if ( !isDefined( self.claymores ) ) + { + self.claymores = []; + } + self thread claymore_watch(); + self giveweapon( "claymore_zm" ); + self set_player_placeable_mine( "claymore_zm" ); + self setactionslot( 4, "weapon", "claymore_zm" ); + self setweaponammostock( "claymore_zm", 2 ); +} + +adjust_trigger_origin( origin ) +{ + origin += vectorScale( ( 0, 0, 1 ), 20 ); + return origin; +} + +on_spawn_retrieve_trigger( watcher, player ) +{ + self maps/mp/gametypes_zm/_weaponobjects::onspawnretrievableweaponobject( watcher, player ); + if ( isDefined( self.pickuptrigger ) ) + { + self.pickuptrigger sethintlowpriority( 0 ); + } +} + +pickup_claymores() +{ + player = self.owner; + if ( !player hasweapon( "claymore_zm" ) ) + { + player thread claymore_watch(); + player giveweapon( "claymore_zm" ); + player set_player_placeable_mine( "claymore_zm" ); + player setactionslot( 4, "weapon", "claymore_zm" ); + player setweaponammoclip( "claymore_zm", 0 ); + player notify( "zmb_enable_claymore_prompt" ); + } + else + { + clip_ammo = player getweaponammoclip( self.name ); + clip_max_ammo = weaponclipsize( self.name ); + if ( clip_ammo >= clip_max_ammo ) + { + self destroy_ent(); + player notify( "zmb_disable_claymore_prompt" ); + return; + } + } + self pick_up(); + clip_ammo = player getweaponammoclip( self.name ); + clip_max_ammo = weaponclipsize( self.name ); + if ( clip_ammo >= clip_max_ammo ) + { + player notify( "zmb_disable_claymore_prompt" ); + } + player maps/mp/zombies/_zm_stats::increment_client_stat( "claymores_pickedup" ); + player maps/mp/zombies/_zm_stats::increment_player_stat( "claymores_pickedup" ); +} + +pickup_claymores_trigger_listener( trigger, player ) +{ + self thread pickup_claymores_trigger_listener_enable( trigger, player ); + self thread pickup_claymores_trigger_listener_disable( trigger, player ); +} + +pickup_claymores_trigger_listener_enable( trigger, player ) +{ + self endon( "delete" ); + self endon( "death" ); + while ( 1 ) + { + player waittill_any( "zmb_enable_claymore_prompt", "spawned_player" ); + if ( !isDefined( trigger ) ) + { + return; + } + trigger trigger_on(); + trigger linkto( self ); + } +} + +pickup_claymores_trigger_listener_disable( trigger, player ) +{ + self endon( "delete" ); + self endon( "death" ); + while ( 1 ) + { + player waittill( "zmb_disable_claymore_prompt" ); + if ( !isDefined( trigger ) ) + { + return; + } + trigger unlink(); + trigger trigger_off(); + } +} + +shouldaffectweaponobject( object ) +{ + pos = self.origin + vectorScale( ( 0, 0, 1 ), 32 ); + dirtopos = pos - object.origin; + objectforward = anglesToForward( object.angles ); + dist = vectordot( dirtopos, objectforward ); + if ( dist < level.claymore_detectionmindist ) + { + return 0; + } + dirtopos = vectornormalize( dirtopos ); + dot = vectordot( dirtopos, objectforward ); + return dot > level.claymore_detectiondot; +} + +claymore_detonation() +{ + self endon( "death" ); + self waittill_not_moving(); + detonateradius = 96; + damagearea = spawn( "trigger_radius", self.origin + ( 0, 0, 0 - detonateradius ), 4, detonateradius, detonateradius * 2 ); + damagearea setexcludeteamfortrigger( self.team ); + damagearea enablelinkto(); + damagearea linkto( self ); + if ( is_true( self.isonbus ) ) + { + damagearea setmovingplatformenabled( 1 ); + } + self.damagearea = damagearea; + self thread delete_claymores_on_death( self.owner, damagearea ); + self.owner.claymores[ self.owner.claymores.size ] = self; + while ( 1 ) + { + damagearea waittill( "trigger", ent ); + if ( isDefined( self.owner ) && ent == self.owner ) + { + continue; + } + while ( isDefined( ent.pers ) && isDefined( ent.pers[ "team" ] ) && ent.pers[ "team" ] == self.team ) + { + continue; + } + if ( isDefined( ent.ignore_claymore ) && ent.ignore_claymore ) + { + continue; + } + while ( !ent shouldaffectweaponobject( self ) ) + { + continue; + } + if ( ent damageconetrace( self.origin, self ) > 0 ) + { + self playsound( "wpn_claymore_alert" ); + wait 0,4; + if ( isDefined( self.owner ) ) + { + self detonate( self.owner ); + } + else + { + self detonate( undefined ); + } + return; + } + } +} + +delete_claymores_on_death( player, ent ) +{ + self waittill( "death" ); + if ( isDefined( player ) ) + { + arrayremovevalue( player.claymores, self ); + } + wait 0,05; + if ( isDefined( ent ) ) + { + ent delete(); + } +} + +satchel_damage() +{ + self endon( "death" ); + self setcandamage( 1 ); + self.health = 100000; + self.maxhealth = self.health; + attacker = undefined; + while ( 1 ) + { + self waittill( "damage", amount, attacker ); + if ( !isDefined( self ) ) + { + return; + } + self.health = self.maxhealth; + while ( !isplayer( attacker ) ) + { + continue; + } + if ( isDefined( self.owner ) && attacker == self.owner ) + { + continue; + } + while ( isDefined( attacker.pers ) && isDefined( attacker.pers[ "team" ] ) && attacker.pers[ "team" ] != level.zombie_team ) + { + continue; + } + } + if ( level.satchelexplodethisframe ) + { + wait ( 0,1 + randomfloat( 0,4 ) ); + } + else wait 0,05; + if ( !isDefined( self ) ) + { + return; + } + level.satchelexplodethisframe = 1; + thread reset_satchel_explode_this_frame(); + self detonate( attacker ); +} + +reset_satchel_explode_this_frame() +{ + wait 0,05; + level.satchelexplodethisframe = 0; +} + +play_claymore_effects() +{ + self endon( "death" ); + self waittill_not_moving(); + playfxontag( level._effect[ "claymore_laser" ], self, "tag_fx" ); +} + +give_claymores_after_rounds() +{ + while ( 1 ) + { + level waittill( "between_round_over" ); + while ( !level flag_exists( "teleporter_used" ) || !flag( "teleporter_used" ) ) + { + players = get_players(); + i = 0; + while ( i < players.size ) + { + if ( players[ i ] is_player_placeable_mine( "claymore_zm" ) ) + { + players[ i ] giveweapon( "claymore_zm" ); + players[ i ] set_player_placeable_mine( "claymore_zm" ); + players[ i ] setactionslot( 4, "weapon", "claymore_zm" ); + players[ i ] setweaponammoclip( "claymore_zm", 2 ); + } + i++; + } + } + } +} + +show_claymore_hint( string ) +{ + self endon( "death" ); + self endon( "disconnect" ); + if ( string == "claymore_purchased" ) + { + text = &"ZOMBIE_CLAYMORE_HOWTO"; + } + else + { + text = &"ZOMBIE_CLAYMORE_ALREADY_PURCHASED"; + } + show_equipment_hint_text( text ); +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_weap_one_inch_punch.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_weap_one_inch_punch.gsc new file mode 100644 index 0000000..e407f85 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_weap_one_inch_punch.gsc @@ -0,0 +1,369 @@ +#include maps/mp/animscripts/zm_shared; +#include maps/mp/zombies/_zm_weap_staff_lightning; +#include maps/mp/zombies/_zm_score; +#include maps/mp/zombies/_zm_weap_staff_water; +#include maps/mp/zombies/_zm_weap_staff_fire; +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zombies/_zm_net; +#include maps/mp/zombies/_zm_utility; +#include common_scripts/utility; +#include maps/mp/_utility; + +one_inch_precache() +{ + precacheitem( "one_inch_punch_zm" ); + precacheitem( "one_inch_punch_fire_zm" ); + precacheitem( "one_inch_punch_air_zm" ); + precacheitem( "one_inch_punch_ice_zm" ); + precacheitem( "one_inch_punch_lightning_zm" ); + precacheitem( "one_inch_punch_upgraded_zm" ); + precacheitem( "zombie_one_inch_punch_flourish" ); + precacheitem( "zombie_one_inch_punch_upgrade_flourish" ); + level._effect[ "oneinch_impact" ] = loadfx( "maps/zombie_tomb/fx_tomb_perk_one_inch_punch" ); + level._effect[ "punch_knockdown_ground" ] = loadfx( "weapon/thunder_gun/fx_thundergun_knockback_ground" ); +} + +one_inch_punch_melee_attack() +{ + self endon( "disconnect" ); + self endon( "stop_one_inch_punch_attack" ); + if ( isDefined( self.one_inch_punch_flag_has_been_init ) && !self.one_inch_punch_flag_has_been_init ) + { + self ent_flag_init( "melee_punch_cooldown" ); + } + self.one_inch_punch_flag_has_been_init = 1; + current_melee_weapon = self get_player_melee_weapon(); + self takeweapon( current_melee_weapon ); + if ( isDefined( self.b_punch_upgraded ) && self.b_punch_upgraded ) + { + str_weapon = self getcurrentweapon(); + self disable_player_move_states( 1 ); + self giveweapon( "zombie_one_inch_punch_upgrade_flourish" ); + self switchtoweapon( "zombie_one_inch_punch_upgrade_flourish" ); + self waittill_any( "player_downed", "weapon_change_complete" ); + self switchtoweapon( str_weapon ); + self enable_player_move_states(); + self takeweapon( "zombie_one_inch_punch_upgrade_flourish" ); + if ( self.str_punch_element == "air" ) + { + self giveweapon( "one_inch_punch_air_zm" ); + self set_player_melee_weapon( "one_inch_punch_air_zm" ); + } + else if ( self.str_punch_element == "fire" ) + { + self giveweapon( "one_inch_punch_fire_zm" ); + self set_player_melee_weapon( "one_inch_punch_fire_zm" ); + } + else if ( self.str_punch_element == "ice" ) + { + self giveweapon( "one_inch_punch_ice_zm" ); + self set_player_melee_weapon( "one_inch_punch_ice_zm" ); + } + else if ( self.str_punch_element == "lightning" ) + { + self giveweapon( "one_inch_punch_lightning_zm" ); + self set_player_melee_weapon( "one_inch_punch_lightning_zm" ); + } + else + { + self giveweapon( "one_inch_punch_upgraded_zm" ); + self set_player_melee_weapon( "one_inch_punch_upgraded_zm" ); + } + } + else + { + str_weapon = self getcurrentweapon(); + self disable_player_move_states( 1 ); + self giveweapon( "zombie_one_inch_punch_flourish" ); + self switchtoweapon( "zombie_one_inch_punch_flourish" ); + self waittill_any( "player_downed", "weapon_change_complete" ); + self switchtoweapon( str_weapon ); + self enable_player_move_states(); + self takeweapon( "zombie_one_inch_punch_flourish" ); + self giveweapon( "one_inch_punch_zm" ); + self set_player_melee_weapon( "one_inch_punch_zm" ); + self thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "perk", "one_inch" ); + } + self thread monitor_melee_swipe(); +} + +monitor_melee_swipe() +{ + self endon( "disconnect" ); + self notify( "stop_monitor_melee_swipe" ); + self endon( "stop_monitor_melee_swipe" ); + self endon( "bled_out" ); + while ( 1 ) + { + while ( !self ismeleeing() ) + { + wait 0,05; + } + while ( self getcurrentweapon() == level.riotshield_name ) + { + wait 0,1; + } + range_mod = 1; + self setclientfield( "oneinchpunch_impact", 1 ); + wait_network_frame(); + self setclientfield( "oneinchpunch_impact", 0 ); + v_punch_effect_fwd = anglesToForward( self getplayerangles() ); + v_punch_yaw = get2dyaw( ( 0, 0, 0 ), v_punch_effect_fwd ); + if ( isDefined( self.b_punch_upgraded ) && self.b_punch_upgraded && isDefined( self.str_punch_element ) && self.str_punch_element == "air" ) + { + range_mod *= 2; + } + a_zombies = getaispeciesarray( level.zombie_team, "all" ); + a_zombies = get_array_of_closest( self.origin, a_zombies, undefined, undefined, 100 ); + _a147 = a_zombies; + _k147 = getFirstArrayKey( _a147 ); + while ( isDefined( _k147 ) ) + { + zombie = _a147[ _k147 ]; + if ( self is_player_facing( zombie, v_punch_yaw ) && distancesquared( self.origin, zombie.origin ) <= ( 4096 * range_mod ) ) + { + self thread zombie_punch_damage( zombie, 1 ); + } + else + { + if ( self is_player_facing( zombie, v_punch_yaw ) ) + { + self thread zombie_punch_damage( zombie, 0,5 ); + } + } + _k147 = getNextArrayKey( _a147, _k147 ); + } + while ( self ismeleeing() ) + { + wait 0,05; + } + wait 0,05; + } +} + +is_player_facing( zombie, v_punch_yaw ) +{ + v_player_to_zombie_yaw = get2dyaw( self.origin, zombie.origin ); + yaw_diff = v_player_to_zombie_yaw - v_punch_yaw; + if ( yaw_diff < 0 ) + { + yaw_diff *= -1; + } + if ( yaw_diff < 35 ) + { + return 1; + } + else + { + return 0; + } +} + +is_oneinch_punch_damage() +{ + if ( isDefined( self.damageweapon ) ) + { + return self.damageweapon == "one_inch_punch_zm"; + } +} + +gib_zombies_head( player ) +{ + player endon( "disconnect" ); + self maps/mp/zombies/_zm_spawner::zombie_head_gib(); +} + +punch_cooldown() +{ + wait 1; + self ent_flag_set( "melee_punch_cooldown" ); +} + +zombie_punch_damage( ai_zombie, n_mod ) +{ + self endon( "disconnect" ); + ai_zombie.punch_handle_pain_notetracks = ::handle_punch_pain_notetracks; + if ( isDefined( n_mod ) ) + { + if ( isDefined( self.b_punch_upgraded ) && self.b_punch_upgraded ) + { + n_base_damage = 11275; + } + else + { + n_base_damage = 2250; + } + n_damage = int( n_base_damage * n_mod ); + if ( isDefined( ai_zombie.is_mechz ) && !ai_zombie.is_mechz ) + { + if ( n_damage >= ai_zombie.health ) + { + self thread zombie_punch_death( ai_zombie ); + self do_player_general_vox( "kill", "one_inch_punch" ); + if ( isDefined( self.b_punch_upgraded ) && self.b_punch_upgraded && isDefined( self.str_punch_element ) ) + { + switch( self.str_punch_element ) + { + case "fire": + ai_zombie thread maps/mp/zombies/_zm_weap_staff_fire::flame_damage_fx( self.current_melee_weapon, self, n_mod ); + break; + case "ice": + ai_zombie thread maps/mp/zombies/_zm_weap_staff_water::ice_affect_zombie( self.current_melee_weapon, self, 0, n_mod ); + break; + case "lightning": + if ( isDefined( ai_zombie.is_mechz ) && ai_zombie.is_mechz ) + { + return; + } + if ( isDefined( ai_zombie.is_electrocuted ) && ai_zombie.is_electrocuted ) + { + return; + } + tag = "J_SpineUpper"; + network_safe_play_fx_on_tag( "lightning_impact", 2, level._effect[ "lightning_impact" ], ai_zombie, tag ); + ai_zombie thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( "electrocute", ai_zombie.animname ); + break; + } + } + break; + } + else self maps/mp/zombies/_zm_score::player_add_points( "damage_light" ); + if ( isDefined( self.b_punch_upgraded ) && self.b_punch_upgraded && isDefined( self.str_punch_element ) ) + { + switch( self.str_punch_element ) + { + case "fire": + ai_zombie thread maps/mp/zombies/_zm_weap_staff_fire::flame_damage_fx( self.current_melee_weapon, self, n_mod ); + break; + case "ice": + ai_zombie thread maps/mp/zombies/_zm_weap_staff_water::ice_affect_zombie( self.current_melee_weapon, self, 0, n_mod ); + break; + case "lightning": + ai_zombie thread maps/mp/zombies/_zm_weap_staff_lightning::stun_zombie(); + break; + } + } + } + ai_zombie dodamage( n_damage, ai_zombie.origin, self, self, 0, "MOD_MELEE", 0, self.current_melee_weapon ); +} +} + +zombie_punch_death( ai_zombie ) +{ + ai_zombie thread gib_zombies_head( self ); + if ( isDefined( level.ragdoll_limit_check ) && !( [[ level.ragdoll_limit_check ]]() ) ) + { + return; + } + if ( isDefined( ai_zombie ) ) + { + ai_zombie startragdoll(); + ai_zombie setclientfield( "oneinchpunch_physics_launchragdoll", 1 ); + } + wait_network_frame(); + if ( isDefined( ai_zombie ) ) + { + ai_zombie setclientfield( "oneinchpunch_physics_launchragdoll", 0 ); + } +} + +handle_punch_pain_notetracks( note ) +{ + if ( note == "zombie_knockdown_ground_impact" ) + { + playfx( level._effect[ "punch_knockdown_ground" ], self.origin, anglesToForward( self.angles ), anglesToUp( self.angles ) ); + } +} + +knockdown_zombie_animate() +{ + self notify( "end_play_punch_pain_anim" ); + self endon( "killanimscript" ); + self endon( "death" ); + self endon( "end_play_punch_pain_anim" ); + if ( isDefined( self.marked_for_death ) && self.marked_for_death ) + { + return; + } + self.allowpain = 0; + animation_direction = undefined; + animation_legs = ""; + animation_side = undefined; + animation_duration = "_default"; + v_forward = vectordot( anglesToForward( self.angles ), vectornormalize( self.v_punched_from - self.origin ) ); + if ( v_forward > 0,6 ) + { + animation_direction = "back"; + if ( isDefined( self.has_legs ) && !self.has_legs ) + { + animation_legs = "_crawl"; + } + if ( randomint( 100 ) > 75 ) + { + animation_side = "belly"; + } + else + { + animation_side = "back"; + } + } + else if ( self.damageyaw > 75 && self.damageyaw < 135 ) + { + animation_direction = "left"; + animation_side = "belly"; + } + else + { + if ( self.damageyaw > -135 && self.damageyaw < -75 ) + { + animation_direction = "right"; + animation_side = "belly"; + } + else + { + animation_direction = "front"; + animation_side = "belly"; + } + } + self thread knockdown_zombie_animate_state(); + self setanimstatefromasd( "zm_punch_fall_" + animation_direction + animation_legs ); + self maps/mp/animscripts/zm_shared::donotetracks( "punch_fall_anim", self.punch_handle_pain_notetracks ); + if ( isDefined( self.has_legs ) || !self.has_legs && isDefined( self.marked_for_death ) && self.marked_for_death ) + { + return; + } + if ( isDefined( self.a.gib_ref ) ) + { + if ( self.a.gib_ref != "no_legs" && self.a.gib_ref != "no_arms" && self.a.gib_ref != "left_leg" && self.a.gib_ref == "right_leg" || randomint( 100 ) > 25 && self.a.gib_ref != "left_arm" && self.a.gib_ref == "right_arm" && randomint( 100 ) > 75 ) + { + animation_duration = "_late"; + } + else + { + if ( randomint( 100 ) > 75 ) + { + animation_duration = "_early"; + } + } + } + else + { + if ( randomint( 100 ) > 25 ) + { + animation_duration = "_early"; + } + } + self setanimstatefromasd( "zm_punch_getup_" + animation_side + animation_duration ); + self maps/mp/animscripts/zm_shared::donotetracks( "punch_getup_anim" ); + self.allowpain = 1; + self notify( "back_up" ); +} + +knockdown_zombie_animate_state() +{ + self endon( "death" ); + self.is_knocked_down = 1; + self waittill_any( "damage", "back_up" ); + self.is_knocked_down = 0; +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_weap_riotshield_tomb.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_weap_riotshield_tomb.gsc new file mode 100644 index 0000000..29a3423 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_weap_riotshield_tomb.gsc @@ -0,0 +1,783 @@ +#include maps/mp/zombies/_zm_audio; +#include maps/mp/animscripts/zm_death; +#include maps/mp/zombies/_zm_unitrigger; +#include maps/mp/zombies/_zm_weapons; +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/zombies/_zm_stats; +#include maps/mp/gametypes_zm/_weaponobjects; +#include maps/mp/zombies/_zm_equipment; +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_utility; +#include common_scripts/utility; +#include maps/mp/_utility; + +init() +{ + maps/mp/zombies/_zm_riotshield_tomb::init(); + set_zombie_var( "riotshield_cylinder_radius", 360 ); + set_zombie_var( "riotshield_fling_range", 90 ); + set_zombie_var( "riotshield_gib_range", 90 ); + set_zombie_var( "riotshield_gib_damage", 75 ); + set_zombie_var( "riotshield_knockdown_range", 90 ); + set_zombie_var( "riotshield_knockdown_damage", 15 ); + set_zombie_var( "riotshield_hit_points", 1500 ); + set_zombie_var( "riotshield_fling_damage_shield", 100 ); + set_zombie_var( "riotshield_knockdown_damage_shield", 15 ); + level.riotshield_network_choke_count = 0; + level.riotshield_gib_refs = []; + level.riotshield_gib_refs[ level.riotshield_gib_refs.size ] = "guts"; + level.riotshield_gib_refs[ level.riotshield_gib_refs.size ] = "right_arm"; + level.riotshield_gib_refs[ level.riotshield_gib_refs.size ] = "left_arm"; + level.riotshield_damage_callback = ::player_damage_shield; + level.deployed_riotshield_damage_callback = ::deployed_damage_shield; + level.transferriotshield = ::transferriotshield; + level.cantransferriotshield = ::cantransferriotshield; + maps/mp/zombies/_zm_spawner::register_zombie_damage_callback( ::riotshield_zombie_damage_response ); + maps/mp/zombies/_zm_equipment::register_equipment( "tomb_shield_zm", &"ZOMBIE_EQUIP_RIOTSHIELD_PICKUP_HINT_STRING", &"ZOMBIE_EQUIP_RIOTSHIELD_HOWTO", "riotshield_zm_icon", "riotshield", ::riotshield_activation_watcher_thread, undefined, ::dropshield, ::pickupshield ); + maps/mp/gametypes_zm/_weaponobjects::createretrievablehint( "riotshield", &"ZOMBIE_EQUIP_RIOTSHIELD_PICKUP_HINT_STRING" ); + onplayerconnect_callback( ::onplayerconnect ); +} + +onplayerconnect() +{ + self.player_shield_reset_health = ::player_init_shield_health; + self.player_shield_apply_damage = ::player_damage_shield; + self.player_shield_reset_location = ::player_init_shield_location; + self thread watchriotshielduse(); + self thread watchriotshieldmelee(); + self thread player_watch_laststand(); +} + +dropshield() +{ + self.shield_placement = 0; + self maps/mp/zombies/_zm_riotshield_tomb::updateriotshieldmodel(); + item = self maps/mp/zombies/_zm_equipment::placed_equipment_think( "t6_wpn_zmb_shield_dlc4_dmg0_world", "tomb_shield_zm", self.origin + vectorScale( ( 0, 0, 1 ), 30 ), self.angles ); + if ( isDefined( item ) ) + { + item.shielddamagetaken = self.shielddamagetaken; + item.original_owner = self; + item.owner = undefined; + item.name = level.riotshield_name; + item.isriotshield = 1; + item deployed_damage_shield( 0 ); + item setscriptmoverflag( 0 ); + item.requires_pickup = 1; + item thread watchtoofriendly( self ); + } + self takeweapon( level.riotshield_name ); + return item; +} + +watchtoofriendly( player ) +{ + wait 1; + if ( isDefined( self ) && isDefined( player ) && distance2dsquared( self.origin, player.origin ) < 36 ) + { + if ( isalive( player ) ) + { + player playlocalsound( level.zmb_laugh_alias ); + } + player maps/mp/zombies/_zm_stats::increment_client_stat( "cheat_total", 0 ); + self deployed_damage_shield( 2000 ); + } +} + +pickupshield( item ) +{ + item.owner = self; + damage = item.shielddamagetaken; + damagemax = level.zombie_vars[ "riotshield_hit_points" ]; + self.shielddamagetaken = damage; + self player_set_shield_health( damage, damagemax ); +} + +placeshield( origin, angles ) +{ + if ( self getcurrentweapon() != level.riotshield_name ) + { + self switchtoweapon( level.riotshield_name ); + self waittill( "weapon_change" ); + } + item = self maps/mp/zombies/_zm_riotshield_tomb::doriotshielddeploy( origin, angles ); + if ( isDefined( item ) ) + { + item.origin = self.origin + vectorScale( ( 0, 0, 1 ), 30 ); + item.angles = self.angles; + item.owner = self; + } + return item; +} + +cantransferriotshield( fromplayer, toplayer ) +{ + if ( isDefined( toplayer.screecher_weapon ) ) + { + return 0; + } + if ( isDefined( toplayer.is_drinking ) && toplayer.is_drinking > 0 ) + { + return 0; + } + if ( toplayer maps/mp/zombies/_zm_laststand::player_is_in_laststand() || toplayer in_revive_trigger() ) + { + return 0; + } + if ( toplayer isthrowinggrenade() ) + { + return 0; + } + if ( fromplayer == toplayer ) + { + return 1; + } + if ( toplayer is_player_equipment( level.riotshield_name ) && toplayer.shield_placement != 3 ) + { + return 0; + } + if ( fromplayer.session_team != toplayer.session_team ) + { + return 0; + } + return 1; +} + +transferriotshield( fromplayer, toplayer ) +{ + damage = fromplayer.shielddamagetaken; + toplayer player_take_riotshield(); + fromplayer player_take_riotshield(); + toplayer.shielddamagetaken = damage; + toplayer.shield_placement = 3; + toplayer.shield_damage_level = 0; + toplayer maps/mp/zombies/_zm_equipment::equipment_give( "tomb_shield_zm" ); + toplayer switchtoweapon( "tomb_shield_zm" ); + damagemax = level.zombie_vars[ "riotshield_hit_points" ]; + toplayer player_set_shield_health( damage, damagemax ); +} + +player_take_riotshield() +{ + self notify( "destroy_riotshield" ); + if ( self getcurrentweapon() == "tomb_shield_zm" ) + { + new_primary = ""; + if ( isDefined( self.laststand ) && self.laststand ) + { + new_primary = self.laststandpistol; + self giveweapon( new_primary ); + } + else + { + primaryweapons = self getweaponslistprimaries(); + i = 0; + while ( i < primaryweapons.size ) + { + if ( primaryweapons[ i ] != "tomb_shield_zm" ) + { + new_primary = primaryweapons[ i ]; + break; + } + else + { + i++; + } + } + if ( new_primary == "" ) + { + self maps/mp/zombies/_zm_weapons::give_fallback_weapon(); + new_primary = "zombie_fists_zm"; + } + } + self switchtoweaponimmediate( new_primary ); + self playsound( "wpn_riotshield_zm_destroy" ); + self waittill( "weapon_change" ); + } + self maps/mp/zombies/_zm_riotshield_tomb::removeriotshield(); + self maps/mp/zombies/_zm_equipment::equipment_take( "tomb_shield_zm" ); + self.hasriotshield = 0; + self.hasriotshieldequipped = 0; +} + +player_watch_laststand() +{ + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "entering_last_stand" ); + if ( self getcurrentweapon() == "tomb_shield_zm" ) + { + new_primary = self.laststandpistol; + self giveweapon( new_primary ); + self switchtoweaponimmediate( new_primary ); + } + } +} + +player_init_shield_health() +{ + retval = self.shielddamagetaken > 0; + self.shielddamagetaken = 0; + self.shield_damage_level = 0; + self maps/mp/zombies/_zm_riotshield_tomb::updateriotshieldmodel(); + return retval; +} + +player_init_shield_location() +{ + self.hasriotshield = 1; + self.hasriotshieldequipped = 0; + self.shield_placement = 2; + self maps/mp/zombies/_zm_riotshield_tomb::updateriotshieldmodel(); +} + +player_set_shield_health( damage, max_damage ) +{ + shieldhealth = int( ( 100 * ( max_damage - damage ) ) / max_damage ); + if ( shieldhealth >= 50 ) + { + self.shield_damage_level = 0; + } + else if ( shieldhealth >= 25 ) + { + self.shield_damage_level = 2; + } + else + { + self.shield_damage_level = 3; + } + self maps/mp/zombies/_zm_riotshield_tomb::updateriotshieldmodel(); +} + +deployed_set_shield_health( damage, max_damage ) +{ + shieldhealth = int( ( 100 * ( max_damage - damage ) ) / max_damage ); + if ( shieldhealth >= 50 ) + { + self.shield_damage_level = 0; + } + else if ( shieldhealth >= 25 ) + { + self.shield_damage_level = 2; + } + else + { + self.shield_damage_level = 3; + } + self maps/mp/zombies/_zm_riotshield_tomb::updatestandaloneriotshieldmodel(); +} + +player_damage_shield( idamage, bheld ) +{ + damagemax = level.zombie_vars[ "riotshield_hit_points" ]; + if ( !isDefined( self.shielddamagetaken ) ) + { + self.shielddamagetaken = 0; + } + self.shielddamagetaken += idamage; + if ( self.shielddamagetaken >= damagemax ) + { + if ( bheld || !isDefined( self.shield_ent ) ) + { + self playrumbleonentity( "damage_heavy" ); + earthquake( 1, 0,75, self.origin, 100 ); + } + else + { + if ( isDefined( self.shield_ent ) ) + { + if ( is_true( self.shield_ent.destroy_begun ) ) + { + return; + } + self.shield_ent.destroy_begun = 1; + shield_origin = self.shield_ent.origin; + level thread maps/mp/zombies/_zm_equipment::equipment_disappear_fx( shield_origin, level._riotshield_dissapear_fx ); + wait 1; + playsoundatposition( "wpn_riotshield_zm_destroy", shield_origin ); + } + } + self thread player_take_riotshield(); + } + else + { + if ( bheld ) + { + self playrumbleonentity( "damage_light" ); + earthquake( 0,5, 0,5, self.origin, 100 ); + } + self player_set_shield_health( self.shielddamagetaken, damagemax ); + self playsound( "fly_riotshield_zm_impact_zombies" ); + } +} + +deployed_damage_shield( idamage ) +{ + damagemax = level.zombie_vars[ "riotshield_hit_points" ]; + if ( !isDefined( self.shielddamagetaken ) ) + { + self.shielddamagetaken = 0; + } + self.shielddamagetaken += idamage; + if ( self.shielddamagetaken >= damagemax ) + { + shield_origin = self.origin; + if ( isDefined( self.stub ) ) + { + thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( self.stub ); + } + if ( isDefined( self.original_owner ) ) + { + self.original_owner maps/mp/zombies/_zm_equipment::equipment_take( "tomb_shield_zm" ); + } + maps/mp/zombies/_zm_equipment::equipment_disappear_fx( shield_origin, level._riotshield_dissapear_fx ); + playsoundatposition( "wpn_riotshield_zm_destroy", shield_origin ); + self_delete(); + } + else + { + self deployed_set_shield_health( self.shielddamagetaken, damagemax ); + } +} + +riotshield_activation_watcher_thread() +{ + self endon( "zombified" ); + self endon( "disconnect" ); + self endon( "tomb_shield_zm_taken" ); + while ( 1 ) + { + self waittill_either( "tomb_shield_zm_activate", "tomb_shield_zm_deactivate" ); + } +} + +watchriotshielduse() +{ + self endon( "death" ); + self endon( "disconnect" ); + self.shielddamagetaken = 0; + self thread maps/mp/zombies/_zm_riotshield_tomb::trackriotshield(); + self thread maps/mp/zombies/_zm_riotshield_tomb::trackequipmentchange(); + self thread maps/mp/zombies/_zm_riotshield_tomb::watchshieldlaststand(); + self thread trackstuckzombies(); + for ( ;; ) + { + self waittill( "raise_riotshield" ); + self thread maps/mp/zombies/_zm_riotshield_tomb::startriotshielddeploy(); + } +} + +watchriotshieldmelee() +{ + for ( ;; ) + { + self waittill( "weapon_melee", weapon ); + if ( weapon == level.riotshield_name ) + { + self riotshield_melee(); + } + } +} + +is_riotshield_damage( mod, player, amount ) +{ + if ( mod == "MOD_MELEE" && player hasweapon( level.riotshield_name ) && amount < 10 ) + { + return 1; + } + return 0; +} + +riotshield_damage( amount ) +{ +} + +riotshield_fling_zombie( player, fling_vec, index ) +{ + if ( !isDefined( self ) || !isalive( self ) ) + { + return; + } + if ( isDefined( self.ignore_riotshield ) && self.ignore_riotshield ) + { + return; + } + if ( isDefined( self.riotshield_fling_func ) ) + { + self [[ self.riotshield_fling_func ]]( player ); + return; + } + damage = 2500; + self dodamage( damage, player.origin, player, player, "", "MOD_IMPACT" ); + if ( self.health < 1 ) + { + self.riotshield_death = 1; + if ( isDefined( level.ragdoll_limit_check ) && !( [[ level.ragdoll_limit_check ]]() ) ) + { + return; + } + self startragdoll(); + self launchragdoll( fling_vec ); + } +} + +zombie_knockdown( player, gib ) +{ + damage = level.zombie_vars[ "riotshield_knockdown_damage" ]; + if ( isDefined( level.override_riotshield_damage_func ) ) + { + self [[ level.override_riotshield_damage_func ]]( player, gib ); + } + else + { + if ( gib ) + { + self.a.gib_ref = random( level.riotshield_gib_refs ); + self thread maps/mp/animscripts/zm_death::do_gib(); + } + self dodamage( damage, player.origin, player ); + } +} + +riotshield_knockdown_zombie( player, gib ) +{ + self endon( "death" ); + playsoundatposition( "vox_riotshield_forcehit", self.origin ); + playsoundatposition( "wpn_riotshield_proj_impact", self.origin ); + if ( !isDefined( self ) || !isalive( self ) ) + { + return; + } + if ( isDefined( self.riotshield_knockdown_func ) ) + { + self [[ self.riotshield_knockdown_func ]]( player, gib ); + } + else + { + self zombie_knockdown( player, gib ); + } + self dodamage( level.zombie_vars[ "riotshield_knockdown_damage" ], player.origin, player ); + self playsound( "fly_riotshield_forcehit" ); +} + +riotshield_get_enemies_in_range() +{ + view_pos = self geteye(); + zombies = get_array_of_closest( view_pos, get_round_enemy_array_wrapper(), undefined, undefined, 2 * level.zombie_vars[ "riotshield_knockdown_range" ] ); + if ( !isDefined( zombies ) ) + { + return; + } + knockdown_range_squared = level.zombie_vars[ "riotshield_knockdown_range" ] * level.zombie_vars[ "riotshield_knockdown_range" ]; + gib_range_squared = level.zombie_vars[ "riotshield_gib_range" ] * level.zombie_vars[ "riotshield_gib_range" ]; + fling_range_squared = level.zombie_vars[ "riotshield_fling_range" ] * level.zombie_vars[ "riotshield_fling_range" ]; + cylinder_radius_squared = level.zombie_vars[ "riotshield_cylinder_radius" ] * level.zombie_vars[ "riotshield_cylinder_radius" ]; + forward_view_angles = self getweaponforwarddir(); + end_pos = view_pos + vectorScale( forward_view_angles, level.zombie_vars[ "riotshield_knockdown_range" ] ); +/# + if ( getDvarInt( #"BF480CE9" ) == 2 ) + { + near_circle_pos = view_pos + vectorScale( forward_view_angles, 2 ); + circle( near_circle_pos, level.zombie_vars[ "riotshield_cylinder_radius" ], ( 0, 0, 1 ), 0, 0, 100 ); + line( near_circle_pos, end_pos, ( 0, 0, 1 ), 1, 0, 100 ); + circle( end_pos, level.zombie_vars[ "riotshield_cylinder_radius" ], ( 0, 0, 1 ), 0, 0, 100 ); +#/ + } + i = 0; + while ( i < zombies.size ) + { + if ( !isDefined( zombies[ i ] ) || !isalive( zombies[ i ] ) ) + { + i++; + continue; + } + else + { + test_origin = zombies[ i ] getcentroid(); + test_range_squared = distancesquared( view_pos, test_origin ); + if ( test_range_squared > knockdown_range_squared ) + { + zombies[ i ] riotshield_debug_print( "range", ( 0, 0, 1 ) ); + return; + } + normal = vectornormalize( test_origin - view_pos ); + dot = vectordot( forward_view_angles, normal ); + if ( dot <= 0 ) + { + zombies[ i ] riotshield_debug_print( "dot", ( 0, 0, 1 ) ); + i++; + continue; + } + else radial_origin = pointonsegmentnearesttopoint( view_pos, end_pos, test_origin ); + if ( distancesquared( test_origin, radial_origin ) > cylinder_radius_squared ) + { + zombies[ i ] riotshield_debug_print( "cylinder", ( 0, 0, 1 ) ); + i++; + continue; + } + else if ( zombies[ i ] damageconetrace( view_pos, self ) == 0 ) + { + zombies[ i ] riotshield_debug_print( "cone", ( 0, 0, 1 ) ); + i++; + continue; + } + else if ( test_range_squared < fling_range_squared ) + { + level.riotshield_fling_enemies[ level.riotshield_fling_enemies.size ] = zombies[ i ]; + dist_mult = ( fling_range_squared - test_range_squared ) / fling_range_squared; + fling_vec = vectornormalize( test_origin - view_pos ); + if ( test_range_squared >= 5000 ) + { + fling_vec += vectornormalize( test_origin - radial_origin ); + } + fling_vec = ( fling_vec[ 0 ], fling_vec[ 1 ], abs( fling_vec[ 2 ] ) ); + fling_vec = vectorScale( fling_vec, 100 + ( 100 * dist_mult ) ); + level.riotshield_fling_vecs[ level.riotshield_fling_vecs.size ] = fling_vec; + zombies[ i ] riotshield_debug_print( "fling", ( 0, 0, 1 ) ); + i++; + continue; + } + else + { + level.riotshield_knockdown_enemies[ level.riotshield_knockdown_enemies.size ] = zombies[ i ]; + level.riotshield_knockdown_gib[ level.riotshield_knockdown_gib.size ] = 0; + zombies[ i ] riotshield_debug_print( "knockdown", ( 0, 0, 1 ) ); + } + } + i++; + } +} + +riotshield_network_choke() +{ + level.riotshield_network_choke_count++; + if ( level.riotshield_network_choke_count % 10 ) + { + wait_network_frame(); + wait_network_frame(); + wait_network_frame(); + } +} + +riotshield_melee() +{ + if ( !isDefined( level.riotshield_knockdown_enemies ) ) + { + level.riotshield_knockdown_enemies = []; + level.riotshield_knockdown_gib = []; + level.riotshield_fling_enemies = []; + level.riotshield_fling_vecs = []; + } + self riotshield_get_enemies_in_range(); + shield_damage = 0; + level.riotshield_network_choke_count = 0; + i = 0; + while ( i < level.riotshield_fling_enemies.size ) + { + riotshield_network_choke(); + if ( isDefined( level.riotshield_fling_enemies[ i ] ) ) + { + level.riotshield_fling_enemies[ i ] thread riotshield_fling_zombie( self, level.riotshield_fling_vecs[ i ], i ); + shield_damage += level.zombie_vars[ "riotshield_fling_damage_shield" ]; + } + i++; + } + i = 0; + while ( i < level.riotshield_knockdown_enemies.size ) + { + riotshield_network_choke(); + level.riotshield_knockdown_enemies[ i ] thread riotshield_knockdown_zombie( self, level.riotshield_knockdown_gib[ i ] ); + shield_damage += level.zombie_vars[ "riotshield_knockdown_damage_shield" ]; + i++; + } + level.riotshield_knockdown_enemies = []; + level.riotshield_knockdown_gib = []; + level.riotshield_fling_enemies = []; + level.riotshield_fling_vecs = []; + if ( shield_damage ) + { + self player_damage_shield( shield_damage, 0 ); + } +} + +trackstuckzombies() +{ + self endon( "death" ); + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "deployed_riotshield" ); + if ( isDefined( self.riotshieldentity ) ) + { + self thread watchstuckzombies(); + } + } +} + +attack_shield( shield ) +{ + self endon( "death" ); + shield.owner endon( "death" ); + shield.owner endon( "disconnect" ); + shield.owner endon( "start_riotshield_deploy" ); + shield.owner endon( "destroy_riotshield" ); + if ( isDefined( self.doing_shield_attack ) && self.doing_shield_attack ) + { + return 0; + } + self.old_origin = self.origin; + if ( getDvar( "zombie_shield_attack_freq" ) == "" ) + { + setdvar( "zombie_shield_attack_freq", "15" ); + } + freq = getDvarInt( "zombie_shield_attack_freq" ); + self.doing_shield_attack = 1; + self.enemyoverride[ 0 ] = shield.origin; + self.enemyoverride[ 1 ] = shield; + wait ( randomint( 100 ) / 100 ); + self thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( "attack", self.animname ); + attackanim = "zm_riotshield_melee"; + if ( !self.has_legs ) + { + attackanim += "_crawl"; + } + self orientmode( "face point", shield.origin ); + self animscripted( self.origin, flat_angle( vectorToAngle( shield.origin - self.origin ) ), attackanim ); + if ( isDefined( shield.owner.player_shield_apply_damage ) ) + { + shield.owner [[ shield.owner.player_shield_apply_damage ]]( 100, 0 ); + } + else + { + shield.owner player_damage_shield( 100, 0 ); + } + self thread attack_shield_stop( shield ); + wait ( randomint( 100 ) / 100 ); + self.doing_shield_attack = 0; + self orientmode( "face default" ); +} + +attack_shield_stop( shield ) +{ + self notify( "attack_shield_stop" ); + self endon( "attack_shield_stop" ); + self endon( "death" ); + shield waittill( "death" ); + self stopanimscripted(); + if ( isDefined( self.doing_shield_attack ) && self.doing_shield_attack ) + { + breachanim = "zm_riotshield_breakthrough"; + if ( !self.has_legs ) + { + breachanim += "_crawl"; + } + self animscripted( self.origin, flat_angle( self.angles ), breachanim ); + } +} + +window_notetracks( msg, player ) +{ + self endon( "death" ); + while ( 1 ) + { + self waittill( msg, notetrack ); + if ( notetrack == "end" ) + { + return; + } + if ( notetrack == "fire" ) + { + player player_damage_shield( 100, 0 ); + } + } +} + +watchstuckzombies() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "start_riotshield_deploy" ); + self endon( "destroy_riotshield" ); + self endon( "deployed_riotshield" ); + level endon( "intermission" ); + self.riotshieldentity maps/mp/zombies/_zm_equipment::item_attract_zombies(); +} + +riotshield_active() +{ + return self maps/mp/zombies/_zm_equipment::is_equipment_active( "tomb_shield_zm" ); +} + +riotshield_debug_print( msg, color ) +{ +/# + if ( !getDvarInt( #"BF480CE9" ) ) + { + return; + } + if ( !isDefined( color ) ) + { + color = ( 0, 0, 1 ); + } + print3d( self.origin + vectorScale( ( 0, 0, 1 ), 60 ), msg, color, 1, 1, 40 ); +#/ +} + +shield_zombie_attract_func( poi ) +{ +} + +shield_zombie_arrive_func( poi ) +{ + self endon( "death" ); + self endon( "zombie_acquire_enemy" ); + self endon( "path_timer_done" ); + self waittill( "goal" ); + if ( isDefined( poi.owner ) ) + { + poi.owner player_damage_shield( 100, 0 ); + if ( isDefined( poi.owner.player_shield_apply_damage ) ) + { + poi.owner [[ poi.owner.player_shield_apply_damage ]]( 100, 0 ); + } + } +} + +createriotshieldattractor() +{ + self create_zombie_point_of_interest( 50, 8, 0, 1, ::shield_zombie_attract_func, ::shield_zombie_arrive_func ); + self thread create_zombie_point_of_interest_attractor_positions( 4, 15, 15 ); + return get_zombie_point_of_interest( self.origin ); +} + +riotshield_zombie_damage_response( mod, hit_location, hit_origin, player, amount ) +{ + if ( self is_riotshield_damage( mod, player, amount ) ) + { + self riotshield_damage( amount ); + return 1; + } + return 0; +} + +watchriotshieldattractor() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "start_riotshield_deploy" ); + self endon( "destroy_riotshield" ); + self endon( "deployed_riotshield" ); + poi = self.riotshieldentity createriotshieldattractor(); +} + +trackriotshieldattractor() +{ + self endon( "death" ); + self endon( "disconnect" ); + for ( ;; ) + { + self waittill( "deployed_riotshield" ); + self thread watchriotshieldattractor(); + } +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_weap_staff_air.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_weap_staff_air.gsc new file mode 100644 index 0000000..c88e120 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_weap_staff_air.gsc @@ -0,0 +1,640 @@ +#include maps/mp/animscripts/shared; +#include maps/mp/zombies/_zm_powerups; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/zombies/_zm_ai_basic; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_net; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + level._effect[ "whirlwind" ] = loadfx( "weapon/zmb_staff/fx_zmb_staff_air_ug_impact_miss" ); + registerclientfield( "scriptmover", "whirlwind_play_fx", 14000, 1, "int" ); + registerclientfield( "actor", "air_staff_launch", 14000, 1, "int" ); + registerclientfield( "allplayers", "air_staff_source", 14000, 1, "int" ); + onplayerconnect_callback( ::onplayerconnect ); + maps/mp/zombies/_zm_ai_basic::init_inert_zombies(); + flag_init( "whirlwind_active" ); + maps/mp/zombies/_zm_spawner::register_zombie_damage_callback( ::staff_air_zombie_damage_response ); + maps/mp/zombies/_zm_spawner::register_zombie_death_event_callback( ::staff_air_death_event ); +} + +precache() +{ + precacheitem( "staff_air_melee_zm" ); +} + +onplayerconnect() +{ + self thread onplayerspawned(); +} + +onplayerspawned() +{ + self endon( "disconnect" ); + self thread watch_staff_air_fired(); + self thread watch_staff_air_impact(); + self thread watch_staff_usage(); +} + +air_projectile_delete() +{ + self endon( "death" ); + wait 0,75; + self delete(); +} + +watch_staff_air_fired() +{ + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "missile_fire", e_projectile, str_weapon ); + if ( str_weapon == "staff_air_upgraded_zm" || str_weapon == "staff_air_zm" ) + { + e_projectile thread air_projectile_delete(); + wind_damage_cone( str_weapon ); + self setclientfield( "air_staff_source", 1 ); + wait_network_frame(); + self setclientfield( "air_staff_source", 0 ); + } + } +} + +watch_staff_air_impact() +{ + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "projectile_impact", str_weap_name, v_explode_point, n_radius, projectile ); + if ( str_weap_name == "staff_air_upgraded2_zm" || str_weap_name == "staff_air_upgraded3_zm" ) + { + self thread staff_air_find_source( v_explode_point, str_weap_name ); + } + } +} + +staff_air_find_source( v_detonate, str_weapon ) +{ + self endon( "disconnect" ); + if ( !isDefined( v_detonate ) ) + { + return; + } + a_zombies = getaiarray( level.zombie_team ); + a_zombies = get_array_of_closest( v_detonate, a_zombies ); + if ( a_zombies.size ) + { + i = 0; + while ( i < a_zombies.size ) + { + if ( isalive( a_zombies[ i ] ) ) + { + if ( is_true( a_zombies[ i ].staff_hit ) ) + { + i++; + continue; + } + else + { + if ( distance2dsquared( v_detonate, a_zombies[ i ].origin ) <= 10000 ) + { + self thread staff_air_zombie_source( a_zombies[ 0 ], str_weapon ); + } + else + { + self thread staff_air_position_source( v_detonate, str_weapon ); + } + return; + } + } + i++; + } + } + else self thread staff_air_position_source( v_detonate, str_weapon ); +} + +staff_air_zombie_source( ai_zombie, str_weapon ) +{ + self endon( "disconnect" ); + ai_zombie.staff_hit = 1; + ai_zombie.is_source = 1; + v_whirlwind_pos = ai_zombie.origin; + self thread staff_air_position_source( v_whirlwind_pos, str_weapon ); + if ( !isDefined( ai_zombie.is_mechz ) ) + { + self thread source_zombie_death( ai_zombie ); + } +} + +staff_air_position_source( v_detonate, str_weapon ) +{ + self endon( "disconnect" ); + if ( !isDefined( v_detonate ) ) + { + return; + } + if ( flag( "whirlwind_active" ) ) + { + level notify( "whirlwind_stopped" ); + while ( flag( "whirlwind_active" ) ) + { + wait_network_frame(); + } + wait 0,3; + } + flag_set( "whirlwind_active" ); + n_time = self.chargeshotlevel * 3,5; + e_whirlwind = spawn( "script_model", v_detonate + vectorScale( ( 0, 0, 0 ), 100 ) ); + e_whirlwind setmodel( "tag_origin" ); + e_whirlwind.angles = vectorScale( ( 0, 0, 0 ), 90 ); + e_whirlwind thread puzzle_debug_position( "X", vectorScale( ( 0, 0, 0 ), 255 ) ); + e_whirlwind moveto( groundpos_ignore_water_new( e_whirlwind.origin ), 0,05 ); + e_whirlwind waittill( "movedone" ); + e_whirlwind setclientfield( "whirlwind_play_fx", 1 ); + e_whirlwind thread whirlwind_rumble_nearby_players( "whirlwind_active" ); + e_whirlwind thread whirlwind_timeout( n_time ); + wait 0,5; + e_whirlwind.player_owner = self; + e_whirlwind thread whirlwind_seek_zombies( self.chargeshotlevel, str_weapon ); +} + +whirlwind_seek_zombies( n_level, str_weapon ) +{ + self endon( "death" ); + self.b_found_zombies = 0; + n_range = get_air_blast_range( n_level ); + while ( 1 ) + { + a_zombies = staff_air_zombie_range( self.origin, n_range ); + if ( a_zombies.size ) + { + self.b_found_zombies = 1; + self thread whirlwind_kill_zombies( n_level, str_weapon ); + return; + } + else + { + wait 0,1; + } + } +} + +whirlwind_timeout( n_time ) +{ + self endon( "death" ); + level waittill_any_or_timeout( n_time, "whirlwind_stopped" ); + level notify( "whirlwind_stopped" ); + self setclientfield( "whirlwind_play_fx", 0 ); + self notify( "stop_debug_position" ); + flag_clear( "whirlwind_active" ); + wait 1,5; + self delete(); +} + +move_along_ground_position( v_position, n_time ) +{ + v_diff = vectornormalize( v_position - self.origin ); + v_newpos = self.origin + ( v_diff * 50 ) + vectorScale( ( 0, 0, 0 ), 50 ); + v_ground = groundpos_ignore_water_new( v_newpos ); + self moveto( v_ground, n_time ); +} + +whirlwind_kill_zombies( n_level, str_weapon ) +{ + self endon( "death" ); + n_range = get_air_blast_range( n_level ); + self.n_charge_level = n_level; + while ( 1 ) + { + a_zombies = staff_air_zombie_range( self.origin, n_range ); + a_zombies = get_array_of_closest( self.origin, a_zombies ); + i = 0; + while ( i < a_zombies.size ) + { + if ( !isDefined( a_zombies[ i ] ) ) + { + i++; + continue; + } + else if ( a_zombies[ i ].ai_state != "find_flesh" ) + { + i++; + continue; + } + else if ( is_true( a_zombies[ i ].is_mechz ) ) + { + i++; + continue; + } + else if ( is_true( self._whirlwind_attract_anim ) ) + { + i++; + continue; + } + else v_offset = ( 10, 10, 32 ); + if ( !bullet_trace_throttled( self.origin + v_offset, a_zombies[ i ].origin + v_offset, undefined ) ) + { + i++; + continue; + } + else if ( !isDefined( a_zombies[ i ] ) || !isalive( a_zombies[ i ] ) ) + { + i++; + continue; + } + else + { + v_offset = ( -10, -10, 64 ); + if ( !bullet_trace_throttled( self.origin + v_offset, a_zombies[ i ].origin + v_offset, undefined ) ) + { + i++; + continue; + } + else if ( !isDefined( a_zombies[ i ] ) || !isalive( a_zombies[ i ] ) ) + { + i++; + continue; + } + else + { + a_zombies[ i ] thread whirlwind_drag_zombie( self, str_weapon ); + wait 0,5; + } + } + i++; + } + wait_network_frame(); + } +} + +whirlwind_drag_zombie( e_whirlwind, str_weapon ) +{ + if ( isDefined( self.e_linker ) ) + { + return; + } + self whirlwind_move_zombie( e_whirlwind ); + if ( isDefined( self ) && isDefined( e_whirlwind ) && flag( "whirlwind_active" ) ) + { + player = e_whirlwind.player_owner; + self do_damage_network_safe( player, self.health, str_weapon, "MOD_IMPACT" ); + level thread staff_air_gib( self ); + } +} + +whirlwind_move_zombie( e_whirlwind ) +{ + if ( isDefined( self.e_linker ) ) + { + return; + } + self.e_linker = spawn( "script_origin", ( 0, 0, 0 ) ); + self.e_linker.origin = self.origin; + self.e_linker.angles = self.angles; + self linkto( self.e_linker ); + self thread whirlwind_unlink( e_whirlwind ); + if ( isDefined( e_whirlwind ) ) + { + n_dist_sq = distance2dsquared( e_whirlwind.origin, self.origin ); + } + n_fling_range_sq = 900; + while ( isalive( self ) && n_dist_sq > n_fling_range_sq && isDefined( e_whirlwind ) && flag( "whirlwind_active" ) ) + { + n_dist_sq = distance2dsquared( e_whirlwind.origin, self.origin ); + if ( isDefined( self.ai_state ) && self.ai_state == "find_flesh" ) + { + b_supercharged = e_whirlwind.n_charge_level == 3; + self thread whirlwind_attract_anim( e_whirlwind.origin, b_supercharged ); + n_movetime = 1; + if ( b_supercharged ) + { + n_movetime = 0,8; + } + self.e_linker thread move_along_ground_position( e_whirlwind.origin, n_movetime ); + } + else + { + } + wait 0,05; + } + self notify( "reached_whirlwind" ); + self.e_linker delete(); +} + +whirlwind_unlink( e_whirlwind ) +{ + self endon( "death" ); + e_whirlwind waittill( "death" ); + self unlink(); +} + +source_zombie_death( ai_zombie ) +{ + self endon( "disconnect" ); + n_range = get_air_blast_range( self.chargeshotlevel ); + tag = "J_SpineUpper"; + if ( ai_zombie.isdog ) + { + tag = "J_Spine1"; + } + v_source = ai_zombie gettagorigin( tag ); + ai_zombie thread staff_air_fling_zombie( self ); + a_zombies = staff_air_zombie_range( v_source, n_range ); + if ( !isDefined( a_zombies ) ) + { + return; + } + self thread staff_air_proximity_kill( a_zombies ); +} + +get_air_blast_range( n_charge ) +{ + switch( n_charge ) + { + case 1: + n_range = 100; + break; + default: + n_range = 250; + break; + } + return n_range; +} + +staff_air_proximity_kill( a_zombies ) +{ + self endon( "disconnect" ); + if ( !isDefined( a_zombies ) ) + { + return; + } + i = 0; + while ( i < a_zombies.size ) + { + if ( isalive( a_zombies[ i ] ) ) + { + a_zombies[ i ] thread staff_air_fling_zombie( self ); + wait 0,05; + } + i++; + } +} + +staff_air_zombie_range( v_source, n_range ) +{ + a_enemies = []; + a_zombies = getaiarray( level.zombie_team ); + a_zombies = get_array_of_closest( v_source, a_zombies ); + n_range_sq = n_range * n_range; + while ( isDefined( a_zombies ) ) + { + i = 0; + while ( i < a_zombies.size ) + { + if ( !isDefined( a_zombies[ i ] ) ) + { + i++; + continue; + } + else v_zombie_pos = a_zombies[ i ].origin; + if ( isDefined( a_zombies[ i ].staff_hit ) && a_zombies[ i ].staff_hit == 1 ) + { + i++; + continue; + } + else + { + if ( distancesquared( v_source, v_zombie_pos ) > n_range_sq ) + { + i++; + continue; + } + else + { + a_enemies[ a_enemies.size ] = a_zombies[ i ]; + } + } + i++; + } + } + return a_enemies; +} + +staff_air_fling_zombie( player ) +{ + player endon( "disconnect" ); + if ( !isalive( self ) ) + { + return; + } + if ( isDefined( self.is_source ) || cointoss() ) + { + self thread zombie_launch( player, "staff_air_upgraded_zm" ); + } + else + { + self do_damage_network_safe( player, self.health, "staff_air_upgraded_zm", "MOD_IMPACT" ); + level thread staff_air_gib( self ); + } +} + +zombie_launch( e_attacker, str_weapon ) +{ + self do_damage_network_safe( e_attacker, self.health, str_weapon, "MOD_IMPACT" ); + if ( isDefined( level.ragdoll_limit_check ) && !( [[ level.ragdoll_limit_check ]]() ) ) + { + level thread staff_air_gib( self ); + } + else + { + self startragdoll(); + self setclientfield( "air_staff_launch", 1 ); + } +} + +determine_launch_vector( e_attacker, ai_target ) +{ + v_launch = ( vectornormalize( ai_target.origin - e_attacker.origin ) * randomintrange( 125, 150 ) ) + ( 0, 0, randomintrange( 75, 150 ) ); + return v_launch; +} + +staff_air_gib( ai_zombie ) +{ + if ( cointoss() ) + { + ai_zombie thread zombie_gib_all(); + } + ai_zombie thread zombie_gib_guts(); +} + +staff_air_zombie_damage_response( mod, hit_location, hit_origin, player, amount ) +{ + if ( self is_staff_air_damage() && mod != "MOD_MELEE" ) + { + self thread stun_zombie(); + return 1; + } + return 0; +} + +is_staff_air_damage() +{ + if ( isDefined( self.damageweapon ) && self.damageweapon != "staff_air_zm" && self.damageweapon == "staff_air_upgraded_zm" ) + { + return !is_true( self.set_beacon_damage ); + } +} + +staff_air_death_event() +{ + if ( is_staff_air_damage() && self.damagemod != "MOD_MELEE" ) + { + if ( is_true( self.is_mechz ) ) + { + return; + } + self thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( "death", self.animname ); + self thread zombie_eye_glow_stop(); + if ( isDefined( level.ragdoll_limit_check ) && !( [[ level.ragdoll_limit_check ]]() ) ) + { + level thread staff_air_gib( self ); + return; + } + else + { + self startragdoll(); + self setclientfield( "air_staff_launch", 1 ); + } + } +} + +wind_damage_cone( str_weapon ) +{ + fire_angles = self getplayerangles(); + fire_origin = self getplayercamerapos(); + a_targets = getaiarray( "axis" ); + a_targets = get_array_of_closest( self.origin, a_targets, undefined, 12, 400 ); + if ( str_weapon == "staff_air_upgraded_zm" ) + { + n_damage = 3300; + n_fov = 60; + } + else + { + n_damage = 2050; + n_fov = 45; + } + _a675 = a_targets; + _k675 = getFirstArrayKey( _a675 ); + while ( isDefined( _k675 ) ) + { + target = _a675[ _k675 ]; + if ( isai( target ) ) + { + if ( within_fov( fire_origin, fire_angles, target gettagorigin( "j_spine4" ), cos( n_fov ) ) ) + { + if ( self maps/mp/zombies/_zm_powerups::is_insta_kill_active() ) + { + n_damage = target.health; + } + target do_damage_network_safe( self, n_damage, str_weapon, "MOD_IMPACT" ); + } + } + _k675 = getNextArrayKey( _a675, _k675 ); + } +} + +stun_zombie() +{ + self endon( "death" ); + if ( is_true( self.is_mechz ) ) + { + return; + } + if ( is_true( self.is_electrocuted ) ) + { + return; + } + if ( !isDefined( self.ai_state ) || self.ai_state != "find_flesh" ) + { + return; + } + self.forcemovementscriptstate = 1; + self.ignoreall = 1; + self.is_electrocuted = 1; + tag = "J_SpineUpper"; + if ( self.isdog ) + { + tag = "J_Spine1"; + } + self animscripted( self.origin, self.angles, "zm_electric_stun" ); + self maps/mp/animscripts/shared::donotetracks( "stunned" ); + self.forcemovementscriptstate = 0; + self.ignoreall = 0; + self.is_electrocuted = 0; +} + +whirlwind_attract_anim_watch_cancel() +{ + self endon( "death" ); + while ( flag( "whirlwind_active" ) ) + { + wait_network_frame(); + } + self.deathanim = undefined; + self stopanimscripted(); + self._whirlwind_attract_anim = 0; +} + +whirlwind_attract_anim( v_attract_point, b_move_fast ) +{ + if ( !isDefined( b_move_fast ) ) + { + b_move_fast = 0; + } + self endon( "death" ); + level endon( "whirlwind_stopped" ); + if ( is_true( self._whirlwind_attract_anim ) ) + { + return; + } + v_angles_to_source = vectorToAngle( v_attract_point - self.origin ); + v_source_to_target = vectorToAngle( self.origin - v_attract_point ); + self.a.runblendtime = 0,9; + if ( self.has_legs ) + { + self.needs_run_update = 1; + self._had_legs = 1; + if ( b_move_fast ) + { + self animscripted( self.origin, v_source_to_target, "zm_move_whirlwind_fast" ); + } + else + { + self animscripted( self.origin, v_source_to_target, "zm_move_whirlwind" ); + } + } + else self.needs_run_update = 1; + self._had_legs = 0; + if ( b_move_fast ) + { + self animscripted( self.origin, v_source_to_target, "zm_move_whirlwind_crawl" ); + } + else + { + self animscripted( self.origin, v_source_to_target, "zm_move_whirlwind_fast_crawl" ); + } + if ( is_true( self.nogravity ) ) + { + self animmode( "none" ); + self.nogravity = undefined; + } + self._whirlwind_attract_anim = 1; + self.a.runblendtime = self._normal_run_blend_time; + self thread whirlwind_attract_anim_watch_cancel(); + self waittill( "reached_whirlwind" ); +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_weap_staff_fire.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_weap_staff_fire.gsc new file mode 100644 index 0000000..a01403f --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_weap_staff_fire.gsc @@ -0,0 +1,452 @@ +#include maps/mp/zombies/_zm_powerups; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/zombies/_zm_ai_basic; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_net; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + registerclientfield( "actor", "fire_char_fx", 14000, 1, "int" ); + registerclientfield( "toplayer", "fire_muzzle_fx", 14000, 1, "int" ); + onplayerconnect_callback( ::onplayerconnect ); + maps/mp/zombies/_zm_ai_basic::init_inert_zombies(); + maps/mp/zombies/_zm_spawner::register_zombie_damage_callback( ::staff_fire_zombie_damage_response ); + maps/mp/zombies/_zm_spawner::register_zombie_death_event_callback( ::staff_fire_death_event ); +} + +precache() +{ + precacheitem( "staff_fire_melee_zm" ); +} + +onplayerconnect() +{ + self thread onplayerspawned(); +} + +onplayerspawned() +{ + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "spawned_player" ); + self thread watch_staff_fire_upgrade_fired(); + self thread watch_staff_fire_fired(); + self thread watch_staff_usage(); + } +} + +watch_staff_fire_fired() +{ + self notify( "watch_staff_fired" ); + self endon( "disconnect" ); + self endon( "watch_staff_fired" ); + while ( 1 ) + { + self waittill( "missile_fire", e_projectile, str_weapon ); + while ( is_true( e_projectile.additional_shot ) ) + { + continue; + } + if ( str_weapon == "staff_fire_zm" || str_weapon == "staff_fire_upgraded_zm" ) + { + self fire_spread_shots( str_weapon ); + } + } +} + +watch_staff_fire_upgrade_fired() +{ + self notify( "watch_staff_upgrade_fired" ); + self endon( "disconnect" ); + self endon( "watch_staff_upgrade_fired" ); + while ( 1 ) + { + self waittill( "grenade_fire", e_projectile, str_weapon ); + while ( is_true( e_projectile.additional_shot ) ) + { + continue; + } + if ( str_weapon == "staff_fire_upgraded2_zm" || str_weapon == "staff_fire_upgraded3_zm" ) + { + e_projectile thread fire_staff_update_grenade_fuse(); + e_projectile thread fire_staff_area_of_effect( self, str_weapon ); + self fire_additional_shots( str_weapon ); + } + } +} + +fire_spread_shots( str_weapon ) +{ + wait_network_frame(); + wait_network_frame(); + v_fwd = self getweaponforwarddir(); + fire_angles = vectorToAngle( v_fwd ); + fire_origin = self getweaponmuzzlepoint(); + trace = bullettrace( fire_origin, fire_origin + ( v_fwd * 100 ), 0, undefined ); + if ( trace[ "fraction" ] != 1 ) + { + return; + } + v_left_angles = ( fire_angles[ 0 ], fire_angles[ 1 ] - 15, fire_angles[ 2 ] ); + v_left = anglesToForward( v_left_angles ); + e_proj = magicbullet( str_weapon, fire_origin + ( v_fwd * 50 ), fire_origin + ( v_left * 100 ), self ); + e_proj.additional_shot = 1; + wait_network_frame(); + wait_network_frame(); + v_fwd = self getweaponforwarddir(); + fire_angles = vectorToAngle( v_fwd ); + fire_origin = self getweaponmuzzlepoint(); + v_right_angles = ( fire_angles[ 0 ], fire_angles[ 1 ] + 15, fire_angles[ 2 ] ); + v_right = anglesToForward( v_right_angles ); + e_proj = magicbullet( str_weapon, fire_origin + ( v_fwd * 50 ), fire_origin + ( v_right * 100 ), self ); + e_proj.additional_shot = 1; +} + +fire_staff_area_of_effect( e_attacker, str_weapon ) +{ + self waittill( "explode", v_pos ); + ent = spawn( "script_origin", v_pos ); + ent playloopsound( "wpn_firestaff_grenade_loop", 1 ); +/# + level thread puzzle_debug_position( "X", vectorScale( ( 0, 0, 0 ), 255 ), v_pos, undefined, 5 ); +#/ + n_alive_time = 5; + aoe_radius = 80; + if ( str_weapon == "staff_fire_upgraded3_zm" ) + { + aoe_radius = 100; + } + n_step_size = 0,2; + while ( n_alive_time > 0 ) + { + if ( ( n_alive_time - n_step_size ) <= 0 ) + { + aoe_radius *= 2; + } + a_targets = getaiarray( "axis" ); + a_targets = get_array_of_closest( v_pos, a_targets, undefined, undefined, aoe_radius ); + wait n_step_size; + n_alive_time -= n_step_size; + _a213 = a_targets; + _k213 = getFirstArrayKey( _a213 ); + while ( isDefined( _k213 ) ) + { + e_target = _a213[ _k213 ]; + if ( isDefined( e_target ) && isalive( e_target ) ) + { + if ( !is_true( self.is_on_fire ) ) + { + e_target thread flame_damage_fx( str_weapon, e_attacker ); + } + } + _k213 = getNextArrayKey( _a213, _k213 ); + } + } + ent playsound( "wpn_firestaff_proj_impact" ); + ent delete(); +} + +grenade_waittill_still_or_bounce() +{ + self endon( "death" ); + self endon( "grenade_bounce" ); + wait 0,5; + prev_origin = self.origin; + wait_network_frame(); + wait_network_frame(); +} + +fire_staff_update_grenade_fuse() +{ + self endon( "death" ); + self grenade_waittill_still_or_bounce(); + self notify( "fire_aoe_start" ); + self resetmissiledetonationtime( 0 ); +} + +fire_additional_shots( str_weapon ) +{ + self endon( "disconnect" ); + self endon( "weapon_change" ); + n_shots = 1; + if ( str_weapon == "staff_fire_upgraded3_zm" ) + { + n_shots = 2; + } + i = 1; + while ( i <= n_shots ) + { + wait 0,35; + if ( isDefined( self ) && self getcurrentweapon() == "staff_fire_upgraded_zm" ) + { + v_player_angles = vectorToAngle( self getweaponforwarddir() ); + n_player_pitch = v_player_angles[ 0 ]; + n_player_pitch += 5 * i; + n_player_yaw = v_player_angles[ 1 ] + randomfloatrange( -15, 15 ); + v_shot_angles = ( n_player_pitch, n_player_yaw, v_player_angles[ 2 ] ); + v_shot_start = self getweaponmuzzlepoint(); + v_shot_end = v_shot_start + anglesToForward( v_shot_angles ); + e_proj = magicbullet( str_weapon, v_shot_start, v_shot_end, self ); + e_proj.additional_shot = 1; + e_proj thread fire_staff_update_grenade_fuse(); + e_proj thread fire_staff_area_of_effect( self, str_weapon ); + self setclientfieldtoplayer( "fire_muzzle_fx", 1 ); + wait_network_frame(); + self setclientfieldtoplayer( "fire_muzzle_fx", 0 ); + } + i++; + } +} + +staff_fire_zombie_damage_response( mod, hit_location, hit_origin, player, amount ) +{ + if ( self is_staff_fire_damage() && mod != "MOD_MELEE" ) + { + self thread staff_fire_zombie_hit_response_internal( mod, self.damageweapon, player, amount ); + return 1; + } + return 0; +} + +is_staff_fire_damage() +{ + if ( isDefined( self.damageweapon ) && self.damageweapon != "staff_fire_zm" && self.damageweapon != "staff_fire_upgraded_zm" && self.damageweapon != "staff_fire_upgraded2_zm" && self.damageweapon == "staff_fire_upgraded3_zm" ) + { + return !is_true( self.set_beacon_damage ); + } +} + +staff_fire_zombie_hit_response_internal( mod, damageweapon, player, amount ) +{ + player endon( "disconnect" ); + if ( !isalive( self ) ) + { + return; + } + if ( mod != "MOD_BURNED" && mod != "MOD_GRENADE_SPLASH" ) + { + pct_from_center = ( amount - 1 ) / 10; + pct_damage = 0,5 + ( 0,5 * pct_from_center ); + if ( is_true( self.is_mechz ) ) + { + self thread mechz_flame_damage( damageweapon, player, pct_damage ); + return; + } + self thread flame_damage_fx( damageweapon, player, pct_damage ); + } +} + +staff_fire_death_event() +{ + if ( is_staff_fire_damage() && self.damagemod != "MOD_MELEE" ) + { + self setclientfield( "fire_char_fx", 1 ); + self thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( "death", self.animname ); + self thread zombie_eye_glow_stop(); + } +} + +on_fire_timeout( n_duration ) +{ + self endon( "death" ); + wait n_duration; + self.is_on_fire = 0; + self notify( "stop_flame_damage" ); +} + +flame_damage_fx( damageweapon, e_attacker, pct_damage ) +{ + if ( !isDefined( pct_damage ) ) + { + pct_damage = 1; + } + was_on_fire = is_true( self.is_on_fire ); + n_initial_dmg = get_impact_damage( damageweapon ) * pct_damage; + if ( damageweapon != "staff_fire_upgraded_zm" && damageweapon != "staff_fire_upgraded2_zm" ) + { + is_upgraded = damageweapon == "staff_fire_upgraded3_zm"; + } + if ( is_upgraded && pct_damage > 0,5 && n_initial_dmg > self.health && cointoss() ) + { + self do_damage_network_safe( e_attacker, self.health, damageweapon, "MOD_BURNED" ); + if ( cointoss() ) + { + self thread zombie_gib_all(); + } + else + { + self thread zombie_gib_guts(); + } + return; + } + self endon( "death" ); + if ( !was_on_fire ) + { + self.is_on_fire = 1; + self thread zombie_set_and_restore_flame_state(); + wait 0,5; + self thread flame_damage_over_time( e_attacker, damageweapon, pct_damage ); + } + if ( n_initial_dmg > 0 ) + { + self do_damage_network_safe( e_attacker, n_initial_dmg, damageweapon, "MOD_BURNED" ); + } +} + +_fire_stun_zombie_internal( do_stun, run_cycle ) +{ + if ( !isalive( self ) ) + { + return; + } + if ( is_true( self.has_legs ) ) + { + self set_zombie_run_cycle( run_cycle ); + } + if ( do_stun ) + { + self animscripted( self.origin, self.angles, "zm_afterlife_stun" ); + } +} + +fire_stun_zombie_choked( do_stun, run_cycle ) +{ + maps/mp/zombies/_zm_net::network_safe_init( "fire_stun", 2 ); + self maps/mp/zombies/_zm_net::network_choke_action( "fire_stun", ::_fire_stun_zombie_internal, do_stun, run_cycle ); +} + +zombie_set_and_restore_flame_state() +{ + if ( !isalive( self ) ) + { + return; + } + if ( is_true( self.is_mechz ) ) + { + return; + } + self setclientfield( "fire_char_fx", 1 ); + self.disablemelee = 1; + prev_run_cycle = self.zombie_move_speed; + if ( is_true( self.has_legs ) ) + { + self.deathanim = "zm_death_fire"; + } + if ( self.ai_state == "find_flesh" ) + { + self fire_stun_zombie_choked( 1, "burned" ); + } + self waittill( "stop_flame_damage" ); + self.deathanim = undefined; + self.disablemelee = undefined; + if ( self.ai_state == "find_flesh" ) + { + self fire_stun_zombie_choked( 0, prev_run_cycle ); + } + self setclientfield( "fire_char_fx", 0 ); +} + +get_impact_damage( damageweapon ) +{ + switch( damageweapon ) + { + case "staff_fire_zm": + return 2050; + case "staff_fire_upgraded_zm": + return 3300; + case "staff_fire_upgraded2_zm": + return 11500; + case "staff_fire_upgraded3_zm": + return 20000; + case "one_inch_punch_fire_zm": + return 0; + default: + return 0; + } +} + +get_damage_per_second( damageweapon ) +{ + switch( damageweapon ) + { + case "staff_fire_zm": + return 75; + case "staff_fire_upgraded_zm": + return 150; + case "staff_fire_upgraded2_zm": + return 300; + case "staff_fire_upgraded3_zm": + return 450; + case "one_inch_punch_fire_zm": + return 250; + default: + return self.health; + } +} + +get_damage_duration( damageweapon ) +{ + switch( damageweapon ) + { + case "staff_fire_zm": + return 8; + case "staff_fire_upgraded_zm": + return 8; + case "staff_fire_upgraded2_zm": + return 8; + case "staff_fire_upgraded3_zm": + return 8; + case "one_inch_punch_fire_zm": + return 8; + default: + return 8; + } +} + +flame_damage_over_time( e_attacker, damageweapon, pct_damage ) +{ + e_attacker endon( "disconnect" ); + self endon( "death" ); + self endon( "stop_flame_damage" ); + n_damage = get_damage_per_second( damageweapon ); + n_duration = get_damage_duration( damageweapon ); + n_damage *= pct_damage; + self thread on_fire_timeout( n_duration ); + while ( 1 ) + { + if ( isDefined( e_attacker ) && isplayer( e_attacker ) ) + { + if ( e_attacker maps/mp/zombies/_zm_powerups::is_insta_kill_active() ) + { + n_damage = self.health; + } + } + self do_damage_network_safe( e_attacker, n_damage, damageweapon, "MOD_BURNED" ); + wait 1; + } +} + +mechz_flame_damage( damageweapon, e_attacker, pct_damage ) +{ + self endon( "death" ); + n_initial_dmg = get_impact_damage( damageweapon ); + if ( n_initial_dmg > 0 ) + { + self do_damage_network_safe( e_attacker, n_initial_dmg, damageweapon, "MOD_BURNED" ); + } +} + +stop_zombie() +{ + e_linker = spawn( "script_origin", ( 0, 0, 0 ) ); + e_linker.origin = self.origin; + e_linker.angles = self.angles; + self linkto( e_linker ); + self waittill( "death" ); + e_linker delete(); +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_weap_staff_lightning.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_weap_staff_lightning.gsc new file mode 100644 index 0000000..f5ae142 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_weap_staff_lightning.gsc @@ -0,0 +1,444 @@ +#include maps/mp/animscripts/shared; +#include maps/mp/zombies/_zm_score; +#include maps/mp/zombies/_zm_powerups; +#include maps/mp/zombies/_zm_audio; +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_net; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + level._effect[ "lightning_miss" ] = loadfx( "weapon/zmb_staff/fx_zmb_staff_elec_ug_impact_miss" ); + level._effect[ "lightning_arc" ] = loadfx( "weapon/zmb_staff/fx_zmb_staff_elec_trail_bolt_cheap" ); + level._effect[ "lightning_impact" ] = loadfx( "weapon/zmb_staff/fx_zmb_staff_elec_ug_impact_hit_torso" ); + level._effect[ "tesla_shock_eyes" ] = loadfx( "maps/zombie/fx_zombie_tesla_shock_eyes" ); + registerclientfield( "actor", "lightning_impact_fx", 14000, 1, "int" ); + registerclientfield( "scriptmover", "lightning_miss_fx", 14000, 1, "int" ); + registerclientfield( "actor", "lightning_arc_fx", 14000, 1, "int" ); + set_zombie_var( "tesla_head_gib_chance", 50 ); + onplayerconnect_callback( ::onplayerconnect ); + maps/mp/zombies/_zm_spawner::register_zombie_damage_callback( ::staff_lightning_zombie_damage_response ); + maps/mp/zombies/_zm_spawner::register_zombie_death_event_callback( ::staff_lightning_death_event ); +} + +precache() +{ + precacheitem( "staff_lightning_melee_zm" ); +} + +onplayerconnect() +{ + self thread onplayerspawned(); +} + +onplayerspawned() +{ + self endon( "disconnect" ); + self thread watch_staff_lightning_fired(); + self thread watch_staff_usage(); +} + +watch_staff_lightning_fired() +{ + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "missile_fire", e_projectile, str_weapon ); + if ( str_weapon == "staff_lightning_upgraded2_zm" || str_weapon == "staff_lightning_upgraded3_zm" ) + { + fire_angles = vectorToAngle( self getweaponforwarddir() ); + fire_origin = self getweaponmuzzlepoint(); + self thread staff_lightning_position_source( fire_origin, fire_angles, str_weapon ); + } + } +} + +lightning_ball_wait( n_lifetime_after_move ) +{ + level endon( "lightning_ball_created" ); + self waittill( "movedone" ); + wait n_lifetime_after_move; + return 1; +} + +staff_lightning_position_source( v_detonate, v_angles, str_weapon ) +{ + self endon( "disconnect" ); + level notify( "lightning_ball_created" ); + if ( !isDefined( v_angles ) ) + { + v_angles = ( 0, 0, 1 ); + } + e_ball_fx = spawn( "script_model", v_detonate + ( anglesToForward( v_angles ) * 100 ) ); + e_ball_fx.angles = v_angles; + e_ball_fx.str_weapon = str_weapon; + e_ball_fx setmodel( "tag_origin" ); + e_ball_fx.n_range = get_lightning_blast_range( self.chargeshotlevel ); + e_ball_fx.n_damage_per_sec = get_lightning_ball_damage_per_sec( self.chargeshotlevel ); + e_ball_fx setclientfield( "lightning_miss_fx", 1 ); + n_shot_range = staff_lightning_get_shot_range( self.chargeshotlevel ); + v_end = v_detonate + ( anglesToForward( v_angles ) * n_shot_range ); + trace = bullettrace( v_detonate, v_end, 0, undefined ); + if ( trace[ "fraction" ] != 1 ) + { + v_end = trace[ "position" ]; + } + staff_lightning_ball_speed = n_shot_range / 8; + n_dist = distance( e_ball_fx.origin, v_end ); + n_max_movetime_s = n_shot_range / staff_lightning_ball_speed; + n_movetime_s = n_dist / staff_lightning_ball_speed; + n_leftover_time = n_max_movetime_s - n_movetime_s; + e_ball_fx thread staff_lightning_ball_kill_zombies( self ); +/# + e_ball_fx thread puzzle_debug_position( "X", ( 175, 0, 255 ) ); +#/ + e_ball_fx moveto( v_end, n_movetime_s ); + finished_playing = e_ball_fx lightning_ball_wait( n_leftover_time ); + e_ball_fx notify( "stop_killing" ); + e_ball_fx notify( "stop_debug_position" ); + if ( is_true( finished_playing ) ) + { + wait 3; + } + if ( isDefined( e_ball_fx ) ) + { + e_ball_fx delete(); + } +} + +staff_lightning_ball_kill_zombies( e_attacker ) +{ + self endon( "death" ); + self endon( "stop_killing" ); + while ( 1 ) + { + a_zombies = staff_lightning_get_valid_targets( e_attacker, self.origin ); + while ( isDefined( a_zombies ) ) + { + _a173 = a_zombies; + _k173 = getFirstArrayKey( _a173 ); + while ( isDefined( _k173 ) ) + { + zombie = _a173[ _k173 ]; + if ( staff_lightning_is_target_valid( zombie ) ) + { + e_attacker thread staff_lightning_arc_fx( self, zombie ); + wait 0,2; + } + _k173 = getNextArrayKey( _a173, _k173 ); + } + } + wait 0,5; + } +} + +staff_lightning_get_valid_targets( player, v_source ) +{ + player endon( "disconnect" ); + a_enemies = []; + a_zombies = getaiarray( level.zombie_team ); + a_zombies = get_array_of_closest( v_source, a_zombies, undefined, undefined, self.n_range ); + while ( isDefined( a_zombies ) ) + { + _a200 = a_zombies; + _k200 = getFirstArrayKey( _a200 ); + while ( isDefined( _k200 ) ) + { + ai_zombie = _a200[ _k200 ]; + if ( staff_lightning_is_target_valid( ai_zombie ) ) + { + a_enemies[ a_enemies.size ] = ai_zombie; + } + _k200 = getNextArrayKey( _a200, _k200 ); + } + } + return a_enemies; +} + +staff_lightning_get_shot_range( n_charge ) +{ + switch( n_charge ) + { + case 3: + return 1200; + default: + return 800; + } +} + +get_lightning_blast_range( n_charge ) +{ + switch( n_charge ) + { + case 1: + n_range = 200; + break; + case 2: + n_range = 150; + break; + case 3: + default: + n_range = 250; + break; + } + return n_range; +} + +get_lightning_ball_damage_per_sec( n_charge ) +{ + if ( !isDefined( n_charge ) ) + { + return 2500; + } + switch( n_charge ) + { + case 3: + return 3500; + default: + return 2500; + } +} + +staff_lightning_is_target_valid( ai_zombie ) +{ + if ( !isDefined( ai_zombie ) ) + { + return 0; + } + if ( is_true( ai_zombie.is_being_zapped ) ) + { + return 0; + } + if ( is_true( ai_zombie.is_mechz ) ) + { + return 0; + } + return 1; +} + +staff_lightning_ball_damage_over_time( e_source, e_target, e_attacker ) +{ + e_attacker endon( "disconnect" ); + e_target setclientfield( "lightning_impact_fx", 1 ); + e_target thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( "electrocute", e_target.animname ); + n_range_sq = e_source.n_range * e_source.n_range; + e_target.is_being_zapped = 1; + e_target setclientfield( "lightning_arc_fx", 1 ); + wait 0,5; + if ( isDefined( e_source ) ) + { + if ( !isDefined( e_source.n_damage_per_sec ) ) + { + e_source.n_damage_per_sec = get_lightning_ball_damage_per_sec( e_attacker.chargeshotlevel ); + } + n_damage_per_pulse = e_source.n_damage_per_sec * 1; + } + while ( isDefined( e_source ) && isalive( e_target ) ) + { + e_target thread stun_zombie(); + wait 1; + if ( !isDefined( e_source ) || !isalive( e_target ) ) + { + } + else + { + n_dist_sq = distancesquared( e_source.origin, e_target.origin ); + if ( n_dist_sq > n_range_sq ) + { + } + else if ( isalive( e_target ) && isDefined( e_source ) ) + { + instakill_on = e_attacker maps/mp/zombies/_zm_powerups::is_insta_kill_active(); + if ( n_damage_per_pulse < e_target.health && !instakill_on ) + { + e_target do_damage_network_safe( e_attacker, n_damage_per_pulse, e_source.str_weapon, "MOD_RIFLE_BULLET" ); + } + else + { + e_target thread zombie_shock_eyes(); + e_target thread staff_lightning_kill_zombie( e_attacker, e_source.str_weapon ); + } + } + else + { + } + } + } + if ( isDefined( e_target ) ) + { + e_target.is_being_zapped = 0; + e_target setclientfield( "lightning_arc_fx", 0 ); + } +} + +staff_lightning_arc_fx( e_source, ai_zombie ) +{ + self endon( "disconnect" ); + if ( !isDefined( ai_zombie ) ) + { + return; + } + if ( !bullet_trace_throttled( e_source.origin, ai_zombie.origin + vectorScale( ( 0, 0, 1 ), 20 ), ai_zombie ) ) + { + return; + } + if ( isDefined( e_source ) && isDefined( ai_zombie ) && isalive( ai_zombie ) ) + { + level thread staff_lightning_ball_damage_over_time( e_source, ai_zombie, self ); + } +} + +staff_lightning_kill_zombie( player, str_weapon ) +{ + player endon( "disconnect" ); + if ( !isalive( self ) ) + { + return; + } + if ( is_true( self.has_legs ) ) + { + if ( !self hasanimstatefromasd( "zm_death_tesla" ) ) + { + return; + } + self.deathanim = "zm_death_tesla"; + } + else + { + if ( !self hasanimstatefromasd( "zm_death_tesla_crawl" ) ) + { + return; + } + self.deathanim = "zm_death_tesla_crawl"; + } + if ( is_true( self.is_traversing ) ) + { + self.deathanim = undefined; + } + self do_damage_network_safe( player, self.health, str_weapon, "MOD_RIFLE_BULLET" ); + player maps/mp/zombies/_zm_score::player_add_points( "death", "", "" ); +} + +staff_lightning_death_fx() +{ + if ( isDefined( self ) ) + { + self setclientfield( "lightning_impact_fx", 1 ); + self thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( "electrocute", self.animname ); + self thread zombie_shock_eyes(); + } +} + +zombie_shock_eyes_network_safe( fx, entity, tag ) +{ + if ( network_entity_valid( entity ) ) + { + if ( !is_true( self.head_gibbed ) ) + { + playfxontag( fx, entity, tag ); + } + } +} + +zombie_shock_eyes() +{ + if ( isDefined( self.head_gibbed ) && self.head_gibbed ) + { + return; + } + maps/mp/zombies/_zm_net::network_safe_init( "shock_eyes", 2 ); + maps/mp/zombies/_zm_net::network_choke_action( "shock_eyes", ::zombie_shock_eyes_network_safe, level._effect[ "tesla_shock_eyes" ], self, "J_Eyeball_LE" ); +} + +staff_lightning_zombie_damage_response( mod, hit_location, hit_origin, player, amount ) +{ + if ( self is_staff_lightning_damage() && self.damagemod != "MOD_RIFLE_BULLET" ) + { + self thread stun_zombie(); + } + return 0; +} + +is_staff_lightning_damage() +{ + if ( isDefined( self.damageweapon ) && self.damageweapon != "staff_lightning_zm" && self.damageweapon == "staff_lightning_upgraded_zm" ) + { + return !is_true( self.set_beacon_damage ); + } +} + +staff_lightning_death_event() +{ + if ( is_staff_lightning_damage() && self.damagemod != "MOD_MELEE" ) + { + if ( is_true( self.is_mechz ) ) + { + return; + } + self thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( "death", self.animname ); + self thread zombie_eye_glow_stop(); + if ( is_true( self.has_legs ) ) + { + if ( !self hasanimstatefromasd( "zm_death_tesla" ) ) + { + return; + } + self.deathanim = "zm_death_tesla"; + } + else + { + if ( !self hasanimstatefromasd( "zm_death_tesla_crawl" ) ) + { + return; + } + self.deathanim = "zm_death_tesla_crawl"; + } + if ( is_true( self.is_traversing ) ) + { + self.deathanim = undefined; + } + tag = "J_SpineUpper"; + self setclientfield( "lightning_impact_fx", 1 ); + self thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( "electrocute", self.animname ); + self thread zombie_shock_eyes(); + if ( isDefined( self.deathanim ) ) + { + self waittillmatch( "death_anim" ); + return "die"; + } + self do_damage_network_safe( self.attacker, self.health, self.damageweapon, "MOD_RIFLE_BULLET" ); + } +} + +stun_zombie() +{ + self endon( "death" ); + if ( is_true( self.is_mechz ) ) + { + return; + } + if ( is_true( self.is_electrocuted ) ) + { + return; + } + if ( !isDefined( self.ai_state ) || self.ai_state != "find_flesh" ) + { + return; + } + self.forcemovementscriptstate = 1; + self.ignoreall = 1; + self.is_electrocuted = 1; + tag = "J_SpineUpper"; + network_safe_play_fx_on_tag( "lightning_impact", 2, level._effect[ "lightning_impact" ], self, tag ); + if ( is_true( self.has_legs ) ) + { + self animscripted( self.origin, self.angles, "zm_electric_stun" ); + } + self maps/mp/animscripts/shared::donotetracks( "stunned" ); + self.forcemovementscriptstate = 0; + self.ignoreall = 0; + self.is_electrocuted = 0; +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_weap_staff_revive.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_weap_staff_revive.gsc new file mode 100644 index 0000000..237857b --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_weap_staff_revive.gsc @@ -0,0 +1,74 @@ +#include maps/mp/zombies/_zm_laststand; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_net; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + onplayerconnect_callback( ::onplayerconnect ); +} + +onplayerconnect() +{ + self thread onplayerspawned(); +} + +onplayerspawned() +{ + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "spawned_player" ); + self thread watch_staff_revive_fired(); + } +} + +watch_staff_revive_fired() +{ + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "missile_fire", e_projectile, str_weapon ); + while ( str_weapon != "staff_revive_zm" ) + { + continue; + } + self waittill( "projectile_impact", e_ent, v_explode_point, n_radius, str_name, n_impact ); + self thread staff_revive_impact( v_explode_point ); + } +} + +staff_revive_impact( v_explode_point ) +{ + self endon( "disconnect" ); + e_closest_player = undefined; + n_closest_dist_sq = 1024; + playsoundatposition( "wpn_revivestaff_proj_impact", v_explode_point ); + a_e_players = getplayers(); + _a70 = a_e_players; + _k70 = getFirstArrayKey( _a70 ); + while ( isDefined( _k70 ) ) + { + e_player = _a70[ _k70 ]; + if ( e_player == self || !e_player maps/mp/zombies/_zm_laststand::player_is_in_laststand() ) + { + } + else + { + n_dist_sq = distancesquared( v_explode_point, e_player.origin ); + if ( n_dist_sq < n_closest_dist_sq ) + { + e_closest_player = e_player; + } + } + _k70 = getNextArrayKey( _a70, _k70 ); + } + if ( isDefined( e_closest_player ) ) + { + e_closest_player notify( "remote_revive" ); + e_closest_player playsoundtoplayer( "wpn_revivestaff_revive_plr", e_player ); + self notify( "revived_player_with_upgraded_staff" ); + } +} diff --git a/zm_tomb_patch/maps/mp/zombies/_zm_weap_staff_water.gsc b/zm_tomb_patch/maps/mp/zombies/_zm_weap_staff_water.gsc new file mode 100644 index 0000000..1b60c18 --- /dev/null +++ b/zm_tomb_patch/maps/mp/zombies/_zm_weap_staff_water.gsc @@ -0,0 +1,545 @@ +#include maps/mp/zombies/_zm_powerups; +#include maps/mp/zombies/_zm_score; +#include maps/mp/zombies/_zm_spawner; +#include maps/mp/zm_tomb_utility; +#include maps/mp/zombies/_zm_net; +#include maps/mp/zombies/_zm_utility; +#include maps/mp/_utility; +#include common_scripts/utility; + +init() +{ + level._effect[ "staff_water_blizzard" ] = loadfx( "weapon/zmb_staff/fx_zmb_staff_ice_ug_impact_hit" ); + level._effect[ "staff_water_ice_shard" ] = loadfx( "weapon/zmb_staff/fx_zmb_staff_ice_trail_bolt" ); + level._effect[ "staff_water_shatter" ] = loadfx( "weapon/zmb_staff/fx_zmb_staff_ice_exp" ); + registerclientfield( "scriptmover", "staff_blizzard_fx", 14000, 1, "int" ); + registerclientfield( "actor", "anim_rate", 14000, 2, "float" ); + registerclientfield( "actor", "attach_bullet_model", 14000, 1, "int" ); + onplayerconnect_callback( ::onplayerconnect ); + precacheitem( "staff_water_fake_dart_zm" ); + precacheitem( "staff_water_dart_zm" ); + flag_init( "blizzard_active" ); + init_tag_array(); + level thread water_dart_cleanup(); + maps/mp/zombies/_zm_spawner::register_zombie_death_event_callback( ::staff_water_death_event ); + maps/mp/zombies/_zm_spawner::add_cusom_zombie_spawn_logic( ::staff_water_on_zombie_spawned ); +} + +precache() +{ + precacheitem( "staff_water_melee_zm" ); +} + +init_tag_array() +{ + level.zombie_water_icicle_tag = []; + level.zombie_water_icicle_tag[ 0 ] = "j_hip_le"; + level.zombie_water_icicle_tag[ 1 ] = "j_hip_ri"; + level.zombie_water_icicle_tag[ 2 ] = "j_spine4"; + level.zombie_water_icicle_tag[ 3 ] = "j_elbow_le"; + level.zombie_water_icicle_tag[ 4 ] = "j_elbow_ri"; + level.zombie_water_icicle_tag[ 5 ] = "j_clavicle_le"; + level.zombie_water_icicle_tag[ 6 ] = "j_clavicle_ri"; +} + +water_dart_cleanup() +{ + while ( 1 ) + { + a_grenades = getentarray( "grenade", "classname" ); + _a73 = a_grenades; + _k73 = getFirstArrayKey( _a73 ); + while ( isDefined( _k73 ) ) + { + e_grenade = _a73[ _k73 ]; + if ( isDefined( e_grenade.model ) && e_grenade.model == "p6_zm_tm_staff_projectile_ice" ) + { + time = getTime(); + if ( ( time - e_grenade.birthtime ) >= 1000 ) + { + e_grenade delete(); + } + } + _k73 = getNextArrayKey( _a73, _k73 ); + } + wait 0,1; + } +} + +onplayerconnect() +{ + self thread onplayerspawned(); +} + +onplayerspawned() +{ + self endon( "disconnect" ); + self thread watch_staff_water_fired(); + self thread watch_staff_water_impact(); + self thread watch_staff_usage(); +} + +watch_staff_water_fired() +{ + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "missile_fire", e_projectile, str_weapon ); + if ( str_weapon == "staff_water_zm" || str_weapon == "staff_water_upgraded_zm" ) + { + wait_network_frame(); + _icicle_locate_target( str_weapon ); + wait_network_frame(); + _icicle_locate_target( str_weapon ); + wait_network_frame(); + _icicle_locate_target( str_weapon ); + } + } +} + +watch_staff_water_impact() +{ + self endon( "disconnect" ); + while ( 1 ) + { + self waittill( "projectile_impact", str_weapon, v_explode_point, n_radius, str_name, n_impact ); + if ( str_weapon == "staff_water_upgraded2_zm" || str_weapon == "staff_water_upgraded3_zm" ) + { + n_lifetime = 6; + if ( str_weapon == "staff_water_upgraded3_zm" ) + { + n_lifetime = 9; + } + self thread staff_water_position_source( v_explode_point, n_lifetime, str_weapon ); + } + } +} + +staff_water_kill_zombie( player, str_weapon ) +{ + self freeze_zombie(); + self do_damage_network_safe( player, self.health, str_weapon, "MOD_RIFLE_BULLET" ); + if ( isDefined( self.deathanim ) ) + { + self waittillmatch( "death_anim" ); + return "shatter"; + } + if ( isDefined( self ) ) + { + self thread frozen_zombie_shatter(); + } + player maps/mp/zombies/_zm_score::player_add_points( "death", "", "" ); +} + +freeze_zombie() +{ + if ( is_true( self.is_mechz ) ) + { + return; + } + if ( !self.isdog ) + { + if ( self.has_legs ) + { + if ( !self hasanimstatefromasd( "zm_death_freeze" ) ) + { + return; + } + self.deathanim = "zm_death_freeze"; + } + else + { + if ( !self hasanimstatefromasd( "zm_death_freeze_crawl" ) ) + { + return; + } + self.deathanim = "zm_death_freeze_crawl"; + } + } + else + { + self.a.nodeath = undefined; + } + if ( is_true( self.is_traversing ) ) + { + self.deathanim = undefined; + } +} + +_network_safe_play_fx( fx, v_origin ) +{ + playfx( fx, v_origin, ( 0, 0, 1 ), ( 0, 0, 1 ) ); +} + +network_safe_play_fx( id, max, fx, v_origin ) +{ + network_safe_init( id, max ); + network_choke_action( id, ::_network_safe_play_fx, fx, v_origin ); +} + +frozen_zombie_shatter() +{ + if ( is_true( self.is_mechz ) ) + { + return; + } + if ( isDefined( self ) ) + { + if ( is_mature() ) + { + v_fx = self gettagorigin( "J_SpineLower" ); + level thread network_safe_play_fx( "frozen_shatter", 2, level._effect[ "staff_water_shatter" ], v_fx ); + self thread frozen_zombie_gib( "normal" ); + return; + } + else + { + self startragdoll(); + } + } +} + +frozen_zombie_gib( gib_type ) +{ + gibarray = []; + gibarray[ gibarray.size ] = level._zombie_gib_piece_index_all; + self gib( gib_type, gibarray ); + self ghost(); + wait 0,4; + if ( isDefined( self ) ) + { + self self_delete(); + } +} + +staff_water_position_source( v_detonate, n_lifetime_sec, str_weapon ) +{ + self endon( "disconnect" ); + if ( isDefined( v_detonate ) ) + { + level notify( "blizzard_shot" ); + e_fx = spawn( "script_model", v_detonate + vectorScale( ( 0, 0, 1 ), 33 ) ); + e_fx setmodel( "tag_origin" ); + e_fx setclientfield( "staff_blizzard_fx", 1 ); + e_fx thread puzzle_debug_position( "X", ( 0, 64, 255 ) ); + wait 1; + flag_set( "blizzard_active" ); + e_fx thread ice_staff_blizzard_do_kills( self, str_weapon ); + e_fx thread whirlwind_rumble_nearby_players( "blizzard_active" ); + e_fx thread ice_staff_blizzard_timeout( n_lifetime_sec ); + e_fx thread ice_staff_blizzard_off(); + e_fx waittill( "blizzard_off" ); + flag_clear( "blizzard_active" ); + e_fx notify( "stop_debug_position" ); + wait 0,1; + e_fx setclientfield( "staff_blizzard_fx", 0 ); + wait 0,1; + e_fx delete(); + } +} + +ice_staff_blizzard_do_kills( player, str_weapon ) +{ + player endon( "disconnect" ); + self endon( "blizzard_off" ); + while ( 1 ) + { + a_zombies = getaiarray( level.zombie_team ); + _a317 = a_zombies; + _k317 = getFirstArrayKey( _a317 ); + while ( isDefined( _k317 ) ) + { + zombie = _a317[ _k317 ]; + if ( !is_true( zombie.is_on_ice ) ) + { + if ( distancesquared( self.origin, zombie.origin ) <= 30625 ) + { + if ( is_true( zombie.is_mechz ) ) + { + zombie thread ice_affect_mechz( player, 1 ); + break; + } + else + { + if ( isalive( zombie ) ) + { + zombie thread ice_affect_zombie( str_weapon, player, 1 ); + } + } + } + } + _k317 = getNextArrayKey( _a317, _k317 ); + } + wait 0,1; + } +} + +ice_staff_blizzard_timeout( n_time ) +{ + self endon( "death" ); + self endon( "blizzard_off" ); + wait n_time; + self notify( "blizzard_off" ); +} + +ice_staff_blizzard_off() +{ + self endon( "death" ); + self endon( "blizzard_off" ); + level waittill( "blizzard_shot" ); + self notify( "blizzard_off" ); +} + +get_ice_blast_range( n_charge ) +{ + switch( n_charge ) + { + case 0: + case 1: + n_range = 250000; + break; + case 2: + n_range = 640000; + break; + case 3: + n_range = 1000000; + break; + } + return n_range; +} + +staff_water_zombie_range( v_source, n_range ) +{ + a_enemies = []; + a_zombies = getaiarray( level.zombie_team ); + a_zombies = get_array_of_closest( v_source, a_zombies ); + while ( isDefined( a_zombies ) ) + { + i = 0; + while ( i < a_zombies.size ) + { + if ( !isDefined( a_zombies[ i ] ) ) + { + i++; + continue; + } + else v_zombie_pos = a_zombies[ i ] gettagorigin( "j_head" ); + if ( distancesquared( v_source, v_zombie_pos ) > n_range ) + { + i++; + continue; + } + else if ( !bullet_trace_throttled( v_source, v_zombie_pos, undefined ) ) + { + i++; + continue; + } + else + { + if ( isDefined( a_zombies[ i ] ) && isalive( a_zombies[ i ] ) ) + { + a_enemies[ a_enemies.size ] = a_zombies[ i ]; + } + } + i++; + } + } + return a_enemies; +} + +is_staff_water_damage() +{ + if ( isDefined( self.damageweapon ) && self.damageweapon != "staff_water_zm" && self.damageweapon != "staff_water_upgraded_zm" && self.damageweapon == "staff_water_fake_dart_zm" ) + { + return !is_true( self.set_beacon_damage ); + } +} + +ice_affect_mechz( e_player, is_upgraded ) +{ + if ( is_true( self.is_on_ice ) ) + { + return; + } + self.is_on_ice = 1; + if ( is_upgraded ) + { + self do_damage_network_safe( e_player, 3300, "staff_water_upgraded_zm", "MOD_RIFLE_BULLET" ); + } + else + { + self do_damage_network_safe( e_player, 2050, "staff_water_zm", "MOD_RIFLE_BULLET" ); + } + wait 1; + self.is_on_ice = 0; +} + +ice_affect_zombie( str_weapon, e_player, always_kill, n_mod ) +{ + if ( !isDefined( str_weapon ) ) + { + str_weapon = "staff_water_zm"; + } + if ( !isDefined( always_kill ) ) + { + always_kill = 0; + } + if ( !isDefined( n_mod ) ) + { + n_mod = 1; + } + self endon( "death" ); + instakill_on = e_player maps/mp/zombies/_zm_powerups::is_insta_kill_active(); + if ( str_weapon == "staff_water_zm" ) + { + n_damage = 2050; + } + else if ( str_weapon != "staff_water_upgraded_zm" || str_weapon == "staff_water_upgraded2_zm" && str_weapon == "staff_water_upgraded3_zm" ) + { + n_damage = 3300; + } + else + { + if ( str_weapon == "one_inch_punch_ice_zm" ) + { + n_damage = 11275; + } + } + if ( is_true( self.is_on_ice ) ) + { + return; + } + self.is_on_ice = 1; + self setclientfield( "attach_bullet_model", 1 ); + n_speed = 0,3; + self set_anim_rate( 0,3 ); + if ( instakill_on || always_kill ) + { + wait randomfloatrange( 0,5, 0,7 ); + } + else + { + wait randomfloatrange( 1,8, 2,3 ); + } + if ( n_damage >= self.health || instakill_on && always_kill ) + { + self set_anim_rate( 1 ); + wait_network_frame(); + if ( str_weapon != "one_inch_punch_ice_zm" ) + { + staff_water_kill_zombie( e_player, str_weapon ); + } + } + else + { + self do_damage_network_safe( e_player, n_damage, str_weapon, "MOD_RIFLE_BULLET" ); + self.deathanim = undefined; + self setclientfield( "attach_bullet_model", 0 ); + wait 0,5; + self set_anim_rate( 1 ); + self.is_on_ice = 0; + } +} + +set_anim_rate( n_speed ) +{ + self setclientfield( "anim_rate", n_speed ); + n_rate = self getclientfield( "anim_rate" ); + self setentityanimrate( n_rate ); + if ( n_speed != 1 ) + { + self.preserve_asd_substates = 1; + } + wait_network_frame(); + if ( !is_true( self.is_traversing ) ) + { + self.needs_run_update = 1; + self notify( "needs_run_update" ); + } + wait_network_frame(); + if ( n_speed == 1 ) + { + self.preserve_asd_substates = 0; + } +} + +staff_water_on_zombie_spawned() +{ + self setclientfield( "anim_rate", 1 ); + n_rate = self getclientfield( "anim_rate" ); + self setentityanimrate( n_rate ); +} + +staff_water_death_event() +{ + if ( is_staff_water_damage() && self.damagemod != "MOD_MELEE" ) + { + self.no_gib = 1; + self.nodeathragdoll = 1; + self freeze_zombie(); + if ( isDefined( self.deathanim ) ) + { + self waittillmatch( "death_anim" ); + return "shatter"; + } + self thread frozen_zombie_shatter(); + } +} + +_icicle_locate_target( str_weapon ) +{ + is_upgraded = str_weapon == "staff_water_upgraded_zm"; + fire_angles = self getplayerangles(); + fire_origin = self getplayercamerapos(); + a_targets = getaiarray( "axis" ); + a_targets = get_array_of_closest( self.origin, a_targets, undefined, undefined, 600 ); + _a592 = a_targets; + _k592 = getFirstArrayKey( _a592 ); + while ( isDefined( _k592 ) ) + { + target = _a592[ _k592 ]; + if ( is_true( target.is_on_ice ) ) + { + } + else + { + if ( within_fov( fire_origin, fire_angles, target gettagorigin( "j_spine4" ), cos( 25 ) ) ) + { + if ( isai( target ) ) + { + a_tags = []; + a_tags[ 0 ] = "j_hip_le"; + a_tags[ 1 ] = "j_hip_ri"; + a_tags[ 2 ] = "j_spine4"; + a_tags[ 3 ] = "j_elbow_le"; + a_tags[ 4 ] = "j_elbow_ri"; + a_tags[ 5 ] = "j_clavicle_le"; + a_tags[ 6 ] = "j_clavicle_ri"; + str_tag = a_tags[ randomint( a_tags.size ) ]; + b_trace_pass = bullet_trace_throttled( fire_origin, target gettagorigin( str_tag ), target ); + if ( b_trace_pass && isDefined( target ) && isalive( target ) ) + { + if ( is_true( target.is_mechz ) ) + { + target thread ice_affect_mechz( self, is_upgraded ); + } + else + { + target thread ice_affect_zombie( str_weapon, self ); + } + return; + } + } + } + } + _k592 = getNextArrayKey( _a592, _k592 ); + } +} + +_icicle_get_spread( n_spread ) +{ + n_x = randomintrange( n_spread * -1, n_spread ); + n_y = randomintrange( n_spread * -1, n_spread ); + n_z = randomintrange( n_spread * -1, n_spread ); + return ( n_x, n_y, n_z ); +} diff --git a/zm_tomb_patch/readme.md b/zm_tomb_patch/readme.md index bb023d5..58445e7 100644 --- a/zm_tomb_patch/readme.md +++ b/zm_tomb_patch/readme.md @@ -10,4 +10,77 @@ zm_tomb_patch/maps/mp/zombies/_zm_perk_random.gsc ### The following scripts compile but cause a minidump or other severe error: +### The following scripts have been checked, but they have not been tested yet +``` + +``` + +### The following scripts are not checked yet, uploaded to setup a baseline: +``` +maps/mp/zm_tomb.gsc +maps/mp/zm_tomb_achivement.gsc +maps/mp/zm_tomb_amb.gsc +maps/mp/zm_tomb_ambient_scripts.gsc +maps/mp/zm_tomb_capture_zones.gsc +maps/mp/zm_tomb_capture_zones_ffotd.gsc +maps/mp/zm_tomb_challenges.gsc +maps/mp/zm_tomb_chamber.gsc +maps/mp/zm_tomb_classic.gsc +maps/mp/zm_tomb_craftables.gsc +maps/mp/zm_tomb_dig.gsc +maps/mp/zm_tomb_distance_tracking.gsc +maps/mp/zm_tomb_ee_lights.gsc +maps/mp/zm_tomb_ee_main.gsc +maps/mp/zm_tomb_ee_main_step_1.gsc +maps/mp/zm_tomb_ee_main_step_2.gsc +maps/mp/zm_tomb_ee_main_step_3.gsc +maps/mp/zm_tomb_ee_main_step_4.gsc +maps/mp/zm_tomb_ee_main_step_5.gsc +maps/mp/zm_tomb_ee_main_step_6.gsc +maps/mp/zm_tomb_ee_main_step_7.gsc +maps/mp/zm_tomb_ee_main_step_8.gsc +maps/mp/zm_tomb_ee_side.gsc +maps/mp/zm_tomb_ffotd.gsc +maps/mp/zm_tomb_fx.gsc +maps/mp/zm_tomb_gamemodes.gsc +maps/mp/zm_tomb_giant_robot.gsc +maps/mp/zm_tomb_giant_robot_ffotd.gsc +maps/mp/zm_tomb_main_quest.gsc +maps/mp/zm_tomb_quest_air.gsc +maps/mp/zm_tomb_quest_crypt.gsc +maps/mp/zm_tomb_quest_elec.gsc +maps/mp/zm_tomb_quest_fire.gsc +maps/mp/zm_tomb_quest_ice.gsc +maps/mp/zm_tomb_standard.gsc +maps/mp/zm_tomb_tank.gsc +maps/mp/zm_tomb_teleporter.gsc +maps/mp/zm_tomb_utility.gsc +maps/mp/zm_tomb_vo.gsc +maps/mp/gametypes_zm/zstandard.gsc +maps/mp/zombies/_zm_ai_mechz.gsc +maps/mp/zombies/_zm_ai_mechz_booster.gsc +maps/mp/zombies/_zm_ai_mechz_claw.gsc +maps/mp/zombies/_zm_ai_mechz_dev.gsc +maps/mp/zombies/_zm_ai_mechz_ffotd.gsc +maps/mp/zombies/_zm_ai_mechz_ft.gsc +maps/mp/zombies/_zm_ai_quadrotor.gsc +maps/mp/zombies/_zm_challenges.gsc +maps/mp/zombies/_zm_craftables.gsc +maps/mp/zombies/_zm_magicbox_tomb.gsc +maps/mp/zombies/_zm_melee_weapon.gsc +maps/mp/zombies/_zm_perk_divetonuke.gsc +maps/mp/zombies/_zm_powerup_zombie_blood.gsc +maps/mp/zombies/_zm_riotshield_tomb.gsc +maps/mp/zombies/_zm_weap_ballistic_knife.gsc +maps/mp/zombies/_zm_weap_beacon.gsc +maps/mp/zombies/_zm_weap_claymore.gsc +maps/mp/zombies/_zm_weap_one_inch_punch.gsc +maps/mp/zombies/_zm_weap_riotshield.gsc +maps/mp/zombies/_zm_weap_staff_air.gsc +maps/mp/zombies/_zm_weap_staff_fire.gsc +maps/mp/zombies/_zm_weap_staff_lightning.gsc +maps/mp/zombies/_zm_weap_staff_revive.gsc +maps/mp/zombies/_zm_weap_staff_water.gsc +``` + ### notes: