burc_2004

_zm_ai_leaper.gsc

Oct 21st, 2015
172
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 34.76 KB | None | 0 0
  1. #include maps/mp/zm_highrise_elevators;
  2. #include maps/mp/zombies/_zm_audio;
  3. #include maps/mp/zombies/_zm_powerups;
  4. #include maps/mp/gametypes_zm/_globallogic_score;
  5. #include maps/mp/zombies/_zm_zonemgr;
  6. #include maps/mp/zombies/_zm_ai_basic;
  7. #include maps/mp/animscripts/zm_shared;
  8. #include maps/mp/zombies/_zm_score;
  9. #include maps/mp/zombies/_zm_spawner;
  10. #include maps/mp/animscripts/zm_utility;
  11. #include maps/mp/zombies/_zm_utility;
  12. #include maps/mp/_utility;
  13. #include common_scripts/utility;
  14.  
  15. precache()
  16. {
  17.     precache_fx();
  18. }
  19.  
  20. precache_fx()
  21. {
  22.     level._effect[ "leaper_death" ] = loadfx( "maps/zombie/fx_zmb_leaper_death" );
  23.     level._effect[ "leaper_spawn" ] = loadfx( "maps/zombie/fx_zmb_leaper_spawn" );
  24.     level._effect[ "leaper_trail" ] = loadfx( "maps/zombie/fx_zmb_leaper_trail" );
  25.     level._effect[ "leaper_walk" ] = loadfx( "maps/zombie/fx_zmb_leaper_walk" );
  26.     level._effect[ "leaper_wall_impact" ] = loadfx( "maps/zombie/fx_zmb_leaper_wall_impact" );
  27. }
  28.  
  29. init()
  30. {
  31.     leaper_spawner_init();
  32.     leaper_calc_anim_offsets();
  33.     if ( !isDefined( level.leapers_per_player ) )
  34.     {
  35.         level.leapers_per_player = 2;
  36.     }
  37.     level.no_jump_triggers = getentarray( "leaper_no_jump_trigger", "targetname" );
  38. }
  39.  
  40. leaper_calc_anim_offsets()
  41. {
  42.     leaper = spawn_zombie( level.leaper_spawners[ 0 ] );
  43.     if ( isDefined( leaper ) )
  44.     {
  45.         level.leaper_anim = spawnstruct();
  46.         asd = "zm_wall_up";
  47.         anim_id = leaper getanimfromasd( asd, 0 );
  48.         level.leaper_anim.up_mid = getmovedelta( anim_id, 0, 0,488 ) + vectorScale( ( 0, 0, 1 ), 6 );
  49.         level.leaper_anim.up_end = getmovedelta( anim_id, 0, 1 );
  50.         asd = "zm_wall_left";
  51.         anim_id = leaper getanimfromasd( asd, 0 );
  52.         wallhit_time = getnotetracktimes( anim_id, "wallhit" );
  53.         level.leaper_anim.left_mid = getmovedelta( anim_id, 0, wallhit_time[ 0 ] ) + vectorScale( ( 0, 0, 1 ), 48 );
  54.         level.leaper_anim.left_end = getmovedelta( anim_id, 0, 1 );
  55.         asd = "zm_wall_left_large";
  56.         anim_id = leaper getanimfromasd( asd, 0 );
  57.         wallhit_time = getnotetracktimes( anim_id, "wallhit" );
  58.         level.leaper_anim.left_large_mid = getmovedelta( anim_id, 0, wallhit_time[ 0 ] ) + vectorScale( ( 0, 0, 1 ), 48 );
  59.         level.leaper_anim.left_large_end = getmovedelta( anim_id, 0, 1 );
  60.         asd = "zm_wall_right";
  61.         anim_id = leaper getanimfromasd( asd, 0 );
  62.         wallhit_time = getnotetracktimes( anim_id, "wallhit" );
  63.         level.leaper_anim.right_mid = getmovedelta( anim_id, 0, wallhit_time[ 0 ] ) + vectorScale( ( 0, 0, 1 ), 48 );
  64.         level.leaper_anim.right_end = getmovedelta( anim_id, 0, 1 );
  65.         asd = "zm_wall_right_large";
  66.         anim_id = leaper getanimfromasd( asd, 0 );
  67.         wallhit_time = getnotetracktimes( anim_id, "wallhit" );
  68.         level.leaper_anim.right_large_mid = getmovedelta( anim_id, 0, wallhit_time[ 0 ] ) + vectorScale( ( 0, 0, 1 ), 48 );
  69.         level.leaper_anim.right_large_end = getmovedelta( anim_id, 0, 1 );
  70.         leaper delete();
  71.     }
  72. }
  73.  
  74. leaper_spawner_init()
  75. {
  76.     level.leaper_spawners = getentarray( "leaper_zombie_spawner", "script_noteworthy" );
  77.     if ( level.leaper_spawners.size == 0 )
  78.     {
  79.         return;
  80.     }
  81.     i = 0;
  82.     while ( i < level.leaper_spawners.size )
  83.     {
  84.         level.leaper_spawners[ i ].is_enabled = 1;
  85.         level.leaper_spawners[ i ].script_forcespawn = 1;
  86.         i++;
  87.     }
  88. /#
  89.     assert( level.leaper_spawners.size > 0 );
  90. #/
  91.     level.leaper_health = 100;
  92.     array_thread( level.leaper_spawners, ::add_spawn_function, ::leaper_init );
  93. /#
  94.     if ( isDefined( level.leaper_rounds_enabled ) && level.leaper_rounds_enabled )
  95.     {
  96.         level thread leaper_spawner_zone_check();
  97. #/
  98.     }
  99. }
  100.  
  101. leaper_spawner_zone_check()
  102. {
  103.     flag_wait( "zones_initialized" );
  104.     str_zone_list = "";
  105.     str_spawn_count_list = "";
  106.     n_zones_missing_spawners = 0;
  107.     a_zones = getarraykeys( level.zones );
  108.     i = 0;
  109.     while ( i < a_zones.size )
  110.     {
  111.         if ( level.zones[ a_zones[ i ] ].leaper_locations.size == 0 )
  112.         {
  113.             n_zones_missing_spawners++;
  114.             str_zone_list = ( str_zone_list + "\n " ) + a_zones[ i ];
  115.         }
  116.         str_spawn_count_list = str_spawn_count_list + a_zones[ i ] + ": " + level.zones[ a_zones[ i ] ].leaper_locations.size + "\n";
  117.         i++;
  118.     }
  119. /#
  120.     assert( n_zones_missing_spawners == 0, "All zones require at least one leaper spawn point." + n_zones_missing_spawners + " zones are missing leaper spawners. They are: " + str_zone_list );
  121. #/
  122. /#
  123.     println( "========== LEAPER SPAWN COUNT PER ZONE ===========" );
  124.     println( str_spawn_count_list );
  125.     println( "==================================================" );
  126. #/
  127. }
  128.  
  129. leaper_init()
  130. {
  131.     self endon( "death" );
  132.     level endon( "intermission" );
  133.     self.animname = "leaper_zombie";
  134.     self.audio_type = "leaper";
  135.     self.has_legs = 1;
  136.     self.ignore_all_poi = 1;
  137.     self.is_leaper = 1;
  138.     self.melee_anim_func = ::melee_anim_func;
  139.     self.meleedamage = 30;
  140.     recalc_zombie_array();
  141.     if ( isDefined( self.spawn_point ) )
  142.     {
  143.         spot = self.spawn_point;
  144.         if ( !isDefined( spot.angles ) )
  145.         {
  146.             spot.angles = ( 0, 0, 1 );
  147.         }
  148.         self forceteleport( spot.origin, spot.angles );
  149.     }
  150.     self playsound( "zmb_vocals_leaper_spawn" );
  151.     self set_zombie_run_cycle( "run" );
  152.     self.state = "init";
  153.     self thread leaper_think();
  154.     self thread leaper_spawn_failsafe();
  155.     self thread leaper_traverse_watcher();
  156.     self.maxhealth = level.leaper_health;
  157.     self.health = level.leaper_health;
  158.     self setphysparams( 15, 0, 24 );
  159.     self.zombie_init_done = 1;
  160.     self notify( "zombie_init_done" );
  161.     self.allowpain = 0;
  162.     self thread play_ambient_leaper_vocals();
  163.     self animmode( "normal" );
  164.     self orientmode( "face enemy" );
  165.     self maps/mp/zombies/_zm_spawner::zombie_setup_attack_properties();
  166.     self maps/mp/zombies/_zm_spawner::zombie_complete_emerging_into_playable_area();
  167.     self setfreecameralockonallowed( 0 );
  168.     if ( isDefined( self.spawn_point.script_parameters ) || self.spawn_point.script_parameters == "emerge_bottom" && self.spawn_point.script_parameters == "emerge_top" )
  169.     {
  170.         self thread do_leaper_emerge( self.spawn_point );
  171.     }
  172.     self thread leaper_death();
  173.     self thread leaper_check_zone();
  174.     self thread leaper_check_no_jump();
  175.     self thread leaper_watch_enemy();
  176.     self.combat_animmode = ::leaper_combat_animmode;
  177.     level thread maps/mp/zombies/_zm_spawner::zombie_death_event( self );
  178.     self thread maps/mp/zombies/_zm_spawner::enemy_death_detection();
  179. }
  180.  
  181. play_ambient_leaper_vocals()
  182. {
  183.     self endon( "death" );
  184.     wait randomintrange( 2, 4 );
  185.     while ( 1 )
  186.     {
  187.         if ( isDefined( self ) )
  188.         {
  189.             if ( isDefined( self.favoriteenemy ) && distance( self.origin, self.favoriteenemy.origin ) <= 150 )
  190.             {
  191.                 break;
  192.             }
  193.             else
  194.             {
  195.                 self playsound( "zmb_vocals_leaper_ambience" );
  196.             }
  197.         }
  198.         wait randomfloatrange( 1, 1,5 );
  199.     }
  200. }
  201.  
  202. leaper_death()
  203. {
  204.     self endon( "leaper_cleanup" );
  205.     self waittill( "death" );
  206.     self leaper_stop_trail_fx();
  207.     self playsound( "zmb_vocals_leaper_death" );
  208.     playfx( level._effect[ "leaper_death" ], self.origin );
  209.     if ( get_current_zombie_count() == 0 && level.zombie_total == 0 )
  210.     {
  211.         level.last_leaper_origin = self.origin;
  212.         level notify( "last_leaper_down" );
  213.     }
  214.     if ( isplayer( self.attacker ) )
  215.     {
  216.         event = "death";
  217.         if ( issubstr( self.damageweapon, "knife_ballistic_" ) )
  218.         {
  219.             event = "ballistic_knife_death";
  220.         }
  221.         self.attacker thread do_player_general_vox( "general", "leaper_killed", 20, 20 );
  222.         self.attacker maps/mp/zombies/_zm_score::player_add_points( event, self.damagemod, self.damagelocation, 1 );
  223.     }
  224. }
  225.  
  226. leaper_think()
  227. {
  228.     self endon( "death" );
  229.     while ( 1 )
  230.     {
  231.         switch( self.state )
  232.         {
  233.             case "init":
  234.                 leaper_building_jump();
  235.                 break;
  236.             case "chasing":
  237.                 leaper_check_wall();
  238.                 break;
  239.             case "leaping":
  240.             }
  241.             wait 0,1;
  242.         }
  243.     }
  244. }
  245.  
  246. leaper_can_use_anim( local_mid, local_end, dir )
  247. {
  248.     start = self.origin;
  249.     mid = self localtoworldcoords( local_mid );
  250.     end = self localtoworldcoords( local_end );
  251.     real_mid = mid;
  252.     forward_dist = length( end - start ) * 0,5;
  253.     forward_vec = vectornormalize( end - start );
  254.     temp_org = start + vectorScale( forward_vec, forward_dist );
  255.     forward_org = ( temp_org[ 0 ], temp_org[ 1 ], real_mid[ 2 ] );
  256.     end_top = end + vectorScale( ( 0, 0, 1 ), 24 );
  257.     end_bottom = end + vectorScale( ( 0, 0, 1 ), 60 );
  258.     trace = bullettrace( start, mid, 1, self );
  259.     if ( isDefined( trace[ "entity" ] ) )
  260.     {
  261.         return 0;
  262.     }
  263.     if ( isDefined( trace[ "fraction" ] ) && trace[ "fraction" ] < 1 )
  264.     {
  265.         if ( trace[ "fraction" ] < 0,2 )
  266.         {
  267. /#
  268.             if ( getDvarInt( #"5B4FE0B3" ) == 1 )
  269.             {
  270.                 line( start, mid, ( 0, 0, 1 ), 1, 0, 100 );
  271. #/
  272.             }
  273.             return 0;
  274.         }
  275.         if ( dir == "up" )
  276.         {
  277.             if ( trace[ "fraction" ] < 0,9 )
  278.             {
  279.                 return 0;
  280.             }
  281.         }
  282.         mid = trace[ "position" ];
  283. /#
  284.         if ( getDvarInt( #"5B4FE0B3" ) >= 1 )
  285.         {
  286.             line( start, mid, ( 0, 0, 1 ), 1, 0, 100 );
  287. #/
  288.         }
  289.         if ( dir != "up" )
  290.         {
  291.             trace = bullettrace( forward_org, real_mid, 1, self );
  292.             if ( isDefined( trace[ "entity" ] ) )
  293.             {
  294.                 return 0;
  295.             }
  296.             if ( isDefined( trace[ "fraction" ] ) && trace[ "fraction" ] < 1 )
  297.             {
  298. /#
  299.                 if ( getDvarInt( #"5B4FE0B3" ) == 1 )
  300.                 {
  301.                     line( forward_org, real_mid, ( 0, 0, 1 ), 1, 0, 100 );
  302. #/
  303.                 }
  304.             }
  305.             else
  306.             {
  307. /#
  308.                 if ( getDvarInt( #"5B4FE0B3" ) == 1 )
  309.                 {
  310.                     line( forward_org, real_mid, ( 0, 0, 1 ), 1, 0, 100 );
  311. #/
  312.                 }
  313.                 return 0;
  314.             }
  315.         }
  316.     }
  317.     else
  318.     {
  319. /#
  320.         if ( getDvarInt( #"5B4FE0B3" ) == 1 )
  321.         {
  322.             line( start, mid, ( 0, 0, 1 ), 1, 0, 100 );
  323. #/
  324.         }
  325.         return 0;
  326.     }
  327.     trace = bullettrace( mid, end, 1, self );
  328.     if ( isDefined( trace[ "fraction" ] ) && trace[ "fraction" ] < 1 )
  329.     {
  330. /#
  331.         if ( getDvarInt( #"5B4FE0B3" ) == 1 )
  332.         {
  333.             line( mid, end, ( 0, 0, 1 ), 1, 0, 100 );
  334. #/
  335.         }
  336.         return 0;
  337.     }
  338.     else
  339.     {
  340. /#
  341.         if ( getDvarInt( #"5B4FE0B3" ) >= 1 )
  342.         {
  343.             line( mid, end, ( 0, 0, 1 ), 1, 0, 100 );
  344. #/
  345.         }
  346.     }
  347.     trace = bullettrace( end_top, end_bottom, 1, self );
  348.     if ( isDefined( trace[ "fraction" ] ) && trace[ "fraction" ] >= 1 )
  349.     {
  350. /#
  351.         if ( getDvarInt( #"5B4FE0B3" ) == 1 )
  352.         {
  353.             line( end_top, end_bottom, ( 0, 0, 1 ), 1, 0, 100 );
  354. #/
  355.         }
  356.         return 0;
  357.     }
  358.     else
  359.     {
  360. /#
  361.         if ( getDvarInt( #"5B4FE0B3" ) >= 1 )
  362.         {
  363.             line( end_top, end_bottom, ( 0, 0, 1 ), 1, 0, 100 );
  364. #/
  365.         }
  366.     }
  367.     return 1;
  368. }
  369.  
  370. leaper_building_jump()
  371. {
  372.     self endon( "death" );
  373.     if ( isDefined( self.spawn_point.script_string ) && self.spawn_point.script_string != "find_flesh" )
  374.     {
  375.         self animscripted( self.spawn_point.origin, self.spawn_point.angles, "zm_building_leap", self.spawn_point.script_string );
  376.         self maps/mp/animscripts/zm_shared::donotetracks( "building_leap_anim" );
  377.     }
  378.     self thread leaper_playable_area_failsafe();
  379.     self thread maps/mp/zombies/_zm_ai_basic::find_flesh();
  380.     self.state = "chasing";
  381. }
  382.  
  383. leaper_check_wall()
  384. {
  385.     self endon( "death" );
  386.     if ( !isDefined( self.next_leap_time ) )
  387.     {
  388.         self.next_leap_time = getTime() + 500;
  389.     }
  390.     if ( is_true( self.sliding_on_goo ) || is_true( self.is_leaping ) )
  391.     {
  392.         return;
  393.     }
  394.     if ( getTime() > self.next_leap_time && !is_true( self.no_jump ) )
  395.     {
  396.         wall_anim = [];
  397.         if ( self leaper_can_use_anim( level.leaper_anim.up_mid, level.leaper_anim.up_end, "up" ) )
  398.         {
  399.             wall_anim[ wall_anim.size ] = "zm_wall_up";
  400.         }
  401.         if ( self leaper_can_use_anim( level.leaper_anim.left_mid, level.leaper_anim.left_end, "left" ) )
  402.         {
  403.             wall_anim[ wall_anim.size ] = "zm_wall_left";
  404.         }
  405.         else
  406.         {
  407.             if ( self leaper_can_use_anim( level.leaper_anim.left_large_mid, level.leaper_anim.left_large_end, "left_large" ) )
  408.             {
  409.                 wall_anim[ wall_anim.size ] = "zm_wall_left_large";
  410.             }
  411.         }
  412.         if ( self leaper_can_use_anim( level.leaper_anim.right_mid, level.leaper_anim.right_end, "right" ) )
  413.         {
  414.             wall_anim[ wall_anim.size ] = "zm_wall_right";
  415.         }
  416.         else
  417.         {
  418.             if ( self leaper_can_use_anim( level.leaper_anim.right_large_mid, level.leaper_anim.right_large_end, "right_large" ) )
  419.             {
  420.                 wall_anim[ wall_anim.size ] = "zm_wall_right_large";
  421.             }
  422.         }
  423.         if ( !self isinscriptedstate() )
  424.         {
  425.             b_should_play_wall_jump_anim = wall_anim.size > 0;
  426.         }
  427.         if ( b_should_play_wall_jump_anim && isDefined( self.enemy ) || self cansee( self.enemy ) && is_true( self.in_player_zone ) )
  428.         {
  429.             wall_anim = array_randomize( wall_anim );
  430.             self.leap_anim = wall_anim[ 0 ];
  431.             self leaper_start_trail_fx();
  432.             self.ignoreall = 1;
  433.             self.is_leaping = 1;
  434.             self notify( "stop_find_flesh" );
  435.             self notify( "zombie_acquire_enemy" );
  436.             self animcustom( ::leaper_play_anim );
  437.             self waittill( "leap_anim_done" );
  438.             self leaper_stop_trail_fx();
  439.             self.ignoreall = 0;
  440.             self.is_leaping = 0;
  441.             self thread maps/mp/zombies/_zm_ai_basic::find_flesh();
  442.             self.next_leap_time = getTime() + 500;
  443.         }
  444.     }
  445. }
  446.  
  447. leaper_check_zone()
  448. {
  449.     self endon( "death" );
  450.     self.in_player_zone = 0;
  451.     while ( 1 )
  452.     {
  453.         self.in_player_zone = 0;
  454.         _a578 = level.zones;
  455.         _k578 = getFirstArrayKey( _a578 );
  456.         while ( isDefined( _k578 ) )
  457.         {
  458.             zone = _a578[ _k578 ];
  459.             if ( !isDefined( zone.volumes ) || zone.volumes.size == 0 )
  460.             {
  461.             }
  462.             else
  463.             {
  464.                 zone_name = zone.volumes[ 0 ].targetname;
  465.                 if ( self maps/mp/zombies/_zm_zonemgr::entity_in_zone( zone_name ) )
  466.                 {
  467.                     if ( is_true( zone.is_occupied ) )
  468.                     {
  469.                         self.in_player_zone = 1;
  470.                         break;
  471.                     }
  472.                 }
  473.             }
  474.             else
  475.             {
  476.                 _k578 = getNextArrayKey( _a578, _k578 );
  477.             }
  478.         }
  479.         wait 0,2;
  480.     }
  481. }
  482.  
  483. leaper_check_no_jump()
  484. {
  485.     self endon( "death" );
  486.     while ( 1 )
  487.     {
  488.         self.no_jump = 0;
  489.         _a611 = level.no_jump_triggers;
  490.         _k611 = getFirstArrayKey( _a611 );
  491.         while ( isDefined( _k611 ) )
  492.         {
  493.             trigger = _a611[ _k611 ];
  494.             if ( self istouching( trigger ) )
  495.             {
  496.                 self.no_jump = 1;
  497.                 break;
  498.             }
  499.             else
  500.             {
  501.                 _k611 = getNextArrayKey( _a611, _k611 );
  502.             }
  503.         }
  504.         wait 0,2;
  505.     }
  506. }
  507.  
  508. melee_anim_func()
  509. {
  510.     self.next_leap_time = getTime() + 1500;
  511.     self animmode( "gravity" );
  512. }
  513.  
  514. leaper_start_trail_fx()
  515. {
  516.     self endon( "death" );
  517.     self leaper_stop_trail_fx();
  518.     self.trail_fx = spawn( "script_model", self.origin );
  519.     self.trail_fx setmodel( "tag_origin" );
  520.     self.trail_fx linkto( self );
  521.     wait 0,1;
  522.     playfxontag( level._effect[ "leaper_trail" ], self.trail_fx, "tag_origin" );
  523. }
  524.  
  525. leaper_stop_trail_fx()
  526. {
  527.     if ( isDefined( self.trail_fx ) )
  528.     {
  529.         self.trail_fx delete();
  530.     }
  531. }
  532.  
  533. leaper_play_anim()
  534. {
  535.     self endon( "death" );
  536.     self animmode( "nogravity" );
  537.     self setanimstatefromasd( self.leap_anim );
  538.     self thread leaper_handle_fx_notetracks( "wall_anim" );
  539.     maps/mp/animscripts/zm_shared::donotetracks( "wall_anim" );
  540.     self animmode( "normal" );
  541.     self notify( "leap_anim_done" );
  542. }
  543.  
  544. leaper_handle_fx_notetracks( animname )
  545. {
  546.     self endon( "death" );
  547.     self endon( "leap_anim_done" );
  548.     if ( isDefined( self.leap_anim ) && self getanimhasnotetrackfromasd( "wallhit" ) )
  549.     {
  550.         self waittillmatch( animname );
  551.         return "wallhit";
  552.         playfx( level._effect[ "leaper_wall_impact" ], self.origin );
  553.     }
  554. }
  555.  
  556. leaper_notetracks( animname )
  557. {
  558.     self endon( "death" );
  559.     self endon( "leap_anim_done" );
  560.     self waittillmatch( animname );
  561.     return "gravity on";
  562.     self animmode( "normal" );
  563. }
  564.  
  565. enable_leaper_rounds()
  566. {
  567.     level.leaper_rounds_enabled = 1;
  568.     flag_init( "leaper_round" );
  569.     level thread leaper_round_tracker();
  570. }
  571.  
  572. leaper_round_tracker()
  573. {
  574.     level.leaper_round_count = 1;
  575.     level.next_leaper_round = level.round_number + randomintrange( 4, 7 );
  576.     old_spawn_func = level.round_spawn_func;
  577.     old_wait_func = level.round_wait_func;
  578.     while ( 1 )
  579.     {
  580.         level waittill( "between_round_over" );
  581.         if ( level.round_number == level.next_leaper_round )
  582.         {
  583.             level.music_round_override = 1;
  584.             old_spawn_func = level.round_spawn_func;
  585.             old_wait_func = level.round_wait_func;
  586.             leaper_round_start();
  587.             level.round_spawn_func = ::leaper_round_spawning;
  588.             level.round_wait_func = ::leaper_round_wait;
  589.             level.next_leaper_round = level.round_number + randomintrange( 4, 6 );
  590.             continue;
  591.         }
  592.         else
  593.         {
  594.             if ( flag( "leaper_round" ) )
  595.             {
  596.                 leaper_round_stop();
  597.                 level.round_spawn_func = old_spawn_func;
  598.                 level.round_wait_func = old_wait_func;
  599.                 level.music_round_override = 0;
  600.                 level.leaper_round_count += 1;
  601.             }
  602.         }
  603.     }
  604. }
  605.  
  606. leaper_round_spawning()
  607. {
  608.     level endon( "intermission" );
  609.     level endon( "leaper_round_ending" );
  610.     level.leaper_targets = getplayers();
  611.     i = 0;
  612.     while ( i < level.leaper_targets.size )
  613.     {
  614.         level.leaper_targets[ i ].hunted_by = 0;
  615.         i++;
  616.     }
  617. /#
  618.     level endon( "kill_round" );
  619.     if ( getDvarInt( "zombie_cheat" ) == 2 || getDvarInt( "zombie_cheat" ) >= 4 )
  620.     {
  621.         return;
  622. #/
  623.     }
  624.     if ( level.intermission )
  625.     {
  626.         return;
  627.     }
  628.     level.leaper_intermission = 1;
  629.     level thread leaper_round_accuracy_tracking();
  630.     level thread leaper_round_aftermath();
  631.     players = get_players();
  632.     wait 1;
  633.     playsoundatposition( "vox_zmba_event_dogstart_0", ( 0, 0, 1 ) );
  634.     wait 1;
  635.     if ( level.leaper_round_count < 3 )
  636.     {
  637.         max = players.size * level.leapers_per_player;
  638.     }
  639.     else
  640.     {
  641.         max = players.size * level.leapers_per_player;
  642.     }
  643.     level.zombie_total = max;
  644.     leaper_health_increase();
  645.     level.leaper_count = 0;
  646.     while ( 1 )
  647.     {
  648.         b_hold_spawning_when_leapers_are_all_dead = 1;
  649. /#
  650.         n_test_mode_active = getDvarInt( #"298DD9A4" );
  651.         if ( isDefined( n_test_mode_active ) && n_test_mode_active == 1 )
  652.         {
  653.             level.zombie_total = 9999;
  654.             b_hold_spawning_when_leapers_are_all_dead = 0;
  655.         }
  656.         else
  657.         {
  658.             n_remaining_leapers_this_round = max - level.leaper_count;
  659.             level.zombie_total = clamp( n_remaining_leapers_this_round, 0, max );
  660. #/
  661.         }
  662.         while ( level.leaper_count >= max && b_hold_spawning_when_leapers_are_all_dead )
  663.         {
  664.             wait 0,5;
  665.         }
  666.         num_player_valid = get_number_of_valid_players();
  667.         per_player = 2;
  668. /#
  669.         if ( getDvarInt( #"5A273E4B" ) == 2 )
  670.         {
  671.             per_player = 1;
  672. #/
  673.         }
  674.         while ( get_current_zombie_count() >= ( num_player_valid * per_player ) )
  675.         {
  676.             wait 2;
  677.             num_player_valid = get_number_of_valid_players();
  678.         }
  679.         players = get_players();
  680.         favorite_enemy = get_favorite_enemy();
  681.         spawn_point = leaper_spawn_logic( level.enemy_dog_spawns, favorite_enemy );
  682.         ai = spawn_zombie( level.leaper_spawners[ 0 ] );
  683.         if ( isDefined( ai ) )
  684.         {
  685.             ai.favoriteenemy = favorite_enemy;
  686.             ai.spawn_point = spawn_point;
  687.             spawn_point thread leaper_spawn_fx( ai, spawn_point );
  688.             level.zombie_total--;
  689.  
  690.             level.leaper_count++;
  691.         }
  692.         waiting_for_next_leaper_spawn( level.leaper_count, max );
  693.     }
  694. }
  695.  
  696. leaper_round_accuracy_tracking()
  697. {
  698.     players = getplayers();
  699.     level.leaper_round_accurate_players = 0;
  700.     i = 0;
  701.     while ( i < players.size )
  702.     {
  703.         players[ i ].total_shots_start_leaper_round = players[ i ] maps/mp/gametypes_zm/_globallogic_score::getpersstat( "total_shots" );
  704.         players[ i ].total_hits_start_leaper_round = players[ i ] maps/mp/gametypes_zm/_globallogic_score::getpersstat( "hits" );
  705.         i++;
  706.     }
  707.     level waittill( "last_leaper_down" );
  708.     players = getplayers();
  709.     i = 0;
  710.     while ( i < players.size )
  711.     {
  712.         total_shots_end_leaper_round = players[ i ] maps/mp/gametypes_zm/_globallogic_score::getpersstat( "total_shots" ) - players[ i ].total_shots_start_leaper_round;
  713.         total_hits_end_leaper_round = players[ i ] maps/mp/gametypes_zm/_globallogic_score::getpersstat( "hits" ) - players[ i ].total_hits_start_leaper_round;
  714.         if ( total_shots_end_leaper_round == total_hits_end_leaper_round )
  715.         {
  716.             level.leaper_round_accurate_players++;
  717.         }
  718.         i++;
  719.     }
  720.     if ( level.leaper_round_accurate_players == players.size )
  721.     {
  722.         i = 0;
  723.         while ( i < players.size )
  724.         {
  725.             players[ i ] maps/mp/zombies/_zm_score::add_to_player_score( 2000 );
  726.             i++;
  727.         }
  728.         if ( isDefined( level.last_leaper_origin ) )
  729.         {
  730.             trace = groundtrace( level.last_leaper_origin + vectorScale( ( 0, 0, 1 ), 10 ), level.last_leaper_origin + vectorScale( ( 0, 0, 1 ), 150 ), 0, undefined, 1 );
  731.             power_up_origin = trace[ "position" ];
  732.             level thread maps/mp/zombies/_zm_powerups::specific_powerup_drop( "free_perk", power_up_origin + vectorScale( ( 0, 0, 1 ), 30 ) );
  733.         }
  734.     }
  735. }
  736.  
  737. leaper_round_wait()
  738. {
  739.     level endon( "restart_round" );
  740. /#
  741.     if ( getDvarInt( "zombie_cheat" ) == 2 || getDvarInt( "zombie_cheat" ) >= 4 )
  742.     {
  743.         level waittill( "forever" );
  744. #/
  745.     }
  746.     wait 1;
  747.     while ( flag( "leaper_round" ) )
  748.     {
  749.         wait 7;
  750.         while ( level.leaper_intermission )
  751.         {
  752.             wait 0,5;
  753.         }
  754.     }
  755. }
  756.  
  757. leaper_health_increase()
  758. {
  759.     players = getplayers();
  760.     if ( level.leaper_round_count == 1 )
  761.     {
  762.         level.leaper_health = 400;
  763.     }
  764.     else if ( level.leaper_round_count == 2 )
  765.     {
  766.         level.leaper_health = 900;
  767.     }
  768.     else if ( level.leaper_round_count == 3 )
  769.     {
  770.         level.leaper_health = 1300;
  771.     }
  772.     else
  773.     {
  774.         if ( level.leaper_round_count == 4 )
  775.         {
  776.             level.leaper_health = 1600;
  777.         }
  778.     }
  779.     if ( level.leaper_health > 1600 )
  780.     {
  781.         level.leaper_health = 1600;
  782.     }
  783. }
  784.  
  785. get_favorite_enemy()
  786. {
  787.     leaper_targets = getplayers();
  788.     least_hunted = leaper_targets[ 0 ];
  789.     i = 0;
  790.     while ( i < leaper_targets.size )
  791.     {
  792.         if ( !isDefined( leaper_targets[ i ].hunted_by ) )
  793.         {
  794.             leaper_targets[ i ].hunted_by = 0;
  795.         }
  796.         if ( !is_player_valid( leaper_targets[ i ] ) )
  797.         {
  798.             i++;
  799.             continue;
  800.         }
  801.         else
  802.         {
  803.             if ( !is_player_valid( least_hunted ) )
  804.             {
  805.                 least_hunted = leaper_targets[ i ];
  806.             }
  807.             if ( leaper_targets[ i ].hunted_by < least_hunted.hunted_by )
  808.             {
  809.                 least_hunted = leaper_targets[ i ];
  810.             }
  811.         }
  812.         i++;
  813.     }
  814.     least_hunted.hunted_by += 1;
  815.     return least_hunted;
  816. }
  817.  
  818. leaper_watch_enemy()
  819. {
  820.     self endon( "death" );
  821.     while ( 1 )
  822.     {
  823.         if ( !is_player_valid( self.favoriteenemy ) )
  824.         {
  825.             self.favoriteenemy = get_favorite_enemy();
  826.         }
  827.         wait 0,2;
  828.     }
  829. }
  830.  
  831. leaper_combat_animmode()
  832. {
  833.     self animmode( "gravity", 0 );
  834. }
  835.  
  836. leaper_spawn_logic_old( leaper_array, favorite_enemy )
  837. {
  838.     all_locs = getstructarray( "leaper_location", "script_noteworthy" );
  839.     leaper_locs = array_randomize( all_locs );
  840.     i = 0;
  841.     while ( i < leaper_locs.size )
  842.     {
  843.         if ( leaper_locs.size > 1 )
  844.         {
  845.             if ( isDefined( level.old_leaper_spawn ) && level.old_leaper_spawn == leaper_locs[ i ] )
  846.             {
  847.                 i++;
  848.                 continue;
  849.             }
  850.         }
  851.         else
  852.         {
  853.             dist_squared = distancesquared( leaper_locs[ i ].origin, favorite_enemy.origin );
  854.             if ( dist_squared > 160000 && dist_squared < 1000000 )
  855.             {
  856.                 level.old_leaper_spawn = leaper_locs[ i ];
  857.                 return leaper_locs[ i ];
  858.             }
  859.         }
  860.         i++;
  861.     }
  862.     return leaper_locs[ 0 ];
  863. }
  864.  
  865. leaper_spawn_logic( leaper_array, favorite_enemy )
  866. {
  867.     a_zones_active = level.active_zone_names;
  868.     a_zones_occupied = [];
  869.     _a1071 = a_zones_active;
  870.     _k1071 = getFirstArrayKey( _a1071 );
  871.     while ( isDefined( _k1071 ) )
  872.     {
  873.         zone = _a1071[ _k1071 ];
  874.         if ( level.zones[ zone ].is_occupied )
  875.         {
  876.             a_zones_occupied[ a_zones_occupied.size ] = zone;
  877.         }
  878.         _k1071 = getNextArrayKey( _a1071, _k1071 );
  879.     }
  880.     a_leaper_spawn_points = [];
  881.     _a1082 = a_zones_occupied;
  882.     _k1082 = getFirstArrayKey( _a1082 );
  883.     while ( isDefined( _k1082 ) )
  884.     {
  885.         zone = _a1082[ _k1082 ];
  886.         a_leaper_spawn_points = arraycombine( a_leaper_spawn_points, level.zones[ zone ].leaper_locations, 0, 0 );
  887.         _k1082 = getNextArrayKey( _a1082, _k1082 );
  888.     }
  889.     while ( a_leaper_spawn_points.size == 0 )
  890.     {
  891.         _a1090 = a_zones_active;
  892.         _k1090 = getFirstArrayKey( _a1090 );
  893.         while ( isDefined( _k1090 ) )
  894.         {
  895.             zone = _a1090[ _k1090 ];
  896.             a_leaper_spawn_points = arraycombine( a_leaper_spawn_points, level.zones[ zone ].leaper_locations, 0, 0 );
  897.             _k1090 = getNextArrayKey( _a1090, _k1090 );
  898.         }
  899.     }
  900.     if ( a_leaper_spawn_points.size == 0 )
  901.     {
  902.         str_zone_list_occupied = "";
  903.         a_keys_error = getarraykeys( a_zones_occupied );
  904.         _a1101 = a_zones_occupied;
  905.         _k1101 = getFirstArrayKey( _a1101 );
  906.         while ( isDefined( _k1101 ) )
  907.         {
  908.             key = _a1101[ _k1101 ];
  909.             str_zone_list_occupied = ( str_zone_list_occupied + "  " ) + key;
  910.             _k1101 = getNextArrayKey( _a1101, _k1101 );
  911.         }
  912.         str_zone_list_active = "";
  913.         a_keys_error = getarraykeys( a_zones_active );
  914.         _a1109 = a_zones_active;
  915.         _k1109 = getFirstArrayKey( _a1109 );
  916.         while ( isDefined( _k1109 ) )
  917.         {
  918.             key = _a1109[ _k1109 ];
  919.             str_zone_list_active = ( str_zone_list_active + "  " ) + key;
  920.             _k1109 = getNextArrayKey( _a1109, _k1109 );
  921.         }
  922. /#
  923.         assertmsg( "No leaper spawn locations were found in any of the occupied or active zones. Occupied zones: " + str_zone_list_occupied + ". Active zones: " + str_zone_list_active );
  924. #/
  925.     }
  926. /#
  927.     if ( getDvarInt( #"A8C231AA" ) )
  928.     {
  929.         player = get_players()[ 0 ];
  930.         a_spawn_points_in_view = [];
  931.         i = 0;
  932.         while ( i < a_leaper_spawn_points.size )
  933.         {
  934.             player_vec = vectornormalize( anglesToForward( player.angles ) );
  935.             player_spawn = vectornormalize( a_leaper_spawn_points[ i ].origin - player.origin );
  936.             dot = vectordot( player_vec, player_spawn );
  937.             if ( dot > 0,707 )
  938.             {
  939.                 a_spawn_points_in_view[ a_spawn_points_in_view.size ] = a_leaper_spawn_points[ i ];
  940.                 debugstar( a_leaper_spawn_points[ i ].origin, 1000, ( 0, 0, 1 ) );
  941.             }
  942.             i++;
  943.         }
  944.         if ( a_spawn_points_in_view.size <= 0 )
  945.         {
  946.             a_spawn_points_in_view[ a_spawn_points_in_view.size ] = a_leaper_spawn_points[ 0 ];
  947.             iprintln( "no spawner in view" );
  948.         }
  949.         a_leaper_spawn_points = a_spawn_points_in_view;
  950. #/
  951.     }
  952.     s_leaper_spawn_point = select_leaper_spawn_point( a_leaper_spawn_points );
  953.     return s_leaper_spawn_point;
  954. }
  955.  
  956. select_leaper_spawn_point( a_spawn_points )
  957. {
  958.     a_valid_nodes = get_valid_spawner_array( a_spawn_points );
  959.     if ( a_valid_nodes.size == 0 )
  960.     {
  961. /#
  962.         iprintln( "All leaper spawns used...resetting" );
  963. #/
  964.         i = 0;
  965.         while ( i < a_spawn_points.size )
  966.         {
  967.             a_spawn_points[ i ].has_spawned_leaper_this_round = 0;
  968.             i++;
  969.         }
  970.         a_valid_nodes = get_valid_spawner_array( a_spawn_points );
  971.     }
  972.     if ( a_valid_nodes.size > 0 )
  973.     {
  974.         s_spawn_point = random( a_valid_nodes );
  975.         s_spawn_point.has_spawned_leaper_this_round = 1;
  976.     }
  977.     else
  978.     {
  979. /#
  980.         iprintln( "DEBUG: no valid leaper spawns available" );
  981. #/
  982.         s_spawn_point = a_spawn_points[ 0 ];
  983.     }
  984.     return s_spawn_point;
  985. }
  986.  
  987. get_valid_spawner_array( a_spawn_points )
  988. {
  989.     a_valid_nodes = [];
  990.     i = 0;
  991.     while ( i < a_spawn_points.size )
  992.     {
  993.         if ( isDefined( a_spawn_points[ i ].is_blocked ) && !a_spawn_points[ i ].is_blocked && isDefined( a_spawn_points[ i ].is_enabled ) || !a_spawn_points[ i ].is_enabled && isDefined( a_spawn_points[ i ].is_spawning ) && a_spawn_points[ i ].is_spawning )
  994.         {
  995.             i++;
  996.             continue;
  997.         }
  998.         else
  999.         {
  1000.             if ( !isDefined( a_spawn_points[ i ].has_spawned_leaper_this_round ) )
  1001.             {
  1002.                 a_spawn_points[ i ].has_spawned_leaper_this_round = 0;
  1003.             }
  1004.             if ( !a_spawn_points[ i ].has_spawned_leaper_this_round )
  1005.             {
  1006.                 a_valid_nodes[ a_valid_nodes.size ] = a_spawn_points[ i ];
  1007.             }
  1008.         }
  1009.         i++;
  1010.     }
  1011.     return a_valid_nodes;
  1012. }
  1013.  
  1014. leaper_spawn_fx( ai, ent )
  1015. {
  1016.     ai setfreecameralockonallowed( 0 );
  1017.     ai show();
  1018.     ai setfreecameralockonallowed( 1 );
  1019.     v_fx_origin = ai.spawn_point.origin;
  1020.     if ( isDefined( ai.spawn_point.script_string ) && ai.spawn_point.script_string != "find_flesh" )
  1021.     {
  1022.         wait 0,1;
  1023.         v_fx_origin = ai gettagorigin( "J_SpineLower" );
  1024.     }
  1025.     playfx( level._effect[ "leaper_spawn" ], v_fx_origin );
  1026.     playsoundatposition( "zmb_leaper_spawn_fx", v_fx_origin );
  1027. }
  1028.  
  1029. waiting_for_next_leaper_spawn( count, max )
  1030. {
  1031.     default_wait = 1,5;
  1032.     if ( level.leaper_round_count == 1 )
  1033.     {
  1034.         default_wait = 3;
  1035.     }
  1036.     else if ( level.leaper_round_count == 2 )
  1037.     {
  1038.         default_wait = 2,5;
  1039.     }
  1040.     else if ( level.leaper_round_count == 3 )
  1041.     {
  1042.         default_wait = 2;
  1043.     }
  1044.     else
  1045.     {
  1046.         default_wait = 1,5;
  1047.     }
  1048.     default_wait -= count / max;
  1049.     default_wait = clamp( default_wait, 0, 3 );
  1050.     wait default_wait;
  1051. }
  1052.  
  1053. leaper_round_aftermath()
  1054. {
  1055.     level waittill( "last_leaper_down" );
  1056.     level thread maps/mp/zombies/_zm_audio::change_zombie_music( "dog_end" );
  1057.     power_up_origin = undefined;
  1058.     if ( isDefined( level.last_leaper_origin ) )
  1059.     {
  1060.         trace = groundtrace( level.last_leaper_origin + vectorScale( ( 0, 0, 1 ), 10 ), level.last_leaper_origin + vectorScale( ( 0, 0, 1 ), 150 ), 0, undefined, 1 );
  1061.         power_up_origin = trace[ "position" ];
  1062.     }
  1063.     if ( isDefined( power_up_origin ) )
  1064.     {
  1065.         level thread maps/mp/zombies/_zm_powerups::specific_powerup_drop( "full_ammo", power_up_origin );
  1066.     }
  1067.     wait 2;
  1068.     clientnotify( "leaper_stop" );
  1069.     wait 6;
  1070.     level.leaper_intermission = 0;
  1071. }
  1072.  
  1073. leaper_round_start()
  1074. {
  1075.     flag_set( "leaper_round" );
  1076.     level thread maps/mp/zombies/_zm_audio::change_zombie_music( "dog_start" );
  1077.     level thread leaper_round_start_audio();
  1078.     level notify( "leaper_round_starting" );
  1079.     clientnotify( "leaper_start" );
  1080. }
  1081.  
  1082. leaper_round_stop()
  1083. {
  1084.     flag_clear( "leaper_round" );
  1085.     level notify( "leaper_round_ending" );
  1086.     clientnotify( "leaper_stop" );
  1087. }
  1088.  
  1089. leaper_traverse_watcher()
  1090. {
  1091.     self endon( "death" );
  1092.     while ( 1 )
  1093.     {
  1094.         if ( is_true( self.is_traversing ) )
  1095.         {
  1096.             self.elevator_parent = undefined;
  1097.             if ( is_true( self maps/mp/zm_highrise_elevators::object_is_on_elevator() ) )
  1098.             {
  1099.                 if ( isDefined( self.elevator_parent ) )
  1100.                 {
  1101.                     if ( is_true( self.elevator_parent.is_moving ) )
  1102.                     {
  1103.                         playfx( level._effect[ "zomb_gib" ], self.origin );
  1104.                         self leaper_cleanup();
  1105.                         self delete();
  1106.                         return;
  1107.                     }
  1108.                 }
  1109.             }
  1110.         }
  1111.         wait 0,2;
  1112.     }
  1113. }
  1114.  
  1115. leaper_playable_area_failsafe()
  1116. {
  1117.     self endon( "death" );
  1118.     self.leaper_failsafe_start_time = getTime();
  1119.     playable_area = getentarray( "player_volume", "script_noteworthy" );
  1120.     b_outside_playable_space_this_frame = 0;
  1121.     self.leaper_outside_playable_space_time = -2;
  1122.     while ( 1 )
  1123.     {
  1124.         b_outside_playable_last_check = b_outside_playable_space_this_frame;
  1125.         b_outside_playable_space_this_frame = is_leaper_outside_playable_space( playable_area );
  1126.         n_current_time = getTime();
  1127.         if ( b_outside_playable_space_this_frame && !b_outside_playable_last_check )
  1128.         {
  1129.             self.leaper_outside_playable_space_time = n_current_time;
  1130.         }
  1131.         else
  1132.         {
  1133.             if ( !b_outside_playable_space_this_frame )
  1134.             {
  1135.                 self.leaper_outside_playable_space = -1;
  1136.             }
  1137.         }
  1138.         b_leaper_has_been_alive_long_enough = ( n_current_time - self.leaper_failsafe_start_time ) > 3000;
  1139.         b_leaper_is_in_scripted_state = self isinscriptedstate();
  1140.         if ( b_outside_playable_space_this_frame )
  1141.         {
  1142.             b_leaper_has_been_out_of_playable_space_long_enough_to_delete = ( n_current_time - self.leaper_outside_playable_space_time ) > 2000;
  1143.         }
  1144.         if ( b_leaper_has_been_alive_long_enough && !b_leaper_is_in_scripted_state )
  1145.         {
  1146.             b_can_delete = b_leaper_has_been_out_of_playable_space_long_enough_to_delete;
  1147.         }
  1148.         if ( b_can_delete )
  1149.         {
  1150.             playsoundatposition( "zmb_vocals_leaper_fall", self.origin );
  1151.             self leaper_cleanup();
  1152. /#
  1153.             str_traversal_data = "";
  1154.             if ( isDefined( self.traversestartnode ) )
  1155.             {
  1156.                 str_traversal_data = " Last traversal used = " + self.traversestartnode.animscript + " at " + self.traversestartnode.origin;
  1157.             }
  1158.             iprintln( "leaper at " + self.origin + " with spawn point " + self.spawn_point.origin + " out of play space. DELETING!" + str_traversal_data );
  1159. #/
  1160.             self delete();
  1161.             return;
  1162.         }
  1163.         wait 1;
  1164.     }
  1165. }
  1166.  
  1167. is_leaper_outside_playable_space( playable_area )
  1168. {
  1169.     b_outside_play_space = 1;
  1170.     _a1421 = playable_area;
  1171.     _k1421 = getFirstArrayKey( _a1421 );
  1172.     while ( isDefined( _k1421 ) )
  1173.     {
  1174.         area = _a1421[ _k1421 ];
  1175.         if ( self istouching( area ) )
  1176.         {
  1177.             b_outside_play_space = 0;
  1178.         }
  1179.         _k1421 = getNextArrayKey( _a1421, _k1421 );
  1180.     }
  1181.     return b_outside_play_space;
  1182. }
  1183.  
  1184. leaper_cleanup()
  1185. {
  1186.     self leaper_stop_trail_fx();
  1187.     self notify( "leaper_cleanup" );
  1188.     wait 0,05;
  1189.     level.leaper_count--;
  1190.  
  1191.     level.zombie_total++;
  1192. }
  1193.  
  1194. leaper_spawn_failsafe()
  1195. {
  1196.     self endon( "death" );
  1197.     while ( 1 )
  1198.     {
  1199.         prevorigin = self.origin;
  1200.         dist_sq = 0;
  1201.         i = 0;
  1202.         while ( i < 3 )
  1203.         {
  1204.             if ( is_true( self.sliding_on_goo ) )
  1205.             {
  1206.                 dist_sq += 576;
  1207.             }
  1208.             wait 1;
  1209.             dist_sq += distancesquared( self.origin, prevorigin );
  1210.             prevorigin = self.origin;
  1211.             i++;
  1212.         }
  1213.         if ( dist_sq < 576 )
  1214.         {
  1215.             if ( !is_true( self.melee_attack ) )
  1216.             {
  1217.                 self leaper_cleanup();
  1218. /#
  1219.                 str_traversal_data = "";
  1220.                 if ( isDefined( self.traversestartnode ) )
  1221.                 {
  1222.                     str_traversal_data = " Last traversal used = " + self.traversestartnode.animscript + " at " + self.traversestartnode.origin;
  1223.                 }
  1224.                 iprintln( "leaper_spawn_failsafe() killing leaper at " + self.origin + " with spawn point " + self.spawn_point.origin + "!\n" + str_traversal_data );
  1225. #/
  1226.                 self dodamage( self.health + 100, ( 0, 0, 1 ) );
  1227.                 return;
  1228.             }
  1229.             else /#
  1230.             if ( getDvarInt( #"5A273E4B" ) == 1 )
  1231.             {
  1232.                 iprintln( "leaper tried melee" );
  1233. #/
  1234.             }
  1235.             self.melee_attack = 0;
  1236.         }
  1237.     }
  1238. }
  1239.  
  1240. do_leaper_emerge( spot )
  1241. {
  1242.     self endon( "death" );
  1243.     self.deathfunction = ::leaper_death_ragdoll;
  1244.     self.no_powerups = 1;
  1245.     self.in_the_ceiling = 1;
  1246.     spot.is_spawning = 1;
  1247.     anim_org = spot.origin;
  1248.     anim_ang = spot.angles;
  1249.     self ghost();
  1250.     self thread maps/mp/zombies/_zm_spawner::hide_pop();
  1251.     self thread leaper_death_wait( "spawn_anim" );
  1252.     if ( isDefined( level.custom_faller_entrance_logic ) )
  1253.     {
  1254.         self thread [[ level.custom_faller_entrance_logic ]]();
  1255.     }
  1256.     self leaper_emerge();
  1257.     wait 0,1;
  1258.     self notify( "spawn_anim_finished" );
  1259.     spot.is_spawning = 0;
  1260. }
  1261.  
  1262. leaper_death_ragdoll()
  1263. {
  1264.     self startragdoll();
  1265.     self launchragdoll( ( 0, 0, 1 ) );
  1266.     return self maps/mp/zombies/_zm_spawner::zombie_death_animscript();
  1267. }
  1268.  
  1269. leaper_death_wait( endon_notify )
  1270. {
  1271.     self endon( "spawn_anim_finished" );
  1272.     self waittill( "death" );
  1273.     self.spawn_point.is_spawning = 0;
  1274. }
  1275.  
  1276. leaper_emerge()
  1277. {
  1278.     self endon( "death" );
  1279.     if ( self.spawn_point.script_parameters == "emerge_bottom" )
  1280.     {
  1281.         self animscripted( self.spawn_point.origin, self.spawn_point.angles, "zm_spawn_elevator_from_floor" );
  1282.     }
  1283.     else
  1284.     {
  1285.         self animscripted( self.spawn_point.origin, self.spawn_point.angles, "zm_spawn_elevator_from_ceiling" );
  1286.     }
  1287.     self maps/mp/animscripts/zm_shared::donotetracks( "spawn_anim" );
  1288.     self.deathfunction = ::maps/mp/zombies/_zm_spawner::zombie_death_animscript;
  1289.     self.in_the_ceiling = 0;
  1290. }
  1291.  
  1292. leaper_round_start_audio()
  1293. {
  1294.     wait 2,5;
  1295.     players = get_players();
  1296.     num = randomintrange( 0, players.size );
  1297.     players[ num ] maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "leaper_round" );
  1298.     array_thread( players, ::wait_for_player_to_see_leaper );
  1299.     array_thread( players, ::wait_for_leaper_attack );
  1300. }
  1301.  
  1302. wait_for_player_to_see_leaper()
  1303. {
  1304.     self endon( "disconnect" );
  1305.     level endon( "leaper_round_ending" );
  1306.     while ( 1 )
  1307.     {
  1308.         leapers = getaiarray( level.zombie_team );
  1309.         _a1579 = leapers;
  1310.         _k1579 = getFirstArrayKey( _a1579 );
  1311.         while ( isDefined( _k1579 ) )
  1312.         {
  1313.             leaper = _a1579[ _k1579 ];
  1314.             player_vec = vectornormalize( anglesToForward( self.angles ) );
  1315.             player_leaper = vectornormalize( leaper.origin - self.origin );
  1316.             dot = vectordot( player_vec, player_leaper );
  1317.             if ( dot > 0,707 )
  1318.             {
  1319.                 if ( sighttracepassed( self.origin + vectorScale( ( 0, 0, 1 ), 40 ), leaper.origin + vectorScale( ( 0, 0, 1 ), 10 ), 0, self ) )
  1320.                 {
  1321.                     self maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "leaper_seen" );
  1322.                     return;
  1323.                 }
  1324.             }
  1325.             _k1579 = getNextArrayKey( _a1579, _k1579 );
  1326.         }
  1327.         wait 0,25;
  1328.     }
  1329. }
  1330.  
  1331. wait_for_leaper_attack()
  1332. {
  1333.     self endon( "disconnect" );
  1334.     level endon( "leaper_round_ending" );
  1335.     while ( 1 )
  1336.     {
  1337.         self waittill( "melee_swipe", enemy );
  1338.         if ( isDefined( enemy.is_leaper ) && enemy.is_leaper )
  1339.         {
  1340.             self thread do_player_general_vox( "general", "leaper_attack", 10, 5 );
  1341.             wait 5;
  1342.         }
  1343.     }
  1344. }
Advertisement
Add Comment
Please, Sign In to add comment