Advertisement
MakeCents

zombiemode_spawner

Mar 13th, 2015
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include maps\_utility;
  2. #include common_scripts\utility;
  3. #include maps\_zombiemode_utility;
  4.  
  5.  
  6. #using_animtree( "generic_human" );
  7. init()
  8. {
  9.     level.zombie_move_speed = 1;
  10.     level.zombie_health = 150;
  11.    
  12.     level.zombie_eyes_limited = 1;
  13.     level.zombie_eyes_disabled = 1;
  14.    
  15.     if(getdvarint("g_allzombieseyeglow"))
  16.     {
  17.         level.zombie_eyes_limited = 0;
  18.     }
  19.    
  20.     zombies = getEntArray( "zombie_spawner", "script_noteworthy" );
  21.     later_rounds = getentarray("later_round_spawners", "script_noteworthy" );
  22.    
  23.     zombies = array_combine( zombies, later_rounds );
  24.  
  25.     for( i = 0; i < zombies.size; i++ )
  26.     {
  27.         if( is_spawner_targeted_by_blocker( zombies[i] ) )
  28.         {
  29.             zombies[i].locked_spawner = true;
  30.         }
  31.     }
  32.    
  33.     array_thread(zombies, ::add_spawn_function, ::zombie_spawn_init);
  34.     array_thread(zombies, ::add_spawn_function, ::zombie_rise);
  35. }
  36.  
  37.  
  38. #using_animtree( "generic_human" );
  39. is_spawner_targeted_by_blocker( ent )
  40. {
  41.     if( IsDefined( ent.targetname ) )
  42.     {
  43.         targeters = GetEntArray( ent.targetname, "target" );
  44.  
  45.         for( i = 0; i < targeters.size; i++ )
  46.         {
  47.             if( targeters[i].targetname == "zombie_door" || targeters[i].targetname == "zombie_debris" )
  48.             {
  49.                 return true;
  50.             }
  51.  
  52.             result = is_spawner_targeted_by_blocker( targeters[i] );
  53.             if( result )
  54.             {
  55.                 return true;
  56.             }
  57.         }
  58.     }
  59.  
  60.     return false;
  61. }
  62.  
  63. // set up zombie walk cycles
  64. zombie_spawn_init( animname_set )
  65. {
  66.     if( !isDefined( animname_set ) )
  67.     {
  68.         animname_set = false;
  69.     }
  70.    
  71.     self.targetname = "zombie";
  72.     self.script_noteworthy = undefined;
  73.  
  74.     if( !animname_set )
  75.     {
  76.         self.animname = "zombie";      
  77.     }
  78.     self.ignoreall = true;
  79.     self.allowdeath = true;             // allows death during animscripted calls
  80.     self.gib_override = true;       // needed to make sure this guy does gibs
  81.     self.is_zombie = true;          // needed for melee.gsc in the animscripts
  82.     self.has_legs = true;           // Sumeet - This tells the zombie that he is allowed to stand anymore or not, gibbing can take
  83.                                     // out both legs and then the only allowed stance should be prone.
  84.     self allowedStances( "stand" );
  85.  
  86.     self.gibbed = false;
  87.     self.head_gibbed = false;
  88.    
  89.     // might need this so co-op zombie players cant block zombie pathing
  90.     self PushPlayer( true );
  91. //  self.meleeRange = 128;
  92. //  self.meleeRangeSq = anim.meleeRange * anim.meleeRange;
  93.    
  94.     animscripts\shared::placeWeaponOn( self.primaryweapon, "none" );
  95.    
  96.     // This isn't working, might need an "empty" weapon
  97.     //self animscripts\shared::placeWeaponOn( self.weapon, "none" );
  98.  
  99.     self.disableArrivals = true;
  100.     self.disableExits = true;
  101.     self.grenadeawareness = 0;
  102.     self.badplaceawareness = 0;
  103.  
  104.     self.ignoreSuppression = true;  
  105.     self.suppressionThreshold = 1;
  106.     self.noDodgeMove = true;
  107.     self.dontShootWhileMoving = true;
  108.     self.pathenemylookahead = 0;
  109.  
  110.     self.badplaceawareness = 0;
  111.     self.chatInitialized = false;
  112.  
  113.     self disable_pain();
  114.  
  115.     self.maxhealth = level.zombie_health;
  116.     self.health = level.zombie_health;
  117.  
  118.     self.dropweapon = false;
  119.     level thread zombie_death_event( self );
  120.  
  121.     // We need more script/code to get this to work properly
  122. //  self add_to_spectate_list();
  123.     self random_tan();
  124.     self set_zombie_run_cycle();
  125.     self thread zombie_think();
  126.     self thread zombie_gib_on_damage();
  127.     self thread zombie_damage_failsafe();
  128.  
  129.     // MM - mixed zombies test
  130. //  if ( flag( "crawler_round" ) ||
  131. //       ( IsDefined( level.mixed_rounds_enabled ) && level.mixed_rounds_enabled == 1 &&
  132. //         level.zombie_total > 10 &&
  133. //         level.round_number > 5 && RandomInt(100) < 10 ) )
  134. //  {
  135. //      self thread make_crawler();
  136. //  }
  137.  
  138. //  self thread zombie_head_gib();
  139.     self thread delayed_zombie_eye_glow();  // delayed eye glow for ground crawlers (the eyes floated above the ground before the anim started)
  140.     self.deathFunction = ::zombie_death_animscript;
  141.     self.flame_damage_time = 0;
  142.    
  143.     self zombie_history( "zombie_spawn_init -> Spawned = " + self.origin );
  144.  
  145.     self notify( "zombie_init_done" );
  146. }
  147.  
  148. /*
  149. delayed_zombie_eye_glow:
  150. Fixes problem where zombies that climb out of the ground are warped to their start positions
  151. and their eyes glowed above the ground for a split second before their animation started even
  152. though the zombie model is hidden. and applying this delay to all the zombies doesn't really matter.
  153. */
  154. delayed_zombie_eye_glow()
  155. {
  156.     wait .5;
  157.     self zombie_eye_glow();
  158. }
  159.  
  160.  
  161. zombie_damage_failsafe()
  162. {
  163.     self endon ("death");
  164.  
  165.     continue_failsafe_damage = false;  
  166.     while (1)
  167.     {
  168.         //should only be for zombie exploits
  169.         wait 0.5;
  170.        
  171.         if (!isdefined(self.enemy))
  172.         {
  173.             continue;
  174.         }
  175.        
  176.         if (self istouching(self.enemy))
  177.         {
  178.             old_org = self.origin;
  179.             if (!continue_failsafe_damage)
  180.             {
  181.                 wait 5;
  182.             }
  183.            
  184.             //make sure player doesn't die instantly after getting touched by a zombie.
  185.             if (!isdefined(self.enemy) || self.enemy hasperk("specialty_armorvest"))
  186.             {
  187.                 continue;
  188.             }
  189.        
  190.             if (self istouching(self.enemy)
  191.                 && !self.enemy maps\_laststand::player_is_in_laststand()
  192.                 && isalive(self.enemy))
  193.             {
  194.                 if (distancesquared(old_org, self.origin) < (35 * 35) )
  195.                 {
  196.                     setsaveddvar("player_deathInvulnerableTime", 0);
  197.                     self.enemy DoDamage( self.enemy.health + 1000, self.enemy.origin, undefined, undefined, "riflebullet" );
  198.                     setsaveddvar("player_deathInvulnerableTime", level.startInvulnerableTime); 
  199.                
  200.                     continue_failsafe_damage = true;
  201.                 }
  202.             }
  203.         }
  204.         else
  205.         {
  206.             continue_failsafe_damage = false;
  207.         }
  208.     }
  209. }
  210.  
  211. set_zombie_run_cycle()
  212. {
  213.     self set_run_speed();
  214.  
  215.     death_anims = level._zombie_deaths[self.animname];
  216.  
  217.     self.deathanim = random(death_anims);
  218.  
  219.     //if(level.round_number < 3)
  220.     //{
  221.     //  self.zombie_move_speed = "walk";
  222.     //}
  223.  
  224.     switch(self.zombie_move_speed)
  225.     {
  226.     case "walk":
  227.         var = randomintrange(1, 8);        
  228.         self set_run_anim( "walk" + var );                        
  229.         self.run_combatanim = level.scr_anim[self.animname]["walk" + var];
  230.         break;
  231.     case "run":                                
  232.         var = randomintrange(1, 6);
  233.         self set_run_anim( "run" + var );              
  234.         self.run_combatanim = level.scr_anim[self.animname]["run" + var];
  235.         break;
  236.     case "sprint":                            
  237.         var = randomintrange(1, 4);
  238.         self set_run_anim( "sprint" + var );                      
  239.         self.run_combatanim = level.scr_anim[self.animname]["sprint" + var];
  240.         break;
  241.     }
  242. }
  243.  
  244. set_run_speed()
  245. {
  246.     rand = randomintrange( level.zombie_move_speed, level.zombie_move_speed + 35 );
  247.    
  248. //  self thread print_run_speed( rand );
  249.     if( rand <= 35 )
  250.     {
  251.         self.zombie_move_speed = "walk";
  252.     }
  253.     else if( rand <= 70 )
  254.     {
  255.         self.zombie_move_speed = "run";
  256.     }
  257.     else
  258.     {  
  259.         self.zombie_move_speed = "sprint";
  260.     }
  261. }
  262.  
  263. // this is the main zombie think thread that starts when they spawn in
  264. zombie_think()
  265. {
  266.     self endon( "death" );
  267.     assert( !self enemy_is_dog() );
  268.    
  269.     //node = level.exterior_goals[randomint( level.exterior_goals.size )];
  270.    
  271.     // MM - 5/8/9 Add ability for risers to find_flesh immediately after spawning if the
  272.     //  rise struct has the script_noteworthy "find_flesh"
  273.     rise_struct_string = undefined;
  274.  
  275.     //CHRIS_P - test dudes rising from ground
  276.     if (GetDVarInt("zombie_rise_test") || (isDefined(self.script_string) && self.script_string == "riser" ))
  277.     {
  278.         self.do_rise = 1;
  279.         //self notify("do_rise");
  280.         self waittill("risen", rise_struct_string );
  281.     }
  282.     else
  283.     {
  284.         self notify("no_rise");
  285.     }
  286.    
  287.     node = undefined;
  288.  
  289.     desired_nodes = [];
  290.     self.entrance_nodes = [];
  291.  
  292.     if ( IsDefined( level.max_barrier_search_dist_override ) )
  293.     {
  294.         max_dist = level.max_barrier_search_dist_override;
  295.     }
  296.     else
  297.     {
  298.         max_dist = 500;
  299.     }
  300.  
  301.     if( IsDefined( self.script_forcegoal ) && self.script_forcegoal )
  302.     {
  303.         desired_origin = get_desired_origin();
  304.  
  305.         AssertEx( IsDefined( desired_origin ), "Spawner @ " + self.origin + " has a script_forcegoal but did not find a target" );
  306.    
  307.         origin = desired_origin;
  308.            
  309.         node = getclosest( origin, level.exterior_goals );  
  310.         self.entrance_nodes[0] = node;
  311.  
  312.         self zombie_history( "zombie_think -> #1 entrance (script_forcegoal) origin = " + self.entrance_nodes[0].origin );
  313.     }
  314.     // DCS: for riser zombies to go to a door instead of to player (see next else if).
  315.     else if(isDefined(rise_struct_string) && rise_struct_string == "riser_door")
  316.     {
  317.         origin = self.origin;
  318.  
  319.         desired_origin = get_desired_origin();
  320.         if( IsDefined( desired_origin ) )
  321.         {
  322.             origin = desired_origin;
  323.         }
  324.  
  325.         // Get the 3 closest nodes
  326.         nodes = get_array_of_closest( origin, level.exterior_goals, undefined, 3 );
  327.  
  328.         // Figure out the distances between them, if any of them are greater than 256 units compared to the previous, drop it
  329.         desired_nodes[0] = nodes[0];
  330.         prev_dist = Distance( self.origin, nodes[0].origin );
  331.         for( i = 1; i < nodes.size; i++ )
  332.         {
  333.             dist = Distance( self.origin, nodes[i].origin );
  334.             if( ( dist - prev_dist ) > max_dist )
  335.             {
  336.                 break;
  337.             }
  338.  
  339.             prev_dist = dist;
  340.             desired_nodes[i] = nodes[i];
  341.         }
  342.  
  343.         node = desired_nodes[0];
  344.         if( desired_nodes.size > 1 )
  345.         {
  346.             node = desired_nodes[RandomInt(desired_nodes.size)];
  347.         }
  348.  
  349.         self.entrance_nodes = desired_nodes;
  350.  
  351.         self zombie_history( "zombie_think -> #1 entrance origin = " + node.origin );
  352.  
  353.         // Incase the guy does not move from spawn, then go to the closest one instead
  354.         self thread zombie_assure_node();
  355.     }
  356.     // JMA - this is used in swamp to spawn outdoor zombies and immediately rush the player
  357.     // JMA - if riser becomes a non-riser, make sure they go to a barrier first instead of chasing a player
  358.     else if ( (IsDefined( self.script_string ) && self.script_string == "zombie_chaser" ) ||
  359.         ( IsDefined(rise_struct_string) && rise_struct_string == "find_flesh" ) )
  360.     {
  361.         self zombie_setup_attack_properties();
  362.         //if the zombie has a target, make them go there first
  363.         if (isDefined(self.target))
  364.         {
  365.             end_at_node = GetNode(self.target, "targetname");
  366.             if (isDefined(end_at_node))
  367.             {
  368.                 self setgoalnode (end_at_node);
  369.                 self waittill("goal");
  370.             }
  371.         }
  372.  
  373.         self thread find_flesh();
  374.         return;
  375.     }
  376.     else
  377.     {
  378.         origin = self.origin;
  379.  
  380.         desired_origin = get_desired_origin();
  381.         if( IsDefined( desired_origin ) )
  382.         {
  383.             origin = desired_origin;
  384.         }
  385.  
  386.         // Get the 3 closest nodes
  387.         nodes = get_array_of_closest( origin, level.exterior_goals, undefined, 3 );
  388.  
  389.         // Figure out the distances between them, if any of them are greater than 256 units compared to the previous, drop it
  390.         desired_nodes[0] = nodes[0];
  391.         prev_dist = Distance( self.origin, nodes[0].origin );
  392.         for( i = 1; i < nodes.size; i++ )
  393.         {
  394.             dist = Distance( self.origin, nodes[i].origin );
  395.             if( ( dist - prev_dist ) > max_dist )
  396.             {
  397.                 break;
  398.             }
  399.  
  400.             prev_dist = dist;
  401.             desired_nodes[i] = nodes[i];
  402.         }
  403.  
  404.         node = desired_nodes[0];
  405.         if( desired_nodes.size > 1 )
  406.         {
  407.             node = desired_nodes[RandomInt(desired_nodes.size)];
  408.         }
  409.  
  410.         self.entrance_nodes = desired_nodes;
  411.  
  412.         self zombie_history( "zombie_think -> #1 entrance origin = " + node.origin );
  413.  
  414.         // Incase the guy does not move from spawn, then go to the closest one instead
  415.         self thread zombie_assure_node();
  416.     }
  417.  
  418.     AssertEx( IsDefined( node ), "Did not find a node!!! [Should not see this!]" );
  419.  
  420.     level thread draw_line_ent_to_pos( self, node.origin, "goal" );
  421.    
  422.     self.first_node = node;
  423.    
  424.     self thread zombie_goto_entrance( node );
  425. }
  426.  
  427. get_desired_origin()
  428. {
  429.     if( IsDefined( self.target ) )
  430.     {
  431.         ent = GetEnt( self.target, "targetname" );
  432.         if( !IsDefined( ent ) )
  433.         {
  434.             ent = getstruct( self.target, "targetname" );
  435.         }
  436.    
  437.         if( !IsDefined( ent ) )
  438.         {
  439.             ent = GetNode( self.target, "targetname" );
  440.         }
  441.    
  442.         AssertEx( IsDefined( ent ), "Cannot find the targeted ent/node/struct, \"" + self.target + "\" at " + self.origin );
  443.    
  444.         return ent.origin;
  445.     }
  446.  
  447.     return undefined;
  448. }
  449.  
  450. zombie_goto_entrance( node, endon_bad_path )
  451. {
  452.     assert( !self enemy_is_dog() );
  453.    
  454.     self endon( "death" );
  455.     level endon( "intermission" );
  456.  
  457.     if( IsDefined( endon_bad_path ) && endon_bad_path )
  458.     {
  459.         // If we cannot go to the goal, then end...
  460.         // Used from find_flesh
  461.         self endon( "bad_path" );
  462.     }
  463.  
  464.  
  465.  
  466.     self zombie_history( "zombie_goto_entrance -> start goto entrance " + node.origin );
  467.  
  468.     self.got_to_entrance = false;
  469.     self.goalradius = 128;
  470.     self SetGoalPos( node.origin );
  471.     self waittill( "goal" );
  472.     self.got_to_entrance = true;
  473.  
  474.     self zombie_history( "zombie_goto_entrance -> reached goto entrance " + node.origin );
  475.  
  476.     // Guy should get to goal and tear into building until all barrier chunks are gone
  477.     self tear_into_building();
  478.        
  479.     //REMOVED THIS, WAS CAUSING ISSUES
  480.     if(isDefined(self.first_node.clip))
  481.     {
  482.         //if(!isDefined(self.first_node.clip.disabled) || !self.first_node.clip.disabled)
  483.         //{
  484.         //  self.first_node.clip disable_trigger();
  485.             self.first_node.clip connectpaths();
  486.         //}
  487.     }
  488.  
  489.     // here is where they zombie would play the traversal into the building( if it's a window )
  490.     // and begin the player seek logic
  491.     self zombie_setup_attack_properties();
  492.    
  493.     //PI CHANGE - force the zombie to go over the traversal near their goal node if desired
  494.     if (isDefined(level.script) && level.script == "nazi_zombie_sumpf")
  495.     {
  496.         if (isDefined(self.target))
  497.         {
  498.             temp_node = GetNode(self.target, "targetname");
  499.             if (isDefined(temp_node) && isDefined(temp_node.target))
  500.             {
  501.                 end_at_node = GetNode(temp_node.target, "targetname");
  502.                 if (isDefined(end_at_node))
  503.                 {
  504.                     self setgoalnode (end_at_node);
  505.                     self waittill("goal");
  506.                 }
  507.             }
  508.         }
  509.     }
  510.     //END PI CHANGE
  511.    
  512.     self thread find_flesh();
  513. }
  514.  
  515.  
  516. zombie_assure_node()
  517. {
  518.     self endon( "death" );
  519.     self endon( "goal" );
  520.     level endon( "intermission" );
  521.  
  522.     start_pos = self.origin;
  523.  
  524.     for( i = 0; i < self.entrance_nodes.size; i++ )
  525.     {
  526.         if( self zombie_bad_path() )
  527.         {
  528.             self zombie_history( "zombie_assure_node -> assigned assured node = " + self.entrance_nodes[i].origin );
  529.  
  530.             println( "^1Zombie @ " + self.origin + " did not move for 1 second. Going to next closest node @ " + self.entrance_nodes[i].origin );
  531.             level thread draw_line_ent_to_pos( self, self.entrance_nodes[i].origin, "goal" );
  532.             self.first_node = self.entrance_nodes[i];
  533.             self SetGoalPos( self.entrance_nodes[i].origin );
  534.         }
  535.         else
  536.         {
  537.             return;
  538.         }
  539.     }  
  540.     // CHRISP - must add an additional check, since the 'self.entrance_nodes' array is not dynamically updated to accomodate for entrance points that can be turned on and off
  541.     // only do this if it's the asylum map
  542.     if(level.script == "nazi_zombie_asylum" || level.script == "nazi_zombie_sumpf" || level.script == "nazi_zombie_factory" || level.script == "nazi_zombie_paris" || level.script == "nazi_zombie_coast" || level.script == "nazi_zombie_theater")
  543.     {
  544.         wait(2);
  545.         // Get more nodes and try again
  546.         nodes = get_array_of_closest( self.origin, level.exterior_goals, undefined, 20 );
  547.         self.entrance_nodes = nodes;
  548.         for( i = 0; i < self.entrance_nodes.size; i++ )
  549.         {
  550.             if( self zombie_bad_path() )
  551.             {
  552.                 self zombie_history( "zombie_assure_node -> assigned assured node = " + self.entrance_nodes[i].origin );
  553.  
  554.                 println( "^1Zombie @ " + self.origin + " did not move for 1 second. Going to next closest node @ " + self.entrance_nodes[i].origin );
  555.                 level thread draw_line_ent_to_pos( self, self.entrance_nodes[i].origin, "goal" );
  556.                 self.first_node = self.entrance_nodes[i];
  557.                 self SetGoalPos( self.entrance_nodes[i].origin );
  558.             }
  559.             else
  560.             {
  561.                 return;
  562.             }
  563.         }
  564.     }      
  565.  
  566.     self zombie_history( "zombie_assure_node -> failed to find a good entrance point" );
  567.    
  568.     //assertmsg( "^1Zombie @ " + self.origin + " did not find a good entrance point... Please fix pathing or Entity setup" );
  569.     wait(20);
  570.     //iprintln( "^1Zombie @ " + self.origin + " did not find a good entrance point... Please fix pathing or Entity setup" );
  571.     self DoDamage( self.health + 10, self.origin );
  572. }
  573.  
  574. zombie_bad_path()
  575. {
  576.     self endon( "death" );
  577.     self endon( "goal" );
  578.  
  579.     self thread zombie_bad_path_notify();
  580.     self thread zombie_bad_path_timeout();
  581.  
  582.     self.zombie_bad_path = undefined;
  583.     while( !IsDefined( self.zombie_bad_path ) )
  584.     {
  585.         wait( 0.05 );
  586.     }
  587.  
  588.     self notify( "stop_zombie_bad_path" );
  589.  
  590.     return self.zombie_bad_path;
  591. }
  592.  
  593. zombie_bad_path_notify()
  594. {
  595.     self endon( "death" );
  596.     self endon( "stop_zombie_bad_path" );
  597.  
  598.     self waittill( "bad_path" );
  599.     self.zombie_bad_path = true;
  600. }
  601.  
  602. zombie_bad_path_timeout()
  603. {
  604.     self endon( "death" );
  605.     self endon( "stop_zombie_bad_path" );
  606.  
  607.     wait( 2 );
  608.     self.zombie_bad_path = false;
  609. }
  610.  
  611. // zombies are trying to get at player contained behind barriers, so the barriers
  612. // need to come down
  613. tear_into_building()
  614. {
  615.     //chrisp - added this
  616.     //checkpass = false;
  617.    
  618.     self endon( "death" );
  619.  
  620.     self zombie_history( "tear_into_building -> start" );
  621.  
  622.     while( 1 )
  623.     {
  624.         if( IsDefined( self.first_node.script_noteworthy ) )
  625.         {
  626.             if( self.first_node.script_noteworthy == "no_blocker" )
  627.             {
  628.                 return;
  629.             }
  630.         }
  631.  
  632.         if( !IsDefined( self.first_node.target ) )
  633.         {
  634.             return;
  635.         }
  636.  
  637.         if( all_chunks_destroyed( self.first_node.barrier_chunks ) )
  638.         {
  639.             self zombie_history( "tear_into_building -> all chunks destroyed" );
  640.         }
  641.  
  642.         // Pick a spot to tear down
  643.         if( !get_attack_spot( self.first_node ) )
  644.         {
  645.             self zombie_history( "tear_into_building -> Could not find an attack spot" );
  646.             wait( 0.5 );
  647.             continue;
  648.         }
  649.  
  650.         self.goalradius = 4;
  651.         self SetGoalPos( self.attacking_spot, self.first_node.angles );
  652.         self waittill( "goal" );
  653.         //  MM- 05/09
  654.         //  If you wait for "orientdone", you NEED to also have a timeout.
  655.         //  Otherwise, zombies could get stuck waiting to do their facing.
  656.         self waittill_notify_or_timeout( "orientdone", 1 );
  657.  
  658.         self zombie_history( "tear_into_building -> Reach position and orientated" );      
  659.  
  660.         // chrisp - do one final check to make sure that the boards are still torn down
  661.         // this *mostly* prevents the zombies from coming through the windows as you are boarding them up.
  662.         if( all_chunks_destroyed( self.first_node.barrier_chunks ) )
  663.         {
  664.             self zombie_history( "tear_into_building -> all chunks destroyed" );
  665.             for( i = 0; i < self.first_node.attack_spots_taken.size; i++ )
  666.             {
  667.                 self.first_node.attack_spots_taken[i] = false;
  668.             }
  669.             return;
  670.         }
  671.  
  672.         // Now tear down boards
  673.         while( 1 )
  674.         {
  675.             chunk = get_closest_non_destroyed_chunk( self.origin, self.first_node.barrier_chunks );
  676.    
  677.             if( !IsDefined( chunk ) )
  678.             {
  679.                 for( i = 0; i < self.first_node.attack_spots_taken.size; i++ )
  680.                 {
  681.                     self.first_node.attack_spots_taken[i] = false;
  682.                 }
  683.                 return;
  684.             }
  685.  
  686.             self zombie_history( "tear_into_building -> animating" );
  687.  
  688.             tear_anim = get_tear_anim(chunk, self);
  689.             chunk.target_by_zombie = true;
  690.             self AnimScripted( "tear_anim", self.origin, self.first_node.angles, tear_anim );
  691.             self zombie_tear_notetracks( "tear_anim", chunk, self.first_node );
  692.            
  693.             //chris - adding new window attack & gesture animations ;)
  694.             if(level.script != "nazi_zombie_prototype")
  695.             {
  696.                 attack = self should_attack_player_thru_boards();
  697.                 if(isDefined(attack) && !attack && self.has_legs)
  698.                 {
  699.                     self do_a_taunt();
  700.                 }              
  701.             }      
  702.             //chrisp - fix the extra tear anim bug
  703.             if( all_chunks_destroyed( self.first_node.barrier_chunks ) )
  704.             {
  705.                 for( i = 0; i < self.first_node.attack_spots_taken.size; i++ )
  706.                 {
  707.                     self.first_node.attack_spots_taken[i] = false;
  708.                 }
  709.                 return;
  710.             }  
  711.         }
  712.         self reset_attack_spot();
  713.     }      
  714. }
  715.  
  716. /*------------------------------------
  717. checks to see if the zombie should
  718. do a taunt when tearing thru the boards
  719. ------------------------------------*/
  720. do_a_taunt()
  721. {
  722.     if( !self.has_legs)
  723.     {
  724.         return false;
  725.     }
  726.  
  727.     self.old_origin = self.origin;
  728.     if(getdvar("zombie_taunt_freq") == "")
  729.     {
  730.         setdvar("zombie_taunt_freq","5");
  731.     }
  732.     freq = getdvarint("zombie_taunt_freq");
  733.    
  734.     if( freq >= randomint(100) )
  735.     {
  736.         anime = random(level._zombie_board_taunt[self.animname]);
  737.         self animscripted("zombie_taunt",self.origin,self.angles,anime);
  738.         wait(getanimlength(anime));
  739.         self teleport(self.old_origin);
  740.     }
  741. }
  742.  
  743. /*------------------------------------
  744. checks to see if the players are near
  745. the entrance and tries to attack them
  746. thru the boards. 50% chance
  747. ------------------------------------*/
  748. should_attack_player_thru_boards()
  749. {
  750.    
  751.     //no board attacks if they are crawlers
  752.     if( !self.has_legs)
  753.     {
  754.         return false;
  755.     }
  756.    
  757.     if(getdvar("zombie_reachin_freq") == "")
  758.     {
  759.         setdvar("zombie_reachin_freq","50");
  760.     }
  761.     freq = getdvarint("zombie_reachin_freq");
  762.    
  763.     players = get_players();
  764.     attack = false;
  765.    
  766.     for(i=0;i<players.size;i++)
  767.     {
  768.         if(distance2d(self.origin,players[i].origin) <= 72)
  769.         {
  770.             attack = true;
  771.         }
  772.     }  
  773.     if(attack && freq >= randomint(100) )
  774.     {
  775.         //iprintln("checking attack");
  776.        
  777.         //check to see if the guy is left, right, or center
  778.         self.old_origin = self.origin;
  779.         if(self.attacking_spot_index == 0) //he's in the center
  780.         {
  781.            
  782.         if(randomint(100) > 50)
  783.         {
  784.            
  785.                 self animscripted("window_melee",self.origin,self.angles,%ai_zombie_window_attack_arm_l_out);
  786.         }
  787.         else
  788.         {
  789.             self animscripted("window_melee",self.origin,self.angles,%ai_zombie_window_attack_arm_r_out);
  790.         }
  791.         self window_notetracks( "window_melee" );
  792.    
  793.  
  794.  
  795.  
  796.            
  797.         }
  798.         else if(self.attacking_spot_index == 2) //<-- he's to the left
  799.         {
  800.             self animscripted("window_melee",self.origin,self.angles,%ai_zombie_window_attack_arm_r_out);
  801.             self window_notetracks( "window_melee" );
  802.         }
  803.         else if(self.attacking_spot_index == 1) //<-- he's to the right
  804.         {
  805.             self animscripted("window_melee",self.origin,self.angles,%ai_zombie_window_attack_arm_l_out);
  806.             self window_notetracks( "window_melee" );
  807.         }                  
  808.     }
  809.     else
  810.     {
  811.         return false;  
  812.     }
  813. }
  814. window_notetracks(msg)
  815. {
  816.     while(1)
  817.     {
  818.         self waittill( msg, notetrack );
  819.  
  820.         if( notetrack == "end" )
  821.         {
  822.             //self waittill("end");
  823.             self teleport(self.old_origin);
  824.  
  825.             return;
  826.         }
  827.         if( notetrack == "fire" )
  828.         {
  829.             if(self.ignoreall)
  830.             {
  831.                 self.ignoreall = false;
  832.             }
  833.             self melee();
  834.         }
  835.     }
  836. }
  837.  
  838.  
  839. crash_into_building()
  840. {
  841.     self endon( "death" );
  842.  
  843.     self zombie_history( "tear_into_building -> start" );
  844.  
  845.     while( 1 )
  846.     {
  847.         if( IsDefined( self.first_node.script_noteworthy ) )
  848.         {
  849.             if( self.first_node.script_noteworthy == "no_blocker" )
  850.             {
  851.                 return;
  852.             }
  853.         }
  854.  
  855.         if( !IsDefined( self.first_node.target ) )
  856.         {
  857.             return;
  858.         }
  859.  
  860.         if( all_chunks_destroyed( self.first_node.barrier_chunks ) )
  861.         {
  862.             self zombie_history( "tear_into_building -> all chunks destroyed" );
  863.             return;
  864.         }
  865.  
  866.         // Pick a spot to tear down
  867.         if( !get_attack_spot( self.first_node ) )
  868.         {
  869.             self zombie_history( "tear_into_building -> Could not find an attack spot" );
  870.             wait( 0.5 );
  871.             continue;
  872.         }
  873.  
  874.         self.goalradius = 4;
  875.         self SetGoalPos( self.attacking_spot, self.first_node.angles );
  876.         self waittill( "goal" );
  877.         self zombie_history( "tear_into_building -> Reach position and orientated" );
  878.  
  879.         // Now tear down boards
  880.         while( 1 )
  881.         {
  882.             chunk = get_closest_non_destroyed_chunk( self.origin, self.first_node.barrier_chunks );
  883.    
  884.             if( !IsDefined( chunk ) )
  885.             {
  886.                 for( i = 0; i < self.first_node.attack_spots_taken.size; i++ )
  887.                 {
  888.                     self.first_node.attack_spots_taken[i] = false;
  889.                 }
  890.                 return;
  891.             }
  892.  
  893.             self zombie_history( "tear_into_building -> crash" );
  894.  
  895.             //tear_anim = get_tear_anim( chunk );
  896.             //self AnimScripted( "tear_anim", self.origin, self.first_node.angles, tear_anim );
  897.             //self zombie_tear_notetracks( "tear_anim", chunk, self.first_node );
  898.             PlayFx( level._effect["wood_chunk_destory"], chunk.origin );
  899.             PlayFx( level._effect["wood_chunk_destory"], chunk.origin + ( randomint( 20 ), randomint( 20 ), randomint( 10 ) ) );
  900.             PlayFx( level._effect["wood_chunk_destory"], chunk.origin + ( randomint( 40 ), randomint( 40 ), randomint( 20 ) ) );
  901.    
  902.             level thread maps\_zombiemode_blockers_new::remove_chunk( chunk, self.first_node, true );
  903.            
  904.             if( all_chunks_destroyed( self.first_node.barrier_chunks ) )
  905.             {
  906.                 EarthQuake( randomfloatrange( 0.5, 0.8 ), 0.5, chunk.origin, 300 );
  907.    
  908.                 if( IsDefined( self.first_node.clip ) )
  909.                 {
  910.                     self.first_node.clip ConnectPaths();
  911.                     wait( 0.05 );
  912.                     self.first_node.clip disable_trigger();
  913.                 }
  914.                 else
  915.                 {
  916.                     for( i = 0; i < self.first_node.barrier_chunks.size; i++ )
  917.                     {
  918.                         self.first_node.barrier_chunks[i] ConnectPaths();
  919.                     }
  920.                 }
  921.             }
  922.             else
  923.             {
  924.                 EarthQuake( RandomFloatRange( 0.1, 0.15 ), 0.2, chunk.origin, 200 );
  925.             }
  926.                    
  927.         }
  928.  
  929.         self reset_attack_spot();
  930.     }      
  931. }
  932.  
  933. reset_attack_spot()
  934. {
  935.     if( IsDefined( self.attacking_node ) )
  936.     {
  937.         node = self.attacking_node;
  938.         index = self.attacking_spot_index;
  939.         node.attack_spots_taken[index] = false;
  940.  
  941.         self.attacking_node = undefined;
  942.         self.attacking_spot_index = undefined;
  943.     }
  944. }
  945.  
  946. get_attack_spot( node )
  947. {
  948.     index = get_attack_spot_index( node );
  949.     if( !IsDefined( index ) )
  950.     {
  951.         return false;
  952.     }
  953.  
  954.     self.attacking_node = node;
  955.     self.attacking_spot_index = index;
  956.     node.attack_spots_taken[index] = true;
  957.     self.attacking_spot = node.attack_spots[index];
  958.  
  959.     return true;
  960. }
  961.  
  962. get_attack_spot_index( node )
  963. {
  964.     indexes = [];
  965.     for( i = 0; i < node.attack_spots.size; i++ )
  966.     {
  967.         if( !node.attack_spots_taken[i] )
  968.         {
  969.             indexes[indexes.size] = i;
  970.         }
  971.     }
  972.  
  973.     if( indexes.size == 0 )
  974.     {
  975.         return undefined;
  976.     }
  977.  
  978.     return indexes[RandomInt( indexes.size )];
  979. }
  980.  
  981. zombie_tear_notetracks( msg, chunk, node )
  982. {
  983.  
  984.     self endon("death");
  985.  
  986.     chunk thread check_for_zombie_death(self);
  987.     while( 1 )
  988.     {
  989.         self waittill( msg, notetrack );
  990.  
  991.         if( notetrack == "end" )
  992.         {
  993.             return;
  994.         }
  995.  
  996.         if( notetrack == "board" )
  997.         {
  998.             if( !chunk.destroyed )
  999.             {
  1000.                 self.lastchunk_destroy_time = getTime();
  1001.    
  1002.                 PlayFx( level._effect["wood_chunk_destory"], chunk.origin );
  1003.                 PlayFx( level._effect["wood_chunk_destory"], chunk.origin + ( randomint( 20 ), randomint( 20 ), randomint( 10 ) ) );
  1004.                 PlayFx( level._effect["wood_chunk_destory"], chunk.origin + ( randomint( 40 ), randomint( 40 ), randomint( 20 ) ) );
  1005.    
  1006.                 level thread maps\_zombiemode_blockers_new::remove_chunk( chunk, node, true );
  1007.             }
  1008.         }
  1009.     }
  1010. }
  1011.  
  1012. check_for_zombie_death(zombie)
  1013. {
  1014.     self endon( "destroyed" );
  1015.     zombie waittill( "death" );
  1016.  
  1017.     self.target_by_zombie = undefined;
  1018. }
  1019.  
  1020.  
  1021.  
  1022. get_tear_anim( chunk, zombo )
  1023. {
  1024.  
  1025.     //level._zombie_board_tearing["left"]["one"] = %ai_zombie_boardtear_l_1;
  1026.     //level._zombie_board_tearing["left"]["two"] = %ai_zombie_boardtear_l_2;
  1027.     //level._zombie_board_tearing["left"]["three"] = %ai_zombie_boardtear_l_3;
  1028.     //level._zombie_board_tearing["left"]["four"] = %ai_zombie_boardtear_l_4;
  1029.     //level._zombie_board_tearing["left"]["five"] = %ai_zombie_boardtear_l_5;
  1030.     //level._zombie_board_tearing["left"]["six"] = %ai_zombie_boardtear_l_6;
  1031.  
  1032.     //level._zombie_board_tearing["middle"]["one"] = %ai_zombie_boardtear_m_1;
  1033.     //level._zombie_board_tearing["middle"]["two"] = %ai_zombie_boardtear_m_2;
  1034.     //level._zombie_board_tearing["middle"]["three"] = %ai_zombie_boardtear_m_3;
  1035.     //level._zombie_board_tearing["middle"]["four"] = %ai_zombie_boardtear_m_4;
  1036.     //level._zombie_board_tearing["middle"]["five"] = %ai_zombie_boardtear_m_5;
  1037.     //level._zombie_board_tearing["middle"]["six"] = %ai_zombie_boardtear_m_6;
  1038.  
  1039.     //level._zombie_board_tearing["right"]["one"] = %ai_zombie_boardtear_r_1;
  1040.     //level._zombie_board_tearing["right"]["two"] = %ai_zombie_boardtear_r_2;
  1041.     //level._zombie_board_tearing["right"]["three"] = %ai_zombie_boardtear_r_3;
  1042.     //level._zombie_board_tearing["right"]["four"] = %ai_zombie_boardtear_r_4;
  1043.     //level._zombie_board_tearing["right"]["five"] = %ai_zombie_boardtear_r_5;
  1044.     //level._zombie_board_tearing["right"]["six"] = %ai_zombie_boardtear_r_6;
  1045.     anims = [];
  1046.     anims[anims.size] = %ai_zombie_door_tear_left;
  1047.     anims[anims.size] = %ai_zombie_door_tear_right;
  1048.  
  1049.     tear_anim = anims[RandomInt( anims.size )];
  1050.  
  1051.     if( self.has_legs )
  1052.     {
  1053.  
  1054.         if(isdefined(chunk.script_noteworthy))
  1055.         {
  1056.  
  1057.             if(zombo.attacking_spot_index == 0)
  1058.             {
  1059.                 if(chunk.script_noteworthy == "1")
  1060.                 {
  1061.  
  1062.                     tear_anim = %ai_zombie_boardtear_m_1;
  1063.  
  1064.                 }
  1065.                 else if(chunk.script_noteworthy == "2")
  1066.                 {
  1067.  
  1068.                     tear_anim = %ai_zombie_boardtear_m_2;
  1069.                 }
  1070.                 else if(chunk.script_noteworthy == "3")
  1071.                 {
  1072.  
  1073.                     tear_anim = %ai_zombie_boardtear_m_3;
  1074.                 }
  1075.                 else if(chunk.script_noteworthy == "4")
  1076.                 {
  1077.  
  1078.                     tear_anim = %ai_zombie_boardtear_m_4;
  1079.                 }
  1080.                 else if(chunk.script_noteworthy == "5")
  1081.                 {
  1082.  
  1083.                     tear_anim = %ai_zombie_boardtear_m_5;
  1084.                 }
  1085.                 else if(chunk.script_noteworthy == "6")
  1086.                 {
  1087.  
  1088.                     tear_anim = %ai_zombie_boardtear_m_6;
  1089.                 }
  1090.  
  1091.             }
  1092.             else if(zombo.attacking_spot_index == 1)
  1093.             {
  1094.                 if(chunk.script_noteworthy == "1")
  1095.                 {
  1096.  
  1097.                     tear_anim = %ai_zombie_boardtear_r_1;
  1098.  
  1099.                 }
  1100.                 else if(chunk.script_noteworthy == "3")
  1101.                 {
  1102.  
  1103.                     tear_anim = %ai_zombie_boardtear_r_3;
  1104.                 }
  1105.                 else if(chunk.script_noteworthy == "4")
  1106.                 {
  1107.  
  1108.                     tear_anim = %ai_zombie_boardtear_r_4;
  1109.                 }
  1110.                 else if(chunk.script_noteworthy == "5")
  1111.                 {
  1112.  
  1113.                     tear_anim = %ai_zombie_boardtear_r_5;
  1114.                 }
  1115.                 else if(chunk.script_noteworthy == "6")
  1116.                 {
  1117.                     tear_anim = %ai_zombie_boardtear_r_6;
  1118.                 }
  1119.                 else if(chunk.script_noteworthy == "2")
  1120.                 {
  1121.  
  1122.                     tear_anim = %ai_zombie_boardtear_r_2;
  1123.                 }
  1124.  
  1125.             }
  1126.             else if(zombo.attacking_spot_index == 2)
  1127.             {
  1128.                 if(chunk.script_noteworthy == "1")
  1129.                 {
  1130.  
  1131.                     tear_anim = %ai_zombie_boardtear_l_1;
  1132.  
  1133.                 }
  1134.                 else if(chunk.script_noteworthy == "2")
  1135.                 {
  1136.  
  1137.                     tear_anim = %ai_zombie_boardtear_l_2;
  1138.                 }
  1139.                 else if(chunk.script_noteworthy == "4")
  1140.                 {
  1141.  
  1142.                     tear_anim = %ai_zombie_boardtear_l_4;
  1143.                 }
  1144.                 else if(chunk.script_noteworthy == "5")
  1145.                 {
  1146.  
  1147.                     tear_anim = %ai_zombie_boardtear_l_5;
  1148.                 }
  1149.                 else if(chunk.script_noteworthy == "6")
  1150.                 {
  1151.                     tear_anim = %ai_zombie_boardtear_l_6;
  1152.                 }
  1153.                 else if(chunk.script_noteworthy == "3")
  1154.                 {
  1155.  
  1156.                     tear_anim = %ai_zombie_boardtear_l_3;
  1157.                 }
  1158.  
  1159.             }
  1160.  
  1161.         }
  1162.         else
  1163.         {
  1164.             z_dist = chunk.origin[2] - self.origin[2];
  1165.             if( z_dist > 70 )
  1166.             {
  1167.                 tear_anim = %ai_zombie_door_tear_high;
  1168.             }
  1169.             else if( z_dist < 40 )
  1170.             {
  1171.                 tear_anim = %ai_zombie_door_tear_low;
  1172.             }
  1173.             else
  1174.             {
  1175.                 anims = [];
  1176.                 anims[anims.size] = %ai_zombie_door_tear_left;
  1177.                 anims[anims.size] = %ai_zombie_door_tear_right;
  1178.  
  1179.                 tear_anim = anims[RandomInt( anims.size )];
  1180.             }
  1181.         }
  1182.  
  1183.     }
  1184.     else
  1185.     {
  1186.  
  1187.         if(isdefined(chunk.script_noteworthy))
  1188.         {
  1189.  
  1190.             if(zombo.attacking_spot_index == 0)
  1191.             {
  1192.                 if(chunk.script_noteworthy == "1")
  1193.                 {
  1194.  
  1195.                     tear_anim = %ai_zombie_boardtear_crawl_m_1;
  1196.  
  1197.                 }
  1198.                 else if(chunk.script_noteworthy == "2")
  1199.                 {
  1200.  
  1201.                     tear_anim = %ai_zombie_boardtear_crawl_m_2;
  1202.                 }
  1203.                 else if(chunk.script_noteworthy == "3")
  1204.                 {
  1205.  
  1206.                     tear_anim = %ai_zombie_boardtear_crawl_m_3;
  1207.                 }
  1208.                 else if(chunk.script_noteworthy == "4")
  1209.                 {
  1210.  
  1211.                     tear_anim = %ai_zombie_boardtear_crawl_m_4;
  1212.                 }
  1213.                 else if(chunk.script_noteworthy == "5")
  1214.                 {
  1215.  
  1216.                     tear_anim = %ai_zombie_boardtear_crawl_m_5;
  1217.                 }
  1218.                 else if(chunk.script_noteworthy == "6")
  1219.                 {
  1220.  
  1221.                     tear_anim = %ai_zombie_boardtear_crawl_m_6;
  1222.                 }
  1223.  
  1224.             }
  1225.             else if(zombo.attacking_spot_index == 1)
  1226.             {
  1227.                 if(chunk.script_noteworthy == "1")
  1228.                 {
  1229.  
  1230.                     tear_anim = %ai_zombie_boardtear_crawl_r_1;
  1231.  
  1232.                 }
  1233.                 else if(chunk.script_noteworthy == "3")
  1234.                 {
  1235.  
  1236.                     tear_anim = %ai_zombie_boardtear_crawl_r_3;
  1237.                 }
  1238.                 else if(chunk.script_noteworthy == "4")
  1239.                 {
  1240.  
  1241.                     tear_anim = %ai_zombie_boardtear_crawl_r_4;
  1242.                 }
  1243.                 else if(chunk.script_noteworthy == "5")
  1244.                 {
  1245.  
  1246.                     tear_anim = %ai_zombie_boardtear_crawl_r_5;
  1247.                 }
  1248.                 else if(chunk.script_noteworthy == "6")
  1249.                 {
  1250.                     tear_anim = %ai_zombie_boardtear_crawl_r_6;
  1251.                 }
  1252.                 else if(chunk.script_noteworthy == "2")
  1253.                 {
  1254.  
  1255.                     tear_anim = %ai_zombie_boardtear_crawl_r_2;
  1256.                 }
  1257.  
  1258.             }
  1259.             else if(zombo.attacking_spot_index == 2)
  1260.             {
  1261.                 if(chunk.script_noteworthy == "1")
  1262.                 {
  1263.  
  1264.                     tear_anim = %ai_zombie_boardtear_crawl_l_1;
  1265.  
  1266.                 }
  1267.                 else if(chunk.script_noteworthy == "2")
  1268.                 {
  1269.  
  1270.                     tear_anim = %ai_zombie_boardtear_crawl_l_2;
  1271.                 }
  1272.                 else if(chunk.script_noteworthy == "4")
  1273.                 {
  1274.  
  1275.                     tear_anim = %ai_zombie_boardtear_crawl_l_4;
  1276.                 }
  1277.                 else if(chunk.script_noteworthy == "5")
  1278.                 {
  1279.  
  1280.                     tear_anim = %ai_zombie_boardtear_crawl_l_5;
  1281.                 }
  1282.                 else if(chunk.script_noteworthy == "6")
  1283.                 {
  1284.                     tear_anim = %ai_zombie_boardtear_crawl_l_6;
  1285.                 }
  1286.                 else if(chunk.script_noteworthy == "3")
  1287.                 {
  1288.  
  1289.                     tear_anim = %ai_zombie_boardtear_crawl_l_3;
  1290.                 }
  1291.  
  1292.             }
  1293.  
  1294.  
  1295.  
  1296.         }
  1297.         else
  1298.         {
  1299.             anims = [];
  1300.             anims[anims.size] = %ai_zombie_attack_crawl;
  1301.             anims[anims.size] = %ai_zombie_attack_crawl_lunge;
  1302.  
  1303.             tear_anim = anims[RandomInt( anims.size )];
  1304.         }
  1305.        
  1306.     }
  1307.  
  1308.     return tear_anim;
  1309. }
  1310.  
  1311. cap_zombie_head_gibs()
  1312. {
  1313.     if( !isDefined( level.max_head_gibs_per_frame ) )
  1314.     {
  1315.         level.max_head_gibs_per_frame = 4;
  1316.     }
  1317.    
  1318.     while( true )
  1319.     {
  1320.         level.head_gibs_this_frame = 0;
  1321.         wait_network_frame();
  1322.     }
  1323. }
  1324.  
  1325. zombie_head_gib( attacker )
  1326. {
  1327.     if ( is_german_build() )
  1328.     {
  1329.         return;
  1330.     }
  1331.  
  1332.     if( IsDefined( self.head_gibbed ) && self.head_gibbed )
  1333.     {
  1334.         return;
  1335.     }
  1336.    
  1337.     if( !isDefined( level.head_gibs_this_frame ) )
  1338.     {
  1339.         level thread cap_zombie_head_gibs();
  1340.     }
  1341.    
  1342.     if( level.head_gibs_this_frame >= level.max_head_gibs_per_frame )
  1343.     {
  1344.         return;
  1345.     }
  1346.  
  1347.     level.head_gibs_this_frame++;
  1348.  
  1349.     self.head_gibbed = true;
  1350.     self zombie_eye_glow_stop();
  1351.  
  1352.     size = self GetAttachSize();
  1353.     for( i = 0; i < size; i++ )
  1354.     {
  1355.         model = self GetAttachModelName( i );
  1356.         if( IsSubStr( model, "head" ) )
  1357.         {
  1358.             // SRS 9/2/2008: wet em up
  1359.             self thread headshot_blood_fx();
  1360.             if(isdefined(self.hatmodel))
  1361.             {
  1362.                 self detach( self.hatModel, "" );
  1363.             }
  1364.  
  1365.             self play_sound_on_ent( "zombie_head_gib" );
  1366.            
  1367.             self Detach( model, "", true );
  1368.             self Attach( "char_ger_honorgd_zomb_behead", "", true );
  1369.             break;
  1370.         }
  1371.     }
  1372.  
  1373.     self thread damage_over_time( self.health * 0.2, 1, attacker );
  1374. }
  1375.  
  1376. damage_over_time( dmg, delay, attacker )
  1377. {
  1378.     self endon( "death" );
  1379.  
  1380.     if( !IsAlive( self ) )
  1381.     {
  1382.         return;
  1383.     }
  1384.  
  1385.     if( !IsPlayer( attacker ) )
  1386.     {
  1387.         attacker = undefined;
  1388.     }
  1389.  
  1390.     while( 1 )
  1391.     {
  1392.         wait( delay );
  1393.  
  1394.         if( IsDefined( attacker ) )
  1395.         {
  1396.             self DoDamage( dmg, self.origin, attacker );
  1397.         }
  1398.         else
  1399.         {
  1400.             self DoDamage( dmg, self.origin );
  1401.         }
  1402.     }
  1403. }
  1404.  
  1405. // SRS 9/2/2008: reordered checks, added ability to gib heads with airburst grenades
  1406. head_should_gib( attacker, type, point )
  1407. {
  1408.     if ( is_german_build() )
  1409.     {
  1410.         return false;
  1411.     }
  1412.  
  1413.     if( self.head_gibbed )
  1414.     {
  1415.         return false;
  1416.     }
  1417.  
  1418.     // check if the attacker was a player
  1419.     if( !IsDefined( attacker ) || !IsPlayer( attacker ) )
  1420.     {
  1421.         return false;
  1422.     }
  1423.  
  1424.     // check the enemy's health
  1425.     low_health_percent = ( self.health / self.maxhealth ) * 100;
  1426.     if( low_health_percent > 10 )
  1427.     {
  1428.         return false;
  1429.     }
  1430.  
  1431.     weapon = attacker GetCurrentWeapon();
  1432.  
  1433.  
  1434.     // SRS 9/2/2008: check for damage type
  1435.     //  - most SMGs use pistol bullets
  1436.     //  - projectiles = rockets, raygun
  1437.     if( type != "MOD_RIFLE_BULLET" && type != "MOD_PISTOL_BULLET" )
  1438.     {
  1439.         // maybe it's ok, let's see if it's a grenade
  1440.         if( type == "MOD_GRENADE" || type == "MOD_GRENADE_SPLASH" )
  1441.         {
  1442.             if( Distance( point, self GetTagOrigin( "j_head" ) ) > 55 )
  1443.             {
  1444.                 return false;
  1445.             }
  1446.             else
  1447.             {
  1448.                 // the grenade airburst close to the head so return true
  1449.                 return true;
  1450.             }
  1451.         }
  1452.         else if( type == "MOD_PROJECTILE" )
  1453.         {
  1454.             if( Distance( point, self GetTagOrigin( "j_head" ) ) > 10 )
  1455.             {
  1456.                 return false;
  1457.             }
  1458.             else
  1459.             {
  1460.                 return true;
  1461.             }
  1462.         }
  1463.         // shottys don't give a testable damage type but should still gib heads
  1464.         else if( WeaponClass( weapon ) != "spread" )
  1465.         {
  1466.             return false;
  1467.         }
  1468.     }
  1469.  
  1470.     // check location now that we've checked for grenade damage (which reports "none" as a location)
  1471.     if( !self animscripts\utility::damageLocationIsAny( "head", "helmet", "neck" ) )
  1472.     {
  1473.         return false;
  1474.     }
  1475.  
  1476.     // check weapon - don't want "none", pistol, or flamethrower
  1477.     if( weapon == "none"  || WeaponClass( weapon ) == "pistol" || WeaponIsGasWeapon( self.weapon ) )
  1478.     {
  1479.         return false;
  1480.     }
  1481.  
  1482.     return true;
  1483. }
  1484.  
  1485. // does blood fx for fun and to mask head gib swaps
  1486. headshot_blood_fx()
  1487. {
  1488.     if( !IsDefined( self ) )
  1489.     {
  1490.         return;
  1491.     }
  1492.  
  1493.     if( !is_mature() )
  1494.     {
  1495.         return;
  1496.     }
  1497.  
  1498.     fxTag = "j_neck";
  1499.     fxOrigin = self GetTagOrigin( fxTag );
  1500.     upVec = AnglesToUp( self GetTagAngles( fxTag ) );
  1501.     forwardVec = AnglesToForward( self GetTagAngles( fxTag ) );
  1502.    
  1503.     // main head pop fx
  1504.     PlayFX( level._effect["headshot"], fxOrigin, forwardVec, upVec );
  1505.     PlayFX( level._effect["headshot_nochunks"], fxOrigin, forwardVec, upVec );
  1506.    
  1507.     wait( 0.3 );
  1508.     if(IsDefined( self ))
  1509.     {
  1510.         if( self maps\_zombiemode_tesla::enemy_killed_by_tesla() )
  1511.         {
  1512.             PlayFxOnTag( level._effect["tesla_head_light"], self, fxTag );
  1513.         }
  1514.         else
  1515.         {
  1516.             PlayFxOnTag( level._effect["bloodspurt"], self, fxTag );
  1517.         }
  1518.     }
  1519. }
  1520.  
  1521. // gib limbs if enough firepower occurs
  1522. zombie_gib_on_damage()
  1523. {
  1524. //  self endon( "death" );
  1525.  
  1526.     while( 1 )
  1527.     {
  1528.         self waittill( "damage", amount, attacker, direction_vec, point, type );
  1529.  
  1530.         if( !IsDefined( self ) )
  1531.         {
  1532.             return;
  1533.         }
  1534.  
  1535.         if( !self zombie_should_gib( amount, attacker, type ) )
  1536.         {
  1537.             continue;
  1538.         }
  1539.  
  1540.         if( self head_should_gib( attacker, type, point ) && type != "MOD_BURNED" )
  1541.         {
  1542.             self zombie_head_gib( attacker );
  1543.             if(IsDefined(attacker.headshot_count))
  1544.             {
  1545.                 attacker.headshot_count++;
  1546.             }
  1547.             else
  1548.             {
  1549.                 attacker.headshot_count = 1;
  1550.             }
  1551.             //stats tracking
  1552.             attacker.stats["headshots"] = attacker.headshot_count;
  1553.             attacker.stats["zombie_gibs"]++;
  1554.  
  1555.             continue;
  1556.         }
  1557.  
  1558.         if( !self.gibbed )
  1559.         {
  1560.             // The head_should_gib() above checks for this, so we should not randomly gib if shot in the head
  1561.             if( self animscripts\utility::damageLocationIsAny( "head", "helmet", "neck" ) )
  1562.             {
  1563.                 continue;
  1564.             }
  1565.  
  1566.             refs = [];
  1567.             switch( self.damageLocation )
  1568.             {
  1569.                 case "torso_upper":
  1570.                 case "torso_lower":
  1571.                     // HACK the torso that gets swapped for guts also removes the left arm
  1572.                     //  so we need to sometimes do another ref
  1573.                     refs[refs.size] = "guts";
  1574.                     refs[refs.size] = "right_arm";
  1575.                     break;
  1576.    
  1577.                 case "right_arm_upper":
  1578.                 case "right_arm_lower":
  1579.                 case "right_hand":
  1580.                     //if( IsDefined( self.left_arm_gibbed ) )
  1581.                     //  refs[refs.size] = "no_arms";
  1582.                     //else
  1583.                     refs[refs.size] = "right_arm";
  1584.    
  1585.                     //self.right_arm_gibbed = true;
  1586.                     break;
  1587.    
  1588.                 case "left_arm_upper":
  1589.                 case "left_arm_lower":
  1590.                 case "left_hand":
  1591.                     //if( IsDefined( self.right_arm_gibbed ) )
  1592.                     //  refs[refs.size] = "no_arms";
  1593.                     //else
  1594.                     refs[refs.size] = "left_arm";
  1595.    
  1596.                     //self.left_arm_gibbed = true;
  1597.                     break;
  1598.    
  1599.                 case "right_leg_upper":
  1600.                 case "right_leg_lower":
  1601.                 case "right_foot":
  1602.                     if( self.health <= 0 )
  1603.                     {
  1604.                         // Addition "right_leg" refs so that the no_legs happens less and is more rare
  1605.                         refs[refs.size] = "right_leg";
  1606.                         refs[refs.size] = "right_leg";
  1607.                         refs[refs.size] = "right_leg";
  1608.                         refs[refs.size] = "no_legs";
  1609.                     }
  1610.                     break;
  1611.    
  1612.                 case "left_leg_upper":
  1613.                 case "left_leg_lower":
  1614.                 case "left_foot":
  1615.                     if( self.health <= 0 )
  1616.                     {
  1617.                         // Addition "left_leg" refs so that the no_legs happens less and is more rare
  1618.                         refs[refs.size] = "left_leg";
  1619.                         refs[refs.size] = "left_leg";
  1620.                         refs[refs.size] = "left_leg";
  1621.                         refs[refs.size] = "no_legs";
  1622.                     }
  1623.                     break;
  1624.             default:
  1625.                
  1626.                 if( self.damageLocation == "none" )
  1627.                 {
  1628.                     // SRS 9/7/2008: might be a nade or a projectile
  1629.                     if( type == "MOD_GRENADE" || type == "MOD_GRENADE_SPLASH" || type == "MOD_PROJECTILE" )
  1630.                     {
  1631.                         // ... in which case we have to derive the ref ourselves
  1632.                         refs = self derive_damage_refs( point );
  1633.                         break;
  1634.                     }
  1635.                 }
  1636.                 else
  1637.                 {
  1638.                     refs[refs.size] = "guts";
  1639.                     refs[refs.size] = "right_arm";
  1640.                     refs[refs.size] = "left_arm";
  1641.                     refs[refs.size] = "right_leg";
  1642.                     refs[refs.size] = "left_leg";
  1643.                     refs[refs.size] = "no_legs";
  1644.                     break;
  1645.                 }
  1646.             }
  1647.  
  1648.             if( refs.size )
  1649.             {
  1650.                 self.a.gib_ref = animscripts\death::get_random( refs );
  1651.            
  1652.                 // Don't stand if a leg is gone
  1653.                 if( ( self.a.gib_ref == "no_legs" || self.a.gib_ref == "right_leg" || self.a.gib_ref == "left_leg" ) && self.health > 0 )
  1654.                 {
  1655.                     self.has_legs = false;
  1656.                     self AllowedStances( "crouch" );
  1657.                                        
  1658.                     which_anim = RandomInt( 5 );
  1659.                     if(self.a.gib_ref == "no_legs")
  1660.                     {
  1661.                        
  1662.                         if(randomint(100) < 50)
  1663.                         {
  1664.                             self.deathanim = %ai_zombie_crawl_death_v1;
  1665.                             self set_run_anim( "death3" );
  1666.                             self.run_combatanim = level.scr_anim[self.animname]["crawl_hand_1"];
  1667.                             self.crouchRunAnim = level.scr_anim[self.animname]["crawl_hand_1"];
  1668.                             self.crouchrun_combatanim = level.scr_anim[self.animname]["crawl_hand_1"];
  1669.                         }
  1670.                         else
  1671.                         {
  1672.                             self.deathanim = %ai_zombie_crawl_death_v1;
  1673.                             self set_run_anim( "death3" );
  1674.                             self.run_combatanim = level.scr_anim[self.animname]["crawl_hand_2"];
  1675.                             self.crouchRunAnim = level.scr_anim[self.animname]["crawl_hand_2"];
  1676.                             self.crouchrun_combatanim = level.scr_anim[self.animname]["crawl_hand_2"];
  1677.                         }
  1678.  
  1679.  
  1680.                     }
  1681.                     else if( which_anim == 0 )
  1682.                     {
  1683.                         self.deathanim = %ai_zombie_crawl_death_v1;
  1684.                         self set_run_anim( "death3" );
  1685.                         self.run_combatanim = level.scr_anim[self.animname]["crawl1"];
  1686.                         self.crouchRunAnim = level.scr_anim[self.animname]["crawl1"];
  1687.                         self.crouchrun_combatanim = level.scr_anim[self.animname]["crawl1"];
  1688.                     }
  1689.                     else if( which_anim == 1 )
  1690.                     {
  1691.                         self.deathanim = %ai_zombie_crawl_death_v2;
  1692.                         self set_run_anim( "death4" );
  1693.                         self.run_combatanim = level.scr_anim[self.animname]["crawl2"];
  1694.                         self.crouchRunAnim = level.scr_anim[self.animname]["crawl2"];
  1695.                         self.crouchrun_combatanim = level.scr_anim[self.animname]["crawl2"];
  1696.                     }
  1697.                     else if( which_anim == 2 )
  1698.                     {
  1699.                         self.deathanim = %ai_zombie_crawl_death_v1;
  1700.                         self set_run_anim( "death3" );
  1701.                         self.run_combatanim = level.scr_anim[self.animname]["crawl3"];
  1702.                         self.crouchRunAnim = level.scr_anim[self.animname]["crawl3"];
  1703.                         self.crouchrun_combatanim = level.scr_anim[self.animname]["crawl3"];
  1704.                     }
  1705.                     else if( which_anim == 3 )
  1706.                     {
  1707.                         self.deathanim = %ai_zombie_crawl_death_v2;
  1708.                         self set_run_anim( "death4" );
  1709.                         self.run_combatanim = level.scr_anim[self.animname]["crawl4"];
  1710.                         self.crouchRunAnim = level.scr_anim[self.animname]["crawl4"];
  1711.                         self.crouchrun_combatanim = level.scr_anim[self.animname]["crawl4"];
  1712.                     }
  1713.                     else if( which_anim == 4 )
  1714.                     {
  1715.                         self.deathanim = %ai_zombie_crawl_death_v1;
  1716.                         self set_run_anim( "death3" );
  1717.                         self.run_combatanim = level.scr_anim[self.animname]["crawl5"];
  1718.                         self.crouchRunAnim = level.scr_anim[self.animname]["crawl5"];
  1719.                         self.crouchrun_combatanim = level.scr_anim[self.animname]["crawl5"];
  1720.                     }
  1721.                                        
  1722.                 }
  1723.             }
  1724.  
  1725.             if( self.health > 0 )
  1726.             {
  1727.                 // force gibbing if the zombie is still alive
  1728.                 self thread animscripts\death::do_gib();
  1729.  
  1730.                 //stat tracking
  1731.                 attacker.stats["zombie_gibs"]++;
  1732.             }
  1733.         }
  1734.     }
  1735. }
  1736.  
  1737.  
  1738. zombie_should_gib( amount, attacker, type )
  1739. {
  1740.     if ( is_german_build() )
  1741.     {
  1742.         return false;
  1743.     }
  1744.  
  1745.     if( !IsDefined( type ) )
  1746.     {
  1747.         return false;
  1748.     }
  1749.  
  1750.     switch( type )
  1751.     {
  1752.         case "MOD_UNKNOWN":
  1753.         case "MOD_CRUSH":
  1754.         case "MOD_TELEFRAG":
  1755.         case "MOD_FALLING":
  1756.         case "MOD_SUICIDE":
  1757.         case "MOD_TRIGGER_HURT":
  1758.         case "MOD_BURNED": 
  1759.             return false;
  1760.         case "MOD_MELEE":  
  1761.             if( isPlayer( attacker ) && randomFloat( 1 ) > 0.25 && attacker HasPerk( "specialty_altmelee" ) )
  1762.             {
  1763.                 return true;
  1764.             }
  1765.             else
  1766.             {
  1767.                 return false;
  1768.             }
  1769.     }
  1770.  
  1771.     if( type == "MOD_PISTOL_BULLET" || type == "MOD_RIFLE_BULLET" )
  1772.     {
  1773.         if( !IsDefined( attacker ) || !IsPlayer( attacker ) )
  1774.         {
  1775.             return false;
  1776.         }
  1777.  
  1778.         weapon = attacker GetCurrentWeapon();
  1779.  
  1780.         if( weapon == "none" )
  1781.         {
  1782.             return false;
  1783.         }
  1784.  
  1785.         if( WeaponClass( weapon ) == "pistol" )
  1786.         {
  1787.             return false;
  1788.         }
  1789.  
  1790.         if( WeaponIsGasWeapon( self.weapon ) )
  1791.         {
  1792.             return false;
  1793.         }
  1794.     }
  1795.  
  1796. //  println( "**DEBUG amount = ", amount );
  1797. //  println( "**DEBUG self.head_gibbed = ", self.head_gibbed );
  1798. //  println( "**DEBUG self.health = ", self.health );
  1799.  
  1800.     prev_health = amount + self.health;
  1801.     if( prev_health <= 0 )
  1802.     {
  1803.         prev_health = 1;
  1804.     }
  1805.  
  1806.     damage_percent = ( amount / prev_health ) * 100;
  1807.  
  1808.     if( damage_percent < 10 /*|| damage_percent >= 100*/ )
  1809.     {
  1810.         return false;
  1811.     }
  1812.  
  1813.     return true;
  1814. }
  1815.  
  1816. // SRS 9/7/2008: need to derive damage location for types that return location of "none"
  1817. derive_damage_refs( point )
  1818. {
  1819.     if( !IsDefined( level.gib_tags ) )
  1820.     {
  1821.         init_gib_tags();
  1822.     }
  1823.    
  1824.     closestTag = undefined;
  1825.    
  1826.     for( i = 0; i < level.gib_tags.size; i++ )
  1827.     {
  1828.         if( !IsDefined( closestTag ) )
  1829.         {
  1830.             closestTag = level.gib_tags[i];
  1831.         }
  1832.         else
  1833.         {
  1834.             if( DistanceSquared( point, self GetTagOrigin( level.gib_tags[i] ) ) < DistanceSquared( point, self GetTagOrigin( closestTag ) ) )
  1835.             {
  1836.                 closestTag = level.gib_tags[i];
  1837.             }
  1838.         }
  1839.     }
  1840.    
  1841.     refs = [];
  1842.    
  1843.     // figure out the refs based on the tag returned
  1844.     if( closestTag == "J_SpineLower" || closestTag == "J_SpineUpper" || closestTag == "J_Spine4" )
  1845.     {
  1846.         // HACK the torso that gets swapped for guts also removes the left arm
  1847.         //  so we need to sometimes do another ref
  1848.         refs[refs.size] = "guts";
  1849.         refs[refs.size] = "right_arm";
  1850.     }
  1851.     else if( closestTag == "J_Shoulder_LE" || closestTag == "J_Elbow_LE" || closestTag == "J_Wrist_LE" )
  1852.     {
  1853.         refs[refs.size] = "left_arm";
  1854.     }
  1855.     else if( closestTag == "J_Shoulder_RI" || closestTag == "J_Elbow_RI" || closestTag == "J_Wrist_RI" )
  1856.     {
  1857.         refs[refs.size] = "right_arm";
  1858.     }
  1859.     else if( closestTag == "J_Hip_LE" || closestTag == "J_Knee_LE" || closestTag == "J_Ankle_LE" )
  1860.     {
  1861.         refs[refs.size] = "left_leg";
  1862.         refs[refs.size] = "no_legs";
  1863.     }
  1864.     else if( closestTag == "J_Hip_RI" || closestTag == "J_Knee_RI" || closestTag == "J_Ankle_RI" )
  1865.     {
  1866.         refs[refs.size] = "right_leg";
  1867.         refs[refs.size] = "no_legs";
  1868.     }
  1869.    
  1870.     ASSERTEX( array_validate( refs ), "get_closest_damage_refs(): couldn't derive refs from closestTag " + closestTag );
  1871.    
  1872.     return refs;
  1873. }
  1874.  
  1875. init_gib_tags()
  1876. {
  1877.     tags = [];
  1878.                    
  1879.     // "guts", "right_arm", "left_arm", "right_leg", "left_leg", "no_legs"
  1880.    
  1881.     // "guts"
  1882.     tags[tags.size] = "J_SpineLower";
  1883.     tags[tags.size] = "J_SpineUpper";
  1884.     tags[tags.size] = "J_Spine4";
  1885.    
  1886.     // "left_arm"
  1887.     tags[tags.size] = "J_Shoulder_LE";
  1888.     tags[tags.size] = "J_Elbow_LE";
  1889.     tags[tags.size] = "J_Wrist_LE";
  1890.    
  1891.     // "right_arm"
  1892.     tags[tags.size] = "J_Shoulder_RI";
  1893.     tags[tags.size] = "J_Elbow_RI";
  1894.     tags[tags.size] = "J_Wrist_RI";
  1895.    
  1896.     // "left_leg"/"no_legs"
  1897.     tags[tags.size] = "J_Hip_LE";
  1898.     tags[tags.size] = "J_Knee_LE";
  1899.     tags[tags.size] = "J_Ankle_LE";
  1900.    
  1901.     // "right_leg"/"no_legs"
  1902.     tags[tags.size] = "J_Hip_RI";
  1903.     tags[tags.size] = "J_Knee_RI";
  1904.     tags[tags.size] = "J_Ankle_RI";
  1905.    
  1906.     level.gib_tags = tags;
  1907. }
  1908.  
  1909. zombie_can_drop_powerups( zombie )
  1910. {
  1911.     if( zombie.damageweapon == "zombie_cymbal_monkey" )
  1912.     {
  1913.         return false;
  1914.     }
  1915.    
  1916.     return true;
  1917. }
  1918.  
  1919. zombie_death_points( origin, mod, hit_location, player,zombie )
  1920. {
  1921.     //ChrisP - no points or powerups for killing zombies
  1922.     if(IsDefined(zombie.marked_for_death))
  1923.     {
  1924.         return;
  1925.     }
  1926.    
  1927.     if( zombie_can_drop_powerups( zombie ) )
  1928.     {
  1929.         level thread maps\_zombiemode_powerups::powerup_drop( origin );
  1930.     }
  1931.        
  1932.     if( !IsDefined( player ) || !IsPlayer( player ) )
  1933.     {
  1934.         return;
  1935.     }
  1936.  
  1937.     //TUEY Play VO if you get a Head Shot
  1938.     //add this check ( 3/24/09 - Chrisp)
  1939.     if(level.script != "nazi_zombie_prototype")
  1940.     {
  1941.         level thread play_death_vo(hit_location, player,mod,zombie);
  1942.     }
  1943.  
  1944.     player maps\_zombiemode_score::player_add_points( "death", mod, hit_location );
  1945. }
  1946. designate_rival_hero(player, hero, rival)
  1947. {
  1948.     players = getplayers();
  1949.  
  1950. //      iprintlnbold("designating_rival");
  1951.  
  1952.     playHero = isdefined(players[hero]);
  1953.     playRival = isdefined(players[rival]);
  1954.    
  1955.     if(playHero && playRival)
  1956.     {
  1957.         if(randomfloatrange(0,1) < .5)
  1958.         {
  1959.             playRival = false;
  1960.         }
  1961.         else
  1962.         {
  1963.             playHero = false;
  1964.         }
  1965.     }  
  1966.     if(playHero)
  1967.     {      
  1968.         if( distance (player.origin, players[hero].origin) < 400)
  1969.         {
  1970.             player_responder = "plr_" + hero+"_";
  1971.             players[hero] play_headshot_response_hero(player_responder);
  1972.         }
  1973.     }      
  1974.    
  1975.     if(playRival)
  1976.     {
  1977.         if( distance (player.origin, players[rival].origin) < 400)
  1978.         {
  1979.             player_responder = "plr_" + rival+"_";
  1980.             players[rival] play_headshot_response_rival(player_responder);
  1981.         }
  1982.     }
  1983. }
  1984. play_death_vo(hit_location, player,mod,zombie)
  1985. {
  1986.     // CHRISP - adding some modifiers here so that it doens't play 100% of the time
  1987.     // and takes into account the damage type.
  1988.     //  default is 10% chance of saying something
  1989.     //iprintlnbold(mod);
  1990.    
  1991.     //iprintlnbold(player);
  1992.    
  1993.     if( getdvar("zombie_death_vo_freq") == "" )
  1994.     {
  1995.         setdvar("zombie_death_vo_freq","100"); //TUEY moved to 50---We can take this out\tweak this later.
  1996.     }
  1997.    
  1998.     chance = getdvarint("zombie_death_vo_freq");
  1999.    
  2000.     weapon = player GetCurrentWeapon();
  2001.     //iprintlnbold (weapon);
  2002.    
  2003.     sound = undefined;
  2004.     //just return and don't play a sound if the chance is not there
  2005.     if(chance < randomint(100) )
  2006.     {
  2007.         return;
  2008.     }
  2009.  
  2010.     //TUEY - this funciton allows you to play a voice over when you kill a zombie and its last hit spot was something specific (like Headshot).
  2011.     //players = getplayers();
  2012.     index = maps\_zombiemode_weapons::get_player_index(player);
  2013.    
  2014.     players = getplayers();
  2015.  
  2016.     if(!isdefined (level.player_is_speaking))
  2017.     {
  2018.         level.player_is_speaking = 0;
  2019.     }
  2020.     if(!isdefined(level.zombie_vars["zombie_insta_kill"] ))
  2021.     {
  2022.         level.zombie_vars["zombie_insta_kill"] = 0;
  2023.     }
  2024.     if(hit_location == "head" && level.zombie_vars["zombie_insta_kill"] != 1   )
  2025.     {
  2026.         //no VO for non bullet headshot kills
  2027.         if( mod != "MOD_PISTOL_BULLET" &&   mod != "MOD_RIFLE_BULLET" )
  2028.         {
  2029.             return;
  2030.         }                  
  2031.         //chrisp - far headshot sounds
  2032.         if(distance(player.origin,zombie.origin) > 450)
  2033.         {
  2034.             //sound = "plr_" + index + "_vox_kill_headdist" + "_" + randomintrange(0, 11);
  2035.             plr = "plr_" + index + "_";
  2036.             player thread play_headshot_dialog (plr);
  2037.  
  2038.             if(index == 0)
  2039.             {   //DEMPSEY gets a headshot, response hero Tenko, rival The Doc
  2040.            
  2041.                 designate_rival_hero(player,2,3);  
  2042.             }
  2043.             if(index == 1) 
  2044.             {      
  2045.                 //Nickolai gets a headshot, response hero Dempsey, rival Tenko
  2046.                 designate_rival_hero(player,3,2);
  2047.             }      
  2048.             if(index == 2)
  2049.             {
  2050.                 //Tenko gets a headshot, response hero The Doctor, rival Nickolai
  2051.                 designate_rival_hero(player,0,1);  
  2052.             }
  2053.             if(index == 3)
  2054.             {
  2055.                 //The Doc gets a headshot, response hero Nickolai, rival Dempsey
  2056.                 designate_rival_hero(player,1,0);  
  2057.             }
  2058.             return;
  2059.  
  2060.         }  
  2061.         //remove headshot sounds for instakill
  2062.         if (level.zombie_vars["zombie_insta_kill"] != 0)
  2063.         {          
  2064.             sound = undefined;
  2065.         }
  2066.  
  2067.     }
  2068.     if(weapon == "ray_gun")
  2069.     {
  2070.         //Ray Gun Kills
  2071.         if(distance(player.origin,zombie.origin) > 348 && level.zombie_vars["zombie_insta_kill"] == 0)
  2072.         {
  2073.             rand = randomintrange(0, 100);
  2074.             if(rand < 28)
  2075.             {
  2076.                 plr = "plr_" + index + "_";
  2077.                 player play_raygun_dialog(plr);
  2078.                
  2079.             }
  2080.            
  2081.         }  
  2082.         return;
  2083.     }
  2084.     if(weapon == "ray_gun")
  2085.     {
  2086.         //Ray Gun Kills
  2087.         if(distance(player.origin,zombie.origin) > 348 && level.zombie_vars["zombie_insta_kill"] == 0)
  2088.         {
  2089.             rand = randomintrange(0, 100);
  2090.             if(rand < 28)
  2091.             {
  2092.                 plr = "plr_" + index + "_";
  2093.                 player play_raygun_dialog(plr);
  2094.                
  2095.             }
  2096.            
  2097.         }  
  2098.         return;
  2099.     }
  2100.     if( mod == "MOD_BURNED" )
  2101.     {
  2102.         //TUEY play flamethrower death sounds
  2103.        
  2104.         //  iprintlnbold(mod);
  2105.         plr = "plr_" + index + "_";
  2106.         player play_flamethrower_dialog (plr);
  2107.         return;
  2108.     }  
  2109.     //check for close range kills, and play a special sound, unless instakill is on
  2110.    
  2111.     if( mod != "MOD_MELEE" && hit_location != "head" && level.zombie_vars["zombie_insta_kill"] == 0 && !zombie.has_legs )
  2112.     {
  2113.         rand = randomintrange(0, 100);
  2114.         if(rand < 15)
  2115.         {
  2116.             plr = "plr_" + index + "_";
  2117.             player create_and_play_dialog ( plr, "vox_crawl_kill", 0.25 );
  2118.         }
  2119.         return;
  2120.     }
  2121.    
  2122.     if( player HasPerk( "specialty_altmelee" ) && mod == "MOD_MELEE" && level.zombie_vars["zombie_insta_kill"] == 0 )
  2123.     {
  2124.         rand = randomintrange(0, 100);
  2125.         if(rand < 25)
  2126.         {
  2127.             plr = "plr_" + index + "_";
  2128.             player create_and_play_dialog ( plr, "vox_kill_bowie", 0.25 );
  2129.         }
  2130.         return;
  2131.     }
  2132.    
  2133.     //special case for close range melee attacks while insta-kill is on
  2134.     if (level.zombie_vars["zombie_insta_kill"] != 0)
  2135.     {
  2136.         if( mod == "MOD_MELEE" || mod == "MOD_BAYONET" || mod == "MOD_UNKNOWN" && distance(player.origin,zombie.origin) < 64)
  2137.         {
  2138.             plr = "plr_" + index + "_";
  2139.             player play_insta_melee_dialog(plr);
  2140.             //sound = "plr_" + index + "_vox_melee_insta" + "_" + randomintrange(0, 5);
  2141.             return;
  2142.         }
  2143.     }
  2144.    
  2145.     //Explosive Kills
  2146.     if((mod == "MOD_GRENADE_SPLASH" || mod == "MOD_GRENADE") && level.zombie_vars["zombie_insta_kill"] == 0 )
  2147.     {
  2148.         //Plays explosion dialog
  2149.         if( zombie.damageweapon == "zombie_cymbal_monkey" )
  2150.         {
  2151.             plr = "plr_" + index + "_";
  2152.             player create_and_play_dialog( plr, "vox_kill_monkey", 0.25 );
  2153.             return;
  2154.         }
  2155.         else
  2156.         {
  2157.             plr = "plr_" + index + "_";
  2158.             player play_explosion_dialog(plr);
  2159.             return;
  2160.         }
  2161.     }
  2162.    
  2163.     if( mod == "MOD_PROJECTILE")
  2164.     {  
  2165.         //Plays explosion dialog
  2166.         plr = "plr_" + index + "_";
  2167.         player play_explosion_dialog(plr);
  2168.     }
  2169.    
  2170.     if(IsDefined(zombie) && distance(player.origin,zombie.origin) < 64 && level.zombie_vars["zombie_insta_kill"] == 0 && mod != "MOD_BURNED" )
  2171.     {
  2172.         rand = randomintrange(0, 100);
  2173.         if(rand < 40)
  2174.         {
  2175.             plr = "plr_" + index + "_";
  2176.             player play_closekill_dialog (plr);            
  2177.         }  
  2178.         return;
  2179.    
  2180.     }  
  2181.    
  2182. /*
  2183.     //This keeps multiple voice overs from playing on the same player (both killstreaks and headshots).
  2184.     if (level.player_is_speaking != 1 && isDefined(sound) && level.zombie_vars["zombie_insta_kill"] != 0)
  2185.     {  
  2186.         level.player_is_speaking = 1;
  2187.         player playsound(sound, "sound_done");         
  2188.         player waittill("sound_done");
  2189.         //This ensures that there is at least 2 seconds waittime before playing another VO.
  2190.         wait(2);       
  2191.         level.player_is_speaking = 0;
  2192.     }
  2193.     //This allows us to play VO's faster if the player is in Instakill and killing at a short distance.
  2194.     else if (level.player_is_speaking != 1 && isDefined(sound) && level.zombie_vars["zombie_insta_kill"] == 0)
  2195.     {
  2196.         level.player_is_speaking = 1;
  2197.         player playsound(sound, "sound_done");         
  2198.         player waittill("sound_done");
  2199.         //This ensures that there is at least 3 seconds waittime before playing another VO.
  2200.         wait(0.5);     
  2201.         level.player_is_speaking = 0;
  2202.  
  2203.     }  
  2204. */
  2205. }
  2206.  
  2207. play_headshot_response_hero(player_index)
  2208. {
  2209.        
  2210.         waittime = 0;
  2211.         if(!IsDefined( self.one_at_a_time_hero))
  2212.         {
  2213.             self.one_at_a_time_hero = 0;
  2214.         }
  2215.         if(!IsDefined (self.vox_resp_hr_headdist))
  2216.         {
  2217.             num_variants = get_number_variants(player_index + "vox_resp_hr_headdist");
  2218.         //  iprintlnbold(num_variants);
  2219.             self.vox_resp_hr_headdist = [];
  2220.             for(i=0;i<num_variants;i++)
  2221.             {
  2222.                 self.vox_resp_hr_headdist[self.vox_resp_hr_headdist.size] = "vox_resp_hr_headdist_" + i;   
  2223.             }
  2224.             self.vox_resp_hr_headdist_available = self.vox_resp_hr_headdist;
  2225.         }
  2226.         if(self.one_at_a_time_hero == 0)
  2227.         {
  2228.             self.one_at_a_time_hero = 1;
  2229.             sound_to_play = random(self.vox_resp_hr_headdist_available);
  2230.         //  iprintlnbold(player_index + "_" + sound_to_play);
  2231.        
  2232.             wait(2);
  2233.             self do_player_playdialog(player_index, sound_to_play, waittime);
  2234.             self.vox_resp_hr_headdist_available = array_remove(self.vox_resp_hr_headdist_available,sound_to_play);         
  2235.             if (self.vox_resp_hr_headdist_available.size < 1 )
  2236.             {
  2237.                 self.vox_resp_hr_headdist_available = self.vox_resp_hr_headdist;
  2238.             }
  2239.             self.one_at_a_time_hero = 0;
  2240.         }
  2241. }
  2242. play_headshot_response_rival(player_index)
  2243. {
  2244.        
  2245.         waittime = 0;
  2246.         if(!IsDefined( self.one_at_a_time_rival))
  2247.         {
  2248.             self.one_at_a_time_rival = 0;
  2249.         }
  2250.         if(!IsDefined (self.vox_resp_riv_headdist))
  2251.         {
  2252.             num_variants = get_number_variants(player_index + "vox_resp_riv_headdist");
  2253.             self.vox_resp_riv_headdist = [];
  2254.             for(i=0;i<num_variants;i++)
  2255.             {
  2256.                 self.vox_resp_riv_headdist[self.vox_resp_riv_headdist.size] = "vox_resp_riv_headdist_" + i;
  2257.             }
  2258.             self.vox_resp_riv_headdist_available = self.vox_resp_riv_headdist;
  2259.         }
  2260.         if(self.one_at_a_time_rival == 0)
  2261.         {
  2262.             self.one_at_a_time_rival = 1;
  2263.             sound_to_play = random(self.vox_resp_riv_headdist_available);
  2264.         //  iprintlnbold(player_index + "_" + sound_to_play);
  2265.             self.vox_resp_riv_headdist_available = array_remove(self.vox_resp_riv_headdist_available,sound_to_play);   
  2266.             wait(2);       
  2267.             self do_player_playdialog(player_index, sound_to_play, waittime);
  2268.             if (self.vox_resp_riv_headdist_available.size < 1 )
  2269.             {
  2270.                 self.vox_resp_riv_headdist_available = self.vox_resp_riv_headdist;
  2271.             }
  2272.             self.one_at_a_time_rival = 0;
  2273.         }
  2274. }
  2275. play_projectile_dialog(player_index)
  2276. {
  2277.        
  2278.         waittime = 1;
  2279.         if(!IsDefined( self.one_at_a_time))
  2280.         {
  2281.             self.one_at_a_time = 0;
  2282.         }
  2283.         if(!IsDefined (self.vox_kill_explo))
  2284.         {
  2285.             num_variants = get_number_variants(player_index + "vox_kill_explo");
  2286.             self.vox_kill_explo = [];
  2287.             for(i=0;i<num_variants;i++)
  2288.             {
  2289.                 self.vox_kill_explo[self.vox_kill_explo.size] = "vox_kill_explo_" + i; 
  2290.             }
  2291.             self.vox_kill_explo_available = self.vox_kill_explo;
  2292.         }
  2293.         if(self.one_at_a_time == 0)
  2294.         {
  2295.             self.one_at_a_time = 1;
  2296.             sound_to_play = random(self.vox_kill_explo_available);
  2297.     //      iprintlnbold(player_index + "_" + sound_to_play);
  2298.             self.vox_kill_explo_available = array_remove(self.vox_kill_explo_available,sound_to_play);         
  2299.             self do_player_playdialog(player_index, sound_to_play, waittime);
  2300.             if (self.vox_kill_explo_available.size < 1 )
  2301.             {
  2302.                 self.vox_kill_explo_available = self.vox_kill_explo;
  2303.             }
  2304.             self.one_at_a_time = 0;
  2305.         }
  2306. }
  2307. play_explosion_dialog(player_index)
  2308. {
  2309.        
  2310.         waittime = 0.25;
  2311.         if(!IsDefined( self.one_at_a_time))
  2312.         {
  2313.             self.one_at_a_time = 0;
  2314.         }
  2315.         if(!IsDefined (self.vox_kill_explo))
  2316.         {
  2317.             num_variants = get_number_variants(player_index + "vox_kill_explo");
  2318.             self.vox_kill_explo = [];
  2319.             for(i=0;i<num_variants;i++)
  2320.             {
  2321.                 self.vox_kill_explo[self.vox_kill_explo.size] = "vox_kill_explo_" + i; 
  2322.             }
  2323.             self.vox_kill_explo_available = self.vox_kill_explo;
  2324.         }
  2325.         if(self.one_at_a_time == 0)
  2326.         {
  2327.             self.one_at_a_time = 1;
  2328.             sound_to_play = random(self.vox_kill_explo_available);
  2329. //          iprintlnbold(player_index + "_" + sound_to_play);
  2330.             self.vox_kill_explo_available = array_remove(self.vox_kill_explo_available,sound_to_play);         
  2331.             self do_player_playdialog(player_index, sound_to_play, waittime);
  2332.             if (self.vox_kill_explo_available.size < 1 )
  2333.             {
  2334.                 self.vox_kill_explo_available = self.vox_kill_explo;
  2335.             }
  2336.             self.one_at_a_time = 0;
  2337.         }
  2338. }
  2339.  
  2340. play_flamethrower_dialog(player_index)
  2341. {
  2342.        
  2343.         waittime = 0.5;
  2344.         if(!IsDefined( self.one_at_a_time))
  2345.         {
  2346.             self.one_at_a_time = 0;
  2347.         }
  2348.         if(!IsDefined (self.vox_kill_flame))
  2349.         {
  2350.             num_variants = get_number_variants(player_index + "vox_kill_flame");
  2351.             self.vox_kill_flame = [];
  2352.             for(i=0;i<num_variants;i++)
  2353.             {
  2354.                 self.vox_kill_flame[self.vox_kill_flame.size] = "vox_kill_flame_" + i; 
  2355.             }
  2356.             self.vox_kill_flame_available = self.vox_kill_flame;
  2357.         }
  2358.         if(self.one_at_a_time == 0)
  2359.         {
  2360.             self.one_at_a_time = 1;
  2361.             sound_to_play = random(self.vox_kill_flame_available);
  2362.             self.vox_kill_flame_available = array_remove(self.vox_kill_flame_available,sound_to_play);         
  2363.  
  2364.             self do_player_playdialog(player_index, sound_to_play, waittime);
  2365.             if (self.vox_kill_flame_available.size < 1 )
  2366.             {
  2367.                 self.vox_kill_flame_available = self.vox_kill_flame;
  2368.             }
  2369.             self.one_at_a_time = 0;
  2370.         }
  2371. }
  2372. play_closekill_dialog(player_index)
  2373. {
  2374.  
  2375.         waittime = 1;
  2376.         if(!IsDefined( self.one_at_a_time))
  2377.         {
  2378.             self.one_at_a_time = 0;
  2379.         }
  2380.         if(!IsDefined (self.vox_close))
  2381.         {
  2382.             num_variants = get_number_variants(player_index + "vox_close");
  2383.             self.vox_close = [];
  2384.             for(i=0;i<num_variants;i++)
  2385.             {
  2386.                 self.vox_close[self.vox_close.size] = "vox_close_" + i;
  2387.             }
  2388.             self.vox_close_available = self.vox_close;
  2389.         }
  2390.         if(self.one_at_a_time == 0)
  2391.         {
  2392.             self.one_at_a_time = 1;
  2393.             if (self.vox_close_available.size >= 1)
  2394.             {
  2395.                 sound_to_play = random(self.vox_close_available);
  2396.                 self.vox_close_available = array_remove(self.vox_close_available,sound_to_play);
  2397.                 self do_player_playdialog(player_index, sound_to_play, waittime);
  2398.             }
  2399.  
  2400.             if (self.vox_close_available.size < 1 )
  2401.             {
  2402.                 self.vox_close_available = self.vox_close;
  2403.             }
  2404.             self.one_at_a_time = 0;
  2405.         }
  2406. }
  2407. get_number_variants(aliasPrefix)
  2408. {
  2409.         for(i=0; i<100; i++)
  2410.         {
  2411.             if( !SoundExists( aliasPrefix + "_" + i) )
  2412.             {
  2413.                 //iprintlnbold(aliasPrefix +"_" + i);
  2414.                 return i;
  2415.             }
  2416.         }
  2417. }  
  2418. play_headshot_dialog(player_index)
  2419. {
  2420.        
  2421.         waittime = 0.25;
  2422.         if(!IsDefined (self.vox_kill_headdist))
  2423.         {
  2424.             num_variants = get_number_variants(player_index + "vox_kill_headdist");
  2425.             //iprintlnbold(num_variants);
  2426.             self.vox_kill_headdist = [];
  2427.             for(i=0;i<num_variants;i++)
  2428.             {
  2429.                 self.vox_kill_headdist[self.vox_kill_headdist.size] = "vox_kill_headdist_" + i;
  2430.                 //iprintlnbold("vox_kill_headdist_" + i);  
  2431.             }
  2432.             self.vox_kill_headdist_available = self.vox_kill_headdist;
  2433.         }
  2434.         sound_to_play = random(self.vox_kill_headdist_available);
  2435.         //iprintlnbold("LINE:" + player_index + sound_to_play);
  2436.         self do_player_playdialog(player_index, sound_to_play, waittime);
  2437.         self.vox_kill_headdist_available = array_remove(self.vox_kill_headdist_available,sound_to_play);
  2438.    
  2439.         if (self.vox_kill_headdist_available.size < 1 )
  2440.         {
  2441.             self.vox_kill_headdist_available = self.vox_kill_headdist;
  2442.         }
  2443.  
  2444. }
  2445. play_tesla_dialog(player_index)
  2446. {
  2447.        
  2448.         waittime = 0.25;
  2449.         if(!IsDefined (self.vox_kill_tesla))
  2450.         {
  2451.             num_variants = get_number_variants(player_index + "vox_kill_tesla");
  2452.             //iprintlnbold(num_variants);
  2453.             self.vox_kill_tesla = [];
  2454.             for(i=0;i<num_variants;i++)
  2455.             {
  2456.                 self.vox_kill_tesla[self.vox_kill_tesla.size] = "vox_kill_tesla_" + i;
  2457.                 //iprintlnbold("vox_kill_tesla_" + i); 
  2458.             }
  2459.             self.vox_kill_tesla_available = self.vox_kill_tesla;
  2460.         }
  2461.  
  2462.         if(!isdefined (level.player_is_speaking))
  2463.         {
  2464.             level.player_is_speaking = 0;
  2465.         }
  2466.  
  2467.         sound_to_play = random(self.vox_kill_tesla_available);
  2468.         //iprintlnbold("LINE:" + player_index + sound_to_play);
  2469.         self do_player_playdialog(player_index, sound_to_play, waittime);
  2470.         self.vox_kill_tesla_available = array_remove(self.vox_kill_tesla_available,sound_to_play);
  2471.    
  2472.         if (self.vox_kill_tesla_available.size < 1 )
  2473.         {
  2474.             self.vox_kill_tesla_available = self.vox_kill_tesla;
  2475.         }
  2476.  
  2477. }
  2478. play_raygun_dialog(player_index)
  2479. {
  2480.        
  2481.         waittime = 0.05;
  2482.         if(!IsDefined (self.vox_kill_ray))
  2483.         {
  2484.             num_variants = get_number_variants(player_index + "vox_kill_ray");
  2485.             //iprintlnbold(num_variants);
  2486.             self.vox_kill_ray = [];
  2487.             for(i=0;i<num_variants;i++)
  2488.             {
  2489.                 self.vox_kill_ray[self.vox_kill_ray.size] = "vox_kill_ray_" + i;
  2490.                 //iprintlnbold("vox_kill_ray_" + i);   
  2491.             }
  2492.             self.vox_kill_ray_available = self.vox_kill_ray;
  2493.         }
  2494.  
  2495.         if(!isdefined (level.player_is_speaking))
  2496.         {
  2497.             level.player_is_speaking = 0;
  2498.         }
  2499.  
  2500.         sound_to_play = random(self.vox_kill_ray_available);
  2501.     //  iprintlnbold("LINE:" + player_index + sound_to_play);
  2502.         self do_player_playdialog(player_index, sound_to_play, waittime);
  2503.         self.vox_kill_ray_available = array_remove(self.vox_kill_ray_available,sound_to_play);
  2504.    
  2505.         if (self.vox_kill_ray_available.size < 1 )
  2506.         {
  2507.             self.vox_kill_ray_available = self.vox_kill_ray;
  2508.         }
  2509.  
  2510. }
  2511. play_insta_melee_dialog(player_index)
  2512. {
  2513.        
  2514.         waittime = 0.25;
  2515.         if(!IsDefined( self.one_at_a_time))
  2516.         {
  2517.             self.one_at_a_time = 0;
  2518.         }
  2519.         if(!IsDefined (self.vox_insta_melee))
  2520.         {
  2521.             num_variants = get_number_variants(player_index + "vox_insta_melee");
  2522.             self.vox_insta_melee = [];
  2523.             for(i=0;i<num_variants;i++)
  2524.             {
  2525.                 self.vox_insta_melee[self.vox_insta_melee.size] = "vox_insta_melee_" + i;  
  2526.             }
  2527.             self.vox_insta_melee_available = self.vox_insta_melee;
  2528.         }
  2529.         if(self.one_at_a_time == 0)
  2530.         {
  2531.             self.one_at_a_time = 1;
  2532.             sound_to_play = random(self.vox_insta_melee_available);
  2533.             self.vox_insta_melee_available = array_remove(self.vox_insta_melee_available,sound_to_play);
  2534.             if (self.vox_insta_melee_available.size < 1 )
  2535.             {
  2536.                 self.vox_insta_melee_available = self.vox_insta_melee;
  2537.             }
  2538.             self do_player_playdialog(player_index, sound_to_play, waittime);
  2539.             //self playsound(player_index + sound_to_play, "sound_done" + sound_to_play);          
  2540.             //self waittill("sound_done" + sound_to_play);
  2541.             wait(waittime);
  2542.             self.one_at_a_time = 0;
  2543.  
  2544.         }
  2545.         //This ensures that there is at least 3 seconds waittime before playing another VO.
  2546.  
  2547. }
  2548. do_player_playdialog(player_index, sound_to_play, waittime, response)
  2549. {
  2550.     index = maps\_zombiemode_weapons::get_player_index(self);
  2551.    
  2552.     if(!IsDefined(level.player_is_speaking))
  2553.     {
  2554.         level.player_is_speaking = 0;  
  2555.     }
  2556.     if(level.player_is_speaking != 1)
  2557.     {
  2558.         level.player_is_speaking = 1;
  2559.         //iprintlnbold(sound_to_play);
  2560.         self playsound(player_index + sound_to_play, "sound_done" + sound_to_play);        
  2561.         self waittill("sound_done" + sound_to_play);
  2562.         wait(waittime);    
  2563.         level.player_is_speaking = 0;
  2564.         if( isdefined( response ) )
  2565.         {
  2566.             level thread setup_response_line( self, index, response );
  2567.         }
  2568.     }
  2569. }
  2570. // Called from animscripts\death.gsc
  2571. zombie_death_animscript()
  2572. {
  2573.     self reset_attack_spot();
  2574.  
  2575.     if( self maps\_zombiemode_tesla::enemy_killed_by_tesla() )
  2576.     {
  2577.         return false;
  2578.     }
  2579.  
  2580.     // If no_legs, then use the AI no-legs death
  2581.     if( self.has_legs && IsDefined( self.a.gib_ref ) && self.a.gib_ref == "no_legs" )
  2582.     {
  2583.         self.deathanim = %ai_gib_bothlegs_gib;
  2584.     }
  2585.  
  2586.     self.grenadeAmmo = 0;
  2587.  
  2588.     // Give attacker points
  2589.    
  2590.     //ChrisP - 12/8/08 - added additional 'self' argument
  2591.     level zombie_death_points( self.origin, self.damagemod, self.damagelocation, self.attacker,self );
  2592.  
  2593.     if( self.damagemod == "MOD_BURNED" )
  2594.     {
  2595.         self thread animscripts\death::flame_death_fx();
  2596.     }
  2597.     if( self.damagemod == "MOD_GRENADE" || self.damagemod == "MOD_GRENADE_SPLASH" )
  2598.     {
  2599.         level notify( "zombie_grenade_death", self.origin );
  2600.     }
  2601.  
  2602.     return false;
  2603. }
  2604.  
  2605. damage_on_fire( player )
  2606. {
  2607.     self endon ("death");
  2608.     self endon ("stop_flame_damage");
  2609.     wait( 2 );
  2610.    
  2611.     while( isdefined( self.is_on_fire) && self.is_on_fire )
  2612.     {
  2613.         if( level.round_number < 6 )
  2614.         {
  2615.             dmg = level.zombie_health * RandomFloatRange( 0.2, 0.3 ); // 20% - 30%
  2616.         }
  2617.         else if( level.round_number < 9 )
  2618.         {
  2619.             dmg = level.zombie_health * RandomFloatRange( 0.15, 0.25 );
  2620.         }
  2621.         else if( level.round_number < 11 )
  2622.         {
  2623.             dmg = level.zombie_health * RandomFloatRange( 0.1, 0.2 );
  2624.         }
  2625.         else
  2626.         {
  2627.             dmg = level.zombie_health * RandomFloatRange( 0.1, 0.15 );
  2628.         }
  2629.  
  2630.         if ( Isdefined( player ) && Isalive( player ) )
  2631.         {
  2632.             self DoDamage( dmg, self.origin, player );
  2633.         }
  2634.         else
  2635.         {
  2636.             self DoDamage( dmg, self.origin, level );
  2637.         }
  2638.        
  2639.         wait( randomfloatrange( 1.0, 3.0 ) );
  2640.     }
  2641. }
  2642.  
  2643. zombie_damage( mod, hit_location, hit_origin, player )
  2644. {
  2645.     if( is_magic_bullet_shield_enabled( self ) )
  2646.     {
  2647.         return;
  2648.     }
  2649.  
  2650.     //ChrisP - 12/8 - no points for killing gassed zombies!
  2651.     player.use_weapon_type = mod;
  2652.     if(isDefined(self.marked_for_death))
  2653.     {
  2654.         return;
  2655.     }  
  2656.  
  2657.     if( !IsDefined( player ) )
  2658.     {
  2659.         return;
  2660.     }
  2661.  
  2662.     if( self zombie_flame_damage( mod, player ) )
  2663.     {
  2664.         if( self zombie_give_flame_damage_points() )
  2665.         {
  2666.             player maps\_zombiemode_score::player_add_points( "damage", mod, hit_location, self enemy_is_dog() );
  2667.         }
  2668.     }
  2669.     else if( self maps\_zombiemode_tesla::is_tesla_damage( mod ) )
  2670.     {
  2671.         self maps\_zombiemode_tesla::tesla_damage_init( hit_location, hit_origin, player );
  2672.         return;
  2673.     }
  2674.     else
  2675.     {
  2676.         player maps\_zombiemode_score::player_add_points( "damage", mod, hit_location, self enemy_is_dog() );
  2677.     }
  2678.  
  2679.     if ( mod == "MOD_GRENADE" || mod == "MOD_GRENADE_SPLASH" )
  2680.     {
  2681.         if ( isdefined( player ) && isalive( player ) )
  2682.         {
  2683.             self DoDamage( level.round_number + randomintrange( 100, 500 ), self.origin, player);
  2684.         }
  2685.         else
  2686.         {
  2687.             self DoDamage( level.round_number + randomintrange( 100, 500 ), self.origin, undefined );
  2688.         }
  2689.     }
  2690.     else if( mod == "MOD_PROJECTILE" || mod == "MOD_EXPLOSIVE" || mod == "MOD_PROJECTILE_SPLASH" || mod == "MOD_PROJECTILE_SPLASH")
  2691.     {
  2692.         if ( isdefined( player ) && isalive( player ) )
  2693.         {
  2694.             self DoDamage( level.round_number * randomintrange( 0, 100 ), self.origin, player);
  2695.         }
  2696.         else
  2697.         {
  2698.             self DoDamage( level.round_number * randomintrange( 0, 100 ), self.origin, undefined );
  2699.         }
  2700.     }
  2701.     else if( mod == "MOD_ZOMBIE_BETTY" )
  2702.     {
  2703.         if ( isdefined( player ) && isalive( player ) )
  2704.         {
  2705.             self DoDamage( level.round_number * randomintrange( 100, 200 ), self.origin, player);
  2706.         }
  2707.         else
  2708.         {
  2709.             self DoDamage( level.round_number * randomintrange( 100, 200 ), self.origin, undefined );
  2710.         }
  2711.     }
  2712.    
  2713.     //AUDIO Plays a sound when Crawlers are created
  2714.     if( IsDefined( self.a.gib_ref ) && (self.a.gib_ref == "no_legs") && isalive( self ) )
  2715.     {
  2716.         if ( isdefined( player ) )
  2717.         {
  2718.             rand = randomintrange(0, 100);
  2719.             if(rand < 10)
  2720.             {
  2721.                 index = maps\_zombiemode_weapons::get_player_index(player);
  2722.                 plr = "plr_" + index + "_";
  2723.                 player thread create_and_play_dialog( plr, "vox_crawl_spawn", 0.25, "resp_cspawn" );
  2724.             }
  2725.         }
  2726.     }
  2727.     else if( IsDefined( self.a.gib_ref ) && ( (self.a.gib_ref == "right_arm") || (self.a.gib_ref == "left_arm") ) )
  2728.     {
  2729.         if( self.has_legs && isalive( self ) )
  2730.         {
  2731.             if ( isdefined( player ) )
  2732.             {
  2733.                 rand = randomintrange(0, 100);
  2734.                 if(rand < 3)
  2735.                 {
  2736.                     index = maps\_zombiemode_weapons::get_player_index(player);
  2737.                     plr = "plr_" + index + "_";
  2738.                     player thread create_and_play_dialog( plr, "vox_shoot_limb", 0.25 );
  2739.                 }
  2740.             }
  2741.         }
  2742.     }  
  2743.     self thread maps\_zombiemode_powerups::check_for_instakill( player );
  2744. }
  2745.  
  2746. zombie_damage_ads( mod, hit_location, hit_origin, player )
  2747. {
  2748.     if( is_magic_bullet_shield_enabled( self ) )
  2749.     {
  2750.         return;
  2751.     }
  2752.  
  2753.     player.use_weapon_type = mod;
  2754.     if( !IsDefined( player ) )
  2755.     {
  2756.         return;
  2757.     }
  2758.  
  2759.     if( self zombie_flame_damage( mod, player ) )
  2760.     {
  2761.         if( self zombie_give_flame_damage_points() )
  2762.         {
  2763.             player maps\_zombiemode_score::player_add_points( "damage_ads", mod, hit_location );
  2764.         }
  2765.     }
  2766.     else if( self maps\_zombiemode_tesla::is_tesla_damage( mod ) )
  2767.     {
  2768.         self maps\_zombiemode_tesla::tesla_damage_init( hit_location, hit_origin, player );
  2769.         return;
  2770.     }
  2771.     else
  2772.     {
  2773.         player maps\_zombiemode_score::player_add_points( "damage_ads", mod, hit_location );
  2774.     }
  2775.  
  2776.     self thread maps\_zombiemode_powerups::check_for_instakill( player );
  2777. }
  2778.  
  2779. zombie_give_flame_damage_points()
  2780. {
  2781.     if( GetTime() > self.flame_damage_time )
  2782.     {
  2783.         self.flame_damage_time = GetTime() + level.zombie_vars["zombie_flame_dmg_point_delay"];
  2784.         return true;
  2785.     }
  2786.  
  2787.     return false;
  2788. }
  2789.  
  2790. zombie_flame_damage( mod, player )
  2791. {
  2792.     if( mod == "MOD_BURNED" )
  2793.     {
  2794.         self.moveplaybackrate = 0.8;
  2795.        
  2796.         if( !IsDefined( self.is_on_fire ) || ( Isdefined( self.is_on_fire ) && !self.is_on_fire ) )
  2797.         {
  2798.             self thread damage_on_fire( player );
  2799.         }
  2800.  
  2801.         do_flame_death = true;
  2802.         dist = 100 * 100;
  2803.         ai = GetAiArray( "axis" );
  2804.         for( i = 0; i < ai.size; i++ )
  2805.         {
  2806.             if( IsDefined( ai[i].is_on_fire ) && ai[i].is_on_fire )
  2807.             {
  2808.                 if( DistanceSquared( ai[i].origin, self.origin ) < dist )
  2809.                 {
  2810.                     do_flame_death = false;
  2811.                     break;
  2812.                 }
  2813.             }
  2814.         }
  2815.  
  2816.         if( do_flame_death )
  2817.         {
  2818.             self thread animscripts\death::flame_death_fx();
  2819.         }
  2820.  
  2821.         return true;
  2822.     }
  2823.  
  2824.     return false;
  2825. }
  2826.  
  2827.  
  2828. zombie_death_event( zombie )
  2829. {
  2830.     zombie waittill( "death" );
  2831.     zombie thread zombie_eye_glow_stop();
  2832.     playsoundatposition ("death_vocals", zombie.origin);
  2833.     // this is controlling killstreak voice over in the asylum.gsc
  2834.     if(isdefined (zombie.attacker) && isplayer(zombie.attacker) && level.script != "nazi_zombie_prototype")
  2835.     {
  2836.         if(!isdefined ( zombie.attacker.killcounter))
  2837.         {
  2838.             zombie.attacker.killcounter = 1;
  2839.         }
  2840.         else
  2841.         {
  2842.             zombie.attacker.killcounter ++;
  2843.         }
  2844.        
  2845.         if ( IsDefined( zombie.sound_damage_player ) && zombie.sound_damage_player == zombie.attacker )
  2846.         {  
  2847.             zombie.attacker thread play_closeDamage_dialog();  
  2848.         }
  2849.        
  2850.         zombie.attacker notify("zom_kill");
  2851.     }
  2852.    
  2853.     if( isdefined( zombie.attacker ) && isplayer( zombie.attacker ) )
  2854.     {
  2855.         damageloc = zombie.damagelocation;
  2856.         damagemod = zombie.damagemod;
  2857.         attacker = zombie.attacker;
  2858.         weapon = zombie.damageWeapon;
  2859.  
  2860.         bbPrint( "zombie_kills: round %d zombietype zombie damagetype %s damagelocation %s playername %s playerweapon %s playerx %f playery %f playerz %f zombiex %f zombiey %f zombiez %f",
  2861.                 level.round_number, damagemod, damageloc, attacker.playername, weapon, attacker.origin, zombie.origin );
  2862.     }
  2863. }
  2864. play_closeDamage_dialog()
  2865. {
  2866.     index = maps\_zombiemode_weapons::get_player_index(self);
  2867.     player_index = "plr_" + index + "_";
  2868.    
  2869.     if(!IsDefined (self.vox_dmg_close))
  2870.     {
  2871.         num_variants = maps\_zombiemode_spawner::get_number_variants(player_index + "vox_dmg_close");
  2872.         self.vox_dmg_close = [];
  2873.         for(i=0;i<num_variants;i++)
  2874.         {
  2875.             self.vox_dmg_close[self.vox_dmg_close.size] = "vox_dmg_close_" + i;
  2876.         }
  2877.         self.vox_dmg_close_available = self.vox_dmg_close;
  2878.     }
  2879.     sound_to_play = random(self.vox_dmg_close_available);
  2880.     self.vox_dmg_close_available = array_remove(self.vox_dmg_close_available,sound_to_play);
  2881.    
  2882.     if( self.vox_dmg_close_available.size < 1)
  2883.     {
  2884.         self.vox_dmg_close_available = self.vox_dmg_close; 
  2885.     }
  2886.    
  2887.     self maps\_zombiemode_spawner::do_player_playdialog(player_index, sound_to_play, 0.25);
  2888. }
  2889. // this is where zombies go into attack mode, and need different attributes set up
  2890. zombie_setup_attack_properties()
  2891. {
  2892.     self zombie_history( "zombie_setup_attack_properties()" );
  2893.  
  2894.     // allows zombie to attack again
  2895.     self.ignoreall = false;
  2896.  
  2897.     // push the player out of the way so they use traversals in the house.
  2898.     self PushPlayer( true );
  2899.  
  2900.     self.pathEnemyFightDist = 64;
  2901.     self.meleeAttackDist = 64;
  2902.    
  2903.     //try to prevent always turning towards the enemy
  2904.     self.maxsightdistsqrd = 128 * 128;
  2905.  
  2906.     // turn off transition anims
  2907.     self.disableArrivals = true;
  2908.     self.disableExits = true;
  2909. }
  2910.  
  2911.  
  2912. // the seeker logic for zombies
  2913. find_flesh()
  2914. {
  2915.     self endon( "death" );
  2916.     level endon( "intermission" );
  2917.  
  2918.     if( level.intermission )
  2919.     {
  2920.         return;
  2921.     }
  2922.  
  2923.     self.ignore_player = undefined;
  2924.  
  2925.     self zombie_history( "find flesh -> start" );
  2926.  
  2927.     self.goalradius = 32;
  2928.     while( 1 )
  2929.     {
  2930.  
  2931.         // try to split the zombies up when the bunch up
  2932.         // see if a bunch zombies are already near my current target; if there's a bunch
  2933.         // and I'm still far enough away, ignore my current target and go after another one
  2934. //      near_zombies = getaiarray("axis");
  2935. //      same_enemy_count = 0;
  2936. //      for (i = 0; i < near_zombies.size; i++)
  2937. //      {
  2938. //          if ( isdefined( near_zombies[i] ) && isalive( near_zombies[i] ) )
  2939. //          {
  2940. //              if ( isdefined( near_zombies[i].favoriteenemy ) && isdefined( self.favoriteenemy )
  2941. //              &&  near_zombies[i].favoriteenemy == self.favoriteenemy )
  2942. //              {
  2943. //                  if ( distancesquared( near_zombies[i].origin, self.favoriteenemy.origin ) < 225 * 225
  2944. //                  &&   distancesquared( near_zombies[i].origin, self.origin ) > 525 * 525)
  2945. //                  {
  2946. //                      same_enemy_count++;
  2947. //                  }
  2948. //              }
  2949. //          }
  2950. //      }
  2951. //     
  2952. //      if (same_enemy_count > 12)
  2953. //      {
  2954. //          self.ignore_player = self.favoriteenemy;
  2955. //      }
  2956.  
  2957.         zombie_poi = self get_zombie_point_of_interest( self.origin );
  2958.        
  2959.         players = get_players();
  2960.        
  2961.         //PI_CHANGE_BEGIN - 6/18/09 JV It was requested that we use the poi functionality to set the "wait" point while all players  
  2962.         //are in the process of teleportation. It should not intefere with the monkey.  The way it should work is, if all players are in teleportation,
  2963.         //zombies should go and wait at the stage, but if there is a valid player not in teleportation, they should go to him
  2964.         if (isDefined(level.zombieTheaterTeleporterSeekLogicFunc) )
  2965.         {
  2966.             temp_poi = self [[ level.zombieTheaterTeleporterSeekLogicFunc ]](players, zombie_poi);
  2967.             if (IsDefined(temp_poi))
  2968.                 zombie_poi = temp_poi;
  2969.         }
  2970.         //PI_CHANGE_END
  2971.  
  2972.                    
  2973.         // If playing single player, never ignore the player
  2974.         if( players.size == 1 )
  2975.         {
  2976.             self.ignore_player = undefined;
  2977.         }
  2978.            
  2979.         player = get_closest_valid_player( self.origin, self.ignore_player );
  2980.        
  2981.         if( !isDefined( player ) && !isDefined( zombie_poi ) )
  2982.         {
  2983.             self zombie_history( "find flesh -> can't find player, continue" );
  2984.             if( IsDefined( self.ignore_player ) )
  2985.             {
  2986.                 self.ignore_player = undefined;
  2987.                 self.ignore_player = [];
  2988.             }
  2989.  
  2990.             wait( 1 );
  2991.             continue;
  2992.         }
  2993.        
  2994.         self.ignore_player = undefined;
  2995.  
  2996.         self.enemyoverride = zombie_poi;
  2997.         self.favoriteenemy = player;
  2998.         self thread zombie_pathing();
  2999.  
  3000.         self.zombie_path_timer = GetTime() + ( RandomFloatRange( 1, 3 ) * 1000 );
  3001.         while( GetTime() < self.zombie_path_timer )
  3002.         {
  3003.             wait( 0.1 );
  3004.         }
  3005.  
  3006.         self zombie_history( "find flesh -> bottom of loop" );
  3007.  
  3008.         debug_print( "Zombie is re-acquiring enemy, ending breadcrumb search" );
  3009.         self notify( "zombie_acquire_enemy" );
  3010.     }
  3011. }
  3012.  
  3013.  
  3014. zombie_pathing()
  3015. {
  3016.     self endon( "death" );
  3017.     self endon( "zombie_acquire_enemy" );
  3018.     level endon( "intermission" );
  3019.  
  3020.     assert( IsDefined( self.favoriteenemy ) || IsDefined( self.enemyoverride ) );
  3021.  
  3022.     self thread zombie_follow_enemy();
  3023.     self waittill( "bad_path" );
  3024.    
  3025.     if( isDefined( self.enemyoverride ) )
  3026.     {
  3027.         debug_print( "Zombie couldn't path to point of interest at origin: " + self.enemyoverride[0] + " Falling back to breadcrumb system" );
  3028.         if( isDefined( self.enemyoverride[1] ) )
  3029.         {
  3030.             self.enemyoverride = self.enemyoverride[1] invalidate_attractor_pos( self.enemyoverride, self );
  3031.             self.zombie_path_timer = 0;
  3032.             return;
  3033.         }
  3034.     }
  3035.     else
  3036.     {
  3037.         debug_print( "Zombie couldn't path to player at origin: " + self.favoriteenemy.origin + " Falling back to breadcrumb system" );
  3038.     }
  3039.    
  3040.     if( !isDefined( self.favoriteenemy ) )
  3041.     {
  3042.         self.zombie_path_timer = 0;
  3043.         return;
  3044.     }
  3045.     else
  3046.     {
  3047.         self.favoriteenemy endon( "disconnect" );
  3048.     }
  3049.  
  3050.     crumb_list = self.favoriteenemy.zombie_breadcrumbs;
  3051.     bad_crumbs = [];
  3052.  
  3053.     while( 1 )
  3054.     {
  3055.         if( !is_player_valid( self.favoriteenemy ) )
  3056.         {
  3057.             self.zombie_path_timer = 0;
  3058.             return;
  3059.         }
  3060.  
  3061.         goal = zombie_pathing_get_breadcrumb( self.favoriteenemy.origin, crumb_list, bad_crumbs, ( RandomInt( 100 ) < 20 ) );
  3062.        
  3063.         if ( !IsDefined( goal ) )
  3064.         {
  3065.             debug_print( "Zombie exhausted breadcrumb search" );
  3066.             goal = self.favoriteenemy.spectator_respawn.origin;
  3067.         }
  3068.  
  3069.         debug_print( "Setting current breadcrumb to " + goal );
  3070.  
  3071.         self.zombie_path_timer += 1000;
  3072.         self SetGoalPos( goal );
  3073.         self waittill( "bad_path" );
  3074.  
  3075.         debug_print( "Zombie couldn't path to breadcrumb at " + goal + " Finding next breadcrumb" );
  3076.         for( i = 0; i < crumb_list.size; i++ )
  3077.         {
  3078.             if( goal == crumb_list[i] )
  3079.             {
  3080.                 bad_crumbs[bad_crumbs.size] = i;
  3081.                 break;
  3082.             }
  3083.         }
  3084.     }
  3085. }
  3086.  
  3087. zombie_pathing_get_breadcrumb( origin, breadcrumbs, bad_crumbs, pick_random )
  3088. {
  3089.     assert( IsDefined( origin ) );
  3090.     assert( IsDefined( breadcrumbs ) );
  3091.     assert( IsArray( breadcrumbs ) );
  3092.  
  3093.     /#
  3094.         if ( pick_random )
  3095.         {
  3096.             debug_print( "Finding random breadcrumb" );
  3097.         }
  3098.     #/
  3099.            
  3100.     for( i = 0; i < breadcrumbs.size; i++ )
  3101.     {
  3102.         if ( pick_random )
  3103.         {
  3104.             crumb_index = RandomInt( breadcrumbs.size );
  3105.         }
  3106.         else
  3107.         {
  3108.             crumb_index = i;
  3109.         }
  3110.                
  3111.         if( crumb_is_bad( crumb_index, bad_crumbs ) )
  3112.         {
  3113.             continue;
  3114.         }
  3115.  
  3116.         return breadcrumbs[crumb_index];
  3117.     }
  3118.  
  3119.     return undefined;
  3120. }
  3121.  
  3122. crumb_is_bad( crumb, bad_crumbs )
  3123. {
  3124.     for ( i = 0; i < bad_crumbs.size; i++ )
  3125.     {
  3126.         if ( bad_crumbs[i] == crumb )
  3127.         {
  3128.             return true;
  3129.         }
  3130.     }
  3131.  
  3132.     return false;
  3133. }
  3134.  
  3135. jitter_enemies_bad_breadcrumbs( start_crumb )
  3136. {
  3137.     trace_distance = 35;
  3138.     jitter_distance = 2;
  3139.    
  3140.     index = start_crumb;
  3141.    
  3142.     while (isdefined(self.favoriteenemy.zombie_breadcrumbs[ index + 1 ]))
  3143.     {
  3144.         current_crumb = self.favoriteenemy.zombie_breadcrumbs[ index ];
  3145.         next_crumb = self.favoriteenemy.zombie_breadcrumbs[ index + 1 ];
  3146.        
  3147.         angles = vectortoangles(current_crumb - next_crumb);
  3148.        
  3149.         right = anglestoright(angles);
  3150.         left = anglestoright(angles + (0,180,0));
  3151.        
  3152.         dist_pos = current_crumb + vectorScale( right, trace_distance );
  3153.        
  3154.         trace = bulletTrace( current_crumb, dist_pos, true, undefined );
  3155.         vector = trace["position"];
  3156.        
  3157.         if (distance(vector, current_crumb) < 17 )
  3158.         {
  3159.             self.favoriteenemy.zombie_breadcrumbs[ index ] = current_crumb + vectorScale( left, jitter_distance );
  3160.             continue;
  3161.         }
  3162.        
  3163.        
  3164.         // try the other side
  3165.         dist_pos = current_crumb + vectorScale( left, trace_distance );
  3166.        
  3167.         trace = bulletTrace( current_crumb, dist_pos, true, undefined );
  3168.         vector = trace["position"];
  3169.        
  3170.         if (distance(vector, current_crumb) < 17 )
  3171.         {
  3172.             self.favoriteenemy.zombie_breadcrumbs[ index ] = current_crumb + vectorScale( right, jitter_distance );
  3173.             continue;
  3174.         }
  3175.        
  3176.         index++;
  3177.     }
  3178.    
  3179. }
  3180.  
  3181. zombie_follow_enemy()
  3182. {
  3183.     self endon( "death" );
  3184.     self endon( "zombie_acquire_enemy" );
  3185.     self endon( "bad_path" );
  3186.    
  3187.     level endon( "intermission" );
  3188.  
  3189.     while( 1 )
  3190.     {
  3191.         if( isDefined( self.enemyoverride ) && isDefined( self.enemyoverride[1] ) )
  3192.         {
  3193.             if( distanceSquared( self.origin, self.enemyoverride[0] ) > 1*1 )
  3194.             {
  3195.                 self OrientMode( "face motion" );
  3196.             }
  3197.             else
  3198.             {
  3199.                 self OrientMode( "face point", self.enemyoverride[1].origin );
  3200.             }
  3201.             self.ignoreall = true;
  3202.             self SetGoalPos( self.enemyoverride[0] );
  3203.         }
  3204.         else if( IsDefined( self.favoriteenemy ) )
  3205.         {
  3206.             self.ignoreall = false;
  3207.             self OrientMode( "face default" );
  3208.             self SetGoalPos( self.favoriteenemy.origin );
  3209.         }
  3210.        
  3211.         // PI_CHANGE_BEGIN
  3212.         // JMA - while on the zipline, get zipline destination and use it as the goal
  3213.         if( (isDefined(level.script) && level.script == "nazi_zombie_sumpf") )
  3214.         {          
  3215.             if( (isDefined(self.favoriteenemy.on_zipline) &&  self.favoriteenemy.on_zipline == true) )
  3216.             {
  3217.                 crumb_list = self.favoriteenemy.zombie_breadcrumbs;
  3218.                 bad_crumbs = [];
  3219.                 goal = zombie_pathing_get_breadcrumb( self.favoriteenemy.origin, crumb_list, bad_crumbs, 0 );
  3220.                 if( isDefined(goal) )
  3221.                     self SetGoalPos( goal );
  3222.             }      
  3223.         }
  3224.         // PI_CHANGE_END
  3225.        
  3226.         wait( 0.1 );
  3227.     }
  3228. }
  3229.  
  3230.  
  3231. // When a Zombie spawns, set his eyes to glowing.
  3232. zombie_eye_glow()
  3233. {
  3234.     if( IsDefined( level.zombie_eye_glow ) && !level.zombie_eye_glow )
  3235.     {
  3236.         return;
  3237.     }
  3238.  
  3239.     if( !IsDefined( self ) )
  3240.     {
  3241.         return;
  3242.     }
  3243.  
  3244. /*  if(!isdefined(level._numZombEyeGlows))
  3245.     {
  3246.         level._numZombEyeGlows = 0;
  3247.     }
  3248.    
  3249. //  if(level.zombie_eyes_limited && level._numZombEyeGlows > 8)
  3250. //      return;
  3251.  
  3252.     if ( level.zombie_eyes_disabled )
  3253.     {
  3254.         return;
  3255.     }
  3256.  
  3257.     linkTag = "J_Eyeball_LE";
  3258.     fxModel = "tag_origin";
  3259.     fxTag = "tag_origin";
  3260.  
  3261.     // SRS 9/2/2008: only using one particle now per Barry's request;
  3262.     //  modified to be able to turn particle off
  3263.    
  3264.     self.fx_eye_glow = Spawn( "script_model", self GetTagOrigin( linkTag ) );
  3265.     self.fx_eye_glow.angles = self GetTagAngles( linkTag );
  3266.     self.fx_eye_glow SetModel( fxModel );
  3267.     self.fx_eye_glow LinkTo( self, linkTag );
  3268.  
  3269.     // TEMP for testing
  3270.     //self.fx_eye_glow thread maps\_debug::drawTagForever( fxTag );
  3271.  
  3272.     PlayFxOnTag( level._effect["eye_glow"], self.fx_eye_glow, fxTag );
  3273.    
  3274.     level._numZombEyeGlows ++;
  3275.     addtagname(linkTag);
  3276.     self haseyes(1);*/
  3277. }
  3278.  
  3279. // Called when either the Zombie dies or if his head gets blown off
  3280. zombie_eye_glow_stop()
  3281. {
  3282. /*  if( IsDefined( self.fx_eye_glow ) )
  3283.     {
  3284.         self.fx_eye_glow Delete();
  3285.         level._numZombEyeGlows --;
  3286.     }
  3287.    
  3288.     self haseyes(0);*/
  3289. }
  3290.  
  3291.  
  3292. //
  3293. // DEBUG
  3294. //
  3295.  
  3296. zombie_history( msg )
  3297. {
  3298. /#
  3299.     if( !IsDefined( self.zombie_history ) )
  3300.     {
  3301.         self.zombie_history = [];
  3302.     }
  3303.  
  3304.     self.zombie_history[self.zombie_history.size] = msg;
  3305. #/
  3306. }
  3307.  
  3308. /*
  3309.     Zombie Rise Stuff
  3310. */
  3311.  
  3312. zombie_rise()
  3313. {
  3314.     self endon("death");
  3315.     self endon("no_rise");
  3316.  
  3317.     while(!IsDefined(self.do_rise))
  3318.     {
  3319.         wait_network_frame();
  3320.     }
  3321.  
  3322.     self do_zombie_rise();
  3323. }
  3324.  
  3325. /*
  3326. zombie_rise:
  3327. Zombies rise from the ground
  3328. */
  3329. do_zombie_rise()
  3330. {
  3331.     self endon("death");
  3332.  
  3333.     self.zombie_rise_version = (RandomInt(99999) % 2) + 1;  // equally choose between version 1 and verson 2 of the animations
  3334.     if (self.zombie_move_speed != "walk")
  3335.     {
  3336.         // only do version 1 anims for "run" and "sprint"
  3337.         self.zombie_rise_version = 1;
  3338.     }
  3339.  
  3340.     self.in_the_ground = true;
  3341.  
  3342.     //self.zombie_rise_version = 1; // TESTING: override version
  3343.  
  3344.     self.anchor = spawn("script_origin", self.origin);
  3345.     self.anchor.angles = self.angles;
  3346.     self linkto(self.anchor);
  3347.  
  3348.     // JMA - this is used in swamp to only spawn risers in active player zones
  3349.     if( IsDefined( level.zombie_rise_spawners ) )
  3350.     {
  3351.         spots = level.zombie_rise_spawners;
  3352.     }
  3353.     else
  3354.     {
  3355.         spots = GetStructArray("zombie_rise", "targetname");
  3356.     }
  3357.  
  3358.     if( spots.size < 1 )
  3359.     {
  3360.         self unlink();
  3361.         self.anchor delete();
  3362.         return;
  3363.     }
  3364.     else
  3365.     spot = random(spots);
  3366.  
  3367.     /#
  3368.     if (GetDVarInt("zombie_rise_test"))
  3369.     {
  3370.         spot = SpawnStruct();           // I know this never gets deleted, but it's just for testing
  3371.         spot.origin = (472, 240, 56);   // TEST LOCATION
  3372.         spot.angles = (0, 0, 0);
  3373.     }
  3374.     #/
  3375.  
  3376.     if( !isDefined( spot.angles ) )
  3377.     {
  3378.         spot.angles = (0, 0, 0);
  3379.     }
  3380.  
  3381.     anim_org = spot.origin;
  3382.     anim_ang = spot.angles;
  3383.  
  3384.     //TODO: bbarnes: do a bullet trace to the ground so the structs don't have to be exactly on the ground.
  3385.  
  3386.     if (self.zombie_rise_version == 2)
  3387.     {
  3388.         anim_org = anim_org + (0, 0, -14);  // version 2 animation starts 14 units below the ground
  3389.     }
  3390.     else
  3391.     {
  3392.         anim_org = anim_org + (0, 0, -45);  // start the animation 45 units below the ground
  3393.     }
  3394.  
  3395.     //self Teleport(anim_org, anim_ang);    // we should get this working for MP
  3396.  
  3397.     self Hide();
  3398.     self.anchor moveto(anim_org, .05);
  3399.     self.anchor waittill("movedone");
  3400.  
  3401.     // face goal
  3402.     target_org = maps\_zombiemode_spawner::get_desired_origin();
  3403.     if (IsDefined(target_org))
  3404.     {
  3405.         anim_ang = VectorToAngles(target_org - self.origin);
  3406.         self.anchor RotateTo((0, anim_ang[1], 0), .05);
  3407.         self.anchor waittill("rotatedone");
  3408.     }
  3409.  
  3410.     self unlink();
  3411.     self.anchor delete();
  3412.  
  3413.     self thread hide_pop(); // hack to hide the pop when the zombie gets to the start position before the anim starts
  3414.  
  3415.     level thread zombie_rise_death(self, spot);
  3416.     spot thread zombie_rise_fx(self);
  3417.  
  3418.     //self animMode("nogravity");
  3419.     //self setFlaggedAnimKnoballRestart("rise", level.scr_anim["zombie"]["rise_walk"], %body, 1, .1, 1);    // no "noclip" mode for these anim functions
  3420.  
  3421.     self AnimScripted("rise", self.origin, spot.angles, self get_rise_anim());
  3422.     self animscripts\shared::DoNoteTracks("rise", ::handle_rise_notetracks, undefined, spot);
  3423.  
  3424.     self notify("rise_anim_finished");
  3425.     spot notify("stop_zombie_rise_fx");
  3426.     self.in_the_ground = false;
  3427.     self notify("risen", spot.script_noteworthy );
  3428. }
  3429.  
  3430. hide_pop()
  3431. {
  3432.     wait .5;
  3433.     self Show();
  3434. }
  3435.  
  3436. handle_rise_notetracks(note, spot)
  3437. {
  3438.     // the anim notetracks control which death anim to play
  3439.     // default to "deathin" (still in the ground)
  3440.  
  3441.     if (note == "deathout" || note == "deathhigh")
  3442.     {
  3443.         self.zombie_rise_death_out = true;
  3444.         self notify("zombie_rise_death_out");
  3445.  
  3446.         wait 2;
  3447.         spot notify("stop_zombie_rise_fx");
  3448.     }
  3449. }
  3450.  
  3451. /*
  3452. zombie_rise_death:
  3453. Track when the zombie should die, set the death anim, and stop the animscripted so he can die
  3454. */
  3455. zombie_rise_death(zombie, spot)
  3456. {
  3457.     //self.nodeathragdoll = true;
  3458.     zombie.zombie_rise_death_out = false;
  3459.  
  3460.     zombie endon("rise_anim_finished");
  3461.  
  3462.     while (zombie.health > 1)   // health will only go down to 1 when playing animation with AnimScripted()
  3463.     {
  3464.         zombie waittill("damage", amount);
  3465.     }
  3466.  
  3467.     spot notify("stop_zombie_rise_fx");
  3468.  
  3469.     zombie.deathanim = zombie get_rise_death_anim();
  3470.     zombie StopAnimScripted();  // stop the anim so the zombie can die.  death anim is handled by the anim scripts.
  3471. }
  3472.  
  3473. /*
  3474. zombie_rise_fx:  self is the script struct at the rise location
  3475. Play the fx as the zombie crawls out of the ground and thread another function to handle the dust falling
  3476. off when the zombie is out of the ground.
  3477. */
  3478. zombie_rise_fx(zombie)
  3479. {
  3480.     self thread zombie_rise_dust_fx(zombie);
  3481.     self thread zombie_rise_burst_fx();
  3482.     playsoundatposition ("zombie_spawn", self.origin);
  3483.     zombie endon("death");
  3484.     self endon("stop_zombie_rise_fx");
  3485.     wait 1;
  3486.     if (zombie.zombie_move_speed != "sprint")
  3487.     {
  3488.         // wait longer before starting billowing fx if it's not a really fast animation
  3489.         wait 1;
  3490.     }
  3491. }
  3492.  
  3493. zombie_rise_burst_fx()
  3494. {
  3495.     self endon("stop_zombie_rise_fx");
  3496.     self endon("rise_anim_finished");
  3497.    
  3498.     if(IsDefined(self.script_noteworthy) && self.script_noteworthy == "in_water")
  3499.     {
  3500.  
  3501.         playfx(level._effect["rise_burst_water"],self.origin + ( 0,0,randomintrange(5,10) ) );
  3502.         wait(.25);
  3503.         playfx(level._effect["rise_billow_water"],self.origin + ( randomintrange(-10,10),randomintrange(-10,10),randomintrange(5,10) ) );
  3504.        
  3505.     }
  3506.     else
  3507.     {
  3508.         playfx(level._effect["rise_burst"],self.origin + ( 0,0,randomintrange(5,10) ) );
  3509.         wait(.25);
  3510.         playfx(level._effect["rise_billow"],self.origin + ( randomintrange(-10,10),randomintrange(-10,10),randomintrange(5,10) ) );
  3511.  
  3512.  
  3513.     }
  3514.    
  3515.  
  3516.    
  3517.    
  3518.     //burst_time = 10; // play dust fx for a max time
  3519.     //interval = randomfloatrange(.15,.45); // wait this time in between playing the effect
  3520.        
  3521.     //for (t = 0; t < burst_time; t += interval)
  3522.     //{
  3523.     //  wait interval;
  3524.     //}
  3525. }
  3526.  
  3527. zombie_rise_dust_fx(zombie)
  3528. {
  3529.     dust_tag = "J_SpineUpper";
  3530.    
  3531.     self endon("stop_zombie_rise_dust_fx");
  3532.     self thread stop_zombie_rise_dust_fx(zombie);
  3533.  
  3534.     dust_time = 7.5; // play dust fx for a max time
  3535.     dust_interval = .1; //randomfloatrange(.1,.25); // wait this time in between playing the effect
  3536.    
  3537.     //TODO - add rising dust stuff ere
  3538.     if(IsDefined(self.script_noteworthy) && self.script_noteworthy == "in_water")
  3539.     {
  3540.  
  3541.         for (t = 0; t < dust_time; t += dust_interval)
  3542.         {
  3543.             PlayfxOnTag(level._effect["rise_dust_water"], zombie, dust_tag);
  3544.             wait dust_interval;
  3545.         }
  3546.  
  3547.     }
  3548.     else
  3549.     {
  3550.         for (t = 0; t < dust_time; t += dust_interval)
  3551.         {
  3552.         PlayfxOnTag(level._effect["rise_dust"], zombie, dust_tag);
  3553.         wait dust_interval;
  3554.         }
  3555.     }
  3556. }
  3557.  
  3558. stop_zombie_rise_dust_fx(zombie)
  3559. {
  3560.     zombie waittill("death");
  3561.     self notify("stop_zombie_rise_dust_fx");
  3562. }
  3563.  
  3564. /*
  3565. get_rise_anim:
  3566. Return a random rise animation based on a possible set of animations
  3567. */
  3568. get_rise_anim()
  3569. {
  3570.     ///* TESTING: put this block back in
  3571.     speed = self.zombie_move_speed;
  3572.     return random(level._zombie_rise_anims[self.animname][self.zombie_rise_version][speed]);
  3573.     //*/
  3574.  
  3575.     //return %ai_zombie_traverse_ground_v1_crawlfast;
  3576.     //return %ai_zombie_traverse_ground_v2_walk;
  3577.     //return %ai_zombie_traverse_ground_v2_walk_altB;
  3578. }
  3579.  
  3580. /*
  3581. get_rise_death_anim:
  3582. Return a random death animation based on a possible set of animations
  3583. */
  3584. get_rise_death_anim()
  3585. {
  3586.     possible_anims = [];
  3587.  
  3588.     if (self.zombie_rise_death_out)
  3589.     {
  3590.         possible_anims = level._zombie_rise_death_anims[self.animname][self.zombie_rise_version]["out"];
  3591.     }
  3592.     else
  3593.     {
  3594.         possible_anims = level._zombie_rise_death_anims[self.animname][self.zombie_rise_version]["in"];
  3595.     }
  3596.  
  3597.     return random(possible_anims);
  3598. }
  3599.  
  3600.  
  3601.  
  3602.  
  3603. // gib limbs if enough firepower occurs
  3604. make_crawler()
  3605. {
  3606.     //  self endon( "death" );
  3607.     if( !IsDefined( self ) )
  3608.     {
  3609.         return;
  3610.     }
  3611.  
  3612.     self.has_legs = false;
  3613.     self AllowedStances( "crouch" );
  3614.  
  3615.     damage_type[0] = "right_foot";
  3616.     damage_type[1] = "left_foot";
  3617.    
  3618.     refs = [];
  3619.     switch( damage_type[ RandomInt(damage_type.size) ] )
  3620.     {
  3621.     case "right_leg_upper":
  3622.     case "right_leg_lower":
  3623.     case "right_foot":
  3624.         // Addition "right_leg" refs so that the no_legs happens less and is more rare
  3625.         refs[refs.size] = "right_leg";
  3626.         refs[refs.size] = "right_leg";
  3627.         refs[refs.size] = "right_leg";
  3628.         refs[refs.size] = "no_legs";
  3629.         break;
  3630.  
  3631.     case "left_leg_upper":
  3632.     case "left_leg_lower":
  3633.     case "left_foot":
  3634.         // Addition "left_leg" refs so that the no_legs happens less and is more rare
  3635.         refs[refs.size] = "left_leg";
  3636.         refs[refs.size] = "left_leg";
  3637.         refs[refs.size] = "left_leg";
  3638.         refs[refs.size] = "no_legs";
  3639.         break;
  3640.     }
  3641.  
  3642.     if( refs.size )
  3643.     {
  3644.         self.a.gib_ref = animscripts\death::get_random( refs );
  3645.  
  3646.         // Don't stand if a leg is gone
  3647.         if( ( self.a.gib_ref == "no_legs" || self.a.gib_ref == "right_leg" || self.a.gib_ref == "left_leg" ) && self.health > 0 )
  3648.         {
  3649.             self.has_legs = false;
  3650.             self AllowedStances( "crouch" );
  3651.  
  3652.             which_anim = RandomInt( 5 );
  3653.             if(self.a.gib_ref == "no_legs")
  3654.             {
  3655.  
  3656.                 if(randomint(100) < 50)
  3657.                 {
  3658.                     self.deathanim = %ai_zombie_crawl_death_v1;
  3659.                     self set_run_anim( "death3" );
  3660.                     self.run_combatanim = level.scr_anim[self.animname]["crawl_hand_1"];
  3661.                     self.crouchRunAnim = level.scr_anim[self.animname]["crawl_hand_1"];
  3662.                     self.crouchrun_combatanim = level.scr_anim[self.animname]["crawl_hand_1"];
  3663.                 }
  3664.                 else
  3665.                 {
  3666.                     self.deathanim = %ai_zombie_crawl_death_v1;
  3667.                     self set_run_anim( "death3" );
  3668.                     self.run_combatanim = level.scr_anim[self.animname]["crawl_hand_2"];
  3669.                     self.crouchRunAnim = level.scr_anim[self.animname]["crawl_hand_2"];
  3670.                     self.crouchrun_combatanim = level.scr_anim[self.animname]["crawl_hand_2"];
  3671.                 }
  3672.  
  3673.  
  3674.             }
  3675.             else if( which_anim == 0 )
  3676.             {
  3677.                 self.deathanim = %ai_zombie_crawl_death_v1;
  3678.                 self set_run_anim( "death3" );
  3679.                 self.run_combatanim = level.scr_anim[self.animname]["crawl1"];
  3680.                 self.crouchRunAnim = level.scr_anim[self.animname]["crawl1"];
  3681.                 self.crouchrun_combatanim = level.scr_anim[self.animname]["crawl1"];
  3682.             }
  3683.             else if( which_anim == 1 )
  3684.             {
  3685.                 self.deathanim = %ai_zombie_crawl_death_v2;
  3686.                 self set_run_anim( "death4" );
  3687.                 self.run_combatanim = level.scr_anim[self.animname]["crawl2"];
  3688.                 self.crouchRunAnim = level.scr_anim[self.animname]["crawl2"];
  3689.                 self.crouchrun_combatanim = level.scr_anim[self.animname]["crawl2"];
  3690.             }
  3691.             else if( which_anim == 2 )
  3692.             {
  3693.                 self.deathanim = %ai_zombie_crawl_death_v1;
  3694.                 self set_run_anim( "death3" );
  3695.                 self.run_combatanim = level.scr_anim[self.animname]["crawl3"];
  3696.                 self.crouchRunAnim = level.scr_anim[self.animname]["crawl3"];
  3697.                 self.crouchrun_combatanim = level.scr_anim[self.animname]["crawl3"];
  3698.             }
  3699.             else if( which_anim == 3 )
  3700.             {
  3701.                 self.deathanim = %ai_zombie_crawl_death_v2;
  3702.                 self set_run_anim( "death4" );
  3703.                 self.run_combatanim = level.scr_anim[self.animname]["crawl4"];
  3704.                 self.crouchRunAnim = level.scr_anim[self.animname]["crawl4"];
  3705.                 self.crouchrun_combatanim = level.scr_anim[self.animname]["crawl4"];
  3706.             }
  3707.             else if( which_anim == 4 )
  3708.             {
  3709.                 self.deathanim = %ai_zombie_crawl_death_v1;
  3710.                 self set_run_anim( "death3" );
  3711.                 self.run_combatanim = level.scr_anim[self.animname]["crawl5"];
  3712.                 self.crouchRunAnim = level.scr_anim[self.animname]["crawl5"];
  3713.                 self.crouchrun_combatanim = level.scr_anim[self.animname]["crawl5"];
  3714.             }
  3715.  
  3716.         }
  3717.     }
  3718.  
  3719. //  if( self.health > 0 )
  3720. //  {
  3721. //      // force gibbing if the zombie is still alive
  3722. //      self thread animscripts\death::do_gib();
  3723. //
  3724. //      //stat tracking
  3725. //      attacker.stats["zombie_gibs"]++;
  3726. //  }
  3727. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement