‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
_zm_spawner.gsc
Go to the documentation of this file.
1 #using scripts\codescripts\struct;
2 
3 #using scripts\shared\array_shared;
4 #using scripts\shared\clientfield_shared;
5 #using scripts\shared\demo_shared;
6 #using scripts\shared\flag_shared;
7 #using scripts\shared\laststand_shared;
8 #using scripts\shared\util_shared;
9 
10 #using scripts\shared\ai\zombie_death;
11 #using scripts\shared\ai\zombie_shared;
12 #using scripts\shared\ai\systems\gib;
13 #using scripts\shared\ai\zombie_utility;
14 
15 #using scripts\zm\_util;
16 #using scripts\zm\_zm;
17 #using scripts\zm\_zm_audio;
18 #using scripts\zm\_zm_behavior;
19 #using scripts\zm\_zm_behavior_utility;
20 #using scripts\zm\_zm_blockers;
21 #using scripts\zm\_zm_bgb;
22 #using scripts\zm\_zm_equipment;
23 #using scripts\zm\_zm_laststand;
24 #using scripts\zm\_zm_net;
25 #using scripts\zm\_zm_pers_upgrades;
26 #using scripts\zm\_zm_pers_upgrades_functions;
27 #using scripts\zm\_zm_powerups;
28 #using scripts\zm\_zm_puppet;
29 #using scripts\zm\_zm_score;
30 #using scripts\zm\_zm_stats;
31 #using scripts\zm\_zm_utility;
32 #using scripts\zm\_zm_weapons;
33 
34 #insert scripts\shared\shared.gsh;
35 #insert scripts\shared\version.gsh;
36 #insert scripts\shared\ai\zombie.gsh;
37 #insert scripts\shared\ai\systems\gib.gsh;
38 #insert scripts\zm\_zm.gsh;
39 #insert scripts\zm\_zm_perks.gsh;
40 
41 #namespace zm_spawner;
42 
43 function ‪init()
44 {
45  level._CONTEXTUAL_GRAB_LERP_TIME = .3; // This is the time it takes to move into position for each bar.
46 
47  level.zombie_spawners = GetEntArray( "zombie_spawner", "script_noteworthy" );
48 
49  // This will be an array of archetypes and the saved health of any entities cleaned up so that replacements can have the same health.
50  // We don't want people exploiting cleaned up zombies as a way to generate extra points by continually shooting fresh enemies.
51  level.a_zombie_respawn_health = [];
52 
53  // added functionality to respawn elemental type zombies cleaned up.
54  level.a_zombie_respawn_type = [];
55 
56  if(‪IS_TRUE(level.use_multiple_spawns))
57  {
58  level.zombie_spawn = [];
59  for ( i = 0; i < level.zombie_spawners.size; i++ )
60  {
61  if(IsDefined(level.zombie_spawners[i].script_int))
62  {
63  int = level.zombie_spawners[i].script_int;
64  if ( !IsDefined( level.zombie_spawn[int] ))
65  {
66  level.zombie_spawn[int] = [];
67  }
68  level.zombie_spawn[int][level.zombie_spawn[int].size] = level.zombie_spawners[i];
69  }
70  }
71  }
72 
73  if ( IsDefined( level.ignore_spawner_func ) )
74  {
75  for ( i = 0; i < level.zombie_spawners.size; i++ )
76  {
77  ‪ignore = [[ level.ignore_spawner_func ]]( level.zombie_spawners[i] );
78  if ( ‪ignore )
79  {
80  ArrayRemoveValue(level.zombie_spawners, level.zombie_spawners[i]);
81  }
82  }
83  }
84 
85  if ( !IsDefined( level.attack_player_thru_boards_range ) )
86  {
87  level.attack_player_thru_boards_range = 109.8;
88  }
89 
90  if(isdefined(level._game_module_custom_spawn_init_func))
91  {
92  [[level._game_module_custom_spawn_init_func]]();
93  }
94 }
95 
96 function ‪player_attacks_enemy( player, amount, type, point, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel )
97 {
98  team = undefined;
99  if(isDefined(self._race_team))
100  {
101  team = self._race_team;
102  }
103 
104  if ( ‪IS_TRUE( player.allow_zombie_to_target_ai) || !player ‪util::is_ads() )
105  {
106  // defaults to empty_kill_func, for arcademode
107  [[ level.global_damage_func ]]( type, self.damagelocation, point, player, amount, team, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel );
108  return false;
109  }
110 
111  if ( !‪zm_utility::bullet_attack( type ) )
112  {
113  // defaults to empty_kill_func, for arcademode
114  [[ level.global_damage_func ]]( type, self.damagelocation, point, player, amount, team, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel );
115  return false;
116  }
117 
118  // defaults to empty_kill_func, for arcademode
119  [[ level.global_damage_func_ads ]]( type, self.damagelocation, point, player, amount, team, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel );
120 
121  return true;
122 }
123 
124 
125 function ‪player_attacker( attacker )
126 {
127  if ( IsPlayer(attacker) )
128  {
129  return true;
130  }
131  return false;
132 }
133 
135 {
136  self endon ("death");
137 
138  for ( ;; )
139  {
140  self waittill( "damage", amount, attacker, direction_vec, point, type, tagName, modelName, partName, weapon, dFlags, inflictor, chargeLevel );
141 
142  if ( !isDefined(amount) )
143  {
144  continue;
145  }
146 
147  if ( !isalive( self ) )
148  {
149  return;
150  }
151 
152  if ( !‪player_attacker( attacker ) && !‪IS_TRUE( attacker.allow_zombie_to_target_ai) )
153  {
154  continue;
155  }
156 
157  self.has_been_damaged_by_player = true;
158 
159  self ‪player_attacks_enemy( attacker, amount, type, point, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel );
160  }
161 }
162 
163 
165 {
166  if( IsDefined( ent.targetname ) )
167  {
168  targeters = GetEntArray( ent.targetname, "target" );
169 
170  for( i = 0; i < targeters.size; i++ )
171  {
172  if( targeters[i].targetname == "zombie_door" || targeters[i].targetname == "zombie_debris" )
173  {
174  return true;
175  }
176 
178  if( ‪result )
179  {
180  return true;
181  }
182  }
183  }
184 
185  return false;
186 }
187 
189 {
190  if(!IsDefined(level._zombie_custom_spawn_logic))
191  {
192  level._zombie_custom_spawn_logic = [];
193  }
194 
195  level._zombie_custom_spawn_logic[level._zombie_custom_spawn_logic.size] = func;
196 }
197 
198 
199 // set up zombie walk cycles
200 function ‪zombie_spawn_init( animname_set )
201 {
202  if( !isDefined( animname_set ) )
203  {
204  animname_set = false;
205  }
206 
207  self.targetname = "zombie";
208  self.script_noteworthy = undefined;
209 
210  //A zombie was spawned - recalculate zombie array
212 
213  if( !animname_set )
214  {
215  self.animname = "zombie";
216  }
217 
218  //pre-spawn gamemodule init
219  if(isdefined(‪zm_utility::get_gamemode_var("pre_init_zombie_spawn_func")))
220  {
221  self [[‪zm_utility::get_gamemode_var("pre_init_zombie_spawn_func")]]();
222  }
223 
224  self thread ‪play_ambient_zombie_vocals();
226  self.zmb_vocals_attack = "zmb_vocals_zombie_attack";
227 
228  self.ignoreme = false;
229  self.allowdeath = true; // allows death during animscripted calls
230  self.force_gib = true; // needed to make sure this guy does gibs
231  self.is_zombie = true; // needed for melee.gsc in the animscripts
232  self allowedStances( "stand" );
233 
234  //needed to make sure zombies don't distribute themselves amongst players
235  self.attackerCountThreatScale = 0;
236  //reduce the amount zombies favor their current enemy
237  self.currentEnemyThreatScale = 0;
238  //reduce the amount zombies target recent attackers
239  self.recentAttackerThreatScale = 0;
240  //zombies dont care about whether players are in cover
241  self.coverThreatScale = 0;
242  //make sure zombies have 360 degree visibility
243  self.fovcosine = 0;
244  self.fovcosinebusy = 0;
245 
246  self.zombie_damaged_by_bar_knockdown = false; // This tracks when I can knock down a zombie with a bar
247 
248  self.gibbed = false;
249  self.head_gibbed = false;
250 
251  // might need this so co-op zombie players cant block zombie pathing
252 // self PushPlayer( true );
253 // self.meleeRange = 128;
254 // self.meleeRangeSq = anim.meleeRange * anim.meleeRange;
255 
256  self setPhysParams( 15, 0, 72 );
257  self.goalradius = 32;
258 
259  self.disableArrivals = true;
260  self.disableExits = true;
261  self.grenadeawareness = 0;
262  self.badplaceawareness = 0;
263 
264  self.ignoreSuppression = true;
265  self.suppressionThreshold = 1;
266  self.noDodgeMove = true;
267  self.dontShootWhileMoving = true;
268  self.pathenemylookahead = 0;
269 
270 
271  self.holdfire = true; //no firing - performance gain
272 
273  self.badplaceawareness = 0;
274  self.chatInitialized = false;
275  self.missingLegs = false;
276 
277  if ( !isdefined( self.zombie_arms_position ) )
278  {
279  if(randomint( 2 ) == 0)
280  self.zombie_arms_position = "up";
281  else
282  self.zombie_arms_position = "down";
283  }
284 
285  if ( randomint( 100 ) < ‪ZM_CAN_STUMBLE )
286  {
287  self.canStumble = true;
288  }
289 
290  self.a.disablepain = true;
291  self ‪zm_utility::disable_react(); // SUMEET - zombies dont use react feature.
292 
293  if ( isdefined( level.zombie_health ) )
294  {
295  self.maxhealth = level.zombie_health;
296 
297  if( IsDefined(level.a_zombie_respawn_health[ self.archetype ] ) && level.a_zombie_respawn_health[ self.archetype ].size > 0 )
298  {
299  self.health = level.a_zombie_respawn_health[ self.archetype ][0];
300  ArrayRemoveValue(level.a_zombie_respawn_health[ self.archetype ], level.a_zombie_respawn_health[ self.archetype ][0]);
301  }
302  else
303  {
304  self.health = level.zombie_health;
305  }
306  }
307  else
308  {
309  self.maxhealth = level.zombie_vars["zombie_health_start"];
310  self.health = self.maxhealth;
311  }
312 
313  self.freezegun_damage = 0;
314 
315  //setting avoidance parameters for zombies
316  self setAvoidanceMask( "avoid none" );
317 
318  // wait for zombie to teleport into position before pathing
319  self PathMode( "dont move" );
320 
321  level thread ‪zombie_death_event( self );
322 
323  // We need more script/code to get this to work properly
324 // self add_to_spectate_list();
325 // self random_tan();
327  self thread ‪zombie_think();
329  self thread ‪zombie_damage_failsafe();
330 
331  self thread ‪enemy_death_detection();
332 
333  if(IsDefined(level._zombie_custom_spawn_logic))
334  {
335  if(IsArray(level._zombie_custom_spawn_logic))
336  {
337  for(i = 0; i < level._zombie_custom_spawn_logic.size; i ++)
338  {
339  self thread [[level._zombie_custom_spawn_logic[i]]]();
340  }
341  }
342  else
343  {
344  self thread [[level._zombie_custom_spawn_logic]]();
345  }
346  }
347 
348  if ( !isdefined( self.no_eye_glow ) || !self.no_eye_glow )
349  {
350  if ( !‪IS_TRUE( self.is_inert ) )
351  {
352  self thread ‪zombie_utility::delayed_zombie_eye_glow(); // delayed eye glow for ground crawlers (the eyes floated above the ground before the anim started)
353  }
354  }
355  self.deathFunction = &‪zombie_death_animscript;
356  self.flame_damage_time = 0;
357 
358  self.meleeDamage = 60; // 45
359  self.no_powerups = true;
360 
361  self ‪zombie_history( "zombie_spawn_init -> Spawned = " + self.origin );
362 
363  self.thundergun_knockdown_func = level.basic_zombie_thundergun_knockdown;
364  self.tesla_head_gib_func = &‪zombie_tesla_head_gib;
365 
366  self.team = level.zombie_team;
367 
368  // No sight update
369  self.updateSight = false;
370 
371  self.heroweapon_kill_power = ‪ZM_ZOMBIE_HERO_WEAPON_KILL_POWER;
372  self.sword_kill_power = ‪ZM_ZOMBIE_HERO_WEAPON_KILL_POWER;
373 
374  if ( isDefined(level.achievement_monitor_func) )
375  {
376  self [[level.achievement_monitor_func]]();
377  }
378 
379  //gamemodule post init
380  if(isdefined(‪zm_utility::get_gamemode_var("post_init_zombie_spawn_func")))
381  {
382  self [[‪zm_utility::get_gamemode_var("post_init_zombie_spawn_func")]]();
383  }
384 
385  if ( isDefined( level.zombie_init_done ) )
386  {
387  self [[ level.zombie_init_done ]]();
388  }
389  self.zombie_init_done = true;
390 
391  self notify( "zombie_init_done" );
392 }
393 
395 {
396  self endon ("death");
397 
398  continue_failsafe_damage = false;
399  while (1)
400  {
401  //should only be for zombie exploits
402  wait 0.5;
403 
404  if ( !isdefined( self.enemy ) || !IsPlayer( self.enemy ) )
405  {
406  continue;
407  }
408 
409  if (self istouching(self.enemy))
410  {
411  old_org = self.origin;
412  if (!continue_failsafe_damage)
413  {
414  wait 5;
415  }
416 
417  //make sure player doesn't die instantly after getting touched by a zombie.
418  if (!isdefined(self.enemy) || !IsPlayer( self.enemy ) || self.enemy hasperk( ‪PERK_JUGGERNOG ) )
419  {
420  continue;
421  }
422 
423 
424  if (self istouching(self.enemy)
425  && !self.enemy ‪laststand::player_is_in_laststand()
426  && isalive(self.enemy))
427  {
428  //TODO THIS SHOULD NOT BE A PERMANENT FIX, ONLY TEMP TEST
429  //MM -10/13/09 This distance used to be 35
430  if (distancesquared(old_org, self.origin) < (60 * 60) )
431  {
432  self.enemy DoDamage( self.enemy.health + 1000, self.enemy.origin, self, self, "none", "MOD_RIFLE_BULLET" );
433 
434  continue_failsafe_damage = true;
435  }
436  }
437  }
438  else
439  {
440  continue_failsafe_damage = false;
441  }
442  }
443 }
444 
445 
446 function ‪should_skip_teardown( find_flesh_struct_string )
447 {
448  // Riser who spawns in the playable area
449  if( IsDefined(find_flesh_struct_string) && find_flesh_struct_string == "find_flesh" )
450  {
451  return true;
452  }
453  // Used on dogs...could be used on a zombie who spawns in and immediately chases player
454  if( isDefined( self.script_string ) && self.script_string == "find_flesh" )
455  {
456  return true;
457  }
458 
459  return false;
460 }
461 
463 {
464 
465  node = undefined;
466 
467  desired_nodes = [];
468  self.entrance_nodes = [];
469 
470  if ( IsDefined( level.max_barrier_search_dist_override ) )
471  {
472  max_dist = level.max_barrier_search_dist_override;
473  }
474  else
475  {
476  max_dist = 500;
477  }
478 
479  if( !IsDefined(self.find_flesh_struct_string) && IsDefined( self.target ) && self.target != "" )
480  {
481  desired_origin = ‪zombie_utility::get_desired_origin();
482 
483  assert( IsDefined( desired_origin ), "Spawner @ " + self.origin + " has a .target but did not find a target" );
484 
485  origin = desired_origin;
486 
487  node = ArrayGetClosest( origin, level.exterior_goals );
488  self.entrance_nodes[self.entrance_nodes.size] = node;
489 
490  self ‪zombie_history( "zombie_think -> #1 entrance (script_forcegoal) origin = " + self.entrance_nodes[0].origin );
491  }
492  // JMA - this is used in swamp to spawn outdoor zombies and immediately rush the player
493  // JMA - if riser becomes a non-riser, make sure they go to a barrier first instead of chasing a player
494  else if ( self ‪should_skip_teardown( self.find_flesh_struct_string ) )
495  {
497  //if the zombie has a target, make them go there first
498  if (isDefined(self.target))
499  {
500  end_at_node = GetNode(self.target, "targetname");
501  if (isDefined(end_at_node))
502  {
503  self setgoalnode (end_at_node);
504  self waittill("goal");
505  }
506  }
507 
508  if ( ‪IS_TRUE( self.start_inert ) )
509  {
511  }
512  else
513  {
514  self thread ‪zombie_entered_playable();
515  }
516  return;
517  }
518  else if( IsDefined(self.find_flesh_struct_string) )
519  {
520  for( i=0; i<level.exterior_goals.size; i++ )
521  {
522  if( IsDefined(level.exterior_goals[i].script_string) && level.exterior_goals[i].script_string == self.find_flesh_struct_string )
523  {
524  node = level.exterior_goals[i];
525  break;
526  }
527  }
528  self.entrance_nodes[self.entrance_nodes.size] = node;
529 
530  self ‪zombie_history( "zombie_think -> #1 entrance origin = " + node.origin );
531 
532  // Incase the guy does not move from spawn, then go to the closest one instead
533  self thread ‪zombie_assure_node();
534  }
535 
536  assert( IsDefined( node ), "Did not find a node!!! [Should not see this!]" );
537 
538  level thread ‪zm_utility::draw_line_ent_to_pos( self, node.origin, "goal" );
539 
540  self.first_node = node; // This is the first locatin the zombies go to
541 
542 }
543 
544 // JL 12/08/09 this is the main zombie think thread that starts when they spawn in
545 function ‪zombie_think()
546 {
547  self endon( "death" );
548  assert( !self.isdog );
549 
550  self.ai_state = "zombie_think";
551 
552  //node = level.exterior_goals[randomint( level.exterior_goals.size )];
553 
554  // MM - 5/8/9 Add ability for risers to find_flesh immediately after spawning if the
555  // rise struct has the script_noteworthy "find_flesh"
556  find_flesh_struct_string = undefined;
557 
558  if ( IsDefined(level.zombie_custom_think_logic) )
559  {
560  shouldWait = self [[ level.zombie_custom_think_logic ]]();
561  if ( shouldWait )
562  {
563  self waittill("zombie_custom_think_done", find_flesh_struct_string);
564  }
565  }
566  else if ( ‪IS_TRUE( self.start_inert ) )
567  {
568  find_flesh_struct_string = "find_flesh";
569  }
570  else
571  {
572  if ( isdefined( self.custom_location ) )
573  {
574  self thread [[ self.custom_location ]]();
575  }
576  else
577  {
578  // DCS 032612: find available structs to spawn at:
579  self thread ‪do_zombie_spawn();
580  }
581  self waittill("risen", find_flesh_struct_string );
582  }
583  self.find_flesh_struct_string = find_flesh_struct_string;
584 
585  // what is the zombies goal radius at this point
586  //self thread zombie_goto_entrance( self.first_node ); // sends the zombie to the node right in front of the window
587 
588  self SetGoal( self.origin );
589  self PathMode( "move allowed" );
590  self.zombie_think_done = true;
591 }
592 
594 {
595  self endon( "death" );
596 
597  if ( !IsDefined( level.playable_areas ) )
598  {
599  level.playable_areas = GetEntArray("player_volume", "script_noteworthy" );
600  }
601 
602  while ( true )
603  {
604  foreach(area in level.playable_areas)
605  {
606  if(self IsTouching(area))
607  {
609  return;
610  }
611  }
612  wait(1);
613  }
614 }
615 
616 function ‪zombie_goto_entrance( node, endon_bad_path )
617 {
618  assert( !self.isdog );
619 
620  self endon( "death" );
621  self endon( "stop_zombie_goto_entrance" );
622  level endon( "intermission" );
623 
624  self.ai_state = "zombie_goto_entrance";
625 
626  if( IsDefined( endon_bad_path ) && endon_bad_path )
627  {
628  // If we cannot go to the goal, then end...
629  // Used from find_flesh
630  self endon( "bad_path" );
631  }
632 
633 
634 
635  self ‪zombie_history( "zombie_goto_entrance -> start goto entrance " + node.origin );
636 
637  self.got_to_entrance = false;
638 
639 
640 
641  // This is the goal radius while the zombies search for a window to attack
642  self.goalradius = 128;
643  self SetGoal( node.origin );
644  self waittill( "goal" );
645  self.got_to_entrance = true;
646 
647  self ‪zombie_history( "zombie_goto_entrance -> reached goto entrance " + node.origin );
648 
649  // Guy should get to goal and tear into building until all barrier chunks are gone
650  // They go into this function and do everything they and then comeback once all the barriers are removed
651  self ‪tear_into_building();
652 
653  if( isDefined( level.pre_aggro_pathfinding_func ) )
654  {
655  self [[ level.pre_aggro_pathfinding_func ]]();
656  }
657 
658  barrier_pos = [];
659  barrier_pos[0] = "m";
660  barrier_pos[1] = "r";
661  barrier_pos[2] = "l";
662 
663  self.barricade_enter = true;
664  animstate = ‪zombie_utility::append_missing_legs_suffix( "zm_barricade_enter" );
665  //substate = "barrier_" + self.zombie_move_speed + "_" + barrier_pos[ self.attacking_spot_index ];
666  //self AnimScripted( self.first_node.zbarrier.origin, self.first_node.zbarrier.angles, animstate, substate );
667  self AnimScripted( "barricade_enter_anim", self.first_node.zbarrier.origin, self.first_node.zbarrier.angles, "ai_zombie_barricade_enter_m_v1" );
668  ‪zombie_shared::DoNoteTracks( "barricade_enter_anim" );
669 
671 
672  //self.pathEnemyFightDist = 4; // make sure zombie gets out of the window
673 
675  //self.pathEnemyFightDist = 64; // restore
676  self.barricade_enter = false;
677 }
678 
679 
680 // Here the zombies constantly search
682 {
683  self endon( "death" );
684  self endon( "goal" );
685  level endon( "intermission" );
686 
687  start_pos = self.origin;
688  if(IsDefined(self.entrance_nodes))
689  {
690  for( i = 0; i < self.entrance_nodes.size; i++ )
691  {
692  if( self ‪zombie_bad_path() )
693  {
694  self ‪zombie_history( "zombie_assure_node -> assigned assured node = " + self.entrance_nodes[i].origin );
695 
696 
697  level thread ‪zm_utility::draw_line_ent_to_pos( self, self.entrance_nodes[i].origin, "goal" );
698  self.first_node = self.entrance_nodes[i];
699  self SetGoal( self.entrance_nodes[i].origin );
700  }
701  else
702  {
703  return;
704  }
705  }
706  }
707  wait(2);
708  // Get more nodes and try again
709  nodes = array::get_all_closest( self.origin, level.exterior_goals, undefined, 20 );
710  //nodes = ArraySort( level.exterior_goals, self.origin, true, 20 );
711 
712  if(IsDefined(nodes))
713  {
714  self.entrance_nodes = nodes;
715  for( i = 0; i < self.entrance_nodes.size; i++ )
716  {
717  if( self ‪zombie_bad_path() )
718  {
719  self ‪zombie_history( "zombie_assure_node -> assigned assured node = " + self.entrance_nodes[i].origin );
720 
721 
722  level thread ‪zm_utility::draw_line_ent_to_pos( self, self.entrance_nodes[i].origin, "goal" );
723  self.first_node = self.entrance_nodes[i];
724  self SetGoal( self.entrance_nodes[i].origin );
725  }
726  else
727  {
728  return;
729  }
730  }
731  }
732 
733  self ‪zombie_history( "zombie_assure_node -> failed to find a good entrance point" );
734 
735  //assertmsg( "^1Zombie @ " + self.origin + " did not find a good entrance point... Please fix pathing or Entity setup" );
736  wait(20);
737  //iprintln( "^1Zombie @ " + self.origin + " did not find a good entrance point... Please fix pathing or Entity setup" );
738 
739 
740  self DoDamage( self.health + 10, self.origin );
741 
742  //add this zombie back into the spawner queue to be re-spawned, should only happen with a bad window.
743  if(‪IS_TRUE(level.put_timed_out_zombies_back_in_queue ) && !‪IS_TRUE(self.has_been_damaged_by_player))
744  {
745  level.zombie_total++;
746  level.zombie_total_subtract++;
747  }
748 
749  //add this to the stats even tho he really didn't 'die'
750  level.zombies_timeout_spawn++;
751 
752 }
753 
755 {
756  self endon( "death" );
757  self endon( "goal" );
758 
759  self thread ‪zombie_bad_path_notify();
760  self thread ‪zombie_bad_path_timeout();
761 
762  self.zombie_bad_path = undefined;
763  while( !IsDefined( self.‪zombie_bad_path ) )
764  {
766  }
767 
768  self notify( "stop_zombie_bad_path" );
769 
770  return self.zombie_bad_path;
771 }
772 
774 {
775  self endon( "death" );
776  self endon( "stop_zombie_bad_path" );
777 
778  self waittill( "bad_path" );
779 
780 
781  self.zombie_bad_path = true;
782 }
783 
785 {
786  self endon( "death" );
787  self endon( "stop_zombie_bad_path" );
788 
789  wait( 2 );
790  self.zombie_bad_path = false;
791 }
792 
793 
794 // This controls the zombies breaking into the building.
795 // Self is a specific zombie
796 // Node is the player's origin
798 {
799  self endon( "death" ); // this is a zombie
800  self endon("teleporting");
801  self ‪zombie_history( "tear_into_building -> start" ); // update history that they have started to tear in
802 
803  while( 1 )
804  {
805  //also check
806  //if( IsDefined( self.first_node) )
807  //{
808 
809  if( IsDefined( self.first_node.script_noteworthy ) )
810  {
811  if( self.first_node.script_noteworthy == "no_blocker" )
812  {
813  return; // if no blocker checks out ok... then allow the zombie to connect paths
814  }
815  }
816 
817  if( !IsDefined( self.first_node.target ) )
818  {
819  return;
820  }
821 
822  // barrier_chunks is the exterior_goal that has all the bars and boards connected to it.
823  // remember all_chunks_destroyed is in utility script _zombie_utility
824  if( ‪zm_utility::all_chunks_destroyed( self.first_node, self.first_node.barrier_chunks ) ) // If barrier_chunks status says all chunks are destroyed then continue
825  {
826  // latest
827  // Send this notify but only accept the first time it comes through.
828  self ‪zombie_history( "tear_into_building -> all chunks destroyed" ); // Enter the building if all chunks are gone. This is threaded for each zombie
829  }
830 
831  // If an attacking_spot is availiable then they well grab one, if not they taunt.
832  // Jluyties (02/04/10)Added the ability for zombies to taunt while they wait to attack a window
833  if( !‪get_attack_spot( self.first_node ) )
834  {
835  self ‪zombie_history( "tear_into_building -> Could not find an attack spot" );
836  //Print3d(self.origin+(0,0,70), "Hey I am waiting to attack, play random " );
837  //Print3d(self.origin+(0,0,70), "Hey I am waiting to attack", ( 1, 0.8, 0.5), 1, 1, 5);
838  //IPrintLnBold( "Hey I am waiting to attack " );
839  self thread ‪do_a_taunt();
840  wait( 0.5 );
841  continue;
842  }
843 
844  // This is where the zombie moves into position to tear down a board/bar
845  self.goalradius = 2;
846  //self maps\_zombiemode_utility:: lerp( chunk );
847  self.at_entrance_tear_spot = false;
848  if ( isdefined( level.tear_into_position ) )
849  {
850  self [[ level.tear_into_position ]]();
851  }
852  else
853  {
854  angles = self.first_node.zbarrier.angles;
855 
856  self SetGoal( self.attacking_spot );
857  }
858  self waittill( "goal" );
859  self.at_entrance_tear_spot = true;
860  // MM- 05/09
861  // If you wait for "orientdone", you NEED to also have a timeout.
862  // Otherwise, zombies could get stuck waiting to do their facing.
863  if ( isdefined( level.tear_into_wait ) )
864  {
865  self [[ level.tear_into_wait ]]();
866  }
867  else
868  {
869  self ‪util::waittill_any_ex( 1, "orientdone", "death", "teleporting" );
870  }
871 
872  self ‪zombie_history( "tear_into_building -> Reach position and orientated" );
873 
874  // chrisp - do one final check to make sure that the boards are still torn down
875  // this *mostly* prevents the zombies from coming through the windows as you are boarding them up.
876  if( ‪zm_utility::all_chunks_destroyed( self.first_node, self.first_node.barrier_chunks ) )
877  {
878  self ‪zombie_history( "tear_into_building -> all chunks destroyed" );
879  for( i = 0; i < self.first_node.attack_spots_taken.size; i++ )
880  {
881  self.first_node.attack_spots_taken[i] = false;
882  }
883  return;
884  }
885  //}
886 
887  // Now tear down boards
888  while( 1 )
889  {
890  if ( isDefined( self.zombie_board_tear_down_callback ) )
891  {
892  self [[self.zombie_board_tear_down_callback]]();
893  }
894 
895  // get_closest_non_destroyed_chunk calls into _zombiemode_utility and returns if any chunks are still there
896  self.chunk = ‪zm_utility::get_closest_non_destroyed_chunk( self.origin, self.first_node, self.first_node.barrier_chunks );
897 
898  if ( !IsDefined( self.chunk ) )
899  {
900  if( !‪zm_utility::all_chunks_destroyed( self.first_node, self.first_node.barrier_chunks ) )
901  {
902  attack = self ‪should_attack_player_thru_boards();
903  if(isDefined(attack) && !attack && !self.missingLegs)
904  {
905  self ‪do_a_taunt();
906  }
907  else
908  {
909  wait( 0.1 );
910  }
911  continue;
912  }
913 
914 
915  for( i = 0; i < self.first_node.attack_spots_taken.size; i++ )
916  {
917  self.first_node.attack_spots_taken[i] = false;
918  }
919  return;
920  }
921 
922  self ‪zombie_history( "tear_into_building -> animating" );
923 
924  self.first_node.zbarrier SetZBarrierPieceState(self.chunk, "targetted_by_zombie");
925  self.first_node thread ‪check_zbarrier_piece_for_zombie_inert(self.chunk, self.first_node.zbarrier, self);
926  self.first_node thread ‪check_zbarrier_piece_for_zombie_death(self.chunk, self.first_node.zbarrier, self);
927 
928  self notify( "bhtn_action_notify", "teardown" );
929 
930  /*if( isdefined( level.zbarrier_override_tear_in ) )
931  {
932  animStateBase = self [[ level.zbarrier_override_tear_in ]]( chunk );
933  }
934  else
935  {
936  animStateBase = self.first_node.zbarrier GetZBarrierPieceAnimState(chunk);
937  }
938 
939  animSubState = "spot_" + self.attacking_spot_index + "_piece_" + self.first_node.zbarrier GetZBarrierPieceAnimSubState(chunk);
940 
941  anim_sub_index = self GetAnimSubStateFromASD( animStateBase + "_in", animSubState );
942  */
943 
944  //self AnimScripted( self.first_node.zbarrier.origin, self.first_node.zbarrier.angles, zombie_utility::append_missing_legs_suffix( animStateBase + "_in" ), anim_sub_index );
945  self AnimScripted( "tear_anim", self.first_node.zbarrier.origin, self.first_node.zbarrier.angles, "ai_zombie_boardtear_aligned_m_1_grab" );
946 
947 
948  self ‪zombie_tear_notetracks( "tear_anim", self.chunk, self.first_node );
949 
950  while(0 < self.first_node.zbarrier.chunk_health[self.chunk])
951  {
952  //self AnimScripted( self.first_node.zbarrier.origin, self.first_node.zbarrier.angles, zombie_utility::append_missing_legs_suffix( animStateBase + "_loop" ), anim_sub_index );
953  self AnimScripted( "tear_anim", self.first_node.zbarrier.origin, self.first_node.zbarrier.angles, "ai_zombie_boardtear_aligned_m_1_hold" );
954  self ‪zombie_tear_notetracks( "tear_anim", self.chunk, self.first_node );
955  self.first_node.zbarrier.chunk_health[self.chunk]--;
956  }
957 
958  //self AnimScripted( self.first_node.zbarrier.origin, self.first_node.zbarrier.angles, zombie_utility::append_missing_legs_suffix( animStateBase + "_out" ), anim_sub_index );
959  self AnimScripted( "tear_anim", self.first_node.zbarrier.origin, self.first_node.zbarrier.angles, "ai_zombie_boardtear_aligned_m_1_pull" );
960  self waittill("temp proceed");
961 
962  //to prevent the zombie from being deleted by the failsafe system
963  self.lastchunk_destroy_time = GetTime();
964 
965  attack = self ‪should_attack_player_thru_boards();
966  if ( isDefined( attack ) && !attack && !self.missingLegs )
967  {
968  self ‪do_a_taunt();
969  }
970 
971  //chrisp - fix the extra tear anim bug
972  if ( ‪zm_utility::all_chunks_destroyed( self.first_node, self.first_node.barrier_chunks ) )
973  {
974  for( i = 0; i < self.first_node.attack_spots_taken.size; i++ )
975  {
976  self.first_node.attack_spots_taken[i] = false;
977  }
978 
979  level notify( "last_board_torn", self.first_node.zbarrier.origin );
980 
981  return;
982  }
983  }
984 
986  }
987 }
988 
989 
990 /*------------------------------------
991 function checks to see if the zombie should
992 function do a taunt when tearing thru the boards
993 ------------------------------------*/
994 function ‪do_a_taunt()
995 {
996  self endon ("death"); // Jluyties 02/16/10 added death check, cause of crash
997  if( self.missingLegs )
998  {
999  return false;
1000  }
1001 
1002  if(!self.first_node.zbarrier ZBarrierSupportsZombieTaunts())
1003  {
1004  return;
1005  }
1006 
1007  self.old_origin = self.origin;
1008  if(GetDvarString( "zombie_taunt_freq") == "")
1009  {
1010  SetDvar("zombie_taunt_freq","5");
1011  }
1012  freq = GetDvarInt( "zombie_taunt_freq");
1013 
1014  if( freq >= randomint(100) )
1015  {
1016  self notify( "bhtn_action_notify", "taunt" );
1017 
1018  tauntState = "zm_taunt";
1019 
1020  if(isdefined(self.first_node.zbarrier) && self.first_node.zbarrier GetZBarrierTauntAnimState() != "")
1021  {
1022  tauntState = self.first_node.zbarrier GetZBarrierTauntAnimState();
1023  }
1024 
1025  //self animscripted( "anim_wait_done", self.origin, self.angles, tauntState );
1026  self animscripted( "taunt_anim", self.origin, self.angles, "ai_zombie_taunts_4" );
1027  self ‪taunt_notetracks( "taunt_anim" );
1028  }
1029 }
1030 
1031 function ‪taunt_notetracks(msg)
1032 {
1033  self endon("death");
1034 
1035  while(1)
1036  {
1037  self waittill( msg, notetrack );
1038 
1039  if( notetrack == "end" )
1040  {
1041  self ForceTeleport(self.old_origin);
1042 
1043  return;
1044  }
1045  }
1046 }
1047 /*------------------------------------
1048 function checks to see if the players are near
1049 function the entrance and tries to attack them
1050 function thru the boards. 50% chance
1051 function Self is a zombie
1052 ------------------------------------*/
1054 {
1055 
1056  //no board attacks if they are crawlers
1057  if( self.missingLegs )
1058  {
1059  return false;
1060  }
1061 
1062  if(isdefined(self.first_node.zbarrier))
1063  {
1064  if(!self.first_node.zbarrier ZBarrierSupportsZombieReachThroughAttacks())
1065  {
1066  return false;
1067  }
1068  }
1069 
1070  if(GetDvarString( "zombie_reachin_freq") == "")
1071  {
1072  SetDvar("zombie_reachin_freq","50");
1073  }
1074  freq = GetDvarInt( "zombie_reachin_freq");
1075 
1076  players = GetPlayers();
1077  attack = false;
1078 
1079  self.player_targets = [];
1080  for(i=0;i<players.size;i++)
1081  {
1082  if ( isAlive( players[i] ) && !isDefined( players[i].revivetrigger ) && distance2d( self.origin, players[i].origin ) <= level.attack_player_thru_boards_range && !‪IS_TRUE( players[i].zombie_vars[ "zombie_powerup_zombie_blood_on" ] ) )
1083  {
1084  self.player_targets[self.player_targets.size] = players[i];
1085  attack = true;
1086  }
1087  }
1088 
1089  if ( !attack || freq < randomint(100) )
1090  {
1091  return false;
1092  }
1093 
1094  self.old_origin = self.origin;
1095 
1096  attackAnimState = "zm_window_melee";
1097 
1098  if(isdefined(self.first_node.zbarrier) && self.first_node.zbarrier GetZBarrierReachThroughAttackAnimState() != "")
1099  {
1100  attackAnimState = self.first_node.zbarrier GetZBarrierReachThroughAttackAnimState();
1101  }
1102 
1103  // index 0 is center, index 2 is left and index 1 is the right, so (0 - 1) results in randomizing between both options
1104  self notify( "bhtn_action_notify", "attack" );
1105  //self AnimScripted( self.origin, self.angles, attackAnimState, self.attacking_spot_index - 1 );
1106  self AnimScripted( "window_melee_anim", self.origin, self.angles, "ai_zombie_window_attack_arm_l_out" );
1107  self ‪window_notetracks( "window_melee_anim" );
1108 
1109  return true;
1110 }
1111 
1113 {
1114  self endon("death");
1115 
1116  while(1)
1117  {
1118  self waittill( msg, notetrack );
1119 
1120  if( notetrack == "end" )
1121  {
1122  //self waittill("end");
1123  self ‪teleport(self.old_origin);
1124 
1125  return;
1126  }
1127  if( notetrack == "fire" )
1128  {
1129  if(self.ignoreall)
1130  {
1131  self.ignoreall = false;
1132  }
1133 
1134  // just hit a player
1135  if ( isDefined( self.first_node ) )
1136  {
1137  _MELEE_DIST_SQ = 90*90;
1138 
1139  if ( IsDefined( level.attack_player_thru_boards_range ) )
1140  {
1141  _MELEE_DIST_SQ = level.attack_player_thru_boards_range * level.attack_player_thru_boards_range;
1142  }
1143 
1144  _TRIGGER_DIST_SQ = 51*51;
1145 
1146  for ( i = 0; i < self.player_targets.size; i++ )
1147  {
1148  playerDistSq = Distance2DSquared( self.player_targets[i].origin, self.origin );
1149  heightDiff = abs( self.player_targets[i].origin[2] - self.origin[2] ); // be sure we're on the same floor
1150  if ( playerDistSq < _MELEE_DIST_SQ && (heightDiff * heightDiff) < _MELEE_DIST_SQ )
1151  {
1152  triggerDistSq = Distance2DSquared( self.player_targets[i].origin, self.first_node.trigger_location.origin );
1153  heightDiff = abs( self.player_targets[i].origin[2] - self.first_node.trigger_location.origin[2] ); // be sure we're on the same floor
1154  if ( triggerDistSq < _TRIGGER_DIST_SQ && (heightDiff * heightDiff) < _TRIGGER_DIST_SQ )
1155  {
1156  self.player_targets[i] DoDamage( self.meleeDamage, self.origin, self, self, "none", "MOD_MELEE" );
1157  break;
1158  }
1159  }
1160  }
1161  }
1162  else
1163  {
1164  self melee();
1165  }
1166  }
1167  }
1168 }
1169 
1170 function ‪get_attack_spot( node )
1171 {
1172  index = ‪get_attack_spot_index( node );
1173  if( !IsDefined( index ) )
1174  {
1175  return false;
1176  }
1177 
1178  self.attacking_node = node;
1179  self.attacking_spot_index = index;
1180  node.attack_spots_taken[index] = true;
1181  self.attacking_spot = node.attack_spots[index];
1182 
1183  return true;
1184 }
1185 
1187 {
1188  indexes = [];
1189  ‪DEFAULT(node.attack_spots,[]);
1190  for( i = 0; i < node.attack_spots.size; i++ )
1191  {
1192  if( !node.attack_spots_taken[i] )
1193  {
1194  indexes[indexes.size] = i;
1195  }
1196  }
1197 
1198  if( indexes.size == 0 )
1199  {
1200  return undefined;
1201  }
1202 
1203  return indexes[RandomInt( indexes.size )];
1204 }
1205 
1206 // Self is zombie
1207 function ‪zombie_tear_notetracks( msg, chunk, node )
1208 {
1209  self endon("death");
1210 
1211  while( 1 )
1212  {
1213  self waittill( msg, notetrack );
1214 
1215  if ( notetrack == "end" )
1216  {
1217  return;
1218  }
1219 
1220  if ( notetrack == "board" || notetrack == "destroy_piece" || notetrack == "bar")
1221  {
1222  if( isdefined( level.zbarrier_zombie_tear_notetrack_override ) )
1223  {
1224  self thread [[ level.zbarrier_zombie_tear_notetrack_override ]]( node, chunk );
1225  }
1226  node.zbarrier SetZBarrierPieceState(chunk, "opening");
1227  }
1228  }
1229 }
1230 
1231 // jl I am doing this so I can have an offset of timing for when the chunks come off to give it more life
1232 // 0.8 is too long
1233 // need to offset sound
1234 // need to add this to the boards
1236 {
1237  // DCS 090110: fx for breaking out glass or wall.
1238  if ( IsDefined( chunk.script_parameters ) && ( chunk.script_parameters == "repair_board" || chunk.script_parameters == "board") )
1239  {
1240  if(IsDefined(chunk.unbroken) && chunk.unbroken == true)
1241  {
1242  if(IsDefined(chunk.material) && chunk.material == "glass")
1243  {
1244  PlayFX( level._effect["glass_break"], chunk.origin, node.angles );
1245  chunk.unbroken = false;
1246  }
1247  else if(IsDefined(chunk.material) && chunk.material == "metal")
1248  {
1249  PlayFX( level._effect["fx_zombie_bar_break"], chunk.origin );
1250  chunk.unbroken = false;
1251  }
1252  else if(IsDefined(chunk.material) && chunk.material == "rock")
1253  {
1254  if( ‪IS_TRUE(level.use_clientside_rock_tearin_fx))
1255  {
1256  chunk ‪clientfield::set( "tearin_rock_fx", 1 );
1257  }
1258  else
1259  {
1260  PlayFX( level._effect["wall_break"], chunk.origin );
1261  }
1262  chunk.unbroken = false;
1263  }
1264  }
1265  }
1266  if ( IsDefined( chunk.script_parameters ) && ( chunk.script_parameters == "barricade_vents" ) )
1267  {
1268  if( ‪IS_TRUE(level.use_clientside_board_fx))
1269  {
1270  chunk ‪clientfield::set( "tearin_board_vertical_fx", 1);
1271  }
1272  else
1273  {
1274  PlayFX( level._effect["fx_zombie_bar_break"], chunk.origin );
1275  }
1276  }
1277  else if(IsDefined(chunk.material) && chunk.material == "rock")
1278  {
1279  if( ‪IS_TRUE(level.use_clientside_rock_tearin_fx))
1280  {
1281  chunk ‪clientfield::set( "tearin_rock_fx", 1 );
1282  }
1283  }
1284 
1285  else
1286  {
1287  if(isDefined(level.use_clientside_board_fx))
1288  {
1289  chunk ‪clientfield::set( "tearin_board_vertical_fx", 1 );
1290  }
1291  else
1292  {
1293 // PlayFx( level._effect["wood_chunk_destory"], chunk.origin + (0, 0, 30));
1294  wait( randomfloatrange( 0.2, 0.4 ));
1295 // PlayFx( level._effect["wood_chunk_destory"], chunk.origin + (0, 0, -30));
1296  }
1297  }
1298 }
1299 
1301 {
1302  // DCS 090110: fx for breaking out glass or wall.
1303  if ( IsDefined( chunk.script_parameters ) && ( chunk.script_parameters == "repair_board" || chunk.script_parameters == "board") )
1304  {
1305  if(IsDefined(chunk.unbroken) && chunk.unbroken == true)
1306  {
1307  if(IsDefined(chunk.material) && chunk.material == "glass")
1308  {
1309  PlayFX( level._effect["glass_break"], chunk.origin, node.angles );
1310  chunk.unbroken = false;
1311  }
1312  else if(IsDefined(chunk.material) && chunk.material == "metal")
1313  {
1314  PlayFX( level._effect["fx_zombie_bar_break"], chunk.origin );
1315  chunk.unbroken = false;
1316  }
1317  else if(IsDefined(chunk.material) && chunk.material == "rock")
1318  {
1319  if( ‪IS_TRUE(level.use_clientside_rock_tearin_fx))
1320  {
1321  chunk ‪clientfield::set( "tearin_rock_fx", 1 );
1322  }
1323  else
1324  {
1325  PlayFX( level._effect["wall_break"], chunk.origin );
1326  }
1327  chunk.unbroken = false;
1328  }
1329  }
1330  }
1331  if ( IsDefined( chunk.script_parameters ) && ( chunk.script_parameters == "barricade_vents" ) )
1332  {
1333  if(isDefined(level.use_clientside_board_fx))
1334  {
1335  chunk ‪clientfield::set( "tearin_board_horizontal_fx", 1 );
1336  }
1337  else
1338  {
1339  PlayFX( level._effect["fx_zombie_bar_break"], chunk.origin );
1340  }
1341  }
1342  else if(IsDefined(chunk.material) && chunk.material == "rock")
1343  {
1344  if( ‪IS_TRUE(level.use_clientside_rock_tearin_fx))
1345  {
1346  chunk ‪clientfield::set( "tearin_rock_fx", 1 );
1347  }
1348  }
1349  else
1350  {
1351  if(isDefined(level.use_clientside_board_fx))
1352  {
1353  chunk ‪clientfield::set( "tearin_board_horizontal_fx", 1 );
1354  }
1355  else
1356  {
1357 // PlayFx( level._effect["wood_chunk_destory"], chunk.origin + (30, 0, 0));
1358  wait( randomfloatrange( 0.2, 0.4 ));
1359 // PlayFx( level._effect["wood_chunk_destory"], chunk.origin + (-30, 0, 0));
1360  }
1361  }
1362 }
1363 
1364 
1366 {
1367  if ( IsDefined ( chunk.script_parameters ) && ( chunk.script_parameters == "bar" ) || ( chunk.script_noteworthy == "board" ))
1368  {
1369  // array random grab for fx
1370  //point = points[i];
1371  possible_tag_array_1 = [];
1372  possible_tag_array_1[0] = "Tag_fx_top";
1373  possible_tag_array_1[1] = "";
1374  possible_tag_array_1[2] = "Tag_fx_top";
1375  possible_tag_array_1[3] = "";
1376 
1377  possible_tag_array_2 = [];
1378  possible_tag_array_2[0] = "";
1379  possible_tag_array_2[1] = "Tag_fx_bottom";
1380  possible_tag_array_2[2] = "";
1381  possible_tag_array_2[3] = "Tag_fx_bottom";
1382  // now I need a random int between 0 and 3
1383  possible_tag_array_2 = array::randomize( possible_tag_array_2 );
1384 
1385  random_fx = [];
1386  random_fx[0] = level._effect["fx_zombie_bar_break"];
1387  random_fx[1] = level._effect["fx_zombie_bar_break_lite"];
1388  random_fx[2] = level._effect["fx_zombie_bar_break"];
1389  random_fx[3] = level._effect["fx_zombie_bar_break_lite"];
1390  // now I need a random int between 0 and 3
1391  random_fx = array::randomize( random_fx );
1392 
1393  switch( randomInt( 9 ) ) // This sets up random versions of the bars being pulled apart for variety
1394  {
1395  case 0:
1396  PlayFXOnTag( level._effect["fx_zombie_bar_break_lite"], chunk, "Tag_fx_top" );
1397  wait( randomfloatrange( 0.0, 0.3 ));
1398  PlayFXOnTag( level._effect["fx_zombie_bar_break_lite"], chunk, "Tag_fx_bottom" );
1399  break;
1400 
1401  case 1:
1402  PlayFXOnTag( level._effect["fx_zombie_bar_break"], chunk, "Tag_fx_top" );
1403  wait( randomfloatrange( 0.0, 0.3 ));
1404  PlayFXOnTag( level._effect["fx_zombie_bar_break"], chunk, "Tag_fx_bottom" );
1405  break;
1406 
1407  case 2:
1408  PlayFXOnTag( level._effect["fx_zombie_bar_break_lite"], chunk, "Tag_fx_top" );
1409  wait( randomfloatrange( 0.0, 0.3 ));
1410  PlayFXOnTag( level._effect["fx_zombie_bar_break"], chunk, "Tag_fx_bottom" );
1411  break;
1412 
1413  case 3:
1414  PlayFXOnTag( level._effect["fx_zombie_bar_break"], chunk, "Tag_fx_top" );
1415  wait( randomfloatrange( 0.0, 0.3 ));
1416  PlayFXOnTag( level._effect["fx_zombie_bar_break_lite"], chunk, "Tag_fx_bottom" );
1417  break;
1418 
1419  case 4:
1420  PlayFXOnTag( level._effect["fx_zombie_bar_break_lite"], chunk, "Tag_fx_top" );
1421  wait( randomfloatrange( 0.0, 0.3 ));
1422  PlayFXOnTag( level._effect["fx_zombie_bar_break_lite"], chunk, "Tag_fx_bottom" );
1423  break;
1424 
1425  case 5:
1426  PlayFXOnTag( level._effect["fx_zombie_bar_break_lite"], chunk, "Tag_fx_top" );
1427  break;
1428  case 6:
1429  PlayFXOnTag( level._effect["fx_zombie_bar_break_lite"], chunk, "Tag_fx_bottom" );
1430  break;
1431  case 7:
1432  PlayFXOnTag( level._effect["fx_zombie_bar_break"], chunk, "Tag_fx_top" );
1433  break;
1434  case 8:
1435  PlayFXOnTag( level._effect["fx_zombie_bar_break"], chunk, "Tag_fx_bottom" );
1436  break;
1437  }
1438  }
1439 }
1440 
1441 //jl I am doing this so I can have an offset of timing for when the chunks come off to give it more life
1443 {
1444  if ( IsDefined ( chunk.script_parameters ) && ( chunk.script_parameters == "bar" ) || ( chunk.script_noteworthy == "board" ))
1445  {
1446  switch( randomInt( 10 ) ) // This sets up random versions of the bars being pulled apart for variety
1447  {
1448  case 0:
1449  PlayFXOnTag( level._effect["fx_zombie_bar_break_lite"], chunk, "Tag_fx_left" );
1450  wait( randomfloatrange( 0.0, 0.3 ));
1451  PlayFXOnTag( level._effect["fx_zombie_bar_break_lite"], chunk, "Tag_fx_right" );
1452  break;
1453 
1454  case 1:
1455  PlayFXOnTag( level._effect["fx_zombie_bar_break"], chunk, "Tag_fx_left" );
1456  wait( randomfloatrange( 0.0, 0.3 ));
1457  PlayFXOnTag( level._effect["fx_zombie_bar_break"], chunk, "Tag_fx_right" );
1458  break;
1459 
1460  case 2:
1461  PlayFXOnTag( level._effect["fx_zombie_bar_break_lite"], chunk, "Tag_fx_left" );
1462  wait( randomfloatrange( 0.0, 0.3 ));
1463  PlayFXOnTag( level._effect["fx_zombie_bar_break"], chunk, "Tag_fx_right" );
1464  break;
1465 
1466  case 3:
1467  PlayFXOnTag( level._effect["fx_zombie_bar_break"], chunk, "Tag_fx_left" );
1468  wait( randomfloatrange( 0.0, 0.3 ));
1469  PlayFXOnTag( level._effect["fx_zombie_bar_break_lite"], chunk, "Tag_fx_right" );
1470  break;
1471 
1472  case 4:
1473  PlayFXOnTag( level._effect["fx_zombie_bar_break_lite"], chunk, "Tag_fx_left" );
1474  wait( randomfloatrange( 0.0, 0.3 ));
1475  PlayFXOnTag( level._effect["fx_zombie_bar_break_lite"], chunk, "Tag_fx_right" );
1476  break;
1477 
1478  case 5:
1479  PlayFXOnTag( level._effect["fx_zombie_bar_break_lite"], chunk, "Tag_fx_left" );
1480  break;
1481  case 6:
1482  PlayFXOnTag( level._effect["fx_zombie_bar_break_lite"], chunk, "Tag_fx_right" );
1483  break;
1484  case 7:
1485  PlayFXOnTag( level._effect["fx_zombie_bar_break"], chunk, "Tag_fx_right" );
1486  break;
1487  case 8:
1488  PlayFXOnTag( level._effect["fx_zombie_bar_break"], chunk, "Tag_fx_right" );
1489  break;
1490  }
1491  }
1492 }
1493 
1494 function ‪check_zbarrier_piece_for_zombie_inert(chunk_index, zbarrier, zombie)
1495 {
1496  zombie endon( "completed_emerging_into_playable_area" );
1497 
1498  zombie waittill( "stop_zombie_goto_entrance" );
1499 
1500  if ( zbarrier GetZBarrierPieceState(chunk_index) == "targetted_by_zombie" )
1501  {
1502  zbarrier SetZBarrierPieceState(chunk_index, "closed");
1503  }
1504 }
1505 
1506 function ‪check_zbarrier_piece_for_zombie_death(chunk_index, zbarrier, zombie)
1507 {
1508  while(1)
1509  {
1510  if(zbarrier GetZBarrierPieceState(chunk_index) != "targetted_by_zombie")
1511  {
1512  return;
1513  }
1514 
1515  if(!isdefined(zombie) || !IsAlive(zombie))
1516  {
1517  zbarrier SetZBarrierPieceState(chunk_index, "closed");
1518  return;
1519  }
1520 
1522  }
1523 }
1524 
1526 {
1527  self endon("destroyed");
1528 
1529  wait(2.5);
1530  self ‪zm_blockers::update_states("repaired");
1531 }
1532 
1533 //
1535 {
1536  if ( IsDefined(self) && ‪IS_TRUE(self.inhibit_scoring_from_zombies) )
1537  {
1538  return false;
1539  }
1540  return true;
1541 }
1542 
1543 //
1544 //
1546 {
1547  if( ‪zm_utility::is_tactical_grenade( zombie.damageweapon ) || !level ‪flag::get( "zombie_drop_powerups" ) )
1548  {
1549  return false;
1550  }
1551 
1552  if ( isdefined(zombie.no_powerups) && zombie.no_powerups )
1553  {
1554  return false;
1555  }
1556 
1557  if( ‪IS_TRUE(level.no_powerups) )
1558  {
1559  return( false );
1560  }
1561 
1562  if ( ‪IS_TRUE( level.use_powerup_volumes ) )
1563  {
1564  volumes = GetEntArray( "no_powerups", "targetname" );
1565  foreach( volume in volumes )
1566  {
1567  if ( zombie IsTouching( volume ) )
1568  {
1569  return false;
1570  }
1571  }
1572  }
1573 
1574  return true;
1575 }
1576 
1578 {
1580  level thread ‪zm_powerups::powerup_drop( origin );
1581 }
1582 
1583 //
1584 // award points on death
1585 function ‪zombie_death_points( origin, mod, hit_location, attacker, zombie,team )
1586 {
1587  if( !IsDefined( attacker ) || !IsPlayer( attacker ) )
1588  {
1589  return;
1590  }
1591 
1592  if ( !attacker ‪player_can_score_from_zombies() )
1593  {
1594  zombie.marked_for_recycle = 1;
1595  return;
1596  }
1597 
1598  if( ‪zombie_can_drop_powerups( zombie ) )
1599  {
1600  // DCS 031611: hack to prevent risers from dropping powerups under the ground.
1601  if(IsDefined(zombie.in_the_ground) && zombie.in_the_ground == true)
1602  {
1603  ‪trace = BulletTrace(zombie.origin + (0, 0, 100), zombie.origin + (0, 0, -100), false, undefined);
1604  origin = ‪trace["position"];
1605  level thread ‪zombie_delay_powerup_drop( origin );
1606  }
1607  else
1608  {
1609  ‪trace = GroundTrace(zombie.origin + (0, 0, 5), zombie.origin + (0, 0, -300), false, undefined);
1610  origin = ‪trace["position"];
1611  level thread ‪zombie_delay_powerup_drop( origin );
1612  }
1613  }
1614 
1615  //AUDIO: Ayers - Decides what vox to play after killing a zombie
1616  level thread ‪zm_audio::player_zombie_kill_vox( hit_location, attacker, mod, zombie );
1617 
1618  event = "death";
1619  if ( zombie.damageweapon.isBallisticKnife && (mod == "MOD_MELEE" || mod == "MOD_IMPACT") )
1620  {
1621  event = "ballistic_knife_death";
1622  }
1623 
1624  if(‪IS_TRUE(zombie.deathpoints_already_given))
1625  {
1626  return;
1627  }
1628 
1629  zombie.deathpoints_already_given = true;
1630 
1631  if ( ‪zm_equipment::is_equipment(zombie.damageweapon) )
1632  return;
1633 
1634  death_weapon = attacker.currentweapon;
1635  if ( IsDefined( zombie.damageweapon ) )
1636  {
1637  death_weapon = zombie.damageweapon;
1638  }
1639 
1640  if ( IsDefined(attacker) )
1641  {
1642  attacker ‪zm_score::player_add_points( event, mod, hit_location, undefined, team, death_weapon );
1643  }
1644 
1645  if( isdefined(level.hero_power_update))
1646  {
1647  level thread [[level.hero_power_update]](attacker, zombie);
1648  }
1649 }
1650 
1651 function ‪get_number_variants(aliasPrefix)
1652 {
1653  for(i=0; i<100; i++)
1654  {
1655  if( !SoundExists( aliasPrefix + "_" + i) )
1656  {
1657  //iprintlnbold(aliasPrefix +"_" + i);
1658  return i;
1659  }
1660  }
1661 }
1662 
1663 
1665 {
1666  if ( self.isdog )
1667  {
1668  return;
1669  }
1670 
1671  if( !IsDefined( level._effect ) || !IsDefined( level._effect["character_fire_death_sm"] ) )
1672  {
1673  return;
1674  }
1675 
1676  PlayFxOnTag( level._effect["character_fire_death_sm"], self, "J_SpineLower" );
1677 
1678  tagArray = [];
1679  if( !IsDefined( self.‪a.gib_ref ) || self.a.gib_ref != "left_arm" )
1680  {
1681  tagArray[tagArray.size] = "J_Elbow_LE";
1682  tagArray[tagArray.size] = "J_Wrist_LE";
1683  }
1684  if( !IsDefined( self.‪a.gib_ref ) || self.a.gib_ref != "right_arm" )
1685  {
1686  tagArray[tagArray.size] = "J_Elbow_RI";
1687  tagArray[tagArray.size] = "J_Wrist_RI";
1688  }
1689  if( !IsDefined( self.‪a.gib_ref ) || (self.a.gib_ref != "no_legs" && self.a.gib_ref != "left_leg") )
1690  {
1691  tagArray[tagArray.size] = "J_Knee_LE";
1692  tagArray[tagArray.size] = "J_Ankle_LE";
1693  }
1694  if( !IsDefined( self.‪a.gib_ref ) || (self.a.gib_ref != "no_legs" && self.a.gib_ref != "right_leg") )
1695  {
1696  tagArray[tagArray.size] = "J_Knee_RI";
1697  tagArray[tagArray.size] = "J_Ankle_RI";
1698  }
1699 
1700  tagArray = array::randomize( tagArray );
1701  PlayFxOnTag( level._effect["character_fire_death_sm"], self, tagArray[0] );
1702 }
1703 
1704 function ‪zombie_ragdoll_then_explode( launchvector, attacker )
1705 {
1706  if (!isdefined(self))
1707  return;
1708 
1710  self ‪clientfield::set("zombie_ragdoll_explode", 1);
1711  self notify( "exploding" );
1712  self notify( "end_melee" );
1713  self notify( "death", attacker );
1714 
1715  // Physics Launch off Window
1716  //--------------------------
1717  self.dont_die_on_me = true;
1718  self.exploding = true;
1719  self.a.nodeath = true;
1720  self.dont_throw_gib = true;
1721  self StartRagdoll();
1722  self SetPlayerCollision(0);
1724 
1725  if (isdefined(launchvector))
1726  self LaunchRagdoll( launchvector );
1727 
1728  wait 2.1;
1729  if (isdefined(self))
1730  {
1731  self ghost();
1732  self ‪util::delay( 0.25, undefined, &‪zm_utility::self_delete );
1733  }
1734 }
1735 
1736 
1737 
1738 // Called from animscripts\zm_death.gsc
1739 function ‪zombie_death_animscript( eInflictor, attacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime )
1740 {
1741  team = undefined;
1742 
1743  //A zombie died - recalculate zombie array
1745 
1746  if(isDefined(self._race_team))
1747  {
1748  team = self._race_team;
1749  }
1750 
1752 
1754  {
1755  return false;
1756  }
1757 
1758  // animscript override
1759  if( IsDefined( level.zombie_death_animscript_override ) )
1760  {
1761  self [ [ level.zombie_death_animscript_override ] ] ();
1762  }
1763 
1764  self.grenadeAmmo = 0;
1765 
1766  // rsh090710 - nuked zombies don't give points but should still possibly drop powerups
1767  if ( IsDefined( self.nuked ) )
1768  {
1769  if( ‪zombie_can_drop_powerups( self ) )
1770  {
1771  // DCS 031611: hack to prevent risers from dropping powerups under the ground.
1772  if(IsDefined(self.in_the_ground) && self.in_the_ground == true)
1773  {
1774  ‪trace = BulletTrace(self.origin + (0, 0, 100), self.origin + (0, 0, -100), false, undefined);
1775  origin = ‪trace["position"];
1776  level thread ‪zombie_delay_powerup_drop( origin );
1777  }
1778  else
1779  {
1780  ‪trace = GroundTrace(self.origin + (0, 0, 5), self.origin + (0, 0, -300), false, undefined);
1781  origin = ‪trace["position"];
1782  level thread ‪zombie_delay_powerup_drop( self.origin );
1783  }
1784  }
1785  }
1786  else
1787  {
1788  // Give attacker points
1789  //ChrisP - 12/8/08 - added additional 'self' argument
1790  level ‪zombie_death_points( self.origin, self.damagemod, self.damagelocation, self.attacker, self ,team);
1791  }
1792 
1793  // switch to inflictor when SP DoDamage supports it
1794  if( isdefined( self.attacker ) && isai( self.attacker ) )
1795  {
1796  self.attacker notify( "killed", self );
1797  }
1798 
1799 
1800  if( "rottweil72_upgraded" == self.damageweapon.name && "MOD_RIFLE_BULLET" == self.damagemod )
1801  {
1802  self thread ‪dragons_breath_flame_death_fx();
1803  }
1804  if( "tazer_knuckles" == self.damageweapon.name && "MOD_MELEE" == self.damagemod )
1805  {
1806  self.is_on_fire = false;
1807  self notify("stop_flame_damage");
1808  }
1809  if( self.damagemod == "MOD_BURNED" )
1810  {
1811  self thread ‪zombie_death::flame_death_fx();
1812  }
1813  if( self.damagemod == "MOD_GRENADE" || self.damagemod == "MOD_GRENADE_SPLASH" )
1814  {
1815  level notify( "zombie_grenade_death", self.origin );
1816  }
1817 
1818  return false;
1819 }
1820 
1821 
1823 {
1824  if ( !isdefined( level.zombie_death_animscript_callbacks ) )
1825  {
1826  return false;
1827  }
1828 
1829  for ( i = 0; i < level.zombie_death_animscript_callbacks.size; i++ )
1830  {
1831  if ( self [[ level.zombie_death_animscript_callbacks[i] ]]() )
1832  {
1833  return true;
1834  }
1835  }
1836 
1837  return false;
1838 }
1839 
1840 
1842 {
1843  if ( !isdefined( level.zombie_death_animscript_callbacks ) )
1844  {
1845  level.zombie_death_animscript_callbacks = [];
1846  }
1847 
1848  level.zombie_death_animscript_callbacks[level.zombie_death_animscript_callbacks.size] = func;
1849 }
1850 
1851 
1852 function ‪damage_on_fire( player )
1853 {
1854  self endon ("death");
1855  self endon ("stop_flame_damage");
1856  wait( 2 );
1857 
1858  while( isdefined( self.is_on_fire) && self.is_on_fire )
1859  {
1860  if( level.round_number < 6 )
1861  {
1862  dmg = level.zombie_health * RandomFloatRange( 0.2, 0.3 ); // 20% - 30%
1863  }
1864  else if( level.round_number < 9 )
1865  {
1866  dmg = level.zombie_health * RandomFloatRange( 0.15, 0.25 );
1867  }
1868  else if( level.round_number < 11 )
1869  {
1870  dmg = level.zombie_health * RandomFloatRange( 0.1, 0.2 );
1871  }
1872  else
1873  {
1874  dmg = level.zombie_health * RandomFloatRange( 0.1, 0.15 );
1875  }
1876 
1877  if ( Isdefined( player ) && Isalive( player ) )
1878  {
1879  self DoDamage( dmg, self.origin, player );
1880  }
1881  else
1882  {
1883  self DoDamage( dmg, self.origin, level );
1884  }
1885 
1886  wait( randomfloatrange( 1.0, 3.0 ) );
1887  }
1888 }
1889 
1891 {
1892  if( IsPlayer( player) ) //check because robot companion can fire off this function, and internally requires a player
1893  {
1894  weapon = player GetCurrentWeapon();
1895 
1896  return (weapon == level.weaponNone || weapon.isSemiAuto);
1897  }
1898 
1899  return false;
1900 }
1901 
1902 function ‪zombie_damage( mod, hit_location, hit_origin, player, amount, team, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel )
1903 {
1905  {
1906  return;
1907  }
1908 
1909  //ChrisP - 12/8 - no points for killing gassed zombies!
1910  player.use_weapon_type = mod;
1911  if(isDefined(self.marked_for_death))
1912  {
1913  return;
1914  }
1915 
1916  if( !IsDefined( player ) )
1917  {
1918  return;
1919  }
1920 
1921  if (isdefined(hit_origin))
1922  self.damagehit_origin = hit_origin;
1923  else
1924  self.damagehit_origin = player GetWeaponMuzzlePoint();
1925 
1926  if ( self ‪check_zombie_damage_callbacks( mod, hit_location, hit_origin, player, amount, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel ) )
1927  {
1928  return;
1929  }
1930  else if ( !player ‪player_can_score_from_zombies() )
1931  {
1932 
1933  }
1934  else if ( IsDefined(weapon) && weapon.isriotshield )
1935  {
1936  }
1937  else if( self ‪zombie_flame_damage( mod, player ) )
1938  {
1940  {
1941  player ‪zm_score::player_add_points( "damage", mod, hit_location, self.isdog,team );
1942  }
1943  }
1944  else
1945  {
1946  if( ‪player_using_hi_score_weapon( player ) )
1947  {
1948  damage_type = "damage";
1949  }
1950  else
1951  {
1952  damage_type = "damage_light";
1953  }
1954 
1955  if ( !‪IS_TRUE( self.no_damage_points ) )
1956  {
1957  player ‪zm_score::player_add_points( damage_type, mod, hit_location, self.isdog, team, weapon );
1958  }
1959  }
1960 
1961  if ( IsDefined( self.zombie_damage_fx_func ) )
1962  {
1963  self [[ self.zombie_damage_fx_func ]]( mod, hit_location, hit_origin, player, direction_vec );
1964  }
1965 
1966  if ( "MOD_IMPACT" != mod && ‪zm_utility::is_placeable_mine( weapon ) )
1967  {
1968  if ( IsDefined( self.zombie_damage_claymore_func ) )
1969  {
1970  self [[ self.zombie_damage_claymore_func ]]( mod, hit_location, hit_origin, player );
1971  }
1972  else if ( isdefined( player ) && isalive( player ) )
1973  {
1974  self DoDamage( level.round_number * randomintrange( 100, 200 ), self.origin, player, self, hit_location, mod, 0, weapon );
1975  }
1976  else
1977  {
1978  self DoDamage( level.round_number * randomintrange( 100, 200 ), self.origin, undefined, self, hit_location, mod, 0, weapon );
1979  }
1980  }
1981  else if ( mod == "MOD_GRENADE" || mod == "MOD_GRENADE_SPLASH" )
1982  {
1983  if ( isdefined( player ) && isalive( player ) )
1984  {
1985  player.grenade_multiattack_count++;
1986  player.grenade_multiattack_ent = self;
1987 
1988  self DoDamage( level.round_number + randomintrange( 100, 200 ), self.origin, player, self, hit_location, mod, 0, weapon );
1989  }
1990  else
1991  {
1992  self DoDamage( level.round_number + randomintrange( 100, 200 ), self.origin, undefined, self, hit_location, mod, 0, weapon );
1993  }
1994  }
1995  else if( mod == "MOD_PROJECTILE" || mod == "MOD_EXPLOSIVE" || mod == "MOD_PROJECTILE_SPLASH" )
1996  {
1997  if ( isdefined( player ) && isalive( player ) )
1998  {
1999  self DoDamage( level.round_number * randomintrange( 0, 100 ), self.origin, player, self, hit_location, mod, 0, weapon );
2000  }
2001  else
2002  {
2003  self DoDamage( level.round_number * randomintrange( 0, 100 ), self.origin, undefined, self, hit_location, mod, 0, weapon );
2004  }
2005  }
2006 
2007  //AUDIO Plays a sound when Crawlers are created
2008  if( ‪IS_TRUE( self.gibbed ))
2009  {
2010  if( ‪IS_TRUE( self.missinglegs ) && isalive(self) )
2011  {
2012  if ( isdefined( player ) )
2013  {
2014  player ‪zm_audio::create_and_play_dialog( "general", "crawl_spawn" );
2015  }
2016  }
2017  else if( IsDefined( self.‪a.gib_ref ) && ( (self.a.gib_ref == "right_arm") || (self.a.gib_ref == "left_arm") ) )
2018  {
2019  if( !self.missingLegs && isalive( self ) )
2020  {
2021  if ( isdefined( player ) )
2022  {
2023  rand = randomintrange(0, 100);
2024  if(rand < 7)
2025  {
2026  player ‪zm_audio::create_and_play_dialog( "general", "shoot_arm" );
2027  }
2028  }
2029  }
2030  }
2031  }
2032  self thread ‪zm_powerups::check_for_instakill( player, mod, hit_location );
2033 }
2034 
2035 function ‪zombie_damage_ads( mod, hit_location, hit_origin, player, amount, team, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel )
2036 {
2037 
2039  {
2040  return;
2041  }
2042 
2043  player.use_weapon_type = mod;
2044  if( !IsDefined( player ) )
2045  {
2046  return;
2047  }
2048 
2049  if (isdefined(hit_origin))
2050  self.damagehit_origin = hit_origin;
2051  else
2052  self.damagehit_origin = player GetWeaponMuzzlePoint();
2053 
2054 
2055  if ( self ‪check_zombie_damage_callbacks( mod, hit_location, hit_origin, player, amount, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel ) )
2056  {
2057  return;
2058  }
2059  else if ( !player ‪player_can_score_from_zombies() )
2060  {
2061  }
2062  else if( self ‪zombie_flame_damage( mod, player ) )
2063  {
2065  {
2066  player ‪zm_score::player_add_points( "damage_ads", mod, hit_location,undefined,team );
2067  }
2068  }
2069  else
2070  {
2071  if( ‪player_using_hi_score_weapon( player ) )
2072  {
2073  damage_type = "damage";
2074  }
2075  else
2076  {
2077  damage_type = "damage_light";
2078  }
2079 
2080  if ( !‪IS_TRUE( self.no_damage_points ) )
2081  {
2082  player ‪zm_score::player_add_points( damage_type, mod, hit_location, undefined, team, weapon );
2083  }
2084  }
2085 
2086  if ( IsDefined( self.zombie_damage_fx_func ) )
2087  {
2088  self [[ self.zombie_damage_fx_func ]]( mod, hit_location, hit_origin, player, direction_vec );
2089  }
2090 
2091  self thread ‪zm_powerups::check_for_instakill( player, mod, hit_location );
2092 }
2093 
2094 
2095 function ‪check_zombie_damage_callbacks( mod, hit_location, hit_origin, player, amount, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel )
2096 {
2097  if ( !isdefined( level.zombie_damage_callbacks ) )
2098  {
2099  return false;
2100  }
2101 
2102  for ( i = 0; i < level.zombie_damage_callbacks.size; i++ )
2103  {
2104  if ( self [[ level.zombie_damage_callbacks[i] ]]( mod, hit_location, hit_origin, player, amount, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel ) )
2105  {
2106  return true;
2107  }
2108  }
2109 
2110  return false;
2111 }
2112 
2113 
2115 {
2116  if ( !isdefined( level.zombie_damage_callbacks ) )
2117  {
2118  level.zombie_damage_callbacks = [];
2119  }
2120 
2121  level.zombie_damage_callbacks[level.zombie_damage_callbacks.size] = func;
2122 }
2123 
2125 {
2126  if( !isDefined( self.flame_damage_time ) || GetTime() > self.flame_damage_time )
2127  {
2128  self.flame_damage_time = GetTime() + level.zombie_vars["zombie_flame_dmg_point_delay"];
2129  return true;
2130  }
2131 
2132  return false;
2133 }
2134 
2135 function ‪zombie_flame_damage( mod, player )
2136 {
2137  if( mod == "MOD_BURNED" )
2138  {
2139  if( !IsDefined( self.is_on_fire ) || ( Isdefined( self.is_on_fire ) && !self.is_on_fire ) )
2140  {
2141  self thread ‪damage_on_fire( player );
2142  }
2143 
2144  do_flame_death = true;
2145  dist = 100 * 100;
2146  ai = GetAiTeamArray( level.zombie_team );
2147  for( i = 0; i < ai.size; i++ )
2148  {
2149  if( IsDefined( ai[i].is_on_fire ) && ai[i].is_on_fire )
2150  {
2151  if( DistanceSquared( ai[i].origin, self.origin ) < dist )
2152  {
2153  do_flame_death = false;
2154  break;
2155  }
2156  }
2157  }
2158 
2159  if( do_flame_death )
2160  {
2161  self thread ‪zombie_death::flame_death_fx();
2162  }
2163 
2164  return true;
2165  }
2166 
2167  return false;
2168 }
2169 
2170 function ‪is_weapon_shotgun( weapon )
2171 {
2172  return (weapon.weapClass == "spread");
2173 }
2174 
2175 function ‪zombie_explodes_intopieces( random_gibs )
2176 {
2177  if ( isdefined(self) && IsActor(self) )
2178  {
2179  if( (!random_gibs) || (randomint(100) < 50) )
2180  gibserverutils::gibhead( self );
2181  if( (!random_gibs) || (randomint(100) < 50) )
2182  gibserverutils::gibleftarm( self );
2183  if( (!random_gibs) || (randomint(100) < 50) )
2184  gibserverutils::gibrightarm( self );
2185  if( (!random_gibs) || (randomint(100) < 50) )
2186  gibserverutils::giblegs( self );
2187  }
2188  //gibserverutils::Annihilate( zombie );
2189 }
2190 
2191 //*****************************************************************************
2192 // A zombie has been killed
2193 //*****************************************************************************
2194 
2195 function ‪zombie_death_event( zombie )
2196 {
2197  zombie.marked_for_recycle = 0;
2198 
2199  force_explode = 0;
2200  force_head_gib = 0;
2201 
2202  zombie waittill( "death", attacker);
2203  time_of_death = gettime();
2204 
2205  if(isDefined(zombie))
2206  {
2207  zombie StopSounds();
2208  }
2209 
2210  // The Insta Kill Upgrade - Forces melee deaths on close proximity
2211  if( IsDefined(zombie) && IsDefined(zombie.marked_for_insta_upgraded_death) )
2212  {
2213  force_head_gib = 1;
2214  }
2215 
2216  if ( IsDefined(zombie) && !isdefined( zombie.damagehit_origin ) && isdefined( attacker ) && IsAlive( attacker ) && !IsVehicle( attacker ) )
2217  {
2218  zombie.damagehit_origin = attacker GetWeaponMuzzlePoint();
2219  }
2220 
2221  //stat tracking
2222  if(isDefined(attacker) && isPlayer(attacker) && attacker ‪player_can_score_from_zombies() )
2223  {
2224  // If a zombie dies with the kvp (script_parameters), notify the attacker. script_parameter is inherited from the spawn location.
2225  if( isdefined(zombie.script_parameters) )
2226  {
2227  attacker notify( "zombie_death_params", zombie.script_parameters, ‪IS_TRUE(zombie.completed_emerging_into_playable_area) );
2228  }
2229 
2230  // Widows wine kill notify
2231  if( isdefined(zombie.b_widows_wine_cocoon) && isdefined(zombie.e_widows_wine_player) )
2232  {
2233  attacker notify( "widows_wine_kill", zombie.e_widows_wine_player );
2234  }
2235 
2236  // Carpenter - Persistent upgrade kills accumulator
2237  if( ‪IS_TRUE(level.pers_upgrade_carpenter) )
2238  {
2239  ‪zm_pers_upgrades::pers_zombie_death_location_check( attacker, zombie.origin );
2240  }
2241 
2242  // Player "sniper" persistent ability tracking
2243  if( ‪IS_TRUE(level.pers_upgrade_sniper) )
2244  {
2246  }
2247 
2248  if(isDefined(zombie) && isDefined(zombie.damagelocation) )
2249  {
2250  if( ‪zm_utility::is_headshot( zombie.damageweapon, zombie.damagelocation, zombie.damagemod ))
2251  {
2252  attacker.headshots++;
2253  attacker ‪zm_stats::increment_client_stat( "headshots" ); //headshots
2254  attacker AddWeaponStat(zombie.damageWeapon, "headshots", 1);
2255  attacker ‪zm_stats::increment_player_stat( "headshots" );
2256  attacker ‪zm_stats::increment_challenge_stat( "ZOMBIE_HUNTER_KILL_HEADSHOT" );
2257 
2258  // Only in classic mode
2260  {
2261  //track pers upgrade
2262  attacker ‪zm_pers_upgrades_functions::pers_check_for_pers_headshot( time_of_death, zombie );
2263  }
2264  }
2265  else
2266  {
2267  attacker notify("zombie_death_no_headshot");
2268  }
2269 
2270  }
2271  if(isDefined(zombie) && isDefined(zombie.damagemod) && zombie.damagemod == "MOD_MELEE")
2272  {
2273  attacker ‪zm_stats::increment_client_stat( "melee_kills" ); //melee kills
2274  attacker ‪zm_stats::increment_player_stat( "melee_kills" );
2275  attacker notify( "melee_kill" );
2276  attacker ‪zm_stats::increment_challenge_stat( "ZOMBIE_HUNTER_KILL_MELEE" );
2277 
2278  // If the insta_kill - force an explosive death of the zombies
2280  {
2281  force_explode = 1;
2282  }
2283  }
2284 
2286  attacker.kills++;
2287  attacker ‪zm_stats::increment_client_stat( "kills" ); //total kills
2288  attacker ‪zm_stats::increment_player_stat( "kills" );
2289 
2290  // Persistent upgrade - pistol points
2291  if ( ‪IS_TRUE(level.pers_upgrade_pistol_points) )
2292  {
2294  }
2295 
2296  if ( isDefined( zombie ) && isDefined( zombie.damageweapon ) )
2297  {
2298  attacker AddWeaponStat(zombie.damageWeapon, "kills", 1);
2299 
2300  if ( ‪zm_weapons::is_weapon_upgraded(zombie.damageWeapon) )
2301  {
2302  attacker ‪zm_stats::increment_challenge_stat( "ZOMBIE_HUNTER_KILL_PACKAPUNCH" );
2303  }
2304  }
2305 
2306  // If zombie is crawler notify the player of ther crawler kill
2307  if ( isDefined( zombie ) && ‪IS_TRUE( zombie.missingLegs ) )
2308  {
2309  attacker ‪zm_stats::increment_challenge_stat( "ZOMBIE_HUNTER_KILL_CRAWLER" );
2310  }
2311 
2312  // Check for persistant headshot upgrade and always gib the head no matter if it's a headshot or not
2313  // Also check for a force head gib
2314  if( (attacker ‪zm_pers_upgrades_functions::pers_mulit_kill_headshot_active()) || (force_head_gib) )
2315  {
2317  }
2318 
2319  // Player "sniper" persistent ability tracking
2320  if( ‪IS_TRUE(level.pers_upgrade_nube) )
2321  {
2322  attacker notify( "pers_player_zombie_kill" );
2323  }
2324  }
2325 
2326  //A zombie died - recalculate zombie array
2328 
2329  // Need to check in case he got deleted earlier
2330  if ( !IsDefined( zombie ) )
2331  {
2332  return;
2333  }
2334 
2335  //Track all zombies killed
2336  level.global_zombies_killed++;
2337 
2338  //track stats on zombies killed by traps
2339  if(isDefined(zombie.marked_for_death) && !isDefined(zombie.nuked))
2340  {
2341  level.zombie_trap_killed_count++;
2342  }
2343 
2344  zombie ‪check_zombie_death_event_callbacks( attacker );
2345  zombie ‪bgb::actor_death_override( attacker );
2346 
2347  // Need to check in case he got deleted in the callback
2348  if ( !IsDefined( zombie ) )
2349  {
2350  return;
2351  }
2352 
2353  ‪name = zombie.animname;
2354  if( isdefined( zombie.sndname ) )
2355  {
2356  ‪name = zombie.sndname;
2357  }
2358 
2359  self notify( "bhtn_action_notify", "death" );
2361 
2362  if( IsActor( zombie ) )
2363  {
2364  if( ‪IS_TRUE(zombie.damageweapon.doannihilate) )
2365  {
2366  zombie ‪zombie_explodes_intopieces( false );
2367  }
2368  else
2369  {
2370  if( (‪is_weapon_shotgun( zombie.damageweapon ) && ‪zm_weapons::is_weapon_upgraded( zombie.damageweapon )) ||
2371  ( ‪zm_utility::is_placeable_mine( zombie.damageweapon ) )||
2372  ( (zombie.damagemod === "MOD_GRENADE") || (zombie.damagemod === "MOD_GRENADE_SPLASH") || (zombie.damagemod === "MOD_EXPLOSIVE") || (force_explode == 1) ) )
2373  {
2374  splode_dist = 12 * 15;
2375  if ( isdefined(zombie.damagehit_origin) && distancesquared(zombie.origin,zombie.damagehit_origin) < splode_dist * splode_dist )
2376  {
2377  tag = "J_SpineLower";
2378 
2379 
2380  if ( ‪IS_TRUE( zombie.isdog ) )
2381  {
2382  tag = "tag_origin";
2383  }
2384 
2385  if (!‪IS_TRUE(zombie.is_on_fire) && !‪IS_TRUE(zombie.guts_explosion))
2386  {
2388  }
2389  /*
2390  else if( IsDefined( level._effect[ "zomb_gib" ] ) )
2391  {
2392  PlayFX( level._effect[ "zomb_gib" ], zombie GetTagOrigin( tag ) );
2393  }
2394  */
2395  }
2396 
2397  if ( isdefined(attacker) && IsPlayer( attacker ) && !‪is_weapon_shotgun( zombie.damageweapon ) )
2398  {
2399  attacker ‪zm_stats::increment_challenge_stat( "ZOMBIE_HUNTER_KILL_EXPLOSIVES" );
2400  }
2401  }
2402  }
2403 
2404  if ( zombie.damagemod === "MOD_GRENADE" || zombie.damagemod === "MOD_GRENADE_SPLASH" )
2405  {
2406  if ( isdefined( attacker ) && isalive( attacker ) &&isPlayer( attacker ) )
2407  {
2408  attacker.grenade_multiattack_count++;
2409  attacker.grenade_multiattack_ent = zombie;
2410  attacker.grenade_multikill_count++; // Black Ops 3 - TU1 Fix; track multikill count in addition to multiattack, for the Five-for-One Challenge
2411  }
2412  }
2413  }
2414 
2415  // this is controlling killstreak voice over in the asylum.gsc
2416  if ( !‪IS_TRUE(zombie.has_been_damaged_by_player) && ‪IS_TRUE(zombie.marked_for_recycle))
2417  {
2418  level.zombie_total++;
2419  level.zombie_total_subtract++;
2420  }
2421  else if(isdefined (zombie.attacker) && isplayer(zombie.attacker) )
2422  {
2423 
2424  //this tracks the zombies killed by a player for stat tracking
2425  level.zombie_player_killed_count++;
2426 
2427  if ( IsDefined( zombie.sound_damage_player ) && zombie.sound_damage_player == zombie.attacker )
2428  {
2429  zombie.attacker ‪zm_audio::create_and_play_dialog( "kill", "damage" );
2430  }
2431 
2432  zombie.attacker notify( "zom_kill", zombie );
2433  }
2434  else
2435  {
2436  if(zombie.ignoreall && !‪IS_TRUE(zombie.marked_for_death) )
2437  {
2438  level.zombies_timeout_spawn++;
2439  }
2440  }
2441 
2442  level notify( "zom_kill" );
2443  level.total_zombies_killed++;
2444 }
2445 
2446 //*****************************************************************************
2447 //*****************************************************************************
2448 
2450 {
2451  if ( !isdefined( level.zombie_death_event_callbacks ) )
2452  {
2453  return;
2454  }
2455 
2456  for ( i = 0; i < level.zombie_death_event_callbacks.size; i++ )
2457  {
2458  self [[ level.zombie_death_event_callbacks[i] ]]( attacker );
2459  }
2460 }
2461 
2462 
2464 {
2465  if ( !isdefined( level.zombie_death_event_callbacks ) )
2466  {
2467  level.zombie_death_event_callbacks = [];
2468  }
2469 
2470  level.zombie_death_event_callbacks[level.zombie_death_event_callbacks.size] = func;
2471 }
2472 
2474 {
2475  if (isdefined( level.zombie_death_event_callbacks ) )
2476  {
2477  ArrayRemoveValue(level.zombie_death_event_callbacks,func);
2478  }
2479 }
2480 
2481 
2482 // this is where zombies go into attack mode, and need different attributes set up
2484 {
2485  self ‪zombie_history( "zombie_setup_attack_properties()" );
2486 
2487  // allows zombie to attack again
2488  self.ignoreall = false;
2489 
2490  // push the player out of the way so they use traversals in the house.
2491  //self PushPlayer( true );
2492 
2493 // self.pathEnemyFightDist = 64; //set in gdt now
2494  self.meleeAttackDist = 64;
2495 
2496  //try to prevent always turning towards the enemy
2497  self.maxsightdistsqrd = 128 * 128;
2498 
2499  // turn off transition anims
2500  self.disableArrivals = true;
2501  self.disableExits = true;
2502 }
2503 
2504 
2505 //this lets them wake up and go after things like the monkey bomb immediately
2507 {
2508  self endon( "death" );
2509  level endon( "intermission" );
2510  self endon( "stop_find_flesh" );
2511  self endon( "path_timer_done" );
2512 
2513  level waittill( "attractor_positions_generated" );
2514  self.zombie_path_timer = 0;
2515 }
2516 
2517 
2519 {
2520  self endon( "death" );
2521  self endon( "zombie_acquire_enemy" );
2522  level endon( "intermission" );
2523 
2524  assert( IsDefined( self.favoriteenemy ) || IsDefined( self.enemyoverride ) );
2525 
2526  self._skip_pathing_first_delay = true;
2527  self thread ‪zombie_follow_enemy();
2528  self waittill( "bad_path" );
2529 
2530  level.zombie_pathing_failed ++;
2531 
2532  //If we get here then we have a bad path and the zombie can't use the regular pathing system to find the player
2533  //..... crap!
2534 
2535  if( isDefined( self.enemyoverride ) )
2536  {
2537  ‪zm_utility::debug_print( "Zombie couldn't path to point of interest at origin: " + self.enemyoverride[0] + " Falling back to breadcrumb system" );
2538  if( isDefined( self.enemyoverride[1] ) )
2539  {
2540  self.enemyoverride = self.enemyoverride[1] ‪zm_utility::invalidate_attractor_pos( self.enemyoverride, self );
2541  self.zombie_path_timer = 0;
2542  return;
2543  }
2544  }
2545  else
2546  {
2547  if(isDefined(self.favoriteenemy))
2548  {
2549  ‪zm_utility::debug_print( "Zombie couldn't path to player at origin: " + self.favoriteenemy.origin + " Falling back to breadcrumb system" );
2550  }
2551  else
2552  {
2553  ‪zm_utility::debug_print( "Zombie couldn't path to a player ( the other 'prefered' player might be ignored for encounters mode ). Falling back to breadcrumb system" );
2554  }
2555  }
2556 
2557  if( !isDefined( self.favoriteenemy ) )
2558  {
2559  self.zombie_path_timer = 0;
2560  return;
2561  }
2562  else
2563  {
2564  self.favoriteenemy endon( "disconnect" );
2565  }
2566 
2567  //this is for selecting the valid player from the player to use for tracking purposes.
2568  players = GetPlayers();
2569  valid_player_num = 0;
2570  for( i = 0; i < players.size; i++ )
2571  {
2572  if( ‪zm_utility::is_player_valid( players[i], true ) )
2573  {
2574  valid_player_num += 1;
2575  }
2576  }
2577  //PI_CHANGE_BEGIN - 7/2/2009 JV Reenabling change 274916 (from DLC3)
2578  if( players.size > 1 )
2579  {
2580  if(isDefined(level._should_skip_ignore_player_logic) && [[level._should_skip_ignore_player_logic]]() )
2581  {
2582  self.zombie_path_timer = 0;
2583  return;
2584  }
2585  if( !IsInArray( self.ignore_player, self.favoriteenemy) )
2586  {
2587  self.ignore_player[self.ignore_player.size] = self.favoriteenemy;
2588  }
2589 
2590  if( self.ignore_player.size < valid_player_num )
2591  {
2592  self.zombie_path_timer = 0;
2593  return;
2594  }
2595  }
2596  //PI_CHANGE_END
2597 
2598  crumb_list = self.favoriteenemy.zombie_breadcrumbs;
2599  bad_crumbs = [];
2600 
2601  while( 1 )
2602  {
2603  if( !‪zm_utility::is_player_valid( self.favoriteenemy, true ) )
2604  {
2605  self.zombie_path_timer = 0;
2606  return;
2607  }
2608 
2609  goal = ‪zombie_pathing_get_breadcrumb( self.favoriteenemy.origin, crumb_list, bad_crumbs, ( RandomInt( 100 ) < 20 ) );
2610 
2611  if ( !IsDefined( goal ) )
2612  {
2613  ‪zm_utility::debug_print( "Zombie exhausted breadcrumb search" );
2614 
2615  //zombies failed to get breadcrumbs
2616  level.zombie_breadcrumb_failed ++;
2617 
2618  goal = self.favoriteenemy.spectator_respawn.origin;
2619  }
2620 
2621  ‪zm_utility::debug_print( "Setting current breadcrumb to " + goal );
2622 
2623  self.zombie_path_timer += 100;
2624  self SetGoal( goal );
2625  self waittill( "bad_path" );
2626 
2627  ‪zm_utility::debug_print( "Zombie couldn't path to breadcrumb at " + goal + " Finding next breadcrumb" );
2628  for( i = 0; i < crumb_list.size; i++ )
2629  {
2630  if( goal == crumb_list[i] )
2631  {
2632  bad_crumbs[bad_crumbs.size] = i;
2633  break;
2634  }
2635  }
2636  }
2637 }
2638 
2639 function ‪zombie_pathing_get_breadcrumb( origin, breadcrumbs, bad_crumbs, pick_random )
2640 {
2641  assert( IsDefined( origin ) );
2642  assert( IsDefined( breadcrumbs ) );
2643  assert( IsArray( breadcrumbs ) );
2644 
2645  for( i = 0; i < breadcrumbs.size; i++ )
2646  {
2647  if ( pick_random )
2648  {
2649  crumb_index = RandomInt( breadcrumbs.size );
2650  }
2651  else
2652  {
2653  crumb_index = i;
2654  }
2655 
2656  if( ‪crumb_is_bad( crumb_index, bad_crumbs ) )
2657  {
2658  continue;
2659  }
2660 
2661  return breadcrumbs[crumb_index];
2662  }
2663 
2664  return undefined;
2665 }
2666 
2667 function ‪crumb_is_bad( crumb, bad_crumbs )
2668 {
2669  for ( i = 0; i < bad_crumbs.size; i++ )
2670  {
2671  if ( bad_crumbs[i] == crumb )
2672  {
2673  return true;
2674  }
2675  }
2676 
2677  return false;
2678 }
2679 
2680 function ‪jitter_enemies_bad_breadcrumbs( start_crumb )
2681 {
2682  trace_distance = 35;
2683  jitter_distance = 2;
2684 
2685  index = start_crumb;
2686 
2687  while (isdefined(self.favoriteenemy.zombie_breadcrumbs[ index + 1 ]))
2688  {
2689  current_crumb = self.favoriteenemy.zombie_breadcrumbs[ index ];
2690  next_crumb = self.favoriteenemy.zombie_breadcrumbs[ index + 1 ];
2691 
2692  angles = vectortoangles(current_crumb - next_crumb);
2693 
2694  right = anglestoright(angles);
2695  left = anglestoright(angles + (0,180,0));
2696 
2697  dist_pos = current_crumb + VectorScale( right, trace_distance );
2698 
2699  ‪trace = bulletTrace( current_crumb, dist_pos, true, undefined );
2700  vector = ‪trace["position"];
2701 
2702  if (distance(vector, current_crumb) < 17 )
2703  {
2704  self.favoriteenemy.zombie_breadcrumbs[ index ] = current_crumb + VectorScale( left, jitter_distance );
2705  continue;
2706  }
2707 
2708 
2709  // try the other side
2710  dist_pos = current_crumb + VectorScale( left, trace_distance );
2711 
2712  ‪trace = bulletTrace( current_crumb, dist_pos, true, undefined );
2713  vector = ‪trace["position"];
2714 
2715  if (distance(vector, current_crumb) < 17 )
2716  {
2717  self.favoriteenemy.zombie_breadcrumbs[ index ] = current_crumb + VectorScale( right, jitter_distance );
2718  continue;
2719  }
2720 
2721  index++;
2722  }
2723 
2724 }
2725 
2727 {
2728  note = 0;
2729 
2730  notes = [];
2731 
2732  for(i = 0; i < 4; i ++)
2733  {
2734  notes[notes.size] = "zombie_repath_notify_"+i;
2735  }
2736 
2737  while(1)
2738  {
2739  level notify(notes[note]);
2740 
2741  note = (note + 1) % 4;
2743  }
2744 }
2745 
2747 {
2748  self endon( "death" );
2749  self endon( "zombie_acquire_enemy" );
2750  self endon( "bad_path" );
2751 
2752  level endon( "intermission" );
2753 
2754  if(!isdefined(level.repathNotifierStarted))
2755  {
2756  level.repathNotifierStarted = true;
2757 
2758  level thread ‪zombie_repath_notifier();
2759  }
2760 
2761  if(!isdefined(self.zombie_repath_notify))
2762  {
2763  self.zombie_repath_notify = "zombie_repath_notify_" + (self getentitynumber() % 4);
2764  }
2765 
2766  while( 1 )
2767  {
2768  if(!isdefined(self._skip_pathing_first_delay))
2769  {
2770  level waittill(self.zombie_repath_notify);
2771  }
2772  else
2773  {
2774  self._skip_pathing_first_delay = undefined;
2775  }
2776 
2777  if( !‪IS_TRUE( self.ignore_enemyoverride ) && isDefined( self.enemyoverride ) && isDefined( self.enemyoverride[1] ) )
2778  {
2779  if( distanceSquared( self.origin, self.enemyoverride[0] ) > 1*1 )
2780  {
2781  self OrientMode( "face motion" );
2782  }
2783  else
2784  {
2785  self OrientMode( "face point", self.enemyoverride[1].origin );
2786  }
2787  self.ignoreall = true;
2788 
2789  goalPos = self.enemyoverride[0];
2790  if ( IsDefined( level.adjust_enemyoverride_func ) )
2791  {
2792  goalPos = self [[ level.adjust_enemyoverride_func ]]();
2793  }
2794  self SetGoal( goalPos );
2795  }
2796  else if( IsDefined( self.favoriteenemy ) )
2797  {
2798  self.ignoreall = false;
2799 
2800  //TEMP Just to get us running for the playtest. Need to kill this whole function later.
2801  if ( IsDefined( level.enemy_location_override_func ) )
2802  {
2803  goalPos = [[ level.enemy_location_override_func ]]( self, self.favoriteenemy );
2804 
2805  if ( IsDefined( goalPos ) )
2806  {
2807  self SetGoal( goalPos );
2808  }
2809  else
2810  {
2812  }
2813  }
2814  else if( ‪IS_TRUE(self.is_rat_test) )
2815  {
2816  }
2818  {
2820  continue;
2821  }
2822  else if ( IsDefined( self.favoriteenemy.last_valid_position ) )
2823  {
2824  self SetGoal( self.favoriteenemy.last_valid_position );
2825  }
2826  else
2827  {
2828  //AssertMsg( "no last_valid_position" );
2829  }
2830 
2831  if ( !IsDefined( level.ignore_path_delays ) )
2832  {
2833  distSq = distanceSquared( self.origin, self.favoriteenemy.origin );
2834 
2835  if( distSq > 3200 * 3200 )
2836  {
2837  wait(2.0 + randomFloat( 1.0 ));
2838  }
2839  else if( distSq > 2200 * 2200 )
2840  {
2841  wait(1.0 + randomFloat( 0.5 ));
2842  }
2843  else if( distSq > 1200 * 1200 )
2844  {
2845  wait(0.5 + randomFloat( 0.5 ));
2846  }
2847  }
2848  }
2849 
2850  // LDS - changed this from a level specific catch function to a general one that can be overloaded based
2851  // on the conditions in a level that can render a player inaccessible to zombies.
2852  if( isDefined( level.inaccesible_player_func ) )
2853  {
2854  self [[ level.inaccessible_player_func ]]();
2855  }
2856  }
2857 }
2858 
2859 //
2860 // DEBUG
2861 //
2862 
2863 function ‪zombie_history( msg )
2864 {
2865 }
2866 
2868 {
2869  self endon("death");
2870 
2871  spots = [];
2872 
2873  // special case, seems to appear in gamemodules.
2874  if(isDefined(self._rise_spot))
2875  {
2876  spot = self._rise_spot;
2877  self thread ‪do_zombie_rise(spot);
2878  return;
2879  }
2880 
2881  // add spawner locations
2882  if ( ‪IS_TRUE( level.use_multiple_spawns ) && isdefined( self.script_int ) )
2883  {
2884  foreach( loc in level.zm_loc_types[ "zombie_location" ] )
2885  {
2886  if ( !(IsDefined( level.spawner_int ) && (level.spawner_int == self.script_int)) &&
2887  !(IsDefined( loc.script_int ) || IsDefined( level.zones[ loc.zone_name ].script_int )) )
2888  {
2889  continue;
2890  }
2891 
2892  if ( IsDefined( loc.script_int ) && ( loc.script_int != self.script_int ) )
2893  {
2894  continue;
2895  }
2896  else if ( IsDefined( level.zones[ loc.zone_name ].script_int ) && ( level.zones[ loc.zone_name ].script_int != self.script_int ) )
2897  {
2898  continue;
2899  }
2900 
2901  spots[spots.size] = loc;
2902  }
2903  }
2904  else
2905  {
2906  spots = level.zm_loc_types[ "zombie_location" ];
2907  }
2908 
2909  if ( GetDvarInt("scr_zombie_spawn_in_view") )
2910  {
2911  player = GetPlayers()[0];
2912  spots = [];
2913  max_dot = 0;
2914  look_loc = undefined;
2915  foreach ( loc in level.zm_loc_types[ "zombie_location" ] )
2916  {
2917  player_vec = VectorNormalize( AnglesToForward( player GetPlayerAngles() ) );
2918  player_vec_2d = ( player_vec[0], player_vec[1], 0 );
2919  player_spawn = VectorNormalize( loc.origin - player.origin );
2920  player_spawn_2d = ( player_spawn[0], player_spawn[1], 0 );
2921  dot = VectorDot( player_vec_2d, player_spawn_2d );
2922  dist = Distance( loc.origin, player.origin );
2923  if ( dot > 0.707 && dist <= GetDvarInt( "scr_zombie_spawn_in_view_dist" ) )
2924  {
2925  if ( dot > max_dot )
2926  {
2927  look_loc = loc;
2928  max_dot = dot;
2929  }
2930  //spots[spots.size] = loc;
2931 
2932  }
2933  }
2934 
2935  if ( isdefined( look_loc ) )
2936  {
2937  spots[ spots.size ] = look_loc;
2938 
2939  }
2940 
2941  if ( spots.size <= 0 )
2942  {
2943  spots[spots.size] = level.zm_loc_types[ "zombie_location" ][0];
2944  iprintln( "no spawner in view" );
2945  }
2946  }
2947 
2948  assert( spots.size > 0, "No spawn locations found" );
2949 
2950  if( isdefined(level.zm_custom_spawn_location_selection) )
2951  {
2952  spot = [[level.zm_custom_spawn_location_selection]](spots);
2953  }
2954  else
2955  {
2956  spot = array::random(spots);
2957  }
2958  self.spawn_point = spot;
2959 
2960 
2961  self thread [[level.move_spawn_func]](spot);
2962 }
2963 
2965 {
2966 }
2967 
2968 
2969 function ‪do_zombie_rise(spot)
2970 {
2971  self endon("death");
2972 
2973  self.in_the_ground = true;
2974 
2975  if ( IsDefined( self.anchor ) )
2976  {
2977  self.anchor Delete();
2978  }
2979 
2980  self.anchor = ‪spawn("script_origin", self.origin);
2981  self.anchor.angles = self.angles;
2982  self linkto(self.anchor);
2983 
2984  if( !isDefined( spot.angles ) )
2985  {
2986  spot.angles = (0, 0, 0);
2987  }
2988 
2989  anim_org = spot.origin;
2990  anim_ang = spot.angles;
2991 
2992  anim_org = anim_org + (0, 0, 0); // start the animation 45 units below the ground
2993 
2994  //self Teleport(anim_org, anim_ang);
2995 
2996  self Ghost();
2997  self.anchor moveto(anim_org, .05);
2998  self.anchor waittill("movedone");
2999 
3000  // face goal
3002  if (IsDefined(target_org))
3003  {
3004  anim_ang = VectorToAngles(target_org - self.origin);
3005  self.anchor RotateTo((0, anim_ang[1], 0), .05);
3006  self.anchor waittill("rotatedone");
3007  }
3008 
3009  self unlink();
3010 
3011  if(isDefined(self.anchor))
3012  {
3013  self.anchor delete();
3014  }
3015 
3016  self thread ‪zombie_utility::hide_pop(); // hack to hide the pop when the zombie gets to the start position before the anim starts
3017 
3018  level thread ‪zombie_utility::zombie_rise_death(self, spot);
3019  spot thread ‪zombie_rise_fx(self);
3020 
3021  substate = 0;
3022  if ( self.zombie_move_speed == "walk" )
3023  {
3024  substate = RandomInt( 2 );
3025  }
3026  else if ( self.zombie_move_speed == "run" )
3027  {
3028  substate = 2;
3029  }
3030  else if ( self.zombie_move_speed == "sprint" )
3031  {
3032  substate = 3;
3033  }
3034 
3035  self OrientMode( "face default" );
3036 
3037  if( isdefined( level.custom_riseanim ) )
3038  {
3039  self AnimScripted( "rise_anim", self.origin, spot.angles, level.custom_riseanim );
3040  }
3041  else if( isdefined( level.custom_rise_func ) )
3042  {
3043  self [[ level.custom_rise_func ]]( spot );
3044  }
3045  else
3046  {
3047  self AnimScripted( "rise_anim", self.origin, spot.angles, "ai_zombie_traverse_ground_climbout_fast" );
3048  }
3049  //self AnimScripted( self.origin, spot.angles, "zm_rise", substate );
3051 
3052  self notify("rise_anim_finished");
3053  spot notify("stop_zombie_rise_fx");
3054  self.in_the_ground = false;
3055  self notify("risen", spot.script_string );
3056 }
3057 
3058 /*
3059 function zombie_rise_fx: self is the script struct at the rise location
3060 function Play the fx as the zombie crawls out of the ground and thread another function to handle the dust falling
3061 function off when the zombie is out of the ground.
3062 */
3063 function ‪zombie_rise_fx(zombie)
3064 {
3065 
3066  if(!‪IS_TRUE(level.riser_fx_on_client))
3067  {
3068  self thread ‪zombie_rise_dust_fx(zombie);
3069  self thread ‪zombie_rise_burst_fx(zombie);
3070  }
3071  else
3072  {
3073  self thread ‪zombie_rise_burst_fx(zombie);
3074  }
3075  zombie endon("death");
3076  self endon("stop_zombie_rise_fx");
3077  wait 1;
3078  if (zombie.zombie_move_speed != "sprint")
3079  {
3080  // wait longer before starting billowing fx if it's not a really fast animation
3081  wait 1;
3082  }
3083 }
3084 
3085 function ‪zombie_rise_burst_fx(zombie)
3086 {
3087  self endon("stop_zombie_rise_fx");
3088  self endon("rise_anim_finished");
3089 
3090  if(IsDefined(self.script_parameters) && self.script_parameters == "in_water" && (!‪IS_TRUE(level._no_water_risers)) )
3091  {
3092  zombie ‪clientfield::set("zombie_riser_fx_water", 1);
3093  }
3094  else if(IsDefined(self.script_parameters) && self.script_parameters == "in_foliage" && (‪IS_TRUE(level._foliage_risers)) )
3095  {
3096  zombie ‪clientfield::set("zombie_riser_fx_foliage", 1);
3097  }
3098  else if(IsDefined(self.script_parameters) && self.script_parameters == "in_snow")
3099  {
3100 
3101  // this needs to have "level.riser_type = "snow" set in the level script to work properly in snow levels!
3102  zombie ‪clientfield::set("zombie_riser_fx", 1);
3103  }
3104  else
3105  {
3106  if(isDefined(zombie.zone_name ) && isDefined(level.zones[zombie.zone_name]) )
3107  {
3108  low_g_zones = getentarray(zombie.zone_name,"targetname");
3109 
3110  if(isDefined(low_g_zones[0].script_string) && low_g_zones[0].script_string == "lowgravity")
3111  {
3112  zombie ‪clientfield::set("zombie_riser_fx_lowg", 1);
3113  }
3114  else
3115  {
3116 
3117  zombie ‪clientfield::set("zombie_riser_fx", 1);
3118 
3119  }
3120  }
3121  else
3122  {
3123 
3124  zombie ‪clientfield::set("zombie_riser_fx", 1);
3125 
3126  }
3127  }
3128 }
3129 
3130 function ‪zombie_rise_dust_fx(zombie)
3131 {
3132  dust_tag = "J_SpineUpper";
3133 
3134  self endon("stop_zombie_rise_dust_fx");
3135  self thread ‪stop_zombie_rise_dust_fx(zombie);
3136  wait(2);
3137  dust_time = 5.5; // play dust fx for a max time
3138  dust_interval = .3; //randomfloatrange(.1,.25); // wait this time in between playing the effect
3139 
3140  //TODO - add rising dust stuff ere
3141  if(IsDefined(self.script_parameters) && self.script_parameters == "in_water")
3142  {
3143 
3144  for (t = 0; t < dust_time; t += dust_interval)
3145  {
3146  PlayfxOnTag(level._effect["rise_dust_water"], zombie, dust_tag);
3147  wait dust_interval;
3148  }
3149 
3150  }
3151  else if(IsDefined(self.script_parameters) && self.script_parameters == "in_snow")
3152  {
3153 
3154  for (t = 0; t < dust_time; t += dust_interval)
3155  {
3156  PlayfxOnTag(level._effect["rise_dust_snow"], zombie, dust_tag);
3157  wait dust_interval;
3158  }
3159 
3160  }
3161  else if(IsDefined(self.script_parameters) && self.script_parameters == "in_foliage")
3162  {
3163 
3164  for (t = 0; t < dust_time; t += dust_interval)
3165  {
3166  PlayfxOnTag(level._effect["rise_dust_foliage"], zombie, dust_tag);
3167  wait dust_interval;
3168  }
3169 
3170  }
3171  else
3172  {
3173  for (t = 0; t < dust_time; t += dust_interval)
3174  {
3175  PlayfxOnTag(level._effect["rise_dust"], zombie, dust_tag);
3176  wait dust_interval;
3177  }
3178  }
3179 }
3180 
3182 {
3183  zombie waittill("death");
3184  self notify("stop_zombie_rise_dust_fx");
3185 }
3186 
3187 // for now only regular zombies can head gib from the tesla
3189 {
3190  self endon("death");
3191 
3192  if(self.animname == "quad_zombie")
3193  {
3194  return;
3195  }
3196 
3197  if( RandomInt( 100 ) < level.zombie_vars["tesla_head_gib_chance"] )
3198  {
3199  wait( randomfloatrange( 0.53, 1.0 ) );
3201  }
3202  else
3203  {
3204  ‪zm_net::network_safe_play_fx_on_tag( "tesla_death_fx", 2, level._effect["tesla_shock_eyes"], self, "J_Eyeball_LE" );
3205  }
3206 }
3207 
3209 {
3210  self endon( "death" );
3211 
3212  while(1)
3213  {
3214  type = "ambient";
3215  float = 4;
3216 
3217  if( isdefined( self.zombie_move_speed ) )
3218  {
3219  switch(self.zombie_move_speed)
3220  {
3221  case "walk": type="ambient"; float=4; break;
3222  case "run": type="sprint"; float=4; break;
3223  case "sprint": type="sprint"; float=4; break;
3224  }
3225  }
3226 
3227  if( self.animname == "zombie" && self.missingLegs )
3228  {
3229  type = "crawler";
3230  }
3231  else if( self.animname == "thief_zombie" || self.animname == "leaper_zombie" )
3232  {
3233  float = 1.2;
3234  }
3235  else if( self.voicePrefix == "keeper" )
3236  {
3237  float = 1.2;
3238  }
3239 
3240  ‪name = self.animname;
3241  if( isdefined( self.sndname ) )
3242  {
3243  ‪name = self.sndname;
3244  }
3245 
3246 
3247  self notify( "bhtn_action_notify", type );
3248 
3249  wait(RandomFloatRange(1,float));
3250  }
3251 }
3252 
3254 {
3255  self.should_turn = false;
3256  self.completed_emerging_into_playable_area = true;
3257  self.no_powerups = false;
3258  self notify( "completed_emerging_into_playable_area" );
3259  if( IsDefined( self.backedUpGoal ) )
3260  {
3261  self SetGoal( self.backedUpGoal );
3262  self.backedUpGoal = undefined;
3263  }
3264  self thread ‪zombie_free_cam_allowed();
3265  self thread ‪zombie_push();
3266  self thread ‪zm::update_zone_name();
3267 }
3268 
3270 {
3271  self endon( "death" );
3272 
3273  wait( 1.5 );
3274  if ( !IsDefined( self ) )
3275  {
3276  return;
3277  }
3278  self SetFreeCameraLockOnAllowed( true );
3279 }
3280 
3281 function ‪zombie_push()
3282 {
3283  self endon( "death" );
3284 
3285  wait( 5 );
3286  if ( !IsDefined( self ) )
3287  {
3288  return;
3289  }
3290  self PushActors( true );
3291 }
3292 
‪PERK_JUGGERNOG
‪#define PERK_JUGGERNOG
Definition: mechz.gsc:47
‪disable_react
‪function disable_react()
Definition: _zm_utility.gsc:4747
‪is_equipment
‪function is_equipment(weapon)
Definition: _zm_equipment.gsc:691
‪player_using_hi_score_weapon
‪function player_using_hi_score_weapon(player)
Definition: _zm_spawner.gsc:1890
‪should_attack_player_thru_boards
‪function should_attack_player_thru_boards()
Definition: _zm_spawner.gsc:1053
‪jitter_enemies_bad_breadcrumbs
‪function jitter_enemies_bad_breadcrumbs(start_crumb)
Definition: _zm_spawner.gsc:2680
‪get_attack_spot_index
‪function get_attack_spot_index(node)
Definition: _zm_spawner.gsc:1186
‪deregister_zombie_death_event_callback
‪function deregister_zombie_death_event_callback(func)
Definition: _zm_spawner.gsc:2473
‪crumb_is_bad
‪function crumb_is_bad(crumb, bad_crumbs)
Definition: _zm_spawner.gsc:2667
‪zombie_bad_path_notify
‪function zombie_bad_path_notify()
Definition: _zm_spawner.gsc:773
‪increment_client_stat
‪function increment_client_stat(stat_name, include_gametype)
Definition: _zm_stats.gsc:389
‪pers_upgrade_pistol_points_kill
‪function pers_upgrade_pistol_points_kill()
Definition: _zm_pers_upgrades_functions.gsc:20
‪zombie_ragdoll_then_explode
‪function zombie_ragdoll_then_explode(launchvector, attacker)
Definition: _zm_spawner.gsc:1704
‪zombie_rise_burst_fx
‪function zombie_rise_burst_fx(zombie)
Definition: _zm_spawner.gsc:3085
‪zombie_bartear_offset_fx_horizontle
‪function zombie_bartear_offset_fx_horizontle(chunk)
Definition: _zm_spawner.gsc:1442
‪zombieShouldMoveAwayCondition
‪function zombieShouldMoveAwayCondition(behaviorTreeEntity)
Definition: _zm_behavior.gsc:788
‪increment_player_stat
‪function increment_player_stat(stat_name)
Definition: _zm_stats.gsc:369
‪player_add_points
‪function player_add_points(event, mod, hit_location, is_dog, zombie_team, damage_weapon)
Definition: _zm_score.gsc:129
‪ignore
‪function ignore(str_system)
Definition: system_shared.csc:165
‪delayed_zombie_eye_glow
‪function delayed_zombie_eye_glow()
Definition: zombie_utility.gsc:1700
‪damage_on_fire
‪function damage_on_fire(player)
Definition: _zm_spawner.gsc:1852
‪is_weapon_shotgun
‪function is_weapon_shotgun(weapon)
Definition: _zm_spawner.gsc:2170
‪do_zombie_spawn
‪function do_zombie_spawn()
Definition: _zm_spawner.gsc:2867
‪zombie_head_gib
‪function zombie_head_gib(attacker, means_of_death)
Definition: zombie_utility.gsc:2952
‪zombie_setup_attack_properties
‪function zombie_setup_attack_properties()
Definition: _zm_spawner.gsc:2483
‪zombie_boardtear_offset_fx_verticle
‪function zombie_boardtear_offset_fx_verticle(chunk, node)
Definition: _zm_spawner.gsc:1300
‪zombie_damage
‪function zombie_damage(mod, hit_location, hit_origin, player, amount, team, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel)
Definition: _zm_spawner.gsc:1902
‪get_closest_non_destroyed_chunk
‪function get_closest_non_destroyed_chunk(origin, barrier, barrier_chunks)
Definition: _zm_utility.gsc:2392
‪add_custom_zombie_spawn_logic
‪function add_custom_zombie_spawn_logic(func)
Definition: _zm_spawner.gsc:188
‪zmbAIVox_NotifyConvert
‪function zmbAIVox_NotifyConvert()
Definition: _zm_audio.gsc:1354
‪ZM_CAN_STUMBLE
‪#define ZM_CAN_STUMBLE
Definition: zombie.gsh:42
‪taunt_notetracks
‪function taunt_notetracks(msg)
Definition: _zm_spawner.gsc:1031
‪check_zombie_death_event_callbacks
‪function check_zombie_death_event_callbacks(attacker)
Definition: _zm_spawner.gsc:2449
‪check_for_instakill
‪function check_for_instakill(player, mod, hit_location)
Definition: _zm_powerups.gsc:1438
‪debug_print
‪function debug_print(str_line)
Definition: _zm_daily_challenges.gsc:402
‪zombie_bartear_offset_fx_verticle
‪function zombie_bartear_offset_fx_verticle(chunk)
Definition: _zm_spawner.gsc:1365
‪add_actor_bookmark_kill_time
‪function add_actor_bookmark_kill_time()
Definition: demo_shared.gsc:119
‪zombie_bad_path
‪function zombie_bad_path()
Definition: _zm_spawner.gsc:754
‪tear_into_building
‪function tear_into_building()
Definition: _zm_spawner.gsc:797
‪is_Classic
‪function is_Classic()
Definition: _zm_utility.gsc:42
‪teleport
‪function teleport(animation, v_origin_or_ent, v_angles_or_tag, time)
Definition: animation_shared.gsc:311
‪zombie_follow_enemy
‪function zombie_follow_enemy()
Definition: _zm_spawner.gsc:2746
‪trace
‪function trace(from, to, target)
Definition: grapple.gsc:369
‪zombie_goto_entrance
‪function zombie_goto_entrance(node, endon_bad_path)
Definition: _zm_spawner.gsc:616
‪powerup_drop
‪function powerup_drop(drop_point)
Definition: _zm_powerups.gsc:586
‪zombie_explodes_intopieces
‪function zombie_explodes_intopieces(random_gibs)
Definition: _zm_spawner.gsc:2175
‪zombie_spawn_init
‪function zombie_spawn_init(animname_set)
Definition: _zm_spawner.gsc:200
‪self_delete
‪function self_delete()
Definition: _util.gsc:739
‪register_zombie_death_animscript_callback
‪function register_zombie_death_animscript_callback(func)
Definition: _zm_spawner.gsc:1841
‪pers_upgrade_sniper_kill_check
‪function pers_upgrade_sniper_kill_check(zombie, attacker)
Definition: _zm_pers_upgrades_functions.gsc:18
‪check_zombie_damage_callbacks
‪function check_zombie_damage_callbacks(mod, hit_location, hit_origin, player, amount, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel)
Definition: _zm_spawner.gsc:2095
‪spawn
‪function spawn(v_origin=(0, 0, 0), v_angles=(0, 0, 0))
Definition: struct.csc:23
‪is_weapon_upgraded
‪function is_weapon_upgraded(weapon)
Definition: _zm_weapons.csc:155
‪get_desired_origin
‪function get_desired_origin()
Definition: zombie_utility.gsc:1570
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪get_attack_spot
‪function get_attack_spot(node)
Definition: _zm_spawner.gsc:1170
‪get
‪function get(kvp_value, kvp_key="targetname")
Definition: struct.csc:13
‪zombie_think
‪function zombie_think()
Definition: _zm_spawner.gsc:545
‪a
‪function add_remove_list a
Definition: util_shared.csc:906
‪delay
‪function delay(time_or_notify, str_endon, func, arg1, arg2, arg3, arg4, arg5, arg6)
Definition: util_shared.csc:784
‪is_player_valid
‪function is_player_valid(player, checkIgnoreMeFlag, ignore_laststand_players)
Definition: skeleton.gsc:256
‪is_tactical_grenade
‪function is_tactical_grenade(weapon)
Definition: _zm_utility.gsc:4215
‪ZM_ZOMBIE_HERO_WEAPON_KILL_POWER
‪#define ZM_ZOMBIE_HERO_WEAPON_KILL_POWER
Definition: _zm.gsh:1
‪register_zombie_death_event_callback
‪function register_zombie_death_event_callback(func)
Definition: _zm_spawner.gsc:2463
‪reset_attack_spot
‪function reset_attack_spot()
Definition: zombie_utility.gsc:1671
‪zombie_repath_notifier
‪function zombie_repath_notifier()
Definition: _zm_spawner.gsc:2726
‪check_zbarrier_piece_for_zombie_inert
‪function check_zbarrier_piece_for_zombie_inert(chunk_index, zbarrier, zombie)
Definition: _zm_spawner.gsc:1494
‪pers_check_for_pers_headshot
‪function pers_check_for_pers_headshot(time_of_death, zombie)
Definition: _zm_pers_upgrades_functions.gsc:19
‪increment_challenge_stat
‪function increment_challenge_stat(stat_name, amount=1)
Definition: _zm_stats.gsc:478
‪zombie_give_flame_damage_points
‪function zombie_give_flame_damage_points()
Definition: _zm_spawner.gsc:2124
‪check_zbarrier_piece_for_zombie_death
‪function check_zbarrier_piece_for_zombie_death(chunk_index, zbarrier, zombie)
Definition: _zm_spawner.gsc:1506
‪check_zombie_death_animscript_callbacks
‪function check_zombie_death_animscript_callbacks()
Definition: _zm_spawner.gsc:1822
‪hide_pop
‪function hide_pop()
Definition: zombie_utility.gsc:1593
‪DoNoteTracks
‪function DoNoteTracks(flagName, customFunction, debugIdentifier, var1)
Definition: shared.gsc:387
‪DEFAULT
‪#define DEFAULT(__var, __default)
Definition: shared.gsh:270
‪zombie_rise_death
‪function zombie_rise_death(zombie, spot)
Definition: zombie_utility.gsc:1635
‪zombieUpdateGoal
‪function zombieUpdateGoal()
Definition: _zm_behavior.gsc:498
‪waittill_any_ex
‪function waittill_any_ex(...)
Definition: util_shared.csc:270
‪play_ambient_zombie_vocals
‪function play_ambient_zombie_vocals()
Definition: _zm_spawner.gsc:3208
‪zombie_gib_on_damage
‪function zombie_gib_on_damage()
Definition: zombie_utility.gsc:2287
‪wait_network_frame
‪function wait_network_frame(n_count=1)
Definition: util_shared.gsc:64
‪pers_zombie_death_location_check
‪function pers_zombie_death_location_check(attacker, v_pos)
Definition: _zm_pers_upgrades.gsc:7
‪zombie_rise_fx
‪function zombie_rise_fx(zombie)
Definition: _zm_spawner.gsc:3063
‪draw_zone_spawned_from
‪function draw_zone_spawned_from()
Definition: _zm_spawner.gsc:2964
‪check_for_zombie_death
‪function check_for_zombie_death(zombie)
Definition: _zm_spawner.gsc:1525
‪append_missing_legs_suffix
‪function append_missing_legs_suffix(animstate)
Definition: zombie_utility.gsc:190
‪get_number_variants
‪function get_number_variants(aliasPrefix)
Definition: _zm_spawner.gsc:1651
‪zombie_history
‪function zombie_history(msg)
Definition: _zm_spawner.gsc:2863
‪attractors_generated_listener
‪function attractors_generated_listener()
Definition: _zm_spawner.gsc:2506
‪zombie_eye_glow_stop
‪function zombie_eye_glow_stop()
Definition: zombie_utility.gsc:1733
‪dragons_breath_flame_death_fx
‪function dragons_breath_flame_death_fx()
Definition: _zm_spawner.gsc:1664
‪player_can_score_from_zombies
‪function player_can_score_from_zombies()
Definition: _zm_spawner.gsc:1534
‪is_ads
‪function is_ads()
Definition: util_shared.gsc:1521
‪zombie_boardtear_offset_fx_horizontle
‪function zombie_boardtear_offset_fx_horizontle(chunk, node)
Definition: _zm_spawner.gsc:1235
‪zombie_rise_dust_fx
‪function zombie_rise_dust_fx(zombie)
Definition: _zm_spawner.gsc:3130
‪is_headshot
‪function is_headshot(weapon, sHitLoc, sMeansOfDeath)
Definition: _zm_utility.gsc:5265
‪bullet_attack
‪function bullet_attack(type)
Definition: _zm_utility.gsc:4776
‪init_zombie_run_cycle
‪function init_zombie_run_cycle()
Definition: _zm_utility.gsc:116
‪zombie_bad_path_timeout
‪function zombie_bad_path_timeout()
Definition: _zm_spawner.gsc:784
‪zombie_delay_powerup_drop
‪function zombie_delay_powerup_drop(origin)
Definition: _zm_spawner.gsc:1577
‪init
‪function init()
Definition: _zm_spawner.gsc:43
‪enemy_death_detection
‪function enemy_death_detection()
Definition: _zm_spawner.gsc:134
‪stop_zombie_rise_dust_fx
‪function stop_zombie_rise_dust_fx(zombie)
Definition: _zm_spawner.gsc:3181
‪register_zombie_damage_callback
‪function register_zombie_damage_callback(func)
Definition: _zm_spawner.gsc:2114
‪zombie_damage_ads
‪function zombie_damage_ads(mod, hit_location, hit_origin, player, amount, team, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel)
Definition: _zm_spawner.gsc:2035
‪do_a_taunt
‪function do_a_taunt()
Definition: _zm_spawner.gsc:994
‪network_safe_play_fx_on_tag
‪function network_safe_play_fx_on_tag(id, max, fx, entity, tag)
Definition: _zm_net.gsc:108
‪flame_death_fx
‪function flame_death_fx(localClientNum)
Definition: zombie_death.csc:35
‪zombie_flame_damage
‪function zombie_flame_damage(mod, player)
Definition: _zm_spawner.gsc:2135
‪draw_line_ent_to_pos
‪function draw_line_ent_to_pos(ent, pos, end_on)
Definition: _zm_utility.gsc:3272
‪recalc_zombie_array
‪function recalc_zombie_array()
Definition: _zm_utility.gsc:96
‪zombie_death_event
‪function zombie_death_event(zombie)
Definition: _zm_spawner.gsc:2195
‪zombie_push
‪function zombie_push()
Definition: _zm_spawner.gsc:3281
‪is_insta_kill_upgraded_and_active
‪function is_insta_kill_upgraded_and_active()
Definition: _zm_pers_upgrades.gsc:8
‪invalidate_attractor_pos
‪function invalidate_attractor_pos(attractor_pos, zombie)
Definition: _zm_utility.gsc:1290
‪zombie_gut_explosion
‪function zombie_gut_explosion()
Definition: zombie_utility.gsc:1684
‪update_zone_name
‪function update_zone_name()
Definition: _zm.gsc:7113
‪player_zombie_kill_vox
‪function player_zombie_kill_vox(hit_location, player, mod, zombie)
Definition: _zm_audio.gsc:306
‪set
‪function set(str_field_name, n_value)
Definition: clientfield_shared.gsc:34
‪do_zombie_rise
‪function do_zombie_rise(spot)
Definition: _zm_spawner.gsc:2969
‪player_is_in_laststand
‪function player_is_in_laststand()
Definition: laststand_shared.gsc:18
‪zombie_tesla_head_gib
‪function zombie_tesla_head_gib()
Definition: _zm_spawner.gsc:3188
‪actor_death_override
‪function actor_death_override(attacker)
Definition: _zm_bgb.gsc:6
‪handle_rise_notetracks
‪function handle_rise_notetracks(note, spot)
Definition: zombie_utility.gsc:1611
‪zombie_findnodes
‪function zombie_findnodes()
Definition: _zm_spawner.gsc:462
‪update_states
‪function update_states(states)
Definition: _zm_blockers.gsc:3183
‪zombie_death_points
‪function zombie_death_points(origin, mod, hit_location, attacker, zombie, team)
Definition: _zm_spawner.gsc:1585
‪zombie_pathing
‪function zombie_pathing()
Definition: _zm_spawner.gsc:2518
‪should_skip_teardown
‪function should_skip_teardown(find_flesh_struct_string)
Definition: _zm_spawner.gsc:446
‪all_chunks_destroyed
‪function all_chunks_destroyed(barrier, barrier_chunks)
Definition: _zm_utility.gsc:455
‪zombie_tear_notetracks
‪function zombie_tear_notetracks(msg, chunk, node)
Definition: _zm_spawner.gsc:1207
‪zombie_death_animscript
‪function zombie_death_animscript(eInflictor, attacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime)
Definition: _zm_spawner.gsc:1739
‪create_and_play_dialog
‪function create_and_play_dialog(category, subcategory, force_variant)
Definition: _zm_audio.gsc:603
‪zombie_pathing_get_breadcrumb
‪function zombie_pathing_get_breadcrumb(origin, breadcrumbs, bad_crumbs, pick_random)
Definition: _zm_spawner.gsc:2639
‪is_spawner_targeted_by_blocker
‪function is_spawner_targeted_by_blocker(ent)
Definition: _zm_spawner.gsc:164
‪zombie_damage_failsafe
‪function zombie_damage_failsafe()
Definition: _zm_spawner.gsc:394
‪result
‪function result(death, attacker, mod, weapon)
Definition: _zm_aat_blast_furnace.gsc:46
‪zombie_can_drop_powerups
‪function zombie_can_drop_powerups(zombie)
Definition: _zm_spawner.gsc:1545
‪name
‪class GroundFx name
‪is_placeable_mine
‪function is_placeable_mine(weapon)
Definition: _zm_utility.gsc:4267
‪zombie_free_cam_allowed
‪function zombie_free_cam_allowed()
Definition: _zm_spawner.gsc:3269
‪window_notetracks
‪function window_notetracks(msg)
Definition: _zm_spawner.gsc:1112
‪zombie_assure_node
‪function zombie_assure_node()
Definition: _zm_spawner.gsc:681
‪player_attacker
‪function player_attacker(attacker)
Definition: _zm_spawner.gsc:125
‪zombie_entered_playable
‪function zombie_entered_playable()
Definition: _zm_spawner.gsc:593
‪player_attacks_enemy
‪function player_attacks_enemy(player, amount, type, point, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel)
Definition: _zm_spawner.gsc:96
‪is_magic_bullet_shield_enabled
‪function is_magic_bullet_shield_enabled(ent)
Definition: _zm_utility.gsc:3474
‪pers_mulit_kill_headshot_active
‪function pers_mulit_kill_headshot_active()
Definition: _zm_pers_upgrades_functions.gsc:21
‪WAIT_SERVER_FRAME
‪#define WAIT_SERVER_FRAME
Definition: shared.gsh:265
‪zombie_complete_emerging_into_playable_area
‪function zombie_complete_emerging_into_playable_area()
Definition: _zm_spawner.gsc:3253
‪get_gamemode_var
‪function get_gamemode_var(gvar)
Definition: _zm_utility.gsc:5208