burc_2004

_zm_ai_mechz.gsc

Oct 1st, 2015
134
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 58.10 KB | None | 0 0
  1. #include maps/mp/zombies/_zm_ai_basic;
  2. #include maps/mp/zm_tomb_chamber;
  3. #include maps/mp/zombies/_zm_powerups;
  4. #include maps/mp/zombies/_zm_stats;
  5. #include maps/mp/zombies/_zm_score;
  6. #include maps/mp/zombies/_zm_audio;
  7. #include maps/mp/animscripts/zm_shared;
  8. #include maps/mp/zombies/_zm_spawner;
  9. #include maps/mp/zombies/_zm_ai_mechz;
  10. #include maps/mp/zombies/_zm_ai_mechz_ffotd;
  11. #include maps/mp/zombies/_zm_ai_mechz_booster;
  12. #include maps/mp/zombies/_zm_ai_mechz_ft;
  13. #include maps/mp/zombies/_zm_ai_mechz_claw;
  14. #include maps/mp/zombies/_zm_ai_mechz_dev;
  15. #include maps/mp/zm_tomb_tank;
  16. #include maps/mp/animscripts/zm_utility;
  17. #include maps/mp/zombies/_zm_utility;
  18. #include maps/mp/zombies/_zm_net;
  19. #include maps/mp/_utility;
  20. #include common_scripts/utility;
  21. #include maps/mp/zombies/_zm_zonemgr;
  22.  
  23. #using_animtree( "mechz_claw" );
  24.  
  25. precache()
  26. {
  27.     level thread mechz_setup_armor_pieces();
  28.     precachemodel( "c_zom_mech_claw" );
  29.     precachemodel( "c_zom_mech_faceplate" );
  30.     precachemodel( "c_zom_mech_powersupply_cap" );
  31.     level._effect[ "mech_dmg_sparks" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_dmg_sparks" );
  32.     level._effect[ "mech_dmg_steam" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_dmg_steam" );
  33.     level._effect[ "mech_booster" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_jump_booster" );
  34.     level._effect[ "mech_wpn_source" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_wpn_source" );
  35.     level._effect[ "mech_wpn_flamethrower" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_wpn_flamethrower" );
  36.     level._effect[ "mech_booster_landing" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_jump_landing" );
  37.     level._effect[ "mech_faceplate_dmg" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_dmg_armor_face" );
  38.     level._effect[ "mech_armor_dmg" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_dmg_armor" );
  39.     level._effect[ "mech_exhaust" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_exhaust_smoke" );
  40.     level._effect[ "mech_booster_feet" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_jump_booster_sm" );
  41.     level._effect[ "mech_headlamp" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_head_light" );
  42.     level._effect[ "mech_footstep_steam" ] = loadfx( "maps/zombie_tomb/fx_tomb_mech_foot_step_steam" );
  43.     setdvar( "zombie_double_wide_checks", 1 );
  44.     precacherumble( "mechz_footsteps" );
  45.     precacheshellshock( "lava_small" );
  46. }
  47.  
  48. init()
  49. {
  50.     maps/mp/zombies/_zm_ai_mechz_ffotd::mechz_init_start();
  51.     level.mechz_spawners = getentarray( "mechz_spawner", "script_noteworthy" );
  52.     if ( level.mechz_spawners.size == 0 )
  53.     {
  54.         return;
  55.     }
  56.     i = 0;
  57.     while ( i < level.mechz_spawners.size )
  58.     {
  59.         level.mechz_spawners[ i ].is_enabled = 1;
  60.         level.mechz_spawners[ i ].script_forcespawn = 1;
  61.         i++;
  62.     }
  63.     level.mechz_base_health = 5000;
  64.     level.mechz_health = level.mechz_base_health;
  65.     level.mechz_health_increase = 1000;
  66.     level.mechz_round_count = 0;
  67.     level.mechz_damage_percent = 0,1;
  68.     level.mechz_remove_helmet_head_dmg_base = 500;
  69.     level.mechz_remove_helmet_head_dmg = level.mechz_remove_helmet_head_dmg_base;
  70.     level.mechz_remove_helmet_head_dmg_increase = 250;
  71.     level.mechz_explosive_dmg_head_scaler = 0,25;
  72.     level.mechz_helmet_health_percentage = 0,1;
  73.     level.mechz_powerplant_expose_dmg_base = 300;
  74.     level.mechz_powerplant_expose_dmg = level.mechz_powerplant_expose_base_dmg;
  75.     level.mechz_powerplant_expose_dmg_increase = 100;
  76.     level.mechz_powerplant_destroy_dmg_base = 500;
  77.     level.mechz_powerplant_destroy_dmg = level.mechz_powerplant_destroy_dmg_base;
  78.     level.mechz_powerplant_destroy_dmg_increase = 150;
  79.     level.mechz_powerplant_expose_health_percentage = 0,05;
  80.     level.mechz_powerplant_destroyed_health_percentage = 0,025;
  81.     level.mechz_explosive_dmg_to_cancel_claw_percentage = 0,1;
  82.     level.mechz_min_round_fq = 3;
  83.     level.mechz_max_round_fq = 4;
  84.     level.mechz_min_round_fq_solo = 4;
  85.     level.mechz_max_round_fq_solo = 6;
  86.     level.mechz_reset_dist_sq = 65536;
  87.     level.mechz_sticky_dist_sq = 1048576;
  88.     level.mechz_aggro_dist_sq = 16384;
  89.     level.mechz_zombie_per_round = 1;
  90.     level.mechz_left_to_spawn = 0;
  91.     level.mechz_players_in_zone_spawn_point_cap = 120;
  92.     level.mechz_shotgun_damage_mod = 1,5;
  93.     level.mechz_failed_paths_to_jump = 3;
  94.     level.mechz_jump_dist_threshold = 4410000;
  95.     level.mechz_jump_delay = 3;
  96.     level.mechz_player_flame_dmg = 10;
  97.     level.mechz_half_front_arc = cos( 45 );
  98.     level.mechz_ft_sweep_chance = 10;
  99.     level.mechz_aim_max_pitch = 60;
  100.     level.mechz_aim_max_yaw = 45;
  101.     level.mechz_custom_goalradius = 48;
  102.     level.mechz_custom_goalradius_sq = level.mechz_custom_goalradius * level.mechz_custom_goalradius;
  103.     level.mechz_tank_knockdown_time = 5;
  104.     level.mechz_robot_knockdown_time = 10;
  105.     level.mechz_dist_for_sprint = 129600;
  106.     level.mechz_dist_for_stop_sprint = 57600;
  107.     level.mechz_claw_cooldown_time = 7000;
  108.     level.mechz_flamethrower_cooldown_time = 5000;
  109.     level.mechz_min_extra_spawn = 8;
  110.     level.mechz_max_extra_spawn = 11;
  111.     level.mechz_points_for_killer = 250;
  112.     level.mechz_points_for_team = 500;
  113.     level.mechz_points_for_helmet = 100;
  114.     level.mechz_points_for_powerplant = 100;
  115.     level.mechz_flogger_stun_time = 3;
  116.     level.mechz_powerplant_stun_time = 4;
  117.     flag_init( "mechz_launching_claw" );
  118.     flag_init( "mechz_claw_move_complete" );
  119.     registerclientfield( "actor", "mechz_fx", 14000, 12, "int" );
  120.     registerclientfield( "toplayer", "mechz_grab", 14000, 1, "int" );
  121.     level thread init_flamethrower_triggers();
  122.     if ( isDefined( level.mechz_spawning_logic_override_func ) )
  123.     {
  124.         level thread [[ level.mechz_spawning_logic_override_func ]]();
  125.     }
  126.     else
  127.     {
  128.         level thread mechz_spawning_logic();
  129.     }
  130.     scriptmodelsuseanimtree( -1 );
  131. /#
  132.     setup_devgui();
  133. #/
  134.     maps/mp/zombies/_zm_ai_mechz_ffotd::mechz_init_end();
  135. }
  136.  
  137. mechz_setup_armor_pieces()
  138. {
  139.     level.mechz_armor_info = [];
  140.     level.mechz_armor_info[ 0 ] = spawnstruct();
  141.     level.mechz_armor_info[ 0 ].model = "c_zom_mech_armor_knee_left";
  142.     level.mechz_armor_info[ 0 ].tag = "J_Knee_Attach_LE";
  143.     level.mechz_armor_info[ 1 ] = spawnstruct();
  144.     level.mechz_armor_info[ 1 ].model = "c_zom_mech_armor_knee_right";
  145.     level.mechz_armor_info[ 1 ].tag = "J_Knee_attach_RI";
  146.     level.mechz_armor_info[ 2 ] = spawnstruct();
  147.     level.mechz_armor_info[ 2 ].model = "c_zom_mech_armor_shoulder_left";
  148.     level.mechz_armor_info[ 2 ].tag = "J_ShoulderArmor_LE";
  149.     level.mechz_armor_info[ 3 ] = spawnstruct();
  150.     level.mechz_armor_info[ 3 ].model = "c_zom_mech_armor_shoulder_right";
  151.     level.mechz_armor_info[ 3 ].tag = "J_ShoulderArmor_RI";
  152.     level.mechz_armor_info[ 4 ] = spawnstruct();
  153.     level.mechz_armor_info[ 4 ].tag = "J_Root_Attach_LE";
  154.     level.mechz_armor_info[ 5 ] = spawnstruct();
  155.     level.mechz_armor_info[ 5 ].tag = "J_Root_Attach_RI";
  156.     i = 0;
  157.     while ( i < level.mechz_armor_info.size )
  158.     {
  159.         if ( isDefined( level.mechz_armor_info[ i ].model ) )
  160.         {
  161.             precachemodel( level.mechz_armor_info[ i ].model );
  162.         }
  163.         i++;
  164.     }
  165. }
  166.  
  167. mechz_setup_fx()
  168. {
  169.     self.fx_field = 0;
  170.     self thread booster_fx_watcher();
  171.     self thread flamethrower_fx_watcher();
  172. }
  173.  
  174. clear_one_off_fx( fx_id )
  175. {
  176.     self endon( "death" );
  177.     wait 10;
  178.     self.fx_field &= fx_id;
  179.     self setclientfield( "mechz_fx", self.fx_field );
  180. }
  181.  
  182. traversal_booster_fx_watcher()
  183. {
  184.     self endon( "death" );
  185.     while ( 1 )
  186.     {
  187.         self waittill( "traverse_anim", notetrack );
  188.         if ( notetrack == "booster_on" )
  189.         {
  190.             self.fx_field |= 128;
  191.             self.sndloopent playsound( "zmb_ai_mechz_rocket_start" );
  192.             self.sndloopent playloopsound( "zmb_ai_mechz_rocket_loop", 0,75 );
  193.         }
  194.         else
  195.         {
  196.             if ( notetrack == "booster_off" )
  197.             {
  198.                 self.fx_field &= 128;
  199.                 self.sndloopent playsound( "zmb_ai_mechz_rocket_stop" );
  200.                 self.sndloopent stoploopsound( 1 );
  201.             }
  202.         }
  203.         self setclientfield( "mechz_fx", self.fx_field );
  204.     }
  205. }
  206.  
  207. booster_fx_watcher()
  208. {
  209.     self endon( "death" );
  210.     self thread traversal_booster_fx_watcher();
  211.     while ( 1 )
  212.     {
  213.         self waittill( "jump_anim", notetrack );
  214.         if ( isDefined( self.mechz_hidden ) && self.mechz_hidden )
  215.         {
  216.             continue;
  217.         }
  218.         if ( notetrack == "booster_on" )
  219.         {
  220.             self.fx_field |= 128;
  221.             self.sndloopent playsound( "zmb_ai_mechz_rocket_start" );
  222.             self.sndloopent playloopsound( "zmb_ai_mechz_rocket_loop", 0,75 );
  223.         }
  224.         else if ( notetrack == "booster_off" )
  225.         {
  226.             self.fx_field &= 128;
  227.             self.sndloopent playsound( "zmb_ai_mechz_rocket_stop" );
  228.             self.sndloopent stoploopsound( 1 );
  229.         }
  230.         else
  231.         {
  232.             if ( notetrack == "impact" )
  233.             {
  234.                 self.fx_field |= 512;
  235.                 if ( isDefined( self.has_helmet ) && self.has_helmet )
  236.                 {
  237.                     self.fx_field |= 2048;
  238.                 }
  239.                 self thread clear_one_off_fx( 512 );
  240.             }
  241.         }
  242.         self setclientfield( "mechz_fx", self.fx_field );
  243.     }
  244. }
  245.  
  246. flamethrower_fx_watcher()
  247. {
  248.     self endon( "death" );
  249.     while ( 1 )
  250.     {
  251.         self waittill( "flamethrower_anim", notetrack );
  252.         if ( notetrack == "start_ft" )
  253.         {
  254.             self.fx_field |= 64;
  255.         }
  256.         else
  257.         {
  258.             if ( notetrack == "stop_ft" )
  259.             {
  260.                 self.fx_field &= 64;
  261.             }
  262.         }
  263.         self setclientfield( "mechz_fx", self.fx_field );
  264.     }
  265. }
  266.  
  267. fx_cleanup()
  268. {
  269.     self.fx_field = 0;
  270.     self setclientfield( "mechz_fx", self.fx_field );
  271.     wait_network_frame();
  272. }
  273.  
  274. mechz_setup_snd()
  275. {
  276.     self.audio_type = "mechz";
  277.     if ( !isDefined( self.sndloopent ) )
  278.     {
  279.         self.sndloopent = spawn( "script_origin", self.origin );
  280.         self.sndloopent linkto( self, "tag_origin" );
  281.         self thread snddeleteentondeath( self.sndloopent );
  282.     }
  283.     self thread play_ambient_mechz_vocals();
  284. }
  285.  
  286. snddeleteentondeath( ent )
  287. {
  288.     self waittill( "death" );
  289.     ent delete();
  290. }
  291.  
  292. play_ambient_mechz_vocals()
  293. {
  294.     self endon( "death" );
  295.     wait randomintrange( 2, 4 );
  296.     while ( 1 )
  297.     {
  298.         if ( isDefined( self ) )
  299.         {
  300.             if ( isDefined( self.favoriteenemy ) && distance( self.origin, self.favoriteenemy.origin ) <= 150 )
  301.             {
  302.                 break;
  303.             }
  304.             else
  305.             {
  306.                 self playsound( "zmb_ai_mechz_vox_ambient" );
  307.             }
  308.         }
  309.         wait randomfloatrange( 3, 6 );
  310.     }
  311. }
  312.  
  313. enable_mechz_rounds()
  314. {
  315. /#
  316.     if ( getDvarInt( "zombie_cheat" ) >= 2 )
  317.     {
  318.         return;
  319. #/
  320.     }
  321.     level.mechz_rounds_enabled = 1;
  322.     flag_init( "mechz_round" );
  323.     level thread mechz_round_tracker();
  324. }
  325.  
  326. mechz_round_tracker()
  327. {
  328.     maps/mp/zombies/_zm_ai_mechz_ffotd::mechz_round_tracker_start();
  329.     level.num_mechz_spawned = 0;
  330.     old_spawn_func = level.round_spawn_func;
  331.     old_wait_func = level.round_wait_func;
  332.     while ( !isDefined( level.zombie_mechz_locations ) )
  333.     {
  334.         wait 0,05;
  335.     }
  336.     flag_wait( "activate_zone_nml" );
  337.     mech_start_round_num = 8;
  338.     if ( isDefined( level.is_forever_solo_game ) && level.is_forever_solo_game )
  339.     {
  340.         mech_start_round_num = 8;
  341.     }
  342.     while ( level.round_number < mech_start_round_num )
  343.     {
  344.         level waittill( "between_round_over" );
  345.     }
  346.     level.next_mechz_round = level.round_number;
  347.     level thread debug_print_mechz_round();
  348.     while ( 1 )
  349.     {
  350.         maps/mp/zombies/_zm_ai_mechz_ffotd::mechz_round_tracker_loop_start();
  351.         if ( level.num_mechz_spawned > 0 )
  352.         {
  353.             level.mechz_should_drop_powerup = 1;
  354.         }
  355.         while ( level.next_mechz_round <= level.round_number )
  356.         {
  357.             a_zombies = getaispeciesarray( level.zombie_team, "all" );
  358.             _a485 = a_zombies;
  359.             _k485 = getFirstArrayKey( _a485 );
  360.             while ( isDefined( _k485 ) )
  361.             {
  362.                 zombie = _a485[ _k485 ];
  363.                 if ( isDefined( zombie.is_mechz ) && zombie.is_mechz && isalive( zombie ) )
  364.                 {
  365.                     level.next_mechz_round++;
  366.                     break;
  367.                 }
  368.                 else
  369.                 {
  370.                     _k485 = getNextArrayKey( _a485, _k485 );
  371.                 }
  372.             }
  373.         }
  374.         if ( level.mechz_left_to_spawn == 0 && level.next_mechz_round <= level.round_number )
  375.         {
  376.             mechz_health_increases();
  377.             if ( isDefined( level.is_forever_solo_game ) && level.is_forever_solo_game )
  378.             {
  379.                 level.mechz_zombie_per_round = 1;
  380.             }
  381.             else
  382.             {
  383.                 if ( level.mechz_round_count < 2 )
  384.                 {
  385.                     level.mechz_zombie_per_round = 1;
  386.                     break;
  387.                 }
  388.                 else if ( level.mechz_round_count < 5 )
  389.                 {
  390.                     level.mechz_zombie_per_round = 2;
  391.                     break;
  392.                 }
  393.                 else
  394.                 {
  395.                     level.mechz_zombie_per_round = 3;
  396.                 }
  397.             }
  398.             level.mechz_left_to_spawn = level.mechz_zombie_per_round;
  399.             mechz_spawning = level.mechz_left_to_spawn;
  400.             wait randomfloatrange( 10, 15 );
  401.             level notify( "spawn_mechz" );
  402.             if ( isDefined( level.is_forever_solo_game ) && level.is_forever_solo_game )
  403.             {
  404.                 n_round_gap = randomintrange( level.mechz_min_round_fq_solo, level.mechz_max_round_fq_solo );
  405.             }
  406.             else
  407.             {
  408.                 n_round_gap = randomintrange( level.mechz_min_round_fq, level.mechz_max_round_fq );
  409.             }
  410.             level.next_mechz_round = level.round_number + n_round_gap;
  411.             level.mechz_round_count++;
  412.             level thread debug_print_mechz_round();
  413.             level.num_mechz_spawned += mechz_spawning;
  414.         }
  415.         maps/mp/zombies/_zm_ai_mechz_ffotd::mechz_round_tracker_loop_end();
  416.         level waittill( "between_round_over" );
  417.         mechz_clear_spawns();
  418.     }
  419. }
  420.  
  421. debug_print_mechz_round()
  422. {
  423.     flag_wait( "start_zombie_round_logic" );
  424. /#
  425.     iprintln( "Next mechz Round = " + level.next_mechz_round );
  426. #/
  427. }
  428.  
  429. mechz_spawning_logic()
  430. {
  431.     level thread enable_mechz_rounds();
  432.     while ( 1 )
  433.     {
  434.         level waittill( "spawn_mechz" );
  435.         while ( level.mechz_left_to_spawn )
  436.         {
  437.             while ( level.zombie_mechz_locations.size < 1 )
  438.             {
  439.                 wait randomfloatrange( 5, 10 );
  440.             }
  441.             ai = spawn_zombie( level.mechz_spawners[ 0 ] );
  442.             ai thread mechz_spawn();
  443.             level.mechz_left_to_spawn--;
  444.  
  445.             if ( level.mechz_left_to_spawn == 0 )
  446.             {
  447.                 level thread response_to_air_raid_siren_vo();
  448.             }
  449.             ai thread mechz_hint_vo();
  450.             wait randomfloatrange( 3, 6 );
  451.         }
  452.     }
  453. }
  454.  
  455. mechz_prespawn()
  456. {
  457. }
  458.  
  459. mechz_attach_objects()
  460. {
  461.     self detachall();
  462.     self.armor_state = [];
  463.     i = 0;
  464.     while ( i < level.mechz_armor_info.size )
  465.     {
  466.         self.armor_state[ i ] = spawnstruct();
  467.         self.armor_state[ i ].index = i;
  468.         self.armor_state[ i ].tag = level.mechz_armor_info[ i ].tag;
  469.         if ( isDefined( level.mechz_armor_info[ i ].model ) )
  470.         {
  471.             self attach( level.mechz_armor_info[ i ].model, level.mechz_armor_info[ i ].tag, 1 );
  472.             self.armor_state[ i ].model = level.mechz_armor_info[ i ].model;
  473.         }
  474.         i++;
  475.     }
  476.     if ( isDefined( self.m_claw ) )
  477.     {
  478.         self.m_claw delete();
  479.         self.m_claw = undefined;
  480.     }
  481.     org = self gettagorigin( "tag_claw" );
  482.     ang = self gettagangles( "tag_claw" );
  483.     self.m_claw = spawn( "script_model", org );
  484.     self.m_claw setmodel( "c_zom_mech_claw" );
  485.     self.m_claw.angles = ang;
  486.     self.m_claw linkto( self, "tag_claw" );
  487.     self.m_claw useanimtree( -1 );
  488.     if ( isDefined( self.m_claw_damage_trigger ) )
  489.     {
  490.         self.m_claw_damage_trigger unlink();
  491.         self.m_claw_damage_trigger delete();
  492.         self.m_claw_damage_trigger = undefined;
  493.     }
  494.     trigger_spawnflags = 0;
  495.     trigger_radius = 3;
  496.     trigger_height = 15;
  497.     self.m_claw_damage_trigger = spawn( "trigger_damage", org, trigger_spawnflags, trigger_radius, trigger_height );
  498.     self.m_claw_damage_trigger.angles = ang;
  499.     self.m_claw_damage_trigger enablelinkto();
  500.     self.m_claw_damage_trigger linkto( self, "tag_claw" );
  501.     self thread mechz_claw_damage_trigger_thread();
  502.     self attach( "c_zom_mech_faceplate", "J_Helmet", 0 );
  503.     self.has_helmet = 1;
  504.     self attach( "c_zom_mech_powersupply_cap", "tag_powersupply", 0 );
  505.     self.has_powerplant = 1;
  506.     self.powerplant_covered = 1;
  507.     self.armor_state = array_randomize( self.armor_state );
  508. }
  509.  
  510. mechz_set_starting_health()
  511. {
  512.     self.maxhealth = level.mechz_health;
  513.     self.helmet_dmg = 0;
  514.     self.helmet_dmg_for_removal = self.maxhealth * level.mechz_helmet_health_percentage;
  515.     self.powerplant_cover_dmg = 0;
  516.     self.powerplant_cover_dmg_for_removal = self.maxhealth * level.mechz_powerplant_expose_health_percentage;
  517.     self.powerplant_dmg = 0;
  518.     self.powerplant_dmg_for_destroy = self.maxhealth * level.mechz_powerplant_destroyed_health_percentage;
  519.     level.mechz_explosive_dmg_to_cancel_claw = self.maxhealth * level.mechz_explosive_dmg_to_cancel_claw_percentage;
  520. /#
  521.     if ( getDvarInt( #"E7121222" ) > 0 )
  522.     {
  523.         println( "\nMZ: MechZ Starting Health: " + self.maxhealth );
  524.         println( "\nMZ: MechZ Required Helmet Dmg: " + self.helmet_dmg_for_removal );
  525.         println( "\nMZ: MechZ Required Powerplant Cover Dmg: " + self.powerplant_cover_dmg_for_removal );
  526.         println( "\nMZ: MechZ Required Powerplant Dmg: " + self.powerplant_dmg_for_destroy );
  527. #/
  528.     }
  529.     self.health = level.mechz_health;
  530.     self.non_attacker_func = ::mechz_non_attacker_damage_override;
  531.     self.non_attack_func_takes_attacker = 1;
  532.     self.actor_damage_func = ::mechz_damage_override;
  533.     self.instakill_func = ::mechz_instakill_override;
  534.     self.nuke_damage_func = ::mechz_nuke_override;
  535. }
  536.  
  537. mechz_spawn()
  538. {
  539.     self maps/mp/zombies/_zm_ai_mechz_ffotd::spawn_start();
  540.     self endon( "death" );
  541.     level endon( "intermission" );
  542.     self mechz_attach_objects();
  543.     self mechz_set_starting_health();
  544.     self mechz_setup_fx();
  545.     self mechz_setup_snd();
  546.     level notify( "sam_clue_mechz" );
  547.     self.closest_player_override = ::get_favorite_enemy;
  548.     self.animname = "mechz_zombie";
  549.     self.has_legs = 1;
  550.     self.no_gib = 1;
  551.     self.ignore_all_poi = 1;
  552.     self.is_mechz = 1;
  553.     self.ignore_enemy_count = 1;
  554.     self.no_damage_points = 1;
  555.     self.melee_anim_func = ::melee_anim_func;
  556.     self.meleedamage = 75;
  557.     self.custom_item_dmg = 2000;
  558.     recalc_zombie_array();
  559.     self setphysparams( 20, 0, 80 );
  560.     self setcandamage( 0 );
  561.     self.zombie_init_done = 1;
  562.     self notify( "zombie_init_done" );
  563.     self.allowpain = 0;
  564.     self animmode( "normal" );
  565.     self orientmode( "face enemy" );
  566.     self maps/mp/zombies/_zm_spawner::zombie_setup_attack_properties();
  567.     self.completed_emerging_into_playable_area = 1;
  568.     self notify( "completed_emerging_into_playable_area" );
  569.     self.no_powerups = 0;
  570.     self setfreecameralockonallowed( 0 );
  571.     self notsolid();
  572.     self thread maps/mp/zombies/_zm_spawner::zombie_eye_glow();
  573.     level thread maps/mp/zombies/_zm_spawner::zombie_death_event( self );
  574.     self thread maps/mp/zombies/_zm_spawner::enemy_death_detection();
  575.     if ( level.zombie_mechz_locations.size )
  576.     {
  577.         spawn_pos = self get_best_mechz_spawn_pos();
  578.     }
  579.     if ( !isDefined( spawn_pos ) )
  580.     {
  581. /#
  582.         println( "ERROR: Tried to spawn mechz with no mechz spawn_positions!\n" );
  583.         iprintln( "ERROR: Tried to spawn mechz with no mechz spawn_positions!" );
  584. #/
  585.         self delete();
  586.         return;
  587.     }
  588.     if ( isDefined( level.mechz_force_spawn_pos ) )
  589.     {
  590.         spawn_pos = level.mechz_force_spawn_pos;
  591.         level.mechz_force_spawn_pos = undefined;
  592.     }
  593.     if ( !isDefined( spawn_pos.angles ) )
  594.     {
  595.         spawn_pos.angles = ( 0, 0, 1 );
  596.     }
  597.     self thread mechz_death();
  598.     self forceteleport( spawn_pos.origin, spawn_pos.angles );
  599.     self playsound( "zmb_ai_mechz_incoming_alarm" );
  600.     if ( !isDefined( spawn_pos.angles ) )
  601.     {
  602.         spawn_pos.angles = ( 0, 0, 1 );
  603.     }
  604.     self animscripted( spawn_pos.origin, spawn_pos.angles, "zm_spawn" );
  605.     self maps/mp/animscripts/zm_shared::donotetracks( "jump_anim" );
  606.     self setfreecameralockonallowed( 1 );
  607.     self solid();
  608.     self set_zombie_run_cycle( "walk" );
  609.     if ( isDefined( level.mechz_find_flesh_override_func ) )
  610.     {
  611.         level thread [[ level.mechz_find_flesh_override_func ]]();
  612.     }
  613.     else
  614.     {
  615.         self thread mechz_find_flesh();
  616.     }
  617.     self thread mechz_jump_think( spawn_pos );
  618.     self setcandamage( 1 );
  619.     self init_anim_rate();
  620.     self maps/mp/zombies/_zm_ai_mechz_ffotd::spawn_end();
  621. }
  622.  
  623. get_closest_mechz_spawn_pos( org )
  624. {
  625.     best_dist = -1;
  626.     best_pos = undefined;
  627.     players = get_players();
  628.     i = 0;
  629.     while ( i < level.zombie_mechz_locations.size )
  630.     {
  631.         dist = distancesquared( org, level.zombie_mechz_locations[ i ].origin );
  632.         if ( dist < best_dist || best_dist < 0 )
  633.         {
  634.             best_dist = dist;
  635.             best_pos = level.zombie_mechz_locations[ i ];
  636.         }
  637.         i++;
  638.     }
  639. /#
  640.     if ( !isDefined( best_pos ) )
  641.     {
  642.         println( "Error: Mechz could not find a valid jump pos from position ( " + self.origin[ 0 ] + ", " + self.origin[ 1 ] + ", " + self.origin[ 2 ] + " )" );
  643. #/
  644.     }
  645.     return best_pos;
  646. }
  647.  
  648. get_best_mechz_spawn_pos( ignore_used_positions )
  649. {
  650.     if ( !isDefined( ignore_used_positions ) )
  651.     {
  652.         ignore_used_positions = 0;
  653.     }
  654.     best_dist = -1;
  655.     best_pos = undefined;
  656.     players = get_players();
  657.     i = 0;
  658.     while ( i < level.zombie_mechz_locations.size )
  659.     {
  660.         if ( !ignore_used_positions && isDefined( level.zombie_mechz_locations[ i ].has_been_used ) && level.zombie_mechz_locations[ i ].has_been_used )
  661.         {
  662.             i++;
  663.             continue;
  664.         }
  665.         else
  666.         {
  667.             if ( ignore_used_positions == 1 && isDefined( level.zombie_mechz_locations[ i ].used_cooldown ) && level.zombie_mechz_locations[ i ].used_cooldown )
  668.             {
  669.                 i++;
  670.                 continue;
  671.             }
  672.             else
  673.             {
  674.                 j = 0;
  675.                 while ( j < players.size )
  676.                 {
  677.                     if ( is_player_valid( players[ j ], 1, 1 ) )
  678.                     {
  679.                         dist = distancesquared( level.zombie_mechz_locations[ i ].origin, players[ j ].origin );
  680.                         if ( dist < best_dist || best_dist < 0 )
  681.                         {
  682.                             best_dist = dist;
  683.                             best_pos = level.zombie_mechz_locations[ i ];
  684.                         }
  685.                     }
  686.                     j++;
  687.                 }
  688.             }
  689.         }
  690.         i++;
  691.     }
  692.     if ( ignore_used_positions && isDefined( best_pos ) )
  693.     {
  694.         best_pos thread jump_pos_used_cooldown();
  695.     }
  696.     if ( isDefined( best_pos ) )
  697.     {
  698.         best_pos.has_been_used = 1;
  699.     }
  700.     else
  701.     {
  702.         if ( level.zombie_mechz_locations.size > 0 )
  703.         {
  704.             return level.zombie_mechz_locations[ randomint( level.zombie_mechz_locations.size ) ];
  705.         }
  706.     }
  707.     return best_pos;
  708. }
  709.  
  710. mechz_clear_spawns()
  711. {
  712.     i = 0;
  713.     while ( i < level.zombie_mechz_locations.size )
  714.     {
  715.         level.zombie_mechz_locations[ i ].has_been_used = 0;
  716.         i++;
  717.     }
  718. }
  719.  
  720. jump_pos_used_cooldown()
  721. {
  722.     self.used_cooldown = 1;
  723.     wait 5;
  724.     self.used_cooldown = 0;
  725. }
  726.  
  727. mechz_health_increases()
  728. {
  729.     if ( !isDefined( level.mechz_last_spawn_round ) || level.round_number > level.mechz_last_spawn_round )
  730.     {
  731.         a_players = getplayers();
  732.         n_player_modifier = 1;
  733.         if ( a_players.size > 1 )
  734.         {
  735.             n_player_modifier = a_players.size * 0,75;
  736.         }
  737.         level.mechz_health = int( n_player_modifier * ( level.mechz_base_health + ( level.mechz_health_increase * level.mechz_round_count ) ) );
  738.         if ( level.mechz_health >= ( 22500 * n_player_modifier ) )
  739.         {
  740.             level.mechz_health = int( 22500 * n_player_modifier );
  741.         }
  742.         level.mechz_last_spawn_round = level.round_number;
  743.     }
  744. }
  745.  
  746. mechz_death()
  747. {
  748.     self endon( "mechz_cleanup" );
  749.     thread mechz_cleanup();
  750.     self waittill( "death" );
  751.     death_origin = self.origin;
  752.     if ( isDefined( self.robot_stomped ) && self.robot_stomped )
  753.     {
  754.         death_origin += vectorScale( ( 0, 0, 1 ), 90 );
  755.     }
  756.     self mechz_claw_detach();
  757.     self release_flamethrower_trigger();
  758.     self.fx_field = 0;
  759.     self setclientfield( "mechz_fx", self.fx_field );
  760.     self thread maps/mp/zombies/_zm_spawner::zombie_eye_glow_stop();
  761.     self mechz_interrupt();
  762.     if ( isDefined( self.favoriteenemy ) )
  763.     {
  764.         if ( isDefined( self.favoriteenemy.hunted_by ) )
  765.         {
  766.             self.favoriteenemy.hunted_by--;
  767.  
  768.         }
  769.     }
  770.     self thread mechz_explode( "tag_powersupply", death_origin );
  771.     if ( get_current_zombie_count() == 0 && level.zombie_total == 0 )
  772.     {
  773.         level.last_mechz_origin = self.origin;
  774.         level notify( "last_mechz_down" );
  775.     }
  776.     if ( isplayer( self.attacker ) )
  777.     {
  778.         event = "death";
  779.         if ( issubstr( self.damageweapon, "knife_ballistic_" ) )
  780.         {
  781.             event = "ballistic_knife_death";
  782.         }
  783.         self.attacker delay_thread( 4, ::maps/mp/zombies/_zm_audio::create_and_play_dialog, "general", "mech_defeated" );
  784.         self.attacker maps/mp/zombies/_zm_score::player_add_points( event, self.damagemod, self.damagelocation, 1 );
  785.         self.attacker maps/mp/zombies/_zm_stats::increment_client_stat( "tomb_mechz_killed", 0 );
  786.         self.attacker maps/mp/zombies/_zm_stats::increment_player_stat( "tomb_mechz_killed" );
  787.         if ( isDefined( level.mechz_should_drop_powerup ) && level.mechz_should_drop_powerup )
  788.         {
  789.             wait_network_frame();
  790.             wait_network_frame();
  791.             level.mechz_should_drop_powerup = 0;
  792.             if ( level.powerup_drop_count >= level.zombie_vars[ "zombie_powerup_drop_max_per_round" ] )
  793.             {
  794.                 level.powerup_drop_count = level.zombie_vars[ "zombie_powerup_drop_max_per_round" ] - 1;
  795.             }
  796.             level.zombie_vars[ "zombie_drop_item" ] = 1;
  797.             level thread maps/mp/zombies/_zm_powerups::powerup_drop( self.origin );
  798.         }
  799.     }
  800. }
  801.  
  802. mechz_explode( str_tag, death_origin )
  803. {
  804.     wait 2;
  805.     v_origin = self gettagorigin( str_tag );
  806.     level notify( "mechz_exploded" );
  807.     playsoundatposition( "zmb_ai_mechz_death_explode", v_origin );
  808.     playfx( level._effect[ "mechz_death" ], v_origin );
  809.     radiusdamage( v_origin, 128, 100, 25, undefined, "MOD_GRENADE_SPLASH" );
  810.     earthquake( 0,5, 1, v_origin, 256 );
  811.     playrumbleonposition( "grenade_rumble", v_origin );
  812.     level notify( "mechz_killed" );
  813. }
  814.  
  815. mechz_cleanup()
  816. {
  817.     self waittill( "mechz_cleanup" );
  818.     self mechz_interrupt();
  819.     level.sndmechzistalking = 0;
  820.     if ( isDefined( self.sndmechzmusicent ) )
  821.     {
  822.         self.sndmechzmusicent delete();
  823.         self.sndmechzmusicent = undefined;
  824.     }
  825.     if ( isDefined( self.favoriteenemy ) )
  826.     {
  827.         if ( isDefined( self.favoriteenemy.hunted_by ) )
  828.         {
  829.             self.favoriteenemy.hunted_by--;
  830.  
  831.         }
  832.     }
  833. }
  834.  
  835. mechz_interrupt()
  836. {
  837.     self notify( "kill_claw" );
  838.     self notify( "kill_ft" );
  839.     self notify( "kill_jump" );
  840. }
  841.  
  842. mechz_stun( time )
  843. {
  844.     self endon( "death" );
  845.     if ( isalive( self ) && isDefined( self.not_interruptable ) || self.not_interruptable && isDefined( self.is_traversing ) && self.is_traversing )
  846.     {
  847.         return;
  848.     }
  849.     curr_time = 0;
  850.     anim_time = self getanimlengthfromasd( "zm_stun", 0 );
  851.     self mechz_interrupt();
  852.     self mechz_claw_detach();
  853.     wait 0,05;
  854.     self.not_interruptable = 1;
  855. /#
  856.     if ( getDvarInt( #"E7121222" ) > 1 )
  857.     {
  858.         println( "\nMZ: Stun setting not interruptable\n" );
  859. #/
  860.     }
  861.     while ( curr_time < time )
  862.     {
  863.         self animscripted( self.origin, self.angles, "zm_stun" );
  864.         self maps/mp/animscripts/zm_shared::donotetracks( "stun_anim" );
  865.         self clearanim( %root, 0 );
  866.         curr_time += anim_time;
  867.     }
  868.     self.not_interruptable = 0;
  869. /#
  870.     if ( getDvarInt( #"E7121222" ) > 1 )
  871.     {
  872.         println( "\nMZ: Stun clearing not interruptable\n" );
  873. #/
  874.     }
  875. }
  876.  
  877. mechz_tank_hit_callback()
  878. {
  879.     self endon( "death" );
  880.     if ( isDefined( self.mechz_hit_by_tank ) && self.mechz_hit_by_tank )
  881.     {
  882.         return;
  883.     }
  884. /#
  885.     if ( getDvarInt( #"E7121222" ) > 1 )
  886.     {
  887.         println( "\nMZ: Tank damage setting not interruptable\n" );
  888. #/
  889.     }
  890.     self.not_interruptable = 1;
  891.     self.mechz_hit_by_tank = 1;
  892.     self mechz_interrupt();
  893.     v_trace_start = self.origin + vectorScale( ( 0, 0, 1 ), 100 );
  894.     v_trace_end = self.origin - vectorScale( ( 0, 0, 1 ), 500 );
  895.     v_trace = physicstrace( self.origin, v_trace_end, ( -15, -15, -5 ), ( 15, 15, 5 ), self );
  896.     self.origin = v_trace[ "position" ];
  897.     timer = 0;
  898.     self animscripted( self.origin, self.angles, "zm_tank_hit_in" );
  899.     self maps/mp/animscripts/zm_shared::donotetracks( "pain_anim" );
  900.     anim_length = self getanimlengthfromasd( "zm_tank_hit_loop", 0 );
  901.     while ( timer < level.mechz_tank_knockdown_time )
  902.     {
  903.         timer += anim_length;
  904.         self animscripted( self.origin, self.angles, "zm_tank_hit_loop" );
  905.         self maps/mp/animscripts/zm_shared::donotetracks( "pain_anim" );
  906.     }
  907.     self animscripted( self.origin, self.angles, "zm_tank_hit_out" );
  908.     self maps/mp/animscripts/zm_shared::donotetracks( "pain_anim" );
  909. /#
  910.     if ( getDvarInt( #"E7121222" ) > 1 )
  911.     {
  912.         println( "\nMZ: Tank damage clearing not interruptable\n" );
  913. #/
  914.     }
  915.     self.not_interruptable = 0;
  916.     self.mechz_hit_by_tank = 0;
  917.     if ( !level.vh_tank ent_flag( "tank_moving" ) && self istouching( level.vh_tank ) )
  918.     {
  919.         self notsolid();
  920.         self ghost();
  921.         self.mechz_hidden = 1;
  922.         if ( isDefined( self.m_claw ) )
  923.         {
  924.             self.m_claw ghost();
  925.         }
  926.         self.fx_field_old = self.fx_field;
  927.         self thread maps/mp/zombies/_zm_spawner::zombie_eye_glow_stop();
  928.         self fx_cleanup();
  929.         self mechz_do_jump();
  930.         self solid();
  931.         self.mechz_hidden = 0;
  932.     }
  933. }
  934.  
  935. mechz_robot_stomp_callback()
  936. {
  937.     self endon( "death" );
  938.     if ( isDefined( self.robot_stomped ) && self.robot_stomped )
  939.     {
  940.         return;
  941.     }
  942.     self.not_interruptable = 1;
  943.     self.robot_stomped = 1;
  944.     self mechz_interrupt();
  945. /#
  946.     if ( getDvarInt( #"E7121222" ) > 1 )
  947.     {
  948.         println( "\nMZ: Robot stomp setting not interruptable\n" );
  949. #/
  950.     }
  951.     self thread mechz_stomped_by_giant_robot_vo();
  952.     v_trace_start = self.origin + vectorScale( ( 0, 0, 1 ), 100 );
  953.     v_trace_end = self.origin - vectorScale( ( 0, 0, 1 ), 500 );
  954.     v_trace = physicstrace( self.origin, v_trace_end, ( -15, -15, -5 ), ( 15, 15, 5 ), self );
  955.     self.origin = v_trace[ "position" ];
  956.     timer = 0;
  957.     self animscripted( self.origin, self.angles, "zm_robot_hit_in" );
  958.     self maps/mp/animscripts/zm_shared::donotetracks( "pain_anim" );
  959.     anim_length = self getanimlengthfromasd( "zm_robot_hit_loop", 0 );
  960.     while ( timer < level.mechz_robot_knockdown_time )
  961.     {
  962.         timer += anim_length;
  963.         self animscripted( self.origin, self.angles, "zm_robot_hit_loop" );
  964.         self maps/mp/animscripts/zm_shared::donotetracks( "pain_anim" );
  965.     }
  966.     self animscripted( self.origin, self.angles, "zm_robot_hit_out" );
  967.     self maps/mp/animscripts/zm_shared::donotetracks( "jump_anim" );
  968. /#
  969.     if ( getDvarInt( #"E7121222" ) > 1 )
  970.     {
  971.         println( "\nMZ: Robot stomp clearing not interruptable\n" );
  972. #/
  973.     }
  974.     self.not_interruptable = 0;
  975.     self.robot_stomped = 0;
  976. }
  977.  
  978. mechz_delayed_item_delete()
  979. {
  980.     wait 30;
  981.     self delete();
  982. }
  983.  
  984. mechz_get_closest_valid_player()
  985. {
  986.     players = get_players();
  987.     while ( isDefined( self.ignore_player ) )
  988.     {
  989.         i = 0;
  990.         while ( i < self.ignore_player.size )
  991.         {
  992.             arrayremovevalue( players, self.ignore_player[ i ] );
  993.             i++;
  994.         }
  995.     }
  996.     i = 0;
  997.     while ( i < players.size )
  998.     {
  999.         if ( isDefined( level._zombie_using_humangun ) && level._zombie_using_humangun && isai( players[ i ] ) )
  1000.         {
  1001.             return players[ i ];
  1002.         }
  1003.         if ( !is_player_valid( players[ i ], 1, 1 ) )
  1004.         {
  1005.             arrayremovevalue( players, players[ i ] );
  1006.             i--;
  1007.  
  1008.         }
  1009.         i++;
  1010.     }
  1011.     switch( players.size )
  1012.     {
  1013.         case 0:
  1014.             return undefined;
  1015.         case 1:
  1016.             return players[ 0 ];
  1017.         default:
  1018.             if ( isDefined( level.closest_player_override ) )
  1019.             {
  1020.                 player = [[ level.closest_player_override ]]( self.origin, players );
  1021.             }
  1022.             else if ( isDefined( level.calc_closest_player_using_paths ) && level.calc_closest_player_using_paths )
  1023.             {
  1024.                 player = get_closest_player_using_paths( self.origin, players );
  1025.             }
  1026.             else
  1027.             {
  1028.                 player = getclosest( self.origin, players );
  1029.             }
  1030.             return player;
  1031.     }
  1032. }
  1033.  
  1034. get_favorite_enemy( origin, players )
  1035. {
  1036.     mechz_targets = getplayers();
  1037.     least_hunted = undefined;
  1038.     best_hunted_val = -1;
  1039.     best_dist = -1;
  1040.     distances = [];
  1041.     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() )
  1042.     {
  1043. /#
  1044.         assert( isDefined( self.favoriteenemy.hunted_by ) );
  1045. #/
  1046.         self.favoriteenemy.hunted_by--;
  1047.  
  1048.         least_hunted = self.favoriteenemy;
  1049.     }
  1050.     i = 0;
  1051.     while ( i < mechz_targets.size )
  1052.     {
  1053.         if ( !isDefined( mechz_targets[ i ].hunted_by ) || mechz_targets[ i ].hunted_by < 0 )
  1054.         {
  1055.             mechz_targets[ i ].hunted_by = 0;
  1056.         }
  1057.         if ( !is_player_valid( mechz_targets[ i ], 1, 1 ) )
  1058.         {
  1059.             i++;
  1060.             continue;
  1061.         }
  1062.         else
  1063.         {
  1064.             distances[ i ] = distancesquared( self.origin, mechz_targets[ i ].origin );
  1065.         }
  1066.         i++;
  1067.     }
  1068.     found_weapon_target = 0;
  1069.     i = 0;
  1070.     while ( i < mechz_targets.size )
  1071.     {
  1072.         if ( abs( mechz_targets[ i ].origin[ 2 ] - self.origin[ 2 ] ) > 60 )
  1073.         {
  1074.             i++;
  1075.             continue;
  1076.         }
  1077.         else dist = distances[ i ];
  1078.         if ( !isDefined( dist ) )
  1079.         {
  1080.             i++;
  1081.             continue;
  1082.         }
  1083.         else
  1084.         {
  1085.             if ( dist < 50000 || dist < best_dist && best_dist < 0 )
  1086.             {
  1087.                 found_weapon_target = 1;
  1088.                 least_hunted = mechz_targets[ i ];
  1089.                 best_dist = dist;
  1090.             }
  1091.         }
  1092.         i++;
  1093.     }
  1094.     if ( found_weapon_target )
  1095.     {
  1096.         least_hunted.hunted_by++;
  1097.         return least_hunted;
  1098.     }
  1099.     if ( isDefined( self.favoriteenemy ) && is_player_valid( self.favoriteenemy, 1, 1 ) )
  1100.     {
  1101.         if ( distancesquared( self.origin, self.favoriteenemy.origin ) <= level.mechz_sticky_dist_sq )
  1102.         {
  1103.             self.favoriteenemy.hunted_by++;
  1104.             return self.favoriteenemy;
  1105.         }
  1106.     }
  1107.     i = 0;
  1108.     while ( i < mechz_targets.size )
  1109.     {
  1110.         if ( isDefined( mechz_targets[ i ].in_giant_robot_head ) )
  1111.         {
  1112.             i++;
  1113.             continue;
  1114.         }
  1115.         else if ( mechz_targets[ i ] maps/mp/zm_tomb_chamber::is_player_in_chamber() )
  1116.         {
  1117.             i++;
  1118.             continue;
  1119.         }
  1120.         else if ( isDefined( distances[ i ] ) )
  1121.         {
  1122.             dist = distances[ i ];
  1123.         }
  1124.         else
  1125.         {
  1126.         }
  1127.         hunted = mechz_targets[ i ].hunted_by;
  1128.         if ( !isDefined( least_hunted ) || hunted <= least_hunted.hunted_by )
  1129.         {
  1130.             if ( dist < best_dist || best_dist < 0 )
  1131.             {
  1132.                 least_hunted = mechz_targets[ i ];
  1133.                 best_dist = dist;
  1134.             }
  1135.         }
  1136.         i++;
  1137.     }
  1138.     if ( isDefined( least_hunted ) )
  1139.     {
  1140.         least_hunted.hunted_by++;
  1141.     }
  1142.     return least_hunted;
  1143. }
  1144.  
  1145. mechz_check_in_arc( right_offset )
  1146. {
  1147.     origin = self.origin;
  1148.     if ( isDefined( right_offset ) )
  1149.     {
  1150.         right_angle = anglesToRight( self.angles );
  1151.         origin += right_angle * right_offset;
  1152.     }
  1153.     facing_vec = anglesToForward( self.angles );
  1154.     enemy_vec = self.favoriteenemy.origin - origin;
  1155.     enemy_yaw_vec = ( enemy_vec[ 0 ], enemy_vec[ 1 ], 0 );
  1156.     facing_yaw_vec = ( facing_vec[ 0 ], facing_vec[ 1 ], 0 );
  1157.     enemy_yaw_vec = vectornormalize( enemy_yaw_vec );
  1158.     facing_yaw_vec = vectornormalize( facing_yaw_vec );
  1159.     enemy_dot = vectordot( facing_yaw_vec, enemy_yaw_vec );
  1160.     if ( enemy_dot < cos( level.mechz_aim_max_yaw ) )
  1161.     {
  1162.         return 0;
  1163.     }
  1164.     enemy_angles = vectorToAngle( enemy_vec );
  1165.     if ( abs( angleClamp180( enemy_angles[ 0 ] ) ) > level.mechz_aim_max_pitch )
  1166.     {
  1167.         return 0;
  1168.     }
  1169.     return 1;
  1170. }
  1171.  
  1172. mechz_get_aim_anim( anim_prefix, target_pos, right_offset )
  1173. {
  1174.     in_arc = self mechz_check_in_arc( right_offset );
  1175.     if ( !in_arc )
  1176.     {
  1177.         return undefined;
  1178.     }
  1179.     origin = self.origin;
  1180.     if ( isDefined( right_offset ) )
  1181.     {
  1182.         right_angle = anglesToRight( self.angles );
  1183.         origin += right_angle * right_offset;
  1184.     }
  1185.     aiming_vec = vectorToAngle( target_pos - origin );
  1186.     pitch = angleClamp180( aiming_vec[ 0 ] );
  1187.     yaw = angleClamp180( self.angles[ 1 ] - aiming_vec[ 1 ] );
  1188.     centered_ud = abs( pitch ) < ( level.mechz_aim_max_pitch / 2 );
  1189.     centered_lr = abs( yaw ) < ( level.mechz_aim_max_yaw / 2 );
  1190.     right_anim = angleClamp180( self.angles[ 1 ] - aiming_vec[ 1 ] ) > 0;
  1191.     up_anim = pitch < 0;
  1192.     if ( centered_ud && centered_lr )
  1193.     {
  1194.         return anim_prefix + "_aim_5";
  1195.     }
  1196.     else
  1197.     {
  1198.         if ( centered_ud && right_anim )
  1199.         {
  1200.             return anim_prefix + "_aim_6";
  1201.         }
  1202.         else
  1203.         {
  1204.             if ( centered_ud )
  1205.             {
  1206.                 return anim_prefix + "_aim_4";
  1207.             }
  1208.             else
  1209.             {
  1210.                 if ( centered_lr && up_anim )
  1211.                 {
  1212.                     return anim_prefix + "_aim_8";
  1213.                 }
  1214.                 else
  1215.                 {
  1216.                     if ( centered_lr )
  1217.                     {
  1218.                         return anim_prefix + "_aim_2";
  1219.                     }
  1220.                     else
  1221.                     {
  1222.                         if ( right_anim && up_anim )
  1223.                         {
  1224.                             return anim_prefix + "_aim_9";
  1225.                         }
  1226.                         else
  1227.                         {
  1228.                             if ( right_anim )
  1229.                             {
  1230.                                 return anim_prefix + "_aim_3";
  1231.                             }
  1232.                             else
  1233.                             {
  1234.                                 if ( up_anim )
  1235.                                 {
  1236.                                     return anim_prefix + "_aim_7";
  1237.                                 }
  1238.                                 else
  1239.                                 {
  1240.                                     return anim_prefix + "_aim_1";
  1241.                                 }
  1242.                             }
  1243.                         }
  1244.                     }
  1245.                 }
  1246.             }
  1247.         }
  1248.     }
  1249. }
  1250.  
  1251. mechz_start_basic_find_flesh()
  1252. {
  1253.     self.goalradius = level.mechz_custom_goalradius;
  1254.     self.custom_goalradius_override = level.mechz_custom_goalradius;
  1255.     if ( !isDefined( self.ai_state ) || self.ai_state != "find_flesh" )
  1256.     {
  1257.         self.ai_state = "find_flesh";
  1258.         self thread maps/mp/zombies/_zm_ai_basic::find_flesh();
  1259.     }
  1260. }
  1261.  
  1262. mechz_stop_basic_find_flesh()
  1263. {
  1264.     if ( isDefined( self.ai_state ) && self.ai_state == "find_flesh" )
  1265.     {
  1266.         self.ai_state = undefined;
  1267.         self notify( "stop_find_flesh" );
  1268.         self notify( "zombie_acquire_enemy" );
  1269.     }
  1270. }
  1271.  
  1272. watch_for_player_dist()
  1273. {
  1274.     self endon( "death" );
  1275.     while ( 1 )
  1276.     {
  1277.         player = mechz_get_closest_valid_player();
  1278.         if ( isDefined( player ) && isDefined( player.is_player_slowed ) && player.is_player_slowed )
  1279.         {
  1280.             reset_dist = level.mechz_reset_dist_sq / 2;
  1281.         }
  1282.         else
  1283.         {
  1284.             reset_dist = level.mechz_reset_dist_sq;
  1285.         }
  1286.         if ( !isDefined( player ) || distancesquared( player.origin, self.origin ) > reset_dist )
  1287.         {
  1288.             self.disable_complex_behaviors = 0;
  1289.         }
  1290.         wait 0,5;
  1291.     }
  1292. }
  1293.  
  1294. mechz_find_flesh()
  1295. {
  1296.     self endon( "death" );
  1297.     level endon( "intermission" );
  1298.     if ( level.intermission )
  1299.     {
  1300.         return;
  1301.     }
  1302.     self.helitarget = 1;
  1303.     self.ignoreme = 0;
  1304.     self.nododgemove = 1;
  1305.     self.ignore_player = [];
  1306.     self.goalradius = 32;
  1307.     self.ai_state = "spawning";
  1308.     self thread watch_for_player_dist();
  1309.     for ( ;; )
  1310.     {
  1311.         while ( 1 )
  1312.         {
  1313. /#
  1314.             while ( isDefined( self.force_behavior ) && self.force_behavior )
  1315.             {
  1316.                 wait 0,05;
  1317. #/
  1318.             }
  1319.             while ( isDefined( self.not_interruptable ) && self.not_interruptable )
  1320.             {
  1321. /#
  1322.                 if ( getDvarInt( #"E7121222" ) > 1 )
  1323.                 {
  1324.                     println( "\nMZ: Not thinking since a behavior has set not_interruptable\n" );
  1325. #/
  1326.                 }
  1327.                 wait 0,05;
  1328.             }
  1329.             while ( isDefined( self.is_traversing ) && self.is_traversing )
  1330.             {
  1331. /#
  1332.                 if ( getDvarInt( #"E7121222" ) > 1 )
  1333.                 {
  1334.                     println( "\nMZ: Not thinking since mech is traversing\n" );
  1335. #/
  1336.                 }
  1337.                 wait 0,05;
  1338.             }
  1339.             player = [[ self.closest_player_override ]]();
  1340.             self mechz_set_locomotion_speed();
  1341. /#
  1342.             if ( getDvarInt( #"E7121222" ) > 1 )
  1343.             {
  1344.                 println( "\nMZ: Doing think\n" );
  1345. #/
  1346.             }
  1347.             self.favoriteenemy = player;
  1348.             while ( !isDefined( player ) )
  1349.             {
  1350. /#
  1351.                 if ( getDvarInt( #"E7121222" ) > 1 )
  1352.                 {
  1353.                     println( "\n\tMZ: No Enemy, idling\n" );
  1354. #/
  1355.                 }
  1356.                 self.goal_pos = self.origin;
  1357.                 self setgoalpos( self.goal_pos );
  1358.                 self.ai_state = "idle";
  1359.                 self setanimstatefromasd( "zm_idle" );
  1360.                 wait 0,5;
  1361.             }
  1362.             if ( player entity_on_tank() )
  1363.             {
  1364.                 if ( level.vh_tank ent_flag( "tank_moving" ) )
  1365.                 {
  1366.                     if ( isDefined( self.jump_pos ) && self mechz_in_range_for_jump() )
  1367.                     {
  1368. /#
  1369.                         if ( getDvarInt( #"E7121222" ) > 1 )
  1370.                         {
  1371.                             println( "\n\tMZ: Enemy on moving tank, do jump out and jump in when tank is stationary\n" );
  1372. #/
  1373.                         }
  1374.                         self mechz_do_jump( 1 );
  1375.                         break;
  1376.                     }
  1377.                     else
  1378.                     {
  1379. /#
  1380.                         if ( getDvarInt( #"E7121222" ) > 1 )
  1381.                         {
  1382.                             println( "\n\tMZ: Enemy on moving tank, Jump Requested, going to jump pos\n" );
  1383. #/
  1384.                         }
  1385.                         if ( !isDefined( self.jump_pos ) )
  1386.                         {
  1387.                             self.jump_pos = get_closest_mechz_spawn_pos( self.origin );
  1388.                         }
  1389.                         if ( isDefined( self.jump_pos ) )
  1390.                         {
  1391.                             self.goal_pos = self.jump_pos.origin;
  1392.                             self setgoalpos( self.goal_pos );
  1393.                         }
  1394.                         wait 0,5;
  1395.                     }
  1396.                 }
  1397.             }
  1398.             else /#
  1399.             if ( getDvarInt( #"E7121222" ) > 1 )
  1400.             {
  1401.                 println( "\n\tMZ: Enemy on tank, targetting a tank pos\n" );
  1402. #/
  1403.             }
  1404.             self.disable_complex_behaviors = 0;
  1405.             self mechz_stop_basic_find_flesh();
  1406.             self.ai_state = "tracking_tank";
  1407.             self.goalradius = level.mechz_custom_goalradius;
  1408.             self.custom_goalradius_override = level.mechz_custom_goalradius;
  1409.             closest_tank_tag = level.vh_tank get_closest_mechz_tag_on_tank( self, self.origin );
  1410.             while ( !isDefined( closest_tank_tag ) )
  1411.             {
  1412. /#
  1413.                 if ( getDvarInt( #"E7121222" ) > 1 )
  1414.                 {
  1415.                     println( "\n\tMZ: Enemy on tank, no closest tank pos found, continuing\n" );
  1416. #/
  1417.                 }
  1418.                 wait 0,5;
  1419.             }
  1420.             closest_tank_tag_pos = level.vh_tank gettagorigin( closest_tank_tag );
  1421.             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 )
  1422.             {
  1423. /#
  1424.                 if ( getDvarInt( #"E7121222" ) > 1 )
  1425.                 {
  1426.                     println( "\n\tMZ: Enemy on tank, setting tank pos as goal\n" );
  1427. #/
  1428.                 }
  1429.                 self.goal_pos = closest_tank_tag_pos;
  1430.                 self setgoalpos( self.goal_pos );
  1431.                 self waittill_any_or_timeout( 0,5, "goal", "bad_path" );
  1432.                 while ( !player entity_on_tank() )
  1433.                 {
  1434. /#
  1435.                     if ( getDvarInt( #"E7121222" ) > 1 )
  1436.                     {
  1437.                         println( "\n\tMZ: Enemy got off tank by the time we reached our goal, continuing\n" );
  1438. #/
  1439.                     }
  1440.                 }
  1441.             }
  1442.             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 )
  1443.             {
  1444. /#
  1445.                 if ( getDvarInt( #"E7121222" ) > 1 )
  1446.                 {
  1447.                     println( "\n\tMZ: Enemy on tank, reached tank pos, doing flamethrower sweep\n" );
  1448. #/
  1449.                 }
  1450.                 self.angles = vectorToAngle( level.vh_tank.origin - self.origin );
  1451.                 self mechz_do_flamethrower_attack( 1 );
  1452.                 self notify( "tank_flamethrower_attack_complete" );
  1453.             }
  1454.         }
  1455.     }
  1456.     else if ( isDefined( self.jump_requested ) || self.jump_requested && isDefined( self.force_jump ) && self.force_jump )
  1457.     {
  1458.         if ( self mechz_in_range_for_jump() )
  1459.         {
  1460.             self mechz_do_jump();
  1461.         }
  1462.         else
  1463.         {
  1464. /#
  1465.             if ( getDvarInt( #"E7121222" ) > 1 )
  1466.             {
  1467.                 println( "\n\tMZ: Jump Requested, going to jump pos\n" );
  1468. #/
  1469.             }
  1470.             self.goal_pos = self.jump_pos.origin;
  1471.             self setgoalpos( self.goal_pos );
  1472.             wait 0,5;
  1473.         }
  1474.     }
  1475. }
  1476. else if ( self.zombie_move_speed == "sprint" && isDefined( player ) )
  1477. {
  1478. /#
  1479.     if ( getDvarInt( #"E7121222" ) > 1 )
  1480.     {
  1481.         println( "\n\tMZ: Sprinting\n" );
  1482. #/
  1483.     }
  1484.     self.goal_pos = player.origin;
  1485.     self setgoalpos( self.goal_pos );
  1486.     wait 0,5;
  1487. }
  1488. }
  1489. else if ( distancesquared( self.origin, player.origin ) < level.mechz_aggro_dist_sq )
  1490. {
  1491. /#
  1492. if ( getDvarInt( #"E7121222" ) > 1 )
  1493. {
  1494.     println( "\n\tMZ: Player very close, switching to melee only\n" );
  1495. #/
  1496. }
  1497. self.disable_complex_behaviors = 1;
  1498. }
  1499. else if ( self should_do_claw_attack() )
  1500. {
  1501. self mechz_do_claw_grab();
  1502. }
  1503. }
  1504. else while ( self should_do_flamethrower_attack() )
  1505. {
  1506. self mechz_do_flamethrower_attack();
  1507. }
  1508. /#
  1509. if ( getDvarInt( #"E7121222" ) > 1 )
  1510. {
  1511. println( "\n\tMZ: No special behavior valid, heading after player\n" );
  1512. #/
  1513. }
  1514. self.goal_pos = player.origin;
  1515. if ( isDefined( level.damage_prone_players_override_func ) )
  1516. {
  1517. level thread [[ level.damage_prone_players_override_func ]]();
  1518. }
  1519. else
  1520. {
  1521. self thread damage_prone_players();
  1522. }
  1523. mechz_start_basic_find_flesh();
  1524. wait 0,5;
  1525. }
  1526. }
  1527.  
  1528. damage_prone_players()
  1529. {
  1530.     self endon( "death" );
  1531.     a_players = getplayers();
  1532.     _a1878 = a_players;
  1533.     _k1878 = getFirstArrayKey( _a1878 );
  1534.     while ( isDefined( _k1878 ) )
  1535.     {
  1536.         player = _a1878[ _k1878 ];
  1537.         if ( isDefined( self.favoriteenemy ) && self.favoriteenemy == player )
  1538.         {
  1539.             n_dist = distance2dsquared( player.origin, self.origin );
  1540.             if ( n_dist < 2025 )
  1541.             {
  1542.                 player_z = player.origin[ 2 ];
  1543.                 mechz_z = self.origin[ 2 ];
  1544.                 if ( player_z < mechz_z && ( mechz_z - player_z ) <= 75 )
  1545.                 {
  1546.                     if ( isDefined( self.meleedamage ) )
  1547.                     {
  1548.                         idamage = self.meleedamage;
  1549.                     }
  1550.                     else
  1551.                     {
  1552.                         idamage = 50;
  1553.                     }
  1554.                     player dodamage( idamage, self.origin, self, self, "none", "MOD_MELEE" );
  1555.                 }
  1556.             }
  1557.         }
  1558.         _k1878 = getNextArrayKey( _a1878, _k1878 );
  1559.     }
  1560. }
  1561.  
  1562. melee_anim_func()
  1563. {
  1564.     self.next_leap_time = getTime() + 1500;
  1565. }
  1566.  
  1567. mechz_launch_armor_piece()
  1568. {
  1569.     if ( !isDefined( self.next_armor_piece ) )
  1570.     {
  1571.         self.next_armor_piece = 0;
  1572.     }
  1573.     if ( !isDefined( self.armor_state ) || self.next_armor_piece >= self.armor_state.size )
  1574.     {
  1575. /#
  1576.         println( "Trying to launch armor piece after all pieces have already been launched!" );
  1577. #/
  1578.         return;
  1579.     }
  1580.     if ( isDefined( self.armor_state[ self.next_armor_piece ].model ) )
  1581.     {
  1582.         self detach( self.armor_state[ self.next_armor_piece ].model, self.armor_state[ self.next_armor_piece ].tag );
  1583.     }
  1584.     self.fx_field |= 1 << self.armor_state[ self.next_armor_piece ].index;
  1585.     self setclientfield( "mechz_fx", self.fx_field );
  1586.     if ( sndmechzisnetworksafe( "destruction" ) )
  1587.     {
  1588.         self playsound( "zmb_ai_mechz_destruction" );
  1589.     }
  1590.     self.next_armor_piece++;
  1591. }
  1592.  
  1593. mechz_damage_override( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, shitloc, poffsettime, boneindex )
  1594. {
  1595.     num_tiers = level.mechz_armor_info.size + 1;
  1596.     old_health_tier = int( ( num_tiers * self.health ) / self.maxhealth );
  1597.     bonename = getpartname( "c_zom_mech_body", boneindex );
  1598.     if ( isDefined( attacker ) && isalive( attacker ) && isplayer( attacker ) || level.zombie_vars[ attacker.team ][ "zombie_insta_kill" ] && isDefined( attacker.personal_instakill ) && attacker.personal_instakill )
  1599.     {
  1600.         n_mechz_damage_percent = 1;
  1601.         n_mechz_headshot_modifier = 2;
  1602.     }
  1603.     else
  1604.     {
  1605.         n_mechz_damage_percent = level.mechz_damage_percent;
  1606.         n_mechz_headshot_modifier = 1;
  1607.     }
  1608.     if ( isDefined( weapon ) && is_weapon_shotgun( weapon ) )
  1609.     {
  1610.         n_mechz_damage_percent *= level.mechz_shotgun_damage_mod;
  1611.         n_mechz_headshot_modifier *= level.mechz_shotgun_damage_mod;
  1612.     }
  1613.     if ( damage <= 10 )
  1614.     {
  1615.         n_mechz_damage_percent = 1;
  1616.     }
  1617.     if ( is_explosive_damage( meansofdeath ) || issubstr( weapon, "staff" ) )
  1618.     {
  1619.         if ( n_mechz_damage_percent < 0,5 )
  1620.         {
  1621.             n_mechz_damage_percent = 0,5;
  1622.         }
  1623.         if ( isDefined( self.has_helmet ) && !self.has_helmet && issubstr( weapon, "staff" ) && n_mechz_damage_percent < 1 )
  1624.         {
  1625.             n_mechz_damage_percent = 1;
  1626.         }
  1627.         final_damage = damage * n_mechz_damage_percent;
  1628.         if ( !isDefined( self.explosive_dmg_taken ) )
  1629.         {
  1630.             self.explosive_dmg_taken = 0;
  1631.         }
  1632.         self.explosive_dmg_taken += final_damage;
  1633.         self.helmet_dmg += final_damage;
  1634.         if ( isDefined( self.explosive_dmg_taken_on_grab_start ) )
  1635.         {
  1636.             if ( isDefined( self.e_grabbed ) && ( self.explosive_dmg_taken - self.explosive_dmg_taken_on_grab_start ) > level.mechz_explosive_dmg_to_cancel_claw )
  1637.             {
  1638.                 if ( isDefined( self.has_helmet ) && self.has_helmet || self.helmet_dmg < self.helmet_dmg_for_removal && isDefined( self.has_helmet ) && !self.has_helmet )
  1639.                 {
  1640.                     self thread mechz_claw_shot_pain_reaction();
  1641.                 }
  1642.                 self thread ent_released_from_claw_grab_achievement( attacker, self.e_grabbed );
  1643.                 self thread mechz_claw_release();
  1644.             }
  1645.         }
  1646.     }
  1647.     else
  1648.     {
  1649.         if ( shitloc != "head" && shitloc != "helmet" )
  1650.         {
  1651.             if ( bonename == "tag_powersupply" )
  1652.             {
  1653.                 final_damage = damage * n_mechz_damage_percent;
  1654.                 if ( isDefined( self.powerplant_covered ) && !self.powerplant_covered )
  1655.                 {
  1656.                     self.powerplant_dmg += final_damage;
  1657.                 }
  1658.                 else
  1659.                 {
  1660.                     self.powerplant_cover_dmg += final_damage;
  1661.                 }
  1662.             }
  1663.             if ( isDefined( self.e_grabbed ) && shitloc != "left_hand" || shitloc == "left_arm_lower" && shitloc == "left_arm_upper" )
  1664.             {
  1665.                 if ( isDefined( self.e_grabbed ) )
  1666.                 {
  1667.                     self thread mechz_claw_shot_pain_reaction();
  1668.                 }
  1669.                 self thread ent_released_from_claw_grab_achievement( attacker, self.e_grabbed );
  1670.                 self thread mechz_claw_release( 1 );
  1671.             }
  1672.             final_damage = damage * n_mechz_damage_percent;
  1673.         }
  1674.         else
  1675.         {
  1676.             if ( isDefined( self.has_helmet ) && !self.has_helmet )
  1677.             {
  1678.                 final_damage = damage * n_mechz_headshot_modifier;
  1679.             }
  1680.             else
  1681.             {
  1682.                 final_damage = damage * n_mechz_damage_percent;
  1683.                 self.helmet_dmg += final_damage;
  1684.             }
  1685.         }
  1686.     }
  1687.     if ( !isDefined( weapon ) || weapon == "none" )
  1688.     {
  1689.         if ( !isplayer( attacker ) )
  1690.         {
  1691.             final_damage = 0;
  1692.         }
  1693.     }
  1694.     new_health_tier = int( ( num_tiers * ( self.health - final_damage ) ) / self.maxhealth );
  1695.     while ( old_health_tier > new_health_tier )
  1696.     {
  1697.         while ( old_health_tier > new_health_tier )
  1698.         {
  1699. /#
  1700.             if ( getDvarInt( #"E7121222" ) > 0 )
  1701.             {
  1702.                 println( "\nMZ: Old tier: " + old_health_tier + "   New Health Tier: " + new_health_tier + "   Launching armor piece" );
  1703. #/
  1704.             }
  1705.             if ( old_health_tier < num_tiers )
  1706.             {
  1707.                 self mechz_launch_armor_piece();
  1708.             }
  1709.             old_health_tier--;
  1710.  
  1711.         }
  1712.     }
  1713.     if ( isDefined( self.has_helmet ) && self.has_helmet && self.helmet_dmg >= self.helmet_dmg_for_removal )
  1714.     {
  1715.         self.has_helmet = 0;
  1716.         self detach( "c_zom_mech_faceplate", "J_Helmet" );
  1717.         if ( sndmechzisnetworksafe( "destruction" ) )
  1718.         {
  1719.             self playsound( "zmb_ai_mechz_destruction" );
  1720.         }
  1721.         if ( sndmechzisnetworksafe( "angry" ) )
  1722.         {
  1723.             self playsound( "zmb_ai_mechz_vox_angry" );
  1724.         }
  1725.         self.fx_field |= 1024;
  1726.         self.fx_field &= 2048;
  1727.         self setclientfield( "mechz_fx", self.fx_field );
  1728.         if ( isDefined( self.not_interruptable ) && !self.not_interruptable && isDefined( self.is_traversing ) && !self.is_traversing )
  1729.         {
  1730.             self mechz_interrupt();
  1731.             self animscripted( self.origin, self.angles, "zm_pain_faceplate" );
  1732.             self maps/mp/animscripts/zm_shared::donotetracks( "pain_anim_faceplate" );
  1733.         }
  1734.         self thread shoot_mechz_head_vo();
  1735.     }
  1736.     if ( isDefined( self.powerplant_covered ) && self.powerplant_covered && self.powerplant_cover_dmg >= self.powerplant_cover_dmg_for_removal )
  1737.     {
  1738.         self.powerplant_covered = 0;
  1739.         self detach( "c_zom_mech_powersupply_cap", "tag_powersupply" );
  1740.         cap_model = spawn( "script_model", self gettagorigin( "tag_powersupply" ) );
  1741.         cap_model.angles = self gettagangles( "tag_powersupply" );
  1742.         cap_model setmodel( "c_zom_mech_powersupply_cap" );
  1743.         cap_model physicslaunch( cap_model.origin, anglesToForward( cap_model.angles ) );
  1744.         cap_model thread mechz_delayed_item_delete();
  1745.         if ( sndmechzisnetworksafe( "destruction" ) )
  1746.         {
  1747.             self playsound( "zmb_ai_mechz_destruction" );
  1748.         }
  1749.         if ( isDefined( self.not_interruptable ) && !self.not_interruptable && isDefined( self.is_traversing ) && !self.is_traversing )
  1750.         {
  1751.             self mechz_interrupt();
  1752.             self animscripted( self.origin, self.angles, "zm_pain_powercore" );
  1753.             self maps/mp/animscripts/zm_shared::donotetracks( "pain_anim_powercore" );
  1754.         }
  1755.     }
  1756.     else
  1757.     {
  1758.         if ( isDefined( self.powerplant_covered ) && !self.powerplant_covered && isDefined( self.has_powerplant ) && self.has_powerplant && self.powerplant_dmg >= self.powerplant_dmg_for_destroy )
  1759.         {
  1760.             self.has_powerplant = 0;
  1761.             self thread mechz_stun( level.mechz_powerplant_stun_time );
  1762.             if ( sndmechzisnetworksafe( "destruction" ) )
  1763.             {
  1764.                 self playsound( "zmb_ai_mechz_destruction" );
  1765.             }
  1766.         }
  1767.     }
  1768. /#
  1769.     if ( getDvarInt( #"E7121222" ) > 0 )
  1770.     {
  1771.         println( "\nMZ: Doing " + final_damage + " damage to mechz,   Health Remaining: " + self.health );
  1772.         if ( self.helmet_dmg < self.helmet_dmg_for_removal )
  1773.         {
  1774.             println( "\nMZ: Current helmet dmg: " + self.helmet_dmg + "    Required helmet dmg: " + self.helmet_dmg_for_removal );
  1775. #/
  1776.         }
  1777.     }
  1778.     return final_damage;
  1779. }
  1780.  
  1781. mechz_non_attacker_damage_override( damage, weapon, attacker )
  1782. {
  1783.     if ( attacker == level.vh_tank )
  1784.     {
  1785.         self thread mechz_tank_hit_callback();
  1786.     }
  1787.     return 0;
  1788. }
  1789.  
  1790. mechz_instakill_override()
  1791. {
  1792.     return;
  1793. }
  1794.  
  1795. mechz_nuke_override()
  1796. {
  1797.     self endon( "death" );
  1798.     wait randomfloatrange( 0,1, 0,7 );
  1799.     self playsound( "evt_nuked" );
  1800.     self dodamage( self.health * 0,25, self.origin );
  1801.     return;
  1802. }
  1803.  
  1804. mechz_set_locomotion_speed()
  1805. {
  1806.     self endon( "death" );
  1807.     self.prev_move_speed = self.zombie_move_speed;
  1808.     if ( !isDefined( self.favoriteenemy ) )
  1809.     {
  1810.         self.zombie_move_speed = "walk";
  1811.     }
  1812.     else if ( isDefined( self.force_run ) && self.force_run )
  1813.     {
  1814.         self.zombie_move_speed = "run";
  1815.     }
  1816.     else
  1817.     {
  1818.         if ( isDefined( self.force_sprint ) && self.force_sprint )
  1819.         {
  1820.             self.zombie_move_speed = "sprint";
  1821.         }
  1822.         else
  1823.         {
  1824.             if ( isDefined( self.favoriteenemy ) && self.favoriteenemy entity_on_tank() && isDefined( level.vh_tank ) && level.vh_tank ent_flag( "tank_activated" ) )
  1825.             {
  1826.                 self.zombie_move_speed = "run";
  1827.             }
  1828.             else
  1829.             {
  1830.                 if ( isDefined( self.favoriteenemy ) && distancesquared( self.origin, self.favoriteenemy.origin ) > level.mechz_dist_for_sprint )
  1831.                 {
  1832.                     self.zombie_move_speed = "run";
  1833.                 }
  1834.                 else
  1835.                 {
  1836.                     if ( isDefined( self.has_powerplant ) && !self.has_powerplant )
  1837.                     {
  1838.                         self.zombie_move_speed = "walk";
  1839.                     }
  1840.                     else
  1841.                     {
  1842.                         self.zombie_move_speed = "walk";
  1843.                     }
  1844.                 }
  1845.             }
  1846.         }
  1847.     }
  1848.     if ( self.zombie_move_speed == "sprint" && self.prev_move_speed != "sprint" )
  1849.     {
  1850.         self mechz_interrupt();
  1851.         self animscripted( self.origin, self.angles, "zm_sprint_intro" );
  1852.         self maps/mp/animscripts/zm_shared::donotetracks( "jump_anim" );
  1853.     }
  1854.     else
  1855.     {
  1856.         if ( self.zombie_move_speed != "sprint" && self.prev_move_speed == "sprint" )
  1857.         {
  1858.             self animscripted( self.origin, self.angles, "zm_sprint_outro" );
  1859.             self maps/mp/animscripts/zm_shared::donotetracks( "jump_anim" );
  1860.         }
  1861.     }
  1862.     self set_zombie_run_cycle( self.zombie_move_speed );
  1863. }
  1864.  
  1865. response_to_air_raid_siren_vo()
  1866. {
  1867.     wait 3;
  1868.     a_players = getplayers();
  1869.     if ( a_players.size == 0 )
  1870.     {
  1871.         return;
  1872.     }
  1873.     a_players = array_randomize( a_players );
  1874.     _a2280 = a_players;
  1875.     _k2280 = getFirstArrayKey( _a2280 );
  1876.     while ( isDefined( _k2280 ) )
  1877.     {
  1878.         player = _a2280[ _k2280 ];
  1879.         if ( is_player_valid( player ) )
  1880.         {
  1881.             if ( isDefined( player.dontspeak ) && !player.dontspeak )
  1882.             {
  1883.                 if ( !isDefined( level.air_raid_siren_count ) )
  1884.                 {
  1885.                     player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "siren_1st_time" );
  1886.                     level.air_raid_siren_count = 1;
  1887.                     while ( isDefined( player ) && isDefined( player.isspeaking ) && player.isspeaking )
  1888.                     {
  1889.                         wait 0,1;
  1890.                     }
  1891.                     level thread start_see_mech_zombie_vo();
  1892.                     return;
  1893.                 }
  1894.                 else if ( level.mechz_zombie_per_round == 1 )
  1895.                 {
  1896.                     player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "siren_generic" );
  1897.                     return;
  1898.                 }
  1899.                 else player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "multiple_mechs" );
  1900.                 return;
  1901.             }
  1902.         }
  1903.         else
  1904.         {
  1905.             _k2280 = getNextArrayKey( _a2280, _k2280 );
  1906.         }
  1907.     }
  1908. }
  1909.  
  1910. start_see_mech_zombie_vo()
  1911. {
  1912.     wait 1;
  1913.     a_zombies = getaispeciesarray( level.zombie_team, "all" );
  1914.     _a2321 = a_zombies;
  1915.     _k2321 = getFirstArrayKey( _a2321 );
  1916.     while ( isDefined( _k2321 ) )
  1917.     {
  1918.         zombie = _a2321[ _k2321 ];
  1919.         if ( isDefined( zombie.is_mechz ) && zombie.is_mechz )
  1920.         {
  1921.             ai_mechz = zombie;
  1922.         }
  1923.         _k2321 = getNextArrayKey( _a2321, _k2321 );
  1924.     }
  1925.     a_players = getplayers();
  1926.     if ( a_players.size == 0 )
  1927.     {
  1928.         return;
  1929.     }
  1930.     while ( isalive( ai_mechz ) )
  1931.     {
  1932.         _a2337 = a_players;
  1933.         _k2337 = getFirstArrayKey( _a2337 );
  1934.         while ( isDefined( _k2337 ) )
  1935.         {
  1936.             player = _a2337[ _k2337 ];
  1937.             player thread player_looking_at_mechz_watcher( ai_mechz );
  1938.             _k2337 = getNextArrayKey( _a2337, _k2337 );
  1939.         }
  1940.     }
  1941. }
  1942.  
  1943. player_looking_at_mechz_watcher( ai_mechz )
  1944. {
  1945.     self endon( "disconnect" );
  1946.     ai_mechz endon( "death" );
  1947.     level endon( "first_mech_zombie_seen" );
  1948.     while ( 1 )
  1949.     {
  1950.         if ( distancesquared( self.origin, ai_mechz.origin ) < 1000000 )
  1951.         {
  1952.             if ( self is_player_looking_at( ai_mechz.origin + vectorScale( ( 0, 0, 1 ), 60 ), 0,75 ) )
  1953.             {
  1954.                 if ( isDefined( self.dontspeak ) && !self.dontspeak )
  1955.                 {
  1956.                     self maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "discover_mech" );
  1957.                     level notify( "first_mech_zombie_seen" );
  1958.                     return;
  1959.                 }
  1960.             }
  1961.         }
  1962.         else
  1963.         {
  1964.             wait 0,1;
  1965.         }
  1966.     }
  1967. }
  1968.  
  1969. mechz_grabbed_played_vo( ai_mechz )
  1970. {
  1971.     self endon( "disconnect" );
  1972.     self maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "mech_grab" );
  1973.     while ( isDefined( self ) && isDefined( self.isspeaking ) && self.isspeaking )
  1974.     {
  1975.         wait 0,1;
  1976.     }
  1977.     wait 1;
  1978.     if ( isalive( ai_mechz ) && isDefined( ai_mechz.e_grabbed ) )
  1979.     {
  1980.         ai_mechz thread play_shoot_arm_hint_vo();
  1981.     }
  1982. }
  1983.  
  1984. play_shoot_arm_hint_vo()
  1985. {
  1986.     self endon( "death" );
  1987.     while ( 1 )
  1988.     {
  1989.         if ( !isDefined( self.e_grabbed ) )
  1990.         {
  1991.             return;
  1992.         }
  1993.         a_players = getplayers();
  1994.         _a2399 = a_players;
  1995.         _k2399 = getFirstArrayKey( _a2399 );
  1996.         while ( isDefined( _k2399 ) )
  1997.         {
  1998.             player = _a2399[ _k2399 ];
  1999.             if ( player == self.e_grabbed )
  2000.             {
  2001.             }
  2002.             else
  2003.             {
  2004.                 if ( distancesquared( self.origin, player.origin ) < 1000000 )
  2005.                 {
  2006.                     if ( player is_player_looking_at( self.origin + vectorScale( ( 0, 0, 1 ), 60 ), 0,75 ) )
  2007.                     {
  2008.                         if ( isDefined( player.dontspeak ) && !player.dontspeak )
  2009.                         {
  2010.                             player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "shoot_mech_arm" );
  2011.                             return;
  2012.                         }
  2013.                     }
  2014.                 }
  2015.             }
  2016.             _k2399 = getNextArrayKey( _a2399, _k2399 );
  2017.         }
  2018.         wait 0,1;
  2019.     }
  2020. }
  2021.  
  2022. mechz_hint_vo()
  2023. {
  2024.     self endon( "death" );
  2025.     wait 30;
  2026.     while ( 1 )
  2027.     {
  2028.         while ( self.health > ( self.maxhealth * 0,5 ) )
  2029.         {
  2030.             wait 1;
  2031.         }
  2032.         while ( isDefined( self.powerplant_covered ) && !self.powerplant_covered )
  2033.         {
  2034.             wait 1;
  2035.         }
  2036.         a_players = getplayers();
  2037.         _a2444 = a_players;
  2038.         _k2444 = getFirstArrayKey( _a2444 );
  2039.         while ( isDefined( _k2444 ) )
  2040.         {
  2041.             player = _a2444[ _k2444 ];
  2042.             if ( isDefined( self.e_grabbed ) && self.e_grabbed == player )
  2043.             {
  2044.             }
  2045.             else
  2046.             {
  2047.                 if ( distancesquared( self.origin, player.origin ) < 1000000 )
  2048.                 {
  2049.                     if ( player is_player_looking_at( self.origin + vectorScale( ( 0, 0, 1 ), 60 ), 0,75 ) )
  2050.                     {
  2051.                         if ( isDefined( player.dontspeak ) && !player.dontspeak )
  2052.                         {
  2053.                             player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "shoot_mech_power" );
  2054.                             return;
  2055.                         }
  2056.                     }
  2057.                 }
  2058.             }
  2059.             _k2444 = getNextArrayKey( _a2444, _k2444 );
  2060.         }
  2061.         wait 0,1;
  2062.     }
  2063. }
  2064.  
  2065. shoot_mechz_head_vo()
  2066. {
  2067.     self endon( "death" );
  2068.     a_players = getplayers();
  2069.     _a2473 = a_players;
  2070.     _k2473 = getFirstArrayKey( _a2473 );
  2071.     while ( isDefined( _k2473 ) )
  2072.     {
  2073.         player = _a2473[ _k2473 ];
  2074.         if ( isDefined( self.e_grabbed ) && self.e_grabbed == player )
  2075.         {
  2076.         }
  2077.         else
  2078.         {
  2079.             if ( distancesquared( self.origin, player.origin ) < 1000000 )
  2080.             {
  2081.                 if ( player is_player_looking_at( self.origin + vectorScale( ( 0, 0, 1 ), 60 ), 0,75 ) )
  2082.                 {
  2083.                     if ( isDefined( player.dontspeak ) && !player.dontspeak )
  2084.                     {
  2085.                         player maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "shoot_mech_head" );
  2086.                         return;
  2087.                     }
  2088.                 }
  2089.             }
  2090.         }
  2091.         _k2473 = getNextArrayKey( _a2473, _k2473 );
  2092.     }
  2093. }
  2094.  
  2095. mechz_jump_vo()
  2096. {
  2097.     a_players = getplayers();
  2098.     _a2497 = a_players;
  2099.     _k2497 = getFirstArrayKey( _a2497 );
  2100.     while ( isDefined( _k2497 ) )
  2101.     {
  2102.         player = _a2497[ _k2497 ];
  2103.         if ( distancesquared( self.origin, player.origin ) < 1000000 )
  2104.         {
  2105.             if ( player is_player_looking_at( self.origin + vectorScale( ( 0, 0, 1 ), 60 ), 0,5 ) )
  2106.             {
  2107.                 if ( isDefined( player.dontspeak ) && !player.dontspeak )
  2108.                 {
  2109.                     player delay_thread( 3, ::maps/mp/zombies/_zm_audio::create_and_play_dialog, "general", "rspnd_mech_jump" );
  2110.                     return;
  2111.                 }
  2112.             }
  2113.         }
  2114.         _k2497 = getNextArrayKey( _a2497, _k2497 );
  2115.     }
  2116. }
  2117.  
  2118. mechz_stomped_by_giant_robot_vo()
  2119. {
  2120.     self endon( "death" );
  2121.     wait 5;
  2122.     a_players = getplayers();
  2123.     _a2520 = a_players;
  2124.     _k2520 = getFirstArrayKey( _a2520 );
  2125.     while ( isDefined( _k2520 ) )
  2126.     {
  2127.         player = _a2520[ _k2520 ];
  2128.         if ( distancesquared( self.origin, player.origin ) < 1000000 )
  2129.         {
  2130.             if ( player is_player_looking_at( self.origin + vectorScale( ( 0, 0, 1 ), 60 ), 0,75 ) )
  2131.             {
  2132.                 if ( isDefined( player.dontspeak ) && !player.dontspeak )
  2133.                 {
  2134.                     player thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "robot_crush_mech" );
  2135.                     return;
  2136.                 }
  2137.             }
  2138.         }
  2139.         _k2520 = getNextArrayKey( _a2520, _k2520 );
  2140.     }
  2141. }
  2142.  
  2143. init_anim_rate()
  2144. {
  2145.     self setclientfield( "anim_rate", 1 );
  2146.     n_rate = self getclientfield( "anim_rate" );
  2147.     self setentityanimrate( n_rate );
  2148. }
  2149.  
  2150. sndmechzisnetworksafe( type )
  2151. {
  2152.     if ( !isDefined( level.sndmechz ) )
  2153.     {
  2154.         level.sndmechz = [];
  2155.     }
  2156.     if ( !isDefined( level.sndmechz[ type ] ) )
  2157.     {
  2158.         level thread sndmechznetworkchoke( type );
  2159.     }
  2160.     if ( level.sndmechz[ type ] > 1 )
  2161.     {
  2162.         return 0;
  2163.     }
  2164.     level.sndmechz[ type ]++;
  2165.     return 1;
  2166. }
  2167.  
  2168. sndmechznetworkchoke( type )
  2169. {
  2170.     while ( 1 )
  2171.     {
  2172.         level.sndmechz[ type ] = 0;
  2173.         wait_network_frame();
  2174.     }
  2175. }
Add Comment
Please, Sign In to add comment