burc_2004

_zm_spawner.gsc

Oct 22nd, 2015
167
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 88.79 KB | None | 0 0
  1. #include maps/mp/zombies/_zm_ai_faller;
  2. #include maps/mp/zombies/_zm_weapons;
  3. #include maps/mp/zombies/_zm_spawner;
  4. #include maps/mp/zombies/_zm;
  5. #include maps/mp/zombies/_zm_pers_upgrades_functions;
  6. #include maps/mp/zombies/_zm_stats;
  7. #include maps/mp/zombies/_zm_pers_upgrades;
  8. #include maps/mp/zombies/_zm_score;
  9. #include maps/mp/zombies/_zm_powerups;
  10. #include maps/mp/animscripts/zm_run;
  11. #include maps/mp/animscripts/zm_death;
  12. #include maps/mp/zombies/_zm_blockers;
  13. #include maps/mp/animscripts/zm_shared;
  14. #include maps/mp/animscripts/zm_utility;
  15. #include maps/mp/zombies/_zm_ai_basic;
  16. #include maps/mp/zombies/_zm_laststand;
  17. #include maps/mp/zombies/_zm_net;
  18. #include maps/mp/zombies/_zm_utility;
  19. #include maps/mp/_utility;
  20. #include common_scripts/utility;
  21.  
  22. init()
  23. {
  24.     level._contextual_grab_lerp_time = 0,3;
  25.     level.zombie_spawners = getentarray( "zombie_spawner", "script_noteworthy" );
  26.     while ( isDefined( level.use_multiple_spawns ) && level.use_multiple_spawns )
  27.     {
  28.         level.zombie_spawn = [];
  29.         i = 0;
  30.         while ( i < level.zombie_spawners.size )
  31.         {
  32.             if ( isDefined( level.zombie_spawners[ i ].script_int ) )
  33.             {
  34.                 int = level.zombie_spawners[ i ].script_int;
  35.                 if ( !isDefined( level.zombie_spawn[ int ] ) )
  36.                 {
  37.                     level.zombie_spawn[ int ] = [];
  38.                 }
  39.                 level.zombie_spawn[ int ][ level.zombie_spawn[ int ].size ] = level.zombie_spawners[ i ];
  40.             }
  41.             i++;
  42.         }
  43.     }
  44.     precachemodel( "p6_anim_zm_barricade_board_01_upgrade" );
  45.     precachemodel( "p6_anim_zm_barricade_board_02_upgrade" );
  46.     precachemodel( "p6_anim_zm_barricade_board_03_upgrade" );
  47.     precachemodel( "p6_anim_zm_barricade_board_04_upgrade" );
  48.     precachemodel( "p6_anim_zm_barricade_board_05_upgrade" );
  49.     precachemodel( "p6_anim_zm_barricade_board_06_upgrade" );
  50.     while ( isDefined( level.ignore_spawner_func ) )
  51.     {
  52.         i = 0;
  53.         while ( i < level.zombie_spawners.size )
  54.         {
  55.             ignore = [[ level.ignore_spawner_func ]]( level.zombie_spawners[ i ] );
  56.             if ( ignore )
  57.             {
  58.                 arrayremovevalue( level.zombie_spawners, level.zombie_spawners[ i ] );
  59.             }
  60.             i++;
  61.         }
  62.     }
  63.     gametype = getDvar( "ui_gametype" );
  64.     if ( !isDefined( level.attack_player_thru_boards_range ) )
  65.     {
  66.         level.attack_player_thru_boards_range = 109,8;
  67.     }
  68.     if ( isDefined( level._game_module_custom_spawn_init_func ) )
  69.     {
  70.         [[ level._game_module_custom_spawn_init_func ]]();
  71.     }
  72.     registerclientfield( "actor", "zombie_has_eyes", 1, 1, "int" );
  73.     registerclientfield( "actor", "zombie_ragdoll_explode", 1, 1, "int" );
  74.     registerclientfield( "actor", "zombie_gut_explosion", 9000, 1, "int" );
  75. }
  76.  
  77. add_cusom_zombie_spawn_logic( func )
  78. {
  79.     if ( !isDefined( level._zombie_custom_spawn_logic ) )
  80.     {
  81.         level._zombie_custom_spawn_logic = [];
  82.     }
  83.     level._zombie_custom_spawn_logic[ level._zombie_custom_spawn_logic.size ] = func;
  84. }
  85.  
  86. player_attacks_enemy( player, amount, type, point )
  87. {
  88.     team = undefined;
  89.     if ( isDefined( self._race_team ) )
  90.     {
  91.         team = self._race_team;
  92.     }
  93.     if ( !isads( player ) )
  94.     {
  95.         [[ level.global_damage_func ]]( type, self.damagelocation, point, player, amount, team );
  96.         return 0;
  97.     }
  98.     if ( !bullet_attack( type ) )
  99.     {
  100.         [[ level.global_damage_func ]]( type, self.damagelocation, point, player, amount, team );
  101.         return 0;
  102.     }
  103.     [[ level.global_damage_func_ads ]]( type, self.damagelocation, point, player, amount, team );
  104.     return 1;
  105. }
  106.  
  107. player_attacker( attacker )
  108. {
  109.     if ( isplayer( attacker ) )
  110.     {
  111.         return 1;
  112.     }
  113.     return 0;
  114. }
  115.  
  116. enemy_death_detection()
  117. {
  118.     self endon( "death" );
  119.     for ( ;; )
  120.     {
  121.         self waittill( "damage", amount, attacker, direction_vec, point, type );
  122.         if ( !isDefined( amount ) )
  123.         {
  124.             continue;
  125.         }
  126.         else if ( !isalive( self ) || self.delayeddeath )
  127.         {
  128.             return;
  129.         }
  130.         if ( !player_attacker( attacker ) )
  131.         {
  132.             continue;
  133.         }
  134.         else
  135.         {
  136.             self.has_been_damaged_by_player = 1;
  137.             self player_attacks_enemy( attacker, amount, type, point );
  138.         }
  139.     }
  140. }
  141.  
  142. is_spawner_targeted_by_blocker( ent )
  143. {
  144.     while ( isDefined( ent.targetname ) )
  145.     {
  146.         targeters = getentarray( ent.targetname, "target" );
  147.         i = 0;
  148.         while ( i < targeters.size )
  149.         {
  150.             if ( targeters[ i ].targetname == "zombie_door" || targeters[ i ].targetname == "zombie_debris" )
  151.             {
  152.                 return 1;
  153.             }
  154.             result = is_spawner_targeted_by_blocker( targeters[ i ] );
  155.             if ( result )
  156.             {
  157.                 return 1;
  158.             }
  159.             i++;
  160.         }
  161.     }
  162.     return 0;
  163. }
  164.  
  165. add_custom_zombie_spawn_logic( func )
  166. {
  167.     if ( !isDefined( level._zombie_custom_spawn_logic ) )
  168.     {
  169.         level._zombie_custom_spawn_logic = [];
  170.     }
  171.     level._zombie_custom_spawn_logic[ level._zombie_custom_spawn_logic.size ] = func;
  172. }
  173.  
  174. zombie_spawn_init( animname_set )
  175. {
  176.     if ( !isDefined( animname_set ) )
  177.     {
  178.         animname_set = 0;
  179.     }
  180.     self.targetname = "zombie";
  181.     self.script_noteworthy = undefined;
  182.     recalc_zombie_array();
  183.     if ( !animname_set )
  184.     {
  185.         self.animname = "zombie";
  186.     }
  187.     if ( isDefined( get_gamemode_var( "pre_init_zombie_spawn_func" ) ) )
  188.     {
  189.         self [[ get_gamemode_var( "pre_init_zombie_spawn_func" ) ]]();
  190.     }
  191.     self thread play_ambient_zombie_vocals();
  192.     self.zmb_vocals_attack = "zmb_vocals_zombie_attack";
  193.     self.ignoreall = 1;
  194.     self.ignoreme = 1;
  195.     self.allowdeath = 1;
  196.     self.force_gib = 1;
  197.     self.is_zombie = 1;
  198.     self.has_legs = 1;
  199.     self allowedstances( "stand" );
  200.     self.zombie_damaged_by_bar_knockdown = 0;
  201.     self.gibbed = 0;
  202.     self.head_gibbed = 0;
  203.     self setphysparams( 15, 0, 72 );
  204.     self.disablearrivals = 1;
  205.     self.disableexits = 1;
  206.     self.grenadeawareness = 0;
  207.     self.badplaceawareness = 0;
  208.     self.ignoresuppression = 1;
  209.     self.suppressionthreshold = 1;
  210.     self.nododgemove = 1;
  211.     self.dontshootwhilemoving = 1;
  212.     self.pathenemylookahead = 0;
  213.     self.badplaceawareness = 0;
  214.     self.chatinitialized = 0;
  215.     self.a.disablepain = 1;
  216.     self disable_react();
  217.     if ( isDefined( level.zombie_health ) )
  218.     {
  219.         self.maxhealth = level.zombie_health;
  220.         if ( isDefined( level.zombie_respawned_health ) && level.zombie_respawned_health.size > 0 )
  221.         {
  222.             self.health = level.zombie_respawned_health[ 0 ];
  223.             arrayremovevalue( level.zombie_respawned_health, level.zombie_respawned_health[ 0 ] );
  224.         }
  225.         else
  226.         {
  227.             self.health = level.zombie_health;
  228.         }
  229.     }
  230.     else
  231.     {
  232.         self.maxhealth = level.zombie_vars[ "zombie_health_start" ];
  233.         self.health = self.maxhealth;
  234.     }
  235.     self.freezegun_damage = 0;
  236.     self.dropweapon = 0;
  237.     level thread zombie_death_event( self );
  238.     self init_zombie_run_cycle();
  239.     self thread zombie_think();
  240.     self thread zombie_gib_on_damage();
  241.     self thread zombie_damage_failsafe();
  242.     self thread enemy_death_detection();
  243.     if ( isDefined( level._zombie_custom_spawn_logic ) )
  244.     {
  245.         if ( isarray( level._zombie_custom_spawn_logic ) )
  246.         {
  247.             i = 0;
  248.             while ( i < level._zombie_custom_spawn_logic.size )
  249.             {
  250.                 self thread [[ level._zombie_custom_spawn_logic[ i ] ]]();
  251.                 i++;
  252.             }
  253.         }
  254.         else self thread [[ level._zombie_custom_spawn_logic ]]();
  255.     }
  256.     if ( !isDefined( self.no_eye_glow ) || !self.no_eye_glow )
  257.     {
  258.         if ( isDefined( self.is_inert ) && !self.is_inert )
  259.         {
  260.             self thread delayed_zombie_eye_glow();
  261.         }
  262.     }
  263.     self.deathfunction = ::zombie_death_animscript;
  264.     self.flame_damage_time = 0;
  265.     self.meleedamage = 60;
  266.     self.no_powerups = 1;
  267.     self zombie_history( "zombie_spawn_init -> Spawned = " + self.origin );
  268.     self.thundergun_knockdown_func = level.basic_zombie_thundergun_knockdown;
  269.     self.tesla_head_gib_func = ::zombie_tesla_head_gib;
  270.     self.team = level.zombie_team;
  271.     if ( isDefined( level.achievement_monitor_func ) )
  272.     {
  273.         self [[ level.achievement_monitor_func ]]();
  274.     }
  275.     if ( isDefined( get_gamemode_var( "post_init_zombie_spawn_func" ) ) )
  276.     {
  277.         self [[ get_gamemode_var( "post_init_zombie_spawn_func" ) ]]();
  278.     }
  279.     if ( isDefined( level.zombie_init_done ) )
  280.     {
  281.         self [[ level.zombie_init_done ]]();
  282.     }
  283.     self.zombie_init_done = 1;
  284.     self notify( "zombie_init_done" );
  285. }
  286.  
  287. delayed_zombie_eye_glow()
  288. {
  289.     self endon( "zombie_delete" );
  290.     if ( isDefined( self.in_the_ground ) || self.in_the_ground && isDefined( self.in_the_ceiling ) && self.in_the_ceiling )
  291.     {
  292.         while ( !isDefined( self.create_eyes ) )
  293.         {
  294.             wait 0,1;
  295.         }
  296.     }
  297.     else wait 0,5;
  298.     self zombie_eye_glow();
  299. }
  300.  
  301. zombie_damage_failsafe()
  302. {
  303.     self endon( "death" );
  304.     continue_failsafe_damage = 0;
  305.     while ( 1 )
  306.     {
  307.         wait 0,5;
  308.         if ( !isDefined( self.enemy ) || !isplayer( self.enemy ) )
  309.         {
  310.             continue;
  311.         }
  312.         if ( self istouching( self.enemy ) )
  313.         {
  314.             old_org = self.origin;
  315.             if ( !continue_failsafe_damage )
  316.             {
  317.                 wait 5;
  318.             }
  319.             while ( isDefined( self.enemy ) || !isplayer( self.enemy ) && self.enemy hasperk( "specialty_armorvest" ) )
  320.             {
  321.                 continue;
  322.             }
  323.             if ( self istouching( self.enemy ) && !self.enemy maps/mp/zombies/_zm_laststand::player_is_in_laststand() && isalive( self.enemy ) )
  324.             {
  325.                 if ( distancesquared( old_org, self.origin ) < 3600 )
  326.                 {
  327.                     self.enemy dodamage( self.enemy.health + 1000, self.enemy.origin, self, self, "none", "MOD_RIFLE_BULLET" );
  328.                     continue_failsafe_damage = 1;
  329.                 }
  330.             }
  331.             continue;
  332.         }
  333.         else
  334.         {
  335.             continue_failsafe_damage = 0;
  336.         }
  337.     }
  338. }
  339.  
  340. should_skip_teardown( find_flesh_struct_string )
  341. {
  342.     if ( isDefined( find_flesh_struct_string ) && find_flesh_struct_string == "find_flesh" )
  343.     {
  344.         return 1;
  345.     }
  346.     if ( isDefined( self.script_string ) && self.script_string == "zombie_chaser" )
  347.     {
  348.         return 1;
  349.     }
  350.     return 0;
  351. }
  352.  
  353. zombie_think()
  354. {
  355.     self endon( "death" );
  356. /#
  357.     assert( !self.isdog );
  358. #/
  359.     self.ai_state = "zombie_think";
  360.     find_flesh_struct_string = undefined;
  361.     if ( isDefined( level.zombie_custom_think_logic ) )
  362.     {
  363.         shouldwait = self [[ level.zombie_custom_think_logic ]]();
  364.         if ( shouldwait )
  365.         {
  366.             self waittill( "zombie_custom_think_done", find_flesh_struct_string );
  367.         }
  368.     }
  369.     else if ( isDefined( self.start_inert ) && self.start_inert )
  370.     {
  371.         find_flesh_struct_string = "find_flesh";
  372.     }
  373.     else
  374.     {
  375.         if ( isDefined( self.custom_location ) )
  376.         {
  377.             self thread [[ self.custom_location ]]();
  378.         }
  379.         else
  380.         {
  381.             self thread do_zombie_spawn();
  382.         }
  383.         self waittill( "risen", find_flesh_struct_string );
  384.     }
  385.     node = undefined;
  386.     desired_nodes = [];
  387.     self.entrance_nodes = [];
  388.     if ( isDefined( level.max_barrier_search_dist_override ) )
  389.     {
  390.         max_dist = level.max_barrier_search_dist_override;
  391.     }
  392.     else
  393.     {
  394.         max_dist = 500;
  395.     }
  396.     if ( !isDefined( find_flesh_struct_string ) && isDefined( self.target ) && self.target != "" )
  397.     {
  398.         desired_origin = get_desired_origin();
  399. /#
  400.         assert( isDefined( desired_origin ), "Spawner @ " + self.origin + " has a .target but did not find a target" );
  401. #/
  402.         origin = desired_origin;
  403.         node = getclosest( origin, level.exterior_goals );
  404.         self.entrance_nodes[ self.entrance_nodes.size ] = node;
  405.         self zombie_history( "zombie_think -> #1 entrance (script_forcegoal) origin = " + self.entrance_nodes[ 0 ].origin );
  406.     }
  407.     else
  408.     {
  409.         if ( self should_skip_teardown( find_flesh_struct_string ) )
  410.         {
  411.             self zombie_setup_attack_properties();
  412.             if ( isDefined( self.target ) )
  413.             {
  414.                 end_at_node = getnode( self.target, "targetname" );
  415.                 if ( isDefined( end_at_node ) )
  416.                 {
  417.                     self setgoalnode( end_at_node );
  418.                     self waittill( "goal" );
  419.                 }
  420.             }
  421.             if ( isDefined( self.start_inert ) && self.start_inert )
  422.             {
  423.                 self thread maps/mp/zombies/_zm_ai_basic::start_inert( 1 );
  424.                 self zombie_complete_emerging_into_playable_area();
  425.             }
  426.             else
  427.             {
  428.                 self thread maps/mp/zombies/_zm_ai_basic::find_flesh();
  429.                 self thread zombie_entered_playable();
  430.             }
  431.             return;
  432.         }
  433.         else if ( isDefined( find_flesh_struct_string ) )
  434.         {
  435. /#
  436.             assert( isDefined( find_flesh_struct_string ) );
  437. #/
  438.             i = 0;
  439.             while ( i < level.exterior_goals.size )
  440.             {
  441.                 if ( isDefined( level.exterior_goals[ i ].script_string ) && level.exterior_goals[ i ].script_string == find_flesh_struct_string )
  442.                 {
  443.                     node = level.exterior_goals[ i ];
  444.                     break;
  445.                 }
  446.                 else
  447.                 {
  448.                     i++;
  449.                 }
  450.             }
  451.             self.entrance_nodes[ self.entrance_nodes.size ] = node;
  452.             self zombie_history( "zombie_think -> #1 entrance origin = " + node.origin );
  453.             self thread zombie_assure_node();
  454.         }
  455.         else
  456.         {
  457.             origin = self.origin;
  458.             desired_origin = get_desired_origin();
  459.             if ( isDefined( desired_origin ) )
  460.             {
  461.                 origin = desired_origin;
  462.             }
  463.             nodes = get_array_of_closest( origin, level.exterior_goals, undefined, 3 );
  464.             desired_nodes[ 0 ] = nodes[ 0 ];
  465.             prev_dist = distance( self.origin, nodes[ 0 ].origin );
  466.             i = 1;
  467.             while ( i < nodes.size )
  468.             {
  469.                 dist = distance( self.origin, nodes[ i ].origin );
  470.                 if ( ( dist - prev_dist ) > max_dist )
  471.                 {
  472.                     break;
  473.                 }
  474.                 else
  475.                 {
  476.                     prev_dist = dist;
  477.                     desired_nodes[ i ] = nodes[ i ];
  478.                     i++;
  479.                 }
  480.             }
  481.             node = desired_nodes[ 0 ];
  482.             if ( desired_nodes.size > 1 )
  483.             {
  484.                 node = desired_nodes[ randomint( desired_nodes.size ) ];
  485.             }
  486.             self.entrance_nodes = desired_nodes;
  487.             self zombie_history( "zombie_think -> #1 entrance origin = " + node.origin );
  488.             self thread zombie_assure_node();
  489.         }
  490.     }
  491. /#
  492.     assert( isDefined( node ), "Did not find a node!!! [Should not see this!]" );
  493. #/
  494.     level thread draw_line_ent_to_pos( self, node.origin, "goal" );
  495.     self.first_node = node;
  496.     self thread zombie_goto_entrance( node );
  497. }
  498.  
  499. zombie_entered_playable()
  500. {
  501.     self endon( "death" );
  502.     if ( !isDefined( level.playable_areas ) )
  503.     {
  504.         level.playable_areas = getentarray( "player_volume", "script_noteworthy" );
  505.     }
  506.     while ( 1 )
  507.     {
  508.         _a614 = level.playable_areas;
  509.         _k614 = getFirstArrayKey( _a614 );
  510.         while ( isDefined( _k614 ) )
  511.         {
  512.             area = _a614[ _k614 ];
  513.             if ( self istouching( area ) )
  514.             {
  515.                 self zombie_complete_emerging_into_playable_area();
  516.                 return;
  517.             }
  518.             _k614 = getNextArrayKey( _a614, _k614 );
  519.         }
  520.         wait 1;
  521.     }
  522. }
  523.  
  524. get_desired_origin()
  525. {
  526.     if ( isDefined( self.target ) )
  527.     {
  528.         ent = getent( self.target, "targetname" );
  529.         if ( !isDefined( ent ) )
  530.         {
  531.             ent = getstruct( self.target, "targetname" );
  532.         }
  533.         if ( !isDefined( ent ) )
  534.         {
  535.             ent = getnode( self.target, "targetname" );
  536.         }
  537. /#
  538.         assert( isDefined( ent ), "Cannot find the targeted ent/node/struct, "" + self.target + "" at " + self.origin );
  539. #/
  540.         return ent.origin;
  541.     }
  542.     return undefined;
  543. }
  544.  
  545. zombie_goto_entrance( node, endon_bad_path )
  546. {
  547. /#
  548.     assert( !self.isdog );
  549. #/
  550.     self endon( "death" );
  551.     self endon( "stop_zombie_goto_entrance" );
  552.     level endon( "intermission" );
  553.     self.ai_state = "zombie_goto_entrance";
  554.     if ( isDefined( endon_bad_path ) && endon_bad_path )
  555.     {
  556.         self endon( "bad_path" );
  557.     }
  558.     self zombie_history( "zombie_goto_entrance -> start goto entrance " + node.origin );
  559.     self.got_to_entrance = 0;
  560.     self.goalradius = 128;
  561.     self setgoalpos( node.origin );
  562.     self waittill( "goal" );
  563.     self.got_to_entrance = 1;
  564.     self zombie_history( "zombie_goto_entrance -> reached goto entrance " + node.origin );
  565.     self tear_into_building();
  566.     if ( isDefined( level.pre_aggro_pathfinding_func ) )
  567.     {
  568.         self [[ level.pre_aggro_pathfinding_func ]]();
  569.     }
  570.     barrier_pos = [];
  571.     barrier_pos[ 0 ] = "m";
  572.     barrier_pos[ 1 ] = "r";
  573.     barrier_pos[ 2 ] = "l";
  574.     self.barricade_enter = 1;
  575.     animstate = maps/mp/animscripts/zm_utility::append_missing_legs_suffix( "zm_barricade_enter" );
  576.     substate = "barrier_" + self.zombie_move_speed + "_" + barrier_pos[ self.attacking_spot_index ];
  577.     self animscripted( self.first_node.zbarrier.origin, self.first_node.zbarrier.angles, animstate, substate );
  578.     maps/mp/animscripts/zm_shared::donotetracks( "barricade_enter_anim" );
  579.     self zombie_setup_attack_properties();
  580.     self thread maps/mp/zombies/_zm_ai_basic::find_flesh();
  581.     self.pathenemyfightdist = 4;
  582.     self zombie_complete_emerging_into_playable_area();
  583.     self.pathenemyfightdist = 64;
  584.     self.barricade_enter = 0;
  585. }
  586.  
  587. zombie_assure_node()
  588. {
  589.     self endon( "death" );
  590.     self endon( "goal" );
  591.     level endon( "intermission" );
  592.     start_pos = self.origin;
  593.     while ( isDefined( self.entrance_nodes ) )
  594.     {
  595.         i = 0;
  596.         while ( i < self.entrance_nodes.size )
  597.         {
  598.             if ( self zombie_bad_path() )
  599.             {
  600.                 self zombie_history( "zombie_assure_node -> assigned assured node = " + self.entrance_nodes[ i ].origin );
  601. /#
  602.                 println( "^1Zombie @ " + self.origin + " did not move for 1 second. Going to next closest node @ " + self.entrance_nodes[ i ].origin );
  603. #/
  604.                 level thread draw_line_ent_to_pos( self, self.entrance_nodes[ i ].origin, "goal" );
  605.                 self.first_node = self.entrance_nodes[ i ];
  606.                 self setgoalpos( self.entrance_nodes[ i ].origin );
  607.                 i++;
  608.                 continue;
  609.             }
  610.             else
  611.             {
  612.                 return;
  613.             }
  614.             i++;
  615.         }
  616.     }
  617.     wait 2;
  618.     nodes = get_array_of_closest( self.origin, level.exterior_goals, undefined, 20 );
  619.     while ( isDefined( nodes ) )
  620.     {
  621.         self.entrance_nodes = nodes;
  622.         i = 0;
  623.         while ( i < self.entrance_nodes.size )
  624.         {
  625.             if ( self zombie_bad_path() )
  626.             {
  627.                 self zombie_history( "zombie_assure_node -> assigned assured node = " + self.entrance_nodes[ i ].origin );
  628. /#
  629.                 println( "^1Zombie @ " + self.origin + " did not move for 1 second. Going to next closest node @ " + self.entrance_nodes[ i ].origin );
  630. #/
  631.                 level thread draw_line_ent_to_pos( self, self.entrance_nodes[ i ].origin, "goal" );
  632.                 self.first_node = self.entrance_nodes[ i ];
  633.                 self setgoalpos( self.entrance_nodes[ i ].origin );
  634.                 i++;
  635.                 continue;
  636.             }
  637.             else
  638.             {
  639.                 return;
  640.             }
  641.             i++;
  642.         }
  643.     }
  644.     self zombie_history( "zombie_assure_node -> failed to find a good entrance point" );
  645.     wait 20;
  646.     self dodamage( self.health + 10, self.origin );
  647.     level.zombies_timeout_spawn++;
  648. }
  649.  
  650. zombie_bad_path()
  651. {
  652.     self endon( "death" );
  653.     self endon( "goal" );
  654.     self thread zombie_bad_path_notify();
  655.     self thread zombie_bad_path_timeout();
  656.     self.zombie_bad_path = undefined;
  657.     while ( !isDefined( self.zombie_bad_path ) )
  658.     {
  659.         wait 0,05;
  660.     }
  661.     self notify( "stop_zombie_bad_path" );
  662.     return self.zombie_bad_path;
  663. }
  664.  
  665. zombie_bad_path_notify()
  666. {
  667.     self endon( "death" );
  668.     self endon( "stop_zombie_bad_path" );
  669.     self waittill( "bad_path" );
  670.     self.zombie_bad_path = 1;
  671. }
  672.  
  673. zombie_bad_path_timeout()
  674. {
  675.     self endon( "death" );
  676.     self endon( "stop_zombie_bad_path" );
  677.     wait 2;
  678.     self.zombie_bad_path = 0;
  679. }
  680.  
  681. tear_into_building()
  682. {
  683.     self endon( "death" );
  684.     self endon( "teleporting" );
  685.     self zombie_history( "tear_into_building -> start" );
  686.     while ( 1 )
  687.     {
  688.         if ( isDefined( self.first_node.script_noteworthy ) )
  689.         {
  690.             if ( self.first_node.script_noteworthy == "no_blocker" )
  691.             {
  692.                 return;
  693.             }
  694.         }
  695.         if ( !isDefined( self.first_node.target ) )
  696.         {
  697.             return;
  698.         }
  699.         if ( all_chunks_destroyed( self.first_node, self.first_node.barrier_chunks ) )
  700.         {
  701.             self zombie_history( "tear_into_building -> all chunks destroyed" );
  702.         }
  703.         while ( !get_attack_spot( self.first_node ) )
  704.         {
  705.             self zombie_history( "tear_into_building -> Could not find an attack spot" );
  706.             self thread do_a_taunt();
  707.             wait 0,5;
  708.         }
  709.         self.goalradius = 2;
  710.         if ( isDefined( level.tear_into_position ) )
  711.         {
  712.             self [[ level.tear_into_position ]]();
  713.         }
  714.         else
  715.         {
  716.             angles = self.first_node.zbarrier.angles;
  717.             self setgoalpos( self.attacking_spot, angles );
  718.         }
  719.         self waittill( "goal" );
  720.         if ( isDefined( level.tear_into_wait ) )
  721.         {
  722.             self [[ level.tear_into_wait ]]();
  723.         }
  724.         else
  725.         {
  726.             self waittill_notify_or_timeout( "orientdone", 1 );
  727.         }
  728.         self zombie_history( "tear_into_building -> Reach position and orientated" );
  729.         if ( all_chunks_destroyed( self.first_node, self.first_node.barrier_chunks ) )
  730.         {
  731.             self zombie_history( "tear_into_building -> all chunks destroyed" );
  732.             i = 0;
  733.             while ( i < self.first_node.attack_spots_taken.size )
  734.             {
  735.                 self.first_node.attack_spots_taken[ i ] = 0;
  736.                 i++;
  737.             }
  738.             return;
  739.         }
  740.         while ( 1 )
  741.         {
  742.             if ( isDefined( self.zombie_board_tear_down_callback ) )
  743.             {
  744.                 self [[ self.zombie_board_tear_down_callback ]]();
  745.             }
  746.             chunk = get_closest_non_destroyed_chunk( self.origin, self.first_node, self.first_node.barrier_chunks );
  747.             if ( !isDefined( chunk ) )
  748.             {
  749.                 while ( !all_chunks_destroyed( self.first_node, self.first_node.barrier_chunks ) )
  750.                 {
  751.                     attack = self should_attack_player_thru_boards();
  752.                     if ( isDefined( attack ) && !attack && self.has_legs )
  753.                     {
  754.                         self do_a_taunt();
  755.                         continue;
  756.                     }
  757.                     else
  758.                     {
  759.                         wait 0,1;
  760.                     }
  761.                 }
  762.                 i = 0;
  763.                 while ( i < self.first_node.attack_spots_taken.size )
  764.                 {
  765.                     self.first_node.attack_spots_taken[ i ] = 0;
  766.                     i++;
  767.                 }
  768.                 return;
  769.             }
  770.             self zombie_history( "tear_into_building -> animating" );
  771.             self.first_node.zbarrier setzbarrierpiecestate( chunk, "targetted_by_zombie" );
  772.             self.first_node thread check_zbarrier_piece_for_zombie_inert( chunk, self.first_node.zbarrier, self );
  773.             self.first_node thread check_zbarrier_piece_for_zombie_death( chunk, self.first_node.zbarrier, self );
  774.             self thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( "teardown", self.animname );
  775.             if ( isDefined( level.zbarrier_override_tear_in ) )
  776.             {
  777.                 animstatebase = self [[ level.zbarrier_override_tear_in ]]( chunk );
  778.             }
  779.             else
  780.             {
  781.                 animstatebase = self.first_node.zbarrier getzbarrierpieceanimstate( chunk );
  782.             }
  783.             animsubstate = "spot_" + self.attacking_spot_index + "_piece_" + self.first_node.zbarrier getzbarrierpieceanimsubstate( chunk );
  784.             anim_sub_index = self getanimsubstatefromasd( animstatebase + "_in", animsubstate );
  785.             self animscripted( self.first_node.zbarrier.origin, self.first_node.zbarrier.angles, maps/mp/animscripts/zm_utility::append_missing_legs_suffix( animstatebase + "_in" ), anim_sub_index );
  786.             self zombie_tear_notetracks( "tear_anim", chunk, self.first_node );
  787.             while ( self.first_node.zbarrier.chunk_health[ chunk ] >= 0 )
  788.             {
  789.                 self animscripted( self.first_node.zbarrier.origin, self.first_node.zbarrier.angles, maps/mp/animscripts/zm_utility::append_missing_legs_suffix( animstatebase + "_loop" ), anim_sub_index );
  790.                 self zombie_tear_notetracks( "tear_anim", chunk, self.first_node );
  791.                 self.first_node.zbarrier.chunk_health[ chunk ]--;
  792.  
  793.             }
  794.             self animscripted( self.first_node.zbarrier.origin, self.first_node.zbarrier.angles, maps/mp/animscripts/zm_utility::append_missing_legs_suffix( animstatebase + "_out" ), anim_sub_index );
  795.             self zombie_tear_notetracks( "tear_anim", chunk, self.first_node );
  796.             self.lastchunk_destroy_time = getTime();
  797.             attack = self should_attack_player_thru_boards();
  798.             if ( isDefined( attack ) && !attack && self.has_legs )
  799.             {
  800.                 self do_a_taunt();
  801.             }
  802.             if ( all_chunks_destroyed( self.first_node, self.first_node.barrier_chunks ) )
  803.             {
  804.                 i = 0;
  805.                 while ( i < self.first_node.attack_spots_taken.size )
  806.                 {
  807.                     self.first_node.attack_spots_taken[ i ] = 0;
  808.                     i++;
  809.                 }
  810.                 level notify( "last_board_torn" );
  811.                 return;
  812.             }
  813.         }
  814.         self reset_attack_spot();
  815.     }
  816. }
  817.  
  818. do_a_taunt()
  819. {
  820.     self endon( "death" );
  821.     if ( !self.has_legs )
  822.     {
  823.         return 0;
  824.     }
  825.     if ( !self.first_node.zbarrier zbarriersupportszombietaunts() )
  826.     {
  827.         return;
  828.     }
  829.     self.old_origin = self.origin;
  830.     if ( getDvar( "zombie_taunt_freq" ) == "" )
  831.     {
  832.         setdvar( "zombie_taunt_freq", "5" );
  833.     }
  834.     freq = getDvarInt( "zombie_taunt_freq" );
  835.     if ( freq >= randomint( 100 ) )
  836.     {
  837.         self thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( "taunt", self.animname );
  838.         tauntstate = "zm_taunt";
  839.         if ( isDefined( self.first_node.zbarrier ) && self.first_node.zbarrier getzbarriertauntanimstate() != "" )
  840.         {
  841.             tauntstate = self.first_node.zbarrier getzbarriertauntanimstate();
  842.         }
  843.         self animscripted( self.origin, self.angles, tauntstate );
  844.         self taunt_notetracks( "taunt_anim" );
  845.     }
  846. }
  847.  
  848. taunt_notetracks( msg )
  849. {
  850.     self endon( "death" );
  851.     while ( 1 )
  852.     {
  853.         self waittill( msg, notetrack );
  854.         if ( notetrack == "end" )
  855.         {
  856.             self forceteleport( self.old_origin );
  857.             return;
  858.         }
  859.     }
  860. }
  861.  
  862. should_attack_player_thru_boards()
  863. {
  864.     if ( !self.has_legs )
  865.     {
  866.         return 0;
  867.     }
  868.     if ( isDefined( self.first_node.zbarrier ) )
  869.     {
  870.         if ( !self.first_node.zbarrier zbarriersupportszombiereachthroughattacks() )
  871.         {
  872.             return 0;
  873.         }
  874.     }
  875.     if ( getDvar( "zombie_reachin_freq" ) == "" )
  876.     {
  877.         setdvar( "zombie_reachin_freq", "50" );
  878.     }
  879.     freq = getDvarInt( "zombie_reachin_freq" );
  880.     players = get_players();
  881.     attack = 0;
  882.     self.player_targets = [];
  883.     i = 0;
  884.     while ( i < players.size )
  885.     {
  886.         if ( isalive( players[ i ] ) && !isDefined( players[ i ].revivetrigger ) && distance2d( self.origin, players[ i ].origin ) <= level.attack_player_thru_boards_range && isDefined( players[ i ].zombie_vars[ "zombie_powerup_zombie_blood_on" ] ) && !players[ i ].zombie_vars[ "zombie_powerup_zombie_blood_on" ] )
  887.         {
  888.             self.player_targets[ self.player_targets.size ] = players[ i ];
  889.             attack = 1;
  890.         }
  891.         i++;
  892.     }
  893.     if ( !attack || freq < randomint( 100 ) )
  894.     {
  895.         return 0;
  896.     }
  897.     self.old_origin = self.origin;
  898.     attackanimstate = "zm_window_melee";
  899.     if ( isDefined( self.first_node.zbarrier ) && self.first_node.zbarrier getzbarrierreachthroughattackanimstate() != "" )
  900.     {
  901.         attackanimstate = self.first_node.zbarrier getzbarrierreachthroughattackanimstate();
  902.     }
  903.     self thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( "attack", self.animname );
  904.     self animscripted( self.origin, self.angles, attackanimstate, self.attacking_spot_index - 1 );
  905.     self window_notetracks( "window_melee_anim" );
  906.     return 1;
  907. }
  908.  
  909. window_notetracks( msg )
  910. {
  911.     self endon( "death" );
  912.     while ( 1 )
  913.     {
  914.         self waittill( msg, notetrack );
  915.         if ( notetrack == "end" )
  916.         {
  917.             self teleport( self.old_origin );
  918.             return;
  919.         }
  920.         if ( notetrack == "fire" )
  921.         {
  922.             if ( self.ignoreall )
  923.             {
  924.                 self.ignoreall = 0;
  925.             }
  926.             if ( isDefined( self.first_node ) )
  927.             {
  928.                 _melee_dist_sq = 8100;
  929.                 if ( isDefined( level.attack_player_thru_boards_range ) )
  930.                 {
  931.                     _melee_dist_sq = level.attack_player_thru_boards_range * level.attack_player_thru_boards_range;
  932.                 }
  933.                 _trigger_dist_sq = 2601;
  934.                 i = 0;
  935.                 while ( i < self.player_targets.size )
  936.                 {
  937.                     playerdistsq = distance2dsquared( self.player_targets[ i ].origin, self.origin );
  938.                     heightdiff = abs( self.player_targets[ i ].origin[ 2 ] - self.origin[ 2 ] );
  939.                     if ( playerdistsq < _melee_dist_sq && ( heightdiff * heightdiff ) < _melee_dist_sq )
  940.                     {
  941.                         triggerdistsq = distance2dsquared( self.player_targets[ i ].origin, self.first_node.trigger_location.origin );
  942.                         heightdiff = abs( self.player_targets[ i ].origin[ 2 ] - self.first_node.trigger_location.origin[ 2 ] );
  943.                         if ( triggerdistsq < _trigger_dist_sq && ( heightdiff * heightdiff ) < _trigger_dist_sq )
  944.                         {
  945.                             self.player_targets[ i ] dodamage( self.meleedamage, self.origin, self, self, "none", "MOD_MELEE" );
  946.                             break;
  947.                         }
  948.                     }
  949.                     else
  950.                     {
  951.                         i++;
  952.                     }
  953.                 }
  954.             }
  955.             else self melee();
  956.         }
  957.     }
  958. }
  959.  
  960. reset_attack_spot()
  961. {
  962.     if ( isDefined( self.attacking_node ) )
  963.     {
  964.         node = self.attacking_node;
  965.         index = self.attacking_spot_index;
  966.         node.attack_spots_taken[ index ] = 0;
  967.         self.attacking_node = undefined;
  968.         self.attacking_spot_index = undefined;
  969.     }
  970. }
  971.  
  972. get_attack_spot( node )
  973. {
  974.     index = get_attack_spot_index( node );
  975.     if ( !isDefined( index ) )
  976.     {
  977.         return 0;
  978.     }
  979.     self.attacking_node = node;
  980.     self.attacking_spot_index = index;
  981.     node.attack_spots_taken[ index ] = 1;
  982.     self.attacking_spot = node.attack_spots[ index ];
  983.     return 1;
  984. }
  985.  
  986. get_attack_spot_index( node )
  987. {
  988.     indexes = [];
  989.     i = 0;
  990.     while ( i < node.attack_spots.size )
  991.     {
  992.         if ( !node.attack_spots_taken[ i ] )
  993.         {
  994.             indexes[ indexes.size ] = i;
  995.         }
  996.         i++;
  997.     }
  998.     if ( indexes.size == 0 )
  999.     {
  1000.         return undefined;
  1001.     }
  1002.     return indexes[ randomint( indexes.size ) ];
  1003. }
  1004.  
  1005. zombie_tear_notetracks( msg, chunk, node )
  1006. {
  1007.     self endon( "death" );
  1008.     while ( 1 )
  1009.     {
  1010.         self waittill( msg, notetrack );
  1011.         if ( notetrack == "end" )
  1012.         {
  1013.             return;
  1014.         }
  1015.         if ( notetrack != "board" || notetrack == "destroy_piece" && notetrack == "bar" )
  1016.         {
  1017.             if ( isDefined( level.zbarrier_zombie_tear_notetrack_override ) )
  1018.             {
  1019.                 self thread [[ level.zbarrier_zombie_tear_notetrack_override ]]( node, chunk );
  1020.             }
  1021.             node.zbarrier setzbarrierpiecestate( chunk, "opening" );
  1022.         }
  1023.     }
  1024. }
  1025.  
  1026. zombie_boardtear_offset_fx_horizontle( chunk, node )
  1027. {
  1028.     if ( isDefined( chunk.script_parameters ) || chunk.script_parameters == "repair_board" && chunk.script_parameters == "board" )
  1029.     {
  1030.         if ( isDefined( chunk.unbroken ) && chunk.unbroken == 1 )
  1031.         {
  1032.             if ( isDefined( chunk.material ) && chunk.material == "glass" )
  1033.             {
  1034.                 playfx( level._effect[ "glass_break" ], chunk.origin, node.angles );
  1035.                 chunk.unbroken = 0;
  1036.             }
  1037.             else
  1038.             {
  1039.                 if ( isDefined( chunk.material ) && chunk.material == "metal" )
  1040.                 {
  1041.                     playfx( level._effect[ "fx_zombie_bar_break" ], chunk.origin );
  1042.                     chunk.unbroken = 0;
  1043.                 }
  1044.                 else
  1045.                 {
  1046.                     if ( isDefined( chunk.material ) && chunk.material == "rock" )
  1047.                     {
  1048.                         if ( isDefined( level.use_clientside_rock_tearin_fx ) && level.use_clientside_rock_tearin_fx )
  1049.                         {
  1050.                             chunk setclientflag( level._zombie_scriptmover_flag_rock_fx );
  1051.                         }
  1052.                         else
  1053.                         {
  1054.                             playfx( level._effect[ "wall_break" ], chunk.origin );
  1055.                         }
  1056.                         chunk.unbroken = 0;
  1057.                     }
  1058.                 }
  1059.             }
  1060.         }
  1061.     }
  1062.     if ( isDefined( chunk.script_parameters ) && chunk.script_parameters == "barricade_vents" )
  1063.     {
  1064.         if ( isDefined( level.use_clientside_board_fx ) && level.use_clientside_board_fx )
  1065.         {
  1066.             chunk setclientflag( level._zombie_scriptmover_flag_board_horizontal_fx );
  1067.         }
  1068.         else
  1069.         {
  1070.             playfx( level._effect[ "fx_zombie_bar_break" ], chunk.origin );
  1071.         }
  1072.     }
  1073.     else
  1074.     {
  1075.         if ( isDefined( chunk.material ) && chunk.material == "rock" )
  1076.         {
  1077.             if ( isDefined( level.use_clientside_rock_tearin_fx ) && level.use_clientside_rock_tearin_fx )
  1078.             {
  1079.                 chunk setclientflag( level._zombie_scriptmover_flag_rock_fx );
  1080.             }
  1081.             return;
  1082.         }
  1083.         else
  1084.         {
  1085.             if ( isDefined( level.use_clientside_board_fx ) )
  1086.             {
  1087.                 chunk setclientflag( level._zombie_scriptmover_flag_board_horizontal_fx );
  1088.                 return;
  1089.             }
  1090.             else
  1091.             {
  1092.                 playfx( level._effect[ "wood_chunk_destory" ], chunk.origin + vectorScale( ( 0, 0, 0 ), 30 ) );
  1093.                 wait randomfloatrange( 0,2, 0,4 );
  1094.                 playfx( level._effect[ "wood_chunk_destory" ], chunk.origin + vectorScale( ( 0, 0, 0 ), 30 ) );
  1095.             }
  1096.         }
  1097.     }
  1098. }
  1099.  
  1100. zombie_boardtear_offset_fx_verticle( chunk, node )
  1101. {
  1102.     if ( isDefined( chunk.script_parameters ) || chunk.script_parameters == "repair_board" && chunk.script_parameters == "board" )
  1103.     {
  1104.         if ( isDefined( chunk.unbroken ) && chunk.unbroken == 1 )
  1105.         {
  1106.             if ( isDefined( chunk.material ) && chunk.material == "glass" )
  1107.             {
  1108.                 playfx( level._effect[ "glass_break" ], chunk.origin, node.angles );
  1109.                 chunk.unbroken = 0;
  1110.             }
  1111.             else
  1112.             {
  1113.                 if ( isDefined( chunk.material ) && chunk.material == "metal" )
  1114.                 {
  1115.                     playfx( level._effect[ "fx_zombie_bar_break" ], chunk.origin );
  1116.                     chunk.unbroken = 0;
  1117.                 }
  1118.                 else
  1119.                 {
  1120.                     if ( isDefined( chunk.material ) && chunk.material == "rock" )
  1121.                     {
  1122.                         if ( isDefined( level.use_clientside_rock_tearin_fx ) && level.use_clientside_rock_tearin_fx )
  1123.                         {
  1124.                             chunk setclientflag( level._zombie_scriptmover_flag_rock_fx );
  1125.                         }
  1126.                         else
  1127.                         {
  1128.                             playfx( level._effect[ "wall_break" ], chunk.origin );
  1129.                         }
  1130.                         chunk.unbroken = 0;
  1131.                     }
  1132.                 }
  1133.             }
  1134.         }
  1135.     }
  1136.     if ( isDefined( chunk.script_parameters ) && chunk.script_parameters == "barricade_vents" )
  1137.     {
  1138.         if ( isDefined( level.use_clientside_board_fx ) )
  1139.         {
  1140.             chunk setclientflag( level._zombie_scriptmover_flag_board_vertical_fx );
  1141.         }
  1142.         else
  1143.         {
  1144.             playfx( level._effect[ "fx_zombie_bar_break" ], chunk.origin );
  1145.         }
  1146.     }
  1147.     else
  1148.     {
  1149.         if ( isDefined( chunk.material ) && chunk.material == "rock" )
  1150.         {
  1151.             if ( isDefined( level.use_clientside_rock_tearin_fx ) && level.use_clientside_rock_tearin_fx )
  1152.             {
  1153.                 chunk setclientflag( level._zombie_scriptmover_flag_rock_fx );
  1154.             }
  1155.             return;
  1156.         }
  1157.         else
  1158.         {
  1159.             if ( isDefined( level.use_clientside_board_fx ) )
  1160.             {
  1161.                 chunk setclientflag( level._zombie_scriptmover_flag_board_vertical_fx );
  1162.                 return;
  1163.             }
  1164.             else
  1165.             {
  1166.                 playfx( level._effect[ "wood_chunk_destory" ], chunk.origin + vectorScale( ( 0, 0, 0 ), 30 ) );
  1167.                 wait randomfloatrange( 0,2, 0,4 );
  1168.                 playfx( level._effect[ "wood_chunk_destory" ], chunk.origin + vectorScale( ( 0, 0, 0 ), 30 ) );
  1169.             }
  1170.         }
  1171.     }
  1172. }
  1173.  
  1174. zombie_bartear_offset_fx_verticle( chunk )
  1175. {
  1176.     if ( isDefined( chunk.script_parameters ) || chunk.script_parameters == "bar" && chunk.script_noteworthy == "board" )
  1177.     {
  1178.         possible_tag_array_1 = [];
  1179.         possible_tag_array_1[ 0 ] = "Tag_fx_top";
  1180.         possible_tag_array_1[ 1 ] = "";
  1181.         possible_tag_array_1[ 2 ] = "Tag_fx_top";
  1182.         possible_tag_array_1[ 3 ] = "";
  1183.         possible_tag_array_2 = [];
  1184.         possible_tag_array_2[ 0 ] = "";
  1185.         possible_tag_array_2[ 1 ] = "Tag_fx_bottom";
  1186.         possible_tag_array_2[ 2 ] = "";
  1187.         possible_tag_array_2[ 3 ] = "Tag_fx_bottom";
  1188.         possible_tag_array_2 = array_randomize( possible_tag_array_2 );
  1189.         random_fx = [];
  1190.         random_fx[ 0 ] = level._effect[ "fx_zombie_bar_break" ];
  1191.         random_fx[ 1 ] = level._effect[ "fx_zombie_bar_break_lite" ];
  1192.         random_fx[ 2 ] = level._effect[ "fx_zombie_bar_break" ];
  1193.         random_fx[ 3 ] = level._effect[ "fx_zombie_bar_break_lite" ];
  1194.         random_fx = array_randomize( random_fx );
  1195.         switch( randomint( 9 ) )
  1196.         {
  1197.             case 0:
  1198.                 playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_top" );
  1199.                 wait randomfloatrange( 0, 0,3 );
  1200.                 playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_bottom" );
  1201.                 break;
  1202.             return;
  1203.             case 1:
  1204.                 playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_top" );
  1205.                 wait randomfloatrange( 0, 0,3 );
  1206.                 playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_bottom" );
  1207.                 break;
  1208.             return;
  1209.             case 2:
  1210.                 playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_top" );
  1211.                 wait randomfloatrange( 0, 0,3 );
  1212.                 playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_bottom" );
  1213.                 break;
  1214.             return;
  1215.             case 3:
  1216.                 playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_top" );
  1217.                 wait randomfloatrange( 0, 0,3 );
  1218.                 playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_bottom" );
  1219.                 break;
  1220.             return;
  1221.             case 4:
  1222.                 playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_top" );
  1223.                 wait randomfloatrange( 0, 0,3 );
  1224.                 playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_bottom" );
  1225.                 break;
  1226.             return;
  1227.             case 5:
  1228.                 playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_top" );
  1229.                 break;
  1230.             return;
  1231.             case 6:
  1232.                 playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_bottom" );
  1233.                 break;
  1234.             return;
  1235.             case 7:
  1236.                 playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_top" );
  1237.                 break;
  1238.             return;
  1239.             case 8:
  1240.                 playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_bottom" );
  1241.                 break;
  1242.             return;
  1243.         }
  1244.     }
  1245. }
  1246.  
  1247. zombie_bartear_offset_fx_horizontle( chunk )
  1248. {
  1249.     if ( isDefined( chunk.script_parameters ) || chunk.script_parameters == "bar" && chunk.script_noteworthy == "board" )
  1250.     {
  1251.         switch( randomint( 10 ) )
  1252.         {
  1253.             case 0:
  1254.                 playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_left" );
  1255.                 wait randomfloatrange( 0, 0,3 );
  1256.                 playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_right" );
  1257.                 break;
  1258.             return;
  1259.             case 1:
  1260.                 playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_left" );
  1261.                 wait randomfloatrange( 0, 0,3 );
  1262.                 playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_right" );
  1263.                 break;
  1264.             return;
  1265.             case 2:
  1266.                 playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_left" );
  1267.                 wait randomfloatrange( 0, 0,3 );
  1268.                 playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_right" );
  1269.                 break;
  1270.             return;
  1271.             case 3:
  1272.                 playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_left" );
  1273.                 wait randomfloatrange( 0, 0,3 );
  1274.                 playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_right" );
  1275.                 break;
  1276.             return;
  1277.             case 4:
  1278.                 playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_left" );
  1279.                 wait randomfloatrange( 0, 0,3 );
  1280.                 playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_right" );
  1281.                 break;
  1282.             return;
  1283.             case 5:
  1284.                 playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_left" );
  1285.                 break;
  1286.             return;
  1287.             case 6:
  1288.                 playfxontag( level._effect[ "fx_zombie_bar_break_lite" ], chunk, "Tag_fx_right" );
  1289.                 break;
  1290.             return;
  1291.             case 7:
  1292.                 playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_right" );
  1293.                 break;
  1294.             return;
  1295.             case 8:
  1296.                 playfxontag( level._effect[ "fx_zombie_bar_break" ], chunk, "Tag_fx_right" );
  1297.                 break;
  1298.             return;
  1299.         }
  1300.     }
  1301. }
  1302.  
  1303. check_zbarrier_piece_for_zombie_inert( chunk_index, zbarrier, zombie )
  1304. {
  1305.     zombie endon( "completed_emerging_into_playable_area" );
  1306.     zombie waittill( "stop_zombie_goto_entrance" );
  1307.     if ( zbarrier getzbarrierpiecestate( chunk_index ) == "targetted_by_zombie" )
  1308.     {
  1309.         zbarrier setzbarrierpiecestate( chunk_index, "closed" );
  1310.     }
  1311. }
  1312.  
  1313. check_zbarrier_piece_for_zombie_death( chunk_index, zbarrier, zombie )
  1314. {
  1315.     while ( 1 )
  1316.     {
  1317.         if ( zbarrier getzbarrierpiecestate( chunk_index ) != "targetted_by_zombie" )
  1318.         {
  1319.             return;
  1320.         }
  1321.         if ( !isDefined( zombie ) || !isalive( zombie ) )
  1322.         {
  1323.             zbarrier setzbarrierpiecestate( chunk_index, "closed" );
  1324.             return;
  1325.         }
  1326.         wait 0,05;
  1327.     }
  1328. }
  1329.  
  1330. check_for_zombie_death( zombie )
  1331. {
  1332.     self endon( "destroyed" );
  1333.     wait 2,5;
  1334.     self maps/mp/zombies/_zm_blockers::update_states( "repaired" );
  1335. }
  1336.  
  1337. zombie_hat_gib( attacker, means_of_death )
  1338. {
  1339.     self endon( "death" );
  1340.     if ( !is_mature() )
  1341.     {
  1342.         return 0;
  1343.     }
  1344.     if ( isDefined( self.hat_gibbed ) && self.hat_gibbed )
  1345.     {
  1346.         return;
  1347.     }
  1348.     if ( !isDefined( self.gibspawn5 ) || !isDefined( self.gibspawntag5 ) )
  1349.     {
  1350.         return;
  1351.     }
  1352.     self.hat_gibbed = 1;
  1353.     if ( isDefined( self.hatmodel ) )
  1354.     {
  1355.         self detach( self.hatmodel, "" );
  1356.     }
  1357.     temp_array = [];
  1358.     temp_array[ 0 ] = level._zombie_gib_piece_index_hat;
  1359.     self gib( "normal", temp_array );
  1360.     if ( isDefined( level.track_gibs ) )
  1361.     {
  1362.         level [[ level.track_gibs ]]( self, temp_array );
  1363.     }
  1364. }
  1365.  
  1366. zombie_head_gib( attacker, means_of_death )
  1367. {
  1368.     self endon( "death" );
  1369.     if ( !is_mature() )
  1370.     {
  1371.         return 0;
  1372.     }
  1373.     if ( isDefined( self.head_gibbed ) && self.head_gibbed )
  1374.     {
  1375.         return;
  1376.     }
  1377.     self.head_gibbed = 1;
  1378.     self zombie_eye_glow_stop();
  1379.     size = self getattachsize();
  1380.     i = 0;
  1381.     while ( i < size )
  1382.     {
  1383.         model = self getattachmodelname( i );
  1384.         if ( issubstr( model, "head" ) )
  1385.         {
  1386.             if ( isDefined( self.hatmodel ) )
  1387.             {
  1388.                 self detach( self.hatmodel, "" );
  1389.             }
  1390.             self detach( model, "" );
  1391.             if ( isDefined( self.torsodmg5 ) )
  1392.             {
  1393.                 self attach( self.torsodmg5, "", 1 );
  1394.             }
  1395.             break;
  1396.         }
  1397.         else
  1398.         {
  1399.             i++;
  1400.         }
  1401.     }
  1402.     temp_array = [];
  1403.     temp_array[ 0 ] = level._zombie_gib_piece_index_head;
  1404.     if ( isDefined( self.hat_gibbed ) && !self.hat_gibbed && isDefined( self.gibspawn5 ) && isDefined( self.gibspawntag5 ) )
  1405.     {
  1406.         temp_array[ 1 ] = level._zombie_gib_piece_index_hat;
  1407.     }
  1408.     self.hat_gibbed = 1;
  1409.     self gib( "normal", temp_array );
  1410.     if ( isDefined( level.track_gibs ) )
  1411.     {
  1412.         level [[ level.track_gibs ]]( self, temp_array );
  1413.     }
  1414.     self thread damage_over_time( ceil( self.health * 0,2 ), 1, attacker, means_of_death );
  1415. }
  1416.  
  1417. damage_over_time( dmg, delay, attacker, means_of_death )
  1418. {
  1419.     self endon( "death" );
  1420.     self endon( "exploding" );
  1421.     if ( !isalive( self ) )
  1422.     {
  1423.         return;
  1424.     }
  1425.     if ( !isplayer( attacker ) )
  1426.     {
  1427.         attacker = self;
  1428.     }
  1429.     if ( !isDefined( means_of_death ) )
  1430.     {
  1431.         means_of_death = "MOD_UNKNOWN";
  1432.     }
  1433.     while ( 1 )
  1434.     {
  1435.         if ( isDefined( delay ) )
  1436.         {
  1437.             wait delay;
  1438.         }
  1439.         if ( isDefined( self ) )
  1440.         {
  1441.             self dodamage( dmg, self gettagorigin( "j_neck" ), attacker, self, self.damagelocation, means_of_death, 0, self.damageweapon );
  1442.         }
  1443.     }
  1444. }
  1445.  
  1446. head_should_gib( attacker, type, point )
  1447. {
  1448.     if ( !is_mature() )
  1449.     {
  1450.         return 0;
  1451.     }
  1452.     if ( self.head_gibbed )
  1453.     {
  1454.         return 0;
  1455.     }
  1456.     if ( !isDefined( attacker ) || !isplayer( attacker ) )
  1457.     {
  1458.         return 0;
  1459.     }
  1460.     weapon = attacker getcurrentweapon();
  1461.     if ( type != "MOD_RIFLE_BULLET" && type != "MOD_PISTOL_BULLET" )
  1462.     {
  1463.         if ( type == "MOD_GRENADE" || type == "MOD_GRENADE_SPLASH" )
  1464.         {
  1465.             if ( distance( point, self gettagorigin( "j_head" ) ) > 55 )
  1466.             {
  1467.                 return 0;
  1468.             }
  1469.             else
  1470.             {
  1471.                 return 1;
  1472.             }
  1473.         }
  1474.         else
  1475.         {
  1476.             if ( type == "MOD_PROJECTILE" )
  1477.             {
  1478.                 if ( distance( point, self gettagorigin( "j_head" ) ) > 10 )
  1479.                 {
  1480.                     return 0;
  1481.                 }
  1482.                 else
  1483.                 {
  1484.                     return 1;
  1485.                 }
  1486.             }
  1487.             else
  1488.             {
  1489.                 if ( weaponclass( weapon ) != "spread" )
  1490.                 {
  1491.                     return 0;
  1492.                 }
  1493.             }
  1494.         }
  1495.     }
  1496.     if ( !self maps/mp/animscripts/zm_utility::damagelocationisany( "head", "helmet", "neck" ) )
  1497.     {
  1498.         return 0;
  1499.     }
  1500.     if ( weapon != "none" || weapon == level.start_weapon && weaponisgasweapon( self.weapon ) )
  1501.     {
  1502.         return 0;
  1503.     }
  1504.     low_health_percent = ( self.health / self.maxhealth ) * 100;
  1505.     if ( low_health_percent > 10 )
  1506.     {
  1507.         self zombie_hat_gib( attacker, type );
  1508.         return 0;
  1509.     }
  1510.     return 1;
  1511. }
  1512.  
  1513. headshot_blood_fx()
  1514. {
  1515.     if ( !isDefined( self ) )
  1516.     {
  1517.         return;
  1518.     }
  1519.     if ( !is_mature() )
  1520.     {
  1521.         return;
  1522.     }
  1523.     fxtag = "j_neck";
  1524.     fxorigin = self gettagorigin( fxtag );
  1525.     upvec = anglesToUp( self gettagangles( fxtag ) );
  1526.     forwardvec = anglesToForward( self gettagangles( fxtag ) );
  1527.     playfx( level._effect[ "headshot" ], fxorigin, forwardvec, upvec );
  1528.     playfx( level._effect[ "headshot_nochunks" ], fxorigin, forwardvec, upvec );
  1529.     wait 0,3;
  1530.     if ( isDefined( self ) )
  1531.     {
  1532.         playfxontag( level._effect[ "bloodspurt" ], self, fxtag );
  1533.     }
  1534. }
  1535.  
  1536. zombie_gib_on_damage()
  1537. {
  1538.     while ( 1 )
  1539.     {
  1540.         self waittill( "damage", amount, attacker, direction_vec, point, type, tagname, modelname, partname, weaponname );
  1541.         if ( !isDefined( self ) )
  1542.         {
  1543.             return;
  1544.         }
  1545.         while ( !self zombie_should_gib( amount, attacker, type ) )
  1546.         {
  1547.             continue;
  1548.         }
  1549.         while ( self head_should_gib( attacker, type, point ) && type != "MOD_BURNED" )
  1550.         {
  1551.             self zombie_head_gib( attacker, type );
  1552.         }
  1553.         if ( !self.gibbed )
  1554.         {
  1555.             while ( self maps/mp/animscripts/zm_utility::damagelocationisany( "head", "helmet", "neck" ) )
  1556.             {
  1557.                 continue;
  1558.             }
  1559.             refs = [];
  1560.             switch( self.damagelocation )
  1561.             {
  1562.                 case "torso_lower":
  1563.                 case "torso_upper":
  1564.                     refs[ refs.size ] = "guts";
  1565.                     refs[ refs.size ] = "right_arm";
  1566.                     break;
  1567.                 case "right_arm_lower":
  1568.                 case "right_arm_upper":
  1569.                 case "right_hand":
  1570.                     refs[ refs.size ] = "right_arm";
  1571.                     break;
  1572.                 case "left_arm_lower":
  1573.                 case "left_arm_upper":
  1574.                 case "left_hand":
  1575.                     refs[ refs.size ] = "left_arm";
  1576.                     break;
  1577.                 case "right_foot":
  1578.                 case "right_leg_lower":
  1579.                 case "right_leg_upper":
  1580.                     if ( self.health <= 0 )
  1581.                     {
  1582.                         refs[ refs.size ] = "right_leg";
  1583.                         refs[ refs.size ] = "right_leg";
  1584.                         refs[ refs.size ] = "right_leg";
  1585.                         refs[ refs.size ] = "no_legs";
  1586.                     }
  1587.                     break;
  1588.                 case "left_foot":
  1589.                 case "left_leg_lower":
  1590.                 case "left_leg_upper":
  1591.                     if ( self.health <= 0 )
  1592.                     {
  1593.                         refs[ refs.size ] = "left_leg";
  1594.                         refs[ refs.size ] = "left_leg";
  1595.                         refs[ refs.size ] = "left_leg";
  1596.                         refs[ refs.size ] = "no_legs";
  1597.                     }
  1598.                     break;
  1599.                 default:
  1600.                     if ( self.damagelocation == "none" )
  1601.                     {
  1602.                         if ( type != "MOD_GRENADE" && type != "MOD_GRENADE_SPLASH" || type == "MOD_PROJECTILE" && type == "MOD_PROJECTILE_SPLASH" )
  1603.                         {
  1604.                             refs = self derive_damage_refs( point );
  1605.                             break;
  1606.                     }
  1607.                     else }
  1608.                 else refs[ refs.size ] = "guts";
  1609.                 refs[ refs.size ] = "right_arm";
  1610.                 refs[ refs.size ] = "left_arm";
  1611.                 refs[ refs.size ] = "right_leg";
  1612.                 refs[ refs.size ] = "left_leg";
  1613.                 refs[ refs.size ] = "no_legs";
  1614.                 break;
  1615.         }
  1616.         if ( isDefined( level.custom_derive_damage_refs ) )
  1617.         {
  1618.             refs = self [[ level.custom_derive_damage_refs ]]( refs, point, weaponname );
  1619.         }
  1620.         if ( refs.size )
  1621.         {
  1622.             self.a.gib_ref = maps/mp/animscripts/zm_death::get_random( refs );
  1623.             if ( self.a.gib_ref != "no_legs" && self.a.gib_ref != "right_leg" && self.a.gib_ref == "left_leg" && self.health > 0 )
  1624.             {
  1625.                 self.has_legs = 0;
  1626.                 self allowedstances( "crouch" );
  1627.                 self setphysparams( 15, 0, 24 );
  1628.                 self allowpitchangle( 1 );
  1629.                 self setpitchorient();
  1630.                 health = self.health;
  1631.                 health *= 0,1;
  1632.                 self thread maps/mp/animscripts/zm_run::needsdelayedupdate();
  1633.                 if ( isDefined( self.crawl_anim_override ) )
  1634.                 {
  1635.                     self [[ self.crawl_anim_override ]]();
  1636.                 }
  1637.             }
  1638.         }
  1639.         if ( self.health > 0 )
  1640.         {
  1641.             self thread maps/mp/animscripts/zm_death::do_gib();
  1642.             if ( isDefined( level.gib_on_damage ) )
  1643.             {
  1644.                 self thread [[ level.gib_on_damage ]]();
  1645.             }
  1646.         }
  1647.     }
  1648. }
  1649. }
  1650.  
  1651. zombie_should_gib( amount, attacker, type )
  1652. {
  1653.     if ( !is_mature() )
  1654.     {
  1655.         return 0;
  1656.     }
  1657.     if ( !isDefined( type ) )
  1658.     {
  1659.         return 0;
  1660.     }
  1661.     if ( isDefined( self.is_on_fire ) && self.is_on_fire )
  1662.     {
  1663.         return 0;
  1664.     }
  1665.     if ( isDefined( self.no_gib ) && self.no_gib == 1 )
  1666.     {
  1667.         return 0;
  1668.     }
  1669.     switch( type )
  1670.     {
  1671.         case "MOD_BURNED":
  1672.         case "MOD_CRUSH":
  1673.         case "MOD_FALLING":
  1674.         case "MOD_SUICIDE":
  1675.         case "MOD_TELEFRAG":
  1676.         case "MOD_TRIGGER_HURT":
  1677.         case "MOD_UNKNOWN":
  1678.             return 0;
  1679.         case "MOD_MELEE":
  1680.             return 0;
  1681.     }
  1682.     if ( type == "MOD_PISTOL_BULLET" || type == "MOD_RIFLE_BULLET" )
  1683.     {
  1684.         if ( !isDefined( attacker ) || !isplayer( attacker ) )
  1685.         {
  1686.             return 0;
  1687.         }
  1688.         weapon = attacker getcurrentweapon();
  1689.         if ( weapon == "none" || weapon == level.start_weapon )
  1690.         {
  1691.             return 0;
  1692.         }
  1693.         if ( weaponisgasweapon( self.weapon ) )
  1694.         {
  1695.             return 0;
  1696.         }
  1697.     }
  1698.     else
  1699.     {
  1700.         if ( type == "MOD_PROJECTILE" )
  1701.         {
  1702.             if ( isDefined( attacker ) && isplayer( attacker ) )
  1703.             {
  1704.                 weapon = attacker getcurrentweapon();
  1705.                 if ( weapon == "slipgun_zm" || weapon == "slipgun_upgraded_zm" )
  1706.                 {
  1707.                     return 0;
  1708.                 }
  1709.             }
  1710.         }
  1711.     }
  1712.     prev_health = amount + self.health;
  1713.     if ( prev_health <= 0 )
  1714.     {
  1715.         prev_health = 1;
  1716.     }
  1717.     damage_percent = ( amount / prev_health ) * 100;
  1718.     if ( damage_percent < 10 )
  1719.     {
  1720.         return 0;
  1721.     }
  1722.     return 1;
  1723. }
  1724.  
  1725. derive_damage_refs( point )
  1726. {
  1727.     if ( !isDefined( level.gib_tags ) )
  1728.     {
  1729.         init_gib_tags();
  1730.     }
  1731.     closesttag = undefined;
  1732.     i = 0;
  1733.     while ( i < level.gib_tags.size )
  1734.     {
  1735.         if ( !isDefined( closesttag ) )
  1736.         {
  1737.             closesttag = level.gib_tags[ i ];
  1738.             i++;
  1739.             continue;
  1740.         }
  1741.         else
  1742.         {
  1743.             if ( distancesquared( point, self gettagorigin( level.gib_tags[ i ] ) ) < distancesquared( point, self gettagorigin( closesttag ) ) )
  1744.             {
  1745.                 closesttag = level.gib_tags[ i ];
  1746.             }
  1747.         }
  1748.         i++;
  1749.     }
  1750.     refs = [];
  1751.     if ( closesttag != "J_SpineLower" || closesttag == "J_SpineUpper" && closesttag == "J_Spine4" )
  1752.     {
  1753.         refs[ refs.size ] = "guts";
  1754.         refs[ refs.size ] = "right_arm";
  1755.     }
  1756.     else
  1757.     {
  1758.         if ( closesttag != "J_Shoulder_LE" || closesttag == "J_Elbow_LE" && closesttag == "J_Wrist_LE" )
  1759.         {
  1760.             refs[ refs.size ] = "left_arm";
  1761.         }
  1762.         else
  1763.         {
  1764.             if ( closesttag != "J_Shoulder_RI" || closesttag == "J_Elbow_RI" && closesttag == "J_Wrist_RI" )
  1765.             {
  1766.                 refs[ refs.size ] = "right_arm";
  1767.             }
  1768.             else
  1769.             {
  1770.                 if ( closesttag != "J_Hip_LE" || closesttag == "J_Knee_LE" && closesttag == "J_Ankle_LE" )
  1771.                 {
  1772.                     refs[ refs.size ] = "left_leg";
  1773.                     refs[ refs.size ] = "no_legs";
  1774.                 }
  1775.                 else
  1776.                 {
  1777.                     if ( closesttag != "J_Hip_RI" || closesttag == "J_Knee_RI" && closesttag == "J_Ankle_RI" )
  1778.                     {
  1779.                         refs[ refs.size ] = "right_leg";
  1780.                         refs[ refs.size ] = "no_legs";
  1781.                     }
  1782.                 }
  1783.             }
  1784.         }
  1785.     }
  1786. /#
  1787.     assert( array_validate( refs ), "get_closest_damage_refs(): couldn't derive refs from closestTag " + closesttag );
  1788. #/
  1789.     return refs;
  1790. }
  1791.  
  1792. init_gib_tags()
  1793. {
  1794.     tags = [];
  1795.     tags[ tags.size ] = "J_SpineLower";
  1796.     tags[ tags.size ] = "J_SpineUpper";
  1797.     tags[ tags.size ] = "J_Spine4";
  1798.     tags[ tags.size ] = "J_Shoulder_LE";
  1799.     tags[ tags.size ] = "J_Elbow_LE";
  1800.     tags[ tags.size ] = "J_Wrist_LE";
  1801.     tags[ tags.size ] = "J_Shoulder_RI";
  1802.     tags[ tags.size ] = "J_Elbow_RI";
  1803.     tags[ tags.size ] = "J_Wrist_RI";
  1804.     tags[ tags.size ] = "J_Hip_LE";
  1805.     tags[ tags.size ] = "J_Knee_LE";
  1806.     tags[ tags.size ] = "J_Ankle_LE";
  1807.     tags[ tags.size ] = "J_Hip_RI";
  1808.     tags[ tags.size ] = "J_Knee_RI";
  1809.     tags[ tags.size ] = "J_Ankle_RI";
  1810.     level.gib_tags = tags;
  1811. }
  1812.  
  1813. zombie_can_drop_powerups( zombie )
  1814. {
  1815.     if ( is_tactical_grenade( zombie.damageweapon ) || !flag( "zombie_drop_powerups" ) )
  1816.     {
  1817.         return 0;
  1818.     }
  1819.     if ( isDefined( zombie.no_powerups ) && zombie.no_powerups )
  1820.     {
  1821.         return 0;
  1822.     }
  1823.     return 1;
  1824. }
  1825.  
  1826. zombie_delay_powerup_drop( origin )
  1827. {
  1828.     wait_network_frame();
  1829.     level thread maps/mp/zombies/_zm_powerups::powerup_drop( origin );
  1830. }
  1831.  
  1832. zombie_death_points( origin, mod, hit_location, attacker, zombie, team )
  1833. {
  1834.     if ( !isDefined( attacker ) || !isplayer( attacker ) )
  1835.     {
  1836.         return;
  1837.     }
  1838.     if ( zombie_can_drop_powerups( zombie ) )
  1839.     {
  1840.         if ( isDefined( zombie.in_the_ground ) && zombie.in_the_ground == 1 )
  1841.         {
  1842.             trace = bullettrace( zombie.origin + vectorScale( ( 0, 0, 0 ), 100 ), zombie.origin + vectorScale( ( 0, 0, 0 ), 100 ), 0, undefined );
  1843.             origin = trace[ "position" ];
  1844.             level thread zombie_delay_powerup_drop( origin );
  1845.         }
  1846.         else
  1847.         {
  1848.             trace = groundtrace( zombie.origin + vectorScale( ( 0, 0, 0 ), 5 ), zombie.origin + vectorScale( ( 0, 0, 0 ), 300 ), 0, undefined );
  1849.             origin = trace[ "position" ];
  1850.             level thread zombie_delay_powerup_drop( origin );
  1851.         }
  1852.     }
  1853.     level thread maps/mp/zombies/_zm_audio::player_zombie_kill_vox( hit_location, attacker, mod, zombie );
  1854.     event = "death";
  1855.     if ( isDefined( zombie.damageweapon ) && issubstr( zombie.damageweapon, "knife_ballistic_" ) || mod == "MOD_MELEE" && mod == "MOD_IMPACT" )
  1856.     {
  1857.         event = "ballistic_knife_death";
  1858.     }
  1859.     if ( isDefined( zombie.deathpoints_already_given ) && zombie.deathpoints_already_given )
  1860.     {
  1861.         return;
  1862.     }
  1863.     zombie.deathpoints_already_given = 1;
  1864.     if ( isDefined( zombie.damageweapon ) && is_equipment( zombie.damageweapon ) )
  1865.     {
  1866.         return;
  1867.     }
  1868.     attacker maps/mp/zombies/_zm_score::player_add_points( event, mod, hit_location, undefined, team, attacker.currentweapon );
  1869. }
  1870.  
  1871. get_number_variants( aliasprefix )
  1872. {
  1873.     i = 0;
  1874.     while ( i < 100 )
  1875.     {
  1876.         if ( !soundexists( ( aliasprefix + "_" ) + i ) )
  1877.         {
  1878.             return i;
  1879.         }
  1880.         i++;
  1881.     }
  1882. }
  1883.  
  1884. dragons_breath_flame_death_fx()
  1885. {
  1886.     if ( self.isdog )
  1887.     {
  1888.         return;
  1889.     }
  1890.     if ( !isDefined( level._effect ) || !isDefined( level._effect[ "character_fire_death_sm" ] ) )
  1891.     {
  1892. /#
  1893.         println( "^3ANIMSCRIPT WARNING: You are missing level._effect["character_fire_death_sm"], please set it in your levelname_fx.gsc. Use "env/fire/fx_fire_zombie_md"" );
  1894. #/
  1895.         return;
  1896.     }
  1897.     playfxontag( level._effect[ "character_fire_death_sm" ], self, "J_SpineLower" );
  1898.     tagarray = [];
  1899.     if ( !isDefined( self.a.gib_ref ) || self.a.gib_ref != "left_arm" )
  1900.     {
  1901.         tagarray[ tagarray.size ] = "J_Elbow_LE";
  1902.         tagarray[ tagarray.size ] = "J_Wrist_LE";
  1903.     }
  1904.     if ( !isDefined( self.a.gib_ref ) || self.a.gib_ref != "right_arm" )
  1905.     {
  1906.         tagarray[ tagarray.size ] = "J_Elbow_RI";
  1907.         tagarray[ tagarray.size ] = "J_Wrist_RI";
  1908.     }
  1909.     if ( !isDefined( self.a.gib_ref ) || self.a.gib_ref != "no_legs" && self.a.gib_ref != "left_leg" )
  1910.     {
  1911.         tagarray[ tagarray.size ] = "J_Knee_LE";
  1912.         tagarray[ tagarray.size ] = "J_Ankle_LE";
  1913.     }
  1914.     if ( !isDefined( self.a.gib_ref ) || self.a.gib_ref != "no_legs" && self.a.gib_ref != "right_leg" )
  1915.     {
  1916.         tagarray[ tagarray.size ] = "J_Knee_RI";
  1917.         tagarray[ tagarray.size ] = "J_Ankle_RI";
  1918.     }
  1919.     tagarray = array_randomize( tagarray );
  1920.     playfxontag( level._effect[ "character_fire_death_sm" ], self, tagarray[ 0 ] );
  1921. }
  1922.  
  1923. zombie_ragdoll_then_explode( launchvector, attacker )
  1924. {
  1925.     if ( !isDefined( self ) )
  1926.     {
  1927.         return;
  1928.     }
  1929.     self zombie_eye_glow_stop();
  1930.     self setclientfield( "zombie_ragdoll_explode", 1 );
  1931.     self notify( "exploding" );
  1932.     self notify( "end_melee" );
  1933.     self notify( "death" );
  1934.     self.dont_die_on_me = 1;
  1935.     self.exploding = 1;
  1936.     self.a.nodeath = 1;
  1937.     self.dont_throw_gib = 1;
  1938.     self startragdoll();
  1939.     self setplayercollision( 0 );
  1940.     self reset_attack_spot();
  1941.     if ( isDefined( launchvector ) )
  1942.     {
  1943.         self launchragdoll( launchvector );
  1944.     }
  1945.     wait 2,1;
  1946.     if ( isDefined( self ) )
  1947.     {
  1948.         self ghost();
  1949.         self delay_thread( 0,25, ::self_delete );
  1950.     }
  1951. }
  1952.  
  1953. zombie_death_animscript()
  1954. {
  1955.     team = undefined;
  1956.     recalc_zombie_array();
  1957.     if ( isDefined( self._race_team ) )
  1958.     {
  1959.         team = self._race_team;
  1960.     }
  1961.     self reset_attack_spot();
  1962.     if ( self check_zombie_death_animscript_callbacks() )
  1963.     {
  1964.         return 0;
  1965.     }
  1966.     if ( isDefined( level.zombie_death_animscript_override ) )
  1967.     {
  1968.         self [[ level.zombie_death_animscript_override ]]();
  1969.     }
  1970.     if ( self.has_legs && isDefined( self.a.gib_ref ) && self.a.gib_ref == "no_legs" )
  1971.     {
  1972.         self.deathanim = "zm_death";
  1973.     }
  1974.     self.grenadeammo = 0;
  1975.     if ( isDefined( self.nuked ) )
  1976.     {
  1977.         if ( zombie_can_drop_powerups( self ) )
  1978.         {
  1979.             if ( isDefined( self.in_the_ground ) && self.in_the_ground == 1 )
  1980.             {
  1981.                 trace = bullettrace( self.origin + vectorScale( ( 0, 0, 0 ), 100 ), self.origin + vectorScale( ( 0, 0, 0 ), 100 ), 0, undefined );
  1982.                 origin = trace[ "position" ];
  1983.                 level thread zombie_delay_powerup_drop( origin );
  1984.             }
  1985.             else
  1986.             {
  1987.                 trace = groundtrace( self.origin + vectorScale( ( 0, 0, 0 ), 5 ), self.origin + vectorScale( ( 0, 0, 0 ), 300 ), 0, undefined );
  1988.                 origin = trace[ "position" ];
  1989.                 level thread zombie_delay_powerup_drop( self.origin );
  1990.             }
  1991.         }
  1992.     }
  1993.     else
  1994.     {
  1995.         level zombie_death_points( self.origin, self.damagemod, self.damagelocation, self.attacker, self, team );
  1996.     }
  1997.     if ( isDefined( self.attacker ) && isai( self.attacker ) )
  1998.     {
  1999.         self.attacker notify( "killed" );
  2000.     }
  2001.     if ( self.damageweapon == "rottweil72_upgraded_zm" && self.damagemod == "MOD_RIFLE_BULLET" )
  2002.     {
  2003.         self thread dragons_breath_flame_death_fx();
  2004.     }
  2005.     if ( self.damageweapon == "tazer_knuckles_zm" && self.damagemod == "MOD_MELEE" )
  2006.     {
  2007.         self.is_on_fire = 0;
  2008.         self notify( "stop_flame_damage" );
  2009.     }
  2010.     if ( self.damagemod == "MOD_BURNED" )
  2011.     {
  2012.         self thread maps/mp/animscripts/zm_death::flame_death_fx();
  2013.     }
  2014.     if ( self.damagemod == "MOD_GRENADE" || self.damagemod == "MOD_GRENADE_SPLASH" )
  2015.     {
  2016.         level notify( "zombie_grenade_death" );
  2017.     }
  2018.     return 0;
  2019. }
  2020.  
  2021. check_zombie_death_animscript_callbacks()
  2022. {
  2023.     if ( !isDefined( level.zombie_death_animscript_callbacks ) )
  2024.     {
  2025.         return 0;
  2026.     }
  2027.     i = 0;
  2028.     while ( i < level.zombie_death_animscript_callbacks.size )
  2029.     {
  2030.         if ( self [[ level.zombie_death_animscript_callbacks[ i ] ]]() )
  2031.         {
  2032.             return 1;
  2033.         }
  2034.         i++;
  2035.     }
  2036.     return 0;
  2037. }
  2038.  
  2039. register_zombie_death_animscript_callback( func )
  2040. {
  2041.     if ( !isDefined( level.zombie_death_animscript_callbacks ) )
  2042.     {
  2043.         level.zombie_death_animscript_callbacks = [];
  2044.     }
  2045.     level.zombie_death_animscript_callbacks[ level.zombie_death_animscript_callbacks.size ] = func;
  2046. }
  2047.  
  2048. damage_on_fire( player )
  2049. {
  2050.     self endon( "death" );
  2051.     self endon( "stop_flame_damage" );
  2052.     wait 2;
  2053.     while ( isDefined( self.is_on_fire ) && self.is_on_fire )
  2054.     {
  2055.         if ( level.round_number < 6 )
  2056.         {
  2057.             dmg = level.zombie_health * randomfloatrange( 0,2, 0,3 );
  2058.         }
  2059.         else if ( level.round_number < 9 )
  2060.         {
  2061.             dmg = level.zombie_health * randomfloatrange( 0,15, 0,25 );
  2062.         }
  2063.         else if ( level.round_number < 11 )
  2064.         {
  2065.             dmg = level.zombie_health * randomfloatrange( 0,1, 0,2 );
  2066.         }
  2067.         else
  2068.         {
  2069.             dmg = level.zombie_health * randomfloatrange( 0,1, 0,15 );
  2070.         }
  2071.         if ( isDefined( player ) && isalive( player ) )
  2072.         {
  2073.             self dodamage( dmg, self.origin, player );
  2074.         }
  2075.         else
  2076.         {
  2077.             self dodamage( dmg, self.origin, level );
  2078.         }
  2079.         wait randomfloatrange( 1, 3 );
  2080.     }
  2081. }
  2082.  
  2083. player_using_hi_score_weapon( player )
  2084. {
  2085.     weapon = player getcurrentweapon();
  2086.     if ( weapon == "none" || weaponissemiauto( weapon ) )
  2087.     {
  2088.         return 1;
  2089.     }
  2090.     return 0;
  2091. }
  2092.  
  2093. zombie_damage( mod, hit_location, hit_origin, player, amount, team )
  2094. {
  2095.     if ( is_magic_bullet_shield_enabled( self ) )
  2096.     {
  2097.         return;
  2098.     }
  2099.     player.use_weapon_type = mod;
  2100.     if ( isDefined( self.marked_for_death ) )
  2101.     {
  2102.         return;
  2103.     }
  2104.     if ( !isDefined( player ) )
  2105.     {
  2106.         return;
  2107.     }
  2108.     if ( isDefined( hit_origin ) )
  2109.     {
  2110.         self.damagehit_origin = hit_origin;
  2111.     }
  2112.     else
  2113.     {
  2114.         self.damagehit_origin = player getweaponmuzzlepoint();
  2115.     }
  2116.     if ( self check_zombie_damage_callbacks( mod, hit_location, hit_origin, player, amount ) )
  2117.     {
  2118.         return;
  2119.     }
  2120.     else if ( self zombie_flame_damage( mod, player ) )
  2121.     {
  2122.         if ( self zombie_give_flame_damage_points() )
  2123.         {
  2124.             player maps/mp/zombies/_zm_score::player_add_points( "damage", mod, hit_location, self.isdog, team );
  2125.         }
  2126.     }
  2127.     else
  2128.     {
  2129.         if ( player_using_hi_score_weapon( player ) )
  2130.         {
  2131.             damage_type = "damage";
  2132.         }
  2133.         else
  2134.         {
  2135.             damage_type = "damage_light";
  2136.         }
  2137.         if ( isDefined( self.no_damage_points ) && !self.no_damage_points )
  2138.         {
  2139.             player maps/mp/zombies/_zm_score::player_add_points( damage_type, mod, hit_location, self.isdog, team, self.damageweapon );
  2140.         }
  2141.     }
  2142.     if ( isDefined( self.zombie_damage_fx_func ) )
  2143.     {
  2144.         self [[ self.zombie_damage_fx_func ]]( mod, hit_location, hit_origin, player );
  2145.     }
  2146.     modname = remove_mod_from_methodofdeath( mod );
  2147.     if ( is_placeable_mine( self.damageweapon ) )
  2148.     {
  2149.         if ( isDefined( self.zombie_damage_claymore_func ) )
  2150.         {
  2151.             self [[ self.zombie_damage_claymore_func ]]( mod, hit_location, hit_origin, player );
  2152.         }
  2153.         else if ( isDefined( player ) && isalive( player ) )
  2154.         {
  2155.             self dodamage( level.round_number * randomintrange( 100, 200 ), self.origin, player, self, hit_location, mod );
  2156.         }
  2157.         else
  2158.         {
  2159.             self dodamage( level.round_number * randomintrange( 100, 200 ), self.origin, undefined, self, hit_location, mod );
  2160.         }
  2161.     }
  2162.     else if ( mod == "MOD_GRENADE" || mod == "MOD_GRENADE_SPLASH" )
  2163.     {
  2164.         if ( isDefined( player ) && isalive( player ) )
  2165.         {
  2166.             player.grenade_multiattack_count++;
  2167.             player.grenade_multiattack_ent = self;
  2168.             self dodamage( level.round_number + randomintrange( 100, 200 ), self.origin, player, self, hit_location, modname );
  2169.         }
  2170.         else
  2171.         {
  2172.             self dodamage( level.round_number + randomintrange( 100, 200 ), self.origin, undefined, self, hit_location, modname );
  2173.         }
  2174.     }
  2175.     else
  2176.     {
  2177.         if ( mod != "MOD_PROJECTILE" || mod == "MOD_EXPLOSIVE" && mod == "MOD_PROJECTILE_SPLASH" )
  2178.         {
  2179.             if ( isDefined( player ) && isalive( player ) )
  2180.             {
  2181.                 self dodamage( level.round_number * randomintrange( 0, 100 ), self.origin, player, self, hit_location, modname );
  2182.             }
  2183.             else
  2184.             {
  2185.                 self dodamage( level.round_number * randomintrange( 0, 100 ), self.origin, undefined, self, hit_location, modname );
  2186.             }
  2187.         }
  2188.     }
  2189.     if ( isDefined( self.a.gib_ref ) && self.a.gib_ref == "no_legs" && isalive( self ) )
  2190.     {
  2191.         if ( isDefined( player ) )
  2192.         {
  2193.             rand = randomintrange( 0, 100 );
  2194.             if ( rand < 10 )
  2195.             {
  2196.                 player create_and_play_dialog( "general", "crawl_spawn" );
  2197.             }
  2198.         }
  2199.     }
  2200.     else
  2201.     {
  2202.         if ( isDefined( self.a.gib_ref ) || self.a.gib_ref == "right_arm" && self.a.gib_ref == "left_arm" )
  2203.         {
  2204.             if ( self.has_legs && isalive( self ) )
  2205.             {
  2206.                 if ( isDefined( player ) )
  2207.                 {
  2208.                     rand = randomintrange( 0, 100 );
  2209.                     if ( rand < 7 )
  2210.                     {
  2211.                         player create_and_play_dialog( "general", "shoot_arm" );
  2212.                     }
  2213.                 }
  2214.             }
  2215.         }
  2216.     }
  2217.     self thread maps/mp/zombies/_zm_powerups::check_for_instakill( player, mod, hit_location );
  2218. }
  2219.  
  2220. zombie_damage_ads( mod, hit_location, hit_origin, player, amount, team )
  2221. {
  2222.     if ( is_magic_bullet_shield_enabled( self ) )
  2223.     {
  2224.         return;
  2225.     }
  2226.     player.use_weapon_type = mod;
  2227.     if ( !isDefined( player ) )
  2228.     {
  2229.         return;
  2230.     }
  2231.     if ( isDefined( hit_origin ) )
  2232.     {
  2233.         self.damagehit_origin = hit_origin;
  2234.     }
  2235.     else
  2236.     {
  2237.         self.damagehit_origin = player getweaponmuzzlepoint();
  2238.     }
  2239.     if ( self check_zombie_damage_callbacks( mod, hit_location, hit_origin, player, amount ) )
  2240.     {
  2241.         return;
  2242.     }
  2243.     else if ( self zombie_flame_damage( mod, player ) )
  2244.     {
  2245.         if ( self zombie_give_flame_damage_points() )
  2246.         {
  2247.             player maps/mp/zombies/_zm_score::player_add_points( "damage_ads", mod, hit_location, undefined, team );
  2248.         }
  2249.     }
  2250.     else
  2251.     {
  2252.         if ( player_using_hi_score_weapon( player ) )
  2253.         {
  2254.             damage_type = "damage";
  2255.         }
  2256.         else
  2257.         {
  2258.             damage_type = "damage_light";
  2259.         }
  2260.         if ( isDefined( self.no_damage_points ) && !self.no_damage_points )
  2261.         {
  2262.             player maps/mp/zombies/_zm_score::player_add_points( damage_type, mod, hit_location, undefined, team, self.damageweapon );
  2263.         }
  2264.     }
  2265.     self thread maps/mp/zombies/_zm_powerups::check_for_instakill( player, mod, hit_location );
  2266. }
  2267.  
  2268. check_zombie_damage_callbacks( mod, hit_location, hit_origin, player, amount )
  2269. {
  2270.     if ( !isDefined( level.zombie_damage_callbacks ) )
  2271.     {
  2272.         return 0;
  2273.     }
  2274.     i = 0;
  2275.     while ( i < level.zombie_damage_callbacks.size )
  2276.     {
  2277.         if ( self [[ level.zombie_damage_callbacks[ i ] ]]( mod, hit_location, hit_origin, player, amount ) )
  2278.         {
  2279.             return 1;
  2280.         }
  2281.         i++;
  2282.     }
  2283.     return 0;
  2284. }
  2285.  
  2286. register_zombie_damage_callback( func )
  2287. {
  2288.     if ( !isDefined( level.zombie_damage_callbacks ) )
  2289.     {
  2290.         level.zombie_damage_callbacks = [];
  2291.     }
  2292.     level.zombie_damage_callbacks[ level.zombie_damage_callbacks.size ] = func;
  2293. }
  2294.  
  2295. zombie_give_flame_damage_points()
  2296. {
  2297.     if ( getTime() > self.flame_damage_time )
  2298.     {
  2299.         self.flame_damage_time = getTime() + level.zombie_vars[ "zombie_flame_dmg_point_delay" ];
  2300.         return 1;
  2301.     }
  2302.     return 0;
  2303. }
  2304.  
  2305. zombie_flame_damage( mod, player )
  2306. {
  2307.     if ( mod == "MOD_BURNED" )
  2308.     {
  2309.         if ( !isDefined( self.is_on_fire ) || isDefined( self.is_on_fire ) && !self.is_on_fire )
  2310.         {
  2311.             self thread damage_on_fire( player );
  2312.         }
  2313.         do_flame_death = 1;
  2314.         dist = 10000;
  2315.         ai = getaiarray( level.zombie_team );
  2316.         i = 0;
  2317.         while ( i < ai.size )
  2318.         {
  2319.             if ( isDefined( ai[ i ].is_on_fire ) && ai[ i ].is_on_fire )
  2320.             {
  2321.                 if ( distancesquared( ai[ i ].origin, self.origin ) < dist )
  2322.                 {
  2323.                     do_flame_death = 0;
  2324.                     break;
  2325.                 }
  2326.             }
  2327.             else
  2328.             {
  2329.                 i++;
  2330.             }
  2331.         }
  2332.         if ( do_flame_death )
  2333.         {
  2334.             self thread maps/mp/animscripts/zm_death::flame_death_fx();
  2335.         }
  2336.         return 1;
  2337.     }
  2338.     return 0;
  2339. }
  2340.  
  2341. is_weapon_shotgun( sweapon )
  2342. {
  2343.     if ( isDefined( sweapon ) && weaponclass( sweapon ) == "spread" )
  2344.     {
  2345.         return 1;
  2346.     }
  2347.     return 0;
  2348. }
  2349.  
  2350. zombie_death_event( zombie )
  2351. {
  2352.     zombie.marked_for_recycle = 0;
  2353.     force_explode = 0;
  2354.     force_head_gib = 0;
  2355.     zombie waittill( "death", attacker );
  2356.     time_of_death = getTime();
  2357.     if ( isDefined( zombie ) )
  2358.     {
  2359.         zombie stopsounds();
  2360.     }
  2361.     if ( isDefined( zombie ) && isDefined( zombie.marked_for_insta_upgraded_death ) )
  2362.     {
  2363.         force_head_gib = 1;
  2364.     }
  2365.     if ( !isDefined( zombie.damagehit_origin ) && isDefined( attacker ) )
  2366.     {
  2367.         zombie.damagehit_origin = attacker getweaponmuzzlepoint();
  2368.     }
  2369.     if ( isDefined( attacker ) && isplayer( attacker ) )
  2370.     {
  2371.         if ( isDefined( level.pers_upgrade_carpenter ) && level.pers_upgrade_carpenter )
  2372.         {
  2373.             maps/mp/zombies/_zm_pers_upgrades::pers_zombie_death_location_check( attacker, zombie.origin );
  2374.         }
  2375.         if ( isDefined( level.pers_upgrade_sniper ) && level.pers_upgrade_sniper )
  2376.         {
  2377.             attacker pers_upgrade_sniper_kill_check( zombie, attacker );
  2378.         }
  2379.         if ( isDefined( zombie ) && isDefined( zombie.damagelocation ) )
  2380.         {
  2381.             if ( is_headshot( zombie.damageweapon, zombie.damagelocation, zombie.damagemod ) )
  2382.             {
  2383.                 attacker.headshots++;
  2384.                 attacker maps/mp/zombies/_zm_stats::increment_client_stat( "headshots" );
  2385.                 attacker addweaponstat( zombie.damageweapon, "headshots", 1 );
  2386.                 attacker maps/mp/zombies/_zm_stats::increment_player_stat( "headshots" );
  2387.                 if ( is_classic() )
  2388.                 {
  2389.                     attacker maps/mp/zombies/_zm_pers_upgrades_functions::pers_check_for_pers_headshot( time_of_death, zombie );
  2390.                 }
  2391.             }
  2392.             else
  2393.             {
  2394.                 attacker notify( "zombie_death_no_headshot" );
  2395.             }
  2396.         }
  2397.         if ( isDefined( zombie ) && isDefined( zombie.damagemod ) && zombie.damagemod == "MOD_MELEE" )
  2398.         {
  2399.             attacker maps/mp/zombies/_zm_stats::increment_client_stat( "melee_kills" );
  2400.             attacker maps/mp/zombies/_zm_stats::increment_player_stat( "melee_kills" );
  2401.             attacker notify( "melee_kill" );
  2402.             if ( attacker maps/mp/zombies/_zm_pers_upgrades::is_insta_kill_upgraded_and_active() )
  2403.             {
  2404.                 force_explode = 1;
  2405.             }
  2406.         }
  2407.         attacker maps/mp/zombies/_zm::add_rampage_bookmark_kill_time();
  2408.         attacker.kills++;
  2409.         attacker maps/mp/zombies/_zm_stats::increment_client_stat( "kills" );
  2410.         attacker maps/mp/zombies/_zm_stats::increment_player_stat( "kills" );
  2411.         if ( isDefined( level.pers_upgrade_pistol_points ) && level.pers_upgrade_pistol_points )
  2412.         {
  2413.             attacker maps/mp/zombies/_zm_pers_upgrades_functions::pers_upgrade_pistol_points_kill();
  2414.         }
  2415.         dmgweapon = zombie.damageweapon;
  2416.         if ( is_alt_weapon( dmgweapon ) )
  2417.         {
  2418.             dmgweapon = weaponaltweaponname( dmgweapon );
  2419.         }
  2420.         attacker addweaponstat( dmgweapon, "kills", 1 );
  2421.         if ( attacker maps/mp/zombies/_zm_pers_upgrades_functions::pers_mulit_kill_headshot_active() || force_head_gib )
  2422.         {
  2423.             zombie maps/mp/zombies/_zm_spawner::zombie_head_gib();
  2424.         }
  2425.         if ( isDefined( level.pers_upgrade_nube ) && level.pers_upgrade_nube )
  2426.         {
  2427.             attacker notify( "pers_player_zombie_kill" );
  2428.         }
  2429.     }
  2430.     zombie_death_achievement_sliquifier_check( attacker, zombie );
  2431.     recalc_zombie_array();
  2432.     if ( !isDefined( zombie ) )
  2433.     {
  2434.         return;
  2435.     }
  2436.     level.global_zombies_killed++;
  2437.     if ( isDefined( zombie.marked_for_death ) && !isDefined( zombie.nuked ) )
  2438.     {
  2439.         level.zombie_trap_killed_count++;
  2440.     }
  2441.     zombie check_zombie_death_event_callbacks();
  2442.     name = zombie.animname;
  2443.     if ( isDefined( zombie.sndname ) )
  2444.     {
  2445.         name = zombie.sndname;
  2446.     }
  2447.     zombie thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( "death", name );
  2448.     zombie thread zombie_eye_glow_stop();
  2449.     if ( isDefined( zombie.damageweapon ) && is_weapon_shotgun( zombie.damageweapon ) && !maps/mp/zombies/_zm_weapons::is_weapon_upgraded( zombie.damageweapon ) && isDefined( zombie.damageweapon ) || is_placeable_mine( zombie.damageweapon ) && zombie.damagemod != "MOD_GRENADE" && zombie.damagemod != "MOD_GRENADE_SPLASH" || zombie.damagemod == "MOD_EXPLOSIVE" && force_explode == 1 )
  2450.     {
  2451.         splode_dist = 180;
  2452.         if ( isDefined( zombie.damagehit_origin ) && distancesquared( zombie.origin, zombie.damagehit_origin ) < ( splode_dist * splode_dist ) )
  2453.         {
  2454.             tag = "J_SpineLower";
  2455.             if ( isDefined( zombie.isdog ) && zombie.isdog )
  2456.             {
  2457.                 tag = "tag_origin";
  2458.             }
  2459.             if ( isDefined( zombie.is_on_fire ) && !zombie.is_on_fire && isDefined( zombie.guts_explosion ) && !zombie.guts_explosion )
  2460.             {
  2461.                 zombie thread zombie_gut_explosion();
  2462.             }
  2463.         }
  2464.     }
  2465.     if ( zombie.damagemod == "MOD_GRENADE" || zombie.damagemod == "MOD_GRENADE_SPLASH" )
  2466.     {
  2467.         if ( isDefined( attacker ) && isalive( attacker ) )
  2468.         {
  2469.             attacker.grenade_multiattack_count++;
  2470.             attacker.grenade_multiattack_ent = zombie;
  2471.         }
  2472.     }
  2473.     if ( isDefined( zombie.has_been_damaged_by_player ) && !zombie.has_been_damaged_by_player && isDefined( zombie.marked_for_recycle ) && zombie.marked_for_recycle )
  2474.     {
  2475.         level.zombie_total++;
  2476.         level.zombie_total_subtract++;
  2477.     }
  2478.     else
  2479.     {
  2480.         if ( isDefined( zombie.attacker ) && isplayer( zombie.attacker ) )
  2481.         {
  2482.             level.zombie_player_killed_count++;
  2483.             if ( isDefined( zombie.sound_damage_player ) && zombie.sound_damage_player == zombie.attacker )
  2484.             {
  2485.                 chance = get_response_chance( "damage" );
  2486.                 if ( chance != 0 )
  2487.                 {
  2488.                     if ( chance > randomintrange( 1, 100 ) )
  2489.                     {
  2490.                         zombie.attacker maps/mp/zombies/_zm_audio::create_and_play_dialog( "kill", "damage" );
  2491.                     }
  2492.                 }
  2493.                 else
  2494.                 {
  2495.                     zombie.attacker maps/mp/zombies/_zm_audio::create_and_play_dialog( "kill", "damage" );
  2496.                 }
  2497.             }
  2498.             zombie.attacker notify( "zom_kill" );
  2499.             damageloc = zombie.damagelocation;
  2500.             damagemod = zombie.damagemod;
  2501.             attacker = zombie.attacker;
  2502.             weapon = zombie.damageweapon;
  2503.             bbprint( "zombie_kills", "round %d zombietype %s damagetype %s damagelocation %s playername %s playerweapon %s playerx %f playery %f playerz %f zombiex %f zombiey %f zombiez %f", level.round_number, zombie.animname, damagemod, damageloc, attacker.name, weapon, attacker.origin, zombie.origin );
  2504.         }
  2505.         else
  2506.         {
  2507.             if ( zombie.ignoreall && isDefined( zombie.marked_for_death ) && !zombie.marked_for_death )
  2508.             {
  2509.                 level.zombies_timeout_spawn++;
  2510.             }
  2511.         }
  2512.     }
  2513.     level notify( "zom_kill" );
  2514.     level.total_zombies_killed++;
  2515. }
  2516.  
  2517. zombie_gut_explosion()
  2518. {
  2519.     self.guts_explosion = 1;
  2520.     if ( is_mature() )
  2521.     {
  2522.         self setclientfield( "zombie_gut_explosion", 1 );
  2523.     }
  2524.     if ( isDefined( self.isdog ) && !self.isdog )
  2525.     {
  2526.         wait 0,1;
  2527.     }
  2528.     if ( isDefined( self ) )
  2529.     {
  2530.         self ghost();
  2531.     }
  2532. }
  2533.  
  2534. zombie_death_achievement_sliquifier_check( e_player, e_zombie )
  2535. {
  2536.     if ( !isplayer( e_player ) )
  2537.     {
  2538.         return;
  2539.     }
  2540.     if ( isDefined( e_zombie ) )
  2541.     {
  2542.         if ( isDefined( e_zombie.damageweapon ) && e_zombie.damageweapon == "slipgun_zm" )
  2543.         {
  2544.             if ( !isDefined( e_player.num_sliquifier_kills ) )
  2545.             {
  2546.                 e_player.num_sliquifier_kills = 0;
  2547.             }
  2548.             e_player.num_sliquifier_kills++;
  2549.             e_player notify( "sliquifier_kill" );
  2550.         }
  2551.     }
  2552. }
  2553.  
  2554. check_zombie_death_event_callbacks()
  2555. {
  2556.     if ( !isDefined( level.zombie_death_event_callbacks ) )
  2557.     {
  2558.         return;
  2559.     }
  2560.     i = 0;
  2561.     while ( i < level.zombie_death_event_callbacks.size )
  2562.     {
  2563.         self [[ level.zombie_death_event_callbacks[ i ] ]]();
  2564.         i++;
  2565.     }
  2566. }
  2567.  
  2568. register_zombie_death_event_callback( func )
  2569. {
  2570.     if ( !isDefined( level.zombie_death_event_callbacks ) )
  2571.     {
  2572.         level.zombie_death_event_callbacks = [];
  2573.     }
  2574.     level.zombie_death_event_callbacks[ level.zombie_death_event_callbacks.size ] = func;
  2575. }
  2576.  
  2577. deregister_zombie_death_event_callback( func )
  2578. {
  2579.     if ( isDefined( level.zombie_death_event_callbacks ) )
  2580.     {
  2581.         arrayremovevalue( level.zombie_death_event_callbacks, func );
  2582.     }
  2583. }
  2584.  
  2585. zombie_setup_attack_properties()
  2586. {
  2587.     self zombie_history( "zombie_setup_attack_properties()" );
  2588.     self.ignoreall = 0;
  2589.     self.pathenemyfightdist = 64;
  2590.     self.meleeattackdist = 64;
  2591.     self.maxsightdistsqrd = 16384;
  2592.     self.disablearrivals = 1;
  2593.     self.disableexits = 1;
  2594. }
  2595.  
  2596. attractors_generated_listener()
  2597. {
  2598.     self endon( "death" );
  2599.     level endon( "intermission" );
  2600.     self endon( "stop_find_flesh" );
  2601.     self endon( "path_timer_done" );
  2602.     level waittill( "attractor_positions_generated" );
  2603.     self.zombie_path_timer = 0;
  2604. }
  2605.  
  2606. zombie_pathing()
  2607. {
  2608.     self endon( "death" );
  2609.     self endon( "zombie_acquire_enemy" );
  2610.     level endon( "intermission" );
  2611. /#
  2612.     if ( !isDefined( self.favoriteenemy ) )
  2613.     {
  2614.         assert( isDefined( self.enemyoverride ) );
  2615.     }
  2616. #/
  2617.     self._skip_pathing_first_delay = 1;
  2618.     self thread zombie_follow_enemy();
  2619.     self waittill( "bad_path" );
  2620.     level.zombie_pathing_failed++;
  2621.     if ( isDefined( self.enemyoverride ) )
  2622.     {
  2623.         debug_print( "Zombie couldn't path to point of interest at origin: " + self.enemyoverride[ 0 ] + " Falling back to breadcrumb system" );
  2624.         if ( isDefined( self.enemyoverride[ 1 ] ) )
  2625.         {
  2626.             self.enemyoverride = self.enemyoverride[ 1 ] invalidate_attractor_pos( self.enemyoverride, self );
  2627.             self.zombie_path_timer = 0;
  2628.             return;
  2629.         }
  2630.     }
  2631.     else if ( isDefined( self.favoriteenemy ) )
  2632.     {
  2633.         debug_print( "Zombie couldn't path to player at origin: " + self.favoriteenemy.origin + " Falling back to breadcrumb system" );
  2634.     }
  2635.     else
  2636.     {
  2637.         debug_print( "Zombie couldn't path to a player ( the other 'prefered' player might be ignored for encounters mode ). Falling back to breadcrumb system" );
  2638.     }
  2639.     if ( !isDefined( self.favoriteenemy ) )
  2640.     {
  2641.         self.zombie_path_timer = 0;
  2642.         return;
  2643.     }
  2644.     else
  2645.     {
  2646.         self.favoriteenemy endon( "disconnect" );
  2647.     }
  2648.     players = get_players();
  2649.     valid_player_num = 0;
  2650.     i = 0;
  2651.     while ( i < players.size )
  2652.     {
  2653.         if ( is_player_valid( players[ i ], 1 ) )
  2654.         {
  2655.             valid_player_num += 1;
  2656.         }
  2657.         i++;
  2658.     }
  2659.     if ( players.size > 1 )
  2660.     {
  2661.         if ( isDefined( level._should_skip_ignore_player_logic ) && [[ level._should_skip_ignore_player_logic ]]() )
  2662.         {
  2663.             self.zombie_path_timer = 0;
  2664.             return;
  2665.         }
  2666.         if ( array_check_for_dupes( self.ignore_player, self.favoriteenemy ) )
  2667.         {
  2668.             self.ignore_player[ self.ignore_player.size ] = self.favoriteenemy;
  2669.         }
  2670.         if ( self.ignore_player.size < valid_player_num )
  2671.         {
  2672.             self.zombie_path_timer = 0;
  2673.             return;
  2674.         }
  2675.     }
  2676.     crumb_list = self.favoriteenemy.zombie_breadcrumbs;
  2677.     bad_crumbs = [];
  2678.     while ( 1 )
  2679.     {
  2680.         if ( !is_player_valid( self.favoriteenemy, 1 ) )
  2681.         {
  2682.             self.zombie_path_timer = 0;
  2683.             return;
  2684.         }
  2685.         goal = zombie_pathing_get_breadcrumb( self.favoriteenemy.origin, crumb_list, bad_crumbs, randomint( 100 ) < 20 );
  2686.         if ( !isDefined( goal ) )
  2687.         {
  2688.             debug_print( "Zombie exhausted breadcrumb search" );
  2689.             level.zombie_breadcrumb_failed++;
  2690.             goal = self.favoriteenemy.spectator_respawn.origin;
  2691.         }
  2692.         debug_print( "Setting current breadcrumb to " + goal );
  2693.         self.zombie_path_timer += 100;
  2694.         self setgoalpos( goal );
  2695.         self waittill( "bad_path" );
  2696.         debug_print( "Zombie couldn't path to breadcrumb at " + goal + " Finding next breadcrumb" );
  2697.         i = 0;
  2698.         while ( i < crumb_list.size )
  2699.         {
  2700.             if ( goal == crumb_list[ i ] )
  2701.             {
  2702.                 bad_crumbs[ bad_crumbs.size ] = i;
  2703.                 break;
  2704.             }
  2705.             else
  2706.             {
  2707.                 i++;
  2708.             }
  2709.         }
  2710.     }
  2711. }
  2712.  
  2713. zombie_pathing_get_breadcrumb( origin, breadcrumbs, bad_crumbs, pick_random )
  2714. {
  2715. /#
  2716.     assert( isDefined( origin ) );
  2717. #/
  2718. /#
  2719.     assert( isDefined( breadcrumbs ) );
  2720. #/
  2721. /#
  2722.     assert( isarray( breadcrumbs ) );
  2723. #/
  2724. /#
  2725.     if ( pick_random )
  2726.     {
  2727.         debug_print( "Finding random breadcrumb" );
  2728. #/
  2729.     }
  2730.     i = 0;
  2731.     while ( i < breadcrumbs.size )
  2732.     {
  2733.         if ( pick_random )
  2734.         {
  2735.             crumb_index = randomint( breadcrumbs.size );
  2736.         }
  2737.         else
  2738.         {
  2739.             crumb_index = i;
  2740.         }
  2741.         if ( crumb_is_bad( crumb_index, bad_crumbs ) )
  2742.         {
  2743.             i++;
  2744.             continue;
  2745.         }
  2746.         else
  2747.         {
  2748.             return breadcrumbs[ crumb_index ];
  2749.         }
  2750.         i++;
  2751.     }
  2752.     return undefined;
  2753. }
  2754.  
  2755. crumb_is_bad( crumb, bad_crumbs )
  2756. {
  2757.     i = 0;
  2758.     while ( i < bad_crumbs.size )
  2759.     {
  2760.         if ( bad_crumbs[ i ] == crumb )
  2761.         {
  2762.             return 1;
  2763.         }
  2764.         i++;
  2765.     }
  2766.     return 0;
  2767. }
  2768.  
  2769. jitter_enemies_bad_breadcrumbs( start_crumb )
  2770. {
  2771.     trace_distance = 35;
  2772.     jitter_distance = 2;
  2773.     index = start_crumb;
  2774.     while ( isDefined( self.favoriteenemy.zombie_breadcrumbs[ index + 1 ] ) )
  2775.     {
  2776.         current_crumb = self.favoriteenemy.zombie_breadcrumbs[ index ];
  2777.         next_crumb = self.favoriteenemy.zombie_breadcrumbs[ index + 1 ];
  2778.         angles = vectorToAngle( current_crumb - next_crumb );
  2779.         right = anglesToRight( angles );
  2780.         left = anglesToRight( angles + vectorScale( ( 0, 0, 0 ), 180 ) );
  2781.         dist_pos = current_crumb + vectorScale( right, trace_distance );
  2782.         trace = bullettrace( current_crumb, dist_pos, 1, undefined );
  2783.         vector = trace[ "position" ];
  2784.         while ( distance( vector, current_crumb ) < 17 )
  2785.         {
  2786.             self.favoriteenemy.zombie_breadcrumbs[ index ] = current_crumb + vectorScale( left, jitter_distance );
  2787.         }
  2788.         dist_pos = current_crumb + vectorScale( left, trace_distance );
  2789.         trace = bullettrace( current_crumb, dist_pos, 1, undefined );
  2790.         vector = trace[ "position" ];
  2791.         while ( distance( vector, current_crumb ) < 17 )
  2792.         {
  2793.             self.favoriteenemy.zombie_breadcrumbs[ index ] = current_crumb + vectorScale( right, jitter_distance );
  2794.         }
  2795.         index++;
  2796.     }
  2797. }
  2798.  
  2799. zombie_repath_notifier()
  2800. {
  2801.     note = 0;
  2802.     notes = [];
  2803.     i = 0;
  2804.     while ( i < 4 )
  2805.     {
  2806.         notes[ notes.size ] = "zombie_repath_notify_" + i;
  2807.         i++;
  2808.     }
  2809.     while ( 1 )
  2810.     {
  2811.         level notify( notes[ note ] );
  2812.         note = ( note + 1 ) % 4;
  2813.         wait 0,05;
  2814.     }
  2815. }
  2816.  
  2817. zombie_follow_enemy()
  2818. {
  2819.     self endon( "death" );
  2820.     self endon( "zombie_acquire_enemy" );
  2821.     self endon( "bad_path" );
  2822.     level endon( "intermission" );
  2823.     if ( !isDefined( level.repathnotifierstarted ) )
  2824.     {
  2825.         level.repathnotifierstarted = 1;
  2826.         level thread zombie_repath_notifier();
  2827.     }
  2828.     if ( !isDefined( self.zombie_repath_notify ) )
  2829.     {
  2830.         self.zombie_repath_notify = "zombie_repath_notify_" + ( self getentitynumber() % 4 );
  2831.     }
  2832.     while ( 1 )
  2833.     {
  2834.         if ( !isDefined( self._skip_pathing_first_delay ) )
  2835.         {
  2836.             level waittill( self.zombie_repath_notify );
  2837.         }
  2838.         else
  2839.         {
  2840.             self._skip_pathing_first_delay = undefined;
  2841.         }
  2842.         if ( isDefined( self.ignore_enemyoverride ) && !self.ignore_enemyoverride && isDefined( self.enemyoverride ) && isDefined( self.enemyoverride[ 1 ] ) )
  2843.         {
  2844.             if ( distancesquared( self.origin, self.enemyoverride[ 0 ] ) > 1 )
  2845.             {
  2846.                 self orientmode( "face motion" );
  2847.             }
  2848.             else
  2849.             {
  2850.                 self orientmode( "face point", self.enemyoverride[ 1 ].origin );
  2851.             }
  2852.             self.ignoreall = 1;
  2853.             goalpos = self.enemyoverride[ 0 ];
  2854.             if ( isDefined( level.adjust_enemyoverride_func ) )
  2855.             {
  2856.                 goalpos = self [[ level.adjust_enemyoverride_func ]]();
  2857.             }
  2858.             self setgoalpos( goalpos );
  2859.         }
  2860.         else
  2861.         {
  2862.             if ( isDefined( self.favoriteenemy ) )
  2863.             {
  2864.                 self.ignoreall = 0;
  2865.                 self orientmode( "face default" );
  2866.                 goalpos = self.favoriteenemy.origin;
  2867.                 if ( isDefined( level.enemy_location_override_func ) )
  2868.                 {
  2869.                     goalpos = [[ level.enemy_location_override_func ]]( self, self.favoriteenemy );
  2870.                 }
  2871.                 self setgoalpos( goalpos );
  2872.                 if ( !isDefined( level.ignore_path_delays ) )
  2873.                 {
  2874.                     distsq = distancesquared( self.origin, self.favoriteenemy.origin );
  2875.                     if ( distsq > 10240000 )
  2876.                     {
  2877.                         wait ( 2 + randomfloat( 1 ) );
  2878.                         break;
  2879.                     }
  2880.                     else if ( distsq > 4840000 )
  2881.                     {
  2882.                         wait ( 1 + randomfloat( 0,5 ) );
  2883.                         break;
  2884.                     }
  2885.                     else
  2886.                     {
  2887.                         if ( distsq > 1440000 )
  2888.                         {
  2889.                             wait ( 0,5 + randomfloat( 0,5 ) );
  2890.                         }
  2891.                     }
  2892.                 }
  2893.             }
  2894.         }
  2895.         if ( isDefined( level.inaccesible_player_func ) )
  2896.         {
  2897.             self [[ level.inaccessible_player_func ]]();
  2898.         }
  2899.     }
  2900. }
  2901.  
  2902. zombie_eye_glow()
  2903. {
  2904.     if ( !isDefined( self ) )
  2905.     {
  2906.         return;
  2907.     }
  2908.     if ( !isDefined( self.no_eye_glow ) || !self.no_eye_glow )
  2909.     {
  2910.         self setclientfield( "zombie_has_eyes", 1 );
  2911.     }
  2912. }
  2913.  
  2914. zombie_eye_glow_stop()
  2915. {
  2916.     if ( !isDefined( self ) )
  2917.     {
  2918.         return;
  2919.     }
  2920.     if ( !isDefined( self.no_eye_glow ) || !self.no_eye_glow )
  2921.     {
  2922.         self setclientfield( "zombie_has_eyes", 0 );
  2923.     }
  2924. }
  2925.  
  2926. zombie_history( msg )
  2927. {
  2928. /#
  2929.     if ( !isDefined( self.zombie_history ) || self.zombie_history.size > 32 )
  2930.     {
  2931.         self.zombie_history = [];
  2932.     }
  2933.     self.zombie_history[ self.zombie_history.size ] = msg;
  2934. #/
  2935. }
  2936.  
  2937. do_zombie_spawn()
  2938. {
  2939.     self endon( "death" );
  2940.     spots = [];
  2941.     if ( isDefined( self._rise_spot ) )
  2942.     {
  2943.         spot = self._rise_spot;
  2944.         self thread do_zombie_rise( spot );
  2945.         return;
  2946.     }
  2947.     while ( isDefined( level.zombie_spawn_locations ) )
  2948.     {
  2949.         i = 0;
  2950.         while ( i < level.zombie_spawn_locations.size )
  2951.         {
  2952.             if ( isDefined( level.use_multiple_spawns ) && level.use_multiple_spawns && isDefined( self.script_int ) )
  2953.             {
  2954.                 if ( isDefined( level.spawner_int ) && self.script_int != level.spawner_int && !isDefined( level.zombie_spawn_locations[ i ].script_int ) && !isDefined( level.zones[ level.zombie_spawn_locations[ i ].zone_name ].script_int ) )
  2955.                 {
  2956.                     i++;
  2957.                     continue;
  2958.                 }
  2959.                 else
  2960.                 {
  2961.                     if ( isDefined( level.zombie_spawn_locations[ i ].script_int ) && level.zombie_spawn_locations[ i ].script_int != self.script_int )
  2962.                     {
  2963.                         i++;
  2964.                         continue;
  2965.                     }
  2966.                     else if ( isDefined( level.zones[ level.zombie_spawn_locations[ i ].zone_name ].script_int ) && level.zones[ level.zombie_spawn_locations[ i ].zone_name ].script_int != self.script_int )
  2967.                     {
  2968.                         i++;
  2969.                         continue;
  2970.                     }
  2971.                 }
  2972.                 else
  2973.                 {
  2974.                     spots[ spots.size ] = level.zombie_spawn_locations[ i ];
  2975.                 }
  2976.             }
  2977.             i++;
  2978.         }
  2979.     }
  2980. /#
  2981.     if ( getDvarInt( #"A8C231AA" ) )
  2982.     {
  2983.         if ( isDefined( level.zombie_spawn_locations ) )
  2984.         {
  2985.             player = get_players()[ 0 ];
  2986.             spots = [];
  2987.             i = 0;
  2988.             while ( i < level.zombie_spawn_locations.size )
  2989.             {
  2990.                 player_vec = vectornormalize( anglesToForward( player.angles ) );
  2991.                 player_spawn = vectornormalize( level.zombie_spawn_locations[ i ].origin - player.origin );
  2992.                 dot = vectordot( player_vec, player_spawn );
  2993.                 if ( dot > 0,707 )
  2994.                 {
  2995.                     spots[ spots.size ] = level.zombie_spawn_locations[ i ];
  2996.                     debugstar( level.zombie_spawn_locations[ i ].origin, 1000, ( 0, 0, 0 ) );
  2997.                 }
  2998.                 i++;
  2999.             }
  3000.             if ( spots.size <= 0 )
  3001.             {
  3002.                 spots[ spots.size ] = level.zombie_spawn_locations[ 0 ];
  3003.                 iprintln( "no spawner in view" );
  3004. #/
  3005.             }
  3006.         }
  3007.     }
  3008. /#
  3009.     assert( spots.size > 0, "No spawn locations found" );
  3010. #/
  3011.     spot = random( spots );
  3012.     self.spawn_point = spot;
  3013. /#
  3014.     if ( isDefined( level.toggle_show_spawn_locations ) && level.toggle_show_spawn_locations )
  3015.     {
  3016.         debugstar( spot.origin, getDvarInt( #"BB9101B2" ), ( 0, 0, 0 ) );
  3017.         host_player = gethostplayer();
  3018.         distance = distance( spot.origin, host_player.origin );
  3019.         iprintln( "Distance to player: " + ( distance / 12 ) + "feet" );
  3020. #/
  3021.     }
  3022.     if ( isDefined( spot.target ) )
  3023.     {
  3024.         self.target = spot.target;
  3025.     }
  3026.     if ( isDefined( spot.zone_name ) )
  3027.     {
  3028.         self.zone_name = spot.zone_name;
  3029.     }
  3030.     if ( isDefined( spot.script_parameters ) )
  3031.     {
  3032.         self.script_parameters = spot.script_parameters;
  3033.     }
  3034.     tokens = strtok( spot.script_noteworthy, " " );
  3035.     _a3588 = tokens;
  3036.     index = getFirstArrayKey( _a3588 );
  3037.     while ( isDefined( index ) )
  3038.     {
  3039.         token = _a3588[ index ];
  3040.         if ( isDefined( self.spawn_point_override ) )
  3041.         {
  3042.             spot = self.spawn_point_override;
  3043.             token = spot.script_noteworthy;
  3044.         }
  3045.         if ( token == "custom_spawner_entry" )
  3046.         {
  3047.             next_token = index + 1;
  3048.             if ( isDefined( tokens[ next_token ] ) )
  3049.             {
  3050.                 str_spawn_entry = tokens[ next_token ];
  3051.                 if ( isDefined( level.custom_spawner_entry ) && isDefined( level.custom_spawner_entry[ str_spawn_entry ] ) )
  3052.                 {
  3053.                     self thread [[ level.custom_spawner_entry[ str_spawn_entry ] ]]( spot );
  3054.                 }
  3055.             }
  3056.         }
  3057.         else
  3058.         {
  3059.             if ( token == "riser_location" )
  3060.             {
  3061.                 self thread do_zombie_rise( spot );
  3062.                 break;
  3063.             }
  3064.             else if ( token == "faller_location" )
  3065.             {
  3066.                 self thread maps/mp/zombies/_zm_ai_faller::do_zombie_fall( spot );
  3067.                 break;
  3068.             }
  3069.             else if ( token == "dog_location" )
  3070.             {
  3071.                 break;
  3072.             }
  3073.             else if ( token == "screecher_location" )
  3074.             {
  3075.                 break;
  3076.             }
  3077.             else if ( token == "leaper_location" )
  3078.             {
  3079.                 break;
  3080.             }
  3081.             else if ( isDefined( self.anchor ) )
  3082.             {
  3083.                 return;
  3084.             }
  3085.             self.anchor = spawn( "script_origin", self.origin );
  3086.             self.anchor.angles = self.angles;
  3087.             self linkto( self.anchor );
  3088.             if ( !isDefined( spot.angles ) )
  3089.             {
  3090.                 spot.angles = ( 0, 0, 0 );
  3091.             }
  3092.             self ghost();
  3093.             self.anchor moveto( spot.origin, 0,05 );
  3094.             self.anchor waittill( "movedone" );
  3095.             target_org = get_desired_origin();
  3096.             if ( isDefined( target_org ) )
  3097.             {
  3098.                 anim_ang = vectorToAngle( target_org - self.origin );
  3099.                 self.anchor rotateto( ( 0, anim_ang[ 1 ], 0 ), 0,05 );
  3100.                 self.anchor waittill( "rotatedone" );
  3101.             }
  3102.             if ( isDefined( level.zombie_spawn_fx ) )
  3103.             {
  3104.                 playfx( level.zombie_spawn_fx, spot.origin );
  3105.             }
  3106.             self unlink();
  3107.             if ( isDefined( self.anchor ) )
  3108.             {
  3109.                 self.anchor delete();
  3110.             }
  3111.             self show();
  3112.             self notify( "risen" );
  3113.         }
  3114.         index = getNextArrayKey( _a3588, index );
  3115.     }
  3116. }
  3117.  
  3118. do_zombie_rise( spot )
  3119. {
  3120.     self endon( "death" );
  3121.     self.in_the_ground = 1;
  3122.     if ( isDefined( self.anchor ) )
  3123.     {
  3124.         self.anchor delete();
  3125.     }
  3126.     self.anchor = spawn( "script_origin", self.origin );
  3127.     self.anchor.angles = self.angles;
  3128.     self linkto( self.anchor );
  3129.     if ( !isDefined( spot.angles ) )
  3130.     {
  3131.         spot.angles = ( 0, 0, 0 );
  3132.     }
  3133.     anim_org = spot.origin;
  3134.     anim_ang = spot.angles;
  3135.     anim_org += ( 0, 0, 0 );
  3136.     self ghost();
  3137.     self.anchor moveto( anim_org, 0,05 );
  3138.     self.anchor waittill( "movedone" );
  3139.     target_org = get_desired_origin();
  3140.     if ( isDefined( target_org ) )
  3141.     {
  3142.         anim_ang = vectorToAngle( target_org - self.origin );
  3143.         self.anchor rotateto( ( 0, anim_ang[ 1 ], 0 ), 0,05 );
  3144.         self.anchor waittill( "rotatedone" );
  3145.     }
  3146.     self unlink();
  3147.     if ( isDefined( self.anchor ) )
  3148.     {
  3149.         self.anchor delete();
  3150.     }
  3151.     self thread hide_pop();
  3152.     level thread zombie_rise_death( self, spot );
  3153.     spot thread zombie_rise_fx( self );
  3154.     substate = 0;
  3155.     if ( self.zombie_move_speed == "walk" )
  3156.     {
  3157.         substate = randomint( 2 );
  3158.     }
  3159.     else if ( self.zombie_move_speed == "run" )
  3160.     {
  3161.         substate = 2;
  3162.     }
  3163.     else
  3164.     {
  3165.         if ( self.zombie_move_speed == "sprint" )
  3166.         {
  3167.             substate = 3;
  3168.         }
  3169.     }
  3170.     self orientmode( "face default" );
  3171.     self animscripted( self.origin, spot.angles, "zm_rise", substate );
  3172.     self maps/mp/animscripts/zm_shared::donotetracks( "rise_anim", ::handle_rise_notetracks, spot );
  3173.     self notify( "rise_anim_finished" );
  3174.     spot notify( "stop_zombie_rise_fx" );
  3175.     self.in_the_ground = 0;
  3176.     self notify( "risen" );
  3177. }
  3178.  
  3179. hide_pop()
  3180. {
  3181.     self endon( "death" );
  3182.     wait 0,5;
  3183.     if ( isDefined( self ) )
  3184.     {
  3185.         self show();
  3186.         wait_network_frame();
  3187.         if ( isDefined( self ) )
  3188.         {
  3189.             self.create_eyes = 1;
  3190.         }
  3191.     }
  3192. }
  3193.  
  3194. handle_rise_notetracks( note, spot )
  3195. {
  3196.     if ( note == "deathout" || note == "deathhigh" )
  3197.     {
  3198.         self.zombie_rise_death_out = 1;
  3199.         self notify( "zombie_rise_death_out" );
  3200.         wait 2;
  3201.         spot notify( "stop_zombie_rise_fx" );
  3202.     }
  3203. }
  3204.  
  3205. zombie_rise_death( zombie, spot )
  3206. {
  3207.     zombie.zombie_rise_death_out = 0;
  3208.     zombie endon( "rise_anim_finished" );
  3209.     while ( isDefined( zombie ) && isDefined( zombie.health ) && zombie.health > 1 )
  3210.     {
  3211.         zombie waittill( "damage", amount );
  3212.     }
  3213.     spot notify( "stop_zombie_rise_fx" );
  3214.     if ( isDefined( zombie ) )
  3215.     {
  3216.         zombie.deathanim = zombie get_rise_death_anim();
  3217.         zombie stopanimscripted();
  3218.     }
  3219. }
  3220.  
  3221. zombie_rise_fx( zombie )
  3222. {
  3223.     if ( isDefined( level.riser_fx_on_client ) && !level.riser_fx_on_client )
  3224.     {
  3225.         self thread zombie_rise_dust_fx( zombie );
  3226.         self thread zombie_rise_burst_fx( zombie );
  3227.     }
  3228.     else
  3229.     {
  3230.         self thread zombie_rise_burst_fx( zombie );
  3231.     }
  3232.     zombie endon( "death" );
  3233.     self endon( "stop_zombie_rise_fx" );
  3234.     wait 1;
  3235.     if ( zombie.zombie_move_speed != "sprint" )
  3236.     {
  3237.         wait 1;
  3238.     }
  3239. }
  3240.  
  3241. zombie_rise_burst_fx( zombie )
  3242. {
  3243.     self endon( "stop_zombie_rise_fx" );
  3244.     self endon( "rise_anim_finished" );
  3245.     if ( isDefined( self.script_parameters ) && self.script_parameters == "in_water" && isDefined( level._no_water_risers ) && !level._no_water_risers )
  3246.     {
  3247.         zombie setclientfield( "zombie_riser_fx_water", 1 );
  3248.     }
  3249.     else
  3250.     {
  3251.         if ( isDefined( self.script_parameters ) && self.script_parameters == "in_foliage" && isDefined( level._foliage_risers ) && level._foliage_risers )
  3252.         {
  3253.             zombie setclientfield( "zombie_riser_fx_foliage", 1 );
  3254.             return;
  3255.         }
  3256.         else
  3257.         {
  3258.             if ( isDefined( self.script_parameters ) && self.script_parameters == "in_snow" )
  3259.             {
  3260.                 zombie setclientfield( "zombie_riser_fx", 1 );
  3261.                 return;
  3262.             }
  3263.             else
  3264.             {
  3265.                 if ( isDefined( zombie.zone_name ) && isDefined( level.zones[ zombie.zone_name ] ) )
  3266.                 {
  3267.                     low_g_zones = getentarray( zombie.zone_name, "targetname" );
  3268.                     if ( isDefined( low_g_zones[ 0 ].script_string ) && low_g_zones[ 0 ].script_string == "lowgravity" )
  3269.                     {
  3270.                         zombie setclientfield( "zombie_riser_fx_lowg", 1 );
  3271.                     }
  3272.                     else
  3273.                     {
  3274.                         zombie setclientfield( "zombie_riser_fx", 1 );
  3275.                     }
  3276.                     return;
  3277.                 }
  3278.                 else
  3279.                 {
  3280.                     zombie setclientfield( "zombie_riser_fx", 1 );
  3281.                 }
  3282.             }
  3283.         }
  3284.     }
  3285. }
  3286.  
  3287. zombie_rise_dust_fx( zombie )
  3288. {
  3289.     dust_tag = "J_SpineUpper";
  3290.     self endon( "stop_zombie_rise_dust_fx" );
  3291.     self thread stop_zombie_rise_dust_fx( zombie );
  3292.     wait 2;
  3293.     dust_time = 5,5;
  3294.     dust_interval = 0,3;
  3295.     if ( isDefined( self.script_string ) && self.script_string == "in_water" )
  3296.     {
  3297.         t = 0;
  3298.         while ( t < dust_time )
  3299.         {
  3300.             playfxontag( level._effect[ "rise_dust_water" ], zombie, dust_tag );
  3301.             wait dust_interval;
  3302.             t += dust_interval;
  3303.         }
  3304.     }
  3305.     else if ( isDefined( self.script_string ) && self.script_string == "in_snow" )
  3306.     {
  3307.         t = 0;
  3308.         while ( t < dust_time )
  3309.         {
  3310.             playfxontag( level._effect[ "rise_dust_snow" ], zombie, dust_tag );
  3311.             wait dust_interval;
  3312.             t += dust_interval;
  3313.         }
  3314.     }
  3315.     else if ( isDefined( self.script_string ) && self.script_string == "in_foliage" )
  3316.     {
  3317.         t = 0;
  3318.         while ( t < dust_time )
  3319.         {
  3320.             playfxontag( level._effect[ "rise_dust_foliage" ], zombie, dust_tag );
  3321.             wait dust_interval;
  3322.             t += dust_interval;
  3323.         }
  3324.     }
  3325.     else t = 0;
  3326.     while ( t < dust_time )
  3327.     {
  3328.         playfxontag( level._effect[ "rise_dust" ], zombie, dust_tag );
  3329.         wait dust_interval;
  3330.         t += dust_interval;
  3331.     }
  3332. }
  3333.  
  3334. stop_zombie_rise_dust_fx( zombie )
  3335. {
  3336.     zombie waittill( "death" );
  3337.     self notify( "stop_zombie_rise_dust_fx" );
  3338. }
  3339.  
  3340. get_rise_death_anim()
  3341. {
  3342.     if ( self.zombie_rise_death_out )
  3343.     {
  3344.         return "zm_rise_death_out";
  3345.     }
  3346.     self.noragdoll = 1;
  3347.     self.nodeathragdoll = 1;
  3348.     return "zm_rise_death_in";
  3349. }
  3350.  
  3351. zombie_tesla_head_gib()
  3352. {
  3353.     self endon( "death" );
  3354.     if ( self.animname == "quad_zombie" )
  3355.     {
  3356.         return;
  3357.     }
  3358.     if ( randomint( 100 ) < level.zombie_vars[ "tesla_head_gib_chance" ] )
  3359.     {
  3360.         wait randomfloatrange( 0,53, 1 );
  3361.         self zombie_head_gib();
  3362.     }
  3363.     else
  3364.     {
  3365.         network_safe_play_fx_on_tag( "tesla_death_fx", 2, level._effect[ "tesla_shock_eyes" ], self, "J_Eyeball_LE" );
  3366.     }
  3367. }
  3368.  
  3369. play_ambient_zombie_vocals()
  3370. {
  3371.     self endon( "death" );
  3372.     if ( self.animname == "monkey_zombie" || isDefined( self.is_avogadro ) && self.is_avogadro )
  3373.     {
  3374.         return;
  3375.     }
  3376.     while ( 1 )
  3377.     {
  3378.         type = "ambient";
  3379.         float = 2;
  3380.         while ( !isDefined( self.zombie_move_speed ) )
  3381.         {
  3382.             wait 0,5;
  3383.         }
  3384.         switch( self.zombie_move_speed )
  3385.         {
  3386.             case "walk":
  3387.                 type = "ambient";
  3388.                 float = 4;
  3389.                 break;
  3390.             case "run":
  3391.                 type = "sprint";
  3392.                 float = 4;
  3393.                 break;
  3394.             case "sprint":
  3395.                 type = "sprint";
  3396.                 float = 4;
  3397.                 break;
  3398.         }
  3399.         if ( self.animname == "zombie" && !self.has_legs )
  3400.         {
  3401.             type = "crawler";
  3402.         }
  3403.         else
  3404.         {
  3405.             if ( self.animname == "thief_zombie" || self.animname == "leaper_zombie" )
  3406.             {
  3407.                 float = 1,2;
  3408.             }
  3409.         }
  3410.         name = self.animname;
  3411.         if ( isDefined( self.sndname ) )
  3412.         {
  3413.             name = self.sndname;
  3414.         }
  3415.         self thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( type, name );
  3416.         wait randomfloatrange( 1, float );
  3417.     }
  3418. }
  3419.  
  3420. zombie_complete_emerging_into_playable_area()
  3421. {
  3422.     self.completed_emerging_into_playable_area = 1;
  3423.     self notify( "completed_emerging_into_playable_area" );
  3424.     self.no_powerups = 0;
  3425.     self thread zombie_free_cam_allowed();
  3426. }
  3427.  
  3428. zombie_free_cam_allowed()
  3429. {
  3430.     self endon( "death" );
  3431.     wait 1,5;
  3432.     self setfreecameralockonallowed( 1 );
  3433. }
Advertisement
Add Comment
Please, Sign In to add comment